diff -Nur linux-2.4.19/Documentation/Changes linux-2.4.19-sgi211r3/Documentation/Changes --- linux-2.4.19/Documentation/Changes Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/Documentation/Changes Wed Oct 16 14:02:58 2002 @@ -56,6 +56,7 @@ o e2fsprogs 1.25 # tune2fs o jfsutils 1.0.12 # fsck.jfs -V o reiserfsprogs 3.x.1b # reiserfsck 2>&1|grep reiserfsprogs +o xfsprogs 2.1.0 # xfs_db -V o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -190,6 +191,17 @@ versions of mkreiserfs, resize_reiserfs, debugreiserfs and reiserfsck. These utils work on both i386 and alpha platforms. +Xfsprogs +-------- + +The latest version of xfsprogs contains mkfs.xfs, xfs_db, and the +xfs_repair utilities, among others, for the XFS filesystem. It is +architecture independent and any version from 2.0.0 onward should +work correctly with this version of the XFS kernel code. For the new +(v2) log format that has better support for stripe-size aligning on +LVM and MD devices at least xfsprogs 2.1.0 is needed. + + Pcmcia-cs --------- @@ -327,6 +339,10 @@ Reiserfsprogs ------------- o + +Xfsprogs +-------- +o LVM toolset ----------- diff -Nur linux-2.4.19/Documentation/Configure.help linux-2.4.19-sgi211r3/Documentation/Configure.help --- linux-2.4.19/Documentation/Configure.help Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/Documentation/Configure.help Fri Nov 1 07:16:07 2002 @@ -2342,6 +2342,19 @@ behaviour is platform-dependent, but normally the flash frequency is a hyperbolic function of the 5-minute load average. +CpuMemSet support +CONFIG_CPUMEMSET + CpuMemSets provide a way for any permitted user to place task + scheduling and memory allocation onto specific processors and memory + banks. + This option makes sense for big machines, and particularly for NUMA + machines. You can find a more detailled description of CpuMemSets + here: + + + If you don't know what CpuMemSets are, and if you are not using any + big SMP or NUMA machine, you should probably say N. + Networking support CONFIG_NET Unless you really know what you are doing, you should say Y here. @@ -3772,6 +3785,25 @@ up to the user level program to do useful things with this information. This is generally a good idea, so say Y. +CSA Job Accounting +CONFIG_CSA_JOB_ACCT + Comprehensive System Accounting (CSA) provides job level accounting + of resource usage. The accounting records are written by the + kernel into a file. CSA user level scripts and commands process + the binary accounting records and combine them by job identifier + within system boot uptime periods. These accounting records are + then used to produce reports and charge fees to users. + + Say Y here if you want job level accounting to be compiled into + the kernel. Say M here if you want the writing of accounting + records portion of this feature to be a loadable module. Say + N here if you do not want job level accounting (the default). + + The CSA commands and scripts package needs to be installed to + process the CSA accounting records. See http://oss.sgi.com/projects/csa + for further information about CSA and download instructions for the CSA + commands package and documentation. + Sysctl support CONFIG_SYSCTL The sysctl interface provides a means of dynamically changing @@ -3813,6 +3845,13 @@ Not necessary unless you're using a very out-of-date binutils version. You probably want KCORE_ELF. +Kernel crash dumps (version 2) +CONFIG_DUMP + This creates a dump driver suitable for dumping system memory on + system failure to an appropriate dump device. Use a dump utility + program to open up /dev/dump to perform dump configuration. + More information about dumping is at http://lkcd.sourceforge.net/. + Kernel support for ELF binaries CONFIG_BINFMT_ELF ELF (Executable and Linkable Format) is a format for libraries and @@ -12157,6 +12196,20 @@ The module will be called isp16.o. If you want to compile it as a module, say M here and read . +Posix Access Control Lists +CONFIG_FS_POSIX_ACL + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you plan to use Access Control Lists, you may also need the + getfacl and setfacl utilities, along with some additional patches + from the website. + + If you don't know what Access Control Lists are, say N. + iSeries Virtual I/O CD Support CONFIG_VIOCD If you are running Linux on an IBM iSeries system and you want to @@ -12165,12 +12218,44 @@ Quota support CONFIG_QUOTA If you say Y here, you will be able to set per user limits for disk - usage (also called disk quotas). Currently, it works only for the - ext2 file system. You need additional software in order to use quota - support; for details, read the Quota mini-HOWTO, available from + usage (also called disk quotas). Currently, it works for the + ext2, ext3, and reiserfs file system. You need additional software + in order to use quota support (you can download sources from + ). For further details, read + the Quota mini-HOWTO, available from . Probably the quota support is only useful for multi user systems. If unsure, say N. +Old quota format support +CONFIG_QFMT_V1 + This quota format was (is) used by kernels earlier than 2.4.??. If + you have quota working and you don't want to convert to new quota + format say Y here. + +VFS v0 quota format support +CONFIG_QFMT_V2 + This quota format allows using quotas with 32-bit UIDs/GIDs. If you + need this functionality say Y here. Note that you will need latest + quota utilities for new quota format with this kernel. + +Compatible quota interfaces +CONFIG_QIFACE_COMPAT + This option will enable old quota interface in kernel. + If you have old quota tools (version <= 3.04) and you don't want to + upgrade them say Y here. + +Original quota interface +CONFIG_QIFACE_V1 + This is the oldest quota interface. It was used for old quota format. + If you have old quota tools and you use old quota format choose this + interface (if unsure, this interface is the best one to choose). + +VFS v0 quota interface +CONFIG_QIFACE_V2 + This quota interface was used by VFS v0 quota format. If you need + support for VFS v0 quota format (eg. you're using quota on ReiserFS) + and you don't want to upgrade quota tools, choose this interface. + Memory Technology Device (MTD) support CONFIG_MTD Memory Technology Devices are flash, RAM and similar chips, often @@ -15190,6 +15275,92 @@ Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. +XFS filesystem support +CONFIG_XFS_FS + XFS is a high performance journaling filesystem which originated + on the SGI IRIX platform. It is completely multi-threaded, can + support large files and large filesystems, extended attributes, + variable block sizes, is extent based, and makes extensive use of + Btrees (directories, extents, free space) to aid both performance + and scalability. + + Refer to the documentation at + for complete details. This implementation is on-disk compatible + with the IRIX version of XFS. + + If you want to compile this file system as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read . The + module will be called xfs.o. Be aware, however, that if the file + system of your root partition is compiled as a module, you'll need + to use an initial ramdisk (initrd) to boot. + +DMAPI support +CONFIG_XFS_DMAPI + The Data Management API is a system interface used to implement + the interface defined in the X/Open document: + "Systems Management: Data Storage Management (XDSM) API", + dated February 1997. This interface is used by hierarchical + storage management systems. + + If XFS is built as module (= code which can be inserted in and + removed from the running kernel whenever you want), this code will + also be built as module. It is called xfs_dmapi.o. + + If unsure, say N. + +Quota support +CONFIG_XFS_QUOTA + If you say Y here, you will be able to set limits for disk usage on + a per user and/or per group basis under XFS. XFS considers quota + information as filesystem metadata and uses journaling to provide a + higher level guarantee of consistency. The on-disk data format for + quota is also compatible with the IRIX version of XFS, allowing a + filesystem to be migrated between Linux and IRIX without any need + for conversion. + + If unsure, say N. More comprehensive documentation can be found in + README.quota in the xfsprogs package. XFS quota can be used either + with or without the generic quota support enabled (CONFIG_QUOTA) - + they are completely independent subsystems. + +Realtime support (EXPERIMENTAL) +CONFIG_XFS_RT + If you say Y here you will be able to mount and use XFS filesystems + which contain a realtime subvolume. The realtime subvolume is a + separate area of disk space where only file data is stored. The + realtime subvolume is designed to provide very deterministic + data rates suitable for media streaming applications. + + See the xfs man page in section 5 for a bit more information. + + This feature is unsupported at this time, is not yet fully + functional, and may cause serious problems. + + If unsure, say N. + +Debugging support (EXPERIMENTAL) +CONFIG_XFS_DEBUG + Say Y here to get an XFS build with many debugging features, + including ASSERT checks, function wrappers around macros, + and extra sanity-checking functions in various code paths. + + Note that the resulting code will be HUGE and SLOW, and probably + not useful unless you are debugging a particular problem. + + Say N unless you are an XFS developer, or play one on TV. + +Pagebuf debugging support (EXPERIMENTAL) +CONFIG_PAGEBUF_DEBUG + Say Y here to get an XFS build which may help you debug pagebuf + problems. Enabling this option will attach tracing information + to pagebufs, which can be read with the kdb kernel debugger. + + Note that you will also have to enable the sysctl in + /proc/sys/vm/pagebuf/debug for this to work. + + Say N unless you're interested in debugging pagebuf. + Advanced partition selection CONFIG_PARTITION_ADVANCED Say Y here if you would like to use hard disks under Linux which @@ -15331,12 +15502,6 @@ were partitioned using EFI GPT. Presently only useful on the IA-64 platform. -/dev/guid support (EXPERIMENTAL) -CONFIG_DEVFS_GUID - Say Y here if you would like to access disks and partitions by - their Globally Unique Identifiers (GUIDs) which will appear as - symbolic links in /dev/guid. - Ultrix partition table support CONFIG_ULTRIX_PARTITION Say Y here if you would like to be able to read the hard disk @@ -19406,6 +19571,12 @@ Say Y or M if you have a sound system driven by ESS's Maestro 3 PCI sound chip. +ForteMedia FM801 driver +CONFIG_SOUND_FORTE + Say Y or M if you want driver support for the ForteMedia FM801 PCI + audio controller (Abit AU10, Genius Sound Maker, HP Workstation + zx2000, and others). + Adlib Cards CONFIG_SOUND_ADLIB Includes ASB 64 4D. Information on programming AdLib cards is @@ -19613,6 +19784,88 @@ keys are documented in . Don't say Y unless you really know what this hack does. +Process Aggregates support +CONFIG_PAGG + Say Y here if you will be loading modules which provide support + for process aggregate containers. Currently, this option is only + applicable to Intel (i386) architectures. Examples of such modules + include the Linux Jobs module and the Linux Array Sessions module. + If you will not be using such modules, say N. + +Process Aggregates Job support +CONFIG_PAGG_JOB + The Job feature implements a type of process aggregate, + or grouping. A job is the collection of all processes that + are descended from a point-of-entry process. Examples of such + points-of-entry include telnet, rlogin, and console logins. + A job differs from a session and process group since the job + container (or group) is inescapable. Only root level processes, + or those with the CAP_SYS_RESOURCE capability, can create new jobs + or escape from a job. + + A job is identified by a unique job identifier (jid). Currently, + that jid can be used to obtain status information about the job + and the processes it contians. The jid can also be used to send + signals to all processes contained in the job. In addition, + other processes can wait for the completion of a job - the event + where the last process contained in the job has exited. + + In the future, resource limit features will be added to jobs. + Such limits would be enforced against the aggregate usage of + resources by all processes within the job. + + If you want to compile support for jobs into the kernel, select + this entry using Y. If you want the support for jobs provided as + a module, select this entry using M. If you do not want support + for jobs, select this entry using N (this is the default setting). + +Kernel Debugging support +CONFIG_KDB + This option provides a built-in kernel debugger. The built-in + kernel debugger contains commands which allow memory to be examined, + instructions to be disassembled and breakpoints to be set. For details, + see Documentation/kdb/kdb.mm and the manual pages kdb_bt, kdb_ss, etc. + Kdb can also be used via the serial port. Set up the system to + have a serial console (see Documentation/serial-console.txt). + The Control-A key sequence on the serial port will cause the + kernel debugger to be entered with input from the serial port and + output to the serial console. Selecting this option will + automatically set CONFIG_KALLSYMS. If unsure, say N. + +KDB modules +CONFIG_KDB_MODULES + KDB can be extended by adding your own modules, in directory + kdb/modules. This option selects the way that these modules should + be compiled, as free standing modules (select M) or built into the + kernel (select Y). If unsure say M. + +KDB off by default +CONFIG_KDB_OFF + Normally kdb is activated by default, as long as CONFIG_KDB is set. + If you want to ship a kernel with kdb support but only have kdb + turned on when the user requests it then select this option. When + compiled with CONFIG_KDB_OFF, kdb ignores all events unless you boot + with kdb=on or you echo "1" > /proc/sys/kernel/kdb. This option also + works in reverse, if kdb is normally activated, you can boot with + kdb=off or echo "0" > /proc/sys/kernel/kdb to deactivate kdb. If + unsure, say N. + +Support for USB Keyboard in KDB +CONFIG_KDB_USB + If you want to use kdb from a USB keyboard then say Y here. If you + say N then kdb can only be used from a PC (AT) keyboard or a serial + console. + +Load all symbols for debugging +CONFIG_KALLSYMS + Normally only exported symbols are available to modules. For + debugging you may want all symbols, not just the exported ones. If + you say Y here then extra data is added to the kernel and modules, + this data lists all the non-stack symbols in the kernel or module + and can be used by any debugger. You need modutils >= 2.3.11 to use + this option. See "man kallsyms" for the data format, it adds 10-20% + to the size of the kernel and the loaded modules. If unsure, say N. + ISDN support CONFIG_ISDN ISDN ("Integrated Services Digital Networks", called RNIS in France) @@ -24402,13 +24655,19 @@ HP-simulator For the HP simulator (). + HP-zx1 For HP zx1 Platforms. SN1 For SGI SN1 Platforms. SN2 For SGI SN2 Platforms. DIG-compliant For DIG ("Developer's Interface Guide") compliant - system. + systems. If you don't know what to do, choose "generic". +CONFIG_IA64_HP_ZX1 + Build a kernel that runs on HP zx1-based systems. This adds support + for the zx1 IOMMU and makes root bus bridges appear in PCI config space + (required for zx1 agpgart support). + CONFIG_IA64_SGI_SN_SIM Build a kernel that runs on both the SGI simulator AND on hardware. There is a very slight performance penalty on hardware for including this @@ -24419,6 +24678,11 @@ platform/kernel bugs. There is a small but measurable performance degradation when this option is enabled. +CONFIG_IA64_SGI_AUTOTEST + Build a kernel used for hardware validation. If you include the + keyword "autotest" on the boot command line, the kernel does NOT boot. + Instead, it starts all cpus and runs cache coherency tests instead. + # Choice: pagesize Kernel page size CONFIG_IA64_PAGE_SIZE_4KB @@ -24479,12 +24743,31 @@ and restore instructions. It's useful for tracking down spinlock problems, but slow! If you're unsure, select N. -Early printk support (requires VGA!) +Early printk support CONFIG_IA64_EARLY_PRINTK - Selecting this option uses the VGA screen for printk() output before - the consoles are initialised. It is useful for debugging problems - early in the boot process, but only if you have a VGA screen - attached. If you're unsure, select N. + Selecting this option uses a UART or VGA screen (or both) for + printk() output before the consoles are initialised. It is useful + for debugging problems early in the boot process, but only if you + have a serial terminal or a VGA screen attached. If you're unsure, + select N. + +Early printk on serial port +CONFIG_IA64_EARLY_PRINTK_UART + Select this option to use a serial port for early printk() output. + You must also select either CONFIG_IA64_EARLY_PRINTK_UART_BASE or + CONFIG_SERIAL_HCDP. If you select CONFIG_SERIAL_HCDP, early + printk() output will appear on the first console device described by + the HCDP. If you set CONFIG_IA64_EARLY_PRINTK_UART_BASE, the HCDP + will be ignored. + +UART base address +CONFIG_IA64_EARLY_PRINTK_UART_BASE + The physical MMIO address of the UART to use for early printk(). + This overrides any UART located using the EFI HCDP table. + +Early printk on VGA +CONFIG_IA64_EARLY_PRINTK_VGA + Select this option to use VGA for early printk() output. Print possible IA64 hazards to console CONFIG_IA64_PRINT_HAZARDS @@ -24507,6 +24790,15 @@ Layer) information in /proc/pal. This contains useful information about the processors in your systems, such as cache and TLB sizes and the PAL firmware version in use. + + To use this option, you have to check that the "/proc file system + support" (CONFIG_PROC_FS) is enabled, too. + +/proc/efi/vars support +CONFIG_EFI_VARS + If you say Y here, you are able to get EFI (Extensible Firmware + Interface) variable information in /proc/efi/vars. You may read, + write, create, and destroy EFI variables through this interface. To use this option, you have to check that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. diff -Nur linux-2.4.19/Documentation/filesystems/00-INDEX linux-2.4.19-sgi211r3/Documentation/filesystems/00-INDEX --- linux-2.4.19/Documentation/filesystems/00-INDEX Wed Jun 20 11:10:27 2001 +++ linux-2.4.19-sgi211r3/Documentation/filesystems/00-INDEX Tue May 14 08:04:51 2002 @@ -44,3 +44,5 @@ - info on using the VFAT filesystem used in Windows NT and Windows 95 vfs.txt - Overview of the Virtual File System +xfs.txt + - info and mount options for the XFS filesystem. diff -Nur linux-2.4.19/Documentation/filesystems/Locking linux-2.4.19-sgi211r3/Documentation/filesystems/Locking --- linux-2.4.19/Documentation/filesystems/Locking Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/Documentation/filesystems/Locking Mon Oct 28 20:43:23 2002 @@ -45,6 +45,10 @@ int (*revalidate) (struct dentry *); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct dentry *, struct iattr *); + int (*setxattr) (struct dentry *, const char *, void *, size_t, int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); locking rules: all may block @@ -60,10 +64,14 @@ readlink: no no no follow_link: no no no truncate: yes yes no (see below) -setattr: yes if ATTR_SIZE no -permssion: yes no no +setattr: no yes no +permission: yes no no getattr: (see below) revalidate: no (see below) +setxattr: yes yes no +getxattr: yes yes no +listxattr: yes yes no +removexattr: yes yes no Additionally, ->rmdir() has i_zombie on victim and so does ->rename() in case when target exists and is a directory. ->rename() on directories has (per-superblock) ->s_vfs_rename_sem. @@ -234,7 +242,7 @@ locking rules: All except ->poll() may block. BKL -llseek: yes +llseek: yes (see below) read: no write: no readdir: yes (see below) @@ -249,6 +257,13 @@ lock: yes readv: no writev: no + +->llseek() locking has moved from llseek to the individual llseek +implementations. If your fs is not using generic_file_llseek, you +need to acquire and release the appropriate lock(s) in your ->llseek(). +For many filesystems, it is probably safe to acquire the inode +semaphore. Note some filesystems (i.e. remote ones) provide no +protection for i_size so you will need to use the BKL. ->open() locking is in-transit: big lock partially moved into the methods. The only exception is ->open() in the instances of file_operations that never diff -Nur linux-2.4.19/Documentation/filesystems/xfs.txt linux-2.4.19-sgi211r3/Documentation/filesystems/xfs.txt --- linux-2.4.19/Documentation/filesystems/xfs.txt Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/filesystems/xfs.txt Fri Nov 1 12:24:39 2002 @@ -0,0 +1,118 @@ + +The SGI XFS Filesystem +====================== + +XFS is a high performance journaling filesystem which originated +on the SGI IRIX platform. It is completely multi-threaded, can +support large files and large filesystems, extended attributes, +variable block sizes, is extent based, and makes extensive use of +Btrees (directories, extents, free space) to aid both performance +and scalability. + +Refer to the documentation at http://oss.sgi.com/projects/xfs/ +for further details. This implementation is on-disk compatible +with the IRIX version of XFS. + + +Options +======= + +When mounting an XFS filesystem, the following options are accepted. + + biosize=size + Sets the preferred buffered I/O size (default size is 64K). + "size" must be expressed as the logarithm (base2) of the + desired I/O size. + Valid values for this option are 14 through 16, inclusive + (i.e. 16K, 32K, and 64K bytes). On machines with a 4K + pagesize, 13 (8K bytes) is also a valid size. + The preferred buffered I/O size can also be altered on an + individual file basis using the ioctl(2) system call. + + dmapi + Enable the DMAPI (Data Management API) event callouts. + Use with the "mtpt" option. + + logbufs=value + Set the number of in-memory log buffers. Valid numbers range + from 2-8 inclusive. + The default value is 8 buffers for filesystems with a + blocksize of 64K, 4 buffers for filesystems with a blocksize + of 32K, 3 buffers for filesystems with a blocksize of 16K + and 2 buffers for all other configurations. Increasing the + number of buffers may increase performance on some workloads + at the cost of the memory used for the additional log buffers + and their associated control structures. + + logbsize=value + Set the size of each in-memory log buffer. + Size may be specified in bytes, or in kilobytes with a "k" suffix. + Valid sizes for version 1 and version 2 logs are 16384 (16k) and + 32768 (32k). Valid sizes for version 2 logs also include + 65536 (64k), 131072 (128k) and 262144 (256k). + The default value for machines with more than 32MB of memory + is 32768, machines with less memory use 16384 by default. + + logdev=device and rtdev=device + Use an external log (metadata journal) and/or real-time device. + An XFS filesystem has up to three parts: a data section, a log + section, and a real-time section. The real-time section is + optional, and the log section can be separate from the data + section or contained within it. + + mtpt=mountpoint + Use with the "dmapi" option. The value specified here will be + included in the DMAPI mount event, and should be the path of + the actual mountpoint that is used. + + noalign + Data allocations will not be aligned at stripe unit boundaries. + + noatime + Access timestamps are not updated when a file is read. + + norecovery + The filesystem will be mounted without running log recovery. + If the filesystem was not cleanly unmounted, it is likely to + be inconsistent when mounted in "norecovery" mode. + Some files or directories may not be accessible because of this. + Filesystems mounted "norecovery" must be mounted read-only or + the mount will fail. + + osyncisosync + Make O_SYNC writes implement true O_SYNC. WITHOUT this option, + Linux XFS behaves as if an "osyncisdsync" option is used, + which will make writes to files opened with the O_SYNC flag set + behave as if the O_DSYNC flag had been used instead. + This can result in better performance without compromising + data safety. + However if this option is not in effect, timestamp updates from + O_SYNC writes can be lost if the system crashes. + If timestamp updates are critical, use the osyncisosync option. + + quota/usrquota/uqnoenforce + User disk quota accounting enabled, and limits (optionally) + enforced. + + grpquota/gqnoenforce + Group disk quota accounting enabled and limits (optionally) + enforced. + + sunit=value and swidth=value + Used to specify the stripe unit and width for a RAID device or + a stripe volume. "value" must be specified in 512-byte block + units. + If this option is not specified and the filesystem was made on + a stripe volume or the stripe width or unit were specified for + the RAID device at mkfs time, then the mount system call will + restore the value from the superblock. For filesystems that + are made directly on RAID devices, these options can be used + to override the information in the superblock if the underlying + disk layout changes after the filesystem has been created. + The "swidth" option is required if the "sunit" option has been + specified, and must be a multiple of the "sunit" value. + + nouuid + Don't check for double mounted file systems using the file system uuid. + This is useful to mount LVM snapshot volumes. + diff -Nur linux-2.4.19/Documentation/job.txt linux-2.4.19-sgi211r3/Documentation/job.txt --- linux-2.4.19/Documentation/job.txt Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/job.txt Thu Jan 31 12:33:13 2002 @@ -0,0 +1,443 @@ +Linux Jobs - A Process Aggregate (PAGG) Module +---------------------------------------------- + +Comments by: Sam Watters +Last Change: 2001.04.15 + + +1. Overview + +This document provides two additional sections. Section 2 provides a +listing of the manual page that describes the particulars of the Linux +job implementation. Section 3 provides a listing of the manual page +describing the Linux job support for the paggctl(3) system call. + +2. Job Man Page + + +JOB(7) Linux User's Manual JOB(7) + + +NAME + job - Linux Jobs kernel module overiew + +DESCRIPTION + A job is a group of related processes all descended from a + point of entry process and identified by a unique job + identifier (jid). A job can contain multiple process + groups or sessions, and all processes in one of these sub- + groups can only be contained within a single job. + + The primary purpose for having jobs is to provide job + based resource limits. The current implementation only + provides the job container and resource limits will be + provided in a later implementation. When an implementa- + tion that provides job limits is available, this descrip- + tion will be expanded to provide further explanation of + job based limits. + + Not every process on the system is part of a job. That + is, only processes which are started by a login initiator + like login, rlogin, rsh and so on, get assigned a job ID. + In the Linux environment, jobs are created via a PAM mod- + ule. + + Jobs on Linux are provided using a loadable kernel module. + Linux jobs have the following characteristics: + + o A job is an inescapable container. A process cannot + leave the job nor can a new process be created outside + the job without explicit action, that is, a system + call with root privilege. + + o Each new process inherits the jid and limits [when + implemented] from its parent process. + + o All point of entry processes (job initiators) create a + new job and set the job limits [when implemented] + appropriately. + + o Job initiation on Linux is performed via a PAM session + module. + + o The job initiator performs authentication and security + checks. + + o Users can raise and lower their own job limits within + maximum values specified by the system administrator + [when implemented]. + + o Not all pocesses on a system need be members of a job. + + o The process control initialization process (init(1M)) + and startup scripts called by init are not part of a + job. + + + Job initiators can be categorized as either interactive or + batch processes. Limit domain names are defined by the + system administrator when the user limits database (ULDB) + is created. [The ULDB will be implemented in conjunction + with future job limits work.] + + Note: The existing command jobs(1) applies to shell "jobs" + and it is not related to the Linux Kernel Module jobs. + The at(1), atd(8), atq(1), batch(1), atrun(8), atrm(1)) + man pages refer to shell scripts as a job. a shell + script. + +SEE ALSO + job(1), jwait(1), jstat(1), jkill(1) + + + + + + + + + + + + + + +3. Man Page for Job paggctl(3) System Call Support + + +job_paggctl(3) job_paggctl(3) + + +NAME + job_paggctl, paggctl - control and obtain status for the + Job PAGG module + +SYNOPSIS + #include + + int paggctl (char *module_name, int request, void *data); + +DESCRIPTION + The paggctl system call is used as the system call inter- + face for Process Aggregation (PAGG) modules. The paggctl + system call allows processes to obtain status information + about jobs and to create new jobs. When the Job module is + to be used to service a request, the paggctl.h header file + should be included to obtain the proper request macros and + data structures. + + The use of the paggctl system call requires three parame- + ters. The first, module_name, is a string that provides + the name module that should service the request. In the + case of a request for the Job module, the JOB_NAME macro + is provided to use for this argument. + + The second argument, request, is a code that indicates to + the Job module what operation the caller is requesting. + Macros that specify the requests are provided in the pag- + gctl.h include file. The macro for job requests is + PAGG_JOB. + + The final arugment, data, is a void pointer that refer- + ences the structure used to pass data between the calling + process and the Job module's paggctl service function. + The data structure types passed via the data pointer are + defined in the paggctl.h include file. + + The Job module handles the following request macros (as + defined in paggctl.h): + + JOB_CREATE + Create a new job. The calling process is attached + to the new job. This request requires + CAP_SYS_RESOURCE capability. (See the capabil- + ity(4) and capabilities(4) man pages for more + information on the capability mechanism for con- + trolling process privileges.) The data structure + pointed to by data is defined as follows: + + typedef struct job_create_s { + uint64_t r_jid; + uint64_t jid; + uid_t user; + int options; + } job_create_t; + + The r_jid member is the job ID (jid) value used for + the new job. If the operation to create a job + failed, then r_jid will be set to 0. The jid mem- + ber allows the caller to specify a jid value to use + when creating the job. If the caller want the Job + module to generate the job ID, then set jid to 0. + The user member is used to supply the user ID (uid) + value for the user that will own the job. The + options member is for future use. + + JOB_GETJID + Get the job ID (jid) for the specified process pid. + The data structure pointed to by data is defined as + follows: + + typedef struct job_getjid_s { + uint64_t r_jid; + pid_t pid; + } job_getjid_t; + + The r_jid member is the job ID (jid) value for the + job to which process is attached. The r_jid value + will be equal to 0 if the attempt to get the job ID + failed, and errno will be set to indicate the + error. The pid member is used to specify the pro- + cess for which the caller is requesting the jid. + + JOB_WAITJID + Wait for the job, specified by the supplied jid, to + complete. The data structure pointed to by data is + defined as follows: + + typedef struct job_waitjid_s { + uint64_t r_jid; + uint64_t jid; + int stat; + int options; + } job_waitjid_t; + + The r_jid data member is the jid value for the job + that was waited upon. If the wait operation + failed, then r_jid will be set equal to 0 and errno + will be set to indicate the error. The jid member + is the jid value that identifies the job to wait + upon. The stat member is the completion status of + the job. The completion status is determined by + the exit status for the last process in the job + that exits. The status can be evaluated using the + same macros as described in the wait(2) manual + page. The options data member is for future use. + + JOB_KILLJID + Send a signal to all processes in the specified + job. The data argument should point to a structure + of type job_killjid_t defined as follows: + + typedef struct job_killjid_s { + int r_val; + uint64_t jid; + int sig; + } job_killjid_t; + + The r_val member is the return value for the opera- + tion. On success, r_val=0 and on failure r_val<0. + The jid member specifies the job that should be + sent the signal. the sig member specifies what + signal should be sent. + + JOB_GETJIDCNT + Get the number of jobs currently running on the + system. The data argument should point to a struc- + ture of type job_jidcnt_t defined as follows: + + typedef struct job_jidcnt_s { + int r_val; + } job_jidcnt_t; + + The number of jobs on the system is returned in the + r_val member. This value will be greater than or + equal to 0. + + JOB_GETJIDLST + Get the list of job jids for job currently running + on the system. The data argument should point to a + structure of type job_jidlst_t defined as follows: + + typedef struct job_jidlst_s { + int r_val; + uint64_t *jid; + } job_jidlst_t; + + The list of job jid values is returned in the array + pointed to by the jid member. The caller is + responsible for allocating and freeing the memory + for the array pointed to by jid. The caller speci- + fies the number of elements in the array using the + r_val member. Upon return, the r_val member will + contain the number of job jid values that were + inserted into the array by the Job module. The + number of jid values returned via the jid list is + limited to the number of elements specified by the + caller using r_val. + + JOB_GETPIDCNT + Get the number of processes (pids) attached to a + specified job. The data argument should point to a + structure of type job_pidcnt_t, defined as follows: + + typedef struct job_pidcnt_s { + int r_val; + uint64_t jid; + } job_pidcnt_t; + + The r_val member indicates the number of processes + attached to the job upon return. The jid member is + set by the caller to specify the job that is to be + queried for the number of attached processes. + + JOB_GETPIDLST + Get the list of process pids attached to a speci- + fied job. The data argument should point to a + structure of type job_pidlst_t, defined as follows: + + typedef struct job_pidlst_s { + int r_val; + pid_t *pid; + uint64_t jid; } job_pidlst_t; + + The list of process pid values is returned in the + array pointed to by the pid member. The caller is + responsible for allocating and freeing the memory + for the array pointed to by pid. The caller speci- + fies the number of elements in the array using the + r_val member. Upon return, the r_val member will + contain the number of pid values that were inserted + into the array by the Job module. The number of + pid values returned via the pid list is limited to + the number of elements specified by the caller + using r_val. + + JOB_GETUSER + Get the owner of a job. The data argument should + point to a structure of type job_user_t, defined as + follows: + + typedef struct job_user_s { + uint16_t r_user; + uint64_t jid; + } job_user_t; + + The jid member is used by the caller to specify the + job to query to determine the owning user. The + r_user member is set by the Job module to the user + ID (uid) that owns the job. + + JOB_GETPRIMEPID + Get the prime (oldest) process pid for a job. The + data argument should point to a structure of type + job_primepid_t, defined as follows: + + typedef struct job_primepid_s { + pid_t r_pid; + uint64_t jid; + } job_primepid_t; + + The jid member is used by the caller to specify the + job to query. The process ID (pid) value will be + returned in the r_pid data member. If the opera- + tion failed, then r_pid will be set to 0 and errno + will be set to indicate the error. + + +EXAMPLES + The following example shows how to print a list of job IDs + for the jobs currently running on the system: You need to + use the following include statements: + + #include + #include + #include + #include + + int + main(void) + { + job_jidcnt_t jidcnt; + job_jidlst_t jidlst; + int i; + + /* Get current number of jobs on system */ + jidcnt.r_val = 0; + + if (paggctl(JOB_NAME, JOB_GETJIDCNT, + (void *)&jidcnt)) { + perror("paggctl: JOB_GETJIDCNT"); + exit(1); + } + + /* No jobs found on system */ + if (jidcnt.r_val == 0) { + printf("No JIDs on system\n"); + return 0; + } + + /* Alloc memory to hold list of jobs */ + jidlst.r_val = jidcnt.r_val; + jidlst.jid = (uint64_t *)malloc( + sizeof(uint64_t) + *jidlst.r_val); + + /* Get list of jobs */ + if (paggctl(JOB_NAME, JOB_GETJIDLST, + (void *)&jidlst)) { + perror("paggctl: JOB_GETJIDLST"); + exit(1); + } + + /* No jobs on system */ + if (jidlst.r_val == 0) { + printf("No JIDs on system\n"); + free(jidlst.jid); + return 0; + } + + /* Print list of jobs on system */ + printf("List of JIDs on system0); + for (i = 0; i < jidlst.r_val; i++) { + printf("\t%0#18Lx\n", jidlst.jid[i]); + } + + /* Free memory alloc'd for list */ + free(jidlst.jid); + + return 0; + + } + + +ERRORS + Under the following conditions, the paggctl function fails + and sets errno to: + + [EBADR] An invalid request code was provided. + + [EBUSY] Attempt to create a new job using a jid + value that is already in use. + + [EFAULT] The data pointer references an invalid + address. + + [EINPROGRESS] The job is in process of dying and being + cleaned up. + + [EINVAL] An invalid argument was specified. + + [ENODATA] The process is not a member of any job. A + jid value could not be + + [ENOMEM] A memory allocation failed. + + [ENOSYS] The paggctl system call in not implemented. + + [ENXIO] The job module is not loaded. + + [EPERM] The process does not have appropriate capa- + bility for the requested operation. found + for the process in question. + + [ESRCH] The process could not be found. + +DIAGNOSTICS + Upon successful completion, paggctl returns a value of 0. + Otherwise, a value of -1 is returned and errno is set to + indicate the error. + +SEE ALSO + paggctl(3), job(7). + diff -Nur linux-2.4.19/Documentation/kdb/kdb.mm linux-2.4.19-sgi211r3/Documentation/kdb/kdb.mm --- linux-2.4.19/Documentation/kdb/kdb.mm Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb.mm Tue Feb 4 15:36:30 2003 @@ -0,0 +1,401 @@ +.TH KDB 8 "2 February 2003" +.hy 0 +.SH NAME +Built-in Kernel Debugger for Linux - v3.0 +.SH "Overview" +This document describes the built-in kernel debugger available +for linux. This debugger allows the programmer to interactively +examine kernel memory, disassemble kernel functions, set breakpoints +in the kernel code and display and modify register contents. +.P +A symbol table is included in the kernel image and in modules which +enables all non-stack symbols (including static symbols) to be used as +arguments to the kernel debugger commands. +.SH "Getting Started" +To include the kernel debugger in a linux kernel, use a +configuration mechanism (e.g. xconfig, menuconfig, et. al.) +to enable the \fBCONFIG_KDB\fP option. Additionally, for accurate +stack tracebacks, it is recommended that the \fBCONFIG_FRAME_POINTER\fP +option be enabled (if present). \fBCONFIG_FRAME_POINTER\fP changes the compiler +flags so that the frame pointer register will be used as a frame +pointer rather than a general purpose register. +.P +After linux has been configured to include the kernel debugger, +make a new kernel with the new configuration file (a make clean +is recommended before making the kernel), and install the kernel +as normal. +.P +You can compile a kernel with kdb support but have kdb off by default, +select \fBCONFIG_KDB_OFF\fR. Then the user has to explicitly activate +kdb by booting with the 'kdb=on' flag or, after /proc is mounted, by +.nf + echo "1" > /proc/sys/kernel/kdb +.fi +You can also do the reverse, compile a kernel with kdb on and +deactivate kdb with the boot flag 'kdb=off' or, after /proc is mounted, +by +.nf + echo "0" > /proc/sys/kernel/kdb +.fi +.P +When booting the new kernel, the 'kdb=early' flag +may be added after the image name on the boot line to +force the kernel to stop in the kernel debugger early in the +kernel initialization process. 'kdb=early' implies 'kdb=on'. +If the 'kdb=early' flag isn't provided, then kdb will automatically be +invoked upon system panic or when the \fBPAUSE\fP key is used from the +keyboard, assuming that kdb is on. Older versions of kdb used just a +boot flag of 'kdb' to activate kdb early, this is still supported but +is deprecated. +.P +Kdb can also be used via the serial port. Set up the system to +have a serial console (see \fIDocumentation/serial-console.txt\fP), you +must also have a user space program such as agetty set up to read from +the serial console.. +The \fBControl-A\fP key sequence on the serial port will cause the +kernel debugger to be entered, assuming that kdb is on, that some +program is reading from the serial console, at least one cpu is +accepting interrupts and the serial consoel driver is still usable. +.P +\fBNote:\fR\ Your distributor may have chosen a different kdb +activation sequence for the serial console. +Consult your distribution documentation. +.P +If you have both a keyboard+video and a serial console, you can use +either for kdb. +Define both video and serial consoles with boot parameters +.P +.nf + console=tty0 console=ttyS0,38400 +.fi +.P +Any kdb data entered on the keyboard or the serial console will be echoed +to both. +.P +While kdb is active, the keyboard (not serial console) indicators may strobe. +The caps lock and scroll lock lights will turn on and off, num lock is not used +because it can confuse laptop keyboards where the numeric keypad is mapped over +the normal keys. +On exit from kdb the keyboard indicators will probably be wrong, they will not match the kernel state. +Pressing caps lock twice should get the indicators back in sync with +the kernel. +.SH "Basic Commands" +There are several categories of commands available to the +kernel debugger user including commands providing memory +display and modification, register display and modification, +instruction disassemble, breakpoints and stack tracebacks. +Any command can be prefixed with '-' which will cause kdb to ignore any +errors on that command, this is useful when packaging commands using +defcmd. +.P +The following table shows the currently implemented standard commands, +these are always available. Other commands can be added by extra +debugging modules, type '?' at the kdb prompt to get a list of all +available commands. +.DS +.TS +box, center; +l | l +l | l. +Command Description +_ +bc Clear Breakpoint +bd Disable Breakpoint +be Enable Breakpoint +bl Display breakpoints +bp Set or Display breakpoint +bph Set or Display hardware breakpoint +bpa Set or Display breakpoint globally +bpha Set or Display hardware breakpoint globally +bt Stack backtrace for current process +btp Stack backtrace for specific process +bta Stack backtrace for all processes +btc Cycle over all live cpus and backtrace each one +cpu Display or switch cpus +dmesg Display system messages +defcmd Define a command as a set of other commands +ef Print exception frame +env Show environment +go Restart execution +help Display help message +id Disassemble Instructions +ll Follow Linked Lists +lsmod List loaded modules +md Display memory contents +mdWcN Display memory contents with width W and count N. +mdr Display raw memory contents +mds Display memory contents symbolically +mm Modify memory contents, words +mmW Modify memory contents, bytes +ps Display process status +reboot Reboot the machine +rd Display register contents +rm Modify register contents +rmmod Remove a module +sections List information on all known sections +set Add/change environment variable +sr Invoke SysReq commands +ss Single step a cpu +ssb Single step a cpu until a branch instruction +.TE +.DE +.P +Some commands can be abbreviated, such commands are indicated by a +non-zero \fIminlen\fP parameter to \fBkdb_register\fP; the value of +\fIminlen\fP being the minimum length to which the command can be +abbreviated (for example, the \fBgo\fP command can be abbreviated +legally to \fBg\fP). +.P +If an input string does not match a command in the command table, +it is treated as an address expression and the corresponding address +value and nearest symbol are shown. +.P +Some of the commands are described here. +Information on the more complicated commands can be found in the +appropriate manual pages. +.TP 8 +cpu +With no parameters, it lists the available cpus, '*' after a cpu number +indicates a cpu that did not respond to the kdb stop signal. +.I cpu +followed by a number will switch to that cpu, you cannot switch to +a cpu marked '*'. +This command is only available if the kernel was configured for SMP. +.TP 8 +dmesg [lines] +Displays the last set of system messages from the kernel buffer. If +kdb logging is on, it is disabled by dmesg and is left as disabled. +If lines is specified, only dump the last 'lines' from the buffer, 0 +dumps all lines. +.TP 8 +defcmd +Defines a new command as a set of other commands, all input until +.I endefcmd +is saved and executed as a package. +.I defcmd +takes three parameters, the command name to be defined and used to +invoke the package, a quoted string containing the usage text and a +quoted string containing the help text for the command. +When using defcmd, it is a good idea to prefix commands that might fail +with '-', this ignores errors so the following commands are still +executed. +For example, +.P +.nf + defcmd diag "" "Standard diagnostics" + set LINES 2000 + set BTAPROMPT 0 + -id %eip-0x40 + -cpu + -ps + -dmesg 80 + -bt + -bta + endefcmd +.fi +.TP 8 +go +Continue normal execution. +Active breakpoints are reestablished and the processor(s) allowed to +run normally. +To continue at a specific address, use +.I rm +to change the instruction pointer then go. +.TP 8 +id +Disassemble instructions starting at an address. +Environment variable IDCOUNT controls how many lines of disassembly +output the command produces. +.TP 8 +lsmod +Internal command to list modules. +This does not use any kernel nor user space services so can be used at any time. +.TP 8 +ps +Display status of all processes in the desired state. +This command does not take any locks (all cpus should be frozen while +kdb is running) so it can safely be used to debug lock problems with +the process table. +Without any parameters, \fBps\fP displays all processes. +If a parameter is specified, it is a single string consisting of the +letters D, R, S, T, Z and U, in any order. +Each letter selects processes in a specific state, when multiple +letters are specified, a process will be displayed if it is in any of +the specified states. +\fBps\ RD\fR displays only tasks that are running or are in an +uninterruptible sleep. +The states are\ :- +.P +.DS +.TS +box, center; +l | l +l | l. +D Uninterruptible sleep +R Running +S Interruptible sleep +T Traced or stopped +Z Zombie +U Unrunnable +.TE +.DE +.P +.TP 8 +reboot +Reboot the system, with no attempt to do a clean close down. +.TP 8 +rmmod +Internal command to remove a module. +This does not use any user space services, however it calls the module +cleanup routine and that routine may try to use kernel services. +Because kdb runs disabled there is no guarantee that the module cleanup +routine will succeed, there is a real risk of the routine hanging and +taking kdb with it. +Use the +.I rmmod +command with extreme care. +.TP 8 +sections +List information for all known sections. The output is one line per +module plus the kernel, starting with the module name. This is +followed by one or more repeats of section name, section start, +section end and section flags. This data is not designed for human +readability, it is intended to tell external debuggers where each +section has been loaded. +.SH INITIAL KDB COMMANDS +kdb/kdb_cmds is a plain text file where you can define kdb commands +which are to be issued during kdb_init(). One command per line, blank +lines are ignored, lines starting with '#' are ignored. kdb_cmds is +intended for per user customization of kdb, you can use it to set +environment variables to suit your hardware or to set standard +breakpoints for the problem you are debugging. This file is converted +to a small C object, compiled and linked into the kernel. You must +rebuild and reinstall the kernel after changing kdb_cmds. This file +will never be shipped with any useful data so you can always override +it with your local copy. Sample kdb_cmds: +.P +.nf +# Initial commands for kdb, alter to suit your needs. +# These commands are executed in kdb_init() context, no SMP, no +# processes. Commands that require process data (including stack or +# registers) are not reliable this early. set and bp commands should +# be safe. Global breakpoint commands affect each cpu as it is booted. + +set LINES=50 +set MDCOUNT=25 +set RECURSE=1 +bp sys_init_module +.fi +.SH INTERRUPTS AND KDB +When a kdb event occurs, one cpu (the initial cpu) enters kdb state. +It uses a cross system interrupt to interrupt the +other cpus and bring them all into kdb state. All cpus run with +interrupts disabled while they are inside kdb, this prevents most +external events from disturbing the kernel while kdb is running. +.B Note: +Disabled interrupts means that any I/O that relies on interrupts cannot +proceed while kdb is in control, devices can time out. The clock tick +is also disabled, machines will lose track of time while they are +inside kdb. +.P +Even with interrupts disabled, some non-maskable interrupt events will +still occur, these can disturb the kernel while you are debugging it. +The initial cpu will still accept NMI events, assuming that kdb was not +entered for an NMI event. Any cpu where you use the SS or SSB commands +will accept NMI events, even after the instruction has finished and the +cpu is back in kdb. This is an unavoidable side effect of the fact that +doing SS[B] requires the cpu to drop all the way out of kdb, including +exiting from the event that brought the cpu into kdb. Under normal +circumstances the only NMI event is for the NMI oopser and that is kdb +aware so it does not disturb the kernel while kdb is running. +.P +Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, +even though the cpu is disabled for interrupts. I have not been able +to track this one down but I suspect that the interrupt was pending +when kdb was entered and it runs when kdb exits through IRET even +though the popped flags are marked as cli(). If any ix86 hardware +expert can shed some light on this problem, please notify the kdb +maintainer. +.SH RECOVERING FROM KDB ERRORS +If a kdb command breaks and kdb has enough of a recovery environment +then kdb will abort the command and drop back into mainline kdb code. +This means that user written kdb commands can follow bad pointers +without killing kdb. Ideally all code should verify that data areas +are valid (using kdb_getarea) before accessing it but lots of calls to +kdb_getarea can be clumsy. +.P +The sparc64 port does not currently provide this error recovery. +If someone would volunteer to write the necessary longjmp/setjmp +code, their efforts would be greatly appreciated. In the +meantime, it is possible for kdb to trigger a panic by accessing +a bad address. +.SH DEBUGGING THE DEBUGGER +kdb has limited support for debugging problems within kdb. If you +suspect that kdb is failing, you can set environment variable KDBDEBUG +to a bit pattern which will activate kdb_printf statements within kdb. +See include/linux/kdb.h, KDB_DEBUG_FLAG_xxx defines. For example +.nf + set KDBDEBUG=0x60 +.fi +activates the event callbacks into kdb plus state tracing in sections +of kdb. +.nf + set KDBDEBUG=0x18 +.fi +gives lots of tracing as kdb tries to decode the process stack. +.P +You can also perform one level of recursion in kdb. If environment +variable RECURSE is not set or is 0 then kdb will either recover from +an error (if the recovery environment is satisfactory) or kdb will +allow the error to percolate, usually resulting in a dead system. When +RECURSE is 1 then kdb will recover from an error or, if there is no +satisfactory recovery environment, it will drop into kdb state to let +you diagnose the problem. When RECURSE is 2 then all errors drop into +kdb state, kdb does not attempt recovery first. Errors while in +recursive state all drop through, kdb does not even attempt to recover +from recursive errors. +.SH KEYBOARD EDITING +kdb supports a command history, which can be accessed via keyboard +sequences. +It supports the special keys on PC keyboards, control characters and +vt100 sequences on a serial console or a PC keyboard. +.P +.DS +.TS +box, center; +l | l | l l | l +l | l | l l | l. +PC Special keys Control VT100 key Codes Action +_ +Backspace ctrl-H Backspace 0x7f Delete character to the left of the cursor +Delete ctrl-D Delete \\e[3~ Delete character to the right of the cursor +Home ctrl-A Home \\e[1~ Go to start of line +End ctrl-E End \\e[4~ Go to end of line +Up arrow ctrl-P Up arrow \\e[A Up one command in history +Down arrow ctrl-N Down arrow \\e[B Down one command in history +Left arrow ctrl-B Left arrow \\e[D Left one character in current command +Right arrow ctrl-F Right arrow \\e[C Right one character in current command +.TE +.DE +.P +There is no toggle for insert/replace mode, kdb editing is always in +insert mode. +Use delete and backspace to delete characters. +.P +kdb also supports tab completion for kernel symbols +Type the start of a kernel symbol and press tab (ctrl-I) to complete +the name +If there is more than one possible match, kdb will append any common +characters and wait for more input, pressing tab a second time will +display the possible matches +The number of matches is limited by environment variable DTABCOUNT, +with a default of 30 if that variable is not set. +.SH AUTHORS +Scott Lurndal, Richard Bass, Scott Foehner, Srinivasa Thirumalachar, +Masahiro Adegawa, Marc Esipovich, Ted Kline, Steve Lord, Andi Kleen, +Sonic Zhang. +.br +Keith Owens - kdb maintainer. +.SH SEE ALSO +.P +linux/Documentation/kdb/kdb_{bp,bt,env,ll,md,rd,sr,ss}.man diff -Nur linux-2.4.19/Documentation/kdb/kdb_bp.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_bp.man --- linux-2.4.19/Documentation/kdb/kdb_bp.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_bp.man Wed Jan 30 15:22:45 2002 @@ -0,0 +1,180 @@ +.TH BD 1 "17 January 2002" +.SH NAME +bp, bpa, bph, bpha, bd, bc, be, bl \- breakpoint commands +.SH SYNOPSIS +bp \fIaddress-expression\fP +.LP +bpa \fIaddress-expression\fP +.LP +bph \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +.LP +bpha \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +.LP +bd \fIbreakpoint-number\fP +.LP +bc \fIbreakpoint-number\fP +.LP +be \fIbreakpoint-number\fP +.LP +bl +.SH DESCRIPTION +.hy 0 +The +.B bp +family of commands are used to establish a breakpoint. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by a +percent symbol '%', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +\fBbph\fP and \fBbpha\fP will force the use of a hardware register, provided +the processor architecture supports them. +.P +The \fIaddress-expression\fP may also consist of a single +asterisk '*' symbol which indicates that the command should +operate on all existing breakpoints (valid only for \fBbc\fP, +\fBbd\fP and \fBbe\fP). +.P +Four different types of +breakpoints may be set: + +.TP 8 +Instruction +Causes the kernel debugger to be invoked from the debug exception +path when an instruction is fetched from the specified address. This +is the default if no other type of breakpoint is requested or when +the \fBbp\fP command is used. + +.TP 8 +DATAR +Causes the kernel debugger to be entered when data of length +\fIlength\fP is read from or written to the specified address. +This type of breakpoint must use a processor debug register which +places an architecture dependent limit on the number of data and I/O +breakpoints that may be established. +The \fBbph\fP or \fBbpha\fP commands must be used. + +.TP 8 +DATAW +Enters the kernel debugger when data of length \fIlength\fP +is written to the specified address. \fIlength\fP defaults +to four bytes if it is not explicitly specified. +Note that the processor may have already overwritten the prior data at +the breakpoint location before the kernel debugger is invoked. +The prior data should be saved before establishing the breakpoint, if +required. +The \fBbph\fP or \fBbpha\fP commands must be used. + +.TP 8 +IO +Enters the kernel debugger when an \fBin\fP or \fBout\fP instruction +targets the specified I/O address. The \fBbph\fP or \fBbpha\fP +commands must be used. + +.P +The +.B bpha +command will establish a breakpoint on all processors in an +SMP system. This command is not available in an uniprocessor +kernel. +.P +The +.B bd +command will disable a breakpoint without removing it from the kernel +debugger's breakpoint table. +This can be used to keep breakpoints in the table without exceeding the +architecture limit on breakpoint registers. +.P +The +.B be +command will re-enable a disabled breakpoint. +.P +The +.B bc +command will clear a breakpoint from the breakpoint table. +.P +The +.B bl +command will list the existing set of breakpoints. +.SH LIMITATIONS +There is a compile time limit of sixteen entries in the +breakpoint table at any one time. +.P +There are architecture dependent limits on the number of hardware +breakpoints that can be set. +.IP ix86 8 +Four. +.PD 0 +.IP ia64 8 +? +.PD 0 +.IP sparc64 8 +None. +.PD 1 +When issuing the "go" command after entering the debugger due to +a breakpoint, kdb will silently perform a single step in order to +reapply the breakpoint. The sparc64 port has some limitations on +single stepping, which may limit where a breakpoint may be safely +set. Please read the man page for \fBss\fP for more information. +.SH ENVIRONMENT +The breakpoint subsystem does not currently use any environment +variables. +.SH SMP CONSIDERATIONS +Using +.B bc +is risky on SMP systems. +If you clear a breakpoint when another cpu has hit that breakpoint but +has not been processed then it may not be recognised as a kdb +breakpoint, usually resulting in incorrect program counters and kernel +panics. +It is safer to disable the breakpoint with +.BR bd , +then +.B go +to let any other processors that are waiting on the breakpoint to +clear. +After all processors are clear of the disabled breakpoint then it is +safe to clear it using +.BR bc . +.P +Breakpoints which use the processor breakpoint registers +are only established on the processor which is +currently active. If you wish breakpoints to be universal +use the +.B bpa +or +.B bpha +commands. +.SH EXAMPLES +.TP 8 +bp schedule +Sets an instruction breakpoint at the begining of the +function \fBschedule\fP. + +.TP 8 +bp schedule+0x12e +Sets an instruction breakpoint at the instruction located +at \fBschedule\fP+\fI0x12e\fP. + +.TP 8 +bph ttybuffer+0x24 dataw +Sets a data write breakpoint at the location referenced by +\fBttybuffer\fP+\fI0x24\fP for a length of four bytes. + +.TP 8 +bph 0xc0254010 datar 1 +Establishes a data reference breakpoint at address \fB0xc0254010\fP +for a length of one byte. + +.TP 8 +bp +List current breakpoint table. + +.TP 8 +bd 0 +Disable breakpoint #0. + +.TP 8 +bc * +Clear all breakpoints diff -Nur linux-2.4.19/Documentation/kdb/kdb_bt.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_bt.man --- linux-2.4.19/Documentation/kdb/kdb_bt.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_bt.man Tue Feb 4 15:36:30 2003 @@ -0,0 +1,214 @@ +.TH BT 1 "2 February 2003" +.SH NAME +bt \- Stack Traceback command +.SH SYNOPSIS +bt [ ] +.LP +btp +.LP +btc +.LP +bta [ DRSTZU ] +.SH DESCRIPTION +.hy 0 +The +.B bt +command is used to print a stack traceback. It uses the +current registers (see \fBrd\fP command) to determine +the starting context and attempts to provide a complete +stack traceback for the active thread. If \fIstack-frame-address\fP +is supplied, it is assumed to point to the start of a valid +stack frame and the stack will be traced back from that +point (e.g. on i386 architecture, \fIstack-frame-address\fP +should be the stack address of a saved \fB%eip\fP value from a \fBcall\fP +instruction. on sparc64 architecture, it should be a pointer to a +saved register window, as is found in the \fB%fp\fP register). +.P +If present, a kernel configuration option \fBCONFIG_FRAME_POINTER\fP +should be enabled so that the compiler will utilize the frame pointer +register properly to maintain a stack which can be correctly +analyzed. Some architectures (e.g. sparc64) always use +\fBCONFIG_FRAME_POINTER\fP, and so the option is not present. +.P +The \fBbt\fP command will attempt to analyze the stack without +frame pointers if the \fBCONFIG_FRAME_POINTER\fP option is not +enabled, but the analysis is difficult and may not produce +accurate nor complete results. +.P +The \fBbtp\fP command will analyze the stack for the given +process identification (see the \fBps\fP command). +.P +The \fBbtc\fP command will analyze the stack for the current process on +each live cpu. It automatically switches to the first live cpu, does +\fBbt\fR, switches to the next live cpu etc., until it has done the +last live cpu. It then switches to the initial cpu (the one that first +entered kdb) and asks for more input. +Cpus that did not respond to the initial kdb request are skipped, in +the output from the cpu command, the unavailable cpus have '*' against +them in. +.P +The \fBbta\fP command lists the stack for all processes in the desired +state. +Without any parameters, \fBbta\fP gives a backtrace for all processes. +If a parameter is specified, it is a single string consisting of the +letters D, R, S, T, Z and U, in any order. +Each letter selects processes in a specific state, when multiple +letters are specified, a process will be traced if it is in any of the +specified states. +\fBbta\ RD\fR displays only tasks that are running or are in an +uninterruptible sleep. +The states are\ :- +.IP D 3 +Uninterruptible sleep. +.PD 0 +.IP R 3 +Running. +The process may not be on a cpu at the moment, but it is ready to run. +The header line above the backtrace contains '1' in the fourth field if +the process is actually on a cpu. +.IP S 3 +Interruptible sleep. +.IP T 3 +Traced or stopped. +.IP Z 3 +Zombie. +.IP U 3 +Unrunnable. +.PD 1 +.P +For each function, the stack trace prints at least two lines. +The first line contains four or five fields\ :- +.IP * 3 +The pointer to the previous stack frame, blank if there is no valid +frame pointer. +.PD 0 +.IP * 3 +The current address within this frame. +.IP * 3 +The address converted to a function name (actually the first non-local +label which is <= the address). +.IP * 3 +The offset of the address within the function. +.IP * 3 +Any parameters to the function. +.PD 1 +.PP +On the next line there are five fields which are designed to make it +easier to match the trace against the kernel code\ :- +.IP * 3 +The module name that contains the address, "kernel" if it is in the +base kernel. +.PD 0 +.IP * 3 +The section name that contains the address. +.IP * 3 +The start address of the section. +.IP * 3 +The start address of the function. +.IP * 3 +The end address of the function (the first non-local label which is > +the address). +.PD 1 +.PP +If arguments are being converted to symbols, any argument which +converts to a kernel or module address is printed as\ :- +.IP * 3 +Argument address. +.PD 0 +.IP * 3 +The module name that contains the address, "kernel" if it is in the +base kernel. +.IP * 3 +The symbol name the argument maps to. +.IP * 3 +The offset of the argument from the symbol, suppressed if 0. +.PD 1 +.SH MATCHING TRACE TO KERNEL CODE +The command "objdump\ -S" will disassemble an object and, if the code +was compiled with debugging (gcc flag -g), objdump will interleave the +C source lines with the generated object. +.PP +A complete objdump of the kernel or a module is too big, normally you +only want specific functions. +By default objdump will only print the .text section but Linux uses +other section names for executable code. +When objdump prints relocatable objects (modules) it uses an offset of +0 which is awkward to relate to the stack trace. +The five fields which are printed for each function are designed to +make it easier to match the stack trace against the kernel code using +"objdump\ -S". +.PP +If the function is in the kernel then you need the section name, the +start and end address of the function. The command is +.PP +.nf + objdump -S -j \\ + --start-address= \\ + --stop-address= \\ + /usr/src/linux/vmlinux +.fi +.PP +If the function is in a module then you need the section name, the +start address of the section, the start and end address of the +function, the module name. The command is +.PP +.nf + objdump -S -j \\ + --adjust-vma= \\ + --start-address= \\ + --stop-address= \\ + /path/to/module/.o +.fi +.PP +All addresses to objdump must be preceded by '0x' if they are in hex, +objdump does not assume hex. +The stack trace values are printed with leading '0x' to make it easy to +run objdump. +.SH LIMITATIONS +If the kernel is compiled without frame pointers, stack tracebacks +may be incomplete. The \fBmds %esp\fP (i386) or \fBmds %fp\fP (sparc64) +command may be useful in attemping to determine the actual stack +traceback manually. +.P +A stack trace can be misleading if any code in a function exit has been +executed, the stack is partially unwound at that stage. +.P +The \fBbt\fP command may print more arguments for a function +than that function accepts; For sparc64, this will always happen +as the debugger cannot determine the correct number. For i386, this happens +when the C compiler doesn't immediately pop the arguments off the stack upon +return from a called function. When this is this case, these extra +stack words will be considered additional arguments by the \fBbt\fP +command. +.SH ENVIRONMENT +The \fBBTARGS\fP environment variable governs the maximum number +of arguments that are printed for any single function. +.PP +If the \fBBTSYMARG\fP environment variable is non-zero then any +arguments that fall within the kernel are converted to symbols. +.PP +If the \fBNOSECT\fP environment variable is non-zero then the +section information is suppressed. +.PP +The \fBBTAPROMPT\fP environment variable controls the prompt after each +process is listed by the \fBbta\fP command. If \fBBTAPROMPT\fP is not +set or is non-zero then \fBbta\fP issues a prompt after each process is +listed. If \fBBTAPROMPT\fP is set to zero then no prompt is issued and +all processes are listed without human intervention. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +Entering kdb (0xc3cb4000) due to Breakpoint @ 0xc011725d +Instruction(i) breakpoint #0 at 0xc011725c +qm_modules+0xd1: movl %ebp,%esp +kdb> bt + EBP EIP Function(args) +0xc3cb5f98 0xc011725d qm_modules+0xd1 (0x80721c0, 0x100, 0xbfff5000) + kernel .text 0xc0100000 0xc011718c 0xc0117264 +0xc3cb5fbc 0xc0117875 sys_query_module+0x1b1 (0x0, 0x1, 0x80721c0, 0x100, 0xbfff5000) + kernel .text 0xc0100000 0xc01176c4 0xc01178e8 + 0xc01095f8 system_call+0x34 + kernel .text 0xc0100000 0xc01095c4 0xc01095fc diff -Nur linux-2.4.19/Documentation/kdb/kdb_env.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_env.man --- linux-2.4.19/Documentation/kdb/kdb_env.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_env.man Wed Jan 30 15:22:45 2002 @@ -0,0 +1,46 @@ +.TH ENV 1 "24 September 2000" +.SH NAME +env, set \- Environment manipulation commands +.SH SYNOPSIS +env +.LP +set \fIenvironment-variable\fP=\fIvalue\fP +.SH DESCRIPTION +The kernel debugger contains an environment which contains a series +of name-value pairs. Some environment variables are known to the +various kernel debugger commands and have specific meaning to the +command; such are enumerated on the respective reference material. +.P +Arbitrary environment variables may be created and used with +many commands (those which require an \fIaddress-expression\fP). +.P +The +.B env +command is used to display the current environment. +.P +The +.B set +command is used to alter an existing environment variable or +establish a new environment variable. +.SH LIMITATIONS +There is a compile-time limit of 33 environment variables. +.P +There is a compile-time limit of 512 bytes (\fBKDB_ENVBUFSIZE\fP) +of heap space available for new environment variables and for +environment variables changed from their compile-time values. +.SH ENVIRONMENT +These commands explicitly manipulate the environment. +.SH SMP CONSIDERATIONS +None. +.SH USER SETTINGS +You can include "set" commands in kdb/kdb_cmds (see kdb.mm) to define +your environment variables at kernel startup. +.SH EXAMPLES +.TP 8 +env +Display current environment settings. + +.TP 8 +set IDCOUNT=100 +Set the number of lines to display for the \fBid\fP command +to the value \fI100\fP. diff -Nur linux-2.4.19/Documentation/kdb/kdb_ll.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_ll.man --- linux-2.4.19/Documentation/kdb/kdb_ll.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_ll.man Wed Jan 30 15:22:45 2002 @@ -0,0 +1,134 @@ +.TH LL 1 "19 April 1999" +.SH NAME +ll \- Linked List examination +.SH SYNOPSIS +ll +.SH DESCRIPTION +The +.B ll +command is used to execute a single command repetitively for +each element of a linked list. +.P +The command specified by will be executed with a single +argument, the address of the current element. +.SH LIMITATIONS +Be careful if using this command recursively. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +# cd modules +# insmod kdbm_vm.o +# Entering kdb on processor 0 due to PAUSE +kdb> ps +Task Addr Pid Parent cpu lcpu Tss Command +0xc03de000 0000000001 0000000000 0000 0000 0xc03de2d4 init +0xc0090000 0000000002 0000000001 0000 0000 0xc00902d4 kflushd +0xc000e000 0000000003 0000000001 0000 0000 0xc000e2d4 kpiod +0xc000c000 0000000004 0000000001 0000 0000 0xc000c2d4 kswapd +0xc7de2000 0000000056 0000000001 0000 0000 0xc7de22d4 kerneld +0xc7d3a000 0000000179 0000000001 0000 0000 0xc7d3a2d4 syslogd +0xc7a7e000 0000000188 0000000001 0000 0000 0xc7a7e2d4 klogd +0xc7a04000 0000000199 0000000001 0000 0000 0xc7a042d4 atd +0xc7b84000 0000000210 0000000001 0000 0000 0xc7b842d4 crond +0xc79d6000 0000000221 0000000001 0000 0000 0xc79d62d4 portmap +0xc798e000 0000000232 0000000001 0000 0000 0xc798e2d4 snmpd +0xc7904000 0000000244 0000000001 0000 0000 0xc79042d4 inetd +0xc78fc000 0000000255 0000000001 0000 0000 0xc78fc2d4 lpd +0xc77ec000 0000000270 0000000001 0000 0000 0xc77ec2d4 sendmail +0xc77b8000 0000000282 0000000001 0000 0000 0xc77b82d4 gpm +0xc7716000 0000000300 0000000001 0000 0000 0xc77162d4 smbd +0xc7ee2000 0000000322 0000000001 0000 0000 0xc7ee22d4 mingetty +0xc7d6e000 0000000323 0000000001 0000 0000 0xc7d6e2d4 login +0xc778c000 0000000324 0000000001 0000 0000 0xc778c2d4 mingetty +0xc78b6000 0000000325 0000000001 0000 0000 0xc78b62d4 mingetty +0xc77e8000 0000000326 0000000001 0000 0000 0xc77e82d4 mingetty +0xc7708000 0000000327 0000000001 0000 0000 0xc77082d4 mingetty +0xc770e000 0000000328 0000000001 0000 0000 0xc770e2d4 mingetty +0xc76b0000 0000000330 0000000001 0000 0000 0xc76b02d4 update +0xc7592000 0000000331 0000000323 0000 0000 0xc75922d4 ksh +0xc7546000 0000000338 0000000331 0000 0000 0xc75462d4 su +0xc74dc000 0000000339 0000000338 0000 0000 0xc74dc2d4 ksh +kdb> md 0xc74dc2d4 +c74dc2d4: 00000000 c74de000 00000018 00000000 .....`MG........ +c74dc2e4: 00000000 00000000 00000000 074de000 .............`M. +c74dc2f4: c01123ff 00000000 00000000 00000000 #.@............ +c74dc304: 00000000 00000000 c74dded0 00000000 ........P^MG.... +[omitted] +c74dc474: 00000000 00000000 00000000 00000000 ................ +c74dc484: 00000000 c7c15d00 c77b0900 c026fbe0 .....]AG..{G`{&@ +c74dc494: 00000000 c76c2000 00000000 00000000 ..... lG........ +c74dc4a4: 00000000 00000000 00000000 c74dc4ac ............,DMG +kdb> md 0xc026fbe0 +c026fbe0: c0262b60 00000000 c7594940 c74de000 @HYG....@IYG.`MG +[omitted] +kdb> md 0xc0262b60 +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +kdb> ll c0262b60 12 md +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +c7bec360: c0266660 0804c000 0804d000 c7becb20 `f&@.@...P.. K>G +c7becb20: c0266660 0804d000 08050000 c7bec3a0 `f&@.P...... C>G +c7bec3a0: c0266660 40000000 40009000 c7bec420 `f&@...@...@ D>G +c7bec420: c0266660 40009000 4000b000 c7bec4a0 `f&@...@.0.@ D>G +c7bec4a0: c0266660 4000b000 40010000 c7bec8e0 `f&@.0.@...@`H>G +c7bec8e0: c0266660 40010000 400a1000 c7becbe0 `f&@...@...@`K>G +c7becbe0: c0266660 400a1000 400a8000 c7becc60 `f&@...@...@`L>G +c7becc60: c0266660 400a8000 400b4000 c7952300 `f&@...@.@.@.#.G +c7952300: c0266660 400b5000 400bc000 c79521c0 `f&@.P.@.@.@@!.G +c79521c0: c0266660 400bc000 400bd000 c7bec6e0 `f&@.@.@.P.@`F>G +c7bec6e0: c0266660 bffff000 c0000000 00000000 `f&@.p?...@.... +kdb> +kdb> ll c0262b60 12 vm +struct vm_area_struct at 0xc0262b60 for 56 bytes +vm_start = 0x8048000 vm_end = 0x804c000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7bec360 for 56 bytes +vm_start = 0x804c000 vm_end = 0x804d000 +page_prot = 0x25 avl_height = -31808 vm_offset = 0x3000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7becb20 for 56 bytes +vm_start = 0x804d000 vm_end = 0x8050000 +page_prot = 0x25 avl_height = -28664 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec3a0 for 56 bytes +vm_start = 0x40000000 vm_end = 0x40009000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec420 for 56 bytes +vm_start = 0x40009000 vm_end = 0x4000b000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x8000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec4a0 for 56 bytes +vm_start = 0x4000b000 vm_end = 0x40010000 +page_prot = 0x25 avl_height = 26853 vm_offset = 0x0 +flags: READ MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec8e0 for 56 bytes +vm_start = 0x40010000 vm_end = 0x400a1000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becbe0 for 56 bytes +vm_start = 0x400a1000 vm_end = 0x400a8000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x90000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becc60 for 56 bytes +vm_start = 0x400a8000 vm_end = 0x400b4000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7952300 for 56 bytes +vm_start = 0x400b5000 vm_end = 0x400bc000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc79521c0 for 56 bytes +vm_start = 0x400bc000 vm_end = 0x400bd000 +page_prot = 0x25 avl_height = -16344 vm_offset = 0x6000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec6e0 for 56 bytes +vm_start = 0xbffff000 vm_end = 0xc0000000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN +kdb> diff -Nur linux-2.4.19/Documentation/kdb/kdb_md.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_md.man --- linux-2.4.19/Documentation/kdb/kdb_md.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_md.man Wed Jan 30 15:22:45 2002 @@ -0,0 +1,125 @@ +.TH MD 1 "25 September, 2001" +.SH NAME +md, mdWcN, mdr, mds, mm, mmW\- Memory manipulation commands +.SH SYNOPSIS +md [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +md\fIW\fRc\fIn\fR [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mdr \fIaddress-expression\fP,\fIbytes\fP +.LP +mds [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mm \fIaddress-expression\fP \fInew-contents\fP +.LP +mm\fIW\fR \fIaddress-expression\fP \fInew-contents\fP +.SH DESCRIPTION +The +.B md +command is used to display the contents of memory. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by one or more +percent symbols '%', an environment variable name preceeded by +a currency symbol '$', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +If an address is specified and the \fIline-count\fP or \fIradix\fP arguments +are omitted, they default to the values of the \fBMDCOUNT\fP and \fBRADIX\fP +environment variables respectively. If the \fBMDCOUNT\fP or \fBRADIX\fP +environment variables are unset, the appropriate defaults will be used [see +\fBENVIRONMENT\fP below]. If no address is specified then md resumes +after the last address printed, using the previous values of count and +radix. The start address is rounded down to a multiple of the +BYTESPERWORD (md) or width (md\fIW\fR). +.P +md uses the current value of environment variable \fBBYTESPERWORD\fP to +read the data. When reading hardware registers that require special +widths, it is more convenient to use md\fIW\fRc\fIn\fR where \fIW\fR is +the width for this command and \fRc\fIn\fR is the number of entries to +read. For example, md1c20 reads 20 bytes, 1 at a time. To continue +printing just type md, the width and count apply to following md +commands with no parameters. \fBNote:\fR The count is the number of +repeats of the width, unlike MDCOUNT which gives the number of md lines +to print. +.P +The +.B mdr +command displays the raw contents of memory, starting at the specified +address for the specified number of bytes. +The data is printed in one line without a leading address and no +trailing character conversion. +.B mdr +is intended for interfacing with external debuggers, it is of little +use to humans. +.P +The +.B mds +command displays the contents of memory one word per line and +attempts to correlate the contents of each word with a symbol +in the symbol table. If no symbol is found, the ascii representation +of the word is printed, otherwise the symbol name and offset from +symbol value are printed. +By default the section data is printed for kernel symbols. +.P +The +.B mm +and +\fBmm\fIW\fR +commands allow modification of memory. The bytes at the address +represented by \fIaddress-expression\fP are changed to +\fInew-contents\fP. \fInew-contents\fP is allowed to be an +\fIaddress-expression\fP. +.B mm +changes a machine word, \fBmm\fIW\fR changes \fIW\fR bytes at that +address. +.SH LIMITATIONS +None. +.SH ENVIRONMENT +.TP 8 +MDCOUNT +This environment variable (default=8) defines the number of lines +that will be displayed by each invocation of the \fBmd\fP command. + +.TP 8 +RADIX +This environment variable (default=16) defines the radix used to +print the memory contents. + +.TP 8 +BYTESPERWORD +This environment variable (default=4) selects the width of output +data when printing memory contents. Select the value two to get +16-bit word output, select the value one to get byte output. + +.TP 8 +LINES +This environment variable governs the number of lines of output +that will be presented before the kernel debugger built-in pager +pauses the output. This variable only affects the functioning +of the \fBmd\fP and \fBmds\fP if the \fBMDCOUNT\fP variable +is set to a value greater than the \fBLINES\fP variable. + +.TP 8 +If the \fBNOSECT\fP environment variable is non-zero then the +section information is suppressed. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +md %edx +Display memory starting at the address contained in register \fB%edx\fP. + +.TP 8 +mds %esp +Display stack contents symbolically. This command is quite useful +in manual stack traceback. + +.TP 8 +mm 0xc0252110 0x25 +Change the memory location at 0xc0252110 to the value 0x25. + +.TP 8 +md chrdev_table 15 +Display 15 lines (at 16 bytes per line) starting at address +represented by the symbol \fIchrdev_table\fP. diff -Nur linux-2.4.19/Documentation/kdb/kdb_rd.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_rd.man --- linux-2.4.19/Documentation/kdb/kdb_rd.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_rd.man Wed Jan 30 15:22:45 2002 @@ -0,0 +1,81 @@ +.TH RD 1 "17 January 2002" +.SH NAME +rd, rm\- Register manipulation commands +.SH SYNOPSIS +rd [c|d|u] +.LP +rm \fIregister-name\fP \fInew-contents\fP +.LP +ef
+.SH DESCRIPTION +The +.B rd +command is used to display the contents of processor registers. +Without any arguments, the rd command displays the contents of +the general register set at the point at which the kernel debugger +was entered. +.P +With the 'c' argument, the processor control registers +%cr0, %cr1, %cr2 and %cr4 are displayed, while with the 'd' argument +the processor debug registers are displayed. If the 'u' argument +is supplied, the registers for the current task as of the last +time the current task entered the kernel are displayed. +.P +On ix86, the +.B rm +command allows modification of a register. The following +register names are valid: \fB%eax\fP, \fB%ebx\fP, \fB%ecx\fP, +\fB%edx\fP, \fB%esi\fP, \fB%edi\fP, \fB%esp\fP, \fB%eip\fP, +and \fB%ebp\fP. Note that if two '%' symbols are used +consecutively, the register set displayed by the 'u' argument +to the \fBrd\fP command is modified. +.P +The debug registers, \fBdr0\fP through \fBdr3\fP and both +\fBdr6\fP and \fBdr7\fP can also be modified with the \fBrm\fP +command. +.P +On sparc64, the valid registers are named \fB%g0\fP through +\fB%g7\fP, \fB%l0\fP through \fB%l7\fP, \fB%o0\fP through +\fB%o7\fP, and \fB%i0\fP through \fB%i7\fP, with the exceptions +that \fB%o6\fP is called \fB%sp\fP and that \fB%i6\fP is called +\fB%fp\fP. The registers \fB%tstate\fP, \fB%tpc\fP, \fB%tnpc\fP, +\fB%y\fP, and \fB%fprs\fP provide state information at the time +the system entered kdb. Additionally, when viewing registers, two +convenience names are provided: \fB%®s\fP shows the +address on the stack of the current registers, and \fB%csp\fP +shows the current stack pointer within kdb itself. +.P +The +.B ef +command displays an exception frame at the specified address. +.SH LIMITATIONS +Currently the \fBrm\fP command will not allow modification of the +control registers. +.P +Currently neither the \fBrd\fP command nor the \fBrm\fP command will +display or modify the model specific registers on the Pentium +and Pentium Pro families. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +rd +Display general register set. + +.TP 8 +rm %eax 0 +Set the contents of \fB%eax\fP to zero. This will be the +value of %eax when kdb returns from the condition which +invoked it. + +.TP 8 +rm %%eax 0 +Set the value of the \fB%eax\fP register to zero. This will +be the value the user-mode application will see upon returning +from the kernel. + +.TP 8 +rm dr0 0xc1287220 +Set the value of the \fBdr0\fB register to \f(CW0xc1287220\fP. diff -Nur linux-2.4.19/Documentation/kdb/kdb_sr.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_sr.man --- linux-2.4.19/Documentation/kdb/kdb_sr.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_sr.man Tue Feb 4 15:36:30 2003 @@ -0,0 +1,68 @@ +.TH SR 1 "7 October 2002" +.SH NAME +sr \- invoke sysrq commands from kdb +.SH SYNOPSIS +sr \fIx\fP +.SH DESCRIPTION +.hy 0 +The +.B sr +command invokes the existing sysrq handler code in the kernel. +This command takes a single character which is passed to sysrq +processing, as if you had entered the sysrq key sequence followed by +that character. +.P +.B Caveats: +.P +kdb will always call the sysrq code but sysrq may be disabled. +If you expect to use sysrq functions during debugging then +.IP "" +echo "1" > /proc/sys/kernel/sysrq +.P +before starting the debug session. +Alternatively issue +.IP "" +mm4 sysrq_enabled 1 +.P +during debugging. +.P +The sysrq code prints a heading using console loglevel 7 then reverts +to the original loglevel for the rest of the sysrq processing. +If the rest of the sysrq output is printed at a level below your +current loglevel then you will not see the output on the kdb console, +the output will only appear in the printk buffer. +It is the user's responsibility to set the loglevel correctly if they +want to see the sysrq output on the console. +Issue +.IP "" +sr 7 +.P +before any other +.B sr +commands if you want to see the output on the console. +You may even have to adjust the default message loglevel in order to +see any output from +.BR sr . +See Documentation/sysctl/kernel.txt for details on setting console +loglevels via /proc. +You can also adjust the loglevel variables via kdb +.BR mm ; +on older kernels there are variables such as default_message_level, on +newer kernels all the loglevel variables are in array console_printk, +see kernel/printk.c for your kernel. +.P +Operations that require interrupt driven I/O can be invoked from kdb +.BR sr , +but they will not do anything until you type 'go' to exit from kdb +(interrupts are disabled while in kdb). +There is no guarantee that these operations will work, if the machine +entered kdb because of an error then interrupt driven I/O may already +be dead. +Do not assume that +.B sr\ s +does anything useful. +.P +The sysrq handler uses locks and calls printk which also uses locks. +If the sysrq handler or any of the sysrq functions have to wait for a +lock then they will never return and kdb will appear to hang. +Invoking sysrq code from kdb is inherently unsafe. diff -Nur linux-2.4.19/Documentation/kdb/kdb_ss.man linux-2.4.19-sgi211r3/Documentation/kdb/kdb_ss.man --- linux-2.4.19/Documentation/kdb/kdb_ss.man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/kdb_ss.man Wed Jan 30 15:22:45 2002 @@ -0,0 +1,109 @@ +.TH SS 1 "17 January 2002" +.SH NAME +ss, ssb \- Single Step +.SH SYNOPSIS +ss +.LP +ssb +.SH DESCRIPTION +The +.B ss +command is used to execute a single instruction and return +to the kernel debugger. +.P +Both the instruction that was single-stepped and the next +instruction to execute are printed. +.P +The \fBssb\fP command will execute instructions from the +current value of the instruction pointer. Each instruction +may be printed as it is executed, depending upon architecture; +execution will stop at any instruction which would cause the flow +of control to change (e.g. branch, call, interrupt instruction, +return, etc.) +.SH LIMITATIONS +On sparc64, there are some circumstances where single-stepping +can be dangerous. Do not single-step across an instruction which +changes the interrupt-enable bit in %tstate. Do not single step +through code which is invoked when entering or leaving the +kernel, particularly any kernel entry code before %tl is set to +0, or any kernel exit code after %tl is set to 1. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +Other processors are held in the kernel debugger when the instruction +is traced. Single stepping though code that requires a lock which is +in use by another processor is an exercise in futility, it will never +succeed. +.SH INTERRUPT CONSIDERATIONS +When a kdb event occurs, one cpu (the initial cpu) enters kdb state. +It uses a cross system interrupt to interrupt the +other cpus and bring them all into kdb state. All cpus run with +interrupts disabled while they are inside kdb, this prevents most +external events from disturbing the kernel while kdb is running. +.B Note: +Disabled interrupts means that any I/O that relies on interrupts cannot +proceed while kdb is in control, devices can time out. The clock tick +is also disabled, machines will lose track of time while they are +inside kdb. +.P +Even with interrupts disabled, some non-maskable interrupt events +will still occur, these can disturb the kernel while you are +debugging it. The initial cpu will still accept NMI events, +assuming that kdb was not entered for an NMI event. Any cpu +where you use the SS or SSB commands will accept NMI events, even +after the instruction has finished and the cpu is back in kdb. +This is an unavoidable side effect of the fact that doing SS[B] +requires the cpu to drop all the way out of kdb, including +exiting from the NMI event that brought the cpu into kdb. Under +normal circumstances the only NMI event is for the NMI oopser and +that is kdb aware so it does not disturb the kernel while kdb is +running. +.P +Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, +even though the cpu is disabled for interrupts. I have not been able +to track this one down but I suspect that the interrupt was pending +when kdb was entered and it runs when kdb exits through IRET even +though the popped flags are marked as cli(). If any ix86 hardware +expert can shed some light on this problem, please notify the kdb +maintainer. +.SH EXAMPLES +.nf +.na +.ft CW +kdb> bp gendisk_head datar 4 +Data Access Breakpoint #0 at 0xc024ddf4 (gendisk_head) in dr0 is enabled on cpu 0 +for 4 bytes +kdb> go +... +[root@host /root]# cat /proc/partitions +Entering kdb on processor 0 due to Debug Exception @ 0xc01845e3 +Read/Write breakpoint #0 at 0xc024ddf4 +[0]kdb> ssb +sd_finish+0x7b: movzbl 0xc02565d4,%edx +sd_finish+0x82: leal 0xf(%edx),%eax +sd_finish+0x85: sarl $0x4,%eax +sd_finish+0x88: movl 0xc0256654,%ecx +sd_finish+0x8e: leal (%eax,%eax,4),%edx +sd_finish+0x91: leal (%eax,%edx,2),%edx +sd_finish+0x94: movl 0xc0251108,%eax +sd_finish+0x99: movl %eax,0xffffffc(%ecx,%edx,4) +sd_finish+0x9d: movl %ecx,0xc0251108 +sd_finish+0xa3: xorl %ebx,%ebx +sd_finish+0xa5: cmpb $0x0,0xc02565d4 +[0]kdb> go +[root@host /root]# + +[0]kdb> ss +sys_read: pushl %ebp +SS trap at 0xc01274c1 +sys_read+0x1: movl %esp,%ebp +[0]kdb> ss +sys_read+0x1: movl %esp,%ebp +SS trap at 0xc01274c3 +sys_read+0x3: subl $0xc,%esp +[0]kdb> ss +sys_read+0x3: subl $0xc,%esp +SS trap at 0xc01274c6 +sys_read+0x6: pushl %edi +[0]kdb> + diff -Nur linux-2.4.19/Documentation/kdb/slides linux-2.4.19-sgi211r3/Documentation/kdb/slides --- linux-2.4.19/Documentation/kdb/slides Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/kdb/slides Fri Apr 26 11:07:18 2002 @@ -0,0 +1,1383 @@ +#! /opt/cpg/bin/do-mgp +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%deffont "standard" tfont "comic.ttf" +%deffont "thick" tfont "arialb.ttf" +%deffont "typewriter" xfont "courier new-bold-r" +%deffont "type2writer" xfont "arial narrow-bold-r" +%% +%% Default settings per each line numbers. +%% +#%default 1 leftfill, size 2, fore "black", back "LemonChiffon2", font "thick" +%default 1 leftfill, size 2, fore "black", back "white", font "thick" +%default 2 size 10, vgap 10, prefix " ", center +%default 3 size 2, bar "gray70", vgap 10 +%default 4 size 6, fore "black", vgap 30, prefix " ", font "standard", left +%% +%% Default settings that are applied to TAB-indented lines. +%% +%tab 1 size 4, vgap 35, prefix " ", icon arc "red" 40 +%tab 2 size 4, vgap 20, prefix " ", icon delta3 "blue" 40 +%tab 3 size 4, vgap 20, prefix " ", icon delta3 "green" 40 +%% +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB - Kernel Debugger + + + +%size 7,center, font "thick" +Introduction + +And + +Demonstration + + +%size 3 + +February 5, 2002 IBM Linux Technology Center Paul Dorwin +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +IBM Legal + + + IBM Legal requires this information: + +%size 3 + + THE INFORMATION IN THE FOLLOWING PRESENTATION IS PREPARED + SOLELY FOR THE INFORMATION OF THE READER, AND COMES "AS IS" + AND WITHOUT WARRANTY OR REPRESENATION OF ANY KIND. + + ANY PARTY USING THE MATERIALS IN THIS PRESENTATION DOES SO + AT ITS OWN RISK LIABILITY AND THE PROVIDER OF THE MATERIALS + ACCEPTS NO RISK OR LIABILITY FOR SUCH USE OR RESULTING FROM + DISSEMINATION TO OR USE BY ANY OTHER PARTY + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Agenda + +%size 5 + + Installing and Configuring KDB + + KDB Commands + + Scull Demo + + Setting Breakpoints + + Displaying Data Structures + + Kernel Data structures + + Take a walk through an IO operation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Installing Configuring KDB + + + Install KDB patch. + Start with a clean source tree + Apply architecture specific patches + Obtain patch for your kernel version + see http://oss.sgi.com/projects/kdb/ + Apply the kdb patch + patch -p 1 -N -u -i /path/to/patch + Apply any other patches + Build and reboot on your kdb enabled kernel + Man pages can be found at Documentation/kdb + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Configuring KDB + + + Config kernel with the following options: + These are documented in Documentation/Configure.help + + CONFIG_KDB=y + Enable compilation of KDB in the kernel.. + Setting this also sets CONFIG_KALLSYMS=y. + CONFIG_KDB_MODULES=n + KDB may be extended, compiling kdb/modules. + CONFIG_KDB_OFF=n + y = KDB is disabled by default. + boot with kdb=on to enable at boot. + /proc/sys/kernel/kdb to enable/disable when system is up. + CONFIG_KALLSYMS=y + This causes all symbols to be exported. + CONFIG_FRAME_POINTER=y +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Invoking KDB + + + KDB can be invoked in the following ways: + + Early init with "kdb=early" lilo flag + Hits breakpoint prior to fork_init() (init/main.c) + + Serial console with CNTRL-A + + Console with PAUSE key + + When a pre-set breakpoint is hit + + On panic + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + KDB environment + env Show environment variables + set Set environment variables + help Display Help Message + ? Display Help Message + + System related + sections List kernel and module sections + lsmod List loaded kernel modules + rmmod Remove a kernel module + reboot Reboot the machine immediately + cpu Switch to new cpu + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + Memory Manipulation + md Display Memory Contents + mdr Display Raw Memory + mds Display Symbolically + mm Modify Memory Contents + id Display Instructions + + Register Manipulation + rd Display Registers + rm Modify Registers + ef Display exception frame + + Stack + bt [] Stack traceback + btp Display stack for + bta Display all stacks + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + Breakpoint + bc Clear Breakpoint + bd Disable Breakpoint + be Enable Breakpoint + bl [] Display breakpoints + bp [] Set/Display breakpoints + bpa [] Set/Display global breakpoints + bph [] Set hardware breakpoint + bpha [] Set global hardware breakpoint + bp* modifiers: + instruction - break on instruction fetch (default) + datar - break on read at vaddr + dataw - break on write at vaddr + IO - break on in or out op at vaddress + + Execution control + go [] Continue Execution + ss [<#steps>] Single Step + ssb Single step to branch/call +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + Kernel structures + ll Traverse list and execute command + ps Display active task list + vm Display vm_area_struct + dentry Display interesting dentry stuff + filp Display interesting filp stuff + sh Show scsi_host + sd Show scsi_device + sc Show scsi_cmnd + kiobuf Display kiobuf + page Display page + inode Display inode + bh Display buffer head + inode_pages Display pages in an inode +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo + + + Objective + Find and display the data associated with a scull device + + The sequence of events + Populate the scull device with data + Identify the breakpoints + Set breakpoint in the device read function + Identify the data structure elements + Identify device structures used to track data + Display data structures containing the data + Show the usage of the filp command + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Populate Device + + + Obtain the code + Surf to http://examples.oreilly.com/linuxdrive2/ + Download the tarball + Untar it to /usr/src + + Build and install the module + cd /usr/src/ldd2-samples-1.0.1/scull + make + ./scull.init start + + Populate the scull device + cat main.c > /dev/scull0 + cat /dev/scull0 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Driver Details + + + cat /dev/scull0 + fd = +%fore "blue", cont +open +%fore "black", cont +("/dev/scull0", O_RDONLY); + Kernel finds the file_operations structure + Kernel then invokes the open function +%fore "blue" + read +%fore "black", cont +(fd, buf, size); + Kernel finds the file_operations structure + Kernel then invokes the read function + + Scull device file operations structure + +%font "typewriter", size 3 + struct file_operations scull_fops = { + llseek: scull_llseek, +%fore "blue" + read: scull_read, +%fore "black" + write: scull_write, + ioctl: scull_ioctl, +%fore "blue" + open: scull_open, +%fore "black" + release: scull_release, + }; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Driver Details + +%font "typewriter", size 3 + scull_open code +%font "typewriter", size 3 + int +%fore "blue", cont +scull_open +%fore "black", cont +(struct inode *inode, struct file *filp) + { + Scull_Dev *dev; /* device information */ + int num = NUM(inode->i_rdev); + + + + dev = (Scull_Dev *)filp->private_data; + if (!dev) { + if (num >= scull_nr_devs) return -ENODEV; +%fore "blue" + dev = &scull_devices[num]; + filp->private_data = dev; +%fore "black" + } + + + + } +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Driver Details + +%font "typewriter", size 3 + scull_read code +%font "typewriter", size 3 + ssize_t +%fore "blue", cont +scull_read +%fore "black", cont +(struct file *filp, char *buf, size_t count, + loff_t *f_pos) + { + +%fore "blue", cont + Scull_Dev *dev = filp->private_data; +%fore "black", cont + /* the first listitem */ +%fore "blue" + Scull_Dev *dptr; +%fore "black" + int quantum = dev->quantum; + int qset = dev->qset; + int itemsize = quantum * qset; + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + if (*f_pos + count > dev->size) + count = dev->size - *f_pos; + + /* find listitem, qset index, and offset in the quantum */ + item = (long)*f_pos / itemsize; + rest = (long)*f_pos % itemsize; + s_pos = rest / quantum; q_pos = rest % quantum; + + /* follow the list up to the right position */ +%fore "blue" + dptr = scull_follow(dev, item); +%fore "black" + + + + } +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Breakpoints + + +%font "typewriter", size 3 + Determine where to set breakpoint +%font "typewriter", size 3 +%fore "blue" + dptr = scull_follow(dev, item); +%fore "black" + +%font "typewriter", size 3 + Disassemble scull_read +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +id scull_read +%fore "black" + 0xf8c083b4 scull_read: push %ebp + 0xf8c083b5 scull_read+0x1:mov %esp,%ebp + 0xf8c083b7 scull_read+0x3:push %edi + + 0xf8c08465 scull_read+0xb1:sub $0x8,%esp +%fore "blue" + 0xf8c08468 scull_read+0xb4:push %ecx + 0xf8c08469 scull_read+0xb5:push %esi + 0xf8c0846a scull_read+0xb6:call 0xf8c08364 scull_follow: +%fore "black" + 0xf8c0846f scull_read+0xbb:mov %eax, +%fore "blue", cont + %edx +%fore "black" + 0xf8c08471 +%fore "blue", cont +scull_read+0xbd +%fore "black", cont +:add $0x10,%esp + + + Set breakpoint in driver read +%font "typewriter", size 3 + [0]kdb> +%fore "blue",cont +bp scull_read+0xbd +%fore "black" + Instruction(i) BP #0 at 0xf8c08471 ([scull]scull_read+0xbd) + is enabled globally adjust 1 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Breakpoints + + +%font "typewriter", size 3 + Restart the system +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +go +%fore "black" + + Hit the Breakpoint +%font "typewriter", size 3 + [root@elm3b77 root]# +%fore "blue", cont +cat /dev/scull0 +%fore "black" + Instruction(i) breakpoint #0 at 0xf8c08471 (adjusted) + 0xf8c08471 scull_read+0xbd:int3 + Entering kdb (current=0xf73ec000, pid 1249) on processor 2 + due to Breakpoint @ 0xf8c08471 + + Display the registers +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +rd +%fore "black" + eax = 0xf77d7b60 ebx = 0x00000000 ecx = 0x00000000 edx = +%fore "blue", cont +0xf77d7b60 +%fore "black" + esi = +%fore "blue", cont +0xf77d7b60 +%fore "black", cont + edi = 0x00001000 esp = 0xf7415f40 eip = 0xf8c08471 + ebp = 0xf7415f78 xss = 0x00000018 xcs = 0x00000010 eflags = 0x00000246 + xds = 0xf7590018 xes = 0x00000018 origeax = 0xffffffff ®s = 0xf7415f0c +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Data Structures + +%font "typewriter", size 3 + Display the Scull_Dev structure +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +md 0xf77d7b60 2 +%fore "black" + 0xf77d7b60 +%fore "blue", cont +f7400000 +%fore "black", cont + 00000000 00000fa0 000003e8 ..@w.... ...h... + 0xf77d7b70 0000534e 00000000 00000000 00000000 NS.............. + + Scull Device Structure +%font "typewriter", size 3 + typedef struct Scull_Dev { +%fore "blue" + void **data; +%fore "black" + struct Scull_Dev *next; /* next listitem */ + int quantum; /* the current quantum size */ + int qset; /* the current array size */ + unsigned long size; + devfs_handle_t handle; /* only used if devfs is there */ + unsigned int access_key; /* used by sculluid and scullpriv */ + struct semaphore sem; /* mutual exclusion semaphore */ + } Scull_Dev; +%size 6 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Data Structures + + +%font "typewriter", size 3 + Display the quantum set (dev->data) +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +md f7400000 2 +%fore "black" + 0xf7400000 +%fore "blue", cont +f73ea000 +%fore "black", cont + f73f1000 f740c000 f7ab4000 . >w..?w.@@w.@+w + 0xf7400010 f73ef000 f755b000 00000000 00000000 .p>w.0Uw........ + + Display the first quantum (dev->data[0]) +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +md f73ea000 +%fore "black" + 0xf73ea000 200a2a2f 616d202a 632e6e69 202d2d20 /*. * main.c -- + 0xf73ea010 20656874 65726162 75637320 63206c6c the bare scull c + 0xf73ea020 20726168 75646f6d 200a656c 2a200a2a har module. *. * + 0xf73ea030 706f4320 67697279 28207468 32202943 Copyright (C) 2 + 0xf73ea040 20313030 73656c41 646e6173 52206f72 001 Alessandro R + 0xf73ea050 6e696275 6e612069 6f4a2064 6874616e ubini and Jonath + 0xf73ea060 43206e61 6562726f 2a200a74 706f4320 an Corbet. * Cop + 0xf73ea070 67697279 28207468 32202943 20313030 yright (C) 2001 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: filp command + + +%font "typewriter", size 3 + Show filp usage - here is the scull_read prototype +%font "typewriter", size 3 + ssize_t scull_read( +%fore "blue", cont +struct file *filp +%fore "black", cont +, char *buf, + size_t count, loff_t *f_pos); + Show the stack trace: +%font "typewriter", size 3 +[2]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xee9dbf78 0xf8c08471 [scull]scull_read+0xbd ( +%fore "blue", cont +0xeaf6c0c0 +%fore "black", cont +, 0x804e128, + 0x1000, 0xeaf6c0e0, 0x804f000) + scull .text 0xf8c08060 0xf8c083b4 0xf8c084dc + 0xee9dbfbc 0xc0136278 sys_read+0x98 (0x3, 0x804e128, 0x1000, ... + kernel .text 0xc0100000 0xc01361e0 0xc01362b0 + 0xc010702b system_call+0x33 + kernel .text 0xc0100000 0xc0106ff8 0xc0107030 + And show the filp output +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +filp 0xeaf6c0c0 +%fore "black" + name.name 0xe93889fc name.len 6 + File Pointer at 0xeaf6c0c0 + f_list.nxt = 0xe42deca0 f_list.prv = 0xf7e69070 +%fore "blue" + f_dentry = 0xe93889a0 +%fore "black", cont + f_op = 0xf8c0a200 + f_count = 2 f_flags = 0x8000 f_mode = 0x1 + f_pos = 0 f_reada = 0 f_ramax = 0 + f_raend = 0 f_ralen = 0 f_rawin = 0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: filp command + + +%font "typewriter", size 3 + filp output - continued +%font "typewriter", size 3 +%fore "blue" + Directory Entry at 0xe93889a0 +%fore "black" + d_name.len = 6 +%fore "orange", cont +d_name.name = 0xe93889fc +%fore "black", cont +> + d_count = 1 d_flags = 0x0 +%fore "blue", cont +d_inode = 0xe827b680 +%fore "black" + d_hash.nxt = 0xc215aec8 d_hash.prv = 0xc215aec8 + d_lru.nxt = 0xe93889b8 d_lru.prv = 0xe93889b8 + d_child.nxt = 0xe89e1e80 d_child.prv = 0xe9388940 + d_subdirs.nxt = 0xe93889c8 d_subdirs.prv = 0xe93889c8 + d_alias.nxt = 0xe827b690 d_alias.prv = 0xe827b690 + d_op = 0x00000000 d_sb = 0xf7e69000 + +%fore "blue" + Inode Entry at 0xe827b680 +%fore "black" + i_mode = 0x21a4 i_nlink = 1 i_rdev = 0xfe00 + i_ino = 37182 i_count = 1 i_dev = 0x821 + i_hash.nxt = 0xc20e6be8 i_hash.prv = 0xc20e6be8 + i_list.nxt = 0xe827b2c8 i_list.prv = 0xe827b868 + i_dentry.nxt = 0xe93889d0 i_dentry.prv = 0xe93889d0 + + Check the filename (display d_name.name) +%font "typewriter", size 3 + [2]kdb> +%fore "orange", cont +md 0xe93889fc 1 +%fore "black" + 0xe93889fc 6c756373 0000306c 00000000 00000000 scull0.......... + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Kernel Structures + + + Objective + Show output from various kernel related kdb commands + + Sequence of events + Simple Program + Write a simple program which allocates memory and hangs + Show usage of the ps, vm, and ll commands + Walk an IO operation + Hit a breakpoint in qlogic driver (isp1020_queuecommand) + Show usage of scsi related commands (sc, sh, and sd) + Show usage of vm related commands (bh, page, inode, inode_pages) + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple program + +%font "typewriter", size 3 + simple.c - simple program which allocates memory +%font "typewriter", size 3 +%fore "blue" + int foo_global[8192]; +%fore "black" + main() + { + int * +%fore "blue", cont +foo_malloc; +%fore "black" + int i; + foo_malloc = (int *)malloc(0x8192); + for(i = 0; i < 0x100; i++) { + foo_global[i] = 0xdead0000 | i; + foo_malloc[i] = 0xbeef0000 | i; + } + printf("foo_global at %x\n", (int)foo_global); + printf("foo_malloc at %x\n", (int)foo_malloc); + printf("sleep forever\n"); + sleep(2000000); + } + + simple output +%font "typewriter", size 3 + [root@elm3b77 scull]# cc -o simple simple.c + [root@elm3b77 scull]# ./simple + foo_global at +%fore "blue", cont +8049780 +%fore "black" + foo_malloc at +%fore "blue", cont +8051788 +%fore "black" + sleep forever + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Show the output of the ps command +%font "typewriter", size 3 + Entering kdb (current=0xc2010000, pid 0) on processor 3 due to + Keyboard Entry + [3]kdb> +%fore "blue", cont +ps +%fore "black" + Task Addr Pid Parent [*] cpu State Thread Command + 0xf7efe000 00000001 00000000 0 003 stop 0xf7efe370 init + 0xf7ef0000 00000002 00000001 0 001 stop 0xf7ef0370 keventd + 0xf7eec000 00000003 00000000 0 000 stop 0xf7eec370 ksoftirqd_CPU0 + 0xf7eea000 00000004 00000000 0 001 stop 0xf7eea370 ksoftirqd_CPU1 + 0xf7ee8000 00000005 00000000 0 002 stop 0xf7ee8370 ksoftirqd_CPU2 + 0xf7ee6000 00000006 00000000 0 003 stop 0xf7ee6370 ksoftirqd_CPU3 + + + + 0xf7b46000 00001006 00000737 0 003 stop 0xf7b46370 sshd + 0xf7ace000 00001007 00001006 0 000 stop 0xf7ace370 bash + 0xef06a000 00001066 00001007 0 003 stop 0xef06a370 su + 0xeef88000 00001067 00001066 0 000 stop 0xeef88370 bash + 0xeef64000 00001119 00000770 0 001 stop 0xeef64370 in.ftpd +%fore "blue" + 0xeeeac000 +%fore "black", cont + 00001138 00001067 0 001 stop 0xeeeac370 +%fore "blue", cont +simple +%fore "black" + [3]kdb> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Display the task struct +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +md 0xeeeac000 +%fore "black" + 0xeeeac000 00000001 00000000 00000000 c0000000 ................ + 0xeeeac010 c0339880 00000000 00000000 ffffffff ................ + 0xeeeac020 0000000a 00000000 00000000 +%fore "blue", cont +f7e10f00 +%fore "black", cont + ..............aw + 0xeeeac030 00000001 ffffffff ffffffff 00000000 ................ + +%font "typewriter", size 3 + Determine offset of mm_struct ptr in task_struct +%font "typewriter", size 3 + struct task_struct { + [0] volatile long state; + [4] unsigned long flags; + [8] int sigpending; + [c] mm_segment_t addr_limit; + [10] struct exec_domain *exec_domain; + [14] volatile long need_resched; + [18] unsigned long ptrace; + [1c] int lock_depth; + [20] long counter; + [24] long nice; + [28] unsigned long policy; +%fore "blue" + [2c] struct mm_struct *mm; +%fore "black" + [30] int processor; + [34] unsigned long cpus_runnable, cpus_allowed; + + }; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + + +%font "typewriter", size 3 + Display the mm_struct associated with simple process +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +md f7e10f00 +%fore "black" + 0xf7e10f00 +%fore "blue", cont +e8357a80 +%fore "black", cont + e8357978 f7ac77e0 eb15eac0 .z5hxy5h`w,w@j.k + 0xf7e10f10 00000001 00000002 0000000b 00000000 ................ + 0xf7e10f20 00000001 f7e10f24 f7e10f24 00000001 ................ + 0xf7e10f30 f7e35e70 eea7e8f0 08048000 0804862b ................ + 0xf7e10f40 0804962c 08049744 08051780 0805a000 ................ + 0xf7e10f50 bffffd10 bffffe00 bffffe09 bffffe09 ................ + 0xf7e10f60 bffffff3 0000005a 00000168 00000000 ................ + 0xf7e10f70 00000000 00000002 00000000 00000001 ................ + +%font "typewriter", size 3 + Determine offset of the first vma in the process +%font "typewriter", size 3 + struct mm_struct { +%fore "blue" + struct vm_area_struct * mmap; +%fore "black" + rb_root_t mm_rb; + struct vm_area_struct * mmap_cache; + + }; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Display the first vma using md +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +md e8357a80 +%fore "black" + 0xe8357a80 f7e10f00 08048000 08049000 +%fore "blue", cont +e8727e00 +%fore "black",cont + ..aw.........~rh + 0xe8357a90 00000025 00001875 e8727e18 00000001 %...u....~rh.... + + Display the first vma using vma +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +vma e8357a80 +%fore "black" + struct vm_area_struct at 0xe8357a80 for 68 bytes + vm_start = 0x8048000 vm_end = 0x8049000 + page_prot = 0x25 + flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +%font "typewriter", size 3 + + Determine the offset to the vma list +%font "typewriter", size 3 + struct vm_area_struct { + [0] struct mm_struct * vm_mm; + [4] unsigned long vm_start; + [8] unsigned long vm_end; +%fore "blue" + [c] struct vm_area_struct *vm_next; +%fore "black" + + }; + Display the next vma +%font "typewriter", size 3 + [3]kdb> vma e8727e00 + struct vm_area_struct at 0xe8727e00 for 68 bytes + vm_start = 0x8049000 vm_end = 0x804a000 + page_prot = 0x25 + flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Use the ll command to display the list of vma's +%font "typewriter", size 3 + [3]kdb> ll e8357a80 0xc vma +. + struct vm_area_struct at 0xe8357a80 for 68 bytes + vm_start = 0x8048000 vm_end = 0x8049000 + page_prot = 0x25 + flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +. + struct vm_area_struct at 0xe8727e00 for 68 bytes + vm_start = +%fore "orange", cont +0x8049000 +%fore "black", cont + vm_end = +%fore "orange", cont +0x804a000 +%fore "black" + page_prot = 0x25 + flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +. + struct vm_area_struct at 0xe8727c80 for 68 bytes + vm_start = +%fore "blue", cont +0x804a000 +%fore "black", cont + vm_end = +%fore "blue", cont +0x805a000 +%fore "black" + page_prot = 0x25 + flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC + + struct vm_area_struct at 0xe8357900 for 68 bytes + vm_start = 0xbfffe000 vm_end = 0xc0000000 + page_prot = 0x25 + flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN + + Match the vma to the displayed addresses +%font "typewriter", size 3 + foo_global at +%fore "orange", cont +8049780 +%fore "black" + foo_malloc at +%fore "blue", cont +8051788 +%fore "black" +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + + Objective + Show usage of various scsi and vm related kdb commands + + Sequence: + Set a breakpoint in the scsi driver + Stops when queueing a command to the controller + Cause IO on an idle disk + Show various IO stack traces + Display the IO data structures + Display vm information about the data + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Set the breakpoint + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +bp isp1020_queuecommand +%fore "black" + Instruction(i) BP #0 at 0xc01ecfe0 (isp1020_queuecommand) + is enabled globally adjust 1 + +%font "typewriter", size 3 + Create some activity on a previously unused disk + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + [root@elm3b77 root]# +%fore "blue", cont +ls /rh62 +%fore "black" + + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand:int3 + + Entering kdb (current=0xf75ba000, pid 1181) on processor 3 due to + Breakpoint @ 0xc01ecfe0 + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the stack. + This is a read of the /rh62 directory + +%font "typewriter", size 3 + [1]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xf75bbdf4 0xc01ecfe0 isp1020_queuecommand + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xf75bbe24 0xc01e99b1 scsi_request_fn+0x2f1 + 0xf75bbe34 0xc01c84fd generic_unplug_device+0x2d + 0xf75bbe50 0xc011b3af __run_task_queue+0x5f + 0xf75bbe6c 0xc013a63c block_sync_page+0x1c + 0xf75bbe98 0xc0128127 __lock_page+0x77 + 0xf75bbea4 0xc0128178 lock_page+0x18 + 0xf75bbec8 0xc012a4b3 read_cache_page+0xc3 + 0xf75bbef4 0xc0168e23 ext2_get_page+0x23 + 0xf75bbf48 0xc0168fdd ext2_readdir+0xfd + 0xf75bbf68 0xc0143d2e vfs_readdir+0x7e + 0xf75bbfbc 0xc01442ed +%fore "blue", cont +sys_getdents64+0x4d +%fore "black" + 0xc010702b system_call+0x33 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Allow the operation to complete + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + bench build etc lib mnt oldsys rh72 spv usr + bin data h linux mnt1 opt root test var + boot dev home lost+found mnt2 proc sbin tmp + +%font "typewriter", size 3 + Force some more activity + +%font "typewriter", size 3 + [root@elm3b77 root]# +%fore "blue", cont +cd /rh62/tmp +%fore "black" + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand:int3 + + Entering kdb (current=0xf768a000, pid 981) on processor 3 due to + Breakpoint @ 0xc01ecfe0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the stack. + This is an inode read for /rh62/tmp + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xf768bd68 0xc01ecfe0 isp1020_queuecommand + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xf768bd98 0xc01e99b1 scsi_request_fn+0x2f1 + 0xf768bda8 0xc01c84fd generic_unplug_device+0x2d + 0xf768bdc4 0xc011b3af __run_task_queue+0x5f + 0xf768bdfc 0xc0137216 __wait_on_buffer+0x56 + 0xf768be1c 0xc0138600 bread+0x50 + 0xf768be5c 0xc016b684 ext2_read_inode+0x114 + 0xf768bf0c 0xc013fbec real_lookup+0x7c + 0xf768bf78 0xc014035d link_path_walk+0x5ad +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Create a new file, causing yet more disk activity + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + + [root@elm3b77 tmp]# +%fore "blue", cont +echo "Hello linux reading group" > j1;sync +%fore "black" + + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand:int3 + + Entering kdb (current=0xf768a000, pid 981) on processor 3 due to + Breakpoint @ 0xc01ecfe0 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the stack + This is an inode read in response to the open +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xf768bd78 0xc01ecfe0 isp1020_queuecommand + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xf768bda8 0xc01e99b1 scsi_request_fn+0x2f1 + 0xf768bdb8 0xc01c84fd generic_unplug_device+0x2d + 0xf768bdd4 0xc011b3af __run_task_queue+0x5f + 0xf768bdf0 0xc013a63c block_sync_page+0x1c + 0xf768be1c 0xc0128127 __lock_page+0x77 + 0xf768be28 0xc0128178 lock_page+0x18 + 0xf768be4c 0xc012a4b3 read_cache_page+0xc3 + 0xf768be78 0xc0168e23 ext2_get_page+0x23 + 0xf768beb8 0xc01691ed ext2_find_entry+0x8d + 0xf768bed4 0xc016933a ext2_inode_by_name+0x1a + 0xf768befc 0xc016c077 ext2_lookup+0x27 + 0xf768bf1c 0xc014094a lookup_hash+0x9a + 0xf768bf64 0xc0140c4d open_namei+0xfd + 0xf768bfa0 0xc0135907 filp_open+0x37 + 0xf768bfbc 0xc0135c64 sys_open+0x34 + 0xc010702b system_call+0x33 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Let the operation continue +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand: int3 + Entering kdb (current=0xc0352000, pid 0) on processor 0 due to + Breakpoint @ 0xc01ecfe0 + Show the stack + This is an io completion queuing the next request +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xc0353df4 0xc01ecfe0 isp1020_queuecommand( +%fore "blue", cont +0xf7e63a00 +%fore "black", cont +,0xc01e7fc0... + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xc0353e24 0xc01e99b1 scsi_request_fn+0x2f1 + 0xc0353e40 0xc01e8f6a +%fore "blue", cont +scsi_queue_next_request+0x4a +%fore "black" + 0xc0353e5c 0xc01e9166 __scsi_end_request+0x116 + 0xc0353ea8 0xc01e93e0 +%fore "blue", cont +scsi_io_completion+0x170 +%fore "black" + 0xc0353ecc 0xc01f658e rw_intr+0x14e + 0xc0353ef8 0xc01e8668 scsi_old_done+0x6a8 + 0xc0353fd4 0xc01052c2 cpu_idle+0x52 + Function prototype +%font "typewriter", size 3 + int isp1020_queuecommand( +%fore "blue", cont +Scsi_Cmnd *Cmnd, +%fore "black" + void (*done)(Scsi_Cmnd *)) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the command being queued +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +sc 0xf7e63a00 +%fore "black" + scsi_cmnd at 0xf7e63a00 +%fore "blue" + host = 0xf7e91400 +%fore "black", cont + state = 4099 owner = 258 +%fore "blue", cont +device = 0xf7ed5d80 +%fore "black" + bnext = 0x00000000 reset_chain = 0x00000000 eh_state = 0 + done = 0xc01f6440 + serial_number = 3402 serial_num_at_to = 0 retries = 0 timeout = 0 + id/lun/cmnd = [0/0/0] cmd_len = 10 old_cmd_len = 10 + cmnd = [2a/00/00/28/00/3f/00/00/10/00/ef/f7] + data_cmnd = [2a/00/00/28/00/3f/00/00/10/00/ef/f7] + request_buffer = 0xc03fd000 bh_next = 0x00000000 + request_bufflen = 8192 + use_sg = 2 old_use_sg = 2 sglist_len = 512 abore_reason = 0 + bufflen = 8192 buffer = 0xc03fd000 underflow = 8192 + transfersize = 512 + tag = 0 pid = 3401 + request struct + rq_status = RQ_ACTIVE rq_dev = [8/1] errors = 1 cmd = 0 + sector = 2621440 nr_sectors = 16 current_nr_sectors = 8 + buffer = 0xf7599000 +%fore "blue", cont +bh = 0xf75ca300 +%fore "black", cont + bhtail = 0xf75ca3c0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the host adapter +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +sh 0xf7e91400 +%fore "black" + Scsi_Host at 0xf7e91400 + next = 0x00000000 +%fore "blue", cont +host_queue = 0xf7ed5d80 +%fore "black" + ehandler = 0x00000000 eh_wait = 0x00000000 en_notify = 0x00000000 + eh_action = 0x00000000 + h_active = 0x0 host_wait = 0xc0353ac4 hostt = 0xc034bce0 + host_busy = 1 + host_failed = 0 extra_bytes = 524 host_no = 0 resetting = 0 + max id/lun/channel = [16/8/0] this_id = 7 + can_queue = 64 cmd_per_lun = 1 sg_tablesize = 427 u_isa_dma = 0 + host_blocked = 0 reverse_ordering = 0 + +%font "typewriter", size 3 + Display the scsi device +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +sd 0xf7ed5d80 +%fore "black" + scsi_device at 0xf7ed5d80 + next = 0xf7ed5c80 prev = 0x00000000 host = 0xf7e91400 + device_busy = 1 +%fore "blue", cont +device_queue 0xf7e63a00 +%fore "black" + id/lun/chan = [0/0/0] single_lun = 0 device_blocked = 0 + queue_depth = 1 current_tag = 0 scsi_level = 4 + IBM DGHS18X 0360 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the Buffer header associated with the command +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +bh 0xf75ca300 +%fore "black" + buffer_head at 0xf75ca300 + next 0x00000000 bno 327680 rsec 2621440 size 4096 + dev 0x801 rdev 0x801 + count 2 state 0x1d [Uptodate Lock Req Mapped] ftime 0x7695e + b_list 1 b_reqnext 0xf75ca3c0 b_data 0xf7599000 +%fore "blue" + b_page 0xc1dd6640 +%fore "black", cont + b_this_page 0xf75ca300 b_private 0x00000000 + + Display the associated page structure +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +page 0xc1dd6640 +%fore "black" + struct page at 0xc1dd6640 + next 0xc1dd7300 prev 0xc1dd6240 +%fore "blue", cont +addr space 0xf7af04d0 +%fore "black" + index 327680 (offset 0x50000000) + count 2 flags PG_referenced PG_lru virtual 0xf7599000 + buffers 0xf75ca300 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the Address space associated with the page +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +md 0xf7af04d0 +%fore "black" + 0xf7af04d0 c1dd6240 c1dea740 f7af04d8 f7af04d8 @b]A@'^AX./wX./w + 0xf7af04e0 f7af04e0 f7af04e0 00000007 c033b700 `./w`./w.....73@ + 0xf7af04f0 +%fore "blue", cont +f7af0420 +%fore "black", cont + 00000000 00000000 00000001 ./w............ + 0xf7af0500 000001d0 00000000 00000000 f7af050c P............./w + 0xf7af0510 f7af050c 00000000 f7a8afa0 00000000 ../w.... /(w.... + + The structure looks like: +%size 3 + struct address_space { + struct list_head clean_pages; /* list of clean pages */ + struct list_head dirty_pages; /* list of dirty pages */ + struct list_head locked_pages;/* list of locked pages */ + unsigned long nrpages; /* number of total pages */ + spinlock_t page_lock; /* spinlock protecting them*/ + struct address_space_operations *a_ops; /* methods */ +%fore "blue" + struct inode *host; /* owner: inode, block_dev */ +%fore "black" + + }; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the inode associated with the address space + I think htis is the inode for the block device. + +%font "typewriter", size 3 + [1]kdb> +%fore "blue", cont +inode f7af0420 +%fore "black" + struct inode at 0xf7af0420 + i_ino = 289 i_count = 1 i_dev = 0x801 i_size 4301789184 + i_mode = 0x8000 i_nlink = 1 i_rdev = 0x801 + i_hash.nxt = 0xf7af0420 i_hash.prv = 0xf7af0420 + i_list.nxt = 0xf7af0608 i_list.prv = 0xf7af0068 + i_dentry.nxt = 0xf7af0430 i_dentry.prv = 0xf7af0430 + i_dirty_buffers.nxt = 0xf7af0438 i_dirty_buffers.prv = 0xf7af0438 + i_sb = 0xc201f200 i_op = 0xc03cfdc0 i_data = 0xf7af04d0 nrpages = 6 + i_mapping = 0xf7af04d0 + i_flags 0x0 i_state 0x0 [] fs specific info @ 0xf7af0540 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the page list associated with the inode +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +inode_pages f7af0420 +%fore "black" +CLEAN page_struct index cnt flags + 0xc1dd6240 327735 2 0x44 bh 0xf75caae0 bno 327735 + [Lock Req Mapped] +%fore "blue" + 0xc1dd6640 327680 2 0x44 bh 0xf75ca300 bno 327680 + [Uptodate Lock Req Mapped] +%fore "black" + 0xc1dd7300 327681 2 0x44 bh 0xf75ca3c0 bno 327681 + [Uptodate Lock Req Mapped] + 0xc1dd6e00 327684 2 0x44 bh 0xf75ca420 bno 327684 + [Uptodate Req Mapped] + 0xc1de8fc0 4 2 0xc0 bh 0xf7b5ade0 bno 4 + [Uptodate Req Mapped] + 0xc1dea700 1 2 0x44 bh 0xf7e02740 bno 1 + [Uptodate Req Mapped] + 0xc1dea740 0 2 0x44 bh 0xf7e028c0 bno 0 + [Uptodate Req Mapped] +DIRTY page_struct index cnt flags +LOCKED page_struct index cnt flags diff -Nur linux-2.4.19/Documentation/pagg.txt linux-2.4.19-sgi211r3/Documentation/pagg.txt --- linux-2.4.19/Documentation/pagg.txt Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/pagg.txt Thu Jan 31 12:33:13 2002 @@ -0,0 +1,303 @@ +Linux Process Aggregates (PAGG) +------------------------------- + +Comments by: Sam Watters +Last Update: 2001.04.15 + + +1. Description + +The process aggregates infrastructure, or PAGG, provides a mechanism to +construct arbitrary process groups in Linux. PAGG consists of a series +of functions for registering and unregistering support for new types of +process aggregation containers with the kernel. This is similar to the +support currently provided within Linux that allows for dynamic support +of filesystems, block and character devices, symbol tables, network +devices, serial devices, and execution domains. This implementation +of PAGG provides developers with the basic hooks necessary to implement +kernel modules for specific process containers, such as the job container. + +The do_fork function in the kernel was altered to support PAGG. If a +process is attached to any PAGG containers and subsequently forks a +child process, the child process will also be attached to the same PAGG +containers as the parent process. The PAGG containers being attached to +by the child process are notified that a new process has been attached. +The notification is accomplished via a callback function provided by +the PAGG module. + +The do_exit function in the kernel has also been altered. If a process +is attached to any PAGG containers and that process is exiting, the PAGG +containers are notified that a process has detached from the container. +The notification is accomplished via a callback function provided by +the PAGG module. + +Additional details concerning this implementation of the process aggregates +infrastructure are described in the sections that follow. + + +2. Kernel Changes + +This section describes the files and data strcutrues that are involved in +this implementation of PAGG. Both modified and new files data structures +are discussed. + +3.1. Modified Files + +The following files were modified to implement PAGG: + +- Documentation/Configure.help +- arch/i386/config.in +- arch/ia64/config.in +- include/asm-i386/unistd.h +- include/asm-ia64/unistd.h +- include/linux/sched.h +- arch/i386/kernel/entry.S +- arch/ia64/kernel/entry.S +- kernel/Makefile +- kernel/exit.c +- kernel/fork.c +- kernel/ksyms.c + +This implementation of PAGG supports the i386 and ia64 architectures. Support +for other architectures will be added in the future. Testing volunteers +for new architectures are needed and should contact pagg@oss.sgi.com. + +2.2. New Files + +The following files were added to implement PAGG: + +- Documentation/pagg.txt +- include/linux/pagg.h +- include/linux/paggctl.h +- kernel/pagg.c + +2.3. Modified Data Structures + +The following existing data structures were altered to implement PAGG. + +- struct task_struct: (include/linux/sched.h) + struct pagg_list_s pagg_list; /* List of pagg containers */ + +This new member in task_struct, pagg, points to the list of pagg containers +to which the process is currently attached. + +2.4. New Data Structures + +The following new data structures were introduced to implement PAGG. + +- struct pagg_s: (include/linux/pagg.h) + struct pagg_hook_s *hook /* Ptr to pagg module entry */ + void *data; /* Task specific data */ + struct list_head entry; /* List connection */ + +- struct pagg_hook_s: (include/linux/pagg.h) + char *name; /* PAGG hook name - restricted + * to 32 characters. */ + int (*do_attach)(struct task_struct *, /* Function to attach */ + struct pagg_s *, + void *); + int (*do_detach)(struct task_struct *, /* Function to detach */ + struct pagg_s *); + int (*do_init)(struct task_struct *, /* Load task init func. */ + struct pagg_s *); + int (*do_paggctl)(int, void *); /* Funtion for paggctl */ + void *data; /* Module specific data */ + struct module *module; /* Ptr to PAGG module */ + struct list_head entry; /* List connection */ + +The pagg_s structure provides the process' reference to the PAGG +containers provided by the PAGG modules. The do_attach function pointer +is the function used to notify the referenced PAGG container that the +process is being attached. The do_detach function pointer is used to notify +the referenced PAGG container that the process is exiting or otherwise +detaching from the container. + +The pagg_hook_s structure provides the reference to the module that +implements a type of PAGG container. In addition to the function pointers +described concerning pagg_s, this structure provides two addition +function pointers. The do_init function pointer is currently not used +but will be available in the future. Future use of the do_init function +will be optional and will used to attach currently running processes to +a default PAGG container when a PAGG module is loaded on a running system. + The do_paggctl function provides this modules interface for the paggctl +system call. + + +2.5. Modified Functions + +The following functions were changed to implement PAGG: + +- do_fork: (kernel/fork.c) + /* execute the following pseudocode before add to run-queue */ + If parent process pagg list is not empty + Call attach_pagg_list function with child task_struct as argument +- do_exit: (kernel/exit.c) + /* execute the following pseudocode prior to schedule call */ + If current process pagg list is not empty + Call detach_pagg_list function with current task_struct + +2.6 New Functions + +The following new functions were added to implement PAGG: + +- int register_pagg_hook(struct pagg_hook_s *); (kernel/pagg.c) + Add module entry into table of pagg modules +- int unregister_pagg_hook(struct pagg_hook_s *); (kernel/pagg.c) + Find module entry in list of pagg modules + Foreach task + If task is attached to this pagg module + return error + If no tasks are referencing this module + remove module entry from list of pagg modules +- int attach_pagg_list(struct task_struct *); (kernel/pagg.c) + /* Assumed task pagg list pts to paggs that it attaches to */ + While another pagg container reference + Make copy of pagg container reference & insert into new list + Attach task to pagg container using new container reference + Get next pagg container reference + Make task pagg list use the new pagg list +- int detach_pagg_list(struct task_struct *); (kernel/pagg.c) + While another pagg container reference + Detach task from pagg container using reference + + +2.7 New System Calls + +The following new system call was added to implement a control +interface for PAGG modules: + +- int sys_paggctl(const char *, int, void *); (kernel/pagg.c) + If requested name is invalid + Return -EINVAL + If requested module name not found in pagg module table + Return -ENOXIO + If requested module does not provide do_paggctl function + Return -ENOXIO + Else + Call pagg module do_paggctl function + Return result + +The paggctl system call provides the necessary interface for +controlling the function of the pagg container modules. + + +3. Paggctl System Call Man Page + + +paggctl(3c) paggctl(3c) + + +NAME + paggctl - controls and provides status for Process Aggre- + gation (PAGG) modules + +SYNOPSIS + int paggctl (char *module_name, int request, void *data); + +DESCRIPTION + The paggctl system call is used as the system call inter- + face for Process Aggregation (PAGG) modules. For a PAGG + module to support the paggctl interface, it must have pro- + vided a reference to a processing function that is imple- + mented in the module to handle paggctl calls the request + the module. It is not required that a PAGG module support + the paggctl system call. + + The paggctl system call allows processes to obtain infor- + mation from the PAGG modules, such as status information. + In addition, this interface provides processes with the + ability to provide information to the PAGG module. + + The use of the paggctl system call requires three parame- + ters. The first, module_name, is a string that provides + the name of the module that should service the request. + The second argument, request, is a code that indicates to + the module what the operation the caller is requesting. + The final argument, data, is a pointer to a strucuture + used to transfer data between the process and the module. + The module servicing the request will provide the struc- + ture definitions for the data argument. + + Each PAGG module that implements a service function for + paggctl should provide a manual page that provides addi- + itonal details. The Linux Job module is an example of a + PAGG module. The Job module manual page, job_paggctl(3c), + provides additional details about the requests that the + service function provided by the Job module may handle and + any required header files. + + The PAGG system handles requests for information concern- + ing PAGG hooks that are currently registered. To per- + form PAGG hook queries, the first argument, hook_name + should be set to the PAGG_HOOK macro (found in the + paggctl.h include file). The second and third arguments + should be set as follows: + + PAGG_HOOK_GETCNT + Get a count for the number of PAGG hooks currently + registered. The data structure referenced by the + data is a pointer to an int. The count of hooks + will be stored in the memory referenced by this + pointer. + + PAGG_HOOK_GETLST + Get the list of hooks currently registered. The + data structure referenced by data is a pointer to + the following struct: + + typedef struct pagg_hook_getlst_s { + int r_val; + pagg_namestr_t *list; + } pagg_hook_getlst_t; + + The list of PAGG hook service names is returned in + the list of character arrays pointed to the list + member. The caller is responsible for allocating + and freeing the memory for the list. The caller + specifies the number of elements in the array using + the r_val member. Upon return, the r_val member + will contain the number of module names that were + inserted into the list. The number of hook names + returned is limited to the numer of elemets speci- + fied by what the caller specifies in the r_val mem- + ber. An example of allocating a list of that can + contain up to five module names is as follows: + + pagg_hook_getlst_t getlst; + getlst.r_val = 5; + getlst.list = (pagg_namestr_t *)malloc( + (sizeof(pagg_namestr_t)*getlst.r_val); + + + PAGG_HOOK_GETCHK + Determine if a specific PAGG hook is registered. + The data structure referenced by data is a pointer + to the following struct: + + typedef struct pagg_hook_getchk_s { + int r_val; + pagg_namestr_t name; + } pagg_hook_getlst_t; + + The caller specifies the PAGG hook service name via + the name member of the struct. If the PAGG hook + is not registered, the value 0 is returned via the + r_val member of the struct. If the PAGG hook is + registered, then a value of 1 is returned. + +ERRORS + Under the following conditions, the acctctl function fails + and sets errno to: + + [ENOSYS] The paggctl system call is not implemented. + + [ENXIO] The module could not be found, or it did + not provide a service function. Additional + errno codes are listed on the manual pages + provided by the PAGG modules + +DIAGNOSTICS + Upon successful completion, paggctl returns a value of 0. + Otherwise, a value of -1 is returned and errno is set to + indicate the error. + diff -Nur linux-2.4.19/Documentation/sound/forte linux-2.4.19-sgi211r3/Documentation/sound/forte --- linux-2.4.19/Documentation/sound/forte Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/sound/forte Wed Oct 16 14:02:58 2002 @@ -0,0 +1,41 @@ + + forte - an OSS/Lite driver for FortéMedia FM801 sound chips + =========================================================== + +This is a driver for cards using the FortéMedia FM801 audio +controller. The Genius Sound Maker Live card and the onboard audio in +HP Workstation zx2000 has been tested. + +Both IA-32 and IA-64 architectures are supported, but the driver +should work on any platform. + +The FM801 controller supports a variety of AC'97 codecs. This driver +lets the OSS core code figure the codec out, and should thus support +any codec with support in the Linux kernel. + +The driver supports /dev/mixer and /dev/dsp for generic OSS audio +support. In general it adheres to the OSS spec to the extent it can +be done with the way the hardware works. The FM801 controller doesn't +support scatter-gather, so if the application sets fragment size too +low, it puts strict requirements on interrupt processing speed. The +driver tries to compensate by enforcing bigger buffers than requested +by the application if the fragment size is low. + +The forte driver includes both standard read()/write() and the +unsupported mmap() interface used by Quake. mmap() is only supported +in playback mode. + +U8 and S16 audio formats are supported, mono/stereo, as well as most +all sample rates implemented by the chip. Default is 48 KHz, 16-bit, +mono. + +MIDI, FM audio, and the gameport controller are not currently +supported. + + +The latest version of this driver can be found at: + + http://mkp.net/forte/ + + +Martin K. Petersen, July 2002 diff -Nur linux-2.4.19/Documentation/vm/numa_sgi_sn1 linux-2.4.19-sgi211r3/Documentation/vm/numa_sgi_sn1 --- linux-2.4.19/Documentation/vm/numa_sgi_sn1 Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/Documentation/vm/numa_sgi_sn1 Fri Feb 1 11:39:38 2002 @@ -0,0 +1,284 @@ + NUMA Implementation in Linux on the + SGI SN1 Architecture + +Introduction +============ + +The purpose of this document is to explain the design of the NUMA +implementation on SGI's SN1 systems. + +The NUMA support in Linux is collected under CONFIG_DISCONTIGMEM. The +physical memory model for this code assumes that the entire physical +memory is not contiguous but consists of a few lumps of contiguous +memory. These lumps are called NODEs and is identified by a NODE Id. +Access time to all memory in a NODE is the same and access time to +different NODEs is different. The access time from a CPU to one of +the NODE's memory is the lowest. This is called the LOCAL NODE for +that CPU. The other NODEs are called REMOTE NODEs. Access time from a +CPU to sets of REMOTE NODEs can be different and so each NODE will +have a 'nearness' value from each CPU. + +Kernel memory allocation routines use the 'nearness' factor to determine +which NODE to allocate memory from. They also provide an API to enable +each kernel task to be able to specify the node on which memory is allocated. + +The following topics are covered: + + o Brief introduction to SN1 Mem Arch + o Linux VM data structures + o Inter Node Holes + o Intra Node Holes + +Brief introduction to SN1 Mem Arch +================================== + +The memory arch in SN1 is slightly different from the above General +NUMA model. Each node's memory starts on a 8 GB boundary. A physical +number present in the SN1 hardware chipset determines which 8GB boundary +the NODE's memory will start. This number is called NASID (Numa Address +Space Identifier). The nasid is 8 bits wide so the range of the nasid +is 0-255. The nasids for each node is dynamically determined during +system boot. For example a system can have nasids of 3,5 and 9. The memory +map will look like + + +-----------------------+ + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + | | + | | + 72 GB +-----------------------+ + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + | | + | | + 40 GB +-----------------------+ + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| --> Hole + |\\\\\\\\\\\\\\\\\\\\\\\| + | | + | | + 24 GB +-----------------------+ + +All the 8 GB in a NODE's memory area need not be populated with physical +memory. This results in large memory holes between NODEs. These holes +are called Inter node holes. + +Each NODE consists of 8 BANKS. Each bank is populated with DIMMs to get +physical memory. DIMM sizes range from 64 MB to 1 GB. Each BANK starts at +1 GB boundary. This means that for 64 MB DIMMs, the size of holes between +BANKs will in itself be fairly big. These are called Intra Node Holes. + +Linux VM data structs (Section incomplete) +===================== + +struct page +MAP_NR +bootmem_data_t +pg_dat_t +kern_addr_valid +mem_map + MAP_NR +page-mem_map +max_mapnr + + | | + | | + | Free Memory | + +-----------------------+ + | | + | Bit Map | + +-----------------------+ + | | + | Mem Map | + 7.8 MB +-----------------------+ + | | + | Kernel Text | + 5 MB +-----------------------+ + | | + | | + 0 +-----------------------+ + +Mem Map (Page Table) + + + +----------+-----------+-----------+-----------------+----------+ + |//////////|///////////| |/////////////////| | + +----------+-----------+-----------+-----------------+----------+ + + Rsvd Rsvd Free Rsvd Free + Kern txt Mmap,BitMap Free Mem Intra Bank Hole Bank 1 Mem + +MAP_NR() should be valid for hole addrs also, as some code will check the +flags field. The correct usage is to do a kern_addr_valid() before doing +MAP_NR(). + +max_mapnr is the mapnr of the highest mem page in the node assuming all +space up to that is full of struct_page ?? + +zone->free_pages viz based on max_mapnr is bogus ?? + +size field in NODE_MEMMAP ?? + + start_kernel + paging_init (divide total mem into pages) + alloc_bootmem_node should be working + bootmem_data_t initted + bootmem bit map valid + bootmem base addr valid + kernel text IO holes reserved in bootmem bitmap + free_area_init_core + alloc from bootmem, an area for mem_map + reserve all pages in memmap table + zone init + + free_all_bootmem_core + frees all boot mem based on bootmem bit map + can free unused memmap here or in the + calling routine of free_all_bootmem_core + viz mem_init or paging_init in plat/mm/init.c + +The MAP_NR() macro is already complex, just changing it to +'extend memmap beyond a bank will fix all problems' looks ok and the +best solution. Will not need a warning msg at all. + +For now, the approach is 3 steps: + + - free unused memmap + - change MAP_NR to check for kern addr in holes + Assuming that it is only the MAP_NR that is troublesome + - user warning msg + - spread memmap + bitmap across banks + +Init Sequence + setup_arch + init_bootmem + build a bootmem page valid map for early + mem alloc. This just uses a bit map + reserve all pages initially + free_area_init + reserve_boot_mem + paging_init + free_all_bootmem + mem_init + +Inter Node Holes (Section Incomplete) +================ + +Intra Node Holes +================ + +Problem Definition +------------------ + +From the description of the SN1 memory arch above, we see that from a Linux +point of view, the Inter Node holes are also fairly big and need a separate +design consideration. + +Since this feature is SN1 specific it does not make sense to extend the +core Linux concept of NODEs into NODEs and BANKs. + +An example will highlight the problem clearly: + +Assume a single node system with 2 64 MB DIMMs. Assume they are +populated at Bank 0 and Bank 7. The memory map looks like + + + 8 GB +-----------------------+ + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + 7GB+ 64 MB +-----------------------+ + | | + | | + 7 GB +-----------------------+ + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| --> Hole + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + |\\\\\\\\\\\\\\\\\\\\\\\| + 64 MB +-----------------------+ + | | + | | + 0 GB +-----------------------+ + +Total Physical Memory - 128 MB +Physical Address spanned - 0 - 7GB+64MB +Intra node hole - 64 MB - 7 GB + +Since core Linux does not know about Intra Node Holes, it assumes that +the memory within a NODE is contiguous. It builds a page table for +~7GB of memory. The size of the page struct is 0x90 bytes and the kernel +memory layout and params for this config is: + +Start - 0xe000000000000000, +Size - 0x1c4000000 (top phys addr of last bank) +MemMap - 0xe000000000798000, +BitMap - 0xe000000004744540 (~64 MB) +Mapnr - 0xd800 + +There are 2 problems with this: + +- Kernel Data structures extend up to 0xe000000004744540, while the + physically contiguous memory stops at 0xe000000004000000 (64 MB). + Identity mapped kernel addr space. + +- The following formula gives space usage by the page table + + (Highest Valid Mem Addr on Node - Actual Valid Phys Mem) >> PAGE_SHIFT + * 0x90 + + is the space wasted. For the above config it is + + ((0x44000000-0x8000000) >> 14) * 0x90 ~ 8.7 MB + + This does not include a few MB wasted by the bitmap structure. + +The kernel initially will mark all these pages as reserved and they will +stay that way forever. + +The page table cannot be extended to the second bank as the physical +address to page structure translation is a MACRO MAP_NR, which is a +simple translation. + +The size of page struct may change with versions so we cannot put an +upper limit on the table space needed. + +How it affects the User +----------------------- + +The user will not be able to boot the above config. + +A lot of memory will be wasted. + +Solution Alternatives +----------------------- + +1. Change the core Linux NODE memory allocation scheme to a NODE BANK + scheme. Put a page table on each bank. This results in memory + fragmentation for large page implementations. The bit map has + to be on bank 0. + +2. Free up the unused page table areas and change macros like + kern_addr_valid(), MAP_NR so that they return error for addrs in + HOLES. + +3. Try loading the kernel at other addresses and see if the table + + Bitmap fits in the min bank size. + +4. For such configs, print a user warning message and use only the + banks whose page table + Bit map fits in Bank 0. + +Proposed Solution +----------------------- + +A combination of 2 and 4. + +If the requirement of the Bank 0 can be changed from 64 MB to 128 MB +then all combinations work smoothly. But we cannot gurantee that someone +in the field will not encounter this situation. So the software fixes +are needed. + + + diff -Nur linux-2.4.19/MAINTAINERS linux-2.4.19-sgi211r3/MAINTAINERS --- linux-2.4.19/MAINTAINERS Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/MAINTAINERS Thu Feb 6 20:29:36 2003 @@ -1415,8 +1415,6 @@ S: Maintained SGI VISUAL WORKSTATION 320 AND 540 -P: Bent Hagemark -M: bh@sgi.com P: Ingo Molnar M: mingo@redhat.com S: Maintained @@ -1850,6 +1848,14 @@ M: eis@baty.hanse.de L: linux-x25@vger.kernel.org S: Maintained + +XFS FILESYSTEM +P: Silicon Graphics Inc +M: owner-xfs@oss.sgi.com +M: lord@sgi.com +L: linux-xfs@oss.sgi.com +W: http://oss.sgi.com/projects/xfs +S: Supported X86 3-LEVEL PAGING (PAE) SUPPORT P: Ingo Molnar diff -Nur linux-2.4.19/Makefile linux-2.4.19-sgi211r3/Makefile --- linux-2.4.19/Makefile Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/Makefile Thu Feb 20 19:55:58 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 19 -EXTRAVERSION = +EXTRAVERSION = -lbs KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -37,13 +37,24 @@ MAKEFILES = $(TOPDIR)/.config GENKSYMS = /sbin/genksyms DEPMOD = /sbin/depmod +KALLSYMS = /sbin/kallsyms MODFLAGS = -DMODULE CFLAGS_KERNEL = PERL = perl +AWK = awk +READELF = $(CROSS_COMPILE)readelf + +ifeq ($(ARCH),ia64) +IA64_UNWIND_FIX := 1 +else +IA64_UNWIND_FIX := 0 +endif + +TMPPREFIX = export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \ CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ - CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL + CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL AWK READELF all: do-it-all @@ -87,8 +98,9 @@ # CPPFLAGS := -D__KERNEL__ -I$(HPATH) +CPPFLAGS += $(patsubst %,-I%,$(CROSS_COMPILE_INC)) -CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ +CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -g -O2 \ -fno-strict-aliasing -fno-common ifndef CONFIG_FRAME_POINTER CFLAGS += -fomit-frame-pointer @@ -127,6 +139,11 @@ LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib +ifeq ($(CONFIG_KDB),y) +CORE_FILES += kdb/kdb.o +SUBDIRS += kdb +endif + DRIVERS-n := DRIVERS-y := DRIVERS-m := @@ -152,10 +169,13 @@ DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o +DRIVERS-$(CONFIG_XSCSI) += drivers/xscsi/xscsidrv.o DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o +DRIVERS-$(CONFIG_DUMP) += drivers/dump/dumpdrv.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o +DRIVERS-$(CONFIG_IA64_SGI_SN) += drivers/sgi/sn/sn_drivers.a -ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) +ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),$(CONFIG_XSCSI_MMSC)) DRIVERS-y += drivers/cdrom/driver.o endif @@ -196,7 +216,7 @@ CLEAN_FILES = \ kernel/ksyms.lst include/linux/compile.h \ vmlinux System.map \ - .tmp* \ + $(TMPPREFIX).tmp* \ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \ drivers/char/conmakehash \ drivers/char/drm/*-mod.c \ @@ -239,9 +259,10 @@ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \ .menuconfig.log \ include/asm \ + kdb/gen-kdb_cmds.c \ .hdepend scripts/mkdep scripts/split-include scripts/docproc \ $(TOPDIR)/include/linux/modversions.h \ - kernel.spec + kernel.spec Kerntypes # directories removed with 'make mrproper' MRPROPER_DIRS = \ @@ -276,16 +297,48 @@ boot: vmlinux @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot -vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o linuxsubdirs - $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \ - --start-group \ - $(CORE_FILES) \ - $(DRIVERS) \ - $(NETWORKS) \ - $(LIBS) \ - --end-group \ - -o vmlinux +LD_VMLINUX := $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \ + --start-group \ + $(CORE_FILES) \ + $(DRIVERS) \ + $(NETWORKS) \ + $(LIBS) \ + --end-group +ifeq ($(CONFIG_KALLSYMS),y) +LD_VMLINUX_KALLSYMS := $(TMPPREFIX).tmp_kallsyms3.o +else +LD_VMLINUX_KALLSYMS := +endif + +vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o Kerntypes linuxsubdirs + @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" kallsyms + [ $(IA64_UNWIND_FIX) == 0 ] || $(PERL) scripts/ia64_unwind_fix.pl vmlinux > .tmp_vmlinux_ia64_unwind_fix + +.PHONY: kallsyms + +kallsyms: +ifeq ($(CONFIG_KALLSYMS),y) + @echo kallsyms pass 1 + $(LD_VMLINUX) -o $(TMPPREFIX).tmp_vmlinux1 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux1 > $(TMPPREFIX).tmp_kallsyms1.o + @echo kallsyms pass 2 + @$(LD_VMLINUX) $(TMPPREFIX).tmp_kallsyms1.o -o $(TMPPREFIX).tmp_vmlinux2 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux2 > $(TMPPREFIX).tmp_kallsyms2.o + @echo kallsyms pass 3 + @$(LD_VMLINUX) $(TMPPREFIX).tmp_kallsyms2.o -o $(TMPPREFIX).tmp_vmlinux3 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux3 > $(TMPPREFIX).tmp_kallsyms3.o +endif + $(LD_VMLINUX) $(LD_VMLINUX_KALLSYMS) -o $(TMPPREFIX)vmlinux +ifneq ($(TMPPREFIX),) + mv $(TMPPREFIX)vmlinux vmlinux +endif $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + @rm -f $(TMPPREFIX).tmp_vmlinux* $(TMPPREFIX).tmp_kallsyms* + +Kerntypes: init/kerntypes.o + @if [ -f init/kerntypes.o ]; then \ + mv init/kerntypes.o Kerntypes; \ + fi symlinks: rm -f include/asm @@ -298,8 +351,9 @@ $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in xconfig: symlinks - $(MAKE) -C scripts kconfig.tk - wish -f scripts/kconfig.tk + @echo -e "***\n* Sorry, xconfig is broken; use \"make menuconfig\" instead.\n***" +# $(MAKE) -C scripts kconfig.tk +# wish -f scripts/kconfig.tk menuconfig: include/linux/version.h symlinks $(MAKE) -C scripts/lxdialog all @@ -354,6 +408,9 @@ comma := , +init/kerntypes.o: init/kerntypes.c include/config/MARKER + $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -gstabs -c -o $@ $< + init/version.o: init/version.c include/linux/compile.h include/config/MARKER $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(ARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c @@ -373,11 +430,17 @@ # Exuberant ctags works better with -I tags: dummy - CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \ - ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \ - find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \ + CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"` + ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` + find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a find $(SUBDIRS) init -name '*.[ch]' | xargs ctags $$CTAGSF -a +scope: dummy + find include/asm-$(ARCH) -name '*.h' > scope.list + find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print >> scope.list + find $(SUBDIRS) init -name '*.[ch]' >> scope.list + cscope -b -i scope.list + ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h @@ -413,6 +476,7 @@ .PHONY: _modinst_post _modinst_post: _modinst_post_pcmcia if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi + [ $(IA64_UNWIND_FIX) == 0 ] || $(PERL) scripts/ia64_unwind_fix.pl `find $(strip $(INSTALL_MOD_PATH))/lib/modules/$(KERNELRELEASE) -name '*.o'` > .tmp_modules_ia64_unwind_fix # Backwards compatibilty symlinks for people still using old versions # of pcmcia-cs with hard coded pathnames on insmod. Remove @@ -569,3 +633,10 @@ . scripts/mkversion > .version ; \ rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \ rm $(TOPDIR)/../$(KERNELPATH).tar.gz + +kernel-cflags: + echo "#! /bin/sh" > kernel-cflags +# (offer) remove include paths, those are definetly going to be wrong... +# (steiner) must not have -mconstant-gp + echo "echo \"$(CFLAGS)\" " | sed -e 's/ -I[^ ]\+//g' -e 's/-mconstant-gp//g' >> kernel-cflags + chmod 755 kernel-cflags diff -Nur linux-2.4.19/arch/alpha/config.in linux-2.4.19-sgi211r3/arch/alpha/config.in --- linux-2.4.19/arch/alpha/config.in Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/alpha/config.in Thu Oct 24 04:22:20 2002 @@ -410,6 +410,16 @@ bool 'Legacy kernel start address' CONFIG_ALPHA_LEGACY_START_ADDRESS +tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP +if [ "$CONFIG_DUMP" = "y" ]; then + dep_bool ' LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP + dep_bool ' LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP +fi +if [ "$CONFIG_DUMP" = "m" ]; then + dep_tristate ' LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP + dep_tristate ' LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP +fi + bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then tristate ' Kernel FP software completion' CONFIG_MATHEMU diff -Nur linux-2.4.19/arch/alpha/defconfig linux-2.4.19-sgi211r3/arch/alpha/defconfig --- linux-2.4.19/arch/alpha/defconfig Mon Nov 19 15:19:42 2001 +++ linux-2.4.19-sgi211r3/arch/alpha/defconfig Wed Jan 30 16:28:11 2002 @@ -795,3 +795,12 @@ CONFIG_MATHEMU=y # CONFIG_DEBUG_SLAB is not set CONFIG_MAGIC_SYSRQ=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set diff -Nur linux-2.4.19/arch/alpha/kernel/setup.c linux-2.4.19-sgi211r3/arch/alpha/kernel/setup.c --- linux-2.4.19/arch/alpha/kernel/setup.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/alpha/kernel/setup.c Thu Oct 24 04:22:20 2002 @@ -387,7 +387,11 @@ extern void setup_memory(void *); #endif /* !CONFIG_DISCONTIGMEM */ +#ifndef CONFIG_DUMP int __init +#else +int +#endif page_is_ram(unsigned long pfn) { struct memclust_struct * cluster; diff -Nur linux-2.4.19/arch/alpha/kernel/traps.c linux-2.4.19-sgi211r3/arch/alpha/kernel/traps.c --- linux-2.4.19/arch/alpha/kernel/traps.c Tue Nov 20 15:49:31 2001 +++ linux-2.4.19-sgi211r3/arch/alpha/kernel/traps.c Thu Oct 24 04:22:20 2002 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -186,6 +187,7 @@ while (1); } current->thread.flags |= (1UL << 63); + dump((char *)str, regs); do_exit(SIGSEGV); } diff -Nur linux-2.4.19/arch/alpha/mm/fault.c linux-2.4.19-sgi211r3/arch/alpha/mm/fault.c --- linux-2.4.19/arch/alpha/mm/fault.c Mon Sep 17 16:15:02 2001 +++ linux-2.4.19-sgi211r3/arch/alpha/mm/fault.c Mon Oct 28 20:43:23 2002 @@ -196,8 +196,7 @@ */ out_of_memory: if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -Nur linux-2.4.19/arch/arm/defconfig linux-2.4.19-sgi211r3/arch/arm/defconfig --- linux-2.4.19/arch/arm/defconfig Sat May 19 17:43:05 2001 +++ linux-2.4.19-sgi211r3/arch/arm/defconfig Wed Jan 30 16:28:11 2002 @@ -509,3 +509,12 @@ # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_LL=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set diff -Nur linux-2.4.19/arch/arm/mm/fault-common.c linux-2.4.19-sgi211r3/arch/arm/mm/fault-common.c --- linux-2.4.19/arch/arm/mm/fault-common.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/arm/mm/fault-common.c Mon Oct 28 20:43:23 2002 @@ -225,8 +225,7 @@ * If we are out of memory for pid1, * sleep for a while and retry */ - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); goto survive; check_stack: diff -Nur linux-2.4.19/arch/cris/defconfig linux-2.4.19-sgi211r3/arch/cris/defconfig --- linux-2.4.19/arch/cris/defconfig Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/cris/defconfig Wed Oct 16 14:02:58 2002 @@ -514,3 +514,12 @@ # Kernel hacking # # CONFIG_PROFILE is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set diff -Nur linux-2.4.19/arch/cris/drivers/eeprom.c linux-2.4.19-sgi211r3/arch/cris/drivers/eeprom.c --- linux-2.4.19/arch/cris/drivers/eeprom.c Thu Jul 26 15:10:06 2001 +++ linux-2.4.19-sgi211r3/arch/cris/drivers/eeprom.c Mon Oct 28 20:43:23 2002 @@ -71,6 +71,7 @@ #include #include #include +#include #include #include "i2c.h" @@ -445,36 +446,39 @@ * orig 1: relative from current position * orig 2: position from last eeprom address */ - + loff_t ret; + + lock_kernel(); switch (orig) { case 0: - file->f_pos = offset; + ret = file->f_pos = offset; break; case 1: - file->f_pos += offset; + ret = file->f_pos += offset; break; case 2: - file->f_pos = eeprom.size - offset; + ret = file->f_pos = eeprom.size - offset; break; default: - return -EINVAL; + ret = -EINVAL; } /* truncate position */ if (file->f_pos < 0) { file->f_pos = 0; - return(-EOVERFLOW); + unlock_kernel(); + ret = -EOVERFLOW; } if (file->f_pos >= eeprom.size) { file->f_pos = eeprom.size - 1; - return(-EOVERFLOW); + ret = -EOVERFLOW; } - return ( file->f_pos ); + return ( ret ); } /* Reads data from eeprom. */ diff -Nur linux-2.4.19/arch/i386/Makefile linux-2.4.19-sgi211r3/arch/i386/Makefile --- linux-2.4.19/arch/i386/Makefile Thu Apr 12 12:20:31 2001 +++ linux-2.4.19-sgi211r3/arch/i386/Makefile Wed Oct 16 14:02:58 2002 @@ -93,6 +93,12 @@ CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a +ifdef CONFIG_KDB +LIBS := $(LIBS) $(TOPDIR)/arch/i386/kdb/kdba.o +SUBDIRS := $(SUBDIRS) arch/i386/kdb +CFLAGS += $(shell if $(CC) -fno-optimize-sibling-calls -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-optimize-sibling-calls"; fi) +endif + ifdef CONFIG_MATH_EMULATION SUBDIRS += arch/i386/math-emu DRIVERS += arch/i386/math-emu/math.o @@ -103,6 +109,11 @@ arch/i386/mm: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm + +ifdef CONFIG_KDB +arch/i386/kdb: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/i386/kdb +endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot diff -Nur linux-2.4.19/arch/i386/boot/Makefile linux-2.4.19-sgi211r3/arch/i386/boot/Makefile --- linux-2.4.19/arch/i386/boot/Makefile Sun Aug 5 13:13:19 2001 +++ linux-2.4.19-sgi211r3/arch/i386/boot/Makefile Thu Oct 24 04:22:20 2002 @@ -32,12 +32,14 @@ zlilo: $(CONFIGURE) $(BOOTIMAGE) if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi + if [ -f $(INSTALL_PATH)/Kerntypes ]; then mv $(INSTALL_PATH)/Kerntypes $(INSTALL_PATH)/Kerntypes.old; fi cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz cp $(TOPDIR)/System.map $(INSTALL_PATH)/ + cp $(TOPDIR)/Kerntypes $(INSTALL_PATH)/ if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi install: $(CONFIGURE) $(BOOTIMAGE) - sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)" + sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)" tools/build: tools/build.c $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include diff -Nur linux-2.4.19/arch/i386/boot/install.sh linux-2.4.19-sgi211r3/arch/i386/boot/install.sh --- linux-2.4.19/arch/i386/boot/install.sh Fri Sep 14 14:04:06 2001 +++ linux-2.4.19-sgi211r3/arch/i386/boot/install.sh Thu Oct 24 04:22:20 2002 @@ -16,7 +16,8 @@ # $1 - kernel version # $2 - kernel image file # $3 - kernel map file -# $4 - default install path (blank if root directory) +# $4 - kernel type file +# $5 - default install path (blank if root directory) # # User may have a custom install script @@ -26,15 +27,20 @@ # Default install - same as make zlilo -if [ -f $4/vmlinuz ]; then - mv $4/vmlinuz $4/vmlinuz.old +if [ -f $5/vmlinuz ]; then + mv $5/vmlinuz $5/vmlinuz.old fi -if [ -f $4/System.map ]; then - mv $4/System.map $4/System.old +if [ -f $5/System.map ]; then + mv $5/System.map $5/System.old fi -cat $2 > $4/vmlinuz -cp $3 $4/System.map +if [ -f $5/Kerntypes ]; then + mv $5/Kerntypes $5/Kerntypes.old +fi + +cat $2 > $5/vmlinuz +cp $3 $5/System.map +cp $4 $5/Kerntypes if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi diff -Nur linux-2.4.19/arch/i386/config.in linux-2.4.19-sgi211r3/arch/i386/config.in --- linux-2.4.19/arch/i386/config.in Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/config.in Thu Feb 20 19:55:58 2003 @@ -211,6 +211,8 @@ bool 'Networking support' CONFIG_NET +bool 'CpuMemSet support' CONFIG_CPUMEMSET + # Visual Workstation support is utterly broken. # If you want to see it working mail an VW540 to hch@infradead.org 8) #bool 'SGI Visual Workstation support' CONFIG_VISWS @@ -261,6 +263,11 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +bool 'Support for process aggregates (PAGGs)' CONFIG_PAGG +if [ "$CONFIG_PAGG" = "y" ] ; then + tristate ' Process aggregate based jobs' CONFIG_PAGG_JOB + dep_tristate ' CSA Job Accounting' CONFIG_CSA_JOB_ACCT $CONFIG_PAGG_JOB +fi if [ "$CONFIG_PROC_FS" = "y" ]; then choice 'Kernel core (/proc/kcore) format' \ "ELF CONFIG_KCORE_ELF \ @@ -323,6 +330,15 @@ endmenu mainmenu_option next_comment +comment 'Alternate SCSI support' + +bool 'Alternate SCSI drivers' CONFIG_XSCSI +if [ "$CONFIG_XSCSI" != "n" ]; then + source drivers/xscsi/Config.in +fi +endmenu + +mainmenu_option next_comment comment 'SCSI support' tristate 'SCSI support' CONFIG_SCSI @@ -381,7 +397,7 @@ source drivers/input/Config.in source drivers/char/Config.in -#source drivers/misc/Config.in +source drivers/misc/Config.in source drivers/media/Config.in @@ -415,6 +431,16 @@ mainmenu_option next_comment comment 'Kernel hacking' +tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP +if [ "$CONFIG_DUMP" = "y" ]; then + dep_bool ' LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP + dep_bool ' LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP +fi +if [ "$CONFIG_DUMP" = "m" ]; then + dep_tristate ' LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP + dep_tristate ' LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP +fi + bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM @@ -423,6 +449,18 @@ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER + bool ' Built-in Kernel Debugger support' CONFIG_KDB + dep_tristate ' KDB modules' CONFIG_KDB_MODULES $CONFIG_KDB + if [ "$CONFIG_KDB" = "y" ]; then + bool ' KDB off by default' CONFIG_KDB_OFF + if [ "$CONFIG_USB" != "n" ] ; then + bool ' Support for USB Keyboard in KDB' CONFIG_KDB_USB + fi + comment ' Load all symbols for debugging is required for KDB' + define_bool CONFIG_KALLSYMS y + else + bool ' Load all symbols for debugging' CONFIG_KALLSYMS + fi fi endmenu diff -Nur linux-2.4.19/arch/i386/defconfig linux-2.4.19-sgi211r3/arch/i386/defconfig --- linux-2.4.19/arch/i386/defconfig Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/defconfig Wed Oct 16 14:02:58 2002 @@ -878,3 +878,12 @@ # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set diff -Nur linux-2.4.19/arch/i386/kdb/ChangeLog linux-2.4.19-sgi211r3/arch/i386/kdb/ChangeLog --- linux-2.4.19/arch/i386/kdb/ChangeLog Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/ChangeLog Tue Feb 4 15:36:30 2003 @@ -0,0 +1,127 @@ +2003-02-04 Keith Owens + + * Backport to 2.4.19. + * kdb v3.0-2.4.19-i386-1. + +2003-02-03 Keith Owens + + * Register kdb commands early. + * Handle KDB_ENTER() when kdb=off. + * Optimize __kdba_getarea_size when width is a constant. + * Decode oops via kallsyms if it is available. + * Update copyright notices to 2003. + * Handle call *disp32(%reg) in backtrace. + * Correct keyboard freeze. Ashish Kalra. + * Add command history and editing. Sonic Zhang. + * kdb_toggleled is conditional on KDB_BLINK_LED. Bernhard Fischer. + * Allow tab on serial line for symbol completion. + * Ignore KDB_ENTER() when kdb is already running. + * kdb v3.0-2.4.20-i386-1. + +2002-11-29 Keith Owens + + * Upgrade to 2.4.20. + * kdb v2.5-2.4.20-i386-1. + +2002-11-14 Keith Owens + + * Upgrade to 2.4.20-rc1. + * kdb v2.5-2.4.20-rc1-i386-1. + +2002-11-14 Keith Owens + + * General clean up of handling for breakpoints and single stepping over + software breakpoints. + * Accept ff 1x as well as ff dx for call *(%reg) in backtrace. + * kdb v2.5-2.4.19-i386-1. + +2002-11-01 Keith Owens + + * Prevent SMP IRQ overwriting KDB_ENTER(). + * kdb v2.4-2.4.19-i386-2. + +2002-10-31 Keith Owens + + * Avoid KDB_VECTOR conflict with DUMP_VECTOR. + * Remove kdb_eframe_t. + * Sanity check if we have pt_regs. + * Remove kdba_getcurrentframe(). + * Reinstate missing nmi_watchdog/kdb hook. + * kdb v2.4-2.4.19-i386-1. + +2002-10-17 Keith Owens + + * Correct compile with CONFIG_VT_CONSOLE=n. + * kdb v2.3-2.4.19-i386-5. + +2002-10-04 Keith Owens + + * Add USB keyboard option. + * Minimize differences between patches for 2.4 and 2.5 kernels. + * kdb v2.3-2.4.19-i386-4. + +2002-08-10 Keith Owens + + * Replace kdb_port with kdb_serial to support memory mapped I/O. + Note: This needs kdb v2.3-2.4.19-common-2 or later. + * kdb v2.3-2.4.19-i386-3. + +2002-08-09 Keith Owens + + * Use -fno-optimize-sibling-calls for kdb if gcc supports it. + * .text.lock does not consume an activation frame. + * kdb v2.3-2.4.19-i386-2. + +2002-08-07 Keith Owens + + * Upgrade to 2.4.19. + * Remove individual SGI copyrights, the general SGI copyright applies. + * New .text.lock name. Hugh Dickins. + * Set KERNEL_CS in kdba_getcurrentframe. Hugh Dickins. + * Clean up disassembly layout. Hugh Dickins, Keith Owens. + * Replace hard coded stack size with THREAD_SIZE. Hugh Dickins. + * Better stack layout on bt with no frame pointers. Hugh Dickins. + * Make i386 IO breakpoints (bpha
IO) work again. + Martin Wilck, Keith Owens. + * Remove fixed KDB_MAX_COMMANDS size. + * Add set_fs() around __copy_to_user on kernel addresses. + Randolph Chung. + * Position i386 for CONFIG_NUMA_REPLICATE. + * kdb v2.3-2.4.19-i386-1. + +2002-07-09 Keith Owens + + * Upgrade to 2.4.19-rc1. + +2002-06-14 Keith Owens + + * Upgrade to 2.4.19-pre10. + * kdb v2.1-2.4.19-pre10-i386-1. + +2002-04-09 Keith Owens + + * Upgrade to 2.4.19-pre6. + * kdb v2.1-2.4.19-pre6-i386-1. + +2002-02-26 Keith Owens + + * Upgrade to 2.4.18. + * kdb v2.1-2.4.18-i386-1. + +2002-01-18 Keith Owens + + * Use new kdb_get/put functions. + * Define kdba_{get,put}area_size functions for i386. + * Remove over-engineered dblist callback functions. + * Correctly handle failing call disp32 in backtrace. + * Remove bp_instvalid flag, redundant code. + * Remove dead code. + * kdb v2.1-2.4.17-i386-1. + +2002-01-04 Keith Owens + + * Sync xfs <-> kdb i386 code. + +2001-12-22 Keith Owens + + * Split kdb for i386 as kdb v2.0-2.4.17-i386-1. diff -Nur linux-2.4.19/arch/i386/kdb/Makefile linux-2.4.19-sgi211r3/arch/i386/kdb/Makefile --- linux-2.4.19/arch/i386/kdb/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/Makefile Tue Feb 4 15:36:30 2003 @@ -0,0 +1,40 @@ +# +# Copyright (c) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +O_TARGET := kdba.o +obj-y := kdba_bt.o kdba_bp.o kdba_id.o kdba_io.o kdbasupport.o i386-dis.o + +override CFLAGS := $(CFLAGS:%-pg=% ) + +EXTRA_CFLAGS += -I $(TOPDIR)/arch/$(ARCH)/kdb + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/i386/kdb/ansidecl.h linux-2.4.19-sgi211r3/arch/i386/kdb/ansidecl.h --- linux-2.4.19/arch/i386/kdb/ansidecl.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/ansidecl.h Wed Jan 30 15:32:11 2002 @@ -0,0 +1,198 @@ +/* ANSI and traditional C compatability macros + Copyright 1991, 1992, 1996, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + PTR `void *' `char *' + LONG_DOUBLE `long double' `double' + VOLATILE `volatile' `' + SIGNED `signed' `' + PTRCONST `void *const' `char *' + ANSI_PROTOTYPES 1 not defined + + CONST is also defined, but is obsolete. Just use const. + + obsolete -- DEFUN (name, arglist, args) + + Defines function NAME. + + ARGLIST lists the arguments, separated by commas and enclosed in + parentheses. ARGLIST becomes the argument list in traditional C. + + ARGS list the arguments with their types. It becomes a prototype in + ANSI C, and the type declarations in traditional C. Arguments should + be separated with `AND'. For functions with a variable number of + arguments, the last thing listed should be `DOTS'. + + obsolete -- DEFUN_VOID (name) + + Defines a function NAME, which takes no arguments. + + obsolete -- EXFUN (name, (prototype)) -- obsolete. + + Replaced by PARAMS. Do not use; will disappear someday soon. + Was used in external function declarations. + In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in + parentheses). In traditional C it is `NAME()'. + For a function that takes no arguments, PROTOTYPE should be `(void)'. + + obsolete -- PROTO (type, name, (prototype) -- obsolete. + + This one has also been replaced by PARAMS. Do not use. + + PARAMS ((args)) + + We could use the EXFUN macro to handle prototype declarations, but + the name is misleading and the result is ugly. So we just define a + simple macro to handle the parameter lists, as in: + + static int foo PARAMS ((int, char)); + + This produces: `static int foo();' or `static int foo (int, char);' + + EXFUN would have done it like this: + + static int EXFUN (foo, (int, char)); + + but the function is not external...and it's hard to visually parse + the function name out of the mess. EXFUN should be considered + obsolete; new code should be written to use PARAMS. + + DOTS is also obsolete. + + Examples: + + extern int printf PARAMS ((const char *format, ...)); +*/ + +#ifndef _ANSIDECL_H + +#define _ANSIDECL_H 1 + + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + + +#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ + +#define PTR void * +#define PTRCONST void *CONST +#define LONG_DOUBLE long double + +#ifndef IN_GCC +#define AND , +#define NOARGS void +#define VOLATILE volatile +#define SIGNED signed +#endif /* ! IN_GCC */ + +#ifndef PARAMS +#define PARAMS(paramlist) paramlist +#endif +#define ANSI_PROTOTYPES 1 + +#define VPARAMS(ARGS) ARGS +#define VA_START(va_list,var) va_start(va_list,var) + +/* These are obsolete. Do not use. */ +#ifndef IN_GCC +#define CONST const +#define DOTS , ... +#define PROTO(type, name, arglist) type name arglist +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(void) +#endif /* ! IN_GCC */ + +#else /* Not ANSI C. */ + +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#ifndef IN_GCC +#define AND ; +#define NOARGS +#define VOLATILE +#define SIGNED +#endif /* !IN_GCC */ + +#ifndef const /* some systems define it in header files for non-ansi mode */ +#define const +#endif + +#define PARAMS(paramlist) () + +#define VPARAMS(ARGS) (va_alist) va_dcl +#define VA_START(va_list,var) va_start(va_list) + +/* These are obsolete. Do not use. */ +#ifndef IN_GCC +#define CONST +#define DOTS +#define PROTO(type, name, arglist) type name () +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() +#endif /* ! IN_GCC */ + +#endif /* ANSI C. */ + +/* Define macros for some gcc attributes. This permits us to use the + macros freely, and know that they will come into play for the + version of gcc in which they are supported. */ + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED_LABEL +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93) +# define ATTRIBUTE_UNUSED_LABEL +# else +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED +# endif /* GNUC < 2.93 */ +#endif /* ATTRIBUTE_UNUSED_LABEL */ + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif /* ATTRIBUTE_UNUSED */ + +#ifndef ATTRIBUTE_NORETURN +#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif /* ATTRIBUTE_NORETURN */ + +#ifndef ATTRIBUTE_PRINTF +#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((format (__printf__, m, n))) +#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) +#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) +#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) +#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) +#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) +#endif /* ATTRIBUTE_PRINTF */ + +#endif /* ansidecl.h */ diff -Nur linux-2.4.19/arch/i386/kdb/bfd.h linux-2.4.19-sgi211r3/arch/i386/kdb/bfd.h --- linux-2.4.19/arch/i386/kdb/bfd.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/bfd.h Wed Jan 30 15:32:11 2002 @@ -0,0 +1,3102 @@ +/* Main header file for the bfd library -- portable access to object files. + Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 1999 + Free Software Foundation, Inc. + Contributed by Cygnus Support. + +** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them; +** instead, change bfd-in.h or the other BFD source files processed to +** generate these files. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* bfd.h -- The only header file required by users of the bfd library + +The bfd.h file is generated from bfd-in.h and various .c files; if you +change it, your changes will probably be lost. + +All the prototypes and definitions following the comment "THE FOLLOWING +IS EXTRACTED FROM THE SOURCE" are extracted from the source files for +BFD. If you change it, someone oneday will extract it from the source +again, and your changes will be lost. To save yourself from this bind, +change the definitions in the source in the bfd directory. Type "make +docs" and then "make headers" in that directory, and magically this file +will change to reflect your changes. + +If you don't have the tools to perform the extraction, then you are +safe from someone on your system trampling over your header files. +You should still maintain the equivalence between the source and this +file though; every change you make to the .c file should be reflected +here. */ + +#ifndef __BFD_H_SEEN__ +#define __BFD_H_SEEN__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" + +/* These two lines get substitutions done by commands in Makefile.in. */ +#define BFD_VERSION "2.9.5.0.22" +#define BFD_ARCH_SIZE 32 +#define BFD_HOST_64BIT_LONG 0 +#if 0 +#define BFD_HOST_64_BIT +#define BFD_HOST_U_64_BIT +#endif + +#if BFD_ARCH_SIZE >= 64 +#define BFD64 +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* forward declaration */ +typedef struct _bfd bfd; + +/* To squelch erroneous compiler warnings ("illegal pointer + combination") from the SVR3 compiler, we would like to typedef + boolean to int (it doesn't like functions which return boolean. + Making sure they are never implicitly declared to return int + doesn't seem to help). But this file is not configured based on + the host. */ +/* General rules: functions which are boolean return true on success + and false on failure (unless they're a predicate). -- bfd.doc */ +/* I'm sure this is going to break something and someone is going to + force me to change it. */ +/* typedef enum boolean {false, true} boolean; */ +/* Yup, SVR4 has a "typedef enum boolean" in -fnf */ +/* It gets worse if the host also defines a true/false enum... -sts */ +/* And even worse if your compiler has built-in boolean types... -law */ +#if defined (__GNUG__) && (__GNUC_MINOR__ > 5) +#define TRUE_FALSE_ALREADY_DEFINED +#endif +#ifdef MPW +/* Pre-emptive strike - get the file with the enum. */ +#include +#define TRUE_FALSE_ALREADY_DEFINED +#endif /* MPW */ +#ifndef TRUE_FALSE_ALREADY_DEFINED +typedef enum bfd_boolean {false, true} boolean; +#define BFD_TRUE_FALSE +#else +/* Use enum names that will appear nowhere else. */ +typedef enum bfd_boolean {bfd_fffalse, bfd_tttrue} boolean; +#endif + +/* A pointer to a position in a file. */ +/* FIXME: This should be using off_t from . + For now, try to avoid breaking stuff by not including here. + This will break on systems with 64-bit file offsets (e.g. 4.4BSD). + Probably the best long-term answer is to avoid using file_ptr AND off_t + in this header file, and to handle this in the BFD implementation + rather than in its interface. */ +/* typedef off_t file_ptr; */ +typedef long int file_ptr; + +/* Support for different sizes of target format ints and addresses. + If the type `long' is at least 64 bits, BFD_HOST_64BIT_LONG will be + set to 1 above. Otherwise, if gcc is being used, this code will + use gcc's "long long" type. Otherwise, BFD_HOST_64_BIT must be + defined above. */ + +#ifndef BFD_HOST_64_BIT +# if BFD_HOST_64BIT_LONG +# define BFD_HOST_64_BIT long +# define BFD_HOST_U_64_BIT unsigned long +# else +# ifdef __GNUC__ +# if __GNUC__ >= 2 +# define BFD_HOST_64_BIT long long +# define BFD_HOST_U_64_BIT unsigned long long +# endif /* __GNUC__ >= 2 */ +# endif /* ! defined (__GNUC__) */ +# endif /* ! BFD_HOST_64BIT_LONG */ +#endif /* ! defined (BFD_HOST_64_BIT) */ + +#ifdef BFD64 + +#ifndef BFD_HOST_64_BIT + #error No 64 bit integer type available +#endif /* ! defined (BFD_HOST_64_BIT) */ + +typedef BFD_HOST_U_64_BIT bfd_vma; +typedef BFD_HOST_64_BIT bfd_signed_vma; +typedef BFD_HOST_U_64_BIT bfd_size_type; +typedef BFD_HOST_U_64_BIT symvalue; + +#ifndef fprintf_vma +#if BFD_HOST_64BIT_LONG +#define sprintf_vma(s,x) sprintf (s, "%016lx", x) +#define fprintf_vma(f,x) fprintf (f, "%016lx", x) +#else +#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) +#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) +#define fprintf_vma(s,x) \ + fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#define sprintf_vma(s,x) \ + sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#endif +#endif + +#else /* not BFD64 */ + +/* Represent a target address. Also used as a generic unsigned type + which is guaranteed to be big enough to hold any arithmetic types + we need to deal with. */ +typedef unsigned long bfd_vma; + +/* A generic signed type which is guaranteed to be big enough to hold any + arithmetic types we need to deal with. Can be assumed to be compatible + with bfd_vma in the same way that signed and unsigned ints are compatible + (as parameters, in assignment, etc). */ +typedef long bfd_signed_vma; + +typedef unsigned long symvalue; +typedef unsigned long bfd_size_type; + +/* Print a bfd_vma x on stream s. */ +#define fprintf_vma(s,x) fprintf(s, "%08lx", x) +#define sprintf_vma(s,x) sprintf(s, "%08lx", x) + +#endif /* not BFD64 */ + +#define printf_vma(x) fprintf_vma(stdout,x) + +typedef unsigned int flagword; /* 32 bits of flags */ +typedef unsigned char bfd_byte; + +/** File formats */ + +typedef enum bfd_format { + bfd_unknown = 0, /* file format is unknown */ + bfd_object, /* linker/assember/compiler output */ + bfd_archive, /* object archive file */ + bfd_core, /* core dump */ + bfd_type_end} /* marks the end; don't use it! */ + bfd_format; + +/* Values that may appear in the flags field of a BFD. These also + appear in the object_flags field of the bfd_target structure, where + they indicate the set of flags used by that backend (not all flags + are meaningful for all object file formats) (FIXME: at the moment, + the object_flags values have mostly just been copied from backend + to another, and are not necessarily correct). */ + +/* No flags. */ +#define BFD_NO_FLAGS 0x00 + +/* BFD contains relocation entries. */ +#define HAS_RELOC 0x01 + +/* BFD is directly executable. */ +#define EXEC_P 0x02 + +/* BFD has line number information (basically used for F_LNNO in a + COFF header). */ +#define HAS_LINENO 0x04 + +/* BFD has debugging information. */ +#define HAS_DEBUG 0x08 + +/* BFD has symbols. */ +#define HAS_SYMS 0x10 + +/* BFD has local symbols (basically used for F_LSYMS in a COFF + header). */ +#define HAS_LOCALS 0x20 + +/* BFD is a dynamic object. */ +#define DYNAMIC 0x40 + +/* Text section is write protected (if D_PAGED is not set, this is + like an a.out NMAGIC file) (the linker sets this by default, but + clears it for -r or -N). */ +#define WP_TEXT 0x80 + +/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the + linker sets this by default, but clears it for -r or -n or -N). */ +#define D_PAGED 0x100 + +/* BFD is relaxable (this means that bfd_relax_section may be able to + do something) (sometimes bfd_relax_section can do something even if + this is not set). */ +#define BFD_IS_RELAXABLE 0x200 + +/* This may be set before writing out a BFD to request using a + traditional format. For example, this is used to request that when + writing out an a.out object the symbols not be hashed to eliminate + duplicates. */ +#define BFD_TRADITIONAL_FORMAT 0x400 + +/* This flag indicates that the BFD contents are actually cached in + memory. If this is set, iostream points to a bfd_in_memory struct. */ +#define BFD_IN_MEMORY 0x800 + +/* symbols and relocation */ + +/* A count of carsyms (canonical archive symbols). */ +typedef unsigned long symindex; + +/* How to perform a relocation. */ +typedef const struct reloc_howto_struct reloc_howto_type; + +#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) + +/* General purpose part of a symbol X; + target specific parts are in libcoff.h, libaout.h, etc. */ + +#define bfd_get_section(x) ((x)->section) +#define bfd_get_output_section(x) ((x)->section->output_section) +#define bfd_set_section(x,y) ((x)->section) = (y) +#define bfd_asymbol_base(x) ((x)->section->vma) +#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) +#define bfd_asymbol_name(x) ((x)->name) +/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ +#define bfd_asymbol_bfd(x) ((x)->the_bfd) +#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) + +/* A canonical archive symbol. */ +/* This is a type pun with struct ranlib on purpose! */ +typedef struct carsym { + char *name; + file_ptr file_offset; /* look here to find the file */ +} carsym; /* to make these you call a carsymogen */ + + +/* Used in generating armaps (archive tables of contents). + Perhaps just a forward definition would do? */ +struct orl { /* output ranlib */ + char **name; /* symbol name */ + file_ptr pos; /* bfd* or file position */ + int namidx; /* index into string table */ +}; + + +/* Linenumber stuff */ +typedef struct lineno_cache_entry { + unsigned int line_number; /* Linenumber from start of function*/ + union { + struct symbol_cache_entry *sym; /* Function name */ + unsigned long offset; /* Offset into section */ + } u; +} alent; + +/* object and core file sections */ + +#define align_power(addr, align) \ + ( ((addr) + ((1<<(align))-1)) & (-1 << (align))) + +typedef struct sec *sec_ptr; + +#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) +#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) +#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_section_name(bfd, ptr) ((ptr)->name) +#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr)) +#define bfd_section_vma(bfd, ptr) ((ptr)->vma) +#define bfd_section_lma(bfd, ptr) ((ptr)->lma) +#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) +#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) +#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) + +#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) + +#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = (boolean)true), true) +#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true) +#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true) + +typedef struct stat stat_type; + +typedef enum bfd_print_symbol +{ + bfd_print_symbol_name, + bfd_print_symbol_more, + bfd_print_symbol_all +} bfd_print_symbol_type; + +/* Information about a symbol that nm needs. */ + +typedef struct _symbol_info +{ + symvalue value; + char type; + CONST char *name; /* Symbol name. */ + unsigned char stab_type; /* Stab type. */ + char stab_other; /* Stab other. */ + short stab_desc; /* Stab desc. */ + CONST char *stab_name; /* String for stab type. */ +} symbol_info; + +/* Get the name of a stabs type code. */ + +extern const char *bfd_get_stab_name PARAMS ((int)); + +/* Hash table routines. There is no way to free up a hash table. */ + +/* An element in the hash table. Most uses will actually use a larger + structure, and an instance of this will be the first field. */ + +struct bfd_hash_entry +{ + /* Next entry for this hash code. */ + struct bfd_hash_entry *next; + /* String being hashed. */ + const char *string; + /* Hash code. This is the full hash code, not the index into the + table. */ + unsigned long hash; +}; + +/* A hash table. */ + +struct bfd_hash_table +{ + /* The hash array. */ + struct bfd_hash_entry **table; + /* The number of slots in the hash table. */ + unsigned int size; + /* A function used to create new elements in the hash table. The + first entry is itself a pointer to an element. When this + function is first invoked, this pointer will be NULL. However, + having the pointer permits a hierarchy of method functions to be + built each of which calls the function in the superclass. Thus + each function should be written to allocate a new block of memory + only if the argument is NULL. */ + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + /* An objalloc for this hash table. This is a struct objalloc *, + but we use PTR to avoid requiring the inclusion of objalloc.h. */ + PTR memory; +}; + +/* Initialize a hash table. */ +extern boolean bfd_hash_table_init + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Initialize a hash table specifying a size. */ +extern boolean bfd_hash_table_init_n + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int size)); + +/* Free up a hash table. */ +extern void bfd_hash_table_free PARAMS ((struct bfd_hash_table *)); + +/* Look up a string in a hash table. If CREATE is true, a new entry + will be created for this string if one does not already exist. The + COPY argument must be true if this routine should copy the string + into newly allocated memory when adding an entry. */ +extern struct bfd_hash_entry *bfd_hash_lookup + PARAMS ((struct bfd_hash_table *, const char *, boolean create, + boolean copy)); + +/* Replace an entry in a hash table. */ +extern void bfd_hash_replace + PARAMS ((struct bfd_hash_table *, struct bfd_hash_entry *old, + struct bfd_hash_entry *nw)); + +/* Base method for creating a hash table entry. */ +extern struct bfd_hash_entry *bfd_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +/* Grab some space for a hash table entry. */ +extern PTR bfd_hash_allocate PARAMS ((struct bfd_hash_table *, + unsigned int)); + +/* Traverse a hash table in a random order, calling a function on each + element. If the function returns false, the traversal stops. The + INFO argument is passed to the function. */ +extern void bfd_hash_traverse PARAMS ((struct bfd_hash_table *, + boolean (*) (struct bfd_hash_entry *, + PTR), + PTR info)); + +/* Semi-portable string concatenation in cpp. + The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors. + The problem is, "32_" is not a valid preprocessing token, and we don't + want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the + inner CAT macros to be evaluated first, producing still-valid pp-tokens. + Then the final concatenation can be done. (Sigh.) */ +#ifndef CAT +#ifdef SABER +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#else +#if defined(__STDC__) || defined(ALMOST_STDC) +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define XCAT2(a,b) CAT(a,b) +#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d)) +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#endif +#endif +#endif + +#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table + +/* User program access to BFD facilities */ + +/* Direct I/O routines, for programs which know more about the object + file than BFD does. Use higher level routines if possible. */ + +extern bfd_size_type bfd_read + PARAMS ((PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern bfd_size_type bfd_write + PARAMS ((const PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern int bfd_seek PARAMS ((bfd *abfd, file_ptr fp, int direction)); +extern long bfd_tell PARAMS ((bfd *abfd)); +extern int bfd_flush PARAMS ((bfd *abfd)); +extern int bfd_stat PARAMS ((bfd *abfd, struct stat *)); + + +/* Cast from const char * to char * so that caller can assign to + a char * without a warning. */ +#define bfd_get_filename(abfd) ((char *) (abfd)->filename) +#define bfd_get_cacheable(abfd) ((abfd)->cacheable) +#define bfd_get_format(abfd) ((abfd)->format) +#define bfd_get_target(abfd) ((abfd)->xvec->name) +#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) +#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) +#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) +#define bfd_header_big_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) +#define bfd_header_little_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) +#define bfd_get_file_flags(abfd) ((abfd)->flags) +#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) +#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) +#define bfd_my_archive(abfd) ((abfd)->my_archive) +#define bfd_has_map(abfd) ((abfd)->has_armap) + +#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) +#define bfd_usrdata(abfd) ((abfd)->usrdata) + +#define bfd_get_start_address(abfd) ((abfd)->start_address) +#define bfd_get_symcount(abfd) ((abfd)->symcount) +#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) +#define bfd_count_sections(abfd) ((abfd)->section_count) + +#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) + +#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = (boolean)(bool)), true) + +extern boolean bfd_record_phdr + PARAMS ((bfd *, unsigned long, boolean, flagword, boolean, bfd_vma, + boolean, boolean, unsigned int, struct sec **)); + +/* Byte swapping routines. */ + +bfd_vma bfd_getb64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb16 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_16 PARAMS ((const unsigned char *)); +void bfd_putb64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb16 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl16 PARAMS ((bfd_vma, unsigned char *)); + +/* Externally visible ECOFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_debug_info; +struct ecoff_debug_swap; +struct ecoff_extr; +struct symbol_cache_entry; +struct bfd_link_info; +struct bfd_link_hash_entry; +struct bfd_elf_version_tree; +#endif +extern bfd_vma bfd_ecoff_get_gp_value PARAMS ((bfd * abfd)); +extern boolean bfd_ecoff_set_gp_value PARAMS ((bfd *abfd, bfd_vma gp_value)); +extern boolean bfd_ecoff_set_regmasks + PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask, + unsigned long *cprmask)); +extern PTR bfd_ecoff_debug_init + PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern void bfd_ecoff_debug_free + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + bfd *input_bfd, struct ecoff_debug_info *input_debug, + const struct ecoff_debug_swap *input_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate_other + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, bfd *input_bfd, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_externals + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + boolean relocateable, + boolean (*get_extr) (struct symbol_cache_entry *, + struct ecoff_extr *), + void (*set_index) (struct symbol_cache_entry *, + bfd_size_type))); +extern boolean bfd_ecoff_debug_one_external + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + const char *name, struct ecoff_extr *esym)); +extern bfd_size_type bfd_ecoff_debug_size + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +extern boolean bfd_ecoff_write_debug + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, file_ptr where)); +extern boolean bfd_ecoff_write_accumulated_debug + PARAMS ((PTR handle, bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + struct bfd_link_info *info, file_ptr where)); +extern boolean bfd_mips_ecoff_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* Externally visible ELF routines. */ + +struct bfd_link_needed_list +{ + struct bfd_link_needed_list *next; + bfd *by; + const char *name; +}; + +extern boolean bfd_elf32_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern boolean bfd_elf64_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern struct bfd_link_needed_list *bfd_elf_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf_get_bfd_needed_list + PARAMS ((bfd *, struct bfd_link_needed_list **)); +extern boolean bfd_elf32_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, const char *, + const char * const *, struct bfd_link_info *, struct sec **, + struct bfd_elf_version_tree *)); +extern boolean bfd_elf64_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, const char *, + const char * const *, struct bfd_link_info *, struct sec **, + struct bfd_elf_version_tree *)); +extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *)); +extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *)); + +/* SunOS shared library support routines for the linker. */ + +extern struct bfd_link_needed_list *bfd_sunos_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_sunos_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_sunos_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, struct sec **, struct sec **, + struct sec **)); + +/* Linux shared library support routines for the linker. */ + +extern boolean bfd_i386linux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_m68klinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_sparclinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +/* mmap hacks */ + +struct _bfd_window_internal; +typedef struct _bfd_window_internal bfd_window_internal; + +typedef struct _bfd_window { + /* What the user asked for. */ + PTR data; + bfd_size_type size; + /* The actual window used by BFD. Small user-requested read-only + regions sharing a page may share a single window into the object + file. Read-write versions shouldn't until I've fixed things to + keep track of which portions have been claimed by the + application; don't want to give the same region back when the + application wants two writable copies! */ + struct _bfd_window_internal *i; +} bfd_window; + +extern void bfd_init_window PARAMS ((bfd_window *)); +extern void bfd_free_window PARAMS ((bfd_window *)); +extern boolean bfd_get_file_window + PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, boolean)); + +/* XCOFF support routines for the linker. */ + +extern boolean bfd_xcoff_link_record_set + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_size_type)); +extern boolean bfd_xcoff_import_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_vma, const char *, const char *, const char *)); +extern boolean bfd_xcoff_export_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + boolean)); +extern boolean bfd_xcoff_link_count_reloc + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, + unsigned long, unsigned long, unsigned long, boolean, + int, boolean, boolean, struct sec **)); + +/* Externally visible COFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct internal_syment; +union internal_auxent; +#endif + +extern boolean bfd_coff_get_syment + PARAMS ((bfd *, struct symbol_cache_entry *, struct internal_syment *)); + +extern boolean bfd_coff_get_auxent + PARAMS ((bfd *, struct symbol_cache_entry *, int, union internal_auxent *)); + +extern boolean bfd_coff_set_symbol_class + PARAMS ((bfd *, struct symbol_cache_entry *, unsigned int)); + +/* ARM Interworking support. Called from linker. */ +extern boolean bfd_arm_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern boolean bfd_arm_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern boolean bfd_arm_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +/* ELF ARM Interworking support. Called from linker. */ +extern boolean bfd_elf32_arm_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern boolean bfd_elf32_arm_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern boolean bfd_elf32_arm_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +/* And more from the source. */ +void +bfd_init PARAMS ((void)); + +bfd * +bfd_openr PARAMS ((CONST char *filename, CONST char *target)); + +bfd * +bfd_fdopenr PARAMS ((CONST char *filename, CONST char *target, int fd)); + +bfd * +bfd_openstreamr PARAMS ((const char *, const char *, PTR)); + +bfd * +bfd_openw PARAMS ((CONST char *filename, CONST char *target)); + +boolean +bfd_close PARAMS ((bfd *abfd)); + +boolean +bfd_close_all_done PARAMS ((bfd *)); + +bfd * +bfd_create PARAMS ((CONST char *filename, bfd *templ)); + +boolean +bfd_make_writable PARAMS ((bfd *abfd)); + +boolean +bfd_make_readable PARAMS ((bfd *abfd)); + + + /* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + ((void) (*((unsigned char *)(ptr)) = (unsigned char)(val))) +#define bfd_put_signed_8 \ + bfd_put_8 +#define bfd_get_8(abfd, ptr) \ + (*(unsigned char *)(ptr)) +#define bfd_get_signed_8(abfd, ptr) \ + ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) + +#define bfd_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +#define bfd_put_signed_16 \ + bfd_put_16 +#define bfd_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx16, (ptr)) +#define bfd_get_signed_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) + +#define bfd_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +#define bfd_put_signed_32 \ + bfd_put_32 +#define bfd_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx32, (ptr)) +#define bfd_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) + +#define bfd_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +#define bfd_put_signed_64 \ + bfd_put_64 +#define bfd_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx64, (ptr)) +#define bfd_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) + +#define bfd_get(bits, abfd, ptr) \ + ((bits) == 8 ? bfd_get_8 (abfd, ptr) \ + : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ + : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ + : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ + : (abort (), (bfd_vma) - 1)) + +#define bfd_put(bits, abfd, val, ptr) \ + ((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ + : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ + : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ + : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ + : (abort (), (void) 0)) + + + /* Byte swapping macros for file header data. */ + +#define bfd_h_put_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_put_signed_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_get_8(abfd, ptr) \ + bfd_get_8 (abfd, ptr) +#define bfd_h_get_signed_8(abfd, ptr) \ + bfd_get_signed_8 (abfd, ptr) + +#define bfd_h_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +#define bfd_h_put_signed_16 \ + bfd_h_put_16 +#define bfd_h_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx16,(ptr)) +#define bfd_h_get_signed_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) + +#define bfd_h_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +#define bfd_h_put_signed_32 \ + bfd_h_put_32 +#define bfd_h_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx32,(ptr)) +#define bfd_h_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) + +#define bfd_h_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +#define bfd_h_put_signed_64 \ + bfd_h_put_64 +#define bfd_h_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx64,(ptr)) +#define bfd_h_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) + + /* This structure is used for a comdat section, as in PE. A comdat + section is associated with a particular symbol. When the linker + sees a comdat section, it keeps only one of the sections with a + given name and associated with a given symbol. */ + +struct bfd_comdat_info +{ + /* The name of the symbol associated with a comdat section. */ + const char *name; + + /* The local symbol table index of the symbol associated with a + comdat section. This is only meaningful to the object file format + specific code; it is not an index into the list returned by + bfd_canonicalize_symtab. */ + long symbol; + + /* If this section is being discarded, the linker uses this field + to point to the input section which is being kept. */ + struct sec *sec; +}; + +typedef struct sec +{ + /* The name of the section; the name isn't a copy, the pointer is + the same as that passed to bfd_make_section. */ + + CONST char *name; + + /* Which section is it; 0..nth. */ + + int index; + + /* The next section in the list belonging to the BFD, or NULL. */ + + struct sec *next; + + /* The field flags contains attributes of the section. Some + flags are read in from the object file, and some are + synthesized from other information. */ + + flagword flags; + +#define SEC_NO_FLAGS 0x000 + + /* Tells the OS to allocate space for this section when loading. + This is clear for a section containing debug information + only. */ +#define SEC_ALLOC 0x001 + + /* Tells the OS to load the section from the file when loading. + This is clear for a .bss section. */ +#define SEC_LOAD 0x002 + + /* The section contains data still to be relocated, so there is + some relocation information too. */ +#define SEC_RELOC 0x004 + +#if 0 /* Obsolete ? */ +#define SEC_BALIGN 0x008 +#endif + + /* A signal to the OS that the section contains read only + data. */ +#define SEC_READONLY 0x010 + + /* The section contains code only. */ +#define SEC_CODE 0x020 + + /* The section contains data only. */ +#define SEC_DATA 0x040 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x080 + + /* The section contains constructor information. This section + type is used by the linker to create lists of constructors and + destructors used by <>. When a back end sees a symbol + which should be used in a constructor list, it creates a new + section for the type of name (e.g., <<__CTOR_LIST__>>), attaches + the symbol to it, and builds a relocation. To build the lists + of constructors, all the linker has to do is catenate all the + sections called <<__CTOR_LIST__>> and relocate the data + contained within - exactly the operations it would peform on + standard data. */ +#define SEC_CONSTRUCTOR 0x100 + + /* The section is a constructor, and should be placed at the + end of the text, data, or bss section(?). */ +#define SEC_CONSTRUCTOR_TEXT 0x1100 +#define SEC_CONSTRUCTOR_DATA 0x2100 +#define SEC_CONSTRUCTOR_BSS 0x3100 + + /* The section has contents - a data section could be + <> | <>; a debug section could be + <> */ +#define SEC_HAS_CONTENTS 0x200 + + /* An instruction to the linker to not output the section + even if it has information which would normally be written. */ +#define SEC_NEVER_LOAD 0x400 + + /* The section is a COFF shared library section. This flag is + only for the linker. If this type of section appears in + the input file, the linker must copy it to the output file + without changing the vma or size. FIXME: Although this + was originally intended to be general, it really is COFF + specific (and the flag was renamed to indicate this). It + might be cleaner to have some more general mechanism to + allow the back end to control what the linker does with + sections. */ +#define SEC_COFF_SHARED_LIBRARY 0x800 + + /* The section contains common symbols (symbols may be defined + multiple times, the value of a symbol is the amount of + space it requires, and the largest symbol value is the one + used). Most targets have exactly one of these (which we + translate to bfd_com_section_ptr), but ECOFF has two. */ +#define SEC_IS_COMMON 0x8000 + + /* The section contains only debugging information. For + example, this is set for ELF .debug and .stab sections. + strip tests this flag to see if a section can be + discarded. */ +#define SEC_DEBUGGING 0x10000 + + /* The contents of this section are held in memory pointed to + by the contents field. This is checked by + bfd_get_section_contents, and the data is retrieved from + memory if appropriate. */ +#define SEC_IN_MEMORY 0x20000 + + /* The contents of this section are to be excluded by the + linker for executable and shared objects unless those + objects are to be further relocated. */ +#define SEC_EXCLUDE 0x40000 + + /* The contents of this section are to be sorted by the + based on the address specified in the associated symbol + table. */ +#define SEC_SORT_ENTRIES 0x80000 + + /* When linking, duplicate sections of the same name should be + discarded, rather than being combined into a single section as + is usually done. This is similar to how common symbols are + handled. See SEC_LINK_DUPLICATES below. */ +#define SEC_LINK_ONCE 0x100000 + + /* If SEC_LINK_ONCE is set, this bitfield describes how the linker + should handle duplicate sections. */ +#define SEC_LINK_DUPLICATES 0x600000 + + /* This value for SEC_LINK_DUPLICATES means that duplicate + sections with the same name should simply be discarded. */ +#define SEC_LINK_DUPLICATES_DISCARD 0x0 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if there are any duplicate sections, although + it should still only link one copy. */ +#define SEC_LINK_DUPLICATES_ONE_ONLY 0x200000 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if any duplicate sections are a different size. */ +#define SEC_LINK_DUPLICATES_SAME_SIZE 0x400000 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if any duplicate sections contain different + contents. */ +#define SEC_LINK_DUPLICATES_SAME_CONTENTS 0x600000 + + /* This section was created by the linker as part of dynamic + relocation or other arcane processing. It is skipped when + going through the first-pass output, trusting that someone + else up the line will take care of it later. */ +#define SEC_LINKER_CREATED 0x800000 + + /* This section should not be subject to garbage collection. */ +#define SEC_KEEP 0x1000000 + + /* This section contains "short" data, and should be placed + "near" the GP. */ +#define SEC_SMALL_DATA 0x2000000 + + /* This section contains data which may be shared with other + executables or shared objects. */ +#define SEC_SHARED 0x4000000 + + /* End of section flags. */ + + /* Some internal packed boolean fields. */ + + /* See the vma field. */ + unsigned int user_set_vma : 1; + + /* Whether relocations have been processed. */ + unsigned int reloc_done : 1; + + /* A mark flag used by some of the linker backends. */ + unsigned int linker_mark : 1; + + /* A mark flag used by some linker backends for garbage collection. */ + unsigned int gc_mark : 1; + + /* End of internal packed boolean fields. */ + + /* The virtual memory address of the section - where it will be + at run time. The symbols are relocated against this. The + user_set_vma flag is maintained by bfd; if it's not set, the + backend can assign addresses (for example, in <>, where + the default address for <<.data>> is dependent on the specific + target and various flags). */ + + bfd_vma vma; + + /* The load address of the section - where it would be in a + rom image; really only used for writing section header + information. */ + + bfd_vma lma; + + /* The size of the section in bytes, as it will be output. + contains a value even if the section has no contents (e.g., the + size of <<.bss>>). This will be filled in after relocation */ + + bfd_size_type _cooked_size; + + /* The original size on disk of the section, in bytes. Normally this + value is the same as the size, but if some relaxing has + been done, then this value will be bigger. */ + + bfd_size_type _raw_size; + + /* If this section is going to be output, then this value is the + offset into the output section of the first byte in the input + section. E.g., if this was going to start at the 100th byte in + the output section, this value would be 100. */ + + bfd_vma output_offset; + + /* The output section through which to map on output. */ + + struct sec *output_section; + + /* The alignment requirement of the section, as an exponent of 2 - + e.g., 3 aligns to 2^3 (or 8). */ + + unsigned int alignment_power; + + /* If an input section, a pointer to a vector of relocation + records for the data in this section. */ + + struct reloc_cache_entry *relocation; + + /* If an output section, a pointer to a vector of pointers to + relocation records for the data in this section. */ + + struct reloc_cache_entry **orelocation; + + /* The number of relocation records in one of the above */ + + unsigned reloc_count; + + /* Information below is back end specific - and not always used + or updated. */ + + /* File position of section data */ + + file_ptr filepos; + + /* File position of relocation info */ + + file_ptr rel_filepos; + + /* File position of line data */ + + file_ptr line_filepos; + + /* Pointer to data for applications */ + + PTR userdata; + + /* If the SEC_IN_MEMORY flag is set, this points to the actual + contents. */ + unsigned char *contents; + + /* Attached line number information */ + + alent *lineno; + + /* Number of line number records */ + + unsigned int lineno_count; + + /* Optional information about a COMDAT entry; NULL if not COMDAT */ + + struct bfd_comdat_info *comdat; + + /* When a section is being output, this value changes as more + linenumbers are written out */ + + file_ptr moving_line_filepos; + + /* What the section number is in the target world */ + + int target_index; + + PTR used_by_bfd; + + /* If this is a constructor section then here is a list of the + relocations created to relocate items within it. */ + + struct relent_chain *constructor_chain; + + /* The BFD which owns the section. */ + + bfd *owner; + + /* A symbol which points at this section only */ + struct symbol_cache_entry *symbol; + struct symbol_cache_entry **symbol_ptr_ptr; + + struct bfd_link_order *link_order_head; + struct bfd_link_order *link_order_tail; +} asection ; + + /* These sections are global, and are managed by BFD. The application + and target back end are not permitted to change the values in + these sections. New code should use the section_ptr macros rather + than referring directly to the const sections. The const sections + may eventually vanish. */ +#define BFD_ABS_SECTION_NAME "*ABS*" +#define BFD_UND_SECTION_NAME "*UND*" +#define BFD_COM_SECTION_NAME "*COM*" +#define BFD_IND_SECTION_NAME "*IND*" + + /* the absolute section */ +extern const asection bfd_abs_section; +#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) +#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) + /* Pointer to the undefined section */ +extern const asection bfd_und_section; +#define bfd_und_section_ptr ((asection *) &bfd_und_section) +#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) + /* Pointer to the common section */ +extern const asection bfd_com_section; +#define bfd_com_section_ptr ((asection *) &bfd_com_section) + /* Pointer to the indirect section */ +extern const asection bfd_ind_section; +#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) + +extern const struct symbol_cache_entry * const bfd_abs_symbol; +extern const struct symbol_cache_entry * const bfd_com_symbol; +extern const struct symbol_cache_entry * const bfd_und_symbol; +extern const struct symbol_cache_entry * const bfd_ind_symbol; +#define bfd_get_section_size_before_reloc(section) \ + (section->reloc_done ? (abort(),1): (section)->_raw_size) +#define bfd_get_section_size_after_reloc(section) \ + ((section->reloc_done) ? (section)->_cooked_size: (abort(),1)) +asection * +bfd_get_section_by_name PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section_old_way PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section_anyway PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section PARAMS ((bfd *, CONST char *name)); + +boolean +bfd_set_section_flags PARAMS ((bfd *abfd, asection *sec, flagword flags)); + +void +bfd_map_over_sections PARAMS ((bfd *abfd, + void (*func)(bfd *abfd, + asection *sect, + PTR obj), + PTR obj)); + +boolean +bfd_set_section_size PARAMS ((bfd *abfd, asection *sec, bfd_size_type val)); + +boolean +bfd_set_section_contents + PARAMS ((bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count)); + +boolean +bfd_get_section_contents + PARAMS ((bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count)); + +boolean +bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec, bfd *obfd, asection *osec)); + +#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ + BFD_SEND (obfd, _bfd_copy_private_section_data, \ + (ibfd, isection, obfd, osection)) +void +_bfd_strip_section_from_output + PARAMS ((asection *section)); + +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ +#define bfd_mach_m68000 1 +#define bfd_mach_m68008 2 +#define bfd_mach_m68010 3 +#define bfd_mach_m68020 4 +#define bfd_mach_m68030 5 +#define bfd_mach_m68040 6 +#define bfd_mach_m68060 7 +#define bfd_mach_cpu32 8 + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 +#define bfd_mach_i960_jx 7 +#define bfd_mach_i960_hx 8 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ +#define bfd_mach_sparc 1 + /* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +#define bfd_mach_sparc_sparclet 2 +#define bfd_mach_sparc_sparclite 3 +#define bfd_mach_sparc_v8plus 4 +#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */ +#define bfd_mach_sparc_sparclite_le 6 +#define bfd_mach_sparc_v9 7 +#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns */ + /* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v9_p(mach) \ + ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a) + bfd_arch_mips, /* MIPS Rxxxx */ +#define bfd_mach_mips3000 3000 +#define bfd_mach_mips3900 3900 +#define bfd_mach_mips4000 4000 +#define bfd_mach_mips4010 4010 +#define bfd_mach_mips4100 4100 +#define bfd_mach_mips4111 4111 +#define bfd_mach_mips4300 4300 +#define bfd_mach_mips4400 4400 +#define bfd_mach_mips4600 4600 +#define bfd_mach_mips4650 4650 +#define bfd_mach_mips5000 5000 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips16 16 + bfd_arch_i386, /* Intel 386 */ +#define bfd_mach_i386_i386 0 +#define bfd_mach_i386_i8086 1 +#define bfd_mach_i386_i386_intel_syntax 2 + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_i370, /* IBM 360/370 Mainframes */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Hitachi H8/300 */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 +#define bfd_mach_h8300s 3 + bfd_arch_powerpc, /* PowerPC */ + bfd_arch_rs6000, /* IBM RS/6000 */ + bfd_arch_hppa, /* HP PA RISC */ + bfd_arch_d10v, /* Mitsubishi D10V */ +#define bfd_mach_d10v 0 +#define bfd_mach_d10v_ts2 2 +#define bfd_mach_d10v_ts3 3 + bfd_arch_d30v, /* Mitsubishi D30V */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ +#define bfd_mach_sh 0 +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3e 0x3e + bfd_arch_alpha, /* Dec Alpha */ +#define bfd_mach_alpha_ev4 0x10 +#define bfd_mach_alpha_ev5 0x20 +#define bfd_mach_alpha_ev6 0x30 + bfd_arch_arm, /* Advanced Risc Machines ARM */ +#define bfd_mach_arm_2 1 +#define bfd_mach_arm_2a 2 +#define bfd_mach_arm_3 3 +#define bfd_mach_arm_3M 4 +#define bfd_mach_arm_4 5 +#define bfd_mach_arm_4T 6 +#define bfd_mach_arm_5 7 +#define bfd_mach_arm_5T 8 + bfd_arch_ns32k, /* National Semiconductors ns32000 */ + bfd_arch_w65, /* WDC 65816 */ + bfd_arch_tic30, /* Texas Instruments TMS320C30 */ + bfd_arch_tic80, /* TI TMS320c80 (MVP) */ + bfd_arch_v850, /* NEC V850 */ +#define bfd_mach_v850 0 +#define bfd_mach_v850e 'E' +#define bfd_mach_v850ea 'A' + bfd_arch_arc, /* Argonaut RISC Core */ +#define bfd_mach_arc_base 0 + bfd_arch_m32r, /* Mitsubishi M32R/D */ +#define bfd_mach_m32r 0 /* backwards compatibility */ +#define bfd_mach_m32rx 'x' + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ +#define bfd_mach_mn10300 300 +#define bfd_mach_am33 330 + bfd_arch_fr30, +#define bfd_mach_fr30 0x46523330 + bfd_arch_mcore, + bfd_arch_pj, + bfd_arch_last + }; + +typedef struct bfd_arch_info +{ + int bits_per_word; + int bits_per_address; + int bits_per_byte; + enum bfd_architecture arch; + unsigned long mach; + const char *arch_name; + const char *printable_name; + unsigned int section_align_power; + /* true if this is the default machine for the architecture */ + boolean the_default; + const struct bfd_arch_info * (*compatible) + PARAMS ((const struct bfd_arch_info *a, + const struct bfd_arch_info *b)); + + boolean (*scan) PARAMS ((const struct bfd_arch_info *, const char *)); + + const struct bfd_arch_info *next; +} bfd_arch_info_type; +const char * +bfd_printable_name PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_scan_arch PARAMS ((const char *string)); + +const char ** +bfd_arch_list PARAMS ((void)); + +const bfd_arch_info_type * +bfd_arch_get_compatible PARAMS (( + const bfd *abfd, + const bfd *bbfd)); + +void +bfd_set_arch_info PARAMS ((bfd *abfd, const bfd_arch_info_type *arg)); + +enum bfd_architecture +bfd_get_arch PARAMS ((bfd *abfd)); + +unsigned long +bfd_get_mach PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_address PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_get_arch_info PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_lookup_arch + PARAMS ((enum bfd_architecture + arch, + unsigned long machine)); + +const char * +bfd_printable_arch_mach + PARAMS ((enum bfd_architecture arch, unsigned long machine)); + +typedef enum bfd_reloc_status +{ + /* No errors detected */ + bfd_reloc_ok, + + /* The relocation was performed, but there was an overflow. */ + bfd_reloc_overflow, + + /* The address to relocate was not within the section supplied. */ + bfd_reloc_outofrange, + + /* Used by special functions */ + bfd_reloc_continue, + + /* Unsupported relocation size requested. */ + bfd_reloc_notsupported, + + /* Unused */ + bfd_reloc_other, + + /* The symbol to relocate against was undefined. */ + bfd_reloc_undefined, + + /* The relocation was performed, but may not be ok - presently + generated only when linking i960 coff files with i960 b.out + symbols. If this type is returned, the error_message argument + to bfd_perform_relocation will be set. */ + bfd_reloc_dangerous + } + bfd_reloc_status_type; + + +typedef struct reloc_cache_entry +{ + /* A pointer into the canonical table of pointers */ + struct symbol_cache_entry **sym_ptr_ptr; + + /* offset in section */ + bfd_size_type address; + + /* addend for relocation value */ + bfd_vma addend; + + /* Pointer to how to perform the required relocation */ + reloc_howto_type *howto; + +} arelent; +enum complain_overflow +{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the bitfield overflows, whether it is considered + as signed or unsigned. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +}; + +struct reloc_howto_struct +{ + /* The type field has mainly a documentary use - the back end can + do what it wants with it, though normally the back end's + external idea of what a reloc number is stored + in this field. For example, a PC relative word relocation + in a coff environment has the type 023 - because that's + what the outside world calls a R_PCRWORD reloc. */ + unsigned int type; + + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift; + + /* The size of the item to be relocated. This is *not* a + power-of-two measure. To get the number of bytes operated + on by a type of relocation, use bfd_get_reloc_size. */ + int size; + + /* The number of bits in the item to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize; + + /* Notes that the relocation is relative to the location in the + data section of the addend. The relocation function will + subtract from the relocation value the address of the location + being relocated. */ + boolean pc_relative; + + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos; + + /* What type of overflow error should be checked for when + relocating. */ + enum complain_overflow complain_on_overflow; + + /* If this field is non null, then the supplied function is + called rather than the normal function. This allows really + strange relocation methods to be accomodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + PARAMS ((bfd *abfd, + arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + + /* The textual name of the relocation type. */ + char *name; + + /* When performing a partial link, some formats must modify the + relocations rather than the data - this flag signals this.*/ + boolean partial_inplace; + + /* The src_mask selects which parts of the read in data + are to be used in the relocation sum. E.g., if this was an 8 bit + bit of data which we read and relocated, this would be + 0x000000ff. When we have relocs which have an addend, such as + sun4 extended relocs, the value in the offset part of a + relocating field is garbage so we never use it. In this case + the mask would be 0x00000000. */ + bfd_vma src_mask; + + /* The dst_mask selects which parts of the instruction are replaced + into the instruction. In most cases src_mask == dst_mask, + except in the above special case, where dst_mask would be + 0x000000ff, and src_mask would be 0x00000000. */ + bfd_vma dst_mask; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., m88k bcs); this flag signals the fact.*/ + boolean pcrel_offset; + +}; +#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ + {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} +#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) + +#define EMPTY_HOWTO(C) \ + HOWTO((C),0,0,0,false,0,complain_overflow_dont,NULL,NULL,false,0,0,false) + +#define HOWTO_PREPARE(relocation, symbol) \ + { \ + if (symbol != (asymbol *)NULL) { \ + if (bfd_is_com_section (symbol->section)) { \ + relocation = 0; \ + } \ + else { \ + relocation = symbol->value; \ + } \ + } \ +} +unsigned int +bfd_get_reloc_size PARAMS ((reloc_howto_type *)); + +typedef struct relent_chain { + arelent relent; + struct relent_chain *next; +} arelent_chain; +bfd_reloc_status_type + +bfd_check_overflow + PARAMS ((enum complain_overflow how, + unsigned int bitsize, + unsigned int rightshift, + unsigned int addrsize, + bfd_vma relocation)); + +bfd_reloc_status_type + +bfd_perform_relocation + PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + +bfd_reloc_status_type + +bfd_install_relocation + PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, bfd_vma data_start, + asection *input_section, + char **error_message)); + +enum bfd_reloc_code_real { + _dummy_first_bfd_reloc_code_real, + + +/* Basic absolute relocations of N bits. */ + BFD_RELOC_64, + BFD_RELOC_32, + BFD_RELOC_26, + BFD_RELOC_24, + BFD_RELOC_16, + BFD_RELOC_14, + BFD_RELOC_8, + +/* PC-relative relocations. Sometimes these are relative to the address +of the relocation itself; sometimes they are relative to the start of +the section containing the relocation. It depends on the specific target. + +The 24-bit relocation is used in some Intel 960 configurations. */ + BFD_RELOC_64_PCREL, + BFD_RELOC_32_PCREL, + BFD_RELOC_24_PCREL, + BFD_RELOC_16_PCREL, + BFD_RELOC_12_PCREL, + BFD_RELOC_8_PCREL, + +/* For ELF. */ + BFD_RELOC_32_GOT_PCREL, + BFD_RELOC_16_GOT_PCREL, + BFD_RELOC_8_GOT_PCREL, + BFD_RELOC_32_GOTOFF, + BFD_RELOC_16_GOTOFF, + BFD_RELOC_LO16_GOTOFF, + BFD_RELOC_HI16_GOTOFF, + BFD_RELOC_HI16_S_GOTOFF, + BFD_RELOC_8_GOTOFF, + BFD_RELOC_32_PLT_PCREL, + BFD_RELOC_24_PLT_PCREL, + BFD_RELOC_16_PLT_PCREL, + BFD_RELOC_8_PLT_PCREL, + BFD_RELOC_32_PLTOFF, + BFD_RELOC_16_PLTOFF, + BFD_RELOC_LO16_PLTOFF, + BFD_RELOC_HI16_PLTOFF, + BFD_RELOC_HI16_S_PLTOFF, + BFD_RELOC_8_PLTOFF, + +/* Relocations used by 68K ELF. */ + BFD_RELOC_68K_GLOB_DAT, + BFD_RELOC_68K_JMP_SLOT, + BFD_RELOC_68K_RELATIVE, + +/* Linkage-table relative. */ + BFD_RELOC_32_BASEREL, + BFD_RELOC_16_BASEREL, + BFD_RELOC_LO16_BASEREL, + BFD_RELOC_HI16_BASEREL, + BFD_RELOC_HI16_S_BASEREL, + BFD_RELOC_8_BASEREL, + BFD_RELOC_RVA, + +/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ + BFD_RELOC_8_FFnn, + +/* These PC-relative relocations are stored as word displacements -- +i.e., byte displacements shifted right two bits. The 30-bit word +displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the +SPARC. (SPARC tools generally refer to this as <>.) The +signed 16-bit displacement is used on the MIPS, and the 23-bit +displacement is used on the Alpha. */ + BFD_RELOC_32_PCREL_S2, + BFD_RELOC_16_PCREL_S2, + BFD_RELOC_23_PCREL_S2, + +/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of +the target word. These are used on the SPARC. */ + BFD_RELOC_HI22, + BFD_RELOC_LO10, + +/* For systems that allocate a Global Pointer register, these are +displacements off that register. These relocation types are +handled specially, because the value the register will have is +decided relatively late. */ + BFD_RELOC_GPREL16, + BFD_RELOC_GPREL32, + +/* Reloc types used for i960/b.out. */ + BFD_RELOC_I960_CALLJ, + +/* SPARC ELF relocations. There is probably some overlap with other +relocation types already defined. */ + BFD_RELOC_NONE, + BFD_RELOC_SPARC_WDISP22, + BFD_RELOC_SPARC22, + BFD_RELOC_SPARC13, + BFD_RELOC_SPARC_GOT10, + BFD_RELOC_SPARC_GOT13, + BFD_RELOC_SPARC_GOT22, + BFD_RELOC_SPARC_PC10, + BFD_RELOC_SPARC_PC22, + BFD_RELOC_SPARC_WPLT30, + BFD_RELOC_SPARC_COPY, + BFD_RELOC_SPARC_GLOB_DAT, + BFD_RELOC_SPARC_JMP_SLOT, + BFD_RELOC_SPARC_RELATIVE, + BFD_RELOC_SPARC_UA32, + +/* I think these are specific to SPARC a.out (e.g., Sun 4). */ + BFD_RELOC_SPARC_BASE13, + BFD_RELOC_SPARC_BASE22, + +/* SPARC64 relocations */ +#define BFD_RELOC_SPARC_64 BFD_RELOC_64 + BFD_RELOC_SPARC_10, + BFD_RELOC_SPARC_11, + BFD_RELOC_SPARC_OLO10, + BFD_RELOC_SPARC_HH22, + BFD_RELOC_SPARC_HM10, + BFD_RELOC_SPARC_LM22, + BFD_RELOC_SPARC_PC_HH22, + BFD_RELOC_SPARC_PC_HM10, + BFD_RELOC_SPARC_PC_LM22, + BFD_RELOC_SPARC_WDISP16, + BFD_RELOC_SPARC_WDISP19, + BFD_RELOC_SPARC_7, + BFD_RELOC_SPARC_6, + BFD_RELOC_SPARC_5, +#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL + BFD_RELOC_SPARC_PLT64, + BFD_RELOC_SPARC_HIX22, + BFD_RELOC_SPARC_LOX10, + BFD_RELOC_SPARC_H44, + BFD_RELOC_SPARC_M44, + BFD_RELOC_SPARC_L44, + BFD_RELOC_SPARC_REGISTER, + +/* SPARC little endian relocation */ + BFD_RELOC_SPARC_REV32, + +/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or +"addend" in some special way. +For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when +writing; when reading, it will be the absolute section symbol. The +addend is the displacement in bytes of the "lda" instruction from +the "ldah" instruction (which is at the address of this reloc). */ + BFD_RELOC_ALPHA_GPDISP_HI16, + +/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as +with GPDISP_HI16 relocs. The addend is ignored when writing the +relocations out, and is filled in with the file's GP value on +reading, for convenience. */ + BFD_RELOC_ALPHA_GPDISP_LO16, + +/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 +relocation except that there is no accompanying GPDISP_LO16 +relocation. */ + BFD_RELOC_ALPHA_GPDISP, + +/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; +the assembler turns it into a LDQ instruction to load the address of +the symbol, and then fills in a register in the real instruction. + +The LITERAL reloc, at the LDQ instruction, refers to the .lita +section symbol. The addend is ignored when writing, but is filled +in with the file's GP value on reading, for convenience, as with the +GPDISP_LO16 reloc. + +The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. +It should refer to the symbol to be referenced, as with 16_GOTOFF, +but it generates output not based on the position within the .got +section, but relative to the GP value chosen for the file during the +final link stage. + +The LITUSE reloc, on the instruction using the loaded address, gives +information to the linker that it might be able to use to optimize +away some literal section references. The symbol is ignored (read +as the absolute section symbol), and the "addend" indicates the type +of instruction using the register: +1 - "memory" fmt insn +2 - byte-manipulation (byte offset reg) +3 - jsr (target of branch) + +The GNU linker currently doesn't do any of this optimizing. */ + BFD_RELOC_ALPHA_LITERAL, + BFD_RELOC_ALPHA_ELF_LITERAL, + BFD_RELOC_ALPHA_LITUSE, + +/* The BFD_RELOC_ALPHA_USER_* relocations are used by the assembler to +process the explicit !!sequence relocations, and are mapped +into the normal relocations at the end of processing. */ + BFD_RELOC_ALPHA_USER_LITERAL, + BFD_RELOC_ALPHA_USER_LITUSE_BASE, + BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF, + BFD_RELOC_ALPHA_USER_LITUSE_JSR, + BFD_RELOC_ALPHA_USER_GPDISP, + BFD_RELOC_ALPHA_USER_GPRELHIGH, + BFD_RELOC_ALPHA_USER_GPRELLOW, + +/* The HINT relocation indicates a value that should be filled into the +"hint" field of a jmp/jsr/ret instruction, for possible branch- +prediction logic which may be provided on some processors. */ + BFD_RELOC_ALPHA_HINT, + +/* The LINKAGE relocation outputs a linkage pair in the object file, +which is filled by the linker. */ + BFD_RELOC_ALPHA_LINKAGE, + +/* The CODEADDR relocation outputs a STO_CA in the object file, +which is filled by the linker. */ + BFD_RELOC_ALPHA_CODEADDR, + +/* Bits 27..2 of the relocation address shifted right 2 bits; +simple reloc otherwise. */ + BFD_RELOC_MIPS_JMP, + +/* The MIPS16 jump instruction. */ + BFD_RELOC_MIPS16_JMP, + +/* MIPS16 GP relative reloc. */ + BFD_RELOC_MIPS16_GPREL, + +/* High 16 bits of 32-bit value; simple reloc. */ + BFD_RELOC_HI16, + +/* High 16 bits of 32-bit value but the low 16 bits will be sign +extended and added to form the final result. If the low 16 +bits form a negative number, we need to add one to the high value +to compensate for the borrow when the low bits are added. */ + BFD_RELOC_HI16_S, + +/* Low 16 bits. */ + BFD_RELOC_LO16, + +/* Like BFD_RELOC_HI16_S, but PC relative. */ + BFD_RELOC_PCREL_HI16_S, + +/* Like BFD_RELOC_LO16, but PC relative. */ + BFD_RELOC_PCREL_LO16, + +/* Relocation relative to the global pointer. */ +#define BFD_RELOC_MIPS_GPREL BFD_RELOC_GPREL16 + +/* Relocation against a MIPS literal section. */ + BFD_RELOC_MIPS_LITERAL, + +/* MIPS ELF relocations. */ + BFD_RELOC_MIPS_GOT16, + BFD_RELOC_MIPS_CALL16, +#define BFD_RELOC_MIPS_GPREL32 BFD_RELOC_GPREL32 + BFD_RELOC_MIPS_GOT_HI16, + BFD_RELOC_MIPS_GOT_LO16, + BFD_RELOC_MIPS_CALL_HI16, + BFD_RELOC_MIPS_CALL_LO16, + BFD_RELOC_MIPS_SUB, + BFD_RELOC_MIPS_GOT_PAGE, + BFD_RELOC_MIPS_GOT_OFST, + BFD_RELOC_MIPS_GOT_DISP, + + +/* i386/elf relocations */ + BFD_RELOC_386_GOT32, + BFD_RELOC_386_PLT32, + BFD_RELOC_386_COPY, + BFD_RELOC_386_GLOB_DAT, + BFD_RELOC_386_JUMP_SLOT, + BFD_RELOC_386_RELATIVE, + BFD_RELOC_386_GOTOFF, + BFD_RELOC_386_GOTPC, + +/* ns32k relocations */ + BFD_RELOC_NS32K_IMM_8, + BFD_RELOC_NS32K_IMM_16, + BFD_RELOC_NS32K_IMM_32, + BFD_RELOC_NS32K_IMM_8_PCREL, + BFD_RELOC_NS32K_IMM_16_PCREL, + BFD_RELOC_NS32K_IMM_32_PCREL, + BFD_RELOC_NS32K_DISP_8, + BFD_RELOC_NS32K_DISP_16, + BFD_RELOC_NS32K_DISP_32, + BFD_RELOC_NS32K_DISP_8_PCREL, + BFD_RELOC_NS32K_DISP_16_PCREL, + BFD_RELOC_NS32K_DISP_32_PCREL, + +/* Picojava relocs. Not all of these appear in object files. */ + BFD_RELOC_PJ_CODE_HI16, + BFD_RELOC_PJ_CODE_LO16, + BFD_RELOC_PJ_CODE_DIR16, + BFD_RELOC_PJ_CODE_DIR32, + BFD_RELOC_PJ_CODE_REL16, + BFD_RELOC_PJ_CODE_REL32, + +/* Power(rs6000) and PowerPC relocations. */ + BFD_RELOC_PPC_B26, + BFD_RELOC_PPC_BA26, + BFD_RELOC_PPC_TOC16, + BFD_RELOC_PPC_B16, + BFD_RELOC_PPC_B16_BRTAKEN, + BFD_RELOC_PPC_B16_BRNTAKEN, + BFD_RELOC_PPC_BA16, + BFD_RELOC_PPC_BA16_BRTAKEN, + BFD_RELOC_PPC_BA16_BRNTAKEN, + BFD_RELOC_PPC_COPY, + BFD_RELOC_PPC_GLOB_DAT, + BFD_RELOC_PPC_JMP_SLOT, + BFD_RELOC_PPC_RELATIVE, + BFD_RELOC_PPC_LOCAL24PC, + BFD_RELOC_PPC_EMB_NADDR32, + BFD_RELOC_PPC_EMB_NADDR16, + BFD_RELOC_PPC_EMB_NADDR16_LO, + BFD_RELOC_PPC_EMB_NADDR16_HI, + BFD_RELOC_PPC_EMB_NADDR16_HA, + BFD_RELOC_PPC_EMB_SDAI16, + BFD_RELOC_PPC_EMB_SDA2I16, + BFD_RELOC_PPC_EMB_SDA2REL, + BFD_RELOC_PPC_EMB_SDA21, + BFD_RELOC_PPC_EMB_MRKREF, + BFD_RELOC_PPC_EMB_RELSEC16, + BFD_RELOC_PPC_EMB_RELST_LO, + BFD_RELOC_PPC_EMB_RELST_HI, + BFD_RELOC_PPC_EMB_RELST_HA, + BFD_RELOC_PPC_EMB_BIT_FLD, + BFD_RELOC_PPC_EMB_RELSDA, + +/* Instruction 370/390 relocations */ + BFD_RELOC_I370_D12, + +/* The type of reloc used to build a contructor table - at the moment +probably a 32 bit wide absolute relocation, but the target can choose. +It generally does map to one of the other relocation types. */ + BFD_RELOC_CTOR, + +/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. */ + BFD_RELOC_ARM_PCREL_BRANCH, + +/* These relocs are only used within the ARM assembler. They are not +(at present) written to any object files. */ + BFD_RELOC_ARM_IMMEDIATE, + BFD_RELOC_ARM_ADRL_IMMEDIATE, + BFD_RELOC_ARM_OFFSET_IMM, + BFD_RELOC_ARM_SHIFT_IMM, + BFD_RELOC_ARM_SWI, + BFD_RELOC_ARM_MULTI, + BFD_RELOC_ARM_CP_OFF_IMM, + BFD_RELOC_ARM_ADR_IMM, + BFD_RELOC_ARM_LDR_IMM, + BFD_RELOC_ARM_LITERAL, + BFD_RELOC_ARM_IN_POOL, + BFD_RELOC_ARM_OFFSET_IMM8, + BFD_RELOC_ARM_HWLITERAL, + BFD_RELOC_ARM_THUMB_ADD, + BFD_RELOC_ARM_THUMB_IMM, + BFD_RELOC_ARM_THUMB_SHIFT, + BFD_RELOC_ARM_THUMB_OFFSET, + BFD_RELOC_ARM_GOT12, + BFD_RELOC_ARM_GOT32, + BFD_RELOC_ARM_JUMP_SLOT, + BFD_RELOC_ARM_COPY, + BFD_RELOC_ARM_GLOB_DAT, + BFD_RELOC_ARM_PLT32, + BFD_RELOC_ARM_RELATIVE, + BFD_RELOC_ARM_GOTOFF, + BFD_RELOC_ARM_GOTPC, + +/* Hitachi SH relocs. Not all of these appear in object files. */ + BFD_RELOC_SH_PCDISP8BY2, + BFD_RELOC_SH_PCDISP12BY2, + BFD_RELOC_SH_IMM4, + BFD_RELOC_SH_IMM4BY2, + BFD_RELOC_SH_IMM4BY4, + BFD_RELOC_SH_IMM8, + BFD_RELOC_SH_IMM8BY2, + BFD_RELOC_SH_IMM8BY4, + BFD_RELOC_SH_PCRELIMM8BY2, + BFD_RELOC_SH_PCRELIMM8BY4, + BFD_RELOC_SH_SWITCH16, + BFD_RELOC_SH_SWITCH32, + BFD_RELOC_SH_USES, + BFD_RELOC_SH_COUNT, + BFD_RELOC_SH_ALIGN, + BFD_RELOC_SH_CODE, + BFD_RELOC_SH_DATA, + BFD_RELOC_SH_LABEL, + +/* Thumb 23-, 12- and 9-bit pc-relative branches. The lowest bit must +be zero and is not stored in the instruction. */ + BFD_RELOC_THUMB_PCREL_BRANCH9, + BFD_RELOC_THUMB_PCREL_BRANCH12, + BFD_RELOC_THUMB_PCREL_BRANCH23, + +/* Argonaut RISC Core (ARC) relocs. +ARC 22 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. The high 20 bits are installed in bits 26 +through 7 of the instruction. */ + BFD_RELOC_ARC_B22_PCREL, + +/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not +stored in the instruction. The high 24 bits are installed in bits 23 +through 0. */ + BFD_RELOC_ARC_B26, + +/* Mitsubishi D10V relocs. +This is a 10-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_10_PCREL_R, + +/* Mitsubishi D10V relocs. +This is a 10-bit reloc with the right 2 bits +assumed to be 0. This is the same as the previous reloc +except it is in the left container, i.e., +shifted left 15 bits. */ + BFD_RELOC_D10V_10_PCREL_L, + +/* This is an 18-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_18, + +/* This is an 18-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_18_PCREL, + +/* Mitsubishi D30V relocs. +This is a 6-bit absolute reloc. */ + BFD_RELOC_D30V_6, + +/* This is a 6-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_9_PCREL, + +/* This is a 6-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_9_PCREL_R, + +/* This is a 12-bit absolute reloc with the +right 3 bitsassumed to be 0. */ + BFD_RELOC_D30V_15, + +/* This is a 12-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_15_PCREL, + +/* This is a 12-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_15_PCREL_R, + +/* This is an 18-bit absolute reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_21, + +/* This is an 18-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_21_PCREL, + +/* This is an 18-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_21_PCREL_R, + +/* This is a 32-bit absolute reloc. */ + BFD_RELOC_D30V_32, + +/* This is a 32-bit pc-relative reloc. */ + BFD_RELOC_D30V_32_PCREL, + +/* Mitsubishi M32R relocs. +This is a 24 bit absolute address. */ + BFD_RELOC_M32R_24, + +/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_10_PCREL, + +/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_18_PCREL, + +/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_26_PCREL, + +/* This is a 16-bit reloc containing the high 16 bits of an address +used when the lower 16 bits are treated as unsigned. */ + BFD_RELOC_M32R_HI16_ULO, + +/* This is a 16-bit reloc containing the high 16 bits of an address +used when the lower 16 bits are treated as signed. */ + BFD_RELOC_M32R_HI16_SLO, + +/* This is a 16-bit reloc containing the lower 16 bits of an address. */ + BFD_RELOC_M32R_LO16, + +/* This is a 16-bit reloc containing the small data area offset for use in +add3, load, and store instructions. */ + BFD_RELOC_M32R_SDA16, + +/* This is a 9-bit reloc */ + BFD_RELOC_V850_9_PCREL, + +/* This is a 22-bit reloc */ + BFD_RELOC_V850_22_PCREL, + +/* This is a 16 bit offset from the short data area pointer. */ + BFD_RELOC_V850_SDA_16_16_OFFSET, + +/* This is a 16 bit offset (of which only 15 bits are used) from the +short data area pointer. */ + BFD_RELOC_V850_SDA_15_16_OFFSET, + +/* This is a 16 bit offset from the zero data area pointer. */ + BFD_RELOC_V850_ZDA_16_16_OFFSET, + +/* This is a 16 bit offset (of which only 15 bits are used) from the +zero data area pointer. */ + BFD_RELOC_V850_ZDA_15_16_OFFSET, + +/* This is an 8 bit offset (of which only 6 bits are used) from the +tiny data area pointer. */ + BFD_RELOC_V850_TDA_6_8_OFFSET, + +/* This is an 8bit offset (of which only 7 bits are used) from the tiny +data area pointer. */ + BFD_RELOC_V850_TDA_7_8_OFFSET, + +/* This is a 7 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_7_7_OFFSET, + +/* This is a 16 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_16_16_OFFSET, + +/* This is a 5 bit offset (of which only 4 bits are used) from the tiny +data area pointer. */ + BFD_RELOC_V850_TDA_4_5_OFFSET, + +/* This is a 4 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_4_4_OFFSET, + +/* This is a 16 bit offset from the short data area pointer, with the +bits placed non-contigously in the instruction. */ + BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, + +/* This is a 16 bit offset from the zero data area pointer, with the +bits placed non-contigously in the instruction. */ + BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, + +/* This is a 6 bit offset from the call table base pointer. */ + BFD_RELOC_V850_CALLT_6_7_OFFSET, + +/* This is a 16 bit offset from the call table base pointer. */ + BFD_RELOC_V850_CALLT_16_16_OFFSET, + + +/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_32_PCREL, + +/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_16_PCREL, + +/* This is a 8bit DP reloc for the tms320c30, where the most +significant 8 bits of a 24 bit word are placed into the least +significant 8 bits of the opcode. */ + BFD_RELOC_TIC30_LDP, + +/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ + BFD_RELOC_FR30_48, + +/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into +two sections. */ + BFD_RELOC_FR30_20, + +/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in +4 bits. */ + BFD_RELOC_FR30_6_IN_4, + +/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset +into 8 bits. */ + BFD_RELOC_FR30_8_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset +into 8 bits. */ + BFD_RELOC_FR30_9_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset +into 8 bits. */ + BFD_RELOC_FR30_10_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative +short offset into 8 bits. */ + BFD_RELOC_FR30_9_PCREL, + +/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative +short offset into 11 bits. */ + BFD_RELOC_FR30_12_PCREL, + +/* Motorola Mcore relocations. */ + BFD_RELOC_MCORE_PCREL_IMM8BY4, + BFD_RELOC_MCORE_PCREL_IMM11BY2, + BFD_RELOC_MCORE_PCREL_IMM4BY2, + BFD_RELOC_MCORE_PCREL_32, + BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, + BFD_RELOC_MCORE_RVA, + +/* These two relocations are used by the linker to determine which of +the entries in a C++ virtual function table are actually used. When +the --gc-sections option is given, the linker will zero out the entries +that are not used, so that the code for those functions need not be +included in the output. + +VTABLE_INHERIT is a zero-space relocation used to describe to the +linker the inheritence tree of a C++ virtual function table. The +relocation's symbol should be the parent class' vtable, and the +relocation should be located at the child vtable. + +VTABLE_ENTRY is a zero-space relocation that describes the use of a +virtual function table entry. The reloc's symbol should refer to the +table of the class mentioned in the code. Off of that base, an offset +describes the entry that is being used. For Rela hosts, this offset +is stored in the reloc's addend. For Rel hosts, we are forced to put +this offset in the reloc's section offset. */ + BFD_RELOC_VTABLE_INHERIT, + BFD_RELOC_VTABLE_ENTRY, + BFD_RELOC_UNUSED }; +typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +reloc_howto_type * + +bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + +const char * +bfd_get_reloc_code_name PARAMS ((bfd_reloc_code_real_type code)); + + +typedef struct symbol_cache_entry +{ + /* A pointer to the BFD which owns the symbol. This information + is necessary so that a back end can work out what additional + information (invisible to the application writer) is carried + with the symbol. + + This field is *almost* redundant, since you can use section->owner + instead, except that some symbols point to the global sections + bfd_{abs,com,und}_section. This could be fixed by making + these globals be per-bfd (or per-target-flavor). FIXME. */ + + struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ + + /* The text of the symbol. The name is left alone, and not copied; the + application may not alter it. */ + CONST char *name; + + /* The value of the symbol. This really should be a union of a + numeric value with a pointer, since some flags indicate that + a pointer to another symbol is stored here. */ + symvalue value; + + /* Attributes of a symbol: */ + +#define BSF_NO_FLAGS 0x00 + + /* The symbol has local scope; <> in <>. The value + is the offset into the section of the data. */ +#define BSF_LOCAL 0x01 + + /* The symbol has global scope; initialized data in <>. The + value is the offset into the section of the data. */ +#define BSF_GLOBAL 0x02 + + /* The symbol has global scope and is exported. The value is + the offset into the section of the data. */ +#define BSF_EXPORT BSF_GLOBAL /* no real difference */ + + /* A normal C symbol would be one of: + <>, <>, <> or + <> */ + + /* The symbol is a debugging record. The value has an arbitary + meaning, unless BSF_DEBUGGING_RELOC is also set. */ +#define BSF_DEBUGGING 0x08 + + /* The symbol denotes a function entry point. Used in ELF, + perhaps others someday. */ +#define BSF_FUNCTION 0x10 + + /* Used by the linker. */ +#define BSF_KEEP 0x20 +#define BSF_KEEP_G 0x40 + + /* A weak global symbol, overridable without warnings by + a regular global symbol of the same name. */ +#define BSF_WEAK 0x80 + + /* This symbol was created to point to a section, e.g. ELF's + STT_SECTION symbols. */ +#define BSF_SECTION_SYM 0x100 + + /* The symbol used to be a common symbol, but now it is + allocated. */ +#define BSF_OLD_COMMON 0x200 + + /* The default value for common data. */ +#define BFD_FORT_COMM_DEFAULT_VALUE 0 + + /* In some files the type of a symbol sometimes alters its + location in an output file - ie in coff a <> symbol + which is also <> symbol appears where it was + declared and not at the end of a section. This bit is set + by the target BFD part to convey this information. */ + +#define BSF_NOT_AT_END 0x400 + + /* Signal that the symbol is the label of constructor section. */ +#define BSF_CONSTRUCTOR 0x800 + + /* Signal that the symbol is a warning symbol. The name is a + warning. The name of the next symbol is the one to warn about; + if a reference is made to a symbol with the same name as the next + symbol, a warning is issued by the linker. */ +#define BSF_WARNING 0x1000 + + /* Signal that the symbol is indirect. This symbol is an indirect + pointer to the symbol with the same name as the next symbol. */ +#define BSF_INDIRECT 0x2000 + + /* BSF_FILE marks symbols that contain a file name. This is used + for ELF STT_FILE symbols. */ +#define BSF_FILE 0x4000 + + /* Symbol is from dynamic linking information. */ +#define BSF_DYNAMIC 0x8000 + + /* The symbol denotes a data object. Used in ELF, and perhaps + others someday. */ +#define BSF_OBJECT 0x10000 + + /* This symbol is a debugging symbol. The value is the offset + into the section of the data. BSF_DEBUGGING should be set + as well. */ +#define BSF_DEBUGGING_RELOC 0x20000 + + flagword flags; + + /* A pointer to the section to which this symbol is + relative. This will always be non NULL, there are special + sections for undefined and absolute symbols. */ + struct sec *section; + + /* Back end special data. */ + union + { + PTR p; + bfd_vma i; + } udata; + +} asymbol; +#define bfd_get_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) +boolean +bfd_is_local_label PARAMS ((bfd *abfd, asymbol *sym)); + +boolean +bfd_is_local_label_name PARAMS ((bfd *abfd, const char *name)); + +#define bfd_is_local_label_name(abfd, name) \ + BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab,\ + (abfd, location)) +boolean +bfd_set_symtab PARAMS ((bfd *abfd, asymbol **location, unsigned int count)); + +void +bfd_print_symbol_vandf PARAMS ((PTR file, asymbol *symbol)); + +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +int +bfd_decode_symclass PARAMS ((asymbol *symbol)); + +void +bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret)); + +boolean +bfd_copy_private_symbol_data PARAMS ((bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym)); + +#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ + BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ + (ibfd, isymbol, obfd, osymbol)) +struct _bfd +{ + /* The filename the application opened the BFD with. */ + CONST char *filename; + + /* A pointer to the target jump table. */ + const struct bfd_target *xvec; + + /* To avoid dragging too many header files into every file that + includes `<>', IOSTREAM has been declared as a "char + *", and MTIME as a "long". Their correct types, to which they + are cast when used, are "FILE *" and "time_t". The iostream + is the result of an fopen on the filename. However, if the + BFD_IN_MEMORY flag is set, then iostream is actually a pointer + to a bfd_in_memory struct. */ + PTR iostream; + + /* Is the file descriptor being cached? That is, can it be closed as + needed, and re-opened when accessed later? */ + + boolean cacheable; + + /* Marks whether there was a default target specified when the + BFD was opened. This is used to select which matching algorithm + to use to choose the back end. */ + + boolean target_defaulted; + + /* The caching routines use these to maintain a + least-recently-used list of BFDs */ + + struct _bfd *lru_prev, *lru_next; + + /* When a file is closed by the caching routines, BFD retains + state information on the file here: */ + + file_ptr where; + + /* and here: (``once'' means at least once) */ + + boolean opened_once; + + /* Set if we have a locally maintained mtime value, rather than + getting it from the file each time: */ + + boolean mtime_set; + + /* File modified time, if mtime_set is true: */ + + long mtime; + + /* Reserved for an unimplemented file locking extension.*/ + + int ifd; + + /* The format which belongs to the BFD. (object, core, etc.) */ + + bfd_format format; + + /* The direction the BFD was opened with*/ + + enum bfd_direction {no_direction = 0, + read_direction = 1, + write_direction = 2, + both_direction = 3} direction; + + /* Format_specific flags*/ + + flagword flags; + + /* Currently my_archive is tested before adding origin to + anything. I believe that this can become always an add of + origin, with origin set to 0 for non archive files. */ + + file_ptr origin; + + /* Remember when output has begun, to stop strange things + from happening. */ + boolean output_has_begun; + + /* Pointer to linked list of sections*/ + struct sec *sections; + + /* The number of sections */ + unsigned int section_count; + + /* Stuff only useful for object files: + The start address. */ + bfd_vma start_address; + + /* Used for input and output*/ + unsigned int symcount; + + /* Symbol table for output BFD (with symcount entries) */ + struct symbol_cache_entry **outsymbols; + + /* Pointer to structure which contains architecture information*/ + const struct bfd_arch_info *arch_info; + + /* Stuff only useful for archives:*/ + PTR arelt_data; + struct _bfd *my_archive; /* The containing archive BFD. */ + struct _bfd *next; /* The next BFD in the archive. */ + struct _bfd *archive_head; /* The first BFD in the archive. */ + boolean has_armap; + + /* A chain of BFD structures involved in a link. */ + struct _bfd *link_next; + + /* A field used by _bfd_generic_link_add_archive_symbols. This will + be used only for archive elements. */ + int archive_pass; + + /* Used by the back end to hold private data. */ + + union + { + struct aout_data_struct *aout_data; + struct artdata *aout_ar_data; + struct _oasys_data *oasys_obj_data; + struct _oasys_ar_data *oasys_ar_data; + struct coff_tdata *coff_obj_data; + struct pe_tdata *pe_obj_data; + struct xcoff_tdata *xcoff_obj_data; + struct ecoff_tdata *ecoff_obj_data; + struct ieee_data_struct *ieee_data; + struct ieee_ar_data_struct *ieee_ar_data; + struct srec_data_struct *srec_data; + struct ihex_data_struct *ihex_data; + struct tekhex_data_struct *tekhex_data; + struct elf_obj_tdata *elf_obj_data; + struct nlm_obj_tdata *nlm_obj_data; + struct bout_data_struct *bout_data; + struct sun_core_struct *sun_core_data; + struct sco5_core_struct *sco5_core_data; + struct trad_core_struct *trad_core_data; + struct som_data_struct *som_data; + struct hpux_core_struct *hpux_core_data; + struct hppabsd_core_struct *hppabsd_core_data; + struct sgi_core_struct *sgi_core_data; + struct lynx_core_struct *lynx_core_data; + struct osf_core_struct *osf_core_data; + struct cisco_core_struct *cisco_core_data; + struct versados_data_struct *versados_data; + struct netbsd_core_struct *netbsd_core_data; + PTR any; + } tdata; + + /* Used by the application to hold private data*/ + PTR usrdata; + + /* Where all the allocated stuff under this BFD goes. This is a + struct objalloc *, but we use PTR to avoid requiring the inclusion of + objalloc.h. */ + PTR memory; +}; + +typedef enum bfd_error +{ + bfd_error_no_error = 0, + bfd_error_system_call, + bfd_error_invalid_target, + bfd_error_wrong_format, + bfd_error_invalid_operation, + bfd_error_no_memory, + bfd_error_no_symbols, + bfd_error_no_armap, + bfd_error_no_more_archived_files, + bfd_error_malformed_archive, + bfd_error_file_not_recognized, + bfd_error_file_ambiguously_recognized, + bfd_error_no_contents, + bfd_error_nonrepresentable_section, + bfd_error_no_debug_section, + bfd_error_bad_value, + bfd_error_file_truncated, + bfd_error_file_too_big, + bfd_error_invalid_error_code +} bfd_error_type; + +bfd_error_type +bfd_get_error PARAMS ((void)); + +void +bfd_set_error PARAMS ((bfd_error_type error_tag)); + +CONST char * +bfd_errmsg PARAMS ((bfd_error_type error_tag)); + +void +bfd_perror PARAMS ((CONST char *message)); + +typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...)); + +bfd_error_handler_type +bfd_set_error_handler PARAMS ((bfd_error_handler_type)); + +void +bfd_set_error_program_name PARAMS ((const char *)); + +bfd_error_handler_type +bfd_get_error_handler PARAMS ((void)); + +long +bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); + +long +bfd_canonicalize_reloc + PARAMS ((bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms)); + +void +bfd_set_reloc + PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count) + + ); + +boolean +bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags)); + +boolean +bfd_set_start_address PARAMS ((bfd *abfd, bfd_vma vma)); + +long +bfd_get_mtime PARAMS ((bfd *abfd)); + +long +bfd_get_size PARAMS ((bfd *abfd)); + +int +bfd_get_gp_size PARAMS ((bfd *abfd)); + +void +bfd_set_gp_size PARAMS ((bfd *abfd, int i)); + +bfd_vma +bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base)); + +boolean +bfd_copy_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_copy_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ + (ibfd, obfd)) +boolean +bfd_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_merge_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ + (ibfd, obfd)) +boolean +bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags)); + +#define bfd_set_private_flags(abfd, flags) \ + BFD_SEND (abfd, _bfd_set_private_flags, \ + (abfd, flags)) +#define bfd_sizeof_headers(abfd, reloc) \ + BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) + +#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ + BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) + + /* Do these three do anything useful at all, for any back end? */ +#define bfd_debug_info_start(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) + +#define bfd_debug_info_end(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) + +#define bfd_debug_info_accumulate(abfd, section) \ + BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) + + +#define bfd_stat_arch_elt(abfd, stat) \ + BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) + +#define bfd_update_armap_timestamp(abfd) \ + BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) + +#define bfd_set_arch_mach(abfd, arch, mach)\ + BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) + +#define bfd_relax_section(abfd, section, link_info, again) \ + BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) + +#define bfd_gc_sections(abfd, link_info) \ + BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) + +#define bfd_link_hash_table_create(abfd) \ + BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) + +#define bfd_link_add_symbols(abfd, info) \ + BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) + +#define bfd_final_link(abfd, info) \ + BFD_SEND (abfd, _bfd_final_link, (abfd, info)) + +#define bfd_free_cached_info(abfd) \ + BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) + +#define bfd_get_dynamic_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) + +#define bfd_print_private_bfd_data(abfd, file)\ + BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) + +#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) + +#define bfd_get_dynamic_reloc_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) + +#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) + +extern bfd_byte *bfd_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, + struct bfd_link_order *, bfd_byte *, + boolean, asymbol **)); + +symindex +bfd_get_next_mapent PARAMS ((bfd *abfd, symindex previous, carsym **sym)); + +boolean +bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head)); + +bfd * +bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous)); + +CONST char * +bfd_core_file_failing_command PARAMS ((bfd *abfd)); + +int +bfd_core_file_failing_signal PARAMS ((bfd *abfd)); + +boolean +core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +#define BFD_SEND(bfd, message, arglist) \ + ((*((bfd)->xvec->message)) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND +#define BFD_SEND(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + ((*((bfd)->xvec->message)) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND_FMT +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif +enum bfd_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_ihex_flavour, + bfd_target_som_flavour, + bfd_target_os9k_flavour, + bfd_target_versados_flavour, + bfd_target_msdos_flavour, + bfd_target_ovax_flavour, + bfd_target_evax_flavour +}; + +enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; + + /* Forward declaration. */ +typedef struct bfd_link_info _bfd_link_info; + +typedef struct bfd_target +{ + char *name; + enum bfd_flavour flavour; + enum bfd_endian byteorder; + enum bfd_endian header_byteorder; + flagword object_flags; + flagword section_flags; + char symbol_leading_char; + char ar_pad_char; + unsigned short ar_max_namelen; + bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + + /* Generic entry points. */ +#define BFD_JUMP_TABLE_GENERIC(NAME)\ +CAT(NAME,_close_and_cleanup),\ +CAT(NAME,_bfd_free_cached_info),\ +CAT(NAME,_new_section_hook),\ +CAT(NAME,_get_section_contents),\ +CAT(NAME,_get_section_contents_in_window) + + /* Called when the BFD is being closed to do any necessary cleanup. */ + boolean (*_close_and_cleanup) PARAMS ((bfd *)); + /* Ask the BFD to free all cached information. */ + boolean (*_bfd_free_cached_info) PARAMS ((bfd *)); + /* Called when a new section is created. */ + boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + /* Read the contents of a section. */ + boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + boolean (*_bfd_get_section_contents_in_window) + PARAMS ((bfd *, sec_ptr, bfd_window *, + file_ptr, bfd_size_type)); + + /* Entry points to copy private data. */ +#define BFD_JUMP_TABLE_COPY(NAME)\ +CAT(NAME,_bfd_copy_private_bfd_data),\ +CAT(NAME,_bfd_merge_private_bfd_data),\ +CAT(NAME,_bfd_copy_private_section_data),\ +CAT(NAME,_bfd_copy_private_symbol_data),\ +CAT(NAME,_bfd_set_private_flags),\ +CAT(NAME,_bfd_print_private_bfd_data)\ + /* Called to copy BFD general private data from one object file + to another. */ + boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to merge BFD general private data from one object file + to a common output file when linking. */ + boolean (*_bfd_merge_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to copy BFD private section data from one object file + to another. */ + boolean (*_bfd_copy_private_section_data) PARAMS ((bfd *, sec_ptr, + bfd *, sec_ptr)); + /* Called to copy BFD private symbol data from one symbol + to another. */ + boolean (*_bfd_copy_private_symbol_data) PARAMS ((bfd *, asymbol *, + bfd *, asymbol *)); + /* Called to set private backend flags */ + boolean (*_bfd_set_private_flags) PARAMS ((bfd *, flagword)); + + /* Called to print private BFD data */ + boolean (*_bfd_print_private_bfd_data) PARAMS ((bfd *, PTR)); + + /* Core file entry points. */ +#define BFD_JUMP_TABLE_CORE(NAME)\ +CAT(NAME,_core_file_failing_command),\ +CAT(NAME,_core_file_failing_signal),\ +CAT(NAME,_core_file_matches_executable_p) + char * (*_core_file_failing_command) PARAMS ((bfd *)); + int (*_core_file_failing_signal) PARAMS ((bfd *)); + boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + + /* Archive entry points. */ +#define BFD_JUMP_TABLE_ARCHIVE(NAME)\ +CAT(NAME,_slurp_armap),\ +CAT(NAME,_slurp_extended_name_table),\ +CAT(NAME,_construct_extended_name_table),\ +CAT(NAME,_truncate_arname),\ +CAT(NAME,_write_armap),\ +CAT(NAME,_read_ar_hdr),\ +CAT(NAME,_openr_next_archived_file),\ +CAT(NAME,_get_elt_at_index),\ +CAT(NAME,_generic_stat_arch_elt),\ +CAT(NAME,_update_armap_timestamp) + boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); + boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); + boolean (*_bfd_construct_extended_name_table) + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); + void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); + boolean (*write_armap) PARAMS ((bfd *arch, + unsigned int elength, + struct orl *map, + unsigned int orl_count, + int stridx)); + PTR (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *)); + bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); +#define bfd_get_elt_at_index(b,i) BFD_SEND(b, _bfd_get_elt_at_index, (b,i)) + bfd * (*_bfd_get_elt_at_index) PARAMS ((bfd *, symindex)); + int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); + boolean (*_bfd_update_armap_timestamp) PARAMS ((bfd *)); + + /* Entry points used for symbols. */ +#define BFD_JUMP_TABLE_SYMBOLS(NAME)\ +CAT(NAME,_get_symtab_upper_bound),\ +CAT(NAME,_get_symtab),\ +CAT(NAME,_make_empty_symbol),\ +CAT(NAME,_print_symbol),\ +CAT(NAME,_get_symbol_info),\ +CAT(NAME,_bfd_is_local_label_name),\ +CAT(NAME,_get_lineno),\ +CAT(NAME,_find_nearest_line),\ +CAT(NAME,_bfd_make_debug_symbol),\ +CAT(NAME,_read_minisymbols),\ +CAT(NAME,_minisymbol_to_symbol) + long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *)); + long (*_bfd_canonicalize_symtab) PARAMS ((bfd *, + struct symbol_cache_entry **)); + struct symbol_cache_entry * + (*_bfd_make_empty_symbol) PARAMS ((bfd *)); + void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, + struct symbol_cache_entry *, + bfd_print_symbol_type)); +#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) + void (*_bfd_get_symbol_info) PARAMS ((bfd *, + struct symbol_cache_entry *, + symbol_info *)); +#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + boolean (*_bfd_is_local_label_name) PARAMS ((bfd *, const char *)); + + alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); + boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, + struct sec *section, struct symbol_cache_entry **symbols, + bfd_vma offset, CONST char **file, CONST char **func, + unsigned int *line)); + /* Back-door to allow format-aware applications to create debug symbols + while using BFD for everything else. Currently used by the assembler + when creating COFF files. */ + asymbol * (*_bfd_make_debug_symbol) PARAMS (( + bfd *abfd, + void *ptr, + unsigned long size)); +#define bfd_read_minisymbols(b, d, m, s) \ + BFD_SEND (b, _read_minisymbols, (b, d, m, s)) + long (*_read_minisymbols) PARAMS ((bfd *, boolean, PTR *, + unsigned int *)); +#define bfd_minisymbol_to_symbol(b, d, m, f) \ + BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) + asymbol *(*_minisymbol_to_symbol) PARAMS ((bfd *, boolean, const PTR, + asymbol *)); + + /* Routines for relocs. */ +#define BFD_JUMP_TABLE_RELOCS(NAME)\ +CAT(NAME,_get_reloc_upper_bound),\ +CAT(NAME,_canonicalize_reloc),\ +CAT(NAME,_bfd_reloc_type_lookup) + long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); + long (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, + struct symbol_cache_entry **)); + /* See documentation on reloc types. */ + reloc_howto_type * + (*reloc_type_lookup) PARAMS ((bfd *abfd, + bfd_reloc_code_real_type code)); + + /* Routines used when writing an object file. */ +#define BFD_JUMP_TABLE_WRITE(NAME)\ +CAT(NAME,_set_arch_mach),\ +CAT(NAME,_set_section_contents) + boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); + boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + + /* Routines used by the linker. */ +#define BFD_JUMP_TABLE_LINK(NAME)\ +CAT(NAME,_sizeof_headers),\ +CAT(NAME,_bfd_get_relocated_section_contents),\ +CAT(NAME,_bfd_relax_section),\ +CAT(NAME,_bfd_link_hash_table_create),\ +CAT(NAME,_bfd_link_add_symbols),\ +CAT(NAME,_bfd_final_link),\ +CAT(NAME,_bfd_link_split_section),\ +CAT(NAME,_bfd_gc_sections) + int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); + bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, + struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *data, boolean relocateable, + struct symbol_cache_entry **)); + + boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, + struct bfd_link_info *, boolean *again)); + + /* Create a hash table for the linker. Different backends store + different information in this table. */ + struct bfd_link_hash_table *(*_bfd_link_hash_table_create) PARAMS ((bfd *)); + + /* Add symbols from this object file into the hash table. */ + boolean (*_bfd_link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Do a link based on the link_order structures attached to each + section of the BFD. */ + boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Should this section be split up into smaller pieces during linking. */ + boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *)); + + /* Remove sections that are not referenced from the output. */ + boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Routines to handle dynamic symbols and relocs. */ +#define BFD_JUMP_TABLE_DYNAMIC(NAME)\ +CAT(NAME,_get_dynamic_symtab_upper_bound),\ +CAT(NAME,_canonicalize_dynamic_symtab),\ +CAT(NAME,_get_dynamic_reloc_upper_bound),\ +CAT(NAME,_canonicalize_dynamic_reloc) + /* Get the amount of memory required to hold the dynamic symbols. */ + long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic symbols. */ + long (*_bfd_canonicalize_dynamic_symtab) + PARAMS ((bfd *, struct symbol_cache_entry **)); + /* Get the amount of memory required to hold the dynamic relocs. */ + long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic relocs. */ + long (*_bfd_canonicalize_dynamic_reloc) + PARAMS ((bfd *, arelent **, struct symbol_cache_entry **)); + + /* Opposite endian version of this target. */ + const struct bfd_target * alternative_target; + + PTR backend_data; + +} bfd_target; +boolean +bfd_set_default_target PARAMS ((const char *name)); + +const bfd_target * +bfd_find_target PARAMS ((CONST char *target_name, bfd *abfd)); + +const char ** +bfd_target_list PARAMS ((void)); + +const bfd_target * +bfd_search_for_target PARAMS ((int (* search_func)(const bfd_target *, void *), void *)); + +boolean +bfd_check_format PARAMS ((bfd *abfd, bfd_format format)); + +boolean +bfd_check_format_matches PARAMS ((bfd *abfd, bfd_format format, char ***matching)); + +boolean +bfd_set_format PARAMS ((bfd *abfd, bfd_format format)); + +CONST char * +bfd_format_string PARAMS ((bfd_format format)); + +#ifdef __cplusplus +} +#endif +#endif diff -Nur linux-2.4.19/arch/i386/kdb/i386-dis.c linux-2.4.19-sgi211r3/arch/i386/kdb/i386-dis.c --- linux-2.4.19/arch/i386/kdb/i386-dis.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/i386-dis.c Wed Jan 30 15:32:11 2002 @@ -0,0 +1,3781 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 97, 98, 1999 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * modified by John Hassey (hassey@dg-rtp.dg.com) + */ + +/* Extracted from cygnus CVS and modified for kdb use. + * Keith Owens 30 Oct 2000 + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#ifdef __KERNEL__ +#include +#include +#include +#include +#else +#include "dis-asm.h" +#include "sysdep.h" +#include "opintl.h" +#endif + +#define MAXLEN 20 + +#ifndef __KERNEL__ +#include +#endif + +#ifndef UNIXWARE_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes. */ +#define UNIXWARE_COMPAT 1 +#endif + +static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); + +struct dis_private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; +#ifndef __KERNEL__ + jmp_buf bailout; +#endif +}; + +/* The opcode for the fwait instruction, which we treat as a prefix + when we can. */ +#define FWAIT_OPCODE (0x9b) + +/* Flags for the prefixes for the current instruction. See below. */ +static int prefixes; + +/* Flags for prefixes which we somehow handled when printing the + current instruction. */ +static int used_prefixes; + +/* Flags stored in PREFIXES. */ +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADDR 0x400 +#define PREFIX_FWAIT 0x800 + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (info, addr) + struct disassemble_info *info; + bfd_byte *addr; +{ + int status; + struct dis_private *priv = (struct dis_private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + /* If we did manage to read at least one byte, then + print_insn_i386 will do something sensible. Otherwise, print + an error. We do that here because this is where we know + STATUS. */ + if (priv->max_fetched == priv->the_buffer) + (*info->memory_error_func) (status, start, info); +#ifndef __KERNEL__ + longjmp (priv->bailout, 1); +#else + /* XXX - what to do? */ + kdb_printf("Hmm. longjmp.\n"); +#endif + } + else + priv->max_fetched = addr; + return 1; +} + +#define XX NULL, 0 + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define Ed OP_E, d_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 /* lea */ +#define Mp OP_E, 0 /* 32 or 48 bit memory operand for LDS, LES etc */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rd OP_Rd, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, 0 +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSreg, eSI_reg +#define Xv OP_DSreg, eSI_reg +#define Yb OP_ESreg, eDI_reg +#define Yv OP_ESreg, eDI_reg +#define DSBX OP_DSreg, eBX_reg + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +#define MX OP_MMX, 0 +#define XM OP_XMM, 0 +#define EM OP_EM, v_mode +#define EX OP_EX, v_mode +#define MS OP_MS, v_mode +#define None OP_E, 0 +#define OPSUF OP_3DNowSuffix, 0 +#define OPSIMD OP_SIMD_Suffix, 0 + +/* bits in sizeflag */ +#if 0 /* leave undefined until someone adds the extra flag to objdump */ +#define SUFFIX_ALWAYS 4 +#endif +#define AFLAG 2 +#define DFLAG 1 + +typedef void (*op_rtn) PARAMS ((int bytemode, int sizeflag)); + +static void OP_E PARAMS ((int, int)); +static void OP_G PARAMS ((int, int)); +static void OP_I PARAMS ((int, int)); +static void OP_indirE PARAMS ((int, int)); +static void OP_sI PARAMS ((int, int)); +static void OP_REG PARAMS ((int, int)); +static void OP_J PARAMS ((int, int)); +static void OP_DIR PARAMS ((int, int)); +static void OP_OFF PARAMS ((int, int)); +static void OP_ESreg PARAMS ((int, int)); +static void OP_DSreg PARAMS ((int, int)); +static void OP_SEG PARAMS ((int, int)); +static void OP_C PARAMS ((int, int)); +static void OP_D PARAMS ((int, int)); +static void OP_T PARAMS ((int, int)); +static void OP_Rd PARAMS ((int, int)); +static void OP_ST PARAMS ((int, int)); +static void OP_STi PARAMS ((int, int)); +static void OP_MMX PARAMS ((int, int)); +static void OP_XMM PARAMS ((int, int)); +static void OP_EM PARAMS ((int, int)); +static void OP_EX PARAMS ((int, int)); +static void OP_MS PARAMS ((int, int)); +static void OP_3DNowSuffix PARAMS ((int, int)); +static void OP_SIMD_Suffix PARAMS ((int, int)); +static void SIMD_Fixup PARAMS ((int, int)); + +static void append_seg PARAMS ((void)); +static void set_op PARAMS ((unsigned int op)); +static void putop PARAMS ((const char *template, int sizeflag)); +static void dofloat PARAMS ((int sizeflag)); +static int get16 PARAMS ((void)); +static int get32 PARAMS ((void)); +static void ckprefix PARAMS ((void)); +static const char *prefix_name PARAMS ((int, int)); +static void ptr_reg PARAMS ((int, int)); +static void BadOp PARAMS ((void)); + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 +#define x_mode 5 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 + +#define eAX_reg 108 +#define eCX_reg 109 +#define eDX_reg 110 +#define eBX_reg 111 +#define eSP_reg 112 +#define eBP_reg 113 +#define eSI_reg 114 +#define eDI_reg 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define USE_GROUPS 1 +#define USE_PREFIX_USER_TABLE 2 + +#define GRP1b NULL, NULL, 0, NULL, USE_GROUPS, NULL, 0 +#define GRP1S NULL, NULL, 1, NULL, USE_GROUPS, NULL, 0 +#define GRP1Ss NULL, NULL, 2, NULL, USE_GROUPS, NULL, 0 +#define GRP2b NULL, NULL, 3, NULL, USE_GROUPS, NULL, 0 +#define GRP2S NULL, NULL, 4, NULL, USE_GROUPS, NULL, 0 +#define GRP2b_one NULL, NULL, 5, NULL, USE_GROUPS, NULL, 0 +#define GRP2S_one NULL, NULL, 6, NULL, USE_GROUPS, NULL, 0 +#define GRP2b_cl NULL, NULL, 7, NULL, USE_GROUPS, NULL, 0 +#define GRP2S_cl NULL, NULL, 8, NULL, USE_GROUPS, NULL, 0 +#define GRP3b NULL, NULL, 9, NULL, USE_GROUPS, NULL, 0 +#define GRP3S NULL, NULL, 10, NULL, USE_GROUPS, NULL, 0 +#define GRP4 NULL, NULL, 11, NULL, USE_GROUPS, NULL, 0 +#define GRP5 NULL, NULL, 12, NULL, USE_GROUPS, NULL, 0 +#define GRP6 NULL, NULL, 13, NULL, USE_GROUPS, NULL, 0 +#define GRP7 NULL, NULL, 14, NULL, USE_GROUPS, NULL, 0 +#define GRP8 NULL, NULL, 15, NULL, USE_GROUPS, NULL, 0 +#define GRP9 NULL, NULL, 16, NULL, USE_GROUPS, NULL, 0 +#define GRP10 NULL, NULL, 17, NULL, USE_GROUPS, NULL, 0 +#define GRP11 NULL, NULL, 18, NULL, USE_GROUPS, NULL, 0 +#define GRP12 NULL, NULL, 19, NULL, USE_GROUPS, NULL, 0 +#define GRP13 NULL, NULL, 20, NULL, USE_GROUPS, NULL, 0 +#define GRP14 NULL, NULL, 21, NULL, USE_GROUPS, NULL, 0 +#define GRPAMD NULL, NULL, 22, NULL, USE_GROUPS, NULL, 0 + +#define PREGRP0 NULL, NULL, 0, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP1 NULL, NULL, 1, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP2 NULL, NULL, 2, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP3 NULL, NULL, 3, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP4 NULL, NULL, 4, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP5 NULL, NULL, 5, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP6 NULL, NULL, 6, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP7 NULL, NULL, 7, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP8 NULL, NULL, 8, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP9 NULL, NULL, 9, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP10 NULL, NULL, 10, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP11 NULL, NULL, 11, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP12 NULL, NULL, 12, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP13 NULL, NULL, 13, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP14 NULL, NULL, 14, NULL, USE_PREFIX_USER_TABLE, NULL, 0 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 + +struct dis386 { + const char *name; + op_rtn op1; + int bytemode1; + op_rtn op2; + int bytemode2; + op_rtn op3; + int bytemode3; +}; + +/* Upper case letters in the instruction names here are macros. + 'A' => print 'b' if no register operands or suffix_always is true + 'B' => print 'b' if suffix_always is true + 'E' => print 'e' if 32-bit form of jcxz + 'L' => print 'l' if suffix_always is true + 'N' => print 'n' if instruction has no wait "prefix" + 'P' => print 'w' or 'l' if instruction has an operand size prefix, + or suffix_always is true + 'Q' => print 'w' or 'l' if no register operands or suffix_always is true + 'R' => print 'w' or 'l' ("wd" or "dq" in intel mode) + 'S' => print 'w' or 'l' if suffix_always is true + 'W' => print 'b' or 'w' ("w" or "de" in intel mode) +*/ + +static const struct dis386 dis386_att[] = { + /* 00 */ + { "addB", Eb, Gb, XX }, + { "addS", Ev, Gv, XX }, + { "addB", Gb, Eb, XX }, + { "addS", Gv, Ev, XX }, + { "addB", AL, Ib, XX }, + { "addS", eAX, Iv, XX }, + { "pushP", es, XX, XX }, + { "popP", es, XX, XX }, + /* 08 */ + { "orB", Eb, Gb, XX }, + { "orS", Ev, Gv, XX }, + { "orB", Gb, Eb, XX }, + { "orS", Gv, Ev, XX }, + { "orB", AL, Ib, XX }, + { "orS", eAX, Iv, XX }, + { "pushP", cs, XX, XX }, + { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcB", Eb, Gb, XX }, + { "adcS", Ev, Gv, XX }, + { "adcB", Gb, Eb, XX }, + { "adcS", Gv, Ev, XX }, + { "adcB", AL, Ib, XX }, + { "adcS", eAX, Iv, XX }, + { "pushP", ss, XX, XX }, + { "popP", ss, XX, XX }, + /* 18 */ + { "sbbB", Eb, Gb, XX }, + { "sbbS", Ev, Gv, XX }, + { "sbbB", Gb, Eb, XX }, + { "sbbS", Gv, Ev, XX }, + { "sbbB", AL, Ib, XX }, + { "sbbS", eAX, Iv, XX }, + { "pushP", ds, XX, XX }, + { "popP", ds, XX, XX }, + /* 20 */ + { "andB", Eb, Gb, XX }, + { "andS", Ev, Gv, XX }, + { "andB", Gb, Eb, XX }, + { "andS", Gv, Ev, XX }, + { "andB", AL, Ib, XX }, + { "andS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG ES prefix */ + { "daa", XX, XX, XX }, + /* 28 */ + { "subB", Eb, Gb, XX }, + { "subS", Ev, Gv, XX }, + { "subB", Gb, Eb, XX }, + { "subS", Gv, Ev, XX }, + { "subB", AL, Ib, XX }, + { "subS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG CS prefix */ + { "das", XX, XX, XX }, + /* 30 */ + { "xorB", Eb, Gb, XX }, + { "xorS", Ev, Gv, XX }, + { "xorB", Gb, Eb, XX }, + { "xorS", Gv, Ev, XX }, + { "xorB", AL, Ib, XX }, + { "xorS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG SS prefix */ + { "aaa", XX, XX, XX }, + /* 38 */ + { "cmpB", Eb, Gb, XX }, + { "cmpS", Ev, Gv, XX }, + { "cmpB", Gb, Eb, XX }, + { "cmpS", Gv, Ev, XX }, + { "cmpB", AL, Ib, XX }, + { "cmpS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG DS prefix */ + { "aas", XX, XX, XX }, + /* 40 */ + { "incS", eAX, XX, XX }, + { "incS", eCX, XX, XX }, + { "incS", eDX, XX, XX }, + { "incS", eBX, XX, XX }, + { "incS", eSP, XX, XX }, + { "incS", eBP, XX, XX }, + { "incS", eSI, XX, XX }, + { "incS", eDI, XX, XX }, + /* 48 */ + { "decS", eAX, XX, XX }, + { "decS", eCX, XX, XX }, + { "decS", eDX, XX, XX }, + { "decS", eBX, XX, XX }, + { "decS", eSP, XX, XX }, + { "decS", eBP, XX, XX }, + { "decS", eSI, XX, XX }, + { "decS", eDI, XX, XX }, + /* 50 */ + { "pushS", eAX, XX, XX }, + { "pushS", eCX, XX, XX }, + { "pushS", eDX, XX, XX }, + { "pushS", eBX, XX, XX }, + { "pushS", eSP, XX, XX }, + { "pushS", eBP, XX, XX }, + { "pushS", eSI, XX, XX }, + { "pushS", eDI, XX, XX }, + /* 58 */ + { "popS", eAX, XX, XX }, + { "popS", eCX, XX, XX }, + { "popS", eDX, XX, XX }, + { "popS", eBX, XX, XX }, + { "popS", eSP, XX, XX }, + { "popS", eBP, XX, XX }, + { "popS", eSI, XX, XX }, + { "popS", eDI, XX, XX }, + /* 60 */ + { "pushaP", XX, XX, XX }, + { "popaP", XX, XX, XX }, + { "boundS", Gv, Ma, XX }, + { "arpl", Ew, Gw, XX }, + { "(bad)", XX, XX, XX }, /* seg fs */ + { "(bad)", XX, XX, XX }, /* seg gs */ + { "(bad)", XX, XX, XX }, /* op size prefix */ + { "(bad)", XX, XX, XX }, /* adr size prefix */ + /* 68 */ + { "pushP", Iv, XX, XX }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushP", sIb, XX, XX }, /* push of byte really pushes 2 or 4 bytes */ + { "imulS", Gv, Ev, sIb }, + { "insb", Yb, indirDX, XX }, + { "insR", Yv, indirDX, XX }, + { "outsb", indirDX, Xb, XX }, + { "outsR", indirDX, Xv, XX }, + /* 70 */ + { "jo", Jb, XX, XX }, + { "jno", Jb, XX, XX }, + { "jb", Jb, XX, XX }, + { "jae", Jb, XX, XX }, + { "je", Jb, XX, XX }, + { "jne", Jb, XX, XX }, + { "jbe", Jb, XX, XX }, + { "ja", Jb, XX, XX }, + /* 78 */ + { "js", Jb, XX, XX }, + { "jns", Jb, XX, XX }, + { "jp", Jb, XX, XX }, + { "jnp", Jb, XX, XX }, + { "jl", Jb, XX, XX }, + { "jge", Jb, XX, XX }, + { "jle", Jb, XX, XX }, + { "jg", Jb, XX, XX }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)", XX, XX, XX }, + { GRP1Ss }, + { "testB", Eb, Gb, XX }, + { "testS", Ev, Gv, XX }, + { "xchgB", Eb, Gb, XX }, + { "xchgS", Ev, Gv, XX }, + /* 88 */ + { "movB", Eb, Gb, XX }, + { "movS", Ev, Gv, XX }, + { "movB", Gb, Eb, XX }, + { "movS", Gv, Ev, XX }, + { "movQ", Ev, Sw, XX }, + { "leaS", Gv, M, XX }, + { "movQ", Sw, Ev, XX }, + { "popQ", Ev, XX, XX }, + /* 90 */ + { "nop", XX, XX, XX }, + { "xchgS", eCX, eAX, XX }, + { "xchgS", eDX, eAX, XX }, + { "xchgS", eBX, eAX, XX }, + { "xchgS", eSP, eAX, XX }, + { "xchgS", eBP, eAX, XX }, + { "xchgS", eSI, eAX, XX }, + { "xchgS", eDI, eAX, XX }, + /* 98 */ + { "cWtR", XX, XX, XX }, + { "cRtd", XX, XX, XX }, + { "lcallP", Ap, XX, XX }, + { "(bad)", XX, XX, XX }, /* fwait */ + { "pushfP", XX, XX, XX }, + { "popfP", XX, XX, XX }, + { "sahf", XX, XX, XX }, + { "lahf", XX, XX, XX }, + /* a0 */ + { "movB", AL, Ob, XX }, + { "movS", eAX, Ov, XX }, + { "movB", Ob, AL, XX }, + { "movS", Ov, eAX, XX }, + { "movsb", Yb, Xb, XX }, + { "movsR", Yv, Xv, XX }, + { "cmpsb", Xb, Yb, XX }, + { "cmpsR", Xv, Yv, XX }, + /* a8 */ + { "testB", AL, Ib, XX }, + { "testS", eAX, Iv, XX }, + { "stosB", Yb, AL, XX }, + { "stosS", Yv, eAX, XX }, + { "lodsB", AL, Xb, XX }, + { "lodsS", eAX, Xv, XX }, + { "scasB", AL, Yb, XX }, + { "scasS", eAX, Yv, XX }, + /* b0 */ + { "movB", AL, Ib, XX }, + { "movB", CL, Ib, XX }, + { "movB", DL, Ib, XX }, + { "movB", BL, Ib, XX }, + { "movB", AH, Ib, XX }, + { "movB", CH, Ib, XX }, + { "movB", DH, Ib, XX }, + { "movB", BH, Ib, XX }, + /* b8 */ + { "movS", eAX, Iv, XX }, + { "movS", eCX, Iv, XX }, + { "movS", eDX, Iv, XX }, + { "movS", eBX, Iv, XX }, + { "movS", eSP, Iv, XX }, + { "movS", eBP, Iv, XX }, + { "movS", eSI, Iv, XX }, + { "movS", eDI, Iv, XX }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "retP", Iw, XX, XX }, + { "retP", XX, XX, XX }, + { "lesS", Gv, Mp, XX }, + { "ldsS", Gv, Mp, XX }, + { "movA", Eb, Ib, XX }, + { "movQ", Ev, Iv, XX }, + /* c8 */ + { "enterP", Iw, Ib, XX }, + { "leaveP", XX, XX, XX }, + { "lretP", Iw, XX, XX }, + { "lretP", XX, XX, XX }, + { "int3", XX, XX, XX }, + { "int", Ib, XX, XX }, + { "into", XX, XX, XX}, + { "iretP", XX, XX, XX }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", sIb, XX, XX }, + { "aad", sIb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "xlat", DSBX, XX, XX }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb, XX, XX }, + { "loope", Jb, XX, XX }, + { "loop", Jb, XX, XX }, + { "jEcxz", Jb, XX, XX }, + { "inB", AL, Ib, XX }, + { "inS", eAX, Ib, XX }, + { "outB", Ib, AL, XX }, + { "outS", Ib, eAX, XX }, + /* e8 */ + { "callP", Jv, XX, XX }, + { "jmpP", Jv, XX, XX }, + { "ljmpP", Ap, XX, XX }, + { "jmp", Jb, XX, XX }, + { "inB", AL, indirDX, XX }, + { "inS", eAX, indirDX, XX }, + { "outB", indirDX, AL, XX }, + { "outS", indirDX, eAX, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, /* lock prefix */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* repne */ + { "(bad)", XX, XX, XX }, /* repz */ + { "hlt", XX, XX, XX }, + { "cmc", XX, XX, XX }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc", XX, XX, XX }, + { "stc", XX, XX, XX }, + { "cli", XX, XX, XX }, + { "sti", XX, XX, XX }, + { "cld", XX, XX, XX }, + { "std", XX, XX, XX }, + { GRP4 }, + { GRP5 }, +}; + +static const struct dis386 dis386_intel[] = { + /* 00 */ + { "add", Eb, Gb, XX }, + { "add", Ev, Gv, XX }, + { "add", Gb, Eb, XX }, + { "add", Gv, Ev, XX }, + { "add", AL, Ib, XX }, + { "add", eAX, Iv, XX }, + { "push", es, XX, XX }, + { "pop", es, XX, XX }, + /* 08 */ + { "or", Eb, Gb, XX }, + { "or", Ev, Gv, XX }, + { "or", Gb, Eb, XX }, + { "or", Gv, Ev, XX }, + { "or", AL, Ib, XX }, + { "or", eAX, Iv, XX }, + { "push", cs, XX, XX }, + { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adc", Eb, Gb, XX }, + { "adc", Ev, Gv, XX }, + { "adc", Gb, Eb, XX }, + { "adc", Gv, Ev, XX }, + { "adc", AL, Ib, XX }, + { "adc", eAX, Iv, XX }, + { "push", ss, XX, XX }, + { "pop", ss, XX, XX }, + /* 18 */ + { "sbb", Eb, Gb, XX }, + { "sbb", Ev, Gv, XX }, + { "sbb", Gb, Eb, XX }, + { "sbb", Gv, Ev, XX }, + { "sbb", AL, Ib, XX }, + { "sbb", eAX, Iv, XX }, + { "push", ds, XX, XX }, + { "pop", ds, XX, XX }, + /* 20 */ + { "and", Eb, Gb, XX }, + { "and", Ev, Gv, XX }, + { "and", Gb, Eb, XX }, + { "and", Gv, Ev, XX }, + { "and", AL, Ib, XX }, + { "and", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG ES prefix */ + { "daa", XX, XX, XX }, + /* 28 */ + { "sub", Eb, Gb, XX }, + { "sub", Ev, Gv, XX }, + { "sub", Gb, Eb, XX }, + { "sub", Gv, Ev, XX }, + { "sub", AL, Ib, XX }, + { "sub", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG CS prefix */ + { "das", XX, XX, XX }, + /* 30 */ + { "xor", Eb, Gb, XX }, + { "xor", Ev, Gv, XX }, + { "xor", Gb, Eb, XX }, + { "xor", Gv, Ev, XX }, + { "xor", AL, Ib, XX }, + { "xor", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG SS prefix */ + { "aaa", XX, XX, XX }, + /* 38 */ + { "cmp", Eb, Gb, XX }, + { "cmp", Ev, Gv, XX }, + { "cmp", Gb, Eb, XX }, + { "cmp", Gv, Ev, XX }, + { "cmp", AL, Ib, XX }, + { "cmp", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG DS prefix */ + { "aas", XX, XX, XX }, + /* 40 */ + { "inc", eAX, XX, XX }, + { "inc", eCX, XX, XX }, + { "inc", eDX, XX, XX }, + { "inc", eBX, XX, XX }, + { "inc", eSP, XX, XX }, + { "inc", eBP, XX, XX }, + { "inc", eSI, XX, XX }, + { "inc", eDI, XX, XX }, + /* 48 */ + { "dec", eAX, XX, XX }, + { "dec", eCX, XX, XX }, + { "dec", eDX, XX, XX }, + { "dec", eBX, XX, XX }, + { "dec", eSP, XX, XX }, + { "dec", eBP, XX, XX }, + { "dec", eSI, XX, XX }, + { "dec", eDI, XX, XX }, + /* 50 */ + { "push", eAX, XX, XX }, + { "push", eCX, XX, XX }, + { "push", eDX, XX, XX }, + { "push", eBX, XX, XX }, + { "push", eSP, XX, XX }, + { "push", eBP, XX, XX }, + { "push", eSI, XX, XX }, + { "push", eDI, XX, XX }, + /* 58 */ + { "pop", eAX, XX, XX }, + { "pop", eCX, XX, XX }, + { "pop", eDX, XX, XX }, + { "pop", eBX, XX, XX }, + { "pop", eSP, XX, XX }, + { "pop", eBP, XX, XX }, + { "pop", eSI, XX, XX }, + { "pop", eDI, XX, XX }, + /* 60 */ + { "pusha", XX, XX, XX }, + { "popa", XX, XX, XX }, + { "bound", Gv, Ma, XX }, + { "arpl", Ew, Gw, XX }, + { "(bad)", XX, XX, XX }, /* seg fs */ + { "(bad)", XX, XX, XX }, /* seg gs */ + { "(bad)", XX, XX, XX }, /* op size prefix */ + { "(bad)", XX, XX, XX }, /* adr size prefix */ + /* 68 */ + { "push", Iv, XX, XX }, /* 386 book wrong */ + { "imul", Gv, Ev, Iv }, + { "push", sIb, XX, XX }, /* push of byte really pushes 2 or 4 bytes */ + { "imul", Gv, Ev, sIb }, + { "ins", Yb, indirDX, XX }, + { "ins", Yv, indirDX, XX }, + { "outs", indirDX, Xb, XX }, + { "outs", indirDX, Xv, XX }, + /* 70 */ + { "jo", Jb, XX, XX }, + { "jno", Jb, XX, XX }, + { "jb", Jb, XX, XX }, + { "jae", Jb, XX, XX }, + { "je", Jb, XX, XX }, + { "jne", Jb, XX, XX }, + { "jbe", Jb, XX, XX }, + { "ja", Jb, XX, XX }, + /* 78 */ + { "js", Jb, XX, XX }, + { "jns", Jb, XX, XX }, + { "jp", Jb, XX, XX }, + { "jnp", Jb, XX, XX }, + { "jl", Jb, XX, XX }, + { "jge", Jb, XX, XX }, + { "jle", Jb, XX, XX }, + { "jg", Jb, XX, XX }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)", XX, XX, XX }, + { GRP1Ss }, + { "test", Eb, Gb, XX }, + { "test", Ev, Gv, XX }, + { "xchg", Eb, Gb, XX }, + { "xchg", Ev, Gv, XX }, + /* 88 */ + { "mov", Eb, Gb, XX }, + { "mov", Ev, Gv, XX }, + { "mov", Gb, Eb, XX }, + { "mov", Gv, Ev, XX }, + { "mov", Ev, Sw, XX }, + { "lea", Gv, M, XX }, + { "mov", Sw, Ev, XX }, + { "pop", Ev, XX, XX }, + /* 90 */ + { "nop", XX, XX, XX }, + { "xchg", eCX, eAX, XX }, + { "xchg", eDX, eAX, XX }, + { "xchg", eBX, eAX, XX }, + { "xchg", eSP, eAX, XX }, + { "xchg", eBP, eAX, XX }, + { "xchg", eSI, eAX, XX }, + { "xchg", eDI, eAX, XX }, + /* 98 */ + { "cW", XX, XX, XX }, /* cwde and cbw */ + { "cR", XX, XX, XX }, /* cdq and cwd */ + { "lcall", Ap, XX, XX }, + { "(bad)", XX, XX, XX }, /* fwait */ + { "pushf", XX, XX, XX }, + { "popf", XX, XX, XX }, + { "sahf", XX, XX, XX }, + { "lahf", XX, XX, XX }, + /* a0 */ + { "mov", AL, Ob, XX }, + { "mov", eAX, Ov, XX }, + { "mov", Ob, AL, XX }, + { "mov", Ov, eAX, XX }, + { "movs", Yb, Xb, XX }, + { "movs", Yv, Xv, XX }, + { "cmps", Xb, Yb, XX }, + { "cmps", Xv, Yv, XX }, + /* a8 */ + { "test", AL, Ib, XX }, + { "test", eAX, Iv, XX }, + { "stos", Yb, AL, XX }, + { "stos", Yv, eAX, XX }, + { "lods", AL, Xb, XX }, + { "lods", eAX, Xv, XX }, + { "scas", AL, Yb, XX }, + { "scas", eAX, Yv, XX }, + /* b0 */ + { "mov", AL, Ib, XX }, + { "mov", CL, Ib, XX }, + { "mov", DL, Ib, XX }, + { "mov", BL, Ib, XX }, + { "mov", AH, Ib, XX }, + { "mov", CH, Ib, XX }, + { "mov", DH, Ib, XX }, + { "mov", BH, Ib, XX }, + /* b8 */ + { "mov", eAX, Iv, XX }, + { "mov", eCX, Iv, XX }, + { "mov", eDX, Iv, XX }, + { "mov", eBX, Iv, XX }, + { "mov", eSP, Iv, XX }, + { "mov", eBP, Iv, XX }, + { "mov", eSI, Iv, XX }, + { "mov", eDI, Iv, XX }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw, XX, XX }, + { "ret", XX, XX, XX }, + { "les", Gv, Mp, XX }, + { "lds", Gv, Mp, XX }, + { "mov", Eb, Ib, XX }, + { "mov", Ev, Iv, XX }, + /* c8 */ + { "enter", Iw, Ib, XX }, + { "leave", XX, XX, XX }, + { "lret", Iw, XX, XX }, + { "lret", XX, XX, XX }, + { "int3", XX, XX, XX }, + { "int", Ib, XX, XX }, + { "into", XX, XX, XX }, + { "iret", XX, XX, XX }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", sIb, XX, XX }, + { "aad", sIb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "xlat", DSBX, XX, XX }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb, XX, XX }, + { "loope", Jb, XX, XX }, + { "loop", Jb, XX, XX }, + { "jEcxz", Jb, XX, XX }, + { "in", AL, Ib, XX }, + { "in", eAX, Ib, XX }, + { "out", Ib, AL, XX }, + { "out", Ib, eAX, XX }, + /* e8 */ + { "call", Jv, XX, XX }, + { "jmp", Jv, XX, XX }, + { "ljmp", Ap, XX, XX }, + { "jmp", Jb, XX, XX }, + { "in", AL, indirDX, XX }, + { "in", eAX, indirDX, XX }, + { "out", indirDX, AL, XX }, + { "out", indirDX, eAX, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, /* lock prefix */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* repne */ + { "(bad)", XX, XX, XX }, /* repz */ + { "hlt", XX, XX, XX }, + { "cmc", XX, XX, XX }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc", XX, XX, XX }, + { "stc", XX, XX, XX }, + { "cli", XX, XX, XX }, + { "sti", XX, XX, XX }, + { "cld", XX, XX, XX }, + { "std", XX, XX, XX }, + { GRP4 }, + { GRP5 }, +}; + +static const struct dis386 dis386_twobyte_att[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew, XX }, + { "lslS", Gv, Ew, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "clts", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 08 */ + { "invd", XX, XX, XX }, + { "wbinvd", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "ud2a", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { GRPAMD }, + { "femms", XX, XX, XX }, + { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix */ + /* 10 */ + { PREGRP8 }, + { PREGRP9 }, + { "movlps", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ + { "movlps", EX, XM, SIMD_Fixup, 'h' }, + { "unpcklps", XM, EX, XX }, + { "unpckhps", XM, EX, XX }, + { "movhps", XM, EX, SIMD_Fixup, 'l' }, + { "movhps", EX, XM, SIMD_Fixup, 'l' }, + /* 18 */ + { GRP14 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movL", Rd, Cd, XX }, + { "movL", Rd, Dd, XX }, + { "movL", Cd, Rd, XX }, + { "movL", Dd, Rd, XX }, + { "movL", Rd, Td, XX }, + { "(bad)", XX, XX, XX }, + { "movL", Td, Rd, XX }, + { "(bad)", XX, XX, XX }, + /* 28 */ + { "movaps", XM, EX, XX }, + { "movaps", EX, XM, XX }, + { PREGRP2 }, + { "movntps", Ev, XM, XX }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomiss", XM, EX, XX }, + { "comiss", XM, EX, XX }, + /* 30 */ + { "wrmsr", XX, XX, XX }, + { "rdtsc", XX, XX, XX }, + { "rdmsr", XX, XX, XX }, + { "rdpmc", XX, XX, XX }, + { "sysenter", XX, XX, XX }, + { "sysexit", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 38 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 40 */ + { "cmovo", Gv, Ev, XX }, + { "cmovno", Gv, Ev, XX }, + { "cmovb", Gv, Ev, XX }, + { "cmovae", Gv, Ev, XX }, + { "cmove", Gv, Ev, XX }, + { "cmovne", Gv, Ev, XX }, + { "cmovbe", Gv, Ev, XX }, + { "cmova", Gv, Ev, XX }, + /* 48 */ + { "cmovs", Gv, Ev, XX }, + { "cmovns", Gv, Ev, XX }, + { "cmovp", Gv, Ev, XX }, + { "cmovnp", Gv, Ev, XX }, + { "cmovl", Gv, Ev, XX }, + { "cmovge", Gv, Ev, XX }, + { "cmovle", Gv, Ev, XX }, + { "cmovg", Gv, Ev, XX }, + /* 50 */ + { "movmskps", Gv, EX, XX }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andps", XM, EX, XX }, + { "andnps", XM, EX, XX }, + { "orps", XM, EX, XX }, + { "xorps", XM, EX, XX }, + /* 58 */ + { PREGRP0 }, + { PREGRP10 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, + /* 60 */ + { "punpcklbw", MX, EM, XX }, + { "punpcklwd", MX, EM, XX }, + { "punpckldq", MX, EM, XX }, + { "packsswb", MX, EM, XX }, + { "pcmpgtb", MX, EM, XX }, + { "pcmpgtw", MX, EM, XX }, + { "pcmpgtd", MX, EM, XX }, + { "packuswb", MX, EM, XX }, + /* 68 */ + { "punpckhbw", MX, EM, XX }, + { "punpckhwd", MX, EM, XX }, + { "punpckhdq", MX, EM, XX }, + { "packssdw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", MX, Ed, XX }, + { "movq", MX, EM, XX }, + /* 70 */ + { "pshufw", MX, EM, Ib }, + { GRP10 }, + { GRP11 }, + { GRP12 }, + { "pcmpeqb", MX, EM, XX }, + { "pcmpeqw", MX, EM, XX }, + { "pcmpeqd", MX, EM, XX }, + { "emms", XX, XX, XX }, + /* 78 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", Ed, MX, XX }, + { "movq", EM, MX, XX }, + /* 80 */ + { "jo", Jv, XX, XX }, + { "jno", Jv, XX, XX }, + { "jb", Jv, XX, XX }, + { "jae", Jv, XX, XX }, + { "je", Jv, XX, XX }, + { "jne", Jv, XX, XX }, + { "jbe", Jv, XX, XX }, + { "ja", Jv, XX, XX }, + /* 88 */ + { "js", Jv, XX, XX }, + { "jns", Jv, XX, XX }, + { "jp", Jv, XX, XX }, + { "jnp", Jv, XX, XX }, + { "jl", Jv, XX, XX }, + { "jge", Jv, XX, XX }, + { "jle", Jv, XX, XX }, + { "jg", Jv, XX, XX }, + /* 90 */ + { "seto", Eb, XX, XX }, + { "setno", Eb, XX, XX }, + { "setb", Eb, XX, XX }, + { "setae", Eb, XX, XX }, + { "sete", Eb, XX, XX }, + { "setne", Eb, XX, XX }, + { "setbe", Eb, XX, XX }, + { "seta", Eb, XX, XX }, + /* 98 */ + { "sets", Eb, XX, XX }, + { "setns", Eb, XX, XX }, + { "setp", Eb, XX, XX }, + { "setnp", Eb, XX, XX }, + { "setl", Eb, XX, XX }, + { "setge", Eb, XX, XX }, + { "setle", Eb, XX, XX }, + { "setg", Eb, XX, XX }, + /* a0 */ + { "pushP", fs, XX, XX }, + { "popP", fs, XX, XX }, + { "cpuid", XX, XX, XX }, + { "btS", Ev, Gv, XX }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* a8 */ + { "pushP", gs, XX, XX }, + { "popP", gs, XX, XX }, + { "rsm", XX, XX, XX }, + { "btsS", Ev, Gv, XX }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { GRP13 }, + { "imulS", Gv, Ev, XX }, + /* b0 */ + { "cmpxchgB", Eb, Gb, XX }, + { "cmpxchgS", Ev, Gv, XX }, + { "lssS", Gv, Mp, XX }, + { "btrS", Ev, Gv, XX }, + { "lfsS", Gv, Mp, XX }, + { "lgsS", Gv, Mp, XX }, + { "movzbR", Gv, Eb, XX }, + { "movzwR", Gv, Ew, XX }, /* yes, there really is movzww ! */ + /* b8 */ + { "(bad)", XX, XX, XX }, + { "ud2b", XX, XX, XX }, + { GRP8 }, + { "btcS", Ev, Gv, XX }, + { "bsfS", Gv, Ev, XX }, + { "bsrS", Gv, Ev, XX }, + { "movsbR", Gv, Eb, XX }, + { "movswR", Gv, Ew, XX }, /* yes, there really is movsww ! */ + /* c0 */ + { "xaddB", Eb, Gb, XX }, + { "xaddS", Ev, Gv, XX }, + { PREGRP1 }, + { "(bad)", XX, XX, XX }, + { "pinsrw", MX, Ev, Ib }, + { "pextrw", Ev, MX, Ib }, + { "shufps", XM, EX, Ib }, + { GRP9 }, + /* c8 */ + { "bswap", eAX, XX, XX }, /* bswap doesn't support 16 bit regs */ + { "bswap", eCX, XX, XX }, + { "bswap", eDX, XX, XX }, + { "bswap", eBX, XX, XX }, + { "bswap", eSP, XX, XX }, + { "bswap", eBP, XX, XX }, + { "bswap", eSI, XX, XX }, + { "bswap", eDI, XX, XX }, + /* d0 */ + { "(bad)", XX, XX, XX }, + { "psrlw", MX, EM, XX }, + { "psrld", MX, EM, XX }, + { "psrlq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmullw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmovmskb", Ev, MX, XX }, + /* d8 */ + { "psubusb", MX, EM, XX }, + { "psubusw", MX, EM, XX }, + { "pminub", MX, EM, XX }, + { "pand", MX, EM, XX }, + { "paddusb", MX, EM, XX }, + { "paddusw", MX, EM, XX }, + { "pmaxub", MX, EM, XX }, + { "pandn", MX, EM, XX }, + /* e0 */ + { "pavgb", MX, EM, XX }, + { "psraw", MX, EM, XX }, + { "psrad", MX, EM, XX }, + { "pavgw", MX, EM, XX }, + { "pmulhuw", MX, EM, XX }, + { "pmulhw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "movntq", Ev, MX, XX }, + /* e8 */ + { "psubsb", MX, EM, XX }, + { "psubsw", MX, EM, XX }, + { "pminsw", MX, EM, XX }, + { "por", MX, EM, XX }, + { "paddsb", MX, EM, XX }, + { "paddsw", MX, EM, XX }, + { "pmaxsw", MX, EM, XX }, + { "pxor", MX, EM, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, + { "psllw", MX, EM, XX }, + { "pslld", MX, EM, XX }, + { "psllq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmaddwd", MX, EM, XX }, + { "psadbw", MX, EM, XX }, + { "maskmovq", MX, EM, XX }, + /* f8 */ + { "psubb", MX, EM, XX }, + { "psubw", MX, EM, XX }, + { "psubd", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "paddb", MX, EM, XX }, + { "paddw", MX, EM, XX }, + { "paddd", MX, EM, XX }, + { "(bad)", XX, XX, XX } +}; + +static const struct dis386 dis386_twobyte_intel[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "lar", Gv, Ew, XX }, + { "lsl", Gv, Ew, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "clts", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 08 */ + { "invd", XX, XX, XX }, + { "wbinvd", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "ud2a", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { GRPAMD }, + { "femms" , XX, XX, XX}, + { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix */ + /* 10 */ + { PREGRP8 }, + { PREGRP9 }, + { "movlps", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ + { "movlps", EX, XM, SIMD_Fixup, 'h' }, + { "unpcklps", XM, EX, XX }, + { "unpckhps", XM, EX, XX }, + { "movhps", XM, EX, SIMD_Fixup, 'l' }, + { "movhps", EX, XM, SIMD_Fixup, 'l' }, + /* 18 */ + { GRP14 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "mov", Rd, Cd, XX }, + { "mov", Rd, Dd, XX }, + { "mov", Cd, Rd, XX }, + { "mov", Dd, Rd, XX }, + { "mov", Rd, Td, XX }, + { "(bad)", XX, XX, XX }, + { "mov", Td, Rd, XX }, + { "(bad)", XX, XX, XX }, + /* 28 */ + { "movaps", XM, EX, XX }, + { "movaps", EX, XM, XX }, + { PREGRP2 }, + { "movntps", Ev, XM, XX }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomiss", XM, EX, XX }, + { "comiss", XM, EX, XX }, + /* 30 */ + { "wrmsr", XX, XX, XX }, + { "rdtsc", XX, XX, XX }, + { "rdmsr", XX, XX, XX }, + { "rdpmc", XX, XX, XX }, + { "sysenter", XX, XX, XX }, + { "sysexit", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 38 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 40 */ + { "cmovo", Gv, Ev, XX }, + { "cmovno", Gv, Ev, XX }, + { "cmovb", Gv, Ev, XX }, + { "cmovae", Gv, Ev, XX }, + { "cmove", Gv, Ev, XX }, + { "cmovne", Gv, Ev, XX }, + { "cmovbe", Gv, Ev, XX }, + { "cmova", Gv, Ev, XX }, + /* 48 */ + { "cmovs", Gv, Ev, XX }, + { "cmovns", Gv, Ev, XX }, + { "cmovp", Gv, Ev, XX }, + { "cmovnp", Gv, Ev, XX }, + { "cmovl", Gv, Ev, XX }, + { "cmovge", Gv, Ev, XX }, + { "cmovle", Gv, Ev, XX }, + { "cmovg", Gv, Ev, XX }, + /* 50 */ + { "movmskps", Gv, EX, XX }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andps", XM, EX, XX }, + { "andnps", XM, EX, XX }, + { "orps", XM, EX, XX }, + { "xorps", XM, EX, XX }, + /* 58 */ + { PREGRP0 }, + { PREGRP10 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, + /* 60 */ + { "punpcklbw", MX, EM, XX }, + { "punpcklwd", MX, EM, XX }, + { "punpckldq", MX, EM, XX }, + { "packsswb", MX, EM, XX }, + { "pcmpgtb", MX, EM, XX }, + { "pcmpgtw", MX, EM, XX }, + { "pcmpgtd", MX, EM, XX }, + { "packuswb", MX, EM, XX }, + /* 68 */ + { "punpckhbw", MX, EM, XX }, + { "punpckhwd", MX, EM, XX }, + { "punpckhdq", MX, EM, XX }, + { "packssdw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", MX, Ed, XX }, + { "movq", MX, EM, XX }, + /* 70 */ + { "pshufw", MX, EM, Ib }, + { GRP10 }, + { GRP11 }, + { GRP12 }, + { "pcmpeqb", MX, EM, XX }, + { "pcmpeqw", MX, EM, XX }, + { "pcmpeqd", MX, EM, XX }, + { "emms", XX, XX, XX }, + /* 78 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", Ed, MX, XX }, + { "movq", EM, MX, XX }, + /* 80 */ + { "jo", Jv, XX, XX }, + { "jno", Jv, XX, XX }, + { "jb", Jv, XX, XX }, + { "jae", Jv, XX, XX }, + { "je", Jv, XX, XX }, + { "jne", Jv, XX, XX }, + { "jbe", Jv, XX, XX }, + { "ja", Jv, XX, XX }, + /* 88 */ + { "js", Jv, XX, XX }, + { "jns", Jv, XX, XX }, + { "jp", Jv, XX, XX }, + { "jnp", Jv, XX, XX }, + { "jl", Jv, XX, XX }, + { "jge", Jv, XX, XX }, + { "jle", Jv, XX, XX }, + { "jg", Jv, XX, XX }, + /* 90 */ + { "seto", Eb, XX, XX }, + { "setno", Eb, XX, XX }, + { "setb", Eb, XX, XX }, + { "setae", Eb, XX, XX }, + { "sete", Eb, XX, XX }, + { "setne", Eb, XX, XX }, + { "setbe", Eb, XX, XX }, + { "seta", Eb, XX, XX }, + /* 98 */ + { "sets", Eb, XX, XX }, + { "setns", Eb, XX, XX }, + { "setp", Eb, XX, XX }, + { "setnp", Eb, XX, XX }, + { "setl", Eb, XX, XX }, + { "setge", Eb, XX, XX }, + { "setle", Eb, XX, XX }, + { "setg", Eb, XX, XX }, + /* a0 */ + { "push", fs, XX, XX }, + { "pop", fs, XX, XX }, + { "cpuid", XX, XX, XX }, + { "bt", Ev, Gv, XX }, + { "shld", Ev, Gv, Ib }, + { "shld", Ev, Gv, CL }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* a8 */ + { "push", gs, XX, XX }, + { "pop", gs, XX, XX }, + { "rsm" , XX, XX, XX}, + { "bts", Ev, Gv, XX }, + { "shrd", Ev, Gv, Ib }, + { "shrd", Ev, Gv, CL }, + { GRP13 }, + { "imul", Gv, Ev, XX }, + /* b0 */ + { "cmpxchg", Eb, Gb, XX }, + { "cmpxchg", Ev, Gv, XX }, + { "lss", Gv, Mp, XX }, + { "btr", Ev, Gv, XX }, + { "lfs", Gv, Mp, XX }, + { "lgs", Gv, Mp, XX }, + { "movzx", Gv, Eb, XX }, + { "movzx", Gv, Ew, XX }, + /* b8 */ + { "(bad)", XX, XX, XX }, + { "ud2b", XX, XX, XX }, + { GRP8 }, + { "btc", Ev, Gv, XX }, + { "bsf", Gv, Ev, XX }, + { "bsr", Gv, Ev, XX }, + { "movsx", Gv, Eb, XX }, + { "movsx", Gv, Ew, XX }, + /* c0 */ + { "xadd", Eb, Gb, XX }, + { "xadd", Ev, Gv, XX }, + { PREGRP1 }, + { "(bad)", XX, XX, XX }, + { "pinsrw", MX, Ev, Ib }, + { "pextrw", Ev, MX, Ib }, + { "shufps", XM, EX, Ib }, + { GRP9 }, + /* c8 */ + { "bswap", eAX, XX, XX }, /* bswap doesn't support 16 bit regs */ + { "bswap", eCX, XX, XX }, + { "bswap", eDX, XX, XX }, + { "bswap", eBX, XX, XX }, + { "bswap", eSP, XX, XX }, + { "bswap", eBP, XX, XX }, + { "bswap", eSI, XX, XX }, + { "bswap", eDI, XX, XX }, + /* d0 */ + { "(bad)", XX, XX, XX }, + { "psrlw", MX, EM, XX }, + { "psrld", MX, EM, XX }, + { "psrlq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmullw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmovmskb", Ev, MX, XX }, + /* d8 */ + { "psubusb", MX, EM, XX }, + { "psubusw", MX, EM, XX }, + { "pminub", MX, EM, XX }, + { "pand", MX, EM, XX }, + { "paddusb", MX, EM, XX }, + { "paddusw", MX, EM, XX }, + { "pmaxub", MX, EM, XX }, + { "pandn", MX, EM, XX }, + /* e0 */ + { "pavgb", MX, EM, XX }, + { "psraw", MX, EM, XX }, + { "psrad", MX, EM, XX }, + { "pavgw", MX, EM, XX }, + { "pmulhuw", MX, EM, XX }, + { "pmulhw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "movntq", Ev, MX, XX }, + /* e8 */ + { "psubsb", MX, EM, XX }, + { "psubsw", MX, EM, XX }, + { "pminsw", MX, EM, XX }, + { "por", MX, EM, XX }, + { "paddsb", MX, EM, XX }, + { "paddsw", MX, EM, XX }, + { "pmaxsw", MX, EM, XX }, + { "pxor", MX, EM, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, + { "psllw", MX, EM, XX }, + { "pslld", MX, EM, XX }, + { "psllq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmaddwd", MX, EM, XX }, + { "psadbw", MX, EM, XX }, + { "maskmovq", MX, EM, XX }, + /* f8 */ + { "psubb", MX, EM, XX }, + { "psubw", MX, EM, XX }, + { "psubd", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "paddb", MX, EM, XX }, + { "paddw", MX, EM, XX }, + { "paddd", MX, EM, XX }, + { "(bad)", XX, XX, XX } +}; + +static const unsigned char onebyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ + /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ + /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ + /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ + /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ + /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ + /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ + /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ + /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */ + /* 70 */ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ + /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ + /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ + /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_f3_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *insn_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static int mod; +static int rm; +static int reg; +static void oappend PARAMS ((const char *s)); + +static const char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static const char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static const char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static const char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; +static const char *index16[] = { + "%bx,%si","%bx,%di","%bp,%si","%bp,%di","%si","%di","%bp","%bx" +}; + +static const struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addA", Eb, Ib, XX }, + { "orA", Eb, Ib, XX }, + { "adcA", Eb, Ib, XX }, + { "sbbA", Eb, Ib, XX }, + { "andA", Eb, Ib, XX }, + { "subA", Eb, Ib, XX }, + { "xorA", Eb, Ib, XX }, + { "cmpA", Eb, Ib, XX } + }, + /* GRP1S */ + { + { "addQ", Ev, Iv, XX }, + { "orQ", Ev, Iv, XX }, + { "adcQ", Ev, Iv, XX }, + { "sbbQ", Ev, Iv, XX }, + { "andQ", Ev, Iv, XX }, + { "subQ", Ev, Iv, XX }, + { "xorQ", Ev, Iv, XX }, + { "cmpQ", Ev, Iv, XX } + }, + /* GRP1Ss */ + { + { "addQ", Ev, sIb, XX }, + { "orQ", Ev, sIb, XX }, + { "adcQ", Ev, sIb, XX }, + { "sbbQ", Ev, sIb, XX }, + { "andQ", Ev, sIb, XX }, + { "subQ", Ev, sIb, XX }, + { "xorQ", Ev, sIb, XX }, + { "cmpQ", Ev, sIb, XX } + }, + /* GRP2b */ + { + { "rolA", Eb, Ib, XX }, + { "rorA", Eb, Ib, XX }, + { "rclA", Eb, Ib, XX }, + { "rcrA", Eb, Ib, XX }, + { "shlA", Eb, Ib, XX }, + { "shrA", Eb, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, Ib, XX }, + }, + /* GRP2S */ + { + { "rolQ", Ev, Ib, XX }, + { "rorQ", Ev, Ib, XX }, + { "rclQ", Ev, Ib, XX }, + { "rcrQ", Ev, Ib, XX }, + { "shlQ", Ev, Ib, XX }, + { "shrQ", Ev, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, Ib, XX }, + }, + /* GRP2b_one */ + { + { "rolA", Eb, XX, XX }, + { "rorA", Eb, XX, XX }, + { "rclA", Eb, XX, XX }, + { "rcrA", Eb, XX, XX }, + { "shlA", Eb, XX, XX }, + { "shrA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, XX, XX }, + }, + /* GRP2S_one */ + { + { "rolQ", Ev, XX, XX }, + { "rorQ", Ev, XX, XX }, + { "rclQ", Ev, XX, XX }, + { "rcrQ", Ev, XX, XX }, + { "shlQ", Ev, XX, XX }, + { "shrQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX}, + { "sarQ", Ev, XX, XX }, + }, + /* GRP2b_cl */ + { + { "rolA", Eb, CL, XX }, + { "rorA", Eb, CL, XX }, + { "rclA", Eb, CL, XX }, + { "rcrA", Eb, CL, XX }, + { "shlA", Eb, CL, XX }, + { "shrA", Eb, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, CL, XX }, + }, + /* GRP2S_cl */ + { + { "rolQ", Ev, CL, XX }, + { "rorQ", Ev, CL, XX }, + { "rclQ", Ev, CL, XX }, + { "rcrQ", Ev, CL, XX }, + { "shlQ", Ev, CL, XX }, + { "shrQ", Ev, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, CL, XX } + }, + /* GRP3b */ + { + { "testA", Eb, Ib, XX }, + { "(bad)", Eb, XX, XX }, + { "notA", Eb, XX, XX }, + { "negA", Eb, XX, XX }, + { "mulB", AL, Eb, XX }, + { "imulB", AL, Eb, XX }, + { "divB", AL, Eb, XX }, + { "idivB", AL, Eb, XX } + }, + /* GRP3S */ + { + { "testQ", Ev, Iv, XX }, + { "(bad)", XX, XX, XX }, + { "notQ", Ev, XX, XX }, + { "negQ", Ev, XX, XX }, + { "mulS", eAX, Ev, XX }, + { "imulS", eAX, Ev, XX }, + { "divS", eAX, Ev, XX }, + { "idivS", eAX, Ev, XX }, + }, + /* GRP4 */ + { + { "incA", Eb, XX, XX }, + { "decA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP5 */ + { + { "incQ", Ev, XX, XX }, + { "decQ", Ev, XX, XX }, + { "callP", indirEv, XX, XX }, + { "lcallP", indirEv, XX, XX }, + { "jmpP", indirEv, XX, XX }, + { "ljmpP", indirEv, XX, XX }, + { "pushQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP6 */ + { + { "sldt", Ew, XX, XX }, + { "str", Ew, XX, XX }, + { "lldt", Ew, XX, XX }, + { "ltr", Ew, XX, XX }, + { "verr", Ew, XX, XX }, + { "verw", Ew, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX } + }, + /* GRP7 */ + { + { "sgdt", Ew, XX, XX }, + { "sidt", Ew, XX, XX }, + { "lgdt", Ew, XX, XX }, + { "lidt", Ew, XX, XX }, + { "smsw", Ew, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lmsw", Ew, XX, XX }, + { "invlpg", Ew, XX, XX }, + }, + /* GRP8 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "btQ", Ev, Ib, XX }, + { "btsQ", Ev, Ib, XX }, + { "btrQ", Ev, Ib, XX }, + { "btcQ", Ev, Ib, XX }, + }, + /* GRP9 */ + { + { "(bad)", XX, XX, XX }, + { "cmpxchg8b", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP10 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psraw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psllw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP11 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psrad", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "pslld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP12 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlq", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psllq", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP13 */ + { + { "fxsave", Ev, XX, XX }, + { "fxrstor", Ev, XX, XX }, + { "ldmxcsr", Ev, XX, XX }, + { "stmxcsr", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "sfence", None, XX, XX }, + }, + /* GRP14 */ + { + { "prefetchnta", Ev, XX, XX }, + { "prefetcht0", Ev, XX, XX }, + { "prefetcht1", Ev, XX, XX }, + { "prefetcht2", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRPAMD */ + { + { "prefetch", Eb, XX, XX }, + { "prefetchw", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + } + +}; + +static const struct dis386 prefix_user_table[][2] = { + /* PREGRP0 */ + { + { "addps", XM, EX, XX }, + { "addss", XM, EX, XX }, + }, + /* PREGRP1 */ + { + { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX */ + { "", XM, EX, OPSIMD }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", XM, EM, XX }, + { "cvtsi2ss", XM, Ev, XX }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", MX, EX, XX }, + { "cvtss2si", Gv, EX, XX }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", MX, EX, XX }, + { "cvttss2si", Gv, EX, XX }, + }, + /* PREGRP5 */ + { + { "divps", XM, EX, XX }, + { "divss", XM, EX, XX }, + }, + /* PREGRP6 */ + { + { "maxps", XM, EX, XX }, + { "maxss", XM, EX, XX }, + }, + /* PREGRP7 */ + { + { "minps", XM, EX, XX }, + { "minss", XM, EX, XX }, + }, + /* PREGRP8 */ + { + { "movups", XM, EX, XX }, + { "movss", XM, EX, XX }, + }, + /* PREGRP9 */ + { + { "movups", EX, XM, XX }, + { "movss", EX, XM, XX }, + }, + /* PREGRP10 */ + { + { "mulps", XM, EX, XX }, + { "mulss", XM, EX, XX }, + }, + /* PREGRP11 */ + { + { "rcpps", XM, EX, XX }, + { "rcpss", XM, EX, XX }, + }, + /* PREGRP12 */ + { + { "rsqrtps", XM, EX, XX }, + { "rsqrtss", XM, EX, XX }, + }, + /* PREGRP13 */ + { + { "sqrtps", XM, EX, XX }, + { "sqrtss", XM, EX, XX }, + }, + /* PREGRP14 */ + { + { "subps", XM, EX, XX }, + { "subss", XM, EX, XX }, + } +}; + +#define INTERNAL_DISASSEMBLER_ERROR "" + +static void +ckprefix () +{ + prefixes = 0; + used_prefixes = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADDR; + break; + case FWAIT_OPCODE: + /* fwait is really an instruction. If there are prefixes + before the fwait, they belong to the fwait, *not* to the + following instruction. */ + if (prefixes) + { + prefixes |= PREFIX_FWAIT; + codep++; + return; + } + prefixes = PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +/* Return the name of the prefix byte PREF, or NULL if PREF is not a + prefix byte. */ + +static const char * +prefix_name (pref, sizeflag) + int pref; + int sizeflag; +{ + switch (pref) + { + case 0xf3: + return "repz"; + case 0xf2: + return "repnz"; + case 0xf0: + return "lock"; + case 0x2e: + return "cs"; + case 0x36: + return "ss"; + case 0x3e: + return "ds"; + case 0x26: + return "es"; + case 0x64: + return "fs"; + case 0x65: + return "gs"; + case 0x66: + return (sizeflag & DFLAG) ? "data16" : "data32"; + case 0x67: + return (sizeflag & AFLAG) ? "addr16" : "addr32"; + case FWAIT_OPCODE: + return "fwait"; + default: + return NULL; + } +} + +static char op1out[100], op2out[100], op3out[100]; +static int op_ad, op_index[3]; +static unsigned int op_address[3]; +static unsigned int start_pc; + + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +static int print_insn_i386 + PARAMS ((bfd_vma pc, disassemble_info *info)); + +static char intel_syntax; +static char open_char; +static char close_char; +static char separator_char; +static char scale_char; + +int +print_insn_i386_att (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 0; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + + return print_insn_i386 (pc, info); +} + +int +print_insn_i386_intel (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 1; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + + return print_insn_i386 (pc, info); +} + +static int +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + const struct dis386 *dp; + int i; + int two_source_ops; + char *first, *second, *third; + int needcomma; + unsigned char need_modrm; + unsigned char uses_f3_prefix; + VOLATILE int sizeflag; + VOLATILE int orig_sizeflag; + + struct dis_private priv; + bfd_byte *inbuf = priv.the_buffer; + + if (info->mach == bfd_mach_i386_i386 + || info->mach == bfd_mach_i386_i386_intel_syntax) + sizeflag = AFLAG|DFLAG; + else if (info->mach == bfd_mach_i386_i8086) + sizeflag = 0; + else + abort (); + orig_sizeflag = sizeflag; + + /* The output looks better if we put 7 bytes on a line, since that + puts most long word instructions on a single line. */ + info->bytes_per_line = 7; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + the_info = info; + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + +#ifndef __KERNEL__ + if (setjmp (priv.bailout) != 0) + { + const char *name; + + /* Getting here means we tried for data but didn't get it. That + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > inbuf) + { + name = prefix_name (inbuf[0], orig_sizeflag); + if (name != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + { + /* Just print the first byte as a .byte instruction. */ + (*info->fprintf_func) (info->stream, ".byte 0x%x", + (unsigned int) inbuf[0]); + } + + return 1; + } + + return -1; + } +#endif + + ckprefix (); + + insn_codep = codep; + + FETCH_DATA (info, codep + 1); + two_source_ops = (*codep == 0x62) || (*codep == 0xc8); + + obufp = obuf; + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + const char *name; + + /* fwait not followed by floating point instruction. Print the + first prefix, which is probably fwait itself. */ + name = prefix_name (inbuf[0], orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + + if (*codep == 0x0f) + { + FETCH_DATA (info, codep + 2); + if (intel_syntax) + dp = &dis386_twobyte_intel[*++codep]; + else + dp = &dis386_twobyte_att[*++codep]; + need_modrm = twobyte_has_modrm[*codep]; + uses_f3_prefix = twobyte_uses_f3_prefix[*codep]; + } + else + { + if (intel_syntax) + dp = &dis386_intel[*codep]; + else + dp = &dis386_att[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + uses_f3_prefix = 0; + } + codep++; + + if (!uses_f3_prefix && (prefixes & PREFIX_REPZ)) + { + oappend ("repz "); + used_prefixes |= PREFIX_REPZ; + } + if (prefixes & PREFIX_REPNZ) + { + oappend ("repnz "); + used_prefixes |= PREFIX_REPNZ; + } + if (prefixes & PREFIX_LOCK) + { + oappend ("lock "); + used_prefixes |= PREFIX_LOCK; + } + + if (prefixes & PREFIX_DATA) + sizeflag ^= DFLAG; + + if (prefixes & PREFIX_ADDR) + { + sizeflag ^= AFLAG; + if (sizeflag & AFLAG) + oappend ("addr32 "); + else + oappend ("addr16 "); + used_prefixes |= PREFIX_ADDR; + } + + if (need_modrm) + { + FETCH_DATA (info, codep + 1); + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + } + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (sizeflag); + } + else + { + if (dp->name == NULL) + { + switch(dp->bytemode2) + { + case USE_GROUPS: + dp = &grps[dp->bytemode1][reg]; + break; + case USE_PREFIX_USER_TABLE: + dp = &prefix_user_table[dp->bytemode1][prefixes & PREFIX_REPZ ? 1 : 0]; + used_prefixes |= (prefixes & PREFIX_REPZ); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + } + + putop (dp->name, sizeflag); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1, sizeflag); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2, sizeflag); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3, sizeflag); + } + + /* See if any prefixes were not used. If so, print the first one + separately. If we don't do this, we'll wind up printing an + instruction stream which does not precisely correspond to the + bytes we are disassembling. */ + if ((prefixes & ~used_prefixes) != 0) + { + const char *name; + + name = prefix_name (inbuf[0], orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* The enter and bound instructions are printed with operands in the same + order as the intel book; everything else is printed in reverse order. */ + if (intel_syntax || two_source_ops) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); + else + (*info->fprintf_func) (info->stream, "%s", first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[1] != -1) + (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); + else + (*info->fprintf_func) (info->stream, "%s", second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[2] != -1) + (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); + else + (*info->fprintf_func) (info->stream, "%s", third); + } + return codep - inbuf; +} + +static const char *float_mem_att[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +static const char *float_mem_intel[] = { + /* d8 */ + "fadd", + "fmul", + "fcom", + "fcomp", + "fsub", + "fsubr", + "fdiv", + "fdivr", + /* d9 */ + "fld", + "(bad)", + "fst", + "fstp", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* db */ + "fild", + "(bad)", + "fist", + "fistp", + "(bad)", + "fld", + "(bad)", + "fstp", + /* dc */ + "fadd", + "fmul", + "fcom", + "fcomp", + "fsub", + "fsubr", + "fdiv", + "fdivr", + /* dd */ + "fld", + "(bad)", + "fst", + "fstp", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fild", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 + +#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 +#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 +#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 +#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 +#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 +#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 +#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 +#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 + +static const struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi, XX }, + { "fmul", ST, STi, XX }, + { "fcom", STi, XX, XX }, + { "fcomp", STi, XX, XX }, + { "fsub", ST, STi, XX }, + { "fsubr", ST, STi, XX }, + { "fdiv", ST, STi, XX }, + { "fdivr", ST, STi, XX }, + }, + /* d9 */ + { + { "fld", STi, XX, XX }, + { "fxch", STi, XX, XX }, + { FGRPd9_2 }, + { "(bad)", XX, XX, XX }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", ST, STi, XX }, + { "fcmove", ST, STi, XX }, + { "fcmovbe",ST, STi, XX }, + { "fcmovu", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + { FGRPda_5 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* db */ + { + { "fcmovnb",ST, STi, XX }, + { "fcmovne",ST, STi, XX }, + { "fcmovnbe",ST, STi, XX }, + { "fcmovnu",ST, STi, XX }, + { FGRPdb_4 }, + { "fucomi", ST, STi, XX }, + { "fcomi", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + }, + /* dc */ + { + { "fadd", STi, ST, XX }, + { "fmul", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, +#if UNIXWARE_COMPAT + { "fsub", STi, ST, XX }, + { "fsubr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, + { "fdivr", STi, ST, XX }, +#else + { "fsubr", STi, ST, XX }, + { "fsub", STi, ST, XX }, + { "fdivr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, +#endif + }, + /* dd */ + { + { "ffree", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "fst", STi, XX, XX }, + { "fstp", STi, XX, XX }, + { "fucom", STi, XX, XX }, + { "fucomp", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* de */ + { + { "faddp", STi, ST, XX }, + { "fmulp", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { FGRPde_3 }, +#if UNIXWARE_COMPAT + { "fsubp", STi, ST, XX }, + { "fsubrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, +#else + { "fsubrp", STi, ST, XX }, + { "fsubp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, +#endif + }, + /* df */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { FGRPdf_4 }, + { "fucomip",ST, STi, XX }, + { "fcomip", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + }, +}; + + +static char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat (sizeflag) + int sizeflag; +{ + const struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + if (intel_syntax) + putop (float_mem_intel[(floatop - 0xd8 ) * 8 + reg], sizeflag); + else + putop (float_mem_att[(floatop - 0xd8 ) * 8 + reg], sizeflag); + obufp = op1out; + if (floatop == 0xdb) + OP_E (x_mode, sizeflag); + else if (floatop == 0xdd) + OP_E (d_mode, sizeflag); + else + OP_E (v_mode, sizeflag); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm], sizeflag); + + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf && codep[-1] == 0xe0) + strcpy (op1out, names16[0]); + } + else + { + putop (dp->name, sizeflag); + + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1, sizeflag); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2, sizeflag); + } +} + +/* ARGSUSED */ +static void +OP_ST (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + oappend ("%st"); +} + +/* ARGSUSED */ +static void +OP_STi (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); +} + + +/* capital letters in template are macros */ +static void +putop (template, sizeflag) + const char *template; + int sizeflag; +{ + const char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'A': + if (intel_syntax) + break; + if (mod != 3 +#ifdef SUFFIX_ALWAYS + || (sizeflag & SUFFIX_ALWAYS) +#endif + ) + *obufp++ = 'b'; + break; + case 'B': + if (intel_syntax) + break; +#ifdef SUFFIX_ALWAYS + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'b'; +#endif + break; + case 'E': /* For jcxz/jecxz */ + if (sizeflag & AFLAG) + *obufp++ = 'e'; + break; + case 'L': + if (intel_syntax) + break; +#ifdef SUFFIX_ALWAYS + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'l'; +#endif + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + else + used_prefixes |= PREFIX_FWAIT; + break; + case 'P': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) +#ifdef SUFFIX_ALWAYS + || (sizeflag & SUFFIX_ALWAYS) +#endif + ) + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'Q': + if (intel_syntax) + break; + if (mod != 3 +#ifdef SUFFIX_ALWAYS + || (sizeflag & SUFFIX_ALWAYS) +#endif + ) + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'R': + if (intel_syntax) + { + if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'q'; + } + else + { + *obufp++ = 'w'; + *obufp++ = 'd'; + } + } + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'S': + if (intel_syntax) + break; +#ifdef SUFFIX_ALWAYS + if (sizeflag & SUFFIX_ALWAYS) + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } +#endif + break; + case 'W': + /* operand size flag for cwtl, cbtw */ + if (sizeflag & DFLAG) + *obufp++ = 'w'; + else + *obufp++ = 'b'; + if (intel_syntax) + { + if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'e'; + } + else + { + *obufp++ = 'w'; + } + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + } + *obufp = 0; +} + +static void +oappend (s) + const char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); +} + +static void +append_seg () +{ + if (prefixes & PREFIX_CS) + { + oappend ("%cs:"); + used_prefixes |= PREFIX_CS; + } + if (prefixes & PREFIX_DS) + { + oappend ("%ds:"); + used_prefixes |= PREFIX_DS; + } + if (prefixes & PREFIX_SS) + { + oappend ("%ss:"); + used_prefixes |= PREFIX_SS; + } + if (prefixes & PREFIX_ES) + { + oappend ("%es:"); + used_prefixes |= PREFIX_ES; + } + if (prefixes & PREFIX_FS) + { + oappend ("%fs:"); + used_prefixes |= PREFIX_FS; + } + if (prefixes & PREFIX_GS) + { + oappend ("%gs:"); + used_prefixes |= PREFIX_GS; + } +} + +static void +OP_indirE (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (!intel_syntax) + oappend ("*"); + OP_E (bytemode, sizeflag); +} + +static void +OP_E (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int disp; + + /* skip mod/rm byte */ + codep++; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case d_mode: + oappend (names32[rm]); + break; + case v_mode: + if (sizeflag & DFLAG) + oappend (names32[rm]); + else + oappend (names16[rm]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 0: + if ( !(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */)) + BadOp(); /* bad sfence,lea,lds,les,lfs,lgs,lss modrm */ + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + return; + } + + disp = 0; + append_seg (); + + if (sizeflag & AFLAG) /* 32 bit address mode */ + { + int havesib; + int havebase; + int base; + int index = 0; + int scale = 0; + + havesib = 0; + havebase = 1; + base = rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + if (base == 5) + { + havebase = 0; + disp = get32 (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get32 (); + break; + } + + if (!intel_syntax) + if (mod != 0 || base == 5) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (havebase || (havesib && (index != 4 || scale != 0))) + { + if (intel_syntax) + { + switch (bytemode) + { + case b_mode: + oappend("BYTE PTR "); + break; + case w_mode: + oappend("WORD PTR "); + break; + case v_mode: + oappend("DWORD PTR "); + break; + case d_mode: + oappend("QWORD PTR "); + break; + case x_mode: + oappend("XWORD PTR "); + break; + default: + break; + } + } + *obufp++ = open_char; + *obufp = '\0'; + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + if (intel_syntax) + { + if (havebase) + { + *obufp++ = separator_char; + *obufp = '\0'; + } + sprintf (scratchbuf, "%s", names32[index]); + } + else + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + if (!intel_syntax + || (intel_syntax + && bytemode != b_mode + && bytemode != w_mode + && bytemode != v_mode)) + { + *obufp++ = scale_char; + *obufp = '\0'; + sprintf (scratchbuf, "%d", 1 << scale); + oappend (scratchbuf); + } + } + if (intel_syntax) + if (mod != 0 || base == 5) + { + /* Don't print zero displacements */ + if (disp > 0) + { + sprintf (scratchbuf, "+%d", disp); + oappend (scratchbuf); + } + else if (disp < 0) + { + sprintf (scratchbuf, "%d", disp); + oappend (scratchbuf); + } + } + + *obufp++ = close_char; + *obufp = '\0'; + } + else if (intel_syntax) + { + if (mod != 0 || base == 5) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[3]); + oappend (":"); + } + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + } + } + else + { /* 16 bit address mode */ + switch (mod) + { + case 0: + if (rm == 6) + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + break; + } + + if (!intel_syntax) + if (mod != 0 || rm == 6) + { + sprintf (scratchbuf, "%d", disp); + oappend (scratchbuf); + } + + if (mod != 0 || rm != 6) + { + *obufp++ = open_char; + *obufp = '\0'; + oappend (index16[rm]); + *obufp++ = close_char; + *obufp = '\0'; + } + } +} + +static void +OP_G (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (sizeflag & DFLAG) + oappend (names32[reg]); + else + oappend (names16[reg]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } +} + +static int +get32 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return x; +} + +static int +get16 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return x; +} + +static void +set_op (op) + unsigned int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +static void +OP_REG (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + + switch (code) + { + case indir_dx_reg: + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (sizeflag & DFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_I (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++ & 0xff; + break; + case v_mode: + if (sizeflag & DFLAG) + op = get32 (); + else + op = get16 (); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + if (intel_syntax) + sprintf (scratchbuf, "0x%x", op); + else + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + scratchbuf[0] = '\0'; +} + +static void +OP_sI (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + if ((op & 0x80) != 0) + op -= 0x100; + break; + case v_mode: + if (sizeflag & DFLAG) + op = get32 (); + else + { + op = get16(); + if ((op & 0x8000) != 0) + op -= 0x10000; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + op = get16 (); + if ((op & 0x8000) != 0) + op -= 0x10000; + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + if (intel_syntax) + sprintf (scratchbuf, "%d", op); + else + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +static void +OP_J (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case v_mode: + if (sizeflag & DFLAG) + disp = get32 (); + else + { + disp = get16 (); + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_SEG (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); +} + +/* ARGSUSED */ +static void +OP_DIR (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag; +{ + int seg, offset; + + if (sizeflag & DFLAG) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + used_prefixes |= (prefixes & PREFIX_DATA); + sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_OFF (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag; +{ + int off; + + append_seg (); + + if (sizeflag & AFLAG) + off = get32 (); + else + off = get16 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[3]); + oappend (":"); + } + } + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); +} + +static void +ptr_reg (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + oappend ("("); + if (sizeflag & AFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + oappend (s); + oappend (")"); +} + +static void +OP_ESreg (code, sizeflag) + int code; + int sizeflag; +{ + oappend ("%es:"); + ptr_reg (code, sizeflag); +} + +static void +OP_DSreg (code, sizeflag) + int code; + int sizeflag; +{ + if ((prefixes + & (PREFIX_CS + | PREFIX_DS + | PREFIX_SS + | PREFIX_ES + | PREFIX_FS + | PREFIX_GS)) == 0) + prefixes |= PREFIX_DS; + append_seg(); + ptr_reg (code, sizeflag); +} + +/* ARGSUSED */ +static void +OP_C (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_D (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_T (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); +} + +static void +OP_Rd (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_E (bytemode, sizeflag); + else + BadOp(); +} + +static void +OP_MMX (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%mm%d", reg); + oappend (scratchbuf); +} + +static void +OP_XMM (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%xmm%d", reg); + oappend (scratchbuf); +} + +static void +OP_EM (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + + codep++; + sprintf (scratchbuf, "%%mm%d", rm); + oappend (scratchbuf); +} + +static void +OP_EX (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + + codep++; + sprintf (scratchbuf, "%%xmm%d", rm); + oappend (scratchbuf); +} + +static void +OP_MS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EM (bytemode, sizeflag); + else + BadOp(); +} + +static const char *Suffix3DNow[] = { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ "pi2fw", "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ "pf2iw", "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, "pfnacc", NULL, +/* 8C */ NULL, NULL, "pfpnacc", NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", +/* B8 */ NULL, NULL, NULL, "pswapd", +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static void +OP_3DNowSuffix (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + const char *mnemonic; + + FETCH_DATA (the_info, codep + 1); + /* AMD 3DNow! instructions are specified by an opcode suffix in the + place where an 8-bit immediate would normally go. ie. the last + byte of the instruction. */ + obufp = obuf + strlen(obuf); + mnemonic = Suffix3DNow[*codep++ & 0xff]; + if (mnemonic) + oappend (mnemonic); + else + { + /* Since a variable sized modrm/sib chunk is between the start + of the opcode (0x0f0f) and the opcode suffix, we need to do + all the modrm processing first, and don't know until now that + we have a bad opcode. This necessitates some cleaning up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp(); + } +} + + +static const char *simd_cmp_op [] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; + +static void +OP_SIMD_Suffix (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + unsigned int cmp_type; + + FETCH_DATA (the_info, codep + 1); + obufp = obuf + strlen(obuf); + cmp_type = *codep++ & 0xff; + if (cmp_type < 8) + { + sprintf (scratchbuf, "cmp%s%cs", + simd_cmp_op[cmp_type], + prefixes & PREFIX_REPZ ? 's' : 'p'); + used_prefixes |= (prefixes & PREFIX_REPZ); + oappend (scratchbuf); + } + else + { + /* We have a bad extension byte. Clean up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp(); + } +} + +static void +SIMD_Fixup (extrachar, sizeflag) + int extrachar; + int sizeflag ATTRIBUTE_UNUSED; +{ + /* Change movlps/movhps to movhlps/movlhps for 2 register operand + forms of these instructions. */ + if (mod == 3) + { + char *p = obuf + strlen(obuf); + *(p+1) = '\0'; + *p = *(p-1); + *(p-1) = *(p-2); + *(p-2) = *(p-3); + *(p-3) = extrachar; + } +} + +static void BadOp (void) +{ + codep = insn_codep + 1; /* throw away prefixes and 1st. opcode byte */ + oappend ("(bad)"); +} diff -Nur linux-2.4.19/arch/i386/kdb/kdba_bp.c linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_bp.c --- linux-2.4.19/arch/i386/kdb/kdba_bp.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_bp.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,804 @@ +/* + * Kernel Debugger Architecture Dependent Breakpoint Handling + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include + + +static char *kdba_rwtypes[] = { "Instruction(Register)", "Data Write", + "I/O", "Data Access"}; + +/* + * Table describing processor architecture hardware + * breakpoint registers. + */ + +kdbhard_bp_t kdb_hardbreaks[KDB_MAXHARDBPT]; + +/* + * kdba_db_trap + * + * Perform breakpoint processing upon entry to the + * processor debugger fault. Determine and print + * the active breakpoint. + * + * Parameters: + * regs Exception frame containing machine register state + * error Error number passed to kdb. + * Outputs: + * None. + * Returns: + * KDB_DB_BPT Standard instruction or data breakpoint encountered + * KDB_DB_SS Single Step fault ('ss' command or end of 'ssb' command) + * KDB_DB_SSB Single Step fault, caller should continue ('ssb' command) + * KDB_DB_SSBPT Single step over breakpoint + * KDB_DB_NOBPT No existing kdb breakpoint matches this debug exception + * Locking: + * None. + * Remarks: + * Yup, there be goto's here. + * + * If multiple processors receive debug exceptions simultaneously, + * one may be waiting at the kdb fence in kdb() while the user + * issues a 'bc' command to clear the breakpoint the processor + * which is waiting has already encountered. If this is the case, + * the debug registers will no longer match any entry in the + * breakpoint table, and we'll return the value KDB_DB_NOBPT. + * This can cause a panic in die_if_kernel(). It is safer to + * disable the breakpoint (bd), go until all processors are past + * the breakpoint then clear the breakpoint (bc). This code + * recognises a breakpoint even when disabled but not when it has + * been cleared. + * + * WARNING: This routine clears the debug state. It should be called + * once per debug and the result cached. + */ + +kdb_dbtrap_t +kdba_db_trap(struct pt_regs *regs, int error_unused) +{ + kdb_machreg_t dr6; + kdb_machreg_t dr7; + int rw, reg; + int i; + kdb_dbtrap_t rv = KDB_DB_BPT; + kdb_bp_t *bp; + + if (KDB_NULL_REGS(regs)) + return KDB_DB_NOBPT; + + dr6 = kdba_getdr6(); + dr7 = kdba_getdr7(); + + if (KDB_DEBUG(BP)) + kdb_printf("kdb: dr6 0x%lx dr7 0x%lx\n", dr6, dr7); + if (dr6 & DR6_BS) { + if (KDB_STATE(SSBPT)) { + if (KDB_DEBUG(BP)) + kdb_printf("ssbpt\n"); + KDB_STATE_CLEAR(SSBPT); + for(i=0,bp=kdb_breakpoints; + i < KDB_MAXBPT; + i++, bp++) { + if (KDB_DEBUG(BP)) + kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n", + bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu); + if (!bp->bp_enabled) + continue; + if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) + continue; + if (KDB_DEBUG(BP)) + kdb_printf("bp for this cpu\n"); + if (bp->bp_delayed) { + bp->bp_delayed = 0; + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp\n"); + kdba_installbp(regs, bp); + if (!KDB_STATE(DOING_SS)) { + regs->eflags &= ~EF_TF; + return(KDB_DB_SSBPT); + } + break; + } + } + if (i == KDB_MAXBPT) { + kdb_printf("kdb: Unable to find delayed breakpoint\n"); + } + if (!KDB_STATE(DOING_SS)) { + regs->eflags &= ~EF_TF; + return(KDB_DB_NOBPT); + } + /* FALLTHROUGH */ + } + + /* + * KDB_STATE_DOING_SS is set when the kernel debugger is using + * the processor trap flag to single-step a processor. If a + * single step trap occurs and this flag is clear, the SS trap + * will be ignored by KDB and the kernel will be allowed to deal + * with it as necessary (e.g. for ptrace). + */ + if (!KDB_STATE(DOING_SS)) + goto unknown; + + /* single step */ + rv = KDB_DB_SS; /* Indicate single step */ + if (KDB_STATE(DOING_SSB)) { + unsigned char instruction[2]; + + kdb_id1(regs->eip); + if (kdb_getarea(instruction, regs->eip) || + (instruction[0]&0xf0) == 0xe0 || /* short disp jumps */ + (instruction[0]&0xf0) == 0x70 || /* Misc. jumps */ + instruction[0] == 0xc2 || /* ret */ + instruction[0] == 0x9a || /* call */ + (instruction[0]&0xf8) == 0xc8 || /* enter, leave, iret, int, */ + ((instruction[0] == 0x0f) && + ((instruction[1]&0xf0)== 0x80)) + ) { + /* + * End the ssb command here. + */ + KDB_STATE_CLEAR(DOING_SSB); + KDB_STATE_CLEAR(DOING_SS); + } else { + rv = KDB_DB_SSB; /* Indicate ssb - dismiss immediately */ + } + } else { + /* + * Print current insn + */ + kdb_printf("SS trap at "); + kdb_symbol_print(regs->eip, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE); + kdb_id1(regs->eip); + KDB_STATE_CLEAR(DOING_SS); + } + + if (rv != KDB_DB_SSB) + regs->eflags &= ~EF_TF; + } + + if (dr6 & DR6_B0) { + rw = DR7_RW0(dr7); + reg = 0; + goto handle; + } + + if (dr6 & DR6_B1) { + rw = DR7_RW1(dr7); + reg = 1; + goto handle; + } + + if (dr6 & DR6_B2) { + rw = DR7_RW2(dr7); + reg = 2; + goto handle; + } + + if (dr6 & DR6_B3) { + rw = DR7_RW3(dr7); + reg = 3; + goto handle; + } + + if (rv > 0) + goto handled; + + goto unknown; /* dismiss */ + +handle: + /* + * Set Resume Flag + */ + regs->eflags |= EF_RF; + + /* + * Determine which breakpoint was encountered. + */ + for(i=0, bp=kdb_breakpoints; ibp_free) + && (bp->bp_global || bp->bp_cpu == smp_processor_id()) + && (bp->bp_hard) + && (bp->bp_hard->bph_reg == reg)) { + /* + * Hit this breakpoint. + */ + kdb_printf("%s breakpoint #%d at " kdb_bfd_vma_fmt "\n", + kdba_rwtypes[rw], + i, bp->bp_addr); + + /* + * For an instruction breakpoint, disassemble + * the current instruction. + */ + if (rw == 0) { + kdb_id1(regs->eip); + } + + goto handled; + } + } + +unknown: + regs->eflags |= EF_RF; /* Supress further faults */ + rv = KDB_DB_NOBPT; /* Cause kdb() to return */ + +handled: + + /* + * Clear the pending exceptions. + */ + kdba_putdr6(0); + + return rv; +} + +/* + * kdba_bp_trap + * + * Perform breakpoint processing upon entry to the + * processor breakpoint instruction fault. Determine and print + * the active breakpoint. + * + * Parameters: + * regs Exception frame containing machine register state + * error Error number passed to kdb. + * Outputs: + * None. + * Returns: + * 0 Standard instruction or data breakpoint encountered + * 1 Single Step fault ('ss' command) + * 2 Single Step fault, caller should continue ('ssb' command) + * 3 No existing kdb breakpoint matches this debug exception + * Locking: + * None. + * Remarks: + * + * If multiple processors receive debug exceptions simultaneously, + * one may be waiting at the kdb fence in kdb() while the user + * issues a 'bc' command to clear the breakpoint the processor which + * is waiting has already encountered. If this is the case, the + * debug registers will no longer match any entry in the breakpoint + * table, and we'll return the value '3'. This can cause a panic + * in die_if_kernel(). It is safer to disable the breakpoint (bd), + * 'go' until all processors are past the breakpoint then clear the + * breakpoint (bc). This code recognises a breakpoint even when + * disabled but not when it has been cleared. + * + * WARNING: This routine resets the eip. It should be called + * once per breakpoint and the result cached. + */ + +kdb_dbtrap_t +kdba_bp_trap(struct pt_regs *regs, int error_unused) +{ + int i; + kdb_dbtrap_t rv; + kdb_bp_t *bp; + + if (KDB_NULL_REGS(regs)) + return KDB_DB_NOBPT; + + /* + * Determine which breakpoint was encountered. + */ + if (KDB_DEBUG(BP)) + kdb_printf("kdba_bp_trap: eip=0x%lx (not adjusted) " + "eflags=0x%lx regs=0x%p esp=0x%lx\n", + regs->eip, regs->eflags, regs, regs->esp); + + rv = KDB_DB_NOBPT; /* Cause kdb() to return */ + + for(i=0, bp=kdb_breakpoints; ibp_free) + continue; + if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) + continue; + if ((void *)bp->bp_addr == (void *)(regs->eip - bp->bp_adjust)) { + /* Hit this breakpoint. */ + regs->eip -= bp->bp_adjust; + kdb_printf("Instruction(i) breakpoint #%d at 0x%lx (adjusted)\n", + i, regs->eip); + kdb_id1(regs->eip); + rv = KDB_DB_BPT; + bp->bp_delay = 1; + /* SSBPT is set when the kernel debugger must single + * step a task in order to re-establish an instruction + * breakpoint which uses the instruction replacement + * mechanism. It is cleared by any action that removes + * the need to single-step the breakpoint. + */ + KDB_STATE_SET(SSBPT); + break; + } + } + + return rv; +} + +/* + * kdba_handle_bp + * + * Handle an instruction-breakpoint trap. Called when re-installing + * an enabled breakpoint which has has the bp_delay bit set. + * + * Parameters: + * Returns: + * Locking: + * Remarks: + * + * Ok, we really need to: + * 1) Restore the original instruction byte + * 2) Single Step + * 3) Restore breakpoint instruction + * 4) Continue. + * + * + */ + +static void +kdba_handle_bp(struct pt_regs *regs, kdb_bp_t *bp) +{ + if (KDB_NULL_REGS(regs)) + return; + + if (KDB_DEBUG(BP)) + kdb_printf("regs->eip = 0x%lx\n", regs->eip); + + /* + * Setup single step + */ + kdba_setsinglestep(regs); + + /* + * Reset delay attribute + */ + bp->bp_delay = 0; + bp->bp_delayed = 1; +} + + +/* + * kdba_bptype + * + * Return a string describing type of breakpoint. + * + * Parameters: + * bph Pointer to hardware breakpoint description + * Outputs: + * None. + * Returns: + * Character string. + * Locking: + * None. + * Remarks: + */ + +char * +kdba_bptype(kdbhard_bp_t *bph) +{ + char *mode; + + mode = kdba_rwtypes[bph->bph_mode]; + + return mode; +} + +/* + * kdba_printbpreg + * + * Print register name assigned to breakpoint + * + * Parameters: + * bph Pointer hardware breakpoint structure + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdba_printbpreg(kdbhard_bp_t *bph) +{ + kdb_printf(" in dr%ld", bph->bph_reg); +} + +/* + * kdba_printbp + * + * Print string describing hardware breakpoint. + * + * Parameters: + * bph Pointer to hardware breakpoint description + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdba_printbp(kdb_bp_t *bp) +{ + kdb_printf("\n is enabled"); + if (bp->bp_hardtype) { + kdba_printbpreg(bp->bp_hard); + if (bp->bp_hard->bph_mode != 0) { + kdb_printf(" for %d bytes", + bp->bp_hard->bph_length+1); + } + } +} + +/* + * kdba_parsebp + * + * Parse architecture dependent portion of the + * breakpoint command. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + * for Ia32 architure, data access, data write and + * I/O breakpoints are supported in addition to instruction + * breakpoints. + * + * {datar|dataw|io|inst} [length] + */ + +int +kdba_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp) +{ + int nextarg = *nextargp; + int diag; + kdbhard_bp_t *bph = &bp->bp_template; + + bph->bph_mode = 0; /* Default to instruction breakpoint */ + bph->bph_length = 0; /* Length must be zero for insn bp */ + if ((argc + 1) != nextarg) { + if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) { + bph->bph_mode = 3; + } else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) { + bph->bph_mode = 1; + } else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) { + bph->bph_mode = 2; + } else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0) { + bph->bph_mode = 0; + } else { + return KDB_ARGCOUNT; + } + + bph->bph_length = 3; /* Default to 4 byte */ + + nextarg++; + + if ((argc + 1) != nextarg) { + unsigned long len; + + diag = kdbgetularg((char *)argv[nextarg], + &len); + if (diag) + return diag; + + + if ((len > 4) || (len == 3)) + return KDB_BADLENGTH; + + bph->bph_length = len; + bph->bph_length--; /* Normalize for debug register */ + nextarg++; + } + + if ((argc + 1) != nextarg) + return KDB_ARGCOUNT; + + /* + * Indicate to architecture independent level that + * a hardware register assignment is required to enable + * this breakpoint. + */ + + bph->bph_free = 0; + } else { + if (KDB_DEBUG(BP)) + kdb_printf("kdba_bp: no args, forcehw is %d\n", bp->bp_forcehw); + if (bp->bp_forcehw) { + /* + * We are forced to use a hardware register for this + * breakpoint because either the bph or bpha + * commands were used to establish this breakpoint. + */ + bph->bph_free = 0; + } else { + /* + * Indicate to architecture dependent level that + * the instruction replacement breakpoint technique + * should be used for this breakpoint. + */ + bph->bph_free = 1; + bp->bp_adjust = 1; /* software, int 3 is one byte */ + } + } + + if (bph->bph_mode != 2 && kdba_verify_rw(bp->bp_addr, bph->bph_length+1)) { + kdb_printf("Invalid address for breakpoint, ignoring bp command\n"); + return KDB_BADADDR; + } + + *nextargp = nextarg; + return 0; +} + +/* + * kdba_allocbp + * + * Associate a hardware register with a breakpoint. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * A pointer to the allocated register kdbhard_bp_t structure for + * success, Null and a non-zero diagnostic for failure. + * Locking: + * None. + * Remarks: + */ + +kdbhard_bp_t * +kdba_allocbp(kdbhard_bp_t *bph, int *diagp) +{ + int i; + kdbhard_bp_t *newbph; + + for(i=0,newbph=kdb_hardbreaks; i < KDB_MAXHARDBPT; i++, newbph++) { + if (newbph->bph_free) { + break; + } + } + + if (i == KDB_MAXHARDBPT) { + *diagp = KDB_TOOMANYDBREGS; + return NULL; + } + + *diagp = 0; + + /* + * Copy data from template. Can't just copy the entire template + * here because the register number in kdb_hardbreaks must be + * preserved. + */ + newbph->bph_data = bph->bph_data; + newbph->bph_write = bph->bph_write; + newbph->bph_mode = bph->bph_mode; + newbph->bph_length = bph->bph_length; + + /* + * Mark entry allocated. + */ + newbph->bph_free = 0; + + return newbph; +} + +/* + * kdba_freebp + * + * Deallocate a hardware breakpoint + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + */ + +void +kdba_freebp(kdbhard_bp_t *bph) +{ + bph->bph_free = 1; +} + +/* + * kdba_initbp + * + * Initialize the breakpoint table for the hardware breakpoint + * register. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + * + * There is one entry per register. On the ia32 architecture + * all the registers are interchangeable, so no special allocation + * criteria are required. + */ + +void +kdba_initbp(void) +{ + int i; + kdbhard_bp_t *bph; + + /* + * Clear the hardware breakpoint table + */ + + memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks)); + + for(i=0,bph=kdb_hardbreaks; ibph_reg = i; + bph->bph_free = 1; + } +} + +/* + * kdba_installbp + * + * Install a breakpoint + * + * Parameters: + * regs Exception frame + * bp Breakpoint structure for the breakpoint to be installed + * Outputs: + * None. + * Returns: + * 0 if breakpoint installed. + * Locking: + * None. + * Remarks: + * For hardware breakpoints, a debug register is allocated + * and assigned to the breakpoint. If no debug register is + * available, a warning message is printed and the breakpoint + * is disabled. + * + * For instruction replacement breakpoints, we must single-step + * over the replaced instruction at this point so we can re-install + * the breakpoint instruction after the single-step. SSBPT is set + * when the breakpoint is initially hit and is cleared by any action + * that removes the need for single-step over the breakpoint. + */ + +int +kdba_installbp(struct pt_regs *regs, kdb_bp_t *bp) +{ + /* + * Install the breakpoint, if it is not already installed. + */ + + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_installbp bp_installed %d\n", bp->bp_installed); + } + if (!KDB_STATE(SSBPT)) + bp->bp_delay = 0; + if (!bp->bp_installed) { + if (bp->bp_hardtype) { + kdba_installdbreg(bp); + bp->bp_installed = 1; + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt "\n", + bp->bp_hard->bph_reg, bp->bp_addr); + } + } else if (bp->bp_delay) { + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp delayed bp\n"); + kdba_handle_bp(regs, bp); + } else { + if (kdb_getarea_size(&(bp->bp_inst), bp->bp_addr, 1) || + kdb_putword(bp->bp_addr, IA32_BREAKPOINT_INSTRUCTION, 1)) { + kdb_printf("kdba_installbp failed to set software breakpoint at 0x%lx\n", bp->bp_addr); + return(1); + } + bp->bp_installed = 1; + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp instruction 0x%x at " kdb_bfd_vma_fmt "\n", + IA32_BREAKPOINT_INSTRUCTION, bp->bp_addr); + } + } + return(0); +} + +/* + * kdba_removebp + * + * Make a breakpoint ineffective. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +int +kdba_removebp(kdb_bp_t *bp) +{ + /* + * For hardware breakpoints, remove it from the active register, + * for software breakpoints, restore the instruction stream. + */ + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed); + } + if (bp->bp_installed) { + if (bp->bp_hardtype) { + if (KDB_DEBUG(BP)) { + kdb_printf("kdb: removing hardware reg %ld at " kdb_bfd_vma_fmt "\n", + bp->bp_hard->bph_reg, bp->bp_addr); + } + kdba_removedbreg(bp); + } else { + if (KDB_DEBUG(BP)) + kdb_printf("kdb: restoring instruction 0x%x at " kdb_bfd_vma_fmt "\n", + bp->bp_inst, bp->bp_addr); + if (kdb_putword(bp->bp_addr, bp->bp_inst, 1)) + return(1); + } + bp->bp_installed = 0; + } + return(0); +} diff -Nur linux-2.4.19/arch/i386/kdb/kdba_bt.c linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_bt.c --- linux-2.4.19/arch/i386/kdb/kdba_bt.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_bt.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,366 @@ +/* + * Kernel Debugger Architecture Dependent Stack Traceback + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_FRAME_POINTER +#define EFPSTR "EBP" +#define EFP ebp +#define NOBP 0 +#else +#define EFPSTR "ESP" +#define EFP esp +#define NOBP esp +#endif + +/* + * bt_print_one + * + * Print one back trace entry. + * + * Inputs: + * eip Current program counter, or return address. + * efp #ifdef CONFIG_FRAME_POINTER: Previous frame pointer ebp, + * 0 if not valid; #else: Stack pointer esp when at eip. + * ar Activation record for this frame. + * symtab Information about symbol that eip falls within. + * argcount Maximum number of arguments to print. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +static void +bt_print_one(kdb_machreg_t eip, kdb_machreg_t efp, const kdb_ar_t *ar, + const kdb_symtab_t *symtab, int argcount) +{ + int btsymarg = 0; + int nosect = 0; + kdb_machreg_t word; + + kdbgetintenv("BTSYMARG", &btsymarg); + kdbgetintenv("NOSECT", &nosect); + + if (efp) + kdb_printf("0x%08lx", efp); + else + kdb_printf(" "); + kdb_symbol_print(eip, symtab, KDB_SP_SPACEB|KDB_SP_VALUE); + if (argcount && ar->args) { + int i, argc = ar->args / 4; + + kdb_printf(" ("); + if (argc > argcount) + argc = argcount; + + for(i=1; i<=argc; i++){ + kdb_machreg_t argp = ar->arg0 - ar->args + 4*i; + + if (i != 1) + kdb_printf(", "); + kdb_getword(&word, argp, sizeof(word)); + kdb_printf("0x%lx", word); + } + kdb_printf(")"); + } + if (symtab->sym_name) { + if (!nosect) { + kdb_printf("\n"); + kdb_printf(" %s %s 0x%lx 0x%lx 0x%lx", + symtab->mod_name, + symtab->sec_name, + symtab->sec_start, + symtab->sym_start, + symtab->sym_end); + } + } + kdb_printf("\n"); + if (argcount && ar->args && btsymarg) { + int i, argc = ar->args / 4; + kdb_symtab_t arg_symtab; + kdb_machreg_t arg; + for(i=1; i<=argc; i++){ + kdb_machreg_t argp = ar->arg0 - ar->args + 4*i; + kdb_getword(&arg, argp, sizeof(arg)); + if (kdbnearsym(arg, &arg_symtab)) { + kdb_printf(" "); + kdb_symbol_print(arg, &arg_symtab, KDB_SP_DEFAULT|KDB_SP_NEWLINE); + } + } + } +} + +/* + * kdba_bt_stack_i386 + * + * kdba_bt_stack with i386 specific parameters. + * Specification as kdba_bt_stack plus :- + * + * Inputs: + * As kba_bt_stack plus + * regs_esp If 1 get esp from the registers (exception frame), if 0 + * get esp from kdba_getregcontents. + */ + +static int +kdba_bt_stack_i386(struct pt_regs *regs, kdb_machreg_t *addr, int argcount, + struct task_struct *p, int regs_esp) +{ + kdb_ar_t ar; + kdb_machreg_t eip, esp, ebp, ss, cs; + kdb_symtab_t symtab; + + /* + * The caller may have supplied an address at which the + * stack traceback operation should begin. This address + * is assumed by this code to point to a return-address + * on the stack to be traced back. + * + * The end result of this will make it appear as if a function + * entitled '' was called from the function which + * contains return-address. + */ + if (addr) { + eip = 0; + ebp = 0; + esp = *addr; + cs = __KERNEL_CS; /* have to assume kernel space */ + } else { + if (KDB_NULL_REGS(regs)) + return KDB_BADREG; + eip = regs->eip; + ebp = regs->ebp; + if (regs_esp) + esp = regs->esp; + else + kdba_getregcontents("esp", regs, &esp); + kdba_getregcontents("xcs", regs, &cs); + } + ss = esp & -THREAD_SIZE; + + if ((cs & 0xffff) != __KERNEL_CS) { + kdb_printf("Stack is not in kernel space, backtrace not available\n"); + return 0; + } + + kdb_printf(EFPSTR " EIP Function (args)\n"); + + /* + * Run through the activation records and print them. + */ + + while (1) { + kdb_ar_t save_ar = ar; + kdbnearsym(eip, &symtab); + if (!kdb_get_next_ar(esp, symtab.sym_start, eip, ebp, ss, + &ar, &symtab)) { + break; + } + + if (strncmp(".text.lock.", symtab.sym_name, 11) == 0) { + /* + * Instructions in the .text.lock area are generated by + * the out of line code in lock handling, see + * include/asm-i386 semaphore.h and rwlock.h. There can + * be multiple instructions which eventually end with a + * jump back to the mainline code. Use the disassmebler + * to silently step through the code until we find the + * jump, resolve its destination and translate it to a + * symbol. Replace '.text.lock' with the symbol. + */ + unsigned char inst; + kdb_machreg_t offset = 0, realeip = eip; + int length, offsize = 0; + kdb_symtab_t lock_symtab; + /* Dummy out the disassembler print function */ + fprintf_ftype save_fprintf_func = kdb_di.fprintf_func; + + kdb_di.fprintf_func = &kdb_dis_fprintf_dummy; + while((length = kdba_id_printinsn(realeip, &kdb_di)) > 0) { + kdb_getarea(inst, realeip); + offsize = 0; + switch (inst) { + case 0xeb: /* jmp with 1 byte offset */ + offsize = 1-4; + /* drop through */ + case 0xe9: /* jmp with 4 byte offset */ + offsize += 4; + kdb_getword(&offset, realeip+1, offsize); + break; + default: + realeip += length; /* next instruction */ + break; + } + if (offsize) + break; + } + kdb_di.fprintf_func = save_fprintf_func; + + if (offsize) { + realeip += 1 + offsize + offset; + if (kdbnearsym(realeip, &lock_symtab)) { + /* Print the stext entry without args */ + bt_print_one(eip, NOBP, &ar, &symtab, 0); + /* Point to mainline code */ + eip = realeip; + ar = save_ar; /* lock text does not consume an activation frame */ + continue; + } + } + } + + if (strcmp("ret_from_intr", symtab.sym_name) == 0 || + strcmp("error_code", symtab.sym_name) == 0) { + if (strcmp("ret_from_intr", symtab.sym_name) == 0) { + /* + * Non-standard frame. ret_from_intr is + * preceded by 9 registers (ebx, ecx, edx, esi, + * edi, ebp, eax, ds, cs), original eax and the + * return address for a total of 11 words. + */ + ar.start = ar.end + 11*4; + } + if (strcmp("error_code", symtab.sym_name) == 0) { + /* + * Non-standard frame. error_code is preceded + * by two parameters (-> registers, error code), + * 9 registers (ebx, ecx, edx, esi, edi, ebp, + * eax, ds, cs), original eax and the return + * address for a total of 13 words. + */ + ar.start = ar.end + 13*4; + } + /* Print the non-standard entry without args */ + bt_print_one(eip, NOBP, &ar, &symtab, 0); + kdb_printf("Interrupt registers:\n"); + kdba_dumpregs((struct pt_regs *)(ar.end), NULL, NULL); + /* Step the frame to the interrupted code */ + kdb_getword(&eip, ar.start-4, 4); + ebp = 0; + esp = ar.start; + if ((((struct pt_regs *)(ar.end))->xcs & 0xffff) != __KERNEL_CS) { + kdb_printf("Interrupt from user space, end of kernel trace\n"); + break; + } + continue; + } + + bt_print_one(eip, EFP, &ar, &symtab, argcount); + + if (ar.ret == 0) + break; /* End of frames */ + eip = ar.ret; + ebp = ar.oldfp; + esp = ar.start; + } + + return 0; +} + +/* + * kdba_bt_stack + * + * This function implements the 'bt' command. Print a stack + * traceback. + * + * bt [] (addr-exp is for alternate stacks) + * btp (Kernel stack for ) + * + * address expression refers to a return address on the stack. It + * may be preceeded by a frame pointer. + * + * Inputs: + * regs registers at time kdb was entered. + * addr Pointer to Address provided to 'bt' command, if any. + * argcount + * p Pointer to task for 'btp' command. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * mds comes in handy when examining the stack to do a manual + * traceback. + */ + +int +kdba_bt_stack(struct pt_regs *regs, kdb_machreg_t *addr, int argcount, + struct task_struct *p) +{ + return(kdba_bt_stack_i386(regs, addr, argcount, p, 0)); +} + +int +kdba_bt_process(struct task_struct *p, int argcount) +{ + struct pt_regs taskregs; + + memset(&taskregs, 0, sizeof(taskregs)); + taskregs.eip = p->thread.eip; + taskregs.esp = p->thread.esp; + + /* + * Since we don't really use the TSS + * to store register between task switches, + * attempt to locate real ebp (should be + * top of stack if task is in schedule) + */ + taskregs.ebp = *(kdb_machreg_t *)(taskregs.esp); + + taskregs.xcs = __KERNEL_CS; /* have to assume kernel space */ + + if (taskregs.esp < (unsigned long)p || + taskregs.esp >= (unsigned long)p + THREAD_SIZE) { + kdb_printf("Stack is not in task_struct, backtrace not available\n"); + return(0); + } + + return kdba_bt_stack_i386(&taskregs, NULL, argcount, p, 1); + +} diff -Nur linux-2.4.19/arch/i386/kdb/kdba_id.c linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_id.c --- linux-2.4.19/arch/i386/kdb/kdba_id.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_id.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,279 @@ +/* + * Kernel Debugger Architecture Dependent Instruction Disassembly + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * kdba_dis_getsym + * + * Get a symbol for the disassembler. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * Not used for kdb. + */ + +/* ARGSUSED */ +static int +kdba_dis_getsym(bfd_vma addr, disassemble_info *dip) +{ + + return 0; +} + +/* + * kdba_printaddress + * + * Print (symbolically) an address. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * flag True if a ":" sequence should follow the address + * Returns: + * 0 + * Locking: + * Remarks: + * + */ + +/* ARGSUSED */ +void +kdba_printaddress(kdb_machreg_t addr, disassemble_info *dip, int flag) +{ + kdb_symtab_t symtab; + int spaces = 5; + unsigned int offset; + + /* + * Print a symbol name or address as necessary. + */ + kdbnearsym(addr, &symtab); + if (symtab.sym_name) { + /* Do not use kdb_symbol_print here, it always does + * kdb_printf but we want dip->fprintf_func. + */ + dip->fprintf_func(dip->stream, + "0x%0*lx %s", + 2*sizeof(addr), addr, symtab.sym_name); + if ((offset = addr - symtab.sym_start) == 0) { + spaces += 4; + } + else { + unsigned int o = offset; + while (o >>= 4) + --spaces; + dip->fprintf_func(dip->stream, "+0x%x", offset); + } + + } else { + dip->fprintf_func(dip->stream, "0x%x", addr); + } + + if (flag) { + if (spaces < 1) { + spaces = 1; + } + dip->fprintf_func(dip->stream, ":%*s", spaces, " "); + } +} + +/* + * kdba_dis_printaddr + * + * Print (symbolically) an address. Called by GNU disassembly + * code via disassemble_info structure. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * This function will never append ":" to the printed + * symbolic address. + */ + +static void +kdba_dis_printaddr(bfd_vma addr, disassemble_info *dip) +{ + kdba_printaddress(addr, dip, 0); +} + +/* + * kdba_dis_getmem + * + * Fetch 'length' bytes from 'addr' into 'buf'. + * + * Parameters: + * addr Address for which to get symbol + * buf Address of buffer to fill with bytes from 'addr' + * length Number of bytes to fetch + * dip Pointer to disassemble_info + * Returns: + * 0 if data is available, otherwise error. + * Locking: + * Remarks: + * + */ + +/* ARGSUSED */ +static int +kdba_dis_getmem(bfd_vma addr, bfd_byte *buf, unsigned int length, disassemble_info *dip) +{ + return kdb_getarea_size(buf, addr, length); +} + +/* + * kdba_id_parsemode + * + * Parse IDMODE environment variable string and + * set appropriate value into "disassemble_info" structure. + * + * Parameters: + * mode Mode string + * dip Disassemble_info structure pointer + * Returns: + * Locking: + * Remarks: + * We handle the values 'x86' and '8086' to enable either + * 32-bit instruction set or 16-bit legacy instruction set. + */ + +int +kdba_id_parsemode(const char *mode, disassemble_info *dip) +{ + + if (mode) { + if (strcmp(mode, "x86") == 0) { + dip->mach = bfd_mach_i386_i386; + } else if (strcmp(mode, "8086") == 0) { + dip->mach = bfd_mach_i386_i8086; + } else { + return KDB_BADMODE; + } + } + + return 0; +} + +/* + * kdba_check_pc + * + * Check that the pc is satisfactory. + * + * Parameters: + * pc Program Counter Value. + * Returns: + * None + * Locking: + * None. + * Remarks: + * Can change pc. + */ + +void +kdba_check_pc(kdb_machreg_t *pc) +{ + /* No action */ +} + +/* + * kdba_id_printinsn + * + * Format and print a single instruction at 'pc'. Return the + * length of the instruction. + * + * Parameters: + * pc Program Counter Value. + * dip Disassemble_info structure pointer + * Returns: + * Length of instruction, -1 for error. + * Locking: + * None. + * Remarks: + * Depends on 'IDMODE' environment variable. + */ + +int +kdba_id_printinsn(kdb_machreg_t pc, disassemble_info *dip) +{ + kdba_printaddress(pc, dip, 1); + return print_insn_i386_att(pc, dip); +} + +/* + * kdba_id_init + * + * Initialize the architecture dependent elements of + * the disassembly information structure + * for the GNU disassembler. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void __init +kdba_id_init(disassemble_info *dip) +{ + dip->read_memory_func = kdba_dis_getmem; + dip->print_address_func = kdba_dis_printaddr; + dip->symbol_at_address_func = kdba_dis_getsym; + + dip->flavour = bfd_target_elf_flavour; + dip->arch = bfd_arch_i386; + dip->mach = bfd_mach_i386_i386; + dip->endian = BFD_ENDIAN_LITTLE; + + dip->display_endian = BFD_ENDIAN_LITTLE; +} diff -Nur linux-2.4.19/arch/i386/kdb/kdba_io.c linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_io.c --- linux-2.4.19/arch/i386/kdb/kdba_io.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/kdba_io.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,518 @@ +/* + * Kernel Debugger Architecture Dependent Console I/O handler + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include /* ashishk@sco.com */ + +#ifdef CONFIG_VT_CONSOLE +#define KDB_BLINK_LED 1 +#else +#undef KDB_BLINK_LED +#endif + +#ifdef CONFIG_KDB_USB +struct kdb_usb_exchange kdb_usb_infos = { NULL, NULL, NULL, NULL, NULL, 0}; + +static unsigned char kdb_usb_keycode[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140 +}; + +/* get_usb_char + * This function drives the UHCI controller, + * fetch the USB scancode and decode it + */ +static int get_usb_char(void) +{ + static int usb_lock; + unsigned char keycode, spec; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + /* Is USB initialized ? */ + if(!kdb_usb_infos.poll_func) + return -1; + + /* Transfer char if they are present */ + (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (urb_t *)kdb_usb_infos.urb); + + spec = kdb_usb_infos.buffer[0]; + keycode = kdb_usb_infos.buffer[2]; + kdb_usb_infos.buffer[0] = (char)0; + kdb_usb_infos.buffer[2] = (char)0; + + if(kdb_usb_infos.buffer[3]) + return -1; + + /* A normal key is pressed, decode it */ + if(keycode) + keycode = kdb_usb_keycode[keycode]; + + /* 2 Keys pressed at one time ? */ + if (spec && keycode) { + switch(spec) + { + case 0x2: + case 0x20: /* Shift */ + return shift_map[keycode]; + case 0x1: + case 0x10: /* Ctrl */ + return ctrl_map[keycode]; + case 0x4: + case 0x40: /* Alt */ + break; + } + } + else { + if(keycode) { /* If only one key pressed */ + switch(keycode) + { + case 0x1C: /* Enter */ + return 13; + + case 0x3A: /* Capslock */ + usb_lock ? (usb_lock = 0) : (usb_lock = 1); + break; + case 0x0E: /* Backspace */ + return 8; + case 0x0F: /* TAB */ + return 9; + case 0x77: /* Pause */ + break ; + default: + if(!usb_lock) { + return plain_map[keycode]; + } + else { + return shift_map[keycode]; + } + } + } + } + return -1; +} +#endif + +struct kdb_serial kdb_serial; + +/* + * This module contains code to read characters from the keyboard or a serial + * port. + * + * It is used by the kernel debugger, and is polled, not interrupt driven. + * + */ + +#ifdef KDB_BLINK_LED +/* + * send: Send a byte to the keyboard controller. Used primarily to + * alter LED settings. + */ + +static void +kdb_kbdsend(unsigned char byte) +{ + while (inb(KBD_STATUS_REG) & KBD_STAT_IBF) + ; + outb(byte, KBD_DATA_REG); +} + +static void +kdb_toggleled(int led) +{ + static int leds; + + leds ^= led; + + kdb_kbdsend(KBD_CMD_SET_LEDS); + kdb_kbdsend((unsigned char)leds); +} +#endif /* KDB_BLINK_LED */ + +#if defined(CONFIG_SERIAL_CONSOLE) + +static inline unsigned int +serial_inp(struct kdb_serial *kdb_serial, unsigned long offset) +{ + offset <<= kdb_serial->ioreg_shift; + + switch (kdb_serial->io_type) { + case SERIAL_IO_MEM: + return readb(kdb_serial->iobase + offset); + break; + default: + return inb(kdb_serial->iobase + offset); + break; + } +} + +/* Check if there is a byte ready at the serial port */ +static int get_serial_char(void) +{ + unsigned char ch; + + if (kdb_serial.iobase == 0) + return -1; + + if (serial_inp(&kdb_serial, UART_LSR) & UART_LSR_DR) { + ch = serial_inp(&kdb_serial, UART_RX); + if (ch == 0x7f) + ch = 8; + return ch; + } + return -1; +} +#endif /* CONFIG_SERIAL_CONSOLE */ + +#ifdef CONFIG_VT_CONSOLE + +static int kbd_exists = -1; + +/* + * Check if the keyboard controller has a keypress for us. + * Some parts (Enter Release, LED change) are still blocking polled here, + * but hopefully they are all short. + */ +static int get_kbd_char(void) +{ + int scancode, scanstatus; + static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ + static int shift_key; /* Shift next keypress */ + static int ctrl_key; + u_short keychar; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + if (kbd_exists <= 0) { + if (kbd_exists == 0) + return -1; + + if (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff) { + kbd_exists = 0; + return -1; + } + kbd_exists = 1; + } + + if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + return -1; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + /* + * Ignore mouse events. + */ + if (scanstatus & KBD_STAT_MOUSE_OBF) + return -1; + + /* + * Ignore release, trigger on make + * (except for shift keys, where we want to + * keep the shift state so long as the key is + * held down). + */ + + if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { + /* + * Next key may use shift table + */ + if ((scancode & 0x80) == 0) { + shift_key=1; + } else { + shift_key=0; + } + return -1; + } + + if ((scancode&0x7f) == 0x1d) { + /* + * Left ctrl key + */ + if ((scancode & 0x80) == 0) { + ctrl_key = 1; + } else { + ctrl_key = 0; + } + return -1; + } + + if ((scancode & 0x80) != 0) + return -1; + + scancode &= 0x7f; + + /* + * Translate scancode + */ + + if (scancode == 0x3a) { + /* + * Toggle caps lock + */ + shift_lock ^= 1; + +#ifdef KDB_BLINK_LED + kdb_toggleled(0x4); +#endif + return -1; + } + + if (scancode == 0x0e) { + /* + * Backspace + */ + return 8; + } + + /* Special Key */ + switch (scancode) { + case 0xF: /* Tab */ + return 9; + case 0x53: /* Del */ + return 4; + case 0x47: /* Home */ + return 1; + case 0x4F: /* End */ + return 5; + case 0x4B: /* Left */ + return 2; + case 0x48: /* Up */ + return 16; + case 0x50: /* Down */ + return 14; + case 0x4D: /* Right */ + return 6; + } + + if (scancode == 0xe0) { + return -1; + } + + /* + * For Japanese 86/106 keyboards + * See comment in drivers/char/pc_keyb.c. + * - Masahiro Adegawa + */ + if (scancode == 0x73) { + scancode = 0x59; + } else if (scancode == 0x7d) { + scancode = 0x7c; + } + + if (!shift_lock && !shift_key && !ctrl_key) { + keychar = plain_map[scancode]; + } else if (shift_lock || shift_key) { + keychar = shift_map[scancode]; + } else if (ctrl_key) { + keychar = ctrl_map[scancode]; + } else { + keychar = 0x0020; + kdb_printf("Unknown state/scancode (%d)\n", scancode); + } + keychar &= 0x0fff; + if (keychar == '\t') + keychar = ' '; + switch (KTYP(keychar)) { + case KT_LETTER: + case KT_LATIN: + if (isprint(keychar)) + break; /* printable characters */ + /* drop through */ + case KT_SPEC: + if (keychar == K_ENTER) + break; + /* drop through */ + default: + return(-1); /* ignore unprintables */ + } + + if ((scancode & 0x7f) == 0x1c) { + /* + * enter key. All done. Absorb the release scancode. + */ + while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + ; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + while (scanstatus & KBD_STAT_MOUSE_OBF) { + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + } + + if (scancode != 0x9c) { + /* + * Wasn't an enter-release, why not? + */ + kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", + scancode, scanstatus); + } + + kdb_printf("\n"); + return 13; + } + + return keychar & 0xff; +} +#endif /* CONFIG_VT_CONSOLE */ + +#ifdef KDB_BLINK_LED + +/* Leave numlock alone, setting it messes up laptop keyboards with the keypad + * mapped over normal keys. + */ +int kdba_blink_mask = 0x1 | 0x4; + +#define BOGOMIPS (boot_cpu_data.loops_per_jiffy/(500000/HZ)) +static int blink_led(void) +{ + static long delay; + + if (kbd_exists == 0) + return -1; + + if (--delay < 0) { + if (BOGOMIPS == 0) /* early kdb */ + delay = 150000000/1000; /* arbitrary bogomips */ + else + delay = 150000000/BOGOMIPS; /* Roughly 1 second when polling */ + kdb_toggleled(kdba_blink_mask); + } + return -1; +} +#endif + +get_char_func poll_funcs[] = { +#if defined(CONFIG_VT_CONSOLE) + get_kbd_char, +#endif +#if defined(CONFIG_SERIAL_CONSOLE) + get_serial_char, +#endif +#ifdef KDB_BLINK_LED + blink_led, +#endif +#ifdef CONFIG_KDB_USB + get_usb_char, +#endif + NULL +}; + +/* + * On some Compaq Deskpro's, there is a keyboard freeze many times after + * exiting from the kdb. As kdb's keyboard handler is not interrupt-driven and + * uses a polled interface, it makes more sense to disable motherboard keyboard + * controller's OBF interrupts during kdb's polling.In case, of interrupts + * remaining enabled during kdb's polling, it may cause un-necessary + * interrupts being signalled during keypresses, which are also sometimes seen + * as spurious interrupts after exiting from kdb. This hack to disable OBF + * interrupts before entry to kdb and re-enabling them at kdb exit point also + * solves the keyboard freeze issue. These functions are called from + * kdb_local(), hence these are arch. specific setup and cleanup functions + * executing only on the local processor - ashishk@sco.com + */ + +void kdba_local_arch_setup(void) +{ + unsigned char c; + + while (kbd_read_status() & KBD_STAT_IBF); + kbd_write_command(KBD_CCMD_READ_MODE); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF); + while ( !(kbd_read_status() & KBD_STAT_OBF) ); + c = kbd_read_input(); + c &= ~KBD_MODE_KBD_INT; + while (kbd_read_status() & KBD_STAT_IBF); + kbd_write_command(KBD_CCMD_WRITE_MODE); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF); + kbd_write_output(c); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF); + mdelay(1); +} + +void kdba_local_arch_cleanup(void) +{ + unsigned char c; + + while (kbd_read_status() & KBD_STAT_IBF); + kbd_write_command(KBD_CCMD_READ_MODE); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF); + while ( !(kbd_read_status() & KBD_STAT_OBF) ); + c = kbd_read_input(); + c |= KBD_MODE_KBD_INT; + while (kbd_read_status() & KBD_STAT_IBF); + kbd_write_command(KBD_CCMD_WRITE_MODE); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF); + kbd_write_output(c); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF); + mdelay(1); +} diff -Nur linux-2.4.19/arch/i386/kdb/kdbasupport.c linux-2.4.19-sgi211r3/arch/i386/kdb/kdbasupport.c --- linux-2.4.19/arch/i386/kdb/kdbasupport.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/i386/kdb/kdbasupport.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,1298 @@ +/* + * Kernel Debugger Architecture Independent Support Functions + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * kdba_find_return + * + * Given a starting point on the stack and symtab data for the + * current function, scan up the stack looking for a return + * address for this function. + * Inputs: + * sp Starting stack pointer for scan + * ss Start of stack for current process + * symtab kallsyms symbol data for the function + * Outputs: + * None. + * Returns: + * Position on stack of return address, 0 if not found. + * Locking: + * None. + * Remarks: + * This is sensitive to the calling sequence generated by gcc. + */ + +static kdb_machreg_t +kdba_find_return(kdb_machreg_t sp, kdb_machreg_t ss, const kdb_symtab_t *symtab) +{ + kdb_machreg_t ret; + kdb_symtab_t caller_symtab; + unsigned long disp8; + unsigned long disp32; + unsigned char code[7]; +#define retaddr(off) code[sizeof(code)+(off)] + + if (KDB_DEBUG(ARA)) { + kdb_printf(" kdba_find_return: start\n"); + } + + if ((sp & -THREAD_SIZE) != ss) { + kdb_printf(" sp is in wrong stack 0x%lx 0x%lx 0x%lx\n", sp, ss, sp & -THREAD_SIZE); + return(0); + } + + if ((sp & (THREAD_SIZE - 1)) < sizeof(struct task_struct)) { + kdb_printf(" sp is inside task_struct\n"); + return(0); + } + + for (;ret = 0, sp & (THREAD_SIZE-1);sp += 4) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" sp=0x%lx", sp); + } + if (kdb_getword(&ret, sp, 4)) + break; + kdbnearsym(ret, &caller_symtab); + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret="); + kdb_symbol_print(ret, &caller_symtab, KDB_SP_DEFAULT|KDB_SP_SYMSIZE); + } + if (!caller_symtab.sym_name) { + if (KDB_DEBUG(ARA)) { + kdb_printf("\n"); + } + continue; /* not a valid kernel address */ + } + KDB_STATE_SET(SUPPRESS); + if (kdb_getarea(code, ret-sizeof(code)) || + kdb_getword(&disp32, ret-4, 4) || + kdb_getword(&disp8, ret-1, 1)) + continue; /* not a valid return address */ + if (retaddr(-5) == 0xe8) { + /* call disp32 */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call disp32"); + } + if (ret + (s32) disp32 == symtab->sym_start) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* call to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (retaddr(-7) == 0xff && retaddr(-6) == 0x14 && retaddr(-5) == 0x85) { + /* call *disp32(,%eax,4), used by syscall. + * Cannot calculate address, assume it is valid + * if the current function name starts with + * 'sys_' or 'old_'. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call *0xnnnn(,%%eax,4)"); + } + if (strncmp(symtab->sym_name, "sys_", 4) == 0 || + strncmp(symtab->sym_name, "old_", 4) == 0) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* probably call to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (retaddr(-2) == 0xff && + ((retaddr(-1) & 0xf8) == 0xd0 || (retaddr(-1) & 0xf8) == 0x10)) { + /* call *%reg. Cannot validate, have to assume + * it is valid. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call *%%reg, assume valid\n"); + } + break; /* hope it is a call to this function */ + } else if (retaddr(-3) == 0xff && (retaddr(-2) & 0xf8) == 0x50) { + /* call *disp8(%reg). Cannot validate, have to assume + * it is valid. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call *disp8(%%reg), assume valid\n"); + } + break; /* hope it is a call to this function */ + } else if (retaddr(-6) == 0xff && (retaddr(-5) & 0xf8) == 0x90) { + /* call *disp32(%reg). Cannot validate, have to assume + * it is valid. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call *disp32(%%reg), assume valid\n"); + } + break; /* hope it is a call to this function */ + } else if (retaddr(-5) == 0xe9) { + /* jmp disp32. I have been told that gcc may + * do function tail optimization and replace + * call with jmp. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" jmp disp32\n"); + } + if (ret + (s32) disp32 == symtab->sym_start) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* jmp to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (retaddr(-2) == 0xeb) { + /* jmp disp8 */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" jmp disp8\n"); + } + if (ret + (s8) disp8 == symtab->sym_start) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* jmp to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (strcmp(caller_symtab.sym_name, "ret_from_intr") == 0 + && ret == caller_symtab.sym_start) { + /* ret_from_intr is pushed on stack for interrupts */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret_from_intr matched\n"); + } + break; /* special case, hand crafted frame */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf("\n"); + } + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" end ret=0x%lx sp=0x%lx\n", ret, sp); + } + if (ret) + return(sp); + return(0); +} + +/* + * kdba_prologue + * + * This function analyzes a gcc-generated function prototype + * with or without frame pointers to determine the amount of + * automatic storage and register save storage is used on the + * stack of the target function. It only counts instructions + * that have been executed up to but excluding the current eip. + * Inputs: + * code Start address of function code to analyze + * pc Current program counter within function + * sp Current stack pointer for function + * fp Current frame pointer for function, may not be valid + * ss Start of stack for current process. + * caller 1 if looking for data on the caller frame, 0 for callee. + * Outputs: + * ar Activation record, all fields may be set. fp and oldfp + * are 0 if they cannot be extracted. return is 0 if the + * code cannot find a valid return address. args and arg0 + * are 0 if the number of arguments cannot be safely + * calculated. + * Returns: + * 1 if prologue is valid, 0 otherwise. If pc is 0 treat it as a + * valid prologue to allow bt on wild branches. + * Locking: + * None. + * Remarks: + * + * A prologue for ia32 generally looks like: + * + * pushl %ebp [All functions, but only if + * movl %esp, %ebp compiled with frame pointers] + * subl $auto, %esp [some functions] + * pushl %reg [some functions] + * pushl %reg [some functions] + * + * FIXME: Mike Galbraith says that gcc 2.95 can generate a slightly + * different prologue. No support for gcc 2.95 yet. + */ + +int +kdba_prologue(const kdb_symtab_t *symtab, kdb_machreg_t pc, kdb_machreg_t sp, + kdb_machreg_t fp, kdb_machreg_t ss, int caller, kdb_ar_t *ar) +{ + kdb_machreg_t ret_p, code = symtab->sym_start; + int oldfp_present = 0, unwound = 0; + unsigned char instruction[6]; + + if (KDB_DEBUG(ARA)) { + kdb_printf("kdba_prologue: code=0x%lx %s pc=0x%lx sp=0x%lx fp=0x%lx\n", + code, symtab->sym_name, pc, sp, fp); + } + + /* Special case for wild branches. Assumes top of stack is return address */ + if (pc == 0) { + memset(ar, 0, sizeof(*ar)); + ar->setup = 4; + ar->end = sp; + ar->start = ar->end + 4; + kdb_getword(&(ar->ret), sp, 4); + if (KDB_DEBUG(ARA)) { + kdb_printf(" pc==0: ret=0x%lx\n", ar->ret); + } + return(1); + } + + if (code == 0 || sp & 3 || ss != (sp & -THREAD_SIZE)) + return(0); + + ar->end = sp; /* End of activation record +1 */ + + /* Special cases galore when the caller pc is within entry.S. + * The return address for these routines is outside the kernel, + * so the normal algorithm to find the frame does not work. + * Hand craft the frame to no setup, regs, locals etc, assume 6 + * parameters. + * This list was extracted from entry.S by looking for all call + * instructions that were eventually followed by RESTORE_ALL, + * take the label before each such instruction. + */ + if (caller && + (strcmp(symtab->sym_name, "lcall7") == 0 || + strcmp(symtab->sym_name, "lcall27") == 0 || + strcmp(symtab->sym_name, "kdb_call") == 0 || + strcmp(symtab->sym_name, "system_call") == 0 || + strcmp(symtab->sym_name, "tracesys") == 0 || + strcmp(symtab->sym_name, "signal_return") == 0 || + strcmp(symtab->sym_name, "v86_signal_return") == 0 || + strcmp(symtab->sym_name, "tracesys") == 0 || + strcmp(symtab->sym_name, "tracesys_exit") == 0 || + strcmp(symtab->sym_name, "handle_softirq") == 0 || + strcmp(symtab->sym_name, "reschedule") == 0 || + strcmp(symtab->sym_name, "error_code") == 0 || + strcmp(symtab->sym_name, "device_not_available") == 0 || + strcmp(symtab->sym_name, "nmi") == 0)) { + ar->start = ar->end + 6*4; /* 6 parameters */ + if ((ar->start & -THREAD_SIZE) != ss) + ar->start = 0; + return(1); + } + + ar->setup = 4; /* Return address is always on stack */ + + /* Kludge. If we are sitting on 'ret' then the stack has been unwound, + * ignore all the startup code. + */ + if (kdb_getarea(instruction[0], pc)) + return(0); + if (instruction[0] == 0xc3) { + /* ret */ + unwound = 1; + } + + if (kdb_getarea(instruction, code)) + return(0); + if (!unwound && code < pc && instruction[0] == 0x55) { + /* pushl %ebp */ + ar->setup += 4; /* Frame pointer is on stack */ + oldfp_present = 1; + ++code; + if (KDB_DEBUG(ARA)) { + kdb_printf(" pushl %%ebp\n"); + } + if (code < pc && instruction[0] == 0x89 && instruction[1] == 0xe5) { + /* movl %esp,%ebp */ + if (fp >= sp && (fp & -THREAD_SIZE) == ss) + ar->fp = fp; /* %ebp has been set */ + code += 2; + if (KDB_DEBUG(ARA)) { + kdb_printf(" movl %%esp,%%ebp, fp=0x%lx\n", ar->fp); + } + } + } + + if (!unwound && code < pc) { + if (instruction[0] == 0x83 && instruction[1] == 0xec) { + /* subl $xx,%esp */ + kdb_getword(&(ar->locals), (unsigned long)(instruction+2), 1); + code += 3; + if (KDB_DEBUG(ARA)) { + kdb_printf(" subl $xx,%%esp, locals=%ld\n", ar->locals); + } + } else if (instruction[0] == 0x81 && instruction[1] == 0xec) { + /* subl $xxxxxxxx,%esp */ + kdb_getword(&(ar->locals), (unsigned long)(instruction+2), 4); + code += 6; + if (KDB_DEBUG(ARA)) { + kdb_printf(" subl $xxxxxxxx,%%esp, locals=%ld\n", ar->locals); + } + } + } + + while (!unwound && code < pc && + kdb_getarea(instruction, code) == 0 && + (instruction[0] & 0xf8) == 0x50) { + /* pushl %reg */ + ar->regs += 4; + ++code; + if (KDB_DEBUG(ARA)) { + kdb_printf(" pushl %%reg, regs=%ld\n", ar->regs); + } + } + + /* Check the return address. It must point within the kernel + * and the code at that location must be a valid entry sequence. + */ + if (ar->fp) { + ret_p = ar->fp + ar->setup; + } + else { + ret_p = ar->end + ar->regs + ar->locals + ar->setup; + } + ret_p -= 4; + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret_p(0)=0x%lx\n", ret_p); + } + ar->ret = 0; + if ((ret_p & -THREAD_SIZE) == ss && + (ret_p = kdba_find_return(ret_p, ss, symtab))) { + kdb_getword(&(ar->ret), ret_p, 4); + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret_p(1)=0x%lx ret=0x%lx\n", ret_p, ar->ret); + } + if (ar->ret) { + ar->fp = ret_p - ar->setup + 4; /* "accurate" fp */ + ar->start = ret_p + 4; + if (KDB_DEBUG(ARA)) { + kdb_printf(" fp=0x%lx start=0x%lx\n", ar->fp, ar->start); + } + } + if (oldfp_present) { + if (ar->fp) + kdb_getword(&(ar->oldfp), ar->fp, 4); + if (KDB_DEBUG(ARA)) { + kdb_printf(" oldfp=0x%lx", ar->oldfp); + } + if (ar->oldfp <= ar->fp || (ar->oldfp & -THREAD_SIZE) != ss) { + ar->oldfp = 0; + if (KDB_DEBUG(ARA)) { + kdb_printf(" (out of range)"); + } + } + if (KDB_DEBUG(ARA)) { + kdb_printf("\n"); + } + } + return(1); +} + +kdb_machreg_t +kdba_getdr6(void) +{ + return kdba_getdr(6); +} + +kdb_machreg_t +kdba_getdr7(void) +{ + return kdba_getdr(7); +} + +void +kdba_putdr6(kdb_machreg_t contents) +{ + kdba_putdr(6, contents); +} + +static void +kdba_putdr7(kdb_machreg_t contents) +{ + kdba_putdr(7, contents); +} + +void +kdba_installdbreg(kdb_bp_t *bp) +{ + kdb_machreg_t dr7; + + dr7 = kdba_getdr7(); + + kdba_putdr(bp->bp_hard->bph_reg, bp->bp_addr); + + dr7 |= DR7_GE; + if (cpu_has_de) + set_in_cr4(X86_CR4_DE); + + switch (bp->bp_hard->bph_reg){ + case 0: + DR7_RW0SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN0SET(dr7,bp->bp_hard->bph_length); + DR7_G0SET(dr7); + break; + case 1: + DR7_RW1SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN1SET(dr7,bp->bp_hard->bph_length); + DR7_G1SET(dr7); + break; + case 2: + DR7_RW2SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN2SET(dr7,bp->bp_hard->bph_length); + DR7_G2SET(dr7); + break; + case 3: + DR7_RW3SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN3SET(dr7,bp->bp_hard->bph_length); + DR7_G3SET(dr7); + break; + default: + kdb_printf("kdb: Bad debug register!! %ld\n", + bp->bp_hard->bph_reg); + break; + } + + kdba_putdr7(dr7); + return; +} + +void +kdba_removedbreg(kdb_bp_t *bp) +{ + int regnum; + kdb_machreg_t dr7; + + if (!bp->bp_hard) + return; + + regnum = bp->bp_hard->bph_reg; + + dr7 = kdba_getdr7(); + + kdba_putdr(regnum, 0); + + switch (regnum) { + case 0: + DR7_G0CLR(dr7); + DR7_L0CLR(dr7); + break; + case 1: + DR7_G1CLR(dr7); + DR7_L1CLR(dr7); + break; + case 2: + DR7_G2CLR(dr7); + DR7_L2CLR(dr7); + break; + case 3: + DR7_G3CLR(dr7); + DR7_L3CLR(dr7); + break; + default: + kdb_printf("kdb: Bad debug register!! %d\n", regnum); + break; + } + + kdba_putdr7(dr7); +} + +kdb_machreg_t +kdba_getdr(int regnum) +{ + kdb_machreg_t contents = 0; + switch(regnum) { + case 0: + __asm__ ("movl %%db0,%0\n\t":"=r"(contents)); + break; + case 1: + __asm__ ("movl %%db1,%0\n\t":"=r"(contents)); + break; + case 2: + __asm__ ("movl %%db2,%0\n\t":"=r"(contents)); + break; + case 3: + __asm__ ("movl %%db3,%0\n\t":"=r"(contents)); + break; + case 4: + case 5: + break; + case 6: + __asm__ ("movl %%db6,%0\n\t":"=r"(contents)); + break; + case 7: + __asm__ ("movl %%db7,%0\n\t":"=r"(contents)); + break; + default: + break; + } + + return contents; +} + + +kdb_machreg_t +kdb_getcr(int regnum) +{ + kdb_machreg_t contents = 0; + switch(regnum) { + case 0: + __asm__ ("movl %%cr0,%0\n\t":"=r"(contents)); + break; + case 1: + break; + case 2: + __asm__ ("movl %%cr2,%0\n\t":"=r"(contents)); + break; + case 3: + __asm__ ("movl %%cr3,%0\n\t":"=r"(contents)); + break; + case 4: + __asm__ ("movl %%cr4,%0\n\t":"=r"(contents)); + break; + default: + break; + } + + return contents; +} + +void +kdba_putdr(int regnum, kdb_machreg_t contents) +{ + switch(regnum) { + case 0: + __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); + break; + case 1: + __asm__ ("movl %0,%%db1\n\t"::"r"(contents)); + break; + case 2: + __asm__ ("movl %0,%%db2\n\t"::"r"(contents)); + break; + case 3: + __asm__ ("movl %0,%%db3\n\t"::"r"(contents)); + break; + case 4: + case 5: + break; + case 6: + __asm__ ("movl %0,%%db6\n\t"::"r"(contents)); + break; + case 7: + __asm__ ("movl %0,%%db7\n\t"::"r"(contents)); + break; + default: + break; + } +} + +/* + * kdba_getregcontents + * + * Return the contents of the register specified by the + * input string argument. Return an error if the string + * does not match a machine register. + * + * The following pseudo register names are supported: + * ®s - Prints address of exception frame + * kesp - Prints kernel stack pointer at time of fault + * cesp - Prints current kernel stack pointer, inside kdb + * ceflags - Prints current flags, inside kdb + * % - Uses the value of the registers at the + * last time the user process entered kernel + * mode, instead of the registers at the time + * kdb was entered. + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * Outputs: + * *contents Pointer to unsigned long to recieve register contents + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + * If kdb was entered via an interrupt from the kernel itself then + * ss and esp are *not* on the stack. + */ + +static struct kdbregs { + char *reg_name; + size_t reg_offset; +} kdbreglist[] = { + { "eax", offsetof(struct pt_regs, eax) }, + { "ebx", offsetof(struct pt_regs, ebx) }, + { "ecx", offsetof(struct pt_regs, ecx) }, + { "edx", offsetof(struct pt_regs, edx) }, + + { "esi", offsetof(struct pt_regs, esi) }, + { "edi", offsetof(struct pt_regs, edi) }, + { "esp", offsetof(struct pt_regs, esp) }, + { "eip", offsetof(struct pt_regs, eip) }, + + { "ebp", offsetof(struct pt_regs, ebp) }, + { "xss", offsetof(struct pt_regs, xss) }, + { "xcs", offsetof(struct pt_regs, xcs) }, + { "eflags", offsetof(struct pt_regs, eflags) }, + + { "xds", offsetof(struct pt_regs, xds) }, + { "xes", offsetof(struct pt_regs, xes) }, + { "origeax", offsetof(struct pt_regs, orig_eax) }, + +}; + +static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); + +static struct kdbregs dbreglist[] = { + { "dr0", 0 }, + { "dr1", 1 }, + { "dr2", 2 }, + { "dr3", 3 }, + { "dr6", 6 }, + { "dr7", 7 }, +}; + +static const int ndbreglist = sizeof(dbreglist) / sizeof(struct kdbregs); + +int +kdba_getregcontents(const char *regname, + struct pt_regs *regs, + kdb_machreg_t *contents) +{ + int i; + + if (strcmp(regname, "cesp") == 0) { + asm volatile("movl %%esp,%0":"=m" (*contents)); + return 0; + } + + if (strcmp(regname, "ceflags") == 0) { + int flags; + __save_flags(flags); + *contents = flags; + return 0; + } + + if (regname[0] == '%') { + /* User registers: %%e[a-c]x, etc */ + regname++; + regs = (struct pt_regs *) + (current->thread.esp0 - sizeof(struct pt_regs)); + } + + for (i=0; ixcs & 0xffff) == __KERNEL_CS) { + /* esp and ss are not on stack */ + *contents -= 2*4; + } + return 0; + } + + for (i=0; ixcs & 0xffff) == __KERNEL_CS) { + /* No cpl switch, esp and ss are not on stack */ + if (strcmp(kdbreglist[i].reg_name, "esp") == 0) { + *contents = (kdb_machreg_t)regs + + sizeof(struct pt_regs) - 2*4; + return(0); + } + if (strcmp(kdbreglist[i].reg_name, "xss") == 0) { + asm volatile( + "pushl %%ss\n" + "popl %0\n" + :"=m" (*contents)); + return(0); + } + } + *contents = *(unsigned long *)((unsigned long)regs + + kdbreglist[i].reg_offset); + return(0); + } + + return KDB_BADREG; +} + +/* + * kdba_setregcontents + * + * Set the contents of the register specified by the + * input string argument. Return an error if the string + * does not match a machine register. + * + * Supports modification of user-mode registers via + * % + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * contents Unsigned long containing new register contents + * Outputs: + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + */ + +int +kdba_setregcontents(const char *regname, + struct pt_regs *regs, + unsigned long contents) +{ + int i; + + if (regname[0] == '%') { + regname++; + regs = (struct pt_regs *) + (current->thread.esp0 - sizeof(struct pt_regs)); + } + + for (i=0; ithread.esp0 - sizeof(struct pt_regs)); + } + + if (type == NULL) { + struct kdbregs *rlp; + kdb_machreg_t contents; + + if (!regs) { + kdb_printf("%s: pt_regs not available\n", __FUNCTION__); + return KDB_BADREG; + } + + for (i=0, rlp=kdbreglist; ieip : 0; +} + +int +kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc) +{ + if (KDB_NULL_REGS(regs)) + return KDB_BADREG; + regs->eip = newpc; + KDB_STATE_SET(IP_ADJUSTED); + return 0; +} + +/* + * kdba_main_loop + * + * Do any architecture specific set up before entering the main kdb loop. + * The primary function of this routine is to make all processes look the + * same to kdb, kdb must be able to list a process without worrying if the + * process is running or blocked, so make all process look as though they + * are blocked. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * error2 kdb's current reason code. Initially error but can change + * acording to kdb state. + * db_result Result from break or debug point. + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it should + * always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Outputs: + * Sets eip and esp in current->thread. + * Locking: + * None. + * Remarks: + * none. + */ + +int +kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, + kdb_dbtrap_t db_result, struct pt_regs *regs) +{ + if (regs) { + kdba_getregcontents("eip", regs, &(current->thread.eip)); + kdba_getregcontents("esp", regs, &(current->thread.esp)); + } + return(kdb_main_loop(reason, reason2, error, db_result, regs)); +} + +void +kdba_disableint(kdb_intstate_t *state) +{ + int *fp = (int *)state; + int flags; + + __save_flags(flags); + __cli(); + + *fp = flags; +} + +void +kdba_restoreint(kdb_intstate_t *state) +{ + int flags = *(int *)state; + __restore_flags(flags); +} + +void +kdba_setsinglestep(struct pt_regs *regs) +{ + if (KDB_NULL_REGS(regs)) + return; + if (regs->eflags & EF_IE) + KDB_STATE_SET(A_IF); + else + KDB_STATE_CLEAR(A_IF); + regs->eflags = (regs->eflags | EF_TF) & ~EF_IE; +} + +void +kdba_clearsinglestep(struct pt_regs *regs) +{ + if (KDB_NULL_REGS(regs)) + return; + if (KDB_STATE(A_IF)) + regs->eflags |= EF_IE; + else + regs->eflags &= ~EF_IE; +} + +#ifdef KDB_HAVE_LONGJMP +int +kdba_setjmp(kdb_jmp_buf *jb) +{ +#if defined(CONFIG_FRAME_POINTER) + __asm__ ("movl 8(%esp), %eax\n\t" + "movl %ebx, 0(%eax)\n\t" + "movl %esi, 4(%eax)\n\t" + "movl %edi, 8(%eax)\n\t" + "movl (%esp), %ecx\n\t" + "movl %ecx, 12(%eax)\n\t" + "leal 8(%esp), %ecx\n\t" + "movl %ecx, 16(%eax)\n\t" + "movl 4(%esp), %ecx\n\t" + "movl %ecx, 20(%eax)\n\t"); +#else /* CONFIG_FRAME_POINTER */ + __asm__ ("movl 4(%esp), %eax\n\t" + "movl %ebx, 0(%eax)\n\t" + "movl %esi, 4(%eax)\n\t" + "movl %edi, 8(%eax)\n\t" + "movl %ebp, 12(%eax)\n\t" + "leal 4(%esp), %ecx\n\t" + "movl %ecx, 16(%eax)\n\t" + "movl 0(%esp), %ecx\n\t" + "movl %ecx, 20(%eax)\n\t"); +#endif /* CONFIG_FRAME_POINTER */ + KDB_STATE_SET(LONGJMP); + return 0; +} + +void +kdba_longjmp(kdb_jmp_buf *jb, int reason) +{ +#if defined(CONFIG_FRAME_POINTER) + __asm__("movl 8(%esp), %ecx\n\t" + "movl 12(%esp), %eax\n\t" + "movl 20(%ecx), %edx\n\t" + "movl 0(%ecx), %ebx\n\t" + "movl 4(%ecx), %esi\n\t" + "movl 8(%ecx), %edi\n\t" + "movl 12(%ecx), %ebp\n\t" + "movl 16(%ecx), %esp\n\t" + "jmp *%edx\n"); +#else /* CONFIG_FRAME_POINTER */ + __asm__("movl 4(%esp), %ecx\n\t" + "movl 8(%esp), %eax\n\t" + "movl 20(%ecx), %edx\n\t" + "movl 0(%ecx), %ebx\n\t" + "movl 4(%ecx), %esi\n\t" + "movl 8(%ecx), %edi\n\t" + "movl 12(%ecx), %ebp\n\t" + "movl 16(%ecx), %esp\n\t" + "jmp *%edx\n"); +#endif /* CONFIG_FRAME_POINTER */ +} +#endif /* KDB_HAVE_LONGJMP */ + + +/* + * kdba_enable_mce + * + * This function is called once on each CPU to enable machine + * check exception handling. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +void +kdba_enable_mce(void) +{ + /* No longer required, arch/i386/kernel/bluesmoke.c does the job now */ +} + +/* + * kdba_enable_lbr + * + * Enable last branch recording. + * + * Parameters: + * None. + * Returns: + * None + * Locking: + * None + * Remarks: + * None. + */ + +static unsigned char lbr_warned; + +void +kdba_enable_lbr(void) +{ + u32 lv, hv; + + if (!test_bit(X86_FEATURE_MCA, boot_cpu_data.x86_capability)) { + if (lbr_warned) { + kdb_printf("kdb: machine does not support last branch recording\n"); + lbr_warned = 1; + } + return; + } + rdmsr(MSR_IA32_DEBUGCTLMSR, lv, hv); + lv |= 0x1; /* Set LBR enable */ + wrmsr(MSR_IA32_DEBUGCTLMSR, lv, hv); +} + +/* + * kdba_disable_lbr + * + * disable last branch recording. + * + * Parameters: + * None. + * Returns: + * None + * Locking: + * None + * Remarks: + * None. + */ + +void +kdba_disable_lbr(void) +{ + u32 lv, hv; + + if (!test_bit(X86_FEATURE_MCA, boot_cpu_data.x86_capability)) { + if (lbr_warned) { + kdb_printf("kdb: machine does not support last branch recording\n"); + lbr_warned = 1; + } + return; + } + rdmsr(MSR_IA32_DEBUGCTLMSR, lv, hv); + lv &= ~0x1; /* Set LBR disable */ + wrmsr(MSR_IA32_DEBUGCTLMSR, lv, hv); +} + +/* + * kdba_print_lbr + * + * Print last branch and last exception addresses + * + * Parameters: + * None. + * Returns: + * None + * Locking: + * None + * Remarks: + * None. + */ + +void +kdba_print_lbr(void) +{ + u32 from, to, dummy; + + if (!test_bit(X86_FEATURE_MCA, boot_cpu_data.x86_capability)) + return; + + rdmsr(MSR_IA32_LASTBRANCHFROMIP, from, dummy); + rdmsr(MSR_IA32_LASTBRANCHTOIP, to, dummy); + kdb_printf("Last Branch IP, from: "); + kdb_symbol_print(from, NULL, KDB_SP_DEFAULT); + kdb_printf(" to: "); + kdb_symbol_print(to, NULL, KDB_SP_DEFAULT); + kdb_printf("\n"); + rdmsr(MSR_IA32_LASTINTFROMIP, from, dummy); + rdmsr(MSR_IA32_LASTINTTOIP, to, dummy); + kdb_printf("Last Int IP, from: "); + kdb_symbol_print(from, NULL, KDB_SP_DEFAULT); + kdb_printf(" to: "); + kdb_symbol_print(to, NULL, KDB_SP_DEFAULT); + kdb_printf("\n"); +} + +/* + * kdba_init + * + * Architecture specific initialization. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +void __init +kdba_init(void) +{ + kdba_enable_lbr(); + + return; +} + +/* + * kdba_adjust_ip + * + * Architecture specific adjustment of instruction pointer before leaving + * kdb. + * + * Parameters: + * reason The reason KDB was invoked + * error The hardware-defined error code + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it should + * always be valid. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * noop on ix86. + */ + +void +kdba_adjust_ip(kdb_reason_t reason, int error, struct pt_regs *regs) +{ + return; +} diff -Nur linux-2.4.19/arch/i386/kernel/bluesmoke.c linux-2.4.19-sgi211r3/arch/i386/kernel/bluesmoke.c --- linux-2.4.19/arch/i386/kernel/bluesmoke.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/bluesmoke.c Wed Oct 16 14:02:58 2002 @@ -4,6 +4,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include @@ -109,6 +112,9 @@ asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) { machine_check_vector(regs, error_code); +#ifdef CONFIG_KDB + (void)kdb(KDB_REASON_NMI, error_code, regs); +#endif /* CONFIG_KDB */ } /* diff -Nur linux-2.4.19/arch/i386/kernel/cpuid.c linux-2.4.19-sgi211r3/arch/i386/kernel/cpuid.c --- linux-2.4.19/arch/i386/kernel/cpuid.c Thu Oct 11 09:04:57 2001 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/cpuid.c Mon Oct 28 20:43:23 2002 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -82,16 +83,25 @@ static loff_t cpuid_seek(struct file *file, loff_t offset, int orig) { + loff_t ret; + + lock_kernel(); + switch (orig) { case 0: file->f_pos = offset; - return file->f_pos; + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return file->f_pos; + ret = file->f_pos; + break; default: - return -EINVAL; /* SEEK_END not supported */ + ret = -EINVAL; } + + unlock_kernel(); + return ret; } static ssize_t cpuid_read(struct file * file, char * buf, diff -Nur linux-2.4.19/arch/i386/kernel/entry.S linux-2.4.19-sgi211r3/arch/i386/kernel/entry.S --- linux-2.4.19/arch/i386/kernel/entry.S Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/entry.S Mon Oct 28 20:43:23 2002 @@ -77,7 +77,7 @@ exec_domain = 16 need_resched = 20 tsk_ptrace = 24 -processor = 52 +cpu = 32 ENOSYS = 38 @@ -176,14 +176,28 @@ ENTRY(ret_from_fork) +#if CONFIG_SMP pushl %ebx call SYMBOL_NAME(schedule_tail) addl $4, %esp +#endif GET_CURRENT(%ebx) testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys_exit jmp ret_from_sys_call +#if defined(CONFIG_KDB) +ENTRY(kdb_call) + pushl %eax # save orig EAX + SAVE_ALL + pushl %esp # struct pt_regs + pushl $0 # error_code + pushl $7 # KDB_REASON_ENTRY + call SYMBOL_NAME(kdb) + addl $12,%esp # remove args + RESTORE_ALL +#endif + /* * Return to user mode is not as complex as all this looks, * but we want the default path for a system call return to @@ -380,6 +394,22 @@ pushl $ SYMBOL_NAME(do_alignment_check) jmp error_code +#if defined(CONFIG_KDB) +ENTRY(page_fault_mca) + pushl %ecx + pushl %edx + pushl %eax + movl $473,%ecx + rdmsr + andl $0xfffffffe,%eax /* Disable last branch recording */ + wrmsr + popl %eax + popl %edx + popl %ecx + pushl $ SYMBOL_NAME(do_page_fault) + jmp error_code +#endif + ENTRY(page_fault) pushl $ SYMBOL_NAME(do_page_fault) jmp error_code @@ -622,23 +652,44 @@ .long SYMBOL_NAME(sys_ni_syscall) /* Reserved for Security */ .long SYMBOL_NAME(sys_gettid) .long SYMBOL_NAME(sys_readahead) /* 225 */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for setxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for lsetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fsetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for getxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* 230 reserved for lgetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fgetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for listxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for llistxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for flistxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* 235 reserved for removexattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for lremovexattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fremovexattr */ + .long SYMBOL_NAME(sys_setxattr) + .long SYMBOL_NAME(sys_lsetxattr) + .long SYMBOL_NAME(sys_fsetxattr) + .long SYMBOL_NAME(sys_getxattr) + .long SYMBOL_NAME(sys_lgetxattr) /* 230 */ + .long SYMBOL_NAME(sys_fgetxattr) + .long SYMBOL_NAME(sys_listxattr) + .long SYMBOL_NAME(sys_llistxattr) + .long SYMBOL_NAME(sys_flistxattr) + .long SYMBOL_NAME(sys_removexattr) /* 235 */ + .long SYMBOL_NAME(sys_lremovexattr) + .long SYMBOL_NAME(sys_fremovexattr) .long SYMBOL_NAME(sys_tkill) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sendfile64 */ .long SYMBOL_NAME(sys_ni_syscall) /* 240 reserved for futex */ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_setaffinity */ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_getaffinity */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 245 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 250 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + +#if defined(CONFIG_PAGG) + .long SYMBOL_NAME(sys_paggctl) +#else + .long SYMBOL_NAME(sys_ni_syscall) +#endif /* CONFIG_PAGG */ +#if defined(CONFIG_CSA_JOB_ACCT) || defined(CONFIG_CSA_JOB_ACCT_MODULE) + .long SYMBOL_NAME(sys_acctctl) +#else + .long SYMBOL_NAME(sys_ni_syscall) +#endif .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) diff -Nur linux-2.4.19/arch/i386/kernel/i386_ksyms.c linux-2.4.19-sgi211r3/arch/i386/kernel/i386_ksyms.c --- linux-2.4.19/arch/i386/kernel/i386_ksyms.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/i386_ksyms.c Thu Oct 24 04:22:20 2002 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -161,6 +162,27 @@ EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(rtc_lock); + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#ifdef CONFIG_SMP +extern irq_desc_t irq_desc[]; +extern unsigned long irq_affinity[]; +EXPORT_SYMBOL(irq_affinity); +EXPORT_SYMBOL(irq_desc); +extern void dump_send_ipi(void); +EXPORT_SYMBOL(dump_send_ipi); +extern int (*dump_ipi_function_ptr)(struct pt_regs *); +EXPORT_SYMBOL(dump_ipi_function_ptr); +extern void (*dump_trace_ptr)(struct pt_regs *); +EXPORT_SYMBOL(dump_trace_ptr); +extern void show_this_cpu_state(int, struct pt_regs *, struct task_struct *); +EXPORT_SYMBOL(show_this_cpu_state); +#endif +#ifdef CONFIG_HIGHMEM +EXPORT_SYMBOL(kmap_prot); +EXPORT_SYMBOL(kmap_pte); +#endif +#endif #undef memcpy #undef memset diff -Nur linux-2.4.19/arch/i386/kernel/i8259.c linux-2.4.19-sgi211r3/arch/i386/kernel/i8259.c --- linux-2.4.19/arch/i386/kernel/i8259.c Mon Sep 17 23:03:09 2001 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/i8259.c Wed Jan 30 15:32:11 2002 @@ -456,7 +456,11 @@ */ for (i = 0; i < NR_IRQS; i++) { int vector = FIRST_EXTERNAL_VECTOR + i; - if (vector != SYSCALL_VECTOR) + if ((vector != SYSCALL_VECTOR) +#if defined(CONFIG_KDB) + && (vector != KDBENTER_VECTOR) +#endif + ) set_intr_gate(vector, interrupt[i]); } diff -Nur linux-2.4.19/arch/i386/kernel/io_apic.c linux-2.4.19-sgi211r3/arch/i386/kernel/io_apic.c --- linux-2.4.19/arch/i386/kernel/io_apic.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/io_apic.c Fri Nov 1 07:16:07 2002 @@ -28,6 +28,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include @@ -592,6 +595,10 @@ current_vector += 8; if (current_vector == SYSCALL_VECTOR) goto next; +#ifdef CONFIG_KDB + if (current_vector == KDBENTER_VECTOR) + goto next; +#endif /* CONFIG_KDB */ if (current_vector > FIRST_SYSTEM_VECTOR) { offset++; diff -Nur linux-2.4.19/arch/i386/kernel/irq.c linux-2.4.19-sgi211r3/arch/i386/kernel/irq.c --- linux-2.4.19/arch/i386/kernel/irq.c Thu Oct 25 13:53:46 2001 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/irq.c Thu Oct 24 04:22:20 2002 @@ -32,6 +32,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include @@ -316,6 +319,11 @@ static inline void get_irqlock(int cpu) { +#ifdef CONFIG_KDB + static int kdb_rate; + if (KDB_IS_RUNNING() && kdb_rate++ < 10) + kdb_printf("Warning: get_irqlock on cpu %d while kdb is running, may hang\n", smp_processor_id()); +#endif /* CONFIG_KDB */ if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ if ((unsigned char) cpu == global_irq_holder) @@ -1076,7 +1084,7 @@ static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { diff -Nur linux-2.4.19/arch/i386/kernel/msr.c linux-2.4.19-sgi211r3/arch/i386/kernel/msr.c --- linux-2.4.19/arch/i386/kernel/msr.c Thu Oct 11 09:04:57 2001 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/msr.c Mon Oct 28 20:43:23 2002 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -162,16 +163,19 @@ static loff_t msr_seek(struct file *file, loff_t offset, int orig) { + loff_t ret = -EINVAL; + lock_kernel(); switch (orig) { case 0: file->f_pos = offset; - return file->f_pos; + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return file->f_pos; - default: - return -EINVAL; /* SEEK_END not supported */ + ret = file->f_pos; } + unlock_kernel(); + return ret; } static ssize_t msr_read(struct file * file, char * buf, diff -Nur linux-2.4.19/arch/i386/kernel/nmi.c linux-2.4.19-sgi211r3/arch/i386/kernel/nmi.c --- linux-2.4.19/arch/i386/kernel/nmi.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/nmi.c Fri Nov 1 07:16:07 2002 @@ -18,8 +18,12 @@ #include #include #include +#include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include @@ -343,6 +347,14 @@ */ int sum, cpu = smp_processor_id(); +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + /* + * Ignore watchdog when dumping is in progress. + * Todo: consider using the touch_nmi_watchdog() approach instead + */ + if (dump_in_progress && cpu != dumping_cpu) return; +#endif + sum = apic_timer_irqs[cpu]; if (last_irq_sums[cpu] == sum) { @@ -361,6 +373,10 @@ printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip); show_registers(regs); printk("console shuts up ...\n"); +#ifdef CONFIG_KDB + kdb(KDB_REASON_NMI, 0, regs); +#endif /* CONFIG_KDB */ + dump("NMI Watchdog Detected", regs); console_silent(); spin_unlock(&nmi_print_lock); bust_spinlocks(0); diff -Nur linux-2.4.19/arch/i386/kernel/process.c linux-2.4.19-sgi211r3/arch/i386/kernel/process.c --- linux-2.4.19/arch/i386/kernel/process.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/process.c Mon Oct 28 20:43:23 2002 @@ -33,6 +33,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include @@ -124,15 +127,12 @@ void cpu_idle (void) { /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - current->counter = -100; while (1) { void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; - while (!current->need_resched) + if (!current->need_resched) idle(); schedule(); check_pgt_cache(); @@ -398,6 +398,14 @@ * Stop all CPUs and turn off local APICs and the IO-APIC, so * other OSs see a clean IRQ state. */ +#ifdef CONFIG_KDB + /* + * If this restart is occuring while kdb is running (e.g. reboot + * command), the other CPU's are already stopped. Don't try to + * stop them yet again. + */ + if (!KDB_IS_RUNNING()) +#endif /* CONFIG_KDB */ smp_send_stop(); disable_IO_APIC(); #endif @@ -697,15 +705,17 @@ asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); /* - * Restore %fs and %gs. + * Restore %fs and %gs if needed. */ - loadsegment(fs, next->fs); - loadsegment(gs, next->gs); + if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) { + loadsegment(fs, next->fs); + loadsegment(gs, next->gs); + } /* * Now maybe reload the debug registers */ - if (next->debugreg[7]){ + if (unlikely(next->debugreg[7])) { loaddebug(next, 0); loaddebug(next, 1); loaddebug(next, 2); @@ -715,7 +725,7 @@ loaddebug(next, 7); } - if (prev->ioperm || next->ioperm) { + if (unlikely(prev->ioperm || next->ioperm)) { if (next->ioperm) { /* * 4 cachelines copy ... not good, but not that diff -Nur linux-2.4.19/arch/i386/kernel/setup.c linux-2.4.19-sgi211r3/arch/i386/kernel/setup.c --- linux-2.4.19/arch/i386/kernel/setup.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/setup.c Mon Oct 28 20:43:23 2002 @@ -3131,9 +3131,10 @@ load_TR(nr); load_LDT(&init_mm); - /* - * Clear all 6 debug registers: - */ + /* Clear %fs and %gs. */ + asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); + + /* Clear all 6 debug registers: */ #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); diff -Nur linux-2.4.19/arch/i386/kernel/smp.c linux-2.4.19-sgi211r3/arch/i386/kernel/smp.c --- linux-2.4.19/arch/i386/kernel/smp.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/smp.c Mon Oct 28 20:43:23 2002 @@ -18,11 +18,17 @@ #include #include #include +#include #include #include #include +#include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ + /* * Some notes on x86 processor bugs affecting SMP operation: * @@ -139,11 +145,29 @@ */ apic_wait_icr_idle(); +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + if (vector == DUMP_VECTOR) { + /* + * Setup DUMP IPI to be delivered as an NMI + */ + cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI; + } +#endif /* CONFIG_DUMP */ + /* * No need to touch the target chip field */ cfg = __prepare_ICR(shortcut, vector); +#ifdef CONFIG_KDB + if (vector == KDB_VECTOR) { + /* + * Setup KDB IPI to be delivered as an NMI + */ + cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI; + } +#endif /* CONFIG_KDB */ + /* * Send the IPI. The write to APIC_ICR fires this off. */ @@ -386,6 +410,11 @@ static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, unsigned long va) { +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + /* some cpu may not be running... LWS */ + unsigned long ipi_mask; +#endif + /* * A couple of (to be removed) sanity checks: * @@ -395,8 +424,14 @@ */ if (!cpumask) BUG(); +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + /* Some cpus may be stopped...like at crash dump time... LWS */ + if ((ipi_mask = cpumask & cpu_online_map) == 0) + return; +#else if ((cpumask & cpu_online_map) != cpumask) BUG(); +#endif if (cpumask & (1 << smp_processor_id())) BUG(); if (!mm) @@ -412,12 +447,20 @@ flush_mm = mm; flush_va = va; +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + atomic_set_mask(ipi_mask, &flush_cpumask); +#else atomic_set_mask(cpumask, &flush_cpumask); +#endif /* * We have to send the IPI only to * CPUs affected. */ +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + send_IPI_mask(ipi_mask, INVALIDATE_TLB_VECTOR); +#else send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR); +#endif while (flush_cpumask) /* nothing. lockup detection does not belong here */; @@ -488,6 +531,21 @@ do_flush_tlb_all_local(); } +#ifdef CONFIG_KDB +void +smp_kdb_stop(void) +{ + send_IPI_allbutself(KDB_VECTOR); +} +#endif /* CONFIG_KDB */ + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +void dump_send_ipi(void) +{ + send_IPI_allbutself(DUMP_VECTOR); +} +#endif + /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing @@ -496,7 +554,26 @@ void smp_send_reschedule(int cpu) { +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + /* only do this for on-line CPUs */ + unsigned long cpumask = (1 << cpu) & cpu_online_map; + if (cpumask) { + send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR); + } +#else send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR); +#endif +} + +/* + * this function sends a reschedule IPI to all (other) CPUs. + * This should only be used if some 'global' task became runnable, + * such as a RT task, that must be handled now. The first CPU + * that manages to grab the task will run it. + */ +void smp_send_reschedule_all(void) +{ + send_IPI_allbutself(RESCHEDULE_VECTOR); } /* @@ -555,8 +632,25 @@ send_IPI_allbutself(CALL_FUNCTION_VECTOR); /* Wait for response */ +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + if (dump_in_progress) { + int i = 1 * 1000; /* milliseconds to delay waiting for other CPU to start IPI processing (1 second) */ + while (atomic_read(&data.started) != cpus && i--) { + mdelay(1); + barrier(); + } + if (i <= 0) { + spin_unlock_bh(&call_lock); + return -ETIMEDOUT; + } + } else { + while (atomic_read(&data.started) != cpus) + barrier(); + } +#else while (atomic_read(&data.started) != cpus) barrier(); +#endif if (wait) while (atomic_read(&data.finished) != cpus) diff -Nur linux-2.4.19/arch/i386/kernel/smpboot.c linux-2.4.19-sgi211r3/arch/i386/kernel/smpboot.c --- linux-2.4.19/arch/i386/kernel/smpboot.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/smpboot.c Mon Oct 28 20:43:23 2002 @@ -40,6 +40,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include @@ -61,7 +64,10 @@ int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ /* Bitmask of currently online CPUs */ -unsigned long cpu_online_map; +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +volatile +#endif + unsigned long cpu_online_map; static volatile unsigned long cpu_callin_map; static volatile unsigned long cpu_callout_map; @@ -308,14 +314,14 @@ if (tsc_values[i] < avg) realdelta = -realdelta; - printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n", - i, realdelta); + printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n", i, realdelta); } sum += delta; } if (!buggy) printk("passed.\n"); + ; } static void __init synchronize_tsc_ap (void) @@ -365,7 +371,7 @@ * (This works even if the APIC is not enabled.) */ phys_id = GET_APIC_ID(apic_read(APIC_ID)); - cpuid = current->processor; + cpuid = cpu(); if (test_and_set_bit(cpuid, &cpu_online_map)) { printk("huh, phys CPU#%d, CPU#%d already present??\n", phys_id, cpuid); @@ -430,11 +436,17 @@ calibrate_delay(); Dprintk("Stack at about %p\n",&cpuid); + disable_APIC_timer(); /* * Save our processor parameters */ smp_store_cpu_info(cpuid); +#ifdef CONFIG_KDB + /* Activate any preset global breakpoints on this cpu */ + kdb(KDB_REASON_SILENT, 0, 0); +#endif /* CONFIG_KDB */ + /* * Allow the master to continue. */ @@ -465,6 +477,7 @@ smp_callin(); while (!atomic_read(&smp_commenced)) rep_nop(); + enable_APIC_timer(); /* * low-memory mappings have been cleared, flush them from * the local TLBs too. @@ -803,16 +816,13 @@ if (!idle) panic("No idle process for CPU %d", cpu); - idle->processor = cpu; - idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + init_idle(idle, cpu); map_cpu_to_boot_apicid(cpu, apicid); idle->thread.eip = (unsigned long) start_secondary; - del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpu] = idle; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); @@ -925,6 +935,7 @@ } cycles_t cacheflush_time; +unsigned long cache_decay_ticks; static void smp_tune_scheduling (void) { @@ -958,9 +969,13 @@ cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth; } + cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000; + printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", (long)cacheflush_time/(cpu_khz/1000), ((long)cacheflush_time*100/(cpu_khz/1000)) % 100); + printk("task migration cache decay timeout: %ld msecs.\n", + (cache_decay_ticks + 1) * 1000 / HZ); } /* @@ -1023,8 +1038,7 @@ map_cpu_to_boot_apicid(0, boot_cpu_apicid); global_irq_holder = 0; - current->processor = 0; - init_idle(); + current->cpu = 0; smp_tune_scheduling(); /* diff -Nur linux-2.4.19/arch/i386/kernel/time.c linux-2.4.19-sgi211r3/arch/i386/kernel/time.c --- linux-2.4.19/arch/i386/kernel/time.c Mon Feb 25 11:37:53 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/time.c Mon Oct 28 09:18:11 2002 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -78,7 +79,7 @@ */ unsigned long fast_gettimeoffset_quotient; -extern rwlock_t xtime_lock; +extern frlock_t xtime_lock; extern unsigned long wall_jiffies; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -265,19 +266,21 @@ */ void do_gettimeofday(struct timeval *tv) { - unsigned long flags; + unsigned long seq; unsigned long usec, sec; - read_lock_irqsave(&xtime_lock, flags); - usec = do_gettimeoffset(); - { - unsigned long lost = jiffies - wall_jiffies; - if (lost) - usec += lost * (1000000 / HZ); - } - sec = xtime.tv_sec; - usec += xtime.tv_usec; - read_unlock_irqrestore(&xtime_lock, flags); + do { + seq = fr_read_begin(&xtime_lock); + usec = do_gettimeoffset(); + { + unsigned long lost = jiffies - wall_jiffies; + if (lost) + usec += lost * (1000000 / HZ); + } + + sec = xtime.tv_sec; + usec += xtime.tv_usec; + } while (seq != fr_read_end(&xtime_lock)); while (usec >= 1000000) { usec -= 1000000; @@ -290,7 +293,7 @@ void do_settimeofday(struct timeval *tv) { - write_lock_irq(&xtime_lock); + fr_write_lock_irq(&xtime_lock); /* * This is revolting. We need to set "xtime" correctly. However, the * value in this location is the value at the most recent update of @@ -310,7 +313,7 @@ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - write_unlock_irq(&xtime_lock); + fr_write_unlock_irq(&xtime_lock); } /* @@ -476,7 +479,7 @@ * the irq version of write_lock because as just said we have irq * locally disabled. -arca */ - write_lock(&xtime_lock); + fr_write_lock(&xtime_lock); if (use_tsc) { @@ -509,7 +512,7 @@ do_timer_interrupt(irq, NULL, regs); - write_unlock(&xtime_lock); + fr_write_unlock(&xtime_lock); } diff -Nur linux-2.4.19/arch/i386/kernel/traps.c linux-2.4.19-sgi211r3/arch/i386/kernel/traps.c --- linux-2.4.19/arch/i386/kernel/traps.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/kernel/traps.c Tue Feb 4 15:36:30 2003 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,10 @@ #include #endif +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ + #include #include #include @@ -51,6 +56,9 @@ #include asmlinkage int system_call(void); +#ifdef CONFIG_KDB +asmlinkage int kdb_call(void); +#endif /* CONFIG_KDB */ asmlinkage void lcall7(void); asmlinkage void lcall27(void); @@ -79,6 +87,9 @@ asmlinkage void stack_segment(void); asmlinkage void general_protection(void); asmlinkage void page_fault(void); +#ifdef CONFIG_KDB +asmlinkage void page_fault_mca(void); +#endif /* CONFIG_KDB */ asmlinkage void coprocessor_error(void); asmlinkage void simd_coprocessor_error(void); asmlinkage void alignment_check(void); @@ -88,6 +99,108 @@ int kstack_depth_to_print = 24; +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#ifdef CONFIG_SMP +void (*dump_trace_ptr)(struct pt_regs *) = NULL; +/* + * This code mimics show_trace() etc in arch/i386/kernel/traps.c. We don't + * use them directly as they depend on 8K aligned kernel stacks that our + * saved stacks don't satisfy. However, there is move to relax the requirement + * on task_struct to be 8K-aligned. Once that happens, we could simpify this + * function. + */ +void show_this_cpu_state(int cpu, struct pt_regs * regs, struct task_struct *tsk) +{ + int i; + unsigned long *esp; + unsigned char *c; + int in_kernel = 1; + + esp = (unsigned long *)regs->esp; + c = (unsigned char *)regs->eip; + + if (regs->xcs & 3) { + in_kernel = 0; + } + printk("CPU: %d\nEIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", + cpu, 0xffff & regs->xcs, regs->eip, regs->eflags); + printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk("esi: %08lx edi: %08lx ebp: %08lx esp: %p\n", + regs->esi, regs->edi, regs->ebp, esp); + printk("ds: %04x es: %04x ss: %04x\n", + regs->xds & 0xffff, regs->xes & 0xffff, regs->xss & 0xffff); + if (!tsk) { + printk("no stack for this cpu\n"); + return; + } + printk("Process %s (pid: %d, stackpage=%08lx)", + tsk->comm, tsk->pid, 4096+(regs->esp & ~(THREAD_SIZE-1))); + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (in_kernel) { + unsigned long *stack; + unsigned long addr, module_start, module_end; + extern char _stext, _etext; + + extern int kstack_depth_to_print; + + esp = (unsigned long *)((unsigned long)tsk + (regs->esp & (THREAD_SIZE-1))); + + printk("\nStack: "); + stack = esp; + for(i=0; i < kstack_depth_to_print; i++) { + if ((unsigned long)stack > (unsigned long)tsk + THREAD_SIZE-1) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + + printk("\nCall Trace: "); + i = 1; + stack = esp; + module_start = VMALLOC_START; + module_end = VMALLOC_END; + module_end = 0; + while ((unsigned long)stack < (unsigned long)tsk + THREAD_SIZE) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } + printk("\n"); + + printk("\nCode: "); + if(regs->eip < PAGE_OFFSET) { + printk("eip in user space. error.\n"); + } + + for(i=0;i<20;i++) { + printk("%02x ", *c++); + } + } + printk("\n"); + return; +} +#endif /* CONFIG_SMP */ +#endif /* CONFIG_DUMP */ + /* * If the address is either in the .text section of the * kernel, or in the vmalloc'ed module regions, it *may* @@ -139,15 +252,16 @@ if (!stack) stack = (unsigned long*)&stack; - printk("Call Trace: "); + printk("Call Trace:"); +#if CONFIG_KALLSYMS + printk("\n"); +#endif i = 1; while (((long) stack & (THREAD_SIZE-1)) != 0) { addr = *stack++; if (kernel_text_address(addr)) { - if (i && ((i % 6) == 0)) - printk("\n "); - printk(" [<%08lx>]", addr); - i++; + printk(" [<%08lx>] ", addr); + print_symbol("%s\n", addr); } } printk("\n"); @@ -186,6 +300,14 @@ show_trace(esp); } +/* + * The architecture-independent backtrace generator + */ +void dump_stack(void) +{ + show_stack(0); +} + void show_registers(struct pt_regs *regs) { int i; @@ -200,8 +322,11 @@ esp = regs->esp; ss = regs->xss & 0xffff; } + print_modules(); printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n", smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags); + + print_symbol("EIP is at %s\n", regs->eip); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", @@ -219,7 +344,7 @@ printk("\nStack: "); show_stack((unsigned long*)esp); - printk("\nCode: "); + printk("Code: "); if(regs->eip < PAGE_OFFSET) goto bad; @@ -284,6 +409,11 @@ show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); +#ifdef CONFIG_KDB + kdb_diemsg = str; + kdb(KDB_REASON_OOPS, err, regs); +#endif /* CONFIG_KDB */ + dump((char *)str, regs); do_exit(SIGSEGV); } @@ -372,7 +502,9 @@ } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +#ifndef CONFIG_KDB DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) +#endif /* !CONFIG_KDB */ DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) @@ -439,6 +571,23 @@ outb(reason, 0x61); } +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#ifdef CONFIG_SMP +int (*dump_ipi_function_ptr)(struct pt_regs *) = NULL; +static int dump_ipi(struct pt_regs *regs) +{ + if (!(dump_ipi_function_ptr && dump_ipi_function_ptr(regs))) { + return 0; + } + ack_APIC_irq(); + return 1; +} +#else +#define dump_ipi(regs) 0 +#endif +#endif + + static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) { #ifdef CONFIG_MCA @@ -449,17 +598,43 @@ return; } #endif +#ifdef CONFIG_KDB + (void)kdb(KDB_REASON_NMI, reason, regs); +#endif /* CONFIG_KDB */ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); printk("Dazed and confused, but trying to continue\n"); printk("Do you have a strange power saving mode enabled?\n"); } +#if defined(CONFIG_SMP) && defined(CONFIG_KDB) +static void +do_ack_apic_irq(void) +{ + ack_APIC_irq(); +} +#endif /* defined(CONFIG_SMP) && defined(CONFIG_KDB) */ + asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { unsigned char reason = inb(0x61); ++nmi_count(smp_processor_id()); +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + if (dump_ipi(regs)) { + return; + } +#endif + +#if defined(CONFIG_SMP) && defined(CONFIG_KDB) + /* + * Call the kernel debugger to see if this NMI is due + * to an KDB requested IPI. If so, kdb will handle it. + */ + if (kdb_ipi(regs, do_ack_apic_irq)) { + return; + } +#endif /* defined(CONFIG_SMP) && defined(CONFIG_KDB) */ if (!(reason & 0xc0)) { #if CONFIG_X86_LOCAL_APIC /* @@ -518,6 +693,11 @@ __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); +#ifdef CONFIG_KDB + if (kdb(KDB_REASON_DEBUG, error_code, regs)) + return; +#endif /* CONFIG_KDB */ + /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) @@ -579,6 +759,16 @@ return; } +#ifdef CONFIG_KDB +asmlinkage void do_int3(struct pt_regs * regs, long error_code) +{ + if (kdb(KDB_REASON_BREAK, error_code, regs)) + return; + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); +} +#endif /* CONFIG_KDB */ + + /* * Note that we play around with the 'TS' bit in an attempt to get * the correct behaviour even in the presence of the asynchronous @@ -977,7 +1167,17 @@ set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); +#ifdef CONFIG_KDB + if (test_bit(X86_FEATURE_MCE, boot_cpu_data.x86_capability) && + test_bit(X86_FEATURE_MCA, boot_cpu_data.x86_capability)) { + set_intr_gate(14,&page_fault_mca); + } + else { + set_intr_gate(14,&page_fault); + } +#else /* !CONFIG_KDB */ set_intr_gate(14,&page_fault); +#endif /* CONFIG_KDB */ set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); @@ -985,6 +1185,17 @@ set_trap_gate(19,&simd_coprocessor_error); set_system_gate(SYSCALL_VECTOR,&system_call); +#ifdef CONFIG_KDB + { + set_trap_gate(18, &machine_check); + } + kdb_enablehwfault(); + /* + * A trap gate, used by the kernel to enter the + * debugger, preserving all registers. + */ + set_trap_gate(KDBENTER_VECTOR, &kdb_call); +#endif /* CONFIG_KDB */ /* * default LDT is a single-entry callgate to lcall7 for iBCS diff -Nur linux-2.4.19/arch/i386/mm/fault.c linux-2.4.19-sgi211r3/arch/i386/mm/fault.c --- linux-2.4.19/arch/i386/mm/fault.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/mm/fault.c Mon Oct 28 20:43:23 2002 @@ -86,8 +86,7 @@ out_of_memory: if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); goto survive; } goto bad_area; @@ -336,8 +335,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -Nur linux-2.4.19/arch/i386/mm/init.c linux-2.4.19-sgi211r3/arch/i386/mm/init.c --- linux-2.4.19/arch/i386/mm/init.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/i386/mm/init.c Thu Oct 24 04:22:20 2002 @@ -415,7 +415,11 @@ } } +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +int page_is_ram (unsigned long pagenr) +#else static inline int page_is_ram (unsigned long pagenr) +#endif { int i; diff -Nur linux-2.4.19/arch/i386/vmlinux.lds linux-2.4.19-sgi211r3/arch/i386/vmlinux.lds --- linux-2.4.19/arch/i386/vmlinux.lds Mon Feb 25 11:37:53 2002 +++ linux-2.4.19-sgi211r3/arch/i386/vmlinux.lds Mon Dec 9 14:58:33 2002 @@ -28,6 +28,10 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + .data : { /* Data */ *(.data) CONSTRUCTORS @@ -46,6 +50,9 @@ __setup_start = .; .setup.init : { *(.setup.init) } __setup_end = .; + __kdb_initcall_start = .; + .kdb_initcall.init : { *(.kdb_initcall.init) } + __kdb_initcall_end = .; __initcall_start = .; .initcall.init : { *(.initcall.init) } __initcall_end = .; @@ -69,6 +76,7 @@ *(.text.exit) *(.data.exit) *(.exitcall.exit) + *(.kdb_exitcall.exit) } /* Stabs debugging sections. */ diff -Nur linux-2.4.19/arch/ia64/Makefile linux-2.4.19-sgi211r3/arch/ia64/Makefile --- linux-2.4.19/arch/ia64/Makefile Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/Makefile Thu Dec 19 15:59:36 2002 @@ -22,10 +22,14 @@ # -ffunction-sections CFLAGS_KERNEL := -mconstant-gp -GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') +# Temp - Make stacks executable. For RH7.2 compatiblity. Delete when +# RH release is upgraded to a 2.4.17 (or above) kernel. +CFLAGS += -DSGI_SN_EXECUTABLE_STACKS + +GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') ifneq ($(GCC_VERSION),2) - CFLAGS += -frename-registers --param max-inline-insns=2000 + CFLAGS += -frename-registers --param max-inline-insns=5000 endif ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y) @@ -33,16 +37,11 @@ endif ifdef CONFIG_IA64_GENERIC - CORE_FILES := arch/$(ARCH)/hp/hp.a \ - arch/$(ARCH)/sn/sn.o \ - arch/$(ARCH)/dig/dig.a \ - arch/$(ARCH)/sn/io/sgiio.o \ + CORE_FILES := arch/$(ARCH)/hp/hp.o \ + arch/$(ARCH)/dig/dig.a \ $(CORE_FILES) SUBDIRS := arch/$(ARCH)/hp \ - arch/$(ARCH)/sn/sn1 \ - arch/$(ARCH)/sn \ arch/$(ARCH)/dig \ - arch/$(ARCH)/sn/io \ $(SUBDIRS) else # !GENERIC @@ -50,12 +49,22 @@ ifdef CONFIG_IA64_HP_SIM SUBDIRS := arch/$(ARCH)/hp \ $(SUBDIRS) - CORE_FILES := arch/$(ARCH)/hp/hp.a \ + CORE_FILES := arch/$(ARCH)/hp/hp.o \ + $(CORE_FILES) +endif + +ifdef CONFIG_IA64_HP_ZX1 + SUBDIRS := arch/$(ARCH)/hp \ + arch/$(ARCH)/dig \ + $(SUBDIRS) + CORE_FILES := arch/$(ARCH)/hp/hp.o \ + arch/$(ARCH)/dig/dig.a \ $(CORE_FILES) endif ifdef CONFIG_IA64_SGI_SN CFLAGS += -DBRINGUP + AFLAGS += -DBRINGUP SUBDIRS := arch/$(ARCH)/sn/kernel \ arch/$(ARCH)/sn/io \ arch/$(ARCH)/sn/fakeprom \ @@ -65,6 +74,16 @@ $(CORE_FILES) endif +ifdef CONFIG_IA64_SGI_SN2 +ifdef CONFIG_SHUB_1_0_SPECIFIC + CFLAGS += -DBRINGUP2 -DII_PRTE_TLB_WAR -DBUS_INT_WAR -DLED_WAR -DPTCG_WAR + AFLAGS += -DBRINGUP2 -DII_PRTE_TLB_WAR -DBUS_INT_WAR -DLED_WAR -DPTCG_WAR +else + CFLAGS += -DBRINGUP2 -DII_INT0_WAR + AFLAGS += -DBRINGUP2 -DII_INT0_WAR +endif +endif + ifdef CONFIG_IA64_SOFTSDV SUBDIRS := arch/$(ARCH)/dig \ $(SUBDIRS) @@ -86,6 +105,11 @@ CORE_FILES := arch/$(ARCH)/ia32/ia32.o $(CORE_FILES) endif +ifdef CONFIG_KDB + LIBS := $(LIBS) $(TOPDIR)/arch/$(ARCH)/kdb/kdba.o + SUBDIRS := $(SUBDIRS) arch/$(ARCH)/kdb +endif + HEAD := arch/$(ARCH)/kernel/head.o arch/ia64/kernel/init_task.o SUBDIRS := arch/$(ARCH)/tools arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/lib $(SUBDIRS) @@ -105,7 +129,7 @@ FORCE: ; compressed: vmlinux - $(OBJCOPY) --strip-all vmlinux vmlinux-tmp + $(OBJCOPY) --strip-debug vmlinux vmlinux-tmp gzip vmlinux-tmp mv vmlinux-tmp.gz vmlinux.gz diff -Nur linux-2.4.19/arch/ia64/boot/Makefile linux-2.4.19-sgi211r3/arch/ia64/boot/Makefile --- linux-2.4.19/arch/ia64/boot/Makefile Thu Jan 4 12:50:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/boot/Makefile Wed Oct 16 14:02:58 2002 @@ -27,6 +27,6 @@ -o bootloader clean: - rm -f $(TARGETS) + rm -f $(targets-y) $(OBJECTS) dep: diff -Nur linux-2.4.19/arch/ia64/config.in linux-2.4.19-sgi211r3/arch/ia64/config.in --- linux-2.4.19/arch/ia64/config.in Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/config.in Thu Feb 20 19:55:58 2003 @@ -26,29 +26,32 @@ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n -if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then - define_bool CONFIG_ACPI y - define_bool CONFIG_ACPI_EFI y - define_bool CONFIG_ACPI_INTERPRETER y - define_bool CONFIG_ACPI_KERNEL_CONFIG y -fi - choice 'IA-64 processor type' \ - "Itanium CONFIG_ITANIUM \ - McKinley CONFIG_MCKINLEY" Itanium + "Itanium CONFIG_ITANIUM \ + Itanium-2 CONFIG_MCKINLEY" Itanium choice 'IA-64 system type' \ "generic CONFIG_IA64_GENERIC \ DIG-compliant CONFIG_IA64_DIG \ HP-simulator CONFIG_IA64_HP_SIM \ + HP-zx1 CONFIG_IA64_HP_ZX1 \ SGI-SN1 CONFIG_IA64_SGI_SN1 \ SGI-SN2 CONFIG_IA64_SGI_SN2" generic -choice 'Kernel page size' \ +if [ "$CONFIG_ITANIUM" = "y" ]; then + choice 'Kernel page size' \ + "4KB CONFIG_IA64_PAGE_SIZE_4KB \ + 8KB CONFIG_IA64_PAGE_SIZE_8KB \ + 16KB CONFIG_IA64_PAGE_SIZE_16KB" 16KB +else + choice 'Kernel page size' \ "4KB CONFIG_IA64_PAGE_SIZE_4KB \ 8KB CONFIG_IA64_PAGE_SIZE_8KB \ 16KB CONFIG_IA64_PAGE_SIZE_16KB \ 64KB CONFIG_IA64_PAGE_SIZE_64KB" 16KB +fi + +bool 'Virtually mapped mem_map?' CONFIG_VIRTUAL_MEM_MAP n if [ "$CONFIG_ITANIUM" = "y" ]; then define_bool CONFIG_IA64_BRL_EMU y @@ -68,27 +71,40 @@ fi fi -if [ "$CONFIG_IA64_DIG" = "y" ]; then +if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ]; then + bool ' Enable NUMA support' CONFIG_NUMA + if [ "$CONFIG_NUMA" = "y" ]; then + define_bool CONFIG_DISCONTIGMEM y + define_bool CONFIG_NUMA_REPLICATE y + fi bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA define_bool CONFIG_PM y + define_bool CONFIG_IA64_HAVE_SYNCHRONIZED_ITC y + bool ' Enable DEVFS (EXPERIMENTAL)' CONFIG_DEVFS_FS + if [ "$CONFIG_DEVFS_FS" = "y" ]; then + bool ' Enable DEVFS Debug' CONFIG_DEVFS_DEBUG + fi fi -if [ "$CONFIG_IA64_SGI_SN1" = "y" ] || [ "$CONFIG_IA64_SGI_SN2" = "y" ]; then +if [ "$CONFIG_IA64_SGI_SN1" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ]; then define_bool CONFIG_IA64_SGI_SN y - bool ' Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG n + bool ' Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN_SIM bool ' Enable autotest (llsc). Option to run cache test instead of booting' \ - CONFIG_IA64_SGI_AUTOTEST n + CONFIG_IA64_SGI_AUTOTEST + bool ' Enable SHUB 1.0 specific support' CONFIG_SHUB_1_0_SPECIFIC define_bool CONFIG_DEVFS_FS y if [ "$CONFIG_DEVFS_FS" = "y" ]; then - bool ' Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG n + bool ' Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG fi - bool ' Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL y define_bool CONFIG_DISCONTIGMEM y define_bool CONFIG_IA64_MCA y define_bool CONFIG_NUMA y + define_bool CONFIG_NUMA_REPLICATE y define_bool CONFIG_PERCPU_IRQ y + define_bool CONFIG_IA64_HAVE_SYNCHRONIZED_ITC n tristate ' PCIBA support' CONFIG_PCIBA + tristate 'Block Transfer Engine Test' CONFIG_IA64_SGI_SN_BRT fi define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore. @@ -100,28 +116,38 @@ tristate '/proc/efi/vars support' CONFIG_EFI_VARS bool 'Networking support' CONFIG_NET +bool 'CpuMemSet support' CONFIG_CPUMEMSET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +bool 'Support for process aggregates (PAGGs)' CONFIG_PAGG +if [ "$CONFIG_PAGG" = "y" ] ; then + tristate ' Process aggregate based jobs' CONFIG_PAGG_JOB + dep_tristate ' CSA Job Accounting' CONFIG_CSA_JOB_ACCT $CONFIG_PAGG_JOB +fi tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then +if [ "$CONFIG_IA64_HP_SIM" = "y" ]; then + define_bool CONFIG_IA64_HAVE_SYNCHRONIZED_ITC y +fi -source drivers/acpi/Config.in -bool 'PCI support' CONFIG_PCI -source drivers/pci/Config.in +if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + source drivers/acpi/Config.in -bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG -if [ "$CONFIG_HOTPLUG" = "y" ]; then - source drivers/pcmcia/Config.in -else - define_bool CONFIG_PCMCIA n -fi + bool 'PCI support' CONFIG_PCI + source drivers/pci/Config.in -source drivers/parport/Config.in + bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + if [ "$CONFIG_HOTPLUG" = "y" ]; then + source drivers/hotplug/Config.in + source drivers/pcmcia/Config.in + else + define_bool CONFIG_PCMCIA n + fi + source drivers/parport/Config.in fi # !HP_SIM endmenu @@ -131,29 +157,48 @@ fi if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + source drivers/mtd/Config.in + source drivers/pnp/Config.in + source drivers/block/Config.in + source drivers/ieee1394/Config.in + source drivers/message/i2o/Config.in + source drivers/md/Config.in + source drivers/message/fusion/Config.in -source drivers/mtd/Config.in -source drivers/pnp/Config.in -source drivers/block/Config.in -source drivers/ieee1394/Config.in -source drivers/message/i2o/Config.in -source drivers/md/Config.in + mainmenu_option next_comment + comment 'ATA/IDE/MFM/RLL support' -mainmenu_option next_comment -comment 'ATA/IDE/MFM/RLL support' + tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE + + if [ "$CONFIG_IDE" != "n" ]; then + source drivers/ide/Config.in + else + define_bool CONFIG_BLK_DEV_IDE_MODES n + define_bool CONFIG_BLK_DEV_HD n + fi + endmenu +else # HP_SIM + mainmenu_option next_comment + comment 'Block devices' + tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP + dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET + + tristate 'RAM disk support' CONFIG_BLK_DEV_RAM + if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 + fi + endmenu +fi # HP_SIM -tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE +mainmenu_option next_comment +comment 'Alternate SCSI support' -if [ "$CONFIG_IDE" != "n" ]; then - source drivers/ide/Config.in -else - define_bool CONFIG_BLK_DEV_IDE_MODES n - define_bool CONFIG_BLK_DEV_HD n +bool 'Alternate SCSI drivers' CONFIG_XSCSI +if [ "$CONFIG_XSCSI" != "n" ]; then + source drivers/xscsi/Config.in fi endmenu -fi # !HP_SIM - mainmenu_option next_comment comment 'SCSI support' @@ -164,43 +209,37 @@ fi endmenu -if [ "$CONFIG_PCI" = "y" ]; then - source drivers/message/fusion/Config.in -fi - if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + fi + endmenu + fi + + source net/ax25/Config.in -if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment - comment 'Network device support' + comment 'ISDN subsystem' - bool 'Network device support' CONFIG_NETDEVICES - if [ "$CONFIG_NETDEVICES" = "y" ]; then - source drivers/net/Config.in + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in fi endmenu -fi - -source net/ax25/Config.in -mainmenu_option next_comment -comment 'ISDN subsystem' - -tristate 'ISDN support' CONFIG_ISDN -if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in -fi -endmenu - -mainmenu_option next_comment -comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' - -bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI -if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then - source drivers/cdrom/Config.in -fi -endmenu + mainmenu_option next_comment + comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' + bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI + if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in + fi + endmenu fi # !HP_SIM # @@ -209,7 +248,7 @@ source drivers/input/Config.in source drivers/char/Config.in -#source drivers/misc/Config.in +source drivers/misc/Config.in source drivers/media/Config.in @@ -227,22 +266,20 @@ fi if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + mainmenu_option next_comment + comment 'Sound' -mainmenu_option next_comment -comment 'Sound' - -tristate 'Sound card support' CONFIG_SOUND -if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in -fi -endmenu - -source drivers/usb/Config.in + tristate 'Sound card support' CONFIG_SOUND + if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in + fi + endmenu -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi + source drivers/usb/Config.in + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + source net/bluetooth/Config.in + fi fi # !HP_SIM if [ "$CONFIG_IA64_HP_SIM" != "n" -o "$CONFIG_IA64_GENERIC" != "n" ]; then @@ -265,17 +302,46 @@ "16MB CONFIG_IA64_GRANULE_16MB \ 64MB CONFIG_IA64_GRANULE_64MB" 64MB +tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP +if [ "$CONFIG_DUMP" = "y" ]; then + dep_bool ' LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP + dep_bool ' LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP +fi +if [ "$CONFIG_DUMP" = "m" ]; then + dep_tristate ' LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP + dep_tristate ' LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP +fi + bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then bool ' Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS bool ' Disable VHPT' CONFIG_DISABLE_VHPT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ - bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK + bool ' Early printk support' CONFIG_IA64_EARLY_PRINTK + if [ "$CONFIG_IA64_EARLY_PRINTK" != "n" ]; then + bool ' Early printk on MMIO serial port' CONFIG_IA64_EARLY_PRINTK_UART + if [ "$CONFIG_IA64_EARLY_PRINTK_UART" != "n" ]; then + hex ' UART MMIO base address' CONFIG_IA64_EARLY_PRINTK_UART_BASE 0 + fi + bool ' Early printk on VGA' CONFIG_IA64_EARLY_PRINTK_VGA + fi bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG bool ' Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ + bool ' Built-in Kernel Debugger support' CONFIG_KDB + dep_tristate ' KDB modules' CONFIG_KDB_MODULES $CONFIG_KDB + if [ "$CONFIG_KDB" = "y" ]; then + bool ' KDB off by default' CONFIG_KDB_OFF + if [ "$CONFIG_USB" != "n" ] ; then + bool ' Support for USB Keyboard in KDB' CONFIG_KDB_USB + fi + comment ' Load all symbols for debugging is required for KDB' + define_bool CONFIG_KALLSYMS y + else + bool ' Load all symbols for debugging' CONFIG_KALLSYMS + fi fi endmenu diff -Nur linux-2.4.19/arch/ia64/defconfig linux-2.4.19-sgi211r3/arch/ia64/defconfig --- linux-2.4.19/arch/ia64/defconfig Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/defconfig Wed Oct 16 14:02:58 2002 @@ -24,21 +24,18 @@ # CONFIG_SBUS is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y CONFIG_ITANIUM=y # CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y +CONFIG_IA64_GENERIC=y +# CONFIG_IA64_DIG is not set # CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set # CONFIG_IA64_SGI_SN1 is not set # CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_PAGE_SIZE_4KB is not set # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_VIRTUAL_MEM_MAP=y CONFIG_IA64_BRL_EMU=y # CONFIG_ITANIUM_BSTEP_SPECIFIC is not set CONFIG_IA64_L1_CACHE_SHIFT=6 @@ -56,15 +53,27 @@ CONFIG_SYSCTL=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y + +# +# ACPI Support +# +CONFIG_ACPI_PCI=y +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUS=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y # CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_PROCESSOR is not set # CONFIG_ACPI_THERMAL is not set +# CONFIG_ACPI_DEBUG is not set CONFIG_PCI=y CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set @@ -80,7 +89,7 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set CONFIG_FILTER=y CONFIG_UNIX=y @@ -90,6 +99,7 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -102,6 +112,11 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -119,6 +134,11 @@ # CONFIG_NET_SCHED is not set # +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# # Memory Technology Devices (MTD) # # CONFIG_MTD is not set @@ -137,13 +157,20 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set # +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# # I2O device support # # CONFIG_I2O is not set @@ -166,6 +193,15 @@ # CONFIG_BLK_DEV_LVM is not set # +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_BOOT=y +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# # ATA/IDE/MFM/RLL support # CONFIG_IDE=y @@ -182,6 +218,7 @@ # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set # CONFIG_BLK_DEV_IDEDISK_IBM is not set @@ -196,6 +233,7 @@ # CONFIG_BLK_DEV_IDETAPE is not set CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y +# CONFIG_IDE_TASK_IOCTL is not set # # IDE chipset support/bugfixes @@ -207,12 +245,15 @@ CONFIG_BLK_DEV_IDEPCI=y CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set # CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_IDEDMA_ONLYDISK is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_AEC62XX_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set @@ -220,6 +261,7 @@ # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set @@ -278,8 +320,12 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AACRAID is not set +CONFIG_SCSI_AIC7XXX=y +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_PROBE_EISA_VL is not set +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set @@ -299,9 +345,11 @@ # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_SYM53C8XX_2 is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -331,6 +379,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -340,7 +389,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -353,7 +401,10 @@ # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set -# CONFIG_TULIP is not set +CONFIG_TULIP=y +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set @@ -369,6 +420,7 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -382,12 +434,15 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set # CONFIG_DL2K is not set # CONFIG_MYRI_SBUS is not set +CONFIG_E1000=y # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set +CONFIG_TIGON3=y # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PLIP is not set @@ -445,8 +500,9 @@ CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_ACPI is not set +CONFIG_SERIAL_HCDP=y # CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_ACPI is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 @@ -464,6 +520,7 @@ CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set # # Joysticks @@ -519,16 +576,20 @@ # CONFIG_FTAPE is not set CONFIG_AGP=y # CONFIG_AGP_INTEL is not set -CONFIG_AGP_I460=y # CONFIG_AGP_I810 is not set # CONFIG_AGP_VIA is not set # CONFIG_AGP_AMD is not set # CONFIG_AGP_SIS is not set # CONFIG_AGP_ALI is not set # CONFIG_AGP_SWORKS is not set +CONFIG_AGP_I460=y +CONFIG_AGP_HP_ZX1=y CONFIG_DRM=y -# CONFIG_DRM_NEW is not set CONFIG_DRM_OLD=y + +# +# DRM 4.0 drivers +# CONFIG_DRM40_TDFX=y # CONFIG_DRM40_GAMMA is not set # CONFIG_DRM40_R128 is not set @@ -607,7 +668,7 @@ # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set -# CONFIG_RAMFS is not set +CONFIG_RAMFS=y CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set @@ -671,12 +732,11 @@ # CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_EFI_PARTITION=y -# CONFIG_DEVFS_GUID is not set # CONFIG_LDM_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y # CONFIG_SMB_NLS is not set CONFIG_NLS=y @@ -705,6 +765,7 @@ # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set @@ -737,6 +798,7 @@ CONFIG_SOUND=y # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_FORTE is not set # CONFIG_SOUND_EMU10K1 is not set # CONFIG_MIDI_EMU10K1 is not set # CONFIG_SOUND_FUSION is not set @@ -771,8 +833,9 @@ # CONFIG_USB_LONG_TIMEOUT is not set # -# USB Controllers +# USB Host Controller Drivers # +CONFIG_USB_EHCI_HCD=m CONFIG_USB_UHCI=m # CONFIG_USB_UHCI_ALT is not set # CONFIG_USB_OHCI is not set @@ -781,6 +844,7 @@ # USB Device Class drivers # # CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set # CONFIG_USB_BLUETOOTH is not set # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set @@ -798,6 +862,7 @@ # USB Human Interface Devices (HID) # CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y CONFIG_USB_HIDDEV=y CONFIG_USB_KBD=m CONFIG_USB_MOUSE=m @@ -819,6 +884,8 @@ # CONFIG_USB_OV511 is not set # CONFIG_USB_PWC is not set # CONFIG_USB_SE401 is not set +# CONFIG_USB_STV680 is not set +# CONFIG_USB_VICAM is not set # CONFIG_USB_DSBR is not set # CONFIG_USB_DABUSB is not set @@ -826,6 +893,7 @@ # USB Network adaptors # # CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set # CONFIG_USB_CDCETHER is not set @@ -847,6 +915,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -860,6 +929,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set @@ -869,6 +939,8 @@ # USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set # # Bluetooth support @@ -876,6 +948,13 @@ # CONFIG_BLUEZ is not set # +# Simulated drivers +# +# CONFIG_SIMETH is not set +# CONFIG_SIM_SERIAL is not set +# CONFIG_SCSI_SIM is not set + +# # Kernel hacking # # CONFIG_IA64_GRANULE_16MB is not set @@ -885,7 +964,19 @@ # CONFIG_DISABLE_VHPT is not set CONFIG_MAGIC_SYSRQ=y CONFIG_IA64_EARLY_PRINTK=y +CONFIG_IA64_EARLY_PRINTK_UART=y +CONFIG_IA64_EARLY_PRINTK_UART_BASE=0 +# CONFIG_IA64_EARLY_PRINTK_VGA is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set diff -Nur linux-2.4.19/arch/ia64/dig/machvec.c linux-2.4.19-sgi211r3/arch/ia64/dig/machvec.c --- linux-2.4.19/arch/ia64/dig/machvec.c Fri Aug 11 19:09:06 2000 +++ linux-2.4.19-sgi211r3/arch/ia64/dig/machvec.c Fri Feb 1 11:39:38 2002 @@ -1,2 +1,5 @@ #define MACHVEC_PLATFORM_NAME dig #include +#include +void * +__ia64_mk_io_addr_MACRO diff -Nur linux-2.4.19/arch/ia64/dig/setup.c linux-2.4.19-sgi211r3/arch/ia64/dig/setup.c --- linux-2.4.19/arch/ia64/dig/setup.c Thu Apr 5 12:51:47 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/dig/setup.c Fri Apr 26 11:07:18 2002 @@ -33,8 +33,7 @@ * is sufficient (the IDE driver will autodetect the drive geometry). */ char drive_info[4*16]; - -unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */ +extern int pcat_compat; void __init dig_setup (char **cmdline_p) @@ -81,13 +80,7 @@ screen_info.orig_video_ega_bx = 3; /* XXX fake */ } -void +void __init dig_irq_init (void) { - /* - * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support - * enabled. - */ - outb(0xff, 0xA1); - outb(0xff, 0x21); } diff -Nur linux-2.4.19/arch/ia64/hp/Makefile linux-2.4.19-sgi211r3/arch/ia64/hp/Makefile --- linux-2.4.19/arch/ia64/hp/Makefile Thu Jan 4 12:50:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/Makefile Fri Apr 26 11:07:18 2002 @@ -1,17 +1,15 @@ -# -# ia64/platform/hp/Makefile -# -# Copyright (C) 1999 Silicon Graphics, Inc. -# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) -# +# arch/ia64/hp/Makefile +# Copyright (c) 2002 Matthew Wilcox for Hewlett Packard -all: hp.a +ALL_SUB_DIRS := sim zx1 common -O_TARGET := hp.a +O_TARGET := hp.o -obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o -obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o +subdir-$(CONFIG_IA64_GENERIC) += $(ALL_SUB_DIRS) +subdir-$(CONFIG_IA64_HP_SIM) += sim +subdir-$(CONFIG_IA64_HP_ZX1) += zx1 common -clean:: +SUB_DIRS := $(subdir-y) +obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/hp/common/Makefile linux-2.4.19-sgi211r3/arch/ia64/hp/common/Makefile --- linux-2.4.19/arch/ia64/hp/common/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/common/Makefile Fri Apr 26 11:07:18 2002 @@ -0,0 +1,14 @@ +# +# ia64/platform/hp/common/Makefile +# +# Copyright (C) 2002 Hewlett Packard +# Copyright (C) Alex Williamson (alex_williamson@hp.com) +# + +O_TARGET := common.o + +export-objs := sba_iommu.o + +obj-y := sba_iommu.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/hp/common/sba_iommu.c linux-2.4.19-sgi211r3/arch/ia64/hp/common/sba_iommu.c --- linux-2.4.19/arch/ia64/hp/common/sba_iommu.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/common/sba_iommu.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1867 @@ +/* +** IA64 System Bus Adapter (SBA) I/O MMU manager +** +** (c) Copyright 2002 Alex Williamson +** (c) Copyright 2002 Hewlett-Packard Company +** +** Portions (c) 2000 Grant Grundler (from parisc I/O MMU code) +** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** +** This module initializes the IOC (I/O Controller) found on HP +** McKinley machines and their successors. +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* ia64_get_itc() */ +#include +#include /* PAGE_OFFSET */ + + +#define PFX "IOC: " + +#define ALLOW_IOV_BYPASS +#define ENABLE_MARK_CLEAN +/* +** The number of debug flags is a clue - this code is fragile. +*/ +#undef DEBUG_SBA_INIT +#undef DEBUG_SBA_RUN +#undef DEBUG_SBA_RUN_SG +#undef DEBUG_SBA_RESOURCE +#undef ASSERT_PDIR_SANITY +#undef DEBUG_LARGE_SG_ENTRIES +#undef DEBUG_BYPASS + +#define SBA_INLINE __inline__ +/* #define SBA_INLINE */ + +#ifdef DEBUG_SBA_INIT +#define DBG_INIT(x...) printk(x) +#else +#define DBG_INIT(x...) +#endif + +#ifdef DEBUG_SBA_RUN +#define DBG_RUN(x...) printk(x) +#else +#define DBG_RUN(x...) +#endif + +#ifdef DEBUG_SBA_RUN_SG +#define DBG_RUN_SG(x...) printk(x) +#else +#define DBG_RUN_SG(x...) +#endif + + +#ifdef DEBUG_SBA_RESOURCE +#define DBG_RES(x...) printk(x) +#else +#define DBG_RES(x...) +#endif + +#ifdef DEBUG_BYPASS +#define DBG_BYPASS(x...) printk(x) +#else +#define DBG_BYPASS(x...) +#endif + +#ifdef ASSERT_PDIR_SANITY +#define ASSERT(expr) \ + if(!(expr)) { \ + printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \ + panic(#expr); \ + } +#else +#define ASSERT(expr) +#endif + +/* +** The number of pdir entries to "free" before issueing +** a read to PCOM register to flush out PCOM writes. +** Interacts with allocation granularity (ie 4 or 8 entries +** allocated and free'd/purged at a time might make this +** less interesting). +*/ +#define DELAYED_RESOURCE_CNT 16 + +#define DEFAULT_DMA_HINT_REG 0 + +#define ZX1_IOC_ID ((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP) +#define REO_IOC_ID ((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP) + +#define ZX1_IOC_OFFSET 0x1000 /* ACPI reports SBA, we want IOC */ + +#define IOC_FUNC_ID 0x000 +#define IOC_FCLASS 0x008 /* function class, bist, header, rev... */ +#define IOC_IBASE 0x300 /* IO TLB */ +#define IOC_IMASK 0x308 +#define IOC_PCOM 0x310 +#define IOC_TCNFG 0x318 +#define IOC_PDIR_BASE 0x320 + +/* AGP GART driver looks for this */ +#define ZX1_SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL + +/* +** IOC supports 4/8/16/64KB page sizes (see TCNFG register) +** It's safer (avoid memory corruption) to keep DMA page mappings +** equivalently sized to VM PAGE_SIZE. +** +** We really can't avoid generating a new mapping for each +** page since the Virtual Coherence Index has to be generated +** and updated for each page. +** +** IOVP_SIZE could only be greater than PAGE_SIZE if we are +** confident the drivers really only touch the next physical +** page iff that driver instance owns it. +*/ +#define IOVP_SIZE PAGE_SIZE +#define IOVP_SHIFT PAGE_SHIFT +#define IOVP_MASK PAGE_MASK + +struct ioc { + void *ioc_hpa; /* I/O MMU base address */ + char *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + unsigned long ibase; /* pdir IOV Space base */ + unsigned long imask; /* pdir IOV Space mask */ + + unsigned long *res_hint; /* next avail IOVP - circular search */ + spinlock_t res_lock; + unsigned long hint_mask_pdir; /* bits used for DMA hints */ + unsigned int res_bitshift; /* from the RIGHT! */ + unsigned int res_size; /* size of resource map in bytes */ + unsigned int hint_shift_pdir; + unsigned long dma_mask; +#if DELAYED_RESOURCE_CNT > 0 + int saved_cnt; + struct sba_dma_pair { + dma_addr_t iova; + size_t size; + } saved[DELAYED_RESOURCE_CNT]; +#endif + +#ifdef CONFIG_PROC_FS +#define SBA_SEARCH_SAMPLE 0x100 + unsigned long avg_search[SBA_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; +#ifdef ALLOW_IOV_BYPASS + unsigned long msingle_bypass; + unsigned long usingle_bypass; + unsigned long msg_bypass; +#endif +#endif + + /* Stuff we don't need in performance path */ + struct ioc *next; /* list of IOC's in system */ + acpi_handle handle; /* for multiple IOC's */ + const char *name; + unsigned int func_id; + unsigned int rev; /* HW revision of chip */ + u32 iov_size; + unsigned int pdir_size; /* in bytes, determined by IOV Space size */ + struct pci_dev *sac_only_dev; +}; + +static struct ioc *ioc_list; +static int reserve_sba_gart = 1; + +#define sba_sg_iova(sg) (sg->address) +#define sba_sg_len(sg) (sg->length) +#define sba_sg_buffer(sg) (sg->orig_address) + +#define GET_IOC(dev) ((struct ioc *) PCI_CONTROLLER(dev)->iommu) + +/* +** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up +** (or rather not merge) DMA's into managable chunks. +** On parisc, this is more of the software/tuning constraint +** rather than the HW. I/O MMU allocation alogorithms can be +** faster with smaller size is (to some degree). +*/ +#define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE) + +#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) + +/************************************ +** SBA register read and write support +** +** BE WARNED: register writes are posted. +** (ie follow writes which must reach HW with a read) +** +*/ +#define READ_REG(addr) __raw_readq(addr) +#define WRITE_REG(val, addr) __raw_writeq(val, addr) + +#ifdef DEBUG_SBA_INIT + +/** + * sba_dump_tlb - debugging only - print IOMMU operating parameters + * @hpa: base address of the IOMMU + * + * Print the size/location of the IO MMU PDIR. + */ +static void +sba_dump_tlb(char *hpa) +{ + DBG_INIT("IO TLB at 0x%p\n", (void *)hpa); + DBG_INIT("IOC_IBASE : %016lx\n", READ_REG(hpa+IOC_IBASE)); + DBG_INIT("IOC_IMASK : %016lx\n", READ_REG(hpa+IOC_IMASK)); + DBG_INIT("IOC_TCNFG : %016lx\n", READ_REG(hpa+IOC_TCNFG)); + DBG_INIT("IOC_PDIR_BASE: %016lx\n", READ_REG(hpa+IOC_PDIR_BASE)); + DBG_INIT("\n"); +} +#endif + + +#ifdef ASSERT_PDIR_SANITY + +/** + * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @msg: text to print ont the output line. + * @pide: pdir index. + * + * Print one entry of the IO MMU PDIR in human readable form. + */ +static void +sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) +{ + /* start printing from lowest pde in rval */ + u64 *ptr = &(ioc->pdir_base[pide & ~(BITS_PER_LONG - 1)]); + unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); + uint rcnt; + + /* printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n", */ + printk("SBA: %s rp %p bit %d rval 0x%lx\n", + msg, rptr, pide & (BITS_PER_LONG - 1), *rptr); + + rcnt = 0; + while (rcnt < BITS_PER_LONG) { + printk("%s %2d %p %016Lx\n", + (rcnt == (pide & (BITS_PER_LONG - 1))) + ? " -->" : " ", + rcnt, ptr, *ptr ); + rcnt++; + ptr++; + } + printk("%s", msg); +} + + +/** + * sba_check_pdir - debugging only - consistency checker + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @msg: text to print ont the output line. + * + * Verify the resource map and pdir state is consistent + */ +static int +sba_check_pdir(struct ioc *ioc, char *msg) +{ + u64 *rptr_end = (u64 *) &(ioc->res_map[ioc->res_size]); + u64 *rptr = (u64 *) ioc->res_map; /* resource map ptr */ + u64 *pptr = ioc->pdir_base; /* pdir ptr */ + uint pide = 0; + + while (rptr < rptr_end) { + u64 rval; + int rcnt; /* number of bits we might check */ + + rval = *rptr; + rcnt = 64; + + while (rcnt) { + /* Get last byte and highest bit from that */ + u32 pde = ((u32)((*pptr >> (63)) & 0x1)); + if ((rval & 0x1) ^ pde) + { + /* + ** BUMMER! -- res_map != pdir -- + ** Dump rval and matching pdir entries + */ + sba_dump_pdir_entry(ioc, msg, pide); + return(1); + } + rcnt--; + rval >>= 1; /* try the next bit */ + pptr++; + pide++; + } + rptr++; /* look at next word of res_map */ + } + /* It'd be nice if we always got here :^) */ + return 0; +} + + +/** + * sba_dump_sg - debugging only - print Scatter-Gather list + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @startsg: head of the SG list + * @nents: number of entries in SG list + * + * print the SG list so we can verify it's correct by hand. + */ +static void +sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) +{ + while (nents-- > 0) { + printk(" %d : %08lx/%05x %p\n", + nents, + (unsigned long) sba_sg_iova(startsg), + sba_sg_len(startsg), + sba_sg_buffer(startsg)); + startsg++; + } +} +static void +sba_check_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) +{ + struct scatterlist *the_sg = startsg; + int the_nents = nents; + + while (the_nents-- > 0) { + if (sba_sg_buffer(the_sg) == 0x0UL) + sba_dump_sg(NULL, startsg, nents); + the_sg++; + } +} + +#endif /* ASSERT_PDIR_SANITY */ + + + + +/************************************************************** +* +* I/O Pdir Resource Management +* +* Bits set in the resource map are in use. +* Each bit can represent a number of pages. +* LSbs represent lower addresses (IOVA's). +* +***************************************************************/ +#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */ + +/* Convert from IOVP to IOVA and vice versa. */ +#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir))) +#define SBA_IOVP(ioc,iova) (((iova) & ioc->hint_mask_pdir) & ~(ioc->ibase)) + +/* FIXME : review these macros to verify correctness and usage */ +#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) + +#define RESMAP_MASK(n) ~(~0UL << (n)) +#define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) + + +/** + * sba_search_bitmap - find free space in IO PDIR resource bitmap + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @bits_wanted: number of entries we need. + * + * Find consecutive free bits in resource bitmap. + * Each bit represents one entry in the IO Pdir. + * Cool perf optimization: search for log2(size) bits at a time. + */ +static SBA_INLINE unsigned long +sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) +{ + unsigned long *res_ptr = ioc->res_hint; + unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); + unsigned long pide = ~0UL; + + ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); + ASSERT(res_ptr < res_end); + if (bits_wanted > (BITS_PER_LONG/2)) { + /* Search word at a time - no mask needed */ + for(; res_ptr < res_end; ++res_ptr) { + if (*res_ptr == 0) { + *res_ptr = RESMAP_MASK(bits_wanted); + pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); + pide <<= 3; /* convert to bit address */ + break; + } + } + /* point to the next word on next pass */ + res_ptr++; + ioc->res_bitshift = 0; + } else { + /* + ** Search the resource bit map on well-aligned values. + ** "o" is the alignment. + ** We need the alignment to invalidate I/O TLB using + ** SBA HW features in the unmap path. + */ + unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT); + uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o); + unsigned long mask; + + if (bitshiftcnt >= BITS_PER_LONG) { + bitshiftcnt = 0; + res_ptr++; + } + mask = RESMAP_MASK(bits_wanted) << bitshiftcnt; + + DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr); + while(res_ptr < res_end) + { + DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); + ASSERT(0 != mask); + if(0 == ((*res_ptr) & mask)) { + *res_ptr |= mask; /* mark resources busy! */ + pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); + pide <<= 3; /* convert to bit address */ + pide += bitshiftcnt; + break; + } + mask <<= o; + bitshiftcnt += o; + if (0 == mask) { + mask = RESMAP_MASK(bits_wanted); + bitshiftcnt=0; + res_ptr++; + } + } + /* look in the same word on the next pass */ + ioc->res_bitshift = bitshiftcnt + bits_wanted; + } + + /* wrapped ? */ + if (res_end <= res_ptr) { + ioc->res_hint = (unsigned long *) ioc->res_map; + ioc->res_bitshift = 0; + } else { + ioc->res_hint = res_ptr; + } + return (pide); +} + + +/** + * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @size: number of bytes to create a mapping for + * + * Given a size, find consecutive unmarked and then mark those bits in the + * resource bit map. + */ +static int +sba_alloc_range(struct ioc *ioc, size_t size) +{ + unsigned int pages_needed = size >> IOVP_SHIFT; +#ifdef CONFIG_PROC_FS + unsigned long itc_start = ia64_get_itc(); +#endif + unsigned long pide; + + ASSERT(pages_needed); + ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE); + ASSERT(pages_needed <= BITS_PER_LONG); + ASSERT(0 == (size & ~IOVP_MASK)); + + /* + ** "seek and ye shall find"...praying never hurts either... + */ + + pide = sba_search_bitmap(ioc, pages_needed); + if (pide >= (ioc->res_size << 3)) { + pide = sba_search_bitmap(ioc, pages_needed); + if (pide >= (ioc->res_size << 3)) + panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa); + } + +#ifdef ASSERT_PDIR_SANITY + /* verify the first enable bit is clear */ + if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) { + sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide); + } +#endif + + DBG_RES("%s(%x) %d -> %lx hint %x/%x\n", + __FUNCTION__, size, pages_needed, pide, + (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), + ioc->res_bitshift ); + +#ifdef CONFIG_PROC_FS + { + unsigned long itc_end = ia64_get_itc(); + unsigned long tmp = itc_end - itc_start; + /* check for roll over */ + itc_start = (itc_end < itc_start) ? -(tmp) : (tmp); + } + ioc->avg_search[ioc->avg_idx++] = itc_start; + ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1; + + ioc->used_pages += pages_needed; +#endif + + return (pide); +} + + +/** + * sba_free_range - unmark bits in IO PDIR resource bitmap + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @iova: IO virtual address which was previously allocated. + * @size: number of bytes to create a mapping for + * + * clear bits in the ioc's resource map + */ +static SBA_INLINE void +sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) +{ + unsigned long iovp = SBA_IOVP(ioc, iova); + unsigned int pide = PDIR_INDEX(iovp); + unsigned int ridx = pide >> 3; /* convert bit to byte address */ + unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]); + + int bits_not_wanted = size >> IOVP_SHIFT; + + /* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */ + unsigned long m = RESMAP_MASK(bits_not_wanted) << (pide & (BITS_PER_LONG - 1)); + + DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n", + __FUNCTION__, (uint) iova, size, + bits_not_wanted, m, pide, res_ptr, *res_ptr); + +#ifdef CONFIG_PROC_FS + ioc->used_pages -= bits_not_wanted; +#endif + + ASSERT(m != 0); + ASSERT(bits_not_wanted); + ASSERT((bits_not_wanted * IOVP_SIZE) <= DMA_CHUNK_SIZE); + ASSERT(bits_not_wanted <= BITS_PER_LONG); + ASSERT((*res_ptr & m) == m); /* verify same bits are set */ + *res_ptr &= ~m; +} + + +/************************************************************** +* +* "Dynamic DMA Mapping" support (aka "Coherent I/O") +* +***************************************************************/ + +#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir) + + +/** + * sba_io_pdir_entry - fill in one IO PDIR entry + * @pdir_ptr: pointer to IO PDIR entry + * @vba: Virtual CPU address of buffer to map + * + * SBA Mapping Routine + * + * Given a virtual address (vba, arg1) sba_io_pdir_entry() + * loads the I/O PDIR entry pointed to by pdir_ptr (arg0). + * Each IO Pdir entry consists of 8 bytes as shown below + * (LSB == bit 0): + * + * 63 40 11 7 0 + * +-+---------------------+----------------------------------+----+--------+ + * |V| U | PPN[39:12] | U | FF | + * +-+---------------------+----------------------------------+----+--------+ + * + * V == Valid Bit + * U == Unused + * PPN == Physical Page Number + * + * The physical address fields are filled with the results of virt_to_phys() + * on the vba. + */ + +#if 1 +#define sba_io_pdir_entry(pdir_ptr, vba) *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x8000000000000000ULL) +#else +void SBA_INLINE +sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba) +{ + *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL); +} +#endif + +#ifdef ENABLE_MARK_CLEAN +/** + * Since DMA is i-cache coherent, any (complete) pages that were written via + * DMA can be marked as "clean" so that update_mmu_cache() doesn't have to + * flush them when they get mapped into an executable vm-area. + */ +static void +mark_clean (void *addr, size_t size) +{ + unsigned long pg_addr, end; + + pg_addr = PAGE_ALIGN((unsigned long) addr); + end = (unsigned long) addr + size; + while (pg_addr + PAGE_SIZE <= end) { + struct page *page = virt_to_page(pg_addr); + set_bit(PG_arch_1, &page->flags); + pg_addr += PAGE_SIZE; + } +} +#endif + +/** + * sba_mark_invalid - invalidate one or more IO PDIR entries + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @iova: IO Virtual Address mapped earlier + * @byte_cnt: number of bytes this mapping covers. + * + * Marking the IO PDIR entry(ies) as Invalid and invalidate + * corresponding IO TLB entry. The PCOM (Purge Command Register) + * is to purge stale entries in the IO TLB when unmapping entries. + * + * The PCOM register supports purging of multiple pages, with a minium + * of 1 page and a maximum of 2GB. Hardware requires the address be + * aligned to the size of the range being purged. The size of the range + * must be a power of 2. The "Cool perf optimization" in the + * allocation routine helps keep that true. + */ +static SBA_INLINE void +sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) +{ + u32 iovp = (u32) SBA_IOVP(ioc,iova); + + int off = PDIR_INDEX(iovp); + + /* Must be non-zero and rounded up */ + ASSERT(byte_cnt > 0); + ASSERT(0 == (byte_cnt & ~IOVP_MASK)); + +#ifdef ASSERT_PDIR_SANITY + /* Assert first pdir entry is set */ + if (!(ioc->pdir_base[off] >> 60)) { + sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp)); + } +#endif + + if (byte_cnt <= IOVP_SIZE) + { + ASSERT(off < ioc->pdir_size); + + iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ + + /* + ** clear I/O PDIR entry "valid" bit + ** Do NOT clear the rest - save it for debugging. + ** We should only clear bits that have previously + ** been enabled. + */ + ioc->pdir_base[off] &= ~(0x80000000000000FFULL); + } else { + u32 t = get_order(byte_cnt) + PAGE_SHIFT; + + iovp |= t; + ASSERT(t <= 31); /* 2GB! Max value of "size" field */ + + do { + /* verify this pdir entry is enabled */ + ASSERT(ioc->pdir_base[off] >> 63); + /* clear I/O Pdir entry "valid" bit first */ + ioc->pdir_base[off] &= ~(0x80000000000000FFULL); + off++; + byte_cnt -= IOVP_SIZE; + } while (byte_cnt > 0); + } + + WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM); +} + +/** + * sba_map_single - map one buffer and return IOVA for DMA + * @dev: instance of PCI owned by the driver that's asking. + * @addr: driver buffer to map. + * @size: number of bytes to map in driver buffer. + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +dma_addr_t +sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +{ + struct ioc *ioc; + unsigned long flags; + dma_addr_t iovp; + dma_addr_t offset; + u64 *pdir_start; + int pide; +#ifdef ALLOW_IOV_BYPASS + unsigned long pci_addr = virt_to_phys(addr); +#endif + + ioc = GET_IOC(dev); + ASSERT(ioc); + +#ifdef ALLOW_IOV_BYPASS + /* + ** Check if the PCI device can DMA to ptr... if so, just return ptr + */ + if ((pci_addr & ~dev->dma_mask) == 0) { + /* + ** Device is bit capable of DMA'ing to the buffer... + ** just return the PCI address of ptr + */ +#ifdef CONFIG_PROC_FS + spin_lock_irqsave(&ioc->res_lock, flags); + ioc->msingle_bypass++; + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n", + dev->dma_mask, pci_addr); + return pci_addr; + } +#endif + + ASSERT(size > 0); + ASSERT(size <= DMA_CHUNK_SIZE); + + /* save offset bits */ + offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK; + + /* round up to nearest IOVP_SIZE */ + size = (size + offset + ~IOVP_MASK) & IOVP_MASK; + + spin_lock_irqsave(&ioc->res_lock, flags); +#ifdef ASSERT_PDIR_SANITY + if (sba_check_pdir(ioc,"Check before sba_map_single()")) + panic("Sanity check failed"); +#endif + +#ifdef CONFIG_PROC_FS + ioc->msingle_calls++; + ioc->msingle_pages += size >> IOVP_SHIFT; +#endif + pide = sba_alloc_range(ioc, size); + iovp = (dma_addr_t) pide << IOVP_SHIFT; + + DBG_RUN("%s() 0x%p -> 0x%lx\n", + __FUNCTION__, addr, (long) iovp | offset); + + pdir_start = &(ioc->pdir_base[pide]); + + while (size > 0) { + ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */ + sba_io_pdir_entry(pdir_start, (unsigned long) addr); + + DBG_RUN(" pdir 0x%p %lx\n", pdir_start, *pdir_start); + + addr += IOVP_SIZE; + size -= IOVP_SIZE; + pdir_start++; + } + /* form complete address */ +#ifdef ASSERT_PDIR_SANITY + sba_check_pdir(ioc,"Check after sba_map_single()"); +#endif + spin_unlock_irqrestore(&ioc->res_lock, flags); + return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG); +} + +/** + * sba_unmap_single - unmap one IOVA and free resources + * @dev: instance of PCI owned by the driver that's asking. + * @iova: IOVA of driver buffer previously mapped. + * @size: number of bytes mapped in driver buffer. + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, + int direction) +{ + struct ioc *ioc; +#if DELAYED_RESOURCE_CNT > 0 + struct sba_dma_pair *d; +#endif + unsigned long flags; + dma_addr_t offset; + + ioc = GET_IOC(dev); + ASSERT(ioc); + +#ifdef ALLOW_IOV_BYPASS + if ((iova & ioc->imask) != ioc->ibase) { + /* + ** Address does not fall w/in IOVA, must be bypassing + */ +#ifdef CONFIG_PROC_FS + spin_lock_irqsave(&ioc->res_lock, flags); + ioc->usingle_bypass++; + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova); + +#ifdef ENABLE_MARK_CLEAN + if (direction == PCI_DMA_FROMDEVICE) { + mark_clean(phys_to_virt(iova), size); + } +#endif + return; + } +#endif + offset = iova & ~IOVP_MASK; + + DBG_RUN("%s() iovp 0x%lx/%x\n", + __FUNCTION__, (long) iova, size); + + iova ^= offset; /* clear offset bits */ + size += offset; + size = ROUNDUP(size, IOVP_SIZE); + + spin_lock_irqsave(&ioc->res_lock, flags); +#ifdef CONFIG_PROC_FS + ioc->usingle_calls++; + ioc->usingle_pages += size >> IOVP_SHIFT; +#endif + +#if DELAYED_RESOURCE_CNT > 0 + d = &(ioc->saved[ioc->saved_cnt]); + d->iova = iova; + d->size = size; + if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) { + int cnt = ioc->saved_cnt; + while (cnt--) { + sba_mark_invalid(ioc, d->iova, d->size); + sba_free_range(ioc, d->iova, d->size); + d--; + } + ioc->saved_cnt = 0; + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ + } +#else /* DELAYED_RESOURCE_CNT == 0 */ + sba_mark_invalid(ioc, iova, size); + sba_free_range(ioc, iova, size); + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ +#endif /* DELAYED_RESOURCE_CNT == 0 */ +#ifdef ENABLE_MARK_CLEAN + if (direction == PCI_DMA_FROMDEVICE) { + u32 iovp = (u32) SBA_IOVP(ioc,iova); + int off = PDIR_INDEX(iovp); + void *addr; + + if (size <= IOVP_SIZE) { + addr = phys_to_virt(ioc->pdir_base[off] & + ~0xE000000000000FFFULL); + mark_clean(addr, size); + } else { + size_t byte_cnt = size; + + do { + addr = phys_to_virt(ioc->pdir_base[off] & + ~0xE000000000000FFFULL); + mark_clean(addr, min(byte_cnt, IOVP_SIZE)); + off++; + byte_cnt -= IOVP_SIZE; + + } while (byte_cnt > 0); + } + } +#endif + spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support. + ** For Astro based systems this isn't a big deal WRT performance. + ** As long as 2.4 kernels copyin/copyout data from/to userspace, + ** we don't need the syncdma. The issue here is I/O MMU cachelines + ** are *not* coherent in all cases. May be hwrev dependent. + ** Need to investigate more. + asm volatile("syncdma"); + */ +} + + +/** + * sba_alloc_consistent - allocate/map shared mem for DMA + * @hwdev: instance of PCI owned by the driver that's asking. + * @size: number of bytes mapped in driver buffer. + * @dma_handle: IOVA of new buffer. + * + * See Documentation/DMA-mapping.txt + */ +void * +sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + struct ioc *ioc; + void *ret; + + if (!hwdev) { + /* only support PCI */ + *dma_handle = 0; + return 0; + } + + ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + + if (ret) { + memset(ret, 0, size); + /* + * REVISIT: if sba_map_single starts needing more + * than dma_mask from the device, this needs to be + * updated. + */ + ioc = GET_IOC(hwdev); + *dma_handle = sba_map_single(ioc->sac_only_dev, ret, size, 0); + } + + return ret; +} + + +/** + * sba_free_consistent - free/unmap shared mem for DMA + * @hwdev: instance of PCI owned by the driver that's asking. + * @size: number of bytes mapped in driver buffer. + * @vaddr: virtual address IOVA of "consistent" buffer. + * @dma_handler: IO virtual address of "consistent" buffer. + * + * See Documentation/DMA-mapping.txt + */ +void sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + sba_unmap_single(hwdev, dma_handle, size, 0); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +/* +** Since 0 is a valid pdir_base index value, can't use that +** to determine if a value is valid or not. Use a flag to indicate +** the SG list entry contains a valid pdir index. +*/ +#define PIDE_FLAG 0x1UL + +#ifdef DEBUG_LARGE_SG_ENTRIES +int dump_run_sg = 0; +#endif + + +/** + * sba_fill_pdir - write allocated SG entries into IO PDIR + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @startsg: list of IOVA/size pairs + * @nents: number of entries in startsg list + * + * Take preprocessed SG list and write corresponding entries + * in the IO PDIR. + */ + +static SBA_INLINE int +sba_fill_pdir( + struct ioc *ioc, + struct scatterlist *startsg, + int nents) +{ + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + int n_mappings = 0; + u64 *pdirp = 0; + unsigned long dma_offset = 0; + + dma_sg--; + while (nents-- > 0) { + int cnt = sba_sg_len(startsg); + sba_sg_len(startsg) = 0; + +#ifdef DEBUG_LARGE_SG_ENTRIES + if (dump_run_sg) + printk(" %2d : %08lx/%05x %p\n", + nents, + (unsigned long) sba_sg_iova(startsg), cnt, + sba_sg_buffer(startsg) + ); +#else + DBG_RUN_SG(" %d : %08lx/%05x %p\n", + nents, + (unsigned long) sba_sg_iova(startsg), cnt, + sba_sg_buffer(startsg) + ); +#endif + /* + ** Look for the start of a new DMA stream + */ + if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) { + u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + sba_sg_iova(startsg) = 0; + dma_sg++; + sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase); + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + n_mappings++; + } + + /* + ** Look for a VCONTIG chunk + */ + if (cnt) { + unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg); + ASSERT(pdirp); + + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ + sba_sg_len(dma_sg) += cnt; + cnt += dma_offset; + dma_offset=0; /* only want offset on first chunk */ + cnt = ROUNDUP(cnt, IOVP_SIZE); +#ifdef CONFIG_PROC_FS + ioc->msg_pages += cnt >> IOVP_SHIFT; +#endif + do { + sba_io_pdir_entry(pdirp, vaddr); + vaddr += IOVP_SIZE; + cnt -= IOVP_SIZE; + pdirp++; + } while (cnt > 0); + } + startsg++; + } +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = 0; +#endif + return(n_mappings); +} + + +/* +** Two address ranges are DMA contiguous *iff* "end of prev" and +** "start of next" are both on a page boundry. +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + + +/** + * sba_coalesce_chunks - preprocess the SG list + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @startsg: list of IOVA/size pairs + * @nents: number of entries in startsg list + * + * First pass is to walk the SG list and determine where the breaks are + * in the DMA stream. Allocates PDIR entries but does not fill them. + * Returns the number of DMA chunks. + * + * Doing the fill seperate from the coalescing/allocation keeps the + * code simpler. Future enhancement could make one pass through + * the sglist do both. + */ +static SBA_INLINE int +sba_coalesce_chunks( struct ioc *ioc, + struct scatterlist *startsg, + int nents) +{ + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + int n_mappings = 0; + + while (nents > 0) { + unsigned long vaddr = (unsigned long) (startsg->address); + + /* + ** Prepare for first/next DMA stream + */ + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg); + vcontig_end += vaddr; + dma_offset = vaddr & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sba_sg_buffer(startsg) = sba_sg_iova(startsg); + sba_sg_iova(startsg) = 0; + sba_sg_len(startsg) = 0; + + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while (--nents > 0) { + unsigned long vaddr; /* tmp */ + + startsg++; + + /* catch brokenness in SCSI layer */ + ASSERT(startsg->length <= DMA_CHUNK_SIZE); + + /* + ** First make sure current dma stream won't + ** exceed DMA_CHUNK_SIZE if we coalesce the + ** next entry. + */ + if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE) + break; + + /* + ** Then look for virtually contiguous blocks. + ** + ** append the next transaction? + */ + vaddr = (unsigned long) sba_sg_iova(startsg); + if (vcontig_end == vaddr) + { + vcontig_len += sba_sg_len(startsg); + vcontig_end += sba_sg_len(startsg); + dma_len += sba_sg_len(startsg); + sba_sg_buffer(startsg) = (char *)vaddr; + sba_sg_iova(startsg) = 0; + sba_sg_len(startsg) = 0; + continue; + } + +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = (vcontig_len > IOVP_SIZE); +#endif + + /* + ** Not virtually contigous. + ** Terminate prev chunk. + ** Start a new chunk. + ** + ** Once we start a new VCONTIG chunk, dma_offset + ** can't change. And we need the offset from the first + ** chunk - not the last one. Ergo Successive chunks + ** must start on page boundaries and dove tail + ** with it's predecessor. + */ + sba_sg_len(vcontig_sg) = vcontig_len; + + vcontig_sg = startsg; + vcontig_len = sba_sg_len(startsg); + + /* + ** 3) do the entries end/start on page boundaries? + ** Don't update vcontig_end until we've checked. + */ + if (DMA_CONTIG(vcontig_end, vaddr)) + { + vcontig_end = vcontig_len + vaddr; + dma_len += vcontig_len; + sba_sg_buffer(startsg) = (char *)vaddr; + sba_sg_iova(startsg) = 0; + continue; + } else { + break; + } + } + + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + sba_sg_len(vcontig_sg) = vcontig_len; + dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; + ASSERT(dma_len <= DMA_CHUNK_SIZE); + sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG + | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset); + n_mappings++; + } + + return n_mappings; +} + + +/** + * sba_map_sg - map Scatter/Gather list + * @dev: instance of PCI owned by the driver that's asking. + * @sglist: array of buffer/length pairs + * @nents: number of entries in list + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, + int direction) +{ + struct ioc *ioc; + int coalesced, filled = 0; + unsigned long flags; +#ifdef ALLOW_IOV_BYPASS + struct scatterlist *sg; +#endif + + DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + ioc = GET_IOC(dev); + ASSERT(ioc); + +#ifdef ALLOW_IOV_BYPASS + if (dev->dma_mask >= ioc->dma_mask) { + for (sg = sglist ; filled < nents ; filled++, sg++){ + sba_sg_buffer(sg) = sba_sg_iova(sg); + sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg)); + } +#ifdef CONFIG_PROC_FS + spin_lock_irqsave(&ioc->res_lock, flags); + ioc->msg_bypass++; + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + return filled; + } +#endif + /* Fast path single entry scatterlists. */ + if (nents == 1) { + sba_sg_buffer(sglist) = sba_sg_iova(sglist); + sba_sg_iova(sglist) = (char *)sba_map_single(dev, + sba_sg_buffer(sglist), + sba_sg_len(sglist), direction); +#ifdef CONFIG_PROC_FS + /* + ** Should probably do some stats counting, but trying to + ** be precise quickly starts wasting CPU time. + */ +#endif + return 1; + } + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef ASSERT_PDIR_SANITY + if (sba_check_pdir(ioc,"Check before sba_map_sg()")) + { + sba_dump_sg(ioc, sglist, nents); + panic("Check before sba_map_sg()"); + } +#endif + +#ifdef CONFIG_PROC_FS + ioc->msg_calls++; +#endif + + /* + ** First coalesce the chunks and allocate I/O pdir space + ** + ** If this is one DMA stream, we can properly map using the + ** correct virtual address associated with each DMA page. + ** w/o this association, we wouldn't have coherent DMA! + ** Access to the virtual address is what forces a two pass algorithm. + */ + coalesced = sba_coalesce_chunks(ioc, sglist, nents); + + /* + ** Program the I/O Pdir + ** + ** map the virtual addresses to the I/O Pdir + ** o dma_address will contain the pdir index + ** o dma_len will contain the number of bytes to map + ** o address contains the virtual address. + */ + filled = sba_fill_pdir(ioc, sglist, nents); + +#ifdef ASSERT_PDIR_SANITY + if (sba_check_pdir(ioc,"Check after sba_map_sg()")) + { + sba_dump_sg(ioc, sglist, nents); + panic("Check after sba_map_sg()\n"); + } +#endif + + spin_unlock_irqrestore(&ioc->res_lock, flags); + + ASSERT(coalesced == filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + + return filled; +} + + +/** + * sba_unmap_sg - unmap Scatter/Gather list + * @dev: instance of PCI owned by the driver that's asking. + * @sglist: array of buffer/length pairs + * @nents: number of entries in list + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +void sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, + int direction) +{ + struct ioc *ioc; +#ifdef ASSERT_PDIR_SANITY + unsigned long flags; +#endif + + DBG_RUN_SG("%s() START %d entries, %p,%x\n", + __FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length); + + ioc = GET_IOC(dev); + ASSERT(ioc); + +#ifdef CONFIG_PROC_FS + ioc->usg_calls++; +#endif + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + sba_check_pdir(ioc,"Check before sba_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + + while (sba_sg_len(sglist) && nents--) { + + sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist), + sba_sg_len(sglist), direction); +#ifdef CONFIG_PROC_FS + /* + ** This leaves inconsistent data in the stats, but we can't + ** tell which sg lists were mapped by map_single and which + ** were coalesced to a single entry. The stats are fun, + ** but speed is more important. + */ + ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT; +#endif + ++sglist; + } + + DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + sba_check_pdir(ioc,"Check after sba_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + +} + +unsigned long +sba_dma_address (struct scatterlist *sg) +{ + return ((unsigned long)sba_sg_iova(sg)); +} + +int +sba_dma_supported (struct pci_dev *dev, u64 mask) +{ + return 1; +} + +/************************************************************** +* +* Initialization and claim +* +***************************************************************/ + +static void __init +ioc_iova_init(struct ioc *ioc) +{ + u32 iova_space_mask; + int iov_order, tcnfg; + int agp_found = 0; + struct pci_dev *device; + + /* + ** Firmware programs the base and size of a "safe IOVA space" + ** (one that doesn't overlap memory or LMMIO space) in the + ** IBASE and IMASK registers. + */ + ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1UL; + ioc->iov_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1; + + if (ioc->ibase == 0) { + if (((unsigned long) ioc->ioc_hpa & 0x3000UL) == 0x2000) + ioc->ibase = 0xc0000000; + else + ioc->ibase = 0x80000000; + printk("WARNING: IBASE is zero; setting to 0x%lx\n", ioc->ibase); + } + + if (ioc->ibase < 0xfed00000UL && ioc->ibase + ioc->iov_size >= 0xfee00000UL) { + printk("WARNING: IOV space overlaps local config and interrupt message, truncating\n"); + ioc->iov_size /= 2; + } + + /* + ** iov_order is always based on a 1GB IOVA space since we want to + ** turn on the other half for AGP GART. + */ + iov_order = get_order(ioc->iov_size >> (IOVP_SHIFT - PAGE_SHIFT)); + ioc->pdir_size = (ioc->iov_size / IOVP_SIZE) * sizeof(u64); + + DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits) PDIR size 0x%0x\n", + __FUNCTION__, ioc->ioc_hpa, ioc->iov_size >> 20, + iov_order + PAGE_SHIFT, ioc->pdir_size); + + /* FIXME : DMA HINTs not used */ + ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; + ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); + + ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL, + get_order(ioc->pdir_size)); + if (!ioc->pdir_base) + panic(PFX "Couldn't allocate I/O Page Table\n"); + + memset(ioc->pdir_base, 0, ioc->pdir_size); + + DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n", + __FUNCTION__, ioc->pdir_base, ioc->pdir_size, + ioc->hint_shift_pdir, ioc->hint_mask_pdir); + + ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base); + WRITE_REG(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE); + + DBG_INIT(" base %p\n", ioc->pdir_base); + + /* build IMASK for IOC and Elroy */ + iova_space_mask = 0xffffffff; + iova_space_mask <<= (iov_order + PAGE_SHIFT); + ioc->imask = iova_space_mask; + + DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", + __FUNCTION__, ioc->ibase, ioc->imask); + + /* + ** FIXME: Hint registers are programmed with default hint + ** values during boot, so hints should be sane even if we + ** can't reprogram them the way drivers want. + */ + WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK); + + /* + ** Setting the upper bits makes checking for bypass addresses + ** a little faster later on. + */ + ioc->imask |= 0xFFFFFFFF00000000UL; + + /* Set I/O PDIR Page size to system page size */ + switch (PAGE_SHIFT) { + case 12: tcnfg = 0; break; /* 4K */ + case 13: tcnfg = 1; break; /* 8K */ + case 14: tcnfg = 2; break; /* 16K */ + case 16: tcnfg = 3; break; /* 64K */ + default: + panic(PFX "Unsupported system page size %d", + 1 << PAGE_SHIFT); + break; + } + WRITE_REG(tcnfg, ioc->ioc_hpa + IOC_TCNFG); + + /* + ** Program the IOC's ibase and enable IOVA translation + ** Bit zero == enable bit. + */ + WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE); + + /* + ** Clear I/O TLB of any possible entries. + ** (Yes. This is a bit paranoid...but so what) + */ + WRITE_REG(0 | 31, ioc->ioc_hpa + IOC_PCOM); + + /* + ** If an AGP device is present, only use half of the IOV space + ** for PCI DMA. Unfortunately we can't know ahead of time + ** whether GART support will actually be used, for now we + ** can just key on an AGP device found in the system. + ** We program the next pdir index after we stop w/ a key for + ** the GART code to handshake on. + */ + pci_for_each_dev(device) + agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP); + + if (agp_found && reserve_sba_gart) { + DBG_INIT("%s: AGP device found, reserving half of IOVA for GART support\n", __FUNCTION__); + ioc->pdir_size /= 2; + ((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE; + } +} + +static void __init +ioc_resource_init(struct ioc *ioc) +{ + spin_lock_init(&ioc->res_lock); + + /* resource map size dictated by pdir_size */ + ioc->res_size = ioc->pdir_size / sizeof(u64); /* entries */ + ioc->res_size >>= 3; /* convert bit count to byte count */ + DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size); + + ioc->res_map = (char *) __get_free_pages(GFP_KERNEL, + get_order(ioc->res_size)); + if (!ioc->res_map) + panic(PFX "Couldn't allocate resource map\n"); + + memset(ioc->res_map, 0, ioc->res_size); + /* next available IOVP - circular search */ + ioc->res_hint = (unsigned long *) ioc->res_map; + +#ifdef ASSERT_PDIR_SANITY + /* Mark first bit busy - ie no IOVA 0 */ + ioc->res_map[0] = 0x1; + ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE; +#endif + + DBG_INIT("%s() res_map %x %p\n", __FUNCTION__, + ioc->res_size, (void *) ioc->res_map); +} + +static void __init +ioc_sac_init(struct ioc *ioc) +{ + struct pci_dev *sac = NULL; + struct pci_controller *controller = NULL; + + /* + * pci_alloc_consistent() must return a DMA address which is + * SAC (single address cycle) addressable, so allocate a + * pseudo-device to enforce that. + */ + sac = kmalloc(sizeof(*sac), GFP_KERNEL); + if (!sac) + panic(PFX "Couldn't allocate struct pci_dev"); + memset(sac, 0, sizeof(*sac)); + + controller = kmalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + panic(PFX "Couldn't allocate struct pci_controller"); + memset(controller, 0, sizeof(*controller)); + + controller->iommu = ioc; + sac->sysdata = controller; + sac->dma_mask = 0xFFFFFFFFUL; + ioc->sac_only_dev = sac; +} + +static void __init +ioc_zx1_init(struct ioc *ioc) +{ + if (ioc->rev < 0x20) + panic(PFX "IOC 2.0 or later required for IOMMU support\n"); + + ioc->dma_mask = 0xFFFFFFFFFFUL; +} + +typedef void (initfunc)(struct ioc *); + +struct ioc_iommu { + u32 func_id; + char *name; + initfunc *init; +}; + +static struct ioc_iommu ioc_iommu_info[] __initdata = { + { ZX1_IOC_ID, "zx1", ioc_zx1_init }, + { REO_IOC_ID, "REO" }, +}; + +static struct ioc * __init +ioc_init(u64 hpa, void *handle) +{ + struct ioc *ioc; + struct ioc_iommu *info; + + ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) + return NULL; + + memset(ioc, 0, sizeof(*ioc)); + + ioc->next = ioc_list; + ioc_list = ioc; + + ioc->handle = handle; + ioc->ioc_hpa = ioremap(hpa, 0x1000); + + ioc->func_id = READ_REG(ioc->ioc_hpa + IOC_FUNC_ID); + ioc->rev = READ_REG(ioc->ioc_hpa + IOC_FCLASS) & 0xFFUL; + ioc->dma_mask = 0xFFFFFFFFFFFFFFFFUL; /* conservative */ + + for (info = ioc_iommu_info; info < ioc_iommu_info + ARRAY_SIZE(ioc_iommu_info); info++) { + if (ioc->func_id == info->func_id) { + ioc->name = info->name; + if (info->init) + (info->init)(ioc); + } + } + if (!ioc->name) + ioc->name = "Unknown"; + + ioc_iova_init(ioc); + ioc_resource_init(ioc); + ioc_sac_init(ioc); + + printk(KERN_INFO PFX + "Found %s IOC %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n", + ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF, + hpa, ioc->iov_size >> 20, ioc->ibase); + + return ioc; +} + + + +/************************************************************************** +** +** SBA initialization code (HW and SW) +** +** o identify SBA chip itself +** o FIXME: initialize DMA hints for reasonable defaults +** +**************************************************************************/ + +#ifdef CONFIG_PROC_FS +static int +sba_proc_info_one(char *buf, struct ioc *ioc) +{ + int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */ + unsigned long i = 0, avg = 0, min, max; + + sprintf(buf, "Hewlett Packard %s IOC rev %d.%d\n", + ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF)); + sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", + buf, + (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ + total_pages); + + sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, + total_pages - ioc->used_pages, ioc->used_pages, + (int) (ioc->used_pages * 100 / total_pages)); + + sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", + buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */ + + min = max = ioc->avg_search[0]; + for (i = 0; i < SBA_SEARCH_SAMPLE; i++) { + avg += ioc->avg_search[i]; + if (ioc->avg_search[i] > max) max = ioc->avg_search[i]; + if (ioc->avg_search[i] < min) min = ioc->avg_search[i]; + } + avg /= SBA_SEARCH_SAMPLE; + sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", + buf, min, avg, max); + + sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n", + buf, ioc->msingle_calls, ioc->msingle_pages, + (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); +#ifdef ALLOW_IOV_BYPASS + sprintf(buf, "%spci_map_single(): %12ld bypasses\n", + buf, ioc->msingle_bypass); +#endif + + sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n", + buf, ioc->usingle_calls, ioc->usingle_pages, + (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls)); +#ifdef ALLOW_IOV_BYPASS + sprintf(buf, "%spci_unmap_single: %12ld bypasses\n", + buf, ioc->usingle_bypass); +#endif + + sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n", + buf, ioc->msg_calls, ioc->msg_pages, + (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); +#ifdef ALLOW_IOV_BYPASS + sprintf(buf, "%spci_map_sg() : %12ld bypasses\n", + buf, ioc->msg_bypass); +#endif + + sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", + buf, ioc->usg_calls, ioc->usg_pages, + (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); + + return strlen(buf); +} + +static int +sba_proc_info(char *buf, char **start, off_t offset, int len) +{ + struct ioc *ioc; + char *base = buf; + + for (ioc = ioc_list; ioc; ioc = ioc->next) { + buf += sba_proc_info_one(buf, ioc); + } + + return strlen(base); +} + +static int +sba_resource_map_one(char *buf, struct ioc *ioc) +{ + unsigned int *res_ptr = (unsigned int *)ioc->res_map; + int i; + + buf[0] = '\0'; + for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) { + if ((i & 7) == 0) + strcat(buf,"\n "); + sprintf(buf, "%s %08x", buf, *res_ptr); + } + strcat(buf, "\n"); + + return strlen(buf); +} + +static int +sba_resource_map(char *buf, char **start, off_t offset, int len) +{ + struct ioc *ioc; + char *base = buf; + + for (ioc = ioc_list; ioc; ioc = ioc->next) { + buf += sba_resource_map_one(buf, ioc); + } + + return strlen(base); +} +#endif + +void +sba_enable_device(struct pci_dev *dev) +{ + acpi_handle handle, parent; + acpi_status status; + struct ioc *ioc; + + handle = PCI_CONTROLLER(dev)->acpi_handle; + if (!handle) + return; + + /* + * The IOC scope encloses PCI root bridges in the ACPI + * namespace, so work our way out until we find an IOC we + * claimed previously. + */ + do { + for (ioc = ioc_list; ioc; ioc = ioc->next) + if (ioc->handle == handle) { + PCI_CONTROLLER(dev)->iommu = ioc; + return; + } + + status = acpi_get_parent(handle, &parent); + handle = parent; + } while (ACPI_SUCCESS(status)); + + printk("No IOC for %s in ACPI\n", dev->slot_name); +} + +static int __init +acpi_sba_ioc_add(struct acpi_device *device) +{ + struct ioc *ioc; + acpi_status status; + u64 hpa, length; + + /* + * Only SBA appears in ACPI namespace. It encloses the PCI + * root bridges, and its CSR space includes the IOC function. + */ + status = acpi_hp_csr_space(device->handle, &hpa, &length); + if (ACPI_FAILURE(status)) + return 1; + ioc = ioc_init(hpa + ZX1_IOC_OFFSET, device->handle); + if (!ioc) + return 1; + + return 0; +} + +static int __init +acpi_ioc_add(struct acpi_device *device) +{ + struct ioc *ioc; + acpi_status status; + u64 hpa, length; + + status = acpi_hp_csr_space(device->handle, &hpa, &length); + if (ACPI_FAILURE(status)) + return 1; + ioc = ioc_init(hpa, device->handle); + if (!ioc) + return 1; + + return 0; +} + +static struct acpi_driver acpi_sba_ioc_driver = { + name: "IOC IOMMU Driver", + ids: "HWP0001", + ops: { + add: acpi_sba_ioc_add, + }, +}; + +static struct acpi_driver acpi_ioc_driver = { + name: "IOC IOMMU Driver", + ids: "HWP0004", + ops: { + add: acpi_ioc_add, + }, +}; + +void __init +ioc_acpi_init(void) +{ + acpi_bus_register_driver(&acpi_sba_ioc_driver); + acpi_bus_register_driver(&acpi_ioc_driver); +} + +void __init +sba_init(void) +{ + ioc_acpi_init(); + +#ifdef CONFIG_PROC_FS + if (ioc_list) { + struct proc_dir_entry * proc_mckinley_root; + + proc_mckinley_root = proc_mkdir("bus/mckinley",0); + create_proc_info_entry(ioc_list->name, 0, proc_mckinley_root, sba_proc_info); + create_proc_info_entry("bitmap", 0, proc_mckinley_root, sba_resource_map); + } +#endif +} + +static int __init +nosbagart(char *str) +{ + reserve_sba_gart = 0; + return 1; +} + +__setup("nosbagart", nosbagart); + +EXPORT_SYMBOL(sba_init); +EXPORT_SYMBOL(sba_map_single); +EXPORT_SYMBOL(sba_unmap_single); +EXPORT_SYMBOL(sba_map_sg); +EXPORT_SYMBOL(sba_unmap_sg); +EXPORT_SYMBOL(sba_dma_address); +EXPORT_SYMBOL(sba_dma_supported); +EXPORT_SYMBOL(sba_alloc_consistent); +EXPORT_SYMBOL(sba_free_consistent); diff -Nur linux-2.4.19/arch/ia64/hp/hpsim_console.c linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_console.c --- linux-2.4.19/arch/ia64/hp/hpsim_console.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_console.c Wed Dec 31 16:00:00 1969 @@ -1,61 +0,0 @@ -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang - * Copyright (C) 1999 Vijay Chander - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "hpsim_ssc.h" - -static int simcons_init (struct console *, char *); -static void simcons_write (struct console *, const char *, unsigned); -static kdev_t simcons_console_device (struct console *); - -struct console hpsim_cons = { - name: "simcons", - write: simcons_write, - device: simcons_console_device, - setup: simcons_init, - flags: CON_PRINTBUFFER, - index: -1, -}; - -static int -simcons_init (struct console *cons, char *options) -{ - return 0; -} - -static void -simcons_write (struct console *cons, const char *buf, unsigned count) -{ - unsigned long ch; - - while (count-- > 0) { - ch = *buf++; - ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR); - if (ch == '\n') - ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR); - } -} - -static kdev_t -simcons_console_device (struct console *c) -{ - return MKDEV(TTY_MAJOR, 64 + c->index); -} diff -Nur linux-2.4.19/arch/ia64/hp/hpsim_irq.c linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_irq.c --- linux-2.4.19/arch/ia64/hp/hpsim_irq.c Thu Apr 5 12:51:47 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_irq.c Wed Dec 31 16:00:00 1969 @@ -1,46 +0,0 @@ -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang - */ - -#include -#include -#include -#include - -static unsigned int -hpsim_irq_startup (unsigned int irq) -{ - return 0; -} - -static void -hpsim_irq_noop (unsigned int irq) -{ -} - -static struct hw_interrupt_type irq_type_hp_sim = { - typename: "hpsim", - startup: hpsim_irq_startup, - shutdown: hpsim_irq_noop, - enable: hpsim_irq_noop, - disable: hpsim_irq_noop, - ack: hpsim_irq_noop, - end: hpsim_irq_noop, - set_affinity: (void (*)(unsigned int, unsigned long)) hpsim_irq_noop, -}; - -void __init -hpsim_irq_init (void) -{ - irq_desc_t *idesc; - int i; - - for (i = 0; i < NR_IRQS; ++i) { - idesc = irq_desc(i); - if (idesc->handler == &no_irq_type) - idesc->handler = &irq_type_hp_sim; - } -} diff -Nur linux-2.4.19/arch/ia64/hp/hpsim_machvec.c linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_machvec.c --- linux-2.4.19/arch/ia64/hp/hpsim_machvec.c Fri Aug 11 19:09:06 2000 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_machvec.c Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -#define MACHVEC_PLATFORM_NAME hpsim -#include diff -Nur linux-2.4.19/arch/ia64/hp/hpsim_setup.c linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_setup.c --- linux-2.4.19/arch/ia64/hp/hpsim_setup.c Tue Jul 31 10:30:08 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_setup.c Wed Dec 31 16:00:00 1969 @@ -1,58 +0,0 @@ -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang - * Copyright (C) 1999 Vijay Chander - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "hpsim_ssc.h" - -extern struct console hpsim_cons; - -/* - * Simulator system call. - */ -asm (".text\n" - ".align 32\n" - ".global ia64_ssc\n" - ".proc ia64_ssc\n" - "ia64_ssc:\n" - "mov r15=r36\n" - "break 0x80001\n" - "br.ret.sptk.many rp\n" - ".endp\n"); - -void -ia64_ssc_connect_irq (long intr, long irq) -{ - ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT); -} - -void -ia64_ctl_trace (long on) -{ - ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE); -} - -void __init -hpsim_setup (char **cmdline_p) -{ - ROOT_DEV = to_kdev_t(0x0801); /* default to first SCSI drive */ - - register_console (&hpsim_cons); -} diff -Nur linux-2.4.19/arch/ia64/hp/hpsim_ssc.h linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_ssc.h --- linux-2.4.19/arch/ia64/hp/hpsim_ssc.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/hpsim_ssc.h Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -/* - * Platform dependent support for HP simulator. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang - * Copyright (C) 1999 Vijay Chander - */ -#ifndef _IA64_PLATFORM_HPSIM_SSC_H -#define _IA64_PLATFORM_HPSIM_SSC_H - -/* Simulator system calls: */ - -#define SSC_CONSOLE_INIT 20 -#define SSC_GETCHAR 21 -#define SSC_PUTCHAR 31 -#define SSC_CONNECT_INTERRUPT 58 -#define SSC_GENERATE_INTERRUPT 59 -#define SSC_SET_PERIODIC_INTERRUPT 60 -#define SSC_GET_RTC 65 -#define SSC_EXIT 66 -#define SSC_LOAD_SYMBOLS 69 -#define SSC_GET_TOD 74 -#define SSC_CTL_TRACE 76 - -#define SSC_NETDEV_PROBE 100 -#define SSC_NETDEV_SEND 101 -#define SSC_NETDEV_RECV 102 -#define SSC_NETDEV_ATTACH 103 -#define SSC_NETDEV_DETACH 104 - -/* - * Simulator system call. - */ -extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr); - -#endif /* _IA64_PLATFORM_HPSIM_SSC_H */ diff -Nur linux-2.4.19/arch/ia64/hp/sim/Makefile linux-2.4.19-sgi211r3/arch/ia64/hp/sim/Makefile --- linux-2.4.19/arch/ia64/hp/sim/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/sim/Makefile Fri Apr 26 11:07:18 2002 @@ -0,0 +1,13 @@ +# +# ia64/platform/hp/sim/Makefile +# +# Copyright (C) 1999 Silicon Graphics, Inc. +# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) +# + +O_TARGET := sim.o + +obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o +obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/hp/sim/hpsim_console.c linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_console.c --- linux-2.4.19/arch/ia64/hp/sim/hpsim_console.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_console.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,62 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 Vijay Chander + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "hpsim_ssc.h" + +static int simcons_init (struct console *, char *); +static void simcons_write (struct console *, const char *, unsigned); +static int simcons_wait_key (struct console *); +static kdev_t simcons_console_device (struct console *); + +struct console hpsim_cons = { + name: "simcons", + write: simcons_write, + device: simcons_console_device, + setup: simcons_init, + flags: CON_PRINTBUFFER, + index: -1, +}; + +static int +simcons_init (struct console *cons, char *options) +{ + return 0; +} + +static void +simcons_write (struct console *cons, const char *buf, unsigned count) +{ + unsigned long ch; + + while (count-- > 0) { + ch = *buf++; + ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR); + if (ch == '\n') + ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR); + } +} + +static kdev_t +simcons_console_device (struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} diff -Nur linux-2.4.19/arch/ia64/hp/sim/hpsim_irq.c linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_irq.c --- linux-2.4.19/arch/ia64/hp/sim/hpsim_irq.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_irq.c Fri Apr 26 11:07:18 2002 @@ -0,0 +1,46 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang + */ + +#include +#include +#include +#include + +static unsigned int +hpsim_irq_startup (unsigned int irq) +{ + return 0; +} + +static void +hpsim_irq_noop (unsigned int irq) +{ +} + +static struct hw_interrupt_type irq_type_hp_sim = { + typename: "hpsim", + startup: hpsim_irq_startup, + shutdown: hpsim_irq_noop, + enable: hpsim_irq_noop, + disable: hpsim_irq_noop, + ack: hpsim_irq_noop, + end: hpsim_irq_noop, + set_affinity: (void (*)(unsigned int, unsigned long)) hpsim_irq_noop, +}; + +void __init +hpsim_irq_init (void) +{ + irq_desc_t *idesc; + int i; + + for (i = 0; i < NR_IRQS; ++i) { + idesc = irq_desc(i); + if (idesc->handler == &no_irq_type) + idesc->handler = &irq_type_hp_sim; + } +} diff -Nur linux-2.4.19/arch/ia64/hp/sim/hpsim_machvec.c linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_machvec.c --- linux-2.4.19/arch/ia64/hp/sim/hpsim_machvec.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_machvec.c Fri Apr 26 11:07:18 2002 @@ -0,0 +1,2 @@ +#define MACHVEC_PLATFORM_NAME hpsim +#include diff -Nur linux-2.4.19/arch/ia64/hp/sim/hpsim_setup.c linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_setup.c --- linux-2.4.19/arch/ia64/hp/sim/hpsim_setup.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_setup.c Fri Apr 26 11:07:18 2002 @@ -0,0 +1,58 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 Vijay Chander + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "hpsim_ssc.h" + +extern struct console hpsim_cons; + +/* + * Simulator system call. + */ +asm (".text\n" + ".align 32\n" + ".global ia64_ssc\n" + ".proc ia64_ssc\n" + "ia64_ssc:\n" + "mov r15=r36\n" + "break 0x80001\n" + "br.ret.sptk.many rp\n" + ".endp\n"); + +void +ia64_ssc_connect_irq (long intr, long irq) +{ + ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT); +} + +void +ia64_ctl_trace (long on) +{ + ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE); +} + +void __init +hpsim_setup (char **cmdline_p) +{ + ROOT_DEV = to_kdev_t(0x0801); /* default to first SCSI drive */ + + register_console (&hpsim_cons); +} diff -Nur linux-2.4.19/arch/ia64/hp/sim/hpsim_ssc.h linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_ssc.h --- linux-2.4.19/arch/ia64/hp/sim/hpsim_ssc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/sim/hpsim_ssc.h Fri Apr 26 11:07:18 2002 @@ -0,0 +1,36 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 Vijay Chander + */ +#ifndef _IA64_PLATFORM_HPSIM_SSC_H +#define _IA64_PLATFORM_HPSIM_SSC_H + +/* Simulator system calls: */ + +#define SSC_CONSOLE_INIT 20 +#define SSC_GETCHAR 21 +#define SSC_PUTCHAR 31 +#define SSC_CONNECT_INTERRUPT 58 +#define SSC_GENERATE_INTERRUPT 59 +#define SSC_SET_PERIODIC_INTERRUPT 60 +#define SSC_GET_RTC 65 +#define SSC_EXIT 66 +#define SSC_LOAD_SYMBOLS 69 +#define SSC_GET_TOD 74 +#define SSC_CTL_TRACE 76 + +#define SSC_NETDEV_PROBE 100 +#define SSC_NETDEV_SEND 101 +#define SSC_NETDEV_RECV 102 +#define SSC_NETDEV_ATTACH 103 +#define SSC_NETDEV_DETACH 104 + +/* + * Simulator system call. + */ +extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr); + +#endif /* _IA64_PLATFORM_HPSIM_SSC_H */ diff -Nur linux-2.4.19/arch/ia64/hp/zx1/Makefile linux-2.4.19-sgi211r3/arch/ia64/hp/zx1/Makefile --- linux-2.4.19/arch/ia64/hp/zx1/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/zx1/Makefile Fri Apr 26 11:07:18 2002 @@ -0,0 +1,13 @@ +# +# ia64/platform/hp/zx1/Makefile +# +# Copyright (C) 2002 Hewlett Packard +# Copyright (C) Alex Williamson (alex_williamson@hp.com) +# + +O_TARGET := zx1.o + +obj-y := hpzx1_misc.o +obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/hp/zx1/hpzx1_machvec.c linux-2.4.19-sgi211r3/arch/ia64/hp/zx1/hpzx1_machvec.c --- linux-2.4.19/arch/ia64/hp/zx1/hpzx1_machvec.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/zx1/hpzx1_machvec.c Fri Apr 26 11:07:18 2002 @@ -0,0 +1,2 @@ +#define MACHVEC_PLATFORM_NAME hpzx1 +#include diff -Nur linux-2.4.19/arch/ia64/hp/zx1/hpzx1_misc.c linux-2.4.19-sgi211r3/arch/ia64/hp/zx1/hpzx1_misc.c --- linux-2.4.19/arch/ia64/hp/zx1/hpzx1_misc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/hp/zx1/hpzx1_misc.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,308 @@ +/* + * Misc. support for HP zx1 chipset support + * + * Copyright (C) 2002 Hewlett-Packard Co + * Copyright (C) 2002 Alex Williamson + * Copyright (C) 2002 Bjorn Helgaas + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include + +extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *); + +#define PFX "hpzx1: " + +static int hpzx1_devices; + +struct fake_pci_dev { + unsigned long csr_base; + unsigned long csr_size; + unsigned long mapped_csrs; // ioremapped + int sizing; // in middle of BAR sizing operation? +}; + +#define PCI_FAKE_DEV(dev) ((struct fake_pci_dev *) \ + PCI_CONTROLLER(dev)->platform_data) + +static struct pci_ops *orig_pci_ops; + +#define HP_CFG_RD(sz, bits, name) \ +static int hp_cfg_read##sz (struct pci_dev *dev, int where, u##bits *value) \ +{ \ + struct fake_pci_dev *fake_dev; \ + if (!(fake_dev = PCI_FAKE_DEV(dev))) \ + return orig_pci_ops->name(dev, where, value); \ + \ + if (where == PCI_BASE_ADDRESS_0) { \ + if (fake_dev->sizing) \ + *value = ~(fake_dev->csr_size - 1); \ + else \ + *value = (fake_dev->csr_base & \ + PCI_BASE_ADDRESS_MEM_MASK) | \ + PCI_BASE_ADDRESS_SPACE_MEMORY; \ + fake_dev->sizing = 0; \ + return PCIBIOS_SUCCESSFUL; \ + } \ + *value = read##sz(fake_dev->mapped_csrs + where); \ + if (where == PCI_COMMAND) \ + *value |= PCI_COMMAND_MEMORY; /* SBA omits this */ \ + return PCIBIOS_SUCCESSFUL; \ +} + +#define HP_CFG_WR(sz, bits, name) \ +static int hp_cfg_write##sz (struct pci_dev *dev, int where, u##bits value) \ +{ \ + struct fake_pci_dev *fake_dev; \ + \ + if (!(fake_dev = PCI_FAKE_DEV(dev))) \ + return orig_pci_ops->name(dev, where, value); \ + \ + if (where == PCI_BASE_ADDRESS_0) { \ + if (value == (u##bits) ~0) \ + fake_dev->sizing = 1; \ + return PCIBIOS_SUCCESSFUL; \ + } else \ + write##sz(value, fake_dev->mapped_csrs + where); \ + return PCIBIOS_SUCCESSFUL; \ +} + +HP_CFG_RD(b, 8, read_byte) +HP_CFG_RD(w, 16, read_word) +HP_CFG_RD(l, 32, read_dword) +HP_CFG_WR(b, 8, write_byte) +HP_CFG_WR(w, 16, write_word) +HP_CFG_WR(l, 32, write_dword) + +static struct pci_ops hp_pci_conf = { + hp_cfg_readb, + hp_cfg_readw, + hp_cfg_readl, + hp_cfg_writeb, + hp_cfg_writew, + hp_cfg_writel, +}; + +static void +hpzx1_fake_pci_dev(char *name, unsigned int busnum, unsigned long addr, unsigned int size) +{ + struct pci_controller *controller; + struct fake_pci_dev *fake; + int slot; + struct pci_dev *dev; + struct pci_bus *b, *bus = NULL; + u8 hdr; + + controller = kmalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) { + printk(KERN_ERR PFX "No memory for %s (0x%p) sysdata\n", name, + (void *) addr); + return; + } + memset(controller, 0, sizeof(*controller)); + + fake = kmalloc(sizeof(*fake), GFP_KERNEL); + if (!fake) { + printk(KERN_ERR PFX "No memory for %s (0x%p) sysdata\n", name, + (void *) addr); + kfree(controller); + return; + } + + memset(fake, 0, sizeof(*fake)); + fake->csr_base = addr; + fake->csr_size = size; + fake->mapped_csrs = (unsigned long) ioremap(addr, size); + fake->sizing = 0; + controller->platform_data = fake; + + pci_for_each_bus(b) + if (busnum == b->number) { + bus = b; + break; + } + + if (!bus) { + printk(KERN_ERR PFX "No host bus 0x%02x for %s (0x%p)\n", + busnum, name, (void *) addr); + kfree(fake); + kfree(controller); + return; + } + + for (slot = 0x1e; slot; slot--) + if (!pci_find_slot(busnum, PCI_DEVFN(slot, 0))) + break; + + if (slot < 0) { + printk(KERN_ERR PFX "No space for %s (0x%p) on bus 0x%02x\n", + name, (void *) addr, busnum); + kfree(fake); + kfree(controller); + return; + } + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR PFX "No memory for %s (0x%p)\n", name, + (void *) addr); + kfree(fake); + kfree(controller); + return; + } + + bus->ops = &hp_pci_conf; // replace pci ops for this bus + + memset(dev, 0, sizeof(*dev)); + dev->bus = bus; + dev->sysdata = controller; + dev->devfn = PCI_DEVFN(slot, 0); + pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor); + pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); + pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr); + dev->hdr_type = hdr & 0x7f; + + pci_setup_device(dev); + + // pci_insert_device() without running /sbin/hotplug + list_add_tail(&dev->bus_list, &bus->devices); + list_add_tail(&dev->global_list, &pci_devices); + + printk(KERN_INFO PFX "%s at 0x%lx; pci dev %s\n", name, addr, + dev->slot_name); + + hpzx1_devices++; +} + +static acpi_status +hpzx1_sba_probe(acpi_handle obj, u32 depth, void *context, void **ret) +{ + u64 csr_base = 0, csr_length = 0; + acpi_status status; + char *name = context; + char fullname[16]; + + status = acpi_hp_csr_space(obj, &csr_base, &csr_length); + if (ACPI_FAILURE(status)) + return status; + + /* + * Only SBA shows up in ACPI namespace, so its CSR space + * includes both SBA and IOC. Make SBA and IOC show up + * separately in PCI space. + */ + sprintf(fullname, "%s SBA", name); + hpzx1_fake_pci_dev(fullname, 0, csr_base, 0x1000); + sprintf(fullname, "%s IOC", name); + hpzx1_fake_pci_dev(fullname, 0, csr_base + 0x1000, 0x1000); + + return AE_OK; +} + +static acpi_status +hpzx1_lba_probe(acpi_handle obj, u32 depth, void *context, void **ret) +{ + u64 csr_base = 0, csr_length = 0; + acpi_status status; + NATIVE_UINT busnum; + char *name = context; + char fullname[32]; + + status = acpi_hp_csr_space(obj, &csr_base, &csr_length); + if (ACPI_FAILURE(status)) + return status; + + status = acpi_evaluate_integer(obj, METHOD_NAME__BBN, NULL, &busnum); + if (ACPI_FAILURE(status)) { + printk(KERN_WARNING PFX "evaluate _BBN fail=0x%x\n", status); + busnum = 0; // no _BBN; stick it on bus 0 + } + + sprintf(fullname, "%s _BBN 0x%02x", name, (unsigned int) busnum); + hpzx1_fake_pci_dev(fullname, busnum, csr_base, csr_length); + + return AE_OK; +} + +static void +hpzx1_acpi_dev_init(void) +{ + extern struct pci_ops *pci_root_ops; + + orig_pci_ops = pci_root_ops; + + /* + * Make fake PCI devices for the following hardware in the + * ACPI namespace. This makes it more convenient for drivers + * because they can claim these devices based on PCI + * information, rather than needing to know about ACPI. The + * 64-bit "HPA" space for this hardware is available as BAR + * 0/1. + * + * HWP0001: Single IOC SBA w/o IOC in namespace + * HWP0002: LBA device + * HWP0003: AGP LBA device + */ + acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL); +#ifdef CONFIG_IA64_HP_PROTO + if (hpzx1_devices) { +#endif + acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL); + acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL); + +#ifdef CONFIG_IA64_HP_PROTO + } + +#define ZX1_FUNC_ID_VALUE (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP + /* + * Early protos don't have bridges in the ACPI namespace, so + * if we didn't find anything, add the things we know are + * there. + */ + if (hpzx1_devices == 0) { + u64 hpa, csr_base; + + csr_base = 0xfed00000UL; + hpa = (u64) ioremap(csr_base, 0x2000); + if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) { + hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000); + hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000, + 0x1000); + + csr_base = 0xfed24000UL; + iounmap(hpa); + hpa = (u64) ioremap(csr_base, 0x1000); + hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base, + 0x1000); + } + iounmap(hpa); + } +#endif +} + +extern void sba_init(void); + +void +hpzx1_pci_fixup (int phase) +{ + iosapic_pci_fixup(phase); + switch (phase) { + case 0: + /* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */ + MAX_DMA_ADDRESS = ~0UL; + break; + + case 1: + hpzx1_acpi_dev_init(); + sba_init(); + break; + } +} diff -Nur linux-2.4.19/arch/ia64/ia32/binfmt_elf32.c linux-2.4.19-sgi211r3/arch/ia64/ia32/binfmt_elf32.c --- linux-2.4.19/arch/ia64/ia32/binfmt_elf32.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/ia32/binfmt_elf32.c Wed Feb 5 20:48:13 2003 @@ -47,6 +47,8 @@ #define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) #define elf_map elf32_map + +#undef SET_PERSONALITY #define SET_PERSONALITY(ex, ibcs2) elf32_set_personality() /* Ugly but avoids duplication */ @@ -89,6 +91,9 @@ vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; +#ifdef CONFIG_CPUMEMSET + vma->vm_mems_allowed = cms_current_mems_allowed(); +#endif down_write(¤t->mm->mmap_sem); { insert_vm_struct(current->mm, vma); @@ -111,6 +116,9 @@ vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; +#ifdef CONFIG_CPUMEMSET + vma->vm_mems_allowed = cms_current_mems_allowed(); +#endif down_write(¤t->mm->mmap_sem); { insert_vm_struct(current->mm, vma); @@ -184,6 +192,9 @@ mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = 0; +#ifdef CONFIG_CPUMEMSET + mpnt->vm_mems_allowed = cms_current_mems_allowed(); +#endif insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } diff -Nur linux-2.4.19/arch/ia64/ia32/ia32_signal.c linux-2.4.19-sgi211r3/arch/ia64/ia32/ia32_signal.c --- linux-2.4.19/arch/ia64/ia32/ia32_signal.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/ia32/ia32_signal.c Tue Oct 29 14:53:41 2002 @@ -39,6 +39,16 @@ #define __IA32_NR_sigreturn 119 #define __IA32_NR_rt_sigreturn 173 +register double f16 asm ("f16"); register double f17 asm ("f17"); +register double f18 asm ("f18"); register double f19 asm ("f19"); +register double f20 asm ("f20"); register double f21 asm ("f21"); +register double f22 asm ("f22"); register double f23 asm ("f23"); + +register double f24 asm ("f24"); register double f25 asm ("f25"); +register double f26 asm ("f26"); register double f27 asm ("f27"); +register double f28 asm ("f28"); register double f29 asm ("f29"); +register double f30 asm ("f30"); register double f31 asm ("f31"); + struct sigframe_ia32 { int pretcode; @@ -143,6 +153,282 @@ return err; } + +/* + * SAVE and RESTORE of ia32 fpstate info, from ia64 current state + * Used in exception handler to pass the fpstate to the user, and restore + * the fpstate while returning from the exception handler. + * + * fpstate info and their mapping to IA64 regs: + * fpstate REG(BITS) Attribute Comments + * cw ar.fcr(0:12) with bits 7 and 6 not used + * sw ar.fsr(0:15) + * tag ar.fsr(16:31) with odd numbered bits not used + * (read returns 0, writes ignored) + * ipoff ar.fir(0:31) RO + * cssel ar.fir(32:47) RO + * dataoff ar.fdr(0:31) RO + * datasel ar.fdr(32:47) RO + * + * _st[(0+TOS)%8] f8 + * _st[(1+TOS)%8] f9 (f8, f9 from ptregs) + * : : : (f10..f15 from live reg) + * : : : + * _st[(7+TOS)%8] f15 TOS=sw.top(bits11:13) + * + * status Same as sw RO + * magic 0 as X86_FXSR_MAGIC in ia32 + * mxcsr Bits(7:15)=ar.fcr(39:47) + * Bits(0:5) =ar.fsr(32:37) with bit 6 reserved + * _xmm[0..7] f16..f31 (live registers) + * with _xmm[0] + * Bit(64:127)=f17(0:63) + * Bit(0:63)=f16(0:63) + * All other fields unused... + */ + +#define __ldfe(regnum, x) \ +({ \ + register double __f__ asm ("f"#regnum); \ + __asm__ __volatile__ ("ldfe %0=[%1] ;;" :"=f"(__f__): "r"(x)); \ +}) + +#define __ldf8(regnum, x) \ +({ \ + register double __f__ asm ("f"#regnum); \ + __asm__ __volatile__ ("ldf8 %0=[%1] ;;" :"=f"(__f__): "r"(x)); \ +}) + +#define __stfe(x, regnum) \ +({ \ + register double __f__ asm ("f"#regnum); \ + __asm__ __volatile__ ("stfe [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ +}) + +#define __stf8(x, regnum) \ +({ \ + register double __f__ asm ("f"#regnum); \ + __asm__ __volatile__ ("stf8 [%0]=%1" :: "r"(x), "f"(__f__) : "memory"); \ +}) + +static int +save_ia32_fpstate_live (struct _fpstate_ia32 *save) +{ + struct task_struct *tsk = current; + struct pt_regs *ptp; + struct _fpreg_ia32 *fpregp; + char buf[32]; + unsigned long fsr, fcr, fir, fdr; + unsigned long new_fsr; + unsigned long num128[2]; + unsigned long mxcsr=0; + int fp_tos, fr8_st_map; + + if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) + return -EFAULT; + + /* Readin fsr, fcr, fir, fdr and copy onto fpstate */ + asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr)); + asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr)); + asm volatile ( "mov %0=ar.fir;" : "=r"(fir)); + asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr)); + /* + * We need to clear the exception state before calling the signal + * handler. Clear the bits 15, bits 0-7 in fp status word. Similar + * to the functionality of fnclex instruction. + */ + new_fsr = fsr & (~0x80ff) ; + asm volatile ( "mov ar.fsr=%0;" :: "r"(new_fsr)); + + __put_user(fcr & 0xffff, &save->cw); + __put_user(fsr & 0xffff, &save->sw); + __put_user((fsr>>16) & 0xffff, &save->tag); + __put_user(fir, &save->ipoff); + __put_user((fir>>32) & 0xffff, &save->cssel); + __put_user(fdr, &save->dataoff); + __put_user((fdr>>32) & 0xffff, &save->datasel); + __put_user(fsr & 0xffff, &save->status); + + mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f); + __put_user(mxcsr & 0xffff, &save->mxcsr); + __put_user( 0, &save->magic); //#define X86_FXSR_MAGIC 0x0000 + + /* + * save f8 and f9 from pt_regs + * save f10..f15 from live register set + */ + /* + * Find the location where f8 has to go in fp reg stack + * This depends on TOP(11:13) field of sw. Other f reg continue + * sequentially from where f8 maps to. + */ + fp_tos = (fsr>>11)&0x7; + fr8_st_map = (8-fp_tos)&0x7; + ptp = ia64_task_regs(tsk); + fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); + ia64f2ia32f(fpregp, &ptp->f8); + copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + ia64f2ia32f(fpregp, &ptp->f9); + copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + + __stfe(fpregp, 10); + copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + __stfe(fpregp, 11); + copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + __stfe(fpregp, 12); + copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + __stfe(fpregp, 13); + copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + __stfe(fpregp, 14); + copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + __stfe(fpregp, 15); + copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + + __stf8(&num128[0], 16); + __stf8(&num128[1], 17); + copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32)); + + __stf8(&num128[0], 18); + __stf8(&num128[1], 19); + copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32)); + + __stf8(&num128[0], 20); + __stf8(&num128[1], 21); + copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32)); + + __stf8(&num128[0], 22); + __stf8(&num128[1], 23); + copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32)); + + __stf8(&num128[0], 24); + __stf8(&num128[1], 25); + copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32)); + + __stf8(&num128[0], 26); + __stf8(&num128[1], 27); + copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32)); + + __stf8(&num128[0], 28); + __stf8(&num128[1], 29); + copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32)); + + __stf8(&num128[0], 30); + __stf8(&num128[1], 31); + copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32)); + return 0; +} + +static int +restore_ia32_fpstate_live (struct _fpstate_ia32 *save) +{ + struct task_struct *tsk = current; + struct pt_regs *ptp; + unsigned int lo, hi; + unsigned long num128[2]; + unsigned long num64, mxcsr; + struct _fpreg_ia32 *fpregp; + char buf[32]; + unsigned long fsr, fcr; + int fp_tos, fr8_st_map; + + if (!access_ok(VERIFY_READ, save, sizeof(*save))) + return(-EFAULT); + + /* + * Updating fsr, fcr, fir, fdr. + * Just a bit more complicated than save. + * - Need to make sure that we dont write any value other than the + * specific fpstate info + * - Need to make sure that the untouched part of frs, fdr, fir, fcr + * should remain same while writing. + * So, we do a read, change specific fields and write. + */ + asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr)); + asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr)); + + __get_user(mxcsr, (unsigned int *)&save->mxcsr); + /* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */ + __get_user(lo, (unsigned int *)&save->cw); + num64 = mxcsr & 0xff10; + num64 = (num64 << 32) | (lo & 0x1f3f); + fcr = (fcr & (~0xff1000001f3f)) | num64; + + /* setting bits 0..31 with sw and tag and 32..37 from mxcsr */ + __get_user(lo, (unsigned int *)&save->sw); + __get_user(hi, (unsigned int *)&save->tag); + num64 = mxcsr & 0x3f; + num64 = (num64 << 16) | (hi & 0xffff); + num64 = (num64 << 16) | (lo & 0xffff); + fsr = (fsr & (~0x3fffffffff)) | num64; + + asm volatile ( "mov ar.fsr=%0;" :: "r"(fsr)); + asm volatile ( "mov ar.fcr=%0;" :: "r"(fcr)); + /* + * restore f8, f9 onto pt_regs + * restore f10..f15 onto live registers + */ + /* + * Find the location where f8 has to go in fp reg stack + * This depends on TOP(11:13) field of sw. Other f reg continue + * sequentially from where f8 maps to. + */ + fp_tos = (fsr>>11)&0x7; + fr8_st_map = (8-fp_tos)&0x7; + fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); + + ptp = ia64_task_regs(tsk); + copy_from_user(fpregp, &save->_st[(0+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + ia32f2ia64f(&ptp->f8, fpregp); + copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + ia32f2ia64f(&ptp->f9, fpregp); + + copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + __ldfe(10, fpregp); + copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + __ldfe(11, fpregp); + copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + __ldfe(12, fpregp); + copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + __ldfe(13, fpregp); + copy_from_user(fpregp, &save->_st[(6+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + __ldfe(14, fpregp); + copy_from_user(fpregp, &save->_st[(7+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); + __ldfe(15, fpregp); + + copy_from_user(num128, &save->_xmm[0], sizeof(struct _xmmreg_ia32)); + __ldf8(16, &num128[0]); + __ldf8(17, &num128[1]); + + copy_from_user(num128, &save->_xmm[1], sizeof(struct _xmmreg_ia32)); + __ldf8(18, &num128[0]); + __ldf8(19, &num128[1]); + + copy_from_user(num128, &save->_xmm[2], sizeof(struct _xmmreg_ia32)); + __ldf8(20, &num128[0]); + __ldf8(21, &num128[1]); + + copy_from_user(num128, &save->_xmm[3], sizeof(struct _xmmreg_ia32)); + __ldf8(22, &num128[0]); + __ldf8(23, &num128[1]); + + copy_from_user(num128, &save->_xmm[4], sizeof(struct _xmmreg_ia32)); + __ldf8(24, &num128[0]); + __ldf8(25, &num128[1]); + + copy_from_user(num128, &save->_xmm[5], sizeof(struct _xmmreg_ia32)); + __ldf8(26, &num128[0]); + __ldf8(27, &num128[1]); + + copy_from_user(num128, &save->_xmm[6], sizeof(struct _xmmreg_ia32)); + __ldf8(28, &num128[0]); + __ldf8(29, &num128[1]); + + copy_from_user(num128, &save->_xmm[7], sizeof(struct _xmmreg_ia32)); + __ldf8(30, &num128[0]); + __ldf8(31, &num128[1]); + return 0; +} + static inline void sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer) { @@ -371,6 +657,9 @@ int err = 0; unsigned long flag; + if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc))) + return -EFAULT; + err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs); err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs); err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es); @@ -397,6 +686,11 @@ err |= __put_user(regs->r12, &sc->esp_at_signal); err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); + if ( save_ia32_fpstate_live(fpstate) < 0 ) + err = -EFAULT; + else + err |= __put_user((u32)(u64)fpstate, &sc->fpstate); + #if 0 tmp = save_i387(fpstate); if (tmp < 0) @@ -418,6 +712,9 @@ { unsigned int err = 0; + if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) + return(-EFAULT); + #define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) #define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) @@ -475,6 +772,16 @@ asm volatile ("mov ar.eflag=%0 ;;" :: "r"(flag)); regs->r1 = -1; /* disable syscall checks, r1 is orig_eax */ + } + + { + struct _fpstate_ia32 *buf = NULL; + u32 fpstate_ptr; + err |= get_user(fpstate_ptr, &(sc->fpstate)); + buf = (struct _fpstate_ia32 *)(u64)fpstate_ptr; + if (buf) { + err |= restore_ia32_fpstate_live(buf); + } } #if 0 diff -Nur linux-2.4.19/arch/ia64/ia32/ia32_traps.c linux-2.4.19-sgi211r3/arch/ia64/ia32/ia32_traps.c --- linux-2.4.19/arch/ia64/ia32/ia32_traps.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/ia32/ia32_traps.c Fri Apr 26 11:07:18 2002 @@ -20,7 +20,7 @@ { switch ((isr >> 16) & 0xff) { case 0: /* Instruction intercept fault */ - case 3: /* Locked Data reference fault */ + case 4: /* Locked Data reference fault */ case 1: /* Gate intercept trap */ return -1; diff -Nur linux-2.4.19/arch/ia64/ia32/sys_ia32.c linux-2.4.19-sgi211r3/arch/ia64/ia32/sys_ia32.c --- linux-2.4.19/arch/ia64/ia32/sys_ia32.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/ia32/sys_ia32.c Mon Dec 16 12:46:56 2002 @@ -623,7 +623,8 @@ /* end address is 4KB aligned but not page aligned. */ retval = mprotect_subpage(PAGE_START(end), prot); if (retval < 0) - return retval; + goto out; + end = PAGE_START(end); } retval = sys_mprotect(start, end - start, prot); @@ -2843,20 +2844,6 @@ } } -static inline void -ia32f2ia64f (void *dst, void *src) -{ - asm volatile ("ldfe f6=[%1];; stf.spill [%0]=f6" :: "r"(dst), "r"(src) : "memory"); - return; -} - -static inline void -ia64f2ia32f (void *dst, void *src) -{ - asm volatile ("ldf.fill f6=[%1];; stfe [%0]=f6" :: "r"(dst), "r"(src) : "memory"); - return; -} - static void put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos) @@ -3693,7 +3680,11 @@ return result; } -struct dqblk32 { +extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr); + +#ifdef CONFIG_QIFACE_COMPAT +#ifdef CONFIG_QIFACE_V1 +struct user_dqblk32 { __u32 dqb_bhardlimit; __u32 dqb_bsoftlimit; __u32 dqb_curblocks; @@ -3703,49 +3694,82 @@ __kernel_time_t32 dqb_btime; __kernel_time_t32 dqb_itime; }; +typedef struct v1c_mem_dqblk comp_dqblk_t; -asmlinkage long -sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr) +#define Q_COMP_GETQUOTA Q_V1_GETQUOTA +#define Q_COMP_SETQUOTA Q_V1_SETQUOTA +#define Q_COMP_SETQLIM Q_V1_SETQLIM +#define Q_COMP_SETUSE Q_V1_SETUSE +#else +struct user_dqblk32 { + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u64 dqb_curspace; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v2c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V2_GETQUOTA +#define Q_COMP_SETQUOTA Q_V2_SETQUOTA +#define Q_COMP_SETQLIM Q_V2_SETQLIM +#define Q_COMP_SETUSE Q_V2_SETUSE +#endif + +asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) { - extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t); int cmds = cmd >> SUBCMDSHIFT; + long err; + comp_dqblk_t d; mm_segment_t old_fs; - struct dqblk d; char *spec; - long err; - + switch (cmds) { - case Q_GETQUOTA: - break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, addr, sizeof(struct dqblk32))) - return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; - break; - default: - return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr); + case Q_COMP_GETQUOTA: + break; + case Q_COMP_SETQUOTA: + case Q_COMP_SETUSE: + case Q_COMP_SETQLIM: + if (copy_from_user(&d, (struct user_dqblk32 *)addr, + sizeof (struct user_dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime; + break; + default: + return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr); } - spec = getname32((void *) A(special)); + spec = getname (special); err = PTR_ERR(spec); - if (IS_ERR(spec)) + if (IS_ERR(spec)) return err; + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); + set_fs (old_fs); + putname (spec); + if (err) return err; - old_fs = get_fs (); - set_fs(KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); - set_fs(old_fs); - putname(spec); - if (cmds == Q_GETQUOTA) { + if (cmds == Q_COMP_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user(addr, &d, sizeof(struct dqblk32))) + ((struct user_dqblk32 *)&d)->dqb_itime = i; + ((struct user_dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct user_dqblk32 *)addr, &d, + sizeof (struct user_dqblk32))) return -EFAULT; } - return err; + return 0; } + +#else +/* No conversion needed for new interface */ +asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) +{ + return sys_quotactl(cmd, special, id, addr); +} +#endif asmlinkage long sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval) diff -Nur linux-2.4.19/arch/ia64/kdb/ChangeLog linux-2.4.19-sgi211r3/arch/ia64/kdb/ChangeLog --- linux-2.4.19/arch/ia64/kdb/ChangeLog Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ChangeLog Tue Feb 4 15:36:30 2003 @@ -0,0 +1,89 @@ +2003-02-04 Keith Owens + + * Backport to2.4.19-ia64-020821-1. + * kdb v3.0-2.4.19-ia64-020821-1. + +2003-02-03 Keith Owens + + * Register kdb commands early. + * Handle KDB_ENTER() when kdb=off. + * Optimize __kdba_getarea_size when width is a constant. + * Decode oops via kallsyms if it is available. + * Update copyright notices to 2003. + * Add commands to dump struct pt_regs and switch_stack. + * Handle padding from unw_init_running for switch_stack. + * Add dummy kdba_local_arch_setup/kdba_local_arch_cleanup. + * Warning for pod mode. + * Add command history and editing. Sonic Zhang. + * kdb_toggleled is conditional on KDB_BLINK_LED. Bernhard Fischer. + * Allow tab on serial line for symbol completion. + * Ignore KDB_ENTER() when kdb is already running. + * kdb v3.0-2.4.20-ia64-021210-1. + +2003-01-23 Keith Owens + + * Upgrade to 2.4.20-ia64-021210. + * kdb v2.5-2.4.20-ia64-021210-1. + +2002-11-14 Keith Owens + + * General clean up of handling for breakpoints and single stepping over + software breakpoints. + * kdb v2.5-2.4.19-ia64-020821-1. + +2002-10-31 Keith Owens + + * Remove kdb_eframe_t. + * Sanity check if we have pt_regs. + * Remove kdba_getcurrentframe(). + * Comments for coexistence with O(1) scheduler. + * kdb v2.4-2.4.19-ia64-020821-1. + +2002-10-15 Keith Owens + + * Minimize differences between patches for 2.4 and 2.5 kernels. + * kdb v2.3-2.4.19-ia64-020821-2. + +2002-08-10 Keith Owens + + * Verify rw address for instruction breakpoint. + * Replace kdb_port with kdb_serial to support memory mapped I/O. + David Mosberger. + Note: This needs kdb v2.3-2.4.18-common-2 or later. + * kdb v2.3-2.4.18-ia64-020722-2. + +2002-08-07 Keith Owens + + * Upgrade to 2.4.18-ia64-020722. + * Remove individual SGI copyrights, the general SGI copyright applies. + * Clean up disassembly layout. Hugh Dickins, Keith Owens. + * Remove fixed KDB_MAX_COMMANDS size. + * Add set_fs() around __copy_to_user on kernel addresses. + Randolph Chung. + * Position ia64 for CONFIG_NUMA_REPLICATE. + * Stacked registers modification support. Sebastien Lelarge. + * USB keyboard support. Sebastien Lelarge. + * kdb v2.3-2.4.18-ia64-020722-1. + +2002-03-20 Keith Owens + + * Sync with 2.4.17-sn2. + * Add pod command. + +2002-02-20 Keith Owens + + * Call kdb from mca handler. Jenna S. Hall, Intel. + * kdb v2.1-2.4.17-ia64-011226-2. + +2002-01-18 Keith Owens + + * Replace kdb_get/putword with kdb_get/putarea functions. + * Wrap kdb references in #ifdef CONFIG_KDB. + * Delete sample i386 code. + * Refuse to update kernel text on NUMA systems. + * Reject hardware breakpoints, not supported yet. + * kdb v2.1-2.4.17-ia64-011226-1. + +2002-01-07 Keith Owens + + * Split kdb for ia64 as kdb v2.0-2.4.17-ia64-011226-1. diff -Nur linux-2.4.19/arch/ia64/kdb/Makefile linux-2.4.19-sgi211r3/arch/ia64/kdb/Makefile --- linux-2.4.19/arch/ia64/kdb/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/Makefile Tue Feb 4 15:36:30 2003 @@ -0,0 +1,46 @@ +# +# Copyright (c) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +O_TARGET := kdba.o +obj-y := kdba_bt.o kdba_bp.o kdba_io.o kdbasupport.o \ + cpu-ia64-opc.o ia64-dis.o ia64-opc.o kdba_id.o kdba_jmp.o + +obj-$(CONFIG_IA64_SGI_SN2) += kdba_pod.o + +override CFLAGS := $(CFLAGS:%-pg=% ) + +EXTRA_CFLAGS += -I $(TOPDIR)/arch/$(ARCH)/kdb + +AFLAGS_kdba_jmp.o += $(AFLAGS_KERNEL) + +USE_STANDARD_AS_RULE := true +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/kdb/ansidecl.h linux-2.4.19-sgi211r3/arch/ia64/kdb/ansidecl.h --- linux-2.4.19/arch/ia64/kdb/ansidecl.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ansidecl.h Wed Jan 30 15:40:36 2002 @@ -0,0 +1,251 @@ +/* ANSI and traditional C compatability macros + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + PTR `void *' `char *' + LONG_DOUBLE `long double' `double' + VOLATILE `volatile' `' + SIGNED `signed' `' + PTRCONST `void *const' `char *' + ANSI_PROTOTYPES 1 not defined + + CONST is also defined, but is obsolete. Just use const. + + obsolete -- DEFUN (name, arglist, args) + + Defines function NAME. + + ARGLIST lists the arguments, separated by commas and enclosed in + parentheses. ARGLIST becomes the argument list in traditional C. + + ARGS list the arguments with their types. It becomes a prototype in + ANSI C, and the type declarations in traditional C. Arguments should + be separated with `AND'. For functions with a variable number of + arguments, the last thing listed should be `DOTS'. + + obsolete -- DEFUN_VOID (name) + + Defines a function NAME, which takes no arguments. + + obsolete -- EXFUN (name, (prototype)) -- obsolete. + + Replaced by PARAMS. Do not use; will disappear someday soon. + Was used in external function declarations. + In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in + parentheses). In traditional C it is `NAME()'. + For a function that takes no arguments, PROTOTYPE should be `(void)'. + + obsolete -- PROTO (type, name, (prototype) -- obsolete. + + This one has also been replaced by PARAMS. Do not use. + + PARAMS ((args)) + + We could use the EXFUN macro to handle prototype declarations, but + the name is misleading and the result is ugly. So we just define a + simple macro to handle the parameter lists, as in: + + static int foo PARAMS ((int, char)); + + This produces: `static int foo();' or `static int foo (int, char);' + + EXFUN would have done it like this: + + static int EXFUN (foo, (int, char)); + + but the function is not external...and it's hard to visually parse + the function name out of the mess. EXFUN should be considered + obsolete; new code should be written to use PARAMS. + + DOTS is also obsolete. + + Examples: + + extern int printf PARAMS ((const char *format, ...)); +*/ + +#ifndef _ANSIDECL_H + +#define _ANSIDECL_H 1 + + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + + +#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ + +#define PTR void * +#define PTRCONST void *CONST +#define LONG_DOUBLE long double + +#ifndef IN_GCC +#define AND , +#define NOARGS void +#define VOLATILE volatile +#define SIGNED signed +#endif /* ! IN_GCC */ + +#define PARAMS(paramlist) paramlist +#define ANSI_PROTOTYPES 1 + +#define VPARAMS(ARGS) ARGS +#define VA_START(va_list,var) va_start(va_list,var) + +/* These are obsolete. Do not use. */ +#ifndef IN_GCC +#define CONST const +#define DOTS , ... +#define PROTO(type, name, arglist) type name arglist +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(void) +#endif /* ! IN_GCC */ + +#else /* Not ANSI C. */ + +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#ifndef IN_GCC +#define AND ; +#define NOARGS +#define VOLATILE +#define SIGNED +#endif /* !IN_GCC */ + +#ifndef const /* some systems define it in header files for non-ansi mode */ +#define const +#endif + +#define PARAMS(paramlist) () + +#define VPARAMS(ARGS) (va_alist) va_dcl +#define VA_START(va_list,var) va_start(va_list) + +/* These are obsolete. Do not use. */ +#ifndef IN_GCC +#define CONST +#define DOTS +#define PROTO(type, name, arglist) type name () +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() +#endif /* ! IN_GCC */ + +#endif /* ANSI C. */ + +/* Using MACRO(x,y) in cpp #if conditionals does not work with some + older preprocessors. Thus we can't define something like this: + +#define HAVE_GCC_VERSION(MAJOR, MINOR) \ + (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) + +and then test "#if HAVE_GCC_VERSION(2,7)". + +So instead we use the macro below and test it against specific values. */ + +/* This macro simplifies testing whether we are using gcc, and if it + is of a particular minimum version. (Both major & minor numbers are + significant.) This macro will evaluate to 0 if we are not using + gcc at all. */ +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +/* Define macros for some gcc attributes. This permits us to use the + macros freely, and know that they will come into play for the + version of gcc in which they are supported. */ + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ +#ifndef ATTRIBUTE_MALLOC +# if (GCC_VERSION >= 2096) +# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define ATTRIBUTE_MALLOC +# endif /* GNUC >= 2.96 */ +#endif /* ATTRIBUTE_MALLOC */ + +/* Attributes on labels were valid as of gcc 2.93. */ +#ifndef ATTRIBUTE_UNUSED_LABEL +# if (GCC_VERSION >= 2093) +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif /* GNUC >= 2.93 */ +#endif /* ATTRIBUTE_UNUSED_LABEL */ + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif /* ATTRIBUTE_UNUSED */ + +#ifndef ATTRIBUTE_NORETURN +#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif /* ATTRIBUTE_NORETURN */ + +#ifndef ATTRIBUTE_PRINTF +#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) +#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) +#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) +#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) +#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) +#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) +#endif /* ATTRIBUTE_PRINTF */ + +/* We use __extension__ in some places to suppress -pedantic warnings + about GCC extensions. This feature didn't work properly before + gcc 2.8. */ +#if GCC_VERSION < 2008 +#define __extension__ +#endif + +/* Bootstrap support: Autoconf will possibly define the `inline' or + `const' keywords as macros, however this is only valid for the + stage1 compiler. If we detect a modern version of gcc, + unconditionally reset the values. This makes sure the right thing + happens in stage2 and later. We need to do this very early; + i.e. before any header files that might use these keywords. + Otherwise conflicts might occur. */ + +#if (GCC_VERSION >= 2007) +# ifdef __STDC__ +# undef const +# endif +# undef inline +# define inline __inline__ /* __inline__ prevents -pedantic warnings */ +# ifndef HAVE_LONG_DOUBLE +# define HAVE_LONG_DOUBLE 1 +# endif +#endif /* GCC >= 2.7 */ + +#endif /* ansidecl.h */ diff -Nur linux-2.4.19/arch/ia64/kdb/bfd.h linux-2.4.19-sgi211r3/arch/ia64/kdb/bfd.h --- linux-2.4.19/arch/ia64/kdb/bfd.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/bfd.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,3612 @@ +/* Main header file for the bfd library -- portable access to object files. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001 + Free Software Foundation, Inc. + Contributed by Cygnus Support. + +** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them; +** instead, change bfd-in.h or the other BFD source files processed to +** generate these files. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* bfd.h -- The only header file required by users of the bfd library + +The bfd.h file is generated from bfd-in.h and various .c files; if you +change it, your changes will probably be lost. + +All the prototypes and definitions following the comment "THE FOLLOWING +IS EXTRACTED FROM THE SOURCE" are extracted from the source files for +BFD. If you change it, someone oneday will extract it from the source +again, and your changes will be lost. To save yourself from this bind, +change the definitions in the source in the bfd directory. Type "make +docs" and then "make headers" in that directory, and magically this file +will change to reflect your changes. + +If you don't have the tools to perform the extraction, then you are +safe from someone on your system trampling over your header files. +You should still maintain the equivalence between the source and this +file though; every change you make to the .c file should be reflected +here. */ + +#ifndef __BFD_H_SEEN__ +#define __BFD_H_SEEN__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" + +/* These two lines get substitutions done by commands in Makefile.in. */ +#define BFD_VERSION "2.11.90.0.8" +#define BFD_ARCH_SIZE 64 +#define BFD_HOST_64BIT_LONG 1 +#if 0 +#define BFD_HOST_64_BIT +#define BFD_HOST_U_64_BIT +#endif + +#if BFD_ARCH_SIZE >= 64 +#define BFD64 +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* forward declaration */ +typedef struct _bfd bfd; + +/* To squelch erroneous compiler warnings ("illegal pointer + combination") from the SVR3 compiler, we would like to typedef + boolean to int (it doesn't like functions which return boolean. + Making sure they are never implicitly declared to return int + doesn't seem to help). But this file is not configured based on + the host. */ +/* General rules: functions which are boolean return true on success + and false on failure (unless they're a predicate). -- bfd.doc */ +/* I'm sure this is going to break something and someone is going to + force me to change it. */ +/* typedef enum boolean {false, true} boolean; */ +/* Yup, SVR4 has a "typedef enum boolean" in -fnf */ +/* It gets worse if the host also defines a true/false enum... -sts */ +/* And even worse if your compiler has built-in boolean types... -law */ +#if defined (__GNUG__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6)) +#define TRUE_FALSE_ALREADY_DEFINED +#endif +#ifdef MPW +/* Pre-emptive strike - get the file with the enum. */ +#include +#define TRUE_FALSE_ALREADY_DEFINED +#endif /* MPW */ +#ifndef TRUE_FALSE_ALREADY_DEFINED +typedef enum bfd_boolean {false, true} boolean; +#define BFD_TRUE_FALSE +#else +/* Use enum names that will appear nowhere else. */ +typedef enum bfd_boolean {bfd_fffalse, bfd_tttrue} boolean; +#endif + +/* A pointer to a position in a file. */ +/* FIXME: This should be using off_t from . + For now, try to avoid breaking stuff by not including here. + This will break on systems with 64-bit file offsets (e.g. 4.4BSD). + Probably the best long-term answer is to avoid using file_ptr AND off_t + in this header file, and to handle this in the BFD implementation + rather than in its interface. */ +/* typedef off_t file_ptr; */ +typedef long int file_ptr; + +/* Support for different sizes of target format ints and addresses. + If the type `long' is at least 64 bits, BFD_HOST_64BIT_LONG will be + set to 1 above. Otherwise, if gcc is being used, this code will + use gcc's "long long" type. Otherwise, BFD_HOST_64_BIT must be + defined above. */ + +#ifndef BFD_HOST_64_BIT +# if BFD_HOST_64BIT_LONG +# define BFD_HOST_64_BIT long +# define BFD_HOST_U_64_BIT unsigned long +# else +# ifdef __GNUC__ +# if __GNUC__ >= 2 +# define BFD_HOST_64_BIT long long +# define BFD_HOST_U_64_BIT unsigned long long +# endif /* __GNUC__ >= 2 */ +# endif /* ! defined (__GNUC__) */ +# endif /* ! BFD_HOST_64BIT_LONG */ +#endif /* ! defined (BFD_HOST_64_BIT) */ + +#ifdef BFD64 + +#ifndef BFD_HOST_64_BIT + #error No 64 bit integer type available +#endif /* ! defined (BFD_HOST_64_BIT) */ + +typedef BFD_HOST_U_64_BIT bfd_vma; +typedef BFD_HOST_64_BIT bfd_signed_vma; +typedef BFD_HOST_U_64_BIT bfd_size_type; +typedef BFD_HOST_U_64_BIT symvalue; + +#ifndef fprintf_vma +#if BFD_HOST_64BIT_LONG +#define sprintf_vma(s,x) sprintf (s, "%016lx", x) +#define fprintf_vma(f,x) fprintf (f, "%016lx", x) +#else +#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) +#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) +#define fprintf_vma(s,x) \ + fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#define sprintf_vma(s,x) \ + sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#endif +#endif + +#else /* not BFD64 */ + +/* Represent a target address. Also used as a generic unsigned type + which is guaranteed to be big enough to hold any arithmetic types + we need to deal with. */ +typedef unsigned long bfd_vma; + +/* A generic signed type which is guaranteed to be big enough to hold any + arithmetic types we need to deal with. Can be assumed to be compatible + with bfd_vma in the same way that signed and unsigned ints are compatible + (as parameters, in assignment, etc). */ +typedef long bfd_signed_vma; + +typedef unsigned long symvalue; +typedef unsigned long bfd_size_type; + +/* Print a bfd_vma x on stream s. */ +#define fprintf_vma(s,x) fprintf (s, "%08lx", x) +#define sprintf_vma(s,x) sprintf (s, "%08lx", x) + +#endif /* not BFD64 */ + +#define printf_vma(x) fprintf_vma(stdout,x) + +typedef unsigned int flagword; /* 32 bits of flags */ +typedef unsigned char bfd_byte; + +/** File formats */ + +typedef enum bfd_format { + bfd_unknown = 0, /* file format is unknown */ + bfd_object, /* linker/assember/compiler output */ + bfd_archive, /* object archive file */ + bfd_core, /* core dump */ + bfd_type_end} /* marks the end; don't use it! */ + bfd_format; + +/* Values that may appear in the flags field of a BFD. These also + appear in the object_flags field of the bfd_target structure, where + they indicate the set of flags used by that backend (not all flags + are meaningful for all object file formats) (FIXME: at the moment, + the object_flags values have mostly just been copied from backend + to another, and are not necessarily correct). */ + +/* No flags. */ +#define BFD_NO_FLAGS 0x00 + +/* BFD contains relocation entries. */ +#define HAS_RELOC 0x01 + +/* BFD is directly executable. */ +#define EXEC_P 0x02 + +/* BFD has line number information (basically used for F_LNNO in a + COFF header). */ +#define HAS_LINENO 0x04 + +/* BFD has debugging information. */ +#define HAS_DEBUG 0x08 + +/* BFD has symbols. */ +#define HAS_SYMS 0x10 + +/* BFD has local symbols (basically used for F_LSYMS in a COFF + header). */ +#define HAS_LOCALS 0x20 + +/* BFD is a dynamic object. */ +#define DYNAMIC 0x40 + +/* Text section is write protected (if D_PAGED is not set, this is + like an a.out NMAGIC file) (the linker sets this by default, but + clears it for -r or -N). */ +#define WP_TEXT 0x80 + +/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the + linker sets this by default, but clears it for -r or -n or -N). */ +#define D_PAGED 0x100 + +/* BFD is relaxable (this means that bfd_relax_section may be able to + do something) (sometimes bfd_relax_section can do something even if + this is not set). */ +#define BFD_IS_RELAXABLE 0x200 + +/* This may be set before writing out a BFD to request using a + traditional format. For example, this is used to request that when + writing out an a.out object the symbols not be hashed to eliminate + duplicates. */ +#define BFD_TRADITIONAL_FORMAT 0x400 + +/* This flag indicates that the BFD contents are actually cached in + memory. If this is set, iostream points to a bfd_in_memory struct. */ +#define BFD_IN_MEMORY 0x800 + +/* symbols and relocation */ + +/* A count of carsyms (canonical archive symbols). */ +typedef unsigned long symindex; + +/* How to perform a relocation. */ +typedef const struct reloc_howto_struct reloc_howto_type; + +#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) + +/* General purpose part of a symbol X; + target specific parts are in libcoff.h, libaout.h, etc. */ + +#define bfd_get_section(x) ((x)->section) +#define bfd_get_output_section(x) ((x)->section->output_section) +#define bfd_set_section(x,y) ((x)->section) = (y) +#define bfd_asymbol_base(x) ((x)->section->vma) +#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) +#define bfd_asymbol_name(x) ((x)->name) +/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ +#define bfd_asymbol_bfd(x) ((x)->the_bfd) +#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) + +/* A canonical archive symbol. */ +/* This is a type pun with struct ranlib on purpose! */ +typedef struct carsym { + char *name; + file_ptr file_offset; /* look here to find the file */ +} carsym; /* to make these you call a carsymogen */ + +/* Used in generating armaps (archive tables of contents). + Perhaps just a forward definition would do? */ +struct orl { /* output ranlib */ + char **name; /* symbol name */ + file_ptr pos; /* bfd* or file position */ + int namidx; /* index into string table */ +}; + +/* Linenumber stuff */ +typedef struct lineno_cache_entry { + unsigned int line_number; /* Linenumber from start of function*/ + union { + struct symbol_cache_entry *sym; /* Function name */ + unsigned long offset; /* Offset into section */ + } u; +} alent; + +/* object and core file sections */ + +#define align_power(addr, align) \ + ( ((addr) + ((1<<(align))-1)) & (-1 << (align))) + +typedef struct sec *sec_ptr; + +#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) +#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) +#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_section_name(bfd, ptr) ((ptr)->name) +#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr)) +#define bfd_section_vma(bfd, ptr) ((ptr)->vma) +#define bfd_section_lma(bfd, ptr) ((ptr)->lma) +#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) +#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) +#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) + +#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) + +#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = (boolean)true), true) +#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true) +#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true) + +typedef struct stat stat_type; + +typedef enum bfd_print_symbol +{ + bfd_print_symbol_name, + bfd_print_symbol_more, + bfd_print_symbol_all +} bfd_print_symbol_type; + +/* Information about a symbol that nm needs. */ + +typedef struct _symbol_info +{ + symvalue value; + char type; + CONST char *name; /* Symbol name. */ + unsigned char stab_type; /* Stab type. */ + char stab_other; /* Stab other. */ + short stab_desc; /* Stab desc. */ + CONST char *stab_name; /* String for stab type. */ +} symbol_info; + +/* Get the name of a stabs type code. */ + +extern const char *bfd_get_stab_name PARAMS ((int)); + +/* Hash table routines. There is no way to free up a hash table. */ + +/* An element in the hash table. Most uses will actually use a larger + structure, and an instance of this will be the first field. */ + +struct bfd_hash_entry +{ + /* Next entry for this hash code. */ + struct bfd_hash_entry *next; + /* String being hashed. */ + const char *string; + /* Hash code. This is the full hash code, not the index into the + table. */ + unsigned long hash; +}; + +/* A hash table. */ + +struct bfd_hash_table +{ + /* The hash array. */ + struct bfd_hash_entry **table; + /* The number of slots in the hash table. */ + unsigned int size; + /* A function used to create new elements in the hash table. The + first entry is itself a pointer to an element. When this + function is first invoked, this pointer will be NULL. However, + having the pointer permits a hierarchy of method functions to be + built each of which calls the function in the superclass. Thus + each function should be written to allocate a new block of memory + only if the argument is NULL. */ + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + /* An objalloc for this hash table. This is a struct objalloc *, + but we use PTR to avoid requiring the inclusion of objalloc.h. */ + PTR memory; +}; + +/* Initialize a hash table. */ +extern boolean bfd_hash_table_init + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Initialize a hash table specifying a size. */ +extern boolean bfd_hash_table_init_n + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int size)); + +/* Free up a hash table. */ +extern void bfd_hash_table_free PARAMS ((struct bfd_hash_table *)); + +/* Look up a string in a hash table. If CREATE is true, a new entry + will be created for this string if one does not already exist. The + COPY argument must be true if this routine should copy the string + into newly allocated memory when adding an entry. */ +extern struct bfd_hash_entry *bfd_hash_lookup + PARAMS ((struct bfd_hash_table *, const char *, boolean create, + boolean copy)); + +/* Replace an entry in a hash table. */ +extern void bfd_hash_replace + PARAMS ((struct bfd_hash_table *, struct bfd_hash_entry *old, + struct bfd_hash_entry *nw)); + +/* Base method for creating a hash table entry. */ +extern struct bfd_hash_entry *bfd_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +/* Grab some space for a hash table entry. */ +extern PTR bfd_hash_allocate PARAMS ((struct bfd_hash_table *, + unsigned int)); + +/* Traverse a hash table in a random order, calling a function on each + element. If the function returns false, the traversal stops. The + INFO argument is passed to the function. */ +extern void bfd_hash_traverse PARAMS ((struct bfd_hash_table *, + boolean (*) (struct bfd_hash_entry *, + PTR), + PTR info)); + +/* Semi-portable string concatenation in cpp. + The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors. + The problem is, "32_" is not a valid preprocessing token, and we don't + want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the + inner CAT macros to be evaluated first, producing still-valid pp-tokens. + Then the final concatenation can be done. (Sigh.) */ +#ifndef CAT +#ifdef SABER +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#else +#if defined(__STDC__) || defined(ALMOST_STDC) +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define XCAT2(a,b) CAT(a,b) +#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d)) +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#endif +#endif +#endif + +#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table + +/* User program access to BFD facilities */ + +/* Direct I/O routines, for programs which know more about the object + file than BFD does. Use higher level routines if possible. */ + +extern bfd_size_type bfd_read + PARAMS ((PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern bfd_size_type bfd_write + PARAMS ((const PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern int bfd_seek PARAMS ((bfd *abfd, file_ptr fp, int direction)); +extern long bfd_tell PARAMS ((bfd *abfd)); +extern int bfd_flush PARAMS ((bfd *abfd)); +extern int bfd_stat PARAMS ((bfd *abfd, struct stat *)); + +/* Cast from const char * to char * so that caller can assign to + a char * without a warning. */ +#define bfd_get_filename(abfd) ((char *) (abfd)->filename) +#define bfd_get_cacheable(abfd) ((abfd)->cacheable) +#define bfd_get_format(abfd) ((abfd)->format) +#define bfd_get_target(abfd) ((abfd)->xvec->name) +#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) +#define bfd_family_coff(abfd) \ + (bfd_get_flavour (abfd) == bfd_target_coff_flavour || \ + bfd_get_flavour (abfd) == bfd_target_xcoff_flavour) +#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) +#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) +#define bfd_header_big_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) +#define bfd_header_little_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) +#define bfd_get_file_flags(abfd) ((abfd)->flags) +#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) +#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) +#define bfd_my_archive(abfd) ((abfd)->my_archive) +#define bfd_has_map(abfd) ((abfd)->has_armap) + +#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) +#define bfd_usrdata(abfd) ((abfd)->usrdata) + +#define bfd_get_start_address(abfd) ((abfd)->start_address) +#define bfd_get_symcount(abfd) ((abfd)->symcount) +#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) +#define bfd_count_sections(abfd) ((abfd)->section_count) + +#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) + +#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = (boolean) (bool)), true) + +extern boolean bfd_cache_close PARAMS ((bfd *abfd)); +/* NB: This declaration should match the autogenerated one in libbfd.h. */ + +extern boolean bfd_record_phdr + PARAMS ((bfd *, unsigned long, boolean, flagword, boolean, bfd_vma, + boolean, boolean, unsigned int, struct sec **)); + +/* Byte swapping routines. */ + +bfd_vma bfd_getb64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb16 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_16 PARAMS ((const unsigned char *)); +void bfd_putb64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb16 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl16 PARAMS ((bfd_vma, unsigned char *)); + +/* Byte swapping routines which take size and endiannes as arguments. */ + +bfd_vma bfd_get_bits PARAMS ((bfd_byte *, int, boolean)); +void bfd_put_bits PARAMS ((bfd_vma, bfd_byte *, int, boolean)); + +/* Externally visible ECOFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_debug_info; +struct ecoff_debug_swap; +struct ecoff_extr; +struct symbol_cache_entry; +struct bfd_link_info; +struct bfd_link_hash_entry; +struct bfd_elf_version_tree; +#endif +extern bfd_vma bfd_ecoff_get_gp_value PARAMS ((bfd * abfd)); +extern boolean bfd_ecoff_set_gp_value PARAMS ((bfd *abfd, bfd_vma gp_value)); +extern boolean bfd_ecoff_set_regmasks + PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask, + unsigned long *cprmask)); +extern PTR bfd_ecoff_debug_init + PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern void bfd_ecoff_debug_free + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + bfd *input_bfd, struct ecoff_debug_info *input_debug, + const struct ecoff_debug_swap *input_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate_other + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, bfd *input_bfd, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_externals + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + boolean relocateable, + boolean (*get_extr) (struct symbol_cache_entry *, + struct ecoff_extr *), + void (*set_index) (struct symbol_cache_entry *, + bfd_size_type))); +extern boolean bfd_ecoff_debug_one_external + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + const char *name, struct ecoff_extr *esym)); +extern bfd_size_type bfd_ecoff_debug_size + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +extern boolean bfd_ecoff_write_debug + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, file_ptr where)); +extern boolean bfd_ecoff_write_accumulated_debug + PARAMS ((PTR handle, bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + struct bfd_link_info *info, file_ptr where)); +extern boolean bfd_mips_ecoff_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* Externally visible ELF routines. */ + +struct bfd_link_needed_list +{ + struct bfd_link_needed_list *next; + bfd *by; + const char *name; +}; + +extern boolean bfd_elf32_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern boolean bfd_elf64_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern struct bfd_link_needed_list *bfd_elf_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf_get_bfd_needed_list + PARAMS ((bfd *, struct bfd_link_needed_list **)); +extern boolean bfd_elf32_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, const char *, + const char * const *, struct bfd_link_info *, struct sec **, + struct bfd_elf_version_tree *)); +extern boolean bfd_elf64_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, const char *, + const char * const *, struct bfd_link_info *, struct sec **, + struct bfd_elf_version_tree *)); +extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *)); +extern void bfd_elf_set_dt_needed_soname PARAMS ((bfd *, const char *)); +extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *)); +extern struct bfd_link_needed_list *bfd_elf_get_runpath_list + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Return an upper bound on the number of bytes required to store a + copy of ABFD's program header table entries. Return -1 if an error + occurs; bfd_get_error will return an appropriate code. */ +extern long bfd_get_elf_phdr_upper_bound PARAMS ((bfd *abfd)); + +/* Copy ABFD's program header table entries to *PHDRS. The entries + will be stored as an array of Elf_Internal_Phdr structures, as + defined in include/elf/internal.h. To find out how large the + buffer needs to be, call bfd_get_elf_phdr_upper_bound. + + Return the number of program header table entries read, or -1 if an + error occurs; bfd_get_error will return an appropriate code. */ +extern int bfd_get_elf_phdrs PARAMS ((bfd *abfd, void *phdrs)); + +/* Return the arch_size field of an elf bfd, or -1 if not elf. */ +extern int bfd_get_arch_size PARAMS ((bfd *)); + +/* Return true if address "naturally" sign extends, or -1 if not elf. */ +extern int bfd_get_sign_extend_vma PARAMS ((bfd *)); + +extern boolean bfd_m68k_elf32_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* SunOS shared library support routines for the linker. */ + +extern struct bfd_link_needed_list *bfd_sunos_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_sunos_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_sunos_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, struct sec **, struct sec **, + struct sec **)); + +/* Linux shared library support routines for the linker. */ + +extern boolean bfd_i386linux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_m68klinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_sparclinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +/* mmap hacks */ + +struct _bfd_window_internal; +typedef struct _bfd_window_internal bfd_window_internal; + +typedef struct _bfd_window { + /* What the user asked for. */ + PTR data; + bfd_size_type size; + /* The actual window used by BFD. Small user-requested read-only + regions sharing a page may share a single window into the object + file. Read-write versions shouldn't until I've fixed things to + keep track of which portions have been claimed by the + application; don't want to give the same region back when the + application wants two writable copies! */ + struct _bfd_window_internal *i; +} bfd_window; + +extern void bfd_init_window PARAMS ((bfd_window *)); +extern void bfd_free_window PARAMS ((bfd_window *)); +extern boolean bfd_get_file_window + PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, boolean)); + +/* XCOFF support routines for the linker. */ + +extern boolean bfd_xcoff_link_record_set + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_size_type)); +extern boolean bfd_xcoff_import_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_vma, const char *, const char *, const char *)); +extern boolean bfd_xcoff_export_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + boolean)); +extern boolean bfd_xcoff_link_count_reloc + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, + unsigned long, unsigned long, unsigned long, boolean, + int, boolean, boolean, struct sec **)); + +/* Externally visible COFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct internal_syment; +union internal_auxent; +#endif + +extern boolean bfd_coff_get_syment + PARAMS ((bfd *, struct symbol_cache_entry *, struct internal_syment *)); + +extern boolean bfd_coff_get_auxent + PARAMS ((bfd *, struct symbol_cache_entry *, int, union internal_auxent *)); + +extern boolean bfd_coff_set_symbol_class + PARAMS ((bfd *, struct symbol_cache_entry *, unsigned int)); + +extern boolean bfd_m68k_coff_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* ARM Interworking support. Called from linker. */ +extern boolean bfd_arm_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern boolean bfd_arm_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern boolean bfd_arm_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +/* PE ARM Interworking support. Called from linker. */ +extern boolean bfd_arm_pe_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern boolean bfd_arm_pe_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern boolean bfd_arm_pe_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +/* ELF ARM Interworking support. Called from linker. */ +extern boolean bfd_elf32_arm_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern boolean bfd_elf32_arm_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern boolean bfd_elf32_arm_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +/* TI COFF load page support. */ +extern void bfd_ticoff_set_section_load_page + PARAMS ((struct sec *, int)); + +extern int bfd_ticoff_get_section_load_page + PARAMS ((struct sec *)); + +/* And more from the source. */ +void +bfd_init PARAMS ((void)); + +bfd * +bfd_openr PARAMS ((CONST char *filename, CONST char *target)); + +bfd * +bfd_fdopenr PARAMS ((CONST char *filename, CONST char *target, int fd)); + +bfd * +bfd_openstreamr PARAMS ((const char *, const char *, PTR)); + +bfd * +bfd_openw PARAMS ((CONST char *filename, CONST char *target)); + +boolean +bfd_close PARAMS ((bfd *abfd)); + +boolean +bfd_close_all_done PARAMS ((bfd *)); + +bfd * +bfd_create PARAMS ((CONST char *filename, bfd *templ)); + +boolean +bfd_make_writable PARAMS ((bfd *abfd)); + +boolean +bfd_make_readable PARAMS ((bfd *abfd)); + + +/* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + ((void) (*((unsigned char *) (ptr)) = (unsigned char) (val))) +#define bfd_put_signed_8 \ + bfd_put_8 +#define bfd_get_8(abfd, ptr) \ + (*(unsigned char *) (ptr)) +#define bfd_get_signed_8(abfd, ptr) \ + ((*(unsigned char *) (ptr) ^ 0x80) - 0x80) + +#define bfd_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +#define bfd_put_signed_16 \ + bfd_put_16 +#define bfd_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx16, (ptr)) +#define bfd_get_signed_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) + +#define bfd_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +#define bfd_put_signed_32 \ + bfd_put_32 +#define bfd_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx32, (ptr)) +#define bfd_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) + +#define bfd_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +#define bfd_put_signed_64 \ + bfd_put_64 +#define bfd_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx64, (ptr)) +#define bfd_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) + +#define bfd_get(bits, abfd, ptr) \ + ((bits) == 8 ? bfd_get_8 (abfd, ptr) \ + : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ + : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ + : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ + : (abort (), (bfd_vma) - 1)) + +#define bfd_put(bits, abfd, val, ptr) \ + ((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ + : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ + : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ + : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ + : (abort (), (void) 0)) + + +/* Byte swapping macros for file header data. */ + +#define bfd_h_put_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_put_signed_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_get_8(abfd, ptr) \ + bfd_get_8 (abfd, ptr) +#define bfd_h_get_signed_8(abfd, ptr) \ + bfd_get_signed_8 (abfd, ptr) + +#define bfd_h_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +#define bfd_h_put_signed_16 \ + bfd_h_put_16 +#define bfd_h_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx16,(ptr)) +#define bfd_h_get_signed_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) + +#define bfd_h_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +#define bfd_h_put_signed_32 \ + bfd_h_put_32 +#define bfd_h_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx32,(ptr)) +#define bfd_h_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) + +#define bfd_h_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +#define bfd_h_put_signed_64 \ + bfd_h_put_64 +#define bfd_h_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx64,(ptr)) +#define bfd_h_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) + +/* This structure is used for a comdat section, as in PE. A comdat + section is associated with a particular symbol. When the linker + sees a comdat section, it keeps only one of the sections with a + given name and associated with a given symbol. */ + +struct bfd_comdat_info +{ + /* The name of the symbol associated with a comdat section. */ + const char *name; + + /* The local symbol table index of the symbol associated with a + comdat section. This is only meaningful to the object file format + specific code; it is not an index into the list returned by + bfd_canonicalize_symtab. */ + long symbol; +}; + +typedef struct sec +{ + /* The name of the section; the name isn't a copy, the pointer is + the same as that passed to bfd_make_section. */ + + const char *name; + + /* A unique sequence number. */ + + int id; + + /* Which section is it; 0..nth. */ + + int index; + + /* The next section in the list belonging to the BFD, or NULL. */ + + struct sec *next; + + /* The field flags contains attributes of the section. Some + flags are read in from the object file, and some are + synthesized from other information. */ + + flagword flags; + +#define SEC_NO_FLAGS 0x000 + + /* Tells the OS to allocate space for this section when loading. + This is clear for a section containing debug information only. */ +#define SEC_ALLOC 0x001 + + /* Tells the OS to load the section from the file when loading. + This is clear for a .bss section. */ +#define SEC_LOAD 0x002 + + /* The section contains data still to be relocated, so there is + some relocation information too. */ +#define SEC_RELOC 0x004 + +#if 0 /* Obsolete ? */ +#define SEC_BALIGN 0x008 +#endif + + /* A signal to the OS that the section contains read only data. */ +#define SEC_READONLY 0x010 + + /* The section contains code only. */ +#define SEC_CODE 0x020 + + /* The section contains data only. */ +#define SEC_DATA 0x040 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x080 + + /* The section contains constructor information. This section + type is used by the linker to create lists of constructors and + destructors used by <>. When a back end sees a symbol + which should be used in a constructor list, it creates a new + section for the type of name (e.g., <<__CTOR_LIST__>>), attaches + the symbol to it, and builds a relocation. To build the lists + of constructors, all the linker has to do is catenate all the + sections called <<__CTOR_LIST__>> and relocate the data + contained within - exactly the operations it would peform on + standard data. */ +#define SEC_CONSTRUCTOR 0x100 + + /* The section is a constructor, and should be placed at the + end of the text, data, or bss section(?). */ +#define SEC_CONSTRUCTOR_TEXT 0x1100 +#define SEC_CONSTRUCTOR_DATA 0x2100 +#define SEC_CONSTRUCTOR_BSS 0x3100 + + /* The section has contents - a data section could be + <> | <>; a debug section could be + <> */ +#define SEC_HAS_CONTENTS 0x200 + + /* An instruction to the linker to not output the section + even if it has information which would normally be written. */ +#define SEC_NEVER_LOAD 0x400 + + /* The section is a COFF shared library section. This flag is + only for the linker. If this type of section appears in + the input file, the linker must copy it to the output file + without changing the vma or size. FIXME: Although this + was originally intended to be general, it really is COFF + specific (and the flag was renamed to indicate this). It + might be cleaner to have some more general mechanism to + allow the back end to control what the linker does with + sections. */ +#define SEC_COFF_SHARED_LIBRARY 0x800 + + /* The section has GOT references. This flag is only for the + linker, and is currently only used by the elf32-hppa back end. + It will be set if global offset table references were detected + in this section, which indicate to the linker that the section + contains PIC code, and must be handled specially when doing a + static link. */ +#define SEC_HAS_GOT_REF 0x4000 + + /* The section contains common symbols (symbols may be defined + multiple times, the value of a symbol is the amount of + space it requires, and the largest symbol value is the one + used). Most targets have exactly one of these (which we + translate to bfd_com_section_ptr), but ECOFF has two. */ +#define SEC_IS_COMMON 0x8000 + + /* The section contains only debugging information. For + example, this is set for ELF .debug and .stab sections. + strip tests this flag to see if a section can be + discarded. */ +#define SEC_DEBUGGING 0x10000 + + /* The contents of this section are held in memory pointed to + by the contents field. This is checked by bfd_get_section_contents, + and the data is retrieved from memory if appropriate. */ +#define SEC_IN_MEMORY 0x20000 + + /* The contents of this section are to be excluded by the + linker for executable and shared objects unless those + objects are to be further relocated. */ +#define SEC_EXCLUDE 0x40000 + + /* The contents of this section are to be sorted by the + based on the address specified in the associated symbol + table. */ +#define SEC_SORT_ENTRIES 0x80000 + + /* When linking, duplicate sections of the same name should be + discarded, rather than being combined into a single section as + is usually done. This is similar to how common symbols are + handled. See SEC_LINK_DUPLICATES below. */ +#define SEC_LINK_ONCE 0x100000 + + /* If SEC_LINK_ONCE is set, this bitfield describes how the linker + should handle duplicate sections. */ +#define SEC_LINK_DUPLICATES 0x600000 + + /* This value for SEC_LINK_DUPLICATES means that duplicate + sections with the same name should simply be discarded. */ +#define SEC_LINK_DUPLICATES_DISCARD 0x0 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if there are any duplicate sections, although + it should still only link one copy. */ +#define SEC_LINK_DUPLICATES_ONE_ONLY 0x200000 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if any duplicate sections are a different size. */ +#define SEC_LINK_DUPLICATES_SAME_SIZE 0x400000 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if any duplicate sections contain different + contents. */ +#define SEC_LINK_DUPLICATES_SAME_CONTENTS 0x600000 + + /* This section was created by the linker as part of dynamic + relocation or other arcane processing. It is skipped when + going through the first-pass output, trusting that someone + else up the line will take care of it later. */ +#define SEC_LINKER_CREATED 0x800000 + + /* This section should not be subject to garbage collection. */ +#define SEC_KEEP 0x1000000 + + /* This section contains "short" data, and should be placed + "near" the GP. */ +#define SEC_SMALL_DATA 0x2000000 + + /* This section contains data which may be shared with other + executables or shared objects. */ +#define SEC_SHARED 0x4000000 + + /* When a section with this flag is being linked, then if the size of + the input section is less than a page, it should not cross a page + boundary. If the size of the input section is one page or more, it + should be aligned on a page boundary. */ +#define SEC_BLOCK 0x8000000 + + /* Conditionally link this section; do not link if there are no + references found to any symbol in the section. */ +#define SEC_CLINK 0x10000000 + + /* Attempt to merge identical entities in the section. + Entity size is given in the entsize field. */ +#define SEC_MERGE 0x20000000 + + /* If given with SEC_MERGE, entities to merge are zero terminated + strings where entsize specifies character size instead of fixed + size entries. */ +#define SEC_STRINGS 0x40000000 + + /* End of section flags. */ + + /* Some internal packed boolean fields. */ + + /* See the vma field. */ + unsigned int user_set_vma : 1; + + /* Whether relocations have been processed. */ + unsigned int reloc_done : 1; + + /* A mark flag used by some of the linker backends. */ + unsigned int linker_mark : 1; + + /* A mark flag used by some linker backends for garbage collection. */ + unsigned int gc_mark : 1; + + /* Used by the ELF code to mark sections which have been allocated to segments. */ + unsigned int segment_mark : 1; + + /* End of internal packed boolean fields. */ + + /* The virtual memory address of the section - where it will be + at run time. The symbols are relocated against this. The + user_set_vma flag is maintained by bfd; if it's not set, the + backend can assign addresses (for example, in <>, where + the default address for <<.data>> is dependent on the specific + target and various flags). */ + + bfd_vma vma; + + /* The load address of the section - where it would be in a + rom image; really only used for writing section header + information. */ + + bfd_vma lma; + + /* The size of the section in octets, as it will be output. + Contains a value even if the section has no contents (e.g., the + size of <<.bss>>). This will be filled in after relocation. */ + + bfd_size_type _cooked_size; + + /* The original size on disk of the section, in octets. Normally this + value is the same as the size, but if some relaxing has + been done, then this value will be bigger. */ + + bfd_size_type _raw_size; + + /* If this section is going to be output, then this value is the + offset in *bytes* into the output section of the first byte in the + input section (byte ==> smallest addressable unit on the + target). In most cases, if this was going to start at the + 100th octet (8-bit quantity) in the output section, this value + would be 100. However, if the target byte size is 16 bits + (bfd_octets_per_byte is "2"), this value would be 50. */ + + bfd_vma output_offset; + + /* The output section through which to map on output. */ + + struct sec *output_section; + + /* The alignment requirement of the section, as an exponent of 2 - + e.g., 3 aligns to 2^3 (or 8). */ + + unsigned int alignment_power; + + /* If an input section, a pointer to a vector of relocation + records for the data in this section. */ + + struct reloc_cache_entry *relocation; + + /* If an output section, a pointer to a vector of pointers to + relocation records for the data in this section. */ + + struct reloc_cache_entry **orelocation; + + /* The number of relocation records in one of the above */ + + unsigned reloc_count; + + /* Information below is back end specific - and not always used + or updated. */ + + /* File position of section data. */ + + file_ptr filepos; + + /* File position of relocation info. */ + + file_ptr rel_filepos; + + /* File position of line data. */ + + file_ptr line_filepos; + + /* Pointer to data for applications. */ + + PTR userdata; + + /* If the SEC_IN_MEMORY flag is set, this points to the actual + contents. */ + unsigned char *contents; + + /* Attached line number information. */ + + alent *lineno; + + /* Number of line number records. */ + + unsigned int lineno_count; + + /* Entity size for merging purposes. */ + + unsigned int entsize; + + /* Optional information about a COMDAT entry; NULL if not COMDAT. */ + + struct bfd_comdat_info *comdat; + + /* Points to the kept section if this section is a link-once section, + and is discarded. */ + struct sec *kept_section; + + /* When a section is being output, this value changes as more + linenumbers are written out. */ + + file_ptr moving_line_filepos; + + /* What the section number is in the target world. */ + + int target_index; + + PTR used_by_bfd; + + /* If this is a constructor section then here is a list of the + relocations created to relocate items within it. */ + + struct relent_chain *constructor_chain; + + /* The BFD which owns the section. */ + + bfd *owner; + + /* A symbol which points at this section only */ + struct symbol_cache_entry *symbol; + struct symbol_cache_entry **symbol_ptr_ptr; + + struct bfd_link_order *link_order_head; + struct bfd_link_order *link_order_tail; +} asection ; + +/* These sections are global, and are managed by BFD. The application + and target back end are not permitted to change the values in + these sections. New code should use the section_ptr macros rather + than referring directly to the const sections. The const sections + may eventually vanish. */ +#define BFD_ABS_SECTION_NAME "*ABS*" +#define BFD_UND_SECTION_NAME "*UND*" +#define BFD_COM_SECTION_NAME "*COM*" +#define BFD_IND_SECTION_NAME "*IND*" + +/* the absolute section */ +extern const asection bfd_abs_section; +#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) +#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) +/* Pointer to the undefined section */ +extern const asection bfd_und_section; +#define bfd_und_section_ptr ((asection *) &bfd_und_section) +#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) +/* Pointer to the common section */ +extern const asection bfd_com_section; +#define bfd_com_section_ptr ((asection *) &bfd_com_section) +/* Pointer to the indirect section */ +extern const asection bfd_ind_section; +#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) + +extern const struct symbol_cache_entry * const bfd_abs_symbol; +extern const struct symbol_cache_entry * const bfd_com_symbol; +extern const struct symbol_cache_entry * const bfd_und_symbol; +extern const struct symbol_cache_entry * const bfd_ind_symbol; +#define bfd_get_section_size_before_reloc(section) \ + ((section)->reloc_done ? (abort (), (bfd_size_type) 1) \ + : (section)->_raw_size) +#define bfd_get_section_size_after_reloc(section) \ + ((section)->reloc_done ? (section)->_cooked_size \ + : (abort (), (bfd_size_type) 1)) +asection * +bfd_get_section_by_name PARAMS ((bfd *abfd, const char *name)); + +char * +bfd_get_unique_section_name PARAMS ((bfd *abfd, + const char *templat, + int *count)); + +asection * +bfd_make_section_old_way PARAMS ((bfd *abfd, const char *name)); + +asection * +bfd_make_section_anyway PARAMS ((bfd *abfd, const char *name)); + +asection * +bfd_make_section PARAMS ((bfd *, const char *name)); + +boolean +bfd_set_section_flags PARAMS ((bfd *abfd, asection *sec, flagword flags)); + +void +bfd_map_over_sections PARAMS ((bfd *abfd, + void (*func) (bfd *abfd, + asection *sect, + PTR obj), + PTR obj)); + +boolean +bfd_set_section_size PARAMS ((bfd *abfd, asection *sec, bfd_size_type val)); + +boolean +bfd_set_section_contents PARAMS ((bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count)); + +boolean +bfd_get_section_contents PARAMS ((bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count)); + +boolean +bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec, bfd *obfd, asection *osec)); + +#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ + BFD_SEND (obfd, _bfd_copy_private_section_data, \ + (ibfd, isection, obfd, osection)) +void +_bfd_strip_section_from_output PARAMS ((struct bfd_link_info *info, asection *section)); + +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ +#define bfd_mach_m68000 1 +#define bfd_mach_m68008 2 +#define bfd_mach_m68010 3 +#define bfd_mach_m68020 4 +#define bfd_mach_m68030 5 +#define bfd_mach_m68040 6 +#define bfd_mach_m68060 7 +#define bfd_mach_cpu32 8 +#define bfd_mach_mcf5200 9 +#define bfd_mach_mcf5206e 10 +#define bfd_mach_mcf5307 11 +#define bfd_mach_mcf5407 12 + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 +#define bfd_mach_i960_jx 7 +#define bfd_mach_i960_hx 8 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ +#define bfd_mach_sparc 1 +/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +#define bfd_mach_sparc_sparclet 2 +#define bfd_mach_sparc_sparclite 3 +#define bfd_mach_sparc_v8plus 4 +#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */ +#define bfd_mach_sparc_sparclite_le 6 +#define bfd_mach_sparc_v9 7 +#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns */ +#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns */ +#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns */ +/* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v9_p(mach) \ + ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ + && (mach) != bfd_mach_sparc_sparclite_le) + bfd_arch_mips, /* MIPS Rxxxx */ +#define bfd_mach_mips3000 3000 +#define bfd_mach_mips3900 3900 +#define bfd_mach_mips4000 4000 +#define bfd_mach_mips4010 4010 +#define bfd_mach_mips4100 4100 +#define bfd_mach_mips4111 4111 +#define bfd_mach_mips4300 4300 +#define bfd_mach_mips4400 4400 +#define bfd_mach_mips4600 4600 +#define bfd_mach_mips4650 4650 +#define bfd_mach_mips5000 5000 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips16 16 +#define bfd_mach_mips32 32 +#define bfd_mach_mips32_4k 3204113 /* 32, 04, octal 'K' */ +#define bfd_mach_mips5 5 +#define bfd_mach_mips64 64 +#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ + bfd_arch_i386, /* Intel 386 */ +#define bfd_mach_i386_i386 0 +#define bfd_mach_i386_i8086 1 +#define bfd_mach_i386_i386_intel_syntax 2 +#define bfd_mach_x86_64 3 +#define bfd_mach_x86_64_intel_syntax 4 + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_i370, /* IBM 360/370 Mainframes */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Hitachi H8/300 */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 +#define bfd_mach_h8300s 3 + bfd_arch_pdp11, /* DEC PDP-11 */ + bfd_arch_powerpc, /* PowerPC */ +#define bfd_mach_ppc 0 +#define bfd_mach_ppc_403 403 +#define bfd_mach_ppc_403gc 4030 +#define bfd_mach_ppc_505 505 +#define bfd_mach_ppc_601 601 +#define bfd_mach_ppc_602 602 +#define bfd_mach_ppc_603 603 +#define bfd_mach_ppc_ec603e 6031 +#define bfd_mach_ppc_604 604 +#define bfd_mach_ppc_620 620 +#define bfd_mach_ppc_630 630 +#define bfd_mach_ppc_750 750 +#define bfd_mach_ppc_860 860 +#define bfd_mach_ppc_a35 35 +#define bfd_mach_ppc_rs64ii 642 +#define bfd_mach_ppc_rs64iii 643 +#define bfd_mach_ppc_7400 7400 + bfd_arch_rs6000, /* IBM RS/6000 */ +#define bfd_mach_rs6k 0 +#define bfd_mach_rs6k_rs1 6001 +#define bfd_mach_rs6k_rsc 6003 +#define bfd_mach_rs6k_rs2 6002 + bfd_arch_hppa, /* HP PA RISC */ + bfd_arch_d10v, /* Mitsubishi D10V */ +#define bfd_mach_d10v 0 +#define bfd_mach_d10v_ts2 2 +#define bfd_mach_d10v_ts3 3 + bfd_arch_d30v, /* Mitsubishi D30V */ + bfd_arch_m68hc11, /* Motorola 68HC11 */ + bfd_arch_m68hc12, /* Motorola 68HC12 */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ +#define bfd_mach_sh 0 +#define bfd_mach_sh2 0x20 +#define bfd_mach_sh_dsp 0x2d +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3_dsp 0x3d +#define bfd_mach_sh3e 0x3e +#define bfd_mach_sh4 0x40 + bfd_arch_alpha, /* Dec Alpha */ +#define bfd_mach_alpha_ev4 0x10 +#define bfd_mach_alpha_ev5 0x20 +#define bfd_mach_alpha_ev6 0x30 + bfd_arch_arm, /* Advanced Risc Machines ARM */ +#define bfd_mach_arm_2 1 +#define bfd_mach_arm_2a 2 +#define bfd_mach_arm_3 3 +#define bfd_mach_arm_3M 4 +#define bfd_mach_arm_4 5 +#define bfd_mach_arm_4T 6 +#define bfd_mach_arm_5 7 +#define bfd_mach_arm_5T 8 +#define bfd_mach_arm_5TE 9 +#define bfd_mach_arm_XScale 10 + bfd_arch_ns32k, /* National Semiconductors ns32000 */ + bfd_arch_w65, /* WDC 65816 */ + bfd_arch_tic30, /* Texas Instruments TMS320C30 */ + bfd_arch_tic54x, /* Texas Instruments TMS320C54X */ + bfd_arch_tic80, /* TI TMS320c80 (MVP) */ + bfd_arch_v850, /* NEC V850 */ +#define bfd_mach_v850 0 +#define bfd_mach_v850e 'E' +#define bfd_mach_v850ea 'A' + bfd_arch_arc, /* ARC Cores */ +#define bfd_mach_arc_5 0 +#define bfd_mach_arc_6 1 +#define bfd_mach_arc_7 2 +#define bfd_mach_arc_8 3 + bfd_arch_m32r, /* Mitsubishi M32R/D */ +#define bfd_mach_m32r 0 /* backwards compatibility */ +#define bfd_mach_m32rx 'x' + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ +#define bfd_mach_mn10300 300 +#define bfd_mach_am33 330 + bfd_arch_fr30, +#define bfd_mach_fr30 0x46523330 + bfd_arch_mcore, + bfd_arch_ia64, /* HP/Intel ia64 */ +#define bfd_mach_ia64_elf64 0 +#define bfd_mach_ia64_elf32 1 + bfd_arch_pj, + bfd_arch_avr, /* Atmel AVR microcontrollers */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 + bfd_arch_cris, /* Axis CRIS */ + bfd_arch_s390, /* IBM s390 */ +#define bfd_mach_s390_esa 0 +#define bfd_mach_s390_esame 1 + bfd_arch_openrisc, /* OpenRISC */ + bfd_arch_last + }; + +typedef struct bfd_arch_info +{ + int bits_per_word; + int bits_per_address; + int bits_per_byte; + enum bfd_architecture arch; + unsigned long mach; + const char *arch_name; + const char *printable_name; + unsigned int section_align_power; + /* True if this is the default machine for the architecture. */ + boolean the_default; + const struct bfd_arch_info * (*compatible) + PARAMS ((const struct bfd_arch_info *a, + const struct bfd_arch_info *b)); + + boolean (*scan) PARAMS ((const struct bfd_arch_info *, const char *)); + + const struct bfd_arch_info *next; +} bfd_arch_info_type; +const char * +bfd_printable_name PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_scan_arch PARAMS ((const char *string)); + +const char ** +bfd_arch_list PARAMS ((void)); + +const bfd_arch_info_type * +bfd_arch_get_compatible PARAMS (( + const bfd *abfd, + const bfd *bbfd)); + +void +bfd_set_arch_info PARAMS ((bfd *abfd, const bfd_arch_info_type *arg)); + +enum bfd_architecture +bfd_get_arch PARAMS ((bfd *abfd)); + +unsigned long +bfd_get_mach PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_address PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_get_arch_info PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_lookup_arch PARAMS ((enum bfd_architecture + arch, + unsigned long machine)); + +const char * +bfd_printable_arch_mach PARAMS ((enum bfd_architecture arch, unsigned long machine)); + +unsigned int +bfd_octets_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_mach_octets_per_byte PARAMS ((enum bfd_architecture arch, + unsigned long machine)); + +typedef enum bfd_reloc_status +{ + /* No errors detected */ + bfd_reloc_ok, + + /* The relocation was performed, but there was an overflow. */ + bfd_reloc_overflow, + + /* The address to relocate was not within the section supplied. */ + bfd_reloc_outofrange, + + /* Used by special functions */ + bfd_reloc_continue, + + /* Unsupported relocation size requested. */ + bfd_reloc_notsupported, + + /* Unused */ + bfd_reloc_other, + + /* The symbol to relocate against was undefined. */ + bfd_reloc_undefined, + + /* The relocation was performed, but may not be ok - presently + generated only when linking i960 coff files with i960 b.out + symbols. If this type is returned, the error_message argument + to bfd_perform_relocation will be set. */ + bfd_reloc_dangerous + } + bfd_reloc_status_type; + + +typedef struct reloc_cache_entry +{ + /* A pointer into the canonical table of pointers */ + struct symbol_cache_entry **sym_ptr_ptr; + + /* offset in section */ + bfd_size_type address; + + /* addend for relocation value */ + bfd_vma addend; + + /* Pointer to how to perform the required relocation */ + reloc_howto_type *howto; + +} arelent; +enum complain_overflow +{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the bitfield overflows, whether it is considered + as signed or unsigned. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +}; + +struct reloc_howto_struct +{ + /* The type field has mainly a documentary use - the back end can + do what it wants with it, though normally the back end's + external idea of what a reloc number is stored + in this field. For example, a PC relative word relocation + in a coff environment has the type 023 - because that's + what the outside world calls a R_PCRWORD reloc. */ + unsigned int type; + + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift; + + /* The size of the item to be relocated. This is *not* a + power-of-two measure. To get the number of bytes operated + on by a type of relocation, use bfd_get_reloc_size. */ + int size; + + /* The number of bits in the item to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize; + + /* Notes that the relocation is relative to the location in the + data section of the addend. The relocation function will + subtract from the relocation value the address of the location + being relocated. */ + boolean pc_relative; + + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos; + + /* What type of overflow error should be checked for when + relocating. */ + enum complain_overflow complain_on_overflow; + + /* If this field is non null, then the supplied function is + called rather than the normal function. This allows really + strange relocation methods to be accomodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + PARAMS ((bfd *abfd, + arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + + /* The textual name of the relocation type. */ + char *name; + + /* Some formats record a relocation addend in the section contents + rather than with the relocation. For ELF formats this is the + distinction between USE_REL and USE_RELA (though the code checks + for USE_REL == 1/0). The value of this field is TRUE if the + addend is recorded with the section contents; when performing a + partial link (ld -r) the section contents (the data) will be + modified. The value of this field is FALSE if addends are + recorded with the relocation (in arelent.addend); when performing + a partial link the relocation will be modified. + All relocations for all ELF USE_RELA targets should set this field + to FALSE (values of TRUE should be looked on with suspicion). + However, the converse is not true: not all relocations of all ELF + USE_REL targets set this field to TRUE. Why this is so is peculiar + to each particular target. For relocs that aren't used in partial + links (e.g. GOT stuff) it doesn't matter what this is set to. */ + boolean partial_inplace; + + /* The src_mask selects which parts of the read in data + are to be used in the relocation sum. E.g., if this was an 8 bit + byte of data which we read and relocated, this would be + 0x000000ff. When we have relocs which have an addend, such as + sun4 extended relocs, the value in the offset part of a + relocating field is garbage so we never use it. In this case + the mask would be 0x00000000. */ + bfd_vma src_mask; + + /* The dst_mask selects which parts of the instruction are replaced + into the instruction. In most cases src_mask == dst_mask, + except in the above special case, where dst_mask would be + 0x000000ff, and src_mask would be 0x00000000. */ + bfd_vma dst_mask; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., m88k bcs); this flag signals the fact.*/ + boolean pcrel_offset; + +}; +#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ + {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} +#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) + +#define EMPTY_HOWTO(C) \ + HOWTO((C),0,0,0,false,0,complain_overflow_dont,NULL,NULL,false,0,0,false) + +#define HOWTO_PREPARE(relocation, symbol) \ + { \ + if (symbol != (asymbol *)NULL) { \ + if (bfd_is_com_section (symbol->section)) { \ + relocation = 0; \ + } \ + else { \ + relocation = symbol->value; \ + } \ + } \ +} +unsigned int +bfd_get_reloc_size PARAMS ((reloc_howto_type *)); + +typedef struct relent_chain { + arelent relent; + struct relent_chain *next; +} arelent_chain; +bfd_reloc_status_type +bfd_check_overflow PARAMS ((enum complain_overflow how, + unsigned int bitsize, + unsigned int rightshift, + unsigned int addrsize, + bfd_vma relocation)); + +bfd_reloc_status_type +bfd_perform_relocation PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + +bfd_reloc_status_type +bfd_install_relocation PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, bfd_vma data_start, + asection *input_section, + char **error_message)); + +enum bfd_reloc_code_real { + _dummy_first_bfd_reloc_code_real, + + +/* Basic absolute relocations of N bits. */ + BFD_RELOC_64, + BFD_RELOC_32, + BFD_RELOC_26, + BFD_RELOC_24, + BFD_RELOC_16, + BFD_RELOC_14, + BFD_RELOC_8, + +/* PC-relative relocations. Sometimes these are relative to the address +of the relocation itself; sometimes they are relative to the start of +the section containing the relocation. It depends on the specific target. + +The 24-bit relocation is used in some Intel 960 configurations. */ + BFD_RELOC_64_PCREL, + BFD_RELOC_32_PCREL, + BFD_RELOC_24_PCREL, + BFD_RELOC_16_PCREL, + BFD_RELOC_12_PCREL, + BFD_RELOC_8_PCREL, + +/* For ELF. */ + BFD_RELOC_32_GOT_PCREL, + BFD_RELOC_16_GOT_PCREL, + BFD_RELOC_8_GOT_PCREL, + BFD_RELOC_32_GOTOFF, + BFD_RELOC_16_GOTOFF, + BFD_RELOC_LO16_GOTOFF, + BFD_RELOC_HI16_GOTOFF, + BFD_RELOC_HI16_S_GOTOFF, + BFD_RELOC_8_GOTOFF, + BFD_RELOC_32_PLT_PCREL, + BFD_RELOC_24_PLT_PCREL, + BFD_RELOC_16_PLT_PCREL, + BFD_RELOC_8_PLT_PCREL, + BFD_RELOC_32_PLTOFF, + BFD_RELOC_16_PLTOFF, + BFD_RELOC_LO16_PLTOFF, + BFD_RELOC_HI16_PLTOFF, + BFD_RELOC_HI16_S_PLTOFF, + BFD_RELOC_8_PLTOFF, + +/* Relocations used by 68K ELF. */ + BFD_RELOC_68K_GLOB_DAT, + BFD_RELOC_68K_JMP_SLOT, + BFD_RELOC_68K_RELATIVE, + +/* Linkage-table relative. */ + BFD_RELOC_32_BASEREL, + BFD_RELOC_16_BASEREL, + BFD_RELOC_LO16_BASEREL, + BFD_RELOC_HI16_BASEREL, + BFD_RELOC_HI16_S_BASEREL, + BFD_RELOC_8_BASEREL, + BFD_RELOC_RVA, + +/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ + BFD_RELOC_8_FFnn, + +/* These PC-relative relocations are stored as word displacements -- +i.e., byte displacements shifted right two bits. The 30-bit word +displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the +SPARC. (SPARC tools generally refer to this as <>.) The +signed 16-bit displacement is used on the MIPS, and the 23-bit +displacement is used on the Alpha. */ + BFD_RELOC_32_PCREL_S2, + BFD_RELOC_16_PCREL_S2, + BFD_RELOC_23_PCREL_S2, + +/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of +the target word. These are used on the SPARC. */ + BFD_RELOC_HI22, + BFD_RELOC_LO10, + +/* For systems that allocate a Global Pointer register, these are +displacements off that register. These relocation types are +handled specially, because the value the register will have is +decided relatively late. */ + BFD_RELOC_GPREL16, + BFD_RELOC_GPREL32, + +/* Reloc types used for i960/b.out. */ + BFD_RELOC_I960_CALLJ, + +/* SPARC ELF relocations. There is probably some overlap with other +relocation types already defined. */ + BFD_RELOC_NONE, + BFD_RELOC_SPARC_WDISP22, + BFD_RELOC_SPARC22, + BFD_RELOC_SPARC13, + BFD_RELOC_SPARC_GOT10, + BFD_RELOC_SPARC_GOT13, + BFD_RELOC_SPARC_GOT22, + BFD_RELOC_SPARC_PC10, + BFD_RELOC_SPARC_PC22, + BFD_RELOC_SPARC_WPLT30, + BFD_RELOC_SPARC_COPY, + BFD_RELOC_SPARC_GLOB_DAT, + BFD_RELOC_SPARC_JMP_SLOT, + BFD_RELOC_SPARC_RELATIVE, + BFD_RELOC_SPARC_UA32, + +/* I think these are specific to SPARC a.out (e.g., Sun 4). */ + BFD_RELOC_SPARC_BASE13, + BFD_RELOC_SPARC_BASE22, + +/* SPARC64 relocations */ +#define BFD_RELOC_SPARC_64 BFD_RELOC_64 + BFD_RELOC_SPARC_10, + BFD_RELOC_SPARC_11, + BFD_RELOC_SPARC_OLO10, + BFD_RELOC_SPARC_HH22, + BFD_RELOC_SPARC_HM10, + BFD_RELOC_SPARC_LM22, + BFD_RELOC_SPARC_PC_HH22, + BFD_RELOC_SPARC_PC_HM10, + BFD_RELOC_SPARC_PC_LM22, + BFD_RELOC_SPARC_WDISP16, + BFD_RELOC_SPARC_WDISP19, + BFD_RELOC_SPARC_7, + BFD_RELOC_SPARC_6, + BFD_RELOC_SPARC_5, +#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL + BFD_RELOC_SPARC_PLT64, + BFD_RELOC_SPARC_HIX22, + BFD_RELOC_SPARC_LOX10, + BFD_RELOC_SPARC_H44, + BFD_RELOC_SPARC_M44, + BFD_RELOC_SPARC_L44, + BFD_RELOC_SPARC_REGISTER, + +/* SPARC little endian relocation */ + BFD_RELOC_SPARC_REV32, + +/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or +"addend" in some special way. +For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when +writing; when reading, it will be the absolute section symbol. The +addend is the displacement in bytes of the "lda" instruction from +the "ldah" instruction (which is at the address of this reloc). */ + BFD_RELOC_ALPHA_GPDISP_HI16, + +/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as +with GPDISP_HI16 relocs. The addend is ignored when writing the +relocations out, and is filled in with the file's GP value on +reading, for convenience. */ + BFD_RELOC_ALPHA_GPDISP_LO16, + +/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 +relocation except that there is no accompanying GPDISP_LO16 +relocation. */ + BFD_RELOC_ALPHA_GPDISP, + +/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; +the assembler turns it into a LDQ instruction to load the address of +the symbol, and then fills in a register in the real instruction. + +The LITERAL reloc, at the LDQ instruction, refers to the .lita +section symbol. The addend is ignored when writing, but is filled +in with the file's GP value on reading, for convenience, as with the +GPDISP_LO16 reloc. + +The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. +It should refer to the symbol to be referenced, as with 16_GOTOFF, +but it generates output not based on the position within the .got +section, but relative to the GP value chosen for the file during the +final link stage. + +The LITUSE reloc, on the instruction using the loaded address, gives +information to the linker that it might be able to use to optimize +away some literal section references. The symbol is ignored (read +as the absolute section symbol), and the "addend" indicates the type +of instruction using the register: +1 - "memory" fmt insn +2 - byte-manipulation (byte offset reg) +3 - jsr (target of branch) + +The GNU linker currently doesn't do any of this optimizing. */ + BFD_RELOC_ALPHA_LITERAL, + BFD_RELOC_ALPHA_ELF_LITERAL, + BFD_RELOC_ALPHA_LITUSE, + +/* The BFD_RELOC_ALPHA_USER_* relocations are used by the assembler to +process the explicit !!sequence relocations, and are mapped +into the normal relocations at the end of processing. */ + BFD_RELOC_ALPHA_USER_LITERAL, + BFD_RELOC_ALPHA_USER_LITUSE_BASE, + BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF, + BFD_RELOC_ALPHA_USER_LITUSE_JSR, + BFD_RELOC_ALPHA_USER_GPDISP, + BFD_RELOC_ALPHA_USER_GPRELHIGH, + BFD_RELOC_ALPHA_USER_GPRELLOW, + +/* The HINT relocation indicates a value that should be filled into the +"hint" field of a jmp/jsr/ret instruction, for possible branch- +prediction logic which may be provided on some processors. */ + BFD_RELOC_ALPHA_HINT, + +/* The LINKAGE relocation outputs a linkage pair in the object file, +which is filled by the linker. */ + BFD_RELOC_ALPHA_LINKAGE, + +/* The CODEADDR relocation outputs a STO_CA in the object file, +which is filled by the linker. */ + BFD_RELOC_ALPHA_CODEADDR, + +/* Bits 27..2 of the relocation address shifted right 2 bits; +simple reloc otherwise. */ + BFD_RELOC_MIPS_JMP, + +/* The MIPS16 jump instruction. */ + BFD_RELOC_MIPS16_JMP, + +/* MIPS16 GP relative reloc. */ + BFD_RELOC_MIPS16_GPREL, + +/* High 16 bits of 32-bit value; simple reloc. */ + BFD_RELOC_HI16, + +/* High 16 bits of 32-bit value but the low 16 bits will be sign +extended and added to form the final result. If the low 16 +bits form a negative number, we need to add one to the high value +to compensate for the borrow when the low bits are added. */ + BFD_RELOC_HI16_S, + +/* Low 16 bits. */ + BFD_RELOC_LO16, + +/* Like BFD_RELOC_HI16_S, but PC relative. */ + BFD_RELOC_PCREL_HI16_S, + +/* Like BFD_RELOC_LO16, but PC relative. */ + BFD_RELOC_PCREL_LO16, + +/* Relocation relative to the global pointer. */ +#define BFD_RELOC_MIPS_GPREL BFD_RELOC_GPREL16 + +/* Relocation against a MIPS literal section. */ + BFD_RELOC_MIPS_LITERAL, + +/* MIPS ELF relocations. */ + BFD_RELOC_MIPS_GOT16, + BFD_RELOC_MIPS_CALL16, +#define BFD_RELOC_MIPS_GPREL32 BFD_RELOC_GPREL32 + BFD_RELOC_MIPS_GOT_HI16, + BFD_RELOC_MIPS_GOT_LO16, + BFD_RELOC_MIPS_CALL_HI16, + BFD_RELOC_MIPS_CALL_LO16, + BFD_RELOC_MIPS_SUB, + BFD_RELOC_MIPS_GOT_PAGE, + BFD_RELOC_MIPS_GOT_OFST, + BFD_RELOC_MIPS_GOT_DISP, + + +/* i386/elf relocations */ + BFD_RELOC_386_GOT32, + BFD_RELOC_386_PLT32, + BFD_RELOC_386_COPY, + BFD_RELOC_386_GLOB_DAT, + BFD_RELOC_386_JUMP_SLOT, + BFD_RELOC_386_RELATIVE, + BFD_RELOC_386_GOTOFF, + BFD_RELOC_386_GOTPC, + +/* x86-64/elf relocations */ + BFD_RELOC_X86_64_GOT32, + BFD_RELOC_X86_64_PLT32, + BFD_RELOC_X86_64_COPY, + BFD_RELOC_X86_64_GLOB_DAT, + BFD_RELOC_X86_64_JUMP_SLOT, + BFD_RELOC_X86_64_RELATIVE, + BFD_RELOC_X86_64_GOTPCREL, + BFD_RELOC_X86_64_32S, + +/* ns32k relocations */ + BFD_RELOC_NS32K_IMM_8, + BFD_RELOC_NS32K_IMM_16, + BFD_RELOC_NS32K_IMM_32, + BFD_RELOC_NS32K_IMM_8_PCREL, + BFD_RELOC_NS32K_IMM_16_PCREL, + BFD_RELOC_NS32K_IMM_32_PCREL, + BFD_RELOC_NS32K_DISP_8, + BFD_RELOC_NS32K_DISP_16, + BFD_RELOC_NS32K_DISP_32, + BFD_RELOC_NS32K_DISP_8_PCREL, + BFD_RELOC_NS32K_DISP_16_PCREL, + BFD_RELOC_NS32K_DISP_32_PCREL, + +/* PDP11 relocations */ + BFD_RELOC_PDP11_DISP_8_PCREL, + BFD_RELOC_PDP11_DISP_6_PCREL, + +/* Picojava relocs. Not all of these appear in object files. */ + BFD_RELOC_PJ_CODE_HI16, + BFD_RELOC_PJ_CODE_LO16, + BFD_RELOC_PJ_CODE_DIR16, + BFD_RELOC_PJ_CODE_DIR32, + BFD_RELOC_PJ_CODE_REL16, + BFD_RELOC_PJ_CODE_REL32, + +/* Power(rs6000) and PowerPC relocations. */ + BFD_RELOC_PPC_B26, + BFD_RELOC_PPC_BA26, + BFD_RELOC_PPC_TOC16, + BFD_RELOC_PPC_B16, + BFD_RELOC_PPC_B16_BRTAKEN, + BFD_RELOC_PPC_B16_BRNTAKEN, + BFD_RELOC_PPC_BA16, + BFD_RELOC_PPC_BA16_BRTAKEN, + BFD_RELOC_PPC_BA16_BRNTAKEN, + BFD_RELOC_PPC_COPY, + BFD_RELOC_PPC_GLOB_DAT, + BFD_RELOC_PPC_JMP_SLOT, + BFD_RELOC_PPC_RELATIVE, + BFD_RELOC_PPC_LOCAL24PC, + BFD_RELOC_PPC_EMB_NADDR32, + BFD_RELOC_PPC_EMB_NADDR16, + BFD_RELOC_PPC_EMB_NADDR16_LO, + BFD_RELOC_PPC_EMB_NADDR16_HI, + BFD_RELOC_PPC_EMB_NADDR16_HA, + BFD_RELOC_PPC_EMB_SDAI16, + BFD_RELOC_PPC_EMB_SDA2I16, + BFD_RELOC_PPC_EMB_SDA2REL, + BFD_RELOC_PPC_EMB_SDA21, + BFD_RELOC_PPC_EMB_MRKREF, + BFD_RELOC_PPC_EMB_RELSEC16, + BFD_RELOC_PPC_EMB_RELST_LO, + BFD_RELOC_PPC_EMB_RELST_HI, + BFD_RELOC_PPC_EMB_RELST_HA, + BFD_RELOC_PPC_EMB_BIT_FLD, + BFD_RELOC_PPC_EMB_RELSDA, + +/* IBM 370/390 relocations */ + BFD_RELOC_I370_D12, + +/* The type of reloc used to build a contructor table - at the moment +probably a 32 bit wide absolute relocation, but the target can choose. +It generally does map to one of the other relocation types. */ + BFD_RELOC_CTOR, + +/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. */ + BFD_RELOC_ARM_PCREL_BRANCH, + +/* ARM 26 bit pc-relative branch. The lowest bit must be zero and is +not stored in the instruction. The 2nd lowest bit comes from a 1 bit +field in the instruction. */ + BFD_RELOC_ARM_PCREL_BLX, + +/* Thumb 22 bit pc-relative branch. The lowest bit must be zero and is +not stored in the instruction. The 2nd lowest bit comes from a 1 bit +field in the instruction. */ + BFD_RELOC_THUMB_PCREL_BLX, + +/* These relocs are only used within the ARM assembler. They are not +(at present) written to any object files. */ + BFD_RELOC_ARM_IMMEDIATE, + BFD_RELOC_ARM_ADRL_IMMEDIATE, + BFD_RELOC_ARM_OFFSET_IMM, + BFD_RELOC_ARM_SHIFT_IMM, + BFD_RELOC_ARM_SWI, + BFD_RELOC_ARM_MULTI, + BFD_RELOC_ARM_CP_OFF_IMM, + BFD_RELOC_ARM_ADR_IMM, + BFD_RELOC_ARM_LDR_IMM, + BFD_RELOC_ARM_LITERAL, + BFD_RELOC_ARM_IN_POOL, + BFD_RELOC_ARM_OFFSET_IMM8, + BFD_RELOC_ARM_HWLITERAL, + BFD_RELOC_ARM_THUMB_ADD, + BFD_RELOC_ARM_THUMB_IMM, + BFD_RELOC_ARM_THUMB_SHIFT, + BFD_RELOC_ARM_THUMB_OFFSET, + BFD_RELOC_ARM_GOT12, + BFD_RELOC_ARM_GOT32, + BFD_RELOC_ARM_JUMP_SLOT, + BFD_RELOC_ARM_COPY, + BFD_RELOC_ARM_GLOB_DAT, + BFD_RELOC_ARM_PLT32, + BFD_RELOC_ARM_RELATIVE, + BFD_RELOC_ARM_GOTOFF, + BFD_RELOC_ARM_GOTPC, + +/* Hitachi SH relocs. Not all of these appear in object files. */ + BFD_RELOC_SH_PCDISP8BY2, + BFD_RELOC_SH_PCDISP12BY2, + BFD_RELOC_SH_IMM4, + BFD_RELOC_SH_IMM4BY2, + BFD_RELOC_SH_IMM4BY4, + BFD_RELOC_SH_IMM8, + BFD_RELOC_SH_IMM8BY2, + BFD_RELOC_SH_IMM8BY4, + BFD_RELOC_SH_PCRELIMM8BY2, + BFD_RELOC_SH_PCRELIMM8BY4, + BFD_RELOC_SH_SWITCH16, + BFD_RELOC_SH_SWITCH32, + BFD_RELOC_SH_USES, + BFD_RELOC_SH_COUNT, + BFD_RELOC_SH_ALIGN, + BFD_RELOC_SH_CODE, + BFD_RELOC_SH_DATA, + BFD_RELOC_SH_LABEL, + BFD_RELOC_SH_LOOP_START, + BFD_RELOC_SH_LOOP_END, + BFD_RELOC_SH_COPY, + BFD_RELOC_SH_GLOB_DAT, + BFD_RELOC_SH_JMP_SLOT, + BFD_RELOC_SH_RELATIVE, + BFD_RELOC_SH_GOTPC, + +/* Thumb 23-, 12- and 9-bit pc-relative branches. The lowest bit must +be zero and is not stored in the instruction. */ + BFD_RELOC_THUMB_PCREL_BRANCH9, + BFD_RELOC_THUMB_PCREL_BRANCH12, + BFD_RELOC_THUMB_PCREL_BRANCH23, + +/* ARC Cores relocs. +ARC 22 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. The high 20 bits are installed in bits 26 +through 7 of the instruction. */ + BFD_RELOC_ARC_B22_PCREL, + +/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not +stored in the instruction. The high 24 bits are installed in bits 23 +through 0. */ + BFD_RELOC_ARC_B26, + +/* Mitsubishi D10V relocs. +This is a 10-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_10_PCREL_R, + +/* Mitsubishi D10V relocs. +This is a 10-bit reloc with the right 2 bits +assumed to be 0. This is the same as the previous reloc +except it is in the left container, i.e., +shifted left 15 bits. */ + BFD_RELOC_D10V_10_PCREL_L, + +/* This is an 18-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_18, + +/* This is an 18-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_18_PCREL, + +/* Mitsubishi D30V relocs. +This is a 6-bit absolute reloc. */ + BFD_RELOC_D30V_6, + +/* This is a 6-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_9_PCREL, + +/* This is a 6-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_9_PCREL_R, + +/* This is a 12-bit absolute reloc with the +right 3 bitsassumed to be 0. */ + BFD_RELOC_D30V_15, + +/* This is a 12-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_15_PCREL, + +/* This is a 12-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_15_PCREL_R, + +/* This is an 18-bit absolute reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_21, + +/* This is an 18-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_21_PCREL, + +/* This is an 18-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_21_PCREL_R, + +/* This is a 32-bit absolute reloc. */ + BFD_RELOC_D30V_32, + +/* This is a 32-bit pc-relative reloc. */ + BFD_RELOC_D30V_32_PCREL, + +/* Mitsubishi M32R relocs. +This is a 24 bit absolute address. */ + BFD_RELOC_M32R_24, + +/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_10_PCREL, + +/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_18_PCREL, + +/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_26_PCREL, + +/* This is a 16-bit reloc containing the high 16 bits of an address +used when the lower 16 bits are treated as unsigned. */ + BFD_RELOC_M32R_HI16_ULO, + +/* This is a 16-bit reloc containing the high 16 bits of an address +used when the lower 16 bits are treated as signed. */ + BFD_RELOC_M32R_HI16_SLO, + +/* This is a 16-bit reloc containing the lower 16 bits of an address. */ + BFD_RELOC_M32R_LO16, + +/* This is a 16-bit reloc containing the small data area offset for use in +add3, load, and store instructions. */ + BFD_RELOC_M32R_SDA16, + +/* This is a 9-bit reloc */ + BFD_RELOC_V850_9_PCREL, + +/* This is a 22-bit reloc */ + BFD_RELOC_V850_22_PCREL, + +/* This is a 16 bit offset from the short data area pointer. */ + BFD_RELOC_V850_SDA_16_16_OFFSET, + +/* This is a 16 bit offset (of which only 15 bits are used) from the +short data area pointer. */ + BFD_RELOC_V850_SDA_15_16_OFFSET, + +/* This is a 16 bit offset from the zero data area pointer. */ + BFD_RELOC_V850_ZDA_16_16_OFFSET, + +/* This is a 16 bit offset (of which only 15 bits are used) from the +zero data area pointer. */ + BFD_RELOC_V850_ZDA_15_16_OFFSET, + +/* This is an 8 bit offset (of which only 6 bits are used) from the +tiny data area pointer. */ + BFD_RELOC_V850_TDA_6_8_OFFSET, + +/* This is an 8bit offset (of which only 7 bits are used) from the tiny +data area pointer. */ + BFD_RELOC_V850_TDA_7_8_OFFSET, + +/* This is a 7 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_7_7_OFFSET, + +/* This is a 16 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_16_16_OFFSET, + +/* This is a 5 bit offset (of which only 4 bits are used) from the tiny +data area pointer. */ + BFD_RELOC_V850_TDA_4_5_OFFSET, + +/* This is a 4 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_4_4_OFFSET, + +/* This is a 16 bit offset from the short data area pointer, with the +bits placed non-contigously in the instruction. */ + BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, + +/* This is a 16 bit offset from the zero data area pointer, with the +bits placed non-contigously in the instruction. */ + BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, + +/* This is a 6 bit offset from the call table base pointer. */ + BFD_RELOC_V850_CALLT_6_7_OFFSET, + +/* This is a 16 bit offset from the call table base pointer. */ + BFD_RELOC_V850_CALLT_16_16_OFFSET, + + +/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_32_PCREL, + +/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_16_PCREL, + +/* This is a 8bit DP reloc for the tms320c30, where the most +significant 8 bits of a 24 bit word are placed into the least +significant 8 bits of the opcode. */ + BFD_RELOC_TIC30_LDP, + +/* This is a 7bit reloc for the tms320c54x, where the least +significant 7 bits of a 16 bit word are placed into the least +significant 7 bits of the opcode. */ + BFD_RELOC_TIC54X_PARTLS7, + +/* This is a 9bit DP reloc for the tms320c54x, where the most +significant 9 bits of a 16 bit word are placed into the least +significant 9 bits of the opcode. */ + BFD_RELOC_TIC54X_PARTMS9, + +/* This is an extended address 23-bit reloc for the tms320c54x. */ + BFD_RELOC_TIC54X_23, + +/* This is a 16-bit reloc for the tms320c54x, where the least +significant 16 bits of a 23-bit extended address are placed into +the opcode. */ + BFD_RELOC_TIC54X_16_OF_23, + +/* This is a reloc for the tms320c54x, where the most +significant 7 bits of a 23-bit extended address are placed into +the opcode. */ + BFD_RELOC_TIC54X_MS7_OF_23, + +/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ + BFD_RELOC_FR30_48, + +/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into +two sections. */ + BFD_RELOC_FR30_20, + +/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in +4 bits. */ + BFD_RELOC_FR30_6_IN_4, + +/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset +into 8 bits. */ + BFD_RELOC_FR30_8_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset +into 8 bits. */ + BFD_RELOC_FR30_9_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset +into 8 bits. */ + BFD_RELOC_FR30_10_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative +short offset into 8 bits. */ + BFD_RELOC_FR30_9_PCREL, + +/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative +short offset into 11 bits. */ + BFD_RELOC_FR30_12_PCREL, + +/* Motorola Mcore relocations. */ + BFD_RELOC_MCORE_PCREL_IMM8BY4, + BFD_RELOC_MCORE_PCREL_IMM11BY2, + BFD_RELOC_MCORE_PCREL_IMM4BY2, + BFD_RELOC_MCORE_PCREL_32, + BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, + BFD_RELOC_MCORE_RVA, + +/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative +short offset into 7 bits. */ + BFD_RELOC_AVR_7_PCREL, + +/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative +short offset into 12 bits. */ + BFD_RELOC_AVR_13_PCREL, + +/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually +program memory address) into 16 bits. */ + BFD_RELOC_AVR_16_PM, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually +data memory address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_LO8_LDI, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit +of data memory address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HI8_LDI, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit +of program memory address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HH8_LDI, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(usually data memory address) into 8 bit immediate value of SUBI insn. */ + BFD_RELOC_AVR_LO8_LDI_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(high 8 bit of data memory address) into 8 bit immediate value of +SUBI insn. */ + BFD_RELOC_AVR_HI8_LDI_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(most high 8 bit of program memory address) into 8 bit immediate value +of LDI or SUBI insn. */ + BFD_RELOC_AVR_HH8_LDI_NEG, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually +command address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_LO8_LDI_PM, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit +of command address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HI8_LDI_PM, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit +of command address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HH8_LDI_PM, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(usually command address) into 8 bit immediate value of SUBI insn. */ + BFD_RELOC_AVR_LO8_LDI_PM_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(high 8 bit of 16 bit command address) into 8 bit immediate value +of SUBI insn. */ + BFD_RELOC_AVR_HI8_LDI_PM_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(high 6 bit of 22 bit command address) into 8 bit immediate +value of SUBI insn. */ + BFD_RELOC_AVR_HH8_LDI_PM_NEG, + +/* This is a 32 bit reloc for the AVR that stores 23 bit value +into 22 bits. */ + BFD_RELOC_AVR_CALL, + +/* Direct 12 bit. */ + BFD_RELOC_390_12, + +/* 12 bit GOT offset. */ + BFD_RELOC_390_GOT12, + +/* 32 bit PC relative PLT address. */ + BFD_RELOC_390_PLT32, + +/* Copy symbol at runtime. */ + BFD_RELOC_390_COPY, + +/* Create GOT entry. */ + BFD_RELOC_390_GLOB_DAT, + +/* Create PLT entry. */ + BFD_RELOC_390_JMP_SLOT, + +/* Adjust by program base. */ + BFD_RELOC_390_RELATIVE, + +/* 32 bit PC relative offset to GOT. */ + BFD_RELOC_390_GOTPC, + +/* 16 bit GOT offset. */ + BFD_RELOC_390_GOT16, + +/* PC relative 16 bit shifted by 1. */ + BFD_RELOC_390_PC16DBL, + +/* 16 bit PC rel. PLT shifted by 1. */ + BFD_RELOC_390_PLT16DBL, + +/* PC relative 32 bit shifted by 1. */ + BFD_RELOC_390_PC32DBL, + +/* 32 bit PC rel. PLT shifted by 1. */ + BFD_RELOC_390_PLT32DBL, + +/* 32 bit PC rel. GOT shifted by 1. */ + BFD_RELOC_390_GOTPCDBL, + +/* 64 bit GOT offset. */ + BFD_RELOC_390_GOT64, + +/* 64 bit PC relative PLT address. */ + BFD_RELOC_390_PLT64, + +/* 32 bit rel. offset to GOT entry. */ + BFD_RELOC_390_GOTENT, + +/* These two relocations are used by the linker to determine which of +the entries in a C++ virtual function table are actually used. When +the --gc-sections option is given, the linker will zero out the entries +that are not used, so that the code for those functions need not be +included in the output. + +VTABLE_INHERIT is a zero-space relocation used to describe to the +linker the inheritence tree of a C++ virtual function table. The +relocation's symbol should be the parent class' vtable, and the +relocation should be located at the child vtable. + +VTABLE_ENTRY is a zero-space relocation that describes the use of a +virtual function table entry. The reloc's symbol should refer to the +table of the class mentioned in the code. Off of that base, an offset +describes the entry that is being used. For Rela hosts, this offset +is stored in the reloc's addend. For Rel hosts, we are forced to put +this offset in the reloc's section offset. */ + BFD_RELOC_VTABLE_INHERIT, + BFD_RELOC_VTABLE_ENTRY, + +/* Intel IA64 Relocations. */ + BFD_RELOC_IA64_IMM14, + BFD_RELOC_IA64_IMM22, + BFD_RELOC_IA64_IMM64, + BFD_RELOC_IA64_DIR32MSB, + BFD_RELOC_IA64_DIR32LSB, + BFD_RELOC_IA64_DIR64MSB, + BFD_RELOC_IA64_DIR64LSB, + BFD_RELOC_IA64_GPREL22, + BFD_RELOC_IA64_GPREL64I, + BFD_RELOC_IA64_GPREL32MSB, + BFD_RELOC_IA64_GPREL32LSB, + BFD_RELOC_IA64_GPREL64MSB, + BFD_RELOC_IA64_GPREL64LSB, + BFD_RELOC_IA64_LTOFF22, + BFD_RELOC_IA64_LTOFF64I, + BFD_RELOC_IA64_PLTOFF22, + BFD_RELOC_IA64_PLTOFF64I, + BFD_RELOC_IA64_PLTOFF64MSB, + BFD_RELOC_IA64_PLTOFF64LSB, + BFD_RELOC_IA64_FPTR64I, + BFD_RELOC_IA64_FPTR32MSB, + BFD_RELOC_IA64_FPTR32LSB, + BFD_RELOC_IA64_FPTR64MSB, + BFD_RELOC_IA64_FPTR64LSB, + BFD_RELOC_IA64_PCREL21B, + BFD_RELOC_IA64_PCREL21BI, + BFD_RELOC_IA64_PCREL21M, + BFD_RELOC_IA64_PCREL21F, + BFD_RELOC_IA64_PCREL22, + BFD_RELOC_IA64_PCREL60B, + BFD_RELOC_IA64_PCREL64I, + BFD_RELOC_IA64_PCREL32MSB, + BFD_RELOC_IA64_PCREL32LSB, + BFD_RELOC_IA64_PCREL64MSB, + BFD_RELOC_IA64_PCREL64LSB, + BFD_RELOC_IA64_LTOFF_FPTR22, + BFD_RELOC_IA64_LTOFF_FPTR64I, + BFD_RELOC_IA64_LTOFF_FPTR64MSB, + BFD_RELOC_IA64_LTOFF_FPTR64LSB, + BFD_RELOC_IA64_SEGREL32MSB, + BFD_RELOC_IA64_SEGREL32LSB, + BFD_RELOC_IA64_SEGREL64MSB, + BFD_RELOC_IA64_SEGREL64LSB, + BFD_RELOC_IA64_SECREL32MSB, + BFD_RELOC_IA64_SECREL32LSB, + BFD_RELOC_IA64_SECREL64MSB, + BFD_RELOC_IA64_SECREL64LSB, + BFD_RELOC_IA64_REL32MSB, + BFD_RELOC_IA64_REL32LSB, + BFD_RELOC_IA64_REL64MSB, + BFD_RELOC_IA64_REL64LSB, + BFD_RELOC_IA64_LTV32MSB, + BFD_RELOC_IA64_LTV32LSB, + BFD_RELOC_IA64_LTV64MSB, + BFD_RELOC_IA64_LTV64LSB, + BFD_RELOC_IA64_IPLTMSB, + BFD_RELOC_IA64_IPLTLSB, + BFD_RELOC_IA64_COPY, + BFD_RELOC_IA64_TPREL22, + BFD_RELOC_IA64_TPREL64MSB, + BFD_RELOC_IA64_TPREL64LSB, + BFD_RELOC_IA64_LTOFF_TP22, + BFD_RELOC_IA64_LTOFF22X, + BFD_RELOC_IA64_LDXMOV, + +/* Motorola 68HC11 reloc. +This is the 8 bits high part of an absolute address. */ + BFD_RELOC_M68HC11_HI8, + +/* Motorola 68HC11 reloc. +This is the 8 bits low part of an absolute address. */ + BFD_RELOC_M68HC11_LO8, + +/* Motorola 68HC11 reloc. +This is the 3 bits of a value. */ + BFD_RELOC_M68HC11_3B, + +/* These relocs are only used within the CRIS assembler. They are not +(at present) written to any object files. */ + BFD_RELOC_CRIS_BDISP8, + BFD_RELOC_CRIS_UNSIGNED_5, + BFD_RELOC_CRIS_SIGNED_6, + BFD_RELOC_CRIS_UNSIGNED_6, + BFD_RELOC_CRIS_UNSIGNED_4, + +/* Relocs used in ELF shared libraries for CRIS. */ + BFD_RELOC_CRIS_COPY, + BFD_RELOC_CRIS_GLOB_DAT, + BFD_RELOC_CRIS_JUMP_SLOT, + BFD_RELOC_CRIS_RELATIVE, + +/* 32-bit offset to symbol-entry within GOT. */ + BFD_RELOC_CRIS_32_GOT, + +/* 16-bit offset to symbol-entry within GOT. */ + BFD_RELOC_CRIS_16_GOT, + +/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_CRIS_32_GOTPLT, + +/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_CRIS_16_GOTPLT, + +/* 32-bit offset to symbol, relative to GOT. */ + BFD_RELOC_CRIS_32_GOTREL, + +/* 32-bit offset to symbol with PLT entry, relative to GOT. */ + BFD_RELOC_CRIS_32_PLT_GOTREL, + +/* 32-bit offset to symbol with PLT entry, relative to this relocation. */ + BFD_RELOC_CRIS_32_PLT_PCREL, + +/* Intel i860 Relocations. */ + BFD_RELOC_860_COPY, + BFD_RELOC_860_GLOB_DAT, + BFD_RELOC_860_JUMP_SLOT, + BFD_RELOC_860_RELATIVE, + BFD_RELOC_860_PC26, + BFD_RELOC_860_PLT26, + BFD_RELOC_860_PC16, + BFD_RELOC_860_LOW0, + BFD_RELOC_860_SPLIT0, + BFD_RELOC_860_LOW1, + BFD_RELOC_860_SPLIT1, + BFD_RELOC_860_LOW2, + BFD_RELOC_860_SPLIT2, + BFD_RELOC_860_LOW3, + BFD_RELOC_860_LOGOT0, + BFD_RELOC_860_SPGOT0, + BFD_RELOC_860_LOGOT1, + BFD_RELOC_860_SPGOT1, + BFD_RELOC_860_LOGOTOFF0, + BFD_RELOC_860_SPGOTOFF0, + BFD_RELOC_860_LOGOTOFF1, + BFD_RELOC_860_SPGOTOFF1, + BFD_RELOC_860_LOGOTOFF2, + BFD_RELOC_860_LOGOTOFF3, + BFD_RELOC_860_LOPC, + BFD_RELOC_860_HIGHADJ, + BFD_RELOC_860_HAGOT, + BFD_RELOC_860_HAGOTOFF, + BFD_RELOC_860_HAPC, + BFD_RELOC_860_HIGH, + BFD_RELOC_860_HIGOT, + BFD_RELOC_860_HIGOTOFF, + +/* OpenRISC Relocations. */ + BFD_RELOC_OPENRISC_ABS_26, + BFD_RELOC_OPENRISC_REL_26, + BFD_RELOC_UNUSED }; +typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +reloc_howto_type * +bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + +const char * +bfd_get_reloc_code_name PARAMS ((bfd_reloc_code_real_type code)); + + +typedef struct symbol_cache_entry +{ + /* A pointer to the BFD which owns the symbol. This information + is necessary so that a back end can work out what additional + information (invisible to the application writer) is carried + with the symbol. + + This field is *almost* redundant, since you can use section->owner + instead, except that some symbols point to the global sections + bfd_{abs,com,und}_section. This could be fixed by making + these globals be per-bfd (or per-target-flavor). FIXME. */ + + struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ + + /* The text of the symbol. The name is left alone, and not copied; the + application may not alter it. */ + CONST char *name; + + /* The value of the symbol. This really should be a union of a + numeric value with a pointer, since some flags indicate that + a pointer to another symbol is stored here. */ + symvalue value; + + /* Attributes of a symbol: */ + +#define BSF_NO_FLAGS 0x00 + + /* The symbol has local scope; <> in <>. The value + is the offset into the section of the data. */ +#define BSF_LOCAL 0x01 + + /* The symbol has global scope; initialized data in <>. The + value is the offset into the section of the data. */ +#define BSF_GLOBAL 0x02 + + /* The symbol has global scope and is exported. The value is + the offset into the section of the data. */ +#define BSF_EXPORT BSF_GLOBAL /* no real difference */ + + /* A normal C symbol would be one of: + <>, <>, <> or + <> */ + + /* The symbol is a debugging record. The value has an arbitary + meaning, unless BSF_DEBUGGING_RELOC is also set. */ +#define BSF_DEBUGGING 0x08 + + /* The symbol denotes a function entry point. Used in ELF, + perhaps others someday. */ +#define BSF_FUNCTION 0x10 + + /* Used by the linker. */ +#define BSF_KEEP 0x20 +#define BSF_KEEP_G 0x40 + + /* A weak global symbol, overridable without warnings by + a regular global symbol of the same name. */ +#define BSF_WEAK 0x80 + + /* This symbol was created to point to a section, e.g. ELF's + STT_SECTION symbols. */ +#define BSF_SECTION_SYM 0x100 + + /* The symbol used to be a common symbol, but now it is + allocated. */ +#define BSF_OLD_COMMON 0x200 + + /* The default value for common data. */ +#define BFD_FORT_COMM_DEFAULT_VALUE 0 + + /* In some files the type of a symbol sometimes alters its + location in an output file - ie in coff a <> symbol + which is also <> symbol appears where it was + declared and not at the end of a section. This bit is set + by the target BFD part to convey this information. */ + +#define BSF_NOT_AT_END 0x400 + + /* Signal that the symbol is the label of constructor section. */ +#define BSF_CONSTRUCTOR 0x800 + + /* Signal that the symbol is a warning symbol. The name is a + warning. The name of the next symbol is the one to warn about; + if a reference is made to a symbol with the same name as the next + symbol, a warning is issued by the linker. */ +#define BSF_WARNING 0x1000 + + /* Signal that the symbol is indirect. This symbol is an indirect + pointer to the symbol with the same name as the next symbol. */ +#define BSF_INDIRECT 0x2000 + + /* BSF_FILE marks symbols that contain a file name. This is used + for ELF STT_FILE symbols. */ +#define BSF_FILE 0x4000 + + /* Symbol is from dynamic linking information. */ +#define BSF_DYNAMIC 0x8000 + + /* The symbol denotes a data object. Used in ELF, and perhaps + others someday. */ +#define BSF_OBJECT 0x10000 + + /* This symbol is a debugging symbol. The value is the offset + into the section of the data. BSF_DEBUGGING should be set + as well. */ +#define BSF_DEBUGGING_RELOC 0x20000 + + flagword flags; + + /* A pointer to the section to which this symbol is + relative. This will always be non NULL, there are special + sections for undefined and absolute symbols. */ + struct sec *section; + + /* Back end special data. */ + union + { + PTR p; + bfd_vma i; + } udata; + +} asymbol; +#define bfd_get_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) +boolean +bfd_is_local_label PARAMS ((bfd *abfd, asymbol *sym)); + +boolean +bfd_is_local_label_name PARAMS ((bfd *abfd, const char *name)); + +#define bfd_is_local_label_name(abfd, name) \ + BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab,\ + (abfd, location)) +boolean +bfd_set_symtab PARAMS ((bfd *abfd, asymbol **location, unsigned int count)); + +void +bfd_print_symbol_vandf PARAMS ((PTR file, asymbol *symbol)); + +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +int +bfd_decode_symclass PARAMS ((asymbol *symbol)); + +boolean +bfd_is_undefined_symclass PARAMS ((int symclass)); + +void +bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret)); + +boolean +bfd_copy_private_symbol_data PARAMS ((bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym)); + +#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ + BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ + (ibfd, isymbol, obfd, osymbol)) +struct _bfd +{ + /* The filename the application opened the BFD with. */ + CONST char *filename; + + /* A pointer to the target jump table. */ + const struct bfd_target *xvec; + + /* To avoid dragging too many header files into every file that + includes `<>', IOSTREAM has been declared as a "char + *", and MTIME as a "long". Their correct types, to which they + are cast when used, are "FILE *" and "time_t". The iostream + is the result of an fopen on the filename. However, if the + BFD_IN_MEMORY flag is set, then iostream is actually a pointer + to a bfd_in_memory struct. */ + PTR iostream; + + /* Is the file descriptor being cached? That is, can it be closed as + needed, and re-opened when accessed later? */ + + boolean cacheable; + + /* Marks whether there was a default target specified when the + BFD was opened. This is used to select which matching algorithm + to use to choose the back end. */ + + boolean target_defaulted; + + /* The caching routines use these to maintain a + least-recently-used list of BFDs */ + + struct _bfd *lru_prev, *lru_next; + + /* When a file is closed by the caching routines, BFD retains + state information on the file here: */ + + file_ptr where; + + /* and here: (``once'' means at least once) */ + + boolean opened_once; + + /* Set if we have a locally maintained mtime value, rather than + getting it from the file each time: */ + + boolean mtime_set; + + /* File modified time, if mtime_set is true: */ + + long mtime; + + /* Reserved for an unimplemented file locking extension.*/ + + int ifd; + + /* The format which belongs to the BFD. (object, core, etc.) */ + + bfd_format format; + + /* The direction the BFD was opened with*/ + + enum bfd_direction {no_direction = 0, + read_direction = 1, + write_direction = 2, + both_direction = 3} direction; + + /* Format_specific flags*/ + + flagword flags; + + /* Currently my_archive is tested before adding origin to + anything. I believe that this can become always an add of + origin, with origin set to 0 for non archive files. */ + + file_ptr origin; + + /* Remember when output has begun, to stop strange things + from happening. */ + boolean output_has_begun; + + /* Pointer to linked list of sections*/ + struct sec *sections; + + /* The number of sections */ + unsigned int section_count; + + /* Stuff only useful for object files: + The start address. */ + bfd_vma start_address; + + /* Used for input and output*/ + unsigned int symcount; + + /* Symbol table for output BFD (with symcount entries) */ + struct symbol_cache_entry **outsymbols; + + /* Pointer to structure which contains architecture information*/ + const struct bfd_arch_info *arch_info; + + /* Stuff only useful for archives:*/ + PTR arelt_data; + struct _bfd *my_archive; /* The containing archive BFD. */ + struct _bfd *next; /* The next BFD in the archive. */ + struct _bfd *archive_head; /* The first BFD in the archive. */ + boolean has_armap; + + /* A chain of BFD structures involved in a link. */ + struct _bfd *link_next; + + /* A field used by _bfd_generic_link_add_archive_symbols. This will + be used only for archive elements. */ + int archive_pass; + + /* Used by the back end to hold private data. */ + + union + { + struct aout_data_struct *aout_data; + struct artdata *aout_ar_data; + struct _oasys_data *oasys_obj_data; + struct _oasys_ar_data *oasys_ar_data; + struct coff_tdata *coff_obj_data; + struct pe_tdata *pe_obj_data; + struct xcoff_tdata *xcoff_obj_data; + struct ecoff_tdata *ecoff_obj_data; + struct ieee_data_struct *ieee_data; + struct ieee_ar_data_struct *ieee_ar_data; + struct srec_data_struct *srec_data; + struct ihex_data_struct *ihex_data; + struct tekhex_data_struct *tekhex_data; + struct elf_obj_tdata *elf_obj_data; + struct nlm_obj_tdata *nlm_obj_data; + struct bout_data_struct *bout_data; + struct sun_core_struct *sun_core_data; + struct sco5_core_struct *sco5_core_data; + struct trad_core_struct *trad_core_data; + struct som_data_struct *som_data; + struct hpux_core_struct *hpux_core_data; + struct hppabsd_core_struct *hppabsd_core_data; + struct sgi_core_struct *sgi_core_data; + struct lynx_core_struct *lynx_core_data; + struct osf_core_struct *osf_core_data; + struct cisco_core_struct *cisco_core_data; + struct versados_data_struct *versados_data; + struct netbsd_core_struct *netbsd_core_data; + PTR any; + } tdata; + + /* Used by the application to hold private data*/ + PTR usrdata; + + /* Where all the allocated stuff under this BFD goes. This is a + struct objalloc *, but we use PTR to avoid requiring the inclusion of + objalloc.h. */ + PTR memory; +}; + +typedef enum bfd_error +{ + bfd_error_no_error = 0, + bfd_error_system_call, + bfd_error_invalid_target, + bfd_error_wrong_format, + bfd_error_invalid_operation, + bfd_error_no_memory, + bfd_error_no_symbols, + bfd_error_no_armap, + bfd_error_no_more_archived_files, + bfd_error_malformed_archive, + bfd_error_file_not_recognized, + bfd_error_file_ambiguously_recognized, + bfd_error_no_contents, + bfd_error_nonrepresentable_section, + bfd_error_no_debug_section, + bfd_error_bad_value, + bfd_error_file_truncated, + bfd_error_file_too_big, + bfd_error_invalid_error_code +} bfd_error_type; + +bfd_error_type +bfd_get_error PARAMS ((void)); + +void +bfd_set_error PARAMS ((bfd_error_type error_tag)); + +CONST char * +bfd_errmsg PARAMS ((bfd_error_type error_tag)); + +void +bfd_perror PARAMS ((CONST char *message)); + +typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...)); + +bfd_error_handler_type +bfd_set_error_handler PARAMS ((bfd_error_handler_type)); + +void +bfd_set_error_program_name PARAMS ((const char *)); + +bfd_error_handler_type +bfd_get_error_handler PARAMS ((void)); + +long +bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); + +long +bfd_canonicalize_reloc PARAMS ((bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms)); + +void +bfd_set_reloc PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count) + + ); + +boolean +bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags)); + +int +bfd_get_arch_size PARAMS ((bfd *abfd)); + +int +bfd_get_sign_extend_vma PARAMS ((bfd *abfd)); + +boolean +bfd_set_start_address PARAMS ((bfd *abfd, bfd_vma vma)); + +long +bfd_get_mtime PARAMS ((bfd *abfd)); + +long +bfd_get_size PARAMS ((bfd *abfd)); + +int +bfd_get_gp_size PARAMS ((bfd *abfd)); + +void +bfd_set_gp_size PARAMS ((bfd *abfd, int i)); + +bfd_vma +bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base)); + +boolean +bfd_copy_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_copy_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ + (ibfd, obfd)) +boolean +bfd_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_merge_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ + (ibfd, obfd)) +boolean +bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags)); + +#define bfd_set_private_flags(abfd, flags) \ + BFD_SEND (abfd, _bfd_set_private_flags, \ + (abfd, flags)) +#define bfd_sizeof_headers(abfd, reloc) \ + BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) + +#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ + BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) + + /* Do these three do anything useful at all, for any back end? */ +#define bfd_debug_info_start(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) + +#define bfd_debug_info_end(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) + +#define bfd_debug_info_accumulate(abfd, section) \ + BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) + + +#define bfd_stat_arch_elt(abfd, stat) \ + BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) + +#define bfd_update_armap_timestamp(abfd) \ + BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) + +#define bfd_set_arch_mach(abfd, arch, mach)\ + BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) + +#define bfd_relax_section(abfd, section, link_info, again) \ + BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) + +#define bfd_gc_sections(abfd, link_info) \ + BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) + +#define bfd_merge_sections(abfd, link_info) \ + BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) + +#define bfd_link_hash_table_create(abfd) \ + BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) + +#define bfd_link_add_symbols(abfd, info) \ + BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) + +#define bfd_final_link(abfd, info) \ + BFD_SEND (abfd, _bfd_final_link, (abfd, info)) + +#define bfd_free_cached_info(abfd) \ + BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) + +#define bfd_get_dynamic_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) + +#define bfd_print_private_bfd_data(abfd, file)\ + BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) + +#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) + +#define bfd_get_dynamic_reloc_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) + +#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) + +extern bfd_byte *bfd_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, + struct bfd_link_order *, bfd_byte *, + boolean, asymbol **)); + +symindex +bfd_get_next_mapent PARAMS ((bfd *abfd, symindex previous, carsym **sym)); + +boolean +bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head)); + +bfd * +bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous)); + +CONST char * +bfd_core_file_failing_command PARAMS ((bfd *abfd)); + +int +bfd_core_file_failing_signal PARAMS ((bfd *abfd)); + +boolean +core_file_matches_executable_p PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +#define BFD_SEND(bfd, message, arglist) \ + ((*((bfd)->xvec->message)) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND +#define BFD_SEND(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + ((*((bfd)->xvec->message)) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND_FMT +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif +enum bfd_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_xcoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_ihex_flavour, + bfd_target_som_flavour, + bfd_target_os9k_flavour, + bfd_target_versados_flavour, + bfd_target_msdos_flavour, + bfd_target_ovax_flavour, + bfd_target_evax_flavour +}; + +enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; + +/* Forward declaration. */ +typedef struct bfd_link_info _bfd_link_info; + +typedef struct bfd_target +{ + char *name; + enum bfd_flavour flavour; + enum bfd_endian byteorder; + enum bfd_endian header_byteorder; + flagword object_flags; + flagword section_flags; + char symbol_leading_char; + char ar_pad_char; + unsigned short ar_max_namelen; + bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + + /* Generic entry points. */ +#define BFD_JUMP_TABLE_GENERIC(NAME)\ +CAT(NAME,_close_and_cleanup),\ +CAT(NAME,_bfd_free_cached_info),\ +CAT(NAME,_new_section_hook),\ +CAT(NAME,_get_section_contents),\ +CAT(NAME,_get_section_contents_in_window) + + /* Called when the BFD is being closed to do any necessary cleanup. */ + boolean (*_close_and_cleanup) PARAMS ((bfd *)); + /* Ask the BFD to free all cached information. */ + boolean (*_bfd_free_cached_info) PARAMS ((bfd *)); + /* Called when a new section is created. */ + boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + /* Read the contents of a section. */ + boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + boolean (*_bfd_get_section_contents_in_window) + PARAMS ((bfd *, sec_ptr, bfd_window *, + file_ptr, bfd_size_type)); + + /* Entry points to copy private data. */ +#define BFD_JUMP_TABLE_COPY(NAME)\ +CAT(NAME,_bfd_copy_private_bfd_data),\ +CAT(NAME,_bfd_merge_private_bfd_data),\ +CAT(NAME,_bfd_copy_private_section_data),\ +CAT(NAME,_bfd_copy_private_symbol_data),\ +CAT(NAME,_bfd_set_private_flags),\ +CAT(NAME,_bfd_print_private_bfd_data)\ + /* Called to copy BFD general private data from one object file + to another. */ + boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to merge BFD general private data from one object file + to a common output file when linking. */ + boolean (*_bfd_merge_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to copy BFD private section data from one object file + to another. */ + boolean (*_bfd_copy_private_section_data) PARAMS ((bfd *, sec_ptr, + bfd *, sec_ptr)); + /* Called to copy BFD private symbol data from one symbol + to another. */ + boolean (*_bfd_copy_private_symbol_data) PARAMS ((bfd *, asymbol *, + bfd *, asymbol *)); + /* Called to set private backend flags */ + boolean (*_bfd_set_private_flags) PARAMS ((bfd *, flagword)); + + /* Called to print private BFD data */ + boolean (*_bfd_print_private_bfd_data) PARAMS ((bfd *, PTR)); + + /* Core file entry points. */ +#define BFD_JUMP_TABLE_CORE(NAME)\ +CAT(NAME,_core_file_failing_command),\ +CAT(NAME,_core_file_failing_signal),\ +CAT(NAME,_core_file_matches_executable_p) + char * (*_core_file_failing_command) PARAMS ((bfd *)); + int (*_core_file_failing_signal) PARAMS ((bfd *)); + boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + + /* Archive entry points. */ +#define BFD_JUMP_TABLE_ARCHIVE(NAME)\ +CAT(NAME,_slurp_armap),\ +CAT(NAME,_slurp_extended_name_table),\ +CAT(NAME,_construct_extended_name_table),\ +CAT(NAME,_truncate_arname),\ +CAT(NAME,_write_armap),\ +CAT(NAME,_read_ar_hdr),\ +CAT(NAME,_openr_next_archived_file),\ +CAT(NAME,_get_elt_at_index),\ +CAT(NAME,_generic_stat_arch_elt),\ +CAT(NAME,_update_armap_timestamp) + boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); + boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); + boolean (*_bfd_construct_extended_name_table) + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); + void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); + boolean (*write_armap) PARAMS ((bfd *arch, + unsigned int elength, + struct orl *map, + unsigned int orl_count, + int stridx)); + PTR (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *)); + bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); +#define bfd_get_elt_at_index(b,i) BFD_SEND(b, _bfd_get_elt_at_index, (b,i)) + bfd * (*_bfd_get_elt_at_index) PARAMS ((bfd *, symindex)); + int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); + boolean (*_bfd_update_armap_timestamp) PARAMS ((bfd *)); + + /* Entry points used for symbols. */ +#define BFD_JUMP_TABLE_SYMBOLS(NAME)\ +CAT(NAME,_get_symtab_upper_bound),\ +CAT(NAME,_get_symtab),\ +CAT(NAME,_make_empty_symbol),\ +CAT(NAME,_print_symbol),\ +CAT(NAME,_get_symbol_info),\ +CAT(NAME,_bfd_is_local_label_name),\ +CAT(NAME,_get_lineno),\ +CAT(NAME,_find_nearest_line),\ +CAT(NAME,_bfd_make_debug_symbol),\ +CAT(NAME,_read_minisymbols),\ +CAT(NAME,_minisymbol_to_symbol) + long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *)); + long (*_bfd_canonicalize_symtab) PARAMS ((bfd *, + struct symbol_cache_entry **)); + struct symbol_cache_entry * + (*_bfd_make_empty_symbol) PARAMS ((bfd *)); + void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, + struct symbol_cache_entry *, + bfd_print_symbol_type)); +#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) + void (*_bfd_get_symbol_info) PARAMS ((bfd *, + struct symbol_cache_entry *, + symbol_info *)); +#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + boolean (*_bfd_is_local_label_name) PARAMS ((bfd *, const char *)); + + alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); + boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, + struct sec *section, struct symbol_cache_entry **symbols, + bfd_vma offset, CONST char **file, CONST char **func, + unsigned int *line)); + /* Back-door to allow format-aware applications to create debug symbols + while using BFD for everything else. Currently used by the assembler + when creating COFF files. */ + asymbol * (*_bfd_make_debug_symbol) PARAMS (( + bfd *abfd, + void *ptr, + unsigned long size)); +#define bfd_read_minisymbols(b, d, m, s) \ + BFD_SEND (b, _read_minisymbols, (b, d, m, s)) + long (*_read_minisymbols) PARAMS ((bfd *, boolean, PTR *, + unsigned int *)); +#define bfd_minisymbol_to_symbol(b, d, m, f) \ + BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) + asymbol *(*_minisymbol_to_symbol) PARAMS ((bfd *, boolean, const PTR, + asymbol *)); + + /* Routines for relocs. */ +#define BFD_JUMP_TABLE_RELOCS(NAME)\ +CAT(NAME,_get_reloc_upper_bound),\ +CAT(NAME,_canonicalize_reloc),\ +CAT(NAME,_bfd_reloc_type_lookup) + long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); + long (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, + struct symbol_cache_entry **)); + /* See documentation on reloc types. */ + reloc_howto_type * + (*reloc_type_lookup) PARAMS ((bfd *abfd, + bfd_reloc_code_real_type code)); + + /* Routines used when writing an object file. */ +#define BFD_JUMP_TABLE_WRITE(NAME)\ +CAT(NAME,_set_arch_mach),\ +CAT(NAME,_set_section_contents) + boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); + boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + + /* Routines used by the linker. */ +#define BFD_JUMP_TABLE_LINK(NAME)\ +CAT(NAME,_sizeof_headers),\ +CAT(NAME,_bfd_get_relocated_section_contents),\ +CAT(NAME,_bfd_relax_section),\ +CAT(NAME,_bfd_link_hash_table_create),\ +CAT(NAME,_bfd_link_add_symbols),\ +CAT(NAME,_bfd_final_link),\ +CAT(NAME,_bfd_link_split_section),\ +CAT(NAME,_bfd_gc_sections),\ +CAT(NAME,_bfd_merge_sections) + int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); + bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, + struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *data, boolean relocateable, + struct symbol_cache_entry **)); + + boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, + struct bfd_link_info *, boolean *again)); + + /* Create a hash table for the linker. Different backends store + different information in this table. */ + struct bfd_link_hash_table *(*_bfd_link_hash_table_create) PARAMS ((bfd *)); + + /* Add symbols from this object file into the hash table. */ + boolean (*_bfd_link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Do a link based on the link_order structures attached to each + section of the BFD. */ + boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Should this section be split up into smaller pieces during linking. */ + boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *)); + + /* Remove sections that are not referenced from the output. */ + boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Attempt to merge SEC_MERGE sections. */ + boolean (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Routines to handle dynamic symbols and relocs. */ +#define BFD_JUMP_TABLE_DYNAMIC(NAME)\ +CAT(NAME,_get_dynamic_symtab_upper_bound),\ +CAT(NAME,_canonicalize_dynamic_symtab),\ +CAT(NAME,_get_dynamic_reloc_upper_bound),\ +CAT(NAME,_canonicalize_dynamic_reloc) + /* Get the amount of memory required to hold the dynamic symbols. */ + long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic symbols. */ + long (*_bfd_canonicalize_dynamic_symtab) + PARAMS ((bfd *, struct symbol_cache_entry **)); + /* Get the amount of memory required to hold the dynamic relocs. */ + long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic relocs. */ + long (*_bfd_canonicalize_dynamic_reloc) + PARAMS ((bfd *, arelent **, struct symbol_cache_entry **)); + + /* Opposite endian version of this target. */ + const struct bfd_target * alternative_target; + + PTR backend_data; + +} bfd_target; +boolean +bfd_set_default_target PARAMS ((const char *name)); + +const bfd_target * +bfd_find_target PARAMS ((CONST char *target_name, bfd *abfd)); + +const char ** +bfd_target_list PARAMS ((void)); + +const bfd_target * +bfd_search_for_target PARAMS ((int (* search_func) (const bfd_target *, void *), void *)); + +boolean +bfd_check_format PARAMS ((bfd *abfd, bfd_format format)); + +boolean +bfd_check_format_matches PARAMS ((bfd *abfd, bfd_format format, char ***matching)); + +boolean +bfd_set_format PARAMS ((bfd *abfd, bfd_format format)); + +CONST char * +bfd_format_string PARAMS ((bfd_format format)); + +#ifdef __cplusplus +} +#endif +#endif diff -Nur linux-2.4.19/arch/ia64/kdb/cpu-ia64-opc.c linux-2.4.19-sgi211r3/arch/ia64/kdb/cpu-ia64-opc.c --- linux-2.4.19/arch/ia64/kdb/cpu-ia64-opc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/cpu-ia64-opc.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,586 @@ +/* Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Logically, this code should be part of libopcode but since some of + the operand insertion/extraction functions help bfd to implement + relocations, this code is included as part of elf64-ia64.c. This + avoids circular dependencies between libopcode and libbfd and also + obviates the need for applications to link in libopcode when all + they really want is libbfd. + + --davidm Mon Apr 13 22:14:02 1998 */ + +#include "ia64-opc.h" + +#define NELEMS(a) ((int) (sizeof (a) / sizeof ((a)[0]))) + +static const char* +ins_rsvd (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + return "internal error---this shouldn't happen"; +} + +static const char* +ext_rsvd (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + return "internal error---this shouldn't happen"; +} + +static const char* +ins_const (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + return 0; +} + +static const char* +ext_const (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + return 0; +} + +static const char* +ins_reg (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + if (value >= 1u << self->field[0].bits) + return "register number out of range"; + + *code |= value << self->field[0].shift; + return 0; +} + +static const char* +ext_reg (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + *valuep = ((code >> self->field[0].shift) + & ((1u << self->field[0].bits) - 1)); + return 0; +} + +static const char* +ins_immu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + ia64_insn new = 0; + int i; + + for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) + { + new |= ((value & ((((ia64_insn) 1) << self->field[i].bits) - 1)) + << self->field[i].shift); + value >>= self->field[i].bits; + } + if (value) + return "integer operand out of range"; + + *code |= new; + return 0; +} + +static const char* +ext_immu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + BFD_HOST_U_64_BIT value = 0; + int i, bits = 0, total = 0; + + for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) + { + bits = self->field[i].bits; + value |= ((code >> self->field[i].shift) + & ((((BFD_HOST_U_64_BIT) 1) << bits) - 1)) << total; + total += bits; + } + *valuep = value; + return 0; +} + +static const char* +ins_immus8 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + if (value & 0x7) + return "value not an integer multiple of 8"; + return ins_immu (self, value >> 3, code); +} + +static const char* +ext_immus8 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + const char *result; + + result = ext_immu (self, code, valuep); + if (result) + return result; + + *valuep = *valuep << 3; + return 0; +} + +static const char* +ins_imms_scaled (const struct ia64_operand *self, ia64_insn value, + ia64_insn *code, int scale) +{ + BFD_HOST_64_BIT svalue = value, sign_bit = 0; + ia64_insn new = 0; + int i; + + svalue >>= scale; + + for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) + { + new |= ((svalue & ((((ia64_insn) 1) << self->field[i].bits) - 1)) + << self->field[i].shift); + sign_bit = (svalue >> (self->field[i].bits - 1)) & 1; + svalue >>= self->field[i].bits; + } + if ((!sign_bit && svalue != 0) || (sign_bit && svalue != -1)) + return "integer operand out of range"; + + *code |= new; + return 0; +} + +static const char* +ext_imms_scaled (const struct ia64_operand *self, ia64_insn code, + ia64_insn *valuep, int scale) +{ + int i, bits = 0, total = 0, shift; + BFD_HOST_64_BIT val = 0; + + for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) + { + bits = self->field[i].bits; + val |= ((code >> self->field[i].shift) + & ((((BFD_HOST_U_64_BIT) 1) << bits) - 1)) << total; + total += bits; + } + /* sign extend: */ + shift = 8*sizeof (val) - total; + val = (val << shift) >> shift; + + *valuep = (val << scale); + return 0; +} + +static const char* +ins_imms (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + return ins_imms_scaled (self, value, code, 0); +} + +static const char* +ins_immsu4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + if (value == (BFD_HOST_U_64_BIT) 0x100000000) + value = 0; + else + value = (((BFD_HOST_64_BIT)value << 32) >> 32); + + return ins_imms_scaled (self, value, code, 0); +} + +static const char* +ext_imms (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + return ext_imms_scaled (self, code, valuep, 0); +} + +static const char* +ins_immsm1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + --value; + return ins_imms_scaled (self, value, code, 0); +} + +static const char* +ins_immsm1u4 (const struct ia64_operand *self, ia64_insn value, + ia64_insn *code) +{ + if (value == (BFD_HOST_U_64_BIT) 0x100000000) + value = 0; + else + value = (((BFD_HOST_64_BIT)value << 32) >> 32); + + --value; + return ins_imms_scaled (self, value, code, 0); +} + +static const char* +ext_immsm1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + const char *res = ext_imms_scaled (self, code, valuep, 0); + + ++*valuep; + return res; +} + +static const char* +ins_imms1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + return ins_imms_scaled (self, value, code, 1); +} + +static const char* +ext_imms1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + return ext_imms_scaled (self, code, valuep, 1); +} + +static const char* +ins_imms4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + return ins_imms_scaled (self, value, code, 4); +} + +static const char* +ext_imms4 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + return ext_imms_scaled (self, code, valuep, 4); +} + +static const char* +ins_imms16 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + return ins_imms_scaled (self, value, code, 16); +} + +static const char* +ext_imms16 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + return ext_imms_scaled (self, code, valuep, 16); +} + +static const char* +ins_cimmu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + ia64_insn mask = (((ia64_insn) 1) << self->field[0].bits) - 1; + return ins_immu (self, value ^ mask, code); +} + +static const char* +ext_cimmu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + const char *result; + ia64_insn mask; + + mask = (((ia64_insn) 1) << self->field[0].bits) - 1; + result = ext_immu (self, code, valuep); + if (!result) + { + mask = (((ia64_insn) 1) << self->field[0].bits) - 1; + *valuep ^= mask; + } + return result; +} + +static const char* +ins_cnt (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + --value; + if (value >= ((BFD_HOST_U_64_BIT) 1) << self->field[0].bits) + return "count out of range"; + + *code |= value << self->field[0].shift; + return 0; +} + +static const char* +ext_cnt (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + *valuep = ((code >> self->field[0].shift) + & ((((BFD_HOST_U_64_BIT) 1) << self->field[0].bits) - 1)) + 1; + return 0; +} + +static const char* +ins_cnt2b (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + --value; + + if (value > 2) + return "count must be in range 1..3"; + + *code |= value << self->field[0].shift; + return 0; +} + +static const char* +ext_cnt2b (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + *valuep = ((code >> self->field[0].shift) & 0x3) + 1; + return 0; +} + +static const char* +ins_cnt2c (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + switch (value) + { + case 0: value = 0; break; + case 7: value = 1; break; + case 15: value = 2; break; + case 16: value = 3; break; + default: return "count must be 0, 7, 15, or 16"; + } + *code |= value << self->field[0].shift; + return 0; +} + +static const char* +ext_cnt2c (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + ia64_insn value; + + value = (code >> self->field[0].shift) & 0x3; + switch (value) + { + case 0: value = 0; break; + case 1: value = 7; break; + case 2: value = 15; break; + case 3: value = 16; break; + } + *valuep = value; + return 0; +} + +static const char* +ins_inc3 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) +{ + BFD_HOST_64_BIT val = value; + BFD_HOST_U_64_BIT sign = 0; + + if (val < 0) + { + sign = 0x4; + value = -value; + } + switch (value) + { + case 1: value = 3; break; + case 4: value = 2; break; + case 8: value = 1; break; + case 16: value = 0; break; + default: return "count must be +/- 1, 4, 8, or 16"; + } + *code |= (sign | value) << self->field[0].shift; + return 0; +} + +static const char* +ext_inc3 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) +{ + BFD_HOST_64_BIT val; + int negate; + + val = (code >> self->field[0].shift) & 0x7; + negate = val & 0x4; + switch (val & 0x3) + { + case 0: val = 16; break; + case 1: val = 8; break; + case 2: val = 4; break; + case 3: val = 1; break; + } + if (negate) + val = -val; + + *valuep = val; + return 0; +} + +#define CST IA64_OPND_CLASS_CST +#define REG IA64_OPND_CLASS_REG +#define IND IA64_OPND_CLASS_IND +#define ABS IA64_OPND_CLASS_ABS +#define REL IA64_OPND_CLASS_REL + +#define SDEC IA64_OPND_FLAG_DECIMAL_SIGNED +#define UDEC IA64_OPND_FLAG_DECIMAL_UNSIGNED + +const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT] = + { + /* constants: */ + { CST, ins_const, ext_const, "NIL", {{ 0, }}, 0, "" }, + { CST, ins_const, ext_const, "ar.ccv", {{ 0, }}, 0, "ar.ccv" }, + { CST, ins_const, ext_const, "ar.pfs", {{ 0, }}, 0, "ar.pfs" }, + { CST, ins_const, ext_const, "1", {{ 0, }}, 0, "1" }, + { CST, ins_const, ext_const, "8", {{ 0, }}, 0, "1" }, + { CST, ins_const, ext_const, "16", {{ 0, }}, 0, "16" }, + { CST, ins_const, ext_const, "r0", {{ 0, }}, 0, "r0" }, + { CST, ins_const, ext_const, "ip", {{ 0, }}, 0, "ip" }, + { CST, ins_const, ext_const, "pr", {{ 0, }}, 0, "pr" }, + { CST, ins_const, ext_const, "pr.rot", {{ 0, }}, 0, "pr.rot" }, + { CST, ins_const, ext_const, "psr", {{ 0, }}, 0, "psr" }, + { CST, ins_const, ext_const, "psr.l", {{ 0, }}, 0, "psr.l" }, + { CST, ins_const, ext_const, "psr.um", {{ 0, }}, 0, "psr.um" }, + + /* register operands: */ + { REG, ins_reg, ext_reg, "ar", {{ 7, 20}}, 0, /* AR3 */ + "an application register" }, + { REG, ins_reg, ext_reg, "b", {{ 3, 6}}, 0, /* B1 */ + "a branch register" }, + { REG, ins_reg, ext_reg, "b", {{ 3, 13}}, 0, /* B2 */ + "a branch register"}, + { REG, ins_reg, ext_reg, "cr", {{ 7, 20}}, 0, /* CR */ + "a control register"}, + { REG, ins_reg, ext_reg, "f", {{ 7, 6}}, 0, /* F1 */ + "a floating-point register" }, + { REG, ins_reg, ext_reg, "f", {{ 7, 13}}, 0, /* F2 */ + "a floating-point register" }, + { REG, ins_reg, ext_reg, "f", {{ 7, 20}}, 0, /* F3 */ + "a floating-point register" }, + { REG, ins_reg, ext_reg, "f", {{ 7, 27}}, 0, /* F4 */ + "a floating-point register" }, + { REG, ins_reg, ext_reg, "p", {{ 6, 6}}, 0, /* P1 */ + "a predicate register" }, + { REG, ins_reg, ext_reg, "p", {{ 6, 27}}, 0, /* P2 */ + "a predicate register" }, + { REG, ins_reg, ext_reg, "r", {{ 7, 6}}, 0, /* R1 */ + "a general register" }, + { REG, ins_reg, ext_reg, "r", {{ 7, 13}}, 0, /* R2 */ + "a general register" }, + { REG, ins_reg, ext_reg, "r", {{ 7, 20}}, 0, /* R3 */ + "a general register" }, + { REG, ins_reg, ext_reg, "r", {{ 2, 20}}, 0, /* R3_2 */ + "a general register r0-r3" }, + + /* indirect operands: */ + { IND, ins_reg, ext_reg, "cpuid", {{7, 20}}, 0, /* CPUID_R3 */ + "a cpuid register" }, + { IND, ins_reg, ext_reg, "dbr", {{7, 20}}, 0, /* DBR_R3 */ + "a dbr register" }, + { IND, ins_reg, ext_reg, "dtr", {{7, 20}}, 0, /* DTR_R3 */ + "a dtr register" }, + { IND, ins_reg, ext_reg, "itr", {{7, 20}}, 0, /* ITR_R3 */ + "an itr register" }, + { IND, ins_reg, ext_reg, "ibr", {{7, 20}}, 0, /* IBR_R3 */ + "an ibr register" }, + { IND, ins_reg, ext_reg, "", {{7, 20}}, 0, /* MR3 */ + "an indirect memory address" }, + { IND, ins_reg, ext_reg, "msr", {{7, 20}}, 0, /* MSR_R3 */ + "an msr register" }, + { IND, ins_reg, ext_reg, "pkr", {{7, 20}}, 0, /* PKR_R3 */ + "a pkr register" }, + { IND, ins_reg, ext_reg, "pmc", {{7, 20}}, 0, /* PMC_R3 */ + "a pmc register" }, + { IND, ins_reg, ext_reg, "pmd", {{7, 20}}, 0, /* PMD_R3 */ + "a pmd register" }, + { IND, ins_reg, ext_reg, "rr", {{7, 20}}, 0, /* RR_R3 */ + "an rr register" }, + + /* immediate operands: */ + { ABS, ins_cimmu, ext_cimmu, 0, {{ 5, 20 }}, UDEC, /* CCNT5 */ + "a 5-bit count (0-31)" }, + { ABS, ins_cnt, ext_cnt, 0, {{ 2, 27 }}, UDEC, /* CNT2a */ + "a 2-bit count (1-4)" }, + { ABS, ins_cnt2b, ext_cnt2b, 0, {{ 2, 27 }}, UDEC, /* CNT2b */ + "a 2-bit count (1-3)" }, + { ABS, ins_cnt2c, ext_cnt2c, 0, {{ 2, 30 }}, UDEC, /* CNT2c */ + "a count (0, 7, 15, or 16)" }, + { ABS, ins_immu, ext_immu, 0, {{ 5, 14}}, UDEC, /* CNT5 */ + "a 5-bit count (0-31)" }, + { ABS, ins_immu, ext_immu, 0, {{ 6, 27}}, UDEC, /* CNT6 */ + "a 6-bit count (0-63)" }, + { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 20}}, UDEC, /* CPOS6a */ + "a 6-bit bit pos (0-63)" }, + { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 14}}, UDEC, /* CPOS6b */ + "a 6-bit bit pos (0-63)" }, + { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 31}}, UDEC, /* CPOS6c */ + "a 6-bit bit pos (0-63)" }, + { ABS, ins_imms, ext_imms, 0, {{ 1, 36}}, SDEC, /* IMM1 */ + "a 1-bit integer (-1, 0)" }, + { ABS, ins_immu, ext_immu, 0, {{ 2, 13}}, UDEC, /* IMMU2 */ + "a 2-bit unsigned (0-3)" }, + { ABS, ins_immu, ext_immu, 0, {{ 7, 13}}, 0, /* IMMU7a */ + "a 7-bit unsigned (0-127)" }, + { ABS, ins_immu, ext_immu, 0, {{ 7, 20}}, 0, /* IMMU7b */ + "a 7-bit unsigned (0-127)" }, + { ABS, ins_immu, ext_immu, 0, {{ 7, 13}}, UDEC, /* SOF */ + "a frame size (register count)" }, + { ABS, ins_immu, ext_immu, 0, {{ 7, 20}}, UDEC, /* SOL */ + "a local register count" }, + { ABS, ins_immus8,ext_immus8,0, {{ 4, 27}}, UDEC, /* SOR */ + "a rotating register count (integer multiple of 8)" }, + { ABS, ins_imms, ext_imms, 0, /* IMM8 */ + {{ 7, 13}, { 1, 36}}, SDEC, + "an 8-bit integer (-128-127)" }, + { ABS, ins_immsu4, ext_imms, 0, /* IMM8U4 */ + {{ 7, 13}, { 1, 36}}, SDEC, + "an 8-bit signed integer for 32-bit unsigned compare (-128-127)" }, + { ABS, ins_immsm1, ext_immsm1, 0, /* IMM8M1 */ + {{ 7, 13}, { 1, 36}}, SDEC, + "an 8-bit integer (-127-128)" }, + { ABS, ins_immsm1u4, ext_immsm1, 0, /* IMM8M1U4 */ + {{ 7, 13}, { 1, 36}}, SDEC, + "an 8-bit integer for 32-bit unsigned compare (-127-(-1),1-128,0x100000000)" }, + { ABS, ins_immsm1, ext_immsm1, 0, /* IMM8M1U8 */ + {{ 7, 13}, { 1, 36}}, SDEC, + "an 8-bit integer for 64-bit unsigned compare (-127-(-1),1-128,0x10000000000000000)" }, + { ABS, ins_immu, ext_immu, 0, {{ 2, 33}, { 7, 20}}, 0, /* IMMU9 */ + "a 9-bit unsigned (0-511)" }, + { ABS, ins_imms, ext_imms, 0, /* IMM9a */ + {{ 7, 6}, { 1, 27}, { 1, 36}}, SDEC, + "a 9-bit integer (-256-255)" }, + { ABS, ins_imms, ext_imms, 0, /* IMM9b */ + {{ 7, 13}, { 1, 27}, { 1, 36}}, SDEC, + "a 9-bit integer (-256-255)" }, + { ABS, ins_imms, ext_imms, 0, /* IMM14 */ + {{ 7, 13}, { 6, 27}, { 1, 36}}, SDEC, + "a 14-bit integer (-8192-8191)" }, + { ABS, ins_imms1, ext_imms1, 0, /* IMM17 */ + {{ 7, 6}, { 8, 24}, { 1, 36}}, 0, + "a 17-bit integer (-65536-65535)" }, + { ABS, ins_immu, ext_immu, 0, {{20, 6}, { 1, 36}}, 0, /* IMMU21 */ + "a 21-bit unsigned" }, + { ABS, ins_imms, ext_imms, 0, /* IMM22 */ + {{ 7, 13}, { 9, 27}, { 5, 22}, { 1, 36}}, SDEC, + "a 22-bit integer" }, + { ABS, ins_immu, ext_immu, 0, /* IMMU24 */ + {{21, 6}, { 2, 31}, { 1, 36}}, 0, + "a 24-bit unsigned" }, + { ABS, ins_imms16,ext_imms16,0, {{27, 6}, { 1, 36}}, 0, /* IMM44 */ + "a 44-bit unsigned (least 16 bits ignored/zeroes)" }, + { ABS, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* IMMU62 */ + "a 62-bit unsigned" }, + { ABS, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* IMMU64 */ + "a 64-bit unsigned" }, + { ABS, ins_inc3, ext_inc3, 0, {{ 3, 13}}, SDEC, /* INC3 */ + "an increment (+/- 1, 4, 8, or 16)" }, + { ABS, ins_cnt, ext_cnt, 0, {{ 4, 27}}, UDEC, /* LEN4 */ + "a 4-bit length (1-16)" }, + { ABS, ins_cnt, ext_cnt, 0, {{ 6, 27}}, UDEC, /* LEN6 */ + "a 6-bit length (1-64)" }, + { ABS, ins_immu, ext_immu, 0, {{ 4, 20}}, 0, /* MBTYPE4 */ + "a mix type (@rev, @mix, @shuf, @alt, or @brcst)" }, + { ABS, ins_immu, ext_immu, 0, {{ 8, 20}}, 0, /* MBTYPE8 */ + "an 8-bit mix type" }, + { ABS, ins_immu, ext_immu, 0, {{ 6, 14}}, UDEC, /* POS6 */ + "a 6-bit bit pos (0-63)" }, + { REL, ins_imms4, ext_imms4, 0, {{ 7, 6}, { 2, 33}}, 0, /* TAG13 */ + "a branch tag" }, + { REL, ins_imms4, ext_imms4, 0, {{ 9, 24}}, 0, /* TAG13b */ + "a branch tag" }, + { REL, ins_imms4, ext_imms4, 0, {{20, 6}, { 1, 36}}, 0, /* TGT25 */ + "a branch target" }, + { REL, ins_imms4, ext_imms4, 0, /* TGT25b */ + {{ 7, 6}, {13, 20}, { 1, 36}}, 0, + "a branch target" }, + { REL, ins_imms4, ext_imms4, 0, {{20, 13}, { 1, 36}}, 0, /* TGT25c */ + "a branch target" }, + { REL, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* TGT64 */ + "a branch target" }, + }; diff -Nur linux-2.4.19/arch/ia64/kdb/ia64-asmtab.c linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-asmtab.c --- linux-2.4.19/arch/ia64/kdb/ia64-asmtab.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-asmtab.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,6562 @@ +/* This file is automatically generated by ia64-gen. Do not edit! */ +static const char *ia64_strings[] = { + "", "0", "1", "a", "acq", "add", "addl", "addp4", "adds", "alloc", "and", + "andcm", "b", "bias", "br", "break", "brl", "brp", "bsw", "c", "call", + "cexit", "chk", "cloop", "clr", "clrrrb", "cmp", "cmp4", "cmpxchg1", + "cmpxchg2", "cmpxchg4", "cmpxchg8", "cond", "cover", "ctop", "czx1", + "czx2", "d", "dc", "dep", "dpnt", "dptk", "e", "epc", "eq", "excl", + "exit", "exp", "extr", "f", "fabs", "fadd", "famax", "famin", "fand", + "fandcm", "fault", "fc", "fchkf", "fclass", "fclrf", "fcmp", "fcvt", + "fetchadd4", "fetchadd8", "few", "fill", "flushrs", "fma", "fmax", + "fmerge", "fmin", "fmix", "fmpy", "fms", "fneg", "fnegabs", "fnma", + "fnmpy", "fnorm", "for", "fpabs", "fpack", "fpamax", "fpamin", "fpcmp", + "fpcvt", "fpma", "fpmax", "fpmerge", "fpmin", "fpmpy", "fpms", "fpneg", + "fpnegabs", "fpnma", "fpnmpy", "fprcpa", "fprsqrta", "frcpa", "frsqrta", + "fselect", "fsetc", "fsub", "fswap", "fsxt", "fwb", "fx", "fxor", "fxu", + "g", "ga", "ge", "getf", "geu", "gt", "gtu", "h", "hu", "i", "ia", "imp", + "invala", "itc", "itr", "l", "ld1", "ld2", "ld4", "ld8", "ldf", "ldf8", + "ldfd", "ldfe", "ldfp8", "ldfpd", "ldfps", "ldfs", "le", "leu", "lfetch", + "loadrs", "loop", "lr", "lt", "ltu", "lu", "m", "many", "mf", "mix1", + "mix2", "mix4", "mov", "movl", "mux1", "mux2", "nc", "ne", "neq", "nge", + "ngt", "nl", "nle", "nlt", "nm", "nop", "nr", "ns", "nt", "nt1", "nt2", + "nta", "nz", "or", "orcm", "ord", "pack2", "pack4", "padd1", "padd2", + "padd4", "pavg1", "pavg2", "pavgsub1", "pavgsub2", "pcmp1", "pcmp2", + "pcmp4", "pmax1", "pmax2", "pmin1", "pmin2", "pmpy2", "pmpyshr2", + "popcnt", "pr", "probe", "psad1", "pshl2", "pshl4", "pshladd2", "pshr2", + "pshr4", "pshradd2", "psub1", "psub2", "psub4", "ptc", "ptr", "r", "raz", + "rel", "ret", "rfi", "rsm", "rum", "rw", "s", "s0", "s1", "s2", "s3", + "sa", "se", "setf", "shl", "shladd", "shladdp4", "shr", "shrp", "sig", + "spill", "spnt", "sptk", "srlz", "ssm", "sss", "st1", "st2", "st4", "st8", + "stf", "stf8", "stfd", "stfe", "stfs", "sub", "sum", "sxt1", "sxt2", + "sxt4", "sync", "tak", "tbit", "thash", "tk", "tnat", "tpa", "trunc", + "ttag", "u", "unc", "unord", "unpack1", "unpack2", "unpack4", "uss", + "uus", "uuu", "w", "wexit", "wtop", "x", "xchg1", "xchg2", "xchg4", + "xchg8", "xf", "xma", "xmpy", "xor", "xuf", "z", "zxt1", "zxt2", "zxt4", +}; + +static const struct ia64_dependency +dependencies[] = { + { "ALAT", 0, 0, 0, -1, }, + { "AR[BSP]", 25, 0, 2, 17, }, + { "AR[BSPSTORE]", 25, 0, 2, 18, }, + { "AR[CCV]", 25, 0, 2, 32, }, + { "AR[EC]", 25, 0, 2, 66, }, + { "AR[FPSR].sf0.controls", 29, 0, 2, -1, }, + { "AR[FPSR].sf1.controls", 29, 0, 2, -1, }, + { "AR[FPSR].sf2.controls", 29, 0, 2, -1, }, + { "AR[FPSR].sf3.controls", 29, 0, 2, -1, }, + { "AR[FPSR].sf0.flags", 29, 0, 2, -1, }, + { "AR[FPSR].sf1.flags", 29, 0, 2, -1, }, + { "AR[FPSR].sf2.flags", 29, 0, 2, -1, }, + { "AR[FPSR].sf3.flags", 29, 0, 2, -1, }, + { "AR[FPSR].traps", 29, 0, 2, -1, }, + { "AR[FPSR].rv", 29, 0, 2, -1, }, + { "AR[ITC]", 25, 0, 2, 44, }, + { "AR[K%], % in 0 - 7", 1, 0, 2, -1, }, + { "AR[LC]", 25, 0, 2, 65, }, + { "AR[PFS]", 25, 0, 2, 64, }, + { "AR[PFS]", 25, 0, 2, 64, }, + { "AR[PFS]", 25, 0, 0, 64, }, + { "AR[RNAT]", 25, 0, 2, 19, }, + { "AR[RSC]", 25, 0, 2, 16, }, + { "AR[UNAT]{%}, % in 0 - 63", 2, 0, 2, -1, }, + { "AR%, % in 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111", 3, 0, 0, -1, }, + { "AR%, % in 48-63, 112-127", 4, 0, 2, -1, }, + { "BR%, % in 0 - 7", 5, 0, 2, -1, }, + { "BR%, % in 0 - 7", 5, 0, 0, -1, }, + { "BR%, % in 0 - 7", 5, 0, 2, -1, }, + { "CFM", 6, 0, 2, -1, }, + { "CFM", 6, 0, 2, -1, }, + { "CFM", 6, 0, 2, -1, }, + { "CFM", 6, 0, 2, -1, }, + { "CFM", 6, 0, 0, -1, }, + { "CPUID#", 7, 0, 5, -1, }, + { "CR[CMCV]", 26, 0, 3, 74, }, + { "CR[DCR]", 26, 0, 3, 0, }, + { "CR[EOI]", 26, 0, 6, 67, "SC Section 10.8.3.4", }, + { "CR[GPTA]", 26, 0, 3, 9, }, + { "CR[IFA]", 26, 0, 1, 20, }, + { "CR[IFA]", 26, 0, 3, 20, }, + { "CR[IFS]", 26, 0, 3, 23, }, + { "CR[IFS]", 26, 0, 1, 23, }, + { "CR[IFS]", 26, 0, 1, 23, }, + { "CR[IHA]", 26, 0, 3, 25, }, + { "CR[IIM]", 26, 0, 3, 24, }, + { "CR[IIP]", 26, 0, 3, 19, }, + { "CR[IIP]", 26, 0, 1, 19, }, + { "CR[IIPA]", 26, 0, 3, 22, }, + { "CR[IPSR]", 26, 0, 3, 16, }, + { "CR[IPSR]", 26, 0, 1, 16, }, + { "CR[IRR%], % in 0 - 3", 8, 0, 3, -1, }, + { "CR[ISR]", 26, 0, 3, 17, }, + { "CR[ITIR]", 26, 0, 3, 21, }, + { "CR[ITIR]", 26, 0, 1, 21, }, + { "CR[ITM]", 26, 0, 3, 1, }, + { "CR[ITV]", 26, 0, 3, 72, }, + { "CR[IVA]", 26, 0, 4, 2, }, + { "CR[IVR]", 26, 0, 6, 65, "SC Section 10.8.3.2", }, + { "CR[LID]", 26, 0, 6, 64, "SC Section 10.8.3.1", }, + { "CR[LRR%], % in 0 - 1", 9, 0, 3, -1, }, + { "CR[PMV]", 26, 0, 3, 73, }, + { "CR[PTA]", 26, 0, 3, 8, }, + { "CR[TPR]", 26, 0, 3, 66, }, + { "CR[TPR]", 26, 0, 6, 66, "SC Section 10.8.3.3", }, + { "CR%, % in 3-7, 10-15, 18, 26-63, 75-79, 82-127", 10, 0, 0, -1, }, + { "DBR#", 11, 0, 2, -1, }, + { "DBR#", 11, 0, 3, -1, }, + { "DTC", 0, 0, 3, -1, }, + { "DTC", 0, 0, 2, -1, }, + { "DTC", 0, 0, 0, -1, }, + { "DTC", 0, 0, 2, -1, }, + { "DTC_LIMIT*", 0, 0, 2, -1, }, + { "DTR", 0, 0, 3, -1, }, + { "DTR", 0, 0, 2, -1, }, + { "DTR", 0, 0, 3, -1, }, + { "DTR", 0, 0, 0, -1, }, + { "DTR", 0, 0, 2, -1, }, + { "FR%, % in 0 - 1", 12, 0, 0, -1, }, + { "FR%, % in 2 - 127", 13, 0, 2, -1, }, + { "FR%, % in 2 - 127", 13, 0, 0, -1, }, + { "GR0", 14, 0, 0, -1, }, + { "GR%, % in 1 - 127", 15, 0, 0, -1, }, + { "GR%, % in 1 - 127", 15, 0, 2, -1, }, + { "IBR#", 16, 0, 2, -1, }, + { "InService*", 17, 0, 3, -1, }, + { "InService*", 17, 0, 2, -1, }, + { "InService*", 17, 0, 2, -1, }, + { "IP", 0, 0, 0, -1, }, + { "ITC", 0, 0, 4, -1, }, + { "ITC", 0, 0, 2, -1, }, + { "ITC", 0, 0, 0, -1, }, + { "ITC", 0, 0, 4, -1, }, + { "ITC", 0, 0, 2, -1, }, + { "ITC_LIMIT*", 0, 0, 2, -1, }, + { "ITR", 0, 0, 2, -1, }, + { "ITR", 0, 0, 4, -1, }, + { "ITR", 0, 0, 2, -1, }, + { "ITR", 0, 0, 0, -1, }, + { "ITR", 0, 0, 4, -1, }, + { "memory", 0, 0, 0, -1, }, + { "MSR#", 18, 0, 5, -1, }, + { "PKR#", 19, 0, 3, -1, }, + { "PKR#", 19, 0, 0, -1, }, + { "PKR#", 19, 0, 2, -1, }, + { "PKR#", 19, 0, 2, -1, }, + { "PMC#", 20, 0, 2, -1, }, + { "PMC#", 20, 0, 6, -1, "SC+3 Section 12.1.1", }, + { "PMD#", 21, 0, 2, -1, }, + { "PR0", 0, 0, 0, -1, }, + { "PR%, % in 1 - 62", 22, 0, 2, -1, }, + { "PR%, % in 1 - 62", 22, 0, 2, -1, }, + { "PR%, % in 1 - 62", 22, 0, 0, -1, }, + { "PR63", 23, 0, 2, -1, }, + { "PR63", 23, 0, 2, -1, }, + { "PR63", 23, 0, 0, -1, }, + { "PSR.ac", 27, 0, 1, 3, }, + { "PSR.ac", 27, 0, 3, 3, }, + { "PSR.ac", 27, 0, 2, 3, }, + { "PSR.be", 27, 0, 1, 1, }, + { "PSR.be", 27, 0, 3, 1, }, + { "PSR.be", 27, 0, 2, 1, }, + { "PSR.bn", 27, 0, 2, 44, }, + { "PSR.cpl", 27, 0, 1, 32, }, + { "PSR.da", 27, 0, 3, 38, }, + { "PSR.db", 27, 0, 3, 24, }, + { "PSR.db", 27, 0, 2, 24, }, + { "PSR.db", 27, 0, 3, 24, }, + { "PSR.dd", 27, 0, 3, 39, }, + { "PSR.dfh", 27, 0, 3, 19, }, + { "PSR.dfh", 27, 0, 2, 19, }, + { "PSR.dfl", 27, 0, 3, 18, }, + { "PSR.dfl", 27, 0, 2, 18, }, + { "PSR.di", 27, 0, 3, 22, }, + { "PSR.di", 27, 0, 2, 22, }, + { "PSR.dt", 27, 0, 3, 17, }, + { "PSR.dt", 27, 0, 2, 17, }, + { "PSR.ed", 27, 0, 3, 43, }, + { "PSR.i", 27, 0, 2, 14, }, + { "PSR.i", 27, 0, 3, 14, }, + { "PSR.ia", 27, 0, 0, 14, }, + { "PSR.ic", 27, 0, 2, 13, }, + { "PSR.ic", 27, 0, 3, 13, }, + { "PSR.id", 27, 0, 0, 14, }, + { "PSR.is", 27, 0, 0, 14, }, + { "PSR.it", 27, 0, 3, 14, }, + { "PSR.lp", 27, 0, 2, 25, }, + { "PSR.lp", 27, 0, 3, 25, }, + { "PSR.lp", 27, 0, 3, 25, }, + { "PSR.mc", 27, 0, 0, 35, }, + { "PSR.mfh", 27, 0, 2, 5, }, + { "PSR.mfl", 27, 0, 2, 4, }, + { "PSR.pk", 27, 0, 3, 15, }, + { "PSR.pk", 27, 0, 2, 15, }, + { "PSR.pp", 27, 0, 2, 21, }, + { "PSR.ri", 27, 0, 0, 41, }, + { "PSR.rt", 27, 0, 2, 27, }, + { "PSR.rt", 27, 0, 3, 27, }, + { "PSR.rt", 27, 0, 3, 27, }, + { "PSR.si", 27, 0, 2, 23, }, + { "PSR.si", 27, 0, 3, 23, }, + { "PSR.sp", 27, 0, 2, 20, }, + { "PSR.sp", 27, 0, 3, 20, }, + { "PSR.ss", 27, 0, 3, 40, }, + { "PSR.tb", 27, 0, 3, 26, }, + { "PSR.tb", 27, 0, 2, 26, }, + { "PSR.up", 27, 0, 2, 2, }, + { "RR#", 24, 0, 3, -1, }, + { "RR#", 24, 0, 2, -1, }, + { "RSE", 28, 0, 2, -1, }, + { "ALAT", 0, 1, 0, -1, }, + { "AR[BSP]", 25, 1, 2, 17, }, + { "AR[BSPSTORE]", 25, 1, 2, 18, }, + { "AR[CCV]", 25, 1, 2, 32, }, + { "AR[EC]", 25, 1, 2, 66, }, + { "AR[FPSR].sf0.controls", 29, 1, 2, -1, }, + { "AR[FPSR].sf1.controls", 29, 1, 2, -1, }, + { "AR[FPSR].sf2.controls", 29, 1, 2, -1, }, + { "AR[FPSR].sf3.controls", 29, 1, 2, -1, }, + { "AR[FPSR].sf0.flags", 29, 1, 0, -1, }, + { "AR[FPSR].sf0.flags", 29, 1, 2, -1, }, + { "AR[FPSR].sf0.flags", 29, 1, 2, -1, }, + { "AR[FPSR].sf1.flags", 29, 1, 0, -1, }, + { "AR[FPSR].sf1.flags", 29, 1, 2, -1, }, + { "AR[FPSR].sf1.flags", 29, 1, 2, -1, }, + { "AR[FPSR].sf2.flags", 29, 1, 0, -1, }, + { "AR[FPSR].sf2.flags", 29, 1, 2, -1, }, + { "AR[FPSR].sf2.flags", 29, 1, 2, -1, }, + { "AR[FPSR].sf3.flags", 29, 1, 0, -1, }, + { "AR[FPSR].sf3.flags", 29, 1, 2, -1, }, + { "AR[FPSR].sf3.flags", 29, 1, 2, -1, }, + { "AR[FPSR].rv", 29, 1, 2, -1, }, + { "AR[FPSR].traps", 29, 1, 2, -1, }, + { "AR[ITC]", 25, 1, 2, 44, }, + { "AR[K%], % in 0 - 7", 1, 1, 2, -1, }, + { "AR[LC]", 25, 1, 2, 65, }, + { "AR[PFS]", 25, 1, 0, 64, }, + { "AR[PFS]", 25, 1, 2, 64, }, + { "AR[PFS]", 25, 1, 2, 64, }, + { "AR[RNAT]", 25, 1, 2, 19, }, + { "AR[RSC]", 25, 1, 2, 16, }, + { "AR[UNAT]{%}, % in 0 - 63", 2, 1, 2, -1, }, + { "AR%, % in 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111", 3, 1, 0, -1, }, + { "AR%, % in 48 - 63, 112-127", 4, 1, 2, -1, }, + { "BR%, % in 0 - 7", 5, 1, 2, -1, }, + { "BR%, % in 0 - 7", 5, 1, 2, -1, }, + { "BR%, % in 0 - 7", 5, 1, 2, -1, }, + { "BR%, % in 0 - 7", 5, 1, 0, -1, }, + { "CFM", 6, 1, 2, -1, }, + { "CPUID#", 7, 1, 0, -1, }, + { "CR[CMCV]", 26, 1, 2, 74, }, + { "CR[DCR]", 26, 1, 2, 0, }, + { "CR[EOI]", 26, 1, 6, 67, "SC Section 10.8.3.4", }, + { "CR[GPTA]", 26, 1, 2, 9, }, + { "CR[IFA]", 26, 1, 2, 20, }, + { "CR[IFS]", 26, 1, 2, 23, }, + { "CR[IHA]", 26, 1, 2, 25, }, + { "CR[IIM]", 26, 1, 2, 24, }, + { "CR[IIP]", 26, 1, 2, 19, }, + { "CR[IIPA]", 26, 1, 2, 22, }, + { "CR[IPSR]", 26, 1, 2, 16, }, + { "CR[IRR%], % in 0 - 3", 8, 1, 2, -1, }, + { "CR[ISR]", 26, 1, 2, 17, }, + { "CR[ITIR]", 26, 1, 2, 21, }, + { "CR[ITM]", 26, 1, 2, 1, }, + { "CR[ITV]", 26, 1, 2, 72, }, + { "CR[IVA]", 26, 1, 2, 2, }, + { "CR[IVR]", 26, 1, 6, 65, "SC", }, + { "CR[LID]", 26, 1, 6, 64, "SC", }, + { "CR[LRR%], % in 0 - 1", 9, 1, 2, -1, }, + { "CR[PMV]", 26, 1, 2, 73, }, + { "CR[PTA]", 26, 1, 2, 8, }, + { "CR[TPR]", 26, 1, 2, 66, }, + { "CR%, % in 3-7, 10-15, 18, 26-63, 75-79, 82-127", 10, 1, 0, -1, }, + { "DBR#", 11, 1, 2, -1, }, + { "DTC", 0, 1, 0, -1, }, + { "DTC", 0, 1, 2, -1, }, + { "DTC", 0, 1, 2, -1, }, + { "DTC_LIMIT*", 0, 1, 2, -1, }, + { "DTR", 0, 1, 2, -1, }, + { "DTR", 0, 1, 2, -1, }, + { "DTR", 0, 1, 2, -1, }, + { "DTR", 0, 1, 0, -1, }, + { "FR%, % in 0 - 1", 12, 1, 0, -1, }, + { "FR%, % in 2 - 127", 13, 1, 2, -1, }, + { "GR0", 14, 1, 0, -1, }, + { "GR%, % in 1 - 127", 15, 1, 2, -1, }, + { "IBR#", 16, 1, 2, -1, }, + { "InService*", 17, 1, 6, -1, "SC", }, + { "IP", 0, 1, 0, -1, }, + { "ITC", 0, 1, 0, -1, }, + { "ITC", 0, 1, 2, -1, }, + { "ITC", 0, 1, 2, -1, }, + { "ITR", 0, 1, 2, -1, }, + { "ITR", 0, 1, 2, -1, }, + { "ITR", 0, 1, 0, -1, }, + { "memory", 0, 1, 0, -1, }, + { "MSR#", 18, 1, 6, -1, "SC", }, + { "PKR#", 19, 1, 0, -1, }, + { "PKR#", 19, 1, 0, -1, }, + { "PKR#", 19, 1, 2, -1, }, + { "PMC#", 20, 1, 2, -1, }, + { "PMD#", 21, 1, 2, -1, }, + { "PR0", 0, 1, 0, -1, }, + { "PR%, % in 1 - 62", 22, 1, 0, -1, }, + { "PR%, % in 1 - 62", 22, 1, 0, -1, }, + { "PR%, % in 1 - 62", 22, 1, 2, -1, }, + { "PR%, % in 1 - 62", 22, 1, 2, -1, }, + { "PR63", 23, 1, 0, -1, }, + { "PR63", 23, 1, 0, -1, }, + { "PR63", 23, 1, 2, -1, }, + { "PR63", 23, 1, 2, -1, }, + { "PSR.ac", 27, 1, 2, 3, }, + { "PSR.be", 27, 1, 2, 1, }, + { "PSR.bn", 27, 1, 2, 44, }, + { "PSR.cpl", 27, 1, 2, 32, }, + { "PSR.da", 27, 1, 2, 38, }, + { "PSR.db", 27, 1, 2, 24, }, + { "PSR.dd", 27, 1, 2, 39, }, + { "PSR.dfh", 27, 1, 2, 19, }, + { "PSR.dfl", 27, 1, 2, 18, }, + { "PSR.di", 27, 1, 2, 22, }, + { "PSR.dt", 27, 1, 2, 17, }, + { "PSR.ed", 27, 1, 2, 43, }, + { "PSR.i", 27, 1, 2, 14, }, + { "PSR.ia", 27, 1, 2, 14, }, + { "PSR.ic", 27, 1, 2, 13, }, + { "PSR.id", 27, 1, 2, 14, }, + { "PSR.is", 27, 1, 2, 14, }, + { "PSR.it", 27, 1, 2, 14, }, + { "PSR.lp", 27, 1, 2, 25, }, + { "PSR.mc", 27, 1, 2, 35, }, + { "PSR.mfh", 27, 1, 0, 5, }, + { "PSR.mfh", 27, 1, 2, 5, }, + { "PSR.mfh", 27, 1, 2, 5, }, + { "PSR.mfl", 27, 1, 0, 4, }, + { "PSR.mfl", 27, 1, 2, 4, }, + { "PSR.mfl", 27, 1, 2, 4, }, + { "PSR.pk", 27, 1, 2, 15, }, + { "PSR.pp", 27, 1, 2, 21, }, + { "PSR.ri", 27, 1, 2, 41, }, + { "PSR.rt", 27, 1, 2, 27, }, + { "PSR.si", 27, 1, 2, 23, }, + { "PSR.sp", 27, 1, 2, 20, }, + { "PSR.ss", 27, 1, 2, 40, }, + { "PSR.tb", 27, 1, 2, 26, }, + { "PSR.up", 27, 1, 2, 2, }, + { "RR#", 24, 1, 2, -1, }, + { "RSE", 28, 1, 2, -1, }, + { "PR63", 23, 2, 2, -1, }, +}; + +static const short dep0[] = { + 88, 249, 2131, 2294, +}; + +static const short dep1[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, 20602, + +}; + +static const short dep2[] = { + 2131, 2294, +}; + +static const short dep3[] = { + 32, 33, 2129, 2130, 2131, 2294, 4127, 20602, +}; + +static const short dep4[] = { + 32, 33, 81, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 20602, +}; + +static const short dep5[] = { + 88, 249, 2157, 2158, 2160, 2161, 2163, 2311, 2314, 2315, 2318, 2319, +}; + +static const short dep6[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2311, 2314, 2315, + 2318, 2319, 4127, 20602, +}; + +static const short dep7[] = { + 88, 249, 22637, 22638, 22640, 22641, 22643, 22791, 22794, 22795, 22798, 22799, + +}; + +static const short dep8[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, 22791, + 22794, 22795, 22798, 22799, +}; + +static const short dep9[] = { + 88, 249, 2312, 2314, 2316, 2318, +}; + +static const short dep10[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2312, 2315, 2316, + 2319, 4127, 20602, +}; + +static const short dep11[] = { + 88, 249, 2313, 2315, 2317, 2319, +}; + +static const short dep12[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2313, 2314, 2317, + 2318, 4127, 20602, +}; + +static const short dep13[] = { + 88, 249, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319, +}; + +static const short dep14[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2312, 2313, 2314, + 2315, 2316, 2317, 2318, 2319, 4127, 20602, +}; + +static const short dep15[] = { + 88, 249, 2357, +}; + +static const short dep16[] = { + 32, 33, 88, 145, 163, 164, 249, 2074, 2075, 2157, 2159, 2160, 2162, 2163, + 4127, +}; + +static const short dep17[] = { + 88, 144, 249, 288, 2357, 28841, 28980, +}; + +static const short dep18[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, + 23, 24, 25, 32, 33, 88, 133, 145, 163, 164, 249, 288, 2074, 2075, 2157, 2159, + 2160, 2162, 2163, 4127, 28841, 28980, +}; + +static const short dep19[] = { + 1, 4, 32, 88, 123, 171, 174, 208, 249, 275, 2357, 28841, 28980, +}; + +static const short dep20[] = { + 1, 18, 20, 30, 32, 33, 88, 145, 147, 148, 163, 164, 171, 174, 208, 249, 275, + 2074, 2075, 2157, 2159, 2160, 2162, 2163, 4127, 28841, 28980, +}; + +static const short dep21[] = { + 1, 32, 43, 88, 171, 208, 215, 249, 28841, 28980, +}; + +static const short dep22[] = { + 1, 30, 32, 33, 88, 142, 163, 171, 208, 215, 249, 4127, 28841, 28980, +}; + +static const short dep23[] = { + 32, 88, 208, 249, +}; + +static const short dep24[] = { + 88, 163, 208, 249, +}; + +static const short dep25[] = { + 1, 32, 88, 117, 118, 120, 121, 122, 123, 124, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 148, 149, 150, + 151, 152, 153, 154, 155, 158, 159, 160, 161, 162, 163, 164, 165, 166, 171, + 208, 249, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 293, 294, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 28841, 28980, +}; + +static const short dep26[] = { + 1, 30, 32, 33, 42, 43, 47, 50, 64, 88, 123, 163, 171, 208, 249, 272, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 293, 294, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 4127, 28841, 28980, +}; + +static const short dep27[] = { + 88, 122, 249, 274, +}; + +static const short dep28[] = { + 88, 123, 163, 249, 274, +}; + +static const short dep29[] = { + 88, 123, 249, 275, +}; + +static const short dep30[] = { + 18, 19, 88, 89, 92, 96, 99, 123, 145, 163, 249, 275, +}; + +static const short dep31[] = { + 32, 33, 88, 163, 249, 2157, 2159, 2160, 2162, 2163, 4127, +}; + +static const short dep32[] = { + 1, 18, 32, 88, 171, 196, 197, 208, 249, 2074, 2252, 2255, 2357, 28841, 28980, + +}; + +static const short dep33[] = { + 1, 4, 30, 32, 33, 88, 123, 145, 163, 164, 171, 196, 198, 208, 249, 2074, 2075, + 2157, 2159, 2160, 2162, 2163, 2253, 2255, 4127, 28841, 28980, +}; + +static const short dep34[] = { + 88, 249, +}; + +static const short dep35[] = { + 88, 163, 249, 2074, 2076, +}; + +static const short dep36[] = { + 32, 33, 88, 145, 163, 164, 249, 2157, 2159, 2160, 2162, 2163, 4127, +}; + +static const short dep37[] = { + 4, 29, 30, 31, 88, 113, 114, 174, 208, 249, 270, 271, 2357, +}; + +static const short dep38[] = { + 4, 29, 32, 33, 88, 145, 163, 164, 174, 208, 249, 270, 271, 309, 2157, 2159, + 2160, 2162, 2163, 4127, +}; + +static const short dep39[] = { + 17, 88, 195, 249, 2357, +}; + +static const short dep40[] = { + 17, 32, 33, 88, 145, 163, 164, 195, 249, 2157, 2159, 2160, 2162, 2163, 4127, + +}; + +static const short dep41[] = { + 4, 17, 29, 30, 31, 88, 113, 114, 174, 195, 208, 249, 270, 271, 2357, +}; + +static const short dep42[] = { + 4, 17, 29, 32, 33, 88, 145, 163, 164, 174, 195, 208, 249, 270, 271, 309, 2157, + 2159, 2160, 2162, 2163, 4127, +}; + +static const short dep43[] = { + 1, 4, 30, 32, 33, 88, 123, 145, 163, 164, 171, 196, 198, 208, 249, 2157, 2159, + 2160, 2162, 2163, 2253, 2255, 4127, 28841, 28980, +}; + +static const short dep44[] = { + 88, 163, 249, +}; + +static const short dep45[] = { + 9, 88, 179, 180, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep46[] = { + 5, 13, 14, 32, 33, 88, 163, 179, 181, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep47[] = { + 9, 10, 11, 12, 88, 179, 180, 182, 183, 185, 186, 188, 189, 249, 2127, 2292, + 18582, 18583, 18724, 18725, 18727, 18728, 22637, 22638, 22639, 22641, 22642, + 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep48[] = { + 5, 6, 7, 8, 13, 14, 32, 33, 88, 163, 179, 181, 182, 184, 185, 187, 188, 190, + 249, 2126, 2127, 2128, 2157, 2158, 2161, 2292, 4127, 16513, 16515, 18724, + 18726, 18727, 18729, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep49[] = { + 10, 88, 182, 183, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep50[] = { + 6, 13, 14, 32, 33, 88, 163, 182, 184, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep51[] = { + 11, 88, 185, 186, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep52[] = { + 7, 13, 14, 32, 33, 88, 163, 185, 187, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep53[] = { + 12, 88, 188, 189, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep54[] = { + 8, 13, 14, 32, 33, 88, 163, 188, 190, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep55[] = { + 9, 88, 179, 180, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + +}; + +static const short dep56[] = { + 5, 13, 14, 32, 33, 88, 163, 179, 181, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, +}; + +static const short dep57[] = { + 9, 10, 11, 12, 88, 179, 180, 182, 183, 185, 186, 188, 189, 249, 2127, 2292, + 18582, 18583, 18724, 18725, 18727, 18728, +}; + +static const short dep58[] = { + 5, 6, 7, 8, 13, 14, 32, 33, 88, 163, 179, 181, 182, 184, 185, 187, 188, 190, + 249, 2126, 2127, 2128, 2157, 2158, 2161, 2292, 4127, 16513, 16515, 18724, + 18726, 18727, 18729, +}; + +static const short dep59[] = { + 10, 88, 182, 183, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + +}; + +static const short dep60[] = { + 6, 13, 14, 32, 33, 88, 163, 182, 184, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, +}; + +static const short dep61[] = { + 11, 88, 185, 186, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + +}; + +static const short dep62[] = { + 7, 13, 14, 32, 33, 88, 163, 185, 187, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, +}; + +static const short dep63[] = { + 12, 88, 188, 189, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, + +}; + +static const short dep64[] = { + 8, 13, 14, 32, 33, 88, 163, 188, 190, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, +}; + +static const short dep65[] = { + 88, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, +}; + +static const short dep66[] = { + 32, 33, 88, 163, 249, 2126, 2127, 2128, 2157, 2158, 2161, 2292, 4127, 16513, + 16515, 18724, 18726, 18727, 18729, +}; + +static const short dep67[] = { + 5, 88, 175, 249, +}; + +static const short dep68[] = { + 5, 32, 33, 88, 163, 175, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep69[] = { + 5, 32, 33, 88, 163, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep70[] = { + 6, 88, 176, 249, +}; + +static const short dep71[] = { + 5, 32, 33, 88, 163, 176, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep72[] = { + 7, 88, 177, 249, +}; + +static const short dep73[] = { + 5, 32, 33, 88, 163, 177, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep74[] = { + 8, 88, 178, 249, +}; + +static const short dep75[] = { + 5, 32, 33, 88, 163, 178, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep76[] = { + 9, 88, 180, 181, 249, +}; + +static const short dep77[] = { + 32, 33, 88, 163, 180, 181, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep78[] = { + 32, 33, 88, 163, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep79[] = { + 10, 88, 183, 184, 249, +}; + +static const short dep80[] = { + 32, 33, 88, 163, 183, 184, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep81[] = { + 11, 88, 186, 187, 249, +}; + +static const short dep82[] = { + 32, 33, 88, 163, 186, 187, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep83[] = { + 12, 88, 189, 190, 249, +}; + +static const short dep84[] = { + 32, 33, 88, 163, 189, 190, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep85[] = { + 9, 13, 14, 32, 33, 88, 145, 163, 164, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep86[] = { + 9, 10, 13, 14, 32, 33, 88, 145, 163, 164, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep87[] = { + 9, 11, 13, 14, 32, 33, 88, 145, 163, 164, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep88[] = { + 9, 12, 13, 14, 32, 33, 88, 145, 163, 164, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep89[] = { + 9, 88, 179, 180, 249, +}; + +static const short dep90[] = { + 5, 13, 14, 32, 33, 88, 163, 179, 181, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep91[] = { + 9, 10, 11, 12, 88, 179, 180, 182, 183, 185, 186, 188, 189, 249, +}; + +static const short dep92[] = { + 5, 6, 7, 8, 13, 14, 32, 33, 88, 163, 179, 181, 182, 184, 185, 187, 188, 190, + 249, 2157, 2158, 2161, 4127, +}; + +static const short dep93[] = { + 10, 88, 182, 183, 249, +}; + +static const short dep94[] = { + 6, 13, 14, 32, 33, 88, 163, 182, 184, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep95[] = { + 11, 88, 185, 186, 249, +}; + +static const short dep96[] = { + 7, 13, 14, 32, 33, 88, 163, 185, 187, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep97[] = { + 12, 88, 188, 189, 249, +}; + +static const short dep98[] = { + 8, 13, 14, 32, 33, 88, 163, 188, 190, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep99[] = { + 9, 88, 179, 180, 249, 2157, 2158, 2159, 2161, 2162, 2311, 2314, 2315, 2318, + 2319, +}; + +static const short dep100[] = { + 5, 13, 14, 32, 33, 88, 163, 179, 181, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2311, 2314, 2315, 2318, 2319, 4127, 16513, 16515, +}; + +static const short dep101[] = { + 9, 10, 11, 12, 88, 179, 180, 182, 183, 185, 186, 188, 189, 249, 2157, 2158, + 2159, 2161, 2162, 2311, 2314, 2315, 2318, 2319, +}; + +static const short dep102[] = { + 5, 6, 7, 8, 13, 14, 32, 33, 88, 163, 179, 181, 182, 184, 185, 187, 188, 190, + 249, 2126, 2127, 2128, 2157, 2158, 2161, 2311, 2314, 2315, 2318, 2319, 4127, + 16513, 16515, +}; + +static const short dep103[] = { + 10, 88, 182, 183, 249, 2157, 2158, 2159, 2161, 2162, 2311, 2314, 2315, 2318, + 2319, +}; + +static const short dep104[] = { + 6, 13, 14, 32, 33, 88, 163, 182, 184, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2311, 2314, 2315, 2318, 2319, 4127, 16513, 16515, +}; + +static const short dep105[] = { + 11, 88, 185, 186, 249, 2157, 2158, 2159, 2161, 2162, 2311, 2314, 2315, 2318, + 2319, +}; + +static const short dep106[] = { + 7, 13, 14, 32, 33, 88, 163, 185, 187, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2311, 2314, 2315, 2318, 2319, 4127, 16513, 16515, +}; + +static const short dep107[] = { + 12, 88, 188, 189, 249, 2157, 2158, 2159, 2161, 2162, 2311, 2314, 2315, 2318, + 2319, +}; + +static const short dep108[] = { + 8, 13, 14, 32, 33, 88, 163, 188, 190, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 2311, 2314, 2315, 2318, 2319, 4127, 16513, 16515, +}; + +static const short dep109[] = { + 9, 88, 179, 180, 249, 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep110[] = { + 5, 13, 14, 32, 33, 88, 163, 179, 181, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 4127, 16513, 16515, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep111[] = { + 9, 10, 11, 12, 88, 179, 180, 182, 183, 185, 186, 188, 189, 249, 22637, 22638, + 22639, 22641, 22642, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep112[] = { + 5, 6, 7, 8, 13, 14, 32, 33, 88, 163, 179, 181, 182, 184, 185, 187, 188, 190, + 249, 2126, 2127, 2128, 2157, 2158, 2161, 4127, 16513, 16515, 22791, 22794, + 22795, 22798, 22799, +}; + +static const short dep113[] = { + 10, 88, 182, 183, 249, 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep114[] = { + 6, 13, 14, 32, 33, 88, 163, 182, 184, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 4127, 16513, 16515, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep115[] = { + 11, 88, 185, 186, 249, 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep116[] = { + 7, 13, 14, 32, 33, 88, 163, 185, 187, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 4127, 16513, 16515, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep117[] = { + 12, 88, 188, 189, 249, 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, + 22798, 22799, +}; + +static const short dep118[] = { + 8, 13, 14, 32, 33, 88, 163, 188, 190, 249, 2126, 2127, 2128, 2157, 2158, 2161, + 4127, 16513, 16515, 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep119[] = { + 88, 249, 2157, 2158, 2159, 2161, 2162, 2311, 2314, 2315, 2318, 2319, +}; + +static const short dep120[] = { + 32, 33, 88, 163, 249, 2126, 2127, 2128, 2157, 2158, 2161, 2311, 2314, 2315, + 2318, 2319, 4127, 16513, 16515, +}; + +static const short dep121[] = { + 88, 249, 22637, 22638, 22639, 22641, 22642, 22791, 22794, 22795, 22798, 22799, + +}; + +static const short dep122[] = { + 32, 33, 88, 163, 249, 2126, 2127, 2128, 2157, 2158, 2161, 4127, 16513, 16515, + 22791, 22794, 22795, 22798, 22799, +}; + +static const short dep123[] = { + 13, 14, 32, 33, 88, 163, 249, 2126, 2127, 2128, 2157, 2158, 2161, 2292, 4127, + 16513, 16515, 18724, 18726, 18727, 18729, +}; + +static const short dep124[] = { + 32, 33, 88, 145, 163, 164, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, + 20602, +}; + +static const short dep125[] = { + 88, 249, 2075, 2076, 2253, 2254, +}; + +static const short dep126[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2252, 2254, 4127, + 20602, +}; + +static const short dep127[] = { + 32, 33, 88, 163, 249, 2074, 2076, 2157, 2158, 2161, 2294, 4127, 20602, +}; + +static const short dep128[] = { + 88, 249, 14446, 14448, 14449, 14451, 14602, 14603, 14606, 14607, +}; + +static const short dep129[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 4127, 14602, 14603, 14606, 14607, + 20602, 24685, 24686, 24689, +}; + +static const short dep130[] = { + 88, 110, 112, 113, 115, 249, 14602, 14603, 14606, 14607, +}; + +static const short dep131[] = { + 32, 33, 88, 163, 249, 4127, 14602, 14603, 14606, 14607, 24685, 24686, 24689, + +}; + +static const short dep132[] = { + 32, 33, 88, 163, 249, 2157, 2158, 2161, 2294, 4127, 20602, +}; + +static const short dep133[] = { + 32, 33, 88, 110, 113, 163, 249, 2294, 4127, 20602, 24685, +}; + +static const short dep134[] = { + 4, 17, 19, 20, 88, 174, 195, 198, 249, 2073, 2251, +}; + +static const short dep135[] = { + 32, 33, 88, 163, 174, 195, 197, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2251, + 4127, 20602, +}; + +static const short dep136[] = { + 4, 17, 18, 19, 32, 33, 88, 163, 249, 2073, 2157, 2158, 2161, 2294, 4127, 20602, + +}; + +static const short dep137[] = { + 0, 32, 33, 88, 145, 163, 164, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep138[] = { + 0, 88, 170, 249, +}; + +static const short dep139[] = { + 0, 32, 33, 88, 145, 163, 164, 170, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep140[] = { + 32, 33, 88, 163, 170, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep141[] = { + 2, 21, 88, 172, 199, 249, 28841, 28980, +}; + +static const short dep142[] = { + 1, 2, 21, 22, 88, 157, 158, 163, 172, 199, 249, 28841, 28980, +}; + +static const short dep143[] = { + 1, 21, 22, 30, 32, 33, 88, 157, 158, 163, 172, 199, 249, 4127, 28841, 28980, + +}; + +static const short dep144[] = { + 0, 32, 33, 88, 163, 170, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep145[] = { + 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 21, 22, 23, 88, 171, 172, + 173, 175, 176, 177, 178, 180, 181, 183, 184, 186, 187, 189, 190, 191, 192, + 193, 199, 200, 201, 249, 2064, 2073, 2242, 2251, 28841, 28980, +}; + +static const short dep146[] = { + 22, 32, 33, 88, 123, 163, 171, 172, 173, 175, 176, 177, 178, 180, 181, 183, + 184, 186, 187, 189, 190, 191, 192, 193, 199, 200, 201, 249, 2129, 2130, 2131, + 2157, 2158, 2161, 2242, 2251, 4127, 20602, 28841, 28980, +}; + +static const short dep147[] = { + 88, 249, 14452, 14454, 14455, 14457, 14486, 14487, 14502, 14608, 14609, 14629, + 14630, 14632, 14633, 14642, +}; + +static const short dep148[] = { + 32, 33, 88, 162, 163, 249, 2157, 2158, 2161, 4127, 14608, 14609, 14629, 14630, + 14632, 14633, 14642, +}; + +static const short dep149[] = { + 14452, 14454, 14455, 14457, 14486, 14487, 14502, 14608, 14609, 14629, 14630, + 14632, 14633, 14642, +}; + +static const short dep150[] = { + 162, 14608, 14609, 14629, 14630, 14632, 14633, 14642, +}; + +static const short dep151[] = { + 88, 249, 14453, 14454, 14456, 14457, 14465, 14466, 14467, 14468, 14469, 14470, + 14471, 14472, 14474, 14477, 14478, 14486, 14487, 14488, 14489, 14490, 14495, + 14496, 14497, 14498, 14502, 14608, 14609, 14615, 14616, 14617, 14618, 14620, + 14622, 14629, 14630, 14632, 14633, 14634, 14635, 14638, 14639, 14642, +}; + +static const short dep152[] = { + 32, 33, 64, 88, 123, 163, 249, 2157, 2158, 2161, 4127, 14608, 14609, 14615, + 14616, 14617, 14618, 14620, 14622, 14629, 14630, 14632, 14633, 14634, 14635, + 14638, 14639, 14642, +}; + +static const short dep153[] = { + 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 21, 22, 23, 32, 33, 88, 123, + 160, 163, 249, 2064, 2073, 2157, 2158, 2161, 2294, 4127, 20602, 28841, +}; + +static const short dep154[] = { + 35, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, + 56, 57, 59, 61, 62, 63, 64, 85, 87, 88, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 222, 223, 224, 225, 226, 228, 230, 231, 232, 248, 249, + 2108, 2277, +}; + +static const short dep155[] = { + 32, 33, 87, 88, 123, 142, 163, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 222, 223, 224, 225, 226, 228, 230, 231, 232, 248, 249, 2129, 2130, + 2131, 2157, 2158, 2161, 2277, 4127, 20602, +}; + +static const short dep156[] = { + 51, 86, 88, 221, 248, 249, 2131, 2294, +}; + +static const short dep157[] = { + 32, 33, 35, 36, 38, 40, 41, 43, 44, 45, 46, 48, 49, 52, 53, 55, 56, 57, 58, + 59, 61, 62, 63, 85, 86, 88, 123, 142, 163, 221, 248, 249, 2099, 2108, 2157, + 2158, 2161, 2294, 4127, 20602, +}; + +static const short dep158[] = { + 2, 21, 33, 88, 172, 199, 208, 249, 2131, 2294, 28841, 28980, +}; + +static const short dep159[] = { + 2, 18, 19, 21, 22, 30, 32, 33, 88, 157, 158, 163, 172, 199, 208, 249, 2294, + 4127, 20602, 28841, 28980, +}; + +static const short dep160[] = { + 88, 117, 118, 120, 121, 125, 126, 129, 130, 131, 132, 133, 134, 135, 136, + 138, 141, 142, 146, 147, 150, 151, 152, 153, 154, 156, 157, 159, 160, 161, + 162, 164, 165, 166, 249, 272, 273, 277, 279, 280, 281, 282, 284, 286, 290, + 293, 294, 296, 297, 298, 299, 301, 302, 303, 305, 306, +}; + +static const short dep161[] = { + 32, 33, 64, 88, 123, 163, 249, 272, 273, 277, 279, 280, 281, 282, 284, 286, + 290, 293, 294, 296, 297, 298, 299, 301, 302, 303, 305, 306, 2129, 2130, 2131, + 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep162[] = { + 88, 116, 118, 119, 121, 150, 151, 166, 249, 272, 273, 293, 294, 296, 297, + 306, +}; + +static const short dep163[] = { + 32, 33, 88, 162, 163, 249, 272, 273, 293, 294, 296, 297, 306, 2129, 2130, + 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep164[] = { + 32, 33, 88, 118, 121, 123, 126, 127, 130, 132, 134, 136, 138, 139, 141, 145, + 146, 148, 149, 150, 151, 153, 154, 156, 158, 159, 161, 163, 165, 166, 249, + 2157, 2158, 2161, 2294, 4127, 20602, +}; + +static const short dep165[] = { + 32, 33, 88, 118, 121, 150, 151, 163, 166, 249, 2157, 2158, 2161, 2294, 4127, + 20602, +}; + +static const short dep166[] = { + 32, 33, 67, 68, 73, 75, 88, 102, 123, 152, 163, 167, 249, 2129, 2130, 2131, + 2157, 2158, 2161, 2294, 4127, 20602, +}; + +static const short dep167[] = { + 32, 33, 67, 68, 73, 75, 88, 102, 123, 124, 125, 127, 128, 152, 163, 167, 249, + 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep168[] = { + 68, 69, 88, 92, 93, 236, 237, 249, 251, 252, +}; + +static const short dep169[] = { + 32, 33, 39, 54, 69, 71, 77, 88, 90, 93, 123, 142, 163, 167, 236, 237, 249, + 251, 252, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep170[] = { + 32, 33, 39, 54, 69, 71, 88, 90, 93, 95, 97, 123, 142, 163, 167, 236, 237, + 249, 251, 252, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep171[] = { + 88, 249, 12455, 12456, 12595, +}; + +static const short dep172[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 12595, + 20602, +}; + +static const short dep173[] = { + 88, 249, 6210, 6211, 6378, +}; + +static const short dep174[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 6378, + 20602, +}; + +static const short dep175[] = { + 88, 249, 6228, 6391, +}; + +static const short dep176[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 6391, + 20602, +}; + +static const short dep177[] = { + 88, 249, 6246, 6247, 6248, 6249, 6402, 6404, 8451, +}; + +static const short dep178[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 6249, + 6403, 6404, 8295, 8450, 20602, +}; + +static const short dep179[] = { + 88, 249, 6250, 6251, 6405, +}; + +static const short dep180[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 6405, + 20602, +}; + +static const short dep181[] = { + 88, 249, 6252, 6406, +}; + +static const short dep182[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 6406, + 20602, +}; + +static const short dep183[] = { + 88, 249, 10341, 10497, +}; + +static const short dep184[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 10497, + 20602, +}; + +static const short dep185[] = { + 68, 69, 73, 74, 88, 92, 93, 236, 237, 239, 240, 249, 251, 252, +}; + +static const short dep186[] = { + 32, 33, 39, 69, 71, 74, 77, 88, 90, 93, 123, 142, 163, 167, 236, 237, 239, + 241, 249, 251, 252, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep187[] = { + 68, 69, 88, 92, 93, 95, 96, 236, 237, 249, 251, 252, 253, 254, +}; + +static const short dep188[] = { + 32, 33, 39, 54, 69, 71, 88, 90, 93, 95, 97, 123, 142, 163, 167, 236, 237, + 249, 251, 252, 253, 254, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, + +}; + +static const short dep189[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 12456, 20602, +}; + +static const short dep190[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 6210, 20602, +}; + +static const short dep191[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 6228, 20602, +}; + +static const short dep192[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 6248, 8294, 20602, +}; + +static const short dep193[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 6250, 20602, +}; + +static const short dep194[] = { + 32, 33, 88, 123, 162, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, + 4127, 6251, 6252, 20602, +}; + +static const short dep195[] = { + 32, 33, 88, 123, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 10341, 20602, +}; + +static const short dep196[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, 6178, + 20602, +}; + +static const short dep197[] = { + 68, 70, 71, 88, 89, 90, 91, 235, 236, 249, 250, 251, +}; + +static const short dep198[] = { + 32, 33, 69, 70, 74, 76, 88, 91, 93, 95, 98, 123, 163, 167, 235, 237, 249, + 250, 252, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep199[] = { + 68, 70, 71, 72, 88, 89, 90, 91, 94, 235, 236, 238, 249, 250, 251, +}; + +static const short dep200[] = { + 32, 33, 69, 70, 72, 74, 76, 88, 91, 93, 94, 95, 98, 123, 163, 167, 235, 237, + 238, 249, 250, 252, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep201[] = { + 68, 70, 71, 75, 76, 77, 88, 89, 90, 91, 235, 236, 241, 242, 249, 250, 251, + +}; + +static const short dep202[] = { + 32, 33, 69, 70, 74, 76, 88, 91, 93, 123, 163, 167, 235, 237, 240, 242, 249, + 250, 252, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep203[] = { + 68, 70, 71, 88, 89, 90, 91, 97, 98, 99, 235, 236, 249, 250, 251, 254, 255, + +}; + +static const short dep204[] = { + 32, 33, 69, 70, 88, 91, 93, 95, 98, 123, 163, 167, 235, 237, 249, 250, 252, + 253, 255, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep205[] = { + 32, 33, 38, 62, 88, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, + 4127, 20602, +}; + +static const short dep206[] = { + 32, 33, 88, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 20602, +}; + +static const short dep207[] = { + 32, 33, 68, 73, 75, 88, 123, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, + 2161, 2294, 4127, 20602, +}; + +static const short dep208[] = { + 32, 33, 88, 145, 163, 164, 249, 2126, 2127, 2128, 2129, 2130, 2131, 2157, + 2158, 2161, 4127, 16513, 16515, 20602, +}; + +static const short dep209[] = { + 32, 33, 68, 73, 75, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, + 20602, +}; + +static const short dep210[] = { + 32, 33, 69, 70, 88, 91, 123, 163, 235, 237, 249, 250, 252, 2129, 2130, 2131, + 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep211[] = { + 32, 33, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, 127, + 128, 135, 152, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, 4127, + 20602, +}; + +static const short dep212[] = { + 32, 33, 36, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, + 127, 128, 135, 137, 152, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, 2161, + 2294, 4127, 20602, +}; + +static const short dep213[] = { + 0, 88, 170, 249, 2131, 2294, +}; + +static const short dep214[] = { + 0, 32, 33, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, + 127, 128, 135, 152, 163, 167, 170, 249, 2129, 2130, 2131, 2157, 2158, 2161, + 2294, 4127, 20602, +}; + +static const short dep215[] = { + 0, 32, 33, 36, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, + 125, 127, 128, 135, 137, 152, 163, 167, 170, 249, 2129, 2130, 2131, 2157, + 2158, 2161, 2294, 4127, 20602, +}; + +static const short dep216[] = { + 23, 32, 33, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, + 127, 128, 135, 152, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, + 4127, 20602, +}; + +static const short dep217[] = { + 0, 88, 170, 249, 2294, 26706, +}; + +static const short dep218[] = { + 0, 88, 100, 170, 249, 256, +}; + +static const short dep219[] = { + 0, 32, 33, 67, 68, 73, 75, 88, 102, 116, 117, 119, 120, 123, 124, 125, 127, + 128, 135, 152, 163, 167, 170, 249, 256, 2129, 2130, 2131, 2157, 2158, 2161, + 4127, 20602, +}; + +static const short dep220[] = { + 0, 23, 88, 100, 170, 201, 249, 256, +}; + +static const short dep221[] = { + 0, 32, 33, 67, 68, 73, 75, 88, 102, 116, 117, 119, 120, 123, 124, 125, 127, + 128, 135, 152, 163, 167, 170, 201, 249, 256, 2129, 2130, 2131, 2157, 2158, + 2161, 4127, 20602, +}; + +static const short dep222[] = { + 0, 88, 100, 170, 249, 256, 2131, 2294, +}; + +static const short dep223[] = { + 0, 3, 32, 33, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, + 125, 127, 128, 135, 152, 163, 167, 170, 249, 256, 2129, 2130, 2131, 2157, + 2158, 2161, 2294, 4127, 20602, +}; + +static const short dep224[] = { + 0, 32, 33, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, + 127, 128, 135, 152, 163, 167, 170, 249, 256, 2129, 2130, 2131, 2157, 2158, + 2161, 2294, 4127, 20602, +}; + +static const short dep225[] = { + 32, 33, 88, 163, 249, 2126, 2127, 2128, 2157, 2158, 2161, 2294, 4127, 16513, + 16515, 20602, +}; + +static const short dep226[] = { + 32, 33, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, 127, + 128, 135, 152, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2292, 4127, + 16513, 16515, 18724, 18726, 18727, 18729, 20602, +}; + +static const short dep227[] = { + 32, 33, 36, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, + 127, 128, 135, 137, 152, 163, 167, 249, 2129, 2130, 2131, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, 20602, +}; + +static const short dep228[] = { + 0, 88, 170, 249, 2127, 2292, 18582, 18583, 18724, 18725, 18727, 18728, +}; + +static const short dep229[] = { + 0, 32, 33, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, 125, + 127, 128, 135, 152, 163, 167, 170, 249, 2129, 2130, 2131, 2157, 2158, 2161, + 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, 20602, +}; + +static const short dep230[] = { + 0, 32, 33, 36, 67, 68, 73, 75, 88, 100, 102, 116, 117, 119, 120, 123, 124, + 125, 127, 128, 135, 137, 152, 163, 167, 170, 249, 2129, 2130, 2131, 2157, + 2158, 2161, 2292, 4127, 16513, 16515, 18724, 18726, 18727, 18729, 20602, +}; + +static const short dep231[] = { + 0, 88, 170, 249, 2128, 2292, 18582, 18583, 18724, 18725, 18727, 18728, +}; + +static const short dep232[] = { + 32, 33, 67, 88, 123, 137, 163, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep233[] = { + 32, 33, 67, 88, 123, 124, 128, 137, 163, 249, 2157, 2158, 2161, 4127, +}; + +static const short dep234[] = { + 32, 33, 67, 88, 123, 137, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 2294, + 4127, 20602, +}; + +static const short dep235[] = { + 32, 33, 67, 88, 123, 124, 128, 137, 163, 249, 2129, 2130, 2131, 2157, 2158, + 2161, 2294, 4127, 20602, +}; + +static const short dep236[] = { + 32, 33, 88, 163, 249, 2129, 2130, 2131, 2157, 2158, 2161, 4127, 20602, +}; + +static const short dep237[] = { + 32, 33, 88, 163, 249, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 4127, +}; + +static const short dep238[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 20, 21, 22, 23, + 88, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 183, 184, 186, 187, + 189, 190, 191, 192, 193, 195, 198, 199, 200, 201, 249, 2064, 2073, 2131, 2242, + 2251, 2294, 28841, 28980, +}; + +static const short dep239[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 21, 22, 23, + 32, 33, 88, 123, 160, 163, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, + 183, 184, 186, 187, 189, 190, 191, 192, 193, 195, 197, 199, 200, 201, 249, + 2064, 2073, 2129, 2130, 2131, 2157, 2158, 2161, 2242, 2251, 2294, 4127, 20602, + 28841, 28980, +}; + +#define NELS(X) (sizeof(X)/sizeof(X[0])) +static const struct ia64_opcode_dependency +op_dependencies[] = { + { NELS(dep1), dep1, NELS(dep0), dep0, }, + { NELS(dep3), dep3, NELS(dep2), dep2, }, + { NELS(dep4), dep4, NELS(dep0), dep0, }, + { NELS(dep6), dep6, NELS(dep5), dep5, }, + { NELS(dep8), dep8, NELS(dep7), dep7, }, + { NELS(dep10), dep10, NELS(dep9), dep9, }, + { NELS(dep12), dep12, NELS(dep11), dep11, }, + { NELS(dep14), dep14, NELS(dep13), dep13, }, + { NELS(dep16), dep16, NELS(dep15), dep15, }, + { NELS(dep18), dep18, NELS(dep17), dep17, }, + { NELS(dep20), dep20, NELS(dep19), dep19, }, + { NELS(dep22), dep22, NELS(dep21), dep21, }, + { NELS(dep24), dep24, NELS(dep23), dep23, }, + { NELS(dep26), dep26, NELS(dep25), dep25, }, + { NELS(dep28), dep28, NELS(dep27), dep27, }, + { NELS(dep30), dep30, NELS(dep29), dep29, }, + { NELS(dep31), dep31, NELS(dep15), dep15, }, + { NELS(dep33), dep33, NELS(dep32), dep32, }, + { NELS(dep35), dep35, NELS(dep34), dep34, }, + { NELS(dep36), dep36, NELS(dep15), dep15, }, + { NELS(dep38), dep38, NELS(dep37), dep37, }, + { NELS(dep40), dep40, NELS(dep39), dep39, }, + { NELS(dep42), dep42, NELS(dep41), dep41, }, + { NELS(dep43), dep43, NELS(dep32), dep32, }, + { NELS(dep44), dep44, NELS(dep34), dep34, }, + { NELS(dep46), dep46, NELS(dep45), dep45, }, + { NELS(dep48), dep48, NELS(dep47), dep47, }, + { NELS(dep50), dep50, NELS(dep49), dep49, }, + { NELS(dep52), dep52, NELS(dep51), dep51, }, + { NELS(dep54), dep54, NELS(dep53), dep53, }, + { NELS(dep56), dep56, NELS(dep55), dep55, }, + { NELS(dep58), dep58, NELS(dep57), dep57, }, + { NELS(dep60), dep60, NELS(dep59), dep59, }, + { NELS(dep62), dep62, NELS(dep61), dep61, }, + { NELS(dep64), dep64, NELS(dep63), dep63, }, + { NELS(dep66), dep66, NELS(dep65), dep65, }, + { NELS(dep68), dep68, NELS(dep67), dep67, }, + { NELS(dep69), dep69, NELS(dep34), dep34, }, + { NELS(dep71), dep71, NELS(dep70), dep70, }, + { NELS(dep73), dep73, NELS(dep72), dep72, }, + { NELS(dep75), dep75, NELS(dep74), dep74, }, + { NELS(dep77), dep77, NELS(dep76), dep76, }, + { NELS(dep78), dep78, NELS(dep34), dep34, }, + { NELS(dep80), dep80, NELS(dep79), dep79, }, + { NELS(dep82), dep82, NELS(dep81), dep81, }, + { NELS(dep84), dep84, NELS(dep83), dep83, }, + { NELS(dep85), dep85, NELS(dep34), dep34, }, + { NELS(dep86), dep86, NELS(dep34), dep34, }, + { NELS(dep87), dep87, NELS(dep34), dep34, }, + { NELS(dep88), dep88, NELS(dep34), dep34, }, + { NELS(dep90), dep90, NELS(dep89), dep89, }, + { NELS(dep92), dep92, NELS(dep91), dep91, }, + { NELS(dep94), dep94, NELS(dep93), dep93, }, + { NELS(dep96), dep96, NELS(dep95), dep95, }, + { NELS(dep98), dep98, NELS(dep97), dep97, }, + { NELS(dep100), dep100, NELS(dep99), dep99, }, + { NELS(dep102), dep102, NELS(dep101), dep101, }, + { NELS(dep104), dep104, NELS(dep103), dep103, }, + { NELS(dep106), dep106, NELS(dep105), dep105, }, + { NELS(dep108), dep108, NELS(dep107), dep107, }, + { NELS(dep110), dep110, NELS(dep109), dep109, }, + { NELS(dep112), dep112, NELS(dep111), dep111, }, + { NELS(dep114), dep114, NELS(dep113), dep113, }, + { NELS(dep116), dep116, NELS(dep115), dep115, }, + { NELS(dep118), dep118, NELS(dep117), dep117, }, + { NELS(dep120), dep120, NELS(dep119), dep119, }, + { NELS(dep122), dep122, NELS(dep121), dep121, }, + { NELS(dep123), dep123, NELS(dep65), dep65, }, + { NELS(dep124), dep124, NELS(dep34), dep34, }, + { NELS(dep126), dep126, NELS(dep125), dep125, }, + { NELS(dep127), dep127, NELS(dep0), dep0, }, + { NELS(dep129), dep129, NELS(dep128), dep128, }, + { NELS(dep131), dep131, NELS(dep130), dep130, }, + { NELS(dep132), dep132, NELS(dep0), dep0, }, + { NELS(dep133), dep133, NELS(dep0), dep0, }, + { NELS(dep135), dep135, NELS(dep134), dep134, }, + { NELS(dep136), dep136, NELS(dep0), dep0, }, + { NELS(dep137), dep137, NELS(dep34), dep34, }, + { NELS(dep139), dep139, NELS(dep138), dep138, }, + { NELS(dep140), dep140, NELS(dep138), dep138, }, + { NELS(dep142), dep142, NELS(dep141), dep141, }, + { NELS(dep143), dep143, NELS(dep141), dep141, }, + { NELS(dep144), dep144, NELS(dep138), dep138, }, + { NELS(dep146), dep146, NELS(dep145), dep145, }, + { NELS(dep148), dep148, NELS(dep147), dep147, }, + { NELS(dep150), dep150, NELS(dep149), dep149, }, + { NELS(dep152), dep152, NELS(dep151), dep151, }, + { NELS(dep153), dep153, NELS(dep0), dep0, }, + { NELS(dep155), dep155, NELS(dep154), dep154, }, + { NELS(dep157), dep157, NELS(dep156), dep156, }, + { NELS(dep159), dep159, NELS(dep158), dep158, }, + { NELS(dep161), dep161, NELS(dep160), dep160, }, + { NELS(dep163), dep163, NELS(dep162), dep162, }, + { NELS(dep164), dep164, NELS(dep0), dep0, }, + { NELS(dep165), dep165, NELS(dep0), dep0, }, + { NELS(dep166), dep166, NELS(dep0), dep0, }, + { NELS(dep167), dep167, NELS(dep34), dep34, }, + { NELS(dep169), dep169, NELS(dep168), dep168, }, + { NELS(dep170), dep170, NELS(dep168), dep168, }, + { NELS(dep172), dep172, NELS(dep171), dep171, }, + { NELS(dep174), dep174, NELS(dep173), dep173, }, + { NELS(dep176), dep176, NELS(dep175), dep175, }, + { NELS(dep178), dep178, NELS(dep177), dep177, }, + { NELS(dep180), dep180, NELS(dep179), dep179, }, + { NELS(dep182), dep182, NELS(dep181), dep181, }, + { NELS(dep184), dep184, NELS(dep183), dep183, }, + { NELS(dep186), dep186, NELS(dep185), dep185, }, + { NELS(dep188), dep188, NELS(dep187), dep187, }, + { NELS(dep189), dep189, NELS(dep0), dep0, }, + { NELS(dep190), dep190, NELS(dep0), dep0, }, + { NELS(dep191), dep191, NELS(dep0), dep0, }, + { NELS(dep192), dep192, NELS(dep0), dep0, }, + { NELS(dep193), dep193, NELS(dep0), dep0, }, + { NELS(dep194), dep194, NELS(dep0), dep0, }, + { NELS(dep195), dep195, NELS(dep0), dep0, }, + { NELS(dep196), dep196, NELS(dep0), dep0, }, + { NELS(dep198), dep198, NELS(dep197), dep197, }, + { NELS(dep200), dep200, NELS(dep199), dep199, }, + { NELS(dep202), dep202, NELS(dep201), dep201, }, + { NELS(dep204), dep204, NELS(dep203), dep203, }, + { NELS(dep205), dep205, NELS(dep0), dep0, }, + { NELS(dep206), dep206, NELS(dep0), dep0, }, + { NELS(dep207), dep207, NELS(dep0), dep0, }, + { NELS(dep208), dep208, NELS(dep34), dep34, }, + { NELS(dep209), dep209, NELS(dep34), dep34, }, + { NELS(dep210), dep210, NELS(dep197), dep197, }, + { NELS(dep211), dep211, NELS(dep0), dep0, }, + { NELS(dep212), dep212, NELS(dep0), dep0, }, + { NELS(dep214), dep214, NELS(dep213), dep213, }, + { NELS(dep215), dep215, NELS(dep213), dep213, }, + { NELS(dep216), dep216, NELS(dep0), dep0, }, + { NELS(dep214), dep214, NELS(dep217), dep217, }, + { NELS(dep219), dep219, NELS(dep218), dep218, }, + { NELS(dep221), dep221, NELS(dep220), dep220, }, + { NELS(dep223), dep223, NELS(dep222), dep222, }, + { NELS(dep224), dep224, NELS(dep222), dep222, }, + { NELS(dep225), dep225, NELS(dep0), dep0, }, + { NELS(dep226), dep226, NELS(dep65), dep65, }, + { NELS(dep227), dep227, NELS(dep65), dep65, }, + { NELS(dep229), dep229, NELS(dep228), dep228, }, + { NELS(dep230), dep230, NELS(dep228), dep228, }, + { NELS(dep229), dep229, NELS(dep231), dep231, }, + { NELS(dep232), dep232, NELS(dep34), dep34, }, + { NELS(dep233), dep233, NELS(dep34), dep34, }, + { NELS(dep234), dep234, NELS(dep0), dep0, }, + { NELS(dep235), dep235, NELS(dep0), dep0, }, + { NELS(dep236), dep236, NELS(dep34), dep34, }, + { NELS(dep237), dep237, NELS(dep15), dep15, }, + { NELS(dep239), dep239, NELS(dep238), dep238, }, +}; + +static const struct ia64_completer_table +completer_table[] = { + { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 1 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 90 }, + { 0x0, 0x0, 0, 122, -1, 0, 1, 8 }, + { 0x0, 0x0, 0, 127, -1, 0, 1, 19 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 147 }, + { 0x0, 0x0, 0, 724, -1, 0, 1, 12 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 11 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 73 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 15 }, + { 0x1, 0x1, 0, 1008, -1, 13, 1, 0 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 35 }, + { 0x0, 0x0, 0, 141, -1, 0, 1, 31 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 31 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 124 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 46 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 42 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 80 }, + { 0x0, 0x0, 0, 143, -1, 0, 1, 31 }, + { 0x0, 0x0, 0, 145, -1, 0, 1, 31 }, + { 0x0, 0x0, 0, 756, -1, 0, 1, 31 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 26 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 37 }, + { 0x0, 0x0, 0, 553, -1, 0, 1, 35 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 79 }, + { 0x0, 0x0, 0, 77, -1, 0, 1, 126 }, + { 0x0, 0x0, 0, 78, -1, 0, 1, 126 }, + { 0x0, 0x0, 0, 79, -1, 0, 1, 137 }, + { 0x0, 0x0, 0, 326, -1, 0, 1, 142 }, + { 0x0, 0x0, 0, 328, -1, 0, 1, 144 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 81 }, + { 0x0, 0x0, 0, 80, -1, 0, 1, 42 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 2 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 69 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 70 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 71 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 72 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 74 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 88 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 89 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 91 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 92 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 93 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 94 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 99 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 100 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 101 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 102 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 103 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 104 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 105 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 108 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 109 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 110 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 111 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 112 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 113 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 114 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 115 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 148 }, + { 0x0, 0x0, 0, 938, -1, 0, 1, 0 }, + { 0x0, 0x0, 0, 731, -1, 0, 1, 0 }, + { 0x0, 0x0, 0, 1009, -1, 0, 1, 0 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 13 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 86 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 85 }, + { 0x0, 0x0, 0, 696, -1, 0, 1, 132 }, + { 0x0, 0x0, 0, 698, -1, 0, 1, 132 }, + { 0x0, 0x0, 0, 695, -1, 0, 1, 132 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 84 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 122 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 120 }, + { 0x0, 0x0, 0, -1, -1, 0, 1, 121 }, + { 0x0, 0x0, 0, 654, -1, 0, 1, 135 }, + { 0x0, 0x0, 1, 75, -1, 0, 1, 14 }, + { 0x1, 0x1, 2, -1, -1, 27, 1, 14 }, + { 0x0, 0x0, 3, -1, 132, 0, 0, -1 }, + { 0x1, 0x1, 3, 84, 655, 33, 1, 128 }, + { 0x1, 0x1, 3, 85, 655, 33, 1, 128 }, + { 0x1, 0x1, 3, 112, 663, 33, 1, 139 }, + { 0x1, 0x1, 3, -1, -1, 27, 1, 42 }, + { 0x0, 0x0, 4, 732, 653, 0, 1, 134 }, + { 0x0, 0x0, 4, 733, 654, 0, 1, 135 }, + { 0x1, 0x1, 4, 657, 657, 33, 1, 131 }, + { 0x5, 0x5, 4, 108, 656, 32, 1, 126 }, + { 0x5, 0x5, 4, 109, 656, 32, 1, 126 }, + { 0x1, 0x21, 10, 701, -1, 33, 1, 5 }, + { 0x200001, 0x200001, 10, 702, -1, 12, 1, 5 }, + { 0x1, 0x1, 10, 703, -1, 33, 1, 5 }, + { 0x0, 0x0, 10, 704, -1, 0, 1, 5 }, + { 0x1, 0x1, 10, 705, -1, 12, 1, 5 }, + { 0x0, 0x0, 10, -1, 712, 0, 0, -1 }, + { 0x0, 0x0, 10, -1, 713, 0, 0, -1 }, + { 0x0, 0x0, 10, -1, 714, 0, 0, -1 }, + { 0x0, 0x0, 10, -1, 715, 0, 0, -1 }, + { 0x1000001, 0x1000001, 10, 706, -1, 12, 1, 5 }, + { 0x1, 0x1, 10, 707, -1, 36, 1, 5 }, + { 0x0, 0x0, 10, 105, 716, 0, 0, -1 }, + { 0x0, 0x0, 10, 106, 718, 0, 0, -1 }, + { 0x2, 0x3, 11, -1, -1, 37, 1, 7 }, + { 0x1, 0x1, 11, 708, -1, 12, 1, 5 }, + { 0x0, 0x0, 11, 709, -1, 0, 1, 5 }, + { 0x200001, 0x200001, 11, 710, -1, 12, 1, 5 }, + { 0x1, 0x1, 11, 711, -1, 33, 1, 5 }, + { 0x1, 0x1, 11, -1, -1, 36, 1, 7 }, + { 0x1, 0x1, 11, 717, -1, 36, 1, 5 }, + { 0x1000001, 0x1000001, 11, 719, -1, 12, 1, 5 }, + { 0x0, 0x0, 12, -1, -1, 0, 1, 16 }, + { 0x1, 0x1, 13, 110, 656, 34, 1, 126 }, + { 0x1, 0x1, 13, 111, 656, 34, 1, 126 }, + { 0x0, 0x0, 19, 660, 133, 0, 0, -1 }, + { 0x0, 0x0, 19, 399, 133, 0, 0, -1 }, + { 0x0, 0x0, 19, 667, 134, 0, 0, -1 }, + { 0x0, 0x0, 20, -1, 266, 0, 0, -1 }, + { 0x0, 0x0, 20, -1, 267, 0, 0, -1 }, + { 0x0, 0x0, 20, -1, 280, 0, 0, -1 }, + { 0x0, 0x0, 20, -1, 281, 0, 0, -1 }, + { 0x0, 0x0, 21, 139, 276, 0, 0, -1 }, + { 0x0, 0x0, 21, 140, 278, 0, 0, -1 }, + { 0x0, 0x0, 23, -1, 274, 0, 0, -1 }, + { 0x0, 0x0, 23, -1, 275, 0, 0, -1 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, + { 0x1, 0x1, 24, 339, -1, 35, 1, 8 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 9 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 10 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, + { 0x1, 0x1, 24, 355, -1, 35, 1, 19 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 22 }, + { 0x1, 0x1, 24, -1, -1, 35, 1, 23 }, + { 0x1, 0x1, 24, 538, -1, 33, 1, 78 }, + { 0x1, 0x1, 24, 539, 83, 35, 1, 131 }, + { 0x1, 0x1, 24, 540, 664, 35, 1, 141 }, + { 0x0, 0x0, 32, 260, 258, 0, 0, -1 }, + { 0x0, 0x0, 32, 263, 261, 0, 0, -1 }, + { 0x0, 0x0, 32, 268, 268, 0, 0, -1 }, + { 0x0, 0x0, 32, 269, 269, 0, 0, -1 }, + { 0x0, 0x0, 34, -1, 277, 0, 0, -1 }, + { 0x0, 0x0, 34, -1, 279, 0, 0, -1 }, + { 0x1, 0x1, 37, 746, 756, 37, 1, 31 }, + { 0x0, 0x0, 37, 747, 774, 0, 0, -1 }, + { 0x1, 0x1, 37, 748, -1, 37, 1, 31 }, + { 0x0, 0x0, 37, 750, 774, 0, 0, -1 }, + { 0x1, 0x1, 37, 751, -1, 37, 1, 31 }, + { 0x3, 0x3, 37, 331, -1, 30, 1, 136 }, + { 0x0, 0x0, 37, 433, -1, 0, 1, 97 }, + { 0x0, 0x0, 37, -1, -1, 0, 1, 106 }, + { 0x0, 0x0, 37, 437, -1, 0, 1, 118 }, + { 0x3, 0x3, 37, 332, -1, 30, 1, 146 }, + { 0x0, 0x0, 37, 438, -1, 0, 1, 42 }, + { 0x5, 0x5, 38, 566, 441, 0, 1, 18 }, + { 0x1, 0x1, 38, 567, 441, 1, 1, 18 }, + { 0x0, 0x0, 38, 568, 565, 0, 0, -1 }, + { 0x1, 0x1, 38, 569, 441, 5, 1, 18 }, + { 0x25, 0x25, 38, 570, 441, 0, 1, 18 }, + { 0x11, 0x11, 38, 571, 441, 1, 1, 18 }, + { 0x0, 0x0, 38, 572, 155, 0, 0, -1 }, + { 0x1, 0x1, 38, 573, 441, 4, 1, 18 }, + { 0x1, 0x1, 38, -1, 441, 4, 1, 18 }, + { 0x0, 0x0, 38, -1, 160, 0, 0, -1 }, + { 0x15, 0x15, 38, 574, 441, 0, 1, 18 }, + { 0x9, 0x9, 38, 575, 441, 1, 1, 18 }, + { 0x0, 0x0, 38, 384, 159, 0, 0, -1 }, + { 0x800001, 0x800001, 38, 577, 441, 4, 1, 18 }, + { 0x800001, 0x800001, 38, -1, 441, 4, 1, 18 }, + { 0x0, 0x0, 38, -1, 166, 0, 0, -1 }, + { 0x8000015, 0x8000015, 38, 578, 441, 0, 1, 18 }, + { 0x4000009, 0x4000009, 38, 579, 441, 1, 1, 18 }, + { 0x0, 0x0, 38, 385, 165, 0, 0, -1 }, + { 0x1, 0x1, 38, 581, 441, 27, 1, 18 }, + { 0x1, 0x1, 38, -1, 441, 27, 1, 18 }, + { 0x0, 0x0, 38, -1, 172, 0, 0, -1 }, + { 0x8000005, 0x8000005, 38, 582, 441, 0, 1, 18 }, + { 0x4000001, 0x4000001, 38, 583, 441, 1, 1, 18 }, + { 0x0, 0x0, 38, 386, 171, 0, 0, -1 }, + { 0x0, 0x0, 38, 565, 441, 0, 1, 18 }, + { 0x0, 0x0, 38, -1, 441, 0, 1, 18 }, + { 0x0, 0x0, 38, -1, 178, 0, 0, -1 }, + { 0x0, 0x0, 38, 387, 177, 0, 0, -1 }, + { 0x5, 0x5, 38, 586, 443, 0, 1, 24 }, + { 0x1, 0x1, 38, 587, 443, 1, 1, 24 }, + { 0x0, 0x0, 38, 588, 585, 0, 0, -1 }, + { 0x1, 0x1, 38, 589, 443, 5, 1, 24 }, + { 0x25, 0x25, 38, 590, 443, 0, 1, 24 }, + { 0x11, 0x11, 38, 591, 443, 1, 1, 24 }, + { 0x0, 0x0, 38, 592, 184, 0, 0, -1 }, + { 0x1, 0x1, 38, 593, 443, 4, 1, 24 }, + { 0x1, 0x1, 38, -1, 443, 4, 1, 24 }, + { 0x0, 0x0, 38, -1, 189, 0, 0, -1 }, + { 0x15, 0x15, 38, 594, 443, 0, 1, 24 }, + { 0x9, 0x9, 38, 595, 443, 1, 1, 24 }, + { 0x0, 0x0, 38, 389, 188, 0, 0, -1 }, + { 0x3, 0x3, 38, 597, 443, 3, 1, 24 }, + { 0x3, 0x3, 38, -1, 443, 3, 1, 24 }, + { 0x0, 0x0, 38, -1, 195, 0, 0, -1 }, + { 0x1d, 0x1d, 38, 598, 443, 0, 1, 24 }, + { 0xd, 0xd, 38, 599, 443, 1, 1, 24 }, + { 0x0, 0x0, 38, 390, 194, 0, 0, -1 }, + { 0x1, 0x1, 38, 601, 443, 3, 1, 24 }, + { 0x1, 0x1, 38, -1, 443, 3, 1, 24 }, + { 0x0, 0x0, 38, -1, 201, 0, 0, -1 }, + { 0xd, 0xd, 38, 602, 443, 0, 1, 24 }, + { 0x5, 0x5, 38, 603, 443, 1, 1, 24 }, + { 0x0, 0x0, 38, 391, 200, 0, 0, -1 }, + { 0x0, 0x0, 38, 585, 443, 0, 1, 24 }, + { 0x0, 0x0, 38, -1, 443, 0, 1, 24 }, + { 0x0, 0x0, 38, -1, 207, 0, 0, -1 }, + { 0x0, 0x0, 38, 392, 206, 0, 0, -1 }, + { 0x1, 0x1, 38, 605, 445, 21, 1, 69 }, + { 0x1005, 0x1005, 38, 606, 445, 9, 1, 69 }, + { 0x801, 0x801, 38, 607, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 608, 210, 0, 0, -1 }, + { 0x201, 0x201, 38, 609, 445, 12, 1, 69 }, + { 0x100d, 0x100d, 38, 610, 445, 9, 1, 69 }, + { 0x805, 0x805, 38, 611, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 612, 214, 0, 0, -1 }, + { 0x1, 0x1, 38, 613, 445, 20, 1, 69 }, + { 0x805, 0x805, 38, 614, 445, 9, 1, 69 }, + { 0x401, 0x401, 38, 615, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 616, 218, 0, 0, -1 }, + { 0x101, 0x101, 38, 617, 445, 12, 1, 69 }, + { 0x80d, 0x80d, 38, 618, 445, 9, 1, 69 }, + { 0x405, 0x405, 38, 619, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 620, 222, 0, 0, -1 }, + { 0x3, 0x3, 38, 621, 445, 21, 1, 69 }, + { 0x3005, 0x3005, 38, 622, 445, 9, 1, 69 }, + { 0x1801, 0x1801, 38, 623, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 624, 226, 0, 0, -1 }, + { 0x601, 0x601, 38, 625, 445, 12, 1, 69 }, + { 0x300d, 0x300d, 38, 626, 445, 9, 1, 69 }, + { 0x1805, 0x1805, 38, 627, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 628, 230, 0, 0, -1 }, + { 0x5, 0x5, 38, 629, 445, 20, 1, 69 }, + { 0x2805, 0x2805, 38, 630, 445, 9, 1, 69 }, + { 0x1401, 0x1401, 38, 631, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 632, 234, 0, 0, -1 }, + { 0x501, 0x501, 38, 633, 445, 12, 1, 69 }, + { 0x280d, 0x280d, 38, 634, 445, 9, 1, 69 }, + { 0x1405, 0x1405, 38, 635, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 636, 238, 0, 0, -1 }, + { 0x1, 0x1, 38, 637, 445, 22, 1, 69 }, + { 0x2005, 0x2005, 38, 638, 445, 9, 1, 69 }, + { 0x1001, 0x1001, 38, 639, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 640, 242, 0, 0, -1 }, + { 0x401, 0x401, 38, 641, 445, 12, 1, 69 }, + { 0x200d, 0x200d, 38, 642, 445, 9, 1, 69 }, + { 0x1005, 0x1005, 38, 643, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 644, 246, 0, 0, -1 }, + { 0x0, 0x0, 38, 645, 445, 0, 1, 69 }, + { 0x5, 0x5, 38, 646, 445, 9, 1, 69 }, + { 0x1, 0x1, 38, 647, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 648, 250, 0, 0, -1 }, + { 0x1, 0x1, 38, 649, 445, 12, 1, 69 }, + { 0xd, 0xd, 38, 650, 445, 9, 1, 69 }, + { 0x5, 0x5, 38, 651, 445, 10, 1, 69 }, + { 0x0, 0x0, 38, 652, 254, 0, 0, -1 }, + { 0x0, 0x0, 40, 282, 340, 0, 0, -1 }, + { 0x0, 0x0, 40, 283, 343, 0, 0, -1 }, + { 0x0, 0x0, 40, 284, 340, 0, 0, -1 }, + { 0x3, 0x3, 40, 285, 121, 33, 1, 8 }, + { 0x18000001, 0x18000001, 40, 286, 123, 6, 1, 9 }, + { 0x3, 0x3, 40, 287, 121, 33, 1, 8 }, + { 0x0, 0x0, 40, 288, 347, 0, 0, -1 }, + { 0x3, 0x3, 40, 289, 124, 33, 1, 10 }, + { 0x0, 0x0, 40, 290, 351, 0, 0, -1 }, + { 0x3, 0x3, 40, 291, 125, 33, 1, 17 }, + { 0x0, 0x0, 40, 292, 356, 0, 0, -1 }, + { 0x3, 0x3, 40, 293, 126, 33, 1, 19 }, + { 0x0, 0x0, 40, 294, 359, 0, 0, -1 }, + { 0x0, 0x0, 40, 295, 363, 0, 0, -1 }, + { 0x3, 0x3, 40, 296, 128, 33, 1, 20 }, + { 0x18000001, 0x18000001, 40, 297, 128, 6, 1, 20 }, + { 0x0, 0x0, 40, 298, 367, 0, 0, -1 }, + { 0x3, 0x3, 40, 299, 129, 33, 1, 21 }, + { 0x0, 0x0, 40, 300, 371, 0, 0, -1 }, + { 0x0, 0x0, 40, 301, 375, 0, 0, -1 }, + { 0x3, 0x3, 40, 302, 130, 33, 1, 22 }, + { 0x18000001, 0x18000001, 40, 303, 130, 6, 1, 22 }, + { 0x0, 0x0, 40, 304, 379, 0, 0, -1 }, + { 0x3, 0x3, 40, 305, 131, 33, 1, 23 }, + { 0x0, 0x0, 41, 884, 341, 0, 0, -1 }, + { 0x0, 0x0, 41, 885, 344, 0, 0, -1 }, + { 0x0, 0x0, 41, 439, 341, 0, 0, -1 }, + { 0x1, 0x1, 41, 886, 121, 34, 1, 8 }, + { 0x10000001, 0x10000001, 41, 887, 123, 6, 1, 9 }, + { 0x1, 0x1, 41, 440, 121, 34, 1, 8 }, + { 0x0, 0x0, 41, 888, 348, 0, 0, -1 }, + { 0x1, 0x1, 41, 889, 124, 34, 1, 10 }, + { 0x0, 0x0, 41, 890, 352, 0, 0, -1 }, + { 0x1, 0x1, 41, 891, 125, 34, 1, 17 }, + { 0x0, 0x0, 41, 892, 357, 0, 0, -1 }, + { 0x1, 0x1, 41, 893, 126, 34, 1, 19 }, + { 0x0, 0x0, 41, 894, 360, 0, 0, -1 }, + { 0x0, 0x0, 41, 895, 364, 0, 0, -1 }, + { 0x1, 0x1, 41, 896, 128, 34, 1, 20 }, + { 0x10000001, 0x10000001, 41, 897, 128, 6, 1, 20 }, + { 0x0, 0x0, 41, 898, 368, 0, 0, -1 }, + { 0x1, 0x1, 41, 899, 129, 34, 1, 21 }, + { 0x0, 0x0, 41, 900, 372, 0, 0, -1 }, + { 0x0, 0x0, 41, 901, 376, 0, 0, -1 }, + { 0x1, 0x1, 41, 902, 130, 34, 1, 22 }, + { 0x10000001, 0x10000001, 41, 903, 130, 6, 1, 22 }, + { 0x0, 0x0, 41, 904, 380, 0, 0, -1 }, + { 0x1, 0x1, 41, 905, 131, 34, 1, 23 }, + { 0x800001, 0x800001, 41, 928, 383, 4, 1, 18 }, + { 0x1, 0x1, 41, 738, 383, 4, 1, 18 }, + { 0x0, 0x0, 41, 930, 170, 0, 0, -1 }, + { 0x0, 0x0, 41, 739, 164, 0, 0, -1 }, + { 0x1, 0x1, 41, 329, 388, 4, 1, 24 }, + { 0x0, 0x0, 41, 330, 193, 0, 0, -1 }, + { 0x0, 0x0, 41, 396, 394, 0, 0, -1 }, + { 0x0, 0x0, 41, 398, 393, 0, 0, -1 }, + { 0x0, 0x0, 42, -1, -1, 0, 1, 82 }, + { 0x0, 0x0, 42, -1, -1, 0, 1, 125 }, + { 0x1, 0x1, 44, 468, 86, 38, 1, 3 }, + { 0x0, 0x0, 44, 543, 100, 0, 0, -1 }, + { 0x0, 0x0, 44, 544, 91, 0, 0, -1 }, + { 0x1, 0x1, 44, 472, 86, 38, 1, 3 }, + { 0x0, 0x0, 44, 459, 761, 0, 0, -1 }, + { 0x0, 0x0, 44, 460, 1016, 0, 1, 56 }, + { 0x0, 0x0, 44, 461, 777, 0, 0, -1 }, + { 0x0, 0x0, 44, 462, -1, 0, 1, 51 }, + { 0x0, 0x0, 44, 423, -1, 0, 1, 0 }, + { 0x1, 0x1, 45, 669, 669, 30, 1, 143 }, + { 0x1, 0x1, 45, 334, 668, 30, 1, 142 }, + { 0x1, 0x1, 45, 671, 671, 30, 1, 145 }, + { 0x1, 0x1, 45, 335, 670, 30, 1, 144 }, + { 0x3, 0x3, 46, 465, 388, 3, 1, 24 }, + { 0x0, 0x0, 46, 466, 199, 0, 0, -1 }, + { 0x1, 0x1, 47, 752, -1, 30, 1, 136 }, + { 0x1, 0x1, 47, 755, -1, 30, 1, 146 }, + { 0x0, 0x0, 49, -1, -1, 0, 1, 42 }, + { 0x1, 0x1, 56, 668, 325, 31, 1, 143 }, + { 0x1, 0x1, 56, 670, 327, 31, 1, 145 }, + { 0x2, 0x3, 56, -1, -1, 27, 1, 96 }, + { 0x0, 0x0, 56, -1, -1, 0, 1, 96 }, + { 0x1, 0x1, 56, -1, -1, 28, 1, 96 }, + { 0x0, 0x0, 65, 486, 121, 0, 1, 8 }, + { 0x3, 0x3, 65, 487, 121, 33, 1, 8 }, + { 0x1, 0x1, 65, 488, 121, 34, 1, 8 }, + { 0x1, 0x1, 65, 489, 121, 33, 1, 8 }, + { 0x18000001, 0x18000001, 65, 490, 123, 6, 1, 9 }, + { 0x10000001, 0x10000001, 65, 491, 123, 6, 1, 9 }, + { 0x8000001, 0x8000001, 65, 492, 123, 6, 1, 9 }, + { 0x1, 0x1, 65, 493, 123, 6, 1, 9 }, + { 0x3, 0x3, 65, 494, 124, 33, 1, 10 }, + { 0x1, 0x1, 65, 495, 124, 34, 1, 10 }, + { 0x1, 0x1, 65, 496, 124, 33, 1, 10 }, + { 0x0, 0x0, 65, 497, 124, 0, 1, 10 }, + { 0x3, 0x3, 65, 498, 125, 33, 1, 17 }, + { 0x1, 0x1, 65, 499, 125, 34, 1, 17 }, + { 0x1, 0x1, 65, 500, 125, 33, 1, 17 }, + { 0x0, 0x0, 65, 501, 125, 0, 1, 17 }, + { 0x0, 0x0, 65, 502, 126, 0, 1, 19 }, + { 0x3, 0x3, 65, 503, 126, 33, 1, 19 }, + { 0x1, 0x1, 65, 504, 126, 34, 1, 19 }, + { 0x1, 0x1, 65, 505, 126, 33, 1, 19 }, + { 0x3, 0x3, 65, 506, 128, 33, 1, 20 }, + { 0x1, 0x1, 65, 507, 128, 34, 1, 20 }, + { 0x1, 0x1, 65, 508, 128, 33, 1, 20 }, + { 0x0, 0x0, 65, 509, 128, 0, 1, 20 }, + { 0x18000001, 0x18000001, 65, 510, 128, 6, 1, 20 }, + { 0x10000001, 0x10000001, 65, 511, 128, 6, 1, 20 }, + { 0x8000001, 0x8000001, 65, 512, 128, 6, 1, 20 }, + { 0x1, 0x1, 65, 513, 128, 6, 1, 20 }, + { 0x3, 0x3, 65, 514, 129, 33, 1, 21 }, + { 0x1, 0x1, 65, 515, 129, 34, 1, 21 }, + { 0x1, 0x1, 65, 516, 129, 33, 1, 21 }, + { 0x0, 0x0, 65, 517, 129, 0, 1, 21 }, + { 0x3, 0x3, 65, 518, 130, 33, 1, 22 }, + { 0x1, 0x1, 65, 519, 130, 34, 1, 22 }, + { 0x1, 0x1, 65, 520, 130, 33, 1, 22 }, + { 0x0, 0x0, 65, 521, 130, 0, 1, 22 }, + { 0x18000001, 0x18000001, 65, 522, 130, 6, 1, 22 }, + { 0x10000001, 0x10000001, 65, 523, 130, 6, 1, 22 }, + { 0x8000001, 0x8000001, 65, 524, 130, 6, 1, 22 }, + { 0x1, 0x1, 65, 525, 130, 6, 1, 22 }, + { 0x3, 0x3, 65, 526, 131, 33, 1, 23 }, + { 0x1, 0x1, 65, 527, 131, 34, 1, 23 }, + { 0x1, 0x1, 65, 528, 131, 33, 1, 23 }, + { 0x0, 0x0, 65, 529, 131, 0, 1, 23 }, + { 0x0, 0x0, 65, 442, 154, 0, 0, -1 }, + { 0x0, 0x0, 65, 576, 161, 0, 0, -1 }, + { 0x0, 0x0, 65, 580, 167, 0, 0, -1 }, + { 0x0, 0x0, 65, 584, 173, 0, 0, -1 }, + { 0x0, 0x0, 65, 568, 179, 0, 0, -1 }, + { 0x0, 0x0, 65, 444, 183, 0, 0, -1 }, + { 0x0, 0x0, 65, 596, 190, 0, 0, -1 }, + { 0x0, 0x0, 65, 600, 196, 0, 0, -1 }, + { 0x0, 0x0, 65, 604, 202, 0, 0, -1 }, + { 0x0, 0x0, 65, 588, 208, 0, 0, -1 }, + { 0x0, 0x0, 65, 532, 213, 0, 0, -1 }, + { 0x0, 0x0, 65, 533, 229, 0, 0, -1 }, + { 0x0, 0x0, 65, 534, 245, 0, 0, -1 }, + { 0x0, 0x0, 65, 535, 237, 0, 0, -1 }, + { 0x0, 0x0, 65, 536, 253, 0, 0, -1 }, + { 0x0, 0x0, 65, 537, 221, 0, 0, -1 }, + { 0x3, 0x3, 66, 660, 661, 33, 1, 130 }, + { 0x0, 0x0, 66, -1, 662, 0, 1, 137 }, + { 0x0, 0x0, 107, 403, 771, 0, 0, -1 }, + { 0x0, 0x0, 107, 404, 1007, 0, 1, 31 }, + { 0x0, 0x0, 109, -1, 773, 0, 0, -1 }, + { 0x1, 0x1, 109, -1, 1007, 27, 1, 31 }, + { 0x0, 0x0, 110, 406, -1, 0, 1, 117 }, + { 0x1, 0x1, 111, -1, -1, 27, 1, 117 }, + { 0x0, 0x0, 112, 414, 1010, 0, 1, 3 }, + { 0x0, 0x0, 112, 417, 88, 0, 0, -1 }, + { 0x0, 0x0, 112, 418, 102, 0, 0, -1 }, + { 0x0, 0x0, 112, 420, 93, 0, 0, -1 }, + { 0x0, 0x0, 112, 542, 1010, 0, 1, 3 }, + { 0x0, 0x0, 112, 421, 769, 0, 0, -1 }, + { 0x1, 0x9, 112, 422, 1016, 33, 1, 56 }, + { 0x1, 0x1, 114, 542, 1010, 37, 1, 3 }, + { 0x0, 0x0, 114, -1, 1010, 0, 1, 3 }, + { 0x0, 0x0, 115, 424, 1010, 0, 1, 3 }, + { 0x0, 0x0, 115, 455, 89, 0, 0, -1 }, + { 0x0, 0x0, 115, 456, 100, 0, 0, -1 }, + { 0x0, 0x0, 115, -1, 1010, 0, 1, 3 }, + { 0x0, 0x0, 115, 458, 91, 0, 0, -1 }, + { 0x0, 0x0, 115, -1, 761, 0, 0, -1 }, + { 0x0, 0x0, 115, -1, 1016, 0, 1, 56 }, + { 0x1, 0x1, 115, -1, -1, 27, 1, 0 }, + { 0x1, 0x1, 116, -1, 1010, 37, 1, 3 }, + { 0x0, 0x0, 116, -1, 1010, 0, 1, 3 }, + { 0x0, 0x0, 117, 451, -1, 0, 1, 0 }, + { 0x3, 0x3, 117, 429, -1, 34, 1, 35 }, + { 0x3, 0x3, 117, 430, -1, 34, 1, 42 }, + { 0x1, 0x1, 118, 452, -1, 35, 1, 35 }, + { 0x1, 0x1, 118, 453, -1, 35, 1, 42 }, + { 0x0, 0x0, 119, -1, -1, 0, 1, 42 }, + { 0x0, 0x0, 119, -1, -1, 0, 1, 68 }, + { 0x1, 0x1, 119, -1, -1, 27, 1, 98 }, + { 0x0, 0x0, 119, -1, -1, 0, 1, 107 }, + { 0x0, 0x0, 119, -1, -1, 0, 1, 75 }, + { 0x0, 0x0, 119, -1, -1, 0, 1, 76 }, + { 0x1, 0x1, 119, -1, -1, 27, 1, 119 }, + { 0x1, 0x1, 119, -1, -1, 27, 1, 42 }, + { 0x0, 0x0, 120, 884, 259, 0, 0, -1 }, + { 0x0, 0x0, 120, 886, 262, 0, 0, -1 }, + { 0x1, 0x1, 121, -1, -1, 35, 1, 18 }, + { 0x1, 0x1, 121, 530, -1, 35, 1, 18 }, + { 0x1, 0x1, 121, -1, -1, 35, 1, 24 }, + { 0x1, 0x1, 121, 531, -1, 35, 1, 24 }, + { 0x1, 0x1, 121, -1, -1, 23, 1, 69 }, + { 0x0, 0x0, 125, 725, -1, 0, 1, 0 }, + { 0x1, 0x1, 125, 467, -1, 28, 1, 35 }, + { 0x1, 0x1, 125, 727, -1, 27, 1, 35 }, + { 0x1, 0x1, 125, 728, -1, 29, 1, 0 }, + { 0x0, 0x0, 125, -1, -1, 0, 1, 116 }, + { 0x1, 0x1, 125, -1, -1, 29, 1, 0 }, + { 0x0, 0x0, 125, -1, -1, 0, 1, 35 }, + { 0x0, 0x0, 125, 480, -1, 0, 1, 42 }, + { 0x0, 0x0, 138, 463, 1010, 0, 1, 3 }, + { 0x0, 0x0, 138, 469, 90, 0, 0, -1 }, + { 0x0, 0x0, 138, 470, 101, 0, 0, -1 }, + { 0x0, 0x0, 138, -1, 1010, 0, 1, 3 }, + { 0x0, 0x0, 138, 471, 92, 0, 0, -1 }, + { 0x0, 0x0, 138, 473, 763, 0, 0, -1 }, + { 0x1, 0x1, 138, 474, 1016, 33, 1, 56 }, + { 0x0, 0x0, 138, 475, 778, 0, 0, -1 }, + { 0x1, 0x1, 138, 476, -1, 28, 1, 51 }, + { 0x1, 0x1, 139, -1, 1010, 37, 1, 3 }, + { 0x0, 0x0, 139, -1, 1010, 0, 1, 3 }, + { 0x1, 0x1, 142, 932, 388, 3, 1, 24 }, + { 0x0, 0x0, 142, 933, 205, 0, 0, -1 }, + { 0x0, 0x0, 143, 726, -1, 0, 1, 35 }, + { 0x0, 0x0, 144, 477, 1010, 0, 1, 3 }, + { 0x0, 0x0, 144, -1, 87, 0, 0, -1 }, + { 0x0, 0x0, 144, -1, 103, 0, 0, -1 }, + { 0x0, 0x0, 144, -1, 94, 0, 0, -1 }, + { 0x0, 0x0, 144, 541, 1010, 0, 1, 3 }, + { 0x0, 0x0, 144, 1019, 765, 0, 0, -1 }, + { 0x1, 0x1, 144, 1020, 1016, 36, 1, 56 }, + { 0x0, 0x0, 144, 547, 779, 0, 0, -1 }, + { 0x1, 0x1, 144, 548, -1, 27, 1, 51 }, + { 0x1, 0x1, 145, 541, 1010, 37, 1, 3 }, + { 0x0, 0x0, 145, -1, 1010, 0, 1, 3 }, + { 0x0, 0x0, 146, -1, -1, 0, 1, 35 }, + { 0x0, 0x0, 146, -1, -1, 0, 1, 42 }, + { 0x0, 0x0, 147, -1, -1, 0, 1, 42 }, + { 0x0, 0x0, 147, -1, -1, 0, 1, 68 }, + { 0x0, 0x0, 147, -1, 1011, 0, 1, 65 }, + { 0x0, 0x0, 147, -1, -1, 0, 1, 83 }, + { 0x0, 0x0, 147, -1, -1, 0, 1, 87 }, + { 0x1, 0x1, 148, -1, 121, 12, 1, 8 }, + { 0x600001, 0x600001, 148, -1, 121, 12, 1, 8 }, + { 0x400001, 0x400001, 148, -1, 121, 12, 1, 8 }, + { 0x200001, 0x200001, 148, -1, 121, 12, 1, 8 }, + { 0x18000041, 0x18000041, 148, -1, 123, 6, 1, 9 }, + { 0x10000041, 0x10000041, 148, -1, 123, 6, 1, 9 }, + { 0x8000041, 0x8000041, 148, -1, 123, 6, 1, 9 }, + { 0x41, 0x41, 148, -1, 123, 6, 1, 9 }, + { 0x600001, 0x600001, 148, -1, 124, 12, 1, 10 }, + { 0x400001, 0x400001, 148, -1, 124, 12, 1, 10 }, + { 0x200001, 0x200001, 148, -1, 124, 12, 1, 10 }, + { 0x1, 0x1, 148, -1, 124, 12, 1, 10 }, + { 0x600001, 0x600001, 148, -1, 125, 12, 1, 17 }, + { 0x400001, 0x400001, 148, -1, 125, 12, 1, 17 }, + { 0x200001, 0x200001, 148, -1, 125, 12, 1, 17 }, + { 0x1, 0x1, 148, -1, 125, 12, 1, 17 }, + { 0x1, 0x1, 148, -1, 126, 12, 1, 19 }, + { 0x600001, 0x600001, 148, -1, 126, 12, 1, 19 }, + { 0x400001, 0x400001, 148, -1, 126, 12, 1, 19 }, + { 0x200001, 0x200001, 148, -1, 126, 12, 1, 19 }, + { 0x600001, 0x600001, 148, -1, 128, 12, 1, 20 }, + { 0x400001, 0x400001, 148, -1, 128, 12, 1, 20 }, + { 0x200001, 0x200001, 148, -1, 128, 12, 1, 20 }, + { 0x1, 0x1, 148, -1, 128, 12, 1, 20 }, + { 0x18000041, 0x18000041, 148, -1, 128, 6, 1, 20 }, + { 0x10000041, 0x10000041, 148, -1, 128, 6, 1, 20 }, + { 0x8000041, 0x8000041, 148, -1, 128, 6, 1, 20 }, + { 0x41, 0x41, 148, -1, 128, 6, 1, 20 }, + { 0x600001, 0x600001, 148, -1, 129, 12, 1, 21 }, + { 0x400001, 0x400001, 148, -1, 129, 12, 1, 21 }, + { 0x200001, 0x200001, 148, -1, 129, 12, 1, 21 }, + { 0x1, 0x1, 148, -1, 129, 12, 1, 21 }, + { 0x600001, 0x600001, 148, -1, 130, 12, 1, 22 }, + { 0x400001, 0x400001, 148, -1, 130, 12, 1, 22 }, + { 0x200001, 0x200001, 148, -1, 130, 12, 1, 22 }, + { 0x1, 0x1, 148, -1, 130, 12, 1, 22 }, + { 0x18000041, 0x18000041, 148, -1, 130, 6, 1, 22 }, + { 0x10000041, 0x10000041, 148, -1, 130, 6, 1, 22 }, + { 0x8000041, 0x8000041, 148, -1, 130, 6, 1, 22 }, + { 0x41, 0x41, 148, -1, 130, 6, 1, 22 }, + { 0x600001, 0x600001, 148, -1, 131, 12, 1, 23 }, + { 0x400001, 0x400001, 148, -1, 131, 12, 1, 23 }, + { 0x200001, 0x200001, 148, -1, 131, 12, 1, 23 }, + { 0x1, 0x1, 148, -1, 131, 12, 1, 23 }, + { 0x0, 0x0, 148, -1, 158, 0, 0, -1 }, + { 0x0, 0x0, 148, -1, 187, 0, 0, -1 }, + { 0x0, 0x0, 148, -1, 217, 0, 0, -1 }, + { 0x0, 0x0, 148, -1, 233, 0, 0, -1 }, + { 0x0, 0x0, 148, -1, 249, 0, 0, -1 }, + { 0x0, 0x0, 148, 934, 241, 0, 0, -1 }, + { 0x0, 0x0, 148, -1, 257, 0, 0, -1 }, + { 0x0, 0x0, 148, 740, 225, 0, 0, -1 }, + { 0x0, 0x0, 157, -1, -1, 0, 1, 77 }, + { 0x9, 0x9, 157, -1, 657, 32, 1, 131 }, + { 0x9, 0x9, 157, -1, 664, 32, 1, 141 }, + { 0x0, 0x0, 158, -1, 87, 0, 0, -1 }, + { 0x1, 0x1, 158, -1, 1010, 38, 1, 3 }, + { 0x0, 0x0, 158, -1, 101, 0, 0, -1 }, + { 0x0, 0x0, 158, -1, 92, 0, 0, -1 }, + { 0x0, 0x0, 159, 554, 761, 0, 0, -1 }, + { 0x0, 0x0, 159, 555, 1016, 0, 1, 56 }, + { 0x0, 0x0, 159, 556, 780, 0, 0, -1 }, + { 0x1, 0x1, 159, 557, -1, 29, 1, 51 }, + { 0x0, 0x0, 160, 551, 769, 0, 0, -1 }, + { 0x1, 0x9, 160, 552, 1016, 33, 1, 56 }, + { 0x0, 0x0, 161, -1, 761, 0, 0, -1 }, + { 0x0, 0x0, 161, -1, 1016, 0, 1, 56 }, + { 0x1, 0x1, 162, 563, -1, 27, 1, 35 }, + { 0x0, 0x0, 163, 558, 763, 0, 0, -1 }, + { 0x1, 0x1, 163, 559, 1016, 33, 1, 56 }, + { 0x0, 0x0, 163, 560, 781, 0, 0, -1 }, + { 0x3, 0x3, 163, 561, -1, 28, 1, 51 }, + { 0x0, 0x0, 164, 720, 765, 0, 0, -1 }, + { 0x1, 0x1, 164, 721, 1016, 36, 1, 56 }, + { 0x0, 0x0, 164, 722, 782, 0, 0, -1 }, + { 0x5, 0x5, 164, 723, -1, 27, 1, 51 }, + { 0x0, 0x0, 165, -1, 1011, 0, 1, 65 }, + { 0x1, 0x1, 167, -1, -1, 28, 1, 35 }, + { 0x1, 0x1, 168, 749, -1, 27, 1, 35 }, + { 0x1, 0x1, 169, -1, 441, 0, 1, 18 }, + { 0x7, 0x7, 169, 939, 441, 0, 1, 18 }, + { 0x1, 0x1, 169, 940, 441, 2, 1, 18 }, + { 0x0, 0x0, 169, 941, 152, 0, 0, -1 }, + { 0x21, 0x21, 169, -1, 441, 0, 1, 18 }, + { 0x27, 0x27, 169, 942, 441, 0, 1, 18 }, + { 0x9, 0x9, 169, 943, 441, 2, 1, 18 }, + { 0x0, 0x0, 169, 944, 156, 0, 0, -1 }, + { 0x11, 0x11, 169, -1, 441, 0, 1, 18 }, + { 0x17, 0x17, 169, 945, 441, 0, 1, 18 }, + { 0x5, 0x5, 169, 946, 441, 2, 1, 18 }, + { 0x0, 0x0, 169, 947, 162, 0, 0, -1 }, + { 0x8000011, 0x8000011, 169, -1, 441, 0, 1, 18 }, + { 0x8000017, 0x8000017, 169, 948, 441, 0, 1, 18 }, + { 0x2000005, 0x2000005, 169, 949, 441, 2, 1, 18 }, + { 0x0, 0x0, 169, 950, 168, 0, 0, -1 }, + { 0x8000001, 0x8000001, 169, -1, 441, 0, 1, 18 }, + { 0x8000007, 0x8000007, 169, 951, 441, 0, 1, 18 }, + { 0x2000001, 0x2000001, 169, 952, 441, 2, 1, 18 }, + { 0x0, 0x0, 169, 953, 174, 0, 0, -1 }, + { 0x1, 0x1, 169, -1, 443, 0, 1, 24 }, + { 0x7, 0x7, 169, 954, 443, 0, 1, 24 }, + { 0x1, 0x1, 169, 955, 443, 2, 1, 24 }, + { 0x0, 0x0, 169, 956, 181, 0, 0, -1 }, + { 0x21, 0x21, 169, -1, 443, 0, 1, 24 }, + { 0x27, 0x27, 169, 957, 443, 0, 1, 24 }, + { 0x9, 0x9, 169, 958, 443, 2, 1, 24 }, + { 0x0, 0x0, 169, 959, 185, 0, 0, -1 }, + { 0x11, 0x11, 169, -1, 443, 0, 1, 24 }, + { 0x17, 0x17, 169, 960, 443, 0, 1, 24 }, + { 0x5, 0x5, 169, 961, 443, 2, 1, 24 }, + { 0x0, 0x0, 169, 962, 191, 0, 0, -1 }, + { 0x19, 0x19, 169, -1, 443, 0, 1, 24 }, + { 0x1f, 0x1f, 169, 963, 443, 0, 1, 24 }, + { 0x7, 0x7, 169, 964, 443, 2, 1, 24 }, + { 0x0, 0x0, 169, 965, 197, 0, 0, -1 }, + { 0x9, 0x9, 169, -1, 443, 0, 1, 24 }, + { 0xf, 0xf, 169, 966, 443, 0, 1, 24 }, + { 0x3, 0x3, 169, 967, 443, 2, 1, 24 }, + { 0x0, 0x0, 169, 968, 203, 0, 0, -1 }, + { 0x1001, 0x1001, 169, -1, 445, 9, 1, 69 }, + { 0x1007, 0x1007, 169, 969, 445, 9, 1, 69 }, + { 0x401, 0x401, 169, 970, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 971, 211, 0, 0, -1 }, + { 0x1009, 0x1009, 169, -1, 445, 9, 1, 69 }, + { 0x100f, 0x100f, 169, 972, 445, 9, 1, 69 }, + { 0x403, 0x403, 169, 973, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 974, 215, 0, 0, -1 }, + { 0x801, 0x801, 169, -1, 445, 9, 1, 69 }, + { 0x807, 0x807, 169, 975, 445, 9, 1, 69 }, + { 0x201, 0x201, 169, 976, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 977, 219, 0, 0, -1 }, + { 0x809, 0x809, 169, -1, 445, 9, 1, 69 }, + { 0x80f, 0x80f, 169, 978, 445, 9, 1, 69 }, + { 0x203, 0x203, 169, 979, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 980, 223, 0, 0, -1 }, + { 0x3001, 0x3001, 169, -1, 445, 9, 1, 69 }, + { 0x3007, 0x3007, 169, 981, 445, 9, 1, 69 }, + { 0xc01, 0xc01, 169, 982, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 983, 227, 0, 0, -1 }, + { 0x3009, 0x3009, 169, -1, 445, 9, 1, 69 }, + { 0x300f, 0x300f, 169, 984, 445, 9, 1, 69 }, + { 0xc03, 0xc03, 169, 985, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 986, 231, 0, 0, -1 }, + { 0x2801, 0x2801, 169, -1, 445, 9, 1, 69 }, + { 0x2807, 0x2807, 169, 987, 445, 9, 1, 69 }, + { 0xa01, 0xa01, 169, 988, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 989, 235, 0, 0, -1 }, + { 0x2809, 0x2809, 169, -1, 445, 9, 1, 69 }, + { 0x280f, 0x280f, 169, 990, 445, 9, 1, 69 }, + { 0xa03, 0xa03, 169, 991, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 992, 239, 0, 0, -1 }, + { 0x2001, 0x2001, 169, -1, 445, 9, 1, 69 }, + { 0x2007, 0x2007, 169, 993, 445, 9, 1, 69 }, + { 0x801, 0x801, 169, 994, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 995, 243, 0, 0, -1 }, + { 0x2009, 0x2009, 169, -1, 445, 9, 1, 69 }, + { 0x200f, 0x200f, 169, 996, 445, 9, 1, 69 }, + { 0x803, 0x803, 169, 997, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 998, 247, 0, 0, -1 }, + { 0x1, 0x1, 169, -1, 445, 9, 1, 69 }, + { 0x7, 0x7, 169, 999, 445, 9, 1, 69 }, + { 0x1, 0x1, 169, 1000, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 1001, 251, 0, 0, -1 }, + { 0x9, 0x9, 169, -1, 445, 9, 1, 69 }, + { 0xf, 0xf, 169, 1002, 445, 9, 1, 69 }, + { 0x3, 0x3, 169, 1003, 445, 11, 1, 69 }, + { 0x0, 0x0, 169, 1004, 255, 0, 0, -1 }, + { 0x1, 0x1, 170, 676, -1, 28, 1, 134 }, + { 0x1, 0x1, 170, 677, -1, 28, 1, 135 }, + { 0x1, 0x1, 170, 678, -1, 28, 1, 128 }, + { 0x1, 0x1, 170, 679, -1, 28, 1, 126 }, + { 0x1, 0x1, 170, 680, -1, 28, 1, 131 }, + { 0x1, 0x1, 170, 681, -1, 28, 1, 127 }, + { 0x1, 0x1, 170, 682, -1, 28, 1, 129 }, + { 0x1, 0x1, 170, 683, -1, 28, 1, 126 }, + { 0x1, 0x1, 170, 684, -1, 28, 1, 130 }, + { 0x1, 0x1, 170, 685, -1, 28, 1, 137 }, + { 0x1, 0x1, 170, 686, -1, 28, 1, 139 }, + { 0x1, 0x1, 170, 687, -1, 28, 1, 141 }, + { 0x1, 0x1, 170, 688, -1, 28, 1, 138 }, + { 0x1, 0x1, 170, 689, -1, 28, 1, 140 }, + { 0x1, 0x1, 170, 690, -1, 28, 1, 137 }, + { 0x1, 0x1, 170, 672, -1, 28, 1, 142 }, + { 0x1, 0x1, 170, 673, -1, 28, 1, 143 }, + { 0x1, 0x1, 170, 674, -1, 28, 1, 144 }, + { 0x1, 0x1, 170, 675, -1, 28, 1, 145 }, + { 0x1, 0x1, 171, 691, -1, 29, 1, 142 }, + { 0x1, 0x1, 171, 692, -1, 29, 1, 143 }, + { 0x1, 0x1, 171, 693, -1, 29, 1, 144 }, + { 0x1, 0x1, 171, 694, -1, 29, 1, 145 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 134 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 135 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 128 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 126 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 131 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 127 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 129 }, + { 0x3, 0x3, 172, 753, -1, 28, 1, 126 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 130 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 137 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 139 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 141 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 138 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 140 }, + { 0x3, 0x3, 172, 754, -1, 28, 1, 137 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 142 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 143 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 144 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 145 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 132 }, + { 0x3, 0x3, 172, 734, -1, 28, 1, 132 }, + { 0x3, 0x3, 172, -1, -1, 28, 1, 133 }, + { 0x3, 0x3, 172, 735, -1, 28, 1, 132 }, + { 0x0, 0x0, 173, 1036, 95, 0, 0, -1 }, + { 0x0, 0x0, 173, 1037, 97, 0, 1, 3 }, + { 0x11, 0x31, 174, 1010, 99, 33, 1, 6 }, + { 0x2200001, 0x2200001, 174, -1, 99, 12, 1, 6 }, + { 0x11, 0x11, 174, -1, 99, 33, 1, 6 }, + { 0x1, 0x1, 174, -1, 99, 37, 1, 6 }, + { 0x2000001, 0x2000001, 174, -1, 99, 12, 1, 6 }, + { 0x200001, 0x200001, 174, -1, 104, 12, 1, 6 }, + { 0x1, 0x1, 174, 1010, 104, 33, 1, 6 }, + { 0x2000001, 0x2000001, 175, -1, -1, 12, 1, 6 }, + { 0x1, 0x1, 175, -1, -1, 37, 1, 6 }, + { 0x2200001, 0x2200001, 175, -1, -1, 12, 1, 6 }, + { 0x11, 0x11, 175, -1, -1, 33, 1, 6 }, + { 0x1, 0x1, 175, -1, -1, 12, 1, 7 }, + { 0x0, 0x0, 175, -1, -1, 0, 1, 7 }, + { 0x200001, 0x200001, 175, -1, -1, 12, 1, 7 }, + { 0x1, 0x1, 175, -1, -1, 33, 1, 7 }, + { 0x9, 0x9, 175, -1, -1, 33, 1, 7 }, + { 0x1, 0x1, 175, 1010, -1, 33, 1, 6 }, + { 0x1200001, 0x1200001, 175, -1, -1, 12, 1, 7 }, + { 0x200001, 0x200001, 175, -1, -1, 12, 1, 6 }, + { 0x0, 0x0, 176, -1, 767, 0, 0, -1 }, + { 0x9, 0x9, 176, -1, 1017, 33, 1, 51 }, + { 0x0, 0x0, 176, 1021, 783, 0, 0, -1 }, + { 0x7, 0x7, 176, 1022, -1, 27, 1, 51 }, + { 0x1, 0x1, 196, -1, -1, 27, 1, 12 }, + { 0x1, 0x1, 210, -1, -1, 29, 1, 0 }, + { 0x2, 0x3, 210, -1, -1, 27, 1, 35 }, + { 0x0, 0x0, 210, -1, -1, 0, 1, 35 }, + { 0x0, 0x0, 210, -1, -1, 0, 1, 0 }, + { 0x0, 0x0, 210, 1026, -1, 0, 1, 95 }, + { 0x0, 0x0, 210, 741, 336, 0, 0, -1 }, + { 0x1, 0x1, 211, -1, -1, 27, 1, 0 }, + { 0x1, 0x1, 212, -1, 653, 32, 1, 134 }, + { 0x1, 0x1, 212, -1, 654, 32, 1, 135 }, + { 0x1, 0x1, 212, -1, 695, 32, 1, 132 }, + { 0x1, 0x1, 212, 882, 695, 32, 1, 132 }, + { 0x0, 0x0, 213, -1, 264, 0, 0, -1 }, + { 0x0, 0x0, 213, -1, 265, 0, 0, -1 }, + { 0x0, 0x0, 213, 929, 306, 0, 0, -1 }, + { 0x0, 0x0, 213, 931, 308, 0, 0, -1 }, + { 0x0, 0x0, 213, 935, 312, 0, 0, -1 }, + { 0x0, 0x0, 217, 1027, 337, 0, 0, -1 }, + { 0x0, 0x0, 218, -1, 432, 0, 0, -1 }, + { 0x0, 0x0, 218, -1, 482, 0, 0, -1 }, + { 0x0, 0x0, 218, -1, -1, 0, 1, 123 }, + { 0x0, 0x0, 218, -1, -1, 0, 1, 68 }, + { 0x1, 0x1, 218, 756, 757, 36, 1, 67 }, + { 0x1, 0x1, 218, 756, 788, 36, 1, 67 }, + { 0x0, 0x0, 218, -1, 775, 0, 0, -1 }, + { 0x0, 0x0, 218, 879, -1, 0, 1, 35 }, + { 0x0, 0x0, 218, 756, 776, 0, 0, -1 }, + { 0x1, 0x1, 218, -1, -1, 36, 1, 67 }, + { 0x1, 0x1, 218, 880, -1, 31, 1, 136 }, + { 0x1, 0x1, 218, 877, 658, 32, 1, 127 }, + { 0x1, 0x1, 218, 878, 665, 32, 1, 138 }, + { 0x1, 0x1, 218, 881, -1, 31, 1, 146 }, + { 0x0, 0x0, 219, 787, -1, 0, 1, 30 }, + { 0x0, 0x0, 219, 788, -1, 0, 1, 67 }, + { 0x0, 0x0, 219, 789, -1, 0, 1, 46 }, + { 0x0, 0x0, 219, 790, -1, 0, 1, 41 }, + { 0x1, 0x1, 219, 791, -1, 12, 1, 60 }, + { 0x0, 0x0, 219, 792, -1, 0, 1, 55 }, + { 0x200001, 0x200001, 219, 793, -1, 12, 1, 60 }, + { 0x1, 0x1, 219, 794, -1, 33, 1, 55 }, + { 0x1000001, 0x1000001, 219, 795, -1, 12, 1, 60 }, + { 0x1, 0x1, 219, 796, -1, 36, 1, 55 }, + { 0x1200001, 0x1200001, 219, 797, -1, 12, 1, 50 }, + { 0x9, 0x9, 219, 798, -1, 33, 1, 50 }, + { 0x200001, 0x1200001, 219, 799, -1, 12, 1, 60 }, + { 0x1, 0x9, 219, 800, -1, 33, 1, 55 }, + { 0x1, 0x1, 219, 801, -1, 28, 1, 30 }, + { 0x0, 0x0, 219, 802, -1, 0, 1, 30 }, + { 0x3, 0x3, 219, 803, -1, 27, 1, 30 }, + { 0x1, 0x1, 219, 804, -1, 27, 1, 30 }, + { 0x1, 0x1, 219, 805, -1, 37, 1, 30 }, + { 0x1, 0x1, 219, -1, -1, 36, 1, 67 }, + { 0x1, 0x1, 219, 806, -1, 36, 1, 67 }, + { 0x0, 0x0, 219, 807, -1, 0, 1, 50 }, + { 0x1, 0x1, 219, 808, -1, 28, 1, 50 }, + { 0x1, 0x1, 219, 809, -1, 27, 1, 50 }, + { 0x1, 0x1, 219, 810, -1, 29, 1, 50 }, + { 0x3, 0x3, 219, 811, -1, 28, 1, 50 }, + { 0x5, 0x5, 219, 812, -1, 27, 1, 50 }, + { 0x7, 0x7, 219, 813, -1, 27, 1, 50 }, + { 0x3, 0x3, 219, 814, -1, 27, 1, 50 }, + { 0x0, 0x0, 219, 815, -1, 0, 1, 25 }, + { 0x0, 0x0, 219, 816, -1, 0, 1, 36 }, + { 0x1, 0x1, 220, 817, -1, 34, 1, 32 }, + { 0x1, 0x1, 220, 818, -1, 34, 1, 67 }, + { 0x1, 0x1, 220, 819, -1, 34, 1, 47 }, + { 0x1, 0x1, 220, 820, -1, 34, 1, 43 }, + { 0x400001, 0x400001, 220, 821, -1, 12, 1, 62 }, + { 0x1, 0x1, 220, 822, -1, 34, 1, 57 }, + { 0x600001, 0x600001, 220, 823, -1, 12, 1, 62 }, + { 0x3, 0x3, 220, 824, -1, 33, 1, 57 }, + { 0x1400001, 0x1400001, 220, 825, -1, 12, 1, 62 }, + { 0x5, 0x5, 220, 826, -1, 34, 1, 57 }, + { 0x1600001, 0x1600001, 220, 827, -1, 12, 1, 52 }, + { 0xb, 0xb, 220, 828, -1, 33, 1, 52 }, + { 0x600001, 0x1600001, 220, 829, -1, 12, 1, 62 }, + { 0x3, 0xb, 220, 830, -1, 33, 1, 57 }, + { 0x41, 0x41, 220, 831, -1, 28, 1, 32 }, + { 0x1, 0x1, 220, 832, -1, 34, 1, 32 }, + { 0x83, 0x83, 220, 833, -1, 27, 1, 32 }, + { 0x81, 0x81, 220, 834, -1, 27, 1, 32 }, + { 0x9, 0x9, 220, 835, -1, 34, 1, 32 }, + { 0x5, 0x5, 220, 836, -1, 34, 1, 67 }, + { 0x1, 0x1, 220, 837, -1, 34, 1, 52 }, + { 0x41, 0x41, 220, 838, -1, 28, 1, 52 }, + { 0x81, 0x81, 220, 839, -1, 27, 1, 52 }, + { 0x21, 0x21, 220, 840, -1, 29, 1, 52 }, + { 0x43, 0x43, 220, 841, -1, 28, 1, 52 }, + { 0x85, 0x85, 220, 842, -1, 27, 1, 52 }, + { 0x87, 0x87, 220, 843, -1, 27, 1, 52 }, + { 0x83, 0x83, 220, 844, -1, 27, 1, 52 }, + { 0x1, 0x1, 220, 845, -1, 34, 1, 27 }, + { 0x1, 0x1, 220, 846, -1, 34, 1, 38 }, + { 0x1, 0x1, 221, 847, -1, 35, 1, 33 }, + { 0x1, 0x1, 221, 848, -1, 35, 1, 67 }, + { 0x1, 0x1, 221, 849, -1, 35, 1, 48 }, + { 0x1, 0x1, 221, 850, -1, 35, 1, 44 }, + { 0x800001, 0x800001, 221, 851, -1, 12, 1, 63 }, + { 0x1, 0x1, 221, 852, -1, 35, 1, 58 }, + { 0xa00001, 0xa00001, 221, 853, -1, 12, 1, 63 }, + { 0x5, 0x5, 221, 854, -1, 33, 1, 58 }, + { 0x1800001, 0x1800001, 221, 855, -1, 12, 1, 63 }, + { 0x3, 0x3, 221, 856, -1, 35, 1, 58 }, + { 0x1a00001, 0x1a00001, 221, 857, -1, 12, 1, 53 }, + { 0xd, 0xd, 221, 858, -1, 33, 1, 53 }, + { 0xa00001, 0x1a00001, 221, 859, -1, 12, 1, 63 }, + { 0x5, 0xd, 221, 860, -1, 33, 1, 58 }, + { 0x81, 0x81, 221, 861, -1, 28, 1, 33 }, + { 0x1, 0x1, 221, 862, -1, 35, 1, 33 }, + { 0x103, 0x103, 221, 863, -1, 27, 1, 33 }, + { 0x101, 0x101, 221, 864, -1, 27, 1, 33 }, + { 0x5, 0x5, 221, 865, -1, 35, 1, 33 }, + { 0x3, 0x3, 221, 866, -1, 35, 1, 67 }, + { 0x1, 0x1, 221, 867, -1, 35, 1, 53 }, + { 0x81, 0x81, 221, 868, -1, 28, 1, 53 }, + { 0x101, 0x101, 221, 869, -1, 27, 1, 53 }, + { 0x41, 0x41, 221, 870, -1, 29, 1, 53 }, + { 0x83, 0x83, 221, 871, -1, 28, 1, 53 }, + { 0x105, 0x105, 221, 872, -1, 27, 1, 53 }, + { 0x107, 0x107, 221, 873, -1, 27, 1, 53 }, + { 0x103, 0x103, 221, 874, -1, 27, 1, 53 }, + { 0x1, 0x1, 221, 875, -1, 35, 1, 28 }, + { 0x1, 0x1, 221, 876, -1, 35, 1, 39 }, + { 0x3, 0x3, 222, -1, -1, 34, 1, 34 }, + { 0x3, 0x3, 222, -1, -1, 34, 1, 67 }, + { 0x3, 0x3, 222, -1, -1, 34, 1, 49 }, + { 0x3, 0x3, 222, -1, -1, 34, 1, 45 }, + { 0xc00001, 0xc00001, 222, -1, -1, 12, 1, 64 }, + { 0x3, 0x3, 222, 1012, -1, 34, 1, 59 }, + { 0xe00001, 0xe00001, 222, -1, -1, 12, 1, 64 }, + { 0x7, 0x7, 222, 1013, -1, 33, 1, 59 }, + { 0x1c00001, 0x1c00001, 222, -1, -1, 12, 1, 64 }, + { 0x7, 0x7, 222, 1014, -1, 34, 1, 59 }, + { 0x1e00001, 0x1e00001, 222, -1, -1, 12, 1, 54 }, + { 0xf, 0xf, 222, 1015, -1, 33, 1, 54 }, + { 0xe00001, 0x1e00001, 222, -1, -1, 12, 1, 64 }, + { 0x7, 0xf, 222, 1018, -1, 33, 1, 59 }, + { 0xc1, 0xc1, 222, -1, -1, 28, 1, 34 }, + { 0x3, 0x3, 222, 1005, -1, 34, 1, 34 }, + { 0x183, 0x183, 222, -1, -1, 27, 1, 34 }, + { 0x181, 0x181, 222, 1006, -1, 27, 1, 34 }, + { 0xb, 0xb, 222, -1, -1, 34, 1, 34 }, + { 0x7, 0x7, 222, -1, -1, 34, 1, 67 }, + { 0x3, 0x3, 222, -1, -1, 34, 1, 54 }, + { 0xc1, 0xc1, 222, -1, -1, 28, 1, 54 }, + { 0x181, 0x181, 222, -1, -1, 27, 1, 54 }, + { 0x61, 0x61, 222, -1, -1, 29, 1, 54 }, + { 0xc3, 0xc3, 222, -1, -1, 28, 1, 54 }, + { 0x185, 0x185, 222, -1, -1, 27, 1, 54 }, + { 0x187, 0x187, 222, -1, -1, 27, 1, 54 }, + { 0x183, 0x183, 222, -1, -1, 27, 1, 54 }, + { 0x3, 0x3, 222, -1, -1, 34, 1, 29 }, + { 0x3, 0x3, 222, -1, -1, 34, 1, 40 }, + { 0x3, 0x3, 223, -1, 659, 32, 1, 129 }, + { 0x3, 0x3, 223, -1, 666, 32, 1, 140 }, + { 0x1, 0x1, 224, -1, -1, 28, 1, 35 }, + { 0x0, 0x0, 231, -1, -1, 0, 1, 136 }, + { 0x0, 0x0, 231, -1, -1, 0, 1, 146 }, + { 0x1, 0x1, 232, -1, 697, 33, 1, 133 }, + { 0x0, 0x0, 232, -1, 695, 0, 1, 132 }, + { 0x0, 0x0, 233, 906, 342, 0, 0, -1 }, + { 0x0, 0x0, 233, 907, 345, 0, 0, -1 }, + { 0x1, 0x1, 233, 908, 121, 33, 1, 8 }, + { 0x8000001, 0x8000001, 233, 909, 123, 6, 1, 9 }, + { 0x0, 0x0, 233, 910, 349, 0, 0, -1 }, + { 0x1, 0x1, 233, 911, 124, 33, 1, 10 }, + { 0x0, 0x0, 233, 912, 353, 0, 0, -1 }, + { 0x1, 0x1, 233, 913, 125, 33, 1, 17 }, + { 0x0, 0x0, 233, 914, 358, 0, 0, -1 }, + { 0x1, 0x1, 233, 915, 126, 33, 1, 19 }, + { 0x0, 0x0, 233, 916, 361, 0, 0, -1 }, + { 0x0, 0x0, 233, 917, 365, 0, 0, -1 }, + { 0x1, 0x1, 233, 918, 128, 33, 1, 20 }, + { 0x8000001, 0x8000001, 233, 919, 128, 6, 1, 20 }, + { 0x0, 0x0, 233, 920, 369, 0, 0, -1 }, + { 0x1, 0x1, 233, 921, 129, 33, 1, 21 }, + { 0x0, 0x0, 233, 922, 373, 0, 0, -1 }, + { 0x0, 0x0, 233, 923, 377, 0, 0, -1 }, + { 0x1, 0x1, 233, 924, 130, 33, 1, 22 }, + { 0x8000001, 0x8000001, 233, 925, 130, 6, 1, 22 }, + { 0x0, 0x0, 233, 926, 381, 0, 0, -1 }, + { 0x1, 0x1, 233, 927, 131, 33, 1, 23 }, + { 0x0, 0x0, 234, -1, 339, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 346, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 121, 0, 1, 8 }, + { 0x1, 0x1, 234, -1, 123, 6, 1, 9 }, + { 0x0, 0x0, 234, -1, 350, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 124, 0, 1, 10 }, + { 0x0, 0x0, 234, -1, 354, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 125, 0, 1, 17 }, + { 0x0, 0x0, 234, -1, 355, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 126, 0, 1, 19 }, + { 0x0, 0x0, 234, -1, 362, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 366, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 128, 0, 1, 20 }, + { 0x1, 0x1, 234, -1, 128, 6, 1, 20 }, + { 0x0, 0x0, 234, -1, 370, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 129, 0, 1, 21 }, + { 0x0, 0x0, 234, -1, 374, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 378, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 130, 0, 1, 22 }, + { 0x1, 0x1, 234, -1, 130, 6, 1, 22 }, + { 0x0, 0x0, 234, -1, 382, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 131, 0, 1, 23 }, + { 0x1, 0x1, 234, -1, 383, 27, 1, 18 }, + { 0x0, 0x0, 234, -1, 383, 0, 1, 18 }, + { 0x0, 0x0, 234, -1, 176, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 180, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 388, 0, 1, 24 }, + { 0x0, 0x0, 234, -1, 209, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 395, 0, 0, -1 }, + { 0x0, 0x0, 234, -1, 397, 0, 0, -1 }, + { 0x1, 0x1, 237, 1023, -1, 29, 1, 0 }, + { 0x0, 0x0, 237, -1, -1, 0, 1, 0 }, + { 0x1, 0x1, 237, 1024, -1, 27, 1, 0 }, + { 0x3, 0x3, 256, -1, 441, 1, 1, 18 }, + { 0x3, 0x3, 256, -1, 441, 0, 1, 18 }, + { 0x0, 0x0, 256, -1, 153, 0, 0, -1 }, + { 0x13, 0x13, 256, -1, 441, 1, 1, 18 }, + { 0x23, 0x23, 256, -1, 441, 0, 1, 18 }, + { 0x0, 0x0, 256, -1, 157, 0, 0, -1 }, + { 0xb, 0xb, 256, -1, 441, 1, 1, 18 }, + { 0x13, 0x13, 256, -1, 441, 0, 1, 18 }, + { 0x0, 0x0, 256, -1, 163, 0, 0, -1 }, + { 0x400000b, 0x400000b, 256, -1, 441, 1, 1, 18 }, + { 0x8000013, 0x8000013, 256, -1, 441, 0, 1, 18 }, + { 0x0, 0x0, 256, -1, 169, 0, 0, -1 }, + { 0x4000003, 0x4000003, 256, -1, 441, 1, 1, 18 }, + { 0x8000003, 0x8000003, 256, -1, 441, 0, 1, 18 }, + { 0x0, 0x0, 256, -1, 175, 0, 0, -1 }, + { 0x3, 0x3, 256, -1, 443, 1, 1, 24 }, + { 0x3, 0x3, 256, -1, 443, 0, 1, 24 }, + { 0x0, 0x0, 256, -1, 182, 0, 0, -1 }, + { 0x13, 0x13, 256, -1, 443, 1, 1, 24 }, + { 0x23, 0x23, 256, -1, 443, 0, 1, 24 }, + { 0x0, 0x0, 256, -1, 186, 0, 0, -1 }, + { 0xb, 0xb, 256, -1, 443, 1, 1, 24 }, + { 0x13, 0x13, 256, -1, 443, 0, 1, 24 }, + { 0x0, 0x0, 256, -1, 192, 0, 0, -1 }, + { 0xf, 0xf, 256, -1, 443, 1, 1, 24 }, + { 0x1b, 0x1b, 256, -1, 443, 0, 1, 24 }, + { 0x0, 0x0, 256, -1, 198, 0, 0, -1 }, + { 0x7, 0x7, 256, -1, 443, 1, 1, 24 }, + { 0xb, 0xb, 256, -1, 443, 0, 1, 24 }, + { 0x0, 0x0, 256, -1, 204, 0, 0, -1 }, + { 0x803, 0x803, 256, -1, 445, 10, 1, 69 }, + { 0x1003, 0x1003, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 212, 0, 0, -1 }, + { 0x807, 0x807, 256, -1, 445, 10, 1, 69 }, + { 0x100b, 0x100b, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 216, 0, 0, -1 }, + { 0x403, 0x403, 256, -1, 445, 10, 1, 69 }, + { 0x803, 0x803, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 220, 0, 0, -1 }, + { 0x407, 0x407, 256, -1, 445, 10, 1, 69 }, + { 0x80b, 0x80b, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 224, 0, 0, -1 }, + { 0x1803, 0x1803, 256, -1, 445, 10, 1, 69 }, + { 0x3003, 0x3003, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 228, 0, 0, -1 }, + { 0x1807, 0x1807, 256, -1, 445, 10, 1, 69 }, + { 0x300b, 0x300b, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 232, 0, 0, -1 }, + { 0x1403, 0x1403, 256, -1, 445, 10, 1, 69 }, + { 0x2803, 0x2803, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 236, 0, 0, -1 }, + { 0x1407, 0x1407, 256, -1, 445, 10, 1, 69 }, + { 0x280b, 0x280b, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 240, 0, 0, -1 }, + { 0x1003, 0x1003, 256, -1, 445, 10, 1, 69 }, + { 0x2003, 0x2003, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 244, 0, 0, -1 }, + { 0x1007, 0x1007, 256, -1, 445, 10, 1, 69 }, + { 0x200b, 0x200b, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 248, 0, 0, -1 }, + { 0x3, 0x3, 256, -1, 445, 10, 1, 69 }, + { 0x3, 0x3, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 252, 0, 0, -1 }, + { 0x7, 0x7, 256, -1, 445, 10, 1, 69 }, + { 0xb, 0xb, 256, -1, 445, 9, 1, 69 }, + { 0x0, 0x0, 256, -1, 256, 0, 0, -1 }, + { 0x0, 0x0, 259, -1, 770, 0, 0, -1 }, + { 0x0, 0x0, 259, -1, 772, 0, 0, -1 }, + { 0x1, 0x1, 259, -1, -1, 28, 1, 31 }, + { 0x0, 0x0, 261, -1, -1, 0, 1, 0 }, + { 0x0, 0x1, 261, -1, -1, 29, 1, 0 }, + { 0x1, 0x1, 262, -1, -1, 12, 1, 4 }, + { 0x1, 0x1, 262, -1, -1, 12, 1, 66 }, + { 0x0, 0x0, 262, -1, 760, 0, 0, -1 }, + { 0x0, 0x0, 262, -1, 762, 0, 0, -1 }, + { 0x0, 0x0, 262, -1, 764, 0, 0, -1 }, + { 0x0, 0x0, 262, -1, 766, 0, 0, -1 }, + { 0x1, 0x1, 262, -1, -1, 12, 1, 61 }, + { 0x1, 0x1, 262, -1, -1, 12, 1, 51 }, + { 0x0, 0x0, 262, -1, 768, 0, 0, -1 }, + { 0x0, 0x0, 263, -1, 767, 0, 0, -1 }, + { 0x9, 0x9, 263, -1, 1017, 33, 1, 51 }, + { 0x0, 0x0, 263, -1, 784, 0, 0, -1 }, + { 0x3, 0x3, 263, -1, -1, 27, 1, 51 }, + { 0x0, 0x0, 267, -1, -1, 0, 1, 0 }, + { 0x3, 0x3, 268, 1025, -1, 27, 1, 0 }, + { 0x1, 0x1, 269, -1, -1, 28, 1, 0 }, + { 0x1, 0x1, 270, -1, -1, 27, 1, 95 }, + { 0x0, 0x0, 270, -1, 338, 0, 0, -1 }, + { 0x0, 0x0, 271, 1030, 270, 0, 0, -1 }, + { 0x0, 0x0, 271, 1031, 272, 0, 0, -1 }, + { 0x0, 0x0, 272, -1, 271, 0, 0, -1 }, + { 0x0, 0x0, 272, -1, 273, 0, 0, -1 }, + { 0x0, 0x0, 273, -1, -1, 0, 1, 42 }, + { 0x0, 0x0, 278, -1, -1, 0, 1, 35 }, + { 0x0, 0x0, 282, -1, 141, 0, 1, 31 }, + { 0x0, 0x0, 283, -1, -1, 0, 1, 73 }, + { 0x0, 0x0, 283, -1, 96, 0, 1, 3 }, + { 0x0, 0x0, 283, -1, 98, 0, 0, -1 }, +}; + +static const struct ia64_main_table +main_table[] = { + { 5, 1, 1, 0x10000000000ull, 0x1eff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 5, 1, 1, 0x10008000000ull, 0x1eff8000000ull, { 23, 24, 25, 3, 0 }, 0x0, 0, }, + { 5, 7, 1, 0x0ull, 0x0ull, { 23, 65, 25, 0, 0 }, 0x0, 0, }, + { 6, 1, 1, 0x12000000000ull, 0x1e000000000ull, { 23, 65, 26, 0, 0 }, 0x0, 1, }, + { 7, 1, 1, 0x10040000000ull, 0x1eff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 7, 1, 1, 0x10c00000000ull, 0x1ee00000000ull, { 23, 62, 25, 0, 0 }, 0x0, 0, }, + { 8, 1, 1, 0x10800000000ull, 0x1ee00000000ull, { 23, 62, 25, 0, 0 }, 0x0, 1, }, + { 9, 3, 1, 0x2c00000000ull, 0x1ee00000000ull, { 23, 2, 51, 52, 53 }, 0x221, 2, }, + { 10, 1, 1, 0x10060000000ull, 0x1eff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 10, 1, 1, 0x10160000000ull, 0x1eff8000000ull, { 23, 54, 25, 0, 0 }, 0x0, 0, }, + { 11, 1, 1, 0x10068000000ull, 0x1eff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 11, 1, 1, 0x10168000000ull, 0x1eff8000000ull, { 23, 54, 25, 0, 0 }, 0x0, 0, }, + { 14, 4, 0, 0x100000000ull, 0x1eff80011ffull, { 15, 0, 0, 0, 0 }, 0x40, 3, }, + { 14, 4, 0, 0x100000000ull, 0x1eff80011c0ull, { 15, 0, 0, 0, 0 }, 0x0, 135, }, + { 14, 4, 0, 0x100000000ull, 0x1eff80011c0ull, { 15, 0, 0, 0, 0 }, 0x40, 136, }, + { 14, 4, 0, 0x108000100ull, 0x1eff80011c0ull, { 15, 0, 0, 0, 0 }, 0x200, 736, }, + { 14, 4, 0, 0x108000100ull, 0x1eff80011c0ull, { 15, 0, 0, 0, 0 }, 0x240, 737, }, + { 14, 4, 1, 0x2000000000ull, 0x1ee00001000ull, { 14, 15, 0, 0, 0 }, 0x0, 113, }, + { 14, 4, 1, 0x2000000000ull, 0x1ee00001000ull, { 14, 15, 0, 0, 0 }, 0x40, 114, }, + { 14, 4, 0, 0x8000000000ull, 0x1ee000011ffull, { 80, 0, 0, 0, 0 }, 0x40, 4, }, + { 14, 4, 0, 0x8000000000ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x0, 137, }, + { 14, 4, 0, 0x8000000000ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x40, 138, }, + { 14, 4, 0, 0x8000000080ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x210, 1028, }, + { 14, 4, 0, 0x8000000080ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x250, 1029, }, + { 14, 4, 0, 0x8000000140ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x30, 119, }, + { 14, 4, 0, 0x8000000140ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x70, 120, }, + { 14, 4, 0, 0x8000000180ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x230, 117, }, + { 14, 4, 0, 0x8000000180ull, 0x1ee000011c0ull, { 80, 0, 0, 0, 0 }, 0x270, 118, }, + { 14, 4, 1, 0xa000000000ull, 0x1ee00001000ull, { 14, 80, 0, 0, 0 }, 0x0, 115, }, + { 14, 4, 1, 0xa000000000ull, 0x1ee00001000ull, { 14, 80, 0, 0, 0 }, 0x40, 116, }, + { 15, 4, 0, 0x0ull, 0x1e1f8000000ull, { 64, 0, 0, 0, 0 }, 0x0, 107, }, + { 15, 5, 0, 0x0ull, 0x1e3f8000000ull, { 64, 0, 0, 0, 0 }, 0x0, 333, }, + { 15, 2, 0, 0x0ull, 0x1eff8000000ull, { 64, 0, 0, 0, 0 }, 0x2, 431, }, + { 15, 3, 0, 0x0ull, 0x1eff8000000ull, { 64, 0, 0, 0, 0 }, 0x0, 481, }, + { 15, 6, 0, 0x0ull, 0x1eff8000000ull, { 68, 0, 0, 0, 0 }, 0x0, 1032, }, + { 15, 7, 0, 0x0ull, 0x0ull, { 64, 0, 0, 0, 0 }, 0x0, 5, }, + { 16, 6, 0, 0x18000000000ull, 0x1ee000011ffull, { 81, 0, 0, 0, 0 }, 0x40, 4, }, + { 16, 6, 0, 0x18000000000ull, 0x1ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x0, 137, }, + { 16, 6, 0, 0x18000000000ull, 0x1ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x40, 138, }, + { 16, 6, 1, 0x1a000000000ull, 0x1ee00001000ull, { 14, 81, 0, 0, 0 }, 0x0, 115, }, + { 16, 6, 1, 0x1a000000000ull, 0x1ee00001000ull, { 14, 81, 0, 0, 0 }, 0x40, 116, }, + { 17, 4, 0, 0x4080000000ull, 0x1e9f800003full, { 15, 76, 0, 0, 0 }, 0x20, 307, }, + { 17, 4, 0, 0x4080000000ull, 0x1e9f800003full, { 15, 76, 0, 0, 0 }, 0x60, 309, }, + { 17, 4, 0, 0xe000000000ull, 0x1e80000003full, { 80, 76, 0, 0, 0 }, 0x20, 310, }, + { 17, 4, 0, 0xe000000000ull, 0x1e80000003full, { 80, 76, 0, 0, 0 }, 0x60, 311, }, + { 18, 4, 0, 0x60000000ull, 0x1e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x2c, 74, }, + { 22, 2, 0, 0x200000000ull, 0x1ee00000000ull, { 24, 79, 0, 0, 0 }, 0x0, 742, }, + { 22, 3, 0, 0x800000000ull, 0x1ee00000000ull, { 23, 80, 0, 0, 0 }, 0x0, 76, }, + { 22, 3, 0, 0xc00000000ull, 0x1ee00000000ull, { 17, 80, 0, 0, 0 }, 0x0, 76, }, + { 22, 3, 0, 0x2200000000ull, 0x1ee00000000ull, { 24, 79, 0, 0, 0 }, 0x0, 743, }, + { 22, 3, 0, 0x2600000000ull, 0x1ee00000000ull, { 18, 79, 0, 0, 0 }, 0x0, 744, }, + { 22, 7, 0, 0x0ull, 0x0ull, { 24, 79, 0, 0, 0 }, 0x0, 745, }, + { 25, 4, 0, 0x20000000ull, 0x1e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x224, 6, }, + { 26, 1, 2, 0x18000000000ull, 0x1fe00001000ull, { 21, 22, 24, 25, 0 }, 0x0, 316, }, + { 26, 1, 2, 0x18000000000ull, 0x1fe00001000ull, { 22, 21, 25, 24, 0 }, 0x0, 454, }, + { 26, 1, 2, 0x18000000000ull, 0x1fe00001000ull, { 21, 22, 25, 24, 0 }, 0x0, 416, }, + { 26, 1, 2, 0x18000000000ull, 0x1fe00001000ull, { 22, 21, 24, 25, 0 }, 0x0, 407, }, + { 26, 1, 2, 0x18200000000ull, 0x1fe00001000ull, { 21, 22, 24, 25, 0 }, 0x40, 317, }, + { 26, 1, 2, 0x19000000000ull, 0x1fe00001000ull, { 21, 22, 6, 25, 0 }, 0x0, 408, }, + { 26, 1, 2, 0x19000000000ull, 0x1fe00001000ull, { 21, 22, 6, 25, 0 }, 0x40, 409, }, + { 26, 1, 2, 0x18800000000ull, 0x1ee00001000ull, { 21, 22, 54, 25, 0 }, 0x0, 316, }, + { 26, 1, 2, 0x18800000000ull, 0x1ee00001000ull, { 21, 22, 56, 25, 0 }, 0x0, 457, }, + { 26, 1, 2, 0x18800000000ull, 0x1ee00001000ull, { 22, 21, 56, 25, 0 }, 0x0, 419, }, + { 26, 1, 2, 0x18800000000ull, 0x1ee00001000ull, { 22, 21, 54, 25, 0 }, 0x0, 407, }, + { 26, 1, 2, 0x18a00000000ull, 0x1ee00001000ull, { 21, 22, 54, 25, 0 }, 0x40, 317, }, + { 26, 1, 2, 0x1a800000000ull, 0x1ee00001000ull, { 21, 22, 58, 25, 0 }, 0x0, 464, }, + { 26, 1, 2, 0x1a800000000ull, 0x1ee00001000ull, { 22, 21, 58, 25, 0 }, 0x0, 425, }, + { 26, 1, 2, 0x1c200000000ull, 0x1fe00001000ull, { 22, 21, 24, 25, 0 }, 0x40, 318, }, + { 26, 1, 2, 0x1d000000000ull, 0x1fe00001000ull, { 22, 21, 6, 25, 0 }, 0x40, 410, }, + { 26, 1, 2, 0x1ca00000000ull, 0x1ee00001000ull, { 22, 21, 54, 25, 0 }, 0x40, 318, }, + { 27, 1, 2, 0x18400000000ull, 0x1fe00001000ull, { 21, 22, 24, 25, 0 }, 0x0, 316, }, + { 27, 1, 2, 0x18400000000ull, 0x1fe00001000ull, { 22, 21, 25, 24, 0 }, 0x0, 454, }, + { 27, 1, 2, 0x18400000000ull, 0x1fe00001000ull, { 21, 22, 25, 24, 0 }, 0x0, 416, }, + { 27, 1, 2, 0x18400000000ull, 0x1fe00001000ull, { 22, 21, 24, 25, 0 }, 0x0, 407, }, + { 27, 1, 2, 0x18600000000ull, 0x1fe00001000ull, { 21, 22, 24, 25, 0 }, 0x40, 317, }, + { 27, 1, 2, 0x19400000000ull, 0x1fe00001000ull, { 21, 22, 6, 25, 0 }, 0x0, 408, }, + { 27, 1, 2, 0x19400000000ull, 0x1fe00001000ull, { 21, 22, 6, 25, 0 }, 0x40, 409, }, + { 27, 1, 2, 0x18c00000000ull, 0x1ee00001000ull, { 21, 22, 54, 25, 0 }, 0x0, 319, }, + { 27, 1, 2, 0x18c00000000ull, 0x1ee00001000ull, { 21, 22, 56, 25, 0 }, 0x0, 457, }, + { 27, 1, 2, 0x18c00000000ull, 0x1ee00001000ull, { 22, 21, 56, 25, 0 }, 0x0, 419, }, + { 27, 1, 2, 0x18c00000000ull, 0x1ee00001000ull, { 22, 21, 54, 25, 0 }, 0x0, 411, }, + { 27, 1, 2, 0x18e00000000ull, 0x1ee00001000ull, { 21, 22, 54, 25, 0 }, 0x40, 317, }, + { 27, 1, 2, 0x1ac00000000ull, 0x1ee00001000ull, { 21, 22, 55, 25, 0 }, 0x0, 478, }, + { 27, 1, 2, 0x1ac00000000ull, 0x1ee00001000ull, { 21, 22, 57, 25, 0 }, 0x0, 464, }, + { 27, 1, 2, 0x1ac00000000ull, 0x1ee00001000ull, { 22, 21, 57, 25, 0 }, 0x0, 425, }, + { 27, 1, 2, 0x1ac00000000ull, 0x1ee00001000ull, { 22, 21, 55, 25, 0 }, 0x0, 415, }, + { 27, 1, 2, 0x1c600000000ull, 0x1fe00001000ull, { 22, 21, 24, 25, 0 }, 0x40, 318, }, + { 27, 1, 2, 0x1d400000000ull, 0x1fe00001000ull, { 22, 21, 6, 25, 0 }, 0x40, 410, }, + { 27, 1, 2, 0x1ce00000000ull, 0x1ee00001000ull, { 22, 21, 54, 25, 0 }, 0x40, 318, }, + { 28, 3, 1, 0x8008000000ull, 0x1fff8000000ull, { 23, 32, 24, 1, 0 }, 0x0, 81, }, + { 29, 3, 1, 0x8048000000ull, 0x1fff8000000ull, { 23, 32, 24, 1, 0 }, 0x0, 81, }, + { 30, 3, 1, 0x8088000000ull, 0x1fff8000000ull, { 23, 32, 24, 1, 0 }, 0x0, 81, }, + { 31, 3, 1, 0x80c8000000ull, 0x1fff8000000ull, { 23, 32, 24, 1, 0 }, 0x0, 81, }, + { 33, 4, 0, 0x10000000ull, 0x1e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x224, 7, }, + { 35, 2, 1, 0xc0000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 446, }, + { 36, 2, 1, 0xc8000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 446, }, + { 39, 2, 1, 0x8000000000ull, 0x1e000000000ull, { 23, 24, 25, 46, 71 }, 0x0, 8, }, + { 39, 2, 1, 0xa600000000ull, 0x1ee04000000ull, { 23, 24, 44, 72, 0 }, 0x0, 1035, }, + { 39, 2, 1, 0xa604000000ull, 0x1ee04000000ull, { 23, 54, 44, 72, 0 }, 0x0, 1035, }, + { 39, 2, 1, 0xae00000000ull, 0x1ee00000000ull, { 23, 47, 25, 45, 72 }, 0x0, 8, }, + { 43, 4, 0, 0x80000000ull, 0x1e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x20, 9, }, + { 48, 2, 1, 0xa400000000ull, 0x1ee00002000ull, { 23, 25, 75, 72, 0 }, 0x0, 10, }, + { 50, 5, 1, 0x80000000ull, 0x1e3f80fe000ull, { 17, 19, 0, 0, 0 }, 0x40, 11, }, + { 51, 5, 1, 0x10008000000ull, 0x1fff8000000ull, { 17, 19, 18, 0, 0 }, 0x40, 12, }, + { 52, 5, 1, 0xb8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 52, 5, 1, 0xb8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 53, 5, 1, 0xb0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 53, 5, 1, 0xb0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 54, 5, 1, 0x160000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 11, }, + { 55, 5, 1, 0x168000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 11, }, + { 57, 3, 0, 0x2180000000ull, 0x1eff8000000ull, { 25, 0, 0, 0, 0 }, 0x0, 14, }, + { 58, 5, 0, 0x40000000ull, 0x1eff8000000ull, { 78, 0, 0, 0, 0 }, 0x0, 758, }, + { 58, 5, 0, 0x40000000ull, 0x1eff8000000ull, { 78, 0, 0, 0, 0 }, 0x40, 15, }, + { 59, 5, 2, 0xa000000000ull, 0x1e000001000ull, { 21, 22, 18, 59, 0 }, 0x0, 483, }, + { 59, 5, 2, 0xa000000000ull, 0x1e000001000ull, { 22, 21, 18, 59, 0 }, 0x40, 562, }, + { 60, 5, 0, 0x28000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 759, }, + { 60, 5, 0, 0x28000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x40, 16, }, + { 61, 5, 2, 0x8000000000ull, 0x1fe00001000ull, { 21, 22, 18, 19, 0 }, 0x0, 320, }, + { 61, 5, 2, 0x8000000000ull, 0x1fe00001000ull, { 21, 22, 18, 19, 0 }, 0x40, 321, }, + { 61, 5, 2, 0x9000000000ull, 0x1fe00001000ull, { 21, 22, 19, 18, 0 }, 0x0, 412, }, + { 61, 5, 2, 0x9000000000ull, 0x1fe00001000ull, { 21, 22, 19, 18, 0 }, 0x40, 413, }, + { 61, 5, 2, 0x8000000000ull, 0x1fe00001000ull, { 22, 21, 18, 19, 0 }, 0x0, 545, }, + { 61, 5, 2, 0x8000000000ull, 0x1fe00001000ull, { 22, 21, 18, 19, 0 }, 0x40, 546, }, + { 61, 5, 2, 0x9000000000ull, 0x1fe00001000ull, { 22, 21, 19, 18, 0 }, 0x0, 549, }, + { 61, 5, 2, 0x9000000000ull, 0x1fe00001000ull, { 22, 21, 19, 18, 0 }, 0x40, 550, }, + { 62, 5, 1, 0xc0000000ull, 0x1eff8000000ull, { 17, 18, 0, 0, 0 }, 0x0, 401, }, + { 62, 5, 1, 0xc0000000ull, 0x1eff8000000ull, { 17, 18, 0, 0, 0 }, 0x40, 402, }, + { 62, 5, 1, 0xe0000000ull, 0x1e3f8000000ull, { 17, 18, 0, 0, 0 }, 0x0, 1033, }, + { 62, 5, 1, 0x10008000000ull, 0x1fff80fe000ull, { 17, 19, 0, 0, 0 }, 0x40, 1034, }, + { 63, 3, 1, 0x8488000000ull, 0x1fff8000000ull, { 23, 32, 70, 0, 0 }, 0x0, 82, }, + { 64, 3, 1, 0x84c8000000ull, 0x1fff8000000ull, { 23, 32, 70, 0, 0 }, 0x0, 82, }, + { 67, 3, 0, 0x60000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x21, 17, }, + { 68, 5, 1, 0x10000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x0, 142, }, + { 68, 5, 1, 0x10000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x40, 18, }, + { 69, 5, 1, 0xa8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 69, 5, 1, 0xa8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 70, 5, 1, 0x80000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 564, }, + { 71, 5, 1, 0xa0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 71, 5, 1, 0xa0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 72, 5, 1, 0x1c8000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 447, }, + { 73, 5, 1, 0x10000000000ull, 0x1fc000fe000ull, { 17, 19, 20, 0, 0 }, 0x40, 12, }, + { 74, 5, 1, 0x14000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x0, 144, }, + { 74, 5, 1, 0x14000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x40, 19, }, + { 75, 5, 1, 0x88000000ull, 0x1e3f8000000ull, { 17, 19, 0, 0, 0 }, 0xc0, 11, }, + { 76, 5, 1, 0x88000000ull, 0x1e3f80fe000ull, { 17, 19, 0, 0, 0 }, 0x40, 11, }, + { 77, 5, 1, 0x18000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x0, 144, }, + { 77, 5, 1, 0x18000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x40, 19, }, + { 78, 5, 1, 0x18000000000ull, 0x1fc000fe000ull, { 17, 19, 20, 0, 0 }, 0x40, 12, }, + { 79, 5, 1, 0x10008000000ull, 0x1fff80fe000ull, { 17, 19, 0, 0, 0 }, 0x40, 12, }, + { 80, 5, 1, 0x170000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 11, }, + { 81, 5, 1, 0x2080000000ull, 0x1e3f80fe000ull, { 17, 19, 0, 0, 0 }, 0x40, 11, }, + { 82, 5, 1, 0x140000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 11, }, + { 83, 5, 1, 0x20b8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 83, 5, 1, 0x20b8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 84, 5, 1, 0x20b0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 84, 5, 1, 0x20b0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 85, 5, 1, 0x2180000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 322, }, + { 85, 5, 1, 0x2180000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 323, }, + { 86, 5, 1, 0x20c0000000ull, 0x1eff8000000ull, { 17, 18, 0, 0, 0 }, 0x0, 401, }, + { 86, 5, 1, 0x20c0000000ull, 0x1eff8000000ull, { 17, 18, 0, 0, 0 }, 0x40, 402, }, + { 87, 5, 1, 0x13000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x0, 756, }, + { 87, 5, 1, 0x13000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x40, 13, }, + { 88, 5, 1, 0x20a8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 88, 5, 1, 0x20a8000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 89, 5, 1, 0x2080000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 564, }, + { 90, 5, 1, 0x20a0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 756, }, + { 90, 5, 1, 0x20a0000000ull, 0x1eff8000000ull, { 17, 18, 19, 0, 0 }, 0x40, 13, }, + { 91, 5, 1, 0x13000000000ull, 0x1fc000fe000ull, { 17, 19, 20, 0, 0 }, 0x40, 20, }, + { 92, 5, 1, 0x17000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x0, 756, }, + { 92, 5, 1, 0x17000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x40, 13, }, + { 93, 5, 1, 0x2088000000ull, 0x1e3f8000000ull, { 17, 19, 0, 0, 0 }, 0xc0, 11, }, + { 94, 5, 1, 0x2088000000ull, 0x1e3f80fe000ull, { 17, 19, 0, 0, 0 }, 0x40, 11, }, + { 95, 5, 1, 0x1b000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x0, 756, }, + { 95, 5, 1, 0x1b000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x40, 13, }, + { 96, 5, 1, 0x1b000000000ull, 0x1fc000fe000ull, { 17, 19, 20, 0, 0 }, 0x40, 20, }, + { 97, 5, 2, 0x2200000000ull, 0x1fe00000000ull, { 17, 22, 18, 19, 0 }, 0x0, 785, }, + { 97, 5, 2, 0x2200000000ull, 0x1fe00000000ull, { 17, 22, 18, 19, 0 }, 0x40, 21, }, + { 98, 5, 2, 0x3200000000ull, 0x1fe00000000ull, { 17, 22, 19, 0, 0 }, 0x0, 785, }, + { 98, 5, 2, 0x3200000000ull, 0x1fe00000000ull, { 17, 22, 19, 0, 0 }, 0x40, 21, }, + { 99, 5, 2, 0x200000000ull, 0x1fe00000000ull, { 17, 22, 18, 19, 0 }, 0x0, 785, }, + { 99, 5, 2, 0x200000000ull, 0x1fe00000000ull, { 17, 22, 18, 19, 0 }, 0x40, 21, }, + { 100, 5, 2, 0x1200000000ull, 0x1fe00000000ull, { 17, 22, 19, 0, 0 }, 0x0, 785, }, + { 100, 5, 2, 0x1200000000ull, 0x1fe00000000ull, { 17, 22, 19, 0, 0 }, 0x40, 21, }, + { 101, 5, 1, 0x1c000000000ull, 0x1f000000000ull, { 17, 19, 20, 18, 0 }, 0x0, 11, }, + { 102, 5, 0, 0x20000000ull, 0x1eff8000000ull, { 49, 50, 0, 0, 0 }, 0x0, 786, }, + { 102, 5, 0, 0x20000000ull, 0x1eff8000000ull, { 49, 50, 0, 0, 0 }, 0x40, 22, }, + { 103, 5, 1, 0x14008000000ull, 0x1fff8000000ull, { 17, 19, 18, 0, 0 }, 0x40, 12, }, + { 104, 5, 1, 0x1a0000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 23, }, + { 105, 5, 1, 0x1e0000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 448, }, + { 106, 3, 0, 0x100000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 16, }, + { 108, 5, 1, 0x178000000ull, 0x1e3f8000000ull, { 17, 18, 19, 0, 0 }, 0x0, 11, }, + { 113, 3, 1, 0x8708000000ull, 0x1ffc8000000ull, { 23, 18, 0, 0, 0 }, 0x0, 146, }, + { 122, 3, 0, 0x80000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 24, }, + { 122, 3, 0, 0x90000000ull, 0x1eff8000000ull, { 23, 0, 0, 0, 0 }, 0x0, 314, }, + { 122, 3, 0, 0x98000000ull, 0x1eff8000000ull, { 17, 0, 0, 0, 0 }, 0x0, 314, }, + { 123, 3, 0, 0x2170000000ull, 0x1eff8000000ull, { 24, 0, 0, 0, 0 }, 0xc, 147, }, + { 124, 3, 1, 0x2070000000ull, 0x1eff8000000ull, { 29, 24, 0, 0, 0 }, 0x8, 148, }, + { 124, 3, 1, 0x2078000000ull, 0x1eff8000000ull, { 30, 24, 0, 0, 0 }, 0x8, 434, }, + { 126, 3, 1, 0x8000000000ull, 0x1fff8000000ull, { 23, 32, 0, 0, 0 }, 0x0, 25, }, + { 126, 3, 1, 0x9000000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 25, }, + { 126, 3, 1, 0xa000000000ull, 0x1eff0000000ull, { 23, 32, 61, 0, 0 }, 0x0, 25, }, + { 127, 3, 1, 0x8040000000ull, 0x1fff8000000ull, { 23, 32, 0, 0, 0 }, 0x0, 25, }, + { 127, 3, 1, 0x9040000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 25, }, + { 127, 3, 1, 0xa040000000ull, 0x1eff0000000ull, { 23, 32, 61, 0, 0 }, 0x0, 25, }, + { 128, 3, 1, 0x8080000000ull, 0x1fff8000000ull, { 23, 32, 0, 0, 0 }, 0x0, 25, }, + { 128, 3, 1, 0x9080000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 25, }, + { 128, 3, 1, 0xa080000000ull, 0x1eff0000000ull, { 23, 32, 61, 0, 0 }, 0x0, 25, }, + { 129, 3, 1, 0x80c0000000ull, 0x1fff8000000ull, { 23, 32, 0, 0, 0 }, 0x0, 26, }, + { 129, 3, 1, 0x90c0000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 26, }, + { 129, 3, 1, 0xa0c0000000ull, 0x1eff0000000ull, { 23, 32, 61, 0, 0 }, 0x0, 26, }, + { 130, 3, 1, 0xc6c0000000ull, 0x1fff8000000ull, { 17, 32, 0, 0, 0 }, 0x0, 400, }, + { 130, 3, 1, 0xd6c0000000ull, 0x1fff8000000ull, { 17, 32, 24, 0, 0 }, 0x0, 400, }, + { 130, 3, 1, 0xe6c0000000ull, 0x1eff0000000ull, { 17, 32, 61, 0, 0 }, 0x0, 400, }, + { 131, 3, 1, 0xc040000000ull, 0x1fff8000000ull, { 17, 32, 0, 0, 0 }, 0x0, 27, }, + { 131, 3, 1, 0xd040000000ull, 0x1fff8000000ull, { 17, 32, 24, 0, 0 }, 0x0, 27, }, + { 131, 3, 1, 0xe040000000ull, 0x1eff0000000ull, { 17, 32, 61, 0, 0 }, 0x0, 27, }, + { 132, 3, 1, 0xc0c0000000ull, 0x1fff8000000ull, { 17, 32, 0, 0, 0 }, 0x0, 27, }, + { 132, 3, 1, 0xd0c0000000ull, 0x1fff8000000ull, { 17, 32, 24, 0, 0 }, 0x0, 27, }, + { 132, 3, 1, 0xe0c0000000ull, 0x1eff0000000ull, { 17, 32, 61, 0, 0 }, 0x0, 27, }, + { 133, 3, 1, 0xc000000000ull, 0x1fff8000000ull, { 17, 32, 0, 0, 0 }, 0x0, 27, }, + { 133, 3, 1, 0xd000000000ull, 0x1fff8000000ull, { 17, 32, 24, 0, 0 }, 0x0, 27, }, + { 133, 3, 1, 0xe000000000ull, 0x1eff0000000ull, { 17, 32, 61, 0, 0 }, 0x0, 27, }, + { 134, 3, 2, 0xc048000000ull, 0x1fff8000000ull, { 17, 18, 32, 0, 0 }, 0x0, 27, }, + { 134, 3, 2, 0xd048000000ull, 0x1fff8000000ull, { 17, 18, 32, 5, 0 }, 0x0, 27, }, + { 135, 3, 2, 0xc0c8000000ull, 0x1fff8000000ull, { 17, 18, 32, 0, 0 }, 0x0, 27, }, + { 135, 3, 2, 0xd0c8000000ull, 0x1fff8000000ull, { 17, 18, 32, 5, 0 }, 0x0, 27, }, + { 136, 3, 2, 0xc088000000ull, 0x1fff8000000ull, { 17, 18, 32, 0, 0 }, 0x0, 27, }, + { 136, 3, 2, 0xd088000000ull, 0x1fff8000000ull, { 17, 18, 32, 4, 0 }, 0x0, 27, }, + { 137, 3, 1, 0xc080000000ull, 0x1fff8000000ull, { 17, 32, 0, 0, 0 }, 0x0, 27, }, + { 137, 3, 1, 0xd080000000ull, 0x1fff8000000ull, { 17, 32, 24, 0, 0 }, 0x0, 27, }, + { 137, 3, 1, 0xe080000000ull, 0x1eff0000000ull, { 17, 32, 61, 0, 0 }, 0x0, 27, }, + { 140, 3, 0, 0xcb00000000ull, 0x1fff8000000ull, { 32, 0, 0, 0, 0 }, 0x0, 28, }, + { 140, 3, 0, 0xdb00000000ull, 0x1fff8000000ull, { 32, 24, 0, 0, 0 }, 0x0, 29, }, + { 140, 3, 0, 0xeb00000000ull, 0x1eff0000000ull, { 32, 61, 0, 0, 0 }, 0x0, 29, }, + { 141, 3, 0, 0x50000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x21, 30, }, + { 149, 3, 0, 0x110000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 31, }, + { 150, 2, 1, 0xe880000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 449, }, + { 151, 2, 1, 0xea80000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 449, }, + { 152, 2, 1, 0xf880000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 449, }, + { 153, 1, 1, 0x10800000000ull, 0x1fff80fe000ull, { 23, 25, 0, 0, 0 }, 0x0, 1, }, + { 153, 1, 1, 0x10800000000ull, 0x1ee07f00000ull, { 23, 62, 0, 0, 0 }, 0x40, 1, }, + { 153, 1, 1, 0x12000000000ull, 0x1e000300000ull, { 23, 65, 0, 0, 0 }, 0x40, 32, }, + { 153, 5, 1, 0x80000000ull, 0x1e3f8000000ull, { 17, 19, 0, 0, 0 }, 0xc0, 11, }, + { 153, 2, 1, 0xe00100000ull, 0x1ee00f01e00ull, { 14, 24, 0, 0, 0 }, 0x40, 33, }, + { 153, 2, 1, 0xe00000000ull, 0x1ee00f01e00ull, { 14, 24, 77, 0, 0 }, 0x0, 313, }, + { 153, 2, 1, 0x188000000ull, 0x1eff8000000ull, { 23, 15, 0, 0, 0 }, 0x0, 34, }, + { 153, 2, 1, 0x600000000ull, 0x1ee00000000ull, { 8, 24, 63, 0, 0 }, 0x0, 35, }, + { 153, 2, 1, 0x400000000ull, 0x1ee00000000ull, { 9, 67, 0, 0, 0 }, 0x0, 36, }, + { 153, 2, 1, 0x180000000ull, 0x1eff8000000ull, { 23, 7, 0, 0, 0 }, 0x0, 8, }, + { 153, 2, 1, 0x198000000ull, 0x1eff8000000ull, { 23, 8, 0, 0, 0 }, 0x0, 37, }, + { 153, 2, 1, 0x150000000ull, 0x1eff8000000ull, { 13, 24, 0, 0, 0 }, 0x0, 435, }, + { 153, 2, 1, 0x50000000ull, 0x1eff8000000ull, { 13, 54, 0, 0, 0 }, 0x0, 435, }, + { 153, 2, 1, 0x190000000ull, 0x1eff8000000ull, { 23, 13, 0, 0, 0 }, 0x0, 436, }, + { 153, 3, 1, 0x140000000ull, 0x1eff8000000ull, { 13, 54, 0, 0, 0 }, 0x0, 484, }, + { 153, 3, 1, 0x2150000000ull, 0x1eff8000000ull, { 13, 24, 0, 0, 0 }, 0x0, 484, }, + { 153, 3, 1, 0x2110000000ull, 0x1eff8000000ull, { 23, 13, 0, 0, 0 }, 0x0, 485, }, + { 153, 3, 1, 0x2160000000ull, 0x1eff8000000ull, { 16, 24, 0, 0, 0 }, 0x8, 38, }, + { 153, 3, 1, 0x2120000000ull, 0x1eff8000000ull, { 23, 16, 0, 0, 0 }, 0x8, 39, }, + { 153, 3, 1, 0x2168000000ull, 0x1eff8000000ull, { 11, 24, 0, 0, 0 }, 0x8, 40, }, + { 153, 3, 1, 0x2148000000ull, 0x1eff8000000ull, { 12, 24, 0, 0, 0 }, 0x0, 41, }, + { 153, 3, 1, 0x2128000000ull, 0x1eff8000000ull, { 23, 10, 0, 0, 0 }, 0x8, 42, }, + { 153, 3, 1, 0x2108000000ull, 0x1eff8000000ull, { 23, 12, 0, 0, 0 }, 0x0, 43, }, + { 153, 3, 1, 0x2000000000ull, 0x1eff8000000ull, { 37, 24, 0, 0, 0 }, 0x8, 44, }, + { 153, 3, 1, 0x2008000000ull, 0x1eff8000000ull, { 28, 24, 0, 0, 0 }, 0x8, 45, }, + { 153, 3, 1, 0x2010000000ull, 0x1eff8000000ull, { 31, 24, 0, 0, 0 }, 0x8, 46, }, + { 153, 3, 1, 0x2018000000ull, 0x1eff8000000ull, { 34, 24, 0, 0, 0 }, 0x8, 47, }, + { 153, 3, 1, 0x2020000000ull, 0x1eff8000000ull, { 35, 24, 0, 0, 0 }, 0x8, 48, }, + { 153, 3, 1, 0x2028000000ull, 0x1eff8000000ull, { 36, 24, 0, 0, 0 }, 0x8, 49, }, + { 153, 3, 1, 0x2030000000ull, 0x1eff8000000ull, { 33, 24, 0, 0, 0 }, 0x8, 50, }, + { 153, 3, 1, 0x2080000000ull, 0x1eff8000000ull, { 23, 37, 0, 0, 0 }, 0x8, 51, }, + { 153, 3, 1, 0x2088000000ull, 0x1eff8000000ull, { 23, 28, 0, 0, 0 }, 0x8, 52, }, + { 153, 3, 1, 0x2090000000ull, 0x1eff8000000ull, { 23, 31, 0, 0, 0 }, 0x8, 53, }, + { 153, 3, 1, 0x2098000000ull, 0x1eff8000000ull, { 23, 34, 0, 0, 0 }, 0x8, 54, }, + { 153, 3, 1, 0x20a0000000ull, 0x1eff8000000ull, { 23, 35, 0, 0, 0 }, 0x8, 55, }, + { 153, 3, 1, 0x20a8000000ull, 0x1eff8000000ull, { 23, 36, 0, 0, 0 }, 0x0, 56, }, + { 153, 3, 1, 0x20b0000000ull, 0x1eff8000000ull, { 23, 33, 0, 0, 0 }, 0x8, 57, }, + { 153, 3, 1, 0x20b8000000ull, 0x1eff8000000ull, { 23, 27, 0, 0, 0 }, 0x0, 58, }, + { 153, 7, 1, 0x0ull, 0x0ull, { 23, 13, 0, 0, 0 }, 0x0, 59, }, + { 153, 7, 1, 0x0ull, 0x0ull, { 13, 54, 0, 0, 0 }, 0x0, 59, }, + { 153, 7, 1, 0x0ull, 0x0ull, { 13, 24, 0, 0, 0 }, 0x0, 59, }, + { 154, 6, 1, 0xc000000000ull, 0x1e000100000ull, { 23, 69, 0, 0, 0 }, 0x0, 8, }, + { 155, 2, 1, 0xeca0000000ull, 0x1fff0000000ull, { 23, 24, 73, 0, 0 }, 0x0, 0, }, + { 156, 2, 1, 0xeea0000000ull, 0x1fff0000000ull, { 23, 24, 74, 0, 0 }, 0x0, 0, }, + { 166, 4, 0, 0x4000000000ull, 0x1e1f8000000ull, { 64, 0, 0, 0, 0 }, 0x0, 107, }, + { 166, 5, 0, 0x8000000ull, 0x1e3f8000000ull, { 64, 0, 0, 0, 0 }, 0x0, 333, }, + { 166, 2, 0, 0x8000000ull, 0x1eff8000000ull, { 64, 0, 0, 0, 0 }, 0x2, 431, }, + { 166, 3, 0, 0x8000000ull, 0x1eff8000000ull, { 64, 0, 0, 0, 0 }, 0x0, 481, }, + { 166, 6, 0, 0x8000000ull, 0x1eff8000000ull, { 68, 0, 0, 0, 0 }, 0x0, 1032, }, + { 166, 7, 0, 0x0ull, 0x0ull, { 64, 0, 0, 0, 0 }, 0x0, 5, }, + { 174, 1, 1, 0x10070000000ull, 0x1eff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 174, 1, 1, 0x10170000000ull, 0x1eff8000000ull, { 23, 54, 25, 0, 0 }, 0x0, 0, }, + { 177, 2, 1, 0xea00000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 936, }, + { 178, 2, 1, 0xf820000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 937, }, + { 179, 1, 1, 0x10400000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 60, }, + { 180, 1, 1, 0x10600000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 60, }, + { 181, 1, 1, 0x11400000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 182, 1, 1, 0x10450000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 61, }, + { 183, 1, 1, 0x10650000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 61, }, + { 184, 1, 1, 0x10470000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 185, 1, 1, 0x10670000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 186, 1, 1, 0x10520000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 324, }, + { 187, 1, 1, 0x10720000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 324, }, + { 188, 1, 1, 0x11520000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 324, }, + { 189, 2, 1, 0xe850000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 1008, }, + { 190, 2, 1, 0xea70000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 191, 2, 1, 0xe810000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 1008, }, + { 192, 2, 1, 0xea30000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 193, 2, 1, 0xead0000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 449, }, + { 194, 2, 1, 0xe230000000ull, 0x1ff30000000ull, { 23, 24, 25, 41, 0 }, 0x0, 62, }, + { 195, 2, 1, 0xe690000000ull, 0x1fff0000000ull, { 23, 25, 0, 0, 0 }, 0x0, 0, }, + { 197, 3, 1, 0x21c0000000ull, 0x1eff8000000ull, { 23, 25, 24, 0, 0 }, 0x0, 729, }, + { 197, 3, 1, 0x20c0000000ull, 0x1eff8000000ull, { 23, 25, 48, 0, 0 }, 0x0, 729, }, + { 197, 3, 0, 0x2188000000ull, 0x1eff8000000ull, { 25, 48, 0, 0, 0 }, 0x0, 730, }, + { 198, 2, 1, 0xe8b0000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 199, 2, 1, 0xe240000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 199, 2, 1, 0xee50000000ull, 0x1fff0000000ull, { 23, 24, 38, 0, 0 }, 0x0, 0, }, + { 200, 2, 1, 0xf040000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 200, 2, 1, 0xfc50000000ull, 0x1fff0000000ull, { 23, 24, 38, 0, 0 }, 0x0, 0, }, + { 201, 1, 1, 0x10680000000ull, 0x1ffe0000000ull, { 23, 24, 40, 25, 0 }, 0x0, 0, }, + { 202, 2, 1, 0xe220000000ull, 0x1fff0000000ull, { 23, 25, 24, 0, 0 }, 0x0, 62, }, + { 202, 2, 1, 0xe630000000ull, 0x1fff0000000ull, { 23, 25, 42, 0, 0 }, 0x0, 62, }, + { 203, 2, 1, 0xf020000000ull, 0x1fff0000000ull, { 23, 25, 24, 0, 0 }, 0x0, 62, }, + { 203, 2, 1, 0xf430000000ull, 0x1fff0000000ull, { 23, 25, 42, 0, 0 }, 0x0, 62, }, + { 204, 1, 1, 0x106c0000000ull, 0x1ffe0000000ull, { 23, 24, 40, 25, 0 }, 0x0, 0, }, + { 205, 1, 1, 0x10420000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 60, }, + { 206, 1, 1, 0x10620000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 60, }, + { 207, 1, 1, 0x11420000000ull, 0x1fff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 208, 3, 0, 0x2048000000ull, 0x1eff8000000ull, { 25, 24, 0, 0, 0 }, 0x8, 450, }, + { 208, 3, 0, 0x2050000000ull, 0x1eff8000000ull, { 25, 24, 0, 0, 0 }, 0xc, 405, }, + { 208, 3, 0, 0x21a0000000ull, 0x1eff8000000ull, { 25, 0, 0, 0, 0 }, 0x8, 315, }, + { 209, 3, 0, 0x2060000000ull, 0x1eff8000000ull, { 25, 24, 0, 0, 0 }, 0x8, 149, }, + { 214, 4, 0, 0x40000000ull, 0x1e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x22c, 63, }, + { 215, 3, 0, 0x38000000ull, 0x1ee78000000ull, { 66, 0, 0, 0, 0 }, 0x8, 64, }, + { 216, 3, 0, 0x28000000ull, 0x1ee78000000ull, { 66, 0, 0, 0, 0 }, 0x0, 65, }, + { 225, 3, 1, 0xc708000000ull, 0x1ffc8000000ull, { 17, 24, 0, 0, 0 }, 0x0, 150, }, + { 226, 2, 1, 0xa600000000ull, 0x1ee04000000ull, { 23, 24, 44, 0, 0 }, 0x140, 0, }, + { 226, 2, 1, 0xf240000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 227, 1, 1, 0x10080000000ull, 0x1efe0000000ull, { 23, 24, 39, 25, 0 }, 0x0, 0, }, + { 228, 1, 1, 0x100c0000000ull, 0x1efe0000000ull, { 23, 24, 39, 25, 0 }, 0x0, 0, }, + { 229, 2, 1, 0xa400000000ull, 0x1ee00002000ull, { 23, 25, 75, 0, 0 }, 0x140, 10, }, + { 229, 2, 1, 0xf220000000ull, 0x1fff0000000ull, { 23, 25, 24, 0, 0 }, 0x0, 62, }, + { 230, 2, 1, 0xac00000000ull, 0x1ee00000000ull, { 23, 24, 25, 43, 0 }, 0x0, 0, }, + { 235, 3, 0, 0x180000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 151, }, + { 236, 3, 0, 0x30000000ull, 0x1ee78000000ull, { 66, 0, 0, 0, 0 }, 0x8, 64, }, + { 238, 3, 1, 0x8c00000000ull, 0x1fff8000000ull, { 32, 24, 0, 0, 0 }, 0x0, 66, }, + { 238, 3, 1, 0xac00000000ull, 0x1eff0000000ull, { 32, 24, 60, 0, 0 }, 0x0, 66, }, + { 239, 3, 1, 0x8c40000000ull, 0x1fff8000000ull, { 32, 24, 0, 0, 0 }, 0x0, 66, }, + { 239, 3, 1, 0xac40000000ull, 0x1eff0000000ull, { 32, 24, 60, 0, 0 }, 0x0, 66, }, + { 240, 3, 1, 0x8c80000000ull, 0x1fff8000000ull, { 32, 24, 0, 0, 0 }, 0x0, 66, }, + { 240, 3, 1, 0xac80000000ull, 0x1eff0000000ull, { 32, 24, 60, 0, 0 }, 0x0, 66, }, + { 241, 3, 1, 0x8cc0000000ull, 0x1fff8000000ull, { 32, 24, 0, 0, 0 }, 0x0, 67, }, + { 241, 3, 1, 0xacc0000000ull, 0x1eff0000000ull, { 32, 24, 60, 0, 0 }, 0x0, 67, }, + { 242, 3, 1, 0xcec0000000ull, 0x1fff8000000ull, { 32, 18, 0, 0, 0 }, 0x0, 883, }, + { 242, 3, 1, 0xeec0000000ull, 0x1eff0000000ull, { 32, 18, 60, 0, 0 }, 0x0, 883, }, + { 243, 3, 1, 0xcc40000000ull, 0x1fff8000000ull, { 32, 18, 0, 0, 0 }, 0x0, 68, }, + { 243, 3, 1, 0xec40000000ull, 0x1eff0000000ull, { 32, 18, 60, 0, 0 }, 0x0, 68, }, + { 244, 3, 1, 0xccc0000000ull, 0x1fff8000000ull, { 32, 18, 0, 0, 0 }, 0x0, 68, }, + { 244, 3, 1, 0xecc0000000ull, 0x1eff0000000ull, { 32, 18, 60, 0, 0 }, 0x0, 68, }, + { 245, 3, 1, 0xcc00000000ull, 0x1fff8000000ull, { 32, 18, 0, 0, 0 }, 0x0, 68, }, + { 245, 3, 1, 0xec00000000ull, 0x1eff0000000ull, { 32, 18, 60, 0, 0 }, 0x0, 68, }, + { 246, 3, 1, 0xcc80000000ull, 0x1fff8000000ull, { 32, 18, 0, 0, 0 }, 0x0, 68, }, + { 246, 3, 1, 0xec80000000ull, 0x1eff0000000ull, { 32, 18, 60, 0, 0 }, 0x0, 68, }, + { 247, 1, 1, 0x10028000000ull, 0x1eff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 247, 1, 1, 0x10020000000ull, 0x1eff8000000ull, { 23, 24, 25, 3, 0 }, 0x0, 0, }, + { 247, 1, 1, 0x10128000000ull, 0x1eff8000000ull, { 23, 54, 25, 0, 0 }, 0x0, 0, }, + { 248, 3, 0, 0x20000000ull, 0x1ee78000000ull, { 66, 0, 0, 0, 0 }, 0x0, 69, }, + { 249, 2, 1, 0xa0000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 0, }, + { 250, 2, 1, 0xa8000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 0, }, + { 251, 2, 1, 0xb0000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 0, }, + { 252, 3, 0, 0x198000000ull, 0x1eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 431, }, + { 253, 3, 1, 0x20f8000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x8, 70, }, + { 254, 2, 2, 0xa000000000ull, 0x1fe00003000ull, { 21, 22, 25, 75, 0 }, 0x0, 699, }, + { 254, 2, 2, 0xa000000000ull, 0x1fe00003000ull, { 22, 21, 25, 75, 0 }, 0x40, 700, }, + { 255, 3, 1, 0x20d0000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 71, }, + { 257, 2, 2, 0xa000002000ull, 0x1fe00003000ull, { 21, 22, 25, 0, 0 }, 0x0, 699, }, + { 257, 2, 2, 0xa000002000ull, 0x1fe00003000ull, { 22, 21, 25, 0, 0 }, 0x40, 700, }, + { 258, 3, 1, 0x20f0000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x8, 70, }, + { 260, 3, 1, 0x20d8000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 72, }, + { 264, 2, 1, 0xe840000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 426, }, + { 265, 2, 1, 0xea40000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 426, }, + { 266, 2, 1, 0xf840000000ull, 0x1fff0000000ull, { 23, 24, 25, 0, 0 }, 0x0, 426, }, + { 274, 3, 1, 0x8208000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 73, }, + { 275, 3, 1, 0x8248000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 73, }, + { 276, 3, 1, 0x8288000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 73, }, + { 277, 3, 1, 0x82c8000000ull, 0x1fff8000000ull, { 23, 32, 24, 0, 0 }, 0x0, 73, }, + { 279, 5, 1, 0x1d000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x0, 427, }, + { 279, 5, 1, 0x1d000000000ull, 0x1fc00000000ull, { 17, 19, 20, 18, 0 }, 0x40, 479, }, + { 280, 5, 1, 0x1d000000000ull, 0x1fc000fe000ull, { 17, 19, 20, 0, 0 }, 0x40, 428, }, + { 281, 1, 1, 0x10078000000ull, 0x1eff8000000ull, { 23, 24, 25, 0, 0 }, 0x0, 0, }, + { 281, 1, 1, 0x10178000000ull, 0x1eff8000000ull, { 23, 54, 25, 0, 0 }, 0x0, 0, }, + { 284, 2, 1, 0x80000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 0, }, + { 285, 2, 1, 0x88000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 0, }, + { 286, 2, 1, 0x90000000ull, 0x1eff8000000ull, { 23, 25, 0, 0, 0 }, 0x0, 0, }, +}; + +static const char dis_table[] = { +0xa0, 0xf0, 0xd0, 0xa0, 0x4d, 0xc8, 0xa0, 0x3e, 0x88, 0xa0, 0x2e, 0x78, +0x98, 0xb0, 0x01, 0x40, 0x90, 0x50, 0x90, 0x28, 0x24, 0x25, 0xc8, 0x24, +0x25, 0xc0, 0x90, 0x28, 0x24, 0x25, 0xb8, 0x24, 0x25, 0xb0, 0x90, 0x50, +0x90, 0x28, 0x24, 0x25, 0xa0, 0x24, 0x25, 0x98, 0x90, 0x28, 0x24, 0x25, +0x90, 0x24, 0x25, 0x88, 0xa8, 0x0b, 0x28, 0x29, 0x08, 0x97, 0x00, 0x95, +0xa8, 0x9a, 0x98, 0x05, 0x18, 0x90, 0xf8, 0x90, 0x80, 0x90, 0x40, 0x80, +0xa4, 0x06, 0x50, 0x39, 0x47, 0x80, 0xa4, 0x32, 0xb8, 0x34, 0xae, 0x90, +0x50, 0x90, 0x28, 0x80, 0x36, 0x60, 0x80, 0x31, 0xbc, 0x81, 0x35, 0xa0, +0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x00, 0x00, 0x34, 0x8f, 0xa4, +0x24, 0x60, 0x34, 0x8d, 0x90, 0x38, 0xa4, 0x2c, 0x70, 0x35, 0x83, 0xa4, +0x33, 0x80, 0x36, 0x6a, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x34, 0x70, 0x36, +0x92, 0xa4, 0x2e, 0x78, 0x35, 0xd7, 0x80, 0xa4, 0x34, 0x68, 0x36, 0x91, +0x92, 0x18, 0x91, 0xc0, 0x80, 0x91, 0x80, 0x90, 0xf8, 0xdb, 0x84, 0x61, +0x25, 0x80, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0x20, 0x8c, 0x52, 0xf0, 0x84, +0x3a, 0x8e, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0x10, 0x8c, 0x52, 0xd0, 0x84, +0x3a, 0x8a, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x2c, 0x50, +0xc0, 0xc0, 0x81, 0x3a, 0x2a, 0xa4, 0x0d, 0xd0, 0x31, 0xbb, 0x80, 0x90, +0x28, 0x80, 0x30, 0xe5, 0x80, 0x30, 0xe7, 0x81, 0x90, 0x38, 0xa4, 0x07, +0x70, 0x30, 0xea, 0xa4, 0x07, 0x40, 0x30, 0xe6, 0xc0, 0x40, 0x10, 0x10, +0x90, 0x38, 0xa4, 0x04, 0x30, 0x30, 0x3f, 0xa4, 0x04, 0x38, 0x30, 0x7b, +0x18, 0x24, 0x3a, 0x70, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, +0x80, 0xa4, 0x52, 0x50, 0x3a, 0x6a, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0x40, +0x3a, 0x66, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x32, 0x50, +0xc0, 0xc0, 0x81, 0x3a, 0x30, 0x92, 0xb8, 0x99, 0x84, 0x07, 0x60, 0x90, +0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x32, 0xb0, 0x34, 0xad, 0x82, +0x36, 0x5f, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x2c, 0x68, 0x35, +0x82, 0xa4, 0x33, 0x78, 0x36, 0x69, 0x80, 0x90, 0x38, 0xa4, 0x2e, 0x98, +0x35, 0xdb, 0xa4, 0x2e, 0x70, 0x35, 0xd6, 0x83, 0x90, 0xa8, 0xd3, 0x82, +0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0x80, 0x3a, 0x76, 0xc0, 0xc0, 0x80, +0xa4, 0x52, 0x70, 0x3a, 0x72, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, +0x3a, 0x38, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x36, 0x18, 0x24, 0x07, 0x68, +0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0xb0, +0x3a, 0x82, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0xa0, 0x3a, 0x7e, 0xd3, 0x82, +0x40, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x3e, 0x50, 0xc0, 0xc0, 0x81, 0x3a, +0x3c, 0x94, 0x50, 0x92, 0xf8, 0x99, 0x84, 0x3a, 0x60, 0x90, 0x78, 0x90, +0x50, 0x10, 0x10, 0x80, 0xa4, 0x32, 0xa8, 0x34, 0xac, 0x82, 0x36, 0x5e, +0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x2c, 0x60, 0x35, 0x81, 0xa4, +0x33, 0x70, 0x36, 0x68, 0x80, 0x90, 0x38, 0xa4, 0x2e, 0x90, 0x35, 0xda, +0xa4, 0x2e, 0x68, 0x35, 0xd5, 0x83, 0x90, 0xe8, 0xd3, 0x83, 0xc0, 0xc0, +0xc0, 0x80, 0xa4, 0x52, 0x30, 0x8c, 0x53, 0x10, 0x84, 0x3a, 0x8c, 0xc0, +0xc0, 0x80, 0xa4, 0x52, 0x18, 0x8c, 0x52, 0xe0, 0x84, 0x3a, 0x8b, 0xd3, +0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x2e, 0x50, 0xc0, 0xc0, 0x81, +0x3a, 0x2b, 0x18, 0x24, 0x3a, 0x68, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, +0xc0, 0xc0, 0x80, 0xa4, 0x52, 0x60, 0x3a, 0x6e, 0xc0, 0xc0, 0x80, 0xa4, +0x52, 0x48, 0x3a, 0x68, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x3a, +0x34, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x31, 0x92, 0xb8, 0x99, 0x84, 0x3a, +0x50, 0x90, 0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x32, 0xa0, 0x34, +0xab, 0x82, 0x36, 0x5d, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x2c, +0x58, 0x35, 0x80, 0xa4, 0x33, 0x68, 0x36, 0x67, 0x80, 0x90, 0x38, 0xa4, +0x2e, 0x88, 0x35, 0xd9, 0xa4, 0x2e, 0x60, 0x35, 0xd4, 0x83, 0x90, 0xa8, +0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0x90, 0x3a, 0x7a, 0xc0, +0xc0, 0x80, 0xa4, 0x52, 0x78, 0x3a, 0x74, 0xd3, 0x82, 0x40, 0x50, 0xc0, +0xc0, 0x81, 0x3a, 0x3a, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x37, 0x18, 0x20, +0x01, 0x48, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, +0x52, 0xc0, 0x3a, 0x86, 0xc0, 0xc0, 0x80, 0xa4, 0x52, 0xa8, 0x3a, 0x80, +0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x3a, 0x40, 0x50, 0xc0, 0xc0, +0x81, 0x3a, 0x3d, 0xea, 0x00, 0x57, 0x21, 0xd2, 0xc0, 0x95, 0x60, 0x93, +0x90, 0x91, 0xc8, 0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, +0x60, 0x31, 0x0e, 0xa4, 0x08, 0x00, 0x31, 0x04, 0x90, 0x38, 0xa4, 0x08, +0x50, 0x31, 0x02, 0xa4, 0x08, 0x40, 0x31, 0x06, 0x90, 0x70, 0x90, 0x38, +0xa4, 0x07, 0xe0, 0x30, 0xfe, 0xa4, 0x07, 0x80, 0x30, 0xf4, 0x90, 0x38, +0xa4, 0x07, 0xd0, 0x30, 0xf2, 0xa4, 0x07, 0xc0, 0x30, 0xf6, 0xd1, 0xc7, +0x40, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x0c, 0x60, 0x31, 0xaf, 0xa4, 0x0c, +0x00, 0x31, 0x84, 0x90, 0x38, 0xa4, 0x0c, 0x50, 0x31, 0x82, 0xa4, 0x0c, +0x40, 0x31, 0x86, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x0b, 0xe0, 0x31, 0x7e, +0xa4, 0x0b, 0x80, 0x31, 0x74, 0x90, 0x38, 0xa4, 0x0b, 0xd0, 0x31, 0x72, +0xa4, 0x0b, 0xc0, 0x31, 0x76, 0x80, 0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x0d, 0x58, 0x31, 0xad, 0xa4, 0x0c, 0xf8, 0x31, 0xa3, 0x90, +0x38, 0xa4, 0x0d, 0x48, 0x31, 0xa1, 0xa4, 0x0d, 0x38, 0x31, 0xa5, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x0c, 0xd8, 0x31, 0x9d, 0xa4, 0x0c, 0x78, 0x31, +0x93, 0x90, 0x38, 0xa4, 0x0c, 0xc8, 0x31, 0x91, 0xa4, 0x0c, 0xb8, 0x31, +0x95, 0x93, 0x90, 0x91, 0xc8, 0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, 0x38, +0xa4, 0x09, 0x60, 0x31, 0x2e, 0xa4, 0x09, 0x00, 0x31, 0x24, 0x90, 0x38, +0xa4, 0x09, 0x50, 0x31, 0x22, 0xa4, 0x09, 0x40, 0x31, 0x26, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x08, 0xe0, 0x31, 0x1e, 0xa4, 0x08, 0x80, 0x31, 0x14, +0x90, 0x38, 0xa4, 0x08, 0xd0, 0x31, 0x12, 0xa4, 0x08, 0xc0, 0x31, 0x16, +0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x0a, 0x60, 0x31, 0x4e, +0xa4, 0x0a, 0x00, 0x31, 0x44, 0x90, 0x38, 0xa4, 0x0a, 0x50, 0x31, 0x42, +0xa4, 0x0a, 0x40, 0x31, 0x46, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, 0xe0, +0x31, 0x3e, 0xa4, 0x09, 0x80, 0x31, 0x34, 0x90, 0x38, 0xa4, 0x09, 0xd0, +0x31, 0x32, 0xa4, 0x09, 0xc0, 0x31, 0x36, 0x80, 0xd1, 0xc7, 0x40, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x0b, 0x60, 0x31, 0x6e, 0xa4, 0x0b, 0x00, 0x31, +0x64, 0x90, 0x38, 0xa4, 0x0b, 0x50, 0x31, 0x62, 0xa4, 0x0b, 0x40, 0x31, +0x66, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x0a, 0xe0, 0x31, 0x5e, 0xa4, 0x0a, +0x80, 0x31, 0x54, 0x90, 0x38, 0xa4, 0x0a, 0xd0, 0x31, 0x52, 0xa4, 0x0a, +0xc0, 0x31, 0x56, 0x95, 0x60, 0x93, 0x90, 0x91, 0xc8, 0xd1, 0xc7, 0x40, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0x68, 0x31, 0x0f, 0xa4, 0x08, 0x08, +0x31, 0x05, 0x90, 0x38, 0xa4, 0x08, 0x58, 0x31, 0x03, 0xa4, 0x08, 0x48, +0x31, 0x07, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07, 0xe8, 0x30, 0xff, 0xa4, +0x07, 0x88, 0x30, 0xf5, 0x90, 0x38, 0xa4, 0x07, 0xd8, 0x30, 0xf3, 0xa4, +0x07, 0xc8, 0x30, 0xf7, 0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x0c, 0x68, 0x31, 0x8e, 0xa4, 0x0c, 0x08, 0x31, 0x85, 0x90, 0x38, 0xa4, +0x0c, 0x58, 0x31, 0x83, 0xa4, 0x0c, 0x48, 0x31, 0x87, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x0b, 0xe8, 0x31, 0x7f, 0xa4, 0x0b, 0x88, 0x31, 0x75, 0x90, +0x38, 0xa4, 0x0b, 0xd8, 0x31, 0x73, 0xa4, 0x0b, 0xc8, 0x31, 0x77, 0x80, +0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x0d, 0x60, 0x31, 0xae, +0xa4, 0x0d, 0x00, 0x31, 0xa4, 0x90, 0x38, 0xa4, 0x0d, 0x50, 0x31, 0xa2, +0xa4, 0x0d, 0x40, 0x31, 0xa6, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x0c, 0xe0, +0x31, 0x9e, 0xa4, 0x0c, 0x80, 0x31, 0x94, 0x90, 0x38, 0xa4, 0x0c, 0xd0, +0x31, 0x92, 0xa4, 0x0c, 0xc0, 0x31, 0x96, 0x93, 0x90, 0x91, 0xc8, 0xd1, +0xc7, 0x40, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, 0x68, 0x31, 0x2f, 0xa4, +0x09, 0x08, 0x31, 0x25, 0x90, 0x38, 0xa4, 0x09, 0x58, 0x31, 0x23, 0xa4, +0x09, 0x48, 0x31, 0x27, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0xe8, 0x31, +0x1f, 0xa4, 0x08, 0x88, 0x31, 0x15, 0x90, 0x38, 0xa4, 0x08, 0xd8, 0x31, +0x13, 0xa4, 0x08, 0xc8, 0x31, 0x17, 0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x0a, 0x68, 0x31, 0x4f, 0xa4, 0x0a, 0x08, 0x31, 0x45, 0x90, +0x38, 0xa4, 0x0a, 0x58, 0x31, 0x43, 0xa4, 0x0a, 0x48, 0x31, 0x47, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x09, 0xe8, 0x31, 0x3f, 0xa4, 0x09, 0x88, 0x31, +0x35, 0x90, 0x38, 0xa4, 0x09, 0xd8, 0x31, 0x33, 0xa4, 0x09, 0xc8, 0x31, +0x37, 0x80, 0xd1, 0xc7, 0x40, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x0b, 0x68, +0x31, 0x6f, 0xa4, 0x0b, 0x08, 0x31, 0x65, 0x90, 0x38, 0xa4, 0x0b, 0x58, +0x31, 0x63, 0xa4, 0x0b, 0x48, 0x31, 0x67, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x0a, 0xe8, 0x31, 0x5f, 0xa4, 0x0a, 0x88, 0x31, 0x55, 0x90, 0x38, 0xa4, +0x0a, 0xd8, 0x31, 0x53, 0xa4, 0x0a, 0xc8, 0x31, 0x57, 0xc8, 0x40, 0x18, +0x00, 0x91, 0x38, 0x90, 0x40, 0x82, 0xa4, 0x06, 0x68, 0x39, 0x4a, 0x90, +0xc0, 0x80, 0x90, 0x90, 0x90, 0x48, 0xc9, 0xe1, 0x61, 0xc0, 0x85, 0x36, +0x82, 0xc9, 0xe1, 0x62, 0x40, 0x85, 0x35, 0x5e, 0x80, 0x35, 0x86, 0x10, +0x10, 0x81, 0x35, 0xcb, 0x90, 0xa8, 0x10, 0x10, 0x90, 0x28, 0x81, 0x35, +0x3d, 0x90, 0x38, 0xa4, 0x33, 0x28, 0x36, 0x66, 0xa4, 0x24, 0xa8, 0x35, +0x3f, 0x90, 0x70, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x24, 0xd0, 0x34, 0x9b, +0x80, 0x34, 0x99, 0x90, 0x60, 0x90, 0x28, 0x24, 0x2b, 0xf0, 0xa4, 0x2b, +0xf8, 0x35, 0x7d, 0x80, 0xa4, 0x24, 0xc0, 0x34, 0x97, 0x80, 0x90, 0xf8, +0x90, 0x90, 0x90, 0x50, 0x90, 0x28, 0x80, 0x39, 0x4b, 0x80, 0x36, 0x95, +0x80, 0xa4, 0x3a, 0x30, 0x37, 0x47, 0x90, 0x28, 0x81, 0x30, 0x88, 0x80, +0xa4, 0x3a, 0x78, 0x37, 0x50, 0x83, 0x36, 0x87, 0x98, 0xb0, 0x01, 0x40, +0x90, 0x50, 0x90, 0x28, 0x24, 0x26, 0x18, 0x24, 0x26, 0x10, 0x90, 0x28, +0x24, 0x26, 0x08, 0x24, 0x26, 0x00, 0x90, 0x50, 0x90, 0x28, 0x24, 0x25, +0xf0, 0x24, 0x25, 0xe8, 0x90, 0x28, 0x24, 0x25, 0xe0, 0x24, 0x25, 0xd8, +0xa8, 0x08, 0xe0, 0x0d, 0xe0, 0x96, 0x38, 0x95, 0xe8, 0x9b, 0x48, 0x05, +0xa8, 0x91, 0xa0, 0x90, 0xd0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0xd8, +0x30, 0xdc, 0xa4, 0x06, 0xc8, 0x30, 0xda, 0x90, 0x38, 0xa4, 0x06, 0xb8, +0x30, 0xd8, 0x80, 0x30, 0xd6, 0x90, 0x60, 0x90, 0x28, 0x24, 0x04, 0x68, +0xa4, 0x04, 0x58, 0x30, 0x8c, 0x90, 0x38, 0xa4, 0x04, 0x48, 0x30, 0x8a, +0xa4, 0x24, 0x40, 0x34, 0x89, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x06, 0xa0, 0x30, 0xd5, 0xa4, 0x06, 0x90, 0x30, 0xd3, 0x90, 0x38, 0xa4, +0x27, 0x38, 0x34, 0xdd, 0xa4, 0x29, 0xd0, 0x35, 0x34, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x27, 0xc0, 0x35, 0x04, 0xa4, 0x27, 0x90, 0x34, 0xfe, 0x10, +0x10, 0xa4, 0x01, 0xf0, 0x30, 0x1d, 0x91, 0x50, 0x90, 0x90, 0x90, 0x50, +0x90, 0x28, 0x24, 0x06, 0xe8, 0x80, 0x30, 0xe3, 0x80, 0xa4, 0x06, 0xf0, +0x30, 0xe1, 0x90, 0x50, 0x90, 0x28, 0x24, 0x06, 0xf8, 0x80, 0x30, 0xe4, +0x90, 0x38, 0xa4, 0x07, 0x00, 0x30, 0xe2, 0xa4, 0x24, 0x50, 0x34, 0x8b, +0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x29, 0x28, 0x36, 0x62, 0xa4, +0x28, 0x50, 0x35, 0x2b, 0x90, 0x38, 0xa4, 0x28, 0xa8, 0x35, 0x1f, 0xa4, +0x28, 0x80, 0x35, 0x1a, 0x81, 0xa4, 0x05, 0x30, 0x30, 0xa7, 0xe4, 0xe2, +0x84, 0x80, 0x3a, 0x14, 0xed, 0x22, 0x86, 0x21, 0xd2, 0x40, 0x3a, 0x1a, +0x92, 0x40, 0x99, 0x18, 0x02, 0x00, 0x10, 0x10, 0x90, 0x80, 0x10, 0x10, +0x90, 0x38, 0xa4, 0x27, 0x30, 0x34, 0xdc, 0xa4, 0x29, 0xc8, 0x35, 0x33, +0x80, 0x90, 0x38, 0xa4, 0x27, 0xb8, 0x35, 0x03, 0xa4, 0x27, 0x88, 0x34, +0xfd, 0x10, 0x10, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x29, 0x20, 0x35, +0x30, 0xa4, 0x28, 0x48, 0x35, 0x2a, 0x90, 0x38, 0xa4, 0x28, 0xa0, 0x35, +0x1e, 0xa4, 0x28, 0x78, 0x35, 0x19, 0xe4, 0xe2, 0x87, 0x80, 0x3a, 0x20, +0xed, 0x22, 0x89, 0x21, 0xd2, 0x00, 0x3a, 0x26, 0x92, 0x80, 0x92, 0x40, +0x99, 0x18, 0x02, 0x00, 0x10, 0x10, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, +0xa4, 0x27, 0x28, 0x34, 0xdb, 0xa4, 0x29, 0xc0, 0x35, 0x32, 0x80, 0x90, +0x38, 0xa4, 0x27, 0xb0, 0x35, 0x02, 0xa4, 0x27, 0x80, 0x34, 0xfc, 0x10, +0x10, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x29, 0x18, 0x35, 0x2f, 0xa4, +0x28, 0x40, 0x35, 0x29, 0x90, 0x38, 0xa4, 0x28, 0x98, 0x35, 0x1d, 0xa4, +0x28, 0x70, 0x35, 0x18, 0xe4, 0xe2, 0x84, 0xc0, 0x3a, 0x16, 0xe5, 0x22, +0x86, 0x40, 0x3a, 0x1c, 0x92, 0x50, 0x99, 0x18, 0x02, 0x00, 0x10, 0x10, +0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x27, 0x20, 0x34, 0xda, 0xa4, +0x29, 0xb8, 0x35, 0x31, 0x80, 0x90, 0x38, 0xa4, 0x27, 0xa8, 0x35, 0x01, +0xa4, 0x27, 0x78, 0x34, 0xfb, 0x10, 0x10, 0x80, 0x90, 0x70, 0x90, 0x38, +0xa4, 0x29, 0x10, 0x35, 0x2e, 0xa4, 0x28, 0x38, 0x35, 0x28, 0x90, 0x38, +0xa4, 0x28, 0x90, 0x35, 0x1c, 0xa4, 0x28, 0x68, 0x35, 0x17, 0xec, 0xe2, +0x87, 0xe2, 0xa5, 0x00, 0x3a, 0x22, 0xe5, 0x22, 0x89, 0x40, 0x3a, 0x28, +0xc0, 0x40, 0x80, 0x10, 0x10, 0x81, 0x90, 0x90, 0x90, 0x48, 0xc9, 0xe1, +0x38, 0x40, 0x85, 0x35, 0x3e, 0xc9, 0xe1, 0x38, 0x80, 0x85, 0x34, 0xcf, +0x80, 0x34, 0xe0, 0x80, 0xd8, 0x7c, 0x80, 0x77, 0xc0, 0xc0, 0x80, 0x10, +0x10, 0x82, 0x93, 0xa8, 0xd5, 0x4e, 0xc0, 0x90, 0xe8, 0x80, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x42, 0x38, 0x38, 0x19, 0xa4, 0x41, 0x78, 0x38, 0x37, +0x90, 0x38, 0xa4, 0x42, 0x18, 0x38, 0x33, 0xa4, 0x41, 0xf8, 0x38, 0x3b, +0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x46, 0xe8, 0x38, 0xaf, 0xa4, 0x46, +0x28, 0x38, 0xcd, 0x90, 0x38, 0xa4, 0x46, 0xc8, 0x38, 0xc9, 0xa4, 0x46, +0xa8, 0x38, 0xd1, 0x90, 0xe8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x41, +0x40, 0x38, 0x2a, 0xa4, 0x40, 0xe0, 0x38, 0x20, 0x90, 0x38, 0xa4, 0x41, +0x30, 0x38, 0x1e, 0xa4, 0x41, 0x20, 0x38, 0x22, 0x80, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x45, 0xf0, 0x38, 0xc0, 0xa4, 0x45, 0x90, 0x38, 0xb6, 0x90, +0x38, 0xa4, 0x45, 0xe0, 0x38, 0xb4, 0xa4, 0x45, 0xd0, 0x38, 0xb8, 0xd5, +0x4e, 0xc0, 0x90, 0xe8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x43, 0xc8, +0x38, 0x4b, 0xa4, 0x43, 0x08, 0x38, 0x69, 0x90, 0x38, 0xa4, 0x43, 0xa8, +0x38, 0x65, 0xa4, 0x43, 0x88, 0x38, 0x6d, 0x80, 0x90, 0x70, 0x90, 0x38, +0xa4, 0x45, 0x58, 0x38, 0x7d, 0xa4, 0x44, 0x98, 0x38, 0x9b, 0x90, 0x38, +0xa4, 0x45, 0x38, 0x38, 0x97, 0xa4, 0x45, 0x18, 0x38, 0x9f, 0x90, 0xe8, +0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x42, 0xd0, 0x38, 0x5c, 0xa4, 0x42, +0x70, 0x38, 0x52, 0x90, 0x38, 0xa4, 0x42, 0xc0, 0x38, 0x50, 0xa4, 0x42, +0xb0, 0x38, 0x54, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x44, 0x60, 0x38, +0x8e, 0xa4, 0x44, 0x00, 0x38, 0x84, 0x90, 0x38, 0xa4, 0x44, 0x50, 0x38, +0x82, 0xa4, 0x44, 0x40, 0x38, 0x86, 0xc0, 0x80, 0x10, 0x10, 0x82, 0x93, +0xa8, 0xd5, 0x4e, 0xc0, 0x90, 0xe8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x42, 0x48, 0x38, 0x2c, 0xa4, 0x41, 0x88, 0x38, 0x39, 0x90, 0x38, 0xa4, +0x42, 0x28, 0x38, 0x35, 0xa4, 0x42, 0x08, 0x38, 0x3d, 0x80, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x46, 0xf8, 0x38, 0xc2, 0xa4, 0x46, 0x38, 0x38, 0xcf, +0x90, 0x38, 0xa4, 0x46, 0xd8, 0x38, 0xcb, 0xa4, 0x46, 0xb8, 0x38, 0xd3, +0x90, 0xe8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x41, 0x48, 0x38, 0x2b, +0xa4, 0x40, 0xe8, 0x38, 0x21, 0x90, 0x38, 0xa4, 0x41, 0x38, 0x38, 0x1f, +0xa4, 0x41, 0x28, 0x38, 0x23, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x45, +0xf8, 0x38, 0xc1, 0xa4, 0x45, 0x98, 0x38, 0xb7, 0x90, 0x38, 0xa4, 0x45, +0xe8, 0x38, 0xb5, 0xa4, 0x45, 0xd8, 0x38, 0xb9, 0xd5, 0x4e, 0xc0, 0x90, +0xe8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x43, 0xd8, 0x38, 0x5e, 0xa4, +0x43, 0x18, 0x38, 0x6b, 0x90, 0x38, 0xa4, 0x43, 0xb8, 0x38, 0x67, 0xa4, +0x43, 0x98, 0x38, 0x6f, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x45, 0x68, +0x38, 0x90, 0xa4, 0x44, 0xa8, 0x38, 0x9d, 0x90, 0x38, 0xa4, 0x45, 0x48, +0x38, 0x99, 0xa4, 0x45, 0x28, 0x38, 0xa1, 0x90, 0xe8, 0x80, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x42, 0xd8, 0x38, 0x5d, 0xa4, 0x42, 0x78, 0x38, 0x53, +0x90, 0x38, 0xa4, 0x42, 0xc8, 0x38, 0x51, 0xa4, 0x42, 0xb8, 0x38, 0x55, +0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x44, 0x68, 0x38, 0x8f, 0xa4, 0x44, +0x08, 0x38, 0x85, 0x90, 0x38, 0xa4, 0x44, 0x58, 0x38, 0x83, 0xa4, 0x44, +0x48, 0x38, 0x87, 0xc0, 0x80, 0x84, 0x30, 0xce, 0xa0, 0x56, 0x50, 0xa0, +0x40, 0x70, 0xa8, 0x1d, 0x40, 0x33, 0x18, 0xa0, 0x12, 0x38, 0xa0, 0x0b, +0x48, 0x96, 0x00, 0x9a, 0xf0, 0x05, 0xc0, 0x91, 0x70, 0x90, 0xb8, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x35, 0x58, 0x34, 0x87, 0xa4, 0x35, 0x68, 0x34, +0x74, 0x10, 0x10, 0xa4, 0x35, 0x60, 0x34, 0x73, 0x90, 0x70, 0x90, 0x38, +0xa4, 0x35, 0x28, 0x34, 0x36, 0xa4, 0x35, 0x38, 0x34, 0x23, 0x10, 0x10, +0xa4, 0x35, 0x30, 0x34, 0x22, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x34, 0xf8, 0x33, 0xe5, 0xa4, 0x35, 0x08, 0x33, 0xd2, 0x10, 0x10, 0xa4, +0x35, 0x00, 0x33, 0xd1, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x34, 0xc8, 0x33, +0x94, 0xa4, 0x34, 0xd8, 0x33, 0x7e, 0x10, 0x10, 0xa4, 0x34, 0xd0, 0x33, +0x7d, 0x91, 0x70, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x35, 0x40, +0x34, 0x70, 0xa4, 0x35, 0x50, 0x34, 0x72, 0x10, 0x10, 0xa4, 0x35, 0x48, +0x34, 0x71, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x35, 0x10, 0x34, 0x1f, 0xa4, +0x35, 0x20, 0x34, 0x21, 0x10, 0x10, 0xa4, 0x35, 0x18, 0x34, 0x20, 0x90, +0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x34, 0xe0, 0x33, 0xce, 0xa4, 0x34, +0xf0, 0x33, 0xd0, 0x10, 0x10, 0xa4, 0x34, 0xe8, 0x33, 0xcf, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x34, 0xb0, 0x33, 0x7a, 0xa4, 0x34, 0xc0, 0x33, 0x7c, +0x10, 0x10, 0xa4, 0x34, 0xb8, 0x33, 0x7b, 0xe4, 0xe1, 0x91, 0x80, 0x36, +0x50, 0x9a, 0xf0, 0x05, 0x00, 0x91, 0x70, 0x90, 0xb8, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x00, 0xb0, 0x34, 0x84, 0xa4, 0x00, 0xa8, 0x34, 0x86, 0x10, +0x10, 0xa4, 0x00, 0xa0, 0x34, 0x85, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x00, +0x98, 0x34, 0x33, 0xa4, 0x00, 0x90, 0x34, 0x35, 0x10, 0x10, 0xa4, 0x00, +0x88, 0x34, 0x34, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x00, 0x80, +0x33, 0xe2, 0xa4, 0x00, 0x78, 0x33, 0xe4, 0x10, 0x10, 0xa4, 0x00, 0x70, +0x33, 0xe3, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x00, 0x68, 0x33, 0x91, 0xa4, +0x00, 0x60, 0x33, 0x93, 0x10, 0x10, 0xa4, 0x00, 0x58, 0x33, 0x92, 0x91, +0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x6d, 0x80, 0x34, +0x6f, 0x10, 0x10, 0x80, 0x34, 0x6e, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, +0x1c, 0x80, 0x34, 0x1e, 0x10, 0x10, 0x80, 0x34, 0x1d, 0x90, 0x88, 0x90, +0x50, 0x90, 0x28, 0x80, 0x33, 0xcb, 0x80, 0x33, 0xcd, 0x10, 0x10, 0x80, +0x33, 0xcc, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x77, 0x80, 0x33, 0x79, +0x10, 0x10, 0x80, 0x33, 0x78, 0xe4, 0xe1, 0x89, 0x00, 0x36, 0x38, 0x95, +0x40, 0x9a, 0x90, 0x05, 0x00, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, +0x28, 0x80, 0x34, 0x7e, 0x80, 0x34, 0x80, 0x10, 0x10, 0x80, 0x34, 0x7f, +0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x2d, 0x80, 0x34, 0x2f, 0x10, 0x10, +0x80, 0x34, 0x2e, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x2d, 0x50, +0x33, 0xdc, 0xa4, 0x2d, 0x60, 0x33, 0xde, 0x10, 0x10, 0xa4, 0x2d, 0x58, +0x33, 0xdd, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x2d, 0x20, 0x33, 0x8b, 0xa4, +0x2d, 0x30, 0x33, 0x8d, 0x10, 0x10, 0xa4, 0x2d, 0x28, 0x33, 0x8c, 0x91, +0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x81, 0x80, 0x34, +0x83, 0x10, 0x10, 0x80, 0x34, 0x82, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, +0x30, 0x80, 0x34, 0x32, 0x10, 0x10, 0x80, 0x34, 0x31, 0x90, 0xb8, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x2d, 0x38, 0x33, 0xdf, 0xa4, 0x2d, 0x48, 0x33, +0xe1, 0x10, 0x10, 0xa4, 0x2d, 0x40, 0x33, 0xe0, 0x90, 0x70, 0x90, 0x38, +0xa4, 0x2d, 0x08, 0x33, 0x8e, 0xa4, 0x2d, 0x18, 0x33, 0x90, 0x10, 0x10, +0xa4, 0x2d, 0x10, 0x33, 0x8f, 0xe4, 0xe1, 0x91, 0x00, 0x36, 0x4e, 0x98, +0xb8, 0x01, 0x68, 0x10, 0x10, 0x10, 0x10, 0x90, 0x50, 0x90, 0x28, 0x80, +0x33, 0x7f, 0x80, 0x33, 0x81, 0x10, 0x10, 0x80, 0x33, 0x80, 0x90, 0x60, +0x90, 0x30, 0x60, 0xa1, 0x24, 0x40, 0x60, 0xa1, 0x24, 0xc0, 0x90, 0x30, +0x60, 0xa1, 0x24, 0x80, 0x60, 0xa1, 0x25, 0x00, 0xe4, 0xe1, 0x88, 0x00, +0x36, 0x34, 0x96, 0xe8, 0x94, 0x80, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, +0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x78, 0x80, 0x34, 0x7a, +0x10, 0x10, 0x80, 0x34, 0x79, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x27, +0x80, 0x34, 0x29, 0x10, 0x10, 0x80, 0x34, 0x28, 0x90, 0x88, 0x90, 0x50, +0x90, 0x28, 0x80, 0x33, 0xd6, 0x80, 0x33, 0xd8, 0x10, 0x10, 0x80, 0x33, +0xd7, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x85, 0x80, 0x33, 0x87, 0x10, +0x10, 0x80, 0x33, 0x86, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, +0x80, 0x34, 0x75, 0x80, 0x34, 0x77, 0x10, 0x10, 0x80, 0x34, 0x76, 0x90, +0x50, 0x90, 0x28, 0x80, 0x34, 0x24, 0x80, 0x34, 0x26, 0x10, 0x10, 0x80, +0x34, 0x25, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xd3, 0x80, +0x33, 0xd5, 0x10, 0x10, 0x80, 0x33, 0xd4, 0x90, 0x50, 0x90, 0x28, 0x80, +0x33, 0x82, 0x80, 0x33, 0x84, 0x10, 0x10, 0x80, 0x33, 0x83, 0xe4, 0xe1, +0x90, 0x80, 0x36, 0x4c, 0x88, 0x02, 0x28, 0x91, 0x10, 0x90, 0x88, 0x90, +0x50, 0x90, 0x28, 0x80, 0x34, 0x7b, 0x80, 0x34, 0x7d, 0x10, 0x10, 0x80, +0x34, 0x7c, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x2a, 0x80, 0x34, 0x2c, +0x10, 0x10, 0x80, 0x34, 0x2b, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, +0x33, 0xd9, 0x80, 0x33, 0xdb, 0x10, 0x10, 0x80, 0x33, 0xda, 0x90, 0x50, +0x90, 0x28, 0x80, 0x33, 0x88, 0x80, 0x33, 0x8a, 0x10, 0x10, 0x80, 0x33, +0x89, 0xe4, 0xe1, 0x87, 0x00, 0x36, 0x30, 0x93, 0x40, 0x99, 0x90, 0x03, +0x00, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x28, 0x81, 0x30, 0x7a, 0x10, 0x10, +0x80, 0x30, 0x79, 0x90, 0x28, 0x81, 0x30, 0x72, 0x10, 0x10, 0x80, 0x30, +0x71, 0x90, 0x60, 0x90, 0x28, 0x81, 0x30, 0x6a, 0x10, 0x10, 0x80, 0x30, +0x69, 0x90, 0x28, 0x81, 0x30, 0x62, 0x10, 0x10, 0x80, 0x30, 0x61, 0x90, +0xc0, 0x90, 0x60, 0x90, 0x28, 0x81, 0x30, 0x77, 0x10, 0x10, 0x80, 0x30, +0x78, 0x90, 0x28, 0x81, 0x30, 0x6f, 0x10, 0x10, 0x80, 0x30, 0x70, 0x90, +0x60, 0x90, 0x28, 0x81, 0x30, 0x67, 0x10, 0x10, 0x80, 0x30, 0x68, 0x90, +0x28, 0x81, 0x30, 0x5f, 0x10, 0x10, 0x80, 0x30, 0x60, 0xe4, 0xe1, 0x90, +0x00, 0x36, 0x4a, 0x88, 0x00, 0x88, 0x10, 0x10, 0x10, 0x10, 0x90, 0x28, +0x81, 0x30, 0x5d, 0x10, 0x10, 0x80, 0x30, 0x5e, 0xe4, 0xe1, 0x86, 0x00, +0x36, 0x2c, 0xa0, 0x0e, 0x80, 0xa0, 0x09, 0x08, 0x94, 0x80, 0x9a, 0x30, +0x04, 0x40, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, +0x6c, 0x80, 0x34, 0x59, 0x10, 0x10, 0x80, 0x34, 0x58, 0x90, 0x50, 0x90, +0x28, 0x80, 0x34, 0x1b, 0x80, 0x34, 0x08, 0x10, 0x10, 0x80, 0x34, 0x07, +0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xca, 0x80, 0x33, 0xb7, +0x10, 0x10, 0x80, 0x33, 0xb6, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x76, +0x80, 0x33, 0x60, 0x10, 0x10, 0x80, 0x33, 0x5f, 0x91, 0x10, 0x90, 0x88, +0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x55, 0x80, 0x34, 0x57, 0x10, 0x10, +0x80, 0x34, 0x56, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x04, 0x80, 0x34, +0x06, 0x10, 0x10, 0x80, 0x34, 0x05, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, +0x80, 0x33, 0xb3, 0x80, 0x33, 0xb5, 0x10, 0x10, 0x80, 0x33, 0xb4, 0x90, +0x50, 0x90, 0x28, 0x80, 0x33, 0x5c, 0x80, 0x33, 0x5e, 0x10, 0x10, 0x80, +0x33, 0x5d, 0xe4, 0xe1, 0x7f, 0x00, 0x36, 0x10, 0x9a, 0x30, 0x04, 0x40, +0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x69, 0x80, +0x34, 0x6b, 0x10, 0x10, 0x80, 0x34, 0x6a, 0x90, 0x50, 0x90, 0x28, 0x80, +0x34, 0x18, 0x80, 0x34, 0x1a, 0x10, 0x10, 0x80, 0x34, 0x19, 0x90, 0x88, +0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xc7, 0x80, 0x33, 0xc9, 0x10, 0x10, +0x80, 0x33, 0xc8, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x73, 0x80, 0x33, +0x75, 0x10, 0x10, 0x80, 0x33, 0x74, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, +0x90, 0x28, 0x80, 0x34, 0x52, 0x80, 0x34, 0x54, 0x10, 0x10, 0x80, 0x34, +0x53, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x01, 0x80, 0x34, 0x03, 0x10, +0x10, 0x80, 0x34, 0x02, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, +0xb0, 0x80, 0x33, 0xb2, 0x10, 0x10, 0x80, 0x33, 0xb1, 0x90, 0x50, 0x90, +0x28, 0x80, 0x33, 0x59, 0x80, 0x33, 0x5b, 0x10, 0x10, 0x80, 0x33, 0x5a, +0xe4, 0xe1, 0x78, 0x80, 0x35, 0xec, 0x94, 0x80, 0x9a, 0x30, 0x04, 0x40, +0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x63, 0x80, +0x34, 0x65, 0x10, 0x10, 0x80, 0x34, 0x64, 0x90, 0x50, 0x90, 0x28, 0x80, +0x34, 0x12, 0x80, 0x34, 0x14, 0x10, 0x10, 0x80, 0x34, 0x13, 0x90, 0x88, +0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xc1, 0x80, 0x33, 0xc3, 0x10, 0x10, +0x80, 0x33, 0xc2, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x6d, 0x80, 0x33, +0x6f, 0x10, 0x10, 0x80, 0x33, 0x6e, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, +0x90, 0x28, 0x80, 0x34, 0x66, 0x80, 0x34, 0x68, 0x10, 0x10, 0x80, 0x34, +0x67, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x15, 0x80, 0x34, 0x17, 0x10, +0x10, 0x80, 0x34, 0x16, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, +0xc4, 0x80, 0x33, 0xc6, 0x10, 0x10, 0x80, 0x33, 0xc5, 0x90, 0x50, 0x90, +0x28, 0x80, 0x33, 0x70, 0x80, 0x33, 0x72, 0x10, 0x10, 0x80, 0x33, 0x71, +0xe4, 0xe1, 0x7e, 0x00, 0x36, 0x0c, 0x88, 0x00, 0xb0, 0x10, 0x10, 0x10, +0x10, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x61, 0x80, 0x33, 0x63, 0x10, +0x10, 0x80, 0x33, 0x62, 0xe4, 0xe1, 0x78, 0x00, 0x35, 0xea, 0x96, 0xe8, +0x94, 0x80, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, +0x90, 0x28, 0x80, 0x34, 0x5d, 0x80, 0x34, 0x5f, 0x10, 0x10, 0x80, 0x34, +0x5e, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x0c, 0x80, 0x34, 0x0e, 0x10, +0x10, 0x80, 0x34, 0x0d, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, +0xbb, 0x80, 0x33, 0xbd, 0x10, 0x10, 0x80, 0x33, 0xbc, 0x90, 0x50, 0x90, +0x28, 0x80, 0x33, 0x67, 0x80, 0x33, 0x69, 0x10, 0x10, 0x80, 0x33, 0x68, +0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x5a, 0x80, +0x34, 0x5c, 0x10, 0x10, 0x80, 0x34, 0x5b, 0x90, 0x50, 0x90, 0x28, 0x80, +0x34, 0x09, 0x80, 0x34, 0x0b, 0x10, 0x10, 0x80, 0x34, 0x0a, 0x90, 0x88, +0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xb8, 0x80, 0x33, 0xba, 0x10, 0x10, +0x80, 0x33, 0xb9, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x64, 0x80, 0x33, +0x66, 0x10, 0x10, 0x80, 0x33, 0x65, 0xe4, 0xe1, 0x7d, 0x00, 0x36, 0x08, +0x88, 0x02, 0x28, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, +0x34, 0x60, 0x80, 0x34, 0x62, 0x10, 0x10, 0x80, 0x34, 0x61, 0x90, 0x50, +0x90, 0x28, 0x80, 0x34, 0x0f, 0x80, 0x34, 0x11, 0x10, 0x10, 0x80, 0x34, +0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xbe, 0x80, 0x33, +0xc0, 0x10, 0x10, 0x80, 0x33, 0xbf, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, +0x6a, 0x80, 0x33, 0x6c, 0x10, 0x10, 0x80, 0x33, 0x6b, 0xe4, 0xe1, 0x77, +0x80, 0x35, 0xe8, 0x90, 0x40, 0xe5, 0x21, 0x7c, 0x00, 0x36, 0x04, 0xe5, +0x21, 0x77, 0x00, 0x35, 0xe6, 0x9e, 0xb4, 0x34, 0x60, 0x93, 0x70, 0x91, +0xd8, 0xd5, 0x07, 0x80, 0xd0, 0xc4, 0x40, 0x90, 0x48, 0x80, 0x8c, 0x4f, +0x00, 0x84, 0x3a, 0x10, 0xa4, 0x4d, 0x70, 0x39, 0xc6, 0x90, 0x28, 0x24, +0x4c, 0xb0, 0xa4, 0x4b, 0x30, 0x39, 0x7e, 0xd0, 0xc4, 0x40, 0x90, 0x48, +0x80, 0x8c, 0x4e, 0xe0, 0x84, 0x3a, 0x0c, 0xa4, 0x4d, 0x60, 0x39, 0xc4, +0x90, 0x28, 0x24, 0x4c, 0xa0, 0xa4, 0x4b, 0x20, 0x39, 0x7c, 0xd5, 0x06, +0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x39, 0xec, 0xa4, 0x4d, 0xa0, +0x39, 0xcc, 0x90, 0x28, 0x24, 0x4c, 0xe0, 0xa4, 0x4b, 0x60, 0x39, 0x84, +0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x39, 0xe8, 0xa4, 0x4d, 0x90, 0x39, +0xca, 0x90, 0x28, 0x24, 0x4c, 0xd0, 0xa4, 0x4b, 0x50, 0x39, 0x82, 0x91, +0x98, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x39, 0xf8, +0xa4, 0x4d, 0xd0, 0x39, 0xd2, 0x90, 0x28, 0x24, 0x4d, 0x10, 0xa4, 0x4b, +0x90, 0x39, 0x8a, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x39, 0xf4, 0xa4, +0x4d, 0xc0, 0x39, 0xd0, 0x90, 0x28, 0x24, 0x4d, 0x00, 0xa4, 0x4b, 0x80, +0x39, 0x88, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x3a, +0x04, 0xa4, 0x4e, 0x00, 0x39, 0xd8, 0x90, 0x28, 0x24, 0x4d, 0x40, 0xa4, +0x4b, 0xc0, 0x39, 0x90, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x3a, 0x00, +0xa4, 0x4d, 0xf0, 0x39, 0xd6, 0x90, 0x28, 0x24, 0x4d, 0x30, 0xa4, 0x4b, +0xb0, 0x39, 0x8e, 0x93, 0x70, 0x91, 0xd8, 0xd5, 0x07, 0x80, 0xd0, 0xc4, +0x40, 0x90, 0x48, 0x80, 0x8c, 0x4f, 0x20, 0x84, 0x3a, 0x0e, 0xa4, 0x4d, +0x80, 0x39, 0xc8, 0x90, 0x28, 0x24, 0x4c, 0xc0, 0xa4, 0x4b, 0x40, 0x39, +0x80, 0xd0, 0xc4, 0x40, 0x90, 0x48, 0x80, 0x8c, 0x4e, 0xf0, 0x84, 0x3a, +0x0d, 0xa4, 0x4d, 0x68, 0x39, 0xc5, 0x90, 0x28, 0x24, 0x4c, 0xa8, 0xa4, +0x4b, 0x28, 0x39, 0x7d, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, +0x80, 0x39, 0xf0, 0xa4, 0x4d, 0xb0, 0x39, 0xce, 0x90, 0x28, 0x24, 0x4c, +0xf0, 0xa4, 0x4b, 0x70, 0x39, 0x86, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, +0x39, 0xea, 0xa4, 0x4d, 0x98, 0x39, 0xcb, 0x90, 0x28, 0x24, 0x4c, 0xd8, +0xa4, 0x4b, 0x58, 0x39, 0x83, 0x91, 0x98, 0xd5, 0x06, 0x80, 0xd0, 0xc3, +0x40, 0x90, 0x28, 0x80, 0x39, 0xfc, 0xa4, 0x4d, 0xe0, 0x39, 0xd4, 0x90, +0x28, 0x24, 0x4d, 0x20, 0xa4, 0x4b, 0xa0, 0x39, 0x8c, 0xd0, 0xc3, 0x40, +0x90, 0x28, 0x80, 0x39, 0xf6, 0xa4, 0x4d, 0xc8, 0x39, 0xd1, 0x90, 0x28, +0x24, 0x4d, 0x08, 0xa4, 0x4b, 0x88, 0x39, 0x89, 0xd5, 0x06, 0x80, 0xd0, +0xc3, 0x40, 0x90, 0x28, 0x80, 0x3a, 0x08, 0xa4, 0x4e, 0x10, 0x39, 0xda, +0x90, 0x28, 0x24, 0x4d, 0x50, 0xa4, 0x4b, 0xd0, 0x39, 0x92, 0xd0, 0xc3, +0x40, 0x90, 0x28, 0x80, 0x3a, 0x02, 0xa4, 0x4d, 0xf8, 0x39, 0xd7, 0x90, +0x28, 0x24, 0x4d, 0x38, 0xa4, 0x4b, 0xb8, 0x39, 0x8f, 0x99, 0x08, 0x01, +0xf0, 0x81, 0x90, 0x78, 0xd4, 0xc2, 0x00, 0xa4, 0x01, 0x80, 0x30, 0x2e, +0xa4, 0x01, 0x00, 0x30, 0x1e, 0xd4, 0xc2, 0x00, 0xa4, 0x01, 0xc0, 0x30, +0x32, 0xa4, 0x01, 0x40, 0x30, 0x22, 0x81, 0x90, 0x78, 0xd4, 0xc2, 0x00, +0xa4, 0x01, 0xe0, 0x30, 0x36, 0xa4, 0x01, 0x60, 0x30, 0x26, 0xd4, 0xc2, +0x00, 0xa4, 0x01, 0xd0, 0x30, 0x34, 0xa4, 0x01, 0x50, 0x30, 0x24, 0xa8, +0x0b, 0x18, 0x13, 0xa8, 0x96, 0x80, 0x93, 0x40, 0x99, 0x90, 0x03, 0x00, +0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x21, 0xf0, 0x34, 0x51, 0x24, +0x21, 0xe8, 0x90, 0x38, 0xa4, 0x1f, 0x68, 0x34, 0x00, 0x24, 0x1f, 0x60, +0x90, 0x60, 0x90, 0x38, 0xa4, 0x1c, 0xe0, 0x33, 0xaf, 0x24, 0x1c, 0xd8, +0x90, 0x38, 0xa4, 0x1a, 0x10, 0x33, 0x58, 0x24, 0x1a, 0x08, 0x90, 0xc0, +0x90, 0x60, 0x90, 0x38, 0xa4, 0x21, 0xe0, 0x34, 0x3a, 0x24, 0x21, 0xd8, +0x90, 0x38, 0xa4, 0x1f, 0x58, 0x33, 0xe9, 0x24, 0x1f, 0x50, 0x90, 0x60, +0x90, 0x38, 0xa4, 0x1c, 0xd0, 0x33, 0x98, 0x24, 0x1c, 0xc8, 0x90, 0x38, +0xa4, 0x1a, 0x00, 0x33, 0x3e, 0x24, 0x19, 0xf8, 0xe4, 0xe2, 0x53, 0x00, +0x39, 0x4e, 0x99, 0x90, 0x03, 0x00, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, +0xa4, 0x22, 0x80, 0x34, 0x4e, 0x24, 0x22, 0x78, 0x90, 0x38, 0xa4, 0x1f, +0xf8, 0x33, 0xfd, 0x24, 0x1f, 0xf0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x1d, +0x70, 0x33, 0xac, 0x24, 0x1d, 0x68, 0x90, 0x38, 0xa4, 0x1a, 0xb8, 0x33, +0x55, 0x24, 0x1a, 0xb0, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x21, +0xc8, 0x34, 0x37, 0x24, 0x21, 0xc0, 0x90, 0x38, 0xa4, 0x1f, 0x40, 0x33, +0xe6, 0x24, 0x1f, 0x38, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x1c, 0xb8, 0x33, +0x95, 0x24, 0x1c, 0xb0, 0x90, 0x38, 0xa4, 0x19, 0xe8, 0x33, 0x3b, 0x24, +0x19, 0xe0, 0xe4, 0xe2, 0x54, 0x80, 0x39, 0x54, 0x93, 0x78, 0x99, 0x90, +0x03, 0x00, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x22, 0x50, 0x34, +0x48, 0x24, 0x22, 0x48, 0x90, 0x38, 0xa4, 0x1f, 0xc8, 0x33, 0xf7, 0x24, +0x1f, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x1d, 0x40, 0x33, 0xa6, 0x24, +0x1d, 0x38, 0x90, 0x38, 0xa4, 0x1a, 0x88, 0x33, 0x4f, 0x24, 0x1a, 0x80, +0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x22, 0x68, 0x34, 0x4b, 0x24, +0x22, 0x60, 0x90, 0x38, 0xa4, 0x1f, 0xe0, 0x33, 0xfa, 0x24, 0x1f, 0xd8, +0x90, 0x60, 0x90, 0x38, 0xa4, 0x1d, 0x58, 0x33, 0xa9, 0x24, 0x1d, 0x50, +0x90, 0x38, 0xa4, 0x1a, 0xa0, 0x33, 0x52, 0x24, 0x1a, 0x98, 0xec, 0xa1, +0xa1, 0x40, 0x02, 0x00, 0x36, 0x83, 0xa4, 0x4a, 0xc0, 0x39, 0x5a, 0x88, +0x00, 0x88, 0x10, 0x10, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x1a, 0x28, 0x33, +0x43, 0x24, 0x1a, 0x20, 0xe9, 0x61, 0xa2, 0x40, 0x02, 0x00, 0x36, 0x8a, +0xe3, 0x62, 0x57, 0x80, 0x39, 0x60, 0x95, 0x08, 0x93, 0x40, 0x99, 0x90, +0x03, 0x00, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x22, 0x20, 0x34, +0x42, 0x24, 0x22, 0x18, 0x90, 0x38, 0xa4, 0x1f, 0x98, 0x33, 0xf1, 0x24, +0x1f, 0x90, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x1d, 0x10, 0x33, 0xa0, 0x24, +0x1d, 0x08, 0x90, 0x38, 0xa4, 0x1a, 0x58, 0x33, 0x49, 0x24, 0x1a, 0x50, +0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x22, 0x08, 0x34, 0x3f, 0x24, +0x22, 0x00, 0x90, 0x38, 0xa4, 0x1f, 0x80, 0x33, 0xee, 0x24, 0x1f, 0x78, +0x90, 0x60, 0x90, 0x38, 0xa4, 0x1c, 0xf8, 0x33, 0x9d, 0x24, 0x1c, 0xf0, +0x90, 0x38, 0xa4, 0x1a, 0x40, 0x33, 0x46, 0x24, 0x1a, 0x38, 0xe4, 0xe2, +0x53, 0x40, 0x39, 0x50, 0x88, 0x01, 0x88, 0x90, 0xc0, 0x90, 0x60, 0x90, +0x38, 0xa4, 0x22, 0x38, 0x34, 0x45, 0x24, 0x22, 0x30, 0x90, 0x38, 0xa4, +0x1f, 0xb0, 0x33, 0xf4, 0x24, 0x1f, 0xa8, 0x90, 0x60, 0x90, 0x38, 0xa4, +0x1d, 0x28, 0x33, 0xa3, 0x24, 0x1d, 0x20, 0x90, 0x38, 0xa4, 0x1a, 0x70, +0x33, 0x4c, 0x24, 0x1a, 0x68, 0xe4, 0xe2, 0x54, 0xc0, 0x39, 0x56, 0x92, +0xd0, 0x99, 0x50, 0x02, 0x80, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, +0x30, 0x76, 0x24, 0x03, 0xa8, 0x90, 0x28, 0x80, 0x30, 0x6e, 0x24, 0x03, +0x68, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0x66, 0x24, 0x03, 0x28, 0x90, +0x28, 0x80, 0x30, 0x5c, 0x24, 0x02, 0xd8, 0x90, 0xa0, 0x90, 0x50, 0x90, +0x28, 0x80, 0x30, 0x73, 0x24, 0x03, 0xa0, 0x90, 0x28, 0x80, 0x30, 0x6b, +0x24, 0x03, 0x60, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0x63, 0x24, 0x03, +0x20, 0x90, 0x28, 0x80, 0x30, 0x59, 0x24, 0x02, 0xd0, 0xec, 0xe2, 0x56, +0x60, 0x1f, 0x00, 0x39, 0x5c, 0x88, 0x00, 0x78, 0x10, 0x10, 0x10, 0x10, +0x90, 0x28, 0x80, 0x30, 0x57, 0x24, 0x02, 0xc0, 0xec, 0xe2, 0x57, 0xe1, +0xa2, 0x00, 0x39, 0x62, 0xe5, 0xa1, 0x96, 0xc0, 0x36, 0x59, 0xa0, 0x2a, +0x10, 0xa8, 0x16, 0x60, 0x29, 0xd8, 0xa0, 0x0c, 0x48, 0xa0, 0x0a, 0xc8, +0x95, 0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, +0x80, 0x32, 0xc5, 0x80, 0x32, 0xbb, 0x10, 0x10, 0x80, 0x32, 0xba, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x14, 0x78, 0x33, 0x31, 0xa4, 0x14, 0x28, 0x33, +0x27, 0x10, 0x10, 0xa4, 0x14, 0x20, 0x33, 0x26, 0x90, 0xb8, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x12, 0x38, 0x32, 0x23, 0xa4, 0x11, 0xe8, 0x32, 0x19, +0x10, 0x10, 0xa4, 0x11, 0xe0, 0x32, 0x18, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x13, 0x58, 0x32, 0xfb, 0xa4, 0x13, 0x08, 0x32, 0xf1, 0x10, 0x10, 0xa4, +0x13, 0x00, 0x32, 0xf0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, +0x80, 0x32, 0xb7, 0x80, 0x32, 0xb9, 0x10, 0x10, 0x80, 0x32, 0xb8, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x14, 0x08, 0x33, 0x23, 0xa4, 0x14, 0x18, 0x33, +0x25, 0x10, 0x10, 0xa4, 0x14, 0x10, 0x33, 0x24, 0x90, 0xb8, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x11, 0xc8, 0x32, 0x15, 0xa4, 0x11, 0xd8, 0x32, 0x17, +0x10, 0x10, 0xa4, 0x11, 0xd0, 0x32, 0x16, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x12, 0xe8, 0x32, 0xed, 0xa4, 0x12, 0xf8, 0x32, 0xef, 0x10, 0x10, 0xa4, +0x12, 0xf0, 0x32, 0xee, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, +0x90, 0x28, 0x80, 0x32, 0xc2, 0x80, 0x32, 0xc4, 0x10, 0x10, 0x80, 0x32, +0xc3, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0x60, 0x33, 0x2e, 0xa4, 0x14, +0x70, 0x33, 0x30, 0x10, 0x10, 0xa4, 0x14, 0x68, 0x33, 0x2f, 0x90, 0xb8, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, 0x20, 0x32, 0x20, 0xa4, 0x12, 0x30, +0x32, 0x22, 0x10, 0x10, 0xa4, 0x12, 0x28, 0x32, 0x21, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x13, 0x40, 0x32, 0xf8, 0xa4, 0x13, 0x50, 0x32, 0xfa, 0x10, +0x10, 0xa4, 0x13, 0x48, 0x32, 0xf9, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, +0x90, 0x28, 0x80, 0x32, 0xb4, 0x80, 0x32, 0xb6, 0x10, 0x10, 0x80, 0x32, +0xb5, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0xf0, 0x33, 0x20, 0xa4, 0x14, +0x00, 0x33, 0x22, 0x10, 0x10, 0xa4, 0x13, 0xf8, 0x33, 0x21, 0x90, 0xb8, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, 0xb0, 0x32, 0x12, 0xa4, 0x11, 0xc0, +0x32, 0x14, 0x10, 0x10, 0xa4, 0x11, 0xb8, 0x32, 0x13, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x12, 0xd0, 0x32, 0xea, 0xa4, 0x12, 0xe0, 0x32, 0xec, 0x10, +0x10, 0xa4, 0x12, 0xd8, 0x32, 0xeb, 0x10, 0x10, 0x90, 0xa8, 0x10, 0x10, +0x10, 0x10, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x38, 0x80, 0x33, 0x3a, +0x10, 0x10, 0x80, 0x33, 0x39, 0x90, 0x60, 0x90, 0x30, 0x60, 0xa0, 0x20, +0x80, 0x60, 0xa0, 0x21, 0x00, 0x90, 0x30, 0x60, 0xa0, 0x20, 0xc0, 0x60, +0xa0, 0x21, 0x40, 0x97, 0xf0, 0x95, 0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, +0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xbf, 0x80, 0x32, 0xc1, 0x10, +0x10, 0x80, 0x32, 0xc0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0x48, 0x33, +0x2b, 0xa4, 0x14, 0x58, 0x33, 0x2d, 0x10, 0x10, 0xa4, 0x14, 0x50, 0x33, +0x2c, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, 0x08, 0x32, 0x1d, +0xa4, 0x12, 0x18, 0x32, 0x1f, 0x10, 0x10, 0xa4, 0x12, 0x10, 0x32, 0x1e, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x28, 0x32, 0xf5, 0xa4, 0x13, 0x38, +0x32, 0xf7, 0x10, 0x10, 0xa4, 0x13, 0x30, 0x32, 0xf6, 0x91, 0x40, 0x90, +0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xbc, 0x80, 0x32, 0xbe, 0x10, +0x10, 0x80, 0x32, 0xbd, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0x30, 0x33, +0x28, 0xa4, 0x14, 0x40, 0x33, 0x2a, 0x10, 0x10, 0xa4, 0x14, 0x38, 0x33, +0x29, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, 0xf0, 0x32, 0x1a, +0xa4, 0x12, 0x00, 0x32, 0x1c, 0x10, 0x10, 0xa4, 0x11, 0xf8, 0x32, 0x1b, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x10, 0x32, 0xf2, 0xa4, 0x13, 0x20, +0x32, 0xf4, 0x10, 0x10, 0xa4, 0x13, 0x18, 0x32, 0xf3, 0x10, 0x10, 0x91, +0x40, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xed, 0x80, 0x31, +0xe0, 0x90, 0x28, 0x80, 0x31, 0xdf, 0x80, 0x31, 0xde, 0x90, 0x50, 0x90, +0x28, 0x80, 0x31, 0xe9, 0x80, 0x31, 0xec, 0x90, 0x28, 0x80, 0x31, 0xeb, +0x80, 0x31, 0xea, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xe1, +0x80, 0x31, 0xe4, 0x90, 0x28, 0x80, 0x31, 0xe3, 0x80, 0x31, 0xe2, 0x90, +0x50, 0x90, 0x28, 0x80, 0x31, 0xe5, 0x80, 0x31, 0xe8, 0x90, 0x28, 0x80, +0x31, 0xe7, 0x80, 0x31, 0xe6, 0x91, 0x88, 0x80, 0x90, 0xc0, 0x90, 0x60, +0x90, 0x28, 0x81, 0x30, 0x4a, 0x10, 0x10, 0x80, 0x30, 0x49, 0x90, 0x28, +0x81, 0x30, 0x52, 0x10, 0x10, 0x80, 0x30, 0x51, 0x90, 0x60, 0x90, 0x28, +0x81, 0x30, 0x46, 0x10, 0x10, 0x80, 0x30, 0x45, 0x90, 0x28, 0x81, 0x30, +0x4e, 0x10, 0x10, 0x80, 0x30, 0x4d, 0x80, 0x10, 0x10, 0x10, 0x10, 0x90, +0x28, 0x81, 0x30, 0x55, 0x10, 0x10, 0x80, 0x30, 0x56, 0xa0, 0x0b, 0x90, +0xa0, 0x0a, 0xc8, 0x95, 0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, +0x50, 0x90, 0x28, 0x80, 0x32, 0xb3, 0x80, 0x32, 0xa9, 0x10, 0x10, 0x80, +0x32, 0xa8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0xe8, 0x33, 0x1f, 0xa4, +0x13, 0x98, 0x33, 0x15, 0x10, 0x10, 0xa4, 0x13, 0x90, 0x33, 0x14, 0x90, +0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, 0xa8, 0x32, 0x11, 0xa4, 0x11, +0x58, 0x32, 0x07, 0x10, 0x10, 0xa4, 0x11, 0x50, 0x32, 0x06, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x12, 0xc8, 0x32, 0xe9, 0xa4, 0x12, 0x78, 0x32, 0xdf, +0x10, 0x10, 0xa4, 0x12, 0x70, 0x32, 0xde, 0x91, 0x40, 0x90, 0x88, 0x90, +0x50, 0x90, 0x28, 0x80, 0x32, 0xa5, 0x80, 0x32, 0xa7, 0x10, 0x10, 0x80, +0x32, 0xa6, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x78, 0x33, 0x11, 0xa4, +0x13, 0x88, 0x33, 0x13, 0x10, 0x10, 0xa4, 0x13, 0x80, 0x33, 0x12, 0x90, +0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, 0x38, 0x32, 0x03, 0xa4, 0x11, +0x48, 0x32, 0x05, 0x10, 0x10, 0xa4, 0x11, 0x40, 0x32, 0x04, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x12, 0x58, 0x32, 0xdb, 0xa4, 0x12, 0x68, 0x32, 0xdd, +0x10, 0x10, 0xa4, 0x12, 0x60, 0x32, 0xdc, 0x92, 0xb0, 0x91, 0x40, 0x90, +0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xb0, 0x80, 0x32, 0xb2, 0x10, +0x10, 0x80, 0x32, 0xb1, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0xd0, 0x33, +0x1c, 0xa4, 0x13, 0xe0, 0x33, 0x1e, 0x10, 0x10, 0xa4, 0x13, 0xd8, 0x33, +0x1d, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, 0x90, 0x32, 0x0e, +0xa4, 0x11, 0xa0, 0x32, 0x10, 0x10, 0x10, 0xa4, 0x11, 0x98, 0x32, 0x0f, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, 0xb0, 0x32, 0xe6, 0xa4, 0x12, 0xc0, +0x32, 0xe8, 0x10, 0x10, 0xa4, 0x12, 0xb8, 0x32, 0xe7, 0x91, 0x40, 0x90, +0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xa2, 0x80, 0x32, 0xa4, 0x10, +0x10, 0x80, 0x32, 0xa3, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x60, 0x33, +0x0e, 0xa4, 0x13, 0x70, 0x33, 0x10, 0x10, 0x10, 0xa4, 0x13, 0x68, 0x33, +0x0f, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, 0x20, 0x32, 0x00, +0xa4, 0x11, 0x30, 0x32, 0x02, 0x10, 0x10, 0xa4, 0x11, 0x28, 0x32, 0x01, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, 0x40, 0x32, 0xd8, 0xa4, 0x12, 0x50, +0x32, 0xda, 0x10, 0x10, 0xa4, 0x12, 0x48, 0x32, 0xd9, 0x10, 0x10, 0x80, +0x10, 0x10, 0x10, 0x10, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x35, 0x80, +0x33, 0x37, 0x10, 0x10, 0x80, 0x33, 0x36, 0x80, 0x95, 0x60, 0x92, 0xb0, +0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xad, 0x80, +0x32, 0xaf, 0x10, 0x10, 0x80, 0x32, 0xae, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x13, 0xb8, 0x33, 0x19, 0xa4, 0x13, 0xc8, 0x33, 0x1b, 0x10, 0x10, 0xa4, +0x13, 0xc0, 0x33, 0x1a, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, +0x78, 0x32, 0x0b, 0xa4, 0x11, 0x88, 0x32, 0x0d, 0x10, 0x10, 0xa4, 0x11, +0x80, 0x32, 0x0c, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, 0x98, 0x32, 0xe3, +0xa4, 0x12, 0xa8, 0x32, 0xe5, 0x10, 0x10, 0xa4, 0x12, 0xa0, 0x32, 0xe4, +0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xaa, 0x80, +0x32, 0xac, 0x10, 0x10, 0x80, 0x32, 0xab, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x13, 0xa0, 0x33, 0x16, 0xa4, 0x13, 0xb0, 0x33, 0x18, 0x10, 0x10, 0xa4, +0x13, 0xa8, 0x33, 0x17, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x11, +0x60, 0x32, 0x08, 0xa4, 0x11, 0x70, 0x32, 0x0a, 0x10, 0x10, 0xa4, 0x11, +0x68, 0x32, 0x09, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, 0x80, 0x32, 0xe0, +0xa4, 0x12, 0x90, 0x32, 0xe2, 0x10, 0x10, 0xa4, 0x12, 0x88, 0x32, 0xe1, +0x10, 0x10, 0x91, 0x40, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, +0xdd, 0x80, 0x31, 0xd0, 0x90, 0x28, 0x80, 0x31, 0xcf, 0x80, 0x31, 0xce, +0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xd9, 0x80, 0x31, 0xdc, 0x90, 0x28, +0x80, 0x31, 0xdb, 0x80, 0x31, 0xda, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, +0x80, 0x31, 0xd1, 0x80, 0x31, 0xd4, 0x90, 0x28, 0x80, 0x31, 0xd3, 0x80, +0x31, 0xd2, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xd5, 0x80, 0x31, 0xd8, +0x90, 0x28, 0x80, 0x31, 0xd7, 0x80, 0x31, 0xd6, 0xc3, 0xc0, 0x30, 0xd1, +0x9c, 0xe8, 0x07, 0x60, 0x91, 0x90, 0x90, 0xf0, 0x10, 0x10, 0x80, 0x88, +0x00, 0x80, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0x9e, 0x80, 0x30, 0x9f, +0x81, 0x30, 0xa4, 0xd0, 0x41, 0x80, 0x24, 0x05, 0x48, 0x24, 0x05, 0x50, +0x10, 0x10, 0x80, 0x90, 0x58, 0x80, 0x90, 0x28, 0x24, 0x04, 0xe0, 0x24, +0x04, 0xe8, 0x81, 0x24, 0x05, 0x40, 0x92, 0x68, 0x91, 0x00, 0x80, 0x90, +0x90, 0x90, 0x30, 0x80, 0x24, 0x05, 0x70, 0x90, 0x38, 0xa4, 0x05, 0x80, +0x30, 0x1c, 0x80, 0x30, 0x1b, 0x80, 0x90, 0x28, 0x80, 0x31, 0xb8, 0xa4, +0x05, 0x28, 0x31, 0xb9, 0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x28, 0x80, +0x30, 0xc6, 0xa4, 0x05, 0x68, 0x30, 0xc7, 0x90, 0x28, 0x80, 0x30, 0x1a, +0xa4, 0x05, 0x78, 0x30, 0x19, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xb6, +0x80, 0x31, 0xb7, 0x90, 0x28, 0x24, 0x05, 0x58, 0x24, 0x05, 0x60, 0x90, +0x58, 0x80, 0x10, 0x10, 0x80, 0x10, 0x10, 0x80, 0x30, 0xd0, 0x80, 0x90, +0x40, 0x10, 0x10, 0x80, 0x24, 0x05, 0x18, 0x80, 0x10, 0x10, 0x80, 0x30, +0xcf, 0x91, 0x58, 0x91, 0x00, 0x90, 0x80, 0x81, 0x90, 0x50, 0x90, 0x28, +0x80, 0x30, 0x9a, 0x80, 0x30, 0x9b, 0x81, 0x30, 0xa2, 0x81, 0x90, 0x50, +0x90, 0x28, 0x80, 0x30, 0x7d, 0x80, 0x30, 0x7e, 0x81, 0x30, 0x81, 0x83, +0x90, 0x28, 0x24, 0x04, 0xc0, 0x24, 0x04, 0xc8, 0x90, 0xe8, 0x81, 0x90, +0x88, 0x90, 0x38, 0x10, 0x10, 0x80, 0x30, 0xc5, 0x90, 0x28, 0x80, 0x30, +0x18, 0x80, 0x30, 0x17, 0x80, 0x90, 0x28, 0x80, 0x31, 0xb4, 0x80, 0x31, +0xb5, 0x82, 0x10, 0x10, 0x80, 0x24, 0x05, 0x08, 0xa0, 0x0d, 0xa8, 0x9e, +0x10, 0x06, 0x98, 0x93, 0x00, 0x91, 0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, +0x38, 0xa4, 0x14, 0xb8, 0x32, 0xa1, 0x24, 0x14, 0xb0, 0x90, 0x38, 0xa4, +0x18, 0x18, 0x33, 0x0d, 0x24, 0x18, 0x10, 0x90, 0x60, 0x90, 0x38, 0xa4, +0x0f, 0xa8, 0x31, 0xff, 0x24, 0x0f, 0xa0, 0x90, 0x38, 0xa4, 0x16, 0x68, +0x32, 0xd7, 0x24, 0x16, 0x60, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, +0x14, 0xa8, 0x32, 0x93, 0x24, 0x14, 0xa0, 0x90, 0x38, 0xa4, 0x18, 0x08, +0x32, 0xff, 0x24, 0x18, 0x00, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x0f, 0x98, +0x31, 0xf1, 0x24, 0x0f, 0x90, 0x90, 0x38, 0xa4, 0x16, 0x58, 0x32, 0xc9, +0x24, 0x16, 0x50, 0x91, 0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, +0x15, 0x00, 0x32, 0x9e, 0x24, 0x14, 0xf8, 0x90, 0x38, 0xa4, 0x18, 0x60, +0x33, 0x0a, 0x24, 0x18, 0x58, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x0f, 0xf0, +0x31, 0xfc, 0x24, 0x0f, 0xe8, 0x90, 0x38, 0xa4, 0x16, 0xb0, 0x32, 0xd4, +0x24, 0x16, 0xa8, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x14, 0x90, +0x32, 0x90, 0x24, 0x14, 0x88, 0x90, 0x38, 0xa4, 0x17, 0xf0, 0x32, 0xfc, +0x24, 0x17, 0xe8, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x0f, 0x80, 0x31, 0xee, +0x24, 0x0f, 0x78, 0x90, 0x38, 0xa4, 0x16, 0x40, 0x32, 0xc6, 0x24, 0x16, +0x38, 0x10, 0x10, 0x80, 0x10, 0x10, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x19, +0xa0, 0x33, 0x32, 0x24, 0x19, 0x98, 0xd7, 0x1c, 0x40, 0x91, 0xc0, 0x90, +0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3b, 0xf8, 0x37, 0x51, 0xa4, 0x3b, +0x38, 0x37, 0x6f, 0x90, 0x38, 0xa4, 0x3b, 0xd8, 0x37, 0x6b, 0xa4, 0x3b, +0xb8, 0x37, 0x73, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3d, 0x88, 0x37, 0x83, +0xa4, 0x3c, 0xc8, 0x37, 0xa1, 0x90, 0x38, 0xa4, 0x3d, 0x68, 0x37, 0x9d, +0xa4, 0x3d, 0x48, 0x37, 0xa5, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, +0x40, 0xa8, 0x37, 0xe7, 0xa4, 0x3f, 0xe8, 0x38, 0x05, 0x90, 0x38, 0xa4, +0x40, 0x88, 0x38, 0x01, 0xa4, 0x40, 0x68, 0x38, 0x09, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x3f, 0x18, 0x37, 0xb5, 0xa4, 0x3e, 0x58, 0x37, 0xd3, 0x90, +0x38, 0xa4, 0x3e, 0xf8, 0x37, 0xcf, 0xa4, 0x3e, 0xd8, 0x37, 0xd7, 0x91, +0xc0, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3b, 0x00, 0x37, 0x62, +0xa4, 0x3a, 0xa0, 0x37, 0x58, 0x90, 0x38, 0xa4, 0x3a, 0xf0, 0x37, 0x56, +0xa4, 0x3a, 0xe0, 0x37, 0x5a, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3c, 0x90, +0x37, 0x94, 0xa4, 0x3c, 0x30, 0x37, 0x8a, 0x90, 0x38, 0xa4, 0x3c, 0x80, +0x37, 0x88, 0xa4, 0x3c, 0x70, 0x37, 0x8c, 0x90, 0xe0, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x3f, 0xb0, 0x37, 0xf8, 0xa4, 0x3f, 0x50, 0x37, 0xee, 0x90, +0x38, 0xa4, 0x3f, 0xa0, 0x37, 0xec, 0xa4, 0x3f, 0x90, 0x37, 0xf0, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x3e, 0x20, 0x37, 0xc6, 0xa4, 0x3d, 0xc0, 0x37, +0xbc, 0x90, 0x38, 0xa4, 0x3e, 0x10, 0x37, 0xba, 0xa4, 0x3e, 0x00, 0x37, +0xbe, 0x9c, 0xe0, 0x06, 0x90, 0x93, 0x00, 0x91, 0x80, 0x90, 0xc0, 0x90, +0x60, 0x90, 0x38, 0xa4, 0x14, 0xe8, 0x32, 0x9b, 0x24, 0x14, 0xe0, 0x90, +0x38, 0xa4, 0x18, 0x48, 0x33, 0x07, 0x24, 0x18, 0x40, 0x90, 0x60, 0x90, +0x38, 0xa4, 0x0f, 0xd8, 0x31, 0xf9, 0x24, 0x0f, 0xd0, 0x90, 0x38, 0xa4, +0x16, 0x98, 0x32, 0xd1, 0x24, 0x16, 0x90, 0x90, 0xc0, 0x90, 0x60, 0x90, +0x38, 0xa4, 0x14, 0xd0, 0x32, 0x98, 0x24, 0x14, 0xc8, 0x90, 0x38, 0xa4, +0x18, 0x30, 0x33, 0x04, 0x24, 0x18, 0x28, 0x90, 0x60, 0x90, 0x38, 0xa4, +0x0f, 0xc0, 0x31, 0xf6, 0x24, 0x0f, 0xb8, 0x90, 0x38, 0xa4, 0x16, 0x80, +0x32, 0xce, 0x24, 0x16, 0x78, 0x10, 0x10, 0x90, 0xe0, 0x90, 0x70, 0x90, +0x38, 0xa4, 0x0e, 0x00, 0x31, 0xcd, 0xa4, 0x0d, 0xf0, 0x31, 0xbf, 0x90, +0x38, 0xa4, 0x0e, 0x60, 0x31, 0xc9, 0xa4, 0x0e, 0x50, 0x31, 0xcb, 0x90, +0x70, 0x90, 0x38, 0xa4, 0x0e, 0x20, 0x31, 0xc1, 0xa4, 0x0e, 0x10, 0x31, +0xc3, 0x90, 0x38, 0xa4, 0x0e, 0x40, 0x31, 0xc5, 0xa4, 0x0e, 0x30, 0x31, +0xc7, 0x91, 0x48, 0x80, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, +0x48, 0x24, 0x02, 0x38, 0x90, 0x28, 0x80, 0x30, 0x50, 0x24, 0x02, 0x78, +0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0x44, 0x24, 0x02, 0x18, 0x90, 0x28, +0x80, 0x30, 0x4c, 0x24, 0x02, 0x58, 0x80, 0x10, 0x10, 0x10, 0x10, 0x90, +0x28, 0x80, 0x30, 0x53, 0x24, 0x02, 0xa0, 0xd7, 0x1c, 0x40, 0x91, 0xc0, +0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3c, 0x08, 0x37, 0x64, 0xa4, +0x3b, 0x48, 0x37, 0x71, 0x90, 0x38, 0xa4, 0x3b, 0xe8, 0x37, 0x6d, 0xa4, +0x3b, 0xc8, 0x37, 0x75, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3d, 0x98, 0x37, +0x96, 0xa4, 0x3c, 0xd8, 0x37, 0xa3, 0x90, 0x38, 0xa4, 0x3d, 0x78, 0x37, +0x9f, 0xa4, 0x3d, 0x58, 0x37, 0xa7, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, +0xa4, 0x40, 0xb8, 0x37, 0xfa, 0xa4, 0x3f, 0xf8, 0x38, 0x07, 0x90, 0x38, +0xa4, 0x40, 0x98, 0x38, 0x03, 0xa4, 0x40, 0x78, 0x38, 0x0b, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x3f, 0x28, 0x37, 0xc8, 0xa4, 0x3e, 0x68, 0x37, 0xd5, +0x90, 0x38, 0xa4, 0x3f, 0x08, 0x37, 0xd1, 0xa4, 0x3e, 0xe8, 0x37, 0xd9, +0x91, 0xc0, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3b, 0x08, 0x37, +0x63, 0xa4, 0x3a, 0xa8, 0x37, 0x59, 0x90, 0x38, 0xa4, 0x3a, 0xf8, 0x37, +0x57, 0xa4, 0x3a, 0xe8, 0x37, 0x5b, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x3c, +0x98, 0x37, 0x95, 0xa4, 0x3c, 0x38, 0x37, 0x8b, 0x90, 0x38, 0xa4, 0x3c, +0x88, 0x37, 0x89, 0xa4, 0x3c, 0x78, 0x37, 0x8d, 0x90, 0xe0, 0x90, 0x70, +0x90, 0x38, 0xa4, 0x3f, 0xb8, 0x37, 0xf9, 0xa4, 0x3f, 0x58, 0x37, 0xef, +0x90, 0x38, 0xa4, 0x3f, 0xa8, 0x37, 0xed, 0xa4, 0x3f, 0x98, 0x37, 0xf1, +0x90, 0x70, 0x90, 0x38, 0xa4, 0x3e, 0x28, 0x37, 0xc7, 0xa4, 0x3d, 0xc8, +0x37, 0xbd, 0x90, 0x38, 0xa4, 0x3e, 0x18, 0x37, 0xbb, 0xa4, 0x3e, 0x08, +0x37, 0xbf, 0xa0, 0x14, 0x90, 0xa0, 0x10, 0xb8, 0xa0, 0x0c, 0x88, 0x9e, +0x88, 0x09, 0xd0, 0x94, 0xf0, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, +0x10, 0xc9, 0xe1, 0xa0, 0x00, 0x85, 0x35, 0xb3, 0xcb, 0x61, 0x65, 0x00, +0x85, 0x35, 0x7b, 0x9a, 0x00, 0x03, 0xf8, 0x91, 0x98, 0x80, 0x91, 0x10, +0x90, 0xa0, 0x90, 0x68, 0x90, 0x20, 0x30, 0xc4, 0xc9, 0xe1, 0x9d, 0x00, +0x85, 0x35, 0xb1, 0xa4, 0x06, 0x18, 0x30, 0xc2, 0x90, 0x38, 0xa4, 0x04, +0xa8, 0x30, 0x96, 0xa4, 0x04, 0xa0, 0x30, 0x93, 0x90, 0x48, 0x10, 0x10, +0xa4, 0x05, 0xd8, 0x30, 0xbc, 0x10, 0x10, 0x80, 0x30, 0xb8, 0x81, 0x10, +0x10, 0x80, 0xa4, 0x05, 0xa8, 0x30, 0xb6, 0x91, 0xb0, 0x91, 0x60, 0x90, +0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0x00, 0x30, 0xc1, 0xa4, 0x05, +0xf8, 0x30, 0xbe, 0x90, 0x38, 0xa4, 0x04, 0x88, 0x30, 0x92, 0xa4, 0x04, +0x80, 0x30, 0x8f, 0x90, 0x48, 0x10, 0x10, 0xa4, 0x05, 0xc8, 0x30, 0xba, +0x10, 0x10, 0x80, 0x30, 0xb7, 0x90, 0x28, 0x80, 0x30, 0xa0, 0x80, 0x30, +0x97, 0x81, 0x10, 0x10, 0x80, 0xa4, 0x05, 0x98, 0x30, 0xb4, 0xcb, 0x61, +0x64, 0xc0, 0x85, 0x35, 0x70, 0x90, 0xd8, 0x88, 0x00, 0x90, 0x84, 0x90, +0x38, 0xc1, 0xc0, 0x85, 0x31, 0xb3, 0xc9, 0xe1, 0x9c, 0xc0, 0x85, 0x35, +0xaf, 0xcb, 0x61, 0x64, 0x80, 0x85, 0x35, 0x6f, 0x88, 0x00, 0x68, 0x84, +0x10, 0x10, 0xc9, 0xe1, 0x9c, 0x80, 0x85, 0x35, 0xad, 0xcb, 0x61, 0x64, +0x40, 0x85, 0x35, 0x6e, 0x91, 0xf8, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, +0x10, 0x10, 0xc9, 0xe1, 0x9e, 0x40, 0x85, 0x35, 0xbd, 0xcb, 0x61, 0x65, +0x80, 0x85, 0x35, 0x74, 0x88, 0x01, 0x00, 0x90, 0xa0, 0x81, 0x90, 0x70, +0x80, 0x90, 0x20, 0x30, 0xbd, 0xc9, 0xe1, 0x9e, 0x00, 0x85, 0x35, 0xbb, +0x81, 0x30, 0x8e, 0x81, 0x10, 0x10, 0x80, 0xa4, 0x05, 0x88, 0x30, 0xb2, +0xcb, 0x61, 0x66, 0x80, 0x85, 0x35, 0x73, 0x90, 0xb0, 0x88, 0x00, 0x68, +0x84, 0x10, 0x10, 0xc9, 0xe1, 0x9d, 0xc0, 0x85, 0x35, 0xb9, 0xcb, 0x61, +0x66, 0x40, 0x85, 0x35, 0x72, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, +0xe1, 0x9d, 0x80, 0x85, 0x35, 0xb7, 0xcb, 0x61, 0x66, 0x00, 0x85, 0x35, +0x71, 0x92, 0x38, 0x81, 0x91, 0x68, 0x91, 0x18, 0x90, 0x80, 0x90, 0x40, +0x80, 0xa4, 0x54, 0xc8, 0x3a, 0x9a, 0x80, 0xa4, 0x02, 0x10, 0x30, 0x41, +0x90, 0x28, 0x81, 0x3a, 0x97, 0x90, 0x38, 0xa4, 0x54, 0x88, 0x3a, 0x93, +0xa4, 0x00, 0x10, 0x30, 0xc9, 0x90, 0x28, 0x80, 0x30, 0x80, 0x80, 0x30, +0x7f, 0x80, 0x90, 0x40, 0x10, 0x10, 0x80, 0x24, 0x02, 0x00, 0x10, 0x10, +0x90, 0x38, 0xa4, 0x54, 0x80, 0x3a, 0x92, 0xa4, 0x00, 0x08, 0x30, 0xc8, +0x90, 0x50, 0x80, 0xc9, 0xa2, 0xa5, 0x40, 0x85, 0x31, 0xb2, 0x80, 0x3a, +0x96, 0x9a, 0xd0, 0x03, 0xe0, 0x91, 0x60, 0x90, 0xb0, 0x88, 0x00, 0x68, +0x84, 0x10, 0x10, 0xc9, 0xe1, 0x9f, 0x80, 0x85, 0x35, 0xc7, 0xcb, 0x61, +0x67, 0x80, 0x85, 0x35, 0x79, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, +0xe1, 0x9f, 0x40, 0x85, 0x35, 0xc5, 0xcb, 0x61, 0x67, 0x40, 0x85, 0x35, +0x78, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x9f, +0x00, 0x85, 0x35, 0xc3, 0xcb, 0x61, 0x67, 0x00, 0x85, 0x35, 0x77, 0x88, +0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x9e, 0xc0, 0x85, 0x35, 0xc1, +0xcb, 0x61, 0x66, 0xc0, 0x85, 0x35, 0x76, 0x90, 0x90, 0x90, 0x48, 0xcb, +0xa1, 0x3b, 0x40, 0x85, 0x34, 0xd8, 0xcb, 0xa1, 0x3b, 0x00, 0x85, 0x34, +0xd7, 0x90, 0x48, 0xcb, 0xa1, 0x3a, 0xc0, 0x85, 0x34, 0xd6, 0xcb, 0xa1, +0x3a, 0x80, 0x85, 0x34, 0xd5, 0xcb, 0xa2, 0xa6, 0x00, 0x80, 0x31, 0xb1, +0x92, 0x40, 0x91, 0x20, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x2b, 0x10, 0x84, +0x24, 0x25, 0x48, 0x8c, 0x2b, 0x08, 0x84, 0x24, 0x24, 0xf0, 0x90, 0x48, +0x8c, 0x2b, 0x00, 0x84, 0x24, 0x24, 0xe8, 0x8c, 0x2a, 0xf8, 0x84, 0x24, +0x24, 0xe0, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x2b, 0x38, 0x84, 0x24, 0x25, +0x10, 0x8c, 0x2b, 0x30, 0x84, 0x24, 0x25, 0x08, 0x90, 0x48, 0x8c, 0x2b, +0x28, 0x84, 0x24, 0x25, 0x00, 0x8c, 0x2b, 0x20, 0x84, 0x24, 0x24, 0xf8, +0x91, 0x20, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x2b, 0x60, 0x84, 0x24, 0x25, +0x38, 0x8c, 0x2b, 0x58, 0x84, 0x24, 0x25, 0x30, 0x90, 0x48, 0x8c, 0x2b, +0x50, 0x84, 0x24, 0x25, 0x28, 0x8c, 0x2b, 0x48, 0x84, 0x24, 0x25, 0x20, +0x90, 0x38, 0xa4, 0x26, 0x90, 0x34, 0xd3, 0xa4, 0x26, 0x80, 0x34, 0xd1, +0xa0, 0x0f, 0x50, 0xa0, 0x09, 0x08, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x90, +0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x21, 0xce, 0x00, 0x37, 0x34, +0xe5, 0x21, 0xca, 0x80, 0x37, 0x44, 0xcb, 0x61, 0x54, 0x80, 0x85, 0x35, +0x4d, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x21, 0xbb, 0x00, 0x36, 0xe8, 0xe5, +0x21, 0xb7, 0x80, 0x36, 0xf8, 0xcb, 0x61, 0x54, 0x40, 0x85, 0x35, 0x42, +0x90, 0x48, 0xcb, 0xa1, 0x54, 0x00, 0x85, 0x35, 0x41, 0xcb, 0xa1, 0x53, +0xc0, 0x85, 0x35, 0x40, 0x91, 0x90, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, +0xe5, 0x21, 0xc6, 0x00, 0x37, 0x1e, 0xe5, 0x21, 0xc4, 0x80, 0x37, 0x24, +0xcb, 0x61, 0x55, 0xc0, 0x85, 0x35, 0x46, 0x98, 0x50, 0x00, 0x80, 0xe5, +0x21, 0xb3, 0x00, 0x36, 0xd2, 0xe5, 0x21, 0xb1, 0x80, 0x36, 0xd8, 0xcb, +0x61, 0x55, 0x80, 0x85, 0x35, 0x45, 0x90, 0x48, 0xcb, 0xa1, 0x55, 0x40, +0x85, 0x35, 0x44, 0xcb, 0xa1, 0x55, 0x00, 0x85, 0x35, 0x43, 0x92, 0x20, +0x91, 0x30, 0x90, 0xb8, 0xd5, 0x03, 0x00, 0xc0, 0xc0, 0x81, 0x8c, 0x48, +0xa8, 0x84, 0x39, 0x45, 0xc0, 0xc0, 0x81, 0x8c, 0x48, 0x88, 0x84, 0x39, +0x41, 0xd5, 0x02, 0x00, 0xc0, 0xc0, 0x81, 0x39, 0x21, 0xc0, 0xc0, 0x81, +0x39, 0x1d, 0x90, 0x78, 0xd5, 0x02, 0x00, 0xc0, 0xc0, 0x81, 0x39, 0x2d, +0xc0, 0xc0, 0x81, 0x39, 0x29, 0xd5, 0x02, 0x00, 0xc0, 0xc0, 0x81, 0x39, +0x39, 0xc0, 0xc0, 0x81, 0x39, 0x35, 0x91, 0x70, 0x90, 0xd8, 0xd5, 0x03, +0x80, 0xc8, 0xe1, 0xbf, 0x80, 0x81, 0x8c, 0x48, 0xc8, 0x84, 0x39, 0x43, +0xc8, 0xe1, 0xc0, 0x80, 0x81, 0x8c, 0x48, 0x98, 0x84, 0x39, 0x42, 0xd5, +0x02, 0x80, 0xc8, 0xe1, 0xc3, 0x00, 0x81, 0x39, 0x25, 0xc8, 0xe1, 0xbf, +0x00, 0x81, 0x39, 0x1f, 0x90, 0x98, 0xd5, 0x02, 0x80, 0xc8, 0xe1, 0xac, +0x80, 0x81, 0x39, 0x31, 0xc8, 0xe1, 0xad, 0x80, 0x81, 0x39, 0x2b, 0xd5, +0x02, 0x80, 0xc8, 0xe1, 0xb0, 0x00, 0x81, 0x39, 0x3d, 0xc8, 0xe1, 0xac, +0x00, 0x81, 0x39, 0x37, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x90, 0x90, 0xc8, +0x98, 0x50, 0x00, 0x80, 0xe5, 0x21, 0xcc, 0x00, 0x37, 0x2c, 0xe5, 0x21, +0xc9, 0x80, 0x37, 0x40, 0xcb, 0x61, 0x57, 0x00, 0x85, 0x35, 0x4b, 0x98, +0x50, 0x00, 0x80, 0xe5, 0x21, 0xb9, 0x00, 0x36, 0xe0, 0xe5, 0x21, 0xb6, +0x80, 0x36, 0xf4, 0xcb, 0x61, 0x56, 0xc0, 0x85, 0x35, 0x4a, 0x90, 0x48, +0xcb, 0xa1, 0x56, 0x80, 0x85, 0x35, 0x49, 0xcb, 0xa1, 0x56, 0x40, 0x85, +0x35, 0x48, 0x91, 0x90, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x21, +0xc5, 0x00, 0x37, 0x1a, 0xe5, 0x21, 0xc3, 0x80, 0x37, 0x20, 0xcb, 0x61, +0x33, 0x40, 0x85, 0x34, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x21, 0xb2, +0x00, 0x36, 0xce, 0xe5, 0x21, 0xb0, 0x80, 0x36, 0xd4, 0xcb, 0x61, 0x33, +0x00, 0x85, 0x34, 0xc7, 0x90, 0x48, 0xcb, 0xa1, 0x32, 0xc0, 0x85, 0x34, +0xc6, 0xcb, 0xa1, 0x32, 0x80, 0x85, 0x34, 0xc5, 0x91, 0x00, 0x90, 0x80, +0x90, 0x40, 0xe5, 0x22, 0x38, 0x40, 0x38, 0xe7, 0xe5, 0x22, 0x3b, 0xc0, +0x38, 0xf3, 0x90, 0x40, 0xe5, 0x22, 0x3e, 0x40, 0x38, 0xff, 0xe5, 0x22, +0x41, 0xc0, 0x39, 0x0b, 0x90, 0x80, 0x90, 0x40, 0xe5, 0x22, 0x38, 0x80, +0x38, 0xe9, 0xe5, 0x22, 0x3c, 0x00, 0x38, 0xf5, 0x90, 0x40, 0xe5, 0x22, +0x3e, 0x80, 0x39, 0x01, 0xe5, 0x22, 0x42, 0x00, 0x39, 0x0d, 0x80, 0x99, +0x28, 0x02, 0xf0, 0x8c, 0x25, 0x80, 0x90, 0x80, 0x90, 0x40, 0xe5, 0x21, +0xcf, 0x80, 0x37, 0x3c, 0xe5, 0x21, 0xca, 0x00, 0x37, 0x42, 0x90, 0x40, +0xe5, 0x21, 0xbc, 0x80, 0x36, 0xf0, 0xe5, 0x21, 0xb7, 0x00, 0x36, 0xf6, +0x91, 0x48, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x21, 0xc5, 0x80, +0x37, 0x1c, 0xe5, 0x21, 0xc4, 0x00, 0x37, 0x22, 0xcb, 0x60, 0x01, 0xc0, +0x85, 0x30, 0x03, 0x90, 0x40, 0xe5, 0x21, 0xb2, 0x80, 0x36, 0xd0, 0xe5, +0x21, 0xb1, 0x00, 0x36, 0xd6, 0x90, 0x48, 0xcb, 0xa0, 0x02, 0x40, 0x85, +0x30, 0x05, 0xcb, 0xa0, 0x02, 0x80, 0x85, 0x30, 0x06, 0x10, 0x10, 0x90, +0x80, 0x90, 0x40, 0xe5, 0x21, 0xc2, 0x00, 0x37, 0x06, 0xe5, 0x21, 0xbe, +0x80, 0x37, 0x0a, 0x90, 0x40, 0xe5, 0x21, 0xaf, 0x00, 0x36, 0xba, 0xe5, +0x21, 0xab, 0x80, 0x36, 0xbe, +}; + +static const struct ia64_dis_names ia64_dis_names[] = { +{ 0x1, 391, 0 }, +{ 0x1, 389, 0 }, +{ 0x1, 388, 0 }, +{ 0x4, 387, 1 }, +{ 0x8, 387, 0 }, +{ 0x2, 387, 0 }, +{ 0x1, 387, 0 }, +{ 0x4, 385, 1 }, +{ 0x1, 386, 0 }, +{ 0x2, 385, 0 }, +{ 0x1, 385, 0 }, +{ 0x4, 384, 0 }, +{ 0x2, 384, 0 }, +{ 0x1, 384, 0 }, +{ 0x4, 383, 0 }, +{ 0x2, 383, 0 }, +{ 0x1, 383, 0 }, +{ 0x4, 382, 0 }, +{ 0x2, 382, 0 }, +{ 0x1, 382, 0 }, +{ 0x4, 381, 0 }, +{ 0x2, 381, 0 }, +{ 0x1, 381, 0 }, +{ 0x2, 380, 0 }, +{ 0x1, 380, 0 }, +{ 0x2, 379, 0 }, +{ 0x1, 379, 0 }, +{ 0x2, 378, 0 }, +{ 0x1, 378, 0 }, +{ 0x1, 376, 0 }, +{ 0x2, 374, 1 }, +{ 0x1, 375, 0 }, +{ 0x12, 374, 1 }, +{ 0x11, 375, 0 }, +{ 0xa, 374, 1 }, +{ 0x9, 375, 0 }, +{ 0x1a, 374, 1 }, +{ 0x7, 375, 0 }, +{ 0x6, 374, 1 }, +{ 0x5, 375, 0 }, +{ 0x5, 374, 1 }, +{ 0x12, 375, 0 }, +{ 0xd, 374, 1 }, +{ 0xe, 375, 0 }, +{ 0x3, 374, 1 }, +{ 0xa, 375, 0 }, +{ 0x2, 371, 1 }, +{ 0x1, 372, 0 }, +{ 0x12, 371, 1 }, +{ 0x11, 372, 0 }, +{ 0xa, 371, 1 }, +{ 0x9, 372, 0 }, +{ 0x1a, 371, 1 }, +{ 0x7, 372, 0 }, +{ 0x6, 371, 1 }, +{ 0x5, 372, 0 }, +{ 0x5, 371, 1 }, +{ 0x12, 372, 0 }, +{ 0xd, 371, 1 }, +{ 0xe, 372, 0 }, +{ 0x3, 371, 1 }, +{ 0xa, 372, 0 }, +{ 0x1, 370, 0 }, +{ 0x1, 365, 0 }, +{ 0x1, 364, 0 }, +{ 0x1, 363, 0 }, +{ 0x1, 362, 0 }, +{ 0x2, 361, 0 }, +{ 0x1, 361, 0 }, +{ 0x2, 360, 0 }, +{ 0x1, 360, 0 }, +{ 0x2, 359, 0 }, +{ 0x1, 359, 0 }, +{ 0x2, 358, 0 }, +{ 0x1, 358, 0 }, +{ 0x2, 357, 0 }, +{ 0x1, 357, 0 }, +{ 0x2, 356, 0 }, +{ 0x1, 356, 0 }, +{ 0x2, 355, 0 }, +{ 0x1, 355, 0 }, +{ 0x2, 354, 0 }, +{ 0x1, 354, 0 }, +{ 0x1, 353, 0 }, +{ 0x3, 353, 0 }, +{ 0x1, 352, 0 }, +{ 0x3, 352, 0 }, +{ 0x8, 351, 0 }, +{ 0x18, 351, 0 }, +{ 0x4, 351, 0 }, +{ 0xc, 351, 0 }, +{ 0x2, 351, 0 }, +{ 0x1, 351, 0 }, +{ 0x8, 350, 0 }, +{ 0x18, 350, 0 }, +{ 0x4, 350, 0 }, +{ 0xc, 350, 0 }, +{ 0x2, 350, 0 }, +{ 0x1, 350, 0 }, +{ 0x4, 349, 0 }, +{ 0xc, 349, 0 }, +{ 0x2, 349, 0 }, +{ 0x1, 349, 0 }, +{ 0x4, 348, 0 }, +{ 0xc, 348, 0 }, +{ 0x2, 348, 0 }, +{ 0x1, 348, 0 }, +{ 0x4, 347, 0 }, +{ 0xc, 347, 0 }, +{ 0x2, 347, 0 }, +{ 0x1, 347, 0 }, +{ 0x4, 346, 0 }, +{ 0xc, 346, 0 }, +{ 0x2, 346, 0 }, +{ 0x1, 346, 0 }, +{ 0x4, 345, 0 }, +{ 0xc, 345, 0 }, +{ 0x2, 345, 0 }, +{ 0x1, 345, 0 }, +{ 0x4, 344, 0 }, +{ 0xc, 344, 0 }, +{ 0x2, 344, 0 }, +{ 0x1, 344, 0 }, +{ 0x1, 343, 0 }, +{ 0x1, 341, 0 }, +{ 0x2, 340, 0 }, +{ 0x1, 340, 0 }, +{ 0x1, 338, 0 }, +{ 0x1, 337, 0 }, +{ 0x1, 336, 0 }, +{ 0x8, 334, 0 }, +{ 0x4, 334, 0 }, +{ 0x2, 334, 0 }, +{ 0x1, 334, 0 }, +{ 0x1, 333, 0 }, +{ 0x1, 332, 0 }, +{ 0x1, 331, 0 }, +{ 0x2, 330, 0 }, +{ 0x1, 330, 0 }, +{ 0x2, 328, 0 }, +{ 0x1, 328, 0 }, +{ 0x1, 327, 0 }, +{ 0x1, 326, 0 }, +{ 0x8, 325, 0 }, +{ 0x4, 325, 0 }, +{ 0x2, 325, 0 }, +{ 0x1, 325, 0 }, +{ 0x8, 324, 0 }, +{ 0x4, 324, 0 }, +{ 0x2, 324, 0 }, +{ 0x1, 324, 0 }, +{ 0x1, 323, 0 }, +{ 0x2, 322, 0 }, +{ 0x1, 322, 0 }, +{ 0x2, 321, 0 }, +{ 0x1, 321, 0 }, +{ 0x2, 320, 0 }, +{ 0x1, 320, 0 }, +{ 0x2, 319, 0 }, +{ 0x1, 319, 0 }, +{ 0x1, 318, 0 }, +{ 0x1, 317, 0 }, +{ 0x1, 316, 0 }, +{ 0x1, 315, 0 }, +{ 0x1, 314, 0 }, +{ 0x1, 313, 0 }, +{ 0x2, 310, 0 }, +{ 0x1, 310, 0 }, +{ 0x1, 309, 0 }, +{ 0x2, 308, 0 }, +{ 0x1, 308, 0 }, +{ 0x2, 307, 0 }, +{ 0x1, 307, 0 }, +{ 0x1, 306, 0 }, +{ 0x1, 305, 0 }, +{ 0x1, 304, 0 }, +{ 0x1, 303, 0 }, +{ 0x2, 302, 0 }, +{ 0x1, 302, 0 }, +{ 0x2, 301, 0 }, +{ 0x1, 301, 0 }, +{ 0x2, 300, 0 }, +{ 0x1, 300, 0 }, +{ 0x1, 299, 0 }, +{ 0x1, 298, 0 }, +{ 0x2, 297, 0 }, +{ 0x1, 297, 0 }, +{ 0x2, 296, 0 }, +{ 0x1, 296, 0 }, +{ 0x1, 295, 0 }, +{ 0x8, 294, 0 }, +{ 0x4, 294, 0 }, +{ 0x2, 294, 0 }, +{ 0x1, 294, 0 }, +{ 0x8, 293, 0 }, +{ 0x4, 293, 0 }, +{ 0x1, 293, 0 }, +{ 0x1, 292, 0 }, +{ 0x2, 291, 0 }, +{ 0x1, 291, 0 }, +{ 0x1, 290, 0 }, +{ 0x1, 289, 0 }, +{ 0x1, 285, 1 }, +{ 0x1, 286, 1 }, +{ 0x1, 287, 0 }, +{ 0x1, 284, 0 }, +{ 0x1, 283, 0 }, +{ 0x1, 282, 0 }, +{ 0x1, 281, 0 }, +{ 0x1, 280, 0 }, +{ 0x1, 272, 0 }, +{ 0x1, 271, 0 }, +{ 0x1, 270, 0 }, +{ 0x1, 269, 0 }, +{ 0x1, 268, 0 }, +{ 0x1, 267, 0 }, +{ 0x1, 266, 0 }, +{ 0x1, 265, 0 }, +{ 0x1, 264, 0 }, +{ 0x1, 263, 0 }, +{ 0x1, 262, 0 }, +{ 0x1, 261, 0 }, +{ 0x1, 260, 0 }, +{ 0x1, 259, 0 }, +{ 0x1, 258, 0 }, +{ 0x1, 257, 0 }, +{ 0x1, 256, 0 }, +{ 0x1, 255, 0 }, +{ 0x1, 254, 0 }, +{ 0x1, 253, 0 }, +{ 0x1, 252, 0 }, +{ 0x1, 250, 0 }, +{ 0x1, 249, 1 }, +{ 0x1, 369, 0 }, +{ 0x1, 248, 1 }, +{ 0x1, 342, 0 }, +{ 0x1, 247, 0 }, +{ 0x1, 246, 0 }, +{ 0x1, 245, 1 }, +{ 0x2, 342, 0 }, +{ 0x1250, 244, 0 }, +{ 0x3250, 244, 0 }, +{ 0xa50, 244, 0 }, +{ 0x1a50, 244, 0 }, +{ 0x650, 244, 0 }, +{ 0xe50, 244, 0 }, +{ 0x950, 244, 0 }, +{ 0x1950, 244, 0 }, +{ 0x550, 244, 0 }, +{ 0xd50, 244, 0 }, +{ 0x350, 244, 0 }, +{ 0x750, 244, 0 }, +{ 0x2d0, 244, 0 }, +{ 0x6d0, 244, 0 }, +{ 0x1d0, 244, 0 }, +{ 0x3d0, 244, 0 }, +{ 0x930, 244, 0 }, +{ 0x1930, 244, 0 }, +{ 0x530, 244, 0 }, +{ 0xd30, 244, 0 }, +{ 0x330, 244, 0 }, +{ 0x730, 244, 0 }, +{ 0x4b0, 244, 0 }, +{ 0xcb0, 244, 0 }, +{ 0x2b0, 244, 0 }, +{ 0x6b0, 244, 0 }, +{ 0x1b0, 244, 0 }, +{ 0x3b0, 244, 0 }, +{ 0x170, 244, 0 }, +{ 0x370, 244, 0 }, +{ 0xf0, 244, 0 }, +{ 0x1f0, 244, 0 }, +{ 0x9288, 244, 0 }, +{ 0x19288, 244, 0 }, +{ 0x5288, 244, 0 }, +{ 0xd288, 244, 0 }, +{ 0x3288, 244, 0 }, +{ 0x7288, 244, 0 }, +{ 0x4a88, 244, 0 }, +{ 0xca88, 244, 0 }, +{ 0x2a88, 244, 0 }, +{ 0x6a88, 244, 0 }, +{ 0x1a88, 244, 0 }, +{ 0x3a88, 244, 0 }, +{ 0x1688, 244, 0 }, +{ 0x3688, 244, 0 }, +{ 0xe88, 244, 0 }, +{ 0x1e88, 244, 0 }, +{ 0x4988, 244, 0 }, +{ 0xc988, 244, 0 }, +{ 0x2988, 244, 0 }, +{ 0x6988, 244, 0 }, +{ 0x1988, 244, 0 }, +{ 0x3988, 244, 0 }, +{ 0x2588, 244, 0 }, +{ 0x6588, 244, 0 }, +{ 0x1588, 244, 0 }, +{ 0x3588, 244, 0 }, +{ 0xd88, 244, 0 }, +{ 0x1d88, 244, 0 }, +{ 0xb88, 244, 0 }, +{ 0x1b88, 244, 0 }, +{ 0x788, 244, 0 }, +{ 0xf88, 244, 0 }, +{ 0x1248, 244, 0 }, +{ 0x3248, 244, 0 }, +{ 0xa48, 244, 0 }, +{ 0x1a48, 244, 0 }, +{ 0x648, 244, 0 }, +{ 0xe48, 244, 0 }, +{ 0x948, 244, 0 }, +{ 0x1948, 244, 0 }, +{ 0x548, 244, 0 }, +{ 0xd48, 244, 0 }, +{ 0x348, 244, 0 }, +{ 0x748, 244, 0 }, +{ 0x2c8, 244, 0 }, +{ 0x6c8, 244, 0 }, +{ 0x1c8, 244, 0 }, +{ 0x3c8, 244, 0 }, +{ 0x928, 244, 0 }, +{ 0x1928, 244, 0 }, +{ 0x528, 244, 0 }, +{ 0xd28, 244, 0 }, +{ 0x328, 244, 0 }, +{ 0x728, 244, 0 }, +{ 0x4a8, 244, 0 }, +{ 0xca8, 244, 0 }, +{ 0x2a8, 244, 0 }, +{ 0x6a8, 244, 0 }, +{ 0x1a8, 244, 0 }, +{ 0x3a8, 244, 0 }, +{ 0x168, 244, 0 }, +{ 0x368, 244, 0 }, +{ 0xe8, 244, 0 }, +{ 0x1e8, 244, 0 }, +{ 0x1258, 244, 0 }, +{ 0x3258, 244, 0 }, +{ 0xa58, 244, 0 }, +{ 0x1a58, 244, 0 }, +{ 0x658, 244, 0 }, +{ 0xe58, 244, 0 }, +{ 0x958, 244, 0 }, +{ 0x1958, 244, 0 }, +{ 0x558, 244, 0 }, +{ 0xd58, 244, 0 }, +{ 0x358, 244, 0 }, +{ 0x758, 244, 0 }, +{ 0x2d8, 244, 0 }, +{ 0x6d8, 244, 0 }, +{ 0x1d8, 244, 0 }, +{ 0x3d8, 244, 0 }, +{ 0x938, 244, 0 }, +{ 0x1938, 244, 0 }, +{ 0x538, 244, 0 }, +{ 0xd38, 244, 0 }, +{ 0x338, 244, 0 }, +{ 0x738, 244, 0 }, +{ 0x4b8, 244, 0 }, +{ 0xcb8, 244, 0 }, +{ 0x2b8, 244, 0 }, +{ 0x6b8, 244, 0 }, +{ 0x1b8, 244, 0 }, +{ 0x3b8, 244, 0 }, +{ 0x178, 244, 0 }, +{ 0x378, 244, 0 }, +{ 0xf8, 244, 0 }, +{ 0x1f8, 244, 0 }, +{ 0x124, 244, 0 }, +{ 0x324, 244, 0 }, +{ 0xa4, 244, 0 }, +{ 0x1a4, 244, 0 }, +{ 0x64, 244, 0 }, +{ 0xe4, 244, 0 }, +{ 0x94, 244, 0 }, +{ 0x194, 244, 0 }, +{ 0x54, 244, 0 }, +{ 0xd4, 244, 0 }, +{ 0x34, 244, 0 }, +{ 0x74, 244, 0 }, +{ 0x2c, 244, 0 }, +{ 0x6c, 244, 0 }, +{ 0x1c, 244, 0 }, +{ 0x3c, 244, 0 }, +{ 0x92, 244, 0 }, +{ 0x192, 244, 0 }, +{ 0x52, 244, 0 }, +{ 0xd2, 244, 0 }, +{ 0x32, 244, 0 }, +{ 0x72, 244, 0 }, +{ 0x4a, 244, 0 }, +{ 0xca, 244, 0 }, +{ 0x2a, 244, 0 }, +{ 0x6a, 244, 0 }, +{ 0x1a, 244, 0 }, +{ 0x3a, 244, 0 }, +{ 0x16, 244, 0 }, +{ 0x36, 244, 0 }, +{ 0x1e, 244, 0 }, +{ 0x125, 244, 0 }, +{ 0x325, 244, 0 }, +{ 0xa5, 244, 0 }, +{ 0x1a5, 244, 0 }, +{ 0x65, 244, 0 }, +{ 0xe5, 244, 0 }, +{ 0x95, 244, 0 }, +{ 0x195, 244, 0 }, +{ 0x55, 244, 0 }, +{ 0xd5, 244, 0 }, +{ 0x35, 244, 0 }, +{ 0x75, 244, 0 }, +{ 0x2d, 244, 0 }, +{ 0x6d, 244, 0 }, +{ 0x1d, 244, 0 }, +{ 0x3d, 244, 0 }, +{ 0x93, 244, 0 }, +{ 0x193, 244, 0 }, +{ 0x53, 244, 0 }, +{ 0xd3, 244, 0 }, +{ 0x33, 244, 0 }, +{ 0x73, 244, 0 }, +{ 0x4b, 244, 0 }, +{ 0xcb, 244, 0 }, +{ 0x2b, 244, 0 }, +{ 0x6b, 244, 0 }, +{ 0x1b, 244, 0 }, +{ 0x3b, 244, 0 }, +{ 0x17, 244, 0 }, +{ 0x37, 244, 0 }, +{ 0xf, 244, 0 }, +{ 0x1f, 244, 0 }, +{ 0x1, 243, 1 }, +{ 0xe, 244, 0 }, +{ 0x1, 241, 0 }, +{ 0x1, 240, 0 }, +{ 0x1, 239, 0 }, +{ 0x2, 238, 0 }, +{ 0x1, 238, 0 }, +{ 0x2, 237, 0 }, +{ 0x1, 237, 0 }, +{ 0x2, 236, 0 }, +{ 0x1, 236, 0 }, +{ 0x2, 235, 0 }, +{ 0x1, 235, 0 }, +{ 0x1, 234, 1 }, +{ 0x1, 251, 0 }, +{ 0x20, 233, 0 }, +{ 0x10, 233, 0 }, +{ 0x8, 233, 0 }, +{ 0x4, 233, 0 }, +{ 0x44, 233, 0 }, +{ 0x24, 233, 0 }, +{ 0x14, 233, 0 }, +{ 0xc, 233, 0 }, +{ 0x4c, 233, 0 }, +{ 0x2c, 233, 0 }, +{ 0x1c, 233, 0 }, +{ 0x2, 233, 0 }, +{ 0x12, 233, 0 }, +{ 0xa, 233, 0 }, +{ 0x6, 233, 0 }, +{ 0x1, 233, 0 }, +{ 0x20, 232, 0 }, +{ 0x10, 232, 0 }, +{ 0x8, 232, 0 }, +{ 0x4, 232, 0 }, +{ 0x44, 232, 0 }, +{ 0x24, 232, 0 }, +{ 0x14, 232, 0 }, +{ 0xc, 232, 0 }, +{ 0x4c, 232, 0 }, +{ 0x2c, 232, 0 }, +{ 0x1c, 232, 0 }, +{ 0x2, 232, 0 }, +{ 0x12, 232, 0 }, +{ 0xa, 232, 0 }, +{ 0x6, 232, 0 }, +{ 0x1, 232, 0 }, +{ 0x20, 231, 0 }, +{ 0x10, 231, 0 }, +{ 0x8, 231, 0 }, +{ 0x4, 231, 0 }, +{ 0x44, 231, 0 }, +{ 0x24, 231, 0 }, +{ 0x14, 231, 0 }, +{ 0xc, 231, 0 }, +{ 0x4c, 231, 0 }, +{ 0x2c, 231, 0 }, +{ 0x1c, 231, 0 }, +{ 0x2, 231, 0 }, +{ 0x12, 231, 0 }, +{ 0xa, 231, 0 }, +{ 0x6, 231, 0 }, +{ 0x1, 231, 0 }, +{ 0x40, 230, 0 }, +{ 0x140, 230, 0 }, +{ 0xc0, 230, 0 }, +{ 0x20, 230, 0 }, +{ 0xa0, 230, 0 }, +{ 0x60, 230, 0 }, +{ 0x10, 230, 0 }, +{ 0x8, 230, 0 }, +{ 0x14, 230, 0 }, +{ 0x54, 230, 0 }, +{ 0x34, 230, 0 }, +{ 0xc, 230, 0 }, +{ 0x2c, 230, 0 }, +{ 0x1c, 230, 0 }, +{ 0x2, 230, 0 }, +{ 0xa, 230, 0 }, +{ 0x6, 230, 0 }, +{ 0x1, 230, 0 }, +{ 0x40, 229, 0 }, +{ 0x140, 229, 0 }, +{ 0xc0, 229, 0 }, +{ 0x20, 229, 0 }, +{ 0xa0, 229, 0 }, +{ 0x60, 229, 0 }, +{ 0x10, 229, 0 }, +{ 0x8, 229, 0 }, +{ 0x14, 229, 0 }, +{ 0x54, 229, 0 }, +{ 0x34, 229, 0 }, +{ 0xc, 229, 0 }, +{ 0x2c, 229, 0 }, +{ 0x1c, 229, 0 }, +{ 0x2, 229, 0 }, +{ 0xa, 229, 0 }, +{ 0x6, 229, 0 }, +{ 0x1, 229, 0 }, +{ 0x40, 228, 0 }, +{ 0x140, 228, 0 }, +{ 0xc0, 228, 0 }, +{ 0x20, 228, 0 }, +{ 0xa0, 228, 0 }, +{ 0x60, 228, 0 }, +{ 0x10, 228, 0 }, +{ 0x8, 228, 0 }, +{ 0x14, 228, 0 }, +{ 0x54, 228, 0 }, +{ 0x34, 228, 0 }, +{ 0xc, 228, 0 }, +{ 0x2c, 228, 0 }, +{ 0x1c, 228, 0 }, +{ 0x2, 228, 0 }, +{ 0xa, 228, 0 }, +{ 0x6, 228, 0 }, +{ 0x1, 228, 0 }, +{ 0x40, 227, 0 }, +{ 0x140, 227, 0 }, +{ 0xc0, 227, 0 }, +{ 0x20, 227, 0 }, +{ 0xa0, 227, 0 }, +{ 0x60, 227, 0 }, +{ 0x10, 227, 0 }, +{ 0x8, 227, 0 }, +{ 0x14, 227, 0 }, +{ 0x54, 227, 0 }, +{ 0x34, 227, 0 }, +{ 0xc, 227, 0 }, +{ 0x2c, 227, 0 }, +{ 0x1c, 227, 0 }, +{ 0x2, 227, 0 }, +{ 0xa, 227, 0 }, +{ 0x6, 227, 0 }, +{ 0x1, 227, 0 }, +{ 0x40, 226, 0 }, +{ 0x140, 226, 0 }, +{ 0xc0, 226, 0 }, +{ 0x20, 226, 0 }, +{ 0xa0, 226, 0 }, +{ 0x60, 226, 0 }, +{ 0x10, 226, 0 }, +{ 0x8, 226, 0 }, +{ 0x14, 226, 0 }, +{ 0x54, 226, 0 }, +{ 0x34, 226, 0 }, +{ 0xc, 226, 0 }, +{ 0x2c, 226, 0 }, +{ 0x1c, 226, 0 }, +{ 0x2, 226, 0 }, +{ 0xa, 226, 0 }, +{ 0x6, 226, 0 }, +{ 0x1, 226, 0 }, +{ 0x40, 225, 0 }, +{ 0x140, 225, 0 }, +{ 0xc0, 225, 0 }, +{ 0x20, 225, 0 }, +{ 0xa0, 225, 0 }, +{ 0x60, 225, 0 }, +{ 0x10, 225, 0 }, +{ 0x8, 225, 0 }, +{ 0x14, 225, 0 }, +{ 0x54, 225, 0 }, +{ 0x34, 225, 0 }, +{ 0xc, 225, 0 }, +{ 0x2c, 225, 0 }, +{ 0x1c, 225, 0 }, +{ 0x2, 225, 0 }, +{ 0xa, 225, 0 }, +{ 0x6, 225, 0 }, +{ 0x1, 225, 0 }, +{ 0x40, 224, 0 }, +{ 0x140, 224, 0 }, +{ 0xc0, 224, 0 }, +{ 0x20, 224, 0 }, +{ 0xa0, 224, 0 }, +{ 0x60, 224, 0 }, +{ 0x10, 224, 0 }, +{ 0x8, 224, 0 }, +{ 0x14, 224, 0 }, +{ 0x54, 224, 0 }, +{ 0x34, 224, 0 }, +{ 0xc, 224, 0 }, +{ 0x2c, 224, 0 }, +{ 0x1c, 224, 0 }, +{ 0x2, 224, 0 }, +{ 0xa, 224, 0 }, +{ 0x6, 224, 0 }, +{ 0x1, 224, 0 }, +{ 0x40, 223, 0 }, +{ 0x140, 223, 0 }, +{ 0xc0, 223, 0 }, +{ 0x20, 223, 0 }, +{ 0xa0, 223, 0 }, +{ 0x60, 223, 0 }, +{ 0x10, 223, 0 }, +{ 0x8, 223, 0 }, +{ 0x14, 223, 0 }, +{ 0x54, 223, 0 }, +{ 0x34, 223, 0 }, +{ 0xc, 223, 0 }, +{ 0x2c, 223, 0 }, +{ 0x1c, 223, 0 }, +{ 0x2, 223, 0 }, +{ 0xa, 223, 0 }, +{ 0x6, 223, 0 }, +{ 0x1, 223, 0 }, +{ 0x40, 222, 0 }, +{ 0x140, 222, 0 }, +{ 0xc0, 222, 0 }, +{ 0x20, 222, 0 }, +{ 0xa0, 222, 0 }, +{ 0x60, 222, 0 }, +{ 0x10, 222, 0 }, +{ 0x8, 222, 0 }, +{ 0x14, 222, 0 }, +{ 0x54, 222, 0 }, +{ 0x34, 222, 0 }, +{ 0xc, 222, 0 }, +{ 0x2c, 222, 0 }, +{ 0x1c, 222, 0 }, +{ 0x2, 222, 0 }, +{ 0xa, 222, 0 }, +{ 0x6, 222, 0 }, +{ 0x1, 222, 0 }, +{ 0x40, 221, 0 }, +{ 0x140, 221, 0 }, +{ 0xc0, 221, 0 }, +{ 0x20, 221, 0 }, +{ 0xa0, 221, 0 }, +{ 0x60, 221, 0 }, +{ 0x10, 221, 0 }, +{ 0x8, 221, 0 }, +{ 0x14, 221, 0 }, +{ 0x54, 221, 0 }, +{ 0x34, 221, 0 }, +{ 0xc, 221, 0 }, +{ 0x2c, 221, 0 }, +{ 0x1c, 221, 0 }, +{ 0x2, 221, 0 }, +{ 0xa, 221, 0 }, +{ 0x6, 221, 0 }, +{ 0x1, 221, 0 }, +{ 0x40, 220, 0 }, +{ 0x140, 220, 0 }, +{ 0xc0, 220, 0 }, +{ 0x20, 220, 0 }, +{ 0xa0, 220, 0 }, +{ 0x60, 220, 0 }, +{ 0x10, 220, 0 }, +{ 0x8, 220, 0 }, +{ 0x14, 220, 0 }, +{ 0x54, 220, 0 }, +{ 0x34, 220, 0 }, +{ 0xc, 220, 0 }, +{ 0x2c, 220, 0 }, +{ 0x1c, 220, 0 }, +{ 0x2, 220, 0 }, +{ 0xa, 220, 0 }, +{ 0x6, 220, 0 }, +{ 0x1, 220, 0 }, +{ 0x40, 219, 0 }, +{ 0x140, 219, 0 }, +{ 0xc0, 219, 0 }, +{ 0x20, 219, 0 }, +{ 0xa0, 219, 0 }, +{ 0x60, 219, 0 }, +{ 0x10, 219, 0 }, +{ 0x8, 219, 0 }, +{ 0x14, 219, 0 }, +{ 0x54, 219, 0 }, +{ 0x34, 219, 0 }, +{ 0xc, 219, 0 }, +{ 0x2c, 219, 0 }, +{ 0x1c, 219, 0 }, +{ 0x2, 219, 0 }, +{ 0xa, 219, 0 }, +{ 0x6, 219, 0 }, +{ 0x1, 219, 0 }, +{ 0x40, 218, 0 }, +{ 0x140, 218, 0 }, +{ 0xc0, 218, 0 }, +{ 0x20, 218, 0 }, +{ 0xa0, 218, 0 }, +{ 0x60, 218, 0 }, +{ 0x10, 218, 0 }, +{ 0x8, 218, 0 }, +{ 0x14, 218, 0 }, +{ 0x54, 218, 0 }, +{ 0x34, 218, 0 }, +{ 0xc, 218, 0 }, +{ 0x2c, 218, 0 }, +{ 0x1c, 218, 0 }, +{ 0x2, 218, 0 }, +{ 0xa, 218, 0 }, +{ 0x6, 218, 0 }, +{ 0x1, 218, 0 }, +{ 0x40, 217, 0 }, +{ 0x140, 217, 0 }, +{ 0xc0, 217, 0 }, +{ 0x20, 217, 0 }, +{ 0xa0, 217, 0 }, +{ 0x60, 217, 0 }, +{ 0x10, 217, 0 }, +{ 0x8, 217, 0 }, +{ 0x14, 217, 0 }, +{ 0x54, 217, 0 }, +{ 0x34, 217, 0 }, +{ 0xc, 217, 0 }, +{ 0x2c, 217, 0 }, +{ 0x1c, 217, 0 }, +{ 0x2, 217, 0 }, +{ 0xa, 217, 0 }, +{ 0x6, 217, 0 }, +{ 0x1, 217, 0 }, +{ 0x40, 216, 0 }, +{ 0x140, 216, 0 }, +{ 0xc0, 216, 0 }, +{ 0x20, 216, 0 }, +{ 0xa0, 216, 0 }, +{ 0x60, 216, 0 }, +{ 0x10, 216, 0 }, +{ 0x8, 216, 0 }, +{ 0x14, 216, 0 }, +{ 0x54, 216, 0 }, +{ 0x34, 216, 0 }, +{ 0xc, 216, 0 }, +{ 0x2c, 216, 0 }, +{ 0x1c, 216, 0 }, +{ 0x2, 216, 0 }, +{ 0xa, 216, 0 }, +{ 0x6, 216, 0 }, +{ 0x1, 216, 0 }, +{ 0x40, 215, 0 }, +{ 0x140, 215, 0 }, +{ 0xc0, 215, 0 }, +{ 0x20, 215, 0 }, +{ 0xa0, 215, 0 }, +{ 0x60, 215, 0 }, +{ 0x10, 215, 0 }, +{ 0x8, 215, 0 }, +{ 0x14, 215, 0 }, +{ 0x54, 215, 0 }, +{ 0x34, 215, 0 }, +{ 0xc, 215, 0 }, +{ 0x2c, 215, 0 }, +{ 0x1c, 215, 0 }, +{ 0x2, 215, 0 }, +{ 0xa, 215, 0 }, +{ 0x6, 215, 0 }, +{ 0x1, 215, 0 }, +{ 0x40, 214, 0 }, +{ 0x140, 214, 0 }, +{ 0xc0, 214, 0 }, +{ 0x20, 214, 0 }, +{ 0xa0, 214, 0 }, +{ 0x60, 214, 0 }, +{ 0x10, 214, 0 }, +{ 0x8, 214, 0 }, +{ 0x14, 214, 0 }, +{ 0x54, 214, 0 }, +{ 0x34, 214, 0 }, +{ 0xc, 214, 0 }, +{ 0x2c, 214, 0 }, +{ 0x1c, 214, 0 }, +{ 0x2, 214, 0 }, +{ 0xa, 214, 0 }, +{ 0x6, 214, 0 }, +{ 0x1, 214, 0 }, +{ 0x40, 213, 0 }, +{ 0x140, 213, 0 }, +{ 0xc0, 213, 0 }, +{ 0x20, 213, 0 }, +{ 0xa0, 213, 0 }, +{ 0x60, 213, 0 }, +{ 0x10, 213, 0 }, +{ 0x8, 213, 0 }, +{ 0x14, 213, 0 }, +{ 0x54, 213, 0 }, +{ 0x34, 213, 0 }, +{ 0xc, 213, 0 }, +{ 0x2c, 213, 0 }, +{ 0x1c, 213, 0 }, +{ 0x2, 213, 0 }, +{ 0xa, 213, 0 }, +{ 0x6, 213, 0 }, +{ 0x1, 213, 0 }, +{ 0x1, 212, 0 }, +{ 0x5, 212, 0 }, +{ 0x3, 212, 0 }, +{ 0x1, 211, 0 }, +{ 0x5, 211, 0 }, +{ 0x3, 211, 0 }, +{ 0x1, 210, 0 }, +{ 0x5, 210, 0 }, +{ 0x3, 210, 0 }, +{ 0x200, 209, 0 }, +{ 0xa00, 209, 0 }, +{ 0x600, 209, 0 }, +{ 0x100, 209, 0 }, +{ 0x500, 209, 0 }, +{ 0x300, 209, 0 }, +{ 0x80, 209, 0 }, +{ 0x40, 209, 0 }, +{ 0x20, 209, 0 }, +{ 0xa0, 209, 0 }, +{ 0x60, 209, 0 }, +{ 0x50, 209, 0 }, +{ 0x150, 209, 0 }, +{ 0xd0, 209, 0 }, +{ 0x30, 209, 0 }, +{ 0x130, 209, 0 }, +{ 0xb0, 209, 0 }, +{ 0x70, 209, 0 }, +{ 0x170, 209, 0 }, +{ 0xf0, 209, 0 }, +{ 0x8, 209, 0 }, +{ 0x28, 209, 0 }, +{ 0x18, 209, 0 }, +{ 0x4, 209, 0 }, +{ 0x14, 209, 0 }, +{ 0xc, 209, 0 }, +{ 0x2, 209, 0 }, +{ 0xa, 209, 0 }, +{ 0x6, 209, 0 }, +{ 0x1, 209, 0 }, +{ 0x200, 208, 0 }, +{ 0xa00, 208, 0 }, +{ 0x600, 208, 0 }, +{ 0x100, 208, 0 }, +{ 0x500, 208, 0 }, +{ 0x300, 208, 0 }, +{ 0x80, 208, 0 }, +{ 0x40, 208, 0 }, +{ 0x20, 208, 0 }, +{ 0xa0, 208, 0 }, +{ 0x60, 208, 0 }, +{ 0x50, 208, 0 }, +{ 0x150, 208, 0 }, +{ 0xd0, 208, 0 }, +{ 0x30, 208, 0 }, +{ 0x130, 208, 0 }, +{ 0xb0, 208, 0 }, +{ 0x70, 208, 0 }, +{ 0x170, 208, 0 }, +{ 0xf0, 208, 0 }, +{ 0x8, 208, 0 }, +{ 0x28, 208, 0 }, +{ 0x18, 208, 0 }, +{ 0x4, 208, 0 }, +{ 0x14, 208, 0 }, +{ 0xc, 208, 0 }, +{ 0x2, 208, 0 }, +{ 0xa, 208, 0 }, +{ 0x6, 208, 0 }, +{ 0x1, 208, 0 }, +{ 0x200, 207, 0 }, +{ 0xa00, 207, 0 }, +{ 0x600, 207, 0 }, +{ 0x100, 207, 0 }, +{ 0x500, 207, 0 }, +{ 0x300, 207, 0 }, +{ 0x80, 207, 0 }, +{ 0x40, 207, 0 }, +{ 0x20, 207, 0 }, +{ 0xa0, 207, 0 }, +{ 0x60, 207, 0 }, +{ 0x50, 207, 0 }, +{ 0x150, 207, 0 }, +{ 0xd0, 207, 0 }, +{ 0x30, 207, 0 }, +{ 0x130, 207, 0 }, +{ 0xb0, 207, 0 }, +{ 0x70, 207, 0 }, +{ 0x170, 207, 0 }, +{ 0xf0, 207, 0 }, +{ 0x8, 207, 0 }, +{ 0x28, 207, 0 }, +{ 0x18, 207, 0 }, +{ 0x4, 207, 0 }, +{ 0x14, 207, 0 }, +{ 0xc, 207, 0 }, +{ 0x2, 207, 0 }, +{ 0xa, 207, 0 }, +{ 0x6, 207, 0 }, +{ 0x1, 207, 0 }, +{ 0x100, 206, 0 }, +{ 0x500, 206, 0 }, +{ 0x300, 206, 0 }, +{ 0x80, 206, 0 }, +{ 0x280, 206, 0 }, +{ 0x180, 206, 0 }, +{ 0x40, 206, 0 }, +{ 0x20, 206, 0 }, +{ 0x50, 206, 0 }, +{ 0x150, 206, 0 }, +{ 0xd0, 206, 0 }, +{ 0x30, 206, 0 }, +{ 0x130, 206, 0 }, +{ 0xb0, 206, 0 }, +{ 0x70, 206, 0 }, +{ 0x170, 206, 0 }, +{ 0xf0, 206, 0 }, +{ 0x8, 206, 0 }, +{ 0x28, 206, 0 }, +{ 0x18, 206, 0 }, +{ 0x4, 206, 0 }, +{ 0x14, 206, 0 }, +{ 0xc, 206, 0 }, +{ 0x2, 206, 0 }, +{ 0xa, 206, 0 }, +{ 0x6, 206, 0 }, +{ 0x1, 206, 0 }, +{ 0x100, 205, 0 }, +{ 0x500, 205, 0 }, +{ 0x300, 205, 0 }, +{ 0x80, 205, 0 }, +{ 0x280, 205, 0 }, +{ 0x180, 205, 0 }, +{ 0x40, 205, 0 }, +{ 0x20, 205, 0 }, +{ 0x50, 205, 0 }, +{ 0x150, 205, 0 }, +{ 0xd0, 205, 0 }, +{ 0x30, 205, 0 }, +{ 0x130, 205, 0 }, +{ 0xb0, 205, 0 }, +{ 0x70, 205, 0 }, +{ 0x170, 205, 0 }, +{ 0xf0, 205, 0 }, +{ 0x8, 205, 0 }, +{ 0x28, 205, 0 }, +{ 0x18, 205, 0 }, +{ 0x4, 205, 0 }, +{ 0x14, 205, 0 }, +{ 0xc, 205, 0 }, +{ 0x2, 205, 0 }, +{ 0xa, 205, 0 }, +{ 0x6, 205, 0 }, +{ 0x1, 205, 0 }, +{ 0x100, 204, 0 }, +{ 0x500, 204, 0 }, +{ 0x300, 204, 0 }, +{ 0x80, 204, 0 }, +{ 0x280, 204, 0 }, +{ 0x180, 204, 0 }, +{ 0x40, 204, 0 }, +{ 0x20, 204, 0 }, +{ 0x50, 204, 0 }, +{ 0x150, 204, 0 }, +{ 0xd0, 204, 0 }, +{ 0x30, 204, 0 }, +{ 0x130, 204, 0 }, +{ 0xb0, 204, 0 }, +{ 0x70, 204, 0 }, +{ 0x170, 204, 0 }, +{ 0xf0, 204, 0 }, +{ 0x8, 204, 0 }, +{ 0x28, 204, 0 }, +{ 0x18, 204, 0 }, +{ 0x4, 204, 0 }, +{ 0x14, 204, 0 }, +{ 0xc, 204, 0 }, +{ 0x2, 204, 0 }, +{ 0xa, 204, 0 }, +{ 0x6, 204, 0 }, +{ 0x1, 204, 0 }, +{ 0x100, 203, 0 }, +{ 0x500, 203, 0 }, +{ 0x300, 203, 0 }, +{ 0x80, 203, 0 }, +{ 0x280, 203, 0 }, +{ 0x180, 203, 0 }, +{ 0x40, 203, 0 }, +{ 0x20, 203, 0 }, +{ 0x50, 203, 0 }, +{ 0x150, 203, 0 }, +{ 0xd0, 203, 0 }, +{ 0x30, 203, 0 }, +{ 0x130, 203, 0 }, +{ 0xb0, 203, 0 }, +{ 0x70, 203, 0 }, +{ 0x170, 203, 0 }, +{ 0xf0, 203, 0 }, +{ 0x8, 203, 0 }, +{ 0x28, 203, 0 }, +{ 0x18, 203, 0 }, +{ 0x4, 203, 0 }, +{ 0x14, 203, 0 }, +{ 0xc, 203, 0 }, +{ 0x2, 203, 0 }, +{ 0xa, 203, 0 }, +{ 0x6, 203, 0 }, +{ 0x1, 203, 0 }, +{ 0x100, 202, 0 }, +{ 0x500, 202, 0 }, +{ 0x300, 202, 0 }, +{ 0x80, 202, 0 }, +{ 0x280, 202, 0 }, +{ 0x180, 202, 0 }, +{ 0x40, 202, 0 }, +{ 0x20, 202, 0 }, +{ 0x50, 202, 0 }, +{ 0x150, 202, 0 }, +{ 0xd0, 202, 0 }, +{ 0x30, 202, 0 }, +{ 0x130, 202, 0 }, +{ 0xb0, 202, 0 }, +{ 0x70, 202, 0 }, +{ 0x170, 202, 0 }, +{ 0xf0, 202, 0 }, +{ 0x8, 202, 0 }, +{ 0x28, 202, 0 }, +{ 0x18, 202, 0 }, +{ 0x4, 202, 0 }, +{ 0x14, 202, 0 }, +{ 0xc, 202, 0 }, +{ 0x2, 202, 0 }, +{ 0xa, 202, 0 }, +{ 0x6, 202, 0 }, +{ 0x1, 202, 0 }, +{ 0x100, 201, 0 }, +{ 0x500, 201, 0 }, +{ 0x300, 201, 0 }, +{ 0x80, 201, 0 }, +{ 0x280, 201, 0 }, +{ 0x180, 201, 0 }, +{ 0x40, 201, 0 }, +{ 0x20, 201, 0 }, +{ 0x50, 201, 0 }, +{ 0x150, 201, 0 }, +{ 0xd0, 201, 0 }, +{ 0x30, 201, 0 }, +{ 0x130, 201, 0 }, +{ 0xb0, 201, 0 }, +{ 0x70, 201, 0 }, +{ 0x170, 201, 0 }, +{ 0xf0, 201, 0 }, +{ 0x8, 201, 0 }, +{ 0x28, 201, 0 }, +{ 0x18, 201, 0 }, +{ 0x4, 201, 0 }, +{ 0x14, 201, 0 }, +{ 0xc, 201, 0 }, +{ 0x2, 201, 0 }, +{ 0xa, 201, 0 }, +{ 0x6, 201, 0 }, +{ 0x1, 201, 0 }, +{ 0x100, 200, 0 }, +{ 0x500, 200, 0 }, +{ 0x300, 200, 0 }, +{ 0x80, 200, 0 }, +{ 0x280, 200, 0 }, +{ 0x180, 200, 0 }, +{ 0x40, 200, 0 }, +{ 0x20, 200, 0 }, +{ 0x50, 200, 0 }, +{ 0x150, 200, 0 }, +{ 0xd0, 200, 0 }, +{ 0x30, 200, 0 }, +{ 0x130, 200, 0 }, +{ 0xb0, 200, 0 }, +{ 0x70, 200, 0 }, +{ 0x170, 200, 0 }, +{ 0xf0, 200, 0 }, +{ 0x8, 200, 0 }, +{ 0x28, 200, 0 }, +{ 0x18, 200, 0 }, +{ 0x4, 200, 0 }, +{ 0x14, 200, 0 }, +{ 0xc, 200, 0 }, +{ 0x2, 200, 0 }, +{ 0xa, 200, 0 }, +{ 0x6, 200, 0 }, +{ 0x1, 200, 0 }, +{ 0x100, 199, 0 }, +{ 0x500, 199, 0 }, +{ 0x300, 199, 0 }, +{ 0x80, 199, 0 }, +{ 0x280, 199, 0 }, +{ 0x180, 199, 0 }, +{ 0x40, 199, 0 }, +{ 0x20, 199, 0 }, +{ 0x50, 199, 0 }, +{ 0x150, 199, 0 }, +{ 0xd0, 199, 0 }, +{ 0x30, 199, 0 }, +{ 0x130, 199, 0 }, +{ 0xb0, 199, 0 }, +{ 0x70, 199, 0 }, +{ 0x170, 199, 0 }, +{ 0xf0, 199, 0 }, +{ 0x8, 199, 0 }, +{ 0x28, 199, 0 }, +{ 0x18, 199, 0 }, +{ 0x4, 199, 0 }, +{ 0x14, 199, 0 }, +{ 0xc, 199, 0 }, +{ 0x2, 199, 0 }, +{ 0xa, 199, 0 }, +{ 0x6, 199, 0 }, +{ 0x1, 199, 0 }, +{ 0x100, 198, 0 }, +{ 0x500, 198, 0 }, +{ 0x300, 198, 0 }, +{ 0x80, 198, 0 }, +{ 0x280, 198, 0 }, +{ 0x180, 198, 0 }, +{ 0x40, 198, 0 }, +{ 0x20, 198, 0 }, +{ 0x50, 198, 0 }, +{ 0x150, 198, 0 }, +{ 0xd0, 198, 0 }, +{ 0x30, 198, 0 }, +{ 0x130, 198, 0 }, +{ 0xb0, 198, 0 }, +{ 0x70, 198, 0 }, +{ 0x170, 198, 0 }, +{ 0xf0, 198, 0 }, +{ 0x8, 198, 0 }, +{ 0x28, 198, 0 }, +{ 0x18, 198, 0 }, +{ 0x4, 198, 0 }, +{ 0x14, 198, 0 }, +{ 0xc, 198, 0 }, +{ 0x2, 198, 0 }, +{ 0xa, 198, 0 }, +{ 0x6, 198, 0 }, +{ 0x1, 198, 0 }, +{ 0x1, 197, 0 }, +{ 0x1, 196, 0 }, +{ 0x2, 195, 0 }, +{ 0x1, 195, 0 }, +{ 0x1, 194, 0 }, +{ 0x1, 193, 1 }, +{ 0x1, 392, 0 }, +{ 0x1, 192, 1 }, +{ 0x1, 390, 0 }, +{ 0x8, 191, 0 }, +{ 0x4, 191, 0 }, +{ 0x2, 191, 0 }, +{ 0x1, 191, 0 }, +{ 0x1, 190, 0 }, +{ 0x1, 189, 0 }, +{ 0x2, 188, 0 }, +{ 0x1, 188, 0 }, +{ 0x4, 187, 0 }, +{ 0x2, 187, 0 }, +{ 0x1, 187, 0 }, +{ 0x40, 186, 0 }, +{ 0x20, 186, 0 }, +{ 0x10, 186, 0 }, +{ 0x44, 186, 0 }, +{ 0x24, 186, 0 }, +{ 0x14, 186, 0 }, +{ 0xc, 186, 1 }, +{ 0x4, 186, 0 }, +{ 0x22, 186, 0 }, +{ 0x12, 186, 0 }, +{ 0xa, 186, 0 }, +{ 0x6, 186, 1 }, +{ 0x2, 186, 0 }, +{ 0x1, 186, 1 }, +{ 0x8, 186, 0 }, +{ 0x8, 184, 0 }, +{ 0x4, 184, 0 }, +{ 0x2, 184, 0 }, +{ 0x1, 184, 1 }, +{ 0x1, 185, 0 }, +{ 0x1, 183, 0 }, +{ 0x8, 181, 0 }, +{ 0x4, 181, 0 }, +{ 0x2, 181, 0 }, +{ 0x1, 181, 1 }, +{ 0x1, 182, 0 }, +{ 0x8, 179, 0 }, +{ 0x4, 179, 0 }, +{ 0x2, 179, 0 }, +{ 0x1, 179, 1 }, +{ 0x1, 180, 0 }, +{ 0x8, 177, 0 }, +{ 0x4, 177, 0 }, +{ 0x2, 177, 0 }, +{ 0x1, 177, 1 }, +{ 0x1, 178, 0 }, +{ 0x8, 175, 0 }, +{ 0x4, 175, 0 }, +{ 0x2, 175, 0 }, +{ 0x1, 175, 1 }, +{ 0x1, 176, 0 }, +{ 0x10, 174, 0 }, +{ 0x8, 174, 0 }, +{ 0x4, 174, 0 }, +{ 0x1, 174, 1 }, +{ 0x2, 174, 0 }, +{ 0x8, 172, 0 }, +{ 0x4, 172, 0 }, +{ 0x2, 172, 0 }, +{ 0x1, 172, 1 }, +{ 0x1, 173, 0 }, +{ 0x1, 171, 0 }, +{ 0x8, 168, 0 }, +{ 0x4, 168, 0 }, +{ 0x2, 168, 0 }, +{ 0x1, 168, 1 }, +{ 0x1, 169, 0 }, +{ 0x10, 167, 0 }, +{ 0x8, 167, 0 }, +{ 0x4, 167, 0 }, +{ 0x1, 167, 1 }, +{ 0x2, 167, 0 }, +{ 0x8, 165, 0 }, +{ 0x4, 165, 0 }, +{ 0x2, 165, 0 }, +{ 0x1, 165, 1 }, +{ 0x1, 166, 1 }, +{ 0x1, 273, 0 }, +{ 0x4, 164, 0 }, +{ 0x2, 164, 0 }, +{ 0x1, 164, 1 }, +{ 0x1, 170, 0 }, +{ 0x8, 162, 0 }, +{ 0x4, 162, 0 }, +{ 0x2, 162, 0 }, +{ 0x1, 162, 1 }, +{ 0x1, 163, 1 }, +{ 0x1, 274, 0 }, +{ 0x8, 160, 0 }, +{ 0x4, 160, 0 }, +{ 0x2, 160, 0 }, +{ 0x1, 160, 1 }, +{ 0x1, 161, 0 }, +{ 0x442, 158, 0 }, +{ 0x242, 158, 0 }, +{ 0x142, 158, 0 }, +{ 0xc2, 158, 1 }, +{ 0x6, 159, 1 }, +{ 0x1, 377, 0 }, +{ 0x22, 158, 0 }, +{ 0x12, 158, 0 }, +{ 0xa, 158, 0 }, +{ 0x6, 158, 1 }, +{ 0x2, 159, 1 }, +{ 0x2, 311, 0 }, +{ 0x221, 158, 0 }, +{ 0x121, 158, 0 }, +{ 0xa1, 158, 0 }, +{ 0x61, 158, 1 }, +{ 0x3, 159, 1 }, +{ 0x1, 373, 0 }, +{ 0x11, 158, 0 }, +{ 0x9, 158, 0 }, +{ 0x5, 158, 0 }, +{ 0x3, 158, 1 }, +{ 0x1, 159, 1 }, +{ 0x1, 311, 0 }, +{ 0x880, 156, 0 }, +{ 0x480, 156, 0 }, +{ 0x280, 156, 0 }, +{ 0x180, 156, 1 }, +{ 0x80, 157, 1 }, +{ 0xc, 312, 0 }, +{ 0x440, 156, 0 }, +{ 0x240, 156, 0 }, +{ 0x140, 156, 0 }, +{ 0xc0, 156, 1 }, +{ 0x40, 157, 0 }, +{ 0x220, 156, 0 }, +{ 0x120, 156, 0 }, +{ 0xa0, 156, 0 }, +{ 0x60, 156, 1 }, +{ 0x20, 157, 0 }, +{ 0x110, 156, 0 }, +{ 0x90, 156, 0 }, +{ 0x50, 156, 0 }, +{ 0x30, 156, 1 }, +{ 0x10, 157, 0 }, +{ 0x88, 156, 0 }, +{ 0x48, 156, 0 }, +{ 0x28, 156, 0 }, +{ 0x18, 156, 1 }, +{ 0x8, 157, 1 }, +{ 0x1, 329, 0 }, +{ 0x44, 156, 0 }, +{ 0x24, 156, 0 }, +{ 0x14, 156, 0 }, +{ 0xc, 156, 1 }, +{ 0x4, 157, 1 }, +{ 0x6, 312, 0 }, +{ 0x22, 156, 0 }, +{ 0x12, 156, 0 }, +{ 0xa, 156, 0 }, +{ 0x6, 156, 1 }, +{ 0x2, 157, 1 }, +{ 0x3, 312, 0 }, +{ 0x11, 156, 0 }, +{ 0x9, 156, 0 }, +{ 0x5, 156, 0 }, +{ 0x8, 154, 0 }, +{ 0x4, 154, 0 }, +{ 0x2, 154, 0 }, +{ 0x1, 154, 1 }, +{ 0x1, 155, 1 }, +{ 0x1, 275, 0 }, +{ 0x8, 152, 0 }, +{ 0x4, 152, 0 }, +{ 0x2, 152, 0 }, +{ 0x1, 152, 1 }, +{ 0x1, 153, 1 }, +{ 0x1, 276, 0 }, +{ 0x1, 151, 0 }, +{ 0x1, 150, 0 }, +{ 0x1, 149, 0 }, +{ 0x40, 147, 0 }, +{ 0x20, 147, 0 }, +{ 0x10, 147, 0 }, +{ 0x44, 147, 0 }, +{ 0x24, 147, 0 }, +{ 0x14, 147, 0 }, +{ 0xc, 147, 1 }, +{ 0x4, 147, 0 }, +{ 0x22, 147, 0 }, +{ 0x12, 147, 0 }, +{ 0xa, 147, 0 }, +{ 0x6, 147, 1 }, +{ 0x2, 147, 0 }, +{ 0x1, 147, 1 }, +{ 0x8, 147, 0 }, +{ 0x20, 145, 0 }, +{ 0x10, 145, 0 }, +{ 0x8, 145, 0 }, +{ 0x4, 145, 1 }, +{ 0x1, 146, 0 }, +{ 0x22, 145, 0 }, +{ 0x12, 145, 0 }, +{ 0xa, 145, 0 }, +{ 0x6, 145, 1 }, +{ 0x4, 146, 0 }, +{ 0x11, 145, 0 }, +{ 0x9, 145, 0 }, +{ 0x5, 145, 0 }, +{ 0x3, 145, 1 }, +{ 0x2, 146, 0 }, +{ 0x1, 144, 0 }, +{ 0x20, 141, 0 }, +{ 0x10, 141, 0 }, +{ 0x8, 141, 0 }, +{ 0x4, 141, 1 }, +{ 0x1, 142, 0 }, +{ 0x22, 141, 0 }, +{ 0x12, 141, 0 }, +{ 0xa, 141, 0 }, +{ 0x6, 141, 1 }, +{ 0x4, 142, 0 }, +{ 0x11, 141, 0 }, +{ 0x9, 141, 0 }, +{ 0x5, 141, 0 }, +{ 0x3, 141, 1 }, +{ 0x2, 142, 0 }, +{ 0x40, 140, 0 }, +{ 0x20, 140, 0 }, +{ 0x10, 140, 0 }, +{ 0x44, 140, 0 }, +{ 0x24, 140, 0 }, +{ 0x14, 140, 0 }, +{ 0xc, 140, 1 }, +{ 0x4, 140, 0 }, +{ 0x22, 140, 0 }, +{ 0x12, 140, 0 }, +{ 0xa, 140, 0 }, +{ 0x6, 140, 1 }, +{ 0x2, 140, 0 }, +{ 0x1, 140, 1 }, +{ 0x8, 140, 0 }, +{ 0x4, 139, 0 }, +{ 0x2, 139, 0 }, +{ 0x1, 139, 0 }, +{ 0x8, 137, 0 }, +{ 0x4, 137, 0 }, +{ 0x2, 137, 0 }, +{ 0x1, 137, 1 }, +{ 0x1, 138, 1 }, +{ 0x1, 366, 0 }, +{ 0x4, 136, 0 }, +{ 0x2, 136, 1 }, +{ 0x1, 242, 0 }, +{ 0x1, 136, 1 }, +{ 0x1, 143, 0 }, +{ 0x8, 134, 0 }, +{ 0x4, 134, 0 }, +{ 0x2, 134, 0 }, +{ 0x1, 134, 1 }, +{ 0x1, 135, 1 }, +{ 0x1, 367, 0 }, +{ 0x20, 132, 0 }, +{ 0x10, 132, 0 }, +{ 0x8, 132, 0 }, +{ 0x4, 132, 1 }, +{ 0x1, 133, 0 }, +{ 0x2, 132, 1 }, +{ 0xc, 133, 0 }, +{ 0x12, 132, 0 }, +{ 0xa, 132, 0 }, +{ 0x6, 132, 0 }, +{ 0x11, 132, 0 }, +{ 0x9, 132, 0 }, +{ 0x5, 132, 0 }, +{ 0x3, 132, 1 }, +{ 0x2, 133, 0 }, +{ 0x1, 131, 0 }, +{ 0x2, 130, 0 }, +{ 0xa, 130, 0 }, +{ 0x6, 130, 0 }, +{ 0x1, 130, 0 }, +{ 0x5, 130, 0 }, +{ 0x3, 130, 0 }, +{ 0x2, 129, 0 }, +{ 0xa, 129, 0 }, +{ 0x6, 129, 0 }, +{ 0x1, 129, 0 }, +{ 0x5, 129, 0 }, +{ 0x3, 129, 0 }, +{ 0x41, 128, 1 }, +{ 0x40, 148, 0 }, +{ 0x21, 128, 1 }, +{ 0x20, 148, 0 }, +{ 0x11, 128, 1 }, +{ 0x10, 148, 0 }, +{ 0x9, 128, 1 }, +{ 0x1, 128, 1 }, +{ 0x1, 148, 1 }, +{ 0x8, 148, 0 }, +{ 0x45, 128, 1 }, +{ 0x44, 148, 0 }, +{ 0x25, 128, 1 }, +{ 0x24, 148, 0 }, +{ 0x15, 128, 1 }, +{ 0x14, 148, 0 }, +{ 0xd, 128, 1 }, +{ 0x5, 128, 1 }, +{ 0xc, 148, 1 }, +{ 0x4, 148, 0 }, +{ 0x23, 128, 1 }, +{ 0x22, 148, 0 }, +{ 0x13, 128, 1 }, +{ 0x12, 148, 0 }, +{ 0xb, 128, 1 }, +{ 0xa, 148, 0 }, +{ 0x7, 128, 1 }, +{ 0x3, 128, 1 }, +{ 0x6, 148, 1 }, +{ 0x2, 148, 0 }, +{ 0x1, 127, 0 }, +{ 0x442, 125, 0 }, +{ 0x242, 125, 0 }, +{ 0x142, 125, 0 }, +{ 0xc2, 125, 1 }, +{ 0x6, 126, 0 }, +{ 0x22, 125, 0 }, +{ 0x12, 125, 0 }, +{ 0xa, 125, 0 }, +{ 0x221, 125, 0 }, +{ 0x121, 125, 0 }, +{ 0xa1, 125, 0 }, +{ 0x61, 125, 1 }, +{ 0x3, 126, 0 }, +{ 0x11, 125, 0 }, +{ 0x9, 125, 0 }, +{ 0x5, 125, 0 }, +{ 0x1108, 117, 1 }, +{ 0x1108, 121, 0 }, +{ 0x908, 117, 1 }, +{ 0x908, 121, 0 }, +{ 0x508, 117, 1 }, +{ 0x508, 121, 0 }, +{ 0x308, 117, 1 }, +{ 0x18, 118, 1 }, +{ 0x308, 121, 1 }, +{ 0x18, 122, 0 }, +{ 0x88, 117, 1 }, +{ 0x88, 121, 0 }, +{ 0x48, 117, 1 }, +{ 0x48, 121, 0 }, +{ 0x28, 117, 1 }, +{ 0x28, 121, 0 }, +{ 0x18, 117, 1 }, +{ 0x8, 118, 1 }, +{ 0x18, 121, 1 }, +{ 0x8, 122, 0 }, +{ 0x884, 117, 1 }, +{ 0x442, 119, 1 }, +{ 0x884, 121, 1 }, +{ 0x442, 123, 0 }, +{ 0x484, 117, 1 }, +{ 0x242, 119, 1 }, +{ 0x484, 121, 1 }, +{ 0x242, 123, 0 }, +{ 0x284, 117, 1 }, +{ 0x142, 119, 1 }, +{ 0x284, 121, 1 }, +{ 0x142, 123, 0 }, +{ 0x184, 117, 1 }, +{ 0xc, 118, 1 }, +{ 0xc2, 119, 1 }, +{ 0x6, 120, 1 }, +{ 0x184, 121, 1 }, +{ 0xc, 122, 1 }, +{ 0xc2, 123, 1 }, +{ 0x6, 124, 0 }, +{ 0x44, 117, 1 }, +{ 0x22, 119, 1 }, +{ 0x44, 121, 1 }, +{ 0x22, 123, 0 }, +{ 0x24, 117, 1 }, +{ 0x12, 119, 1 }, +{ 0x24, 121, 1 }, +{ 0x12, 123, 0 }, +{ 0x14, 117, 1 }, +{ 0xa, 119, 1 }, +{ 0x14, 121, 1 }, +{ 0xa, 123, 0 }, +{ 0xc, 117, 1 }, +{ 0x4, 118, 1 }, +{ 0x6, 119, 1 }, +{ 0x2, 120, 1 }, +{ 0xc, 121, 1 }, +{ 0x4, 122, 1 }, +{ 0x6, 123, 1 }, +{ 0x2, 124, 0 }, +{ 0x442, 117, 1 }, +{ 0x221, 119, 1 }, +{ 0x442, 121, 1 }, +{ 0x221, 123, 0 }, +{ 0x242, 117, 1 }, +{ 0x121, 119, 1 }, +{ 0x242, 121, 1 }, +{ 0x121, 123, 0 }, +{ 0x142, 117, 1 }, +{ 0xa1, 119, 1 }, +{ 0x142, 121, 1 }, +{ 0xa1, 123, 0 }, +{ 0xc2, 117, 1 }, +{ 0x6, 118, 1 }, +{ 0x61, 119, 1 }, +{ 0x3, 120, 1 }, +{ 0xc2, 121, 1 }, +{ 0x6, 122, 1 }, +{ 0x61, 123, 1 }, +{ 0x3, 124, 0 }, +{ 0x22, 117, 1 }, +{ 0x11, 119, 1 }, +{ 0x22, 121, 1 }, +{ 0x11, 123, 0 }, +{ 0x12, 117, 1 }, +{ 0x9, 119, 1 }, +{ 0x12, 121, 1 }, +{ 0x9, 123, 0 }, +{ 0xa, 117, 1 }, +{ 0x5, 119, 1 }, +{ 0xa, 121, 1 }, +{ 0x5, 123, 0 }, +{ 0x6, 117, 1 }, +{ 0x2, 118, 1 }, +{ 0x3, 119, 1 }, +{ 0x1, 120, 1 }, +{ 0x6, 121, 1 }, +{ 0x2, 122, 1 }, +{ 0x3, 123, 1 }, +{ 0x1, 124, 0 }, +{ 0x221, 117, 1 }, +{ 0x221, 121, 0 }, +{ 0x121, 117, 1 }, +{ 0x121, 121, 0 }, +{ 0xa1, 117, 1 }, +{ 0xa1, 121, 0 }, +{ 0x61, 117, 1 }, +{ 0x3, 118, 1 }, +{ 0x61, 121, 1 }, +{ 0x3, 122, 0 }, +{ 0x11, 117, 1 }, +{ 0x11, 121, 0 }, +{ 0x9, 117, 1 }, +{ 0x9, 121, 0 }, +{ 0x5, 117, 1 }, +{ 0x5, 121, 0 }, +{ 0x3, 117, 1 }, +{ 0x1, 118, 1 }, +{ 0x3, 121, 1 }, +{ 0x1, 122, 0 }, +{ 0x8, 115, 0 }, +{ 0x4, 115, 0 }, +{ 0x2, 115, 0 }, +{ 0x1, 115, 1 }, +{ 0x1, 116, 0 }, +{ 0x1, 113, 1 }, +{ 0x1, 114, 0 }, +{ 0x3, 113, 1 }, +{ 0x3, 114, 0 }, +{ 0x8, 111, 0 }, +{ 0x4, 111, 0 }, +{ 0x2, 111, 0 }, +{ 0x1, 111, 1 }, +{ 0x1, 112, 0 }, +{ 0x1, 110, 1 }, +{ 0x3, 156, 1 }, +{ 0x1, 157, 0 }, +{ 0x1, 109, 0 }, +{ 0x1, 108, 0 }, +{ 0x8, 106, 0 }, +{ 0x4, 106, 0 }, +{ 0x2, 106, 0 }, +{ 0x1, 106, 1 }, +{ 0x1, 107, 1 }, +{ 0x1, 368, 0 }, +{ 0x8, 104, 0 }, +{ 0x4, 104, 0 }, +{ 0x2, 104, 0 }, +{ 0x1, 104, 1 }, +{ 0x1, 105, 0 }, +{ 0x40, 103, 0 }, +{ 0x20, 103, 0 }, +{ 0x10, 103, 1 }, +{ 0x2, 293, 0 }, +{ 0x44, 103, 0 }, +{ 0x24, 103, 0 }, +{ 0x14, 103, 0 }, +{ 0xc, 103, 1 }, +{ 0x4, 103, 0 }, +{ 0x22, 103, 0 }, +{ 0x12, 103, 0 }, +{ 0xa, 103, 0 }, +{ 0x6, 103, 1 }, +{ 0x2, 103, 0 }, +{ 0x1, 103, 1 }, +{ 0x8, 103, 0 }, +{ 0x1, 102, 0 }, +{ 0x2, 101, 1 }, +{ 0x2, 339, 0 }, +{ 0x1, 101, 1 }, +{ 0x1, 339, 0 }, +{ 0x1, 100, 0 }, +{ 0x1, 99, 0 }, +{ 0x1, 98, 0 }, +{ 0x1, 97, 1 }, +{ 0x1, 335, 0 }, +{ 0x1, 96, 0 }, +{ 0x2, 95, 0 }, +{ 0x1, 95, 1 }, +{ 0x6, 125, 1 }, +{ 0x2, 126, 0 }, +{ 0x2, 94, 0 }, +{ 0x1, 94, 1 }, +{ 0x3, 125, 1 }, +{ 0x1, 126, 0 }, +{ 0x1, 93, 0 }, +{ 0x2, 92, 0 }, +{ 0xa, 92, 0 }, +{ 0x6, 92, 0 }, +{ 0x1, 92, 0 }, +{ 0x5, 92, 0 }, +{ 0x3, 92, 0 }, +{ 0x2, 91, 0 }, +{ 0xa, 91, 0 }, +{ 0x6, 91, 0 }, +{ 0x1, 91, 0 }, +{ 0x5, 91, 0 }, +{ 0x3, 91, 0 }, +{ 0x2, 90, 0 }, +{ 0xa, 90, 0 }, +{ 0x6, 90, 0 }, +{ 0x1, 90, 0 }, +{ 0x5, 90, 0 }, +{ 0x3, 90, 0 }, +{ 0x2, 89, 0 }, +{ 0xa, 89, 0 }, +{ 0x6, 89, 0 }, +{ 0x1, 89, 0 }, +{ 0x5, 89, 0 }, +{ 0x3, 89, 0 }, +{ 0x34, 77, 1 }, +{ 0x7, 88, 0 }, +{ 0xc, 77, 1 }, +{ 0x3, 81, 0 }, +{ 0x2, 77, 1 }, +{ 0x1, 78, 1 }, +{ 0x1, 79, 1 }, +{ 0x1, 80, 0 }, +{ 0x6, 77, 1 }, +{ 0x3, 78, 1 }, +{ 0x3, 79, 1 }, +{ 0x3, 80, 0 }, +{ 0x1, 77, 1 }, +{ 0x2, 80, 0 }, +{ 0x9, 77, 1 }, +{ 0x6, 80, 0 }, +{ 0xd, 77, 1 }, +{ 0xe, 88, 0 }, +{ 0x3, 77, 1 }, +{ 0x6, 81, 0 }, +{ 0x28, 75, 1 }, +{ 0x5, 76, 0 }, +{ 0x68, 75, 1 }, +{ 0x7, 87, 0 }, +{ 0x18, 75, 1 }, +{ 0x3, 76, 0 }, +{ 0x14, 75, 1 }, +{ 0xa, 76, 0 }, +{ 0x34, 75, 1 }, +{ 0xe, 87, 0 }, +{ 0xc, 75, 1 }, +{ 0x6, 76, 0 }, +{ 0xa, 75, 1 }, +{ 0x14, 76, 0 }, +{ 0x1a, 75, 1 }, +{ 0x1c, 87, 0 }, +{ 0x6, 75, 1 }, +{ 0xc, 76, 0 }, +{ 0x5, 75, 1 }, +{ 0x28, 76, 0 }, +{ 0xd, 75, 1 }, +{ 0x38, 87, 0 }, +{ 0x3, 75, 1 }, +{ 0x18, 76, 0 }, +{ 0x28, 70, 1 }, +{ 0x5, 74, 0 }, +{ 0x68, 70, 1 }, +{ 0x7, 86, 0 }, +{ 0x18, 70, 1 }, +{ 0x3, 74, 0 }, +{ 0x4, 70, 1 }, +{ 0x2, 71, 1 }, +{ 0x2, 72, 1 }, +{ 0x2, 73, 0 }, +{ 0xc, 70, 1 }, +{ 0x6, 71, 1 }, +{ 0x6, 72, 1 }, +{ 0x6, 73, 0 }, +{ 0x2, 70, 1 }, +{ 0x1, 71, 1 }, +{ 0x1, 72, 1 }, +{ 0x1, 73, 0 }, +{ 0x6, 70, 1 }, +{ 0x3, 71, 1 }, +{ 0x3, 72, 1 }, +{ 0x3, 73, 0 }, +{ 0x1, 70, 1 }, +{ 0x4, 73, 0 }, +{ 0x9, 70, 1 }, +{ 0xc, 73, 0 }, +{ 0x5, 70, 1 }, +{ 0xa, 74, 0 }, +{ 0xd, 70, 1 }, +{ 0xe, 86, 0 }, +{ 0x3, 70, 1 }, +{ 0x6, 74, 0 }, +{ 0x68, 60, 1 }, +{ 0x7, 69, 0 }, +{ 0x18, 60, 1 }, +{ 0x3, 64, 0 }, +{ 0x2, 60, 1 }, +{ 0x1, 61, 1 }, +{ 0x1, 62, 1 }, +{ 0x1, 63, 0 }, +{ 0x6, 60, 1 }, +{ 0x3, 61, 1 }, +{ 0x3, 62, 1 }, +{ 0x3, 63, 0 }, +{ 0x1, 60, 1 }, +{ 0x4, 63, 0 }, +{ 0x9, 60, 1 }, +{ 0xc, 63, 0 }, +{ 0xd, 60, 1 }, +{ 0xe, 69, 0 }, +{ 0x3, 60, 1 }, +{ 0x6, 64, 0 }, +{ 0x28, 58, 1 }, +{ 0x5, 59, 0 }, +{ 0x68, 58, 1 }, +{ 0x7, 68, 0 }, +{ 0x18, 58, 1 }, +{ 0x3, 59, 0 }, +{ 0x14, 58, 1 }, +{ 0xa, 59, 0 }, +{ 0x34, 58, 1 }, +{ 0xe, 68, 0 }, +{ 0xc, 58, 1 }, +{ 0x6, 59, 0 }, +{ 0xa, 58, 1 }, +{ 0x14, 59, 0 }, +{ 0x1a, 58, 1 }, +{ 0x1c, 68, 0 }, +{ 0x6, 58, 1 }, +{ 0xc, 59, 0 }, +{ 0x5, 58, 1 }, +{ 0x28, 59, 0 }, +{ 0xd, 58, 1 }, +{ 0x38, 68, 0 }, +{ 0x3, 58, 1 }, +{ 0x18, 59, 0 }, +{ 0x28, 53, 1 }, +{ 0x5, 57, 0 }, +{ 0x68, 53, 1 }, +{ 0x7, 67, 0 }, +{ 0x18, 53, 1 }, +{ 0x3, 57, 0 }, +{ 0x4, 53, 1 }, +{ 0x2, 54, 1 }, +{ 0x2, 55, 1 }, +{ 0x2, 56, 0 }, +{ 0xc, 53, 1 }, +{ 0x6, 54, 1 }, +{ 0x6, 55, 1 }, +{ 0x6, 56, 0 }, +{ 0x2, 53, 1 }, +{ 0x1, 54, 1 }, +{ 0x1, 55, 1 }, +{ 0x1, 56, 0 }, +{ 0x6, 53, 1 }, +{ 0x3, 54, 1 }, +{ 0x3, 55, 1 }, +{ 0x3, 56, 0 }, +{ 0x1, 53, 1 }, +{ 0x4, 56, 0 }, +{ 0x9, 53, 1 }, +{ 0xc, 56, 0 }, +{ 0x5, 53, 1 }, +{ 0xa, 57, 0 }, +{ 0xd, 53, 1 }, +{ 0xe, 67, 0 }, +{ 0x3, 53, 1 }, +{ 0x6, 57, 0 }, +{ 0x2, 52, 0 }, +{ 0x1, 52, 0 }, +{ 0x1, 50, 0 }, +{ 0x3, 49, 0 }, +{ 0x5, 48, 0 }, +{ 0x3, 48, 0 }, +{ 0x5, 47, 0 }, +{ 0x3, 47, 0 }, +{ 0x3, 46, 0 }, +{ 0x2, 45, 0 }, +{ 0x1, 45, 0 }, +{ 0x8, 43, 1 }, +{ 0x38, 44, 1 }, +{ 0xe8, 44, 0 }, +{ 0x1248, 43, 0 }, +{ 0x3248, 43, 0 }, +{ 0xa48, 43, 0 }, +{ 0x1a48, 43, 0 }, +{ 0x648, 43, 0 }, +{ 0xe48, 43, 0 }, +{ 0x948, 43, 0 }, +{ 0x1948, 43, 0 }, +{ 0x548, 43, 0 }, +{ 0xd48, 43, 0 }, +{ 0x348, 43, 0 }, +{ 0x748, 43, 0 }, +{ 0x2c8, 43, 0 }, +{ 0x6c8, 43, 0 }, +{ 0x1c8, 43, 0 }, +{ 0x3c8, 43, 0 }, +{ 0x28, 43, 1 }, +{ 0x78, 44, 1 }, +{ 0x1e8, 44, 0 }, +{ 0x498, 43, 1 }, +{ 0x488, 44, 0 }, +{ 0xc98, 43, 1 }, +{ 0xc88, 44, 0 }, +{ 0x298, 43, 1 }, +{ 0x288, 44, 0 }, +{ 0x698, 43, 1 }, +{ 0x688, 44, 0 }, +{ 0x198, 43, 1 }, +{ 0x188, 44, 0 }, +{ 0x398, 43, 1 }, +{ 0x388, 44, 0 }, +{ 0x258, 43, 1 }, +{ 0x248, 44, 0 }, +{ 0x658, 43, 1 }, +{ 0x648, 44, 0 }, +{ 0x158, 43, 1 }, +{ 0x148, 44, 0 }, +{ 0x358, 43, 1 }, +{ 0x348, 44, 0 }, +{ 0xd8, 43, 1 }, +{ 0xc8, 44, 0 }, +{ 0x1d8, 43, 1 }, +{ 0x1c8, 44, 0 }, +{ 0x78, 43, 1 }, +{ 0x58, 44, 0 }, +{ 0xf8, 43, 1 }, +{ 0xd8, 44, 0 }, +{ 0x4, 43, 1 }, +{ 0x1c, 44, 1 }, +{ 0x74, 44, 0 }, +{ 0x924, 43, 0 }, +{ 0x1924, 43, 0 }, +{ 0x524, 43, 0 }, +{ 0xd24, 43, 0 }, +{ 0x324, 43, 0 }, +{ 0x724, 43, 0 }, +{ 0x4a4, 43, 0 }, +{ 0xca4, 43, 0 }, +{ 0x2a4, 43, 0 }, +{ 0x6a4, 43, 0 }, +{ 0x1a4, 43, 0 }, +{ 0x3a4, 43, 0 }, +{ 0x164, 43, 0 }, +{ 0x364, 43, 0 }, +{ 0xe4, 43, 0 }, +{ 0x1e4, 43, 0 }, +{ 0x14, 43, 1 }, +{ 0x3c, 44, 1 }, +{ 0xf4, 44, 0 }, +{ 0x24c, 43, 1 }, +{ 0x244, 44, 0 }, +{ 0x64c, 43, 1 }, +{ 0x644, 44, 0 }, +{ 0x14c, 43, 1 }, +{ 0x144, 44, 0 }, +{ 0x34c, 43, 1 }, +{ 0x344, 44, 0 }, +{ 0xcc, 43, 1 }, +{ 0xc4, 44, 0 }, +{ 0x1cc, 43, 1 }, +{ 0x1c4, 44, 0 }, +{ 0x12c, 43, 1 }, +{ 0x124, 44, 0 }, +{ 0x32c, 43, 1 }, +{ 0x324, 44, 0 }, +{ 0xac, 43, 1 }, +{ 0xa4, 44, 0 }, +{ 0x1ac, 43, 1 }, +{ 0x1a4, 44, 0 }, +{ 0x6c, 43, 1 }, +{ 0x64, 44, 0 }, +{ 0xec, 43, 1 }, +{ 0xe4, 44, 0 }, +{ 0x3c, 43, 1 }, +{ 0x2c, 44, 0 }, +{ 0x7c, 43, 1 }, +{ 0x6c, 44, 0 }, +{ 0x2, 43, 1 }, +{ 0xe, 44, 1 }, +{ 0x3a, 44, 0 }, +{ 0x492, 43, 0 }, +{ 0xc92, 43, 0 }, +{ 0x292, 43, 0 }, +{ 0x692, 43, 0 }, +{ 0x192, 43, 0 }, +{ 0x392, 43, 0 }, +{ 0x252, 43, 0 }, +{ 0x652, 43, 0 }, +{ 0x152, 43, 0 }, +{ 0x352, 43, 0 }, +{ 0xd2, 43, 0 }, +{ 0x1d2, 43, 0 }, +{ 0xb2, 43, 0 }, +{ 0x1b2, 43, 0 }, +{ 0x72, 43, 0 }, +{ 0xf2, 43, 0 }, +{ 0xa, 43, 1 }, +{ 0x1e, 44, 1 }, +{ 0x7a, 44, 0 }, +{ 0x126, 43, 1 }, +{ 0x122, 44, 0 }, +{ 0x326, 43, 1 }, +{ 0x322, 44, 0 }, +{ 0xa6, 43, 1 }, +{ 0xa2, 44, 0 }, +{ 0x1a6, 43, 1 }, +{ 0x1a2, 44, 0 }, +{ 0x66, 43, 1 }, +{ 0x62, 44, 0 }, +{ 0xe6, 43, 1 }, +{ 0xe2, 44, 0 }, +{ 0x96, 43, 1 }, +{ 0x92, 44, 0 }, +{ 0x196, 43, 1 }, +{ 0x192, 44, 0 }, +{ 0x56, 43, 1 }, +{ 0x52, 44, 0 }, +{ 0xd6, 43, 1 }, +{ 0xd2, 44, 0 }, +{ 0x36, 43, 1 }, +{ 0x32, 44, 0 }, +{ 0x76, 43, 1 }, +{ 0x72, 44, 0 }, +{ 0x1e, 43, 1 }, +{ 0x16, 44, 0 }, +{ 0x3e, 43, 1 }, +{ 0x36, 44, 0 }, +{ 0x1, 43, 1 }, +{ 0x7, 44, 1 }, +{ 0x1d, 44, 0 }, +{ 0x249, 43, 0 }, +{ 0x649, 43, 0 }, +{ 0x149, 43, 0 }, +{ 0x349, 43, 0 }, +{ 0xc9, 43, 0 }, +{ 0x1c9, 43, 0 }, +{ 0x129, 43, 0 }, +{ 0x329, 43, 0 }, +{ 0xa9, 43, 0 }, +{ 0x1a9, 43, 0 }, +{ 0x69, 43, 0 }, +{ 0xe9, 43, 0 }, +{ 0x59, 43, 0 }, +{ 0xd9, 43, 0 }, +{ 0x39, 43, 0 }, +{ 0x79, 43, 0 }, +{ 0x5, 43, 1 }, +{ 0xf, 44, 1 }, +{ 0x3d, 44, 0 }, +{ 0x93, 43, 1 }, +{ 0x91, 44, 0 }, +{ 0x193, 43, 1 }, +{ 0x191, 44, 0 }, +{ 0x53, 43, 1 }, +{ 0x51, 44, 0 }, +{ 0xd3, 43, 1 }, +{ 0xd1, 44, 0 }, +{ 0x33, 43, 1 }, +{ 0x31, 44, 0 }, +{ 0x73, 43, 1 }, +{ 0x71, 44, 0 }, +{ 0x4b, 43, 1 }, +{ 0x49, 44, 0 }, +{ 0xcb, 43, 1 }, +{ 0xc9, 44, 0 }, +{ 0x2b, 43, 1 }, +{ 0x29, 44, 0 }, +{ 0x6b, 43, 1 }, +{ 0x69, 44, 0 }, +{ 0x1b, 43, 1 }, +{ 0x19, 44, 0 }, +{ 0x3b, 43, 1 }, +{ 0x39, 44, 0 }, +{ 0xf, 43, 1 }, +{ 0xb, 44, 0 }, +{ 0x1f, 43, 1 }, +{ 0x1b, 44, 0 }, +{ 0x4, 41, 1 }, +{ 0x1c, 42, 1 }, +{ 0x74, 42, 0 }, +{ 0x924, 41, 0 }, +{ 0x1924, 41, 0 }, +{ 0x524, 41, 0 }, +{ 0xd24, 41, 0 }, +{ 0x324, 41, 0 }, +{ 0x724, 41, 0 }, +{ 0x4a4, 41, 0 }, +{ 0xca4, 41, 0 }, +{ 0x2a4, 41, 0 }, +{ 0x6a4, 41, 0 }, +{ 0x1a4, 41, 0 }, +{ 0x3a4, 41, 0 }, +{ 0x164, 41, 0 }, +{ 0x364, 41, 0 }, +{ 0xe4, 41, 0 }, +{ 0x1e4, 41, 0 }, +{ 0x14, 41, 1 }, +{ 0x3c, 42, 1 }, +{ 0xf4, 42, 0 }, +{ 0x24c, 41, 1 }, +{ 0x244, 42, 0 }, +{ 0x64c, 41, 1 }, +{ 0x644, 42, 0 }, +{ 0x14c, 41, 1 }, +{ 0x144, 42, 0 }, +{ 0x34c, 41, 1 }, +{ 0x344, 42, 0 }, +{ 0xcc, 41, 1 }, +{ 0xc4, 42, 0 }, +{ 0x1cc, 41, 1 }, +{ 0x1c4, 42, 0 }, +{ 0x12c, 41, 1 }, +{ 0x124, 42, 0 }, +{ 0x32c, 41, 1 }, +{ 0x324, 42, 0 }, +{ 0xac, 41, 1 }, +{ 0xa4, 42, 0 }, +{ 0x1ac, 41, 1 }, +{ 0x1a4, 42, 0 }, +{ 0x6c, 41, 1 }, +{ 0x64, 42, 0 }, +{ 0xec, 41, 1 }, +{ 0xe4, 42, 0 }, +{ 0x3c, 41, 1 }, +{ 0x2c, 42, 0 }, +{ 0x7c, 41, 1 }, +{ 0x6c, 42, 0 }, +{ 0xa, 41, 1 }, +{ 0x3a, 42, 1 }, +{ 0xea, 42, 0 }, +{ 0x124a, 41, 0 }, +{ 0x324a, 41, 0 }, +{ 0xa4a, 41, 0 }, +{ 0x1a4a, 41, 0 }, +{ 0x64a, 41, 0 }, +{ 0xe4a, 41, 0 }, +{ 0x94a, 41, 0 }, +{ 0x194a, 41, 0 }, +{ 0x54a, 41, 0 }, +{ 0xd4a, 41, 0 }, +{ 0x34a, 41, 0 }, +{ 0x74a, 41, 0 }, +{ 0x2ca, 41, 0 }, +{ 0x6ca, 41, 0 }, +{ 0x1ca, 41, 0 }, +{ 0x3ca, 41, 0 }, +{ 0x2a, 41, 1 }, +{ 0x7a, 42, 1 }, +{ 0x1ea, 42, 0 }, +{ 0x49a, 41, 1 }, +{ 0x48a, 42, 0 }, +{ 0xc9a, 41, 1 }, +{ 0xc8a, 42, 0 }, +{ 0x29a, 41, 1 }, +{ 0x28a, 42, 0 }, +{ 0x69a, 41, 1 }, +{ 0x68a, 42, 0 }, +{ 0x19a, 41, 1 }, +{ 0x18a, 42, 0 }, +{ 0x39a, 41, 1 }, +{ 0x38a, 42, 0 }, +{ 0x25a, 41, 1 }, +{ 0x24a, 42, 0 }, +{ 0x65a, 41, 1 }, +{ 0x64a, 42, 0 }, +{ 0x15a, 41, 1 }, +{ 0x14a, 42, 0 }, +{ 0x35a, 41, 1 }, +{ 0x34a, 42, 0 }, +{ 0xda, 41, 1 }, +{ 0xca, 42, 0 }, +{ 0x1da, 41, 1 }, +{ 0x1ca, 42, 0 }, +{ 0x7a, 41, 1 }, +{ 0x5a, 42, 0 }, +{ 0xfa, 41, 1 }, +{ 0xda, 42, 0 }, +{ 0x6, 41, 1 }, +{ 0x1e, 42, 1 }, +{ 0x76, 42, 0 }, +{ 0x926, 41, 0 }, +{ 0x1926, 41, 0 }, +{ 0x526, 41, 0 }, +{ 0xd26, 41, 0 }, +{ 0x326, 41, 0 }, +{ 0x726, 41, 0 }, +{ 0x4a6, 41, 0 }, +{ 0xca6, 41, 0 }, +{ 0x2a6, 41, 0 }, +{ 0x6a6, 41, 0 }, +{ 0x1a6, 41, 0 }, +{ 0x3a6, 41, 0 }, +{ 0x166, 41, 0 }, +{ 0x366, 41, 0 }, +{ 0xe6, 41, 0 }, +{ 0x1e6, 41, 0 }, +{ 0x16, 41, 1 }, +{ 0x3e, 42, 1 }, +{ 0xf6, 42, 0 }, +{ 0x24e, 41, 1 }, +{ 0x246, 42, 0 }, +{ 0x64e, 41, 1 }, +{ 0x646, 42, 0 }, +{ 0x14e, 41, 1 }, +{ 0x146, 42, 0 }, +{ 0x34e, 41, 1 }, +{ 0x346, 42, 0 }, +{ 0xce, 41, 1 }, +{ 0xc6, 42, 0 }, +{ 0x1ce, 41, 1 }, +{ 0x1c6, 42, 0 }, +{ 0x12e, 41, 1 }, +{ 0x126, 42, 0 }, +{ 0x32e, 41, 1 }, +{ 0x326, 42, 0 }, +{ 0xae, 41, 1 }, +{ 0xa6, 42, 0 }, +{ 0x1ae, 41, 1 }, +{ 0x1a6, 42, 0 }, +{ 0x6e, 41, 1 }, +{ 0x66, 42, 0 }, +{ 0xee, 41, 1 }, +{ 0xe6, 42, 0 }, +{ 0x3e, 41, 1 }, +{ 0x2e, 42, 0 }, +{ 0x7e, 41, 1 }, +{ 0x6e, 42, 0 }, +{ 0x1, 41, 1 }, +{ 0x7, 42, 1 }, +{ 0x1d, 42, 0 }, +{ 0x249, 41, 0 }, +{ 0x649, 41, 0 }, +{ 0x149, 41, 0 }, +{ 0x349, 41, 0 }, +{ 0xc9, 41, 0 }, +{ 0x1c9, 41, 0 }, +{ 0x129, 41, 0 }, +{ 0x329, 41, 0 }, +{ 0xa9, 41, 0 }, +{ 0x1a9, 41, 0 }, +{ 0x69, 41, 0 }, +{ 0xe9, 41, 0 }, +{ 0x59, 41, 0 }, +{ 0xd9, 41, 0 }, +{ 0x39, 41, 0 }, +{ 0x79, 41, 0 }, +{ 0x5, 41, 1 }, +{ 0xf, 42, 1 }, +{ 0x3d, 42, 0 }, +{ 0x93, 41, 1 }, +{ 0x91, 42, 0 }, +{ 0x193, 41, 1 }, +{ 0x191, 42, 0 }, +{ 0x53, 41, 1 }, +{ 0x51, 42, 0 }, +{ 0xd3, 41, 1 }, +{ 0xd1, 42, 0 }, +{ 0x33, 41, 1 }, +{ 0x31, 42, 0 }, +{ 0x73, 41, 1 }, +{ 0x71, 42, 0 }, +{ 0x4b, 41, 1 }, +{ 0x49, 42, 0 }, +{ 0xcb, 41, 1 }, +{ 0xc9, 42, 0 }, +{ 0x2b, 41, 1 }, +{ 0x29, 42, 0 }, +{ 0x6b, 41, 1 }, +{ 0x69, 42, 0 }, +{ 0x1b, 41, 1 }, +{ 0x19, 42, 0 }, +{ 0x3b, 41, 1 }, +{ 0x39, 42, 0 }, +{ 0xf, 41, 1 }, +{ 0xb, 42, 0 }, +{ 0x1f, 41, 1 }, +{ 0x1b, 42, 0 }, +{ 0x51, 39, 0 }, +{ 0xd1, 39, 1 }, +{ 0xc, 60, 1 }, +{ 0x6, 63, 1 }, +{ 0x3, 65, 1 }, +{ 0x3, 66, 0 }, +{ 0x31, 39, 1 }, +{ 0x11, 40, 0 }, +{ 0x71, 39, 1 }, +{ 0x31, 40, 1 }, +{ 0x4, 60, 1 }, +{ 0x2, 63, 1 }, +{ 0x1, 65, 1 }, +{ 0x1, 66, 0 }, +{ 0x29, 39, 0 }, +{ 0x69, 39, 1 }, +{ 0x28, 60, 1 }, +{ 0x5, 64, 0 }, +{ 0x19, 39, 1 }, +{ 0x9, 40, 0 }, +{ 0x39, 39, 1 }, +{ 0x19, 40, 1 }, +{ 0x5, 60, 1 }, +{ 0xa, 64, 0 }, +{ 0x15, 39, 0 }, +{ 0x35, 39, 1 }, +{ 0x3, 82, 1 }, +{ 0x3, 83, 1 }, +{ 0x3, 84, 1 }, +{ 0x3, 85, 0 }, +{ 0xd, 39, 1 }, +{ 0x5, 40, 0 }, +{ 0x1d, 39, 1 }, +{ 0xd, 40, 1 }, +{ 0x1, 82, 1 }, +{ 0x1, 83, 1 }, +{ 0x1, 84, 1 }, +{ 0x1, 85, 0 }, +{ 0xb, 39, 0 }, +{ 0x1b, 39, 1 }, +{ 0x14, 77, 1 }, +{ 0x5, 81, 0 }, +{ 0x7, 39, 1 }, +{ 0x3, 40, 0 }, +{ 0xf, 39, 1 }, +{ 0x7, 40, 1 }, +{ 0x5, 77, 1 }, +{ 0xa, 81, 0 }, +{ 0x51, 37, 1 }, +{ 0x50, 37, 0 }, +{ 0xd1, 37, 1 }, +{ 0xd0, 37, 0 }, +{ 0x31, 37, 1 }, +{ 0x30, 37, 1 }, +{ 0x11, 38, 1 }, +{ 0x10, 38, 0 }, +{ 0x71, 37, 1 }, +{ 0x70, 37, 1 }, +{ 0x31, 38, 1 }, +{ 0x30, 38, 0 }, +{ 0x29, 37, 1 }, +{ 0x28, 37, 0 }, +{ 0x69, 37, 1 }, +{ 0x68, 37, 0 }, +{ 0x19, 37, 1 }, +{ 0x18, 37, 1 }, +{ 0x9, 38, 1 }, +{ 0x8, 38, 0 }, +{ 0x39, 37, 1 }, +{ 0x38, 37, 1 }, +{ 0x19, 38, 1 }, +{ 0x18, 38, 0 }, +{ 0x15, 37, 1 }, +{ 0x14, 37, 0 }, +{ 0x35, 37, 1 }, +{ 0x34, 37, 0 }, +{ 0xd, 37, 1 }, +{ 0xc, 37, 1 }, +{ 0x5, 38, 1 }, +{ 0x4, 38, 0 }, +{ 0x1d, 37, 1 }, +{ 0x1c, 37, 1 }, +{ 0xd, 38, 1 }, +{ 0xc, 38, 0 }, +{ 0xb, 37, 1 }, +{ 0xa, 37, 0 }, +{ 0x1b, 37, 1 }, +{ 0x1a, 37, 0 }, +{ 0x7, 37, 1 }, +{ 0x6, 37, 1 }, +{ 0x3, 38, 1 }, +{ 0x2, 38, 0 }, +{ 0xf, 37, 1 }, +{ 0xe, 37, 1 }, +{ 0x7, 38, 1 }, +{ 0x6, 38, 0 }, +{ 0x8, 36, 0 }, +{ 0x18, 36, 0 }, +{ 0x2, 36, 1 }, +{ 0xc, 36, 0 }, +{ 0x1, 36, 1 }, +{ 0x4, 36, 0 }, +{ 0x1, 32, 1 }, +{ 0x1, 33, 1 }, +{ 0x1, 34, 0 }, +{ 0x1, 31, 0 }, +{ 0x1, 30, 0 }, +{ 0x51, 28, 0 }, +{ 0xd1, 28, 0 }, +{ 0x31, 28, 1 }, +{ 0x11, 29, 0 }, +{ 0x71, 28, 1 }, +{ 0x31, 29, 0 }, +{ 0x29, 28, 0 }, +{ 0x69, 28, 0 }, +{ 0x19, 28, 1 }, +{ 0x9, 29, 0 }, +{ 0x39, 28, 1 }, +{ 0x19, 29, 0 }, +{ 0x15, 28, 0 }, +{ 0x35, 28, 0 }, +{ 0xd, 28, 1 }, +{ 0x5, 29, 0 }, +{ 0x1d, 28, 1 }, +{ 0xd, 29, 0 }, +{ 0xb, 28, 0 }, +{ 0x1b, 28, 0 }, +{ 0x7, 28, 1 }, +{ 0x3, 29, 0 }, +{ 0xf, 28, 1 }, +{ 0x7, 29, 0 }, +{ 0xa2, 26, 0 }, +{ 0x1a2, 26, 0 }, +{ 0x62, 26, 1 }, +{ 0x22, 27, 0 }, +{ 0xe2, 26, 1 }, +{ 0x62, 27, 0 }, +{ 0x52, 26, 0 }, +{ 0xd2, 26, 0 }, +{ 0x32, 26, 1 }, +{ 0x12, 27, 0 }, +{ 0x72, 26, 1 }, +{ 0x32, 27, 0 }, +{ 0x2a, 26, 0 }, +{ 0x6a, 26, 0 }, +{ 0x1a, 26, 1 }, +{ 0xa, 27, 0 }, +{ 0x3a, 26, 1 }, +{ 0x1a, 27, 0 }, +{ 0x16, 26, 0 }, +{ 0x36, 26, 0 }, +{ 0xe, 26, 1 }, +{ 0x6, 27, 0 }, +{ 0x1e, 26, 1 }, +{ 0xe, 27, 0 }, +{ 0x51, 26, 0 }, +{ 0xd1, 26, 0 }, +{ 0x31, 26, 1 }, +{ 0x11, 27, 0 }, +{ 0x71, 26, 1 }, +{ 0x31, 27, 0 }, +{ 0x29, 26, 0 }, +{ 0x69, 26, 0 }, +{ 0x19, 26, 1 }, +{ 0x9, 27, 0 }, +{ 0x39, 26, 1 }, +{ 0x19, 27, 0 }, +{ 0x15, 26, 0 }, +{ 0x35, 26, 0 }, +{ 0xd, 26, 1 }, +{ 0x5, 27, 0 }, +{ 0x1d, 26, 1 }, +{ 0xd, 27, 0 }, +{ 0xb, 26, 0 }, +{ 0x1b, 26, 0 }, +{ 0x7, 26, 1 }, +{ 0x3, 27, 0 }, +{ 0xf, 26, 1 }, +{ 0x7, 27, 0 }, +{ 0x51, 24, 0 }, +{ 0xd1, 24, 0 }, +{ 0x31, 24, 1 }, +{ 0x11, 25, 0 }, +{ 0x71, 24, 1 }, +{ 0x31, 25, 0 }, +{ 0x29, 24, 0 }, +{ 0x69, 24, 0 }, +{ 0x19, 24, 1 }, +{ 0x9, 25, 0 }, +{ 0x39, 24, 1 }, +{ 0x19, 25, 0 }, +{ 0x15, 24, 0 }, +{ 0x35, 24, 0 }, +{ 0xd, 24, 1 }, +{ 0x5, 25, 0 }, +{ 0x1d, 24, 1 }, +{ 0xd, 25, 0 }, +{ 0xb, 24, 0 }, +{ 0x1b, 24, 0 }, +{ 0x7, 24, 1 }, +{ 0x3, 25, 0 }, +{ 0xf, 24, 1 }, +{ 0x7, 25, 0 }, +{ 0xa2, 22, 0 }, +{ 0x1a2, 22, 0 }, +{ 0x62, 22, 1 }, +{ 0x22, 23, 0 }, +{ 0xe2, 22, 1 }, +{ 0x62, 23, 0 }, +{ 0x52, 22, 0 }, +{ 0xd2, 22, 0 }, +{ 0x32, 22, 1 }, +{ 0x12, 23, 0 }, +{ 0x72, 22, 1 }, +{ 0x32, 23, 0 }, +{ 0x2a, 22, 0 }, +{ 0x6a, 22, 0 }, +{ 0x1a, 22, 1 }, +{ 0xa, 23, 0 }, +{ 0x3a, 22, 1 }, +{ 0x1a, 23, 0 }, +{ 0x16, 22, 0 }, +{ 0x36, 22, 0 }, +{ 0xe, 22, 1 }, +{ 0x6, 23, 0 }, +{ 0x1e, 22, 1 }, +{ 0xe, 23, 0 }, +{ 0x51, 22, 0 }, +{ 0xd1, 22, 0 }, +{ 0x31, 22, 1 }, +{ 0x11, 23, 0 }, +{ 0x71, 22, 1 }, +{ 0x31, 23, 0 }, +{ 0x29, 22, 0 }, +{ 0x69, 22, 0 }, +{ 0x19, 22, 1 }, +{ 0x9, 23, 0 }, +{ 0x39, 22, 1 }, +{ 0x19, 23, 0 }, +{ 0x15, 22, 0 }, +{ 0x35, 22, 0 }, +{ 0xd, 22, 1 }, +{ 0x5, 23, 0 }, +{ 0x1d, 22, 1 }, +{ 0xd, 23, 0 }, +{ 0xb, 22, 0 }, +{ 0x1b, 22, 0 }, +{ 0x7, 22, 1 }, +{ 0x3, 23, 0 }, +{ 0xf, 22, 1 }, +{ 0x7, 23, 0 }, +{ 0x51, 20, 1 }, +{ 0x50, 20, 0 }, +{ 0xd1, 20, 1 }, +{ 0xd0, 20, 0 }, +{ 0x31, 20, 1 }, +{ 0x30, 20, 1 }, +{ 0x11, 21, 1 }, +{ 0x10, 21, 0 }, +{ 0x71, 20, 1 }, +{ 0x70, 20, 1 }, +{ 0x31, 21, 1 }, +{ 0x30, 21, 0 }, +{ 0x29, 20, 1 }, +{ 0x28, 20, 0 }, +{ 0x69, 20, 1 }, +{ 0x68, 20, 0 }, +{ 0x19, 20, 1 }, +{ 0x18, 20, 1 }, +{ 0x9, 21, 1 }, +{ 0x8, 21, 0 }, +{ 0x39, 20, 1 }, +{ 0x38, 20, 1 }, +{ 0x19, 21, 1 }, +{ 0x18, 21, 0 }, +{ 0x15, 20, 1 }, +{ 0x14, 20, 0 }, +{ 0x35, 20, 1 }, +{ 0x34, 20, 0 }, +{ 0xd, 20, 1 }, +{ 0xc, 20, 1 }, +{ 0x5, 21, 1 }, +{ 0x4, 21, 0 }, +{ 0x1d, 20, 1 }, +{ 0x1c, 20, 1 }, +{ 0xd, 21, 1 }, +{ 0xc, 21, 0 }, +{ 0xb, 20, 1 }, +{ 0xa, 20, 0 }, +{ 0x1b, 20, 1 }, +{ 0x1a, 20, 0 }, +{ 0x7, 20, 1 }, +{ 0x6, 20, 1 }, +{ 0x3, 21, 1 }, +{ 0x2, 21, 0 }, +{ 0xf, 20, 1 }, +{ 0xe, 20, 1 }, +{ 0x7, 21, 1 }, +{ 0x6, 21, 0 }, +{ 0x8, 19, 0 }, +{ 0x18, 19, 0 }, +{ 0x2, 19, 1 }, +{ 0xc, 19, 0 }, +{ 0x1, 19, 1 }, +{ 0x4, 19, 0 }, +{ 0x51, 17, 0 }, +{ 0xd1, 17, 0 }, +{ 0x31, 17, 1 }, +{ 0x11, 18, 0 }, +{ 0x71, 17, 1 }, +{ 0x31, 18, 0 }, +{ 0x29, 17, 0 }, +{ 0x69, 17, 0 }, +{ 0x19, 17, 1 }, +{ 0x9, 18, 0 }, +{ 0x39, 17, 1 }, +{ 0x19, 18, 0 }, +{ 0x15, 17, 0 }, +{ 0x35, 17, 0 }, +{ 0xd, 17, 1 }, +{ 0x5, 18, 0 }, +{ 0x1d, 17, 1 }, +{ 0xd, 18, 0 }, +{ 0xb, 17, 0 }, +{ 0x1b, 17, 0 }, +{ 0x7, 17, 1 }, +{ 0x3, 18, 0 }, +{ 0xf, 17, 1 }, +{ 0x7, 18, 0 }, +{ 0x51, 15, 0 }, +{ 0xd1, 15, 0 }, +{ 0x31, 15, 1 }, +{ 0x11, 16, 0 }, +{ 0x71, 15, 1 }, +{ 0x31, 16, 0 }, +{ 0x29, 15, 0 }, +{ 0x69, 15, 0 }, +{ 0x19, 15, 1 }, +{ 0x9, 16, 0 }, +{ 0x39, 15, 1 }, +{ 0x19, 16, 0 }, +{ 0x15, 15, 0 }, +{ 0x35, 15, 0 }, +{ 0xd, 15, 1 }, +{ 0x5, 16, 0 }, +{ 0x1d, 15, 1 }, +{ 0xd, 16, 0 }, +{ 0xb, 15, 0 }, +{ 0x1b, 15, 0 }, +{ 0x7, 15, 1 }, +{ 0x3, 16, 0 }, +{ 0xf, 15, 1 }, +{ 0x7, 16, 0 }, +{ 0x288, 13, 0 }, +{ 0x688, 13, 0 }, +{ 0x188, 13, 1 }, +{ 0x88, 14, 0 }, +{ 0x388, 13, 1 }, +{ 0x188, 14, 0 }, +{ 0x148, 13, 0 }, +{ 0x348, 13, 0 }, +{ 0xc8, 13, 1 }, +{ 0x48, 14, 0 }, +{ 0x1c8, 13, 1 }, +{ 0xc8, 14, 0 }, +{ 0xa8, 13, 0 }, +{ 0x1a8, 13, 0 }, +{ 0x68, 13, 1 }, +{ 0x28, 14, 0 }, +{ 0xe8, 13, 1 }, +{ 0x68, 14, 0 }, +{ 0x58, 13, 0 }, +{ 0xd8, 13, 0 }, +{ 0x38, 13, 1 }, +{ 0x18, 14, 0 }, +{ 0x78, 13, 1 }, +{ 0x38, 14, 0 }, +{ 0x51, 13, 1 }, +{ 0xa0, 13, 0 }, +{ 0xd1, 13, 1 }, +{ 0x1a0, 13, 0 }, +{ 0x31, 13, 1 }, +{ 0x60, 13, 1 }, +{ 0x11, 14, 1 }, +{ 0x20, 14, 0 }, +{ 0x71, 13, 1 }, +{ 0xe0, 13, 1 }, +{ 0x31, 14, 1 }, +{ 0x60, 14, 0 }, +{ 0x29, 13, 1 }, +{ 0x50, 13, 0 }, +{ 0x69, 13, 1 }, +{ 0xd0, 13, 0 }, +{ 0x19, 13, 1 }, +{ 0x30, 13, 1 }, +{ 0x9, 14, 1 }, +{ 0x10, 14, 0 }, +{ 0x39, 13, 1 }, +{ 0x70, 13, 1 }, +{ 0x19, 14, 1 }, +{ 0x30, 14, 0 }, +{ 0x15, 13, 1 }, +{ 0x14, 13, 0 }, +{ 0x35, 13, 1 }, +{ 0x34, 13, 0 }, +{ 0xd, 13, 1 }, +{ 0xc, 13, 1 }, +{ 0x5, 14, 1 }, +{ 0x4, 14, 0 }, +{ 0x1d, 13, 1 }, +{ 0x1c, 13, 1 }, +{ 0xd, 14, 1 }, +{ 0xc, 14, 0 }, +{ 0xb, 13, 1 }, +{ 0xa, 13, 0 }, +{ 0x1b, 13, 1 }, +{ 0x1a, 13, 0 }, +{ 0x7, 13, 1 }, +{ 0x6, 13, 1 }, +{ 0x3, 14, 1 }, +{ 0x2, 14, 0 }, +{ 0xf, 13, 1 }, +{ 0xe, 13, 1 }, +{ 0x7, 14, 1 }, +{ 0x6, 14, 0 }, +{ 0x8, 12, 0 }, +{ 0x18, 12, 0 }, +{ 0x2, 12, 1 }, +{ 0xc, 12, 0 }, +{ 0x1, 12, 1 }, +{ 0x4, 12, 0 }, +{ 0x1, 11, 0 }, +{ 0x1, 10, 0 }, +{ 0x1, 9, 0 }, +{ 0x1, 8, 0 }, +{ 0x1, 7, 0 }, +{ 0x1, 6, 0 }, +{ 0x1, 5, 0 }, +{ 0x1, 4, 0 }, +{ 0x1, 3, 0 }, +{ 0x1, 1, 0 }, +{ 0x1, 0, 0 }, +}; + diff -Nur linux-2.4.19/arch/ia64/kdb/ia64-asmtab.h linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-asmtab.h --- linux-2.4.19/arch/ia64/kdb/ia64-asmtab.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-asmtab.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,148 @@ +/* ia64-asmtab.h -- Header for compacted IA-64 opcode tables. + Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Bob Manson of Cygnus Support + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 2, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef IA64_ASMTAB_H +#define IA64_ASMTAB_H + +#include "ia64.h" + +/* The primary opcode table is made up of the following: */ +struct ia64_main_table +{ + /* The entry in the string table that corresponds to the name of this + opcode. */ + unsigned short name_index; + + /* The type of opcode; corresponds to the TYPE field in + struct ia64_opcode. */ + unsigned char opcode_type; + + /* The number of outputs for this opcode. */ + unsigned char num_outputs; + + /* The base insn value for this opcode. It may be modified by completers. */ + ia64_insn opcode; + + /* The mask of valid bits in OPCODE. Zeros indicate operand fields. */ + ia64_insn mask; + + /* The operands of this instruction. Corresponds to the OPERANDS field + in struct ia64_opcode. */ + unsigned char operands[5]; + + /* The flags for this instruction. Corresponds to the FLAGS field in + struct ia64_opcode. */ + short flags; + + /* The tree of completers for this instruction; this is an offset into + completer_table. */ + short completers; +}; + +/* Each instruction has a set of possible "completers", or additional + suffixes that can alter the instruction's behavior, and which has + potentially different dependencies. + + The completer entries modify certain bits in the instruction opcode. + Which bits are to be modified are marked by the BITS, MASK and + OFFSET fields. The completer entry may also note dependencies for the + opcode. + + These completers are arranged in a DAG; the pointers are indexes + into the completer_table array. The completer DAG is searched by + find_completer () and ia64_find_matching_opcode (). + + Note that each completer needs to be applied in turn, so that if we + have the instruction + cmp.lt.unc + the completer entries for both "lt" and "unc" would need to be applied + to the opcode's value. + + Some instructions do not require any completers; these contain an + empty completer entry. Instructions that require a completer do + not contain an empty entry. + + Terminal completers (those completers that validly complete an + instruction) are marked by having the TERMINAL_COMPLETER flag set. + + Only dependencies listed in the terminal completer for an opcode are + considered to apply to that opcode instance. */ + +struct ia64_completer_table +{ + /* The bit value that this completer sets. */ + unsigned int bits; + + /* And its mask. 1s are bits that are to be modified in the + instruction. */ + unsigned int mask; + + /* The entry in the string table that corresponds to the name of this + completer. */ + unsigned short name_index; + + /* An alternative completer, or -1 if this is the end of the chain. */ + short alternative; + + /* A pointer to the DAG of completers that can potentially follow + this one, or -1. */ + short subentries; + + /* The bit offset in the instruction where BITS and MASK should be + applied. */ + unsigned char offset : 7; + + unsigned char terminal_completer : 1; + + /* Index into the dependency list table */ + short dependencies; +}; + +/* This contains sufficient information for the disassembler to resolve + the complete name of the original instruction. */ +struct ia64_dis_names +{ + /* COMPLETER_INDEX represents the tree of completers that make up + the instruction. The LSB represents the top of the tree for the + specified instruction. + + A 0 bit indicates to go to the next alternate completer via the + alternative field; a 1 bit indicates that the current completer + is part of the instruction, and to go down the subentries index. + We know we've reached the final completer when we run out of 1 + bits. + + There is always at least one 1 bit. */ + unsigned int completer_index : 20; + + /* The index in the main_table[] array for the instruction. */ + unsigned short insn_index : 11; + + /* If set, the next entry in this table is an alternate possibility + for this instruction encoding. Which one to use is determined by + the instruction type and other factors (see opcode_verify ()). */ + unsigned int next_flag : 1; + + /* The disassembly priority of this entry among instructions. */ + unsigned short priority; +}; + +#endif diff -Nur linux-2.4.19/arch/ia64/kdb/ia64-dis.c linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-dis.c --- linux-2.4.19/arch/ia64/kdb/ia64-dis.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-dis.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,304 @@ +/* ia64-dis.c -- Disassemble ia64 instructions + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 2, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Extracted from cygnus CVS and modified for kdb use. + * Keith Owens 30 Oct 2000 + */ + +#ifdef __KERNEL__ +#include +#include +#include +#include "ia64.h" + +/* imported from bfd/libbfd.c for kernel */ +static inline bfd_vma +bfd_getl64 (const bfd_byte *addr) +{ + unsigned long low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((unsigned long)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return high << 32 | low; + +} + +#else /* ! __KERNEL__ */ +#include +#include + +#include "dis-asm.h" +#include "opcode/ia64.h" +#endif + +#define NELEMS(a) ((int) (sizeof (a) / sizeof (a[0]))) + +/* Disassemble ia64 instruction. */ + +/* Return the instruction type for OPCODE found in unit UNIT. */ + +static enum ia64_insn_type +unit_to_type (ia64_insn opcode, enum ia64_unit unit) +{ + enum ia64_insn_type type; + int op; + + op = IA64_OP (opcode); + + if (op >= 8 && (unit == IA64_UNIT_I || unit == IA64_UNIT_M)) + { + type = IA64_TYPE_A; + } + else + { + switch (unit) + { + case IA64_UNIT_I: + type = IA64_TYPE_I; break; + case IA64_UNIT_M: + type = IA64_TYPE_M; break; + case IA64_UNIT_B: + type = IA64_TYPE_B; break; + case IA64_UNIT_F: + type = IA64_TYPE_F; break; + case IA64_UNIT_L: + case IA64_UNIT_X: + type = IA64_TYPE_X; break; + default: + type = -1; + } + } + return type; +} + +int +print_insn_ia64 (bfd_vma memaddr, struct disassemble_info *info) +{ + ia64_insn t0, t1, slot[3], template, s_bit, insn; + int slotnum, j, status, need_comma, retval, slot_multiplier; + const struct ia64_operand *odesc; + const struct ia64_opcode *idesc; + const char *err, *str, *tname; + BFD_HOST_U_64_BIT value; + bfd_byte bundle[16]; + enum ia64_unit unit; + char regname[16]; + + if (info->bytes_per_line == 0) + info->bytes_per_line = 6; + info->display_endian = info->endian; + + slot_multiplier = info->bytes_per_line; + retval = slot_multiplier; + + slotnum = (((long) memaddr) & 0xf) / slot_multiplier; + if (slotnum > 2) + return -1; + + memaddr -= (memaddr & 0xf); + status = (*info->read_memory_func) (memaddr, bundle, sizeof (bundle), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + /* bundles are always in little-endian byte order */ + t0 = bfd_getl64 (bundle); + t1 = bfd_getl64 (bundle + 8); + s_bit = t0 & 1; + template = (t0 >> 1) & 0xf; + slot[0] = (t0 >> 5) & 0x1ffffffffffLL; + slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18); + slot[2] = (t1 >> 23) & 0x1ffffffffffLL; + + tname = ia64_templ_desc[template].name; + if (slotnum == 0) + (*info->fprintf_func) (info->stream, "[%s] ", tname); + else + (*info->fprintf_func) (info->stream, " ", tname); + + unit = ia64_templ_desc[template].exec_unit[slotnum]; + + if (template == 2 && slotnum == 1) + { + /* skip L slot in MLI template: */ + slotnum = 2; + retval += slot_multiplier; + } + + insn = slot[slotnum]; + + if (unit == IA64_UNIT_NIL) + goto decoding_failed; + + idesc = ia64_dis_opcode (insn, unit_to_type (insn, unit)); + if (idesc == NULL) + goto decoding_failed; + + /* print predicate, if any: */ + + if ((idesc->flags & IA64_OPCODE_NO_PRED) + || (insn & 0x3f) == 0) + (*info->fprintf_func) (info->stream, " "); + else + (*info->fprintf_func) (info->stream, "(p%02d) ", (int)(insn & 0x3f)); + + /* now the actual instruction: */ + + (*info->fprintf_func) (info->stream, "%s", idesc->name); + if (idesc->operands[0]) + (*info->fprintf_func) (info->stream, " "); + + need_comma = 0; + for (j = 0; j < NELEMS (idesc->operands) && idesc->operands[j]; ++j) + { + odesc = elf64_ia64_operands + idesc->operands[j]; + + if (need_comma) + (*info->fprintf_func) (info->stream, ","); + + if (odesc - elf64_ia64_operands == IA64_OPND_IMMU64) + { + /* special case of 64 bit immediate load: */ + value = ((insn >> 13) & 0x7f) | (((insn >> 27) & 0x1ff) << 7) + | (((insn >> 22) & 0x1f) << 16) | (((insn >> 21) & 0x1) << 21) + | (slot[1] << 22) | (((insn >> 36) & 0x1) << 63); + } + else if (odesc - elf64_ia64_operands == IA64_OPND_IMMU62) + { + /* 62-bit immediate for nop.x/break.x */ + value = ((slot[1] & 0x1ffffffffffLL) << 21) + | (((insn >> 36) & 0x1) << 20) + | ((insn >> 6) & 0xfffff); + } + else if (odesc - elf64_ia64_operands == IA64_OPND_TGT64) + { + /* 60-bit immedate for long branches. */ + value = (((insn >> 13) & 0xfffff) + | (((insn >> 36) & 1) << 59) + | (slot[1] << 20)) << 4; + } + else + { + err = (*odesc->extract) (odesc, insn, &value); + if (err) + { + (*info->fprintf_func) (info->stream, "%s", err); + goto done; + } + } + + switch (odesc->class) + { + case IA64_OPND_CLASS_CST: + (*info->fprintf_func) (info->stream, "%s", odesc->str); + break; + + case IA64_OPND_CLASS_REG: + if (odesc->str[0] == 'a' && odesc->str[1] == 'r') + { + switch (value) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + sprintf (regname, "ar.k%u", (unsigned int) value); + break; + case 16: strcpy (regname, "ar.rsc"); break; + case 17: strcpy (regname, "ar.bsp"); break; + case 18: strcpy (regname, "ar.bspstore"); break; + case 19: strcpy (regname, "ar.rnat"); break; + case 32: strcpy (regname, "ar.ccv"); break; + case 36: strcpy (regname, "ar.unat"); break; + case 40: strcpy (regname, "ar.fpsr"); break; + case 44: strcpy (regname, "ar.itc"); break; + case 64: strcpy (regname, "ar.pfs"); break; + case 65: strcpy (regname, "ar.lc"); break; + case 66: strcpy (regname, "ar.ec"); break; + default: + sprintf (regname, "ar%u", (unsigned int) value); + break; + } + (*info->fprintf_func) (info->stream, "%s", regname); + } + else + (*info->fprintf_func) (info->stream, "%s%d", odesc->str, (int)value); + break; + + case IA64_OPND_CLASS_IND: + (*info->fprintf_func) (info->stream, "%s[r%d]", odesc->str, (int)value); + break; + + case IA64_OPND_CLASS_ABS: + str = 0; + if (odesc - elf64_ia64_operands == IA64_OPND_MBTYPE4) + switch (value) + { + case 0x0: str = "@brcst"; break; + case 0x8: str = "@mix"; break; + case 0x9: str = "@shuf"; break; + case 0xa: str = "@alt"; break; + case 0xb: str = "@rev"; break; + } + + if (str) + (*info->fprintf_func) (info->stream, "%s", str); + else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_SIGNED) + (*info->fprintf_func) (info->stream, "%lld", value); + else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED) + (*info->fprintf_func) (info->stream, "%llu", value); + else + (*info->fprintf_func) (info->stream, "0x%llx", value); + break; + + case IA64_OPND_CLASS_REL: + (*info->print_address_func) (memaddr + value, info); + break; + } + + need_comma = 1; + if (j + 1 == idesc->num_outputs) + { + (*info->fprintf_func) (info->stream, "="); + need_comma = 0; + } + } + if (slotnum + 1 == ia64_templ_desc[template].group_boundary + || ((slotnum == 2) && s_bit)) + (*info->fprintf_func) (info->stream, ";;"); + + done: + ia64_free_opcode (idesc); + failed: + if (slotnum == 2) + retval += 16 - 3*slot_multiplier; + return retval; + + decoding_failed: + (*info->fprintf_func) (info->stream, " data8 %#011llx", insn); + goto failed; +} diff -Nur linux-2.4.19/arch/ia64/kdb/ia64-opc.c linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-opc.c --- linux-2.4.19/arch/ia64/kdb/ia64-opc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-opc.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,726 @@ +/* ia64-opc.c -- Functions to access the compacted opcode table + Copyright (C) 1999 Free Software Foundation, Inc. + Written by Bob Manson of Cygnus Solutions, + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 2, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +#if defined(__KERNEL__) +#include +#include +#include +#include +#else +#include "ansidecl.h" +#include "libiberty.h" +#include "sysdep.h" +#endif + +#include "ia64-asmtab.h" +#include "ia64-asmtab.c" + +const struct ia64_templ_desc ia64_templ_desc[16] = + { + { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" }, /* 0 */ + { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" }, + { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" }, + { 0, { 0, }, "-3-" }, + { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" }, /* 4 */ + { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" }, + { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" }, + { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" }, + { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" }, /* 8 */ + { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" }, + { 0, { 0, }, "-a-" }, + { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" }, + { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" }, /* c */ + { 0, { 0, }, "-d-" }, + { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" }, + { 0, { 0, }, "-f-" }, + }; + + +/* Copy the prefix contained in *PTR (up to a '.' or a NUL) to DEST. + PTR will be adjusted to point to the start of the next portion + of the opcode, or at the NUL character. */ + +static void +get_opc_prefix (const char **ptr, char *dest) +{ + char *c = strchr (*ptr, '.'); + if (c != NULL) + { + memcpy (dest, *ptr, c - *ptr); + dest[c - *ptr] = '\0'; + *ptr = c + 1; + } + else + { + int l = strlen (*ptr); + memcpy (dest, *ptr, l); + dest[l] = '\0'; + *ptr += l; + } +} + +/* Find the index of the entry in the string table corresponding to + STR; return -1 if one does not exist. */ + +static short +find_string_ent (const char *str) +{ + short start = 0; + short end = sizeof (ia64_strings) / sizeof (const char *); + short i = (start + end) / 2; + + if (strcmp (str, ia64_strings[end - 1]) > 0) + { + return -1; + } + while (start <= end) + { + int c = strcmp (str, ia64_strings[i]); + if (c < 0) + { + end = i - 1; + } + else if (c == 0) + { + return i; + } + else + { + start = i + 1; + } + i = (start + end) / 2; + } + return -1; +} + +/* Find the opcode in the main opcode table whose name is STRINGINDEX, or + return -1 if one does not exist. */ + +static short +find_main_ent (short nameindex) +{ + short start = 0; + short end = sizeof (main_table) / sizeof (struct ia64_main_table); + short i = (start + end) / 2; + + if (nameindex < main_table[0].name_index + || nameindex > main_table[end - 1].name_index) + { + return -1; + } + while (start <= end) + { + if (nameindex < main_table[i].name_index) + { + end = i - 1; + } + else if (nameindex == main_table[i].name_index) + { + while (i > 0 && main_table[i - 1].name_index == nameindex) + { + i--; + } + return i; + } + else + { + start = i + 1; + } + i = (start + end) / 2; + } + return -1; +} + +/* Find the index of the entry in the completer table that is part of + MAIN_ENT (starting from PREV_COMPLETER) that matches NAME, or + return -1 if one does not exist. */ + +static short +find_completer (short main_ent, short prev_completer, const char *name) +{ + short name_index = find_string_ent (name); + + if (name_index < 0) + { + return -1; + } + + if (prev_completer == -1) + { + prev_completer = main_table[main_ent].completers; + } + else + { + prev_completer = completer_table[prev_completer].subentries; + } + + while (prev_completer != -1) + { + if (completer_table[prev_completer].name_index == name_index) + { + return prev_completer; + } + prev_completer = completer_table[prev_completer].alternative; + } + return -1; +} + +/* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and + return the result. */ + +static ia64_insn +apply_completer (ia64_insn opcode, int completer_index) +{ + ia64_insn mask = completer_table[completer_index].mask; + ia64_insn bits = completer_table[completer_index].bits; + int shiftamt = (completer_table[completer_index].offset & 63); + + mask = mask << shiftamt; + bits = bits << shiftamt; + opcode = (opcode & ~mask) | bits; + return opcode; +} + +/* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in + the dis_table array, and return its value. (BITOFFSET is numbered + starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the + first byte in OP_POINTER.) */ + +static int +extract_op_bits (int op_pointer, int bitoffset, int bits) +{ + int res = 0; + + op_pointer += (bitoffset / 8); + + if (bitoffset % 8) + { + unsigned int op = dis_table[op_pointer++]; + int numb = 8 - (bitoffset % 8); + int mask = (1 << numb) - 1; + int bata = (bits < numb) ? bits : numb; + int delta = numb - bata; + + res = (res << bata) | ((op & mask) >> delta); + bitoffset += bata; + bits -= bata; + } + while (bits >= 8) + { + res = (res << 8) | (dis_table[op_pointer++] & 255); + bits -= 8; + } + if (bits > 0) + { + unsigned int op = (dis_table[op_pointer++] & 255); + res = (res << bits) | (op >> (8 - bits)); + } + return res; +} + +/* Examine the state machine entry at OP_POINTER in the dis_table + array, and extract its values into OPVAL and OP. The length of the + state entry in bits is returned. */ + +static int +extract_op (int op_pointer, int *opval, unsigned int *op) +{ + int oplen = 5; + + *op = dis_table[op_pointer]; + + if ((*op) & 0x40) + { + opval[0] = extract_op_bits (op_pointer, oplen, 5); + oplen += 5; + } + switch ((*op) & 0x30) + { + case 0x10: + { + opval[1] = extract_op_bits (op_pointer, oplen, 8); + oplen += 8; + opval[1] += op_pointer; + break; + } + case 0x20: + { + opval[1] = extract_op_bits (op_pointer, oplen, 16); + if (! (opval[1] & 32768)) + { + opval[1] += op_pointer; + } + oplen += 16; + break; + } + case 0x30: + { + oplen--; + opval[2] = extract_op_bits (op_pointer, oplen, 12); + oplen += 12; + opval[2] |= 32768; + break; + } + } + if (((*op) & 0x08) && (((*op) & 0x30) != 0x30)) + { + opval[2] = extract_op_bits (op_pointer, oplen, 16); + oplen += 16; + if (! (opval[2] & 32768)) + { + opval[2] += op_pointer; + } + } + return oplen; +} + +/* Returns a non-zero value if the opcode in the main_table list at + PLACE matches OPCODE and is of type TYPE. */ + +static int +opcode_verify (ia64_insn opcode, int place, enum ia64_insn_type type) +{ + if (main_table[place].opcode_type != type) + { + return 0; + } + if (main_table[place].flags + & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT)) + { + const struct ia64_operand *o1, *o2; + ia64_insn f2, f3; + + if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3) + { + o1 = elf64_ia64_operands + IA64_OPND_F2; + o2 = elf64_ia64_operands + IA64_OPND_F3; + (*o1->extract) (o1, opcode, &f2); + (*o2->extract) (o2, opcode, &f3); + if (f2 != f3) + return 0; + } + else + { + ia64_insn len, count; + + /* length must equal 64-count: */ + o1 = elf64_ia64_operands + IA64_OPND_LEN6; + o2 = elf64_ia64_operands + main_table[place].operands[2]; + (*o1->extract) (o1, opcode, &len); + (*o2->extract) (o2, opcode, &count); + if (len != 64 - count) + return 0; + } + } + return 1; +} + +/* Find an instruction entry in the ia64_dis_names array that matches + opcode OPCODE and is of type TYPE. Returns either a positive index + into the array, or a negative value if an entry for OPCODE could + not be found. Checks all matches and returns the one with the highest + priority. */ + +static int +locate_opcode_ent (ia64_insn opcode, enum ia64_insn_type type) +{ + int currtest[41]; + int bitpos[41]; + int op_ptr[41]; + int currstatenum = 0; + short found_disent = -1; + short found_priority = -1; + + currtest[currstatenum] = 0; + op_ptr[currstatenum] = 0; + bitpos[currstatenum] = 40; + + while (1) + { + int op_pointer = op_ptr[currstatenum]; + unsigned int op; + int currbitnum = bitpos[currstatenum]; + int oplen; + int opval[3]; + int next_op; + int currbit; + + oplen = extract_op (op_pointer, opval, &op); + + bitpos[currstatenum] = currbitnum; + + /* Skip opval[0] bits in the instruction. */ + if (op & 0x40) + { + currbitnum -= opval[0]; + } + + /* The value of the current bit being tested. */ + currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0; + next_op = -1; + + /* We always perform the tests specified in the current state in + a particular order, falling through to the next test if the + previous one failed. */ + switch (currtest[currstatenum]) + { + case 0: + currtest[currstatenum]++; + if (currbit == 0 && (op & 0x80)) + { + /* Check for a zero bit. If this test solely checks for + a zero bit, we can check for up to 8 consecutive zero + bits (the number to check is specified by the lower 3 + bits in the state code.) + + If the state instruction matches, we go to the very + next state instruction; otherwise, try the next test. */ + + if ((op & 0xf8) == 0x80) + { + int count = op & 0x7; + int x; + + for (x = 0; x <= count; x++) + { + int i = + opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0; + if (i) + { + break; + } + } + if (x > count) + { + next_op = op_pointer + ((oplen + 7) / 8); + currbitnum -= count; + break; + } + } + else if (! currbit) + { + next_op = op_pointer + ((oplen + 7) / 8); + break; + } + } + /* FALLTHROUGH */ + case 1: + /* If the bit in the instruction is one, go to the state + instruction specified by opval[1]. */ + currtest[currstatenum]++; + if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30)) + { + next_op = opval[1]; + break; + } + /* FALLTHROUGH */ + case 2: + /* Don't care. Skip the current bit and go to the state + instruction specified by opval[2]. + + An encoding of 0x30 is special; this means that a 12-bit + offset into the ia64_dis_names[] array is specified. */ + currtest[currstatenum]++; + if ((op & 0x08) || ((op & 0x30) == 0x30)) + { + next_op = opval[2]; + break; + } + } + + /* If bit 15 is set in the address of the next state, an offset + in the ia64_dis_names array was specified instead. We then + check to see if an entry in the list of opcodes matches the + opcode we were given; if so, we have succeeded. */ + + if ((next_op >= 0) && (next_op & 32768)) + { + short disent = next_op & 32767; + short priority = -1; + + if (next_op > 65535) + { + abort (); + } + + /* Run through the list of opcodes to check, trying to find + one that matches. */ + while (disent >= 0) + { + int place = ia64_dis_names[disent].insn_index; + + priority = ia64_dis_names[disent].priority; + + if (opcode_verify (opcode, place, type) + && priority > found_priority) + { + break; + } + if (ia64_dis_names[disent].next_flag) + { + disent++; + } + else + { + disent = -1; + } + } + + if (disent >= 0) + { + found_disent = disent; + found_priority = priority; + } + /* Try the next test in this state, regardless of whether a match + was found. */ + next_op = -2; + } + + /* next_op == -1 is "back up to the previous state". + next_op == -2 is "stay in this state and try the next test". + Otherwise, transition to the state indicated by next_op. */ + + if (next_op == -1) + { + currstatenum--; + if (currstatenum < 0) + { + return found_disent; + } + } + else if (next_op >= 0) + { + currstatenum++; + bitpos[currstatenum] = currbitnum - 1; + op_ptr[currstatenum] = next_op; + currtest[currstatenum] = 0; + } + } +} + +/* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */ + +static struct ia64_opcode * +make_ia64_opcode (ia64_insn opcode, const char *name, int place, int depind) +{ + struct ia64_opcode *res = + (struct ia64_opcode *) xmalloc (sizeof (struct ia64_opcode)); + res->name = xstrdup (name); + res->type = main_table[place].opcode_type; + res->num_outputs = main_table[place].num_outputs; + res->opcode = opcode; + res->mask = main_table[place].mask; + res->operands[0] = main_table[place].operands[0]; + res->operands[1] = main_table[place].operands[1]; + res->operands[2] = main_table[place].operands[2]; + res->operands[3] = main_table[place].operands[3]; + res->operands[4] = main_table[place].operands[4]; + res->flags = main_table[place].flags; + res->ent_index = place; + res->dependencies = &op_dependencies[depind]; + return res; +} + +/* Determine the ia64_opcode entry for the opcode specified by INSN + and TYPE. If a valid entry is not found, return NULL. */ +struct ia64_opcode * +ia64_dis_opcode (ia64_insn insn, enum ia64_insn_type type) +{ + int disent = locate_opcode_ent (insn, type); + + if (disent < 0) + { + return NULL; + } + else + { + unsigned int cb = ia64_dis_names[disent].completer_index; + static char name[128]; + int place = ia64_dis_names[disent].insn_index; + int ci = main_table[place].completers; + ia64_insn tinsn = main_table[place].opcode; + + strcpy (name, ia64_strings [main_table[place].name_index]); + + while (cb) + { + if (cb & 1) + { + int cname = completer_table[ci].name_index; + + tinsn = apply_completer (tinsn, ci); + + if (ia64_strings[cname][0] != '\0') + { + strcat (name, "."); + strcat (name, ia64_strings[cname]); + } + if (cb != 1) + { + ci = completer_table[ci].subentries; + } + } + else + { + ci = completer_table[ci].alternative; + } + if (ci < 0) + { + abort (); + } + cb = cb >> 1; + } + if (tinsn != (insn & main_table[place].mask)) + { + abort (); + } + return make_ia64_opcode (insn, name, place, + completer_table[ci].dependencies); + } +} + +/* Search the main_opcode table starting from PLACE for an opcode that + matches NAME. Return NULL if one is not found. */ + +static struct ia64_opcode * +ia64_find_matching_opcode (const char *name, short place) +{ + char op[129]; + const char *suffix; + short name_index; + + if (strlen (name) > 128) + { + return NULL; + } + suffix = name; + get_opc_prefix (&suffix, op); + name_index = find_string_ent (op); + if (name_index < 0) + { + return NULL; + } + + while (main_table[place].name_index == name_index) + { + const char *curr_suffix = suffix; + ia64_insn curr_insn = main_table[place].opcode; + short completer = -1; + + do { + if (suffix[0] == '\0') + { + completer = find_completer (place, completer, suffix); + } + else + { + get_opc_prefix (&curr_suffix, op); + completer = find_completer (place, completer, op); + } + if (completer != -1) + { + curr_insn = apply_completer (curr_insn, completer); + } + } while (completer != -1 && curr_suffix[0] != '\0'); + + if (completer != -1 && curr_suffix[0] == '\0' + && completer_table[completer].terminal_completer) + { + int depind = completer_table[completer].dependencies; + return make_ia64_opcode (curr_insn, name, place, depind); + } + else + { + place++; + } + } + return NULL; +} + +/* Find the next opcode after PREV_ENT that matches PREV_ENT, or return NULL + if one does not exist. + + It is the caller's responsibility to invoke ia64_free_opcode () to + release any resources used by the returned entry. */ + +struct ia64_opcode * +ia64_find_next_opcode (struct ia64_opcode *prev_ent) +{ + return ia64_find_matching_opcode (prev_ent->name, + prev_ent->ent_index + 1); +} + +/* Find the first opcode that matches NAME, or return NULL if it does + not exist. + + It is the caller's responsibility to invoke ia64_free_opcode () to + release any resources used by the returned entry. */ + +struct ia64_opcode * +ia64_find_opcode (const char *name) +{ + char op[129]; + const char *suffix; + short place; + short name_index; + + if (strlen (name) > 128) + { + return NULL; + } + suffix = name; + get_opc_prefix (&suffix, op); + name_index = find_string_ent (op); + if (name_index < 0) + { + return NULL; + } + + place = find_main_ent (name_index); + + if (place < 0) + { + return NULL; + } + return ia64_find_matching_opcode (name, place); +} + +/* Free any resources used by ENT. */ +void +ia64_free_opcode (ent) + struct ia64_opcode *ent; +{ + free ((void *)ent->name); + free (ent); +} + +const struct ia64_dependency * +ia64_find_dependency (index) + int index; +{ + index = DEP(index); + + if (index < 0 || index >= sizeof(dependencies) / sizeof(dependencies[0])) + return NULL; + + return &dependencies[index]; +} diff -Nur linux-2.4.19/arch/ia64/kdb/ia64-opc.h linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-opc.h --- linux-2.4.19/arch/ia64/kdb/ia64-opc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64-opc.h Wed Jan 30 15:40:36 2002 @@ -0,0 +1,129 @@ +/* ia64-opc.h -- IA-64 opcode table. + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version + 2, or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef IA64_OPC_H +#define IA64_OPC_H + +#include "ia64.h" + +/* define a couple of abbreviations: */ + +#define bOp(x) (((ia64_insn) ((x) & 0xf)) << 37) +#define mOp bOp (-1) +#define Op(x) bOp (x), mOp + +#define FIRST IA64_OPCODE_FIRST +#define X_IN_MLX IA64_OPCODE_X_IN_MLX +#define LAST IA64_OPCODE_LAST +#define PRIV IA64_OPCODE_PRIV +#define NO_PRED IA64_OPCODE_NO_PRED +#define SLOT2 IA64_OPCODE_SLOT2 +#define PSEUDO IA64_OPCODE_PSEUDO +#define F2_EQ_F3 IA64_OPCODE_F2_EQ_F3 +#define LEN_EQ_64MCNT IA64_OPCODE_LEN_EQ_64MCNT +#define MOD_RRBS IA64_OPCODE_MOD_RRBS + +#define AR_CCV IA64_OPND_AR_CCV +#define AR_PFS IA64_OPND_AR_PFS +#define C1 IA64_OPND_C1 +#define C8 IA64_OPND_C8 +#define C16 IA64_OPND_C16 +#define GR0 IA64_OPND_GR0 +#define IP IA64_OPND_IP +#define PR IA64_OPND_PR +#define PR_ROT IA64_OPND_PR_ROT +#define PSR IA64_OPND_PSR +#define PSR_L IA64_OPND_PSR_L +#define PSR_UM IA64_OPND_PSR_UM + +#define AR3 IA64_OPND_AR3 +#define B1 IA64_OPND_B1 +#define B2 IA64_OPND_B2 +#define CR3 IA64_OPND_CR3 +#define F1 IA64_OPND_F1 +#define F2 IA64_OPND_F2 +#define F3 IA64_OPND_F3 +#define F4 IA64_OPND_F4 +#define P1 IA64_OPND_P1 +#define P2 IA64_OPND_P2 +#define R1 IA64_OPND_R1 +#define R2 IA64_OPND_R2 +#define R3 IA64_OPND_R3 +#define R3_2 IA64_OPND_R3_2 + +#define CPUID_R3 IA64_OPND_CPUID_R3 +#define DBR_R3 IA64_OPND_DBR_R3 +#define DTR_R3 IA64_OPND_DTR_R3 +#define ITR_R3 IA64_OPND_ITR_R3 +#define IBR_R3 IA64_OPND_IBR_R3 +#define MR3 IA64_OPND_MR3 +#define MSR_R3 IA64_OPND_MSR_R3 +#define PKR_R3 IA64_OPND_PKR_R3 +#define PMC_R3 IA64_OPND_PMC_R3 +#define PMD_R3 IA64_OPND_PMD_R3 +#define RR_R3 IA64_OPND_RR_R3 + +#define CCNT5 IA64_OPND_CCNT5 +#define CNT2a IA64_OPND_CNT2a +#define CNT2b IA64_OPND_CNT2b +#define CNT2c IA64_OPND_CNT2c +#define CNT5 IA64_OPND_CNT5 +#define CNT6 IA64_OPND_CNT6 +#define CPOS6a IA64_OPND_CPOS6a +#define CPOS6b IA64_OPND_CPOS6b +#define CPOS6c IA64_OPND_CPOS6c +#define IMM1 IA64_OPND_IMM1 +#define IMM14 IA64_OPND_IMM14 +#define IMM17 IA64_OPND_IMM17 +#define IMM22 IA64_OPND_IMM22 +#define IMM44 IA64_OPND_IMM44 +#define SOF IA64_OPND_SOF +#define SOL IA64_OPND_SOL +#define SOR IA64_OPND_SOR +#define IMM8 IA64_OPND_IMM8 +#define IMM8U4 IA64_OPND_IMM8U4 +#define IMM8M1 IA64_OPND_IMM8M1 +#define IMM8M1U4 IA64_OPND_IMM8M1U4 +#define IMM8M1U8 IA64_OPND_IMM8M1U8 +#define IMM9a IA64_OPND_IMM9a +#define IMM9b IA64_OPND_IMM9b +#define IMMU2 IA64_OPND_IMMU2 +#define IMMU21 IA64_OPND_IMMU21 +#define IMMU24 IA64_OPND_IMMU24 +#define IMMU62 IA64_OPND_IMMU62 +#define IMMU64 IA64_OPND_IMMU64 +#define IMMU7a IA64_OPND_IMMU7a +#define IMMU7b IA64_OPND_IMMU7b +#define IMMU9 IA64_OPND_IMMU9 +#define INC3 IA64_OPND_INC3 +#define LEN4 IA64_OPND_LEN4 +#define LEN6 IA64_OPND_LEN6 +#define MBTYPE4 IA64_OPND_MBTYPE4 +#define MHTYPE8 IA64_OPND_MHTYPE8 +#define POS6 IA64_OPND_POS6 +#define TAG13 IA64_OPND_TAG13 +#define TAG13b IA64_OPND_TAG13b +#define TGT25 IA64_OPND_TGT25 +#define TGT25b IA64_OPND_TGT25b +#define TGT25c IA64_OPND_TGT25c +#define TGT64 IA64_OPND_TGT64 + +#endif diff -Nur linux-2.4.19/arch/ia64/kdb/ia64.h linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64.h --- linux-2.4.19/arch/ia64/kdb/ia64.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/ia64.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,390 @@ +/* ia64.h -- Header file for ia64 opcode table + Copyright (C) 1998, 1999 David Mosberger-Tang + + See the file HP-COPYRIGHT for additional information. */ + +#ifndef opcode_ia64_h +#define opcode_ia64_h + +#ifndef __KERNEL__ +#include +#else +#include +#endif + + +typedef BFD_HOST_U_64_BIT ia64_insn; + +enum ia64_insn_type + { + IA64_TYPE_NIL = 0, /* illegal type */ + IA64_TYPE_A, /* integer alu (I- or M-unit) */ + IA64_TYPE_I, /* non-alu integer (I-unit) */ + IA64_TYPE_M, /* memory (M-unit) */ + IA64_TYPE_B, /* branch (B-unit) */ + IA64_TYPE_F, /* floating-point (F-unit) */ + IA64_TYPE_X, /* long encoding (X-unit) */ + IA64_TYPE_DYN, /* Dynamic opcode */ + IA64_NUM_TYPES + }; + +enum ia64_unit + { + IA64_UNIT_NIL = 0, /* illegal unit */ + IA64_UNIT_I, /* integer unit */ + IA64_UNIT_M, /* memory unit */ + IA64_UNIT_B, /* branching unit */ + IA64_UNIT_F, /* floating-point unit */ + IA64_UNIT_L, /* long "unit" */ + IA64_UNIT_X, /* may be integer or branch unit */ + IA64_NUM_UNITS + }; + +/* Changes to this enumeration must be propagated to the operand table in + bfd/cpu-ia64-opc.c + */ +enum ia64_opnd + { + IA64_OPND_NIL, /* no operand---MUST BE FIRST!*/ + + /* constants */ + IA64_OPND_AR_CCV, /* application register ccv (ar.ccv) */ + IA64_OPND_AR_PFS, /* application register pfs (ar.pfs) */ + IA64_OPND_C1, /* the constant 1 */ + IA64_OPND_C8, /* the constant 8 */ + IA64_OPND_C16, /* the constant 16 */ + IA64_OPND_GR0, /* gr0 */ + IA64_OPND_IP, /* instruction pointer (ip) */ + IA64_OPND_PR, /* predicate register (pr) */ + IA64_OPND_PR_ROT, /* rotating predicate register (pr.rot) */ + IA64_OPND_PSR, /* processor status register (psr) */ + IA64_OPND_PSR_L, /* processor status register L (psr.l) */ + IA64_OPND_PSR_UM, /* processor status register UM (psr.um) */ + + /* register operands: */ + IA64_OPND_AR3, /* third application register # (bits 20-26) */ + IA64_OPND_B1, /* branch register # (bits 6-8) */ + IA64_OPND_B2, /* branch register # (bits 13-15) */ + IA64_OPND_CR3, /* third control register # (bits 20-26) */ + IA64_OPND_F1, /* first floating-point register # */ + IA64_OPND_F2, /* second floating-point register # */ + IA64_OPND_F3, /* third floating-point register # */ + IA64_OPND_F4, /* fourth floating-point register # */ + IA64_OPND_P1, /* first predicate # */ + IA64_OPND_P2, /* second predicate # */ + IA64_OPND_R1, /* first register # */ + IA64_OPND_R2, /* second register # */ + IA64_OPND_R3, /* third register # */ + IA64_OPND_R3_2, /* third register # (limited to gr0-gr3) */ + + /* indirect operands: */ + IA64_OPND_CPUID_R3, /* cpuid[reg] */ + IA64_OPND_DBR_R3, /* dbr[reg] */ + IA64_OPND_DTR_R3, /* dtr[reg] */ + IA64_OPND_ITR_R3, /* itr[reg] */ + IA64_OPND_IBR_R3, /* ibr[reg] */ + IA64_OPND_MR3, /* memory at addr of third register # */ + IA64_OPND_MSR_R3, /* msr[reg] */ + IA64_OPND_PKR_R3, /* pkr[reg] */ + IA64_OPND_PMC_R3, /* pmc[reg] */ + IA64_OPND_PMD_R3, /* pmd[reg] */ + IA64_OPND_RR_R3, /* rr[reg] */ + + /* immediate operands: */ + IA64_OPND_CCNT5, /* 5-bit count (31 - bits 20-24) */ + IA64_OPND_CNT2a, /* 2-bit count (1 + bits 27-28) */ + IA64_OPND_CNT2b, /* 2-bit count (bits 27-28): 1, 2, 3 */ + IA64_OPND_CNT2c, /* 2-bit count (bits 30-31): 0, 7, 15, or 16 */ + IA64_OPND_CNT5, /* 5-bit count (bits 14-18) */ + IA64_OPND_CNT6, /* 6-bit count (bits 27-32) */ + IA64_OPND_CPOS6a, /* 6-bit count (63 - bits 20-25) */ + IA64_OPND_CPOS6b, /* 6-bit count (63 - bits 14-19) */ + IA64_OPND_CPOS6c, /* 6-bit count (63 - bits 31-36) */ + IA64_OPND_IMM1, /* signed 1-bit immediate (bit 36) */ + IA64_OPND_IMMU2, /* unsigned 2-bit immediate (bits 13-14) */ + IA64_OPND_IMMU7a, /* unsigned 7-bit immediate (bits 13-19) */ + IA64_OPND_IMMU7b, /* unsigned 7-bit immediate (bits 20-26) */ + IA64_OPND_SOF, /* 8-bit stack frame size */ + IA64_OPND_SOL, /* 8-bit size of locals */ + IA64_OPND_SOR, /* 6-bit number of rotating registers (scaled by 8) */ + IA64_OPND_IMM8, /* signed 8-bit immediate (bits 13-19 & 36) */ + IA64_OPND_IMM8U4, /* cmp4*u signed 8-bit immediate (bits 13-19 & 36) */ + IA64_OPND_IMM8M1, /* signed 8-bit immediate -1 (bits 13-19 & 36) */ + IA64_OPND_IMM8M1U4, /* cmp4*u signed 8-bit immediate -1 (bits 13-19 & 36)*/ + IA64_OPND_IMM8M1U8, /* cmp*u signed 8-bit immediate -1 (bits 13-19 & 36) */ + IA64_OPND_IMMU9, /* unsigned 9-bit immediate (bits 33-34, 20-26) */ + IA64_OPND_IMM9a, /* signed 9-bit immediate (bits 6-12, 27, 36) */ + IA64_OPND_IMM9b, /* signed 9-bit immediate (bits 13-19, 27, 36) */ + IA64_OPND_IMM14, /* signed 14-bit immediate (bits 13-19, 27-32, 36) */ + IA64_OPND_IMM17, /* signed 17-bit immediate (2*bits 6-12, 24-31, 36) */ + IA64_OPND_IMMU21, /* unsigned 21-bit immediate (bits 6-25, 36) */ + IA64_OPND_IMM22, /* signed 22-bit immediate (bits 13-19, 22-36) */ + IA64_OPND_IMMU24, /* unsigned 24-bit immediate (bits 6-26, 31-32, 36) */ + IA64_OPND_IMM44, /* signed 44-bit immediate (2^16*bits 6-32, 36) */ + IA64_OPND_IMMU62, /* unsigned 62-bit immediate */ + IA64_OPND_IMMU64, /* unsigned 64-bit immediate (lotsa bits...) */ + IA64_OPND_INC3, /* signed 3-bit (bits 13-15): +/-1, 4, 8, 16 */ + IA64_OPND_LEN4, /* 4-bit count (bits 27-30 + 1) */ + IA64_OPND_LEN6, /* 6-bit count (bits 27-32 + 1) */ + IA64_OPND_MBTYPE4, /* 4-bit mux type (bits 20-23) */ + IA64_OPND_MHTYPE8, /* 8-bit mux type (bits 20-27) */ + IA64_OPND_POS6, /* 6-bit count (bits 14-19) */ + IA64_OPND_TAG13, /* signed 13-bit tag (ip + 16*bits 6-12, 33-34) */ + IA64_OPND_TAG13b, /* signed 13-bit tag (ip + 16*bits 24-32) */ + IA64_OPND_TGT25, /* signed 25-bit (ip + 16*bits 6-25, 36) */ + IA64_OPND_TGT25b, /* signed 25-bit (ip + 16*bits 6-12, 20-32, 36) */ + IA64_OPND_TGT25c, /* signed 25-bit (ip + 16*bits 13-32, 36) */ + IA64_OPND_TGT64, /* 64-bit (ip + 16*bits 13-32, 36, 2-40(L)) */ + + IA64_OPND_COUNT /* # of operand types (MUST BE LAST!) */ + }; + +enum ia64_dependency_mode +{ + IA64_DV_RAW, + IA64_DV_WAW, + IA64_DV_WAR, +}; + +enum ia64_dependency_semantics +{ + IA64_DVS_NONE, + IA64_DVS_IMPLIED, + IA64_DVS_IMPLIEDF, + IA64_DVS_DATA, + IA64_DVS_INSTR, + IA64_DVS_SPECIFIC, + IA64_DVS_OTHER, +}; + +enum ia64_resource_specifier +{ + IA64_RS_ANY, + IA64_RS_AR_K, + IA64_RS_AR_UNAT, + IA64_RS_AR, /* 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111 */ + IA64_RS_ARb, /* 48-63, 112-127 */ + IA64_RS_BR, + IA64_RS_CFM, + IA64_RS_CPUID, + IA64_RS_CR_IRR, + IA64_RS_CR_LRR, + IA64_RS_CR, /* 3-7,10-15,18,26-63,75-79,82-127 */ + IA64_RS_DBR, + IA64_RS_FR, + IA64_RS_FRb, + IA64_RS_GR0, + IA64_RS_GR, + IA64_RS_IBR, + IA64_RS_INSERVICE, /* CR[EOI] or CR[IVR] */ + IA64_RS_MSR, + IA64_RS_PKR, + IA64_RS_PMC, + IA64_RS_PMD, + IA64_RS_PR, + IA64_RS_PR63, + IA64_RS_RR, + + IA64_RS_ARX, /* ARs not in RS_AR or RS_ARb */ + IA64_RS_CRX, /* CRs not in RS_CR */ + IA64_RS_PSR, /* PSR bits */ + IA64_RS_RSE, /* implementation-specific RSE resources */ + IA64_RS_AR_FPSR, +}; + +enum ia64_rse_resource +{ + IA64_RSE_N_STACKED_PHYS, + IA64_RSE_BOF, + IA64_RSE_STORE_REG, + IA64_RSE_LOAD_REG, + IA64_RSE_BSPLOAD, + IA64_RSE_RNATBITINDEX, + IA64_RSE_CFLE, + IA64_RSE_NDIRTY, +}; + +/* Information about a given resource dependency */ +struct ia64_dependency +{ + /* Name of the resource */ + const char *name; + /* Does this dependency need further specification? */ + enum ia64_resource_specifier specifier; + /* Mode of dependency */ + enum ia64_dependency_mode mode; + /* Dependency semantics */ + enum ia64_dependency_semantics semantics; + /* Register index, if applicable (distinguishes AR, CR, and PSR deps) */ +#define REG_NONE (-1) + int regindex; + /* Special info on semantics */ + const char *info; +}; + +/* Two arrays of indexes into the ia64_dependency table. + chks are dependencies to check for conflicts when an opcode is + encountered; regs are dependencies to register (mark as used) when an + opcode is used. chks correspond to readers (RAW) or writers (WAW or + WAR) of a resource, while regs correspond to writers (RAW or WAW) and + readers (WAR) of a resource. */ +struct ia64_opcode_dependency +{ + int nchks; + const unsigned short *chks; + int nregs; + const unsigned short *regs; +}; + +/* encode/extract the note/index for a dependency */ +#define RDEP(N,X) (((N)<<11)|(X)) +#define NOTE(X) (((X)>>11)&0x1F) +#define DEP(X) ((X)&0x7FF) + +/* A template descriptor describes the execution units that are active + for each of the three slots. It also specifies the location of + instruction group boundaries that may be present between two slots. */ +struct ia64_templ_desc + { + int group_boundary; /* 0=no boundary, 1=between slot 0 & 1, etc. */ + enum ia64_unit exec_unit[3]; + const char *name; + }; + +/* The opcode table is an array of struct ia64_opcode. */ + +struct ia64_opcode + { + /* The opcode name. */ + const char *name; + + /* The type of the instruction: */ + enum ia64_insn_type type; + + /* Number of output operands: */ + int num_outputs; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + ia64_insn opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + ia64_insn mask; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + enum ia64_opnd operands[5]; + + /* One bit flags for the opcode. These are primarily used to + indicate specific processors and environments support the + instructions. The defined values are listed below. */ + unsigned int flags; + + /* Used by ia64_find_next_opcode (). */ + short ent_index; + + /* Opcode dependencies. */ + const struct ia64_opcode_dependency *dependencies; + }; + +/* Values defined for the flags field of a struct ia64_opcode. */ + +#define IA64_OPCODE_FIRST (1<<0) /* must be first in an insn group */ +#define IA64_OPCODE_X_IN_MLX (1<<1) /* insn is allowed in X slot of MLX */ +#define IA64_OPCODE_LAST (1<<2) /* must be last in an insn group */ +#define IA64_OPCODE_PRIV (1<<3) /* privileged instruct */ +#define IA64_OPCODE_SLOT2 (1<<4) /* insn allowed in slot 2 only */ +#define IA64_OPCODE_NO_PRED (1<<5) /* insn cannot be predicated */ +#define IA64_OPCODE_PSEUDO (1<<6) /* insn is a pseudo-op */ +#define IA64_OPCODE_F2_EQ_F3 (1<<7) /* constraint: F2 == F3 */ +#define IA64_OPCODE_LEN_EQ_64MCNT (1<<8) /* constraint: LEN == 64-CNT */ +#define IA64_OPCODE_MOD_RRBS (1<<9) /* modifies all rrbs in CFM */ + +/* A macro to extract the major opcode from an instruction. */ +#define IA64_OP(i) (((i) >> 37) & 0xf) + +enum ia64_operand_class + { + IA64_OPND_CLASS_CST, /* constant */ + IA64_OPND_CLASS_REG, /* register */ + IA64_OPND_CLASS_IND, /* indirect register */ + IA64_OPND_CLASS_ABS, /* absolute value */ + IA64_OPND_CLASS_REL, /* IP-relative value */ + }; + +/* The operands table is an array of struct ia64_operand. */ + +struct ia64_operand +{ + enum ia64_operand_class class; + + /* Set VALUE as the operand bits for the operand of type SELF in the + instruction pointed to by CODE. If an error occurs, *CODE is not + modified and the returned string describes the cause of the + error. If no error occurs, NULL is returned. */ + const char *(*insert) (const struct ia64_operand *self, ia64_insn value, + ia64_insn *code); + + /* Extract the operand bits for an operand of type SELF from + instruction CODE store them in *VALUE. If an error occurs, the + cause of the error is described by the string returned. If no + error occurs, NULL is returned. */ + const char *(*extract) (const struct ia64_operand *self, ia64_insn code, + ia64_insn *value); + + /* A string whose meaning depends on the operand class. */ + + const char *str; + + struct bit_field + { + /* The number of bits in the operand. */ + int bits; + + /* How far the operand is left shifted in the instruction. */ + int shift; + } + field[4]; /* no operand has more than this many bit-fields */ + + unsigned int flags; + + const char *desc; /* brief description */ +}; + +/* Values defined for the flags field of a struct ia64_operand. */ + +/* Disassemble as signed decimal (instead of hex): */ +#define IA64_OPND_FLAG_DECIMAL_SIGNED (1<<0) +/* Disassemble as unsigned decimal (instead of hex): */ +#define IA64_OPND_FLAG_DECIMAL_UNSIGNED (1<<1) + +extern const struct ia64_templ_desc ia64_templ_desc[16]; + +/* The tables are sorted by major opcode number and are otherwise in + the order in which the disassembler should consider instructions. */ +extern struct ia64_opcode ia64_opcodes_a[]; +extern struct ia64_opcode ia64_opcodes_i[]; +extern struct ia64_opcode ia64_opcodes_m[]; +extern struct ia64_opcode ia64_opcodes_b[]; +extern struct ia64_opcode ia64_opcodes_f[]; +extern struct ia64_opcode ia64_opcodes_d[]; + + +extern struct ia64_opcode *ia64_find_opcode (const char *name); +extern struct ia64_opcode *ia64_find_next_opcode (struct ia64_opcode *ent); + +extern struct ia64_opcode *ia64_dis_opcode (ia64_insn insn, + enum ia64_insn_type type); + +extern void ia64_free_opcode (struct ia64_opcode *ent); +extern const struct ia64_dependency *ia64_find_dependency (int index); + +/* To avoid circular library dependencies, this array is implemented + in bfd/cpu-ia64-opc.c: */ +extern const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT]; + +#endif /* opcode_ia64_h */ diff -Nur linux-2.4.19/arch/ia64/kdb/kdba_bp.c linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_bp.c --- linux-2.4.19/arch/ia64/kdb/kdba_bp.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_bp.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,727 @@ +/* + * Kernel Debugger Architecture Dependent Breakpoint Handling + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +static char *kdba_rwtypes[] = { "Instruction(Register)", "Data Write", + "I/O", "Data Access"}; + +/* + * Table describing processor architecture hardware + * breakpoint registers. + */ + +kdbhard_bp_t kdb_hardbreaks[KDB_MAXHARDBPT]; + +/* + * kdba_db_trap + * + * Perform breakpoint processing upon entry to the + * processor debugger fault. Determine and print + * the active breakpoint. + * + * Parameters: + * regs Exception frame containing machine register state + * error Error number passed to kdb. + * Outputs: + * None. + * Returns: + * KDB_DB_BPT Standard instruction or data breakpoint encountered + * KDB_DB_SS Single Step fault ('ss' command or end of 'ssb' command) + * KDB_DB_SSB Single Step fault, caller should continue ('ssb' command) + * KDB_DB_SSBPT Single step over breakpoint + * KDB_DB_NOBPT No existing kdb breakpoint matches this debug exception + * Locking: + * None. + * Remarks: + * Yup, there be goto's here. + * + * If multiple processors receive debug exceptions simultaneously, + * one may be waiting at the kdb fence in kdb() while the user + * issues a 'bc' command to clear the breakpoint the processor + * which is waiting has already encountered. If this is the case, + * the debug registers will no longer match any entry in the + * breakpoint table, and we'll return the value KDB_DB_NOBPT. + * This can cause a panic in die_if_kernel(). It is safer to + * disable the breakpoint (bd), go until all processors are past + * the breakpoint then clear the breakpoint (bc). This code + * recognises a breakpoint even when disabled but not when it has + * been cleared. + * + * WARNING: This routine clears the debug state. It should be called + * once per debug and the result cached. + */ + +kdb_dbtrap_t +kdba_db_trap(struct pt_regs *regs, int error) +{ + int i; + kdb_dbtrap_t rv = KDB_DB_BPT; + kdb_bp_t *bp; + + if (KDB_NULL_REGS(regs)) + return KDB_DB_NOBPT; + + if (KDB_DEBUG(BP)) + kdb_printf("kdba_db_trap: error %d\n", error); + + if (error == 36) { + /* Single step */ + if (KDB_STATE(SSBPT)) { + if (KDB_DEBUG(BP)) + kdb_printf("ssbpt\n"); + KDB_STATE_CLEAR(SSBPT); + for(i=0,bp=kdb_breakpoints; + i < KDB_MAXBPT; + i++, bp++) { + if (KDB_DEBUG(BP)) + kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n", + bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu); + if (!bp->bp_enabled) + continue; + if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) + continue; + if (KDB_DEBUG(BP)) + kdb_printf("bp for this cpu\n"); + if (bp->bp_delayed) { + bp->bp_delayed = 0; + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp\n"); + kdba_installbp(regs, bp); + if (!KDB_STATE(DOING_SS)) { + kdba_clearsinglestep(regs); + return(KDB_DB_SSBPT); + } + break; + } + } + if (i == KDB_MAXBPT) { + kdb_printf("kdb: Unable to find delayed breakpoint\n"); + } + if (!KDB_STATE(DOING_SS)) { + kdba_clearsinglestep(regs); + return(KDB_DB_NOBPT); + } + /* FALLTHROUGH */ + } + + /* + * KDB_STATE_DOING_SS is set when the kernel debugger is using + * the processor trap flag to single-step a processor. If a + * single step trap occurs and this flag is clear, the SS trap + * will be ignored by KDB and the kernel will be allowed to deal + * with it as necessary (e.g. for ptrace). + */ + if (!KDB_STATE(DOING_SS)) + return(KDB_DB_NOBPT); + + /* single step */ + rv = KDB_DB_SS; /* Indicate single step */ + if (KDB_STATE(DOING_SSB)) /* No ia64 ssb support yet */ + KDB_STATE_CLEAR(DOING_SSB); /* No ia64 ssb support yet */ + if (KDB_STATE(DOING_SSB)) { + /* No IA64 ssb support yet */ + } else { + /* + * Print current insn + */ + kdb_machreg_t pc = regs->cr_iip + ia64_psr(regs)->ri * 6; + kdb_printf("SS trap at "); + kdb_symbol_print(pc, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE); + kdb_id1(pc); + KDB_STATE_CLEAR(DOING_SS); + } + + if (rv != KDB_DB_SSB) + kdba_clearsinglestep(regs); + } + + return(rv); +} + +/* + * kdba_bp_trap + * + * Perform breakpoint processing upon entry to the + * processor breakpoint instruction fault. Determine and print + * the active breakpoint. + * + * Parameters: + * regs Exception frame containing machine register state + * error Error number passed to kdb. + * Outputs: + * None. + * Returns: + * 0 Standard instruction or data breakpoint encountered + * 1 Single Step fault ('ss' command) + * 2 Single Step fault, caller should continue ('ssb' command) + * 3 No existing kdb breakpoint matches this debug exception + * Locking: + * None. + * Remarks: + * + * If multiple processors receive debug exceptions simultaneously, + * one may be waiting at the kdb fence in kdb() while the user + * issues a 'bc' command to clear the breakpoint the processor which + * is waiting has already encountered. If this is the case, the + * debug registers will no longer match any entry in the breakpoint + * table, and we'll return the value '3'. This can cause a panic + * in die_if_kernel(). It is safer to disable the breakpoint (bd), + * 'go' until all processors are past the breakpoint then clear the + * breakpoint (bc). This code recognises a breakpoint even when + * disabled but not when it has been cleared. + * + * WARNING: This routine resets the ip. It should be called + * once per breakpoint and the result cached. + */ + +kdb_dbtrap_t +kdba_bp_trap(struct pt_regs *regs, int error) +{ + int i; + kdb_dbtrap_t rv; + kdb_bp_t *bp; + + if (KDB_NULL_REGS(regs)) + return KDB_DB_NOBPT; + + /* + * Determine which breakpoint was encountered. + */ + if (KDB_DEBUG(BP)) + kdb_printf("kdba_bp_trap: ip=0x%lx " + "regs=0x%p sp=0x%lx\n", + regs->cr_iip, regs, regs->r12); + + rv = KDB_DB_NOBPT; /* Cause kdb() to return */ + + for(i=0, bp=kdb_breakpoints; ibp_free) + continue; + if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) + continue; + if (bp->bp_addr == regs->cr_iip) { + /* Hit this breakpoint. */ + kdb_printf("Instruction(i) breakpoint #%d at 0x%lx\n", + i, regs->cr_iip); + kdb_id1(regs->cr_iip); + rv = KDB_DB_BPT; + bp->bp_delay = 1; + /* SSBPT is set when the kernel debugger must single + * step a task in order to re-establish an instruction + * breakpoint which uses the instruction replacement + * mechanism. It is cleared by any action that removes + * the need to single-step the breakpoint. + */ + KDB_STATE_SET(SSBPT); + break; + } + } + + return rv; +} + +/* + * kdba_handle_bp + * + * Handle an instruction-breakpoint trap. Called when re-installing + * an enabled breakpoint which has has the bp_delay bit set. + * + * Parameters: + * Returns: + * Locking: + * Remarks: + * + * Ok, we really need to: + * 1) Restore the original instruction byte(s) + * 2) Single Step + * 3) Restore breakpoint instruction + * 4) Continue. + * + * + */ + +static void +kdba_handle_bp(struct pt_regs *regs, kdb_bp_t *bp) +{ + if (KDB_NULL_REGS(regs)) + return; + + if (KDB_DEBUG(BP)) + kdb_printf("regs->cr_iip = 0x%lx\n", regs->cr_iip); + + /* + * Setup single step + */ + kdba_setsinglestep(regs); + + /* + * Reset delay attribute + */ + bp->bp_delay = 0; + bp->bp_delayed = 1; +} + + +/* + * kdba_bptype + * + * Return a string describing type of breakpoint. + * + * Parameters: + * bph Pointer to hardware breakpoint description + * Outputs: + * None. + * Returns: + * Character string. + * Locking: + * None. + * Remarks: + */ + +char * +kdba_bptype(kdbhard_bp_t *bph) +{ + char *mode; + + mode = kdba_rwtypes[bph->bph_mode]; + + return mode; +} + +/* + * kdba_printbpreg + * + * Print register name assigned to breakpoint + * + * Parameters: + * bph Pointer hardware breakpoint structure + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdba_printbpreg(kdbhard_bp_t *bph) +{ + kdb_printf(" in dr%ld", bph->bph_reg); +} + +/* + * kdba_printbp + * + * Print string describing hardware breakpoint. + * + * Parameters: + * bph Pointer to hardware breakpoint description + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdba_printbp(kdb_bp_t *bp) +{ + kdb_printf("\n is enabled"); + if (bp->bp_hardtype) { + kdba_printbpreg(bp->bp_hard); + if (bp->bp_hard->bph_mode != 0) { + kdb_printf(" for %d bytes", + bp->bp_hard->bph_length+1); + } + } +} + +/* + * kdba_parsebp + * + * Parse architecture dependent portion of the + * breakpoint command. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + * for IA64 architure, data access, data write and + * I/O breakpoints are supported in addition to instruction + * breakpoints. + * + * {datar|dataw|io|inst} [length] + */ + +int +kdba_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp) +{ + int nextarg = *nextargp; + int diag; + kdbhard_bp_t *bph = &bp->bp_template; + + bph->bph_mode = 0; /* Default to instruction breakpoint */ + bph->bph_length = 0; /* Length must be zero for insn bp */ + if ((argc + 1) != nextarg) { + if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) { + bph->bph_mode = 3; + } else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) { + bph->bph_mode = 1; + } else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) { + bph->bph_mode = 2; + } else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0) { + bph->bph_mode = 0; + } else { + return KDB_ARGCOUNT; + } + + bph->bph_length = 3; /* Default to 4 byte */ + + nextarg++; + + if ((argc + 1) != nextarg) { + unsigned long len; + + diag = kdbgetularg((char *)argv[nextarg], + &len); + if (diag) + return diag; + + + if ((len > 4) || (len == 3)) + return KDB_BADLENGTH; + + bph->bph_length = len; + bph->bph_length--; /* Normalize for debug register */ + nextarg++; + } + + if ((argc + 1) != nextarg) + return KDB_ARGCOUNT; + + /* + * Indicate to architecture independent level that + * a hardware register assignment is required to enable + * this breakpoint. + */ + + bph->bph_free = 0; + } else { + if (KDB_DEBUG(BP)) + kdb_printf("kdba_bp: no args, forcehw is %d\n", bp->bp_forcehw); + if (bp->bp_forcehw) { + /* + * We are forced to use a hardware register for this + * breakpoint because either the bph or bpha + * commands were used to establish this breakpoint. + */ + bph->bph_free = 0; + } else { + /* + * Indicate to architecture dependent level that + * the instruction replacement breakpoint technique + * should be used for this breakpoint. + */ + bph->bph_free = 1; + bp->bp_adjust = 0; /* software, break is fault, not trap */ + } + } + + if (bph->bph_mode == 0 && kdba_verify_rw(bp->bp_addr, bph->bph_length+1)) { + kdb_printf("Invalid address for breakpoint, ignoring bp command\n"); + return KDB_BADADDR; + } + + *nextargp = nextarg; + if (!bph->bph_free) { + kdb_printf("kdba_parsebp hardware breakpoints are not supported yet\n"); + return KDB_NOTIMP; + } + return 0; +} + +/* + * kdba_allocbp + * + * Associate a hardware register with a breakpoint. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * A pointer to the allocated register kdbhard_bp_t structure for + * success, Null and a non-zero diagnostic for failure. + * Locking: + * None. + * Remarks: + */ + +kdbhard_bp_t * +kdba_allocbp(kdbhard_bp_t *bph, int *diagp) +{ + int i; + kdbhard_bp_t *newbph; + + for(i=0,newbph=kdb_hardbreaks; i < KDB_MAXHARDBPT; i++, newbph++) { + if (newbph->bph_free) { + break; + } + } + + if (i == KDB_MAXHARDBPT) { + *diagp = KDB_TOOMANYDBREGS; + return NULL; + } + + *diagp = 0; + + /* + * Copy data from template. Can't just copy the entire template + * here because the register number in kdb_hardbreaks must be + * preserved. + */ + newbph->bph_data = bph->bph_data; + newbph->bph_write = bph->bph_write; + newbph->bph_mode = bph->bph_mode; + newbph->bph_length = bph->bph_length; + + /* + * Mark entry allocated. + */ + newbph->bph_free = 0; + + return newbph; +} + +/* + * kdba_freebp + * + * Deallocate a hardware breakpoint + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + */ + +void +kdba_freebp(kdbhard_bp_t *bph) +{ + bph->bph_free = 1; +} + +/* + * kdba_initbp + * + * Initialize the breakpoint table for the hardware breakpoint + * register. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + * + * There is one entry per register. On the ia64 architecture + * all the registers are interchangeable, so no special allocation + * criteria are required. + */ + +void +kdba_initbp(void) +{ + int i; + kdbhard_bp_t *bph; + + /* + * Clear the hardware breakpoint table + */ + + memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks)); + + for(i=0,bph=kdb_hardbreaks; ibph_reg = i; + bph->bph_free = 1; + } +} + +/* + * kdba_installbp + * + * Install a breakpoint + * + * Parameters: + * regs Exception frame + * bp Breakpoint structure for the breakpoint to be installed + * Outputs: + * None. + * Returns: + * 0 if breakpoint set, otherwise error. + * Locking: + * None. + * Remarks: + * For hardware breakpoints, a debug register is allocated + * and assigned to the breakpoint. If no debug register is + * available, a warning message is printed and the breakpoint + * is disabled. + * + * For instruction replacement breakpoints, we must single-step + * over the replaced instruction at this point so we can re-install + * the breakpoint instruction after the single-step. SSBPT is set + * when the breakpoint is initially hit and is cleared by any action + * that removes the need for single-step over the breakpoint. + */ + +int +kdba_installbp(struct pt_regs *regs, kdb_bp_t *bp) +{ + /* + * Install the breakpoint, if it is not already installed. + */ + + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_installbp bp_installed %d\n", bp->bp_installed); + } + if (!KDB_STATE(SSBPT)) + bp->bp_delay = 0; + if (!bp->bp_installed) { + if (bp->bp_hardtype) { + kdba_installdbreg(bp); + bp->bp_installed = 1; + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt0 "\n", + bp->bp_hard->bph_reg, bp->bp_addr); + } + } else if (bp->bp_delay) { + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp delayed bp\n"); + kdba_handle_bp(regs, bp); + } else { + /* Software breakpoints always use slot 0 in the 128 bit + * bundle. The template type does not matter, slot 0 + * can only be M or B and the encodings for break.m and + * break.b are the same. + */ + unsigned long break_inst; + if (kdb_getarea_size(bp->bp_inst.inst, bp->bp_addr, sizeof(bp->bp_inst.inst))) { + kdb_printf("kdba_installbp failed to read software breakpoint at 0x%lx\n", bp->bp_addr); + return(1); + } + break_inst = (bp->bp_inst.inst[0] & ~INST_SLOT0_MASK) | BREAK_INSTR; + if (kdb_putarea_size(bp->bp_addr, &break_inst, sizeof(break_inst))) { + kdb_printf("kdba_installbp failed to set software breakpoint at 0x%lx\n", bp->bp_addr); + return(1); + } + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp instruction 0x%lx at " kdb_bfd_vma_fmt0 "\n", + BREAK_INSTR, bp->bp_addr); + bp->bp_installed = 1; + flush_icache_range(bp->bp_addr, bp->bp_addr+16); + } + } + return(0); +} + +/* + * kdba_removebp + * + * Make a breakpoint ineffective. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * 0 if breakpoint removed, otherwise error. + * Locking: + * None. + * Remarks: + */ + +int +kdba_removebp(kdb_bp_t *bp) +{ + /* + * For hardware breakpoints, remove it from the active register, + * for software breakpoints, restore the instruction stream. + */ + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed); + } + if (bp->bp_installed) { + if (bp->bp_hardtype) { + if (KDB_DEBUG(BP)) { + kdb_printf("kdb: removing hardware reg %ld at " kdb_bfd_vma_fmt0 "\n", + bp->bp_hard->bph_reg, bp->bp_addr); + } + kdba_removedbreg(bp); + } else { + if (KDB_DEBUG(BP)) + kdb_printf("kdb: restoring instruction 0x%016lx%016lx at " kdb_bfd_vma_fmt0 "\n", + bp->bp_inst.inst[0], bp->bp_inst.inst[1], bp->bp_addr); + if (kdba_putarea_size(bp->bp_addr, bp->bp_inst.inst, sizeof(bp->bp_inst.inst))) + return(1); + } + bp->bp_installed = 0; + flush_icache_range(bp->bp_addr, bp->bp_addr+16); + } + return(0); +} diff -Nur linux-2.4.19/arch/ia64/kdb/kdba_bt.c linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_bt.c --- linux-2.4.19/arch/ia64/kdb/kdba_bt.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_bt.c Fri Jan 3 13:57:03 2003 @@ -0,0 +1,259 @@ +/* + * Kernel Debugger Architecture Dependent Stack Traceback + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * bt_print_one + * + * Print one back trace entry. + * + * Inputs: + * ip Current program counter. + * symtab Information about symbol that ip falls within. + * ar Activation record for this frame. + * argcount Maximum number of arguments to print. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +static void +bt_print_one(kdb_machreg_t ip, const kdb_ar_t *ar, + const kdb_symtab_t *symtab, int argcount, + struct unw_frame_info *info /* FIXME: should be part of ar for ia64 */) +{ + int btsymarg = 0; /* Convert arguments to symbols */ + int btsp = 0; /* Print stack and backing store pointers */ + int nosect = 0; /* Suppress section data */ + kdb_machreg_t sp, bsp, cfm; /* FIXME: should be part of ar for ia64 */ + + kdbgetintenv("BTSYMARG", &btsymarg); + kdbgetintenv("BTSP", &btsp); + kdbgetintenv("NOSECT", &nosect); + + unw_get_sp(info, &sp); /* FIXME: should be part of ar for ia64 */ + unw_get_bsp(info, &bsp); /* FIXME: should be part of ar for ia64 */ + unw_get_cfm(info, &cfm); /* FIXME: info/cfm should be part of ar for ia64 */ + kdb_symbol_print(ip, symtab, KDB_SP_VALUE|KDB_SP_NEWLINE); + /* FIXME: number of args should be set in prologue code */ + ((kdb_ar_t *)ar)->args = (cfm >> 7) & 0x7f; /* sol */ + if (!ar->args) + ((kdb_ar_t *)ar)->args = cfm & 0x7f; /* no in/local, use sof instead */ + if (argcount && ar->args) { + int i, argc = ar->args; + + kdb_printf(" args ("); + if (argc > argcount) + argc = argcount; + + for(i = 0; i < argc; i++){ + /* FIXME: prologue code should extract arguments */ + kdb_machreg_t arg; + char nat; + if (unw_access_gr(info, i+32, &arg, &nat, 0)) + arg = 0; + + if (i) + kdb_printf(", "); + kdb_printf("0x%lx", arg); + } + kdb_printf(")\n"); + if (btsymarg) { + kdb_symtab_t arg_symtab; + kdb_machreg_t arg; + for(i = 0; i < argc; i++){ + /* FIXME: prologue code should extract arguments */ + char nat; + if (unw_access_gr(info, i+32, &arg, &nat, 0)) + arg = 0; + if (kdbnearsym(arg, &arg_symtab)) { + kdb_printf(" arg %d ", i); + kdb_symbol_print(arg, &arg_symtab, KDB_SP_DEFAULT|KDB_SP_NEWLINE); + } + } + } + } + if (symtab->sym_name) { + if (!nosect) { + kdb_printf(" %s %s 0x%lx 0x%lx 0x%lx\n", + symtab->mod_name, + symtab->sec_name, + symtab->sec_start, + symtab->sym_start, + symtab->sym_end); + } + } + if (btsp) + kdb_printf(" sp 0x%016lx bsp 0x%016lx cfm 0x%016lx\n", sp, bsp, cfm); +} + +/* + * kdba_bt_stack + * + * This function implements the 'bt' command. Print a stack + * traceback. + * + * bt (stack address is not supported on IA64) + * btp (Kernel stack for ) + * + * Inputs: + * regs registers at time kdb was entered. + * addr Pointer to Address provided to 'bt' command, if any. + * argcount + * p Pointer to task for 'btp' command. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * mds comes in handy when examining the stack to do a manual + * traceback. + */ + +int +kdba_bt_stack(struct pt_regs *regs, kdb_machreg_t *addr, int argcount, + struct task_struct *p) +{ + kdb_symtab_t symtab; + kdb_ar_t ar; + struct unw_frame_info info; /* FIXME: should be part of ar */ + struct switch_stack *sw; /* FIXME: should be part of ar */ + + if (addr) { + kdb_printf("bt
is unsupported for IA-64\n"); + return 0; + } + + /* FIXME: All the arch specific code should be in activation records, not here */ + memset(&ar, 0, sizeof(ar)); + + /* + * Upon entering kdb_main_loop, the stack frame looks like this: + * + * +---------------------+ + * | struct pt_regs | + * +---------------------+ + * | | + * | kernel stack | + * | | + * +=====================+ <--- top of stack upon entering kdb + * | struct pt_regs | + * +---------------------+ + * | | + * | kdb stack | + * | | + * +---------------------+ + * | struct switch_stack | + * +=====================+ <--- kdb_sw[cpu] from do_kdba_main_loop + * + * When looking at another process, we do not have the address of the + * current pt_regs, it is NULL. + */ + + sw = NULL; + if (p == current) { + sw = kdb_sw[smp_processor_id()]; + } +#ifdef CONFIG_SMP + else if (task_has_cpu(p)) { + sw = kdb_sw[p->cpu]; + } +#endif + else { + /* Not running, assume blocked */ + sw = (struct switch_stack *) (p->thread.ksp + 16); + } + if (!sw) { + kdb_printf("Process does not have a switch_stack, cannot backtrace\n"); + return 0; + } + + unw_init_frame_info(&info, p, sw); /* FIXME: should be using activation records */ + + /* If we have the address of pt_regs, suppress backtrace on the frames below + * pt_regs. No point in displaying kdb itself. + */ + if (regs) { + kdb_machreg_t sp; /* FIXME: should be part of ar for ia64 */ + if (user_mode(regs)) { + kdb_printf("Process was interrupted in user mode, no backtrace available\n"); + return 0; + } + do { + unw_get_sp(&info, &sp); + if (sp >= (kdb_machreg_t)regs) + break; + } while (unw_unwind(&info) >= 0); /* FIXME: should be using activation records */ + } + + do { + kdb_machreg_t ip; + + unw_get_ip(&info, &ip); /* FIXME: should be using activation records */ + if (ip == 0) + break; + + kdbnearsym(ip, &symtab); + if (!symtab.sym_name) { + kdb_printf("0x%0*lx - No name. May be an area that has no unwind data\n", + (int)(2*sizeof(ip)), ip); + return 0; + } + bt_print_one(ip, &ar, &symtab, argcount, &info); + } while (unw_unwind(&info) >= 0); /* FIXME: should be using activation records */ + + return 0; +} + +int +kdba_bt_process(struct task_struct *p, int argcount) +{ + return kdba_bt_stack(NULL, NULL, argcount, p); +} diff -Nur linux-2.4.19/arch/ia64/kdb/kdba_id.c linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_id.c --- linux-2.4.19/arch/ia64/kdb/kdba_id.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_id.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,300 @@ +/* + * Kernel Debugger Architecture Dependent Instruction Disassembly + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 Stephane Eranian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include + +#define KDBA_PRINTBUF_LEN 64 /* buffer len to print a single instr */ +#define KDBA_READBUFFER_LEN 256 /* buffer for BFD disassembler */ + +#define BUNDLE_MULTIPLIER 3 /* how many instr/bundle */ +#define BUNDLE_SIZE 16 /* how many bytes/bundle */ +#define KDBA_DEFAULT_IDLEN 3 /* default number of bundles to disassemble */ + +/* + * kdba_dis_getsym + * + * Get a symbol for the disassembler. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * Not used for kdb. + */ + +/* ARGSUSED */ +static int +kdba_dis_getsym(bfd_vma addr, disassemble_info *dip) +{ + + return 0; +} + +/* + * kdba_printaddress + * + * Print (symbolically) an address. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * flag True if a ":" sequence should follow the address + * Returns: + * 0 + * Locking: + * Remarks: + * + */ + +/* ARGSUSED */ +void +kdba_printaddress(kdb_machreg_t addr, disassemble_info *dip, int flag) +{ + kdb_symtab_t symtab; + int spaces = 5; + unsigned int offset; + int slot; + + /* Some code prints slot number, some prints "byte" offset + * from start of bundle. Standardise on "byte" offset. + */ + slot = addr & 0x0f; + if (slot < 3) + slot *= 6; + addr = (addr & ~0x0f) + slot; + + /* + * Print a symbol name or address as necessary. + */ + dip->fprintf_func(dip->stream, "0x%0*lx ", 2*sizeof(addr), addr); + kdbnearsym(addr, &symtab); + if (symtab.sym_name) { + /* Do not use kdb_symbol_print here, it always does + * kdb_printf but we want dip->fprintf_func. + */ + dip->fprintf_func(dip->stream, "%s", symtab.sym_name); + if ((offset = addr - symtab.sym_start) == 0) { + spaces += 4; + } + else { + unsigned int o = offset; + while (o >>= 4) + --spaces; + dip->fprintf_func(dip->stream, "+0x%x", offset); + } + } + + if (flag) { + if (spaces < 1) { + spaces = 1; + } + dip->fprintf_func(dip->stream, ":%*s", spaces, " "); + } +} + +/* + * kdba_dis_printaddr + * + * Print (symbolically) an address. Called by GNU disassembly + * code via disassemble_info structure. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * This function will never append ":" to the printed + * symbolic address. + */ + +static void +kdba_dis_printaddr(bfd_vma addr, disassemble_info *dip) +{ + kdba_printaddress(addr, dip, 0); +} + +/* + * kdba_dis_getmem + * + * Fetch 'length' bytes from 'addr' into 'buf'. + * + * Parameters: + * addr Address for which to get symbol + * buf Address of buffer to fill with bytes from 'addr' + * length Number of bytes to fetch + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * + */ + +/* ARGSUSED */ +static int +kdba_dis_getmem(bfd_vma addr, bfd_byte *buf, unsigned int length, disassemble_info *dip) +{ + return kdb_getarea_size(buf, addr, length); +} + +/* + * kdba_id_parsemode + * + * Parse IDMODE environment variable string and + * set appropriate value into "disassemble_info" structure. + * + * Parameters: + * mode Mode string + * dip Disassemble_info structure pointer + * Returns: + * Locking: + * Remarks: + * No mode supported yet. + */ + +int +kdba_id_parsemode(const char *mode, disassemble_info *dip) +{ + if (mode && strcmp(mode, "ia64")) + return KDB_BADMODE; + return 0; +} + +/* + * kdba_check_pc + * + * Check that the pc is satisfactory. + * + * Parameters: + * pc Program Counter Value. + * Returns: + * None + * Locking: + * None. + * Remarks: + * Can change pc. + */ + +void +kdba_check_pc(kdb_machreg_t *pc) +{ + (*pc) &= ~0xf; /* pc must be 16 byte aligned */ +} + +/* + * kdba_id_printinsn + * + * Format and print a single bundle at 'pc'. Return the + * length of the bundle. + * + * Parameters: + * pc Program Counter Value. + * dip Disassemble_info structure pointer + * Returns: + * Length of instruction, -1 for error. + * Locking: + * None. + * Remarks: + * None. + */ + +int +kdba_id_printinsn(kdb_machreg_t pc, disassemble_info *dip) +{ + int ret; + int byte=0; + int off = 0; + + dip->fprintf_func = dip->fprintf_dummy; + off = pc & 0xf; + kdba_check_pc(&pc); + while (byte < 16) { + if (byte == off) + dip->fprintf_func = kdb_dis_fprintf; + else + dip->fprintf_func = dip->fprintf_dummy; + kdba_dis_printaddr(pc+byte, dip); + ret = print_insn_ia64((kdb_machreg_t)(pc+byte), dip); + dip->fprintf_func(dip->stream, "\n"); + if (ret < 0) + break; + byte += ret; + } + return(byte); +} + +/* + * kdba_id_init + * + * Initialize the architecture dependent elements of + * the disassembly information structure + * for the GNU disassembler. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void __init +kdba_id_init(disassemble_info *dip) +{ + dip->read_memory_func = kdba_dis_getmem; + dip->print_address_func = kdba_dis_printaddr; + dip->symbol_at_address_func = kdba_dis_getsym; + + dip->flavour = bfd_target_elf_flavour; + dip->arch = bfd_arch_ia64; + dip->endian = BFD_ENDIAN_LITTLE; + + dip->display_endian = BFD_ENDIAN_LITTLE; +} diff -Nur linux-2.4.19/arch/ia64/kdb/kdba_io.c linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_io.c --- linux-2.4.19/arch/ia64/kdb/kdba_io.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_io.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,530 @@ +/* + * Kernel Debugger Architecture Dependent Console I/O handler + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef BRINGUP +#define KDB_BLINK_LED 1 +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) && defined(BRINGUP) +#warning KDB assumes CONFIG_SERIAL_CONSOLE *or* BRINGUP, not both +#undef CONFIG_SERIAL_CONSOLE +#endif + +#ifdef CONFIG_KDB_USB +struct kdb_usb_exchange kdb_usb_infos = { NULL, NULL, NULL, NULL, NULL, 0}; + +static unsigned char kdb_usb_keycode[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140 +}; + +/* get_usb_char + * This function drives the UHCI controller, + * fetch the USB scancode and decode it + */ +static int get_usb_char(void) +{ + static int usb_lock; + unsigned char keycode, spec; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + /* Is USB initialized ? */ + if(!kdb_usb_infos.poll_func) + return -1; + + /* Transfer char if they are present */ + (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (urb_t *)kdb_usb_infos.urb); + + spec = kdb_usb_infos.buffer[0]; + keycode = kdb_usb_infos.buffer[2]; + kdb_usb_infos.buffer[0] = (char)0; + kdb_usb_infos.buffer[2] = (char)0; + + if(kdb_usb_infos.buffer[3]) + return -1; + + /* A normal key is pressed, decode it */ + if(keycode) + keycode = kdb_usb_keycode[keycode]; + + /* 2 Keys pressed at one time ? */ + if (spec && keycode) { + switch(spec) + { + case 0x2: + case 0x20: /* Shift */ + return shift_map[keycode]; + case 0x1: + case 0x10: /* Ctrl */ + return ctrl_map[keycode]; + case 0x4: + case 0x40: /* Alt */ + break; + } + } + else { + if(keycode) { /* If only one key pressed */ + switch(keycode) + { + case 0x1C: /* Enter */ + return 13; + + case 0x3A: /* Capslock */ + usb_lock ? (usb_lock = 0) : (usb_lock = 1); + break; + case 0x0E: /* Backspace */ + return 8; + case 0x0F: /* TAB */ + case 0x77: /* Pause */ + break ; + default: + if(!usb_lock) { + return plain_map[keycode]; + } + else { + return shift_map[keycode]; + } + } + } + } + return -1; +} +#endif + +struct kdb_serial kdb_serial; + +/* + * This module contains code to read characters from the keyboard or a serial + * port. + * + * It is used by the kernel debugger, and is polled, not interrupt driven. + * + */ + +#ifdef KDB_BLINK_LED +/* + * send: Send a byte to the keyboard controller. Used primarily to + * alter LED settings. + */ + +static void +kdb_kbdsend(unsigned char byte) +{ + while (inb(KBD_STATUS_REG) & KBD_STAT_IBF) + ; + outb(byte, KBD_DATA_REG); +} + +static void +kdb_toggleled(int led) +{ + static int leds; + + leds ^= led; + + kdb_kbdsend(KBD_CMD_SET_LEDS); + kdb_kbdsend((unsigned char)leds); +} +#endif /* KDB_BLINK_LED */ + +#if defined(CONFIG_SERIAL_CONSOLE) + +static inline unsigned int +serial_inp(struct kdb_serial *kdb_serial, unsigned long offset) +{ + offset <<= kdb_serial->ioreg_shift; + + switch (kdb_serial->io_type) { + case SERIAL_IO_MEM: + return readb(kdb_serial->iobase + offset); + break; + default: + return inb(kdb_serial->iobase + offset); + break; + } +} + +/* Check if there is a byte ready at the serial port */ +static int get_serial_char(void) +{ + unsigned char ch; + + if (kdb_serial.iobase == 0) + return -1; + + if (serial_inp(&kdb_serial, UART_LSR) & UART_LSR_DR) { + ch = serial_inp(&kdb_serial, UART_RX); + if (ch == 0x7f) + ch = 8; + return ch; + } + return -1; +} +#endif /* CONFIG_SERIAL_CONSOLE */ + +#if defined(CONFIG_VT) + +static int kbd_exists = -1; + +/* + * Check if the keyboard controller has a keypress for us. + * Some parts (Enter Release, LED change) are still blocking polled here, + * but hopefully they are all short. + */ +static int get_kbd_char(void) +{ + int scancode, scanstatus; + static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ + static int shift_key; /* Shift next keypress */ + static int ctrl_key; + u_short keychar; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + if (kbd_exists <= 0) { + if (kbd_exists == 0) + return -1; + + if (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff) { + kbd_exists = 0; + return -1; + } + kbd_exists = 1; + } + + if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + return -1; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + /* + * Ignore mouse events. + */ + if (scanstatus & KBD_STAT_MOUSE_OBF) + return -1; + + /* + * Ignore release, trigger on make + * (except for shift keys, where we want to + * keep the shift state so long as the key is + * held down). + */ + + if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { + /* + * Next key may use shift table + */ + if ((scancode & 0x80) == 0) { + shift_key=1; + } else { + shift_key=0; + } + return -1; + } + + if ((scancode&0x7f) == 0x1d) { + /* + * Left ctrl key + */ + if ((scancode & 0x80) == 0) { + ctrl_key = 1; + } else { + ctrl_key = 0; + } + return -1; + } + + if ((scancode & 0x80) != 0) + return -1; + + scancode &= 0x7f; + + /* + * Translate scancode + */ + + if (scancode == 0x3a) { + /* + * Toggle caps lock + */ + shift_lock ^= 1; + +#ifdef KDB_BLINK_LED + kdb_toggleled(0x4); +#endif + return -1; + } + + if (scancode == 0x0e) { + /* + * Backspace + */ + return 8; + } + + /* Special Key */ + switch (scancode) { + case 0xF: /* Tab */ + return 9; + case 0x53: /* Del */ + return 4; + case 0x47: /* Home */ + return 1; + case 0x4F: /* End */ + return 5; + case 0x4B: /* Left */ + return 2; + case 0x48: /* Up */ + return 16; + case 0x50: /* Down */ + return 14; + case 0x4D: /* Right */ + return 6; + } + + if (scancode == 0xe0) { + return -1; + } + + /* + * For Japanese 86/106 keyboards + * See comment in drivers/char/pc_keyb.c. + * - Masahiro Adegawa + */ + if (scancode == 0x73) { + scancode = 0x59; + } else if (scancode == 0x7d) { + scancode = 0x7c; + } + + if (!shift_lock && !shift_key && !ctrl_key) { + keychar = plain_map[scancode]; + } else if (shift_lock || shift_key) { + keychar = shift_map[scancode]; + } else if (ctrl_key) { + keychar = ctrl_map[scancode]; + } else { + keychar = 0x0020; + kdb_printf("Unknown state/scancode (%d)\n", scancode); + } + keychar &= 0x0fff; + if (keychar == '\t') + keychar = ' '; + switch (KTYP(keychar)) { + case KT_LETTER: + case KT_LATIN: + if (isprint(keychar)) + break; /* printable characters */ + /* drop through */ + case KT_SPEC: + if (keychar == K_ENTER) + break; + /* drop through */ + default: + return(-1); /* ignore unprintables */ + } + + if ((scancode & 0x7f) == 0x1c) { + /* + * enter key. All done. Absorb the release scancode. + */ + while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + ; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + while (scanstatus & KBD_STAT_MOUSE_OBF) { + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + } + + if (scancode != 0x9c) { + /* + * Wasn't an enter-release, why not? + */ + kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", + scancode, scanstatus); + } + + kdb_printf("\n"); + return 13; + } + + return keychar & 0xff; +} +#endif /* CONFIG_VT */ + +#ifdef BRINGUP +/* + * Code used to directly access real SGI SNIA serial console (won't work with HPSIM) + */ + +extern u64 master_node_bedrock_address; + +/* UART registers on the Bedrock start at 0x80 */ + +extern int l1_serial_in_polled(void); +extern int l1_control_in_polled(int); + +static inline +int serial_inp(int offset) +{ + if ( offset & 0x80 ) { + int counter = 10000; + int value; + while ( counter-- ) { + value = l1_serial_in_polled(); + /* Gobble up the 0's */ + if ( value ) + return(value); + } + return(0); + } + else { + int c; + c = l1_control_in_polled(offset); + return(c); + } +} + + +/* Check if there is a byte ready at the L1 port. kdb_serial is ignored */ +static int snia_get_serial_char(void) +{ + unsigned char ch; + int status; + + if ((status = serial_inp(UART_LSR)) & UART_LSR_DR) { + ch = serial_inp(UART_RX | 0x80); /* bedrock offset */ + if (ch == 0x7f) + ch = 8; + if (ch == '\t') + ch = ' '; + return ch; + } + return -1; +} + +#endif /* BRINGUP */ + +#ifdef KDB_BLINK_LED + +/* Leave numlock alone, setting it messes up laptop keyboards with the keypad + * mapped over normal keys. + */ +int kdba_blink_mask = 0x1 | 0x4; + +#ifdef CONFIG_SMP +#define BOGOMIPS (local_cpu_data->loops_per_jiffy/(500000/HZ)) +#else +#define BOGOMIPS (loops_per_jiffy/(500000/HZ)) +#endif +static int blink_led(void) +{ + static long delay; + + if (kbd_exists == 0) + return -1; + + if (--delay < 0) { + if (BOGOMIPS == 0) /* early kdb */ + delay = 150000000/1000; /* arbitrary bogomips */ + else + delay = 150000000/BOGOMIPS; /* Roughly 1 second when polling */ + kdb_toggleled(kdba_blink_mask); + } + return -1; +} +#endif + +get_char_func poll_funcs[] = { +#if defined(CONFIG_VT) + get_kbd_char, +#endif +#if defined(CONFIG_SERIAL_CONSOLE) + get_serial_char, +#endif +#ifdef BRINGUP + snia_get_serial_char, /* SGI SNIA */ +#endif +#ifdef KDB_BLINK_LED + blink_led, +#endif +#ifdef CONFIG_KDB_USB + get_usb_char, +#endif + NULL +}; + +/* Dummy versions of kdba_local_arch_setup, kdba_local_arch_cleanup. + * FIXME: ia64 with legacy keyboard might need the same code as i386. + */ + +void kdba_local_arch_setup(void) {} +void kdba_local_arch_cleanup(void) {} diff -Nur linux-2.4.19/arch/ia64/kdb/kdba_jmp.S linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_jmp.S --- linux-2.4.19/arch/ia64/kdb/kdba_jmp.S Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_jmp.S Thu Aug 15 20:01:22 2002 @@ -0,0 +1,422 @@ +/* + * Kernel Debugger Architecture Dependent Longjump Support. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* setjmp() and longjmp() assembler support for kdb on ia64. + + This code was copied from glibc CVS as of 2001-06-27 and modified where + necessary to fit the kernel. No glibc lines were changed or deleted, all + adjustments are wrapped in #ifdef __KERNEL__, except for the added + .mem.offset lines, they work in or out of the kenrel. The original code is + in sysdeps/unix/sysv/linux/ia64/{setjmp.S,__longjmp.S}. + + glibc has setjmp (save signals) and _setjmp (do not save signals). Kernel + code does not have signals, only kdba_setjmp_asm() is used. + + Keith Owens 2001-06-27 + */ + +/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The layout of the jmp_buf is as follows. This is subject to change + and user-code should never depend on the particular layout of + jmp_buf! + + + offset: description: + ------- ------------ + 0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS) + 0x008 r1 (gp) + 0x010 caller's unat + 0x018 fpsr + 0x020 r4 + 0x028 r5 + 0x030 r6 + 0x038 r7 + 0x040 rp (b0) + 0x048 b1 + 0x050 b2 + 0x058 b3 + 0x060 b4 + 0x068 b5 + 0x070 ar.pfs + 0x078 ar.lc + 0x080 pr + 0x088 ar.bsp ; unchangeable (see __longjmp.S) + 0x090 ar.unat + 0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat) + 0x0a0 f2 + 0x0b0 f3 + 0x0c0 f4 + 0x0d0 f5 + 0x0e0 f16 + 0x0f0 f17 + 0x100 f18 + 0x110 f19 + 0x120 f20 + 0x130 f21 + 0x130 f22 + 0x140 f23 + 0x150 f24 + 0x160 f25 + 0x170 f26 + 0x180 f27 + 0x190 f28 + 0x1a0 f29 + 0x1b0 f30 + 0x1c0 f31 */ + +#ifndef __KERNEL__ + +#include +#include + + /* The following two entry points are the traditional entry points: */ + +LEAF(setjmp) + alloc r8=ar.pfs,2,0,0,0 + mov in1=1 + br.cond.sptk.many __sigsetjmp +END(setjmp) + +LEAF(_setjmp) + alloc r8=ar.pfs,2,0,0,0 + mov in1=0 + br.cond.sptk.many __sigsetjmp +END(_setjmp) + + /* __sigsetjmp(__jmp_buf buf, int savemask) */ + +ENTRY(__sigsetjmp) + +#else /* __KERNEL __ */ +#include +#define ret br.ret.sptk.few rp +GLOBAL_ENTRY(kdba_setjmp) +#endif /* !__KERNEL__ */ + + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + alloc loc1=ar.pfs,2,2,2,0 + mov r16=ar.unat + ;; + mov r17=ar.fpsr + mov r2=in0 + add r3=8,in0 + ;; +.mem.offset 0,0; + st8.spill.nta [r2]=sp,16 // r12 (sp) +.mem.offset 8,0; + st8.spill.nta [r3]=gp,16 // r1 (gp) + ;; + st8.nta [r2]=r16,16 // save caller's unat + st8.nta [r3]=r17,16 // save fpsr + add r8=0xa0,in0 + ;; +.mem.offset 160,0; + st8.spill.nta [r2]=r4,16 // r4 +.mem.offset 168,0; + st8.spill.nta [r3]=r5,16 // r5 + add r9=0xb0,in0 + ;; + stf.spill.nta [r8]=f2,32 + stf.spill.nta [r9]=f3,32 + mov loc0=rp + .body + ;; + stf.spill.nta [r8]=f4,32 + stf.spill.nta [r9]=f5,32 + mov r17=b1 + ;; + stf.spill.nta [r8]=f16,32 + stf.spill.nta [r9]=f17,32 + mov r18=b2 + ;; + stf.spill.nta [r8]=f18,32 + stf.spill.nta [r9]=f19,32 + mov r19=b3 + ;; + stf.spill.nta [r8]=f20,32 + stf.spill.nta [r9]=f21,32 + mov r20=b4 + ;; + stf.spill.nta [r8]=f22,32 + stf.spill.nta [r9]=f23,32 + mov r21=b5 + ;; + stf.spill.nta [r8]=f24,32 + stf.spill.nta [r9]=f25,32 + mov r22=ar.lc + ;; + stf.spill.nta [r8]=f26,32 + stf.spill.nta [r9]=f27,32 + mov r24=pr + ;; + stf.spill.nta [r8]=f28,32 + stf.spill.nta [r9]=f29,32 + ;; + stf.spill.nta [r8]=f30 + stf.spill.nta [r9]=f31 + +.mem.offset 0,0; + st8.spill.nta [r2]=r6,16 // r6 +.mem.offset 8,0; + st8.spill.nta [r3]=r7,16 // r7 + ;; + mov r23=ar.bsp + mov r25=ar.unat +#ifndef __KERNEL__ + mov out0=in0 +#endif /* !__KERNEL__ */ + + st8.nta [r2]=loc0,16 // b0 + st8.nta [r3]=r17,16 // b1 +#ifndef __KERNEL__ + mov out1=in1 +#endif /* !__KERNEL__ */ + ;; + st8.nta [r2]=r18,16 // b2 + st8.nta [r3]=r19,16 // b3 + ;; + st8.nta [r2]=r20,16 // b4 + st8.nta [r3]=r21,16 // b5 + ;; + st8.nta [r2]=loc1,16 // ar.pfs + st8.nta [r3]=r22,16 // ar.lc + ;; + st8.nta [r2]=r24,16 // pr + st8.nta [r3]=r23,16 // ar.bsp + ;; + st8.nta [r2]=r25 // ar.unat + st8.nta [r3]=in0 // &__jmp_buf +#ifndef __KERNEL__ + br.call.dpnt.few rp=__sigjmp_save +.ret0: // force a new bundle ::q +#endif /* !_KERNEL__ */ + mov r8=0 + mov rp=loc0 + mov ar.pfs=loc1 + ret +#ifndef __KERNEL__ +END(__sigsetjmp) + +weak_extern(_setjmp) +weak_extern(setjmp) + +#else /* __KERNEL__ */ +END(kdba_setjmp) +#endif /* !_KERNEL__ */ + +/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Note that __sigsetjmp() did NOT flush the register stack. Instead, + we do it here since __longjmp() is usually much less frequently + invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp() + didn't (and wouldn't be able to) save ar.rnat either. This is a problem + because if we're not careful, we could end up loading random NaT bits. + There are two cases: + + (i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp) + ar.rnat contains the desired bits---preserve ar.rnat + across loadrs and write to ar.bspstore + + (ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp) + The desired ar.rnat is stored in + ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those + bits into ar.rnat after setting ar.bspstore. */ + +#ifndef __KERNEL__ +#include +#include +#endif /* !__KERNEL__ */ + +# define pPos p6 /* is rotate count positive? */ +# define pNeg p7 /* is rotate count negative? */ + + + /* __longjmp(__jmp_buf buf, int val) */ + +#ifndef __KERNEL__ +LEAF(__longjmp) +#else /* __KERNEL__ */ +GLOBAL_ENTRY(kdba_longjmp) +#endif /* !__KERNEL__ */ + alloc r8=ar.pfs,2,1,0,0 + mov r27=ar.rsc + add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr + ;; + ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr + mov r10=ar.bsp + and r11=~0x3,r27 // clear ar.rsc.mode + ;; + flushrs // flush dirty regs to backing store (must be first in insn grp) + ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp + sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf + ;; + ld8 r25=[r2] // r25 <- jmpbuf.ar_unat + extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f + ;; + cmp.lt pNeg,pPos=r8,r0 + mov r2=in0 + ;; +(pPos) mov r16=r8 +(pNeg) add r16=64,r8 +(pPos) sub r17=64,r8 +(pNeg) sub r17=r0,r8 + ;; + mov ar.rsc=r11 // put RSE in enforced lazy mode + shr.u r8=r25,r16 + add r3=8,in0 // r3 <- &jmpbuf.r1 + shl r9=r25,r17 + ;; + or r25=r8,r9 + ;; + mov r26=ar.rnat + mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12) + ;; + ld8.fill.nta sp=[r2],16 // r12 (sp) + ld8.fill.nta gp=[r3],16 // r1 (gp) + dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp) + ;; + ld8.nta r16=[r2],16 // caller's unat + ld8.nta r17=[r3],16 // fpsr + ;; + ld8.fill.nta r4=[r2],16 // r4 + ld8.fill.nta r5=[r3],16 // r5 (gp) + cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp) + ;; + ld8.fill.nta r6=[r2],16 // r6 + ld8.fill.nta r7=[r3],16 // r7 + ;; + mov ar.unat=r16 // restore caller's unat + mov ar.fpsr=r17 // restore fpsr + ;; + ld8.nta r16=[r2],16 // b0 + ld8.nta r17=[r3],16 // b1 + ;; +(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp) + mov ar.bspstore=r23 // restore ar.bspstore + ;; + ld8.nta r18=[r2],16 // b2 + ld8.nta r19=[r3],16 // b3 + ;; + ld8.nta r20=[r2],16 // b4 + ld8.nta r21=[r3],16 // b5 + ;; + ld8.nta r11=[r2],16 // ar.pfs + ld8.nta r22=[r3],56 // ar.lc + ;; + ld8.nta r24=[r2],32 // pr + mov b0=r16 + ;; + ldf.fill.nta f2=[r2],32 + ldf.fill.nta f3=[r3],32 + mov b1=r17 + ;; + ldf.fill.nta f4=[r2],32 + ldf.fill.nta f5=[r3],32 + mov b2=r18 + ;; + ldf.fill.nta f16=[r2],32 + ldf.fill.nta f17=[r3],32 + mov b3=r19 + ;; + ldf.fill.nta f18=[r2],32 + ldf.fill.nta f19=[r3],32 + mov b4=r20 + ;; + ldf.fill.nta f20=[r2],32 + ldf.fill.nta f21=[r3],32 + mov b5=r21 + ;; + ldf.fill.nta f22=[r2],32 + ldf.fill.nta f23=[r3],32 + mov ar.lc=r22 + ;; + ldf.fill.nta f24=[r2],32 + ldf.fill.nta f25=[r3],32 + cmp.eq p8,p9=0,in1 + ;; + ldf.fill.nta f26=[r2],32 + ldf.fill.nta f27=[r3],32 + mov ar.pfs=r11 + ;; + ldf.fill.nta f28=[r2],32 + ldf.fill.nta f29=[r3],32 + ;; + ldf.fill.nta f30=[r2] + ldf.fill.nta f31=[r3] +(p8) mov r8=1 + + mov ar.rnat=r26 // restore ar.rnat + ;; + mov ar.rsc=r27 // restore ar.rsc +(p9) mov r8=in1 + + invala // virt. -> phys. regnum mapping may change + mov pr=r24,-1 + ret +#ifndef __KERNEL__ +END(__longjmp) +#else /* __KERNEL__ */ +END(kdba_longjmp) +#endif /* !_KERNEL__ */ diff -Nur linux-2.4.19/arch/ia64/kdb/kdba_pod.c linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_pod.c --- linux-2.4.19/arch/ia64/kdb/kdba_pod.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/kdba_pod.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,89 @@ +/* + * Kernel Debugger Architecture Dependent POD functions. + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jesse Barnes"); +MODULE_DESCRIPTION("Enter POD through KDB"); +MODULE_LICENSE("GPL"); + +/** + * kdba_pod - enter POD mode from kdb + * @argc: arg count + * @argv: arg values + * @envp: kdb env. vars + * @regs: current register state + * + * Enter POD mode from kdb using SGI SN specific SAL function call. + */ +static int +kdba_pod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_printf("WARNING: pod commands are dangerous unless you know exactly\n" + "what you are doing. If in doubt, type exit immediately.\n"); + return ia64_sn_pod_mode(); +} + +/** + * kdba_pod_init - register 'pod' command with kdb + * + * Register the 'pod' command with kdb at load time. + */ +static int __init +kdba_pod_init(void) +{ + kdb_register("pod", kdba_pod, 0, "Enter POD", 0); + + return 0; +} + +/** + * kdba_pod_exit - unregister the 'pod' command + * + * Tell kdb that the 'pod' command is no longer available. + */ +static void __exit +kdba_pod_exit(void) +{ + kdb_unregister("pod"); +} + +kdb_module_init(kdba_pod_init) +kdb_module_exit(kdba_pod_exit) + diff -Nur linux-2.4.19/arch/ia64/kdb/kdbasupport.c linux-2.4.19-sgi211r3/arch/ia64/kdb/kdbasupport.c --- linux-2.4.19/arch/ia64/kdb/kdbasupport.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kdb/kdbasupport.c Fri Jan 3 13:57:03 2003 @@ -0,0 +1,1203 @@ +/* + * Kernel Debugger Architecture Independent Support Functions + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * Copyright (C) David Mosberger-Tang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef CONFIG_SMP +#include +#endif + +#if defined(CONFIG_SMP) +unsigned long smp_kdb_wait; +#endif + +/* + * kdba_prologue + * + * FIXME: On ia64 this function is not used yet. It should be used + * so every arch has a common interface. For the moment, + * kdba_bt uses ia64 specific unwind code. + * + * This function analyzes a gcc-generated function prototype + * with or without frame pointers to determine the amount of + * automatic storage and register save storage is used on the + * stack of the target function. It only counts instructions + * that have been executed up to but excluding the current eip. + * Inputs: + * code Start address of function code to analyze + * pc Current program counter within function + * sp Current stack pointer for function + * fp Current frame pointer for function, may not be valid + * ss Start of stack for current process. + * caller 1 if looking for data on the caller frame, 0 for callee. + * Outputs: + * ar Activation record, all fields may be set. fp and oldfp + * are 0 if they cannot be extracted. return is 0 if the + * code cannot find a valid return address. args and arg0 + * are 0 if the number of arguments cannot be safely + * calculated. + * Returns: + * 1 if prologue is valid, 0 otherwise. If pc is 0 treat it as a + * valid prologue to allow bt on wild branches. + * Locking: + * None. + * Remarks: + * FIXME: design an activation record format that works for all architectures. + */ + +int +kdba_prologue(const kdb_symtab_t *symtab, kdb_machreg_t pc, kdb_machreg_t sp, + kdb_machreg_t fp, kdb_machreg_t ss, int caller, kdb_ar_t *ar) +{ + return(1); /*temp*/ +} + + +static int +kdba_itm (int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + unsigned long val; + + diag = kdbgetularg(argv[1], &val); + if (diag) + return diag; + kdb_printf("new itm=" kdb_machreg_fmt "\n", val); + + ia64_set_itm(val); + return 0; +} + +static void +kdba_show_intregs(void) +{ + u64 lid, tpr, lrr0, lrr1, itv, pmv, cmcv; + + asm ("mov %0=cr.lid" : "=r"(lid)); + asm ("mov %0=cr.tpr" : "=r"(tpr)); + asm ("mov %0=cr.lrr0" : "=r"(lrr0)); + asm ("mov %0=cr.lrr1" : "=r"(lrr1)); + kdb_printf("lid=" kdb_machreg_fmt ", tpr=" kdb_machreg_fmt ", lrr0=" kdb_machreg_fmt ", llr1=" kdb_machreg_fmt "\n", lid, tpr, lrr0, lrr1); + + asm ("mov %0=cr.itv" : "=r"(itv)); + asm ("mov %0=cr.pmv" : "=r"(pmv)); + asm ("mov %0=cr.cmcv" : "=r"(cmcv)); + kdb_printf("itv=" kdb_machreg_fmt ", pmv=" kdb_machreg_fmt ", cmcv=" kdb_machreg_fmt "\n", itv, pmv, cmcv); + + kdb_printf("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", + ia64_get_irr0(), ia64_get_irr1(), ia64_get_irr2(), ia64_get_irr3()); + + kdb_printf("itc=0x%016lx, itm=0x%016lx\n", ia64_get_itc(), ia64_get_itm()); +} + +static int +kdba_sir (int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdba_show_intregs(); + + return 0; +} + +static void +kdba_print_nameval(const char *name, unsigned long val) +{ + kdb_symtab_t symtab; + kdb_printf(" %-11.11s ", name); + if (kdbnearsym(val, &symtab)) + kdb_symbol_print(val, &symtab, KDB_SP_VALUE|KDB_SP_SYMSIZE|KDB_SP_NEWLINE); + else + kdb_printf("0x%lx\n", val); +} + +/* + * kdb_pt_regs + * + * Format a struct pt_regs + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * If no address is supplied, it uses regs. + */ + +static int +kdba_pt_regs(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset = 0; + int nextarg; + struct pt_regs *p; + + if (argc == 0) { + addr = (kdb_machreg_t) regs; + } else if (argc == 1) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + } else { + return KDB_ARGCOUNT; + } + + p = (struct pt_regs *) addr; + kdb_printf("struct pt_regs %p-%p\n", p, (unsigned char *)p + sizeof(*p) - 1); + kdb_printf(" cr_ipsr 0x%lx\n", p->cr_ipsr); + kdba_print_nameval("cr_iip", p->cr_iip); + kdb_printf(" cr_ifs 0x%lx\n", p->cr_ifs); + kdb_printf(" ar_unat 0x%lx\n", p->ar_unat); + kdb_printf(" ar_pfs 0x%lx\n", p->ar_pfs); + kdb_printf(" ar_rsc 0x%lx\n", p->ar_rsc); + kdb_printf(" ar_rnat 0x%lx\n", p->ar_rnat); + kdb_printf(" ar_bspstore 0x%lx\n", p->ar_bspstore); + kdb_printf(" pr 0x%lx\n", p->pr); + kdba_print_nameval("b6", p->b6); + kdb_printf(" loadrs 0x%lx\n", p->loadrs); + kdba_print_nameval("r1", p->r1); + kdba_print_nameval("r2", p->r2); + kdba_print_nameval("r3", p->r3); + kdba_print_nameval("r12", p->r12); + kdba_print_nameval("r13", p->r13); + kdba_print_nameval("r14", p->r14); + kdba_print_nameval("r15", p->r15); + kdba_print_nameval("r8", p->r8); + kdba_print_nameval("r9", p->r9); + kdba_print_nameval("r10", p->r10); + kdba_print_nameval("r11", p->r11); + kdba_print_nameval("r16", p->r16); + kdba_print_nameval("r17", p->r17); + kdba_print_nameval("r18", p->r18); + kdba_print_nameval("r19", p->r19); + kdba_print_nameval("r20", p->r20); + kdba_print_nameval("r21", p->r21); + kdba_print_nameval("r22", p->r22); + kdba_print_nameval("r23", p->r23); + kdba_print_nameval("r24", p->r24); + kdba_print_nameval("r25", p->r25); + kdba_print_nameval("r26", p->r26); + kdba_print_nameval("r27", p->r27); + kdba_print_nameval("r28", p->r28); + kdba_print_nameval("r29", p->r29); + kdba_print_nameval("r30", p->r30); + kdba_print_nameval("r31", p->r31); + kdb_printf(" ar_ccv 0x%lx\n", p->ar_ccv); + kdb_printf(" ar_fpsr 0x%lx\n", p->ar_fpsr); + kdba_print_nameval("b0", p->b0); + kdba_print_nameval("b7", p->b7); + kdb_printf(" f6 0x%lx 0x%lx\n", p->f6.u.bits[0], p->f6.u.bits[1]); + kdb_printf(" f7 0x%lx 0x%lx\n", p->f7.u.bits[0], p->f7.u.bits[1]); + kdb_printf(" f8 0x%lx 0x%lx\n", p->f8.u.bits[0], p->f8.u.bits[1]); + kdb_printf(" f9 0x%lx 0x%lx\n", p->f9.u.bits[0], p->f9.u.bits[1]); + + return 0; +} + +/* + * kdb_switch_stack + * + * Format a struct switch_stack + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * If no address is supplied, it uses kdb_sw[smp_processor_id()]. + */ + +static int +kdba_switch_stack(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset = 0; + int nextarg; + struct switch_stack *p; + + if (argc == 0) { + addr = (kdb_machreg_t) kdb_sw[smp_processor_id()]; + } else if (argc == 1) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + } else { + return KDB_ARGCOUNT; + } + + p = (struct switch_stack *) addr; + kdb_printf("struct switch_stack %p-%p\n", p, (unsigned char *)p + sizeof(*p) - 1); + kdb_printf(" caller_unat 0x%lx\n", p->caller_unat); + kdb_printf(" ar_fpsr 0x%lx\n", p->ar_fpsr); + kdb_printf(" f2 0x%lx 0x%lx\n", p->f2.u.bits[0], p->f2.u.bits[1]); + kdb_printf(" f3 0x%lx 0x%lx\n", p->f3.u.bits[0], p->f3.u.bits[1]); + kdb_printf(" f4 0x%lx 0x%lx\n", p->f4.u.bits[0], p->f4.u.bits[1]); + kdb_printf(" f5 0x%lx 0x%lx\n", p->f5.u.bits[0], p->f5.u.bits[1]); + kdb_printf(" f10 0x%lx 0x%lx\n", p->f10.u.bits[0], p->f10.u.bits[1]); + kdb_printf(" f11 0x%lx 0x%lx\n", p->f11.u.bits[0], p->f11.u.bits[1]); + kdb_printf(" f12 0x%lx 0x%lx\n", p->f12.u.bits[0], p->f12.u.bits[1]); + kdb_printf(" f13 0x%lx 0x%lx\n", p->f13.u.bits[0], p->f13.u.bits[1]); + kdb_printf(" f14 0x%lx 0x%lx\n", p->f14.u.bits[0], p->f14.u.bits[1]); + kdb_printf(" f15 0x%lx 0x%lx\n", p->f15.u.bits[0], p->f15.u.bits[1]); + kdb_printf(" f16 0x%lx 0x%lx\n", p->f16.u.bits[0], p->f16.u.bits[1]); + kdb_printf(" f17 0x%lx 0x%lx\n", p->f17.u.bits[0], p->f17.u.bits[1]); + kdb_printf(" f18 0x%lx 0x%lx\n", p->f18.u.bits[0], p->f18.u.bits[1]); + kdb_printf(" f19 0x%lx 0x%lx\n", p->f19.u.bits[0], p->f19.u.bits[1]); + kdb_printf(" f20 0x%lx 0x%lx\n", p->f20.u.bits[0], p->f20.u.bits[1]); + kdb_printf(" f21 0x%lx 0x%lx\n", p->f21.u.bits[0], p->f21.u.bits[1]); + kdb_printf(" f22 0x%lx 0x%lx\n", p->f22.u.bits[0], p->f22.u.bits[1]); + kdb_printf(" f23 0x%lx 0x%lx\n", p->f23.u.bits[0], p->f23.u.bits[1]); + kdb_printf(" f24 0x%lx 0x%lx\n", p->f24.u.bits[0], p->f24.u.bits[1]); + kdb_printf(" f25 0x%lx 0x%lx\n", p->f25.u.bits[0], p->f25.u.bits[1]); + kdb_printf(" f26 0x%lx 0x%lx\n", p->f26.u.bits[0], p->f26.u.bits[1]); + kdb_printf(" f27 0x%lx 0x%lx\n", p->f27.u.bits[0], p->f27.u.bits[1]); + kdb_printf(" f28 0x%lx 0x%lx\n", p->f28.u.bits[0], p->f28.u.bits[1]); + kdb_printf(" f29 0x%lx 0x%lx\n", p->f29.u.bits[0], p->f29.u.bits[1]); + kdb_printf(" f30 0x%lx 0x%lx\n", p->f30.u.bits[0], p->f30.u.bits[1]); + kdb_printf(" f31 0x%lx 0x%lx\n", p->f31.u.bits[0], p->f31.u.bits[1]); + kdba_print_nameval("r4", p->r4); + kdba_print_nameval("r5", p->r5); + kdba_print_nameval("r6", p->r6); + kdba_print_nameval("r7", p->r7); + kdba_print_nameval("b0", p->b0); + kdba_print_nameval("b1", p->b1); + kdba_print_nameval("b2", p->b2); + kdba_print_nameval("b3", p->b3); + kdba_print_nameval("b4", p->b4); + kdba_print_nameval("b5", p->b5); + kdb_printf(" ar_pfs 0x%lx\n", p->ar_pfs); + kdb_printf(" ar_lc 0x%lx\n", p->ar_lc); + kdb_printf(" ar_unat 0x%lx\n", p->ar_unat); + kdb_printf(" ar_rnat 0x%lx\n", p->ar_rnat); + kdb_printf(" ar_bspstore 0x%lx\n", p->ar_bspstore); + kdb_printf(" pr 0x%lx\n", p->pr); + + return 0; +} + +void +kdba_installdbreg(kdb_bp_t *bp) +{ + /* FIXME: code this */ +} + +void +kdba_removedbreg(kdb_bp_t *bp) +{ + /* FIXME: code this */ +} + +kdb_machreg_t +kdba_getdr(int regnum) +{ + kdb_machreg_t contents = 0; + unsigned long reg = (unsigned long)regnum; + + __asm__ ("mov %0=ibr[%1]"::"r"(contents),"r"(reg)); +// __asm__ ("mov ibr[%0]=%1"::"r"(dbreg_cond),"r"(value)); + + return contents; +} + + +kdb_machreg_t +kdb_getcr(int regnum) +{ + kdb_machreg_t contents = 0; + return contents; +} + +void +kdba_putdr(int regnum, kdb_machreg_t contents) +{ + /* FIXME: code this */ +} + +static void +get_fault_regs(fault_regs_t *fr) +{ + fr->ifa = 0 ; + fr->isr = 0 ; + + __asm__ ("rsm psr.ic;;") ; + ia64_srlz_d(); + __asm__ ("mov %0=cr.ifa" : "=r"(fr->ifa)); + __asm__ ("mov %0=cr.isr" : "=r"(fr->isr)); + __asm__ ("ssm psr.ic;;") ; + ia64_srlz_d(); +} + +static void +show_kernel_regs (void) +{ + unsigned long kr[8]; + int i; + + asm ("mov %0=ar.k0" : "=r"(kr[0])); asm ("mov %0=ar.k1" : "=r"(kr[1])); + asm ("mov %0=ar.k2" : "=r"(kr[2])); asm ("mov %0=ar.k3" : "=r"(kr[3])); + asm ("mov %0=ar.k4" : "=r"(kr[4])); asm ("mov %0=ar.k5" : "=r"(kr[5])); + asm ("mov %0=ar.k6" : "=r"(kr[6])); asm ("mov %0=ar.k7" : "=r"(kr[7])); + + for (i = 0; i < 4; ++i) + kdb_printf(" kr%d: %016lx kr%d: %016lx\n", 2*i, kr[2*i], 2*i+1, kr[2*i+1]); + kdb_printf("\n"); +} +static int +change_cur_stack_frame(struct pt_regs *regs, int regno, unsigned long *contents) +{ + unsigned long sof, i, cfm, sp, *bsp; + struct unw_frame_info info; + mm_segment_t old_fs; + + unw_init_frame_info(&info, current, kdb_sw[smp_processor_id()]); + do { + if (unw_unwind(&info) < 0) { + kdb_printf("Failed to unwind\n"); + return 0; + } + unw_get_sp(&info, &sp); + } while (sp <= (unsigned long) regs); + unw_get_bsp(&info, (unsigned long *) &bsp); + unw_get_cfm(&info, &cfm); + + if (!bsp) { + kdb_printf("Unable to get Current Stack Frame\n"); + return 0; + } + + sof = (cfm & 0x7f); + + if(((unsigned long)regno - 32) >= (sof - 2)) return 1; + + old_fs = set_fs(KERNEL_DS); + { + for (i = 0; i < (regno - 32); ++i) { + bsp = ia64_rse_skip_regs(bsp, 1); + } + put_user(*contents, bsp); + } + set_fs(old_fs); + + return 0 ; +} + +static int +show_cur_stack_frame(struct pt_regs *regs, int regno, unsigned long *contents) +{ + unsigned long sof, i, cfm, val, sp, *bsp; + struct unw_frame_info info; + mm_segment_t old_fs; + + /* XXX It would be better to simply create a copy of an unw_frame_info structure + * that is set up in kdba_main_loop(). That way, we could avoid having to skip + * over the first few frames every time... + */ + unw_init_frame_info(&info, current, kdb_sw[smp_processor_id()]); + do { + if (unw_unwind(&info) < 0) { + kdb_printf("Failed to unwind\n"); + return 0; + } + unw_get_sp(&info, &sp); + } while (sp <= (unsigned long) regs); + unw_get_bsp(&info, (unsigned long *) &bsp); + unw_get_cfm(&info, &cfm); + + if (!bsp) { + kdb_printf("Unable to display Current Stack Frame\n"); + return 0; + } + + sof = (cfm & 0x7f); + + if (regno) { + if ((unsigned) regno - 32 >= sof) + return 0; + bsp = ia64_rse_skip_regs(bsp, regno - 32); + old_fs = set_fs(KERNEL_DS); + { + get_user(val, bsp); + } + set_fs(old_fs); + *contents = val; + return 1; + } + + old_fs = set_fs(KERNEL_DS); + { + for (i = 0; i < sof; ++i) { + get_user(val, bsp); + kdb_printf(" r%lu: %016lx ", 32 + i, val); + if (!((i + 1) % 3)) + kdb_printf("\n"); + bsp = ia64_rse_skip_regs(bsp, 1); + } + kdb_printf("\n"); + } + set_fs(old_fs); + + return 0 ; +} + +/* + * kdba_getregcontents + * + * Return the contents of the register specified by the + * input string argument. Return an error if the string + * does not match a machine register. + * + * The following pseudo register names are supported: + * ®s - Prints address of exception frame + * kesp - Prints kernel stack pointer at time of fault + * sstk - Prints switch stack for ia64 + * % - Uses the value of the registers at the + * last time the user process entered kernel + * mode, instead of the registers at the time + * kdb was entered. + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * Outputs: + * *contents Pointer to unsigned long to recieve register contents + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + * + * Note that this function is really machine independent. The kdb + * register list is not, however. + */ + +static struct kdbregs { + char *reg_name; + size_t reg_offset; +} kdbreglist[] = { + { "psr", offsetof(struct pt_regs, cr_ipsr) }, + { "ifs", offsetof(struct pt_regs, cr_ifs) }, + { "ip", offsetof(struct pt_regs, cr_iip) }, + + { "unat", offsetof(struct pt_regs, ar_unat) }, + { "pfs", offsetof(struct pt_regs, ar_pfs) }, + { "rsc", offsetof(struct pt_regs, ar_rsc) }, + + { "rnat", offsetof(struct pt_regs, ar_rnat) }, + { "bsps", offsetof(struct pt_regs, ar_bspstore) }, + { "pr", offsetof(struct pt_regs, pr) }, + + { "ldrs", offsetof(struct pt_regs, loadrs) }, + { "ccv", offsetof(struct pt_regs, ar_ccv) }, + { "fpsr", offsetof(struct pt_regs, ar_fpsr) }, + + { "b0", offsetof(struct pt_regs, b0) }, + { "b6", offsetof(struct pt_regs, b6) }, + { "b7", offsetof(struct pt_regs, b7) }, + + { "r1",offsetof(struct pt_regs, r1) }, + { "r2",offsetof(struct pt_regs, r2) }, + { "r3",offsetof(struct pt_regs, r3) }, + + { "r8",offsetof(struct pt_regs, r8) }, + { "r9",offsetof(struct pt_regs, r9) }, + { "r10",offsetof(struct pt_regs, r10) }, + + { "r11",offsetof(struct pt_regs, r11) }, + { "r12",offsetof(struct pt_regs, r12) }, + { "r13",offsetof(struct pt_regs, r13) }, + + { "r14",offsetof(struct pt_regs, r14) }, + { "r15",offsetof(struct pt_regs, r15) }, + { "r16",offsetof(struct pt_regs, r16) }, + + { "r17",offsetof(struct pt_regs, r17) }, + { "r18",offsetof(struct pt_regs, r18) }, + { "r19",offsetof(struct pt_regs, r19) }, + + { "r20",offsetof(struct pt_regs, r20) }, + { "r21",offsetof(struct pt_regs, r21) }, + { "r22",offsetof(struct pt_regs, r22) }, + + { "r23",offsetof(struct pt_regs, r23) }, + { "r24",offsetof(struct pt_regs, r24) }, + { "r25",offsetof(struct pt_regs, r25) }, + + { "r26",offsetof(struct pt_regs, r26) }, + { "r27",offsetof(struct pt_regs, r27) }, + { "r28",offsetof(struct pt_regs, r28) }, + + { "r29",offsetof(struct pt_regs, r29) }, + { "r30",offsetof(struct pt_regs, r30) }, + { "r31",offsetof(struct pt_regs, r31) }, + +}; + +static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); + +int +kdba_getregcontents(const char *regname, struct pt_regs *regs, unsigned long *contents) +{ + int i; + + if (strcmp(regname, "isr") == 0) { + fault_regs_t fr ; + get_fault_regs(&fr) ; + *contents = fr.isr ; + return 0 ; + } + + if (!regs) { + kdb_printf("%s: pt_regs not available\n", __FUNCTION__); + return KDB_BADREG; + } + + if (strcmp(regname, "®s") == 0) { + *contents = (unsigned long)regs; + return 0; + } + + if (strcmp(regname, "sstk") == 0) { + *contents = (unsigned long)getprsregs(regs) ; + return 0; + } + + if (strcmp(regname, "ksp") == 0) { + *contents = (unsigned long) (regs + 1); + return 0; + } + + for (i=0; i + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * contents Unsigned long containing new register contents + * Outputs: + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + */ + +int +kdba_setregcontents(const char *regname, + struct pt_regs *regs, + unsigned long contents) +{ + int i, ret = 0, fixed = 0; + char *endp; + unsigned long regno; + + if (regname[0] == '%') { + regname++; + regs = (struct pt_regs *) + (current->thread.ksp - sizeof(struct pt_regs)); + } + + if (!regs) { + kdb_printf("%s: pt_regs not available\n", __FUNCTION__); + return KDB_BADREG; + } + + /* fixed registers */ + for (i=0; i (unsigned long)31) { + ret = change_cur_stack_frame(regs, regno, &contents); + if(!ret) return 0; + } + } + + if ((i == nkdbreglist) + || (strlen(kdbreglist[i].reg_name) != strlen(regname)) + || ret) { + return KDB_BADREG; + } + + /* just in case of "standard" register */ + *(unsigned long *)((unsigned long)regs + kdbreglist[i].reg_offset) = + contents; + + return 0; +} + +/* + * kdba_dumpregs + * + * Dump the specified register set to the display. + * + * Parameters: + * regs Pointer to structure containing registers. + * type Character string identifying register set to dump + * extra string further identifying register (optional) + * Outputs: + * Returns: + * 0 Success + * Locking: + * None. + * Remarks: + * This function will dump the general register set if the type + * argument is NULL (struct pt_regs). The alternate register + * set types supported by this function: + * + * d Debug registers + * c Control registers + * u User registers at most recent entry to kernel + * i Interrupt registers -- same as "irr" command + * Following not yet implemented: + * m Model Specific Registers (extra defines register #) + * r Memory Type Range Registers (extra defines register) + * + * For now, all registers are covered as follows: + * + * rd - dumps all regs + * rd %isr - current interrupt status reg, read freshly + * rd s - valid stacked regs + * rd %sstk - gets switch stack addr. dump memory and search + * rd d - debug regs, may not be too useful + * rd k - dump kernel regs + * + * ARs TB Done + * OTHERS TB Decided ?? + * + * Intel wish list + * These will be implemented later - Srinivasa + * + * type action + * ---- ------ + * g dump all General static registers + * s dump all general Stacked registers + * f dump all Floating Point registers + * p dump all Predicate registers + * b dump all Branch registers + * a dump all Application registers + * c dump all Control registers + * + */ + +int +kdba_dumpregs(struct pt_regs *regs, + const char *type, + const char *extra) + +{ + int i; + int count = 0; + + if (type + && (type[0] == 'u')) { + type = NULL; + regs = (struct pt_regs *) + (current->thread.ksp - sizeof(struct pt_regs)); + } + + if (type == NULL) { + if (!regs) { + kdb_printf("%s: pt_regs not available\n", __FUNCTION__); + return KDB_BADREG; + } + for (i=0; icr_iip + ia64_psr(regs)->ri : 0; +} + +int +kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc) +{ + if (KDB_NULL_REGS(regs)) + return KDB_BADREG; + regs->cr_iip = newpc & ~0xf; + ia64_psr(regs)->ri = newpc & 0x3; + KDB_STATE_SET(IP_ADJUSTED); + return 0; +} + +struct kdba_main_loop_data { + kdb_reason_t reason; + kdb_reason_t reason2; + int error; + kdb_dbtrap_t db_result; + struct pt_regs *regs; + int ret; +}; + +/* + * do_kdba_main_loop + * + * Invoked from kdba_main_loop via unw_init_running() after that routine + * has pushed a struct switch_stack. + * + * Inputs: + * info Unwind information. + * data kdb data passed as void * to unw_init_running. + * Returns: + * none (unw_init_running requires void). vdata->ret is set to + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Outputs: + * none + * Locking: + * None. + * Remarks: + * unw_init_running() creates struct switch_stack then struct + * unw_frame_info. We get the address of the info so step over + * that to get switch_stack. Just hope that unw_init_running + * does not change its stack usage. unw_init_running adds padding + * to put switch_stack on a 16 byte boundary. + */ + +struct switch_stack *kdb_sw[NR_CPUS]; + +static void +do_kdba_main_loop(struct unw_frame_info *info, void *vdata) +{ + struct kdba_main_loop_data *data = vdata; + struct switch_stack *sw, *prev_sw; + KDB_DEBUG_STATE("do_kdba_main_loop", data->reason); + prev_sw = kdb_sw[smp_processor_id()]; + sw = (struct switch_stack *)(info+1); + sw = (struct switch_stack *)(((unsigned long)sw + 15) & ~15); /* padding from unw_init_running */ + kdb_sw[smp_processor_id()] = sw; + data->ret = kdb_main_loop(data->reason, data->reason2, data->error, data->db_result, data->regs); + kdb_sw[smp_processor_id()] = prev_sw; +} + +/* + * kdba_main_loop + * + * Do any architecture specific set up before entering the main kdb loop. + * The primary function of this routine is to make all processes look the + * same to kdb, kdb must be able to list a process without worrying if the + * process is running or blocked, so make all processes look as though they + * are blocked. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * error2 kdb's current reason code. Initially error but can change + * acording to kdb state. + * db_result Result from break or debug point. + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it should + * always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Outputs: + * Builds a switch_stack structure before calling the main loop. + * Locking: + * None. + * Remarks: + * none. + */ + +int +kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, + kdb_dbtrap_t db_result, struct pt_regs *regs) +{ + struct kdba_main_loop_data data; + KDB_DEBUG_STATE("kdba_main_loop", reason); + data.reason = reason; + data.reason2 = reason2; + data.error = error; + data.db_result = db_result; + data.regs = regs; + unw_init_running(do_kdba_main_loop, &data); + return(data.ret); +} + +void +kdba_disableint(kdb_intstate_t *state) +{ + int *fp = (int *)state; + int flags; + + __save_flags(flags); + __cli(); + + *fp = flags; +} + +void +kdba_restoreint(kdb_intstate_t *state) +{ + int flags = *(int *)state; + __restore_flags(flags); +} + +void +kdba_setsinglestep(struct pt_regs *regs) +{ + if (KDB_NULL_REGS(regs)) + return; + ia64_psr(regs)->ss = 1; +} + +void +kdba_clearsinglestep(struct pt_regs *regs) +{ + if (KDB_NULL_REGS(regs)) + return; + ia64_psr(regs)->ss = 0; +} + +/* + * kdba_enable_mce + * + * This function is called once on each CPU to enable machine + * check exception handling. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +void +kdba_enable_mce(void) +{ +} + +/* + * kdba_enable_lbr + * + * Enable last branch recording. + * + * Parameters: + * None. + * Returns: + * None + * Locking: + * None + * Remarks: + * None. + */ + +void +kdba_enable_lbr(void) +{ +} + +/* + * kdba_disable_lbr + * + * disable last branch recording. + * + * Parameters: + * None. + * Returns: + * None + * Locking: + * None + * Remarks: + * None. + */ + +void +kdba_disable_lbr(void) +{ +} + +/* + * kdba_print_lbr + * + * Print last branch and last exception addresses + * + * Parameters: + * None. + * Returns: + * None + * Locking: + * None + * Remarks: + * None. + */ + +void +kdba_print_lbr(void) +{ +} + +#if defined(CONFIG_SMP) +/* + * kdba_sendinit + * + * This function implements the 'init' command. + * + * init [] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdba_sendinit(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long cpunum; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetularg(argv[1], &cpunum); + if (diag) + return diag; + + if ((cpunum > NR_CPUS) || !test_bit(cpunum, &cpu_online_map)) + return KDB_BADCPUNUM; + + platform_send_ipi(cpunum, 0, IA64_IPI_DM_INIT, 0); + return 0; +} +#endif /* CONFIG_SMP */ + +/* + * kdba_init + * + * Architecture specific initialization. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +void +kdba_init(void) +{ + kdba_enable_lbr(); + kdb_register("irr", kdba_sir, "", "Show interrupt registers", 0); + kdb_register("itm", kdba_itm, "", "Set new ITM value", 0); +#if defined(CONFIG_SMP) + kdb_register("init", kdba_sendinit, "", "Send INIT to cpu", 0); +#endif + kdb_register("pt_regs", kdba_pt_regs, "address", "Format struct pt_regs", 0); + kdb_register("switch_stack", kdba_switch_stack, "address", "Format struct switch_stack", 0); + + return; +} + +/* + * kdba_adjust_ip + * + * Architecture specific adjustment of instruction pointer before leaving + * kdb. + * + * Parameters: + * reason The reason KDB was invoked + * error The hardware-defined error code + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it should + * always be valid. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * On IA64, KDB_ENTER() uses break which is a fault, not a trap. The + * instruction pointer must be stepped before leaving kdb, otherwise we + * get a loop. + */ + +void +kdba_adjust_ip(kdb_reason_t reason, int error, struct pt_regs *regs) +{ + if (reason == KDB_REASON_ENTER && + !KDB_STATE(IP_ADJUSTED)) { + if (KDB_NULL_REGS(regs)) + return; + if (ia64_psr(regs)->ri < 2) + kdba_setpc(regs, regs->cr_iip + ia64_psr(regs)->ri + 1); + else + kdba_setpc(regs, regs->cr_iip + 16); + } +} diff -Nur linux-2.4.19/arch/ia64/kernel/Makefile linux-2.4.19-sgi211r3/arch/ia64/kernel/Makefile --- linux-2.4.19/arch/ia64/kernel/Makefile Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/Makefile Fri Apr 26 11:07:18 2002 @@ -17,6 +17,7 @@ machvec.o pal.o process.o perfmon.o ptrace.o sal.o salinfo.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o obj-$(CONFIG_IA64_GENERIC) += iosapic.o +obj-$(CONFIG_IA64_HP_ZX1) += iosapic.o obj-$(CONFIG_IA64_DIG) += iosapic.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_EFI_VARS) += efivars.o diff -Nur linux-2.4.19/arch/ia64/kernel/acpi.c linux-2.4.19-sgi211r3/arch/ia64/kernel/acpi.c --- linux-2.4.19/arch/ia64/kernel/acpi.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/acpi.c Tue Feb 4 10:57:27 2003 @@ -1,21 +1,36 @@ /* - * Advanced Configuration and Power Interface + * acpi.c - Architecture-Specific Low-Level ACPI Support * - * Based on 'ACPI Specification 1.0b' February 2, 1999 and - * 'IA-64 Extensions to ACPI Specification' Revision 0.6 + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999,2000 Walt Drummond + * Copyright (C) 2000, 2002 Hewlett-Packard Co. + * David Mosberger-Tang + * Copyright (C) 2000 Intel Corp. + * Copyright (C) 2000,2001 J.I. Lee + * Copyright (C) 2001 Paul Diefenbaugh + * Copyright (C) 2001 Jenna Hall + * Copyright (C) 2001 Takayoshi Kochi * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999,2000 Walt Drummond - * Copyright (C) 2000 Hewlett-Packard Co. - * Copyright (C) 2000 David Mosberger-Tang - * Copyright (C) 2000 Intel Corp. - * Copyright (C) 2000,2001 J.I. Lee - * ACPI based kernel configuration manager. - * ACPI 2.0 & IA64 ext 0.71 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include - #include #include #include @@ -23,657 +38,1267 @@ #include #include #include -#ifdef CONFIG_SERIAL_ACPI -#include -#endif - -#include -#include -#include +#include +#include #include #include #include #include +#include -#undef ACPI_DEBUG /* Guess what this does? */ -/* global array to record platform interrupt vectors for generic int routing */ -int platform_irq_list[ACPI_MAX_PLATFORM_IRQS]; +#define PREFIX "ACPI: " -/* These are ugly but will be reclaimed by the kernel */ -int __initdata available_cpus; -int __initdata total_cpus; +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) +#define ACPI_DEBUG 1 +#endif -void (*pm_idle) (void); -void (*pm_power_off) (void); +#if ACPI_DEBUG +#define Dprintk(x...) printk(x) +#define SRAT_DEBUG 1 +#define SLIT_DEBUG 1 +#else +#define Dprintk(x...) +#endif -asm (".weak iosapic_register_irq"); -asm (".weak iosapic_register_legacy_irq"); -asm (".weak iosapic_register_platform_irq"); + +asm (".weak iosapic_register_intr"); +asm (".weak iosapic_override_isa_irq"); +asm (".weak iosapic_register_platform_intr"); asm (".weak iosapic_init"); asm (".weak iosapic_version"); +asm (".weak acpi_get_current_resources"); + +void (*pm_idle) (void); +void (*pm_power_off) (void); + +unsigned char acpi_kbd_controller_present = 1; const char * acpi_get_sysname (void) { - /* the following should go away once we have an ACPI parser: */ #ifdef CONFIG_IA64_GENERIC - return "hpsim"; + unsigned long rsdp_phys; + struct acpi20_table_rsdp *rsdp; + struct acpi_table_xsdt *xsdt; + struct acpi_table_header *hdr; + + rsdp_phys = acpi_find_rsdp(); + if (!rsdp_phys) { + printk("ACPI 2.0 RSDP not found, default to \"dig\"\n"); + return "dig"; + } + + rsdp = (struct acpi20_table_rsdp *) __va(rsdp_phys); + if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) { + printk("ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n"); + return "dig"; + } + + xsdt = (struct acpi_table_xsdt *) __va(rsdp->xsdt_address); + hdr = &xsdt->header; + if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) { + printk("ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n"); + return "dig"; + } + + if (!strcmp(hdr->oem_id, "HP")) { + return "hpzx1"; + } + + return "dig"; #else # if defined (CONFIG_IA64_HP_SIM) return "hpsim"; +# elif defined (CONFIG_IA64_HP_ZX1) + return "hpzx1"; # elif defined (CONFIG_IA64_SGI_SN1) return "sn1"; # elif defined (CONFIG_IA64_SGI_SN2) return "sn2"; # elif defined (CONFIG_IA64_DIG) return "dig"; +# elif defined (CONFIG_IA64_HP_ZX1) + return "hpzx1"; # else # error Unknown platform. Fix acpi.c. # endif #endif +} + +#ifdef CONFIG_ACPI +/** + * acpi_get_crs - Return the current resource settings for a device + * obj: A handle for this device + * buf: A buffer to be populated by this call. + * + * Pass a valid handle, typically obtained by walking the namespace and a + * pointer to an allocated buffer, and this function will fill in the buffer + * with a list of acpi_resource structures. + */ +acpi_status +acpi_get_crs (acpi_handle obj, acpi_buffer *buf) +{ + acpi_status result; + buf->length = 0; + buf->pointer = NULL; + + result = acpi_get_current_resources(obj, buf); + if (result != AE_BUFFER_OVERFLOW) + return result; + buf->pointer = kmalloc(buf->length, GFP_KERNEL); + if (!buf->pointer) + return -ENOMEM; + + return acpi_get_current_resources(obj, buf); } +acpi_resource * +acpi_get_crs_next (acpi_buffer *buf, int *offset) +{ + acpi_resource *res; + + if (*offset >= buf->length) + return NULL; + + res = buf->pointer + *offset; + *offset += res->length; + return res; +} + +acpi_resource_data * +acpi_get_crs_type (acpi_buffer *buf, int *offset, int type) +{ + for (;;) { + acpi_resource *res = acpi_get_crs_next(buf, offset); + if (!res) + return NULL; + if (res->id == type) + return &res->data; + } +} + +void +acpi_dispose_crs (acpi_buffer *buf) +{ + kfree(buf->pointer); +} + +static void +acpi_get_crs_addr (acpi_buffer *buf, int type, u64 *base, u64 *length, u64 *tra) +{ + int offset = 0; + acpi_resource_address16 *addr16; + acpi_resource_address32 *addr32; + acpi_resource_address64 *addr64; + + for (;;) { + acpi_resource *res = acpi_get_crs_next(buf, &offset); + if (!res) + return; + switch (res->id) { + case ACPI_RSTYPE_ADDRESS16: + addr16 = (acpi_resource_address16 *) &res->data; + + if (type == addr16->resource_type) { + *base = addr16->min_address_range; + *length = addr16->address_length; + *tra = addr16->address_translation_offset; + return; + } + break; + case ACPI_RSTYPE_ADDRESS32: + addr32 = (acpi_resource_address32 *) &res->data; + if (type == addr32->resource_type) { + *base = addr32->min_address_range; + *length = addr32->address_length; + *tra = addr32->address_translation_offset; + return; + } + break; + case ACPI_RSTYPE_ADDRESS64: + addr64 = (acpi_resource_address64 *) &res->data; + if (type == addr64->resource_type) { + *base = addr64->min_address_range; + *length = addr64->address_length; + *tra = addr64->address_translation_offset; + return; + } + break; + } + } +} + +acpi_status +acpi_get_addr_space(acpi_handle obj, u8 type, u64 *base, u64 *length, u64 *tra) +{ + acpi_status status; + acpi_buffer buf; + + *base = 0; + *length = 0; + *tra = 0; + + status = acpi_get_crs(obj, &buf); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n"); + return status; + } + + acpi_get_crs_addr(&buf, type, base, length, tra); + + acpi_dispose_crs(&buf); + + return AE_OK; +} + +typedef struct { + u8 guid_id; + u8 guid[16]; + u8 csr_base[8]; + u8 csr_length[8]; +} acpi_hp_vendor_long; + +#define HP_CCSR_LENGTH 0x21 +#define HP_CCSR_TYPE 0x2 +#define HP_CCSR_GUID EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, \ + 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad) + +acpi_status +acpi_hp_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length) +{ + int i, offset = 0; + acpi_status status; + acpi_buffer buf; + acpi_resource_vendor *res; + acpi_hp_vendor_long *hp_res; + efi_guid_t vendor_guid; + + *csr_base = 0; + *csr_length = 0; + + status = acpi_get_crs(obj, &buf); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n"); + return status; + } + + res = (acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR); + if (!res) { + printk(KERN_ERR PREFIX "Failed to find config space for device\n"); + acpi_dispose_crs(&buf); + return AE_NOT_FOUND; + } + + hp_res = (acpi_hp_vendor_long *)(res->reserved); + + if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) { + printk(KERN_ERR PREFIX "Unknown Vendor data\n"); + acpi_dispose_crs(&buf); + return AE_TYPE; /* Revisit error? */ + } + + memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t)); + if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) { + printk(KERN_ERR PREFIX "Vendor GUID does not match\n"); + acpi_dispose_crs(&buf); + return AE_TYPE; /* Revisit error? */ + } + + for (i = 0 ; i < 8 ; i++) { + *csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8)); + *csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8)); + } + + acpi_dispose_crs(&buf); + + return AE_OK; +} +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_ACPI_BOOT + +#define ACPI_MAX_PLATFORM_INTERRUPTS 256 + +/* Array to record platform interrupt vectors for generic interrupt routing. */ +int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = { [0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1 }; + +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC; + /* - * Interrupt routing API for device drivers. - * Provides the interrupt vector for a generic platform event - * (currently only CPEI implemented) + * Interrupt routing API for device drivers. Provides interrupt vector for + * a generic platform event. Currently only CPEI is implemented. */ int -acpi_request_vector(u32 int_type) +acpi_request_vector (u32 int_type) { int vector = -1; - if (int_type < ACPI_MAX_PLATFORM_IRQS) { + if (int_type < ACPI_MAX_PLATFORM_INTERRUPTS) { /* correctable platform error interrupt */ - vector = platform_irq_list[int_type]; + vector = platform_intr_list[int_type]; } else printk("acpi_request_vector(): invalid interrupt type\n"); return vector; } -/* - * Configure legacy IRQ information. - */ -static void __init -acpi_legacy_irq (char *p) +char * +__acpi_map_table (unsigned long phys_addr, unsigned long size) { - acpi_entry_int_override_t *legacy = (acpi_entry_int_override_t *) p; - unsigned long polarity = 0, edge_triggered = 0; + return __va(phys_addr); +} - /* - * If the platform we're running doesn't define - * iosapic_register_legacy_irq(), we ignore this info... - */ - if (!iosapic_register_legacy_irq) - return; +/* -------------------------------------------------------------------------- + Boot-time Table Parsing + -------------------------------------------------------------------------- */ + +static int total_cpus __initdata; +static int available_cpus __initdata; +struct acpi_table_madt * acpi_madt __initdata; +static u8 has_8259; - switch (legacy->flags) { - case 0x5: polarity = 1; edge_triggered = 1; break; - case 0x7: polarity = 0; edge_triggered = 1; break; - case 0xd: polarity = 1; edge_triggered = 0; break; - case 0xf: polarity = 0; edge_triggered = 0; break; - default: - printk(" ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x\n", legacy->isa_irq, - legacy->flags); - break; + +static int __init +acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header) +{ + struct acpi_table_lapic_addr_ovr *lapic; + + lapic = (struct acpi_table_lapic_addr_ovr *) header; + if (!lapic) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + if (lapic->address) { + iounmap((void *) ipi_base_addr); + ipi_base_addr = (unsigned long) ioremap(lapic->address, 0); } - iosapic_register_legacy_irq(legacy->isa_irq, legacy->pin, polarity, edge_triggered); + + return 0; } -/* - * ACPI 2.0 tables parsing functions - */ -static unsigned long -readl_unaligned(void *p) +static int __init +acpi_parse_lsapic (acpi_table_entry_header *header) { - unsigned long ret; + struct acpi_table_lsapic *lsapic; - memcpy(&ret, p, sizeof(long)); - return ret; -} + lsapic = (struct acpi_table_lsapic *) header; + if (!lsapic) + return -EINVAL; -/* - * Identify usable CPU's and remember them for SMP bringup later. - */ -static void __init -acpi20_lsapic (char *p) -{ - int add = 1; +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) + acpi_table_print_madt_entry(header); +#endif - acpi20_entry_lsapic_t *lsapic = (acpi20_entry_lsapic_t *) p; - printk(" CPU %.04x:%.04x: ", lsapic->eid, lsapic->id); + if (!lsapic->flags.enabled) + printk("NOTE: CPU %d (0x%04x) disabled\n", total_cpus, (lsapic->id << 8) | lsapic->eid); - if ((lsapic->flags & LSAPIC_ENABLED) == 0) { - printk("disabled.\n"); - add = 0; - } + Dprintk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid); -#ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[total_cpus] = -1; -#endif - if (add) { + if (lsapic->flags.enabled) { available_cpus++; - printk("available"); + Dprintk(" enabled"); #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus]) - printk(" (BSP)"); + Dprintk(" (BSP)"); +#endif + } + else { + Dprintk(" disabled"); +#ifdef CONFIG_SMP + smp_boot_data.cpu_phys_id[total_cpus] = -1; #endif - printk(".\n"); } + + Dprintk("\n"); + total_cpus++; + return 0; } -/* - * Extract iosapic info from madt (again) to determine which iosapic - * this platform interrupt resides in - */ + static int __init -acpi20_which_iosapic (int global_vector, acpi_madt_t *madt, u32 *irq_base, char **iosapic_address) +acpi_parse_lapic_nmi (acpi_table_entry_header *header) { - acpi_entry_iosapic_t *iosapic; - char *p, *end; - int ver, max_pin; + struct acpi_table_lapic_nmi *lacpi_nmi; - p = (char *) (madt + 1); - end = p + (madt->header.length - sizeof(acpi_madt_t)); + lacpi_nmi = (struct acpi_table_lapic_nmi*) header; + if (!lacpi_nmi) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* TBD: Support lapic_nmi entries */ + + return 0; +} + + +static int __init +acpi_find_iosapic (unsigned int gsi, u32 *gsi_base, char **iosapic_address) +{ + struct acpi_table_iosapic *iosapic; + int ver; + int max_pin; + char *p; + char *end; + + if (!gsi_base || !iosapic_address) + return -ENODEV; + + p = (char *) (acpi_madt + 1); + end = p + (acpi_madt->header.length - sizeof(struct acpi_table_madt)); while (p < end) { - switch (*p) { - case ACPI20_ENTRY_IO_SAPIC: - /* collect IOSAPIC info for platform int use later */ - iosapic = (acpi_entry_iosapic_t *)p; - *irq_base = iosapic->irq_base; + if (*p == ACPI_MADT_IOSAPIC) { + iosapic = (struct acpi_table_iosapic *) p; + + *gsi_base = iosapic->global_irq_base; *iosapic_address = ioremap(iosapic->address, 0); - /* is this the iosapic we're looking for? */ + ver = iosapic_version(*iosapic_address); max_pin = (ver >> 16) & 0xff; - if ((global_vector - *irq_base) <= max_pin) - return 0; /* found it! */ - break; - default: - break; + + if ((gsi - *gsi_base) <= max_pin) + return 0; /* Found it! */ } p += p[1]; } - return 1; + return -ENODEV; } -/* - * Info on platform interrupt sources: NMI, PMI, INIT, etc. - */ -static void __init -acpi20_platform (char *p, acpi_madt_t *madt) + +#ifndef CONFIG_IA64_SGI_SN +static int __init +acpi_parse_iosapic (acpi_table_entry_header *header) +{ + struct acpi_table_iosapic *iosapic; + + iosapic = (struct acpi_table_iosapic *) header; + if (!iosapic) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + if (iosapic_init) { +#ifndef CONFIG_ITANIUM + /* PCAT_COMPAT flag indicates dual-8259 setup */ + iosapic_init(iosapic->address, iosapic->global_irq_base, + acpi_madt->flags.pcat_compat); +#else + /* Firmware on old Itanium systems is broken */ + iosapic_init(iosapic->address, iosapic->global_irq_base, 1); +#endif + } + return 0; +} + +#endif + +static int __init +acpi_parse_plat_int_src (acpi_table_entry_header *header) { + struct acpi_table_plat_int_src *plintsrc; int vector; - u32 irq_base; + u32 gsi_base; char *iosapic_address; - unsigned long polarity = 0, trigger = 0; - acpi20_entry_platform_src_t *plat = (acpi20_entry_platform_src_t *) p; - printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n", - plat->iosapic_vector, plat->global_vector, plat->eid, plat->id); + plintsrc = (struct acpi_table_plat_int_src *) header; + if (!plintsrc) + return -EINVAL; - /* record platform interrupt vectors for generic int routing code */ + acpi_table_print_madt_entry(header); - if (!iosapic_register_platform_irq) { - printk("acpi20_platform(): no ACPI platform IRQ support\n"); - return; - } - - /* extract polarity and trigger info from flags */ - switch (plat->flags) { - case 0x5: polarity = 1; trigger = 1; break; - case 0x7: polarity = 0; trigger = 1; break; - case 0xd: polarity = 1; trigger = 0; break; - case 0xf: polarity = 0; trigger = 0; break; - default: - printk("acpi20_platform(): unknown flags 0x%x\n", plat->flags); - break; + if (!iosapic_register_platform_intr) { + printk(KERN_WARNING PREFIX "No ACPI platform interrupt support\n"); + return -ENODEV; } - /* which iosapic does this IRQ belong to? */ - if (acpi20_which_iosapic(plat->global_vector, madt, &irq_base, &iosapic_address)) { - printk("acpi20_platform(): I/O SAPIC not found!\n"); - return; + if (acpi_find_iosapic(plintsrc->global_irq, &gsi_base, &iosapic_address)) { + printk(KERN_WARNING PREFIX "IOSAPIC not found\n"); + return -ENODEV; } /* - * get vector assignment for this IRQ, set attributes, and program the IOSAPIC - * routing table + * Get vector assignment for this interrupt, set attributes, + * and program the IOSAPIC routing table. */ - vector = iosapic_register_platform_irq(plat->int_type, - plat->global_vector, - plat->iosapic_vector, - plat->eid, - plat->id, - polarity, - trigger, - irq_base, - iosapic_address); - platform_irq_list[plat->int_type] = vector; + vector = iosapic_register_platform_intr(plintsrc->type, + plintsrc->global_irq, + plintsrc->iosapic_vector, + plintsrc->eid, + plintsrc->id, + (plintsrc->flags.polarity == 1) ? 1 : 0, + (plintsrc->flags.trigger == 1) ? 1 : 0, + gsi_base, + iosapic_address); + + platform_intr_list[plintsrc->type] = vector; + return 0; } -/* - * Override the physical address of the local APIC in the MADT stable header. - */ -static void __init -acpi20_lapic_addr_override (char *p) + +static int __init +acpi_parse_int_src_ovr (acpi_table_entry_header *header) { - acpi20_entry_lapic_addr_override_t * lapic = (acpi20_entry_lapic_addr_override_t *) p; + struct acpi_table_int_src_ovr *p; - if (lapic->lapic_address) { - iounmap((void *)ipi_base_addr); - ipi_base_addr = (unsigned long) ioremap(lapic->lapic_address, 0); + p = (struct acpi_table_int_src_ovr *) header; + if (!p) + return -EINVAL; - printk("LOCAL ACPI override to 0x%lx(p=0x%lx)\n", - ipi_base_addr, lapic->lapic_address); - } -} + acpi_table_print_madt_entry(header); -/* - * Parse the ACPI Multiple APIC Description Table - */ -static void __init -acpi20_parse_madt (acpi_madt_t *madt) -{ - acpi_entry_iosapic_t *iosapic = NULL; - acpi20_entry_lsapic_t *lsapic = NULL; - char *p, *end; - int i; + /* Ignore if the platform doesn't support overrides */ + if (!iosapic_override_isa_irq) + return 0; - /* Base address of IPI Message Block */ - if (madt->lapic_address) { - ipi_base_addr = (unsigned long) ioremap(madt->lapic_address, 0); - printk("Lapic address set to 0x%lx\n", ipi_base_addr); - } else - printk("Lapic address set to default 0x%lx\n", ipi_base_addr); + iosapic_override_isa_irq(p->bus_irq, p->global_irq, + (p->flags.polarity == 1) ? 1 : 0, + (p->flags.trigger == 1) ? 1 : 0); - p = (char *) (madt + 1); - end = p + (madt->header.length - sizeof(acpi_madt_t)); + return 0; +} - /* Initialize platform interrupt vector array */ - for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++) - platform_irq_list[i] = -1; - /* - * Split-up entry parsing to ensure ordering. - */ - while (p < end) { - switch (*p) { - case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE: - printk("ACPI 2.0 MADT: LOCAL APIC Override\n"); - acpi20_lapic_addr_override(p); - break; +static int __init +acpi_parse_nmi_src (acpi_table_entry_header *header) +{ + struct acpi_table_nmi_src *nmi_src; - case ACPI20_ENTRY_LOCAL_SAPIC: - printk("ACPI 2.0 MADT: LOCAL SAPIC\n"); - lsapic = (acpi20_entry_lsapic_t *) p; - acpi20_lsapic(p); - break; + nmi_src = (struct acpi_table_nmi_src*) header; + if (!nmi_src) + return -EINVAL; - case ACPI20_ENTRY_IO_SAPIC: - iosapic = (acpi_entry_iosapic_t *) p; - if (iosapic_init) - /* - * The PCAT_COMPAT flag indicates that the system has a - * dual-8259 compatible setup. - */ - iosapic_init(iosapic->address, iosapic->irq_base, -#ifdef CONFIG_ITANIUM - 1 /* fw on some Itanium systems is broken... */ -#else - (madt->flags & MADT_PCAT_COMPAT) -#endif - ); - break; + acpi_table_print_madt_entry(header); - case ACPI20_ENTRY_PLATFORM_INT_SOURCE: - printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n"); - acpi20_platform(p, madt); - break; + /* TBD: Support nimsrc entries */ - case ACPI20_ENTRY_LOCAL_APIC: - printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break; - case ACPI20_ENTRY_IO_APIC: - printk("ACPI 2.0 MADT: IO APIC entry\n"); break; - case ACPI20_ENTRY_NMI_SOURCE: - printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break; - case ACPI20_ENTRY_LOCAL_APIC_NMI: - printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break; - case ACPI20_ENTRY_INT_SRC_OVERRIDE: - break; - default: - printk("ACPI 2.0 MADT: unknown entry skip\n"); break; - break; - } - p += p[1]; - } + return 0; +} - p = (char *) (madt + 1); - end = p + (madt->header.length - sizeof(acpi_madt_t)); - while (p < end) { - switch (*p) { - case ACPI20_ENTRY_LOCAL_APIC: - if (lsapic) break; - printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); - /* parse local apic if there's no local Sapic */ - break; - case ACPI20_ENTRY_IO_APIC: - if (iosapic) break; - printk("ACPI 2.0 MADT: IO APIC entry\n"); - /* parse ioapic if there's no ioSapic */ - break; - default: - break; - } - p += p[1]; - } +static int __init +acpi_parse_madt (unsigned long phys_addr, unsigned long size) +{ + if (!phys_addr || !size) + return -EINVAL; - p = (char *) (madt + 1); - end = p + (madt->header.length - sizeof(acpi_madt_t)); + acpi_madt = (struct acpi_table_madt *) __va(phys_addr); - while (p < end) { - switch (*p) { - case ACPI20_ENTRY_INT_SRC_OVERRIDE: - printk("ACPI 2.0 MADT: INT SOURCE Override\n"); - acpi_legacy_irq(p); - break; - default: - break; - } - p += p[1]; - } + /* remember the value for reference after free_initmem() */ + has_8259 = acpi_madt->flags.pcat_compat; - /* Make bootup pretty */ - printk(" %d CPUs available, %d CPUs total\n", - available_cpus, total_cpus); + /* Get base address of IPI Message Block */ + + if (acpi_madt->lapic_address) + ipi_base_addr = (unsigned long) ioremap(acpi_madt->lapic_address, 0); + + printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr); + return 0; } -int __init -acpi20_parse (acpi20_rsdp_t *rsdp20) + +static int __init +acpi_parse_fadt (unsigned long phys_addr, unsigned long size) { -# ifdef CONFIG_ACPI - acpi_xsdt_t *xsdt; - acpi_desc_table_hdr_t *hdrp; - acpi_madt_t *madt = NULL; - int tables, i; + struct acpi_table_header *fadt_header; + fadt_descriptor_rev2 *fadt; + u32 sci_irq, gsi_base; + char *iosapic_address; - if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) { - printk("ACPI 2.0 RSDP signature incorrect!\n"); - return 0; - } else { - printk("ACPI 2.0 Root System Description Ptr at 0x%lx\n", - (unsigned long)rsdp20); - } + if (!phys_addr || !size) + return -EINVAL; - xsdt = __va(rsdp20->xsdt); - hdrp = &xsdt->header; - if (strncmp(hdrp->signature, - ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN)) { - printk("ACPI 2.0 XSDT signature incorrect. Trying RSDT\n"); - /* RSDT parsing here */ - return 0; - } else { - printk("ACPI 2.0 XSDT at 0x%lx (p=0x%lx)\n", - (unsigned long)xsdt, (unsigned long)rsdp20->xsdt); - } + fadt_header = (struct acpi_table_header *) __va(phys_addr); - printk("ACPI 2.0: %.6s %.8s %d.%d\n", - hdrp->oem_id, - hdrp->oem_table_id, - hdrp->oem_revision >> 16, - hdrp->oem_revision & 0xffff); + if (fadt_header->revision != 3) + return -ENODEV; /* Only deal with ACPI 2.0 FADT */ - acpi_cf_init((void *)rsdp20); + fadt = (fadt_descriptor_rev2 *) fadt_header; - tables =(hdrp->length -sizeof(acpi_desc_table_hdr_t))>>3; + if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER)) + acpi_kbd_controller_present = 0; - for (i = 0; i < tables; i++) { - hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i])); - printk(" :table %4.4s found\n", hdrp->signature); + sci_irq = fadt->sci_int; - /* Only interested int the MADT table for now ... */ - if (strncmp(hdrp->signature, - ACPI_MADT_SIG, ACPI_MADT_SIG_LEN) != 0) - continue; + if (has_8259 && sci_irq < 16) + return 0; /* legacy, no setup required */ + + if (!iosapic_register_intr) + return -ENODEV; + + if (!acpi_find_iosapic(sci_irq, &gsi_base, &iosapic_address)) + iosapic_register_intr(sci_irq, 0, 0, gsi_base, iosapic_address); + + return 0; +} - /* Save MADT pointer for later */ - madt = (acpi_madt_t *) hdrp; - acpi20_parse_madt(madt); - } #ifdef CONFIG_SERIAL_ACPI + +#include + +static int __init +acpi_parse_spcr (unsigned long phys_addr, unsigned long size) +{ + acpi_ser_t *spcr; + u32 gsi, gsi_base; + char *iosapic_address; + + if (!phys_addr || !size) + return -EINVAL; + + if (!iosapic_register_intr) + return -ENODEV; + /* - * Now we're interested in other tables. We want the iosapics already - * initialized, so we do it in a separate loop. + * ACPI is able to describe serial ports that live at non-standard + * memory addresses and use non-standard interrupts, either via + * direct SAPIC mappings or via PCI interrupts. We handle interrupt + * routing for SAPIC-based (non-PCI) devices here. Interrupt routing + * for PCI devices will be handled when processing the PCI Interrupt + * Routing Table (PRT). */ - for (i = 0; i < tables; i++) { - hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i])); - /* - * search for SPCR and DBGP table entries so we can enable - * non-pci interrupts to IO-SAPICs. - */ - if (!strncmp(hdrp->signature, ACPI_SPCRT_SIG, ACPI_SPCRT_SIG_LEN) || - !strncmp(hdrp->signature, ACPI_DBGPT_SIG, ACPI_DBGPT_SIG_LEN)) - { - acpi_ser_t *spcr = (void *)hdrp; - unsigned long global_int; - - setup_serial_acpi(hdrp); - - /* - * ACPI is able to describe serial ports that live at non-standard - * memory space addresses and use SAPIC interrupts. If not also - * PCI devices, there would be no interrupt vector information for - * them. This checks for and fixes that situation. - */ - if (spcr->length < sizeof(acpi_ser_t)) - /* table is not long enough for full info, thus no int */ - break; - /* - * If the device is not in PCI space, but uses a SAPIC interrupt, - * we need to program the SAPIC so that serial can autoprobe for - * the IA64 interrupt vector later on. If the device is in PCI - * space, it should already be setup via the PCI vectors - */ - if (spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE && - spcr->int_type == ACPI_SERIAL_INT_SAPIC) - { - u32 irq_base; - char *iosapic_address; - int vector; - - /* We have a UART in memory space with a SAPIC interrupt */ - global_int = ( (spcr->global_int[3] << 24) - | (spcr->global_int[2] << 16) - | (spcr->global_int[1] << 8) - | spcr->global_int[0]); - - if (!iosapic_register_irq) - continue; - - /* which iosapic does this IRQ belong to? */ - if (acpi20_which_iosapic(global_int, madt, &irq_base, - &iosapic_address) == 0) - { - vector = iosapic_register_irq(global_int, - 1, /* active high polarity */ - 1, /* edge triggered */ - irq_base, - iosapic_address); - } - } - } - } -#endif - acpi_cf_terminate(); + spcr = (acpi_ser_t *) __va(phys_addr); + setup_serial_acpi(spcr); -# ifdef CONFIG_SMP - if (available_cpus == 0) { - printk("ACPI: Found 0 CPUS; assuming 1\n"); - available_cpus = 1; /* We've got at least one of these, no? */ + if (spcr->length < sizeof(acpi_ser_t)) + /* Table not long enough for full info, thus no interrupt */ + return -ENODEV; + + if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) && + (spcr->int_type == ACPI_SERIAL_INT_SAPIC)) { + + /* We have a UART in memory space with an SAPIC interrupt */ + + gsi = (spcr->global_int[3] << 24) | + (spcr->global_int[2] << 16) | + (spcr->global_int[1] << 8) | + (spcr->global_int[0]); + + if (!acpi_find_iosapic(gsi, &gsi_base, &iosapic_address)) + iosapic_register_intr(gsi, 1, 1, + gsi_base, iosapic_address); } - smp_boot_data.cpu_count = total_cpus; -# endif -# endif /* CONFIG_ACPI */ - return 1; + return 0; } -/* - * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all - * platforms start supporting ACPI 2.0 - */ +#endif /*CONFIG_SERIAL_ACPI*/ + +#if defined(CONFIG_ACPI) && defined(CONFIG_NUMA) /* - * Identify usable CPU's and remember them for SMP bringup later. + * ACPI 2.0 SRAT Table + * http://www.microsoft.com/HWDEV/design/SRAT.htm + * Processor and Memory affinity information */ -static void __init -acpi_lsapic (char *p) -{ - int add = 1; - acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p; - if ((lsapic->flags & LSAPIC_PRESENT) == 0) - return; +/* bitmap length; _PXM is at most 255*/ +#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/8) - printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id); +static int srat_num_cpus; /* number of cpus */ +static u8 pxm_flag[PXM_FLAG_LEN]; /* bitmap of proximity domains */ - if ((lsapic->flags & LSAPIC_ENABLED) == 0) { - printk("Disabled.\n"); - add = 0; - } else if (lsapic->flags & LSAPIC_PERFORMANCE_RESTRICTED) { - printk("Performance Restricted; ignoring.\n"); - add = 0; - } +struct node_memory_chunk_s node_memory_chunk[PLAT_MAXCLUMPS]; +struct node_cpuid_s node_cpuid[NR_CPUS]; -#ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[total_cpus] = -1; +int pxm_to_nid_map[MAX_PXM_DOMAINS]; /* _PXM to logical node ID map */ +int nid_to_pxm_map[PLAT_MAX_COMPACT_NODES]; /* logical node ID to _PXM map */ +int num_memory_chunks; /* total number of memory chunks */ + +/* Identify which cnode a physical address resides on */ +int +paddr_to_nid(unsigned long paddr) +{ + int i; + + for (i = 0; i < num_memory_chunks; i++) + if (paddr >= node_memory_chunk[i].start_paddr && + paddr < node_memory_chunk[i].start_paddr + node_memory_chunk[i].size) + break; + + return (i < num_memory_chunks) ? pxm_to_nid_map[node_memory_chunk[i].pxm] : -1; +} + +/* Identify CPU proximity domains */ + +static void __init +parse_processor_affinity_structure (char *p) +{ + struct acpi_table_processor_affinity *processor_affinity = + (struct acpi_table_processor_affinity *) p; + int pxm_flag_index; + + /* record this node in node bitmap */ + pxm_flag_index = NODE_ARRAY_INDEX(processor_affinity->proximity_domain); + pxm_flag[pxm_flag_index] |= (1 << NODE_ARRAY_OFFSET(processor_affinity->proximity_domain)); + + node_cpuid[srat_num_cpus].phys_id = (processor_affinity->apic_id << 8) | (processor_affinity->lsapic_eid); + /* nid should be overridden as logical node id later */ + node_cpuid[srat_num_cpus].pxm = processor_affinity->proximity_domain; + srat_num_cpus++; + + if (!processor_affinity->flags.enabled) + printk("NOTE: CPU %x in proximity domain %x disabled\n", + processor_affinity->apic_id, processor_affinity->proximity_domain); + +#ifdef SRAT_DEBUG + printk("CPU %x in proximity domain %x %s\n", + processor_affinity->apic_id, processor_affinity->proximity_domain, + processor_affinity->flags.enabled ? "enabled" : "disabled"); #endif - if (add) { - printk("Available.\n"); - available_cpus++; -#ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; -#endif /* CONFIG_SMP */ - } - total_cpus++; } /* - * Info on platform interrupt sources: NMI. PMI, INIT, etc. + * Identify memory proximity domains and hot-remove capabilities. + * Fill node memory chunk list structure. */ + static void __init -acpi_platform (char *p) +parse_memory_affinity_structure (char *memp) { - acpi_entry_platform_src_t *plat = (acpi_entry_platform_src_t *) p; + struct acpi_table_memory_affinity *memory_affinity = + (struct acpi_table_memory_affinity *) memp; + unsigned long paddr, size; + u8 pxm; + int pxm_flag_index; + struct node_memory_chunk_s *p, *q, *pend; + + pxm = memory_affinity->proximity_domain; + + /* record this node in node bitmap */ + pxm_flag_index = NODE_ARRAY_INDEX(pxm); + pxm_flag[pxm_flag_index] |= (1 << NODE_ARRAY_OFFSET(pxm)); + + /* fill node memory chunk structure */ + paddr = memory_affinity->base_addr_hi; + paddr = (paddr << 32) | memory_affinity->base_addr_lo; + size = memory_affinity->length_hi; + size = (size << 32) | memory_affinity->length_lo; + + if (num_memory_chunks >= PLAT_MAXCLUMPS) { + printk("Too many mem chunks in SRAT. Ignoring %ld MBytes at %lx\n", + size/(1024*1024), paddr); + return; + } - printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n", - plat->iosapic_vector, plat->global_vector, plat->eid, plat->id); + /* Insertion sort based on base address */ + pend = &node_memory_chunk[num_memory_chunks]; + for (p = &node_memory_chunk[0]; p < pend; p++) { + if (paddr < p->start_paddr) + break; + } + if (p < pend) { + for (q = pend; q >= p; q--) + *(q + 1) = *q; + } + p->start_paddr = paddr; + p->size = size; + p->pxm = pxm; + + num_memory_chunks++; + + if ( memory_affinity->flags.enabled) + printk("NOTE: memory 0x%lx to 0x%lx disabled\n", paddr, paddr+size); + +#ifdef SRAT_DEBUG + printk("Memory range 0x%lx to 0x%lx (type %x) in proximity domain %x %s\n", + paddr, paddr + size - 1, + memory_affinity->memory_type, + memory_affinity->proximity_domain, + memory_affinity->flags.enabled + ? (memory_affinity->flags.hot_pluggable ? "enabled and removable" : "enabled" ) + : "disabled"); +#endif } -/* - * Parse the ACPI Multiple SAPIC Table - */ +/* Parse the ACPI Static Resource Affinity Table */ static void __init -acpi_parse_msapic (acpi_sapic_t *msapic) +acpi_parse_srat (struct acpi_table_srat *srat) { - acpi_entry_iosapic_t *iosapic; char *p, *end; + u32 mask; + int i, j; - /* Base address of IPI Message Block */ - ipi_base_addr = (unsigned long) ioremap(msapic->interrupt_block, 0); + memset(pxm_flag, 0, PXM_FLAG_LEN); /* init proximity domain bitmap */ + memset(node_memory_chunk, 0, sizeof(node_memory_chunk)); + memset(node_cpuid, 0, sizeof(node_cpuid)); - p = (char *) (msapic + 1); - end = p + (msapic->header.length - sizeof(acpi_sapic_t)); + memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map)); + memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map)); + p = (char *) (srat + 1); /* skip header */ + end = p + (srat->header.length - sizeof(struct acpi_table_srat)); + + num_memory_chunks = 0; while (p < end) { switch (*p) { - case ACPI_ENTRY_LOCAL_SAPIC: - acpi_lsapic(p); - break; - - case ACPI_ENTRY_IO_SAPIC: - iosapic = (acpi_entry_iosapic_t *) p; - if (iosapic_init) - /* - * The ACPI I/O SAPIC table doesn't have a PCAT_COMPAT - * flag like the MADT table, but we can safely assume that - * ACPI 1.0b systems have a dual-8259 setup. - */ - iosapic_init(iosapic->address, iosapic->irq_base, 1); + case ACPI_SRAT_PROCESSOR_AFFINITY: +#ifdef SRAT_DEBUG + printk("ACPI 2.0 SRAT: Processor Local APIC/SAPIC Affinity Structure\n"); +#endif + parse_processor_affinity_structure(p); break; - - case ACPI_ENTRY_INT_SRC_OVERRIDE: - acpi_legacy_irq(p); + case ACPI_SRAT_MEMORY_AFFINITY: +#ifdef SRAT_DEBUG + printk("ACPI 2.0 SRAT: Memory Affinity Structure\n"); +#endif + parse_memory_affinity_structure(p); break; - - case ACPI_ENTRY_PLATFORM_INT_SOURCE: - acpi_platform(p); + default: + printk("ACPI 2.0 SRAT: unknown entry skip\n"); break; + } + p += p[1]; + } - default: - break; + /* calculate total number of nodes in system from PXM bitmap */ + numnodes = 0; /* init total nodes in system */ + for (i = 0; i < PXM_FLAG_LEN; i++) { + mask = 1; + for (j = 0; j < 8; j++) { + if (pxm_flag[i] & mask) { + pxm_to_nid_map[(8*i)+j] = numnodes; + nid_to_pxm_map[numnodes++] = (8*i)+j; + } + mask <<= 1; } + } - /* Move to next table entry. */ - p += p[1]; + /* set cnode id in memory chunk structure */ + for (i = 0; i < num_memory_chunks; i++) + node_memory_chunk[i].nid = pxm_to_nid_map[node_memory_chunk[i].pxm]; + + /* assign memory bank numbers for each chunk on each node */ + for (i = 0; i < numnodes; i++) { + int bank; + + bank = 0; + for (j = 0; j < num_memory_chunks; j++) + if (node_memory_chunk[j].nid == i) + node_memory_chunk[j].bank = bank++; + } + + /* set cnode id in cpu structure */ + for (i = 0; i < srat_num_cpus; i++) + node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].pxm]; + + printk("Number of logical nodes in system = %d\n", numnodes); + printk("Number of memory chunks in system = %d\n", num_memory_chunks); +} + + +/* + * ACPI 2.0 SLIT (System Locality Information Table) + * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/ + */ + +u8 acpi20_slit[PLAT_MAX_COMPACT_NODES * PLAT_MAX_COMPACT_NODES]; +#define node_distance(from,to) (acpi20_slit[from * numnodes + to]) + +static int __init +acpi_parse_slit (unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_slit *slit; + int i, j, pnode_from, pnode_to, cnode_from, cnode_to; + u32 len; + + if (!phys_addr || !size) + return -EINVAL; + + slit = (struct acpi_table_slit *) __va(phys_addr); + if (!slit) { + printk(KERN_WARNING PREFIX "Unable to map SLIT\n"); + return -ENODEV; + } + + len = sizeof(struct acpi_table_header) + 8 + slit->localities * slit->localities; + if (slit->header.length != len) { + printk("ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", + len, slit->header.length); + return -EINVAL; + } + + memset(acpi20_slit, -1, sizeof(acpi20_slit)); + for (i=0; ilocalities; i++) { + pnode_from = PLAT_PXM_TO_PHYS_NODE_NUMBER(i); + if (!phys_node_present(pnode_from)) + continue; + cnode_from = phys_node_to_cnodeid(pnode_from); + for (j=0; jlocalities; j++) { + pnode_to = PLAT_PXM_TO_PHYS_NODE_NUMBER(j); + if (!phys_node_present(pnode_to)) + continue; + cnode_to = phys_node_to_cnodeid(pnode_to); + node_distance(cnode_from, cnode_to) = slit->entry[i*slit->localities + j]; + } } - /* Make bootup pretty */ - printk(" %d CPUs available, %d CPUs total\n", available_cpus, total_cpus); +#ifdef SLIT_DEBUG + printk("ACPI 2.0 SLIT locality table:\n"); + for (i = 0; i < numnodes; i++) { + for (j = 0; j < numnodes; j++) + printk("%03d ", node_distance(i,j)); + printk("\n"); + } +#endif + return 0; } +/* + * If firmware doesn't provide us with SRAT and/or SLIT tables + * we assume some defaults (which are currently set to facilitate + * ccNUMA testing on BigSur/Tiger ... we need to revisit this later to + * provide more useful default information). + */ +static char __initdata phoney_srat[] = { + /* signature */ "SRAT" +#ifdef CONFIG_MCKINLEY + /* length */ "\300\0\0\0" +#else + /* length */ "\240\0\0\0" +#endif + /* revision */ "0" + /* checksum */ "\203" + /* OEMID */ "PHONEY" + /* OEMTBLID */ "[-fake-]" + /* OEMREV*/ "0000" + /* CreatId */ "aegl" + /* CreatRev */ "0000" + + /* tablerev */ "\0\0\0\0" + /* reserved */ "\0\0\0\0\0\0\0\0" + +#ifdef CONFIG_MCKINLEY + /* CPU 0 on node 0 */ + /* type[cpu] */ "\0" + /* len */ "\20" + /* PXM */ "\0" + /* apic_id */ "\306" + /* flags */ "\1\0\0\0" + /* sapic_eid */ "\30" + /* rsvd[7] */ "\0\0\0\0\0\0\0" + + /* CPU 1 on node 0 */ + /* type[cpu] */ "\0" + /* len */ "\20" + /* PXM */ "\0" + /* apic_id */ "\304" + /* flags */ "\1\0\0\0" + /* sapic_eid */ "\30" + /* rsvd[7] */ "\0\0\0\0\0\0\0" + + /* CPU 2 on node 1 */ + /* type[cpu] */ "\0" + /* len */ "\20" + /* PXM */ "\1" + /* apic_id */ "\302" + /* flags */ "\1\0\0\0" + /* sapic_eid */ "\30" + /* rsvd[7] */ "\0\0\0\0\0\0\0" + + /* CPU 3 on node 1 */ + /* type[cpu] */ "\0" + /* len */ "\20" + /* PXM */ "\1" + /* apic_id */ "\300" + /* flags */ "\1\0\0\0" + /* sapic_eid */ "\30" + /* rsvd[7] */ "\0\0\0\0\0\0\0" +#else + /* CPU 0 on node 0 */ + /* type[cpu] */ "\0" + /* len */ "\20" + /* PXM */ "\0" + /* apic_id */ "\0" + /* flags */ "\1\0\0\0" + /* sapic_eid */ "\0" + /* rsvd[7] */ "\0\0\0\0\0\0\0" + + /* CPU 1 on node 1 */ + /* type[cpu] */ "\0" + /* len */ "\20" + /* PXM */ "\1" + /* apic_id */ "\3" + /* flags */ "\1\0\0\0" + /* sapic_eid */ "\0" + /* rsvd[7] */ "\0\0\0\0\0\0\0" +#endif + + /* Memory from 0-512M on node 0 */ + /* type[mem] */ "\1" + /* len */ "\50" + /* PXM */ "\0" + /* rsvd[5] */ "\0\0\0\0\0" + /* base lo+hi*/ "\0\0\0\0" "\0\0\0\0" + /* len lo+hi*/ "\0\0\0\40" "\0\0\0\0" + /* memtype */ "\1\0\0\0" + /* flags */ "\1\0\0\0" + /* reserved */ "\0\0\0\0\0\0\0\0" + + /* Memory from 512-1024M on node 1 */ + /* type[mem] */ "\1" + /* len */ "\50" + /* PXM */ "\1" + /* rsvd[5] */ "\0\0\0\0\0" + /* base lo+hi*/ "\0\0\0\40" "\0\0\0\0" + /* len lo+hi*/ "\0\0\0\40" "\0\0\0\0" + /* memtype */ "\1\0\0\0" + /* flags */ "\3\0\0\0" + /* reserved */ "\0\0\0\0\0\0\0\0" +}; + +static char __initdata phoney_slit[] = { + /* signature */ "SLIT" + /* length */ "\074\0\0\0" + /* revision */ "0" + /* checksum */ "\343" + /* OEMID */ "PHONEY" + /* OEMTBLID */ "[-fake-]" + /* OEMREV*/ "0000" + /* CreatId */ "aegl" + /* CreatRev */ "0000" + + /* localities*/ "\4\0\0\0\0\0\0\0" + + /* entries */ "\12\17\17\17" + "\17\12\17\17" + "\17\17\12\17" + "\17\17\17\12" +}; +#endif /* CONFIG_APCI && CONFIG_NUMA */ + +/* Only parses SRAT table */ int __init -acpi_parse (acpi_rsdp_t *rsdp) +acpi_early_init () { -# ifdef CONFIG_ACPI - acpi_rsdt_t *rsdt; - acpi_desc_table_hdr_t *hdrp; - long tables, i; +#if defined(CONFIG_ACPI) && defined(CONFIG_NUMA) + struct acpi20_table_rsdp *rsdp; + struct acpi_table_xsdt *xsdt; + struct acpi_table_header *header; + struct acpi_table_srat *srat = NULL; + int tables, i; - if (strncmp(rsdp->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) { - printk("Uh-oh, ACPI RSDP signature incorrect!\n"); - return 0; + rsdp = efi.acpi20; + + if (strncmp(rsdp->signature, "RSD PTR ", 8)) { + printk("EARLY ACPI 2.0 RSDP signature incorrect!\n"); + goto done; + } + + xsdt = __va(rsdp->xsdt_address); + if (strncmp(xsdt->header.signature, "XSDT", 4)) { + printk("EARLY ACPI 2.0 XSDT signature incorrect!\n"); + goto done; } + /* TBD: checksumming */ - rsdt = __va(rsdp->rsdt); - if (strncmp(rsdt->header.signature, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN)) { - printk("Uh-oh, ACPI RDST signature incorrect!\n"); - return 0; + tables = (xsdt->header.length - sizeof(struct acpi_table_header)) / 8; + + for (i = 0; i < tables; i++) { + header = __va(xsdt->entry[i]); + + /* TBD: table checksumming */ + + if (strncmp(header->signature, "SRAT", 4) == 0) + srat = (struct acpi_table_srat *) header; } - printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, - rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff); + done: + if (srat == NULL) { + printk("Using Phoney SRAT table\n"); + srat = (struct acpi_table_srat *) phoney_srat; + } - acpi_cf_init(rsdp); + acpi_parse_srat(srat); - tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8; - for (i = 0; i < tables; i++) { - hdrp = (acpi_desc_table_hdr_t *) __va(rsdt->entry_ptrs[i]); +#endif /* CONFIG_ACPI && CONFIG_NUMA */ + return 0; +} - /* Only interested int the MSAPIC table for now ... */ - if (strncmp(hdrp->signature, ACPI_SAPIC_SIG, ACPI_SAPIC_SIG_LEN) != 0) - continue; - acpi_parse_msapic((acpi_sapic_t *) hdrp); +unsigned long __init +acpi_find_rsdp (void) +{ + unsigned long rsdp_phys = 0; + + if (efi.acpi20) + rsdp_phys = __pa(efi.acpi20); + else if (efi.acpi) + printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n"); + + return rsdp_phys; +} + + +int __init +acpi_boot_init (char *cmdline) +{ + int result; + + /* Initialize the ACPI boot-time table parser */ + result = acpi_table_init(cmdline); + if (result) + return result; + + /* + * MADT + * ---- + * Parse the Multiple APIC Description Table (MADT), if exists. + * Note that this table provides platform SMP configuration + * information -- the successor to MPS tables. + */ + + if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) { + printk(KERN_ERR PREFIX "Can't find MADT\n"); + goto skip_madt; } - acpi_cf_terminate(); + /* Local APIC */ + + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, + acpi_parse_lapic_addr_ovr) < 0) + printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); + + if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, + acpi_parse_lsapic) < 1) + printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); + + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, + acpi_parse_lapic_nmi) < 0) + printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); + + /* I/O APIC */ + +#ifndef CONFIG_IA64_SGI_SN + if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, + acpi_parse_iosapic) < 1) + printk(KERN_ERR PREFIX "Error parsing MADT - no IOAPIC entries\n"); +#endif -# ifdef CONFIG_SMP + /* System-Level Interrupt Routing */ + + if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, + acpi_parse_plat_int_src) < 0) + printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n"); + + if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, + acpi_parse_int_src_ovr) < 0) + printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); + + if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, + acpi_parse_nmi_src) < 0) + printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); +skip_madt: + + /* + * The FADT table contains an SCI_INT line, by which the system + * gets interrupts such as power and sleep buttons. If it's not + * on a Legacy interrupt, it needs to be setup. + */ + if (acpi_table_parse(ACPI_FACP, acpi_parse_fadt) < 1) + Dprintk(KERN_ERR PREFIX "Can't find FADT\n"); + +#ifdef CONFIG_NUMA + result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit); + if (result == 0) + acpi_parse_slit((unsigned long)phoney_slit, 1); +#endif + +#ifdef CONFIG_SERIAL_ACPI + acpi_table_parse(ACPI_SPCR, acpi_parse_spcr); +#endif + +#ifdef CONFIG_SMP if (available_cpus == 0) { printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } smp_boot_data.cpu_count = total_cpus; -# endif -# endif /* CONFIG_ACPI */ - return 1; +#endif + /* Make boot-up look pretty */ + printk("%d CPUs available, %d CPUs total\n", available_cpus, total_cpus); + return 0; } + + +/* -------------------------------------------------------------------------- + PCI Interrupt Routing + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_PCI +int __init +acpi_get_prt (struct pci_vector_struct **vectors, int *count) +{ + struct pci_vector_struct *vector; + struct list_head *node; + struct acpi_prt_entry *entry; + int i = 0; + + if (!vectors || !count) + return -EINVAL; + + *vectors = NULL; + *count = 0; + + if (acpi_prt.count < 0) { + printk(KERN_ERR PREFIX "No PCI interrupt routing entries\n"); + return -ENODEV; + } + + /* Allocate vectors */ + + *vectors = kmalloc(sizeof(struct pci_vector_struct) * acpi_prt.count, GFP_KERNEL); + if (!(*vectors)) + return -ENOMEM; + + /* Convert PRT entries to IOSAPIC PCI vectors */ + + vector = *vectors; + + list_for_each(node, &acpi_prt.entries) { + entry = (struct acpi_prt_entry *)node; + vector[i].segment = entry->id.segment; + vector[i].bus = entry->id.bus; + vector[i].pci_id = ((u32) entry->id.device << 16) | 0xffff; + vector[i].pin = entry->pin; + vector[i].irq = entry->link.index; + i++; + } + *count = acpi_prt.count; + return 0; +} + +/* Assume IA64 always use I/O SAPIC */ + +int __init +acpi_get_interrupt_model (int *type) +{ + if (!type) + return -EINVAL; + + *type = ACPI_IRQ_MODEL_IOSAPIC; + return 0; +} + +int +acpi_irq_to_vector (u32 irq) +{ +#ifdef CONFIG_IA64_SGI_SN + return -1; +#else + if (has_8259 && irq < 16) + return isa_irq_to_vector(irq); + + return gsi_to_vector(irq); +#endif +} + +#endif /* CONFIG_ACPI_PCI */ +#endif /* CONFIG_ACPI_BOOT */ diff -Nur linux-2.4.19/arch/ia64/kernel/efi.c linux-2.4.19-sgi211r3/arch/ia64/kernel/efi.c --- linux-2.4.19/arch/ia64/kernel/efi.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/efi.c Fri Feb 7 08:55:45 2003 @@ -5,7 +5,7 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999-2001 Hewlett-Packard Co. + * Copyright (C) 1999-2002 Hewlett-Packard Co. * David Mosberger-Tang * Stephane Eranian * @@ -24,8 +24,8 @@ #include #include #include +#include -#include #include #include #include @@ -51,83 +51,243 @@ static unsigned long mem_limit = ~0UL; -static efi_status_t -phys_get_time (efi_time_t *tm, efi_time_cap_t *tc) -{ - return efi_call_phys(__va(runtime->get_time), __pa(tm), __pa(tc)); -} +#define efi_call_virt(f, args...) (*(f))(args) -static efi_status_t -phys_set_time (efi_time_t *tm) -{ - return efi_call_phys(__va(runtime->set_time), __pa(tm)); -} +#define STUB_GET_TIME(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_get_time_t *) (runtime->get_time), adjust_arg(tm), \ + adjust_arg(tc)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_SET_TIME(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_set_time (efi_time_t *tm) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_set_time_t *) (runtime->set_time), adjust_arg(tm)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_get_wakeup_time_t *) (runtime->get_wakeup_time), \ + adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_set_wakeup_time_t *) (runtime->set_wakeup_time), \ + enabled, adjust_arg(tm)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_GET_VARIABLE(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, \ + unsigned long *data_size, void *data) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_get_variable_t *) (runtime->get_variable), \ + adjust_arg(name), adjust_arg(vendor), adjust_arg(attr), \ + adjust_arg(data_size), adjust_arg(data)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_get_next_variable_t *) (runtime->get_next_variable), \ + adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_SET_VARIABLE(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr, \ + unsigned long data_size, void *data) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_set_variable_t *) (runtime->set_variable), \ + adjust_arg(name), adjust_arg(vendor), attr, data_size, \ + adjust_arg(data)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_get_next_high_mono_count (u64 *count) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_status_t ret; \ + \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_get_next_high_mono_count_t *) \ + (runtime->get_next_high_mono_count), adjust_arg(count)); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ +} + +#define STUB_RESET_SYSTEM(prefix, adjust_arg) \ +static void \ +prefix##_reset_system (int reset_type, efi_status_t status, \ + unsigned long data_size, efi_char16_t *data) \ +{ \ + struct ia64_fpreg fr[6]; \ + \ + ia64_save_scratch_fpregs(fr); \ + efi_call_##prefix((efi_reset_system_t *) (runtime->reset_system), \ + reset_type, status, data_size, adjust_arg(data)); \ + /* should not return, but just in case... */ \ + ia64_load_scratch_fpregs(fr); \ +} + +STUB_GET_TIME(phys, __pa) +STUB_SET_TIME(phys, __pa) +STUB_GET_WAKEUP_TIME(phys, __pa) +STUB_SET_WAKEUP_TIME(phys, __pa) +STUB_GET_VARIABLE(phys, __pa) +STUB_GET_NEXT_VARIABLE(phys, __pa) +STUB_SET_VARIABLE(phys, __pa) +STUB_GET_NEXT_HIGH_MONO_COUNT(phys, __pa) +STUB_RESET_SYSTEM(phys, __pa) + +STUB_GET_TIME(virt, ) +STUB_SET_TIME(virt, ) +STUB_GET_WAKEUP_TIME(virt, ) +STUB_SET_WAKEUP_TIME(virt, ) +STUB_GET_VARIABLE(virt, ) +STUB_GET_NEXT_VARIABLE(virt, ) +STUB_SET_VARIABLE(virt, ) +STUB_GET_NEXT_HIGH_MONO_COUNT(virt, ) +STUB_RESET_SYSTEM(virt, ) -static efi_status_t -phys_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) +void +efi_gettimeofday (struct timeval *tv) { - return efi_call_phys(__va(runtime->get_wakeup_time), __pa(enabled), __pa(pending), - __pa(tm)); -} + efi_time_t tm; -static efi_status_t -phys_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) -{ - return efi_call_phys(__va(runtime->set_wakeup_time), enabled, __pa(tm)); -} + memset(tv, 0, sizeof(tv)); + if ((*efi.get_time)(&tm, 0) != EFI_SUCCESS) + return; -static efi_status_t -phys_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, - unsigned long *data_size, void *data) -{ - return efi_call_phys(__va(runtime->get_variable), __pa(name), __pa(vendor), __pa(attr), - __pa(data_size), __pa(data)); + tv->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); + tv->tv_usec = tm.nanosecond / 1000; } -static efi_status_t -phys_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) +static int +is_available_memory (efi_memory_desc_t *md) { - return efi_call_phys(__va(runtime->get_next_variable), __pa(name_size), __pa(name), - __pa(vendor)); -} + if (!(md->attribute & EFI_MEMORY_WB)) + return 0; -static efi_status_t -phys_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr, - unsigned long data_size, void *data) -{ - return efi_call_phys(__va(runtime->set_variable), __pa(name), __pa(vendor), attr, - data_size, __pa(data)); + switch (md->type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + return 1; + } + return 0; } -static efi_status_t -phys_get_next_high_mono_count (u64 *count) +/* + * Trim descriptor MD so its starts at address START_ADDR. If the descriptor covers + * memory that is normally available to the kernel, issue a warning that some memory + * is being ignored. + */ +static void +trim_bottom (efi_memory_desc_t *md, u64 start_addr) { - return efi_call_phys(__va(runtime->get_next_high_mono_count), __pa(count)); + u64 num_skipped_pages; + + if (md->phys_addr >= start_addr || !md->num_pages) + return; + + num_skipped_pages = (start_addr - md->phys_addr) >> EFI_PAGE_SHIFT; + if (num_skipped_pages > md->num_pages) + num_skipped_pages = md->num_pages; + + if (is_available_memory(md)) + printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole " + "at 0x%lx\n", __FUNCTION__, + (num_skipped_pages << EFI_PAGE_SHIFT) >> 10, + md->phys_addr, start_addr - IA64_GRANULE_SIZE); + /* + * NOTE: Don't set md->phys_addr to START_ADDR because that could cause the memory + * descriptor list to become unsorted. In such a case, md->num_pages will be + * zero, so the Right Thing will happen. + */ + md->phys_addr += num_skipped_pages << EFI_PAGE_SHIFT; + md->num_pages -= num_skipped_pages; } static void -phys_reset_system (int reset_type, efi_status_t status, - unsigned long data_size, efi_char16_t *data) +trim_top (efi_memory_desc_t *md, u64 end_addr) { - efi_call_phys(__va(runtime->reset_system), status, data_size, __pa(data)); -} + u64 num_dropped_pages, md_end_addr; -void -efi_gettimeofday (struct timeval *tv) -{ - efi_time_t tm; + md_end_addr = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); - memset(tv, 0, sizeof(tv)); - if ((*efi.get_time)(&tm, 0) != EFI_SUCCESS) + if (md_end_addr <= end_addr || !md->num_pages) return; - tv->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); - tv->tv_usec = tm.nanosecond / 1000; + num_dropped_pages = (md_end_addr - end_addr) >> EFI_PAGE_SHIFT; + if (num_dropped_pages > md->num_pages) + num_dropped_pages = md->num_pages; + + if (is_available_memory(md)) + printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole " + "at 0x%lx\n", __FUNCTION__, + (num_dropped_pages << EFI_PAGE_SHIFT) >> 10, + md->phys_addr, end_addr); + md->num_pages -= num_dropped_pages; } /* - * Walks the EFI memory map and calls CALLBACK once for each EFI - * memory descriptor that has memory that is available for OS use. + * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that + * has memory that is available for OS use. */ void efi_memmap_walk (efi_freemem_callback_t callback, void *arg) @@ -137,9 +297,9 @@ u64 start; u64 end; } prev, curr; - void *efi_map_start, *efi_map_end, *p; - efi_memory_desc_t *md; - u64 efi_desc_size, start, end; + void *efi_map_start, *efi_map_end, *p, *q; + efi_memory_desc_t *md, *check_md; + u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0; efi_map_start = __va(ia64_boot_param->efi_memmap); efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; @@ -147,27 +307,59 @@ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; - switch (md->type) { - case EFI_LOADER_CODE: - case EFI_LOADER_DATA: - case EFI_BOOT_SERVICES_CODE: - case EFI_BOOT_SERVICES_DATA: - case EFI_CONVENTIONAL_MEMORY: - if (!(md->attribute & EFI_MEMORY_WB)) - continue; - if (md->phys_addr + (md->num_pages << 12) > mem_limit) { + + /* skip over non-WB memory descriptors; that's all we're interested in... */ + if (!(md->attribute & EFI_MEMORY_WB)) + continue; + + if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > first_non_wb_addr) { + /* + * Search for the next run of contiguous WB memory. Start search + * at first granule boundary covered by md. + */ + granule_addr = ((md->phys_addr + IA64_GRANULE_SIZE - 1) + & -IA64_GRANULE_SIZE); + first_non_wb_addr = granule_addr; + for (q = p; q < efi_map_end; q += efi_desc_size) { + check_md = q; + + if (check_md->attribute & EFI_MEMORY_WB) + trim_bottom(md, granule_addr); + + if (check_md->phys_addr < granule_addr) + continue; + + if (!(check_md->attribute & EFI_MEMORY_WB)) + break; /* hit a non-WB region; stop search */ + + if (check_md->phys_addr != first_non_wb_addr) + break; /* hit a memory hole; stop search */ + + first_non_wb_addr += check_md->num_pages << EFI_PAGE_SHIFT; + } + /* round it down to the previous granule-boundary: */ + first_non_wb_addr &= -IA64_GRANULE_SIZE; + + if (!(first_non_wb_addr > granule_addr)) + continue; /* couldn't find enough contiguous memory */ + } + + /* BUG_ON((md->phys_addr >> IA64_GRANULE_SHIFT) < first_non_wb_addr); */ + + trim_top(md, first_non_wb_addr); + + if (is_available_memory(md)) { + if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) { if (md->phys_addr > mem_limit) continue; - md->num_pages = (mem_limit - md->phys_addr) >> 12; + md->num_pages = (mem_limit - md->phys_addr) >> EFI_PAGE_SHIFT; } - if (md->num_pages == 0) { - printk("efi_memmap_walk: ignoring empty region at 0x%lx", - md->phys_addr); + + if (md->num_pages == 0) continue; - } curr.start = PAGE_OFFSET + md->phys_addr; - curr.end = curr.start + (md->num_pages << 12); + curr.end = curr.start + (md->num_pages << EFI_PAGE_SHIFT); if (!prev_valid) { prev = curr; @@ -187,10 +379,6 @@ prev = curr; } } - break; - - default: - continue; } } if (prev_valid) { @@ -202,9 +390,45 @@ } /* + * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that + * has memory that marked as only EFI_MEMORY_UC. + */ +void +efi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size, start, end; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + + if (md->attribute == EFI_MEMORY_UC) { + start = PAGE_ALIGN(md->phys_addr); + end = PAGE_ALIGN((md->phys_addr+(md->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK); + if ((*callback)(start, end, arg) < 0) + return; + } + } +} + +/* * Look for the PAL_CODE region reported by EFI and maps it using an * ITR to enable safe PAL calls in virtual mode. See IA-64 Processor * Abstraction Layer chapter 11 in ADAG + * + * Note that if the granule containing the PAL has non-WB pages, the + * trimming code above will destroy the data in md->phys_addr and md->num_pages, + * so we need to save them off so the secondaries will start up correctly. + * + * Also note that the alt-itlb miss handler (the handler setup to handle faults + * for region 7) will default to using IA64_GRANULE_SIZE for that region when + * it inserts a TLB entry for the missing memory. This has the potential to cause + * an MCA if the translation register below overlaps with the newly inserted region. */ void efi_map_pal_code (void) @@ -212,9 +436,11 @@ void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; u64 efi_desc_size; - int pal_code_count=0; - u64 mask, flags; + int pal_code_count = 0; + u64 mask, psr; u64 vaddr; + static u64 phys_addr = 0, num_pages = 0, pal_end; + int pg_shift; efi_map_start = __va(ia64_boot_param->efi_memmap); efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; @@ -230,12 +456,42 @@ md->phys_addr); continue; } + + /* + * Save off phys_addr and num_pages for later + * since memmap_walk and trim_bottom might hose + * them later. + */ + if (!phys_addr) + phys_addr = md->phys_addr; + if (!num_pages) + num_pages = md->num_pages; + + /* end address of the PAL */ + pal_end = phys_addr + (num_pages << EFI_PAGE_SHIFT); + + /* Find out the smallest page with which we can map the PAL */ + for (pg_shift = _PAGE_SIZE_64K; pg_shift <= IA64_GRANULE_SHIFT; pg_shift += 2) { + /* round the start address down to our test page size */ + unsigned long start = phys_addr & (~((1 << pg_shift) - 1)); + + /* does the test page size cover the newly aligned size? */ + if ((1 << pg_shift) >= (pal_end - start)) + break; + } + /* + * On some platforms, the PAL is in the same granule as + * EFI or the SAL, so we need to map them all. + */ +#ifndef CONFIG_IA64_SGI_SN2 + pg_shift = IA64_GRANULE_SHIFT; +#endif + /* * The only ITLB entry in region 7 that is used is the one installed by * __start(). That entry covers a 64MB range. */ - mask = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1); - vaddr = PAGE_OFFSET + md->phys_addr; + vaddr = __va(phys_addr); /* * We must check that the PAL mapping won't overlap with the kernel @@ -248,27 +504,39 @@ * cross a 64MB unless it is bigger than 64MB (very unlikely!). So for * now the following test is enough to determine whether or not we need a * dedicated ITR for the PAL code. + * + * We set mask here, and then again below, because we want to test + * the PAL address against the kernel page size here. */ + mask = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1); if ((vaddr & mask) == (KERNEL_START & mask)) { - printk(__FUNCTION__ ": no need to install ITR for PAL code\n"); + printk("%s: no need to install ITR for PAL code\n", __FUNCTION__); continue; } - if (md->num_pages << 12 > IA64_GRANULE_SIZE) + if ((1 << pg_shift) > IA64_GRANULE_SIZE) panic("Woah! PAL code size bigger than a granule!"); - mask = ~((1 << IA64_GRANULE_SHIFT) - 1); - printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", - smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12), - vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE); - + /* + * This will mask off the bits we care about for the PAL mapping + * page size we've chosen in the loop above. + */ + mask = ~((1 << pg_shift) - 1); +#if EFI_DEBUG + printk("CPU %d: actual PAL range phys: 0x%lx-0x%lx\n", smp_processor_id(), + phys_addr, phys_addr + (num_pages << EFI_PAGE_SHIFT)); + printk("CPU %d: PAL mapping from phys:0x%lx-0x%lx to virt:0x%lx-0x%lx\n", + smp_processor_id(), phys_addr & mask, + (phys_addr & mask) + (1 << pg_shift), + vaddr & mask, (vaddr & mask) + (1 << pg_shift)); +#endif /* * Cannot write to CRx with PSR.ic=1 */ - ia64_clear_ic(flags); + psr = ia64_clear_ic(); ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask, - pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), IA64_GRANULE_SHIFT); - local_irq_restore(flags); + pte_val(mk_pte_phys((phys_addr & mask), PAGE_KERNEL)), pg_shift); + ia64_set_psr(psr); /* restore psr */ ia64_srlz_i(); } } @@ -378,7 +646,8 @@ md = p; printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", i, md->type, md->attribute, md->phys_addr, - md->phys_addr + (md->num_pages<<12) - 1, md->num_pages >> 8); + md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), + md->num_pages >> (20 - EFI_PAGE_SHIFT)); } } #endif @@ -445,18 +714,17 @@ } /* - * Now that EFI is in virtual mode, we arrange for EFI functions to be - * called directly: + * Now that EFI is in virtual mode, we call the EFI functions more efficiently: */ - efi.get_time = __va(runtime->get_time); - efi.set_time = __va(runtime->set_time); - efi.get_wakeup_time = __va(runtime->get_wakeup_time); - efi.set_wakeup_time = __va(runtime->set_wakeup_time); - efi.get_variable = __va(runtime->get_variable); - efi.get_next_variable = __va(runtime->get_next_variable); - efi.set_variable = __va(runtime->set_variable); - efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count); - efi.reset_system = __va(runtime->reset_system); + efi.get_time = virt_get_time; + efi.set_time = virt_set_time; + efi.get_wakeup_time = virt_get_wakeup_time; + efi.set_wakeup_time = virt_set_wakeup_time; + efi.get_variable = virt_get_variable; + efi.get_next_variable = virt_get_next_variable; + efi.set_variable = virt_set_variable; + efi.get_next_high_mono_count = virt_get_next_high_mono_count; + efi.reset_system = virt_reset_system; } /* @@ -485,8 +753,50 @@ return 0; } +u32 +efi_mem_type (unsigned long phys_addr) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + + if ((md->phys_addr <= phys_addr) && (phys_addr <= + (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1))) + return md->type; + } + return 0; +} + +u64 +efi_mem_attributes (unsigned long phys_addr) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + + if ((md->phys_addr <= phys_addr) && (phys_addr <= + (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1))) + return md->attribute; + } + return 0; +} + static void __exit -efivars_exit(void) +efivars_exit (void) { #ifdef CONFIG_PROC_FS remove_proc_entry(efi_dir->name, NULL); diff -Nur linux-2.4.19/arch/ia64/kernel/efi_stub.S linux-2.4.19-sgi211r3/arch/ia64/kernel/efi_stub.S --- linux-2.4.19/arch/ia64/kernel/efi_stub.S Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/efi_stub.S Tue Aug 27 19:53:13 2002 @@ -53,29 +53,27 @@ mov loc4=ar.rsc // save RSE configuration mov ar.rsc=0 // put RSE in enforced lazy, LE mode ;; - ld8 gp=[in0] // load EFI function's global pointer - mov out0=in1 - mov out1=in2 movl r16=PSR_BITS_TO_CLEAR - mov loc3=psr // save processor status word movl r17=PSR_BITS_TO_SET ;; - mov out2=in3 or loc3=loc3,r17 mov b6=r2 ;; andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared - mov out3=in4 - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret0: mov out4=in5 + mov out0=in1 + mov out1=in2 + mov out2=in3 + mov out3=in4 mov out5=in6 mov out6=in7 br.call.sptk.many rp=b6 // call the EFI function .ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration mov ar.pfs=loc1 mov rp=loc0 diff -Nur linux-2.4.19/arch/ia64/kernel/efivars.c linux-2.4.19-sgi211r3/arch/ia64/kernel/efivars.c --- linux-2.4.19/arch/ia64/kernel/efivars.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/efivars.c Wed Oct 16 14:02:58 2002 @@ -29,6 +29,9 @@ * * Changelog: * + * 25 Mar 2002 - Matt Domsch + * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse() + * * 12 Feb 2002 - Matt Domsch * use list_for_each_safe when deleting vars. * remove ifdef CONFIG_SMP around include @@ -62,15 +65,15 @@ #include #include #include +#include -#include #include MODULE_AUTHOR("Matt Domsch "); MODULE_DESCRIPTION("/proc interface to EFI Variables"); MODULE_LICENSE("GPL"); -#define EFIVARS_VERSION "0.04 2002-Feb-12" +#define EFIVARS_VERSION "0.05 2002-Mar-26" static int efivar_read(char *page, char **start, off_t off, @@ -141,20 +144,6 @@ return len; } - -static void -uuid_unparse(efi_guid_t *guid, char *out) -{ - sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - guid->data1, guid->data2, guid->data3, - guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3], - guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); -} - - - - - /* * efivar_create_proc_entry() * Requires: @@ -197,7 +186,7 @@ private variables from another's. */ *(short_name + strlen(short_name)) = '-'; - uuid_unparse(vendor_guid, short_name + strlen(short_name)); + efi_guid_unparse(vendor_guid, short_name + strlen(short_name)); /* Create the entry in proc */ diff -Nur linux-2.4.19/arch/ia64/kernel/entry.S linux-2.4.19-sgi211r3/arch/ia64/kernel/entry.S --- linux-2.4.19/arch/ia64/kernel/entry.S Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/entry.S Mon Oct 28 20:43:23 2002 @@ -3,7 +3,7 @@ * * Kernel entry points. * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2002 Hewlett-Packard Co * David Mosberger-Tang * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond @@ -141,15 +141,12 @@ ;; st8 [r22]=sp // save kernel stack pointer of old task shr.u r26=r20,IA64_GRANULE_SHIFT - shr.u r17=r20,KERNEL_TR_PAGE_SHIFT - ;; - cmp.ne p6,p7=KERNEL_TR_PAGE_NUM,r17 adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; /* * If we've already mapped this task's page, we can skip doing it again. */ -(p6) cmp.eq p7,p6=r26,r27 + cmp.eq p7,p6=r26,r27 (p6) br.cond.dpnt .map ;; .done: @@ -161,7 +158,8 @@ mov r8=r13 // return pointer to previously running task mov r13=in0 // set "current" pointer ;; -(p6) ssm psr.i // renable psr.i AFTER the ic bit is serialized +//(p6) ssm psr.i // interrupt delivery should not be enabled + // with the new O(1) MQ scheduler DO_LOAD_SWITCH_STACK #ifdef CONFIG_SMP @@ -170,7 +168,7 @@ br.ret.sptk.many rp // boogie on out in new context .map: - rsm psr.i | psr.ic + rsm psr.ic movl r25=PAGE_KERNEL ;; srlz.d @@ -667,23 +665,38 @@ /* * To prevent leaking bits between the kernel and user-space, * we must clear the stacked registers in the "invalid" partition here. - * Not pretty, but at least it's fast (3.34 registers/cycle). - * Architecturally, this loop could go at 4.67 registers/cycle, but that would - * oversubscribe Itanium. + * Not pretty, but at least it's fast (3.34 registers/cycle on Itanium, + * 5 registers/cycle on McKinley). */ # define pRecurse p6 # define pReturn p7 +#ifdef CONFIG_ITANIUM # define Nregs 10 +#else +# define Nregs 14 +#endif alloc loc0=ar.pfs,2,Nregs-2,2,0 shr.u loc1=r18,9 // RNaTslots <= dirtySize / (64*8) + 1 sub r17=r17,r18 // r17 = (physStackedSize + 8) - dirtySize ;; +#if 1 + .align 32 // see comment below about gas bug... +#endif mov ar.rsc=r19 // load ar.rsc to be used for "loadrs" shladd in0=loc1,3,r17 mov in1=0 +#if 0 + // gas-2.11.90 is unable to generate a stop bit after .align, which is bad, + // because alloc must be at the beginning of an insn-group. + .align 32 +#else + nop 0 + nop 0 + nop 0 +#endif ;; -// .align 32 // gas-2.11.90 is unable to generate a stop bit after .align rse_clear_invalid: +#ifdef CONFIG_ITANIUM // cycle 0 { .mii alloc loc0=ar.pfs,2,Nregs-2,2,0 @@ -712,9 +725,31 @@ mov loc7=0 (pReturn) br.ret.sptk.many b6 } +#else /* !CONFIG_ITANIUM */ + alloc loc0=ar.pfs,2,Nregs-2,2,0 + cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse + add out0=-Nregs*8,in0 + add out1=1,in1 // increment recursion count + mov loc1=0 + mov loc2=0 + ;; + mov loc3=0 + mov loc4=0 + mov loc9=0 + mov loc5=0 + mov loc6=0 +(pRecurse) br.call.sptk.many b6=rse_clear_invalid + ;; + mov loc7=0 + mov loc8=0 + cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret + mov loc10=0 + mov loc11=0 +(pReturn) br.ret.sptk.many b6 +#endif /* !CONFIG_ITANIUM */ # undef pRecurse # undef pReturn - + ;; alloc r17=ar.pfs,0,0,0,0 // drop current register frame ;; loadrs @@ -936,7 +971,11 @@ br.ret.sptk.many rp END(unw_init_running) +#ifdef CONFIG_IA64 + .data // syscall table must be writeable for vtune +#else .rodata +#endif .align 8 .globl sys_call_table sys_call_table: @@ -1133,18 +1172,18 @@ data8 sys_getdents64 data8 sys_getunwind // 1215 data8 sys_readahead - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1220 - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1225 - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_setxattr + data8 sys_lsetxattr + data8 sys_fsetxattr + data8 sys_getxattr // 1220 + data8 sys_lgetxattr + data8 sys_fgetxattr + data8 sys_listxattr + data8 sys_llistxattr + data8 sys_flistxattr // 1225 + data8 sys_removexattr + data8 sys_lremovexattr + data8 sys_fremovexattr data8 sys_tkill data8 ia64_ni_syscall // 1230 data8 ia64_ni_syscall @@ -1179,8 +1218,16 @@ data8 ia64_ni_syscall // 1260 data8 ia64_ni_syscall data8 ia64_ni_syscall +#if defined(CONFIG_PAGG) + data8 sys_paggctl +#else data8 ia64_ni_syscall +#endif /* CONFIG_PAGG */ +#if defined(CONFIG_CSA_JOB_ACCT) || defined(CONFIG_CSA_JOB_ACCT_MODULE) + data8 sys_acctctl +#else data8 ia64_ni_syscall +#endif data8 ia64_ni_syscall // 1265 data8 ia64_ni_syscall data8 ia64_ni_syscall diff -Nur linux-2.4.19/arch/ia64/kernel/fw-emu.c linux-2.4.19-sgi211r3/arch/ia64/kernel/fw-emu.c --- linux-2.4.19/arch/ia64/kernel/fw-emu.c Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/fw-emu.c Wed Oct 16 14:02:58 2002 @@ -13,14 +13,16 @@ # include #endif -#include +#include #include #include #include #define MB (1024*1024UL) +#define GB (1024*MB) +#define TB (1024*GB) -#define NUM_MEM_DESCS 3 +#define NUM_MEM_DESCS 4 static char fw_mem[( sizeof(struct ia64_boot_param) + sizeof(efi_system_table_t) @@ -471,7 +473,7 @@ md->phys_addr = 0*MB; md->virt_addr = 0; md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */ - md->attribute = EFI_MEMORY_WB; + md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC; /* fill in a memory descriptor: */ md = &efi_memmap[1]; @@ -489,23 +491,16 @@ md->phys_addr = 1*MB; md->virt_addr = 1*MB; md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */ - md->attribute = EFI_MEMORY_WB; - -#if 0 - /* - * XXX bootmem is broken for now... (remember to NUM_MEM_DESCS - * if you re-enable this!) - */ + md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC; - /* descriptor for high memory (>4GB): */ + /* descriptor for high memory (>4TB): */ md = &efi_memmap[3]; md->type = EFI_CONVENTIONAL_MEMORY; md->pad = 0; - md->phys_addr = 4096*MB; + md->phys_addr = 4*TB; md->virt_addr = 0; - md->num_pages = (32*MB) >> 12; /* 32MB (in 4KB pages) */ + md->num_pages = (64*MB) >> 12; /* 64MB (in 4KB pages) */ md->attribute = EFI_MEMORY_WB; -#endif bp->efi_systab = __pa(&fw_mem); bp->efi_memmap = __pa(efi_memmap); diff -Nur linux-2.4.19/arch/ia64/kernel/gate.S linux-2.4.19-sgi211r3/arch/ia64/kernel/gate.S --- linux-2.4.19/arch/ia64/kernel/gate.S Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/gate.S Tue Aug 27 19:53:13 2002 @@ -29,7 +29,7 @@ # define UNAT_OFF IA64_SIGCONTEXT_AR_UNAT_OFFSET # define FPSR_OFF IA64_SIGCONTEXT_AR_FPSR_OFFSET # define PR_OFF IA64_SIGCONTEXT_PR_OFFSET -# define RP_OFF IA64_SIGCONTEXT_B0_OFFSET +# define RP_OFF IA64_SIGCONTEXT_IP_OFFSET # define SP_OFF IA64_SIGCONTEXT_R12_OFFSET # define RBS_BASE_OFF IA64_SIGCONTEXT_RBS_BASE_OFFSET # define LOADRS_OFF IA64_SIGCONTEXT_LOADRS_OFFSET @@ -108,7 +108,7 @@ dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp ;; - .spillsp ar.pfs, CFM_OFF + .spillsp ar.pfs, CFM_OFF+SIGCONTEXT_OFF st8 [base0]=r8 // save CFM0 adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp ;; diff -Nur linux-2.4.19/arch/ia64/kernel/head.S linux-2.4.19-sgi211r3/arch/ia64/kernel/head.S --- linux-2.4.19/arch/ia64/kernel/head.S Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/head.S Tue Dec 31 09:58:16 2002 @@ -64,17 +64,20 @@ */ rsm psr.i | psr.ic mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (IA64_GRANULE_SHIFT << 2)) + mov r3=ip ;; srlz.i mov r18=KERNEL_TR_PAGE_SHIFT<<2 movl r17=KERNEL_START + dep r2=0,r3,0,12 ;; mov rr[r17]=r16 mov cr.itir=r18 mov cr.ifa=r17 mov r16=IA64_TR_KERNEL - movl r18=((1 << KERNEL_TR_PAGE_SHIFT) | PAGE_KERNEL) + movl r18=PAGE_KERNELRX ;; + or r18=r2,r18 srlz.i ;; itr.i itr[r16]=r18 @@ -84,6 +87,22 @@ srlz.i /* + * Map kernel global data + */ + movl r17=VGLOBAL_BASE + movl r18=PAGE_KERNEL + ;; + mov cr.ifa=r17 + mov r16=IA64_TR_KERNEL_GLOBAL + or r18=r2,r18 + ;; + srlz.i + ;; + itr.d dtr[r16]=r18 + ;; + srlz.i + + /* * Switch into virtual mode: */ movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN \ @@ -132,27 +151,55 @@ movl r3=cpucount ;; ld4 r3=[r3] // r3 <- smp_processor_id() - movl r2=init_tasks - ;; - shladd r2=r3,3,r2 - ;; - ld8 r2=[r2] #else mov r3=0 - movl r2=init_task_union - ;; #endif + + // Make init_tasks an identity mapped pointer + movl r18=init_tasks + ;; cmp4.ne isAP,isBP=r3,r0 - ;; // RAW on r2 - extr r3=r2,0,61 // r3 == phys addr of task struct - mov r16=KERNEL_TR_PAGE_NUM + shladd r18=r3,3,r18 + ;; + ld8 r2=[r18] + ;; + tpa r3=r2 // r3 == phys addr of task struct + ;; + dep r2=-1,r3,61,3 // convert phys to identity mapped virtual + ;; + st8 [r18]=r2 // and save it back in init_tasks[thiscpu] + + + // load mapping for stack (virtaddr in r2, physaddr in r3) + rsm psr.ic + movl r17=PAGE_KERNEL + ;; + srlz.d + dep r18=0,r3,0,12 + ;; + or r18=r17,r18 + ;; + mov r17=rr[r2] ;; + dep r17=0,r17,8,24 + ;; + mov cr.itir=r17 + mov cr.ifa=r2 + + mov r16=IA64_TR_CURRENT_STACK + ;; + itr.d dtr[r16]=r18 + ;; + ssm psr.ic + srlz.d // load the "current" pointer (r13) and ar.k6 with the current task mov r13=r2 mov IA64_KR(CURRENT)=r3 // Physical address - // initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL) + // k4 indicates which large kernel page is mapped + extr.u r16=r3,IA64_GRANULE_SHIFT,64-IA64_GRANULE_SHIFT + ;; mov IA64_KR(CURRENT_STACK)=r16 /* * Reserve space at the top of the stack for "struct pt_regs". Kernel threads @@ -177,6 +224,7 @@ (isBP) st8 [r2]=r28 // save the address of the boot param area passed by the bootloader #ifdef CONFIG_IA64_EARLY_PRINTK +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) .rodata alive_msg: stringz "I'm alive and well\n" @@ -189,6 +237,7 @@ ;; br.call.sptk.many rp=early_printk 1: // force new bundle +#endif #endif /* CONFIG_IA64_EARLY_PRINTK */ #ifdef CONFIG_SMP @@ -562,148 +611,171 @@ END(__ia64_load_fpu) GLOBAL_ENTRY(__ia64_init_fpu) + stf.spill [sp]=f0 // M3 + mov f32=f0 // F + nop.b 0 + + ldfps f33,f34=[sp] // M0 + ldfps f35,f36=[sp] // M1 + mov f37=f0 // F + ;; + + setf.s f38=r0 // M2 + setf.s f39=r0 // M3 + mov f40=f0 // F + + ldfps f41,f42=[sp] // M0 + ldfps f43,f44=[sp] // M1 + mov f45=f0 // F + + setf.s f46=r0 // M2 + setf.s f47=r0 // M3 + mov f48=f0 // F + + ldfps f49,f50=[sp] // M0 + ldfps f51,f52=[sp] // M1 + mov f53=f0 // F + + setf.s f54=r0 // M2 + setf.s f55=r0 // M3 + mov f56=f0 // F + + ldfps f57,f58=[sp] // M0 + ldfps f59,f60=[sp] // M1 + mov f61=f0 // F + + setf.s f62=r0 // M2 + setf.s f63=r0 // M3 + mov f64=f0 // F + + ldfps f65,f66=[sp] // M0 + ldfps f67,f68=[sp] // M1 + mov f69=f0 // F + + setf.s f70=r0 // M2 + setf.s f71=r0 // M3 + mov f72=f0 // F + + ldfps f73,f74=[sp] // M0 + ldfps f75,f76=[sp] // M1 + mov f77=f0 // F + + setf.s f78=r0 // M2 + setf.s f79=r0 // M3 + mov f80=f0 // F + + ldfps f81,f82=[sp] // M0 + ldfps f83,f84=[sp] // M1 + mov f85=f0 // F + + setf.s f86=r0 // M2 + setf.s f87=r0 // M3 + mov f88=f0 // F + + /* + * When the instructions are cached, it would be faster to initialize + * the remaining registers with simply mov instructions (F-unit). + * This gets the time down to ~29 cycles. However, this would use up + * 33 bundles, whereas continuing with the above pattern yields + * 10 bundles and ~30 cycles. + */ + + ldfps f89,f90=[sp] // M0 + ldfps f91,f92=[sp] // M1 + mov f93=f0 // F + + setf.s f94=r0 // M2 + setf.s f95=r0 // M3 + mov f96=f0 // F + + ldfps f97,f98=[sp] // M0 + ldfps f99,f100=[sp] // M1 + mov f101=f0 // F + + setf.s f102=r0 // M2 + setf.s f103=r0 // M3 + mov f104=f0 // F + + ldfps f105,f106=[sp] // M0 + ldfps f107,f108=[sp] // M1 + mov f109=f0 // F + + setf.s f110=r0 // M2 + setf.s f111=r0 // M3 + mov f112=f0 // F + + ldfps f113,f114=[sp] // M0 + ldfps f115,f116=[sp] // M1 + mov f117=f0 // F + + setf.s f118=r0 // M2 + setf.s f119=r0 // M3 + mov f120=f0 // F + + ldfps f121,f122=[sp] // M0 + ldfps f123,f124=[sp] // M1 + mov f125=f0 // F + + setf.s f126=r0 // M2 + setf.s f127=r0 // M3 + br.ret.sptk.many rp // F +END(__ia64_init_fpu) + +/* + * Switch execution mode from virtual to physical + * + * Inputs: + * r16 = new psr to establish + * + * Note: RSE must already be in enforced lazy mode + */ +GLOBAL_ENTRY(ia64_switch_mode_phys) + { alloc r2=ar.pfs,0,0,0,0 - stf.spill [sp]=f0 - mov f32=f0 + rsm psr.i | psr.ic // disable interrupts and interrupt collection + mov r15=ip + } + ;; + { + flushrs // must be first insn in group + srlz.i + } + ;; + mov cr.ipsr=r16 // set new PSR + add r3=1f-ia64_switch_mode_phys,r15 + + mov r17=ar.bsp + mov r14=rp // get return address into a general register + ;; + + // going to physical mode, use tpa to translate virt->phys + tpa r17=r17 + tpa r3=r3 + tpa sp=sp + tpa r14=r14 + ;; + + mov r18=ar.rnat // save ar.rnat + mov ar.bspstore=r17 // this steps on ar.rnat + mov cr.iip=r3 + mov cr.ifs=r0 ;; - ldf.fill f33=[sp] - ldf.fill f34=[sp] - mov f35=f0 - ;; - ldf.fill f36=[sp] - ldf.fill f37=[sp] - mov f38=f0 - ;; - ldf.fill f39=[sp] - ldf.fill f40=[sp] - mov f41=f0 - ;; - ldf.fill f42=[sp] - ldf.fill f43=[sp] - mov f44=f0 - ;; - ldf.fill f45=[sp] - ldf.fill f46=[sp] - mov f47=f0 - ;; - ldf.fill f48=[sp] - ldf.fill f49=[sp] - mov f50=f0 - ;; - ldf.fill f51=[sp] - ldf.fill f52=[sp] - mov f53=f0 - ;; - ldf.fill f54=[sp] - ldf.fill f55=[sp] - mov f56=f0 - ;; - ldf.fill f57=[sp] - ldf.fill f58=[sp] - mov f59=f0 - ;; - ldf.fill f60=[sp] - ldf.fill f61=[sp] - mov f62=f0 - ;; - ldf.fill f63=[sp] - ldf.fill f64=[sp] - mov f65=f0 - ;; - ldf.fill f66=[sp] - ldf.fill f67=[sp] - mov f68=f0 - ;; - ldf.fill f69=[sp] - ldf.fill f70=[sp] - mov f71=f0 - ;; - ldf.fill f72=[sp] - ldf.fill f73=[sp] - mov f74=f0 - ;; - ldf.fill f75=[sp] - ldf.fill f76=[sp] - mov f77=f0 - ;; - ldf.fill f78=[sp] - ldf.fill f79=[sp] - mov f80=f0 - ;; - ldf.fill f81=[sp] - ldf.fill f82=[sp] - mov f83=f0 - ;; - ldf.fill f84=[sp] - ldf.fill f85=[sp] - mov f86=f0 - ;; - ldf.fill f87=[sp] - ldf.fill f88=[sp] - mov f89=f0 - ;; - ldf.fill f90=[sp] - ldf.fill f91=[sp] - mov f92=f0 - ;; - ldf.fill f93=[sp] - ldf.fill f94=[sp] - mov f95=f0 - ;; - ldf.fill f96=[sp] - ldf.fill f97=[sp] - mov f98=f0 - ;; - ldf.fill f99=[sp] - ldf.fill f100=[sp] - mov f101=f0 - ;; - ldf.fill f102=[sp] - ldf.fill f103=[sp] - mov f104=f0 - ;; - ldf.fill f105=[sp] - ldf.fill f106=[sp] - mov f107=f0 - ;; - ldf.fill f108=[sp] - ldf.fill f109=[sp] - mov f110=f0 - ;; - ldf.fill f111=[sp] - ldf.fill f112=[sp] - mov f113=f0 - ;; - ldf.fill f114=[sp] - ldf.fill f115=[sp] - mov f116=f0 - ;; - ldf.fill f117=[sp] - ldf.fill f118=[sp] - mov f119=f0 - ;; - ldf.fill f120=[sp] - ldf.fill f121=[sp] - mov f122=f0 - ;; - ldf.fill f123=[sp] - ldf.fill f124=[sp] - mov f125=f0 + mov ar.rnat=r18 // restore ar.rnat + rfi // must be last insn in group ;; - ldf.fill f126=[sp] - mov f127=f0 +1: mov rp=r14 br.ret.sptk.many rp -END(__ia64_init_fpu) +END(ia64_switch_mode_phys) /* - * Switch execution mode from virtual to physical or vice versa. + * Switch execution mode from physical to virtual * * Inputs: * r16 = new psr to establish * * Note: RSE must already be in enforced lazy mode */ -GLOBAL_ENTRY(ia64_switch_mode) +GLOBAL_ENTRY(ia64_switch_mode_virt) { alloc r2=ar.pfs,0,0,0,0 rsm psr.i | psr.ic // disable interrupts and interrupt collection @@ -713,35 +785,40 @@ { flushrs // must be first insn in group srlz.i - shr.u r19=r15,61 // r19 <- top 3 bits of current IP } ;; mov cr.ipsr=r16 // set new PSR - add r3=1f-ia64_switch_mode,r15 - xor r15=0x7,r19 // flip the region bits + add r3=1f-ia64_switch_mode_virt,r15 mov r17=ar.bsp mov r14=rp // get return address into a general register + ;; - // switch RSE backing store: + // going to virtual + // - for code addresses, set upper bits of addr to VPERNODE_BASE + // - for stack addresses, set upper 3 bits to 0xe.... Dont change any of the + // lower bits since we want it to stay identity mapped + movl r18=VPERNODE_BASE + dep r3=0,r3,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT + dep r14=0,r14,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT + dep r17=-1,r17,61,3 + dep sp=-1,sp,61,3 ;; - dep r17=r15,r17,61,3 // make ar.bsp physical or virtual - mov r18=ar.rnat // save ar.rnat + or r3=r3,r18 + or r14=r14,r18 ;; + + mov r18=ar.rnat // save ar.rnat mov ar.bspstore=r17 // this steps on ar.rnat - dep r3=r15,r3,61,3 // make rfi return address physical or virtual - ;; mov cr.iip=r3 mov cr.ifs=r0 - dep sp=r15,sp,61,3 // make stack pointer physical or virtual ;; mov ar.rnat=r18 // restore ar.rnat - dep r14=r15,r14,61,3 // make function return address physical or virtual rfi // must be last insn in group ;; 1: mov rp=r14 br.ret.sptk.many rp -END(ia64_switch_mode) +END(ia64_switch_mode_virt) #ifdef CONFIG_IA64_BRL_EMU @@ -832,5 +909,87 @@ br .retry // still no luck, retry END(ia64_spinlock_contention) + +#endif + +#ifdef CONFIG_NUMA + +#define PSR_BITS_TO_CLEAR \ + (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \ + IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ + IA64_PSR_DFL | IA64_PSR_DFH) + +#define PSR_BITS_TO_SET \ + (IA64_PSR_BN) + +/* + * ccNUMA systems bring up all cpus running from the copy of the + * kernel that elilo loaded into memory. Processors that find that + * they are not using the kernel text/rodata that is on their local + * node can use this routine to reset their TLB mappings to point + * at the correct copy. + * + * This is like the magic trick where you pull a table cloth out + * from under a table covered with plates, glasses and silverware, + * except in this version we slide an identical tablecloth in to + * replace the one we pulled out. + * + * Inputs: + * in0 = physical address of local node copy to be mapped + */ + +GLOBAL_ENTRY(ia64_remap_kernel) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,5,7,0 + mov loc0=rp + .body + ;; + mov loc4=ar.rsc // save RSE configuration + mov ar.rsc=0 // put RSE in enforced lazy, LE mode + ;; + + movl r16=PSR_BITS_TO_CLEAR + + mov loc3=psr // save processor status word + movl r17=PSR_BITS_TO_SET + ;; + or loc3=loc3,r17 + ;; + andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared + br.call.sptk.few rp=ia64_switch_mode_phys +.ret3: + rsm psr.i | psr.ic + movl r19=VPERNODE_BASE + movl r20=KERNEL_TR_PAGE_SHIFT<<2 + movl r21=PAGE_KERNELRX + mov r22=IA64_TR_KERNEL + ;; + ptr.i r19,r20 // purge old code mapping + ptr.d r19,r20 // and the data mapping too + ;; + srlz.i + ;; + + mov cr.ifa=r19 + mov cr.itir=r20 + or r21=r21,in0 + ;; + + srlz.i + ;; + itr.i itr[r22]=r21 + ;; + itr.d dtr[r22]=r21 + ;; + srlz.i + ;; + + mov r16=loc3 + br.call.sptk.few rp=ia64_switch_mode_virt // return to virtual mode +.ret4: mov ar.rsc=loc4 // restore RSE configuration + mov ar.pfs=loc1 + mov rp=loc0 + br.ret.sptk.few rp +END(ia64_remap_kernel) #endif diff -Nur linux-2.4.19/arch/ia64/kernel/ia64_ksyms.c linux-2.4.19-sgi211r3/arch/ia64/kernel/ia64_ksyms.c --- linux-2.4.19/arch/ia64/kernel/ia64_ksyms.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/ia64_ksyms.c Tue Jan 14 11:02:29 2003 @@ -1,11 +1,11 @@ /* * Architecture-specific kernel symbols */ - #include #include #include + EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(memcmp); @@ -31,6 +31,7 @@ EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(register_percpu_irq); #include EXPORT_SYMBOL(probe_irq_mask); @@ -148,3 +149,19 @@ #include extern struct proc_dir_entry *efi_dir; EXPORT_SYMBOL(efi_dir); + +#include +#ifdef CONFIG_IA64_GENERIC +EXPORT_SYMBOL(ia64_mv); +#endif +EXPORT_SYMBOL(machvec_noop); + +#ifdef CONFIG_DISCONTIGMEM +EXPORT_SYMBOL(invalid_mem_map); +EXPORT_SYMBOL(zero_page_memmap_ptr); +#endif + +#include +EXPORT_SYMBOL(ia64_save_scratch_fpregs); +EXPORT_SYMBOL(ia64_load_scratch_fpregs); + diff -Nur linux-2.4.19/arch/ia64/kernel/iosapic.c linux-2.4.19-sgi211r3/arch/ia64/kernel/iosapic.c --- linux-2.4.19/arch/ia64/kernel/iosapic.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/iosapic.c Wed Oct 16 14:02:58 2002 @@ -22,30 +22,44 @@ * 02/01/07 E. Focht Redirectable interrupt vectors in * iosapic_set_affinity(), initializations for * /proc/irq/#/smp_affinity + * 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing. + * 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq + * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping error + * 02/07/29 T. Kochi Allocate interrupt vectors dynamically + * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector, etc.) + * 02/08/13 B. Helgaas Support PCI segments */ /* * Here is what the interrupt logic between a PCI device and the CPU looks like: * * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The - * device is uniquely identified by its bus--, and slot-number (the function + * device is uniquely identified by its segment--, bus--, and slot-number (the function * number does not matter here because all functions share the same interrupt * lines). * * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. * Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level - * triggered and use the same polarity). Each interrupt line has a unique IOSAPIC - * irq number which can be calculated as the sum of the controller's base irq number - * and the IOSAPIC pin number to which the line connects. + * triggered and use the same polarity). Each interrupt line has a unique Global + * System Interrupt (GSI) number which can be calculated as the sum of the controller's + * base GSI number and the IOSAPIC pin number to which the line connects. * - * (3) The IOSAPIC uses an internal table to map the IOSAPIC pin into the IA-64 interrupt - * vector. This interrupt vector is then sent to the CPU. + * (3) The IOSAPIC uses internal routing table entries (RTEs) to map the IOSAPIC pin + * to the IA-64 interrupt vector. This interrupt vector is then sent to the CPU. * - * In other words, there are two levels of indirections involved: + * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface + * is an architecture-independent interrupt handling mechanism in + * Linux. An IRQ is a number, so we need a mapping between IRQ + * numbers and IA-64 vectors. The platform_irq_to_vector(irq) and + * platform_local_vector_to_irq(vector) APIs can define platform- + * specific mappings. * - * pci pin -> iosapic irq -> IA-64 vector + * To sum up, there are three levels of mappings involved: * - * Note: outside this module, IA-64 vectors are called "irqs". This is because that's - * the traditional name Linux uses for interrupt vectors. + * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ + * + * Note: The term "IRQ" is loosely used everywhere in the Linux kernel + * to describe interrupts. In this module, "IRQ" refers only to Linux + * IRQ numbers ("isa_irq" is an exception to this rule). */ #include @@ -56,9 +70,8 @@ #include #include #include +#include -#include -#include #include #include #include @@ -69,80 +82,103 @@ #include -#undef DEBUG_IRQ_ROUTING -#undef OVERRIDE_DEBUG +#undef DEBUG_INTERRUPT_ROUTING +#undef OVERRIDE_DEBUG + +#ifdef DEBUG_INTERRUPT_ROUTING +#define DBG(fmt...) printk(fmt) +#else +#define DBG(fmt...) +#endif static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; -/* PCI pin to IOSAPIC irq routing information. This info typically comes from ACPI. */ +/* PCI pin to GSI routing information. This info typically comes from ACPI. */ static struct { int num_routes; struct pci_vector_struct *route; } pci_irq; -/* This tables maps IA-64 vectors to the IOSAPIC pin that generates this vector. */ +/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ + +static struct iosapic_intr_info { + char *addr; /* base address of IOSAPIC */ + unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ + char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ + unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ + unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ + unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ +} iosapic_intr_info[IA64_NUM_VECTORS]; + +static struct iosapic { + char *addr; /* base address of IOSAPIC */ + unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ + unsigned short num_rte; /* number of RTE in this IOSAPIC */ + unsigned char pcat_compat; /* 8259 compatibility flag */ +} iosapic_lists[256] __devinitdata; + +static int __devinitdata num_iosapic = 0; -static struct iosapic_irq { - char *addr; /* base address of IOSAPIC */ - unsigned char base_irq; /* first irq assigned to this IOSAPIC */ - char pin; /* IOSAPIC pin (-1 => not an IOSAPIC irq) */ - unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ - unsigned char polarity : 1; /* interrupt polarity (see iosapic.h) */ - unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ -} iosapic_irq[IA64_NUM_VECTORS]; /* - * Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector. If no - * entry exists, return -1. + * Find an IOSAPIC associated with a GSI */ -int -iosapic_irq_to_vector (int irq) +static inline int __devinit +find_iosapic (unsigned int gsi) { - int vector; + int i; - for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) - if (iosapic_irq[vector].base_irq + iosapic_irq[vector].pin == irq) - return vector; + for (i = 0; i < num_iosapic; i++) + if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) + return i; return -1; } /* - * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists, - * return -1. + * Translate GSI number to the corresponding IA-64 interrupt vector. If no + * entry exists, return -1. */ -static int -pci_pin_to_vector (int bus, int slot, int pci_pin) +int +gsi_to_vector (unsigned int gsi) { - struct pci_vector_struct *r; + int vector; - for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; ++r) - if (r->bus == bus && (r->pci_id >> 16) == slot && r->pin == pci_pin) - return iosapic_irq_to_vector(r->irq); + for (vector = 0; vector < IA64_NUM_VECTORS; vector++) + if (iosapic_intr_info[vector].gsi_base + iosapic_intr_info[vector].rte_index == gsi) + return vector; return -1; } static void -set_rte (unsigned int vector, unsigned long dest) +set_rte (unsigned int vector, unsigned int dest) { unsigned long pol, trigger, dmode; u32 low32, high32; char *addr; - int pin; + int rte_index; char redir; - pin = iosapic_irq[vector].pin; - if (pin < 0) + rte_index = iosapic_intr_info[vector].rte_index; + if (rte_index < 0) return; /* not an IOSAPIC interrupt */ - addr = iosapic_irq[vector].addr; - pol = iosapic_irq[vector].polarity; - trigger = iosapic_irq[vector].trigger; - dmode = iosapic_irq[vector].dmode; + addr = iosapic_intr_info[vector].addr; + pol = iosapic_intr_info[vector].polarity; + trigger = iosapic_intr_info[vector].trigger; + dmode = iosapic_intr_info[vector].dmode; redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; #ifdef CONFIG_SMP - set_irq_affinity_info(vector, (int)(dest & 0xffff), redir); + { + int irq; + + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == vector) { + set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); + break; + } + } #endif low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | @@ -153,9 +189,9 @@ /* dest contains both id and eid */ high32 = (dest << IOSAPIC_DEST_SHIFT); - writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT); writel(high32, addr + IOSAPIC_WINDOW); - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); writel(low32, addr + IOSAPIC_WINDOW); } @@ -171,18 +207,18 @@ unsigned long flags; char *addr; u32 low32; - int pin; + int rte_index; ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vec].addr; - pin = iosapic_irq[vec].pin; + addr = iosapic_intr_info[vec].addr; + rte_index = iosapic_intr_info[vec].rte_index; - if (pin < 0) + if (rte_index < 0) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); low32 = readl(addr + IOSAPIC_WINDOW); low32 |= (1 << IOSAPIC_MASK_SHIFT); /* set only the mask bit */ @@ -197,17 +233,17 @@ unsigned long flags; char *addr; u32 low32; - int pin; + int rte_index; ia64_vector vec = irq_to_vector(irq); - addr = iosapic_irq[vec].addr; - pin = iosapic_irq[vec].pin; - if (pin < 0) + addr = iosapic_intr_info[vec].addr; + rte_index = iosapic_intr_info[vec].rte_index; + if (rte_index < 0) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); low32 = readl(addr + IOSAPIC_WINDOW); low32 &= ~(1 << IOSAPIC_MASK_SHIFT); /* clear only the mask bit */ @@ -223,24 +259,28 @@ #ifdef CONFIG_SMP unsigned long flags; u32 high32, low32; - int dest, pin; + int dest, rte_index; char *addr; - int redir = (irq & (1<<31)) ? 1 : 0; + int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; + ia64_vector vec; + + irq &= (~IA64_IRQ_REDIRECTED); + vec = irq_to_vector(irq); mask &= (1UL << smp_num_cpus) - 1; - if (!mask || irq >= IA64_NUM_VECTORS) + if (!mask || vec >= IA64_NUM_VECTORS) return; dest = cpu_physical_id(ffz(~mask)); - pin = iosapic_irq[irq].pin; - addr = iosapic_irq[irq].addr; + rte_index = iosapic_intr_info[vec].rte_index; + addr = iosapic_intr_info[vec].addr; - if (pin < 0) + if (rte_index < 0) return; /* not an IOSAPIC interrupt */ - set_irq_affinity_info(irq,dest,redir); + set_irq_affinity_info(irq, dest, redir); /* dest contains both id and eid */ high32 = dest << IOSAPIC_DEST_SHIFT; @@ -248,7 +288,7 @@ spin_lock_irqsave(&iosapic_lock, flags); { /* get current delivery mode by reading the low32 */ - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); low32 = readl(addr + IOSAPIC_WINDOW); low32 &= ~(7 << IOSAPIC_DELIVERY_SHIFT); @@ -259,9 +299,9 @@ /* change delivery mode to fixed */ low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); - writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_HIGH(rte_index), addr + IOSAPIC_REG_SELECT); writel(high32, addr + IOSAPIC_WINDOW); - writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT); writel(low32, addr + IOSAPIC_WINDOW); } spin_unlock_irqrestore(&iosapic_lock, flags); @@ -284,7 +324,7 @@ { ia64_vector vec = irq_to_vector(irq); - writel(vec, iosapic_irq[vec].addr + IOSAPIC_EOI); + writel(vec, iosapic_intr_info[vec].addr + IOSAPIC_EOI); } #define iosapic_shutdown_level_irq mask_irq @@ -355,7 +395,7 @@ * { * unsigned int version : 8; * unsigned int reserved1 : 8; - * unsigned int pins : 8; + * unsigned int max_redir : 8; * unsigned int reserved2 : 8; * } */ @@ -372,69 +412,72 @@ { int new_vector; - if (iosapic_irq[vector].pin >= 0 || iosapic_irq[vector].addr - || iosapic_irq[vector].base_irq || iosapic_irq[vector].dmode - || iosapic_irq[vector].polarity || iosapic_irq[vector].trigger) + if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr + || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode + || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger) { - new_vector = ia64_alloc_irq(); - printk("Reassigning Vector 0x%x to 0x%x\n", vector, new_vector); - memcpy (&iosapic_irq[new_vector], &iosapic_irq[vector], - sizeof(struct iosapic_irq)); - memset (&iosapic_irq[vector], 0, sizeof(struct iosapic_irq)); - iosapic_irq[vector].pin = -1; + new_vector = ia64_alloc_vector(); + printk("Reassigning Vector %d to %d\n", vector, new_vector); + memcpy (&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], + sizeof(struct iosapic_intr_info)); + memset (&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); + iosapic_intr_info[vector].rte_index = -1; } } static void -register_irq (u32 global_vector, int vector, int pin, unsigned char delivery, - unsigned long polarity, unsigned long edge_triggered, - u32 base_irq, char *iosapic_address) +register_intr (unsigned int gsi, int vector, unsigned char delivery, + unsigned long polarity, unsigned long edge_triggered, + unsigned int gsi_base, char *iosapic_address) { irq_desc_t *idesc; struct hw_interrupt_type *irq_type; + int rte_index; - iosapic_irq[vector].pin = pin; - iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; - iosapic_irq[vector].dmode = delivery; + rte_index = gsi - gsi_base; + iosapic_intr_info[vector].rte_index = rte_index; + iosapic_intr_info[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; + iosapic_intr_info[vector].dmode = delivery; /* - * In override, it does not provide addr/base_irq. global_vector is enough to - * locate iosapic addr, base_irq and pin by examining base_irq and max_pin of - * registered iosapics (tbd) + * In override, it may not provide addr/gsi_base. GSI is enough to + * locate iosapic addr, gsi_base and rte_index by examining + * gsi_base and num_rte of registered iosapics (tbd) */ #ifndef OVERRIDE_DEBUG if (iosapic_address) { - iosapic_irq[vector].addr = iosapic_address; - iosapic_irq[vector].base_irq = base_irq; + iosapic_intr_info[vector].addr = iosapic_address; + iosapic_intr_info[vector].gsi_base = gsi_base; } #else if (iosapic_address) { - if (iosapic_irq[vector].addr && (iosapic_irq[vector].addr != iosapic_address)) - printk("WARN: register_irq: diff IOSAPIC ADDRESS for gv %x, v %x\n", - global_vector, vector); - iosapic_irq[vector].addr = iosapic_address; - if (iosapic_irq[vector].base_irq && (iosapic_irq[vector].base_irq != base_irq)) { - printk("WARN: register_irq: diff BASE IRQ %x for gv %x, v %x\n", - base_irq, global_vector, vector); + if (iosapic_intr_info[vector].addr && (iosapic_intr_info[vector].addr != iosapic_address)) + printk("WARN: %s: diff IOSAPIC ADDRESS for GSI 0x%x, vector %d\n", + __FUNCTION__, gsi, vector); + iosapic_intr_info[vector].addr = iosapic_address; + if (iosapic_intr_info[vector].gsi_base && (iosapic_intr_info[vector].gsi_base != gsi_base)) { + printk("WARN: %s: diff GSI base 0x%x for GSI 0x%x, vector %d\n", + __FUNCTION__, gsi_base, gsi, vector); } - iosapic_irq[vector].base_irq = base_irq; - } else if (!iosapic_irq[vector].addr) - printk("WARN: register_irq: invalid override for gv %x, v %x\n", - global_vector, vector); + iosapic_intr_info[vector].gsi_base = gsi_base; + } else if (!iosapic_intr_info[vector].addr) + printk("WARN: %s: invalid override for GSI 0x%x, vector %d\n", + __FUNCTION__, gsi, vector); #endif if (edge_triggered) { - iosapic_irq[vector].trigger = IOSAPIC_EDGE; + iosapic_intr_info[vector].trigger = IOSAPIC_EDGE; irq_type = &irq_type_iosapic_edge; } else { - iosapic_irq[vector].trigger = IOSAPIC_LEVEL; + iosapic_intr_info[vector].trigger = IOSAPIC_LEVEL; irq_type = &irq_type_iosapic_level; } idesc = irq_desc(vector); if (idesc->handler != irq_type) { if (idesc->handler != &no_irq_type) - printk("register_irq(): changing vector 0x%02x from " - "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); + printk("%s: changing vector %d from %s to %s\n", + __FUNCTION__, vector, idesc->handler->typename, + irq_type->typename); idesc->handler = irq_type; } } @@ -445,24 +488,26 @@ * program the IOSAPIC RTE. */ int -iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long - edge_triggered, u32 base_irq, char *iosapic_address) +iosapic_register_intr (unsigned int gsi, + unsigned long polarity, unsigned long edge_triggered, + unsigned int gsi_base, char *iosapic_address) { int vector; + unsigned int dest = (ia64_get_lid() >> 16) & 0xffff; - vector = iosapic_irq_to_vector(global_vector); + vector = gsi_to_vector(gsi); if (vector < 0) - vector = ia64_alloc_irq(); + vector = ia64_alloc_vector(); - register_irq (global_vector, vector, global_vector - base_irq, - IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, - base_irq, iosapic_address); + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, + polarity, edge_triggered, gsi_base, iosapic_address); - printk("IOSAPIC 0x%x(%s,%s) -> Vector 0x%x\n", global_vector, - (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector); + printk("GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n", + gsi, (polarity ? "high" : "low"), + (edge_triggered ? "edge" : "level"), dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + set_rte(vector, dest); return vector; } @@ -471,15 +516,17 @@ * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). */ int -iosapic_register_platform_irq (u32 int_type, u32 global_vector, - u32 iosapic_vector, u16 eid, u16 id, unsigned long polarity, - unsigned long edge_triggered, u32 base_irq, char *iosapic_address) +iosapic_register_platform_intr (u32 int_type, unsigned int gsi, + int iosapic_vector, u16 eid, u16 id, + unsigned long polarity, unsigned long edge_triggered, + unsigned int gsi_base, char *iosapic_address) { unsigned char delivery; int vector; + unsigned int dest = ((id << 8) | eid) & 0xffff; switch (int_type) { - case ACPI20_ENTRY_PIS_PMI: + case ACPI_INTERRUPT_PMI: vector = iosapic_vector; /* * since PMI vector is alloc'd by FW(ACPI) not by kernel, @@ -488,223 +535,320 @@ iosapic_reassign_vector(vector); delivery = IOSAPIC_PMI; break; - case ACPI20_ENTRY_PIS_CPEI: + case ACPI_INTERRUPT_INIT: + vector = ia64_alloc_vector(); + delivery = IOSAPIC_INIT; + break; + case ACPI_INTERRUPT_CPEI: vector = IA64_PCE_VECTOR; delivery = IOSAPIC_LOWEST_PRIORITY; break; - case ACPI20_ENTRY_PIS_INIT: - vector = ia64_alloc_irq(); - delivery = IOSAPIC_INIT; - break; - default: - printk("iosapic_register_platform_irq(): invalid int type\n"); + default: + printk("%s: invalid interrupt type (%d)\n", __FUNCTION__, + int_type); return -1; } - register_irq(global_vector, vector, global_vector - base_irq, delivery, polarity, - edge_triggered, base_irq, iosapic_address); + register_intr(gsi, vector, delivery, polarity, + edge_triggered, gsi_base, iosapic_address); - printk("PLATFORM int 0x%x: IOSAPIC 0x%x(%s,%s) -> Vector 0x%x CPU %.02u:%.02u\n", - int_type, global_vector, (polarity ? "high" : "low"), - (edge_triggered ? "edge" : "level"), vector, eid, id); + printk("PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n", + int_type, gsi, (polarity ? "high" : "low"), + (edge_triggered ? "edge" : "level"), dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, ((id << 8) | eid) & 0xffff); + set_rte(vector, dest); return vector; } /* - * ACPI calls this when it finds an entry for a legacy ISA interrupt. - * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). + * ACPI calls this when it finds an entry for a legacy ISA IRQ override. + * Note that the gsi_base and IOSAPIC address must be set in iosapic_init(). */ void -iosapic_register_legacy_irq (unsigned long irq, - unsigned long pin, unsigned long polarity, - unsigned long edge_triggered) -{ - int vector = isa_irq_to_vector(irq); - - register_irq(irq, vector, (int)pin, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, - 0, NULL); /* ignored for override */ - -#ifdef DEBUG_IRQ_ROUTING - printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (%s, %s) -> vector %02x\n", - (unsigned) irq, (unsigned) pin, - polarity ? "high" : "low", edge_triggered ? "edge" : "level", - vector); -#endif +iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, + unsigned long polarity, unsigned long edge_triggered) +{ + int index, vector; + unsigned int gsi_base; + char *addr; + unsigned int dest = (ia64_get_lid() >> 16) & 0xffff; + + index = find_iosapic(gsi); + + if (index < 0) { + printk("ISA: No corresponding IOSAPIC found : ISA IRQ %u -> GSI 0x%x\n", isa_irq, gsi); + return; + } + + vector = isa_irq_to_vector(isa_irq); + addr = iosapic_lists[index].addr; + gsi_base = iosapic_lists[index].gsi_base; + + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, edge_triggered, + gsi_base, addr); + + DBG("ISA: IRQ %u -> GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n", + isa_irq, global_vector, + polarity ? "high" : "low", edge_triggered ? "edge" : "level", + dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + set_rte(vector, dest); } -void __init -iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat) +/* + * Map PCI pin to the corresponding GSI. + * If no such mapping exists, return -1. + */ +static int +pci_pin_to_gsi (int segment, int bus, int slot, int pci_pin, unsigned int *gsi) { - int i, irq, max_pin, vector, pin; - unsigned int ver; + struct pci_vector_struct *r; + + for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; r++) + if (r->segment == segment && r->bus == bus && + (r->pci_id >> 16) == slot && r->pin == pci_pin) { + *gsi = r->irq; + return 0; + } + + return -1; +} + +/* + * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists, + * try to allocate a new vector. If it fails, return -1. + */ +static int +pci_pin_to_vector (int segment, int bus, int slot, int pci_pin) +{ + int index, vector; + int gsi_base, pcat_compat; + char *addr; + unsigned int gsi; + + if (pci_pin_to_gsi(segment, bus, slot, pci_pin, &gsi) < 0) { + printk("PCI: no interrupt route for %02x:%02x:%02x pin %c\n", + segment, bus, slot, 'A' + pci_pin); + return -1; + } + + vector = gsi_to_vector(gsi); + + if (vector < 0) { + /* we should allocate a vector for this interrupt line */ + + index = find_iosapic(gsi); + + if (index < 0) { + printk("PCI: GSI 0x%x has no IOSAPIC mapping\n", gsi); + return -1; + } + + addr = iosapic_lists[index].addr; + gsi_base = iosapic_lists[index].gsi_base; + pcat_compat = iosapic_lists[index].pcat_compat; + + if (pcat_compat && (gsi < 16)) + vector = isa_irq_to_vector(gsi); + else { + /* new GSI; allocate a vector for it */ + vector = ia64_alloc_vector(); + } + + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, + 0, 0, gsi_base, addr); + + DBG("PCI: (%02x:%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n", + segment, bus, slot, 'A' + pci_pin, gsi, vector); + } + + return vector; +} + +void __devinit +iosapic_init (unsigned long phys_addr, unsigned int gsi_base, int pcat_compat) +{ + int num_rte, vector; + unsigned int isa_irq, ver; char *addr; static int first_time = 1; if (first_time) { first_time = 0; - for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) - iosapic_irq[vector].pin = -1; /* mark as unused */ + iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ + } + if (pcat_compat) { /* - * Fetch the PCI interrupt routing table: + * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support + * enabled. */ - acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes); + printk("%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__); + outb(0xff, 0xA1); + outb(0xff, 0x21); } addr = ioremap(phys_addr, 0); ver = iosapic_version(addr); - max_pin = (ver >> 16) & 0xff; - printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", - (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin); + /* + * The MAX_REDIR register holds the highest input pin + * number (starting from 0). + * We add 1 so that we can use it for number of pins (= RTEs) + */ + num_rte = ((ver >> 16) & 0xff) + 1; + + iosapic_lists[num_iosapic].addr = addr; + iosapic_lists[num_iosapic].pcat_compat = pcat_compat; + iosapic_lists[num_iosapic].gsi_base = gsi_base; + iosapic_lists[num_iosapic].num_rte = num_rte; + num_iosapic++; + + printk("IOSAPIC: version %x.%x, address 0x%lx, GSIs 0x%x-0x%x\n", + (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, gsi_base, gsi_base + num_rte - 1); + + if ((gsi_base == 0) && pcat_compat) { + unsigned int dest = (ia64_get_lid() >> 16) & 0xffff; - if ((base_irq == 0) && pcat_compat) /* * Map the legacy ISA devices into the IOSAPIC data. Some of these may * get reprogrammed later on with data from the ACPI Interrupt Source * Override table. */ - for (irq = 0; irq < 16; ++irq) { - vector = isa_irq_to_vector(irq); - if ((pin = iosapic_irq[vector].pin) == -1) - pin = irq; + for (isa_irq = 0; isa_irq < 16; ++isa_irq) { + vector = isa_irq_to_vector(isa_irq); - register_irq(irq, vector, pin, + register_intr(isa_irq, vector, IOSAPIC_LOWEST_PRIORITY, /* IOSAPIC_POL_HIGH, IOSAPIC_EDGE */ - IOSAPIC_LOWEST_PRIORITY, 1, 1, base_irq, addr); + 1, 1, gsi_base, addr); -#ifdef DEBUG_IRQ_ROUTING - printk("ISA: IRQ %u -> IOSAPIC irq 0x%02x (high, edge) -> vector 0x%02x\n", - irq, iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, - vector); -#endif + DBG("ISA: IRQ %u -> GSI 0x%x (high,edge) -> CPU 0x%04x vector %d\n", + isa_irq, isa_irq, dest, vector); /* program the IOSAPIC routing table: */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + set_rte(vector, dest); } + } +} - for (i = 0; i < pci_irq.num_routes; i++) { - irq = pci_irq.route[i].irq; - if ((irq < (int)base_irq) || (irq > (int)(base_irq + max_pin))) - /* the interrupt route is for another controller... */ - continue; +/* + * Set allocated interrupt vector to dev->irq and + * program IOSAPIC to deliver interrupts + */ +void +iosapic_fixup_pci_interrupt (struct pci_dev *dev) +{ + int segment; + unsigned char pci_pin; + int vector; + unsigned int dest; + struct hw_interrupt_type *irq_type; + irq_desc_t *idesc; - if (pcat_compat && (irq < 16)) - vector = isa_irq_to_vector(irq); - else { - vector = iosapic_irq_to_vector(irq); - if (vector < 0) - /* new iosapic irq: allocate a vector for it */ - vector = ia64_alloc_irq(); + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pci_pin); + if (pci_pin) { + pci_pin--; /* interrupt pins are numberd starting from 1 */ + + segment = PCI_SEGMENT(dev); + vector = pci_pin_to_vector(segment, dev->bus->number, PCI_SLOT(dev->devfn), pci_pin); + + if (vector < 0 && dev->bus->parent) { + /* go back to the bridge */ + struct pci_dev *bridge = dev->bus->self; + + if (bridge) { + /* allow for multiple bridges on an adapter */ + do { + /* do the bridge swizzle... */ + pci_pin = (pci_pin + PCI_SLOT(dev->devfn)) % 4; + vector = pci_pin_to_vector(segment, + bridge->bus->number, + PCI_SLOT(bridge->devfn), + pci_pin); + } while (vector < 0 && (bridge = bridge->bus->self)); + } + if (vector >= 0) + printk(KERN_WARNING + "PCI: using PPB (%s INT%c) to get vector %d\n", + dev->slot_name, 'A' + pci_pin, + vector); + else + printk(KERN_WARNING + "PCI: Couldn't map irq for (%s INT%c)\n", + dev->slot_name, 'A' + pci_pin); } - register_irq(irq, vector, irq - base_irq, - /* IOSAPIC_POL_LOW, IOSAPIC_LEVEL */ - IOSAPIC_LOWEST_PRIORITY, 0, 0, base_irq, addr); - -# ifdef DEBUG_IRQ_ROUTING - printk("PCI: (B%d,I%d,P%d) -> IOSAPIC irq 0x%02x -> vector 0x%02x\n", - pci_irq.route[i].bus, pci_irq.route[i].pci_id>>16, pci_irq.route[i].pin, - iosapic_irq[vector].base_irq + iosapic_irq[vector].pin, vector); -# endif + if (vector >= 0) { + dev->irq = vector; - /* program the IOSAPIC routing table: */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + irq_type = &irq_type_iosapic_level; + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) + printk("%s: changing vector %d from %s to %s\n", + __FUNCTION__, vector, + idesc->handler->typename, + irq_type->typename); + idesc->handler = irq_type; + } +#ifdef CONFIG_SMP + /* + * For platforms that do not support interrupt redirect + * via the XTP interface, we can round-robin the PCI + * device interrupts to the processors + */ + if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) { + static int cpu_index = 0; + + dest = cpu_physical_id(cpu_index) & 0xffff; + + cpu_index++; + if (cpu_index >= smp_num_cpus) + cpu_index = 0; + } else { + /* + * Direct the interrupt vector to the current cpu, + * platform redirection will distribute them. + */ + dest = (ia64_get_lid() >> 16) & 0xffff; + } +#else + /* direct the interrupt vector to the running cpu id */ + dest = (ia64_get_lid() >> 16) & 0xffff; +#endif + + printk("PCI->APIC IRQ transform: (%s INT%c) -> CPU 0x%04x vector %d\n", + dev->slot_name, 'A' + pci_pin, dest, vector); + set_rte(vector, dest); + } } } + void iosapic_pci_fixup (int phase) { struct pci_dev *dev; - unsigned char pin; - int vector; - struct hw_interrupt_type *irq_type; - irq_desc_t *idesc; + + if (phase == 0) { + if (0 != acpi_get_prt(&pci_irq.route, &pci_irq.num_routes)) { + printk("%s: acpi_get_prt failed\n", __FUNCTION__); + } + return; + } if (phase != 1) return; pci_for_each_dev(dev) { - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin) { - pin--; /* interrupt pins are numbered starting from 1 */ - vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); - if (vector < 0 && dev->bus->parent) { - /* go back to the bridge */ - struct pci_dev *bridge = dev->bus->self; - - if (bridge) { - /* allow for multiple bridges on an adapter */ - do { - /* do the bridge swizzle... */ - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - vector = pci_pin_to_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), - pin); - } while (vector < 0 && (bridge = bridge->bus->self)); - } - if (vector >= 0) - printk(KERN_WARNING - "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n", - dev->bus->number, PCI_SLOT(dev->devfn), - pin, vector); - else - printk(KERN_WARNING - "PCI: Couldn't map irq for (B%d,I%d,P%d)\n", - dev->bus->number, PCI_SLOT(dev->devfn), pin); - } - if (vector >= 0) { - printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n", - dev->bus->number, PCI_SLOT(dev->devfn), pin, vector); - dev->irq = vector; - - irq_type = &irq_type_iosapic_level; - idesc = irq_desc(vector); - if (idesc->handler != irq_type){ - if (idesc->handler != &no_irq_type) - printk("iosapic_pci_fixup: changing vector 0x%02x " - "from %s to %s\n", vector, - idesc->handler->typename, - irq_type->typename); - idesc->handler = irq_type; - } -#ifdef CONFIG_SMP - /* - * For platforms that do not support interrupt redirect - * via the XTP interface, we can round-robin the PCI - * device interrupts to the processors - */ - if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) { - static int cpu_index = 0; + /* fixup dev->irq and program IOSAPIC */ + iosapic_fixup_pci_interrupt(dev); - set_rte(vector, cpu_physical_id(cpu_index) & 0xffff); - - cpu_index++; - if (cpu_index >= smp_num_cpus) - cpu_index = 0; - } else { - /* - * Direct the interrupt vector to the current cpu, - * platform redirection will distribute them. - */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); - } -#else - /* direct the interrupt vector to the running cpu id */ - set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); -#endif - } - } /* * Nothing to fixup * Fix out-of-range IRQ numbers diff -Nur linux-2.4.19/arch/ia64/kernel/irq.c linux-2.4.19-sgi211r3/arch/ia64/kernel/irq.c --- linux-2.4.19/arch/ia64/kernel/irq.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/irq.c Sun Dec 22 13:06:04 2002 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -64,8 +65,33 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t _irq_desc[NR_IVECS] __cacheline_aligned = + { [0 ... NR_IVECS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; + +#ifdef CONFIG_IA64_GENERIC +struct irq_desc * +__ia64_irq_desc (unsigned int irq) +{ + return _irq_desc + irq; +} + +ia64_vector +__ia64_irq_to_vector (unsigned int irq) +{ + return (ia64_vector) irq; +} + +unsigned int +__ia64_local_vector_to_irq (ia64_vector vec) +{ + return (unsigned int) vec; +} + +#endif + +#ifdef CONFIG_IA64_SGI_SN +int irq_action[NR_IVECS]; +#endif static void register_irq_proc (unsigned int irq); @@ -131,57 +157,126 @@ * Generic, controller-independent functions: */ -int get_irq_list(char *buf) +static int +show_interrupts(struct seq_file *m, void *v) { - int i, j; + int i = *(int *)v; + int j; struct irqaction * action; irq_desc_t *idesc; - char *p = buf; - p += sprintf(p, " "); - for (j=0; j NR_IVECS) + BUG(); - for (i = 0 ; i < NR_IRQS ; i++) { + if (i == 0) { + seq_printf(m, " "); + for (j=0; jaction; +#ifdef CONFIG_IA64_SGI_SN + if (!action && !irq_action[i]) + return 0; +#else if (!action) - continue; - p += sprintf(p, "%3d: ",i); + return 0; +#endif + seq_printf(m, "%3d: ",i); #ifndef CONFIG_SMP - p += sprintf(p, "%10u ", kstat_irqs(i)); + seq_printf(m, "%10u ", kstat_irqs(i)); #else for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", + seq_printf(m, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); #endif - p += sprintf(p, " %14s", idesc->handler->typename); - p += sprintf(p, " %s", action->name); + seq_printf(m, " %14s", idesc->handler->typename); +#ifdef CONFIG_IA64_SGI_SN2 +#include + if (idesc->status & IRQ_PER_CPU || idesc->status & SN2_IRQ_PER_HUB) +#endif +#ifdef CONFIG_IA64_SGI_SN + if (action) +#endif + seq_printf(m, " %s", action->name); +#ifdef CONFIG_IA64_SGI_SN2 + for (j = 0; j < smp_num_cpus; j++) { + if (!(irq_desc(j<<8 | i)->status & IRQ_PER_CPU) && !(irq_desc(j<<8 | i)->status & SN2_IRQ_PER_HUB)) { + action = irq_desc(j<<8|i)->action; + if (!action) continue; + seq_printf(m, " %s(%d)", action->name,j); + } + if (j == 0 && (irq_desc(j<<8 | i)->status & IRQ_PER_CPU)) +#endif +#ifdef CONFIG_IA64_SGI_SN + if (action) + #endif for (action=action->next; action; action = action->next) - p += sprintf(p, ", %s", action->name); - *p++ = '\n'; + seq_printf(m, ", %s", action->name); + +#ifdef CONFIG_IA64_SGI_SN2 + } +#endif + seq_printf(m, "\n"); } - p += sprintf(p, "NMI: "); - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - nmi_count(cpu_logical_map(j))); - p += sprintf(p, "\n"); + else { + /* i == NR_IVECS */ + seq_printf(m, "NMI: "); + for (j = 0; j < smp_num_cpus; j++) + seq_printf(m, "%10u ", + nmi_count(cpu_logical_map(j))); + seq_printf(m, "\n"); #if defined(CONFIG_SMP) && defined(CONFIG_X86) - p += sprintf(p, "LOC: "); - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); - p += sprintf(p, "\n"); + seq_printf(m, "LOC: "); + for (j = 0; j < smp_num_cpus; j++) + seq_printf(m, "%10u ", + apic_timer_irqs[cpu_logical_map(j)]); + seq_printf(m, "\n"); #endif - p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); + seq_printf(m, "ERR: %10u\n", atomic_read(&irq_err_count)); #if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG) - p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); + seq_printf(m, "MIS: %10u\n", atomic_read(&irq_mis_count)); #endif - return p - buf; + } + + return 0; +} + +static void * +show_interrupts_start (struct seq_file *m, loff_t *pos) +{ + static int success = 1; + + if (*pos < 0 || *pos > NR_IVECS) + return NULL; + /* *pos == NR_IVECS is special for NMI and ERR trailer */ + show_interrupts(m, pos); + return &success; } +static void * +show_interrupts_next (struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return show_interrupts_start(m, pos); +} + +static void +show_interrupts_stop (struct seq_file *m, void *v) +{ +} + +struct seq_operations interrupts_op = { + start: show_interrupts_start, + next: show_interrupts_next, + stop: show_interrupts_stop, + show: show_interrupts +}; + /* * Global interrupt locks for SMP. Allow interrupts to come in on any @@ -598,7 +693,14 @@ struct irqaction * action; unsigned int status; - kstat.irqs[cpu][irq]++; +#ifdef BUS_INT_WAR + /* For now, dont count interrupts that originated from the "polling" + * path. They are not interesting & we need to make sure that no real + * interrupts are occurring. + */ + if (regs) +#endif + kstat.irqs[cpu][irq_to_vector(irq)]++; if (desc->status & IRQ_PER_CPU) { /* no locking required for CPU-local interrupts: */ @@ -741,6 +843,11 @@ retval = setup_irq(irq, action); if (retval) kfree(action); +#ifdef CONFIG_IA64_SGI_SN + if (!retval) { + irq_action[irq_to_vector(irq)]++; + } +#endif return retval; } @@ -767,11 +874,27 @@ irq_desc_t *desc; struct irqaction **p; unsigned long flags; +#ifdef CONFIG_IA64_SGI_SN + int sgi_i, sgi_num_cpus = 1; + int free_done = 0; +#endif /* CONFIG_IA64_SGI_SN */ if (irq >= NR_IRQS) return; desc = irq_desc(irq); +#ifdef CONFIG_IA64_SGI_SN + if (desc->status & IRQ_PER_CPU) { + sgi_i = 0; + sgi_num_cpus = NR_CPUS; + } else { + sgi_i = irq >> 8; + sgi_num_cpus = sgi_i + 1; + } + for (sgi_i; sgi_i < sgi_num_cpus; sgi_i++) { + desc = irq_desc(sgi_i<<8 | irq_to_vector(irq)); + free_done = 0; +#endif /* CONFIG_IA64_SGI_SN */ spin_lock_irqsave(&desc->lock,flags); p = &desc->action; for (;;) { @@ -782,6 +905,10 @@ if (action->dev_id != dev_id) continue; +#ifdef CONFIG_IA64_SGI_SN + if (irq_action[irq_to_vector(irq)] > 0) + irq_action[irq_to_vector(irq)]--; +#endif /* Found it - now remove it from the list of entries */ *pp = action->next; if (!desc->action) { @@ -795,13 +922,24 @@ while (desc->status & IRQ_INPROGRESS) barrier(); #endif +#ifdef CONFIG_IA64_SGI_SN + if (!free_done) { + kfree(action); + free_done = 1; + } + break; +#else /* CONFIG_IA64_SGI_SN */ kfree(action); return; +#endif /* CONFIG_IA64_SGI_SN */ } printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&desc->lock,flags); return; } +#ifdef CONFIG_IA64_SGI_SN + } +#endif /* CONFIG_IA64_SGI_SN */ } /* @@ -1049,7 +1187,7 @@ } static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * irq_dir [NR_IVECS]; #define HEX_DIGITS 8 @@ -1092,9 +1230,12 @@ #if CONFIG_SMP -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IVECS]; -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +#if !defined(CONFIG_DUMP) && !defined(CONFIG_DUMP_MODULE) +static +#endif + unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; void set_irq_affinity_info(int irq, int hwid, int redir) @@ -1144,7 +1285,7 @@ if (!(new_value & cpu_online_map)) return -EINVAL; - irq_desc(irq)->handler->set_affinity(irq | (redir?(1<<31):0), new_value); + irq_desc(irq)->handler->set_affinity(irq | (redir? IA64_IRQ_REDIRECTED :0), new_value); return full_count; } @@ -1180,29 +1321,29 @@ { char name [MAX_NAMELEN]; - if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type)) + if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type) || irq_dir[irq]) return; memset(name, 0, MAX_NAMELEN); - sprintf(name, "%d", irq); + sprintf(name, "%d", irq_to_vector(irq)); /* create /proc/irq/1234 */ - irq_dir[irq] = proc_mkdir(name, root_irq_dir); + irq_dir[irq_to_vector(irq)] = proc_mkdir(name, root_irq_dir); #if CONFIG_SMP { struct proc_dir_entry *entry; /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq_to_vector(irq)]); if (entry) { entry->nlink = 1; - entry->data = (void *)(long)irq; + entry->data = (void *)(long)irq_to_vector(irq); entry->read_proc = irq_affinity_read_proc; entry->write_proc = irq_affinity_write_proc; } - smp_affinity_entry[irq] = entry; + smp_affinity_entry[irq_to_vector(irq)] = entry; } #endif } @@ -1231,7 +1372,7 @@ /* * Create entries for all existing IRQs. */ - for (i = 0; i < NR_IRQS; i++) { + for (i = 0; i < NR_IVECS; i++) { if (irq_desc(i)->handler == &no_irq_type) continue; register_irq_proc(i); diff -Nur linux-2.4.19/arch/ia64/kernel/irq_ia64.c linux-2.4.19-sgi211r3/arch/ia64/kernel/irq_ia64.c --- linux-2.4.19/arch/ia64/kernel/irq_ia64.c Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/irq_ia64.c Thu Feb 13 10:59:52 2003 @@ -36,8 +36,17 @@ #include #include +#ifdef CONFIG_PERFMON +# include +#endif + #define IRQ_DEBUG 0 +#ifdef BUS_INT_WAR +int bus_int_war_ide_irq; +long allow_ints=1; +#endif + /* default base addr of IPI table */ unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR); @@ -51,14 +60,14 @@ }; int -ia64_alloc_irq (void) +ia64_alloc_vector (void) { - static int next_irq = IA64_FIRST_DEVICE_VECTOR; + static int next_vector = IA64_FIRST_DEVICE_VECTOR; - if (next_irq > IA64_LAST_DEVICE_VECTOR) + if (next_vector > IA64_LAST_DEVICE_VECTOR) /* XXX could look for sharable vectors instead of panic'ing... */ - panic("ia64_alloc_irq: out of interrupt vectors!"); - return next_irq++; + panic("%s: out of interrupt vectors!", __FUNCTION__); + return next_vector++; } extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs); @@ -115,9 +124,31 @@ */ saved_tpr = ia64_get_tpr(); ia64_srlz_d(); + +#ifdef CONFIG_IA64_SGI_SN2 + ia64_eoi(); +#endif + while (vector != IA64_SPURIOUS_INT_VECTOR) { + +#ifdef BUS_INT_WAR + if (regs) { + if (IS_RUNNING_ON_SIMULATOR() && vector == bus_int_war_ide_irq) { + vector = IA64_IPI_RESCHEDULE; + } + } +#endif +#ifdef BUS_INT_WAR + if (!IS_RESCHEDULE(vector) && (allow_ints || regs==0 || vector == IA64_TIMER_VECTOR || vector == IA64_PERFMON_VECTOR)) { + if (regs) /* applies to ia64_set_tpr() below */ +#else if (!IS_RESCHEDULE(vector)) { +#endif +#ifdef CONFIG_IA64_SGI_SN2 + sn_set_tpr(vector); +#else ia64_set_tpr(vector); +#endif ia64_srlz_d(); do_IRQ(local_vector_to_irq(vector), regs); @@ -127,9 +158,32 @@ */ local_irq_disable(); ia64_set_tpr(saved_tpr); + } else { + kstat.irqs[smp_processor_id()][IA64_IPI_RESCHEDULE]++; } +#ifdef BUS_INT_WAR + if (regs) { + ia64_eoi(); + vector = ia64_get_ivr(); + } else { + vector = IA64_SPURIOUS_INT_VECTOR; + } +#else +#ifdef CONFIG_IA64_SGI_SN2 + { + int old_vector = vector; + if (IS_RESCHEDULE(vector)) + local_irq_disable(); + vector = sn_get_ivr(); + if (IS_RESCHEDULE(old_vector)) + local_irq_enable(); + } +#else ia64_eoi(); vector = ia64_get_ivr(); +#endif + +#endif } /* * This must be done *after* the ia64_eoi(). For example, the keyboard softirq @@ -148,6 +202,12 @@ flags: SA_INTERRUPT, name: "IPI" }; + +static struct irqaction resched_irqaction = { + handler: NULL, + flags: SA_INTERRUPT, + name: "Reschedule" +}; #endif void @@ -172,6 +232,10 @@ register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL); #ifdef CONFIG_SMP register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction); + register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction); +#endif +#ifdef CONFIG_PERFMON + perfmon_init_percpu(); #endif platform_irq_init(); } diff -Nur linux-2.4.19/arch/ia64/kernel/ivt.S linux-2.4.19-sgi211r3/arch/ia64/kernel/ivt.S --- linux-2.4.19/arch/ia64/kernel/ivt.S Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/ivt.S Tue Jan 14 11:05:06 2003 @@ -125,8 +125,13 @@ shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of the faulting address ;; (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + .global ia64_ivt_patch1 +ia64_ivt_patch1: +{ .mlx // we patch this bundle to include physical address of swapper_pg_dir srlz.d // ensure "rsm psr.dt" has taken effect -(p6) movl r19=__pa(SWAPPER_PGD_ADDR) // region 5 is rooted at swapper_pg_dir +(p6) movl r19=swapper_pg_dir // region 5 is rooted at swapper_pg_dir +} + .pred.rel "mutex", p6, p7 (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 ;; @@ -316,6 +321,7 @@ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) mov r21=cr.ipsr mov r31=pr + mov r25=_PAGE_SIZE_4K<<2 ;; #ifdef CONFIG_DISABLE_VHPT shr.u r22=r16,61 // get the region number into r21 @@ -328,20 +334,28 @@ (p8) mov r29=b0 // save b0 (p8) br.cond.dptk dtlb_fault #endif + movl r27=((1<<(36-IA64_GRANULE_SHIFT))-1)< #include #include +#include #include #include #include #include +#include +#ifdef CONFIG_KDB +#include +#endif #include #include @@ -43,10 +53,10 @@ #include #include #include +#include #include #include -#include #undef MCA_PRT_XTRA_DATA @@ -62,7 +72,7 @@ u64 ia64_mca_stack[1024] __attribute__((aligned(16))); u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; -u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); +u64 ia64_init_stack[INIT_TASK_SIZE/8] __attribute__((aligned(16))); u64 ia64_mca_sal_data_area[1356]; u64 ia64_mca_min_state_save_info; u64 ia64_tlb_functional; @@ -72,9 +82,9 @@ static void ia64_mca_wakeup(int cpu); static void ia64_mca_wakeup_all(void); static void ia64_log_init(int); -extern void ia64_monarch_init_handler (void); -extern void ia64_slave_init_handler (void); -extern struct hw_interrupt_type irq_type_iosapic_level; +extern void ia64_monarch_init_handler (void); +extern void ia64_slave_init_handler (void); +extern struct hw_interrupt_type irq_type_iosapic_level; static struct irqaction cmci_irqaction = { handler: ia64_mca_cmc_int_handler, @@ -108,16 +118,17 @@ * memory. * * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) + * : clear_errs (indicates if errors should be cleared) * Outputs : platform error status */ int -ia64_mca_log_sal_error_record(int sal_info_type) +ia64_mca_log_sal_error_record(int sal_info_type, int clear_errs) { int platform_err = 0; /* Get the MCA error record */ if (!ia64_log_get(sal_info_type, (prfunc_t)printk)) - return platform_err; // no record retrieved + return -1; // no record retrieved /* TODO: * 1. analyze error logs to determine recoverability @@ -126,7 +137,9 @@ */ platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk); - ia64_sal_clear_state_info(sal_info_type); + if (clear_errs) { + ia64_sal_clear_state_info(sal_info_type); + } return platform_err; } @@ -147,7 +160,7 @@ IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq); /* Get the CMC error record and log it */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 1); } /* @@ -161,7 +174,14 @@ { /* if a kernel debugger is available call it here else just dump the registers */ +#ifndef CONFIG_IA64_SGI_SN + /* show_regs() frequently hangs. Disable for now. */ show_regs(regs); /* dump the state info */ +#endif + +#ifdef CONFIG_KDB + kdb(KDB_REASON_CALL, 0, regs); +#endif /* CONFIG_KDB */ while (1); /* hang city if no debugger */ } @@ -197,10 +217,31 @@ void ia64_mca_check_errors (void) { + int platform_err; + int print_note = 0; + /* * If there is an MCA error record pending, get it and log it. */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); + platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1); + if (platform_err != -1) { + print_note = 1; + } + +#ifdef IA64_DUMP_INIT_RECORDS_AT_BOOT + platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_INIT, 1); + if (platform_err != -1) { + print_note = 1; + } +#endif + + if (print_note) { + printk("+ \n"); + printk("+ The above MCA error records were posted by SAL for a prior failure\n"); + printk("+ which resulted in a machine shutdown before an the error could be logged.\n"); + printk("+ They are probably not a result of the current boot.\n"); + printk("+ \n"); + } } /* @@ -294,8 +335,17 @@ cmcv_reg_t cmcv; cmcv.cmcv_regval = 0; - cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ - cmcv.cmcv_vector = IA64_CMC_VECTOR; + cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ + cmcv.cmcv_vector = IA64_CMC_VECTOR; + +#ifdef BUS_INT_WAR + { + void sn_add_polled_interrupt(int irq, int interval); + sn_add_polled_interrupt(platform_local_vector_to_irq(IA64_CMC_VECTOR), 5000); + cmcv.cmcv_mask = 1; /*Disable interrupts. Poll instead */ + } +#endif + ia64_set_cmcv(cmcv.cmcv_regval); IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected " @@ -348,17 +398,15 @@ verify_guid (efi_guid_t *test, efi_guid_t *target) { int rc; +#ifdef IA64_MCA_DEBUG_INFO + char out[40]; +#endif - if ((rc = memcmp((void *)test, (void *)target, sizeof(efi_guid_t)))) { - IA64_MCA_DEBUG("ia64_mca_print: invalid guid = " - "{ %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " - "%#02x, %#02x, %#02x, %#02x, } } \n ", - test->data1, test->data2, test->data3, test->data4[0], - test->data4[1], test->data4[2], test->data4[3], - test->data4[4], test->data4[5], test->data4[6], - test->data4[7]); + if ((rc = efi_guidcmp(*test, *target))) { + IA64_MCA_DEBUG(KERN_DEBUG + "verify_guid: invalid GUID = %s\n", + efi_guid_unparse(test, out)); } - return rc; } @@ -429,17 +477,17 @@ IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); - ia64_mc_info.imi_mca_handler = __pa(mca_hldlr_ptr->fp); + ia64_mc_info.imi_mca_handler = __tpa(mca_hldlr_ptr->fp); /* * XXX - disable SAL checksum by setting size to 0; should be - * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); + * __tpa(ia64_os_mca_dispatch_end) - __tpa(ia64_os_mca_dispatch); */ ia64_mc_info.imi_mca_handler_size = 0; /* Register the os mca handler with SAL */ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, ia64_mc_info.imi_mca_handler, - mca_hldlr_ptr->gp, + __tpa(mca_hldlr_ptr->gp), ia64_mc_info.imi_mca_handler_size, 0, 0, 0))) { @@ -449,15 +497,15 @@ } IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", - ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp); + ia64_mc_info.imi_mca_handler, __tpa(mca_hldlr_ptr->gp)); /* * XXX - disable SAL checksum by setting size to 0, should be * IA64_INIT_HANDLER_SIZE */ - ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler = __tpa(mon_init_ptr->fp); ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler = __tpa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", @@ -466,10 +514,10 @@ /* Register the os init handler with SAL */ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, ia64_mc_info.imi_monarch_init_handler, - __pa(ia64_get_gp()), + __tpa(ia64_get_gp()), ia64_mc_info.imi_monarch_init_handler_size, ia64_mc_info.imi_slave_init_handler, - __pa(ia64_get_gp()), + __tpa(ia64_get_gp()), ia64_mc_info.imi_slave_init_handler_size))) { printk("ia64_mca_init: Failed to register m/s init handlers with SAL. rc = %ld\n", @@ -496,7 +544,7 @@ { irq_desc_t *desc; unsigned int irq; - int cpev = acpi_request_vector(ACPI20_ENTRY_PIS_CPEI); + int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI); if (cpev >= 0) { for (irq = 0; irq < NR_IRQS; ++irq) @@ -531,7 +579,7 @@ #if 0 // Too early in initialization -- error log is lost /* Do post-failure MCA error logging */ - ia64_mca_check_errors(); + ia64_mca_check_errors(1); #endif // Too early in initialization -- error log is lost } @@ -700,6 +748,9 @@ /* Register pointer to new min state values */ /* NOTE: need to do something with this during recovery phase */ ia64_os_to_sal_handoff_state.imots_new_min_state = &ia64_mca_min_state_save_info; +#ifdef CONFIG_KDB + KDB_ENTER(); +#endif /* CONFIG_KDB */ } /* @@ -710,10 +761,10 @@ * This is the place where the core of OS MCA handling is done. * Right now the logs are extracted and displayed in a well-defined * format. This handler code is supposed to be run only on the - * monarch processor. Once the monarch is done with MCA handling + * monarch processor. Once the monarch is done with MCA handling * further MCA logging is enabled by clearing logs. * Monarch also has the duty of sending wakeup-IPIs to pull the - * slave processors out of rendezvous spinloop. + * slave processors out of rendezvous spinloop. * * Inputs : None * Outputs : None @@ -722,14 +773,30 @@ ia64_mca_ucmc_handler(void) { int platform_err = 0; + int loglevel_save = console_loglevel; + +#ifdef CONFIG_IA64_SGI_SN + if (sal_lock.lock) { + udelay(500000); + sal_lock.lock = 0; + } +#endif + + /* + * Enable console logging. This MAY cause a deadlock if the MCA occurred + * while critical locks were set. But what have we got to lose..... + * This policy must be revisited when we can recover from certain types + * of MCAs. + */ + console_loglevel = 8; /* Get the MCA error record and log it */ - platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); + platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0); /* * Do Platform-specific mca error handling if required. */ - if (platform_err) + if (platform_err > 0) mca_handler_platform(); /* @@ -740,6 +807,7 @@ /* Return to SAL */ ia64_return_to_sal_check(); + console_loglevel = loglevel_save; } /* @@ -764,7 +832,7 @@ cmc_irq, smp_processor_id()); /* Get the CMC error record and log it */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 1); } /* @@ -816,12 +884,31 @@ { sal_log_processor_info_t *proc_ptr; ia64_err_rec_t *plog_ptr; + int loglevel_save = console_loglevel; + +#ifdef CONFIG_IA64_SGI_SN + if (sal_lock.lock) { + udelay(500000); + sal_lock.lock = 0; + } +#endif + /* + * Enable console logging. This MAY cause a deadlock if the INIT occurred + * while critical locks were set. But what have we got to lose..... + * This policy must be revisited when we can recover from certain types + * of INITs. + */ + console_loglevel = 8; printk("Entered OS INIT handler\n"); +#ifndef CONFIG_IA64_SGI_SN1 /* SN1 firmwares don't do this yet */ /* Get the INIT processor log */ - if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk)) + if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk)) { + console_loglevel = loglevel_save; return; // no record retrieved + } +#endif #ifdef IA64_DUMP_ALL_PROC_INFO ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk); @@ -837,10 +924,18 @@ ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area, regs); +#ifndef CONFIG_IA64_SGI_SN /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); +#endif init_handler_platform(regs); /* call platform specific routines */ + +#ifdef CONFIG_KDB + kdb(KDB_REASON_CALL, 0, regs); +#endif /* CONFIG_KDB */ + + console_loglevel = loglevel_save; } /* @@ -856,11 +951,8 @@ void ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc) { - printk("GUID = { %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " - "%#02x, %#02x, %#02x, %#02x, } } \n ", p_guid->data1, - p_guid->data2, p_guid->data3, p_guid->data4[0], p_guid->data4[1], - p_guid->data4[2], p_guid->data4[3], p_guid->data4[4], - p_guid->data4[5], p_guid->data4[6], p_guid->data4[7]); + char out[40]; + printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out)); } static void @@ -922,7 +1014,11 @@ IA64_LOG_LOCK_INIT(sal_info_type); // SAL will tell us the maximum size of any error record of this type +#ifndef CONFIG_IA64_SGI_SN1 max_size = ia64_sal_get_state_info_size(sal_info_type); +#else + max_size = 10000; +#endif // set up OS data structures to hold error info IA64_LOG_ALLOCATE(sal_info_type, max_size); @@ -962,7 +1058,9 @@ return total_len; } else { IA64_LOG_UNLOCK(sal_info_type); +#ifndef CONFIG_IA64_SGI_SN prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type); +#endif return 0; } } @@ -1009,23 +1107,16 @@ sprintf(str_buf, "%2d.%02d", (lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf), (lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf)); - prfunc("+Err Record ID: %d SAL Rev: %s\n", lh->id, str_buf); - sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d", - (lh->timestamp.slh_month >> 4) * 10 + - (lh->timestamp.slh_month & 0xf), - (lh->timestamp.slh_day >> 4) * 10 + - (lh->timestamp.slh_day & 0xf), - (lh->timestamp.slh_century >> 4) * 1000 + - (lh->timestamp.slh_century & 0xf) * 100 + - (lh->timestamp.slh_year >> 4) * 10 + - (lh->timestamp.slh_year & 0xf), - (lh->timestamp.slh_hour >> 4) * 10 + - (lh->timestamp.slh_hour & 0xf), - (lh->timestamp.slh_minute >> 4) * 10 + - (lh->timestamp.slh_minute & 0xf), - (lh->timestamp.slh_second >> 4) * 10 + - (lh->timestamp.slh_second & 0xf)); - prfunc("+Time: %s Severity %d\n", str_buf, lh->severity); + prfunc("+ Err Record ID: %d SAL Rev: %s\n", lh->id, str_buf); + sprintf(str_buf, "%02x/%02x/%02x%02x/ %02x:%02x:%02x", + lh->timestamp.slh_month, + lh->timestamp.slh_day, + lh->timestamp.slh_century, + lh->timestamp.slh_year, + lh->timestamp.slh_hour, + lh->timestamp.slh_minute, + lh->timestamp.slh_second); + prfunc("+ Time: %s Severity %d\n", str_buf, lh->severity); } /* @@ -1524,7 +1615,7 @@ } if (psei->valid.oem_data) { platform_plat_specific_err_print((int)psei->header.len, - (int)sizeof(sal_log_plat_specific_err_info_t) - 1, + ((char*)psei->oem_data - (char*)psei), &(psei->oem_data[0]), prfunc); } prfunc("\n"); @@ -1620,7 +1711,7 @@ int i; sal_log_mod_error_info_t *p_data; - prfunc("+Processor Device Error Info Section\n"); + prfunc("+ Processor Device Error Info Section\n"); #ifdef MCA_PRT_XTRA_DATA // for test only @FVL { @@ -1634,13 +1725,13 @@ #endif // MCA_PRT_XTRA_DATA for test only @FVL if (slpi->valid.proc_error_map) - prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map); + prfunc("+ Processor Error Map: %#lx\n", slpi->proc_error_map); if (slpi->valid.proc_state_param) - prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter); + prfunc("+ Processor State Param: %#lx\n", slpi->proc_state_parameter); if (slpi->valid.proc_cr_lid) - prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid); + prfunc("+ Processor LID: %#lx\n", slpi->proc_cr_lid); /* * Note: March 2001 SAL spec states that if the number of elements in any @@ -1676,11 +1767,12 @@ if (slpi->valid.cpuid_info) { u64 *p = (u64 *)p_data; - prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]); + prfunc("+ CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]); p_data++; } /* Print processor static info if any */ +#ifndef CONFIG_IA64_SGI_SN2 if (slpi->valid.psi_static_struct) { spsi = (sal_processor_static_info_t *)p_data; @@ -1709,6 +1801,12 @@ ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr", prfunc); } +#endif + +#ifdef CONFIG_IA64_SGI_SN2 + platform_plat_specific_err_print((int)slpi->header.len, + 0, (void*)slpi, prfunc); +#endif } /* @@ -1754,7 +1852,7 @@ ia64_log_prt_section_header(slsh, prfunc); #endif // MCA_PRT_XTRA_DATA for test only @FVL - if (verify_guid((void *)&slsh->guid, (void *)&(SAL_PROC_DEV_ERR_SECT_GUID))) { + if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) { IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); continue; } @@ -1788,9 +1886,9 @@ int ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc) { - sal_log_section_hdr_t *slsh; - int n_sects; - int ercd_pos; + sal_log_section_hdr_t *slsh; + int n_sects; + int ercd_pos; int platform_err = 0; if (!lh) @@ -1911,7 +2009,13 @@ prfunc("+END HARDWARE ERROR STATE AT MCA\n"); break; case SAL_INFO_TYPE_INIT: +#ifdef CONFIG_IA64_SGI_SN2 + prfunc("+BEGIN HARDWARE ERROR STATE AT INIT\n"); + platform_err = ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + prfunc("+END HARDWARE ERROR STATE AT INIT\n"); +#else prfunc("+MCA INIT ERROR LOG (UNIMPLEMENTED)\n"); +#endif break; case SAL_INFO_TYPE_CMC: prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n"); diff -Nur linux-2.4.19/arch/ia64/kernel/mca_asm.S linux-2.4.19-sgi211r3/arch/ia64/kernel/mca_asm.S --- linux-2.4.19/arch/ia64/kernel/mca_asm.S Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/mca_asm.S Tue May 14 09:10:56 2002 @@ -49,14 +49,13 @@ * 5. GR11 = Rendez state * 6. GR12 = Return address to location within SAL_CHECK */ -#define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - movl _tmp=ia64_sal_to_os_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ - st8 [_tmp]=r1,0x08;; \ - st8 [_tmp]=r8,0x08;; \ - st8 [_tmp]=r9,0x08;; \ - st8 [_tmp]=r10,0x08;; \ - st8 [_tmp]=r11,0x08;; \ +#define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp,_tmp2) \ + DATA_SYM_TO_PA(_tmp,ia64_sal_to_os_handoff_state,_tmp2);; \ + st8 [_tmp]=r1,0x08;; \ + st8 [_tmp]=r8,0x08;; \ + st8 [_tmp]=r9,0x08;; \ + st8 [_tmp]=r10,0x08;; \ + st8 [_tmp]=r11,0x08;; \ st8 [_tmp]=r12,0x08 /* @@ -117,7 +116,7 @@ // is dependent on the way the C-structure // for ia64_mca_sal_to_os_state_t has been // defined in include/asm/mca.h - SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) + SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2,r3) ;; // LOG PROCESSOR STATE INFO FROM HERE ON.. @@ -127,17 +126,15 @@ ia64_os_mca_done_dump: // Setup new stack frame for OS_MCA handling - movl r2=ia64_mca_bspstore;; // local bspstore area location in r2 - DATA_VA_TO_PA(r2);; - movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3 - DATA_VA_TO_PA(r3);; + DATA_SYM_TO_PA(r2,ia64_mca_bspstore,r12) + DATA_SYM_TO_PA(r3,ia64_mca_stackframe,r12) rse_switch_context(r6,r3,r2);; // RSC management in this new context - movl r12=ia64_mca_stack + + DATA_SYM_TO_PA(r12,ia64_mca_stack,r2) mov r2=8*1024;; // stack size must be same as C array add r12=r2,r12;; // stack base @ bottom of array adds r12=-16,r12;; // allow 16 bytes of scratch // (C calling convention) - DATA_VA_TO_PA(r12);; // Check to see if the MCA resulted from a TLB error begin_tlb_error_check: @@ -207,8 +204,7 @@ ia64_os_mca_proc_state_dump: // Save bank 1 GRs 16-31 which will be used by c-language code when we switch // to virtual addressing mode. - movl r2=ia64_mca_proc_state_dump;; // Os state dump area - DATA_VA_TO_PA(r2) // convert to to physical address + DATA_SYM_TO_PA(r2,ia64_mca_proc_state_dump,r5) // Os state dump area // save ar.NaT mov r5=ar.unat // ar.unat @@ -675,18 +671,12 @@ // Retrieve sal data structure for uncorrected MCA // Make the ia64_sal_get_state_info() call - movl r4=ia64_mca_sal_data_area;; - movl r7=ia64_sal;; + DATA_SYM_TO_PA(r4,ia64_mca_sal_data_area,r8) + DATA_SYM_TO_PA(r7,ia64_sal_phys,r8);; mov r6=r1 // save gp - DATA_VA_TO_PA(r4) // convert to physical address - DATA_VA_TO_PA(r7);; // convert to physical address - ld8 r7=[r7] // get addr of pdesc from ia64_sal - movl r3=SAL_GET_STATE_INFO;; - DATA_VA_TO_PA(r7);; // convert to physical address ld8 r8=[r7],8;; // get pdesc function pointer - DATA_VA_TO_PA(r8) // convert to physical address - ld8 r1=[r7];; // set new (ia64_sal) gp - DATA_VA_TO_PA(r1) // convert to physical address + ld8 r1=[r7] // set new (ia64_sal) gp + movl r3=SAL_GET_STATE_INFO mov b6=r8 alloc r5=ar.pfs,8,0,8,0;; // allocate stack frame for SAL call @@ -704,8 +694,7 @@ mov r1=r6 // restore gp mov ar.pfs=r5;; // restore ar.pfs - movl r6=ia64_tlb_functional;; - DATA_VA_TO_PA(r6) // needed later + DATA_SYM_TO_PA(r6,ia64_tlb_functional,r9) // needed later cmp.eq p6,p7=r0,r8;; // check SAL call return address (p7) st8 [r6]=r0 // clear tlb_functional flag @@ -764,7 +753,7 @@ GLOBAL_ENTRY(ia64_monarch_init_handler) // stash the information the SAL passed to os - SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) + SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2,r3) ;; // now we want to save information so we can dump registers diff -Nur linux-2.4.19/arch/ia64/kernel/minstate.h linux-2.4.19-sgi211r3/arch/ia64/kernel/minstate.h --- linux-2.4.19/arch/ia64/kernel/minstate.h Tue Jul 31 10:30:08 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/minstate.h Fri Apr 26 11:07:18 2002 @@ -59,7 +59,7 @@ (pUser) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ ;; \ (pUser) mov rARRNAT=ar.rnat; \ -(pKern) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ +(pKern) tpa r1=sp; /* compute physical addr of sp */ \ (pUser) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ (pUser) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ (pUser) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */\ @@ -92,7 +92,6 @@ * * Assumed state upon entry: * psr.ic: off - * psr.dt: off * r31: contains saved predicates (pr) * * Upon exit, the state is as follows: @@ -186,7 +185,6 @@ * * Assumed state upon entry: * psr.ic: on - * psr.dt: on * r2: points to &pt_regs.r16 * r3: points to &pt_regs.r17 */ diff -Nur linux-2.4.19/arch/ia64/kernel/pal.S linux-2.4.19-sgi211r3/arch/ia64/kernel/pal.S --- linux-2.4.19/arch/ia64/kernel/pal.S Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/pal.S Mon Jan 13 15:32:26 2003 @@ -114,7 +114,7 @@ ;; rsm psr.i mov b7 = loc2 - ;; + ;; br.call.sptk.many rp=b7 // now make the call .ret0: mov psr.l = loc3 mov ar.pfs = loc1 @@ -161,10 +161,10 @@ ;; mov loc3 = psr // save psr adds r8 = 1f-1b,r8 // calculate return address for call - ;; + ;; mov loc4=ar.rsc // save RSE configuration dep.z loc2=loc2,0,61 // convert pal entry point to physical - dep.z r8=r8,0,61 // convert rp to physical + tpa r8=r8 // convert rp to physical ;; mov b7 = loc2 // install target to branch reg mov ar.rsc=0 // put RSE in enforced lazy, LE mode @@ -174,13 +174,13 @@ or loc3=loc3,r17 // add in psr the bits to set ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret1: mov rp = r8 // install return address (physical) br.cond.sptk.many b7 1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret2: mov psr.l = loc3 // restore init PSR @@ -216,7 +216,7 @@ mov out3 = in3 // copy arg3 ;; mov loc3 = psr // save psr - ;; + ;; mov loc4=ar.rsc // save RSE configuration dep.z loc2=loc2,0,61 // convert pal entry point to physical ;; @@ -228,13 +228,13 @@ mov b7 = loc2 // install target to branch reg ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret6: br.call.sptk.many rp=b7 // now make the call .ret7: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret8: mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 @@ -245,3 +245,49 @@ br.ret.sptk.many b0 END(ia64_pal_call_phys_stacked) +/* + * Save scratch fp scratch regs (fp10-fp15) + * + * NOTE: We need to do this since firmware (SAL or PAL) uses more + * scratch fp regs than the Linux kernel does. + * + * Inputs: + * in0 Address of stack storage for fp regs + */ + +GLOBAL_ENTRY(ia64_save_scratch_fpregs) + alloc r3=ar.pfs,1,0,0,0 + add r2=16,in0 + ;; + stf.spill [in0] = f10,32 + stf.spill [r2] = f11,32 + ;; + stf.spill [in0] = f12,32 + stf.spill [r2] = f13,32 + ;; + stf.spill [in0] = f14,32 + stf.spill [r2] = f15,32 + br.ret.sptk.many rp +END(ia64_save_scratch_fpregs) + +/* + * Load scratch fp scratch regs (fp10-fp15) + * + * Inputs: + * in0 Address of stack storage for fp regs + */ + +GLOBAL_ENTRY(ia64_load_scratch_fpregs) + alloc r3=ar.pfs,1,0,0,0 + add r2=16,in0 + ;; + ldf.fill f10 = [in0],32 + ldf.fill f11 = [r2],32 + ;; + ldf.fill f12 = [in0],32 + ldf.fill f13 = [r2],32 + ;; + ldf.fill f14 = [in0],32 + ldf.fill f15 = [r2],32 + br.ret.sptk.many rp +END(ia64_load_scratch_fpregs) diff -Nur linux-2.4.19/arch/ia64/kernel/palinfo.c linux-2.4.19-sgi211r3/arch/ia64/kernel/palinfo.c --- linux-2.4.19/arch/ia64/kernel/palinfo.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/palinfo.c Thu Dec 19 13:35:13 2002 @@ -21,10 +21,10 @@ #include #include #include +#include #include #include -#include #include #include #ifdef CONFIG_SMP @@ -101,26 +101,15 @@ #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *)) -/* - * The current revision of the Volume 2 (July 2000) of - * IA-64 Architecture Software Developer's Manual is wrong. - * Table 4-10 has invalid information concerning the ma field: - * Correct table is: - * bit 0 - 001 - UC - * bit 4 - 100 - UC - * bit 5 - 101 - UCE - * bit 6 - 110 - WC - * bit 7 - 111 - NatPage - */ static const char *mem_attrib[]={ - "Write Back (WB)", /* 000 */ - "Uncacheable (UC)", /* 001 */ - "Reserved", /* 010 */ - "Reserved", /* 011 */ - "Uncacheable (UC)", /* 100 */ - "Uncacheable Exported (UCE)", /* 101 */ - "Write Coalescing (WC)", /* 110 */ - "NaTPage" /* 111 */ + "WB", /* 000 */ + "SW", /* 001 */ + "010", /* 010 */ + "011", /* 011 */ + "UC", /* 100 */ + "UCE", /* 101 */ + "WC", /* 110 */ + "NaTPage" /* 111 */ }; /* @@ -315,6 +304,7 @@ pal_vm_info_2_u_t vm_info_2; pal_tc_info_u_t tc_info; ia64_ptce_info_t ptce; + const char *sep; int i, j; s64 status; @@ -339,7 +329,15 @@ if (ia64_pal_mem_attrib(&attrib) != 0) return 0; - p += sprintf(p, "Supported memory attributes : %s\n", mem_attrib[attrib&0x7]); + p += sprintf(p, "Supported memory attributes : "); + sep = ""; + for (i = 0; i < 8; i++) { + if (attrib & (1 << i)) { + p += sprintf(p, "%s%s", sep, mem_attrib[i]); + sep = ", "; + } + } + p += sprintf(p, "\n"); if ((status=ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) { printk("ia64_pal_vm_page_size=%ld\n", status); diff -Nur linux-2.4.19/arch/ia64/kernel/pci.c linux-2.4.19-sgi211r3/arch/ia64/kernel/pci.c --- linux-2.4.19/arch/ia64/kernel/pci.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/pci.c Wed Oct 16 14:02:58 2002 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -42,104 +43,256 @@ extern void ia64_mca_check_errors( void ); #endif +struct pci_fixup pcibios_fixups[1]; + +struct pci_ops *pci_root_ops; + +int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); +int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); + + /* - * This interrupt-safe spinlock protects all accesses to PCI - * configuration space. + * Low-level SAL-based PCI configuration access functions. Note that SAL + * calls are already serialized (via sal_lock), so we don't need another + * synchronization mechanism here. */ -static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; -struct pci_fixup pcibios_fixups[] = { - { 0 } -}; +#define PCI_SAL_ADDRESS(seg, bus, dev, fn, reg) \ + ((u64)(seg << 24) | (u64)(bus << 16) | \ + (u64)(dev << 11) | (u64)(fn << 8) | (u64)(reg)) + +static int +pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +{ + int result = 0; + u64 data = 0; + + if (!value || (seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; -/* Macro to build a PCI configuration address to be passed as a parameter to SAL. */ + result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, &data); -#define PCI_CONFIG_ADDRESS(dev, where) \ - (((u64) dev->bus->number << 16) | ((u64) (dev->devfn & 0xff) << 8) | (where & 0xff)) + *value = (u32) data; + + return result; +} static int -pci_conf_read_config_byte(struct pci_dev *dev, int where, u8 *value) +pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { - s64 status; - u64 lval; + if ((seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, value); +} + + +static int +pci_sal_read_config_byte (struct pci_dev *dev, int where, u8 *value) +{ + int result = 0; + u32 data = 0; + + if (!value) + return -EINVAL; - status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 1, &lval); - *value = lval; - return status; + result = pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, &data); + + *value = (u8) data; + + return result; } static int -pci_conf_read_config_word(struct pci_dev *dev, int where, u16 *value) +pci_sal_read_config_word (struct pci_dev *dev, int where, u16 *value) { - s64 status; - u64 lval; + int result = 0; + u32 data = 0; + + if (!value) + return -EINVAL; + + result = pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, &data); + + *value = (u16) data; - status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 2, &lval); - *value = lval; - return status; + return result; } static int -pci_conf_read_config_dword(struct pci_dev *dev, int where, u32 *value) +pci_sal_read_config_dword (struct pci_dev *dev, int where, u32 *value) { - s64 status; - u64 lval; + if (!value) + return -EINVAL; - status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 4, &lval); - *value = lval; - return status; + return pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); } static int -pci_conf_write_config_byte (struct pci_dev *dev, int where, u8 value) +pci_sal_write_config_byte (struct pci_dev *dev, int where, u8 value) { - return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 1, value); + return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, value); } static int -pci_conf_write_config_word (struct pci_dev *dev, int where, u16 value) +pci_sal_write_config_word (struct pci_dev *dev, int where, u16 value) { - return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 2, value); + return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, value); } static int -pci_conf_write_config_dword (struct pci_dev *dev, int where, u32 value) +pci_sal_write_config_dword (struct pci_dev *dev, int where, u32 value) { - return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 4, value); + return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); } -struct pci_ops pci_conf = { - pci_conf_read_config_byte, - pci_conf_read_config_word, - pci_conf_read_config_dword, - pci_conf_write_config_byte, - pci_conf_write_config_word, - pci_conf_write_config_dword +struct pci_ops pci_sal_ops = { + pci_sal_read_config_byte, + pci_sal_read_config_word, + pci_sal_read_config_dword, + pci_sal_write_config_byte, + pci_sal_write_config_word, + pci_sal_write_config_dword }; + /* * Initialization. Uses the SAL interface */ + +static struct pci_controller * +alloc_pci_controller(int seg) +{ + struct pci_controller *controller; + + controller = kmalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + return NULL; + + memset(controller, 0, sizeof(*controller)); + controller->segment = seg; + return controller; +} + +static struct pci_bus * +scan_root_bus(int bus, struct pci_ops *ops, void *sysdata) +{ + struct pci_bus *b; + + /* + * We know this is a new root bus we haven't seen before, so + * scan it, even if we've seen the same bus number in a different + * segment. + */ + b = kmalloc(sizeof(*b), GFP_KERNEL); + if (!b) + return NULL; + + memset(b, 0, sizeof(*b)); + INIT_LIST_HEAD(&b->children); + INIT_LIST_HEAD(&b->devices); + + list_add_tail(&b->node, &pci_root_buses); + + b->number = b->secondary = bus; + b->resource[0] = &ioport_resource; + b->resource[1] = &iomem_resource; + + b->sysdata = sysdata; + b->ops = ops; + b->subordinate = pci_do_scan_bus(b); + + return b; +} + +struct pci_bus * +pcibios_scan_root(void *handle, int seg, int bus) +{ + struct pci_controller *controller; + u64 base, size, offset; + + printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus); + + controller = alloc_pci_controller(seg); + if (!controller) + return NULL; + + controller->acpi_handle = handle; + + acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset); + controller->mem_offset = offset; + + return scan_root_bus(bus, pci_root_ops, controller); +} + +void __init +pcibios_config_init (void) +{ + if (pci_root_ops) + return; + + printk("PCI: Using SAL to access configuration space\n"); + + pci_root_ops = &pci_sal_ops; + pci_config_read = pci_sal_read; + pci_config_write = pci_sal_write; + + return; +} + void __init pcibios_init (void) { # define PCI_BUSES_TO_SCAN 255 - int i; + int i = 0; + struct pci_controller *controller; #ifdef CONFIG_IA64_MCA ia64_mca_check_errors(); /* For post-failure MCA error logging */ #endif - platform_pci_fixup(0); /* phase 0 initialization (before PCI bus has been scanned) */ + pcibios_config_init(); + + platform_pci_fixup(0); /* phase 0 fixups (before buses scanned) */ printk("PCI: Probing PCI hardware\n"); - for (i = 0; i < PCI_BUSES_TO_SCAN; i++) - pci_scan_bus(i, &pci_conf, NULL); + controller = alloc_pci_controller(0); + if (controller) + for (i = 0; i < PCI_BUSES_TO_SCAN; i++) + pci_scan_bus(i, pci_root_ops, controller); + + platform_pci_fixup(1); /* phase 1 fixups (after buses scanned) */ - platform_pci_fixup(1); /* phase 1 initialization (after PCI bus has been scanned) */ return; } +static void __init +pcibios_fixup_resource(struct resource *res, u64 offset) +{ + res->start += offset; + res->end += offset; +} + +void __init +pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) +{ + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (!dev->resource[i].start) + continue; + if (dev->resource[i].flags & IORESOURCE_MEM) + pcibios_fixup_resource(&dev->resource[i], + PCI_CONTROLLER(dev)->mem_offset); + } +} + /* * Called after each bus is probed, but before its children * are examined. @@ -147,7 +300,10 @@ void __init pcibios_fixup_bus (struct pci_bus *b) { - return; + struct list_head *ln; + + for (ln = b->devices.next; ln != &b->devices; ln = ln->next) + pcibios_fixup_device_resources(pci_dev_b(ln), b); } void __init @@ -186,7 +342,39 @@ int pcibios_enable_device (struct pci_dev *dev) { - /* Not needed, since we enable all devices at startup. */ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + if (!dev) + return -EINVAL; + + platform_pci_enable_device(dev); + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR + "PCI: Device %s not available because of resource collisions\n", + dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + + printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name); + return 0; } diff -Nur linux-2.4.19/arch/ia64/kernel/perfmon.c linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon.c --- linux-2.4.19/arch/ia64/kernel/perfmon.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon.c Fri Dec 20 07:16:48 2002 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,7 @@ * you must enable the following flag to activate the support for * accessing the registers via the perfmonctl() interface. */ -#ifdef CONFIG_ITANIUM +#if defined(CONFIG_ITANIUM) || defined(CONFIG_MCKINLEY) #define PFM_PMU_USES_DBR 1 #endif @@ -68,26 +69,27 @@ #define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_soft_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) #define PFM_FL_INHERIT_MASK (PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL) +/* i assume unsigned */ #define PMC_IS_IMPL(i) (i>6] & (1UL<< (i) %64)) #define PMD_IS_IMPL(i) (i>6)] & (1UL<<(i) % 64)) -#define PMD_IS_COUNTING(i) (i >=0 && i < 256 && pmu_conf.counter_pmds[i>>6] & (1UL <<(i) % 64)) -#define PMC_IS_COUNTING(i) PMD_IS_COUNTING(i) +/* XXX: these three assume that register i is implemented */ +#define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) +#define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING) +#define PMC_IS_MONITOR(c) (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR) +/* k assume unsigned */ #define IBR_IS_IMPL(k) (kpmc_es == PMU_BTB_EVENT) - -#define LSHIFT(x) (1UL<<(x)) -#define PMM(x) LSHIFT(x) -#define PMC_IS_MONITOR(c) ((pmu_conf.monitor_pmcs[0] & PMM((c))) != 0) - #define CTX_IS_ENABLED(c) ((c)->ctx_flags.state == PFM_CTX_ENABLED) #define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) #define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) #define CTX_HAS_SMPL(c) ((c)->ctx_psb != NULL) -#define CTX_USED_PMD(ctx,n) (ctx)->ctx_used_pmds[(n)>>6] |= 1UL<< ((n) % 64) +/* XXX: does not support more than 64 PMDs */ +#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask) +#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL) + #define CTX_USED_IBR(ctx,n) (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64) #define CTX_USED_DBR(ctx,n) (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64) @@ -104,17 +106,29 @@ #define PFM_REG_RETFLAG_SET(flags, val) do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0) +#ifdef CONFIG_SMP +#define cpu_is_online(i) (cpu_online_map & (1UL << i)) +#else +#define cpu_is_online(i) (i==0) +#endif + /* * debugging */ #define DBprintk(a) \ do { \ - if (pfm_debug_mode >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + if (pfm_sysctl.debug >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) + +#define DBprintk_ovfl(a) \ + do { \ + if (pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ } while (0) + /* - * These are some helpful architected PMC and IBR/DBR register layouts + * Architected PMC structure */ typedef struct { unsigned long pmc_plm:4; /* privilege level mask */ @@ -139,41 +153,40 @@ typedef struct _pfm_smpl_buffer_desc { spinlock_t psb_lock; /* protection lock */ unsigned long psb_refcnt; /* how many users for the buffer */ - int psb_flags; /* bitvector of flags */ + int psb_flags; /* bitvector of flags (not yet used) */ void *psb_addr; /* points to location of first entry */ unsigned long psb_entries; /* maximum number of entries */ unsigned long psb_size; /* aligned size of buffer */ unsigned long psb_index; /* next free entry slot XXX: must use the one in buffer */ unsigned long psb_entry_size; /* size of each entry including entry header */ + perfmon_smpl_hdr_t *psb_hdr; /* points to sampling buffer header */ struct _pfm_smpl_buffer_desc *psb_next; /* next psb, used for rvfreeing of psb_hdr */ } pfm_smpl_buffer_desc_t; +/* + * psb_flags + */ +#define PSB_HAS_VMA 0x1 /* a virtual mapping for the buffer exists */ + #define LOCK_PSB(p) spin_lock(&(p)->psb_lock) #define UNLOCK_PSB(p) spin_unlock(&(p)->psb_lock) -#define PFM_PSB_VMA 0x1 /* a VMA is describing the buffer */ - /* - * This structure is initialized at boot time and contains - * a description of the PMU main characteristic as indicated - * by PAL + * The possible type of a PMU register */ -typedef struct { - unsigned long pfm_is_disabled; /* indicates if perfmon is working properly */ - unsigned long perf_ovfl_val; /* overflow value for generic counters */ - unsigned long max_counters; /* upper limit on counter pair (PMC/PMD) */ - unsigned long num_pmcs ; /* highest PMC implemented (may have holes) */ - unsigned long num_pmds; /* highest PMD implemented (may have holes) */ - unsigned long impl_regs[16]; /* buffer used to hold implememted PMC/PMD mask */ - unsigned long num_ibrs; /* number of instruction debug registers */ - unsigned long num_dbrs; /* number of data debug registers */ - unsigned long monitor_pmcs[4]; /* which pmc are controlling monitors */ - unsigned long counter_pmds[4]; /* which pmd are used as counters */ -} pmu_config_t; +typedef enum { + PFM_REG_NOTIMPL, /* not implemented */ + PFM_REG_NONE, /* end marker */ + PFM_REG_MONITOR, /* a PMC with a pmc.pm field only */ + PFM_REG_COUNTING,/* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */ + PFM_REG_CONTROL, /* PMU control register */ + PFM_REG_CONFIG, /* refine configuration */ + PFM_REG_BUFFER /* PMD used as buffer */ +} pfm_pmu_reg_type_t; /* * 64-bit software counter structure @@ -221,9 +234,11 @@ struct semaphore ctx_restart_sem; /* use for blocking notification mode */ - unsigned long ctx_used_pmds[4]; /* bitmask of used PMD (speedup ctxsw) */ - unsigned long ctx_saved_pmcs[4]; /* bitmask of PMC to save on ctxsw */ - unsigned long ctx_reload_pmcs[4]; /* bitmask of PMC to reload on ctxsw (SMP) */ + unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ + unsigned long ctx_reload_pmds[4]; /* bitmask of PMD to reload on ctxsw */ + + unsigned long ctx_used_pmcs[4]; /* bitmask PMC used by context */ + unsigned long ctx_reload_pmcs[4]; /* bitmask of PMC to reload on ctxsw */ unsigned long ctx_used_ibrs[4]; /* bitmask of used IBR (speedup ctxsw) */ unsigned long ctx_used_dbrs[4]; /* bitmask of used DBR (speedup ctxsw) */ @@ -235,6 +250,7 @@ unsigned long ctx_cpu; /* cpu to which perfmon is applied (system wide) */ atomic_t ctx_saving_in_progress; /* flag indicating actual save in progress */ + atomic_t ctx_is_busy; /* context accessed by overflow handler */ atomic_t ctx_last_cpu; /* CPU id of current or last CPU used */ } pfm_context_t; @@ -250,16 +266,54 @@ * mostly used to synchronize between system wide and per-process */ typedef struct { - spinlock_t pfs_lock; /* lock the structure */ + spinlock_t pfs_lock; /* lock the structure */ - unsigned long pfs_task_sessions; /* number of per task sessions */ - unsigned long pfs_sys_sessions; /* number of per system wide sessions */ - unsigned long pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ - unsigned long pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ - struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ + unsigned long pfs_task_sessions; /* number of per task sessions */ + unsigned long pfs_sys_sessions; /* number of per system wide sessions */ + unsigned long pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ + unsigned long pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ + struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ } pfm_session_t; /* + * information about a PMC or PMD. + * dep_pmd[]: a bitmask of dependent PMD registers + * dep_pmc[]: a bitmask of dependent PMC registers + */ +typedef struct { + pfm_pmu_reg_type_t type; + int pm_pos; + int (*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + int (*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + unsigned long dep_pmd[4]; + unsigned long dep_pmc[4]; +} pfm_reg_desc_t; +/* assume cnum is a valid monitor */ +#define PMC_PM(cnum, val) (((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1) +#define PMC_WR_FUNC(cnum) (pmu_conf.pmc_desc[cnum].write_check) +#define PMD_WR_FUNC(cnum) (pmu_conf.pmd_desc[cnum].write_check) +#define PMD_RD_FUNC(cnum) (pmu_conf.pmd_desc[cnum].read_check) + +/* + * This structure is initialized at boot time and contains + * a description of the PMU main characteristic as indicated + * by PAL along with a list of inter-registers dependencies and configurations. + */ +typedef struct { + unsigned long pfm_is_disabled; /* indicates if perfmon is working properly */ + unsigned long perf_ovfl_val; /* overflow value for generic counters */ + unsigned long max_counters; /* upper limit on counter pair (PMC/PMD) */ + unsigned long num_pmcs ; /* highest PMC implemented (may have holes) */ + unsigned long num_pmds; /* highest PMD implemented (may have holes) */ + unsigned long impl_regs[16]; /* buffer used to hold implememted PMC/PMD mask */ + unsigned long num_ibrs; /* number of instruction debug registers */ + unsigned long num_dbrs; /* number of data debug registers */ + pfm_reg_desc_t *pmc_desc; /* detailed PMC register descriptions */ + pfm_reg_desc_t *pmd_desc; /* detailed PMD register descriptions */ +} pmu_config_t; + + +/* * structure used to pass argument to/from remote CPU * using IPI to check and possibly save the PMU context on SMP systems. * @@ -301,22 +355,50 @@ #define PFM_CMD_NARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg) #define PFM_CMD_ARG_SIZE(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize) +typedef struct { + int debug; /* turn on/off debugging via syslog */ + int debug_ovfl; /* turn on/off debug printk in overflow handler */ + int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ +} pfm_sysctl_t; + +typedef struct { + unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ + unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ + unsigned long pfm_recorded_samples_count; + unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */ +} pfm_stats_t; /* * perfmon internal variables */ static pmu_config_t pmu_conf; /* PMU configuration */ -static int pfm_debug_mode; /* 0= nodebug, >0= debug output on */ static pfm_session_t pfm_sessions; /* global sessions information */ static struct proc_dir_entry *perfmon_dir; /* for debug only */ -static unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ -static unsigned long pfm_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ -static unsigned long pfm_recorded_samples_count; +static pfm_stats_t pfm_stats; + +/* sysctl() controls */ +static pfm_sysctl_t pfm_sysctl; +static ctl_table pfm_ctl_table[]={ + {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, + { 0, }, +}; +static ctl_table pfm_sysctl_dir[] = { + {1, "perfmon", NULL, 0, 0755, pfm_ctl_table, }, + {0,}, +}; +static ctl_table pfm_sysctl_root[] = { + {1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, }, + {0,}, +}; +static struct ctl_table_header *pfm_sysctl_header; static unsigned long reset_pmcs[IA64_NUM_PMC_REGS]; /* contains PAL reset values for PMCS */ static void pfm_vm_close(struct vm_area_struct * area); + static struct vm_operations_struct pfm_vm_ops={ close: pfm_vm_close }; @@ -339,6 +421,14 @@ #endif static void pfm_lazy_save_regs (struct task_struct *ta); +#if defined(CONFIG_ITANIUM) +#include "perfmon_itanium.h" +#elif defined(CONFIG_MCKINLEY) +#include "perfmon_mckinley.h" +#else +#include "perfmon_generic.h" +#endif + static inline unsigned long pfm_read_soft_counter(pfm_context_t *ctx, int i) { @@ -353,7 +443,7 @@ * writing to unimplemented part is ignore, so we do not need to * mask off top part */ - ia64_set_pmd(i, val); + ia64_set_pmd(i, val & pmu_conf.perf_ovfl_val); } /* @@ -424,7 +514,6 @@ return pa; } - static void * pfm_rvmalloc(unsigned long size) { @@ -500,7 +589,7 @@ * * This function cannot remove the buffer from here, because exit_mmap() must first * complete. Given that there is no other vma related callback in the generic code, - * we have created on own with the linked list of sampling buffer to free which + * we have created our own with the linked list of sampling buffers to free. The list * is part of the thread structure. In release_thread() we check if the list is * empty. If not we call into perfmon to free the buffer and psb. That is the only * way to ensure a safe deallocation of the sampling buffer which works when @@ -516,16 +605,15 @@ psb->psb_next = current->thread.pfm_smpl_buf_list; current->thread.pfm_smpl_buf_list = psb; - DBprintk(("psb for [%d] smpl @%p size %ld inserted into list\n", - current->pid, psb->psb_hdr, psb->psb_size)); + DBprintk(("[%d] add smpl @%p size %lu to smpl_buf_list psb_flags=0x%x\n", + current->pid, psb->psb_hdr, psb->psb_size, psb->psb_flags)); } - DBprintk(("psb vma flag cleared for [%d] smpl @%p size %ld inserted into list\n", - current->pid, psb->psb_hdr, psb->psb_size)); - + DBprintk(("[%d] clearing psb_flags=0x%x smpl @%p size %lu\n", + current->pid, psb->psb_flags, psb->psb_hdr, psb->psb_size)); /* - * indicate to pfm_context_exit() that the vma has been removed. + * decrement the number vma for the buffer */ - psb->psb_flags &= ~PFM_PSB_VMA; + psb->psb_flags &= ~PSB_HAS_VMA; UNLOCK_PSB(psb); } @@ -548,7 +636,7 @@ printk("perfmon: invalid context mm=%p\n", task->mm); return -1; } - psb = ctx->ctx_psb; + psb = ctx->ctx_psb; down_write(&task->mm->mmap_sem); @@ -559,14 +647,9 @@ printk("perfmon: pid %d unable to unmap sampling buffer @0x%lx size=%ld\n", task->pid, ctx->ctx_smpl_vaddr, psb->psb_size); } - DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d\n", - task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r)); - /* - * make sure we suppress all traces of this buffer - * (important for pfm_inherit) - */ - ctx->ctx_smpl_vaddr = 0; + DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d refcnt=%lu psb_flags=0x%x\n", + task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r, psb->psb_refcnt, psb->psb_flags)); return 0; } @@ -599,7 +682,7 @@ while (size > 0) { page = pfm_kvirt_to_pa(buf); - if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM; + if (remap_page_range(addr, page, PAGE_SIZE, PAGE_READONLY)) return -ENOMEM; addr += PAGE_SIZE; buf += PAGE_SIZE; @@ -638,17 +721,25 @@ void *smpl_buf; pfm_smpl_buffer_desc_t *psb; - regcount = pfm_smpl_entry_size(which_pmds, 1); /* note that regcount might be 0, in this case only the header for each * entry will be recorded. */ + regcount = pfm_smpl_entry_size(which_pmds, 1); + + if ((sizeof(perfmon_smpl_hdr_t)+ entries*sizeof(perfmon_smpl_entry_t)) <= entries) { + DBprintk(("requested entries %lu is too big\n", entries)); + return -EINVAL; + } /* * 1 buffer hdr and for each entry a header + regcount PMDs to save */ size = PAGE_ALIGN( sizeof(perfmon_smpl_hdr_t) + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64))); + + DBprintk(("sampling buffer size=%lu bytes\n", size)); + /* * check requested size to avoid Denial-of-service attacks * XXX: may have to refine this test @@ -688,9 +779,13 @@ } /* * partially initialize the vma for the sampling buffer + * + * The VM_DONTCOPY flag is very important as it ensures that the mapping + * will never be inherited for any child process (via fork()) which is always + * what we want. */ vma->vm_mm = mm; - vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; + vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED|VM_DONTCOPY; vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ vma->vm_ops = &pfm_vm_ops; /* necesarry to get the close() callback */ vma->vm_pgoff = 0; @@ -708,8 +803,8 @@ psb->psb_size = size; /* aligned size */ psb->psb_index = 0; psb->psb_entries = entries; - psb->psb_flags = PFM_PSB_VMA; /* remember that there is a vma describing the buffer */ psb->psb_refcnt = 1; + psb->psb_flags = PSB_HAS_VMA; spin_lock_init(&psb->psb_lock); @@ -719,9 +814,9 @@ */ psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64); - DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p\n", + DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p refcnt=%lu psb_flags=0x%x\n", (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, - (void *)psb->psb_addr)); + (void *)psb->psb_addr, psb->psb_refcnt, psb->psb_flags)); /* initialize some of the fields of user visible buffer header */ psb->psb_hdr->hdr_version = PFM_SMPL_VERSION; @@ -797,7 +892,6 @@ && (current->uid ^ task->suid) && (current->uid ^ task->uid); } - static int pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx) { @@ -813,6 +907,11 @@ } ctx_flags = pfx->ctx_flags; + if ((ctx_flags & PFM_FL_INHERIT_MASK) == (PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)) { + DBprintk(("invalid inherit mask 0x%x\n",ctx_flags & PFM_FL_INHERIT_MASK)); + return -EINVAL; + } + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { DBprintk(("cpu_mask=0x%lx\n", pfx->ctx_cpu_mask)); /* @@ -832,8 +931,8 @@ /* * and it must be a valid CPU */ - cpu = ffs(pfx->ctx_cpu_mask); - if (cpu > smp_num_cpus) { + cpu = ffz(~pfx->ctx_cpu_mask); + if (cpu_is_online(cpu) == 0) { DBprintk(("CPU%d is not online\n", cpu)); return -EINVAL; } @@ -851,7 +950,16 @@ * must provide a target for the signal in blocking mode even when * no counter is configured with PFM_FL_REG_OVFL_NOTIFY */ - if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) return -EINVAL; + if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) { + DBprintk(("must have notify_pid when blocking for [%d]\n", task->pid)); + return -EINVAL; + } +#if 0 + if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == task->pid) { + DBprintk(("cannot notify self when blocking for [%d]\n", task->pid)); + return -EINVAL; + } +#endif } /* probably more to add here */ @@ -859,7 +967,7 @@ } static int -pfm_create_context(struct task_struct *task, pfm_context_t *ctx, void *req, int count, +pfm_context_create(struct task_struct *task, pfm_context_t *ctx, void *req, int count, struct pt_regs *regs) { pfarg_context_t tmp; @@ -890,7 +998,7 @@ if (ctx_flags & PFM_FL_SYSTEM_WIDE) { /* at this point, we know there is at least one bit set */ - cpu = ffs(tmp.ctx_cpu_mask) - 1; + cpu = ffz(~tmp.ctx_cpu_mask); DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id())); @@ -984,7 +1092,7 @@ } if (tmp.ctx_smpl_entries) { - DBprintk(("sampling entries=%ld\n",tmp.ctx_smpl_entries)); + DBprintk(("sampling entries=%lu\n",tmp.ctx_smpl_entries)); ret = pfm_smpl_buffer_alloc(ctx, tmp.ctx_smpl_regs, tmp.ctx_smpl_entries, &uaddr); @@ -1010,20 +1118,12 @@ atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */ - /* - * Keep track of the pmds we want to sample - * XXX: may be we don't need to save/restore the DEAR/IEAR pmds - * but we do need the BTB for sure. This is because of a hardware - * buffer of 1 only for non-BTB pmds. - * - * We ignore the unimplemented pmds specified by the user - */ - ctx->ctx_used_pmds[0] = tmp.ctx_smpl_regs[0] & pmu_conf.impl_regs[4]; - ctx->ctx_saved_pmcs[0] = 1; /* always save/restore PMC[0] */ + /* may be redudant with memset() but at least it's easier to remember */ + atomic_set(&ctx->ctx_saving_in_progress, 0); + atomic_set(&ctx->ctx_is_busy, 0); sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ - if (copy_to_user(req, &tmp, sizeof(tmp))) { ret = -EFAULT; goto buffer_error; @@ -1047,9 +1147,7 @@ */ if (ctx->ctx_fl_system) { ctx->ctx_saved_cpus_allowed = task->cpus_allowed; - task->cpus_allowed = 1UL << cpu; - task->need_resched = 1; - DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid,task->cpus_allowed)); + set_cpus_allowed(task, 1UL << cpu); } return 0; @@ -1126,21 +1224,22 @@ current->pid, flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val)); } + ia64_srlz_d(); /* just in case ! */ ctx->ctx_ovfl_regs[0] = 0UL; } static int -pfm_write_pmcs(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +pfm_write_pmcs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - struct thread_struct *th = &ta->thread; + struct thread_struct *th = &task->thread; pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; unsigned int cnum; int i; int ret = 0, reg_retval = 0; /* we don't quite support this right now */ - if (ta != current) return -EINVAL; + if (task != current) return -EINVAL; if (!CTX_IS_ENABLED(ctx)) return -EINVAL; @@ -1169,30 +1268,30 @@ * - per-task : user monitor * any other configuration is rejected. */ - if (PMC_IS_MONITOR(cnum)) { - pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value; - - DBprintk(("pmc[%u].pm = %d\n", cnum, p->pmc_pm)); + if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) { + DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, tmp.reg_value))); - if (ctx->ctx_fl_system ^ p->pmc_pm) { - //if ((ctx->ctx_fl_system == 1 && p->pmc_pm == 0) - // ||(ctx->ctx_fl_system == 0 && p->pmc_pm == 1)) { + if (ctx->ctx_fl_system ^ PMC_PM(cnum, tmp.reg_value)) { + DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, tmp.reg_value), ctx->ctx_fl_system)); ret = -EINVAL; goto abort_mission; } - /* - * enforce generation of overflow interrupt. Necessary on all - * CPUs which do not implement 64-bit hardware counters. - */ - p->pmc_oi = 1; } if (PMC_IS_COUNTING(cnum)) { + pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value; + /* + * enforce generation of overflow interrupt. Necessary on all + * CPUs. + */ + p->pmc_oi = 1; + if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) { /* * must have a target for the signal */ if (ctx->ctx_notify_task == NULL) { + DBprintk(("no notify_task && PFM_REGFL_OVFL_NOTIFY\n")); ret = -EINVAL; goto abort_mission; } @@ -1206,14 +1305,11 @@ ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1]; ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2]; ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3]; - - /* - * needed in case the user does not initialize the equivalent - * PMD. Clearing is done in reset_pmu() so there is no possible - * leak here. - */ - CTX_USED_PMD(ctx, cnum); } + /* + * execute write checker, if any + */ + if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs); abort_mission: if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL; @@ -1233,14 +1329,21 @@ */ if (ret != 0) { DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", - ta->pid, cnum, tmp.reg_value, reg_retval)); + task->pid, cnum, tmp.reg_value, reg_retval)); break; } /* * We can proceed with this register! */ - + + /* + * Needed in case the user does not initialize the equivalent + * PMD. Clearing is done in reset_pmu() so there is no possible + * leak here. + */ + CTX_USED_PMD(ctx, pmu_conf.pmc_desc[cnum].dep_pmd[0]); + /* * keep copy the pmc, used for register reload */ @@ -1248,17 +1351,17 @@ ia64_set_pmc(cnum, tmp.reg_value); - DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x save_pmcs=0%lx reload_pmcs=0x%lx\n", - ta->pid, cnum, tmp.reg_value, + DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", + task->pid, cnum, tmp.reg_value, ctx->ctx_soft_pmds[cnum].flags, - ctx->ctx_saved_pmcs[0], ctx->ctx_reload_pmcs[0])); + ctx->ctx_used_pmds[0])); } return ret; } static int -pfm_write_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; unsigned int cnum; @@ -1266,7 +1369,7 @@ int ret = 0, reg_retval = 0; /* we don't quite support this right now */ - if (ta != current) return -EINVAL; + if (task != current) return -EINVAL; /* * Cannot do anything before PMU is enabled @@ -1281,7 +1384,6 @@ if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; cnum = tmp.reg_num; - if (!PMD_IS_IMPL(cnum)) { ret = -EINVAL; goto abort_mission; @@ -1295,6 +1397,10 @@ ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset; } + /* + * execute write checker, if any + */ + if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs); abort_mission: if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL; @@ -1311,21 +1417,24 @@ */ if (ret != 0) { DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", - ta->pid, cnum, tmp.reg_value, reg_retval)); + task->pid, cnum, tmp.reg_value, reg_retval)); break; } /* keep track of what we use */ - CTX_USED_PMD(ctx, cnum); + CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]); + /* mark this register as used as well */ + CTX_USED_PMD(ctx, RDEP(cnum)); /* writes to unimplemented part is ignored, so this is safe */ - ia64_set_pmd(cnum, tmp.reg_value); + ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val); /* to go away */ ia64_srlz_d(); + DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx short_reset=0x%lx " "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n", - ta->pid, cnum, + task->pid, cnum, ctx->ctx_soft_pmds[cnum].val, ctx->ctx_soft_pmds[cnum].short_reset, ctx->ctx_soft_pmds[cnum].long_reset, @@ -1338,12 +1447,13 @@ } static int -pfm_read_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - struct thread_struct *th = &ta->thread; + struct thread_struct *th = &task->thread; unsigned long val=0; pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; - int i; + unsigned int cnum; + int i, ret = 0; if (!CTX_IS_ENABLED(ctx)) return -EINVAL; @@ -1356,14 +1466,25 @@ /* XXX: ctx locking may be required here */ - DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), ta->pid)); + DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid)); for (i = 0; i < count; i++, req++) { - unsigned long reg_val = ~0UL, ctx_val = ~0UL; + unsigned long ctx_val = ~0UL; if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - if (!PMD_IS_IMPL(tmp.reg_num)) goto abort_mission; + cnum = tmp.reg_num; + + if (!PMD_IS_IMPL(cnum)) goto abort_mission; + /* + * we can only read the register that we use. That includes + * the one we explicitely initialize AND the one we want included + * in the sampling buffer (smpl_regs). + * + * Having this restriction allows optimization in the ctxsw routine + * without compromising security (leaks) + */ + if (!CTX_IS_USED_PMD(ctx, cnum)) goto abort_mission; /* * If the task is not the current one, then we check if the @@ -1372,8 +1493,8 @@ */ if (atomic_read(&ctx->ctx_last_cpu) == smp_processor_id()){ ia64_srlz_d(); - val = reg_val = ia64_get_pmd(tmp.reg_num); - DBprintk(("reading pmd[%u]=0x%lx from hw\n", tmp.reg_num, val)); + val = ia64_get_pmd(cnum); + DBprintk(("reading pmd[%u]=0x%lx from hw\n", cnum, val)); } else { #ifdef CONFIG_SMP int cpu; @@ -1389,30 +1510,35 @@ */ cpu = atomic_read(&ctx->ctx_last_cpu); if (cpu != -1) { - DBprintk(("must fetch on CPU%d for [%d]\n", cpu, ta->pid)); - pfm_fetch_regs(cpu, ta, ctx); + DBprintk(("must fetch on CPU%d for [%d]\n", cpu, task->pid)); + pfm_fetch_regs(cpu, task, ctx); } #endif /* context has been saved */ - val = reg_val = th->pmd[tmp.reg_num]; + val = th->pmd[cnum]; } - if (PMD_IS_COUNTING(tmp.reg_num)) { + if (PMD_IS_COUNTING(cnum)) { /* * XXX: need to check for overflow */ val &= pmu_conf.perf_ovfl_val; - val += ctx_val = ctx->ctx_soft_pmds[tmp.reg_num].val; - } else { + val += ctx_val = ctx->ctx_soft_pmds[cnum].val; + } - val = reg_val = ia64_get_pmd(tmp.reg_num); - } - PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); tmp.reg_value = val; - DBprintk(("read pmd[%u] soft_pmd=0x%lx reg=0x%lx pmc=0x%lx\n", - tmp.reg_num, ctx_val, reg_val, - ia64_get_pmc(tmp.reg_num))); + /* + * execute read checker, if any + */ + if (PMD_RD_FUNC(cnum)) { + ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value, regs); + } + + PFM_REG_RETFLAG_SET(tmp.reg_flags, ret); + + DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", + cnum, ret, val, ia64_get_pmc(cnum))); if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; } @@ -1420,7 +1546,7 @@ abort_mission: PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); /* - * XXX: if this fails, we stick we the original failure, flag not updated! + * XXX: if this fails, we stick with the original failure, flag not updated! */ copy_to_user(req, &tmp, sizeof(tmp)); return -EINVAL; @@ -1455,15 +1581,11 @@ */ if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1; - /* - * XXX: not pretty - */ LOCK_PFS(); /* - * We only allow the use of debug registers when there is no system - * wide monitoring - * XXX: we could relax this by + * We cannot allow setting breakpoints when system wide monitoring + * sessions are using the debug registers. */ if (pfm_sessions.pfs_sys_use_dbregs> 0) ret = -1; @@ -1516,6 +1638,7 @@ { return 0; } + int pfm_release_debug_registers(struct task_struct *task) { @@ -1534,12 +1657,6 @@ */ if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - if (ctx->ctx_fl_frozen==0) { - printk("task %d without pmu_frozen set\n", task->pid); - return -EINVAL; - } - if (task == current) { DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); @@ -1656,25 +1773,35 @@ current->pid, ctx->ctx_fl_system, PMU_OWNER(), current)); + /* simply stop monitoring but not the PMU */ if (ctx->ctx_fl_system) { - __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); - /* disable dcr pp */ ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + /* stop monitoring */ + __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); + + ia64_srlz_i(); + #ifdef CONFIG_SMP local_cpu_data->pfm_dcr_pp = 0; #else pfm_tasklist_toggle_pp(0); #endif - ia64_psr(regs)->pp = 0; } else { + + /* stop monitoring */ __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + ia64_srlz_i(); + + /* + * clear user level psr.up + */ ia64_psr(regs)->up = 0; } return 0; @@ -1701,7 +1828,7 @@ ia64_psr(regs)->up = 0; } /* - * goes back to default behavior + * goes back to default behavior: no user level control * no need to change live psr.sp because useless at the kernel level */ ia64_psr(regs)->sp = 1; @@ -1713,10 +1840,8 @@ return 0; } - - static int -pfm_destroy_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, +pfm_context_destroy(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { /* we don't quite support this right now */ @@ -1742,15 +1867,14 @@ ia64_psr(regs)->up = 0; } - /* restore security level */ - ia64_psr(regs)->sp = 1; - skipped_stop: /* * remove sampling buffer mapping, if any */ - if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task); - + if (ctx->ctx_smpl_vaddr) { + pfm_remove_smpl_mapping(task); + ctx->ctx_smpl_vaddr = 0UL; + } /* now free context and related state */ pfm_context_exit(task); @@ -1761,7 +1885,7 @@ * does nothing at the moment */ static int -pfm_unprotect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, +pfm_context_unprotect(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { return 0; @@ -1791,9 +1915,9 @@ { unsigned int mode = *(unsigned int *)arg; - pfm_debug_mode = mode == 0 ? 0 : 1; + pfm_sysctl.debug = mode == 0 ? 0 : 1; - printk("perfmon debugging %s\n", pfm_debug_mode ? "on" : "off"); + printk("perfmon debugging %s\n", pfm_sysctl.debug ? "on" : "off"); return 0; } @@ -1863,8 +1987,8 @@ if (ctx->ctx_fl_system) { /* we mark ourselves as owner of the debug registers */ ctx->ctx_fl_using_dbreg = 1; - } else { - if (ctx->ctx_fl_using_dbreg == 0) { + DBprintk(("system-wide setting fl_using_dbreg for [%d]\n", task->pid)); + } else if (first_time) { ret= -EBUSY; if ((thread->flags & IA64_THREAD_DBG_VALID) != 0) { DBprintk(("debug registers already in use for [%d]\n", task->pid)); @@ -1873,6 +1997,7 @@ /* we mark ourselves as owner of the debug registers */ ctx->ctx_fl_using_dbreg = 1; + DBprintk(("setting fl_using_dbreg for [%d]\n", task->pid)); /* * Given debug registers cannot be used for both debugging * and performance monitoring at the same time, we reuse @@ -1880,18 +2005,27 @@ */ memset(task->thread.dbr, 0, sizeof(task->thread.dbr)); memset(task->thread.ibr, 0, sizeof(task->thread.ibr)); + } - /* - * clear hardware registers to make sure we don't leak - * information and pick up stale state - */ - for (i=0; i < pmu_conf.num_ibrs; i++) { - ia64_set_ibr(i, 0UL); - } - for (i=0; i < pmu_conf.num_dbrs; i++) { - ia64_set_dbr(i, 0UL); - } + if (first_time) { + DBprintk(("[%d] clearing ibrs,dbrs\n", task->pid)); + /* + * clear hardware registers to make sure we don't + * pick up stale state. + * + * for a system wide session, we do not use + * thread.dbr, thread.ibr because this process + * never leaves the current CPU and the state + * is shared by all processes running on it + */ + for (i=0; i < pmu_conf.num_ibrs; i++) { + ia64_set_ibr(i, 0UL); + } + ia64_srlz_i(); + for (i=0; i < pmu_conf.num_dbrs; i++) { + ia64_set_dbr(i, 0UL); } + ia64_srlz_d(); } ret = -EFAULT; @@ -1951,6 +2085,7 @@ CTX_USED_IBR(ctx, rnum); ia64_set_ibr(rnum, dbreg.val); + ia64_srlz_i(); thread->ibr[rnum] = dbreg.val; @@ -1959,6 +2094,7 @@ CTX_USED_DBR(ctx, rnum); ia64_set_dbr(rnum, dbreg.val); + ia64_srlz_d(); thread->dbr[rnum] = dbreg.val; @@ -2058,27 +2194,35 @@ if (ctx->ctx_fl_system) { - /* enable dcr pp */ - ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); - #ifdef CONFIG_SMP local_cpu_data->pfm_dcr_pp = 1; #else pfm_tasklist_toggle_pp(1); #endif + /* set user level psr.pp */ ia64_psr(regs)->pp = 1; + /* start monitoring at kernel level */ __asm__ __volatile__ ("ssm psr.pp;;"::: "memory"); + /* enable dcr pp */ + ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); + + ia64_srlz_i(); + } else { if ((task->thread.flags & IA64_THREAD_PM_VALID) == 0) { printk("perfmon: pfm_start task flag not set for [%d]\n", task->pid); return -EINVAL; } + /* set user level psr.up */ ia64_psr(regs)->up = 1; + + /* start monitoring at kernel level */ __asm__ __volatile__ ("sum psr.up;;"::: "memory"); + + ia64_srlz_i(); } - ia64_srlz_d(); return 0; } @@ -2101,7 +2245,9 @@ ia64_psr(regs)->pp = 0; ia64_psr(regs)->up = 0; /* just to make sure! */ + /* make sure monitoring is stopped */ __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); + ia64_srlz_i(); #ifdef CONFIG_SMP local_cpu_data->pfm_syst_wide = 1; @@ -2116,21 +2262,21 @@ ia64_psr(regs)->pp = 0; /* just to make sure! */ ia64_psr(regs)->up = 0; + /* make sure monitoring is stopped */ __asm__ __volatile__ ("rum psr.up;;"::: "memory"); - /* - * allow user control (user monitors only) - if (task == ctx->ctx_owner) { - */ - { - DBprintk(("clearing psr.sp for [%d]\n", current->pid)); - ia64_psr(regs)->sp = 0; - } + ia64_srlz_i(); + + DBprintk(("clearing psr.sp for [%d]\n", current->pid)); + + /* allow user level control */ + ia64_psr(regs)->sp = 0; + + /* PMU state will be saved/restored on ctxsw */ task->thread.flags |= IA64_THREAD_PM_VALID; } SET_PMU_OWNER(task); - ctx->ctx_flags.state = PFM_CTX_ENABLED; atomic_set(&ctx->ctx_last_cpu, smp_processor_id()); @@ -2141,6 +2287,40 @@ return 0; } +static int +pfm_get_pmc_reset(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, + struct pt_regs *regs) +{ + pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; + unsigned int cnum; + int i; + + for (i = 0; i < count; i++, req++) { + + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + + cnum = tmp.reg_num; + + if (!PMC_IS_IMPL(cnum)) goto abort_mission; + + tmp.reg_value = reset_pmcs[cnum]; + + PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); + + DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); + + if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; + } + return 0; +abort_mission: + PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); + /* + * XXX: if this fails, we stick with the original failure, flag not updated! + */ + copy_to_user(req, &tmp, sizeof(tmp)); + return -EINVAL; +} + /* * functions MUST be listed in the increasing order of their index (see permfon.h) */ @@ -2148,19 +2328,19 @@ /* 0 */{ NULL, 0, 0, 0}, /* not used */ /* 1 */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, /* 2 */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 3 */{ pfm_read_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, +/* 3 */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, /* 4 */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, /* 5 */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, /* 6 */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, /* 7 */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 8 */{ pfm_create_context, PFM_CMD_ARG_READ, 1, sizeof(pfarg_context_t)}, -/* 9 */{ pfm_destroy_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 8 */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, 1, sizeof(pfarg_context_t)}, +/* 9 */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, /* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0}, /* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, /* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0}, /* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)}, -/* 14 */{ pfm_unprotect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 15 */{ NULL, 0, 0, 0}, /* not used */ +/* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, +/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, /* 16 */{ NULL, 0, 0, 0}, /* not used */ /* 17 */{ NULL, 0, 0, 0}, /* not used */ /* 18 */{ NULL, 0, 0, 0}, /* not used */ @@ -2222,9 +2402,9 @@ { struct pt_regs *regs = (struct pt_regs *)&stack; struct task_struct *task = current; - pfm_context_t *ctx = task->thread.pfm_context; + pfm_context_t *ctx; size_t sz; - int ret = -ESRCH, narg; + int ret, narg; /* * reject any call if perfmon was disabled at initialization time @@ -2254,6 +2434,8 @@ if (pid != current->pid) { + ret = -ESRCH; + read_lock(&tasklist_lock); task = find_task_by_pid(pid); @@ -2268,10 +2450,11 @@ ret = check_task_state(task); if (ret != 0) goto abort_call; } - ctx = task->thread.pfm_context; - } + } } + ctx = task->thread.pfm_context; + if (PFM_CMD_USE_CTX(cmd)) { ret = -EINVAL; if (ctx == NULL) { @@ -2387,9 +2570,9 @@ int j; -pfm_recorded_samples_count++; + idx = ia64_fetch_and_add(1, &psb->psb_index); - DBprintk(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries)); + DBprintk_ovfl(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries)); /* * XXX: there is a small chance that we could run out on index before resetting @@ -2409,7 +2592,7 @@ /* * initialize entry header */ - h->pid = task->pid; + h->pid = current->pid; h->cpu = smp_processor_id(); h->rate = 0; /* XXX: add the sampling rate used here */ h->ip = regs ? regs->cr_iip : 0x0; /* where did the fault happened */ @@ -2437,24 +2620,27 @@ } else { *e = ia64_get_pmd(j); /* slow */ } - DBprintk(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); + DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); e++; } + pfm_stats.pfm_recorded_samples_count++; + /* * make the new entry visible to user, needs to be atomic */ ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); - DBprintk(("index=%ld entries=%ld hdr_count=%ld\n", + DBprintk_ovfl(("index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count)); /* * sampling buffer full ? */ if (idx == (psb->psb_entries-1)) { - DBprintk(("sampling buffer full\n")); + DBprintk_ovfl(("sampling buffer full\n")); /* * XXX: must reset buffer in blocking mode and lost notified */ + pfm_stats.pfm_full_smpl_buffer_count++; return 1; } return 0; @@ -2467,15 +2653,13 @@ * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen */ static unsigned long -pfm_overflow_handler(struct task_struct *task, u64 pmc0, struct pt_regs *regs) +pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) { unsigned long mask; struct thread_struct *t; - pfm_context_t *ctx; unsigned long old_val; unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL; int i; - int my_cpu = smp_processor_id(); int ret = 1; struct siginfo si; /* @@ -2491,18 +2675,7 @@ * valid one, i.e. the one that caused the interrupt. */ - if (task == NULL) { - DBprintk(("owners[%d]=NULL\n", my_cpu)); - return 0x1; - } t = &task->thread; - ctx = task->thread.pfm_context; - - if (!ctx) { - printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", - task->pid); - return 0; - } /* * XXX: debug test @@ -2524,12 +2697,12 @@ mask = pmc0 >> PMU_FIRST_COUNTER; - DBprintk(("pmc0=0x%lx pid=%d iip=0x%lx, %s" - " mode used_pmds=0x%lx save_pmcs=0x%lx reload_pmcs=0x%lx\n", + DBprintk_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s" + " mode used_pmds=0x%lx used_pmcs=0x%lx reload_pmcs=0x%lx\n", pmc0, task->pid, (regs ? regs->cr_iip : 0), CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking", ctx->ctx_used_pmds[0], - ctx->ctx_saved_pmcs[0], + ctx->ctx_used_pmcs[0], ctx->ctx_reload_pmcs[0])); /* @@ -2540,7 +2713,7 @@ /* skip pmd which did not overflow */ if ((mask & 0x1) == 0) continue; - DBprintk(("PMD[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", + DBprintk_ovfl(("pmd[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val)); /* @@ -2552,8 +2725,7 @@ old_val = ctx->ctx_soft_pmds[i].val; ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i); - - DBprintk(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", + DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", i, ctx->ctx_soft_pmds[i].val, old_val, ia64_get_pmd(i) & pmu_conf.perf_ovfl_val)); @@ -2570,7 +2742,7 @@ ovfl_pmds |= 1UL << i; - DBprintk(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds)); + DBprintk_ovfl(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds)); if (PMC_OVFL_NOTIFY(ctx, i)) { ovfl_notify |= 1UL << i; @@ -2609,7 +2781,8 @@ * No overflow requiring a user level notification */ if (ovfl_notify == 0UL) { - pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET); + if (ovfl_pmds) + pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET); return 0x0; } @@ -2684,7 +2857,7 @@ * necessarily go to the signal handler (if any) when it goes back to * user mode. */ - DBprintk(("[%d] sending notification to [%d]\n", + DBprintk_ovfl(("[%d] sending notification to [%d]\n", task->pid, ctx->ctx_notify_task->pid)); @@ -2717,7 +2890,7 @@ * before, changing it to NULL will still maintain this invariant. * Of course, when it is equal to current it cannot change at this point. */ - DBprintk(("block=%d notify [%d] current [%d]\n", + DBprintk_ovfl(("block=%d notify [%d] current [%d]\n", ctx->ctx_fl_block, ctx->ctx_notify_task ? ctx->ctx_notify_task->pid: -1, current->pid )); @@ -2728,7 +2901,7 @@ } else { lost_notify: /* XXX: more to do here, to convert to non-blocking (reset values) */ - DBprintk(("notification task has disappeared !\n")); + DBprintk_ovfl(("notification task has disappeared !\n")); /* * for a non-blocking context, we make sure we do not fall into the * pfm_overflow_notify() trap. Also in the case of a blocking context with lost @@ -2750,7 +2923,7 @@ */ ctx->ctx_fl_frozen = 1; - DBprintk(("reload pmc0=0x%x must_block=%ld\n", + DBprintk_ovfl(("return pmc0=0x%x must_block=%ld\n", ctx->ctx_fl_frozen ? 0x1 : 0x0, t->pfm_ovfl_block_reset)); return ctx->ctx_fl_frozen ? 0x1 : 0x0; @@ -2761,8 +2934,9 @@ { u64 pmc0; struct task_struct *task; + pfm_context_t *ctx; - pfm_ovfl_intr_count++; + pfm_stats.pfm_ovfl_intr_count++; /* * srlz.d done before arriving here @@ -2776,24 +2950,51 @@ * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1 */ if ((pmc0 & ~0x1UL)!=0UL && (task=PMU_OWNER())!= NULL) { - /* - * assumes, PMC[0].fr = 1 at this point - * - * XXX: change protype to pass &pmc0 + * we assume that pmc0.fr is always set here */ - pmc0 = pfm_overflow_handler(task, pmc0, regs); + ctx = task->thread.pfm_context; - /* we never explicitely freeze PMU here */ - if (pmc0 == 0) { - ia64_set_pmc(0, 0); - ia64_srlz_d(); + /* sanity check */ + if (!ctx) { + printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", + task->pid); + return; } - } else { - pfm_spurious_ovfl_intr_count++; +#ifdef CONFIG_SMP + /* + * Because an IPI has higher priority than the PMU overflow interrupt, it is + * possible that the handler be interrupted by a request from another CPU to fetch + * the PMU state of the currently active context. The task may have just been + * migrated to another CPU which is trying to restore the context. If there was + * a pending overflow interrupt when the task left this CPU, it is possible for + * the handler to get interrupt by the IPI. In which case, we fetch request + * MUST be postponed until the interrupt handler is done. The ctx_is_busy + * flag indicates such a condition. The other CPU must busy wait until it's cleared. + */ + atomic_set(&ctx->ctx_is_busy, 1); +#endif + + /* + * assume PMC[0].fr = 1 at this point + */ + pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs); - DBprintk(("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", - smp_processor_id(), pmc0, (void *)PMU_OWNER())); + /* + * We always clear the overflow status bits and either unfreeze + * or keep the PMU frozen. + */ + ia64_set_pmc(0, pmc0); + ia64_srlz_d(); + +#ifdef CONFIG_SMP + /* + * announce that we are doing with the context + */ + atomic_set(&ctx->ctx_is_busy, 0); +#endif + } else { + pfm_stats.pfm_spurious_ovfl_intr_count++; } } @@ -2801,33 +3002,31 @@ static int perfmon_proc_info(char *page) { -#ifdef CONFIG_SMP -#define cpu_is_online(i) (cpu_online_map & (1UL << i)) -#else -#define cpu_is_online(i) 1 -#endif char *p = page; - u64 pmc0 = ia64_get_pmc(0); int i; - p += sprintf(p, "perfmon enabled: %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes"); - - p += sprintf(p, "monitors_pmcs0]=0x%lx\n", pmu_conf.monitor_pmcs[0]); - p += sprintf(p, "counter_pmcds[0]=0x%lx\n", pmu_conf.counter_pmds[0]); - p += sprintf(p, "overflow interrupts=%lu\n", pfm_ovfl_intr_count); - p += sprintf(p, "spurious overflow interrupts=%lu\n", pfm_spurious_ovfl_intr_count); - p += sprintf(p, "recorded samples=%lu\n", pfm_recorded_samples_count); - - p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", - smp_processor_id(), pmc0, pfm_debug_mode ? "On" : "Off"); + p += sprintf(p, "enabled : %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes"); + p += sprintf(p, "fastctxsw : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No"); + p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.perf_ovfl_val); + p += sprintf(p, "overflow intrs : %lu\n", pfm_stats.pfm_ovfl_intr_count); + p += sprintf(p, "spurious intrs : %lu\n", pfm_stats.pfm_spurious_ovfl_intr_count); + p += sprintf(p, "recorded samples : %lu\n", pfm_stats.pfm_recorded_samples_count); + p += sprintf(p, "smpl buffer full : %lu\n", pfm_stats.pfm_full_smpl_buffer_count); #ifdef CONFIG_SMP - p += sprintf(p, "CPU%d cpu_data.pfm_syst_wide=%d cpu_data.dcr_pp=%d\n", - smp_processor_id(), local_cpu_data->pfm_syst_wide, local_cpu_data->pfm_dcr_pp); + p += sprintf(p, "CPU%d syst_wide : %d\n" + "CPU%d dcr_pp : %d\n", + smp_processor_id(), + local_cpu_data->pfm_syst_wide, + smp_processor_id(), + local_cpu_data->pfm_dcr_pp); #endif LOCK_PFS(); - p += sprintf(p, "proc_sessions=%lu\nsys_sessions=%lu\nsys_use_dbregs=%lu\nptrace_use_dbregs=%lu\n", + p += sprintf(p, "proc_sessions : %lu\n" + "sys_sessions : %lu\n" + "sys_use_dbregs : %lu\n" + "ptrace_use_dbregs: %lu\n", pfm_sessions.pfs_task_sessions, pfm_sessions.pfs_sys_sessions, pfm_sessions.pfs_sys_use_dbregs, @@ -2837,12 +3036,28 @@ for(i=0; i < NR_CPUS; i++) { if (cpu_is_online(i)) { - p += sprintf(p, "CPU%d.pmu_owner: %-6d\n", + p += sprintf(p, "CPU%d owner : %-6d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1); } } + for(i=0; pmd_desc[i].type != PFM_REG_NONE; i++) { + p += sprintf(p, "PMD%-2d: %d 0x%lx 0x%lx\n", + i, + pmd_desc[i].type, + pmd_desc[i].dep_pmd[0], + pmd_desc[i].dep_pmc[0]); + } + + for(i=0; pmc_desc[i].type != PFM_REG_NONE; i++) { + p += sprintf(p, "PMC%-2d: %d 0x%lx 0x%lx\n", + i, + pmc_desc[i].type, + pmc_desc[i].dep_pmd[0], + pmc_desc[i].dep_pmc[0]); + } + return p - page; } @@ -2901,6 +3116,7 @@ * It will be restored from ipsr when going back to user level */ __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + ia64_srlz_i(); ctx->ctx_saved_psr = psr; @@ -2956,13 +3172,9 @@ for (i=0; mask; i++, mask>>=1) { if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); } - /* - * XXX: simplify to pmc0 only - */ - mask = ctx->ctx_saved_pmcs[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); - } + + /* save pmc0 */ + t->pmc[0] = ia64_get_pmc(0); /* not owned by this CPU */ atomic_set(&ctx->ctx_last_cpu, -1); @@ -3000,6 +3212,12 @@ PMU_OWNER() ? PMU_OWNER()->pid: -1, atomic_read(&ctx->ctx_saving_in_progress))); + /* must wait until not busy before retrying whole request */ + if (atomic_read(&ctx->ctx_is_busy)) { + arg->retval = 2; + return; + } + /* must wait if saving was interrupted */ if (atomic_read(&ctx->ctx_saving_in_progress)) { arg->retval = 1; @@ -3012,9 +3230,9 @@ return; } - DBprintk(("saving state for [%d] save_pmcs=0x%lx all_pmcs=0x%lx used_pmds=0x%lx\n", + DBprintk(("saving state for [%d] used_pmcs=0x%lx reload_pmcs=0x%lx used_pmds=0x%lx\n", arg->task->pid, - ctx->ctx_saved_pmcs[0], + ctx->ctx_used_pmcs[0], ctx->ctx_reload_pmcs[0], ctx->ctx_used_pmds[0])); @@ -3027,17 +3245,15 @@ /* * XXX needs further optimization. - * Also must take holes into account */ mask = ctx->ctx_used_pmds[0]; for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); - } - - mask = ctx->ctx_saved_pmcs[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); + if (mask & 0x1) t->pmd[i] = ia64_get_pmd(i); } + + /* save pmc0 */ + t->pmc[0] = ia64_get_pmc(0); + /* not owned by this CPU */ atomic_set(&ctx->ctx_last_cpu, -1); @@ -3066,11 +3282,17 @@ arg.task = task; arg.retval = -1; + if (atomic_read(&ctx->ctx_is_busy)) { +must_wait_busy: + while (atomic_read(&ctx->ctx_is_busy)); + } + if (atomic_read(&ctx->ctx_saving_in_progress)) { DBprintk(("no IPI, must wait for [%d] to be saved on [%d]\n", task->pid, cpu)); - +must_wait_saving: /* busy wait */ while (atomic_read(&ctx->ctx_saving_in_progress)); + DBprintk(("done saving for [%d] on [%d]\n", task->pid, cpu)); return; } DBprintk(("calling CPU %d from CPU %d\n", cpu, smp_processor_id())); @@ -3090,11 +3312,8 @@ * This is the case, where we interrupted the saving which started just at the time we sent the * IPI. */ - if (arg.retval == 1) { - DBprintk(("must wait for [%d] to be saved on [%d]\n", task->pid, cpu)); - while (atomic_read(&ctx->ctx_saving_in_progress)); - DBprintk(("done saving for [%d] on [%d]\n", task->pid, cpu)); - } + if (arg.retval == 1) goto must_wait_saving; + if (arg.retval == 2) goto must_wait_busy; } #endif /* CONFIG_SMP */ @@ -3113,6 +3332,30 @@ owner = PMU_OWNER(); ctx = task->thread.pfm_context; + t = &task->thread; + + /* + * we restore ALL the debug registers to avoid picking up + * stale state. + * + * This must be done even when the task is still the owner + * as the registers may have been modified via ptrace() + * (not perfmon) by the previous task. + * + * XXX: dealing with this in a lazy fashion requires modifications + * to the way the the debug registers are managed. This is will done + * in the next version of perfmon. + */ + if (ctx->ctx_fl_using_dbreg) { + for (i=0; i < pmu_conf.num_ibrs; i++) { + ia64_set_ibr(i, t->ibr[i]); + } + ia64_srlz_i(); + for (i=0; i < pmu_conf.num_dbrs; i++) { + ia64_set_dbr(i, t->dbr[i]); + } + ia64_srlz_d(); + } /* * if we were the last user, then nothing to do except restore psr @@ -3148,55 +3391,37 @@ pfm_fetch_regs(cpu, task, ctx); } #endif - t = &task->thread; /* - * XXX: will be replaced by assembly routine - * We clear all unused PMDs to avoid leaking information + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + * + * As an optimization, we will only reload the PMD that we use when + * the context is in protected mode, i.e. psr.sp=1 because then there + * is no leak possible. */ - mask = ctx->ctx_used_pmds[0]; + mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ? ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0]; for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) - ia64_set_pmd(i, t->pmd[i]); - else - ia64_set_pmd(i, 0UL); + if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.perf_ovfl_val); } - /* XXX: will need to clear all unused pmd, for security */ /* - * skip pmc[0] to avoid side-effects, - * all PMCs are systematically reloaded, unsued get default value - * to avoid picking up stale configuration + * PMC0 is never set in the mask because it is always restored + * separately. + * + * ALL PMCs are systematically reloaded, unused registers + * get their default (PAL reset) values to avoid picking up + * stale configuration. */ - mask = ctx->ctx_reload_pmcs[0]>>1; - for (i=1; mask; i++, mask>>=1) { - if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]); - } - - /* - * restore debug registers when used for range restrictions. - * We must restore the unused registers to avoid picking up - * stale information. - */ - mask = ctx->ctx_used_ibrs[0]; + mask = ctx->ctx_reload_pmcs[0]; for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) - ia64_set_ibr(i, t->ibr[i]); - else - ia64_set_ibr(i, 0UL); - } - - mask = ctx->ctx_used_dbrs[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) - ia64_set_dbr(i, t->dbr[i]); - else - ia64_set_dbr(i, 0UL); + if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]); } if (t->pmc[0] & ~0x1) { - ia64_srlz_d(); - pfm_overflow_handler(task, t->pmc[0], NULL); + pfm_overflow_handler(task, ctx, t->pmc[0], NULL); } /* @@ -3249,7 +3474,7 @@ * When restoring context, we must restore ALL pmcs, even the ones * that the task does not use to avoid leaks and possibly corruption * of the sesion because of configuration conflicts. So here, we - * initializaed the table used in the context switch restore routine. + * initialize the entire set used in the context switch restore routine. */ t->pmc[i] = reset_pmcs[i]; DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i])); @@ -3258,39 +3483,61 @@ } /* * clear reset values for PMD. - * XX: good up to 64 PMDS. Suppose that zero is a valid value. + * XXX: good up to 64 PMDS. Suppose that zero is a valid value. */ mask = pmu_conf.impl_regs[4]; for(i=0; mask; mask>>=1, i++) { if (mask & 0x1) ia64_set_pmd(i, 0UL); + t->pmd[i] = 0UL; } /* - * On context switched restore, we must restore ALL pmc even + * On context switched restore, we must restore ALL pmc and ALL pmd even * when they are not actively used by the task. In UP, the incoming process - * may otherwise pick up left over PMC state from the previous process. + * may otherwise pick up left over PMC, PMD state from the previous process. * As opposed to PMD, stale PMC can cause harm to the incoming * process because they may change what is being measured. * Therefore, we must systematically reinstall the entire * PMC state. In SMP, the same thing is possible on the - * same CPU but also on between 2 CPUs. + * same CPU but also on between 2 CPUs. + * + * The problem with PMD is information leaking especially + * to user level when psr.sp=0 * * There is unfortunately no easy way to avoid this problem - * on either UP or SMP. This definitively slows down the - * pfm_load_regs(). + * on either UP or SMP. This definitively slows down the + * pfm_load_regs() function. */ /* * We must include all the PMC in this mask to make sure we don't - * see any side effect of the stale state, such as opcode matching + * see any side effect of a stale state, such as opcode matching * or range restrictions, for instance. + * + * We never directly restore PMC0 so we do not include it in the mask. */ - ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0]; + ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0] & ~0x1; + /* + * We must include all the PMD in this mask to avoid picking + * up stale value and leak information, especially directly + * at the user level when psr.sp=0 + */ + ctx->ctx_reload_pmds[0] = pmu_conf.impl_regs[4]; + + /* + * Keep track of the pmds we want to sample + * XXX: may be we don't need to save/restore the DEAR/IEAR pmds + * but we do need the BTB for sure. This is because of a hardware + * buffer of 1 only for non-BTB pmds. + * + * We ignore the unimplemented pmds specified by the user + */ + ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0] & pmu_conf.impl_regs[4]; + ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */ /* * useful in case of re-enable after disable */ - ctx->ctx_used_pmds[0] = 0UL; ctx->ctx_used_ibrs[0] = 0UL; ctx->ctx_used_dbrs[0] = 0UL; @@ -3312,7 +3559,7 @@ { pfm_context_t *ctx; u64 pmc0; - unsigned long mask, mask2, val; + unsigned long mask2, val; int i; ctx = task->thread.pfm_context; @@ -3334,22 +3581,28 @@ */ if (ctx->ctx_fl_system) { - __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); /* disable dcr pp */ ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + /* stop monitoring */ + __asm__ __volatile__ ("rsm psr.pp;;"::: "memory"); + + ia64_srlz_i(); + #ifdef CONFIG_SMP local_cpu_data->pfm_syst_wide = 0; local_cpu_data->pfm_dcr_pp = 0; #else pfm_tasklist_toggle_pp(0); #endif - } else { + /* stop monitoring */ __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + ia64_srlz_i(); + /* no more save/restore on ctxsw */ current->thread.flags &= ~IA64_THREAD_PM_VALID; } @@ -3383,7 +3636,7 @@ ia64_srlz_d(); /* - * We don't need to restore psr, because we are on our way out anyway + * We don't need to restore psr, because we are on our way out */ /* @@ -3399,10 +3652,12 @@ if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) printk("perfmon: [%d] last_cpu=%d\n", task->pid, atomic_read(&ctx->ctx_last_cpu)); - mask = pmc0 >> PMU_FIRST_COUNTER; - mask2 = ctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER; - - for (i = PMU_FIRST_COUNTER; mask2; i++, mask>>=1, mask2>>=1) { + /* + * we save all the used pmds + * we take care of overflows for pmds used as counters + */ + mask2 = ctx->ctx_used_pmds[0]; + for (i = 0; mask2; i++, mask2>>=1) { /* skip non used pmds */ if ((mask2 & 0x1) == 0) continue; @@ -3410,7 +3665,6 @@ val = ia64_get_pmd(i); if (PMD_IS_COUNTING(i)) { - DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val)); /* collect latest results */ @@ -3423,15 +3677,19 @@ */ task->thread.pmd[i] = 0; - /* take care of overflow inline */ - if (mask & 0x1) { + /* + * take care of overflow inline + */ + if (pmc0 & (1UL << i)) { ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val; DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val)); } } else { DBprintk(("[%d] pmd[%d] hw_pmd=0x%lx\n", task->pid, i, val)); - /* not a counter, just save value as is */ + /* + * not a counter, just save value as is + */ task->thread.pmd[i] = val; } } @@ -3449,31 +3707,72 @@ int pfm_inherit(struct task_struct *task, struct pt_regs *regs) { - pfm_context_t *ctx = current->thread.pfm_context; + pfm_context_t *ctx; pfm_context_t *nctx; - struct thread_struct *th = &task->thread; + struct thread_struct *thread; unsigned long m; int i; /* + * the new task was copied from parent and therefore points + * to the parent's context at this point + */ + ctx = task->thread.pfm_context; + thread = &task->thread; + + /* * make sure child cannot mess up the monitoring session */ ia64_psr(regs)->sp = 1; DBprintk(("enabling psr.sp for [%d]\n", task->pid)); - /* - * remove any sampling buffer mapping from child user - * address space. Must be done for all cases of inheritance. - */ - if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task); + + /* + * if there was a virtual mapping for the sampling buffer + * the mapping is NOT inherited across fork() (see VM_DONTCOPY), + * so we don't have to explicitely remove it here. + * + * + * Part of the clearing of fields is also done in + * copy_thread() because the fiels are outside the + * pfm_context structure and can affect tasks not + * using perfmon. + */ + + /* clear pending notification */ + task->thread.pfm_ovfl_block_reset = 0; + + /* + * clear cpu pinning restriction for child + */ + if (ctx->ctx_fl_system) { + set_cpus_allowed(task, ctx->ctx_saved_cpus_allowed); + + DBprintk(("setting cpus_allowed for [%d] to 0x%lx from 0x%lx\n", + task->pid, + ctx->ctx_saved_cpus_allowed, + current->cpus_allowed)); + } /* * takes care of easiest case first */ if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { + DBprintk(("removing PFM context for [%d]\n", task->pid)); - task->thread.pfm_context = NULL; - task->thread.pfm_ovfl_block_reset = 0; + + task->thread.pfm_context = NULL; + + /* + * we must clear psr.up because the new child does + * not have a context and the PM_VALID flag is cleared + * in copy_thread(). + * + * we do not clear psr.pp because it is always + * controlled by the system wide logic and we should + * never be here when system wide is running anyway + */ + ia64_psr(regs)->up = 0; /* copy_thread() clears IA64_THREAD_PM_VALID */ return 0; @@ -3487,69 +3786,82 @@ if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) { nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; - atomic_set(&nctx->ctx_last_cpu, -1); - - /* - * task is not yet visible in the tasklist, so we do - * not need to lock the newly created context. - * However, we must grab the tasklist_lock to ensure - * that the ctx_owner or ctx_notify_task do not disappear - * while we increment their check counters. - */ - read_lock(&tasklist_lock); + DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid)); + } + /* + * task is not yet visible in the tasklist, so we do + * not need to lock the newly created context. + * However, we must grab the tasklist_lock to ensure + * that the ctx_owner or ctx_notify_task do not disappear + * while we increment their check counters. + */ + read_lock(&tasklist_lock); - if (nctx->ctx_notify_task) - atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check); + if (nctx->ctx_notify_task) + atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check); - if (nctx->ctx_owner) - atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check); + if (nctx->ctx_owner) + atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check); - read_unlock(&tasklist_lock); + read_unlock(&tasklist_lock); - DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid)); - LOCK_PFS(); - pfm_sessions.pfs_task_sessions++; - UNLOCK_PFS(); - } + LOCK_PFS(); + pfm_sessions.pfs_task_sessions++; + UNLOCK_PFS(); /* initialize counters in new context */ - m = pmu_conf.counter_pmds[0] >> PMU_FIRST_COUNTER; + m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER; for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) { - if (m & 0x1) { + if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) { nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val; - th->pmd[i] = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val; + thread->pmd[i] = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val; } + /* what about the other pmds? zero or keep as is */ } - /* clear BTB index register */ - th->pmd[16] = 0; + /* + * clear BTB index register + * XXX: CPU-model specific knowledge! + */ + thread->pmd[16] = 0; - /* if sampling then increment number of users of buffer */ - if (nctx->ctx_psb) { - /* - * XXX: nopt very pretty! - */ + nctx->ctx_fl_frozen = 0; + nctx->ctx_ovfl_regs[0] = 0UL; + atomic_set(&nctx->ctx_last_cpu, -1); + + /* + * here nctx->ctx_psb == ctx->ctx_psb + * + * increment reference count to sampling + * buffer, if any. Note that this is independent + * from the virtual mapping. The latter is never + * inherited while the former will be if context + * is setup to something different from PFM_FL_INHERIT_NONE + */ + if (nctx->ctx_psb) { LOCK_PSB(nctx->ctx_psb); + nctx->ctx_psb->psb_refcnt++; + + DBprintk(("updated smpl @ %p refcnt=%lu psb_flags=0x%x\n", + ctx->ctx_psb->psb_hdr, + ctx->ctx_psb->psb_refcnt, + ctx->ctx_psb->psb_flags)); + UNLOCK_PSB(nctx->ctx_psb); + /* * remove any pointer to sampling buffer mapping */ nctx->ctx_smpl_vaddr = 0; } - nctx->ctx_fl_frozen = 0; - nctx->ctx_ovfl_regs[0] = 0UL; - sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ - /* clear pending notification */ - th->pfm_ovfl_block_reset = 0; - /* link with new task */ - th->pfm_context = nctx; + thread->pfm_context = nctx; DBprintk(("nctx=%p for process [%d]\n", (void *)nctx, task->pid)); @@ -3559,7 +3871,7 @@ */ if (current->thread.flags & IA64_THREAD_PM_VALID) { DBprintk(("setting PM_VALID for [%d]\n", task->pid)); - th->flags |= IA64_THREAD_PM_VALID; + thread->flags |= IA64_THREAD_PM_VALID; } return 0; @@ -3588,9 +3900,9 @@ LOCK_PSB(psb); - DBprintk(("sampling buffer from [%d] @%p size %ld vma_flag=0x%x\n", + DBprintk(("sampling buffer from [%d] @%p size %ld refcnt=%lu psb_flags=0x%x\n", task->pid, - psb->psb_hdr, psb->psb_size, psb->psb_flags)); + psb->psb_hdr, psb->psb_size, psb->psb_refcnt, psb->psb_flags)); /* * in the case where we are the last user, we may be able to free @@ -3613,7 +3925,7 @@ * * See pfm_vm_close() and pfm_cleanup_smpl_buf() for more details. */ - if ((psb->psb_flags & PFM_PSB_VMA) == 0) { + if ((psb->psb_flags & PSB_HAS_VMA) == 0) { DBprintk(("cleaning sampling buffer from [%d] @%p size %ld\n", task->pid, @@ -3645,7 +3957,7 @@ * direct pointer to a task structure thereby bypassing the tasklist. * We must make sure that, if we have task!= NULL, the target task is still * present and is identical to the initial task specified - * during pfm_create_context(). It may already be detached from the tasklist but + * during pfm_context_create(). It may already be detached from the tasklist but * that's okay. Note that it is okay if we miss the deadline and the task scans * the list for nothing, it will affect performance but not correctness. * The correctness is ensured by using the ctx_lock which prevents the @@ -3683,7 +3995,8 @@ pfm_sessions.pfs_sys_session[ctx->ctx_cpu] = NULL; pfm_sessions.pfs_sys_sessions--; DBprintk(("freeing syswide session on CPU%ld\n", ctx->ctx_cpu)); - /* update perfmon debug register counter */ + + /* update perfmon debug register usage counter */ if (ctx->ctx_fl_using_dbreg) { if (pfm_sessions.pfs_sys_use_dbregs == 0) { printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid); @@ -3694,8 +4007,7 @@ /* * remove any CPU pinning */ - task->cpus_allowed = ctx->ctx_saved_cpus_allowed; - task->need_resched = 1; + set_cpus_allowed(task, ctx->ctx_saved_cpus_allowed); } else { pfm_sessions.pfs_task_sessions--; } @@ -3795,6 +4107,8 @@ } } read_unlock(&tasklist_lock); + + atomic_set(&task->thread.pfm_owners_check, 0); } @@ -3852,6 +4166,8 @@ } } read_unlock(&tasklist_lock); + + atomic_set(&task->thread.pfm_notifiers_check, 0); } static struct irqaction perfmon_irqaction = { @@ -3870,6 +4186,12 @@ if (i >= pmu_conf.num_pmcs) break; if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i); } +#ifdef CONFIG_MCKINLEY + /* + * set the 'stupid' enable bit to power the PMU! + */ + reset_pmcs[4] |= 1UL << 23; +#endif } /* @@ -3881,11 +4203,6 @@ pal_perf_mon_info_u_t pm_info; s64 status; - register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); - - ia64_set_pmv(IA64_PERFMON_VECTOR); - ia64_srlz_d(); - pmu_conf.pfm_is_disabled = 1; printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", @@ -3937,23 +4254,12 @@ */ pfm_pmu_snapshot(); - /* - * list the pmc registers used to control monitors - * XXX: unfortunately this information is not provided by PAL - * - * We start with the architected minimum and then refine for each CPU model - */ - pmu_conf.monitor_pmcs[0] = PMM(4)|PMM(5)|PMM(6)|PMM(7); - /* - * architected counters + * setup the register configuration descriptions for the CPU */ - pmu_conf.counter_pmds[0] |= PMM(4)|PMM(5)|PMM(6)|PMM(7); + pmu_conf.pmc_desc = pmc_desc; + pmu_conf.pmd_desc = pmd_desc; -#ifdef CONFIG_ITANIUM - pmu_conf.monitor_pmcs[0] |= PMM(10)|PMM(11)|PMM(12); - /* Itanium does not add more counters */ -#endif /* we are all set */ pmu_conf.pfm_is_disabled = 0; @@ -3962,6 +4268,8 @@ */ perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); + pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); + spin_lock_init(&pfm_sessions.pfs_lock); return 0; @@ -3972,10 +4280,12 @@ void perfmon_init_percpu (void) { + if (smp_processor_id() == 0) + register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + ia64_set_pmv(IA64_PERFMON_VECTOR); ia64_srlz_d(); } - #else /* !CONFIG_PERFMON */ diff -Nur linux-2.4.19/arch/ia64/kernel/perfmon_generic.h linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon_generic.h --- linux-2.4.19/arch/ia64/kernel/perfmon_generic.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon_generic.h Fri Apr 26 11:07:18 2002 @@ -0,0 +1,29 @@ +#define RDEP(x) (1UL<<(x)) + +#ifdef CONFIG_ITANIUM +#error "This file should not be used when CONFIG_ITANIUM is defined" +#endif + +static pfm_reg_desc_t pmc_desc[256]={ +/* pmc0 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc1 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc2 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc3 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc4 */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, + { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static pfm_reg_desc_t pmd_desc[256]={ +/* pmd0 */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}}, +/* pmd1 */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}}, +/* pmd2 */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}}, +/* pmd3 */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}}, +/* pmd4 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +/* pmd5 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +/* pmd6 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +/* pmd7 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, + { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; diff -Nur linux-2.4.19/arch/ia64/kernel/perfmon_itanium.h linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon_itanium.h --- linux-2.4.19/arch/ia64/kernel/perfmon_itanium.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon_itanium.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,99 @@ +/* + * This file contains the Itanium PMU register description tables + * and pmc checker used by perfmon.c. + * + * Copyright (C) 2002 Hewlett Packard Co + * Stephane Eranian + */ + +#define RDEP(x) (1UL<<(x)) + +#ifndef CONFIG_ITANIUM +#error "This file is only valid when CONFIG_ITANIUM is defined" +#endif + +static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs); + +static pfm_reg_desc_t pmc_desc[256]={ +/* pmc0 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc1 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc2 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc3 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc4 */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc10 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, + { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static pfm_reg_desc_t pmd_desc[256]={ +/* pmd0 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd1 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd2 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd3 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd4 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +/* pmd5 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +/* pmd6 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +/* pmd7 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, +/* pmd8 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd9 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, + { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static int +pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +{ + pfm_context_t *ctx = task->thread.pfm_context; + int ret; + + /* + * we must clear the (instruction) debug registers if pmc13.ta bit is cleared + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + */ + if (cnum == 13 && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) { + + /* don't mix debug with perfmon */ + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs); + if (ret) return ret; + } + + /* + * we must clear the (data) debug registers if pmc11.pt bit is cleared + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + */ + if (cnum == 11 && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) { + + /* don't mix debug with perfmon */ + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs); + if (ret) return ret; + } + return 0; +} + diff -Nur linux-2.4.19/arch/ia64/kernel/perfmon_mckinley.h linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon_mckinley.h --- linux-2.4.19/arch/ia64/kernel/perfmon_mckinley.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/perfmon_mckinley.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,134 @@ +/* + * This file contains the McKinley PMU register description tables + * and pmc checker used by perfmon.c. + * + * Copyright (C) 2002 Hewlett Packard Co + * Stephane Eranian + */ + +#define RDEP(x) (1UL<<(x)) + +#ifndef CONFIG_MCKINLEY +#error "This file is only valid when CONFIG_MCKINLEY is defined" +#endif + +static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs); + +static pfm_reg_desc_t pmc_desc[256]={ +/* pmc0 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc1 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc2 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc3 */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc4 */ { PFM_REG_COUNTING, 6, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc10 */ { PFM_REG_MONITOR, 4, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc14 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc15 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, + { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static pfm_reg_desc_t pmd_desc[256]={ +/* pmd0 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd1 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd2 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd3 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd4 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +/* pmd5 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +/* pmd6 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +/* pmd7 */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, +/* pmd8 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd9 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, + { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static int +pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +{ + struct thread_struct *th = &task->thread; + pfm_context_t *ctx = task->thread.pfm_context; + int ret = 0, check_case1 = 0; + unsigned long val8 = 0, val14 = 0, val13 = 0; + + /* + * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + */ + if (cnum == 13 && (*val & (0xfUL << 45)) && ctx->ctx_fl_using_dbreg == 0) { + + /* don't mix debug with perfmon */ + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs); + if (ret) return ret; + } + /* + * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled + * before they are (fl_using_dbreg==0) to avoid picking up stale information. + */ + if (cnum == 14 && ((*val & 0x2222) != 0x2222) && ctx->ctx_fl_using_dbreg == 0) { + + /* don't mix debug with perfmon */ + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs); + if (ret) return ret; + + } + + switch(cnum) { + case 4: *val |= 1UL << 23; /* force power enable bit */ + break; + case 8: val8 = *val; + val13 = th->pmc[13]; + val14 = th->pmc[14]; + check_case1 = 1; + break; + case 13: val8 = th->pmc[8]; + val13 = *val; + val14 = th->pmc[14]; + check_case1 = 1; + break; + case 14: val8 = th->pmc[13]; + val13 = th->pmc[13]; + val14 = *val; + check_case1 = 1; + break; + } + /* check illegal configuration which can produce inconsistencies in tagging + * i-side events in L1D and L2 caches + */ + if (check_case1) { + ret = ((val13 >> 45) & 0xf) == 0 + && ((val8 & 0x1) == 0) + && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0) + ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0)); + + if (ret) printk("perfmon: failure check_case1\n"); + } + + return ret ? -EINVAL : 0; +} diff -Nur linux-2.4.19/arch/ia64/kernel/process.c linux-2.4.19-sgi211r3/arch/ia64/kernel/process.c --- linux-2.4.19/arch/ia64/kernel/process.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/process.c Wed Feb 5 15:21:59 2003 @@ -12,15 +12,16 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include -#include #include #include #include @@ -37,8 +38,9 @@ do_show_stack (struct unw_frame_info *info, void *arg) { unsigned long ip, sp, bsp; + char buf[80]; /* don't make it so big that it overflows the stack! */ - printk("\nCall Trace: "); + printk("\nCall Trace:\n"); do { unw_get_ip(info, &ip); if (ip == 0) @@ -46,7 +48,9 @@ unw_get_sp(info, &sp); unw_get_bsp(info, &bsp); - printk("[<%016lx>] sp=0x%016lx bsp=0x%016lx\n", ip, sp, bsp); + snprintf(buf, sizeof(buf), " [<%016lx>] %%s sp=0x%016lx bsp=0x%016lx\n", + ip, sp, bsp); + print_symbol(buf, ip); } while (unw_unwind(info) >= 0); } @@ -73,13 +77,22 @@ } void +dump_stack (void) +{ + show_stack(NULL); +} + +void show_regs (struct pt_regs *regs) { unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri; printk("\nPid: %d, comm: %20s\n", current->pid, current->comm); + printk("Registers: cpu %d, sapicid 0x%04x, time %ld\n", + smp_processor_id(), hard_smp_processor_id(), jiffies); printk("psr : %016lx ifs : %016lx ip : [<%016lx>] %s\n", regs->cr_ipsr, regs->cr_ifs, ip, print_tainted()); + print_symbol("ip is at %s\n", ip); printk("unat: %016lx pfs : %016lx rsc : %016lx\n", regs->ar_unat, regs->ar_pfs, regs->ar_rsc); printk("rnat: %016lx bsps: %016lx pr : %016lx\n", @@ -126,33 +139,34 @@ cpu_idle (void *unused) { /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - current->counter = -100; +#ifdef CONFIG_IA64_SGI_AUTOTEST + { + extern void sgi_mcatest(int); + sgi_mcatest(1); + } +#endif while (1) { -#ifdef CONFIG_SMP if (!current->need_resched) - min_xtp(); -#endif - - while (!current->need_resched) { -#ifdef CONFIG_IA64_SGI_SN - snidle(); -#endif continue; - } #ifdef CONFIG_IA64_SGI_SN snidleoff(); #endif - #ifdef CONFIG_SMP normal_xtp(); #endif schedule(); check_pgt_cache(); +#ifdef CONFIG_SMP + if (!current->need_resched) + min_xtp(); +#endif +#ifdef CONFIG_IA64_SGI_SN + if (!current->need_resched) + snidle(); +#endif if (pm_idle) (*pm_idle)(); } @@ -174,8 +188,10 @@ # endif #endif +#ifdef CONFIG_IA32_SUPPORT if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_save_state(task); +#endif } void @@ -194,8 +210,10 @@ # endif #endif +#ifdef CONFIG_IA32_SUPPORT if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_load_state(task); +#endif } /* @@ -297,21 +315,24 @@ /* copy parts of thread_struct: */ p->thread.ksp = (unsigned long) child_stack - 16; + + /* stop some PSR bits from being inherited: */ + child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET) + & ~IA64_PSR_BITS_TO_CLEAR); + /* - * NOTE: The calling convention considers all floating point - * registers in the high partition (fph) to be scratch. Since - * the only way to get to this point is through a system call, - * we know that the values in fph are all dead. Hence, there - * is no need to inherit the fph state from the parent to the - * child and all we have to do is to make sure that - * IA64_THREAD_FPH_VALID is cleared in the child. + * NOTE: The calling convention considers all floating point registers in the high + * partition (fph) to be scratch. Since the only way to get to this point is + * through a system call, we know that the values in fph are all dead. Hence, + * there is no need to inherit the fph state from the parent to the child and all + * we have to do is to make sure that IA64_THREAD_FPH_VALID is cleared in the + * child. * - * XXX We could push this optimization a bit further by - * clearing IA64_THREAD_FPH_VALID on ANY system call. - * However, it's not clear this is worth doing. Also, it - * would be a slight deviation from the normal Linux system - * call behavior where scratch registers are preserved across - * system calls (unless used by the system call itself). + * XXX We could push this optimization a bit further by clearing + * IA64_THREAD_FPH_VALID on ANY system call. However, it's not clear this is + * worth doing. Also, it would be a slight deviation from the normal Linux system + * call behavior where scratch registers are preserved across system calls (unless + * used by the system call itself). */ # define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \ | IA64_THREAD_PM_VALID) @@ -333,8 +354,11 @@ */ atomic_set(&p->thread.pfm_notifiers_check, 0); atomic_set(&p->thread.pfm_owners_check, 0); + /* clear list of sampling buffer to free for new task */ + p->thread.pfm_smpl_buf_list = NULL; - if (current->thread.pfm_context) retval = pfm_inherit(p, child_ptregs); + if (current->thread.pfm_context) + retval = pfm_inherit(p, child_ptregs); #endif return retval; } @@ -537,14 +561,13 @@ ia64_set_fpu_owner(0); #endif #ifdef CONFIG_PERFMON - /* if needed, stop monitoring and flush state to perfmon context */ - if (current->thread.pfm_context) + /* stop monitoring */ + if (current->thread.pfm_context) pfm_flush_regs(current); /* free debug register resources */ - if ((current->thread.flags & IA64_THREAD_DBG_VALID) != 0) { + if (current->thread.flags & IA64_THREAD_DBG_VALID) pfm_release_debug_registers(current); - } #endif } @@ -615,6 +638,11 @@ void machine_halt (void) { +#ifdef CONFIG_IA64_SGI_SN + extern void smp_send_stop_all(void); + + smp_send_stop_all(); +#endif cpu_halt(); } diff -Nur linux-2.4.19/arch/ia64/kernel/sal.c linux-2.4.19-sgi211r3/arch/ia64/kernel/sal.c --- linux-2.4.19/arch/ia64/kernel/sal.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/sal.c Fri Nov 15 18:23:19 2002 @@ -21,10 +21,13 @@ spinlock_t sal_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; unsigned long sal_platform_features; -static struct { +typedef struct { void *addr; /* function entry point */ void *gpval; /* gp value to use */ -} pdesc; +} pdesc_t; + +static pdesc_t pdesc; +pdesc_t ia64_sal_phys; static long default_handler (void) @@ -77,12 +80,17 @@ return str; } -static void __init +#if !defined(CONFIG_IA64_EARLY_PRINTK) || !defined(CONFIG_IA64_SGI_SN) +static +#endif +void __init ia64_sal_handler_init (void *entry_point, void *gpval) { /* fill in the SAL procedure descriptor and point ia64_sal to it: */ pdesc.addr = entry_point; pdesc.gpval = gpval; + ia64_sal_phys.addr = (void*)__tpa(entry_point); + ia64_sal_phys.gpval = (void*)__tpa(gpval); ia64_sal = (ia64_sal_handler) &pdesc; } @@ -185,4 +193,13 @@ } p += SAL_DESC_SIZE(*p); } +#ifdef CONFIG_IA64_SGI_SN1 + /* + * XXX Hack to turn this on until SN SAL supports it + */ + printk("SAL: Platform features "); + printk("ITC_may_drift "); + sal_platform_features |= IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT; + printk("\n"); +#endif } diff -Nur linux-2.4.19/arch/ia64/kernel/salinfo.c linux-2.4.19-sgi211r3/arch/ia64/kernel/salinfo.c --- linux-2.4.19/arch/ia64/kernel/salinfo.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/salinfo.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,105 @@ +/* + * salinfo.c + * + * Creates entries in /proc/sal for various system features. + * + * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * + * 10/30/2001 jbarnes@sgi.com copied much of Stephane's palinfo + * code to create this file + */ + +#include +#include +#include + +#include + +MODULE_AUTHOR("Jesse Barnes "); +MODULE_DESCRIPTION("/proc interface to IA-64 SAL features"); +MODULE_LICENSE("GPL"); + +static int salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data); + +typedef struct { + const char *name; /* name of the proc entry */ + unsigned long feature; /* feature bit */ + struct proc_dir_entry *entry; /* registered entry (removal) */ +} salinfo_entry_t; + +/* + * List {name,feature} pairs for every entry in /proc/sal/ + * that this module exports + */ +static salinfo_entry_t salinfo_entries[]={ + { "bus_lock", IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, }, + { "irq_redirection", IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, }, + { "ipi_redirection", IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, }, + { "itc_drift", IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, }, +}; + +#define NR_SALINFO_ENTRIES (sizeof(salinfo_entries)/sizeof(salinfo_entry_t)) + +/* + * One for each feature and one more for the directory entry... + */ +static struct proc_dir_entry *salinfo_proc_entries[NR_SALINFO_ENTRIES + 1]; + +static int __init +salinfo_init(void) +{ + struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */ + struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */ + int i; + + salinfo_dir = proc_mkdir("sal", NULL); + + for (i=0; i < NR_SALINFO_ENTRIES; i++) { + /* pass the feature bit in question as misc data */ + *sdir++ = create_proc_read_entry (salinfo_entries[i].name, 0, salinfo_dir, + salinfo_read, (void *)salinfo_entries[i].feature); + } + *sdir++ = salinfo_dir; + + return 0; +} + +static void __exit +salinfo_exit(void) +{ + int i = 0; + + for (i = 0; i < NR_SALINFO_ENTRIES ; i++) { + if (salinfo_proc_entries[i]) + remove_proc_entry (salinfo_proc_entries[i]->name, NULL); + } +} + +/* + * 'data' contains an integer that corresponds to the feature we're + * testing + */ +static int +salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + + MOD_INC_USE_COUNT; + + len = sprintf(page, (sal_platform_features & (unsigned long)data) ? "1\n" : "0\n"); + + if (len <= off+count) *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) len = count; + if (len<0) len = 0; + + MOD_DEC_USE_COUNT; + + return len; +} + +module_init(salinfo_init); +module_exit(salinfo_exit); diff -Nur linux-2.4.19/arch/ia64/kernel/setup.c linux-2.4.19-sgi211r3/arch/ia64/kernel/setup.c --- linux-2.4.19/arch/ia64/kernel/setup.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/setup.c Fri Jan 31 14:01:34 2003 @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -28,17 +29,20 @@ #include #include #include +#include +#include -#include #include #include +#include #include #include #include #include -#include #include #include +#include +#include #ifdef CONFIG_BLK_DEV_RAM # include @@ -65,6 +69,8 @@ unsigned long ia64_iobase; /* virtual address for I/O accesses */ +unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */ + #define COMMAND_LINE_SIZE 512 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */ @@ -107,15 +113,53 @@ #define IGNORE_PFN0 1 /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */ + +#ifdef CONFIG_DISCONTIGMEM /* - * Free available memory based on the primitive map created from - * the boot parameters. This routine does not assume the incoming - * segments are sorted. + * efi_memmap_walk() knows nothing about layout of memory across nodes. Find + * out to which node a block of memory belongs. Ignore memory that we cannot + * identify, and split blocks that run across multiple nodes. + * + * Take this opportunity to round the start address up and the end address + * down to page boundaries. */ -static int -free_available_memory (unsigned long start, unsigned long end, void *arg) +void +call_pernode_memory (unsigned long start, unsigned long end, void *arg) +{ + unsigned long rs, re; + void (*func)(unsigned long, unsigned long, int, int); + int i; + + start = PAGE_ALIGN(start); + end &= PAGE_MASK; + if (start >= end) + return; + + func = arg; + + for (i = 0; i < num_memory_chunks; i++) { + rs = MAX(start, node_memory_chunk[i].start_paddr); + re = MIN(end, node_memory_chunk[i].start_paddr+node_memory_chunk[i].size); + + if (rs < re) + (*func)(rs, re-rs, node_memory_chunk[i].nid, + node_memory_chunk[i].bank); + } +} +#endif /* CONFIG_DISCONTIGMEM */ + +/* + * Filter incoming memory segments based on the primitive map created from + * the boot parameters. Segments contained in the map are removed from the + * memory ranges. A caller-specified function is called with the memory + * ranges that remain after filtering. + * This routine does not assume the incoming segments are sorted. + */ +int +filter_rsvd_memory (unsigned long start, unsigned long end, void *arg) { unsigned long range_start, range_end, prev_start; + void (*func)(unsigned long, unsigned long); int i; #if IGNORE_PFN0 @@ -129,13 +173,18 @@ * lowest possible address(walker uses virtual) */ prev_start = PAGE_OFFSET; + func = arg; for (i = 0; i < num_rsvd_regions; ++i) { range_start = MAX(start, prev_start); range_end = MIN(end, rsvd_region[i].start); if (range_start < range_end) - free_bootmem(__pa(range_start), range_end - range_start); +#ifdef CONFIG_DISCONTIGMEM + call_pernode_memory(__pa(range_start), __pa(range_end), func); +#else + (*func)(__pa(range_start), range_end - range_start); +#endif /* nothing more available in this segment */ if (range_end == end) return 0; @@ -147,6 +196,8 @@ } +#ifndef CONFIG_DISCONTIGMEM + /* * Find a place to put the bootmap and return its starting address in bootmap_start. * This address must be page-aligned. @@ -171,11 +222,9 @@ range_start = MAX(start, free_start); range_end = MIN(end, rsvd_region[i].start & PAGE_MASK); - if (range_end <= range_start) continue; /* skip over empty range */ - - if (range_end - range_start >= needed) { + if (range_end > range_start && range_end - range_start >= needed) { bootmap_start = __pa(range_start); - return 1; /* done */ + return -1; /* done */ } /* nothing more available in this segment */ @@ -185,6 +234,7 @@ } return 0; } +#endif /* CONFIG_DISCONTIGMEM */ static void sort_regions (struct rsvd_region *rsvd_region, int max) @@ -228,8 +278,8 @@ + strlen(__va(ia64_boot_param->command_line)) + 1); n++; - rsvd_region[n].start = KERNEL_START; - rsvd_region[n].end = KERNEL_END; + rsvd_region[n].start = __imva(KERNEL_START); + rsvd_region[n].end = __imva(KERNEL_END); n++; #ifdef CONFIG_BLK_DEV_INITRD @@ -253,6 +303,13 @@ max_pfn = 0; efi_memmap_walk(find_max_pfn, &max_pfn); +#ifdef CONFIG_DISCONTIGMEM + { + extern void discontig_mem_init(void); + bootmap_start = bootmap_size = 0; /* stops gcc warnings */ + discontig_mem_init() ; + } +#else /* how many bytes to cover all the pages */ bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT; @@ -265,8 +322,9 @@ bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn); /* Free all available memory, then mark bootmem-map as being in use. */ - efi_memmap_walk(free_available_memory, 0); + efi_memmap_walk(filter_rsvd_memory, free_bootmem); reserve_bootmem(bootmap_start, bootmap_size); +#endif /* CONFIG_DISCONTIGMEM */ #ifdef CONFIG_BLK_DEV_INITRD if (ia64_boot_param->initrd_start) { @@ -279,19 +337,70 @@ #endif } +/* + * There are two places in the performance critical path of + * the exception handling code where we need to know the physical + * address of the swapper_pg_dir structure. This routine + * patches the "movl" instructions to load the value needed. + */ +static void __init +patch_ivt_with_phys_swapper_pg_dir(void) +{ + extern char ia64_ivt_patch1[], ia64_ivt_patch2[]; + unsigned long spd = __tpa(swapper_pg_dir); + unsigned long *p; + + p = (unsigned long *)__imva(ia64_ivt_patch1); + + *p = (*p & 0x3fffffffffffUL) | + ((spd & 0x000000ffffc00000UL)<<24); + p++; + *p = (*p & 0xf000080fff800000UL) | + ((spd & 0x8000000000000000UL) >> 4) | + ((spd & 0x7fffff0000000000UL) >> 40) | + ((spd & 0x00000000001f0000UL) << 29) | + ((spd & 0x0000000000200000UL) << 23) | + ((spd & 0x000000000000ff80UL) << 43) | + ((spd & 0x000000000000007fUL) << 36); + + p = (unsigned long *)__imva(ia64_ivt_patch2); + + *p = (*p & 0x3fffffffffffUL) | + ((spd & 0x000000ffffc00000UL)<<24); + p++; + *p = (*p & 0xf000080fff800000UL) | + ((spd & 0x8000000000000000UL) >> 4) | + ((spd & 0x7fffff0000000000UL) >> 40) | + ((spd & 0x00000000001f0000UL) << 29) | + ((spd & 0x0000000000200000UL) << 23) | + ((spd & 0x000000000000ff80UL) << 43) | + ((spd & 0x000000000000007fUL) << 36); +} + void __init setup_arch (char **cmdline_p) { extern unsigned long ia64_iobase; + unsigned long phys_iobase; unw_init(); + patch_ivt_with_phys_swapper_pg_dir(); + *cmdline_p = __va(ia64_boot_param->command_line); strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ efi_init(); +#ifdef CONFIG_ACPI_BOOT + if (efi.acpi20) { + /* Find SRAT and SLIT tables */ + acpi_early_init(); + } +#endif + + iomem_resource.end = ~0UL; /* FIXME probably belongs elsewhere */ find_memory(); #if 0 @@ -315,24 +424,23 @@ #endif /* - * Set `iobase' to the appropriate address in region 6 - * (uncached access range) + * Set `iobase' to the appropriate address in region 6 (uncached access range). * - * The EFI memory map is the "prefered" location to get the I/O port - * space base, rather the relying on AR.KR0. This should become more - * clear in future SAL specs. We'll fall back to getting it out of - * AR.KR0 if no appropriate entry is found in the memory map. + * The EFI memory map is the "preferred" location to get the I/O port space base, + * rather the relying on AR.KR0. This should become more clear in future SAL + * specs. We'll fall back to getting it out of AR.KR0 if no appropriate entry is + * found in the memory map. */ - ia64_iobase = efi_get_iobase(); - if (ia64_iobase) + phys_iobase = efi_get_iobase(); + if (phys_iobase) /* set AR.KR0 since this is all we use it for anyway */ - ia64_set_kr(IA64_KR_IO_BASE, ia64_iobase); + ia64_set_kr(IA64_KR_IO_BASE, phys_iobase); else { - ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE); + phys_iobase = ia64_get_kr(IA64_KR_IO_BASE); printk("No I/O port range found in EFI memory map, falling back to AR.KR0\n"); - printk("I/O port base = 0x%lx\n", ia64_iobase); + printk("I/O port base = 0x%lx\n", phys_iobase); } - ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET); + ia64_iobase = (unsigned long) ioremap(phys_iobase, 0); #ifdef CONFIG_SMP cpu_physical_id(0) = hard_smp_processor_id(); @@ -340,32 +448,40 @@ cpu_init(); /* initialize the bootstrap CPU */ - if (efi.acpi20) { - /* Parse the ACPI 2.0 tables */ - acpi20_parse(efi.acpi20); - } else if (efi.acpi) { - /* Parse the ACPI tables */ - acpi_parse(efi.acpi); - } +#ifdef CONFIG_ACPI_BOOT + acpi_boot_init(*cmdline_p); +#endif +#ifdef CONFIG_SERIAL_HCDP if (efi.hcdp) { + void setup_serial_hcdp(void *); + /* Setup the serial ports described by HCDP */ setup_serial_hcdp(efi.hcdp); } - +#endif #ifdef CONFIG_VT -# if defined(CONFIG_VGA_CONSOLE) - conswitchp = &vga_con; -# elif defined(CONFIG_DUMMY_CONSOLE) +# if defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; # endif +# if defined(CONFIG_VGA_CONSOLE) + /* + * Non-legacy systems may route legacy VGA MMIO range to system + * memory. vga_con probes the MMIO hole, so memory looks like + * a VGA device to it. The EFI memory map can tell us if it's + * memory so we can avoid this problem. + */ + if (efi_mem_type(0xA0000) != EFI_CONVENTIONAL_MEMORY) + conswitchp = &vga_con; +# endif #endif + platform_setup(cmdline_p); + #ifdef CONFIG_IA64_MCA /* enable IA-64 Machine Check Abort Handling */ ia64_mca_init(); #endif - platform_setup(cmdline_p); paging_init(); unw_create_gate_table(); @@ -379,10 +495,10 @@ { #ifdef CONFIG_SMP # define lpj c->loops_per_jiffy -# define cpu c->processor +# define cpum c->processor #else # define lpj loops_per_jiffy -# define cpu 0 +# define cpum 0 #endif char family[32], features[128], *cp; struct cpuinfo_ia64 *c = v; @@ -392,7 +508,7 @@ switch (c->family) { case 0x07: memcpy(family, "Itanium", 8); break; - case 0x1f: memcpy(family, "McKinley", 9); break; + case 0x1f: memcpy(family, "Itanium 2", 10); break; default: sprintf(family, "%u", c->family); break; } @@ -421,19 +537,20 @@ "cpu MHz : %lu.%06lu\n" "itc MHz : %lu.%06lu\n" "BogoMIPS : %lu.%02lu\n\n", - cpu, c->vendor, family, c->model, c->revision, c->archrev, + cpum, c->vendor, family, c->model, c->revision, c->archrev, features, c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, c->itc_freq / 1000000, c->itc_freq % 1000000, lpj*HZ/500000, (lpj*HZ/5000) % 100); return 0; +#undef cpum } static void * c_start (struct seq_file *m, loff_t *pos) { #ifdef CONFIG_SMP - while (*pos < NR_CPUS && !(cpu_online_map & (1 << *pos))) + while (*pos < NR_CPUS && !(cpu_online_map & (1UL << *pos))) ++*pos; #endif return *pos < NR_CPUS ? cpu_data(*pos) : NULL; @@ -508,8 +625,10 @@ impl_va_msb = vm2.pal_vm_info_2_s.impl_va_msb; phys_addr_size = vm1.pal_vm_info_1_s.phys_add_size; } +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) printk("CPU %d: %lu virtual and %lu physical address bits\n", smp_processor_id(), impl_va_msb + 1, phys_addr_size); +#endif c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1)); c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1)); } @@ -527,7 +646,8 @@ unsigned int max_ctx; struct cpuinfo_ia64 *my_cpu_data; #ifdef CONFIG_NUMA - int cpu, order; + int cpu, order=0; + struct cpuinfo_ia64 *old_cpu_data=NULL; /* * If NUMA is configured, the cpu_data array is not preallocated. The boot cpu @@ -537,27 +657,43 @@ * before the cpus are actually started. */ if (!boot_cpu_data) { - my_cpu_data = alloc_bootmem_pages_node(NODE_DATA(numa_node_id()), + my_cpu_data = alloc_bootmem_pages_node(BOOT_NODE_DATA(boot_get_local_cnodeid()), sizeof(struct cpuinfo_ia64)); boot_cpu_data = my_cpu_data; my_cpu_data->cpu_data[0] = my_cpu_data; for (cpu = 1; cpu < NR_CPUS; ++cpu) my_cpu_data->cpu_data[cpu] - = alloc_bootmem_pages_node(NODE_DATA(numa_node_id()), + = alloc_bootmem_pages_node(BOOT_NODE_DATA(boot_get_local_cnodeid()), sizeof(struct cpuinfo_ia64)); for (cpu = 1; cpu < NR_CPUS; ++cpu) memcpy(my_cpu_data->cpu_data[cpu]->cpu_data, my_cpu_data->cpu_data, sizeof(my_cpu_data->cpu_data)); + my_cpu_data->mmu_gathers = alloc_bootmem_pages_node(BOOT_NODE_DATA(boot_get_local_cnodeid()), + sizeof(mmu_gather_t)); } else { +#ifdef CONFIG_IA64_DIG + /* FIXME */ + static struct cpuinfo_ia64 dig_numa_cpu_data[NR_CPUS]; + my_cpu_data = &dig_numa_cpu_data[smp_processor_id()]; +#else + struct page * __init boot_alloc_pages_node(int nid, int gfp_mask, unsigned long order); order = get_order(sizeof(struct cpuinfo_ia64)); - my_cpu_data = page_address(alloc_pages_node(numa_node_id(), GFP_KERNEL, order)); + my_cpu_data = page_address(boot_alloc_pages_node(boot_get_local_cnodeid(), GFP_KERNEL, order)); +#endif memcpy(my_cpu_data, boot_cpu_data->cpu_data[smp_processor_id()], sizeof(struct cpuinfo_ia64)); - __free_pages(virt_to_page(boot_cpu_data->cpu_data[smp_processor_id()]), - order); + + /* Cant call __free_pages until cpu_data is set up. */ + old_cpu_data = boot_cpu_data->cpu_data[smp_processor_id()]; for (cpu = 0; cpu < NR_CPUS; ++cpu) boot_cpu_data->cpu_data[cpu]->cpu_data[smp_processor_id()] = my_cpu_data; + + my_cpu_data->mmu_gathers = page_address(boot_alloc_pages_node(boot_get_local_cnodeid(), + GFP_KERNEL, get_order(sizeof(mmu_gather_t)))); } + my_cpu_data->node_data = get_node_data_ptr(); + my_cpu_data->cnodeid = boot_get_local_cnodeid(); + my_cpu_data->node_data->active_cpu_count++; #else my_cpu_data = cpu_data(smp_processor_id()); #endif @@ -570,6 +706,24 @@ */ identify_cpu(my_cpu_data); +#ifdef CONFIG_MCKINLEY + { +#define FEATURE_SET 16 + struct ia64_pal_retval iprv; + + if (my_cpu_data->family == 0x1f) { + + PAL_CALL_PHYS(iprv, PAL_PROC_GET_FEATURES, 0, FEATURE_SET, 0); + + if ((iprv.status == 0) && (iprv.v0 & 0x80) && (iprv.v2 & 0x80)) { + + PAL_CALL_PHYS(iprv, PAL_PROC_SET_FEATURES, + (iprv.v1 | 0x80), FEATURE_SET, 0); + } + } + } +#endif + /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); @@ -581,7 +735,7 @@ * shouldn't be affected by this (moral: keep your ia32 locks aligned and you'll * be fine). */ - ia64_set_dcr( IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR + ia64_set_dcr( IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC); #ifndef CONFIG_SMP ia64_set_fpu_owner(0); @@ -630,4 +784,9 @@ local_cpu_data->phys_stacked_size_p8 = num_phys_stacked*8 + 8; platform_cpu_init(); + +#ifdef CONFIG_NUMA + if (old_cpu_data) + __free_pages(virt_to_page(old_cpu_data), order); +#endif } diff -Nur linux-2.4.19/arch/ia64/kernel/signal.c linux-2.4.19-sgi211r3/arch/ia64/kernel/signal.c --- linux-2.4.19/arch/ia64/kernel/signal.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/signal.c Tue Oct 29 14:53:41 2002 @@ -41,6 +41,16 @@ extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */ +register double f16 asm ("f16"); register double f17 asm ("f17"); +register double f18 asm ("f18"); register double f19 asm ("f19"); +register double f20 asm ("f20"); register double f21 asm ("f21"); +register double f22 asm ("f22"); register double f23 asm ("f23"); + +register double f24 asm ("f24"); register double f25 asm ("f25"); +register double f26 asm ("f26"); register double f27 asm ("f27"); +register double f28 asm ("f28"); register double f29 asm ("f29"); +register double f30 asm ("f30"); register double f31 asm ("f31"); + long ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) { @@ -143,9 +153,11 @@ { if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { + if (from->si_code < 0) { + if (__copy_to_user(to, from, sizeof(siginfo_t))) + return -EFAULT; + return 0; + } else { int err; /* @@ -559,7 +571,7 @@ continue; switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -Nur linux-2.4.19/arch/ia64/kernel/smp.c linux-2.4.19-sgi211r3/arch/ia64/kernel/smp.c --- linux-2.4.19/arch/ia64/kernel/smp.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/smp.c Fri Dec 13 08:54:25 2002 @@ -31,14 +31,22 @@ #include #include #include +#include + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#include +#endif #include #include #include #include -#include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ + #include #include #include @@ -72,6 +80,17 @@ #define IPI_CALL_FUNC 0 #define IPI_CPU_STOP 1 +#ifdef CONFIG_KDB +#define IPI_KDB_INTERRUPT 2 +#endif /* CONFIG_KDB */ + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#ifdef DUMP_IPI_FLUSH_TLB +#define IPI_FLUSH_TLB 3 +#endif +#define IPI_DUMP_INTERRUPT 4 +int (*dump_ipi_function_ptr)(struct pt_regs *) = NULL; +#endif /* CONFIG_DUMP || CONFIG_DUMP_MODULE */ static void stop_this_cpu (void) @@ -90,7 +109,7 @@ handle_IPI (int irq, void *dev_id, struct pt_regs *regs) { int this_cpu = smp_processor_id(); - unsigned long *pending_ipis = &local_cpu_data->ipi_operation; + unsigned long *pending_ipis = &local_cpu_data->ipi.operation; unsigned long ops; /* Count this now; we may make a call that never returns. */ @@ -132,10 +151,36 @@ } break; +#ifdef DUMP_IPI_FLUSH_TLB + case IPI_FLUSH_TLB: + { + extern void sn1_received_flush_tlb(void); + sn1_received_flush_tlb(); + break; + } +#endif /* DUMP_IPI_FLUSH_TLB */ case IPI_CPU_STOP: stop_this_cpu(); break; +#ifdef CONFIG_KDB + case IPI_KDB_INTERRUPT: + if (!kdb_ipi(regs, NULL)) + printk(KERN_ERR "kdb_ipi() rejected IPI_KDB_INTERRUPT\n"); + break; +#endif + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + case IPI_DUMP_INTERRUPT: + if( dump_ipi_function_ptr != NULL ) { + if (!dump_ipi_function_ptr(regs)) { + printk(KERN_ERR "(*dump_ipi_function_ptr)(): rejected IPI_DUMP_INTERRUPT\n"); + } + } + break; +#endif + + default: printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; @@ -149,7 +194,7 @@ static inline void send_IPI_single (int dest_cpu, int op) { - set_bit(op, &cpu_data(dest_cpu)->ipi_operation); + set_bit(op, &cpu_data(dest_cpu)->ipi.operation); platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); } @@ -186,6 +231,19 @@ } void +smp_send_reschedule_all(void) +{ + send_IPI_all(IA64_IPI_RESCHEDULE); +} + +void +smp_send_stop_all(void) +{ + send_IPI_allbutself(IPI_CPU_STOP); + send_IPI_self(IPI_CPU_STOP); +} + +void smp_flush_tlb_all (void) { smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1); @@ -212,7 +270,7 @@ int cpus = 1; if (cpuid == smp_processor_id()) { - printk(__FUNCTION__" trying to call self\n"); + printk("%s: trying to call self\n", __FUNCTION__); return -EBUSY; } @@ -264,6 +322,7 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) { + static int smp_call_function_timedout = 0; struct call_data_struct data; int cpus = smp_num_cpus-1; @@ -284,8 +343,39 @@ send_IPI_allbutself(IPI_CALL_FUNC); /* Wait for response */ +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + if (dump_in_progress) { + int ms_timeout; /* Timeout other CPU to start IPI processing */ + + if (smp_call_function_timedout) { + ms_timeout = 1 * 1000; /* 1 second for remaining CPUs */ + } else { + ms_timeout = cpus * 5 * 1000; /* 5 seconds per CPU for first CPU */ + } + + while (atomic_read(&data.started) != cpus && ms_timeout--) { + mdelay(1); + barrier(); + } + if (ms_timeout <= 0) { + /* + * All of the CPU's didn't start, + * some are likely hung. We just + * continue on and wait for the + * the started cpus if wait is + * desired. + */ + smp_call_function_timedout++; + cpus = atomic_read(&data.started); + } + } else { + while (atomic_read(&data.started) != cpus) + barrier(); + } +#else while (atomic_read(&data.started) != cpus) barrier(); +#endif if (wait) while (atomic_read(&data.finished) != cpus) @@ -317,8 +407,31 @@ smp_num_cpus = 1; } +#ifdef DUMP_IPI_FLUSH_TLB +void +smp_send_flush_tlb (void) +{ + send_IPI_allbutself(IPI_FLUSH_TLB); +} +#endif /* DUMP_IPI_FLUSH_TLB */ + int __init setup_profiling_timer (unsigned int multiplier) { return -EINVAL; } + +#if defined(CONFIG_KDB) +void +smp_kdb_stop(void) +{ + send_IPI_allbutself(IPI_KDB_INTERRUPT); +} +#endif /* CONFIG_KDB */ + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +void dump_send_ipi(void) +{ + send_IPI_allbutself(IPI_DUMP_INTERRUPT); +} +#endif diff -Nur linux-2.4.19/arch/ia64/kernel/smpboot.c linux-2.4.19-sgi211r3/arch/ia64/kernel/smpboot.c --- linux-2.4.19/arch/ia64/kernel/smpboot.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/smpboot.c Wed Jan 29 07:25:29 2003 @@ -23,13 +23,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include #include @@ -51,6 +52,15 @@ #define Dprintk(x...) #endif +/* + * Timeout for waiting for slave cpus to start. Units are + * in 100usec. + */ +#ifdef CONFIG_IA64_SGI_SN2 +#define APSTART_DELAY 300000 +#else +#define APSTART_DELAY 100000 +#endif /* * ITC synchronization related stuff: @@ -68,6 +78,7 @@ extern void __init calibrate_delay(void); extern void start_ap(void); +extern unsigned long ia64_iobase; int cpucount; @@ -318,6 +329,11 @@ { int cpuid, phys_id; extern void ia64_init_itm(void); +#ifdef CONFIG_DISCONTIGMEM + cnodeid_t kloadnode; + extern unsigned long kcopybase[PLAT_MAX_COMPACT_NODES]; + extern void ia64_remap_kernel(long); +#endif #ifdef CONFIG_PERFMON extern void perfmon_init_percpu(void); @@ -331,19 +347,41 @@ BUG(); } +#ifdef CONFIG_DISCONTIGMEM + /* + * Check to see if there is a closer copy of the kernel to use. + */ + kloadnode = paddr_to_nid(__tpa(&kcopybase[0])); + if (node_cpuid[cpuid].nid != kloadnode && kcopybase[node_cpuid[cpuid].nid] != ~0UL) + ia64_remap_kernel(__pa(kcopybase[node_cpuid[cpuid].nid])); +#endif + smp_setup_percpu_timer(); +#ifdef CONFIG_IA64_HAVE_SYNCHRONIZED_ITC /* * Synchronize the ITC with the BP */ Dprintk("Going to syncup ITC with BP.\n"); ia64_sync_itc(0); +#endif + /* * Get our bogomips. */ ia64_init_itm(); + /* + * Set I/O port base per CPU + */ + +#ifdef CONFIG_IA64_SGI_SN_DEBUG + ia64_set_kr(IA64_KR_IO_BASE, (ia64_iobase & 0x1fffffffffffffffUL)); +#else + ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase)); +#endif + #ifdef CONFIG_IA64_MCA ia64_mca_cmc_vector_setup(); /* Setup vector on AP & enable */ ia64_mca_check_errors(); /* For post-failure MCA error logging */ @@ -356,6 +394,7 @@ local_irq_enable(); calibrate_delay(); local_cpu_data->loops_per_jiffy = loops_per_jiffy; + ia64_disable_timer(); /* * Allow the master to continue. */ @@ -379,7 +418,8 @@ Dprintk("CPU %d is set to go.\n", smp_processor_id()); while (!atomic_read(&smp_commenced)) ; - + /* reenable timer interrupts */ + ia64_cpu_local_tick(); Dprintk("CPU %d is starting idle.\n", smp_processor_id()); return cpu_idle(); } @@ -416,11 +456,10 @@ if (!idle) panic("No idle process for CPU %d", cpu); - task_set_cpu(idle, cpu); /* we schedule the first task manually */ + init_idle(idle, cpu); ia64_cpu_to_sapicid[cpu] = sapicid; - del_from_runqueue(idle); unhash_process(idle); init_tasks[cpu] = idle; @@ -432,7 +471,7 @@ * Wait 10s total for the AP to start */ Dprintk("Waiting on callin_map ..."); - for (timeout = 0; timeout < 100000; timeout++) { + for (timeout = 0; timeout < APSTART_DELAY; timeout++) { if (test_bit(cpu, &cpu_callin_map)) break; /* It has booted */ udelay(100); @@ -441,9 +480,9 @@ if (test_bit(cpu, &cpu_callin_map)) { /* number CPUs logically, starting from 1 (BSP is 0) */ - printk("CPU%d: ", cpu); + Dprintk("CPU%d: ", cpu); /*print_cpu_info(&cpu_data[cpu]); */ - printk("CPU has booted.\n"); + Dprintk("CPU has booted.\n"); } else { printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid); ia64_cpu_to_sapicid[cpu] = -1; @@ -481,8 +520,7 @@ printk("Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id); global_irq_holder = 0; - current->processor = 0; - init_idle(); + current->cpu = 0; /* * If SMP should be disabled, then really disable it! @@ -516,8 +554,8 @@ /* * Make sure we unmap all failed CPUs */ - if (ia64_cpu_to_sapicid[cpu] == -1) - printk("phys CPU#%d not responding - cannot use it.\n", cpu); + if (ia64_cpu_to_sapicid[cpucount] == -1) + printk("phys CPU#%d (0x%lx) not responding - cannot use it.\n", cpucount, sapicid); } smp_num_cpus = cpucount + 1; @@ -528,11 +566,11 @@ printk("Before bogomips.\n"); if (!cpucount) { - printk(KERN_ERR "Error: only one processor found.\n"); + printk(KERN_WARNING "Warning: only one processor found.\n"); } else { unsigned long bogosum = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) - if (cpu_online_map & (1<loops_per_jiffy; printk(KERN_INFO"Total of %d processors activated (%lu.%02lu BogoMIPS).\n", @@ -561,7 +599,7 @@ /* Tell SAL where to drop the AP's. */ ap_startup = (struct fptr *) start_ap; sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, - __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0); + __tpa(ap_startup->fp), __tpa(ap_startup->gp), 0, 0, 0, 0); if (sal_ret < 0) { printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n Forcing UP mode\n", ia64_sal_strerror(sal_ret)); @@ -569,3 +607,9 @@ smp_num_cpus = 1; } } + +/* Number of ticks we consider an idle tasks still cache-hot. + * For Itanium: with 1GB/s bandwidth we need 4ms to fill up 4MB L3 cache... + * So let's try 10 ticks. + */ +unsigned long cache_decay_ticks=10; diff -Nur linux-2.4.19/arch/ia64/kernel/sys_ia64.c linux-2.4.19-sgi211r3/arch/ia64/kernel/sys_ia64.c --- linux-2.4.19/arch/ia64/kernel/sys_ia64.c Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/sys_ia64.c Fri Apr 26 11:07:18 2002 @@ -2,8 +2,8 @@ * This file contains various system calls that have different calling * conventions on different platforms. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include #include @@ -201,15 +201,13 @@ if (len == 0) goto out; - /* don't permit mappings into unmapped space or the virtual page table of a region: */ + /* + * Don't permit mappings into unmapped space, the virtual page table of a region, + * or across a region boundary. Note: RGN_MAP_LIMIT is equal to 2^n-PAGE_SIZE + * (for some integer n <= 61) and len > 0. + */ roff = rgn_offset(addr); - if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) { - addr = -EINVAL; - goto out; - } - - /* don't permit mappings that would cross a region boundary: */ - if (rgn_index(addr) != rgn_index(addr + len)) { + if ((len > RGN_MAP_LIMIT) || (roff > (RGN_MAP_LIMIT - len))) { addr = -EINVAL; goto out; } diff -Nur linux-2.4.19/arch/ia64/kernel/time.c linux-2.4.19-sgi211r3/arch/ia64/kernel/time.c --- linux-2.4.19/arch/ia64/kernel/time.c Mon Feb 25 11:37:53 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/time.c Fri Feb 14 13:25:16 2003 @@ -15,15 +15,21 @@ #include #include #include +#include +#include #include -#include #include #include #include #include +#include -extern rwlock_t xtime_lock; +#ifdef CONFIG_IA64_SGI_SN +#include +#endif + +extern frlock_t xtime_lock; extern unsigned long wall_jiffies; extern unsigned long last_time_offset; @@ -33,29 +39,42 @@ #endif +#ifndef CONFIG_IA64_HAVE_SYNCHRONIZED_ITC +/* for gettimeoffset on platforms where the itc drifts */ +volatile unsigned long last_rtc_val; +volatile unsigned long last_itc_lost_usec; +#endif + +#ifdef CONFIG_IA64_SGI_SN1 +extern void synergy_perf_update(int); +#endif + + static void do_profile (unsigned long ip) { extern unsigned long prof_cpu_mask; extern char _stext; + if (!prof_buffer) + return; + if (!((1UL << smp_processor_id()) & prof_cpu_mask)) return; - if (prof_buffer && current->pid) { - ip -= (unsigned long) &_stext; - ip >>= prof_shift; - /* - * Don't ignore out-of-bounds IP values silently, put them into the last - * histogram slot, so if present, they will show up as a sharp peak. - */ - if (ip > prof_len - 1) - ip = prof_len - 1; + ip -= (unsigned long) &_stext; + ip >>= prof_shift; + /* + * Don't ignore out-of-bounds IP values silently, put them into the last + * histogram slot, so if present, they will show up as a sharp peak. + */ + if (ip > prof_len - 1) + ip = prof_len - 1; - atomic_inc((atomic_t *) &prof_buffer[ip]); - } + atomic_inc((atomic_t *) &prof_buffer[ip]); } +#ifdef CONFIG_IA64_HAVE_SYNCHRONIZED_ITC /* * Return the number of micro-seconds that elapsed since the last update to jiffy. The * xtime_lock must be at least read-locked when calling this routine. @@ -65,7 +84,6 @@ { unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; unsigned long now, last_tick; -# define time_keeper_id 0 /* smp_processor_id() of time-keeper */ last_tick = (cpu_data(time_keeper_id)->itm_next - (lost + 1)*cpu_data(time_keeper_id)->itm_delta); @@ -81,11 +99,12 @@ elapsed_cycles = now - last_tick; return (elapsed_cycles*local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; } +#endif /* CONFIG_IA64_HAVE_SYNCHRONIZED_ITC */ void do_settimeofday (struct timeval *tv) { - write_lock_irq(&xtime_lock); + fr_write_lock_irq(&xtime_lock); { /* * This is revolting. We need to set "xtime" correctly. However, the value @@ -107,34 +126,26 @@ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; } - write_unlock_irq(&xtime_lock); + fr_write_unlock_irq(&xtime_lock); } void do_gettimeofday (struct timeval *tv) { - unsigned long flags, usec, sec, old; + unsigned long seq, usec, sec, old; - read_lock_irqsave(&xtime_lock, flags); - { + do { + seq = fr_read_begin(&xtime_lock); usec = gettimeoffset(); - - /* - * Ensure time never goes backwards, even when ITC on different CPUs are - * not perfectly synchronized. - */ - do { - old = last_time_offset; - if (usec <= old) { - usec = old; - break; - } - } while (cmpxchg(&last_time_offset, old, usec) != old); - + { + unsigned long lost = jiffies - wall_jiffies; + if (lost) + usec += lost * (1000000 / HZ); + } + sec = xtime.tv_sec; usec += xtime.tv_usec; - } - read_unlock_irqrestore(&xtime_lock, flags); + } while (seq != fr_read_end(&xtime_lock)); while (usec >= 1000000) { usec -= 1000000; @@ -149,6 +160,31 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long new_itm; + int cpu = smp_processor_id(); + +#ifdef CONFIG_IA64_SGI_SN + + if (!pda.hb_count--) { + pda.hb_count = HZ/2; + set_led_bits(pda.hb_state ^= LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT); + } + +#ifdef CONFIG_IA64_SGI_SN2 + if (pda.pio_shub_war_cam_addr) + *pda.pio_shub_war_cam_addr = 0x8000000000000010UL; +#endif + +#ifdef BUS_INT_WAR + { + extern void sn_irq_poll(int, int); + sn_irq_poll(cpu, 1); + } +#endif + +#ifdef CONFIG_IA64_SGI_SN1 + synergy_perf_update(cpu); +#endif /* CONFIG_IA64_SGI_SN1 */ +#endif /* CONFIG_IA64_SGI_SN */ new_itm = local_cpu_data->itm_next; @@ -170,17 +206,23 @@ #endif new_itm += local_cpu_data->itm_delta; - if (smp_processor_id() == 0) { + if (cpu == 0) { /* * Here we are in the timer irq handler. We have irqs locally * disabled, but we don't know if the timer_bh is running on * another CPU. We need to avoid to SMP race by acquiring the * xtime_lock. */ - write_lock(&xtime_lock); + fr_write_lock(&xtime_lock); +#ifndef CONFIG_IA64_HAVE_SYNCHRONIZED_ITC + /* Used by gettimeoffset on 'drifty' platforms */ + last_rtc_val = get_cycles(); + last_itc_lost_usec = ((ia64_get_itc()- (new_itm - local_cpu_data->itm_delta)) * + local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; +#endif do_timer(regs); local_cpu_data->itm_next = new_itm; - write_unlock(&xtime_lock); + fr_write_unlock(&xtime_lock); } else local_cpu_data->itm_next = new_itm; @@ -206,7 +248,7 @@ /* * Encapsulate access to the itm structure for SMP. */ -void __init +void ia64_cpu_local_tick (void) { int cpu = smp_processor_id(); @@ -295,3 +337,9 @@ efi_gettimeofday((struct timeval *) &xtime); ia64_init_itm(); } + +void __init ia64_disable_timer(void) +{ + ia64_set_itv(IA64_TIMER_VECTOR | IA64_TIMER_MASK); +} + diff -Nur linux-2.4.19/arch/ia64/kernel/traps.c linux-2.4.19-sgi211r3/arch/ia64/kernel/traps.c --- linux-2.4.19/arch/ia64/kernel/traps.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/traps.c Thu Dec 5 22:23:36 2002 @@ -33,11 +33,15 @@ #include #include #include /* For unblank_screen() */ +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include #include #include +#include #include @@ -48,10 +52,15 @@ void __init trap_init (void) { - printk("fpswa interface at %lx\n", ia64_boot_param->fpswa); - if (ia64_boot_param->fpswa) + if (ia64_boot_param->fpswa) { /* FPSWA fixup: make the interface pointer a kernel virtual address: */ fpswa_interface = __va(ia64_boot_param->fpswa); + printk("FPSWA interface at 0x%lx, revision %d.%d\n", + ia64_boot_param->fpswa, + fpswa_interface->revision >> 16, + fpswa_interface->revision & 0xffff); + } else + printk("No FPSWA interface\n"); } /* @@ -114,6 +123,13 @@ bust_spinlocks(0); die.lock_owner = -1; spin_unlock_irq(&die.lock); +#ifdef CONFIG_KDB + (void)kdb(KDB_REASON_OOPS, err, regs); +#endif /* CONFIG_KDB */ + + if (die.lock_owner_depth < 3) { + dump((char *)str, regs); + } do_exit(SIGSEGV); } @@ -138,6 +154,7 @@ switch (break_num) { case 0: /* unknown error */ + die_if_kernel("bad break", regs, break_num); sig = SIGILL; code = ILL_ILLOPC; break; @@ -185,6 +202,10 @@ sig = SIGSEGV; code = __SEGV_PSTKOVF; break; + case 0x3f000 ... 0x3ffff: /* bundle-update in progress */ + sig = SIGILL; code = __ILL_BNDMOD; + break; + default: if (break_num < 0x40000 || break_num > 0x100000) die_if_kernel("Bad break", regs, break_num); @@ -192,6 +213,14 @@ if (break_num < 0x80000) { sig = SIGILL; code = __ILL_BREAK; } else { +#ifdef CONFIG_KDB + if (break_num == KDB_BREAK_ENTER && + kdb(KDB_REASON_ENTER, break_num, regs)) + return; /* kdb handled it */ + if (break_num == KDB_BREAK_BREAK && + kdb(KDB_REASON_BREAK, break_num, regs)) + return; /* kdb handled it */ +#endif /* CONFIG_KDB */ sig = SIGTRAP; code = TRAP_BRKPT; } } @@ -213,7 +242,8 @@ { struct pt_regs *regs = (struct pt_regs *) &stack; - printk("\n", regs->r15, arg0, arg1, arg2, arg3); + printk("%s(%d): \n", current->comm, current->pid, + regs->r15, arg0, arg1, arg2, arg3); return -ENOSYS; } @@ -242,9 +272,9 @@ if (fpu_owner) ia64_flush_fph(fpu_owner); - ia64_set_fpu_owner(current); } #endif /* !CONFIG_SMP */ + ia64_set_fpu_owner(current); if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { __ia64_load_fpu(current->thread.fph); psr->mfh = 0; @@ -429,7 +459,7 @@ unsigned long code, error = isr; struct siginfo siginfo; char buf[128]; - int result; + int result, sig; static const char *reason[] = { "IA-64 Illegal Operation fault", "IA-64 Privileged Operation fault", @@ -441,30 +471,14 @@ "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" }; -#if 0 - /* this is for minimal trust debugging; yeah this kind of stuff is useful at times... */ - - if (vector != 25) { - static unsigned long last_time; - static char count; - unsigned long n = vector; - char buf[32], *cp; - - if (jiffies - last_time > 5*HZ) - count = 0; - - if (count++ < 5) { - last_time = jiffies; - cp = buf + sizeof(buf); - *--cp = '\0'; - while (n) { - *--cp = "0123456789abcdef"[n & 0xf]; - n >>= 4; - } - printk("<0x%s>", cp); - } + if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { + /* + * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel + * the lfetch. + */ + ia64_psr(regs)->ed = 1; + return; } -#endif switch (vector) { case 24: /* General Exception */ @@ -489,6 +503,30 @@ break; case 26: /* NaT Consumption */ + if (user_mode(regs)) { + if (((isr >> 4) & 0xf) == 2) { + /* NaT page consumption */ + sig = SIGSEGV; + code = SEGV_ACCERR; + } else { + /* register NaT consumption */ + sig = SIGILL; + code = ILL_ILLOPN; + } + siginfo.si_signo = sig; + siginfo.si_code = code; + siginfo.si_errno = 0; + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_imm = vector; + siginfo.si_flags = __ISR_VALID; + siginfo.si_isr = isr; + force_sig_info(sig, &siginfo, current); + return; + } else if (done_with_exception(regs)) + return; + sprintf(buf, "NaT consumption"); + break; + case 31: /* Unsupported Data Reference */ if (user_mode(regs)) { siginfo.si_signo = SIGILL; @@ -501,7 +539,7 @@ force_sig_info(SIGILL, &siginfo, current); return; } - sprintf(buf, (vector == 26) ? "NaT consumption" : "Unsupported data reference"); + sprintf(buf, "Unsupported data reference"); break; case 29: /* Debug */ @@ -518,16 +556,19 @@ if (ia64_psr(regs)->is == 0) ifa = regs->cr_iip; #endif - siginfo.si_addr = (void *) ifa; break; - case 35: siginfo.si_code = TRAP_BRANCH; break; - case 36: siginfo.si_code = TRAP_TRACE; break; + case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; + case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break; } +#ifdef CONFIG_KDB + if (!user_mode(regs) && kdb(KDB_REASON_DEBUG, vector, regs)) + return; /* kdb handled this */ +#endif /* CONFIG_KDB */ siginfo.si_signo = SIGTRAP; siginfo.si_errno = 0; siginfo.si_flags = 0; siginfo.si_isr = 0; - siginfo.si_addr = 0; + siginfo.si_addr = (void *) ifa; siginfo.si_imm = 0; force_sig_info(SIGTRAP, &siginfo, current); return; diff -Nur linux-2.4.19/arch/ia64/kernel/unaligned.c linux-2.4.19-sgi211r3/arch/ia64/kernel/unaligned.c --- linux-2.4.19/arch/ia64/kernel/unaligned.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/unaligned.c Thu Dec 12 15:58:38 2002 @@ -5,6 +5,10 @@ * Stephane Eranian * David Mosberger-Tang * + * 2002/12/09 Fix rotating register handling (off-by-1 error, missing fr-rotation). Fix + * get_rse_reg() to not leak kernel bits to user-level (reading an out-of-frame + * stacked register returns an undefined value; it does NOT trigger a + * "rsvd register fault"). * 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops. * 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes. * 2001/01/17 Add support emulation of unaligned kernel accesses. @@ -275,6 +279,15 @@ # undef F } +static inline unsigned long +rotate_reg (unsigned long sor, unsigned long rrb, unsigned long reg) +{ + reg += rrb; + if (reg >= sor) + reg -= sor; + return reg; +} + static void set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) { @@ -286,26 +299,22 @@ long sof = (regs->cr_ifs) & 0x7f; long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; - long ridx; - - if ((r1 - 32) > sor) - ridx = -sof + (r1 - 32); - else if ((r1 - 32) < (sor - rrb_gr)) - ridx = -sof + (r1 - 32) + rrb_gr; - else - ridx = -sof + (r1 - 32) - (sor - rrb_gr); - - DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", - r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); + long ridx = r1 - 32; - if ((r1 - 32) >= sof) { + if (ridx >= sof) { /* this should never happen, as the "rsvd register fault" has higher priority */ DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof); return; } + if (ridx < sor) + ridx = rotate_reg(sor, rrb_gr, ridx); + + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); + on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ rnat_addr = ia64_rse_rnat_addr(addr); @@ -333,7 +342,7 @@ bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, ridx + sof); + addr = ia64_rse_skip_regs(bsp, ridx); DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); @@ -367,26 +376,22 @@ long sof = (regs->cr_ifs) & 0x7f; long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; - long ridx; + long ridx = r1 - 32; - if ((r1 - 32) > sor) - ridx = -sof + (r1 - 32); - else if ((r1 - 32) < (sor - rrb_gr)) - ridx = -sof + (r1 - 32) + rrb_gr; - else - ridx = -sof + (r1 - 32) - (sor - rrb_gr); + if (ridx >= sof) { + /* read of out-of-frame register returns an undefined value; 0 in our case. */ + DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof); + goto fail; + } + + if (ridx < sor) + ridx = rotate_reg(sor, rrb_gr, ridx); DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); - if ((r1 - 32) >= sof) { - /* this should never happen, as the "rsvd register fault" has higher priority */ - DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof); - return; - } - on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ *val = *addr; @@ -406,13 +411,13 @@ */ if (regs->r12 >= TASK_SIZE) { DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1); - return; + goto fail; } bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, ridx + sof); + addr = ia64_rse_skip_regs(bsp, ridx); DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); @@ -427,6 +432,13 @@ ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); *nat = (rnats & nat_mask) != 0; } + return; + + fail: + *val = 0; + if (nat) + *nat = 0; + return; } @@ -485,7 +497,16 @@ DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat); } -#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR) +/* + * Return the (rotated) index for floating point register REGNUM (REGNUM must be in the + * range from 32-127, result is in the range from 0-95. + */ +static inline unsigned long +fph_index (struct pt_regs *regs, long regnum) +{ + unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f; + return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR)); +} static void setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) @@ -506,7 +527,7 @@ */ if (regnum >= IA64_FIRST_ROTATING_FR) { ia64_sync_fph(current); - current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval; + current->thread.fph[fph_index(regs, regnum)] = *fpval; } else { /* * pt_regs or switch_stack ? @@ -565,7 +586,7 @@ */ if (regnum >= IA64_FIRST_ROTATING_FR) { ia64_flush_fph(current); - *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)]; + *fpval = current->thread.fph[fph_index(regs, regnum)]; } else { /* * f0 = 0.0, f1= 1.0. Those registers are constant and are thus @@ -650,7 +671,7 @@ * just in case. */ if (ld.x6_op == 1 || ld.x6_op == 3) { - printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__); + printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__); die_if_kernel("unaligned reference on specualtive load with register update\n", regs, 30); } @@ -1080,8 +1101,8 @@ * For this reason we keep this sanity check */ if (ld.x6_op == 1 || ld.x6_op == 3) - printk("%s %s: register update on speculative load pair, " - "error\n",KERN_ERR, __FUNCTION__); + printk(KERN_ERR "%s: register update on speculative load pair, error\n", + __FUNCTION__); setreg(ld.r3, ifa, 0, regs); } @@ -1304,11 +1325,7 @@ * handler into reading an arbitrary kernel addresses... */ if (!user_mode(regs)) { -#ifdef GAS_HAS_LOCAL_TAGS - fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); -#else - fix = search_exception_table(regs->cr_iip); -#endif + fix = SEARCH_EXCEPTION_TABLE(regs); } if (user_mode(regs) || fix.cont) { if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0) diff -Nur linux-2.4.19/arch/ia64/kernel/unwind.c linux-2.4.19-sgi211r3/arch/ia64/kernel/unwind.c --- linux-2.4.19/arch/ia64/kernel/unwind.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/unwind.c Sun Dec 15 22:09:43 2002 @@ -51,18 +51,24 @@ #define UNW_LOG_HASH_SIZE (UNW_LOG_CACHE_SIZE + 1) #define UNW_HASH_SIZE (1 << UNW_LOG_HASH_SIZE) -#define UNW_DEBUG 0 #define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */ -#if UNW_DEBUG - static long unw_debug_level = 255; -# define debug(level,format...) if (unw_debug_level > level) printk(format) -# define dprintk(format...) printk(format) -# define inline -#else -# define debug(level,format...) -# define dprintk(format...) -#endif +#ifdef UNW_DEBUG + static unsigned int unw_debug_level = UNW_DEBUG; + #ifdef CONFIG_KDB + #include + #define UNW_DEBUG_ON(n) (unw_debug_level >= n && !KDB_IS_RUNNING()) + #define UNW_DEBUG_PRINT(n, ...) if (UNW_DEBUG_ON(n)) kdb_printf(__VA_ARGS__) + #else /* !CONFIG_KDB */ + #define UNW_DEBUG_ON(n) unw_debug_level >= n + /* Do not code a printk level, not all debug lines end in newline */ + #define UNW_DEBUG_PRINT(n, ...) if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__) + #endif /* CONFIG_KDB */ + #define inline +#else /* !UNW_DEBUG */ + #define UNW_DEBUG_ON(n) 0 + #define UNW_DEBUG_PRINT(n, ...) +#endif /* UNW_DEBUG */ #if UNW_STATS # define STAT(x...) x @@ -111,7 +117,7 @@ /* script cache: */ struct unw_script cache[UNW_CACHE_SIZE]; -# if UNW_DEBUG +# ifdef UNW_DEBUG const char *preg_name[UNW_NUM_REGS]; # endif # if UNW_STATS @@ -190,7 +196,7 @@ struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8, }, hash : { [0 ... UNW_HASH_SIZE - 1] = -1 }, -#if UNW_DEBUG +#ifdef UNW_DEBUG preg_name: { "pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp", "r4", "r5", "r6", "r7", @@ -223,19 +229,31 @@ else if (reg <= 31) off = struct_offset(struct pt_regs, r16) + 8*(reg - 16); else - dprintk("unwind: bad scratch reg r%lu\n", reg); + UNW_DEBUG_PRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg); return off; } +static void +dump_info_pt(struct unw_frame_info *info, const char *func) +{ + /* WAR for no struct pt_regs, may be caused by bad unwind data. KAO */ + if (!info->pt) { + UNW_DEBUG_PRINT(0, "unwind.%s: sp 0x%lx pt 0x%lx, set to 0x%lx\n", func, info->sp, info->pt, info->sp - 16); + info->pt = info->sp - 16; + } + else { + UNW_DEBUG_PRINT(3, "unwind.%s: sp 0x%lx pt 0x%lx\n", func, info->sp, info->pt); + } +} + int unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write) { unsigned long *addr, *nat_addr, nat_mask = 0, dummy_nat; struct unw_ireg *ireg; - struct pt_regs *pt; if ((unsigned) regnum - 1 >= 127) { - dprintk("unwind: trying to access non-existent r%u\n", regnum); + UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent r%u\n", __FUNCTION__, regnum); return -1; } @@ -280,8 +298,9 @@ if ((unsigned long) addr < info->regstk.limit || (unsigned long) addr >= info->regstk.top) { - dprintk("unwind: %p outside of regstk " - "[0x%lx-0x%lx)\n", (void *) addr, + UNW_DEBUG_PRINT(0, "unwind.%s: %p outside of regstk " + "[0x%lx-0x%lx)\n", + __FUNCTION__, (void *) addr, info->regstk.limit, info->regstk.top); return -1; @@ -298,11 +317,8 @@ } } else { /* access a scratch register */ - if (info->flags & UNW_FLAG_INTERRUPT_FRAME) - pt = (struct pt_regs *) info->psp - 1; - else - pt = (struct pt_regs *) info->sp - 1; - addr = (unsigned long *) ((long) pt + pt_regs_off(regnum)); + dump_info_pt(info, __FUNCTION__); + addr = (unsigned long *) (info->pt + pt_regs_off(regnum)); if (info->pri_unat_loc) nat_addr = info->pri_unat_loc; else @@ -316,7 +332,7 @@ if ((unsigned long) addr < info->regstk.limit || (unsigned long) addr >= info->regstk.top) { - dprintk("unwind: ignoring attempt to access register outside of rbs\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: ignoring attempt to access register outside of rbs\n", __FUNCTION__); return -1; } if ((unsigned long) nat_addr >= info->regstk.top) @@ -348,10 +364,8 @@ unsigned long *addr; struct pt_regs *pt; - if (info->flags & UNW_FLAG_INTERRUPT_FRAME) - pt = (struct pt_regs *) info->psp - 1; - else - pt = (struct pt_regs *) info->sp - 1; + dump_info_pt(info, __FUNCTION__); + pt = (struct pt_regs *)info->pt; switch (regnum) { /* scratch: */ case 0: addr = &pt->b0; break; @@ -366,7 +380,7 @@ break; default: - dprintk("unwind: trying to access non-existent b%u\n", regnum); + UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent b%u\n", __FUNCTION__, regnum); return -1; } if (write) @@ -383,14 +397,12 @@ struct pt_regs *pt; if ((unsigned) (regnum - 2) >= 126) { - dprintk("unwind: trying to access non-existent f%u\n", regnum); + UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent f%u\n", __FUNCTION__, regnum); return -1; } - if (info->flags & UNW_FLAG_INTERRUPT_FRAME) - pt = (struct pt_regs *) info->psp - 1; - else - pt = (struct pt_regs *) info->sp - 1; + dump_info_pt(info, __FUNCTION__); + pt = (struct pt_regs *)info->pt; if (regnum <= 5) { addr = *(&info->f2_loc + (regnum - 2)); @@ -428,10 +440,8 @@ unsigned long *addr; struct pt_regs *pt; - if (info->flags & UNW_FLAG_INTERRUPT_FRAME) - pt = (struct pt_regs *) info->psp - 1; - else - pt = (struct pt_regs *) info->sp - 1; + dump_info_pt(info, __FUNCTION__); + pt = (struct pt_regs *)info->pt; switch (regnum) { case UNW_AR_BSP: @@ -495,7 +505,7 @@ break; default: - dprintk("unwind: trying to access non-existent ar%u\n", regnum); + UNW_DEBUG_PRINT(0, "unwind.%s: trying to access non-existent ar%u\n", __FUNCTION__, regnum); return -1; } @@ -532,7 +542,7 @@ rs = alloc_reg_state(); if (!rs) { - printk("unwind: cannot stack reg state!\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: cannot stack reg state!\n", __FUNCTION__); return; } memcpy(rs, &sr->curr, sizeof(*rs)); @@ -545,7 +555,7 @@ struct unw_reg_state *rs = sr->curr.next; if (!rs) { - printk("unwind: stack underflow!\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: stack underflow!\n", __FUNCTION__); return; } memcpy(&sr->curr, rs, sizeof(*rs)); @@ -561,7 +571,7 @@ while (rs) { copy = alloc_reg_state(); if (!copy) { - printk ("unwind.dup_state_stack: out of memory\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: out of memory\n", __FUNCTION__); return NULL; } memcpy(copy, rs, sizeof(*copy)); @@ -612,7 +622,7 @@ default: break; } - dprintk("unwind: bad abreg=0x%x\n", abreg); + UNW_DEBUG_PRINT(0, "unwind.%s: bad abreg=0x%x\n", __FUNCTION__, abreg); return UNW_REG_LC; } @@ -634,8 +644,8 @@ for (reg = hi; reg >= lo; --reg) { if (reg->where == UNW_WHERE_SPILL_HOME) { reg->where = UNW_WHERE_PSPREL; - reg->val = 0x10 - *offp; - *offp += regsize; + *offp -= regsize; + reg->val = *offp; } } } @@ -652,7 +662,7 @@ return; } } - dprintk("unwind: excess spill!\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: excess spill!\n", __FUNCTION__); } static inline void @@ -765,10 +775,13 @@ static inline void desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr) { - if (abi == 0 && context == 'i') + if (abi == 0 && context == 'i') { sr->flags |= UNW_FLAG_INTERRUPT_FRAME; + UNW_DEBUG_PRINT(3, "unwind.%s: interrupt frame\n", __FUNCTION__); + } else - dprintk("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context); + UNW_DEBUG_PRINT(0, "unwind%s: ignoring unwabi(abi=0x%x,context=0x%x)\n", + __FUNCTION__, abi, context); } static inline void @@ -814,7 +827,8 @@ } for (i = 0; i < 20; ++i) { if ((frmask & 1) != 0) { - set_reg(sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, + int base = (i < 4) ? UNW_REG_F2 : UNW_REG_F16 - 4; + set_reg(sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME, sr->region_start + sr->region_len - 1, 0); sr->any_spills = 1; } @@ -950,7 +964,7 @@ return; } } - printk("unwind: failed to find state labeled 0x%lx\n", label); + UNW_DEBUG_PRINT(0, "unwind.%s: failed to find state labeled 0x%lx\n", __FUNCTION__, label); } static inline void @@ -960,7 +974,7 @@ ls = alloc_labeled_state(); if (!ls) { - printk("unwind.desc_label_state(): out of memory\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: out of memory\n", __FUNCTION__); return; } ls->label = label; @@ -1054,7 +1068,7 @@ r->val = 4*spoff; } -#define UNW_DEC_BAD_CODE(code) printk("unwind: unknown code 0x%02x\n", code); +#define UNW_DEC_BAD_CODE(code) UNW_DEBUG_PRINT(0, "unwind.%s: unknown code 0x%02x\n", __FUNCTION__, code); /* * region headers: @@ -1133,6 +1147,8 @@ struct unw_script *script = unw.cache + info->hint; unsigned short index; unsigned long ip, pr; + if (UNW_DEBUG_ON(0)) + return 0; /* Always regenerate scripts in debug mode */ STAT(++unw.stat.cache.lookups); @@ -1258,8 +1274,8 @@ script_emit (struct unw_script *script, struct unw_insn insn) { if (script->count >= UNW_MAX_SCRIPT_LEN) { - dprintk("unwind: script exceeds maximum size of %u instructions!\n", - UNW_MAX_SCRIPT_LEN); + UNW_DEBUG_PRINT(0, "unwind.%s: script exceeds maximum size of %u instructions!\n", + __FUNCTION__, UNW_MAX_SCRIPT_LEN); return; } script->insn[script->count++] = insn; @@ -1300,7 +1316,7 @@ break; default: - dprintk("unwind: don't know how to emit nat info for where = %u\n", r->where); + UNW_DEBUG_PRINT(0, "unwind.%s: don't know how to emit nat info for where = %u\n", __FUNCTION__, r->where); return; } insn.opc = opc; @@ -1337,8 +1353,9 @@ } val = unw.preg_index[UNW_REG_R4 + (rval - 4)]; } else { - opc = UNW_INSN_ADD_SP; - val = -sizeof(struct pt_regs) + pt_regs_off(rval); + /* register got spilled to a scratch register */ + opc = UNW_INSN_MOVE_SCRATCH; + val = pt_regs_off(rval); } break; @@ -1348,12 +1365,11 @@ else if (rval >= 16 && rval <= 31) val = unw.preg_index[UNW_REG_F16 + (rval - 16)]; else { - opc = UNW_INSN_ADD_SP; - val = -sizeof(struct pt_regs); + opc = UNW_INSN_MOVE_SCRATCH; if (rval <= 9) - val += struct_offset(struct pt_regs, f6) + 16*(rval - 6); + val = struct_offset(struct pt_regs, f6) + 16*(rval - 6); else - dprintk("unwind: kernel may not touch f%lu\n", rval); + UNW_DEBUG_PRINT(0, "unwind.%s: kernel may not touch f%lu\n", __FUNCTION__, rval); } break; @@ -1361,14 +1377,13 @@ if (rval >= 1 && rval <= 5) val = unw.preg_index[UNW_REG_B1 + (rval - 1)]; else { - opc = UNW_INSN_ADD_SP; - val = -sizeof(struct pt_regs); + opc = UNW_INSN_MOVE_SCRATCH; if (rval == 0) - val += struct_offset(struct pt_regs, b0); + val = struct_offset(struct pt_regs, b0); else if (rval == 6) - val += struct_offset(struct pt_regs, b6); + val = struct_offset(struct pt_regs, b6); else - val += struct_offset(struct pt_regs, b7); + val = struct_offset(struct pt_regs, b7); } break; @@ -1381,7 +1396,7 @@ break; default: - dprintk("unwind: register %u has unexpected `where' value of %u\n", i, r->where); + UNW_DEBUG_PRINT(0, "unwind%s: register %u has unexpected `where' value of %u\n", __FUNCTION__, i, r->where); break; } insn.opc = opc; @@ -1454,9 +1469,10 @@ r->when = UNW_WHEN_NEVER; sr.pr_val = info->pr; + UNW_DEBUG_PRINT(3, "unwind.%s: ip 0x%lx\n", __FUNCTION__, ip); script = script_new(ip); if (!script) { - dprintk("unwind: failed to create unwind script\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: failed to create unwind script\n", __FUNCTION__); STAT(unw.stat.script.build_time += ia64_get_itc() - start); return 0; } @@ -1474,8 +1490,8 @@ } if (!e) { /* no info, return default unwinder (leaf proc, no mem stack, no saved regs) */ - dprintk("unwind: no unwind info for ip=0x%lx (prev ip=0x%lx)\n", ip, - unw.cache[info->prev_script].ip); + UNW_DEBUG_PRINT(1, "unwind.%s: no unwind info for ip=0x%lx (prev ip=0x%lx)\n", + __FUNCTION__, ip, unw.cache[info->prev_script].ip); sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; sr.curr.reg[UNW_REG_RP].when = -1; sr.curr.reg[UNW_REG_RP].val = 0; @@ -1523,26 +1539,28 @@ sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; sr.curr.reg[UNW_REG_RP].when = -1; sr.curr.reg[UNW_REG_RP].val = sr.return_link_reg; + UNW_DEBUG_PRINT(1, "unwind.%s: using default for rp at ip=0x%lx where=%d val=0x%lx\n", + __FUNCTION__, ip, sr.curr.reg[UNW_REG_RP].where, sr.curr.reg[UNW_REG_RP].val); } -#if UNW_DEBUG - printk("unwind: state record for func 0x%lx, t=%u:\n", - table->segment_base + e->start_offset, sr.when_target); +#ifdef UNW_DEBUG + UNW_DEBUG_PRINT(1, "unwind.%s: state record for func 0x%lx, t=%u:\n", + __FUNCTION__, table->segment_base + e->start_offset, sr.when_target); for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) { if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) { - printk(" %s <- ", unw.preg_name[r - sr.curr.reg]); + UNW_DEBUG_PRINT(1, " %s <- ", unw.preg_name[r - sr.curr.reg]); switch (r->where) { - case UNW_WHERE_GR: printk("r%lu", r->val); break; - case UNW_WHERE_FR: printk("f%lu", r->val); break; - case UNW_WHERE_BR: printk("b%lu", r->val); break; - case UNW_WHERE_SPREL: printk("[sp+0x%lx]", r->val); break; - case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", r->val); break; + case UNW_WHERE_GR: UNW_DEBUG_PRINT(1, "r%lu", r->val); break; + case UNW_WHERE_FR: UNW_DEBUG_PRINT(1, "f%lu", r->val); break; + case UNW_WHERE_BR: UNW_DEBUG_PRINT(1, "b%lu", r->val); break; + case UNW_WHERE_SPREL: UNW_DEBUG_PRINT(1, "[sp+0x%lx]", r->val); break; + case UNW_WHERE_PSPREL: UNW_DEBUG_PRINT(1, "[psp+0x%lx]", r->val); break; case UNW_WHERE_NONE: - printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val); + UNW_DEBUG_PRINT(1, "%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val); break; - default: printk("BADWHERE(%d)", r->where); break; + default: UNW_DEBUG_PRINT(1, "BADWHERE(%d)", r->where); break; } - printk("\t\t%d\n", r->when); + UNW_DEBUG_PRINT(1, "\t\t%d\n", r->when); } } #endif @@ -1640,6 +1658,18 @@ s[dst] = s[val]; break; + case UNW_INSN_MOVE_SCRATCH: + if (state->pt) { + dump_info_pt(state, __FUNCTION__); + UNW_DEBUG_PRINT(6, "unwind.%s: dst %ld val %ld\n", __FUNCTION__, dst, val); + s[dst] = state->pt+val; + } + else { + s[dst] = 0; + UNW_DEBUG_PRINT(0, "unwind.%s: no state->pt, dst=%ld, val=%ld\n", __FUNCTION__, dst, val); + } + break; + case UNW_INSN_MOVE_STACKED: s[dst] = (unsigned long) ia64_rse_skip_regs((unsigned long *)state->bsp, val); @@ -1665,11 +1695,11 @@ break; case UNW_INSN_LOAD: -#if UNW_DEBUG +#ifdef UNW_DEBUG if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0 || s[val] < TASK_SIZE) { - debug(1, "unwind: rejecting bad psp=0x%lx\n", s[val]); + UNW_DEBUG_PRINT(0, "unwind.%s: rejecting bad psp=0x%lx\n", __FUNCTION__, s[val]); break; } #endif @@ -1702,7 +1732,8 @@ if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { /* don't let obviously bad addresses pollute the cache */ - debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip); + /* FIXME: should really be level 0 but it occurs too often. KAO */ + UNW_DEBUG_PRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip); info->rp_loc = 0; return -1; } @@ -1711,8 +1742,8 @@ if (!scr) { scr = build_script(info); if (!scr) { - dprintk("unwind: failed to locate/build unwind script for ip %lx\n", - info->ip); + UNW_DEBUG_PRINT(0, "unwind.%s: failed to locate/build unwind script for ip %lx\n", + __FUNCTION__, info->ip); return -1; } have_write_lock = 1; @@ -1745,7 +1776,8 @@ /* restore the ip */ if (!info->rp_loc) { - debug(1, "unwind: failed to locate return link (ip=0x%lx)!\n", info->ip); + /* FIXME: should really be level 0 but it occurs too often. KAO */ + UNW_DEBUG_PRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n", __FUNCTION__, info->ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } @@ -1755,14 +1787,14 @@ * We don't have unwind info for the gate page, so we consider that part * of user-space for the purpose of unwinding. */ - debug(1, "unwind: reached user-space (ip=0x%lx)\n", ip); + UNW_DEBUG_PRINT(2, "unwind.%s: reached user-space (ip=0x%lx)\n", __FUNCTION__, ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } /* restore the cfm: */ if (!info->pfs_loc) { - dprintk("unwind: failed to locate ar.pfs!\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } @@ -1772,16 +1804,18 @@ pr = info->pr; num_regs = 0; if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) { + info->pt = info->sp + 16; if ((pr & (1UL << pNonSys)) != 0) num_regs = *info->cfm_loc & 0x7f; /* size of frame */ info->pfs_loc = - (unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs)); + (unsigned long *) (info->pt + struct_offset(struct pt_regs, ar_pfs)); + UNW_DEBUG_PRINT(3, "unwind.%s: interrupt_frame pt 0x%lx\n", __FUNCTION__, info->pt); } else num_regs = (*info->cfm_loc >> 7) & 0x7f; /* size of locals */ info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs); if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) { - dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n", - info->bsp, info->regstk.limit, info->regstk.top); + UNW_DEBUG_PRINT(0, "unwind.%s: bsp (0x%lx) out of range [0x%lx-0x%lx]\n", + __FUNCTION__, info->bsp, info->regstk.limit, info->regstk.top); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } @@ -1789,14 +1823,14 @@ /* restore the sp: */ info->sp = info->psp; if (info->sp < info->memstk.top || info->sp > info->memstk.limit) { - dprintk("unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n", - info->sp, info->memstk.top, info->memstk.limit); + UNW_DEBUG_PRINT(0, "unwind.%s: sp (0x%lx) out of range [0x%lx-0x%lx]\n", + __FUNCTION__, info->sp, info->memstk.top, info->memstk.limit); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } if (info->ip == prev_ip && info->sp == prev_sp && info->bsp == prev_bsp) { - dprintk("unwind: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n", ip); + UNW_DEBUG_PRINT(0, "unwind.%s: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n", __FUNCTION__, ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } @@ -1820,7 +1854,7 @@ while (unw_unwind(info) >= 0) { if (unw_get_rp(info, &ip) < 0) { unw_get_ip(info, &ip); - dprintk("unwind: failed to read return pointer (ip=0x%lx)\n", ip); + UNW_DEBUG_PRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n", __FUNCTION__, ip); return -1; } /* @@ -1831,7 +1865,7 @@ return 0; } unw_get_ip(info, &ip); - dprintk("unwind: failed to unwind to user-level (ip=0x%lx)\n", ip); + UNW_DEBUG_PRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip); return -1; } @@ -1872,11 +1906,30 @@ info->task = t; info->sw = sw; info->sp = info->psp = (unsigned long) (sw + 1) - 16; + info->pt = 0; info->cfm_loc = &sw->ar_pfs; sol = (*info->cfm_loc >> 7) & 0x7f; info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); info->ip = sw->b0; info->pr = sw->pr; + UNW_DEBUG_PRINT(3, + "unwind.%s\n" + " rbslimit 0x%lx\n" + " rbstop 0x%lx\n" + " stklimit 0x%lx\n" + " stktop 0x%lx\n" + " task 0x%lx\n" + " sw 0x%lx\n", + __FUNCTION__, rbslimit, rbstop, stklimit, stktop, + (unsigned long)(info->task), + (unsigned long)(info->sw)); + UNW_DEBUG_PRINT(3, + " sp/psp 0x%lx\n" + " sol 0x%lx\n" + " bsp 0x%lx\n" + " ip 0x%lx\n" + " pr 0x%lx\n", + info->sp, sol, info->bsp, info->ip, info->pr); find_save_locs(info); STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); @@ -1887,6 +1940,7 @@ { struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16); + UNW_DEBUG_PRINT(1, "unwind.%s\n", __FUNCTION__); unw_init_frame_info(info, t, sw); } @@ -1914,7 +1968,7 @@ unsigned long flags; if (end - start <= 0) { - dprintk("unwind: ignoring attempt to insert empty unwind table\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: ignoring attempt to insert empty unwind table\n", __FUNCTION__); return 0; } @@ -1944,13 +1998,13 @@ long index; if (!handle) { - dprintk("unwind: ignoring attempt to remove non-existent unwind table\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: ignoring attempt to remove non-existent unwind table\n", __FUNCTION__); return; } table = handle; if (table == &unw.kernel_table) { - dprintk("unwind: sorry, freeing the kernel's unwind table is a no-can-do!\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: sorry, freeing the kernel's unwind table is a no-can-do!\n", __FUNCTION__); return; } @@ -1962,7 +2016,7 @@ if (prev->next == table) break; if (!prev) { - dprintk("unwind: failed to find unwind table %p\n", (void *) table); + UNW_DEBUG_PRINT(0, "unwind.%s: failed to find unwind table %p\n", __FUNCTION__, (void *) table); spin_unlock_irqrestore(&unw.lock, flags); return; } @@ -2012,7 +2066,7 @@ unw.gate_table = alloc_bootmem(size); if (!unw.gate_table) { unw.gate_table_size = 0; - printk("unwind: unable to create unwind data for gate page!\n"); + UNW_DEBUG_PRINT(0, "unwind.%s: unable to create unwind data for gate page!\n", __FUNCTION__); return; } unw.gate_table_size = size; diff -Nur linux-2.4.19/arch/ia64/kernel/unwind_i.h linux-2.4.19-sgi211r3/arch/ia64/kernel/unwind_i.h --- linux-2.4.19/arch/ia64/kernel/unwind_i.h Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/kernel/unwind_i.h Fri Dec 13 13:38:05 2002 @@ -103,7 +103,7 @@ unsigned int in_body : 1; /* are we inside a body (as opposed to a prologue)? */ unsigned long flags; /* see UNW_FLAG_* in unwind.h */ - u8 *imask; /* imask of of spill_mask record or NULL */ + u8 *imask; /* imask of spill_mask record or NULL */ unsigned long pr_val; /* predicate values */ unsigned long pr_mask; /* predicate mask */ long spill_offset; /* psp-relative offset for spill base */ @@ -137,7 +137,8 @@ UNW_INSN_SETNAT_MEMSTK, /* s[dst+1].nat.type = MEMSTK; s[dst+1].nat.off = *s.pri_unat - s[dst] */ UNW_INSN_SETNAT_TYPE, /* s[dst+1].nat.type = val */ - UNW_INSN_LOAD /* s[dst] = *s[val] */ + UNW_INSN_LOAD, /* s[dst] = *s[val] */ + UNW_INSN_MOVE_SCRATCH, /* s[dst] = scratch reg "val" */ }; struct unw_insn { diff -Nur linux-2.4.19/arch/ia64/lib/Makefile linux-2.4.19-sgi211r3/arch/ia64/lib/Makefile --- linux-2.4.19/arch/ia64/lib/Makefile Tue Jul 31 10:30:08 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/Makefile Tue Aug 27 19:53:13 2002 @@ -11,10 +11,13 @@ obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \ - checksum.o clear_page.o csum_partial_copy.o copy_page.o \ - copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ - flush.o io.o do_csum.o \ - memcpy.o memset.o strlen.o swiotlb.o + checksum.o clear_page.o csum_partial_copy.o \ + clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ + flush.o ip_fast_csum.o io.o do_csum.o \ + memset.o strlen.o swiotlb.o + +obj-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o +obj-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff -Nur linux-2.4.19/arch/ia64/lib/checksum.c linux-2.4.19-sgi211r3/arch/ia64/lib/checksum.c --- linux-2.4.19/arch/ia64/lib/checksum.c Tue Jul 31 10:30:08 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/checksum.c Tue Aug 27 19:53:13 2002 @@ -66,15 +66,6 @@ extern unsigned long do_csum (const unsigned char *, long); /* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - */ -unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) -{ - return ~do_csum(iph, ihl*4); -} - -/* * computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) * diff -Nur linux-2.4.19/arch/ia64/lib/clear_page.S linux-2.4.19-sgi211r3/arch/ia64/lib/clear_page.S --- linux-2.4.19/arch/ia64/lib/clear_page.S Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/clear_page.S Fri Apr 26 11:07:18 2002 @@ -1,51 +1,77 @@ /* - * - * Optimized function to clear a page of memory. - * - * Inputs: - * in0: address of page - * - * Output: - * none - * - * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian - * Copyright (C) 1999-2001 David Mosberger-Tang + * Copyright (C) 1999-2002 Hewlett-Packard Co + * Stephane Eranian + * David Mosberger-Tang + * Copyright (C) 2002 Ken Chen * * 1/06/01 davidm Tuned for Itanium. + * 2/12/02 kchen Tuned for both Itanium and McKinley + * 3/08/02 davidm Some more tweaking */ +#include + #include #include +#ifdef CONFIG_ITANIUM +# define L3_LINE_SIZE 64 // Itanium L3 line size +# define PREFETCH_LINES 9 // magic number +#else +# define L3_LINE_SIZE 128 // McKinley L3 line size +# define PREFETCH_LINES 12 // magic number +#endif + #define saved_lc r2 -#define dst0 in0 +#define dst_fetch r3 #define dst1 r8 #define dst2 r9 #define dst3 r10 -#define dst_fetch r11 +#define dst4 r11 + +#define dst_last r31 GLOBAL_ENTRY(clear_page) .prologue .regstk 1,0,0,0 - mov r16 = PAGE_SIZE/64-1 // -1 = repeat/until - ;; + mov r16 = PAGE_SIZE/L3_LINE_SIZE-1 // main loop count, -1=repeat/until .save ar.lc, saved_lc mov saved_lc = ar.lc + .body - mov ar.lc = r16 - adds dst1 = 16, dst0 - adds dst2 = 32, dst0 - adds dst3 = 48, dst0 - adds dst_fetch = 512, dst0 + mov ar.lc = (PREFETCH_LINES - 1) + mov dst_fetch = in0 + adds dst1 = 16, in0 + adds dst2 = 32, in0 + ;; +.fetch: stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE + adds dst3 = 48, in0 // executing this multiple times is harmless + br.cloop.sptk.few .fetch + ;; + addl dst_last = (PAGE_SIZE - PREFETCH_LINES*L3_LINE_SIZE), dst_fetch + mov ar.lc = r16 // one L3 line per iteration + adds dst4 = 64, in0 + ;; +#ifdef CONFIG_ITANIUM + // Optimized for Itanium +1: stf.spill.nta [dst1] = f0, 64 + stf.spill.nta [dst2] = f0, 64 + cmp.lt p8,p0=dst_fetch, dst_last + ;; +#else + // Optimized for McKinley +1: stf.spill.nta [dst1] = f0, 64 + stf.spill.nta [dst2] = f0, 64 + stf.spill.nta [dst3] = f0, 64 + stf.spill.nta [dst4] = f0, 128 + cmp.lt p8,p0=dst_fetch, dst_last ;; -1: stf.spill.nta [dst0] = f0, 64 stf.spill.nta [dst1] = f0, 64 stf.spill.nta [dst2] = f0, 64 +#endif stf.spill.nta [dst3] = f0, 64 - - lfetch [dst_fetch], 64 - br.cloop.dptk.few 1b +(p8) stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE + br.cloop.sptk.few 1b ;; - mov ar.lc = r2 // restore lc + mov ar.lc = saved_lc // restore lc br.ret.sptk.many rp END(clear_page) diff -Nur linux-2.4.19/arch/ia64/lib/copy_page.S linux-2.4.19-sgi211r3/arch/ia64/lib/copy_page.S --- linux-2.4.19/arch/ia64/lib/copy_page.S Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/copy_page.S Tue Aug 27 19:53:13 2002 @@ -30,6 +30,7 @@ #define tgt2 r23 #define srcf r24 #define tgtf r25 +#define tgt_last r26 #define Nrot ((8*PIPE_DEPTH+7)&~7) @@ -55,18 +56,21 @@ mov src1=in1 adds src2=8,in1 + mov tgt_last = PAGE_SIZE ;; adds tgt2=8,in0 add srcf=512,in1 mov ar.lc=lcount mov tgt1=in0 add tgtf=512,in0 + add tgt_last = tgt_last, in0 ;; 1: (p[0]) ld8 t1[0]=[src1],16 (EPI) st8 [tgt1]=t1[PIPE_DEPTH-1],16 (p[0]) ld8 t2[0]=[src2],16 (EPI) st8 [tgt2]=t2[PIPE_DEPTH-1],16 + cmp.ltu p6,p0 = tgtf, tgt_last ;; (p[0]) ld8 t3[0]=[src1],16 (EPI) st8 [tgt1]=t3[PIPE_DEPTH-1],16 @@ -83,8 +87,8 @@ (p[0]) ld8 t8[0]=[src2],16 (EPI) st8 [tgt2]=t8[PIPE_DEPTH-1],16 - lfetch [srcf], 64 - lfetch [tgtf], 64 +(p6) lfetch [srcf], 64 +(p6) lfetch [tgtf], 64 br.ctop.sptk.few 1b ;; mov pr=saved_pr,0xffffffffffff0000 // restore predicates diff -Nur linux-2.4.19/arch/ia64/lib/copy_page_mck.S linux-2.4.19-sgi211r3/arch/ia64/lib/copy_page_mck.S --- linux-2.4.19/arch/ia64/lib/copy_page_mck.S Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/copy_page_mck.S Tue Aug 27 19:53:13 2002 @@ -0,0 +1,185 @@ +/* + * McKinley-optimized version of copy_page(). + * + * Copyright (C) 2002 Hewlett-Packard Co + * David Mosberger + * + * Inputs: + * in0: address of target page + * in1: address of source page + * Output: + * no return value + * + * General idea: + * - use regular loads and stores to prefetch data to avoid consuming M-slot just for + * lfetches => good for in-cache performance + * - avoid l2 bank-conflicts by not storing into the same 16-byte bank within a single + * cycle + * + * Principle of operation: + * First, note that L1 has a line-size of 64 bytes and L2 a line-size of 128 bytes. + * To avoid secondary misses in L2, we prefetch both source and destination with a line-size + * of 128 bytes. When both of these lines are in the L2 and the first half of the + * source line is in L1, we start copying the remaining words. The second half of the + * source line is prefetched in an earlier iteration, so that by the time we start + * accessing it, it's also present in the L1. + * + * We use a software-pipelined loop to control the overall operation. The pipeline + * has 2*PREFETCH_DIST+K stages. The first PREFETCH_DIST stages are used for prefetching + * source cache-lines. The second PREFETCH_DIST stages are used for prefetching destination + * cache-lines, the last K stages are used to copy the cache-line words not copied by + * the prefetches. The four relevant points in the pipelined are called A, B, C, D: + * p[A] is TRUE if a source-line should be prefetched, p[B] is TRUE if a destination-line + * should be prefetched, p[C] is TRUE if the second half of an L2 line should be brought + * into L1D and p[D] is TRUE if a cacheline needs to be copied. + * + * This all sounds very complicated, but thanks to the modulo-scheduled loop support, + * the resulting code is very regular and quite easy to follow (once you get the idea). + * + * As a secondary optimization, the first 2*PREFETCH_DIST iterations are implemented + * as the separate .prefetch_loop. Logically, this loop performs exactly like the + * main-loop (.line_copy), but has all known-to-be-predicated-off instructions removed, + * so that each loop iteration is faster (again, good for cached case). + * + * When reading the code, it helps to keep the following picture in mind: + * + * word 0 word 1 + * +------+------+--- + * | v[x] | t1 | ^ + * | t2 | t3 | | + * | t4 | t5 | | + * | t6 | t7 | | 128 bytes + * | n[y] | t9 | | (L2 cache line) + * | t10 | t11 | | + * | t12 | t13 | | + * | t14 | t15 | v + * +------+------+--- + * + * Here, v[x] is copied by the (memory) prefetch. n[y] is loaded at p[C] + * to fetch the second-half of the L2 cache line into L1, and the tX words are copied in + * an order that avoids bank conflicts. + */ +#include +#include + +#define PREFETCH_DIST 8 // McKinley sustains 16 outstanding L2 misses (8 ld, 8 st) + +#define src0 r2 +#define src1 r3 +#define dst0 r9 +#define dst1 r10 +#define src_pre_mem r11 +#define dst_pre_mem r14 +#define src_pre_l2 r15 +#define dst_pre_l2 r16 +#define t1 r17 +#define t2 r18 +#define t3 r19 +#define t4 r20 +#define t5 t1 // alias! +#define t6 t2 // alias! +#define t7 t3 // alias! +#define t9 t5 // alias! +#define t10 t4 // alias! +#define t11 t7 // alias! +#define t12 t6 // alias! +#define t14 t10 // alias! +#define t13 r21 +#define t15 r22 + +#define saved_lc r23 +#define saved_pr r24 + +#define A 0 +#define B (PREFETCH_DIST) +#define C (B + PREFETCH_DIST) +#define D (C + 3) +#define N (D + 1) +#define Nrot ((N + 7) & ~7) + +GLOBAL_ENTRY(copy_page) + .prologue + alloc r8 = ar.pfs, 2, Nrot-2, 0, Nrot + + .rotr v[2*PREFETCH_DIST], n[D-C+1] + .rotp p[N] + + .save ar.lc, saved_lc + mov saved_lc = ar.lc + .save pr, saved_pr + mov saved_pr = pr + .body + + mov src_pre_mem = in1 + mov pr.rot = 0x10000 + mov ar.ec = 1 // special unrolled loop + + mov dst_pre_mem = in0 + mov ar.lc = 2*PREFETCH_DIST - 1 + + add src_pre_l2 = 8*8, in1 + add dst_pre_l2 = 8*8, in0 + add src0 = 8, in1 // first t1 src + add src1 = 3*8, in1 // first t3 src + add dst0 = 8, in0 // first t1 dst + add dst1 = 3*8, in0 // first t3 dst + mov t1 = (PAGE_SIZE/128) - (2*PREFETCH_DIST) - 1 + nop.m 0 + nop.i 0 + ;; + // same as .line_copy loop, but with all predicated-off instructions removed: +.prefetch_loop: +(p[A]) ld8 v[A] = [src_pre_mem], 128 // M0 +(p[B]) st8 [dst_pre_mem] = v[B], 128 // M2 + br.ctop.sptk .prefetch_loop + ;; + cmp.eq p16, p0 = r0, r0 // reset p16 to 1 (br.ctop cleared it to zero) + mov ar.lc = t1 // with 64KB pages, t1 is too big to fit in 8 bits! + mov ar.ec = N // # of stages in pipeline + ;; +.line_copy: +(p[D]) ld8 t2 = [src0], 3*8 // M0 +(p[D]) ld8 t4 = [src1], 3*8 // M1 +(p[B]) st8 [dst_pre_mem] = v[B], 128 // M2 prefetch dst from memory +(p[D]) st8 [dst_pre_l2] = n[D-C], 128 // M3 prefetch dst from L2 + ;; +(p[A]) ld8 v[A] = [src_pre_mem], 128 // M0 prefetch src from memory +(p[C]) ld8 n[0] = [src_pre_l2], 128 // M1 prefetch src from L2 +(p[D]) st8 [dst0] = t1, 8 // M2 +(p[D]) st8 [dst1] = t3, 8 // M3 + ;; +(p[D]) ld8 t5 = [src0], 8 +(p[D]) ld8 t7 = [src1], 3*8 +(p[D]) st8 [dst0] = t2, 3*8 +(p[D]) st8 [dst1] = t4, 3*8 + ;; +(p[D]) ld8 t6 = [src0], 3*8 +(p[D]) ld8 t10 = [src1], 8 +(p[D]) st8 [dst0] = t5, 8 +(p[D]) st8 [dst1] = t7, 3*8 + ;; +(p[D]) ld8 t9 = [src0], 3*8 +(p[D]) ld8 t11 = [src1], 3*8 +(p[D]) st8 [dst0] = t6, 3*8 +(p[D]) st8 [dst1] = t10, 8 + ;; +(p[D]) ld8 t12 = [src0], 8 +(p[D]) ld8 t14 = [src1], 8 +(p[D]) st8 [dst0] = t9, 3*8 +(p[D]) st8 [dst1] = t11, 3*8 + ;; +(p[D]) ld8 t13 = [src0], 4*8 +(p[D]) ld8 t15 = [src1], 4*8 +(p[D]) st8 [dst0] = t12, 8 +(p[D]) st8 [dst1] = t14, 8 + ;; +(p[D-1])ld8 t1 = [src0], 8 +(p[D-1])ld8 t3 = [src1], 8 +(p[D]) st8 [dst0] = t13, 4*8 +(p[D]) st8 [dst1] = t15, 4*8 + br.ctop.sptk .line_copy + ;; + mov ar.lc = saved_lc + mov pr = saved_pr, -1 + br.ret.sptk.many rp +END(copy_page) diff -Nur linux-2.4.19/arch/ia64/lib/copy_user.S linux-2.4.19-sgi211r3/arch/ia64/lib/copy_user.S --- linux-2.4.19/arch/ia64/lib/copy_user.S Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/copy_user.S Wed Oct 16 14:02:58 2002 @@ -35,7 +35,13 @@ // Tuneable parameters // #define COPY_BREAK 16 // we do byte copy below (must be >=16) + +#if (__GNUC__ == 2) +/* GCC 2.96 can't handle a depth of 21 */ +#define PIPE_DEPTH 4 // pipe depth +#else #define PIPE_DEPTH 21 // pipe depth +#endif #define EPI p[PIPE_DEPTH-1] @@ -237,15 +243,17 @@ .copy_user_bit##rshift: \ 1: \ EX(.failure_out,(EPI) st8 [dst1]=tmp,8); \ -(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ - EX(3f,(p16) ld8 val1[0]=[src1],8); \ +(EPI_1) shrp tmp=val1[PIPE_DEPTH-2],val1[PIPE_DEPTH-1],rshift; \ + EX(3f,(p16) ld8 val1[1]=[src1],8); \ +(p16) mov val1[0]=r0; \ br.ctop.dptk 1b; \ ;; \ br.cond.sptk.many .diff_align_do_tail; \ 2: \ (EPI) st8 [dst1]=tmp,8; \ -(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ +(EPI_1) shrp tmp=val1[PIPE_DEPTH-2],val1[PIPE_DEPTH-1],rshift; \ 3: \ +(p16) mov val1[1]=r0; \ (p16) mov val1[0]=r0; \ br.ctop.dptk 2b; \ ;; \ diff -Nur linux-2.4.19/arch/ia64/lib/do_csum.S linux-2.4.19-sgi211r3/arch/ia64/lib/do_csum.S --- linux-2.4.19/arch/ia64/lib/do_csum.S Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/do_csum.S Tue Aug 27 19:53:13 2002 @@ -8,9 +8,14 @@ * in0: address of buffer to checksum (char *) * in1: length of the buffer (int) * - * Copyright (C) 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian + * Copyright (C) 1999, 2001-2002 Hewlett-Packard Co + * Stephane Eranian * + * 02/04/22 Ken Chen + * Data locality study on the checksum buffer. + * More optimization cleanup - remove excessive stop bits. + * 02/04/08 David Mosberger + * More cleanup and tuning. * 01/04/18 Jun Nakajima * Clean up and optimize and the software pipeline, loading two * back-to-back 8-byte words per loop. Clean up the initialization @@ -71,8 +76,6 @@ // calculating the Internet checksum. // // NOT YET DONE: -// - use the lfetch instruction to augment the chances of the data being in -// the cache when we need it. // - Maybe another algorithm which would take care of the folding at the // end in a different manner // - Work with people more knowledgeable than me on the network stack @@ -80,6 +83,12 @@ // type of packet or alignment we get. Like the ip_fast_csum() routine // where we know we have at least 20bytes worth of data to checksum. // - Do a better job of handling small packets. +// - Note on prefetching: it was found that under various load, i.e. ftp read/write, +// nfs read/write, the L1 cache hit rate is at 60% and L2 cache hit rate is at 99.8% +// on the data that buffer points to (partly because the checksum is often preceded by +// a copy_from_user()). This finding indiate that lfetch will not be beneficial since +// the data is already in the cache. +// #define saved_pfs r11 #define hmask r16 @@ -102,10 +111,6 @@ #define buf in0 #define len in1 -#ifndef CONFIG_IA64_LOAD_LATENCY -#define CONFIG_IA64_LOAD_LATENCY 2 -#endif - #define LOAD_LATENCY 2 // XXX fix me #if (LOAD_LATENCY != 1) && (LOAD_LATENCY != 2) @@ -121,69 +126,70 @@ GLOBAL_ENTRY(do_csum) .prologue .save ar.pfs, saved_pfs - alloc saved_pfs=ar.pfs,2,16,1,16 - .rotr word1[4], word2[4],result1[4],result2[4] - .rotp p[PIPE_DEPTH] + alloc saved_pfs=ar.pfs,2,16,0,16 + .rotr word1[4], word2[4],result1[LOAD_LATENCY+2],result2[LOAD_LATENCY+2] + .rotp p[PIPE_DEPTH], pC1[2], pC2[2] mov ret0=r0 // in case we have zero length cmp.lt p0,p6=r0,len // check for zero length or negative (32bit len) - ;; // avoid WAW on CFM - mov tmp3=0x7 // a temporary mask/value + ;; add tmp1=buf,len // last byte's address -(p6) br.ret.spnt.many rp // return if true (hope we can avoid that) + .save pr, saved_pr + mov saved_pr=pr // preserve predicates (rotation) +(p6) br.ret.spnt.many rp // return if zero or negative length - and firstoff=7,buf // how many bytes off for first1 element - tbit.nz p15,p0=buf,0 // is buf an odd address ? mov hmask=-1 // intialize head mask - ;; - andcm first1=buf,tmp3 // 8byte aligned down address of first1 element + tbit.nz p15,p0=buf,0 // is buf an odd address? + and first1=-8,buf // 8-byte align down address of first1 element + + and firstoff=7,buf // how many bytes off for first1 element mov tmask=-1 // initialize tail mask - adds tmp2=-1,tmp1 // last-1 + ;; + adds tmp2=-1,tmp1 // last-1 and lastoff=7,tmp1 // how many bytes off for last element - andcm last=tmp2,tmp3 // address of word containing last byte - .save pr, saved_pr - mov saved_pr=pr // preserve predicates (rotation) + ;; + sub tmp1=8,lastoff // complement to lastoff + and last=-8,tmp2 // address of word containing last byte ;; sub tmp3=last,first1 // tmp3=distance from first1 to last + .save ar.lc, saved_lc + mov saved_lc=ar.lc // save lc cmp.eq p8,p9=last,first1 // everything fits in one word ? - sub tmp1=8,lastoff // complement to lastoff - ld8 firstval=[first1],8 // load,ahead of time, "first1" word + + ld8 firstval=[first1],8 // load, ahead of time, "first1" word + and tmp1=7, tmp1 // make sure that if tmp1==8 -> tmp1=0 shl tmp2=firstoff,3 // number of bits ;; - and tmp1=7, tmp1 // make sure that if tmp1==8 -> tmp1=0 -(p9) ld8 lastval=[last] // load,ahead of time, "last" word, if needed +(p9) ld8 lastval=[last] // load, ahead of time, "last" word, if needed + shl tmp1=tmp1,3 // number of bits (p9) adds tmp3=-8,tmp3 // effectively loaded ;; (p8) mov lastval=r0 // we don't need lastval if first1==last - shl tmp1=tmp1,3 // number of bits shl hmask=hmask,tmp2 // build head mask, mask off [0,first1off[ - ;; shr.u tmask=tmask,tmp1 // build tail mask, mask off ]8,lastoff] - .save ar.lc, saved_lc - mov saved_lc=ar.lc // save lc ;; .body #define count tmp3 (p8) and hmask=hmask,tmask // apply tail mask to head mask if 1 word only (p9) and word2[0]=lastval,tmask // mask last it as appropriate - shr.u count=count,3 // we do 8 bytes per loop (count) + shr.u count=count,3 // how many 8-byte? ;; // If count is odd, finish this 8-byte word so that we can // load two back-to-back 8-byte words per loop thereafter. - tbit.nz p10,p11=count,0 // if (count is odd) and word1[0]=firstval,hmask // and mask it as appropriate + tbit.nz p10,p11=count,0 // if (count is odd) ;; (p8) mov result1[0]=word1[0] (p9) add result1[0]=word1[0],word2[0] ;; cmp.ltu p6,p0=result1[0],word1[0] // check the carry + cmp.eq.or.andcm p8,p0=0,count // exit if zero 8-byte ;; (p6) adds result1[0]=1,result1[0] (p8) br.cond.dptk .do_csum_exit // if (within an 8-byte word) - ;; (p11) br.cond.dptk .do_csum16 // if (count is even) - ;; + // Here count is odd. ld8 word1[1]=[first1],8 // load an 8-byte word cmp.eq p9,p10=1,count // if (count == 1) @@ -194,58 +200,43 @@ cmp.ltu p6,p0=result1[0],word1[1] ;; (p6) adds result1[0]=1,result1[0] - ;; (p9) br.cond.sptk .do_csum_exit // if (count == 1) exit // Fall through to caluculate the checksum, feeding result1[0] as // the initial value in result1[0]. - ;; // // Calculate the checksum loading two 8-byte words per loop. // .do_csum16: - mov saved_lc=ar.lc + add first2=8,first1 shr.u count=count,1 // we do 16 bytes per loop ;; - cmp.eq p9,p10=r0,count // if (count == 0) + adds count=-1,count + mov carry1=r0 + mov carry2=r0 brp.loop.imp 1f,2f ;; - adds count=-1,count mov ar.ec=PIPE_DEPTH - ;; mov ar.lc=count // set lc - ;; + mov pr.rot=1<<16 // result1[0] must be initialized in advance. mov result2[0]=r0 ;; - mov pr.rot=1<<16 - ;; - mov carry1=r0 - mov carry2=r0 - ;; - add first2=8,first1 - ;; -(p9) br.cond.sptk .do_csum_exit - ;; - nop.m 0 - nop.i 0 - ;; .align 32 1: -(ELD_1) cmp.ltu p31,p0=result1[LOAD_LATENCY],word1[LOAD_LATENCY+1] -(p32) adds carry1=1,carry1 -(ELD_1) cmp.ltu p47,p0=result2[LOAD_LATENCY],word2[LOAD_LATENCY+1] -(p48) adds carry2=1,carry2 +(ELD_1) cmp.ltu pC1[0],p0=result1[LOAD_LATENCY],word1[LOAD_LATENCY+1] +(pC1[1])adds carry1=1,carry1 +(ELD_1) cmp.ltu pC2[0],p0=result2[LOAD_LATENCY],word2[LOAD_LATENCY+1] +(pC2[1])adds carry2=1,carry2 (ELD) add result1[LOAD_LATENCY-1]=result1[LOAD_LATENCY],word1[LOAD_LATENCY] (ELD) add result2[LOAD_LATENCY-1]=result2[LOAD_LATENCY],word2[LOAD_LATENCY] 2: -(p16) ld8 word1[0]=[first1],16 -(p16) ld8 word2[0]=[first2],16 +(p[0]) ld8 word1[0]=[first1],16 +(p[0]) ld8 word2[0]=[first2],16 br.ctop.sptk 1b ;; - // Since len is a 32-bit value, carry cannot be larger than - // a 64-bit value. -(p32) adds carry1=1,carry1 // since we miss the last one -(p48) adds carry2=1,carry2 + // Since len is a 32-bit value, carry cannot be larger than a 64-bit value. +(pC1[1])adds carry1=1,carry1 // since we miss the last one +(pC2[1])adds carry2=1,carry2 ;; add result1[LOAD_LATENCY+1]=result1[LOAD_LATENCY+1],carry1 add result2[LOAD_LATENCY+1]=result2[LOAD_LATENCY+1],carry2 @@ -263,18 +254,15 @@ (p6) adds result1[0]=1,result1[0] ;; .do_csum_exit: - movl tmp3=0xffffffff - ;; - // XXX Fixme // // now fold 64 into 16 bits taking care of carry // that's not very good because it has lots of sequentiality // - and tmp1=result1[0],tmp3 + mov tmp3=0xffff + zxt4 tmp1=result1[0] shr.u tmp2=result1[0],32 ;; add result1[0]=tmp1,tmp2 - shr.u tmp3=tmp3,16 ;; and tmp1=result1[0],tmp3 shr.u tmp2=result1[0],16 diff -Nur linux-2.4.19/arch/ia64/lib/ip_fast_csum.S linux-2.4.19-sgi211r3/arch/ia64/lib/ip_fast_csum.S --- linux-2.4.19/arch/ia64/lib/ip_fast_csum.S Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/ip_fast_csum.S Tue Aug 27 19:53:13 2002 @@ -0,0 +1,90 @@ +/* + * Optmized version of the ip_fast_csum() function + * Used for calculating IP header checksum + * + * Return: 16bit checksum, complemented + * + * Inputs: + * in0: address of buffer to checksum (char *) + * in1: length of the buffer (int) + * + * Copyright (C) 2002 Intel Corp. + * Copyright (C) 2002 Ken Chen + */ + +#include + +/* + * Since we know that most likely this function is called with buf aligned + * on 4-byte boundary and 20 bytes in length, we can execution rather quickly + * versus calling generic version of do_csum, which has lots of overhead in + * handling various alignments and sizes. However, due to lack of constrains + * put on the function input argument, cases with alignment not on 4-byte or + * size not equal to 20 bytes will be handled by the generic do_csum function. + */ + +#define in0 r32 +#define in1 r33 +#define ret0 r8 + +GLOBAL_ENTRY(ip_fast_csum) + .prologue + .body + cmp.ne p6,p7=5,in1 // size other than 20 byte? + and r14=3,in0 // is it aligned on 4-byte? + add r15=4,in0 // second source pointer + ;; + cmp.ne.or.andcm p6,p7=r14,r0 + ;; +(p7) ld4 r20=[in0],8 +(p7) ld4 r21=[r15],8 +(p6) br.spnt .generic + ;; + ld4 r22=[in0],8 + ld4 r23=[r15],8 + ;; + ld4 r24=[in0] + add r20=r20,r21 + add r22=r22,r23 + ;; + add r20=r20,r22 + ;; + add r20=r20,r24 + ;; + shr.u ret0=r20,16 // now need to add the carry + zxt2 r20=r20 + ;; + add r20=ret0,r20 + ;; + shr.u ret0=r20,16 // add carry again + zxt2 r20=r20 + ;; + add r20=ret0,r20 + ;; + shr.u ret0=r20,16 + zxt2 r20=r20 + ;; + add r20=ret0,r20 + ;; + andcm ret0=-1,r20 + .restore sp // reset frame state + br.ret.sptk.many b0 + ;; + +.generic: + .prologue + .save ar.pfs, r35 + alloc r35=ar.pfs,2,2,2,0 + .save rp, r34 + mov r34=b0 + .body + dep.z out1=in1,2,30 + mov out0=in0 + ;; + br.call.sptk.many b0=do_csum + ;; + andcm ret0=-1,ret0 + mov ar.pfs=r35 + mov b0=r34 + br.ret.sptk.many b0 +END(ip_fast_csum) diff -Nur linux-2.4.19/arch/ia64/lib/memcpy_mck.S linux-2.4.19-sgi211r3/arch/ia64/lib/memcpy_mck.S --- linux-2.4.19/arch/ia64/lib/memcpy_mck.S Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/memcpy_mck.S Tue Aug 27 19:53:13 2002 @@ -0,0 +1,675 @@ +/* + * Itanium 2-optimized version of memcpy and copy_user function + * + * Inputs: + * in0: destination address + * in1: source address + * in2: number of bytes to copy + * Output: + * 0 if success, or number of byte NOT copied if error occurred. + * + * Copyright (C) 2002 Intel Corp. + * Copyright (C) 2002 Ken Chen + */ +#include +#include +#include + +#if __GNUC__ >= 3 +# define EK(y...) EX(y) +#else +# define EK(y,x...) x +#endif + +GLOBAL_ENTRY(bcopy) + .regstk 3,0,0,0 + mov r8=in0 + mov in0=in1 + ;; + mov in1=r8 + ;; +END(bcopy) + +/* McKinley specific optimization */ + +#define retval r8 +#define saved_pfs r31 +#define saved_lc r10 +#define saved_pr r11 +#define saved_in0 r14 +#define saved_in1 r15 +#define saved_in2 r16 + +#define src0 r2 +#define src1 r3 +#define dst0 r17 +#define dst1 r18 +#define cnt r9 + +/* r19-r30 are temp for each code section */ +#define PREFETCH_DIST 8 +#define src_pre_mem r19 +#define dst_pre_mem r20 +#define src_pre_l2 r21 +#define dst_pre_l2 r22 +#define t1 r23 +#define t2 r24 +#define t3 r25 +#define t4 r26 +#define t5 t1 // alias! +#define t6 t2 // alias! +#define t7 t3 // alias! +#define n8 r27 +#define t9 t5 // alias! +#define t10 t4 // alias! +#define t11 t7 // alias! +#define t12 t6 // alias! +#define t14 t10 // alias! +#define t13 r28 +#define t15 r29 +#define tmp r30 + +/* defines for long_copy block */ +#define A 0 +#define B (PREFETCH_DIST) +#define C (B + PREFETCH_DIST) +#define D (C + 1) +#define N (D + 1) +#define Nrot ((N + 7) & ~7) + +/* alias */ +#define in0 r32 +#define in1 r33 +#define in2 r34 + +GLOBAL_ENTRY(memcpy) + and r28=0x7,in0 + and r29=0x7,in1 + mov f6=f0 + br.cond.sptk .common_code + ;; +END(memcpy) +GLOBAL_ENTRY(__copy_user) + .prologue +// check dest alignment + and r28=0x7,in0 + and r29=0x7,in1 + mov f6=f1 + mov saved_in0=in0 // save dest pointer + mov saved_in1=in1 // save src pointer + mov saved_in2=in2 // save len + ;; +.common_code: + cmp.gt p15,p0=8,in2 // check for small size + cmp.ne p13,p0=0,r28 // check dest alignment + cmp.ne p14,p0=0,r29 // check src alignment + add src0=0,in1 + sub r30=8,r28 // for .align_dest + mov retval=r0 // initialize return value + ;; + add dst0=0,in0 + add dst1=1,in0 // dest odd index + cmp.le p6,p0 = 1,r30 // for .align_dest +(p15) br.cond.dpnt .memcpy_short +(p13) br.cond.dpnt .align_dest +(p14) br.cond.dpnt .unaligned_src + ;; + +// both dest and src are aligned on 8-byte boundary +.aligned_src: + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,3,Nrot-3,0,Nrot + .save pr, saved_pr + mov saved_pr=pr + + shr.u cnt=in2,7 // this much cache line + ;; + cmp.lt p6,p0=2*PREFETCH_DIST,cnt + cmp.lt p7,p8=1,cnt + .save ar.lc, saved_lc + mov saved_lc=ar.lc + .body + add cnt=-1,cnt + add src_pre_mem=0,in1 // prefetch src pointer + add dst_pre_mem=0,in0 // prefetch dest pointer + ;; +(p7) mov ar.lc=cnt // prefetch count +(p8) mov ar.lc=r0 +(p6) br.cond.dpnt .long_copy + ;; + +.prefetch: + lfetch [src_pre_mem], 128 + lfetch.excl [dst_pre_mem], 128 + br.cloop.dptk.few .prefetch + ;; + +.medium_copy: + and tmp=31,in2 // copy length after iteration + shr.u r29=in2,5 // number of 32-byte iteration + add dst1=8,dst0 // 2nd dest pointer + ;; + add cnt=-1,r29 // ctop iteration adjustment + cmp.eq p10,p0=r29,r0 // do we really need to loop? + add src1=8,src0 // 2nd src pointer + cmp.le p6,p0=8,tmp + ;; + cmp.le p7,p0=16,tmp + mov ar.lc=cnt // loop setup + cmp.eq p16,p17 = r0,r0 + mov ar.ec=2 +(p10) br.dpnt.few .aligned_src_tail + ;; + .align 32 +1: +EX(.ex_handler, (p16) ld8 r34=[src0],16) +EK(.ex_handler, (p16) ld8 r38=[src1],16) +EX(.ex_handler, (p17) st8 [dst0]=r33,16) +EK(.ex_handler, (p17) st8 [dst1]=r37,16) + ;; +EX(.ex_handler, (p16) ld8 r32=[src0],16) +EK(.ex_handler, (p16) ld8 r36=[src1],16) +EX(.ex_handler, (p16) st8 [dst0]=r34,16) +EK(.ex_handler, (p16) st8 [dst1]=r38,16) + br.ctop.dptk.few 1b + ;; + +.aligned_src_tail: +EX(.ex_handler, (p6) ld8 t1=[src0]) + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs +EX(.ex_hndlr_s, (p7) ld8 t2=[src1],8) + cmp.le p8,p0=24,tmp + and r21=-8,tmp + ;; +EX(.ex_hndlr_s, (p8) ld8 t3=[src1]) +EX(.ex_handler, (p6) st8 [dst0]=t1) // store byte 1 + and in2=7,tmp // remaining length +EX(.ex_hndlr_d, (p7) st8 [dst1]=t2,8) // store byte 2 + add src0=src0,r21 // setting up src pointer + add dst0=dst0,r21 // setting up dest pointer + ;; +EX(.ex_handler, (p8) st8 [dst1]=t3) // store byte 3 + mov pr=saved_pr,-1 + br.dptk.many .memcpy_short + ;; + +/* code taken from copy_page_mck */ +.long_copy: + .rotr v[2*PREFETCH_DIST] + .rotp p[N] + + mov src_pre_mem = src0 + mov pr.rot = 0x10000 + mov ar.ec = 1 // special unrolled loop + + mov dst_pre_mem = dst0 + + add src_pre_l2 = 8*8, src0 + add dst_pre_l2 = 8*8, dst0 + ;; + add src0 = 8, src_pre_mem // first t1 src + mov ar.lc = 2*PREFETCH_DIST - 1 + shr.u cnt=in2,7 // number of lines + add src1 = 3*8, src_pre_mem // first t3 src + add dst0 = 8, dst_pre_mem // first t1 dst + add dst1 = 3*8, dst_pre_mem // first t3 dst + ;; + and tmp=127,in2 // remaining bytes after this block + add cnt = -(2*PREFETCH_DIST) - 1, cnt + // same as .line_copy loop, but with all predicated-off instructions removed: +.prefetch_loop: +EX(.ex_hndlr_lcpy_1, (p[A]) ld8 v[A] = [src_pre_mem], 128) // M0 +EK(.ex_hndlr_lcpy_1, (p[B]) st8 [dst_pre_mem] = v[B], 128) // M2 + br.ctop.sptk .prefetch_loop + ;; + cmp.eq p16, p0 = r0, r0 // reset p16 to 1 + mov ar.lc = cnt + mov ar.ec = N // # of stages in pipeline + ;; +.line_copy: +EX(.ex_handler, (p[D]) ld8 t2 = [src0], 3*8) // M0 +EK(.ex_handler, (p[D]) ld8 t4 = [src1], 3*8) // M1 +EX(.ex_handler_lcpy, (p[B]) st8 [dst_pre_mem] = v[B], 128) // M2 prefetch dst from memory +EK(.ex_handler_lcpy, (p[D]) st8 [dst_pre_l2] = n8, 128) // M3 prefetch dst from L2 + ;; +EX(.ex_handler_lcpy, (p[A]) ld8 v[A] = [src_pre_mem], 128) // M0 prefetch src from memory +EK(.ex_handler_lcpy, (p[C]) ld8 n8 = [src_pre_l2], 128) // M1 prefetch src from L2 +EX(.ex_handler, (p[D]) st8 [dst0] = t1, 8) // M2 +EK(.ex_handler, (p[D]) st8 [dst1] = t3, 8) // M3 + ;; +EX(.ex_handler, (p[D]) ld8 t5 = [src0], 8) +EK(.ex_handler, (p[D]) ld8 t7 = [src1], 3*8) +EX(.ex_handler, (p[D]) st8 [dst0] = t2, 3*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t4, 3*8) + ;; +EX(.ex_handler, (p[D]) ld8 t6 = [src0], 3*8) +EK(.ex_handler, (p[D]) ld8 t10 = [src1], 8) +EX(.ex_handler, (p[D]) st8 [dst0] = t5, 8) +EK(.ex_handler, (p[D]) st8 [dst1] = t7, 3*8) + ;; +EX(.ex_handler, (p[D]) ld8 t9 = [src0], 3*8) +EK(.ex_handler, (p[D]) ld8 t11 = [src1], 3*8) +EX(.ex_handler, (p[D]) st8 [dst0] = t6, 3*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t10, 8) + ;; +EX(.ex_handler, (p[D]) ld8 t12 = [src0], 8) +EK(.ex_handler, (p[D]) ld8 t14 = [src1], 8) +EX(.ex_handler, (p[D]) st8 [dst0] = t9, 3*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t11, 3*8) + ;; +EX(.ex_handler, (p[D]) ld8 t13 = [src0], 4*8) +EK(.ex_handler, (p[D]) ld8 t15 = [src1], 4*8) +EX(.ex_handler, (p[D]) st8 [dst0] = t12, 8) +EK(.ex_handler, (p[D]) st8 [dst1] = t14, 8) + ;; +EX(.ex_handler, (p[C]) ld8 t1 = [src0], 8) +EK(.ex_handler, (p[C]) ld8 t3 = [src1], 8) +EX(.ex_handler, (p[D]) st8 [dst0] = t13, 4*8) +EK(.ex_handler, (p[D]) st8 [dst1] = t15, 4*8) + br.ctop.sptk .line_copy + ;; + + add dst0=-8,dst0 + add src0=-8,src0 + mov in2=tmp + .restore sp + br.sptk.many .medium_copy + ;; + +#define BLOCK_SIZE 128*32 +#define blocksize r23 +#define curlen r24 + +// dest is on 8-byte boundary, src is not. We need to do +// ld8-ld8, shrp, then st8. Max 8 byte copy per cycle. +.unaligned_src: + .prologue + .save ar.pfs, saved_pfs + alloc saved_pfs=ar.pfs,3,5,0,8 + .save ar.lc, saved_lc + mov saved_lc=ar.lc + .save pr, saved_pr + mov saved_pr=pr + .body +.4k_block: + mov saved_in0=dst0 // need to save all input arguments + mov saved_in2=in2 + mov blocksize=BLOCK_SIZE + ;; + cmp.lt p6,p7=blocksize,in2 + mov saved_in1=src0 + ;; +(p6) mov in2=blocksize + ;; + shr.u r21=in2,7 // this much cache line + shr.u r22=in2,4 // number of 16-byte iteration + and curlen=15,in2 // copy length after iteration + and r30=7,src0 // source alignment + ;; + cmp.lt p7,p8=1,r21 + add cnt=-1,r21 + ;; + + add src_pre_mem=0,src0 // prefetch src pointer + add dst_pre_mem=0,dst0 // prefetch dest pointer + and src0=-8,src0 // 1st src pointer +(p7) mov ar.lc = r21 +(p8) mov ar.lc = r0 + ;; + .align 32 +1: lfetch [src_pre_mem], 128 + lfetch.excl [dst_pre_mem], 128 + br.cloop.dptk.few 1b + ;; + + shladd dst1=r22,3,dst0 // 2nd dest pointer + shladd src1=r22,3,src0 // 2nd src pointer + cmp.eq p8,p9=r22,r0 // do we really need to loop? + cmp.le p6,p7=8,curlen; // have at least 8 byte remaining? + add cnt=-1,r22 // ctop iteration adjustment + ;; +EX(.ex_handler, (p9) ld8 r33=[src0],8) // loop primer +EK(.ex_handler, (p9) ld8 r37=[src1],8) +(p8) br.dpnt.few .noloop + ;; + +// The jump address is calculated based on src alignment. The COPYU +// macro below need to confine its size to power of two, so an entry +// can be caulated using shl instead of an expensive multiply. The +// size is then hard coded by the following #define to match the +// actual size. This make it somewhat tedious when COPYU macro gets +// changed and this need to be adjusted to match. +#define LOOP_SIZE 6 +1: + mov r29=ip // jmp_table thread + mov ar.lc=cnt + ;; + add r29=.jump_table - 1b - (.jmp1-.jump_table), r29 + shl r28=r30, LOOP_SIZE // jmp_table thread + mov ar.ec=2 // loop setup + ;; + add r29=r29,r28 // jmp_table thread + cmp.eq p16,p17=r0,r0 + ;; + mov b6=r29 // jmp_table thread + ;; + br.cond.sptk.few b6 + +// for 8-15 byte case +// We will skip the loop, but need to replicate the side effect +// that the loop produces. +.noloop: +EX(.ex_handler, (p6) ld8 r37=[src1],8) + add src0=8,src0 +(p6) shl r25=r30,3 + ;; +EX(.ex_handler, (p6) ld8 r27=[src1]) +(p6) shr.u r28=r37,r25 +(p6) sub r26=64,r25 + ;; +(p6) shl r27=r27,r26 + ;; +(p6) or r21=r28,r27 + +.unaligned_src_tail: +/* check if we have more than blocksize to copy, if so go back */ + cmp.gt p8,p0=saved_in2,blocksize + ;; +(p8) add dst0=saved_in0,blocksize +(p8) add src0=saved_in1,blocksize +(p8) sub in2=saved_in2,blocksize +(p8) br.dpnt .4k_block + ;; + +/* we have up to 15 byte to copy in the tail. + * part of work is already done in the jump table code + * we are at the following state. + * src side: + * + * xxxxxx xx <----- r21 has xxxxxxxx already + * -------- -------- -------- + * 0 8 16 + * ^ + * | + * src1 + * + * dst + * -------- -------- -------- + * ^ + * | + * dst1 + */ +EX(.ex_handler, (p6) st8 [dst1]=r21,8) // more than 8 byte to copy +(p6) add curlen=-8,curlen // update length + mov ar.pfs=saved_pfs + ;; + mov ar.lc=saved_lc + mov pr=saved_pr,-1 + mov in2=curlen // remaining length + mov dst0=dst1 // dest pointer + add src0=src1,r30 // forward by src alignment + ;; + +// 7 byte or smaller. +.memcpy_short: + cmp.le p8,p9 = 1,in2 + cmp.le p10,p11 = 2,in2 + cmp.le p12,p13 = 3,in2 + cmp.le p14,p15 = 4,in2 + add src1=1,src0 // second src pointer + add dst1=1,dst0 // second dest pointer + ;; + +EX(.ex_handler_short, (p8) ld1 t1=[src0],2) +EK(.ex_handler_short, (p10) ld1 t2=[src1],2) +(p9) br.ret.dpnt rp // 0 byte copy + ;; + +EX(.ex_handler_short, (p8) st1 [dst0]=t1,2) +EK(.ex_handler_short, (p10) st1 [dst1]=t2,2) +(p11) br.ret.dpnt rp // 1 byte copy + +EX(.ex_handler_short, (p12) ld1 t3=[src0],2) +EK(.ex_handler_short, (p14) ld1 t4=[src1],2) +(p13) br.ret.dpnt rp // 2 byte copy + ;; + + cmp.le p6,p7 = 5,in2 + cmp.le p8,p9 = 6,in2 + cmp.le p10,p11 = 7,in2 + +EX(.ex_handler_short, (p12) st1 [dst0]=t3,2) +EK(.ex_handler_short, (p14) st1 [dst1]=t4,2) +(p15) br.ret.dpnt rp // 3 byte copy + ;; + +EX(.ex_handler_short, (p6) ld1 t5=[src0],2) +EK(.ex_handler_short, (p8) ld1 t6=[src1],2) +(p7) br.ret.dpnt rp // 4 byte copy + ;; + +EX(.ex_handler_short, (p6) st1 [dst0]=t5,2) +EK(.ex_handler_short, (p8) st1 [dst1]=t6,2) +(p9) br.ret.dptk rp // 5 byte copy + +EX(.ex_handler_short, (p10) ld1 t7=[src0],2) +(p11) br.ret.dptk rp // 6 byte copy + ;; + +EX(.ex_handler_short, (p10) st1 [dst0]=t7,2) + br.ret.dptk rp // done all cases + + +/* Align dest to nearest 8-byte boundary. We know we have at + * least 7 bytes to copy, enough to crawl to 8-byte boundary. + * Actual number of byte to crawl depend on the dest alignment. + * 7 byte or less is taken care at .memcpy_short + + * src0 - source even index + * src1 - source odd index + * dst0 - dest even index + * dst1 - dest odd index + * r30 - distance to 8-byte boundary + */ + +.align_dest: + add src1=1,in1 // source odd index + cmp.le p7,p0 = 2,r30 // for .align_dest + cmp.le p8,p0 = 3,r30 // for .align_dest +EX(.ex_handler_short, (p6) ld1 t1=[src0],2) + cmp.le p9,p0 = 4,r30 // for .align_dest + cmp.le p10,p0 = 5,r30 + ;; +EX(.ex_handler_short, (p7) ld1 t2=[src1],2) +EK(.ex_handler_short, (p8) ld1 t3=[src0],2) + cmp.le p11,p0 = 6,r30 +EX(.ex_handler_short, (p6) st1 [dst0] = t1,2) + cmp.le p12,p0 = 7,r30 + ;; +EX(.ex_handler_short, (p9) ld1 t4=[src1],2) +EK(.ex_handler_short, (p10) ld1 t5=[src0],2) +EX(.ex_handler_short, (p7) st1 [dst1] = t2,2) +EK(.ex_handler_short, (p8) st1 [dst0] = t3,2) + ;; +EX(.ex_handler_short, (p11) ld1 t6=[src1],2) +EK(.ex_handler_short, (p12) ld1 t7=[src0],2) + cmp.eq p6,p7=r28,r29 +EX(.ex_handler_short, (p9) st1 [dst1] = t4,2) +EK(.ex_handler_short, (p10) st1 [dst0] = t5,2) + sub in2=in2,r30 + ;; +EX(.ex_handler_short, (p11) st1 [dst1] = t6,2) +EK(.ex_handler_short, (p12) st1 [dst0] = t7) + add dst0=in0,r30 // setup arguments + add src0=in1,r30 +(p6) br.cond.dptk .aligned_src +(p7) br.cond.dpnt .unaligned_src + ;; + +/* main loop body in jump table format */ +#define COPYU(shift) \ +1: \ +EX(.ex_handler, (p16) ld8 r32=[src0],8); /* 1 */ \ +EK(.ex_handler, (p16) ld8 r36=[src1],8); \ + (p17) shrp r35=r33,r34,shift;; /* 1 */ \ +EX(.ex_handler, (p6) ld8 r22=[src1]); /* common, prime for tail section */ \ + nop.m 0; \ + (p16) shrp r38=r36,r37,shift; \ +EX(.ex_handler, (p17) st8 [dst0]=r35,8); /* 1 */ \ +EK(.ex_handler, (p17) st8 [dst1]=r39,8); \ + br.ctop.dptk.few 1b;; \ + (p7) add src1=-8,src1; /* back out for <8 byte case */ \ + shrp r21=r22,r38,shift; /* speculative work */ \ + br.sptk.few .unaligned_src_tail /* branch out of jump table */ \ + ;; + .align 32 +.jump_table: + COPYU(8) // unaligned cases +.jmp1: + COPYU(16) + COPYU(24) + COPYU(32) + COPYU(40) + COPYU(48) + COPYU(56) + +#undef A +#undef B +#undef C +#undef D +END(memcpy) + +/* + * Due to lack of local tag support in gcc 2.x assembler, it is not clear which + * instruction failed in the bundle. The exception algorithm is that we + * first figure out the faulting address, then detect if there is any + * progress made on the copy, if so, redo the copy from last known copied + * location up to the faulting address (exclusive). In the copy_from_user + * case, remaining byte in kernel buffer will be zeroed. + * + * Take copy_from_user as an example, in the code there are multiple loads + * in a bundle and those multiple loads could span over two pages, the + * faulting address is calculated as page_round_down(max(src0, src1)). + * This is based on knowledge that if we can access one byte in a page, we + * can access any byte in that page. + * + * predicate used in the exception handler: + * p6-p7: direction + * p10-p11: src faulting addr calculation + * p12-p13: dst faulting addr calculation + */ + +#define A r19 +#define B r20 +#define C r21 +#define D r22 +#define F r28 + +#define memset_arg0 r32 +#define memset_arg2 r33 + +#define saved_retval loc0 +#define saved_rtlink loc1 +#define saved_pfs_stack loc2 + +.ex_hndlr_s: + add src0=8,src0 + br.sptk .ex_handler + ;; +.ex_hndlr_d: + add dst0=8,dst0 + br.sptk .ex_handler + ;; +.ex_hndlr_lcpy_1: + mov src1=src_pre_mem + mov dst1=dst_pre_mem + cmp.gtu p10,p11=src_pre_mem,saved_in1 + cmp.gtu p12,p13=dst_pre_mem,saved_in0 + ;; +(p10) add src0=8,saved_in1 +(p11) mov src0=saved_in1 +(p12) add dst0=8,saved_in0 +(p13) mov dst0=saved_in0 + br.sptk .ex_handler +.ex_handler_lcpy: + // in line_copy block, the preload addresses should always ahead + // of the other two src/dst pointers. Furthermore, src1/dst1 should + // always ahead of src0/dst0. + mov src1=src_pre_mem + mov dst1=dst_pre_mem +.ex_handler: + mov pr=saved_pr,-1 // first restore pr, lc, and pfs + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + ;; +.ex_handler_short: // fault occurred in these sections didn't change pr, lc, pfs + cmp.ltu p6,p7=saved_in0, saved_in1 // get the copy direction + cmp.ltu p10,p11=src0,src1 + cmp.ltu p12,p13=dst0,dst1 + fcmp.eq p8,p0=f6,f0 // is it memcpy? + mov tmp = dst0 + ;; +(p11) mov src1 = src0 // pick the larger of the two +(p13) mov dst0 = dst1 // make dst0 the smaller one +(p13) mov dst1 = tmp // and dst1 the larger one + ;; +(p6) dep F = r0,dst1,0,PAGE_SHIFT // usr dst round down to page boundary +(p7) dep F = r0,src1,0,PAGE_SHIFT // usr src round down to page boundary + ;; +(p6) cmp.le p14,p0=dst0,saved_in0 // no progress has been made on store +(p7) cmp.le p14,p0=src0,saved_in1 // no progress has been made on load + mov retval=saved_in2 +(p8) ld1 tmp=[src1] // force an oops for memcpy call +(p8) st1 [dst1]=r0 // force an oops for memcpy call +(p14) br.ret.sptk.many rp + +/* + * The remaining byte to copy is calculated as: + * + * A = (faulting_addr - orig_src) -> len to faulting ld address + * or + * (faulting_addr - orig_dst) -> len to faulting st address + * B = (cur_dst - orig_dst) -> len copied so far + * C = A - B -> len need to be copied + * D = orig_len - A -> len need to be zeroed + */ +(p6) sub A = F, saved_in0 +(p7) sub A = F, saved_in1 + clrrrb + ;; + alloc saved_pfs_stack=ar.pfs,3,3,3,0 + sub B = dst0, saved_in0 // how many byte copied so far + ;; + sub C = A, B + sub D = saved_in2, A + ;; + cmp.gt p8,p0=C,r0 // more than 1 byte? + add memset_arg0=saved_in0, A +(p6) mov memset_arg2=0 // copy_to_user should not call memset +(p7) mov memset_arg2=D // copy_from_user need to have kbuf zeroed + mov r8=0 + mov saved_retval = D + mov saved_rtlink = b0 + + add out0=saved_in0, B + add out1=saved_in1, B + mov out2=C +(p8) br.call.sptk.few b0=__copy_user // recursive call + ;; + + add saved_retval=saved_retval,r8 // above might return non-zero value + cmp.gt p8,p0=memset_arg2,r0 // more than 1 byte? + mov out0=memset_arg0 // *s + mov out1=r0 // c + mov out2=memset_arg2 // n +(p8) br.call.sptk.few b0=memset + ;; + + mov retval=saved_retval + mov ar.pfs=saved_pfs_stack + mov b0=saved_rtlink + br.ret.sptk.many rp + +/* end of McKinley specific optimization */ +END(__copy_user) diff -Nur linux-2.4.19/arch/ia64/lib/memset.S linux-2.4.19-sgi211r3/arch/ia64/lib/memset.S --- linux-2.4.19/arch/ia64/lib/memset.S Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/memset.S Tue Aug 27 19:53:13 2002 @@ -1,108 +1,362 @@ -/* - * - * Optimized version of the standard memset() function - * - * Return: none - * - * Inputs: - * in0: address of buffer - * in1: byte value to use for storing - * in2: length of the buffer - * - * Copyright (C) 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian - */ +/* Optimized version of the standard memset() function. + + Copyright (c) 2002 Hewlett-Packard Co/CERN + Sverre Jarp + + Return: dest + + Inputs: + in0: dest + in1: value + in2: count + + The algorithm is fairly straightforward: set byte by byte until we + we get to a 16B-aligned address, then loop on 128 B chunks using an + early store as prefetching, then loop on 32B chucks, then clear remaining + words, finally clear remaining bytes. + Since a stf.spill f0 can store 16B in one go, we use this instruction + to get peak speed when value = 0. */ #include +#undef ret + +#define dest in0 +#define value in1 +#define cnt in2 -// arguments -// -#define buf r32 -#define val r33 -#define len r34 - -// -// local registers -// -#define saved_pfs r14 -#define cnt r18 -#define buf2 r19 -#define saved_lc r20 -#define tmp r21 +#define tmp r31 +#define save_lc r30 +#define ptr0 r29 +#define ptr1 r28 +#define ptr2 r27 +#define ptr3 r26 +#define ptr9 r24 +#define loopcnt r23 +#define linecnt r22 +#define bytecnt r21 + +#define fvalue f6 + +// This routine uses only scratch predicate registers (p6 - p15) +#define p_scr p6 // default register for same-cycle branches +#define p_nz p7 +#define p_zr p8 +#define p_unalgn p9 +#define p_y p11 +#define p_n p12 +#define p_yy p13 +#define p_nn p14 + +#define MIN1 15 +#define MIN1P1HALF 8 +#define LINE_SIZE 128 +#define LSIZE_SH 7 // shift amount +#define PREF_AHEAD 8 GLOBAL_ENTRY(memset) +{ .mmi .prologue - .save ar.pfs, saved_pfs - alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here - cmp.eq p8,p0=r0,len // check for zero length - .save ar.lc, saved_lc - mov saved_lc=ar.lc // preserve ar.lc (slow) - ;; - + alloc tmp = ar.pfs, 3, 0, 0, 0 .body + lfetch.nt1 [dest] // + .save ar.lc, save_lc + mov.i save_lc = ar.lc +} { .mmi + mov ret0 = dest // return value + cmp.ne p_nz, p_zr = value, r0 // use stf.spill if value is zero + cmp.eq p_scr, p0 = cnt, r0 +;; } +{ .mmi + and ptr2 = -(MIN1+1), dest // aligned address + and tmp = MIN1, dest // prepare to check for correct alignment + tbit.nz p_y, p_n = dest, 0 // Do we have an odd address? (M_B_U) +} { .mib + mov ptr1 = dest + mux1 value = value, @brcst // create 8 identical bytes in word +(p_scr) br.ret.dpnt.many rp // return immediately if count = 0 +;; } +{ .mib + cmp.ne p_unalgn, p0 = tmp, r0 // +} { .mib + sub bytecnt = (MIN1+1), tmp // NB: # of bytes to move is 1 higher than loopcnt + cmp.gt p_scr, p0 = 16, cnt // is it a minimalistic task? +(p_scr) br.cond.dptk.many .move_bytes_unaligned // go move just a few (M_B_U) +;; } +{ .mmi +(p_unalgn) add ptr1 = (MIN1+1), ptr2 // after alignment +(p_unalgn) add ptr2 = MIN1P1HALF, ptr2 // after alignment +(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 3 // should we do a st8 ? +;; } +{ .mib +(p_y) add cnt = -8, cnt // +(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 2 // should we do a st4 ? +} { .mib +(p_y) st8 [ptr2] = value,-4 // +(p_n) add ptr2 = 4, ptr2 // +;; } +{ .mib +(p_yy) add cnt = -4, cnt // +(p_unalgn) tbit.nz.unc p_y, p_n = bytecnt, 1 // should we do a st2 ? +} { .mib +(p_yy) st4 [ptr2] = value,-2 // +(p_nn) add ptr2 = 2, ptr2 // +;; } +{ .mmi + mov tmp = LINE_SIZE+1 // for compare +(p_y) add cnt = -2, cnt // +(p_unalgn) tbit.nz.unc p_yy, p_nn = bytecnt, 0 // should we do a st1 ? +} { .mmi + setf.sig fvalue=value // transfer value to FLP side +(p_y) st2 [ptr2] = value,-1 // +(p_n) add ptr2 = 1, ptr2 // +;; } + +{ .mmi +(p_yy) st1 [ptr2] = value // + cmp.gt p_scr, p0 = tmp, cnt // is it a minimalistic task? +} { .mbb +(p_yy) add cnt = -1, cnt // +(p_scr) br.cond.dpnt.many .fraction_of_line // go move just a few +;; } + +{ .mib + nop.m 0 + shr.u linecnt = cnt, LSIZE_SH +(p_zr) br.cond.dptk.many .l1b // Jump to use stf.spill +;; } + + .align 32 // -------------------------- // L1A: store ahead into cache lines; fill later +{ .mmi + and tmp = -(LINE_SIZE), cnt // compute end of range + mov ptr9 = ptr1 // used for prefetching + and cnt = (LINE_SIZE-1), cnt // remainder +} { .mmi + mov loopcnt = PREF_AHEAD-1 // default prefetch loop + cmp.gt p_scr, p0 = PREF_AHEAD, linecnt // check against actual value +;; } +{ .mmi +(p_scr) add loopcnt = -1, linecnt // + add ptr2 = 8, ptr1 // start of stores (beyond prefetch stores) + add ptr1 = tmp, ptr1 // first address beyond total range +;; } +{ .mmi + add tmp = -1, linecnt // next loop count + mov.i ar.lc = loopcnt // +;; } +.pref_l1a: +{ .mib + stf8 [ptr9] = fvalue, 128 // Do stores one cache line apart + nop.i 0 + br.cloop.dptk.few .pref_l1a +;; } +{ .mmi + add ptr0 = 16, ptr2 // Two stores in parallel + mov.i ar.lc = tmp // +;; } +.l1ax: + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 8 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 24 + stf8 [ptr0] = fvalue, 24 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 8 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 24 + stf8 [ptr0] = fvalue, 24 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 8 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 24 + stf8 [ptr0] = fvalue, 24 + ;; } + { .mmi + stf8 [ptr2] = fvalue, 8 + stf8 [ptr0] = fvalue, 32 + cmp.lt p_scr, p0 = ptr9, ptr1 // do we need more prefetching? + ;; } +{ .mmb + stf8 [ptr2] = fvalue, 24 +(p_scr) stf8 [ptr9] = fvalue, 128 + br.cloop.dptk.few .l1ax +;; } +{ .mbb + cmp.le p_scr, p0 = 8, cnt // just a few bytes left ? +(p_scr) br.cond.dpnt.many .fraction_of_line // Branch no. 2 + br.cond.dpnt.many .move_bytes_from_alignment // Branch no. 3 +;; } + + .align 32 +.l1b: // ------------------------------------ // L1B: store ahead into cache lines; fill later +{ .mmi + and tmp = -(LINE_SIZE), cnt // compute end of range + mov ptr9 = ptr1 // used for prefetching + and cnt = (LINE_SIZE-1), cnt // remainder +} { .mmi + mov loopcnt = PREF_AHEAD-1 // default prefetch loop + cmp.gt p_scr, p0 = PREF_AHEAD, linecnt // check against actual value +;; } +{ .mmi +(p_scr) add loopcnt = -1, linecnt + add ptr2 = 16, ptr1 // start of stores (beyond prefetch stores) + add ptr1 = tmp, ptr1 // first address beyond total range +;; } +{ .mmi + add tmp = -1, linecnt // next loop count + mov.i ar.lc = loopcnt +;; } +.pref_l1b: +{ .mib + stf.spill [ptr9] = f0, 128 // Do stores one cache line apart + nop.i 0 + br.cloop.dptk.few .pref_l1b +;; } +{ .mmi + add ptr0 = 16, ptr2 // Two stores in parallel + mov.i ar.lc = tmp +;; } +.l1bx: + { .mmi + stf.spill [ptr2] = f0, 32 + stf.spill [ptr0] = f0, 32 + ;; } + { .mmi + stf.spill [ptr2] = f0, 32 + stf.spill [ptr0] = f0, 32 + ;; } + { .mmi + stf.spill [ptr2] = f0, 32 + stf.spill [ptr0] = f0, 64 + cmp.lt p_scr, p0 = ptr9, ptr1 // do we need more prefetching? + ;; } +{ .mmb + stf.spill [ptr2] = f0, 32 +(p_scr) stf.spill [ptr9] = f0, 128 + br.cloop.dptk.few .l1bx +;; } +{ .mib + cmp.gt p_scr, p0 = 8, cnt // just a few bytes left ? +(p_scr) br.cond.dpnt.many .move_bytes_from_alignment // +;; } + +.fraction_of_line: +{ .mib + add ptr2 = 16, ptr1 + shr.u loopcnt = cnt, 5 // loopcnt = cnt / 32 +;; } +{ .mib + cmp.eq p_scr, p0 = loopcnt, r0 + add loopcnt = -1, loopcnt +(p_scr) br.cond.dpnt.many .store_words +;; } +{ .mib + and cnt = 0x1f, cnt // compute the remaining cnt + mov.i ar.lc = loopcnt +;; } + .align 32 +.l2: // ------------------------------------ // L2A: store 32B in 2 cycles +{ .mmb + stf8 [ptr1] = fvalue, 8 + stf8 [ptr2] = fvalue, 8 +;; } { .mmb + stf8 [ptr1] = fvalue, 24 + stf8 [ptr2] = fvalue, 24 + br.cloop.dptk.many .l2 +;; } +.store_words: +{ .mib + cmp.gt p_scr, p0 = 8, cnt // just a few bytes left ? +(p_scr) br.cond.dpnt.many .move_bytes_from_alignment // Branch +;; } + +{ .mmi + stf8 [ptr1] = fvalue, 8 // store + cmp.le p_y, p_n = 16, cnt + add cnt = -8, cnt // subtract +;; } +{ .mmi +(p_y) stf8 [ptr1] = fvalue, 8 // store +(p_y) cmp.le.unc p_yy, p_nn = 16, cnt +(p_y) add cnt = -8, cnt // subtract +;; } +{ .mmi // store +(p_yy) stf8 [ptr1] = fvalue, 8 +(p_yy) add cnt = -8, cnt // subtract +;; } + +.move_bytes_from_alignment: +{ .mib + cmp.eq p_scr, p0 = cnt, r0 + tbit.nz.unc p_y, p0 = cnt, 2 // should we terminate with a st4 ? +(p_scr) br.cond.dpnt.few .restore_and_exit +;; } +{ .mib +(p_y) st4 [ptr1] = value,4 + tbit.nz.unc p_yy, p0 = cnt, 1 // should we terminate with a st2 ? +;; } +{ .mib +(p_yy) st2 [ptr1] = value,2 + tbit.nz.unc p_y, p0 = cnt, 0 // should we terminate with a st1 ? +;; } + +{ .mib +(p_y) st1 [ptr1] = value +;; } +.restore_and_exit: +{ .mib + nop.m 0 + mov.i ar.lc = save_lc + br.ret.sptk.many rp +;; } - adds tmp=-1,len // br.ctop is repeat/until - tbit.nz p6,p0=buf,0 // odd alignment -(p8) br.ret.spnt.many rp - - cmp.lt p7,p0=16,len // if len > 16 then long memset - mux1 val=val,@brcst // prepare value -(p7) br.cond.dptk .long_memset - ;; - mov ar.lc=tmp // initialize lc for small count - ;; // avoid RAW and WAW on ar.lc -1: // worst case 15 cyles, avg 8 cycles - st1 [buf]=val,1 - br.cloop.dptk.few 1b - ;; // avoid RAW on ar.lc - mov ar.lc=saved_lc - mov ar.pfs=saved_pfs - br.ret.sptk.many rp // end of short memset - - // at this point we know we have more than 16 bytes to copy - // so we focus on alignment -.long_memset: -(p6) st1 [buf]=val,1 // 1-byte aligned -(p6) adds len=-1,len;; // sync because buf is modified - tbit.nz p6,p0=buf,1 - ;; -(p6) st2 [buf]=val,2 // 2-byte aligned -(p6) adds len=-2,len;; - tbit.nz p6,p0=buf,2 - ;; -(p6) st4 [buf]=val,4 // 4-byte aligned -(p6) adds len=-4,len;; - tbit.nz p6,p0=buf,3 - ;; -(p6) st8 [buf]=val,8 // 8-byte aligned -(p6) adds len=-8,len;; - shr.u cnt=len,4 // number of 128-bit (2x64bit) words - ;; - cmp.eq p6,p0=r0,cnt - adds tmp=-1,cnt -(p6) br.cond.dpnt .dotail // we have less than 16 bytes left - ;; - adds buf2=8,buf // setup second base pointer - mov ar.lc=tmp - ;; -2: // 16bytes/iteration - st8 [buf]=val,16 - st8 [buf2]=val,16 - br.cloop.dptk.few 2b - ;; -.dotail: // tail correction based on len only - tbit.nz p6,p0=len,3 - ;; -(p6) st8 [buf]=val,8 // at least 8 bytes - tbit.nz p6,p0=len,2 - ;; -(p6) st4 [buf]=val,4 // at least 4 bytes - tbit.nz p6,p0=len,1 - ;; -(p6) st2 [buf]=val,2 // at least 2 bytes - tbit.nz p6,p0=len,0 - mov ar.lc=saved_lc - ;; -(p6) st1 [buf]=val // only 1 byte left +.move_bytes_unaligned: +{ .mmi + .pred.rel "mutex",p_y, p_n + .pred.rel "mutex",p_yy, p_nn +(p_n) cmp.le p_yy, p_nn = 4, cnt +(p_y) cmp.le p_yy, p_nn = 5, cnt +(p_n) add ptr2 = 2, ptr1 +} { .mmi +(p_y) add ptr2 = 3, ptr1 +(p_y) st1 [ptr1] = value, 1 // fill 1 (odd-aligned) byte [15, 14 (or less) left] +(p_y) add cnt = -1, cnt +;; } +{ .mmi +(p_yy) cmp.le.unc p_y, p0 = 8, cnt + add ptr3 = ptr1, cnt // prepare last store + mov.i ar.lc = save_lc +} { .mmi +(p_yy) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes +(p_yy) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [11, 10 (o less) left] +(p_yy) add cnt = -4, cnt +;; } +{ .mmi +(p_y) cmp.le.unc p_yy, p0 = 8, cnt + add ptr3 = -1, ptr3 // last store + tbit.nz p_scr, p0 = cnt, 1 // will there be a st2 at the end ? +} { .mmi +(p_y) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes +(p_y) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [7, 6 (or less) left] +(p_y) add cnt = -4, cnt +;; } +{ .mmi +(p_yy) st2 [ptr1] = value, 4 // fill 2 (aligned) bytes +(p_yy) st2 [ptr2] = value, 4 // fill 2 (aligned) bytes [3, 2 (or less) left] + tbit.nz p_y, p0 = cnt, 0 // will there be a st1 at the end ? +} { .mmi +(p_yy) add cnt = -4, cnt +;; } +{ .mmb +(p_scr) st2 [ptr1] = value // fill 2 (aligned) bytes +(p_y) st1 [ptr3] = value // fill last byte (using ptr3) br.ret.sptk.many rp +} END(memset) diff -Nur linux-2.4.19/arch/ia64/lib/swiotlb.c linux-2.4.19-sgi211r3/arch/ia64/lib/swiotlb.c --- linux-2.4.19/arch/ia64/lib/swiotlb.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/lib/swiotlb.c Mon Apr 29 16:14:21 2002 @@ -277,8 +277,11 @@ int gfp = GFP_ATOMIC; void *ret; - if (!hwdev || hwdev->dma_mask <= 0xffffffff) - gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ + /* + * Alloc_consistent() is defined to return memory < 4GB, no matter what the DMA + * mask says. + */ + gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ ret = (void *)__get_free_pages(gfp, get_order(size)); if (!ret) return NULL; @@ -486,6 +489,17 @@ return SG_ENT_PHYS_ADDRESS(sg); } +/* + * Return whether the given PCI device DMA address mask can be supported properly. For + * example, if your device can only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +int +swiotlb_pci_dma_supported (struct pci_dev *hwdev, u64 mask) +{ + return 1; +} + EXPORT_SYMBOL(swiotlb_init); EXPORT_SYMBOL(swiotlb_map_single); EXPORT_SYMBOL(swiotlb_unmap_single); @@ -496,3 +510,4 @@ EXPORT_SYMBOL(swiotlb_dma_address); EXPORT_SYMBOL(swiotlb_alloc_consistent); EXPORT_SYMBOL(swiotlb_free_consistent); +EXPORT_SYMBOL(swiotlb_pci_dma_supported); diff -Nur linux-2.4.19/arch/ia64/mm/Makefile linux-2.4.19-sgi211r3/arch/ia64/mm/Makefile --- linux-2.4.19/arch/ia64/mm/Makefile Thu Jan 4 12:50:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/mm/Makefile Thu Jan 31 08:22:43 2002 @@ -10,5 +10,6 @@ O_TARGET := mm.o obj-y := init.o fault.o tlb.o extable.o +obj-$(CONFIG_DISCONTIGMEM) += discontig.o include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/mm/discontig.c linux-2.4.19-sgi211r3/arch/ia64/mm/discontig.c --- linux-2.4.19/arch/ia64/mm/discontig.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/mm/discontig.c Tue Feb 4 10:57:27 2003 @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2000,2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Tony Luck + */ + +/* + * Platform initialization for Discontig Memory + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* + * Round an address upward to the next multiple of chunk size. + */ +#define CHUNKROUNDUP(n) (((n)+PLAT_CHUNKSIZE-1) & ~(PLAT_CHUNKSIZE-1)) + +/* + * (Yes, I know this is a very ugly hack!! This hack should be fixed, but the + * only fix that looks reasonable requires changes to the interface to the bootmem + * allocator. These changes, while not unreasonable, ripple across multiple platforms. + * The following hack is used until we find a better solution). + * + * Ideally, we would define boot_pg_data as + * pg_data_t boot_pg_data[PLAT_MAX_COMPACT_NODES] + * + * However, this adds an unacceptibly large static data structure (8MB on SGI + * platforms) to the kernel. + * + * Pointers to boot_pg_data structures are used in the interface to the bootmem + * allocator. There is only 1 field (bdata) in the boot_pg_data that + * is ever used. Bdata is used by the bootmem allocator to locate the bootmem_data_t + * structure for the node. + * + * The following structure is used during boot as the pg_data structure for all + * nodes. By casting boot_pg_data[n] to the pg_data_t structure for node n, we can + * compress the space required for the pg_data array. + * + */ +static long boot_pg_data[8*PLAT_MAX_COMPACT_NODES+sizeof(pg_data_t)] __initdata; + +static pg_data_t *pg_data_ptr[PLAT_MAX_COMPACT_NODES] __initdata; +static ia64_node_data_t *node_data[PLAT_MAX_COMPACT_NODES] __initdata; +static bootmem_data_t bdata[PLAT_MAX_COMPACT_NODES][PLAT_CLUMPS_PER_NODE+1] __initdata; + +static char node_has_memory[PLAT_MAX_COMPACT_NODES]; +struct page *invalid_mem_map; /* value returned by virt_to_page for bad addresses */ + +extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg); + +/* + * Return the compact node number of this cpu. Used prior to + * setting up the cpu_data area. + * Note - not fast, intended for boot use only!! + */ +int __init +boot_get_local_cnodeid(void) +{ + int i; + + for (i=0; ibdata; + epfn = CHUNKROUNDUP(pstart + length) >> PAGE_SHIFT; + cstart = pstart & ~(PLAT_CLUMPSIZE - 1); + + node_has_memory[cnodeid] = 1; + + while (bdp->node_low_pfn) { + /* if this is part of a block that we have already seen */ + if (cstart == bdp->node_boot_start) { + bdp->node_low_pfn = MAX(bdp->node_low_pfn, epfn); + break; + } + /* if this block immediately follows a block that is >= 95% full */ + if ((cstart>>PAGE_SHIFT) < bdp->node_low_pfn || + (cstart>>PAGE_SHIFT) - bdp->node_low_pfn < (PLAT_CLUMPSIZE>>PAGE_SHIFT)/20) { + bdp->node_low_pfn = epfn; + break; + } + if (i++ == PLAT_CLUMPS_PER_NODE) { + printk("Lost %ld bytes at %lx\n", length, pstart); + return 0; + } + bdp++; + } + if (bdp->node_low_pfn == 0) { + bdp->node_boot_start = cstart; + bdp->node_low_pfn = epfn; + } + + min_low_pfn = MIN(min_low_pfn, bdp->node_boot_start>>PAGE_SHIFT); + max_low_pfn = MAX(max_low_pfn, bdp->node_low_pfn); + + return 0; +} + +/* + * Find space on each node for the bootmem map. + * + * Called by efi_memmap_walk to find boot memory on each node. Note that + * only blocks that are free are passed to this routine (currently filtered by + * free_available_memory). + */ +static int __init +find_bootmap_space(unsigned long pstart, unsigned long length, int cnodeid) +{ + unsigned long mapsize, pages, epfn; + bootmem_data_t *bdp; + + epfn = (pstart + length) >> PAGE_SHIFT; + bdp = &pg_data_ptr[cnodeid]->bdata[0]; + while (bdp->node_low_pfn) { + if (pstart >= bdp->node_boot_start && epfn <= bdp->node_low_pfn) + break; + bdp++; + } + if (bdp->node_low_pfn == 0) + return 0; + + if (!bdp->node_bootmem_map) { + pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT); + mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT; + if (length > mapsize) { + init_bootmem_node( + BOOT_NODE_DATA(cnodeid), + pstart>>PAGE_SHIFT, + bdp->node_boot_start>>PAGE_SHIFT, + bdp->node_low_pfn); + } + + } + + return 0; +} + + +/* + * Free available memory to the bootmem allocator. + * + * Note that only blocks that are free are passed to this routine (currently + * filtered by free_available_memory). + * + */ +static int __init +discontig_free_bootmem_node(unsigned long pstart, unsigned long length, int cnodeid) +{ + free_bootmem_node(BOOT_NODE_DATA(cnodeid), pstart, length); + + return 0; +} + + +/* + * Reserve the space used by the bootmem maps. + */ +static void __init +discontig_reserve_bootmem(void) +{ + int cnodeid; + unsigned long mapbase, mapsize, pages; + bootmem_data_t *bdp; + + for (cnodeid=0; cnodeid < numnodes; cnodeid++) { + bdp = BOOT_NODE_DATA(cnodeid)->bdata; + + while (bdp->node_low_pfn) { + pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT); + mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT; + mapbase = __pa(bdp->node_bootmem_map); + reserve_bootmem_node(BOOT_NODE_DATA(cnodeid), + mapbase, mapsize); + bdp++; + } + } +} + + + +/* + * Allocate per node tables. + * - the pg_data structure is allocated on each node. This minimizes offnode + * memory references + * - the node data is allocated & initialized. Portions of this structure is read-only (after + * boot) and contains node-local pointers to usefuls data structures located on + * other nodes. + * + * We also switch to using the "real" pg_data structures at this point. Earlier in boot, we + * use a different structure. The only use for pg_data prior to the point in boot is to get + * the pointer to the bdata for the node. + */ +static void __init +allocate_pernode_structures(void) +{ + pg_data_t *pgdat=0, *new_pgdat_list=0; + int pxm, cnodeid, mycnodeid, alloc_cnodeid; + + mycnodeid = boot_get_local_cnodeid(); + for (cnodeid=numnodes-1; cnodeid>=0 ; cnodeid--) { + alloc_cnodeid = node_has_memory[cnodeid] ? cnodeid : mycnodeid; + node_data[cnodeid] = alloc_bootmem_node(BOOT_NODE_DATA(alloc_cnodeid), sizeof (ia64_node_data_t)); + + /* + * On SN platforms, we need to make sure that the pg_data structures dont alias + * to the same L1/2/3/4 cache lines. First attempt at making structures node local had + * 3x degradation for a simple page fault. The degradation was caused by aliasing. + * The pgdata structures on all nodes were located at the same node offset. + * + * To prevent aliasing, we use the "goal" parameter of the boot memory allocator + * to specify the lowest acceptible address for allocations. New allocations must + * start after the end of the physical page of the previous allocation, adjusted + * for node numbers. + * + * We could also make a change in the bootmem allocator but that requires changes + * to base linux. Preliminary experiments didnt show any performance advantage + * in changing the bootmem allocator. + * + * Not sure if this problem is SN specific or not..... + * ZZZ - I dont like this method - find a better way ZZZ + */ + pgdat = __alloc_bootmem_node(BOOT_NODE_DATA(alloc_cnodeid), sizeof(pg_data_t), SMP_CACHE_BYTES, + PLAT_BOOTMEM_ALLOC_GOAL(alloc_cnodeid, pgdat+1)); + pgdat->bdata = &(bdata[cnodeid][0]); + pg_data_ptr[cnodeid] = pgdat; + pgdat->node_id = cnodeid; + pgdat->node_next = new_pgdat_list; + new_pgdat_list = pgdat; + + } + + memcpy(node_data[mycnodeid]->pg_data_ptrs, pg_data_ptr, sizeof(pg_data_ptr)); + memcpy(node_data[mycnodeid]->node_data_ptrs, node_data, sizeof(node_data)); + + pgdat_list = new_pgdat_list; + + + memset(node_data[mycnodeid]->physical_node_map, -1, sizeof(node_data[mycnodeid]->physical_node_map)); + for (pxm=0; pxmphysical_node_map[PLAT_PXM_TO_PHYS_NODE_NUMBER(pxm)] = pxm_to_nid_map[pxm]; + +} + + + +/* + * Called early in boot to setup the boot memory allocator, and to + * allocate the node-local pg_data & node-directory data structures.. + */ +void __init +discontig_mem_init(void) +{ + int cnodeid; + + for (cnodeid=0; cnodeidbdata = &bdata[cnodeid][0]; + } + + min_low_pfn = -1; + max_low_pfn = 0; + + + efi_memmap_walk(filter_rsvd_memory, build_maps); + efi_memmap_walk(filter_rsvd_memory, find_bootmap_space); + efi_memmap_walk(filter_rsvd_memory, discontig_free_bootmem_node); + discontig_reserve_bootmem(); + allocate_pernode_structures(); +} + + + +/* + * Add zones of the other nodes to zonelists + */ +static void +build_zonelists_others(int local_node) +{ + int i, j, k, cnodeid; + pg_data_t *pgdat, *node; + zonelist_t *zonelist; + zone_t *zone; + + pgdat = NODE_DATA(local_node); + + for (i = 0; i <= GFP_ZONEMASK; i++) { + + zonelist = pgdat->node_zonelists + i; + + /* find bottom of the list */ + for (j = 0; zonelist->zones[j] ;j++); + + k = ZONE_NORMAL; + if (i & __GFP_HIGHMEM) + k = ZONE_HIGHMEM; + if (i & __GFP_DMA) + k = ZONE_DMA; + + /* + * Now we build the zonelist so that it contains the zones + * of all the other nodes. + */ + + for (cnodeid=local_node+1; local_node!=(cnodeid%numnodes); cnodeid++){ + node = NODE_DATA(cnodeid % numnodes); + switch (k) { + default: + BUG(); + /* + * fallthrough: + */ + case ZONE_HIGHMEM: + zone = node->node_zones + ZONE_HIGHMEM; + if (zone->memsize) { +#ifndef CONFIG_HIGHMEM + BUG(); +#endif + zonelist->zones[j++] = zone; + } + case ZONE_NORMAL: + zone = node->node_zones + ZONE_NORMAL; + if (zone->memsize) + zonelist->zones[j++] = zone; + + case ZONE_DMA: + zone = node->node_zones + ZONE_DMA; + if (zone->memsize) + zonelist->zones[j++] = zone; + } + } + zonelist->zones[j++] = NULL; + } +} + + + +/* + * Initialize the paging system. + * - determine sizes of each node + * - initialize the paging system for the node + * - build the nodedir for the node. This contains pointers to + * the per-bank mem_map entries. + * - fix the page struct "virtual" pointers. These are bank specific + * values that the paging system doesnt understand. + * - replicate the nodedir structure to other nodes + */ + +void __init +discontig_paging_init(void) +{ + int i, cnodeid, mycnodeid; + unsigned long max_dma, zones_size[MAX_NR_ZONES]; + unsigned long kaddr, ekaddr, npages; + struct page *page; + bootmem_data_t *bdp; + + max_mapnr = 0; + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; + + + mycnodeid = boot_get_local_cnodeid(); + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { + long pfn, startpfn; + + if (!node_has_memory[cnodeid]) + continue; + + memset(zones_size, 0, sizeof(zones_size)); + + startpfn = -1; + bdp = BOOT_NODE_DATA(cnodeid)->bdata; + while (bdp->node_low_pfn) { + pfn = bdp->node_boot_start >> PAGE_SHIFT; + if (startpfn == -1) + startpfn = pfn; + if (pfn > max_dma) + zones_size[ZONE_NORMAL] += (bdp->node_low_pfn - pfn); + else if (bdp->node_low_pfn < max_dma) + zones_size[ZONE_DMA] += (bdp->node_low_pfn - pfn); + else { + zones_size[ZONE_DMA] += (max_dma - pfn); + zones_size[ZONE_NORMAL] += (bdp->node_low_pfn - max_dma); + } + bdp++; + } + + free_area_init_node(cnodeid, NODE_DATA(cnodeid), NULL, zones_size, startpfn<node_mem_map; + + bdp = BOOT_NODE_DATA(cnodeid)->bdata; + + while (bdp->node_low_pfn) { + kaddr = (unsigned long)__va(bdp->node_boot_start); + ekaddr = (unsigned long)__va(bdp->node_low_pfn << PAGE_SHIFT); + while (kaddr < ekaddr) { + node_data[mycnodeid]->clump_mem_map_base[PLAT_CLUMP_MEM_MAP_INDEX(kaddr)] = page; + npages = PLAT_CLUMPSIZE/PAGE_SIZE; + if (kaddr + (npages< ekaddr) + npages = (ekaddr - kaddr) >> PAGE_SHIFT; + for (i = 0; i < npages; i++, page++, kaddr += PAGE_SIZE) + page->virtual = (void*)kaddr; + } + bdp++; + } + max_mapnr = MAX(max_mapnr, page - mem_map); + } + + /* build_all_zonelists */ + for (cnodeid=0; cnodeid < numnodes; cnodeid++) { + build_zonelists_others(cnodeid); + } + + /* + * Finish setting up the node data for this node, then copy it to the other nodes. + */ + for (cnodeid=0; cnodeid < numnodes; cnodeid++) + if (mycnodeid != cnodeid) { + memcpy(node_data[cnodeid], node_data[mycnodeid], sizeof(ia64_node_data_t)); + node_data[cnodeid]->cnodeid = cnodeid; + node_data[cnodeid]->active_cpu_count = 0; + } + + invalid_mem_map = mem_map + max_mapnr; +} diff -Nur linux-2.4.19/arch/ia64/mm/extable.c linux-2.4.19-sgi211r3/arch/ia64/mm/extable.c --- linux-2.4.19/arch/ia64/mm/extable.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/mm/extable.c Fri Apr 26 11:07:18 2002 @@ -6,9 +6,8 @@ */ #include - +#include #include -#include extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; @@ -16,28 +15,28 @@ static inline const struct exception_table_entry * search_one_table (const struct exception_table_entry *first, const struct exception_table_entry *last, - unsigned long ip, unsigned long gp) + unsigned long value) { + /* Abort early if the search value is out of range. */ + if (value < first->addr || value > last->addr) + return 0; + while (first <= last) { const struct exception_table_entry *mid; long diff; mid = &first[(last - first)/2]; - diff = (mid->addr + gp) - ip; + diff = mid->addr - value; if (diff == 0) return mid; else if (diff < 0) - first = mid + 1; + first = mid+1; else - last = mid - 1; + last = mid-1; } return 0; } -#ifndef CONFIG_MODULES -register unsigned long main_gp __asm__("gp"); -#endif - struct exception_fixup search_exception_table (unsigned long addr) { @@ -46,9 +45,9 @@ #ifndef CONFIG_MODULES /* There is only the kernel to search. */ - entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr, main_gp); + entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr); if (entry) - fix.cont = entry->cont + main_gp; + fix.cont = entry->cont; return fix; #else struct archdata *archdata; @@ -58,13 +57,9 @@ for (mp = module_list; mp; mp = mp->next) { if (!mp->ex_table_start) continue; - archdata = (struct archdata *) mp->archdata_start; - if (!archdata) - continue; - entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, - addr, (unsigned long) archdata->gp); + entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); if (entry) { - fix.cont = entry->cont + (unsigned long) archdata->gp; + fix.cont = entry->cont; return fix; } } diff -Nur linux-2.4.19/arch/ia64/mm/fault.c linux-2.4.19-sgi211r3/arch/ia64/mm/fault.c --- linux-2.4.19/arch/ia64/mm/fault.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/mm/fault.c Mon Oct 28 20:43:23 2002 @@ -49,7 +49,6 @@ int signal = SIGSEGV, code = SEGV_MAPERR; struct vm_area_struct *vma, *prev_vma; struct mm_struct *mm = current->mm; - struct exception_fixup fix; struct siginfo si; unsigned long mask; @@ -59,6 +58,17 @@ if (in_interrupt() || !mm) goto no_context; +#ifdef CONFIG_VIRTUAL_MEM_MAP + /* + * If fault is in region 5 and we are in the kernel, we may already + * have the mmap_sem (VALID_PAGE macro is called during mmap). There + * should be no vma for region 5 addr's anyway, so skip getting the + * semaphore and go directly to the code that handles a bad area. + */ + if ((REGION_NUMBER(address) == 5) && !user_mode(regs)) + goto bad_area_no_up; +#endif + down_read(&mm->mmap_sem); vma = find_vma_prev(mm, address, &prev_vma); @@ -138,10 +148,16 @@ bad_area: up_read(&mm->mmap_sem); - if (isr & IA64_ISR_SP) { +#ifdef CONFIG_VIRTUAL_MEM_MAP + bad_area_no_up: +#endif + if ((isr & IA64_ISR_SP) + || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) + { /* - * This fault was due to a speculative load set the "ed" bit in the psr to - * ensure forward progress (target register will get a NaT). + * This fault was due to a speculative load or lfetch.fault, set the "ed" + * bit in the psr to ensure forward progress. (Target register will get a + * NaT for ld.s, lfetch will be canceled.) */ ia64_psr(regs)->ed = 1; return; @@ -167,15 +183,8 @@ return; } -#ifdef GAS_HAS_LOCAL_TAGS - fix = search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); -#else - fix = search_exception_table(regs->cr_iip); -#endif - if (fix.cont) { - handle_exception(regs, fix); + if (done_with_exception(regs)) return; - } /* * Oops. The kernel tried to access some bad page. We'll have to terminate things @@ -196,8 +205,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -Nur linux-2.4.19/arch/ia64/mm/init.c linux-2.4.19-sgi211r3/arch/ia64/mm/init.c --- linux-2.4.19/arch/ia64/mm/init.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/mm/init.c Fri Feb 7 12:02:39 2003 @@ -1,8 +1,8 @@ /* * Initialize MMU support. * - * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang + * Copyright (C) 1998-2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include #include @@ -10,13 +10,16 @@ #include #include +#include #include #include #include +#include +#include +#include #include #include -#include #include #include #include @@ -26,16 +29,172 @@ #include #include +#ifndef CONFIG_NUMA mmu_gather_t mmu_gathers[NR_CPUS]; +#endif + /* References to section boundaries: */ -extern char _stext, _etext, _edata, __init_begin, __init_end; +extern char _stext, _etext, _edata, __init_begin, __init_etext, __init_sdata, __init_end; extern void ia64_tlb_init (void); +#ifdef CONFIG_IA64_SGI_SN +/* + * SGI SN has no restrictions on MAX DMA address. + */ +unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + PLAT_MAX_PHYS_MEMORY; +#else unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; +#endif static unsigned long totalram_pages; +struct page *zero_page_memmap_ptr; /* map entry for zero page */ + +#ifdef CONFIG_NUMA + +/* + * Set ktreplicate to 0 to disable kernel text replication. + */ +static int ktreplicate=0; + +static int __init replicate_setup(char *str) +{ + get_option(&str, &ktreplicate); + return 1; +} + +__setup("ktreplicate=", replicate_setup); + + +/* + * Addresses of per-node copies of kernel text/readonly-data + */ +unsigned long kcopybase[PLAT_MAX_COMPACT_NODES]; + +/* + * make properly aligned copies of kernel text and read-only + * data on other nodes. + */ +static void +replicate_kernel(void) +{ + cnodeid_t cnodeid; + char *kpage; + unsigned long kstart = (unsigned long)&_stext; + unsigned long kend = (unsigned long)&__init_etext; + unsigned long size; + cnodeid_t kloadnode; + int cpuid; + extern void ia64_remap_kernel(long); + + memset(kcopybase, -1, sizeof(kcopybase)); + + if (!ktreplicate) { + printk("Kernel text replication is disabled\n"); + return; + } + + kloadnode = paddr_to_nid(__tpa(&kcopybase[0])); + kcopybase[kloadnode] = __imva(&kcopybase[0]) & ~(KERNEL_TR_PAGE_SIZE - 1); + + /* + * Copy to all of the other nodes + */ + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { + if (cnodeid == kloadnode) + continue; + size = kend & (KERNEL_TR_PAGE_SIZE - 1); + size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + /* allocate big page aligned from target node */ + kpage = __alloc_bootmem_node(BOOT_NODE_DATA(cnodeid), size, + KERNEL_TR_PAGE_SIZE, 0L); + + if (kpage == 0) { + printk("Could not replicate kernel to node %d\n", cnodeid); + continue; + } + + /* + * Kernel (_stext) probably does not begin on a big page + * boundary. Free up any pages before needed portion + */ + size = kstart & (KERNEL_TR_PAGE_SIZE - 1); + if (size) + free_bootmem_node(BOOT_NODE_DATA(cnodeid), + __pa(kpage), size); + + kcopybase[cnodeid] = (unsigned long)kpage; + + /* now make the copy */ + memcpy(kpage + size, &_stext, kend-kstart); + + printk("Replicated kernel to %p on node %d\n", (long*)(kpage + size), cnodeid); + } + + /* + * Search the node_cpuid table for our hard_processor_id. We + * are not necessarily on the first cpu in the list. + */ + for (cpuid=0; cpuid +int kdba_putarea_size(unsigned long to_xxx, void *from, size_t size) +{ + unsigned long kstart = (unsigned long)&_stext; + unsigned long kend = (unsigned long)&__init_etext; + cnodeid_t cnodeid; + unsigned long addr; + int ret = 0; + if (!ktreplicate) + return __kdba_putarea_size(to_xxx, from, size); + if ((to_xxx < kstart && to_xxx+size > kstart) || + (to_xxx < kend && to_xxx+size > kend)) { + kdb_printf("%s: area to update %lx(%ld) incompletely overlaps the replicated text\n", + __FUNCTION__, to_xxx, size); + return -EFAULT; + } + if (to_xxx < kstart || to_xxx >= kend) + return __kdba_putarea_size(to_xxx, from, size); + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { + addr = to_xxx - kstart + kcopybase[cnodeid] + (kstart & (KERNEL_TR_PAGE_SIZE - 1)); + if ((ret = __kdba_putarea_size(addr, from, size))) { + kdb_printf("%s: failed to update %lx on node %d, replicated kernels may be inconsistent\n", + __FUNCTION__, addr, cnodeid); + break; + } + } + return ret; +} + +/* Read from the local address, every replicated copy should be identical */ +int kdba_getarea_size(void *to, unsigned long from_xxx, size_t size) +{ + return __kdba_getarea_size(to, from_xxx, size); +} +#endif /* defined(CONFIG_NUMA_REPLICATE) && defined (CONFIG_KDB) */ +#endif + +#ifdef CONFIG_VIRTUAL_MEM_MAP +unsigned long vmalloc_end = VMALLOC_END_INIT; + +static struct page *vmem_map; +static unsigned long num_dma_physpages; +#endif int do_check_pgt_cache (int low, int high) @@ -67,40 +226,91 @@ struct vm_area_struct *vma; /* - * If we're out of memory and kmem_cache_alloc() returns NULL, - * we simply ignore the problem. When the process attempts to - * write to the register backing store for the first time, it - * will get a SEGFAULT in this case. + * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore + * the problem. When the process attempts to write to the register backing store + * for the first time, it will get a SEGFAULT in this case. */ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (vma) { vma->vm_mm = current->mm; vma->vm_start = IA64_RBS_BOT; vma->vm_end = vma->vm_start + PAGE_SIZE; - vma->vm_page_prot = PAGE_COPY; + vma->vm_page_prot = protection_map[VM_READ | VM_WRITE]; vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; vma->vm_ops = NULL; vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; +#ifdef CONFIG_CPUMEMSET + vma->vm_mems_allowed = cms_current_mems_allowed(); +#endif insert_vm_struct(current->mm, vma); } + + /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ + if (!(current->personality & MMAP_PAGE_ZERO)) { + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + memset(vma, 0, sizeof(*vma)); + vma->vm_mm = current->mm; + vma->vm_end = PAGE_SIZE; + vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); + vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED; +#ifdef CONFIG_CPUMEMSET + vma->vm_mems_allowed = cms_current_mems_allowed(); +#endif + insert_vm_struct(current->mm, vma); + } + } } void free_initmem (void) { - unsigned long addr; + unsigned long addr, eaddr; + unsigned long pages_freed = 0; - addr = (unsigned long) &__init_begin; - for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) { +#ifdef CONFIG_NUMA + cnodeid_t cnodeid; + cnodeid_t kloadnode; + + kloadnode = paddr_to_nid(__tpa(&kcopybase[0])); + + /* Also free copy of __init text from each node */ + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { + if (kcopybase[cnodeid] == ~0UL) + continue; + addr = kcopybase[cnodeid] + + (__imva(&__init_begin) & (KERNEL_TR_PAGE_SIZE-1)); + if (cnodeid == kloadnode) + eaddr = kcopybase[cnodeid] + + (__imva(&__init_end) & (KERNEL_TR_PAGE_SIZE-1)); + else + eaddr = kcopybase[cnodeid] + + (__imva(&__init_etext) & (KERNEL_TR_PAGE_SIZE-1)); + printk("Node %d: free from %lx to %lx\n", cnodeid, addr, eaddr); + for (; addr < eaddr; addr += PAGE_SIZE) { + clear_bit(PG_reserved, &virt_to_page(addr)->flags); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + ++totalram_pages; + ++pages_freed; + } + } +#else + addr = __imva(&__init_begin); + eaddr = __imva(&__init_end); + for (; addr < eaddr; addr += PAGE_SIZE) { clear_bit(PG_reserved, &virt_to_page(addr)->flags); set_page_count(virt_to_page(addr), 1); free_page(addr); ++totalram_pages; + ++pages_freed; } - printk (KERN_INFO "Freeing unused kernel memory: %ldkB freed\n", - (&__init_end - &__init_begin) >> 10); +#endif + + printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n", + (pages_freed << PAGE_SHIFT) >> 10); } void @@ -141,7 +351,7 @@ end = end & PAGE_MASK; if (start < end) - printk (KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); + printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { if (!VALID_PAGE(virt_to_page(start))) @@ -169,55 +379,80 @@ void show_mem(void) { - int i, total = 0, reserved = 0; - int shared = 0, cached = 0; - printk("Mem-info:\n"); +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) show_free_areas(); +#endif #ifdef CONFIG_DISCONTIGMEM { - pg_data_t *pgdat = pgdat_list; - - printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - do { - printk("Node ID: %d\n", pgdat->node_id); + int i, nid; + int reserved, cached, slab, free, active; + pg_data_t *pgdat; + zone_t *zone; + + printk("%4s %7s %7s %9s %7s %7s %7s\n", "node","total", + "free","reserved","swap","slab","active"); + + /* + * Iterate over each node's pg_data_t and look at its pages + */ + for(nid = 0; nid < numnodes; nid++) { + pgdat = NODE_DATA(nid); + reserved = cached = slab = free = active = 0; + + /* + * Get info about each page in the node + */ + printk("%4d ", pgdat->node_id); for(i = 0; i < pgdat->node_size; i++) { - if (PageReserved(pgdat->node_mem_map+i)) + if (PageReserved(pgdat->node_mem_map + i)) reserved++; - else if (PageSwapCache(pgdat->node_mem_map+i)) + if (PageSwapCache(pgdat->node_mem_map + i)) cached++; - else if (page_count(pgdat->node_mem_map + i)) - shared += page_count(pgdat->node_mem_map + i) - 1; + if (PageSlab(pgdat->node_mem_map + i)) + slab++; + if (PageActive(pgdat->node_mem_map + i)) + active++; } - printk("\t%d pages of RAM\n", pgdat->node_size); - printk("\t%d reserved pages\n", reserved); - printk("\t%d pages shared\n", shared); - printk("\t%d pages swap cached\n", cached); - pgdat = pgdat->node_next; - } while (pgdat); - printk("Total of %ld pages in page table cache\n", pgtable_cache_size); + for (zone = pgdat->node_zones; + zone < pgdat->node_zones + MAX_NR_ZONES; zone++) + free += zone->free_pages; + + printk("%7ld ", pgdat->node_size); + printk("%7d ", free); + printk("%9d ", reserved); + printk("%7d ", cached); + printk("%7d ", slab); + printk("%7d\n", active); + } show_buffers(); - printk("%d free buffer pages\n", nr_free_buffer_pages()); } #else /* !CONFIG_DISCONTIGMEM */ - printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - i = max_mapnr; - while (i-- > 0) { - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (PageSwapCache(mem_map+i)) - cached++; - else if (page_count(mem_map + i)) - shared += page_count(mem_map + i) - 1; - } - printk("%d pages of RAM\n", total); - printk("%d reserved pages\n", reserved); - printk("%d pages shared\n", shared); - printk("%d pages swap cached\n", cached); - printk("%ld pages in page table cache\n", pgtable_cache_size); - show_buffers(); + { + int i, total = 0, reserved = 0; + int shared = 0, cached = 0; + + printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + if (!VALID_PAGE(mem_map + i)) + continue; + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (page_count(mem_map + i)) + shared += page_count(mem_map + i) - 1; + } + printk("%d pages of RAM\n", total); + printk("%d reserved pages\n", reserved); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n", cached); + printk("%ld pages in page table cache\n", pgtable_cache_size); + show_buffers(); + } #endif /* !CONFIG_DISCONTIGMEM */ } @@ -234,7 +469,7 @@ if (!PageReserved(page)) printk("put_gate_page: gate page at 0x%p not in reserved memory\n", - page_address(page)); + (long*)page_address(page)); pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ @@ -261,7 +496,7 @@ void __init ia64_mmu_init (void *my_cpu_data) { - unsigned long flags, rid, pta, impl_va_bits; + unsigned long psr, rid, pta, impl_va_bits; extern void __init tlb_init (void); #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 @@ -273,7 +508,7 @@ * Set up the kernel identity mapping for regions 6 and 5. The mapping for region * 7 is setup up in _start(). */ - ia64_clear_ic(flags); + psr = ia64_clear_ic(); rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2)); @@ -285,9 +520,9 @@ ia64_srlz_d(); ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, - pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)), PAGE_SHIFT); + pte_val(mk_pte_phys(__tpa(my_cpu_data), PAGE_KERNEL)), PAGE_SHIFT); - __restore_flags(flags); + ia64_set_psr(psr); ia64_srlz_i(); /* @@ -335,21 +570,195 @@ ia64_tlb_init(); } +#ifdef CONFIG_VIRTUAL_MEM_MAP + +#include + +static int +create_mem_map_page_table (u64 start, u64 end, void *arg) +{ + unsigned long address, start_page, end_page; + struct page *map_start, *map_end; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + /* should we use platform_map_nr here? */ + + map_start = vmem_map + MAP_NR_DENSE(start); + map_end = vmem_map + MAP_NR_DENSE(end); + + start_page = (unsigned long) map_start & PAGE_MASK; + end_page = PAGE_ALIGN((unsigned long) map_end); + + for (address = start_page; address < end_page; address += PAGE_SIZE) { + pgd = pgd_offset_k(address); + if (pgd_none(*pgd)) + pgd_populate(&init_mm, pgd, alloc_bootmem_pages(PAGE_SIZE)); + pmd = pmd_offset(pgd, address); + + if (pmd_none(*pmd)) + pmd_populate(&init_mm, pmd, alloc_bootmem_pages(PAGE_SIZE)); + pte = pte_offset(pmd, address); + + if (pte_none(*pte)) + set_pte(pte, mk_pte_phys(__pa(alloc_bootmem_pages(PAGE_SIZE)), + PAGE_KERNEL)); + } + return 0; +} + +struct memmap_init_callback_data { + memmap_init_callback_t *memmap_init; + struct page *start; + struct page *end; + int zone; + int highmem; +}; + +static int +virtual_memmap_init (u64 start, u64 end, void *arg) +{ + struct memmap_init_callback_data *args; + struct page *map_start, *map_end; + + args = (struct memmap_init_callback_data *) arg; + + /* Should we use platform_map_nr here? */ + + map_start = vmem_map + MAP_NR_DENSE(start); + map_end = vmem_map + MAP_NR_DENSE(end); + + if (map_start < args->start) + map_start = args->start; + if (map_end > args->end) + map_end = args->end; + + /* + * We have to initialize "out of bounds" struct page elements + * that fit completely on the same pages that were allocated + * for the "in bounds" elements because they may be referenced + * later (and found to be "reserved"). + */ + map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1)) + / sizeof(struct page); + map_end += ((PAGE_ALIGN((unsigned long) map_end) - + (unsigned long) map_end) + / sizeof(struct page)); + + if (map_start < map_end) + (*args->memmap_init)(map_start, map_end, args->zone, + page_to_phys(map_start), args->highmem); + + return 0; +} + +unsigned long +arch_memmap_init (memmap_init_callback_t *memmap_init, struct page *start, + struct page *end, int zone, unsigned long start_paddr, int highmem) +{ + struct memmap_init_callback_data args; + + args.memmap_init = memmap_init; + args.start = start; + args.end = end; + args.zone = zone; + args.highmem = highmem; + + efi_memmap_walk(virtual_memmap_init, &args); + + return page_to_phys(end); +} + +static int +count_dma_pages (u64 start, u64 end, void *arg) +{ + unsigned long *count = arg; + + if (end <= MAX_DMA_ADDRESS) + *count += (end - start) >> PAGE_SHIFT; + return 0; +} + +int +ia64_page_valid (struct page *page) +{ + char byte; + + return __get_user(byte, (char *) page) == 0; +} + +#endif /* CONFIG_VIRTUAL_MEM_MAP */ + +static int +count_pages (u64 start, u64 end, void *arg) +{ + unsigned long *count = arg; + + *count += (end - start) >> PAGE_SHIFT; + return 0; +} + /* * Set up the page tables. */ void paging_init (void) { - unsigned long max_dma, zones_size[MAX_NR_ZONES]; - - clear_page((void *) ZERO_PAGE_ADDR); +#ifndef CONFIG_DISCONTIGMEM + unsigned long max_dma; +#endif + unsigned long zones_size[MAX_NR_ZONES]; /* initialize mem_map[] */ memset(zones_size, 0, sizeof(zones_size)); + num_physpages = 0; + efi_memmap_walk(count_pages, &num_physpages); + +#ifdef CONFIG_DISCONTIGMEM + { + extern void discontig_paging_init(void); + discontig_paging_init(); + } +#else max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; + +#ifdef CONFIG_VIRTUAL_MEM_MAP + { + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long map_size; + + memset(zholes_size, 0, sizeof(zholes_size)); + + num_dma_physpages = 0; + efi_memmap_walk(count_dma_pages, &num_dma_physpages); + + if (max_low_pfn < max_dma) { + zones_size[ZONE_DMA] = max_low_pfn; + zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages; + } else { + zones_size[ZONE_DMA] = max_dma; + zholes_size[ZONE_DMA] = max_dma - num_dma_physpages; + if (num_physpages > num_dma_physpages) { + zones_size[ZONE_NORMAL] = max_low_pfn - max_dma; + zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma) + - (num_physpages - num_dma_physpages)); + } + } + + /* allocate virtual mem_map: */ + + map_size = PAGE_ALIGN(max_low_pfn*sizeof(struct page)); + vmalloc_end -= map_size; + vmem_map = (struct page *) vmalloc_end; + efi_memmap_walk(create_mem_map_page_table, 0); + + free_area_init_node(0, NULL, vmem_map, zones_size, 0, zholes_size); + printk("Virtual mem_map starts at 0x%p\n", mem_map); + } +#else /* !CONFIG_VIRTUAL_MEM_MAP */ if (max_low_pfn < max_dma) zones_size[ZONE_DMA] = max_low_pfn; else { @@ -357,27 +766,20 @@ zones_size[ZONE_NORMAL] = max_low_pfn - max_dma; } free_area_init(zones_size); -} - -static int -count_pages (u64 start, u64 end, void *arg) -{ - unsigned long *count = arg; +#endif /* !CONFIG_VIRTUAL_MEM_MAP */ +#endif /* CONFIG_DISCONTIGMEM */ - *count += (end - start) >> PAGE_SHIFT; - return 0; + zero_page_memmap_ptr = virt_to_page(__imva(empty_zero_page)); } static int count_reserved_pages (u64 start, u64 end, void *arg) { - unsigned long num_reserved = 0; unsigned long *count = arg; - struct page *pg; - - for (pg = virt_to_page(start); pg < virt_to_page(end); ++pg) - if (PageReserved(pg)) - ++num_reserved; + unsigned long num_reserved = 0; + for (; start < end; start += PAGE_SIZE) + if (PageReserved(virt_to_page(start))) + ++num_reserved; *count += num_reserved; return 0; } @@ -401,25 +803,27 @@ if (!mem_map) BUG(); - num_physpages = 0; - efi_memmap_walk(count_pages, &num_physpages); - +#ifndef CONFIG_DISCONTIGMEM max_mapnr = max_low_pfn; +#endif high_memory = __va(max_low_pfn * PAGE_SIZE); +#ifdef CONFIG_NUMA + replicate_kernel(); +#endif totalram_pages += free_all_bootmem(); reserved_pages = 0; efi_memmap_walk(count_reserved_pages, &reserved_pages); - codesize = (unsigned long) &_etext - (unsigned long) &_stext; - datasize = (unsigned long) &_edata - (unsigned long) &_etext; - initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + codesize = &_etext - &_stext; + datasize = &_edata - &__init_end; + initsize = (&__init_etext - &__init_begin) + (&__init_end - &__init_sdata); - printk("Memory: %luk/%luk available (%luk code, %luk reserved, %luk data, %luk init)\n", + printk(KERN_INFO "Memory: %luk/%luk available (%luk code, %luk reserved, %luk data, %luk init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10), - max_mapnr << (PAGE_SHIFT - 10), codesize >> 10, reserved_pages << (PAGE_SHIFT - 10), - datasize >> 10, initsize >> 10); + num_physpages << (PAGE_SHIFT - 10), codesize >> 10, + reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10); /* * Allow for enough (cached) page table pages so that we can map the entire memory @@ -434,10 +838,115 @@ if (num_pgt_pages > pgt_cache_water[1]) pgt_cache_water[1] = num_pgt_pages; + show_mem() ; + /* install the gate page in the global page table: */ - put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR); + put_gate_page(virt_to_page(__imva(__start_gate_section)), GATE_ADDR); #ifdef CONFIG_IA32_SUPPORT ia32_gdt_init(); #endif + +} + + + + +/**********************************************************************************************/ +#ifdef CONFIG_IA64_SGI_SN_DEBUG +/* + * Debug versions of __va, __pa, __imva & _tpa. These routines + * catch common misuse of the macros. + * + * See include/asm-ia64/page.h for more details + * + */ + + +#define __xva(x) ({ia64_va _v; _v.l = (long) (x); _v.f.reg = -1; _v.p;}) +#define __xtpa(x) ({ia64_va _v; asm("tpa %0=%1" : "=r"(_v.l) : "r"(x)); _v.l;}) + + +extern char _end; +extern char __gp; + +void +bkpt(long l, int i) +{ + i = i; +} + +unsigned long +__pa_debug(long v) +{ + ia64_va a; + int reg; + + a.l = v; + reg = a.f.reg; + a.f.reg = 0; + if (v != 0 && (reg < 6 || (v != MAX_DMA_ADDRESS && a.l != __xtpa(v)))) { + bkpt(v, 0); + printk("BUG __pa 0x%lx, from 0x%lx\n", v, (unsigned long) __builtin_return_address(0)); + panic ("__pa_debug"); + } + return a.l; +} + +void * +__va_debug(long p) +{ + ia64_va a; + int reg; + + a.l = p; + reg = a.f.reg; + a.f.reg = 7; + if (reg != 0 || __xtpa(a.p) != p) { + bkpt(p, 1); + printk("BUG __va 0x%lx, from 0x%lx\n", p, (unsigned long) __builtin_return_address(0)); + panic ("__va_debug"); + } + return a.p; +} + +unsigned long +__tpa_debug(long v) +{ + ia64_va a; + + a.l = v; + if (a.f.reg < 5) { + bkpt(v, 2); + printk("BUG __tpa 0x%lx, from 0x%lx\n", v, (unsigned long) __builtin_return_address(0)); + panic ("__tpa_debug"); + } + + return __xtpa(v); } + + +unsigned long +__imva_debug(long v) +{ + ia64_va a; + unsigned long p; + + a.l = v; + if (a.f.reg != 7) { + bkpt(v, 3); + printk("BUG __imva 0x%lx, from 0x%lx\n", v, (unsigned long) __builtin_return_address(0)); + panic ("__imva_debug"); + } + + p = __xtpa(v); + a.l = p; + a.f.reg = 7; + if (__xtpa(a.p) != p) { + bkpt(p, 4); + printk("BUG __imva 0x%lx -> 0x%lx, from 0x%lx\n", v, a.l, (unsigned long) __builtin_return_address(0)); + panic ("__imva_debug"); + } + return a.l; +} +#endif diff -Nur linux-2.4.19/arch/ia64/mm/tlb.c linux-2.4.19-sgi211r3/arch/ia64/mm/tlb.c --- linux-2.4.19/arch/ia64/mm/tlb.c Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/arch/ia64/mm/tlb.c Mon Oct 28 20:43:23 2002 @@ -48,6 +48,7 @@ { unsigned long tsk_context, max_ctx = ia64_ctx.max_ctx; struct task_struct *tsk; + int i; if (ia64_ctx.next > max_ctx) ia64_ctx.next = 300; /* skip daemons */ @@ -76,10 +77,14 @@ ia64_ctx.limit = tsk_context; } read_unlock(&tasklist_lock); - flush_tlb_all(); + //flush_tlb_all(); /* potential race condition with O(1) scheduler [EF] */ + for (i=0; itlb_flush = 1; + __flush_tlb_all(); + local_cpu_data->tlb_flush = 0; } -static inline void +void ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) { static spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; diff -Nur linux-2.4.19/arch/ia64/sn/configs/README linux-2.4.19-sgi211r3/arch/ia64/sn/configs/README --- linux-2.4.19/arch/ia64/sn/configs/README Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/README Thu Feb 20 19:55:58 2003 @@ -0,0 +1,208 @@ +* +* Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License +* as published by the Free Software Foundation. +* +* This program is distributed in the hope that it would be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* +* Further, this software is distributed without any warranty that it is +* free of the rightful claim of any third person regarding infringement +* or the like. Any license provided herein, whether implied or +* otherwise, applies only to this software file. Patent licenses, if +* any, provided herein do not apply to combinations of this program with +* other software, or any other product whatsoever. +* +* You should have received a copy of the GNU General Public +* License along with this program; if not, write the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +* +* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +* Mountain View, CA 94043, or: +* +* http://www.sgi.com +* +* For further information regarding this notice, see: +* +* http://oss.sgi.com/projects/GenInfo/NoticeExplan +* + +======================================================================== + +The default config files in this directory use the following naming convention: + + defconfig-$arch[-$option...] + +Arch values: + -dig IA64 DIG platform + -i386 x86 platform + -hpsim HP simulator (for test builds) + -sn1 sn1 + -sn2 sn2 + -tiger McKinley "Tiger" Software Development Vehicle (SDV) + +Options: + -underlay for the installer underlay CD + -sp CONFIG_SMP is *not* set. + -nomodules CONFIG_MODULES is *not* set + -stock SGI features (XFS, KDB, etc) are *not* set + -max-modules Everything possible is built as a module + -embedded-net For bringup...used to embed in the prom + +The "default" defconfig file for each arch is simply defconfig-$arch. +This turns into the primary kernel for our products, and it is what is +built by the "official" LBS builds. Below is the strategy or process +for generating/defining these "official" defconfig files. + +======================================================================== + +The Linux kernel "config" file determine what software is included in +Linux kernel builds, as well as whether some components are built as +modules or staticly linked into the kernel. For more information, see +linux/Documentation/Configure.help. + +Strategy for SGI defconfig files. + +1) Start with RedHat config file. + Red Hat has done a reasonable job of including things that most + people might need as modules, so people do no have to rebuild + their kernel. We have the same goal of not requiring the customer + the rebuild their kernel, and in fact our proprietary modules will + cause problems for customers who want to rebuild their kernel. + In addition, we want to be as compatible with Red Hat as possible, + so starting with their config files makes sense. + + For i386 compatibility builds, make i586 the baseline. + This allows old Pentiums to be used as test machines. + + +2) Red Hat's config files are based on whatever kernel they were using + when they released. Our kernels may be newer, and so may have + configuration decisions to make that Red Hat didn't. If we can + anticipate Red Hat's direction (by looking at the 7.3 i386 release, + for example), follow that. Otherwise, for these new items, add them + as modules if possible, else exclude them. Common sense should also + be applied here, if needed. + +3) Turn off device drivers for hardware devices SGI does not support. + Also turn off any other capabilities that are known not to work, + or are not applicable to SN. + +4) Change a number of items from modules to staticly linked. + -- Any device drivers required or used by SN. + -- Any SGI added features that don't have to be modules. + Some features might be modules for license or functional reasons. + +5) Apply any additonal changes, for tuning, configuration, etc. + +======================================================================== + + +As of RedHat 7.2, this means: + kernel-2.4.9-i586-smp.config + kernel-2.4.9-ia64-smp.config + +As of RedHat 7.3: + kernel-2.4.18-i586-smp.config + kernel-2.4.18-i686-smp.config + +# save a copy of what we start from for diffing +cp kernel-2.4.9-i586-smp.config rhconfig-i386 +cp kernel-2.4.9-ia64-smp.config rhconfig-ia64 + +# first versions are "stock" versions +cp rhconfig-i386 defconfig-i386-stock +cp rhconfig-ia64 defconfig-dig-stock + + # Make list of all new values: + cp linux/arch/ia64/sn/configs/new/defconfig-i386-stock \ + linux/arch/ia64/sn/configs/new/foo + while : ; do echo ; done | \ + leditconfig linux/arch/ia64/sn/configs/new/foo | \ + sed 's/(NEW)/(NEW) /g' | \ + grep NEW | \ + sed -e 's/.*CONFIG_/CONFIG_/' -e 's/).*$//' \ + > newvars + cp newvars linux/arch/ia64/sn/configs/new + cd linux/arch/ia64/sn/configs/new + cat newvars | while read var ; do + echo $var + grep -- "$var[ =]" kernel-2.4.18-* + echo "--------------------" + done + + +For i386, make static (y): + CONFIG_M586 test machine flexibility [jh] + CONFIG_I8K Dell laptop [jh] + CONFIG_PCMCIA Dell laptop [jh] + CONFIG_VORTEX Dell laptop [jh] + CONFIG_SCSI 1200 [jh] + CONFIG_BLK_DEV_SD 1200 [jh] + CONFIG_SCSI_MULTI_LUN + CONFIG_SCSI_AIC7XXX 1200 + CONFIG_EEPRO100 1200 + CONFIG_EXT3_FS + CONFIG_JBD + + +# cp defconfig-i386-stock defconfig-i386 +# cp defconfig-dig-stock defconfig-dig + +Add in SGI things: + CONFIG_PAGG + CONFIG_XSCSI (not i386) + CONFIG_FS_POSIX_ACL + CONFIG_XFS_FS + CONFIG_KDB + CONFIG_CPUMEMSET (all but *-stock and *-hpsim) + + CONFIG_BCM5700 (not added) + + +# cp defconfig-dig defconfig-sn1 +# cp defconfig-dig defconfig-sn2 + + +Turn from staticly linked into modules: + CONFIG_IDE Probably not used on sn. [jh] + CONFIG_BLK_DEV_IDE Probably not used on sn. [jh] + CONFIG_BLK_DEV_IDEDISK Probably not used on sn. [jh] + CONFIG_BLK_DEV_IDEFLOPPY Probably not used on sn. [jh] + +Staticly link some things: + CONFIG_EXT3_FS Common, might be root. [jh] + CONFIG_JBD Comes with ext3. [jh] + CONFIG_NFS_FS Common, so include. [jh,steiner] + CONFIG_NFSD Common, so include. [jh,steiner] + CONFIG_SUNRPC Comes with NFS... [jh] + CONFIG_LOCKD Comes with NFS... [jh] + +Turn off: + CONFIG_VGA_CONSOLE We only support serial console on sn1. + What about sn2? [steiner] + CONFIG_VT Doesn't build. [jh] + CONFIG_SCSI_SYM53C8XX_2 Doesn't build. [jh] + CONFIG_IP6_NF_IPTABLES Doesn't build. [jh] + + CONFIG_HOTPLUG Not supported, should be off. [cngam] + CONFIG_SCSI XSCSI on, SCSI off [cngam,steiner,...] + +Turn off on dig: + + + + + + + +Within development, we don't normally build or install modules, +so no code that is necessary to boot & test should be built as modules +(as opposed to building a kernel with modules enabled). + +For dig platforms, some code is built as modules in order to keep +the kernel size from getting too big (after adding XFS). +This code could also just be left out. diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-dig linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig --- linux-2.4.19/arch/ia64/sn/configs/defconfig-dig Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig Thu Feb 20 19:55:58 2003 @@ -0,0 +1,1074 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +CONFIG_IA64_MCA=y +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCHRONIZED_ITC=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# ACPI Support +# +CONFIG_ACPI_PCI=y +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUS=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_ACPI_DEBUG=y +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +# CONFIG_CISS_SCSI_TAPE is not set +CONFIG_BLK_DEV_DAC960=m +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +CONFIG_IEEE1394=m + +# +# Device Drivers +# + +# +# Texas Instruments PCILynx requires I2C bit-banging +# +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +# CONFIG_IEEE1394_SBP2 is not set +# CONFIG_IEEE1394_ETH1394 is not set +# CONFIG_IEEE1394_DV1394 is not set +CONFIG_IEEE1394_RAWIO=m +# CONFIG_IEEE1394_CMP is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_PCI=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_LAN=m +# CONFIG_I2O_SCSI is not set +CONFIG_I2O_PROC=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +CONFIG_MD_MULTIPATH=m +# CONFIG_BLK_DEV_LVM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX=y +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_SVWKS=y +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +CONFIG_BLK_DEV_ATARAID=m +CONFIG_BLK_DEV_ATARAID_PDC=m +CONFIG_BLK_DEV_ATARAID_HPT=m + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_MMSC is not set +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QLFC_KDB is not set +CONFIG_XSCSI_QL=y +CONFIG_XSCSI_QL_KDB=y +# CONFIG_XSCSI_IDE is not set +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +CONFIG_HAPPYMEAL=m +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=m +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=m +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139CP=m +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_NET_BROADCOM is not set +CONFIG_DL2K=m +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_SK98LIN=m +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=y + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +CONFIG_INPUT_GAMEPORT=m +CONFIG_INPUT_NS558=m +CONFIG_INPUT_LIGHTNING=m +CONFIG_INPUT_PCIGAME=m +CONFIG_INPUT_CS461X=m +CONFIG_INPUT_EMU10K1=m +CONFIG_INPUT_SERIO=y +CONFIG_INPUT_SERPORT=y + +# +# Joysticks +# +CONFIG_INPUT_ANALOG=m +CONFIG_INPUT_A3D=m +CONFIG_INPUT_ADI=m +CONFIG_INPUT_COBRA=m +CONFIG_INPUT_GF2K=m +CONFIG_INPUT_GRIP=m +CONFIG_INPUT_INTERACT=m +CONFIG_INPUT_TMDC=m +CONFIG_INPUT_SIDEWINDER=m +CONFIG_INPUT_IFORCE_USB=m +CONFIG_INPUT_IFORCE_232=m +CONFIG_INPUT_WARRIOR=m +CONFIG_INPUT_MAGELLAN=m +CONFIG_INPUT_SPACEORB=m +CONFIG_INPUT_SPACEBALL=m +CONFIG_INPUT_STINGER=m +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +CONFIG_AGP_SWORKS=y +CONFIG_AGP_I460=y +# CONFIG_AGP_HP_ZX1 is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=y +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_MATROX=m +# CONFIG_FB_MATROX_MILLENIUM is not set +# CONFIG_FB_MATROX_MYSTIQUE is not set +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_ATY is not set +CONFIG_FB_RADEON=m +CONFIG_FB_ATY128=m +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_3DFX=m +CONFIG_FB_VOODOO1=m +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=m +CONFIG_FBCON_CFB16=m +CONFIG_FBCON_CFB24=m +CONFIG_FBCON_CFB32=m +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PCI_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=m +CONFIG_SOUND_BT878=m +CONFIG_SOUND_CMPCI=m +CONFIG_SOUND_CMPCI_FM=y +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_MIDI=y +CONFIG_SOUND_CMPCI_MPUIO=330 +CONFIG_SOUND_CMPCI_JOYSTICK=y +CONFIG_SOUND_CMPCI_CM8738=y +# CONFIG_SOUND_CMPCI_SPDIFINVERSE is not set +CONFIG_SOUND_CMPCI_SPDIFLOOP=y +CONFIG_SOUND_CMPCI_SPEAKERS=2 +# CONFIG_SOUND_FORTE is not set +CONFIG_SOUND_EMU10K1=m +# CONFIG_MIDI_EMU10K1 is not set +CONFIG_SOUND_FUSION=m +CONFIG_SOUND_CS4281=m +CONFIG_SOUND_ES1370=m +CONFIG_SOUND_ES1371=m +CONFIG_SOUND_ESSSOLO1=m +CONFIG_SOUND_MAESTRO=m +CONFIG_SOUND_MAESTRO3=m +CONFIG_SOUND_ICH=m +CONFIG_SOUND_RME96XX=m +CONFIG_SOUND_SONICVIBES=m +CONFIG_SOUND_TRIDENT=m +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=m +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_LONG_TIMEOUT=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI=m +CONFIG_USB_UHCI_ALT=m +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_BLUETOOTH=m + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +# CONFIG_USB_HIDINPUT is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +CONFIG_USB_WACOM=m + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +CONFIG_USB_PEGASUS=m +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_RIO500=m +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +# CONFIG_BLUEZ_SCO is not set + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +# CONFIG_BLUEZ_USB_FW_LOAD is not set +# CONFIG_BLUEZ_USB_ZERO_PACKET is not set +CONFIG_BLUEZ_HCIUART=m +# CONFIG_BLUEZ_HCIUART_H4 is not set +# CONFIG_BLUEZ_HCIDTL1 is not set +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-nomodules linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-nomodules --- linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-nomodules Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-nomodules Thu Feb 20 19:55:58 2003 @@ -0,0 +1,1069 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +CONFIG_IA64_MCA=y +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCHRONIZED_ITC=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y + +# +# ACPI Support +# +CONFIG_ACPI_PCI=y +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUS=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_FAN=y +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_ACPI_DEBUG=y +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=y +CONFIG_NET_IPGRE=y +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=y +CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_IRC=y +CONFIG_IP_NF_QUEUE=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_LIMIT=y +CONFIG_IP_NF_MATCH_MAC=y +CONFIG_IP_NF_MATCH_MARK=y +CONFIG_IP_NF_MATCH_MULTIPORT=y +CONFIG_IP_NF_MATCH_TOS=y +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_MATCH_TCPMSS=y +CONFIG_IP_NF_MATCH_STATE=y +CONFIG_IP_NF_MATCH_UNCLEAN=y +CONFIG_IP_NF_MATCH_OWNER=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_MIRROR=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_REDIRECT=y +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=y +CONFIG_IP_NF_NAT_IRC=y +CONFIG_IP_NF_NAT_FTP=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_TARGET_TOS=y +CONFIG_IP_NF_TARGET_MARK=y +CONFIG_IP_NF_TARGET_LOG=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=y +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IPV6=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=y + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=y +CONFIG_NET_SCH_CSZ=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_RED=y +CONFIG_NET_SCH_SFQ=y +CONFIG_NET_SCH_TEQL=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_GRED=y +CONFIG_NET_SCH_DSMARK=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=y +CONFIG_NET_CLS_ROUTE4=y +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_CLS_RSVP=y +CONFIG_NET_CLS_RSVP6=y +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=y +CONFIG_BLK_CPQ_CISS_DA=y +# CONFIG_CISS_SCSI_TAPE is not set +CONFIG_BLK_DEV_DAC960=y +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +CONFIG_IEEE1394=y + +# +# Device Drivers +# + +# +# Texas Instruments PCILynx requires I2C bit-banging +# +CONFIG_IEEE1394_OHCI1394=y + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=y +# CONFIG_IEEE1394_SBP2 is not set +# CONFIG_IEEE1394_ETH1394 is not set +# CONFIG_IEEE1394_DV1394 is not set +CONFIG_IEEE1394_RAWIO=y +# CONFIG_IEEE1394_CMP is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# I2O device support +# +CONFIG_I2O=y +CONFIG_I2O_PCI=y +CONFIG_I2O_BLOCK=y +CONFIG_I2O_LAN=y +# CONFIG_I2O_SCSI is not set +CONFIG_I2O_PROC=y + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +CONFIG_MD_MULTIPATH=y +# CONFIG_BLK_DEV_LVM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=y +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX=y +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_SVWKS=y +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +CONFIG_BLK_DEV_ATARAID=y +CONFIG_BLK_DEV_ATARAID_PDC=y +CONFIG_BLK_DEV_ATARAID_HPT=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_MMSC is not set +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QLFC_KDB is not set +CONFIG_XSCSI_QL=y +CONFIG_XSCSI_QL_KDB=y +# CONFIG_XSCSI_IDE is not set +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +CONFIG_BONDING=y +CONFIG_EQUALIZER=y +CONFIG_TUN=y +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +CONFIG_HAPPYMEAL=y +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +CONFIG_SUNGEM=y +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=y +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +CONFIG_ADAPTEC_STARFIRE=y +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139CP=y +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=y +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_NET_BROADCOM is not set +CONFIG_DL2K=y +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +CONFIG_NS83820=y +CONFIG_HAMACHI=y +CONFIG_YELLOWFIN=y +CONFIG_SK98LIN=y +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +CONFIG_INPUT_GAMEPORT=y +CONFIG_INPUT_NS558=y +CONFIG_INPUT_LIGHTNING=y +CONFIG_INPUT_PCIGAME=y +CONFIG_INPUT_CS461X=y +CONFIG_INPUT_EMU10K1=y +CONFIG_INPUT_SERIO=y +CONFIG_INPUT_SERPORT=y + +# +# Joysticks +# +CONFIG_INPUT_ANALOG=y +CONFIG_INPUT_A3D=y +CONFIG_INPUT_ADI=y +CONFIG_INPUT_COBRA=y +CONFIG_INPUT_GF2K=y +CONFIG_INPUT_GRIP=y +CONFIG_INPUT_INTERACT=y +CONFIG_INPUT_TMDC=y +CONFIG_INPUT_SIDEWINDER=y +# CONFIG_INPUT_IFORCE_USB is not set +CONFIG_INPUT_IFORCE_232=y +CONFIG_INPUT_WARRIOR=y +CONFIG_INPUT_MAGELLAN=y +CONFIG_INPUT_SPACEORB=y +CONFIG_INPUT_SPACEBALL=y +CONFIG_INPUT_STINGER=y +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +CONFIG_AGP_SWORKS=y +CONFIG_AGP_I460=y +# CONFIG_AGP_HP_ZX1 is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=y +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=y +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=y +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=y +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=y +CONFIG_NLS_CODEPAGE_775=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=y +CONFIG_NLS_CODEPAGE_855=y +CONFIG_NLS_CODEPAGE_857=y +CONFIG_NLS_CODEPAGE_860=y +CONFIG_NLS_CODEPAGE_861=y +CONFIG_NLS_CODEPAGE_862=y +CONFIG_NLS_CODEPAGE_863=y +CONFIG_NLS_CODEPAGE_864=y +CONFIG_NLS_CODEPAGE_865=y +CONFIG_NLS_CODEPAGE_866=y +CONFIG_NLS_CODEPAGE_869=y +CONFIG_NLS_CODEPAGE_936=y +CONFIG_NLS_CODEPAGE_950=y +CONFIG_NLS_CODEPAGE_932=y +CONFIG_NLS_CODEPAGE_949=y +CONFIG_NLS_CODEPAGE_874=y +CONFIG_NLS_ISO8859_8=y +CONFIG_NLS_CODEPAGE_1250=y +CONFIG_NLS_CODEPAGE_1251=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=y +CONFIG_NLS_ISO8859_3=y +CONFIG_NLS_ISO8859_4=y +CONFIG_NLS_ISO8859_5=y +CONFIG_NLS_ISO8859_6=y +CONFIG_NLS_ISO8859_7=y +CONFIG_NLS_ISO8859_9=y +CONFIG_NLS_ISO8859_13=y +CONFIG_NLS_ISO8859_14=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_KOI8_R=y +CONFIG_NLS_KOI8_U=y +CONFIG_NLS_UTF8=y + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_MATROX=y +# CONFIG_FB_MATROX_MILLENIUM is not set +# CONFIG_FB_MATROX_MYSTIQUE is not set +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_ATY is not set +CONFIG_FB_RADEON=y +CONFIG_FB_ATY128=y +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_3DFX=y +CONFIG_FB_VOODOO1=y +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PCI_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=y +CONFIG_SOUND_BT878=y +CONFIG_SOUND_CMPCI=y +CONFIG_SOUND_CMPCI_FM=y +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_MIDI=y +CONFIG_SOUND_CMPCI_MPUIO=330 +CONFIG_SOUND_CMPCI_JOYSTICK=y +CONFIG_SOUND_CMPCI_CM8738=y +# CONFIG_SOUND_CMPCI_SPDIFINVERSE is not set +CONFIG_SOUND_CMPCI_SPDIFLOOP=y +CONFIG_SOUND_CMPCI_SPEAKERS=2 +# CONFIG_SOUND_FORTE is not set +CONFIG_SOUND_EMU10K1=y +# CONFIG_MIDI_EMU10K1 is not set +CONFIG_SOUND_FUSION=y +CONFIG_SOUND_CS4281=y +CONFIG_SOUND_ES1370=y +CONFIG_SOUND_ES1371=y +CONFIG_SOUND_ESSSOLO1=y +CONFIG_SOUND_MAESTRO=y +CONFIG_SOUND_MAESTRO3=y +CONFIG_SOUND_ICH=y +CONFIG_SOUND_RME96XX=y +CONFIG_SOUND_SONICVIBES=y +CONFIG_SOUND_TRIDENT=y +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set +CONFIG_INPUT_GAMEPORT=y + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_LONG_TIMEOUT=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI=y +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=y +# CONFIG_USB_EMI26 is not set +CONFIG_USB_BLUETOOTH=y + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_ACM=y +CONFIG_USB_PRINTER=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT is not set +CONFIG_USB_HIDDEV=y +CONFIG_USB_WACOM=y + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=y +CONFIG_USB_MDC800=y +CONFIG_USB_SCANNER=y +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +CONFIG_USB_PEGASUS=y +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_KAWETH=y +CONFIG_USB_CATC=y +CONFIG_USB_CDCETHER=y +CONFIG_USB_USBNET=y + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_DEBUG is not set +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=y +CONFIG_USB_SERIAL_WHITEHEAT=y +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=y +CONFIG_USB_SERIAL_EMPEG=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_SERIAL_VISOR=y +CONFIG_USB_SERIAL_IPAQ=y +CONFIG_USB_SERIAL_IR=y +CONFIG_USB_SERIAL_EDGEPORT=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=y +CONFIG_USB_SERIAL_KLSI=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_SERIAL_CYBERJACK=y +CONFIG_USB_SERIAL_XIRCOM=y +CONFIG_USB_SERIAL_OMNINET=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_RIO500=y +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=y +CONFIG_BLUEZ_L2CAP=y +# CONFIG_BLUEZ_SCO is not set + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=y +# CONFIG_BLUEZ_USB_FW_LOAD is not set +# CONFIG_BLUEZ_USB_ZERO_PACKET is not set +CONFIG_BLUEZ_HCIUART=y +# CONFIG_BLUEZ_HCIUART_H4 is not set +# CONFIG_BLUEZ_HCIDTL1 is not set +CONFIG_BLUEZ_HCIVHCI=y + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +# CONFIG_KDB_MODULES is not set +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-sp --- linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-sp Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-sp Thu Feb 20 19:55:58 2003 @@ -0,0 +1,1074 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +CONFIG_IA64_MCA=y +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCHRONIZED_ITC=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# ACPI Support +# +CONFIG_ACPI_PCI=y +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUS=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_ACPI_DEBUG=y +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +# CONFIG_CISS_SCSI_TAPE is not set +CONFIG_BLK_DEV_DAC960=m +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +CONFIG_IEEE1394=m + +# +# Device Drivers +# + +# +# Texas Instruments PCILynx requires I2C bit-banging +# +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +# CONFIG_IEEE1394_SBP2 is not set +# CONFIG_IEEE1394_ETH1394 is not set +# CONFIG_IEEE1394_DV1394 is not set +CONFIG_IEEE1394_RAWIO=m +# CONFIG_IEEE1394_CMP is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_PCI=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_LAN=m +# CONFIG_I2O_SCSI is not set +CONFIG_I2O_PROC=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +CONFIG_MD_MULTIPATH=m +# CONFIG_BLK_DEV_LVM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX=y +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_SVWKS=y +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +CONFIG_BLK_DEV_ATARAID=m +CONFIG_BLK_DEV_ATARAID_PDC=m +CONFIG_BLK_DEV_ATARAID_HPT=m + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_MMSC is not set +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QLFC_KDB is not set +CONFIG_XSCSI_QL=y +CONFIG_XSCSI_QL_KDB=y +# CONFIG_XSCSI_IDE is not set +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +CONFIG_HAPPYMEAL=m +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=m +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=m +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139CP=m +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_NET_BROADCOM is not set +CONFIG_DL2K=m +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_SK98LIN=m +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=y + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +CONFIG_INPUT_GAMEPORT=m +CONFIG_INPUT_NS558=m +CONFIG_INPUT_LIGHTNING=m +CONFIG_INPUT_PCIGAME=m +CONFIG_INPUT_CS461X=m +CONFIG_INPUT_EMU10K1=m +CONFIG_INPUT_SERIO=y +CONFIG_INPUT_SERPORT=y + +# +# Joysticks +# +CONFIG_INPUT_ANALOG=m +CONFIG_INPUT_A3D=m +CONFIG_INPUT_ADI=m +CONFIG_INPUT_COBRA=m +CONFIG_INPUT_GF2K=m +CONFIG_INPUT_GRIP=m +CONFIG_INPUT_INTERACT=m +CONFIG_INPUT_TMDC=m +CONFIG_INPUT_SIDEWINDER=m +CONFIG_INPUT_IFORCE_USB=m +CONFIG_INPUT_IFORCE_232=m +CONFIG_INPUT_WARRIOR=m +CONFIG_INPUT_MAGELLAN=m +CONFIG_INPUT_SPACEORB=m +CONFIG_INPUT_SPACEBALL=m +CONFIG_INPUT_STINGER=m +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +CONFIG_AGP_SWORKS=y +CONFIG_AGP_I460=y +# CONFIG_AGP_HP_ZX1 is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=y +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_MATROX=m +# CONFIG_FB_MATROX_MILLENIUM is not set +# CONFIG_FB_MATROX_MYSTIQUE is not set +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_ATY is not set +CONFIG_FB_RADEON=m +CONFIG_FB_ATY128=m +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_3DFX=m +CONFIG_FB_VOODOO1=m +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=m +CONFIG_FBCON_CFB16=m +CONFIG_FBCON_CFB24=m +CONFIG_FBCON_CFB32=m +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PCI_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=m +CONFIG_SOUND_BT878=m +CONFIG_SOUND_CMPCI=m +CONFIG_SOUND_CMPCI_FM=y +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_MIDI=y +CONFIG_SOUND_CMPCI_MPUIO=330 +CONFIG_SOUND_CMPCI_JOYSTICK=y +CONFIG_SOUND_CMPCI_CM8738=y +# CONFIG_SOUND_CMPCI_SPDIFINVERSE is not set +CONFIG_SOUND_CMPCI_SPDIFLOOP=y +CONFIG_SOUND_CMPCI_SPEAKERS=2 +# CONFIG_SOUND_FORTE is not set +CONFIG_SOUND_EMU10K1=m +# CONFIG_MIDI_EMU10K1 is not set +CONFIG_SOUND_FUSION=m +CONFIG_SOUND_CS4281=m +CONFIG_SOUND_ES1370=m +CONFIG_SOUND_ES1371=m +CONFIG_SOUND_ESSSOLO1=m +CONFIG_SOUND_MAESTRO=m +CONFIG_SOUND_MAESTRO3=m +CONFIG_SOUND_ICH=m +CONFIG_SOUND_RME96XX=m +CONFIG_SOUND_SONICVIBES=m +CONFIG_SOUND_TRIDENT=m +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=m +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_LONG_TIMEOUT=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI=m +CONFIG_USB_UHCI_ALT=m +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_BLUETOOTH=m + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +# CONFIG_USB_HIDINPUT is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +CONFIG_USB_WACOM=m + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +CONFIG_USB_PEGASUS=m +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_RIO500=m +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +# CONFIG_BLUEZ_SCO is not set + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +# CONFIG_BLUEZ_USB_FW_LOAD is not set +# CONFIG_BLUEZ_USB_ZERO_PACKET is not set +CONFIG_BLUEZ_HCIUART=m +# CONFIG_BLUEZ_HCIUART_H4 is not set +# CONFIG_BLUEZ_HCIDTL1 is not set +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-stock linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-stock --- linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-stock Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-stock Thu Feb 20 19:55:58 2003 @@ -0,0 +1,1119 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +CONFIG_ITANIUM_BSTEP_SPECIFIC=y +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +CONFIG_IA64_MCA=y +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCHRONIZED_ITC=y +# CONFIG_DEVFS_FS is not set +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +# CONFIG_CPUMEMSET is not set +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +# CONFIG_PAGG is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# ACPI Support +# +CONFIG_ACPI_PCI=y +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUS=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_DEBUG=y +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +# CONFIG_CISS_SCSI_TAPE is not set +CONFIG_BLK_DEV_DAC960=m +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +CONFIG_IEEE1394=m + +# +# Device Drivers +# + +# +# Texas Instruments PCILynx requires I2C bit-banging +# +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +# CONFIG_IEEE1394_DV1394 is not set +CONFIG_IEEE1394_RAWIO=m +# CONFIG_IEEE1394_CMP is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_PCI=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_LAN=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_MULTIPATH=m +# CONFIG_BLK_DEV_LVM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=m +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX=y +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_SVWKS=y +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +CONFIG_BLK_DEV_ATARAID=m +CONFIG_BLK_DEV_ATARAID_PDC=m +CONFIG_BLK_DEV_ATARAID_HPT=m + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_PROBE_EISA_VL is not set +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=32 +# CONFIG_AIC7XXX_OLD_PROC_STATS is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +CONFIG_SCSI_MEGARAID=m +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLOGIC_QLA2100=m +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +CONFIG_HAPPYMEAL=m +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=m +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=m +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=m +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139CP=m +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_NET_BROADCOM is not set +CONFIG_DL2K=m +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_SK98LIN=m +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +CONFIG_INPUT=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +CONFIG_INPUT_GAMEPORT=m +CONFIG_INPUT_NS558=m +CONFIG_INPUT_LIGHTNING=m +CONFIG_INPUT_PCIGAME=m +CONFIG_INPUT_CS461X=m +CONFIG_INPUT_EMU10K1=m +CONFIG_INPUT_SERIO=m +CONFIG_INPUT_SERPORT=m + +# +# Joysticks +# +CONFIG_INPUT_ANALOG=m +CONFIG_INPUT_A3D=m +CONFIG_INPUT_ADI=m +CONFIG_INPUT_COBRA=m +CONFIG_INPUT_GF2K=m +CONFIG_INPUT_GRIP=m +CONFIG_INPUT_INTERACT=m +CONFIG_INPUT_TMDC=m +CONFIG_INPUT_SIDEWINDER=m +CONFIG_INPUT_IFORCE_USB=m +CONFIG_INPUT_IFORCE_232=m +CONFIG_INPUT_WARRIOR=m +CONFIG_INPUT_MAGELLAN=m +CONFIG_INPUT_SPACEORB=m +CONFIG_INPUT_SPACEBALL=m +CONFIG_INPUT_STINGER=m +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=m +CONFIG_AGP_INTEL=y +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +CONFIG_AGP_SWORKS=y +CONFIG_AGP_I460=y +# CONFIG_AGP_HP_ZX1 is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_FS_POSIX_ACL is not set +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_DMAPI is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=m +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=y +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_MATROX=m +# CONFIG_FB_MATROX_MILLENIUM is not set +# CONFIG_FB_MATROX_MYSTIQUE is not set +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_ATY is not set +CONFIG_FB_RADEON=m +CONFIG_FB_ATY128=m +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_3DFX=m +CONFIG_FB_VOODOO1=m +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=m +CONFIG_FBCON_CFB16=m +CONFIG_FBCON_CFB24=m +CONFIG_FBCON_CFB32=m +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PCI_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=m +CONFIG_SOUND_BT878=m +CONFIG_SOUND_CMPCI=m +CONFIG_SOUND_CMPCI_FM=y +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_MIDI=y +CONFIG_SOUND_CMPCI_MPUIO=330 +CONFIG_SOUND_CMPCI_JOYSTICK=y +CONFIG_SOUND_CMPCI_CM8738=y +# CONFIG_SOUND_CMPCI_SPDIFINVERSE is not set +CONFIG_SOUND_CMPCI_SPDIFLOOP=y +CONFIG_SOUND_CMPCI_SPEAKERS=2 +# CONFIG_SOUND_FORTE is not set +CONFIG_SOUND_EMU10K1=m +# CONFIG_MIDI_EMU10K1 is not set +CONFIG_SOUND_FUSION=m +CONFIG_SOUND_CS4281=m +CONFIG_SOUND_ES1370=m +CONFIG_SOUND_ES1371=m +CONFIG_SOUND_ESSSOLO1=m +CONFIG_SOUND_MAESTRO=m +CONFIG_SOUND_MAESTRO3=m +CONFIG_SOUND_ICH=m +CONFIG_SOUND_RME96XX=m +CONFIG_SOUND_SONICVIBES=m +CONFIG_SOUND_TRIDENT=m +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=m +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_LONG_TIMEOUT=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI=m +CONFIG_USB_UHCI_ALT=m +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_BLUETOOTH=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +# CONFIG_USB_HIDINPUT is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +CONFIG_USB_WACOM=m + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +CONFIG_USB_PEGASUS=m +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_RIO500=m +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +# CONFIG_BLUEZ_SCO is not set + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +# CONFIG_BLUEZ_USB_FW_LOAD is not set +# CONFIG_BLUEZ_USB_ZERO_PACKET is not set +CONFIG_BLUEZ_HCIUART=m +# CONFIG_BLUEZ_HCIUART_H4 is not set +# CONFIG_BLUEZ_HCIDTL1 is not set +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +# CONFIG_DUMP is not set +# CONFIG_DEBUG_KERNEL is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-underlay linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-underlay --- linux-2.4.19/arch/ia64/sn/configs/defconfig-dig-underlay Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-dig-underlay Thu Feb 20 19:55:58 2003 @@ -0,0 +1,877 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +# CONFIG_NUMA is not set +CONFIG_IA64_MCA=y +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCHRONIZED_ITC=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# ACPI Support +# +CONFIG_ACPI_PCI=y +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUS=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_PIIX_TUNING is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=y +CONFIG_INPUT_SERPORT=y + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +# CONFIG_AGP_INTEL is not set +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +# CONFIG_AGP_SWORKS is not set +CONFIG_AGP_I460=y +# CONFIG_AGP_HP_ZX1 is not set +CONFIG_DRM=y +# CONFIG_DRM_OLD is not set + +# +# DRM 4.1 drivers +# +CONFIG_DRM_NEW=y +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_R128 is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_I810 is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +CONFIG_SOUND_CS4281=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +# CONFIG_KDB_MODULES is not set +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-hpsim linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-hpsim --- linux-2.4.19/arch/ia64/sn/configs/defconfig-hpsim Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-hpsim Thu Feb 20 19:55:58 2003 @@ -0,0 +1,400 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +CONFIG_IA64_HP_SIM=y +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +# CONFIG_CPUMEMSET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_PAGG is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_IA64_HAVE_SYNCHRONIZED_ITC=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_QIFACE_COMPAT is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_DMAPI is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Simulated drivers +# +# CONFIG_SIMETH is not set +# CONFIG_SIM_SERIAL is not set +CONFIG_SCSI_SIM=y + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +# CONFIG_DUMP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=m +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-i386 linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386 --- linux-2.4.19/arch/ia64/sn/configs/defconfig-i386 Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386 Thu Feb 20 19:55:58 2003 @@ -0,0 +1,937 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_ISA=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MELAN is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_L1_CACHE_SHIFT=5 +CONFIG_X86_USE_STRING_486=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_PPRO_FENCE=y +# CONFIG_X86_MCE is not set +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set +CONFIG_NOHIGHMEM=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_MTRR is not set +CONFIG_SMP=y +# CONFIG_MULTIQUAD is not set +CONFIG_HAVE_DEC_LOCK=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_NAMES=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_CARDBUS=y +# CONFIG_TCIC is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_IBM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_PM=y +# CONFIG_APM is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +CONFIG_PNP=y +CONFIG_ISAPNP=y + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_EL3 is not set +# CONFIG_3C515 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=y +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOATM is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_AMD_RNG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_I810=y +CONFIG_AGP_VIA=y +CONFIG_AGP_AMD=y +CONFIG_AGP_SIS=y +CONFIG_AGP_ALI=y +# CONFIG_AGP_SWORKS is not set +CONFIG_DRM=y +# CONFIG_DRM_OLD is not set + +# +# DRM 4.1 drivers +# +CONFIG_DRM_NEW=y +CONFIG_DRM_TDFX=y +# CONFIG_DRM_R128 is not set +CONFIG_DRM_RADEON=y +# CONFIG_DRM_I810 is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_MWAVE is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_QIFACE_COMPAT is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VIDEO_SELECT is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +CONFIG_SOUND_ES1371=y +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI_ALT=y +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# Input core support is needed for USB HID input layer or HIDBP support +# +# CONFIG_USB_HIDINPUT is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-i386-nomodules linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386-nomodules --- linux-2.4.19/arch/ia64/sn/configs/defconfig-i386-nomodules Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386-nomodules Thu Feb 20 19:55:58 2003 @@ -0,0 +1,928 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_ISA=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Processor type and features +# +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MELAN is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_L1_CACHE_SHIFT=5 +CONFIG_X86_USE_STRING_486=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_MCE=y +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set +CONFIG_NOHIGHMEM=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_MTRR is not set +CONFIG_SMP=y +# CONFIG_MULTIQUAD is not set +CONFIG_HAVE_DEC_LOCK=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_NAMES=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_CARDBUS=y +# CONFIG_TCIC is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_IBM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_PM=y +# CONFIG_APM is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +CONFIG_PNP=y +CONFIG_ISAPNP=y + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_VLAN_8021Q=y + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=y +CONFIG_EL2=y +CONFIG_ELPLUS=y +# CONFIG_EL16 is not set +CONFIG_EL3=y +CONFIG_3C515=y +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=y +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_AMD_RNG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_I810=y +CONFIG_AGP_VIA=y +CONFIG_AGP_AMD=y +CONFIG_AGP_SIS=y +CONFIG_AGP_ALI=y +# CONFIG_AGP_SWORKS is not set +CONFIG_DRM=y +# CONFIG_DRM_OLD is not set + +# +# DRM 4.1 drivers +# +CONFIG_DRM_NEW=y +CONFIG_DRM_TDFX=y +# CONFIG_DRM_R128 is not set +CONFIG_DRM_RADEON=y +# CONFIG_DRM_I810 is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_MWAVE is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_QIFACE_COMPAT is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VIDEO_SELECT is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +CONFIG_SOUND_ES1371=y +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI_ALT=y +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# Input core support is needed for USB HID input layer or HIDBP support +# +# CONFIG_USB_HIDINPUT is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-i386-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386-sp --- linux-2.4.19/arch/ia64/sn/configs/defconfig-i386-sp Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386-sp Thu Feb 20 19:55:58 2003 @@ -0,0 +1,937 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_ISA=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# Processor type and features +# +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MELAN is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_L1_CACHE_SHIFT=5 +CONFIG_X86_USE_STRING_486=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_PPRO_FENCE=y +# CONFIG_X86_MCE is not set +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set +CONFIG_NOHIGHMEM=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_MTRR is not set +# CONFIG_SMP is not set +CONFIG_X86_UP_APIC=y +CONFIG_X86_UP_IOAPIC=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_NAMES=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_CARDBUS=y +# CONFIG_TCIC is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_IBM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_PM=y +# CONFIG_APM is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +CONFIG_PNP=y +CONFIG_ISAPNP=y + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=y +CONFIG_EL2=y +CONFIG_ELPLUS=y +# CONFIG_EL16 is not set +CONFIG_EL3=y +CONFIG_3C515=y +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=y +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOATM is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_AMD_RNG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_I810=y +CONFIG_AGP_VIA=y +CONFIG_AGP_AMD=y +CONFIG_AGP_SIS=y +CONFIG_AGP_ALI=y +# CONFIG_AGP_SWORKS is not set +CONFIG_DRM=y +# CONFIG_DRM_OLD is not set + +# +# DRM 4.1 drivers +# +CONFIG_DRM_NEW=y +CONFIG_DRM_TDFX=y +# CONFIG_DRM_R128 is not set +CONFIG_DRM_RADEON=y +# CONFIG_DRM_I810 is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_MWAVE is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_QIFACE_COMPAT is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VIDEO_SELECT is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +CONFIG_SOUND_ES1371=y +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI_ALT=y +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# Input core support is needed for USB HID input layer or HIDBP support +# +# CONFIG_USB_HIDINPUT is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-i386-stock linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386-stock --- linux-2.4.19/arch/ia64/sn/configs/defconfig-i386-stock Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-i386-stock Thu Feb 20 19:55:58 2003 @@ -0,0 +1,913 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_ISA=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_M386=y +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MELAN is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_X86_CMPXCHG is not set +# CONFIG_X86_XADD is not set +CONFIG_X86_L1_CACHE_SHIFT=4 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_X86_PPRO_FENCE=y +# CONFIG_X86_MCE is not set +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set +CONFIG_NOHIGHMEM=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_MTRR is not set +CONFIG_SMP=y +# CONFIG_MULTIQUAD is not set + +# +# General setup +# +CONFIG_NET=y +# CONFIG_CPUMEMSET is not set +CONFIG_X86_IO_APIC=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_NAMES=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_CARDBUS=y +# CONFIG_TCIC is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_IBM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_PAGG is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_PM=y +# CONFIG_APM is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +CONFIG_PNP=y +CONFIG_ISAPNP=y + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +# CONFIG_XSCSI is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_EL3 is not set +# CONFIG_3C515 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=y +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_TC35815 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_AMD_RNG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_I810=y +CONFIG_AGP_VIA=y +CONFIG_AGP_AMD=y +CONFIG_AGP_SIS=y +CONFIG_AGP_ALI=y +# CONFIG_AGP_SWORKS is not set +CONFIG_DRM=y +# CONFIG_DRM_OLD is not set + +# +# DRM 4.1 drivers +# +CONFIG_DRM_NEW=y +CONFIG_DRM_TDFX=y +# CONFIG_DRM_R128 is not set +CONFIG_DRM_RADEON=y +# CONFIG_DRM_I810 is not set +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_MWAVE is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_QIFACE_COMPAT is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_DMAPI is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VIDEO_SELECT is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +CONFIG_SOUND_ES1371=y +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI_ALT=y +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# Input core support is needed for USB HID input layer or HIDBP support +# +# CONFIG_USB_HIDINPUT is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_DUMP is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_KDB is not set +# CONFIG_KDB_MODULES is not set +# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-sn1 linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn1 --- linux-2.4.19/arch/ia64/sn/configs/defconfig-sn1 Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn1 Thu Feb 20 19:55:58 2003 @@ -0,0 +1,770 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +# CONFIG_IA64_SGI_SN_DEBUG is not set +CONFIG_IA64_SGI_SN_SIM=y +# CONFIG_IA64_SGI_AUTOTEST is not set +# CONFIG_SHUB_1_0_SPECIFIC is not set +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_NUMA_REPLICATE=y +CONFIG_PERCPU_IRQ=y +# CONFIG_IA64_HAVE_SYNCHRONIZED_ITC is not set +CONFIG_PCIBA=y +CONFIG_IA64_SGI_SN_BRT=m +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# ACPI Support +# +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +# CONFIG_ACPI_BUS is not set +# CONFIG_ACPI_INTERPRETER is not set +# CONFIG_ACPI_PCI is not set +# CONFIG_ACPI_POWER is not set +# CONFIG_ACPI_SYSTEM is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID5=y +CONFIG_MD_MULTIPATH=y +CONFIG_BLK_DEV_LVM=y + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_PIIX_TUNING is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +CONFIG_XSCSI_MMSC=y +CONFIG_XSCSI_QLFC=y +CONFIG_XSCSI_QLFC_KDB=m +CONFIG_XSCSI_QL=y +CONFIG_XSCSI_QL_KDB=y +# CONFIG_XSCSI_IDE is not set +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=y +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-sn1-max-modules linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn1-max-modules --- linux-2.4.19/arch/ia64/sn/configs/defconfig-sn1-max-modules Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn1-max-modules Thu Feb 20 19:55:58 2003 @@ -0,0 +1,770 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +# CONFIG_IA64_SGI_SN_DEBUG is not set +CONFIG_IA64_SGI_SN_SIM=y +# CONFIG_IA64_SGI_AUTOTEST is not set +# CONFIG_SHUB_1_0_SPECIFIC is not set +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_NUMA_REPLICATE=y +CONFIG_PERCPU_IRQ=y +# CONFIG_IA64_HAVE_SYNCHRONIZED_ITC is not set +CONFIG_PCIBA=m +CONFIG_IA64_SGI_SN_BRT=m +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=m +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=m +CONFIG_CSA_JOB_ACCT=m +CONFIG_BINFMT_ELF=m +CONFIG_BINFMT_MISC=m + +# +# ACPI Support +# +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +# CONFIG_ACPI_BUS is not set +# CONFIG_ACPI_INTERPRETER is not set +# CONFIG_ACPI_PCI is not set +# CONFIG_ACPI_POWER is not set +# CONFIG_ACPI_SYSTEM is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_INITRD is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_LVM=m + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_PIIX_TUNING is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +CONFIG_XSCSI_MMSC=y +CONFIG_XSCSI_QLFC=y +CONFIG_XSCSI_QLFC_KDB=m +CONFIG_XSCSI_QL=m +CONFIG_XSCSI_QL_KDB=m +# CONFIG_XSCSI_IDE is not set +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +CONFIG_RCPCI=m +CONFIG_SHAPER=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +CONFIG_QUOTA=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=m +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=m +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=m +CONFIG_ZLIB_FS_INFLATE=m + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=m +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=m +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-sn1-underlay linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn1-underlay --- linux-2.4.19/arch/ia64/sn/configs/defconfig-sn1-underlay Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn1-underlay Thu Feb 20 19:55:58 2003 @@ -0,0 +1,761 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +CONFIG_IA64_SGI_SN1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_IA64_SGI_SN=y +# CONFIG_IA64_SGI_SN_DEBUG is not set +CONFIG_IA64_SGI_SN_SIM=y +# CONFIG_IA64_SGI_AUTOTEST is not set +# CONFIG_SHUB_1_0_SPECIFIC is not set +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_NUMA_REPLICATE=y +CONFIG_PERCPU_IRQ=y +# CONFIG_IA64_HAVE_SYNCHRONIZED_ITC is not set +CONFIG_PCIBA=y +CONFIG_IA64_SGI_SN_BRT=m +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +# CONFIG_EFI_VARS is not set +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# ACPI Support +# +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +# CONFIG_ACPI_BUS is not set +# CONFIG_ACPI_INTERPRETER is not set +# CONFIG_ACPI_PCI is not set +# CONFIG_ACPI_POWER is not set +# CONFIG_ACPI_SYSTEM is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID5=y +CONFIG_MD_MULTIPATH=y +CONFIG_BLK_DEV_LVM=y + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_PIIX_TUNING is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +CONFIG_XSCSI_MMSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QLFC_KDB is not set +# CONFIG_XSCSI_QL is not set +# CONFIG_XSCSI_QL_KDB is not set +# CONFIG_XSCSI_IDE is not set +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +CONFIG_SCSI_QLOGIC_FC=y +# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set +CONFIG_SCSI_QLOGIC_1280=y +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_FS_POSIX_ACL is not set +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-sn2 linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn2 --- linux-2.4.19/arch/ia64/sn/configs/defconfig-sn2 Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-sn2 Thu Feb 20 19:55:58 2003 @@ -0,0 +1,769 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +CONFIG_IA64_SGI_SN2=y +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set +CONFIG_IA64_SGI_SN=y +# CONFIG_IA64_SGI_SN_DEBUG is not set +CONFIG_IA64_SGI_SN_SIM=y +# CONFIG_IA64_SGI_AUTOTEST is not set +# CONFIG_SHUB_1_0_SPECIFIC is not set +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DISCONTIGMEM=y +CONFIG_IA64_MCA=y +CONFIG_NUMA=y +CONFIG_NUMA_REPLICATE=y +CONFIG_PERCPU_IRQ=y +# CONFIG_IA64_HAVE_SYNCHRONIZED_ITC is not set +CONFIG_PCIBA=y +CONFIG_IA64_SGI_SN_BRT=m +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# ACPI Support +# +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +# CONFIG_ACPI_BUS is not set +# CONFIG_ACPI_INTERPRETER is not set +# CONFIG_ACPI_PCI is not set +# CONFIG_ACPI_POWER is not set +# CONFIG_ACPI_SYSTEM is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID5=y +CONFIG_MD_MULTIPATH=y +CONFIG_BLK_DEV_LVM=y + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_PIIX_TUNING is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +CONFIG_XSCSI_MMSC=y +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QLFC_KDB is not set +CONFIG_XSCSI_QL=y +CONFIG_XSCSI_QL_KDB=y +CONFIG_XSCSI_IDE=y +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_NET_BROADCOM is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +CONFIG_TIGON3=y +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=y +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/defconfig-tiger linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-tiger --- linux-2.4.19/arch/ia64/sn/configs/defconfig-tiger Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/defconfig-tiger Thu Feb 20 19:55:58 2003 @@ -0,0 +1,1137 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_IA64=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +# CONFIG_VIRTUAL_MEM_MAP is not set +CONFIG_IA64_L1_CACHE_SHIFT=7 +CONFIG_MCKINLEY_ASTEP_SPECIFIC=y +CONFIG_MCKINLEY_A0_SPECIFIC=y +# CONFIG_NUMA is not set +CONFIG_IA64_MCA=y +CONFIG_PM=y +CONFIG_IA64_HAVE_SYNCHRONIZED_ITC=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_DEBUG=y +CONFIG_KCORE_ELF=y +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_CPUMEMSET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_PAGG=y +CONFIG_PAGG_JOB=y +CONFIG_CSA_JOB_ACCT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m + +# +# ACPI Support +# +CONFIG_ACPI_PCI=y +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUS=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=m +# CONFIG_ACPI_PROCESSOR is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_ACPI_DEBUG=y +CONFIG_PCI=y +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_AH_ESP is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +# CONFIG_CISS_SCSI_TAPE is not set +CONFIG_BLK_DEV_DAC960=m +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +CONFIG_IEEE1394=m + +# +# Device Drivers +# + +# +# Texas Instruments PCILynx requires I2C bit-banging +# +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +# CONFIG_IEEE1394_SBP2 is not set +# CONFIG_IEEE1394_ETH1394 is not set +# CONFIG_IEEE1394_DV1394 is not set +CONFIG_IEEE1394_RAWIO=m +# CONFIG_IEEE1394_CMP is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_PCI=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_LAN=m +# CONFIG_I2O_SCSI is not set +CONFIG_I2O_PROC=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +CONFIG_MD_MULTIPATH=m +# CONFIG_BLK_DEV_LVM is not set + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_BOOT=y +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +CONFIG_BLK_DEV_PIIX=y +CONFIG_PIIX_TUNING=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX=y +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_SVWKS=y +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +CONFIG_BLK_DEV_ATARAID=m +CONFIG_BLK_DEV_ATARAID_PDC=m +CONFIG_BLK_DEV_ATARAID_HPT=m + +# +# Alternate SCSI support +# +CONFIG_XSCSI=y + +# +# Alternate SCSI support +# +CONFIG_XSCSI_DKSC=y +# CONFIG_XSCSI_MMSC is not set +# CONFIG_XSCSI_QLFC is not set +# CONFIG_XSCSI_QLFC_KDB is not set +CONFIG_XSCSI_QL=y +CONFIG_XSCSI_QL_KDB=y +# CONFIG_XSCSI_IDE is not set +# CONFIG_XSCSI_IDE_KDB is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +CONFIG_HAPPYMEAL=m +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set +CONFIG_VORTEX=m +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=m +# CONFIG_TC35815 is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +CONFIG_8139CP=m +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_NET_BROADCOM is not set +CONFIG_DL2K=m +# CONFIG_MYRI_SBUS is not set +CONFIG_E1000=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_SK98LIN=m +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=y + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_HCDP is not set +# CONFIG_SERIAL_ACPI is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=2048 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +CONFIG_INPUT_GAMEPORT=m +CONFIG_INPUT_NS558=m +CONFIG_INPUT_LIGHTNING=m +CONFIG_INPUT_PCIGAME=m +CONFIG_INPUT_CS461X=m +CONFIG_INPUT_EMU10K1=m +CONFIG_INPUT_SERIO=y +CONFIG_INPUT_SERPORT=y + +# +# Joysticks +# +CONFIG_INPUT_ANALOG=m +CONFIG_INPUT_A3D=m +CONFIG_INPUT_ADI=m +CONFIG_INPUT_COBRA=m +CONFIG_INPUT_GF2K=m +CONFIG_INPUT_GRIP=m +CONFIG_INPUT_INTERACT=m +CONFIG_INPUT_TMDC=m +CONFIG_INPUT_SIDEWINDER=m +CONFIG_INPUT_IFORCE_USB=m +CONFIG_INPUT_IFORCE_232=m +CONFIG_INPUT_WARRIOR=m +CONFIG_INPUT_MAGELLAN=m +CONFIG_INPUT_SPACEORB=m +CONFIG_INPUT_SPACEBALL=m +CONFIG_INPUT_STINGER=m +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +CONFIG_AGP_SWORKS=y +CONFIG_AGP_I460=y +# CONFIG_AGP_HP_ZX1 is not set +# CONFIG_DRM is not set + +# +# Misc devices +# +# CONFIG_DBGTK is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_FS_POSIX_ACL=y +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +# CONFIG_QIFACE_COMPAT is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_MINIX_FS is not set +CONFIG_VXFS_FS=m +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_RW=y +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_DMAPI=y +# CONFIG_XFS_DEBUG is not set +# CONFIG_PAGEBUF_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_INTERMEZZO_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +CONFIG_SMB_NLS_DEFAULT=y +CONFIG_SMB_NLS_REMOTE="cp437" +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +CONFIG_ZISOFS_FS=y +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_MATROX=m +# CONFIG_FB_MATROX_MILLENIUM is not set +# CONFIG_FB_MATROX_MYSTIQUE is not set +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_ATY is not set +CONFIG_FB_RADEON=m +CONFIG_FB_ATY128=m +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_3DFX=m +CONFIG_FB_VOODOO1=m +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=m +CONFIG_FBCON_CFB16=m +CONFIG_FBCON_CFB24=m +CONFIG_FBCON_CFB32=m +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PCI_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=m +CONFIG_SOUND_BT878=m +CONFIG_SOUND_CMPCI=m +CONFIG_SOUND_CMPCI_FM=y +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_FMIO=388 +CONFIG_SOUND_CMPCI_MIDI=y +CONFIG_SOUND_CMPCI_MPUIO=330 +CONFIG_SOUND_CMPCI_JOYSTICK=y +CONFIG_SOUND_CMPCI_CM8738=y +# CONFIG_SOUND_CMPCI_SPDIFINVERSE is not set +CONFIG_SOUND_CMPCI_SPDIFLOOP=y +CONFIG_SOUND_CMPCI_SPEAKERS=2 +# CONFIG_SOUND_FORTE is not set +CONFIG_SOUND_EMU10K1=m +# CONFIG_MIDI_EMU10K1 is not set +CONFIG_SOUND_FUSION=m +CONFIG_SOUND_CS4281=m +CONFIG_SOUND_ES1370=m +CONFIG_SOUND_ES1371=m +CONFIG_SOUND_ESSSOLO1=m +CONFIG_SOUND_MAESTRO=m +CONFIG_SOUND_MAESTRO3=m +CONFIG_SOUND_ICH=m +CONFIG_SOUND_RME96XX=m +CONFIG_SOUND_SONICVIBES=m +CONFIG_SOUND_TRIDENT=m +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_LONG_TIMEOUT=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_UHCI=y +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_BLUETOOTH=m +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT is not set +CONFIG_USB_HIDDEV=y +CONFIG_USB_WACOM=m + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +CONFIG_USB_PEGASUS=m +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_RIO500=m +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +# CONFIG_BLUEZ_SCO is not set + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +# CONFIG_BLUEZ_USB_FW_LOAD is not set +# CONFIG_BLUEZ_USB_ZERO_PACKET is not set +CONFIG_BLUEZ_HCIUART=m +# CONFIG_BLUEZ_HCIUART_H4 is not set +# CONFIG_BLUEZ_HCIDTL1 is not set +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DUMP=y +# CONFIG_DUMP_COMPRESS_RLE is not set +# CONFIG_DUMP_COMPRESS_GZIP is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_IA64_EARLY_PRINTK=y +# CONFIG_IA64_EARLY_PRINTK_UART is not set +# CONFIG_IA64_EARLY_PRINTK_VGA is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_KDB=y +CONFIG_KDB_MODULES=y +# CONFIG_KDB_OFF is not set +# CONFIG_KDB_USB is not set + +# +# Load all symbols for debugging is required for KDB +# +CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp Wed Dec 31 16:00:00 1969 @@ -1,777 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -# CONFIG_NUMA is not set -# CONFIG_IA64_MCA is not set -CONFIG_PM=y -CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_ADMA=y -# CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_IDEDMA_PCI_AUTO is not set -CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_IDEDMA_PCI_WIP is not set -# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_AEC62XX_TUNING is not set -# CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_WDC_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD74XX is not set -# CONFIG_AMD74XX_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_BLK_DEV_CY82C693 is not set -# CONFIG_BLK_DEV_CS5530 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_HPT34X_AUTODMA is not set -# CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_BLK_DEV_PIIX is not set -# CONFIG_PIIX_TUNING is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_PDC202XX is not set -# CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_FORCE is not set -# CONFIG_BLK_DEV_SVWKS is not set -# CONFIG_BLK_DEV_SIS5513 is not set -# CONFIG_BLK_DEV_SLC90E66 is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_IDEDMA_IVB is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -CONFIG_SCSI_QLOGIC_1280=y -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -CONFIG_DUMMY=y -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_PCI=y -# CONFIG_PCNET32 is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -# CONFIG_TULIP is not set -# CONFIG_DE4X5 is not set -# CONFIG_DGRS is not set -# CONFIG_DM9102 is not set -CONFIG_EEPRO100=y -# CONFIG_LNE390 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_NE3210 is not set -# CONFIG_ES3210 is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -# CONFIG_8139TOO_8129 is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_WINBOND_840 is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -CONFIG_KDB=y -CONFIG_KDB_MODULES=y -# CONFIG_KDB_OFF is not set - -# -# Load all symbols for debugging is required for KDB -# -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp Wed Dec 31 16:00:00 1969 @@ -1,772 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -# CONFIG_NUMA is not set -# CONFIG_IA64_MCA is not set -CONFIG_PM=y -CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_BLK_DEV_ADMA=y -# CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_IDEDMA_PCI_AUTO is not set -CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_IDEDMA_PCI_WIP is not set -# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_AEC62XX_TUNING is not set -# CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_WDC_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD74XX is not set -# CONFIG_AMD74XX_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_BLK_DEV_CY82C693 is not set -# CONFIG_BLK_DEV_CS5530 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_HPT34X_AUTODMA is not set -# CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_BLK_DEV_PIIX is not set -# CONFIG_PIIX_TUNING is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_PDC202XX is not set -# CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_FORCE is not set -# CONFIG_BLK_DEV_SVWKS is not set -# CONFIG_BLK_DEV_SIS5513 is not set -# CONFIG_BLK_DEV_SLC90E66 is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_IDEDMA_IVB is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -CONFIG_SCSI_QLOGIC_1280=y -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -CONFIG_DUMMY=y -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_PCI=y -# CONFIG_PCNET32 is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -# CONFIG_TULIP is not set -# CONFIG_DE4X5 is not set -# CONFIG_DGRS is not set -# CONFIG_DM9102 is not set -CONFIG_EEPRO100=y -# CONFIG_LNE390 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_NE3210 is not set -# CONFIG_ES3210 is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -# CONFIG_8139TOO_8129 is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_WINBOND_840 is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-dig-mp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-dig-mp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-dig-mp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-dig-mp Wed Dec 31 16:00:00 1969 @@ -1,459 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -# CONFIG_NUMA is not set -# CONFIG_IA64_MCA is not set -CONFIG_PM=y -CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y -# CONFIG_DEVFS_FS is not set -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -# CONFIG_IA32_SUPPORT is not set -# CONFIG_PERFMON is not set -# CONFIG_IA64_PALINFO is not set -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-dig-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-dig-sp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-dig-sp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-dig-sp Wed Dec 31 16:00:00 1969 @@ -1,459 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -# CONFIG_NUMA is not set -# CONFIG_IA64_MCA is not set -CONFIG_PM=y -CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y -# CONFIG_DEVFS_FS is not set -CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -# CONFIG_IA32_SUPPORT is not set -# CONFIG_PERFMON is not set -# CONFIG_IA64_PALINFO is not set -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-generic-mp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-generic-mp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-generic-mp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-generic-mp Wed Dec 31 16:00:00 1969 @@ -1,460 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -CONFIG_IA64_GENERIC=y -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -# CONFIG_IA32_SUPPORT is not set -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# Simulated drivers -# -# CONFIG_SIMETH is not set -# CONFIG_SIM_SERIAL is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-generic-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-generic-sp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-generic-sp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-generic-sp Wed Dec 31 16:00:00 1969 @@ -1,460 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -CONFIG_IA64_GENERIC=y -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -# CONFIG_IA32_SUPPORT is not set -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# Simulated drivers -# -# CONFIG_SIMETH is not set -# CONFIG_SIM_SERIAL is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-hp-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-hp-sp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-hp-sp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-hp-sp Wed Dec 31 16:00:00 1969 @@ -1,334 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -CONFIG_IA64_HP_SIM=y -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -# CONFIG_IA32_SUPPORT is not set -# CONFIG_PERFMON is not set -# CONFIG_IA64_PALINFO is not set -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set - -# -# Networking options -# -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_PPA is not set -# CONFIG_SCSI_IMM is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -# CONFIG_NFS_FS is not set -# CONFIG_NFS_V3 is not set -# CONFIG_ROOT_NFS is not set -# CONFIG_NFSD is not set -# CONFIG_NFSD_V3 is not set -# CONFIG_SUNRPC is not set -# CONFIG_LOCKD is not set -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Simulated drivers -# -CONFIG_SIMETH=y -CONFIG_SIM_SERIAL=y -CONFIG_SCSI_SIM=y - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-prom-medusa linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-prom-medusa --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-prom-medusa Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-prom-medusa Wed Dec 31 16:00:00 1969 @@ -1,529 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -CONFIG_IA64_SGI_SN1=y -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -# CONFIG_DEVFS_DEBUG is not set -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -# CONFIG_IA32_SUPPORT is not set -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-mp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-mp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp Wed Dec 31 16:00:00 1969 @@ -1,736 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -CONFIG_IA64_SGI_SN1=y -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK_DEV=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y -CONFIG_FILTER=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_SGI_IOC3_ETH=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="n" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -CONFIG_KDB=y -CONFIG_KDB_MODULES=y -# CONFIG_KDB_OFF is not set - -# -# Load all symbols for debugging is required for KDB -# -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules Wed Dec 31 16:00:00 1969 @@ -1,738 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -CONFIG_IA64_SGI_SN1=y -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK_DEV=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y -CONFIG_FILTER=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_SGI_IOC3_ETH=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="n" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -CONFIG_KDB=y -CONFIG_KDB_MODULES=y -# CONFIG_KDB_OFF is not set - -# -# Load all symbols for debugging is required for KDB -# -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 Wed Dec 31 16:00:00 1969 @@ -1,736 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -CONFIG_IA64_SGI_SN1=y -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK_DEV=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y -CONFIG_FILTER=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_SGI_IOC3_ETH=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="n" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -CONFIG_KDB=y -CONFIG_KDB_MODULES=y -# CONFIG_KDB_OFF is not set - -# -# Load all symbols for debugging is required for KDB -# -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-sp --- linux-2.4.19/arch/ia64/sn/configs/sn1/defconfig-sn1-sp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn1/defconfig-sn1-sp Wed Dec 31 16:00:00 1969 @@ -1,736 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -CONFIG_IA64_SGI_SN1=y -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK_DEV=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y -CONFIG_FILTER=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_SGI_IOC3_ETH=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="n" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -CONFIG_KDB=y -CONFIG_KDB_MODULES=y -# CONFIG_KDB_OFF is not set - -# -# Load all symbols for debugging is required for KDB -# -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-dig-numa linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-dig-numa --- linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-dig-numa Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-dig-numa Wed Dec 31 16:00:00 1969 @@ -1,460 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -CONFIG_NUMA=y -CONFIG_DISCONTIGMEM=y -# CONFIG_IA64_MCA is not set -CONFIG_PM=y -CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y -# CONFIG_DEVFS_FS is not set -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -# CONFIG_IA32_SUPPORT is not set -# CONFIG_PERFMON is not set -# CONFIG_IA64_PALINFO is not set -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp --- linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp Wed Dec 31 16:00:00 1969 @@ -1,459 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -# CONFIG_NUMA is not set -# CONFIG_IA64_MCA is not set -CONFIG_PM=y -CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y -# CONFIG_DEVFS_FS is not set -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -# CONFIG_IA32_SUPPORT is not set -# CONFIG_PERFMON is not set -# CONFIG_IA64_PALINFO is not set -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp --- linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp Wed Dec 31 16:00:00 1969 @@ -1,459 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -# CONFIG_EXPERIMENTAL is not set - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -CONFIG_ITANIUM=y -# CONFIG_MCKINLEY is not set -# CONFIG_IA64_GENERIC is not set -CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -# CONFIG_IA64_SGI_SN2 is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_BRL_EMU=y -CONFIG_ITANIUM_BSTEP_SPECIFIC=y -CONFIG_IA64_L1_CACHE_SHIFT=6 -# CONFIG_NUMA is not set -# CONFIG_IA64_MCA is not set -CONFIG_PM=y -CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y -# CONFIG_DEVFS_FS is not set -CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -# CONFIG_IA32_SUPPORT is not set -# CONFIG_PERFMON is not set -# CONFIG_IA64_PALINFO is not set -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -# CONFIG_XSCSI is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_XFS_SUPPORT is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y - -# -# Frame-buffer support -# -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-mp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp --- linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-mp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp Wed Dec 31 16:00:00 1969 @@ -1,730 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -CONFIG_IA64_SGI_SN2=y -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_MCKINLEY_ASTEP_SPECIFIC=y -CONFIG_MCKINLEY_A0_SPECIFIC=y -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK_DEV=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y -CONFIG_FILTER=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="n" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules --- linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules Wed Dec 31 16:00:00 1969 @@ -1,732 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -CONFIG_IA64_SGI_SN2=y -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_MCKINLEY_ASTEP_SPECIFIC=y -CONFIG_MCKINLEY_A0_SPECIFIC=y -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -# CONFIG_SERIAL_SGI_L1_PROTOCOL is not set -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK_DEV=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y -CONFIG_FILTER=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="n" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa --- linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa Wed Dec 31 16:00:00 1969 @@ -1,537 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -CONFIG_IA64_SGI_SN2=y -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_MCKINLEY_ASTEP_SPECIFIC=y -CONFIG_MCKINLEY_A0_SPECIFIC=y -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -CONFIG_SMP=y -# CONFIG_IA32_SUPPORT is not set -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -# CONFIG_NET is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_EFI_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y -# CONFIG_NCPFS_NLS is not set -# CONFIG_SMB_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# - -# -# Networking support is needed for USB Networking device support -# - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -# CONFIG_KALLSYMS is not set diff -Nur linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-sp linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-sp --- linux-2.4.19/arch/ia64/sn/configs/sn2/defconfig-sn2-sp Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/configs/sn2/defconfig-sn2-sp Wed Dec 31 16:00:00 1969 @@ -1,730 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Loadable module support -# -# CONFIG_MODULES is not set - -# -# General setup -# -CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_INTERPRETER=y -CONFIG_ACPI_KERNEL_CONFIG=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y -# CONFIG_IA64_GENERIC is not set -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_SGI_SN1 is not set -CONFIG_IA64_SGI_SN2=y -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_MCKINLEY_ASTEP_SPECIFIC=y -CONFIG_MCKINLEY_A0_SPECIFIC=y -CONFIG_IA64_SGI_SN=y -CONFIG_IA64_SGI_SN_DEBUG=y -CONFIG_IA64_SGI_SN_SIM=y -CONFIG_IA64_SGI_AUTOTEST=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_DEBUG=y -CONFIG_SERIAL_SGI_L1_PROTOCOL=y -CONFIG_DISCONTIGMEM=y -CONFIG_IA64_MCA=y -CONFIG_NUMA=y -CONFIG_PERCPU_IRQ=y -CONFIG_PCIBA=y -CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -CONFIG_IA32_SUPPORT=y -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -# CONFIG_EFI_VARS is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_BUSMGR is not set -# CONFIG_ACPI_SYS is not set -# CONFIG_ACPI_CPU is not set -# CONFIG_ACPI_BUTTON is not set -# CONFIG_ACPI_AC is not set -# CONFIG_ACPI_EC is not set -# CONFIG_ACPI_CMBATT is not set -# CONFIG_ACPI_THERMAL is not set -CONFIG_PCI=y -# CONFIG_PCI_NAMES is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NETLINK_DEV=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_DEBUG=y -CONFIG_FILTER=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# ATA/IDE/MFM/RLL support -# -CONFIG_IDE=y - -# -# IDE, ATA and ATAPI Block devices -# -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -# CONFIG_BLK_DEV_HD is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set -# CONFIG_BLK_DEV_IDECS is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_DMA_NONPCI is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_ATARAID is not set -# CONFIG_BLK_DEV_ATARAID_PDC is not set -# CONFIG_BLK_DEV_ATARAID_HPT is not set - -# -# Alternate 1394 support -# -# CONFIG_X1394 is not set - -# -# Alternate SCSI support -# -CONFIG_XSCSI=y - -# -# Alternate SCSI support -# -CONFIG_XSCSI_DKSC=y -# CONFIG_XSCSI_QLFC is not set -# CONFIG_XSCSI_QL is not set -# CONFIG_XSCSI_SBP2 is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_DEBUG_QUEUES is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -CONFIG_SCSI_QLOGIC_FC=y -# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_QLA2100 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_SUNLANCE is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -CONFIG_EFI_RTC=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -# CONFIG_CRAMFS is not set -CONFIG_TMPFS=y -# CONFIG_RAMFS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -CONFIG_DEVFS_DEBUG=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set -CONFIG_XFS_SUPPORT=y - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="n" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# - -# -# Input core support is needed for USB HID -# - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# Bluetooth support -# -# CONFIG_BLUEZ is not set - -# -# Kernel hacking -# -CONFIG_DEBUG_KERNEL=y -CONFIG_IA64_PRINT_HAZARDS=y -# CONFIG_DISABLE_VHPT is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_IA64_EARLY_PRINTK=y -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_KDB is not set -# CONFIG_KDB_MODULES is not set -CONFIG_KALLSYMS=y diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/Makefile --- linux-2.4.19/arch/ia64/sn/fakeprom/Makefile Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/Makefile Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (c) 2000-2001 Silicon Graphics, Inc. All rights reserved. +# Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. # TOPDIR=../../../.. diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/README linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/README --- linux-2.4.19/arch/ia64/sn/fakeprom/README Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/README Mon Dec 30 14:16:56 2002 @@ -1,3 +1,35 @@ +/* + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + This directory contains the files required to build the fake PROM image that is currently being used to boot IA64 kernels running under the SGI Medusa kernel. diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/fpmem.c linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fpmem.c --- linux-2.4.19/arch/ia64/sn/fakeprom/fpmem.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fpmem.c Fri Feb 7 08:55:45 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -18,7 +18,7 @@ */ #include -#include +#include #include "fpmem.h" /* @@ -54,10 +54,10 @@ #define PROMRESERVED_SIZE (1*MB) #ifdef CONFIG_IA64_SGI_SN1 -#define PHYS_ADDRESS(_n, _x) (((long)_n<<33L) | (long)_x) +#define PHYS_ADDRESS(_n, _x) (((long)_n<<33) | (long)_x) #define MD_BANK_SHFT 30 #else -#define PHYS_ADDRESS(_n, _x) (((long)_n<<38L) | (long)_x | 0x3000000000UL) +#define PHYS_ADDRESS(_n, _x) (((long)_n<<38) | (long)_x | 0x3000000000UL) #define MD_BANK_SHFT 34 #endif @@ -94,7 +94,7 @@ int IsCpuPresent(int cnode, int cpu) { - return sn_memmap[cnode].cpuconfig & (1<type = type; md->phys_addr = paddr; md->virt_addr = 0; md->num_pages = numbytes >> 12; - md->attribute = EFI_MEMORY_WB; + md->attribute = attr; } int @@ -205,7 +205,17 @@ */ numbytes = numbytes * 31 / 32; #endif - numbytes -= 1000; + /* + * Only emulate the memory prom grabs + * if we have lots of memory, to allow + * us to simulate smaller memory configs than + * we can actually run on h/w. Otherwise, + * linux throws away a whole "granule". + */ + if (cnode == 0 && bank == 0 && + numbytes > 128*1024*1024) { + numbytes -= 1000; + } /* * Check for the node 0 hole. Since banks cant @@ -226,28 +236,40 @@ */ if (bank == 0) { if (cnode == 0) { + hole = 2*1024*1024; + build_mem_desc(md, EFI_PAL_CODE, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB); + numbytes -= hole; + paddr += hole; + count++ ; + md += mdsize; hole = 1*1024*1024; - build_mem_desc(md, EFI_PAL_CODE, paddr, hole); + build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, hole, EFI_MEMORY_UC); numbytes -= hole; paddr += hole; count++ ; md += mdsize; - hole = 3*1024*1024; - build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole); + hole = 1*1024*1024; + build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB); numbytes -= hole; paddr += hole; count++ ; md += mdsize; } else { - hole = PROMRESERVED_SIZE; - build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole); + hole = 2*1024*1024; + build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB); + numbytes -= hole; + paddr += hole; + count++ ; + md += mdsize; + hole = 2*1024*1024; + build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_UC); numbytes -= hole; paddr += hole; count++ ; md += mdsize; } } - build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, numbytes); + build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, numbytes, EFI_MEMORY_WB|EFI_MEMORY_WB); md += mdsize ; count++ ; diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/fpmem.h linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fpmem.h --- linux-2.4.19/arch/ia64/sn/fakeprom/fpmem.h Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fpmem.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/fprom.lds linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fprom.lds --- linux-2.4.19/arch/ia64/sn/fakeprom/fprom.lds Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fprom.lds Mon Dec 30 14:16:56 2002 @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ OUTPUT_FORMAT("elf64-ia64-little") OUTPUT_ARCH(ia64) diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/fpromasm.S linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fpromasm.S --- linux-2.4.19/arch/ia64/sn/fakeprom/fpromasm.S Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fpromasm.S Mon Dec 30 14:16:56 2002 @@ -8,7 +8,7 @@ * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -180,7 +180,7 @@ // Now call main & pass it the current LID value. - alloc r0=ar.pfs,0,0,2,0 + alloc r2=ar.pfs,0,0,2,0 mov r32=r26 mov r33=r8;; br.call.sptk.few rp=fmain diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/fw-emu.c linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fw-emu.c --- linux-2.4.19/arch/ia64/sn/fakeprom/fw-emu.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/fw-emu.c Mon Dec 30 14:16:56 2002 @@ -5,7 +5,7 @@ * Copyright (C) 1998-2000 David Mosberger-Tang * * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -36,7 +36,7 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ #include -#include +#include #include #include #include @@ -46,10 +46,26 @@ #include #include #endif -#include +#include #include "fpmem.h" -#define zzACPI_1_0 1 /* Include ACPI 1.0 tables */ +#define RSDP_NAME "RSDP" +#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */ +#define APIC_SIG "APIC" /* Multiple APIC Description Table */ +#define DSDT_SIG "DSDT" /* Differentiated System Description Table */ +#define FADT_SIG "FACP" /* Fixed ACPI Description Table */ +#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */ +#define PSDT_SIG "PSDT" /* Persistent System Description Table */ +#define RSDT_SIG "RSDT" /* Root System Description Table */ +#define XSDT_SIG "XSDT" /* Extended System Description Table */ +#define SSDT_SIG "SSDT" /* Secondary System Description Table */ +#define SBST_SIG "SBST" /* Smart Battery Specification Table */ +#define SPIC_SIG "SPIC" /* IOSAPIC table */ +#define SRAT_SIG "SRAT" /* SRAT table */ +#define SLIT_SIG "SLIT" /* SLIT table */ +#define BOOT_SIG "BOOT" /* Boot table */ +#define ACPI_SRAT_REVISION 1 +#define ACPI_SLIT_REVISION 1 #define OEMID "SGI" #ifdef CONFIG_IA64_SGI_SN1 @@ -77,11 +93,7 @@ #define CPUS_PER_FSB 2 #define CPUS_PER_FSB_MASK (CPUS_PER_FSB-1) -#ifdef ACPI_1_0 -#define NUM_EFI_DESCS 3 -#else #define NUM_EFI_DESCS 2 -#endif #define RSDP_CHECKSUM_LENGTH 20 @@ -139,22 +151,16 @@ + sizeof(struct ia64_sal_systab) + sizeof(struct ia64_sal_desc_entry_point) + sizeof(struct ia64_sal_desc_ap_wakeup) -#ifdef ACPI_1_0 - + sizeof(acpi_rsdp_t) - + sizeof(acpi_rsdt_t) - + sizeof(acpi_sapic_t) - + MAX_LSAPICS*(sizeof(acpi_entry_lsapic_t)) -#endif - + sizeof(acpi20_rsdp_t) - + sizeof(acpi_xsdt_t) - + sizeof(acpi_slit_t) + + sizeof(struct acpi20_table_rsdp) + + sizeof(struct acpi_table_xsdt) + + sizeof(struct acpi_table_slit) + MAX_SN_NODES*MAX_SN_NODES+8 - + sizeof(acpi_madt_t) + + sizeof(struct acpi_table_madt) + 16*MAX_CPUS + (1+8*MAX_SN_NODES)*(sizeof(efi_memory_desc_t)) - + sizeof(acpi_srat_t) - + MAX_CPUS*sizeof(srat_cpu_affinity_t) - + MAX_SN_NODES*sizeof(srat_memory_affinity_t) + + sizeof(struct acpi_table_srat) + + MAX_CPUS*sizeof(struct acpi_table_processor_affinity) + + MAX_SN_NODES*sizeof(struct acpi_table_memory_affinity) + sizeof(ia64_sal_desc_ptc_t) + + MAX_SN_NODES*sizeof(ia64_sal_ptc_domain_info_t) + + MAX_CPUS*sizeof(ia64_sal_ptc_domain_proc_entry_t) + @@ -280,6 +286,7 @@ } else if (index == SAL_GET_STATE_INFO) { ; } else if (index == SAL_GET_STATE_INFO_SIZE) { + r9 = 10000; ; } else if (index == SAL_CLEAR_STATE_INFO) { ; @@ -334,6 +341,8 @@ status = -1; } else if (index == SN_SAL_CONSOLE_POLL) { status = -1; + } else if (index == SN_SAL_SYSCTL_IOBRICK_MODULE_GET) { + status = -1; } else { status = -1; } @@ -402,7 +411,7 @@ } void -acpi_table_init(acpi_desc_table_hdr_t *p, char *sig, int siglen, int revision, int oem_revision) +acpi_table_initx(struct acpi_table_header *p, char *sig, int siglen, int revision, int oem_revision) { memcpy(p->signature, sig, siglen); memcpy(p->oem_id, OEMID, 6); @@ -410,12 +419,12 @@ memcpy(p->oem_table_id+4, PRODUCT, 4); p->revision = revision; p->oem_revision = (revision<<16) + oem_revision; - p->creator_id = 1; - p->creator_revision = 1; + memcpy(p->asl_compiler_id, "FPRM", 4); + p->asl_compiler_revision = 1; } void -acpi_checksum(acpi_desc_table_hdr_t *p, int length) +acpi_checksum(struct acpi_table_header *p, int length) { u8 *cp, *cpe, checksum; @@ -428,16 +437,22 @@ } void -acpi_checksum_rsdp20(acpi20_rsdp_t *p, int length) +acpi_checksum_rsdp20(struct acpi20_table_rsdp *p, int length) { u8 *cp, *cpe, checksum; p->checksum = 0; + p->ext_checksum = 0; p->length = length; checksum = 0; - for (cp=(u8*)p, cpe=cp+RSDP_CHECKSUM_LENGTH; cpchecksum = -checksum; + + checksum = 0; + for (cp=(u8*)p, cpe=cp+length; cpext_checksum = -checksum; } int @@ -462,21 +477,15 @@ static ia64_sal_desc_ptc_t *sal_ptc; static ia64_sal_ptc_domain_info_t *sal_ptcdi; static ia64_sal_ptc_domain_proc_entry_t *sal_ptclid; -#ifdef ACPI_1_0 - static acpi_rsdp_t *acpi_rsdp; - static acpi_rsdt_t *acpi_rsdt; - static acpi_sapic_t *acpi_sapic; - static acpi_entry_lsapic_t *acpi_lsapic; -#endif - static acpi20_rsdp_t *acpi20_rsdp; - static acpi_xsdt_t *acpi_xsdt; - static acpi_slit_t *acpi_slit; - static acpi_madt_t *acpi_madt; - static acpi20_entry_lsapic_t *lsapic20; + static struct acpi20_table_rsdp *acpi20_rsdp; + static struct acpi_table_xsdt *acpi_xsdt; + static struct acpi_table_slit *acpi_slit; + static struct acpi_table_madt *acpi_madt; + static struct acpi_table_lsapic *lsapic20; static struct ia64_sal_systab *sal_systab; - static acpi_srat_t *acpi_srat; - static srat_cpu_affinity_t *srat_cpu_affinity; - static srat_memory_affinity_t *srat_memory_affinity; + static struct acpi_table_srat *acpi_srat; + static struct acpi_table_processor_affinity *srat_cpu_affinity; + static struct acpi_table_memory_affinity *srat_memory_affinity; static efi_memory_desc_t *efi_memmap, *md; static unsigned long *pal_desc, *sal_desc; static struct ia64_sal_desc_entry_point *sal_ed; @@ -525,16 +534,10 @@ acpi_xsdt = (void *) cp; cp += ALIGN8(sizeof(*acpi_xsdt) + 64); /* save space for more OS defined table pointers. */ -#ifdef ACPI_1_0 - acpi_rsdp = (void *) cp; cp += ALIGN8(sizeof(*acpi_rsdp)); - acpi_rsdt = (void *) cp; cp += ALIGN8(sizeof(*acpi_rsdt)); - acpi_sapic = (void *) cp; cp += sizeof(*acpi_sapic); - acpi_lsapic = (void *) cp; cp += num_cpus*sizeof(*acpi_lsapic); -#endif acpi_slit = (void *) cp; cp += ALIGN8(sizeof(*acpi_slit) + 8 + (max_nasid+1)*(max_nasid+1)); - acpi_madt = (void *) cp; cp += ALIGN8(sizeof(*acpi_madt) + 8 * num_cpus+ 8); - acpi_srat = (void *) cp; cp += ALIGN8(sizeof(acpi_srat_t)); - cp += sizeof(srat_cpu_affinity_t)*num_cpus + sizeof(srat_memory_affinity_t)*num_nodes; + acpi_madt = (void *) cp; cp += ALIGN8(sizeof(*acpi_madt) + sizeof(struct acpi_table_lsapic) * (num_cpus+1)); + acpi_srat = (void *) cp; cp += ALIGN8(sizeof(struct acpi_table_srat)); + cp += sizeof(struct acpi_table_processor_affinity)*num_cpus + sizeof(struct acpi_table_memory_affinity)*num_nodes; vendor = (char *) cp; cp += ALIGN8(40); efi_memmap = (void *) cp; cp += ALIGN8(8*32*sizeof(*efi_memmap)); sal_ptcdi = (void *) cp; cp += ALIGN8(CPUS_PER_FSB*(1+num_nodes)*sizeof(*sal_ptcdi)); @@ -585,11 +588,6 @@ efi_tables->guid = SAL_SYSTEM_TABLE_GUID; efi_tables->table = __fwtab_pa(base_nasid, sal_systab); efi_tables++; -#ifdef ACPI_1_0 - efi_tables->guid = ACPI_TABLE_GUID; - efi_tables->table = __fwtab_pa(base_nasid, acpi_rsdp); - efi_tables++; -#endif efi_tables->guid = ACPI_20_TABLE_GUID; efi_tables->table = __fwtab_pa(base_nasid, acpi20_rsdp); efi_tables++; @@ -600,65 +598,32 @@ fix_function_pointer(&efi_reset_system); fix_function_pointer(&efi_set_virtual_address_map); -#ifdef ACPI_1_0 - /* fill in the ACPI system table - has a pointer to the ACPI table header */ - memcpy(acpi_rsdp->signature, "RSD PTR ", 8); - acpi_rsdp->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt); - - acpi_table_init(&acpi_rsdt->header, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN, 1, 1); - acpi_rsdt->header.length = sizeof(acpi_rsdt_t); - acpi_rsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_sapic); - - memcpy(acpi_sapic->header.signature, "SPIC ", 4); - acpi_sapic->header.length = sizeof(acpi_sapic_t)+num_cpus*sizeof(acpi_entry_lsapic_t); - - for (cnode=0; cnodetype = ACPI_ENTRY_LOCAL_SAPIC; - acpi_lsapic->length = sizeof(acpi_entry_lsapic_t); - acpi_lsapic->acpi_processor_id = cnode*4+cpu; - acpi_lsapic->flags = LSAPIC_ENABLED|LSAPIC_PRESENT; -#if defined(CONFIG_IA64_SGI_SN1) - acpi_lsapic->eid = cpu; - acpi_lsapic->id = nasid; -#else - acpi_lsapic->eid = nasid&0xffff; - acpi_lsapic->id = (cpu<<4) | (nasid>>16); -#endif - acpi_lsapic++; - } - } -#endif - /* fill in the ACPI20 system table - has a pointer to the ACPI table header */ memcpy(acpi20_rsdp->signature, "RSD PTR ", 8); - acpi20_rsdp->xsdt = (struct acpi_xsdt*)__fwtab_pa(base_nasid, acpi_xsdt); + acpi20_rsdp->xsdt_address = (u64)__fwtab_pa(base_nasid, acpi_xsdt); acpi20_rsdp->revision = 2; - acpi_checksum_rsdp20(acpi20_rsdp, sizeof(acpi20_rsdp_t)); + acpi_checksum_rsdp20(acpi20_rsdp, sizeof(struct acpi20_table_rsdp)); /* Set up the XSDT table - contains pointers to the other ACPI tables */ - acpi_table_init(&acpi_xsdt->header, ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN, 1, 1); - acpi_xsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_madt); - acpi_xsdt->entry_ptrs[1] = __fwtab_pa(base_nasid, acpi_slit); - acpi_xsdt->entry_ptrs[2] = __fwtab_pa(base_nasid, acpi_srat); - acpi_checksum(&acpi_xsdt->header, sizeof(acpi_xsdt_t) + 16); - - /* Set up the MADT table */ - acpi_table_init(&acpi_madt->header, ACPI_MADT_SIG, ACPI_MADT_SIG_LEN, 1, 1); - lsapic20 = (acpi20_entry_lsapic_t*) (acpi_madt + 1); + acpi_table_initx(&acpi_xsdt->header, XSDT_SIG, 4, 1, 1); + acpi_xsdt->entry[0] = __fwtab_pa(base_nasid, acpi_madt); + acpi_xsdt->entry[1] = __fwtab_pa(base_nasid, acpi_slit); + acpi_xsdt->entry[2] = __fwtab_pa(base_nasid, acpi_srat); + acpi_checksum(&acpi_xsdt->header, sizeof(struct acpi_table_xsdt) + 16); + + /* Set up the APIC table */ + acpi_table_initx(&acpi_madt->header, APIC_SIG, 4, 1, 1); + lsapic20 = (struct acpi_table_lsapic*) (acpi_madt + 1); for (cnode=0; cnodetype = ACPI20_ENTRY_LOCAL_SAPIC; - lsapic20->length = sizeof(acpi_entry_lsapic_t); - lsapic20->acpi_processor_id = cnode*4+cpu; - lsapic20->flags = LSAPIC_ENABLED|LSAPIC_PRESENT; + lsapic20->header.type = ACPI_MADT_LSAPIC; + lsapic20->header.length = sizeof(struct acpi_table_lsapic); + lsapic20->acpi_id = cnode*4+cpu; + lsapic20->flags.enabled = 1; #if defined(CONFIG_IA64_SGI_SN1) lsapic20->eid = cpu; lsapic20->id = nasid; @@ -666,20 +631,20 @@ lsapic20->eid = nasid&0xffff; lsapic20->id = (cpu<<4) | (nasid>>16); #endif - lsapic20 = (acpi20_entry_lsapic_t*) ((long)lsapic20+sizeof(acpi_entry_lsapic_t)); + lsapic20 = (struct acpi_table_lsapic*) ((long)lsapic20+sizeof(struct acpi_table_lsapic)); } } acpi_checksum(&acpi_madt->header, (char*)lsapic20 - (char*)acpi_madt); /* Set up the SRAT table */ - acpi_table_init(&acpi_srat->header, ACPI_SRAT_SIG, ACPI_SRAT_SIG_LEN, ACPI_SRAT_REVISION, 1); + acpi_table_initx(&acpi_srat->header, SRAT_SIG, 4, ACPI_SRAT_REVISION, 1); ptr = acpi_srat+1; for (cnode=0; cnodetype = SRAT_MEMORY_STRUCTURE; - srat_memory_affinity->length = sizeof(srat_memory_affinity_t); + srat_memory_affinity->header.type = ACPI_SRAT_MEMORY_AFFINITY; + srat_memory_affinity->header.length = sizeof(struct acpi_table_memory_affinity); srat_memory_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); srat_memory_affinity->base_addr_lo = 0; srat_memory_affinity->length_lo = 0; @@ -691,7 +656,7 @@ srat_memory_affinity->length_hi = SN2_NODE_SIZE>>32; #endif srat_memory_affinity->memory_type = ACPI_ADDRESS_RANGE_MEMORY; - srat_memory_affinity->flags = SRAT_MEMORY_FLAGS_ENABLED; + srat_memory_affinity->flags.enabled = 1; } for (cnode=0; cnodetype = SRAT_CPU_STRUCTURE; - srat_cpu_affinity->length = sizeof(srat_cpu_affinity_t); + srat_cpu_affinity->header.type = ACPI_SRAT_PROCESSOR_AFFINITY; + srat_cpu_affinity->header.length = sizeof(struct acpi_table_processor_affinity); srat_cpu_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); - srat_cpu_affinity->flags = SRAT_CPU_FLAGS_ENABLED; + srat_cpu_affinity->flags.enabled = 1; #if defined(CONFIG_IA64_SGI_SN1) srat_cpu_affinity->apic_id = nasid; - srat_cpu_affinity->local_sapic_eid = cpu; + srat_cpu_affinity->lsapic_eid = cpu; #else - srat_cpu_affinity->local_sapic_eid = nasid&0xffff; + srat_cpu_affinity->lsapic_eid = nasid&0xffff; srat_cpu_affinity->apic_id = (cpu<<4) | (nasid>>16); #endif } @@ -718,9 +683,9 @@ /* Set up the SLIT table */ - acpi_table_init(&acpi_slit->header, ACPI_SLIT_SIG, ACPI_SLIT_SIG_LEN, ACPI_SLIT_REVISION, 1); + acpi_table_initx(&acpi_slit->header, SLIT_SIG, 4, ACPI_SLIT_REVISION, 1); acpi_slit->localities = PROXIMITY_DOMAIN(max_nasid)+1; - cp=acpi_slit->entries; + cp=acpi_slit->entry; memset(cp, 255, acpi_slit->localities*acpi_slit->localities); for (i=0; i<=max_nasid; i++) @@ -728,7 +693,7 @@ if (nasid_present(i) && nasid_present(j)) *(cp+PROXIMITY_DOMAIN(i)*acpi_slit->localities+PROXIMITY_DOMAIN(j)) = 10 + MIN(254, 5*ABS(i-j)); - cp = acpi_slit->entries + acpi_slit->localities*acpi_slit->localities; + cp = acpi_slit->entry + acpi_slit->localities*acpi_slit->localities; acpi_checksum(&acpi_slit->header, cp - (char*)acpi_slit); @@ -738,6 +703,8 @@ sal_systab->sal_rev_minor = 1; sal_systab->sal_rev_major = 0; sal_systab->entry_count = 3; + sal_systab->sal_b_rev_major = 0x1; /* set the SN SAL rev to */ + sal_systab->sal_b_rev_minor = 0x0; /* 1.00 */ strcpy(sal_systab->oem_id, "SGI"); strcpy(sal_systab->product_id, "SN1"); @@ -792,11 +759,6 @@ * table. We dont build enough table & the kernel aborts. * Note that the PROM hasd thhhe same problem!! */ -#ifdef DOESNT_WORK - for (checksum=0, cp=(char*)acpi_rsdp, cpe=cp+RSDP_CHECKSUM_LENGTH; cpchecksum = -checksum; -#endif md = &efi_memmap[0]; num_memmd = build_efi_memmap((void *)md, mdsize) ; diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/klgraph_init.c linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/klgraph_init.c --- linux-2.4.19/arch/ia64/sn/fakeprom/klgraph_init.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/klgraph_init.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ @@ -49,8 +49,9 @@ klgraph_init(void) { - u64 *temp; - +#ifdef CONFIG_IA64_SGI_SN1 + u64 *temp; +#endif /* * Initialize some hub/xbow registers that allows access to * Xbridge etc. These are normally done in PROM. @@ -109,6 +110,8 @@ // [PI] *(volatile u32 *)0xc00000080f000288L = 0xba98; #endif /* CONFIG_IA64_SGI_SN1 */ +#ifdef CONFIG_IA64_SGI_SN1 + /* * kldir entries initialization - mankato */ @@ -282,6 +285,7 @@ convert(0x8000000000002560, 0xffffffffffffffff, 0xffffffffffffffff); convert(0x8000000000002570, 0xffffffffffffffff, 0xffffffffffffffff); convert(0x8000000000002580, 0x000000000000ffff, 0x0000000000000000); +#endif } diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/main.c linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/main.c --- linux-2.4.19/arch/ia64/sn/fakeprom/main.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/main.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -98,7 +98,7 @@ /* * Enable all FSB flashed interrupts. - * ZZZ - I'd really like defines for this...... + * I'd really like defines for this...... */ base = (long*)0x80000e0000000000LL; /* base of synergy regs */ for (off = 0x2a0; off < 0x2e0; off+=8) /* offset for VEC_MASK_{0-3}_A/B */ diff -Nur linux-2.4.19/arch/ia64/sn/fakeprom/runsim linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/runsim --- linux-2.4.19/arch/ia64/sn/fakeprom/runsim Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/fakeprom/runsim Wed Dec 31 16:00:00 1969 @@ -1,387 +0,0 @@ -#!/bin/sh - -# Script for running PROMs and LINUX kernwls on medusa. -# Type "sim -H" for instructions. - -MEDUSA=${MEDUSA:-/home/rickc/official_medusa/medusa} - -# ------------------ err ----------------------- -err() { - echo "ERROR - $1" - exit 1 -} - -# ---------------- help ---------------------- -help() { -cat <] <-p> | <-k> [] - -p Create PROM control file & links - -k Create LINUX control file & links - -c Control file name [Default: cf] - Path to directory that contains the linux or PROM files. - The directory can be any of the following: - (linux simulations) - worktree - worktree/linux - any directory with vmlinux, vmlinux.sym & fprom files - (prom simulations) - worktree - worktree/stand/arcs/IP37prom/dev - any directory with fw.bin & fw.sim files - - Simulations: - sim [-X ] [-o ] [-M] [] - -c Control file name [Default: cf] - -M Pipe output thru fmtmedusa - -o Output filename (copy of all commands/output) [Default: simout] - -X Specifies number of instructions to execute [Default: 0] - (Used only in auto test mode - not described here) - -Examples: - sim -p # create control file (cf) & links for prom simulations - sim -k # create control file (cf) & links for linux simulations - sim -p -c cfprom # create a prom control file (cfprom) only. No links are made. - - sim # run medusa using previously created links & - # control file (cf). -END -exit 1 -} - -# ----------------------- create control file header -------------------- -create_cf_header() { -cat <>$CF -# -# Template for a control file for running linux kernels under medusa. -# You probably want to make mods here but this is a good starting point. -# - -# Preferences -setenv cpu_stepping A -setenv exceptionPrint off -setenv interrupt_messages off -setenv lastPCsize 100000 -setenv low_power_mode on -setenv partialIntelChipSet on -setenv printIntelMessages off -setenv prom_write_action halt -setenv prom_write_messages on -setenv step_quantum 100 -setenv swizzling on -setenv tsconsole on -setenv uart_echo on -symbols on - -# IDE disk params -setenv diskCylinders 611 -setenv bootDrive C -setenv diskHeads 16 -setenv diskPath idedisk -setenv diskPresent 1 -setenv diskSpt 63 - -# Hardware config -setenv coherency_type nasid -setenv cpu_cache_type default -setenv synergy_cache_type syn_cac_64m_8w -setenv l4_uc_snoop off - -# Numalink config -setenv route_enable on -setenv network_type router # Select [xbar|router] -setenv network_warning 0xff - -END -} - - -# ------------------ create control file entries for linux simulations ------------- -create_cf_linux() { -cat <>$CF -# Kernel specific options -setenv calias_size 0 -setenv mca_on_memory_failure off -setenv LOADPC 0x00100000 # FPROM load address/entry point (8 digits!) -setenv symbol_table vmlinux.sym -load fprom -load vmlinux - -# Useful breakpoints to always have set. Add more if desired. -break 0xe000000000505e00 all # dispatch_to_fault_handler -break panic all # stop on panic -break die_if_kernel all # may as well stop - -END -} - -# ------------------ create control file entries for prom simulations --------------- -create_cf_prom() { - SYM2="" - ADDR="0x80000000ff800000" - [ "$EMBEDDED_LINUX" != "0" ] || SYM2="setenv symbol_table2 vmlinux.sym" - [ "$SIZE" = "8MB" ] || ADDR="0x80000000ffc00000" - cat <>$CF -# PROM specific options -setenv mca_on_memory_failure on -setenv LOADPC 0x80000000ffffffb0 -setenv promFile fw.bin -setenv promAddr $ADDR -setenv symbol_table fw.sym -$SYM2 - -# Useful breakpoints to always have set. Add more if desired. -break ivt_gexx all -break ivt_brk all -break PROM_Panic_Spin all -break PROM_Panic all -break PROM_C_Panic all -break fled_die all -break ResetNow all -break zzzbkpt all - -END -} - - -# ------------------ create control file entries for memory configuration ------------- -create_cf_memory() { -cat <>$CF -# CPU/Memory map format: -# setenv nodeN_memory_config 0xBSBSBSBS -# B=banksize (0=unused, 1=64M, 2=128M, .., 5-1G, c=8M, d=16M, e=32M) -# S=bank enable (0=both disable, 3=both enable, 2=bank1 enable, 1=bank0 enable) -# rightmost digits are for bank 0, the lowest address. -# setenv nodeN_nasid -# specifies the NASID for the node. This is used ONLY if booting the kernel. -# On PROM configurations, set to 0 - PROM will change it later. -# setenv nodeN_cpu_config -# Set bit number N to 1 to enable cpu N. Ex., a value of 5 enables cpu 0 & 2. -# -# Repeat the above 3 commands for each node. -# -# For kernel, default to 32MB. Although this is not a valid hardware configuration, -# it runs faster on medusa. For PROM, 64MB is smallest allowed value. - -setenv node0_cpu_config 0x1 # Enable only cpu 0 on the node -END - -if [ $LINUX -eq 1 ] ; then -cat <>$CF -setenv node0_nasid 0 # cnode 0 has NASID 0 -setenv node0_memory_config 0xe1 # 32MB -END -else -cat <>$CF -setenv node0_memory_config 0x31 # 256MB -END -fi -} - -# -------------------- set links to linux files ------------------------- -set_linux_links() { - if [ -d $D/linux/arch ] ; then - D=$D/linux - elif [ -d $D/arch -o -e vmlinux.sym -o -e $D/vmlinux ] ; then - D=$D - else - err "cant determine directory for linux binaries" - fi - rm -rf vmlinux vmlinux.sym fprom - ln -s $D/vmlinux vmlinux - if [ -f $D/vmlinux.sym ] ; then - ln -s $D/vmlinux.sym vmlinux.sym - elif [ -f $D/System.map ] ; then - ln -s $D/System.map vmlinux.sym - fi - if [ -d $D/arch ] ; then - ln -s $D/arch/ia64/sn/fprom/fprom fprom - else - ln -s $D/fprom fprom - fi - echo " .. Created links to linux files" -} - -# -------------------- set links to prom files ------------------------- -set_prom_links() { - if [ -d $D/stand ] ; then - D=$D/stand/arcs/IP37prom/dev - elif [ -d $D/sal ] ; then - D=$D - else - err "cant determine directory for PROM binaries" - fi - SETUP="/tmp/tmp.$$" - rm -r -f $SETUP - sed 's/export/setenv/' < $D/../../../../.setup | sed 's/=/ /' >$SETUP - egrep -q '^ *setenv *PROMSIZE *8MB|^ *export' $SETUP - if [ $? -eq 0 ] ; then - SIZE="8MB" - else - SIZE="4MB" - fi - grep -q '^ *setenv *LAUNCH_VMLINUX' $SETUP - EMBEDDED_LINUX=$? - PRODUCT=`grep '^ *setenv *PRODUCT' $SETUP | cut -d" " -f3` - rm -f fw.bin fw.map fw.sym vmlinux vmlinux.sym fprom $SETUP - SDIR="${PRODUCT}${SIZE}.O" - BIN="${PRODUCT}ip37prom${SIZE}" - ln -s $D/$SDIR/$BIN.bin fw.bin - ln -s $D/$SDIR/$BIN.map fw.map - ln -s $D/$SDIR/$BIN.sym fw.sym - echo " .. Created links to $SIZE prom files" - if [ $EMBEDDED_LINUX -eq 0 ] ; then - ln -s $D/linux/vmlinux vmlinux - ln -s $D/linux/vmlinux.sym vmlinux.sym - if [ -d linux/arch ] ; then - ln -s $D/linux/arch/ia64/sn/fprom/fprom fprom - else - ln -s $D/linux/fprom fprom - fi - echo " .. Created links to embedded linux files in prom tree" - fi -} - -# --------------- start of shell script -------------------------------- -OUT="simout" -FMTMED=0 -STEPCNT=0 -PROM=0 -LINUX=0 -NCF="cf" -while getopts "HMX:c:o:pk" c ; do - case ${c} in - H) help;; - M) FMTMED=1;; - X) STEPCNT=${OPTARG};; - c) NCF=${OPTARG};; - k) PROM=0;LINUX=1;; - p) PROM=1;LINUX=0;; - o) OUT=${OPTARG};; - \?) exit 1;; - esac -done -shift `expr ${OPTIND} - 1` - -# Check if command is for creating control file and/or links to images. -if [ $PROM -eq 1 -o $LINUX -eq 1 ] ; then - CF=$NCF - [ ! -f $CF ] || err "wont overwrite an existing control file ($CF)" - if [ $# -gt 0 ] ; then - D=$1 - [ -d $D ] || err "cannot find directory $D" - [ $PROM -eq 0 ] || set_prom_links - [ $LINUX -eq 0 ] || set_linux_links - fi - create_cf_header - [ $PROM -eq 0 ] || create_cf_prom - [ $LINUX -eq 0 ] || create_cf_linux - [ ! -f ../idedisk ] || ln -s ../idedisk . - create_cf_memory - echo " .. Basic control file created (in $CF). You might want to edit" - echo " this file (at least, look at it)." - exit 0 -fi - -# Verify that the control file exists -CF=${1:-$NCF} -[ -f $CF ] || err "No control file exists. For help, type: $0 -H" - -# Build the .cf files from the user control file. The .cf file is -# identical except that the actual start & load addresses are inserted -# into the file. In addition, the FPROM commands for configuring memory -# and LIDs are generated. - -rm -f .cf .cf1 .cf2 -awk ' -function strtonum(n) { - if (substr(n,1,2) != "0x") - return int(n) - n = substr(n,3) - r=0 - while (length(n) > 0) { - r = r*16+(index("0123456789abcdef", substr(n,1,1))-1) - n = substr(n,2) - } - return r - } -/^#/ {next} -/^$/ {next} -/^setenv *LOADPC/ {loadpc = $3; next} -/^setenv *node.._cpu_config/ {n=int(substr($2,5,2)); cpuconf[n] = strtonum($3); print; next} -/^setenv *node.._memory_config/ {n=int(substr($2,5,2)); memconf[n] = strtonum($3); print; next} -/^setenv *node.._nasid/ {n=int(substr($2,5,2)); nasid[n] = strtonum($3); print; next} -/^setenv *node._cpu_config/ {n=int(substr($2,5,1)); cpuconf[n] = strtonum($3); print; next} -/^setenv *node._memory_config/ {n=int(substr($2,5,1)); memconf[n] = strtonum($3); print; next} -/^setenv *node._nasid/ {n=int(substr($2,5,1)); nasid[n] = strtonum($3); print; next} - {print} -END { - # Generate the memmap info that starts at the beginning of - # the node the kernel was loaded on. - loadnasid = nasid[0] - cnode = 0 - for (i=0; i<128; i++) { - if (memconf[i] != "") { - printf "sm 0x%x%08x 0x%x%04x%04x\n", - 2*loadnasid, 8*cnodes+8, memconf[i], cpuconf[i], nasid[i] - cnodes++ - cpus += substr("0112122312232334", cpuconf[i]+1,1) - } - } - printf "sm 0x%x00000000 0x%x%08x\n", 2*loadnasid, cnodes, cpus - printf "setenv number_of_nodes %d\n", cnodes - - # Now set the starting PC for each cpu. - cnode = 0 - lowcpu=-1 - for (i=0; i<128; i++) { - if (memconf[i] != "") { - printf "setnode %d\n", cnode - conf = cpuconf[i] - for (j=0; j<4; j++) { - if (conf != int(conf/2)*2) { - printf "setcpu %d\n", j - if (length(loadpc) == 18) - printf "sr pc %s\n", loadpc - else - printf "sr pc 0x%x%s\n", 2*loadnasid, substr(loadpc,3) - if (lowcpu == -1) - lowcpu = j - } - conf = int(conf/2) - } - cnode++ - } - } - printf "setnode 0\n" - printf "setcpu %d\n", lowcpu - } -' <$CF >.cf - -# Now build the .cf1 & .cf2 control files. -CF2_LINES="^sm |^break |^run |^si |^quit |^symbols " -egrep "$CF2_LINES" .cf >.cf2 -egrep -v "$CF2_LINES" .cf >.cf1 -if [ $STEPCNT -ne 0 ] ; then - echo "s $STEPCNT" >>.cf2 - echo "lastpc 1000" >>.cf2 - echo "q" >>.cf2 -fi -if [ -f vmlinux.sym ] ; then - awk '/ _start$/ {print "sr g 9 0x" $3}' < vmlinux.sym >> .cf2 -fi -echo "script-on $OUT" >>.cf2 - -# Now start medusa.... -if [ $FMTMED -ne 0 ] ; then - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 | fmtmedusa -elif [ $STEPCNT -eq 0 ] ; then - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 -else - $MEDUSA -system mpsn1 -c .cf1 -i .cf2 2>&1 -fi diff -Nur linux-2.4.19/arch/ia64/sn/io/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/io/Makefile --- linux-2.4.19/arch/ia64/sn/io/Makefile Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/Makefile Fri Jan 3 19:33:41 2003 @@ -3,43 +3,31 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. -# -# -# Makefile for the linux kernel. -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). +# Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. # +# Makefile for the sn kernel routines. EXTRA_CFLAGS := -DLITTLE_ENDIAN -O_TARGET := sgiio.o - -ifeq ($(CONFIG_MODULES),y) -export-objs = pciio.o hcl.o +ifdef CONFIG_IA64_SGI_SN2 +EXTRA_CFLAGS += -DSHUB_SWAP_WAR endif -obj-y := stubs.o sgi_if.o pciio.o xtalk.o xbow.o xswitch.o klgraph_hack.o \ - hcl.o labelcl.o invent.o klgraph.o klconflib.o sgi_io_sim.o \ - module.o sgi_io_init.o klgraph_hack.o ml_SN_init.o \ - ml_iograph.o hcl_util.o cdl.o hubdev.o hubspc.o \ - alenlist.o pci_bus_cvlink.o \ - eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o \ - ifconfig_net.o efi-rtc.o io.o - -obj-$(CONFIG_IA64_SGI_SN1) += sn1/ml_SN_intr.o sn1/mem_refcnt.o sn1/hubcounters.o \ - sn1/ip37.o sn1/huberror.o sn1/hub_intr.o sn1/pcibr.o - -obj-$(CONFIG_IA64_SGI_SN2) += sn2/ml_SN_intr.o sn2/shub_intr.o sn2/shuberror.o \ - sn2/bte_error.o \ - sn2/pcibr/pcibr_dvr.o sn2/pcibr/pcibr_ate.o \ - sn2/pcibr/pcibr_config.o sn2/pcibr/pcibr_dvr.o \ - sn2/pcibr/pcibr_hints.o \ - sn2/pcibr/pcibr_idbg.o sn2/pcibr/pcibr_intr.o \ - sn2/pcibr/pcibr_rrb.o sn2/pcibr/pcibr_slot.o +O_TARGET := sgiio.o + +export-objs := hcl.o pci_dma.o + +obj-y := stubs.o sgi_if.o xswitch.o klgraph_hack.o \ + hcl.o labelcl.o invent.o sgi_io_sim.o \ + klgraph_hack.o hcl_util.o cdl.o hubdev.o hubspc.o \ + alenlist.o pci.o pci_dma.o ate_utils.o \ + ifconfig_net.o io.o ioconfig_bus.o + +obj-$(CONFIG_IA64_SGI_SN1) += sn1/snio.o +obj-$(CONFIG_IA64_SGI_SN2) += sn2/snio.o +obj-$(CONFIG_PCIBA) += pciba.o -obj-$(CONFIG_PCIBA) += pciba.o +subdir-$(CONFIG_IA64_SGI_SN1) += sn1 +subdir-$(CONFIG_IA64_SGI_SN2) += sn2 include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/sn/io/alenlist.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/alenlist.c --- linux-2.4.19/arch/ia64/sn/io/alenlist.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/alenlist.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* Implementation of Address/Length Lists. */ diff -Nur linux-2.4.19/arch/ia64/sn/io/ate_utils.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/ate_utils.c --- linux-2.4.19/arch/ia64/sn/io/ate_utils.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/ate_utils.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/arch/ia64/sn/io/cdl.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/cdl.c --- linux-2.4.19/arch/ia64/sn/io/cdl.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/cdl.c Mon Dec 30 14:16:56 2002 @@ -4,9 +4,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ +#include #include #include #include @@ -19,6 +20,8 @@ /* these get called directly in cdl_add_connpt in fops bypass hack */ extern int pcibr_attach(devfs_handle_t); extern int xbow_attach(devfs_handle_t); +extern int pic_attach(devfs_handle_t); + /* * cdl: Connection and Driver List @@ -35,13 +38,24 @@ int (*attach) (devfs_handle_t); } dummy_reg; +#ifdef CONFIG_IA64_SGI_SN1 #define MAX_SGI_IO_INFRA_DRVR 4 -struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] = +#else +#define MAX_SGI_IO_INFRA_DRVR 7 +#endif +static struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] = { { XBRIDGE_WIDGET_PART_NUM, XBRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops */}, { BRIDGE_WIDGET_PART_NUM, BRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops */}, +#ifndef CONFIG_IA64_SGI_SN1 + { PIC_WIDGET_PART_NUM_BUS0, PIC_WIDGET_MFGR_NUM, pic_attach /* &pic_fops */}, + { PIC_WIDGET_PART_NUM_BUS1, PIC_WIDGET_MFGR_NUM, pic_attach /* &pic_fops */}, +#endif { XXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, { XBOW_WIDGET_PART_NUM, XBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, +#ifndef CONFIG_IA64_SGI_SN1 + { PXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, +#endif }; /* diff -Nur linux-2.4.19/arch/ia64/sn/io/eeprom.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/eeprom.c --- linux-2.4.19/arch/ia64/sn/io/eeprom.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/eeprom.c Wed Dec 31 16:00:00 1969 @@ -1,1422 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * WARNING: There is more than one copy of this file in different isms. - * All copies must be kept exactly in sync. - * Do not modify this file without also updating the following: - * - * irix/kern/io/eeprom.c - * stand/arcs/lib/libsk/ml/eeprom.c - * stand/arcs/lib/libkl/io/eeprom.c - * - * (from time to time they might not be in sync but that's due to bringup - * activity - this comment is to remind us that they eventually have to - * get back together) - * - * eeprom.c - * - * access to board-mounted EEPROMs via the L1 system controllers - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(EEPROM_DEBUG) -#define db_printf(x) printk x -#else -#define db_printf(x) printk x -#endif - -#define BCOPY(x,y,z) memcpy(y,x,z) - -#define UNDERSCORE 0 /* don't convert underscores to hyphens */ -#define HYPHEN 1 /* convert underscores to hyphens */ - -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ); -uint64_t generate_unique_id( char *sn, int sn_len ); -uchar_t char_to_base36( char c ); -int nicify( char *dst, eeprom_brd_record_t *src ); -static void int64_to_hex_string( char *out, uint64_t val ); - -// extern int router_lock( net_vec_t, int, int ); -// extern int router_unlock( net_vec_t ); -#define ROUTER_LOCK(p) // router_lock(p, 10000, 3000000) -#define ROUTER_UNLOCK(p) // router_unlock(p) - -#define IP27LOG_OVNIC "OverrideNIC" - - -/* the following function converts an EEPROM record to a close facsimile - * of the string returned by reading a Dallas Semiconductor NIC (see - * one of the many incarnations of nic.c for details on that driver) - */ -int nicify( char *dst, eeprom_brd_record_t *src ) -{ - int field_len; - uint64_t unique_id; - char *cur_dst = dst; - eeprom_board_ia_t *board; - - board = src->board_ia; - ASSERT( board ); /* there should always be a board info area */ - - /* copy part number */ - strcpy( cur_dst, "Part:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->part_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN ); - cur_dst += field_len; - - /* copy product name */ - strcpy( cur_dst, ";Name:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII ); - field_len = board->product_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE ); - cur_dst += field_len; - - /* copy serial number */ - strcpy( cur_dst, ";Serial:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->serial_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->serial_num, field_len, - HYPHEN); - - cur_dst += field_len; - - /* copy revision */ - strcpy( cur_dst, ";Revision:"); - cur_dst += strlen( cur_dst ); - ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->board_rev_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN ); - cur_dst += field_len; - - /* EEPROMs don't have equivalents for the Group, Capability and - * Variety fields, so we pad these with 0's - */ - strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" ); - cur_dst += strlen( cur_dst ); - - /* use the board serial number to "fake" a laser id */ - strcpy( cur_dst, ";Laser:" ); - cur_dst += strlen( cur_dst ); - unique_id = generate_unique_id( board->serial_num, - board->serial_num_tl & FIELD_LENGTH_MASK ); - int64_to_hex_string( cur_dst, unique_id ); - strcat( dst, ";" ); - - return 1; -} - - -/* These functions borrow heavily from chars2* in nic.c - */ -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ) -{ - int i; - for( i = 0; i < length; i++ ) { - - /* change underscores to hyphens if requested */ - if( from[i] == '_' && change_underscore == HYPHEN ) - to[i] = '-'; - - /* ; and ; are separators, so mustn't appear within - * a field */ - else if( from[i] == ':' || from[i] == ';' ) - to[i] = '?'; - - /* I'm not sure why or if ASCII character 0xff would - * show up in an EEPROM field, but the NIC parsing - * routines wouldn't like it if it did... so we - * get rid of it, just in case. */ - else if( (unsigned char)from[i] == (unsigned char)0xff ) - to[i] = ' '; - - /* unprintable characters are replaced with . */ - else if( from[i] < ' ' || from[i] >= 0x7f ) - to[i] = '.'; - - /* otherwise, just copy the character */ - else - to[i] = from[i]; - } - - if( i == 0 ) { - to[i] = ' '; /* return at least a space... */ - i++; - } - to[i] = 0; /* terminating null */ -} - -/* Note that int64_to_hex_string currently only has a big-endian - * implementation. - */ -#ifdef _MIPSEB -static void int64_to_hex_string( char *out, uint64_t val ) -{ - int i; - uchar_t table[] = "0123456789abcdef"; - uchar_t *byte_ptr = (uchar_t *)&val; - for( i = 0; i < sizeof(uint64_t); i++ ) { - out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ]; - out[i*2+1] = table[ (*byte_ptr) & 0x0f ]; - byte_ptr++; - } - out[i*2] = '\0'; -} - -#else /* little endian */ - -static void int64_to_hex_string( char *out, uint64_t val ) -{ - - - printk("int64_to_hex_string needs a little-endian implementation.\n"); -} -#endif /* _MIPSEB */ - -/* Convert a standard ASCII serial number to a unique integer - * id number by treating the serial number string as though - * it were a base 36 number - */ -uint64_t generate_unique_id( char *sn, int sn_len ) -{ - int uid = 0; - int i; - - #define VALID_BASE36(c) ((c >= '0' && c <='9') \ - || (c >= 'A' && c <='Z') \ - || (c >= 'a' && c <='z')) - - for( i = 0; i < sn_len; i++ ) { - if( !VALID_BASE36(sn[i]) ) - continue; - uid *= 36; - uid += char_to_base36( sn[i] ); - } - - if( uid == 0 ) - return rtc_time(); - - return uid; -} - -uchar_t char_to_base36( char c ) -{ - uchar_t val; - - if( c >= '0' && c <= '9' ) - val = (c - '0'); - - else if( c >= 'A' && c <= 'Z' ) - val = (c - 'A' + 10); - - else if( c >= 'a' && c <= 'z' ) - val = (c - 'a' + 10); - - else val = 0; - - return val; -} - - -/* given a pointer to the three-byte little-endian EEPROM representation - * of date-of-manufacture, this function translates to a big-endian - * integer format - */ -int eeprom_xlate_board_mfr_date( uchar_t *src ) -{ - int rval = 0; - rval += *src; src++; - rval += ((int)(*src) << 8); src ++; - rval += ((int)(*src) << 16); - return rval; -} - - -int eeprom_str( char *nic_str, nasid_t nasid, int component ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - if( (component & C_DIMM) == C_DIMM ) { - /* this function isn't applicable to DIMMs */ - return EEP_PARAM; - } - else { - eep.board_ia = &board; - eep.spd = NULL; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - } - - switch( component & BRICK_MASK ) { - case C_BRICK: - r = cbrick_eeprom_read( &eep, nasid, component ); - break; - case IO_BRICK: - r = iobrick_eeprom_read( &eep, nasid, component ); - break; - default: - return EEP_PARAM; /* must be an invalid component */ - } - if( r ) - return r; - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - -int vector_eeprom_str( char *nic_str, nasid_t nasid, - int component, net_vec_t path ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - - if( !(component & VECTOR) ) - return EEP_PARAM; - - if( (r = vector_eeprom_read( &eep, nasid, path, component )) ) - return r; - - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - - -int is_iobrick( int nasid, int widget_num ) -{ - uint32_t wid_reg; - int part_num, mfg_num; - - /* Read the widget's WIDGET_ID register to get - * its part number and mfg number - */ - wid_reg = *(volatile int32_t *) - (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID); - - part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; - mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT; - - /* Is this the "xbow part" of an XBridge? If so, this - * widget is definitely part of an I/O brick. - */ - if( part_num == XXBOW_WIDGET_PART_NUM && - mfg_num == XXBOW_WIDGET_MFGR_NUM ) - - return 1; - - /* Is this a "bridge part" of an XBridge? If so, once - * again, we know this widget is part of an I/O brick. - */ - if( part_num == XBRIDGE_WIDGET_PART_NUM && - mfg_num == XBRIDGE_WIDGET_MFGR_NUM ) - - return 1; - - return 0; -} - - -int cbrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 ) - { - /* We successfully read IP27LOG_OVNIC, so return it as the UID. */ - db_printf(( "cbrick_uid_get:" - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - *uid = strtoull( uid_str, NULL, 0 ); - return EEP_OK; - } -#endif - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one. - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = ≻ - sc_init( &sc, nasid, BRL1_LOCALHUB_UART ); - } - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( scp, subch, msg, msg, &len ) ) { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* free up subchannel */ - sc_close(scp, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - return( EEP_L1 ); - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -} - - -int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ) -{ - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - -#define FAIL \ - { \ - *uid = rtc_time(); \ - printk( "rbrick_uid_get failed; using current time as uid\n" ); \ - return EEP_OK; \ - } - - ROUTER_LOCK(path); - sc_init( &sc, nasid, path ); - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) { - ROUTER_UNLOCK(path); - FAIL; - } - - if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* send the request to the L1 */ - if( sc_command( &sc, subch, msg, msg, &len ) ) { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* free up subchannel */ - ROUTER_UNLOCK(path); - sc_close(&sc, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - FAIL; - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -} - -int iobrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( r != EEP_OK ) { - *uid = rtc_time(); - return r; - } - - *uid = generate_unique_id( board.serial_num, - board.serial_num_tl & FIELD_LENGTH_MASK ); - - return EEP_OK; -} - - -int ibrick_mac_addr_get( nasid_t nasid, char *eaddr ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - char *tmp; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) { - db_printf(( "ibrick_mac_addr_get: " - "Couldn't read MAC address from EEPROM\n" )); - return EEP_L1; - } - else { - /* successfully read info area */ - int ix; - tmp = board.mac_addr; - for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ ) - { - *eaddr++ = *tmp++; - } - *eaddr = '\0'; - } - - return EEP_OK; -} - - -/* - * eeprom_vertex_info_set - * - * Given a vertex handle, a component designation, a starting nasid - * and (in the case of a router) a vector path to the component, this - * function will read the EEPROM and attach the resulting information - * to the vertex in the same string format as that provided by the - * Dallas Semiconductor NIC drivers. If the vertex already has the - * string, this function just returns the string. - */ - -extern char *nic_vertex_info_get( devfs_handle_t ); -extern void nic_vmc_check( devfs_handle_t, char * ); -/* the following were lifted from nic.c - change later? */ -#define MAX_INFO 2048 -#define NEWSZ(ptr,sz) ((ptr) = kern_malloc((sz))) -#define DEL(ptr) (kern_free((ptr))) - -char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, - net_vec_t path ) -{ - char *info_tmp; - int info_len; - char *info; - - /* see if this vertex is already marked */ - info_tmp = nic_vertex_info_get(v); - if (info_tmp) return info_tmp; - - /* get a temporary place for the data */ - NEWSZ(info_tmp, MAX_INFO); - if (!info_tmp) return NULL; - - /* read the EEPROM */ - if( component & R_BRICK ) { - if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK ) - return NULL; - } - else { - if( eeprom_str( info_tmp, nasid, component ) != EEP_OK ) - return NULL; - } - - /* allocate a smaller final place */ - info_len = strlen(info_tmp)+1; - NEWSZ(info, info_len); - if (info) { - strcpy(info, info_tmp); - DEL(info_tmp); - } else { - info = info_tmp; - } - - /* add info to the vertex */ - hwgraph_info_add_LBL(v, INFO_LBL_NIC, - (arbitrary_info_t) info); - - /* see if someone else got there first */ - info_tmp = nic_vertex_info_get(v); - if (info != info_tmp) { - DEL(info); - return info_tmp; - } - - /* export the data */ - hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len); - - /* trigger all matching callbacks */ - nic_vmc_check(v, info); - - return info; -} - - -/********************************************************************* - * - * stubs for use until the Bedrock/L1 link is available - * - */ - -#include - -/* #define EEPROM_TEST */ - -/* fake eeprom reading functions (replace when the BR/L1 communication - * channel is in working order) - */ - - -/* generate a charater in [0-9A-Z]; if an "extra" character is - * specified (such as '_'), include it as one of the possibilities. - */ -char random_eeprom_ch( char extra ) -{ - char ch; - int modval = 36; - if( extra ) - modval++; - - ch = rtc_time() % modval; - - if( ch < 10 ) - ch += '0'; - else if( ch >= 10 && ch < 36 ) - ch += ('A' - 10); - else - ch = extra; - - return ch; -} - -/* create a part number of the form xxx-xxxx-xxx. - * It may be important later to generate different - * part numbers depending on the component we're - * supposed to be "reading" from, so the component - * paramter is provided. - */ -void fake_a_part_number( char *buf, int component ) -{ - int i; - switch( component ) { - - /* insert component-specific routines here */ - - case C_BRICK: - strcpy( buf, "030-1266-001" ); - break; - default: - for( i = 0; i < 12; i++ ) { - if( i == 3 || i == 8 ) - buf[i] = '-'; - else - buf[i] = random_eeprom_ch(0); - } - } -} - - -/* create a six-character serial number */ -void fake_a_serial_number( char *buf, uint64_t ser ) -{ - int i; - static const char hexchars[] = "0123456789ABCDEF"; - - if (ser) { - for( i = 5; i >=0; i-- ) { - buf[i] = hexchars[ser & 0xf]; - ser >>= 4; - } - } - else { - for( i = 0; i < 6; i++ ) - buf[i] = random_eeprom_ch(0); - } -} - - -void fake_a_product_name( uchar_t *format, char* buf, int component ) -{ - switch( component & BRICK_MASK ) { - - case C_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "C_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "IP35" ); - *format = 0xC4; - } - break; - - case R_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "R_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "R_BRICK" ); - *format = 0xC7; - } - break; - - case IO_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "IO_BRICK_SUB" ); - *format = 0xCC; - } - else { - strcpy( buf, "IO_BRICK" ); - *format = 0xC8; - } - break; - - default: - strcpy( buf, "UNK_DEVICE" ); - *format = 0xCA; - } -} - - - -int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, - uint64_t ser ) -{ - eeprom_board_ia_t *board; - eeprom_chassis_ia_t *chassis; - int i, cs; - - board = buf->board_ia; - chassis = buf->chassis_ia; - - if( !(component & SUBORD_MASK) ) { - if( !chassis ) - return EEP_PARAM; - chassis->format = 0; - chassis->length = 5; - chassis->type = 0x17; - - chassis->part_num_tl = 0xCC; - fake_a_part_number( chassis->part_num, component ); - chassis->serial_num_tl = 0xC6; - fake_a_serial_number( chassis->serial_num, ser ); - - cs = chassis->format + chassis->length + chassis->type - + chassis->part_num_tl + chassis->serial_num_tl; - for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->part_num[i]; - for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->serial_num[i]; - chassis->checksum = 256 - (cs % 256); - } - - if( !board ) - return EEP_PARAM; - board->format = 0; - board->length = 10; - board->language = 0; - board->mfg_date = 1789200; /* noon, 5/26/99 */ - board->manuf_tl = 0xC3; - strcpy( board->manuf, "SGI" ); - - fake_a_product_name( &(board->product_tl), board->product, component ); - - board->serial_num_tl = 0xC6; - fake_a_serial_number( board->serial_num, ser ); - - board->part_num_tl = 0xCC; - fake_a_part_number( board->part_num, component ); - - board->board_rev_tl = 0xC2; - board->board_rev[0] = '0'; - board->board_rev[1] = '1'; - - board->eeprom_size_tl = 0x01; - board->eeprom_size = 1; - - board->temp_waiver_tl = 0xC2; - board->temp_waiver[0] = '0'; - board->temp_waiver[1] = '1'; - - cs = board->format + board->length + board->language - + (board->mfg_date & 0xFF) - + (board->mfg_date & 0xFF00) - + (board->mfg_date & 0xFF0000) - + board->manuf_tl + board->product_tl + board->serial_num_tl - + board->part_num_tl + board->board_rev_tl - + board->board_rev[0] + board->board_rev[1] - + board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl - + board->temp_waiver[0] + board->temp_waiver[1]; - for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->manuf[i]; - for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->product[i]; - for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->serial_num[i]; - for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->part_num[i]; - - board->checksum = 256 - (cs % 256); - - return EEP_OK; -} - -#define EEPROM_CHUNKSIZE 64 - -#if defined(EEPROM_DEBUG) -#define RETURN_ERROR \ -{ \ - printk( "read_ia error return, component 0x%x, line %d" \ - ", address 0x%x, ia code 0x%x\n", \ - l1_compt, __LINE__, sc->subch[subch].target, ia_code ); \ - return EEP_L1; \ -} - -#else -#define RETURN_ERROR return(EEP_L1) -#endif - -int read_ia( l1sc_t *sc, int subch, int l1_compt, - int ia_code, char *eep_record ) -{ - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */ - int offset = 0; /* current offset into info area */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( ia_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, ia_code, - L1_ARG_INT, offset, - L1_ARG_INT, ia_len )) < 0 ) - { - RETURN_ERROR; - } - - /* send the request to the L1 */ - - if( sc_command( sc, subch, msg, msg, &len ) ) { - RETURN_ERROR; - } - - /* check response */ - if( sc_interpret_resp( msg, 5, - L1_ARG_INT, &ia_len, - L1_ARG_UNKNOWN, &len, eep_record ) < 0 ) - { - RETURN_ERROR; - } - - if( ia_len > EEPROM_CHUNKSIZE ) - ia_len = EEPROM_CHUNKSIZE; - - eep_record += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - - return EEP_OK; -} - - -int read_spd( l1sc_t *sc, int subch, int l1_compt, - eeprom_spd_u *spd ) -{ - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int resp; /* l1 response code */ - int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */ - int offset = 0; /* current offset into spd record */ - char *spd_p = spd->bytes; /* "thumb" for writing to spd */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( spd_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, L1_EEP_SPD, - L1_ARG_INT, offset, - L1_ARG_INT, spd_len )) < 0 ) - { - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - return( EEP_L1 ); - } - - /* check response */ - if( (resp = sc_interpret_resp( msg, 5, - L1_ARG_INT, &spd_len, - L1_ARG_UNKNOWN, &len, spd_p )) < 0 ) - { - /* - * translate l1 response code to eeprom.c error codes: - * The L1 response will be L1_RESP_NAVAIL if the spd - * can't be read (i.e. the spd isn't physically there). It will - * return L1_RESP_INVAL if the spd exists, but fails the checksum - * test because the eeprom wasn't programmed, programmed incorrectly, - * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present, - * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is - * invalid. - */ - if(resp == L1_RESP_INVAL) { - resp = EEP_BAD_CHECKSUM; - } else { - resp = EEP_L1; - } - return( resp ); - } - - if( spd_len > EEPROM_CHUNKSIZE ) - spd_len = EEPROM_CHUNKSIZE; - - spd_p += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - return EEP_OK; -} - - -int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_chassis_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* use to verify eeprom record checksum */ - int i; - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record ) - != EEP_OK ) - { - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->type = *eep_rec_p++; - - ia->part_num_tl = *eep_rec_p++; - - (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->serial_num, - (ia->serial_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->checksum = eep_record[(8 * ia->length) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_chassis_ia: bad checksum\n" )); - db_printf(( "read_chassis_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int read_board_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_board_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* running checksum total */ - int i; - - BZERO( ia, sizeof( eeprom_board_ia_t ) ); - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record ) - != EEP_OK ) - { - db_printf(( "read_board_ia: error reading info area from L1\n" )); - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_board_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->language = *eep_rec_p++; - - ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p ); - eep_rec_p += 3; - - ia->manuf_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK); - - ia->product_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK)); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->part_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - eep_rec_p++; /* we do not use the FRU file id */ - - ia->board_rev_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK); - - ia->eeprom_size_tl = *eep_rec_p++; - ia->eeprom_size = *eep_rec_p++; - - ia->temp_waiver_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->temp_waiver, - (ia->temp_waiver_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK); - - /* if there's more, we must be reading a main board; get - * additional fields - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->ekey_G_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_G, - ia->ekey_G_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK); - - ia->ekey_P_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_P, - ia->ekey_P_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK); - - ia->ekey_Y_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_Y, - ia->ekey_Y_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK); - - /* - * need to get a couple more fields if this is an I brick - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->mac_addr_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->mac_addr, - ia->mac_addr_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK); - - ia->ieee1394_cfg_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->ieee1394_cfg, - ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK ); - - } - } - - ia->checksum = eep_record[(ia->length * 8) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_board_ia: bad checksum\n" )); - db_printf(( "read_board_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp, - int component ) -{ - int r; - uint64_t uid = 0; -#ifdef LOG_GETENV - char uid_str[32]; -#endif - int l1_compt, subch; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting a cbrick */ - if( !(component & C_BRICK) ) - return EEP_PARAM; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 ) - { - db_printf(( "_cbrick_eeprom_read: " - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - uid = strtoull( uid_str, NULL, 0 ); - } -#endif - - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if((component & C_DIMM) == C_DIMM) { - l1_compt = L1_EEP_DIMM(component & COMPT_MASK); - r = read_spd(scp,subch,l1_compt, buf->spd); - sc_close(scp,subch); - return(r); - } - - switch( component ) - { - case C_BRICK: - /* c-brick motherboard */ - l1_compt = L1_EEP_NODE; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( scp, subch ); - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - if( uid ) { - /* If IP27LOG_OVNIC is set, we want to put that value - * in as our UID. */ - fake_a_serial_number( buf->chassis_ia->serial_num, uid ); - buf->chassis_ia->serial_num_tl = 6; - } - break; - - case C_PIMM: - /* one of the PIMM boards */ - l1_compt = L1_EEP_PIMM( component & COMPT_MASK ); - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) - { - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; -} - - -int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - return _cbrick_eeprom_read( buf, scp, component ); -} - - -int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ - int r; - int l1_compt, subch; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're talking to an applicable brick */ - if( !(component & IO_BRICK) ) { - return EEP_PARAM; - } - - /* If we're talking to this c-brick's attached io brick, use - * the local l1sc_t; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 ) - return EEP_L1; - - - switch( component ) - { - case IO_BRICK: - /* IO brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - - if( r != EEP_OK ) { - sc_close( scp, subch ); - /* - * Whenever we no longer need to test on hardware - * that does not have EEPROMS, then this can be removed. - */ - r = fake_an_eeprom_record( buf, component, rtc_time() ); - return r; - } - break; - - case IO_POWER: - /* IO brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) { - return r; - } - return EEP_OK; -} - - -int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - net_vec_t path, int component ) -{ - int r; - uint64_t uid = 0; - int l1_compt, subch; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting an applicable brick */ - if( !(component & VECTOR) ) - return EEP_PARAM; - - switch( component & BRICK_MASK ) - { - case R_BRICK: - ROUTER_LOCK( path ); - sc_init( &sc, nasid, path ); - - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) - { - db_printf(( "vector_eeprom_read: couldn't open subch\n" )); - ROUTER_UNLOCK(path); - return EEP_L1; - } - switch( component ) - { - case R_BRICK: - /* r-brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - printk( "vector_eeprom_read: couldn't get rbrick eeprom info;" - " using current time as uid\n" ); - uid = rtc_time(); - db_printf(("vector_eeprom_read: using a fake eeprom record\n")); - return fake_an_eeprom_record( buf, component, uid ); - } - break; - - case R_POWER: - /* r-brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - return EEP_PARAM; - } - r = read_board_ia( &sc, subch, l1_compt, buf->board_ia ); - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - if( r != EEP_OK ) { - db_printf(( "vector_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; - - case C_BRICK: - sc_init( &sc, nasid, path ); - return _cbrick_eeprom_read( buf, &sc, component ); - - default: - /* unsupported brick type */ - return EEP_PARAM; - } -} diff -Nur linux-2.4.19/arch/ia64/sn/io/efi-rtc.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/efi-rtc.c --- linux-2.4.19/arch/ia64/sn/io/efi-rtc.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/efi-rtc.c Wed Dec 31 16:00:00 1969 @@ -1,185 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 Silicon Graphics, Inc. - * Copyright (C) 2001 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * No locking necessary when this is called from efirtc which protects us - * from racing by efi_rtc_lock. - */ -#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3)) -#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr)) -#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data)) - -#define TOD_SGS_M48T35 1 -#define TOD_DALLAS_DS1386 2 - -static unsigned long nvram_base = 0; -static int tod_chip_type; - -static int -get_tod_chip_type(void) -{ - unsigned char testval; - - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - write_io_port(RTC_DAL_DAY_ADDR, 0xff); - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - - testval = read_io_port(RTC_DAL_DAY_ADDR); - if (testval == 0xff) - return TOD_SGS_M48T35; - - return TOD_DALLAS_DS1386; -} - -efi_status_t -ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps) -{ - if (!nvram_base) { - printk(KERN_CRIT "nvram_base is zero\n"); - return EFI_UNSUPPORTED; - } - - memset(time, 0, sizeof(*time)); - - switch (tod_chip_type) { - case TOD_SGS_M48T35: - write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT); - - time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF; - time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR)); - time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR)); - time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR)); - time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR)); - time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR)); - time->nanosecond = 0; - - write_io_port(RTC_SGS_CONTROL_ADDR, 0); - break; - - case TOD_DALLAS_DS1386: - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - - time->nanosecond = 0; - time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR)); - time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR)); - time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR)); - time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR)); - time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR)); - time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF; - - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - break; - - default: - break; - } - - if (caps) { - caps->resolution = 50000000; /* 50PPM */ - caps->accuracy = 1000; /* 1ms */ - caps->sets_to_zero = 0; - } - - return EFI_SUCCESS; -} - -static efi_status_t ioc3_set_time (efi_time_t *t) -{ - if (!nvram_base) { - printk(KERN_CRIT "nvram_base is zero\n"); - return EFI_UNSUPPORTED; - } - - switch (tod_chip_type) { - case TOD_SGS_M48T35: - write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE); - write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); - write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month)); - write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day)); - write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour)); - write_io_port(RTC_SGS_MIN_ADDR, INT_TO_BCD(t->minute)); - write_io_port(RTC_SGS_SEC_ADDR, INT_TO_BCD(t->second)); - write_io_port(RTC_SGS_CONTROL_ADDR, 0); - break; - - case TOD_DALLAS_DS1386: - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - write_io_port(RTC_DAL_SEC_ADDR, INT_TO_BCD(t->second)); - write_io_port(RTC_DAL_MIN_ADDR, INT_TO_BCD(t->minute)); - write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour)); - write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day)); - write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month)); - write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - break; - - default: - break; - } - - return EFI_SUCCESS; -} - -/* The following two are not supported atm. */ -static efi_status_t -ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) -{ - return EFI_UNSUPPORTED; -} - -static efi_status_t -ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) -{ - return EFI_UNSUPPORTED; -} - -/* - * It looks like the master IOC3 is usually on bus 0, device 4. Hope - * that's right - */ -static __init int efi_ioc3_time_init(void) -{ - struct pci_dev *dev; - static struct ioc3 *ioc3; - - dev = pci_find_slot(0, PCI_DEVFN(4, 0)); - if (!dev) { - printk(KERN_CRIT "Couldn't find master IOC3\n"); - - return -ENODEV; - } - - ioc3 = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); - nvram_base = (unsigned long) ioc3 + IOC3_BYTEBUS_DEV0; - - tod_chip_type = get_tod_chip_type(); - if (tod_chip_type == 1) - printk(KERN_NOTICE "TOD type is SGS M48T35\n"); - else if (tod_chip_type == 2) - printk(KERN_NOTICE "TOD type is Dallas DS1386\n"); - else - printk(KERN_CRIT "No or unknown TOD\n"); - - efi.get_time = ioc3_get_time; - efi.set_time = ioc3_set_time; - efi.get_wakeup_time = ioc3_get_wakeup_time; - efi.set_wakeup_time = ioc3_set_wakeup_time; - - return 0; -} - -module_init(efi_ioc3_time_init); diff -Nur linux-2.4.19/arch/ia64/sn/io/hcl.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/hcl.c --- linux-2.4.19/arch/ia64/sn/io/hcl.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/hcl.c Tue Jan 14 09:11:02 2003 @@ -6,7 +6,7 @@ * * hcl - SGI's Hardware Graph compatibility layer. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -141,6 +141,8 @@ extern void string_table_init(struct string_table *); extern struct string_table label_string_table; extern int init_ifconfig_net(void); + extern int init_ioconfig_bus(void); + int status = 0; int rv = 0; #if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) @@ -155,10 +157,12 @@ /* * Create the hwgraph_root on devfs. */ - rv = hwgraph_path_add(NULL, "hw", &hwgraph_root); + rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root); if (rv) printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); + status = devfs_set_flags (hwgraph_root, DEVFS_FL_HIDE); + /* * Create the hcl driver to support inventory entry manipulations. * By default, it is expected that devfs is mounted on /dev. @@ -183,9 +187,9 @@ /* * Create the directory that links Linux bus numbers to our Xwidget. */ - rv = hwgraph_path_add(hwgraph_root, "linux/busnum", &linux_busnum); + rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum); if (linux_busnum == NULL) { - panic("HCL: Unable to create hw/linux/busnum\n"); + panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS); return(0); } @@ -194,6 +198,8 @@ * Persistent Naming. */ init_ifconfig_net(); + + init_ioconfig_bus(); return(0); diff -Nur linux-2.4.19/arch/ia64/sn/io/hcl_util.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/hcl_util.c --- linux-2.4.19/arch/ia64/sn/io/hcl_util.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/hcl_util.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -93,6 +93,33 @@ } vhdl = master; + } +} + +static devfs_handle_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE; +extern int maxcpus; + +void +mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid) +{ + if (cpuid == CPU_NONE) + return; + + (void)labelcl_info_add_LBL(vhdl, INFO_LBL_CPUID, INFO_DESC_EXPORT, + (arbitrary_info_t)cpuid); + { + char cpuid_buffer[10]; + + if (hwgraph_all_cpuids == GRAPH_VERTEX_NONE) { + (void)hwgraph_path_add( hwgraph_root, + EDGE_LBL_CPUNUM, + &hwgraph_all_cpuids); + } + + sprintf(cpuid_buffer, "%ld", cpuid); + (void)hwgraph_edge_add( hwgraph_all_cpuids, + vhdl, + cpuid_buffer); } } diff -Nur linux-2.4.19/arch/ia64/sn/io/hubdev.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/hubdev.c --- linux-2.4.19/arch/ia64/sn/io/hubdev.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/hubdev.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/arch/ia64/sn/io/hubspc.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/hubspc.c --- linux-2.4.19/arch/ia64/sn/io/hubspc.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/hubspc.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* @@ -161,69 +161,8 @@ sizeof(invent_miscinfo_t)); } -#define FPROM_CONFIG_ADDR MD_JUNK_BUS_TIMING -#define FPROM_ENABLE_MASK MJT_FPROM_ENABLE_MASK -#define FPROM_ENABLE_SHFT MJT_FPROM_ENABLE_SHFT -#define FPROM_SETUP_MASK MJT_FPROM_SETUP_MASK -#define FPROM_SETUP_SHFT MJT_FPROM_SETUP_SHFT +#endif /* CONFIG_IA64_SGI_SN1 */ -/*ARGSUSED*/ -int -cpuprom_map(devfs_handle_t dev, vhandl_t *vt, off_t addr, size_t len) -{ - int errcode = 0; - caddr_t kvaddr; - devfs_handle_t node; - cnodeid_t cnode; - - node = prominfo_nodeget(dev); - - if (!node) - return EIO; - - - kvaddr = hubdev_prombase_get(node); - cnode = hubdev_cnodeid_get(node); -#ifdef HUBSPC_DEBUG - printk("cpuprom_map: hubnode %d kvaddr 0x%x\n", node, kvaddr); -#endif - - if (len > RBOOT_SIZE) - len = RBOOT_SIZE; - /* - * Map in the prom space - */ - errcode = v_mapphys(vt, kvaddr, len); - - if (errcode == 0 ){ - /* - * Set the MD configuration registers suitably. - */ - nasid_t nasid; - uint64_t value; - volatile hubreg_t *regaddr; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - regaddr = REMOTE_HUB_ADDR(nasid, FPROM_CONFIG_ADDR); - value = HUB_L(regaddr); - value &= ~(FPROM_SETUP_MASK | FPROM_ENABLE_MASK); - { - value |= (((long)CONFIG_FPROM_SETUP << FPROM_SETUP_SHFT) | - ((long)CONFIG_FPROM_ENABLE << FPROM_ENABLE_SHFT)); - } - HUB_S(regaddr, value); - - } - return (errcode); -} -#endif /* CONFIG_IA64_SGI_SN1 */ - -/*ARGSUSED*/ -int -cpuprom_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} /***********************************************************************/ /* Base Hub Space Driver */ @@ -245,13 +184,14 @@ hubdev_register(mem_refcnt_attach); #endif +#ifdef CONFIG_IA64_SGI_SN1 /* L1 system controller link */ if ( !IS_RUNNING_ON_SIMULATOR() ) { /* initialize the L1 link */ extern void l1_init(void); l1_init(); } - +#endif /* CONFIG_IA64_SGI_SN1 */ #ifdef HUBSPC_DEBUG printk("hubspc_init: Completed\n"); #endif /* HUBSPC_DEBUG */ @@ -283,7 +223,7 @@ /* check validity of request */ if( len == 0 ) { - return ENXIO; + return -ENXIO; } return errcode; diff -Nur linux-2.4.19/arch/ia64/sn/io/ifconfig_bus.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/ifconfig_bus.c --- linux-2.4.19/arch/ia64/sn/io/ifconfig_bus.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/ifconfig_bus.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,361 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ifconfig_bus - SGI's Persistent PCI Bus Numbering. + * + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SGI_IFCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING" +#define SGI_IFCONFIG_BUS_VERSION "1.0" + +/* + * Some Global definitions. + */ +devfs_handle_t ioconfig_bus_handle = NULL; +unsigned long ioconfig_bus_debug = 0; + +#define IFCONFIG_BUS_DEBUG 1 +#ifdef IFCONFIG_BUS_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +u64 ioconfig_file = 0; +u64 ioconfig_file_size = 0; + + +/* + * PCI Bus Name for PCI + * hw/module/001c01/slab/0/Ibrick/xtalk/15/pci + * + * PCI Bus Name for PCI-X + * hw/module/001c01/slab/0/Pbrick/xtalk/15/pci-x/0 - PCI bus 0 on Widget 14 + * hw/module/001c01/slab/0/Pbrick/xtalk/15/pci-x/1 - PCI bus 1 on Widget 14 + */ + +/* + * For debugging purpose .. hardcode a table .. + */ +struct ascii_moduleid debug_table[32]; + +struct ascii_moduleid *ioconfig_bus_table = debug_table; +u64 ioconfig_bus_table_size = 0; + + +int free_entry = 0; +int new_entry = 0; + +int next_basebus_number = 0; + +void +ioconfig_get_busnum(char *io_moduleid, int *bus_num) +{ + struct ascii_moduleid *temp; + int index; + +#ifdef DEBUG + printk("ioconfig_get_busnum io_moduleid %s\n", io_moduleid); +#endif + + *bus_num = -1; + temp = ioconfig_bus_table; + for (index = 0; index < free_entry; temp++, index++) { + if ( (io_moduleid[0] == temp->io_moduleid[0]) && + (io_moduleid[1] == temp->io_moduleid[1]) && + (io_moduleid[2] == temp->io_moduleid[2]) && + (io_moduleid[4] == temp->io_moduleid[4]) && + (io_moduleid[5] == temp->io_moduleid[5]) ) { + *bus_num = index * 10; + return; + } + } + + /* + * New IO Brick encountered. + */ + if (((int)io_moduleid[0]) == 0) { +#ifdef DEBUG + printk("ioconfig_get_busnum: Invalid Module Id given %s\n", io_moduleid); +#endif + return; + } + + strcpy((char *)&(debug_table[free_entry].io_moduleid), io_moduleid); + *bus_num = free_entry * 10; + free_entry++; +} + +void +dump_ioconfig_table() +{ + + int index = 0; + struct ascii_moduleid *temp; + + temp = ioconfig_bus_table; + while (index < free_entry) { + printk("ASSCI Module ID %s\n", temp->io_moduleid); + temp++; + index++; + } + +} + +#if 0 + +/* + * nextline + * This routine returns the nextline in the buffer. + */ +int nextline(char *buffer, char **next, char *line) +{ + + char *temp; + + if (buffer[0] == 0x0) { + return(0); + } + + temp = buffer; + while (*temp != 0) { + *line = *temp; + if (*temp != '\n'){ + *line = *temp; + temp++; line++; + } else + break; + } + + if (*temp == 0) + *next = temp; + else + *next = ++temp; + + return(1); +} + +/* + * build_pcibus_name + * This routine parses the ioconfig contents read into + * memory by ioconfig command in EFI and builds the + * persistent pci bus naming table. + */ +void +build_pcibus_name(char *file_contents, struct pcipath_to_busnum *table) +{ + /* + * Read the whole file into memory. + */ + int busnum; + int rc; + char *name; + char *temp; + char *next; + char *current; + char *line; + struct pcipath_to_busnum *pcibus; + + line = kmalloc(256, GFP_KERNEL); + memset(line, 0,256); + name = kmalloc(125, GFP_KERNEL); + memset(name, 0, 125); + pcibus = table; + current = file_contents; + while (nextline(current, &next, line)){ + + printk("current 0x%lx next 0x%lx\n", current, next); + + temp = line; + /* + * Skip all leading Blank lines .. + */ + while (isspace(*temp)) + if (*temp != '\n') + temp++; + else + break; + + if (*temp == '\n') { + current = next; + memset(line, 0, 256); + continue; + } + + /* + * Skip comment lines + */ + if (*temp == '#') { + current = next; + memset(line, 0, 256); + continue; + } + + /* + * Get the next free entry in the table. + */ + rc = sscanf(temp, "%d %s", &busnum, name); + pcibus->num = busnum; + pcibus->len = strlen(name); + strcpy(&pcibus->path[0], name); + DBG("pci number = %d pci path = %s\n", pcibus->num, pcibus->path); + if (busnum > highest_pcibus_num) + highest_pcibus_num = busnum; + else + highest_pcibus_num = busnum; + + pcibus_names_index++; + pcibus++; + current = next; + memset(line, 0, 256); + } + + DBG("highest_pcibus_num %d pcibus_names_index %d\n", highest_pcibus_num, pcibus_names_index); + + current_index = pcibus_names_index; + kfree(line); + kfree(name); + + return; +} + +void +ioconfig_bus_init(void) +{ + + struct ia64_sal_retval ret_stuff; + + DBG("ioconfig_bus_init called.\n"); + + /* + * Make SAL call to get the address of the bus configuration table. + */ + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, get_nasid(), 0, 0, 0, 0, 0); + if (ret_stuff.status != 0) { + DBG("ifconfig_bus_init: No Address given\n"); + } + + ioconfig_file = ret_stuff.v0; + ioconfig_file_size = ret_stuff.v1; + DBG("ioconfig_bus_init: ioconfig_file %p %d\n", + (void *)ioconfig_file, (int)ioconfig_file_size); + + /* + * Convert the address to a Cache Address. + */ + ioconfig_file = (CACHEABLE_MEM_SPACE | + (ioconfig_file & TO_PHYS_MASK)); + + ioconfig_bus_table = kmalloc( 512*sizeof(struct pcipath_to_busnum), + GFP_KERNEL ); + + DBG("ioconfig_bus_init: Kernel virtual ioconfig_file %p ioconfig_bus_table %p\n", + (void *)ioconfig_file, (void *)ioconfig_bus_table); + + (void) build_pcibus_name((char *)ioconfig_file, ioconfig_bus_table); + + (void) dump_ioconfig_table(ioconfig_bus_table); + +} + +#endif + +static int ioconfig_bus_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + + struct ioconfig_parm parm; + + /* + * Copy in the parameters. + */ + copy_from_user(&parm, arg, sizeof(struct ioconfig_parm)); + parm.number = free_entry - new_entry; + copy_to_user((char *)arg, &parm, sizeof(struct ioconfig_parm)); + copy_to_user((char *)parm.buffer, &debug_table[new_entry], sizeof(struct ascii_moduleid) * (free_entry - new_entry)); + + return 0; +} + +/* + * ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus". + */ +static int ioconfig_bus_open(struct inode * inode, struct file * filp) +{ + if (ioconfig_bus_debug) { + printk("ioconfig_bus_open called.\n"); + } + + return(0); + +} + +/* + * ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus". + */ +static int ioconfig_bus_close(struct inode * inode, struct file * filp) +{ + + if (ioconfig_bus_debug) { + printk("ioconfig_bus_close called.\n"); + } + + return(0); +} + +struct file_operations ioconfig_bus_fops = { + ioctl:ioconfig_bus_ioctl, + open:ioconfig_bus_open, /* open */ + release:ioconfig_bus_close /* release */ +}; + + +/* + * init_ifconfig_bus() - Boot time initialization. Ensure that it is called + * after devfs has been initialized. + * + */ +int init_ioconfig_bus(void) +{ + ioconfig_bus_handle = NULL; + ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus", + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &ioconfig_bus_fops, NULL); + + if (ioconfig_bus_handle == NULL) { + panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n"); + } + + return(0); + +} diff -Nur linux-2.4.19/arch/ia64/sn/io/ifconfig_net.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/ifconfig_net.c --- linux-2.4.19/arch/ia64/sn/io/ifconfig_net.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/ifconfig_net.c Mon Dec 30 14:16:56 2002 @@ -6,7 +6,7 @@ * * ifconfig_net - SGI's Persistent Network Device names. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/arch/ia64/sn/io/invent.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/invent.c --- linux-2.4.19/arch/ia64/sn/io/invent.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/invent.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* diff -Nur linux-2.4.19/arch/ia64/sn/io/io.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/io.c --- linux-2.4.19/arch/ia64/sn/io/io.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/io.c Mon Dec 30 14:16:56 2002 @@ -4,9 +4,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ +#include #include #include #include @@ -31,21 +32,6 @@ extern void hub_intr_init(devfs_handle_t hubv); -/* - * hub_device_desc_update - * Update the passed in device descriptor with the actual the - * target cpu number and interrupt priority level. - * NOTE : These might be the same as the ones passed in thru - * the descriptor. - */ -void -hub_device_desc_update(device_desc_t dev_desc, - ilvl_t intr_swlevel, - cpuid_t cpu) -{ -} - - /* * Perform any initializations needed to support hub-based I/O. * Called once during startup. @@ -53,11 +39,6 @@ void hubio_init(void) { -#ifdef LATER - /* This isn't needed unless we port the entire sio driver ... */ - extern void early_brl1_port_init( void ); - early_brl1_port_init(); -#endif } /* @@ -149,6 +130,10 @@ nasid_t nasid; volatile hubreg_t junk; unsigned long s; + caddr_t kvaddr; +#ifdef PIOMAP_UNC_ACC_SPACE + uint64_t addr; +#endif /* sanity check */ if (byte_count_max > byte_count) @@ -159,8 +144,19 @@ /* If xtalk_addr range is mapped by a small window, we don't have * to do much */ - if (xtalk_addr + byte_count <= SWIN_SIZE) - return(hubinfo_swin_piomap_get(hubinfo, (int)widget)); + if (xtalk_addr + byte_count <= SWIN_SIZE) { + hub_piomap_t piomap; + + piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget); +#ifdef PIOMAP_UNC_ACC_SPACE + if (flags & PIOMAP_UNC_ACC) { + addr = (uint64_t)piomap->hpio_xtalk_info.xp_kvaddr; + addr |= PIOMAP_UNC_ACC_SPACE; + piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)addr; + } +#endif + return piomap; + } /* We need to use a big window mapping. */ @@ -257,7 +253,15 @@ bw_piomap->hpio_xtalk_info.xp_dev = dev; bw_piomap->hpio_xtalk_info.xp_target = widget; bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr; - bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index); + kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index); +#ifdef PIOMAP_UNC_ACC_SPACE + if (flags & PIOMAP_UNC_ACC) { + addr = (uint64_t)kvaddr; + addr |= PIOMAP_UNC_ACC_SPACE; + kvaddr = (caddr_t)addr; + } +#endif + bw_piomap->hpio_xtalk_info.xp_kvaddr = kvaddr; bw_piomap->hpio_holdcnt++; bw_piomap->hpio_bigwin_num = free_bw_index; @@ -378,12 +382,22 @@ devfs_handle_t hubv = xwidget_info_master_get(widget_info); hub_piomap_t hub_piomap; hubinfo_t hubinfo; + caddr_t addr; hubinfo_get(hubv, &hubinfo); if (xtalk_addr + byte_count <= SWIN_SIZE) { hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget); - return(hub_piomap_addr(hub_piomap, xtalk_addr, byte_count)); + addr = hub_piomap_addr(hub_piomap, xtalk_addr, byte_count); +#ifdef PIOMAP_UNC_ACC_SPACE + if (flags & PIOMAP_UNC_ACC) { + uint64_t iaddr; + iaddr = (uint64_t)addr; + iaddr |= PIOMAP_UNC_ACC_SPACE; + addr = (caddr_t)iaddr; + } +#endif + return(addr); } else return(0); } @@ -392,19 +406,6 @@ /* DMA MANAGEMENT */ /* Mapping from crosstalk space to system physical space */ -/* - * There's not really very much to do here, since crosstalk maps - * directly to system physical space. It's quite possible that this - * DMA layer will be bypassed in performance kernels. - */ - - -/* ARGSUSED */ -void -hub_dma_init(devfs_handle_t hubv) -{ -} - /* * Allocate resources needed to set up DMA mappings up to a specified size @@ -478,7 +479,12 @@ } /* There isn't actually any DMA mapping hardware on the hub. */ - return(paddr); +#ifdef CONFIG_IA64_SGI_SN2 + return( (PHYS_TO_DMA(paddr)) ); +#else + /* no translation needed */ + return(paddr); +#endif } /* @@ -549,8 +555,12 @@ size_t byte_count, /* length */ unsigned flags) /* defined in dma.h */ { +#ifdef CONFIG_IA64_SGI_SN2 + return( (PHYS_TO_DMA(paddr)) ); +#else /* no translation needed */ return(paddr); +#endif } /* @@ -565,6 +575,7 @@ alenlist_t palenlist, /* system address/length list */ unsigned flags) /* defined in dma.h */ { + BUG(); /* no translation needed */ return(palenlist); } @@ -603,11 +614,9 @@ void hub_provider_startup(devfs_handle_t hubv) { - extern void hub_dma_init(devfs_handle_t hubv); extern void hub_pio_init(devfs_handle_t hubv); hub_pio_init(hubv); - hub_dma_init(hubv); hub_intr_init(hubv); } @@ -707,14 +716,12 @@ { iprb_t prb; int prb_offset; -#ifdef LATER extern int force_fire_and_forget; extern volatile int ignore_conveyor_override; if (force_fire_and_forget && !ignore_conveyor_override) if (conveyor == HUB_PIO_CONVEYOR) conveyor = HUB_PIO_FIRE_N_FORGET; -#endif /* * Get the current register value. diff -Nur linux-2.4.19/arch/ia64/sn/io/ioconfig_bus.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/ioconfig_bus.c --- linux-2.4.19/arch/ia64/sn/io/ioconfig_bus.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/ioconfig_bus.c Thu Jan 9 19:31:11 2003 @@ -0,0 +1,402 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ioconfig_bus - SGI's Persistent PCI Bus Numbering. + * + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SGI_IOCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING" +#define SGI_IOCONFIG_BUS_VERSION "1.0" + +/* + * Some Global definitions. + */ +devfs_handle_t ioconfig_bus_handle = NULL; +unsigned long ioconfig_bus_debug = 0; + +#ifdef IOCONFIG_BUS_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +u64 ioconfig_file = 0; +u64 ioconfig_file_size = 0; +u64 ioconfig_activated = 0; +char ioconfig_kernopts[128]; + +/* + * For debugging purpose .. hardcode a table .. + */ +struct ascii_moduleid *ioconfig_bus_table; +u64 ioconfig_bus_table_size = 0; + + +int free_entry = 0; +int new_entry = 0; + +int next_basebus_number = 0; + +void +ioconfig_get_busnum(char *io_moduleid, int *bus_num) +{ + struct ascii_moduleid *temp; + int index; + + DBG("ioconfig_get_busnum io_moduleid %s\n", io_moduleid); + + *bus_num = -1; + temp = ioconfig_bus_table; + for (index = 0; index < free_entry; temp++, index++) { + if ( (io_moduleid[0] == temp->io_moduleid[0]) && + (io_moduleid[1] == temp->io_moduleid[1]) && + (io_moduleid[2] == temp->io_moduleid[2]) && + (io_moduleid[4] == temp->io_moduleid[4]) && + (io_moduleid[5] == temp->io_moduleid[5]) ) { + *bus_num = index * 0x10; + return; + } + } + + /* + * New IO Brick encountered. + */ + if (((int)io_moduleid[0]) == 0) { + DBG("ioconfig_get_busnum: Invalid Module Id given %s\n", io_moduleid); + return; + } + + io_moduleid[3] = '#'; + strcpy((char *)&(ioconfig_bus_table[free_entry].io_moduleid), io_moduleid); + *bus_num = free_entry * 0x10; + free_entry++; +} + +void +dump_ioconfig_table() +{ + + int index = 0; + struct ascii_moduleid *temp; + + temp = ioconfig_bus_table; + while (index < free_entry) { + DBG("ASSCI Module ID %s\n", temp->io_moduleid); + temp++; + index++; + } +} + +/* + * nextline + * This routine returns the nextline in the buffer. + */ +int nextline(char *buffer, char **next, char *line) +{ + + char *temp; + + if (buffer[0] == 0x0) { + return(0); + } + + temp = buffer; + while (*temp != 0) { + *line = *temp; + if (*temp != '\n'){ + *line = *temp; + temp++; line++; + } else + break; + } + + if (*temp == 0) + *next = temp; + else + *next = ++temp; + + return(1); +} + +/* + * build_pcibus_name + * This routine parses the ioconfig contents read into + * memory by ioconfig command in EFI and builds the + * persistent pci bus naming table. + */ +void +build_moduleid_table(char *file_contents, struct ascii_moduleid *table) +{ + /* + * Read the whole file into memory. + */ + int rc; + char *name; + char *temp; + char *next; + char *current; + char *line; + struct ascii_moduleid *moduleid; + + line = kmalloc(256, GFP_KERNEL); + memset(line, 0,256); + name = kmalloc(125, GFP_KERNEL); + memset(name, 0, 125); + moduleid = table; + current = file_contents; + while (nextline(current, &next, line)){ + + DBG("current 0x%lx next 0x%lx\n", current, next); + + temp = line; + /* + * Skip all leading Blank lines .. + */ + while (isspace(*temp)) + if (*temp != '\n') + temp++; + else + break; + + if (*temp == '\n') { + current = next; + memset(line, 0, 256); + continue; + } + + /* + * Skip comment lines + */ + if (*temp == '#') { + current = next; + memset(line, 0, 256); + continue; + } + + /* + * Get the next free entry in the table. + */ + rc = sscanf(temp, "%s", name); + strcpy(&moduleid->io_moduleid[0], name); + DBG("Found %s\n", name); + moduleid++; + free_entry++; + current = next; + memset(line, 0, 256); + } + + new_entry = free_entry; + kfree(line); + kfree(name); + + return; +} + +void +ioconfig_bus_init(void) +{ + + struct ia64_sal_retval ret_stuff; + u64 *temp; + int cnode; + + DBG("ioconfig_bus_init called.\n"); + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid_t nasid; + /* + * Make SAL call to get the address of the bus configuration table. + */ + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + nasid = COMPACT_TO_NASID_NODEID(cnode); + SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, nasid, 0, 0, 0, 0, 0); + temp = (u64 *)TO_NODE_CAC(nasid, ret_stuff.v0); + ioconfig_file = *temp; + DBG("ioconfig_bus_init: Nasid %d ret_stuff.v0 0x%lx\n", nasid, + ret_stuff.v0); + if (ioconfig_file) { + ioconfig_file_size = ret_stuff.v1; + ioconfig_file = (ioconfig_file | CACHEABLE_MEM_SPACE); + ioconfig_activated = 1; + break; + } + } + + DBG("ioconfig_bus_init: ret_stuff.v0 %p ioconfig_file %p %d\n", + ret_stuff.v0, (void *)ioconfig_file, (int)ioconfig_file_size); + + ioconfig_bus_table = kmalloc( 512, GFP_KERNEL ); + memset(ioconfig_bus_table, 0, 512); + + /* + * If ioconfig options are given on the bootline .. take it. + */ + if (*ioconfig_kernopts != '\0') { + /* + * ioconfig="..." kernel options given. + */ + DBG("ioconfig_bus_init: Kernel Options given.\n"); + (void) build_moduleid_table((char *)ioconfig_kernopts, ioconfig_bus_table); + (void) dump_ioconfig_table(ioconfig_bus_table); + return; + } + + if (ioconfig_activated) { + DBG("ioconfig_bus_init: ioconfig file given.\n"); + (void) build_moduleid_table((char *)ioconfig_file, ioconfig_bus_table); + (void) dump_ioconfig_table(ioconfig_bus_table); + } else { + DBG("ioconfig_bus_init: ioconfig command not executed in prom\n"); + } + +} + +void +ioconfig_bus_new_entries(void) +{ + + + int index = 0; + struct ascii_moduleid *temp; + + if ((ioconfig_activated) && (free_entry > new_entry)) { + printk("### Please add the following new IO Bricks Module ID \n"); + printk("### to your Persistent Bus Numbering Config File\n"); + } else + return; + + index = new_entry; + temp = &ioconfig_bus_table[index]; + while (index < free_entry) { + printk("%s\n", temp); + temp++; + index++; + } + printk("### End\n"); + +} +static int ioconfig_bus_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + + struct ioconfig_parm parm; + + /* + * Copy in the parameters. + */ + copy_from_user(&parm, (char *)arg, sizeof(struct ioconfig_parm)); + parm.number = free_entry - new_entry; + parm.ioconfig_activated = ioconfig_activated; + copy_to_user((char *)arg, &parm, sizeof(struct ioconfig_parm)); + copy_to_user((char *)parm.buffer, &ioconfig_bus_table[new_entry], sizeof(struct ascii_moduleid) * (free_entry - new_entry)); + + return 0; +} + +/* + * ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus". + */ +static int ioconfig_bus_open(struct inode * inode, struct file * filp) +{ + if (ioconfig_bus_debug) { + DBG("ioconfig_bus_open called.\n"); + } + + return(0); + +} + +/* + * ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus". + */ +static int ioconfig_bus_close(struct inode * inode, struct file * filp) +{ + + if (ioconfig_bus_debug) { + DBG("ioconfig_bus_close called.\n"); + } + + return(0); +} + +struct file_operations ioconfig_bus_fops = { + ioctl:ioconfig_bus_ioctl, + open:ioconfig_bus_open, /* open */ + release:ioconfig_bus_close /* release */ +}; + + +/* + * init_ifconfig_bus() - Boot time initialization. Ensure that it is called + * after devfs has been initialized. + * + */ +int init_ioconfig_bus(void) +{ + ioconfig_bus_handle = NULL; + ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus", + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &ioconfig_bus_fops, NULL); + + if (ioconfig_bus_handle == NULL) { + panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n"); + } + + return(0); + +} + +static int __init ioconfig_bus_setup (char *str) +{ + + char *temp; + + DBG("ioconfig_bus_setup: Kernel Options %s\n", str); + + temp = (char *)ioconfig_kernopts; + memset(temp, 0, 128); + while ( (*str != '\0') && !isspace (*str) ) { + if (*str == ',') { + *temp = '\n'; + temp++; + str++; + continue; + } + *temp = *str; + temp++; + str++; + } + + return(0); + +} +__setup("ioconfig=", ioconfig_bus_setup); diff -Nur linux-2.4.19/arch/ia64/sn/io/klconflib.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/klconflib.c --- linux-2.4.19/arch/ia64/sn/io/klconflib.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/klconflib.c Wed Dec 31 16:00:00 1969 @@ -1,1046 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define printf printk -int hasmetarouter; - -#define LDEBUG 0 -#define NIC_UNKNOWN ((nic_t) -1) - -#undef DEBUG_KLGRAPH -#ifdef DEBUG_KLGRAPH -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_KLGRAPH */ - -static void sort_nic_names(lboard_t *) ; - -u64 klgraph_addr[MAX_COMPACT_NODES]; -int module_number = 0; - -lboard_t * -find_lboard(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (start->brd_type == brd_type) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_class(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -klinfo_t * -find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) -{ - int index, j; - - if (kli == (klinfo_t *)NULL) { - index = 0; - } else { - for (j = 0; j < KLCF_NUM_COMPS(brd); j++) { - if (kli == KLCF_COMP(brd, j)) - break; - } - index = j; - if (index == KLCF_NUM_COMPS(brd)) { - DBG("find_component: Bad pointer: 0x%p\n", kli); - return (klinfo_t *)NULL; - } - index++; /* next component */ - } - - for (; index < KLCF_NUM_COMPS(brd); index++) { - kli = KLCF_COMP(brd, index); - DBG("find_component: brd %p kli %p request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli)); - if (KLCF_COMP_TYPE(kli) == struct_type) - return kli; - } - - /* Didn't find it. */ - return (klinfo_t *)NULL; -} - -klinfo_t * -find_first_component(lboard_t *brd, unsigned char struct_type) -{ - return find_component(brd, (klinfo_t *)NULL, struct_type); -} - -lboard_t * -find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot) -{ - /* Search all boards stored on this node. */ - while (start) { - if (MODULE_MATCH(start->brd_module, mod) && - (start->brd_slot == slot)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_module(lboard_t *start, moduleid_t mod) -{ - /* Search all boards stored on this node. */ - while (start) { - if (MODULE_MATCH(start->brd_module, mod)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_module_class(lboard_t *start, moduleid_t mod, - unsigned char brd_type) -{ - while (start) { - - DBG("find_lboard_module_class: lboard 0x%p, start->brd_module 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_module, mod, start->brd_type, brd_type); - - if (MODULE_MATCH(start->brd_module, mod) && - (KLCLASS(start->brd_type) == KLCLASS(brd_type))) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - - -/* - * Convert a NIC name to a name for use in the hardware graph. - */ -void -nic_name_convert(char *old_name, char *new_name) -{ - int i; - char c; - char *compare_ptr; - - if ((old_name[0] == '\0') || (old_name[1] == '\0')) { - strcpy(new_name, EDGE_LBL_XWIDGET); - } else { - for (i = 0; i < strlen(old_name); i++) { - c = old_name[i]; - - if (isalpha(c)) - new_name[i] = tolower(c); - else if (isdigit(c)) - new_name[i] = c; - else - new_name[i] = '_'; - } - new_name[i] = '\0'; - } - - /* XXX - - * Since a bunch of boards made it out with weird names like - * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and - * replace it with "baseio" to avoid confusion in the field. - * We also have to make sure we don't report media_io instead of - * baseio. - */ - - /* Skip underscores at the beginning of the name */ - for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++) - ; - - /* - * Check for some names we need to replace. Early boards - * had junk following the name so check only the first - * characters. - */ - if (!strncmp(new_name, "io6", 3) || - !strncmp(new_name, "mio", 3) || - !strncmp(new_name, "media_io", 8)) - strcpy(new_name, "baseio"); - else if (!strncmp(new_name, "divo", 4)) - strcpy(new_name, "divo") ; - -} - -/* Check if the given board corresponds to the global - * master io6 - */ -int -is_master_baseio(nasid_t nasid,moduleid_t module,slotid_t slot) -{ - lboard_t *board; - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -/* If this works then look for callers of is_master_baseio() - * (e.g. iograph.c) and let them pass in a slot if they want - */ - board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module); -#else - board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), module, slot); -#endif - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - board = find_lboard_module((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - module); -#else - board = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - module, slot); -#endif - } -#endif - if (!board) - return(0); - return(board->brd_flags & GLOBAL_MASTER_IO6); -} -/* - * Find the lboard structure and get the board name. - * If we can't find the structure or it's too low a revision, - * use default name. - */ -lboard_t * -get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name) -{ - lboard_t *brd; - - brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), - mod, slot); - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) - brd = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - mod, slot); - } -#endif - - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, name); - } - - /* - * PV # 540860 - * If the name is not 'baseio' - * get the lowest of all the names in the nic string. - * This is needed for boards like divo, which can have - * a bunch of daughter cards, but would like to be called - * divo. We could do this for baseio - * but it has some special case names that we would not - * like to disturb at this point. - */ - - /* gfx boards don't need any of this name scrambling */ - if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) { - return(brd); - } - - if (!(!strcmp(name, "baseio") )) { - if (brd) { - sort_nic_names(brd) ; - /* Convert to small case, '-' to '_' etc */ - nic_name_convert(brd->brd_name, name) ; - } - } - - return(brd); -} - -/* - * get_actual_nasid - * - * Completely disabled brds have their klconfig on - * some other nasid as they have no memory. But their - * actual nasid is hidden in the klconfig. Use this - * routine to get it. Works for normal boards too. - */ -nasid_t -get_actual_nasid(lboard_t *brd) -{ - klhub_t *hub ; - - if (!brd) - return INVALID_NASID ; - - /* find out if we are a completely disabled brd. */ - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - if (!hub) - return INVALID_NASID ; - if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ - return hub->hub_info.physid ; - else - return brd->brd_nasid ; -} - -int -xbow_port_io_enabled(nasid_t nasid, int link) -{ - lboard_t *brd; - klxbow_t *xbow_p; - - /* - * look for boards that might contain an xbow or xbridge - */ - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); - if (brd == NULL) return 0; - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return 0; - - if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) - return 0; - - DBG("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p); - - return 1; -} - -void -board_to_path(lboard_t *brd, char *path) -{ - moduleid_t modnum; - char *board_name; - - ASSERT(brd); - - switch (KLCLASS(brd->brd_type)) { - - case KLCLASS_NODE: - board_name = EDGE_LBL_NODE; - break; - case KLCLASS_ROUTER: - if (brd->brd_type == KLTYPE_META_ROUTER) { - board_name = EDGE_LBL_META_ROUTER; - hasmetarouter++; - } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { - board_name = EDGE_LBL_REPEATER_ROUTER; - hasmetarouter++; - } else - board_name = EDGE_LBL_ROUTER; - break; - case KLCLASS_MIDPLANE: - board_name = EDGE_LBL_MIDPLANE; - break; - case KLCLASS_IO: - board_name = EDGE_LBL_IO; - break; - case KLCLASS_IOBRICK: - if (brd->brd_type == KLTYPE_PBRICK) - board_name = EDGE_LBL_PBRICK; - else if (brd->brd_type == KLTYPE_IBRICK) - board_name = EDGE_LBL_IBRICK; - else if (brd->brd_type == KLTYPE_XBRICK) - board_name = EDGE_LBL_XBRICK; - else - board_name = EDGE_LBL_IOBRICK; - break; - default: - board_name = EDGE_LBL_UNKNOWN; - } - - modnum = brd->brd_module; - - /* ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); */ -if ((modnum == MODULE_UNKNOWN) || (modnum == INVALID_MODULE)) { - modnum = ++module_number; -} -#ifdef __ia64 - { - char buffer[16]; - memset(buffer, 0, 16); - format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); - sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name); - } -#else - sprintf(path, "%H/%s", modnum, board_name); -#endif -} - -/* - * Get the module number for a NASID. - */ -moduleid_t -get_module_id(nasid_t nasid) -{ - lboard_t *brd; - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - - if (!brd) - return INVALID_MODULE; - else - return brd->brd_module; -} - - -#define MHZ 1000000 - - -/* Get the canonical hardware graph name for the given pci component - * on the given io board. - */ -void -device_component_canonical_name_get(lboard_t *brd, - klinfo_t *component, - char *name) -{ - moduleid_t modnum; - slotid_t slot; - char board_name[20]; - - ASSERT(brd); - - /* Get the module number of this board */ - modnum = brd->brd_module; - - /* Convert the [ CLASS | TYPE ] kind of slotid - * into a string - */ - slot = brd->brd_slot; - ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); - - /* Get the io board name */ - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, board_name); - } - - /* Give out the canonical name of the pci device*/ - sprintf(name, - "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/" - EDGE_LBL_PCI"/%d", - modnum, board_name,KLCF_BRIDGE_W_ID(component)); -} - -/* - * Get the serial number of the main component of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - * Assumptions: Nic manufacturing string has the following format - * *Serial:;* - */ -static int -component_serial_number_get(lboard_t *board, - klconf_off_t mfg_nic_offset, - char *serial_number, - char *key_pattern) -{ - - char *mfg_nic_string; - char *serial_string,*str; - int i; - char *serial_pattern = "Serial:"; - - /* We have an error on a null mfg nic offset */ - if (!mfg_nic_offset) - return(1); - /* Get the hub's manufacturing nic information - * which is in the form of a pre-formatted string - */ - mfg_nic_string = - (char *)NODE_OFFSET_TO_K0(NASID_GET(board), - mfg_nic_offset); - /* There is no manufacturing nic info */ - if (!mfg_nic_string) - return(1); - - str = mfg_nic_string; - /* Look for the key pattern first (if it is specified) - * and then print the serial number corresponding to that. - */ - if (strcmp(key_pattern,"") && - !(str = strstr(mfg_nic_string,key_pattern))) - return(1); - - /* There is no serial number info in the manufacturing - * nic info - */ - if (!(serial_string = strstr(str,serial_pattern))) - return(1); - - serial_string = serial_string + strlen(serial_pattern); - /* Copy the serial number information from the klconfig */ - i = 0; - while (serial_string[i] != ';') { - serial_number[i] = serial_string[i]; - i++; - } - serial_number[i] = 0; - - return(0); -} -/* - * Get the serial number of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - */ - -int -board_serial_number_get(lboard_t *board,char *serial_number) -{ - ASSERT(board && serial_number); - if (!board || !serial_number) - return(1); - - strcpy(serial_number,""); - switch(KLCLASS(board->brd_type)) { - case KLCLASS_CPU: { /* Node board */ - klhub_t *hub; - - /* Get the hub component information */ - hub = (klhub_t *)find_first_component(board, - KLSTRUCT_HUB); - /* If we don't have a hub component on an IP27 - * then we have a weird klconfig. - */ - if (!hub) - return(1); - /* Get the serial number information from - * the hub's manufacturing nic info - */ - if (component_serial_number_get(board, - hub->hub_mfg_nic, - serial_number, -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - "IP37")) -#else - "IP27")) - /* Try with IP31 key if IP27 key fails */ - if (component_serial_number_get(board, - hub->hub_mfg_nic, - serial_number, - "IP31")) -#endif /* CONFIG_IA64_SGI_SN1 */ - return(1); - break; - } - case KLCLASS_IO: { /* IO board */ - if (KLTYPE(board->brd_type) == KLTYPE_TPU) { - /* Special case for TPU boards */ - kltpu_t *tpu; - - /* Get the tpu component information */ - tpu = (kltpu_t *)find_first_component(board, - KLSTRUCT_TPU); - /* If we don't have a tpu component on a tpu board - * then we have a weird klconfig. - */ - if (!tpu) - return(1); - /* Get the serial number information from - * the tpu's manufacturing nic info - */ - if (component_serial_number_get(board, - tpu->tpu_mfg_nic, - serial_number, - "")) - return(1); - break; - } else if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) || - (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) { - /* Special case for GSN boards */ - klgsn_t *gsn; - - /* Get the gsn component information */ - gsn = (klgsn_t *)find_first_component(board, - ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ? - KLSTRUCT_GSN_A : KLSTRUCT_GSN_B)); - /* If we don't have a gsn component on a gsn board - * then we have a weird klconfig. - */ - if (!gsn) - return(1); - /* Get the serial number information from - * the gsn's manufacturing nic info - */ - if (component_serial_number_get(board, - gsn->gsn_mfg_nic, - serial_number, - "")) - return(1); - break; - } else { - klbri_t *bridge; - - /* Get the bridge component information */ - bridge = (klbri_t *)find_first_component(board, - KLSTRUCT_BRI); - /* If we don't have a bridge component on an IO board - * then we have a weird klconfig. - */ - if (!bridge) - return(1); - /* Get the serial number information from - * the bridge's manufacturing nic info - */ - if (component_serial_number_get(board, - bridge->bri_mfg_nic, - serial_number, - "")) - return(1); - break; - } - } - case KLCLASS_ROUTER: { /* Router board */ - klrou_t *router; - - /* Get the router component information */ - router = (klrou_t *)find_first_component(board, - KLSTRUCT_ROU); - /* If we don't have a router component on a router board - * then we have a weird klconfig. - */ - if (!router) - return(1); - /* Get the serial number information from - * the router's manufacturing nic info - */ - if (component_serial_number_get(board, - router->rou_mfg_nic, - serial_number, - "")) - return(1); - break; - } - case KLCLASS_GFX: { /* Gfx board */ - klgfx_t *graphics; - - /* Get the graphics component information */ - graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX); - /* If we don't have a gfx component on a gfx board - * then we have a weird klconfig. - */ - if (!graphics) - return(1); - /* Get the serial number information from - * the graphics's manufacturing nic info - */ - if (component_serial_number_get(board, - graphics->gfx_mfg_nic, - serial_number, - "")) - return(1); - break; - } - default: - strcpy(serial_number,""); - break; - } - return(0); -} - -#include "asm/sn/sn_private.h" - -xwidgetnum_t -nodevertex_widgetnum_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - return(hubinfo_p->h_widgetid); -} - -devfs_handle_t -nodevertex_xbow_peer_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - nasid_t xbow_peer_nasid; - cnodeid_t xbow_peer; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer; - if(xbow_peer_nasid == INVALID_NASID) - return ( (devfs_handle_t)-1); - xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid); - return(NODEPDA(xbow_peer)->node_vertex); -} - -/* NIC Sorting Support */ - -#define MAX_NICS_PER_STRING 32 -#define MAX_NIC_NAME_LEN 32 - -static char * -get_nic_string(lboard_t *lb) -{ - int i; - klinfo_t *k = NULL ; - klconf_off_t mfg_off = 0 ; - char *mfg_nic = NULL ; - - for (i = 0; i < KLCF_NUM_COMPS(lb); i++) { - k = KLCF_COMP(lb, i) ; - switch(k->struct_type) { - case KLSTRUCT_BRI: - mfg_off = ((klbri_t *)k)->bri_mfg_nic ; - break ; - - case KLSTRUCT_HUB: - mfg_off = ((klhub_t *)k)->hub_mfg_nic ; - break ; - - case KLSTRUCT_ROU: - mfg_off = ((klrou_t *)k)->rou_mfg_nic ; - break ; - - case KLSTRUCT_GFX: - mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ; - break ; - - case KLSTRUCT_TPU: - mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ; - break ; - - case KLSTRUCT_GSN_A: - case KLSTRUCT_GSN_B: - mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ; - break ; - - case KLSTRUCT_XTHD: - mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ; - break; - - default: - mfg_off = 0 ; - break ; - } - if (mfg_off) - break ; - } - - if ((mfg_off) && (k)) - mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ; - - return mfg_nic ; -} - -char * -get_first_string(char **ptrs, int n) -{ - int i ; - char *tmpptr ; - - if ((ptrs == NULL) || (n == 0)) - return NULL ; - - tmpptr = ptrs[0] ; - - if (n == 1) - return tmpptr ; - - for (i = 0 ; i < n ; i++) { - if (strcmp(tmpptr, ptrs[i]) > 0) - tmpptr = ptrs[i] ; - } - - return tmpptr ; -} - -int -get_ptrs(char *idata, char **ptrs, int n, char *label) -{ - int i = 0 ; - char *tmp = idata ; - - if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0)) - return 0 ; - - while ( (tmp = strstr(tmp, label)) ){ - tmp += strlen(label) ; - /* check for empty name field, and last NULL ptr */ - if ((i < (n-1)) && (*tmp != ';')) { - ptrs[i++] = tmp ; - } - } - - ptrs[i] = NULL ; - - return i ; -} - -/* - * sort_nic_names - * - * Does not really do sorting. Find the alphabetically lowest - * name among all the nic names found in a nic string. - * - * Return: - * Nothing - * - * Side Effects: - * - * lb->brd_name gets the new name found - */ - -static void -sort_nic_names(lboard_t *lb) -{ - char *nic_str ; - char *ptrs[MAX_NICS_PER_STRING] ; - char name[MAX_NIC_NAME_LEN] ; - char *tmp, *tmp1 ; - - *name = 0 ; - - /* Get the nic pointer from the lb */ - - if ((nic_str = get_nic_string(lb)) == NULL) - return ; - - tmp = get_first_string(ptrs, - get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ; - - if (tmp == NULL) - return ; - - if ( (tmp1 = strchr(tmp, ';')) ){ - strncpy(name, tmp, tmp1-tmp) ; - name[tmp1-tmp] = 0 ; - } else { - strncpy(name, tmp, (sizeof(name) -1)) ; - name[sizeof(name)-1] = 0 ; - } - - strcpy(lb->brd_name, name) ; -} - - - -char brick_types[MAX_BRICK_TYPES + 1] = "crikxdp789012345"; - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - -/* - * Format a module id for printing. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - int rack, position; - char brickchar; - - rack = MODULE_GET_RACK(m); - ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); - brickchar = MODULE_GET_BTCHAR(m); - position = MODULE_GET_BPOS(m); - - if (fmt == MODULE_FORMAT_BRIEF) { - /* Brief module number format, eg. 002c15 */ - - /* Decompress the rack number */ - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - /* Add the brick type */ - *buffer++ = brickchar; - } - else if (fmt == MODULE_FORMAT_LONG) { - /* Fuller hwgraph format, eg. rack/002/bay/15 */ - - strcpy(buffer, EDGE_LBL_RACK "/"); buffer += strlen(buffer); - - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - strcpy(buffer, "/" EDGE_LBL_RPOS "/"); buffer += strlen(buffer); - } - - /* Add the bay position, using at least two digits */ - if (position < 10) - *buffer++ = '0'; - sprintf(buffer, "%d", position); - -} - -/* - * Parse a module id, in either brief or long form. - * Returns < 0 on error. - * The long form does not include a brick type, so it defaults to 0 (CBrick) - */ -int -parse_module_id(char *buffer) -{ - unsigned int v, rack, bay, type, form; - moduleid_t m; - char c; - - if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) { - form = MODULE_FORMAT_LONG; - buffer += strlen(EDGE_LBL_RACK "/"); - - /* A long module ID must be exactly 5 non-template chars. */ - if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5) - return -1; - } - else { - form = MODULE_FORMAT_BRIEF; - - /* A brief module id must be exactly 6 characters */ - if (strlen(buffer) != 6) - return -2; - } - - /* The rack number must be exactly 3 digits */ - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2]))) - return -3; - - rack = 0; - v = *buffer++ - '0'; - if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return -4; - RACK_ADD_CLASS(rack, v); - - v = *buffer++ - '0'; - if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return -5; - RACK_ADD_GROUP(rack, v); - - v = *buffer++ - '0'; - /* rack numbers are 1-based */ - if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return -6; - RACK_ADD_NUM(rack, v); - - if (form == MODULE_FORMAT_BRIEF) { - /* Next should be a module type character. Accept ucase or lcase. */ - c = *buffer++; - if (!isalpha(c)) - return -7; - - /* strchr() returns a pointer into brick_types[], or NULL */ - type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types); - if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT) - return -8; - } - else { - /* Hardcode the module type, and skip over the boilerplate */ - type = MODULE_CBRICK; - - if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer) - return -9; - - buffer += strlen("/" EDGE_LBL_RPOS "/"); - } - - /* The bay number is last. Make sure it's exactly two digits */ - - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2])) - return -10; - - bay = 10 * (buffer[0] - '0') + (buffer[1] - '0'); - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return -11; - - m = RBT_TO_MODULE(rack, bay, type); - - /* avoid sign extending the moduleid_t */ - return (int)(unsigned short)m; -} - -#else /* CONFIG_IA64_SGI_SN1 */ - -/* - * Format a module id for printing. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - if (fmt == MODULE_FORMAT_BRIEF) { - sprintf(buffer, "%d", m); - } - else if (fmt == MODULE_FORMAT_LONG) { - sprintf(buffer, EDGE_LBL_MODULE "/%d", m); - } -} - -/* - * Parse a module id, in either brief or long form. - * Returns < 0 on error. - */ -int -parse_module_id(char *buffer) -{ - moduleid_t m; - char c; - - if (strstr(buffer, EDGE_LBL_MODULE "/") == buffer) - buffer += strlen(EDGE_LBL_MODULE "/"); - - for (m = 0; *buffer; buffer++) { - c = *buffer; - if (!isdigit(c)) - return -1; - m = 10 * m + (c - '0'); - } - - /* avoid sign extending the moduleid_t */ - return (int)(unsigned short)m; -} - -#endif /* CONFIG_IA64_SGI_SN1 */ - - diff -Nur linux-2.4.19/arch/ia64/sn/io/klgraph.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/klgraph.c --- linux-2.4.19/arch/ia64/sn/io/klgraph.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/klgraph.c Wed Dec 31 16:00:00 1969 @@ -1,795 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * klgraph.c- - * This file specifies the interface between the kernel and the PROM's - * configuration data structures. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define KLGRAPH_DEBUG 1 */ -#ifdef KLGRAPH_DEBUG -#define GRPRINTF(x) printk x -#define CE_GRPANIC CE_PANIC -#else -#define GRPRINTF(x) -#define CE_GRPANIC CE_PANIC -#endif - -#include - -extern char arg_maxnodes[]; -extern u64 klgraph_addr[]; - -/* - * Support for verbose inventory via hardware graph. - * klhwg_invent_alloc allocates the necessary size of inventory information - * and fills in the generic information. - */ -invent_generic_t * -klhwg_invent_alloc(cnodeid_t cnode, int class, int size) -{ - invent_generic_t *invent; - - invent = kern_malloc(size); - if (!invent) return NULL; - - invent->ig_module = NODE_MODULEID(cnode); - invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode)); - invent->ig_invclass = class; - - return invent; -} - -/* - * Add information about the baseio prom version number - * as a part of detailed inventory info in the hwgraph. - */ -void -klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) -{ - invent_miscinfo_t *baseio_inventory; - unsigned char version = 0,revision = 0; - - /* Allocate memory for the "detailed inventory" info - * for the baseio - */ - baseio_inventory = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); - baseio_inventory->im_type = INV_IO6PROM; - /* Read the io6prom revision from the nvram */ -#ifdef LATER - nvram_prom_version_get(&version,&revision); -#endif - /* Store the revision info in the inventory */ - baseio_inventory->im_version = version; - baseio_inventory->im_rev = revision; - /* Put the inventory info in the hardware graph */ - hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) baseio_inventory); - /* Make the information available to the user programs - * thru hwgfs. - */ - hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -char *hub_rev[] = { - "0.0", - "1.0", - "2.0", - "2.1", - "2.2", - "2.3" -}; - -/* - * Add detailed cpu inventory info to the hardware graph. - */ -void -klhwg_hub_invent_info(devfs_handle_t hubv, - cnodeid_t cnode, - klhub_t *hub) -{ - invent_miscinfo_t *hub_invent; - - hub_invent = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t)); - if (!hub_invent) - return; - - if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub)) - hub_invent->im_gen.ig_flag = INVENT_ENABLED; - - hub_invent->im_type = INV_HUB; - hub_invent->im_rev = hub->hub_info.revision; - hub_invent->im_speed = hub->hub_speed; - hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) hub_invent); - hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -/* ARGSUSED */ -void -klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) -{ -#if defined(CONFIG_IA64_SGI_SN1) - devfs_handle_t myhubv; - devfs_handle_t hub_mon; - devfs_handle_t synergy; - devfs_handle_t fsb0; - devfs_handle_t fsb1; - int rc; - extern struct file_operations hub_mon_fops; - - GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB)); - - (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); - rc = device_master_set(myhubv, node_vertex); - - /* - * hub perf stats. - */ - rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO, - (arbitrary_info_t)(&NODEPDA(cnode)->hubstats)); - - if (rc != GRAPH_SUCCESS) { - printk(KERN_WARNING "klhwg_add_hub: Can't add hub info label 0x%p, code %d", - (void *)myhubv, rc); - } - - klhwg_hub_invent_info(myhubv, cnode, hub); - - hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &hub_mon_fops, - (void *)(long)cnode); - - init_hub_stats(cnode, NODEPDA(cnode)); - - /* - * synergy perf - */ - (void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy); - (void) hwgraph_path_add(synergy, "0", &fsb0); - (void) hwgraph_path_add(synergy, "1", &fsb1); - - fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0)); - - fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1)); -#endif /* CONFIG_IA64_SGI_SN1 */ -} - -void -klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) -{ - lboard_t *brd; - klxbow_t *xbow_p; - nasid_t hub_nasid; - cnodeid_t hub_cnode; - int widgetnum; - devfs_handle_t xbow_v, hubv; - /*REFERENCED*/ - graph_error_t err; - - if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL) - return; - - if (KL_CONFIG_DUPLICATE_BOARD(brd)) - return; - - GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n", - cnode, nasid)); - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return; - -#ifdef LATER - /* - * We cannot support this function in devfs .. see below where - * we use hwgraph_path_add() to create this vertex with a known - * name. - */ - err = hwgraph_vertex_create(&xbow_v); - ASSERT(err == GRAPH_SUCCESS); - - xswitch_vertex_init(xbow_v); -#endif /* LATER */ - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) - continue; - - hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); - if (hub_nasid == INVALID_NASID) { - printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum); - continue; - } - - hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid); - - if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) { - continue; - } - - hubv = cnodeid_to_vertex(hub_cnode); - - err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); - if (err != GRAPH_SUCCESS) { - if (err == GRAPH_DUP) - printk(KERN_WARNING "klhwg_add_xbow: Check for " - "working routers and router links!"); - - PRINT_PANIC("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p to vertex 0x%p," - "error %d\n", - (void *)hubv, (void *)xbow_v, err); - } - xswitch_vertex_init(xbow_v); - - NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; - - /* - * XXX - This won't work is we ever hook up two hubs - * by crosstown through a crossbow. - */ - if (hub_nasid != nasid) { - NODEPDA(hub_cnode)->xbow_peer = nasid; - NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer = - hub_nasid; - } - - GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n", - hub_nasid, EDGE_LBL_XTALK, hubv)); - -#ifdef LATER - err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK); - if (err != GRAPH_SUCCESS) { - if (err == GRAPH_DUP) - printk(KERN_WARNING "klhwg_add_xbow: Check for " - "working routers and router links!"); - - PRINT_PANIC("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), " - "error %d\n", - hubv, hubv, xbow_v, xbow_v, err); - } -#endif - } -} - - -/* ARGSUSED */ -void -klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) -{ - nasid_t nasid; - lboard_t *brd; - klhub_t *hub; - devfs_handle_t node_vertex = NULL; - char path_buffer[100]; - int rv; - char *s; - int board_disabled = 0; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n", - cnode, nasid, brd)); - ASSERT(brd); - - do { - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n", - path_buffer, hwgraph_root)); - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - - if (rv != GRAPH_SUCCESS) - PRINT_PANIC("Node vertex creation failed. " - "Path == %s", - path_buffer); - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - if(hub->hub_info.flags & KLINFO_ENABLE) - board_disabled = 0; - else - board_disabled = 1; - - if(!board_disabled) { - mark_nodevertex_as_node(node_vertex, - cnode + board_disabled * numnodes); - - s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); - NODEPDA(cnode)->hwg_node_name = - kmalloc(strlen(s) + 1, - GFP_KERNEL); - ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL); - strcpy(NODEPDA(cnode)->hwg_node_name, s); - - hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo); - - /* Set up node board's slot */ - NODEPDA(cnode)->slotdesc = brd->brd_slot; - - /* Set up the module we're in */ - NODEPDA(cnode)->module_id = brd->brd_module; - NODEPDA(cnode)->module = module_lookup(brd->brd_module); - } - - if(!board_disabled) - klhwg_add_hub(node_vertex, hub, cnode); - - brd = KLCF_NEXT(brd); - if (brd) - brd = find_lboard(brd, KLTYPE_SNIA); - else - break; - } while(brd); -} - - -/* ARGSUSED */ -void -klhwg_add_all_routers(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - devfs_handle_t node_vertex; - char path_buffer[100]; - int rv; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n", - cnode)); - - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - /* No routers stored in this node's memory */ - continue; - - do { - ASSERT(brd); - GRPRINTF(("Router board struct is %p\n", brd)); - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) - continue; - - GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module)); - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("Router path is %s\n", path_buffer)); - - /* Add the router */ - GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n", - path_buffer, hwgraph_root)); - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - - if (rv != GRAPH_SUCCESS) - PRINT_PANIC("Router vertex creation " - "failed. Path == %s", - path_buffer); - - GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n", - brd)); - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), - KLTYPE_ROUTER)) ); - - GRPRINTF(("klhwg_add_all_routers: Done.\n")); - } - -} - -/* ARGSUSED */ -void -klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, - cnodeid_t cnode, nasid_t nasid) -{ - klrou_t *router; - char path_buffer[50]; - char dest_path[50]; - devfs_handle_t router_hndl; - devfs_handle_t dest_hndl; - int rc; - int port; - lboard_t *dest_brd; - - GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n", - cnode)); - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) { - GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n", - brd, cnode)); - return; - } - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl); - - if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes)) - return; - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find router: %s", path_buffer); - - /* We don't know what to do with multiple router components */ - if (brd->brd_numcompts != 1) { - PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n", - brd->brd_numcompts); - return; - } - - - /* Convert component 0 to klrou_t ptr */ - router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), - brd->brd_compts[0]); - - for (port = 1; port <= MAX_ROUTER_PORTS; port++) { - /* See if the port's active */ - if (router->rou_port[port].port_nasid == INVALID_NASID) { - GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n", - port)); - continue; - } - if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) - == INVALID_CNODEID) { - continue; - } - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - router->rou_port[port].port_nasid, - router->rou_port[port].port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - PRINT_PANIC("Can't find router: %s", dest_path); - } - GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n", - path_buffer, port, dest_path)); - - sprintf(dest_path, "%d", port); - - rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path); - - if (rc == GRAPH_DUP) { - GRPRINTF(("Skipping port %d. nasid %d %s/%s\n", - port, router->rou_port[port].port_nasid, - path_buffer, dest_path)); - continue; - } - - if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) - PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - - } -} - - -void -klhwg_connect_routers(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n", - cnode)); - - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - continue; - - do { - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - klhwg_connect_one_router(hwgraph_root, brd, - cnode, nasid); - - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); - } -} - - - -void -klhwg_connect_hubs(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - klhub_t *hub; - lboard_t *dest_brd; - devfs_handle_t hub_hndl; - devfs_handle_t dest_hndl; - char path_buffer[50]; - char dest_path[50]; - graph_error_t rc; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n", - cnode)); - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(brd); - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - - /* See if the port's active */ - if (hub->hub_port.port_nasid == INVALID_NASID) { - GRPRINTF(("klhwg_connect_hubs: port inactive.\n")); - continue; - } - - if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID) - continue; - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer)); - rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find hub: %s", path_buffer); - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - hub->hub_port.port_nasid, - hub->hub_port.port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - PRINT_PANIC("Can't find board: %s", dest_path); - } else { - - - GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n", - path_buffer, dest_path)); - - rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT); - - if (rc != GRAPH_SUCCESS) - PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - - } - } -} - -/* Store the pci/vme disabled board information as extended administrative - * hints which can later be used by the drivers using the device/driver - * admin interface. - */ -void -klhwg_device_disable_hints_add(void) -{ - cnodeid_t cnode; /* node we are looking at */ - nasid_t nasid; /* nasid of the node */ - lboard_t *board; /* board we are looking at */ - int comp_index; /* component index */ - klinfo_t *component; /* component in the board we are - * looking at - */ - char device_name[MAXDEVNAME]; - -#ifdef LATER - device_admin_table_init(); -#endif - for(cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - board = (lboard_t *)KL_CONFIG_INFO(nasid); - /* Check out all the board info stored on a node */ - while(board) { - /* No need to look at duplicate boards or non-io - * boards - */ - if (KL_CONFIG_DUPLICATE_BOARD(board) || - KLCLASS(board->brd_type) != KLCLASS_IO) { - board = KLCF_NEXT(board); - continue; - } - /* Check out all the components of a board */ - for (comp_index = 0; - comp_index < KLCF_NUM_COMPS(board); - comp_index++) { - component = KLCF_COMP(board,comp_index); - /* If the component is enabled move on to - * the next component - */ - if (KLCONFIG_INFO_ENABLED(component)) - continue; - /* NOTE : Since the prom only supports - * the disabling of pci devices the following - * piece of code makes sense. - * Make sure that this assumption is valid - */ - /* This component is disabled. Store this - * hint in the extended device admin table - */ - /* Get the canonical name of the pci device */ - device_component_canonical_name_get(board, - component, - device_name); -#ifdef LATER - device_admin_table_update(device_name, - ADMIN_LBL_DISABLED, - "yes"); -#endif -#ifdef DEBUG - printf("%s DISABLED\n",device_name); -#endif - } - /* go to the next board info stored on this - * node - */ - board = KLCF_NEXT(board); - } - } -} - -void -klhwg_add_all_modules(devfs_handle_t hwgraph_root) -{ - cmoduleid_t cm; - char name[128]; - devfs_handle_t vhdl; - int rc; - char buffer[16]; - - /* Add devices under each module */ - - for (cm = 0; cm < nummodules; cm++) { - /* Use module as module vertex fastinfo */ - -#ifdef __ia64 - memset(buffer, 0, 16); - format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); - sprintf(name, EDGE_LBL_MODULE "/%s", buffer); -#else - sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id); -#endif - - rc = hwgraph_path_add(hwgraph_root, name, &vhdl); - ASSERT(rc == GRAPH_SUCCESS); - rc = rc; - - hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]); - - /* Add system controller */ - -#ifdef __ia64 - sprintf(name, - EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, - buffer); -#else - sprintf(name, - EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1, - modules[cm]->id); -#endif - - rc = hwgraph_path_add(hwgraph_root, name, &vhdl); - ASSERT_ALWAYS(rc == GRAPH_SUCCESS); - rc = rc; - - hwgraph_info_add_LBL(vhdl, - INFO_LBL_ELSC, - (arbitrary_info_t) (__psint_t) 1); - -#ifdef LATER - sndrv_attach(vhdl); -#else - /* - * We need to call the drivers attach routine .. - */ - FIXME("klhwg_add_all_modules: Need code to call driver attach.\n"); -#endif - } -} - -void -klhwg_add_all_nodes(devfs_handle_t hwgraph_root) -{ - cnodeid_t cnode; - - for (cnode = 0; cnode < numnodes; cnode++) { - klhwg_add_node(hwgraph_root, cnode, NULL); - } - - for (cnode = 0; cnode < numnodes; cnode++) { - klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode)); - } - - /* - * As for router hardware inventory information, we set this - * up in router.c. - */ - - klhwg_add_all_routers(hwgraph_root); - klhwg_connect_routers(hwgraph_root); - klhwg_connect_hubs(hwgraph_root); - - /* Assign guardian nodes to each of the - * routers in the system. - */ - -#ifdef LATER - router_guardians_set(hwgraph_root); -#endif - - /* Go through the entire system's klconfig - * to figure out which pci components have been disabled - */ - klhwg_device_disable_hints_add(); - -} diff -Nur linux-2.4.19/arch/ia64/sn/io/klgraph_hack.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/klgraph_hack.c --- linux-2.4.19/arch/ia64/sn/io/klgraph_hack.c Fri Aug 2 17:39:42 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/klgraph_hack.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -13,13 +13,16 @@ * initial klgraph information that is normally provided by prom. */ +#include #include #include #include #include #include #include +#include +extern u64 klgraph_addr[]; void * real_port; void * real_io_base; void * real_addr; @@ -45,10 +48,15 @@ #define HUBREG ((char *)0xc0000a0001e00000) #define WIDGET0 ((char *)0xc0000a0000000000) +#define convert(a,b,c) temp = (u64 *)a; *temp = b; temp++; *temp = c + void klgraph_hack_init(void) { + u64 *temp; + +#ifdef CONFIG_IA64_SGI_SN1 /* * We need to know whether we are booting from PROM or * boot from disk. @@ -59,6 +67,139 @@ } else { panic("klgraph_hack_init: Unable to locate KLCONFIG TABLE\n"); } + + convert(0x0000000000030000, 0x00000000beedbabe, 0x0000004800000000); + +#else + + if (IS_RUNNING_ON_SIMULATOR()) { + printk("Creating FAKE Klconfig Structure for Embeded Kernel\n"); + klgraph_addr[0] = 0xe000003000030000; + + /* + * klconfig entries initialization - mankato + */ + convert(0xe000003000030000, 0x00000000beedbabe, 0x0000004800000000); + convert(0xe000003000030010, 0x0003007000000018, 0x800002000f820178); + convert(0xe000003000030020, 0x80000a000f024000, 0x800002000f800000); + convert(0xe000003000030030, 0x0300fafa00012580, 0x00000000040f0000); + convert(0xe000003000030040, 0x0000000000000000, 0x0003097000030070); + convert(0xe000003000030050, 0x00030970000303b0, 0x0003181000033f70); + convert(0xe000003000030060, 0x0003d51000037570, 0x0000000000038330); + convert(0xe000003000030070, 0x0203110100030140, 0x0001000000000101); + convert(0xe000003000030080, 0x0900000000000000, 0x000000004e465e67); + convert(0xe000003000030090, 0x0003097000000000, 0x00030b1000030a40); + convert(0xe0000030000300a0, 0x00030cb000030be0, 0x000315a0000314d0); + convert(0xe0000030000300b0, 0x0003174000031670, 0x0000000000000000); + convert(0xe000003000030100, 0x000000000000001a, 0x3350490000000000); + convert(0xe000003000030110, 0x0000000000000037, 0x0000000000000000); + convert(0xe000003000030140, 0x0002420100030210, 0x0001000000000101); + convert(0xe000003000030150, 0x0100000000000000, 0xffffffffffffffff); + convert(0xe000003000030160, 0x00030d8000000000, 0x0000000000030e50); + convert(0xe0000030000301c0, 0x0000000000000000, 0x0000000000030070); + convert(0xe0000030000301d0, 0x0000000000000025, 0x424f490000000000); + convert(0xe0000030000301e0, 0x000000004b434952, 0x0000000000000000); + convert(0xe000003000030210, 0x00027101000302e0, 0x00010000000e4101); + convert(0xe000003000030220, 0x0200000000000000, 0xffffffffffffffff); + convert(0xe000003000030230, 0x00030f2000000000, 0x0000000000030ff0); + convert(0xe000003000030290, 0x0000000000000000, 0x0000000000030140); + convert(0xe0000030000302a0, 0x0000000000000026, 0x7262490000000000); + convert(0xe0000030000302b0, 0x00000000006b6369, 0x0000000000000000); + convert(0xe0000030000302e0, 0x0002710100000000, 0x00010000000f3101); + convert(0xe0000030000302f0, 0x0500000000000000, 0xffffffffffffffff); + convert(0xe000003000030300, 0x000310c000000000, 0x0003126000031190); + convert(0xe000003000030310, 0x0003140000031330, 0x0000000000000000); + convert(0xe000003000030360, 0x0000000000000000, 0x0000000000030140); + convert(0xe000003000030370, 0x0000000000000029, 0x7262490000000000); + convert(0xe000003000030380, 0x00000000006b6369, 0x0000000000000000); + convert(0xe000003000030970, 0x0000000002010102, 0x0000000000000000); + convert(0xe000003000030980, 0x000000004e465e67, 0xffffffff00000000); + /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */ + convert(0xe0000030000309a0, 0x0000000000037570, 0xffffffff00000000); + convert(0xe0000030000309b0, 0x0000000000030070, 0x0000000000000000); + convert(0xe0000030000309c0, 0x000000000003f420, 0x0000000000000000); + convert(0xe000003000030a40, 0x0000000002010125, 0x0000000000000000); + convert(0xe000003000030a50, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000030a70, 0x0000000000037b78, 0x0000000000000000); + convert(0xe000003000030b10, 0x0000000002010125, 0x0000000000000000); + convert(0xe000003000030b20, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000030b40, 0x0000000000037d30, 0x0000000000000001); + convert(0xe000003000030be0, 0x00000000ff010203, 0x0000000000000000); + convert(0xe000003000030bf0, 0xffffffffffffffff, 0xffffffff000000ff); + convert(0xe000003000030c10, 0x0000000000037ee8, 0x0100010000000200); + convert(0xe000003000030cb0, 0x00000000ff310111, 0x0000000000000000); + convert(0xe000003000030cc0, 0xffffffffffffffff, 0x0000000000000000); + convert(0xe000003000030d80, 0x0000000002010104, 0x0000000000000000); + convert(0xe000003000030d90, 0xffffffffffffffff, 0x00000000000000ff); + convert(0xe000003000030db0, 0x0000000000037f18, 0x0000000000000000); + convert(0xe000003000030dc0, 0x0000000000000000, 0x0003007000060000); + convert(0xe000003000030de0, 0x0000000000000000, 0x0003021000050000); + convert(0xe000003000030df0, 0x000302e000050000, 0x0000000000000000); + convert(0xe000003000030e30, 0x0000000000000000, 0x000000000000000a); + convert(0xe000003000030e50, 0x00000000ff00011a, 0x0000000000000000); + convert(0xe000003000030e60, 0xffffffffffffffff, 0x0000000000000000); + convert(0xe000003000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e); + convert(0xe000003000030e90, 0x000000000000bc6e, 0x0000000000000000); + convert(0xe000003000030f20, 0x0000000002010205, 0x00000000d0020000); + convert(0xe000003000030f30, 0xffffffffffffffff, 0x0000000e0000000e); + convert(0xe000003000030f40, 0x000000000000000e, 0x0000000000000000); + convert(0xe000003000030f50, 0x0000000000038010, 0x00000000000007ff); + convert(0xe000003000030f70, 0x0000000000000000, 0x0000000022001077); + convert(0xe000003000030fa0, 0x0000000000000000, 0x000000000003f4a8); + convert(0xe000003000030ff0, 0x0000000000310120, 0x0000000000000000); + convert(0xe000003000031000, 0xffffffffffffffff, 0xffffffff00000002); + convert(0xe000003000031010, 0x000000000000000e, 0x0000000000000000); + convert(0xe000003000031020, 0x0000000000038088, 0x0000000000000000); + convert(0xe0000030000310c0, 0x0000000002010205, 0x00000000d0020000); + convert(0xe0000030000310d0, 0xffffffffffffffff, 0x0000000f0000000f); + convert(0xe0000030000310e0, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000310f0, 0x00000000000380b8, 0x00000000000007ff); + convert(0xe000003000031120, 0x0000000022001077, 0x00000000000310a9); + convert(0xe000003000031130, 0x00000000580211c1, 0x000000008009104c); + convert(0xe000003000031140, 0x0000000000000000, 0x000000000003f4c0); + convert(0xe000003000031190, 0x0000000000310120, 0x0000000000000000); + convert(0xe0000030000311a0, 0xffffffffffffffff, 0xffffffff00000003); + convert(0xe0000030000311b0, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000311c0, 0x0000000000038130, 0x0000000000000000); + convert(0xe000003000031260, 0x0000000000110106, 0x0000000000000000); + convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); + convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); + convert(0xe000003000031280, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000312a0, 0x00000000ff110013, 0x0000000000000000); + convert(0xe0000030000312b0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe0000030000312c0, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000312e0, 0x0000000000110012, 0x0000000000000000); + convert(0xe0000030000312f0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000031300, 0x000000000000000f, 0x0000000000000000); + convert(0xe000003000031310, 0x0000000000038160, 0x0000000000000000); + convert(0xe000003000031330, 0x00000000ff310122, 0x0000000000000000); + convert(0xe000003000031340, 0xffffffffffffffff, 0xffffffff00000005); + convert(0xe000003000031350, 0x000000000000000f, 0x0000000000000000); + convert(0xe000003000031360, 0x0000000000038190, 0x0000000000000000); + convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); + convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); + convert(0xe000003000031410, 0xffffffffffffffff, 0xffffffff00000006); + convert(0xe000003000031420, 0x000000000000000f, 0x0000000000000000); + convert(0xe000003000031430, 0x00000000000381c0, 0x0000000000000000); + convert(0xe0000030000314d0, 0x00000000ff010201, 0x0000000000000000); + convert(0xe0000030000314e0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000031500, 0x00000000000381f0, 0x000030430000ffff); + convert(0xe000003000031510, 0x000000000000ffff, 0x0000000000000000); + convert(0xe0000030000315a0, 0x00000020ff000201, 0x0000000000000000); + convert(0xe0000030000315b0, 0xffffffffffffffff, 0xffffffff00000001); + convert(0xe0000030000315d0, 0x0000000000038240, 0x00003f3f0000ffff); + convert(0xe0000030000315e0, 0x000000000000ffff, 0x0000000000000000); + convert(0xe000003000031670, 0x00000000ff010201, 0x0000000000000000); + convert(0xe000003000031680, 0xffffffffffffffff, 0x0000000100000002); + convert(0xe0000030000316a0, 0x0000000000038290, 0x000030430000ffff); + convert(0xe0000030000316b0, 0x000000000000ffff, 0x0000000000000000); + convert(0xe000003000031740, 0x00000020ff000201, 0x0000000000000000); + convert(0xe000003000031750, 0xffffffffffffffff, 0x0000000500000003); + convert(0xe000003000031770, 0x00000000000382e0, 0x00003f3f0000ffff); + convert(0xe000003000031780, 0x000000000000ffff, 0x0000000000000000); +} + +#endif } diff -Nur linux-2.4.19/arch/ia64/sn/io/l1.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/l1.c --- linux-2.4.19/arch/ia64/sn/io/l1.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/l1.c Wed Dec 31 16:00:00 1969 @@ -1,3143 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* In general, this file is organized in a hierarchy from lower-level - * to higher-level layers, as follows: - * - * UART routines - * Bedrock/L1 "PPP-like" protocol implementation - * System controller "message" interface (allows multiplexing - * of various kinds of requests and responses with - * console I/O) - * Console interface: - * "l1_cons", the glue that allows the L1 to act - * as the system console for the stdio libraries - * - * Routines making use of the system controller "message"-style interface - * can be found in l1_command.c. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_IA64_SGI_SN2) -#define USE_SAL_CONSOLE_IO 1 /* DON'T un-def this for the simulator... */ -#endif - -/* Make all console writes atomic */ -#define SYNC_CONSOLE_WRITE 1 - - -/********************************************************************* - * Hardware-level (UART) driver routines. - */ - -/* macros for reading/writing registers */ - -#define LD(x) (*(volatile uint64_t *)(x)) -#define SD(x, v) (LD(x) = (uint64_t) (v)) - -/* location of uart receive/xmit data register */ -#if defined(CONFIG_IA64_SGI_SN1) -#define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), 0x00000080)) -#define LOCK_HUB REMOTE_HUB_ADDR -#elif defined(CONFIG_IA64_SGI_SN2) -#define L1_UART_BASE(n) ((ulong)REMOTE_HUB((n), SH_JUNK_BUS_UART0)) -#define LOCK_HUB REMOTE_HUB -typedef u64 rtc_time_t; -#endif - - -#define ADDR_L1_REG(n, r) ( L1_UART_BASE(n) | ( (r) << 3 ) ) -#define READ_L1_UART_REG(n, r) ( LD(ADDR_L1_REG((n), (r))) ) -#define WRITE_L1_UART_REG(n, r, v) ( SD(ADDR_L1_REG((n), (r)), (v)) ) - -/* upper layer interface calling methods */ -#define SERIAL_INTERRUPT_MODE 0 -#define SERIAL_POLLED_MODE 1 - - -/* UART-related #defines */ - -#define UART_BAUD_RATE 57600 -#define UART_FIFO_DEPTH 16 -#define UART_DELAY_SPAN 10 -#define UART_PUTC_TIMEOUT 50000 -#define UART_INIT_TIMEOUT 100000 - -/* error codes */ -#define UART_SUCCESS 0 -#define UART_TIMEOUT (-1) -#define UART_LINK (-2) -#define UART_NO_CHAR (-3) -#define UART_VECTOR (-4) - -#define UART_DELAY(x) udelay(x) - -/* Some debug counters */ -#define L1C_INTERRUPTS 0 -#define L1C_OUR_R_INTERRUPTS 1 -#define L1C_OUR_X_INTERRUPTS 2 -#define L1C_SEND_CALLUPS 3 -#define L1C_RECEIVE_CALLUPS 4 -#define L1C_SET_BAUD 5 -#define L1C_ALREADY_LOCKED L1C_SET_BAUD -#define L1C_R_IRQ 6 -#define L1C_R_IRQ_RET 7 -#define L1C_LOCK_TIMEOUTS 8 -#define L1C_LOCK_COUNTER 9 -#define L1C_UNLOCK_COUNTER 10 -#define L1C_REC_STALLS 11 -#define L1C_CONNECT_CALLS 12 -#define L1C_SIZE L1C_CONNECT_CALLS /* Set to the last one */ - -uint64_t L1_collectibles[L1C_SIZE + 1]; - - -/* - * Some macros for handling Endian-ness - */ - -#define COPY_INT_TO_BUFFER(_b, _i, _n) \ - { \ - _b[_i++] = (_n >> 24) & 0xff; \ - _b[_i++] = (_n >> 16) & 0xff; \ - _b[_i++] = (_n >> 8) & 0xff; \ - _b[_i++] = _n & 0xff; \ - } - -#define COPY_BUFFER_TO_INT(_b, _i, _n) \ - { \ - _n = (_b[_i++] << 24) & 0xff; \ - _n |= (_b[_i++] << 16) & 0xff; \ - _n |= (_b[_i++] << 8) & 0xff; \ - _n |= _b[_i++] & 0xff; \ - } - -#define COPY_BUFFER_TO_BUFFER(_b, _i, _bn) \ - { \ - char *_xyz = (char *)_bn; \ - _xyz[3] = _b[_i++]; \ - _xyz[2] = _b[_i++]; \ - _xyz[1] = _b[_i++]; \ - _xyz[0] = _b[_i++]; \ - } - -void snia_kmem_free(void *where, int size); - -#define ALREADY_LOCKED 1 -#define NOT_LOCKED 0 -static int early_l1_serial_out(nasid_t, char *, int, int /* defines above*/ ); - -#define BCOPY(x,y,z) memcpy(y,x,z) - -uint8_t L1_interrupts_connected; /* Non-zero when we are in interrupt mode */ - - -/* - * Console locking defines and functions. - * - */ - -uint8_t L1_cons_is_inited = 0; /* non-zero when console is init'd */ -nasid_t Master_console_nasid = (nasid_t)-1; -extern nasid_t console_nasid; - -#if defined(CONFIG_IA64_SGI_SN1) -u64 ia64_sn_get_console_nasid(void); -#endif - -inline nasid_t -get_master_nasid(void) -{ -#if defined(CONFIG_IA64_SGI_SN1) - nasid_t nasid = Master_console_nasid; - - if ( nasid == (nasid_t)-1 ) { - nasid = (nasid_t)ia64_sn_get_console_nasid(); - if ( (nasid < 0) || (nasid >= MAX_NASIDS) ) { - /* Out of bounds, use local */ - console_nasid = nasid = get_nasid(); - } - else { - /* Got a valid nasid, set the console_nasid */ - char xx[100]; -/* zzzzzz - force nasid to 0 for now */ - sprintf(xx, "Master console is set to nasid %d (%d)\n", 0, (int)nasid); -nasid = 0; -/* end zzzzzz */ - xx[99] = (char)0; - early_l1_serial_out(nasid, xx, strlen(xx), NOT_LOCKED); - Master_console_nasid = console_nasid = nasid; - } - } - return(nasid); -#else - return((nasid_t)0); -#endif /* CONFIG_IA64_SGI_SN1 */ -} - - -#if defined(CONFIG_IA64_SGI_SN1) - -#define HUB_LOCK 16 - -#define PRIMARY_LOCK_TIMEOUT 10000000 -#define HUB_LOCK_REG(n) LOCK_HUB(n, MD_PERF_CNT0) - -#define SET_BITS(reg, bits) SD(reg, LD(reg) | (bits)) -#define CLR_BITS(reg, bits) SD(reg, LD(reg) & ~(bits)) -#define TST_BITS(reg, bits) ((LD(reg) & (bits)) != 0) - -#define HUB_TEST_AND_SET(n) LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ)) -#define HUB_CLEAR(n) SD(LOCK_HUB(n,LB_SCRATCH_REG3),0) - -#define RTC_TIME_MAX ((rtc_time_t) ~0ULL) - -/* - * primary_lock - * - * Allows CPU's 0-3 to mutually exclude the hub from one another by - * obtaining a blocking lock. Does nothing if only one CPU is active. - * - * This lock should be held just long enough to set or clear a global - * lock bit. After a relatively short timeout period, this routine - * figures something is wrong, and steals the lock. It does not set - * any other CPU to "dead". - */ -inline void -primary_lock(nasid_t nasid) -{ - rtc_time_t expire; - - expire = rtc_time() + PRIMARY_LOCK_TIMEOUT; - - while (HUB_TEST_AND_SET(nasid)) { - if (rtc_time() > expire) { - HUB_CLEAR(nasid); - } - } -} - -/* - * primary_unlock (internal) - * - * Counterpart to primary_lock - */ - -inline void -primary_unlock(nasid_t nasid) -{ - HUB_CLEAR(nasid); -} - -/* - * hub_unlock - * - * Counterpart to hub_lock_timeout and hub_lock - */ - -inline void -hub_unlock(nasid_t nasid, int level) -{ - uint64_t mask = 1ULL << level; - - primary_lock(nasid); - CLR_BITS(HUB_LOCK_REG(nasid), mask); - primary_unlock(nasid); -} - -/* - * hub_lock_timeout - * - * Uses primary_lock to implement multiple lock levels. - * - * There are 20 lock levels from 0 to 19 (limited by the number of bits - * in HUB_LOCK_REG). To prevent deadlock, multiple locks should be - * obtained in order of increasingly higher level, and released in the - * reverse order. - * - * A timeout value of 0 may be used for no timeout. - * - * Returns 0 if successful, -1 if lock times out. - */ - -inline int -hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout) -{ - uint64_t mask = 1ULL << level; - rtc_time_t expire = (timeout ? rtc_time() + timeout : RTC_TIME_MAX); - int done = 0; - - while (! done) { - while (TST_BITS(HUB_LOCK_REG(nasid), mask)) { - if (rtc_time() > expire) - return -1; - } - - primary_lock(nasid); - - if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) { - SET_BITS(HUB_LOCK_REG(nasid), mask); - done = 1; - } - primary_unlock(nasid); - } - return 0; -} - - -#define LOCK_TIMEOUT (0x1500000 * 1) /* 0x1500000 is ~30 sec */ - -void -lock_console(nasid_t nasid) -{ - int ret; - - /* If we already have it locked, just return */ - L1_collectibles[L1C_LOCK_COUNTER]++; - - ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); - if ( ret != 0 ) { - L1_collectibles[L1C_LOCK_TIMEOUTS]++; - /* timeout */ - hub_unlock(nasid, HUB_LOCK); - /* If the 2nd lock fails, just pile ahead.... */ - hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); - L1_collectibles[L1C_LOCK_TIMEOUTS]++; - } -} - -inline void -unlock_console(nasid_t nasid) -{ - L1_collectibles[L1C_UNLOCK_COUNTER]++; - hub_unlock(nasid, HUB_LOCK); -} - -#else /* SN2 */ -inline void lock_console(nasid_t n) {} -inline void unlock_console(nasid_t n) {} - -#endif /* CONFIG_IA64_SGI_SN1 */ - -int -get_L1_baud(void) -{ - return UART_BAUD_RATE; -} - - -/* uart driver functions */ - -static inline void -uart_delay( rtc_time_t delay_span ) -{ - UART_DELAY( delay_span ); -} - -#define UART_PUTC_READY(n) (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) - -static int -uart_putc( l1sc_t *sc ) -{ - WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] ); - return UART_SUCCESS; -} - - -static int -uart_getc( l1sc_t *sc ) -{ - u_char lsr_reg = 0; - nasid_t nasid = sc->nasid; - - if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & - (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) - { - if( lsr_reg & LSR_RCA ) - return( (u_char)READ_L1_UART_REG( nasid, REG_DAT ) ); - else if( lsr_reg & (LSR_PARERR | LSR_FRMERR) ) { - return UART_LINK; - } - } - - return UART_NO_CHAR; -} - - -#define PROM_SER_CLK_SPEED 12000000 -#define PROM_SER_DIVISOR(x) (PROM_SER_CLK_SPEED / ((x) * 16)) - -static void -uart_init( l1sc_t *sc, int baud ) -{ - rtc_time_t expire; - int clkdiv; - nasid_t nasid; - - clkdiv = PROM_SER_DIVISOR(baud); - expire = rtc_time() + UART_INIT_TIMEOUT; - nasid = sc->nasid; - - /* make sure the transmit FIFO is empty */ - while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XSRE) ) { - uart_delay( UART_DELAY_SPAN ); - if( rtc_time() > expire ) { - break; - } - } - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* Setup for the proper baud rate */ - WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_DLH, (clkdiv >> 8) & 0xff ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_DLL, clkdiv & 0xff ); - uart_delay( UART_DELAY_SPAN ); - - /* set operating parameters and set DLAB to 0 */ - - /* 8bit, one stop, clear request to send, auto flow control */ - WRITE_L1_UART_REG( nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_MCR, MCR_RTS | MCR_AFE ); - uart_delay( UART_DELAY_SPAN ); - - /* disable interrupts */ - WRITE_L1_UART_REG( nasid, REG_ICR, 0x0 ); - uart_delay( UART_DELAY_SPAN ); - - /* enable FIFO mode and reset both FIFOs, trigger on 1 */ - WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO | RxLVL0); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} - -/* This requires the console lock */ - -#if defined(CONFIG_IA64_SGI_SN1) - -static void -uart_intr_enable( l1sc_t *sc, u_char mask ) -{ - u_char lcr_reg, icr_reg; - nasid_t nasid = sc->nasid; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* make sure that the DLAB bit in the LCR register is 0 - */ - lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); - lcr_reg &= ~(LCR_DLAB); - WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); - - /* enable indicated interrupts - */ - icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); - icr_reg |= mask; - WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} - -/* This requires the console lock */ -static void -uart_intr_disable( l1sc_t *sc, u_char mask ) -{ - u_char lcr_reg, icr_reg; - nasid_t nasid = sc->nasid; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* make sure that the DLAB bit in the LCR register is 0 - */ - lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); - lcr_reg &= ~(LCR_DLAB); - WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); - - /* enable indicated interrupts - */ - icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); - icr_reg &= mask; - WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} -#endif /* CONFIG_IA64_SGI_SN1 */ - -#define uart_enable_xmit_intr(sc) \ - uart_intr_enable((sc), ICR_TIEN) - -#define uart_disable_xmit_intr(sc) \ - uart_intr_disable((sc), ~(ICR_TIEN)) - -#define uart_enable_recv_intr(sc) \ - uart_intr_enable((sc), ICR_RIEN) - -#define uart_disable_recv_intr(sc) \ - uart_intr_disable((sc), ~(ICR_RIEN)) - - -/********************************************************************* - * Routines for accessing a remote (router) UART - */ - -#define READ_RTR_L1_UART_REG(p, n, r, v) \ - { \ - if( vector_read_node( (p), (n), 0, \ - RR_JBUS1(r), (v) ) ) { \ - return UART_VECTOR; \ - } \ - } - -#define WRITE_RTR_L1_UART_REG(p, n, r, v) \ - { \ - if( vector_write_node( (p), (n), 0, \ - RR_JBUS1(r), (v) ) ) { \ - return UART_VECTOR; \ - } \ - } - -#define RTR_UART_PUTC_TIMEOUT UART_PUTC_TIMEOUT*10 -#define RTR_UART_DELAY_SPAN UART_DELAY_SPAN -#define RTR_UART_INIT_TIMEOUT UART_INIT_TIMEOUT*10 - -static int -rtr_uart_putc( l1sc_t *sc ) -{ - uint64_t regval, c; - nasid_t nasid = sc->nasid; - net_vec_t path = sc->uart; - rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT; - - c = (sc->send[sc->sent] & 0xffULL); - - while( 1 ) - { - /* Check for "tx hold reg empty" bit. */ - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & LSR_XHRE ) - { - WRITE_RTR_L1_UART_REG( path, nasid, REG_DAT, c ); - return UART_SUCCESS; - } - - if( rtc_time() >= expire ) - { - return UART_TIMEOUT; - } - uart_delay( RTR_UART_DELAY_SPAN ); - } -} - - -static int -rtr_uart_getc( l1sc_t *sc ) -{ - uint64_t regval; - nasid_t nasid = sc->nasid; - net_vec_t path = sc->uart; - - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) - { - if( regval & LSR_RCA ) - { - READ_RTR_L1_UART_REG( path, nasid, REG_DAT, ®val ); - return( (int)regval ); - } - else - { - return UART_LINK; - } - } - - return UART_NO_CHAR; -} - - -static int -rtr_uart_init( l1sc_t *sc, int baud ) -{ - rtc_time_t expire; - int clkdiv; - nasid_t nasid; - net_vec_t path; - uint64_t regval; - - clkdiv = PROM_SER_DIVISOR(baud); - expire = rtc_time() + RTR_UART_INIT_TIMEOUT; - nasid = sc->nasid; - path = sc->uart; - - /* make sure the transmit FIFO is empty */ - while(1) { - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & LSR_XSRE ) { - break; - } - if( rtc_time() > expire ) { - break; - } - uart_delay( RTR_UART_DELAY_SPAN ); - } - - WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_DLAB ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_DLH, (clkdiv >> 8) & 0xff ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_DLL, clkdiv & 0xff ); - uart_delay( UART_DELAY_SPAN ); - - /* set operating parameters and set DLAB to 0 */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_MCR, MCR_RTS | MCR_AFE ); - uart_delay( UART_DELAY_SPAN ); - - /* disable interrupts */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_ICR, 0x0 ); - uart_delay( UART_DELAY_SPAN ); - - /* enable FIFO mode and reset both FIFOs */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, FCR_FIFOEN ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, - FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO ); - - return 0; -} - -/********************************************************************* - * locking macros - */ - -#define L1SC_SEND_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->send_lock),p); } -#define L1SC_SEND_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->send_lock), p); } -#define L1SC_RECV_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->recv_lock), p); } -#define L1SC_RECV_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->recv_lock), p); } - - -/********************************************************************* - * subchannel manipulation - * - * The SUBCH_[UN]LOCK macros are used to arbitrate subchannel - * allocation. SUBCH_DATA_[UN]LOCK control access to data structures - * associated with particular subchannels (e.g., receive queues). - * - */ -#define SUBCH_LOCK(sc, p) spin_lock_irqsave( &((sc)->subch_lock), p ) -#define SUBCH_UNLOCK(sc, p) spin_unlock_irqrestore( &((sc)->subch_lock), p ) -#define SUBCH_DATA_LOCK(sbch, p) spin_lock_irqsave( &((sbch)->data_lock), p ) -#define SUBCH_DATA_UNLOCK(sbch, p) spin_unlock_irqrestore( &((sbch)->data_lock), p ) - - -/* - * set a function to be called for subchannel ch in the event of - * a transmission low-water interrupt from the uart - */ -void -subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - unsigned long pl = 0; - - L1SC_SEND_LOCK( sc, pl ); -#if !defined(SYNC_CONSOLE_WRITE) - if ( func && !sc->send_in_use ) - uart_enable_xmit_intr( sc ); -#endif - sc->subch[ch].tx_notify = func; - L1SC_SEND_UNLOCK(sc, pl ); -} - -/* - * set a function to be called for subchannel ch when data is received - */ -void -subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - SUBCH_DATA_LOCK( subch, pl ); - sc->subch[ch].rx_notify = func; - SUBCH_DATA_UNLOCK( subch, pl ); -} - -/********************************************************************* - * Queue manipulation macros - * - * - */ -#define NEXT(p) (((p) + 1) & (BRL1_QSIZE-1)) /* assume power of 2 */ - -#define cq_init(q) bzero((q), sizeof (*(q))) -#define cq_empty(q) ((q)->ipos == (q)->opos) -#define cq_full(q) (NEXT((q)->ipos) == (q)->opos) -#define cq_used(q) ((q)->opos <= (q)->ipos ? \ - (q)->ipos - (q)->opos : \ - BRL1_QSIZE + (q)->ipos - (q)->opos) -#define cq_room(q) ((q)->opos <= (q)->ipos ? \ - BRL1_QSIZE - 1 + (q)->opos - (q)->ipos : \ - (q)->opos - (q)->ipos - 1) -#define cq_add(q, c) ((q)->buf[(q)->ipos] = (u_char) (c), \ - (q)->ipos = NEXT((q)->ipos)) -#define cq_rem(q, c) ((c) = (q)->buf[(q)->opos], \ - (q)->opos = NEXT((q)->opos)) -#define cq_discard(q) ((q)->opos = NEXT((q)->opos)) - -#define cq_tent_full(q) (NEXT((q)->tent_next) == (q)->opos) -#define cq_tent_len(q) ((q)->ipos <= (q)->tent_next ? \ - (q)->tent_next - (q)->ipos : \ - BRL1_QSIZE + (q)->tent_next - (q)->ipos) -#define cq_tent_add(q, c) \ - ((q)->buf[(q)->tent_next] = (u_char) (c), \ - (q)->tent_next = NEXT((q)->tent_next)) -#define cq_commit_tent(q) \ - ((q)->ipos = (q)->tent_next) -#define cq_discard_tent(q) \ - ((q)->tent_next = (q)->ipos) - - - - -/********************************************************************* - * CRC-16 (for checking bedrock/L1 packets). - * - * These are based on RFC 1662 ("PPP in HDLC-like framing"). - */ - -static unsigned short fcstab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -#define INIT_CRC 0xFFFF /* initial CRC value */ -#define GOOD_CRC 0xF0B8 /* "good" final CRC value */ - -static unsigned short crc16_calc( unsigned short crc, u_char c ) -{ - return( (crc >> 8) ^ fcstab[(crc ^ c) & 0xff] ); -} - - -/*********************************************************************** - * The following functions implement the PPP-like bedrock/L1 protocol - * layer. - * - */ - -#define BRL1_FLAG_CH 0x7e -#define BRL1_ESC_CH 0x7d -#define BRL1_XOR_CH 0x20 - -/* L1<->Bedrock packet types */ -#define BRL1_REQUEST 0x00 -#define BRL1_RESPONSE 0x20 -#define BRL1_EVENT 0x40 - -#define BRL1_PKT_TYPE_MASK 0xE0 -#define BRL1_SUBCH_MASK 0x1F - -#define PKT_TYPE(tsb) ((tsb) & BRL1_PKT_TYPE_MASK) -#define SUBCH(tsb) ((tsb) & BRL1_SUBCH_MASK) - -/* timeouts */ -#define BRL1_INIT_TIMEOUT 500000 - -/* - * brl1_discard_packet is a dummy "receive callback" used to get rid - * of packets we don't want - */ -void brl1_discard_packet( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - brl1_sch_t *subch = &sc->subch[ch]; - - sc_cq_t *q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); - q->opos = q->ipos; - atomic_set(&(subch->packet_arrived), 0); - SUBCH_DATA_UNLOCK( subch, pl ); -} - - -/* - * brl1_send_chars sends the send buffer in the l1sc_t structure - * out through the uart. Assumes that the caller has locked the - * UART (or send buffer in the kernel). - * - * This routine doesn't block-- if you want it to, call it in - * a loop. - */ -static int -brl1_send_chars( l1sc_t *sc ) -{ - /* We track the depth of the C brick's UART's - * fifo in software, and only check if the UART is accepting - * characters when our count indicates that the fifo should - * be full. - * - * For remote (router) UARTs, we check with the UART before sending every - * character. - */ - if( sc->uart == BRL1_LOCALHUB_UART ) { - if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) ) - sc->fifo_space = UART_FIFO_DEPTH; - - while( (sc->sent < sc->send_len) && (sc->fifo_space) ) { - uart_putc( sc ); - sc->fifo_space--; - sc->sent++; - } - } - else { - - /* remote (router) UARTs */ - - int result; - int tries = 0; - - while( sc->sent < sc->send_len ) { - result = sc->putc_f( sc ); - if( result >= 0 ) { - (sc->sent)++; - continue; - } - if( result == UART_TIMEOUT ) { - tries++; - /* send this character in TIMEOUT_RETRIES... */ - if( tries < 30 /* TIMEOUT_RETRIES */ ) { - continue; - } - /* ...or else... */ - else { - /* ...drop the packet. */ - sc->sent = sc->send_len; - return sc->send_len; - } - } - if( result < 0 ) { - return result; - } - } - } - return sc->sent; -} - - -/* brl1_send formats up a packet and (at least begins to) send it - * to the uart. If the send buffer is in use when this routine obtains - * the lock, it will behave differently depending on the "wait" parameter. - * For wait == 0 (most I/O), it will return 0 (as in "zero bytes sent"), - * hopefully encouraging the caller to back off (unlock any high-level - * spinlocks) and allow the buffer some time to drain. For wait==1 (high- - * priority I/O along the lines of kernel error messages), we will flush - * the current contents of the send buffer and beat on the uart - * until our message has been completely transmitted. - */ - -static int -brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait ) -{ - unsigned long pl = 0; - int index; - int pkt_len = 0; - unsigned short crc = INIT_CRC; - char *send_ptr = sc->send; - - - if( sc->send_in_use && !(wait) ) { - /* We are in the middle of sending, but can wait until done */ - return 0; - } - else if( sc->send_in_use ) { - /* buffer's in use, but we're synchronous I/O, so we're going - * to send whatever's in there right now and take the buffer - */ - int counter = 0; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - while( sc->sent < sc->send_len ) { - brl1_send_chars( sc ); - if ( counter++ > 0xfffff ) { - char *str = "Looping waiting for uart to clear (1)\n"; - early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); - break; - } - } - } - else { - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - sc->send_in_use = 1; - } - *send_ptr++ = BRL1_FLAG_CH; - *send_ptr++ = type_and_subch; - pkt_len += 2; - crc = crc16_calc( crc, type_and_subch ); - - /* limit number of characters accepted to max payload size */ - if( len > (BRL1_QSIZE - 1) ) - len = (BRL1_QSIZE - 1); - - /* copy in the message buffer (inserting PPP - * framing info where necessary) - */ - for( index = 0; index < len; index++ ) { - - switch( *msg ) { - - case BRL1_FLAG_CH: - *send_ptr++ = BRL1_ESC_CH; - *send_ptr++ = (*msg) ^ BRL1_XOR_CH; - pkt_len += 2; - break; - - case BRL1_ESC_CH: - *send_ptr++ = BRL1_ESC_CH; - *send_ptr++ = (*msg) ^ BRL1_XOR_CH; - pkt_len += 2; - break; - - default: - *send_ptr++ = *msg; - pkt_len++; - } - crc = crc16_calc( crc, *msg ); - msg++; - } - crc ^= 0xffff; - - for( index = 0; index < sizeof(crc); index++ ) { - char crc_char = (char)(crc & 0x00FF); - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - *send_ptr++ = BRL1_ESC_CH; - pkt_len++; - crc_char ^= BRL1_XOR_CH; - } - *send_ptr++ = crc_char; - pkt_len++; - crc >>= 8; - } - - *send_ptr++ = BRL1_FLAG_CH; - pkt_len++; - - sc->send_len = pkt_len; - sc->sent = 0; - - { - int counter = 0; - do { - brl1_send_chars( sc ); - if ( counter++ > 0xfffff ) { - char *str = "Looping waiting for uart to clear (2)\n"; - early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); - break; - } - } while( (sc->sent < sc->send_len) && wait ); - } - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(sc->nasid); - - if( sc->sent == sc->send_len ) { - /* success! release the send buffer and call the callup */ -#if !defined(SYNC_CONSOLE_WRITE) - brl1_notif_t callup; -#endif - - sc->send_in_use = 0; - /* call any upper layer that's asked for notification */ -#if defined(XX_SYNC_CONSOLE_WRITE) - /* - * This is probably not a good idea - since the l1_ write func can be called multiple - * time within the callup function. - */ - callup = subch->tx_notify; - if( callup && (SUBCH(type_and_subch) == SC_CONS_SYSTEM) ) { - L1_collectibles[L1C_SEND_CALLUPS]++; - (*callup)(sc->subch[SUBCH(type_and_subch)].irq_frame.bf_irq, - sc->subch[SUBCH(type_and_subch)].irq_frame.bf_dev_id, - sc->subch[SUBCH(type_and_subch)].irq_frame.bf_regs, sc, SUBCH(type_and_subch)); - } -#endif /* SYNC_CONSOLE_WRITE */ - } -#if !defined(SYNC_CONSOLE_WRITE) - else if ( !wait ) { - /* enable low-water interrupts so buffer will be drained */ - uart_enable_xmit_intr(sc); - } -#endif - - L1SC_SEND_UNLOCK(sc, pl); - - return len; -} - -/* brl1_send_cont is intended to be called as an interrupt service - * routine. It sends until the UART won't accept any more characters, - * or until an error is encountered (in which case we surrender the - * send buffer and give up trying to send the packet). Once the - * last character in the packet has been sent, this routine releases - * the send buffer and calls any previously-registered "low-water" - * output routines. - */ - -#if !defined(SYNC_CONSOLE_WRITE) - -int -brl1_send_cont( l1sc_t *sc ) -{ - unsigned long pl = 0; - int done = 0; - brl1_notif_t callups[BRL1_NUM_SUBCHANS]; - brl1_notif_t *callup; - brl1_sch_t *subch; - int index; - - /* - * I'm not sure how I think this is to be handled - whether the lock is held - * over the interrupt - but it seems like it is a bad idea.... - */ - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - brl1_send_chars( sc ); - done = (sc->sent == sc->send_len); - if( done ) { - sc->send_in_use = 0; -#if !defined(SYNC_CONSOLE_WRITE) - uart_disable_xmit_intr(sc); -#endif - } - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(sc->nasid); - /* Release the lock */ - L1SC_SEND_UNLOCK(sc, pl); - - return 0; -} -#endif /* SYNC_CONSOLE_WRITE */ - -/* internal function -- used by brl1_receive to read a character - * from the uart and check whether errors occurred in the process. - */ -static int -read_uart( l1sc_t *sc, int *c, int *result ) -{ - *c = sc->getc_f( sc ); - - /* no character is available */ - if( *c == UART_NO_CHAR ) { - *result = BRL1_NO_MESSAGE; - return 0; - } - - /* some error in UART */ - if( *c < 0 ) { - *result = BRL1_LINK; - return 0; - } - - /* everything's fine */ - *result = BRL1_VALID; - return 1; -} - - -/* - * brl1_receive - * - * This function reads a Bedrock-L1 protocol packet into the l1sc_t - * response buffer. - * - * The operation of this function can be expressed as a finite state - * machine: - * - -START STATE INPUT TRANSITION -========================================================== -BRL1_IDLE (reset or error) flag BRL1_FLAG - other BRL1_IDLE@ - -BRL1_FLAG (saw a flag (0x7e)) flag BRL1_FLAG - escape BRL1_IDLE@ - header byte BRL1_HDR - other BRL1_IDLE@ - -BRL1_HDR (saw a type/subch byte)(see below) BRL1_BODY - BRL1_HDR - -BRL1_BODY (reading packet body) flag BRL1_FLAG - escape BRL1_ESC - other BRL1_BODY - -BRL1_ESC (saw an escape (0x7d)) flag BRL1_FLAG@ - escape BRL1_IDLE@ - other BRL1_BODY -========================================================== - -"@" denotes an error transition. - - * The BRL1_HDR state is a transient state which doesn't read input, - * but just provides a way in to code which decides to whom an - * incoming packet should be directed. - * - * brl1_receive can be used to poll for input from the L1, or as - * an interrupt service routine. It reads as much data as is - * ready from the junk bus UART and places into the appropriate - * input queues according to subchannel. The header byte is - * stripped from console-type data, but is retained for message- - * type data (L1 responses). A length byte will also be - * prepended to message-type packets. - * - * This routine is non-blocking; if the caller needs to block - * for input, it must call brl1_receive in a loop. - * - * brl1_receive returns when there is no more input, the queue - * for the current incoming message is full, or there is an - * error (parity error, bad header, bad CRC, etc.). - */ - -#define STATE_SET(l,s) ((l)->brl1_state = (s)) -#define STATE_GET(l) ((l)->brl1_state) - -#define LAST_HDR_SET(l,h) ((l)->brl1_last_hdr = (h)) -#define LAST_HDR_GET(l) ((l)->brl1_last_hdr) - -#define VALID_HDR(c) \ - ( SUBCH((c)) <= SC_CONS_SYSTEM \ - ? PKT_TYPE((c)) == BRL1_REQUEST \ - : ( PKT_TYPE((c)) == BRL1_RESPONSE || \ - PKT_TYPE((c)) == BRL1_EVENT ) ) - -#define IS_TTY_PKT(l) ( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 ) - - -int -brl1_receive( l1sc_t *sc, int mode ) -{ - int result; /* value to be returned by brl1_receive */ - int c; /* most-recently-read character */ - int done; /* set done to break out of recv loop */ - unsigned long pl = 0, cpl = 0; - sc_cq_t *q; /* pointer to queue we're working with */ - - result = BRL1_NO_MESSAGE; - - L1SC_RECV_LOCK(sc, cpl); - - done = 0; - while( !done ) - { - switch( STATE_GET(sc) ) - { - - case BRL1_IDLE: - /* Initial or error state. Waiting for a flag character - * to resynchronize with the L1. - */ - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* saw a flag character */ - STATE_SET( sc, BRL1_FLAG ); - continue; - } - break; - - case BRL1_FLAG: - /* One or more flag characters have been read; look for - * the beginning of a packet (header byte). - */ - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) - STATE_SET( sc, BRL1_IDLE ); - - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* multiple flags are OK */ - continue; - } - - if( !VALID_HDR( c ) ) { - /* if c isn't a flag it should have been - * a valid header, so we have an error - */ - result = BRL1_PROTOCOL; - STATE_SET( sc, BRL1_IDLE ); - done = 1; - continue; - } - - /* we have a valid header byte */ - LAST_HDR_SET( sc, c ); - STATE_SET( sc, BRL1_HDR ); - - break; - - case BRL1_HDR: - /* A header byte has been read. Do some bookkeeping. */ - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - if( !IS_TTY_PKT(sc) ) { - /* if this is an event or command response rather - * than console I/O, we need to reserve a couple - * of extra spaces in the queue for the header - * byte and a length byte; if we can't, stay in - * the BRL1_HDR state. - */ - if( cq_room( q ) < 2 ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - cq_tent_add( q, 0 ); /* reserve length byte */ - cq_tent_add( q, LAST_HDR_GET( sc ) ); /* record header byte */ - } - STATE_SET( sc, BRL1_BODY ); - - break; - - case BRL1_BODY: - /* A header byte has been read. We are now attempting - * to receive the packet body. - */ - - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - /* if the queue we want to write into is full, don't read from - * the uart (this provides backpressure to the L1 side) - */ - if( cq_tent_full( q ) ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) - STATE_SET( sc, BRL1_IDLE ); - done = 1; - continue; - } - - if( c == BRL1_ESC_CH ) { - /* prepare to unescape the next character */ - STATE_SET( sc, BRL1_ESC ); - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* flag signifies the end of a packet */ - - unsigned short crc; /* holds the crc as we calculate it */ - int i; /* index variable */ - brl1_sch_t *subch; /* subchannel for received packet */ - brl1_notif_t callup; /* "data ready" callup */ - - /* whatever else may happen, we've seen a flag and we're - * starting a new packet - */ - STATE_SET( sc, BRL1_FLAG ); - - /* if the packet body has less than 2 characters, - * it can't be a well-formed packet. Discard it. - */ - if( cq_tent_len( q ) < /* 2 + possible length byte */ - (2 + (IS_TTY_PKT(sc) ? 0 : 1)) ) - { - result = BRL1_PROTOCOL; - cq_discard_tent( q ); - STATE_SET( sc, BRL1_FLAG ); - done = 1; - continue; - } - - /* check CRC */ - - /* accumulate CRC, starting with the header byte and - * ending with the transmitted CRC. This should - * result in a known good value. - */ - crc = crc16_calc( INIT_CRC, LAST_HDR_GET(sc) ); - for( i = (q->ipos + (IS_TTY_PKT(sc) ? 0 : 2)) % BRL1_QSIZE; - i != q->tent_next; - i = (i + 1) % BRL1_QSIZE ) - { - crc = crc16_calc( crc, q->buf[i] ); - } - - /* verify the caclulated crc against the "good" crc value; - * if we fail, discard the bad packet and return an error. - */ - if( crc != (unsigned short)GOOD_CRC ) { - result = BRL1_CRC; - cq_discard_tent( q ); - STATE_SET( sc, BRL1_FLAG ); - done = 1; - continue; - } - - /* so the crc check was ok. Now we discard the CRC - * from the end of the received bytes. - */ - q->tent_next += (BRL1_QSIZE - 2); - q->tent_next %= BRL1_QSIZE; - - /* get the subchannel and lock it */ - subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); - SUBCH_DATA_LOCK( subch, pl ); - - /* if this isn't a console packet, we need to record - * a length byte - */ - if( !IS_TTY_PKT(sc) ) { - q->buf[q->ipos] = cq_tent_len( q ) - 1; - } - - /* record packet for posterity */ - cq_commit_tent( q ); - result = BRL1_VALID; - - /* notify subchannel owner that there's something - * on the queue for them - */ - atomic_inc(&(subch->packet_arrived)); - callup = subch->rx_notify; - SUBCH_DATA_UNLOCK( subch, pl ); - - if( callup && (mode == SERIAL_INTERRUPT_MODE) ) { - L1SC_RECV_UNLOCK( sc, cpl ); - L1_collectibles[L1C_RECEIVE_CALLUPS]++; - (*callup)( sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_irq, - sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_dev_id, - sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_regs, - sc, SUBCH(LAST_HDR_GET(sc)) ); - L1SC_RECV_LOCK( sc, cpl ); - } - continue; /* go back for more! */ - } - - /* none of the special cases applied; we've got a normal - * body character - */ - cq_tent_add( q, c ); - - break; - - case BRL1_ESC: - /* saw an escape character. The next character will need - * to be unescaped. - */ - - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - /* if the queue we want to write into is full, don't read from - * the uart (this provides backpressure to the L1 side) - */ - if( cq_tent_full( q ) ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) { - cq_discard_tent( q ); - STATE_SET( sc, BRL1_IDLE ); - } - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* flag after escape is an error */ - STATE_SET( sc, BRL1_FLAG ); - cq_discard_tent( q ); - result = BRL1_PROTOCOL; - done = 1; - continue; - } - - if( c == BRL1_ESC_CH ) { - /* two consecutive escapes is an error */ - STATE_SET( sc, BRL1_IDLE ); - cq_discard_tent( q ); - result = BRL1_PROTOCOL; - done = 1; - continue; - } - - /* otherwise, we've got a character that needs - * to be unescaped - */ - cq_tent_add( q, (c ^ BRL1_XOR_CH) ); - STATE_SET( sc, BRL1_BODY ); - - break; - - } /* end of switch( STATE_GET(sc) ) */ - } /* end of while(!done) */ - - L1SC_RECV_UNLOCK( sc, cpl ); - - return result; -} - - -/* brl1_init initializes the Bedrock/L1 protocol layer. This includes - * zeroing out the send and receive state information. - */ - -void -brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - int i; - brl1_sch_t *subch; - - bzero( sc, sizeof( *sc ) ); - sc->nasid = nasid; - sc->uart = uart; - sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); - sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); - sc->sol = 1; - subch = sc->subch; - - /* initialize L1 subchannels - */ - - /* assign processor TTY channels */ - for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); - subch->tx_notify = NULL; - /* (for now, drop elscuart packets in the kernel) */ - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* assign system TTY channel (first free subchannel after each - * processor's individual TTY channel has been assigned) - */ - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); - subch->tx_notify = NULL; - if( sc->uart == BRL1_LOCALHUB_UART ) { - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - subch->rx_notify = NULL; - } - else { - /* we shouldn't be getting console input from remote UARTs */ - subch->iqp = &sc->garbage_q; - subch->rx_notify = brl1_discard_packet; - } - subch++; i++; - - /* "reserved" subchannels (0x05-0x0F); for now, throw away - * incoming packets - */ - for( ; i < 0x10; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* remaining subchannels are free */ - for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* initialize synchronization structures - */ - spin_lock_init( &(sc->subch_lock) ); - spin_lock_init( &(sc->send_lock) ); - spin_lock_init( &(sc->recv_lock) ); - - if( sc->uart == BRL1_LOCALHUB_UART ) { - uart_init( sc, UART_BAUD_RATE ); - } - else { - rtr_uart_init( sc, UART_BAUD_RATE ); - } - - /* Set up remaining fields using L1 command functions-- elsc_module_get - * to read the module id, elsc_debug_get to see whether or not we're - * in verbose mode. - */ - { - extern int elsc_module_get(l1sc_t *); - - sc->modid = elsc_module_get( sc ); - sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid); - sc->verbose = 1; - } -} - -/********************************************************************* - * These are interrupt-related functions used in the kernel to service - * the L1. - */ - -/* - * brl1_intrd is the function which is called on a console interrupt. - */ - -#if defined(CONFIG_IA64_SGI_SN1) - -static void -brl1_intrd(int irq, void *dev_id, struct pt_regs *stuff) -{ - u_char isr_reg; - l1sc_t *sc = get_elsc(); - int ret; - - L1_collectibles[L1C_INTERRUPTS]++; - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - - /* Save for callup args in console */ - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_irq = irq; - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_dev_id = dev_id; - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_regs = stuff; - -#if defined(SYNC_CONSOLE_WRITE) - while( isr_reg & ISR_RxRDY ) -#else - while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) -#endif - { - if( isr_reg & ISR_RxRDY ) { - L1_collectibles[L1C_OUR_R_INTERRUPTS]++; - ret = brl1_receive(sc, SERIAL_INTERRUPT_MODE); - if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) - L1_collectibles[L1C_REC_STALLS] = ret; - } -#if !defined(SYNC_CONSOLE_WRITE) - if( (isr_reg & ISR_TxRDY) || (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) { - L1_collectibles[L1C_OUR_X_INTERRUPTS]++; - brl1_send_cont(sc); - } -#endif /* SYNC_CONSOLE_WRITE */ - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - } -} -#endif /* CONFIG_IA64_SGI_SN1 */ - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when the send buffer - * has been emptied. - */ -static inline void -l1_tx_notif( brl1_notif_t func ) -{ - subch_set_tx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, - SC_CONS_SYSTEM, func ); -} - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when a packet has been - * received. - */ -static inline void -l1_rx_notif( brl1_notif_t func ) -{ - subch_set_rx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, - SC_CONS_SYSTEM, func ); -} - - -/* brl1_intr is called directly from the uart interrupt; after it runs, the - * interrupt "daemon" xthread is signalled to continue. - */ -void -brl1_intr( void ) -{ -} - -#define BRL1_INTERRUPT_LEVEL 65 /* linux request_irq() value */ - -/* Return the current interrupt level */ - -//#define CONSOLE_POLLING_ALSO - -int -l1_get_intr_value( void ) -{ -#if defined(USE_SAL_CONSOLE_IO) - return(0); -#else -#if defined(CONSOLE_POLLING_ALSO) - return(0); -#else - return(BRL1_INTERRUPT_LEVEL); -#endif /* CONSOLE_POLLING_ALSO */ -#endif /* USE_SAL_CONSOLE_IO */ -} - -/* Disconnect the callup functions - throw away interrupts */ - -void -l1_unconnect_intr(void) -{ -#if !defined(USE_SAL_CONSOLE_IO) - /* UnRegister the upper-level callup functions */ - l1_rx_notif((brl1_notif_t)NULL); - l1_tx_notif((brl1_notif_t)NULL); - /* We do NOT unregister the interrupts */ -#endif /* !USE_SAL_CONSOLE_IO */ -} - -/* Set up uart interrupt handling for this node's uart */ - -void -l1_connect_intr(void *rx_notify, void *tx_notify) -{ -#if defined(USE_SAL_CONSOLE_IO) -#if 0 - // Will need code here for sn2 - something like this - console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()); - intr_connect_level(console_nodepda->node_first_cpu, - SGI_UART_VECTOR, INTPEND0_MAXMASK, - dummy_intr_func); - request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8), - intr_func, SA_INTERRUPT | SA_SHIRQ, - "l1_protocol_driver", (void *)sc); -#endif -#else - l1sc_t *sc; - nasid_t nasid; -#if defined(CONFIG_IA64_SGI_SN1) - int tmp; -#endif - nodepda_t *console_nodepda; - int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); - - if ( L1_interrupts_connected ) { - /* Interrupts are connected, so just register the callups */ - l1_rx_notif((brl1_notif_t)rx_notify); - l1_tx_notif((brl1_notif_t)tx_notify); - - L1_collectibles[L1C_CONNECT_CALLS]++; - return; - } - else - L1_interrupts_connected = 1; - - nasid = get_master_nasid(); - console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(nasid)); - sc = &console_nodepda->module->elsc; - sc->intr_cpu = console_nodepda->node_first_cpu; - -#if defined(CONFIG_IA64_SGI_SN1) - if ( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, (intr_func_t)brl1_intr) ) { - L1_interrupts_connected = 0; /* FAILS !! */ - } - else { - void synergy_intr_connect(int, int); - - synergy_intr_connect(UART_INTR, sc->intr_cpu); - L1_collectibles[L1C_R_IRQ]++; - tmp = request_irq(BRL1_INTERRUPT_LEVEL, brl1_intrd, SA_INTERRUPT | SA_SHIRQ, "l1_protocol_driver", (void *)sc); - L1_collectibles[L1C_R_IRQ_RET] = (uint64_t)tmp; - if ( tmp ) { - L1_interrupts_connected = 0; /* FAILS !! */ - } - else { - /* Register the upper-level callup functions */ - l1_rx_notif((brl1_notif_t)rx_notify); - l1_tx_notif((brl1_notif_t)tx_notify); - - /* Set the uarts the way we like it */ - uart_enable_recv_intr( sc ); - uart_disable_xmit_intr( sc ); - } - } -#endif /* CONFIG_IA64_SGI_SN1 */ -#endif /* USE_SAL_CONSOLE_IO */ -} - - -/* These are functions to use from serial_in/out when in protocol - * mode to send and receive uart control regs. These are external - * interfaces into the protocol driver. - */ - -void -l1_control_out(int offset, int value) -{ -#if defined(USE_SAL_CONSOLE_IO) - /* quietly ignore unless simulator */ - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - if ( master_node_bedrock_address != (u64)0 ) { - writeb(value, (unsigned long)master_node_bedrock_address + - (offset<< 3)); - } - return; - } -#else - nasid_t nasid = get_master_nasid(); - WRITE_L1_UART_REG(nasid, offset, value); -#endif -} - -/* Console input exported interface. Return a register value. */ - -int -l1_control_in_polled(int offset) -{ - static int l1_control_in_local(int, int); - - return(l1_control_in_local(offset, SERIAL_POLLED_MODE)); -} - -int -l1_control_in(int offset) -{ - static int l1_control_in_local(int, int); - - return(l1_control_in_local(offset, SERIAL_INTERRUPT_MODE)); -} - -static int -l1_control_in_local(int offset, int mode) -{ -#if defined(USE_SAL_CONSOLE_IO) - int sal_call_status = 0, input; - int ret = 0; - - if ( offset == REG_LSR ) { - ret = (LSR_XHRE | LSR_XSRE); /* can send anytime */ - sal_call_status = ia64_sn_console_check(&input); - if ( !sal_call_status && input ) { - /* input pending */ - ret |= LSR_RCA; - } - } - - /* If the sal call failed, do it the old-fashioned way */ - if ( sal_call_status ) { - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - ret = readb((unsigned long)master_node_bedrock_address + - (offset<< 3)); - } - else { -#endif /* USE_SAL_CONSOLE_IO */ - nasid_t nasid; - int ret, input; - static int l1_poll(l1sc_t *, int); - - nasid = get_master_nasid(); - ret = READ_L1_UART_REG(nasid, offset); - - if ( offset == REG_LSR ) { - ret |= (LSR_XHRE | LSR_XSRE); /* can send anytime */ - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { - input = l1_poll(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, mode); - if ( input ) { - ret |= LSR_RCA; - } - } - } - } -#if defined(USE_SAL_CONSOLE_IO) - } - } -#endif - return(ret); -} - -/* - * Console input exported interface. Return a character (if one is available) - */ - -int -l1_serial_in_polled(void) -{ - static int l1_serial_in_local(int mode); - - return(l1_serial_in_local(SERIAL_POLLED_MODE)); -} - -int -l1_serial_in(void) -{ - static int l1_serial_in_local(int mode); - - return(l1_serial_in_local(SERIAL_INTERRUPT_MODE)); -} - -static int -l1_serial_in_local(int mode) -{ -#if defined(USE_SAL_CONSOLE_IO) - int sal_call_status; - int ch; - - sal_call_status = ia64_sn_console_getc(&ch); - if ( !sal_call_status ) { - return(ch); - } - else { - /* If the sal called failed - do it the old-fashioned way */ - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3))); - } - else { -#endif /* USE_SAL_CONSOLE_IO */ - nasid_t nasid; - l1sc_t *sc; - int value; - static int l1_getc( l1sc_t *, int ); - static inline l1sc_t *early_sc_init(nasid_t); - - nasid = get_master_nasid(); - sc = early_sc_init(nasid); - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { - sc = &NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc; - } - } - value = l1_getc(sc, mode); - return(value); -#if defined(USE_SAL_CONSOLE_IO) - } - } -#endif -} - -/* Console output exported interface. Write message to the console. */ - -int -l1_serial_out( char *str, int len ) -{ -#if defined(USE_SAL_CONSOLE_IO) - int sal_call_status = 0; - int counter = len; - - /* Attempt to write things out thru the sal */ - while ( counter > 0 ) { - if ( (sal_call_status = ia64_sn_console_putc(*str)) ) { - break; - } - counter--; - str++; - } - if ( sal_call_status ) { - /* If the sal called failed - do it the old-fashioned way */ - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - if (!master_node_bedrock_address) - early_sn_setup(); - if ( master_node_bedrock_address != (u64)0 ) { -#ifdef FLAG_DIRECT_CONSOLE_WRITES - /* This is an easy way to pre-pend the output to know whether the output - * was done via sal or directly */ - writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); -#endif /* FLAG_DIRECT_CONSOLE_WRITES */ - while ( counter > 0 ) { - writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - counter--; - str++; - } - } - } - else { -#endif /* USE_SAL_CONSOLE_IO */ - nasid_t nasid = get_master_nasid(); - int l1_write(l1sc_t *, char *, int, int); - - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) - return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len, -#if defined(SYNC_CONSOLE_WRITE) - 1 -#else - !L1_interrupts_connected -#endif - )); - } - return(early_l1_serial_out(nasid, str, len, NOT_LOCKED)); -#if defined(USE_SAL_CONSOLE_IO) - } - } - return((counter <= 0) ? 0 : (len - counter)); -#endif -} - - -/* - * These are the 'early' functions - when we need to do things before we have - * all the structs setup. - */ - - -static l1sc_t Early_console; /* fake l1sc_t */ -static int Early_console_inited = 0; - -static void -early_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - int i; - brl1_sch_t *subch; - - bzero( sc, sizeof( *sc ) ); - sc->nasid = nasid; - sc->uart = uart; - sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); - sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); - sc->sol = 1; - subch = sc->subch; - - /* initialize L1 subchannels - */ - - /* assign processor TTY channels */ - for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } - - /* assign system TTY channel (first free subchannel after each - * processor's individual TTY channel has been assigned) - */ - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - if( sc->uart == BRL1_LOCALHUB_UART ) { - static sc_cq_t x_iqp; - - subch->iqp = &x_iqp; - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - } - else { - /* we shouldn't be getting console input from remote UARTs */ - subch->iqp = &sc->garbage_q; - } - subch++; i++; - - /* "reserved" subchannels (0x05-0x0F); for now, throw away - * incoming packets - */ - for( ; i < 0x10; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } - - /* remaining subchannels are free */ - for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } -} - -static inline l1sc_t * -early_sc_init(nasid_t nasid) -{ - /* This is for early I/O */ - if ( Early_console_inited == 0 ) { - early_brl1_init(&Early_console, nasid, BRL1_LOCALHUB_UART); - Early_console_inited = 1; - } - return(&Early_console); -} - -#define PUTCHAR(ch) \ - { \ - while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ - (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ - WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ - } - -static int -early_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state ) -{ - int ret, sent = 0; - char *msg = str; - static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state ); - - while ( sent < len ) { - ret = early_l1_send(nasid, msg, len - sent, lock_state); - sent += ret; - msg += ret; - } - return(len); -} - -static inline int -early_l1_send( nasid_t nasid, char *str, int len, int lock_state ) -{ - int sent; - char crc_char; - unsigned short crc = INIT_CRC; - - if( len > (BRL1_QSIZE - 1) ) - len = (BRL1_QSIZE - 1); - - sent = len; - if ( lock_state == NOT_LOCKED ) - lock_console(nasid); - - PUTCHAR( BRL1_FLAG_CH ); - PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); - crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) ); - - while( len ) { - - if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) { - PUTCHAR( BRL1_ESC_CH ); - PUTCHAR( (*str) ^ BRL1_XOR_CH ); - } - else { - PUTCHAR( *str ); - } - - crc = crc16_calc( crc, *str ); - - str++; len--; - } - - crc ^= 0xffff; - crc_char = crc & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - crc_char = (crc >> 8) & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - PUTCHAR( BRL1_FLAG_CH ); - - if ( lock_state == NOT_LOCKED ) - unlock_console(nasid); - return sent; -} - -/********************************************************************* - * l1_cons functions - * - * These allow the L1 to act as the system console. They're intended - * to abstract away most of the br/l1 internal details from the - * _L1_cons_* functions (in the prom-- see "l1_console.c") and - * l1_* functions (in the kernel-- see "sio_l1.c") that they support. - * - */ - -static int -l1_poll( l1sc_t *sc, int mode ) -{ - int ret; - - /* in case this gets called before the l1sc_t structure for the module_t - * struct for this node is initialized (i.e., if we're called with a - * zero l1sc_t pointer)... - */ - - - if( !sc ) { - return 0; - } - - if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { - return 1; - } - - ret = brl1_receive( sc, mode ); - if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) - L1_collectibles[L1C_REC_STALLS] = ret; - - if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { - return 1; - } - return 0; -} - - -/* pull a character off of the system console queue (if one is available) - */ -static int -l1_getc( l1sc_t *sc, int mode ) -{ - unsigned long pl = 0; - int c; - - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - sc_cq_t *q = subch->iqp; - - if( !l1_poll( sc, mode ) ) { - return 0; - } - - SUBCH_DATA_LOCK( subch, pl ); - if( cq_empty( q ) ) { - atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch, pl ); - return 0; - } - cq_rem( q, c ); - if( cq_empty( q ) ) - atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch, pl ); - - return c; -} - -/* - * Write a message to the L1 on the system console subchannel. - * - * Danger: don't use a non-zero value for the wait parameter unless you're - * someone important (like a kernel error message). - */ - -int -l1_write( l1sc_t *sc, char *msg, int len, int wait ) -{ - int sent = 0, ret = 0; - - if ( wait ) { - while ( sent < len ) { - ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); - sent += ret; - msg += ret; - } - ret = len; - } - else { - ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); - } - return(ret); -} - -/* initialize the system console subchannel - */ -void -l1_init(void) -{ - /* All we do now is remember that we have been called */ - L1_cons_is_inited = 1; -} - - -/********************************************************************* - * The following functions and definitions implement the "message"- - * style interface to the L1 system controller. - * - * Note that throughout this file, "sc" generally stands for "system - * controller", while "subchannels" tend to be represented by - * variables with names like subch or ch. - * - */ - -#ifdef L1_DEBUG -#define L1_DBG_PRF(x) printf x -#else -#define L1_DBG_PRF(x) -#endif - -/* - * sc_data_ready is called to signal threads that are blocked on l1 input. - */ -void -sc_data_ready( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - - brl1_sch_t *subch = &(sc->subch[ch]); - SUBCH_DATA_LOCK( subch, pl ); - sv_signal( &(subch->arrive_sv) ); - SUBCH_DATA_UNLOCK( subch, pl ); -} - -/* sc_open reserves a subchannel to send a request to the L1 (the - * L1's response will arrive on the same channel). The number - * returned by sc_open is the system controller subchannel - * acquired. - */ -int -sc_open( l1sc_t *sc, uint target ) -{ - /* The kernel version implements a locking scheme to arbitrate - * subchannel assignment. - */ - int ch; - unsigned long pl = 0; - brl1_sch_t *subch; - - SUBCH_LOCK( sc, pl ); - - /* Look for a free subchannel. Subchannels 0-15 are reserved - * for other purposes. - */ - for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; - ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) { - if( subch->use == BRL1_SUBCH_FREE ) - break; - } - - if( ch == BRL1_NUM_SUBCHANS ) { - /* there were no subchannels available! */ - SUBCH_UNLOCK( sc, pl ); - return SC_NSUBCH; - } - - subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); - - atomic_set(&subch->packet_arrived, 0); - subch->target = target; - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); - subch->tx_notify = NULL; - subch->rx_notify = sc_data_ready; - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, - NASID_TO_COMPACT_NODEID(sc->nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - - return ch; -} - - -/* sc_close frees a Bedrock<->L1 subchannel. - */ -int -sc_close( l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - brl1_sch_t *subch; - - SUBCH_LOCK( sc, pl ); - subch = &(sc->subch[ch]); - if( subch->use != BRL1_SUBCH_RSVD ) { - /* we're trying to close a subchannel that's not open */ - SUBCH_UNLOCK( sc, pl ); - return SC_NOPEN; - } - - atomic_set(&subch->packet_arrived, 0); - subch->use = BRL1_SUBCH_FREE; - - sv_broadcast( &(subch->arrive_sv) ); - sv_destroy( &(subch->arrive_sv) ); - spin_lock_destroy( &(subch->data_lock) ); - - ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); - snia_kmem_free( subch->iqp, sizeof(sc_cq_t) ); - subch->iqp = &sc->garbage_q; - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - - SUBCH_UNLOCK( sc, pl ); - - return SC_SUCCESS; -} - - -/* sc_construct_msg builds a bedrock-to-L1 request in the supplied - * buffer. Returns the length of the message. The - * safest course when passing a buffer to be filled in is to use - * BRL1_QSIZE as the buffer size. - * - * Command arguments are passed as type/argument pairs, i.e., to - * pass the number 5 as an argument to an L1 command, call - * sc_construct_msg as follows: - * - * char msg[BRL1_QSIZE]; - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 2, - * L1_ARG_INT, 5 ); - * - * To pass an additional ASCII argument, you'd do the following: - * - * char *str; - * ... str points to a null-terminated ascii string ... - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 4, - * L1_ARG_INT, 5, - * L1_ARG_ASCII, str ); - * - * Finally, arbitrary data of unknown type is passed using the argtype - * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g. - * - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 3, - * L1_ARG_UNKNOWN, 32, bufptr ); - * - * ...passes 32 bytes of data starting at bufptr. Note that no string or - * "unknown"-type argument should be long enough to overflow the message - * buffer. - * - * To construct a message for an L1 command that requires no arguments, - * you'd use the following: - * - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 0 ); - * - * The final 0 means "no varargs". Notice that this parameter is used to hold - * the number of additional arguments to sc_construct_msg, _not_ the actual - * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII] - * type argument, and 3 per L1_ARG_UNKOWN type argument). A call to construct - * an L1 command which required three integer arguments and two arguments of - * some arbitrary (unknown) type would pass 12 as the value for this parameter. - * - * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth - * between byte arrays and four-byte big-endian integers. Depending on the - * system controller connection and endianness of future architectures, some - * rewriting might be necessary. - */ -int -sc_construct_msg( l1sc_t *sc, /* system controller struct */ - int ch, /* subchannel for this message */ - char *msg, /* message buffer */ - int msg_len, /* size of message buffer */ - l1addr_t addr_task, /* target system controller task */ - short req_code, /* 16-bit request code */ - int req_nargs, /* # of arguments (varargs) passed */ - ... ) /* any additional parameters */ -{ - uint32_t buf32; /* 32-bit buffer used to bounce things around */ - void *bufptr; /* used to hold command argument addresses */ - va_list al; /* variable argument list */ - int index; /* current index into msg buffer */ - int argno; /* current position in varargs list */ - int l1_argno; /* running total of arguments to l1 */ - int l1_arg_t; /* argument type/length */ - int l1_argno_byte; /* offset of argument count byte */ - - index = argno = 0; - - /* set up destination address */ - if( (msg_len -= sizeof( buf32 )) < 0 ) - return -1; - L1_ADDRESS_TO_TASK( &buf32, sc->subch[ch].target, addr_task ); - COPY_INT_TO_BUFFER(msg, index, buf32); - - /* copy request code */ - if( (msg_len -= 2) < 0 ) - return( -1 ); - msg[index++] = ((req_code >> 8) & 0xff); - msg[index++] = (req_code & 0xff); - - if( !req_nargs ) { - return index; - } - - /* reserve a byte for the argument count */ - if( (msg_len -= 1) < 0 ) - return( -1 ); - l1_argno_byte = index++; - l1_argno = 0; - - /* copy additional arguments */ - va_start( al, req_nargs ); - while( argno < req_nargs ) { - l1_argno++; - l1_arg_t = va_arg( al, int ); argno++; - switch( l1_arg_t ) - { - case L1_ARG_INT: - if( (msg_len -= (sizeof( buf32 ) + 1)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_INT; - buf32 = (unsigned)va_arg( al, int ); argno++; - COPY_INT_TO_BUFFER(msg, index, buf32); - break; - - case L1_ARG_ASCII: - bufptr = va_arg( al, char* ); argno++; - if( (msg_len -= (strlen( bufptr ) + 2)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_ASCII; - strcpy( (char *)&(msg[index]), (char *)bufptr ); - index += (strlen( bufptr ) + 1); /* include terminating null */ - break; - - case L1_ARG_UNKNOWN: - { - int arglen; - - arglen = va_arg( al, int ); argno++; - bufptr = va_arg( al, void* ); argno++; - if( (msg_len -= (arglen + 1)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_UNKNOWN | arglen; - BCOPY( bufptr, &(msg[index]), arglen ); - index += arglen; - break; - } - - default: /* unhandled argument type */ - return -1; - } - } - - va_end( al ); - msg[l1_argno_byte] = l1_argno; - - return index; -} - - - -/* sc_interpret_resp verifies an L1 response to a bedrock request, and - * breaks the response data up into the constituent parts. If the - * response message indicates error, or if a mismatch is found in the - * expected number and type of arguments, an error is returned. The - * arguments to this function work very much like the arguments to - * sc_construct_msg, above, except that L1_ARG_INTs must be followed - * by a _pointer_ to an integer that can be filled in by this function. - */ -int -sc_interpret_resp( char *resp, /* buffer received from L1 */ - int resp_nargs, /* number of _varargs_ passed in */ - ... ) -{ - uint32_t buf32; /* 32-bit buffer used to bounce things around */ - void *bufptr; /* used to hold response field addresses */ - va_list al; /* variable argument list */ - int index; /* current index into response buffer */ - int argno; /* current position in varargs list */ - int l1_fldno; /* number of resp fields received from l1 */ - int l1_fld_t; /* field type/length */ - - index = argno = 0; - -#if defined(L1_DEBUG) -#define DUMP_RESP \ - { \ - int ix; \ - char outbuf[512]; \ - sprintf( outbuf, "sc_interpret_resp error line %d: ", __LINE__ ); \ - for( ix = 0; ix < 16; ix++ ) { \ - sprintf( &outbuf[strlen(outbuf)], "%x ", resp[ix] ); \ - } \ - printk( "%s\n", outbuf ); \ - } -#else -#define DUMP_RESP -#endif /* L1_DEBUG */ - - /* check response code */ - COPY_BUFFER_TO_INT(resp, index, buf32); - if( buf32 != L1_RESP_OK ) { - DUMP_RESP; - return buf32; - } - - /* get number of response fields */ - l1_fldno = resp[index++]; - - va_start( al, resp_nargs ); - - /* copy out response fields */ - while( argno < resp_nargs ) { - l1_fldno--; - l1_fld_t = va_arg( al, int ); argno++; - switch( l1_fld_t ) - { - case L1_ARG_INT: - if( resp[index++] != L1_ARG_INT ) { - /* type mismatch */ - va_end( al ); - DUMP_RESP; - return -1; - } - bufptr = va_arg( al, int* ); argno++; - COPY_BUFFER_TO_BUFFER(resp, index, bufptr); - break; - - case L1_ARG_ASCII: - if( resp[index++] != L1_ARG_ASCII ) { - /* type mismatch */ - va_end( al ); - DUMP_RESP; - return -1; - } - bufptr = va_arg( al, char* ); argno++; - strcpy( (char *)bufptr, (char *)&(resp[index]) ); - /* include terminating null */ - index += (strlen( &(resp[index]) ) + 1); - break; - - default: - if( (l1_fld_t & L1_ARG_UNKNOWN) == L1_ARG_UNKNOWN ) - { - int *arglen; - - arglen = va_arg( al, int* ); argno++; - bufptr = va_arg( al, void* ); argno++; - *arglen = ((resp[index++] & ~L1_ARG_UNKNOWN) & 0xff); - BCOPY( &(resp[index]), bufptr, *arglen ); - index += (*arglen); - } - - else { - /* unhandled type */ - va_end( al ); - DUMP_RESP; - return -1; - } - } - } - va_end( al ); - - if( (l1_fldno != 0) || (argno != resp_nargs) ) { - /* wrong number of arguments */ - DUMP_RESP; - return -1; - } - return 0; -} - -/* sc_send takes as arguments a system controller struct, a - * buffer which contains a Bedrock<->L1 "request" message, - * the message length, and the subchannel (presumably obtained - * from an earlier invocation of sc_open) over which the - * message is to be sent. The final argument ("wait") indicates - * whether the send is to be performed synchronously or not. - * - * sc_send returns either zero or an error value. Synchronous sends - * (wait != 0) will not return until the data has actually been sent - * to the UART. Synchronous sends generally receive privileged - * treatment. The intent is that they be used sparingly, for such - * purposes as kernel printf's (the "ducons" routines). Run-of-the-mill - * console output and L1 requests should NOT use a non-zero value - * for wait. - */ -int -sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait ) -{ - char type_and_subch; - int result; - - if( (ch < 0) || ( ch >= BRL1_NUM_SUBCHANS) ) { - return SC_BADSUBCH; - } - - /* Verify that this is an open subchannel - */ - if( sc->subch[ch].use == BRL1_SUBCH_FREE ) { - return SC_NOPEN; - } - - type_and_subch = (BRL1_REQUEST | ((u_char)ch)); - result = brl1_send( sc, msg, len, type_and_subch, wait ); - - /* If we sent as much as we asked to, return "ok". */ - if( result == len ) - return( SC_SUCCESS ); - - /* Or, if we sent less, than either the UART is busy or - * we're trying to send too large a packet anyway. - */ - else if( result >= 0 && result < len ) - return( SC_BUSY ); - - /* Or, if something else went wrong (result < 0), then - * return that error value. - */ - else - return( result ); -} - -/* subch_pull_msg pulls a message off the receive queue for subch - * and places it the buffer pointed to by msg. This routine should only - * be called when the caller already knows a message is available on the - * receive queue (and, in the kernel, only when the subchannel data lock - * is held by the caller). - */ -static void -subch_pull_msg( brl1_sch_t *subch, char *msg, int *len ) -{ - sc_cq_t *q; /* receive queue */ - int before_wrap, /* packet may be split into two different */ - after_wrap; /* pieces to acommodate queue wraparound */ - - /* pull message off the receive queue */ - q = subch->iqp; - - cq_rem( q, *len ); /* remove length byte and store */ - cq_discard( q ); /* remove type/subch byte and discard */ - - if ( *len > 0 ) - (*len)--; /* don't count type/subch byte in length returned */ - - if( (q->opos + (*len)) > BRL1_QSIZE ) { - before_wrap = BRL1_QSIZE - q->opos; - after_wrap = (*len) - before_wrap; - } - else { - before_wrap = (*len); - after_wrap = 0; - } - - BCOPY( q->buf + q->opos, msg, before_wrap ); - if( after_wrap ) { - BCOPY( q->buf, msg + before_wrap, after_wrap ); - q->opos = after_wrap; - } - else { - q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1)); - } - atomic_dec(&(subch->packet_arrived)); -} - - -/* sc_recv_poll can be called as a blocking or non-blocking function; - * it attempts to pull a message off of the subchannel specified - * in the argument list (ch). - * - * The "block" argument, if non-zero, is interpreted as a timeout - * delay (to avoid permanent waiting). - */ - -int -sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) -{ - int is_msg = 0; - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - rtc_time_t exp_time = rtc_time() + block; - - /* sanity check-- make sure this is an open subchannel */ - if( subch->use == BRL1_SUBCH_FREE ) - return( SC_NOPEN ); - - do { - - /* kick the next lower layer and see if it pulls anything in - */ - brl1_receive( sc, SERIAL_POLLED_MODE ); - is_msg = atomic_read(&subch->packet_arrived); - - } while( block && !is_msg && (rtc_time() < exp_time) ); - - if( !is_msg ) { - /* no message and we didn't care to wait for one */ - return( SC_NMSG ); - } - - SUBCH_DATA_LOCK( subch, pl ); - subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); - - return( SC_SUCCESS ); -} - - -/* Like sc_recv_poll, sc_recv_intr can be called in either a blocking - * or non-blocking mode. Rather than polling until an appointed timeout, - * however, sc_recv_intr sleeps on a syncrhonization variable until a - * signal from the lower layer tells us that a packet has arrived. - * - * sc_recv_intr can't be used with remote (router) L1s. - */ -int -sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) -{ - int is_msg = 0; - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - do { - SUBCH_DATA_LOCK(subch, pl); - is_msg = atomic_read(&subch->packet_arrived); - if( !is_msg && block ) { - /* wake me when you've got something */ - subch->rx_notify = sc_data_ready; - sv_wait( &(subch->arrive_sv), 0, 0); - if( subch->use == BRL1_SUBCH_FREE ) { - /* oops-- somebody closed our subchannel while we were - * sleeping! - */ - - /* no need to unlock since the channel's closed anyhow */ - return( SC_NOPEN ); - } - } - } while( !is_msg && block ); - - if( !is_msg ) { - /* no message and we didn't care to wait for one */ - SUBCH_DATA_UNLOCK( subch, pl ); - return( SC_NMSG ); - } - - subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); - - return( SC_SUCCESS ); -} - -/* sc_command implements a (blocking) combination of sc_send and sc_recv. - * It is intended to be the SN1 equivalent of SN0's "elsc_command", which - * issued a system controller command and then waited for a response from - * the system controller before returning. - * - * cmd points to the outgoing command; resp points to the buffer in - * which the response is to be stored. Both buffers are assumed to - * be the same length; if there is any doubt as to whether the - * response buffer is long enough to hold the L1's response, then - * make it BRL1_QSIZE bytes-- no Bedrock<->L1 message can be any - * bigger. - * - * Be careful using the same buffer for both cmd and resp; it could get - * hairy if there were ever an L1 command reqeuest that spanned multiple - * packets. (On the other hand, that would require some additional - * rewriting of the L1 command interface anyway.) - */ -#define __RETRIES 50 -#define __WAIT_SEND 1 // ( sc->uart != BRL1_LOCALHUB_UART ) -#define __WAIT_RECV 10000000 - - -int -sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) -{ - int result; - int retries; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return SC_NMSG; - - retries = __RETRIES; - - while( (result = sc_send( sc, ch, cmd, *len, __WAIT_SEND )) < 0 ) { - if( result == SC_BUSY ) { - retries--; - if( retries <= 0 ) - return result; - uart_delay(500); - } - else { - return result; - } - } - - /* block on sc_recv_* */ - if( (sc->uart == BRL1_LOCALHUB_UART) && L1_interrupts_connected ) { - return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) ); - } - else { - return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); - } -} - -/* sc_command_kern is a knuckle-dragging, no-patience version of sc_command - * used in situations where the kernel has a command that shouldn't be - * delayed until the send buffer clears. sc_command should be used instead - * under most circumstances. - */ - -int -sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) -{ - int result; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return SC_NMSG; - - if( (result = sc_send( sc, ch, cmd, *len, 1 )) < 0 ) { - return result; - } - - return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); -} - - - -/* sc_poll checks the queue corresponding to the given - * subchannel to see if there's anything available. If - * not, it kicks the brl1 layer and then checks again. - * - * Returns 1 if input is available on the given queue, - * 0 otherwise. - */ - -int -sc_poll( l1sc_t *sc, int ch ) -{ - brl1_sch_t *subch = &(sc->subch[ch]); - - if( atomic_read(&subch->packet_arrived) ) - return 1; - - brl1_receive( sc, SERIAL_POLLED_MODE ); - - if( atomic_read(&subch->packet_arrived) ) - return 1; - - return 0; -} - -/* for now, sc_init just calls brl1_init */ - -void -sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - if ( !IS_RUNNING_ON_SIMULATOR() ) - brl1_init( sc, nasid, uart ); -} - -/* sc_dispatch_env_event handles events sent from the system control - * network's environmental monitor tasks. - */ - -#if defined(LINUX_KERNEL_THREADS) - -static void -sc_dispatch_env_event( uint code, int argc, char *args, int maxlen ) -{ - int j, i = 0; - uint32_t ESPcode; - - switch( code ) { - /* for now, all codes do the same thing: grab two arguments - * and print a cmn_err_tag message */ - default: - /* check number of arguments */ - if( argc != 2 ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected 2 arguments, got %d\n", argc )); - return; - } - - /* get ESP code (integer argument) */ - if( args[i++] != L1_ARG_INT ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected integer argument\n" )); - return; - } - /* WARNING: highly endian */ - COPY_BUFFER_TO_INT(args, i, ESPcode); - - /* verify string argument */ - if( args[i++] != L1_ARG_ASCII ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected an ASCII string\n" )); - return; - } - for( j = i; j < maxlen; j++ ) { - if( args[j] == '\0' ) break; /* found string termination */ - } - if( j == maxlen ) { - j--; - L1_DBG_PRF(( "sc_dispatch_env_event: " - "message too long-- truncating\n" )); - } - - /* strip out trailing cr/lf */ - for( ; - j > 1 && ((args[j-1] == 0xd) || (args[j-1] == 0xa)); - j-- ); - args[j] = '\0'; - - /* strip out leading cr/lf */ - for( ; - i < j && ((args[i] == 0xd) || (args[i] == 0xa)); - i++ ); - } -} - - -/* sc_event waits for events to arrive from the system controller, and - * prints appropriate messages to the syslog. - */ - -static void -sc_event( l1sc_t *sc, int ch ) -{ - char event[BRL1_QSIZE]; - int i; - int result; - int event_len; - uint32_t ev_src; - uint32_t ev_code; - int ev_argc; - - while(1) { - - bzero( event, BRL1_QSIZE ); - - /* - * wait for an event - */ - result = sc_recv_intr( sc, ch, event, &event_len, 1 ); - if( result != SC_SUCCESS ) { - printk(KERN_WARNING "Error receiving sysctl event on nasid %d\n", - sc->nasid ); - } - else { - /* - * an event arrived; break it down into useful pieces - */ -#if defined(L1_DEBUG) && 0 - int ix; - printf( "Event packet received:\n" ); - for (ix = 0; ix < 64; ix++) { - printf( "%x%x ", ((event[ix] >> 4) & ((uint64_t)0xf)), - (event[ix] & ((uint64_t)0xf)) ); - if( (ix % 16) == 0xf ) printf( "\n" ); - } -#endif /* L1_DEBUG */ - - i = 0; - - /* get event source */ - COPY_BUFFER_TO_INT(event, i, ev_src); - COPY_BUFFER_TO_INT(event, i, ev_code); - - /* get arg count */ - ev_argc = (event[i++] & 0xffUL); - - /* dispatch events by task */ - switch( (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT ) - { - case L1_ADDR_TASK_ENV: /* environmental monitor event */ - sc_dispatch_env_event( ev_code, ev_argc, &(event[i]), - BRL1_QSIZE - i ); - break; - - default: /* unhandled task type */ - L1_DBG_PRF(( "Unhandled event type received from system " - "controllers: source task %x\n", - (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT - )); - } - } - - } -} - -/* sc_listen sets up a service thread to listen for incoming events. - */ - -void -sc_listen( l1sc_t *sc ) -{ - int result; - unsigned long pl = 0; - brl1_sch_t *subch; - - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int ch; /* system controller subchannel used */ - - extern int msc_shutdown_pri; - - /* grab the designated "event subchannel" */ - SUBCH_LOCK( sc, pl ); - subch = &(sc->subch[BRL1_EVENT_SUBCH]); - if( subch->use != BRL1_SUBCH_FREE ) { - SUBCH_UNLOCK( sc, pl ); - printk(KERN_WARNING "sysctl event subchannel in use! " - "Not monitoring sysctl events.\n" ); - return; - } - subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); - - atomic_set(&subch->packet_arrived, 0); - subch->target = BRL1_LOCALHUB_UART; - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); - subch->tx_notify = NULL; - subch->rx_notify = sc_data_ready; - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, - NASID_TO_COMPACT_NODEID(sc->nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - - /* set up a thread to listen for events */ - sthread_create( "sysctl event handler", 0, 0, 0, msc_shutdown_pri, - KT_PS, (st_func_t *) sc_event, - (void *)sc, (void *)(uint64_t)BRL1_EVENT_SUBCH, 0, 0 ); - - /* signal the L1 to begin sending events */ - bzero( msg, BRL1_QSIZE ); - ch = sc_open( sc, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( sc, ch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EVENT_SUBCH, 2, - L1_ARG_INT, BRL1_EVENT_SUBCH )) < 0 ) - { - sc_close( sc, ch ); - L1_DBG_PRF(( "Failure in sc_construct_msg (%d)\n", len )); - goto err_return; - } - - result = sc_command_kern( sc, ch, msg, msg, &len ); - if( result < 0 ) - { - sc_close( sc, ch ); - L1_DBG_PRF(( "Failure in sc_command_kern (%d)\n", result )); - goto err_return; - } - - sc_close( sc, ch ); - - result = sc_interpret_resp( msg, 0 ); - if( result < 0 ) - { - L1_DBG_PRF(( "Failure in sc_interpret_resp (%d)\n", result )); - goto err_return; - } - - /* everything went fine; just return */ - return; - -err_return: - /* there was a problem; complain */ - printk(KERN_WARNING "failed to set sysctl event-monitoring subchannel. " - "Sysctl events will not be monitored.\n" ); -} - -#endif /* LINUX_KERNEL_THREADS */ diff -Nur linux-2.4.19/arch/ia64/sn/io/l1_command.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/l1_command.c --- linux-2.4.19/arch/ia64/sn/io/l1_command.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/l1_command.c Wed Dec 31 16:00:00 1969 @@ -1,1378 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc. - * All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ -#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ - -#define LD(x) (*(volatile uint64_t *)(x)) -#define SD(x, v) (LD(x) = (uint64_t) (v)) - -#define hub_cpu_get() 0 - -#define LBYTE(caddr) (*(char *) caddr) - -extern char *bcopy(const char * src, char * dest, int count); - -#define LDEBUG 0 - -/* - * ELSC data is in NVRAM page 7 at the following offsets. - */ - -#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */ -#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */ -#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */ -#define NVRAM_DBG2 0x706 /* physical XOR debug switches */ -#define NVRAM_CFG 0x707 /* ELSC Configuration info */ -#define NVRAM_MODULE 0x708 /* system module number */ -#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */ -#define NVRAM_PARTITION 0x70a /* module's partition id */ -#define NVRAM_DOMAIN 0x70b /* module's domain id */ -#define NVRAM_CLUSTER 0x70c /* module's cluster id */ -#define NVRAM_CELL 0x70d /* module's cellid */ - -#define NVRAM_MAGIC_NO 0x37 /* value of magic number */ -#define NVRAM_SIZE 16 /* 16 bytes in nvram */ - -/* - * Declare a static ELSC NVRAM buffer to hold all data read from - * and written to NVRAM. This nvram "cache" will be used only during the - * IP27prom execution. - */ -static char elsc_nvram_buffer[NVRAM_SIZE]; - -#define SC_COMMAND sc_command - -/* - * elsc_init - * - * Initialize ELSC structure - */ - -void elsc_init(elsc_t *e, nasid_t nasid) -{ - sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART); -} - - -/* - * elsc_errmsg - * - * Given a negative error code, - * returns a corresponding static error string. - */ - -char *elsc_errmsg(int code) -{ - switch (code) { - case ELSC_ERROR_CMD_SEND: - return "Command send error"; - case ELSC_ERROR_CMD_CHECKSUM: - return "Command packet checksum error"; - case ELSC_ERROR_CMD_UNKNOWN: - return "Unknown command"; - case ELSC_ERROR_CMD_ARGS: - return "Invalid command argument(s)"; - case ELSC_ERROR_CMD_PERM: - return "Permission denied"; - case ELSC_ERROR_RESP_TIMEOUT: - return "System controller response timeout"; - case ELSC_ERROR_RESP_CHECKSUM: - return "Response packet checksum error"; - case ELSC_ERROR_RESP_FORMAT: - return "Response format error"; - case ELSC_ERROR_RESP_DIR: - return "Response direction error"; - case ELSC_ERROR_MSG_LOST: - return "Message lost because queue is full"; - case ELSC_ERROR_LOCK_TIMEOUT: - return "Timed out getting ELSC lock"; - case ELSC_ERROR_DATA_SEND: - return "Error sending data"; - case ELSC_ERROR_NIC: - return "NIC protocol error"; - case ELSC_ERROR_NVMAGIC: - return "Bad magic number in NVRAM"; - case ELSC_ERROR_MODULE: - return "Module location protocol error"; - default: - return "Unknown error"; - } -} - -/* - * elsc_nvram_init - * - * Initializes reads and writes to NVRAM. This will perform a single - * read to NVRAM, getting all data at once. When the PROM tries to - * read NVRAM, it returns the data from the buffer being read. If the - * PROM tries to write out to NVRAM, the write is done, and the internal - * buffer is updated. - */ - -void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data) -{ - /* This might require implementation of multiple-packet request/responses - * if it's to provide the same behavior that was available in SN0. - */ - nasid = nasid; - elsc_nvram_data = elsc_nvram_data; -} - -/* - * elsc_nvram_copy - * - * Copies the content of a buffer into the static buffer in this library. - */ - -void elsc_nvram_copy(uchar_t *elsc_nvram_data) -{ - memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE); -} - -/* - * elsc_nvram_write - * - * Copies bytes from 'buf' into NVRAM, starting at NVRAM address - * 'addr' which must be between 0 and 2047. - * - * If 'len' is non-negative, the routine copies 'len' bytes. - * - * If 'len' is negative, the routine treats the data as a string and - * copies bytes up to and including a NUL-terminating zero, but not - * to exceed '-len' bytes. - */ - -int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len) -{ - /* Here again, we might need to work out the details of a - * multiple-packet protocol. - */ - - /* For now, pretend it worked. */ - e = e; - addr = addr; - buf = buf; - return (len < 0 ? -len : len); -} - -/* - * elsc_nvram_read - * - * Copies bytes from NVRAM into 'buf', starting at NVRAM address - * 'addr' which must be between 0 and 2047. - * - * If 'len' is non-negative, the routine copies 'len' bytes. - * - * If 'len' is negative, the routine treats the data as a string and - * copies bytes up to and including a NUL-terminating zero, but not - * to exceed '-len' bytes. NOTE: This method is no longer supported. - * It was never used in the first place. - */ - -int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len) -{ - /* multiple packets? */ - e = e; - addr = addr; - buf = buf; - len = len; - return -1; -} - - -/* - * Command Set - */ - -int elsc_version(elsc_t *e, char *result) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int major, /* major rev number */ - minor, /* minor rev number */ - bugfix; /* bugfix rev number */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_FW_REV, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, - L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) - < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - sprintf( result, "%d.%d.%d", major, minor, bugfix ); - - return 0; -} - -int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2) -{ - /* shush compiler */ - e = e; - byte1 = byte1; - byte2 = byte2; - - /* fill in a buffer with the opcode & params; call sc_command */ - - return 0; -} - -int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int dbg_sw; /* holds debug switch settings */ - int len; /* number of msg buffer bytes used */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RDBG, 0 ) ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* copy out debug switch settings (last two bytes of the - * integer response) - */ - *byte1 = ((dbg_sw >> 8) & 0xFF); - *byte2 = (dbg_sw & 0xFF); - - return 0; -} - - -/* - * elsc_rack_bay_get fills in the two int * arguments with the - * rack number and bay number of the L1 being addressed - */ -int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack/bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRACK, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - - /* send the request to the L1 */ - if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close(e, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - return 0; -} - - -/* elsc_rack_bay_type_get fills in the three int * arguments with the - * rack number, bay number and brick type of the L1 being addressed. Note - * that if the L1 operation fails and this function returns an error value, - * garbage may be written to brick_type. - */ -int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRBT, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, - L1_ARG_INT, brick_type ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - /* convert brick_type to lower case */ - *brick_type = *brick_type - 'A' + 'a'; - - return 0; -} - - -int elsc_module_get(elsc_t *e) -{ - extern char brick_types[]; - uint rnum, rack, bay, bricktype, t; - int ret; - - /* construct module ID from rack and slot info */ - - if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) { - return ret; - } - - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - for( t = 0; t < MAX_BRICK_TYPES; t++ ) { - if( brick_types[t] == bricktype ) - return RBT_TO_MODULE(rack, bay, t); - } - - return ELSC_ERROR_MODULE; -} - -int elsc_partition_set(elsc_t *e, int partition) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PARTITION_SET, 2, - L1_ARG_INT, partition )) < 0 ) - { - - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return( 0 ); -} - -int elsc_partition_get(elsc_t *e) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t partition_id; /* used to copy partition id out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PARTITION_GET, 0 )) < 0 ) - - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &partition_id ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return( partition_id ); -} - - -/* - * elsc_cons_subch selects the "active" console subchannel for this node - * (i.e., the one that will currently receive input) - */ -int elsc_cons_subch(elsc_t *e, uint ch) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_CONS_SUBCH, 2, - L1_ARG_INT, ch)) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* - * elsc_cons_node should only be executed by one node. It declares to - * the system controller that the node from which it is called will be - * the owner of the system console. - */ -int elsc_cons_node(elsc_t *e) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_CONS_NODE, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* elsc_display_line writes up to 12 characters to either the top or bottom - * line of the L1 display. line points to a buffer containing the message - * to be displayed. The zero-based line number is specified by lnum (so - * lnum == 0 specifies the top line and lnum == 1 specifies the bottom). - * Lines longer than 12 characters, or line numbers not less than - * L1_DISPLAY_LINES, cause elsc_display_line to return an error. - */ -int elsc_display_line(elsc_t *e, char *line, int lnum) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int len; /* number of msg buffer bytes used */ - - /* argument sanity checking */ - if( !(lnum < L1_DISPLAY_LINES) ) - return( ELSC_ERROR_CMD_ARGS ); - if( !(strlen( line ) <= L1_DISPLAY_LINE_LENGTH) ) - return( ELSC_ERROR_CMD_ARGS ); - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - (L1_REQ_DISP1+lnum), 2, - L1_ARG_ASCII, line )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* elsc_display_mesg silently drops message characters beyond the 12th. - */ -int elsc_display_mesg(elsc_t *e, char *chr) -{ - - char line[L1_DISPLAY_LINE_LENGTH+1]; - int numlines, i; - int result; - - numlines = (strlen( chr ) + L1_DISPLAY_LINE_LENGTH - 1) / - L1_DISPLAY_LINE_LENGTH; - - if( numlines > L1_DISPLAY_LINES ) - numlines = L1_DISPLAY_LINES; - - for( i = 0; i < numlines; i++ ) - { - strncpy( line, chr, L1_DISPLAY_LINE_LENGTH ); - line[L1_DISPLAY_LINE_LENGTH] = '\0'; - - /* generally we want to leave the first line of the L1 display - * alone (so the L1 can manipulate it). If you need to be able - * to display to both lines (for debugging purposes), define - * L1_DISP_2LINES in irix/kern/ksys/l1.h, or add -DL1_DISP_2LINES - * to your 'defs file. - */ -#if defined(L1_DISP_2LINES) - if( (result = elsc_display_line( e, line, i )) < 0 ) -#else - if( (result = elsc_display_line( e, line, i+1 )) < 0 ) -#endif - - return result; - - chr += L1_DISPLAY_LINE_LENGTH; - } - - return 0; -} - - -int elsc_password_set(elsc_t *e, char *password) -{ - /* shush compiler */ - e = e; - password = password; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - -int elsc_password_get(elsc_t *e, char *password) -{ - /* shush compiler */ - e = e; - password = password; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -/* - * sc_portspeed_get - * - * retrieve the current portspeed setting for the bedrock II - */ -int sc_portspeed_get(l1sc_t *sc) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int portspeed_a, portspeed_b; - /* ioport clock rates */ - - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PORTSPEED, - 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, - L1_ARG_INT, &portspeed_a, - L1_ARG_INT, &portspeed_b ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* for the c-brick, we ignore the portspeed_b value */ - return (portspeed_a ? 600 : 400); -} - -/* - * elsc_power_query - * - * To be used after system reset, this command returns 1 if the reset - * was the result of a power-on, 0 otherwise. - * - * The power query status is cleared to 0 after it is read. - */ - -int elsc_power_query(elsc_t *e) -{ - e = e; /* shush the compiler */ - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 1; -} - -int elsc_rpwr_query(elsc_t *e, int is_master) -{ - /* shush the compiler */ - e = e; - is_master = is_master; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - -/* - * elsc_power_down - * - * Sets up system to shut down in "sec" seconds (or modifies the - * shutdown time if one is already in effect). Use 0 to power - * down immediately. - */ - -int elsc_power_down(elsc_t *e, int sec) -{ - /* shush compiler */ - e = e; - sec = sec; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -int elsc_system_reset(elsc_t *e) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int len; /* number of msg buffer bytes used */ - int result; - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RESET, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( (result = sc_command( e, subch, msg, msg, &len )) ) { - sc_close( e, subch ); - if( result == SC_NMSG ) { - /* timeout is OK. We've sent the reset. Now it's just - * a matter of time... - */ - return( 0 ); - } - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -int elsc_power_cycle(elsc_t *e) -{ - /* shush compiler */ - e = e; - - /* fill in buffer with the opcode & params; call sc_command */ - - return 0; -} - - -/* - * L1 Support for reading - * cbrick uid. - */ - -int elsc_nic_get(elsc_t *e, uint64_t *nic, int verbose) -{ - /* this parameter included only for SN0 compatibility */ - verbose = verbose; - - /* We don't go straight to the bedrock/L1 protocol on this one, but let - * the eeprom layer prepare the eeprom data as we would like it to - * appear to the caller - */ - return cbrick_uid_get( e->nasid, nic ); -} - - -int _elsc_hbt(elsc_t *e, int ival, int rdly) -{ - e = e; - ival = ival; - rdly = rdly; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -/* send a command string to an L1 */ -int sc_command_interp( l1sc_t *sc, l1addr_t compt, l1addr_t rack, l1addr_t bay, - char *cmd ) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - l1addr_t target; /* target system controller for command */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - - L1_BUILD_ADDR( &target, compt, rack, bay, 0 ); - subch = sc_open( sc, target ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2, - L1_ARG_ASCII, cmd )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - -/* - * sc_power_down - * - * Shuts down the c-brick associated with sc, and any attached I/O bricks - * or other c-bricks (won't go through r-bricks). - */ - -int sc_power_down(l1sc_t *sc) -{ - return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, - L1_ADDR_BAY_LOCAL, "* pwr d" ); -} - - -/* - * sc_power_down_all - * - * Works similarly to sc_power_down, except that the request is sent to the - * closest L2 and EVERYBODY gets turned off. - */ - -int sc_power_down_all(l1sc_t *sc) -{ - if( nodepda->num_routers > 0 ) { - return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, - L1_ADDR_BAY_LOCAL, "* pwr d" ); - } - else { - return sc_power_down( sc ); - } -} - - -/* - * Routines for reading the R-brick's L1 - */ - -int router_module_get( nasid_t nasid, net_vec_t path ) -{ - uint rnum, rack, bay, t; - int ret; - l1sc_t sc; - - /* prepare l1sc_t struct */ - sc_init( &sc, nasid, path ); - - /* construct module ID from rack and slot info */ - - if ((ret = elsc_rack_bay_get(&sc, &rnum, &bay)) < 0) - return ret; - - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - ret = RBT_TO_MODULE(rack, bay, MODULE_RBRICK); - return ret; -} - - -/* - * iobrick routines - */ - -/* iobrick_rack_bay_type_get fills in the three int * arguments with the - * rack number, bay number and brick type of the L1 being addressed. Note - * that if the L1 operation fails and this function returns an error value, - * garbage may be written to brick_type. - */ -int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRBT, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, - L1_ARG_INT, brick_type ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - return 0; -} - - -int iobrick_module_get(l1sc_t *sc) -{ - uint rnum, rack, bay, brick_type, t; - int ret; - - /* construct module ID from rack and slot info */ - - if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0) - return ret; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - switch( brick_type ) { - case 'I': - brick_type = MODULE_IBRICK; break; - case 'P': - brick_type = MODULE_PBRICK; break; - case 'X': - brick_type = MODULE_XBRICK; break; - } - - ret = RBT_TO_MODULE(rack, bay, brick_type); - - return ret; -} - -/* iobrick_get_sys_snum asks the attached iobrick for the system - * serial number. This function will only be relevant to the master - * cbrick (the one attached to the bootmaster ibrick); other nodes - * may call the function, but the value returned to the master node - * will be the one used as the system serial number by the kernel. - */ - -int -iobrick_get_sys_snum( l1sc_t *sc, char *snum_str ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SYS_SERIAL, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - return( sc_interpret_resp( msg, 2, L1_ARG_ASCII, snum_str ) ); -} - - -/* - * The following functions apply (or cut off) power to the specified - * pci bus or slot. - */ - -int -iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code ) -{ -#if 0 /* The "bedrock request" method of performing this function - * seems to be broken in the L1, so for now use the command- - * interpreter method - */ - - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCALIO ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - req_code, 4, - L1_ARG_INT, bus, - L1_ARG_INT, slot )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; - -#else - char cmd[64]; - char *fxn; - - switch( req_code ) - { - case L1_REQ_PCI_UP: - fxn = "u"; - break; - case L1_REQ_PCI_DOWN: - fxn = "d"; - break; - case L1_REQ_PCI_RESET: - fxn = "rst"; - break; - default: - return( ELSC_ERROR_CMD_ARGS ); - } - - if( slot == -1 ) - sprintf( cmd, "pci %d %s", bus, fxn ); - else - sprintf( cmd, "pci %d %d %s", bus, slot, fxn ); - - return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK, - L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd ); -#endif -} - -int -iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) -{ - return iobrick_pci_pwr( sc, bus, slot, up ); -} - -int -iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ) -{ - return iobrick_pci_pwr( sc, bus, -1, up ); -} - - -int -iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot ) -{ - return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET ); -} - -int -iobrick_pci_bus_rst( l1sc_t *sc, int bus ) -{ - return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET ); -} - - -/* get the L1 firmware version for an iobrick */ -int -iobrick_sc_version( l1sc_t *sc, char *result ) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int major, /* major rev number */ - minor, /* minor rev number */ - bugfix; /* bugfix rev number */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCALIO ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_FW_REV, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, - L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) - < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - sprintf( result, "%d.%d.%d", major, minor, bugfix ); - - return 0; -} diff -Nur linux-2.4.19/arch/ia64/sn/io/labelcl.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/labelcl.c --- linux-2.4.19/arch/ia64/sn/io/labelcl.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/labelcl.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -275,7 +275,6 @@ if (!strcmp(info_name, old_label_list[i].name)) { /* Not allowed to add duplicate labelled info names. */ kfree(new_label_list); - printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, (void *)de); return(-1); } new_label_list[i] = old_label_list[i]; /* structure copy */ diff -Nur linux-2.4.19/arch/ia64/sn/io/ml_SN_init.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/ml_SN_init.c --- linux-2.4.19/arch/ia64/sn/io/ml_SN_init.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/ml_SN_init.c Wed Dec 31 16:00:00 1969 @@ -1,235 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int numcpus; -extern char arg_maxnodes[]; -extern cpuid_t master_procid; -#if defined(CONFIG_IA64_SGI_SN1) -extern synergy_da_t *Synergy_da_indr[]; -#endif - -extern int hasmetarouter; - -int maxcpus; -cpumask_t boot_cpumask; -hubreg_t region_mask = 0; - - -extern xwidgetnum_t hub_widget_id(nasid_t); - -extern int valid_icache_reasons; /* Reasons to flush the icache */ -extern int valid_dcache_reasons; /* Reasons to flush the dcache */ -extern u_char miniroot; -extern volatile int need_utlbmiss_patch; -extern void iograph_early_init(void); - -nasid_t master_nasid = INVALID_NASID; - - -/* - * mlreset(int slave) - * very early machine reset - at this point NO interrupts have been - * enabled; nor is memory, tlb, p0, etc setup. - * - * slave is zero when mlreset is called for the master processor and - * is nonzero thereafter. - */ - - -void -mlreset(int slave) -{ - if (!slave) { - /* - * We are the master cpu and node. - */ - master_nasid = get_nasid(); - set_master_bridge_base(); - - /* We're the master processor */ - master_procid = smp_processor_id(); - master_nasid = cpuid_to_nasid(master_procid); - - /* - * master_nasid we get back better be same as one from - * get_nasid() - */ - ASSERT_ALWAYS(master_nasid == get_nasid()); - - /* early initialization of iograph */ - iograph_early_init(); - - /* Initialize Hub Pseudodriver Management */ - hubdev_init(); - - } else { /* slave != 0 */ - /* - * This code is performed ONLY by slave processors. - */ - - } -} - - -/* XXX - Move the meat of this to intr.c ? */ -/* - * Set up the platform-dependent fields in the nodepda. - */ -void init_platform_nodepda(nodepda_t *npda, cnodeid_t node) -{ - hubinfo_t hubinfo; -#ifdef CONFIG_IA64_SGI_SN1 - int sn; -#endif - - extern void router_map_init(nodepda_t *); - extern void router_queue_init(nodepda_t *,cnodeid_t); - extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int); - - /* Allocate per-node platform-dependent data */ - hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s)); - - npda->pdinfo = (void *)hubinfo; - hubinfo->h_nodepda = npda; - hubinfo->h_cnodeid = node; - hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node); - - spin_lock_init(&hubinfo->h_crblock); - - hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); - npda->xbow_peer = INVALID_NASID; - - /* - * Initialize the linked list of - * router info pointers to the dependent routers - */ - npda->npda_rip_first = NULL; - - /* - * npda_rip_last always points to the place - * where the next element is to be inserted - * into the list - */ - npda->npda_rip_last = &npda->npda_rip_first; - npda->module_id = INVALID_MODULE; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Initialize the interrupts. - * On sn2, this is done at pci init time, - * because sn2 needs the cpus checked in - * when it initializes interrupts. This is - * so we don't see all the nodes as headless. - */ - for (sn=0; snxbow_sema); /* init it locked? */ - -#ifdef LATER - - /* Setup the (module,slot) --> nic mapping for all the routers - * in the system. This is useful during error handling when - * there is no shared memory. - */ - router_map_init(npda); - - /* Allocate memory for the per-node router traversal queue */ - router_queue_init(npda,node); - npda->sbe_info = alloc_bootmem_node(NODE_DATA(node), sizeof (sbe_info_t)); - ASSERT(npda->sbe_info); - -#endif /* LATER */ -} - -/* XXX - Move the interrupt stuff to intr.c ? */ -/* - * Set up the platform-dependent fields in the processor pda. - * Must be done _after_ init_platform_nodepda(). - * If we need a lock here, something else is wrong! - */ -void init_platform_pda(cpuid_t cpu) -{ -#if defined(CONFIG_IA64_SGI_SN1) - hub_intmasks_t *intmasks; - int i, subnode; - cnodeid_t cnode; - synergy_da_t *sda; - int which_synergy; - - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - intmasks = &sda->s_intmasks; - - /* Clear INT_PEND0 masks. */ - for (i = 0; i < N_INTPEND0_MASKS; i++) - intmasks->intpend0_masks[i] = 0; - - /* Set up pointer to the vector block in the nodepda. */ - /* (Cant use SUBNODEPDA - not working yet) */ - subnode = cpuid_to_subnode(cpu); - intmasks->dispatch0 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; - intmasks->dispatch1 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; - if (intmasks->dispatch0 != &SUBNODEPDA(cnode, subnode)->intr_dispatch0 || - intmasks->dispatch1 != &SUBNODEPDA(cnode, subnode)->intr_dispatch1) - panic("xxx"); - intmasks->dispatch0 = &SUBNODEPDA(cnode, subnode)->intr_dispatch0; - intmasks->dispatch1 = &SUBNODEPDA(cnode, subnode)->intr_dispatch1; - - /* Clear INT_PEND1 masks. */ - for (i = 0; i < N_INTPEND1_MASKS; i++) - intmasks->intpend1_masks[i] = 0; -#endif /* CONFIG_IA64_SGI_SN1 */ -} - -void -update_node_information(cnodeid_t cnodeid) -{ - nodepda_t *npda = NODEPDA(cnodeid); - nodepda_router_info_t *npda_rip; - - /* Go through the list of router info - * structures and copy some frequently - * accessed info from the info hanging - * off the corresponding router vertices - */ - npda_rip = npda->npda_rip_first; - while(npda_rip) { - if (npda_rip->router_infop) { - npda_rip->router_portmask = - npda_rip->router_infop->ri_portmask; - npda_rip->router_slot = - npda_rip->router_infop->ri_slotnum; - } else { - /* No router, no ports. */ - npda_rip->router_portmask = 0; - } - npda_rip = npda_rip->router_next; - } -} diff -Nur linux-2.4.19/arch/ia64/sn/io/ml_iograph.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/ml_iograph.c --- linux-2.4.19/arch/ia64/sn/io/ml_iograph.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/ml_iograph.c Wed Dec 31 16:00:00 1969 @@ -1,1570 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define IOGRAPH_DEBUG */ -#ifdef IOGRAPH_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* IOGRAPH_DEBUG */ - -/* #define PROBE_TEST */ - -/* At most 2 hubs can be connected to an xswitch */ -#define NUM_XSWITCH_VOLUNTEER 2 - -/* - * Track which hubs have volunteered to manage devices hanging off of - * a Crosstalk Switch (e.g. xbow). This structure is allocated, - * initialized, and hung off the xswitch vertex early on when the - * xswitch vertex is created. - */ -typedef struct xswitch_vol_s { - mutex_t xswitch_volunteer_mutex; - int xswitch_volunteer_count; - devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; -} *xswitch_vol_t; - -void -xswitch_vertex_init(devfs_handle_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); - mutex_init(&xvolinfo->xswitch_volunteer_mutex); - xvolinfo->xswitch_volunteer_count = 0; - rc = hwgraph_info_add_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t)xvolinfo); - ASSERT(rc == GRAPH_SUCCESS); rc = rc; -} - - -/* - * When assignment of hubs to widgets is complete, we no longer need the - * xswitch volunteer structure hanging around. Destroy it. - */ -static void -xswitch_volunteer_delete(devfs_handle_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - rc = hwgraph_info_remove_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); -#ifdef LATER - ASSERT(rc == GRAPH_SUCCESS); rc = rc; -#endif - - kfree(xvolinfo); -} -/* - * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. - */ -/* ARGSUSED */ -static void -volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) -{ - xswitch_vol_t xvolinfo = NULL; - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { -#ifdef LATER - if (!is_headless_node_vertex(master)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "volunteer for widgets: vertex %v has no info label", - xswitch); -#else - printk(KERN_WARNING "volunteer for widgets: vertex 0x%x has no info label", - xswitch); -#endif - } -#endif /* LATER */ - return; - } - - mutex_lock(&xvolinfo->xswitch_volunteer_mutex); - ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); - xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; - xvolinfo->xswitch_volunteer_count++; - mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); -} - -extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); - -/* - * Assign all the xwidgets hanging off the specified xswitch to the - * Crosstalk masters that have volunteered for xswitch duty. - */ -/* ARGSUSED */ -static void -assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) -{ - int curr_volunteer, num_volunteer; - xwidgetnum_t widgetnum; - xswitch_info_t xswitch_info; - xswitch_vol_t xvolinfo = NULL; - nasid_t nasid; - hubinfo_t hubinfo; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - xswitch_info = xswitch_info_get(xswitch); - ASSERT(xswitch_info != NULL); - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { -#ifdef LATER - if (!is_headless_node_vertex(hubv)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "assign_widgets_to_volunteers:vertex %v has " - " no info label", - xswitch); -#else - printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%x has " - " no info label", - xswitch); -#endif - } -#endif /* LATER */ - return; - } - - num_volunteer = xvolinfo->xswitch_volunteer_count; - ASSERT(num_volunteer > 0); - curr_volunteer = 0; - - /* Assign master hub for xswitch itself. */ - if (HUB_WIDGET_ID_MIN > 0) { - hubv = xvolinfo->xswitch_volunteer[0]; - xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); - } - - /* - * TBD: Use administrative information to alter assignment of - * widgets to hubs. - */ - for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - - /* - * Ignore disabled/empty ports. - */ - if (!xbow_port_io_enabled(nasid, widgetnum)) - continue; - - /* - * If this is the master IO board, assign it to the same - * hub that owned it in the prom. - */ - if (is_master_nasid_widget(nasid, widgetnum)) { - int i; - - for (i=0; ixswitch_volunteer[i]; - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - if (nasid == get_console_nasid()) - goto do_assignment; - } -#ifdef LATER - PRINT_PANIC("Nasid == %d, console nasid == %d", - nasid, get_console_nasid()); -#endif - } - - - /* - * Do a round-robin assignment among the volunteer nodes. - */ - hubv = xvolinfo->xswitch_volunteer[curr_volunteer]; - curr_volunteer = (curr_volunteer + 1) % num_volunteer; - /* fall through */ - -do_assignment: - /* - * At this point, we want to make hubv the master of widgetnum. - */ - xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); - } - - xswitch_volunteer_delete(xswitch); -} - -/* - * Early iograph initialization. Called by master CPU in mlreset(). - * Useful for including iograph.o in kernel.o. - */ -void -iograph_early_init(void) -{ -/* - * Need new way to get this information .. - */ - cnodeid_t cnode; - nasid_t nasid; - lboard_t *board; - - /* - * Init. the board-to-hwgraph link early, so FRU analyzer - * doesn't trip on leftover values if we panic early on. - */ - for(cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - board = (lboard_t *)KL_CONFIG_INFO(nasid); - DBG("iograph_early_init: Found board 0x%p\n", board); - - /* Check out all the board info stored on a node */ - while(board) { - board->brd_graph_link = GRAPH_VERTEX_NONE; - board = KLCF_NEXT(board); - DBG("iograph_early_init: Found board 0x%p\n", board); - - - } - } - - hubio_init(); -} - -#ifdef LINUX_KERNEL_THREADS -static struct semaphore io_init_sema; -#endif - -/* - * Let boot processor know that we're done initializing our node's IO - * and then exit. - */ -/* ARGSUSED */ -static void -io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) -{ - /* Let boot processor know that we're done. */ -#ifdef LINUX_KERNEL_THREADS - up(&io_init_sema); -#endif -#ifdef LATER - /* This is for the setnoderun done when the io_init thread - * started - */ - restorenoderun(c); - sthread_exit(); -#endif -} - -/* - * Probe to see if this hub's xtalk link is active. If so, - * return the Crosstalk Identification of the widget that we talk to. - * This is called before any of the Crosstalk infrastructure for - * this hub is set up. It's usually called on the node that we're - * probing, but not always. - * - * TBD: Prom code should actually do this work, and pass through - * hwid for our use. - */ -static void -early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) -{ - hubreg_t llp_csr_reg; - nasid_t nasid; - hubinfo_t hubinfo; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - /* - * If link is up, read the widget's part number. - * A direct connect widget must respond to widgetnum=0. - */ - if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { - /* TBD: Put hub into "indirect" mode */ - /* - * We're able to read from a widget because our hub's - * WIDGET_ID was set up earlier. - */ - widgetreg_t widget_id = *(volatile widgetreg_t *) - (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); - - DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, - (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); - - hwid->part_num = XWIDGET_PART_NUM(widget_id); - hwid->rev_num = XWIDGET_REV_NUM(widget_id); - hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); - - /* TBD: link reset */ - } else { - - hwid->part_num = XWIDGET_PART_NUM_NONE; - hwid->rev_num = XWIDGET_REV_NUM_NONE; - hwid->mfg_num = XWIDGET_MFG_NUM_NONE; - } - -} - -/* Add inventory information to the widget vertex - * Right now (module,slot,revision) is being - * added as inventory information. - */ -static void -xwidget_inventory_add(devfs_handle_t widgetv, - lboard_t *board, - struct xwidget_hwid_s hwid) -{ - if (!board) - return; - /* Donot add inventory information for the baseio - * on a speedo with an xbox. It has already been - * taken care of in SN00_vmc. - * Speedo with xbox's baseio comes in at slot io1 (widget 9) - */ - device_inventory_add(widgetv,INV_IOBD,board->brd_type, - board->brd_module, - SLOTNUM_GETSLOT(board->brd_slot), - hwid.rev_num); -} - -/* - * io_xswitch_widget_init - * - */ - -/* defined in include/linux/ctype.h */ -/* #define toupper(c) (islower(c) ? (c) - 'a' + 'A' : (c)) */ - -void -io_xswitch_widget_init(devfs_handle_t xswitchv, - devfs_handle_t hubv, - xwidgetnum_t widgetnum, - async_attach_t aa) -{ - xswitch_info_t xswitch_info; - xwidgetnum_t hub_widgetid; - devfs_handle_t widgetv; - cnodeid_t cnode; - widgetreg_t widget_id; - nasid_t nasid, peer_nasid; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - /*REFERENCED*/ - int rc; - char slotname[SLOTNUM_MAXLENGTH]; - char pathname[128]; - char new_name[64]; - moduleid_t module; - slotid_t slot; - lboard_t *board = NULL; - char buffer[16]; - slotid_t get_widget_slotnum(int xbow, int widget); - - DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); - /* - * Verify that xswitchv is indeed an attached xswitch. - */ - xswitch_info = xswitch_info_get(xswitchv); - ASSERT(xswitch_info != NULL); - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - cnode = NASID_TO_COMPACT_NODEID(nasid); - hub_widgetid = hubinfo->h_widgetid; - - - /* Who's the other guy on out crossbow (if anyone) */ - peer_nasid = NODEPDA(cnode)->xbow_peer; - if (peer_nasid == INVALID_NASID) - /* If I don't have a peer, use myself. */ - peer_nasid = nasid; - - - /* Check my xbow structure and my peer's */ - if (!xbow_port_io_enabled(nasid, widgetnum) && - !xbow_port_io_enabled(peer_nasid, widgetnum)) { - return; - } - - if (xswitch_info_link_ok(xswitch_info, widgetnum)) { - char name[4]; - /* - * If the current hub is not supposed to be the master - * for this widgetnum, then skip this widget. - */ - if (xswitch_info_master_assignment_get(xswitch_info, - widgetnum) != hubv) { - return; - } - - module = NODEPDA(cnode)->module_id; -#ifdef XBRIDGE_REGS_SIM - /* hardwire for now...could do this with something like: - * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl); - * xbow_t xbow = soft->base; - * xbowreg_t xwidget_id = xbow->xb_wid_id; - * but I don't feel like figuring out vhdl right now.. - * and I know for a fact the answer is 0x2d000049 - */ - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); - if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { -#else - if (nasid_has_xbridge(nasid)) { -#endif /* XBRIDGE_REGS_SIM */ - board = find_lboard_module_class( - (lboard_t *)KL_CONFIG_INFO(nasid), - module, - KLTYPE_IOBRICK); - -DBG("io_xswitch_widget_init: Board 0x%p\n", board); -{ - lboard_t dummy; - - - if (board) { - DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); - } else { - DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); - board = &dummy; - } - -} - - /* - * Make sure we really want to say xbrick, pbrick, - * etc. rather than XIO, graphics, etc. - */ - -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" - "%cbrick" "/%s/%d", - NODEPDA(cnode)->module_id, - -#else - memset(buffer, 0, 16); - format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" - "%cbrick" "/%s/%d", - buffer, -#endif - - (board->brd_type == KLTYPE_IBRICK) ? 'I' : - (board->brd_type == KLTYPE_PBRICK) ? 'P' : - (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', - EDGE_LBL_XTALK, widgetnum); - } - - DBG("io_xswitch_widget_init: path= %s\n", pathname); - rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - - ASSERT(rc == GRAPH_SUCCESS); - - /* This is needed to let the user programs to map the - * module,slot numbers to the corresponding widget numbers - * on the crossbow. - */ - rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); - - /* If we are looking at the global master io6 - * then add information about the version of - * the io6prom as a part of "detailed inventory" - * information. - */ - if (is_master_baseio(nasid, - NODEPDA(cnode)->module_id, - get_widget_slotnum(0,widgetnum))) { - extern void klhwg_baseio_inventory_add(devfs_handle_t, - cnodeid_t); - module = NODEPDA(cnode)->module_id; - -#ifdef XBRIDGE_REGS_SIM - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { -#else - if (nasid_has_xbridge(nasid)) { -#endif /* XBRIDGE_REGS_SIM */ - board = find_lboard_module( - (lboard_t *)KL_CONFIG_INFO(nasid), - module); - /* - * Change iobrick to correct i/o brick - */ -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" -#else - sprintf(pathname, EDGE_LBL_MODULE "/%x/" -#endif - "iobrick" "/%s/%d", - NODEPDA(cnode)->module_id, - EDGE_LBL_XTALK, widgetnum); - } else { - slot = get_widget_slotnum(0, widgetnum); - board = get_board_name(nasid, module, slot, - new_name); - /* - * Create the vertex for the widget, - * using the decimal - * widgetnum as the name of the primary edge. - */ -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" - EDGE_LBL_SLOT "/%s/%s", - NODEPDA(cnode)->module_id, - slotname, new_name); -#else - memset(buffer, 0, 16); - format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" - EDGE_LBL_SLOT "/%s/%s", - buffer, - slotname, new_name); -#endif - } - - rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - DBG("io_xswitch_widget_init: (2) path= %s\n", pathname); - /* - * This is a weird ass code needed for error injection - * purposes. - */ - rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); - - klhwg_baseio_inventory_add(widgetv,cnode); - } - sprintf(name, "%d", widgetnum); - DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); - rc = hwgraph_edge_add(xswitchv, widgetv, name); - - /* - * crosstalk switch code tracks which - * widget is attached to each link. - */ - xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); - - /* - * Peek at the widget to get its crosstalk part and - * mfgr numbers, then present it to the generic xtalk - * bus provider to have its driver attach routine - * called (or not). - */ -#ifdef XBRIDGE_REGS_SIM - widget_id = 0x2d000049; - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); -#else - widget_id = XWIDGET_ID_READ(nasid, widgetnum); -#endif /* XBRIDGE_REGS_SIM */ - hwid.part_num = XWIDGET_PART_NUM(widget_id); - hwid.rev_num = XWIDGET_REV_NUM(widget_id); - hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); - /* Store some inventory information about - * the xwidget in the hardware graph. - */ - xwidget_inventory_add(widgetv,board,hwid); - - (void)xwidget_register(&hwid, widgetv, widgetnum, - hubv, hub_widgetid, - aa); - -#ifdef SN0_USE_BTE - bte_bpush_war(cnode, (void *)board); -#endif - } - -} - - -static void -io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) -{ - xwidgetnum_t widgetnum; - async_attach_t aa; - - aa = async_attach_new(); - - DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; - widgetnum++) { - io_xswitch_widget_init(xswitchv, - cnodeid_to_vertex(cnode), - widgetnum, aa); - } - /* - * Wait for parallel attach threads, if any, to complete. - */ - async_attach_waitall(aa); - async_attach_free(aa); -} - -/* - * For each PCI bridge connected to the xswitch, add a link from the - * board's klconfig info to the bridge's hwgraph vertex. This lets - * the FRU analyzer find the bridge without traversing the hardware - * graph and risking hangs. - */ -static void -io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) -{ - xwidgetnum_t widgetnum; - char pathname[128]; - devfs_handle_t vhdl; - nasid_t nasid, peer_nasid; - lboard_t *board; - - - - /* And its connected hub's nasids */ - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - peer_nasid = NODEPDA(cnodeid)->xbow_peer; - - /* - * Look for paths matching "/pci" under xswitchv. - * For every widget, init. its lboard's hwgraph link. If the - * board has a PCI bridge, point the link to it. - */ - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; - widgetnum++) { - sprintf(pathname, "%d", widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) != - GRAPH_SUCCESS) - continue; - - board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), - NODEPDA(cnodeid)->module_id); - if (board == NULL && peer_nasid != INVALID_NASID) { - /* - * Try to find the board on our peer - */ - board = find_lboard_module( - (lboard_t *)KL_CONFIG_INFO(peer_nasid), - NODEPDA(cnodeid)->module_id); - } - if (board == NULL) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "Could not find PROM info for vertex %v, " - "FRU analyzer may fail", - vhdl); -#else - printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, " - "FRU analyzer may fail", - (void *)vhdl); -#endif - return; - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) == - GRAPH_SUCCESS) - board->brd_graph_link = vhdl; - else - board->brd_graph_link = GRAPH_VERTEX_NONE; - } -} - -/* - * Initialize all I/O on the specified node. - */ -static void -io_init_node(cnodeid_t cnodeid) -{ - /*REFERENCED*/ - devfs_handle_t hubv, switchv, widgetv; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - int is_xswitch; - nodepda_t *npdap; - struct semaphore *peer_sema = 0; - uint32_t widget_partnum; - nodepda_router_info_t *npda_rip; - cpu_cookie_t c = 0; - extern int hubdev_docallouts(devfs_handle_t); - -#ifdef LATER - /* Try to execute on the node that we're initializing. */ - c = setnoderun(cnodeid); -#endif - npdap = NODEPDA(cnodeid); - - /* - * Get the "top" vertex for this node's hardware - * graph; it will carry the per-hub hub-specific - * data, and act as the crosstalk provider master. - * It's canonical path is probably something of the - * form /hw/module/%M/slot/%d/node - */ - hubv = cnodeid_to_vertex(cnodeid); - DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); - - ASSERT(hubv != GRAPH_VERTEX_NONE); - - hubdev_docallouts(hubv); - - /* - * Set up the dependent routers if we have any. - */ - npda_rip = npdap->npda_rip_first; - - while(npda_rip) { - /* If the router info has not been initialized - * then we need to do the router initialization - */ - if (!npda_rip->router_infop) { - router_init(cnodeid,0,npda_rip); - } - npda_rip = npda_rip->router_next; - } - - /* - * Read mfg info on this hub - */ -#ifdef LATER - printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n"); - HUB_VERTEX_MFG_INFO(hubv); -#endif /* LATER */ - - /* - * If nothing connected to this hub's xtalk port, we're done. - */ - early_probe_for_widget(hubv, &hwid); - if (hwid.part_num == XWIDGET_PART_NUM_NONE) { -#ifdef PROBE_TEST - if ((cnodeid == 1) || (cnodeid == 2)) { - int index; - - for (index = 0; index < 600; index++) - DBG("Interfering with device probing!!!\n"); - } -#endif - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - - DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); - return; - /* NOTREACHED */ - } - - /* - * attach our hub_provider information to hubv, - * so we can use it as a crosstalk provider "master" - * vertex. - */ - xtalk_provider_register(hubv, &hub_provider); - xtalk_provider_startup(hubv); - - /* - * Create a vertex to represent the crosstalk bus - * attached to this hub, and a vertex to be used - * as the connect point for whatever is out there - * on the other side of our crosstalk connection. - * - * Crosstalk Switch drivers "climb up" from their - * connection point to try and take over the switch - * point. - * - * Of course, the edges and verticies may already - * exist, in which case our net effect is just to - * associate the "xtalk_" driver with the connection - * point for the device. - */ - - (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); - - DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); - - ASSERT(switchv != GRAPH_VERTEX_NONE); - - (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); - - DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); - - /* - * We need to find the widget id and update the basew_id field - * accordingly. In particular, SN00 has direct connected bridge, - * and hence widget id is Not 0. - */ - - widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; - - if (widget_partnum == BRIDGE_WIDGET_PART_NUM || - widget_partnum == XBRIDGE_WIDGET_PART_NUM){ - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - - DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); - - } else if (widget_partnum == XBOW_WIDGET_PART_NUM || - widget_partnum == XXBOW_WIDGET_PART_NUM) { - /* - * Xbow control register does not have the widget ID field. - * So, hard code the widget ID to be zero. - */ - DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); - npdap->basew_id = 0; - - } else if (widget_partnum == XG_WIDGET_PART_NUM) { - /* - * OK, WTF do we do here if we have an XG direct connected to a HUB/Bedrock??? - * So, hard code the widget ID to be zero? - */ - npdap->basew_id = 0; - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - } else { - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - - panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widgt ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); - - /*NOTREACHED*/ - } - { - char widname[10]; - sprintf(widname, "%x", npdap->basew_id); - (void)hwgraph_path_add(switchv, widname, &widgetv); - DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); - ASSERT(widgetv != GRAPH_VERTEX_NONE); - } - - nodepda->basew_xc = widgetv; - - is_xswitch = xwidget_hwid_is_xswitch(&hwid); - - /* - * Try to become the master of the widget. If this is an xswitch - * with multiple hubs connected, only one will succeed. Mastership - * of an xswitch is used only when touching registers on that xswitch. - * The slave xwidgets connected to the xswitch can be owned by various - * masters. - */ - if (device_master_set(widgetv, hubv) == 0) { - - /* Only one hub (thread) per Crosstalk device or switch makes - * it to here. - */ - - /* - * Initialize whatever xwidget is hanging off our hub. - * Whatever it is, it's accessible through widgetnum 0. - */ - hubinfo_get(hubv, &hubinfo); - - (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL); - - if (!is_xswitch) { - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - io_init_done(cnodeid,c); - /* NOTREACHED */ - } - - /* - * Special handling for Crosstalk Switches (e.g. xbow). - * We need to do things in roughly the following order: - * 1) Initialize xswitch hardware (done above) - * 2) Determine which hubs are available to be widget masters - * 3) Discover which links are active from the xswitch - * 4) Assign xwidgets hanging off the xswitch to hubs - * 5) Initialize all xwidgets on the xswitch - */ - - volunteer_for_widgets(switchv, hubv); - - /* If there's someone else on this crossbow, recognize him */ - if (npdap->xbow_peer != INVALID_NASID) { - nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer)); - peer_sema = &peer_npdap->xbow_sema; - volunteer_for_widgets(switchv, peer_npdap->node_vertex); - } - - assign_widgets_to_volunteers(switchv, hubv); - - /* Signal that we're done */ - if (peer_sema) { - mutex_unlock(peer_sema); - } - - } - else { - /* Wait 'til master is done assigning widgets. */ - mutex_lock(&npdap->xbow_sema); - } - -#ifdef PROBE_TEST - if ((cnodeid == 1) || (cnodeid == 2)) { - int index; - - for (index = 0; index < 500; index++) - DBG("Interfering with device probing!!!\n"); - } -#endif - /* Now both nodes can safely inititialize widgets */ - io_init_xswitch_widgets(switchv, cnodeid); - io_link_xswitch_widgets(switchv, cnodeid); - - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - io_init_done(cnodeid,c); - - DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); -} - - -#define IOINIT_STKSZ (16 * 1024) - -#define __DEVSTR1 "/../.master/" -#define __DEVSTR2 "/target/" -#define __DEVSTR3 "/lun/0/disk/partition/" -#define __DEVSTR4 "/../ef" - -#if defined(CONFIG_IA64_SGI_SN1) -/* - * Currently, we need to allow for 5 IBrick slots with 1 FC each - * plus an internal 1394. - * - * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR. - */ -#define NUM_BASE_IO_SCSI_CTLR 6 -#else -#define NUM_BASE_IO_SCSI_CTLR 6 -#endif -/* - * This tells ioconfig where it can start numbering scsi controllers. - * Below this base number, platform-specific handles the numbering. - * XXX Irix legacy..controller numbering should be part of devfsd's job - */ -int num_base_io_scsi_ctlr = 2; /* used by syssgi */ -devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR]; -static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl; - -/* - * Put the logical controller number information in the - * scsi controller vertices for each scsi controller that - * is in a "fixed position". - */ -static void -scsi_ctlr_nums_add(devfs_handle_t pci_vhdl) -{ - { - int i; - - num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR; - - /* Initialize base_io_scsi_ctlr_vhdl array */ - for (i=0; i -devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; - -/* Define the system critical vertices and connect them through - * a canonical parent-child relationships for easy traversal - * during io error handling. - */ -static void -sys_critical_graph_init(void) -{ - devfs_handle_t bridge_vhdl,master_node_vhdl; - devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE; - extern devfs_handle_t hwgraph_root; - devfs_handle_t pci_slot_conn; - int slot; - devfs_handle_t baseio_console_conn; - - DBG("sys_critical_graph_init: FIXME.\n"); - baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); - - if (baseio_console_conn == NULL) { - return; - } - - /* Get the vertex handle for the baseio bridge */ - bridge_vhdl = device_master_get(baseio_console_conn); - - /* Get the master node of the baseio card */ - master_node_vhdl = cnodeid_to_vertex( - master_node_get(baseio_console_vhdl)); - - /* Add the "root->node" part of the system critical graph */ - - sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl); - - /* Check if we have a crossbow */ - if (hwgraph_traverse(master_node_vhdl, - EDGE_LBL_XTALK"/0", - &xbow_vhdl) == GRAPH_SUCCESS) { - /* We have a crossbow.Add "node->xbow" part of the system - * critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl); - - /* Add "xbow->baseio bridge" of the system critical graph */ - sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl); - - hwgraph_vertex_unref(xbow_vhdl); - } else - /* We donot have a crossbow. Add "node->baseio_bridge" - * part of the system critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl); - - /* Add all the populated PCI slot vertices to the system critical - * graph with the bridge vertex as the parent. - */ - for (slot = 0 ; slot < 8; slot++) { - char slot_edge[10]; - - sprintf(slot_edge,"%d",slot); - if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn) - != GRAPH_SUCCESS) - continue; - sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn); - hwgraph_vertex_unref(pci_slot_conn); - } - - hwgraph_vertex_unref(bridge_vhdl); - - /* Add the "ioc3 pci connection point -> console ioc3" part - * of the system critical graph - */ - - if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_console_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "ethernet pci connection point -> base ethernet" part of - * the system critical graph - */ - if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_enet_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "scsi controller pci connection point -> base scsi - * controller" part of the system critical graph - */ - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[0]); - hwgraph_vertex_unref(pci_slot_conn); - } - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[1]); - hwgraph_vertex_unref(pci_slot_conn); - } - hwgraph_vertex_unref(baseio_console_conn); - -} - -static void -baseio_ctlr_num_set(void) -{ - char name[MAXDEVNAME]; - devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; - devfs_handle_t ioc3_console_vhdl_get(void); - - - DBG("baseio_ctlr_num_set; FIXME\n"); - console_vhdl = ioc3_console_vhdl_get(); - if (console_vhdl == GRAPH_VERTEX_NONE) - return; - /* Useful for setting up the system critical graph */ - baseio_console_vhdl = console_vhdl; - - vertex_to_name(console_vhdl,name,MAXDEVNAME); - - strcat(name,__DEVSTR1); - pci_vhdl = hwgraph_path_to_vertex(name); - scsi_ctlr_nums_add(pci_vhdl); - /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(pci_vhdl); - - vertex_to_name(console_vhdl, name, MAXDEVNAME); - strcat(name, __DEVSTR4); - enet_vhdl = hwgraph_path_to_vertex(name); - - /* Useful for setting up the system critical graph */ - baseio_enet_vhdl = enet_vhdl; - - device_controller_num_set(enet_vhdl, 0); - /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(enet_vhdl); -} -/* #endif */ - -void -sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list) -{ - /* REFERENCED */ - int rtn_val; - - /* - ** sn00 population: errb orrb - ** 0- ql 3+? - ** 1- ql 2 - ** 2- ioc3 ethernet 2+? - ** 3- ioc3 secondary 1 - ** 4- 0 - ** 5- PCI slot - ** 6- PCI slot - ** 7- PCI slot - */ - - /* The following code implements this heuristic for getting - * maximum usage out of the rrbs - * - * constraints: - * 8 bit ql1 needs 1+1 - * ql0 or ql5,6,7 wants 1+2 - * ethernet wants 2 or more - * - * rules for even rrbs: - * if nothing in slot 6 - * 4 rrbs to 0 and 2 (0xc8889999) - * else - * 3 2 3 to slots 0 2 6 (0xc8899bbb) - * - * rules for odd rrbs - * if nothing in slot 5 or 7 (0xc8889999) - * 4 rrbs to 1 and 3 - * else if 1 thing in 5 or 7 (0xc8899aaa) or (0xc8899bbb) - * 3 2 3 to slots 1 3 5|7 - * else - * 2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this - * (0xc89aaabb) may short what it wants therefore the - * rule should be to plug pci slots in order) - */ - - - if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) { - /* something in slot 6 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0); - } - else { - rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0); - } - if (rtn_val) - printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); - - if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && - (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) { - /* soemthing in slot 5 and 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0); - } - else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) { - /* soemthing in slot 5 but not 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0); - } - else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) { - /* soemthing in slot 7 but not 5 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0); - } - else { - /* nothing in slot 5 or 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0); - } - if (rtn_val) - printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); -} - - -/* - * Initialize all I/O devices. Starting closest to nodes, probe and - * initialize outward. - */ -void -init_all_devices(void) -{ - /* Governor on init threads..bump up when safe - * (beware many devfs races) - */ -#ifdef LATER - int io_init_node_threads = 2; -#endif - cnodeid_t cnodeid, active; - -#ifdef LINUX_KERNEL_THREADS - sema_init(&io_init_sema, 0); -#endif - - active = 0; - for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { -#ifdef LINUX_KERNEL_THREADS - char thread_name[16]; - extern int io_init_pri; - - /* - * Spawn a service thread for each node to initialize all - * I/O on that node. Each thread attempts to bind itself - * to the node whose I/O it's initializing. - */ - sprintf(thread_name, "IO_init[%d]", cnodeid); - - (void)sthread_create(thread_name, 0, IOINIT_STKSZ, 0, - io_init_pri, KT_PS, (st_func_t *)io_init_node, - (void *)(long)cnodeid, 0, 0, 0); -#else - DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); - io_init_node(cnodeid); - - DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); - -#endif /* LINUX_KERNEL_THREADS */ - -#ifdef LINUX_KERNEL_THREADS - /* Limit how many nodes go at once, to not overload hwgraph */ - /* TBD: Should timeout */ - DBG("started thread for cnode %d\n", cnodeid); - active++; - if (io_init_node_threads && - active >= io_init_node_threads) { - down(&io_init_sema); - active--; - } -#endif /* LINUX_KERNEL_THREADS */ - } - -#ifdef LINUX_KERNEL_THREADS - /* Wait until all IO_init threads are done */ - - while (active > 0) { -#ifdef AA_DEBUG - DBG("waiting, %d still active\n", active); -#endif - down(&io_init_sema); - active--; - } - -#endif /* LINUX_KERNEL_THREADS */ - - for (cnodeid = 0; cnodeid < numnodes; cnodeid++) - /* - * Update information generated by IO init. - */ - update_node_information(cnodeid); - - baseio_ctlr_num_set(); - /* Setup the system critical graph (which is a subgraph of the - * main hwgraph). This information is useful during io error - * handling. - */ - sys_critical_graph_init(); - -#if HWG_PRINT - hwgraph_print(); -#endif - -} - -#define toint(x) ((int)(x) - (int)('0')) - -void -devnamefromarcs(char *devnm) -{ - int val; - char tmpnm[MAXDEVNAME]; - char *tmp1, *tmp2; - - val = strncmp(devnm, "dks", 3); - if (val != 0) - return; - tmp1 = devnm + 3; - if (!isdigit(*tmp1)) - return; - - val = 0; - while (isdigit(*tmp1)) { - val = 10*val+toint(*tmp1); - tmp1++; - } - - if(*tmp1 != 'd') - return; - else - tmp1++; - - if ((val < 0) || (val >= NUM_BASE_IO_SCSI_CTLR)) { - int i; - int viable_found = 0; - - DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); - DBG("prom \"root\" variables of the form dksXdXsX.\n"); - DBG("To use another disk you must use the full hardware graph path\n\n"); - DBG("Possible controller numbers for use in 'dksXdXsX' on this system: "); - for (i=0; i XBOW_PORT_F) - return 0; - - /* Find "brick" in the path name */ - bp = strstr(hw_path_name, "brick"); - if (bp == NULL) - return 0; - - /* Find preceding slash */ - sp = bp; - while (sp > hw_path_name) { - sp--; - if (*sp == '/') - break; - } - - /* Invalid if no preceding slash */ - if (!sp) - return 0; - - /* Bump slash pointer to "brick" prefix */ - sp++; - /* - * Verify "brick" prefix length; valid exaples: - * 'I' from "/Ibrick" - * 'P' from "/Pbrick" - * 'X' from "/Xbrick" - */ - if ((bp - sp) != 1) - return 0; - - return (io_brick_map_widget(*sp, widget_num)); - -} diff -Nur linux-2.4.19/arch/ia64/sn/io/module.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/module.c --- linux-2.4.19/arch/ia64/sn/io/module.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/module.c Wed Dec 31 16:00:00 1969 @@ -1,312 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* #define LDEBUG 1 */ - -#ifdef LDEBUG -#define DPRINTF printk -#define printf printk -#else -#define DPRINTF(x...) -#endif - -module_t *modules[MODULE_MAX]; -int nummodules; - -#define SN00_SERIAL_FUDGE 0x3b1af409d513c2 -#define SN0_SERIAL_FUDGE 0x6e - -void -encode_int_serial(uint64_t src,uint64_t *dest) -{ - uint64_t val; - int i; - - val = src + SN00_SERIAL_FUDGE; - - - for (i = 0; i < sizeof(long long); i++) { - ((char*)dest)[i] = - ((char*)&val)[sizeof(long long)/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))]; - } -} - - -void -decode_int_serial(uint64_t src, uint64_t *dest) -{ - uint64_t val; - int i; - - for (i = 0; i < sizeof(long long); i++) { - ((char*)&val)[sizeof(long long)/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = - ((char*)&src)[i]; - } - - *dest = val - SN00_SERIAL_FUDGE; -} - - -void -encode_str_serial(const char *src, char *dest) -{ - int i; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { - - dest[i] = src[MAX_SERIAL_NUM_SIZE/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] + - SN0_SERIAL_FUDGE; - } -} - -void -decode_str_serial(const char *src, char *dest) -{ - int i; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { - dest[MAX_SERIAL_NUM_SIZE/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] - - SN0_SERIAL_FUDGE; - } -} - - -module_t *module_lookup(moduleid_t id) -{ - int i; - - for (i = 0; i < nummodules; i++) - if (modules[i]->id == id) { - DPRINTF("module_lookup: found m=0x%p\n", modules[i]); - return modules[i]; - } - - return NULL; -} - -/* - * module_add_node - * - * The first time a new module number is seen, a module structure is - * inserted into the module list in order sorted by module number - * and the structure is initialized. - * - * The node number is added to the list of nodes in the module. - */ - -module_t *module_add_node(moduleid_t id, cnodeid_t n) -{ - module_t *m; - int i; - char buffer[16]; - -#ifdef __ia64 - memset(buffer, 0, 16); - format_module_id(buffer, id, MODULE_FORMAT_BRIEF); - DPRINTF("module_add_node: id=%s node=%d\n", buffer, n); -#endif - - if ((m = module_lookup(id)) == 0) { -#ifdef LATER - m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n); -#else - m = kmalloc(sizeof (module_t), GFP_KERNEL); - memset(m, 0 , sizeof(module_t)); -#endif - ASSERT_ALWAYS(m); - - m->id = id; - spin_lock_init(&m->lock); - - mutex_init_locked(&m->thdcnt); - -// set_elsc(&m->elsc); - elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n)); - spin_lock_init(&m->elsclock); - - /* Insert in sorted order by module number */ - - for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--) - modules[i] = modules[i - 1]; - - modules[i] = m; - nummodules++; - } - - m->nodes[m->nodecnt++] = n; - - DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); - - return m; -} - -int module_probe_snum(module_t *m, nasid_t nasid) -{ - lboard_t *board; - klmod_serial_num_t *comp; - char * bcopy(const char * src, char * dest, int count); - char serial_number[16]; - - /* - * record brick serial number - */ - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - { -#if LDEBUG - printf ("module_probe_snum: no IP35 board found!\n"); -#endif - return 0; - } - - board_serial_number_get( board, serial_number ); - if( serial_number[0] != '\0' ) { - encode_str_serial( serial_number, m->snum.snum_str ); - m->snum_valid = 1; - } -#if LDEBUG - else { - printf("module_probe_snum: brick serial number is null!\n"); - } - printf("module_probe_snum: brick serial number == %s\n", serial_number); -#endif /* DEBUG */ - - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), - KLTYPE_IOBRICK_XBOW); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - return 0; - - comp = GET_SNUM_COMP(board); - - if (comp) { -#if LDEBUG - int i; - - printf("********found module with id %x and string", m->id); - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) - printf(" %x ", comp->snum.snum_str[i]); - - printf("\n"); /* Fudged string is not ASCII */ -#endif - - if (comp->snum.snum_str[0] != '\0') { - bcopy(comp->snum.snum_str, - m->sys_snum, - MAX_SERIAL_NUM_SIZE); - m->sys_snum_valid = 1; - } - } - - if (m->sys_snum_valid) - return 1; - else { - DPRINTF("Invalid serial number for module %d, " - "possible missing or invalid NIC.", m->id); - return 0; - } -} - -void -io_module_init(void) -{ - cnodeid_t node; - lboard_t *board; - nasid_t nasid; - int nserial; - module_t *m; - - DPRINTF("*******module_init\n"); - - nserial = 0; - - for (node = 0; node < numnodes; node++) { - nasid = COMPACT_TO_NASID_NODEID(node); - - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(board); - - m = module_add_node(board->brd_module, node); - - if (! m->snum_valid && module_probe_snum(m, nasid)) - nserial++; - } - - DPRINTF("********found total of %d serial numbers in the system\n", - nserial); - - if (nserial == 0) - printk(KERN_WARNING "io_module_init: No serial number found.\n"); -} - -elsc_t *get_elsc(void) -{ - return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc; -} - -int -get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info) -{ - int i; - - if (cmod < 0 || cmod >= nummodules) - return EINVAL; - - if (! modules[cmod]->snum_valid) - return ENXIO; - - mod_info->mod_num = modules[cmod]->id; - { - char temp[MAX_SERIAL_NUM_SIZE]; - - decode_str_serial(modules[cmod]->snum.snum_str, temp); - - /* if this is an invalid serial number return an error */ - if (temp[0] != 'K') - return ENXIO; - - mod_info->serial_num = 0; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) { - mod_info->serial_num <<= 4; - mod_info->serial_num |= (temp[i] & 0xf); - - mod_info->serial_str[i] = temp[i]; - } - - mod_info->serial_str[i] = '\0'; - } - - return 0; -} diff -Nur linux-2.4.19/arch/ia64/sn/io/pci.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/pci.c --- linux-2.4.19/arch/ia64/sn/io/pci.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/pci.c Mon Dec 30 14:16:56 2002 @@ -6,7 +6,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1997, 1998, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1997, 1998, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include @@ -230,7 +230,7 @@ void __init sn_pci_find_bios(void) { - extern struct pci_ops pci_conf; + extern struct pci_ops *pci_root_ops; /* * Go initialize our IO Infrastructure .. */ @@ -239,7 +239,7 @@ sgi_master_io_infr_init(); /* sn_io_infrastructure_init(); */ - pci_conf = snia64_pci_ops; + pci_root_ops = &snia64_pci_ops; } void @@ -276,15 +276,9 @@ d->resource[i].flags = 0UL; } - /* - * Hardcode Device 4 register(IOC3 is in Slot 4) to set the - * DEV_DIRECT bit. This will not work if IOC3 is not on Slot - * 4. - */ - DBG("pci_fixup_ioc3: FIXME .. need to take NASID into account when setting IOC3 devreg 0x%x\n", *(volatile u32 *)0xc0000a000f000220); - - *(volatile u32 *)0xc0000a000f000220 |= 0x90000; - +#ifdef CONFIG_IA64_SGI_SN1 + *(volatile u32 *)0xc0000a000f000220 |= 0x90000; +#endif d->subsystem_vendor = 0; d->subsystem_device = 0; diff -Nur linux-2.4.19/arch/ia64/sn/io/pci_bus_cvlink.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/pci_bus_cvlink.c --- linux-2.4.19/arch/ia64/sn/io/pci_bus_cvlink.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/pci_bus_cvlink.c Wed Dec 31 16:00:00 1969 @@ -1,743 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int bridge_rev_b_data_check_disable; - -devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; -nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; -void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; -unsigned char num_bridges; -static int done_probing = 0; - -static int pci_bus_map_create(devfs_handle_t xtalk); -devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); - -#define SN_IOPORTS_UNIT 256 -#define MAX_IOPORTS 0xffff -#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN_IOPORTS_UNIT) -struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS]; -unsigned long sn_allocate_ioports(unsigned long pci_address); - -extern void sn_init_irq_desc(void); - - - -/* - * pci_bus_cvlink_init() - To be called once during initialization before - * SGI IO Infrastructure init is called. - */ -void -pci_bus_cvlink_init(void) -{ - memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); - memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); - - memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); - - memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs)); - - num_bridges = 0; -} - -/* - * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated - * pci bus vertex from the SGI IO Infrastructure. - */ -devfs_handle_t -pci_bus_to_vertex(unsigned char busnum) -{ - - devfs_handle_t pci_bus = NULL; - - - /* - * First get the xwidget vertex. - */ - pci_bus = busnum_to_pcibr_vhdl[busnum]; - return(pci_bus); -} - -/* - * devfn_to_vertex() - returns the vertex of the device given the bus, slot, - * and function numbers. - */ -devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn) -{ - - int slot = 0; - int func = 0; - char name[16]; - devfs_handle_t pci_bus = NULL; - devfs_handle_t device_vertex = (devfs_handle_t)NULL; - - /* - * Go get the pci bus vertex. - */ - pci_bus = pci_bus_to_vertex(busnum); - if (!pci_bus) { - /* - * During probing, the Linux pci code invents non-existent - * bus numbers and pci_dev structures and tries to access - * them to determine existence. Don't crib during probing. - */ - if (done_probing) - printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); - return(NULL); - } - - - /* - * Go get the slot&function vertex. - * Should call pciio_slot_func_to_name() when ready. - */ - slot = PCI_SLOT(devfn); - func = PCI_FUNC(devfn); - - /* - * For a NON Multi-function card the name of the device looks like: - * ../pci/1, ../pci/2 .. - */ - if (func == 0) { - sprintf(name, "%d", slot); - if (hwgraph_traverse(pci_bus, name, &device_vertex) == - GRAPH_SUCCESS) { - if (device_vertex) { - return(device_vertex); - } - } - } - - /* - * This maybe a multifunction card. It's names look like: - * ../pci/1a, ../pci/1b, etc. - */ - sprintf(name, "%d%c", slot, 'a'+func); - if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { - if (!device_vertex) { - return(NULL); - } - } - - return(device_vertex); -} - -/* - * For the given device, initialize the addresses for both the Device(x) Flush - * Write Buffer register and the Xbow Flush Register for the port the PCI bus - * is connected. - */ -static void -set_flush_addresses(struct pci_dev *device_dev, - struct sn_device_sysdata *device_sysdata) -{ - pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - - device_sysdata->dma_buf_sync = (volatile unsigned int *) - &(bridge->b_wr_req_buf[pciio_slot].reg); - device_sysdata->xbow_buf_sync = (volatile unsigned int *) - XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(get_nasid(), 0), - pcibr_soft->bs_xid); -#ifdef DEBUG - - printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", - device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); - - while((volatile unsigned int )*device_sysdata->dma_buf_sync); - while((volatile unsigned int )*device_sysdata->xbow_buf_sync); -#endif - -} - -/* - * Most drivers currently do not properly tell the arch specific pci dma - * interfaces whether they can handle A64. Here is where we privately - * keep track of this. - */ -static void __init -set_sn_pci64(struct pci_dev *dev) -{ - unsigned short vendor = dev->vendor; - unsigned short device = dev->device; - - if (vendor == PCI_VENDOR_ID_QLOGIC) { - if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) || - (device == PCI_DEVICE_ID_QLOGIC_ISP2200)) { - SET_PCIA64(dev); - return; - } - } - - if (vendor == PCI_VENDOR_ID_SGI) { - if (device == PCI_DEVICE_ID_SGI_IOC3) { - SET_PCIA64(dev); - return; - } - } - -} - -/* - * sn_allocate_ioports() - This routine provides the allocation and - * mappings between Linux style IOPORTs management. - * - * For simplicity sake, SN1 will allocate IOPORTs in chunks of - * 256bytes .. irrespective of what the card desires. This may - * have to change when we understand how to deal with legacy ioports - * which are hardcoded in some drivers e.g. SVGA. - * - * Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers. - * It will remain so. The IO Infrastructure will continue to map - * IO Resource just like IRIX. When this is done, we map IOPORT - * chunks to these resources. The Linux drivers will see and use real - * IOPORT numbers. The various IOPORT access macros e.g. inb/outb etc. - * does the munging of these IOPORT numbers to make a Uncache Virtual - * Address. This address via the tlb entries generates the PCI Address - * allocated by the SN1 IO Infrastructure Layer. - */ -static unsigned long sn_ioport_num = 0x1000; /* Reserve room for Legacy stuff */ -unsigned long -sn_allocate_ioports(unsigned long pci_address) -{ - - unsigned long ioport_index; - - /* - * Just some idiot checking .. - */ - if ( sn_ioport_num > 0xffff ) { - printk("sn_allocate_ioports: No more IO PORTS available\n"); - return(-1); - } - - /* - * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's - * Manual for details. - */ - ioport_index = sn_ioport_num / SN_IOPORTS_UNIT; - - ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */ - ioports_to_tlbs[ioport_index].rv_1 = 0; /* 1 Bit */ - ioports_to_tlbs[ioport_index].ma = 4; /* Memory Attributes 3 bits*/ - ioports_to_tlbs[ioport_index].a = 1; /* Set Data Access Bit Fault 1 Bit*/ - ioports_to_tlbs[ioport_index].d = 1; /* Dirty Bit */ - ioports_to_tlbs[ioport_index].pl = 0;/* Privilege Level - All levels can R/W*/ - ioports_to_tlbs[ioport_index].ar = 3; /* Access Rights - R/W only*/ - ioports_to_tlbs[ioport_index].ppn = pci_address >> 12; /* 4K page size */ - ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */ - ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */ - - /* printk("sn_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index]); */ - - sn_ioport_num += SN_IOPORTS_UNIT; - - return(sn_ioport_num - SN_IOPORTS_UNIT); -} - -/* - * sn_pci_fixup() - This routine is called when platform_pci_fixup() is - * invoked at the end of pcibios_init() to link the Linux pci - * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c - * - * Other platform specific fixup can also be done here. - */ -void -sn_pci_fixup(int arg) -{ - struct list_head *ln; - struct pci_bus *pci_bus = NULL; - struct pci_dev *device_dev = NULL; - struct sn_widget_sysdata *widget_sysdata; - struct sn_device_sysdata *device_sysdata; -#ifdef SN_IOPORTS - unsigned long ioport; -#endif - pciio_intr_t intr_handle; - int cpuid, bit; - devfs_handle_t device_vertex; - pciio_intr_line_t lines; - extern void sn_pci_find_bios(void); -#ifdef CONFIG_IA64_SGI_SN2 - extern int numnodes; - int cnode; -#endif /* CONFIG_IA64_SGI_SN2 */ - - - if (arg == 0) { - sn_init_irq_desc(); - sn_pci_find_bios(); -#ifdef CONFIG_IA64_SGI_SN2 - for (cnode = 0; cnode < numnodes; cnode++) { - extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); - intr_init_vecblk(NODEPDA(cnode), cnode, 0); - } -#endif /* CONFIG_IA64_SGI_SN2 */ - return; - } - -#if 0 -{ - devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - printk("pci_fixup_ioc3: Before devreg fixup\n"); - printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); - printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); - printk("pci_fixup_ioc3: Devreg 2 0x%x\n", bridge->b_device[2].reg); - printk("pci_fixup_ioc3: Devreg 3 0x%x\n", bridge->b_device[3].reg); - printk("pci_fixup_ioc3: Devreg 4 0x%x\n", bridge->b_device[4].reg); - printk("pci_fixup_ioc3: Devreg 5 0x%x\n", bridge->b_device[5].reg); - printk("pci_fixup_ioc3: Devreg 6 0x%x\n", bridge->b_device[6].reg); - printk("pci_fixup_ioc3: Devreg 7 0x%x\n", bridge->b_device[7].reg); -} -#endif - done_probing = 1; - - /* - * Initialize the pci bus vertex in the pci_bus struct. - */ - for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { - pci_bus = pci_bus_b(ln); - widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), - GFP_KERNEL); - widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); - pci_bus->sysdata = (void *)widget_sysdata; - } - - /* - * set the root start and end so that drivers calling check_region() - * won't see a conflict - */ -#ifdef SN_IOPORTS - ioport_resource.start = sn_ioport_num; - ioport_resource.end = 0xffff; -#else -#if defined(CONFIG_IA64_SGI_SN1) - if ( IS_RUNNING_ON_SIMULATOR() ) { - /* - * IDE legacy IO PORTs are supported in Medusa. - * Just open up IO PORTs from 0 .. ioport_resource.end. - */ - ioport_resource.start = 0; - } else { - /* - * We do not support Legacy IO PORT numbers. - */ - ioport_resource.start |= IO_SWIZ_BASE | __IA64_UNCACHED_OFFSET; - } - ioport_resource.end |= (HSPEC_SWIZ_BASE-1) | __IA64_UNCACHED_OFFSET; -#else - // Need something here for sn2.... ZXZXZX -#endif -#endif - - /* - * Set the root start and end for Mem Resource. - */ - iomem_resource.start = 0; - iomem_resource.end = 0xffffffffffffffff; - - /* - * Initialize the device vertex in the pci_dev struct. - */ - pci_for_each_dev(device_dev) { - unsigned int irq; - int idx; - u16 cmd; - devfs_handle_t vhdl; - unsigned long size; - extern int bit_pos_to_irq(int); - - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { - extern void pci_fixup_ioc3(struct pci_dev *d); - pci_fixup_ioc3(device_dev); - } - - /* Set the device vertex */ - - device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), - GFP_KERNEL); - device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); - device_sysdata->isa64 = 0; - /* - * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush - * register addresses. - */ - (void) set_flush_addresses(device_dev, device_sysdata); - - device_dev->sysdata = (void *) device_sysdata; - set_sn_pci64(device_dev); - pci_read_config_word(device_dev, PCI_COMMAND, &cmd); - - /* - * Set the resources address correctly. The assumption here - * is that the addresses in the resource structure has been - * read from the card and it was set in the card by our - * Infrastructure .. - */ - vhdl = device_sysdata->vhdl; - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - size = 0; - size = device_dev->resource[idx].end - - device_dev->resource[idx].start; - if (size) { - device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); - device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; - } - else - continue; - - device_dev->resource[idx].end = - device_dev->resource[idx].start + size; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Adjust the addresses to go to the SWIZZLE .. - */ - device_dev->resource[idx].start = - device_dev->resource[idx].start & 0xfffff7ffffffffff; - device_dev->resource[idx].end = - device_dev->resource[idx].end & 0xfffff7ffffffffff; -#endif - - if (device_dev->resource[idx].flags & IORESOURCE_IO) { - cmd |= PCI_COMMAND_IO; -#ifdef SN_IOPORTS - ioport = sn_allocate_ioports(device_dev->resource[idx].start); - if (ioport < 0) { - printk("sn_pci_fixup: PCI Device 0x%x on PCI Bus %d not mapped to IO PORTs .. IO PORTs exhausted\n", device_dev->devfn, device_dev->bus->number); - continue; - } - pciio_config_set(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + (idx * 4), 4, (res + (ioport & 0xfff))); - -printk("sn_pci_fixup: ioport number %d mapped to pci address 0x%lx\n", ioport, (res + (ioport & 0xfff))); - - device_dev->resource[idx].start = ioport; - device_dev->resource[idx].end = ioport + SN_IOPORTS_UNIT; -#endif - } - if (device_dev->resource[idx].flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - /* - * Now handle the ROM resource .. - */ - size = device_dev->resource[PCI_ROM_RESOURCE].end - - device_dev->resource[PCI_ROM_RESOURCE].start; - - if (size) { - device_dev->resource[PCI_ROM_RESOURCE].start = - (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, - size, 0, PCIIO_BYTE_STREAM); - device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; - device_dev->resource[PCI_ROM_RESOURCE].end = - device_dev->resource[PCI_ROM_RESOURCE].start + size; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * go through synergy swizzled space - */ - device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL; - device_dev->resource[PCI_ROM_RESOURCE].end &= 0xfffff7ffffffffffUL; -#endif - - } - - /* - * Update the Command Word on the Card. - */ - cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ - /* bit gets dropped .. no harm */ - pci_write_config_word(device_dev, PCI_COMMAND, cmd); - - pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { - lines = 1; - } - - device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata; - device_vertex = device_sysdata->vhdl; - - intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); - - bit = intr_handle->pi_irq; - cpuid = intr_handle->pi_cpu; -#ifdef CONFIG_IA64_SGI_SN1 - irq = bit_pos_to_irq(bit); -#else /* SN2 */ - irq = bit; -#endif - irq = irq + (cpuid << 8); - pciio_intr_connect(intr_handle); - device_dev->irq = irq; -#ifdef ajmtestintr - { - int slot = PCI_SLOT(device_dev->devfn); - static int timer_set = 0; - pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - extern void intr_test_handle_intr(int, void*, struct pt_regs *); - - if (!timer_set) { - intr_test_set_timer(); - timer_set = 1; - } - intr_test_register_irq(irq, pcibr_soft, slot); - request_irq(irq, intr_test_handle_intr,0,NULL, NULL); - } -#endif - - } - -#if 0 - -{ - devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - printk("pci_fixup_ioc3: Before devreg fixup\n"); - printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); - printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); - printk("pci_fixup_ioc3: Devreg 2 0x%x\n", bridge->b_device[2].reg); - printk("pci_fixup_ioc3: Devreg 3 0x%x\n", bridge->b_device[3].reg); - printk("pci_fixup_ioc3: Devreg 4 0x%x\n", bridge->b_device[4].reg); - printk("pci_fixup_ioc3: Devreg 5 0x%x\n", bridge->b_device[5].reg); - printk("pci_fixup_ioc3: Devreg 6 0x%x\n", bridge->b_device[6].reg); - printk("pci_fixup_ioc3: Devreg 7 0x%x\n", bridge->b_device[7].reg); -} - -printk("testing Big Window: 0xC0000200c0000000 %p\n", *( (volatile uint64_t *)0xc0000200a0000000)); -printk("testing Big Window: 0xC0000200c0000008 %p\n", *( (volatile uint64_t *)0xc0000200a0000008)); - -#endif - -} - -/* - * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. - * - * Linux PCI Bus numbers are assigned from lowest module_id numbers - * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to - * HUB_WIDGET_ID_MIN: - * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. - * - * Given 2 modules 001c01 and 001c02 we get the following mappings: - * 001c01, widgetnum 15 = Bus number 0 - * 001c01, widgetnum 14 = Bus number 1 - * 001c02, widgetnum 15 = Bus number 3 - * 001c02, widgetnum 14 = Bus number 4 - * etc. - * - * The rational for starting Bus Number 0 with Widget number 15 is because - * the system boot disks are always connected via Widget 15 Slot 0 of the - * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 - * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest - * module id(Master Cnode) of the system. - * - */ -static int -pci_bus_map_create(devfs_handle_t xtalk) -{ - - devfs_handle_t master_node_vertex = NULL; - devfs_handle_t xwidget = NULL; - devfs_handle_t pci_bus = NULL; - hubinfo_t hubinfo = NULL; - xwidgetnum_t widgetnum; - char pathname[128]; - graph_error_t rv; - - /* - * Loop throught this vertex and get the Xwidgets .. - */ - for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { -#if 0 - { - int pos; - char dname[256]; - pos = devfs_generate_path(xtalk, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif - - sprintf(pathname, "%d", widgetnum); - xwidget = NULL; - - /* - * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget - * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device - */ - rv = hwgraph_traverse(xtalk, pathname, &xwidget); - if ( (rv != GRAPH_SUCCESS) ) { - if (!xwidget) - continue; - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - pci_bus = NULL; - if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) - if (!pci_bus) - continue; - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - * - * Should not be any race here ... - */ - num_bridges++; - busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; - - /* - * Get the master node and from there get the NASID. - */ - master_node_vertex = device_master_get(xwidget); - if (!master_node_vertex) { - printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); - } - - hubinfo_get(master_node_vertex, &hubinfo); - if (!hubinfo) { - printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); - return(1); - } else { - busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; - } - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( - sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); - if (!busnum_to_atedmamaps[num_bridges - 1]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); - - memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, - sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); - - } - - return(0); -} - -/* - * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure - * initialization has completed to set up the mappings between Xbridge - * and logical pci bus numbers. We also set up the NASID for each of these - * xbridges. - * - * Must be called before pci_init() is invoked. - */ -int -pci_bus_to_hcl_cvlink(void) -{ - - devfs_handle_t devfs_hdl = NULL; - devfs_handle_t xtalk = NULL; - int rv = 0; - char name[256]; - int master_iobrick; - int i; - - /* - * Iterate throught each xtalk links in the system .. - * /hw/module/001c01/node/xtalk/ 8|9|10|11|12|13|14|15 - * - * /hw/module/001c01/node/xtalk/15 -> /hw/module/001c01/Ibrick/xtalk/15 - * - * What if it is not pci? - */ - devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); - - /* - * To provide consistent(not persistent) device naming, we need to start - * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 - * with an attached I-Brick. Find the master_iobrick. - */ - master_iobrick = -1; - for (i = 0; i < nummodules; i++) { - moduleid_t iobrick_id; - iobrick_id = iobrick_module_get(&modules[i]->elsc); - if (iobrick_id > 0) { /* Valid module id */ - if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) { - master_iobrick = i; - break; - } - } - } - - /* - * The master_iobrick gets bus 0 and 1. - */ - if (master_iobrick >= 0) { - memset(name, 0, 256); - format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF); - strcat(name, "/node/xtalk"); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk); - } - - /* - * Now go do the rest of the modules, starting from the C-Brick with the lowest - * module id, remembering to skip the master_iobrick, which was done above. - */ - for (i = 0; i < nummodules; i++) { - if (i == master_iobrick) { - continue; /* Did the master_iobrick already. */ - } - - memset(name, 0, 256); - format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); - strcat(name, "/node/xtalk"); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk); - } - - return(0); -} diff -Nur linux-2.4.19/arch/ia64/sn/io/pci_dma.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/pci_dma.c --- linux-2.4.19/arch/ia64/sn/io/pci_dma.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/pci_dma.c Tue Jan 14 09:33:52 2003 @@ -3,15 +3,20 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000,2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. + * + * Routines for PCI DMA mapping. See Documentation/DMA-mapping.txt for + * a description of how these routines should be used. */ +#include #include #include #include #include #include #include +#include #include #include @@ -27,15 +32,26 @@ #include #include +/* + * For ATE allocations + */ pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); void free_pciio_dmamap(pcibr_dmamap_t); -struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char); +static struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char); + +/* + * Toplogy stuff + */ extern devfs_handle_t busnum_to_pcibr_vhdl[]; extern nasid_t busnum_to_nid[]; extern void * busnum_to_atedmamaps[]; -/* - * Get a free pciio_dmamap_t entry. +/** + * get_free_pciio_dmamap - find and allocate an ATE + * @pci_bus: PCI bus to get an entry for + * + * Finds and allocates an ATE on the PCI bus specified + * by @pci_bus. */ pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t pci_bus) @@ -46,7 +62,7 @@ /* * Darn, we need to get the maps allocated for this bus. */ - for (i=0; idma_addr) { sn_dma_map->dma_addr = -1; return( (pciio_dmamap_t) sn_dma_map ); } } - return(NULL); - + return NULL; } -/* - * Free pciio_dmamap_t entry. +/** + * free_pciio_dmamap - free an ATE + * @dma_map: ATE to free + * + * Frees the ATE specified by @dma_map. */ void free_pciio_dmamap(pcibr_dmamap_t dma_map) @@ -76,177 +94,249 @@ sn_dma_map = (struct sn_dma_maps_s *) dma_map; sn_dma_map->dma_addr = 0; +} +/** + * find_sn_dma_map - find an ATE associated with @dma_addr and @busnum + * @dma_addr: DMA address to look for + * @busnum: PCI bus to look on + * + * Finds the ATE associated with @dma_addr and @busnum. + */ +static struct sn_dma_maps_s * +find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum) +{ + + struct sn_dma_maps_s *sn_dma_map = NULL; + int i; + + sn_dma_map = busnum_to_atedmamaps[busnum]; + + for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) { + if (sn_dma_map->dma_addr == dma_addr) { + return sn_dma_map; + } + } + + return NULL; } -/* - * sn_dma_sync: This routine flushes all DMA buffers for the device into the II. - * This does not mean that the data is in the "Coherence Domain". But it - * is very close. +/** + * sn_dma_sync - try to flush DMA buffers into the coherence domain + * @hwdev: device to flush + * + * This routine flushes all DMA buffers for the device into the II of + * the destination hub. + * + * NOTE!: this does not mean that the data is in the "coherence domain", + * but it is very close. In other words, this routine *does not work* + * as advertised due to hardware bugs. That said, it should be good enough for + * most situations. */ void -sn_dma_sync( struct pci_dev *hwdev ) +sn_dma_sync(struct pci_dev *hwdev) { +#ifdef SN_DMA_SYNC + struct sn_device_sysdata *device_sysdata; volatile unsigned long dummy; /* - * It is expected that on IA64 platform, a DMA sync ensures that all - * the DMA (dma_handle) are complete and coherent. - * 1. Flush Write Buffers from Bridge. - * 2. Flush Xbow Port. + * A DMA sync is supposed to ensure that + * all the DMA from a particular device + * is complete and coherent. We + * try to do this by + * 1. flushing the write wuffers from Bridge + * 2. flushing the Xbow port. + * Unfortunately, this only gets the DMA transactions 'very close' to + * the coherence domain, but not quite in it. */ device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata; dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync; /* - * For the Xbow Port flush, we maybe denied the request because - * someone else may be flushing the Port .. try again. + * For the Xbow port flush, we may be denied the request because + * someone else may be flushing the port .. try again. */ while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) { udelay(2); } +#endif } - -struct sn_dma_maps_s * -find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum) -{ - - struct sn_dma_maps_s *sn_dma_map = NULL; - int i; - - sn_dma_map = busnum_to_atedmamaps[busnum]; - - for (i=0; idma_addr == dma_addr) { - return( sn_dma_map ); - } - } - -printk("find_pciio_dmamap: Unable find the corresponding dma map\n"); - - return(NULL); - -} - -/* - * sn1 platform specific pci_alloc_consistent() +/** + * sn_pci_alloc_consistent - allocate memory for coherent DMA + * @hwdev: device to allocate for + * @size: size of the region + * @dma_handle: DMA (bus) address + * + * pci_alloc_consistent() returns a pointer to a memory region suitable for + * coherent DMA traffic to/from a PCI device. On SN platforms, this means + * that @dma_handle will have the %PCIIO_DMA_CMD flag set. + * + * This interface is usually used for "command" streams (e.g. the command + * queue for a SCSI controller). See Documentation/DMA-mapping.txt for + * more information. Note that this routine will always put a 32 bit + * DMA address into @dma_handle. This is because most devices + * that are capable of 64 bit PCI DMA transactions can't do 64 bit _coherent_ + * DMAs, and unfortunately this interface has to cater to the LCD. Oh well. * - * this interface is meant for "command" streams, i.e. called only - * once for initializing a device, so we don't want prefetching or - * write gathering turned on, hence the PCIIO_DMA_CMD flag + * Also known as platform_pci_alloc_consistent() by the IA64 machvec code. */ void * -sn_pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { - void *ret; - int gfp = GFP_ATOMIC; - devfs_handle_t vhdl; + void *cpuaddr; + devfs_handle_t vhdl; struct sn_device_sysdata *device_sysdata; - paddr_t temp_ptr; + unsigned long phys_addr; + pciio_dmamap_t dma_map = 0; + struct sn_dma_maps_s *sn_dma_map; + + *dma_handle = 0; - *dma_handle = (dma_addr_t) NULL; + /* We can't easily support < 32 bit devices */ + if (IS_PCI32L(hwdev)) + return NULL; /* - * get vertex for the device + * Get hwgraph vertex for the device */ device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; - if ( (ret = (void *)__get_free_pages(gfp, get_order(size))) ) { - memset(ret, 0, size); - } else { - return(NULL); - } + /* + * Allocate the memory. FIXME: if we're allocating for + * two devices on the same bus, we should at least try to + * allocate memory in the same 2 GB window to avoid using + * ATEs for the translation. See the comment above about the + * 32 bit requirement for this function. + */ + if(!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)))) + return NULL; - temp_ptr = (paddr_t) __pa(ret); - if (IS_PCIA64(hwdev)) { + memset(cpuaddr, 0, size); /* have to zero it out */ - /* - * This device supports 64bits DMA addresses. - */ + /* physical addr. of the memory we just got */ + phys_addr = __pa(cpuaddr); + + /* + * This will try to use a Direct Map register to do the + * 32 bit DMA mapping, but it may not succeed if another + * device on the same bus is already mapped with different + * attributes or to a different memory region. + */ #ifdef CONFIG_IA64_SGI_SN1 - *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, - PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD - | PCIIO_DMA_A64 ); -#else /* SN2 */ - *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, - PCIBR_BARRIER | PCIIO_DMA_CMD | PCIIO_DMA_A64 ); + *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + PCIIO_BYTE_STREAM | + PCIIO_DMA_CMD); +#elif defined(CONFIG_IA64_SGI_SN2) + *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_CMD); +#else +#error unsupported platform #endif - return (ret); - } - /* - * Devices that supports 32 Bits upto 63 Bits DMA Address gets - * 32 Bits DMA addresses. - * - * First try to get 32 Bit Direct Map Support. + * It is a 32 bit card and we cannot do direct mapping, + * so we try to use an ATE. */ - if (IS_PCI32G(hwdev)) { + if (!(*dma_handle)) { #ifdef CONFIG_IA64_SGI_SN1 - *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, - PCIBR_BARRIER | PCIIO_BYTE_STREAM | PCIIO_DMA_CMD); -#else /* SN2 */ - *dma_handle = pciio_dmatrans_addr(vhdl, NULL, temp_ptr, size, - PCIBR_BARRIER | PCIIO_DMA_CMD); + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, + PCIIO_BYTE_STREAM | + PCIIO_DMA_CMD); +#elif defined(CONFIG_IA64_SGI_SN2) + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_CMD); +#else +#error unsupported platform #endif - - if (dma_handle) { - return (ret); - } else { - /* - * We need to map this request by using ATEs. - */ - printk("sn_pci_alloc_consistent: 32Bits DMA Page Map support not available yet!"); - BUG(); + if (!dma_map) { + printk(KERN_ERR "sn_pci_alloc_consistent: Unable to " + "allocate anymore 32 bit page map entries.\n"); + return 0; } + *dma_handle = (dma_addr_t) pciio_dmamap_addr(dma_map,phys_addr, + size); + sn_dma_map = (struct sn_dma_maps_s *)dma_map; + sn_dma_map->dma_addr = *dma_handle; } - if (IS_PCI32L(hwdev)) { - /* - * SNIA64 cannot support DMA Addresses smaller than 32 bits. - */ - return (NULL); - } - - return NULL; + return cpuaddr; } +/** + * sn_pci_free_consistent - free memory associated with coherent DMAable region + * @hwdev: device to free for + * @size: size to free + * @vaddr: kernel virtual address to free + * @dma_handle: DMA address associated with this region + * + * Frees the memory allocated by pci_alloc_consistent(). Also known + * as platform_pci_free_consistent() by the IA64 machvec code. + */ void sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { + struct sn_dma_maps_s *sn_dma_map = NULL; + + /* + * Get the sn_dma_map entry. + */ + if (IS_PCI32_MAPPED(dma_handle)) + sn_dma_map = find_sn_dma_map(dma_handle, hwdev->bus->number); + + /* + * and free it if necessary... + */ + if (sn_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); + sn_dma_map->dma_addr = (dma_addr_t)NULL; + } free_pages((unsigned long) vaddr, get_order(size)); } -/* - * On sn1 we use the page entry of the scatterlist to store - * the physical address corresponding to the given virtual address +/** + * sn_pci_map_sg - map a scatter-gather list for DMA + * @hwdev: device to map for + * @sg: scatterlist to map + * @nents: number of entries + * @direction: direction of the DMA transaction + * + * Maps each entry of @sg for DMA. Also known as platform_pci_map_sg by the + * IA64 machvec code. */ int -sn_pci_map_sg (struct pci_dev *hwdev, - struct scatterlist *sg, int nents, int direction) +sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { int i; - devfs_handle_t vhdl; + devfs_handle_t vhdl; dma_addr_t dma_addr; - paddr_t temp_ptr; + unsigned long phys_addr; struct sn_device_sysdata *device_sysdata; pciio_dmamap_t dma_map; + struct scatterlist *saved_sg = sg; - - + /* can't go anywhere w/o a direction in life */ if (direction == PCI_DMA_NONE) BUG(); /* - * Handle 64 bit cards. + * Get the hwgraph vertex for the device */ device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; vhdl = device_sysdata->vhdl; + + /* + * Setup a DMA address for each entry in the + * scatterlist. + */ for (i = 0; i < nents; i++, sg++) { /* this catches incorrectly written drivers that attempt to map scatterlists that they have @@ -262,50 +352,49 @@ "%p - this is currently being worked around.\n", hwdev->slot_name, (void *)sg->address); #endif - temp_ptr = (u64)sg->address & TO_PHYS_MASK; + phys_addr = (u64)sg->address & TO_PHYS_MASK; break; - case 0xe: /* a good address, we now map it. */ - temp_ptr = (paddr_t) __pa(sg->address); + default: /* not previously mapped, get the phys. addr */ + phys_addr = __pa(sg->address); break; - default: - printk(KERN_ERR - "Very bad address (%p) passed to sn_pci_map_sg\n", - (void *)sg->address); - BUG(); } - sg->page = (char *)NULL; + sg->page = NULL; dma_addr = 0; /* - * Handle the most common case 64Bit cards. + * Handle the most common case: 64 bit cards. This + * call should always succeed. */ if (IS_PCIA64(hwdev)) { -#ifdef CONFIG_IA64_SGI_SN1 - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, sg->length, - PCIIO_BYTE_STREAM | PCIIO_DMA_DATA | - PCIIO_DMA_A64 ); -#else - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, sg->length, - PCIIO_DMA_DATA | PCIIO_DMA_A64 ); -#endif + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, + sg->length, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA | + PCIIO_DMA_A64); sg->address = (char *)dma_addr; continue; } /* - * Handle 32Bits and greater cards. + * Handle 32-63 bit cards via direct mapping */ if (IS_PCI32G(hwdev)) { #ifdef CONFIG_IA64_SGI_SN1 - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, sg->length, - PCIIO_BYTE_STREAM | PCIIO_DMA_DATA); + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, + sg->length, + PCIIO_BYTE_STREAM | + PCIIO_DMA_DATA); +#elif defined(CONFIG_IA64_SGI_SN2) + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, + sg->length, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); #else - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, sg->length, PCIIO_DMA_DATA); +#error unsupported platform #endif + /* + * See if we got a direct map entry + */ if (dma_addr) { sg->address = (char *)dma_addr; continue; @@ -314,24 +403,35 @@ } /* - * It is a 32bit card and we cannot do Direct mapping. - * Let's 32Bit Page map the request. + * It is a 32 bit card and we cannot do direct mapping, + * so we use an ATE. */ - dma_map = NULL; + dma_map = 0; #ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, - PCIIO_BYTE_STREAM | PCIIO_DMA_DATA); + dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, + PCIIO_BYTE_STREAM | + PCIIO_DMA_DATA); +#elif defined(CONFIG_IA64_SGI_SN2) + dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); #else - dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, PCIIO_DMA_DATA); +#error unsupported platform #endif if (!dma_map) { - printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n"); - BUG(); + printk(KERN_ERR "sn_pci_map_sg: Unable to allocate " + "anymore 32 bit page map entries.\n"); + /* + * We will need to free all previously allocated entries. + */ + if (i > 0) { + sn_pci_unmap_sg(hwdev, saved_sg, i, direction); + } + return (0); } - dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length); - /* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */ + dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length); sg->address = (char *)dma_addr; - sg->page = (char *)dma_map; + sg->page = (struct page *)dma_map; } @@ -339,30 +439,34 @@ } -/* - * Unmap a set of streaming mode DMA translations. - * Again, cpu read rules concerning calls here are the same as for - * pci_unmap_single() above. +/** + * sn_pci_unmap_sg - unmap a scatter-gather list + * @hwdev: device to unmap + * @sg: scatterlist to unmap + * @nents: number of scatterlist entries + * @direction: DMA direction + * + * Unmap a set of streaming mode DMA translations. Again, cpu read rules + * concerning calls here are the same as for pci_unmap_single() below. Also + * known as sn_pci_unmap_sg() by the IA64 machvec code. */ void -sn_pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { int i; struct sn_dma_maps_s *sn_dma_map; - + /* can't go anywhere w/o a direction in life */ if (direction == PCI_DMA_NONE) BUG(); - for (i = 0; i < nelems; i++, sg++) + for (i = 0; i < nents; i++, sg++) if (sg->page) { /* * We maintain the DMA Map pointer in sg->page if * it is ever allocated. */ - /* phys_to_virt((dma_addr_t)sg->address | ~0x80000000); */ - /* sg->address = sg->page; */ - sg->address = (char *)-1; + sg->address = 0; sn_dma_map = (struct sn_dma_maps_s *)sg->page; pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); @@ -372,7 +476,17 @@ } -/* +/** + * sn_pci_map_single - map a single region for DMA + * @hwdev: device to map for + * @ptr: kernel virtual address of the region to map + * @size: size of the region + * @direction: DMA direction + * + * Map the region pointed to by @ptr for DMA and return the + * DMA address. Also known as platform_pci_map_single() by + * the IA64 machvec code. + * * We map this to the one step pciio_dmamap_trans interface rather than * the two step pciio_dmamap_alloc/pciio_dmamap_addr because we have * no way of saving the dmamap handle from the alloc to later free @@ -382,20 +496,22 @@ * get rid of dev_desc and vhdl (seems redundant given a pci_dev); * figure out how to save dmamap handle so can use two step. */ -dma_addr_t sn_pci_map_single (struct pci_dev *hwdev, - void *ptr, size_t size, int direction) +dma_addr_t +sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) { - devfs_handle_t vhdl; + devfs_handle_t vhdl; dma_addr_t dma_addr; - paddr_t temp_ptr; + unsigned long phys_addr; struct sn_device_sysdata *device_sysdata; pciio_dmamap_t dma_map = NULL; struct sn_dma_maps_s *sn_dma_map; - if (direction == PCI_DMA_NONE) BUG(); + /* SN cannot support DMA addresses smaller than 32 bits. */ + if (IS_PCI32L(hwdev)) + return 0; /* * find vertex for the device @@ -407,79 +523,81 @@ * Call our dmamap interface */ dma_addr = 0; - temp_ptr = (paddr_t) __pa(ptr); + phys_addr = __pa(ptr); if (IS_PCIA64(hwdev)) { - /* - * This device supports 64bits DMA addresses. - */ -#ifdef CONFIG_IA64_SGI_SN1 - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, size, - PCIIO_BYTE_STREAM | PCIIO_DMA_DATA | PCIIO_DMA_A64 ); -#else - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, size, PCIIO_DMA_DATA | PCIIO_DMA_A64 ); -#endif - return (dma_addr); + /* This device supports 64 bit DMA addresses. */ + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA | + PCIIO_DMA_A64); + return dma_addr; } /* - * Devices that supports 32 Bits upto 63 Bits DMA Address gets - * 32 Bits DMA addresses. + * Devices that support 32 bit to 63 bit DMA addresses get + * 32 bit DMA addresses. * - * First try to get 32 Bit Direct Map Support. + * First try to get a 32 bit direct map register. */ if (IS_PCI32G(hwdev)) { #ifdef CONFIG_IA64_SGI_SN1 - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, size, - PCIIO_BYTE_STREAM | PCIIO_DMA_DATA); + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + PCIIO_BYTE_STREAM | + PCIIO_DMA_DATA); +#elif defined(CONFIG_IA64_SGI_SN2) + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); #else - dma_addr = (dma_addr_t) pciio_dmatrans_addr(vhdl, NULL, - temp_ptr, size, PCIIO_DMA_DATA); +#error unsupported platform #endif - if (dma_addr) { - return (dma_addr); - } + if (dma_addr) + return dma_addr; } - if (IS_PCI32L(hwdev)) { - /* - * SNIA64 cannot support DMA Addresses smaller than 32 bits. - */ - return ((dma_addr_t) NULL); - } - /* - * It is a 32bit card and we cannot do Direct mapping. - * Let's 32Bit Page map the request. + * It's a 32 bit card and we cannot do direct mapping so + * let's use the PMU instead. */ dma_map = NULL; #ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM | + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM | PCIIO_DMA_DATA); +#elif defined(CONFIG_IA64_SGI_SN2) + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); #else - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_DATA); +#error unsupported platform #endif + if (!dma_map) { - printk("pci_map_single: Unable to allocate anymore 32Bits Page Map entries.\n"); - BUG(); + printk(KERN_ERR "pci_map_single: Unable to allocate anymore " + "32 bit page map entries.\n"); + return 0; } - dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, temp_ptr, size); - /* printk("pci_map_single: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, - temp_ptr, dma_addr); */ + dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, phys_addr, size); sn_dma_map = (struct sn_dma_maps_s *)dma_map; sn_dma_map->dma_addr = dma_addr; return ((dma_addr_t)dma_addr); } +/** + * sn_pci_unmap_single - unmap a region used for DMA + * @hwdev: device to unmap + * @dma_addr: DMA address to unmap + * @size: size of region + * @direction: DMA direction + * + * Unmaps the region pointed to by @dma_addr. Also known as + * platform_pci_unmap_single() by the IA64 machvec code. + */ void -sn_pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) +sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { - struct sn_dma_maps_s *sn_dma_map = NULL; if (direction == PCI_DMA_NONE) @@ -491,37 +609,99 @@ if (IS_PCI32_MAPPED(dma_addr)) sn_dma_map = find_sn_dma_map(dma_addr, hwdev->bus->number); + /* + * and free it if necessary... + */ if (sn_dma_map) { pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); sn_dma_map->dma_addr = (dma_addr_t)NULL; } - } +/** + * sn_pci_dma_sync_single - make sure all DMAs have completed + * @hwdev: device to sync + * @dma_handle: DMA address to sync + * @size: size of region + * @direction: DMA direction + * + * This routine is supposed to sync the DMA region specified + * by @dma_handle into the 'coherence domain'. See sn_dma_sync() + * above for more information. Also known as + * platform_pci_dma_sync_single() by the IA64 machvec code. + */ void -sn_pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) +sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { - - if (direction == PCI_DMA_NONE) + if (direction == PCI_DMA_NONE) BUG(); sn_dma_sync(hwdev); - } +/** + * sn_pci_dma_sync_sg - make sure all DMAs have completed + * @hwdev: device to sync + * @sg: scatterlist to sync + * @nents: number of entries in the scatterlist + * @direction: DMA direction + * + * This routine is supposed to sync the DMA regions specified + * by @sg into the 'coherence domain'. See sn_dma_sync() + * above for more information. Also known as + * platform_pci_dma_sync_sg() by the IA64 machvec code. + */ void -sn_pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { if (direction == PCI_DMA_NONE) BUG(); sn_dma_sync(hwdev); - } +/** + * sn_dma_address - get the DMA address for the first entry of a scatterlist + * @sg: sg to look at + * + * Gets the DMA address for the scatterlist @sg. Also known as + * platform_dma_address() by the IA64 machvec code. + */ unsigned long -sn_dma_address (struct scatterlist *sg) +sn_dma_address(struct scatterlist *sg) { return ((unsigned long)sg->address); } + +/** + * sn_dma_supported - test a DMA mask + * @hwdev: device to test + * @mask: DMA mask to test + * + * Return whether the given PCI device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during PCI bus mastering, then you would pass 0x00ffffff as the mask to + * this function. Of course, SN only supports devices that have 32 or more + * address bits when using the PMU. We could theoretically support <32 bit + * cards using direct mapping, but we'll worry about that later--on the off + * chance that someone actually wants to use such a card. + */ +int +sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask) +{ + if (mask < 0xffffffff) + return 0; + return 1; +} + +EXPORT_SYMBOL(sn_pci_unmap_single); +EXPORT_SYMBOL(sn_pci_map_single); +EXPORT_SYMBOL(sn_pci_dma_sync_single); +EXPORT_SYMBOL(sn_pci_map_sg); +EXPORT_SYMBOL(sn_pci_unmap_sg); +EXPORT_SYMBOL(sn_pci_alloc_consistent); +EXPORT_SYMBOL(sn_pci_free_consistent); +EXPORT_SYMBOL(sn_dma_address); +EXPORT_SYMBOL(sn_pci_dma_supported); + diff -Nur linux-2.4.19/arch/ia64/sn/io/pciba.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/pciba.c --- linux-2.4.19/arch/ia64/sn/io/pciba.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/pciba.c Mon Dec 30 14:16:56 2002 @@ -17,7 +17,7 @@ * Public License. See the file "COPYING" in the main directory of * this archive for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. * * 03262001 - Initial version by Chad Talbott */ @@ -285,45 +285,6 @@ static devfs_handle_t pciba_devfs_handle; -#if !defined(CONFIG_IA64_SGI_SN1) - -static status __init -register_with_devfs(void) -{ - struct pci_dev * dev; - devfs_handle_t device_dir_handle; - char devfs_path[40]; - - TRACE(); - - pciba_devfs_handle = devfs_mk_dir(NULL, "pci", NULL); - if (pciba_devfs_handle == NULL) - return failure; - - /* FIXME: don't forget /dev/pci/mem & /dev/pci/io */ - - pci_for_each_dev(dev) { - sprintf(devfs_path, "%02x/%02x.%x", - dev->bus->number, - PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - - device_dir_handle = - devfs_mk_dir(pciba_devfs_handle, devfs_path, NULL); - if (device_dir_handle == NULL) - return failure; - - if (register_pci_device(device_dir_handle, dev) == failure) { - devfs_unregister(pciba_devfs_handle); - return failure; - } - } - - return success; -} - -#else - extern devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); @@ -351,9 +312,6 @@ return success; } - -#endif /* CONFIG_IA64_SGI_SN1 */ - static void __exit unregister_with_devfs(void) diff -Nur linux-2.4.19/arch/ia64/sn/io/pciio.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/pciio.c --- linux-2.4.19/arch/ia64/sn/io/pciio.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/pciio.c Wed Dec 31 16:00:00 1969 @@ -1,1511 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#define USRPCI 0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Must be before iograph.h to get MAX_PORT_NUM */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_PCIIO -#undef DEBUG_PCIIO /* turn this on for yet more console output */ - - -#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DO_DEL(ptr) (kfree(ptr)) - -char pciio_info_fingerprint[] = "pciio_info"; - -cdl_p pciio_registry = NULL; - -int -badaddr_val(volatile void *addr, int len, volatile void *ptr) -{ - int ret = 0; - volatile void *new_addr; - - switch (len) { - case 4: -#ifdef CONFIG_IA64_SGI_SN1 - new_addr = (void *)(((u64) addr)^4); -#else - new_addr = (void *) addr; -#endif - ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); - break; - default: - printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); - } - - if (ret < 0) - panic("badaddr_val: unexpected status (%d) in probing", ret); - return(ret); - -} - - -nasid_t -get_console_nasid(void) -{ - extern nasid_t console_nasid; - if (console_nasid < 0) { - console_nasid = ia64_sn_get_console_nasid(); - if (console_nasid < 0) { -// ZZZ What do we do if we don't get a console nasid on the hardware???? - if (IS_RUNNING_ON_SIMULATOR() ) - console_nasid = master_nasid; - } - } - return console_nasid; -} - -int -hub_dma_enabled(devfs_handle_t xconn_vhdl) -{ - return(0); -} - -int -hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) -{ - return(0); -} - -void -ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror) -{ -} - -/****** - ****** end hack defines ...... - ******/ - - - - -/* ===================================================================== - * PCI Generic Bus Provider - * Implement PCI provider operations. The pciio* layer provides a - * platform-independent interface for PCI devices. This layer - * switches among the possible implementations of a PCI adapter. - */ - -/* ===================================================================== - * Provider Function Location SHORTCUT - * - * On platforms with only one possible PCI provider, macros can be - * set up at the top that cause the table lookups and indirections to - * completely disappear. - */ - -#if defined(CONFIG_IA64_SGI_SN1) -/* - * For the moment, we will assume that IP27 - * only use Bridge ASICs to provide PCI support. - */ -#include -#define DEV_FUNC(dev,func) pcibr_##func -#define CAST_PIOMAP(x) ((pcibr_piomap_t)(x)) -#define CAST_DMAMAP(x) ((pcibr_dmamap_t)(x)) -#define CAST_INTR(x) ((pcibr_intr_t)(x)) -#endif /* CONFIG_IA64_SGI_SN1 */ - -/* ===================================================================== - * Function Table of Contents - */ - -#if !defined(DEV_FUNC) -static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev); -#endif - -pciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); -void pciio_piomap_free(pciio_piomap_t); -caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t); - -void pciio_piomap_done(pciio_piomap_t); -caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); - -iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); - -pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void pciio_dmamap_free(pciio_dmamap_t); -iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned); -void pciio_dmamap_done(pciio_dmamap_t); -iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void pciio_dmamap_drain(pciio_dmamap_t); -void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pciio_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); - -pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -void pciio_intr_free(pciio_intr_t); -int pciio_intr_connect(pciio_intr_t); -void pciio_intr_disconnect(pciio_intr_t); -devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); - -void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); - -void pciio_provider_startup(devfs_handle_t); -void pciio_provider_shutdown(devfs_handle_t); - -pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t); -devfs_handle_t pciio_intr_dev_get(pciio_intr_t); - -devfs_handle_t pciio_pio_dev_get(pciio_piomap_t); -pciio_slot_t pciio_pio_slot_get(pciio_piomap_t); -pciio_space_t pciio_pio_space_get(pciio_piomap_t); -iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t); -ulong pciio_pio_mapsz_get(pciio_piomap_t); -caddr_t pciio_pio_kvaddr_get(pciio_piomap_t); - -devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t); -pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t); - -pciio_info_t pciio_info_chk(devfs_handle_t); -pciio_info_t pciio_info_get(devfs_handle_t); -void pciio_info_set(devfs_handle_t, pciio_info_t); -devfs_handle_t pciio_info_dev_get(pciio_info_t); -pciio_slot_t pciio_info_slot_get(pciio_info_t); -pciio_function_t pciio_info_function_get(pciio_info_t); -pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t); -pciio_device_id_t pciio_info_device_id_get(pciio_info_t); -devfs_handle_t pciio_info_master_get(pciio_info_t); -arbitrary_info_t pciio_info_mfast_get(pciio_info_t); -pciio_provider_t *pciio_info_pops_get(pciio_info_t); -error_handler_f *pciio_info_efunc_get(pciio_info_t); -error_handler_arg_t *pciio_info_einfo_get(pciio_info_t); -pciio_space_t pciio_info_bar_space_get(pciio_info_t, int); -iopaddr_t pciio_info_bar_base_get(pciio_info_t, int); -size_t pciio_info_bar_size_get(pciio_info_t, int); -iopaddr_t pciio_info_rom_base_get(pciio_info_t); -size_t pciio_info_rom_size_get(pciio_info_t); - -void pciio_init(void); -int pciio_attach(devfs_handle_t); - -void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns); -void pciio_provider_unregister(devfs_handle_t); -pciio_provider_t *pciio_provider_fns_get(devfs_handle_t); - -int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned); -void pciio_driver_unregister(char *driver_prefix); - -devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); - -void pciio_device_unregister(devfs_handle_t); -pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -void pciio_device_info_free(pciio_info_t); -devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); -void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); -int pciio_device_attach(devfs_handle_t, int); -int pciio_device_detach(devfs_handle_t, int); -void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); - -int pciio_reset(devfs_handle_t); -int pciio_write_gather_flush(devfs_handle_t); -int pciio_slot_inuse(devfs_handle_t); - -/* ===================================================================== - * Provider Function Location - * - * If there is more than one possible provider for - * this platform, we need to examine the master - * vertex of the current vertex for a provider - * function structure, and indirect through the - * appropriately named member. - */ - -#if !defined(DEV_FUNC) - -static pciio_provider_t * -pciio_to_provider_fns(devfs_handle_t dev) -{ - pciio_info_t card_info; - pciio_provider_t *provider_fns; - - /* - * We're called with two types of vertices, one is - * the bridge vertex (ends with "pci") and the other is the - * pci slot vertex (ends with "pci/[0-8]"). For the first type - * we need to get the provider from the PFUNCS label. For - * the second we get it from fastinfo/c_pops. - */ - provider_fns = pciio_provider_fns_get(dev); - if (provider_fns == NULL) { - card_info = pciio_info_get(dev); - if (card_info != NULL) { - provider_fns = pciio_info_pops_get(card_info); - } - } - - if (provider_fns == NULL) -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_PANIC("%v: provider_fns == NULL", dev); -#else - PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev); -#endif - - return provider_fns; - -} - -#define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((pciio_piomap_t)(x)) -#define CAST_DMAMAP(x) ((pciio_dmamap_t)(x)) -#define CAST_INTR(x) ((pciio_intr_t)(x)) -#endif - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC((map)->pp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC((map)->pd_dev,func) -#define INTR_FUNC(intr_hdl,func) DEV_FUNC((intr_hdl)->pi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * pciio space on a specified card - */ - -pciio_piomap_t -pciio_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* lowest address (or offset in window) */ - size_t byte_count, /* size of region containing our mappings */ - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, space, addr, byte_count, byte_count_max, flags); -} - -void -pciio_piomap_free(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_free) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piomap_addr(pciio_piomap_t pciio_piomap, /* mapping resources */ - iopaddr_t pciio_addr, /* map for this pciio address */ - size_t byte_count) -{ /* map this many bytes */ - pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr) - (CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count); - - return pciio_piomap->pp_kvaddr; -} - -void -pciio_piomap_done(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_done) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, space, addr, byte_count, flags); -} - -caddr_t -pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - pciio_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - pciio_piomap_t map = 0; - int errfree = 0; - caddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_piotrans_addr - (dev, dev_desc, space, addr, byte_count, flags); - if (res) - return res; /* pciio_piotrans worked */ - - if (!map) { - map = pciio_piomap_alloc - (dev, dev_desc, space, addr, byte_count, byte_count, flags); - if (!map) - return res; /* pciio_piomap_alloc failed */ - errfree = 1; - } - - res = pciio_piomap_addr - (map, addr, byte_count); - if (!res) { - if (errfree) - pciio_piomap_free(map); - return res; /* pciio_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_piomap_addr succeeded */ -} - -iopaddr_t -pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ - device_desc_t dev_desc, /* Device descriptor */ - pciio_space_t space, /* MEM32/MEM64/IO */ - size_t byte_count, /* Size of mapping */ - size_t align) -{ /* Alignment needed */ - if (align < NBPP) - align = NBPP; - return DEV_FUNC(dev, piospace_alloc) - (dev, dev_desc, space, byte_count, align); -} - -void -pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ - pciio_space_t space, /* Type of space */ - iopaddr_t pciaddr, /* starting address */ - size_t byte_count) -{ /* Range of address */ - DEV_FUNC(dev, piospace_free) - (dev, space, pciaddr, byte_count); -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from pci space to system - * physical space. - */ - -pciio_dmamap_t -pciio_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - -void -pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_free) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) - (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); -} - -alenlist_t -pciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(pciio_dmamap, dmamap_list) - (CAST_DMAMAP(pciio_dmamap), alenlist, flags); -} - -void -pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_done) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - -alenlist_t -pciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - -iopaddr_t -pciio_dma_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - pciio_dmamap_t *mapp, /* map to use, then map we used */ - unsigned flags) -{ /* PIO flags */ - pciio_dmamap_t map = 0; - int errfree = 0; - iopaddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_dmatrans_addr - (dev, dev_desc, paddr, byte_count, flags); - if (res) - return res; /* pciio_dmatrans worked */ - - if (!map) { - map = pciio_dmamap_alloc - (dev, dev_desc, byte_count, flags); - if (!map) - return res; /* pciio_dmamap_alloc failed */ - errfree = 1; - } - - res = pciio_dmamap_addr - (map, paddr, byte_count); - if (!res) { - if (errfree) - pciio_dmamap_free(map); - return res; /* pciio_dmamap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_dmamap_addr succeeded */ -} - -void -pciio_dmamap_drain(pciio_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -void -pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow crosstalk devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -pciio_intr_t -pciio_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_intr_line_t lines, /* INTR line(s) to attach */ - devfs_handle_t owner_dev) -{ /* owner of this interrupt */ - return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, lines, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -pciio_intr_free(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - -/* - * Associate resources allocated with a previous pciio_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -pciio_intr_connect(pciio_intr_t intr_hdl) /* pciio intr resource handle */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl)); -} - -/* - * Disassociate handler with the specified interrupt. - */ -void -pciio_intr_disconnect(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -pciio_intr_cpu_get(pciio_intr_t intr_hdl) -{ - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); -} - -void -pciio_slot_func_to_name(char *name, - pciio_slot_t slot, - pciio_function_t func) -{ - /* - * standard connection points: - * - * PCIIO_SLOT_NONE: .../pci/direct - * PCIIO_FUNC_NONE: .../pci/ ie. .../pci/3 - * multifunction: .../pci/ ie. .../pci/3c - */ - - if (slot == PCIIO_SLOT_NONE) - sprintf(name, "direct"); - else if (func == PCIIO_FUNC_NONE) - sprintf(name, "%d", slot); - else - sprintf(name, "%d%c", slot, 'a'+func); -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup a crosstalk provider - */ -void -pciio_provider_startup(devfs_handle_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_startup) - (pciio_provider); -} - -/* - * Shutdown a crosstalk provider - */ -void -pciio_provider_shutdown(devfs_handle_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_shutdown) - (pciio_provider); -} - -/* - * Specify endianness constraints. The driver tells us what the device - * does and how it would like to see things in memory. We reply with - * how things will actually appear in memory. - */ -pciio_endian_t -pciio_endian_set(devfs_handle_t dev, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE)); - ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE)); - -#if DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_ALERT "%v: pciio_endian_set is going away.\n" - "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" - "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", - dev); -#else - printk(KERN_ALERT "0x%x: pciio_endian_set is going away.\n" - "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" - "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", - dev); -#endif -#endif - - return DEV_FUNC(dev, endian_set) - (dev, device_end, desired_end); -} - -/* - * Specify PCI arbitration priority. - */ -pciio_priority_t -pciio_priority_set(devfs_handle_t dev, - pciio_priority_t device_prio) -{ - ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); - - return DEV_FUNC(dev, priority_set) - (dev, device_prio); -} - -/* - * Read value of configuration register - */ -uint64_t -pciio_config_get(devfs_handle_t dev, - unsigned reg, - unsigned size) -{ - uint64_t value = 0; - unsigned shift = 0; - - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - value |= DEV_FUNC(dev, config_get) - (dev, reg, biw) << shift; - - shift += 8*biw; - reg += biw; - size -= biw; - } - return value; -} - -/* - * Change value of configuration register - */ -void -pciio_config_set(devfs_handle_t dev, - unsigned reg, - unsigned size, - uint64_t value) -{ - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - DEV_FUNC(dev, config_set) - (dev, reg, biw, value); - reg += biw; - size -= biw; - value >>= biw * 8; - } -} - -/* ===================================================================== - * GENERIC PCI SUPPORT FUNCTIONS - */ - -/* - * Issue a hardware reset to a card. - */ -int -pciio_reset(devfs_handle_t dev) -{ - return DEV_FUNC(dev, reset) (dev); -} - -/* - * flush write gather buffers - */ -int -pciio_write_gather_flush(devfs_handle_t dev) -{ - return DEV_FUNC(dev, write_gather_flush) (dev); -} - -devfs_handle_t -pciio_intr_dev_get(pciio_intr_t pciio_intr) -{ - return (pciio_intr->pi_dev); -} - -/****** Generic crosstalk pio interfaces ******/ -devfs_handle_t -pciio_pio_dev_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_dev); -} - -pciio_slot_t -pciio_pio_slot_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_slot); -} - -pciio_space_t -pciio_pio_space_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_space); -} - -iopaddr_t -pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_pciaddr); -} - -ulong -pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_mapsz); -} - -caddr_t -pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_kvaddr); -} - -/****** Generic crosstalk dma interfaces ******/ -devfs_handle_t -pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap) -{ - return (pciio_dmamap->pd_dev); -} - -pciio_slot_t -pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap) -{ - return (pciio_dmamap->pd_slot); -} - -/****** Generic pci slot information interfaces ******/ - -pciio_info_t -pciio_info_chk(devfs_handle_t pciio) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo); - return (pciio_info_t) ainfo; -} - -pciio_info_t -pciio_info_get(devfs_handle_t pciio) -{ - pciio_info_t pciio_info; - - pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio); - -#ifdef DEBUG_PCIIO - { - int pos; - char dname[256]; - pos = devfs_generate_path(pciio, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif /* DEBUG_PCIIO */ - - if ((pciio_info != NULL) && - (pciio_info->c_fingerprint != pciio_info_fingerprint) - && (pciio_info->c_fingerprint != NULL)) { - - return((pciio_info_t)-1); /* Should panic .. */ - } - - - return pciio_info; -} - -void -pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) -{ - if (pciio_info != NULL) - pciio_info->c_fingerprint = pciio_info_fingerprint; - hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info); - - /* Also, mark this vertex as a PCI slot - * and use the pciio_info, so pciio_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO, - (arbitrary_info_t) pciio_info); -} - -devfs_handle_t -pciio_info_dev_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vertex); -} - -/*ARGSUSED*/ -pciio_bus_t -pciio_info_bus_get(pciio_info_t pciio_info) -{ - /* XXX for now O2 always gets back bus 0 */ - return (pciio_bus_t)0; -} - -pciio_slot_t -pciio_info_slot_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_slot); -} - -pciio_function_t -pciio_info_function_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_func); -} - -pciio_vendor_id_t -pciio_info_vendor_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vendor); -} - -pciio_device_id_t -pciio_info_device_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_device); -} - -devfs_handle_t -pciio_info_master_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_master); -} - -arbitrary_info_t -pciio_info_mfast_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_mfast); -} - -pciio_provider_t * -pciio_info_pops_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_pops); -} - -error_handler_f * -pciio_info_efunc_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_efunc); -} - -error_handler_arg_t * -pciio_info_einfo_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_einfo); -} - -pciio_space_t -pciio_info_bar_space_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_space; -} - -iopaddr_t -pciio_info_bar_base_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_base; -} - -size_t -pciio_info_bar_size_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_size; -} - -iopaddr_t -pciio_info_rom_base_get(pciio_info_t info) -{ - return info->c_rbase; -} - -size_t -pciio_info_rom_size_get(pciio_info_t info) -{ - return info->c_rsize; -} - - -/* ===================================================================== - * GENERIC PCI INITIALIZATION FUNCTIONS - */ - -/* - * pciioinit: called once during device driver - * initializtion if this driver is configured into - * the system. - */ -void -pciio_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("pciio_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (pciio_registry == NULL) { - cp = cdl_new(EDGE_LBL_PCI, "vendor", "device"); - if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(pciio_registry != NULL); -} - -/* - * pciioattach: called for each vertex in the graph - * that is a PCI provider. - */ -/*ARGSUSED */ -int -pciio_attach(devfs_handle_t pciio) -{ -#if DEBUG && ATTACH_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("%v: pciio_attach\n", pciio); -#else - printk("0x%x: pciio_attach\n", pciio); -#endif -#endif - return 0; -} - -/* - * Associate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) -{ - hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); -} - -/* - * Disassociate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_unregister(devfs_handle_t provider) -{ - arbitrary_info_t ainfo; - - hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); -} - -/* - * Obtain a pointer to the pciio_provider functions for a specified Crosstalk - * provider. - */ -pciio_provider_t * -pciio_provider_fns_get(devfs_handle_t provider) -{ - arbitrary_info_t ainfo = 0; - - (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo); - return (pciio_provider_t *) ainfo; -} - -/*ARGSUSED4 */ -int -pciio_driver_register( - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine might call - * pciio_driver_register before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - return cdl_add_driver(pciio_registry, - vendor_id, device_id, - driver_prefix, flags, NULL); -} - -/* - * Remove an initialization function. - */ -void -pciio_driver_unregister( - char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called register; so - * we can assume we have a registry here. - */ - ASSERT(pciio_registry != NULL); - - cdl_del_driver(pciio_registry, driver_prefix, NULL); -} - -/* - * Set the slot status for a device supported by the - * driver being registered. - */ -void -pciio_driver_reg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Set the slot status for a device supported by the - * driver being unregistered. - */ -void -pciio_driver_unreg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -pciio_iterate(char *driver_prefix, - pciio_iter_f * func) -{ - /* a driver's init routine might call - * pciio_iterate before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - ASSERT(pciio_registry != NULL); - - cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func); -} - -devfs_handle_t -pciio_device_register( - devfs_handle_t connectpt, /* vertex for /hw/.../pciio/%d */ - devfs_handle_t master, /* card's master ASIC (PCI provider) */ - pciio_slot_t slot, /* card's slot */ - pciio_function_t func, /* card's func */ - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id) -{ - return pciio_device_info_register - (connectpt, pciio_device_info_new (NULL, master, slot, func, - vendor_id, device_id)); -} - -void -pciio_device_unregister(devfs_handle_t pconn) -{ - DEV_FUNC(pconn,device_unregister)(pconn); -} - -pciio_info_t -pciio_device_info_new( - pciio_info_t pciio_info, - devfs_handle_t master, - pciio_slot_t slot, - pciio_function_t func, - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id) -{ - if (!pciio_info) - GET_NEW(pciio_info); - ASSERT(pciio_info != NULL); - - pciio_info->c_slot = slot; - pciio_info->c_func = func; - pciio_info->c_vendor = vendor_id; - pciio_info->c_device = device_id; - pciio_info->c_master = master; - pciio_info->c_mfast = hwgraph_fastinfo_get(master); - pciio_info->c_pops = pciio_provider_fns_get(master); - pciio_info->c_efunc = 0; - pciio_info->c_einfo = 0; - - return pciio_info; -} - -void -pciio_device_info_free(pciio_info_t pciio_info) -{ - /* NOTE : pciio_info is a structure within the pcibr_info - * and not a pointer to memory allocated on the heap !! - */ - BZERO((char *)pciio_info,sizeof(pciio_info)); -} - -devfs_handle_t -pciio_device_info_register( - devfs_handle_t connectpt, /* vertex at center of bus */ - pciio_info_t pciio_info) /* details about the connectpt */ -{ - char name[32]; - devfs_handle_t pconn; - int device_master_set(devfs_handle_t, devfs_handle_t); - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - if (GRAPH_SUCCESS != - hwgraph_path_add(connectpt, name, &pconn)) - return pconn; - - pciio_info->c_vertex = pconn; - pciio_info_set(pconn, pciio_info); -#ifdef DEBUG_PCIIO - { - int pos; - char dname[256]; - pos = devfs_generate_path(pconn, dname, 256); - printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); - } -#endif /* DEBUG_PCIIO */ - - /* - * create link to our pci provider - */ - - device_master_set(pconn, pciio_info->c_master); - -#if USRPCI - /* - * Call into usrpci provider to let it initialize for - * the given slot. - */ - if (pciio_info->c_slot != PCIIO_SLOT_NONE) - usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot); -#endif - - return pconn; -} - -void -pciio_device_info_unregister(devfs_handle_t connectpt, - pciio_info_t pciio_info) -{ - char name[32]; - devfs_handle_t pconn; - - if (!pciio_info) - return; - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - hwgraph_edge_remove(connectpt,name,&pconn); - pciio_info_set(pconn,0); - - /* Remove the link to our pci provider */ - hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); - - - hwgraph_vertex_unref(pconn); - hwgraph_vertex_destroy(pconn); - -} -/* Add the pci card inventory information to the hwgraph - */ -static void -pciio_device_inventory_add(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - - ASSERT(pciio_info); - ASSERT(pciio_info->c_vertex == pconn_vhdl); - - /* Donot add inventory for non-existent devices */ - if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE) || - (pciio_info->c_device == PCIIO_DEVICE_ID_NONE)) - return; - device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP, - pciio_info->c_vendor,pciio_info->c_device, - pciio_info->c_slot); -} - -static void -pciio_device_inventory_remove(devfs_handle_t pconn_vhdl) -{ -#ifdef LATER - hwgraph_inventory_remove(pconn_vhdl,-1,-1,-1,-1,-1); -#endif -} - -/*ARGSUSED */ -int -pciio_device_attach(devfs_handle_t pconn, - int drv_flags) -{ - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - - pciio_device_inventory_add(pconn); - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); -} - -int -pciio_device_detach(devfs_handle_t pconn, - int drv_flags) -{ - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - pciio_device_inventory_remove(pconn); - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_del_connpt(pciio_registry, vendor_id, device_id, - pconn, drv_flags)); - -} - -/* - * pciio_error_register: - * arrange for a function to be called with - * a specified first parameter plus other - * information when an error is encountered - * and traced to the pci slot corresponding - * to the connection point pconn. - * - * may also be called with a null function - * pointer to "unregister" the error handler. - * - * NOTE: subsequent calls silently overwrite - * previous data for this vertex. We assume that - * cooperating drivers, well, cooperate ... - */ -void -pciio_error_register(devfs_handle_t pconn, - error_handler_f *efunc, - error_handler_arg_t einfo) -{ - pciio_info_t pciio_info; - - pciio_info = pciio_info_get(pconn); - ASSERT(pciio_info != NULL); - pciio_info->c_efunc = efunc; - pciio_info->c_einfo = einfo; -} - -/* - * Check if any device has been found in this slot, and return - * true or false - * vhdl is the vertex for the slot - */ -int -pciio_slot_inuse(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - - ASSERT(pciio_info); - ASSERT(pciio_info->c_vertex == pconn_vhdl); - if (pciio_info->c_vendor) { - /* - * Non-zero value for vendor indicate - * a board being found in this slot. - */ - return 1; - } - return 0; -} - -int -pciio_dma_enabled(devfs_handle_t pconn_vhdl) -{ - return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); -} - -/* - * These are complementary Linux interfaces that takes in a pci_dev * as the - * first arguement instead of devfs_handle_t. - */ -iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); -pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); -void snia_pciio_dmamap_free(pciio_dmamap_t); -iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -void snia_pciio_dmamap_done(pciio_dmamap_t); -pciio_endian_t snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, - pciio_endian_t desired_end); - -#include -EXPORT_SYMBOL(snia_pciio_dmatrans_addr); -EXPORT_SYMBOL(snia_pciio_dmamap_alloc); -EXPORT_SYMBOL(snia_pciio_dmamap_free); -EXPORT_SYMBOL(snia_pciio_dmamap_addr); -EXPORT_SYMBOL(snia_pciio_dmamap_done); -EXPORT_SYMBOL(snia_pciio_endian_set); - -pciio_endian_t -snia_pciio_endian_set(struct pci_dev *pci_dev, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return DEV_FUNC(dev, endian_set) - (dev, device_end, desired_end); -} - -iopaddr_t -snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - -pciio_dmamap_t -snia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - -void -snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_free) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) - (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); -} - -void -snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_done) - (CAST_DMAMAP(pciio_dmamap)); -} - diff -Nur linux-2.4.19/arch/ia64/sn/io/sgi_if.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sgi_if.c --- linux-2.4.19/arch/ia64/sn/io/sgi_if.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sgi_if.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -20,14 +20,50 @@ #include #include +unsigned char Is_pic_on_this_nasid[512]; /* non-0 when this is a pic shub */ + void * snia_kmem_zalloc(size_t size, int flag) { void *ptr = kmalloc(size, GFP_KERNEL); - BZERO(ptr, size); - return ptr; + if ( ptr ) + BZERO(ptr, size); + return(ptr); } +void +snia_kmem_free(void *ptr, size_t size) +{ + kfree(ptr); +} + +int +nic_vertex_info_match(devfs_handle_t v, char *s) +{ + /* we don't support this */ + return(0); +} + +/* + * the alloc/free_node routines do a simple kmalloc for now .. + */ +void * +snia_kmem_alloc_node(register size_t size, register int flags, cnodeid_t node) +{ + /* someday will Allocate on node 'node' */ + return(kmalloc(size, GFP_KERNEL)); +} + +void * +snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node) +{ + void *ptr = kmalloc(size, GFP_KERNEL); + if ( ptr ) + BZERO(ptr, size); + return(ptr); +} + + #define xtod(c) ((c) <= '9' ? '0' - (c) : 'a' - (c) - 10) long atoi(register char *p) @@ -66,4 +102,112 @@ } } return (neg ? n : -n); +} + +char * +strtok_r(char *string, const char *sepset, char **lasts) +{ + register char *q, *r; + + /*first or subsequent call*/ + if (string == NULL) + string = *lasts; + + if(string == 0) /* return if no tokens remaining */ + return(NULL); + + q = string + strspn(string, sepset); /* skip leading separators */ + + if(*q == '\0') { /* return if no tokens remaining */ + *lasts = 0; /* indicate this is last token */ + return(NULL); + } + + if((r = strpbrk(q, sepset)) == NULL) /* move past token */ + *lasts = 0; /* indicate this is last token */ + else { + *r = '\0'; + *lasts = r+1; + } + return(q); +} + +/* + * print_register() allows formatted printing of bit fields. individual + * bit fields are described by a struct reg_desc, multiple bit fields within + * a single word can be described by multiple reg_desc structures. + * %r outputs a string of the format "" + * %R outputs a string of the format "0x%x" + * + * The fields in a reg_desc are: + * unsigned long long rd_mask; An appropriate mask to isolate the bit field + * within a word, and'ed with val + * + * int rd_shift; A shift amount to be done to the isolated + * bit field. done before printing the isolate + * bit field with rd_format and before searching + * for symbolic value names in rd_values + * + * char *rd_name; If non-null, a bit field name to label any + * out from rd_format or searching rd_values. + * if neither rd_format or rd_values is non-null + * rd_name is printed only if the isolated + * bit field is non-null. + * + * char *rd_format; If non-null, the shifted bit field value + * is printed using this format. + * + * struct reg_values *rd_values; If non-null, a pointer to a table + * matching numeric values with symbolic names. + * rd_values are searched and the symbolic + * value is printed if a match is found, if no + * match is found "???" is printed. + * + */ + +void +print_register(unsigned long long reg, struct reg_desc *addr) +{ + register struct reg_desc *rd; + register struct reg_values *rv; + unsigned long long field; + int any; + + printk("<"); + any = 0; + for (rd = addr; rd->rd_mask; rd++) { + field = reg & rd->rd_mask; + field = (rd->rd_shift > 0) ? field << rd->rd_shift : field >> -rd->rd_shift; + if (any && (rd->rd_format || rd->rd_values || (rd->rd_name && field))) + printk(","); + if (rd->rd_name) { + if (rd->rd_format || rd->rd_values || field) { + printk("%s", rd->rd_name); + any = 1; + } + if (rd->rd_format || rd->rd_values) { + printk("="); + any = 1; + } + } + /* You can have any format so long as it is %x */ + if (rd->rd_format) { + printk("%llx", field); + any = 1; + if (rd->rd_values) + printk(":"); + } + if (rd->rd_values) { + any = 1; + for (rv = rd->rd_values; rv->rv_name; rv++) { + if (field == rv->rv_value) { + printk("%s", rv->rv_name); + break; + } + } + if (rv->rv_name == NULL) + printk("???"); + } + } + printk(">\n"); } diff -Nur linux-2.4.19/arch/ia64/sn/io/sgi_io_init.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sgi_io_init.c --- linux-2.4.19/arch/ia64/sn/io/sgi_io_init.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sgi_io_init.c Wed Dec 31 16:00:00 1969 @@ -1,336 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void mlreset(int ); -extern int init_hcl(void); -extern void klgraph_hack_init(void); -extern void hubspc_init(void); -extern void pciio_init(void); -extern void pcibr_init(void); -extern void xtalk_init(void); -extern void xbow_init(void); -extern void xbmon_init(void); -extern void pciiox_init(void); -extern void usrpci_init(void); -extern void ioc3_init(void); -extern void initialize_io(void); -#if defined(CONFIG_IA64_SGI_SN1) -extern void intr_clear_all(nasid_t); -#endif -extern void klhwg_add_all_modules(devfs_handle_t); -extern void klhwg_add_all_nodes(devfs_handle_t); - -void sn_mp_setup(void); -extern devfs_handle_t hwgraph_root; -extern void io_module_init(void); -extern void pci_bus_cvlink_init(void); -extern void temp_hack(void); - -extern int pci_bus_to_hcl_cvlink(void); - -/* #define DEBUG_IO_INIT 1 */ -#ifdef DEBUG_IO_INIT -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_IO_INIT */ - -/* - * per_hub_init - * - * This code is executed once for each Hub chip. - */ -static void -per_hub_init(cnodeid_t cnode) -{ - nasid_t nasid; - nodepda_t *npdap; - ii_icmr_u_t ii_icmr; - ii_ibcr_u_t ii_ibcr; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - ASSERT(nasid != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); - - npdap = NODEPDA(cnode); - -#if defined(CONFIG_IA64_SGI_SN1) - /* initialize per-node synergy perf instrumentation */ - npdap->synergy_perf_enabled = 0; /* off by default */ - npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; - npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; - npdap->synergy_inactive_intervals = 0; - npdap->synergy_active_intervals = 0; - npdap->synergy_perf_data = NULL; - npdap->synergy_perf_first = NULL; -#endif /* CONFIG_IA64_SGI_SN1 */ - - - /* - * Set the total number of CRBs that can be used. - */ - ii_icmr.ii_icmr_regval= 0x0; - ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF; - REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); - - /* - * Set the number of CRBs that both of the BTEs combined - * can use minus 1. - */ - ii_ibcr.ii_ibcr_regval= 0x0; - ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; - REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); - - /* - * Set CRB timeout to be 10ms. - */ - REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 ); - REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); - - -#if defined(CONFIG_IA64_SGI_SN1) - /* Reserve all of the hardwired interrupt levels. */ - intr_reserve_hardwired(cnode); -#endif - - /* Initialize error interrupts for this hub. */ - hub_error_init(cnode); -} - -/* - * This routine is responsible for the setup of all the IRIX hwgraph style - * stuff that's been pulled into linux. It's called by sn_pci_find_bios which - * is called just before the generic Linux PCI layer does its probing (by - * platform_pci_fixup aka sn_pci_fixup). - * - * It is very IMPORTANT that this call is only made by the Master CPU! - * - */ - -void -sgi_master_io_infr_init(void) -{ - int cnode; - - /* - * Do any early init stuff .. einit_tbl[] etc. - */ - DBG("--> sgi_master_io_infr_init: calling init_hcl().\n"); - init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ - -#ifdef Colin - -printk("Testing out Xbridge Access .. if it hangs Xbridge is not init yet.\n"); -printk(" Reading Xbridge WID at address 0xc00000080f000000 0x%p\n", (* (volatile uint32_t *)(0xc00000080f000000))); - -printk("Testing out PCI Address Space Accesses\n"); -printk(" Testing PCI Config Read Byte: address 0xc00000080f020000 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020000))); - -printk(" Testing PCI Config Read Byte: address 0xc00000080f020001 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020001))); - -printk(" Testing PCI Config Read Byte: address 0xc00000080f020002 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020002))); - -printk(" Testing PCI Config Read Byte: address 0xc00000080f020003 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020003))); - -printk(" Testing PCI Config Read Byte: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020004))); - -printk(" Testing PCI Config Read Byte: address 0xc00000080f020005 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020005))); - -printk(" Testing PCI Config Read Byte: address 0xc00000080f020006 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020006))); - -printk(" Testing PCI Config Read Byte: address 0xc00000080f020007 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020007))); - -printk(" Testing PCI Config Word: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020004))); - -printk(" Testing PCI Config Word: address 0xc00000080f020008 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020008))); - -#endif - - /* - * initialize the Linux PCI to xwidget vertexes .. - */ - DBG("--> sgi_master_io_infr_init: calling pci_bus_cvlink_init().\n"); - pci_bus_cvlink_init(); - -#ifdef BRINGUP -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Hack to provide statically initialzed klgraph entries. - */ - DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); - klgraph_hack_init(); -#endif /* CONFIG_IA64_SGI_SN1 */ -#endif /* BRINGUP */ - - /* - * This is the Master CPU. Emulate mlsetup and main.c in Irix. - */ - DBG("--> sgi_master_io_infr_init: calling mlreset(0).\n"); - mlreset(0); /* Master .. */ - - /* - * allowboot() is called by kern/os/main.c in main() - * Emulate allowboot() ... - * per_cpu_init() - only need per_hub_init() - * cpu_io_setup() - Nothing to do. - * - */ - DBG("--> sgi_master_io_infr_init: calling sn_mp_setup().\n"); - sn_mp_setup(); - - DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n"); - for (cnode = 0; cnode < numnodes; cnode++) { - per_hub_init(cnode); - } - - /* We can do headless hub cnodes here .. */ - - /* - * io_init[] stuff. - * - * Get SGI IO Infrastructure drivers to init and register with - * each other etc. - */ - - DBG("--> sgi_master_io_infr_init: calling hubspc_init()\n"); - hubspc_init(); - - DBG("--> sgi_master_io_infr_init: calling pciio_init()\n"); - pciio_init(); - - DBG("--> sgi_master_io_infr_init: calling pcibr_init()\n"); - pcibr_init(); - - DBG("--> sgi_master_io_infr_init: calling xtalk_init()\n"); - xtalk_init(); - - DBG("--> sgi_master_io_infr_init: calling xbow_init()\n"); - xbow_init(); - - DBG("--> sgi_master_io_infr_init: calling xbmon_init()\n"); - xbmon_init(); - - DBG("--> sgi_master_io_infr_init: calling pciiox_init()\n"); - pciiox_init(); - - DBG("--> sgi_master_io_infr_init: calling usrpci_init()\n"); - usrpci_init(); - - DBG("--> sgi_master_io_infr_init: calling ioc3_init()\n"); - ioc3_init(); - - /* - * - * Our IO Infrastructure drivers are in place .. - * Initialize the whole IO Infrastructure .. xwidget/device probes. - * - */ - DBG("--> sgi_master_io_infr_init: Start Probe and IO Initialization\n"); - initialize_io(); - - DBG("--> sgi_master_io_infr_init: Setting up SGI IO Links for Linux PCI\n"); - pci_bus_to_hcl_cvlink(); - -#ifdef CONFIG_PCIBA - DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); - pciba_init(); -#endif - - DBG("--> Leave sgi_master_io_infr_init: DONE setting up SGI Links for PCI\n"); -} - -/* - * sgi_slave_io_infr_init - This routine must be called on all cpus except - * the Master CPU. - */ -void -sgi_slave_io_infr_init(void) -{ - /* Emulate cboot() .. */ - mlreset(1); /* This is a slave cpu */ - - // per_hub_init(0); /* Need to get and send in actual cnode number */ - - /* Done */ -} - -/* - * One-time setup for MP SN. - * Allocate per-node data, slurp prom klconfig information and - * convert it to hwgraph information. - */ -void -sn_mp_setup(void) -{ - cnodeid_t cnode; - cpuid_t cpu; - - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - /* Skip holes in CPU space */ - if (cpu_enabled(cpu)) { - init_platform_pda(cpu); - } - } - - /* - * Initialize platform-dependent vertices in the hwgraph: - * module - * node - * cpu - * memory - * slot - * hub - * router - * xbow - */ - - DBG("sn_mp_io_setup: calling io_module_init()\n"); - io_module_init(); /* Use to be called module_init() .. */ - - DBG("sn_mp_setup: calling klhwg_add_all_modules()\n"); - klhwg_add_all_modules(hwgraph_root); - DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n"); - klhwg_add_all_nodes(hwgraph_root); - - - for (cnode = 0; cnode < numnodes; cnode++) { - - /* - * This routine clears the Hub's Interrupt registers. - */ - /* - * We need to move this intr_clear_all() routine - * from SN/intr.c to a more appropriate file. - * Talk to Al Mayer. - */ -#if defined(CONFIG_IA64_SGI_SN1) - intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); -#endif - /* now init the hub */ - // per_hub_init(cnode); - - } - -#if defined(CONFIG_IA64_SGI_SN1) - synergy_perf_init(); -#endif - -} diff -Nur linux-2.4.19/arch/ia64/sn/io/sgi_io_sim.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sgi_io_sim.c --- linux-2.4.19/arch/ia64/sn/io/sgi_io_sim.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sgi_io_sim.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -71,6 +71,9 @@ */ static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL; nasid_t console_nasid = (nasid_t)-1; +#if !defined(CONFIG_IA64_SGI_SN1) +char master_baseio_wid; +#endif static char console_wid; static char console_pcislot; @@ -92,6 +95,7 @@ return 0; } +#if defined(CONFIG_IA64_SGI_SN1) int is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) { @@ -111,6 +115,29 @@ return 0; } } +#else +int +is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) +{ + extern nasid_t master_baseio_nasid; + + /* + * If the widget numbers are different, we're not the master. + */ + if (test_wid != (xwidgetnum_t)master_baseio_wid) { + return 0; + } + + /* + * If the NASIDs are the same or equivalent, we're the master. + */ + if (check_nasid_equiv(test_nasid, master_baseio_nasid)) { + return 1; + } else { + return 0; + } +} +#endif /* CONFIG_IA64_SGI_SN1 */ /* * Routines provided by ml/SN/nvram.c diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/Makefile --- linux-2.4.19/arch/ia64/sn/io/sn1/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/Makefile Mon Dec 30 14:16:56 2002 @@ -0,0 +1,25 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn1 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +O_TARGET := snio.o + +export-objs := pciio.o + +obj-$(CONFIG_IA64_SGI_SN1) += ml_SN_intr.o mem_refcnt.o hubcounters.o \ + ip37.o huberror.o hub_intr.o pcibr.o \ + eeprom.o l1.o l1_command.o pciio.o \ + klconflib.o klgraph.o \ + efi-rtc.o xbow.o xtalk.o \ + ml_SN_init.o ml_iograph.o module.o \ + pci_bus_cvlink.o sgi_io_init.o + + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/eeprom.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/eeprom.c --- linux-2.4.19/arch/ia64/sn/io/sn1/eeprom.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/eeprom.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1421 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * WARNING: There is more than one copy of this file in different isms. + * All copies must be kept exactly in sync. + * Do not modify this file without also updating the following: + * + * irix/kern/io/eeprom.c + * stand/arcs/lib/libsk/ml/eeprom.c + * stand/arcs/lib/libkl/io/eeprom.c + * + * (from time to time they might not be in sync but that's due to bringup + * activity - this comment is to remind us that they eventually have to + * get back together) + * + * eeprom.c + * + * access to board-mounted EEPROMs via the L1 system controllers + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(EEPROM_DEBUG) +#define db_printf(x) printk x +#else +#define db_printf(x) printk x +#endif + +#define BCOPY(x,y,z) memcpy(y,x,z) + +#define UNDERSCORE 0 /* don't convert underscores to hyphens */ +#define HYPHEN 1 /* convert underscores to hyphens */ + +void copy_ascii_field( char *to, char *from, int length, + int change_underscore ); +uint64_t generate_unique_id( char *sn, int sn_len ); +uchar_t char_to_base36( char c ); +int nicify( char *dst, eeprom_brd_record_t *src ); +static void int64_to_hex_string( char *out, uint64_t val ); + +// extern int router_lock( net_vec_t, int, int ); +// extern int router_unlock( net_vec_t ); +#define ROUTER_LOCK(p) // router_lock(p, 10000, 3000000) +#define ROUTER_UNLOCK(p) // router_unlock(p) + +#define IP27LOG_OVNIC "OverrideNIC" + + +/* the following function converts an EEPROM record to a close facsimile + * of the string returned by reading a Dallas Semiconductor NIC (see + * one of the many incarnations of nic.c for details on that driver) + */ +int nicify( char *dst, eeprom_brd_record_t *src ) +{ + int field_len; + uint64_t unique_id; + char *cur_dst = dst; + eeprom_board_ia_t *board; + + board = src->board_ia; + ASSERT( board ); /* there should always be a board info area */ + + /* copy part number */ + strcpy( cur_dst, "Part:" ); + cur_dst += strlen( cur_dst ); + ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK) + == FIELD_FORMAT_ASCII ); + field_len = board->part_num_tl & FIELD_LENGTH_MASK; + copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN ); + cur_dst += field_len; + + /* copy product name */ + strcpy( cur_dst, ";Name:" ); + cur_dst += strlen( cur_dst ); + ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII ); + field_len = board->product_tl & FIELD_LENGTH_MASK; + copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE ); + cur_dst += field_len; + + /* copy serial number */ + strcpy( cur_dst, ";Serial:" ); + cur_dst += strlen( cur_dst ); + ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK) + == FIELD_FORMAT_ASCII ); + field_len = board->serial_num_tl & FIELD_LENGTH_MASK; + copy_ascii_field( cur_dst, board->serial_num, field_len, + HYPHEN); + + cur_dst += field_len; + + /* copy revision */ + strcpy( cur_dst, ";Revision:"); + cur_dst += strlen( cur_dst ); + ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK) + == FIELD_FORMAT_ASCII ); + field_len = board->board_rev_tl & FIELD_LENGTH_MASK; + copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN ); + cur_dst += field_len; + + /* EEPROMs don't have equivalents for the Group, Capability and + * Variety fields, so we pad these with 0's + */ + strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" ); + cur_dst += strlen( cur_dst ); + + /* use the board serial number to "fake" a laser id */ + strcpy( cur_dst, ";Laser:" ); + cur_dst += strlen( cur_dst ); + unique_id = generate_unique_id( board->serial_num, + board->serial_num_tl & FIELD_LENGTH_MASK ); + int64_to_hex_string( cur_dst, unique_id ); + strcat( dst, ";" ); + + return 1; +} + + +/* These functions borrow heavily from chars2* in nic.c + */ +void copy_ascii_field( char *to, char *from, int length, + int change_underscore ) +{ + int i; + for( i = 0; i < length; i++ ) { + + /* change underscores to hyphens if requested */ + if( from[i] == '_' && change_underscore == HYPHEN ) + to[i] = '-'; + + /* ; and ; are separators, so mustn't appear within + * a field */ + else if( from[i] == ':' || from[i] == ';' ) + to[i] = '?'; + + /* I'm not sure why or if ASCII character 0xff would + * show up in an EEPROM field, but the NIC parsing + * routines wouldn't like it if it did... so we + * get rid of it, just in case. */ + else if( (unsigned char)from[i] == (unsigned char)0xff ) + to[i] = ' '; + + /* unprintable characters are replaced with . */ + else if( from[i] < ' ' || from[i] >= 0x7f ) + to[i] = '.'; + + /* otherwise, just copy the character */ + else + to[i] = from[i]; + } + + if( i == 0 ) { + to[i] = ' '; /* return at least a space... */ + i++; + } + to[i] = 0; /* terminating null */ +} + +/* Note that int64_to_hex_string currently only has a big-endian + * implementation. + */ +#ifdef _MIPSEB +static void int64_to_hex_string( char *out, uint64_t val ) +{ + int i; + uchar_t table[] = "0123456789abcdef"; + uchar_t *byte_ptr = (uchar_t *)&val; + for( i = 0; i < sizeof(uint64_t); i++ ) { + out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ]; + out[i*2+1] = table[ (*byte_ptr) & 0x0f ]; + byte_ptr++; + } + out[i*2] = '\0'; +} + +#else /* little endian */ + +static void int64_to_hex_string( char *out, uint64_t val ) +{ + + + printk("int64_to_hex_string needs a little-endian implementation.\n"); +} +#endif /* _MIPSEB */ + +/* Convert a standard ASCII serial number to a unique integer + * id number by treating the serial number string as though + * it were a base 36 number + */ +uint64_t generate_unique_id( char *sn, int sn_len ) +{ + int uid = 0; + int i; + + #define VALID_BASE36(c) ((c >= '0' && c <='9') \ + || (c >= 'A' && c <='Z') \ + || (c >= 'a' && c <='z')) + + for( i = 0; i < sn_len; i++ ) { + if( !VALID_BASE36(sn[i]) ) + continue; + uid *= 36; + uid += char_to_base36( sn[i] ); + } + + if( uid == 0 ) + return rtc_time(); + + return uid; +} + +uchar_t char_to_base36( char c ) +{ + uchar_t val; + + if( c >= '0' && c <= '9' ) + val = (c - '0'); + + else if( c >= 'A' && c <= 'Z' ) + val = (c - 'A' + 10); + + else if( c >= 'a' && c <= 'z' ) + val = (c - 'a' + 10); + + else val = 0; + + return val; +} + + +/* given a pointer to the three-byte little-endian EEPROM representation + * of date-of-manufacture, this function translates to a big-endian + * integer format + */ +int eeprom_xlate_board_mfr_date( uchar_t *src ) +{ + int rval = 0; + rval += *src; src++; + rval += ((int)(*src) << 8); src ++; + rval += ((int)(*src) << 16); + return rval; +} + + +int eeprom_str( char *nic_str, nasid_t nasid, int component ) +{ + eeprom_brd_record_t eep; + eeprom_board_ia_t board; + eeprom_chassis_ia_t chassis; + int r; + + if( (component & C_DIMM) == C_DIMM ) { + /* this function isn't applicable to DIMMs */ + return EEP_PARAM; + } + else { + eep.board_ia = &board; + eep.spd = NULL; + if( !(component & SUBORD_MASK) ) + eep.chassis_ia = &chassis; /* only main boards have a chassis + * info area */ + else + eep.chassis_ia = NULL; + } + + switch( component & BRICK_MASK ) { + case C_BRICK: + r = cbrick_eeprom_read( &eep, nasid, component ); + break; + case IO_BRICK: + r = iobrick_eeprom_read( &eep, nasid, component ); + break; + default: + return EEP_PARAM; /* must be an invalid component */ + } + if( r ) + return r; + if( !nicify( nic_str, &eep ) ) + return EEP_NICIFY; + + return EEP_OK; +} + +int vector_eeprom_str( char *nic_str, nasid_t nasid, + int component, net_vec_t path ) +{ + eeprom_brd_record_t eep; + eeprom_board_ia_t board; + eeprom_chassis_ia_t chassis; + int r; + + eep.board_ia = &board; + if( !(component & SUBORD_MASK) ) + eep.chassis_ia = &chassis; /* only main boards have a chassis + * info area */ + else + eep.chassis_ia = NULL; + + if( !(component & VECTOR) ) + return EEP_PARAM; + + if( (r = vector_eeprom_read( &eep, nasid, path, component )) ) + return r; + + if( !nicify( nic_str, &eep ) ) + return EEP_NICIFY; + + return EEP_OK; +} + + +int is_iobrick( int nasid, int widget_num ) +{ + uint32_t wid_reg; + int part_num, mfg_num; + + /* Read the widget's WIDGET_ID register to get + * its part number and mfg number + */ + wid_reg = *(volatile int32_t *) + (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID); + + part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; + mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT; + + /* Is this the "xbow part" of an XBridge? If so, this + * widget is definitely part of an I/O brick. + */ + if( part_num == XXBOW_WIDGET_PART_NUM && + mfg_num == XXBOW_WIDGET_MFGR_NUM ) + + return 1; + + /* Is this a "bridge part" of an XBridge? If so, once + * again, we know this widget is part of an I/O brick. + */ + if( part_num == XBRIDGE_WIDGET_PART_NUM && + mfg_num == XBRIDGE_WIDGET_MFGR_NUM ) + + return 1; + + return 0; +} + + +int cbrick_uid_get( nasid_t nasid, uint64_t *uid ) +{ + char uid_str[32]; + char msg[BRL1_QSIZE]; + int subch, len; + l1sc_t sc; + l1sc_t *scp; + int local = (nasid == get_nasid()); + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + + /* If the promlog variable pointed to by IP27LOG_OVNIC is set, + * use that value for the cbrick UID rather than the EEPROM + * serial number. + */ +#ifdef LOG_GETENV + if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 ) + { + /* We successfully read IP27LOG_OVNIC, so return it as the UID. */ + db_printf(( "cbrick_uid_get:" + "Overriding UID with environment variable %s\n", + IP27LOG_OVNIC )); + *uid = strtoull( uid_str, NULL, 0 ); + return EEP_OK; + } +#endif + + /* If this brick is retrieving its own uid, use the local l1sc_t to + * arbitrate access to the l1; otherwise, set up a new one. + */ + if( local ) { + scp = get_l1sc(); + } + else { + scp = ≻ + sc_init( &sc, nasid, BRL1_LOCALHUB_UART ); + } + + /* fill in msg with the opcode & params */ + BZERO( msg, BRL1_QSIZE ); + if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) + return EEP_L1; + + if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_SER_NUM, 0 )) < 0 ) + { + sc_close( scp, subch ); + return( EEP_L1 ); + } + + /* send the request to the L1 */ + if( sc_command( scp, subch, msg, msg, &len ) ) { + sc_close( scp, subch ); + return( EEP_L1 ); + } + + /* free up subchannel */ + sc_close(scp, subch); + + /* check response */ + if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) + { + return( EEP_L1 ); + } + + *uid = generate_unique_id( uid_str, strlen( uid_str ) ); + + return EEP_OK; +} + + +int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ) +{ + char uid_str[32]; + char msg[BRL1_QSIZE]; + int subch, len; + l1sc_t sc; + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + +#define FAIL \ + { \ + *uid = rtc_time(); \ + printk( "rbrick_uid_get failed; using current time as uid\n" ); \ + return EEP_OK; \ + } + + ROUTER_LOCK(path); + sc_init( &sc, nasid, path ); + + /* fill in msg with the opcode & params */ + BZERO( msg, BRL1_QSIZE ); + if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) { + ROUTER_UNLOCK(path); + FAIL; + } + + if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_SER_NUM, 0 )) < 0 ) + { + ROUTER_UNLOCK(path); + sc_close( &sc, subch ); + FAIL; + } + + /* send the request to the L1 */ + if( sc_command( &sc, subch, msg, msg, &len ) ) { + ROUTER_UNLOCK(path); + sc_close( &sc, subch ); + FAIL; + } + + /* free up subchannel */ + ROUTER_UNLOCK(path); + sc_close(&sc, subch); + + /* check response */ + if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) + { + FAIL; + } + + *uid = generate_unique_id( uid_str, strlen( uid_str ) ); + + return EEP_OK; +} + +int iobrick_uid_get( nasid_t nasid, uint64_t *uid ) +{ + eeprom_brd_record_t eep; + eeprom_board_ia_t board; + eeprom_chassis_ia_t chassis; + int r; + + eep.board_ia = &board; + eep.chassis_ia = &chassis; + eep.spd = NULL; + + r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); + if( r != EEP_OK ) { + *uid = rtc_time(); + return r; + } + + *uid = generate_unique_id( board.serial_num, + board.serial_num_tl & FIELD_LENGTH_MASK ); + + return EEP_OK; +} + + +int ibrick_mac_addr_get( nasid_t nasid, char *eaddr ) +{ + eeprom_brd_record_t eep; + eeprom_board_ia_t board; + eeprom_chassis_ia_t chassis; + int r; + char *tmp; + + eep.board_ia = &board; + eep.chassis_ia = &chassis; + eep.spd = NULL; + + r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); + if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) { + db_printf(( "ibrick_mac_addr_get: " + "Couldn't read MAC address from EEPROM\n" )); + return EEP_L1; + } + else { + /* successfully read info area */ + int ix; + tmp = board.mac_addr; + for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ ) + { + *eaddr++ = *tmp++; + } + *eaddr = '\0'; + } + + return EEP_OK; +} + + +/* + * eeprom_vertex_info_set + * + * Given a vertex handle, a component designation, a starting nasid + * and (in the case of a router) a vector path to the component, this + * function will read the EEPROM and attach the resulting information + * to the vertex in the same string format as that provided by the + * Dallas Semiconductor NIC drivers. If the vertex already has the + * string, this function just returns the string. + */ + +extern char *nic_vertex_info_get( devfs_handle_t ); +extern void nic_vmc_check( devfs_handle_t, char * ); +/* the following were lifted from nic.c - change later? */ +#define MAX_INFO 2048 +#define NEWSZ(ptr,sz) ((ptr) = kern_malloc((sz))) +#define DEL(ptr) (kern_free((ptr))) + +char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, + net_vec_t path ) +{ + char *info_tmp; + int info_len; + char *info; + + /* see if this vertex is already marked */ + info_tmp = nic_vertex_info_get(v); + if (info_tmp) return info_tmp; + + /* get a temporary place for the data */ + NEWSZ(info_tmp, MAX_INFO); + if (!info_tmp) return NULL; + + /* read the EEPROM */ + if( component & R_BRICK ) { + if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK ) + return NULL; + } + else { + if( eeprom_str( info_tmp, nasid, component ) != EEP_OK ) + return NULL; + } + + /* allocate a smaller final place */ + info_len = strlen(info_tmp)+1; + NEWSZ(info, info_len); + if (info) { + strcpy(info, info_tmp); + DEL(info_tmp); + } else { + info = info_tmp; + } + + /* add info to the vertex */ + hwgraph_info_add_LBL(v, INFO_LBL_NIC, + (arbitrary_info_t) info); + + /* see if someone else got there first */ + info_tmp = nic_vertex_info_get(v); + if (info != info_tmp) { + DEL(info); + return info_tmp; + } + + /* export the data */ + hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len); + + /* trigger all matching callbacks */ + nic_vmc_check(v, info); + + return info; +} + + +/********************************************************************* + * + * stubs for use until the Bedrock/L1 link is available + * + */ + +#include + +/* #define EEPROM_TEST */ + +/* fake eeprom reading functions (replace when the BR/L1 communication + * channel is in working order) + */ + + +/* generate a charater in [0-9A-Z]; if an "extra" character is + * specified (such as '_'), include it as one of the possibilities. + */ +char random_eeprom_ch( char extra ) +{ + char ch; + int modval = 36; + if( extra ) + modval++; + + ch = rtc_time() % modval; + + if( ch < 10 ) + ch += '0'; + else if( ch >= 10 && ch < 36 ) + ch += ('A' - 10); + else + ch = extra; + + return ch; +} + +/* create a part number of the form xxx-xxxx-xxx. + * It may be important later to generate different + * part numbers depending on the component we're + * supposed to be "reading" from, so the component + * paramter is provided. + */ +void fake_a_part_number( char *buf, int component ) +{ + int i; + switch( component ) { + + /* insert component-specific routines here */ + + case C_BRICK: + strcpy( buf, "030-1266-001" ); + break; + default: + for( i = 0; i < 12; i++ ) { + if( i == 3 || i == 8 ) + buf[i] = '-'; + else + buf[i] = random_eeprom_ch(0); + } + } +} + + +/* create a six-character serial number */ +void fake_a_serial_number( char *buf, uint64_t ser ) +{ + int i; + static const char hexchars[] = "0123456789ABCDEF"; + + if (ser) { + for( i = 5; i >=0; i-- ) { + buf[i] = hexchars[ser & 0xf]; + ser >>= 4; + } + } + else { + for( i = 0; i < 6; i++ ) + buf[i] = random_eeprom_ch(0); + } +} + + +void fake_a_product_name( uchar_t *format, char* buf, int component ) +{ + switch( component & BRICK_MASK ) { + + case C_BRICK: + if( component & SUBORD_MASK ) { + strcpy( buf, "C_BRICK_SUB" ); + *format = 0xCB; + } + else { + strcpy( buf, "IP35" ); + *format = 0xC4; + } + break; + + case R_BRICK: + if( component & SUBORD_MASK ) { + strcpy( buf, "R_BRICK_SUB" ); + *format = 0xCB; + } + else { + strcpy( buf, "R_BRICK" ); + *format = 0xC7; + } + break; + + case IO_BRICK: + if( component & SUBORD_MASK ) { + strcpy( buf, "IO_BRICK_SUB" ); + *format = 0xCC; + } + else { + strcpy( buf, "IO_BRICK" ); + *format = 0xC8; + } + break; + + default: + strcpy( buf, "UNK_DEVICE" ); + *format = 0xCA; + } +} + + + +int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, + uint64_t ser ) +{ + eeprom_board_ia_t *board; + eeprom_chassis_ia_t *chassis; + int i, cs; + + board = buf->board_ia; + chassis = buf->chassis_ia; + + if( !(component & SUBORD_MASK) ) { + if( !chassis ) + return EEP_PARAM; + chassis->format = 0; + chassis->length = 5; + chassis->type = 0x17; + + chassis->part_num_tl = 0xCC; + fake_a_part_number( chassis->part_num, component ); + chassis->serial_num_tl = 0xC6; + fake_a_serial_number( chassis->serial_num, ser ); + + cs = chassis->format + chassis->length + chassis->type + + chassis->part_num_tl + chassis->serial_num_tl; + for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ ) + cs += chassis->part_num[i]; + for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ ) + cs += chassis->serial_num[i]; + chassis->checksum = 256 - (cs % 256); + } + + if( !board ) + return EEP_PARAM; + board->format = 0; + board->length = 10; + board->language = 0; + board->mfg_date = 1789200; /* noon, 5/26/99 */ + board->manuf_tl = 0xC3; + strcpy( board->manuf, "SGI" ); + + fake_a_product_name( &(board->product_tl), board->product, component ); + + board->serial_num_tl = 0xC6; + fake_a_serial_number( board->serial_num, ser ); + + board->part_num_tl = 0xCC; + fake_a_part_number( board->part_num, component ); + + board->board_rev_tl = 0xC2; + board->board_rev[0] = '0'; + board->board_rev[1] = '1'; + + board->eeprom_size_tl = 0x01; + board->eeprom_size = 1; + + board->temp_waiver_tl = 0xC2; + board->temp_waiver[0] = '0'; + board->temp_waiver[1] = '1'; + + cs = board->format + board->length + board->language + + (board->mfg_date & 0xFF) + + (board->mfg_date & 0xFF00) + + (board->mfg_date & 0xFF0000) + + board->manuf_tl + board->product_tl + board->serial_num_tl + + board->part_num_tl + board->board_rev_tl + + board->board_rev[0] + board->board_rev[1] + + board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl + + board->temp_waiver[0] + board->temp_waiver[1]; + for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ ) + cs += board->manuf[i]; + for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ ) + cs += board->product[i]; + for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ ) + cs += board->serial_num[i]; + for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ ) + cs += board->part_num[i]; + + board->checksum = 256 - (cs % 256); + + return EEP_OK; +} + +#define EEPROM_CHUNKSIZE 64 + +#if defined(EEPROM_DEBUG) +#define RETURN_ERROR \ +{ \ + printk( "read_ia error return, component 0x%x, line %d" \ + ", address 0x%x, ia code 0x%x\n", \ + l1_compt, __LINE__, sc->subch[subch].target, ia_code ); \ + return EEP_L1; \ +} + +#else +#define RETURN_ERROR return(EEP_L1) +#endif + +int read_ia( l1sc_t *sc, int subch, int l1_compt, + int ia_code, char *eep_record ) +{ + char msg[BRL1_QSIZE]; /* message buffer */ + int len; /* number of bytes used in message buffer */ + int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */ + int offset = 0; /* current offset into info area */ + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + + BZERO( msg, BRL1_QSIZE ); + + /* retrieve EEPROM data in 64-byte chunks + */ + + while( ia_len ) + { + /* fill in msg with opcode & params */ + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_EEPROM, 8, + L1_ARG_INT, l1_compt, + L1_ARG_INT, ia_code, + L1_ARG_INT, offset, + L1_ARG_INT, ia_len )) < 0 ) + { + RETURN_ERROR; + } + + /* send the request to the L1 */ + + if( sc_command( sc, subch, msg, msg, &len ) ) { + RETURN_ERROR; + } + + /* check response */ + if( sc_interpret_resp( msg, 5, + L1_ARG_INT, &ia_len, + L1_ARG_UNKNOWN, &len, eep_record ) < 0 ) + { + RETURN_ERROR; + } + + if( ia_len > EEPROM_CHUNKSIZE ) + ia_len = EEPROM_CHUNKSIZE; + + eep_record += EEPROM_CHUNKSIZE; + offset += EEPROM_CHUNKSIZE; + } + + return EEP_OK; +} + + +int read_spd( l1sc_t *sc, int subch, int l1_compt, + eeprom_spd_u *spd ) +{ + char msg[BRL1_QSIZE]; /* message buffer */ + int len; /* number of bytes used in message buffer */ + int resp; /* l1 response code */ + int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */ + int offset = 0; /* current offset into spd record */ + char *spd_p = spd->bytes; /* "thumb" for writing to spd */ + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + + BZERO( msg, BRL1_QSIZE ); + + /* retrieve EEPROM data in 64-byte chunks + */ + + while( spd_len ) + { + /* fill in msg with opcode & params */ + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_EEPROM, 8, + L1_ARG_INT, l1_compt, + L1_ARG_INT, L1_EEP_SPD, + L1_ARG_INT, offset, + L1_ARG_INT, spd_len )) < 0 ) + { + return( EEP_L1 ); + } + + /* send the request to the L1 */ + if( sc_command( sc, subch, msg, msg, &len ) ) { + return( EEP_L1 ); + } + + /* check response */ + if( (resp = sc_interpret_resp( msg, 5, + L1_ARG_INT, &spd_len, + L1_ARG_UNKNOWN, &len, spd_p )) < 0 ) + { + /* + * translate l1 response code to eeprom.c error codes: + * The L1 response will be L1_RESP_NAVAIL if the spd + * can't be read (i.e. the spd isn't physically there). It will + * return L1_RESP_INVAL if the spd exists, but fails the checksum + * test because the eeprom wasn't programmed, programmed incorrectly, + * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present, + * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is + * invalid. + */ + if(resp == L1_RESP_INVAL) { + resp = EEP_BAD_CHECKSUM; + } else { + resp = EEP_L1; + } + return( resp ); + } + + if( spd_len > EEPROM_CHUNKSIZE ) + spd_len = EEPROM_CHUNKSIZE; + + spd_p += EEPROM_CHUNKSIZE; + offset += EEPROM_CHUNKSIZE; + } + return EEP_OK; +} + + +int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt, + eeprom_chassis_ia_t *ia ) +{ + char eep_record[512]; /* scratch area for building up info area */ + char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ + int checksum = 0; /* use to verify eeprom record checksum */ + int i; + + /* Read in info area record from the L1. + */ + if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record ) + != EEP_OK ) + { + return EEP_L1; + } + + /* Now we've got the whole info area. Transfer it to the data structure. + */ + + eep_rec_p = eep_record; + ia->format = *eep_rec_p++; + ia->length = *eep_rec_p++; + if( ia->length == 0 ) { + /* since we're using 8*ia->length-1 as an array index later, make + * sure it's sane. + */ + db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" )); + return EEP_L1; + } + ia->type = *eep_rec_p++; + + ia->part_num_tl = *eep_rec_p++; + + (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); + eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); + + ia->serial_num_tl = *eep_rec_p++; + + BCOPY( eep_rec_p, ia->serial_num, + (ia->serial_num_tl & FIELD_LENGTH_MASK) ); + eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); + + ia->checksum = eep_record[(8 * ia->length) - 1]; + + /* verify checksum */ + eep_rec_p = eep_record; + checksum = 0; + for( i = 0; i < (8 * ia->length); i++ ) { + checksum += *eep_rec_p++; + } + + if( (checksum & 0xff) != 0 ) + { + db_printf(( "read_chassis_ia: bad checksum\n" )); + db_printf(( "read_chassis_ia: target 0x%x uart 0x%lx\n", + sc->subch[subch].target, sc->uart )); + return EEP_BAD_CHECKSUM; + } + + return EEP_OK; +} + + +int read_board_ia( l1sc_t *sc, int subch, int l1_compt, + eeprom_board_ia_t *ia ) +{ + char eep_record[512]; /* scratch area for building up info area */ + char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ + int checksum = 0; /* running checksum total */ + int i; + + BZERO( ia, sizeof( eeprom_board_ia_t ) ); + + /* Read in info area record from the L1. + */ + if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record ) + != EEP_OK ) + { + db_printf(( "read_board_ia: error reading info area from L1\n" )); + return EEP_L1; + } + + /* Now we've got the whole info area. Transfer it to the data structure. + */ + + eep_rec_p = eep_record; + ia->format = *eep_rec_p++; + ia->length = *eep_rec_p++; + if( ia->length == 0 ) { + /* since we're using 8*ia->length-1 as an array index later, make + * sure it's sane. + */ + db_printf(( "read_board_ia: eeprom length byte of ZERO\n" )); + return EEP_L1; + } + ia->language = *eep_rec_p++; + + ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p ); + eep_rec_p += 3; + + ia->manuf_tl = *eep_rec_p++; + + BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) ); + eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK); + + ia->product_tl = *eep_rec_p++; + + BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) ); + eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK); + + ia->serial_num_tl = *eep_rec_p++; + + BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK)); + eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); + + ia->part_num_tl = *eep_rec_p++; + + BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); + eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); + + eep_rec_p++; /* we do not use the FRU file id */ + + ia->board_rev_tl = *eep_rec_p++; + + BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) ); + eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK); + + ia->eeprom_size_tl = *eep_rec_p++; + ia->eeprom_size = *eep_rec_p++; + + ia->temp_waiver_tl = *eep_rec_p++; + + BCOPY( eep_rec_p, ia->temp_waiver, + (ia->temp_waiver_tl & FIELD_LENGTH_MASK) ); + eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK); + + /* if there's more, we must be reading a main board; get + * additional fields + */ + if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { + + ia->ekey_G_tl = *eep_rec_p++; + BCOPY( eep_rec_p, (char *)&ia->ekey_G, + ia->ekey_G_tl & FIELD_LENGTH_MASK ); + eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK); + + ia->ekey_P_tl = *eep_rec_p++; + BCOPY( eep_rec_p, (char *)&ia->ekey_P, + ia->ekey_P_tl & FIELD_LENGTH_MASK ); + eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK); + + ia->ekey_Y_tl = *eep_rec_p++; + BCOPY( eep_rec_p, (char *)&ia->ekey_Y, + ia->ekey_Y_tl & FIELD_LENGTH_MASK ); + eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK); + + /* + * need to get a couple more fields if this is an I brick + */ + if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { + + ia->mac_addr_tl = *eep_rec_p++; + BCOPY( eep_rec_p, ia->mac_addr, + ia->mac_addr_tl & FIELD_LENGTH_MASK ); + eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK); + + ia->ieee1394_cfg_tl = *eep_rec_p++; + BCOPY( eep_rec_p, ia->ieee1394_cfg, + ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK ); + + } + } + + ia->checksum = eep_record[(ia->length * 8) - 1]; + + /* verify checksum */ + eep_rec_p = eep_record; + checksum = 0; + for( i = 0; i < (8 * ia->length); i++ ) { + checksum += *eep_rec_p++; + } + + if( (checksum & 0xff) != 0 ) + { + db_printf(( "read_board_ia: bad checksum\n" )); + db_printf(( "read_board_ia: target 0x%x uart 0x%lx\n", + sc->subch[subch].target, sc->uart )); + return EEP_BAD_CHECKSUM; + } + + return EEP_OK; +} + + +int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp, + int component ) +{ + int r; + uint64_t uid = 0; +#ifdef LOG_GETENV + char uid_str[32]; +#endif + int l1_compt, subch; + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + + /* make sure we're targeting a cbrick */ + if( !(component & C_BRICK) ) + return EEP_PARAM; + + /* If the promlog variable pointed to by IP27LOG_OVNIC is set, + * use that value for the cbrick UID rather than the EEPROM + * serial number. + */ +#ifdef LOG_GETENV + if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 ) + { + db_printf(( "_cbrick_eeprom_read: " + "Overriding UID with environment variable %s\n", + IP27LOG_OVNIC )); + uid = strtoull( uid_str, NULL, 0 ); + } +#endif + + if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) + return EEP_L1; + + if((component & C_DIMM) == C_DIMM) { + l1_compt = L1_EEP_DIMM(component & COMPT_MASK); + r = read_spd(scp,subch,l1_compt, buf->spd); + sc_close(scp,subch); + return(r); + } + + switch( component ) + { + case C_BRICK: + /* c-brick motherboard */ + l1_compt = L1_EEP_NODE; + r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); + if( r != EEP_OK ) { + sc_close( scp, subch ); + db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); + return fake_an_eeprom_record( buf, component, uid ); + } + if( uid ) { + /* If IP27LOG_OVNIC is set, we want to put that value + * in as our UID. */ + fake_a_serial_number( buf->chassis_ia->serial_num, uid ); + buf->chassis_ia->serial_num_tl = 6; + } + break; + + case C_PIMM: + /* one of the PIMM boards */ + l1_compt = L1_EEP_PIMM( component & COMPT_MASK ); + break; + + default: + /* unsupported board type */ + sc_close( scp, subch ); + return EEP_PARAM; + } + + r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); + sc_close( scp, subch ); + if( r != EEP_OK ) + { + db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); + return fake_an_eeprom_record( buf, component, uid ); + } + return EEP_OK; +} + + +int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, + int component ) +{ + l1sc_t *scp; + int local = (nasid == get_nasid()); + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + + /* If this brick is retrieving its own uid, use the local l1sc_t to + * arbitrate access to the l1; otherwise, set up a new one (prom) or + * use an existing remote l1sc_t (kernel) + */ + if( local ) { + scp = get_l1sc(); + } + else { + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; + } + + return _cbrick_eeprom_read( buf, scp, component ); +} + + +int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, + int component ) +{ + int r; + int l1_compt, subch; + l1sc_t *scp; + int local = (nasid == get_nasid()); + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + + /* make sure we're talking to an applicable brick */ + if( !(component & IO_BRICK) ) { + return EEP_PARAM; + } + + /* If we're talking to this c-brick's attached io brick, use + * the local l1sc_t; otherwise, set up a new one (prom) or + * use an existing remote l1sc_t (kernel) + */ + if( local ) { + scp = get_l1sc(); + } + else { + scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; + } + + if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 ) + return EEP_L1; + + + switch( component ) + { + case IO_BRICK: + /* IO brick motherboard */ + l1_compt = L1_EEP_LOGIC; + r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); + + if( r != EEP_OK ) { + sc_close( scp, subch ); + /* + * Whenever we no longer need to test on hardware + * that does not have EEPROMS, then this can be removed. + */ + r = fake_an_eeprom_record( buf, component, rtc_time() ); + return r; + } + break; + + case IO_POWER: + /* IO brick power board */ + l1_compt = L1_EEP_POWER; + break; + + default: + /* unsupported board type */ + sc_close( scp, subch ); + return EEP_PARAM; + } + + r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); + sc_close( scp, subch ); + if( r != EEP_OK ) { + return r; + } + return EEP_OK; +} + + +int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, + net_vec_t path, int component ) +{ + int r; + uint64_t uid = 0; + int l1_compt, subch; + l1sc_t sc; + + if ( IS_RUNNING_ON_SIMULATOR() ) + return EEP_L1; + + /* make sure we're targeting an applicable brick */ + if( !(component & VECTOR) ) + return EEP_PARAM; + + switch( component & BRICK_MASK ) + { + case R_BRICK: + ROUTER_LOCK( path ); + sc_init( &sc, nasid, path ); + + if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) + { + db_printf(( "vector_eeprom_read: couldn't open subch\n" )); + ROUTER_UNLOCK(path); + return EEP_L1; + } + switch( component ) + { + case R_BRICK: + /* r-brick motherboard */ + l1_compt = L1_EEP_LOGIC; + r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia ); + if( r != EEP_OK ) { + sc_close( &sc, subch ); + ROUTER_UNLOCK( path ); + printk( "vector_eeprom_read: couldn't get rbrick eeprom info;" + " using current time as uid\n" ); + uid = rtc_time(); + db_printf(("vector_eeprom_read: using a fake eeprom record\n")); + return fake_an_eeprom_record( buf, component, uid ); + } + break; + + case R_POWER: + /* r-brick power board */ + l1_compt = L1_EEP_POWER; + break; + + default: + /* unsupported board type */ + sc_close( &sc, subch ); + ROUTER_UNLOCK( path ); + return EEP_PARAM; + } + r = read_board_ia( &sc, subch, l1_compt, buf->board_ia ); + sc_close( &sc, subch ); + ROUTER_UNLOCK( path ); + if( r != EEP_OK ) { + db_printf(( "vector_eeprom_read: using a fake eeprom record\n" )); + return fake_an_eeprom_record( buf, component, uid ); + } + return EEP_OK; + + case C_BRICK: + sc_init( &sc, nasid, path ); + return _cbrick_eeprom_read( buf, &sc, component ); + + default: + /* unsupported brick type */ + return EEP_PARAM; + } +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/efi-rtc.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/efi-rtc.c --- linux-2.4.19/arch/ia64/sn/io/sn1/efi-rtc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/efi-rtc.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,202 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2001 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No locking necessary when this is called from efirtc which protects us + * from racing by efi_rtc_lock. + */ +#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3)) +#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr)) +#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data)) + +#define TOD_SGS_M48T35 1 +#define TOD_DALLAS_DS1386 2 + +#define TYPE_IOC3 1 +#define TYPE_IOC4 2 + +static unsigned long nvram_base = 0; +static int tod_chip_type; +static int ioc_type; + +static int +get_tod_chip_type(void) +{ + unsigned char testval; + + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + write_io_port(RTC_DAL_DAY_ADDR, 0xff); + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + + testval = read_io_port(RTC_DAL_DAY_ADDR); + if (testval == 0xff) + return TOD_SGS_M48T35; + + return TOD_DALLAS_DS1386; +} + +efi_status_t +ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps) +{ + if (!nvram_base) { + printk(KERN_CRIT "nvram_base is zero\n"); + return EFI_UNSUPPORTED; + } + + memset(time, 0, sizeof(*time)); + + switch (tod_chip_type) { + case TOD_SGS_M48T35: + write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT); + + time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF; + time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR)); + time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR)); + time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR)); + time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR)); + time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR)); + time->nanosecond = 0; + + write_io_port(RTC_SGS_CONTROL_ADDR, 0); + break; + + case TOD_DALLAS_DS1386: + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + + time->nanosecond = 0; + time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR)); + time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR)); + time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR)); + time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR)); + time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR)); + time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF; + + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + break; + + default: + break; + } + + if (caps) { + caps->resolution = 50000000; /* 50PPM */ + caps->accuracy = 1000; /* 1ms */ + caps->sets_to_zero = 0; + } + + return EFI_SUCCESS; +} + +static efi_status_t ioc3_set_time (efi_time_t *t) +{ + if (!nvram_base) { + printk(KERN_CRIT "nvram_base is zero\n"); + return EFI_UNSUPPORTED; + } + + switch (tod_chip_type) { + case TOD_SGS_M48T35: + write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE); + write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); + write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month)); + write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day)); + write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour)); + write_io_port(RTC_SGS_MIN_ADDR, INT_TO_BCD(t->minute)); + write_io_port(RTC_SGS_SEC_ADDR, INT_TO_BCD(t->second)); + write_io_port(RTC_SGS_CONTROL_ADDR, 0); + break; + + case TOD_DALLAS_DS1386: + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + write_io_port(RTC_DAL_SEC_ADDR, INT_TO_BCD(t->second)); + write_io_port(RTC_DAL_MIN_ADDR, INT_TO_BCD(t->minute)); + write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour)); + write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day)); + write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month)); + write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +/* The following two are not supported atm. */ +static efi_status_t +ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t +ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) +{ + return EFI_UNSUPPORTED; +} + +static __init int efi_ioc_time_init(void) +{ + struct pci_dev *dev = NULL; + static void *ioc_base; + + while ( (dev = pci_find_subsys(PCI_VENDOR_ID_SGI, + PCI_ANY_ID, + PCI_ANY_ID, + PCI_ANY_ID, dev))) { + if ( dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { + ioc_type = TYPE_IOC3; + break; + } + else if ( dev->device == PCI_DEVICE_ID_SGI_IOC4 ) { + ioc_type = TYPE_IOC4; + break; + } + else + ;; // keep looking + } + + if ( !dev ) { + printk(KERN_CRIT "Couldn't find master IOC\n"); + return -ENODEV; + } + + ioc_base = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + if ( ioc_type == TYPE_IOC3 ) + nvram_base = (unsigned long) ioc_base + IOC3_BYTEBUS_DEV0; + if ( ioc_type == TYPE_IOC4 ) + nvram_base = (unsigned long) ioc_base + IOC4_BYTEBUS_DEV0; + + tod_chip_type = get_tod_chip_type(); + if (tod_chip_type == 1) + printk(KERN_NOTICE "TOD type is SGS M48T35\n"); + else if (tod_chip_type == 2) + printk(KERN_NOTICE "TOD type is Dallas DS1386\n"); + else + printk(KERN_CRIT "No or unknown TOD\n"); + + efi.get_time = ioc3_get_time; + efi.set_time = ioc3_set_time; + efi.get_wakeup_time = ioc3_get_wakeup_time; + efi.set_wakeup_time = ioc3_set_wakeup_time; + + return 0; +} + +module_init(efi_ioc_time_init); diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/hub_intr.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/hub_intr.c --- linux-2.4.19/arch/ia64/sn/io/sn1/hub_intr.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/hub_intr.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/hubcounters.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/hubcounters.c --- linux-2.4.19/arch/ia64/sn/io/sn1/hubcounters.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/hubcounters.c Mon Dec 30 14:16:56 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc. - * All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include #include diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/huberror.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/huberror.c --- linux-2.4.19/arch/ia64/sn/io/sn1/huberror.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/huberror.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/ip37.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ip37.c --- linux-2.4.19/arch/ia64/sn/io/sn1/ip37.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ip37.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/klconflib.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/klconflib.c --- linux-2.4.19/arch/ia64/sn/io/sn1/klconflib.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/klconflib.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,979 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define printf printk +int hasmetarouter; + +#define LDEBUG 0 +#define NIC_UNKNOWN ((nic_t) -1) + +#undef DEBUG_KLGRAPH +#ifdef DEBUG_KLGRAPH +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG_KLGRAPH */ + +static void sort_nic_names(lboard_t *) ; + +u64 klgraph_addr[MAX_COMPACT_NODES]; +int module_number = 0; + +lboard_t * +find_lboard(lboard_t *start, unsigned char brd_type) +{ + /* Search all boards stored on this node. */ + while (start) { + if (start->brd_type == brd_type) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_class(lboard_t *start, unsigned char brd_type) +{ + /* Search all boards stored on this node. */ + while (start) { + if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +klinfo_t * +find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) +{ + int index, j; + + if (kli == (klinfo_t *)NULL) { + index = 0; + } else { + for (j = 0; j < KLCF_NUM_COMPS(brd); j++) { + if (kli == KLCF_COMP(brd, j)) + break; + } + index = j; + if (index == KLCF_NUM_COMPS(brd)) { + DBG("find_component: Bad pointer: 0x%p\n", kli); + return (klinfo_t *)NULL; + } + index++; /* next component */ + } + + for (; index < KLCF_NUM_COMPS(brd); index++) { + kli = KLCF_COMP(brd, index); + DBG("find_component: brd %p kli %p request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli)); + if (KLCF_COMP_TYPE(kli) == struct_type) + return kli; + } + + /* Didn't find it. */ + return (klinfo_t *)NULL; +} + +klinfo_t * +find_first_component(lboard_t *brd, unsigned char struct_type) +{ + return find_component(brd, (klinfo_t *)NULL, struct_type); +} + +lboard_t * +find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot) +{ + /* Search all boards stored on this node. */ + while (start) { + if (MODULE_MATCH(start->brd_module, mod) && + (start->brd_slot == slot)) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_module(lboard_t *start, moduleid_t mod) +{ + /* Search all boards stored on this node. */ + while (start) { + if (MODULE_MATCH(start->brd_module, mod)) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_module_class(lboard_t *start, moduleid_t mod, + unsigned char brd_type) +{ + while (start) { + DBG("find_lboard_module_class: lboard 0x%p, start->brd_module 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_module, mod, start->brd_type, brd_type); + + if (MODULE_MATCH(start->brd_module, mod) && + (KLCLASS(start->brd_type) == KLCLASS(brd_type))) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + + +/* + * Convert a NIC name to a name for use in the hardware graph. + */ +void +nic_name_convert(char *old_name, char *new_name) +{ + int i; + char c; + char *compare_ptr; + + if ((old_name[0] == '\0') || (old_name[1] == '\0')) { + strcpy(new_name, EDGE_LBL_XWIDGET); + } else { + for (i = 0; i < strlen(old_name); i++) { + c = old_name[i]; + + if (isalpha(c)) + new_name[i] = tolower(c); + else if (isdigit(c)) + new_name[i] = c; + else + new_name[i] = '_'; + } + new_name[i] = '\0'; + } + + /* XXX - + * Since a bunch of boards made it out with weird names like + * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and + * replace it with "baseio" to avoid confusion in the field. + * We also have to make sure we don't report media_io instead of + * baseio. + */ + + /* Skip underscores at the beginning of the name */ + for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++) + ; + + /* + * Check for some names we need to replace. Early boards + * had junk following the name so check only the first + * characters. + */ + if (!strncmp(new_name, "io6", 3) || + !strncmp(new_name, "mio", 3) || + !strncmp(new_name, "media_io", 8)) + strcpy(new_name, "baseio"); + else if (!strncmp(new_name, "divo", 4)) + strcpy(new_name, "divo") ; + +} + +/* Check if the given board corresponds to the global + * master io6 + */ +int +is_master_baseio(nasid_t nasid,moduleid_t module,slotid_t slot) +{ + lboard_t *board; + +/* If this works then look for callers of is_master_baseio() + * (e.g. iograph.c) and let them pass in a slot if they want + */ + board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module); + +#ifndef _STANDALONE + { + cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); + + if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) + board = find_lboard_module((lboard_t *) + KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), + module); + } +#endif + if (!board) + return(0); + return(board->brd_flags & GLOBAL_MASTER_IO6); +} +/* + * Find the lboard structure and get the board name. + * If we can't find the structure or it's too low a revision, + * use default name. + */ +lboard_t * +get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name) +{ + lboard_t *brd; + + brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), + mod, slot); + +#ifndef _STANDALONE + { + cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); + + if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) + brd = find_lboard_modslot((lboard_t *) + KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), + mod, slot); + } +#endif + + if (!brd || (brd->brd_sversion < 2)) { + strcpy(name, EDGE_LBL_XWIDGET); + } else { + nic_name_convert(brd->brd_name, name); + } + + /* + * PV # 540860 + * If the name is not 'baseio' + * get the lowest of all the names in the nic string. + * This is needed for boards like divo, which can have + * a bunch of daughter cards, but would like to be called + * divo. We could do this for baseio + * but it has some special case names that we would not + * like to disturb at this point. + */ + + /* gfx boards don't need any of this name scrambling */ + if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) { + return(brd); + } + + if (!(!strcmp(name, "baseio") )) { + if (brd) { + sort_nic_names(brd) ; + /* Convert to small case, '-' to '_' etc */ + nic_name_convert(brd->brd_name, name) ; + } + } + + return(brd); +} + +/* + * get_actual_nasid + * + * Completely disabled brds have their klconfig on + * some other nasid as they have no memory. But their + * actual nasid is hidden in the klconfig. Use this + * routine to get it. Works for normal boards too. + */ +nasid_t +get_actual_nasid(lboard_t *brd) +{ + klhub_t *hub ; + + if (!brd) + return INVALID_NASID ; + + /* find out if we are a completely disabled brd. */ + + hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + if (!hub) + return INVALID_NASID ; + if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ + return hub->hub_info.physid ; + else + return brd->brd_nasid ; +} + +int +xbow_port_io_enabled(nasid_t nasid, int link) +{ + lboard_t *brd; + klxbow_t *xbow_p; + + /* + * look for boards that might contain an xbow or xbridge + */ + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); + if (brd == NULL) return 0; + + if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) + == NULL) + return 0; + + if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) + return 0; + + return 1; +} + +void +board_to_path(lboard_t *brd, char *path) +{ + moduleid_t modnum; + char *board_name; + + ASSERT(brd); + + switch (KLCLASS(brd->brd_type)) { + + case KLCLASS_NODE: + board_name = EDGE_LBL_NODE; + break; + case KLCLASS_ROUTER: + if (brd->brd_type == KLTYPE_META_ROUTER) { + board_name = EDGE_LBL_META_ROUTER; + hasmetarouter++; + } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { + board_name = EDGE_LBL_REPEATER_ROUTER; + hasmetarouter++; + } else + board_name = EDGE_LBL_ROUTER; + break; + case KLCLASS_MIDPLANE: + board_name = EDGE_LBL_MIDPLANE; + break; + case KLCLASS_IO: + board_name = EDGE_LBL_IO; + break; + case KLCLASS_IOBRICK: + if (brd->brd_type == KLTYPE_PBRICK) + board_name = EDGE_LBL_PBRICK; + else if (brd->brd_type == KLTYPE_IBRICK) + board_name = EDGE_LBL_IBRICK; + else if (brd->brd_type == KLTYPE_XBRICK) + board_name = EDGE_LBL_XBRICK; + else + board_name = EDGE_LBL_IOBRICK; + break; + default: + board_name = EDGE_LBL_UNKNOWN; + } + + modnum = brd->brd_module; + + /* ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); */ +if ((modnum == MODULE_UNKNOWN) || (modnum == INVALID_MODULE)) { + modnum = ++module_number; +} +#ifdef __ia64 + { + char buffer[16]; + memset(buffer, 0, 16); + format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); + sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name); + } +#else + sprintf(path, "%H/%s", modnum, board_name); +#endif +} + +/* + * Get the module number for a NASID. + */ +moduleid_t +get_module_id(nasid_t nasid) +{ + lboard_t *brd; + + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + + if (!brd) + return INVALID_MODULE; + else + return brd->brd_module; +} + + +#define MHZ 1000000 + + +/* Get the canonical hardware graph name for the given pci component + * on the given io board. + */ +void +device_component_canonical_name_get(lboard_t *brd, + klinfo_t *component, + char *name) +{ + moduleid_t modnum; + slotid_t slot; + char board_name[20]; + + ASSERT(brd); + + /* Get the module number of this board */ + modnum = brd->brd_module; + + /* Convert the [ CLASS | TYPE ] kind of slotid + * into a string + */ + slot = brd->brd_slot; + ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); + + /* Get the io board name */ + if (!brd || (brd->brd_sversion < 2)) { + strcpy(name, EDGE_LBL_XWIDGET); + } else { + nic_name_convert(brd->brd_name, board_name); + } + + /* Give out the canonical name of the pci device*/ + sprintf(name, + "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/" + EDGE_LBL_PCI"/%d", + modnum, board_name,KLCF_BRIDGE_W_ID(component)); +} + +/* + * Get the serial number of the main component of a board + * Returns 0 if a valid serial number is found + * 1 otherwise. + * Assumptions: Nic manufacturing string has the following format + * *Serial:;* + */ +static int +component_serial_number_get(lboard_t *board, + klconf_off_t mfg_nic_offset, + char *serial_number, + char *key_pattern) +{ + + char *mfg_nic_string; + char *serial_string,*str; + int i; + char *serial_pattern = "Serial:"; + + /* We have an error on a null mfg nic offset */ + if (!mfg_nic_offset) + return(1); + /* Get the hub's manufacturing nic information + * which is in the form of a pre-formatted string + */ + mfg_nic_string = + (char *)NODE_OFFSET_TO_K0(NASID_GET(board), + mfg_nic_offset); + /* There is no manufacturing nic info */ + if (!mfg_nic_string) + return(1); + + str = mfg_nic_string; + /* Look for the key pattern first (if it is specified) + * and then print the serial number corresponding to that. + */ + if (strcmp(key_pattern,"") && + !(str = strstr(mfg_nic_string,key_pattern))) + return(1); + + /* There is no serial number info in the manufacturing + * nic info + */ + if (!(serial_string = strstr(str,serial_pattern))) + return(1); + + serial_string = serial_string + strlen(serial_pattern); + /* Copy the serial number information from the klconfig */ + i = 0; + while (serial_string[i] != ';') { + serial_number[i] = serial_string[i]; + i++; + } + serial_number[i] = 0; + + return(0); +} +/* + * Get the serial number of a board + * Returns 0 if a valid serial number is found + * 1 otherwise. + */ + +int +board_serial_number_get(lboard_t *board,char *serial_number) +{ + ASSERT(board && serial_number); + if (!board || !serial_number) + return(1); + + strcpy(serial_number,""); + switch(KLCLASS(board->brd_type)) { + case KLCLASS_CPU: { /* Node board */ + klhub_t *hub; + + /* Get the hub component information */ + hub = (klhub_t *)find_first_component(board, + KLSTRUCT_HUB); + /* If we don't have a hub component on an IP27 + * then we have a weird klconfig. + */ + if (!hub) + return(1); + /* Get the serial number information from + * the hub's manufacturing nic info + */ + if (component_serial_number_get(board, + hub->hub_mfg_nic, + serial_number, + "IP37")) + return(1); + break; + } + case KLCLASS_IO: { /* IO board */ + if (KLTYPE(board->brd_type) == KLTYPE_TPU) { + /* Special case for TPU boards */ + kltpu_t *tpu; + + /* Get the tpu component information */ + tpu = (kltpu_t *)find_first_component(board, + KLSTRUCT_TPU); + /* If we don't have a tpu component on a tpu board + * then we have a weird klconfig. + */ + if (!tpu) + return(1); + /* Get the serial number information from + * the tpu's manufacturing nic info + */ + if (component_serial_number_get(board, + tpu->tpu_mfg_nic, + serial_number, + "")) + return(1); + break; + } else if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) || + (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) { + /* Special case for GSN boards */ + klgsn_t *gsn; + + /* Get the gsn component information */ + gsn = (klgsn_t *)find_first_component(board, + ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ? + KLSTRUCT_GSN_A : KLSTRUCT_GSN_B)); + /* If we don't have a gsn component on a gsn board + * then we have a weird klconfig. + */ + if (!gsn) + return(1); + /* Get the serial number information from + * the gsn's manufacturing nic info + */ + if (component_serial_number_get(board, + gsn->gsn_mfg_nic, + serial_number, + "")) + return(1); + break; + } else { + klbri_t *bridge; + + /* Get the bridge component information */ + bridge = (klbri_t *)find_first_component(board, + KLSTRUCT_BRI); + /* If we don't have a bridge component on an IO board + * then we have a weird klconfig. + */ + if (!bridge) + return(1); + /* Get the serial number information from + * the bridge's manufacturing nic info + */ + if (component_serial_number_get(board, + bridge->bri_mfg_nic, + serial_number, + "")) + return(1); + break; + } + } + case KLCLASS_ROUTER: { /* Router board */ + klrou_t *router; + + /* Get the router component information */ + router = (klrou_t *)find_first_component(board, + KLSTRUCT_ROU); + /* If we don't have a router component on a router board + * then we have a weird klconfig. + */ + if (!router) + return(1); + /* Get the serial number information from + * the router's manufacturing nic info + */ + if (component_serial_number_get(board, + router->rou_mfg_nic, + serial_number, + "")) + return(1); + break; + } + case KLCLASS_GFX: { /* Gfx board */ + klgfx_t *graphics; + + /* Get the graphics component information */ + graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX); + /* If we don't have a gfx component on a gfx board + * then we have a weird klconfig. + */ + if (!graphics) + return(1); + /* Get the serial number information from + * the graphics's manufacturing nic info + */ + if (component_serial_number_get(board, + graphics->gfx_mfg_nic, + serial_number, + "")) + return(1); + break; + } + default: + strcpy(serial_number,""); + break; + } + return(0); +} + +#include "asm/sn/sn_private.h" + +xwidgetnum_t +nodevertex_widgetnum_get(devfs_handle_t node_vtx) +{ + hubinfo_t hubinfo_p; + + hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, + (arbitrary_info_t *) &hubinfo_p); + return(hubinfo_p->h_widgetid); +} + +devfs_handle_t +nodevertex_xbow_peer_get(devfs_handle_t node_vtx) +{ + hubinfo_t hubinfo_p; + nasid_t xbow_peer_nasid; + cnodeid_t xbow_peer; + + hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, + (arbitrary_info_t *) &hubinfo_p); + xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer; + if(xbow_peer_nasid == INVALID_NASID) + return ( (devfs_handle_t)-1); + xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid); + return(NODEPDA(xbow_peer)->node_vertex); +} + +/* NIC Sorting Support */ + +#define MAX_NICS_PER_STRING 32 +#define MAX_NIC_NAME_LEN 32 + +static char * +get_nic_string(lboard_t *lb) +{ + int i; + klinfo_t *k = NULL ; + klconf_off_t mfg_off = 0 ; + char *mfg_nic = NULL ; + + for (i = 0; i < KLCF_NUM_COMPS(lb); i++) { + k = KLCF_COMP(lb, i) ; + switch(k->struct_type) { + case KLSTRUCT_BRI: + mfg_off = ((klbri_t *)k)->bri_mfg_nic ; + break ; + + case KLSTRUCT_HUB: + mfg_off = ((klhub_t *)k)->hub_mfg_nic ; + break ; + + case KLSTRUCT_ROU: + mfg_off = ((klrou_t *)k)->rou_mfg_nic ; + break ; + + case KLSTRUCT_GFX: + mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ; + break ; + + case KLSTRUCT_TPU: + mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ; + break ; + + case KLSTRUCT_GSN_A: + case KLSTRUCT_GSN_B: + mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ; + break ; + + case KLSTRUCT_XTHD: + mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ; + break; + + default: + mfg_off = 0 ; + break ; + } + if (mfg_off) + break ; + } + + if ((mfg_off) && (k)) + mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ; + + return mfg_nic ; +} + +char * +get_first_string(char **ptrs, int n) +{ + int i ; + char *tmpptr ; + + if ((ptrs == NULL) || (n == 0)) + return NULL ; + + tmpptr = ptrs[0] ; + + if (n == 1) + return tmpptr ; + + for (i = 0 ; i < n ; i++) { + if (strcmp(tmpptr, ptrs[i]) > 0) + tmpptr = ptrs[i] ; + } + + return tmpptr ; +} + +int +get_ptrs(char *idata, char **ptrs, int n, char *label) +{ + int i = 0 ; + char *tmp = idata ; + + if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0)) + return 0 ; + + while ( (tmp = strstr(tmp, label)) ){ + tmp += strlen(label) ; + /* check for empty name field, and last NULL ptr */ + if ((i < (n-1)) && (*tmp != ';')) { + ptrs[i++] = tmp ; + } + } + + ptrs[i] = NULL ; + + return i ; +} + +/* + * sort_nic_names + * + * Does not really do sorting. Find the alphabetically lowest + * name among all the nic names found in a nic string. + * + * Return: + * Nothing + * + * Side Effects: + * + * lb->brd_name gets the new name found + */ + +static void +sort_nic_names(lboard_t *lb) +{ + char *nic_str ; + char *ptrs[MAX_NICS_PER_STRING] ; + char name[MAX_NIC_NAME_LEN] ; + char *tmp, *tmp1 ; + + *name = 0 ; + + /* Get the nic pointer from the lb */ + + if ((nic_str = get_nic_string(lb)) == NULL) + return ; + + tmp = get_first_string(ptrs, + get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ; + + if (tmp == NULL) + return ; + + if ( (tmp1 = strchr(tmp, ';')) ){ + strncpy(name, tmp, tmp1-tmp) ; + name[tmp1-tmp] = 0 ; + } else { + strncpy(name, tmp, (sizeof(name) -1)) ; + name[sizeof(name)-1] = 0 ; + } + + strcpy(lb->brd_name, name) ; +} + + + +char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#012345"; + + +/* + * Format a module id for printing. + */ +void +format_module_id(char *buffer, moduleid_t m, int fmt) +{ + int rack, position; + char brickchar; + + rack = MODULE_GET_RACK(m); + ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); + brickchar = MODULE_GET_BTCHAR(m); + position = MODULE_GET_BPOS(m); + + if (fmt == MODULE_FORMAT_BRIEF) { + /* Brief module number format, eg. 002c15 */ + + /* Decompress the rack number */ + *buffer++ = '0' + RACK_GET_CLASS(rack); + *buffer++ = '0' + RACK_GET_GROUP(rack); + *buffer++ = '0' + RACK_GET_NUM(rack); + + /* Add the brick type */ + *buffer++ = brickchar; + } + else if (fmt == MODULE_FORMAT_LONG) { + /* Fuller hwgraph format, eg. rack/002/bay/15 */ + + strcpy(buffer, EDGE_LBL_RACK "/"); buffer += strlen(buffer); + + *buffer++ = '0' + RACK_GET_CLASS(rack); + *buffer++ = '0' + RACK_GET_GROUP(rack); + *buffer++ = '0' + RACK_GET_NUM(rack); + + strcpy(buffer, "/" EDGE_LBL_RPOS "/"); buffer += strlen(buffer); + } + + /* Add the bay position, using at least two digits */ + if (position < 10) + *buffer++ = '0'; + sprintf(buffer, "%d", position); + +} + +/* + * Parse a module id, in either brief or long form. + * Returns < 0 on error. + * The long form does not include a brick type, so it defaults to 0 (CBrick) + */ +int +parse_module_id(char *buffer) +{ + unsigned int v, rack, bay, type, form; + moduleid_t m; + char c; + + if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) { + form = MODULE_FORMAT_LONG; + buffer += strlen(EDGE_LBL_RACK "/"); + + /* A long module ID must be exactly 5 non-template chars. */ + if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5) + return -1; + } + else { + form = MODULE_FORMAT_BRIEF; + + /* A brief module id must be exactly 6 characters */ + if (strlen(buffer) != 6) + return -2; + } + + /* The rack number must be exactly 3 digits */ + if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2]))) + return -3; + + rack = 0; + v = *buffer++ - '0'; + if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) + return -4; + RACK_ADD_CLASS(rack, v); + + v = *buffer++ - '0'; + if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) + return -5; + RACK_ADD_GROUP(rack, v); + + v = *buffer++ - '0'; + /* rack numbers are 1-based */ + if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) + return -6; + RACK_ADD_NUM(rack, v); + + if (form == MODULE_FORMAT_BRIEF) { + /* Next should be a module type character. Accept ucase or lcase. */ + c = *buffer++; + if (!isalpha(c)) + return -7; + + /* strchr() returns a pointer into brick_types[], or NULL */ + type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types); + if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT) + return -8; + } + else { + /* Hardcode the module type, and skip over the boilerplate */ + type = MODULE_CBRICK; + + if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer) + return -9; + + buffer += strlen("/" EDGE_LBL_RPOS "/"); + } + + /* The bay number is last. Make sure it's exactly two digits */ + + if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2])) + return -10; + + bay = 10 * (buffer[0] - '0') + (buffer[1] - '0'); + + if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) + return -11; + + m = RBT_TO_MODULE(rack, bay, type); + + /* avoid sign extending the moduleid_t */ + return (int)(unsigned short)m; +} + diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/klgraph.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/klgraph.c --- linux-2.4.19/arch/ia64/sn/io/sn1/klgraph.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/klgraph.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,940 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * klgraph.c- + * This file specifies the interface between the kernel and the PROM's + * configuration data structures. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define KLGRAPH_DEBUG 1 */ +#ifdef KLGRAPH_DEBUG +#define GRPRINTF(x) printk x +#define CE_GRPANIC CE_PANIC +#else +#define GRPRINTF(x) +#define CE_GRPANIC CE_PANIC +#endif + +#include + +extern char arg_maxnodes[]; +extern u64 klgraph_addr[]; + +/* + * Support for verbose inventory via hardware graph. + * klhwg_invent_alloc allocates the necessary size of inventory information + * and fills in the generic information. + */ +invent_generic_t * +klhwg_invent_alloc(cnodeid_t cnode, int class, int size) +{ + invent_generic_t *invent; + + invent = kern_malloc(size); + if (!invent) return NULL; + + invent->ig_module = NODE_MODULEID(cnode); + invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode)); + invent->ig_invclass = class; + + return invent; +} + +/* + * Add detailed disabled cpu inventory info to the hardware graph. + */ +void +klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv, + cnodeid_t cnode, + klcpu_t *cpu, slotid_t slot) +{ + invent_cpuinfo_t *cpu_invent; + diag_inv_t *diag_invent; + + cpu_invent = (invent_cpuinfo_t *) + klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t)); + if (!cpu_invent) + return; + + /* Diag information on this processor */ + diag_invent = (diag_inv_t *) + klhwg_invent_alloc(cnode, INV_CPUDIAGVAL, sizeof(diag_inv_t)); + + if (!diag_invent) + return; + + + /* Disabled CPU */ + cpu_invent->ic_gen.ig_flag = 0x0; + cpu_invent->ic_gen.ig_slot = slot; + cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid; + cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed; + cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed; + + cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz; + cpu_invent->ic_cpuid = cpu->cpu_info.virtid; + cpu_invent->ic_slice = cpu->cpu_info.physid; + + /* Disabled CPU label */ + hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) cpu_invent); + hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + sizeof(invent_cpuinfo_t)); + + /* Diagval label - stores reason for disable +{virt,phys}id +diagval*/ + hwgraph_info_add_LBL(cpuv, INFO_LBL_DIAGVAL, + (arbitrary_info_t) diag_invent); + + hwgraph_info_export_LBL(cpuv, INFO_LBL_DIAGVAL, + sizeof(diag_inv_t)); +} + +/* + * Add detailed cpu inventory info to the hardware graph. + */ +void +klhwg_cpu_invent_info(devfs_handle_t cpuv, + cnodeid_t cnode, + klcpu_t *cpu) +{ + invent_cpuinfo_t *cpu_invent; + + cpu_invent = (invent_cpuinfo_t *) + klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t)); + if (!cpu_invent) + return; + + if (KLCONFIG_INFO_ENABLED((klinfo_t *)cpu)) + cpu_invent->ic_gen.ig_flag = INVENT_ENABLED; + else + cpu_invent->ic_gen.ig_flag = 0x0; + + cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid; + cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed; + cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed; + + cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz; + cpu_invent->ic_cpuid = cpu->cpu_info.virtid; + cpu_invent->ic_slice = cpu_physical_id_to_slice(cpu->cpu_info.virtid); + + hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) cpu_invent); + hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + sizeof(invent_cpuinfo_t)); +} + +/* + * Add information about the baseio prom version number + * as a part of detailed inventory info in the hwgraph. + */ +void +klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) +{ + invent_miscinfo_t *baseio_inventory; + unsigned char version = 0,revision = 0; + + /* Allocate memory for the "detailed inventory" info + * for the baseio + */ + baseio_inventory = (invent_miscinfo_t *) + klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); + baseio_inventory->im_type = INV_IO6PROM; + /* Store the revision info in the inventory */ + baseio_inventory->im_version = version; + baseio_inventory->im_rev = revision; + /* Put the inventory info in the hardware graph */ + hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) baseio_inventory); + /* Make the information available to the user programs + * thru hwgfs. + */ + hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, + sizeof(invent_miscinfo_t)); +} + +char *hub_rev[] = { + "0.0", + "1.0", + "2.0", + "2.1", + "2.2", + "2.3" +}; + +/* + * Add detailed cpu inventory info to the hardware graph. + */ +void +klhwg_hub_invent_info(devfs_handle_t hubv, + cnodeid_t cnode, + klhub_t *hub) +{ + invent_miscinfo_t *hub_invent; + + hub_invent = (invent_miscinfo_t *) + klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t)); + if (!hub_invent) + return; + + if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub)) + hub_invent->im_gen.ig_flag = INVENT_ENABLED; + + hub_invent->im_type = INV_HUB; + hub_invent->im_rev = hub->hub_info.revision; + hub_invent->im_speed = hub->hub_speed; + hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) hub_invent); + hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT, + sizeof(invent_miscinfo_t)); +} + +/* ARGSUSED */ +void +klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) +{ + devfs_handle_t myhubv; + devfs_handle_t hub_mon; + devfs_handle_t synergy; + devfs_handle_t fsb0; + devfs_handle_t fsb1; + int rc; + extern struct file_operations hub_mon_fops; + + GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB)); + + (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); + rc = device_master_set(myhubv, node_vertex); + + /* + * hub perf stats. + */ + rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO, + (arbitrary_info_t)(&NODEPDA(cnode)->hubstats)); + + if (rc != GRAPH_SUCCESS) { + printk(KERN_WARNING "klhwg_add_hub: Can't add hub info label 0x%p, code %d", + (void *)myhubv, rc); + } + + klhwg_hub_invent_info(myhubv, cnode, hub); + + hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &hub_mon_fops, + (void *)(long)cnode); + + init_hub_stats(cnode, NODEPDA(cnode)); + + /* + * synergy perf + */ + (void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy); + (void) hwgraph_path_add(synergy, "0", &fsb0); + (void) hwgraph_path_add(synergy, "1", &fsb1); + + fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0)); + + fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1)); +} + +/* ARGSUSED */ +void +klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) +{ + devfs_handle_t my_cpu; + char name[120]; + cpuid_t cpu_id; + nasid_t nasid; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid); + if(cpu_id != -1){ + sprintf(name, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid); + (void) hwgraph_path_add(node_vertex, name, &my_cpu); + + mark_cpuvertex_as_cpu(my_cpu, cpu_id); + device_master_set(my_cpu, node_vertex); + + klhwg_disabled_cpu_invent_info(my_cpu, cnode, cpu, slot); + return; + } +} + +/* ARGSUSED */ +void +klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu) +{ + devfs_handle_t my_cpu, cpu_dir; + char name[120]; + cpuid_t cpu_id; + nasid_t nasid; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid); + + sprintf(name, "%s/%d/%c", + EDGE_LBL_CPUBUS, + 0, + 'a' + cpu->cpu_info.physid); + + GRPRINTF(("klhwg_add_cpu: adding %s to vertex 0x%x\n", name, node_vertex)); + (void) hwgraph_path_add(node_vertex, name, &my_cpu); + mark_cpuvertex_as_cpu(my_cpu, cpu_id); + device_master_set(my_cpu, node_vertex); + + /* Add an alias under the node's CPU directory */ + if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) { + sprintf(name, "%c", 'a' + cpu->cpu_info.physid); + (void) hwgraph_edge_add(cpu_dir, my_cpu, name); + } + + klhwg_cpu_invent_info(my_cpu, cnode, cpu); +} + + +void +klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) +{ + lboard_t *brd; + klxbow_t *xbow_p; + nasid_t hub_nasid; + cnodeid_t hub_cnode; + int widgetnum; + devfs_handle_t xbow_v, hubv; + /*REFERENCED*/ + graph_error_t err; + + if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL) + return; + + if (KL_CONFIG_DUPLICATE_BOARD(brd)) + return; + + GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n", + cnode, nasid)); + + if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) + == NULL) + return; + +#ifdef LATER + /* + * We cannot support this function in devfs .. see below where + * we use hwgraph_path_add() to create this vertex with a known + * name. + */ + err = hwgraph_vertex_create(&xbow_v); + ASSERT(err == GRAPH_SUCCESS); + + xswitch_vertex_init(xbow_v); +#endif /* LATER */ + + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) + continue; + + hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); + if (hub_nasid == INVALID_NASID) { + printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum); + continue; + } + + hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid); + + if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) { + continue; + } + + hubv = cnodeid_to_vertex(hub_cnode); + + err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); + if (err != GRAPH_SUCCESS) { + if (err == GRAPH_DUP) + printk(KERN_WARNING "klhwg_add_xbow: Check for " + "working routers and router links!"); + + PRINT_PANIC("klhwg_add_xbow: Failed to add " + "edge: vertex 0x%p to vertex 0x%p," + "error %d\n", + (void *)hubv, (void *)xbow_v, err); + } + xswitch_vertex_init(xbow_v); + + NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; + + /* + * XXX - This won't work is we ever hook up two hubs + * by crosstown through a crossbow. + */ + if (hub_nasid != nasid) { + NODEPDA(hub_cnode)->xbow_peer = nasid; + NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer = + hub_nasid; + } + + GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n", + hub_nasid, EDGE_LBL_XTALK, hubv)); + +#ifdef LATER + err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK); + if (err != GRAPH_SUCCESS) { + if (err == GRAPH_DUP) + printk(KERN_WARNING "klhwg_add_xbow: Check for " + "working routers and router links!"); + + PRINT_PANIC("klhwg_add_xbow: Failed to add " + "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), " + "error %d\n", + hubv, hubv, xbow_v, xbow_v, err); + } +#endif + } +} + + +/* ARGSUSED */ +void +klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) +{ + nasid_t nasid; + lboard_t *brd; + klhub_t *hub; + devfs_handle_t node_vertex = NULL; + char path_buffer[100]; + int rv; + char *s; + int board_disabled = 0; + klcpu_t *cpu; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n", + cnode, nasid, brd)); + ASSERT(brd); + + do { + devfs_handle_t cpu_dir; + + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n", + path_buffer, hwgraph_root)); + rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); + + if (rv != GRAPH_SUCCESS) + PRINT_PANIC("Node vertex creation failed. " + "Path == %s", + path_buffer); + + hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + ASSERT(hub); + if(hub->hub_info.flags & KLINFO_ENABLE) + board_disabled = 0; + else + board_disabled = 1; + + if(!board_disabled) { + mark_nodevertex_as_node(node_vertex, + cnode + board_disabled * numnodes); + + s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); + NODEPDA(cnode)->hwg_node_name = + kmalloc(strlen(s) + 1, + GFP_KERNEL); + ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL); + strcpy(NODEPDA(cnode)->hwg_node_name, s); + + hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo); + + /* Set up node board's slot */ + NODEPDA(cnode)->slotdesc = brd->brd_slot; + + /* Set up the module we're in */ + NODEPDA(cnode)->module_id = brd->brd_module; + NODEPDA(cnode)->module = module_lookup(brd->brd_module); + } + + + /* Get the first CPU structure */ + cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU); + + /* + * If there's at least 1 CPU, add a "cpu" directory to represent + * the collection of all CPUs attached to this node. + */ + if (cpu) { + graph_error_t rv; + + rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir); + if (rv != GRAPH_SUCCESS) + panic("klhwg_add_node: Cannot create CPU directory\n"); + } + + /* Add each CPU */ + while (cpu) { + cpuid_t cpu_id; + cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid); + if (cpu_enabled(cpu_id)) + klhwg_add_cpu(node_vertex, cnode, cpu); + else + klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot); + + cpu = (klcpu_t *) + find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU); + } /* while */ + + if(!board_disabled) + klhwg_add_hub(node_vertex, hub, cnode); + + brd = KLCF_NEXT(brd); + if (brd) + brd = find_lboard(brd, KLTYPE_SNIA); + else + break; + } while(brd); +} + + +/* ARGSUSED */ +void +klhwg_add_all_routers(devfs_handle_t hwgraph_root) +{ + nasid_t nasid; + cnodeid_t cnode; + lboard_t *brd; + devfs_handle_t node_vertex; + char path_buffer[100]; + int rv; + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + + GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n", + cnode)); + + brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), + KLTYPE_ROUTER); + + if (!brd) + /* No routers stored in this node's memory */ + continue; + + do { + ASSERT(brd); + GRPRINTF(("Router board struct is %p\n", brd)); + + /* Don't add duplicate boards. */ + if (brd->brd_flags & DUPLICATE_BOARD) + continue; + + GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module)); + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + GRPRINTF(("Router path is %s\n", path_buffer)); + + /* Add the router */ + GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n", + path_buffer, hwgraph_root)); + rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); + + if (rv != GRAPH_SUCCESS) + PRINT_PANIC("Router vertex creation " + "failed. Path == %s", + path_buffer); + + GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n", + brd)); + /* Find the rest of the routers stored on this node. */ + } while ( (brd = find_lboard_class(KLCF_NEXT(brd), + KLTYPE_ROUTER)) ); + + GRPRINTF(("klhwg_add_all_routers: Done.\n")); + } + +} + +/* ARGSUSED */ +void +klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, + cnodeid_t cnode, nasid_t nasid) +{ + klrou_t *router; + char path_buffer[50]; + char dest_path[50]; + devfs_handle_t router_hndl; + devfs_handle_t dest_hndl; + int rc; + int port; + lboard_t *dest_brd; + + GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n", + cnode)); + + /* Don't add duplicate boards. */ + if (brd->brd_flags & DUPLICATE_BOARD) { + GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n", + brd, cnode)); + return; + } + + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl); + + if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes)) + return; + + if (rc != GRAPH_SUCCESS) + printk(KERN_WARNING "Can't find router: %s", path_buffer); + + /* We don't know what to do with multiple router components */ + if (brd->brd_numcompts != 1) { + PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n", + brd->brd_numcompts); + return; + } + + + /* Convert component 0 to klrou_t ptr */ + router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), + brd->brd_compts[0]); + + for (port = 1; port <= MAX_ROUTER_PORTS; port++) { + /* See if the port's active */ + if (router->rou_port[port].port_nasid == INVALID_NASID) { + GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n", + port)); + continue; + } + if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) + == INVALID_CNODEID) { + continue; + } + + dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( + router->rou_port[port].port_nasid, + router->rou_port[port].port_offset); + + /* Generate a hardware graph path for this board. */ + board_to_path(dest_brd, dest_path); + + rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); + + if (rc != GRAPH_SUCCESS) { + if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) + continue; + PRINT_PANIC("Can't find router: %s", dest_path); + } + GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n", + path_buffer, port, dest_path)); + + sprintf(dest_path, "%d", port); + + rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path); + + if (rc == GRAPH_DUP) { + GRPRINTF(("Skipping port %d. nasid %d %s/%s\n", + port, router->rou_port[port].port_nasid, + path_buffer, dest_path)); + continue; + } + + if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", + path_buffer, dest_path, (void *)dest_hndl, rc); + + } +} + + +void +klhwg_connect_routers(devfs_handle_t hwgraph_root) +{ + nasid_t nasid; + cnodeid_t cnode; + lboard_t *brd; + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + + GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n", + cnode)); + + brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), + KLTYPE_ROUTER); + + if (!brd) + continue; + + do { + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + klhwg_connect_one_router(hwgraph_root, brd, + cnode, nasid); + + /* Find the rest of the routers stored on this node. */ + } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); + } +} + + + +void +klhwg_connect_hubs(devfs_handle_t hwgraph_root) +{ + nasid_t nasid; + cnodeid_t cnode; + lboard_t *brd; + klhub_t *hub; + lboard_t *dest_brd; + devfs_handle_t hub_hndl; + devfs_handle_t dest_hndl; + char path_buffer[50]; + char dest_path[50]; + graph_error_t rc; + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + + GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n", + cnode)); + + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + ASSERT(brd); + + hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + ASSERT(hub); + + /* See if the port's active */ + if (hub->hub_port.port_nasid == INVALID_NASID) { + GRPRINTF(("klhwg_connect_hubs: port inactive.\n")); + continue; + } + + if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID) + continue; + + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer)); + rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); + + if (rc != GRAPH_SUCCESS) + printk(KERN_WARNING "Can't find hub: %s", path_buffer); + + dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( + hub->hub_port.port_nasid, + hub->hub_port.port_offset); + + /* Generate a hardware graph path for this board. */ + board_to_path(dest_brd, dest_path); + + rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); + + if (rc != GRAPH_SUCCESS) { + if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) + continue; + PRINT_PANIC("Can't find board: %s", dest_path); + } else { + + + GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n", + path_buffer, dest_path)); + + rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT); + + if (rc != GRAPH_SUCCESS) + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", + path_buffer, dest_path, (void *)dest_hndl, rc); + + } + } +} + +/* Store the pci/vme disabled board information as extended administrative + * hints which can later be used by the drivers using the device/driver + * admin interface. + */ +void +klhwg_device_disable_hints_add(void) +{ + cnodeid_t cnode; /* node we are looking at */ + nasid_t nasid; /* nasid of the node */ + lboard_t *board; /* board we are looking at */ + int comp_index; /* component index */ + klinfo_t *component; /* component in the board we are + * looking at + */ + char device_name[MAXDEVNAME]; + + for(cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + board = (lboard_t *)KL_CONFIG_INFO(nasid); + /* Check out all the board info stored on a node */ + while(board) { + /* No need to look at duplicate boards or non-io + * boards + */ + if (KL_CONFIG_DUPLICATE_BOARD(board) || + KLCLASS(board->brd_type) != KLCLASS_IO) { + board = KLCF_NEXT(board); + continue; + } + /* Check out all the components of a board */ + for (comp_index = 0; + comp_index < KLCF_NUM_COMPS(board); + comp_index++) { + component = KLCF_COMP(board,comp_index); + /* If the component is enabled move on to + * the next component + */ + if (KLCONFIG_INFO_ENABLED(component)) + continue; + /* NOTE : Since the prom only supports + * the disabling of pci devices the following + * piece of code makes sense. + * Make sure that this assumption is valid + */ + /* This component is disabled. Store this + * hint in the extended device admin table + */ + /* Get the canonical name of the pci device */ + device_component_canonical_name_get(board, + component, + device_name); +#ifdef DEBUG + printf("%s DISABLED\n",device_name); +#endif + } + /* go to the next board info stored on this + * node + */ + board = KLCF_NEXT(board); + } + } +} + +void +klhwg_add_all_modules(devfs_handle_t hwgraph_root) +{ + cmoduleid_t cm; + char name[128]; + devfs_handle_t vhdl; + int rc; + char buffer[16]; + + /* Add devices under each module */ + + for (cm = 0; cm < nummodules; cm++) { + /* Use module as module vertex fastinfo */ + +#ifdef __ia64 + memset(buffer, 0, 16); + format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); + sprintf(name, EDGE_LBL_MODULE "/%s", buffer); +#else + sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id); +#endif + + rc = hwgraph_path_add(hwgraph_root, name, &vhdl); + ASSERT(rc == GRAPH_SUCCESS); + rc = rc; + + hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]); + + /* Add system controller */ + +#ifdef __ia64 + sprintf(name, + EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, + buffer); +#else + sprintf(name, + EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1, + modules[cm]->id); +#endif + + rc = hwgraph_path_add(hwgraph_root, name, &vhdl); + ASSERT_ALWAYS(rc == GRAPH_SUCCESS); + rc = rc; + + hwgraph_info_add_LBL(vhdl, + INFO_LBL_ELSC, + (arbitrary_info_t) (__psint_t) 1); + +#ifdef LATER + sndrv_attach(vhdl); + /* + * We need to call the drivers attach routine .. + */ + FIXME("klhwg_add_all_modules: Need code to call driver attach.\n"); +#endif + } +} + +void +klhwg_add_all_nodes(devfs_handle_t hwgraph_root) +{ + cnodeid_t cnode; + + for (cnode = 0; cnode < numnodes; cnode++) { + klhwg_add_node(hwgraph_root, cnode, NULL); + } + + for (cnode = 0; cnode < numnodes; cnode++) { + klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode)); + } + + /* + * As for router hardware inventory information, we set this + * up in router.c. + */ + + klhwg_add_all_routers(hwgraph_root); + klhwg_connect_routers(hwgraph_root); + klhwg_connect_hubs(hwgraph_root); + + /* Go through the entire system's klconfig + * to figure out which pci components have been disabled + */ + klhwg_device_disable_hints_add(); + +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/l1.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/l1.c --- linux-2.4.19/arch/ia64/sn/io/sn1/l1.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/l1.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,3124 @@ +/* $Id: l1.c,v 1.3 2002/12/30 22:16:56 jh Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* In general, this file is organized in a hierarchy from lower-level + * to higher-level layers, as follows: + * + * UART routines + * Bedrock/L1 "PPP-like" protocol implementation + * System controller "message" interface (allows multiplexing + * of various kinds of requests and responses with + * console I/O) + * Console interface: + * "l1_cons", the glue that allows the L1 to act + * as the system console for the stdio libraries + * + * Routines making use of the system controller "message"-style interface + * can be found in l1_command.c. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Make all console writes atomic */ +#define SYNC_CONSOLE_WRITE 1 + + +/********************************************************************* + * Hardware-level (UART) driver routines. + */ + +/* macros for reading/writing registers */ + +/* USLD and USSD are needed for SN2 - but since we moving this code out soon ... */ +#define LD(x) (*(volatile uint64_t *)(x)) +#define USLD(x) LD(x) // (*(volatile ushort *)(x)) +#define SD(x, v) (LD(x) = (uint64_t) (v)) +#define USSD(x, v) SD(x,v) // (USLD(x) = (ushort) (v)) + +/* location of uart receive/xmit data register */ +#define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), 0x00000080)) +#define LOCK_HUB REMOTE_HUB_ADDR + +#define ADDR_L1_REG(n, r) ( L1_UART_BASE(n) | ( (r) << 3 ) ) +#define READ_L1_UART_REG(n, r) ( LD(ADDR_L1_REG((n), (r))) ) + +#define WRITE_L1_UART_REG(n, r, v) ( SD(ADDR_L1_REG((n), (r)), (v)) ) + +/* upper layer interface calling methods */ +#define SERIAL_INTERRUPT_MODE 0 +#define SERIAL_POLLED_MODE 1 + + +/* UART-related #defines */ + +#define UART_BAUD_RATE 57600 +#define UART_FIFO_DEPTH 16 +#define UART_DELAY_SPAN 10 +#define UART_PUTC_TIMEOUT 50000 +#define UART_INIT_TIMEOUT 100000 + +/* error codes */ +#define UART_SUCCESS 0 +#define UART_TIMEOUT (-1) +#define UART_LINK (-2) +#define UART_NO_CHAR (-3) +#define UART_VECTOR (-4) + +#define UART_DELAY(x) udelay(x) + +/* Some debug counters */ +#define L1C_INTERRUPTS 0 +#define L1C_OUR_R_INTERRUPTS 1 +#define L1C_OUR_X_INTERRUPTS 2 +#define L1C_SEND_CALLUPS 3 +#define L1C_RECEIVE_CALLUPS 4 +#define L1C_SET_BAUD 5 +#define L1C_ALREADY_LOCKED L1C_SET_BAUD +#define L1C_R_IRQ 6 +#define L1C_R_IRQ_RET 7 +#define L1C_LOCK_TIMEOUTS 8 +#define L1C_LOCK_COUNTER 9 +#define L1C_UNLOCK_COUNTER 10 +#define L1C_REC_STALLS 11 +#define L1C_CONNECT_CALLS 12 +#define L1C_SIZE L1C_CONNECT_CALLS /* Set to the last one */ + +uint64_t L1_collectibles[L1C_SIZE + 1]; + + +/* + * Some macros for handling Endian-ness + */ + +#define COPY_INT_TO_BUFFER(_b, _i, _n) \ + { \ + _b[_i++] = (_n >> 24) & 0xff; \ + _b[_i++] = (_n >> 16) & 0xff; \ + _b[_i++] = (_n >> 8) & 0xff; \ + _b[_i++] = _n & 0xff; \ + } + +#define COPY_BUFFER_TO_INT(_b, _i, _n) \ + { \ + _n = (_b[_i++] << 24) & 0xff; \ + _n |= (_b[_i++] << 16) & 0xff; \ + _n |= (_b[_i++] << 8) & 0xff; \ + _n |= _b[_i++] & 0xff; \ + } + +#define COPY_BUFFER_TO_BUFFER(_b, _i, _bn) \ + { \ + char *_xyz = (char *)_bn; \ + _xyz[3] = _b[_i++]; \ + _xyz[2] = _b[_i++]; \ + _xyz[1] = _b[_i++]; \ + _xyz[0] = _b[_i++]; \ + } + +void snia_kmem_free(void *where, int size); + +#define ALREADY_LOCKED 1 +#define NOT_LOCKED 0 +static int early_l1_serial_out(nasid_t, char *, int, int /* defines above*/ ); + +#define BCOPY(x,y,z) memcpy(y,x,z) + +uint8_t L1_interrupts_connected; /* Non-zero when we are in interrupt mode */ + + +/* + * Console locking defines and functions. + * + */ + +uint8_t L1_cons_is_inited = 0; /* non-zero when console is init'd */ +nasid_t Master_console_nasid = (nasid_t)-1; +extern nasid_t console_nasid; + +u64 ia64_sn_get_console_nasid(void); + +inline nasid_t +get_master_nasid(void) +{ + nasid_t nasid = Master_console_nasid; + + master_nasid = Master_console_nasid = nasid = 0; + if ( nasid == (nasid_t)-1 ) { + nasid = (nasid_t)ia64_sn_get_console_nasid(); + if ( (nasid < 0) || (nasid >= MAX_NASIDS) ) { + /* Out of bounds, use local */ + console_nasid = nasid = get_nasid(); + } + else { + /* Got a valid nasid, set the console_nasid */ + char xx[100]; +/* zzzzzz - force nasid to 0 for now */ + sprintf(xx, "Master console is set to nasid %d (%d)\n", 0, (int)nasid); +nasid = 0; +/* end zzzzzz */ + xx[99] = (char)0; + early_l1_serial_out(nasid, xx, strlen(xx), NOT_LOCKED); + Master_console_nasid = console_nasid = nasid; + } + } + return(nasid); +} + + + +#define HUB_LOCK 16 + +#define PRIMARY_LOCK_TIMEOUT 10000000 +#define HUB_LOCK_REG(n) LOCK_HUB(n, MD_PERF_CNT0) + +#define SET_BITS(reg, bits) SD(reg, LD(reg) | (bits)) +#define CLR_BITS(reg, bits) SD(reg, LD(reg) & ~(bits)) +#define TST_BITS(reg, bits) ((LD(reg) & (bits)) != 0) + +#define HUB_TEST_AND_SET(n) LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ)) +#define HUB_CLEAR(n) SD(LOCK_HUB(n,LB_SCRATCH_REG3),0) + +#define RTC_TIME_MAX ((rtc_time_t) ~0ULL) + +/* + * primary_lock + * + * Allows CPU's 0-3 to mutually exclude the hub from one another by + * obtaining a blocking lock. Does nothing if only one CPU is active. + * + * This lock should be held just long enough to set or clear a global + * lock bit. After a relatively short timeout period, this routine + * figures something is wrong, and steals the lock. It does not set + * any other CPU to "dead". + */ +inline void +primary_lock(nasid_t nasid) +{ + rtc_time_t expire; + + expire = rtc_time() + PRIMARY_LOCK_TIMEOUT; + + while (HUB_TEST_AND_SET(nasid)) { + if (rtc_time() > expire) { + HUB_CLEAR(nasid); + } + } +} + +/* + * primary_unlock (internal) + * + * Counterpart to primary_lock + */ + +inline void +primary_unlock(nasid_t nasid) +{ + HUB_CLEAR(nasid); +} + +/* + * hub_unlock + * + * Counterpart to hub_lock_timeout and hub_lock + */ + +inline void +hub_unlock(nasid_t nasid, int level) +{ + uint64_t mask = 1ULL << level; + + primary_lock(nasid); + CLR_BITS(HUB_LOCK_REG(nasid), mask); + primary_unlock(nasid); +} + +/* + * hub_lock_timeout + * + * Uses primary_lock to implement multiple lock levels. + * + * There are 20 lock levels from 0 to 19 (limited by the number of bits + * in HUB_LOCK_REG). To prevent deadlock, multiple locks should be + * obtained in order of increasingly higher level, and released in the + * reverse order. + * + * A timeout value of 0 may be used for no timeout. + * + * Returns 0 if successful, -1 if lock times out. + */ + +inline int +hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout) +{ + uint64_t mask = 1ULL << level; + rtc_time_t expire = (timeout ? rtc_time() + timeout : RTC_TIME_MAX); + int done = 0; + + while (! done) { + while (TST_BITS(HUB_LOCK_REG(nasid), mask)) { + if (rtc_time() > expire) + return -1; + } + + primary_lock(nasid); + + if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) { + SET_BITS(HUB_LOCK_REG(nasid), mask); + done = 1; + } + primary_unlock(nasid); + } + return 0; +} + + +#define LOCK_TIMEOUT (0x1500000 * 1) /* 0x1500000 is ~30 sec */ + +void +lock_console(nasid_t nasid) +{ + int ret; + + /* If we already have it locked, just return */ + L1_collectibles[L1C_LOCK_COUNTER]++; + + ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); + if ( ret != 0 ) { + L1_collectibles[L1C_LOCK_TIMEOUTS]++; + /* timeout */ + hub_unlock(nasid, HUB_LOCK); + /* If the 2nd lock fails, just pile ahead.... */ + hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); + L1_collectibles[L1C_LOCK_TIMEOUTS]++; + } +} + +inline void +unlock_console(nasid_t nasid) +{ + L1_collectibles[L1C_UNLOCK_COUNTER]++; + hub_unlock(nasid, HUB_LOCK); +} + + +int +get_L1_baud(void) +{ + return UART_BAUD_RATE; +} + + +/* uart driver functions */ + +static inline void +uart_delay( rtc_time_t delay_span ) +{ + UART_DELAY( delay_span ); +} + +#define UART_PUTC_READY(n) (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) + +static int +uart_putc( l1sc_t *sc ) +{ + WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] ); + return UART_SUCCESS; +} + + +static int +uart_getc( l1sc_t *sc ) +{ + u_char lsr_reg = 0; + nasid_t nasid = sc->nasid; + + if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & + (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) + { + if( lsr_reg & LSR_RCA ) + return( (u_char)READ_L1_UART_REG( nasid, REG_DAT ) ); + else if( lsr_reg & (LSR_PARERR | LSR_FRMERR) ) { + return UART_LINK; + } + } + return UART_NO_CHAR; +} + + +#define PROM_SER_CLK_SPEED 12000000 +#define PROM_SER_DIVISOR(x) (PROM_SER_CLK_SPEED / ((x) * 16)) + +static void +uart_init( l1sc_t *sc, int baud ) +{ +#if !defined(USE_SAL_CONSOLE_IO) + rtc_time_t expire; + int clkdiv; + nasid_t nasid; + + clkdiv = PROM_SER_DIVISOR(baud); + expire = rtc_time() + UART_INIT_TIMEOUT; + nasid = sc->nasid; + + /* make sure the transmit FIFO is empty */ + while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XSRE) ) { + uart_delay( UART_DELAY_SPAN ); + if( rtc_time() > expire ) { + break; + } + } + + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(nasid); + + /* Setup for the proper baud rate */ + WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB ); + uart_delay( UART_DELAY_SPAN ); + WRITE_L1_UART_REG( nasid, REG_DLH, (clkdiv >> 8) & 0xff ); + uart_delay( UART_DELAY_SPAN ); + WRITE_L1_UART_REG( nasid, REG_DLL, clkdiv & 0xff ); + uart_delay( UART_DELAY_SPAN ); + + /* set operating parameters and set DLAB to 0 */ + + /* 8bit, one stop, clear request to send, auto flow control */ + WRITE_L1_UART_REG( nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); + uart_delay( UART_DELAY_SPAN ); + WRITE_L1_UART_REG( nasid, REG_MCR, MCR_RTS | MCR_AFE ); + uart_delay( UART_DELAY_SPAN ); + + /* disable interrupts */ + WRITE_L1_UART_REG( nasid, REG_ICR, 0x0 ); + uart_delay( UART_DELAY_SPAN ); + + /* enable FIFO mode and reset both FIFOs, trigger on 1 */ + WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN ); + uart_delay( UART_DELAY_SPAN ); + WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO | RxLVL0); + + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(nasid); +#endif /* !USE_SAL_CONSOLE_IO */ +} + +/* This requires the console lock */ + + +static void +uart_intr_enable( l1sc_t *sc, u_char mask ) +{ + u_char lcr_reg, icr_reg; + nasid_t nasid = sc->nasid; + + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(nasid); + + /* make sure that the DLAB bit in the LCR register is 0 + */ + lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); + lcr_reg &= ~(LCR_DLAB); + WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); + + /* enable indicated interrupts + */ + icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); + icr_reg |= mask; + WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); + + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(nasid); +} + +/* This requires the console lock */ +static void +uart_intr_disable( l1sc_t *sc, u_char mask ) +{ + u_char lcr_reg, icr_reg; + nasid_t nasid = sc->nasid; + + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(nasid); + + /* make sure that the DLAB bit in the LCR register is 0 + */ + lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); + lcr_reg &= ~(LCR_DLAB); + WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); + + /* enable indicated interrupts + */ + icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); + icr_reg &= mask; + WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); + + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(nasid); +} + +#define uart_enable_xmit_intr(sc) \ + uart_intr_enable((sc), ICR_TIEN) + +#define uart_disable_xmit_intr(sc) \ + uart_intr_disable((sc), ~(ICR_TIEN)) + +#define uart_enable_recv_intr(sc) \ + uart_intr_enable((sc), ICR_RIEN) + +#define uart_disable_recv_intr(sc) \ + uart_intr_disable((sc), ~(ICR_RIEN)) + + +/********************************************************************* + * Routines for accessing a remote (router) UART + */ + +#define READ_RTR_L1_UART_REG(p, n, r, v) \ + { \ + if( vector_read_node( (p), (n), 0, \ + RR_JBUS1(r), (v) ) ) { \ + return UART_VECTOR; \ + } \ + } + +#define WRITE_RTR_L1_UART_REG(p, n, r, v) \ + { \ + if( vector_write_node( (p), (n), 0, \ + RR_JBUS1(r), (v) ) ) { \ + return UART_VECTOR; \ + } \ + } + +#define RTR_UART_PUTC_TIMEOUT UART_PUTC_TIMEOUT*10 +#define RTR_UART_DELAY_SPAN UART_DELAY_SPAN +#define RTR_UART_INIT_TIMEOUT UART_INIT_TIMEOUT*10 + +static int +rtr_uart_putc( l1sc_t *sc ) +{ + uint64_t regval, c; + nasid_t nasid = sc->nasid; + net_vec_t path = sc->uart; + rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT; + + c = (sc->send[sc->sent] & 0xffULL); + + while( 1 ) + { + /* Check for "tx hold reg empty" bit. */ + READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); + if( regval & LSR_XHRE ) + { + WRITE_RTR_L1_UART_REG( path, nasid, REG_DAT, c ); + return UART_SUCCESS; + } + + if( rtc_time() >= expire ) + { + return UART_TIMEOUT; + } + uart_delay( RTR_UART_DELAY_SPAN ); + } +} + + +static int +rtr_uart_getc( l1sc_t *sc ) +{ + uint64_t regval; + nasid_t nasid = sc->nasid; + net_vec_t path = sc->uart; + + READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); + if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) + { + if( regval & LSR_RCA ) + { + READ_RTR_L1_UART_REG( path, nasid, REG_DAT, ®val ); + return( (int)regval ); + } + else + { + return UART_LINK; + } + } + + return UART_NO_CHAR; +} + + +static int +rtr_uart_init( l1sc_t *sc, int baud ) +{ + rtc_time_t expire; + int clkdiv; + nasid_t nasid; + net_vec_t path; + uint64_t regval; + + clkdiv = PROM_SER_DIVISOR(baud); + expire = rtc_time() + RTR_UART_INIT_TIMEOUT; + nasid = sc->nasid; + path = sc->uart; + + /* make sure the transmit FIFO is empty */ + while(1) { + READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); + if( regval & LSR_XSRE ) { + break; + } + if( rtc_time() > expire ) { + break; + } + uart_delay( RTR_UART_DELAY_SPAN ); + } + + WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_DLAB ); + uart_delay( UART_DELAY_SPAN ); + WRITE_RTR_L1_UART_REG( path, nasid, REG_DLH, (clkdiv >> 8) & 0xff ); + uart_delay( UART_DELAY_SPAN ); + WRITE_RTR_L1_UART_REG( path, nasid, REG_DLL, clkdiv & 0xff ); + uart_delay( UART_DELAY_SPAN ); + + /* set operating parameters and set DLAB to 0 */ + WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); + uart_delay( UART_DELAY_SPAN ); + WRITE_RTR_L1_UART_REG( path, nasid, REG_MCR, MCR_RTS | MCR_AFE ); + uart_delay( UART_DELAY_SPAN ); + + /* disable interrupts */ + WRITE_RTR_L1_UART_REG( path, nasid, REG_ICR, 0x0 ); + uart_delay( UART_DELAY_SPAN ); + + /* enable FIFO mode and reset both FIFOs */ + WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, FCR_FIFOEN ); + uart_delay( UART_DELAY_SPAN ); + WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, + FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO ); + + return 0; +} + +/********************************************************************* + * locking macros + */ + +#define L1SC_SEND_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->send_lock),p); } +#define L1SC_SEND_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->send_lock), p); } +#define L1SC_RECV_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->recv_lock), p); } +#define L1SC_RECV_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->recv_lock), p); } + + +/********************************************************************* + * subchannel manipulation + * + * The SUBCH_[UN]LOCK macros are used to arbitrate subchannel + * allocation. SUBCH_DATA_[UN]LOCK control access to data structures + * associated with particular subchannels (e.g., receive queues). + * + */ +#define SUBCH_LOCK(sc, p) spin_lock_irqsave( &((sc)->subch_lock), p ) +#define SUBCH_UNLOCK(sc, p) spin_unlock_irqrestore( &((sc)->subch_lock), p ) +#define SUBCH_DATA_LOCK(sbch, p) spin_lock_irqsave( &((sbch)->data_lock), p ) +#define SUBCH_DATA_UNLOCK(sbch, p) spin_unlock_irqrestore( &((sbch)->data_lock), p ) + + +/* + * set a function to be called for subchannel ch in the event of + * a transmission low-water interrupt from the uart + */ +void +subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) +{ + unsigned long pl = 0; + + L1SC_SEND_LOCK( sc, pl ); +#if !defined(SYNC_CONSOLE_WRITE) + if ( func && !sc->send_in_use ) + uart_enable_xmit_intr( sc ); +#endif + sc->subch[ch].tx_notify = func; + L1SC_SEND_UNLOCK(sc, pl ); +} + +/* + * set a function to be called for subchannel ch when data is received + */ +void +subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) +{ + unsigned long pl = 0; + brl1_sch_t *subch = &(sc->subch[ch]); + + SUBCH_DATA_LOCK( subch, pl ); + sc->subch[ch].rx_notify = func; + SUBCH_DATA_UNLOCK( subch, pl ); +} + +/********************************************************************* + * Queue manipulation macros + * + * + */ +#define NEXT(p) (((p) + 1) & (BRL1_QSIZE-1)) /* assume power of 2 */ + +#define cq_init(q) bzero((q), sizeof (*(q))) +#define cq_empty(q) ((q)->ipos == (q)->opos) +#define cq_full(q) (NEXT((q)->ipos) == (q)->opos) +#define cq_used(q) ((q)->opos <= (q)->ipos ? \ + (q)->ipos - (q)->opos : \ + BRL1_QSIZE + (q)->ipos - (q)->opos) +#define cq_room(q) ((q)->opos <= (q)->ipos ? \ + BRL1_QSIZE - 1 + (q)->opos - (q)->ipos : \ + (q)->opos - (q)->ipos - 1) +#define cq_add(q, c) ((q)->buf[(q)->ipos] = (u_char) (c), \ + (q)->ipos = NEXT((q)->ipos)) +#define cq_rem(q, c) ((c) = (q)->buf[(q)->opos], \ + (q)->opos = NEXT((q)->opos)) +#define cq_discard(q) ((q)->opos = NEXT((q)->opos)) + +#define cq_tent_full(q) (NEXT((q)->tent_next) == (q)->opos) +#define cq_tent_len(q) ((q)->ipos <= (q)->tent_next ? \ + (q)->tent_next - (q)->ipos : \ + BRL1_QSIZE + (q)->tent_next - (q)->ipos) +#define cq_tent_add(q, c) \ + ((q)->buf[(q)->tent_next] = (u_char) (c), \ + (q)->tent_next = NEXT((q)->tent_next)) +#define cq_commit_tent(q) \ + ((q)->ipos = (q)->tent_next) +#define cq_discard_tent(q) \ + ((q)->tent_next = (q)->ipos) + + + + +/********************************************************************* + * CRC-16 (for checking bedrock/L1 packets). + * + * These are based on RFC 1662 ("PPP in HDLC-like framing"). + */ + +static unsigned short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +#define INIT_CRC 0xFFFF /* initial CRC value */ +#define GOOD_CRC 0xF0B8 /* "good" final CRC value */ + +static unsigned short crc16_calc( unsigned short crc, u_char c ) +{ + return( (crc >> 8) ^ fcstab[(crc ^ c) & 0xff] ); +} + + +/*********************************************************************** + * The following functions implement the PPP-like bedrock/L1 protocol + * layer. + * + */ + +#define BRL1_FLAG_CH 0x7e +#define BRL1_ESC_CH 0x7d +#define BRL1_XOR_CH 0x20 + +/* L1<->Bedrock packet types */ +#define BRL1_REQUEST 0x00 +#define BRL1_RESPONSE 0x20 +#define BRL1_EVENT 0x40 + +#define BRL1_PKT_TYPE_MASK 0xE0 +#define BRL1_SUBCH_MASK 0x1F + +#define PKT_TYPE(tsb) ((tsb) & BRL1_PKT_TYPE_MASK) +#define SUBCH(tsb) ((tsb) & BRL1_SUBCH_MASK) + +/* timeouts */ +#define BRL1_INIT_TIMEOUT 500000 + +/* + * brl1_discard_packet is a dummy "receive callback" used to get rid + * of packets we don't want + */ +void brl1_discard_packet( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) +{ + unsigned long pl = 0; + brl1_sch_t *subch = &sc->subch[ch]; + + sc_cq_t *q = subch->iqp; + SUBCH_DATA_LOCK( subch, pl ); + q->opos = q->ipos; + atomic_set(&(subch->packet_arrived), 0); + SUBCH_DATA_UNLOCK( subch, pl ); +} + + +/* + * brl1_send_chars sends the send buffer in the l1sc_t structure + * out through the uart. Assumes that the caller has locked the + * UART (or send buffer in the kernel). + * + * This routine doesn't block-- if you want it to, call it in + * a loop. + */ +static int +brl1_send_chars( l1sc_t *sc ) +{ + /* We track the depth of the C brick's UART's + * fifo in software, and only check if the UART is accepting + * characters when our count indicates that the fifo should + * be full. + * + * For remote (router) UARTs, we check with the UART before sending every + * character. + */ + if( sc->uart == BRL1_LOCALHUB_UART ) { + if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) ) + sc->fifo_space = UART_FIFO_DEPTH; + + while( (sc->sent < sc->send_len) && (sc->fifo_space) ) { + uart_putc( sc ); + sc->fifo_space--; + sc->sent++; + } + } + else { + + /* remote (router) UARTs */ + + int result; + int tries = 0; + + while( sc->sent < sc->send_len ) { + result = sc->putc_f( sc ); + if( result >= 0 ) { + (sc->sent)++; + continue; + } + if( result == UART_TIMEOUT ) { + tries++; + /* send this character in TIMEOUT_RETRIES... */ + if( tries < 30 /* TIMEOUT_RETRIES */ ) { + continue; + } + /* ...or else... */ + else { + /* ...drop the packet. */ + sc->sent = sc->send_len; + return sc->send_len; + } + } + if( result < 0 ) { + return result; + } + } + } + return sc->sent; +} + + +/* brl1_send formats up a packet and (at least begins to) send it + * to the uart. If the send buffer is in use when this routine obtains + * the lock, it will behave differently depending on the "wait" parameter. + * For wait == 0 (most I/O), it will return 0 (as in "zero bytes sent"), + * hopefully encouraging the caller to back off (unlock any high-level + * spinlocks) and allow the buffer some time to drain. For wait==1 (high- + * priority I/O along the lines of kernel error messages), we will flush + * the current contents of the send buffer and beat on the uart + * until our message has been completely transmitted. + */ + +static int +brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait ) +{ + unsigned long pl = 0; + int index; + int pkt_len = 0; + unsigned short crc = INIT_CRC; + char *send_ptr = sc->send; + + + if( sc->send_in_use && !(wait) ) { + /* We are in the middle of sending, but can wait until done */ + return 0; + } + else if( sc->send_in_use ) { + /* buffer's in use, but we're synchronous I/O, so we're going + * to send whatever's in there right now and take the buffer + */ + int counter = 0; + + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(sc->nasid); + L1SC_SEND_LOCK(sc, pl); + while( sc->sent < sc->send_len ) { + brl1_send_chars( sc ); + if ( counter++ > 0xfffff ) { + char *str = "Looping waiting for uart to clear (1)\n"; + early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); + break; + } + } + } + else { + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(sc->nasid); + L1SC_SEND_LOCK(sc, pl); + sc->send_in_use = 1; + } + *send_ptr++ = BRL1_FLAG_CH; + *send_ptr++ = type_and_subch; + pkt_len += 2; + crc = crc16_calc( crc, type_and_subch ); + + /* limit number of characters accepted to max payload size */ + if( len > (BRL1_QSIZE - 1) ) + len = (BRL1_QSIZE - 1); + + /* copy in the message buffer (inserting PPP + * framing info where necessary) + */ + for( index = 0; index < len; index++ ) { + + switch( *msg ) { + + case BRL1_FLAG_CH: + *send_ptr++ = BRL1_ESC_CH; + *send_ptr++ = (*msg) ^ BRL1_XOR_CH; + pkt_len += 2; + break; + + case BRL1_ESC_CH: + *send_ptr++ = BRL1_ESC_CH; + *send_ptr++ = (*msg) ^ BRL1_XOR_CH; + pkt_len += 2; + break; + + default: + *send_ptr++ = *msg; + pkt_len++; + } + crc = crc16_calc( crc, *msg ); + msg++; + } + crc ^= 0xffff; + + for( index = 0; index < sizeof(crc); index++ ) { + char crc_char = (char)(crc & 0x00FF); + if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { + *send_ptr++ = BRL1_ESC_CH; + pkt_len++; + crc_char ^= BRL1_XOR_CH; + } + *send_ptr++ = crc_char; + pkt_len++; + crc >>= 8; + } + + *send_ptr++ = BRL1_FLAG_CH; + pkt_len++; + + sc->send_len = pkt_len; + sc->sent = 0; + + { + int counter = 0; + do { + brl1_send_chars( sc ); + if ( counter++ > 0xfffff ) { + char *str = "Looping waiting for uart to clear (2)\n"; + early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); + break; + } + } while( (sc->sent < sc->send_len) && wait ); + } + + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(sc->nasid); + + if( sc->sent == sc->send_len ) { + /* success! release the send buffer and call the callup */ +#if !defined(SYNC_CONSOLE_WRITE) + brl1_notif_t callup; +#endif + + sc->send_in_use = 0; + /* call any upper layer that's asked for notification */ +#if defined(XX_SYNC_CONSOLE_WRITE) + /* + * This is probably not a good idea - since the l1_ write func can be called multiple + * time within the callup function. + */ + callup = subch->tx_notify; + if( callup && (SUBCH(type_and_subch) == SC_CONS_SYSTEM) ) { + L1_collectibles[L1C_SEND_CALLUPS]++; + (*callup)(sc->subch[SUBCH(type_and_subch)].irq_frame.bf_irq, + sc->subch[SUBCH(type_and_subch)].irq_frame.bf_dev_id, + sc->subch[SUBCH(type_and_subch)].irq_frame.bf_regs, sc, SUBCH(type_and_subch)); + } +#endif /* SYNC_CONSOLE_WRITE */ + } +#if !defined(SYNC_CONSOLE_WRITE) + else if ( !wait ) { + /* enable low-water interrupts so buffer will be drained */ + uart_enable_xmit_intr(sc); + } +#endif + + L1SC_SEND_UNLOCK(sc, pl); + + return len; +} + +/* brl1_send_cont is intended to be called as an interrupt service + * routine. It sends until the UART won't accept any more characters, + * or until an error is encountered (in which case we surrender the + * send buffer and give up trying to send the packet). Once the + * last character in the packet has been sent, this routine releases + * the send buffer and calls any previously-registered "low-water" + * output routines. + */ + +#if !defined(SYNC_CONSOLE_WRITE) + +int +brl1_send_cont( l1sc_t *sc ) +{ + unsigned long pl = 0; + int done = 0; + brl1_notif_t callups[BRL1_NUM_SUBCHANS]; + brl1_notif_t *callup; + brl1_sch_t *subch; + int index; + + /* + * I'm not sure how I think this is to be handled - whether the lock is held + * over the interrupt - but it seems like it is a bad idea.... + */ + + if ( sc->uart == BRL1_LOCALHUB_UART ) + lock_console(sc->nasid); + L1SC_SEND_LOCK(sc, pl); + brl1_send_chars( sc ); + done = (sc->sent == sc->send_len); + if( done ) { + sc->send_in_use = 0; +#if !defined(SYNC_CONSOLE_WRITE) + uart_disable_xmit_intr(sc); +#endif + } + if ( sc->uart == BRL1_LOCALHUB_UART ) + unlock_console(sc->nasid); + /* Release the lock */ + L1SC_SEND_UNLOCK(sc, pl); + + return 0; +} +#endif /* SYNC_CONSOLE_WRITE */ + +/* internal function -- used by brl1_receive to read a character + * from the uart and check whether errors occurred in the process. + */ +static int +read_uart( l1sc_t *sc, int *c, int *result ) +{ + *c = sc->getc_f( sc ); + + /* no character is available */ + if( *c == UART_NO_CHAR ) { + *result = BRL1_NO_MESSAGE; + return 0; + } + + /* some error in UART */ + if( *c < 0 ) { + *result = BRL1_LINK; + return 0; + } + + /* everything's fine */ + *result = BRL1_VALID; + return 1; +} + + +/* + * brl1_receive + * + * This function reads a Bedrock-L1 protocol packet into the l1sc_t + * response buffer. + * + * The operation of this function can be expressed as a finite state + * machine: + * + +START STATE INPUT TRANSITION +========================================================== +BRL1_IDLE (reset or error) flag BRL1_FLAG + other BRL1_IDLE@ + +BRL1_FLAG (saw a flag (0x7e)) flag BRL1_FLAG + escape BRL1_IDLE@ + header byte BRL1_HDR + other BRL1_IDLE@ + +BRL1_HDR (saw a type/subch byte)(see below) BRL1_BODY + BRL1_HDR + +BRL1_BODY (reading packet body) flag BRL1_FLAG + escape BRL1_ESC + other BRL1_BODY + +BRL1_ESC (saw an escape (0x7d)) flag BRL1_FLAG@ + escape BRL1_IDLE@ + other BRL1_BODY +========================================================== + +"@" denotes an error transition. + + * The BRL1_HDR state is a transient state which doesn't read input, + * but just provides a way in to code which decides to whom an + * incoming packet should be directed. + * + * brl1_receive can be used to poll for input from the L1, or as + * an interrupt service routine. It reads as much data as is + * ready from the junk bus UART and places into the appropriate + * input queues according to subchannel. The header byte is + * stripped from console-type data, but is retained for message- + * type data (L1 responses). A length byte will also be + * prepended to message-type packets. + * + * This routine is non-blocking; if the caller needs to block + * for input, it must call brl1_receive in a loop. + * + * brl1_receive returns when there is no more input, the queue + * for the current incoming message is full, or there is an + * error (parity error, bad header, bad CRC, etc.). + */ + +#define STATE_SET(l,s) ((l)->brl1_state = (s)) +#define STATE_GET(l) ((l)->brl1_state) + +#define LAST_HDR_SET(l,h) ((l)->brl1_last_hdr = (h)) +#define LAST_HDR_GET(l) ((l)->brl1_last_hdr) + +#define VALID_HDR(c) \ + ( SUBCH((c)) <= SC_CONS_SYSTEM \ + ? PKT_TYPE((c)) == BRL1_REQUEST \ + : ( PKT_TYPE((c)) == BRL1_RESPONSE || \ + PKT_TYPE((c)) == BRL1_EVENT ) ) + +#define IS_TTY_PKT(l) ( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 ) + + +int +brl1_receive( l1sc_t *sc, int mode ) +{ + int result; /* value to be returned by brl1_receive */ + int c; /* most-recently-read character */ + int done; /* set done to break out of recv loop */ + unsigned long pl = 0, cpl = 0; + sc_cq_t *q; /* pointer to queue we're working with */ + + result = BRL1_NO_MESSAGE; + + L1SC_RECV_LOCK(sc, cpl); + + done = 0; + while( !done ) + { + switch( STATE_GET(sc) ) + { + + case BRL1_IDLE: + /* Initial or error state. Waiting for a flag character + * to resynchronize with the L1. + */ + + if( !read_uart( sc, &c, &result ) ) { + + /* error reading uart */ + done = 1; + continue; + } + + if( c == BRL1_FLAG_CH ) { + /* saw a flag character */ + STATE_SET( sc, BRL1_FLAG ); + continue; + } + break; + + case BRL1_FLAG: + /* One or more flag characters have been read; look for + * the beginning of a packet (header byte). + */ + + if( !read_uart( sc, &c, &result ) ) { + + /* error reading uart */ + if( c != UART_NO_CHAR ) + STATE_SET( sc, BRL1_IDLE ); + + done = 1; + continue; + } + + if( c == BRL1_FLAG_CH ) { + /* multiple flags are OK */ + continue; + } + + if( !VALID_HDR( c ) ) { + /* if c isn't a flag it should have been + * a valid header, so we have an error + */ + result = BRL1_PROTOCOL; + STATE_SET( sc, BRL1_IDLE ); + done = 1; + continue; + } + + /* we have a valid header byte */ + LAST_HDR_SET( sc, c ); + STATE_SET( sc, BRL1_HDR ); + + break; + + case BRL1_HDR: + /* A header byte has been read. Do some bookkeeping. */ + q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; + ASSERT(q); + + if( !IS_TTY_PKT(sc) ) { + /* if this is an event or command response rather + * than console I/O, we need to reserve a couple + * of extra spaces in the queue for the header + * byte and a length byte; if we can't, stay in + * the BRL1_HDR state. + */ + if( cq_room( q ) < 2 ) { + result = BRL1_FULL_Q; + done = 1; + continue; + } + cq_tent_add( q, 0 ); /* reserve length byte */ + cq_tent_add( q, LAST_HDR_GET( sc ) ); /* record header byte */ + } + STATE_SET( sc, BRL1_BODY ); + + break; + + case BRL1_BODY: + /* A header byte has been read. We are now attempting + * to receive the packet body. + */ + + q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; + ASSERT(q); + + /* if the queue we want to write into is full, don't read from + * the uart (this provides backpressure to the L1 side) + */ + if( cq_tent_full( q ) ) { + result = BRL1_FULL_Q; + done = 1; + continue; + } + + if( !read_uart( sc, &c, &result ) ) { + + /* error reading uart */ + if( c != UART_NO_CHAR ) + STATE_SET( sc, BRL1_IDLE ); + done = 1; + continue; + } + + if( c == BRL1_ESC_CH ) { + /* prepare to unescape the next character */ + STATE_SET( sc, BRL1_ESC ); + continue; + } + + if( c == BRL1_FLAG_CH ) { + /* flag signifies the end of a packet */ + + unsigned short crc; /* holds the crc as we calculate it */ + int i; /* index variable */ + brl1_sch_t *subch; /* subchannel for received packet */ + brl1_notif_t callup; /* "data ready" callup */ + + /* whatever else may happen, we've seen a flag and we're + * starting a new packet + */ + STATE_SET( sc, BRL1_FLAG ); + + /* if the packet body has less than 2 characters, + * it can't be a well-formed packet. Discard it. + */ + if( cq_tent_len( q ) < /* 2 + possible length byte */ + (2 + (IS_TTY_PKT(sc) ? 0 : 1)) ) + { + result = BRL1_PROTOCOL; + cq_discard_tent( q ); + STATE_SET( sc, BRL1_FLAG ); + done = 1; + continue; + } + + /* check CRC */ + + /* accumulate CRC, starting with the header byte and + * ending with the transmitted CRC. This should + * result in a known good value. + */ + crc = crc16_calc( INIT_CRC, LAST_HDR_GET(sc) ); + for( i = (q->ipos + (IS_TTY_PKT(sc) ? 0 : 2)) % BRL1_QSIZE; + i != q->tent_next; + i = (i + 1) % BRL1_QSIZE ) + { + crc = crc16_calc( crc, q->buf[i] ); + } + + /* verify the caclulated crc against the "good" crc value; + * if we fail, discard the bad packet and return an error. + */ + if( crc != (unsigned short)GOOD_CRC ) { + result = BRL1_CRC; + cq_discard_tent( q ); + STATE_SET( sc, BRL1_FLAG ); + done = 1; + continue; + } + + /* so the crc check was ok. Now we discard the CRC + * from the end of the received bytes. + */ + q->tent_next += (BRL1_QSIZE - 2); + q->tent_next %= BRL1_QSIZE; + + /* get the subchannel and lock it */ + subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); + SUBCH_DATA_LOCK( subch, pl ); + + /* if this isn't a console packet, we need to record + * a length byte + */ + if( !IS_TTY_PKT(sc) ) { + q->buf[q->ipos] = cq_tent_len( q ) - 1; + } + + /* record packet for posterity */ + cq_commit_tent( q ); + result = BRL1_VALID; + + /* notify subchannel owner that there's something + * on the queue for them + */ + atomic_inc(&(subch->packet_arrived)); + callup = subch->rx_notify; + SUBCH_DATA_UNLOCK( subch, pl ); + + if( callup && (mode == SERIAL_INTERRUPT_MODE) ) { + L1SC_RECV_UNLOCK( sc, cpl ); + L1_collectibles[L1C_RECEIVE_CALLUPS]++; + (*callup)( sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_irq, + sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_dev_id, + sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_regs, + sc, SUBCH(LAST_HDR_GET(sc)) ); + L1SC_RECV_LOCK( sc, cpl ); + } + continue; /* go back for more! */ + } + + /* none of the special cases applied; we've got a normal + * body character + */ + cq_tent_add( q, c ); + + break; + + case BRL1_ESC: + /* saw an escape character. The next character will need + * to be unescaped. + */ + + q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; + ASSERT(q); + + /* if the queue we want to write into is full, don't read from + * the uart (this provides backpressure to the L1 side) + */ + if( cq_tent_full( q ) ) { + result = BRL1_FULL_Q; + done = 1; + continue; + } + + if( !read_uart( sc, &c, &result ) ) { + + /* error reading uart */ + if( c != UART_NO_CHAR ) { + cq_discard_tent( q ); + STATE_SET( sc, BRL1_IDLE ); + } + done = 1; + continue; + } + + if( c == BRL1_FLAG_CH ) { + /* flag after escape is an error */ + STATE_SET( sc, BRL1_FLAG ); + cq_discard_tent( q ); + result = BRL1_PROTOCOL; + done = 1; + continue; + } + + if( c == BRL1_ESC_CH ) { + /* two consecutive escapes is an error */ + STATE_SET( sc, BRL1_IDLE ); + cq_discard_tent( q ); + result = BRL1_PROTOCOL; + done = 1; + continue; + } + + /* otherwise, we've got a character that needs + * to be unescaped + */ + cq_tent_add( q, (c ^ BRL1_XOR_CH) ); + STATE_SET( sc, BRL1_BODY ); + + break; + + } /* end of switch( STATE_GET(sc) ) */ + } /* end of while(!done) */ + + L1SC_RECV_UNLOCK( sc, cpl ); + + return result; +} + + +/* brl1_init initializes the Bedrock/L1 protocol layer. This includes + * zeroing out the send and receive state information. + */ + +void +brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) +{ + int i; + brl1_sch_t *subch; + + bzero( sc, sizeof( *sc ) ); + sc->nasid = nasid; + sc->uart = uart; + sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); + sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); + sc->sol = 1; + subch = sc->subch; + + /* initialize L1 subchannels + */ + + /* assign processor TTY channels */ + for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { + subch->use = BRL1_SUBCH_RSVD; + subch->packet_arrived = ATOMIC_INIT(0); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); + subch->tx_notify = NULL; + /* (for now, drop elscuart packets in the kernel) */ + subch->rx_notify = brl1_discard_packet; + subch->iqp = &sc->garbage_q; + } + + /* assign system TTY channel (first free subchannel after each + * processor's individual TTY channel has been assigned) + */ + subch->use = BRL1_SUBCH_RSVD; + subch->packet_arrived = ATOMIC_INIT(0); + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); + subch->tx_notify = NULL; + if( sc->uart == BRL1_LOCALHUB_UART ) { + subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) ); + ASSERT( subch->iqp ); + cq_init( subch->iqp ); + subch->rx_notify = NULL; + } + else { + /* we shouldn't be getting console input from remote UARTs */ + subch->iqp = &sc->garbage_q; + subch->rx_notify = brl1_discard_packet; + } + subch++; i++; + + /* "reserved" subchannels (0x05-0x0F); for now, throw away + * incoming packets + */ + for( ; i < 0x10; i++, subch++ ) { + subch->use = BRL1_SUBCH_FREE; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = brl1_discard_packet; + subch->iqp = &sc->garbage_q; + } + + /* remaining subchannels are free */ + for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { + subch->use = BRL1_SUBCH_FREE; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = brl1_discard_packet; + subch->iqp = &sc->garbage_q; + } + + /* initialize synchronization structures + */ + spin_lock_init( &(sc->subch_lock) ); + spin_lock_init( &(sc->send_lock) ); + spin_lock_init( &(sc->recv_lock) ); + + if( sc->uart == BRL1_LOCALHUB_UART ) { + uart_init( sc, UART_BAUD_RATE ); + } + else { + rtr_uart_init( sc, UART_BAUD_RATE ); + } + + /* Set up remaining fields using L1 command functions-- elsc_module_get + * to read the module id, elsc_debug_get to see whether or not we're + * in verbose mode. + */ + { + extern int elsc_module_get(l1sc_t *); + + sc->modid = elsc_module_get( sc ); + sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid); + sc->verbose = 1; + } +} + +/********************************************************************* + * These are interrupt-related functions used in the kernel to service + * the L1. + */ + +/* + * brl1_intrd is the function which is called on a console interrupt. + */ + + +static void +brl1_intrd(int irq, void *dev_id, struct pt_regs *stuff) +{ + u_char isr_reg; + l1sc_t *sc = get_elsc(); + int ret; + + L1_collectibles[L1C_INTERRUPTS]++; + isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); + + /* Save for callup args in console */ + sc->subch[SC_CONS_SYSTEM].irq_frame.bf_irq = irq; + sc->subch[SC_CONS_SYSTEM].irq_frame.bf_dev_id = dev_id; + sc->subch[SC_CONS_SYSTEM].irq_frame.bf_regs = stuff; + +#if defined(SYNC_CONSOLE_WRITE) + while( isr_reg & ISR_RxRDY ) +#else + while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) +#endif + { + if( isr_reg & ISR_RxRDY ) { + L1_collectibles[L1C_OUR_R_INTERRUPTS]++; + ret = brl1_receive(sc, SERIAL_INTERRUPT_MODE); + if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) + L1_collectibles[L1C_REC_STALLS] = ret; + } +#if !defined(SYNC_CONSOLE_WRITE) + if( (isr_reg & ISR_TxRDY) || (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) { + L1_collectibles[L1C_OUR_X_INTERRUPTS]++; + brl1_send_cont(sc); + } +#endif /* SYNC_CONSOLE_WRITE */ + isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); + } +} + + +/* + * Install a callback function for the system console subchannel + * to allow an upper layer to be notified when the send buffer + * has been emptied. + */ +static inline void +l1_tx_notif( brl1_notif_t func ) +{ + subch_set_tx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, + SC_CONS_SYSTEM, func ); +} + + +/* + * Install a callback function for the system console subchannel + * to allow an upper layer to be notified when a packet has been + * received. + */ +static inline void +l1_rx_notif( brl1_notif_t func ) +{ + subch_set_rx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, + SC_CONS_SYSTEM, func ); +} + + +/* brl1_intr is called directly from the uart interrupt; after it runs, the + * interrupt "daemon" xthread is signalled to continue. + */ +void +brl1_intr( void ) +{ +} + +#define BRL1_INTERRUPT_LEVEL 65 /* linux request_irq() value */ + +/* Return the current interrupt level */ + +//#define CONSOLE_POLLING_ALSO + +int +l1_get_intr_value( void ) +{ +#if defined(USE_SAL_CONSOLE_IO) + return(0); +#else +#if defined(CONSOLE_POLLING_ALSO) + return(0); +#else + return(BRL1_INTERRUPT_LEVEL); +#endif /* CONSOLE_POLLING_ALSO */ +#endif /* USE_SAL_CONSOLE_IO */ +} + +/* Disconnect the callup functions - throw away interrupts */ + +void +l1_unconnect_intr(void) +{ +#if !defined(USE_SAL_CONSOLE_IO) + /* UnRegister the upper-level callup functions */ + l1_rx_notif((brl1_notif_t)NULL); + l1_tx_notif((brl1_notif_t)NULL); + /* We do NOT unregister the interrupts */ +#endif /* !USE_SAL_CONSOLE_IO */ +} + +/* Set up uart interrupt handling for this node's uart */ + +void +l1_connect_intr(void *rx_notify, void *tx_notify) +{ +#if defined(USE_SAL_CONSOLE_IO) +#if 0 + // Will need code here for sn2 - something like this + console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()); + intr_connect_level(console_nodepda->node_first_cpu, + SGI_UART_VECTOR, INTPEND0_MAXMASK, + dummy_intr_func); + request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8), + intr_func, SA_INTERRUPT | SA_SHIRQ, + "l1_protocol_driver", (void *)sc); +#endif +#else + l1sc_t *sc; + nasid_t nasid; + int tmp; + nodepda_t *console_nodepda; + int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); + + if ( L1_interrupts_connected ) { + /* Interrupts are connected, so just register the callups */ + l1_rx_notif((brl1_notif_t)rx_notify); + l1_tx_notif((brl1_notif_t)tx_notify); + + L1_collectibles[L1C_CONNECT_CALLS]++; + return; + } + else + L1_interrupts_connected = 1; + + nasid = get_master_nasid(); + console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(nasid)); + sc = &console_nodepda->module->elsc; + sc->intr_cpu = console_nodepda->node_first_cpu; + + if ( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, (intr_func_t)brl1_intr) ) { + L1_interrupts_connected = 0; /* FAILS !! */ + } + else { + void synergy_intr_connect(int, int); + + synergy_intr_connect(UART_INTR, sc->intr_cpu); + L1_collectibles[L1C_R_IRQ]++; + tmp = request_irq(BRL1_INTERRUPT_LEVEL, brl1_intrd, SA_INTERRUPT | SA_SHIRQ, "l1_protocol_driver", (void *)sc); + L1_collectibles[L1C_R_IRQ_RET] = (uint64_t)tmp; + if ( tmp ) { + L1_interrupts_connected = 0; /* FAILS !! */ + } + else { + /* Register the upper-level callup functions */ + l1_rx_notif((brl1_notif_t)rx_notify); + l1_tx_notif((brl1_notif_t)tx_notify); + + /* Set the uarts the way we like it */ + uart_enable_recv_intr( sc ); + uart_disable_xmit_intr( sc ); + } + } +#endif /* USE_SAL_CONSOLE_IO */ +} + + +/* These are functions to use from serial_in/out when in protocol + * mode to send and receive uart control regs. These are external + * interfaces into the protocol driver. + */ + +void +l1_control_out(int offset, int value) +{ +#if defined(USE_SAL_CONSOLE_IO) + /* quietly ignore unless simulator */ + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + if ( master_node_bedrock_address != (u64)0 ) { + writeb(value, (unsigned long)master_node_bedrock_address + + (offset<< 3)); + } + return; + } +#else + nasid_t nasid = get_master_nasid(); + WRITE_L1_UART_REG(nasid, offset, value); +#endif +} + +/* Console input exported interface. Return a register value. */ + +int +l1_control_in_polled(int offset) +{ + static int l1_control_in_local(int, int); + + return(l1_control_in_local(offset, SERIAL_POLLED_MODE)); +} + +int +l1_control_in(int offset) +{ + static int l1_control_in_local(int, int); + + return(l1_control_in_local(offset, SERIAL_INTERRUPT_MODE)); +} + +static int +l1_control_in_local(int offset, int mode) +{ +#if defined(USE_SAL_CONSOLE_IO) + int sal_call_status = 0, input; + int ret = 0; + + if ( offset == REG_LSR ) { + ret = (LSR_XHRE | LSR_XSRE); /* can send anytime */ + sal_call_status = ia64_sn_console_check(&input); + if ( !sal_call_status && input ) { + /* input pending */ + ret |= LSR_RCA; + } + } + + /* If the sal call failed, do it the old-fashioned way */ + if ( sal_call_status ) { + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + ret = readb((unsigned long)master_node_bedrock_address + + (offset<< 3)); + } + else { +#endif /* USE_SAL_CONSOLE_IO */ + nasid_t nasid; + int ret, input; + static int l1_poll(l1sc_t *, int); + + nasid = get_master_nasid(); + ret = READ_L1_UART_REG(nasid, offset); + + if ( offset == REG_LSR ) { + ret |= (LSR_XHRE | LSR_XSRE); /* can send anytime */ + if ( L1_cons_is_inited ) { + if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { + input = l1_poll(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, mode); + if ( input ) { + ret |= LSR_RCA; + } + } + } + } +#if defined(USE_SAL_CONSOLE_IO) + } + } +#endif + return(ret); +} + +/* + * Console input exported interface. Return a character (if one is available) + */ + +int +l1_serial_in_polled(void) +{ + static int l1_serial_in_local(int mode); + + return(l1_serial_in_local(SERIAL_POLLED_MODE)); +} + +int +l1_serial_in(void) +{ + static int l1_serial_in_local(int mode); + + return(l1_serial_in_local(SERIAL_INTERRUPT_MODE)); +} + +static int +l1_serial_in_local(int mode) +{ +#if defined(USE_SAL_CONSOLE_IO) + int sal_call_status; + int ch; + + sal_call_status = ia64_sn_console_getc(&ch); + if ( !sal_call_status ) { + return(ch); + } + else { + /* If the sal called failed - do it the old-fashioned way */ + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3))); + } + else { +#endif /* USE_SAL_CONSOLE_IO */ + nasid_t nasid; + l1sc_t *sc; + int value; + static int l1_getc( l1sc_t *, int ); + static inline l1sc_t *early_sc_init(nasid_t); + + nasid = get_master_nasid(); + sc = early_sc_init(nasid); + if ( L1_cons_is_inited ) { + if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { + sc = &NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc; + } + } + value = l1_getc(sc, mode); + return(value); +#if defined(USE_SAL_CONSOLE_IO) + } + } +#endif +} + +/* Console output exported interface. Write message to the console. */ + +int +l1_serial_out( char *str, int len ) +{ +#if defined(USE_SAL_CONSOLE_IO) + void early_sn_setup(void); + int sal_call_status = 0; + int counter = len; + +#if defined(CONFIG_IA64_EARLY_PRINTK) + { + static int inited; + if(!inited) { + inited=1; + early_sn_setup(); + } + } +#endif + + /* Attempt to write things out thru the sal */ + sal_call_status = ia64_sn_console_putb(str, len); + if ( sal_call_status ) { + /* If the sal called failed - do it the old-fashioned way */ + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + if (!master_node_bedrock_address) + early_sn_setup(); + if ( master_node_bedrock_address != (u64)0 ) { +#ifdef FLAG_DIRECT_CONSOLE_WRITES + /* This is an easy way to pre-pend the output to know whether the output + * was done via sal or directly */ + writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); +#endif /* FLAG_DIRECT_CONSOLE_WRITES */ + while ( counter > 0 ) { + writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + counter--; + str++; + } + } + } + else { +#endif /* USE_SAL_CONSOLE_IO */ + nasid_t nasid = get_master_nasid(); + int l1_write(l1sc_t *, char *, int, int); + + if ( L1_cons_is_inited ) { + if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) + return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len, +#if defined(SYNC_CONSOLE_WRITE) + 1 +#else + !L1_interrupts_connected +#endif + )); + } + return(early_l1_serial_out(nasid, str, len, NOT_LOCKED)); +#if defined(USE_SAL_CONSOLE_IO) + } + } + return((counter <= 0) ? 0 : (len - counter)); +#endif +} + + +/* + * These are the 'early' functions - when we need to do things before we have + * all the structs setup. + */ + + +static l1sc_t Early_console; /* fake l1sc_t */ +static int Early_console_inited = 0; + +static void +early_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) +{ + int i; + brl1_sch_t *subch; + + bzero( sc, sizeof( *sc ) ); + sc->nasid = nasid; + sc->uart = uart; + sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); + sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); + sc->sol = 1; + subch = sc->subch; + + /* initialize L1 subchannels + */ + + /* assign processor TTY channels */ + for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { + subch->use = BRL1_SUBCH_RSVD; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + subch->iqp = &sc->garbage_q; + } + + /* assign system TTY channel (first free subchannel after each + * processor's individual TTY channel has been assigned) + */ + subch->use = BRL1_SUBCH_RSVD; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + if( sc->uart == BRL1_LOCALHUB_UART ) { + static sc_cq_t x_iqp; + + subch->iqp = &x_iqp; + ASSERT( subch->iqp ); + cq_init( subch->iqp ); + } + else { + /* we shouldn't be getting console input from remote UARTs */ + subch->iqp = &sc->garbage_q; + } + subch++; i++; + + /* "reserved" subchannels (0x05-0x0F); for now, throw away + * incoming packets + */ + for( ; i < 0x10; i++, subch++ ) { + subch->use = BRL1_SUBCH_FREE; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + subch->iqp = &sc->garbage_q; + } + + /* remaining subchannels are free */ + for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { + subch->use = BRL1_SUBCH_FREE; + subch->packet_arrived = ATOMIC_INIT(0); + subch->tx_notify = NULL; + subch->rx_notify = NULL; + subch->iqp = &sc->garbage_q; + } +} + +static inline l1sc_t * +early_sc_init(nasid_t nasid) +{ + /* This is for early I/O */ + if ( Early_console_inited == 0 ) { + early_brl1_init(&Early_console, nasid, BRL1_LOCALHUB_UART); + Early_console_inited = 1; + } + return(&Early_console); +} + +#define PUTCHAR(ch) \ + { \ + while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ + (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ + WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ + } + +static int +early_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state ) +{ + int ret, sent = 0; + char *msg = str; + static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state ); + + while ( sent < len ) { + ret = early_l1_send(nasid, msg, len - sent, lock_state); + sent += ret; + msg += ret; + } + return(len); +} + +static inline int +early_l1_send( nasid_t nasid, char *str, int len, int lock_state ) +{ + int sent; + char crc_char; + unsigned short crc = INIT_CRC; + + if( len > (BRL1_QSIZE - 1) ) + len = (BRL1_QSIZE - 1); + + sent = len; + if ( lock_state == NOT_LOCKED ) + lock_console(nasid); + + PUTCHAR( BRL1_FLAG_CH ); + PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); + crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) ); + + while( len ) { + + if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) { + PUTCHAR( BRL1_ESC_CH ); + PUTCHAR( (*str) ^ BRL1_XOR_CH ); + } + else { + PUTCHAR( *str ); + } + + crc = crc16_calc( crc, *str ); + + str++; len--; + } + + crc ^= 0xffff; + crc_char = crc & 0xff; + if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { + crc_char ^= BRL1_XOR_CH; + PUTCHAR( BRL1_ESC_CH ); + } + PUTCHAR( crc_char ); + crc_char = (crc >> 8) & 0xff; + if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { + crc_char ^= BRL1_XOR_CH; + PUTCHAR( BRL1_ESC_CH ); + } + PUTCHAR( crc_char ); + PUTCHAR( BRL1_FLAG_CH ); + + if ( lock_state == NOT_LOCKED ) + unlock_console(nasid); + return sent; +} + +/********************************************************************* + * l1_cons functions + * + * These allow the L1 to act as the system console. They're intended + * to abstract away most of the br/l1 internal details from the + * _L1_cons_* functions (in the prom-- see "l1_console.c") and + * l1_* functions (in the kernel-- see "sio_l1.c") that they support. + * + */ + +static int +l1_poll( l1sc_t *sc, int mode ) +{ + int ret; + + /* in case this gets called before the l1sc_t structure for the module_t + * struct for this node is initialized (i.e., if we're called with a + * zero l1sc_t pointer)... + */ + + + if( !sc ) { + return 0; + } + + if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { + return 1; + } + + ret = brl1_receive( sc, mode ); + if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) + L1_collectibles[L1C_REC_STALLS] = ret; + + if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { + return 1; + } + return 0; +} + + +/* pull a character off of the system console queue (if one is available) + */ +static int +l1_getc( l1sc_t *sc, int mode ) +{ + unsigned long pl = 0; + int c; + + brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); + sc_cq_t *q = subch->iqp; + + if( !l1_poll( sc, mode ) ) { + return 0; + } + + SUBCH_DATA_LOCK( subch, pl ); + if( cq_empty( q ) ) { + atomic_set(&subch->packet_arrived, 0); + SUBCH_DATA_UNLOCK( subch, pl ); + return 0; + } + cq_rem( q, c ); + if( cq_empty( q ) ) + atomic_set(&subch->packet_arrived, 0); + SUBCH_DATA_UNLOCK( subch, pl ); + + return c; +} + +/* + * Write a message to the L1 on the system console subchannel. + * + * Danger: don't use a non-zero value for the wait parameter unless you're + * someone important (like a kernel error message). + */ + +int +l1_write( l1sc_t *sc, char *msg, int len, int wait ) +{ + int sent = 0, ret = 0; + + if ( wait ) { + while ( sent < len ) { + ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); + sent += ret; + msg += ret; + } + ret = len; + } + else { + ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); + } + return(ret); +} + +/* initialize the system console subchannel + */ +void +l1_init(void) +{ + /* All we do now is remember that we have been called */ + L1_cons_is_inited = 1; +} + + +/********************************************************************* + * The following functions and definitions implement the "message"- + * style interface to the L1 system controller. + * + * Note that throughout this file, "sc" generally stands for "system + * controller", while "subchannels" tend to be represented by + * variables with names like subch or ch. + * + */ + +#ifdef L1_DEBUG +#define L1_DBG_PRF(x) printf x +#else +#define L1_DBG_PRF(x) +#endif + +/* + * sc_data_ready is called to signal threads that are blocked on l1 input. + */ +void +sc_data_ready( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) +{ + unsigned long pl = 0; + + brl1_sch_t *subch = &(sc->subch[ch]); + SUBCH_DATA_LOCK( subch, pl ); + sv_signal( &(subch->arrive_sv) ); + SUBCH_DATA_UNLOCK( subch, pl ); +} + +/* sc_open reserves a subchannel to send a request to the L1 (the + * L1's response will arrive on the same channel). The number + * returned by sc_open is the system controller subchannel + * acquired. + */ +int +sc_open( l1sc_t *sc, uint target ) +{ + /* The kernel version implements a locking scheme to arbitrate + * subchannel assignment. + */ + int ch; + unsigned long pl = 0; + brl1_sch_t *subch; + + SUBCH_LOCK( sc, pl ); + + /* Look for a free subchannel. Subchannels 0-15 are reserved + * for other purposes. + */ + for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; + ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) { + if( subch->use == BRL1_SUBCH_FREE ) + break; + } + + if( ch == BRL1_NUM_SUBCHANS ) { + /* there were no subchannels available! */ + SUBCH_UNLOCK( sc, pl ); + return SC_NSUBCH; + } + + subch->use = BRL1_SUBCH_RSVD; + SUBCH_UNLOCK( sc, pl ); + + atomic_set(&subch->packet_arrived, 0); + subch->target = target; + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); + subch->tx_notify = NULL; + subch->rx_notify = sc_data_ready; + subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, + NASID_TO_COMPACT_NODEID(sc->nasid) ); + ASSERT( subch->iqp ); + cq_init( subch->iqp ); + + return ch; +} + + +/* sc_close frees a Bedrock<->L1 subchannel. + */ +int +sc_close( l1sc_t *sc, int ch ) +{ + unsigned long pl = 0; + brl1_sch_t *subch; + + SUBCH_LOCK( sc, pl ); + subch = &(sc->subch[ch]); + if( subch->use != BRL1_SUBCH_RSVD ) { + /* we're trying to close a subchannel that's not open */ + SUBCH_UNLOCK( sc, pl ); + return SC_NOPEN; + } + + atomic_set(&subch->packet_arrived, 0); + subch->use = BRL1_SUBCH_FREE; + + sv_broadcast( &(subch->arrive_sv) ); + sv_destroy( &(subch->arrive_sv) ); + spin_lock_destroy( &(subch->data_lock) ); + + ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); + snia_kmem_free( subch->iqp, sizeof(sc_cq_t) ); + subch->iqp = &sc->garbage_q; + subch->tx_notify = NULL; + subch->rx_notify = brl1_discard_packet; + + SUBCH_UNLOCK( sc, pl ); + + return SC_SUCCESS; +} + + +/* sc_construct_msg builds a bedrock-to-L1 request in the supplied + * buffer. Returns the length of the message. The + * safest course when passing a buffer to be filled in is to use + * BRL1_QSIZE as the buffer size. + * + * Command arguments are passed as type/argument pairs, i.e., to + * pass the number 5 as an argument to an L1 command, call + * sc_construct_msg as follows: + * + * char msg[BRL1_QSIZE]; + * msg_len = sc_construct_msg( msg, + * BRL1_QSIZE, + * target_component, + * L1_ADDR_TASK_BOGUSTASK, + * L1_BOGUSTASK_REQ_BOGUSREQ, + * 2, + * L1_ARG_INT, 5 ); + * + * To pass an additional ASCII argument, you'd do the following: + * + * char *str; + * ... str points to a null-terminated ascii string ... + * msg_len = sc_construct_msg( msg, + * BRL1_QSIZE, + * target_component, + * L1_ADDR_TASK_BOGUSTASK, + * L1_BOGUSTASK_REQ_BOGUSREQ, + * 4, + * L1_ARG_INT, 5, + * L1_ARG_ASCII, str ); + * + * Finally, arbitrary data of unknown type is passed using the argtype + * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g. + * + * msg_len = sc_construct_msg( msg, + * BRL1_QSIZE, + * target_component, + * L1_ADDR_TASK_BOGUSTASK, + * L1_BOGUSTASK_REQ_BOGUSREQ, + * 3, + * L1_ARG_UNKNOWN, 32, bufptr ); + * + * ...passes 32 bytes of data starting at bufptr. Note that no string or + * "unknown"-type argument should be long enough to overflow the message + * buffer. + * + * To construct a message for an L1 command that requires no arguments, + * you'd use the following: + * + * msg_len = sc_construct_msg( msg, + * BRL1_QSIZE, + * target_component, + * L1_ADDR_TASK_BOGUSTASK, + * L1_BOGUSTASK_REQ_BOGUSREQ, + * 0 ); + * + * The final 0 means "no varargs". Notice that this parameter is used to hold + * the number of additional arguments to sc_construct_msg, _not_ the actual + * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII] + * type argument, and 3 per L1_ARG_UNKOWN type argument). A call to construct + * an L1 command which required three integer arguments and two arguments of + * some arbitrary (unknown) type would pass 12 as the value for this parameter. + * + * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth + * between byte arrays and four-byte big-endian integers. Depending on the + * system controller connection and endianness of future architectures, some + * rewriting might be necessary. + */ +int +sc_construct_msg( l1sc_t *sc, /* system controller struct */ + int ch, /* subchannel for this message */ + char *msg, /* message buffer */ + int msg_len, /* size of message buffer */ + l1addr_t addr_task, /* target system controller task */ + short req_code, /* 16-bit request code */ + int req_nargs, /* # of arguments (varargs) passed */ + ... ) /* any additional parameters */ +{ + uint32_t buf32; /* 32-bit buffer used to bounce things around */ + void *bufptr; /* used to hold command argument addresses */ + va_list al; /* variable argument list */ + int index; /* current index into msg buffer */ + int argno; /* current position in varargs list */ + int l1_argno; /* running total of arguments to l1 */ + int l1_arg_t; /* argument type/length */ + int l1_argno_byte; /* offset of argument count byte */ + + index = argno = 0; + + /* set up destination address */ + if( (msg_len -= sizeof( buf32 )) < 0 ) + return -1; + L1_ADDRESS_TO_TASK( &buf32, sc->subch[ch].target, addr_task ); + COPY_INT_TO_BUFFER(msg, index, buf32); + + /* copy request code */ + if( (msg_len -= 2) < 0 ) + return( -1 ); + msg[index++] = ((req_code >> 8) & 0xff); + msg[index++] = (req_code & 0xff); + + if( !req_nargs ) { + return index; + } + + /* reserve a byte for the argument count */ + if( (msg_len -= 1) < 0 ) + return( -1 ); + l1_argno_byte = index++; + l1_argno = 0; + + /* copy additional arguments */ + va_start( al, req_nargs ); + while( argno < req_nargs ) { + l1_argno++; + l1_arg_t = va_arg( al, int ); argno++; + switch( l1_arg_t ) + { + case L1_ARG_INT: + if( (msg_len -= (sizeof( buf32 ) + 1)) < 0 ) + return( -1 ); + msg[index++] = L1_ARG_INT; + buf32 = (unsigned)va_arg( al, int ); argno++; + COPY_INT_TO_BUFFER(msg, index, buf32); + break; + + case L1_ARG_ASCII: + bufptr = va_arg( al, char* ); argno++; + if( (msg_len -= (strlen( bufptr ) + 2)) < 0 ) + return( -1 ); + msg[index++] = L1_ARG_ASCII; + strcpy( (char *)&(msg[index]), (char *)bufptr ); + index += (strlen( bufptr ) + 1); /* include terminating null */ + break; + + case L1_ARG_UNKNOWN: + { + int arglen; + + arglen = va_arg( al, int ); argno++; + bufptr = va_arg( al, void* ); argno++; + if( (msg_len -= (arglen + 1)) < 0 ) + return( -1 ); + msg[index++] = L1_ARG_UNKNOWN | arglen; + BCOPY( bufptr, &(msg[index]), arglen ); + index += arglen; + break; + } + + default: /* unhandled argument type */ + return -1; + } + } + + va_end( al ); + msg[l1_argno_byte] = l1_argno; + + return index; +} + + + +/* sc_interpret_resp verifies an L1 response to a bedrock request, and + * breaks the response data up into the constituent parts. If the + * response message indicates error, or if a mismatch is found in the + * expected number and type of arguments, an error is returned. The + * arguments to this function work very much like the arguments to + * sc_construct_msg, above, except that L1_ARG_INTs must be followed + * by a _pointer_ to an integer that can be filled in by this function. + */ +int +sc_interpret_resp( char *resp, /* buffer received from L1 */ + int resp_nargs, /* number of _varargs_ passed in */ + ... ) +{ + uint32_t buf32; /* 32-bit buffer used to bounce things around */ + void *bufptr; /* used to hold response field addresses */ + va_list al; /* variable argument list */ + int index; /* current index into response buffer */ + int argno; /* current position in varargs list */ + int l1_fldno; /* number of resp fields received from l1 */ + int l1_fld_t; /* field type/length */ + + index = argno = 0; + +#if defined(L1_DEBUG) +#define DUMP_RESP \ + { \ + int ix; \ + char outbuf[512]; \ + sprintf( outbuf, "sc_interpret_resp error line %d: ", __LINE__ ); \ + for( ix = 0; ix < 16; ix++ ) { \ + sprintf( &outbuf[strlen(outbuf)], "%x ", resp[ix] ); \ + } \ + printk( "%s\n", outbuf ); \ + } +#else +#define DUMP_RESP +#endif /* L1_DEBUG */ + + /* check response code */ + COPY_BUFFER_TO_INT(resp, index, buf32); + if( buf32 != L1_RESP_OK ) { + DUMP_RESP; + return buf32; + } + + /* get number of response fields */ + l1_fldno = resp[index++]; + + va_start( al, resp_nargs ); + + /* copy out response fields */ + while( argno < resp_nargs ) { + l1_fldno--; + l1_fld_t = va_arg( al, int ); argno++; + switch( l1_fld_t ) + { + case L1_ARG_INT: + if( resp[index++] != L1_ARG_INT ) { + /* type mismatch */ + va_end( al ); + DUMP_RESP; + return -1; + } + bufptr = va_arg( al, int* ); argno++; + COPY_BUFFER_TO_BUFFER(resp, index, bufptr); + break; + + case L1_ARG_ASCII: + if( resp[index++] != L1_ARG_ASCII ) { + /* type mismatch */ + va_end( al ); + DUMP_RESP; + return -1; + } + bufptr = va_arg( al, char* ); argno++; + strcpy( (char *)bufptr, (char *)&(resp[index]) ); + /* include terminating null */ + index += (strlen( &(resp[index]) ) + 1); + break; + + default: + if( (l1_fld_t & L1_ARG_UNKNOWN) == L1_ARG_UNKNOWN ) + { + int *arglen; + + arglen = va_arg( al, int* ); argno++; + bufptr = va_arg( al, void* ); argno++; + *arglen = ((resp[index++] & ~L1_ARG_UNKNOWN) & 0xff); + BCOPY( &(resp[index]), bufptr, *arglen ); + index += (*arglen); + } + + else { + /* unhandled type */ + va_end( al ); + DUMP_RESP; + return -1; + } + } + } + va_end( al ); + + if( (l1_fldno != 0) || (argno != resp_nargs) ) { + /* wrong number of arguments */ + DUMP_RESP; + return -1; + } + return 0; +} + +/* sc_send takes as arguments a system controller struct, a + * buffer which contains a Bedrock<->L1 "request" message, + * the message length, and the subchannel (presumably obtained + * from an earlier invocation of sc_open) over which the + * message is to be sent. The final argument ("wait") indicates + * whether the send is to be performed synchronously or not. + * + * sc_send returns either zero or an error value. Synchronous sends + * (wait != 0) will not return until the data has actually been sent + * to the UART. Synchronous sends generally receive privileged + * treatment. The intent is that they be used sparingly, for such + * purposes as kernel printf's (the "ducons" routines). Run-of-the-mill + * console output and L1 requests should NOT use a non-zero value + * for wait. + */ +int +sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait ) +{ + char type_and_subch; + int result; + + if( (ch < 0) || ( ch >= BRL1_NUM_SUBCHANS) ) { + return SC_BADSUBCH; + } + + /* Verify that this is an open subchannel + */ + if( sc->subch[ch].use == BRL1_SUBCH_FREE ) { + return SC_NOPEN; + } + + type_and_subch = (BRL1_REQUEST | ((u_char)ch)); + result = brl1_send( sc, msg, len, type_and_subch, wait ); + + /* If we sent as much as we asked to, return "ok". */ + if( result == len ) + return( SC_SUCCESS ); + + /* Or, if we sent less, than either the UART is busy or + * we're trying to send too large a packet anyway. + */ + else if( result >= 0 && result < len ) + return( SC_BUSY ); + + /* Or, if something else went wrong (result < 0), then + * return that error value. + */ + else + return( result ); +} + +/* subch_pull_msg pulls a message off the receive queue for subch + * and places it the buffer pointed to by msg. This routine should only + * be called when the caller already knows a message is available on the + * receive queue (and, in the kernel, only when the subchannel data lock + * is held by the caller). + */ +static void +subch_pull_msg( brl1_sch_t *subch, char *msg, int *len ) +{ + sc_cq_t *q; /* receive queue */ + int before_wrap, /* packet may be split into two different */ + after_wrap; /* pieces to acommodate queue wraparound */ + + /* pull message off the receive queue */ + q = subch->iqp; + + cq_rem( q, *len ); /* remove length byte and store */ + cq_discard( q ); /* remove type/subch byte and discard */ + + if ( *len > 0 ) + (*len)--; /* don't count type/subch byte in length returned */ + + if( (q->opos + (*len)) > BRL1_QSIZE ) { + before_wrap = BRL1_QSIZE - q->opos; + after_wrap = (*len) - before_wrap; + } + else { + before_wrap = (*len); + after_wrap = 0; + } + + BCOPY( q->buf + q->opos, msg, before_wrap ); + if( after_wrap ) { + BCOPY( q->buf, msg + before_wrap, after_wrap ); + q->opos = after_wrap; + } + else { + q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1)); + } + atomic_dec(&(subch->packet_arrived)); +} + + +/* sc_recv_poll can be called as a blocking or non-blocking function; + * it attempts to pull a message off of the subchannel specified + * in the argument list (ch). + * + * The "block" argument, if non-zero, is interpreted as a timeout + * delay (to avoid permanent waiting). + */ + +int +sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) +{ + int is_msg = 0; + unsigned long pl = 0; + brl1_sch_t *subch = &(sc->subch[ch]); + + rtc_time_t exp_time = rtc_time() + block; + + /* sanity check-- make sure this is an open subchannel */ + if( subch->use == BRL1_SUBCH_FREE ) + return( SC_NOPEN ); + + do { + + /* kick the next lower layer and see if it pulls anything in + */ + brl1_receive( sc, SERIAL_POLLED_MODE ); + is_msg = atomic_read(&subch->packet_arrived); + + } while( block && !is_msg && (rtc_time() < exp_time) ); + + if( !is_msg ) { + /* no message and we didn't care to wait for one */ + return( SC_NMSG ); + } + + SUBCH_DATA_LOCK( subch, pl ); + subch_pull_msg( subch, msg, len ); + SUBCH_DATA_UNLOCK( subch, pl ); + + return( SC_SUCCESS ); +} + + +/* Like sc_recv_poll, sc_recv_intr can be called in either a blocking + * or non-blocking mode. Rather than polling until an appointed timeout, + * however, sc_recv_intr sleeps on a syncrhonization variable until a + * signal from the lower layer tells us that a packet has arrived. + * + * sc_recv_intr can't be used with remote (router) L1s. + */ +int +sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) +{ + int is_msg = 0; + unsigned long pl = 0; + brl1_sch_t *subch = &(sc->subch[ch]); + + do { + SUBCH_DATA_LOCK(subch, pl); + is_msg = atomic_read(&subch->packet_arrived); + if( !is_msg && block ) { + /* wake me when you've got something */ + subch->rx_notify = sc_data_ready; + sv_wait( &(subch->arrive_sv), 0, 0); + if( subch->use == BRL1_SUBCH_FREE ) { + /* oops-- somebody closed our subchannel while we were + * sleeping! + */ + + /* no need to unlock since the channel's closed anyhow */ + return( SC_NOPEN ); + } + } + } while( !is_msg && block ); + + if( !is_msg ) { + /* no message and we didn't care to wait for one */ + SUBCH_DATA_UNLOCK( subch, pl ); + return( SC_NMSG ); + } + + subch_pull_msg( subch, msg, len ); + SUBCH_DATA_UNLOCK( subch, pl ); + + return( SC_SUCCESS ); +} + +/* sc_command implements a (blocking) combination of sc_send and sc_recv. + * It is intended to be the SN1 equivalent of SN0's "elsc_command", which + * issued a system controller command and then waited for a response from + * the system controller before returning. + * + * cmd points to the outgoing command; resp points to the buffer in + * which the response is to be stored. Both buffers are assumed to + * be the same length; if there is any doubt as to whether the + * response buffer is long enough to hold the L1's response, then + * make it BRL1_QSIZE bytes-- no Bedrock<->L1 message can be any + * bigger. + * + * Be careful using the same buffer for both cmd and resp; it could get + * hairy if there were ever an L1 command reqeuest that spanned multiple + * packets. (On the other hand, that would require some additional + * rewriting of the L1 command interface anyway.) + */ +#define __RETRIES 50 +#define __WAIT_SEND 1 // ( sc->uart != BRL1_LOCALHUB_UART ) +#define __WAIT_RECV 10000000 + + +int +sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) +{ + int result; + int retries; + + if ( IS_RUNNING_ON_SIMULATOR() ) + return SC_NMSG; + + retries = __RETRIES; + + while( (result = sc_send( sc, ch, cmd, *len, __WAIT_SEND )) < 0 ) { + if( result == SC_BUSY ) { + retries--; + if( retries <= 0 ) + return result; + uart_delay(500); + } + else { + return result; + } + } + + /* block on sc_recv_* */ + if( (sc->uart == BRL1_LOCALHUB_UART) && L1_interrupts_connected ) { + return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) ); + } + else { + return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); + } +} + +/* sc_command_kern is a knuckle-dragging, no-patience version of sc_command + * used in situations where the kernel has a command that shouldn't be + * delayed until the send buffer clears. sc_command should be used instead + * under most circumstances. + */ + +int +sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) +{ + int result; + + if ( IS_RUNNING_ON_SIMULATOR() ) + return SC_NMSG; + + if( (result = sc_send( sc, ch, cmd, *len, 1 )) < 0 ) { + return result; + } + + return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); +} + + + +/* sc_poll checks the queue corresponding to the given + * subchannel to see if there's anything available. If + * not, it kicks the brl1 layer and then checks again. + * + * Returns 1 if input is available on the given queue, + * 0 otherwise. + */ + +int +sc_poll( l1sc_t *sc, int ch ) +{ + brl1_sch_t *subch = &(sc->subch[ch]); + + if( atomic_read(&subch->packet_arrived) ) + return 1; + + brl1_receive( sc, SERIAL_POLLED_MODE ); + + if( atomic_read(&subch->packet_arrived) ) + return 1; + + return 0; +} + +/* for now, sc_init just calls brl1_init */ + +void +sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) +{ + if ( !IS_RUNNING_ON_SIMULATOR() ) + brl1_init( sc, nasid, uart ); +} + +/* sc_dispatch_env_event handles events sent from the system control + * network's environmental monitor tasks. + */ + +#if defined(LINUX_KERNEL_THREADS) + +static void +sc_dispatch_env_event( uint code, int argc, char *args, int maxlen ) +{ + int j, i = 0; + uint32_t ESPcode; + + switch( code ) { + /* for now, all codes do the same thing: grab two arguments + * and print a cmn_err_tag message */ + default: + /* check number of arguments */ + if( argc != 2 ) { + L1_DBG_PRF(( "sc_dispatch_env_event: " + "expected 2 arguments, got %d\n", argc )); + return; + } + + /* get ESP code (integer argument) */ + if( args[i++] != L1_ARG_INT ) { + L1_DBG_PRF(( "sc_dispatch_env_event: " + "expected integer argument\n" )); + return; + } + /* WARNING: highly endian */ + COPY_BUFFER_TO_INT(args, i, ESPcode); + + /* verify string argument */ + if( args[i++] != L1_ARG_ASCII ) { + L1_DBG_PRF(( "sc_dispatch_env_event: " + "expected an ASCII string\n" )); + return; + } + for( j = i; j < maxlen; j++ ) { + if( args[j] == '\0' ) break; /* found string termination */ + } + if( j == maxlen ) { + j--; + L1_DBG_PRF(( "sc_dispatch_env_event: " + "message too long-- truncating\n" )); + } + + /* strip out trailing cr/lf */ + for( ; + j > 1 && ((args[j-1] == 0xd) || (args[j-1] == 0xa)); + j-- ); + args[j] = '\0'; + + /* strip out leading cr/lf */ + for( ; + i < j && ((args[i] == 0xd) || (args[i] == 0xa)); + i++ ); + } +} + + +/* sc_event waits for events to arrive from the system controller, and + * prints appropriate messages to the syslog. + */ + +static void +sc_event( l1sc_t *sc, int ch ) +{ + char event[BRL1_QSIZE]; + int i; + int result; + int event_len; + uint32_t ev_src; + uint32_t ev_code; + int ev_argc; + + while(1) { + + bzero( event, BRL1_QSIZE ); + + /* + * wait for an event + */ + result = sc_recv_intr( sc, ch, event, &event_len, 1 ); + if( result != SC_SUCCESS ) { + printk(KERN_WARNING "Error receiving sysctl event on nasid %d\n", + sc->nasid ); + } + else { + /* + * an event arrived; break it down into useful pieces + */ +#if defined(L1_DEBUG) && 0 + int ix; + printf( "Event packet received:\n" ); + for (ix = 0; ix < 64; ix++) { + printf( "%x%x ", ((event[ix] >> 4) & ((uint64_t)0xf)), + (event[ix] & ((uint64_t)0xf)) ); + if( (ix % 16) == 0xf ) printf( "\n" ); + } +#endif /* L1_DEBUG */ + + i = 0; + + /* get event source */ + COPY_BUFFER_TO_INT(event, i, ev_src); + COPY_BUFFER_TO_INT(event, i, ev_code); + + /* get arg count */ + ev_argc = (event[i++] & 0xffUL); + + /* dispatch events by task */ + switch( (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT ) + { + case L1_ADDR_TASK_ENV: /* environmental monitor event */ + sc_dispatch_env_event( ev_code, ev_argc, &(event[i]), + BRL1_QSIZE - i ); + break; + + default: /* unhandled task type */ + L1_DBG_PRF(( "Unhandled event type received from system " + "controllers: source task %x\n", + (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT + )); + } + } + + } +} + +/* sc_listen sets up a service thread to listen for incoming events. + */ + +void +sc_listen( l1sc_t *sc ) +{ + int result; + unsigned long pl = 0; + brl1_sch_t *subch; + + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int ch; /* system controller subchannel used */ + + extern int msc_shutdown_pri; + + /* grab the designated "event subchannel" */ + SUBCH_LOCK( sc, pl ); + subch = &(sc->subch[BRL1_EVENT_SUBCH]); + if( subch->use != BRL1_SUBCH_FREE ) { + SUBCH_UNLOCK( sc, pl ); + printk(KERN_WARNING "sysctl event subchannel in use! " + "Not monitoring sysctl events.\n" ); + return; + } + subch->use = BRL1_SUBCH_RSVD; + SUBCH_UNLOCK( sc, pl ); + + atomic_set(&subch->packet_arrived, 0); + subch->target = BRL1_LOCALHUB_UART; + spin_lock_init( &(subch->data_lock) ); + sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); + subch->tx_notify = NULL; + subch->rx_notify = sc_data_ready; + subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, + NASID_TO_COMPACT_NODEID(sc->nasid) ); + ASSERT( subch->iqp ); + cq_init( subch->iqp ); + + /* set up a thread to listen for events */ + sthread_create( "sysctl event handler", 0, 0, 0, msc_shutdown_pri, + KT_PS, (st_func_t *) sc_event, + (void *)sc, (void *)(uint64_t)BRL1_EVENT_SUBCH, 0, 0 ); + + /* signal the L1 to begin sending events */ + bzero( msg, BRL1_QSIZE ); + ch = sc_open( sc, L1_ADDR_LOCAL ); + + if( (len = sc_construct_msg( sc, ch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_EVENT_SUBCH, 2, + L1_ARG_INT, BRL1_EVENT_SUBCH )) < 0 ) + { + sc_close( sc, ch ); + L1_DBG_PRF(( "Failure in sc_construct_msg (%d)\n", len )); + goto err_return; + } + + result = sc_command_kern( sc, ch, msg, msg, &len ); + if( result < 0 ) + { + sc_close( sc, ch ); + L1_DBG_PRF(( "Failure in sc_command_kern (%d)\n", result )); + goto err_return; + } + + sc_close( sc, ch ); + + result = sc_interpret_resp( msg, 0 ); + if( result < 0 ) + { + L1_DBG_PRF(( "Failure in sc_interpret_resp (%d)\n", result )); + goto err_return; + } + + /* everything went fine; just return */ + return; + +err_return: + /* there was a problem; complain */ + printk(KERN_WARNING "failed to set sysctl event-monitoring subchannel. " + "Sysctl events will not be monitored.\n" ); +} + +#endif /* LINUX_KERNEL_THREADS */ diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/l1_command.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/l1_command.c --- linux-2.4.19/arch/ia64/sn/io/sn1/l1_command.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/l1_command.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1409 @@ +/* $Id: l1_command.c,v 1.3 2002/12/30 22:16:56 jh Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ +#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ + +#define LD(x) (*(volatile uint64_t *)(x)) +#define SD(x, v) (LD(x) = (uint64_t) (v)) + +#define hub_cpu_get() 0 + +#define LBYTE(caddr) (*(char *) caddr) + +extern char *bcopy(const char * src, char * dest, int count); + +#define LDEBUG 0 + +/* + * ELSC data is in NVRAM page 7 at the following offsets. + */ + +#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */ +#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */ +#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */ +#define NVRAM_DBG2 0x706 /* physical XOR debug switches */ +#define NVRAM_CFG 0x707 /* ELSC Configuration info */ +#define NVRAM_MODULE 0x708 /* system module number */ +#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */ +#define NVRAM_PARTITION 0x70a /* module's partition id */ +#define NVRAM_DOMAIN 0x70b /* module's domain id */ +#define NVRAM_CLUSTER 0x70c /* module's cluster id */ +#define NVRAM_CELL 0x70d /* module's cellid */ + +#define NVRAM_MAGIC_NO 0x37 /* value of magic number */ +#define NVRAM_SIZE 16 /* 16 bytes in nvram */ + +/* + * Declare a static ELSC NVRAM buffer to hold all data read from + * and written to NVRAM. This nvram "cache" will be used only during the + * IP27prom execution. + */ +static char elsc_nvram_buffer[NVRAM_SIZE]; + +#define SC_COMMAND sc_command + +/* + * elsc_init + * + * Initialize ELSC structure + */ + +void elsc_init(elsc_t *e, nasid_t nasid) +{ + sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART); +} + + +/* + * elsc_errmsg + * + * Given a negative error code, + * returns a corresponding static error string. + */ + +char *elsc_errmsg(int code) +{ + switch (code) { + case ELSC_ERROR_CMD_SEND: + return "Command send error"; + case ELSC_ERROR_CMD_CHECKSUM: + return "Command packet checksum error"; + case ELSC_ERROR_CMD_UNKNOWN: + return "Unknown command"; + case ELSC_ERROR_CMD_ARGS: + return "Invalid command argument(s)"; + case ELSC_ERROR_CMD_PERM: + return "Permission denied"; + case ELSC_ERROR_RESP_TIMEOUT: + return "System controller response timeout"; + case ELSC_ERROR_RESP_CHECKSUM: + return "Response packet checksum error"; + case ELSC_ERROR_RESP_FORMAT: + return "Response format error"; + case ELSC_ERROR_RESP_DIR: + return "Response direction error"; + case ELSC_ERROR_MSG_LOST: + return "Message lost because queue is full"; + case ELSC_ERROR_LOCK_TIMEOUT: + return "Timed out getting ELSC lock"; + case ELSC_ERROR_DATA_SEND: + return "Error sending data"; + case ELSC_ERROR_NIC: + return "NIC protocol error"; + case ELSC_ERROR_NVMAGIC: + return "Bad magic number in NVRAM"; + case ELSC_ERROR_MODULE: + return "Module location protocol error"; + default: + return "Unknown error"; + } +} + +/* + * elsc_nvram_init + * + * Initializes reads and writes to NVRAM. This will perform a single + * read to NVRAM, getting all data at once. When the PROM tries to + * read NVRAM, it returns the data from the buffer being read. If the + * PROM tries to write out to NVRAM, the write is done, and the internal + * buffer is updated. + */ + +void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data) +{ + /* This might require implementation of multiple-packet request/responses + * if it's to provide the same behavior that was available in SN0. + */ + nasid = nasid; + elsc_nvram_data = elsc_nvram_data; +} + +/* + * elsc_nvram_copy + * + * Copies the content of a buffer into the static buffer in this library. + */ + +void elsc_nvram_copy(uchar_t *elsc_nvram_data) +{ + memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE); +} + +/* + * elsc_nvram_write + * + * Copies bytes from 'buf' into NVRAM, starting at NVRAM address + * 'addr' which must be between 0 and 2047. + * + * If 'len' is non-negative, the routine copies 'len' bytes. + * + * If 'len' is negative, the routine treats the data as a string and + * copies bytes up to and including a NUL-terminating zero, but not + * to exceed '-len' bytes. + */ + +int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len) +{ + /* Here again, we might need to work out the details of a + * multiple-packet protocol. + */ + + /* For now, pretend it worked. */ + e = e; + addr = addr; + buf = buf; + return (len < 0 ? -len : len); +} + +/* + * elsc_nvram_read + * + * Copies bytes from NVRAM into 'buf', starting at NVRAM address + * 'addr' which must be between 0 and 2047. + * + * If 'len' is non-negative, the routine copies 'len' bytes. + * + * If 'len' is negative, the routine treats the data as a string and + * copies bytes up to and including a NUL-terminating zero, but not + * to exceed '-len' bytes. NOTE: This method is no longer supported. + * It was never used in the first place. + */ + +int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len) +{ + /* multiple packets? */ + e = e; + addr = addr; + buf = buf; + len = len; + return -1; +} + + +/* + * Command Set + */ + +int elsc_version(elsc_t *e, char *result) +{ + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int subch; /* system controller subchannel used */ + int major, /* major rev number */ + minor, /* minor rev number */ + bugfix; /* bugfix rev number */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); + + if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_FW_REV, 0 )) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( (l1sc_t *)e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, + L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) + < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + sprintf( result, "%d.%d.%d", major, minor, bugfix ); + + return 0; +} + +int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2) +{ + /* shush compiler */ + e = e; + byte1 = byte1; + byte2 = byte2; + + /* fill in a buffer with the opcode & params; call sc_command */ + + return 0; +} + +int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2) +{ + char msg[BRL1_QSIZE]; + int subch; /* system controller subchannel used */ + int dbg_sw; /* holds debug switch settings */ + int len; /* number of msg buffer bytes used */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { + return( ELSC_ERROR_CMD_SEND ); + } + + if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_RDBG, 0 ) ) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( (l1sc_t *)e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + /* copy out debug switch settings (last two bytes of the + * integer response) + */ + *byte1 = ((dbg_sw >> 8) & 0xFF); + *byte2 = (dbg_sw & 0xFF); + + return 0; +} + + +/* + * elsc_rack_bay_get fills in the two int * arguments with the + * rack number and bay number of the L1 being addressed + */ +int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + uint32_t buf32; /* used to copy 32-bit rack/bay out of msg */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { + return( ELSC_ERROR_CMD_SEND ); + } + + if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_RRACK, 0 )) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + + /* send the request to the L1 */ + if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close(e, subch); + + /* check response */ + if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + /* extract rack/bay info + * + * note that the 32-bit value returned by the L1 actually + * only uses the low-order sixteen bits for rack and bay + * information. A "normal" L1 address puts rack and bay + * information in bit positions 12 through 28. So if + * we initially shift the value returned 12 bits to the left, + * we can use the L1 addressing #define's to extract the + * values we need (see ksys/l1.h for a complete list of the + * various fields of an L1 address). + */ + buf32 <<= L1_ADDR_BAY_SHFT; + + *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; + *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; + + return 0; +} + + +/* elsc_rack_bay_type_get fills in the three int * arguments with the + * rack number, bay number and brick type of the L1 being addressed. Note + * that if the L1 operation fails and this function returns an error value, + * garbage may be written to brick_type. + */ +int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack, + uint *bay, uint *brick_type ) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) { + return ELSC_ERROR_CMD_SEND; + } + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_RRBT, 0 )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND( sc, subch, msg, msg, &len ) ) { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, + L1_ARG_INT, brick_type ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + /* extract rack/bay info + * + * note that the 32-bit value returned by the L1 actually + * only uses the low-order sixteen bits for rack and bay + * information. A "normal" L1 address puts rack and bay + * information in bit positions 12 through 28. So if + * we initially shift the value returned 12 bits to the left, + * we can use the L1 addressing #define's to extract the + * values we need (see ksys/l1.h for a complete list of the + * various fields of an L1 address). + */ + buf32 <<= L1_ADDR_BAY_SHFT; + + *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; + *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; + + /* convert brick_type to lower case */ + *brick_type = *brick_type - 'A' + 'a'; + + return 0; +} + + +int elsc_module_get(elsc_t *e) +{ + extern char brick_types[]; + uint rnum, rack, bay, bricktype, t; + int ret; + + /* construct module ID from rack and slot info */ + + if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) { + return ret; + } + + /* report unset location info. with a special, otherwise invalid modid */ + if (rnum == 0 && bay == 0) + return MODULE_NOT_SET; + + if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) + return ELSC_ERROR_MODULE; + + /* Build a moduleid_t-compatible rack number */ + + rack = 0; + t = rnum / 100; /* rack class (CPU/IO) */ + if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_CLASS(rack, t); + rnum %= 100; + + t = rnum / 10; /* rack group */ + if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_GROUP(rack, t); + + t = rnum % 10; /* rack number (one-based) */ + if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_NUM(rack, t); + + for( t = 0; t < MAX_BRICK_TYPES; t++ ) { + if( brick_types[t] == bricktype ) + return RBT_TO_MODULE(rack, bay, t); + } + + return ELSC_ERROR_MODULE; +} + +int elsc_partition_set(elsc_t *e, int partition) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { + return ELSC_ERROR_CMD_SEND; + } + + if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_PARTITION_SET, 2, + L1_ARG_INT, partition )) < 0 ) + { + + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( sc_command( e, subch, msg, msg, &len ) ) { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return( 0 ); +} + +int elsc_partition_get(elsc_t *e) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + uint32_t partition_id; /* used to copy partition id out of msg */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { + return ELSC_ERROR_CMD_SEND; + } + + if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_PARTITION_GET, 0 )) < 0 ) + + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( sc_command( e, subch, msg, msg, &len ) ) { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 2, L1_ARG_INT, &partition_id ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return( partition_id ); +} + + +/* + * elsc_cons_subch selects the "active" console subchannel for this node + * (i.e., the one that will currently receive input) + */ +int elsc_cons_subch(elsc_t *e, uint ch) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( e, L1_ADDR_LOCAL ); + + if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_CONS_SUBCH, 2, + L1_ARG_INT, ch)) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND( e, subch, msg, msg, &len ) ) { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; +} + + +/* + * elsc_cons_node should only be executed by one node. It declares to + * the system controller that the node from which it is called will be + * the owner of the system console. + */ +int elsc_cons_node(elsc_t *e) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( e, L1_ADDR_LOCAL ); + + if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_CONS_NODE, 0 )) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND( e, subch, msg, msg, &len ) ) { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; +} + + +/* elsc_display_line writes up to 12 characters to either the top or bottom + * line of the L1 display. line points to a buffer containing the message + * to be displayed. The zero-based line number is specified by lnum (so + * lnum == 0 specifies the top line and lnum == 1 specifies the bottom). + * Lines longer than 12 characters, or line numbers not less than + * L1_DISPLAY_LINES, cause elsc_display_line to return an error. + */ +int elsc_display_line(elsc_t *e, char *line, int lnum) +{ + char msg[BRL1_QSIZE]; + int subch; /* system controller subchannel used */ + int len; /* number of msg buffer bytes used */ + + /* argument sanity checking */ + if( !(lnum < L1_DISPLAY_LINES) ) + return( ELSC_ERROR_CMD_ARGS ); + if( !(strlen( line ) <= L1_DISPLAY_LINE_LENGTH) ) + return( ELSC_ERROR_CMD_ARGS ); + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); + + if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + (L1_REQ_DISP1+lnum), 2, + L1_ARG_ASCII, line )) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( (l1sc_t *)e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; +} + + +/* elsc_display_mesg silently drops message characters beyond the 12th. + */ +int elsc_display_mesg(elsc_t *e, char *chr) +{ + + char line[L1_DISPLAY_LINE_LENGTH+1]; + int numlines, i; + int result; + + numlines = (strlen( chr ) + L1_DISPLAY_LINE_LENGTH - 1) / + L1_DISPLAY_LINE_LENGTH; + + if( numlines > L1_DISPLAY_LINES ) + numlines = L1_DISPLAY_LINES; + + for( i = 0; i < numlines; i++ ) + { + strncpy( line, chr, L1_DISPLAY_LINE_LENGTH ); + line[L1_DISPLAY_LINE_LENGTH] = '\0'; + + /* generally we want to leave the first line of the L1 display + * alone (so the L1 can manipulate it). If you need to be able + * to display to both lines (for debugging purposes), define + * L1_DISP_2LINES in irix/kern/ksys/l1.h, or add -DL1_DISP_2LINES + * to your 'defs file. + */ +#if defined(L1_DISP_2LINES) + if( (result = elsc_display_line( e, line, i )) < 0 ) +#else + if( (result = elsc_display_line( e, line, i+1 )) < 0 ) +#endif + + return result; + + chr += L1_DISPLAY_LINE_LENGTH; + } + + return 0; +} + + +int elsc_password_set(elsc_t *e, char *password) +{ + /* shush compiler */ + e = e; + password = password; + + /* fill in buffer with the opcode & params; call elsc_command */ + + return 0; +} + +int elsc_password_get(elsc_t *e, char *password) +{ + /* shush compiler */ + e = e; + password = password; + + /* fill in buffer with the opcode & params; call elsc_command */ + + return 0; +} + + +/* + * sc_portspeed_get + * + * retrieve the current portspeed setting for the bedrock II + */ +int sc_portspeed_get(l1sc_t *sc) +{ + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int subch; /* system controller subchannel used */ + int portspeed_a, portspeed_b; + /* ioport clock rates */ + + bzero( msg, BRL1_QSIZE ); + subch = sc_open( sc, L1_ADDR_LOCAL ); + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_PORTSPEED, + 0 )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( sc_command( sc, subch, msg, msg, &len ) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 4, + L1_ARG_INT, &portspeed_a, + L1_ARG_INT, &portspeed_b ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + /* for the c-brick, we ignore the portspeed_b value */ + return (portspeed_a ? 600 : 400); +} + +/* + * elsc_power_query + * + * To be used after system reset, this command returns 1 if the reset + * was the result of a power-on, 0 otherwise. + * + * The power query status is cleared to 0 after it is read. + */ + +int elsc_power_query(elsc_t *e) +{ + e = e; /* shush the compiler */ + + /* fill in buffer with the opcode & params; call elsc_command */ + + return 1; +} + +int elsc_rpwr_query(elsc_t *e, int is_master) +{ + /* shush the compiler */ + e = e; + is_master = is_master; + + /* fill in buffer with the opcode & params; call elsc_command */ + + return 0; +} + +/* + * elsc_power_down + * + * Sets up system to shut down in "sec" seconds (or modifies the + * shutdown time if one is already in effect). Use 0 to power + * down immediately. + */ + +int elsc_power_down(elsc_t *e, int sec) +{ + /* shush compiler */ + e = e; + sec = sec; + + /* fill in buffer with the opcode & params; call elsc_command */ + + return 0; +} + + +int elsc_system_reset(elsc_t *e) +{ + char msg[BRL1_QSIZE]; + int subch; /* system controller subchannel used */ + int len; /* number of msg buffer bytes used */ + int result; + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { + return ELSC_ERROR_CMD_SEND; + } + + if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_RESET, 0 )) < 0 ) + { + sc_close( e, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( (result = sc_command( e, subch, msg, msg, &len )) ) { + sc_close( e, subch ); + if( result == SC_NMSG ) { + /* timeout is OK. We've sent the reset. Now it's just + * a matter of time... + */ + return( 0 ); + } + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( e, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; +} + + +int elsc_power_cycle(elsc_t *e) +{ + /* shush compiler */ + e = e; + + /* fill in buffer with the opcode & params; call sc_command */ + + return 0; +} + + +int _elsc_hbt(elsc_t *e, int ival, int rdly) +{ + e = e; + ival = ival; + rdly = rdly; + + /* fill in buffer with the opcode & params; call elsc_command */ + + return 0; +} + + +/* send a command string to an L1 */ +int sc_command_interp( l1sc_t *sc, l1addr_t compt, l1addr_t rack, l1addr_t bay, + char *cmd ) +{ + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int subch; /* system controller subchannel used */ + l1addr_t target; /* target system controller for command */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + + L1_BUILD_ADDR( &target, compt, rack, bay, 0 ); + subch = sc_open( sc, target ); + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2, + L1_ARG_ASCII, cmd )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; +} + +/* + * sc_power_down + * + * Shuts down the c-brick associated with sc, and any attached I/O bricks + * or other c-bricks (won't go through r-bricks). + */ + +int sc_power_down(l1sc_t *sc) +{ + return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, + L1_ADDR_BAY_LOCAL, "* pwr d" ); +} + + +/* + * sc_power_down_all + * + * Works similarly to sc_power_down, except that the request is sent to the + * closest L2 and EVERYBODY gets turned off. + */ + +int sc_power_down_all(l1sc_t *sc) +{ + if( nodepda->num_routers > 0 ) { + return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, + L1_ADDR_BAY_LOCAL, "* pwr d" ); + } + else { + return sc_power_down( sc ); + } +} + + +/* + * iobrick routines + */ + +/* iobrick_rack_bay_type_get fills in the three int * arguments with the + * rack number, bay number and brick type of the L1 being addressed. Note + * that if the L1 operation fails and this function returns an error value, + * garbage may be written to brick_type. + */ +int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, + uint *bay, uint *brick_type ) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { + return( ELSC_ERROR_CMD_SEND ); + } + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_RRBT, 0 )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( sc_command( sc, subch, msg, msg, &len ) ) { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, + L1_ARG_INT, brick_type ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + /* extract rack/bay info + * + * note that the 32-bit value returned by the L1 actually + * only uses the low-order sixteen bits for rack and bay + * information. A "normal" L1 address puts rack and bay + * information in bit positions 12 through 28. So if + * we initially shift the value returned 12 bits to the left, + * we can use the L1 addressing #define's to extract the + * values we need (see ksys/l1.h for a complete list of the + * various fields of an L1 address). + */ + buf32 <<= L1_ADDR_BAY_SHFT; + + *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; + *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; + + return 0; +} + + +int iobrick_module_get(l1sc_t *sc) +{ + uint rnum, rack, bay, brick_type, t; + int ret; + + /* construct module ID from rack and slot info */ + + if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0) + return ret; + + if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) + return ELSC_ERROR_MODULE; + + /* Build a moduleid_t-compatible rack number */ + + rack = 0; + t = rnum / 100; /* rack class (CPU/IO) */ + if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_CLASS(rack, t); + rnum %= 100; + + t = rnum / 10; /* rack group */ + if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_GROUP(rack, t); + + t = rnum % 10; /* rack number (one-based) */ + if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_NUM(rack, t); + + switch( brick_type ) { + case 'I': + brick_type = MODULE_IBRICK; break; + case 'P': + brick_type = MODULE_PBRICK; break; + case 'X': + brick_type = MODULE_XBRICK; break; + } + + ret = RBT_TO_MODULE(rack, bay, brick_type); + + return ret; +} + +/* + * iobrick_module_get_nasid() returns a module_id which has the brick + * type encoded in bits 15-12, but this is not the true brick type... + * The module_id returned by iobrick_module_get_nasid() is modified + * to make a PEBRICKs & PXBRICKs look like a PBRICK. So this routine + * iobrick_type_get_nasid() returns the true unmodified brick type. + */ +int +iobrick_type_get_nasid(nasid_t nasid) +{ + l1sc_t *sc = get_elsc(); + elsc_t tmp_sc; + uint rack, bay, type; + int t, ret; + +#ifdef PIC_LATER + if (PEBRICK_NODE(nasid)) { + if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) { + printf("Could not read rack and bay location " + "of PEBrick at nasid %d\n", nasid); + } + if ((ret = peer_iobrick_type_get(sc, rack, bay, &type)) < 0) + return ret; + } + else +#endif /* PIC_LATER */ + if (nasid != get_nasid()) { /* get the io_moduleid from remote node */ + elsc_init(&tmp_sc, nasid); + if ((ret = iobrick_rack_bay_type_get(&tmp_sc, &rack, &bay, &type)) < 0) + return ret; + } + else { + if ((ret = iobrick_rack_bay_type_get(sc, &rack, &bay, &type)) < 0) + return ret; + } + + /* + * Some brick_types need special treatment. NOTE: This switch is + * duplicated in iobrick_module_get(), so if you change this switch + * you must also change it there. + */ + switch (type) + { + case L1_BRICKTYPE_IP45: + /* treat speedo2 like Ibrick for moduleid purposes */ + type = L1_BRICKTYPE_I; + break; + case L1_BRICKTYPE_X2: + /* give X2 bricks the same moduleid as earlier models */ + type = L1_BRICKTYPE_X; + break; + } + + /* convert brick_type to lower case */ + if ((type >= 'A') && (type <= 'Z')) + type = type - 'A' + 'a'; + + /* convert to a module.h brick type */ + for( t = 0; t < MAX_BRICK_TYPES; t++ ) { + if( brick_types[t] == type ) + return t; + } + + return -1; /* unknown brick */ +} + +int iobrick_module_get_nasid(nasid_t nasid) +{ + int io_moduleid; + l1sc_t *sc = get_elsc(); + elsc_t tmp_sc; + +#ifdef PIC_LATER + uint rack, bay; + + if (PEBRICK_NODE(nasid)) { + if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) { + printf("Could not read rack and bay location " + "of PEBrick at nasid %d\n", nasid); + } + + io_moduleid = peer_iobrick_module_get(sc, rack, bay); + } + else +#endif /* PIC_LATER */ + if (nasid != get_nasid()) { /* get the io_moduleid from remote node */ + elsc_init(&tmp_sc, nasid); + + io_moduleid = iobrick_module_get(&tmp_sc); + } + else { + io_moduleid = iobrick_module_get(sc); + } + + return io_moduleid; +} + + +/* iobrick_get_sys_snum asks the attached iobrick for the system + * serial number. This function will only be relevant to the master + * cbrick (the one attached to the bootmaster ibrick); other nodes + * may call the function, but the value returned to the master node + * will be the one used as the system serial number by the kernel. + */ + +int +iobrick_get_sys_snum( l1sc_t *sc, char *snum_str ) +{ + char msg[BRL1_QSIZE]; /* L1 request/response info */ + int subch; /* system controller subchannel used */ + int len; /* length of message */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { + return( ELSC_ERROR_CMD_SEND ); + } + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_SYS_SERIAL, 0 )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( sc_command( sc, subch, msg, msg, &len ) ) { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + return( sc_interpret_resp( msg, 2, L1_ARG_ASCII, snum_str ) ); +} + + +/* + * The following functions apply (or cut off) power to the specified + * pci bus or slot. + */ + +int +iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code ) +{ +#if 0 /* The "bedrock request" method of performing this function + * seems to be broken in the L1, so for now use the command- + * interpreter method + */ + + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int subch; /* system controller subchannel used */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( sc, L1_ADDR_LOCALIO ); + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + req_code, 4, + L1_ARG_INT, bus, + L1_ARG_INT, slot )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 0 ) < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + return 0; + +#else + char cmd[64]; + char *fxn; + + switch( req_code ) + { + case L1_REQ_PCI_UP: + fxn = "u"; + break; + case L1_REQ_PCI_DOWN: + fxn = "d"; + break; + case L1_REQ_PCI_RESET: + fxn = "rst"; + break; + default: + return( ELSC_ERROR_CMD_ARGS ); + } + + if( slot == -1 ) + sprintf( cmd, "pci %d %s", bus, fxn ); + else + sprintf( cmd, "pci %d %d %s", bus, slot, fxn ); + + return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK, + L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd ); +#endif +} + +int +iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) +{ + return iobrick_pci_pwr( sc, bus, slot, up ); +} + +int +iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ) +{ + return iobrick_pci_pwr( sc, bus, -1, up ); +} + + +int +iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot ) +{ + return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET ); +} + +int +iobrick_pci_bus_rst( l1sc_t *sc, int bus ) +{ + return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET ); +} + + +/* get the L1 firmware version for an iobrick */ +int +iobrick_sc_version( l1sc_t *sc, char *result ) +{ + char msg[BRL1_QSIZE]; + int len; /* length of message being sent */ + int subch; /* system controller subchannel used */ + int major, /* major rev number */ + minor, /* minor rev number */ + bugfix; /* bugfix rev number */ + + /* fill in msg with the opcode & params */ + bzero( msg, BRL1_QSIZE ); + subch = sc_open( sc, L1_ADDR_LOCALIO ); + + if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, + L1_ADDR_TASK_GENERAL, + L1_REQ_FW_REV, 0 )) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_ARGS ); + } + + /* send the request to the L1 */ + if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) + { + sc_close( sc, subch ); + return( ELSC_ERROR_CMD_SEND ); + } + + /* free up subchannel */ + sc_close( sc, subch ); + + /* check response */ + if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, + L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) + < 0 ) + { + return( ELSC_ERROR_RESP_FORMAT ); + } + + sprintf( result, "%d.%d.%d", major, minor, bugfix ); + + return 0; +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/mem_refcnt.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/mem_refcnt.c --- linux-2.4.19/arch/ia64/sn/io/sn1/mem_refcnt.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/mem_refcnt.c Mon Dec 30 14:16:56 2002 @@ -4,10 +4,9 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ -#include #include #include #include @@ -43,7 +42,7 @@ int mem_refcnt_attach(devfs_handle_t hub) { -#ifndef CONFIG_IA64_SGI_SN +#if 0 devfs_handle_t refcnt_dev; hwgraph_char_device_add(hub, diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/ml_SN_init.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ml_SN_init.c --- linux-2.4.19/arch/ia64/sn/io/sn1/ml_SN_init.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ml_SN_init.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,211 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int numcpus; +extern char arg_maxnodes[]; +extern cpuid_t master_procid; +extern synergy_da_t *Synergy_da_indr[]; + +extern int hasmetarouter; + +int maxcpus; +cpumask_t boot_cpumask; +hubreg_t region_mask = 0; + + +extern xwidgetnum_t hub_widget_id(nasid_t); + +extern int valid_icache_reasons; /* Reasons to flush the icache */ +extern int valid_dcache_reasons; /* Reasons to flush the dcache */ +extern u_char miniroot; +extern volatile int need_utlbmiss_patch; +extern void iograph_early_init(void); + +nasid_t master_nasid = INVALID_NASID; + + +/* + * mlreset(int slave) + * very early machine reset - at this point NO interrupts have been + * enabled; nor is memory, tlb, p0, etc setup. + * + * slave is zero when mlreset is called for the master processor and + * is nonzero thereafter. + */ + + +void +mlreset(int slave) +{ + if (!slave) { + /* + * We are the master cpu and node. + */ + master_nasid = get_nasid(); + set_master_bridge_base(); + + /* We're the master processor */ + master_procid = smp_processor_id(); + master_nasid = cpuid_to_nasid(master_procid); + + /* + * master_nasid we get back better be same as one from + * get_nasid() + */ + ASSERT_ALWAYS(master_nasid == get_nasid()); + + /* early initialization of iograph */ + iograph_early_init(); + + /* Initialize Hub Pseudodriver Management */ + hubdev_init(); + + } else { /* slave != 0 */ + /* + * This code is performed ONLY by slave processors. + */ + + } +} + + +/* XXX - Move the meat of this to intr.c ? */ +/* + * Set up the platform-dependent fields in the nodepda. + */ +void init_platform_nodepda(nodepda_t *npda, cnodeid_t node) +{ + hubinfo_t hubinfo; + int sn; + + extern void router_map_init(nodepda_t *); + extern void router_queue_init(nodepda_t *,cnodeid_t); + extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int); + + /* Allocate per-node platform-dependent data */ + hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s)); + + npda->pdinfo = (void *)hubinfo; + hubinfo->h_nodepda = npda; + hubinfo->h_cnodeid = node; + hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node); + + spin_lock_init(&hubinfo->h_crblock); + + hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); + npda->xbow_peer = INVALID_NASID; + + /* + * Initialize the linked list of + * router info pointers to the dependent routers + */ + npda->npda_rip_first = NULL; + + /* + * npda_rip_last always points to the place + * where the next element is to be inserted + * into the list + */ + npda->npda_rip_last = &npda->npda_rip_first; + npda->module_id = INVALID_MODULE; + + /* + * Initialize the interrupts. + * On sn2, this is done at pci init time, + * because sn2 needs the cpus checked in + * when it initializes interrupts. This is + * so we don't see all the nodes as headless. + */ + for (sn=0; snxbow_sema); /* init it locked? */ +} + +/* XXX - Move the interrupt stuff to intr.c ? */ +/* + * Set up the platform-dependent fields in the processor pda. + * Must be done _after_ init_platform_nodepda(). + * If we need a lock here, something else is wrong! + */ +void init_platform_pda(cpuid_t cpu) +{ + hub_intmasks_t *intmasks; + int i, subnode; + cnodeid_t cnode; + synergy_da_t *sda; + int which_synergy; + + + cnode = cpuid_to_cnodeid(cpu); + which_synergy = cpuid_to_synergy(cpu); + + sda = Synergy_da_indr[(cnode * 2) + which_synergy]; + intmasks = &sda->s_intmasks; + + /* Clear INT_PEND0 masks. */ + for (i = 0; i < N_INTPEND0_MASKS; i++) + intmasks->intpend0_masks[i] = 0; + + /* Set up pointer to the vector block in the nodepda. */ + /* (Cant use SUBNODEPDA - not working yet) */ + subnode = cpuid_to_subnode(cpu); + intmasks->dispatch0 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; + intmasks->dispatch1 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; + if (intmasks->dispatch0 != &SUBNODEPDA(cnode, subnode)->intr_dispatch0 || + intmasks->dispatch1 != &SUBNODEPDA(cnode, subnode)->intr_dispatch1) + panic("xxx"); + intmasks->dispatch0 = &SUBNODEPDA(cnode, subnode)->intr_dispatch0; + intmasks->dispatch1 = &SUBNODEPDA(cnode, subnode)->intr_dispatch1; + + /* Clear INT_PEND1 masks. */ + for (i = 0; i < N_INTPEND1_MASKS; i++) + intmasks->intpend1_masks[i] = 0; +} + +void +update_node_information(cnodeid_t cnodeid) +{ + nodepda_t *npda = NODEPDA(cnodeid); + nodepda_router_info_t *npda_rip; + + /* Go through the list of router info + * structures and copy some frequently + * accessed info from the info hanging + * off the corresponding router vertices + */ + npda_rip = npda->npda_rip_first; + while(npda_rip) { + if (npda_rip->router_infop) { + npda_rip->router_portmask = + npda_rip->router_infop->ri_portmask; + npda_rip->router_slot = + npda_rip->router_infop->ri_slotnum; + } else { + /* No router, no ports. */ + npda_rip->router_portmask = 0; + } + npda_rip = npda_rip->router_next; + } +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/ml_SN_intr.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ml_SN_intr.c --- linux-2.4.19/arch/ia64/sn/io/sn1/ml_SN_intr.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ml_SN_intr.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/ml_iograph.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ml_iograph.c --- linux-2.4.19/arch/ia64/sn/io/sn1/ml_iograph.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/ml_iograph.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1505 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define IOGRAPH_DEBUG */ +#ifdef IOGRAPH_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* IOGRAPH_DEBUG */ + +/* #define PROBE_TEST */ + +/* At most 2 hubs can be connected to an xswitch */ +#define NUM_XSWITCH_VOLUNTEER 2 + +/* + * Track which hubs have volunteered to manage devices hanging off of + * a Crosstalk Switch (e.g. xbow). This structure is allocated, + * initialized, and hung off the xswitch vertex early on when the + * xswitch vertex is created. + */ +typedef struct xswitch_vol_s { + mutex_t xswitch_volunteer_mutex; + int xswitch_volunteer_count; + devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; +} *xswitch_vol_t; + +void +xswitch_vertex_init(devfs_handle_t xswitch) +{ + xswitch_vol_t xvolinfo; + int rc; + + xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); + mutex_init(&xvolinfo->xswitch_volunteer_mutex); + xvolinfo->xswitch_volunteer_count = 0; + rc = hwgraph_info_add_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t)xvolinfo); + ASSERT(rc == GRAPH_SUCCESS); rc = rc; +} + + +/* + * When assignment of hubs to widgets is complete, we no longer need the + * xswitch volunteer structure hanging around. Destroy it. + */ +static void +xswitch_volunteer_delete(devfs_handle_t xswitch) +{ + xswitch_vol_t xvolinfo; + int rc; + + rc = hwgraph_info_remove_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t *)&xvolinfo); + kfree(xvolinfo); +} +/* + * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. + */ +/* ARGSUSED */ +static void +volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) +{ + xswitch_vol_t xvolinfo = NULL; + devfs_handle_t hubv; + hubinfo_t hubinfo; + + (void)hwgraph_info_get_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t *)&xvolinfo); + if (xvolinfo == NULL) { + return; + } + + mutex_lock(&xvolinfo->xswitch_volunteer_mutex); + ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); + xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; + xvolinfo->xswitch_volunteer_count++; + + /* + * if dual ported, make the lowest widgetid always be + * xswitch_volunteer[0]. + */ + if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) { + hubv = xvolinfo->xswitch_volunteer[0]; + hubinfo_get(hubv, &hubinfo); + if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) { + xvolinfo->xswitch_volunteer[0] = + xvolinfo->xswitch_volunteer[1]; + xvolinfo->xswitch_volunteer[1] = hubv; + } + } + mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); +} + +extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); + +/* + * Assign all the xwidgets hanging off the specified xswitch to the + * Crosstalk masters that have volunteered for xswitch duty. + */ +/* ARGSUSED */ +static void +assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) +{ + xswitch_info_t xswitch_info; + xswitch_vol_t xvolinfo = NULL; + xwidgetnum_t widgetnum; + int num_volunteer; + nasid_t nasid; + hubinfo_t hubinfo; + extern int iobrick_type_get_nasid(nasid_t); + + + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + + xswitch_info = xswitch_info_get(xswitch); + ASSERT(xswitch_info != NULL); + + (void)hwgraph_info_get_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t *)&xvolinfo); + if (xvolinfo == NULL) { + return; + } + + num_volunteer = xvolinfo->xswitch_volunteer_count; + ASSERT(num_volunteer > 0); + + /* Assign master hub for xswitch itself. */ + if (HUB_WIDGET_ID_MIN > 0) { + hubv = xvolinfo->xswitch_volunteer[0]; + xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); + } + + /* + * TBD: Use administrative information to alter assignment of + * widgets to hubs. + */ + for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + int i; + + /* + * Ignore disabled/empty ports. + */ + if (!xbow_port_io_enabled(nasid, widgetnum)) + continue; + + /* + * If this is the master IO board, assign it to the same + * hub that owned it in the prom. + */ + if (is_master_nasid_widget(nasid, widgetnum)) { + for (i=0; ixswitch_volunteer[i]; + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + if (nasid == get_console_nasid()) + goto do_assignment; + } + } + + /* + * Assuming that we're dual-hosted and that PCI cards + * are naturally placed left-to-right, alternate PCI + * buses across both Cbricks. For Pbricks, and Ibricks, + * io_brick_map_widget() returns the PCI bus number + * associated with the given brick type and widget number. + * For Xbricks, it returns the XIO slot number. + */ + + i = 0; + if (num_volunteer > 1) { + int bt; + + bt = iobrick_type_get_nasid(nasid); + if (bt >= 0) { + /* + * PXBRICK has two busses per widget so this + * algorithm wouldn't work (all busses would + * be assigned to one volunteer). Change the + * bricktype to PBRICK whose mapping is setup + * suchthat 2 of the PICs will be assigned to + * one volunteer and the other one will be + * assigned to the other volunteer. + */ + if (bt == MODULE_PXBRICK) + bt = MODULE_PBRICK; + + i = io_brick_map_widget(bt, widgetnum) & 1; + } + } + + hubv = xvolinfo->xswitch_volunteer[i]; + +do_assignment: + /* + * At this point, we want to make hubv the master of widgetnum. + */ + xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); + } + + xswitch_volunteer_delete(xswitch); +} + +/* + * Early iograph initialization. Called by master CPU in mlreset(). + * Useful for including iograph.o in kernel.o. + */ +void +iograph_early_init(void) +{ +/* + * Need new way to get this information .. + */ + cnodeid_t cnode; + nasid_t nasid; + lboard_t *board; + + /* + * Init. the board-to-hwgraph link early, so FRU analyzer + * doesn't trip on leftover values if we panic early on. + */ + for(cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + board = (lboard_t *)KL_CONFIG_INFO(nasid); + DBG("iograph_early_init: Found board 0x%p\n", board); + + /* Check out all the board info stored on a node */ + while(board) { + board->brd_graph_link = GRAPH_VERTEX_NONE; + board = KLCF_NEXT(board); + DBG("iograph_early_init: Found board 0x%p\n", board); + } + } + + hubio_init(); +} + +/* + * Let boot processor know that we're done initializing our node's IO + * and then exit. + */ +/* ARGSUSED */ +static void +io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) +{ + /* Let boot processor know that we're done. */ +} + +/* + * Probe to see if this hub's xtalk link is active. If so, + * return the Crosstalk Identification of the widget that we talk to. + * This is called before any of the Crosstalk infrastructure for + * this hub is set up. It's usually called on the node that we're + * probing, but not always. + * + * TBD: Prom code should actually do this work, and pass through + * hwid for our use. + */ +static void +early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) +{ + hubreg_t llp_csr_reg; + nasid_t nasid; + hubinfo_t hubinfo; + + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + + llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); + /* + * If link is up, read the widget's part number. + * A direct connect widget must respond to widgetnum=0. + */ + if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { + /* TBD: Put hub into "indirect" mode */ + /* + * We're able to read from a widget because our hub's + * WIDGET_ID was set up earlier. + */ + widgetreg_t widget_id = *(volatile widgetreg_t *) + (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); + + DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, + (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); + + hwid->part_num = XWIDGET_PART_NUM(widget_id); + hwid->rev_num = XWIDGET_REV_NUM(widget_id); + hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); + + /* TBD: link reset */ + } else { + + hwid->part_num = XWIDGET_PART_NUM_NONE; + hwid->rev_num = XWIDGET_REV_NUM_NONE; + hwid->mfg_num = XWIDGET_MFG_NUM_NONE; + } +} + +/* Add inventory information to the widget vertex + * Right now (module,slot,revision) is being + * added as inventory information. + */ +static void +xwidget_inventory_add(devfs_handle_t widgetv, + lboard_t *board, + struct xwidget_hwid_s hwid) +{ + if (!board) + return; + /* Donot add inventory information for the baseio + * on a speedo with an xbox. It has already been + * taken care of in SN00_vmc. + * Speedo with xbox's baseio comes in at slot io1 (widget 9) + */ + device_inventory_add(widgetv,INV_IOBD,board->brd_type, + board->brd_module, + SLOTNUM_GETSLOT(board->brd_slot), + hwid.rev_num); +} + +/* + * io_xswitch_widget_init + * + */ + +void +io_xswitch_widget_init(devfs_handle_t xswitchv, + devfs_handle_t hubv, + xwidgetnum_t widgetnum, + async_attach_t aa) +{ + xswitch_info_t xswitch_info; + xwidgetnum_t hub_widgetid; + devfs_handle_t widgetv; + cnodeid_t cnode; + widgetreg_t widget_id; + nasid_t nasid, peer_nasid; + struct xwidget_hwid_s hwid; + hubinfo_t hubinfo; + /*REFERENCED*/ + int rc; + char pathname[128]; + char new_name[64]; + moduleid_t module; + slotid_t slot; + lboard_t *board = NULL; + char buffer[16]; + slotid_t get_widget_slotnum(int xbow, int widget); + + DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); + + /* + * Verify that xswitchv is indeed an attached xswitch. + */ + xswitch_info = xswitch_info_get(xswitchv); + ASSERT(xswitch_info != NULL); + + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + cnode = NASID_TO_COMPACT_NODEID(nasid); + hub_widgetid = hubinfo->h_widgetid; + + /* + * Check that the widget is an io widget and is enabled + * on this nasid or the `peer' nasid. The peer nasid + * is the other hub/bedrock connected to the xbow. + */ + peer_nasid = NODEPDA(cnode)->xbow_peer; + if (peer_nasid == INVALID_NASID) + /* If I don't have a peer, use myself. */ + peer_nasid = nasid; + if (!xbow_port_io_enabled(nasid, widgetnum) && + !xbow_port_io_enabled(peer_nasid, widgetnum)) { + return; + } + + if (xswitch_info_link_ok(xswitch_info, widgetnum)) { + char name[4]; + + /* + * If the current hub is not supposed to be the master + * for this widgetnum, then skip this widget. + */ + if (xswitch_info_master_assignment_get(xswitch_info, + widgetnum) != hubv) { + return; + } + + module = NODEPDA(cnode)->module_id; +#ifdef XBRIDGE_REGS_SIM + /* hardwire for now...could do this with something like: + * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl); + * xbow_t xbow = soft->base; + * xbowreg_t xwidget_id = xbow->xb_wid_id; + * but I don't feel like figuring out vhdl right now.. + * and I know for a fact the answer is 0x2d000049 + */ + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); + DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); + if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) +#else + if (nasid_has_xbridge(nasid)) +#endif /* XBRIDGE_REGS_SIM */ + { + board = find_lboard_module_class( + (lboard_t *)KL_CONFIG_INFO(nasid), + module, + KLTYPE_IOBRICK); + +DBG("io_xswitch_widget_init: Board 0x%p\n", board); +{ + lboard_t dummy; + + + if (board) { + DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); + } else { + DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); + board = &dummy; + } + +} + + /* + * Make sure we really want to say xbrick, pbrick, + * etc. rather than XIO, graphics, etc. + */ + +#ifdef SUPPORT_PRINTING_M_FORMAT + sprintf(pathname, EDGE_LBL_MODULE "/%M/" + "%cbrick" "/%s/%d", + NODEPDA(cnode)->module_id, + +#else + memset(buffer, 0, 16); + format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); + sprintf(pathname, EDGE_LBL_MODULE "/%s/" + "%cbrick" "/%s/%d", + buffer, +#endif + + (board->brd_type == KLTYPE_IBRICK) ? 'I' : + (board->brd_type == KLTYPE_PBRICK) ? 'P' : + (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', + EDGE_LBL_XTALK, widgetnum); + } + + DBG("io_xswitch_widget_init: path= %s\n", pathname); + rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); + + ASSERT(rc == GRAPH_SUCCESS); + + /* This is needed to let the user programs to map the + * module,slot numbers to the corresponding widget numbers + * on the crossbow. + */ + rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); + + /* If we are looking at the global master io6 + * then add information about the version of + * the io6prom as a part of "detailed inventory" + * information. + */ + if (is_master_baseio(nasid, + NODEPDA(cnode)->module_id, + get_widget_slotnum(0,widgetnum))) { + extern void klhwg_baseio_inventory_add(devfs_handle_t, + cnodeid_t); + module = NODEPDA(cnode)->module_id; + +#ifdef XBRIDGE_REGS_SIM + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); + if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) +#else + if (nasid_has_xbridge(nasid)) +#endif /* XBRIDGE_REGS_SIM */ + { + board = find_lboard_module( + (lboard_t *)KL_CONFIG_INFO(nasid), + module); + /* + * Change iobrick to correct i/o brick + */ +#ifdef SUPPORT_PRINTING_M_FORMAT + sprintf(pathname, EDGE_LBL_MODULE "/%M/" +#else + sprintf(pathname, EDGE_LBL_MODULE "/%x/" +#endif + "iobrick" "/%s/%d", + NODEPDA(cnode)->module_id, + EDGE_LBL_XTALK, widgetnum); + } else { + slot = get_widget_slotnum(0, widgetnum); + board = get_board_name(nasid, module, slot, + new_name); + /* + * Create the vertex for the widget, + * using the decimal + * widgetnum as the name of the primary edge. + */ +#ifdef SUPPORT_PRINTING_M_FORMAT + sprintf(pathname, EDGE_LBL_MODULE "/%M/" + EDGE_LBL_SLOT "/%s", + NODEPDA(cnode)->module_id, + new_name); +#else + memset(buffer, 0, 16); + format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); + sprintf(pathname, EDGE_LBL_MODULE "/%s/" + EDGE_LBL_SLOT "/%s", + buffer, + new_name); +#endif + } + + rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); + DBG("io_xswitch_widget_init: (2) path= %s\n", pathname); + /* + * This is a weird ass code needed for error injection + * purposes. + */ + rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); + + klhwg_baseio_inventory_add(widgetv,cnode); + } + sprintf(name, "%d", widgetnum); + DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); + rc = hwgraph_edge_add(xswitchv, widgetv, name); + + /* + * crosstalk switch code tracks which + * widget is attached to each link. + */ + xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); + + /* + * Peek at the widget to get its crosstalk part and + * mfgr numbers, then present it to the generic xtalk + * bus provider to have its driver attach routine + * called (or not). + */ +#ifdef XBRIDGE_REGS_SIM + widget_id = 0x2d000049; + DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); +#else + widget_id = XWIDGET_ID_READ(nasid, widgetnum); +#endif /* XBRIDGE_REGS_SIM */ + hwid.part_num = XWIDGET_PART_NUM(widget_id); + hwid.rev_num = XWIDGET_REV_NUM(widget_id); + hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); + /* Store some inventory information about + * the xwidget in the hardware graph. + */ + xwidget_inventory_add(widgetv,board,hwid); + + (void)xwidget_register(&hwid, widgetv, widgetnum, + hubv, hub_widgetid, + aa); + +#ifdef SN0_USE_BTE + bte_bpush_war(cnode, (void *)board); +#endif + } +} + + +static void +io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) +{ + xwidgetnum_t widgetnum; + async_attach_t aa; + + aa = async_attach_new(); + + DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); + + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; + widgetnum++) { + io_xswitch_widget_init(xswitchv, + cnodeid_to_vertex(cnode), + widgetnum, aa); + } + /* + * Wait for parallel attach threads, if any, to complete. + */ + async_attach_waitall(aa); + async_attach_free(aa); +} + +/* + * For each PCI bridge connected to the xswitch, add a link from the + * board's klconfig info to the bridge's hwgraph vertex. This lets + * the FRU analyzer find the bridge without traversing the hardware + * graph and risking hangs. + */ +static void +io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) +{ + xwidgetnum_t widgetnum; + char pathname[128]; + devfs_handle_t vhdl; + nasid_t nasid, peer_nasid; + lboard_t *board; + + + + /* And its connected hub's nasids */ + nasid = COMPACT_TO_NASID_NODEID(cnodeid); + peer_nasid = NODEPDA(cnodeid)->xbow_peer; + + /* + * Look for paths matching "/pci" under xswitchv. + * For every widget, init. its lboard's hwgraph link. If the + * board has a PCI bridge, point the link to it. + */ + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; + widgetnum++) { + sprintf(pathname, "%d", widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) != + GRAPH_SUCCESS) + continue; + + board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), + NODEPDA(cnodeid)->module_id); + if (board == NULL && peer_nasid != INVALID_NASID) { + /* + * Try to find the board on our peer + */ + board = find_lboard_module( + (lboard_t *)KL_CONFIG_INFO(peer_nasid), + NODEPDA(cnodeid)->module_id); + } + if (board == NULL) { +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_WARNING "Could not find PROM info for vertex %v, " + "FRU analyzer may fail", + vhdl); +#else + printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, " + "FRU analyzer may fail", + (void *)vhdl); +#endif + return; + } + + sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) == + GRAPH_SUCCESS) + board->brd_graph_link = vhdl; + else + board->brd_graph_link = GRAPH_VERTEX_NONE; + } +} + +/* + * Initialize all I/O on the specified node. + */ +static void +io_init_node(cnodeid_t cnodeid) +{ + /*REFERENCED*/ + devfs_handle_t hubv, switchv, widgetv; + struct xwidget_hwid_s hwid; + hubinfo_t hubinfo; + int is_xswitch; + nodepda_t *npdap; + struct semaphore *peer_sema = 0; + uint32_t widget_partnum; + nodepda_router_info_t *npda_rip; + cpu_cookie_t c = 0; + extern int hubdev_docallouts(devfs_handle_t); + +#ifdef LATER + /* Try to execute on the node that we're initializing. */ + c = setnoderun(cnodeid); +#endif + npdap = NODEPDA(cnodeid); + + /* + * Get the "top" vertex for this node's hardware + * graph; it will carry the per-hub hub-specific + * data, and act as the crosstalk provider master. + * It's canonical path is probably something of the + * form /hw/module/%M/slot/%d/node + */ + hubv = cnodeid_to_vertex(cnodeid); + DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); + + ASSERT(hubv != GRAPH_VERTEX_NONE); + + hubdev_docallouts(hubv); + + /* + * Set up the dependent routers if we have any. + */ + npda_rip = npdap->npda_rip_first; + + while(npda_rip) { + /* If the router info has not been initialized + * then we need to do the router initialization + */ + if (!npda_rip->router_infop) { + router_init(cnodeid,0,npda_rip); + } + npda_rip = npda_rip->router_next; + } + + /* + * Read mfg info on this hub + */ + + /* + * If nothing connected to this hub's xtalk port, we're done. + */ + early_probe_for_widget(hubv, &hwid); + if (hwid.part_num == XWIDGET_PART_NUM_NONE) { +#ifdef PROBE_TEST + if ((cnodeid == 1) || (cnodeid == 2)) { + int index; + + for (index = 0; index < 600; index++) + DBG("Interfering with device probing!!!\n"); + } +#endif + /* io_init_done takes cpu cookie as 2nd argument + * to do a restorenoderun for the setnoderun done + * at the start of this thread + */ + + DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); + return; + /* NOTREACHED */ + } + + /* + * attach our hub_provider information to hubv, + * so we can use it as a crosstalk provider "master" + * vertex. + */ + xtalk_provider_register(hubv, &hub_provider); + xtalk_provider_startup(hubv); + + /* + * Create a vertex to represent the crosstalk bus + * attached to this hub, and a vertex to be used + * as the connect point for whatever is out there + * on the other side of our crosstalk connection. + * + * Crosstalk Switch drivers "climb up" from their + * connection point to try and take over the switch + * point. + * + * Of course, the edges and verticies may already + * exist, in which case our net effect is just to + * associate the "xtalk_" driver with the connection + * point for the device. + */ + + (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); + + DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); + + ASSERT(switchv != GRAPH_VERTEX_NONE); + + (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); + + DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); + + /* + * We need to find the widget id and update the basew_id field + * accordingly. In particular, SN00 has direct connected bridge, + * and hence widget id is Not 0. + */ + + widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; + + if (widget_partnum == BRIDGE_WIDGET_PART_NUM || + widget_partnum == XBRIDGE_WIDGET_PART_NUM){ + npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); + + DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); + + } else if ((widget_partnum == XBOW_WIDGET_PART_NUM) || + (widget_partnum == XXBOW_WIDGET_PART_NUM) || + (widget_partnum == PXBOW_WIDGET_PART_NUM) ) { + /* + * Xbow control register does not have the widget ID field. + * So, hard code the widget ID to be zero. + */ + DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); + npdap->basew_id = 0; + + } else { + npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); + + panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); + + /*NOTREACHED*/ + } + { + char widname[10]; + sprintf(widname, "%x", npdap->basew_id); + (void)hwgraph_path_add(switchv, widname, &widgetv); + DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); + ASSERT(widgetv != GRAPH_VERTEX_NONE); + } + + nodepda->basew_xc = widgetv; + + is_xswitch = xwidget_hwid_is_xswitch(&hwid); + + /* + * Try to become the master of the widget. If this is an xswitch + * with multiple hubs connected, only one will succeed. Mastership + * of an xswitch is used only when touching registers on that xswitch. + * The slave xwidgets connected to the xswitch can be owned by various + * masters. + */ + if (device_master_set(widgetv, hubv) == 0) { + + /* Only one hub (thread) per Crosstalk device or switch makes + * it to here. + */ + + /* + * Initialize whatever xwidget is hanging off our hub. + * Whatever it is, it's accessible through widgetnum 0. + */ + hubinfo_get(hubv, &hubinfo); + + (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL); + + if (!is_xswitch) { + /* io_init_done takes cpu cookie as 2nd argument + * to do a restorenoderun for the setnoderun done + * at the start of this thread + */ + io_init_done(cnodeid,c); + /* NOTREACHED */ + } + + /* + * Special handling for Crosstalk Switches (e.g. xbow). + * We need to do things in roughly the following order: + * 1) Initialize xswitch hardware (done above) + * 2) Determine which hubs are available to be widget masters + * 3) Discover which links are active from the xswitch + * 4) Assign xwidgets hanging off the xswitch to hubs + * 5) Initialize all xwidgets on the xswitch + */ + + volunteer_for_widgets(switchv, hubv); + + /* If there's someone else on this crossbow, recognize him */ + if (npdap->xbow_peer != INVALID_NASID) { + nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer)); + peer_sema = &peer_npdap->xbow_sema; + volunteer_for_widgets(switchv, peer_npdap->node_vertex); + } + + assign_widgets_to_volunteers(switchv, hubv); + + /* Signal that we're done */ + if (peer_sema) { + mutex_unlock(peer_sema); + } + + } + else { + /* Wait 'til master is done assigning widgets. */ + mutex_lock(&npdap->xbow_sema); + } + +#ifdef PROBE_TEST + if ((cnodeid == 1) || (cnodeid == 2)) { + int index; + + for (index = 0; index < 500; index++) + DBG("Interfering with device probing!!!\n"); + } +#endif + /* Now both nodes can safely inititialize widgets */ + io_init_xswitch_widgets(switchv, cnodeid); + io_link_xswitch_widgets(switchv, cnodeid); + + /* io_init_done takes cpu cookie as 2nd argument + * to do a restorenoderun for the setnoderun done + * at the start of this thread + */ + io_init_done(cnodeid,c); + + DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); +} + + +#define IOINIT_STKSZ (16 * 1024) + +#define __DEVSTR1 "/../.master/" +#define __DEVSTR2 "/target/" +#define __DEVSTR3 "/lun/0/disk/partition/" +#define __DEVSTR4 "/../ef" + +/* + * Currently, we need to allow for 5 IBrick slots with 1 FC each + * plus an internal 1394. + * + * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR. + */ +#define NUM_BASE_IO_SCSI_CTLR 6 + +/* + * This tells ioconfig where it can start numbering scsi controllers. + * Below this base number, platform-specific handles the numbering. + * XXX Irix legacy..controller numbering should be part of devfsd's job + */ +int num_base_io_scsi_ctlr = 2; /* used by syssgi */ +devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR]; +static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl; + +/* + * Put the logical controller number information in the + * scsi controller vertices for each scsi controller that + * is in a "fixed position". + */ +static void +scsi_ctlr_nums_add(devfs_handle_t pci_vhdl) +{ + { + int i; + + num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR; + + /* Initialize base_io_scsi_ctlr_vhdl array */ + for (i=0; i +devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; + +/* Define the system critical vertices and connect them through + * a canonical parent-child relationships for easy traversal + * during io error handling. + */ +static void +sys_critical_graph_init(void) +{ + devfs_handle_t bridge_vhdl,master_node_vhdl; + devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE; + extern devfs_handle_t hwgraph_root; + devfs_handle_t pci_slot_conn; + int slot; + devfs_handle_t baseio_console_conn; + + DBG("sys_critical_graph_init: FIXME.\n"); + baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); + + if (baseio_console_conn == NULL) { + return; + } + + /* Get the vertex handle for the baseio bridge */ + bridge_vhdl = device_master_get(baseio_console_conn); + + /* Get the master node of the baseio card */ + master_node_vhdl = cnodeid_to_vertex( + master_node_get(baseio_console_vhdl)); + + /* Add the "root->node" part of the system critical graph */ + + sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl); + + /* Check if we have a crossbow */ + if (hwgraph_traverse(master_node_vhdl, + EDGE_LBL_XTALK"/0", + &xbow_vhdl) == GRAPH_SUCCESS) { + /* We have a crossbow.Add "node->xbow" part of the system + * critical graph. + */ + sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl); + + /* Add "xbow->baseio bridge" of the system critical graph */ + sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl); + + hwgraph_vertex_unref(xbow_vhdl); + } else + /* We donot have a crossbow. Add "node->baseio_bridge" + * part of the system critical graph. + */ + sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl); + + /* Add all the populated PCI slot vertices to the system critical + * graph with the bridge vertex as the parent. + */ + for (slot = 0 ; slot < 8; slot++) { + char slot_edge[10]; + + sprintf(slot_edge,"%d",slot); + if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn) + != GRAPH_SUCCESS) + continue; + sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn); + hwgraph_vertex_unref(pci_slot_conn); + } + + hwgraph_vertex_unref(bridge_vhdl); + + /* Add the "ioc3 pci connection point -> console ioc3" part + * of the system critical graph + */ + + if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) == + GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + baseio_console_vhdl); + hwgraph_vertex_unref(pci_slot_conn); + } + + /* Add the "ethernet pci connection point -> base ethernet" part of + * the system critical graph + */ + if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) == + GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + baseio_enet_vhdl); + hwgraph_vertex_unref(pci_slot_conn); + } + + /* Add the "scsi controller pci connection point -> base scsi + * controller" part of the system critical graph + */ + if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0], + "../..",&pci_slot_conn) == GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + base_io_scsi_ctlr_vhdl[0]); + hwgraph_vertex_unref(pci_slot_conn); + } + if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1], + "../..",&pci_slot_conn) == GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + base_io_scsi_ctlr_vhdl[1]); + hwgraph_vertex_unref(pci_slot_conn); + } + hwgraph_vertex_unref(baseio_console_conn); + +} + +static void +baseio_ctlr_num_set(void) +{ + char name[MAXDEVNAME]; + devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; + devfs_handle_t ioc3_console_vhdl_get(void); + + + DBG("baseio_ctlr_num_set; FIXME\n"); + console_vhdl = ioc3_console_vhdl_get(); + if (console_vhdl == GRAPH_VERTEX_NONE) + return; + /* Useful for setting up the system critical graph */ + baseio_console_vhdl = console_vhdl; + + vertex_to_name(console_vhdl,name,MAXDEVNAME); + + strcat(name,__DEVSTR1); + pci_vhdl = hwgraph_path_to_vertex(name); + scsi_ctlr_nums_add(pci_vhdl); + /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex + */ + hwgraph_vertex_unref(pci_vhdl); + + vertex_to_name(console_vhdl, name, MAXDEVNAME); + strcat(name, __DEVSTR4); + enet_vhdl = hwgraph_path_to_vertex(name); + + /* Useful for setting up the system critical graph */ + baseio_enet_vhdl = enet_vhdl; + + device_controller_num_set(enet_vhdl, 0); + /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex + */ + hwgraph_vertex_unref(enet_vhdl); +} +/* #endif */ + +void +sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list) +{ + /* REFERENCED */ + int rtn_val; + + /* + ** sn00 population: errb orrb + ** 0- ql 3+? + ** 1- ql 2 + ** 2- ioc3 ethernet 2+? + ** 3- ioc3 secondary 1 + ** 4- 0 + ** 5- PCI slot + ** 6- PCI slot + ** 7- PCI slot + */ + + /* The following code implements this heuristic for getting + * maximum usage out of the rrbs + * + * constraints: + * 8 bit ql1 needs 1+1 + * ql0 or ql5,6,7 wants 1+2 + * ethernet wants 2 or more + * + * rules for even rrbs: + * if nothing in slot 6 + * 4 rrbs to 0 and 2 (0xc8889999) + * else + * 3 2 3 to slots 0 2 6 (0xc8899bbb) + * + * rules for odd rrbs + * if nothing in slot 5 or 7 (0xc8889999) + * 4 rrbs to 1 and 3 + * else if 1 thing in 5 or 7 (0xc8899aaa) or (0xc8899bbb) + * 3 2 3 to slots 1 3 5|7 + * else + * 2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this + * (0xc89aaabb) may short what it wants therefore the + * rule should be to plug pci slots in order) + */ + + + if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) { + /* something in slot 6 */ + rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0); + } + else { + rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0); + } + if (rtn_val) + printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); + + if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && + (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) { + /* soemthing in slot 5 and 7 */ + rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0); + } + else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) { + /* soemthing in slot 5 but not 7 */ + rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0); + } + else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) { + /* soemthing in slot 7 but not 5 */ + rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0); + } + else { + /* nothing in slot 5 or 7 */ + rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0); + } + if (rtn_val) + printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); +} + + +/* + * Initialize all I/O devices. Starting closest to nodes, probe and + * initialize outward. + */ +void +init_all_devices(void) +{ + /* Governor on init threads..bump up when safe + * (beware many devfs races) + */ + cnodeid_t cnodeid, active; + + active = 0; + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { + DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); + io_init_node(cnodeid); + + DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); + } + + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) + /* + * Update information generated by IO init. + */ + update_node_information(cnodeid); + + baseio_ctlr_num_set(); + /* Setup the system critical graph (which is a subgraph of the + * main hwgraph). This information is useful during io error + * handling. + */ + sys_critical_graph_init(); + +#if HWG_PRINT + hwgraph_print(); +#endif + +} + +#define toint(x) ((int)(x) - (int)('0')) + +void +devnamefromarcs(char *devnm) +{ + int val; + char tmpnm[MAXDEVNAME]; + char *tmp1, *tmp2; + + val = strncmp(devnm, "dks", 3); + if (val != 0) + return; + tmp1 = devnm + 3; + if (!isdigit(*tmp1)) + return; + + val = 0; + while (isdigit(*tmp1)) { + val = 10*val+toint(*tmp1); + tmp1++; + } + + if(*tmp1 != 'd') + return; + else + tmp1++; + + if ((val < 0) || (val >= num_base_io_scsi_ctlr)) { + int i; + int viable_found = 0; + + DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); + DBG("prom \"root\" variables of the form dksXdXsX.\n"); + DBG("To use another disk you must use the full hardware graph path\n\n"); + DBG("Possible controller numbers for use in 'dksXdXsX' on this system: "); + for (i=0; i XBOW_PORT_F) + return 0; + + /* Find "brick" in the path name */ + bp = strstr(hw_path_name, "brick"); + if (bp == NULL) + return 0; + + /* Find preceding slash */ + sp = bp; + while (sp > hw_path_name) { + sp--; + if (*sp == '/') + break; + } + + /* Invalid if no preceding slash */ + if (!sp) + return 0; + + /* Bump slash pointer to "brick" prefix */ + sp++; + /* + * Verify "brick" prefix length; valid exaples: + * 'I' from "/Ibrick" + * 'P' from "/Pbrick" + * 'X' from "/Xbrick" + */ + if ((bp - sp) != 1) + return 0; + + return (io_brick_map_widget((int)*sp, widget_num)); + +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/module.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/module.c --- linux-2.4.19/arch/ia64/sn/io/sn1/module.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/module.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,311 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* #define LDEBUG 1 */ + +#ifdef LDEBUG +#define DPRINTF printk +#define printf printk +#else +#define DPRINTF(x...) +#endif + +module_t *modules[MODULE_MAX]; +int nummodules; + +#define SN00_SERIAL_FUDGE 0x3b1af409d513c2 +#define SN0_SERIAL_FUDGE 0x6e + +void +encode_int_serial(uint64_t src,uint64_t *dest) +{ + uint64_t val; + int i; + + val = src + SN00_SERIAL_FUDGE; + + + for (i = 0; i < sizeof(long long); i++) { + ((char*)dest)[i] = + ((char*)&val)[sizeof(long long)/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))]; + } +} + + +void +decode_int_serial(uint64_t src, uint64_t *dest) +{ + uint64_t val; + int i; + + for (i = 0; i < sizeof(long long); i++) { + ((char*)&val)[sizeof(long long)/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = + ((char*)&src)[i]; + } + + *dest = val - SN00_SERIAL_FUDGE; +} + + +void +encode_str_serial(const char *src, char *dest) +{ + int i; + + for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { + + dest[i] = src[MAX_SERIAL_NUM_SIZE/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))] + + SN0_SERIAL_FUDGE; + } +} + +void +decode_str_serial(const char *src, char *dest) +{ + int i; + + for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { + dest[MAX_SERIAL_NUM_SIZE/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] - + SN0_SERIAL_FUDGE; + } +} + + +module_t *module_lookup(moduleid_t id) +{ + int i; + + for (i = 0; i < nummodules; i++) + if (modules[i]->id == id) { + DPRINTF("module_lookup: found m=0x%p\n", modules[i]); + return modules[i]; + } + + return NULL; +} + +/* + * module_add_node + * + * The first time a new module number is seen, a module structure is + * inserted into the module list in order sorted by module number + * and the structure is initialized. + * + * The node number is added to the list of nodes in the module. + */ + +module_t *module_add_node(moduleid_t id, cnodeid_t n) +{ + module_t *m; + int i; + char buffer[16]; + +#ifdef __ia64 + memset(buffer, 0, 16); + format_module_id(buffer, id, MODULE_FORMAT_BRIEF); + DPRINTF("module_add_node: id=%s node=%d\n", buffer, n); +#endif + + if ((m = module_lookup(id)) == 0) { +#ifdef LATER + m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n); +#else + m = kmalloc(sizeof (module_t), GFP_KERNEL); + memset(m, 0 , sizeof(module_t)); +#endif + ASSERT_ALWAYS(m); + + m->id = id; + spin_lock_init(&m->lock); + + mutex_init_locked(&m->thdcnt); + + elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n)); + spin_lock_init(&m->elsclock); + + /* Insert in sorted order by module number */ + + for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--) + modules[i] = modules[i - 1]; + + modules[i] = m; + nummodules++; + } + + m->nodes[m->nodecnt++] = n; + + DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); + + return m; +} + +int module_probe_snum(module_t *m, nasid_t nasid) +{ + lboard_t *board; + klmod_serial_num_t *comp; + char * bcopy(const char * src, char * dest, int count); + char serial_number[16]; + + /* + * record brick serial number + */ + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + + if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) + { +#if LDEBUG + printf ("module_probe_snum: no IP35 board found!\n"); +#endif + return 0; + } + + board_serial_number_get( board, serial_number ); + if( serial_number[0] != '\0' ) { + encode_str_serial( serial_number, m->snum.snum_str ); + m->snum_valid = 1; + } +#if LDEBUG + else { + printf("module_probe_snum: brick serial number is null!\n"); + } + printf("module_probe_snum: brick serial number == %s\n", serial_number); +#endif /* DEBUG */ + + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), + KLTYPE_IOBRICK_XBOW); + + if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) + return 0; + + comp = GET_SNUM_COMP(board); + + if (comp) { +#if LDEBUG + int i; + + printf("********found module with id %x and string", m->id); + + for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) + printf(" %x ", comp->snum.snum_str[i]); + + printf("\n"); /* Fudged string is not ASCII */ +#endif + + if (comp->snum.snum_str[0] != '\0') { + bcopy(comp->snum.snum_str, + m->sys_snum, + MAX_SERIAL_NUM_SIZE); + m->sys_snum_valid = 1; + } + } + + if (m->sys_snum_valid) + return 1; + else { + DPRINTF("Invalid serial number for module %d, " + "possible missing or invalid NIC.", m->id); + return 0; + } +} + +void +io_module_init(void) +{ + cnodeid_t node; + lboard_t *board; + nasid_t nasid; + int nserial; + module_t *m; + + DPRINTF("*******module_init\n"); + + nserial = 0; + + for (node = 0; node < numnodes; node++) { + nasid = COMPACT_TO_NASID_NODEID(node); + + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + ASSERT(board); + + m = module_add_node(board->brd_module, node); + + if (! m->snum_valid && module_probe_snum(m, nasid)) + nserial++; + } + + DPRINTF("********found total of %d serial numbers in the system\n", + nserial); + + if (nserial == 0) + printk(KERN_WARNING "io_module_init: No serial number found.\n"); +} + +elsc_t *get_elsc(void) +{ + return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc; +} + +int +get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info) +{ + int i; + + if (cmod < 0 || cmod >= nummodules) + return -EINVAL; + + if (! modules[cmod]->snum_valid) + return -ENXIO; + + mod_info->mod_num = modules[cmod]->id; + { + char temp[MAX_SERIAL_NUM_SIZE]; + + decode_str_serial(modules[cmod]->snum.snum_str, temp); + + /* if this is an invalid serial number return an error */ + if (temp[0] != 'K') + return -ENXIO; + + mod_info->serial_num = 0; + + for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) { + mod_info->serial_num <<= 4; + mod_info->serial_num |= (temp[i] & 0xf); + + mod_info->serial_str[i] = temp[i]; + } + + mod_info->serial_str[i] = '\0'; + } + + return 0; +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/pci_bus_cvlink.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/pci_bus_cvlink.c --- linux-2.4.19/arch/ia64/sn/io/sn1/pci_bus_cvlink.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/pci_bus_cvlink.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,696 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int bridge_rev_b_data_check_disable; + +devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; +nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; +void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; +unsigned char num_bridges; +static int done_probing = 0; + +static int pci_bus_map_create(devfs_handle_t xtalk); +devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); + +#define SN_IOPORTS_UNIT 256 +#define MAX_IOPORTS 0xffff +#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN_IOPORTS_UNIT) +struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS]; +unsigned long sn_allocate_ioports(unsigned long pci_address); +extern unsigned char Is_pic_on_this_nasid[512]; + +extern void sn_init_irq_desc(void); + + +/* + * For the given device, initialize whether it is a PIC device. + */ +static void +set_isPIC(struct sn_device_sysdata *device_sysdata) +{ + pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);; +} + +/* + * pci_bus_cvlink_init() - To be called once during initialization before + * SGI IO Infrastructure init is called. + */ +void +pci_bus_cvlink_init(void) +{ + memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); + memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); + + memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); + + memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs)); + + num_bridges = 0; +} + +/* + * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated + * pci bus vertex from the SGI IO Infrastructure. + */ +devfs_handle_t +pci_bus_to_vertex(unsigned char busnum) +{ + + devfs_handle_t pci_bus = NULL; + + + /* + * First get the xwidget vertex. + */ + pci_bus = busnum_to_pcibr_vhdl[busnum]; + return(pci_bus); +} + +/* + * devfn_to_vertex() - returns the vertex of the device given the bus, slot, + * and function numbers. + */ +devfs_handle_t +devfn_to_vertex(unsigned char busnum, unsigned int devfn) +{ + + int slot = 0; + int func = 0; + char name[16]; + devfs_handle_t pci_bus = NULL; + devfs_handle_t device_vertex = (devfs_handle_t)NULL; + + /* + * Go get the pci bus vertex. + */ + pci_bus = pci_bus_to_vertex(busnum); + if (!pci_bus) { + /* + * During probing, the Linux pci code invents non existant + * bus numbers and pci_dev structures and tries to access + * them to determine existance. Don't crib during probing. + */ + if (done_probing) + printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); + return(NULL); + } + + + /* + * Go get the slot&function vertex. + * Should call pciio_slot_func_to_name() when ready. + */ + slot = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* + * For a NON Multi-function card the name of the device looks like: + * ../pci/1, ../pci/2 .. + */ + if (func == 0) { + sprintf(name, "%d", slot); + if (hwgraph_traverse(pci_bus, name, &device_vertex) == + GRAPH_SUCCESS) { + if (device_vertex) { + return(device_vertex); + } + } + } + + /* + * This maybe a multifunction card. It's names look like: + * ../pci/1a, ../pci/1b, etc. + */ + sprintf(name, "%d%c", slot, 'a'+func); + if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { + if (!device_vertex) { + return(NULL); + } + } + + return(device_vertex); +} + +/* + * For the given device, initialize the addresses for both the Device(x) Flush + * Write Buffer register and the Xbow Flush Register for the port the PCI bus + * is connected. + */ +static void +set_flush_addresses(struct pci_dev *device_dev, + struct sn_device_sysdata *device_sysdata) +{ + pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + + device_sysdata->dma_buf_sync = (volatile unsigned int *) + &(bridge->b_wr_req_buf[pciio_slot].reg); + device_sysdata->xbow_buf_sync = (volatile unsigned int *) + XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(get_nasid(), 0), + pcibr_soft->bs_xid); +#ifdef DEBUG + + printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", + device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); + + while((volatile unsigned int )*device_sysdata->dma_buf_sync); + while((volatile unsigned int )*device_sysdata->xbow_buf_sync); +#endif + +} + +/* + * Most drivers currently do not properly tell the arch specific pci dma + * interfaces whether they can handle A64. Here is where we privately + * keep track of this. + */ +static void __init +set_sn_pci64(struct pci_dev *dev) +{ + unsigned short vendor = dev->vendor; + unsigned short device = dev->device; + + if (vendor == PCI_VENDOR_ID_QLOGIC) { + if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) || + (device == PCI_DEVICE_ID_QLOGIC_ISP2200)) { + SET_PCIA64(dev); + return; + } + } + + if (vendor == PCI_VENDOR_ID_SGI) { + if (device == PCI_DEVICE_ID_SGI_IOC3) { + SET_PCIA64(dev); + return; + } + } + +} + +/* + * sn_allocate_ioports() - This routine provides the allocation and + * mappings between Linux style IOPORTs management. + * + * For simplicity sake, SN1 will allocate IOPORTs in chunks of + * 256bytes .. irrespective of what the card desires. This may + * have to change when we understand how to deal with legacy ioports + * which are hardcoded in some drivers e.g. SVGA. + * + * Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers. + * It will remain so. The IO Infrastructure will continue to map + * IO Resource just like IRIX. When this is done, we map IOPORT + * chunks to these resources. The Linux drivers will see and use real + * IOPORT numbers. The various IOPORT access macros e.g. inb/outb etc. + * does the munging of these IOPORT numbers to make a Uncache Virtual + * Address. This address via the tlb entries generates the PCI Address + * allocated by the SN1 IO Infrastructure Layer. + */ +static unsigned long sn_ioport_num = 0x1000; /* Reserve room for Legacy stuff */ +unsigned long +sn_allocate_ioports(unsigned long pci_address) +{ + + unsigned long ioport_index; + + /* + * Just some idiot checking .. + */ + if ( sn_ioport_num > 0xffff ) { + printk("sn_allocate_ioports: No more IO PORTS available\n"); + return(-1); + } + + /* + * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's + * Manual for details. + */ + ioport_index = sn_ioport_num / SN_IOPORTS_UNIT; + + ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */ + ioports_to_tlbs[ioport_index].rv_1 = 0; /* 1 Bit */ + ioports_to_tlbs[ioport_index].ma = 4; /* Memory Attributes 3 bits*/ + ioports_to_tlbs[ioport_index].a = 1; /* Set Data Access Bit Fault 1 Bit*/ + ioports_to_tlbs[ioport_index].d = 1; /* Dirty Bit */ + ioports_to_tlbs[ioport_index].pl = 0;/* Privilege Level - All levels can R/W*/ + ioports_to_tlbs[ioport_index].ar = 3; /* Access Rights - R/W only*/ + ioports_to_tlbs[ioport_index].ppn = pci_address >> 12; /* 4K page size */ + ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */ + ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */ + + /* printk("sn_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index]); */ + + sn_ioport_num += SN_IOPORTS_UNIT; + + return(sn_ioport_num - SN_IOPORTS_UNIT); +} + +/* + * sn_pci_fixup() - This routine is called when platform_pci_fixup() is + * invoked at the end of pcibios_init() to link the Linux pci + * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c + * + * Other platform specific fixup can also be done here. + */ +void +sn_pci_fixup(int arg) +{ + struct list_head *ln; + struct pci_bus *pci_bus = NULL; + struct pci_dev *device_dev = NULL; + struct sn_widget_sysdata *widget_sysdata; + struct sn_device_sysdata *device_sysdata; +#ifdef SN_IOPORTS + unsigned long ioport; +#endif + pciio_intr_t intr_handle; + int cpuid, bit; + devfs_handle_t device_vertex; + pciio_intr_line_t lines; + extern void sn_pci_find_bios(void); + + if (arg == 0) { + sn_init_irq_desc(); + sn_pci_find_bios(); + return; + } + + done_probing = 1; + + /* + * Initialize the pci bus vertex in the pci_bus struct. + */ + for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { + pci_bus = pci_bus_b(ln); + widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), + GFP_KERNEL); + widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); + pci_bus->sysdata = (void *)widget_sysdata; + } + + /* + * set the root start and end so that drivers calling check_region() + * won't see a conflict + */ +#ifdef SN_IOPORTS + ioport_resource.start = sn_ioport_num; + ioport_resource.end = 0xffff; +#else + if ( IS_RUNNING_ON_SIMULATOR() ) { + /* + * IDE legacy IO PORTs are supported in Medusa. + * Just open up IO PORTs from 0 .. ioport_resource.end. + */ + ioport_resource.start = 0; + } else { + /* + * We do not support Legacy IO PORT numbers. + */ + ioport_resource.start |= IO_SWIZ_BASE | __IA64_UNCACHED_OFFSET; + } + ioport_resource.end |= (HSPEC_SWIZ_BASE-1) | __IA64_UNCACHED_OFFSET; +#endif + + /* + * Set the root start and end for Mem Resource. + */ + iomem_resource.start = 0; + iomem_resource.end = 0xffffffffffffffff; + + /* + * Initialize the device vertex in the pci_dev struct. + */ + pci_for_each_dev(device_dev) { + unsigned int irq; + int idx; + u16 cmd; + devfs_handle_t vhdl; + unsigned long size; + extern int bit_pos_to_irq(int); + + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { + extern void pci_fixup_ioc3(struct pci_dev *d); + pci_fixup_ioc3(device_dev); + } + + /* Set the device vertex */ + + device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), + GFP_KERNEL); + device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); + device_sysdata->isa64 = 0; + /* + * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush + * register addresses. + */ + (void) set_flush_addresses(device_dev, device_sysdata); + + device_dev->sysdata = (void *) device_sysdata; + set_sn_pci64(device_dev); + set_isPIC(device_sysdata); + + pci_read_config_word(device_dev, PCI_COMMAND, &cmd); + + /* + * Set the resources address correctly. The assumption here + * is that the addresses in the resource structure has been + * read from the card and it was set in the card by our + * Infrastructure .. + */ + vhdl = device_sysdata->vhdl; + for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { + size = 0; + size = device_dev->resource[idx].end - + device_dev->resource[idx].start; + if (size) { + device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); + device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; + } + else + continue; + + device_dev->resource[idx].end = + device_dev->resource[idx].start + size; + + /* + * Adjust the addresses to go to the SWIZZLE .. + */ + device_dev->resource[idx].start = + device_dev->resource[idx].start & 0xfffff7ffffffffff; + device_dev->resource[idx].end = + device_dev->resource[idx].end & 0xfffff7ffffffffff; + + if (device_dev->resource[idx].flags & IORESOURCE_IO) { + cmd |= PCI_COMMAND_IO; +#ifdef SN_IOPORTS + ioport = sn_allocate_ioports(device_dev->resource[idx].start); + if (ioport < 0) { + printk("sn_pci_fixup: PCI Device 0x%x on PCI Bus %d not mapped to IO PORTs .. IO PORTs exhausted\n", device_dev->devfn, device_dev->bus->number); + continue; + } + pciio_config_set(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + (idx * 4), 4, (res + (ioport & 0xfff))); + + printk("sn_pci_fixup: ioport number %d mapped to pci address 0x%lx\n", ioport, (res + (ioport & 0xfff))); + + device_dev->resource[idx].start = ioport; + device_dev->resource[idx].end = ioport + SN_IOPORTS_UNIT; +#endif + } + if (device_dev->resource[idx].flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + /* + * Now handle the ROM resource .. + */ + size = device_dev->resource[PCI_ROM_RESOURCE].end - + device_dev->resource[PCI_ROM_RESOURCE].start; + + if (size) { + device_dev->resource[PCI_ROM_RESOURCE].start = + (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, + size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); + device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; + device_dev->resource[PCI_ROM_RESOURCE].end = + device_dev->resource[PCI_ROM_RESOURCE].start + size; + + /* + * go through synergy swizzled space + */ + device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL; + device_dev->resource[PCI_ROM_RESOURCE].end &= 0xfffff7ffffffffffUL; + + } + + /* + * Update the Command Word on the Card. + */ + cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ + /* bit gets dropped .. no harm */ + pci_write_config_word(device_dev, PCI_COMMAND, cmd); + + pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { + lines = 1; + } + + device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata; + device_vertex = device_sysdata->vhdl; + + intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); + + bit = intr_handle->pi_irq; + cpuid = intr_handle->pi_cpu; + irq = bit_pos_to_irq(bit); + irq = irq + (cpuid << 8); + pciio_intr_connect(intr_handle); + device_dev->irq = irq; +#ifdef ajmtestintr + { + int slot = PCI_SLOT(device_dev->devfn); + static int timer_set = 0; + pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + extern void intr_test_handle_intr(int, void*, struct pt_regs *); + + if (!timer_set) { + intr_test_set_timer(); + timer_set = 1; + } + intr_test_register_irq(irq, pcibr_soft, slot); + request_irq(irq, intr_test_handle_intr,0,NULL, NULL); + } +#endif + + } +} + +/* + * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. + * + * Linux PCI Bus numbers are assigned from lowest module_id numbers + * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to + * HUB_WIDGET_ID_MIN: + * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. + * + * Given 2 modules 001c01 and 001c02 we get the following mappings: + * 001c01, widgetnum 15 = Bus number 0 + * 001c01, widgetnum 14 = Bus number 1 + * 001c02, widgetnum 15 = Bus number 3 + * 001c02, widgetnum 14 = Bus number 4 + * etc. + * + * The rational for starting Bus Number 0 with Widget number 15 is because + * the system boot disks are always connected via Widget 15 Slot 0 of the + * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 + * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest + * module id(Master Cnode) of the system. + * + */ +static int +pci_bus_map_create(devfs_handle_t xtalk) +{ + + devfs_handle_t master_node_vertex = NULL; + devfs_handle_t xwidget = NULL; + devfs_handle_t pci_bus = NULL; + hubinfo_t hubinfo = NULL; + xwidgetnum_t widgetnum; + char pathname[128]; + graph_error_t rv; + + /* + * Loop throught this vertex and get the Xwidgets .. + */ + for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { + +#if 0 + { + int pos; + char dname[256]; + pos = devfs_generate_path(xtalk, dname, 256); + printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); + } +#endif + + sprintf(pathname, "%d", widgetnum); + xwidget = NULL; + + /* + * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget + * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device + */ + rv = hwgraph_traverse(xtalk, pathname, &xwidget); + if ( (rv != GRAPH_SUCCESS) ) { + if (!xwidget) { + continue; +} + } + + sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); + pci_bus = NULL; + if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) + if (!pci_bus) { + continue; +} + + /* + * Assign the correct bus number and also the nasid of this + * pci Xwidget. + * + * Should not be any race here ... + */ + num_bridges++; + busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; + + /* + * Get the master node and from there get the NASID. + */ + master_node_vertex = device_master_get(xwidget); + if (!master_node_vertex) { + printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); + } + + hubinfo_get(master_node_vertex, &hubinfo); + if (!hubinfo) { + printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); + return(1); + } else { + busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; + } + + /* + * Pre assign DMA maps needed for 32 Bits Page Map DMA. + */ + busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); + if (!busnum_to_atedmamaps[num_bridges - 1]) + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); + + memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); + + } + + return(0); +} + +/* + * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure + * initialization has completed to set up the mappings between Xbridge + * and logical pci bus numbers. We also set up the NASID for each of these + * xbridges. + * + * Must be called before pci_init() is invoked. + */ +int +pci_bus_to_hcl_cvlink(void) +{ + + devfs_handle_t devfs_hdl = NULL; + devfs_handle_t xtalk = NULL; + int rv = 0; + char name[256]; + int master_iobrick; + int i; + + /* + * Iterate throught each xtalk links in the system .. + * /hw/module/001c01/node/xtalk/ 8|9|10|11|12|13|14|15 + * + * /hw/module/001c01/node/xtalk/15 -> /hw/module/001c01/Ibrick/xtalk/15 + * + * What if it is not pci? + */ + devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); + + /* + * To provide consistent(not persistent) device naming, we need to start + * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 + * with an attached I-Brick. Find the master_iobrick. + */ + master_iobrick = -1; + for (i = 0; i < nummodules; i++) { + moduleid_t iobrick_id; + iobrick_id = iobrick_module_get(&modules[i]->elsc); + if (iobrick_id > 0) { /* Valid module id */ + if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) { + master_iobrick = i; + break; + } + } + } + + /* + * The master_iobrick gets bus 0 and 1. + */ + if (master_iobrick >= 0) { + memset(name, 0, 256); + format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF); + strcat(name, "/node/xtalk"); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); + pci_bus_map_create(xtalk); + } + + /* + * Now go do the rest of the modules, starting from the C-Brick with the lowest + * module id, remembering to skip the master_iobrick, which was done above. + */ + for (i = 0; i < nummodules; i++) { + if (i == master_iobrick) { + continue; /* Did the master_iobrick already. */ + } + + memset(name, 0, 256); + format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); + strcat(name, "/node/xtalk"); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); + pci_bus_map_create(xtalk); + } + + return(0); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/pcibr.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/pcibr.c --- linux-2.4.19/arch/ia64/sn/io/sn1/pcibr.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/pcibr.c Mon Dec 30 14:16:56 2002 @@ -3,13 +3,12 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ int NeedXbridgeSwap = 0; #include -#include #include #include #include @@ -332,7 +331,6 @@ extern void rmfree(struct map *mp, size_t size, uint64_t a); extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); extern long atoi(register char *p); -extern void *swap_ptr(void **loc, void *new); extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); extern graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr); @@ -1628,243 +1626,6 @@ "BAD"}; -#ifdef LATER - -void -pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, - int func, - pcibr_slot_func_info_resp_t funcp) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - int win; - - funcp->resp_f_status = 0; - - if (!pcibr_info) { - return; - } - - funcp->resp_f_status |= FUNC_IS_VALID; -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); -#else - sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex); -#endif - - if(is_sys_critical_vertex(pcibr_info->f_vertex)) { - funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; - } - - funcp->resp_f_bus = pcibr_info->f_bus; - funcp->resp_f_slot = pcibr_info->f_slot; - funcp->resp_f_func = pcibr_info->f_func; -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master); -#else - sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master); -#endif - funcp->resp_f_pops = pcibr_info->f_pops; - funcp->resp_f_efunc = pcibr_info->f_efunc; - funcp->resp_f_einfo = pcibr_info->f_einfo; - - funcp->resp_f_vendor = pcibr_info->f_vendor; - funcp->resp_f_device = pcibr_info->f_device; - - for(win = 0 ; win < 6 ; win++) { - funcp->resp_f_window[win].resp_w_base = - pcibr_info->f_window[win].w_base; - funcp->resp_f_window[win].resp_w_size = - pcibr_info->f_window[win].w_size; - sprintf(funcp->resp_f_window[win].resp_w_space, - "%s", - pci_space_name[pcibr_info->f_window[win].w_space]); - } - - funcp->resp_f_rbase = pcibr_info->f_rbase; - funcp->resp_f_rsize = pcibr_info->f_rsize; - - for (win = 0 ; win < 4; win++) { - funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win]; - } - - funcp->resp_f_att_det_error = pcibr_info->f_att_det_error; - -} - -int -pcibr_slot_info_return(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - pcibr_slot_info_resp_t respp) -{ - pcibr_soft_slot_t pss; - int func; - bridge_t *bridge = pcibr_soft->bs_base; - reg_p b_respp; - pcibr_slot_info_resp_t slotp; - pcibr_slot_func_info_resp_t funcp; - - slotp = snia_kmem_zalloc(sizeof(*slotp), KM_SLEEP); - if (slotp == NULL) { - return(ENOMEM); - } - - pss = &pcibr_soft->bs_slot[slot]; - - printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot); - - slotp->resp_has_host = pss->has_host; - slotp->resp_host_slot = pss->host_slot; -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn); -#else - sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn); -#endif - slotp->resp_slot_status = pss->slot_status; - slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl); - - if (is_sys_critical_vertex(pss->slot_conn)) { - slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; - } - - slotp->resp_bss_ninfo = pss->bss_ninfo; - - for (func = 0; func < pss->bss_ninfo; func++) { - funcp = &(slotp->resp_func[func]); - pcibr_slot_func_info_return(pss->bss_infos, func, funcp); - } - - sprintf(slotp->resp_bss_devio_bssd_space, "%s", - pci_space_name[pss->bss_devio.bssd_space]); - slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base; - slotp->resp_bss_device = pss->bss_device; - - slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr; - slotp->resp_bss_d32_uctr = pss->bss_d32_uctr; - slotp->resp_bss_d64_uctr = pss->bss_d64_uctr; - - slotp->resp_bss_d64_base = pss->bss_d64_base; - slotp->resp_bss_d64_flags = pss->bss_d64_flags; - slotp->resp_bss_d32_base = pss->bss_d32_base; - slotp->resp_bss_d32_flags = pss->bss_d32_flags; - - slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active); - - slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer; - slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow; - - slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot]; - slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]; - slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot]; - - if (slot & 1) { - b_respp = &bridge->b_odd_resp; - } else { - b_respp = &bridge->b_even_resp; - } - - slotp->resp_b_resp = *b_respp; - - slotp->resp_b_int_device = bridge->b_int_device; - slotp->resp_b_int_enable = bridge->b_int_enable; - slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; - - if (COPYOUT(slotp, respp, sizeof(*respp))) { - return(EFAULT); - } - - snia_kmem_free(slotp, sizeof(*slotp)); - - return(0); -} - -/* - * pcibr_slot_query - * Return information about the PCI slot maintained by the infrastructure. - * Information is requested in the request structure. - * - * Information returned in the response structure: - * Slot hwgraph name - * Vendor/Device info - * Base register info - * Interrupt mapping from device pins to the bridge pins - * Devio register - * Software RRB info - * RRB register info - * Host/Gues info - * PCI Bus #,slot #, function # - * Slot provider hwgraph name - * Provider Functions - * Error handler - * DMA mapping usage counters - * DMA direct translation info - * External SSRAM workaround info - */ -int -pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pciio_slot_t slot = reqp->req_slot; - pciio_slot_t tmp_slot; - pcibr_slot_info_resp_t respp = (pcibr_slot_info_resp_t) reqp->req_respp; - int size = reqp->req_size; - int error; - - /* Make sure that we are dealing with a bridge device vertex */ - if (!pcibr_soft) { - return(EINVAL); - } - - /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ - if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) { - return(EINVAL); - } - - /* Return information for the requested PCI slot */ - if (slot != PCIIO_SLOT_NONE) { - if (size < sizeof(*respp)) { - return(EINVAL); - } - - /* Acquire read access to the slot */ - mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO); - - error = pcibr_slot_info_return(pcibr_soft, slot, respp); - - /* Release the slot lock */ - mrunlock(pcibr_soft->bs_slot[slot].slot_lock); - - return(error); - } - - /* Return information for all the slots */ - for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) { - - if (size < sizeof(*respp)) { - return(EINVAL); - } - - /* Acquire read access to the slot */ - mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO); - - error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp); - - /* Release the slot lock */ - mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock); - - if (error) { - return(error); - } - - ++respp; - size -= sizeof(*respp); - } - - return(error); -} -#endif /* LATER */ - - /*ARGSUSED */ int pcibr_ioctl(devfs_handle_t dev, @@ -3617,7 +3378,7 @@ self->bl_soft = pcibr_soft; self->bl_vhdl = pcibr_vhdl; self->bl_next = pcibr_list; - self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self); + pcibr_list = self; } #endif @@ -6455,9 +6216,7 @@ intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); -#if defined(CONFIG_IA64_SGI_SN1) REMOTE_CPU_SEND_INTR(cpu, intr_bit); -#endif } } @@ -6822,13 +6581,8 @@ bridgereg_t *int_addr = (bridgereg_t *) xtalk_intr_sfarg_get(xtalk_intr); -#ifdef CONFIG_IA64_SGI_SN2 - *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 26)) | - (BRIDGE_INT_ADDR_FLD & vect)); -#elif CONFIG_IA64_SGI_SN1 *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | (BRIDGE_INT_ADDR_FLD & vect)); -#endif } /*ARGSUSED */ diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/pciio.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/pciio.c --- linux-2.4.19/arch/ia64/sn/io/sn1/pciio.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/pciio.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1681 @@ +/* $Id: pciio.c,v 1.3 2002/12/30 22:16:56 jh Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#define USRPCI 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Must be before iograph.h to get MAX_PORT_NUM */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +#define DEBUG_PCIIO +#undef DEBUG_PCIIO /* turn this on for yet more console output */ + + +#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) +#define DO_DEL(ptr) (kfree(ptr)) + +char pciio_info_fingerprint[] = "pciio_info"; + +cdl_p pciio_registry = NULL; + +int +badaddr_val(volatile void *addr, int len, volatile void *ptr) +{ + int ret = 0; + volatile void *new_addr; + + switch (len) { + case 4: + new_addr = (void *)(((u64) addr)^4); + ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); + break; + default: + printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); + } + + if (ret < 0) + panic("badaddr_val: unexpected status (%d) in probing", ret); + return(ret); + +} + + +nasid_t +get_console_nasid(void) +{ + extern nasid_t console_nasid; + if (console_nasid < 0) { + console_nasid = ia64_sn_get_console_nasid(); + if (console_nasid < 0) { +// ZZZ What do we do if we don't get a console nasid on the hardware???? + if (IS_RUNNING_ON_SIMULATOR() ) + console_nasid = master_nasid; + } + } + return console_nasid; +} + +int +hub_dma_enabled(devfs_handle_t xconn_vhdl) +{ + return(0); +} + +int +hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) +{ + return(0); +} + +void +ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror) +{ +} + +/****** + ****** end hack defines ...... + ******/ + + + + +/* ===================================================================== + * PCI Generic Bus Provider + * Implement PCI provider operations. The pciio* layer provides a + * platform-independent interface for PCI devices. This layer + * switches among the possible implementations of a PCI adapter. + */ + +/* ===================================================================== + * Provider Function Location SHORTCUT + * + * On platforms with only one possible PCI provider, macros can be + * set up at the top that cause the table lookups and indirections to + * completely disappear. + */ + +/* + * For the moment, we will assume that IP27 + * only use Bridge ASICs to provide PCI support. + */ +#include +#define DEV_FUNC(dev,func) pcibr_##func +#define CAST_PIOMAP(x) ((pcibr_piomap_t)(x)) +#define CAST_DMAMAP(x) ((pcibr_dmamap_t)(x)) +#define CAST_INTR(x) ((pcibr_intr_t)(x)) + +/* ===================================================================== + * Function Table of Contents + */ + +#if !defined(DEV_FUNC) +static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev); +#endif + +pciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +void pciio_piomap_free(pciio_piomap_t); +caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t); + +void pciio_piomap_done(pciio_piomap_t); +caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); + +iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); +void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); + +pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +void pciio_dmamap_free(pciio_dmamap_t); +iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); +alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned); +void pciio_dmamap_done(pciio_dmamap_t); +iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +void pciio_dmamap_drain(pciio_dmamap_t); +void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); +void pciio_dmalist_drain(devfs_handle_t, alenlist_t); +iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); + +pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +void pciio_intr_free(pciio_intr_t); +int pciio_intr_connect(pciio_intr_t); +void pciio_intr_disconnect(pciio_intr_t); +devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); + +void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); + +void pciio_provider_startup(devfs_handle_t); +void pciio_provider_shutdown(devfs_handle_t); + +pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); +pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t); +devfs_handle_t pciio_intr_dev_get(pciio_intr_t); + +devfs_handle_t pciio_pio_dev_get(pciio_piomap_t); +pciio_slot_t pciio_pio_slot_get(pciio_piomap_t); +pciio_space_t pciio_pio_space_get(pciio_piomap_t); +iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t); +ulong pciio_pio_mapsz_get(pciio_piomap_t); +caddr_t pciio_pio_kvaddr_get(pciio_piomap_t); + +devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t); +pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t); + +pciio_info_t pciio_info_chk(devfs_handle_t); +pciio_info_t pciio_info_get(devfs_handle_t); +void pciio_info_set(devfs_handle_t, pciio_info_t); +devfs_handle_t pciio_info_dev_get(pciio_info_t); +pciio_slot_t pciio_info_slot_get(pciio_info_t); +pciio_function_t pciio_info_function_get(pciio_info_t); +pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t); +pciio_device_id_t pciio_info_device_id_get(pciio_info_t); +devfs_handle_t pciio_info_master_get(pciio_info_t); +arbitrary_info_t pciio_info_mfast_get(pciio_info_t); +pciio_provider_t *pciio_info_pops_get(pciio_info_t); +error_handler_f *pciio_info_efunc_get(pciio_info_t); +error_handler_arg_t *pciio_info_einfo_get(pciio_info_t); +pciio_space_t pciio_info_bar_space_get(pciio_info_t, int); +iopaddr_t pciio_info_bar_base_get(pciio_info_t, int); +size_t pciio_info_bar_size_get(pciio_info_t, int); +iopaddr_t pciio_info_rom_base_get(pciio_info_t); +size_t pciio_info_rom_size_get(pciio_info_t); + +void pciio_init(void); +int pciio_attach(devfs_handle_t); + +void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns); +void pciio_provider_unregister(devfs_handle_t); +pciio_provider_t *pciio_provider_fns_get(devfs_handle_t); + +int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned); +void pciio_driver_unregister(char *driver_prefix); + +devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); + +void pciio_device_unregister(devfs_handle_t); +pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +void pciio_device_info_free(pciio_info_t); +devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); +void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); +int pciio_device_attach(devfs_handle_t, int); +int pciio_device_detach(devfs_handle_t, int); +void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); + +int pciio_reset(devfs_handle_t); +int pciio_write_gather_flush(devfs_handle_t); +int pciio_slot_inuse(devfs_handle_t); + +/* ===================================================================== + * Provider Function Location + * + * If there is more than one possible provider for + * this platform, we need to examine the master + * vertex of the current vertex for a provider + * function structure, and indirect through the + * appropriately named member. + */ + +#if !defined(DEV_FUNC) + +static pciio_provider_t * +pciio_to_provider_fns(devfs_handle_t dev) +{ + pciio_info_t card_info; + pciio_provider_t *provider_fns; + + /* + * We're called with two types of vertices, one is + * the bridge vertex (ends with "pci") and the other is the + * pci slot vertex (ends with "pci/[0-8]"). For the first type + * we need to get the provider from the PFUNCS label. For + * the second we get it from fastinfo/c_pops. + */ + provider_fns = pciio_provider_fns_get(dev); + if (provider_fns == NULL) { + card_info = pciio_info_get(dev); + if (card_info != NULL) { + provider_fns = pciio_info_pops_get(card_info); + } + } + + if (provider_fns == NULL) +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_PANIC("%v: provider_fns == NULL", dev); +#else + PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev); +#endif + + return provider_fns; + +} + +#define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func +#define CAST_PIOMAP(x) ((pciio_piomap_t)(x)) +#define CAST_DMAMAP(x) ((pciio_dmamap_t)(x)) +#define CAST_INTR(x) ((pciio_intr_t)(x)) +#endif + +/* + * Many functions are not passed their vertex + * information directly; rather, they must + * dive through a resource map. These macros + * are available to coordinate this detail. + */ +#define PIOMAP_FUNC(map,func) DEV_FUNC((map)->pp_dev,func) +#define DMAMAP_FUNC(map,func) DEV_FUNC((map)->pd_dev,func) +#define INTR_FUNC(intr_hdl,func) DEV_FUNC((intr_hdl)->pi_dev,func) + +/* ===================================================================== + * PIO MANAGEMENT + * + * For mapping system virtual address space to + * pciio space on a specified card + */ + +pciio_piomap_t +pciio_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ + iopaddr_t addr, /* lowest address (or offset in window) */ + size_t byte_count, /* size of region containing our mappings */ + size_t byte_count_max, /* maximum size of a mapping */ + unsigned flags) +{ /* defined in sys/pio.h */ + return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc) + (dev, dev_desc, space, addr, byte_count, byte_count_max, flags); +} + +void +pciio_piomap_free(pciio_piomap_t pciio_piomap) +{ + PIOMAP_FUNC(pciio_piomap, piomap_free) + (CAST_PIOMAP(pciio_piomap)); +} + +caddr_t +pciio_piomap_addr(pciio_piomap_t pciio_piomap, /* mapping resources */ + iopaddr_t pciio_addr, /* map for this pciio address */ + size_t byte_count) +{ /* map this many bytes */ + pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr) + (CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count); + + return pciio_piomap->pp_kvaddr; +} + +void +pciio_piomap_done(pciio_piomap_t pciio_piomap) +{ + PIOMAP_FUNC(pciio_piomap, piomap_done) + (CAST_PIOMAP(pciio_piomap)); +} + +caddr_t +pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ + iopaddr_t addr, /* starting address (or offset in window) */ + size_t byte_count, /* map this many bytes */ + unsigned flags) +{ /* (currently unused) */ + return DEV_FUNC(dev, piotrans_addr) + (dev, dev_desc, space, addr, byte_count, flags); +} + +caddr_t +pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ + iopaddr_t addr, /* starting address (or offset in window) */ + size_t byte_count, /* map this many bytes */ + pciio_piomap_t *mapp, /* where to return the map pointer */ + unsigned flags) +{ /* PIO flags */ + pciio_piomap_t map = 0; + int errfree = 0; + caddr_t res; + + if (mapp) { + map = *mapp; /* possible pre-allocated map */ + *mapp = 0; /* record "no map used" */ + } + + res = pciio_piotrans_addr + (dev, dev_desc, space, addr, byte_count, flags); + if (res) + return res; /* pciio_piotrans worked */ + + if (!map) { + map = pciio_piomap_alloc + (dev, dev_desc, space, addr, byte_count, byte_count, flags); + if (!map) + return res; /* pciio_piomap_alloc failed */ + errfree = 1; + } + + res = pciio_piomap_addr + (map, addr, byte_count); + if (!res) { + if (errfree) + pciio_piomap_free(map); + return res; /* pciio_piomap_addr failed */ + } + if (mapp) + *mapp = map; /* pass back map used */ + + return res; /* pciio_piomap_addr succeeded */ +} + +iopaddr_t +pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ + device_desc_t dev_desc, /* Device descriptor */ + pciio_space_t space, /* MEM32/MEM64/IO */ + size_t byte_count, /* Size of mapping */ + size_t align) +{ /* Alignment needed */ + if (align < NBPP) + align = NBPP; + return DEV_FUNC(dev, piospace_alloc) + (dev, dev_desc, space, byte_count, align); +} + +void +pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ + pciio_space_t space, /* Type of space */ + iopaddr_t pciaddr, /* starting address */ + size_t byte_count) +{ /* Range of address */ + DEV_FUNC(dev, piospace_free) + (dev, space, pciaddr, byte_count); +} + +/* ===================================================================== + * DMA MANAGEMENT + * + * For mapping from pci space to system + * physical space. + */ + +pciio_dmamap_t +pciio_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ + device_desc_t dev_desc, /* device descriptor */ + size_t byte_count_max, /* max size of a mapping */ + unsigned flags) +{ /* defined in dma.h */ + return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) + (dev, dev_desc, byte_count_max, flags); +} + +void +pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_free) + (CAST_DMAMAP(pciio_dmamap)); +} + +iopaddr_t +pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ + paddr_t paddr, /* map for this address */ + size_t byte_count) +{ /* map this many bytes */ + return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) + (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); +} + +alenlist_t +pciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ + alenlist_t alenlist, /* map this Address/Length List */ + unsigned flags) +{ + return DMAMAP_FUNC(pciio_dmamap, dmamap_list) + (CAST_DMAMAP(pciio_dmamap), alenlist, flags); +} + +void +pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_done) + (CAST_DMAMAP(pciio_dmamap)); +} + +iopaddr_t +pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_addr) + (dev, dev_desc, paddr, byte_count, flags); +} + +alenlist_t +pciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + alenlist_t palenlist, /* system address/length list */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_list) + (dev, dev_desc, palenlist, flags); +} + +iopaddr_t +pciio_dma_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + pciio_dmamap_t *mapp, /* map to use, then map we used */ + unsigned flags) +{ /* PIO flags */ + pciio_dmamap_t map = 0; + int errfree = 0; + iopaddr_t res; + + if (mapp) { + map = *mapp; /* possible pre-allocated map */ + *mapp = 0; /* record "no map used" */ + } + + res = pciio_dmatrans_addr + (dev, dev_desc, paddr, byte_count, flags); + if (res) + return res; /* pciio_dmatrans worked */ + + if (!map) { + map = pciio_dmamap_alloc + (dev, dev_desc, byte_count, flags); + if (!map) + return res; /* pciio_dmamap_alloc failed */ + errfree = 1; + } + + res = pciio_dmamap_addr + (map, paddr, byte_count); + if (!res) { + if (errfree) + pciio_dmamap_free(map); + return res; /* pciio_dmamap_addr failed */ + } + if (mapp) + *mapp = map; /* pass back map used */ + + return res; /* pciio_dmamap_addr succeeded */ +} + +void +pciio_dmamap_drain(pciio_dmamap_t map) +{ + DMAMAP_FUNC(map, dmamap_drain) + (CAST_DMAMAP(map)); +} + +void +pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +{ + DEV_FUNC(dev, dmaaddr_drain) + (dev, addr, size); +} + +void +pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) +{ + DEV_FUNC(dev, dmalist_drain) + (dev, list); +} + +/* ===================================================================== + * INTERRUPT MANAGEMENT + * + * Allow crosstalk devices to establish interrupts + */ + +/* + * Allocate resources required for an interrupt as specified in intr_desc. + * Return resource handle in intr_hdl. + */ +pciio_intr_t +pciio_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_intr_line_t lines, /* INTR line(s) to attach */ + devfs_handle_t owner_dev) +{ /* owner of this interrupt */ + return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) + (dev, dev_desc, lines, owner_dev); +} + +/* + * Free resources consumed by intr_alloc. + */ +void +pciio_intr_free(pciio_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_free) + (CAST_INTR(intr_hdl)); +} + +/* + * Associate resources allocated with a previous pciio_intr_alloc call with the + * described handler, arg, name, etc. + * + * Returns 0 on success, returns <0 on failure. + */ +int +pciio_intr_connect(pciio_intr_t intr_hdl) /* pciio intr resource handle */ +{ + return INTR_FUNC(intr_hdl, intr_connect) + (CAST_INTR(intr_hdl)); +} + +/* + * Disassociate handler with the specified interrupt. + */ +void +pciio_intr_disconnect(pciio_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_disconnect) + (CAST_INTR(intr_hdl)); +} + +/* + * Return a hwgraph vertex that represents the CPU currently + * targeted by an interrupt. + */ +devfs_handle_t +pciio_intr_cpu_get(pciio_intr_t intr_hdl) +{ + return INTR_FUNC(intr_hdl, intr_cpu_get) + (CAST_INTR(intr_hdl)); +} + +void +pciio_slot_func_to_name(char *name, + pciio_slot_t slot, + pciio_function_t func) +{ + /* + * standard connection points: + * + * PCIIO_SLOT_NONE: .../pci/direct + * PCIIO_FUNC_NONE: .../pci/ ie. .../pci/3 + * multifunction: .../pci/ ie. .../pci/3c + */ + + if (slot == PCIIO_SLOT_NONE) + sprintf(name, EDGE_LBL_DIRECT); + else if (func == PCIIO_FUNC_NONE) + sprintf(name, "%d", slot); + else + sprintf(name, "%d%c", slot, 'a'+func); +} + +/* ===================================================================== + * CONFIGURATION MANAGEMENT + */ + +/* + * Startup a crosstalk provider + */ +void +pciio_provider_startup(devfs_handle_t pciio_provider) +{ + DEV_FUNC(pciio_provider, provider_startup) + (pciio_provider); +} + +/* + * Shutdown a crosstalk provider + */ +void +pciio_provider_shutdown(devfs_handle_t pciio_provider) +{ + DEV_FUNC(pciio_provider, provider_shutdown) + (pciio_provider); +} + +/* + * Specify endianness constraints. The driver tells us what the device + * does and how it would like to see things in memory. We reply with + * how things will actually appear in memory. + */ +pciio_endian_t +pciio_endian_set(devfs_handle_t dev, + pciio_endian_t device_end, + pciio_endian_t desired_end) +{ + ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE)); + ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE)); + +#if DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_ALERT "%v: pciio_endian_set is going away.\n" + "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" + "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", + dev); +#else + printk(KERN_ALERT "0x%x: pciio_endian_set is going away.\n" + "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" + "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", + dev); +#endif +#endif + + return DEV_FUNC(dev, endian_set) + (dev, device_end, desired_end); +} + +/* + * Specify PCI arbitration priority. + */ +pciio_priority_t +pciio_priority_set(devfs_handle_t dev, + pciio_priority_t device_prio) +{ + ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); + + return DEV_FUNC(dev, priority_set) + (dev, device_prio); +} + +/* + * Read value of configuration register + */ +uint64_t +pciio_config_get(devfs_handle_t dev, + unsigned reg, + unsigned size) +{ + uint64_t value = 0; + unsigned shift = 0; + + /* handle accesses that cross words here, + * since that's common code between all + * possible providers. + */ + while (size > 0) { + unsigned biw = 4 - (reg&3); + if (biw > size) + biw = size; + + value |= DEV_FUNC(dev, config_get) + (dev, reg, biw) << shift; + + shift += 8*biw; + reg += biw; + size -= biw; + } + return value; +} + +/* + * Change value of configuration register + */ +void +pciio_config_set(devfs_handle_t dev, + unsigned reg, + unsigned size, + uint64_t value) +{ + /* handle accesses that cross words here, + * since that's common code between all + * possible providers. + */ + while (size > 0) { + unsigned biw = 4 - (reg&3); + if (biw > size) + biw = size; + + DEV_FUNC(dev, config_set) + (dev, reg, biw, value); + reg += biw; + size -= biw; + value >>= biw * 8; + } +} + +/* ===================================================================== + * GENERIC PCI SUPPORT FUNCTIONS + */ + +/* + * Issue a hardware reset to a card. + */ +int +pciio_reset(devfs_handle_t dev) +{ + return DEV_FUNC(dev, reset) (dev); +} + +/* + * flush write gather buffers + */ +int +pciio_write_gather_flush(devfs_handle_t dev) +{ + return DEV_FUNC(dev, write_gather_flush) (dev); +} + +devfs_handle_t +pciio_intr_dev_get(pciio_intr_t pciio_intr) +{ + return (pciio_intr->pi_dev); +} + +/****** Generic crosstalk pio interfaces ******/ +devfs_handle_t +pciio_pio_dev_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_dev); +} + +pciio_slot_t +pciio_pio_slot_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_slot); +} + +pciio_space_t +pciio_pio_space_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_space); +} + +iopaddr_t +pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_pciaddr); +} + +ulong +pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_mapsz); +} + +caddr_t +pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_kvaddr); +} + +/****** Generic crosstalk dma interfaces ******/ +devfs_handle_t +pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap) +{ + return (pciio_dmamap->pd_dev); +} + +pciio_slot_t +pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap) +{ + return (pciio_dmamap->pd_slot); +} + +/****** Generic pci slot information interfaces ******/ + +pciio_info_t +pciio_info_chk(devfs_handle_t pciio) +{ + arbitrary_info_t ainfo = 0; + + hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo); + return (pciio_info_t) ainfo; +} + +pciio_info_t +pciio_info_get(devfs_handle_t pciio) +{ + pciio_info_t pciio_info; + + pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio); + +#ifdef DEBUG_PCIIO + { + int pos; + char dname[256]; + pos = devfs_generate_path(pciio, dname, 256); + printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); + } +#endif /* DEBUG_PCIIO */ + + if ((pciio_info != NULL) && + (pciio_info->c_fingerprint != pciio_info_fingerprint) + && (pciio_info->c_fingerprint != NULL)) { + + return((pciio_info_t)-1); /* Should panic .. */ + } + + + return pciio_info; +} + +void +pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) +{ + if (pciio_info != NULL) + pciio_info->c_fingerprint = pciio_info_fingerprint; + hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info); + + /* Also, mark this vertex as a PCI slot + * and use the pciio_info, so pciio_info_chk + * can work (and be fairly efficient). + */ + hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO, + (arbitrary_info_t) pciio_info); +} + +devfs_handle_t +pciio_info_dev_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_vertex); +} + +pciio_slot_t +pciio_info_slot_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_slot); +} + +pciio_function_t +pciio_info_function_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_func); +} + +pciio_vendor_id_t +pciio_info_vendor_id_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_vendor); +} + +pciio_device_id_t +pciio_info_device_id_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_device); +} + +devfs_handle_t +pciio_info_master_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_master); +} + +arbitrary_info_t +pciio_info_mfast_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_mfast); +} + +pciio_provider_t * +pciio_info_pops_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_pops); +} + +error_handler_f * +pciio_info_efunc_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_efunc); +} + +error_handler_arg_t * +pciio_info_einfo_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_einfo); +} + +pciio_space_t +pciio_info_bar_space_get(pciio_info_t info, int win) +{ + return info->c_window[win].w_space; +} + +iopaddr_t +pciio_info_bar_base_get(pciio_info_t info, int win) +{ + return info->c_window[win].w_base; +} + +size_t +pciio_info_bar_size_get(pciio_info_t info, int win) +{ + return info->c_window[win].w_size; +} + +iopaddr_t +pciio_info_rom_base_get(pciio_info_t info) +{ + return info->c_rbase; +} + +size_t +pciio_info_rom_size_get(pciio_info_t info) +{ + return info->c_rsize; +} + + +/* ===================================================================== + * GENERIC PCI INITIALIZATION FUNCTIONS + */ + +/* + * pciioinit: called once during device driver + * initializtion if this driver is configured into + * the system. + */ +void +pciio_init(void) +{ + cdl_p cp; + +#if DEBUG && ATTACH_DEBUG + printf("pciio_init\n"); +#endif + /* Allocate the registry. + * We might already have one. + * If we don't, go get one. + * MPness: someone might have + * set one up for us while we + * were not looking; use an atomic + * compare-and-swap to commit to + * using the new registry if and + * only if nobody else did first. + * If someone did get there first, + * toss the one we allocated back + * into the pool. + */ + if (pciio_registry == NULL) { + cp = cdl_new(EDGE_LBL_PCI, "vendor", "device"); + if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) { + cdl_del(cp); + } + } + ASSERT(pciio_registry != NULL); +} + +/* + * pciioattach: called for each vertex in the graph + * that is a PCI provider. + */ +/*ARGSUSED */ +int +pciio_attach(devfs_handle_t pciio) +{ +#if DEBUG && ATTACH_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: pciio_attach\n", pciio); +#else + printk("0x%x: pciio_attach\n", pciio); +#endif +#endif + return 0; +} + +/* + * Associate a set of pciio_provider functions with a vertex. + */ +void +pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) +{ + hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); +} + +/* + * Disassociate a set of pciio_provider functions with a vertex. + */ +void +pciio_provider_unregister(devfs_handle_t provider) +{ + arbitrary_info_t ainfo; + + hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); +} + +/* + * Obtain a pointer to the pciio_provider functions for a specified Crosstalk + * provider. + */ +pciio_provider_t * +pciio_provider_fns_get(devfs_handle_t provider) +{ + arbitrary_info_t ainfo = 0; + + (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo); + return (pciio_provider_t *) ainfo; +} + +/*ARGSUSED4 */ +int +pciio_driver_register( + pciio_vendor_id_t vendor_id, + pciio_device_id_t device_id, + char *driver_prefix, + unsigned flags) +{ + /* a driver's init routine might call + * pciio_driver_register before the + * system calls pciio_init; so we + * make the init call ourselves here. + */ + if (pciio_registry == NULL) + pciio_init(); + + return cdl_add_driver(pciio_registry, + vendor_id, device_id, + driver_prefix, flags, NULL); +} + +/* + * Remove an initialization function. + */ +void +pciio_driver_unregister( + char *driver_prefix) +{ + /* before a driver calls unregister, + * it must have called register; so + * we can assume we have a registry here. + */ + ASSERT(pciio_registry != NULL); + + cdl_del_driver(pciio_registry, driver_prefix, NULL); +} + +/* + * Set the slot status for a device supported by the + * driver being registered. + */ +void +pciio_driver_reg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ +} + +/* + * Set the slot status for a device supported by the + * driver being unregistered. + */ +void +pciio_driver_unreg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ +} + +/* + * Call some function with each vertex that + * might be one of this driver's attach points. + */ +void +pciio_iterate(char *driver_prefix, + pciio_iter_f * func) +{ + /* a driver's init routine might call + * pciio_iterate before the + * system calls pciio_init; so we + * make the init call ourselves here. + */ + if (pciio_registry == NULL) + pciio_init(); + + ASSERT(pciio_registry != NULL); + + cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func); +} + +devfs_handle_t +pciio_device_register( + devfs_handle_t connectpt, /* vertex for /hw/.../pciio/%d */ + devfs_handle_t master, /* card's master ASIC (PCI provider) */ + pciio_slot_t slot, /* card's slot */ + pciio_function_t func, /* card's func */ + pciio_vendor_id_t vendor_id, + pciio_device_id_t device_id) +{ + return pciio_device_info_register + (connectpt, pciio_device_info_new (NULL, master, slot, func, + vendor_id, device_id)); +} + +void +pciio_device_unregister(devfs_handle_t pconn) +{ + DEV_FUNC(pconn,device_unregister)(pconn); +} + +pciio_info_t +pciio_device_info_new( + pciio_info_t pciio_info, + devfs_handle_t master, + pciio_slot_t slot, + pciio_function_t func, + pciio_vendor_id_t vendor_id, + pciio_device_id_t device_id) +{ + if (!pciio_info) + GET_NEW(pciio_info); + ASSERT(pciio_info != NULL); + + pciio_info->c_slot = slot; + pciio_info->c_func = func; + pciio_info->c_vendor = vendor_id; + pciio_info->c_device = device_id; + pciio_info->c_master = master; + pciio_info->c_mfast = hwgraph_fastinfo_get(master); + pciio_info->c_pops = pciio_provider_fns_get(master); + pciio_info->c_efunc = 0; + pciio_info->c_einfo = 0; + + return pciio_info; +} + +void +pciio_device_info_free(pciio_info_t pciio_info) +{ + /* NOTE : pciio_info is a structure within the pcibr_info + * and not a pointer to memory allocated on the heap !! + */ + BZERO((char *)pciio_info,sizeof(pciio_info)); +} + +devfs_handle_t +pciio_device_info_register( + devfs_handle_t connectpt, /* vertex at center of bus */ + pciio_info_t pciio_info) /* details about the connectpt */ +{ + char name[32]; + devfs_handle_t pconn; + int device_master_set(devfs_handle_t, devfs_handle_t); + + pciio_slot_func_to_name(name, + pciio_info->c_slot, + pciio_info->c_func); + + if (GRAPH_SUCCESS != + hwgraph_path_add(connectpt, name, &pconn)) + return pconn; + + pciio_info->c_vertex = pconn; + pciio_info_set(pconn, pciio_info); +#ifdef DEBUG_PCIIO + { + int pos; + char dname[256]; + pos = devfs_generate_path(pconn, dname, 256); + printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); + } +#endif /* DEBUG_PCIIO */ + + /* + * create link to our pci provider + */ + + device_master_set(pconn, pciio_info->c_master); + +#if USRPCI + /* + * Call into usrpci provider to let it initialize for + * the given slot. + */ + if (pciio_info->c_slot != PCIIO_SLOT_NONE) + usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot); +#endif + + return pconn; +} + +void +pciio_device_info_unregister(devfs_handle_t connectpt, + pciio_info_t pciio_info) +{ + char name[32]; + devfs_handle_t pconn; + + if (!pciio_info) + return; + + pciio_slot_func_to_name(name, + pciio_info->c_slot, + pciio_info->c_func); + + hwgraph_edge_remove(connectpt,name,&pconn); + pciio_info_set(pconn,0); + + /* Remove the link to our pci provider */ + hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); + + + hwgraph_vertex_unref(pconn); + hwgraph_vertex_destroy(pconn); + +} +/* Add the pci card inventory information to the hwgraph + */ +static void +pciio_device_inventory_add(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + + ASSERT(pciio_info); + ASSERT(pciio_info->c_vertex == pconn_vhdl); + + /* Donot add inventory for non-existent devices */ + if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE) || + (pciio_info->c_device == PCIIO_DEVICE_ID_NONE)) + return; + device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP, + pciio_info->c_vendor,pciio_info->c_device, + pciio_info->c_slot); +} + +/*ARGSUSED */ +int +pciio_device_attach(devfs_handle_t pconn, + int drv_flags) +{ + pciio_info_t pciio_info; + pciio_vendor_id_t vendor_id; + pciio_device_id_t device_id; + + + pciio_device_inventory_add(pconn); + pciio_info = pciio_info_get(pconn); + + vendor_id = pciio_info->c_vendor; + device_id = pciio_info->c_device; + + /* we don't start attaching things until + * all the driver init routines (including + * pciio_init) have been called; so we + * can assume here that we have a registry. + */ + ASSERT(pciio_registry != NULL); + + return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); +} + +int +pciio_device_detach(devfs_handle_t pconn, + int drv_flags) +{ + pciio_info_t pciio_info; + pciio_vendor_id_t vendor_id; + pciio_device_id_t device_id; + + pciio_info = pciio_info_get(pconn); + + vendor_id = pciio_info->c_vendor; + device_id = pciio_info->c_device; + + /* we don't start attaching things until + * all the driver init routines (including + * pciio_init) have been called; so we + * can assume here that we have a registry. + */ + ASSERT(pciio_registry != NULL); + + return(cdl_del_connpt(pciio_registry, vendor_id, device_id, + pconn, drv_flags)); + +} + +/* SN2 */ +/* + * Allocate (if necessary) and initialize a PCI window mapping structure. + */ +pciio_win_map_t +pciio_device_win_map_new(pciio_win_map_t win_map, + size_t region_size, + size_t page_size) +{ + ASSERT((page_size & (page_size - 1)) == 0); + ASSERT((region_size & (page_size - 1)) == 0); + + if (win_map == NULL) + NEW(win_map); + + /* + * The map array tracks the free ``pages'' in the region. The worst + * case scenario is when every other page in the region is free -- + * e.i. maximum fragmentation. This leads to (max pages + 1) / 2 + 1 + * map entries. The first "+1" handles the divide by 2 rounding; the + * second handles the need for an end marker sentinel. + */ + win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1); + win_map->wm_page_size = page_size; + ASSERT(win_map->wm_map != NULL); + + return win_map; +} + +/* + * Free resources associated with a PCI window mapping structure. + */ +extern void +pciio_device_win_map_free(pciio_win_map_t win_map) +{ + rmfreemap(win_map->wm_map); + bzero(win_map, sizeof *win_map); +} + +/* + * Populate window map with specified free range. + */ +void +pciio_device_win_populate(pciio_win_map_t win_map, + iopaddr_t ioaddr, + size_t size) +{ + ASSERT((size & (win_map->wm_page_size - 1)) == 0); + ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0); + + rmfree(win_map->wm_map, + size / win_map->wm_page_size, + (unsigned long)ioaddr / win_map->wm_page_size); + +} +/* + * Allocate space from the specified PCI window mapping resource. On + * success record information about the allocation in the supplied window + * allocation cookie (if non-NULL) and return the address of the allocated + * window. On failure return NULL. + * + * The "size" parameter is usually from a PCI device's Base Address Register + * (BAR) decoder. As such, the allocation must be aligned to be a multiple of + * that. The "align" parameter acts as a ``minimum alignment'' allocation + * constraint. The alignment contraint reflects system or device addressing + * restrictions such as the inability to share higher level ``windows'' + * between devices, etc. The returned PCI address allocation will be a + * multiple of the alignment constraint both in alignment and size. Thus, the + * returned PCI address block is aligned to the maximum of the requested size + * and alignment. + */ +iopaddr_t +pciio_device_win_alloc(pciio_win_map_t win_map, + pciio_win_alloc_t win_alloc, + size_t size, size_t align) +{ + unsigned long base; + +#ifdef PIC_LATER + ASSERT((size & (size - 1)) == 0); + ASSERT((align & (align - 1)) == 0); + + /* + * Convert size and alignment to pages. If size is greated than the + * requested alignment, we bump the alignment up to size; otherwise + * convert the size into a multiple of the alignment request. + */ + size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size; + align = align / win_map->wm_page_size; + if (size > align) + align = size; + else + size = (size + align - 1) & ~(align - 1); + + /* XXXX */ + base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP); + if (base == RMALLOC_FAIL) + return((iopaddr_t)NULL); +#else + int index_page, index_page_align; + int align_pages, size_pages; + int alloc_pages, free_pages; + int addr_align; + + /* Convert PCI bus alignment from bytes to pages */ + align_pages = align / win_map->wm_page_size; + + /* Convert PCI request from bytes to pages */ + size_pages = (size / win_map->wm_page_size) + + ((size % win_map->wm_page_size) ? 1 : 0); + + /* Align address with the larger of the size or the requested slot align */ + if (size_pages > align_pages) + align_pages = size_pages; + + /* + * Avoid wasting space by aligning - 1; this will prevent crossing + * another alignment boundary. + */ + alloc_pages = size_pages + (align_pages - 1); + + /* Allocate PCI bus space in pages */ + index_page = (int) rmalloc(win_map->wm_map, + (size_t) alloc_pages); + + /* Error if no PCI bus address space available */ + if (!index_page) + return 0; + + /* PCI bus address index starts at 0 */ + index_page--; + + /* Align the page offset as requested */ + index_page_align = (index_page + (align_pages - 1)) - + ((index_page + (align_pages - 1)) % align_pages); + + free_pages = (align_pages - 1) - (index_page_align - index_page); + + /* Free unused PCI bus pages adjusting the index to start at 1 */ + rmfree(win_map->wm_map, + free_pages, + (index_page_align + 1) + size_pages); + + /* Return aligned PCI bus space in bytes */ + addr_align = (index_page_align * win_map->wm_page_size); + base = index_page; + size = alloc_pages - free_pages; +#endif /* PIC_LATER */ + + /* + * If a window allocation cookie has been supplied, use it to keep + * track of all the allocated space assigned to this window. + */ + if (win_alloc) { + win_alloc->wa_map = win_map; + win_alloc->wa_base = base; + win_alloc->wa_pages = size; + } + + return base * win_map->wm_page_size; +} + +/* + * Free the specified window allocation back into the PCI window mapping + * resource. As noted above, we keep page addresses offset by 1 ... + */ +void +pciio_device_win_free(pciio_win_alloc_t win_alloc) +{ + if (win_alloc->wa_pages) + rmfree(win_alloc->wa_map->wm_map, + win_alloc->wa_pages, + win_alloc->wa_base); +} + +/* + * pciio_error_register: + * arrange for a function to be called with + * a specified first parameter plus other + * information when an error is encountered + * and traced to the pci slot corresponding + * to the connection point pconn. + * + * may also be called with a null function + * pointer to "unregister" the error handler. + * + * NOTE: subsequent calls silently overwrite + * previous data for this vertex. We assume that + * cooperating drivers, well, cooperate ... + */ +void +pciio_error_register(devfs_handle_t pconn, + error_handler_f *efunc, + error_handler_arg_t einfo) +{ + pciio_info_t pciio_info; + + pciio_info = pciio_info_get(pconn); + ASSERT(pciio_info != NULL); + pciio_info->c_efunc = efunc; + pciio_info->c_einfo = einfo; +} + +/* + * Check if any device has been found in this slot, and return + * true or false + * vhdl is the vertex for the slot + */ +int +pciio_slot_inuse(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + + ASSERT(pciio_info); + ASSERT(pciio_info->c_vertex == pconn_vhdl); + if (pciio_info->c_vendor) { + /* + * Non-zero value for vendor indicate + * a board being found in this slot. + */ + return 1; + } + return 0; +} + +int +pciio_dma_enabled(devfs_handle_t pconn_vhdl) +{ + return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); +} + +/* + * These are complementary Linux interfaces that takes in a pci_dev * as the + * first arguement instead of devfs_handle_t. + */ +iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); +pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); +void snia_pciio_dmamap_free(pciio_dmamap_t); +iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); +void snia_pciio_dmamap_done(pciio_dmamap_t); +pciio_endian_t snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, + pciio_endian_t desired_end); + +#include +EXPORT_SYMBOL(snia_pciio_dmatrans_addr); +EXPORT_SYMBOL(snia_pciio_dmamap_alloc); +EXPORT_SYMBOL(snia_pciio_dmamap_free); +EXPORT_SYMBOL(snia_pciio_dmamap_addr); +EXPORT_SYMBOL(snia_pciio_dmamap_done); +EXPORT_SYMBOL(snia_pciio_endian_set); + +int +snia_pcibr_rrb_alloc(struct pci_dev *pci_dev, + int *count_vchan0, + int *count_vchan1) +{ + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1); +} +EXPORT_SYMBOL(snia_pcibr_rrb_alloc); + +pciio_endian_t +snia_pciio_endian_set(struct pci_dev *pci_dev, + pciio_endian_t device_end, + pciio_endian_t desired_end) +{ + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return DEV_FUNC(dev, endian_set) + (dev, device_end, desired_end); +} + +iopaddr_t +snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + unsigned flags) +{ /* defined in dma.h */ + + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return DEV_FUNC(dev, dmatrans_addr) + (dev, dev_desc, paddr, byte_count, flags); +} + +pciio_dmamap_t +snia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this device */ + device_desc_t dev_desc, /* device descriptor */ + size_t byte_count_max, /* max size of a mapping */ + unsigned flags) +{ /* defined in dma.h */ + + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) + (dev, dev_desc, byte_count_max, flags); +} + +void +snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_free) + (CAST_DMAMAP(pciio_dmamap)); +} + +iopaddr_t +snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ + paddr_t paddr, /* map for this address */ + size_t byte_count) +{ /* map this many bytes */ + return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) + (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); +} + +void +snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_done) + (CAST_DMAMAP(pciio_dmamap)); +} + diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/sgi_io_init.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/sgi_io_init.c --- linux-2.4.19/arch/ia64/sn/io/sn1/sgi_io_init.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/sgi_io_init.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,324 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void mlreset(int ); +extern int init_hcl(void); +extern void klgraph_hack_init(void); +extern void hubspc_init(void); +extern void pciio_init(void); +extern void pcibr_init(void); +extern void xtalk_init(void); +extern void xbow_init(void); +extern void xbmon_init(void); +extern void pciiox_init(void); +extern void usrpci_init(void); +extern void ioc3_init(void); +extern void initialize_io(void); +extern void intr_clear_all(nasid_t); +extern void klhwg_add_all_modules(devfs_handle_t); +extern void klhwg_add_all_nodes(devfs_handle_t); + +void sn_mp_setup(void); +extern devfs_handle_t hwgraph_root; +extern void io_module_init(void); +extern void pci_bus_cvlink_init(void); +extern void temp_hack(void); + +extern int pci_bus_to_hcl_cvlink(void); + +/* #define DEBUG_IO_INIT 1 */ +#ifdef DEBUG_IO_INIT +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG_IO_INIT */ + +/* + * per_hub_init + * + * This code is executed once for each Hub chip. + */ +static void +per_hub_init(cnodeid_t cnode) +{ + nasid_t nasid; + nodepda_t *npdap; + ii_icmr_u_t ii_icmr; + ii_ibcr_u_t ii_ibcr; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + ASSERT(nasid != INVALID_NASID); + ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); + + npdap = NODEPDA(cnode); + + /* initialize per-node synergy perf instrumentation */ + npdap->synergy_perf_enabled = 0; /* off by default */ + npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; + npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; + npdap->synergy_inactive_intervals = 0; + npdap->synergy_active_intervals = 0; + npdap->synergy_perf_data = NULL; + npdap->synergy_perf_first = NULL; + + + /* + * Set the total number of CRBs that can be used. + */ + ii_icmr.ii_icmr_regval= 0x0; + ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF; + REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); + + /* + * Set the number of CRBs that both of the BTEs combined + * can use minus 1. + */ + ii_ibcr.ii_ibcr_regval= 0x0; + ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; + REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); + + /* + * Set CRB timeout to be 10ms. + */ + REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 ); + REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); + + + /* Reserve all of the hardwired interrupt levels. */ + intr_reserve_hardwired(cnode); + + /* Initialize error interrupts for this hub. */ + hub_error_init(cnode); +} + +/* + * This routine is responsible for the setup of all the IRIX hwgraph style + * stuff that's been pulled into linux. It's called by sn_pci_find_bios which + * is called just before the generic Linux PCI layer does its probing (by + * platform_pci_fixup aka sn_pci_fixup). + * + * It is very IMPORTANT that this call is only made by the Master CPU! + * + */ + +void +sgi_master_io_infr_init(void) +{ + int cnode; + + /* + * Do any early init stuff .. einit_tbl[] etc. + */ + DBG("--> sgi_master_io_infr_init: calling init_hcl().\n"); + init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ + +#ifdef Colin + +printk("Testing out Xbridge Access .. if it hangs Xbridge is not init yet.\n"); +printk(" Reading Xbridge WID at address 0xc00000080f000000 0x%p\n", (* (volatile uint32_t *)(0xc00000080f000000))); + +printk("Testing out PCI Address Space Accesses\n"); +printk(" Testing PCI Config Read Byte: address 0xc00000080f020000 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020000))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020001 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020001))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020002 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020002))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020003 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020003))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020004))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020005 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020005))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020006 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020006))); + +printk(" Testing PCI Config Read Byte: address 0xc00000080f020007 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020007))); + +printk(" Testing PCI Config Word: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020004))); + +printk(" Testing PCI Config Word: address 0xc00000080f020008 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020008))); + +#endif + + /* + * initialize the Linux PCI to xwidget vertexes .. + */ + DBG("--> sgi_master_io_infr_init: calling pci_bus_cvlink_init().\n"); + pci_bus_cvlink_init(); + +#ifdef BRINGUP + /* + * Hack to provide statically initialzed klgraph entries. + */ + DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); + klgraph_hack_init(); +#endif /* BRINGUP */ + + /* + * This is the Master CPU. Emulate mlsetup and main.c in Irix. + */ + DBG("--> sgi_master_io_infr_init: calling mlreset(0).\n"); + mlreset(0); /* Master .. */ + + /* + * allowboot() is called by kern/os/main.c in main() + * Emulate allowboot() ... + * per_cpu_init() - only need per_hub_init() + * cpu_io_setup() - Nothing to do. + * + */ + DBG("--> sgi_master_io_infr_init: calling sn_mp_setup().\n"); + sn_mp_setup(); + + DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n"); + for (cnode = 0; cnode < numnodes; cnode++) { + per_hub_init(cnode); + } + + /* We can do headless hub cnodes here .. */ + + /* + * io_init[] stuff. + * + * Get SGI IO Infrastructure drivers to init and register with + * each other etc. + */ + + DBG("--> sgi_master_io_infr_init: calling hubspc_init()\n"); + hubspc_init(); + + DBG("--> sgi_master_io_infr_init: calling pciio_init()\n"); + pciio_init(); + + DBG("--> sgi_master_io_infr_init: calling pcibr_init()\n"); + pcibr_init(); + + DBG("--> sgi_master_io_infr_init: calling xtalk_init()\n"); + xtalk_init(); + + DBG("--> sgi_master_io_infr_init: calling xbow_init()\n"); + xbow_init(); + + DBG("--> sgi_master_io_infr_init: calling xbmon_init()\n"); + xbmon_init(); + + DBG("--> sgi_master_io_infr_init: calling pciiox_init()\n"); + pciiox_init(); + + DBG("--> sgi_master_io_infr_init: calling usrpci_init()\n"); + usrpci_init(); + + DBG("--> sgi_master_io_infr_init: calling ioc3_init()\n"); + ioc3_init(); + + /* + * + * Our IO Infrastructure drivers are in place .. + * Initialize the whole IO Infrastructure .. xwidget/device probes. + * + */ + DBG("--> sgi_master_io_infr_init: Start Probe and IO Initialization\n"); + initialize_io(); + + DBG("--> sgi_master_io_infr_init: Setting up SGI IO Links for Linux PCI\n"); + pci_bus_to_hcl_cvlink(); + +#ifdef CONFIG_PCIBA + DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); + pciba_init(); +#endif + + DBG("--> Leave sgi_master_io_infr_init: DONE setting up SGI Links for PCI\n"); +} + +/* + * sgi_slave_io_infr_init - This routine must be called on all cpus except + * the Master CPU. + */ +void +sgi_slave_io_infr_init(void) +{ + /* Emulate cboot() .. */ + mlreset(1); /* This is a slave cpu */ + + // per_hub_init(0); /* Need to get and send in actual cnode number */ + + /* Done */ +} + +/* + * One-time setup for MP SN. + * Allocate per-node data, slurp prom klconfig information and + * convert it to hwgraph information. + */ +void +sn_mp_setup(void) +{ + cnodeid_t cnode; + cpuid_t cpu; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + /* Skip holes in CPU space */ + if (cpu_enabled(cpu)) { + init_platform_pda(cpu); + } + } + + /* + * Initialize platform-dependent vertices in the hwgraph: + * module + * node + * cpu + * memory + * slot + * hub + * router + * xbow + */ + + DBG("sn_mp_io_setup: calling io_module_init()\n"); + io_module_init(); /* Use to be called module_init() .. */ + + DBG("sn_mp_setup: calling klhwg_add_all_modules()\n"); + klhwg_add_all_modules(hwgraph_root); + DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n"); + klhwg_add_all_nodes(hwgraph_root); + + + for (cnode = 0; cnode < numnodes; cnode++) { + + /* + * This routine clears the Hub's Interrupt registers. + */ + /* + * We need to move this intr_clear_all() routine + * from SN/intr.c to a more appropriate file. + * Talk to Al Mayer. + */ + intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); + /* now init the hub */ + // per_hub_init(cnode); + + } + + synergy_perf_init(); + +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/xbow.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/xbow.c --- linux-2.4.19/arch/ia64/sn/io/sn1/xbow.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/xbow.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1086 @@ +/* $Id: xbow.c,v 1.4 2002/12/30 22:16:56 jh Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define DEBUG 1 */ +/* #define XBOW_DEBUG 1 */ + + +/* + * Files needed to get the device driver entry points + */ + +#include +#include +#include +#include + +#include +#include + + +#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) +#define DEL(ptr) (kfree(ptr)) + +int xbow_devflag = D_MP; + +/* + * This file supports the Xbow chip. Main functions: initializtion, + * error handling, and GBR. + */ + +/* + * each vertex corresponding to an xbow chip + * has a "fastinfo" pointer pointing at one + * of these things. + */ +typedef struct xbow_soft_s *xbow_soft_t; + +struct xbow_soft_s { + devfs_handle_t conn; /* our connection point */ + devfs_handle_t vhdl; /* xbow's private vertex */ + devfs_handle_t busv; /* the xswitch vertex */ + xbow_t *base; /* PIO pointer to crossbow chip */ + char *name; /* hwgraph name */ + + xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; + xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; + xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; + spinlock_t xbow_perf_lock; + int link_monitor; + widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ + + /* Bandwidth allocation state. Bandwidth values are for the + * destination port since contention happens there. + * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. + */ + spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ + unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ + unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ +}; + +#define xbow_soft_set(v,i) hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)) +#define xbow_soft_get(v) ((xbow_soft_t)hwgraph_fastinfo_get((v))) + +/* + * Function Table of Contents + */ + +void xbow_mlreset(xbow_t *); +void xbow_init(void); +int xbow_attach(devfs_handle_t); + +int xbow_open(devfs_handle_t *, int, int, cred_t *); +int xbow_close(devfs_handle_t, int, int, cred_t *); + +int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); +int xbow_unmap(devfs_handle_t, vhandl_t *); +int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); + +int xbow_widget_present(xbow_t *, int); +static int xbow_link_alive(xbow_t *, int); +devfs_handle_t xbow_widget_lookup(devfs_handle_t, int); + +void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); + + + +void xbow_update_perf_counters(devfs_handle_t); +xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); +int xbow_enable_perf_counter(devfs_handle_t, int, int, int); +xbow_link_status_t *xbow_get_llp_status(devfs_handle_t); +void xbow_update_llp_status(devfs_handle_t); + +int xbow_disable_llp_monitor(devfs_handle_t); +int xbow_enable_llp_monitor(devfs_handle_t); +int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, + unsigned long long, unsigned long long); + +xswitch_reset_link_f xbow_reset_link; + +void idbg_xbowregs(int64_t); + +xswitch_provider_t xbow_provider = +{ + xbow_reset_link, +}; + +/* + * xbow_mlreset: called at mlreset time if the + * platform specific code determines that there is + * a crossbow in a critical path that must be + * functional before the driver would normally get + * the device properly set up. + * + * what do we need to do, that the boot prom can + * not be counted on to have already done, that is + * generic across all platforms using crossbows? + */ +/*ARGSUSED */ +void +xbow_mlreset(xbow_t * xbow) +{ +} + +/* + * xbow_init: called with the rest of the device + * driver XXX_init routines. This platform *might* + * have a Crossbow chip, or even several, but it + * might have none. Register with the crosstalk + * generic provider so when we encounter the chip + * the right magic happens. + */ +void +xbow_init(void) +{ + +#if DEBUG && ATTACH_DEBUG + printk("xbow_init\n"); +#endif + + xwidget_driver_register(PXBOW_WIDGET_PART_NUM, + 0, /* XXBOW_WIDGET_MFGR_NUM, */ + "xbow_", + CDL_PRI_HI); /* attach before friends */ + + + xwidget_driver_register(XXBOW_WIDGET_PART_NUM, + 0, /* XXBOW_WIDGET_MFGR_NUM, */ + "xbow_", + CDL_PRI_HI); /* attach before friends */ + + xwidget_driver_register(XBOW_WIDGET_PART_NUM, + XBOW_WIDGET_MFGR_NUM, + "xbow_", + CDL_PRI_HI); /* attach before friends */ +} + +#ifdef XBRIDGE_REGS_SIM +/* xbow_set_simulated_regs: sets xbow regs as needed + * for powering through the boot + */ +void +xbow_set_simulated_regs(xbow_t *xbow, int port) +{ + /* + * turn on link + */ + xbow->xb_link(port).link_status = (1<<31); + /* + * and give it a live widget too + */ + xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT; + /* + * zero the link control reg + */ + xbow->xb_link(port).link_control = 0x0; +} +#endif /* XBRIDGE_REGS_SIM */ + +/* + * xbow_attach: the crosstalk provider has + * determined that there is a crossbow widget + * present, and has handed us the connection + * point for that vertex. + * + * We not only add our own vertex, but add + * some "xtalk switch" data to the switch + * vertex (at the connect point's parent) if + * it does not have any. + */ + +/*ARGSUSED */ +int +xbow_attach(devfs_handle_t conn) +{ + /*REFERENCED */ + devfs_handle_t vhdl; + devfs_handle_t busv; + xbow_t *xbow; + xbow_soft_t soft; + int port; + xswitch_info_t info; + char devnm[MAXDEVNAME], *s; + xbowreg_t id; + int rev; + int i; + int xbow_num; + +#if DEBUG && ATTACH_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: xbow_attach\n", conn); +#else + printk("0x%x: xbow_attach\n", conn); +#endif +#endif + + /* + * Get a PIO pointer to the base of the crossbow + * chip. + */ +#ifdef XBRIDGE_REGS_SIM + printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t)); + xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL); + /* + * turn on ports e and f like in a real live ibrick + */ + xbow_set_simulated_regs(xbow, 0xe); + xbow_set_simulated_regs(xbow, 0xf); +#else + xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0); +#endif /* XBRIDGE_REGS_SIM */ + + /* + * Locate the "switch" vertex: it is the parent + * of our connection point. + */ + busv = hwgraph_connectpt_get(conn); +#if DEBUG && ATTACH_DEBUG + printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); +#endif + + ASSERT(busv != GRAPH_VERTEX_NONE); + + /* + * Create our private vertex, and connect our + * driver information to it. This makes it possible + * for diagnostic drivers to open the crossbow + * vertex for access to registers. + */ + + /* + * We need to teach xbow drivers to provide the right set of + * file ops. + */ + vhdl = NULL; + vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + /* &hcl_fops */ (void *)&vhdl, NULL); + if (!vhdl) { + printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", + (void *)conn); + } + + /* + * Allocate the soft state structure and attach + * it to the xbow's vertex + */ + NEW(soft); + soft->conn = conn; + soft->vhdl = vhdl; + soft->busv = busv; + soft->base = xbow; + /* does the universe really need another macro? */ + /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */ + hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft); + +#define XBOW_NUM_SUFFIX_FORMAT "[xbow# %d]" + + /* Add xbow number as a suffix to the hwgraph name of the xbow. + * This is helpful while looking at the error/warning messages. + */ + xbow_num = 0; + + /* + * get the name of this xbow vertex and keep the info. + * This is needed during errors and interupts, but as + * long as we have it, we can use it elsewhere. + */ + s = dev_to_name(vhdl, devnm, MAXDEVNAME); + soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, + GFP_KERNEL); + sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num); + +#ifdef XBRIDGE_REGS_SIM + /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined + * as 0xd000, so I'm using that for the partnum bitfield. + */ + printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n"); + id = 0x2d000049; +#else + id = xbow->xb_wid_id; +#endif /* XBRIDGE_REGS_SIM */ + rev = XWIDGET_PART_REV_NUM(id); + + mutex_spinlock_init(&soft->xbow_perf_lock); + soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; + soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; + + /* Initialization for GBR bw allocation */ + mutex_spinlock_init(&soft->xbow_bw_alloc_lock); + +#define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */ +#define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ + + /* Set bandwidth hiwatermark and current values */ + for (i = 0; i < MAX_XBOW_PORTS; i++) { + soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX; /* for now */ + soft->bw_cur_used[i] = 0; + } + + /* + * Enable xbow error interrupts + */ + xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); + + /* + * take a census of the widgets present, + * leaving notes at the switch vertex. + */ + info = xswitch_info_new(busv); + + for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; + port < MAX_PORT_NUM; ++port) { + if (!xbow_link_alive(xbow, port)) { +#if DEBUG && XBOW_DEBUG + printk(KERN_INFO "0x%p link %d is not alive\n", + busv, port); +#endif + continue; + } + if (!xbow_widget_present(xbow, port)) { +#if DEBUG && XBOW_DEBUG + printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", busv, port); +#endif + continue; + } +#if DEBUG && XBOW_DEBUG + printk(KERN_INFO "0x%p link %d has a widget\n", + busv, port); +#endif + + xswitch_info_link_is_ok(info, port); + /* + * Turn some error interrupts on + * and turn others off. The PROM has + * some things turned on we don't + * want to see (bandwidth allocation + * errors for instance); so if it + * is not listed here, it is not on. + */ + xbow->xb_link(port).link_control = + ( (xbow->xb_link(port).link_control + /* + * Turn off these bits; they are non-fatal, + * but we might want to save some statistics + * on the frequency of these errors. + * XXX FIXME XXX + */ + & ~XB_CTRL_RCV_CNT_OFLOW_IE + & ~XB_CTRL_XMT_CNT_OFLOW_IE + & ~XB_CTRL_BNDWDTH_ALLOC_IE + & ~XB_CTRL_RCV_IE) + /* + * These are the ones we want to turn on. + */ + | (XB_CTRL_ILLEGAL_DST_IE + | XB_CTRL_OALLOC_IBUF_IE + | XB_CTRL_XMT_MAX_RTRY_IE + | XB_CTRL_MAXREQ_TOUT_IE + | XB_CTRL_XMT_RTRY_IE + | XB_CTRL_SRC_TOUT_IE) ); + } + + xswitch_provider_register(busv, &xbow_provider); + + return 0; /* attach successful */ +} + +/*ARGSUSED */ +int +xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) +{ + return 0; + +} + +/*ARGSUSED */ +int +xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) +{ + return 0; +} + +/*ARGSUSED */ +int +xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + xbow_soft_t soft = xbow_soft_get(vhdl); + int error; + + ASSERT(soft); + len = ctob(btoc(len)); + /* XXX- this ignores the offset!!! */ + error = v_mapphys(vt, (void *) soft->base, len); + return error; +} + +/*ARGSUSED */ +int +xbow_unmap(devfs_handle_t dev, vhandl_t *vt) +{ + return 0; +} + +/* This contains special-case code for grio. There are plans to make + * this general sometime in the future, but till then this should + * be good enough. + */ +xwidgetnum_t +xbow_widget_num_get(devfs_handle_t dev) +{ + devfs_handle_t tdev; + char devname[MAXDEVNAME]; + xwidget_info_t xwidget_info; + int i; + + vertex_to_name(dev, devname, MAXDEVNAME); + + /* If this is a pci controller vertex, traverse up using + * the ".." links to get to the widget. + */ + if (strstr(devname, EDGE_LBL_PCI) && + strstr(devname, EDGE_LBL_CONTROLLER)) { + tdev = dev; + for (i=0; i< 2; i++) { + if (hwgraph_edge_get(tdev, + HWGRAPH_EDGELBL_DOTDOT, &tdev) != + GRAPH_SUCCESS) + return XWIDGET_NONE; + } + + if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) { + return (xwidget_info_id_get(xwidget_info)); + } else { + return XWIDGET_NONE; + } + } + + return XWIDGET_NONE; +} + +int +xbow_ioctl(devfs_handle_t dev, + int cmd, + void *arg, + int flag, + struct cred *cr, + int *rvalp) +{ + devfs_handle_t vhdl; + int error = 0; + +#if defined (DEBUG) + int rc; + devfs_handle_t conn; + struct xwidget_info_s *xwidget_info; + xbow_soft_t xbow_soft; +#endif + *rvalp = 0; + + vhdl = dev_to_vhdl(dev); +#if defined (DEBUG) + xbow_soft = xbow_soft_get(vhdl); + conn = xbow_soft->conn; + + xwidget_info = xwidget_info_get(conn); + ASSERT_ALWAYS(xwidget_info != NULL); + + rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid); + ASSERT_ALWAYS(rc != 0); +#endif + switch (cmd) { + + case XBOWIOC_LLP_ERROR_ENABLE: + if ((error = xbow_enable_llp_monitor(vhdl)) != 0) + error = EINVAL; + + break; + + case XBOWIOC_LLP_ERROR_DISABLE: + + if ((error = xbow_disable_llp_monitor(vhdl)) != 0) + error = EINVAL; + + break; + + default: + break; + + } + return error; +} + +/* + * xbow_widget_present: See if a device is present + * on the specified port of this crossbow. + */ +int +xbow_widget_present(xbow_t *xbow, int port) +{ + if ( IS_RUNNING_ON_SIMULATOR() ) { + if ( (port == 14) || (port == 15) ) { + return 1; + } + else { + return 0; + } + } + else { + /* WAR: port 0xf on PIC is missing present bit */ + /* Need this for PIC */ + if (IS_PIC_XBOW(xbow->xb_wid_id) && port == 0xf) { + return 1; + } + return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT; + } +} + +static int +xbow_link_alive(xbow_t * xbow, int port) +{ + xbwX_stat_t xbow_linkstat; + + xbow_linkstat.linkstatus = xbow->xb_link(port).link_status; + return (xbow_linkstat.link_alive); +} + +/* + * xbow_widget_lookup + * Lookup the edges connected to the xbow specified, and + * retrieve the handle corresponding to the widgetnum + * specified. + * If not found, return 0. + */ +devfs_handle_t +xbow_widget_lookup(devfs_handle_t vhdl, + int widgetnum) +{ + xswitch_info_t xswitch_info; + devfs_handle_t conn; + + xswitch_info = xswitch_info_get(vhdl); + conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); + return conn; +} + +/* + * xbow_intr_preset: called during mlreset time + * if the platform specific code needs to route + * an xbow interrupt before the xtalk infrastructure + * is available for use. + * + * Also called from xbow_setwidint, so we don't + * replicate the guts of the routine. + * + * XXX- probably should be renamed xbow_wid_intr_set or + * something to reduce confusion. + */ +/*ARGSUSED3 */ +void +xbow_intr_preset(void *which_widget, + int which_widget_intr, + xwidgetnum_t targ, + iopaddr_t addr, + xtalk_intr_vector_t vect) +{ + xbow_t *xbow = (xbow_t *) which_widget; + + xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) | + (0x000F0000 & (targ << 16)) | + XTALK_ADDR_TO_UPPER(addr)); + xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); + +} + +int xbow_xmit_retry_errors = 0; + +int +xbow_xmit_retry_error(xbow_soft_t soft, + int port) +{ + xswitch_info_t info; + devfs_handle_t vhdl; + widget_cfg_t *wid; + widgetreg_t id; + int part; + int mfgr; + + wid = soft->wpio[port - BASE_XBOW_PORT]; + if (wid == NULL) { + /* If we can't track down a PIO + * pointer to our widget yet, + * leave our caller knowing that + * we are interested in this + * interrupt if it occurs in + * the future. + */ + info = xswitch_info_get(soft->busv); + if (!info) + return 1; + vhdl = xswitch_info_vhdl_get(info, port); + if (vhdl == GRAPH_VERTEX_NONE) + return 1; + wid = (widget_cfg_t *) xtalk_piotrans_addr + (vhdl, 0, 0, sizeof *wid, 0); + if (!wid) + return 1; + soft->wpio[port - BASE_XBOW_PORT] = wid; + } + id = wid->w_id; + part = XWIDGET_PART_NUM(id); + mfgr = XWIDGET_MFG_NUM(id); + + /* If this thing is not a Bridge, + * do not activate the WAR, and + * tell our caller we do not need + * to be called again. + */ + if ((part != BRIDGE_WIDGET_PART_NUM) || + (mfgr != BRIDGE_WIDGET_MFGR_NUM)) { + /* FIXME: add Xbridge to the WAR. + * Shouldn't hurt anything. Later need to + * check if we can remove this. + */ + if ((part != XBRIDGE_WIDGET_PART_NUM) || + (mfgr != XBRIDGE_WIDGET_MFGR_NUM)) + return 0; + } + + /* count how many times we + * have picked up after + * LLP Transmit problems. + */ + xbow_xmit_retry_errors++; + + /* rewrite the control register + * to fix things up. + */ + wid->w_control = wid->w_control; + wid->w_control; + + return 1; +} + +void +xbow_update_perf_counters(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; + xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; + xbow_perfcount_t perf_reg; + unsigned long s; + int link, i; + + for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { + if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) + continue; + + s = mutex_spinlock(&xbow_soft->xbow_perf_lock); + + perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; + + link = perf_reg.xb_perf.link_select; + + (xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] += + ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK); + xbow_perf->xp_current = perf_reg.xb_perf.count; + + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + } +} + +xbow_perf_link_t * +xbow_get_perf_counters(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; + + return xbow_perf_link; +} + +int +xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; + xbow_linkctrl_t xbow_link_ctrl; + xbow_t *xbow = xbow_soft->base; + xbow_perfcount_t perf_reg; + unsigned long s; + int i; + + link -= BASE_XBOW_PORT; + if ((link < 0) || (link >= MAX_XBOW_PORTS)) + return -1; + + if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK)) + return -1; + + if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS)) + return -1; + + s = mutex_spinlock(&xbow_soft->xbow_perf_lock); + + if ((xbow_perf + counter)->xp_mode && mode) { + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + return -1; + } + for (i = 0; i < XBOW_PERF_COUNTERS; i++) { + if (i == counter) + continue; + if (((xbow_perf + i)->xp_link == link) && + ((xbow_perf + i)->xp_mode)) { + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + return -1; + } + } + xbow_perf += counter; + + xbow_perf->xp_curlink = xbow_perf->xp_link = link; + xbow_perf->xp_curmode = xbow_perf->xp_mode = mode; + + xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control; + xbow_link_ctrl.xb_linkcontrol.perf_mode = mode; + xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword; + + perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; + perf_reg.xb_perf.link_select = link; + *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; + xbow_perf->xp_current = perf_reg.xb_perf.count; + + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + return 0; +} + +xbow_link_status_t * +xbow_get_llp_status(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; + + return xbow_llp_status; +} + +void +xbow_update_llp_status(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; + xbow_t *xbow; + xbwX_stat_t lnk_sts; + xbow_aux_link_status_t aux_sts; + int link; + devfs_handle_t xwidget_vhdl; + char *xwidget_name; + + xbow = (xbow_t *) xbow_soft->base; + for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) { + /* Get the widget name corresponding the current link. + * Note : 0 <= link < MAX_XBOW_PORTS(8). + * BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10) + */ + xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT); + xwidget_name = xwidget_name_get(xwidget_vhdl); + aux_sts.aux_linkstatus + = xbow->xb_link_raw[link].link_aux_status; + lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr; + + if (lnk_sts.link_alive == 0) + continue; + + xbow_llp_status->rx_err_count += + aux_sts.xb_aux_linkstatus.rx_err_cnt; + + xbow_llp_status->tx_retry_count += + aux_sts.xb_aux_linkstatus.tx_retry_cnt; + + if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { +#ifdef LATER + printk(KERN_WARNING "link %d[%s]: bad status 0x%x\n", + link, xwidget_name, lnk_sts.linkstatus); +#endif + } + } +} + +int +xbow_disable_llp_monitor(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + int port; + + for (port = 0; port < MAX_XBOW_PORTS; port++) { + xbow_soft->xbow_link_status[port].rx_err_count = 0; + xbow_soft->xbow_link_status[port].tx_retry_count = 0; + } + + xbow_soft->link_monitor = 0; + return 0; +} + +int +xbow_enable_llp_monitor(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + + xbow_soft->link_monitor = 1; + return 0; +} + + +int +xbow_reset_link(devfs_handle_t xconn_vhdl) +{ + xwidget_info_t widget_info; + xwidgetnum_t port; + xbow_t *xbow; + xbowreg_t ctrl; + xbwX_stat_t stat; + unsigned itick; + unsigned dtick; + static int ticks_per_ms = 0; + + if (!ticks_per_ms) { + itick = get_timestamp(); + us_delay(1000); + ticks_per_ms = get_timestamp() - itick; + } + widget_info = xwidget_info_get(xconn_vhdl); + port = xwidget_info_id_get(widget_info); + +#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ + xbow = XBOW_K1PTR; +#else + { + devfs_handle_t xbow_vhdl; + xbow_soft_t xbow_soft; + + hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); + xbow_soft = xbow_soft_get(xbow_vhdl); + xbow = xbow_soft->base; + } +#endif + + /* + * This requires three PIOs (reset the link, check for the + * reset, restore the control register for the link) plus + * 10us to wait for the reset. We allow up to 1ms for the + * widget to come out of reset before giving up and + * returning a failure. + */ + ctrl = xbow->xb_link(port).link_control; + xbow->xb_link(port).link_reset = 0; + itick = get_timestamp(); + while (1) { + stat.linkstatus = xbow->xb_link(port).link_status; + if (stat.link_alive) + break; + dtick = get_timestamp() - itick; + if (dtick > ticks_per_ms) { + return -1; /* never came out of reset */ + } + DELAY(2); /* don't beat on link_status */ + } + xbow->xb_link(port).link_control = ctrl; + return 0; +} + +/* + * Dump xbow registers. + * input parameter is either a pointer to + * the xbow chip or the vertex handle for + * an xbow vertex. + */ +void +idbg_xbowregs(int64_t regs) +{ + xbow_t *xbow; + int i; + xb_linkregs_t *link; + + xbow = (xbow_t *) regs; + +#ifdef LATER + qprintf("Printing xbow registers starting at 0x%x\n", xbow); + qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", + xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, + xbow->xb_wid_err_lower, xbow->xb_wid_control, + xbow->xb_wid_req_timeout); + qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", + xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, + xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, + xbow->xb_wid_arb_reload); +#endif + + for (i = 8; i <= 0xf; i++) { + link = &xbow->xb_link(i); +#ifdef LATER + qprintf("Link %d registers\n", i); + qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", + link->link_control, link->link_status, + link->link_arb_upper, link->link_arb_lower, + link->link_aux_status); +#endif + } +} + + +#define XBOW_ARB_RELOAD_TICKS 25 + /* granularity: 4 MB/s, max: 124 MB/s */ +#define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS) + +#define XBOW_BYTES_TO_GBR(BYTES_per_s) (int) (BYTES_per_s / GRANULARITY) + +#define XBOW_GBR_TO_BYTES(cnt) (bandwidth_t) ((cnt) * GRANULARITY) + +#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec) \ + ((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr) + +#define XBOW_ARB_GBR_MAX 31 + +#define ABS(x) ((x > 0) ? (x) : (-1 * x)) + /* absolute value */ + +int +xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec) +{ + int gbr_granted; + int new_total_gbr; + int change_gbr; + bandwidth_t new_total_bw; + +#ifdef GRIO_DEBUG + printk("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n", + old_bytes_per_sec, bytes_per_sec); +#endif /* GRIO_DEBUG */ + + gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)), + old_bytes_per_sec); + new_total_bw = old_bytes_per_sec + bytes_per_sec; + new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)), + new_total_bw); + + change_gbr = new_total_gbr - gbr_granted; + +#ifdef GRIO_DEBUG + printk("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n", + gbr_granted, new_total_gbr, change_gbr); +#endif /* GRIO_DEBUG */ + + return (change_gbr); +} + +/* Conversion from GBR to bytes */ +bandwidth_t +xbow_gbr_to_bytes(int gbr) +{ + return (XBOW_GBR_TO_BYTES(gbr)); +} + +/* Given the vhdl for the desired xbow, the src and dest. widget ids + * and the req_bw value, this xbow driver entry point accesses the + * xbow registers and allocates the desired bandwidth if available. + * + * If bandwidth allocation is successful, return success else return failure. + */ +int +xbow_prio_bw_alloc(devfs_handle_t vhdl, + xwidgetnum_t src_wid, + xwidgetnum_t dest_wid, + unsigned long long old_alloc_bw, + unsigned long long req_bw) +{ + xbow_soft_t soft = xbow_soft_get(vhdl); + volatile xbowreg_t *xreg; + xbowreg_t mask; + unsigned long s; + int error = 0; + bandwidth_t old_bw_BYTES, req_bw_BYTES; + xbowreg_t old_xreg; + int old_bw_GBR, req_bw_GBR, new_bw_GBR; + +#ifdef GRIO_DEBUG + printk("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n", + (int) vhdl, (int) src_wid, (int) dest_wid, req_bw); +#endif + + ASSERT(XBOW_WIDGET_IS_VALID(src_wid)); + ASSERT(XBOW_WIDGET_IS_VALID(dest_wid)); + + s = mutex_spinlock(&soft->xbow_bw_alloc_lock); + + /* Get pointer to the correct register */ + xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid); + + /* Get mask for GBR count value */ + mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid); + + req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw); + req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR))) + : xbow_gbr_to_bytes(req_bw_GBR); + +#ifdef GRIO_DEBUG + printk("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n", + req_bw, req_bw_BYTES, req_bw_GBR); +#endif /* GRIO_DEBUG */ + + old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS]; + old_xreg = *xreg; + old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid)); + +#ifdef GRIO_DEBUG + ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR); + + printk("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR); + + printk("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n", + req_bw_BYTES, old_bw_BYTES, + soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]); + +#endif /* GRIO_DEBUG */ + + /* Accept the request only if we don't exceed the destination + * port HIWATER_MARK *AND* the max. link GBR arbitration count + */ + if (((old_bw_BYTES + req_bw_BYTES) <= + soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) && + (req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) { + + new_bw_GBR = (old_bw_GBR + req_bw_GBR); + + /* Set this in the xbow link register */ + *xreg = (old_xreg & ~mask) | \ + (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask); + + soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] = + xbow_gbr_to_bytes(new_bw_GBR); + } else { + error = 1; + } + + mutex_spinunlock(&soft->xbow_bw_alloc_lock, s); + + return (error); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn1/xtalk.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/xtalk.c --- linux-2.4.19/arch/ia64/sn/io/sn1/xtalk.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn1/xtalk.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1003 @@ +/* $Id: xtalk.c,v 1.3 2002/12/30 22:16:56 jh Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Implement crosstalk provider operations. The xtalk* layer provides a + * platform-independent interface for crosstalk devices. This layer + * switches among the possible implementations of a crosstalk adapter. + * + * On platforms with only one possible xtalk provider, macros can be + * set up at the top that cause the table lookups and indirections to + * completely disappear. + */ + +#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) +#define DEL(ptr) (kfree(ptr)) + +char widget_info_fingerprint[] = "widget_info"; + +cdl_p xtalk_registry = NULL; + +#define DEV_FUNC(dev,func) hub_##func +#define CAST_PIOMAP(x) ((hub_piomap_t)(x)) +#define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) +#define CAST_INTR(x) ((hub_intr_t)(x)) + +/* ===================================================================== + * Function Table of Contents + */ +xtalk_piomap_t xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); +void xtalk_piomap_free(xtalk_piomap_t); +caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); +void xtalk_piomap_done(xtalk_piomap_t); +caddr_t xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned); +caddr_t xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); +void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); +caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); +static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); +xtalk_dmamap_t xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +void xtalk_dmamap_free(xtalk_dmamap_t); +iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); +alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); +void xtalk_dmamap_done(xtalk_dmamap_t); +iopaddr_t xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +void xtalk_dmamap_drain(xtalk_dmamap_t); +void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); +void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); +xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); +xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); +void xtalk_intr_free(xtalk_intr_t); +int xtalk_intr_connect(xtalk_intr_t, xtalk_intr_setfunc_t, void *); +void xtalk_intr_disconnect(xtalk_intr_t); +devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); +int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); +int xtalk_error_devenable(devfs_handle_t, int, int); +void xtalk_provider_startup(devfs_handle_t); +void xtalk_provider_shutdown(devfs_handle_t); +devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t); +xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); +xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); +iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); +void *xtalk_intr_sfarg_get(xtalk_intr_t); +devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t); +xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); +iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); +ulong xtalk_pio_mapsz_get(xtalk_piomap_t); +caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); +devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t); +xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); +xwidget_info_t xwidget_info_chk(devfs_handle_t); +xwidget_info_t xwidget_info_get(devfs_handle_t); +void xwidget_info_set(devfs_handle_t, xwidget_info_t); +devfs_handle_t xwidget_info_dev_get(xwidget_info_t); +xwidgetnum_t xwidget_info_id_get(xwidget_info_t); +devfs_handle_t xwidget_info_master_get(xwidget_info_t); +xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); +xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); +xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); +char *xwidget_info_name_get(xwidget_info_t); +void xtalk_init(void); +void xtalk_provider_register(devfs_handle_t, xtalk_provider_t *); +void xtalk_provider_unregister(devfs_handle_t); +xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t); +int xwidget_driver_register(xwidget_part_num_t, + xwidget_mfg_num_t, + char *, unsigned); +void xwidget_driver_unregister(char *); +int xwidget_register(xwidget_hwid_t, devfs_handle_t, + xwidgetnum_t, devfs_handle_t, + xwidgetnum_t, async_attach_t); +int xwidget_unregister(devfs_handle_t); +void xwidget_reset(devfs_handle_t); +char *xwidget_name_get(devfs_handle_t); +#if !defined(DEV_FUNC) +/* + * There is more than one possible provider + * for this platform. We need to examine the + * master vertex of the current vertex for + * a provider function structure, and indirect + * through the appropriately named member. + */ +#define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func +#define CAST_PIOMAP(x) ((xtalk_piomap_t)(x)) +#define CAST_DMAMAP(x) ((xtalk_dmamap_t)(x)) +#define CAST_INTR(x) ((xtalk_intr_t)(x)) + +static xtalk_provider_t * +xwidget_to_provider_fns(devfs_handle_t xconn) +{ + xwidget_info_t widget_info; + xtalk_provider_t *provider_fns; + + widget_info = xwidget_info_get(xconn); + ASSERT(widget_info != NULL); + + provider_fns = xwidget_info_pops_get(widget_info); + ASSERT(provider_fns != NULL); + + return (provider_fns); +} +#endif + +/* + * Many functions are not passed their vertex + * information directly; rather, they must + * dive through a resource map. These macros + * are available to coordinate this detail. + */ +#define PIOMAP_FUNC(map,func) DEV_FUNC(map->xp_dev,func) +#define DMAMAP_FUNC(map,func) DEV_FUNC(map->xd_dev,func) +#define INTR_FUNC(intr,func) DEV_FUNC(intr_hdl->xi_dev,func) + +/* ===================================================================== + * PIO MANAGEMENT + * + * For mapping system virtual address space to + * xtalk space on a specified widget + */ + +xtalk_piomap_t +xtalk_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ + device_desc_t dev_desc, /* device descriptor */ + iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ + size_t byte_count, + size_t byte_count_max, /* maximum size of a mapping */ + unsigned flags) +{ /* defined in sys/pio.h */ + return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc) + (dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags); +} + + +void +xtalk_piomap_free(xtalk_piomap_t xtalk_piomap) +{ + PIOMAP_FUNC(xtalk_piomap, piomap_free) + (CAST_PIOMAP(xtalk_piomap)); +} + + +caddr_t +xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap, /* mapping resources */ + iopaddr_t xtalk_addr, /* map for this xtalk address */ + size_t byte_count) +{ /* map this many bytes */ + return PIOMAP_FUNC(xtalk_piomap, piomap_addr) + (CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count); +} + + +void +xtalk_piomap_done(xtalk_piomap_t xtalk_piomap) +{ + PIOMAP_FUNC(xtalk_piomap, piomap_done) + (CAST_PIOMAP(xtalk_piomap)); +} + + +caddr_t +xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + iopaddr_t xtalk_addr, /* Crosstalk address */ + size_t byte_count, /* map this many bytes */ + unsigned flags) +{ /* (currently unused) */ + return DEV_FUNC(dev, piotrans_addr) + (dev, dev_desc, xtalk_addr, byte_count, flags); +} + +caddr_t +xtalk_pio_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + iopaddr_t addr, /* starting address (or offset in window) */ + size_t byte_count, /* map this many bytes */ + xtalk_piomap_t *mapp, /* where to return the map pointer */ + unsigned flags) +{ /* PIO flags */ + xtalk_piomap_t map = 0; + caddr_t res; + + if (mapp) + *mapp = 0; /* record "no map used" */ + + res = xtalk_piotrans_addr + (dev, dev_desc, addr, byte_count, flags); + if (res) + return res; /* xtalk_piotrans worked */ + + map = xtalk_piomap_alloc + (dev, dev_desc, addr, byte_count, byte_count, flags); + if (!map) + return res; /* xtalk_piomap_alloc failed */ + + res = xtalk_piomap_addr + (map, addr, byte_count); + if (!res) { + xtalk_piomap_free(map); + return res; /* xtalk_piomap_addr failed */ + } + if (mapp) + *mapp = map; /* pass back map used */ + + return res; /* xtalk_piomap_addr succeeded */ +} + +/* ===================================================================== + * EARLY PIOTRANS SUPPORT + * + * There are places where drivers (mgras, for instance) + * need to get PIO translations before the infrastructure + * is extended to them (setting up textports, for + * instance). These drivers should call + * xtalk_early_piotrans_addr with their xtalk ID + * information, a sequence number (so we can use the second + * mgras for instance), and the usual piotrans parameters. + * + * Machine specific code should provide an implementation + * of early_piotrans_addr, and present a pointer to this + * function to xtalk_set_early_piotrans_addr so it can be + * used by clients without the clients having to know what + * platform or what xtalk provider is in use. + */ + +static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr; + +xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr; + +/* xtalk_set_early_piotrans_addr: + * specify the early_piotrans_addr implementation function. + */ +void +xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl) +{ + impl_early_piotrans_addr = impl; +} + +/* xtalk_early_piotrans_addr: + * figure out a PIO address for the "nth" crosstalk widget that + * matches the specified part and mfgr number. Returns NULL if + * there is no such widget, or if the requested mapping can not + * be constructed. + * Limitations on which crosstalk slots (and busses) are + * checked, and definitions of the ordering of the search across + * the crosstalk slots, are defined by the platform. + */ +caddr_t +xtalk_early_piotrans_addr(xwidget_part_num_t part_num, + xwidget_mfg_num_t mfg_num, + int which, + iopaddr_t xtalk_addr, + size_t byte_count, + unsigned flags) +{ + return impl_early_piotrans_addr + (part_num, mfg_num, which, xtalk_addr, byte_count, flags); +} + +/* null_xtalk_early_piotrans_addr: + * used as the early_piotrans_addr implementation until and + * unless a real implementation is provided. In DEBUG kernels, + * we want to know who is calling before the implementation is + * registered; in non-DEBUG kernels, return NULL representing + * lack of mapping support. + */ +/*ARGSUSED */ +static caddr_t +null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num, + xwidget_mfg_num_t mfg_num, + int which, + iopaddr_t xtalk_addr, + size_t byte_count, + unsigned flags) +{ +#if DEBUG + PRINT_PANIC("null_xtalk_early_piotrans_addr"); +#endif + return NULL; +} + +/* ===================================================================== + * DMA MANAGEMENT + * + * For mapping from crosstalk space to system + * physical space. + */ + +xtalk_dmamap_t +xtalk_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ + device_desc_t dev_desc, /* device descriptor */ + size_t byte_count_max, /* max size of a mapping */ + unsigned flags) +{ /* defined in dma.h */ + return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc) + (dev, dev_desc, byte_count_max, flags); +} + + +void +xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap) +{ + DMAMAP_FUNC(xtalk_dmamap, dmamap_free) + (CAST_DMAMAP(xtalk_dmamap)); +} + + +iopaddr_t +xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ + paddr_t paddr, /* map for this address */ + size_t byte_count) +{ /* map this many bytes */ + return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr) + (CAST_DMAMAP(xtalk_dmamap), paddr, byte_count); +} + + +alenlist_t +xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ + alenlist_t alenlist, /* map this Address/Length List */ + unsigned flags) +{ + return DMAMAP_FUNC(xtalk_dmamap, dmamap_list) + (CAST_DMAMAP(xtalk_dmamap), alenlist, flags); +} + + +void +xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) +{ + DMAMAP_FUNC(xtalk_dmamap, dmamap_done) + (CAST_DMAMAP(xtalk_dmamap)); +} + + +iopaddr_t +xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_addr) + (dev, dev_desc, paddr, byte_count, flags); +} + + +alenlist_t +xtalk_dmatrans_list(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + alenlist_t palenlist, /* system address/length list */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_list) + (dev, dev_desc, palenlist, flags); +} + +void +xtalk_dmamap_drain(xtalk_dmamap_t map) +{ + DMAMAP_FUNC(map, dmamap_drain) + (CAST_DMAMAP(map)); +} + +void +xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +{ + DEV_FUNC(dev, dmaaddr_drain) + (dev, addr, size); +} + +void +xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) +{ + DEV_FUNC(dev, dmalist_drain) + (dev, list); +} + +/* ===================================================================== + * INTERRUPT MANAGEMENT + * + * Allow crosstalk devices to establish interrupts + */ + +/* + * Allocate resources required for an interrupt as specified in intr_desc. + * Return resource handle in intr_hdl. + */ +xtalk_intr_t +xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) +{ /* owner of this interrupt */ + return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) + (dev, dev_desc, owner_dev); +} + +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Unconditionally setup resources to be non-threaded. + * Return resource handle in intr_hdl. + */ +xtalk_intr_t +xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt */ +{ + return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) + (dev, dev_desc, owner_dev); +} + +/* + * Free resources consumed by intr_alloc. + */ +void +xtalk_intr_free(xtalk_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_free) + (CAST_INTR(intr_hdl)); +} + + +/* + * Associate resources allocated with a previous xtalk_intr_alloc call with the + * described handler, arg, name, etc. + * + * Returns 0 on success, returns <0 on failure. + */ +int +xtalk_intr_connect(xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ + xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ + void *setfunc_arg) /* arg to setfunc */ +{ + return INTR_FUNC(intr_hdl, intr_connect) + (CAST_INTR(intr_hdl), setfunc, setfunc_arg); +} + + +/* + * Disassociate handler with the specified interrupt. + */ +void +xtalk_intr_disconnect(xtalk_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_disconnect) + (CAST_INTR(intr_hdl)); +} + + +/* + * Return a hwgraph vertex that represents the CPU currently + * targeted by an interrupt. + */ +devfs_handle_t +xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) +{ + return INTR_FUNC(intr_hdl, intr_cpu_get) + (CAST_INTR(intr_hdl)); +} + + +/* ===================================================================== + * CONFIGURATION MANAGEMENT + */ + +/* + * Startup a crosstalk provider + */ +void +xtalk_provider_startup(devfs_handle_t xtalk_provider) +{ + DEV_FUNC(xtalk_provider, provider_startup) + (xtalk_provider); +} + + +/* + * Shutdown a crosstalk provider + */ +void +xtalk_provider_shutdown(devfs_handle_t xtalk_provider) +{ + DEV_FUNC(xtalk_provider, provider_shutdown) + (xtalk_provider); +} + +/* + * Enable a device on a xtalk widget + */ +void +xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) +{ + DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum); +} + +/* + * Shutdown a device on a xtalk widget + */ +void +xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) +{ + DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum); +} + +int +xtalk_dma_enabled(devfs_handle_t xconn_vhdl) +{ + return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl); +} +/* + * Generic crosstalk functions, for use with all crosstalk providers + * and all crosstalk devices. + */ + +/****** Generic crosstalk interrupt interfaces ******/ +devfs_handle_t +xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_dev); +} + +xwidgetnum_t +xtalk_intr_target_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_target); +} + +xtalk_intr_vector_t +xtalk_intr_vector_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_vector); +} + +iopaddr_t +xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr) +{ + return (xtalk_intr->xi_addr); +} + +void * +xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_sfarg); +} + +/****** Generic crosstalk pio interfaces ******/ +devfs_handle_t +xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_dev); +} + +xwidgetnum_t +xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_target); +} + +iopaddr_t +xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_xtalk_addr); +} + +ulong +xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_mapsz); +} + +caddr_t +xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_kvaddr); +} + + +/****** Generic crosstalk dma interfaces ******/ +devfs_handle_t +xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) +{ + return (xtalk_dmamap->xd_dev); +} + +xwidgetnum_t +xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap) +{ + return (xtalk_dmamap->xd_target); +} + + +/****** Generic crosstalk widget information interfaces ******/ + +/* xwidget_info_chk: + * check to see if this vertex is a widget; + * if so, return its widget_info (if any). + * if not, return NULL. + */ +xwidget_info_t +xwidget_info_chk(devfs_handle_t xwidget) +{ + arbitrary_info_t ainfo = 0; + + hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo); + return (xwidget_info_t) ainfo; +} + + +xwidget_info_t +xwidget_info_get(devfs_handle_t xwidget) +{ + xwidget_info_t widget_info; + + widget_info = (xwidget_info_t) + hwgraph_fastinfo_get(xwidget); + +#ifdef LATER + if ((widget_info != NULL) && + (widget_info->w_fingerprint != widget_info_fingerprint)) +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_PANIC("%v bad xwidget_info", xwidget); +#else + PRINT_PANIC("%x bad xwidget_info", xwidget); +#endif +#endif /* LATER */ + + return (widget_info); +} + +void +xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) +{ + if (widget_info != NULL) + widget_info->w_fingerprint = widget_info_fingerprint; + + hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info); + + /* Also, mark this vertex as an xwidget, + * and use the widget_info, so xwidget_info_chk + * can work (and be fairly efficient). + */ + hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET, + (arbitrary_info_t) widget_info); +} + +devfs_handle_t +xwidget_info_dev_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_vertex); +} + +xwidgetnum_t +xwidget_info_id_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_id); +} + + +devfs_handle_t +xwidget_info_master_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_master); +} + +xwidgetnum_t +xwidget_info_masterid_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_masterid); +} + +xwidget_part_num_t +xwidget_info_part_num_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_hwid.part_num); +} + +xwidget_mfg_num_t +xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_hwid.mfg_num); +} +/* Extract the widget name from the widget information + * for the xtalk widget. + */ +char * +xwidget_info_name_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget info"); + return(xwidget_info->w_name); +} +/****** Generic crosstalk initialization interfaces ******/ + +/* + * One-time initialization needed for systems that support crosstalk. + */ +void +xtalk_init(void) +{ + cdl_p cp; + +#if DEBUG && ATTACH_DEBUG + printf("xtalk_init\n"); +#endif + /* Allocate the registry. + * We might already have one. + * If we don't, go get one. + * MPness: someone might have + * set one up for us while we + * were not looking; use an atomic + * compare-and-swap to commit to + * using the new registry if and + * only if nobody else did first. + * If someone did get there first, + * toss the one we allocated back + * into the pool. + */ + if (xtalk_registry == NULL) { + cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr"); + if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) { + cdl_del(cp); + } + } + ASSERT(xtalk_registry != NULL); +} + +/* + * Associate a set of xtalk_provider functions with a vertex. + */ +void +xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) +{ + hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); +} + +/* + * Disassociate a set of xtalk_provider functions with a vertex. + */ +void +xtalk_provider_unregister(devfs_handle_t provider) +{ + hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); +} + +/* + * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk + * provider. + */ +xtalk_provider_t * +xtalk_provider_fns_get(devfs_handle_t provider) +{ + return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); +} + +/* + * Announce a driver for a particular crosstalk part. + * Returns 0 on success or -1 on failure. Failure occurs if the + * specified hardware already has a driver. + */ +/*ARGSUSED4 */ +int +xwidget_driver_register(xwidget_part_num_t part_num, + xwidget_mfg_num_t mfg_num, + char *driver_prefix, + unsigned flags) +{ + /* a driver's init routine could call + * xwidget_driver_register before the + * system calls xtalk_init; so, we + * make the call here. + */ + if (xtalk_registry == NULL) + xtalk_init(); + + return cdl_add_driver(xtalk_registry, + part_num, mfg_num, + driver_prefix, flags, NULL); +} + +/* + * Inform xtalk infrastructure that a driver is no longer available for + * handling any widgets. + */ +void +xwidget_driver_unregister(char *driver_prefix) +{ + /* before a driver calls unregister, + * it must have called registger; so we + * can assume we have a registry here. + */ + ASSERT(xtalk_registry != NULL); + + cdl_del_driver(xtalk_registry, driver_prefix, NULL); +} + +/* + * Call some function with each vertex that + * might be one of this driver's attach points. + */ +void +xtalk_iterate(char *driver_prefix, + xtalk_iter_f *func) +{ + ASSERT(xtalk_registry != NULL); + + cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func); +} + +/* + * xwidget_register: + * Register a xtalk device (xwidget) by doing the following. + * -allocate and initialize xwidget_info data + * -allocate a hwgraph vertex with name based on widget number (id) + * -look up the widget's initialization function and call it, + * or remember the vertex for later initialization. + * + */ +int +xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ + devfs_handle_t widget, /* widget to initialize */ + xwidgetnum_t id, /* widget's target id (0..f) */ + devfs_handle_t master, /* widget's master vertex */ + xwidgetnum_t targetid, /* master's target id (9/a) */ + async_attach_t aa) +{ + xwidget_info_t widget_info; + char *s,devnm[MAXDEVNAME]; + + /* Allocate widget_info and associate it with widget vertex */ + NEW(widget_info); + + /* Initialize widget_info */ + widget_info->w_vertex = widget; + widget_info->w_id = id; + widget_info->w_master = master; + widget_info->w_masterid = targetid; + widget_info->w_hwid = *hwid; /* structure copy */ + widget_info->w_efunc = 0; + widget_info->w_einfo = 0; + /* + * get the name of this xwidget vertex and keep the info. + * This is needed during errors and interupts, but as + * long as we have it, we can use it elsewhere. + */ + s = dev_to_name(widget,devnm,MAXDEVNAME); + widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); + strcpy(widget_info->w_name,s); + + xwidget_info_set(widget, widget_info); + + device_master_set(widget, master); + + /* All the driver init routines (including + * xtalk_init) are called before we get into + * attaching devices, so we can assume we + * have a registry here. + */ + ASSERT(xtalk_registry != NULL); + + /* + * Add pointer to async attach info -- tear down will be done when + * the particular descendant is done with the info. + */ + if (aa) + async_attach_add_info(widget, aa); + + return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); +} + +/* + * xwidget_unregister : + * Unregister the xtalk device and detach all its hwgraph namespace. + */ +int +xwidget_unregister(devfs_handle_t widget) +{ + xwidget_info_t widget_info; + xwidget_hwid_t hwid; + + /* Make sure that we have valid widget information initialized */ + if (!(widget_info = xwidget_info_get(widget))) + return(1); + + /* Remove the inventory information associated + * with the widget. + */ + hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1); + + hwid = &(widget_info->w_hwid); + + cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); + + /* Clean out the xwidget information */ + (void)kfree(widget_info->w_name); + BZERO((void *)widget_info, sizeof(widget_info)); + DEL(widget_info); + + return(0); +} + +/* + * Issue a link reset to a widget. + */ +void +xwidget_reset(devfs_handle_t xwidget) +{ + xswitch_reset_link(xwidget); + +} + + +void +xwidget_gfx_reset(devfs_handle_t xwidget) +{ + xwidget_info_t info; + + xswitch_reset_link(xwidget); + info = xwidget_info_get(xwidget); +#ifdef LATER + ASSERT_ALWAYS(info != NULL); +#endif + + /* + * Enable this for other architectures once we add widget_reset to the + * xtalk provider interface. + */ + DEV_FUNC(xtalk_provider, widget_reset) + (xwidget_info_master_get(info), xwidget_info_id_get(info)); +} + +#define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ + +/* Get the canonical hwgraph name of xtalk widget */ +char * +xwidget_name_get(devfs_handle_t xwidget_vhdl) +{ + xwidget_info_t info; + + /* If we have a bogus widget handle then return + * a default anonymous widget name. + */ + if (xwidget_vhdl == GRAPH_VERTEX_NONE) + return(ANON_XWIDGET_NAME); + /* Read the widget name stored in the widget info + * for the widget setup during widget initialization. + */ + info = xwidget_info_get(xwidget_vhdl); + ASSERT(info != NULL); + return(xwidget_info_name_get(info)); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/Makefile --- linux-2.4.19/arch/ia64/sn/io/sn2/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/Makefile Mon Dec 30 14:16:56 2002 @@ -0,0 +1,28 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +O_TARGET := snio.o + +export-objs := pciio.o + +obj-y += ml_SN_intr.o shub_intr.o shuberror.o shub.o \ + bte_error.o pcibr/pcibr.o pic.o geo_op.o \ + l1.o l1_command.o klconflib.o klgraph.o \ + ml_SN_init.o ml_iograph.o module.o pciio.o \ + xbow.o xtalk.o \ + pci_bus_cvlink.o sgi_io_init.o shubio.o \ + kdba_io.o + +subdir-y += pcibr + +obj-$(CONFIG_SHUB_1_0_SPECIFIC) += efi-rtc.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/bte_error.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/bte_error.c --- linux-2.4.19/arch/ia64/sn/io/sn2/bte_error.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/bte_error.c Tue Jan 14 10:21:44 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -29,6 +29,12 @@ #include #include +/* + * Functions prototypes for externally defined functions. + */ +int hubiio_crb_error_handler(devfs_handle_t, hubinfo_t); + + /************************************************************************ * * * BTE ERROR RECOVERY * @@ -54,96 +60,200 @@ * * ************************************************************************/ -#ifdef BTE_ERROR -// This routine is not called. Yet. It may be someday. It probably -// *should* be someday. Until then, ifdef it out. bte_result_t -bte_error_handler(bte_handle_t *bh) -/* - * Function: bte_error_handler - * Purpose: Process a BTE error after a transfer has failed. - * Parameters: bh - bte handle of bte that failed. - * Returns: The BTE error type. - * Notes: - */ +bte_error_handler(bteinfo_t *bte) + /* + * Function: bte_error_handler + * Purpose: Process a BTE error after a transfer has failed. + * Parameters: bte - bteinfo of bte that failed. + * Returns: The BTE error type. + */ { devfs_handle_t hub_v; + nasid_t nasid; hubinfo_t hinfo; - int il; + int i; hubreg_t iidsr, imem, ieclr; hubreg_t bte_status; + hubreg_t ii_iieph1; +#if RJA + hubreg_t lb_error_bits; +#endif /* RJA */ + ii_ibcr_u_t ibcr; + unsigned long flags; + + bte->bte_error_count++; + + if (!BTE_RECOVER_TRYLOCK(bte)) { + /* + * Someone else is recovering this BTE. + * We must wait for them to complete, then we can assume + * the BTE is fixed (or disabled). Free up our BTE lock, + * so they can proceed. + * When the code at the bottom frees the recover_lock, we get it + * then we grab our BTE lock and free the recover_lock. + */ + BTE_UNLOCK(bte); + while (!BTE_RECOVER_TRYLOCK(bte)) { + udelay(1); /* avoid pounding on lock */ + } + BTE_TRYLOCK(bte); + BTE_RECOVER_UNLOCK(bte); + return(BTEFAIL_ERROR); + } + + /* + * We're the first in, so we will clean up all the BTE interfaces + * on this node. Start by getting all the interface locks. + */ + if (bte_get_all_interfaces(bte) != 0) { + /* + * Can't get all the interfaces + */ + bte_free_interfaces(bte, bte->bte_num); + BTE_RECOVER_UNLOCK(bte); + return(BTEFAIL_ERROR); + } + + /* + * A BTE transfer can use multiple CRBs. We need to make sure + * that all the BTE CRBs are complete (or timed out) before + * attempting to clean up the error. Resetting the BTE while + * there are still BTE CRBs active will hang the BTE. + * We should look at all the CRBs to see if they are allocated + * to the BTE and see if they are still active. When none + * are active, we can continue with the cleanup. + * Until the CRB checking code is written, just wait the + * CRB timeout value, to be sure that all the CRBs have completed + * or timed out. + * + * We also want to make sure that the local NI port is up. + * When a router resets the NI port can go down, while it + * goes through the LLP handshake, but then comes back up. + */ - bh->bh_bte->bte_error_count++; +#if RJA + udelay(160000); +#else + udelay(10); +#endif /* RJA */ - /* + /* * Process any CRB logs - we know that the bte_context contains * the BTE completion status, but to avoid a race with error - * processing, we force a call to pick up any CRB errors pending. - * After this call, we know that we have any CRB errors related to + * processing, we force a call to pick up any CRB errors pending. + * After this call, we know that we have any CRB errors related to * this BTE transfer in the context. */ - hub_v = cnodeid_to_vertex(bh->bh_bte->bte_cnode); + + hub_v = cnodeid_to_vertex(bte->bte_cnode); hubinfo_get(hub_v, &hinfo); + nasid = hinfo->h_nasid; (void)hubiio_crb_error_handler(hub_v, hinfo); - /* Be sure BTE is stopped */ - - (void)BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_CTRL); - - /* - * Now clear up the rest of the error - be sure to hold crblock + /* + * Now clear up the rest of the error - be sure to hold crblock * to avoid race with other cpu on this node. */ - imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); - ieclr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IECLR); - if (bh->bh_bte->bte_num == 0) { + spin_lock_irqsave(&hinfo->h_crblock, flags); + + /* + * Stopping our (hung) transfer has the side effect of killing + * a busy transfer on the other BTE interface. Stop all + * transfers on all BTE interfaces. + */ + for (i = 0; i < BTES_PER_NODE; i++) { + /* + * We should check to see if the BTE is actually has error + * bits set (ie IMEM) instead of just blindly resetting + * it. For now, use the big hammer of resetting both. + */ + HUB_L((shubreg_t *)((nodepda->bte_if[i].bte_base_addr + + BTEOFF_CTRL))); + } + + imem = REMOTE_HUB_L(nasid, IIO_IMEM); + ieclr = REMOTE_HUB_L(nasid, IIO_IECLR); + if (bte->bte_num == 0) { imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD; ieclr|= IECLR_BTE0; } else { imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD; ieclr|= IECLR_BTE1; } + REMOTE_HUB_S(nasid, IIO_IMEM, imem); + REMOTE_HUB_S(nasid, IIO_IECLR, ieclr); - REMOTE_HUB_S(hinfo->h_nasid, IIO_IMEM, imem); - REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, ieclr); - - iidsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR); + iidsr = REMOTE_HUB_L(nasid, IIO_IIDSR); iidsr &= ~IIO_IIDSR_SENT_MASK; iidsr |= IIO_IIDSR_ENB_MASK; - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, iidsr); - mutex_spinunlock(&hinfo->h_crblock, il); + REMOTE_HUB_S(nasid, IIO_IIDSR, iidsr); - bte_status = BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT); - BTE_STORE(bh->bh_bte->bte_base, BTEOFF_STAT, bte_status & ~IBLS_BUSY); - ASSERT(!BTE_IS_BUSY(BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT))); - - switch(bh->bh_error) { - case IIO_ICRB_ECODE_PERR: - return(BTEFAIL_POISON); - case IIO_ICRB_ECODE_WERR: - return(BTEFAIL_PROT); - case IIO_ICRB_ECODE_AERR: - return(BTEFAIL_ACCESS); - case IIO_ICRB_ECODE_TOUT: - return(BTEFAIL_TOUT); - case IIO_ICRB_ECODE_XTERR: - return(BTEFAIL_ERROR); - case IIO_ICRB_ECODE_DERR: - return(BTEFAIL_DIR); - case IIO_ICRB_ECODE_PWERR: - case IIO_ICRB_ECODE_PRERR: - /* NO BREAK */ - default: - printk("BTE failure (%d) unexpected\n", - bh->bh_error); - return(BTEFAIL_ERROR); + /* + * If BTE packets get trunkated (no tail) they can + * leave errror status in several error registers. + * Clean up those error registers. + */ + ii_iieph1 = REMOTE_HUB_L(nasid, IIO_IIEPH1); + if (ii_iieph1) { + REMOTE_HUB_S(nasid, IIO_IIEPH1, 0); + REMOTE_HUB_S(nasid, IIO_IIEPH2, 0); + } +#if RJA + lb_error_bits = REMOTE_HUB_L(nasid, LB_ERROR_BITS); + if (lb_error_bits) { + REMOTE_HUB_S(nasid, LB_ERROR_HDR1, 0LL); + REMOTE_HUB_S(nasid, LB_ERROR_HDR2, 0LL); + REMOTE_HUB_S(nasid, LB_ERROR_DATA, 0LL); + REMOTE_HUB_S(nasid, LB_ERROR_MASK_CLR, -1LL); + } +#endif /* RJA */ + + + /* Reinitialize both BTE state machines. */ + ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); + ibcr.ii_ibcr_fld_s.i_soft_reset = 1; + REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); + + udelay(400); + bte_status = BTE_LOAD(bte->bte_base_addr, BTEOFF_STAT); + BTE_STORE(bte->bte_base_addr, BTEOFF_STAT, bte_status & ~IBLS_BUSY); + + spin_unlock_irqrestore(&hinfo->h_crblock, flags); + bte_free_interfaces(bte, bte->bte_num); + + /* start OLD */ + *nodepda->bte_if[bte->bte_num].most_rcnt_na = IBLS_ERROR; + /* END OLD */ + + BTE_RECOVER_UNLOCK(bte); + + switch(bte->bh_error) { + case IIO_ICRB_ECODE_PERR: + return(BTEFAIL_POISON); + case IIO_ICRB_ECODE_WERR: + return(BTEFAIL_PROT); + case IIO_ICRB_ECODE_AERR: + return(BTEFAIL_ACCESS); + case IIO_ICRB_ECODE_TOUT: + return(BTEFAIL_TOUT); + case IIO_ICRB_ECODE_XTERR: + return(BTEFAIL_ERROR); + case IIO_ICRB_ECODE_DERR: + return(BTEFAIL_DIR); + case IIO_ICRB_ECODE_PWERR: + case IIO_ICRB_ECODE_PRERR: + /* NO BREAK */ + default: + printk("BTE failure (%d) unexpected\n", bte->bh_error); + return(BTEFAIL_ERROR); } + } -#endif // BTE_ERROR void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, - int crbnum, ioerror_t *ioe) + int crbnum, ioerror_t *ioe, int bteop) /* * Function: bte_crb_error_handler * Purpose: Process a CRB for a specific HUB/BTE @@ -159,32 +269,54 @@ */ { hubinfo_t hinfo; + bteinfo_t *bte; icrba_t crba; icrbb_t crbb; nasid_t n; hubinfo_get(hub_v, &hinfo); + bte = NODE_BTE_INFO(hinfo->h_nodepda, btenum); /* Get BTE structure */ + + /* + * The caller has already figured out the error type, we save that + * in the bte handle structure for the using thread to use. + */ + bte->bh_error = ioe->ie_errortype; n = hinfo->h_nasid; - + /* Step 1 */ crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum)); - crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum)); - - - /* Zero error and error code to prevent error_dump complaining - * about these CRBs. + crba.a_addr = TO_PHYS((u64)&bte->crb_flush) >> 3; + crba.a_valid=1; + + /* Step 2 */ + /* + * Zero error and error code to prevent error_dump complaining + * about these CRBs. Copy the CRB to the notification line. + * The crb address is in shub format (physical address shifted + * right by cacheline size). */ + crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum)); crbb.b_error=0; crbb.b_ecode=0; - /* Step 2 */ - REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval); /* Step 3 */ + REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval); + REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval); + REMOTE_HUB_S(n, IIO_ICCR, IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum); + while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING) ; + + /* + * Let waiting process see the error. + */ + if (bte->notify & IBLS_BUSY) { + bte->notify = IBLS_ERROR; + } } diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/efi-rtc.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/efi-rtc.c --- linux-2.4.19/arch/ia64/sn/io/sn2/efi-rtc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/efi-rtc.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,202 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2001 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No locking necessary when this is called from efirtc which protects us + * from racing by efi_rtc_lock. + */ +#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3)) +#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr)) +#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data)) + +#define TOD_SGS_M48T35 1 +#define TOD_DALLAS_DS1386 2 + +#define TYPE_IOC3 1 +#define TYPE_IOC4 2 + +static unsigned long nvram_base = 0; +static int tod_chip_type; +static int ioc_type; + +static int +get_tod_chip_type(void) +{ + unsigned char testval; + + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + write_io_port(RTC_DAL_DAY_ADDR, 0xff); + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + + testval = read_io_port(RTC_DAL_DAY_ADDR); + if (testval == 0xff) + return TOD_SGS_M48T35; + + return TOD_DALLAS_DS1386; +} + +efi_status_t +ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps) +{ + if (!nvram_base) { + printk(KERN_CRIT "nvram_base is zero\n"); + return EFI_UNSUPPORTED; + } + + memset(time, 0, sizeof(*time)); + + switch (tod_chip_type) { + case TOD_SGS_M48T35: + write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT); + + time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF; + time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR)); + time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR)); + time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR)); + time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR)); + time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR)); + time->nanosecond = 0; + + write_io_port(RTC_SGS_CONTROL_ADDR, 0); + break; + + case TOD_DALLAS_DS1386: + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + + time->nanosecond = 0; + time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR)); + time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR)); + time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR)); + time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR)); + time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR)); + time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF; + + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + break; + + default: + break; + } + + if (caps) { + caps->resolution = 50000000; /* 50PPM */ + caps->accuracy = 1000; /* 1ms */ + caps->sets_to_zero = 0; + } + + return EFI_SUCCESS; +} + +static efi_status_t ioc3_set_time (efi_time_t *t) +{ + if (!nvram_base) { + printk(KERN_CRIT "nvram_base is zero\n"); + return EFI_UNSUPPORTED; + } + + switch (tod_chip_type) { + case TOD_SGS_M48T35: + write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE); + write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); + write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month)); + write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day)); + write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour)); + write_io_port(RTC_SGS_MIN_ADDR, INT_TO_BCD(t->minute)); + write_io_port(RTC_SGS_SEC_ADDR, INT_TO_BCD(t->second)); + write_io_port(RTC_SGS_CONTROL_ADDR, 0); + break; + + case TOD_DALLAS_DS1386: + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); + write_io_port(RTC_DAL_SEC_ADDR, INT_TO_BCD(t->second)); + write_io_port(RTC_DAL_MIN_ADDR, INT_TO_BCD(t->minute)); + write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour)); + write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day)); + write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month)); + write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); + write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +/* The following two are not supported atm. */ +static efi_status_t +ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t +ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) +{ + return EFI_UNSUPPORTED; +} + +static __init int efi_ioc_time_init(void) +{ + struct pci_dev *dev = NULL; + static void *ioc_base; + + while ( (dev = pci_find_subsys(PCI_VENDOR_ID_SGI, + PCI_ANY_ID, + PCI_ANY_ID, + PCI_ANY_ID, dev))) { + if ( dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { + ioc_type = TYPE_IOC3; + break; + } + else if ( dev->device == PCI_DEVICE_ID_SGI_IOC4 ) { + ioc_type = TYPE_IOC4; + break; + } + else + ;; // keep looking + } + + if ( !dev ) { + printk(KERN_CRIT "Couldn't find master IOC\n"); + return -ENODEV; + } + + ioc_base = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + if ( ioc_type == TYPE_IOC3 ) + nvram_base = (unsigned long) ioc_base + IOC3_BYTEBUS_DEV0; + if ( ioc_type == TYPE_IOC4 ) + nvram_base = (unsigned long) ioc_base + IOC4_BYTEBUS_DEV0; + + tod_chip_type = get_tod_chip_type(); + if (tod_chip_type == 1) + printk(KERN_NOTICE "TOD type is SGS M48T35\n"); + else if (tod_chip_type == 2) + printk(KERN_NOTICE "TOD type is Dallas DS1386\n"); + else + printk(KERN_CRIT "No or unknown TOD\n"); + + efi.get_time = ioc3_get_time; + efi.set_time = ioc3_set_time; + efi.get_wakeup_time = ioc3_get_wakeup_time; + efi.set_wakeup_time = ioc3_set_wakeup_time; + + return 0; +} + +module_init(efi_ioc_time_init); diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/geo_op.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/geo_op.c --- linux-2.4.19/arch/ia64/sn/io/sn2/geo_op.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/geo_op.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,314 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * @doc file m:hwcfg + * DESCRIPTION: + * + * This file contains routines for manipulating and generating + * Geographic IDs. They are in a file by themself since they have + * no dependencies on other modules. + * + * ORIGIN: + * + * New for SN2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********** Global functions and data (visible outside the module) ***********/ + +/* + * @doc gf:geo_module + * + * moduleid_t geo_module(geoid_t g) + * + * DESCRIPTION: + * + * Return the moduleid component of a geoid. + * + * INTERNALS: + * + * Return INVALID_MODULE for an invalid geoid. Otherwise extract the + * moduleid from the structure, and return it. + * + * ORIGIN: + * + * New for SN2 + */ + +moduleid_t +geo_module(geoid_t g) +{ + if (g.any.type == GEO_TYPE_INVALID) + return INVALID_MODULE; + else + return g.any.module; +} + + +/* + * @doc gf:geo_slab + * + * slabid_t geo_slab(geoid_t g) + * + * DESCRIPTION: + * + * Return the slabid component of a geoid. + * + * INTERNALS: + * + * Return INVALID_SLAB for an invalid geoid. Otherwise extract the + * slabid from the structure, and return it. + * + * ORIGIN: + * + * New for SN2 + */ + +slabid_t +geo_slab(geoid_t g) +{ + if (g.any.type == GEO_TYPE_INVALID) + return INVALID_SLAB; + else + return g.any.slab; +} + + +/* + * @doc gf:geo_type + * + * geo_type_t geo_type(geoid_t g) + * + * DESCRIPTION: + * + * Return the type component of a geoid. + * + * INTERNALS: + * + * Extract the type from the structure, and return it. + * + * ORIGIN: + * + * New for SN2 + */ + +geo_type_t +geo_type(geoid_t g) +{ + return g.any.type; +} + + +/* + * @doc gf:geo_valid + * + * int geo_valid(geoid_t g) + * + * DESCRIPTION: + * + * Return nonzero if g has a valid geoid type. + * + * INTERNALS: + * + * Test the type against GEO_TYPE_INVALID, and return the result. + * + * ORIGIN: + * + * New for SN2 + */ + +int +geo_valid(geoid_t g) +{ + return g.any.type != GEO_TYPE_INVALID; +} + + +/* + * @doc gf:geo_cmp + * + * int geo_cmp(geoid_t g0, geoid_t g1) + * + * DESCRIPTION: + * + * Compare two geoid_t values, from the coarsest field to the finest. + * The comparison should be consistent with the physical locations of + * of the hardware named by the geoids. + * + * INTERNALS: + * + * First compare the module, then the slab, type, and type-specific fields. + * + * ORIGIN: + * + * New for SN2 + */ + +int +geo_cmp(geoid_t g0, geoid_t g1) +{ + int rv; + + /* Compare the common fields */ + rv = MODULE_CMP(geo_module(g0), geo_module(g1)); + if (rv != 0) + return rv; + + rv = geo_slab(g0) - geo_slab(g1); + if (rv != 0) + return rv; + + /* Within a slab, sort by type */ + rv = geo_type(g0) - geo_type(g1); + if (rv != 0) + return rv; + + switch(geo_type(g0)) { + case GEO_TYPE_CPU: + rv = g0.cpu.slice - g1.cpu.slice; + break; + + case GEO_TYPE_IOCARD: + rv = g0.pcicard.bus - g1.pcicard.bus; + if (rv) break; + rv = SLOTNUM_GETSLOT(g0.pcicard.slot) - + SLOTNUM_GETSLOT(g1.pcicard.slot); + break; + + case GEO_TYPE_MEM: + rv = g0.mem.membus - g1.mem.membus; + if (rv) break; + rv = g0.mem.memslot - g1.mem.memslot; + break; + + default: + rv = 0; + } + + return rv; +} + + +/* + * @doc gf:geo_new + * + * geoid_t geo_new(geo_type_t type, ...) + * + * DESCRIPTION: + * + * Generate a new geoid_t value of the given type from its components. + * Expected calling sequences: + * \@itemize \@bullet + * \@item + * \@code\{geo_new(GEO_TYPE_INVALID)\} + * \@item + * \@code\{geo_new(GEO_TYPE_MODULE, moduleid_t m)\} + * \@item + * \@code\{geo_new(GEO_TYPE_NODE, moduleid_t m, slabid_t s)\} + * \@item + * \@code\{geo_new(GEO_TYPE_RTR, moduleid_t m, slabid_t s)\} + * \@item + * \@code\{geo_new(GEO_TYPE_IOCNTL, moduleid_t m, slabid_t s)\} + * \@item + * \@code\{geo_new(GEO_TYPE_IOCARD, moduleid_t m, slabid_t s, char bus, slotid_t slot)\} + * \@item + * \@code\{geo_new(GEO_TYPE_CPU, moduleid_t m, slabid_t s, char slice)\} + * \@item + * \@code\{geo_new(GEO_TYPE_MEM, moduleid_t m, slabid_t s, char membus, char slot)\} + * \@end itemize + * + * Invalid types return a GEO_TYPE_INVALID geoid_t. + * + * INTERNALS: + * + * Use the type to determine which fields to expect. Write the fields into + * a new geoid_t and return it. Note: scalars smaller than an "int" are + * promoted to "int" by the "..." operator, so we need extra casts on "char", + * "slotid_t", and "slabid_t". + * + * ORIGIN: + * + * New for SN2 + */ + +geoid_t +geo_new(geo_type_t type, ...) +{ + va_list al; + geoid_t g; + memset(&g, 0, sizeof(g)); + + va_start(al, type); + + /* Make sure the type is sane */ + if (type >= GEO_TYPE_MAX) + type = GEO_TYPE_INVALID; + + g.any.type = type; + if (type == GEO_TYPE_INVALID) + goto done; /* invalid geoids have no components at all */ + + g.any.module = va_arg(al, moduleid_t); + if (type == GEO_TYPE_MODULE) + goto done; + + g.any.slab = (slabid_t)va_arg(al, int); + + /* Some types have additional components */ + switch(type) { + case GEO_TYPE_CPU: + g.cpu.slice = (char)va_arg(al, int); + break; + + case GEO_TYPE_IOCARD: + g.pcicard.bus = (char)va_arg(al, int); + g.pcicard.slot = (slotid_t)va_arg(al, int); + break; + + case GEO_TYPE_MEM: + g.mem.membus = (char)va_arg(al, int); + g.mem.memslot = (char)va_arg(al, int); + break; + + default: + break; + } + + done: + va_end(al); + return g; +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/kdba_io.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/kdba_io.c --- linux-2.4.19/arch/ia64/sn/io/sn2/kdba_io.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/kdba_io.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,78 @@ +/* + * Kernel Debugger Architecture Dependent POD functions. + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +//#include + +/** + * kdba_io - enter POD mode from kdb + * @argc: arg count + * @argv: arg values + * @envp: kdb env. vars + * @regs: current register state + * + * Enter POD mode from kdb using SGI SN specific SAL function call. + */ +static int +kdba_io(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_printf("kdba_io entered with addr 0x%p\n", (void *) regs); + + return(0); +} + +/** + * kdba_io_init - register 'io' command with kdb + * + * Register the 'io' command with kdb at load time. + */ +void +kdba_io_init(void) +{ + kdb_register("io", kdba_io, "", "Display IO Contents", 0); + + return 0; +} + +/** + * kdba_io_exit - unregister the 'io' command + * + * Tell kdb that the 'io' command is no longer available. + */ +static void __exit +kdba_exit(void) +{ + kdb_unregister("io"); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/klconflib.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/klconflib.c --- linux-2.4.19/arch/ia64/sn/io/sn2/klconflib.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/klconflib.c Tue Feb 11 17:20:34 2003 @@ -0,0 +1,942 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define printf printk +int hasmetarouter; + +#define LDEBUG 0 +#define NIC_UNKNOWN ((nic_t) -1) + +#undef DEBUG_KLGRAPH +#ifdef DEBUG_KLGRAPH +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG_KLGRAPH */ + +static void sort_nic_names(lboard_t *) ; + +u64 klgraph_addr[MAX_COMPACT_NODES]; +int module_number = 0; + +lboard_t * +find_lboard(lboard_t *start, unsigned char brd_type) +{ + /* Search all boards stored on this node. */ + while (start) { + if (start->brd_type == brd_type) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_class(lboard_t *start, unsigned char brd_type) +{ + /* Search all boards stored on this node. */ + while (start) { + if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +klinfo_t * +find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) +{ + int index, j; + + if (kli == (klinfo_t *)NULL) { + index = 0; + } else { + for (j = 0; j < KLCF_NUM_COMPS(brd); j++) { + if (kli == KLCF_COMP(brd, j)) + break; + } + index = j; + if (index == KLCF_NUM_COMPS(brd)) { + DBG("find_component: Bad pointer: 0x%p\n", kli); + return (klinfo_t *)NULL; + } + index++; /* next component */ + } + + for (; index < KLCF_NUM_COMPS(brd); index++) { + kli = KLCF_COMP(brd, index); + DBG("find_component: brd %p kli %p request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli)); + if (KLCF_COMP_TYPE(kli) == struct_type) + return kli; + } + + /* Didn't find it. */ + return (klinfo_t *)NULL; +} + +klinfo_t * +find_first_component(lboard_t *brd, unsigned char struct_type) +{ + return find_component(brd, (klinfo_t *)NULL, struct_type); +} + +lboard_t * +find_lboard_modslot(lboard_t *start, geoid_t geoid) +{ + /* Search all boards stored on this node. */ + while (start) { + if (geo_cmp(start->brd_geoid, geoid)) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_module(lboard_t *start, geoid_t geoid) +{ + /* Search all boards stored on this node. */ + while (start) { + if (geo_cmp(start->brd_geoid, geoid)) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_module_class(lboard_t *start, geoid_t geoid, + unsigned char brd_type) +{ + while (start) { + DBG("find_lboard_module_class: lboard 0x%p, start->brd_geoid 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_geoid, geoid, start->brd_type, brd_type); + + if (geo_cmp(start->brd_geoid, geoid) && + (KLCLASS(start->brd_type) == KLCLASS(brd_type))) + return start; + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +/* + * Convert a NIC name to a name for use in the hardware graph. + */ +void +nic_name_convert(char *old_name, char *new_name) +{ + int i; + char c; + char *compare_ptr; + + if ((old_name[0] == '\0') || (old_name[1] == '\0')) { + strcpy(new_name, EDGE_LBL_XWIDGET); + } else { + for (i = 0; i < strlen(old_name); i++) { + c = old_name[i]; + + if (isalpha(c)) + new_name[i] = tolower(c); + else if (isdigit(c)) + new_name[i] = c; + else + new_name[i] = '_'; + } + new_name[i] = '\0'; + } + + /* XXX - + * Since a bunch of boards made it out with weird names like + * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and + * replace it with "baseio" to avoid confusion in the field. + * We also have to make sure we don't report media_io instead of + * baseio. + */ + + /* Skip underscores at the beginning of the name */ + for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++) + ; + + /* + * Check for some names we need to replace. Early boards + * had junk following the name so check only the first + * characters. + */ + if (!strncmp(new_name, "io6", 3) || + !strncmp(new_name, "mio", 3) || + !strncmp(new_name, "media_io", 8)) + strcpy(new_name, "baseio"); + else if (!strncmp(new_name, "divo", 4)) + strcpy(new_name, "divo") ; + +} + +/* + * Find the lboard structure and get the board name. + * If we can't find the structure or it's too low a revision, + * use default name. + */ +lboard_t * +get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name) +{ + lboard_t *brd; + + brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), + geoid); + +#ifndef _STANDALONE + { + cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); + + if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) + brd = find_lboard_modslot((lboard_t *) + KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), + geoid); + } +#endif + + if (!brd || (brd->brd_sversion < 2)) { + strcpy(name, EDGE_LBL_XWIDGET); + } else { + nic_name_convert(brd->brd_name, name); + } + + /* + * PV # 540860 + * If the name is not 'baseio' + * get the lowest of all the names in the nic string. + * This is needed for boards like divo, which can have + * a bunch of daughter cards, but would like to be called + * divo. We could do this for baseio + * but it has some special case names that we would not + * like to disturb at this point. + */ + + /* gfx boards don't need any of this name scrambling */ + if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) { + return(brd); + } + + if (!(!strcmp(name, "baseio") )) { + if (brd) { + sort_nic_names(brd) ; + /* Convert to small case, '-' to '_' etc */ + nic_name_convert(brd->brd_name, name) ; + } + } + + return(brd); +} + +/* + * get_actual_nasid + * + * Completely disabled brds have their klconfig on + * some other nasid as they have no memory. But their + * actual nasid is hidden in the klconfig. Use this + * routine to get it. Works for normal boards too. + */ +nasid_t +get_actual_nasid(lboard_t *brd) +{ + klhub_t *hub ; + + if (!brd) + return INVALID_NASID ; + + /* find out if we are a completely disabled brd. */ + + hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + if (!hub) + return INVALID_NASID ; + if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ + return hub->hub_info.physid ; + else + return brd->brd_nasid ; +} + +int +xbow_port_io_enabled(nasid_t nasid, int link) +{ + lboard_t *brd; + klxbow_t *xbow_p; + + /* + * look for boards that might contain an xbow or xbridge + */ + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); + if (brd == NULL) return 0; + + if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) + == NULL) + return 0; + + if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) + return 0; + + return 1; +} + +void +board_to_path(lboard_t *brd, char *path) +{ + moduleid_t modnum; + char *board_name; + char buffer[16]; + + ASSERT(brd); + + switch (KLCLASS(brd->brd_type)) { + + case KLCLASS_NODE: + board_name = EDGE_LBL_NODE; + break; + case KLCLASS_ROUTER: + if (brd->brd_type == KLTYPE_META_ROUTER) { + board_name = EDGE_LBL_META_ROUTER; + hasmetarouter++; + } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { + board_name = EDGE_LBL_REPEATER_ROUTER; + hasmetarouter++; + } else + board_name = EDGE_LBL_ROUTER; + break; + case KLCLASS_MIDPLANE: + board_name = EDGE_LBL_MIDPLANE; + break; + case KLCLASS_IO: + board_name = EDGE_LBL_IO; + break; + case KLCLASS_IOBRICK: + if (brd->brd_type == KLTYPE_PXBRICK) + board_name = EDGE_LBL_PXBRICK; + else if (brd->brd_type == KLTYPE_IXBRICK) + board_name = EDGE_LBL_IXBRICK; + else if (brd->brd_type == KLTYPE_PBRICK) + board_name = EDGE_LBL_PBRICK; + else if (brd->brd_type == KLTYPE_IBRICK) + board_name = EDGE_LBL_IBRICK; + else if (brd->brd_type == KLTYPE_XBRICK) + board_name = EDGE_LBL_XBRICK; + else if (brd->brd_type == KLTYPE_PEBRICK) + board_name = EDGE_LBL_PEBRICK; + else if (brd->brd_type == KLTYPE_CGBRICK) + board_name = EDGE_LBL_CGBRICK; + else + board_name = EDGE_LBL_IOBRICK; + break; + default: + board_name = EDGE_LBL_UNKNOWN; + } + + modnum = geo_module(brd->brd_geoid); + memset(buffer, 0, 16); + format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); + sprintf(path, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/%s", buffer, geo_slab(brd->brd_geoid), board_name); +} + +/* + * Get the module number for a NASID. + */ +moduleid_t +get_module_id(nasid_t nasid) +{ + lboard_t *brd; + + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + + if (!brd) + return INVALID_MODULE; + else + return geo_module(brd->brd_geoid); +} + + +#define MHZ 1000000 + + +/* Get the canonical hardware graph name for the given pci component + * on the given io board. + */ +void +device_component_canonical_name_get(lboard_t *brd, + klinfo_t *component, + char *name) +{ + slotid_t slot; + char board_name[20]; + + ASSERT(brd); + + /* Convert the [ CLASS | TYPE ] kind of slotid + * into a string + */ + slot = brd->brd_slot; + + /* Get the io board name */ + if (!brd || (brd->brd_sversion < 2)) { + strcpy(name, EDGE_LBL_XWIDGET); + } else { + nic_name_convert(brd->brd_name, board_name); + } + + /* Give out the canonical name of the pci device*/ + sprintf(name, + "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLAB"/%d/" + EDGE_LBL_SLOT"/%s/"EDGE_LBL_PCI"/%d", + geo_module(brd->brd_geoid), geo_slab(brd->brd_geoid), + board_name, KLCF_BRIDGE_W_ID(component)); +} + +/* + * Get the serial number of the main component of a board + * Returns 0 if a valid serial number is found + * 1 otherwise. + * Assumptions: Nic manufacturing string has the following format + * *Serial:;* + */ +static int +component_serial_number_get(lboard_t *board, + klconf_off_t mfg_nic_offset, + char *serial_number, + char *key_pattern) +{ + + char *mfg_nic_string; + char *serial_string,*str; + int i; + char *serial_pattern = "Serial:"; + + /* We have an error on a null mfg nic offset */ + if (!mfg_nic_offset) + return(1); + /* Get the hub's manufacturing nic information + * which is in the form of a pre-formatted string + */ + mfg_nic_string = + (char *)NODE_OFFSET_TO_K0(NASID_GET(board), + mfg_nic_offset); + /* There is no manufacturing nic info */ + if (!mfg_nic_string) + return(1); + + str = mfg_nic_string; + /* Look for the key pattern first (if it is specified) + * and then print the serial number corresponding to that. + */ + if (strcmp(key_pattern,"") && + !(str = strstr(mfg_nic_string,key_pattern))) + return(1); + + /* There is no serial number info in the manufacturing + * nic info + */ + if (!(serial_string = strstr(str,serial_pattern))) + return(1); + + serial_string = serial_string + strlen(serial_pattern); + /* Copy the serial number information from the klconfig */ + i = 0; + while (serial_string[i] != ';') { + serial_number[i] = serial_string[i]; + i++; + } + serial_number[i] = 0; + + return(0); +} +/* + * Get the serial number of a board + * Returns 0 if a valid serial number is found + * 1 otherwise. + */ + +int +board_serial_number_get(lboard_t *board,char *serial_number) +{ + ASSERT(board && serial_number); + if (!board || !serial_number) + return(1); + + strcpy(serial_number,""); + switch(KLCLASS(board->brd_type)) { + case KLCLASS_CPU: { /* Node board */ + klhub_t *hub; + + /* Get the hub component information */ + hub = (klhub_t *)find_first_component(board, + KLSTRUCT_HUB); + /* If we don't have a hub component on an IP27 + * then we have a weird klconfig. + */ + if (!hub) + return(1); + /* Get the serial number information from + * the hub's manufacturing nic info + */ + if (component_serial_number_get(board, + hub->hub_mfg_nic, + serial_number, + "IP37")) + return(1); + break; + } + case KLCLASS_IO: { /* IO board */ + if (KLTYPE(board->brd_type) == KLTYPE_TPU) { + /* Special case for TPU boards */ + kltpu_t *tpu; + + /* Get the tpu component information */ + tpu = (kltpu_t *)find_first_component(board, + KLSTRUCT_TPU); + /* If we don't have a tpu component on a tpu board + * then we have a weird klconfig. + */ + if (!tpu) + return(1); + /* Get the serial number information from + * the tpu's manufacturing nic info + */ + if (component_serial_number_get(board, + tpu->tpu_mfg_nic, + serial_number, + "")) + return(1); + break; + } else if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) || + (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) { + /* Special case for GSN boards */ + klgsn_t *gsn; + + /* Get the gsn component information */ + gsn = (klgsn_t *)find_first_component(board, + ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ? + KLSTRUCT_GSN_A : KLSTRUCT_GSN_B)); + /* If we don't have a gsn component on a gsn board + * then we have a weird klconfig. + */ + if (!gsn) + return(1); + /* Get the serial number information from + * the gsn's manufacturing nic info + */ + if (component_serial_number_get(board, + gsn->gsn_mfg_nic, + serial_number, + "")) + return(1); + break; + } else { + klbri_t *bridge; + + /* Get the bridge component information */ + bridge = (klbri_t *)find_first_component(board, + KLSTRUCT_BRI); + /* If we don't have a bridge component on an IO board + * then we have a weird klconfig. + */ + if (!bridge) + return(1); + /* Get the serial number information from + * the bridge's manufacturing nic info + */ + if (component_serial_number_get(board, + bridge->bri_mfg_nic, + serial_number, + "")) + return(1); + break; + } + } + case KLCLASS_ROUTER: { /* Router board */ + klrou_t *router; + + /* Get the router component information */ + router = (klrou_t *)find_first_component(board, + KLSTRUCT_ROU); + /* If we don't have a router component on a router board + * then we have a weird klconfig. + */ + if (!router) + return(1); + /* Get the serial number information from + * the router's manufacturing nic info + */ + if (component_serial_number_get(board, + router->rou_mfg_nic, + serial_number, + "")) + return(1); + break; + } + case KLCLASS_GFX: { /* Gfx board */ + klgfx_t *graphics; + + /* Get the graphics component information */ + graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX); + /* If we don't have a gfx component on a gfx board + * then we have a weird klconfig. + */ + if (!graphics) + return(1); + /* Get the serial number information from + * the graphics's manufacturing nic info + */ + if (component_serial_number_get(board, + graphics->gfx_mfg_nic, + serial_number, + "")) + return(1); + break; + } + default: + strcpy(serial_number,""); + break; + } + return(0); +} + +#include "asm/sn/sn_private.h" + +xwidgetnum_t +nodevertex_widgetnum_get(devfs_handle_t node_vtx) +{ + hubinfo_t hubinfo_p; + + hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, + (arbitrary_info_t *) &hubinfo_p); + return(hubinfo_p->h_widgetid); +} + +devfs_handle_t +nodevertex_xbow_peer_get(devfs_handle_t node_vtx) +{ + hubinfo_t hubinfo_p; + nasid_t xbow_peer_nasid; + cnodeid_t xbow_peer; + + hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, + (arbitrary_info_t *) &hubinfo_p); + xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer; + if(xbow_peer_nasid == INVALID_NASID) + return ( (devfs_handle_t)-1); + xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid); + return(NODEPDA(xbow_peer)->node_vertex); +} + +/* NIC Sorting Support */ + +#define MAX_NICS_PER_STRING 32 +#define MAX_NIC_NAME_LEN 32 + +static char * +get_nic_string(lboard_t *lb) +{ + int i; + klinfo_t *k = NULL ; + klconf_off_t mfg_off = 0 ; + char *mfg_nic = NULL ; + + for (i = 0; i < KLCF_NUM_COMPS(lb); i++) { + k = KLCF_COMP(lb, i) ; + switch(k->struct_type) { + case KLSTRUCT_BRI: + mfg_off = ((klbri_t *)k)->bri_mfg_nic ; + break ; + + case KLSTRUCT_HUB: + mfg_off = ((klhub_t *)k)->hub_mfg_nic ; + break ; + + case KLSTRUCT_ROU: + mfg_off = ((klrou_t *)k)->rou_mfg_nic ; + break ; + + case KLSTRUCT_GFX: + mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ; + break ; + + case KLSTRUCT_TPU: + mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ; + break ; + + case KLSTRUCT_GSN_A: + case KLSTRUCT_GSN_B: + mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ; + break ; + + case KLSTRUCT_XTHD: + mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ; + break; + + default: + mfg_off = 0 ; + break ; + } + if (mfg_off) + break ; + } + + if ((mfg_off) && (k)) + mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ; + + return mfg_nic ; +} + +char * +get_first_string(char **ptrs, int n) +{ + int i ; + char *tmpptr ; + + if ((ptrs == NULL) || (n == 0)) + return NULL ; + + tmpptr = ptrs[0] ; + + if (n == 1) + return tmpptr ; + + for (i = 0 ; i < n ; i++) { + if (strcmp(tmpptr, ptrs[i]) > 0) + tmpptr = ptrs[i] ; + } + + return tmpptr ; +} + +int +get_ptrs(char *idata, char **ptrs, int n, char *label) +{ + int i = 0 ; + char *tmp = idata ; + + if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0)) + return 0 ; + + while ( (tmp = strstr(tmp, label)) ){ + tmp += strlen(label) ; + /* check for empty name field, and last NULL ptr */ + if ((i < (n-1)) && (*tmp != ';')) { + ptrs[i++] = tmp ; + } + } + + ptrs[i] = NULL ; + + return i ; +} + +/* + * sort_nic_names + * + * Does not really do sorting. Find the alphabetically lowest + * name among all the nic names found in a nic string. + * + * Return: + * Nothing + * + * Side Effects: + * + * lb->brd_name gets the new name found + */ + +static void +sort_nic_names(lboard_t *lb) +{ + char *nic_str ; + char *ptrs[MAX_NICS_PER_STRING] ; + char name[MAX_NIC_NAME_LEN] ; + char *tmp, *tmp1 ; + + *name = 0 ; + + /* Get the nic pointer from the lb */ + + if ((nic_str = get_nic_string(lb)) == NULL) + return ; + + tmp = get_first_string(ptrs, + get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ; + + if (tmp == NULL) + return ; + + if ( (tmp1 = strchr(tmp, ';')) ){ + strncpy(name, tmp, tmp1-tmp) ; + name[tmp1-tmp] = 0 ; + } else { + strncpy(name, tmp, (sizeof(name) -1)) ; + name[sizeof(name)-1] = 0 ; + } + + strcpy(lb->brd_name, name) ; +} + + + +char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#=012345"; + +/* + * Format a module id for printing. + */ +void +format_module_id(char *buffer, moduleid_t m, int fmt) +{ + int rack, position; + char brickchar; + + rack = MODULE_GET_RACK(m); + ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); + brickchar = MODULE_GET_BTCHAR(m); + + position = MODULE_GET_BPOS(m); + + if (fmt == MODULE_FORMAT_BRIEF) { + /* Brief module number format, eg. 002c15 */ + + /* Decompress the rack number */ + *buffer++ = '0' + RACK_GET_CLASS(rack); + *buffer++ = '0' + RACK_GET_GROUP(rack); + *buffer++ = '0' + RACK_GET_NUM(rack); + + /* Add the brick type */ + *buffer++ = brickchar; + } + else if (fmt == MODULE_FORMAT_LONG) { + /* Fuller hwgraph format, eg. rack/002/bay/15 */ + + strcpy(buffer, EDGE_LBL_RACK "/"); buffer += strlen(buffer); + + *buffer++ = '0' + RACK_GET_CLASS(rack); + *buffer++ = '0' + RACK_GET_GROUP(rack); + *buffer++ = '0' + RACK_GET_NUM(rack); + + strcpy(buffer, "/" EDGE_LBL_RPOS "/"); buffer += strlen(buffer); + } + + /* Add the bay position, using at least two digits */ + if (position < 10) + *buffer++ = '0'; + sprintf(buffer, "%d", position); + +} + +/* + * Parse a module id, in either brief or long form. + * Returns < 0 on error. + * The long form does not include a brick type, so it defaults to 0 (CBrick) + */ +int +parse_module_id(char *buffer) +{ + unsigned int v, rack, bay, type, form; + moduleid_t m; + char c; + + if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) { + form = MODULE_FORMAT_LONG; + buffer += strlen(EDGE_LBL_RACK "/"); + + /* A long module ID must be exactly 5 non-template chars. */ + if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5) + return -1; + } + else { + form = MODULE_FORMAT_BRIEF; + + /* A brief module id must be exactly 6 characters */ + if (strlen(buffer) != 6) + return -2; + } + + /* The rack number must be exactly 3 digits */ + if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2]))) + return -3; + + rack = 0; + v = *buffer++ - '0'; + if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) + return -4; + RACK_ADD_CLASS(rack, v); + + v = *buffer++ - '0'; + if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) + return -5; + RACK_ADD_GROUP(rack, v); + + v = *buffer++ - '0'; + /* rack numbers are 1-based */ + if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) + return -6; + RACK_ADD_NUM(rack, v); + + if (form == MODULE_FORMAT_BRIEF) { + /* Next should be a module type character. Accept ucase or lcase. */ + c = *buffer++; + if (!isalpha(c)) + return -7; + + /* strchr() returns a pointer into brick_types[], or NULL */ + type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types); + if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT) + return -8; + } + else { + /* Hardcode the module type, and skip over the boilerplate */ + type = MODULE_CBRICK; + + if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer) + return -9; + + buffer += strlen("/" EDGE_LBL_RPOS "/"); + } + + /* The bay number is last. Make sure it's exactly two digits */ + + if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2])) + return -10; + + bay = 10 * (buffer[0] - '0') + (buffer[1] - '0'); + + if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) + return -11; + + m = RBT_TO_MODULE(rack, bay, type); + + /* avoid sign extending the moduleid_t */ + return (int)(unsigned short)m; +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/klgraph.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/klgraph.c --- linux-2.4.19/arch/ia64/sn/io/sn2/klgraph.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/klgraph.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,866 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * klgraph.c- + * This file specifies the interface between the kernel and the PROM's + * configuration data structures. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #define KLGRAPH_DEBUG 1 +#ifdef KLGRAPH_DEBUG +#define GRPRINTF(x) printk x +#define CE_GRPANIC CE_PANIC +#else +#define GRPRINTF(x) +#define CE_GRPANIC CE_PANIC +#endif + +#include + +extern char arg_maxnodes[]; +extern u64 klgraph_addr[]; +void mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid); + + +/* + * Support for verbose inventory via hardware graph. + * klhwg_invent_alloc allocates the necessary size of inventory information + * and fills in the generic information. + */ +invent_generic_t * +klhwg_invent_alloc(cnodeid_t cnode, int class, int size) +{ + invent_generic_t *invent; + + invent = kern_malloc(size); + if (!invent) return NULL; + + invent->ig_module = NODE_MODULEID(cnode); + invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode)); + invent->ig_invclass = class; + + return invent; +} + +/* + * Add detailed disabled cpu inventory info to the hardware graph. + */ +void +klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv, + cnodeid_t cnode, + klcpu_t *cpu, slotid_t slot) +{ + invent_cpuinfo_t *cpu_invent; + diag_inv_t *diag_invent; + + cpu_invent = (invent_cpuinfo_t *) + klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t)); + if (!cpu_invent) + return; + + /* Diag information on this processor */ + diag_invent = (diag_inv_t *) + klhwg_invent_alloc(cnode, INV_CPUDIAGVAL, sizeof(diag_inv_t)); + + if (!diag_invent) + return; + + + /* Disabled CPU */ + cpu_invent->ic_gen.ig_flag = 0x0; + cpu_invent->ic_gen.ig_slot = slot; + cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid; + cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed; + cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed; + + cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz; + cpu_invent->ic_cpuid = cpu->cpu_info.virtid; + cpu_invent->ic_slice = cpu->cpu_info.physid; + + /* Disabled CPU label */ + hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) cpu_invent); + hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + sizeof(invent_cpuinfo_t)); + + /* Diagval label - stores reason for disable +{virt,phys}id +diagval*/ + hwgraph_info_add_LBL(cpuv, INFO_LBL_DIAGVAL, + (arbitrary_info_t) diag_invent); + + hwgraph_info_export_LBL(cpuv, INFO_LBL_DIAGVAL, + sizeof(diag_inv_t)); +} + +/* + * Add detailed cpu inventory info to the hardware graph. + */ +void +klhwg_cpu_invent_info(devfs_handle_t cpuv, + cnodeid_t cnode, + klcpu_t *cpu) +{ + invent_cpuinfo_t *cpu_invent; + + cpu_invent = (invent_cpuinfo_t *) + klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t)); + if (!cpu_invent) + return; + + if (KLCONFIG_INFO_ENABLED((klinfo_t *)cpu)) + cpu_invent->ic_gen.ig_flag = INVENT_ENABLED; + else + cpu_invent->ic_gen.ig_flag = 0x0; + + cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid; + cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed; + cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed; + + cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz; + cpu_invent->ic_cpuid = cpu->cpu_info.virtid; + cpu_invent->ic_slice = cpu_physical_id_to_slice(cpu->cpu_info.virtid); + + hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) cpu_invent); + hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT, + sizeof(invent_cpuinfo_t)); +} + +/* + * Add information about the baseio prom version number + * as a part of detailed inventory info in the hwgraph. + */ +void +klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) +{ + invent_miscinfo_t *baseio_inventory; + unsigned char version = 0,revision = 0; + + /* Allocate memory for the "detailed inventory" info + * for the baseio + */ + baseio_inventory = (invent_miscinfo_t *) + klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); + baseio_inventory->im_type = INV_IO6PROM; + /* Store the revision info in the inventory */ + baseio_inventory->im_version = version; + baseio_inventory->im_rev = revision; + /* Put the inventory info in the hardware graph */ + hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) baseio_inventory); + /* Make the information available to the user programs + * thru hwgfs. + */ + hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, + sizeof(invent_miscinfo_t)); +} + +char *hub_rev[] = { + "0.0", + "1.0", + "2.0", + "2.1", + "2.2", + "2.3" +}; + +/* + * Add detailed cpu inventory info to the hardware graph. + */ +void +klhwg_hub_invent_info(devfs_handle_t hubv, + cnodeid_t cnode, + klhub_t *hub) +{ + invent_miscinfo_t *hub_invent; + + hub_invent = (invent_miscinfo_t *) + klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t)); + if (!hub_invent) + return; + + if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub)) + hub_invent->im_gen.ig_flag = INVENT_ENABLED; + + hub_invent->im_type = INV_HUB; + hub_invent->im_rev = hub->hub_info.revision; + hub_invent->im_speed = hub->hub_speed; + hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, + (arbitrary_info_t) hub_invent); + hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT, + sizeof(invent_miscinfo_t)); +} + +/* ARGSUSED */ +void +klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) +{ + devfs_handle_t myhubv; + devfs_handle_t hub_mon; + int rc; + extern struct file_operations shub_mon_fops; + + GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB)); + (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); + rc = device_master_set(myhubv, node_vertex); + hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, + 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &shub_mon_fops, (void *)(long)cnode); +} + +/* ARGSUSED */ +void +klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) +{ + devfs_handle_t my_cpu; + char name[120]; + cpuid_t cpu_id; + nasid_t nasid; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid); + if(cpu_id != -1){ + sprintf(name, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid); + (void) hwgraph_path_add(node_vertex, name, &my_cpu); + + mark_cpuvertex_as_cpu(my_cpu, cpu_id); + device_master_set(my_cpu, node_vertex); + + klhwg_disabled_cpu_invent_info(my_cpu, cnode, cpu, slot); + return; + } +} + +/* ARGSUSED */ +void +klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu) +{ + devfs_handle_t my_cpu, cpu_dir; + char name[120]; + cpuid_t cpu_id; + nasid_t nasid; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid); + + sprintf(name, "%s/%d/%c", + EDGE_LBL_CPUBUS, + 0, + 'a' + cpu->cpu_info.physid); + + GRPRINTF(("klhwg_add_cpu: adding %s to vertex 0x%p\n", name, node_vertex)); + (void) hwgraph_path_add(node_vertex, name, &my_cpu); + mark_cpuvertex_as_cpu(my_cpu, cpu_id); + device_master_set(my_cpu, node_vertex); + + /* Add an alias under the node's CPU directory */ + if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) { + sprintf(name, "%c", 'a' + cpu->cpu_info.physid); + (void) hwgraph_edge_add(cpu_dir, my_cpu, name); + } + + klhwg_cpu_invent_info(my_cpu, cnode, cpu); +} + + +void +klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) +{ + lboard_t *brd; + klxbow_t *xbow_p; + nasid_t hub_nasid; + cnodeid_t hub_cnode; + int widgetnum; + devfs_handle_t xbow_v, hubv; + /*REFERENCED*/ + graph_error_t err; + + if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL) + return; + + if (KL_CONFIG_DUPLICATE_BOARD(brd)) + return; + + GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n", + cnode, nasid)); + + if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) + == NULL) + return; + + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) + continue; + + hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); + if (hub_nasid == INVALID_NASID) { + printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum); + continue; + } + + hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid); + + if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) { + continue; + } + + hubv = cnodeid_to_vertex(hub_cnode); + + err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); + if (err != GRAPH_SUCCESS) { + if (err == GRAPH_DUP) + printk(KERN_WARNING "klhwg_add_xbow: Check for " + "working routers and router links!"); + + PRINT_PANIC("klhwg_add_xbow: Failed to add " + "edge: vertex 0x%p to vertex 0x%p," + "error %d\n", + (void *)hubv, (void *)xbow_v, err); + } + xswitch_vertex_init(xbow_v); + + NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; + + /* + * XXX - This won't work is we ever hook up two hubs + * by crosstown through a crossbow. + */ + if (hub_nasid != nasid) { + NODEPDA(hub_cnode)->xbow_peer = nasid; + NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer = + hub_nasid; + } + + GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n", + hub_nasid, EDGE_LBL_XTALK, hubv)); + } +} + + +/* ARGSUSED */ +void +klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) +{ + nasid_t nasid; + lboard_t *brd; + klhub_t *hub; + devfs_handle_t node_vertex = NULL; + char path_buffer[100]; + int rv; + char *s; + int board_disabled = 0; + klcpu_t *cpu; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n", + cnode, nasid, brd)); + ASSERT(brd); + + do { + devfs_handle_t cpu_dir; + + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n", + path_buffer, hwgraph_root)); + rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); + + if (rv != GRAPH_SUCCESS) + PRINT_PANIC("Node vertex creation failed. " + "Path == %s", + path_buffer); + + hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + ASSERT(hub); + if(hub->hub_info.flags & KLINFO_ENABLE) + board_disabled = 0; + else + board_disabled = 1; + + if(!board_disabled) { + mark_nodevertex_as_node(node_vertex, + cnode + board_disabled * numnodes); + + s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); + NODEPDA(cnode)->hwg_node_name = + kmalloc(strlen(s) + 1, + GFP_KERNEL); + ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL); + strcpy(NODEPDA(cnode)->hwg_node_name, s); + + hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo); + + /* Set up node board's slot */ + NODEPDA(cnode)->slotdesc = brd->brd_slot; + + /* Set up the module we're in */ + NODEPDA(cnode)->geoid = brd->brd_geoid; + NODEPDA(cnode)->module = module_lookup(geo_module(brd->brd_geoid)); + } + + /* Get the first CPU structure */ + cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU); + + /* + * If there's at least 1 CPU, add a "cpu" directory to represent + * the collection of all CPUs attached to this node. + */ + if (cpu) { + graph_error_t rv; + + rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir); + if (rv != GRAPH_SUCCESS) + panic("klhwg_add_node: Cannot create CPU directory\n"); + } + + /* Add each CPU */ + while (cpu) { + cpuid_t cpu_id; + cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid); + if (cpu_enabled(cpu_id)) + klhwg_add_cpu(node_vertex, cnode, cpu); + else + klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot); + + cpu = (klcpu_t *) + find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU); + } /* while */ + + if(!board_disabled) + klhwg_add_hub(node_vertex, hub, cnode); + + brd = KLCF_NEXT(brd); + if (brd) + brd = find_lboard(brd, KLTYPE_SNIA); + else + break; + } while(brd); +} + + +/* ARGSUSED */ +void +klhwg_add_all_routers(devfs_handle_t hwgraph_root) +{ + nasid_t nasid; + cnodeid_t cnode; + lboard_t *brd; + devfs_handle_t node_vertex; + char path_buffer[100]; + int rv; + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + + GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n", + cnode)); + + brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), + KLTYPE_ROUTER); + + if (!brd) + /* No routers stored in this node's memory */ + continue; + + do { + ASSERT(brd); + GRPRINTF(("Router board struct is %p\n", brd)); + + /* Don't add duplicate boards. */ + if (brd->brd_flags & DUPLICATE_BOARD) + continue; + + GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_geoid)); + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + GRPRINTF(("Router path is %s\n", path_buffer)); + + /* Add the router */ + GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n", + path_buffer, hwgraph_root)); + rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); + + if (rv != GRAPH_SUCCESS) + PRINT_PANIC("Router vertex creation " + "failed. Path == %s", + path_buffer); + + GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n", + brd)); + /* Find the rest of the routers stored on this node. */ + } while ( (brd = find_lboard_class(KLCF_NEXT(brd), + KLTYPE_ROUTER)) ); + + GRPRINTF(("klhwg_add_all_routers: Done.\n")); + } + +} + +/* ARGSUSED */ +void +klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, + cnodeid_t cnode, nasid_t nasid) +{ + klrou_t *router; + char path_buffer[50]; + char dest_path[50]; + devfs_handle_t router_hndl; + devfs_handle_t dest_hndl; + int rc; + int port; + lboard_t *dest_brd; + + GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n", + cnode)); + + /* Don't add duplicate boards. */ + if (brd->brd_flags & DUPLICATE_BOARD) { + GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n", + brd, cnode)); + return; + } + + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl); + + if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes)) + return; + + if (rc != GRAPH_SUCCESS) + printk(KERN_WARNING "Can't find router: %s", path_buffer); + + /* We don't know what to do with multiple router components */ + if (brd->brd_numcompts != 1) { + PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n", + brd->brd_numcompts); + return; + } + + + /* Convert component 0 to klrou_t ptr */ + router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), + brd->brd_compts[0]); + + for (port = 1; port <= MAX_ROUTER_PORTS; port++) { + /* See if the port's active */ + if (router->rou_port[port].port_nasid == INVALID_NASID) { + GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n", + port)); + continue; + } + if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) + == INVALID_CNODEID) { + continue; + } + + dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( + router->rou_port[port].port_nasid, + router->rou_port[port].port_offset); + + /* Generate a hardware graph path for this board. */ + board_to_path(dest_brd, dest_path); + + rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); + + if (rc != GRAPH_SUCCESS) { + if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) + continue; + PRINT_PANIC("Can't find router: %s", dest_path); + } + GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n", + path_buffer, port, dest_path)); + + sprintf(dest_path, "%d", port); + + rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path); + + if (rc == GRAPH_DUP) { + GRPRINTF(("Skipping port %d. nasid %d %s/%s\n", + port, router->rou_port[port].port_nasid, + path_buffer, dest_path)); + continue; + } + + if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", + path_buffer, dest_path, (void *)dest_hndl, rc); + + } +} + + +void +klhwg_connect_routers(devfs_handle_t hwgraph_root) +{ + nasid_t nasid; + cnodeid_t cnode; + lboard_t *brd; + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + + GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n", + cnode)); + + brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), + KLTYPE_ROUTER); + + if (!brd) + continue; + + do { + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + klhwg_connect_one_router(hwgraph_root, brd, + cnode, nasid); + + /* Find the rest of the routers stored on this node. */ + } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); + } +} + + + +void +klhwg_connect_hubs(devfs_handle_t hwgraph_root) +{ + nasid_t nasid; + cnodeid_t cnode; + lboard_t *brd; + klhub_t *hub; + lboard_t *dest_brd; + devfs_handle_t hub_hndl; + devfs_handle_t dest_hndl; + char path_buffer[50]; + char dest_path[50]; + graph_error_t rc; + int port; + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + + GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n", + cnode)); + + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + ASSERT(brd); + + hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + ASSERT(hub); + + for (port = 1; port <= MAX_NI_PORTS; port++) { + /* See if the port's active */ + if (hub->hub_port[port].port_nasid == INVALID_NASID) { + GRPRINTF(("klhwg_connect_hubs: port inactive.\n")); + continue; + } + + if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port[port].port_nasid) == INVALID_CNODEID) + continue; + + /* Generate a hardware graph path for this board. */ + board_to_path(brd, path_buffer); + + GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer)); + rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); + + if (rc != GRAPH_SUCCESS) + printk(KERN_WARNING "Can't find hub: %s", path_buffer); + + dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( + hub->hub_port[port].port_nasid, + hub->hub_port[port].port_offset); + + /* Generate a hardware graph path for this board. */ + board_to_path(dest_brd, dest_path); + + rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); + + if (rc != GRAPH_SUCCESS) { + if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) + continue; + PRINT_PANIC("Can't find board: %s", dest_path); + } else { + char buf[1024]; + + + GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n", + path_buffer, dest_path)); + + rc = hwgraph_path_add(hub_hndl, EDGE_LBL_INTERCONNECT, &hub_hndl); + sprintf(buf,"%s/%s",path_buffer,EDGE_LBL_INTERCONNECT); + rc = hwgraph_traverse(hwgraph_root, buf, &hub_hndl); + sprintf(buf,"%d",port); + rc = hwgraph_edge_add(hub_hndl, dest_hndl, buf); + + if (rc != GRAPH_SUCCESS) + PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", + path_buffer, dest_path, (void *)dest_hndl, rc); + + } + } + } +} + +/* Store the pci/vme disabled board information as extended administrative + * hints which can later be used by the drivers using the device/driver + * admin interface. + */ +void +klhwg_device_disable_hints_add(void) +{ + cnodeid_t cnode; /* node we are looking at */ + nasid_t nasid; /* nasid of the node */ + lboard_t *board; /* board we are looking at */ + int comp_index; /* component index */ + klinfo_t *component; /* component in the board we are + * looking at + */ + char device_name[MAXDEVNAME]; + + for(cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + board = (lboard_t *)KL_CONFIG_INFO(nasid); + /* Check out all the board info stored on a node */ + while(board) { + /* No need to look at duplicate boards or non-io + * boards + */ + if (KL_CONFIG_DUPLICATE_BOARD(board) || + KLCLASS(board->brd_type) != KLCLASS_IO) { + board = KLCF_NEXT(board); + continue; + } + /* Check out all the components of a board */ + for (comp_index = 0; + comp_index < KLCF_NUM_COMPS(board); + comp_index++) { + component = KLCF_COMP(board,comp_index); + /* If the component is enabled move on to + * the next component + */ + if (KLCONFIG_INFO_ENABLED(component)) + continue; + /* NOTE : Since the prom only supports + * the disabling of pci devices the following + * piece of code makes sense. + * Make sure that this assumption is valid + */ + /* This component is disabled. Store this + * hint in the extended device admin table + */ + /* Get the canonical name of the pci device */ + device_component_canonical_name_get(board, + component, + device_name); +#ifdef DEBUG + printf("%s DISABLED\n",device_name); +#endif + } + /* go to the next board info stored on this + * node + */ + board = KLCF_NEXT(board); + } + } +} + +void +klhwg_add_all_modules(devfs_handle_t hwgraph_root) +{ + cmoduleid_t cm; + char name[128]; + devfs_handle_t vhdl; + devfs_handle_t module_vhdl; + int rc; + char buffer[16]; + + /* Add devices under each module */ + + for (cm = 0; cm < nummodules; cm++) { + /* Use module as module vertex fastinfo */ + + memset(buffer, 0, 16); + format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); + sprintf(name, EDGE_LBL_MODULE "/%s", buffer); + + rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl); + ASSERT(rc == GRAPH_SUCCESS); + rc = rc; + + hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) modules[cm]); + + /* Add system controller */ + sprintf(name, + EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, + buffer); + + rc = hwgraph_path_add(hwgraph_root, name, &vhdl); + ASSERT_ALWAYS(rc == GRAPH_SUCCESS); + rc = rc; + + hwgraph_info_add_LBL(vhdl, + INFO_LBL_ELSC, + (arbitrary_info_t) (__psint_t) 1); + + } +} + +void +klhwg_add_all_nodes(devfs_handle_t hwgraph_root) +{ + cnodeid_t cnode; + + for (cnode = 0; cnode < numnodes; cnode++) { + klhwg_add_node(hwgraph_root, cnode, NULL); + } + + for (cnode = 0; cnode < numnodes; cnode++) { + klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode)); + } + + /* + * As for router hardware inventory information, we set this + * up in router.c. + */ + + klhwg_add_all_routers(hwgraph_root); + klhwg_connect_routers(hwgraph_root); + klhwg_connect_hubs(hwgraph_root); + + /* Go through the entire system's klconfig + * to figure out which pci components have been disabled + */ + klhwg_device_disable_hints_add(); + +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/l1.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/l1.c --- linux-2.4.19/arch/ia64/sn/io/sn2/l1.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/l1.c Wed Jan 22 16:31:44 2003 @@ -0,0 +1,244 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* In general, this file is organized in a hierarchy from lower-level + * to higher-level layers, as follows: + * + * UART routines + * Bedrock/L1 "PPP-like" protocol implementation + * System controller "message" interface (allows multiplexing + * of various kinds of requests and responses with + * console I/O) + * Console interface: + * "l1_cons", the glue that allows the L1 to act + * as the system console for the stdio libraries + * + * Routines making use of the system controller "message"-style interface + * can be found in l1_command.c. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define UART_BAUD_RATE 57600 + +int +get_L1_baud(void) +{ + return UART_BAUD_RATE; +} + + + +/* Return the current interrupt level */ +int +l1_get_intr_value( void ) +{ + return(0); +} + +/* Disconnect the callup functions - throw away interrupts */ + +void +l1_unconnect_intr(void) +{ +} + +/* Set up uart interrupt handling for this node's uart */ + +void +l1_connect_intr(void *rx_notify, void *tx_notify) +{ +#if 0 + // Will need code here for sn2 - something like this + console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()); + intr_connect_level(console_nodepda->node_first_cpu, + SGI_UART_VECTOR, INTPEND0_MAXMASK, + dummy_intr_func); + request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8), + intr_func, SA_INTERRUPT | SA_SHIRQ, + "l1_protocol_driver", (void *)sc); +#endif +} + + +/* These are functions to use from serial_in/out when in protocol + * mode to send and receive uart control regs. These are external + * interfaces into the protocol driver. + */ + +void +l1_control_out(int offset, int value) +{ + /* quietly ignore unless simulator */ + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + if ( master_node_bedrock_address != (u64)0 ) { + writeb(value, (unsigned long)master_node_bedrock_address + + (offset<< 3)); + } + return; + } +} + +/* Console input exported interface. Return a register value. */ + +int +l1_control_in_polled(int offset) +{ + static int l1_control_in_local(int); + + return(l1_control_in_local(offset)); +} + +int +l1_control_in(int offset) +{ + static int l1_control_in_local(int); + + return(l1_control_in_local(offset)); +} + +static int +l1_control_in_local(int offset) +{ + int sal_call_status = 0, input; + int ret = 0; + + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + ret = readb((unsigned long)master_node_bedrock_address + + (offset<< 3)); + return(ret); + } + if ( offset == REG_LSR ) { + ret = (LSR_XHRE | LSR_XSRE); /* can send anytime */ + sal_call_status = ia64_sn_console_check(&input); + if ( !sal_call_status && input ) { + /* input pending */ + ret |= LSR_RCA; + } + } + return(ret); +} + +/* + * Console input exported interface. Return a character (if one is available) + */ + +int +l1_serial_in_polled(void) +{ + static int l1_serial_in_local(void); + + return(l1_serial_in_local()); +} + +int +l1_serial_in(void) +{ + static int l1_serial_in_local(void); + + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3))); + } + return(l1_serial_in_local()); +} + +static int +l1_serial_in_local(void) +{ + int ch; + + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3))); + } + + if ( !(ia64_sn_console_getc(&ch)) ) + return(ch); + else + return(0); +} + +/* Console output exported interface. Write message to the console. */ + +int +l1_serial_out( char *str, int len ) +{ + int counter = len; + + /* Ignore empty messages */ + if ( len == 0 ) + return(len); + +#if defined(CONFIG_IA64_EARLY_PRINTK) + /* Need to setup SAL calls so the PROM calls will work */ + { + static int inited; + void early_sn_setup(void); + if(!inited) { + inited=1; + early_sn_setup(); + } + } +#endif + + if ( IS_RUNNING_ON_SIMULATOR() ) { + extern u64 master_node_bedrock_address; + void early_sn_setup(void); + if (!master_node_bedrock_address) + early_sn_setup(); + if ( master_node_bedrock_address != (u64)0 ) { +#ifdef FLAG_DIRECT_CONSOLE_WRITES + /* This is an easy way to pre-pend the output to know whether the output + * was done via sal or directly */ + writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); +#endif /* FLAG_DIRECT_CONSOLE_WRITES */ + while ( counter > 0 ) { + writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); + counter--; + str++; + } + } + return(len); + } + + /* Attempt to write things out thru the sal */ + if ( ia64_sn_console_putb(str, len) ) + return(0); + + return((counter <= 0) ? 0 : (len - counter)); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/l1_command.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/l1_command.c --- linux-2.4.19/arch/ia64/sn/io/sn2/l1_command.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/l1_command.c Tue Feb 11 17:20:34 2003 @@ -0,0 +1,236 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ +#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ + +#define hub_cpu_get() 0 + +#define LBYTE(caddr) (*(char *) caddr) + +extern char *bcopy(const char * src, char * dest, int count); + +#define LDEBUG 0 + +/* + * ELSC data is in NVRAM page 7 at the following offsets. + */ + +#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */ +#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */ +#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */ +#define NVRAM_DBG2 0x706 /* physical XOR debug switches */ +#define NVRAM_CFG 0x707 /* ELSC Configuration info */ +#define NVRAM_MODULE 0x708 /* system module number */ +#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */ +#define NVRAM_PARTITION 0x70a /* module's partition id */ +#define NVRAM_DOMAIN 0x70b /* module's domain id */ +#define NVRAM_CLUSTER 0x70c /* module's cluster id */ +#define NVRAM_CELL 0x70d /* module's cellid */ + +#define NVRAM_MAGIC_NO 0x37 /* value of magic number */ +#define NVRAM_SIZE 16 /* 16 bytes in nvram */ + + +/* elsc_display_line writes up to 12 characters to either the top or bottom + * line of the L1 display. line points to a buffer containing the message + * to be displayed. The zero-based line number is specified by lnum (so + * lnum == 0 specifies the top line and lnum == 1 specifies the bottom). + * Lines longer than 12 characters, or line numbers not less than + * L1_DISPLAY_LINES, cause elsc_display_line to return an error. + */ +int elsc_display_line(nasid_t nasid, char *line, int lnum) +{ + return 0; +} + +/* + * iobrick routines + */ + +/* iobrick_rack_bay_type_get fills in the three int * arguments with the + * rack number, bay number and brick type of the L1 being addressed. Note + * that if the L1 operation fails and this function returns an error value, + * garbage may be written to brick_type. + */ + + +int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, + uint *bay, uint *brick_type ) +{ + int result = 0; + + if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) + return( ELSC_ERROR_CMD_SEND ); + + *rack = (result & MODULE_RACK_MASK) >> MODULE_RACK_SHFT; + *bay = (result & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT; + *brick_type = (result & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT; + *brick_type = toupper(*brick_type); + + return 0; +} + + +int iomoduleid_get(nasid_t nasid) +{ + + int result = 0; + + if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) + return( ELSC_ERROR_CMD_SEND ); + + return result; + +} + +int iobrick_module_get(nasid_t nasid) +{ + uint rnum, rack, bay, brick_type, t; + int ret; + + /* construct module ID from rack and slot info */ + + if ((ret = iobrick_rack_bay_type_get(nasid, &rnum, &bay, &brick_type)) < 0) + return ret; + + if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) + return ELSC_ERROR_MODULE; + + /* Build a moduleid_t-compatible rack number */ + + rack = 0; + t = rnum / 100; /* rack class (CPU/IO) */ + if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_CLASS(rack, t); + rnum %= 100; + + t = rnum / 10; /* rack group */ + if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_GROUP(rack, t); + + t = rnum % 10; /* rack number (one-based) */ + if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) + return ELSC_ERROR_MODULE; + RACK_ADD_NUM(rack, t); + + switch( brick_type ) { + case L1_BRICKTYPE_IX: + brick_type = MODULE_IXBRICK; break; + case L1_BRICKTYPE_PX: + brick_type = MODULE_PXBRICK; break; + case L1_BRICKTYPE_I: + brick_type = MODULE_IBRICK; break; + case L1_BRICKTYPE_P: + brick_type = MODULE_PBRICK; break; + case L1_BRICKTYPE_X: + brick_type = MODULE_XBRICK; break; + } + + ret = RBT_TO_MODULE(rack, bay, brick_type); + + return ret; +} + +/* + * iobrick_module_get_nasid() returns a module_id which has the brick + * type encoded in bits 15-12, but this is not the true brick type... + * The module_id returned by iobrick_module_get_nasid() is modified + * to make a PEBRICKs & PXBRICKs look like a PBRICK. So this routine + * iobrick_type_get_nasid() returns the true unmodified brick type. + */ +int +iobrick_type_get_nasid(nasid_t nasid) +{ + uint rack, bay, type; + int t, ret; + extern char brick_types[]; + + if ((ret = iobrick_rack_bay_type_get(nasid, &rack, &bay, &type)) < 0) { + return ret; + } + + /* convert brick_type to lower case */ + if ((type >= 'A') && (type <= 'Z')) + type = type - 'A' + 'a'; + + /* convert to a module.h brick type */ + for( t = 0; t < MAX_BRICK_TYPES; t++ ) { + if( brick_types[t] == type ) { + return t; + } + } + + return -1; /* unknown brick */ +} + +int iobrick_module_get_nasid(nasid_t nasid) +{ + int io_moduleid; + + io_moduleid = iobrick_module_get(nasid); + return io_moduleid; +} + +/* + * given a L1 bricktype, return a bricktype string. This string is the + * string that will be used in the hwpath for I/O bricks + */ +char * +iobrick_L1bricktype_to_name(int type) +{ + switch (type) + { + default: + return("Unknown"); + + case L1_BRICKTYPE_X: + return("Xbrick"); + + case L1_BRICKTYPE_I: + return("Ibrick"); + + case L1_BRICKTYPE_P: + return("Pbrick"); + + case L1_BRICKTYPE_PX: + return("PXbrick"); + + case L1_BRICKTYPE_IX: + return("IXbrick"); + + case L1_BRICKTYPE_C: + return("Cbrick"); + + case L1_BRICKTYPE_R: + return("Rbrick"); + } +} + diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/ml_SN_init.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/ml_SN_init.c --- linux-2.4.19/arch/ia64/sn/io/sn2/ml_SN_init.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/ml_SN_init.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,160 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int numcpus; +extern char arg_maxnodes[]; +extern cpuid_t master_procid; + +extern int hasmetarouter; + +int maxcpus; +cpumask_t boot_cpumask; +hubreg_t region_mask = 0; + + +extern xwidgetnum_t hub_widget_id(nasid_t); + +extern int valid_icache_reasons; /* Reasons to flush the icache */ +extern int valid_dcache_reasons; /* Reasons to flush the dcache */ +extern u_char miniroot; +extern volatile int need_utlbmiss_patch; +extern void iograph_early_init(void); + +nasid_t master_nasid = INVALID_NASID; /* This is the partition master nasid */ +nasid_t master_baseio_nasid = INVALID_NASID; /* This is the master base I/O nasid */ + + +/* + * mlreset(void) + * very early machine reset - at this point NO interrupts have been + * enabled; nor is memory, tlb, p0, etc setup. + * + * slave is zero when mlreset is called for the master processor and + * is nonzero thereafter. + */ + + +void +mlreset(int slave) +{ + /* + * We are the master cpu and node. + */ + master_nasid = get_nasid(); + set_master_bridge_base(); + + /* We're the master processor */ + master_procid = smp_processor_id(); + master_nasid = cpuid_to_nasid(master_procid); + + /* + * master_nasid we get back better be same as one from + * get_nasid() + */ + ASSERT_ALWAYS(master_nasid == get_nasid()); + + /* early initialization of iograph */ + iograph_early_init(); + + /* Initialize Hub Pseudodriver Management */ + hubdev_init(); +} + + +/* XXX - Move the meat of this to intr.c ? */ +/* + * Set up the platform-dependent fields in the nodepda. + */ +void init_platform_nodepda(nodepda_t *npda, cnodeid_t node) +{ + hubinfo_t hubinfo; + + extern void router_map_init(nodepda_t *); + extern void router_queue_init(nodepda_t *,cnodeid_t); + extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int); + + /* Allocate per-node platform-dependent data */ + hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s)); + + npda->pdinfo = (void *)hubinfo; + hubinfo->h_nodepda = npda; + hubinfo->h_cnodeid = node; + hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node); + + spin_lock_init(&hubinfo->h_crblock); + + hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); + npda->xbow_peer = INVALID_NASID; + + /* + * Initialize the linked list of + * router info pointers to the dependent routers + */ + npda->npda_rip_first = NULL; + + /* + * npda_rip_last always points to the place + * where the next element is to be inserted + * into the list + */ + npda->npda_rip_last = &npda->npda_rip_first; + npda->geoid.any.type = GEO_TYPE_INVALID; + + mutex_init_locked(&npda->xbow_sema); /* init it locked? */ +} + +/* XXX - Move the interrupt stuff to intr.c ? */ +/* + * Set up the platform-dependent fields in the processor pda. + * Must be done _after_ init_platform_nodepda(). + * If we need a lock here, something else is wrong! + */ +void init_platform_pda(cpuid_t cpu) +{ +} + +void +update_node_information(cnodeid_t cnodeid) +{ + nodepda_t *npda = NODEPDA(cnodeid); + nodepda_router_info_t *npda_rip; + + /* Go through the list of router info + * structures and copy some frequently + * accessed info from the info hanging + * off the corresponding router vertices + */ + npda_rip = npda->npda_rip_first; + while(npda_rip) { + if (npda_rip->router_infop) { + npda_rip->router_portmask = + npda_rip->router_infop->ri_portmask; + npda_rip->router_slot = + npda_rip->router_infop->ri_slotnum; + } else { + /* No router, no ports. */ + npda_rip->router_portmask = 0; + } + npda_rip = npda_rip->router_next; + } +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/ml_SN_intr.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/ml_SN_intr.c --- linux-2.4.19/arch/ia64/sn/io/sn2/ml_SN_intr.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/ml_SN_intr.c Thu Feb 13 11:02:02 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ /* @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,9 @@ extern nasid_t master_nasid; // Initialize some shub registers for interrupts, both IO and error. +// + + void intr_init_vecblk( nodepda_t *npda, @@ -51,24 +55,15 @@ int sn) { int nasid = cnodeid_to_nasid(node); - nasid_t console_nasid; sh_ii_int0_config_u_t ii_int_config; cpuid_t cpu; cpuid_t cpu0, cpu1; nodepda_t *lnodepda; sh_ii_int0_enable_u_t ii_int_enable; - sh_local_int0_config_u_t local_int_config; - sh_local_int0_enable_u_t local_int_enable; - sh_fsb_system_agent_config_u_t fsb_system_agent; sh_int_node_id_config_u_t node_id_config; - int is_console; - - console_nasid = get_console_nasid(); - if (console_nasid < 0) { - console_nasid = master_nasid; - } + extern void sn_init_cpei_timer(void); + static int timer_added = 0; - is_console = nasid == console_nasid; if (is_headless_node(node) ) { int cnode; @@ -95,13 +90,15 @@ } // Get the physical id's of the cpu's on this node. - cpu0 = id_eid_to_cpu_physical_id(nasid, 0); - cpu1 = id_eid_to_cpu_physical_id(nasid, 1); + cpu0 = nasid_slice_to_cpu_physical_id(nasid, 0); + cpu1 = nasid_slice_to_cpu_physical_id(nasid, 2); HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0); HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0); + // The II_INT_CONFIG register for cpu 0. + ii_int_config.sh_ii_int0_config_regval = 0; ii_int_config.sh_ii_int0_config_s.type = 0; ii_int_config.sh_ii_int0_config_s.agt = 0; ii_int_config.sh_ii_int0_config_s.pid = cpu0; @@ -110,7 +107,9 @@ HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG), ii_int_config.sh_ii_int0_config_regval); + // The II_INT_CONFIG register for cpu 1. + ii_int_config.sh_ii_int0_config_regval = 0; ii_int_config.sh_ii_int0_config_s.type = 0; ii_int_config.sh_ii_int0_config_s.agt = 0; ii_int_config.sh_ii_int0_config_s.pid = cpu1; @@ -119,101 +118,28 @@ HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG), ii_int_config.sh_ii_int0_config_regval); + // Enable interrupts for II_INT0 and 1. + ii_int_enable.sh_ii_int0_enable_regval = 0; ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1; +#if defined(BUS_INT_WAR) && defined(CONFIG_SHUB_1_0_SPECIFIC) + /* Dont enable any ints from II. We will poll for interrupts. */ + ii_int_enable.sh_ii_int0_enable_s.ii_enable = 0; + + /* Enable IPIs. We use them ONLY for send INITs to hung cpus */ + *(volatile long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT_ENABLE) = 1; +#endif HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE), ii_int_enable.sh_ii_int0_enable_regval); HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE), ii_int_enable.sh_ii_int0_enable_regval); - // init error regs - // LOCAL_INT0 is for the UART only. - - local_int_config.sh_local_int0_config_s.type = 0; - local_int_config.sh_local_int0_config_s.agt = 0; - local_int_config.sh_local_int0_config_s.pid = cpu; - local_int_config.sh_local_int0_config_s.base = 0; - local_int_config.sh_local_int0_config_s.idx = SGI_UART_VECTOR; - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_CONFIG), - local_int_config.sh_local_int0_config_regval); - - // LOCAL_INT1 is for all hardware errors. - // It will send a BERR, which will result in an MCA. - local_int_config.sh_local_int0_config_s.idx = 0; - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG), - local_int_config.sh_local_int0_config_regval); - - // Clear the LOCAL_INT_ENABLE register. - local_int_enable.sh_local_int0_enable_regval = 0; - - if (is_console) { - // Enable the UART interrupt. Only applies to the console nasid. - local_int_enable.sh_local_int0_enable_s.uart_int = 1; - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_ENABLE), - local_int_enable.sh_local_int0_enable_regval); - } - - // Enable all the error interrupts. - local_int_enable.sh_local_int0_enable_s.uart_int = 0; - local_int_enable.sh_local_int0_enable_s.pi_hw_int = 1; - local_int_enable.sh_local_int0_enable_s.md_hw_int = 1; - local_int_enable.sh_local_int0_enable_s.xn_hw_int = 1; - local_int_enable.sh_local_int0_enable_s.lb_hw_int = 1; - local_int_enable.sh_local_int0_enable_s.ii_hw_int = 1; - local_int_enable.sh_local_int0_enable_s.pi_uce_int = 1; - local_int_enable.sh_local_int0_enable_s.md_uce_int = 1; - local_int_enable.sh_local_int0_enable_s.xn_uce_int = 1; - local_int_enable.sh_local_int0_enable_s.system_shutdown_int = 1; - local_int_enable.sh_local_int0_enable_s.l1_nmi_int = 1; - local_int_enable.sh_local_int0_enable_s.stop_clock = 1; - - - // Send BERR, rather than an interrupt, for shub errors. - local_int_config.sh_local_int0_config_s.agt = 1; - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG), - local_int_config.sh_local_int0_config_regval); - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_ENABLE), - local_int_enable.sh_local_int0_enable_regval); - - // Make sure BERR is enabled. - fsb_system_agent.sh_fsb_system_agent_config_regval = - HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG) ); - fsb_system_agent.sh_fsb_system_agent_config_s.berr_assert_en = 1; - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG), - fsb_system_agent.sh_fsb_system_agent_config_regval); - - // Set LOCAL_INT2 to field CEs - - local_int_enable.sh_local_int0_enable_regval = 0; - - local_int_config.sh_local_int0_config_s.agt = 0; - local_int_config.sh_local_int0_config_s.idx = SGI_SHUB_ERROR_VECTOR; - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_CONFIG), - local_int_config.sh_local_int0_config_regval); - - local_int_enable.sh_local_int0_enable_s.pi_ce_int = 1; - local_int_enable.sh_local_int0_enable_s.md_ce_int = 1; - local_int_enable.sh_local_int0_enable_s.xn_ce_int = 1; - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_ENABLE), - local_int_enable.sh_local_int0_enable_regval); - - // Make sure all the rest of the LOCAL_INT regs are disabled. - local_int_enable.sh_local_int0_enable_regval = 0; - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT3_ENABLE), - local_int_enable.sh_local_int0_enable_regval); - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT4_ENABLE), - local_int_enable.sh_local_int0_enable_regval); - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE), - local_int_enable.sh_local_int0_enable_regval); + if (!timer_added) { // can only init the timer once. + timer_added = 1; + sn_init_cpei_timer(); + } } // (Un)Reserve an irq on this cpu. @@ -325,11 +251,11 @@ int slice, min_count = 1000; irqpda_t *irqs; - for (slice = 0; slice < CPUS_PER_NODE; slice++) { + for (slice = CPUS_PER_NODE - 1; slice >= 0; slice--) { int intrs; cpu = cnode_slice_to_cpuid(cnode, slice); - if (cpu == CPU_NONE) { + if (cpu == smp_num_cpus) { continue; } @@ -343,6 +269,9 @@ if (min_count > intrs) { min_count = intrs; best_cpu = cpu; +#ifdef II_INT0_WAR + break; +#endif } } return best_cpu; @@ -393,31 +322,40 @@ int *resp_bit) { cpuid_t cpuid; - cnodeid_t candidate = -1; + cpuid_t candidate = CPU_NONE; + cnodeid_t candidate_node; devfs_handle_t pconn_vhdl; pcibr_soft_t pcibr_soft; + int bit; /* SN2 + pcibr addressing limitation */ /* Due to this limitation, all interrupts from a given bridge must go to the name node.*/ +/* The interrupt must also be targetted for the same processor. */ /* This limitation does not exist on PIC. */ +/* But, the processor limitation will stay. The limitation will be similar to */ +/* the bedrock/xbridge limit regarding PI's */ if ( (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) && ( (pcibr_soft = pcibr_soft_get(pconn_vhdl) ) != NULL) ) { if (pcibr_soft->bsi_err_intr) { - candidate = cpuid_to_cnodeid( ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid); + candidate = ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid; } } - if (candidate >= 0) { - // The node was chosen already when we assigned the error interrupt. - cpuid = intr_bit_reserve_test(CPU_NONE, - 0, - candidate, - req_bit, - 0, - owner_dev, - name, - resp_bit); + + if (candidate != CPU_NONE) { + // The cpu was chosen already when we assigned the error interrupt. + bit = intr_reserve_level(candidate, + req_bit, + resflags, + owner_dev, + name); + if (bit < 0) { + cpuid = CPU_NONE; + } else { + cpuid = candidate; + *resp_bit = bit; + } } else { // Need to choose one. Try the controlling c-brick first. cpuid = intr_bit_reserve_test(CPU_NONE, @@ -434,12 +372,11 @@ return cpuid; } - if (candidate >= 0) { - printk("Cannot target interrupt to target node (%d).\n",candidate); - return CPU_NONE; - } else { - printk("Cannot target interrupt to closest node (%d) 0x%p\n", - master_node_get(dev), (void *)owner_dev); + if (candidate != CPU_NONE) { + printk("Cannot target interrupt to target node (%ld).\n",candidate); + return CPU_NONE; } else { + /* printk("Cannot target interrupt to closest node (%d) 0x%p\n", + master_node_get(dev), (void *)owner_dev); */ } // We couldn't put it on the closest node. Try to find another one. @@ -448,11 +385,11 @@ { static cnodeid_t last_node = -1; if (last_node >= numnodes) last_node = 0; - for (candidate = last_node + 1; candidate != last_node; candidate++) { - if (candidate == numnodes) candidate = 0; + for (candidate_node = last_node + 1; candidate_node != last_node; candidate_node++) { + if (candidate_node == numnodes) candidate_node = 0; cpuid = intr_bit_reserve_test(CPU_NONE, 0, - candidate, + candidate_node, req_bit, 0, owner_dev, diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/ml_iograph.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/ml_iograph.c --- linux-2.4.19/arch/ia64/sn/io/sn2/ml_iograph.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/ml_iograph.c Tue Feb 11 17:20:34 2003 @@ -0,0 +1,1354 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define IOGRAPH_DEBUG */ +#ifdef IOGRAPH_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* IOGRAPH_DEBUG */ + +/* #define PROBE_TEST */ + +/* At most 2 hubs can be connected to an xswitch */ +#define NUM_XSWITCH_VOLUNTEER 2 + +extern unsigned char Is_pic_on_this_nasid[512]; + +/* + * Track which hubs have volunteered to manage devices hanging off of + * a Crosstalk Switch (e.g. xbow). This structure is allocated, + * initialized, and hung off the xswitch vertex early on when the + * xswitch vertex is created. + */ +typedef struct xswitch_vol_s { + mutex_t xswitch_volunteer_mutex; + int xswitch_volunteer_count; + devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; +} *xswitch_vol_t; + +void +xswitch_vertex_init(devfs_handle_t xswitch) +{ + xswitch_vol_t xvolinfo; + int rc; + extern void * snia_kmem_zalloc(size_t size, int flag); + + xvolinfo = snia_kmem_zalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); + mutex_init(&xvolinfo->xswitch_volunteer_mutex); + rc = hwgraph_info_add_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t)xvolinfo); + ASSERT(rc == GRAPH_SUCCESS); rc = rc; +} + + +/* + * When assignment of hubs to widgets is complete, we no longer need the + * xswitch volunteer structure hanging around. Destroy it. + */ +static void +xswitch_volunteer_delete(devfs_handle_t xswitch) +{ + xswitch_vol_t xvolinfo; + int rc; + extern void snia_kmem_free(void *ptr, size_t size); + + rc = hwgraph_info_remove_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t *)&xvolinfo); + snia_kmem_free(xvolinfo, sizeof(struct xswitch_vol_s)); +} +/* + * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. + */ +/* ARGSUSED */ +static void +volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) +{ + xswitch_vol_t xvolinfo = NULL; + devfs_handle_t hubv; + hubinfo_t hubinfo; + + (void)hwgraph_info_get_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t *)&xvolinfo); + if (xvolinfo == NULL) { + if (!is_headless_node_vertex(master)) + printk(KERN_WARNING + "volunteer for widgets: vertex 0x%p has no info label", + (void *)xswitch); + return; + } + + mutex_lock(&xvolinfo->xswitch_volunteer_mutex); + ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); + xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; + xvolinfo->xswitch_volunteer_count++; + + /* + * if dual ported, make the lowest widgetid always be + * xswitch_volunteer[0]. + */ + if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) { + hubv = xvolinfo->xswitch_volunteer[0]; + hubinfo_get(hubv, &hubinfo); + if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) { + xvolinfo->xswitch_volunteer[0] = + xvolinfo->xswitch_volunteer[1]; + xvolinfo->xswitch_volunteer[1] = hubv; + } + } + mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); +} + +extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); + +/* + * Assign all the xwidgets hanging off the specified xswitch to the + * Crosstalk masters that have volunteered for xswitch duty. + */ +/* ARGSUSED */ +static void +assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) +{ + xswitch_info_t xswitch_info; + xswitch_vol_t xvolinfo = NULL; + xwidgetnum_t widgetnum; + int num_volunteer; + nasid_t nasid; + hubinfo_t hubinfo; + extern int iobrick_type_get_nasid(nasid_t); + + + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + + xswitch_info = xswitch_info_get(xswitch); + ASSERT(xswitch_info != NULL); + + (void)hwgraph_info_get_LBL(xswitch, + INFO_LBL_XSWITCH_VOL, + (arbitrary_info_t *)&xvolinfo); + if (xvolinfo == NULL) { + if (!is_headless_node_vertex(hubv)) + printk(KERN_WARNING + "assign_widgets_to_volunteers:vertex 0x%p has " + " no info label", + (void *)xswitch); + return; + } + + num_volunteer = xvolinfo->xswitch_volunteer_count; + ASSERT(num_volunteer > 0); + + /* Assign master hub for xswitch itself. */ + if (HUB_WIDGET_ID_MIN > 0) { + hubv = xvolinfo->xswitch_volunteer[0]; + xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); + } + + /* + * TBD: Use administrative information to alter assignment of + * widgets to hubs. + */ + for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + int i; + + /* + * Ignore disabled/empty ports. + */ + if (!xbow_port_io_enabled(nasid, widgetnum)) + continue; + + /* + * If this is the master IO board, assign it to the same + * hub that owned it in the prom. + */ + if (is_master_baseio_nasid_widget(nasid, widgetnum)) { + extern nasid_t get_master_baseio_nasid(void); + for (i=0; ixswitch_volunteer[i]; + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + if (nasid == get_master_baseio_nasid()) + goto do_assignment; + } + PRINT_PANIC("Nasid == %d, console nasid == %d", + nasid, get_master_baseio_nasid()); + } + + /* + * Assuming that we're dual-hosted and that PCI cards + * are naturally placed left-to-right, alternate PCI + * buses across both Cbricks. For Pbricks, and Ibricks, + * io_brick_map_widget() returns the PCI bus number + * associated with the given brick type and widget number. + * For Xbricks, it returns the XIO slot number. + */ + + i = 0; + if (num_volunteer > 1) { + int bt; + + bt = iobrick_type_get_nasid(nasid); + if (bt >= 0) { + i = io_brick_map_widget(bt, widgetnum) & 1; + } + } + + hubv = xvolinfo->xswitch_volunteer[i]; + +do_assignment: + /* + * At this point, we want to make hubv the master of widgetnum. + */ + xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); + } + + xswitch_volunteer_delete(xswitch); +} + +/* + * Early iograph initialization. Called by master CPU in mlreset(). + * Useful for including iograph.o in kernel.o. + */ +void +iograph_early_init(void) +{ +/* + * Need new way to get this information .. + */ + cnodeid_t cnode; + nasid_t nasid; + lboard_t *board; + + /* + * Init. the board-to-hwgraph link early, so FRU analyzer + * doesn't trip on leftover values if we panic early on. + */ + for(cnode = 0; cnode < numnodes; cnode++) { + nasid = COMPACT_TO_NASID_NODEID(cnode); + board = (lboard_t *)KL_CONFIG_INFO(nasid); + DBG("iograph_early_init: Found board 0x%p\n", board); + + /* Check out all the board info stored on a node */ + while(board) { + board->brd_graph_link = GRAPH_VERTEX_NONE; + board = KLCF_NEXT(board); + DBG("iograph_early_init: Found board 0x%p\n", board); + } + } + + hubio_init(); +} + +/* + * Let boot processor know that we're done initializing our node's IO + * and then exit. + */ +/* ARGSUSED */ +static void +io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) +{ + /* Let boot processor know that we're done. */ +} + +/* + * Probe to see if this hub's xtalk link is active. If so, + * return the Crosstalk Identification of the widget that we talk to. + * This is called before any of the Crosstalk infrastructure for + * this hub is set up. It's usually called on the node that we're + * probing, but not always. + * + * TBD: Prom code should actually do this work, and pass through + * hwid for our use. + */ +static void +early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) +{ + hubreg_t llp_csr_reg; + nasid_t nasid; + hubinfo_t hubinfo; + + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + + llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); + /* + * If link is up, read the widget's part number. + * A direct connect widget must respond to widgetnum=0. + */ + if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { + /* TBD: Put hub into "indirect" mode */ + /* + * We're able to read from a widget because our hub's + * WIDGET_ID was set up earlier. + */ + widgetreg_t widget_id = *(volatile widgetreg_t *) + (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); + + DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, + (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); + + hwid->part_num = XWIDGET_PART_NUM(widget_id); + hwid->rev_num = XWIDGET_REV_NUM(widget_id); + hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); + + /* TBD: link reset */ + } else { + + hwid->part_num = XWIDGET_PART_NUM_NONE; + hwid->rev_num = XWIDGET_REV_NUM_NONE; + hwid->mfg_num = XWIDGET_MFG_NUM_NONE; + } +} + +/* Add inventory information to the widget vertex + * Right now (module,slot,revision) is being + * added as inventory information. + */ +static void +xwidget_inventory_add(devfs_handle_t widgetv, + lboard_t *board, + struct xwidget_hwid_s hwid) +{ + if (!board) + return; + /* Donot add inventory information for the baseio + * on a speedo with an xbox. It has already been + * taken care of in SN00_vmc. + * Speedo with xbox's baseio comes in at slot io1 (widget 9) + */ + device_inventory_add(widgetv,INV_IOBD,board->brd_type, + geo_module(board->brd_geoid), + SLOTNUM_GETSLOT(board->brd_slot), + hwid.rev_num); +} + +/* + * io_xswitch_widget_init + * + */ + +void +io_xswitch_widget_init(devfs_handle_t xswitchv, + devfs_handle_t hubv, + xwidgetnum_t widgetnum, + async_attach_t aa) +{ + xswitch_info_t xswitch_info; + xwidgetnum_t hub_widgetid; + devfs_handle_t widgetv; + cnodeid_t cnode; + widgetreg_t widget_id; + nasid_t nasid, peer_nasid; + struct xwidget_hwid_s hwid; + hubinfo_t hubinfo; + /*REFERENCED*/ + int rc; + char pathname[128]; + lboard_t *board = NULL; + char buffer[16]; + char bt; + moduleid_t io_module; + slotid_t get_widget_slotnum(int xbow, int widget); + + DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); + + /* + * Verify that xswitchv is indeed an attached xswitch. + */ + xswitch_info = xswitch_info_get(xswitchv); + ASSERT(xswitch_info != NULL); + + hubinfo_get(hubv, &hubinfo); + nasid = hubinfo->h_nasid; + cnode = NASID_TO_COMPACT_NODEID(nasid); + hub_widgetid = hubinfo->h_widgetid; + + /* + * Check that the widget is an io widget and is enabled + * on this nasid or the `peer' nasid. The peer nasid + * is the other hub/bedrock connected to the xbow. + */ + peer_nasid = NODEPDA(cnode)->xbow_peer; + if (peer_nasid == INVALID_NASID) + /* If I don't have a peer, use myself. */ + peer_nasid = nasid; + if (!xbow_port_io_enabled(nasid, widgetnum) && + !xbow_port_io_enabled(peer_nasid, widgetnum)) { + return; + } + + if (xswitch_info_link_ok(xswitch_info, widgetnum)) { + char name[4]; + lboard_t dummy; + + + /* + * If the current hub is not supposed to be the master + * for this widgetnum, then skip this widget. + */ + if (xswitch_info_master_assignment_get(xswitch_info, + widgetnum) != hubv) { + return; + } + + board = find_lboard_class( + (lboard_t *)KL_CONFIG_INFO(nasid), + KLCLASS_IOBRICK); + if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) { + board = find_lboard_class( + (lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer), + KLCLASS_IOBRICK); + } + + if (board) { + DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); + } else { + DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); + board = &dummy; + } + + + /* Copy over the nodes' geoid info */ + { + lboard_t *brd; + + brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + if ( brd != (lboard_t *)0 ) { + board->brd_geoid = brd->brd_geoid; + } + } + + /* + * Make sure we really want to say xbrick, pbrick, + * etc. rather than XIO, graphics, etc. + */ + + memset(buffer, 0, 16); + format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); + + sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d", + buffer, + geo_slab(board->brd_geoid), + (board->brd_type == KLTYPE_IBRICK) ? EDGE_LBL_IBRICK : + (board->brd_type == KLTYPE_PBRICK) ? EDGE_LBL_PBRICK : + (board->brd_type == KLTYPE_PXBRICK) ? EDGE_LBL_PXBRICK : + (board->brd_type == KLTYPE_IXBRICK) ? EDGE_LBL_IXBRICK : + (board->brd_type == KLTYPE_XBRICK) ? EDGE_LBL_XBRICK : "?brick", + EDGE_LBL_XTALK, widgetnum); + + DBG("io_xswitch_widget_init: path= %s\n", pathname); + rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); + + ASSERT(rc == GRAPH_SUCCESS); + + /* This is needed to let the user programs to map the + * module,slot numbers to the corresponding widget numbers + * on the crossbow. + */ + device_master_set(hwgraph_connectpt_get(widgetv), hubv); + sprintf(name, "%d", widgetnum); + DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); + rc = hwgraph_edge_add(xswitchv, widgetv, name); + + /* + * crosstalk switch code tracks which + * widget is attached to each link. + */ + xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); + + /* + * Peek at the widget to get its crosstalk part and + * mfgr numbers, then present it to the generic xtalk + * bus provider to have its driver attach routine + * called (or not). + */ + widget_id = XWIDGET_ID_READ(nasid, widgetnum); + hwid.part_num = XWIDGET_PART_NUM(widget_id); + hwid.rev_num = XWIDGET_REV_NUM(widget_id); + hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); + /* Store some inventory information about + * the xwidget in the hardware graph. + */ + xwidget_inventory_add(widgetv,board,hwid); + + (void)xwidget_register(&hwid, widgetv, widgetnum, + hubv, hub_widgetid, + aa); + + ia64_sn_sysctl_iobrick_module_get(nasid, &io_module); + + if (io_module >= 0) { + char buffer[16]; + devfs_handle_t to, from; + char *brick_name; + extern char *iobrick_L1bricktype_to_name(int type); + + + memset(buffer, 0, 16); + format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); + + if ( islower(MODULE_GET_BTCHAR(io_module)) ) { + bt = toupper(MODULE_GET_BTCHAR(io_module)); + } + else { + bt = MODULE_GET_BTCHAR(io_module); + } + + brick_name = iobrick_L1bricktype_to_name(bt); + + /* Add a helper vertex so xbow monitoring + * can identify the brick type. It's simply + * an edge from the widget 0 vertex to the + * brick vertex. + */ + + sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/" + EDGE_LBL_SLAB "/%d/" + EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/" + "0", + buffer, geo_slab(board->brd_geoid)); + from = hwgraph_path_to_vertex(pathname); + ASSERT_ALWAYS(from); + sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/" + EDGE_LBL_SLAB "/%d/" + "%s", + buffer, geo_slab(board->brd_geoid), brick_name); + + to = hwgraph_path_to_vertex(pathname); + ASSERT_ALWAYS(to); + rc = hwgraph_edge_add(from, to, + EDGE_LBL_INTERCONNECT); + if (rc == -EEXIST) + goto link_done; + if (rc != GRAPH_SUCCESS) { + printk("%s: Unable to establish link" + " for xbmon.", pathname); + } +link_done: + } + +#ifdef SN0_USE_BTE + bte_bpush_war(cnode, (void *)board); +#endif + } +} + + +static void +io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) +{ + xwidgetnum_t widgetnum; + async_attach_t aa; + + aa = async_attach_new(); + + DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); + + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; + widgetnum++) { + io_xswitch_widget_init(xswitchv, + cnodeid_to_vertex(cnode), + widgetnum, aa); + } + /* + * Wait for parallel attach threads, if any, to complete. + */ + async_attach_waitall(aa); + async_attach_free(aa); +} + +/* + * For each PCI bridge connected to the xswitch, add a link from the + * board's klconfig info to the bridge's hwgraph vertex. This lets + * the FRU analyzer find the bridge without traversing the hardware + * graph and risking hangs. + */ +static void +io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) +{ + xwidgetnum_t widgetnum; + char pathname[128]; + devfs_handle_t vhdl; + nasid_t nasid, peer_nasid; + lboard_t *board; + + + + /* And its connected hub's nasids */ + nasid = COMPACT_TO_NASID_NODEID(cnodeid); + peer_nasid = NODEPDA(cnodeid)->xbow_peer; + + /* + * Look for paths matching "/pci" under xswitchv. + * For every widget, init. its lboard's hwgraph link. If the + * board has a PCI bridge, point the link to it. + */ + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; + widgetnum++) { + sprintf(pathname, "%d", widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) != + GRAPH_SUCCESS) + continue; + + board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), + NODEPDA(cnodeid)->geoid); + if (board == NULL && peer_nasid != INVALID_NASID) { + /* + * Try to find the board on our peer + */ + board = find_lboard_module( + (lboard_t *)KL_CONFIG_INFO(peer_nasid), + NODEPDA(cnodeid)->geoid); + } + if (board == NULL) { + printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, " + "FRU analyzer may fail", + (void *)vhdl); + return; + } + + if ( Is_pic_on_this_nasid[nasid] ) { + /* Check both buses */ + sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) + board->brd_graph_link = vhdl; + else { + sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) + board->brd_graph_link = vhdl; + else + board->brd_graph_link = GRAPH_VERTEX_NONE; + } + } + else { + sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) + board->brd_graph_link = vhdl; + else + board->brd_graph_link = GRAPH_VERTEX_NONE; + } + } +} + +/* + * Initialize all I/O on the specified node. + */ +static void +io_init_node(cnodeid_t cnodeid) +{ + /*REFERENCED*/ + devfs_handle_t hubv, switchv, widgetv; + struct xwidget_hwid_s hwid; + hubinfo_t hubinfo; + int is_xswitch; + nodepda_t *npdap; + struct semaphore *peer_sema = 0; + uint32_t widget_partnum; + nodepda_router_info_t *npda_rip; + cpu_cookie_t c = 0; + extern int hubdev_docallouts(devfs_handle_t); + + npdap = NODEPDA(cnodeid); + + /* + * Get the "top" vertex for this node's hardware + * graph; it will carry the per-hub hub-specific + * data, and act as the crosstalk provider master. + * It's canonical path is probably something of the + * form /hw/module/%M/slot/%d/node + */ + hubv = cnodeid_to_vertex(cnodeid); + DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); + + ASSERT(hubv != GRAPH_VERTEX_NONE); + + hubdev_docallouts(hubv); + + /* + * Set up the dependent routers if we have any. + */ + npda_rip = npdap->npda_rip_first; + + while(npda_rip) { + /* If the router info has not been initialized + * then we need to do the router initialization + */ + if (!npda_rip->router_infop) { + router_init(cnodeid,0,npda_rip); + } + npda_rip = npda_rip->router_next; + } + + /* + * Read mfg info on this hub + */ + + /* + * If nothing connected to this hub's xtalk port, we're done. + */ + early_probe_for_widget(hubv, &hwid); + if (hwid.part_num == XWIDGET_PART_NUM_NONE) { +#ifdef PROBE_TEST + if ((cnodeid == 1) || (cnodeid == 2)) { + int index; + + for (index = 0; index < 600; index++) + DBG("Interfering with device probing!!!\n"); + } +#endif + /* io_init_done takes cpu cookie as 2nd argument + * to do a restorenoderun for the setnoderun done + * at the start of this thread + */ + + DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); + return; + /* NOTREACHED */ + } + + /* + * attach our hub_provider information to hubv, + * so we can use it as a crosstalk provider "master" + * vertex. + */ + xtalk_provider_register(hubv, &hub_provider); + xtalk_provider_startup(hubv); + + /* + * Create a vertex to represent the crosstalk bus + * attached to this hub, and a vertex to be used + * as the connect point for whatever is out there + * on the other side of our crosstalk connection. + * + * Crosstalk Switch drivers "climb up" from their + * connection point to try and take over the switch + * point. + * + * Of course, the edges and verticies may already + * exist, in which case our net effect is just to + * associate the "xtalk_" driver with the connection + * point for the device. + */ + + (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); + + DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); + + ASSERT(switchv != GRAPH_VERTEX_NONE); + + (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); + + DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); + + /* + * We need to find the widget id and update the basew_id field + * accordingly. In particular, SN00 has direct connected bridge, + * and hence widget id is Not 0. + */ + + widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; + + if (widget_partnum == BRIDGE_WIDGET_PART_NUM || + widget_partnum == XBRIDGE_WIDGET_PART_NUM){ + npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); + + DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); + + } else if ((widget_partnum == XBOW_WIDGET_PART_NUM) || + (widget_partnum == XXBOW_WIDGET_PART_NUM) || + (widget_partnum == PXBOW_WIDGET_PART_NUM) ) { + /* + * Xbow control register does not have the widget ID field. + * So, hard code the widget ID to be zero. + */ + DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); + npdap->basew_id = 0; + + } else { + npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); + + panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); + + /*NOTREACHED*/ + } + { + char widname[10]; + sprintf(widname, "%x", npdap->basew_id); + (void)hwgraph_path_add(switchv, widname, &widgetv); + DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); + ASSERT(widgetv != GRAPH_VERTEX_NONE); + } + + nodepda->basew_xc = widgetv; + + is_xswitch = xwidget_hwid_is_xswitch(&hwid); + + /* + * Try to become the master of the widget. If this is an xswitch + * with multiple hubs connected, only one will succeed. Mastership + * of an xswitch is used only when touching registers on that xswitch. + * The slave xwidgets connected to the xswitch can be owned by various + * masters. + */ + if (device_master_set(widgetv, hubv) == 0) { + + /* Only one hub (thread) per Crosstalk device or switch makes + * it to here. + */ + + /* + * Initialize whatever xwidget is hanging off our hub. + * Whatever it is, it's accessible through widgetnum 0. + */ + hubinfo_get(hubv, &hubinfo); + + (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL); + + if (!is_xswitch) { + /* io_init_done takes cpu cookie as 2nd argument + * to do a restorenoderun for the setnoderun done + * at the start of this thread + */ + io_init_done(cnodeid,c); + /* NOTREACHED */ + } + + /* + * Special handling for Crosstalk Switches (e.g. xbow). + * We need to do things in roughly the following order: + * 1) Initialize xswitch hardware (done above) + * 2) Determine which hubs are available to be widget masters + * 3) Discover which links are active from the xswitch + * 4) Assign xwidgets hanging off the xswitch to hubs + * 5) Initialize all xwidgets on the xswitch + */ + + volunteer_for_widgets(switchv, hubv); + + /* If there's someone else on this crossbow, recognize him */ + if (npdap->xbow_peer != INVALID_NASID) { + nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer)); + peer_sema = &peer_npdap->xbow_sema; + volunteer_for_widgets(switchv, peer_npdap->node_vertex); + } + + assign_widgets_to_volunteers(switchv, hubv); + + /* Signal that we're done */ + if (peer_sema) { + mutex_unlock(peer_sema); + } + + } + else { + /* Wait 'til master is done assigning widgets. */ + mutex_lock(&npdap->xbow_sema); + } + +#ifdef PROBE_TEST + if ((cnodeid == 1) || (cnodeid == 2)) { + int index; + + for (index = 0; index < 500; index++) + DBG("Interfering with device probing!!!\n"); + } +#endif + /* Now both nodes can safely inititialize widgets */ + io_init_xswitch_widgets(switchv, cnodeid); + io_link_xswitch_widgets(switchv, cnodeid); + + /* io_init_done takes cpu cookie as 2nd argument + * to do a restorenoderun for the setnoderun done + * at the start of this thread + */ + io_init_done(cnodeid,c); + + DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); +} + + +#define IOINIT_STKSZ (16 * 1024) + +#define __DEVSTR1 "/../.master/" +#define __DEVSTR2 "/target/" +#define __DEVSTR3 "/lun/0/disk/partition/" +#define __DEVSTR4 "/../ef" + +/* + * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR. + */ +#define NUM_BASE_IO_SCSI_CTLR 6 +/* + * This tells ioconfig where it can start numbering scsi controllers. + * Below this base number, platform-specific handles the numbering. + * XXX Irix legacy..controller numbering should be part of devfsd's job + */ +int num_base_io_scsi_ctlr = 2; /* used by syssgi */ +devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR]; +static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl; + +/* + * Put the logical controller number information in the + * scsi controller vertices for each scsi controller that + * is in a "fixed position". + */ +static void +scsi_ctlr_nums_add(devfs_handle_t pci_vhdl) +{ + { + int i; + + num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR; + + /* Initialize base_io_scsi_ctlr_vhdl array */ + for (i=0; i +devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; + +/* Define the system critical vertices and connect them through + * a canonical parent-child relationships for easy traversal + * during io error handling. + */ +static void +sys_critical_graph_init(void) +{ + devfs_handle_t bridge_vhdl,master_node_vhdl; + devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE; + extern devfs_handle_t hwgraph_root; + devfs_handle_t pci_slot_conn; + int slot; + devfs_handle_t baseio_console_conn; + + DBG("sys_critical_graph_init: FIXME.\n"); + baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); + + if (baseio_console_conn == NULL) { + return; + } + + /* Get the vertex handle for the baseio bridge */ + bridge_vhdl = device_master_get(baseio_console_conn); + + /* Get the master node of the baseio card */ + master_node_vhdl = cnodeid_to_vertex( + master_node_get(baseio_console_vhdl)); + + /* Add the "root->node" part of the system critical graph */ + + sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl); + + /* Check if we have a crossbow */ + if (hwgraph_traverse(master_node_vhdl, + EDGE_LBL_XTALK"/0", + &xbow_vhdl) == GRAPH_SUCCESS) { + /* We have a crossbow.Add "node->xbow" part of the system + * critical graph. + */ + sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl); + + /* Add "xbow->baseio bridge" of the system critical graph */ + sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl); + + hwgraph_vertex_unref(xbow_vhdl); + } else + /* We donot have a crossbow. Add "node->baseio_bridge" + * part of the system critical graph. + */ + sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl); + + /* Add all the populated PCI slot vertices to the system critical + * graph with the bridge vertex as the parent. + */ + for (slot = 0 ; slot < 8; slot++) { + char slot_edge[10]; + + sprintf(slot_edge,"%d",slot); + if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn) + != GRAPH_SUCCESS) + continue; + sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn); + hwgraph_vertex_unref(pci_slot_conn); + } + + hwgraph_vertex_unref(bridge_vhdl); + + /* Add the "ioc3 pci connection point -> console ioc3" part + * of the system critical graph + */ + + if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) == + GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + baseio_console_vhdl); + hwgraph_vertex_unref(pci_slot_conn); + } + + /* Add the "ethernet pci connection point -> base ethernet" part of + * the system critical graph + */ + if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) == + GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + baseio_enet_vhdl); + hwgraph_vertex_unref(pci_slot_conn); + } + + /* Add the "scsi controller pci connection point -> base scsi + * controller" part of the system critical graph + */ + if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0], + "../..",&pci_slot_conn) == GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + base_io_scsi_ctlr_vhdl[0]); + hwgraph_vertex_unref(pci_slot_conn); + } + if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1], + "../..",&pci_slot_conn) == GRAPH_SUCCESS) { + sys_critical_graph_vertex_add(pci_slot_conn, + base_io_scsi_ctlr_vhdl[1]); + hwgraph_vertex_unref(pci_slot_conn); + } + hwgraph_vertex_unref(baseio_console_conn); + +} + +static void +baseio_ctlr_num_set(void) +{ + char name[MAXDEVNAME]; + devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; + devfs_handle_t ioc3_console_vhdl_get(void); + + + DBG("baseio_ctlr_num_set; FIXME\n"); + console_vhdl = ioc3_console_vhdl_get(); + if (console_vhdl == GRAPH_VERTEX_NONE) + return; + /* Useful for setting up the system critical graph */ + baseio_console_vhdl = console_vhdl; + + vertex_to_name(console_vhdl,name,MAXDEVNAME); + + strcat(name,__DEVSTR1); + pci_vhdl = hwgraph_path_to_vertex(name); + scsi_ctlr_nums_add(pci_vhdl); + /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex + */ + hwgraph_vertex_unref(pci_vhdl); + + vertex_to_name(console_vhdl, name, MAXDEVNAME); + strcat(name, __DEVSTR4); + enet_vhdl = hwgraph_path_to_vertex(name); + + /* Useful for setting up the system critical graph */ + baseio_enet_vhdl = enet_vhdl; + + device_controller_num_set(enet_vhdl, 0); + /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex + */ + hwgraph_vertex_unref(enet_vhdl); +} +/* #endif */ + +/* + * Initialize all I/O devices. Starting closest to nodes, probe and + * initialize outward. + */ +void +init_all_devices(void) +{ + /* Governor on init threads..bump up when safe + * (beware many devfs races) + */ + cnodeid_t cnodeid, active; + + active = 0; + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { + DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); + io_init_node(cnodeid); + + DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); + } + + for (cnodeid = 0; cnodeid < numnodes; cnodeid++) + /* + * Update information generated by IO init. + */ + update_node_information(cnodeid); + + baseio_ctlr_num_set(); + /* Setup the system critical graph (which is a subgraph of the + * main hwgraph). This information is useful during io error + * handling. + */ + sys_critical_graph_init(); + +#if HWG_PRINT + hwgraph_print(); +#endif + +} + +#define toint(x) ((int)(x) - (int)('0')) + +void +devnamefromarcs(char *devnm) +{ + int val; + char tmpnm[MAXDEVNAME]; + char *tmp1, *tmp2; + + val = strncmp(devnm, "dks", 3); + if (val != 0) + return; + tmp1 = devnm + 3; + if (!isdigit(*tmp1)) + return; + + val = 0; + while (isdigit(*tmp1)) { + val = 10*val+toint(*tmp1); + tmp1++; + } + + if(*tmp1 != 'd') + return; + else + tmp1++; + + if ((val < 0) || (val >= num_base_io_scsi_ctlr)) { + int i; + int viable_found = 0; + + DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); + DBG("prom \"root\" variables of the form dksXdXsX.\n"); + DBG("To use another disk you must use the full hardware graph path\n\n"); + DBG("Possible controller numbers for use in 'dksXdXsX' on this system: "); + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* #define LDEBUG 1 */ + +#ifdef LDEBUG +#define DPRINTF printk +#define printf printk +#else +#define DPRINTF(x...) +#endif + +module_t *modules[MODULE_MAX]; +int nummodules; + +#define SN00_SERIAL_FUDGE 0x3b1af409d513c2 +#define SN0_SERIAL_FUDGE 0x6e + +void +encode_int_serial(uint64_t src,uint64_t *dest) +{ + uint64_t val; + int i; + + val = src + SN00_SERIAL_FUDGE; + + + for (i = 0; i < sizeof(long long); i++) { + ((char*)dest)[i] = + ((char*)&val)[sizeof(long long)/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))]; + } +} + + +void +decode_int_serial(uint64_t src, uint64_t *dest) +{ + uint64_t val; + int i; + + for (i = 0; i < sizeof(long long); i++) { + ((char*)&val)[sizeof(long long)/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = + ((char*)&src)[i]; + } + + *dest = val - SN00_SERIAL_FUDGE; +} + + +void +encode_str_serial(const char *src, char *dest) +{ + int i; + + for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { + + dest[i] = src[MAX_SERIAL_NUM_SIZE/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))] + + SN0_SERIAL_FUDGE; + } +} + +void +decode_str_serial(const char *src, char *dest) +{ + int i; + + for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { + dest[MAX_SERIAL_NUM_SIZE/2 + + ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] - + SN0_SERIAL_FUDGE; + } +} + + +module_t *module_lookup(moduleid_t id) +{ + int i; + + for (i = 0; i < nummodules; i++) + if (modules[i]->id == id) { + DPRINTF("module_lookup: found m=0x%p\n", modules[i]); + return modules[i]; + } + + return NULL; +} + +/* + * module_add_node + * + * The first time a new module number is seen, a module structure is + * inserted into the module list in order sorted by module number + * and the structure is initialized. + * + * The node number is added to the list of nodes in the module. + */ + +module_t *module_add_node(geoid_t geoid, cnodeid_t cnodeid) +{ + module_t *m; + int i; + char buffer[16]; + moduleid_t moduleid; + + memset(buffer, 0, 16); + moduleid = geo_module(geoid); + format_module_id(buffer, moduleid, MODULE_FORMAT_BRIEF); + DPRINTF("module_add_node: moduleid=%s node=%d\n", buffer, cnodeid); + + if ((m = module_lookup(moduleid)) == 0) { + m = kmalloc(sizeof (module_t), GFP_KERNEL); + memset(m, 0 , sizeof(module_t)); + ASSERT_ALWAYS(m); + + m->id = moduleid; + spin_lock_init(&m->lock); + + mutex_init_locked(&m->thdcnt); + + /* Insert in sorted order by module number */ + + for (i = nummodules; i > 0 && modules[i - 1]->id > moduleid; i--) + modules[i] = modules[i - 1]; + + modules[i] = m; + nummodules++; + } + + m->nodes[m->nodecnt] = cnodeid; + m->geoid[m->nodecnt] = geoid; + m->nodecnt++; + + DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); + + return m; +} + +int module_probe_snum(module_t *m, nasid_t nasid) +{ + lboard_t *board; + klmod_serial_num_t *comp; + char * bcopy(const char * src, char * dest, int count); + char serial_number[16]; + + /* + * record brick serial number + */ + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + + if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) + { +#if LDEBUG + printf ("module_probe_snum: no IP35 board found!\n"); +#endif + return 0; + } + + board_serial_number_get( board, serial_number ); + if( serial_number[0] != '\0' ) { + encode_str_serial( serial_number, m->snum.snum_str ); + m->snum_valid = 1; + } +#if LDEBUG + else { + printf("module_probe_snum: brick serial number is null!\n"); + } + printf("module_probe_snum: brick serial number == %s\n", serial_number); +#endif /* DEBUG */ + + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), + KLTYPE_IOBRICK_XBOW); + + if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) + return 0; + + comp = GET_SNUM_COMP(board); + + if (comp) { +#if LDEBUG + int i; + + printf("********found module with id %x and string", m->id); + + for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) + printf(" %x ", comp->snum.snum_str[i]); + + printf("\n"); /* Fudged string is not ASCII */ +#endif + + if (comp->snum.snum_str[0] != '\0') { + bcopy(comp->snum.snum_str, + m->sys_snum, + MAX_SERIAL_NUM_SIZE); + m->sys_snum_valid = 1; + } + } + + if (m->sys_snum_valid) + return 1; + else { + DPRINTF("Invalid serial number for module %d, " + "possible missing or invalid NIC.", m->id); + return 0; + } +} + +void +io_module_init(void) +{ + cnodeid_t node; + lboard_t *board; + nasid_t nasid; + int nserial; + module_t *m; + + DPRINTF("*******module_init\n"); + + nserial = 0; + + for (node = 0; node < numnodes; node++) { + nasid = COMPACT_TO_NASID_NODEID(node); + + board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + ASSERT(board); + + m = module_add_node(board->brd_geoid, node); + + if (! m->snum_valid && module_probe_snum(m, nasid)) + nserial++; + } + + DPRINTF("********found total of %d serial numbers in the system\n", + nserial); + + if (nserial == 0) + DPRINTF(KERN_WARNING "io_module_init: No serial number found.\n"); +} + +int +get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info) +{ + if (cmod < 0 || cmod >= nummodules) + return -EINVAL; + + mod_info->mod_num = modules[cmod]->id; + + ia64_sn_sys_serial_get(mod_info->serial_str); + + mod_info->serial_num = ia64_sn_partition_serial_get(); + + return 0; +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pci_bus_cvlink.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pci_bus_cvlink.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pci_bus_cvlink.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pci_bus_cvlink.c Tue Feb 11 17:20:34 2003 @@ -0,0 +1,739 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int bridge_rev_b_data_check_disable; + +devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; +nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; +void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; +unsigned char num_bridges; +static int done_probing = 0; + +static int pci_bus_map_create(devfs_handle_t xtalk, char * io_moduleid); +devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); + +extern unsigned char Is_pic_on_this_nasid[512]; + +extern void sn_init_irq_desc(void); +extern void register_pcibr_intr(int irq, pcibr_intr_t intr); + + +/* + * For the given device, initialize whether it is a PIC device. + */ +static void +set_isPIC(struct sn_device_sysdata *device_sysdata) +{ + pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);; +} + +/* + * pci_bus_cvlink_init() - To be called once during initialization before + * SGI IO Infrastructure init is called. + */ +void +pci_bus_cvlink_init(void) +{ + + extern void ioconfig_bus_init(void); + + memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); + memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); + + memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); + + num_bridges = 0; + + ioconfig_bus_init(); +} + +/* + * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated + * pci bus vertex from the SGI IO Infrastructure. + */ +devfs_handle_t +pci_bus_to_vertex(unsigned char busnum) +{ + + devfs_handle_t pci_bus = NULL; + + + /* + * First get the xwidget vertex. + */ + pci_bus = busnum_to_pcibr_vhdl[busnum]; + return(pci_bus); +} + +/* + * devfn_to_vertex() - returns the vertex of the device given the bus, slot, + * and function numbers. + */ +devfs_handle_t +devfn_to_vertex(unsigned char busnum, unsigned int devfn) +{ + + int slot = 0; + int func = 0; + char name[16]; + devfs_handle_t pci_bus = NULL; + devfs_handle_t device_vertex = (devfs_handle_t)NULL; + + /* + * Go get the pci bus vertex. + */ + pci_bus = pci_bus_to_vertex(busnum); + if (!pci_bus) { + /* + * During probing, the Linux pci code invents non existant + * bus numbers and pci_dev structures and tries to access + * them to determine existance. Don't crib during probing. + */ + if (done_probing) + printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); + return(NULL); + } + + + /* + * Go get the slot&function vertex. + * Should call pciio_slot_func_to_name() when ready. + */ + slot = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* + * For a NON Multi-function card the name of the device looks like: + * ../pci/1, ../pci/2 .. + */ + if (func == 0) { + sprintf(name, "%d", slot); + if (hwgraph_traverse(pci_bus, name, &device_vertex) == + GRAPH_SUCCESS) { + if (device_vertex) { + return(device_vertex); + } + } + } + + /* + * This maybe a multifunction card. It's names look like: + * ../pci/1a, ../pci/1b, etc. + */ + sprintf(name, "%d%c", slot, 'a'+func); + if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { + if (!device_vertex) { + return(NULL); + } + } + + return(device_vertex); +} + +/* + * For the given device, initialize the addresses for both the Device(x) Flush + * Write Buffer register and the Xbow Flush Register for the port the PCI bus + * is connected. + */ +static void +set_flush_addresses(struct pci_dev *device_dev, + struct sn_device_sysdata *device_sysdata) +{ + pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + nasid_t nasid; + + /* + * Get the nasid from the bridge. + */ + nasid = NASID_GET(device_sysdata->dma_buf_sync); + if (IS_PIC_DEVICE(device_dev)) { + device_sysdata->dma_buf_sync = (volatile unsigned int *) + &bridge->b_wr_req_buf[pciio_slot].reg; + device_sysdata->xbow_buf_sync = (volatile unsigned int *) + XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(nasid, 0), + pcibr_soft->bs_xid); + } else { + /* + * Accessing Xbridge and Xbow register when SHUB swapoper is on!. + */ + device_sysdata->dma_buf_sync = (volatile unsigned int *) + ((uint64_t)&(bridge->b_wr_req_buf[pciio_slot].reg)^4); + device_sysdata->xbow_buf_sync = (volatile unsigned int *) + ((uint64_t)(XBOW_PRIO_LINKREGS_PTR( + NODE_SWIN_BASE(nasid, 0), pcibr_soft->bs_xid)) ^ 4); + } + +#ifdef DEBUG + printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", + device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); + +printk("set_flush_addresses: dma_buf_sync\n"); + while((volatile unsigned int )*device_sysdata->dma_buf_sync); +printk("set_flush_addresses: xbow_buf_sync\n"); + while((volatile unsigned int )*device_sysdata->xbow_buf_sync); +#endif + +} + +/* + * Most drivers currently do not properly tell the arch specific pci dma + * interfaces whether they can handle A64. Here is where we privately + * keep track of this. + */ +static void __init +set_sn_pci64(struct pci_dev *dev) +{ + unsigned short vendor = dev->vendor; + unsigned short device = dev->device; + + if (vendor == PCI_VENDOR_ID_QLOGIC) { + if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) || + (device == PCI_DEVICE_ID_QLOGIC_ISP2200)) { + SET_PCIA64(dev); + return; + } + } + + if (vendor == PCI_VENDOR_ID_SGI) { + if (device == PCI_DEVICE_ID_SGI_IOC3) { + SET_PCIA64(dev); + return; + } + } + +} + +/* + * sn_pci_fixup() - This routine is called when platform_pci_fixup() is + * invoked at the end of pcibios_init() to link the Linux pci + * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c + * + * Other platform specific fixup can also be done here. + */ +void +sn_pci_fixup(int arg) +{ + struct list_head *ln; + struct pci_bus *pci_bus = NULL; + struct pci_dev *device_dev = NULL; + struct sn_widget_sysdata *widget_sysdata; + struct sn_device_sysdata *device_sysdata; + pciio_intr_t intr_handle; + int cpuid, bit; + devfs_handle_t device_vertex; + pciio_intr_line_t lines; + extern void sn_pci_find_bios(void); + extern int numnodes; + int cnode; + extern void io_sh_swapper(int, int); + + for (cnode = 0; cnode < numnodes; cnode++) { + if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) + io_sh_swapper((cnodeid_to_nasid(cnode)), 0); + } + + if (arg == 0) { +#ifdef CONFIG_PROC_FS + extern void register_sn_procfs(void); +#endif + + sn_init_irq_desc(); + sn_pci_find_bios(); + for (cnode = 0; cnode < numnodes; cnode++) { + extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); + intr_init_vecblk(NODEPDA(cnode), cnode, 0); + } + + /* + * When we return to generic Linux, Swapper is always on .. + */ + for (cnode = 0; cnode < numnodes; cnode++) { + if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) + io_sh_swapper((cnodeid_to_nasid(cnode)), 1); + } +#ifdef CONFIG_PROC_FS + register_sn_procfs(); +#endif + return; + } + + + done_probing = 1; + + /* + * Initialize the pci bus vertex in the pci_bus struct. + */ + for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { + pci_bus = pci_bus_b(ln); + widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), + GFP_KERNEL); + widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); + pci_bus->sysdata = (void *)widget_sysdata; + } + + /* + * set the root start and end so that drivers calling check_region() + * won't see a conflict + */ + ioport_resource.start = 0xc000000000000000; + ioport_resource.end = 0xcfffffffffffffff; + + /* + * Set the root start and end for Mem Resource. + */ + iomem_resource.start = 0; + iomem_resource.end = 0xffffffffffffffff; + + /* + * Initialize the device vertex in the pci_dev struct. + */ + pci_for_each_dev(device_dev) { + unsigned int irq; + int idx; + u16 cmd; + devfs_handle_t vhdl; + unsigned long size; + extern int bit_pos_to_irq(int); + + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { + extern void pci_fixup_ioc3(struct pci_dev *d); + pci_fixup_ioc3(device_dev); + } + + /* Set the device vertex */ + + device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), + GFP_KERNEL); + device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); + device_sysdata->isa64 = 0; + /* + * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush + * register addresses. + */ + (void) set_flush_addresses(device_dev, device_sysdata); + + device_dev->sysdata = (void *) device_sysdata; + set_sn_pci64(device_dev); + set_isPIC(device_sysdata); + + pci_read_config_word(device_dev, PCI_COMMAND, &cmd); + + /* + * Set the resources address correctly. The assumption here + * is that the addresses in the resource structure has been + * read from the card and it was set in the card by our + * Infrastructure .. + */ + vhdl = device_sysdata->vhdl; + for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { + size = 0; + size = device_dev->resource[idx].end - + device_dev->resource[idx].start; + if (size) { + device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); + device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; + } + else + continue; + + device_dev->resource[idx].end = + device_dev->resource[idx].start + size; + + if (device_dev->resource[idx].flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + + if (device_dev->resource[idx].flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } +#if 0 + /* + * Software WAR for a Software BUG. + * This is only temporary. + * See PV 872791 + */ + + /* + * Now handle the ROM resource .. + */ + size = device_dev->resource[PCI_ROM_RESOURCE].end - + device_dev->resource[PCI_ROM_RESOURCE].start; + + if (size) { + device_dev->resource[PCI_ROM_RESOURCE].start = + (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, + size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); + device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; + device_dev->resource[PCI_ROM_RESOURCE].end = + device_dev->resource[PCI_ROM_RESOURCE].start + size; + } +#endif + + /* + * Update the Command Word on the Card. + */ + cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ + /* bit gets dropped .. no harm */ + pci_write_config_word(device_dev, PCI_COMMAND, cmd); + + pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { + lines = 1; + } + + device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata; + device_vertex = device_sysdata->vhdl; + + intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); + + bit = intr_handle->pi_irq; + cpuid = intr_handle->pi_cpu; + irq = bit; + irq = irq + (cpuid << 8); + pciio_intr_connect(intr_handle, (intr_func_t)0, (intr_arg_t)0); + device_dev->irq = irq; + register_pcibr_intr(irq, (pcibr_intr_t)intr_handle); +#ifdef ajmtestintr + { + int slot = PCI_SLOT(device_dev->devfn); + static int timer_set = 0; + pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + extern void intr_test_handle_intr(int, void*, struct pt_regs *); + + if (!timer_set) { + intr_test_set_timer(); + timer_set = 1; + } + intr_test_register_irq(irq, pcibr_soft, slot); + request_irq(irq, intr_test_handle_intr,0,NULL, NULL); + } +#endif + + } + + for (cnode = 0; cnode < numnodes; cnode++) { + if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) + io_sh_swapper((cnodeid_to_nasid(cnode)), 1); + } +} + +/* + * linux_bus_cvlink() Creates a link between the Linux PCI Bus number + * to the actual hardware component that it represents: + * /dev/hw/linux/busnum/0 -> ../../../hw/module/001c01/slab/0/Ibrick/xtalk/15/pci + * + * The bus vertex, when called to devfs_generate_path() returns: + * hw/module/001c01/slab/0/Ibrick/xtalk/15/pci + * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/0 + * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/1 + */ +void +linux_bus_cvlink(void) +{ + char name[8]; + int index; + + for (index=0; index < MAX_PCI_XWIDGET; index++) { + if (!busnum_to_pcibr_vhdl[index]) + continue; + + sprintf(name, "%x", index); + (void) hwgraph_edge_add(linux_busnum, busnum_to_pcibr_vhdl[index], + name); + } +} + +/* + * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. + * + * Linux PCI Bus numbers are assigned from lowest module_id numbers + * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to + * HUB_WIDGET_ID_MIN: + * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. + * + * Given 2 modules 001c01 and 001c02 we get the following mappings: + * 001c01, widgetnum 15 = Bus number 0 + * 001c01, widgetnum 14 = Bus number 1 + * 001c02, widgetnum 15 = Bus number 3 + * 001c02, widgetnum 14 = Bus number 4 + * etc. + * + * The rational for starting Bus Number 0 with Widget number 15 is because + * the system boot disks are always connected via Widget 15 Slot 0 of the + * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 + * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest + * module id(Master Cnode) of the system. + * + */ +static int +pci_bus_map_create(devfs_handle_t xtalk, char * io_moduleid) +{ + + devfs_handle_t master_node_vertex = NULL; + devfs_handle_t xwidget = NULL; + devfs_handle_t pci_bus = NULL; + hubinfo_t hubinfo = NULL; + xwidgetnum_t widgetnum; + char pathname[128]; + graph_error_t rv; + int bus; + int basebus_num; + extern void ioconfig_get_busnum(char *, int *); + + int bus_number; + + /* + * Loop throught this vertex and get the Xwidgets .. + */ + + + /* PCI devices */ + + for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { + sprintf(pathname, "%d", widgetnum); + xwidget = NULL; + + /* + * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget + * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device + */ + rv = hwgraph_traverse(xtalk, pathname, &xwidget); + if ( (rv != GRAPH_SUCCESS) ) { + if (!xwidget) { + continue; + } + } + + sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); + pci_bus = NULL; + if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) + if (!pci_bus) { + continue; +} + + /* + * Assign the correct bus number and also the nasid of this + * pci Xwidget. + * + * Should not be any race here ... + */ + num_bridges++; + busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; + + /* + * Get the master node and from there get the NASID. + */ + master_node_vertex = device_master_get(xwidget); + if (!master_node_vertex) { + printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); + } + + hubinfo_get(master_node_vertex, &hubinfo); + if (!hubinfo) { + printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); + return(1); + } else { + busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; + } + + /* + * Pre assign DMA maps needed for 32 Bits Page Map DMA. + */ + busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); + if (!busnum_to_atedmamaps[num_bridges - 1]) + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); + + memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); + + } + + /* + * PCIX devices + * We number busses differently for PCI-X devices. + * We start from Lowest Widget on up .. + */ + + (void) ioconfig_get_busnum((char *)io_moduleid, &basebus_num); + + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + + /* Do both buses */ + for ( bus = 0; bus < 2; bus++ ) { + sprintf(pathname, "%d", widgetnum); + xwidget = NULL; + + /* + * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget + * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0 is the bus + * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0/1 is device + */ + rv = hwgraph_traverse(xtalk, pathname, &xwidget); + if ( (rv != GRAPH_SUCCESS) ) { + if (!xwidget) { + continue; + } + } + + if ( bus == 0 ) + sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); + else + sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); + pci_bus = NULL; + if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) + if (!pci_bus) { + continue; + } + + /* + * Assign the correct bus number and also the nasid of this + * pci Xwidget. + * + * Should not be any race here ... + */ + bus_number = basebus_num + bus + io_brick_map_widget(MODULE_PXBRICK, widgetnum); +#ifdef DEBUG + printk("bus_number %d basebus_num %d bus %d io %d\n", + bus_number, basebus_num, bus, + io_brick_map_widget(MODULE_PXBRICK, widgetnum)); +#endif + busnum_to_pcibr_vhdl[bus_number] = pci_bus; + + /* + * Pre assign DMA maps needed for 32 Bits Page Map DMA. + */ + busnum_to_atedmamaps[bus_number] = (void *) kmalloc( + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); + if (!busnum_to_atedmamaps[bus_number]) + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); + + memset(busnum_to_atedmamaps[bus_number], 0x0, + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); + } + } + + return(0); +} + +/* + * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure + * initialization has completed to set up the mappings between Xbridge + * and logical pci bus numbers. We also set up the NASID for each of these + * xbridges. + * + * Must be called before pci_init() is invoked. + */ +int +pci_bus_to_hcl_cvlink(void) +{ + + devfs_handle_t devfs_hdl = NULL; + devfs_handle_t xtalk = NULL; + int rv = 0; + char name[256]; + char tmp_name[256]; + int i, ii, j; + char *brick_name; + extern void ioconfig_bus_new_entries(void); + + /* + * Figure out which IO Brick is connected to the Compute Bricks. + */ + for (i = 0; i < nummodules; i++) { + extern int iomoduleid_get(nasid_t); + moduleid_t iobrick_id; + nasid_t nasid = -1; + int nodecnt; + int n = 0; + + nodecnt = modules[i]->nodecnt; + for ( n = 0; n < nodecnt; n++ ) { + nasid = cnodeid_to_nasid(modules[i]->nodes[n]); + iobrick_id = iomoduleid_get(nasid); + if ((int)iobrick_id > 0) { /* Valid module id */ + char name[12]; + memset(name, 0, 12); + format_module_id((char *)&(modules[i]->io[n].moduleid), iobrick_id, MODULE_FORMAT_BRIEF); + } + } + } + + devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); + for (i = 0; i < nummodules ; i++) { + for ( j = 0; j < 3; j++ ) { + if ( j == 0 ) + brick_name = EDGE_LBL_PBRICK; + else if ( j == 1 ) + brick_name = EDGE_LBL_PXBRICK; + else + brick_name = EDGE_LBL_IXBRICK; + + for ( ii = 0; ii < 2 ; ii++ ) { + memset(name, 0, 256); + memset(tmp_name, 0, 256); + format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); + sprintf(tmp_name, "/slab/%d/%s/xtalk", geo_slab(modules[i]->geoid[ii]), brick_name); + strcat(name, tmp_name); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); + if ( rv == 0 ) + pci_bus_map_create(xtalk, (char *)&(modules[i]->io[ii].moduleid)); + } + } + } + + /* + * Create the Linux PCI bus number vertex link. + */ + (void)linux_bus_cvlink(); + (void)ioconfig_bus_new_entries(); + + return(0); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/Makefile --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/Makefile Mon Dec 30 14:16:56 2002 @@ -0,0 +1,23 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io pcibr routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +ifdef CONFIG_IA64_SGI_SN2 +EXTRA_CFLAGS += -DSHUB_SWAP_WAR +endif + +O_TARGET := pcibr.o + +obj-$(CONFIG_IA64_SGI_SN2) += pcibr_dvr.o pcibr_ate.o pcibr_config.o \ + pcibr_dvr.o pcibr_hints.o \ + pcibr_intr.o pcibr_rrb.o pcibr_slot.o \ + pcibr_error.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -44,24 +44,6 @@ #endif -#ifdef LATER -#if (PCIBR_FREEZE_TIME) || PCIBR_ATE_DEBUG -LOCAL struct reg_desc ate_bits[] = -{ - {0xFFFF000000000000ull, -48, "RMF", "%x"}, - {~(IOPGSIZE - 1) & /* may trim off some low bits */ - 0x0000FFFFFFFFF000ull, 0, "XIO", "%x"}, - {0x0000000000000F00ull, -8, "port", "%x"}, - {0x0000000000000010ull, 0, "Barrier"}, - {0x0000000000000008ull, 0, "Prefetch"}, - {0x0000000000000004ull, 0, "Precise"}, - {0x0000000000000002ull, 0, "Coherent"}, - {0x0000000000000001ull, 0, "Valid"}, - {0} -}; -#endif -#endif /* LATER */ - #ifndef LOCAL #define LOCAL static #endif @@ -79,7 +61,7 @@ unsigned *freeze_time_ptr, #endif unsigned *cmd_regs); -void ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); +void ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index, #if PCIBR_FREEZE_TIME @@ -119,26 +101,73 @@ int i, j; bridgereg_t old_enable, new_enable; int s; + int this_is_pic = is_pic(bridge); /* Probe SSRAM to determine its size. */ - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; + if ( this_is_pic ) { + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + bridge->b_int_enable = new_enable; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + old_enable = BRIDGE_REG_GET32((&bridge->b_int_enable)); + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + BRIDGE_REG_SET32((&bridge->b_int_enable)) = new_enable; + } + else { + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + bridge->b_int_enable = new_enable; + } + } for (i = 1; i < ATE_NUM_SIZES; i++) { /* Try writing a value */ - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; + if ( this_is_pic ) { + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = __swab64(ATE_PROBE_VALUE); + else + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; + } /* Guard against wrap */ for (j = 1; j < i; j++) bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; /* See if value was written */ - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) - largest_working_size = i; + if ( this_is_pic ) { + if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) + largest_working_size = i; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == __swab64(ATE_PROBE_VALUE)) + largest_working_size = i; + else { + if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) + largest_working_size = i; + } + } + } + } + if ( this_is_pic ) { + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_int_enable)) = old_enable; + BRIDGE_REG_GET32((&bridge->b_wid_tflush)); /* wait until Bridge PIO complete */ + } + else { + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } } - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ /* * ensure that we write and read without any interruption. @@ -146,20 +175,41 @@ */ s = splhi(); - bridge->b_wid_control = (bridge->b_wid_control - & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ + if ( this_is_pic ) { + bridge->b_wid_control = (bridge->b_wid_control + & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) + | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); + bridge->b_wid_control; /* inval addr bug war */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&(bridge->b_wid_control))) = + __swab32((BRIDGE_REG_GET32((&bridge->b_wid_control)) + & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) + | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size)); + BRIDGE_REG_GET32((&bridge->b_wid_control));/* inval addr bug war */ + } + else { + bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) + | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); + bridge->b_wid_control; /* inval addr bug war */ + } + } splx(s); num_entries = ATE_NUM_ENTRIES(largest_working_size); -#if PCIBR_ATE_DEBUG - if (num_entries) - printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries); - else - printk("bridge at 0x%x: no external ATE RAM found\n", bridge); -#endif + if (pcibr_debug_mask & PCIBR_DEBUG_ATE) { + if (num_entries) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL, + "bridge at 0x%x: clearing %d external ATEs\n", + bridge, num_entries)); + } else { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL, + "bridge at 0x%x: no external ATE RAM found\n", + bridge)); + } + } /* Initialize external mapping entries */ for (entry = 0; entry < num_entries; entry++) @@ -339,7 +389,8 @@ #endif cmd_lwa = 0; - for (slot = 0; slot < 8; ++slot) + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { cmd_reg = pcibr_soft-> bs_slot[slot]. @@ -366,28 +417,54 @@ cmd_lwa[0]; /* Flush all the write buffers in the bridge */ - for (slot = 0; slot < 8; ++slot) + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { /* Flush the write buffer associated with this * PCI device which might be using dma map RAM. */ - bridge->b_wr_req_buf[slot].reg; + if ( is_pic(bridge) ) { + bridge->b_wr_req_buf[slot].reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge)) ) { + BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg)); + } + else + bridge->b_wr_req_buf[slot].reg; + } } + } } return s; } -#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) - void -ate_write(bridge_ate_p ate_ptr, +ate_write(pcibr_soft_t pcibr_soft, + bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate) { - while (ate_count-- > 0) { - *ate_ptr++ = ate; - ate += IOPGSIZE; - } + if (IS_PIC_SOFT(pcibr_soft) ) { + while (ate_count-- > 0) { + *ate_ptr++ = ate; + ate += IOPGSIZE; + } + } + else { + if (io_get_sh_swapper(NASID_GET(ate_ptr))) { + while (ate_count-- > 0) { + *ate_ptr++ = __swab64(ate); + ate += IOPGSIZE; + } + } + else { + while (ate_count-- > 0) { + *ate_ptr++ = ate; + ate += IOPGSIZE; + } + } + } } #if PCIBR_FREEZE_TIME @@ -425,10 +502,24 @@ return; /* restore cmd regs */ - for (slot = 0; slot < 8; ++slot) - if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) - bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; - + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) { + if ( IS_PIC_SOFT(pcibr_soft) ) { + pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg); + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = __swab32(cmd_reg); + } + else { +// BUG(); /* Does this really work if called when io_get_sh_swapper = 0? */ +// bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; + pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg); + } + } + } + } pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); @@ -442,7 +533,7 @@ if (max_ate_total < ate_total) max_ate_total = ate_total; pcibr_unlock(pcibr_soft, s); - printk("%s: pci freeze time %d usec for %d ATEs\n" + printk( "%s: pci freeze time %d usec for %d ATEs\n" "\tfirst ate: %R\n", pcibr_soft->bs_name, freeze_time * 1000 / 1250, diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c Fri Jan 3 08:49:36 2003 @@ -4,12 +4,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include #include #include #include @@ -34,12 +35,12 @@ extern pcibr_info_t pcibr_info_get(devfs_handle_t); uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +uint64_t do_pcibr_config_get(int, cfg_p, unsigned, unsigned); void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); -void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); +void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); +static void swap_do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); #ifdef LITTLE_ENDIAN -#ifdef CONFIG_IA64_SGI_SN1 /* * on sn-ia we need to twiddle the the addresses going out * the pci bus because we use the unswizzled synergy space @@ -49,73 +50,218 @@ #define CB(b,r) (((volatile uint8_t *) b)[((r)^4)]) #define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) #define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) -#else -#ifdef CONFIG_IA64_SGI_SN2 -/* - * On sn-ia sn2 everything is little endian. No swizzling - * or byte swapping of addresses required. - */ -#define CB(b,r) (((volatile uint8_t *) b)[(r)]) -#define CS(b,r) (((volatile uint16_t *) b)[(r)/2]) -#define CW(b,r) (((volatile uint32_t *) b)[(r)/4]) -#endif -#endif + +#define CBP(b,r) (((volatile uint8_t *) b)[(r)]) +#define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)]) +#define CWP(b,r) (((volatile uint32_t *) b)[(r)/4]) + +#define SCB(b,r) (((volatile uint8_t *) b)[((r)^3)]) +#define SCS(b,r) (((volatile uint16_t *) b)[((r^2)/2)]) +#define SCW(b,r) (((volatile uint32_t *) b)[((r)/4)]) #else #define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) #define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) #define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) #endif +/* + * Return a config space address for given slot / func / offset. Note the + * returned pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to + * the 32bit word that contains the "offset" byte. + */ +cfg_p +pcibr_func_config_addr(bridge_t *bridge, pciio_bus_t bus, pciio_slot_t slot, + pciio_function_t func, int offset) +{ + /* + * Type 1 config space + */ + if (bus > 0) { + bridge->b_pci_cfg = ((bus << 16) | (slot << 11)); + return &bridge->b_type1_cfg.f[func].l[(offset)]; + } + + /* + * Type 0 config space + */ + if (is_pic(bridge)) + slot++; + return &bridge->b_type0_cfg_dev[slot].f[func].l[offset]; +} + +/* + * Return config space address for given slot / offset. Note the returned + * pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to the + * 32bit word that contains the "offset" byte. + */ +cfg_p +pcibr_slot_config_addr(bridge_t *bridge, pciio_slot_t slot, int offset) +{ + return pcibr_func_config_addr(bridge, 0, slot, 0, offset); +} + +/* + * Return config space data for given slot / offset + */ +unsigned +pcibr_slot_config_get(bridge_t *bridge, pciio_slot_t slot, int offset) +{ + cfg_p cfg_base; + + cfg_base = pcibr_slot_config_addr(bridge, slot, 0); + return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned))); +} + +/* + * Return config space data for given slot / func / offset + */ +unsigned +pcibr_func_config_get(bridge_t *bridge, pciio_slot_t slot, + pciio_function_t func, int offset) +{ + cfg_p cfg_base; + + cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); + return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned))); +} + +/* + * Set config space data for given slot / offset + */ +void +pcibr_slot_config_set(bridge_t *bridge, pciio_slot_t slot, + int offset, unsigned val) +{ + cfg_p cfg_base; + + cfg_base = pcibr_slot_config_addr(bridge, slot, 0); + do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val); +} + +/* + * Set config space data for given slot / func / offset + */ +void +pcibr_func_config_set(bridge_t *bridge, pciio_slot_t slot, + pciio_function_t func, int offset, unsigned val) +{ + cfg_p cfg_base; + + cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); + do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val); +} + +int pcibr_config_debug = 0; cfg_p pcibr_config_addr(devfs_handle_t conn, unsigned reg) { pcibr_info_t pcibr_info; + pciio_bus_t pciio_bus; pciio_slot_t pciio_slot; pciio_function_t pciio_func; pcibr_soft_t pcibr_soft; bridge_t *bridge; cfg_p cfgbase = (cfg_p)0; + pciio_info_t pciio_info; + pciio_info = pciio_info_get(conn); pcibr_info = pcibr_info_get(conn); - pciio_slot = pcibr_info->f_slot; + /* + * Determine the PCI bus/slot/func to generate a config address for. + */ + + if (pciio_info_type1_get(pciio_info)) { + /* + * Conn is a vhdl which uses TYPE 1 addressing explicitly passed + * in reg. + */ + pciio_bus = PCI_TYPE1_BUS(reg); + pciio_slot = PCI_TYPE1_SLOT(reg); + pciio_func = PCI_TYPE1_FUNC(reg); + + ASSERT(pciio_bus != 0); +#if 0 + } else if (conn != pciio_info_hostdev_get(pciio_info)) { + /* + * Conn is on a subordinate bus, so get bus/slot/func directly from + * its pciio_info_t structure. + */ + pciio_bus = pciio_info->c_bus; + pciio_slot = pciio_info->c_slot; + pciio_func = pciio_info->c_func; + if (pciio_func == PCIIO_FUNC_NONE) { + pciio_func = 0; + } +#endif + } else { + /* + * Conn is directly connected to the host bus. PCI bus number is + * hardcoded to 0 (even though it may have a logical bus number != 0) + * and slot/function are derived from the pcibr_info_t associated + * with the device. + */ + pciio_bus = 0; + + pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info); if (pciio_slot == PCIIO_SLOT_NONE) pciio_slot = PCI_TYPE1_SLOT(reg); pciio_func = pcibr_info->f_func; if (pciio_func == PCIIO_FUNC_NONE) pciio_func = PCI_TYPE1_FUNC(reg); + } pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; bridge = pcibr_soft->bs_base; - cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; + cfgbase = pcibr_func_config_addr(bridge, + pciio_bus, pciio_slot, pciio_func, 0); return cfgbase; } +extern unsigned char Is_pic_on_this_nasid[]; uint64_t pcibr_config_get(devfs_handle_t conn, unsigned reg, unsigned size) { - return do_pcibr_config_get(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size); + if ( !Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] ) + return do_pcibr_config_get(0, pcibr_config_addr(conn, reg), + PCI_TYPE1_REG(reg), size); + else + return do_pcibr_config_get(1, pcibr_config_addr(conn, reg), + PCI_TYPE1_REG(reg), size); } uint64_t do_pcibr_config_get( + int pic, cfg_p cfgbase, unsigned reg, unsigned size) { unsigned value; - value = CW(cfgbase, reg); - + if ( pic ) { + value = CWP(cfgbase, reg); + } + else { + if ( io_get_sh_swapper(NASID_GET(cfgbase)) ) { + /* + * Shub Swapper on - 0 returns PCI Offset 0 but byte swapped! + * Do not swizzle address and byte swap the result. + */ + value = SCW(cfgbase, reg); + value = __swab32(value); + } else { + value = CW(cfgbase, reg); + } + } if (reg & 3) value >>= 8 * (reg & 3); if (size < 4) @@ -129,39 +275,103 @@ unsigned size, uint64_t value) { - do_pcibr_config_set(pcibr_config_addr(conn, reg), + if ( Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] ) + do_pcibr_config_set(1, pcibr_config_addr(conn, reg), + PCI_TYPE1_REG(reg), size, value); + else + swap_do_pcibr_config_set(pcibr_config_addr(conn, reg), PCI_TYPE1_REG(reg), size, value); } void -do_pcibr_config_set(cfg_p cfgbase, +do_pcibr_config_set(int pic, + cfg_p cfgbase, unsigned reg, unsigned size, uint64_t value) { + if ( pic ) { + switch (size) { + case 1: + CBP(cfgbase, reg) = value; + break; + case 2: + if (reg & 1) { + CBP(cfgbase, reg) = value; + CBP(cfgbase, reg + 1) = value >> 8; + } else + CSP(cfgbase, reg) = value; + break; + case 3: + if (reg & 1) { + CBP(cfgbase, reg) = value; + CSP(cfgbase, (reg + 1)) = value >> 8; + } else { + CSP(cfgbase, reg) = value; + CBP(cfgbase, reg + 2) = value >> 16; + } + break; + case 4: + CWP(cfgbase, reg) = value; + break; + } + } + else { + switch (size) { + case 1: + CB(cfgbase, reg) = value; + break; + case 2: + if (reg & 1) { + CB(cfgbase, reg) = value; + CB(cfgbase, reg + 1) = value >> 8; + } else + CS(cfgbase, reg) = value; + break; + case 3: + if (reg & 1) { + CB(cfgbase, reg) = value; + CS(cfgbase, (reg + 1)) = value >> 8; + } else { + CS(cfgbase, reg) = value; + CB(cfgbase, reg + 2) = value >> 16; + } + break; + case 4: + CW(cfgbase, reg) = value; + break; + } + } +} + +void +swap_do_pcibr_config_set(cfg_p cfgbase, + unsigned reg, + unsigned size, + uint64_t value) +{ + + uint64_t temp_value = 0; + switch (size) { case 1: - CB(cfgbase, reg) = value; - break; + SCB(cfgbase, reg) = value; + break; case 2: - if (reg & 1) { - CB(cfgbase, reg) = value; - CB(cfgbase, reg + 1) = value >> 8; - } else - CS(cfgbase, reg) = value; - break; + temp_value = __swab16(value); + if (reg & 1) { + SCB(cfgbase, reg) = temp_value; + SCB(cfgbase, reg + 1) = temp_value >> 8; + } else + SCS(cfgbase, reg) = temp_value; + break; case 3: - if (reg & 1) { - CB(cfgbase, reg) = value; - CS(cfgbase, (reg + 1)) = value >> 8; - } else { - CS(cfgbase, reg) = value; - CB(cfgbase, reg + 2) = value >> 16; - } - break; + BUG(); + break; case 4: - CW(cfgbase, reg) = value; - break; + temp_value = __swab32(value); + SCW(cfgbase, reg) = temp_value; + break; } } diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Tue Feb 11 17:20:34 2003 @@ -4,14 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ - #include #include #include #include +#include #include #include #include @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,25 @@ #endif /* + * global variables to toggle the different levels of pcibr debugging. + * -pcibr_debug_mask is the mask of the different types of debugging + * you want to enable. See sys/PCI/pcibr_private.h + * -pcibr_debug_module is the module you want to trace. By default + * all modules are trace. For IP35 this value has the format of + * something like "001c10". For IP27 this value is a node number, + * i.e. "1", "2"... For IP30 this is undefined and should be set to + * 'all'. + * -pcibr_debug_widget is the widget you want to trace. For IP27 + * the widget isn't exposed in the hwpath so use the xio slot num. + * i.e. for 'io2' set pcibr_debug_widget to "2". + * -pcibr_debug_slot is the pci slot you want to trace. + */ +uint32_t pcibr_debug_mask = 0x0; /* 0x00000000 to disable */ +char *pcibr_debug_module = "all"; /* 'all' for all modules */ +int pcibr_debug_widget = -1; /* '-1' for all widgets */ +int pcibr_debug_slot = -1; /* '-1' for all slots */ + +/* * Macros related to the Lucent USS 302/312 usb timeout workaround. It * appears that if the lucent part can get into a retry loop if it sees a * DAC on the bus during a pio read retry. The loop is broken after about @@ -58,68 +78,6 @@ int pcibr_devflag = D_MP; -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -struct file_operations pcibr_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: NULL, - open: NULL, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL -}; - -#ifdef LATER - -#if PCIBR_ATE_DEBUG -static struct reg_values ssram_sizes[] = -{ - {BRIDGE_CTRL_SSRAM_512K, "512k"}, - {BRIDGE_CTRL_SSRAM_128K, "128k"}, - {BRIDGE_CTRL_SSRAM_64K, "64k"}, - {BRIDGE_CTRL_SSRAM_1K, "1k"}, - {0} -}; - -static struct reg_desc control_bits[] = -{ - {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"}, - {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"}, - {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"}, - {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"}, - {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"}, - {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"}, - {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"}, - {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"}, - {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"}, - {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"}, - {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes}, - {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"}, - {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"}, - {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"}, - {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"}, - {BRIDGE_CTRL_SYS_END, 0, "SYS_END"}, - - {BRIDGE_CTRL_BUS_SPEED_MASK, -4, "BUS_SPEED", "%d"}, - {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"}, - {0} -}; -#endif -#endif /* LATER */ - /* kbrick widgetnum-to-bus layout */ int p_busnum[MAX_PORT_NUM] = { /* widget# */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ @@ -132,18 +90,6 @@ 3, /* 0xf */ }; -/* - * Additional PIO spaces per slot are - * recorded in this structure. - */ -struct pciio_piospace_s { - pciio_piospace_t next; /* another space for this device */ - char free; /* 1 if free, 0 if in use */ - pciio_space_t space; /* Which space is in use */ - iopaddr_t start; /* Starting address of the PIO space */ - size_t count; /* size of PIO space */ -}; - #if PCIBR_SOFT_LIST pcibr_list_p pcibr_list = 0; #endif @@ -152,15 +98,15 @@ extern int hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags); extern long atoi(register char *p); extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); -extern void *swap_ptr(void **loc, void *new); extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); extern struct map *atemapalloc(uint64_t); extern void atefree(struct map *, size_t, uint64_t); extern void atemapfree(struct map *); extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); extern void free_pciio_dmamap(pcibr_dmamap_t); +extern void xwidget_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); -#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) +#define ATE_WRITE() ate_write(pcibr_soft, ate_ptr, ate_count, ate) #if PCIBR_FREEZE_TIME #define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) #else @@ -173,7 +119,6 @@ #define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) #endif - /* ===================================================================== * Function Table of Contents * @@ -183,58 +128,54 @@ * perhaps bust this file into smaller chunks. */ -extern void do_pcibr_rrb_clear(bridge_t *, int); -extern void do_pcibr_rrb_flush(bridge_t *, int); -extern int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); -extern int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); -extern int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); -extern int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); - -extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); +extern int do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t); +extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); extern int pcibr_wrb_flush(devfs_handle_t); extern int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -extern int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); -extern int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); extern void pcibr_rrb_flush(devfs_handle_t); static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); -extern void pcibr_clearwidint(bridge_t *); extern void pcibr_setwidint(xtalk_intr_t); +extern void pcibr_clearwidint(bridge_t *); + +extern iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, + pciio_space_t, int, int, int); void pcibr_init(void); int pcibr_attach(devfs_handle_t); +int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, + int, pcibr_soft_t *); int pcibr_detach(devfs_handle_t); int pcibr_open(devfs_handle_t *, int, int, cred_t *); int pcibr_close(devfs_handle_t, int, int, cred_t *); int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); int pcibr_unmap(devfs_handle_t, vhandl_t *); int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); - -void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); - +int pcibr_pcix_rbars_calc(pcibr_soft_t); extern int pcibr_init_ext_ate_ram(bridge_t *); extern int pcibr_ate_alloc(pcibr_soft_t, int); extern void pcibr_ate_free(pcibr_soft_t, int, int); +extern int pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl); -extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, +extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, #if PCIBR_FREEZE_TIME unsigned *freeze_time_ptr, #endif - unsigned *cmd_regs); -extern void ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); -extern void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index, + unsigned *cmd_regs); +extern void ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); +extern void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index, #if PCIBR_FREEZE_TIME - bridge_ate_t ate, - int ate_total, - unsigned freeze_time_start, + bridge_ate_t ate, + int ate_total, + unsigned freeze_time_start, #endif - unsigned *cmd_regs, - unsigned s); + unsigned *cmd_regs, + unsigned s); -pcibr_info_t pcibr_info_get(devfs_handle_t); +pcibr_info_t pcibr_info_get(devfs_handle_t); static iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); @@ -264,23 +205,23 @@ void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); -extern unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); +extern unsigned pcibr_intr_bits(pciio_info_t info, + pciio_intr_line_t lines, int nslots); extern pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); extern void pcibr_intr_free(pcibr_intr_t); extern void pcibr_setpciint(xtalk_intr_t); -extern int pcibr_intr_connect(pcibr_intr_t); +extern int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); extern void pcibr_intr_disconnect(pcibr_intr_t); extern devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); -extern void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); extern void pcibr_intr_func(intr_arg_t); extern void print_bridge_errcmd(uint32_t, char *); extern void pcibr_error_dump(pcibr_soft_t); -extern uint32_t pcibr_errintr_group(uint32_t); +extern uint32_t pcibr_errintr_group(uint32_t); extern void pcibr_pioerr_check(pcibr_soft_t); -extern void pcibr_error_intr_handler(intr_arg_t); +extern void pcibr_error_intr_handler(int, void *, struct pt_regs *); extern int pcibr_addr_toslot(pcibr_soft_t, iopaddr_t, pciio_space_t *, iopaddr_t *, pciio_function_t *); extern void pcibr_error_cleanup(pcibr_soft_t, int); @@ -289,8 +230,7 @@ extern int pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); extern int pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); extern int pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); -extern int pcibr_error_devenable(devfs_handle_t, int); - +extern int pcibr_error_handler_wrapper(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); void pcibr_provider_startup(devfs_handle_t); void pcibr_provider_shutdown(devfs_handle_t); @@ -303,7 +243,6 @@ extern cfg_p pcibr_config_addr(devfs_handle_t, unsigned); extern uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); extern void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); -extern void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); extern pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); extern void pcibr_hints_fix_rrbs(devfs_handle_t); @@ -313,37 +252,56 @@ extern void pcibr_hints_handsoff(devfs_handle_t); extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); -#ifdef BRIDGE_B_DATACORR_WAR -extern int ql_bridge_rev_b_war(devfs_handle_t); -extern int bridge_rev_b_data_check_disable; -char *rev_b_datacorr_warning = -"***************************** WARNING! ******************************\n"; -char *rev_b_datacorr_mesg = -"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n"; -#endif - extern int pcibr_slot_reset(devfs_handle_t,pciio_slot_t); extern int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); extern int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, + pcibr_slot_info_resp_t); +extern void pcibr_slot_func_info_return(pcibr_info_h, int, + pcibr_slot_func_info_resp_t); extern int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t); extern int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); extern int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); -extern int pcibr_slot_call_device_attach(devfs_handle_t, pciio_slot_t, int); -extern int pcibr_slot_call_device_detach(devfs_handle_t, pciio_slot_t, int); -extern int pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, char *, int *); -extern int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); +extern int pcibr_slot_call_device_attach(devfs_handle_t, + pciio_slot_t, int); +extern int pcibr_slot_call_device_detach(devfs_handle_t, + pciio_slot_t, int); +extern int pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, + char *, int *); +extern int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int, + char *, int *); extern int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); -#ifdef LATER -extern int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t); -extern int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t); -extern int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t); -#endif - extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t, pciio_slot_t); extern int pcibr_initial_rrb(devfs_handle_t, pciio_slot_t, pciio_slot_t); - +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +static int pcibr_mmap(struct file * file, struct vm_area_struct * vma); +struct file_operations pcibr_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: pcibr_mmap, + open: pcibr_open, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL, + sendpage: NULL, + get_unmapped_area: NULL +}; /* ===================================================================== * Device(x) register management @@ -377,7 +335,7 @@ bridgereg_t xmask; xmask = mask; - if (pcibr_soft->bs_xbridge) { + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { if (mask == BRIDGE_DEV_PMU_BITS) xmask = XBRIDGE_DEV_PMU_BITS; if (mask == BRIDGE_DEV_D64_BITS) @@ -464,10 +422,10 @@ new &= ~BRIDGE_DEV_WRGA_BITS; if (flags & PCIIO_BYTE_STREAM) - new |= (pcibr_soft->bs_xbridge) ? + new |= (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) ? BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS; if (flags & PCIIO_WORD_VALUES) - new &= (pcibr_soft->bs_xbridge) ? + new &= (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) ? ~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS; /* Provider-specific flags @@ -492,13 +450,28 @@ if (flags & PCIBR_NO64BIT) new &= ~BRIDGE_DEV_DEV_SIZE; + /* + * PIC BRINGUP WAR (PV# 855271): + * Allow setting BRIDGE_DEV_VIRTUAL_EN on PIC iff we're a 64-bit + * device. The bit is only intended for 64-bit devices and, on + * PIC, can cause problems for 32-bit devices. + */ + if (IS_PIC_SOFT(pcibr_soft) && mask == BRIDGE_DEV_D64_BITS && + PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { + if (flags & PCIBR_VCHAN1) { + new |= BRIDGE_DEV_VIRTUAL_EN; + xmask |= BRIDGE_DEV_VIRTUAL_EN; + } + } + + chg = old ^ new; /* what are we changing, */ chg &= xmask; /* of the interesting bits */ if (chg) { badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; - if (pcibr_soft->bs_xbridge) { + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; } else { @@ -517,7 +490,7 @@ * the new stream at all. */ if ( (fix = bad & (BRIDGE_DEV_PRECISE | - BRIDGE_DEV_BARRIER)) ){ + BRIDGE_DEV_BARRIER)) ) { bad &= ~fix; /* don't change these bits if * they are already set in "old" @@ -546,8 +519,10 @@ */ if (bad) { pcibr_unlock(pcibr_soft, s); -#if (DEBUG && PCIBR_DEV_DEBUG) - printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits); +#ifdef PIC_LATER + PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, + "pcibr_try_set_device: mod blocked by %x\n", + bad, device_bits)); #endif return bad; } @@ -571,14 +546,31 @@ pcibr_unlock(pcibr_soft, s); return 0; } - bridge->b_device[slot].reg = new; - slotp->bss_device = new; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_device[slot].reg = new; + slotp->bss_device = new; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_device[slot].reg)) = __swab32(new); + slotp->bss_device = new; + BRIDGE_REG_GET32((&bridge->b_wid_tflush)); /* wait until Bridge PIO complete */ + } else { + bridge->b_device[slot].reg = new; + slotp->bss_device = new; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + } pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg); -#endif +#ifdef PIC_LATER + PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, + "pcibr_try_set_device: Device(%d): %x\n", + slot, new, device_bits)); +#else + printk("pcibr_try_set_device: Device(%d): %x\n", slot, new); +#endif return 0; } @@ -616,7 +608,17 @@ volatile uint32_t wrf; s = pcibr_lock(pcibr_soft); bridge = pcibr_soft->bs_base; - wrf = bridge->b_wr_req_buf[slot].reg; + + if ( IS_PIC_SOFT(pcibr_soft) ) { + wrf = bridge->b_wr_req_buf[slot].reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + wrf = BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg)); + } else { + wrf = bridge->b_wr_req_buf[slot].reg; + } + } pcibr_unlock(pcibr_soft, s); } @@ -637,9 +639,7 @@ void pcibr_init(void) { -#if DEBUG && ATTACH_DEBUG - printk("pcibr_init\n"); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pcibr_init()\n")); xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, XBRIDGE_WIDGET_MFGR_NUM, @@ -675,6 +675,27 @@ return 0; } +static int +pcibr_mmap(struct file * file, struct vm_area_struct * vma) +{ + devfs_handle_t pcibr_vhdl; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + unsigned long phys_addr; + int error = 0; + + pcibr_vhdl = (devfs_handle_t) file->private_data; + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge = pcibr_soft->bs_base; + phys_addr = (unsigned long)bridge & ~0xc000000000000000; /* Mask out the Uncache bits */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; + error = io_remap_page_range(vma->vm_start, phys_addr, + vma->vm_end-vma->vm_start, + vma->vm_page_prot); + return(error); +} + /*ARGSUSED */ int pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) @@ -700,7 +721,7 @@ * XXX- deprecate this in favor of using the * real flash driver ... */ - if (!error && + if (IS_BRIDGE_SOFT(pcibr_soft) && !error && ((off == BRIDGE_EXTERNAL_FLASH) || (len > BRIDGE_EXTERNAL_FLASH))) { int s; @@ -710,11 +731,16 @@ * The read following the write is required for the Bridge war */ s = splhi(); - bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ + + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_wid_control)) |= __swab32(BRIDGE_CTRL_FLASH_WR_EN); + BRIDGE_REG_GET32((&bridge->b_wid_control)); /* inval addr bug war */ + } else { + bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; + bridge->b_wid_control; /* inval addr bug war */ + } splx(s); } - return error; } @@ -728,21 +754,53 @@ hwgraph_vertex_unref(pcibr_vhdl); - /* - * If flashprom write was enabled, disable it, as - * this is the last unmap. - */ - if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { - int s; - + if ( IS_PIC_SOFT(pcibr_soft) ) { /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war + * If flashprom write was enabled, disable it, as + * this is the last unmap. */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); + if (IS_BRIDGE_SOFT(pcibr_soft) && + (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN)) { + int s; + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + s = splhi(); + bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + } + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + if (BRIDGE_REG_GET32((&bridge->b_wid_control)) & BRIDGE_CTRL_FLASH_WR_EN) { + int s; + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + s = splhi(); + BRIDGE_REG_SET32((&bridge->b_wid_control)) &= __swab32((unsigned int)~BRIDGE_CTRL_FLASH_WR_EN); + BRIDGE_REG_GET32((&bridge->b_wid_control)); /* inval addr bug war */ + splx(s); + } else { + if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { + int s; + + /* + * ensure that we write and read without any interruption. + * The read following the write is required for the Bridge war + */ + s = splhi(); + bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; + bridge->b_wid_control; /* inval addr bug war */ + splx(s); + } + } + } } return 0; } @@ -768,7 +826,7 @@ while (tdev != GRAPH_VERTEX_NONE) { pciio_info = pciio_info_chk(tdev); if (pciio_info) { - slot = pciio_info_slot_get(pciio_info); + slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); break; } hwgraph_vertex_unref(tdev); @@ -788,167 +846,7 @@ struct cred *cr, int *rvalp) { - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); -#ifdef LATER - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); -#endif - int error = 0; - - hwgraph_vertex_unref(pcibr_vhdl); - - switch (cmd) { -#ifdef LATER - case GIOCSETBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able((uint64_t)CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH); - break; - } - - case GIOCRELEASEBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); - break; - } - - case PCIBR_SLOT_STARTUP: - { - struct pcibr_slot_req_s req; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &req, sizeof(req))) { - error = EFAULT; - break; - } - - error = pcibr_slot_startup(pcibr_vhdl, &req); - break; - } - case PCIBR_SLOT_SHUTDOWN: - { - struct pcibr_slot_req_s req; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &req, sizeof(req))) { - error = EFAULT; - break; - } - - error = pcibr_slot_shutdown(pcibr_vhdl, &req); - break; - } - case PCIBR_SLOT_QUERY: - { - struct pcibr_slot_req_s req; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &req, sizeof(req))) { - error = EFAULT; - break; - } - - error = pcibr_slot_query(pcibr_vhdl, &req); - break; - } -#endif /* LATER */ - default: - break; - - } - - return error; -} - -void -pcibr_freeblock_sub(iopaddr_t *free_basep, - iopaddr_t *free_lastp, - iopaddr_t base, - size_t size) -{ - iopaddr_t free_base = *free_basep; - iopaddr_t free_last = *free_lastp; - iopaddr_t last = base + size - 1; - - if ((last < free_base) || (base > free_last)); /* free block outside arena */ - - else if ((base <= free_base) && (last >= free_last)) - /* free block contains entire arena */ - *free_basep = *free_lastp = 0; - - else if (base <= free_base) - /* free block is head of arena */ - *free_basep = last + 1; - - else if (last >= free_last) - /* free block is tail of arena */ - *free_lastp = base - 1; - - /* - * We are left with two regions: the free area - * in the arena "below" the block, and the free - * area in the arena "above" the block. Keep - * the one that is bigger. - */ - - else if ((base - free_base) > (free_last - last)) - *free_lastp = base - 1; /* keep lower chunk */ - else - *free_basep = last + 1; /* keep upper chunk */ + return 0; } pcibr_info_t @@ -971,16 +869,22 @@ func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; + /* + * Create a pciio_info_s for this device. pciio_device_info_new() + * will set the c_slot (which is suppose to represent the external + * slot (i.e the slot number silk screened on the back of the I/O + * brick)). So for PIC we need to adjust this "internal slot" num + * passed into us, into it's external representation. See comment + * for the PCIBR_DEVICE_TO_SLOT macro for more information. + */ NEW(pcibr_info); + pciio_device_info_new(&pcibr_info->f_c, pcibr_soft->bs_vhdl, + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + rfunc, vendor, device); + pcibr_info->f_dev = slot; - pciio_device_info_new(&pcibr_info->f_c, - pcibr_soft->bs_vhdl, - slot, rfunc, - vendor, device); - -/* pfg - this is new ..... */ /* Set PCI bus number */ - pcibr_info->f_bus = io_path_map_widget(pcibr_soft->bs_vhdl); + pcibr_info->f_bus = pcibr_widget_to_bus(pcibr_soft->bs_vhdl); if (slot != PCIIO_SLOT_NONE) { @@ -1016,30 +920,6 @@ } -/* FIXME: for now this is needed by both pcibr.c and - * pcibr_slot.c. Need to find a better way, the least - * of which would be to move it to pcibr_private.h - */ - -/* - * PCI_ADDR_SPACE_LIMITS_STORE - * Sets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_STORE() \ - pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ - pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ - pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ - pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ - pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ - pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; - - /* * pcibr_device_unregister * This frees up any hardware resources reserved for this PCI device @@ -1062,7 +942,7 @@ pciio_info = pciio_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = pciio_info_slot_get(pciio_info); + slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge = pcibr_soft->bs_base; @@ -1077,27 +957,24 @@ * If the RRB configuration for this slot has changed, set it * back to the boot-time default */ - if (pcibr_soft->bs_rrb_valid_dflt[slot] >= 0) { + if (pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] >= 0) { s = pcibr_lock(pcibr_soft); - /* Free the rrbs allocated to this slot */ - error_call = do_pcibr_rrb_free(bridge, slot, - pcibr_soft->bs_rrb_valid[slot] + - pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]); - - if (error_call) - error = ERANGE; - - pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] + - pcibr_soft->bs_rrb_valid[slot] + - pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]; - - count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot]; - count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot + - PCIBR_RRB_SLOT_VIRTUAL]; + /* PIC NOTE: If this is a BRIDGE, VCHAN2 & VCHAN3 will be zero so + * no need to conditionalize this (ie. "if (IS_PIC_SOFT())" ). + */ + pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] + + pcibr_soft->bs_rrb_valid[slot][VCHAN0] + + pcibr_soft->bs_rrb_valid[slot][VCHAN1] + + pcibr_soft->bs_rrb_valid[slot][VCHAN2] + + pcibr_soft->bs_rrb_valid[slot][VCHAN3]; + + /* Free the rrbs allocated to this slot, both the normal & virtual */ + do_pcibr_rrb_free_all(pcibr_soft, bridge, slot); + + count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0]; + count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN1]; pcibr_unlock(pcibr_soft, s); @@ -1147,12 +1024,14 @@ pcibr_info = pcibr_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = pciio_info_slot_get(pciio_info); + slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); +#ifdef PIC_LATER /* This may be a loadable driver so lock out any pciconfig actions */ mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); +#endif pcibr_info->f_att_det_error = error; @@ -1164,9 +1043,10 @@ pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; } +#ifdef PIC_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock); - +#endif } /* @@ -1195,12 +1075,14 @@ pcibr_info = pcibr_info_get(pconn_vhdl); pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = pciio_info_slot_get(pciio_info); + slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); +#ifdef PIC_LATER /* This may be a loadable driver so lock out any pciconfig actions */ mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); +#endif pcibr_info->f_att_det_error = error; @@ -1211,10 +1093,11 @@ } else { pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; } - + +#ifdef PIC_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock); - +#endif } /* @@ -1226,7 +1109,7 @@ * depends on hwgraph separator == '/' */ int -pcibr_bus_cnvlink(devfs_handle_t f_c, int slot) +pcibr_bus_cnvlink(devfs_handle_t f_c) { char dst[MAXDEVNAME]; char *dp = dst; @@ -1236,16 +1119,7 @@ devfs_handle_t nvtx, svtx; int rv; -#if DEBUG - printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", - slot, f_c); - { - int pos; - char dname[256]; - pos = devfs_generate_path(f_c, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, f_c, "pcibr_bus_cnvlink\n")); if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME)) return 0; @@ -1261,7 +1135,7 @@ return 0; /* remove "/pci/direct" from path */ - cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct"); + cp = strstr(dst, "/" EDGE_LBL_PCI "/" EDGE_LBL_DIRECT); if (cp == NULL) return 0; *cp = (char)NULL; @@ -1275,7 +1149,8 @@ /* dst example now == /hw/module/001c02/Pbrick */ /* get the bus number */ - strcat(dst, "/bus"); + strcat(dst, "/"); + strcat(dst, EDGE_LBL_BUS); sprintf(pcibus, "%d", p_busnum[widgetnum]); /* link to bus to widget */ @@ -1300,95 +1175,82 @@ /* REFERENCED */ graph_error_t rc; devfs_handle_t pcibr_vhdl; + bridge_t *bridge; + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, xconn_vhdl, "pcibr_attach\n")); + + bridge = (bridge_t *) + xtalk_piotrans_addr(xconn_vhdl, NULL, + 0, sizeof(bridge_t), 0); + /* + * Create the vertex for the PCI bus, which we + * will also use to hold the pcibr_soft and + * which will be the "master" vertex for all the + * pciio connection points we will hang off it. + * This needs to happen before we call nic_bridge_vertex_info + * as we are some of the *_vmc functions need access to the edges. + * + * Opening this vertex will provide access to + * the Bridge registers themselves. + */ + rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); + ASSERT(rc == GRAPH_SUCCESS); + + pciio_provider_register(pcibr_vhdl, &pcibr_provider); + pciio_provider_startup(pcibr_vhdl); + + return pcibr_attach2(xconn_vhdl, bridge, pcibr_vhdl, 0, NULL); +} + + +/*ARGSUSED */ +int +pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, + devfs_handle_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) +{ + /* REFERENCED */ devfs_handle_t ctlr_vhdl; - bridge_t *bridge = NULL; bridgereg_t id; int rev; pcibr_soft_t pcibr_soft; pcibr_info_t pcibr_info; xwidget_info_t info; xtalk_intr_t xtalk_intr; - device_desc_t dev_desc = (device_desc_t)0; int slot; int ibit; devfs_handle_t noslot_conn; char devnm[MAXDEVNAME], *s; pcibr_hints_t pcibr_hints; - bridgereg_t b_int_enable; + uint64_t int_enable; + bridgereg_t int_enable_32; + picreg_t int_enable_64; unsigned rrb_fixed = 0; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - int spl_level; -#ifdef LATER - char *nicinfo = (char *)0; -#endif #if PCI_FBBE int fast_back_to_back_enable; #endif - l1sc_t *scp; nasid_t nasid; + int iobrick_type_get_nasid(nasid_t nasid); + int iobrick_module_get_nasid(nasid_t nasid); + extern unsigned char Is_pic_on_this_nasid[512]; - async_attach_t aa = NULL; - - aa = async_attach_get_info(xconn_vhdl); - -#if DEBUG && ATTACH_DEBUG - printk("pcibr_attach: xconn_vhdl= %p\n", xconn_vhdl); - { - int pos; - char dname[256]; - pos = devfs_generate_path(xconn_vhdl, dname, 256); - printk("%s : path= %s \n", __FUNCTION__, &dname[pos]); - } -#endif - /* Setup the PRB for the bridge in CONVEYOR BELT - * mode. PRBs are setup in default FIRE-AND-FORGET - * mode during the initialization. - */ - hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR); + async_attach_t aa = NULL; - bridge = (bridge_t *) - xtalk_piotrans_addr(xconn_vhdl, NULL, - 0, sizeof(bridge_t), 0); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pcibr_attach2: bridge=0x%p, busnum=%d\n", bridge, busnum)); - /* - * Create the vertex for the PCI bus, which we - * will also use to hold the pcibr_soft and - * which will be the "master" vertex for all the - * pciio connection points we will hang off it. - * This needs to happen before we call nic_bridge_vertex_info - * as we are some of the *_vmc functions need access to the edges. - * - * Opening this vertex will provide access to - * the Bridge registers themselves. - */ - rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); - ASSERT(rc == GRAPH_SUCCESS); + aa = async_attach_get_info(xconn_vhdl); ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &pcibr_fops, NULL); - + ctlr_vhdl = devfs_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, + DEVFS_FL_AUTO_DEVNUM, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &pcibr_fops, (void *)pcibr_vhdl); ASSERT(ctlr_vhdl != NULL); /* - * decode the nic, and hang its stuff off our - * connection point where other drivers can get - * at it. - */ -#ifdef LATER - nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic); -#endif - - /* * Get the hint structure; if some NIC callback * marked this vertex as "hands-off" then we * just return here, before doing anything else. @@ -1408,26 +1270,63 @@ * fields, and hook it up to our vertex. */ NEW(pcibr_soft); + if (ret_softp) + *ret_softp = pcibr_soft; BZERO(pcibr_soft, sizeof *pcibr_soft); pcibr_soft_set(pcibr_vhdl, pcibr_soft); - pcibr_soft->bs_conn = xconn_vhdl; pcibr_soft->bs_vhdl = pcibr_vhdl; pcibr_soft->bs_base = bridge; pcibr_soft->bs_rev_num = rev; - pcibr_soft->bs_intr_bits = pcibr_intr_bits; + pcibr_soft->bs_intr_bits = (pcibr_intr_bits_f *)pcibr_intr_bits; + + pcibr_soft->bs_min_slot = 0; /* lowest possible slot# */ + pcibr_soft->bs_max_slot = 7; /* highest possible slot# */ + pcibr_soft->bs_busnum = busnum; if (is_xbridge(bridge)) { - pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 1; + pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_XBRIDGE; + } else if (is_pic(bridge)) { + pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; } else { + pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_BRIDGE; + } + switch(pcibr_soft->bs_bridge_type) { + case PCIBR_BRIDGETYPE_BRIDGE: pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 0; + pcibr_soft->bs_bridge_mode = 0; /* speed is not available in bridge */ + break; + case PCIBR_BRIDGETYPE_PIC: + pcibr_soft->bs_min_slot = 0; + pcibr_soft->bs_max_slot = 3; + pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; + pcibr_soft->bs_bridge_mode = + (((bridge->p_wid_stat_64 & PIC_STAT_PCIX_SPEED) >> 33) | + ((bridge->p_wid_stat_64 & PIC_STAT_PCIX_ACTIVE) >> 33)); + + /* We have to clear PIC's write request buffer to avoid parity + * errors. See PV#854845. + */ + { + int i; + + for (i=0; i < PIC_WR_REQ_BUFSIZE; i++) { + bridge->p_wr_req_lower[i] = 0; + bridge->p_wr_req_upper[i] = 0; + bridge->p_wr_req_parity[i] = 0; + } + } + + break; + case PCIBR_BRIDGETYPE_XBRIDGE: + pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; + pcibr_soft->bs_bridge_mode = + ((bridge->b_wid_control & BRIDGE_CTRL_PCI_SPEED) >> 3); + break; } - nasid = NASID_GET(bridge); - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - pcibr_soft->bs_l1sc = scp; - pcibr_soft->bs_moduleid = iobrick_module_get(scp); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pcibr_attach2: pcibr_soft=0x%x, mode=0x%x\n", + pcibr_soft, pcibr_soft->bs_bridge_mode)); pcibr_soft->bsi_err_intr = 0; /* Bridges up through REV C @@ -1439,6 +1338,9 @@ pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; } #if PCIBR_SOFT_LIST + /* + * link all the pcibr_soft structs + */ { pcibr_list_p self; @@ -1446,9 +1348,9 @@ self->bl_soft = pcibr_soft; self->bl_vhdl = pcibr_vhdl; self->bl_next = pcibr_list; - self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self); + pcibr_list = self; } -#endif +#endif /* PCIBR_SOFT_LIST */ /* * get the name of this bridge vertex and keep the info. Use this @@ -1458,45 +1360,130 @@ pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); strcpy(pcibr_soft->bs_name, s); -#if SHOW_REVS || DEBUG -#if !DEBUG - if (kdebug) -#endif - printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n", - is_xbridge(bridge) ? "X" : "", - (rev == BRIDGE_PART_REV_A) ? "A" : - (rev == BRIDGE_PART_REV_B) ? "B" : - (rev == BRIDGE_PART_REV_C) ? "C" : - (rev == BRIDGE_PART_REV_D) ? "D" : - (rev == XBRIDGE_PART_REV_A) ? "A" : - (rev == XBRIDGE_PART_REV_B) ? "B" : - "unknown", - rev, pcibr_soft->bs_name); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pcibr_attach2: %s ASIC: rev %s (code=0x%x)\n", + IS_XBRIDGE_SOFT(pcibr_soft) ? "XBridge" : + IS_PIC_SOFT(pcibr_soft) ? "PIC" : "Bridge", + (rev == BRIDGE_PART_REV_A) ? "A" : + (rev == BRIDGE_PART_REV_B) ? "B" : + (rev == BRIDGE_PART_REV_C) ? "C" : + (rev == BRIDGE_PART_REV_D) ? "D" : + (rev == XBRIDGE_PART_REV_A) ? "A" : + (rev == XBRIDGE_PART_REV_B) ? "B" : + (IS_PIC_PART_REV_A(rev)) ? "A" : + "unknown", rev, pcibr_soft->bs_name)); info = xwidget_info_get(xconn_vhdl); pcibr_soft->bs_xid = xwidget_info_id_get(info); pcibr_soft->bs_master = xwidget_info_master_get(info); pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); + pcibr_soft->bs_first_slot = pcibr_soft->bs_min_slot; + pcibr_soft->bs_last_slot = pcibr_soft->bs_max_slot; /* - * Init bridge lock. + * Bridge can only reset slots 0, 1, 2, and 3. Ibrick internal + * slots 4, 5, 6, and 7 must be reset as a group, so do not + * reset them. */ - spin_lock_init(&pcibr_soft->bs_lock); + pcibr_soft->bs_last_reset = 3; + nasid = NASID_GET(bridge); + + /* set whether it is a PIC or not */ + Is_pic_on_this_nasid[nasid] = (IS_PIC_SOFT(pcibr_soft)) ? 1 : 0; + + + if ((pcibr_soft->bs_bricktype = iobrick_type_get_nasid(nasid)) < 0) + printk(KERN_WARNING "0x%p: Unknown bricktype : 0x%x\n", (void *)xconn_vhdl, + (unsigned int)pcibr_soft->bs_bricktype); + + pcibr_soft->bs_moduleid = iobrick_module_get_nasid(nasid); + + if (pcibr_soft->bs_bricktype > 0) { + switch (pcibr_soft->bs_bricktype) { + case MODULE_PXBRICK: + case MODULE_IXBRICK: + pcibr_soft->bs_first_slot = 0; + pcibr_soft->bs_last_slot = 1; + pcibr_soft->bs_last_reset = 1; + + /* If Bus 1 has IO9 then there are 4 devices in that bus. Note + * we figure this out from klconfig since the kernel has yet to + * probe + */ + if (pcibr_widget_to_bus(pcibr_vhdl) == 1) { + lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); + + while (brd) { + if (brd->brd_flags & LOCAL_MASTER_IO6) { + pcibr_soft->bs_last_slot = 3; + pcibr_soft->bs_last_reset = 3; + } + brd = KLCF_NEXT(brd); + } + } + break; + case MODULE_PBRICK: + pcibr_soft->bs_first_slot = 1; + pcibr_soft->bs_last_slot = 2; + pcibr_soft->bs_last_reset = 2; + break; + + case MODULE_IBRICK: + /* + * Here's the current baseio layout for SN1 style systems: + * + * 0 1 2 3 4 5 6 7 slot# + * + * x scsi x x ioc3 usb x x O300 Ibrick + * + * x == never occupied + * E == external (add-in) slot + * + */ + pcibr_soft->bs_first_slot = 1; /* Ibrick first slot == 1 */ + if (pcibr_soft->bs_xid == 0xe) { + pcibr_soft->bs_last_slot = 2; + pcibr_soft->bs_last_reset = 2; + } else { + pcibr_soft->bs_last_slot = 6; + } + break; + default: + break; + } + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pcibr_attach2: %cbrick, slots %d-%d\n", + MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid), + pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot)); + } + + /* + * Initialize bridge and bus locks + */ + spin_lock_init(&pcibr_soft->bs_lock); +#ifdef PIC_LATER + mrinit(pcibr_soft->bs_bus_lock, "bus_lock"); +#endif /* * If we have one, process the hints structure. */ if (pcibr_hints) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, pcibr_vhdl, + "pcibr_attach2: pcibr_hints=0x%x\n", pcibr_hints)); + rrb_fixed = pcibr_hints->ph_rrb_fixed; pcibr_soft->bs_rrb_fixed = rrb_fixed; - if (pcibr_hints->ph_intr_bits) + if (pcibr_hints->ph_intr_bits) { pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; + } - for (slot = 0; slot < 8; ++slot) { - int hslot = pcibr_hints->ph_host_slot[slot] - 1; + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + int hslot = pcibr_hints->ph_host_slot[slot] - 1; if (hslot < 0) { pcibr_soft->bs_slot[slot].host_slot = slot; @@ -1507,13 +1494,16 @@ } } /* - * set up initial values for state fields + * Set-up initial values for state fields */ - for (slot = 0; slot < 8; ++slot) { + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; + pcibr_soft->bs_slot[slot].bss_devio.bssd_ref_cnt = 0; pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); + pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] = -1; } for (ibit = 0; ibit < 8; ++ibit) { @@ -1522,15 +1512,31 @@ pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = &(bridge->b_int_status); + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_ibit = ibit; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; } /* + * connect up our error handler. PIC has 2 busses (thus resulting in 2 + * pcibr_soft structs under 1 widget), so only register a xwidget error + * handler for PIC's bus0. NOTE: for PIC pcibr_error_handler_wrapper() + * is a wrapper routine we register that will call the real error handler + * pcibr_error_handler() with the correct pcibr_soft struct. + */ + if (IS_PIC_SOFT(pcibr_soft)) { + if (busnum == 0) { + xwidget_error_register(xconn_vhdl, pcibr_error_handler_wrapper, pcibr_soft); + } + } else { + xwidget_error_register(xconn_vhdl, pcibr_error_handler, pcibr_soft); + } + + /* * Initialize various Bridge registers. */ - + /* * On pre-Rev.D bridges, set the PCI_RETRY_CNT * to zero to avoid dropping stores. (#475347) @@ -1543,12 +1549,43 @@ */ bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); + /* Initialize some PIC specific registers. */ + if (IS_PIC_SOFT(pcibr_soft)) { + picreg_t pic_ctrl_reg = bridge->p_wid_control_64; + + /* Bridges Requester ID: bus = busnum, dev = 0, func = 0 */ + pic_ctrl_reg &= ~PIC_CTRL_BUS_NUM_MASK; + pic_ctrl_reg |= PIC_CTRL_BUS_NUM(busnum); + pic_ctrl_reg &= ~PIC_CTRL_DEV_NUM_MASK; + pic_ctrl_reg &= ~PIC_CTRL_FUN_NUM_MASK; + + pic_ctrl_reg &= ~PIC_CTRL_NO_SNOOP; + pic_ctrl_reg &= ~PIC_CTRL_RELAX_ORDER; + + /* enable parity checking on PICs internal RAM */ + pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP; + pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE; + /* PIC BRINGUP WAR (PV# 862253): dont enable write request + * parity checking. + */ + if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) { + pic_ctrl_reg |= PIC_CTRL_PAR_EN_REQ; + } + + bridge->p_wid_control_64 = pic_ctrl_reg; + } + /* * Until otherwise set up, * assume all interrupts are - * from slot 7. + * from slot 7(Bridge/Xbridge) or 3(PIC). + * XXX. Not sure why we're doing this, made change for PIC + * just to avoid setting reserved bits. */ - bridge->b_int_device = (uint32_t) 0xffffffff; + if (IS_PIC_SOFT(pcibr_soft)) + bridge->b_int_device = (uint32_t) 0x006db6db; + else + bridge->b_int_device = (uint32_t) 0xffffffff; { bridgereg_t dirmap; @@ -1560,6 +1597,11 @@ int entry; cnodeid_t cnodeid; nasid_t nasid; +#ifdef PIC_LATER + char *node_val; + devfs_handle_t node_vhdl; + char vname[MAXDEVNAME]; +#endif /* Set the Bridge's 32-bit PCI to XTalk * Direct Map register to the most useful @@ -1578,6 +1620,30 @@ */ cnodeid = 0; /* default node id */ + /* + * Determine the base address node id to be used for all 32-bit + * Direct Mapping I/O. The default is node 0, but this can be changed + * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE + * attribute in the irix.sm config file. A device driver can obtain + * this node value via a call to pcibr_get_dmatrans_node(). + */ +#ifdef PIC_LATER +// This probably needs to be addressed - pfg + node_val = device_admin_info_get(pcibr_vhdl, ADMIN_LBL_DMATRANS_NODE); + if (node_val != NULL) { + node_vhdl = hwgraph_path_to_vertex(node_val); + if (node_vhdl != GRAPH_VERTEX_NONE) { + cnodeid = nodevertex_to_cnodeid(node_vhdl); + } + if ((node_vhdl == GRAPH_VERTEX_NONE) || (cnodeid == CNODEID_NONE)) { + cnodeid = 0; + vertex_to_name(pcibr_vhdl, vname, sizeof(vname)); + printk(KERN_WARNING "Invalid hwgraph node path specified:\n" + " DEVICE_ADMIN: %s %s=%s\n", + vname, ADMIN_LBL_DMATRANS_NODE, node_val); + } + } +#endif /* PIC_LATER */ nasid = COMPACT_TO_NASID_NODEID(cnodeid); paddr = NODE_OFFSET(nasid) + 0; @@ -1619,9 +1685,17 @@ */ spl_level = splhi(); #if IOPGSIZE == 4096 - bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; + if (IS_PIC_SOFT(pcibr_soft)) { + bridge->p_wid_control_64 &= ~BRIDGE_CTRL_PAGE_SIZE; + } else { + bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; + } #elif IOPGSIZE == 16384 - bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; + if (IS_PIC_SOFT(pcibr_soft)) { + bridge->p_wid_control_64 |= BRIDGE_CTRL_PAGE_SIZE; + } else { + bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; + } #else <<>>; #endif @@ -1652,7 +1726,8 @@ * recomparing against BRIDGE_INTERNAL_ATES every * time. */ - if (is_xbridge(bridge)) + + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) num_entries = 0; else num_entries = pcibr_init_ext_ate_ram(bridge); @@ -1662,9 +1737,6 @@ */ pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size); -#endif if (num_entries > pcibr_soft->bs_int_ate_size) { #if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ @@ -1674,11 +1746,12 @@ pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, num_entries - pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d EXTERNAL ATEs\n", - num_entries - pcibr_soft->bs_int_ate_size); -#endif } + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_vhdl, + "pcibr_attach2: %d ATEs, %d internal & %d external\n", + num_entries ? num_entries : pcibr_soft->bs_int_ate_size, + pcibr_soft->bs_int_ate_size, + num_entries ? num_entries-pcibr_soft->bs_int_ate_size : 0)); } { @@ -1727,7 +1800,7 @@ * knows to do this. */ - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl); + xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl); ASSERT(xtalk_intr != NULL); pcibr_soft->bsi_err_intr = xtalk_intr; @@ -1740,17 +1813,128 @@ */ pcibr_clearwidint(bridge); - xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); + xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler, + (intr_arg_t) pcibr_soft, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); + + request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, + ((hub_intr_t)xtalk_intr)->i_bit), + (intr_func_t)pcibr_error_intr_handler, 0, "PCIBR error", + (intr_arg_t) pcibr_soft); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl, + "pcibr_setwidint: b_wid_int_upper=0x%x, b_wid_int_lower=0x%x\n", + bridge->b_wid_int_upper, bridge->b_wid_int_lower)); /* * now we can start handling error interrupts; * enable all of them. * NOTE: some PCI ints may already be enabled. */ - b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS; + /* We read the INT_ENABLE register as a 64bit picreg_t for PIC and a + * 32bit bridgereg_t for BRIDGE, but always process the result as a + * 64bit value so the code can be "common" for both PIC and BRIDGE... + */ + if (IS_PIC_SOFT(pcibr_soft)) { + int_enable_64 = bridge->p_int_enable_64 | BRIDGE_ISR_ERRORS; + int_enable = (uint64_t)int_enable_64; +#ifdef PFG_TEST + int_enable = (uint64_t)0x7ffffeff7ffffeff; +#endif + } else { + int_enable_32 = bridge->b_int_enable | (BRIDGE_ISR_ERRORS & 0xffffffff); + int_enable = ((uint64_t)int_enable_32 & 0xffffffff); +#ifdef PFG_TEST + int_enable = (uint64_t)0x7ffffeff; +#endif + } +#ifdef BUS_INT_WAR_NOT_YET + { + extern void sn_add_polled_interrupt(int irq, int interval); + + sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, + ((hub_intr_t)xtalk_intr)->i_bit), 20000); + } +#endif - bridge->b_int_enable = b_int_enable; +#if BRIDGE_ERROR_INTR_WAR + if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { + /* + * We commonly get master timeouts when talking to ql. + * We also see RESP_XTALK_ERROR and LLP_TX_RETRY interrupts. + * Insure that these are all disabled for now. + */ + int_enable &= ~(BRIDGE_IMR_PCI_MST_TIMEOUT | + BRIDGE_ISR_RESP_XTLK_ERR | + BRIDGE_ISR_LLP_TX_RETRY); + } + if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) { + int_enable &= ~BRIDGE_ISR_BAD_XRESP_PKT; + } +#endif /* BRIDGE_ERROR_INTR_WAR */ + +#ifdef QL_SCSI_CTRL_WAR /* for IP30 only */ + /* Really a QL rev A issue, but all newer hearts have newer QLs. + * Forces all IO6/MSCSI to be new. + */ + if (heart_rev() == HEART_REV_A) + int_enable &= ~BRIDGE_IMR_PCI_MST_TIMEOUT; +#endif + +#ifdef BRIDGE1_TIMEOUT_WAR + if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { + /* + * Turn off these interrupts. They can't be trusted in bridge 1 + */ + int_enable &= ~(BRIDGE_IMR_XREAD_REQ_TIMEOUT | + BRIDGE_IMR_UNEXP_RESP); + } +#endif + +#ifdef BRIDGE_B_DATACORR_WAR + + /* WAR panic for Rev B silent data corruption. + * PIOERR turned off here because there is a problem + * with not re-arming it in pcibr_error_intr_handler. + * We don't get LLP error interrupts if we don't + * re-arm PIOERR interrupts! Just disable them here + */ + + if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) { + int_enable |= BRIDGE_IMR_LLP_REC_CBERR; + int_enable &= ~BRIDGE_ISR_PCIBUS_PIOERR; + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "Turning on LLP_REC_CBERR for Rev B Bridge.\n")); + } +#endif + + /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are + * locked out to be freed up sooner (by timing out) so that the + * read tnums are never completely used up. + */ + if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856864, pcibr_soft)) { + int_enable &= ~PIC_ISR_PCIX_REQ_TOUT; + int_enable &= ~BRIDGE_ISR_XREAD_REQ_TIMEOUT; + + bridge->b_wid_req_timeout = 0x750; + } + + /* + * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): Don't use + * RRB0, RRB8, RRB1, and RRB9. Assign them to DEVICE[2|3]--VCHAN3 + * so they are not used + */ + if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856866, pcibr_soft)) { + bridge->b_even_resp |= 0x000f000f; + bridge->b_odd_resp |= 0x000f000f; + } + + if (IS_PIC_SOFT(pcibr_soft)) { + bridge->p_int_enable_64 = (picreg_t)int_enable; + } else { + bridge->b_int_enable = (bridgereg_t)int_enable; + } bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ bridge->b_wid_tflush; /* wait until Bridge PIO complete */ @@ -1788,20 +1972,59 @@ (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; - pciio_provider_register(pcibr_vhdl, &pcibr_provider); - pciio_provider_startup(pcibr_vhdl); - - pci_io_fb = 0x00000004; /* I/O FreeBlock Base */ - pci_io_fl = 0xFFFFFFFF; /* I/O FreeBlock Last */ - - pci_lo_fb = 0x00000010; /* Low Memory FreeBlock Base */ - pci_lo_fl = 0x001FFFFF; /* Low Memory FreeBlock Last */ + /* PIC only supports 64-bit direct mapping in PCI-X mode. Since + * all PCI-X devices that initiate memory transactions must be + * capable of generating 64-bit addressed, we force 64-bit DMAs. + */ + if (IS_PCIX(pcibr_soft)) { + pcibr_soft->bs_dma_flags |= PCIIO_DMA_A64; + } - pci_hi_fb = 0x00200000; /* High Memory FreeBlock Base */ - pci_hi_fl = 0x3FFFFFFF; /* High Memory FreeBlock Last */ + { + pciio_win_map_t win_map_p; + iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; + int prom_base_size = 0x1000000; + iopaddr_t prom_base_limit = prom_base_addr + prom_base_size; + + /* Allocate resource maps based on bus page size; for I/O and memory + * space, free all pages except those in the base area and in the + * range set by the PROM. + * + * PROM creates BAR addresses in this format: 0x0ws00000 where w is + * the widget number and s is the device register offset for the slot. + */ - PCI_ADDR_SPACE_LIMITS_STORE(); + win_map_p = &pcibr_soft->bs_io_win_map; + pciio_device_win_map_new(win_map_p, + PCIBR_BUS_IO_MAX + 1, + PCIBR_BUS_IO_PAGE); + pciio_device_win_populate(win_map_p, + PCIBR_BUS_IO_BASE, + prom_base_addr - PCIBR_BUS_IO_BASE); + pciio_device_win_populate(win_map_p, + prom_base_limit, + (PCIBR_BUS_IO_MAX + 1) - prom_base_limit); + + win_map_p = &pcibr_soft->bs_swin_map; + pciio_device_win_map_new(win_map_p, + PCIBR_BUS_SWIN_MAX + 1, + PCIBR_BUS_SWIN_PAGE); + pciio_device_win_populate(win_map_p, + PCIBR_BUS_SWIN_BASE, + (PCIBR_BUS_SWIN_MAX + 1) - PCIBR_BUS_SWIN_PAGE); + + win_map_p = &pcibr_soft->bs_mem_win_map; + pciio_device_win_map_new(win_map_p, + PCIBR_BUS_MEM_MAX + 1, + PCIBR_BUS_MEM_PAGE); + pciio_device_win_populate(win_map_p, + PCIBR_BUS_MEM_BASE, + prom_base_addr - PCIBR_BUS_MEM_BASE); + pciio_device_win_populate(win_map_p, + prom_base_limit, + (PCIBR_BUS_MEM_MAX + 1) - prom_base_limit); + } /* build "no-slot" connection point */ @@ -1830,59 +2053,90 @@ } #endif -#ifdef LATER - /* If the bridge has been reset then there is no need to reset - * the individual PCI slots. - */ - for (slot = 0; slot < 8; ++slot) - /* Reset all the slots */ - (void)pcibr_slot_reset(pcibr_vhdl, slot); -#endif - - for (slot = 0; slot < 8; ++slot) + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { /* Find out what is out there */ (void)pcibr_slot_info_init(pcibr_vhdl,slot); + } + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) + /* Set up the address space for this slot in the PCI land */ + (void)pcibr_slot_addr_space_init(pcibr_vhdl, slot); - for (slot = 0; slot < 8; ++slot) - /* Set up the address space for this slot in the pci land */ - (void)pcibr_slot_addr_space_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) /* Setup the device register */ - (void)pcibr_slot_device_init(pcibr_vhdl, slot); - - for (slot = 0; slot < 8; ++slot) - /* Setup host/guest relations */ - (void)pcibr_slot_guest_info_init(pcibr_vhdl,slot); + (void)pcibr_slot_device_init(pcibr_vhdl, slot); - for (slot = 0; slot < 8; ++slot) - /* Initial RRB management */ - (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); + if (IS_PCIX(pcibr_soft)) { + pcibr_soft->bs_pcix_rbar_inuse = 0; + pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; + pcibr_soft->bs_pcix_rbar_percent_allowed = + pcibr_pcix_rbars_calc(pcibr_soft); + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) + /* Setup the PCI-X Read Buffer Attribute Registers (RBARs) */ + (void)pcibr_slot_pcix_rbar_init(pcibr_soft, slot); + } + + /* Set up convenience links */ + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) + pcibr_bus_cnvlink(pcibr_soft->bs_vhdl); - /* driver attach routines should be called out from generic linux code */ - for (slot = 0; slot < 8; ++slot) - /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) + /* Setup host/guest relations */ + (void)pcibr_slot_guest_info_init(pcibr_vhdl, slot); + /* Handle initial RRB management for Bridge and Xbridge */ + pcibr_initial_rrb(pcibr_vhdl, + pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot); + +{ /* Before any drivers get called that may want to re-allocate + * RRB's, let's get some special cases pre-allocated. Drivers + * may override these pre-allocations, but by doing pre-allocations + * now we're assured not to step all over what the driver intended. + * + * Note: Someday this should probably be moved over to pcibr_rrb.c + */ /* * Each Pbrick PCI bus only has slots 1 and 2. Similarly for * widget 0xe on Ibricks. Allocate RRB's accordingly. */ - if (pcibr_soft->bs_moduleid > 0) { - switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { - case 'p': /* Pbrick */ - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + if (pcibr_soft->bs_bricktype > 0) { + switch (pcibr_soft->bs_bricktype) { + case MODULE_PBRICK: + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); break; - case 'i': /* Ibrick */ + case MODULE_IBRICK: /* port 0xe on the Ibrick only has slots 1 and 2 */ if (pcibr_soft->bs_xid == 0xe) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); } else { /* allocate one RRB for the serial port */ - do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); + do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1); + } + break; + case MODULE_PXBRICK: + case MODULE_IXBRICK: + /* + * If the IO9 is in the PXBrick (bus1, slot1) allocate + * RRBs to all the devices + */ + if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) && + (pcibr_soft->bs_slot[0].bss_vendor_id == 0x10A9) && + (pcibr_soft->bs_slot[0].bss_device_id == 0x100A)) { + do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 4); + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 4); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 4); + do_pcibr_rrb_autoalloc(pcibr_soft, 3, VCHAN0, 4); + } else { + do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); } break; } /* switch */ @@ -1890,33 +2144,80 @@ #ifdef LATER if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); -#if PCIBR_RRB_DEBUG - printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl); - - printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n", - pcibr_vhdl, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - - for (slot = 0; slot < 8; ++slot) - printf("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - - printf("\n"); + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); + } #endif +} /* OK Special RRB allocations are done. */ + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) + /* Call the device attach */ + (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); + +#ifdef PIC_LATER +#if (defined(USS302_TIMEOUT_WAR)) + /* + * If this bridge holds a Lucent USS-302 or USS-312 pci/usb controller, + * increase the Bridge PCI retry backoff interval. This part seems + * to go away for long periods of time if a DAC appears on the bus during + * a read command that is being retried. + */ + +{ + ii_ixtt_u_t ixtt; + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + if (pcibr_soft->bs_slot[slot].bss_vendor_id == + LUCENT_USBHC_VENDOR_ID_NUM && + (pcibr_soft->bs_slot[slot].bss_device_id == + LUCENT_USBHC302_DEVICE_ID_NUM || + pcibr_soft->bs_slot[slot].bss_device_id == + LUCENT_USBHC312_DEVICE_ID_NUM)) { + printk(KERN_NOTICE + "pcibr_attach: %x Bus holds a usb part - setting" + "bridge PCI_RETRY_HLD to %d\n", + pcibr_vhdl, USS302_BRIDGE_TIMEOUT_HLD); + + bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_HLD_MASK; + bridge->b_bus_timeout |= + BRIDGE_BUS_PCI_RETRY_HLD(USS302_BRIDGE_TIMEOUT_HLD); + + /* + * Have to consider the read response timer in the hub II as well + */ + + hubii_ixtt_get(xconn_vhdl, &ixtt); + + /* + * bump rrsp_ps to allow at least 1ms for read + * responses from this widget + */ + + ixtt.ii_ixtt_fld_s.i_rrsp_ps = 20000; + hubii_ixtt_set(xconn_vhdl, &ixtt); + + /* + * print the current setting + */ + + hubii_ixtt_get(xconn_vhdl, &ixtt); + printk( "Setting hub ixtt.rrsp_ps field to 0x%x\n", + ixtt.ii_ixtt_fld_s.i_rrsp_ps); + + break; /* only need to do it once */ + } } +} +#endif /* (defined(USS302_TIMEOUT_WAR)) */ #else FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); -#endif +#endif /* PIC_LATER */ if (aa) async_attach_add_info(noslot_conn, aa); - pciio_device_attach(noslot_conn, 0); - + pciio_device_attach(noslot_conn, (int)0); /* * Tear down pointer to async attach info -- async threads for @@ -1927,11 +2228,13 @@ return 0; } + /* * pcibr_detach: * Detach the bridge device from the hwgraph after cleaning out all the * underlying vertices. */ + int pcibr_detach(devfs_handle_t xconn) { @@ -1939,6 +2242,9 @@ devfs_handle_t pcibr_vhdl; pcibr_soft_t pcibr_soft; bridge_t *bridge; + unsigned s; + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, xconn, "pcibr_detach\n")); /* Get the bridge vertex from its xtalk connection point */ if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) @@ -1947,16 +2253,20 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge = pcibr_soft->bs_base; + + s = pcibr_lock(pcibr_soft); /* Disable the interrupts from the bridge */ - bridge->b_int_enable = 0; + if (IS_PIC_SOFT(pcibr_soft)) { + bridge->p_int_enable_64 = 0; + } else { + bridge->b_int_enable = 0; + } + pcibr_unlock(pcibr_soft, s); /* Detach all the PCI devices talking to this bridge */ - for(slot = 0; slot < 8; slot++) { -#ifdef DEBUG - printk("pcibr_device_detach called for %p/%d\n", - pcibr_vhdl,slot); -#endif - pcibr_slot_detach(pcibr_vhdl, slot, 0); + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + pcibr_slot_detach(pcibr_vhdl, slot, 0, (char *)NULL, (int *)NULL); } /* Unregister the no-slot connection point */ @@ -1998,17 +2308,29 @@ int pcibr_asic_rev(devfs_handle_t pconn_vhdl) { - devfs_handle_t pcibr_vhdl; + devfs_handle_t pcibr_vhdl; + int tmp_vhdl; arbitrary_info_t ainfo; if (GRAPH_SUCCESS != hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) return -1; - if (GRAPH_SUCCESS != - hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo)) - return -1; + tmp_vhdl = hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo); + /* + * Any hwgraph function that returns a vertex handle will implicity + * increment that vertex's reference count. The caller must explicity + * decrement the vertex's referece count after the last reference to + * that vertex. + * + * Decrement reference count incremented by call to hwgraph_traverse(). + * + */ + hwgraph_vertex_unref(pcibr_vhdl); + + if (tmp_vhdl != GRAPH_SUCCESS) + return -1; return (int) ainfo; } @@ -2018,7 +2340,7 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); pciio_slot_t slot; - slot = pciio_info_slot_get(pciio_info); + slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_device_write_gather_flush(pcibr_soft, slot); return 0; } @@ -2042,17 +2364,21 @@ unsigned bar; /* which BASE reg on device is decoding */ iopaddr_t xio_addr = XIO_NOWHERE; + iopaddr_t base; /* base of devio(x) mapped area on PCI */ + iopaddr_t limit; /* base of devio(x) mapped area on PCI */ pciio_space_t wspace; /* which space device is decoding */ iopaddr_t wbase; /* base of device decode on PCI */ size_t wsize; /* size of device decode on PCI */ int try; /* DevIO(x) window scanning order control */ + int maxtry, halftry; int win; /* which DevIO(x) window is being used */ pciio_space_t mspace; /* target space for devio(x) register */ iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ size_t msize; /* size of devio(x) mapped area on PCI */ size_t mmask; /* addr bits stored in Device(x) */ + char tmp_str[512]; unsigned long s; @@ -2061,6 +2387,17 @@ if (pcibr_soft->bs_slot[slot].has_host) { slot = pcibr_soft->bs_slot[slot].host_slot; pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; + + /* + * Special case for dual-slot pci devices such as ioc3 on IP27 + * baseio. In these cases, pconn_vhdl should never be for a pci + * function on a subordiate PCI bus, so we can safely reset pciio_info + * to be the info struct embedded in pcibr_info. Failure to do this + * results in using a bogus pciio_info_t for calculations done later + * in this routine. + */ + + pciio_info = &pcibr_info->f_c; } if (space == PCIIO_SPACE_NONE) goto done; @@ -2080,7 +2417,7 @@ */ if (((flags & PCIIO_BYTE_STREAM) == 0) && ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) - xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot); + xio_addr = pci_addr + PCIBR_TYPE0_CFG_DEV(pcibr_soft, slot); goto done; } @@ -2090,8 +2427,8 @@ * enabling and disabling * decodes properly. */ - wbase = pcibr_info->f_rbase; - wsize = pcibr_info->f_rsize; + wbase = pciio_info->c_rbase; + wsize = pciio_info->c_rsize; /* * While the driver should know better @@ -2113,13 +2450,13 @@ */ bar = space - PCIIO_SPACE_WIN0; if (bar < 6) { - wspace = pcibr_info->f_window[bar].w_space; + wspace = pciio_info->c_window[bar].w_space; if (wspace == PCIIO_SPACE_NONE) goto done; /* get PCI base and size */ - wbase = pcibr_info->f_window[bar].w_base; - wsize = pcibr_info->f_window[bar].w_size; + wbase = pciio_info->c_window[bar].w_base; + wsize = pciio_info->c_window[bar].w_size; /* * While the driver should know better @@ -2147,11 +2484,15 @@ * We will not attempt to satisfy a single request * by concatinating multiple windows. */ - for (try = 0; try < 16; ++try) { + maxtry = PCIBR_NUM_SLOTS(pcibr_soft) * 2; + halftry = PCIBR_NUM_SLOTS(pcibr_soft) - 1; + for (try = 0; try < maxtry; ++try) { bridgereg_t devreg; unsigned offset; - win = (try + slot) % 8; + /* calculate win based on slot, attempt, and max possible + devices on bus */ + win = (try + slot) % PCIBR_NUM_SLOTS(pcibr_soft); /* If this DevIO(x) mapping area can provide * a mapping to this address, use it. @@ -2176,7 +2517,7 @@ * (only check this the second time through) */ mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; - if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) { + if ((try > halftry) && (mspace == PCIIO_SPACE_NONE)) { /* If this is the primary DevIO(x) window * for some other device, skip it. @@ -2214,25 +2555,59 @@ devreg &= ~BRIDGE_DEV_DEV_SWAP; if (pcibr_soft->bs_slot[win].bss_device != devreg) { - bridge->b_device[win].reg = devreg; - pcibr_soft->bs_slot[win].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_device[win].reg = devreg; + pcibr_soft->bs_slot[win].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_device[win].reg)) = __swab32(devreg); + pcibr_soft->bs_slot[win].bss_device = devreg; + BRIDGE_REG_GET32((&bridge->b_wid_tflush)); /* wait until Bridge PIO complete */ + } else { + bridge->b_device[win].reg = devreg; + pcibr_soft->bs_slot[win].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + } -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg); +#ifdef PCI_LATER + PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, + "pcibr_addr_pci_to_xio: Device(%d): %x\n", + win, devreg, device_bits)); #endif } pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); + xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase); -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", - __FUNCTION__, __LINE__, space, space_desc, - pci_addr, pci_addr + req_size - 1, - slot, win, devreg); -#endif + /* Increment this DevIO's use count */ + pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++; + /* Save the DevIO register index used to access this BAR */ + if (bar != -1) + pcibr_info->f_window[bar].w_devio_index = win; + + /* + * The kernel only allows functions to have so many variable args, + * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printk + * arguments fails so sprintf() it into a temporary string. + */ + if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) { +#ifdef PIC_LATER + sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to %x[%x..%x] for " + "slot %d allocates DevIO(%d) Device(%d) set to %x\n", + space, space_desc, pci_addr, pci_addr + req_size - 1, + slot, win, win, devreg, device_bits); +#else + sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to [%lx..%lx] for " + "slot %d allocates DevIO(%d) Device(%d) set to %lx\n", + (unsigned long)pci_addr, (unsigned long)(pci_addr + req_size - 1), + (unsigned int)slot, win, win, (unsigned long)devreg); +#endif + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str)); + } goto done; } /* endif DevIO(x) not pointed */ mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; @@ -2251,12 +2626,23 @@ * final XIO address, release the lock and * return. */ - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); + xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase); -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n", - __FUNCTION__, __LINE__, space, pci_addr, pci_addr + req_size - 1, slot, win); + /* Increment this DevIO's use count */ + pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++; + + /* Save the DevIO register index used to access this BAR */ + if (bar != -1) + pcibr_info->f_window[bar].w_devio_index = win; + + if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) { +#ifdef PIC_LATER + sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to %x[%x..%x] for " + "slot %d uses DevIO(%d)\n", space, space_desc, pci_addr, + pci_addr + req_size - 1, slot, win); #endif + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str)); + } goto done; } @@ -2275,18 +2661,46 @@ */ case PCIIO_SPACE_MEM: /* "mem space" */ case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= - BRIDGE_PCI_MEM32_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; + if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ + base = PICBRIDGE0_PCI_MEM32_BASE; + limit = PICBRIDGE0_PCI_MEM32_LIMIT; + } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ + base = PICBRIDGE1_PCI_MEM32_BASE; + limit = PICBRIDGE1_PCI_MEM32_LIMIT; + } else { /* Bridge/Xbridge */ + base = BRIDGE_PCI_MEM32_BASE; + limit = BRIDGE_PCI_MEM32_LIMIT; + } + + if ((pci_addr + base + req_size - 1) <= limit) + xio_addr = pci_addr + base; break; case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= - BRIDGE_PCI_MEM64_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; + if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ + base = PICBRIDGE0_PCI_MEM64_BASE; + limit = PICBRIDGE0_PCI_MEM64_LIMIT; + } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ + base = PICBRIDGE1_PCI_MEM64_BASE; + limit = PICBRIDGE1_PCI_MEM64_LIMIT; + } else { /* Bridge/Xbridge */ + base = BRIDGE_PCI_MEM64_BASE; + limit = BRIDGE_PCI_MEM64_LIMIT; + } + + if ((pci_addr + base + req_size - 1) <= limit) + xio_addr = pci_addr + base; break; case PCIIO_SPACE_IO: /* "i/o space" */ + /* + * PIC bridges do not support big-window aliases into PCI I/O space + */ + if (IS_PIC_SOFT(pcibr_soft)) { + xio_addr = XIO_NOWHERE; + break; + } + /* Bridge Hardware Bug WAR #482741: * The 4G area that maps directly from * XIO space to PCI I/O space is busted @@ -2322,33 +2736,55 @@ if (bfn == bfo) { /* we already match. */ ; } else if (bfo != 0) { /* we have a conflict. */ -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n", - space, - bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); + if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) { +#ifdef PIC_LATER + sprintf(tmp_str, "pcibr_addr_pci_to_xio: swap conflict in %x, " + "was%s%s, want%s%s\n", space, space_desc, + bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", + bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); #endif + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str)); + } xio_addr = XIO_NOWHERE; } else { /* OK to make the change. */ - bridgereg_t octl, nctl; - swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP; - octl = bridge->b_wid_control; - nctl = bst ? octl | swb : octl & ~swb; + if ( IS_PIC_SOFT(pcibr_soft) ) { + picreg_t octl, nctl; + octl = bridge->p_wid_control_64; + nctl = bst ? octl | (uint64_t)swb : octl & ((uint64_t)~swb); - if (octl != nctl) /* make the change if any */ - bridge->b_wid_control = nctl; + if (octl != nctl) /* make the change if any */ + bridge->b_wid_control = nctl; + } + else { + picreg_t octl, nctl; + if (io_get_sh_swapper(NASID_GET(bridge))) { + octl = BRIDGE_REG_GET32((&bridge->b_wid_control)); + nctl = bst ? octl | swb : octl & ~swb; + + if (octl != nctl) /* make the change if any */ + BRIDGE_REG_SET32((&bridge->b_wid_control)) = __swab32(nctl); + } else { + octl = bridge->b_wid_control; + nctl = bst ? octl | swb : octl & ~swb; + if (octl != nctl) /* make the change if any */ + bridge->b_wid_control = nctl; + } + } *bfp = bfn; /* record the assignment */ -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap for space %d set to%s%s\n", - space, - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); + if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) { +#ifdef PIC_LATER + sprintf(tmp_str, "pcibr_addr_pci_to_xio: swap for %x set " + "to%s%s\n", space, space_desc, + bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", + bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); #endif + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str)); + } } } done: @@ -2368,7 +2804,7 @@ { pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); pciio_info_t pciio_info = &pcibr_info->f_c; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; @@ -2380,8 +2816,11 @@ unsigned long s; /* Make sure that the req sizes are non-zero */ - if ((req_size < 1) || (req_size_max < 1)) + if ((req_size < 1) || (req_size_max < 1)) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, + "pcibr_piomap_alloc: req_size | req_size_max < 1\n")); return NULL; + } /* * Code to translate slot/space/addr @@ -2390,8 +2829,11 @@ */ xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - if (xio_addr == XIO_NOWHERE) + if (xio_addr == XIO_NOWHERE) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, + "pcibr_piomap_alloc: xio_addr == XIO_NOWHERE\n")); return NULL; + } /* Check the piomap list to see if there is already an allocated * piomap entry but not in use. If so use that one. Otherwise @@ -2415,7 +2857,7 @@ } pcibr_piomap->bp_dev = pconn_vhdl; - pcibr_piomap->bp_slot = pciio_slot; + pcibr_piomap->bp_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, pciio_slot); pcibr_piomap->bp_flags = flags; pcibr_piomap->bp_space = space; pcibr_piomap->bp_pciaddr = pci_addr; @@ -2446,6 +2888,10 @@ pcibr_piomap = 0; } } + + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, + "pcibr_piomap_alloc: map=0x%x\n", pcibr_piomap)); + return pcibr_piomap; } @@ -2453,6 +2899,9 @@ void pcibr_piomap_free(pcibr_piomap_t pcibr_piomap) { + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev, + "pcibr_piomap_free: map=0x%x\n", pcibr_piomap)); + xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio); pcibr_piomap->bp_xtalk_pio = 0; pcibr_piomap->bp_mapsz = 0; @@ -2464,16 +2913,24 @@ iopaddr_t pci_addr, size_t req_size) { - return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, + caddr_t addr; + addr = xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, pcibr_piomap->bp_xtalk_addr + pci_addr - pcibr_piomap->bp_pciaddr, req_size); + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev, + "pcibr_piomap_free: map=0x%x, addr=0x%x\n", + pcibr_piomap, addr)); + + return(addr); } /*ARGSUSED */ void pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) { + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev, + "pcibr_piomap_done: map=0x%x\n", pcibr_piomap)); xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio); } @@ -2487,26 +2944,34 @@ unsigned flags) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; iopaddr_t xio_addr; + caddr_t addr; xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - if (xio_addr == XIO_NOWHERE) + if (xio_addr == XIO_NOWHERE) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIODIR, pconn_vhdl, + "pcibr_piotrans_addr: xio_addr == XIO_NOWHERE\n")); return NULL; + } - return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); + addr = xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); + PCIBR_DEBUG((PCIBR_DEBUG_PIODIR, pconn_vhdl, + "pcibr_piotrans_addr: xio_addr=0x%x, addr=0x%x\n", + xio_addr, addr)); + return(addr); } /* * PIO Space allocation and management. * Allocate and Manage the PCI PIO space (mem and io space) * This routine is pretty simplistic at this time, and - * does pretty trivial management of allocation and freeing.. - * The current scheme is prone for fragmentation.. + * does pretty trivial management of allocation and freeing. + * The current scheme is prone for fragmentation. * Change the scheme to use bitmaps. */ @@ -2525,7 +2990,6 @@ pciio_piospace_t piosp; unsigned long s; - iopaddr_t *pciaddr, *pcilast; iopaddr_t start_addr; size_t align_mask; @@ -2559,38 +3023,43 @@ } ASSERT(!piosp); + /* + * Allocate PCI bus address, usually for the Universe chip driver; + * do not pass window info since the actual PCI bus address + * space will never be freed. The space may be reused after it + * is logically released by pcibr_piospace_free(). + */ switch (space) { case PCIIO_SPACE_IO: - pciaddr = &pcibr_soft->bs_spinfo.pci_io_base; - pcilast = &pcibr_soft->bs_spinfo.pci_io_last; + start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL, + PCIIO_SPACE_IO, + 0, req_size, alignment); break; + case PCIIO_SPACE_MEM: case PCIIO_SPACE_MEM32: - pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base; - pcilast = &pcibr_soft->bs_spinfo.pci_mem_last; + start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL, + PCIIO_SPACE_MEM32, + 0, req_size, alignment); break; + default: ASSERT(0); pcibr_unlock(pcibr_soft, s); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, + "pcibr_piospace_alloc: unknown space %d\n", space)); return 0; } - start_addr = *pciaddr; - /* - * Align start_addr. + * If too big a request, reject it. */ - if (start_addr & align_mask) - start_addr = (start_addr + align_mask) & ~align_mask; - - if ((start_addr + req_size) > *pcilast) { - /* - * If too big a request, reject it. - */ + if (!start_addr) { pcibr_unlock(pcibr_soft, s); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, + "pcibr_piospace_alloc: request 0x%x to big\n", req_size)); return 0; } - *pciaddr = (start_addr + req_size); NEW(piosp); piosp->free = 0; @@ -2601,6 +3070,10 @@ pcibr_info->f_piospace = piosp; pcibr_unlock(pcibr_soft, s); + + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, + "pcibr_piospace_alloc: piosp=0x%x\n", piosp)); + return start_addr; } @@ -2612,7 +3085,9 @@ size_t req_size) { pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); +#ifdef PIC_LATER pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; +#endif pciio_piospace_t piosp; unsigned long s; @@ -2655,6 +3130,9 @@ } piosp->free = 1; pcibr_unlock(pcibr_soft, s); + + PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, + "pcibr_piospace_free: piosp=0x%x\n", piosp)); return; } @@ -2713,7 +3191,7 @@ attributes &= ~PCI64_ATTR_PREF; /* the swap bit is in the address attributes for xbridge */ - if (pcibr_soft->bs_xbridge) { + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { if (flags & PCIIO_BYTE_STREAM) attributes |= PCI64_ATTR_SWAP; if (flags & PCIIO_WORD_VALUES) @@ -2742,6 +3220,11 @@ if (flags & PCIBR_VCHAN0) attributes &= ~PCI64_ATTR_VIRTUAL; + /* PIC in PCI-X mode only supports barrier & swap */ + if (IS_PCIX(pcibr_soft)) { + attributes &= (PCI64_ATTR_BAR | PCI64_ATTR_SWAP); + } + return (attributes); } @@ -2762,6 +3245,7 @@ pcibr_dmamap_t pcibr_dmamap; int ate_count; int ate_index; + int vchan = VCHAN0; /* merge in forced flags */ flags |= pcibr_soft->bs_dma_flags; @@ -2778,17 +3262,16 @@ xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max, flags & DMAMAP_FLAGS); if (!xtalk_dmamap) { -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: xtalk_dmamap_alloc failed\n"); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl, + "pcibr_dmamap_alloc: xtalk_dmamap_alloc failed\n")); free_pciio_dmamap(pcibr_dmamap); return 0; } xio_port = pcibr_soft->bs_mxid; - slot = pciio_info_slot_get(pciio_info); + slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_dmamap->bd_dev = pconn_vhdl; - pcibr_dmamap->bd_slot = slot; + pcibr_dmamap->bd_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot); pcibr_dmamap->bd_soft = pcibr_soft; pcibr_dmamap->bd_xtalk = xtalk_dmamap; pcibr_dmamap->bd_max_size = req_size_max; @@ -2812,29 +3295,37 @@ pcibr_dmamap->bd_xio_addr = 0; pcibr_dmamap->bd_pci_addr = pci_addr; - /* Make sure we have an RRB (or two). + /* If in PCI mode, make sure we have an RRB (or two). */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { + if (IS_PCI(pcibr_soft) && + !(pcibr_soft->bs_rrb_fixed & (1 << slot))) { if (flags & PCIBR_VCHAN1) - slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; + vchan = VCHAN1; + have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan]; if (have_rrbs < 2) { if (pci_addr & PCI64_ATTR_PREF) min_rrbs = 2; else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); + do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan, + min_rrbs - have_rrbs); } } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct64\n"); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmamap_alloc: using direct64, map=0x%x\n", + pcibr_dmamap)); return pcibr_dmamap; } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct64\n"); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmamap_alloc: unable to use direct64\n")); + + /* PIC only supports 64-bit direct mapping in PCI-X mode. */ + if (IS_PCIX(pcibr_soft)) { + DEL(pcibr_dmamap); + return 0; + } + flags &= ~PCIIO_DMA_A64; } if (flags & PCIIO_FIXED) { @@ -2849,17 +3340,17 @@ * Mapping calls may fail if target * is outside the direct32 range. */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct32\n"); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmamap_alloc: using direct32, map=0x%x\n", + pcibr_dmamap)); pcibr_dmamap->bd_flags = flags; pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase; pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE; return pcibr_dmamap; } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct32\n"); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmamap_alloc: unable to use direct32\n")); + /* If the user demands FIXED and we can't * give it to him, fail. */ @@ -2892,9 +3383,9 @@ int have_rrbs; int min_rrbs; -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using PMU\n"); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pconn_vhdl, + "pcibr_dmamap_alloc: using PMU, ate_index=%d, " + "pcibr_dmamap=0x%x\n", ate_index, pcibr_dmamap)); ate_proto = pcibr_flags_to_ate(flags); @@ -2904,7 +3395,7 @@ /* * for xbridge the byte-swap bit == bit 29 of PCI address */ - if (pcibr_soft->bs_xbridge) { + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { if (flags & PCIIO_BYTE_STREAM) ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); /* @@ -2926,18 +3417,19 @@ /* Make sure we have an RRB (or two). */ if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; + have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan]; if (have_rrbs < 2) { if (ate_proto & ATE_PREF) min_rrbs = 2; else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); + do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan, + min_rrbs - have_rrbs); } } if (ate_index >= pcibr_soft->bs_int_ate_size && - !pcibr_soft->bs_xbridge) { + !IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { bridge_t *bridge = pcibr_soft->bs_base; volatile unsigned *cmd_regp; unsigned cmd_reg; @@ -2946,27 +3438,35 @@ pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; s = pcibr_lock(pcibr_soft); - cmd_regp = &(bridge-> - b_type0_cfg_dev[slot]. - l[PCI_CFG_COMMAND / 4]); - cmd_reg = *cmd_regp; + cmd_regp = pcibr_slot_config_addr(bridge, slot, + PCI_CFG_COMMAND/4); + if ( IS_PIC_SOFT(pcibr_soft) ) { + cmd_reg = pcibr_slot_config_get(bridge, slot, PCI_CFG_COMMAND/4); + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&cmd_reg)) = __swab32(*cmd_regp); + } else { + cmd_reg = pcibr_slot_config_get(bridge, slot, PCI_CFG_COMMAND/4); + } + } pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp; pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg; pcibr_unlock(pcibr_soft, s); } return pcibr_dmamap; } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use PMU\n"); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl, + "pcibr_dmamap_alloc: PMU use failed, ate_index=%d\n", + ate_index)); + pcibr_ate_free(pcibr_soft, ate_index, ate_count); } /* total failure: sorry, you just can't * get from here to there that way. */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: complete failure.\n"); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl, + "pcibr_dmamap_alloc: complete failure.\n")); xtalk_dmamap_free(xtalk_dmamap); free_pciio_dmamap(pcibr_dmamap); return 0; @@ -2977,7 +3477,8 @@ pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap) { pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - pciio_slot_t slot = pcibr_dmamap->bd_slot; + pciio_slot_t slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, + pcibr_dmamap->bd_slot); unsigned flags = pcibr_dmamap->bd_flags; @@ -3001,6 +3502,9 @@ pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); } + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_free: pcibr_dmamap=0x%x\n", pcibr_dmamap)); + free_pciio_dmamap(pcibr_dmamap); } @@ -3019,6 +3523,29 @@ iopaddr_t pci_addr; pciio_slot_t slot; + if (IS_PIC_BUSNUM_SOFT(soft, 0)) { + if ((xio_addr >= PICBRIDGE0_PCI_MEM32_BASE) && + (xio_lim <= PICBRIDGE0_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE0_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= PICBRIDGE0_PCI_MEM64_BASE) && + (xio_lim <= PICBRIDGE0_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE0_PCI_MEM64_BASE; + return pci_addr; + } + } else if (IS_PIC_BUSNUM_SOFT(soft, 1)) { + if ((xio_addr >= PICBRIDGE1_PCI_MEM32_BASE) && + (xio_lim <= PICBRIDGE1_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE1_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= PICBRIDGE1_PCI_MEM64_BASE) && + (xio_lim <= PICBRIDGE1_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE1_PCI_MEM64_BASE; + return pci_addr; + } + } else { if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; @@ -3029,15 +3556,16 @@ pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; return pci_addr; } - for (slot = 0; slot < 8; ++slot) - if ((xio_addr >= BRIDGE_DEVIO(slot)) && - (xio_lim < BRIDGE_DEVIO(slot + 1))) { + } + for (slot = soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(soft); ++slot) + if ((xio_addr >= PCIBR_BRIDGE_DEVIO(soft, slot)) && + (xio_lim < PCIBR_BRIDGE_DEVIO(soft, slot + 1))) { bridgereg_t dev; dev = soft->bs_slot[slot].bss_device; pci_addr = dev & BRIDGE_DEV_OFF_MASK; pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT; - pci_addr += xio_addr - BRIDGE_DEVIO(slot); + pci_addr += xio_addr - PCIBR_BRIDGE_DEVIO(soft, slot); return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE; } return 0; @@ -3070,7 +3598,7 @@ } else xio_port = pcibr_dmamap->bd_xio_port; - /* If this DMA is to an address that + /* If this DMA is to an addres that * refers back to this Bridge chip, * reduce it back to the correct * PCI MEM address. @@ -3099,14 +3627,12 @@ if (flags & PCIBR_NOPREFETCH) pci_addr &= ~PCI64_ATTR_PREF; -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct64):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, + pcibr_dmamap->bd_dev, + "pcibr_dmamap_addr: (direct64): wanted paddr [0x%x..0x%x] " + "XIO port 0x%x offset 0x%x, returning PCI 0x%x\n", + paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr)); + } else if (flags & PCIIO_FIXED) { /* A32 direct DMA: * always use 32-bit direct mapping, @@ -3126,14 +3652,12 @@ pci_addr = pcibr_dmamap->bd_pci_addr + xio_addr - pcibr_dmamap->bd_xio_addr; -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct32):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, + pcibr_dmamap->bd_dev, + "pcibr_dmamap_addr (direct32): wanted paddr [0x%x..0x%x] " + "XIO port 0x%x offset 0x%x, returning PCI 0x%x\n", + paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr)); + } else { bridge_t *bridge = pcibr_soft->bs_base; iopaddr_t offset = IOPGOFF(xio_addr); @@ -3148,14 +3672,6 @@ int ate_total = ate_count; unsigned freeze_time; #endif - -#if PCIBR_ATE_DEBUG - bridge_ate_t ate_cmp; - bridge_ate_p ate_cptr; - unsigned ate_lo, ate_hi; - int ate_bad = 0; - int ate_rbc = 0; -#endif bridge_ate_p ate_ptr = pcibr_dmamap->bd_ate_ptr; bridge_ate_t ate; @@ -3183,7 +3699,21 @@ ATE_FREEZE(); ATE_WRITE(); ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_GET32((&bridge->b_wid_tflush)); + } else { + bridge->b_wid_tflush; + } + } + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_addr (PMU) : wanted paddr " + "[0x%x..0x%x] returning PCI 0x%x\n", + paddr, paddr + req_size - 1, pci_addr)); + } else { /* The number of ATE's required is greater than the number * allocated for this map. One way this can happen is if @@ -3193,14 +3723,12 @@ * The other possibility is that the map is just plain too * small to handle the requested target area. */ -#if PCIBR_ATE_DEBUG - printk(KERN_WARNING "pcibr_dmamap_addr :\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tate_count 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - paddr, paddr + req_size - 1, - ate_count, pcibr_dmamap->bd_ate_count); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_addr (PMU) : wanted paddr " + "[0x%x..0x%x] ate_count 0x%x bd_ate_count 0x%x " + "ATE's required > number allocated\n", + paddr, paddr + req_size - 1, + ate_count, pcibr_dmamap->bd_ate_count)); pci_addr = 0; } @@ -3250,17 +3778,24 @@ xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) + if (!xtalk_alenlist) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list: xtalk_dmamap_list() failed, " + "pcibr_dmamap=0x%x\n", pcibr_dmamap)); goto fail; - + } alenlist_cursor_init(xtalk_alenlist, 0, NULL); if (inplace) { pciio_alenlist = xtalk_alenlist; } else { pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) + if (!pciio_alenlist) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list: alenlist_create() failed, " + "pcibr_dmamap=0x%lx\n", (unsigned long)pcibr_dmamap)); goto fail; + } } direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; @@ -3286,8 +3821,12 @@ if (xio_port == pcibr_soft->bs_xid) { new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); - if (new_addr == PCI_NOWHERE) + if (new_addr == PCI_NOWHERE) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list: pcibr_addr_xio_to_pci failed, " + "pcibr_dmamap=0x%x\n", pcibr_dmamap)); goto fail; + } } else if (direct64) { new_addr = pci_addr | xio_addr | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); @@ -3318,9 +3857,8 @@ | (xio_port << ATE_TIDSHIFT) | (xio_addr - offset); if (ate == ate_prev) { -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_list: ATE share\n"); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list: ATE share\n")); ate_ptr--; ate_index--; pci_addr -= IOPGSIZE; @@ -3335,14 +3873,13 @@ /* Ensure that this map contains enough ATE's */ if (ate_total > pcibr_dmamap->bd_ate_count) { -#if PCIBR_ATE_DEBUG - printk(KERN_WARNING "pcibr_dmamap_list :\n" - "\twanted xio_addr [0x%x..0x%x]\n" - "\tate_total 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - xio_addr, xio_addr + length - 1, - ate_total, pcibr_dmamap->bd_ate_count); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list :\n" + "\twanted xio_addr [0x%x..0x%x]\n" + "\tate_total 0x%x bd_ate_count 0x%x\n" + "\tATE's required > number allocated\n", + xio_addr, xio_addr + length - 1, + ate_total, pcibr_dmamap->bd_ate_count)); goto fail; } @@ -3362,13 +3899,22 @@ if (inplace) { if (ALENLIST_SUCCESS != alenlist_replace(pciio_alenlist, NULL, - &new_addr, &length, al_flags)) + &new_addr, &length, al_flags)) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list: alenlist_replace() failed, " + "pcibr_dmamap=0x%x\n", pcibr_dmamap)); + goto fail; + } } else { if (ALENLIST_SUCCESS != alenlist_append(pciio_alenlist, - new_addr, length, al_flags)) + new_addr, length, al_flags)) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list: alenlist_append() failed, " + "pcibr_dmamap=0x%x\n", pcibr_dmamap)); goto fail; + } } } if (!inplace) @@ -3386,8 +3932,21 @@ */ if (ate_freeze_done) { ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_GET32((&bridge->b_wid_tflush)); + } else { + bridge->b_wid_tflush; + } + } } + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_list: pcibr_dmamap=0x%x, pciio_alenlist=0x%x\n", + pcibr_dmamap, pciio_alenlist)); + return pciio_alenlist; fail: @@ -3398,7 +3957,16 @@ */ if (ate_freeze_done) { ATE_THAW(); - bridge->b_wid_tflush; + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_wid_tflush; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_GET32((&bridge->b_wid_tflush)); + } else { + bridge->b_wid_tflush; + } + } } if (pciio_alenlist && !inplace) alenlist_destroy(pciio_alenlist); @@ -3409,6 +3977,10 @@ void pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) { +#ifdef PIC_LATER + pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; + pciio_slot_t slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, +#endif /* * We could go through and invalidate ATEs here; * for performance reasons, we don't. @@ -3423,6 +3995,9 @@ atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); } xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); + + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, + "pcibr_dmamap_done: pcibr_dmamap=0x%x\n", pcibr_dmamap)); } @@ -3455,7 +4030,7 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; xwidgetnum_t xio_port; @@ -3464,6 +4039,7 @@ int have_rrbs; int min_rrbs; + int vchan = VCHAN0; /* merge in forced flags */ flags |= pcibr_soft->bs_dma_flags; @@ -3471,16 +4047,10 @@ xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size, flags & DMAMAP_FLAGS); if (!xio_addr) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xtalk_dmatrans_addr failed with 0x%x\n", + paddr, paddr + req_size - 1, xio_addr)); return 0; } /* @@ -3488,16 +4058,10 @@ */ if (XIO_PACKED(xio_addr)) { if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xtalk_dmatrans_addr failed with XIO_NOWHERE\n", + paddr, paddr + req_size - 1)); return 0; } xio_port = XIO_PORT(xio_addr); @@ -3515,6 +4079,10 @@ */ if (xio_port == pcibr_soft->bs_xid) { pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, pci_addr=0x%x\n", + paddr, paddr + req_size - 1, xio_port, pci_addr)); return pci_addr; } /* If the caller can use A64, try to @@ -3531,92 +4099,65 @@ if ((pci_addr != PCIBR_D64_BASE_UNSET) && (flags == slotp->bss_d64_flags)) { -#ifdef CONFIG_IA64_SGI_SN2 - pci_addr |= (PHYS_TO_DMA(xio_addr)) - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); -#else pci_addr |= xio_addr | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); -#endif -#if DEBUG && PCIBR_DMA_DEBUG #if HWG_PERF_CHECK if (xio_addr != 0x20000000) #endif - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, direct64: pci_addr=0x%x\n", + paddr, paddr + req_size - 1, xio_addr, pci_addr)); return (pci_addr); } if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); slotp->bss_d64_flags = flags; slotp->bss_d64_base = pci_addr; -#ifdef CONFIG_IA64_SGI_SN2 - pci_addr |= (PHYS_TO_DMA(xio_addr)) - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); -#else pci_addr |= xio_addr | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); -#endif - /* Make sure we have an RRB (or two). + /* If in PCI mode, make sure we have an RRB (or two). */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { + if (IS_PCI(pcibr_soft) && + !(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { if (flags & PCIBR_VCHAN1) - pciio_slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; + vchan = VCHAN1; + have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan]; if (have_rrbs < 2) { if (pci_addr & PCI64_ATTR_PREF) min_rrbs = 2; else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); + do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, vchan, + min_rrbs - have_rrbs); } } -#if PCIBR_DMA_DEBUG #if HWG_PERF_CHECK if (xio_addr != 0x20000000) #endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr, (uint64_t) flags); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, direct64: pci_addr=0x%x, " + "new flags: 0x%x\n", paddr, paddr + req_size - 1, + xio_addr, pci_addr, (uint64_t) flags)); return (pci_addr); } - /* our flags conflict with Device(x). - */ - flags = flags - & ~PCIIO_DMA_A64 - & ~PCIBR_VCHAN0 - ; -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-64\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, Unable to set direct64 Device(x) bits\n", + paddr, paddr + req_size - 1, xio_addr)); + + /* PIC only supports 64-bit direct mapping in PCI-X mode */ + if (IS_PCIX(pcibr_soft)) { + return 0; + } + + /* our flags conflict with Device(x). try direct32*/ + flags = flags & ~(PCIIO_DMA_A64 | PCIBR_VCHAN0); } /* Try to satisfy the request with the 32-bit direct * map. This can fail if the configuration bits in @@ -3633,17 +4174,11 @@ (xio_addr < xio_base) || (xio_port != pcibr_soft->bs_dir_xport) || (endoff > map_size)) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\txio region outside direct32 target\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif + + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, xio region outside direct32 target\n", + paddr, paddr + req_size - 1, xio_addr)); } else { pci_addr = slotp->bss_d32_base; if ((pci_addr != PCIBR_D32_BASE_UNSET) && @@ -3651,18 +4186,11 @@ pci_addr |= offset; -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, direct32: pci_addr=0x%x\n", + paddr, paddr + req_size - 1, xio_addr, pci_addr)); + return (pci_addr); } if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { @@ -3675,61 +4203,41 @@ /* Make sure we have an RRB (or two). */ if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; + have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan]; if (have_rrbs < 2) { if (slotp->bss_device & BRIDGE_DEV_PREF) min_rrbs = 2; else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); + do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, + vchan, min_rrbs - have_rrbs); } } -#if PCIBR_DMA_DEBUG #if HWG_PERF_CHECK if (xio_addr != 0x20000000) #endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr, (uint64_t) flags); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, direct32: pci_addr=0x%x, " + "new flags: 0x%x\n", paddr, paddr + req_size - 1, + xio_addr, pci_addr, (uint64_t) flags)); + return (pci_addr); } /* our flags conflict with Device(x). */ -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-32\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, Unable to set direct32 Device(x) bits\n", + paddr, paddr + req_size - 1, xio_port)); } } -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tno acceptable PCI address found or constructable\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " + "xio_port=0x%x, No acceptable PCI address found\n", + paddr, paddr + req_size - 1, xio_port)); return 0; } @@ -3744,7 +4252,7 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; xwidgetnum_t xio_port; @@ -3781,6 +4289,9 @@ /* reuse previous base info */ } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { /* DMA configuration conflict */ + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: DMA configuration conflict " + "for direct64, flags=0x%x\n", flags)); goto fail; } else { relbits = BRIDGE_DEV_D64_BITS; @@ -3796,6 +4307,9 @@ /* reuse previous base info */ } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { /* DMA configuration conflict */ + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: DMA configuration conflict " + "for direct32, flags=0x%x\n", flags)); goto fail; } else { relbits = BRIDGE_DEV_D32_BITS; @@ -3805,8 +4319,12 @@ xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) + if (!xtalk_alenlist) { + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: xtalk_dmatrans_list failed " + "xtalk_alenlist=0x%x\n", xtalk_alenlist)); goto fail; + } alenlist_cursor_init(xtalk_alenlist, 0, NULL); @@ -3814,8 +4332,12 @@ pciio_alenlist = xtalk_alenlist; } else { pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) + if (!pciio_alenlist) { + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: alenlist_create failed with " + " 0x%x\n", pciio_alenlist)); goto fail; + } } while (ALENLIST_SUCCESS == @@ -3827,16 +4349,8 @@ */ if (XIO_PACKED(xio_addr)) { if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: xio_addr == XIO_NOWHERE\n")); return 0; } xio_port = XIO_PORT(xio_addr); @@ -3853,8 +4367,12 @@ */ if (xio_port == pcibr_soft->bs_xid) { pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); - if ( (pci_addr == (alenaddr_t)NULL) ) + if (pci_addr == (alenaddr_t)NULL) { + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: pcibr_addr_xio_to_pci failed " + "xio_addr=0x%x, xio_size=0x%x\n", xio_addr, xio_size)); goto fail; + } } else if (direct64) { ASSERT(xio_port != 0); pci_addr = pci_base | xio_addr @@ -3866,8 +4384,14 @@ if ((xio_size > map_size) || (xio_addr < xio_base) || (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) + (endoff > map_size)) { + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: xio_size > map_size fail\n" + "xio_addr=0x%x, xio_size=0x%x. map_size=0x%x, " + "xio_port=0x%x, endoff=0x%x\n", + xio_addr, xio_size, map_size, xio_port, endoff)); goto fail; + } pci_addr = pci_base + (xio_addr - xio_base); } @@ -3878,13 +4402,19 @@ if (inplace) { if (ALENLIST_SUCCESS != alenlist_replace(pciio_alenlist, NULL, - &pci_addr, &xio_size, al_flags)) + &pci_addr, &xio_size, al_flags)) { + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: alenlist_replace failed\n")); goto fail; + } } else { if (ALENLIST_SUCCESS != alenlist_append(pciio_alenlist, - pci_addr, xio_size, al_flags)) + pci_addr, xio_size, al_flags)) { + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: alenlist_append failed\n")); goto fail; + } } } @@ -3904,6 +4434,11 @@ * to the caller. */ alenlist_cursor_init(pciio_alenlist, 0, NULL); + + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_list: pciio_alenlist=0x%x\n", + pciio_alenlist)); + return pciio_alenlist; fail: @@ -3973,8 +4508,9 @@ int pcibr_reset(devfs_handle_t conn) { +#ifdef PIC_LATER pciio_info_t pciio_info = pciio_info_get(conn); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t ctlreg; @@ -3984,42 +4520,59 @@ pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; int win; + int error = 0; +#endif /* PIC_LATER */ + BUG(); +#ifdef PIC_LATER if (pcibr_soft->bs_slot[pciio_slot].has_host) { pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot; pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0]; } - if (pciio_slot < 4) { + + if ((pciio_slot >= pcibr_soft->bs_first_slot) && + (pciio_slot <= pcibr_soft->bs_last_reset)) { s = pcibr_lock(pcibr_soft); nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos; for (f = 0; f < nf; ++f) if (pcibr_infoh[f]) - cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4]; + cfgctl[f] = pcibr_func_config_get(bridge, pciio_slot, f, + PCI_CFG_COMMAND/4); + + error = iobrick_pci_slot_rst(pcibr_soft->bs_l1sc, + pcibr_widget_to_bus(pcibr_soft->bs_vhdl), + PCIBR_DEVICE_TO_SLOT(pcibr_soft,pciio_slot), + NULL); ctlreg = bridge->b_wid_control; - bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot); - /* XXX delay? */ - bridge->b_wid_control = ctlreg; - /* XXX delay? */ + bridge->b_wid_control = ctlreg & ~BRIDGE_CTRL_RST_PIN(pciio_slot); + nano_delay(&ts); + bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST_PIN(pciio_slot); + nano_delay(&ts); for (f = 0; f < nf; ++f) if ((pcibr_info = pcibr_infoh[f])) for (win = 0; win < 6; ++win) if (pcibr_info->f_window[win].w_base != 0) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = - pcibr_info->f_window[win].w_base; + pcibr_func_config_set(bridge, pciio_slot, f, + PCI_CFG_BASE_ADDR(win) / 4, + pcibr_info->f_window[win].w_base); for (f = 0; f < nf; ++f) if (pcibr_infoh[f]) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f]; + pcibr_func_config_set(bridge, pciio_slot, f, + PCI_CFG_COMMAND / 4, + cfgctl[f]); pcibr_unlock(pcibr_soft, s); + if (error) + return(-1); + return 0; } -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_WARNING "%v: pcibr_reset unimplemented for slot %d\n", - conn, pciio_slot); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, conn, + "pcibr_reset unimplemented for slot %d\n", conn, pciio_slot)); +#endif /* PIC_LATER */ return -1; } @@ -4029,7 +4582,7 @@ pciio_endian_t desired_end) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridgereg_t devreg; unsigned long s; @@ -4053,16 +4606,32 @@ if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { bridge_t *bridge = pcibr_soft->bs_base; - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg); + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */ + } else { + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + } } pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg); +#ifdef PIC_LATER + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl, + "pcibr_endian_set: Device(%d): %x\n", + pciio_slot, devreg, device_bits)); +#else + printk("pcibr_endian_set: Device(%d): %x\n", pciio_slot, devreg); #endif - return desired_end; } @@ -4130,9 +4699,22 @@ if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { bridge_t *bridge = pcibr_soft->bs_base; - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg); + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */ + } else { + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + } } pcibr_unlock(pcibr_soft, s); @@ -4144,7 +4726,7 @@ pciio_priority_t device_prio) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio); @@ -4168,7 +4750,7 @@ pcibr_device_flags_t flags) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridgereg_t set = 0; bridgereg_t clr = 0; @@ -4215,18 +4797,81 @@ if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { bridge_t *bridge = pcibr_soft->bs_base; - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + if ( IS_PIC_SOFT(pcibr_soft) ) { + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg); + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */ + } else { + bridge->b_device[pciio_slot].reg = devreg; + pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + } + } } pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits); +#ifdef PIC_LATER + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl, + "pcibr_device_flags_set: Device(%d): %x\n", + pciio_slot, devreg, device_bits)); +#else + printk("pcibr_device_flags_set: Device(%d): %x\n", pciio_slot, devreg); #endif } return (1); } +/* + * PIC has 16 RBARs per bus; meaning it can have a total of 16 outstanding + * split transactions. If the functions on the bus have requested a total + * of 16 or less, then we can give them what they requested (ie. 100%). + * Otherwise we have make sure each function can get at least one buffer + * and then divide the rest of the buffers up among the functions as ``A + * PERCENTAGE OF WHAT THEY REQUESTED'' (i.e. 0% - 100% of a function's + * pcix_type0_status.max_out_split). This percentage does not include the + * one RBAR that all functions get by default. + */ +int +pcibr_pcix_rbars_calc(pcibr_soft_t pcibr_soft) +{ + /* 'percent_allowed' is the percentage of requested RBARs that functions + * are allowed, ***less the 1 RBAR that all functions get by default*** + */ + int percent_allowed; + + if (pcibr_soft->bs_pcix_num_funcs) { + if (pcibr_soft->bs_pcix_num_funcs > NUM_RBAR) { + printk(KERN_WARNING + "%lx: Must oversubscribe Read Buffer Attribute Registers" + "(RBAR). Bus has %d RBARs but %d funcs need them.\n", + (unsigned long)pcibr_soft->bs_vhdl, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs); + percent_allowed = 0; + } else { + percent_allowed = (((NUM_RBAR-pcibr_soft->bs_pcix_num_funcs)*100) / + pcibr_soft->bs_pcix_split_tot); + + /* +1 to percentage to solve rounding errors that occur because + * we're not doing fractional math. (ie. ((3 * 66%) / 100) = 1) + * but should be "2" if doing true fractional math. NOTE: Since + * the greatest number of outstanding transactions a function + * can request is 32, this "+1" will always work (i.e. we won't + * accidentally oversubscribe the RBARs because of this rounding + * of the percentage). + */ + percent_allowed=(percent_allowed > 100) ? 100 : percent_allowed+1; + } + } else { + return(ENODEV); + } + + return(percent_allowed); +} + pciio_provider_t pcibr_provider = { (pciio_piomap_alloc_f *) pcibr_piomap_alloc, @@ -4262,17 +4907,17 @@ (pciio_priority_set_f *) pcibr_priority_set, (pciio_config_get_f *) pcibr_config_get, (pciio_config_set_f *) pcibr_config_set, - - (pciio_error_devenable_f *) 0, - (pciio_error_extract_f *) 0, - -#ifdef LATER +#ifdef PIC_LATER + (pciio_error_devenable_f *) pcibr_error_devenable, + (pciio_error_extract_f *) pcibr_error_extract, (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, #else + (pciio_error_devenable_f *) 0, + (pciio_error_extract_f *) 0, (pciio_driver_reg_callback_f *) 0, (pciio_driver_unreg_callback_f *) 0, -#endif +#endif /* PIC_LATER */ (pciio_device_unregister_f *) pcibr_device_unregister, (pciio_dma_enabled_f *) pcibr_dma_enabled, }; @@ -4285,4 +4930,84 @@ return xtalk_dma_enabled(pcibr_soft->bs_conn); +} + + +/* + * pcibr_debug() is used to print pcibr debug messages to the console. A + * user enables tracing by setting the following global variables: + * + * pcibr_debug_mask -Bitmask of what to trace. see pcibr_private.h + * pcibr_debug_module -Module to trace. 'all' means trace all modules + * pcibr_debug_widget -Widget to trace. '-1' means trace all widgets + * pcibr_debug_slot -Slot to trace. '-1' means trace all slots + * + * 'type' is the type of debugging that the current PCIBR_DEBUG macro is + * tracing. 'vhdl' (which can be NULL) is the vhdl associated with the + * debug statement. If there is a 'vhdl' associated with this debug + * statement, it is parsed to obtain the module, widget, and slot. If the + * globals above match the PCIBR_DEBUG params, then the debug info in the + * parameter 'format' is sent to the console. + */ +void +pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...) +{ + char hwpath[MAXDEVNAME] = "\0"; + char copy_of_hwpath[MAXDEVNAME]; + char *module = "all"; + short widget = -1; + short slot = -1; + va_list ap; + char *strtok_r(char *string, const char *sepset, char **lasts); + + if (pcibr_debug_mask & type) { + if (vhdl) { + if (!hwgraph_vertex_name_get(vhdl, hwpath, MAXDEVNAME)) { + char *cp; + + if (strcmp(module, pcibr_debug_module)) { + /* strtok_r() wipes out string, use a copy */ + (void)strcpy(copy_of_hwpath, hwpath); + cp = strstr(copy_of_hwpath, "/module/"); + if (cp) { + char *last = NULL; + cp += strlen("/module"); + module = strtok_r(cp, "/", &last); + } + } + if (pcibr_debug_widget != -1) { + cp = strstr(hwpath, "/xtalk/"); + if (cp) { + cp += strlen("/xtalk/"); + widget = atoi(cp); + } + } + if (pcibr_debug_slot != -1) { + cp = strstr(hwpath, "/pci/"); + if (cp) { + cp += strlen("/pci/"); + slot = atoi(cp); + } + } + } + } + if ((vhdl == NULL) || + (!strcmp(module, pcibr_debug_module) && + (widget == pcibr_debug_widget) && + (slot == pcibr_debug_slot))) { +#ifdef LATER + printk("PCIBR_DEBUG<%d>\t: %s :", cpuid(), hwpath); +#else + printk("PCIBR_DEBUG\t: %s :", hwpath); +#endif + /* + * Kernel printk translates to this 3 line sequence. + * Since we have a variable length argument list, we + * need to call printk this way rather than directly + */ + va_start(ap, format); + printk(format, ap); + va_end(ap); + } + } } diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -39,6 +39,14 @@ #endif extern int hubii_check_widget_disabled(nasid_t, int); +#ifdef BRIDGE_B_DATACORR_WAR +extern int ql_bridge_rev_b_war(devfs_handle_t); +extern int bridge_rev_b_data_check_disable; +char *rev_b_datacorr_warning = +"***************************** WARNING! ******************************\n"; +char *rev_b_datacorr_mesg = +"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n"; +#endif /* ===================================================================== * ERROR HANDLING @@ -54,15 +62,18 @@ #define BRIDGE_PIOERR_TIMEOUT 1 /* Timeout in non-debug mode */ #endif +/* PIC has 64bit interrupt error registers, but BRIDGE has 32bit registers. + * Thus 'bridge_errors_to_dump needs' to default to the larger of the two. + */ #ifdef DEBUG #ifdef ERROR_DEBUG -bridgereg_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK; +uint64_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK; #else -bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP; +uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP; #endif #else -bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL | - BRIDGE_ISR_PCIBUS_PIOERR; +uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL | + BRIDGE_ISR_PCIBUS_PIOERR; #endif #if defined (PCIBR_LLP_CONTROL_WAR) @@ -71,8 +82,6 @@ /* FIXME: can these arrays be local ? */ -#ifdef LATER - struct reg_values xio_cmd_pactyp[] = { {0x0, "RdReq"}, @@ -113,7 +122,21 @@ struct reg_desc bridge_int_status_desc[] = { - F(31, "MULTI_ERR"), + F(45, "PCI_X_SPLIT_MES_PE"),/* PIC ONLY */ + F(44, "PCI_X_SPLIT_EMES"), /* PIC ONLY */ + F(43, "PCI_X_SPLIT_TO"), /* PIC ONLY */ + F(42, "PCI_X_UNEX_COMP"), /* PIC ONLY */ + F(41, "INT_RAM_PERR"), /* PIC ONLY */ + F(40, "PCI_X_ARB_ERR"), /* PIC ONLY */ + F(39, "PCI_X_REQ_TOUT"), /* PIC ONLY */ + F(38, "PCI_X_TABORT"), /* PIC ONLY */ + F(37, "PCI_X_PERR"), /* PIC ONLY */ + F(36, "PCI_X_SERR"), /* PIC ONLY */ + F(35, "PCI_X_MRETRY"), /* PIC ONLY */ + F(34, "PCI_X_MTOUT"), /* PIC ONLY */ + F(33, "PCI_X_DA_PARITY"), /* PIC ONLY */ + F(32, "PCI_X_AD_PARITY"), /* PIC ONLY */ + F(31, "MULTI_ERR"), /* BRIDGE ONLY */ F(30, "PMU_ESIZE_EFAULT"), F(29, "UNEXPECTED_RESP"), F(28, "BAD_XRESP_PACKET"), @@ -128,7 +151,7 @@ F(19, "LLP_RCTY"), F(18, "LLP_TX_RETRY"), F(17, "LLP_TCTY"), - F(16, "SSRAM_PERR"), + F(16, "SSRAM_PERR"), /* BRIDGE ONLY */ F(15, "PCI_ABORT"), F(14, "PCI_PARITY"), F(13, "PCI_SERR"), @@ -136,7 +159,7 @@ F(11, "PCI_MASTER_TOUT"), F(10, "PCI_RETRY_CNT"), F(9, "XREAD_REQ_TOUT"), - F(8, "GIO_BENABLE_ERR"), + F(8, "GIO_BENABLE_ERR"), /* BRIDGE ONLY */ F(7, "INT7"), F(6, "INT6"), F(5, "INT5"), @@ -195,20 +218,17 @@ {0} }; -#endif /* LATER */ - void print_bridge_errcmd(uint32_t cmdword, char *errtype) { - printk( - "\t Bridge %s Error Command Word Register %R\n", - errtype, cmdword, xio_cmd_bits); + printk("\t Bridge %s Error Command Word Register ", errtype); + print_register(cmdword, xio_cmd_bits); } char *pcibr_isr_errs[] = { "", "", "", "", "", "", "", "", - "08: GIO non-contiguous byte enable in crosstalk packet", + "08: GIO non-contiguous byte enable in crosstalk packet", /* BRIDGE ONLY */ "09: PCI to Crosstalk read request timeout", "10: PCI retry operation count exhausted.", "11: PCI bus device select timeout", @@ -216,7 +236,7 @@ "13: PCI Address/Cmd parity error ", "14: PCI Bridge detected parity error", "15: PCI abort condition", - "16: SSRAM parity error", + "16: SSRAM parity error", /* BRIDGE ONLY */ "17: LLP Transmitter Retry count wrapped", "18: LLP Transmitter side required Retry", "19: LLP Receiver retry count wrapped", @@ -231,13 +251,29 @@ "28: Framing error, response cmd data size does not match actual", "29: Unexpected response arrived", "30: PMU Access Fault", - "31: Multiple errors occurred", + "31: Multiple errors occurred", /* BRIDGE ONLY */ + + /* bits 32-45 are PIC ONLY */ + "32: PCI-X address or attribute cycle parity error", + "33: PCI-X data cycle parity error", + "34: PCI-X master timeout (ie. master abort)", + "35: PCI-X pio retry counter exhausted", + "36: PCI-X SERR", + "37: PCI-X PERR", + "38: PCI-X target abort", + "39: PCI-X read request timeout", + "40: PCI / PCI-X device requestin arbitration error", + "41: internal RAM parity error", + "42: PCI-X unexpected completion cycle to master", + "43: PCI-X split completion timeout", + "44: PCI-X split completion error message", + "45: PCI-X split completion message parity error", }; #define BEM_ADD_STR(s) printk("%s", (s)) -#define BEM_ADD_VAR(v) printk("\t%20s: 0x%x\n", #v, (v)) -#define BEM_ADD_REG(r) printk("\t%20s: %R\n", #r, (r), r ## _desc) -#define BEM_ADD_NSPC(n,s) printk("\t%20s: %R\n", n, s, space_desc) +#define BEM_ADD_VAR(v) printk("\t%20s: 0x%llx\n", #v, ((unsigned long long)v)) +#define BEM_ADD_REG(r) printk("\t%20s: ", #r); print_register((r), r ## _desc) +#define BEM_ADD_NSPC(n,s) printk("\t%20s: ", n); print_register(s, space_desc) #define BEM_ADD_SPC(s) BEM_ADD_NSPC(#s, s) /* @@ -246,6 +282,7 @@ void pcibr_show_dir_state(paddr_t paddr, char *prefix) { +#ifdef LATER int state; uint64_t vec_ptr; hubreg_t elo; @@ -254,8 +291,9 @@ get_dir_ent(paddr, &state, &vec_ptr, &elo); - printf("%saddr 0x%x: state 0x%x owner 0x%x (%s)\n", + printk("%saddr 0x%lx: state 0x%x owner 0x%lx (%s)\n", prefix, paddr, state, vec_ptr, dir_state_str[state]); +#endif } @@ -267,40 +305,70 @@ pcibr_error_dump(pcibr_soft_t pcibr_soft) { bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t int_status; - bridgereg_t mult_int; - int bit; + uint64_t int_status; + bridgereg_t int_status_32; + picreg_t int_status_64; + uint64_t mult_int; + bridgereg_t mult_int_32; + picreg_t mult_int_64; + uint64_t bit; + int number_bits; int i; char *reg_desc; - paddr_t addr; + paddr_t addr = (paddr_t)0; + + /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a + * 32bit bridgereg_t for BRIDGE, but always process the result as a + * 64bit value so the code can be "common" for both PIC and BRIDGE... + */ + if (IS_PIC_SOFT(pcibr_soft)) { + int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK); + int_status = (uint64_t)int_status_64; + number_bits = PCIBR_ISR_MAX_ERRS_PIC; + } else { + int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK); + int_status = ((uint64_t)int_status_32) & 0xffffffff; + number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE; + } - int_status = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK); if (!int_status) { /* No error bits set */ return; } /* Check if dumping the same error information multiple times */ - if (test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat, - int_status) == int_status) { + if ( pcibr_soft->bs_errinfo.bserr_intstat == int_status ) return; - } + pcibr_soft->bs_errinfo.bserr_intstat = int_status; - printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%X for %s\n" - " Dumping relevant %sBridge registers for each bit set...\n", + printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%lx for %s\n" + " Dumping relevant %s registers for each bit set...\n", int_status, pcibr_soft->bs_name, - (is_xbridge(bridge) ? "X" : "")); + (IS_PIC_SOFT(pcibr_soft) ? "PIC" : + (IS_BRIDGE_SOFT(pcibr_soft) ? "BRIDGE" : "XBRIDGE"))); - for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) { - bit = 1 << i; + for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) { + bit = 1ull << i; /* * A number of int_status bits are only defined for Bridge. - * Ignore them in the case of an XBridge. + * Ignore them in the case of an XBridge or PIC. */ - if (is_xbridge(bridge) && ((bit == BRIDGE_ISR_MULTI_ERR) || - (bit == BRIDGE_ISR_SSRAM_PERR) || - (bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) { + if ((IS_XBRIDGE_SOFT(pcibr_soft) || IS_PIC_SOFT(pcibr_soft)) && + ((bit == BRIDGE_ISR_MULTI_ERR) || + (bit == BRIDGE_ISR_SSRAM_PERR) || + (bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) { + continue; + } + + /* A number of int_status bits are only valid for PIC's bus0 */ + if ((IS_PIC_SOFT(pcibr_soft) && (pcibr_soft->bs_busnum != 0)) && + ((bit == BRIDGE_ISR_UNSUPPORTED_XOP) || + (bit == BRIDGE_ISR_LLP_REC_SNERR) || + (bit == BRIDGE_ISR_LLP_REC_CBERR) || + (bit == BRIDGE_ISR_LLP_RCTY) || + (bit == BRIDGE_ISR_LLP_TX_RETRY) || + (bit == BRIDGE_ISR_LLP_TCTY))) { continue; } @@ -308,91 +376,241 @@ printk("\t%s\n", pcibr_isr_errs[i]); switch (bit) { - case BRIDGE_ISR_PAGE_FAULT: /* PMU_PAGE_FAULT (XBridge) */ -/* case BRIDGE_ISR_PMU_ESIZE_FAULT: PMU_ESIZE_FAULT (Bridge) */ - if (is_xbridge(bridge)) + + case PIC_ISR_INT_RAM_PERR: /* bit41 INT_RAM_PERR */ + /* XXX: should breakdown meaning of bits in reg */ + printk( "\t Internal RAM Parity Error: 0x%lx\n", + bridge->p_ate_parity_err_64); + break; + + case PIC_ISR_PCIX_ARB_ERR: /* bit40 PCI_X_ARB_ERR */ + /* XXX: should breakdown meaning of bits in reg */ + printk( "\t Arbitration Reg: 0x%x\n", + bridge->b_arb); + break; + + case PIC_ISR_PCIX_REQ_TOUT: /* bit39 PCI_X_REQ_TOUT */ + /* XXX: should breakdown meaning of attribute bit */ + printk( + "\t PCI-X DMA Request Error Address Reg: 0x%lx\n" + "\t PCI-X DMA Request Error Attribute Reg: 0x%lx\n", + bridge->p_pcix_dma_req_err_addr_64, + bridge->p_pcix_dma_req_err_attr_64); + break; + + case PIC_ISR_PCIX_SPLIT_MSG_PE: /* bit45 PCI_X_SPLIT_MES_PE */ + case PIC_ISR_PCIX_SPLIT_EMSG: /* bit44 PCI_X_SPLIT_EMESS */ + case PIC_ISR_PCIX_SPLIT_TO: /* bit43 PCI_X_SPLIT_TO */ + /* XXX: should breakdown meaning of attribute bit */ + printk( + "\t PCI-X Split Request Address Reg: 0x%lx\n" + "\t PCI-X Split Request Attribute Reg: 0x%lx\n", + bridge->p_pcix_pio_split_addr_64, + bridge->p_pcix_pio_split_attr_64); + /* FALL THRU */ + + case PIC_ISR_PCIX_UNEX_COMP: /* bit42 PCI_X_UNEX_COMP */ + case PIC_ISR_PCIX_TABORT: /* bit38 PCI_X_TABORT */ + case PIC_ISR_PCIX_PERR: /* bit37 PCI_X_PERR */ + case PIC_ISR_PCIX_SERR: /* bit36 PCI_X_SERR */ + case PIC_ISR_PCIX_MRETRY: /* bit35 PCI_X_MRETRY */ + case PIC_ISR_PCIX_MTOUT: /* bit34 PCI_X_MTOUT */ + case PIC_ISR_PCIX_DA_PARITY: /* bit33 PCI_X_DA_PARITY */ + case PIC_ISR_PCIX_AD_PARITY: /* bit32 PCI_X_AD_PARITY */ + /* XXX: should breakdown meaning of attribute bit */ + printk( + "\t PCI-X Bus Error Address Reg: 0x%lx\n" + "\t PCI-X Bus Error Attribute Reg: 0x%lx\n" + "\t PCI-X Bus Error Data Reg: 0x%lx\n", + bridge->p_pcix_bus_err_addr_64, + bridge->p_pcix_bus_err_attr_64, + bridge->p_pcix_bus_err_data_64); + break; + + case BRIDGE_ISR_PAGE_FAULT: /* bit30 PMU_PAGE_FAULT */ +/* case BRIDGE_ISR_PMU_ESIZE_FAULT: bit30 PMU_ESIZE_FAULT */ + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) reg_desc = "Map Fault Address"; else reg_desc = "SSRAM Parity Error"; - printk("\t %s Register: 0x%x\n", reg_desc, + printk( "\t %s Register: 0x%x\n", reg_desc, bridge->b_ram_perr_or_map_fault); break; - case BRIDGE_ISR_UNEXP_RESP: /* UNEXPECTED_RESP */ - print_bridge_errcmd(bridge->b_wid_aux_err, "Aux"); - break; + case BRIDGE_ISR_UNEXP_RESP: /* bit29 UNEXPECTED_RESP */ + print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); - case BRIDGE_ISR_BAD_XRESP_PKT: /* BAD_RESP_PACKET */ - case BRIDGE_ISR_RESP_XTLK_ERR: /* RESP_XTALK_ERROR */ - case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* XREAD_REQ_TOUT */ + /* PIC in PCI-X mode, dump the PCIX DMA Request registers */ + if (IS_PIC_SOFT(pcibr_soft) && IS_PCIX(pcibr_soft)) { + /* XXX: should breakdown meaning of attr bit */ + printk( + "\t PCI-X DMA Request Error Addr Reg: 0x%lx\n" + "\t PCI-X DMA Request Error Attr Reg: 0x%lx\n", + bridge->p_pcix_dma_req_err_addr_64, + bridge->p_pcix_dma_req_err_attr_64); + } + break; - addr = (((uint64_t) (bridge->b_wid_resp_upper & 0xFFFF) << 32) - | bridge->b_wid_resp_lower); - printk( - "\t Bridge Response Buffer Error Upper Address Register: 0x%x\n" - "\t Bridge Response Buffer Error Lower Address Register: 0x%x\n" - "\t dev-num %d buff-num %d addr 0x%x\n", - bridge->b_wid_resp_upper, bridge->b_wid_resp_lower, - ((bridge->b_wid_resp_upper >> 20) & 0x3), - ((bridge->b_wid_resp_upper >> 16) & 0xF), - addr); + case BRIDGE_ISR_BAD_XRESP_PKT: /* bit28 BAD_RESP_PACKET */ + case BRIDGE_ISR_RESP_XTLK_ERR: /* bit26 RESP_XTALK_ERROR */ + if (IS_PIC_SOFT(pcibr_soft)) { + print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); + } + + /* If PIC in PCI-X mode, DMA Request Error registers are + * valid. But PIC in PCI mode, Response Buffer Address + * register are valid. + */ + if (IS_PCIX(pcibr_soft)) { + /* XXX: should breakdown meaning of attribute bit */ + printk( + "\t PCI-X DMA Request Error Addr Reg: 0x%lx\n" + "\t PCI-X DMA Request Error Attribute Reg: 0x%lx\n", + bridge->p_pcix_dma_req_err_addr_64, + bridge->p_pcix_dma_req_err_attr_64); + } else { + addr= (((uint64_t)(bridge->b_wid_resp_upper & 0xFFFF)<<32) + | bridge->b_wid_resp_lower); + printk("\t Bridge Response Buf Error Upper Addr Reg: 0x%x\n" + "\t Bridge Response Buf Error Lower Addr Reg: 0x%x\n" + "\t dev-num %d buff-num %d addr 0x%lx\n", + bridge->b_wid_resp_upper, bridge->b_wid_resp_lower, + ((bridge->b_wid_resp_upper >> 20) & 0x3), + ((bridge->b_wid_resp_upper >> 16) & 0xF), + addr); + } if (bit == BRIDGE_ISR_RESP_XTLK_ERR) { /* display memory directory associated with cacheline */ pcibr_show_dir_state(addr, "\t "); } break; - case BRIDGE_ISR_BAD_XREQ_PKT: /* BAD_XREQ_PACKET */ - case BRIDGE_ISR_REQ_XTLK_ERR: /* REQ_XTALK_ERROR */ - case BRIDGE_ISR_INVLD_ADDR: /* INVALID_ADDRESS */ - case BRIDGE_ISR_UNSUPPORTED_XOP: /* UNSUPPORTED_XOP */ - print_bridge_errcmd(bridge->b_wid_aux_err, ""); - printk("\t Bridge Error Upper Address Register: 0x%x\n" - "\t Bridge Error Lower Address Register: 0x%x\n" - "\t Bridge Error Address: 0x%x\n", + case BRIDGE_ISR_BAD_XREQ_PKT: /* bit27 BAD_XREQ_PACKET */ + case BRIDGE_ISR_REQ_XTLK_ERR: /* bit25 REQ_XTALK_ERROR */ + case BRIDGE_ISR_INVLD_ADDR: /* bit24 INVALID_ADDRESS */ + print_bridge_errcmd(bridge->b_wid_err_cmdword, ""); + printk( + "\t Bridge Error Upper Address Register: 0x%lx\n" + "\t Bridge Error Lower Address Register: 0x%lx\n" + "\t Bridge Error Address: 0x%lx\n", (uint64_t) bridge->b_wid_err_upper, (uint64_t) bridge->b_wid_err_lower, (((uint64_t) bridge->b_wid_err_upper << 32) | bridge->b_wid_err_lower)); break; - case BRIDGE_ISR_SSRAM_PERR: /* SSRAM_PERR */ - if (!is_xbridge(bridge)) { /* only defined on Bridge */ + case BRIDGE_ISR_UNSUPPORTED_XOP:/* bit23 UNSUPPORTED_XOP */ + if (IS_PIC_SOFT(pcibr_soft)) { + print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); + printk( + "\t Address Holding Link Side Error Reg: 0x%lx\n", + bridge->p_addr_lkerr_64); + } else { + print_bridge_errcmd(bridge->b_wid_err_cmdword, ""); + printk( + "\t Bridge Error Upper Address Register: 0x%lx\n" + "\t Bridge Error Lower Address Register: 0x%lx\n" + "\t Bridge Error Address: 0x%lx\n", + (uint64_t) bridge->b_wid_err_upper, + (uint64_t) bridge->b_wid_err_lower, + (((uint64_t) bridge->b_wid_err_upper << 32) | + bridge->b_wid_err_lower)); + } + break; + + case BRIDGE_ISR_XREQ_FIFO_OFLOW:/* bit22 XREQ_FIFO_OFLOW */ + /* Link side error registers are only valid for PIC */ + if (IS_PIC_SOFT(pcibr_soft)) { + print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); + printk( + "\t Address Holding Link Side Error Reg: 0x%lx\n", + bridge->p_addr_lkerr_64); + } + break; + + case BRIDGE_ISR_SSRAM_PERR: /* bit16 SSRAM_PERR */ + if (IS_BRIDGE_SOFT(pcibr_soft)) { printk( "\t Bridge SSRAM Parity Error Register: 0x%x\n", bridge->b_ram_perr); } break; - case BRIDGE_ISR_PCI_ABORT: /* PCI_ABORT */ - case BRIDGE_ISR_PCI_PARITY: /* PCI_PARITY */ - case BRIDGE_ISR_PCI_SERR: /* PCI_SERR */ - case BRIDGE_ISR_PCI_PERR: /* PCI_PERR */ - case BRIDGE_ISR_PCI_MST_TIMEOUT: /* PCI_MASTER_TOUT */ - case BRIDGE_ISR_PCI_RETRY_CNT: /* PCI_RETRY_CNT */ - case BRIDGE_ISR_GIO_B_ENBL_ERR: /* GIO BENABLE_ERR */ - printk("\t PCI Error Upper Address Register: 0x%x\n" - "\t PCI Error Lower Address Register: 0x%x\n" - "\t PCI Error Address: 0x%x\n", + case BRIDGE_ISR_PCI_ABORT: /* bit15 PCI_ABORT */ + case BRIDGE_ISR_PCI_PARITY: /* bit14 PCI_PARITY */ + case BRIDGE_ISR_PCI_SERR: /* bit13 PCI_SERR */ + case BRIDGE_ISR_PCI_PERR: /* bit12 PCI_PERR */ + case BRIDGE_ISR_PCI_MST_TIMEOUT:/* bit11 PCI_MASTER_TOUT */ + case BRIDGE_ISR_PCI_RETRY_CNT: /* bit10 PCI_RETRY_CNT */ + case BRIDGE_ISR_GIO_B_ENBL_ERR: /* bit08 GIO BENABLE_ERR */ + printk( + "\t PCI Error Upper Address Register: 0x%lx\n" + "\t PCI Error Lower Address Register: 0x%lx\n" + "\t PCI Error Address: 0x%lx\n", (uint64_t) bridge->b_pci_err_upper, (uint64_t) bridge->b_pci_err_lower, (((uint64_t) bridge->b_pci_err_upper << 32) | bridge->b_pci_err_lower)); break; + + case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* bit09 XREAD_REQ_TOUT */ + addr = (((uint64_t)(bridge->b_wid_resp_upper & 0xFFFF) << 32) + | bridge->b_wid_resp_lower); + printk( + "\t Bridge Response Buf Error Upper Addr Reg: 0x%x\n" + "\t Bridge Response Buf Error Lower Addr Reg: 0x%x\n" + "\t dev-num %d buff-num %d addr 0x%lx\n", + bridge->b_wid_resp_upper, bridge->b_wid_resp_lower, + ((bridge->b_wid_resp_upper >> 20) & 0x3), + ((bridge->b_wid_resp_upper >> 16) & 0xF), + addr); + break; } } } - if (is_xbridge(bridge) && (bridge->b_mult_int & ~BRIDGE_ISR_INT_MSK)) { - mult_int = bridge->b_mult_int; - printk(" XBridge Multiple Interrupt Register is 0x%x\n", - mult_int); - for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) { - if (mult_int & (1 << i)) - printk("\t%s\n", pcibr_isr_errs[i]); - } + /* We read the INT_MULT register as a 64bit picreg_t for PIC and a + * 32bit bridgereg_t for BRIDGE, but always process the result as a + * 64bit value so the code can be "common" for both PIC and BRIDGE... + */ + if (IS_PIC_SOFT(pcibr_soft)) { + mult_int_64 = (bridge->p_mult_int_64 & ~BRIDGE_ISR_INT_MSK); + mult_int = (uint64_t)mult_int_64; + number_bits = PCIBR_ISR_MAX_ERRS_PIC; + } else { + mult_int_32 = (bridge->b_mult_int & ~BRIDGE_ISR_INT_MSK); + mult_int = ((uint64_t)mult_int_32) & 0xffffffff; + number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE; + } + + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)&&(mult_int & ~BRIDGE_ISR_INT_MSK)) { + printk( " %s Multiple Interrupt Register is 0x%lx\n", + IS_PIC_SOFT(pcibr_soft) ? "PIC" : "XBridge", mult_int); + for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) { + if (mult_int & (1ull << i)) + printk( "\t%s\n", pcibr_isr_errs[i]); } + } + +#if BRIDGE_ERROR_INTR_WAR + if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { /* known bridge bug */ + /* + * Should never receive interrupts for these reasons on Rev 1 bridge + * as they are not enabled. Assert for it. + */ + ASSERT((int_status & (BRIDGE_IMR_PCI_MST_TIMEOUT | + BRIDGE_ISR_RESP_XTLK_ERR | + BRIDGE_ISR_LLP_TX_RETRY)) == 0); + } + if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) { /* known bridge bug */ + /* + * This interrupt is turned off at init time. So, should never + * see this interrupt. + */ + ASSERT((int_status & BRIDGE_ISR_BAD_XRESP_PKT) == 0); + } +#endif } #define PCIBR_ERRINTR_GROUP(error) \ @@ -430,9 +648,11 @@ pcibr_pioerr_check(pcibr_soft_t soft) { bridge_t *bridge; - bridgereg_t b_int_status; - bridgereg_t b_pci_err_lower; - bridgereg_t b_pci_err_upper; + uint64_t int_status; + bridgereg_t int_status_32; + picreg_t int_status_64; + bridgereg_t pci_err_lower; + bridgereg_t pci_err_upper; iopaddr_t pci_addr; pciio_slot_t slot; pcibr_piomap_t map; @@ -442,40 +662,48 @@ int func; bridge = soft->bs_base; - b_int_status = bridge->b_int_status; - if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - b_pci_err_lower = bridge->b_pci_err_lower; - b_pci_err_upper = bridge->b_pci_err_upper; - b_int_status = bridge->b_int_status; - if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - - pci_addr = b_pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK; - pci_addr = (pci_addr << 32) | b_pci_err_lower; - - slot = 8; - while (slot-- > 0) { - int nfunc = soft->bs_slot[slot].bss_ninfo; - pcibr_info_h pcibr_infoh = soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; func++) { - pcibr_info_t pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - for (map = pcibr_info->f_piomap; - map != NULL; map = map->bp_next) { - base = map->bp_pciaddr; - size = map->bp_mapsz; - win = map->bp_space - PCIIO_SPACE_WIN(0); - if (win < 6) - base += - soft->bs_slot[slot].bss_window[win].bssw_base; - else if (map->bp_space == PCIIO_SPACE_ROM) - base += pcibr_info->f_rbase; - if ((pci_addr >= base) && (pci_addr < (base + size))) - atomicAddInt(map->bp_toc, 1); - } + + /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a + * 32bit bridgereg_t for BRIDGE, but always process the result as a + * 64bit value so the code can be "common" for both PIC and BRIDGE... + */ + if (IS_PIC_SOFT(soft)) { + int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK); + int_status = (uint64_t)int_status_64; + } else { + int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK); + int_status = ((uint64_t)int_status_32) & 0xffffffff; + } + + if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) { + pci_err_lower = bridge->b_pci_err_lower; + pci_err_upper = bridge->b_pci_err_upper; + + pci_addr = pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK; + pci_addr = (pci_addr << 32) | pci_err_lower; + + slot = PCIBR_NUM_SLOTS(soft); + while (slot-- > 0) { + int nfunc = soft->bs_slot[slot].bss_ninfo; + pcibr_info_h pcibr_infoh = soft->bs_slot[slot].bss_infos; + + for (func = 0; func < nfunc; func++) { + pcibr_info_t pcibr_info = pcibr_infoh[func]; + + if (!pcibr_info) + continue; + + for (map = pcibr_info->f_piomap; + map != NULL; map = map->bp_next) { + base = map->bp_pciaddr; + size = map->bp_mapsz; + win = map->bp_space - PCIIO_SPACE_WIN(0); + if (win < 6) + base += soft->bs_slot[slot].bss_window[win].bssw_base; + else if (map->bp_space == PCIIO_SPACE_ROM) + base += pcibr_info->f_rbase; + if ((pci_addr >= base) && (pci_addr < (base + size))) + atomic_inc(&map->bp_toc[0]); } } } @@ -502,25 +730,33 @@ * due to read or write error!. */ - void -pcibr_error_intr_handler(intr_arg_t arg) +pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) { pcibr_soft_t pcibr_soft; bridge_t *bridge; - bridgereg_t int_status; - bridgereg_t err_status; + uint64_t int_status; + uint64_t err_status; + bridgereg_t int_status_32; + picreg_t int_status_64; + int number_bits; int i; /* REFERENCED */ - bridgereg_t disable_errintr_mask = 0; + uint64_t disable_errintr_mask = 0; +#ifdef EHE_ENABLE int rv; int error_code = IOECODE_DMA | IOECODE_READ; ioerror_mode_t mode = MODE_DEVERROR; ioerror_t ioe; +#endif /* EHE_ENABLE */ nasid_t nasid; + #if PCIBR_SOFT_LIST + /* + * Defensive code for linked pcibr_soft structs + */ { extern pcibr_list_p pcibr_list; pcibr_list_p entry; @@ -528,17 +764,14 @@ entry = pcibr_list; while (1) { if (entry == NULL) { - PRINT_PANIC( - "pcibr_error_intr_handler:\n" - "\tmy parameter (0x%x) is not a pcibr_soft!", - arg); + PRINT_PANIC("pcibr_error_intr_handler:\tmy parameter (0x%p) is not a pcibr_soft!", arg); } if ((intr_arg_t) entry->bl_soft == arg) break; entry = entry->bl_next; } } -#endif +#endif /* PCIBR_SOFT_LIST */ pcibr_soft = (pcibr_soft_t) arg; bridge = pcibr_soft->bs_base; @@ -568,16 +801,37 @@ nasid = NASID_GET(bridge); if (hubii_check_widget_disabled(nasid, pcibr_soft->bs_xid)) { - timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT); + DECLARE_WAIT_QUEUE_HEAD(wq); + sleep_on_timeout(&wq, BRIDGE_PIOERR_TIMEOUT*HZ ); /* sleep */ pcibr_soft->bs_errinfo.bserr_toutcnt++; + /* Let's go recursive */ + return(pcibr_error_intr_handler(irq, arg, ep)); +#ifdef LATER + timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT); +#endif return; } + /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a + * 32bit bridgereg_t for BRIDGE, but always process the result as a + * 64bit value so the code can be "common" for both PIC and BRIDGE... + */ + if (IS_PIC_SOFT(pcibr_soft)) { + int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK); + int_status = (uint64_t)int_status_64; + number_bits = PCIBR_ISR_MAX_ERRS_PIC; + } else { + int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK); + int_status = ((uint64_t)int_status_32) & 0xffffffff; + number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE; + } + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ERROR, pcibr_soft->bs_conn, + "pcibr_error_intr_handler: int_status=0x%x\n", int_status)); + /* int_status is which bits we have to clear; * err_status is the bits we haven't handled yet. */ - - int_status = bridge->b_int_status & ~BRIDGE_ISR_INT_MSK; err_status = int_status & ~BRIDGE_ISR_MULTI_ERR; if (!(int_status & ~BRIDGE_ISR_INT_MSK)) { @@ -593,11 +847,29 @@ pcibr_pioerr_check(pcibr_soft); } +#ifdef BRIDGE_B_DATACORR_WAR + if ((pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) && + (err_status & BRIDGE_IMR_LLP_REC_CBERR)) { + if (bridge_rev_b_data_check_disable) + printk(KERN_WARNING "\n%s%s: %s%s\n", rev_b_datacorr_warning, + pcibr_soft->bs_name, rev_b_datacorr_mesg, + rev_b_datacorr_warning); + else { + ql_bridge_rev_b_war(pcibr_soft->bs_vhdl); + PRINT_PANIC( "\n%s%s: %s%s\n", rev_b_datacorr_warning, + pcibr_soft->bs_name, rev_b_datacorr_mesg, + rev_b_datacorr_warning); + } + + err_status &= ~BRIDGE_IMR_LLP_REC_CBERR; + } +#endif /* BRIDGE_B_DATACORR_WAR */ + if (err_status) { struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat; - for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++, bs_estat++) { - if (err_status & (1 << i)) { + for (i = PCIBR_ISR_ERR_START; i < number_bits; i++, bs_estat++) { + if (err_status & (1ull << i)) { uint32_t errrate = 0; uint32_t errcount = 0; uint32_t errinterval = 0, current_tick = 0; @@ -606,12 +878,14 @@ bs_estat->bs_errcount_total++; - current_tick = lbolt; + current_tick = jiffies; errinterval = (current_tick - bs_estat->bs_lasterr_timestamp); errcount = (bs_estat->bs_errcount_total - bs_estat->bs_lasterr_snapshot); - is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY == (1 << i)); + /* LLP interrrupt errors are only valid on BUS0 of the PIC */ + if (pcibr_soft->bs_busnum == 0) + is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY==(1ull << i)); /* Check for the divide by zero condition while * calculating the error rates. @@ -698,6 +972,15 @@ bs_estat->bs_errcount_total; } } + /* PIC BRINGUP WAR (PV# 856155): + * Dont disable PCI_X_ARB_ERR interrupts, we need the + * interrupt inorder to clear the DEV_BROKE bits in + * b_arb register to re-enable the device. + */ + if (IS_PIC_SOFT(pcibr_soft) && + !(err_status & PIC_ISR_PCIX_ARB_ERR) && + PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) { + if (bs_estat->bs_errcount_total > PCIBR_ERRINTR_DISABLE_LEVEL) { /* * We have seen a fairly large number of errors of @@ -709,18 +992,26 @@ pcibr_soft->bs_name, pcibr_isr_errs[i], bs_estat->bs_errcount_total); - disable_errintr_mask |= (1 << i); + disable_errintr_mask |= (1ull << i); } + } /* PIC: WAR for PV 856155 end-of-if */ } } } if (disable_errintr_mask) { + unsigned s; /* * Disable some high frequency errors as they * could eat up too much cpu time. */ - bridge->b_int_enable &= ~disable_errintr_mask; + s = pcibr_lock(pcibr_soft); + if (IS_PIC_SOFT(pcibr_soft)) { + bridge->p_int_enable_64 &= (picreg_t)(~disable_errintr_mask); + } else { + bridge->b_int_enable &= (bridgereg_t)(~disable_errintr_mask); + } + pcibr_unlock(pcibr_soft, s); } /* * If we leave the PROM cacheable, T5 might @@ -783,15 +1074,34 @@ if (rv != IOERROR_HANDLED) { #endif /* EHE_ENABLE */ + bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR; + /* Dump/Log Bridge error interrupt info */ if (err_status & bridge_errors_to_dump) { - printk("BRIDGE ERR_STATUS 0x%x\n", err_status); + printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); pcibr_error_dump(pcibr_soft); } + /* PIC BRINGUP WAR (PV# 867308): + * Make BRIDGE_ISR_LLP_REC_SNERR & BRIDGE_ISR_LLP_REC_CBERR fatal errors + * so we know we've hit the problem defined in PV 867308 that we believe + * has only been seen in simulation + */ + if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV867308, pcibr_soft) && + (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) { + printk("BRIDGE ERR_STATUS 0x%x\n", err_status); + pcibr_error_dump(pcibr_soft); +#ifdef LATER + machine_error_dump(""); +#endif + PRINT_PANIC("PCI Bridge Error interrupt killed the system"); + } + if (err_status & BRIDGE_ISR_ERROR_FATAL) { +#ifdef LATER machine_error_dump(""); - cmn_err_tag(14, CE_PANIC, "PCI Bridge Error interrupt killed the system"); +#endif + PRINT_PANIC("PCI Bridge Error interrupt killed the system"); /*NOTREACHED */ } @@ -804,11 +1114,27 @@ * it would cause problems for devices like IOC3 (Lost * interrupts ?.). So, just cleanup the interrupt, and * use saved values later.. + * + * PIC doesn't require groups of interrupts to be cleared... */ - bridge->b_int_rst_stat = pcibr_errintr_group(int_status); + if (IS_PIC_SOFT(pcibr_soft)) { + bridge->p_int_rst_stat_64 = (picreg_t)(int_status | BRIDGE_IRR_MULTI_CLR); + } else { + bridge->b_int_rst_stat = (bridgereg_t)pcibr_errintr_group(int_status); + } + + /* PIC BRINGUP WAR (PV# 856155): + * On a PCI_X_ARB_ERR error interrupt clear the DEV_BROKE bits from + * the b_arb register to re-enable the device. + */ + if (IS_PIC_SOFT(pcibr_soft) && + (err_status & PIC_ISR_PCIX_ARB_ERR) && + PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) { + bridge->b_arb |= (0xf << 20); + } /* Zero out bserr_intstat field */ - test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat, 0); + pcibr_soft->bs_errinfo.bserr_intstat = 0; } /* @@ -832,7 +1158,7 @@ iopaddr_t *offsetp, pciio_function_t *funcp) { - int s, f, w; + int s, f = 0, w; iopaddr_t base; size_t size; pciio_piospace_t piosp; @@ -864,7 +1190,7 @@ return s; } - for (s = 0; s < 8; s++) { + for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { int nf = pcibr_soft->bs_slot[s].bss_ninfo; pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; @@ -874,8 +1200,7 @@ if (!pcibr_info) continue; for (w = 0; w < 6; w++) { - if (pcibr_info->f_window[w].w_space - == PCIIO_SPACE_NONE) { + if (pcibr_info->f_window[w].w_space == PCIIO_SPACE_NONE) { continue; } base = pcibr_info->f_window[w].w_base; @@ -898,7 +1223,7 @@ * Check if the address was allocated as part of the * pcibr_piospace_alloc calls. */ - for (s = 0; s < 8; s++) { + for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { int nf = pcibr_soft->bs_slot[s].bss_ninfo; pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; @@ -950,8 +1275,14 @@ ASSERT(error_code & IOECODE_PIO); error_code = error_code; - bridge->b_int_rst_stat = - (BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR); + if (IS_PIC_SOFT(pcibr_soft)) { + bridge->p_int_rst_stat_64 = BRIDGE_IRR_PCI_GRP_CLR | + PIC_PCIX_GRP_CLR | + BRIDGE_IRR_MULTI_CLR; + } else { + bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR; + } + (void) bridge->b_wid_tflush; /* flushbus */ } @@ -1040,13 +1371,6 @@ * associated with this device. */ -#define BEM_ADD_STR(s) printk("%s", (s)) -#define BEM_ADD_VAR(v) printk("\t%20s: 0x%x\n", #v, (v)) -#define BEM_ADD_REG(r) printk("\t%20s: %R\n", #r, (r), r ## _desc) - -#define BEM_ADD_NSPC(n,s) printk("\t%20s: %R\n", n, s, space_desc) -#define BEM_ADD_SPC(s) BEM_ADD_NSPC(#s, s) - /* BEM_ADD_IOE doesn't dump the whole ioerror, it just * decodes the PCI specific portions -- we count on our * callers to dump the raw IOE data. @@ -1054,40 +1378,38 @@ #define BEM_ADD_IOE(ioe) \ do { \ if (IOERROR_FIELDVALID(ioe, busspace)) { \ - unsigned spc; \ - unsigned win; \ + iopaddr_t spc; \ + iopaddr_t win; \ + short widdev; \ + iopaddr_t busaddr; \ \ - spc = IOERROR_GETVALUE(ioe, busspace); \ + IOERROR_GETVALUE(spc, ioe, busspace); \ win = spc - PCIIO_SPACE_WIN(0); \ + IOERROR_GETVALUE(busaddr, ioe, busaddr); \ + IOERROR_GETVALUE(widdev, ioe, widgetdev); \ \ switch (spc) { \ case PCIIO_SPACE_CFG: \ - printk( \ - "\tPCI Slot %d Func %d CFG space Offset 0x%x\n", \ - pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - IOERROR_GETVALUE(ioe, busaddr)); \ + printk("\tPCI Slot %d Func %d CFG space Offset 0x%lx\n",\ + pciio_widgetdev_slot_get(widdev), \ + pciio_widgetdev_func_get(widdev), \ + busaddr); \ break; \ case PCIIO_SPACE_IO: \ - printk( \ - "\tPCI I/O space Offset 0x%x\n", \ - IOERROR_GETVALUE(ioe, busaddr)); \ + printk("\tPCI I/O space Offset 0x%lx\n", busaddr); \ break; \ case PCIIO_SPACE_MEM: \ case PCIIO_SPACE_MEM32: \ case PCIIO_SPACE_MEM64: \ - printk( \ - "\tPCI MEM space Offset 0x%x\n", \ - IOERROR_GETVALUE(ioe, busaddr)); \ + printk("\tPCI MEM space Offset 0x%lx\n", busaddr); \ break; \ default: \ if (win < 6) { \ - printk( \ - "\tPCI Slot %d Func %d Window %d Offset 0x%x\n",\ - pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)), \ - win, \ - IOERROR_GETVALUE(ioe, busaddr)); \ + printk("\tPCI Slot %d Func %d Window %ld Offset 0x%lx\n",\ + pciio_widgetdev_slot_get(widdev), \ + pciio_widgetdev_func_get(widdev), \ + win, \ + busaddr); \ } \ break; \ } \ @@ -1129,34 +1451,38 @@ * and need to construct the slot/space/offset. */ - bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr); + IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, + "pcibr_pioerror: pcibr_soft=0x%x, bad_xaddr=0x%x\n", + pcibr_soft, bad_xaddr)); slot = PCIIO_SLOT_NONE; func = PCIIO_FUNC_NONE; raw_space = PCIIO_SPACE_NONE; raw_paddr = 0; - if ((bad_xaddr >= BRIDGE_TYPE0_CFG_DEV0) && - (bad_xaddr < BRIDGE_TYPE1_CFG)) { - raw_paddr = bad_xaddr - BRIDGE_TYPE0_CFG_DEV0; + if ((bad_xaddr >= PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft)) && + (bad_xaddr < PCIBR_TYPE1_CFG(pcibr_soft))) { + raw_paddr = bad_xaddr - PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft); slot = raw_paddr / BRIDGE_TYPE0_CFG_SLOT_OFF; raw_paddr = raw_paddr % BRIDGE_TYPE0_CFG_SLOT_OFF; raw_space = PCIIO_SPACE_CFG; } - if ((bad_xaddr >= BRIDGE_TYPE1_CFG) && - (bad_xaddr < (BRIDGE_TYPE1_CFG + 0x1000))) { + if ((bad_xaddr >= PCIBR_TYPE1_CFG(pcibr_soft)) && + (bad_xaddr < (PCIBR_TYPE1_CFG(pcibr_soft) + 0x1000))) { /* Type 1 config space: * slot and function numbers not known. * Perhaps we can read them back? */ - raw_paddr = bad_xaddr - BRIDGE_TYPE1_CFG; + raw_paddr = bad_xaddr - PCIBR_TYPE1_CFG(pcibr_soft); raw_space = PCIIO_SPACE_CFG; } - if ((bad_xaddr >= BRIDGE_DEVIO0) && - (bad_xaddr < BRIDGE_DEVIO(BRIDGE_DEV_CNT))) { + if ((bad_xaddr >= PCIBR_BRIDGE_DEVIO0(pcibr_soft)) && + (bad_xaddr < PCIBR_BRIDGE_DEVIO(pcibr_soft, BRIDGE_DEV_CNT))) { int x; - raw_paddr = bad_xaddr - BRIDGE_DEVIO0; + raw_paddr = bad_xaddr - PCIBR_BRIDGE_DEVIO0(pcibr_soft); x = raw_paddr / BRIDGE_DEVIO_OFF; raw_paddr %= BRIDGE_DEVIO_OFF; /* first two devio windows are double-sized */ @@ -1223,7 +1549,9 @@ * going on (no guessing). */ - for (cs = 0; (cs < 8) && (slot == PCIIO_SLOT_NONE); cs++) { + for (cs = pcibr_soft->bs_min_slot; + (cs < PCIBR_NUM_SLOTS(pcibr_soft)) && + (slot == PCIIO_SLOT_NONE); cs++) { int nf = pcibr_soft->bs_slot[cs].bss_ninfo; pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; @@ -1283,7 +1611,8 @@ * strict count, the excess counts are not a * problem. */ - for (cs = 0; cs < 8; ++cs) { + for (cs = pcibr_soft->bs_min_slot; + cs < PCIBR_NUM_SLOTS(pcibr_soft); ++cs) { int nf = pcibr_soft->bs_slot[cs].bss_ninfo; pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; @@ -1313,7 +1642,7 @@ wx = PCIIO_SPACE_MEM; wl = wb + ws; if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) { - atomicAddInt(map->bp_toc, 1); + atomic_inc(&map->bp_toc[0]); if (slot == PCIIO_SLOT_NONE) { slot = cs; space = map->bp_space; @@ -1325,15 +1654,21 @@ } } + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, + "pcibr_pioerror: offset=0x%x, slot=0x%x, func=0x%x\n", + offset, slot, func)); + if (space != PCIIO_SPACE_NONE) { - if (slot != PCIIO_SLOT_NONE) - if (func != PCIIO_FUNC_NONE) + if (slot != PCIIO_SLOT_NONE) { + if (func != PCIIO_FUNC_NONE) { IOERROR_SETVALUE(ioe, widgetdev, pciio_widgetdev_create(slot,func)); - else + } + else { IOERROR_SETVALUE(ioe, widgetdev, pciio_widgetdev_create(slot,0)); - + } + } IOERROR_SETVALUE(ioe, busspace, space); IOERROR_SETVALUE(ioe, busaddr, offset); } @@ -1360,7 +1695,7 @@ if (space == PCIIO_SPACE_NONE) { printk("XIO Bus Error at %s\n" - "\taccess to XIO bus offset 0x%x\n" + "\taccess to XIO bus offset 0x%lx\n" "\tdoes not correspond to any PCI address\n", pcibr_soft->bs_name, bad_xaddr); @@ -1434,17 +1769,21 @@ */ BEM_ADD_STR("Raw info from Bridge/PCI layer:\n"); - if (bridge->b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) - pcibr_error_dump(pcibr_soft); + if (IS_PIC_SOFT(pcibr_soft)) { + if (bridge->p_int_status_64 & (picreg_t)BRIDGE_ISR_PCIBUS_PIOERR) + pcibr_error_dump(pcibr_soft); + } else { + if (bridge->b_int_status & (bridgereg_t)BRIDGE_ISR_PCIBUS_PIOERR) + pcibr_error_dump(pcibr_soft); + } BEM_ADD_SPC(raw_space); BEM_ADD_VAR(raw_paddr); if (IOERROR_FIELDVALID(ioe, widgetdev)) { - - slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, - widgetdev)); - func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, - widgetdev)); - if (slot < 8) { + short widdev; + IOERROR_GETVALUE(widdev, ioe, widgetdev); + slot = pciio_widgetdev_slot_get(widdev); + func = pciio_widgetdev_func_get(widdev); + if (slot < PCIBR_NUM_SLOTS(pcibr_soft)) { bridgereg_t device = bridge->b_device[slot].reg; BEM_ADD_VAR(slot); @@ -1472,11 +1811,12 @@ * Need a way to ensure we don't inadvertently clear some * other errors. */ - if (IOERROR_FIELDVALID(ioe, widgetdev)) - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get( - IOERROR_GETVALUE(ioe, widgetdev))); - + if (IOERROR_FIELDVALID(ioe, widgetdev)) { + short widdev; + IOERROR_GETVALUE(widdev, ioe, widgetdev); + pcibr_device_disable(pcibr_soft, + pciio_widgetdev_slot_get(widdev)); + } if (mode == MODE_DEVUSERERROR) pcibr_error_cleanup(pcibr_soft, error_code); } @@ -1490,8 +1830,6 @@ * and try to invoke the appropriate bus service to handle this. */ -#define BRIDGE_DMA_READ_ERROR (BRIDGE_ISR_RESP_XTLK_ERR|BRIDGE_ISR_XREAD_REQ_TIMEOUT) - int pcibr_dmard_error( pcibr_soft_t pcibr_soft, @@ -1511,7 +1849,11 @@ * Look up the address, in the bridge error registers, and * take appropriate action */ - ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid); + { + short tmp; + IOERROR_GETVALUE(tmp, ioe, widgetnum); + ASSERT(tmp == pcibr_soft->bs_xid); + } ASSERT(bridge); /* @@ -1540,10 +1882,11 @@ */ retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - if (retval != IOERROR_HANDLED) - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get( - IOERROR_GETVALUE(ioe,widgetdev))); + if (retval != IOERROR_HANDLED) { + short tmp; + IOERROR_GETVALUE(tmp, ioe, widgetdev); + pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp)); + } /* * Re-enable bridge to interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR @@ -1609,10 +1952,10 @@ retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); if (retval != IOERROR_HANDLED) { - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get( - IOERROR_GETVALUE(ioe, widgetdev))); + short tmp; + IOERROR_GETVALUE(tmp, ioe, widgetdev); + pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp)); } return retval; } @@ -1646,6 +1989,10 @@ pcibr_soft = (pcibr_soft_t) einfo; + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, + "pcibr_error_handler: pcibr_soft=0x%x, error_code=0x%x\n", + pcibr_soft, error_code)); + #ifdef EHE_ENABLE xconn_vhdl = pcibr_soft->bs_conn; pcibr_vhdl = pcibr_soft->bs_vhdl; @@ -1664,7 +2011,7 @@ #endif /* EHE_ENABLE */ #if DEBUG && ERROR_DEBUG - printk("%s: pcibr_error_handler\n", pcibr_soft->bs_name); + printk( "%s: pcibr_error_handler\n", pcibr_soft->bs_name); #endif ASSERT(pcibr_soft != NULL); @@ -1704,6 +2051,159 @@ } /* + * PIC has 2 busses under a single widget so pcibr_attach2 registers this + * wrapper function rather than pcibr_error_handler() for PIC. It's upto + * this wrapper to call pcibr_error_handler() with the correct pcibr_soft + * struct (ie. the pcibr_soft struct for the bus that saw the error). + * + * NOTE: this wrapper function is only registered for PIC ASICs and will + * only be called for a PIC + */ +int +pcibr_error_handler_wrapper( + error_handler_arg_t einfo, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioe) +{ + pcibr_soft_t pcibr_soft = (pcibr_soft_t) einfo; + int pio_retval = -1; + int dma_retval = -1; + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, + "pcibr_error_handler_wrapper: pcibr_soft=0x%x, " + "error_code=0x%x\n", pcibr_soft, error_code)); + + /* + * It is possible that both a IOECODE_PIO and a IOECODE_DMA, and both + * IOECODE_READ and IOECODE_WRITE could be set in error_code so we must + * process all. Since we are a wrapper for pcibr_error_handler(), and + * will be calling it several times within this routine, we turn off the + * error_code bits we don't want it to be processing during that call. + */ + /* + * If the error was a result of a PIO, we tell what bus on the PIC saw + * the error from the PIO address. + */ + +#if 0 + if (mode == MODE_DEVPROBE) + pio_retval = IOERROR_HANDLED; + else { +#endif + if (error_code & IOECODE_PIO) { + iopaddr_t bad_xaddr; + /* + * PIC bus0 PIO space 0x000000 - 0x7fffff or 0x40000000 - 0xbfffffff + * bus1 PIO space 0x800000 - 0xffffff or 0xc0000000 - 0x13fffffff + */ + IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr); + if ((bad_xaddr <= 0x7fffff) || + ((bad_xaddr >= 0x40000000) && (bad_xaddr <= 0xbfffffff))) { + /* bus 0 saw the error */ + pio_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft, + (error_code & ~IOECODE_DMA), mode, ioe); + } else if (((bad_xaddr >= 0x800000) && (bad_xaddr <= 0xffffff)) || + ((bad_xaddr >= 0xc0000000) && (bad_xaddr <= 0x13fffffff))) { + /* bus 1 saw the error */ + pcibr_soft = pcibr_soft->bs_peers_soft; + if (!pcibr_soft) { +#if DEBUG + printk(KERN_WARNING "pcibr_error_handler: " + "bs_peers_soft==NULL. bad_xaddr= 0x%x mode= 0x%x\n", + bad_xaddr, mode); +#endif + pio_retval = IOERROR_HANDLED; + } else + pio_retval= pcibr_error_handler((error_handler_arg_t)pcibr_soft, + (error_code & ~IOECODE_DMA), mode, ioe); + } else { + printk(KERN_WARNING "pcibr_error_handler_wrapper(): IOECODE_PIO: " + "saw an invalid pio address: 0x%lx\n", bad_xaddr); + pio_retval = IOERROR_UNHANDLED; + } + } +#if 0 + } /* MODE_DEVPROBE */ +#endif + + /* + * If the error was a result of a DMA Write, we tell what bus on the PIC + * saw the error by looking at tnum. + */ + if ((error_code & IOECODE_DMA) && (error_code & IOECODE_WRITE)) { + short tmp; + /* + * For DMA writes [X]Bridge encodes the TNUM field of a Xtalk + * packet like this: + * bits value + * 4:3 10b + * 2:0 device number + * + * BUT PIC needs the bus number so it does this: + * bits value + * 4:3 10b + * 2 busnumber + * 1:0 device number + * + * Pull out the bus number from `tnum' and reset the `widgetdev' + * since when hubiio_crb_error_handler() set `widgetdev' it had + * no idea if it was a PIC or a BRIDGE ASIC so it set it based + * off bits 2:0 + */ + IOERROR_GETVALUE(tmp, ioe, tnum); + IOERROR_SETVALUE(ioe, widgetdev, (tmp & 0x3)); + if ((tmp & 0x4) == 0) { + /* bus 0 saw the error. */ + dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft, + (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe); + } else { + /* bus 1 saw the error */ + pcibr_soft = pcibr_soft->bs_peers_soft; + dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft, + (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe); + } + } + + /* + * If the error was a result of a DMA READ, XXX ??? + */ + if ((error_code & IOECODE_DMA) && (error_code & IOECODE_READ)) { + /* + * A DMA Read error will result in a BRIDGE_ISR_RESP_XTLK_ERR + * or BRIDGE_ISR_BAD_XRESP_PKT bridge error interrupt which + * are fatal interrupts (ie. BRIDGE_ISR_ERROR_FATAL) causing + * pcibr_error_intr_handler() to panic the system. So is the + * error handler even going to get called??? It appears that + * the pcibr_dmard_error() attempts to clear the interrupts + * so pcibr_error_intr_handler() won't see them, but there + * appears to be nothing to prevent pcibr_error_intr_handler() + * from running before pcibr_dmard_error() has a chance to + * clear the interrupt. + * + * Since we'll be panicing anyways, don't bother handling the + * error for now until we can fix this race condition mentioned + * above. + */ + dma_retval = IOERROR_UNHANDLED; + } + + /* XXX: pcibr_error_handler() should probably do the same thing, it over- + * write it's return value as it processes the different "error_code"s. + */ + if ((pio_retval == -1) && (dma_retval == -1)) { + return IOERROR_BADERRORCODE; + } else if (dma_retval != IOERROR_HANDLED) { + return dma_retval; + } else if (pio_retval != IOERROR_HANDLED) { + return pio_retval; + } else { + return IOERROR_HANDLED; + } +} + + +/* * Reenable a device after handling the error. * This is called by the lower layers when they wish to be reenabled * after an error. @@ -1715,7 +2215,7 @@ pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); ASSERT(error_code & IOECODE_PIO); diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -85,11 +85,9 @@ if (hint) hint->ph_rrb_fixed = mask; -#if DEBUG else - printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_hints_fix_rrbs: pcibr_hints_get failed\n")); } void @@ -107,11 +105,9 @@ if (hint) hint->ph_host_slot[guest] = host + 1; -#if DEBUG else - printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_hints_dualslot: pcibr_hints_get failed\n")); } void @@ -122,11 +118,9 @@ if (hint) hint->ph_intr_bits = xxx_intr_bits; -#if DEBUG else - printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_hints_intr_bits: pcibr_hints_get failed\n")); } void @@ -145,11 +139,9 @@ if (hint) hint->ph_hands_off = 1; -#if DEBUG else - printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_hints_handsoff: pcibr_hints_get failed\n")); } void @@ -161,13 +153,11 @@ char sdname[16]; devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; - sprintf(sdname, "pci/%d", slot); + sprintf(sdname, "%s/%d", EDGE_LBL_PCI, slot); (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); if (pconn_vhdl == GRAPH_VERTEX_NONE) { -#if DEBUG - printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n" - "\t%p (seeking %s)\n", xconn_vhdl, sdname); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_hints_subdevs: hwgraph_path_create failed\n")); return; } hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); @@ -176,10 +166,8 @@ NEW(subdevp); if (!subdevp) { -#if DEBUG - printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n" - "\t%p\n", pconn_vhdl); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_hints_subdevs: subdev ptr alloc failed\n")); return; } *subdevp = subdevs; @@ -189,16 +177,12 @@ return; DEL(subdevp); if (ainfo == (arbitrary_info_t) NULL) { -#if DEBUG - printk("pcibr_hints_subdevs: null subdevs ptr at\n" - "\t%p\n", pconn_vhdl); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_hints_subdevs: null subdevs ptr\n")); return; } -#if DEBUG - printk("pcibr_subdevs_get: dup subdev add_LBL at\n" - "\t%p\n", pconn_vhdl); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, + "pcibr_subdevs_get: dup subdev add_LBL\n")); } *(uint64_t *) ainfo = subdevs; } diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c Wed Dec 31 16:00:00 1969 @@ -1,147 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef LATER - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - -void -idbg_pss_func(pcibr_info_h pcibr_infoh, int func) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; - qprintf("Per-slot Function Info\n"); - sprintf(name, "%v", pcibr_info->f_vertex); - qprintf("\tSlot Name : %s\n",name); - qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); - qprintf("Slot : %d ", pcibr_info->f_slot); - qprintf("Function : %d ", pcibr_info->f_func); - qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); - qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); - sprintf(name, "%v", pcibr_info->f_master); - qprintf("\tBus provider : %s\n",name); - qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); - qprintf("Error Handler : 0x%x Arg 0x%x\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); - for(win = 0 ; win < 6 ; win++) - qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", - win,pci_space[pcibr_info->f_window[win].w_space], - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_size); - - qprintf("\tRom base 0x%x size 0x%x\n", - pcibr_info->f_rbase,pcibr_info->f_rsize); - - qprintf("\tInterrupt Bit Map\n"); - qprintf("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - qprintf("\n"); -} - - -void -idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - - pss = &pcibr_soft->bs_slot[slot]; - qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); - qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - qprintf("\tHost Slot : %d\n",pss->host_slot); - sprintf(slot_conn_name, "%v", pss->slot_conn); - qprintf("\tSlot Conn : %s\n",slot_conn_name); - qprintf("\t#Functions : %d\n",pss->bss_ninfo); - for (func = 0; func < pss->bss_ninfo; func++) - idbg_pss_func(pss->bss_infos,func); - qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); - qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); - qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); - qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - pss->bss_d64_base, pss->bss_d64_flags, - pss->bss_d32_base, pss->bss_d32_flags); - - qprintf("\tExt ATEs active ? %s", - pss->bss_ext_ates_active ? "yes" : "no"); - qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); - qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); - - qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - -} - -int ips = 0; - -void -idbg_pss(pcibr_soft_t pcibr_soft) -{ - pciio_slot_t slot; - - - if (ips >= 0 && ips < 8) - idbg_pss_info(pcibr_soft,ips); - else if (ips < 0) - for (slot = 0; slot < 8; slot++) - idbg_pss_info(pcibr_soft,slot); - else - qprintf("Invalid ips %d\n",ips); -} -#endif /* LATER */ diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Mon Dec 30 14:16:56 2002 @@ -4,11 +4,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include -#include #include #include #include @@ -39,11 +38,11 @@ #define rmalloc atealloc #endif -unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); +unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); void pcibr_intr_free(pcibr_intr_t); void pcibr_setpciint(xtalk_intr_t); -int pcibr_intr_connect(pcibr_intr_t); +int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); void pcibr_intr_disconnect(pcibr_intr_t); devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); @@ -58,9 +57,9 @@ unsigned pcibr_intr_bits(pciio_info_t info, - pciio_intr_line_t lines) + pciio_intr_line_t lines, int nslots) { - pciio_slot_t slot = pciio_info_slot_get(info); + pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(info); unsigned bbits = 0; /* @@ -79,7 +78,7 @@ * 7 7 3 7 3 */ - if (slot < 8) { + if (slot < nslots) { if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C)) bbits |= 1 << slot; if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D)) @@ -165,32 +164,28 @@ * to check if a specific Bridge b_int_status bit is set, and if so, * cause the setting of the corresponding interrupt bit. * - * On a XBridge (IP35), we do this by writing the appropriate Bridge Force + * On a XBridge (SN1) and PIC (SN2), we do this by writing the appropriate Bridge Force * Interrupt register. */ void -pcibr_force_interrupt(pcibr_intr_wrap_t wrap) +pcibr_force_interrupt(pcibr_intr_t intr) { unsigned bit; - pcibr_soft_t pcibr_soft = wrap->iw_soft; + unsigned bits; + pcibr_soft_t pcibr_soft = intr->bi_soft; bridge_t *bridge = pcibr_soft->bs_base; - cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); - bit = wrap->iw_intr; + bits = intr->bi_ibits; + for (bit = 0; bit < 8; bit++) { + if (bits & (1 << bit)) { - if (pcibr_soft->bs_xbridge) { - bridge->b_force_pin[bit].intr = 1; - } else if ((1 << bit) & *wrap->iw_stat) { - cpuid_t cpu; - unsigned intr_bit; - xtalk_intr_t xtalk_intr = - pcibr_soft->bs_intr[bit].bsi_xtalk_intr; - - intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); - cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); -#if defined(CONFIG_IA64_SGI_SN1) - REMOTE_CPU_SEND_INTR(cpu, intr_bit); -#endif + PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl, + "pcibr_force_interrupt: bit=0x%x\n", bit)); + + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { + bridge->b_force_pin[bit].intr = 1; + } + } } } @@ -202,12 +197,11 @@ devfs_handle_t owner_dev) { pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pcibr_info->f_slot; + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; bridge_t *bridge = pcibr_soft->bs_base; int is_threaded = 0; - int thread_swlevel; xtalk_intr_t *xtalk_intr_p; pcibr_intr_t *pcibr_intr_p; @@ -222,41 +216,32 @@ pcibr_intr_list_t intr_list; bridgereg_t int_dev; -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_alloc\n" - "%v:%s%s%s%s%s\n", - owner_dev, pconn_vhdl, - !(lines & 15) ? " No INTs?" : "", - lines & 1 ? " INTA" : "", - lines & 2 ? " INTB" : "", - lines & 4 ? " INTC" : "", - lines & 8 ? " INTD" : ""); -#endif + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "pcibr_intr_alloc: %s%s%s%s%s\n", + !(lines & 15) ? " No INTs?" : "", + lines & 1 ? " INTA" : "", + lines & 2 ? " INTB" : "", + lines & 4 ? " INTC" : "", + lines & 8 ? " INTD" : "")); NEW(pcibr_intr); if (!pcibr_intr) return NULL; - if (dev_desc) { - cpuid_t intr_target_from_desc(device_desc_t, int); - } else { - extern int default_intr_pri; - - is_threaded = 1; /* PCI interrupts are threaded, by default */ - thread_swlevel = default_intr_pri; - } - pcibr_intr->bi_dev = pconn_vhdl; pcibr_intr->bi_lines = lines; pcibr_intr->bi_soft = pcibr_soft; pcibr_intr->bi_ibits = 0; /* bits will be added below */ + pcibr_intr->bi_func = 0; /* unset until connect */ + pcibr_intr->bi_arg = 0; /* unset until connect */ pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; pcibr_intr->bi_mustruncpu = CPU_NONE; pcibr_intr->bi_ibuf.ib_in = 0; pcibr_intr->bi_ibuf.ib_out = 0; mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); - - pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); + pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines, + PCIBR_NUM_SLOTS(pcibr_soft)); /* @@ -265,9 +250,8 @@ * to, and make sure there are xtalk resources * allocated for it. */ -#if DEBUG && INTR_DEBUG - printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "pcibr_intr_alloc: pcibr_int_bits: 0x%x\n", pcibr_int_bits)); for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) { if (pcibr_int_bits & (1 << pcibr_int_bit)) { xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; @@ -282,10 +266,9 @@ * ordering problems with DMA, completion interrupts, and error * interrupts. (Use of xconn_vhdl forces this.) * - * 2) On IP35, addressing constraints on IP35 and Bridge force + * 2) On SN1, addressing constraints on SN1 and Bridge force * us to use a single PI number for all interrupts from a - * single Bridge. (IP35-specific code forces this, and we - * verify in pcibr_setwidint.) + * single Bridge. (SN1-specific code forces this). */ /* @@ -298,9 +281,9 @@ */ xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, owner_dev); -#if DEBUG && INTR_DEBUG - printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); -#endif + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "pcibr_intr_alloc: xtalk_intr=0x%x\n", xtalk_intr)); /* both an assert and a runtime check on this: * we need to check in non-DEBUG kernels, and @@ -338,10 +321,9 @@ int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit); bridge->b_int_device = int_dev; /* XXXMP */ -#if DEBUG && INTR_DEBUG - printk("%v: bridge intr bit %d clears my wrb\n", - pconn_vhdl, pcibr_int_bit); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "bridge intr bit %d clears my wrb\n", + pcibr_int_bit)); } else { /* someone else got one allocated first; * free the one we just created, and @@ -373,25 +355,17 @@ intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); intr_list_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; -#if DEBUG && INTR_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("0x%x: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#else - printk("%v: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#endif -#endif + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "Bridge bit 0x%x wrap=0x%x\n", pcibr_int_bit, + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap)); if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* we are the first interrupt on this bridge bit. */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "INT 0x%x (bridge bit %d) allocated [FIRST]\n", + pcibr_int_bits, pcibr_int_bit)); continue; } intr_list = *intr_list_p; @@ -402,10 +376,9 @@ * don't need our intr_entry. */ DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased first\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "INT 0x%x (bridge bit %d) replaces erased first\n", + pcibr_int_bits, pcibr_int_bit)); continue; } intr_list_p = &intr_list->il_next; @@ -413,10 +386,9 @@ /* we are the new second interrupt on this bit. */ pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "INT 0x%x (bridge bit %d) is new SECOND\n", + pcibr_int_bits, pcibr_int_bit)); continue; } while (1) { @@ -427,20 +399,19 @@ * don't need our intr_entry. */ DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "INT 0x%x (bridge bit %d) replaces erase Nth\n", + pcibr_int_bits, pcibr_int_bit)); break; } intr_list_p = &intr_list->il_next; if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { /* entry appended to share list */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, + "INT 0x%x (bridge bit %d) is new Nth\n", + pcibr_int_bits, pcibr_int_bit)); break; } /* step to next record in chain @@ -479,10 +450,11 @@ if (compare_and_swap_ptr((void **) &intr_list->il_intr, pcibr_intr, NULL)) { -#if DEBUG && INTR_DEBUG - printk("%s: cleared a handler from bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, + pcibr_intr->bi_dev, + "pcibr_intr_free: cleared hdlr from bit 0x%x\n", + pcibr_int_bit)); } /* If this interrupt line is not being shared between multiple * devices release the xtalk interrupt resources. @@ -515,34 +487,49 @@ void pcibr_setpciint(xtalk_intr_t xtalk_intr) { - iopaddr_t addr = xtalk_intr_addr_get(xtalk_intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(xtalk_intr); - bridgereg_t *int_addr = (bridgereg_t *) - xtalk_intr_sfarg_get(xtalk_intr); - - *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); + iopaddr_t addr; + xtalk_intr_vector_t vect; + devfs_handle_t vhdl; + bridge_t *bridge; + + addr = xtalk_intr_addr_get(xtalk_intr); + vect = xtalk_intr_vector_get(xtalk_intr); + vhdl = xtalk_intr_dev_get(xtalk_intr); + bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0); + + if (is_pic(bridge)) { + picreg_t *int_addr; + int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr); + *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) | + (PIC_INT_ADDR_HOST & addr)); + } else { + bridgereg_t *int_addr; + int_addr = (bridgereg_t *)xtalk_intr_sfarg_get(xtalk_intr); + *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | + (BRIDGE_INT_ADDR_FLD & vect)); + } } /*ARGSUSED */ int -pcibr_intr_connect(pcibr_intr_t pcibr_intr) +pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg) { pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; - bridgereg_t b_int_enable; + uint64_t int_enable; unsigned long s; if (pcibr_intr == NULL) return -1; -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_connect\n", - pcibr_intr->bi_dev); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, + "pcibr_intr_connect: intr_func=0x%x\n", + pcibr_intr)); + pcibr_intr->bi_func = intr_func; + pcibr_intr->bi_arg = intr_arg; *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; /* @@ -553,9 +540,12 @@ */ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) { + pcibr_intr_wrap_t intr_wrap; xtalk_intr_t xtalk_intr; + void *int_addr; xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; + intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; /* * If this interrupt line is being shared and the connect has @@ -569,21 +559,43 @@ * Use the pcibr wrapper function to handle all Bridge interrupts * regardless of whether the interrupt line is shared or not. */ - xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *)&(bridge->b_int_addr[pcibr_int_bit].addr)); + if (IS_PIC_SOFT(pcibr_soft)) + int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]); + else + int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr); + + xtalk_intr_connect(xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap, + (xtalk_intr_setfunc_t) pcibr_setpciint, + (void *)int_addr); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; -#if DEBUG && INTR_DEBUG - printk("%v bridge bit %d wrapper connected\n", - pcibr_intr->bi_dev, pcibr_int_bit); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, + "pcibr_setpciint: int_addr=0x%x, *int_addr=0x%x, " + "pcibr_int_bit=0x%x\n", int_addr, + (is_pic(bridge) ? + *(picreg_t *)int_addr : *(bridgereg_t *)int_addr), + pcibr_int_bit)); } - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable |= pcibr_int_bits; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); + + /* PIC WAR. PV# 854697 + * On PIC we must write 64-bit MMRs with 64-bit stores + */ + s = pcibr_lock(pcibr_soft); + if (IS_PIC_SOFT(pcibr_soft) && + PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { + int_enable = bridge->p_int_enable_64; + int_enable |= pcibr_int_bits; + bridge->p_int_enable_64 = int_enable; + } else { + bridgereg_t int_enable; + + int_enable = bridge->b_int_enable; + int_enable |= pcibr_int_bits; + bridge->b_int_enable = int_enable; + } + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcibr_unlock(pcibr_soft, s); return 0; } @@ -596,13 +608,15 @@ bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; - bridgereg_t b_int_enable; + pcibr_intr_wrap_t intr_wrap; + uint64_t int_enable; unsigned long s; /* Stop calling the function. Now. */ *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; - + pcibr_intr->bi_func = 0; + pcibr_intr->bi_arg = 0; /* * For each PCI interrupt line requested, figure * out which Bridge PCI Interrupt Line it maps @@ -619,15 +633,30 @@ if (!pcibr_int_bits) return; + /* PIC WAR. PV# 854697 + * On PIC we must write 64-bit MMRs with 64-bit stores + */ s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~pcibr_int_bits; - bridge->b_int_enable = b_int_enable; + if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { + int_enable = bridge->p_int_enable_64; + int_enable &= ~pcibr_int_bits; + bridge->p_int_enable_64 = int_enable; + } else { + int_enable = (uint64_t)bridge->b_int_enable; + int_enable &= ~pcibr_int_bits; + bridge->b_int_enable = (bridgereg_t)int_enable; + } bridge->b_wid_tflush; /* wait until Bridge PIO complete */ pcibr_unlock(pcibr_soft, s); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, + "pcibr_intr_disconnect: disabled int_bits=0x%x\n", + pcibr_int_bits)); + for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) { + void *int_addr; + /* if the interrupt line is now shared, * do not disconnect it. */ @@ -637,10 +666,9 @@ xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; -#if DEBUG && INTR_DEBUG - printk("%s: xtalk disconnect done for Bridge bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, + "pcibr_intr_disconnect: disconnect int_bits=0x%x\n", + pcibr_int_bits)); /* if we are sharing the interrupt line, * connect us up; this closes the hole @@ -650,9 +678,22 @@ if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; + intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; + if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) + continue; + + if (IS_PIC_SOFT(pcibr_soft)) + int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]); + else + int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr); + xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, + pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t)pcibr_setpciint, - (void *) &(bridge->b_int_addr[pcibr_int_bit].addr)); + (void *)pcibr_int_bit); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, + "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n", + pcibr_int_bit)); } } @@ -729,6 +770,7 @@ bridge->b_wid_int_upper = NEW_b_wid_int_upper; bridge->b_wid_int_lower = NEW_b_wid_int_lower; bridge->b_int_host_err = vect; + } /* @@ -752,6 +794,9 @@ XTALK_ADDR_TO_UPPER(addr)); bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); bridge->b_int_host_err = vect; +printk("pcibr_xintr_preset: b_wid_int_upper 0x%lx b_wid_int_lower 0x%lx b_int_host_err 0x%x\n", + ( (0x000F0000 & (targ << 16)) | XTALK_ADDR_TO_UPPER(addr)), + XTALK_ADDR_TO_LOWER(addr), vect); /* turn on all interrupts except * the PCI interrupt requests, @@ -794,12 +839,37 @@ { pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; reg_p wrbf; + intr_func_t func; pcibr_intr_t intr; pcibr_intr_list_t list; int clearit; int do_nonthreaded = 1; int is_threaded = 0; int x = 0; + pcibr_soft_t pcibr_soft = wrap->iw_soft; + bridge_t *bridge = pcibr_soft->bs_base; + uint64_t p_enable = pcibr_soft->bs_int_enable; + int bit = wrap->iw_ibit; + + /* + * PIC WAR. PV#855272 + * Early attempt at a workaround for the runaway + * interrupt problem. Briefly disable the enable bit for + * this device. + */ + if (IS_PIC_SOFT(pcibr_soft) && + PCIBR_WAR_ENABLED(PV855272, pcibr_soft)) { + unsigned s; + + /* disable-enable interrupts for this bridge pin */ + + p_enable &= ~(1 << bit); + s = pcibr_lock(pcibr_soft); + bridge->p_int_enable_64 = p_enable; + p_enable |= (1 << bit); + bridge->p_int_enable_64 = p_enable; + pcibr_unlock(pcibr_soft, s); + } /* * If any handler is still running from a previous interrupt @@ -821,35 +891,31 @@ clearit = 1; while (do_nonthreaded) { for (list = wrap->iw_list; list != NULL; list = list->il_next) { - if ((intr = list->il_intr) && - (intr->bi_flags & PCIIO_INTR_CONNECTED)) { + if ((intr = list->il_intr) && (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - /* - * This device may have initiated write - * requests since the bridge last saw - * an edge on this interrupt input; flushing - * the buffer prior to invoking the handler - * should help but may not be sufficient if we - * get more requests after the flush, followed - * by the card deciding it wants service, before - * the interrupt handler checks to see if things need - * to be done. - * - * There is a similar race condition if - * an interrupt handler loops around and - * notices further service is required. - * Perhaps we need to have an explicit - * call that interrupt handlers need to - * do between noticing that DMA to memory - * has completed, but before observing the - * contents of memory? - */ - - if ((do_nonthreaded) && (!is_threaded)) { - /* Non-threaded. - * Call the interrupt handler at interrupt level - */ + /* + * This device may have initiated write + * requests since the bridge last saw + * an edge on this interrupt input; flushing + * the buffer prior to invoking the handler + * should help but may not be sufficient if we + * get more requests after the flush, followed + * by the card deciding it wants service, before + * the interrupt handler checks to see if things need + * to be done. + * + * There is a similar race condition if + * an interrupt handler loops around and + * notices further service is required. + * Perhaps we need to have an explicit + * call that interrupt handlers need to + * do between noticing that DMA to memory + * has completed, but before observing the + * contents of memory? + */ + if ((do_nonthreaded) && (!is_threaded)) { + /* Non-threaded - Call the interrupt handler at interrupt level */ /* Only need to flush write buffers if sharing */ if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { @@ -864,21 +930,23 @@ (void *)list->il_intr->bi_dev, (long) wrbf); #endif } + func = intr->bi_func; + if ( func ) + func(intr->bi_arg); } - clearit = 0; } } + do_nonthreaded = 0; - do_nonthreaded = 0; - /* - * If the non-threaded handler was the last to complete, - * (i.e., no threaded handlers still running) force an - * interrupt to avoid a potential deadlock situation. - */ - if (wrap->iw_hdlrcnt == 0) { - pcibr_force_interrupt(wrap); - } + /* + * If the non-threaded handler was the last to complete, + * (i.e., no threaded handlers still running) force an + * interrupt to avoid a potential deadlock situation. + */ + if (wrap->iw_hdlrcnt == 0) { + pcibr_force_interrupt(wrap); + } } /* If there were no handlers, @@ -892,14 +960,24 @@ if (clearit) { pcibr_soft_t pcibr_soft = wrap->iw_soft; bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t b_int_enable; - bridgereg_t mask = 1 << wrap->iw_intr; + bridgereg_t int_enable; + bridgereg_t mask = 1 << wrap->iw_ibit; unsigned long s; + /* PIC BRINUGP WAR (PV# 854697): + * On PIC we must write 64-bit MMRs with 64-bit stores + */ s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~mask; - bridge->b_int_enable = b_int_enable; + if (IS_PIC_SOFT(pcibr_soft) && + PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { + int_enable = bridge->p_int_enable_64; + int_enable &= ~mask; + bridge->p_int_enable_64 = int_enable; + } else { + int_enable = (uint64_t)bridge->b_int_enable; + int_enable &= ~mask; + bridge->b_int_enable = (bridgereg_t)int_enable; + } bridge->b_wid_tflush; /* wait until Bridge PIO complete */ pcibr_unlock(pcibr_soft, s); return; diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -33,259 +33,478 @@ void do_pcibr_rrb_clear(bridge_t *, int); void do_pcibr_rrb_flush(bridge_t *, int); -int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); +int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t, int); int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); -int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); -int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); +int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int, int); +int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int, int); +void do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t); -void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); +void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); int pcibr_wrb_flush(devfs_handle_t); int pcibr_rrb_alloc(devfs_handle_t, int *, int *); int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); -int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); void pcibr_rrb_flush(devfs_handle_t); int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); -/* - * RRB Management - */ - -#define LSBIT(word) ((word) &~ ((word)-1)) - -void -do_pcibr_rrb_clear(bridge_t *bridge, int rrb) -{ - bridgereg_t status; - - /* bridge_lock must be held; - * this RRB must be disabled. - */ - - /* wait until RRB has no outstanduing XIO packets. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } -} - -void -do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) -{ - reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; - bridgereg_t rrbv; - int shft = 4 * (rrbn >> 1); - unsigned ebit = BRIDGE_RRB_EN << shft; - - rrbv = *rrbp; - if (rrbv & ebit) - *rrbp = rrbv & ~ebit; - - do_pcibr_rrb_clear(bridge, rrbn); - - if (rrbv & ebit) - *rrbp = rrbv; -} +void pcibr_rrb_debug(char *, pcibr_soft_t); /* - * pcibr_rrb_count_valid: count how many RRBs are - * marked valid for the specified PCI slot on this - * bridge. - * - * NOTE: The "slot" parameter for all pcibr_rrb - * management routines must include the "virtual" - * bit; when manageing both the normal and the - * virtual channel, separate calls to these - * routines must be made. To denote the virtual - * channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot - * number. - * - * IMPL NOTE: The obvious algorithm is to iterate - * through the RRB fields, incrementing a count if - * the RRB is valid and matches the slot. However, - * it is much simpler to use an algorithm derived - * from the "partitioned add" idea. First, XOR in a - * pattern such that the fields that match this - * slot come up "all ones" and all other fields - * have zeros in the mismatching bits. Then AND - * together the bits in the field, so we end up - * with one bit turned on for each field that - * matched. Now we need to count these bits. This - * can be done either with a series of shift/add - * instructions or by using "tmp % 15"; I expect - * that the cascaded shift/add will be faster. - */ - + * RRB Management + * + * All the do_pcibr_rrb_ routines manipulate the Read Response Buffer (rrb) + * registers within the Bridge. Two 32 registers (b_rrb_map[2] also known + * as the b_even_resp & b_odd_resp registers) are used to allocate the 16 + * rrbs to devices. The b_even_resp register represents even num devices, + * and b_odd_resp represent odd number devices. Each rrb is represented by + * 4-bits within a register. + * BRIDGE & XBRIDGE: 1 enable bit, 1 virtual channel bit, 2 device bits + * PIC: 1 enable bit, 2 virtual channel bits, 1 device bit + * PIC has 4 devices per bus, and 4 virtual channels (1 normal & 3 virtual) + * per device. BRIDGE & XBRIDGE have 8 devices per bus and 2 virtual + * channels (1 normal & 1 virtual) per device. See the BRIDGE and PIC ASIC + * Programmers Reference guides for more information. + */ + +#define RRB_MASK (0xf) /* mask a single rrb within reg */ +#define RRB_SIZE (4) /* sizeof rrb within reg (bits) */ + +#define RRB_ENABLE_BIT(bridge) (0x8) /* [BRIDGE | PIC]_RRB_EN */ +#define NUM_PDEV_BITS(bridge) (is_pic((bridge)) ? 1 : 2) +#define NUM_VDEV_BITS(bridge) (is_pic((bridge)) ? 2 : 1) +#define NUMBER_VCHANNELS(bridge) (is_pic((bridge)) ? 4 : 2) +#define SLOT_2_PDEV(bridge, slot) ((slot) >> 1) +#define SLOT_2_RRB_REG(bridge, slot) ((slot) & 0x1) + +/* validate that the slot and virtual channel are valid for a given bridge */ +#define VALIDATE_SLOT_n_VCHAN(bridge, s, v) \ + (is_pic((bridge)) ? \ + (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) : \ + (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)7)) && (((v) >= 0) && ((v) <= 1))) ? 1 : 0)) + +/* + * Count how many RRBs are marked valid for the specified PCI slot + * and virtual channel. Return the count. + */ int do_pcibr_rrb_count_valid(bridge_t *bridge, - pciio_slot_t slot) + pciio_slot_t slot, + int vchan) { - bridgereg_t tmp; + bridgereg_t tmp; + uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; + int rrb_index, cnt=0; + + if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) { + printk(KERN_WARNING "do_pcibr_rrb_count_valid() invalid slot/vchan [%d/%d]\n", slot, vchan); + return 0; + } + + enable_bit = RRB_ENABLE_BIT(bridge); + vchan_bits = vchan << NUM_PDEV_BITS(bridge); + pdev_bits = SLOT_2_PDEV(bridge, slot); + rrb_bits = enable_bit | vchan_bits | pdev_bits; + + if ( is_pic(bridge) ) { + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); + } else { + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + } - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp ^= 0x11111111 * (7 - slot / 2); - tmp &= (0xCCCCCCCC & tmp) >> 2; - tmp &= (0x22222222 & tmp) >> 1; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; + for (rrb_index = 0; rrb_index < 8; rrb_index++) { + if ((tmp & RRB_MASK) == rrb_bits) + cnt++; + tmp = (tmp >> RRB_SIZE); + } + return cnt; } - -/* - * do_pcibr_rrb_count_avail: count how many RRBs are - * available to be allocated for the specified slot. - * - * IMPL NOTE: similar to the above, except we are - * just counting how many fields have the valid bit - * turned off. - */ + + +/* + * Count how many RRBs are available to be allocated to the specified + * slot. Return the count. + */ int do_pcibr_rrb_count_avail(bridge_t *bridge, pciio_slot_t slot) { - bridgereg_t tmp; + bridgereg_t tmp; + uint16_t enable_bit; + int rrb_index, cnt=0; + + if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, 0)) { + printk(KERN_WARNING "do_pcibr_rrb_count_avail() invalid slot/vchan"); + return 0; + } + + enable_bit = RRB_ENABLE_BIT(bridge); + + if ( is_pic(bridge) ) { + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); + } else { + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + } - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~tmp) >> 3; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; + for (rrb_index = 0; rrb_index < 8; rrb_index++) { + if ((tmp & enable_bit) != enable_bit) + cnt++; + tmp = (tmp >> RRB_SIZE); + } + return cnt; } - -/* - * do_pcibr_rrb_alloc: allocate some additional RRBs - * for the specified slot. Returns -1 if there were - * insufficient free RRBs to satisfy the request, - * or 0 if the request was fulfilled. - * - * Note that if a request can be partially filled, - * it will be, even if we return failure. - * - * IMPL NOTE: again we avoid iterating across all - * the RRBs; instead, we form up a word containing - * one bit for each free RRB, then peel the bits - * off from the low end. - */ + + +/* + * Allocate some additional RRBs for the specified slot and the specified + * virtual channel. Returns -1 if there were insufficient free RRBs to + * satisfy the request, or 0 if the request was fulfilled. + * + * Note that if a request can be partially filled, it will be, even if + * we return failure. + */ int do_pcibr_rrb_alloc(bridge_t *bridge, pciio_slot_t slot, + int vchan, int more) { - int rv = 0; - bridgereg_t reg, tmp, bit; + bridgereg_t reg, tmp = (bridgereg_t)0; + uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; + int rrb_index; + + if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) { + printk(KERN_WARNING "do_pcibr_rrb_alloc() invalid slot/vchan"); + return -1; + } + + enable_bit = RRB_ENABLE_BIT(bridge); + vchan_bits = vchan << NUM_PDEV_BITS(bridge); + pdev_bits = SLOT_2_PDEV(bridge, slot); + rrb_bits = enable_bit | vchan_bits | pdev_bits; + + if ( is_pic(bridge) ) { + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + reg = tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); + } else { + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + } + + for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) { + if ((tmp & enable_bit) != enable_bit) { + /* clear the rrb and OR in the new rrb into 'reg' */ + reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index)); + reg = reg | (rrb_bits << (RRB_SIZE * rrb_index)); + more--; + } + tmp = (tmp >> RRB_SIZE); + } - reg = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~reg) >> 3; - while (more-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; + if ( is_pic(bridge) ) { + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg; + } else { + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; } - tmp &= ~bit; - reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2))); } - bridge->b_rrb_map[slot & 1].reg = reg; - return rv; + return (more ? -1 : 0); } - -/* - * do_pcibr_rrb_free: release some of the RRBs that - * have been allocated for the specified - * slot. Returns zero for success, or negative if - * it was unable to free that many RRBs. - * - * IMPL NOTE: We form up a bit for each RRB - * allocated to the slot, aligned with the VALID - * bitfield this time; then we peel bits off one at - * a time, releasing the corresponding RRB. - */ + + +/* + * Release some of the RRBs that have been allocated for the specified + * slot. Returns zero for success, or negative if it was unable to free + * that many RRBs. + * + * Note that if a request can be partially fulfilled, it will be, even + * if we return failure. + */ int do_pcibr_rrb_free(bridge_t *bridge, pciio_slot_t slot, + int vchan, int less) { - int rv = 0; - bridgereg_t reg, tmp, clr, bit; - int i; + bridgereg_t reg, tmp = (bridgereg_t)0, clr = 0; + uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; + int rrb_index; + + if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) { + printk(KERN_WARNING "do_pcibr_rrb_free() invalid slot/vchan"); + return -1; + } + + enable_bit = RRB_ENABLE_BIT(bridge); + vchan_bits = vchan << NUM_PDEV_BITS(bridge); + pdev_bits = SLOT_2_PDEV(bridge, slot); + rrb_bits = enable_bit | vchan_bits | pdev_bits; + + if ( is_pic(bridge) ) { + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + reg = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); + } else { + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + } + } + + for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) { + if ((tmp & RRB_MASK) == rrb_bits) { + /* + * the old do_pcibr_rrb_free() code only clears the enable bit + * but I say we should clear the whole rrb (ie): + * reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index)); + * But to be compatable with old code we'll only clear enable. + */ + reg = reg & ~(RRB_ENABLE_BIT(bridge) << (RRB_SIZE * rrb_index)); + clr = clr | (enable_bit << (RRB_SIZE * rrb_index)); + less--; + } + tmp = (tmp >> RRB_SIZE); + } - clr = 0; - reg = bridge->b_rrb_map[slot & 1].reg; + if ( is_pic(bridge) ) { + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg; + } else { + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; + } + } - /* This needs to be done otherwise the rrb's on the virtual channel - * for this slot won't be freed !! + /* call do_pcibr_rrb_clear() for all the rrbs we've freed */ + for (rrb_index = 0; rrb_index < 8; rrb_index++) { + int evn_odd = SLOT_2_RRB_REG(bridge, slot); + if (clr & (enable_bit << (RRB_SIZE * rrb_index))) + do_pcibr_rrb_clear(bridge, (2 * rrb_index) + evn_odd); + } + + return (less ? -1 : 0); +} + + +/* + * free all the rrbs (both the normal and virtual channels) for the + * specified slot. + */ +void +do_pcibr_rrb_free_all(pcibr_soft_t pcibr_soft, + bridge_t *bridge, + pciio_slot_t slot) +{ + int vchan; + int vchan_total = NUMBER_VCHANNELS(bridge); + + /* pretend we own all 8 rrbs and just ignore the return value */ + for (vchan = 0; vchan < vchan_total; vchan++) { + (void)do_pcibr_rrb_free(bridge, slot, vchan, 8); + pcibr_soft->bs_rrb_valid[slot][vchan] = 0; + } +} + + +/* + * Wait for the the specified rrb to have no outstanding XIO pkts + * and for all data to be drained. Mark the rrb as no longer being + * valid. + */ +void +do_pcibr_rrb_clear(bridge_t *bridge, int rrb) +{ + bridgereg_t status; + + /* bridge_lock must be held; + * this RRB must be disabled. */ - tmp = reg & 0xbbbbbbbb; - tmp ^= (0x11111111 * (7 - slot / 2)); - tmp &= (0x33333333 & tmp) << 2; - tmp &= (0x44444444 & tmp) << 1; - while (less-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; + if ( is_pic(bridge) ) { + /* wait until RRB has no outstanduing XIO packets. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + + /* if the RRB has data, drain it. */ + if (status & BRIDGE_RRB_VALID(rrb)) { + bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); + + /* wait until RRB is no longer valid. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + } + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_INUSE(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + + /* if the RRB has data, drain it. */ + if (status & BRIDGE_RRB_VALID(rrb)) { + BRIDGE_REG_SET32((&bridge->b_resp_clear)) = __swab32(BRIDGE_RRB_CLEAR(rrb)); + + /* wait until RRB is no longer valid. */ + while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_VALID(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + } + } else { /* io_get_sh_swapper(NASID_GET(bridge)) */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + + /* if the RRB has data, drain it. */ + if (status & BRIDGE_RRB_VALID(rrb)) { + bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); + /* wait until RRB is no longer valid. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } + } + } + } +} + + +/* + * Flush the specified rrb by calling do_pcibr_rrb_clear(). This + * routine is just a wrapper to make sure the rrb is disabled + * before calling do_pcibr_rrb_clear(). + */ +void +do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) +{ + reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; + bridgereg_t rrbv; + int shft = (RRB_SIZE * (rrbn >> 1)); + unsigned long ebit = RRB_ENABLE_BIT(bridge) << shft; + + if ( is_pic(bridge) ) { + rrbv = *rrbp; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + rrbv = BRIDGE_REG_GET32((&rrbp)); + } else { + rrbv = *rrbp; + } + } + + if (rrbv & ebit) { + if ( is_pic(bridge) ) { + *rrbp = rrbv & ~ebit; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&rrbp)) = __swab32((rrbv & ~ebit)); + } else { + *rrbp = rrbv & ~ebit; + } } - tmp &= ~bit; - reg &= ~bit; - clr |= bit; } - bridge->b_rrb_map[slot & 1].reg = reg; - for (i = 0; i < 8; i++) - if (clr & (8 << (4 * i))) - do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1)); + do_pcibr_rrb_clear(bridge, rrbn); - return rv; + if (rrbv & ebit) { + if ( is_pic(bridge) ) { + *rrbp = rrbv; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + BRIDGE_REG_SET32((&rrbp)) = __swab32(rrbv); + } else { + *rrbp = rrbv; + } + } + } } + void do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, int slot, + int vchan, int more_rrbs) { bridge_t *bridge = pcibr_soft->bs_base; int got; for (got = 0; got < more_rrbs; ++got) { - if (pcibr_soft->bs_rrb_res[slot & 7] > 0) - pcibr_soft->bs_rrb_res[slot & 7]--; + if (pcibr_soft->bs_rrb_res[slot] > 0) + pcibr_soft->bs_rrb_res[slot]--; else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) pcibr_soft->bs_rrb_avail[slot & 1]--; else break; - if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0) + if (do_pcibr_rrb_alloc(bridge, slot, vchan, 1) < 0) break; -#if PCIBR_RRB_DEBUG - printk("do_pcibr_rrb_autoalloc: add one to slot %d%s\n", - slot & 7, slot & 8 ? "v" : ""); -#endif - pcibr_soft->bs_rrb_valid[slot]++; - } -#if PCIBR_RRB_DEBUG - printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (slot = 0; slot < 8; ++slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif + + pcibr_soft->bs_rrb_valid[slot][vchan]++; + } + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, + "do_pcibr_rrb_autoalloc: added %d (of %d requested) RRBs " + "to slot %d, vchan %d\n", got, more_rrbs, + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan)); + + pcibr_rrb_debug("do_pcibr_rrb_autoalloc", pcibr_soft); } + +/* + * Flush all the rrb's assigned to the specified connection point. + */ +void +pcibr_rrb_flush(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info); + pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + + bridgereg_t tmp; + uint16_t enable_bit, pdev_bits, rrb_bits, rrb_mask; + int rrb_index; + unsigned long s; + + enable_bit = RRB_ENABLE_BIT(bridge); + pdev_bits = SLOT_2_PDEV(bridge, slot); + rrb_bits = enable_bit | pdev_bits; + rrb_mask = enable_bit | ((NUM_PDEV_BITS(bridge) << 1) - 1); + + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + + s = pcibr_lock(pcibr_soft); + for (rrb_index = 0; rrb_index < 8; rrb_index++) { + int evn_odd = SLOT_2_RRB_REG(bridge, slot); + if ((tmp & rrb_mask) == rrb_bits) + do_pcibr_rrb_flush(bridge, (2 * rrb_index) + evn_odd); + tmp = (tmp >> RRB_SIZE); + } + pcibr_unlock(pcibr_soft, s); +} + + /* * Device driver interface to flush the write buffers for a specified * device hanging off the bridge. @@ -294,14 +513,24 @@ pcibr_wrb_flush(devfs_handle_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; volatile bridgereg_t *wrb_flush; wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); - while (*wrb_flush); - + if ( IS_PIC_SOFT(pcibr_soft) ) { + while (*wrb_flush) + ; + } + else { + if (io_get_sh_swapper(NASID_GET(bridge))) { + while (BRIDGE_REG_GET32((wrb_flush))); + } else { + while (*wrb_flush) + ; + } + } return(0); } @@ -322,7 +551,7 @@ int *count_vchan1) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; int desired_vchan0; @@ -335,7 +564,9 @@ int final_vchan1; int avail_rrbs; int res_rrbs; - unsigned long s; + int vchan_total; + int vchan; + unsigned long s; int error; /* @@ -352,20 +583,21 @@ s = pcibr_lock(pcibr_soft); + vchan_total = NUMBER_VCHANNELS(bridge); + /* Save the boot-time RRB configuration for this slot */ - if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] < 0) { - pcibr_soft->bs_rrb_valid_dflt[pciio_slot] = - pcibr_soft->bs_rrb_valid[pciio_slot]; - pcibr_soft->bs_rrb_valid_dflt[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][VCHAN0] < 0) { + for (vchan = 0; vchan < vchan_total; vchan++) + pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] = + pcibr_soft->bs_rrb_valid[pciio_slot][vchan]; pcibr_soft->bs_rrb_res_dflt[pciio_slot] = pcibr_soft->bs_rrb_res[pciio_slot]; } /* How many RRBs do we own? */ - orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; - orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0]; + orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1]; /* How many RRBs do we want? */ desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; @@ -417,14 +649,14 @@ /* Commit the allocations: free, then alloc. */ if (delta_vchan0 < 0) - (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0); + (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN0, -delta_vchan0); if (delta_vchan1 < 0) - (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1); + (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN1, -delta_vchan1); if (delta_vchan0 > 0) - (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0); + (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN0, delta_vchan0); if (delta_vchan1 > 0) - (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1); + (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN1, delta_vchan1); /* Return final values to caller. */ @@ -442,8 +674,8 @@ * number of available RRBs. */ - pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0; - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1; + pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0] = final_vchan0; + pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1] = final_vchan1; pcibr_soft->bs_rrb_avail[pciio_slot & 1] = pcibr_soft->bs_rrb_avail[pciio_slot & 1] + pcibr_soft->bs_rrb_res[pciio_slot] @@ -455,34 +687,21 @@ * Reserve enough RRBs so this slot's RRB configuration can be * reset to its boot-time default following a hot-plug shut-down */ - res_rrbs = (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] - - pcibr_soft->bs_rrb_valid[pciio_slot]) - + (pcibr_soft->bs_rrb_valid_dflt[pciio_slot + - PCIBR_RRB_SLOT_VIRTUAL] - - pcibr_soft->bs_rrb_valid[pciio_slot + - PCIBR_RRB_SLOT_VIRTUAL]) - + (pcibr_soft->bs_rrb_res_dflt[pciio_slot] - - pcibr_soft->bs_rrb_res[pciio_slot]); - - if (res_rrbs > 0) { - pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs; - pcibr_soft->bs_rrb_avail[pciio_slot & 1] = - pcibr_soft->bs_rrb_avail[pciio_slot & 1] - - res_rrbs; - } - -#if PCIBR_RRB_DEBUG - printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n", - pciio_slot, final_vchan0, final_vchan1, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot], - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL], + res_rrbs = (pcibr_soft->bs_rrb_res_dflt[pciio_slot] - pcibr_soft->bs_rrb_res[pciio_slot]); - printk("\n"); -#endif + for (vchan = 0; vchan < vchan_total; vchan++) { + res_rrbs += (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] - + pcibr_soft->bs_rrb_valid[pciio_slot][vchan]); + } + + if (res_rrbs > 0) { + pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs; + pcibr_soft->bs_rrb_avail[pciio_slot & 1] = + pcibr_soft->bs_rrb_avail[pciio_slot & 1] + - res_rrbs; + } + + pcibr_rrb_debug("pcibr_rrb_alloc", pcibr_soft); error = 0; } @@ -543,22 +762,22 @@ pciio_info_t pciio_info; pciio_slot_t pciio_slot; pcibr_soft_t pcibr_soft; - unsigned long s; + unsigned long s; int error = -1; if ((pciio_info = pciio_info_get(pconn_vhdl)) && (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && - ((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) { + ((pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info)) < PCIBR_NUM_SLOTS(pcibr_soft))) { s = pcibr_lock(pcibr_soft); if (count_vchan0) *count_vchan0 = - pcibr_soft->bs_rrb_valid[pciio_slot]; + pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0]; if (count_vchan1) *count_vchan1 = - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; + pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1]; if (count_reserved) *count_reserved = @@ -575,159 +794,6 @@ return error; } -/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities - * requested for each of the devices. The evn_odd argument indicates whether - * allocation is for the odd or even rrbs. The next group of four argument - * pairs indicate the amount of rrbs to be assigned to each device. The first - * argument of each pair indicate the total number of rrbs to allocate for that - * device. The second argument of each pair indicates how many rrb's from the - * first argument should be assigned to the virtual channel. The total of all - * of the first arguments should be <= 8. The second argument should be <= the - * first argument. - * if even_odd = 0 the devices in order are 0, 2, 4, 6 - * if even_odd = 1 the devices in order are 1, 3, 5, 7 - * returns 0 if no errors else returns -1 - */ - -int -pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, - int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, - int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) -{ - devfs_handle_t pcibr_vhdl; - pcibr_soft_t pcibr_soft = (pcibr_soft_t)0; - bridge_t *bridge = NULL; - - uint32_t rrb_setting = 0; - int rrb_shift = 7; - uint32_t cur_rrb; - int dev_rrbs[4]; - int virt[4]; - int i, j; - unsigned long s; - - if (GRAPH_SUCCESS == - hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) - bridge = pcibr_soft->bs_base; - hwgraph_vertex_unref(pcibr_vhdl); - } - if (bridge == NULL) - bridge = (bridge_t *) xtalk_piotrans_addr - (vhdl, NULL, 0, sizeof(bridge_t), 0); - - even_odd &= 1; - - dev_rrbs[0] = dev_1_rrbs; - dev_rrbs[1] = dev_2_rrbs; - dev_rrbs[2] = dev_3_rrbs; - dev_rrbs[3] = dev_4_rrbs; - - virt[0] = virt1; - virt[1] = virt2; - virt[2] = virt3; - virt[3] = virt4; - - if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) { - return -1; - } - if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) { - return -1; - } - /* walk through rrbs */ - for (i = 0; i < 4; i++) { - if (virt[i]) { - for( j = 0; j < virt[i]; j++) { - cur_rrb = i | 0xc; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - dev_rrbs[i] = dev_rrbs[i] - 1; - } - } - for (j = 0; j < dev_rrbs[i]; j++) { - cur_rrb = i | 0x8; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - } - } - - if (pcibr_soft) - s = pcibr_lock(pcibr_soft); - - bridge->b_rrb_map[even_odd].reg = rrb_setting; - - if (pcibr_soft) { - - pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd; - - /* since we've "FIXED" the allocations - * for these slots, we probably can dispense - * with tracking avail/res/valid data, but - * keeping it up to date helps debugging. - */ - - pcibr_soft->bs_rrb_avail[even_odd] = - 8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs); - - pcibr_soft->bs_rrb_res[even_odd + 0] = 0; - pcibr_soft->bs_rrb_res[even_odd + 2] = 0; - pcibr_soft->bs_rrb_res[even_odd + 4] = 0; - pcibr_soft->bs_rrb_res[even_odd + 6] = 0; - - pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4; - - pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4; - - pcibr_unlock(pcibr_soft, s); - } - return 0; -} - -/* - * pcibr_rrb_flush: chase down all the RRBs assigned - * to the specified connection point, and flush - * them. - */ -void -pcibr_rrb_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - unsigned long s; - reg_p rrbp; - unsigned rrbm; - int i; - int rrbn; - unsigned sval; - unsigned mask; - - sval = BRIDGE_RRB_EN | (pciio_slot >> 1); - mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV; - rrbn = pciio_slot & 1; - rrbp = &bridge->b_rrb_map[rrbn].reg; - - s = pcibr_lock(pcibr_soft); - rrbm = *rrbp; - for (i = 0; i < 8; ++i) { - if ((rrbm & mask) == sval) - do_pcibr_rrb_flush(bridge, rrbn); - rrbm >>= 4; - rrbn += 2; - } - pcibr_unlock(pcibr_soft, s); -} - /* * pcibr_slot_initial_rrb_alloc * Allocate a default number of rrbs for this slot on @@ -743,75 +809,82 @@ pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; bridge_t *bridge; - int c0, c1, r; + int vchan_total; + int vchan; + int chan[4]; pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + if (!pcibr_soft) return(EINVAL); - bridge = pcibr_soft->bs_base; + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) + return(EINVAL); - /* How may RRBs are on this slot? - */ - c0 = do_pcibr_rrb_count_valid(bridge, slot); - c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); + bridge = pcibr_soft->bs_base; -#if PCIBR_RRB_DEBUG - printk( + /* How many RRBs are on this slot? */ + vchan_total = NUMBER_VCHANNELS(bridge); + for (vchan = 0; vchan < vchan_total; vchan++) + chan[vchan] = do_pcibr_rrb_count_valid(bridge, slot, vchan); + + if (IS_PIC_SOFT(pcibr_soft)) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl, + "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d+%d+%d\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + chan[VCHAN0], chan[VCHAN1], chan[VCHAN2], chan[VCHAN3])); + } else { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl, "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d\n", - slot, c0, c1); -#endif + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + chan[VCHAN0], chan[VCHAN1])); + } /* Do we really need any? */ pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; pcibr_info = pcibr_infoh[0]; - if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && - !pcibr_soft->bs_slot[slot].has_host) { - if (c0 > 0) - do_pcibr_rrb_free(bridge, slot, c0); - if (c1 > 0) - do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); - pcibr_soft->bs_rrb_valid[slot] = 0x1000; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; - return(ENODEV); - } - pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; - pcibr_soft->bs_rrb_valid[slot] = c0; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1; - - pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); - pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); + if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && IS_PIC_SOFT(pcibr_soft) && + (slot == 2 || slot == 3) && + (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && + !pcibr_soft->bs_slot[slot].has_host) { + + for (vchan = 0; vchan < 2; vchan++) { + do_pcibr_rrb_free(bridge, slot, vchan, 8); + pcibr_soft->bs_rrb_valid[slot][vchan] = 0; + } - r = 3 - (c0 + c1); + pcibr_soft->bs_rrb_valid[slot][3] = chan[3]; - if (r > 0) { - pcibr_soft->bs_rrb_res[slot] = r; - pcibr_soft->bs_rrb_avail[slot & 1] -= r; + return(ENODEV); } -#if PCIBR_RRB_DEBUG - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif + for (vchan = 0; vchan < vchan_total; vchan++) + pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan]; return(0); } +void +rrb_reserved_free(pcibr_soft_t pcibr_soft, int slot) +{ + int res = pcibr_soft->bs_rrb_res[slot]; + + if (res) { + pcibr_soft->bs_rrb_avail[slot & 1] += res; + pcibr_soft->bs_rrb_res[slot] = 0; + } +} + /* * pcibr_initial_rrb * Assign an equal total number of RRBs to all candidate slots, * where the total is the sum of the number of RRBs assigned to * the normal channel, the number of RRBs assigned to the virtual - * channel, and the number of RRBs assigned as reserved. + * channels, and the number of RRBs assigned as reserved. * - * A candidate slot is a populated slot on a non-SN1 system or - * any existing (populated or empty) slot on an SN1 system. + * A candidate slot is any existing (populated or empty) slot. * Empty SN1 slots need RRBs to support hot-plug operations. */ @@ -822,7 +895,9 @@ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge_t *bridge = pcibr_soft->bs_base; pciio_slot_t slot; - int c0, c1; + int rrb_total; + int vchan_total; + int vchan; int have[2][3]; int res[2]; int eo; @@ -831,16 +906,21 @@ have[1][0] = have[1][1] = have[1][2] = 0; res[0] = res[1] = 0; - for (slot = 0; slot < 8; ++slot) { + vchan_total = NUMBER_VCHANNELS(bridge); + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { /* Initial RRB management; give back RRBs in all non-existent slots */ (void) pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); /* Base calculations only on existing slots */ if ((slot >= first) && (slot <= last)) { - c0 = pcibr_soft->bs_rrb_valid[slot]; - c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]; - if ((c0 + c1) < 3) - have[slot & 1][c0 + c1]++; + rrb_total = 0; + for (vchan = 0; vchan < vchan_total; vchan++) + rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan]; + + if (rrb_total < 3) + have[slot & 1][rrb_total]++; } } @@ -867,30 +947,70 @@ for (slot = first; slot <= last; ++slot) { int r; - c0 = pcibr_soft->bs_rrb_valid[slot]; - c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]; - r = res[slot & 1] - (c0 + c1); + rrb_total = 0; + for (vchan = 0; vchan < vchan_total; vchan++) + rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan]; + + r = res[slot & 1] - (rrb_total); if (r > 0) { pcibr_soft->bs_rrb_res[slot] = r; pcibr_soft->bs_rrb_avail[slot & 1] -= r; - } + } } -#if PCIBR_RRB_DEBUG - printk("%v RRB MANAGEMENT: %d+%d free\n", - pcibr_vhdl, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (slot = first; slot <= last; ++slot) - printk("\tslot %d: %d+%d+%d", slot, - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif + pcibr_rrb_debug("pcibr_initial_rrb", pcibr_soft); return 0; } +/* + * Dump the pcibr_soft_t RRB state variable + */ +void +pcibr_rrb_debug(char *calling_func, pcibr_soft_t pcibr_soft) +{ + pciio_slot_t slot; + char tmp_str[256]; + + if (pcibr_debug_mask & PCIBR_DEBUG_RRB) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, + "%s: rrbs available, even=%d, odd=%d\n", calling_func, + pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1])); + + if (IS_PIC_SOFT(pcibr_soft)) { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, + "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n")); + } else { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, + "\tslot\tvchan0\tvchan1\treserved\n")); + } + + for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) { + /* + * The kernel only allows functions to have so many variable args, + * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf + * arguments fails so sprintf() it into a temporary string. + */ + if (IS_PIC_SOFT(pcibr_soft)) { + sprintf(tmp_str, "\t %d\t %d\t %d\t %d\t %d\t %d\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0], + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1], + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2], + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3], + pcibr_soft->bs_rrb_res[slot]); + } else { + sprintf(tmp_str, "\t %d\t %d\t %d\t %d\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0], + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1], + pcibr_soft->bs_rrb_res[slot]); + } + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, + "%s", tmp_str)); + } + } +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c Tue Jan 14 11:18:20 2003 @@ -4,12 +4,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include #include #include #include @@ -30,70 +31,90 @@ #include #include #include +#include + +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + extern pcibr_info_t pcibr_info_get(devfs_handle_t); -extern int pcibr_widget_to_bus(int); +extern int pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl); extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -extern void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); -#if 0 -int pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -#endif +extern int pcibr_pcix_rbars_calc(pcibr_soft_t); int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft, pciio_slot_t slot); int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); -int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); +int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, + int drv_flags, char *l1_msg, int *sub_errorp); int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *); -void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); -extern uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +static int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *); +void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); +iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, + pciio_space_t, int, int, int); +void pciibr_bus_addr_free(pcibr_soft_t, pciio_win_info_t); +cfg_p pcibr_find_capability(cfg_p, unsigned); +extern uint64_t do_pcibr_config_get(int, cfg_p, unsigned, unsigned); +void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); -#ifdef LATER int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, int *sub_errorp); -int pcibr_slot_pwr(devfs_handle_t, pciio_slot_t, int, char *); -int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t); -int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t); -void pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, int func, - pcibr_slot_func_info_resp_t funcp); + int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot, pcibr_slot_info_resp_t respp); -int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t); -#endif /* LATER */ extern devfs_handle_t baseio_pci_vhdl; int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t); + /* For now .... */ /* * PCI Hot-Plug Capability Flags + */ #define D_PCI_HOT_PLUG_ATTACH 0x200 /* Driver supports PCI hot-plug attach */ #define D_PCI_HOT_PLUG_DETACH 0x400 /* Driver supports PCI hot-plug detach */ +/* + * PCI-X Max Outstanding Split Transactions translation array and Max Memory + * Read Byte Count translation array, as defined in the PCI-X Specification. + * Section 7.2.3 & 7.2.4 of PCI-X Specification - rev 1.0 + */ +#define MAX_SPLIT_TABLE 8 +#define MAX_READCNT_TABLE 4 +int max_splittrans_to_numbuf[MAX_SPLIT_TABLE] = {1, 2, 3, 4, 8, 12, 16, 32}; +int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 }; + + /*========================================================================== * BRIDGE PCI SLOT RELATED IOCTLs */ -#ifdef LATER - /* * pcibr_slot_startup * Software start-up the PCI slot. */ + +#ifdef PIC_LATER + int pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pciio_slot_t slot = reqp->req_slot; + pciio_slot_t slot; int error = 0; char l1_msg[BRL1_QSIZE+1]; struct pcibr_slot_up_resp_s tmp_up_resp; @@ -103,17 +124,22 @@ return(PCI_NOT_A_BRIDGE); } + /* req_slot is the 'external' slot number, convert for internal use */ + slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot); + /* Do not allow start-up of a slot in a shoehorn */ if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { return(PCI_SLOT_IN_SHOEHORN); } /* Check for the valid slot */ - if (!PCIBR_VALID_SLOT(slot)) + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(PCI_NOT_A_SLOT); +#ifdef PIC_LATER /* Acquire update access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); +#endif if (pcibr_soft->bs_slot[slot].slot_status & SLOT_STARTUP_CMPLT) { error = PCI_SLOT_ALREADY_UP; @@ -132,9 +158,10 @@ startup_unlock: +#ifdef PIC_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock); - +#endif return(error); } @@ -147,7 +174,7 @@ { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge_t *bridge; - pciio_slot_t slot = reqp->req_slot; + pciio_slot_t slot; int error = 0; char l1_msg[BRL1_QSIZE+1]; struct pcibr_slot_down_resp_s tmp_down_resp; @@ -158,10 +185,13 @@ return(PCI_NOT_A_BRIDGE); } + /* req_slot is the 'external' slot number, convert for internal use */ + slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot); + bridge = pcibr_soft->bs_base; /* Check for valid slot */ - if (!PCIBR_VALID_SLOT(slot)) + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(PCI_NOT_A_SLOT); /* Do not allow shut-down of a slot in a shoehorn */ @@ -169,8 +199,10 @@ return(PCI_SLOT_IN_SHOEHORN); } +#ifdef PIC_LATER /* Acquire update access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); +#endif if ((pcibr_soft->bs_slot[slot].slot_status & SLOT_SHUTDOWN_CMPLT) || ((pcibr_soft->bs_slot[slot].slot_status & SLOT_STATUS_MASK) == 0)) { @@ -182,6 +214,13 @@ goto shutdown_unlock; } + /* Do not allow a multi-function card to be hot-plug removed */ + if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) { + tmp_down_resp.resp_sub_errno = EPERM; + error = PCI_MULTI_FUNC_ERR; + goto shutdown_copyout; + } + /* Do not allow the last 33 MHz card to be removed */ if ((bridge->b_wid_control & BRIDGE_CTRL_BUS_SPEED_MASK) == BRIDGE_CTRL_BUS_SPEED_33) { @@ -204,17 +243,22 @@ strncpy(tmp_down_resp.resp_l1_msg, l1_msg, L1_QSIZE); tmp_down_resp.resp_l1_msg[L1_QSIZE] = '\0'; + shutdown_copyout: + if (COPYOUT(&tmp_down_resp, reqp->req_respp.down, reqp->req_size)) { return(EFAULT); } shutdown_unlock: +#ifdef PIC_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock); +#endif return(error); } +#endif /* PIC_LATER */ char *pci_space_name[] = {"NONE", "ROM", @@ -240,6 +284,7 @@ { pcibr_info_t pcibr_info = pcibr_infoh[func]; int win; + boolean_t is_sys_critical_vertex(devfs_handle_t); funcp->resp_f_status = 0; @@ -248,16 +293,19 @@ } funcp->resp_f_status |= FUNC_IS_VALID; +#if defined(SUPPORT_PRINTING_V_FORMAT) sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); - +#endif if(is_sys_critical_vertex(pcibr_info->f_vertex)) { funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; } funcp->resp_f_bus = pcibr_info->f_bus; - funcp->resp_f_slot = pcibr_info->f_slot; + funcp->resp_f_slot = PCIBR_INFO_SLOT_GET_EXT(pcibr_info); funcp->resp_f_func = pcibr_info->f_func; +#if defined(SUPPORT_PRINTING_V_FORMAT) sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master); +#endif funcp->resp_f_pops = pcibr_info->f_pops; funcp->resp_f_efunc = pcibr_info->f_efunc; funcp->resp_f_einfo = pcibr_info->f_einfo; @@ -297,20 +345,29 @@ reg_p b_respp; pcibr_slot_info_resp_t slotp; pcibr_slot_func_info_resp_t funcp; + boolean_t is_sys_critical_vertex(devfs_handle_t); + extern void snia_kmem_free(void *, int); - slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP); + slotp = snia_kmem_zalloc(sizeof(*slotp), 0); if (slotp == NULL) { return(ENOMEM); } pss = &pcibr_soft->bs_slot[slot]; + slotp->resp_bs_bridge_mode = pcibr_soft->bs_bridge_mode; + slotp->resp_bs_bridge_type = pcibr_soft->bs_bridge_type; + slotp->resp_has_host = pss->has_host; slotp->resp_host_slot = pss->host_slot; +#if defined(SUPPORT_PRINTING_V_FORMAT) sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn); +#else + sprintf(slotp->resp_slot_conn_name, "%p", (void *)pss->slot_conn); +#endif slotp->resp_slot_status = pss->slot_status; - slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl); + slotp->resp_l1_bus_num = pcibr_widget_to_bus(pcibr_soft->bs_vhdl); if (is_sys_critical_vertex(pss->slot_conn)) { slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; @@ -342,9 +399,10 @@ slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer; slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow; - slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot]; - slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]; + slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot][VCHAN0]; + slotp->resp_bs_rrb_valid_v1 = pcibr_soft->bs_rrb_valid[slot][VCHAN1]; + slotp->resp_bs_rrb_valid_v2 = pcibr_soft->bs_rrb_valid[slot][VCHAN2]; + slotp->resp_bs_rrb_valid_v3 = pcibr_soft->bs_rrb_valid[slot][VCHAN3]; slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot]; if (slot & 1) { @@ -355,16 +413,21 @@ slotp->resp_b_resp = *b_respp; - slotp->resp_b_wid_control = bridge->b_wid_control; slotp->resp_b_int_device = bridge->b_int_device; - slotp->resp_b_int_enable = bridge->b_int_enable; - slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; + + if (IS_PIC_SOFT(pcibr_soft)) { + slotp->resp_p_int_enable = bridge->p_int_enable_64; + slotp->resp_p_int_host = bridge->p_int_addr_64[slot]; + } else { + slotp->resp_b_int_enable = bridge->b_int_enable; + slotp->resp_b_int_host = bridge->b_int_addr[slot].addr; + } if (COPYOUT(slotp, respp, sizeof(*respp))) { return(EFAULT); } - kmem_free(slotp, sizeof(*slotp)); + snia_kmem_free(slotp, sizeof(*slotp)); return(0); } @@ -395,19 +458,26 @@ pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pciio_slot_t slot = reqp->req_slot; + pciio_slot_t slot; pciio_slot_t tmp_slot; pcibr_slot_info_resp_t respp = reqp->req_respp.query; int size = reqp->req_size; - int error; + int error = 0; /* Make sure that we are dealing with a bridge device vertex */ if (!pcibr_soft) { return(PCI_NOT_A_BRIDGE); } + /* req_slot is the 'external' slot number, convert for internal use */ + slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl, + "pcibr_slot_query: pcibr_soft=0x%x, slot=%d, reqp=0x%x\n", + pcibr_soft, slot, reqp)); + /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */ - if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) { + if ((!PCIBR_VALID_SLOT(pcibr_soft, slot)) && (slot != PCIIO_SLOT_NONE)) { return(PCI_NOT_A_SLOT); } @@ -422,32 +492,37 @@ return(PCI_RESP_AREA_TOO_SMALL); } +#ifdef PIC_LATER /* Acquire read access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO); - +#endif error = pcibr_slot_info_return(pcibr_soft, slot, respp); +#ifdef PIC_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock); - +#endif return(error); } /* Return information for all the slots */ - for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) { + for (tmp_slot = pcibr_soft->bs_min_slot; + tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); tmp_slot++) { if (size < sizeof(*respp)) { return(PCI_RESP_AREA_TOO_SMALL); } +#ifdef PIC_LATER /* Acquire read access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO); - +#endif error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp); +#ifdef PCI_LATER /* Release the bus lock */ mrunlock(pcibr_soft->bs_bus_lock); - +#endif if (error) { return(error); } @@ -458,60 +533,92 @@ return(error); } -#endif /* LATER */ -/* FIXME: there should be a better way to do this. - * pcibr_attach() needs PCI_ADDR_SPACE_LIMITS_STORE +#if 0 +/* + * pcibr_slot_reset + * Reset the PCI device in the particular slot. + * + * The Xbridge does not comply with the PCI Specification + * when resetting an indiviaudl slot. An individual slot is + * is reset by toggling the slot's bit in the Xbridge Control + * Register. The Xbridge will assert the target slot's + * (non-bussed) RST signal, but does not assert the (bussed) + * REQ64 signal as required by the specification. As + * designed, the Xbridge cannot assert the REQ64 signal + * becuase it may interfere with a bus transaction in progress. + * The practical effects of this Xbridge implementation is + * device dependent; it probably will not adversely effect + * 32-bit cards, but may disable 64-bit data transfers by those + * cards that normally support 64-bit data transfers. + * + * The Xbridge will assert REQ64 when all four slots are reset + * by simultaneously toggling all four slot reset bits in the + * Xbridge Control Register. This is basically a PCI bus reset + * and asserting the (bussed) REQ64 signal will not interfere + * with any bus transactions in progress. + * + * The Xbridge (and the SN0 Bridge) support resetting only + * four PCI bus slots via the (X)bridge Control Register. + * + * To reset an individual slot for the PCI Hot-Plug feature + * use the L1 console commands to power-down and then + * power-up the slot, or use the kernel infrastructure + * functions to power-down/up the slot when they are + * implemented for SN1. */ +int +pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge_t *bridge; + bridgereg_t ctrlreg,tmp; + volatile bridgereg_t *wrb_flush; -/* - * PCI_ADDR_SPACE_LIMITS_LOAD - * Gets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_LOAD() \ - pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base; \ - pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last; \ - pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base; \ - pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last; \ - pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base; \ - pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last; -/* - * PCI_ADDR_SPACE_LIMITS_STORE - * Sets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_STORE() \ - pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ - pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ - pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ - pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ - pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ - pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; - -#define PCI_ADDR_SPACE_LIMITS_PRINT() \ - printf("+++++++++++++++++++++++\n" \ - "IO base 0x%x last 0x%x\n" \ - "SWIN base 0x%x last 0x%x\n" \ - "MEM base 0x%x last 0x%x\n" \ - "+++++++++++++++++++++++\n", \ - pcibr_soft->bs_spinfo.pci_io_base, \ - pcibr_soft->bs_spinfo.pci_io_last, \ - pcibr_soft->bs_spinfo.pci_swin_base, \ - pcibr_soft->bs_spinfo.pci_swin_last, \ - pcibr_soft->bs_spinfo.pci_mem_base, \ - pcibr_soft->bs_spinfo.pci_mem_last); + if (!pcibr_soft) + return(EINVAL); + + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) + return(EINVAL); + + /* Enable the DMA operations from this device of the xtalk widget + * (PCI host bridge in this case). + */ + xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot); + + /* Set the reset slot bit in the bridge's wid control register + * to reset the PCI slot + */ + bridge = pcibr_soft->bs_base; + + /* Read the bridge widget control and clear out the reset pin + * bit for the corresponding slot. + */ + tmp = ctrlreg = bridge->b_wid_control; + + tmp &= ~BRIDGE_CTRL_RST_PIN(slot); + + bridge->b_wid_control = tmp; + tmp = bridge->b_wid_control; + + /* Restore the old control register back. + * NOTE : PCI card gets reset when the reset pin bit + * changes from 0 (set above) to 1 (going to be set now). + */ + + bridge->b_wid_control = ctrlreg; + + /* Flush the write buffers if any !! */ + wrb_flush = &(bridge->b_wr_req_buf[slot].reg); + while (*wrb_flush); + return(0); +} +#endif + +#define PROBE_LOCK 0 /* FIXME: we're attempting to lock around accesses + * to b_int_enable. This hangs pcibr_probe_slot() + */ /* * pcibr_slot_info_init @@ -534,12 +641,12 @@ pciio_vendor_id_t vendor; pciio_device_id_t device; unsigned htype; + unsigned lt_time; + int nbars; cfg_p wptr; + cfg_p pcix_cap; int win; pciio_space_t space; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; int nfunc; pciio_function_t rfunc; int func; @@ -552,7 +659,7 @@ return(EINVAL); bridge = pcibr_soft->bs_base; - if (!PCIBR_VALID_SLOT(slot)) + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization @@ -566,28 +673,35 @@ if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) return(EPERM); - /* Load the current values of allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); - /* Try to read the device-id/vendor-id from the config space */ - cfgw = bridge->b_type0_cfg_dev[slot].l; + cfgw = pcibr_slot_config_addr(bridge, slot, 0); +#if PROBE_LOCK + s = pcibr_lock(pcibr_soft); +#endif if (pcibr_probe_slot(bridge, cfgw, &idword)) return(ENODEV); +#if PROBE_LOCK + pcibr_unlock(pcibr_soft, s); +#endif slotp = &pcibr_soft->bs_slot[slot]; slotp->slot_status |= SLOT_POWER_UP; vendor = 0xFFFF & idword; + device = 0xFFFF & (idword >> 16); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PROBE, pcibr_vhdl, + "pcibr_slot_info_init: slot=%d, vendor=0x%x, device=0x%x\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vendor, device)); + /* If the vendor id is not valid then the slot is not populated * and we are done. */ if (vendor == 0xFFFF) return(ENODEV); - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - + htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); nfunc = 1; rfunc = PCIIO_FUNC_NONE; pfail = 0; @@ -599,11 +713,17 @@ if (htype & 0x80) { /* MULTIFUNCTION */ for (func = 1; func < 8; ++func) { - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); +#if PROBE_LOCK + s = pcibr_lock(pcibr_soft); +#endif if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { pfail |= 1 << func; continue; } +#if PROBE_LOCK + pcibr_unlock(pcibr_soft, s); +#endif vendor = 0xFFFF & idwords[func]; if (vendor == 0xFFFF) { pfail |= 1 << func; @@ -612,7 +732,7 @@ nfunc = func + 1; rfunc = 0; } - cfgw = bridge->b_type0_cfg_dev[slot].l; + cfgw = pcibr_slot_config_addr(bridge, slot, 0); } NEWA(pcibr_infoh, nfunc); @@ -627,39 +747,177 @@ continue; idword = idwords[func]; - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); + htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); rfunc = func; } htype &= 0x7f; if (htype != 0x00) { - printk(KERN_WARNING "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", + printk(KERN_WARNING + "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", pcibr_soft->bs_name, slot, func, htype); - continue; + nbars = 2; + } else { + nbars = PCI_CFG_BASE_ADDRS; + } + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, + "pcibr_slot_info_init: slot=%d, func=%d, cfgw=0x%x\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), func, cfgw)); + +#ifdef PIC_LATER + /* + * Check for a Quad ATM PCI "card" and return all the PCI bus + * memory and I/O space. This will work-around an apparent + * hardware problem with the Quad ATM XIO card handling large + * PIO addresses. Releasing all the space for use by the card + * will lower the PIO addresses with the PCI bus address space. + * This is OK since the PROM did not assign any BAR addresses. + * + * Only release all the PCI bus addresses once. + * + */ + if ((vendor == LINC_VENDOR_ID_NUM) && (device == LINC_DEVICE_ID_NUM)) { + iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; + int prom_base_size = 0x1000000; + + if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_MEM_FREED)) { + pciio_device_win_populate(&pcibr_soft->bs_mem_win_map, + prom_base_addr, prom_base_size); + pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_MEM_FREED; + } + + if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_IO_FREED)) { + pciio_device_win_populate(&pcibr_soft->bs_io_win_map, + prom_base_addr, prom_base_size); + pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_IO_FREED; + } + } +#endif /* PIC_LATER */ + + /* + * If the latency timer has already been set, by prom or by the + * card itself, use that value. Otherwise look at the device's + * 'min_gnt' and attempt to calculate a latency time. + * + * NOTE: For now if the device is on the 'real time' arbitration + * ring we dont set the latency timer. + * + * WAR: SGI's IOC3 and RAD devices target abort if you write a + * single byte into their config space. So don't set the Latency + * Timer for these devices + */ + + lt_time = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1); + + if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) && + !((vendor == IOC3_VENDOR_ID_NUM) && + ( +#ifdef PIC_LATER + (device == IOC3_DEVICE_ID_NUM) || + (device == LINC_DEVICE_ID_NUM) || +#endif + (device == 0x5 /* RAD_DEV */)))) { + unsigned min_gnt; + unsigned min_gnt_mult; + + /* 'min_gnt' indicates how long of a burst period a device + * needs in increments of 250ns. But latency timer is in + * PCI clock cycles, so a conversion is needed. + */ + min_gnt = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_MIN_GNT, 1); + + if (IS_133MHZ(pcibr_soft)) + min_gnt_mult = 32; /* 250ns @ 133MHz in clocks */ + else if (IS_100MHZ(pcibr_soft)) + min_gnt_mult = 24; /* 250ns @ 100MHz in clocks */ + else if (IS_66MHZ(pcibr_soft)) + min_gnt_mult = 16; /* 250ns @ 66MHz, in clocks */ + else + min_gnt_mult = 8; /* 250ns @ 33MHz, in clocks */ + + if ((min_gnt != 0) && ((min_gnt * min_gnt_mult) < 256)) + lt_time = (min_gnt * min_gnt_mult); + else + lt_time = 4 * min_gnt_mult; /* 1 micro second */ + + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, + "pcibr_slot_info_init: set Latency Timer for slot=%d, " + "func=%d, to 0x%x\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time)); + } + + + /* In our architecture the setting of the cacheline size isn't + * beneficial for cards in PCI mode, but in PCI-X mode devices + * can optionally use the cacheline size value for internal + * device optimizations (See 7.1.5 of the PCI-X v1.0 spec). + * NOTE: cachline size is in doubleword increments + */ + if (IS_PCIX(pcibr_soft)) { + if (!do_pcibr_config_get(1, cfgw, PCI_CFG_CACHE_LINE, 1)) { + do_pcibr_config_set(1, cfgw, PCI_CFG_CACHE_LINE, 1, 0x20); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, + "pcibr_slot_info_init: set CacheLine for slot=%d, " + "func=%d, to 0x20\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func)); + } + + /* Get the PCI-X capability if running in PCI-X mode. If the func + * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE + * pcibr_info struct so the device driver for that function is not + * called. + */ + if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) { + printk(KERN_WARNING +#if defined(SUPPORT_PRINTING_V_FORMAT) + "%v: Bus running in PCI-X mode, But card in slot %d, " + "func %d not PCI-X capable\n", pcibr_vhdl, slot, func); +#else + "0x%lx: Bus running in PCI-X mode, But card in slot %d, " + "func %d not PCI-X capable\n", (unsigned long)pcibr_vhdl, slot, func); +#endif + pcibr_device_info_new(pcibr_soft, slot, PCIIO_FUNC_NONE, + PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); + continue; + } + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, + "pcibr_slot_info_init: PCI-X capability at 0x%x for " + "slot=%d, func=%d\n", + pcix_cap, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func)); + } else { + pcix_cap = NULL; } -#if DEBUG && ATTACH_DEBUG - printk(KERN_NOTICE - "%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x", - pcibr_soft->bs_name, slot, func, vendor, device); -#endif pcibr_info = pcibr_device_info_new (pcibr_soft, slot, rfunc, vendor, device); + + /* Keep a running total of the number of PIC-X functions on the bus + * and the number of max outstanding split trasnactions that they + * have requested. NOTE: "pcix_cap != NULL" implies IS_PCIX() + */ + pcibr_info->f_pcix_cap = (cap_pcix_type0_t *)pcix_cap; + if (pcibr_info->f_pcix_cap) { + int max_out; /* max outstanding splittrans from status reg */ + + pcibr_soft->bs_pcix_num_funcs++; + max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split; + pcibr_soft->bs_pcix_split_tot += max_splittrans_to_numbuf[max_out]; + } + conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); if (func == 0) slotp->slot_conn = conn_vhdl; -#ifdef SN1_LITTLE_ENDIAN - cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4]; -#else - cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; -#endif + cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { + for (win = 0; win < nbars; ++win) { iopaddr_t base, mask, code; size_t size; @@ -706,11 +964,7 @@ * this could be pushed up into pciio, when we * start supporting more PCI providers. */ -#ifdef SN1_LITTLE_ENDIAN - base = wptr[((win*4)^4)/4]; -#else - base = wptr[win]; -#endif + base = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); if (base & PCI_BA_IO_SPACE) { /* BASE is in I/O space. */ @@ -736,11 +990,7 @@ } else if (base & 0xC0000000) { base = 0; /* outside permissable range */ } else if ((code == PCI_BA_MEM_64BIT) && -#ifdef SN1_LITTLE_ENDIAN - (wptr[(((win + 1)*4)^4)/4] != 0)) { -#else - (wptr[win + 1] != 0)) { -#endif /* LITTLE_ENDIAN */ + (do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, ((win + 1)*4), 4) != 0)) { base = 0; /* outside permissable range */ } } @@ -748,13 +998,8 @@ if (base != 0) { /* estimate size */ size = base & -base; } else { /* calculate size */ -#ifdef SN1_LITTLE_ENDIAN - wptr[((win*4)^4)/4] = ~0; /* turn on all bits */ - size = wptr[((win*4)^4)/4]; /* get stored bits */ -#else - wptr[win] = ~0; /* turn on all bits */ - size = wptr[win]; /* get stored bits */ -#endif /* LITTLE_ENDIAN */ + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, ~0); /* write 1's */ + size = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); /* read back */ size &= mask; /* keep addr */ size &= -size; /* keep lsbit */ if (size == 0) @@ -765,28 +1010,6 @@ pcibr_info->f_window[win].w_base = base; pcibr_info->f_window[win].w_size = size; - /* - * If this window already has PCI space - * allocated for it, "subtract" that space from - * our running freeblocks. Don't worry about - * overlaps in existing allocated windows; we - * may be overstating their sizes anyway. - */ - - if (base && size) { - if (space == PCIIO_SPACE_IO) { - pcibr_freeblock_sub(&pci_io_fb, - &pci_io_fl, - base, size); - } else { - pcibr_freeblock_sub(&pci_lo_fb, - &pci_lo_fl, - base, size); - pcibr_freeblock_sub(&pci_hi_fb, - &pci_hi_fl, - base, size); - } - } #if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) /* * IOC3 BASE_ADDR* BUG WORKAROUND @@ -825,21 +1048,55 @@ #endif if (code == PCI_BA_MEM_64BIT) { win++; /* skip upper half */ -#ifdef SN1_LITTLE_ENDIAN - wptr[((win*4)^4)/4] = 0; /* which must be zero */ -#else - wptr[win] = 0; /* which must be zero */ -#endif /* LITTLE_ENDIAN */ + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, 0); /* must be zero */ } } /* next win */ } /* next func */ - /* Store back the values for allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_STORE(); return(0); } /* + * pcibr_find_capability + * Walk the list of capabilities (if it exists) looking for + * the requested capability. Return a cfg_p pointer to the + * capability if found, else return NULL + */ +cfg_p +pcibr_find_capability(cfg_p cfgw, + unsigned capability) +{ + unsigned cap_nxt; + unsigned cap_id; + int defend_against_circular_linkedlist = 0; + + /* Check to see if there is a capabilities pointer in the cfg header */ + if (!(do_pcibr_config_get(1, cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) { + return (NULL); + } + + /* + * Read up the capabilities head pointer from the configuration header. + * Capabilities are stored as a linked list in the lower 48 dwords of + * config space and are dword aligned. (Note: spec states the least two + * significant bits of the next pointer must be ignored, so we mask + * with 0xfc). + */ + cap_nxt = (do_pcibr_config_get(1, cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc); + + while (cap_nxt && (defend_against_circular_linkedlist <= 48)) { + cap_id = do_pcibr_config_get(1, cfgw, cap_nxt, 1); + if (cap_id == capability) { + return ((cfg_p)((char *)cfgw + cap_nxt)); + } + cap_nxt = (do_pcibr_config_get(1, cfgw, cap_nxt+1, 1) & 0xfc); + defend_against_circular_linkedlist++; + } + + return (NULL); +} + +/* * pcibr_slot_info_free * Remove all the PCI infrastructural information associated * with a particular PCI device. @@ -854,7 +1111,10 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + if (!pcibr_soft) + return(EINVAL); + + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; @@ -868,6 +1128,109 @@ return(0); } +/* + * pcibr_slot_pcix_rbar_init + * Allocate RBARs to the PCI-X functions on a given device + */ +int +pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft, + pciio_slot_t slot) +{ + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; + char tmp_str[256]; + int nfunc; + int func; + + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) + return(EINVAL); + + if ((nfunc = pcibr_soft->bs_slot[slot].bss_ninfo) < 1) + return(EINVAL); + + if (!(pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos)) + return(EINVAL); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, + "pcibr_slot_pcix_rbar_init for slot %d\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot))); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, + "\tslot/func\trequested\tgiven\tinuse\tavail\n")); + + for (func = 0; func < nfunc; ++func) { + cap_pcix_type0_t *pcix_cap_p; + cap_pcix_stat_reg_t *pcix_statreg_p; + cap_pcix_cmd_reg_t *pcix_cmdreg_p; + int num_rbar; + + if (!(pcibr_info = pcibr_infoh[func])) + continue; + + if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) + continue; + + if (!(pcix_cap_p = pcibr_info->f_pcix_cap)) + continue; + + pcix_statreg_p = &pcix_cap_p->pcix_type0_status; + pcix_cmdreg_p = &pcix_cap_p->pcix_type0_command; + + /* If there are enough RBARs to satify the number of "max outstanding + * transactions" each function requested (bs_pcix_rbar_percent_allowed + * is 100%), then give each function what it requested, otherwise give + * the functions a "percentage of what they requested". + */ + if (pcibr_soft->bs_pcix_rbar_percent_allowed >= 100) { + pcix_cmdreg_p->max_split = pcix_statreg_p->max_out_split; + num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split]; + pcibr_soft->bs_pcix_rbar_inuse += num_rbar; + pcibr_soft->bs_pcix_rbar_avail -= num_rbar; + pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt; + } else { + int index; /* index into max_splittrans_to_numbuf table */ + int max_out; /* max outstanding transactions given to func */ + + /* Calculate the percentage of RBARs this function can have. + * NOTE: Every function gets at least 1 RBAR (thus the "+1"). + * bs_pcix_rbar_percent_allowed is the percentage of what was + * requested less this 1 RBAR that all functions automatically + * gets + */ + max_out = ((max_splittrans_to_numbuf[pcix_statreg_p->max_out_split] + * pcibr_soft->bs_pcix_rbar_percent_allowed) / 100) + 1; + + /* round down the newly caclulated max_out to a valid number in + * max_splittrans_to_numbuf[] + */ + for (index = 0; index < MAX_SPLIT_TABLE-1; index++) + if (max_splittrans_to_numbuf[index + 1] > max_out) + break; + + pcix_cmdreg_p->max_split = index; + num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split]; + pcibr_soft->bs_pcix_rbar_inuse += num_rbar; + pcibr_soft->bs_pcix_rbar_avail -= num_rbar; + pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt; + } + /* + * The kernel only allows functions to have so many variable args, + * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf + * arguments fails so sprintf() it into a temporary string. + */ + if (pcibr_debug_mask & PCIBR_DEBUG_RBAR) { + sprintf(tmp_str,"\t %d/%d \t %d \t %d \t %d \t %d\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, + max_splittrans_to_numbuf[pcix_statreg_p->max_out_split], + max_splittrans_to_numbuf[pcix_cmdreg_p->max_split], + pcibr_soft->bs_pcix_rbar_inuse, + pcibr_soft->bs_pcix_rbar_avail); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, + "%s", tmp_str)); + } + } + return(0); +} + int as_debug = 0; /* * pcibr_slot_addr_space_init @@ -878,34 +1241,28 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) { - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; + pcibr_soft_t pcibr_soft; + pcibr_info_h pcibr_infoh; + pcibr_info_t pcibr_info; bridge_t *bridge; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - size_t align; - iopaddr_t mask; - int nbars; - int nfunc; - int func; - int win; + iopaddr_t mask; + int nbars; + int nfunc; + int func; + int win; + int rc = 0; + int align; + int align_slot; pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + if (!pcibr_soft) return(EINVAL); - bridge = pcibr_soft->bs_base; - - /* Get the current values for the allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) + return(EINVAL); - if (as_debug) -#ifdef LATER - PCI_ADDR_SPACE_LIMITS_PRINT(); -#endif + bridge = pcibr_soft->bs_base; /* allocate address space, * for windows that have not been @@ -934,10 +1291,7 @@ * the entire "lo" area is only a * megabyte, total ... */ - align = (slot < 2) ? 0x200000 : 0x100000; - mask = -align; - pci_io_fb = (pci_io_fb + align - 1) & mask; - pci_hi_fb = (pci_hi_fb + align - 1) & mask; + align_slot = 0x100000; for (func = 0; func < nfunc; ++func) { cfg_p cfgw; @@ -945,7 +1299,9 @@ pciio_space_t space; iopaddr_t base; size_t size; - cfg_p pci_cfg_cmd_reg_p; +#ifdef PCI_LATER + char tmp_str[256]; +#endif unsigned pci_cfg_cmd_reg; unsigned pci_cfg_cmd_reg_add = 0; @@ -957,13 +1313,15 @@ if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) continue; - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; + cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - nbars = PCI_CFG_BASE_ADDRS; + if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) + nbars = 2; + else + nbars = PCI_CFG_BASE_ADDRS; for (win = 0; win < nbars; ++win) { - space = pcibr_info->f_window[win].w_space; base = pcibr_info->f_window[win].w_base; size = pcibr_info->f_window[win].w_size; @@ -972,77 +1330,94 @@ continue; if (base >= size) { -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n", - slot, func, win, space, base, base + size - 1); -#endif + /* + * The kernel only allows functions to have so many variable + * args attempting to call PCIBR_DEBUG_ALWAYS() with more than + * 5 printf arguments fails so sprintf() it into a temporary + * string (tmp_str). + */ +#if defined(SUPPORT_PRINTING_R_FORMAT) + if (pcibr_debug_mask & PCIBR_DEBUG_BAR) { + sprintf(tmp_str, "pcibr_slot_addr_space_init: slot=%d, " + "func=%d win %d is in %r [0x%x..0x%x], allocated by " + "prom\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + func, win, space, space_desc, base, base + size - 1); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, + "%s",tmp_str)); + } +#endif /* SUPPORT_PRINTING_R_FORMAT */ continue; /* already allocated */ } - align = size; /* ie. 0x00001000 */ - if (align < _PAGESZ) - align = _PAGESZ; /* ie. 0x00004000 */ - mask = -align; /* ie. 0xFFFFC000 */ + align = (win) ? size : align_slot; + + if (align < _PAGESZ) + align = _PAGESZ; /* ie. 0x00004000 */ + switch (space) { case PCIIO_SPACE_IO: - base = (pci_io_fb + align - 1) & mask; - if ((base + size) > pci_io_fl) { - base = 0; - break; - } - pci_io_fb = base + size; + base = pcibr_bus_addr_alloc(pcibr_soft, + &pcibr_info->f_window[win], + PCIIO_SPACE_IO, + 0, size, align); + if (!base) + rc = ENOSPC; break; case PCIIO_SPACE_MEM: -#ifdef SN1_LITTLE_ENDIAN - if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) == -#else - if ((wptr[win] & PCI_BA_MEM_LOCATION) == -#endif /* LITTLE_ENDIAN */ - PCI_BA_MEM_1MEG) { + if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4) & + PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) { + /* allocate from 20-bit PCI space */ - base = (pci_lo_fb + align - 1) & mask; - if ((base + size) > pci_lo_fl) { - base = 0; - break; - } - pci_lo_fb = base + size; + base = pcibr_bus_addr_alloc(pcibr_soft, + &pcibr_info->f_window[win], + PCIIO_SPACE_MEM, + 0, size, align); + if (!base) + rc = ENOSPC; } else { /* allocate from 32-bit or 64-bit PCI space */ - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) { - base = 0; - break; - } - pci_hi_fb = base + size; + base = pcibr_bus_addr_alloc(pcibr_soft, + &pcibr_info->f_window[win], + PCIIO_SPACE_MEM32, + 0, size, align); + if (!base) + rc = ENOSPC; } break; default: base = 0; -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d window %d had bad space code %d\n", - slot, win, space); -#endif + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, + "pcibr_slot_addr_space_init: slot=%d, window %d " + "had bad space code %d\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space)); } pcibr_info->f_window[win].w_base = base; -#ifdef SN1_LITTLE_ENDIAN - wptr[((win*4)^4)/4] = base; -#if DEBUG && PCI_DEBUG - printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); -#endif -#else - wptr[win] = base; -#endif /* LITTLE_ENDIAN */ + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, base); -#if DEBUG && PCI_DEBUG - if (base >= size) - printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n", - slot, func, win, space, base, base + size - 1); - else - printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n", - slot, func, win, size, space); -#endif +#if defined(SUPPORT_PRINTING_R_FORMAT) + if (pcibr_debug_mask & PCIBR_DEBUG_BAR) { + if (base >= size) { + sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func=" + "%d, win %d is in %r[0x%x..0x%x], " + "allocated by pcibr\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + func, win, space, space_desc, base, + base + size - 1); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, + "%s",tmp_str)); + } + else { + sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func=" + "%d, win %d, unable to alloc 0x%x in %r\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + func, win, size, space, space_desc); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, + "%s",tmp_str)); + } + } +#endif /* SUPPORT_PRINTING_R_FORMAT */ } /* next base */ /* @@ -1055,40 +1430,29 @@ (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { wptr = cfgw + PCI_EXPANSION_ROM / 4; -#ifdef SN1_LITTLE_ENDIAN - wptr[1] = 0xFFFFF000; - mask = wptr[1]; -#else - *wptr = 0xFFFFF000; - mask = *wptr; -#endif /* LITTLE_ENDIAN */ + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, 0xFFFFF000); + mask = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4); if (mask & 0xFFFFF000) { size = mask & -mask; - align = size; - if (align < _PAGESZ) - align = _PAGESZ; - mask = -align; - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) - base = size = 0; + base = pcibr_bus_addr_alloc(pcibr_soft, + &pcibr_info->f_rwindow, + PCIIO_SPACE_MEM32, + 0, size, align); + if (!base) + rc = ENOSPC; else { - pci_hi_fb = base + size; -#ifdef SN1_LITTLE_ENDIAN - wptr[1] = base; -#else - *wptr = base; -#endif /* LITTLE_ENDIAN */ -#if DEBUG && PCI_DEBUG - printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n", - pcibr_soft->bs_name, slot, - base, base + size - 1); -#endif + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, base); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, + "pcibr_slot_addr_space_init: slot=%d, func=%d, " + "ROM in [0x%X..0x%X], allocated by pcibr\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + func, base, base + size - 1)); } } } pcibr_info->f_rbase = base; pcibr_info->f_rsize = size; - + /* * if necessary, update the board's * command register to enable decoding @@ -1116,30 +1480,25 @@ pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; - pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; - pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p; + pci_cfg_cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + #if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) fast_back_to_back_enable = 0; #endif pci_cfg_cmd_reg &= 0xFFFF; if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) - *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add; - + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, + pci_cfg_cmd_reg | pci_cfg_cmd_reg_add); } /* next func */ - - /* Now that we have allocated new chunks of PCI address spaces to this - * card we need to update the bookkeeping values which indicate - * the current PCI address space allocations. - */ - PCI_ADDR_SPACE_LIMITS_STORE(); - return(0); + return(rc); } /* * pcibr_slot_device_init * Setup the device register in the bridge for this PCI slot. */ + int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) @@ -1150,7 +1509,10 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + if (!pcibr_soft) + return(EINVAL); + + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); bridge = pcibr_soft->bs_base; @@ -1161,21 +1523,26 @@ */ devreg = bridge->b_device[slot].reg; devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; - devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; -#ifdef LITTLE_ENDIAN - devreg |= BRIDGE_DEV_DEV_SWAP; -#endif + + /* + * PIC WAR. PV# 855271 + * Don't enable virtual channels in the PIC by default. + * Can cause problems with 32-bit devices. (The bit is only intended + * for 64-bit devices). We set the bit in pcibr_try_set_device() + * if we're 64-bit and requesting virtual channels. + */ + if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) + devreg |= BRIDGE_DEV_COH; + else + devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; pcibr_soft->bs_slot[slot].bss_device = devreg; bridge->b_device[slot].reg = devreg; -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg); -#endif - -#if DEBUG && PCI_DEBUG - printk("pcibr: PCI space allocation done.\n"); +#ifdef PIC_LATER + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl, + "pcibr_slot_device_init: Device(%d): %R\n", + slot, devreg, device_bits)); #endif - return(0); } @@ -1194,7 +1561,10 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + if (!pcibr_soft) + return(EINVAL); + + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(EINVAL); slotp = &pcibr_soft->bs_slot[slot]; @@ -1259,17 +1629,25 @@ pcibr_info_t pcibr_info; async_attach_t aa = NULL; int func; - devfs_handle_t xconn_vhdl,conn_vhdl; + devfs_handle_t xconn_vhdl, conn_vhdl; +#ifdef PIC_LATER + devfs_handle_t scsi_vhdl; +#endif int nfunc; int error_func; int error_slot = 0; int error = ENODEV; +#ifdef PIC_LATER + int hwg_err; +#endif pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + if (!pcibr_soft) return(EINVAL); + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) + return(EINVAL); if (pcibr_soft->bs_slot[slot].has_host) { return(EPERM); @@ -1303,6 +1681,40 @@ error_func = pciio_device_attach(conn_vhdl, drv_flags); +#ifdef PIC_LATER + /* + * Try to assign well-known SCSI controller numbers for hot-plug + * insert + */ + if (drv_flags) { + + hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/0", + &scsi_vhdl, NULL); + + if (hwg_err == GRAPH_SUCCESS) + scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl); + + /* scsi_vhdl will be the final vertex in either the complete path + * on success or a partial path on failure; in either case, + * unreference that vertex. + */ + hwgraph_vertex_unref(scsi_vhdl); + + hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/1", + &scsi_vhdl, NULL); + + if (hwg_err == GRAPH_SUCCESS) + scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl); + + /* scsi_vhdl will be the final vertex in either the complete path + * on success or a partial path on failure; in either case, + * unreference that vertex. + */ + hwgraph_vertex_unref(scsi_vhdl); + + } +#endif /* PIC_LATER */ + pcibr_info->f_att_det_error = error_func; if (error_func) @@ -1313,9 +1725,12 @@ } /* next func */ if (error) { - if ((error != ENODEV) && (error != EUNATCH)) + if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) { + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; + } } else { + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; } @@ -1344,14 +1759,13 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) + if (!pcibr_soft) return(EINVAL); - if (pcibr_soft->bs_slot[slot].has_host) - return(EPERM); + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) + return(EINVAL); - /* Make sure that we do not detach a system critical function vertex */ - if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + if (pcibr_soft->bs_slot[slot].has_host) return(EPERM); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; @@ -1367,6 +1781,14 @@ if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) continue; + if (IS_PCIX(pcibr_soft) && pcibr_info->f_pcix_cap) { + int max_out; + + pcibr_soft->bs_pcix_num_funcs--; + max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split; + pcibr_soft->bs_pcix_split_tot -= max_splittrans_to_numbuf[max_out]; + } + conn_vhdl = pcibr_info->f_vertex; error_func = pciio_device_detach(conn_vhdl, drv_flags); @@ -1380,22 +1802,22 @@ } /* next func */ - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; if (error) { - if ((error != ENODEV) && (error != EUNATCH)) + if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) { + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; + } } else { if (conn_vhdl != GRAPH_VERTEX_NONE) pcibr_device_unregister(conn_vhdl); + pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; } return(error); } -#ifdef LATER - /* * pcibr_slot_attach * This is a place holder routine to keep track of all the @@ -1411,81 +1833,16 @@ int *sub_errorp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); +#ifdef PIC_LATER timespec_t ts; - int error; - - if (!(pcibr_soft->bs_slot[slot].slot_status & SLOT_POWER_UP)) { - /* Power-up the slot */ - error = pcibr_slot_pwr(pcibr_vhdl, slot, L1_REQ_PCI_UP, l1_msg); - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_L1_ERR); - } else { - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_POWER_MASK; - pcibr_soft->bs_slot[slot].slot_status |= SLOT_POWER_UP; - } - -#ifdef LATER - /* - * Allow cards like the Alteon Gigabit Ethernet Adapter to complete - * on-card initialization following the slot reset - */ - ts.tv_sec = 0; /* 0 secs */ - ts.tv_nsec = 500 * (1000 * 1000); /* 500 msecs */ - nano_delay(&ts); -#else -#endif -#if 0 - /* Reset the slot */ - error = pcibr_slot_reset(pcibr_vhdl, slot) - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_RESET_ERR); - } #endif + int error; - /* Find out what is out there */ - error = pcibr_slot_info_init(pcibr_vhdl, slot); - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_INFO_INIT_ERR); - } - - /* Set up the address space for this slot in the PCI land */ - error = pcibr_slot_addr_space_init(pcibr_vhdl, slot); - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_ADDR_INIT_ERR); - } - - /* Setup the device register */ - error = pcibr_slot_device_init(pcibr_vhdl, slot); - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_DEV_INIT_ERR); - } - - /* Setup host/guest relations */ - error = pcibr_slot_guest_info_init(pcibr_vhdl, slot); - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_GUEST_INIT_ERR); - } - - /* Initial RRB management */ - error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_RRB_ALLOC_ERR); - } - + /* Do not allow a multi-function card to be hot-plug inserted */ + if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) { + if (sub_errorp) + *sub_errorp = EPERM; + return(PCI_MULTI_FUNC_ERR); } /* Call the device attach */ @@ -1501,7 +1858,6 @@ return(0); } -#endif /* LATER */ /* * pcibr_slot_detach @@ -1511,13 +1867,42 @@ int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, - int drv_flags) + int drv_flags, + char *l1_msg, + int *sub_errorp) { + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); int error; + /* Make sure that we do not detach a system critical function vertex */ + if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) + return(PCI_IS_SYS_CRITICAL); + /* Call the device detach function */ error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); - return (error); + if (error) { + if (sub_errorp) + *sub_errorp = error; + return(PCI_SLOT_DRV_DETACH_ERR); + } + + /* Recalculate the RBARs for all the devices on the bus since we've + * just freed some up and some of the devices could use them. + */ + if (IS_PCIX(pcibr_soft)) { + int tmp_slot; + + pcibr_soft->bs_pcix_rbar_inuse = 0; + pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; + pcibr_soft->bs_pcix_rbar_percent_allowed = + pcibr_pcix_rbars_calc(pcibr_soft); + + for (tmp_slot = pcibr_soft->bs_min_slot; + tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot) + (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot); + } + + return (0); } @@ -1540,11 +1925,14 @@ devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; int nfunc; int func; - boolean_t is_sys_critical_vertex(devfs_handle_t); + boolean_t is_sys_critical_vertex(devfs_handle_t); pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(0); + if (!pcibr_soft) + return(EINVAL); + + if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) + return(EINVAL); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; @@ -1574,57 +1962,112 @@ } /* - * pcibr_probe_slot: read a config space word - * while trapping any errors; reutrn zero if + * pcibr_probe_slot_pic: read a config space word + * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. * The value read, if any, is passed back * through the valp parameter. */ -int -pcibr_probe_slot(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) +static int +pcibr_probe_slot_pic(bridge_t *bridge, + cfg_p cfg, + unsigned *valp) { - int rv; - bridgereg_t old_enable, new_enable; - int badaddr_val(volatile void *, int, volatile void *); - - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + int rv; + picreg_t p_old_enable = (picreg_t)0, p_new_enable; + extern int badaddr_val(volatile void *, int, volatile void *); + + p_old_enable = bridge->p_int_enable_64; + p_new_enable = p_old_enable & ~(BRIDGE_IMR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT); + bridge->p_int_enable_64 = p_new_enable; + + if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) + bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR; + + if (bridge->p_int_status_64 & (BRIDGE_IRR_PCI_GRP | PIC_PCIX_GRP_CLR)) { + bridge->p_int_rst_stat_64 = (BRIDGE_IRR_PCI_GRP_CLR | PIC_PCIX_GRP_CLR); + (void) bridge->b_wid_tflush; /* flushbus */ + } + rv = badaddr_val((void *) cfg, 4, valp); + if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) { + bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR; + rv = 1; /* unoccupied slot */ + } + bridge->p_int_enable_64 = p_old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + return(rv); +} - bridge->b_int_enable = new_enable; +/* + * pcibr_probe_slot_non_pic: read a config space word + * while trapping any errors; return zero if + * all went OK, or nonzero if there was an error. + * The value read, if any, is passed back + * through the valp parameter. + */ +static int +pcibr_probe_slot_non_pic(bridge_t *bridge, + cfg_p cfg, + unsigned *valp) +{ + int rv; + bridgereg_t b_old_enable = (bridgereg_t)0, b_new_enable = (bridgereg_t)0; + extern int badaddr_val(volatile void *, int, volatile void *); + + b_old_enable = bridge->b_int_enable; + b_new_enable = b_old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + bridge->b_int_enable = b_new_enable; /* * The xbridge doesn't clear b_err_int_view unless * multi-err is cleared... */ - if (is_xbridge(bridge)) - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { + if (is_xbridge(bridge)) { + if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - } - - if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { - bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; - (void) bridge->b_wid_tflush; /* flushbus */ - } - rv = badaddr_val((void *) cfg, 4, valp); + } + if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { + bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; + (void) bridge->b_wid_tflush; /* flushbus */ + } + rv = badaddr_val((void *) (((uint64_t)cfg) ^ 4), 4, valp); /* * The xbridge doesn't set master timeout in b_int_status * here. Fortunately it's in error_interrupt_view. */ - if (is_xbridge(bridge)) + if (is_xbridge(bridge)) { if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; rv = 1; /* unoccupied slot */ } + } + bridge->b_int_enable = b_old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + + return(rv); +} - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - return rv; +/* + * pcibr_probe_slot: read a config space word + * while trapping any errors; return zero if + * all went OK, or nonzero if there was an error. + * The value read, if any, is passed back + * through the valp parameter. + */ +static int +pcibr_probe_slot(bridge_t *bridge, + cfg_p cfg, + unsigned *valp) +{ + if ( is_pic(bridge) ) + return(pcibr_probe_slot_pic(bridge, cfg, valp)); + else + return(pcibr_probe_slot_non_pic(bridge, cfg, valp)); } + void pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) { @@ -1632,10 +2075,13 @@ pcibr_info_t pcibr_info; pciio_function_t func; pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; + bridge_t *bridge = pcibr_soft->bs_base; + cfg_p cfgw; int nfunc = slotp->bss_ninfo; int bar; int devio_index; int s; + unsigned cmd_reg; for (func = 0; func < nfunc; func++) { @@ -1646,10 +2092,19 @@ s = pcibr_lock(pcibr_soft); + /* Disable memory and I/O BARs */ + cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); + cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE); + do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, cmd_reg); + for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) { if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE) continue; + /* Free the PCI bus space */ + pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_window[bar]); + /* Get index of the DevIO(x) register used to access this BAR */ devio_index = pcibr_info->f_window[bar].w_devio_index; @@ -1664,6 +2119,11 @@ } } + /* Free the Expansion ROM PCI bus space */ + if(pcibr_info->f_rbase && pcibr_info->f_rsize) { + pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_rwindow); + } + pcibr_unlock(pcibr_soft, s); slotp->bss_infos[func] = 0; @@ -1689,4 +2149,69 @@ slotp->bss_cmd_pointer = 0; slotp->bss_cmd_shadow = 0; +} + + +iopaddr_t +pcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p, + pciio_space_t space, int start, int size, int align) +{ + pciio_win_map_t win_map_p; + + switch (space) { + + case PCIIO_SPACE_IO: + win_map_p = &pcibr_soft->bs_io_win_map; + break; + + case PCIIO_SPACE_MEM: + win_map_p = &pcibr_soft->bs_swin_map; + break; + + case PCIIO_SPACE_MEM32: + win_map_p = &pcibr_soft->bs_mem_win_map; + break; + + default: + return 0; + + } + return pciio_device_win_alloc(win_map_p, + win_info_p + ? &win_info_p->w_win_alloc + : NULL, + start, size, align); +} + + +void +pciibr_bus_addr_free(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p) +{ + pciio_device_win_free(&win_info_p->w_win_alloc); +} + +/* + * given a vertex_hdl to the pcibr_vhdl, return the brick's bus number + * associated with that vertex_hdl. The true mapping happens from the + * io_brick_tab[] array defined in ml/SN/iograph.c + */ +int +pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl) +{ + pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); + xwidgetnum_t widget = pcibr_soft->bs_xid; + int bricktype = pcibr_soft->bs_bricktype; + int bus = pcibr_soft->bs_busnum; + + /* + * For PIC there are 2 busses per widget and pcibr_soft->bs_busnum + * will be 0 or 1. For [X]BRIDGE there is 1 bus per widget and + * pcibr_soft->bs_busnum will always be zero. So we add bs_busnum + * to what io_brick_map_widget returns to get the bus number. + */ + if ((bus += io_brick_map_widget(bricktype, widget)) > 0) { + return bus; + } else { + return 0; + } } diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pciio.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pciio.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pciio.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pciio.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1877 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#define USRPCI 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Must be before iograph.h to get MAX_PORT_NUM */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64 +#define rmallocmap atemapalloc +#define rmfreemap atemapfree +#define rmfree atefree +#define rmalloc atealloc +#endif + +#define DEBUG_PCIIO +#undef DEBUG_PCIIO /* turn this on for yet more console output */ + + +#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) +#define DO_DEL(ptr) (kfree(ptr)) + +char pciio_info_fingerprint[] = "pciio_info"; + +cdl_p pciio_registry = NULL; + +int +badaddr_val(volatile void *addr, int len, volatile void *ptr) +{ + int ret = 0; + volatile void *new_addr; + + switch (len) { + case 4: + new_addr = (void *) addr; + ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); + break; + default: + printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); + } + + if (ret < 0) + panic("badaddr_val: unexpected status (%d) in probing", ret); + return(ret); + +} + + +nasid_t +get_console_nasid(void) +{ + extern nasid_t console_nasid; + extern nasid_t master_baseio_nasid; + + if (console_nasid < 0) { + console_nasid = ia64_sn_get_console_nasid(); + if (console_nasid < 0) { +// ZZZ What do we do if we don't get a console nasid on the hardware???? + if (IS_RUNNING_ON_SIMULATOR() ) + console_nasid = master_baseio_nasid; + } + } + return console_nasid; +} + +nasid_t +get_master_baseio_nasid(void) +{ + extern nasid_t master_baseio_nasid; + extern char master_baseio_wid; + + if (master_baseio_nasid < 0) { + nasid_t tmp; + + master_baseio_nasid = ia64_sn_get_master_baseio_nasid(); + + if ( master_baseio_nasid >= 0 ) { + master_baseio_wid = WIDGETID_GET(KL_CONFIG_CH_CONS_INFO(master_baseio_nasid)->memory_base); + } + } + return master_baseio_nasid; +} + +int +hub_dma_enabled(devfs_handle_t xconn_vhdl) +{ + return(0); +} + +int +hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) +{ + return(0); +} + +void +ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror) +{ +} + +/****** + ****** end hack defines ...... + ******/ + + + + +/* ===================================================================== + * PCI Generic Bus Provider + * Implement PCI provider operations. The pciio* layer provides a + * platform-independent interface for PCI devices. This layer + * switches among the possible implementations of a PCI adapter. + */ + +/* ===================================================================== + * Provider Function Location SHORTCUT + * + * On platforms with only one possible PCI provider, macros can be + * set up at the top that cause the table lookups and indirections to + * completely disappear. + */ + + +/* ===================================================================== + * Function Table of Contents + */ + +#if !defined(DEV_FUNC) +static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev); +#endif + +pciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +void pciio_piomap_free(pciio_piomap_t); +caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t); + +void pciio_piomap_done(pciio_piomap_t); +caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); + +iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); +void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); + +pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +void pciio_dmamap_free(pciio_dmamap_t); +iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); +alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned); +void pciio_dmamap_done(pciio_dmamap_t); +iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +void pciio_dmamap_drain(pciio_dmamap_t); +void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); +void pciio_dmalist_drain(devfs_handle_t, alenlist_t); +iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); + +pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +void pciio_intr_free(pciio_intr_t); +int pciio_intr_connect(pciio_intr_t, intr_func_t, intr_arg_t); +void pciio_intr_disconnect(pciio_intr_t); +devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); + +void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); + +void pciio_provider_startup(devfs_handle_t); +void pciio_provider_shutdown(devfs_handle_t); + +pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); +pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t); +devfs_handle_t pciio_intr_dev_get(pciio_intr_t); + +devfs_handle_t pciio_pio_dev_get(pciio_piomap_t); +pciio_slot_t pciio_pio_slot_get(pciio_piomap_t); +pciio_space_t pciio_pio_space_get(pciio_piomap_t); +iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t); +ulong pciio_pio_mapsz_get(pciio_piomap_t); +caddr_t pciio_pio_kvaddr_get(pciio_piomap_t); + +devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t); +pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t); + +pciio_info_t pciio_info_chk(devfs_handle_t); +pciio_info_t pciio_info_get(devfs_handle_t); +void pciio_info_set(devfs_handle_t, pciio_info_t); +devfs_handle_t pciio_info_dev_get(pciio_info_t); +pciio_slot_t pciio_info_slot_get(pciio_info_t); +pciio_function_t pciio_info_function_get(pciio_info_t); +pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t); +pciio_device_id_t pciio_info_device_id_get(pciio_info_t); +devfs_handle_t pciio_info_master_get(pciio_info_t); +arbitrary_info_t pciio_info_mfast_get(pciio_info_t); +pciio_provider_t *pciio_info_pops_get(pciio_info_t); +error_handler_f *pciio_info_efunc_get(pciio_info_t); +error_handler_arg_t *pciio_info_einfo_get(pciio_info_t); +pciio_space_t pciio_info_bar_space_get(pciio_info_t, int); +iopaddr_t pciio_info_bar_base_get(pciio_info_t, int); +size_t pciio_info_bar_size_get(pciio_info_t, int); +iopaddr_t pciio_info_rom_base_get(pciio_info_t); +size_t pciio_info_rom_size_get(pciio_info_t); + +void pciio_init(void); +int pciio_attach(devfs_handle_t); + +void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns); +void pciio_provider_unregister(devfs_handle_t); +pciio_provider_t *pciio_provider_fns_get(devfs_handle_t); + +int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned); +void pciio_driver_unregister(char *driver_prefix); + +devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); + +void pciio_device_unregister(devfs_handle_t); +pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +void pciio_device_info_free(pciio_info_t); +devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); +void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); +int pciio_device_attach(devfs_handle_t, int); +int pciio_device_detach(devfs_handle_t, int); +void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); + +int pciio_reset(devfs_handle_t); +int pciio_write_gather_flush(devfs_handle_t); +int pciio_slot_inuse(devfs_handle_t); + +/* ===================================================================== + * Provider Function Location + * + * If there is more than one possible provider for + * this platform, we need to examine the master + * vertex of the current vertex for a provider + * function structure, and indirect through the + * appropriately named member. + */ + +#if !defined(DEV_FUNC) + +static pciio_provider_t * +pciio_to_provider_fns(devfs_handle_t dev) +{ + pciio_info_t card_info; + pciio_provider_t *provider_fns; + + /* + * We're called with two types of vertices, one is + * the bridge vertex (ends with "pci") and the other is the + * pci slot vertex (ends with "pci/[0-8]"). For the first type + * we need to get the provider from the PFUNCS label. For + * the second we get it from fastinfo/c_pops. + */ + provider_fns = pciio_provider_fns_get(dev); + if (provider_fns == NULL) { + card_info = pciio_info_get(dev); + if (card_info != NULL) { + provider_fns = pciio_info_pops_get(card_info); + } + } + + if (provider_fns == NULL) +#if defined(SUPPORT_PRINTING_V_FORMAT) + PRINT_PANIC("%v: provider_fns == NULL", dev); +#else + PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev); +#endif + + return provider_fns; + +} + +#define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func +#define CAST_PIOMAP(x) ((pciio_piomap_t)(x)) +#define CAST_DMAMAP(x) ((pciio_dmamap_t)(x)) +#define CAST_INTR(x) ((pciio_intr_t)(x)) +#endif + +/* + * Many functions are not passed their vertex + * information directly; rather, they must + * dive through a resource map. These macros + * are available to coordinate this detail. + */ +#define PIOMAP_FUNC(map,func) DEV_FUNC((map)->pp_dev,func) +#define DMAMAP_FUNC(map,func) DEV_FUNC((map)->pd_dev,func) +#define INTR_FUNC(intr_hdl,func) DEV_FUNC((intr_hdl)->pi_dev,func) + +/* ===================================================================== + * PIO MANAGEMENT + * + * For mapping system virtual address space to + * pciio space on a specified card + */ + +pciio_piomap_t +pciio_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ + iopaddr_t addr, /* lowest address (or offset in window) */ + size_t byte_count, /* size of region containing our mappings */ + size_t byte_count_max, /* maximum size of a mapping */ + unsigned flags) +{ /* defined in sys/pio.h */ + return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc) + (dev, dev_desc, space, addr, byte_count, byte_count_max, flags); +} + +void +pciio_piomap_free(pciio_piomap_t pciio_piomap) +{ + PIOMAP_FUNC(pciio_piomap, piomap_free) + (CAST_PIOMAP(pciio_piomap)); +} + +caddr_t +pciio_piomap_addr(pciio_piomap_t pciio_piomap, /* mapping resources */ + iopaddr_t pciio_addr, /* map for this pciio address */ + size_t byte_count) +{ /* map this many bytes */ + pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr) + (CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count); + + return pciio_piomap->pp_kvaddr; +} + +void +pciio_piomap_done(pciio_piomap_t pciio_piomap) +{ + PIOMAP_FUNC(pciio_piomap, piomap_done) + (CAST_PIOMAP(pciio_piomap)); +} + +caddr_t +pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ + iopaddr_t addr, /* starting address (or offset in window) */ + size_t byte_count, /* map this many bytes */ + unsigned flags) +{ /* (currently unused) */ + return DEV_FUNC(dev, piotrans_addr) + (dev, dev_desc, space, addr, byte_count, flags); +} + +caddr_t +pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ + iopaddr_t addr, /* starting address (or offset in window) */ + size_t byte_count, /* map this many bytes */ + pciio_piomap_t *mapp, /* where to return the map pointer */ + unsigned flags) +{ /* PIO flags */ + pciio_piomap_t map = 0; + int errfree = 0; + caddr_t res; + + if (mapp) { + map = *mapp; /* possible pre-allocated map */ + *mapp = 0; /* record "no map used" */ + } + + res = pciio_piotrans_addr + (dev, dev_desc, space, addr, byte_count, flags); + if (res) + return res; /* pciio_piotrans worked */ + + if (!map) { + map = pciio_piomap_alloc + (dev, dev_desc, space, addr, byte_count, byte_count, flags); + if (!map) + return res; /* pciio_piomap_alloc failed */ + errfree = 1; + } + + res = pciio_piomap_addr + (map, addr, byte_count); + if (!res) { + if (errfree) + pciio_piomap_free(map); + return res; /* pciio_piomap_addr failed */ + } + if (mapp) + *mapp = map; /* pass back map used */ + + return res; /* pciio_piomap_addr succeeded */ +} + +iopaddr_t +pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ + device_desc_t dev_desc, /* Device descriptor */ + pciio_space_t space, /* MEM32/MEM64/IO */ + size_t byte_count, /* Size of mapping */ + size_t align) +{ /* Alignment needed */ + if (align < NBPP) + align = NBPP; + return DEV_FUNC(dev, piospace_alloc) + (dev, dev_desc, space, byte_count, align); +} + +void +pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ + pciio_space_t space, /* Type of space */ + iopaddr_t pciaddr, /* starting address */ + size_t byte_count) +{ /* Range of address */ + DEV_FUNC(dev, piospace_free) + (dev, space, pciaddr, byte_count); +} + +/* ===================================================================== + * DMA MANAGEMENT + * + * For mapping from pci space to system + * physical space. + */ + +pciio_dmamap_t +pciio_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ + device_desc_t dev_desc, /* device descriptor */ + size_t byte_count_max, /* max size of a mapping */ + unsigned flags) +{ /* defined in dma.h */ + return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) + (dev, dev_desc, byte_count_max, flags); +} + +void +pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_free) + (CAST_DMAMAP(pciio_dmamap)); +} + +iopaddr_t +pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ + paddr_t paddr, /* map for this address */ + size_t byte_count) +{ /* map this many bytes */ + return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) + (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); +} + +alenlist_t +pciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ + alenlist_t alenlist, /* map this Address/Length List */ + unsigned flags) +{ + return DMAMAP_FUNC(pciio_dmamap, dmamap_list) + (CAST_DMAMAP(pciio_dmamap), alenlist, flags); +} + +void +pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_done) + (CAST_DMAMAP(pciio_dmamap)); +} + +iopaddr_t +pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_addr) + (dev, dev_desc, paddr, byte_count, flags); +} + +alenlist_t +pciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + alenlist_t palenlist, /* system address/length list */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_list) + (dev, dev_desc, palenlist, flags); +} + +iopaddr_t +pciio_dma_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + pciio_dmamap_t *mapp, /* map to use, then map we used */ + unsigned flags) +{ /* PIO flags */ + pciio_dmamap_t map = 0; + int errfree = 0; + iopaddr_t res; + + if (mapp) { + map = *mapp; /* possible pre-allocated map */ + *mapp = 0; /* record "no map used" */ + } + + res = pciio_dmatrans_addr + (dev, dev_desc, paddr, byte_count, flags); + if (res) + return res; /* pciio_dmatrans worked */ + + if (!map) { + map = pciio_dmamap_alloc + (dev, dev_desc, byte_count, flags); + if (!map) + return res; /* pciio_dmamap_alloc failed */ + errfree = 1; + } + + res = pciio_dmamap_addr + (map, paddr, byte_count); + if (!res) { + if (errfree) + pciio_dmamap_free(map); + return res; /* pciio_dmamap_addr failed */ + } + if (mapp) + *mapp = map; /* pass back map used */ + + return res; /* pciio_dmamap_addr succeeded */ +} + +void +pciio_dmamap_drain(pciio_dmamap_t map) +{ + DMAMAP_FUNC(map, dmamap_drain) + (CAST_DMAMAP(map)); +} + +void +pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +{ + DEV_FUNC(dev, dmaaddr_drain) + (dev, addr, size); +} + +void +pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) +{ + DEV_FUNC(dev, dmalist_drain) + (dev, list); +} + +/* ===================================================================== + * INTERRUPT MANAGEMENT + * + * Allow crosstalk devices to establish interrupts + */ + +/* + * Allocate resources required for an interrupt as specified in intr_desc. + * Return resource handle in intr_hdl. + */ +pciio_intr_t +pciio_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + pciio_intr_line_t lines, /* INTR line(s) to attach */ + devfs_handle_t owner_dev) +{ /* owner of this interrupt */ + return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) + (dev, dev_desc, lines, owner_dev); +} + +/* + * Free resources consumed by intr_alloc. + */ +void +pciio_intr_free(pciio_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_free) + (CAST_INTR(intr_hdl)); +} + +/* + * Associate resources allocated with a previous pciio_intr_alloc call with the + * described handler, arg, name, etc. + * + * Returns 0 on success, returns <0 on failure. + */ +int +pciio_intr_connect(pciio_intr_t intr_hdl, + intr_func_t intr_func, intr_arg_t intr_arg) /* pciio intr resource handle */ +{ + return INTR_FUNC(intr_hdl, intr_connect) + (CAST_INTR(intr_hdl), intr_func, intr_arg); +} + +/* + * Disassociate handler with the specified interrupt. + */ +void +pciio_intr_disconnect(pciio_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_disconnect) + (CAST_INTR(intr_hdl)); +} + +/* + * Return a hwgraph vertex that represents the CPU currently + * targeted by an interrupt. + */ +devfs_handle_t +pciio_intr_cpu_get(pciio_intr_t intr_hdl) +{ + return INTR_FUNC(intr_hdl, intr_cpu_get) + (CAST_INTR(intr_hdl)); +} + +void +pciio_slot_func_to_name(char *name, + pciio_slot_t slot, + pciio_function_t func) +{ + /* + * standard connection points: + * + * PCIIO_SLOT_NONE: .../pci/direct + * PCIIO_FUNC_NONE: .../pci/ ie. .../pci/3 + * multifunction: .../pci/ ie. .../pci/3c + */ + + if (slot == PCIIO_SLOT_NONE) + sprintf(name, EDGE_LBL_DIRECT); + else if (func == PCIIO_FUNC_NONE) + sprintf(name, "%d", slot); + else + sprintf(name, "%d%c", slot, 'a'+func); +} + +/* + * pciio_cardinfo_get + * + * Get the pciio info structure corresponding to the + * specified PCI "slot" (we like it when the same index + * number is used for the PCI IDSEL, the REQ/GNT pair, + * and the interrupt line being used for INTA. We like + * it so much we call it the slot number). + */ +static pciio_info_t +pciio_cardinfo_get( + devfs_handle_t pciio_vhdl, + pciio_slot_t pci_slot) +{ + char namebuf[16]; + pciio_info_t info = 0; + devfs_handle_t conn; + + pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE); + if (GRAPH_SUCCESS == + hwgraph_traverse(pciio_vhdl, namebuf, &conn)) { + info = pciio_info_chk(conn); + hwgraph_vertex_unref(conn); + } + + return info; +} + + +/* + * pciio_error_handler: + * dispatch an error to the appropriate + * pciio connection point, or process + * it as a generic pci error. + * Yes, the first parameter is the + * provider vertex at the middle of + * the bus; we get to the pciio connect + * point using the ioerror widgetdev field. + * + * This function is called by the + * specific PCI provider, after it has figured + * out where on the PCI bus (including which slot, + * if it can tell) the error came from. + */ +/*ARGSUSED */ +int +pciio_error_handler( + devfs_handle_t pciio_vhdl, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioerror) +{ + pciio_info_t pciio_info; + devfs_handle_t pconn_vhdl; +#if USRPCI + devfs_handle_t usrpci_v; +#endif + pciio_slot_t slot; + + int retval; +#ifdef EHE_ENABLE + error_state_t e_state; +#endif /* EHE_ENABLE */ + +#if DEBUG && ERROR_DEBUG + printk("%v: pciio_error_handler\n", pciio_vhdl); +#endif + + IOERR_PRINTF(printk(KERN_NOTICE "%v: PCI Bus Error: Error code: %d Error mode: %d\n", + pciio_vhdl, error_code, mode)); + + /* If there is an error handler sitting on + * the "no-slot" connection point, give it + * first crack at the error. NOTE: it is + * quite possible that this function may + * do further refining of the ioerror. + */ + pciio_info = pciio_cardinfo_get(pciio_vhdl, PCIIO_SLOT_NONE); + if (pciio_info && pciio_info->c_efunc) { + pconn_vhdl = pciio_info_dev_get(pciio_info); + +#ifdef EHE_ENABLE + e_state = error_state_get(pciio_vhdl); + + if (e_state == ERROR_STATE_ACTION) + (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); + + if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE) + return(IOERROR_UNHANDLED); +#endif + + retval = pciio_info->c_efunc + (pciio_info->c_einfo, error_code, mode, ioerror); + if (retval != IOERROR_UNHANDLED) + return retval; + } + + /* Is the error associated with a particular slot? + */ + if (IOERROR_FIELDVALID(ioerror, widgetdev)) { + short widgetdev; + /* + * NOTE : + * widgetdev is a 4byte value encoded as slot in the higher order + * 2 bytes and function in the lower order 2 bytes. + */ + IOERROR_GETVALUE(widgetdev, ioerror, widgetdev); + slot = pciio_widgetdev_slot_get(widgetdev); + + /* If this slot has an error handler, + * deliver the error to it. + */ + pciio_info = pciio_cardinfo_get(pciio_vhdl, slot); + if (pciio_info != NULL) { + if (pciio_info->c_efunc != NULL) { + + pconn_vhdl = pciio_info_dev_get(pciio_info); + +#ifdef EHE_ENABLE + e_state = error_state_get(pciio_vhdl); + + if (e_state == ERROR_STATE_ACTION) + (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); + + if (error_state_set(pconn_vhdl,e_state) == + ERROR_RETURN_CODE_CANNOT_SET_STATE) + return(IOERROR_UNHANDLED); +#endif /* EHE_ENABLE */ + + retval = pciio_info->c_efunc + (pciio_info->c_einfo, error_code, mode, ioerror); + if (retval != IOERROR_UNHANDLED) + return retval; + } + +#if USRPCI + /* If the USRPCI driver is available and + * knows about this connection point, + * deliver the error to it. + * + * OK to use pconn_vhdl here, even though we + * have already UNREF'd it, since we know that + * it is not going away. + */ + pconn_vhdl = pciio_info_dev_get(pciio_info); + if (GRAPH_SUCCESS == hwgraph_traverse(pconn_vhdl, EDGE_LBL_USRPCI, &usrpci_v)) { + iopaddr_t busaddr; + IOERROR_GETVALUE(busaddr, ioerror, busaddr); + retval = usrpci_error_handler (usrpci_v, error_code, busaddr); + hwgraph_vertex_unref(usrpci_v); + if (retval != IOERROR_UNHANDLED) { + /* + * This unref is not needed. If this code is called often enough, + * the system will crash, due to vertex reference count reaching 0, + * causing vertex to be unallocated. -jeremy + * hwgraph_vertex_unref(pconn_vhdl); + */ + return retval; + } + } +#endif + } + } + + return (mode == MODE_DEVPROBE) + ? IOERROR_HANDLED /* probes are OK */ + : IOERROR_UNHANDLED; /* otherwise, foo! */ +} + +/* ===================================================================== + * CONFIGURATION MANAGEMENT + */ + +/* + * Startup a crosstalk provider + */ +void +pciio_provider_startup(devfs_handle_t pciio_provider) +{ + DEV_FUNC(pciio_provider, provider_startup) + (pciio_provider); +} + +/* + * Shutdown a crosstalk provider + */ +void +pciio_provider_shutdown(devfs_handle_t pciio_provider) +{ + DEV_FUNC(pciio_provider, provider_shutdown) + (pciio_provider); +} + +/* + * Specify endianness constraints. The driver tells us what the device + * does and how it would like to see things in memory. We reply with + * how things will actually appear in memory. + */ +pciio_endian_t +pciio_endian_set(devfs_handle_t dev, + pciio_endian_t device_end, + pciio_endian_t desired_end) +{ + ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE)); + ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE)); + +#if DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_ALERT "%v: pciio_endian_set is going away.\n" + "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" + "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", + dev); +#else + printk(KERN_ALERT "0x%x: pciio_endian_set is going away.\n" + "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" + "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", + dev); +#endif +#endif + + return DEV_FUNC(dev, endian_set) + (dev, device_end, desired_end); +} + +/* + * Specify PCI arbitration priority. + */ +pciio_priority_t +pciio_priority_set(devfs_handle_t dev, + pciio_priority_t device_prio) +{ + ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); + + return DEV_FUNC(dev, priority_set) + (dev, device_prio); +} + +/* + * Read value of configuration register + */ +uint64_t +pciio_config_get(devfs_handle_t dev, + unsigned reg, + unsigned size) +{ + uint64_t value = 0; + unsigned shift = 0; + + /* handle accesses that cross words here, + * since that's common code between all + * possible providers. + */ + while (size > 0) { + unsigned biw = 4 - (reg&3); + if (biw > size) + biw = size; + + value |= DEV_FUNC(dev, config_get) + (dev, reg, biw) << shift; + + shift += 8*biw; + reg += biw; + size -= biw; + } + return value; +} + +/* + * Change value of configuration register + */ +void +pciio_config_set(devfs_handle_t dev, + unsigned reg, + unsigned size, + uint64_t value) +{ + /* handle accesses that cross words here, + * since that's common code between all + * possible providers. + */ + while (size > 0) { + unsigned biw = 4 - (reg&3); + if (biw > size) + biw = size; + + DEV_FUNC(dev, config_set) + (dev, reg, biw, value); + reg += biw; + size -= biw; + value >>= biw * 8; + } +} + +/* ===================================================================== + * GENERIC PCI SUPPORT FUNCTIONS + */ + +/* + * Issue a hardware reset to a card. + */ +int +pciio_reset(devfs_handle_t dev) +{ + return DEV_FUNC(dev, reset) (dev); +} + +/* + * flush write gather buffers + */ +int +pciio_write_gather_flush(devfs_handle_t dev) +{ + return DEV_FUNC(dev, write_gather_flush) (dev); +} + +devfs_handle_t +pciio_intr_dev_get(pciio_intr_t pciio_intr) +{ + return (pciio_intr->pi_dev); +} + +/****** Generic crosstalk pio interfaces ******/ +devfs_handle_t +pciio_pio_dev_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_dev); +} + +pciio_slot_t +pciio_pio_slot_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_slot); +} + +pciio_space_t +pciio_pio_space_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_space); +} + +iopaddr_t +pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_pciaddr); +} + +ulong +pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_mapsz); +} + +caddr_t +pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap) +{ + return (pciio_piomap->pp_kvaddr); +} + +/****** Generic crosstalk dma interfaces ******/ +devfs_handle_t +pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap) +{ + return (pciio_dmamap->pd_dev); +} + +pciio_slot_t +pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap) +{ + return (pciio_dmamap->pd_slot); +} + +/****** Generic pci slot information interfaces ******/ + +pciio_info_t +pciio_info_chk(devfs_handle_t pciio) +{ + arbitrary_info_t ainfo = 0; + + hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo); + return (pciio_info_t) ainfo; +} + +pciio_info_t +pciio_info_get(devfs_handle_t pciio) +{ + pciio_info_t pciio_info; + + pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio); + +#ifdef DEBUG_PCIIO + { + int pos; + char dname[256]; + pos = devfs_generate_path(pciio, dname, 256); + printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); + } +#endif /* DEBUG_PCIIO */ + + if ((pciio_info != NULL) && + (pciio_info->c_fingerprint != pciio_info_fingerprint) + && (pciio_info->c_fingerprint != NULL)) { + + return((pciio_info_t)-1); /* Should panic .. */ + } + + + return pciio_info; +} + +void +pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) +{ + if (pciio_info != NULL) + pciio_info->c_fingerprint = pciio_info_fingerprint; + hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info); + + /* Also, mark this vertex as a PCI slot + * and use the pciio_info, so pciio_info_chk + * can work (and be fairly efficient). + */ + hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO, + (arbitrary_info_t) pciio_info); +} + +devfs_handle_t +pciio_info_dev_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_vertex); +} + +pciio_slot_t +pciio_info_slot_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_slot); +} + +pciio_function_t +pciio_info_function_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_func); +} + +pciio_vendor_id_t +pciio_info_vendor_id_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_vendor); +} + +pciio_device_id_t +pciio_info_device_id_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_device); +} + +devfs_handle_t +pciio_info_master_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_master); +} + +arbitrary_info_t +pciio_info_mfast_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_mfast); +} + +pciio_provider_t * +pciio_info_pops_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_pops); +} + +error_handler_f * +pciio_info_efunc_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_efunc); +} + +error_handler_arg_t * +pciio_info_einfo_get(pciio_info_t pciio_info) +{ + return (pciio_info->c_einfo); +} + +pciio_space_t +pciio_info_bar_space_get(pciio_info_t info, int win) +{ + return info->c_window[win].w_space; +} + +iopaddr_t +pciio_info_bar_base_get(pciio_info_t info, int win) +{ + return info->c_window[win].w_base; +} + +size_t +pciio_info_bar_size_get(pciio_info_t info, int win) +{ + return info->c_window[win].w_size; +} + +iopaddr_t +pciio_info_rom_base_get(pciio_info_t info) +{ + return info->c_rbase; +} + +size_t +pciio_info_rom_size_get(pciio_info_t info) +{ + return info->c_rsize; +} + + +/* ===================================================================== + * GENERIC PCI INITIALIZATION FUNCTIONS + */ + +/* + * pciioinit: called once during device driver + * initializtion if this driver is configured into + * the system. + */ +void +pciio_init(void) +{ + cdl_p cp; + +#if DEBUG && ATTACH_DEBUG + printf("pciio_init\n"); +#endif + /* Allocate the registry. + * We might already have one. + * If we don't, go get one. + * MPness: someone might have + * set one up for us while we + * were not looking; use an atomic + * compare-and-swap to commit to + * using the new registry if and + * only if nobody else did first. + * If someone did get there first, + * toss the one we allocated back + * into the pool. + */ + if (pciio_registry == NULL) { + cp = cdl_new(EDGE_LBL_PCI, "vendor", "device"); + if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) { + cdl_del(cp); + } + } + ASSERT(pciio_registry != NULL); +} + +/* + * pciioattach: called for each vertex in the graph + * that is a PCI provider. + */ +/*ARGSUSED */ +int +pciio_attach(devfs_handle_t pciio) +{ +#if DEBUG && ATTACH_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: pciio_attach\n", pciio); +#else + printk("0x%x: pciio_attach\n", pciio); +#endif +#endif + return 0; +} + +/* + * Associate a set of pciio_provider functions with a vertex. + */ +void +pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) +{ + hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); +} + +/* + * Disassociate a set of pciio_provider functions with a vertex. + */ +void +pciio_provider_unregister(devfs_handle_t provider) +{ + arbitrary_info_t ainfo; + + hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); +} + +/* + * Obtain a pointer to the pciio_provider functions for a specified Crosstalk + * provider. + */ +pciio_provider_t * +pciio_provider_fns_get(devfs_handle_t provider) +{ + arbitrary_info_t ainfo = 0; + + (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo); + return (pciio_provider_t *) ainfo; +} + +/*ARGSUSED4 */ +int +pciio_driver_register( + pciio_vendor_id_t vendor_id, + pciio_device_id_t device_id, + char *driver_prefix, + unsigned flags) +{ + /* a driver's init routine might call + * pciio_driver_register before the + * system calls pciio_init; so we + * make the init call ourselves here. + */ + if (pciio_registry == NULL) + pciio_init(); + + return cdl_add_driver(pciio_registry, + vendor_id, device_id, + driver_prefix, flags, NULL); +} + +/* + * Remove an initialization function. + */ +void +pciio_driver_unregister( + char *driver_prefix) +{ + /* before a driver calls unregister, + * it must have called register; so + * we can assume we have a registry here. + */ + ASSERT(pciio_registry != NULL); + + cdl_del_driver(pciio_registry, driver_prefix, NULL); +} + +/* + * Set the slot status for a device supported by the + * driver being registered. + */ +void +pciio_driver_reg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ +} + +/* + * Set the slot status for a device supported by the + * driver being unregistered. + */ +void +pciio_driver_unreg_callback( + devfs_handle_t pconn_vhdl, + int key1, + int key2, + int error) +{ +} + +/* + * Call some function with each vertex that + * might be one of this driver's attach points. + */ +void +pciio_iterate(char *driver_prefix, + pciio_iter_f * func) +{ + /* a driver's init routine might call + * pciio_iterate before the + * system calls pciio_init; so we + * make the init call ourselves here. + */ + if (pciio_registry == NULL) + pciio_init(); + + ASSERT(pciio_registry != NULL); + + cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func); +} + +devfs_handle_t +pciio_device_register( + devfs_handle_t connectpt, /* vertex for /hw/.../pciio/%d */ + devfs_handle_t master, /* card's master ASIC (PCI provider) */ + pciio_slot_t slot, /* card's slot */ + pciio_function_t func, /* card's func */ + pciio_vendor_id_t vendor_id, + pciio_device_id_t device_id) +{ + return pciio_device_info_register + (connectpt, pciio_device_info_new (NULL, master, slot, func, + vendor_id, device_id)); +} + +void +pciio_device_unregister(devfs_handle_t pconn) +{ + DEV_FUNC(pconn,device_unregister)(pconn); +} + +pciio_info_t +pciio_device_info_new( + pciio_info_t pciio_info, + devfs_handle_t master, + pciio_slot_t slot, + pciio_function_t func, + pciio_vendor_id_t vendor_id, + pciio_device_id_t device_id) +{ + if (!pciio_info) + GET_NEW(pciio_info); + ASSERT(pciio_info != NULL); + + pciio_info->c_slot = slot; + pciio_info->c_func = func; + pciio_info->c_vendor = vendor_id; + pciio_info->c_device = device_id; + pciio_info->c_master = master; + pciio_info->c_mfast = hwgraph_fastinfo_get(master); + pciio_info->c_pops = pciio_provider_fns_get(master); + pciio_info->c_efunc = 0; + pciio_info->c_einfo = 0; + + return pciio_info; +} + +void +pciio_device_info_free(pciio_info_t pciio_info) +{ + /* NOTE : pciio_info is a structure within the pcibr_info + * and not a pointer to memory allocated on the heap !! + */ + BZERO((char *)pciio_info,sizeof(pciio_info)); +} + +devfs_handle_t +pciio_device_info_register( + devfs_handle_t connectpt, /* vertex at center of bus */ + pciio_info_t pciio_info) /* details about the connectpt */ +{ + char name[32]; + devfs_handle_t pconn; + int device_master_set(devfs_handle_t, devfs_handle_t); + + pciio_slot_func_to_name(name, + pciio_info->c_slot, + pciio_info->c_func); + + if (GRAPH_SUCCESS != + hwgraph_path_add(connectpt, name, &pconn)) + return pconn; + + pciio_info->c_vertex = pconn; + pciio_info_set(pconn, pciio_info); +#ifdef DEBUG_PCIIO + { + int pos; + char dname[256]; + pos = devfs_generate_path(pconn, dname, 256); + printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); + } +#endif /* DEBUG_PCIIO */ + + /* + * create link to our pci provider + */ + + device_master_set(pconn, pciio_info->c_master); + +#if USRPCI + /* + * Call into usrpci provider to let it initialize for + * the given slot. + */ + if (pciio_info->c_slot != PCIIO_SLOT_NONE) + usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot); +#endif + + return pconn; +} + +void +pciio_device_info_unregister(devfs_handle_t connectpt, + pciio_info_t pciio_info) +{ + char name[32]; + devfs_handle_t pconn; + + if (!pciio_info) + return; + + pciio_slot_func_to_name(name, + pciio_info->c_slot, + pciio_info->c_func); + + hwgraph_edge_remove(connectpt,name,&pconn); + pciio_info_set(pconn,0); + + /* Remove the link to our pci provider */ + hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); + + + hwgraph_vertex_unref(pconn); + hwgraph_vertex_destroy(pconn); + +} +/* Add the pci card inventory information to the hwgraph + */ +static void +pciio_device_inventory_add(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + + ASSERT(pciio_info); + ASSERT(pciio_info->c_vertex == pconn_vhdl); + + /* Donot add inventory for non-existent devices */ + if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE) || + (pciio_info->c_device == PCIIO_DEVICE_ID_NONE)) + return; + device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP, + pciio_info->c_vendor,pciio_info->c_device, + pciio_info->c_slot); +} + +/*ARGSUSED */ +int +pciio_device_attach(devfs_handle_t pconn, + int drv_flags) +{ + pciio_info_t pciio_info; + pciio_vendor_id_t vendor_id; + pciio_device_id_t device_id; + + + pciio_device_inventory_add(pconn); + pciio_info = pciio_info_get(pconn); + + vendor_id = pciio_info->c_vendor; + device_id = pciio_info->c_device; + + /* we don't start attaching things until + * all the driver init routines (including + * pciio_init) have been called; so we + * can assume here that we have a registry. + */ + ASSERT(pciio_registry != NULL); + + return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); +} + +int +pciio_device_detach(devfs_handle_t pconn, + int drv_flags) +{ + pciio_info_t pciio_info; + pciio_vendor_id_t vendor_id; + pciio_device_id_t device_id; + + pciio_info = pciio_info_get(pconn); + + vendor_id = pciio_info->c_vendor; + device_id = pciio_info->c_device; + + /* we don't start attaching things until + * all the driver init routines (including + * pciio_init) have been called; so we + * can assume here that we have a registry. + */ + ASSERT(pciio_registry != NULL); + + return(cdl_del_connpt(pciio_registry, vendor_id, device_id, + pconn, drv_flags)); + +} + +/* SN2 */ +/* + * Allocate (if necessary) and initialize a PCI window mapping structure. + */ +pciio_win_map_t +pciio_device_win_map_new(pciio_win_map_t win_map, + size_t region_size, + size_t page_size) +{ + ASSERT((page_size & (page_size - 1)) == 0); + ASSERT((region_size & (page_size - 1)) == 0); + + if (win_map == NULL) + NEW(win_map); + + /* + * The map array tracks the free ``pages'' in the region. The worst + * case scenario is when every other page in the region is free -- + * e.i. maximum fragmentation. This leads to (max pages + 1) / 2 + 1 + * map entries. The first "+1" handles the divide by 2 rounding; the + * second handles the need for an end marker sentinel. + */ + win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1); + win_map->wm_page_size = page_size; + ASSERT(win_map->wm_map != NULL); + + return win_map; +} + +/* + * Free resources associated with a PCI window mapping structure. + */ +extern void +pciio_device_win_map_free(pciio_win_map_t win_map) +{ + rmfreemap(win_map->wm_map); + bzero(win_map, sizeof *win_map); +} + +/* + * Populate window map with specified free range. + */ +void +pciio_device_win_populate(pciio_win_map_t win_map, + iopaddr_t ioaddr, + size_t size) +{ + ASSERT((size & (win_map->wm_page_size - 1)) == 0); + ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0); + + rmfree(win_map->wm_map, + size / win_map->wm_page_size, + (unsigned long)ioaddr / win_map->wm_page_size); + +} +/* + * Allocate space from the specified PCI window mapping resource. On + * success record information about the allocation in the supplied window + * allocation cookie (if non-NULL) and return the address of the allocated + * window. On failure return NULL. + * + * The "size" parameter is usually from a PCI device's Base Address Register + * (BAR) decoder. As such, the allocation must be aligned to be a multiple of + * that. The "align" parameter acts as a ``minimum alignment'' allocation + * constraint. The alignment contraint reflects system or device addressing + * restrictions such as the inability to share higher level ``windows'' + * between devices, etc. The returned PCI address allocation will be a + * multiple of the alignment constraint both in alignment and size. Thus, the + * returned PCI address block is aligned to the maximum of the requested size + * and alignment. + */ +iopaddr_t +pciio_device_win_alloc(pciio_win_map_t win_map, + pciio_win_alloc_t win_alloc, + size_t start, size_t size, size_t align) +{ + unsigned long base; + +#ifdef PIC_LATER + ASSERT((size & (size - 1)) == 0); + ASSERT((align & (align - 1)) == 0); + + /* + * Convert size and alignment to pages. If size is greated than the + * requested alignment, we bump the alignment up to size; otherwise + * convert the size into a multiple of the alignment request. + */ + size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size; + align = align / win_map->wm_page_size; + if (size > align) + align = size; + else + size = (size + align - 1) & ~(align - 1); + + /* XXXX */ + base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP); + if (base == RMALLOC_FAIL) + return((iopaddr_t)NULL); +#else + int index_page, index_page_align; + int align_pages, size_pages; + int alloc_pages, free_pages; + int addr_align; + + /* Convert PCI bus alignment from bytes to pages */ + align_pages = align / win_map->wm_page_size; + + /* Convert PCI request from bytes to pages */ + size_pages = (size / win_map->wm_page_size) + + ((size % win_map->wm_page_size) ? 1 : 0); + + /* Align address with the larger of the size or the requested slot align */ + if (size_pages > align_pages) + align_pages = size_pages; + + /* + * Avoid wasting space by aligning - 1; this will prevent crossing + * another alignment boundary. + */ + alloc_pages = size_pages + (align_pages - 1); + + /* Allocate PCI bus space in pages */ + index_page = (int) rmalloc(win_map->wm_map, + (size_t) alloc_pages); + + /* Error if no PCI bus address space available */ + if (!index_page) + return 0; + + /* PCI bus address index starts at 0 */ + index_page--; + + /* Align the page offset as requested */ + index_page_align = (index_page + (align_pages - 1)) - + ((index_page + (align_pages - 1)) % align_pages); + + free_pages = (align_pages - 1) - (index_page_align - index_page); + + /* Free unused PCI bus pages adjusting the index to start at 1 */ + rmfree(win_map->wm_map, + free_pages, + (index_page_align + 1) + size_pages); + + /* Return aligned PCI bus space in bytes */ + addr_align = (index_page_align * win_map->wm_page_size); + base = index_page; + size = alloc_pages - free_pages; +#endif /* PIC_LATER */ + + /* + * If a window allocation cookie has been supplied, use it to keep + * track of all the allocated space assigned to this window. + */ + if (win_alloc) { + win_alloc->wa_map = win_map; + win_alloc->wa_base = base; + win_alloc->wa_pages = size; + } + + return base * win_map->wm_page_size; +} + +/* + * Free the specified window allocation back into the PCI window mapping + * resource. As noted above, we keep page addresses offset by 1 ... + */ +void +pciio_device_win_free(pciio_win_alloc_t win_alloc) +{ + if (win_alloc->wa_pages) + rmfree(win_alloc->wa_map->wm_map, + win_alloc->wa_pages, + win_alloc->wa_base); +} + +/* + * pciio_error_register: + * arrange for a function to be called with + * a specified first parameter plus other + * information when an error is encountered + * and traced to the pci slot corresponding + * to the connection point pconn. + * + * may also be called with a null function + * pointer to "unregister" the error handler. + * + * NOTE: subsequent calls silently overwrite + * previous data for this vertex. We assume that + * cooperating drivers, well, cooperate ... + */ +void +pciio_error_register(devfs_handle_t pconn, + error_handler_f *efunc, + error_handler_arg_t einfo) +{ + pciio_info_t pciio_info; + + pciio_info = pciio_info_get(pconn); + ASSERT(pciio_info != NULL); + pciio_info->c_efunc = efunc; + pciio_info->c_einfo = einfo; +} + +/* + * Check if any device has been found in this slot, and return + * true or false + * vhdl is the vertex for the slot + */ +int +pciio_slot_inuse(devfs_handle_t pconn_vhdl) +{ + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); + + ASSERT(pciio_info); + ASSERT(pciio_info->c_vertex == pconn_vhdl); + if (pciio_info->c_vendor) { + /* + * Non-zero value for vendor indicate + * a board being found in this slot. + */ + return 1; + } + return 0; +} + +int +pciio_dma_enabled(devfs_handle_t pconn_vhdl) +{ + return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); +} + +int +pciio_info_type1_get(pciio_info_t pci_info) +{ + return(0); +} + + +/* + * These are complementary Linux interfaces that takes in a pci_dev * as the + * first arguement instead of devfs_handle_t. + */ +iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); +pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); +void snia_pciio_dmamap_free(pciio_dmamap_t); +iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); +void snia_pciio_dmamap_done(pciio_dmamap_t); +pciio_endian_t snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, + pciio_endian_t desired_end); + +#include +EXPORT_SYMBOL(snia_pciio_dmatrans_addr); +EXPORT_SYMBOL(snia_pciio_dmamap_alloc); +EXPORT_SYMBOL(snia_pciio_dmamap_free); +EXPORT_SYMBOL(snia_pciio_dmamap_addr); +EXPORT_SYMBOL(snia_pciio_dmamap_done); +EXPORT_SYMBOL(snia_pciio_endian_set); + +int +snia_pcibr_rrb_alloc(struct pci_dev *pci_dev, + int *count_vchan0, + int *count_vchan1) +{ + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1); +} +EXPORT_SYMBOL(snia_pcibr_rrb_alloc); + +pciio_endian_t +snia_pciio_endian_set(struct pci_dev *pci_dev, + pciio_endian_t device_end, + pciio_endian_t desired_end) +{ + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + return DEV_FUNC(dev, endian_set) + (dev, device_end, desired_end); +} + +iopaddr_t +snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + unsigned flags) +{ /* defined in dma.h */ + + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + /* + * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be + * set. Otherwise, it must not be set. This applies to SN1 and SN2. + */ + return DEV_FUNC(dev, dmatrans_addr) + (dev, dev_desc, paddr, byte_count, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM); +} + +pciio_dmamap_t +snia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this device */ + device_desc_t dev_desc, /* device descriptor */ + size_t byte_count_max, /* max size of a mapping */ + unsigned flags) +{ /* defined in dma.h */ + + devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + + /* + * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be + * set. Otherwise, it must not be set. This applies to SN1 and SN2. + */ + return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) + (dev, dev_desc, byte_count_max, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM); +} + +void +snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_free) + (CAST_DMAMAP(pciio_dmamap)); +} + +iopaddr_t +snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ + paddr_t paddr, /* map for this address */ + size_t byte_count) +{ /* map this many bytes */ + return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) + (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); +} + +void +snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) +{ + DMAMAP_FUNC(pciio_dmamap, dmamap_done) + (CAST_DMAMAP(pciio_dmamap)); +} + diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/pic.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pic.c --- linux-2.4.19/arch/ia64/sn/io/sn2/pic.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/pic.c Mon Jan 13 20:39:24 2003 @@ -0,0 +1,325 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *bcopy(const char * src, char * dest, int count); + + +#define PCI_BUS_NO_1 1 + +int pic_devflag = D_MP; + +extern int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, int, pcibr_soft_t *); +extern void pcibr_driver_reg_callback(devfs_handle_t, int, int, int); +extern void pcibr_driver_unreg_callback(devfs_handle_t, int, int, int); + + +void +pic_init(void) +{ + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pic_init()\n")); + + xwidget_driver_register(PIC_WIDGET_PART_NUM_BUS0, + PIC_WIDGET_MFGR_NUM, + "pic_", + 0); +} + +/* + * copy inventory_t from conn_v to peer_conn_v + */ +int +pic_bus1_inventory_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v) +{ + inventory_t *pinv, *peer_pinv; + + if (hwgraph_info_get_LBL(conn_v, INFO_LBL_INVENT, + (arbitrary_info_t *)&pinv) == GRAPH_SUCCESS) + { + NEW(peer_pinv); + bcopy(pinv, peer_pinv, sizeof(inventory_t)); + if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_INVENT, + (arbitrary_info_t)peer_pinv) != GRAPH_SUCCESS) { + DEL(peer_pinv); + return 0; + } + return 1; + } + + printk("pic_bus1_inventory_dup: cannot get INFO_LBL_INVENT from 0x%lx\n ", + conn_v); + return 0; +} + +/* + * copy xwidget_info_t from conn_v to peer_conn_v + */ +int +pic_bus1_widget_info_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v, + cnodeid_t xbow_peer) +{ + xwidget_info_t widget_info, peer_widget_info; + char peer_path[256]; + char *p; + devfs_handle_t peer_hubv; + hubinfo_t peer_hub_info; + + /* get the peer hub's widgetid */ + peer_hubv = NODEPDA(xbow_peer)->node_vertex; + peer_hub_info = NULL; + hubinfo_get(peer_hubv, &peer_hub_info); + if (peer_hub_info == NULL) + return 0; + + if (hwgraph_info_get_LBL(conn_v, INFO_LBL_XWIDGET, + (arbitrary_info_t *)&widget_info) == GRAPH_SUCCESS) { + NEW(peer_widget_info); + peer_widget_info->w_vertex = peer_conn_v; + peer_widget_info->w_id = widget_info->w_id; + peer_widget_info->w_master = peer_hubv; + peer_widget_info->w_masterid = peer_hub_info->h_widgetid; + /* structure copy */ + peer_widget_info->w_hwid = widget_info->w_hwid; + peer_widget_info->w_efunc = 0; + peer_widget_info->w_einfo = 0; + peer_widget_info->w_name = kmalloc(strlen(peer_path) + 1, GFP_KERNEL); + strcpy(peer_widget_info->w_name, peer_path); + + if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_XWIDGET, + (arbitrary_info_t)peer_widget_info) != GRAPH_SUCCESS) { + DEL(peer_widget_info); + return 0; + } + + xwidget_info_set(peer_conn_v, peer_widget_info); + + return 1; + } + + printk("pic_bus1_widget_info_dup: " + "cannot get INFO_LBL_XWIDGET from 0x%lx\n", conn_v); + return 0; +} + +/* + * If this PIC is attached to two Cbricks ("dual-ported") then + * attach each bus to opposite Cbricks. + * + * If successful, return a new vertex suitable for attaching the PIC bus. + * If not successful, return zero and both buses will attach to the + * vertex passed into pic_attach(). + */ +devfs_handle_t +pic_bus1_redist(nasid_t nasid, devfs_handle_t conn_v) +{ + cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); + cnodeid_t xbow_peer = -1; + char pathname[256], peer_path[256], tmpbuf[256]; + char *p; + int rc; + devfs_handle_t peer_conn_v; + int pos; + slabid_t slab; + + if (NODEPDA(cnode)->xbow_peer >= 0) { /* if dual-ported */ + /* create a path for this widget on the peer Cbrick */ + /* pcibr widget hw/module/001c11/slab/0/Pbrick/xtalk/12 */ + /* sprintf(pathname, "%v", conn_v); */ + xbow_peer = NASID_TO_COMPACT_NODEID(NODEPDA(cnode)->xbow_peer); + pos = devfs_generate_path(conn_v, tmpbuf, 256); + strcpy(pathname, &tmpbuf[pos]); + p = pathname + strlen("hw/module/001c01/slab/0/"); + + memset(tmpbuf, 0, 16); + format_module_id(tmpbuf, geo_module((NODEPDA(xbow_peer))->geoid), MODULE_FORMAT_BRIEF); + slab = geo_slab((NODEPDA(xbow_peer))->geoid); + sprintf(peer_path, "module/%s/slab/%d/%s", tmpbuf, (int)slab, p); + + /* Look for vertex for this widget on the peer Cbrick. + * Expect GRAPH_NOT_FOUND. + */ + rc = hwgraph_traverse(hwgraph_root, peer_path, &peer_conn_v); + if (GRAPH_SUCCESS == rc) + printk("pic_attach: found unexpected vertex: 0x%lx\n", + peer_conn_v); + else if (GRAPH_NOT_FOUND != rc) { + printk("pic_attach: hwgraph_traverse unexpectedly" + " returned 0x%x\n", rc); + } else { + /* try to add the widget vertex to the peer Cbrick */ + rc = hwgraph_path_add(hwgraph_root, peer_path, &peer_conn_v); + + if (GRAPH_SUCCESS != rc) + printk("pic_attach: hwgraph_path_add" + " failed with 0x%x\n", rc); + else { + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, + "pic_bus1_redist: added vertex %v\n", peer_conn_v)); + + /* Now hang appropiate stuff off of the new + * vertex. We bail out if we cannot add something. + * In that case, we don't remove the newly added + * vertex but that should be safe and we don't + * really expect the additions to fail anyway. + */ +#if 0 + if (!pic_bus1_inventory_dup(conn_v, peer_conn_v)) + return 0; + pic_bus1_device_desc_dup(conn_v, peer_conn_v); +#endif + if (!pic_bus1_widget_info_dup(conn_v, peer_conn_v, xbow_peer)) + return 0; + + return peer_conn_v; + } + } + } + return 0; +} + + +int +pic_attach(devfs_handle_t conn_v) +{ + int rc; + bridge_t *bridge0, *bridge1 = (bridge_t *)0; + devfs_handle_t pcibr_vhdl0, pcibr_vhdl1 = (devfs_handle_t)0; + pcibr_soft_t bus0_soft, bus1_soft = (pcibr_soft_t)0; + devfs_handle_t conn_v0, conn_v1, peer_conn_v; + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n")); + + bridge0 = (bridge_t *) xtalk_piotrans_addr(conn_v, NULL, + 0, sizeof(bridge_t), 0); + bridge1 = (bridge_t *)((char *)bridge0 + PIC_BUS1_OFFSET); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, + "pic_attach: bridge0=0x%x, bridge1=0x%x\n", + bridge0, bridge1)); + + conn_v0 = conn_v1 = conn_v; + + /* If dual-ported then split the two PIC buses across both Cbricks */ + if (peer_conn_v = pic_bus1_redist(NASID_GET(bridge0), conn_v)) + conn_v1 = peer_conn_v; + + /* + * Create the vertex for the PCI buses, which week + * will also use to hold the pcibr_soft and + * which will be the "master" vertex for all the + * pciio connection points we will hang off it. + * This needs to happen before we call nic_bridge_vertex_info + * as we are some of the *_vmc functions need access to the edges. + * + * Opening this vertex will provide access to + * the Bridge registers themselves. + */ + /* FIXME: what should the hwgraph path look like ? */ + rc = hwgraph_path_add(conn_v0, EDGE_LBL_PCIX_0, &pcibr_vhdl0); + ASSERT(rc == GRAPH_SUCCESS); + rc = hwgraph_path_add(conn_v1, EDGE_LBL_PCIX_1, &pcibr_vhdl1); + ASSERT(rc == GRAPH_SUCCESS); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, + "pic_attach: pcibr_vhdl0=%v, pcibr_vhdl1=%v\n", + pcibr_vhdl0, pcibr_vhdl1)); + + /* register pci provider array */ + pciio_provider_register(pcibr_vhdl0, &pci_pic_provider); + pciio_provider_register(pcibr_vhdl1, &pci_pic_provider); + + pciio_provider_startup(pcibr_vhdl0); + pciio_provider_startup(pcibr_vhdl1); + + pcibr_attach2(conn_v0, bridge0, pcibr_vhdl0, 0, &bus0_soft); + pcibr_attach2(conn_v1, bridge1, pcibr_vhdl1, 1, &bus1_soft); + + /* save a pointer to the PIC's other bus's soft struct */ + bus0_soft->bs_peers_soft = bus1_soft; + bus1_soft->bs_peers_soft = bus0_soft; + bus0_soft->bs_peers_soft = (pcibr_soft_t)0; + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, + "pic_attach: bus0_soft=0x%x, bus1_soft=0x%x\n", + bus0_soft, bus1_soft)); + + return 0; +} + +/* + * pci provider functions + * + * mostly in pcibr.c but if any are needed here then + * this might be a way to get them here. + */ +pciio_provider_t pci_pic_provider = +{ + (pciio_piomap_alloc_f *) pcibr_piomap_alloc, + (pciio_piomap_free_f *) pcibr_piomap_free, + (pciio_piomap_addr_f *) pcibr_piomap_addr, + (pciio_piomap_done_f *) pcibr_piomap_done, + (pciio_piotrans_addr_f *) pcibr_piotrans_addr, + (pciio_piospace_alloc_f *) pcibr_piospace_alloc, + (pciio_piospace_free_f *) pcibr_piospace_free, + + (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, + (pciio_dmamap_free_f *) pcibr_dmamap_free, + (pciio_dmamap_addr_f *) pcibr_dmamap_addr, + (pciio_dmamap_list_f *) pcibr_dmamap_list, + (pciio_dmamap_done_f *) pcibr_dmamap_done, + (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, + (pciio_dmatrans_list_f *) pcibr_dmatrans_list, + (pciio_dmamap_drain_f *) pcibr_dmamap_drain, + (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, + (pciio_dmalist_drain_f *) pcibr_dmalist_drain, + + (pciio_intr_alloc_f *) pcibr_intr_alloc, + (pciio_intr_free_f *) pcibr_intr_free, + (pciio_intr_connect_f *) pcibr_intr_connect, + (pciio_intr_disconnect_f *) pcibr_intr_disconnect, + (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, + + (pciio_provider_startup_f *) pcibr_provider_startup, + (pciio_provider_shutdown_f *) pcibr_provider_shutdown, + (pciio_reset_f *) pcibr_reset, + (pciio_write_gather_flush_f *) pcibr_write_gather_flush, + (pciio_endian_set_f *) pcibr_endian_set, + (pciio_priority_set_f *) pcibr_priority_set, + (pciio_config_get_f *) pcibr_config_get, + (pciio_config_set_f *) pcibr_config_set, + (pciio_error_devenable_f *) 0, + (pciio_error_extract_f *) 0, + (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, + (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, + (pciio_device_unregister_f *) pcibr_device_unregister, + (pciio_dma_enabled_f *) pcibr_dma_enabled, +}; diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/sgi_io_init.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/sgi_io_init.c --- linux-2.4.19/arch/ia64/sn/io/sn2/sgi_io_init.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/sgi_io_init.c Fri Feb 14 10:36:17 2003 @@ -0,0 +1,230 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void mlreset(void); +extern int init_hcl(void); +extern void klgraph_hack_init(void); +extern void hubspc_init(void); +extern void pciio_init(void); +extern void pcibr_init(void); +extern void xtalk_init(void); +extern void xbow_init(void); +extern void xbmon_init(void); +extern void pciiox_init(void); +extern void pic_init(void); +extern void usrpci_init(void); +extern void ioc3_init(void); +extern void initialize_io(void); +extern void klhwg_add_all_modules(devfs_handle_t); +extern void klhwg_add_all_nodes(devfs_handle_t); + +void sn_mp_setup(void); +extern devfs_handle_t hwgraph_root; +extern void io_module_init(void); +extern void pci_bus_cvlink_init(void); +extern void temp_hack(void); + +extern int pci_bus_to_hcl_cvlink(void); + +/* #define DEBUG_IO_INIT 1 */ +#ifdef DEBUG_IO_INIT +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG_IO_INIT */ + +/* + * per_hub_init + * + * This code is executed once for each Hub chip. + */ +static void +per_hub_init(cnodeid_t cnode) +{ + nasid_t nasid; + nodepda_t *npdap; + ii_icmr_u_t ii_icmr; + ii_ibcr_u_t ii_ibcr; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + ASSERT(nasid != INVALID_NASID); + ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); + + npdap = NODEPDA(cnode); + + REMOTE_HUB_S(nasid, IIO_IWEIM, 0x8000); + + /* + * Set the total number of CRBs that can be used. + */ + ii_icmr.ii_icmr_regval= 0x0; + ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xf; +#ifdef II_INT0_WAR + // Set bit one of ICMR to prevent II from sending interrupt for II bug. + ii_icmr.ii_icmr_regval |= 0x1; +#endif + REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); + + /* + * Set the number of CRBs that both of the BTEs combined + * can use minus 1. + */ + ii_ibcr.ii_ibcr_regval= 0x0; + ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; + REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); + + /* + * Set CRB timeout to be 10ms. + */ +#ifdef BRINGUP2 + REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff ); + REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); + //REMOTE_HUB_S(nasid, IIO_IWI, 0x00FF00FF00FFFFFF); +#endif + + /* Initialize error interrupts for this hub. */ + hub_error_init(cnode); +} + +/* + * This routine is responsible for the setup of all the IRIX hwgraph style + * stuff that's been pulled into linux. It's called by sn_pci_find_bios which + * is called just before the generic Linux PCI layer does its probing (by + * platform_pci_fixup aka sn_pci_fixup). + * + * It is very IMPORTANT that this call is only made by the Master CPU! + * + */ + +void +sgi_master_io_infr_init(void) +{ + int cnode; + extern void kdba_io_init(); + + /* + * Do any early init stuff .. einit_tbl[] etc. + */ + init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ + + /* + * initialize the Linux PCI to xwidget vertexes .. + */ + pci_bus_cvlink_init(); + + kdba_io_init(); + +#ifdef BRINGUP + /* + * Hack to provide statically initialzed klgraph entries. + */ + DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); + klgraph_hack_init(); +#endif /* BRINGUP */ + + /* + * This is the Master CPU. Emulate mlsetup and main.c in Irix. + */ + mlreset(); + + /* + * allowboot() is called by kern/os/main.c in main() + * Emulate allowboot() ... + * per_cpu_init() - only need per_hub_init() + * cpu_io_setup() - Nothing to do. + * + */ + sn_mp_setup(); + + for (cnode = 0; cnode < numnodes; cnode++) { + per_hub_init(cnode); + } + + /* We can do headless hub cnodes here .. */ + + /* + * io_init[] stuff. + * + * Get SGI IO Infrastructure drivers to init and register with + * each other etc. + */ + + hubspc_init(); + pciio_init(); + pcibr_init(); + pic_init(); + xtalk_init(); + xbow_init(); + xbmon_init(); + pciiox_init(); + usrpci_init(); + ioc3_init(); + + /* + * + * Our IO Infrastructure drivers are in place .. + * Initialize the whole IO Infrastructure .. xwidget/device probes. + * + */ + initialize_io(); + pci_bus_to_hcl_cvlink(); + +#ifdef CONFIG_PCIBA + DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); +#ifndef BRINGUP2 + pciba_init(); +#endif +#endif +} + +/* + * One-time setup for MP SN. + * Allocate per-node data, slurp prom klconfig information and + * convert it to hwgraph information. + */ +void +sn_mp_setup(void) +{ + cpuid_t cpu; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + /* Skip holes in CPU space */ + if (cpu_enabled(cpu)) { + init_platform_pda(cpu); + } + } + + /* + * Initialize platform-dependent vertices in the hwgraph: + * module + * node + * cpu + * memory + * slot + * hub + * router + * xbow + */ + + io_module_init(); /* Use to be called module_init() .. */ + klhwg_add_all_modules(hwgraph_root); + klhwg_add_all_nodes(hwgraph_root); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/shub.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shub.c --- linux-2.4.19/arch/ia64/sn/io/sn2/shub.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shub.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,233 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + */ + +#ident "$Revision: 1.167 $" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Shub WAR for Xbridge Little Endian problem: + * Xbridge has to run in BIG ENDIAN even with Shub. + */ + + +/* + * io_sh_swapper: Turn on Shub byte swapping. + * All data destined to and from Shub to XIO are byte-swapped. + */ +void +io_sh_swapper(nasid_t nasid, int onoff) +{ + ii_iwc_u_t ii_iwc; + + ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC); + + ii_iwc.ii_iwc_fld_s.i_dma_byte_swap = onoff; + REMOTE_HUB_S(nasid, IIO_IWC, ii_iwc.ii_iwc_regval); + ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC); + +} + +/* + * io_get_sh_swapper: Return current Swap mode. + * 1 = Swap on, 0 = Swap off. + */ +int +io_get_sh_swapper(nasid_t nasid) +{ + ii_iwc_u_t ii_iwc; + + ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC); + return(ii_iwc.ii_iwc_fld_s.i_dma_byte_swap); + +} + +#define SHUB_NUM_ECF_REGISTERS 8 + +static uint32_t shub_perf_counts[SHUB_NUM_ECF_REGISTERS]; + +static shubreg_t shub_perf_counts_regs[SHUB_NUM_ECF_REGISTERS] = { + SH_PERFORMANCE_COUNTER0, + SH_PERFORMANCE_COUNTER1, + SH_PERFORMANCE_COUNTER2, + SH_PERFORMANCE_COUNTER3, + SH_PERFORMANCE_COUNTER4, + SH_PERFORMANCE_COUNTER5, + SH_PERFORMANCE_COUNTER6, + SH_PERFORMANCE_COUNTER7 +}; + +static inline void +shub_mmr_write(cnodeid_t cnode, shubreg_t reg, uint64_t val) +{ + int nasid = cnodeid_to_nasid(cnode); + volatile uint64_t *addr = (uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg)); + + *addr = val; + __ia64_mf_a(); +} + +static inline void +shub_mmr_write32(cnodeid_t cnode, shubreg_t reg, uint32_t val) +{ + int nasid = cnodeid_to_nasid(cnode); + volatile uint32_t *addr = (uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg)); + + *addr = val; + __ia64_mf_a(); +} + +static inline uint64_t +shub_mmr_read(cnodeid_t cnode, shubreg_t reg) +{ + int nasid = cnodeid_to_nasid(cnode); + volatile uint64_t val; + + val = *(uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg)); + __ia64_mf_a(); + + return val; +} + +static inline uint32_t +shub_mmr_read32(cnodeid_t cnode, shubreg_t reg) +{ + int nasid = cnodeid_to_nasid(cnode); + volatile uint32_t val; + + val = *(uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg)); + __ia64_mf_a(); + + return val; +} + +static int +reset_shub_stats(cnodeid_t cnode) +{ + int i; + + for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) { + shub_perf_counts[i] = 0; + shub_mmr_write32(cnode, shub_perf_counts_regs[i], 0); + } + return 0; +} + +static int +configure_shub_stats(cnodeid_t cnode, unsigned long arg) +{ + uint64_t *p = (uint64_t *)arg; + uint64_t i; + uint64_t regcnt; + uint64_t regval[2]; + + if (copy_from_user((void *)®cnt, p, sizeof(regcnt))) + return -EFAULT; + + for (p++, i=0; i < regcnt; i++, p += 2) { + if (copy_from_user((void *)regval, (void *)p, sizeof(regval))) + return -EFAULT; + if (regval[0] & 0x7) { + printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]); + return -EINVAL; + } + shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]); + } + return 0; +} + +static int +capture_shub_stats(cnodeid_t cnode, uint32_t *counts) +{ + int i; + + for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) { + counts[i] = shub_mmr_read32(cnode, shub_perf_counts_regs[i]); + } + return 0; +} + +static int +shubstats_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + cnodeid_t cnode; + uint64_t longarg; + devfs_handle_t d; + int nasid; + + if ((d = devfs_get_handle_from_inode(inode)) == NULL) + return -ENODEV; + cnode = (cnodeid_t)hwgraph_fastinfo_get(d); + + switch (cmd) { + case SNDRV_SHUB_CONFIGURE: + return configure_shub_stats(cnode, arg); + break; + + case SNDRV_SHUB_RESETSTATS: + reset_shub_stats(cnode); + break; + + case SNDRV_SHUB_INFOSIZE: + longarg = sizeof(shub_perf_counts); + if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) { + return -EFAULT; + } + break; + + case SNDRV_SHUB_GETSTATS: + capture_shub_stats(cnode, shub_perf_counts); + if (copy_to_user((void *)arg, shub_perf_counts, + sizeof(shub_perf_counts))) { + return -EFAULT; + } + break; + + case SNDRV_SHUB_GETNASID: + nasid = cnodeid_to_nasid(cnode); + if (copy_to_user((void *)arg, &nasid, + sizeof(nasid))) { + return -EFAULT; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +struct file_operations shub_mon_fops = { + ioctl: shubstats_ioctl, +}; diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/shub_intr.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shub_intr.c --- linux-2.4.19/arch/ia64/sn/io/sn2/shub_intr.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shub_intr.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include @@ -25,21 +25,13 @@ #include #include #include +#include #include -extern void hub_device_desc_update(device_desc_t, ilvl_t, cpuid_t); - /* ARGSUSED */ void hub_intr_init(devfs_handle_t hubv) { - extern void sn_cpei_handler(int, void *, struct pt_regs *); - extern void sn_init_cpei_timer(void); - - if (request_irq(SGI_SHUB_ERROR_VECTOR, sn_cpei_handler, 0, "SN hub error", NULL) ) { - printk("hub_intr_init: Couldn't register SGI_SHUB_ERROR_VECTOR = %x\n",SGI_SHUB_ERROR_VECTOR); - } - sn_init_cpei_timer(); } xwidgetnum_t @@ -82,11 +74,9 @@ cnode = cpuid_to_cnodeid(cpu); if (slice) { - xtalk_addr = SH_II_INT1 | GLOBAL_MMR_SPACE | - ((unsigned long)nasid << 36) | (1UL << 47); + xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47); } else { - xtalk_addr = SH_II_INT0 | GLOBAL_MMR_SPACE | - ((unsigned long)nasid << 36) | (1UL << 47); + xtalk_addr = SH_II_INT0 | ((unsigned long)nasid << 36) | (1UL << 47); } intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, cnode); @@ -107,7 +97,6 @@ intr_hdl->i_bit = vector; intr_hdl->i_flags |= HUB_INTR_IS_ALLOCED; - hub_device_desc_update(dev_desc, intr_swlevel, cpu); return(intr_hdl); } @@ -150,6 +139,8 @@ int hub_intr_connect(hub_intr_t intr_hdl, + intr_func_t intr_func, /* xtalk intr handler */ + void *intr_arg, /* arg to intr handler */ xtalk_intr_setfunc_t setfunc, void *setfunc_arg) { @@ -160,7 +151,6 @@ ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED); rv = intr_connect_level(cpu, vector, intr_hdl->i_swlevel, NULL); - if (rv < 0) { return rv; } diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/shuberror.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shuberror.c --- linux-2.4.19/arch/ia64/sn/io/sn2/shuberror.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shuberror.c Wed Jan 15 11:51:10 2003 @@ -4,12 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include +#include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,12 +37,22 @@ extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); int hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); int hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); -extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe); +extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop); +void print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, + ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, + ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe); extern int maxcpus; +extern error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state); #define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ +#ifdef BUS_INT_WAR +void sn_add_polled_interrupt(int irq, int interval); +void sn_delete_polled_interrupt(int irq); +extern int bus_int_war_ide_irq; +#endif + void hub_error_clear(nasid_t nasid) @@ -118,9 +131,7 @@ hubinfo_t hinfo; cpuid_t intr_cpu; devfs_handle_t hub_v; - ii_ilcsr_u_t ilcsr; int bit_pos_to_irq(int bit); - int synergy_intr_connect(int bit, int cpuid); hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); @@ -130,17 +141,6 @@ ASSERT(hinfo); ASSERT(hinfo->h_cnodeid == cnode); - ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); - - if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { - /* - * HUB II link is not up. - * Just disable LLP, and don't connect any interrupts. - */ - ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; - REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); - return; - } /* Select a possible interrupt target where there is a free interrupt * bit and also reserve the interrupt bit for this IO error interrupt */ @@ -152,7 +152,11 @@ } rv = intr_connect_level(intr_cpu, bit, 0, NULL); - request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v); + request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN_hub_error", (void *)hub_v); + irq_desc(bit + (intr_cpu << 8))->status |= SN2_IRQ_PER_HUB; +#ifdef BUS_INT_WAR + sn_add_polled_interrupt(bit + (intr_cpu << 8), (0.01 * HZ)); +#endif ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; @@ -180,6 +184,16 @@ hubinfo_get(hub_v, &hinfo); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICMR); +#if 0 + if (idsr & 0x1) { + /* ICMR bit is set .. we are getting into "Spurious Interrupts condition. */ + printk("Cnode %d II has seen the ICMR condition\n", hinfo->h_cnodeid); + printk("***** Please file PV with the above messages *****\n"); + /* panic("We have to panic to prevent further unknown states ..\n"); */ + } +#endif + /* * Identify the reason for error. */ @@ -219,8 +233,8 @@ * Note: we may never be able to print this, if the II talking * to Xbow which hosts the console is dead. */ - printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", - hinfo->h_cnodeid, reason); + printk("Hub %d, cnode %d to Xtalk Link failed (II_ECRAZY) Reason: %s", + hinfo->h_nasid, hinfo->h_cnodeid, reason); } /* @@ -257,15 +271,16 @@ void hubiio_crb_free(hubinfo_t hinfo, int crbnum) { - ii_icrb0_a_u_t icrba; + ii_icrb0_b_u_t icrbb; /* * The hardware does NOT clear the mark bit, so it must get cleared * here to be sure the error is not processed twice. */ - icrba.ii_icrb0_a_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_A(crbnum)); - icrba.a_valid = 0; - REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_A(crbnum), icrba.ii_icrb0_a_regval); + icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_B(crbnum)); + icrbb.b_mark = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_B(crbnum), icrbb.ii_icrb0_b_regval); + /* * Deallocate the register. */ @@ -295,6 +310,105 @@ "Xtalk Error Packet" }; +void +print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, + ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, + ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe) +{ + printk("CRB %d regA\n\t" + "a_iow 0x%x\n\t" + "valid0x%x\n\t" + "Address0x%lx\n\t" + "a_tnum 0x%x\n\t" + "a_sidn 0x%x\n", + crb_num, + icrba.a_iow, + icrba.a_valid, + icrba.a_addr, + icrba.a_tnum, + icrba.a_sidn); + printk("CRB %d regB\n\t" + "b_imsgtype 0x%x\n\t" + "b_imsg 0x%x\n" + "\tb_use_old 0x%x\n\t" + "b_initiator 0x%x\n\t" + "b_exc 0x%x\n" + "\tb_ackcnt 0x%x\n\t" + "b_resp 0x%x\n\t" + "b_ack 0x%x\n" + "\tb_hold 0x%x\n\t" + "b_wb 0x%x\n\t" + "b_intvn 0x%x\n" + "\tb_stall_ib 0x%x\n\t" + "b_stall_int 0x%x\n" + "\tb_stall_bte_0 0x%x\n\t" + "b_stall_bte_1 0x%x\n" + "\tb_error 0x%x\n\t" + "b_lnetuce 0x%x\n\t" + "b_mark 0x%x\n\t" + "b_xerr 0x%x\n", + crb_num, + icrbb.b_imsgtype, + icrbb.b_imsg, + icrbb.b_use_old, + icrbb.b_initiator, + icrbb.b_exc, + icrbb.b_ackcnt, + icrbb.b_resp, + icrbb.b_ack, + icrbb.b_hold, + icrbb.b_wb, + icrbb.b_intvn, + icrbb.b_stall_ib, + icrbb.b_stall_int, + icrbb.b_stall_bte_0, + icrbb.b_stall_bte_1, + icrbb.b_error, + icrbb.b_lnetuce, + icrbb.b_mark, + icrbb.b_xerr); + printk("CRB %d regC\n\t" + "c_source 0x%x\n\t" + "c_xtsize 0x%x\n\t" + "c_cohtrans 0x%x\n\t" + "c_btenum 0x%x\n\t" + "c_gbr 0x%x\n\t" + "c_doresp 0x%x\n\t" + "c_barrop 0x%x\n\t" + "c_suppl 0x%x\n", + crb_num, + icrbc.c_source, + icrbc.c_xtsize, + icrbc.c_cohtrans, + icrbc.c_btenum, + icrbc.c_gbr, + icrbc.c_doresp, + icrbc.c_barrop, + icrbc.c_suppl); + printk("CRB %d regD\n\t" + "d_bteaddr 0x%lx\n\t" + "d_bteop 0x%x\n\t" + "d_pripsc 0x%x\n\t" + "d_pricnt 0x%x\n\t" + "d_sleep 0x%x\n\t", + crb_num, + icrbd.d_bteaddr, + icrbd.d_bteop, + icrbd.d_pripsc, + icrbd.d_pricnt, + icrbd.d_sleep); + printk("CRB %d regE\n\t" + "icrbe_timeout 0x%x\n\t" + "icrbe_context 0x%x\n\t" + "icrbe_toutvld 0x%x\n\t" + "icrbe_ctxtvld 0x%x\n\t", + crb_num, + icrbe.icrbe_timeout, + icrbe.icrbe_context, + icrbe.icrbe_toutvld, + icrbe.icrbe_ctxtvld); +} + /* * hubiio_crb_error_handler * @@ -325,28 +439,41 @@ ii_icrb0_b_u_t icrbb; /* II CRB Register B */ ii_icrb0_c_u_t icrbc; /* II CRB Register C */ ii_icrb0_d_u_t icrbd; /* II CRB Register D */ + ii_icrb0_e_u_t icrbe; /* II CRB Register D */ int i; int num_errors = 0; /* Num of errors handled */ ioerror_t ioerror; + int rc; nasid = hinfo->h_nasid; cnode = NASID_TO_COMPACT_NODEID(nasid); /* + * XXX - Add locking for any recovery actions + */ + /* * Scan through all CRBs in the Hub, and handle the errors * in any of the CRBs marked. */ for (i = 0; i < IIO_NUM_CRBS; i++) { + /* Check this crb entry to see if it is in error. */ + icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); + + if (icrbb.b_mark == 0) { + continue; + } + icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i)); IOERROR_INIT(&ioerror); /* read other CRB error registers. */ - icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i)); icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); + icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i)); IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); + /* Check if this error is due to BTE operation, * and handle it separately. */ @@ -363,8 +490,15 @@ else /* b_initiator bit 2 gives BTE number */ bte_num = (icrbb.b_initiator & 0x4) >> 2; + /* >>> bte_crb_error_handler needs to be + * broken into two parts. The first should + * cleanup the CRB. The second should wait + * until all bte related CRB's are complete + * and then do the error reset. + */ bte_crb_error_handler(hub_v, bte_num, - i, &ioerror); + i, &ioerror, + icrbd.d_bteop); hubiio_crb_free(hinfo, i); num_errors++; continue; @@ -401,11 +535,222 @@ */ IOERROR_SETVALUE(&ioerror,widgetdev, TNUM_TO_WIDGET_DEV(icrba.a_tnum)); + /* + * The encoding of TNUM (see comments above) is + * different for PIC. So we'll save TNUM here and + * deal with the differences later when we can + * determine if we're using a Bridge or the PIC. + * + * XXX: We may be able to remove saving the widgetdev + * above and just sort it out of TNUM later. + */ + IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum); + + } + if (icrbb.b_error) { + /* + * CRB 'i' has some error. Identify the type of error, + * and try to handle it. + * + */ + switch(icrbb.b_ecode) { + case IIO_ICRB_ECODE_PERR: + case IIO_ICRB_ECODE_WERR: + case IIO_ICRB_ECODE_AERR: + case IIO_ICRB_ECODE_PWERR: + case IIO_ICRB_ECODE_TOUT: + case IIO_ICRB_ECODE_XTERR: + printk("Shub II CRB %d: error %s on hub cnodeid: %d", + i, hubiio_crb_errors[icrbb.b_ecode], cnode); + /* + * Any sort of write error is mostly due + * bad programming (Note it's not a timeout.) + * So, invoke hub_iio_error_handler with + * appropriate information. + */ + IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); + + /* Go through the error bit lookup phase */ + if (error_state_set(hub_v, ERROR_STATE_LOOKUP) == + ERROR_RETURN_CODE_CANNOT_SET_STATE) + return(IOERROR_UNHANDLED); + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVERROR, + &ioerror); + if (rc == IOERROR_HANDLED) { + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVREENABLE, + &ioerror); + }else { + printk("Unable to handle %s on hub %d", + hubiio_crb_errors[icrbb.b_ecode], + cnode); + /* panic; */ + } + /* Go to Next error */ + print_crb_fields(i, icrba, icrbb, icrbc, + icrbd, icrbe); + hubiio_crb_free(hinfo, i); + continue; + case IIO_ICRB_ECODE_PRERR: + case IIO_ICRB_ECODE_DERR: + printk("Shub II CRB %d: error %s on hub : %d", + i, hubiio_crb_errors[icrbb.b_ecode], cnode); + /* panic */ + default: + printk("Shub II CRB error (code : %d) on hub : %d", + icrbb.b_ecode, cnode); + /* panic */ + } + } + /* + * Error is not indicated via the errcode field + * Check other error indications in this register. + */ + if (icrbb.b_xerr) { + printk("Shub II CRB %d: Xtalk Packet with error bit set to hub %d", + i, cnode); + /* panic */ + } + if (icrbb.b_lnetuce) { + printk("Shub II CRB %d: Uncorrectable data error detected on data " + " from NUMAlink to node %d", + i, cnode); + /* panic */ + } + print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); + + + + + if (icrbb.b_error) { + /* + * CRB 'i' has some error. Identify the type of error, + * and try to handle it. + */ + switch(icrbb.b_ecode) { + case IIO_ICRB_ECODE_PERR: + case IIO_ICRB_ECODE_WERR: + case IIO_ICRB_ECODE_AERR: + case IIO_ICRB_ECODE_PWERR: + + printk("%s on hub cnodeid: %d", + hubiio_crb_errors[icrbb.b_ecode], cnode); + /* + * Any sort of write error is mostly due + * bad programming (Note it's not a timeout.) + * So, invoke hub_iio_error_handler with + * appropriate information. + */ + IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); + + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVERROR, + &ioerror); + + if (rc == IOERROR_HANDLED) { + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVREENABLE, + &ioerror); + ASSERT(rc == IOERROR_HANDLED); + }else { + + panic("Unable to handle %s on hub %d", + hubiio_crb_errors[icrbb.b_ecode], + cnode); + /*NOTREACHED*/ + } + /* Go to Next error */ + hubiio_crb_free(hinfo, i); + continue; + + case IIO_ICRB_ECODE_PRERR: + + case IIO_ICRB_ECODE_TOUT: + case IIO_ICRB_ECODE_XTERR: + + case IIO_ICRB_ECODE_DERR: + panic("Fatal %s on hub : %d", + hubiio_crb_errors[icrbb.b_ecode], cnode); + /*NOTREACHED*/ + + default: + panic("Fatal error (code : %d) on hub : %d", + icrbb.b_ecode, cnode); + /*NOTREACHED*/ + + } + } /* if (icrbb.b_error) */ + + /* + * Error is not indicated via the errcode field + * Check other error indications in this register. + */ + + if (icrbb.b_xerr) { + panic("Xtalk Packet with error bit set to hub %d", + cnode); + /*NOTREACHED*/ + } + + if (icrbb.b_lnetuce) { + panic("Uncorrectable data error detected on data " + " from Craylink to node %d", + cnode); + /*NOTREACHED*/ } } return num_errors; +} + +/* + * hubii_check_widget_disabled + * + * Check if PIO access to the specified widget is disabled due + * to any II errors that are currently set. + * + * The specific error bits checked are: + * IPRBx register: SPUR_RD (51) + * SPUR_WR (50) + * RD_TO (49) + * ERROR (48) + * + * WSTAT register: CRAZY (32) + */ + +int +hubii_check_widget_disabled(nasid_t nasid, int wnum) +{ + iprb_t iprb; + ii_wstat_u_t wstat; + + iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(wnum)); + if (iprb.iprb_regval & (IIO_PRB_SPUR_RD | IIO_PRB_SPUR_WR | + IIO_PRB_RD_TO | IIO_PRB_ERROR)) { +#ifdef DEBUG + printk(KERN_WARNING "II error, IPRB%x=0x%lx\n", wnum, iprb.iprb_regval); +#endif + return(1); + } + + wstat.ii_wstat_regval = REMOTE_HUB_L(nasid, IIO_WSTAT); + if (wstat.ii_wstat_regval & IIO_WSTAT_ECRAZY) { +#ifdef DEBUG + printk(KERN_WARNING "II error, WSTAT=0x%lx\n", wstat.ii_wstat_regval); +#endif + return(1); + } + return(0); } /*ARGSUSED*/ diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/shubio.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shubio.c --- linux-2.4.19/arch/ia64/sn/io/sn2/shubio.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/shubio.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,510 @@ +/* $Id: shubio.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +error_state_t error_state_get(devfs_handle_t v); +error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state); + + +/* + * Get the xtalk provider function pointer for the + * specified hub. + */ + +/*ARGSUSED*/ +int +hub_xp_error_handler( + devfs_handle_t hub_v, + nasid_t nasid, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioerror) +{ + /*REFERENCED*/ + hubreg_t iio_imem; + devfs_handle_t xswitch; + error_state_t e_state; + cnodeid_t cnode; + + /* + * Before walking down to the next level, check if + * the I/O link is up. If it's been disabled by the + * hub ii for some reason, we can't even touch the + * widget registers. + */ + iio_imem = REMOTE_HUB_L(nasid, IIO_IMEM); + + if (!(iio_imem & (IIO_IMEM_B0ESD|IIO_IMEM_W0ESD))){ + /* + * IIO_IMEM_B0ESD getting set, indicates II shutdown + * on HUB0 parts.. Hopefully that's not true for + * Hub1 parts.. + * + * + * If either one of them is shut down, can't + * go any further. + */ + return IOERROR_XTALKLEVEL; + } + + /* Get the error state of the hub */ + e_state = error_state_get(hub_v); + + cnode = NASID_TO_COMPACT_NODEID(nasid); + + xswitch = NODEPDA(cnode)->basew_xc; + + /* Set the error state of the crosstalk device to that of + * hub. + */ + if (error_state_set(xswitch , e_state) == + ERROR_RETURN_CODE_CANNOT_SET_STATE) + return(IOERROR_UNHANDLED); + + /* Clean the error state of the hub if we are in the action handling + * phase. + */ + if (e_state == ERROR_STATE_ACTION) + (void)error_state_set(hub_v, ERROR_STATE_NONE); + /* hand the error off to the switch or the directly + * connected crosstalk device. + */ + return xtalk_error_handler(xswitch, + error_code, mode, ioerror); + +} + +/* + * Check if the widget in error has been enabled for PIO accesses + */ +int +is_widget_pio_enabled(ioerror_t *ioerror) +{ + cnodeid_t src_node; + nasid_t src_nasid; + hubreg_t ii_iowa; + xwidgetnum_t widget; + iopaddr_t p; + + /* Get the node where the PIO error occurred */ + IOERROR_GETVALUE(p,ioerror, srcnode); + src_node = p; + if (src_node == CNODEID_NONE) + return(0); + + /* Get the nasid for the cnode */ + src_nasid = COMPACT_TO_NASID_NODEID(src_node); + if (src_nasid == INVALID_NASID) + return(0); + + /* Read the Outbound widget access register for this hub */ + ii_iowa = REMOTE_HUB_L(src_nasid, IIO_IOWA); + IOERROR_GETVALUE(p,ioerror, widgetnum); + widget = p; + + /* Check if the PIOs to the widget with PIO error have been + * enabled. + */ + if (ii_iowa & IIO_IOWA_WIDGET(widget)) + return(1); + + return(0); +} + +/* + * Hub IO error handling. + * + * Gets invoked for different types of errors found at the hub. + * Typically this includes situations from bus error or due to + * an error interrupt (mostly generated at the hub). + */ +int +hub_ioerror_handler( + devfs_handle_t hub_v, + int error_code, + int mode, + struct io_error_s *ioerror) +{ + hubinfo_t hinfo; /* Hub info pointer */ + nasid_t nasid; + int retval = 0; + /*REFERENCED*/ + iopaddr_t p; + + IOERROR_DUMP("hub_ioerror_handler", error_code, mode, ioerror); + + hubinfo_get(hub_v, &hinfo); + + if (!hinfo){ + /* Print an error message and return */ + goto end; + } + nasid = hinfo->h_nasid; + + switch(error_code) { + + case PIO_READ_ERROR: + /* + * Cpu got a bus error while accessing IO space. + * hubaddr field in ioerror structure should have + * the IO address that caused access error. + */ + + /* + * Identify if the physical address in hub_error_data + * corresponds to small/large window, and accordingly, + * get the xtalk address. + */ + + /* + * Evaluate the widget number and the widget address that + * caused the error. Use 'vaddr' if it's there. + * This is typically true either during probing + * or a kernel driver getting into trouble. + * Otherwise, use paddr to figure out widget details + * This is typically true for user mode bus errors while + * accessing I/O space. + */ + IOERROR_GETVALUE(p,ioerror,vaddr); + if (p){ + /* + * If neither in small window nor in large window range, + * outright reject it. + */ + IOERROR_GETVALUE(p,ioerror,vaddr); + if (NODE_SWIN_ADDR(nasid, (paddr_t)p)){ + iopaddr_t hubaddr; + xwidgetnum_t widgetnum; + iopaddr_t xtalkaddr; + + IOERROR_GETVALUE(p,ioerror,hubaddr); + hubaddr = p; + widgetnum = SWIN_WIDGETNUM(hubaddr); + xtalkaddr = SWIN_WIDGETADDR(hubaddr); + /* + * differentiate local register vs IO space access + */ + IOERROR_SETVALUE(ioerror,widgetnum,widgetnum); + IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); + + + } else if (NODE_BWIN_ADDR(nasid, (paddr_t)p)){ + /* + * Address corresponds to large window space. + * Convert it to xtalk address. + */ + int bigwin; + hub_piomap_t bw_piomap; + xtalk_piomap_t xt_pmap = NULL; + iopaddr_t hubaddr; + xwidgetnum_t widgetnum; + iopaddr_t xtalkaddr; + + IOERROR_GETVALUE(p,ioerror,hubaddr); + hubaddr = p; + + /* + * Have to loop to find the correct xtalk_piomap + * because the're not allocated on a one-to-one + * basis to the window number. + */ + for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) { + bw_piomap = hubinfo_bwin_piomap_get(hinfo, + bigwin); + + if (bw_piomap->hpio_bigwin_num == + (BWIN_WINDOWNUM(hubaddr) - 1)) { + xt_pmap = hub_piomap_xt_piomap(bw_piomap); + break; + } + } + + ASSERT(xt_pmap); + + widgetnum = xtalk_pio_target_get(xt_pmap); + xtalkaddr = xtalk_pio_xtalk_addr_get(xt_pmap) + BWIN_WIDGETADDR(hubaddr); + + IOERROR_SETVALUE(ioerror,widgetnum,widgetnum); + IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); + + /* + * Make sure that widgetnum doesnot map to hub + * register widget number, as we never use + * big window to access hub registers. + */ + ASSERT(widgetnum != HUB_REGISTER_WIDGET); + } + } else if (IOERROR_FIELDVALID(ioerror,hubaddr)) { + iopaddr_t hubaddr; + xwidgetnum_t widgetnum; + iopaddr_t xtalkaddr; + + IOERROR_GETVALUE(p,ioerror,hubaddr); + hubaddr = p; + if (BWIN_WINDOWNUM(hubaddr)){ + int window = BWIN_WINDOWNUM(hubaddr) - 1; + hubreg_t itte; + itte = (hubreg_t)HUB_L(IIO_ITTE_GET(nasid, window)); + widgetnum = (itte >> IIO_ITTE_WIDGET_SHIFT) & + IIO_ITTE_WIDGET_MASK; + xtalkaddr = (((itte >> IIO_ITTE_OFFSET_SHIFT) & + IIO_ITTE_OFFSET_MASK) << + BWIN_SIZE_BITS) + + BWIN_WIDGETADDR(hubaddr); + } else { + widgetnum = SWIN_WIDGETNUM(hubaddr); + xtalkaddr = SWIN_WIDGETADDR(hubaddr); + } + IOERROR_SETVALUE(ioerror,widgetnum,widgetnum); + IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); + } else { + IOERROR_DUMP("hub_ioerror_handler", error_code, + mode, ioerror); + IOERR_PRINTF(printk( + "hub_ioerror_handler: Invalid address passed")); + + return IOERROR_INVALIDADDR; + } + + + IOERROR_GETVALUE(p,ioerror,widgetnum); + if ((p) == HUB_REGISTER_WIDGET) { + /* + * Error in accessing Hub local register + * This should happen mostly in SABLE mode.. + */ + retval = 0; + } else { + /* Make sure that the outbound widget access for this + * widget is enabled. + */ + if (!is_widget_pio_enabled(ioerror)) { + if (error_state_get(hub_v) == + ERROR_STATE_ACTION) + ioerror_dump("No outbound widget" + " access - ", + error_code, mode, ioerror); + return(IOERROR_HANDLED); + } + + + retval = hub_xp_error_handler( + hub_v, nasid, error_code, mode, ioerror); + + } + + IOERR_PRINTF(printk( + "hub_ioerror_handler:PIO_READ_ERROR return: %d", + retval)); + + break; + + case PIO_WRITE_ERROR: + /* + * This hub received an interrupt indicating a widget + * attached to this hub got a timeout. + * widgetnum field should be filled to indicate the + * widget that caused error. + * + * NOTE: This hub may have nothing to do with this error. + * We are here since the widget attached to the xbow + * gets its PIOs through this hub. + * + * There is nothing that can be done at this level. + * Just invoke the xtalk error handling mechanism. + */ + IOERROR_GETVALUE(p,ioerror,widgetnum); + if ((p) == HUB_REGISTER_WIDGET) { + } else { + /* Make sure that the outbound widget access for this + * widget is enabled. + */ + + if (!is_widget_pio_enabled(ioerror)) { + if (error_state_get(hub_v) == + ERROR_STATE_ACTION) + ioerror_dump("No outbound widget" + " access - ", + error_code, mode, ioerror); + return(IOERROR_HANDLED); + } + + retval = hub_xp_error_handler( + hub_v, nasid, error_code, mode, ioerror); + } + break; + + case DMA_READ_ERROR: + /* + * DMA Read error always ends up generating an interrupt + * at the widget level, and never at the hub level. So, + * we don't expect to come here any time + */ + ASSERT(0); + retval = IOERROR_UNHANDLED; + break; + + case DMA_WRITE_ERROR: + /* + * DMA Write error is generated when a write by an I/O + * device could not be completed. Problem is, device is + * totally unaware of this problem, and would continue + * writing to system memory. So, hub has a way to send + * an error interrupt on the first error, and bitbucket + * all further write transactions. + * Coming here indicates that hub detected one such error, + * and we need to handle it. + * + * Hub interrupt handler would have extracted physaddr, + * widgetnum, and widgetdevice from the CRB + * + * There is nothing special to do here, since gathering + * data from crb's is done elsewhere. Just pass the + * error to xtalk layer. + */ + retval = hub_xp_error_handler(hub_v, nasid, error_code, mode, + ioerror); + break; + + default: + ASSERT(0); + return IOERROR_BADERRORCODE; + + } + + /* + * If error was not handled, we may need to take certain action + * based on the error code. + * For e.g. in case of PIO_READ_ERROR, we may need to release the + * PIO Read entry table (they are sticky after errors). + * Similarly other cases. + * + * Further Action TBD + */ +end: + if (retval == IOERROR_HWGRAPH_LOOKUP) { + /* + * If we get errors very early, we can't traverse + * the path using hardware graph. + * To handle this situation, we need a functions + * which don't depend on the hardware graph vertex to + * handle errors. This break the modularity of the + * existing code. Instead we print out the reason for + * not handling error, and return. On return, all the + * info collected would be dumped. This should provide + * sufficient info to analyse the error. + */ + printk("Unable to handle IO error: hardware graph not setup\n"); + } + + return retval; +} + +#define L_BITSMINOR 18 +#define L_MAXMAJ 0x1ff +#define emajor(x) (int )(((unsigned )(x)>>L_BITSMINOR) & L_MAXMAJ) +#define dev_is_vertex(dev) (emajor((dev_t)(dev)) == 0) + +#define INFO_LBL_ERROR_STATE "error_state" + +#define v_error_state_get(v,s) \ +(hwgraph_info_get_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t *)&s)) + +#define v_error_state_set(v,s,replace) \ +(replace ? \ +hwgraph_info_replace_LBL(v,INFO_LBL_ERROR_STATE,(arbitrary_info_t)s,0) :\ +hwgraph_info_add_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t)s)) + + +#define v_error_state_clear(v) \ +(hwgraph_info_remove_LBL(v,INFO_LBL_ERROR_STATE,0)) + +/* + * error_state_get + * Get the state of the vertex. + * Returns ERROR_STATE_INVALID on failure + * current state otherwise + */ +error_state_t +error_state_get(devfs_handle_t v) +{ + error_state_t s; + + /* Check if we have a valid hwgraph vertex */ + if (!dev_is_vertex(v)) + return(ERROR_STATE_NONE); + + /* Get the labelled info hanging off the vertex which corresponds + * to the state. + */ + if (v_error_state_get(v, s) != GRAPH_SUCCESS) { + return(ERROR_STATE_NONE); + } + return(s); +} + + +/* + * error_state_set + * Set the state of the vertex + * Returns ERROR_RETURN_CODE_CANNOT_SET_STATE on failure + * ERROR_RETURN_CODE_SUCCESS otherwise + */ +error_return_code_t +error_state_set(devfs_handle_t v,error_state_t new_state) +{ + error_state_t old_state; + boolean_t replace = B_TRUE; + + /* Check if we have a valid hwgraph vertex */ + if (!dev_is_vertex(v)) + return(ERROR_RETURN_CODE_GENERAL_FAILURE); + + + /* This means that the error state needs to be cleaned */ + if (new_state == ERROR_STATE_NONE) { + /* Make sure that we have an error state */ + if (v_error_state_get(v,old_state) == GRAPH_SUCCESS) + v_error_state_clear(v); + return(ERROR_RETURN_CODE_SUCCESS); + } + + /* Check if the state information has been set at least once + * for this vertex. + */ + if (v_error_state_get(v,old_state) != GRAPH_SUCCESS) + replace = B_FALSE; + + if (v_error_state_set(v,new_state,replace) != GRAPH_SUCCESS) { + return(ERROR_RETURN_CODE_CANNOT_SET_STATE); + } + return(ERROR_RETURN_CODE_SUCCESS); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/xbow.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/xbow.c --- linux-2.4.19/arch/ia64/sn/io/sn2/xbow.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/xbow.c Fri Jan 3 19:33:41 2003 @@ -0,0 +1,1681 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define DEBUG 1 */ +/* #define XBOW_DEBUG 1 */ +/* #define DEBUG_ERROR 1 */ + + +/* + * Files needed to get the device driver entry points + */ + +#include +#include +#include +#include + +#include +#include + + +#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) +#define DEL(ptr) (kfree(ptr)) + +int xbow_devflag = D_MP; + +/* + * This file supports the Xbow chip. Main functions: initializtion, + * error handling, and GBR. + */ + +/* + * each vertex corresponding to an xbow chip + * has a "fastinfo" pointer pointing at one + * of these things. + */ +typedef struct xbow_soft_s *xbow_soft_t; + +struct xbow_soft_s { + devfs_handle_t conn; /* our connection point */ + devfs_handle_t vhdl; /* xbow's private vertex */ + devfs_handle_t busv; /* the xswitch vertex */ + xbow_t *base; /* PIO pointer to crossbow chip */ + char *name; /* hwgraph name */ + + xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; + xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; + xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; + spinlock_t xbow_perf_lock; + int link_monitor; + widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ + + /* Bandwidth allocation state. Bandwidth values are for the + * destination port since contention happens there. + * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. + */ + spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ + unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ + unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ +}; + +#define xbow_soft_set(v,i) hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)) +#define xbow_soft_get(v) ((xbow_soft_t)hwgraph_fastinfo_get((v))) + +/* + * Function Table of Contents + */ + +void xbow_mlreset(xbow_t *); +void xbow_init(void); +int xbow_attach(devfs_handle_t); + +int xbow_open(devfs_handle_t *, int, int, cred_t *); +int xbow_close(devfs_handle_t, int, int, cred_t *); + +int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); +int xbow_unmap(devfs_handle_t, vhandl_t *); +int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); + +int xbow_widget_present(xbow_t *, int); +static int xbow_link_alive(xbow_t *, int); +devfs_handle_t xbow_widget_lookup(devfs_handle_t, int); + +void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); + + + +void xbow_update_perf_counters(devfs_handle_t); +xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); +int xbow_enable_perf_counter(devfs_handle_t, int, int, int); +xbow_link_status_t *xbow_get_llp_status(devfs_handle_t); +void xbow_update_llp_status(devfs_handle_t); + +int xbow_disable_llp_monitor(devfs_handle_t); +int xbow_enable_llp_monitor(devfs_handle_t); +int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, + unsigned long long, unsigned long long); +static void xbow_setwidint(xtalk_intr_t); +void idbg_xbowregs(int64_t); + +xswitch_reset_link_f xbow_reset_link; + +xswitch_provider_t xbow_provider = +{ + xbow_reset_link, +}; + +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +static int xbow_mmap(struct file * file, struct vm_area_struct * vma); +struct file_operations xbow_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + readdir: NULL, + poll: NULL, + ioctl: NULL, + mmap: xbow_mmap, + open: xbow_open, + flush: NULL, + release: NULL, + fsync: NULL, + fasync: NULL, + lock: NULL, + readv: NULL, + writev: NULL, + sendpage: NULL, + get_unmapped_area: NULL +}; + +static int +xbow_mmap(struct file * file, struct vm_area_struct * vma) +{ + unsigned long phys_addr; + int error = 0; + + phys_addr = (unsigned long)file->private_data & ~0xc000000000000000; /* Mask out the Uncache bits */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; + error = io_remap_page_range(vma->vm_start, phys_addr, + vma->vm_end-vma->vm_start, + vma->vm_page_prot); + return(error); +} + + +/* + * xbow_mlreset: called at mlreset time if the + * platform specific code determines that there is + * a crossbow in a critical path that must be + * functional before the driver would normally get + * the device properly set up. + * + * what do we need to do, that the boot prom can + * not be counted on to have already done, that is + * generic across all platforms using crossbows? + */ +/*ARGSUSED */ +void +xbow_mlreset(xbow_t * xbow) +{ +} + +/* + * xbow_init: called with the rest of the device + * driver XXX_init routines. This platform *might* + * have a Crossbow chip, or even several, but it + * might have none. Register with the crosstalk + * generic provider so when we encounter the chip + * the right magic happens. + */ +void +xbow_init(void) +{ + +#if DEBUG && ATTACH_DEBUG + printk("xbow_init\n"); +#endif + + xwidget_driver_register(PXBOW_WIDGET_PART_NUM, + 0, /* XXBOW_WIDGET_MFGR_NUM, */ + "xbow_", + CDL_PRI_HI); /* attach before friends */ + + + xwidget_driver_register(XXBOW_WIDGET_PART_NUM, + 0, /* XXBOW_WIDGET_MFGR_NUM, */ + "xbow_", + CDL_PRI_HI); /* attach before friends */ + + xwidget_driver_register(XBOW_WIDGET_PART_NUM, + XBOW_WIDGET_MFGR_NUM, + "xbow_", + CDL_PRI_HI); /* attach before friends */ +} + +#ifdef XBRIDGE_REGS_SIM +/* xbow_set_simulated_regs: sets xbow regs as needed + * for powering through the boot + */ +void +xbow_set_simulated_regs(xbow_t *xbow, int port) +{ + /* + * turn on link + */ + xbow->xb_link(port).link_status = (1<<31); + /* + * and give it a live widget too + */ + xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT; + /* + * zero the link control reg + */ + xbow->xb_link(port).link_control = 0x0; +} +#endif /* XBRIDGE_REGS_SIM */ + +/* + * xbow_attach: the crosstalk provider has + * determined that there is a crossbow widget + * present, and has handed us the connection + * point for that vertex. + * + * We not only add our own vertex, but add + * some "xtalk switch" data to the switch + * vertex (at the connect point's parent) if + * it does not have any. + */ + +/*ARGSUSED */ +int +xbow_attach(devfs_handle_t conn) +{ + /*REFERENCED */ + devfs_handle_t vhdl; + devfs_handle_t busv; + xbow_t *xbow; + xbow_soft_t soft; + int port; + xswitch_info_t info; + xtalk_intr_t intr_hdl; + char devnm[MAXDEVNAME], *s; + xbowreg_t id; + int rev; + int i; + int xbow_num; + static void xbow_errintr_handler(int, void *, struct pt_regs *); + + +#if DEBUG && ATTACH_DEBUG +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk("%v: xbow_attach\n", conn); +#else + printk("0x%x: xbow_attach\n", conn); +#endif +#endif + + /* + * Get a PIO pointer to the base of the crossbow + * chip. + */ +#ifdef XBRIDGE_REGS_SIM + printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t)); + xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL); + /* + * turn on ports e and f like in a real live ibrick + */ + xbow_set_simulated_regs(xbow, 0xe); + xbow_set_simulated_regs(xbow, 0xf); +#else + xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0); +#endif /* XBRIDGE_REGS_SIM */ + + /* + * Locate the "switch" vertex: it is the parent + * of our connection point. + */ + busv = hwgraph_connectpt_get(conn); +#if DEBUG && ATTACH_DEBUG + printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); +#endif + + ASSERT(busv != GRAPH_VERTEX_NONE); + + /* + * Create our private vertex, and connect our + * driver information to it. This makes it possible + * for diagnostic drivers to open the crossbow + * vertex for access to registers. + */ + + /* + * Register a xbow driver with devfs. + * file ops. + */ + vhdl = NULL; + vhdl = devfs_register(conn, EDGE_LBL_XBOW, + DEVFS_FL_AUTO_DEVNUM, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &xbow_fops, (void *)xbow); + if (!vhdl) { + printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", + (void *)conn); + } + + /* + * Allocate the soft state structure and attach + * it to the xbow's vertex + */ + NEW(soft); + soft->conn = conn; + soft->vhdl = vhdl; + soft->busv = busv; + soft->base = xbow; + /* does the universe really need another macro? */ + /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */ + /* hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft); */ + +#define XBOW_NUM_SUFFIX_FORMAT "[xbow# %d]" + + /* Add xbow number as a suffix to the hwgraph name of the xbow. + * This is helpful while looking at the error/warning messages. + */ + xbow_num = 0; + + /* + * get the name of this xbow vertex and keep the info. + * This is needed during errors and interupts, but as + * long as we have it, we can use it elsewhere. + */ + s = dev_to_name(vhdl, devnm, MAXDEVNAME); + soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, + GFP_KERNEL); + sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num); + +#ifdef XBRIDGE_REGS_SIM + /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined + * as 0xd000, so I'm using that for the partnum bitfield. + */ + printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n"); + id = 0x2d000049; +#else + id = xbow->xb_wid_id; +#endif /* XBRIDGE_REGS_SIM */ + rev = XWIDGET_PART_REV_NUM(id); + + mutex_spinlock_init(&soft->xbow_perf_lock); + soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; + soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; + + /* Initialization for GBR bw allocation */ + mutex_spinlock_init(&soft->xbow_bw_alloc_lock); + +#define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */ +#define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ + + /* Set bandwidth hiwatermark and current values */ + for (i = 0; i < MAX_XBOW_PORTS; i++) { + soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX; /* for now */ + soft->bw_cur_used[i] = 0; + } + + /* + * attach the crossbow error interrupt. + */ + intr_hdl = xtalk_intr_alloc(conn, (device_desc_t)0, vhdl); + ASSERT(intr_hdl != NULL); + + xtalk_intr_connect(intr_hdl, + (intr_func_t) xbow_errintr_handler, + (intr_arg_t) soft, + (xtalk_intr_setfunc_t) xbow_setwidint, + (void *) xbow); + + request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid, + ((hub_intr_t)intr_hdl)->i_bit), + (intr_func_t)xbow_errintr_handler, 0, "XBOW error", + (intr_arg_t) soft); + +#ifdef BUS_INT_WAR_NOT_YET + { + void sn_add_polled_interrupt(int, int); + sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid, + ((hub_intr_t)intr_hdl)->i_bit), 5000); + } +#endif + + + /* + * Enable xbow error interrupts + */ + xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); + + /* + * take a census of the widgets present, + * leaving notes at the switch vertex. + */ + info = xswitch_info_new(busv); + + for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; + port < MAX_PORT_NUM; ++port) { + if (!xbow_link_alive(xbow, port)) { +#if DEBUG && XBOW_DEBUG + printk(KERN_INFO "0x%p link %d is not alive\n", + (void *)busv, port); +#endif + continue; + } + if (!xbow_widget_present(xbow, port)) { +#if DEBUG && XBOW_DEBUG + printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", (void *)busv, port); +#endif + continue; + } +#if DEBUG && XBOW_DEBUG + printk(KERN_INFO "0x%p link %d has a widget\n", + (void *)busv, port); +#endif + + xswitch_info_link_is_ok(info, port); + /* + * Turn some error interrupts on + * and turn others off. The PROM has + * some things turned on we don't + * want to see (bandwidth allocation + * errors for instance); so if it + * is not listed here, it is not on. + */ + xbow->xb_link(port).link_control = + ( (xbow->xb_link(port).link_control + /* + * Turn off these bits; they are non-fatal, + * but we might want to save some statistics + * on the frequency of these errors. + * XXX FIXME XXX + */ + & ~XB_CTRL_RCV_CNT_OFLOW_IE + & ~XB_CTRL_XMT_CNT_OFLOW_IE + & ~XB_CTRL_BNDWDTH_ALLOC_IE + & ~XB_CTRL_RCV_IE) + /* + * These are the ones we want to turn on. + */ + | (XB_CTRL_ILLEGAL_DST_IE + | XB_CTRL_OALLOC_IBUF_IE + | XB_CTRL_XMT_MAX_RTRY_IE + | XB_CTRL_MAXREQ_TOUT_IE + | XB_CTRL_XMT_RTRY_IE + | XB_CTRL_SRC_TOUT_IE) ); + } + + xswitch_provider_register(busv, &xbow_provider); + + return 0; /* attach successful */ +} + +/*ARGSUSED */ +int +xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) +{ + return 0; +} + +/*ARGSUSED */ +int +xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) +{ + return 0; +} + +/*ARGSUSED */ +int +xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) +{ + devfs_handle_t vhdl = dev_to_vhdl(dev); + xbow_soft_t soft = xbow_soft_get(vhdl); + int error; + + ASSERT(soft); + len = ctob(btoc(len)); + /* XXX- this ignores the offset!!! */ + error = v_mapphys(vt, (void *) soft->base, len); + return error; +} + +/*ARGSUSED */ +int +xbow_unmap(devfs_handle_t dev, vhandl_t *vt) +{ + return 0; +} + +/* This contains special-case code for grio. There are plans to make + * this general sometime in the future, but till then this should + * be good enough. + */ +xwidgetnum_t +xbow_widget_num_get(devfs_handle_t dev) +{ + devfs_handle_t tdev; + char devname[MAXDEVNAME]; + xwidget_info_t xwidget_info; + int i; + + vertex_to_name(dev, devname, MAXDEVNAME); + + /* If this is a pci controller vertex, traverse up using + * the ".." links to get to the widget. + */ + if (strstr(devname, EDGE_LBL_PCI) && + strstr(devname, EDGE_LBL_CONTROLLER)) { + tdev = dev; + for (i=0; i< 2; i++) { + if (hwgraph_edge_get(tdev, + HWGRAPH_EDGELBL_DOTDOT, &tdev) != + GRAPH_SUCCESS) + return XWIDGET_NONE; + } + + if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) { + return (xwidget_info_id_get(xwidget_info)); + } else { + return XWIDGET_NONE; + } + } + + return XWIDGET_NONE; +} + +int +xbow_ioctl(devfs_handle_t dev, + int cmd, + void *arg, + int flag, + struct cred *cr, + int *rvalp) +{ + devfs_handle_t vhdl; + int error = 0; + +#if defined (DEBUG) + int rc; + devfs_handle_t conn; + struct xwidget_info_s *xwidget_info; + xbow_soft_t xbow_soft; +#endif + *rvalp = 0; + + vhdl = dev_to_vhdl(dev); +#if defined (DEBUG) + xbow_soft = xbow_soft_get(vhdl); + conn = xbow_soft->conn; + + xwidget_info = xwidget_info_get(conn); + ASSERT_ALWAYS(xwidget_info != NULL); + + rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid); + ASSERT_ALWAYS(rc != 0); +#endif + switch (cmd) { + + case XBOWIOC_LLP_ERROR_ENABLE: + if ((error = xbow_enable_llp_monitor(vhdl)) != 0) + error = EINVAL; + + break; + + case XBOWIOC_LLP_ERROR_DISABLE: + + if ((error = xbow_disable_llp_monitor(vhdl)) != 0) + error = EINVAL; + + break; + + default: + break; + + } + return error; +} + +/* + * xbow_widget_present: See if a device is present + * on the specified port of this crossbow. + */ +int +xbow_widget_present(xbow_t *xbow, int port) +{ + if ( IS_RUNNING_ON_SIMULATOR() ) { + if ( (port == 14) || (port == 15) ) { + return 1; + } + else { + return 0; + } + } + else { + /* WAR: port 0xf on PIC is missing present bit */ + if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) && + IS_PIC_XBOW(xbow->xb_wid_id) && port==0xf) { + return 1; + } + return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT; + } +} + +static int +xbow_link_alive(xbow_t * xbow, int port) +{ + xbwX_stat_t xbow_linkstat; + + xbow_linkstat.linkstatus = xbow->xb_link(port).link_status; + return (xbow_linkstat.link_alive); +} + +/* + * xbow_widget_lookup + * Lookup the edges connected to the xbow specified, and + * retrieve the handle corresponding to the widgetnum + * specified. + * If not found, return 0. + */ +devfs_handle_t +xbow_widget_lookup(devfs_handle_t vhdl, + int widgetnum) +{ + xswitch_info_t xswitch_info; + devfs_handle_t conn; + + xswitch_info = xswitch_info_get(vhdl); + conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); + return conn; +} + +/* + * xbow_setwidint: called when xtalk + * is establishing or migrating our + * interrupt service. + */ +static void +xbow_setwidint(xtalk_intr_t intr) +{ + xwidgetnum_t targ = xtalk_intr_target_get(intr); + iopaddr_t addr = xtalk_intr_addr_get(intr); + xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); + xbow_t *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr); + + xbow_intr_preset((void *) xbow, 0, targ, addr, vect); +} + +/* + * xbow_intr_preset: called during mlreset time + * if the platform specific code needs to route + * an xbow interrupt before the xtalk infrastructure + * is available for use. + * + * Also called from xbow_setwidint, so we don't + * replicate the guts of the routine. + * + * XXX- probably should be renamed xbow_wid_intr_set or + * something to reduce confusion. + */ +/*ARGSUSED3 */ +void +xbow_intr_preset(void *which_widget, + int which_widget_intr, + xwidgetnum_t targ, + iopaddr_t addr, + xtalk_intr_vector_t vect) +{ + xbow_t *xbow = (xbow_t *) which_widget; + + xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) | + (0x000F0000 & (targ << 16)) | + XTALK_ADDR_TO_UPPER(addr)); + xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); + +} + +#define XEM_ADD_STR(s) printk("%s", (s)) +#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%llx\n", (n), ((unsigned long long)v)) +#define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v)) +#define XEM_ADD_IOEF(p,n) if (IOERROR_FIELDVALID(ioe,n)) { \ + IOERROR_GETVALUE(p,ioe,n); \ + XEM_ADD_NVAR("ioe." #n, p); \ + } + +#ifdef LATER +static void +xem_add_ioe(ioerror_t *ioe) +{ + union tmp { + ushort stmp; + unsigned long long lltmp; + cpuid_t cputmp; + cnodeid_t cntmp; + iopaddr_t iotmp; + caddr_t catmp; + paddr_t patmp; + } tmp; + + XEM_ADD_IOEF(tmp.stmp, errortype); + XEM_ADD_IOEF(tmp.stmp, widgetnum); + XEM_ADD_IOEF(tmp.stmp, widgetdev); + XEM_ADD_IOEF(tmp.cputmp, srccpu); + XEM_ADD_IOEF(tmp.cntmp, srcnode); + XEM_ADD_IOEF(tmp.cntmp, errnode); + XEM_ADD_IOEF(tmp.iotmp, sysioaddr); + XEM_ADD_IOEF(tmp.iotmp, xtalkaddr); + XEM_ADD_IOEF(tmp.iotmp, busspace); + XEM_ADD_IOEF(tmp.iotmp, busaddr); + XEM_ADD_IOEF(tmp.catmp, vaddr); + XEM_ADD_IOEF(tmp.patmp, memaddr); + XEM_ADD_IOEF(tmp.catmp, epc); + XEM_ADD_IOEF(tmp.catmp, ef); + XEM_ADD_IOEF(tmp.stmp, tnum); +} + +#define XEM_ADD_IOE() (xem_add_ioe(ioe)) +#endif /* LATER */ + +int xbow_xmit_retry_errors = 0; + +int +xbow_xmit_retry_error(xbow_soft_t soft, + int port) +{ + xswitch_info_t info; + devfs_handle_t vhdl; + widget_cfg_t *wid; + widgetreg_t id; + int part; + int mfgr; + + wid = soft->wpio[port - BASE_XBOW_PORT]; + if (wid == NULL) { + /* If we can't track down a PIO + * pointer to our widget yet, + * leave our caller knowing that + * we are interested in this + * interrupt if it occurs in + * the future. + */ + info = xswitch_info_get(soft->busv); + if (!info) + return 1; + vhdl = xswitch_info_vhdl_get(info, port); + if (vhdl == GRAPH_VERTEX_NONE) + return 1; + wid = (widget_cfg_t *) xtalk_piotrans_addr + (vhdl, 0, 0, sizeof *wid, 0); + if (!wid) + return 1; + soft->wpio[port - BASE_XBOW_PORT] = wid; + } + id = wid->w_id; + part = XWIDGET_PART_NUM(id); + mfgr = XWIDGET_MFG_NUM(id); + + /* If this thing is not a Bridge, + * do not activate the WAR, and + * tell our caller we do not need + * to be called again. + */ + if ((part != BRIDGE_WIDGET_PART_NUM) || + (mfgr != BRIDGE_WIDGET_MFGR_NUM)) { + /* FIXME: add Xbridge to the WAR. + * Shouldn't hurt anything. Later need to + * check if we can remove this. + */ + if ((part != XBRIDGE_WIDGET_PART_NUM) || + (mfgr != XBRIDGE_WIDGET_MFGR_NUM)) + return 0; + } + + /* count how many times we + * have picked up after + * LLP Transmit problems. + */ + xbow_xmit_retry_errors++; + + /* rewrite the control register + * to fix things up. + */ + wid->w_control = wid->w_control; + wid->w_control; + + return 1; +} + +/* + * xbow_errintr_handler will be called if the xbow + * sends an interrupt request to report an error. + */ +static void +xbow_errintr_handler(int irq, void *arg, struct pt_regs *ep) +{ + ioerror_t ioe[1]; + xbow_soft_t soft = (xbow_soft_t) arg; + xbow_t *xbow = soft->base; + xbowreg_t wid_control; + xbowreg_t wid_stat; + xbowreg_t wid_err_cmdword; + xbowreg_t wid_err_upper; + xbowreg_t wid_err_lower; + w_err_cmd_word_u wid_err; + unsigned long long wid_err_addr; + + int fatal = 0; + int dump_ioe = 0; + static int xbow_error_handler(void *, int, ioerror_mode_t, ioerror_t *); + + wid_control = xbow->xb_wid_control; + wid_stat = xbow->xb_wid_stat_clr; + wid_err_cmdword = xbow->xb_wid_err_cmdword; + wid_err_upper = xbow->xb_wid_err_upper; + wid_err_lower = xbow->xb_wid_err_lower; + xbow->xb_wid_err_cmdword = 0; + + wid_err_addr = wid_err_lower | (((iopaddr_t) wid_err_upper & WIDGET_ERR_UPPER_ADDR_ONLY) << 32); + + if (wid_stat & XB_WID_STAT_LINK_INTR_MASK) { + int port; + + wid_err.r = wid_err_cmdword; + + for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; + port < MAX_PORT_NUM; port++) { + if (wid_stat & XB_WID_STAT_LINK_INTR(port)) { + xb_linkregs_t *link = &(xbow->xb_link(port)); + xbowreg_t link_control = link->link_control; + xbowreg_t link_status = link->link_status_clr; + xbowreg_t link_aux_status = link->link_aux_status; + xbowreg_t link_pend; + + link_pend = link_status & link_control & + (XB_STAT_ILLEGAL_DST_ERR + | XB_STAT_OALLOC_IBUF_ERR + | XB_STAT_RCV_CNT_OFLOW_ERR + | XB_STAT_XMT_CNT_OFLOW_ERR + | XB_STAT_XMT_MAX_RTRY_ERR + | XB_STAT_RCV_ERR + | XB_STAT_XMT_RTRY_ERR + | XB_STAT_MAXREQ_TOUT_ERR + | XB_STAT_SRC_TOUT_ERR + ); + + if (link_pend & XB_STAT_ILLEGAL_DST_ERR) { + if (wid_err.f.sidn == port) { + IOERROR_INIT(ioe); + IOERROR_SETVALUE(ioe, widgetnum, port); + IOERROR_SETVALUE(ioe, xtalkaddr, wid_err_addr); + if (IOERROR_HANDLED == + xbow_error_handler(soft, + IOECODE_DMA, + MODE_DEVERROR, + ioe)) { + link_pend &= ~XB_STAT_ILLEGAL_DST_ERR; + } else { + dump_ioe++; + } + } + } + /* Xbow/Bridge WAR: + * if the bridge signals an LLP Transmitter Retry, + * rewrite its control register. + * If someone else triggers this interrupt, + * ignore (and disable) the interrupt. + */ + if (link_pend & XB_STAT_XMT_RTRY_ERR) { + if (!xbow_xmit_retry_error(soft, port)) { + link_control &= ~XB_CTRL_XMT_RTRY_IE; + link->link_control = link_control; + link->link_control; /* stall until written */ + } + link_pend &= ~XB_STAT_XMT_RTRY_ERR; + } + if (link_pend) { + devfs_handle_t xwidget_vhdl; + char *xwidget_name; + + /* Get the widget name corresponding to the current + * xbow link. + */ + xwidget_vhdl = xbow_widget_lookup(soft->busv,port); + xwidget_name = xwidget_name_get(xwidget_vhdl); + + printk("%s port %X[%s] XIO Bus Error", + soft->name, port, xwidget_name); + if (link_status & XB_STAT_MULTI_ERR) + XEM_ADD_STR("\tMultiple Errors\n"); + if (link_status & XB_STAT_ILLEGAL_DST_ERR) + XEM_ADD_STR("\tInvalid Packet Destination\n"); + if (link_status & XB_STAT_OALLOC_IBUF_ERR) + XEM_ADD_STR("\tInput Overallocation Error\n"); + if (link_status & XB_STAT_RCV_CNT_OFLOW_ERR) + XEM_ADD_STR("\tLLP receive error counter overflow\n"); + if (link_status & XB_STAT_XMT_CNT_OFLOW_ERR) + XEM_ADD_STR("\tLLP transmit retry counter overflow\n"); + if (link_status & XB_STAT_XMT_MAX_RTRY_ERR) + XEM_ADD_STR("\tLLP Max Transmitter Retry\n"); + if (link_status & XB_STAT_RCV_ERR) + XEM_ADD_STR("\tLLP Receiver error\n"); + if (link_status & XB_STAT_XMT_RTRY_ERR) + XEM_ADD_STR("\tLLP Transmitter Retry\n"); + if (link_status & XB_STAT_MAXREQ_TOUT_ERR) + XEM_ADD_STR("\tMaximum Request Timeout\n"); + if (link_status & XB_STAT_SRC_TOUT_ERR) + XEM_ADD_STR("\tSource Timeout Error\n"); + + { + int other_port; + + for (other_port = 8; other_port < 16; ++other_port) { + if (link_aux_status & (1 << other_port)) { + /* XXX- need to go to "other_port" + * and clean up after the timeout? + */ + XEM_ADD_VAR(other_port); + } + } + } + +#if !DEBUG + if (kdebug) { +#endif + XEM_ADD_VAR(link_control); + XEM_ADD_VAR(link_status); + XEM_ADD_VAR(link_aux_status); + +#ifdef LATER + if (dump_ioe) { + XEM_ADD_IOE(); + dump_ioe = 0; + } +#endif +#if !DEBUG + } +#endif + fatal++; + } + } + } + } + if (wid_stat & wid_control & XB_WID_STAT_WIDGET0_INTR) { + /* we have a "widget zero" problem */ + + if (wid_stat & (XB_WID_STAT_MULTI_ERR + | XB_WID_STAT_XTALK_ERR + | XB_WID_STAT_REG_ACC_ERR)) { + + printk("%s Port 0 XIO Bus Error", + soft->name); + if (wid_stat & XB_WID_STAT_MULTI_ERR) + XEM_ADD_STR("\tMultiple Error\n"); + if (wid_stat & XB_WID_STAT_XTALK_ERR) + XEM_ADD_STR("\tXIO Error\n"); + if (wid_stat & XB_WID_STAT_REG_ACC_ERR) + XEM_ADD_STR("\tRegister Access Error\n"); + + fatal++; + } + } + if (fatal) { + XEM_ADD_VAR(wid_stat); + XEM_ADD_VAR(wid_control); + XEM_ADD_VAR(wid_err_cmdword); + XEM_ADD_VAR(wid_err_upper); + XEM_ADD_VAR(wid_err_lower); + XEM_ADD_VAR(wid_err_addr); + PRINT_PANIC("XIO Bus Error"); + } +} + +/* + * XBOW ERROR Handling routines. + * These get invoked as part of walking down the error handling path + * from hub/heart towards the I/O device that caused the error. + */ + +/* + * xbow_error_handler + * XBow error handling dispatch routine. + * This is the primary interface used by external world to invoke + * in case of an error related to a xbow. + * Only functionality in this layer is to identify the widget handle + * given the widgetnum. Otherwise, xbow does not gathers any error + * data. + */ +static int +xbow_error_handler( + void *einfo, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioerror) +{ + int retval = IOERROR_WIDGETLEVEL; + + xbow_soft_t soft = (xbow_soft_t) einfo; + int port; + devfs_handle_t conn; + devfs_handle_t busv; + + xbow_t *xbow = soft->base; + xbowreg_t wid_stat; + xbowreg_t wid_err_cmdword; + xbowreg_t wid_err_upper; + xbowreg_t wid_err_lower; + unsigned long long wid_err_addr; + + xb_linkregs_t *link; + xbowreg_t link_control; + xbowreg_t link_status; + xbowreg_t link_aux_status; + + ASSERT(soft != 0); + busv = soft->busv; + +#if DEBUG && ERROR_DEBUG + printk("%s: xbow_error_handler\n", soft->name, busv); +#endif + + IOERROR_GETVALUE(port, ioerror, widgetnum); + + if (port == 0) { + /* error during access to xbow: + * do NOT attempt to access xbow regs. + */ + if (mode == MODE_DEVPROBE) + return IOERROR_HANDLED; + + if (error_code & IOECODE_DMA) { + printk(KERN_ALERT + "DMA error blamed on Crossbow at %s\n" + "\tbut Crosbow never initiates DMA!", + soft->name); + } + if (error_code & IOECODE_PIO) { + iopaddr_t tmp; + IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); + printk(KERN_ALERT "PIO Error on XIO Bus %s\n" + "\tattempting to access XIO controller\n" + "\twith offset 0x%lx", + soft->name, tmp); + } + /* caller will dump contents of ioerror + * in DEBUG and kdebug kernels. + */ + + return retval; + } + /* + * error not on port zero: + * safe to read xbow registers. + */ + wid_stat = xbow->xb_wid_stat; + wid_err_cmdword = xbow->xb_wid_err_cmdword; + wid_err_upper = xbow->xb_wid_err_upper; + wid_err_lower = xbow->xb_wid_err_lower; + + wid_err_addr = + wid_err_lower + | (((iopaddr_t) wid_err_upper + & WIDGET_ERR_UPPER_ADDR_ONLY) + << 32); + + if ((port < BASE_XBOW_PORT) || + (port >= MAX_PORT_NUM)) { + + if (mode == MODE_DEVPROBE) + return IOERROR_HANDLED; + + if (error_code & IOECODE_DMA) { + printk(KERN_ALERT + "DMA error blamed on XIO port at %s/%d\n" + "\tbut Crossbow does not support that port", + soft->name, port); + } + if (error_code & IOECODE_PIO) { + iopaddr_t tmp; + IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); + printk(KERN_ALERT + "PIO Error on XIO Bus %s\n" + "\tattempting to access XIO port %d\n" + "\t(which Crossbow does not support)" + "\twith offset 0x%lx", + soft->name, port, tmp); + } +#if !DEBUG + if (kdebug) { +#endif + XEM_ADD_STR("Raw status values for Crossbow:\n"); + XEM_ADD_VAR(wid_stat); + XEM_ADD_VAR(wid_err_cmdword); + XEM_ADD_VAR(wid_err_upper); + XEM_ADD_VAR(wid_err_lower); + XEM_ADD_VAR(wid_err_addr); +#if !DEBUG + } +#endif + + /* caller will dump contents of ioerror + * in DEBUG and kdebug kernels. + */ + + return retval; + } + /* access to valid port: + * ok to check port status. + */ + + link = &(xbow->xb_link(port)); + link_control = link->link_control; + link_status = link->link_status; + link_aux_status = link->link_aux_status; + + /* Check that there is something present + * in that XIO port. + */ + /* WAR: PIC widget 0xf is missing prescense bit */ + if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) && + IS_PIC_XBOW(xbow->xb_wid_id) && (port==0xf)) + ; + else + if (!(link_aux_status & XB_AUX_STAT_PRESENT)) { + /* nobody connected. */ + if (mode == MODE_DEVPROBE) + return IOERROR_HANDLED; + + if (error_code & IOECODE_DMA) { + printk(KERN_ALERT + "DMA error blamed on XIO port at %s/%d\n" + "\tbut there is no device connected there.", + soft->name, port); + } + if (error_code & IOECODE_PIO) { + iopaddr_t tmp; + IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); + printk(KERN_ALERT + "PIO Error on XIO Bus %s\n" + "\tattempting to access XIO port %d\n" + "\t(which has no device connected)" + "\twith offset 0x%lx", + soft->name, port, tmp); + } +#if !DEBUG + if (kdebug) { +#endif + XEM_ADD_STR("Raw status values for Crossbow:\n"); + XEM_ADD_VAR(wid_stat); + XEM_ADD_VAR(wid_err_cmdword); + XEM_ADD_VAR(wid_err_upper); + XEM_ADD_VAR(wid_err_lower); + XEM_ADD_VAR(wid_err_addr); + XEM_ADD_VAR(port); + XEM_ADD_VAR(link_control); + XEM_ADD_VAR(link_status); + XEM_ADD_VAR(link_aux_status); +#if !DEBUG + } +#endif + return retval; + + } + /* Check that the link is alive. + */ + if (!(link_status & XB_STAT_LINKALIVE)) { + iopaddr_t tmp; + /* nobody connected. */ + if (mode == MODE_DEVPROBE) + return IOERROR_HANDLED; + + printk(KERN_ALERT + "%s%sError on XIO Bus %s port %d", + (error_code & IOECODE_DMA) ? "DMA " : "", + (error_code & IOECODE_PIO) ? "PIO " : "", + soft->name, port); + + IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); + if ((error_code & IOECODE_PIO) && + (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { + printk("\tAccess attempted to offset 0x%lx\n", tmp); + } + if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD) + XEM_ADD_STR("\tLink never came out of reset\n"); + else + XEM_ADD_STR("\tLink failed while transferring data\n"); + + } + /* get the connection point for the widget + * involved in this error; if it exists and + * is not our connectpoint, cycle back through + * xtalk_error_handler to deliver control to + * the proper handler (or to report a generic + * crosstalk error). + * + * If the downstream handler won't handle + * the problem, we let our upstream caller + * deal with it, after (in DEBUG and kdebug + * kernels) dumping the xbow state for this + * port. + */ + conn = xbow_widget_lookup(busv, port); + if ((conn != GRAPH_VERTEX_NONE) && + (conn != soft->conn)) { + retval = xtalk_error_handler(conn, error_code, mode, ioerror); + if (retval == IOERROR_HANDLED) + return IOERROR_HANDLED; + } + if (mode == MODE_DEVPROBE) + return IOERROR_HANDLED; + + if (retval == IOERROR_UNHANDLED) { + iopaddr_t tmp; + retval = IOERROR_PANIC; + + printk(KERN_ALERT + "%s%sError on XIO Bus %s port %d", + (error_code & IOECODE_DMA) ? "DMA " : "", + (error_code & IOECODE_PIO) ? "PIO " : "", + soft->name, port); + + IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); + if ((error_code & IOECODE_PIO) && + (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { + printk("\tAccess attempted to offset 0x%lx\n", tmp); + } + } + +#if !DEBUG + if (kdebug) { +#endif + XEM_ADD_STR("Raw status values for Crossbow:\n"); + XEM_ADD_VAR(wid_stat); + XEM_ADD_VAR(wid_err_cmdword); + XEM_ADD_VAR(wid_err_upper); + XEM_ADD_VAR(wid_err_lower); + XEM_ADD_VAR(wid_err_addr); + XEM_ADD_VAR(port); + XEM_ADD_VAR(link_control); + XEM_ADD_VAR(link_status); + XEM_ADD_VAR(link_aux_status); +#if !DEBUG + } +#endif + /* caller will dump raw ioerror data + * in DEBUG and kdebug kernels. + */ + + return retval; +} + +void +xbow_update_perf_counters(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; + xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; + xbow_perfcount_t perf_reg; + unsigned long s; + int link, i; + + for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { + if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) + continue; + + s = mutex_spinlock(&xbow_soft->xbow_perf_lock); + + perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; + + link = perf_reg.xb_perf.link_select; + + (xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] += + ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK); + xbow_perf->xp_current = perf_reg.xb_perf.count; + + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + } +} + +xbow_perf_link_t * +xbow_get_perf_counters(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; + + return xbow_perf_link; +} + +int +xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; + xbow_linkctrl_t xbow_link_ctrl; + xbow_t *xbow = xbow_soft->base; + xbow_perfcount_t perf_reg; + unsigned long s; + int i; + + link -= BASE_XBOW_PORT; + if ((link < 0) || (link >= MAX_XBOW_PORTS)) + return -1; + + if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK)) + return -1; + + if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS)) + return -1; + + s = mutex_spinlock(&xbow_soft->xbow_perf_lock); + + if ((xbow_perf + counter)->xp_mode && mode) { + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + return -1; + } + for (i = 0; i < XBOW_PERF_COUNTERS; i++) { + if (i == counter) + continue; + if (((xbow_perf + i)->xp_link == link) && + ((xbow_perf + i)->xp_mode)) { + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + return -1; + } + } + xbow_perf += counter; + + xbow_perf->xp_curlink = xbow_perf->xp_link = link; + xbow_perf->xp_curmode = xbow_perf->xp_mode = mode; + + xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control; + xbow_link_ctrl.xb_linkcontrol.perf_mode = mode; + xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword; + + perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; + perf_reg.xb_perf.link_select = link; + *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; + xbow_perf->xp_current = perf_reg.xb_perf.count; + + mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); + return 0; +} + +xbow_link_status_t * +xbow_get_llp_status(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; + + return xbow_llp_status; +} + +void +xbow_update_llp_status(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; + xbow_t *xbow; + xbwX_stat_t lnk_sts; + xbow_aux_link_status_t aux_sts; + int link; + devfs_handle_t xwidget_vhdl; + char *xwidget_name; + + xbow = (xbow_t *) xbow_soft->base; + for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) { + /* Get the widget name corresponding the current link. + * Note : 0 <= link < MAX_XBOW_PORTS(8). + * BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10) + */ + xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT); + xwidget_name = xwidget_name_get(xwidget_vhdl); + aux_sts.aux_linkstatus + = xbow->xb_link_raw[link].link_aux_status; + lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr; + + if (lnk_sts.link_alive == 0) + continue; + + xbow_llp_status->rx_err_count += + aux_sts.xb_aux_linkstatus.rx_err_cnt; + + xbow_llp_status->tx_retry_count += + aux_sts.xb_aux_linkstatus.tx_retry_cnt; + + if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { +#ifdef LATER + printk(KERN_WARNING "link %d[%s]: bad status 0x%x\n", + link, xwidget_name, lnk_sts.linkstatus); +#endif + } + } +} + +int +xbow_disable_llp_monitor(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + int port; + + for (port = 0; port < MAX_XBOW_PORTS; port++) { + xbow_soft->xbow_link_status[port].rx_err_count = 0; + xbow_soft->xbow_link_status[port].tx_retry_count = 0; + } + + xbow_soft->link_monitor = 0; + return 0; +} + +int +xbow_enable_llp_monitor(devfs_handle_t vhdl) +{ + xbow_soft_t xbow_soft = xbow_soft_get(vhdl); + + xbow_soft->link_monitor = 1; + return 0; +} + + +int +xbow_reset_link(devfs_handle_t xconn_vhdl) +{ + xwidget_info_t widget_info; + xwidgetnum_t port; + xbow_t *xbow; + xbowreg_t ctrl; + xbwX_stat_t stat; + unsigned itick; + unsigned dtick; + static int ticks_per_ms = 0; + + if (!ticks_per_ms) { + itick = get_timestamp(); + us_delay(1000); + ticks_per_ms = get_timestamp() - itick; + } + widget_info = xwidget_info_get(xconn_vhdl); + port = xwidget_info_id_get(widget_info); + +#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ + xbow = XBOW_K1PTR; +#else + { + devfs_handle_t xbow_vhdl; + xbow_soft_t xbow_soft; + + hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); + xbow_soft = xbow_soft_get(xbow_vhdl); + xbow = xbow_soft->base; + } +#endif + + /* + * This requires three PIOs (reset the link, check for the + * reset, restore the control register for the link) plus + * 10us to wait for the reset. We allow up to 1ms for the + * widget to come out of reset before giving up and + * returning a failure. + */ + ctrl = xbow->xb_link(port).link_control; + xbow->xb_link(port).link_reset = 0; + itick = get_timestamp(); + while (1) { + stat.linkstatus = xbow->xb_link(port).link_status; + if (stat.link_alive) + break; + dtick = get_timestamp() - itick; + if (dtick > ticks_per_ms) { + return -1; /* never came out of reset */ + } + DELAY(2); /* don't beat on link_status */ + } + xbow->xb_link(port).link_control = ctrl; + return 0; +} + +/* + * Dump xbow registers. + * input parameter is either a pointer to + * the xbow chip or the vertex handle for + * an xbow vertex. + */ +void +idbg_xbowregs(int64_t regs) +{ + xbow_t *xbow; + int i; + xb_linkregs_t *link; + + xbow = (xbow_t *) regs; + +#ifdef LATER + qprintf("Printing xbow registers starting at 0x%x\n", xbow); + qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", + xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, + xbow->xb_wid_err_lower, xbow->xb_wid_control, + xbow->xb_wid_req_timeout); + qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", + xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, + xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, + xbow->xb_wid_arb_reload); +#endif + + for (i = 8; i <= 0xf; i++) { + link = &xbow->xb_link(i); +#ifdef LATER + qprintf("Link %d registers\n", i); + qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", + link->link_control, link->link_status, + link->link_arb_upper, link->link_arb_lower, + link->link_aux_status); +#endif + } +} + + +#define XBOW_ARB_RELOAD_TICKS 25 + /* granularity: 4 MB/s, max: 124 MB/s */ +#define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS) + +#define XBOW_BYTES_TO_GBR(BYTES_per_s) (int) (BYTES_per_s / GRANULARITY) + +#define XBOW_GBR_TO_BYTES(cnt) (bandwidth_t) ((cnt) * GRANULARITY) + +#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec) \ + ((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr) + +#define XBOW_ARB_GBR_MAX 31 + +#define ABS(x) ((x > 0) ? (x) : (-1 * x)) + /* absolute value */ + +int +xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec) +{ + int gbr_granted; + int new_total_gbr; + int change_gbr; + bandwidth_t new_total_bw; + +#ifdef GRIO_DEBUG + printk("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n", + old_bytes_per_sec, bytes_per_sec); +#endif /* GRIO_DEBUG */ + + gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)), + old_bytes_per_sec); + new_total_bw = old_bytes_per_sec + bytes_per_sec; + new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)), + new_total_bw); + + change_gbr = new_total_gbr - gbr_granted; + +#ifdef GRIO_DEBUG + printk("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n", + gbr_granted, new_total_gbr, change_gbr); +#endif /* GRIO_DEBUG */ + + return (change_gbr); +} + +/* Conversion from GBR to bytes */ +bandwidth_t +xbow_gbr_to_bytes(int gbr) +{ + return (XBOW_GBR_TO_BYTES(gbr)); +} + +/* Given the vhdl for the desired xbow, the src and dest. widget ids + * and the req_bw value, this xbow driver entry point accesses the + * xbow registers and allocates the desired bandwidth if available. + * + * If bandwidth allocation is successful, return success else return failure. + */ +int +xbow_prio_bw_alloc(devfs_handle_t vhdl, + xwidgetnum_t src_wid, + xwidgetnum_t dest_wid, + unsigned long long old_alloc_bw, + unsigned long long req_bw) +{ + xbow_soft_t soft = xbow_soft_get(vhdl); + volatile xbowreg_t *xreg; + xbowreg_t mask; + unsigned long s; + int error = 0; + bandwidth_t old_bw_BYTES, req_bw_BYTES; + xbowreg_t old_xreg; + int old_bw_GBR, req_bw_GBR, new_bw_GBR; + +#ifdef GRIO_DEBUG + printk("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n", + (int) vhdl, (int) src_wid, (int) dest_wid, req_bw); +#endif + + ASSERT(XBOW_WIDGET_IS_VALID(src_wid)); + ASSERT(XBOW_WIDGET_IS_VALID(dest_wid)); + + s = mutex_spinlock(&soft->xbow_bw_alloc_lock); + + /* Get pointer to the correct register */ + xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid); + + /* Get mask for GBR count value */ + mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid); + + req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw); + req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR))) + : xbow_gbr_to_bytes(req_bw_GBR); + +#ifdef GRIO_DEBUG + printk("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n", + req_bw, req_bw_BYTES, req_bw_GBR); +#endif /* GRIO_DEBUG */ + + old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS]; + old_xreg = *xreg; + old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid)); + +#ifdef GRIO_DEBUG + ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR); + + printk("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR); + + printk("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n", + req_bw_BYTES, old_bw_BYTES, + soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]); + +#endif /* GRIO_DEBUG */ + + /* Accept the request only if we don't exceed the destination + * port HIWATER_MARK *AND* the max. link GBR arbitration count + */ + if (((old_bw_BYTES + req_bw_BYTES) <= + soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) && + (req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) { + + new_bw_GBR = (old_bw_GBR + req_bw_GBR); + + /* Set this in the xbow link register */ + *xreg = (old_xreg & ~mask) | \ + (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask); + + soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] = + xbow_gbr_to_bytes(new_bw_GBR); + } else { + error = 1; + } + + mutex_spinunlock(&soft->xbow_bw_alloc_lock, s); + + return (error); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/sn2/xtalk.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/xtalk.c --- linux-2.4.19/arch/ia64/sn/io/sn2/xtalk.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/sn2/xtalk.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1087 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Implement crosstalk provider operations. The xtalk* layer provides a + * platform-independent interface for crosstalk devices. This layer + * switches among the possible implementations of a crosstalk adapter. + * + * On platforms with only one possible xtalk provider, macros can be + * set up at the top that cause the table lookups and indirections to + * completely disappear. + */ + +#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) +#define DEL(ptr) (kfree(ptr)) + +char widget_info_fingerprint[] = "widget_info"; + +cdl_p xtalk_registry = NULL; + +#define DEV_FUNC(dev,func) hub_##func +#define CAST_PIOMAP(x) ((hub_piomap_t)(x)) +#define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) +#define CAST_INTR(x) ((hub_intr_t)(x)) + +/* ===================================================================== + * Function Table of Contents + */ +xtalk_piomap_t xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); +void xtalk_piomap_free(xtalk_piomap_t); +caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); +void xtalk_piomap_done(xtalk_piomap_t); +caddr_t xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned); +caddr_t xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); +void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); +caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); +static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); +xtalk_dmamap_t xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +void xtalk_dmamap_free(xtalk_dmamap_t); +iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); +alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); +void xtalk_dmamap_done(xtalk_dmamap_t); +iopaddr_t xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +void xtalk_dmamap_drain(xtalk_dmamap_t); +void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); +void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); +xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); +xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); +void xtalk_intr_free(xtalk_intr_t); +int xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *); +void xtalk_intr_disconnect(xtalk_intr_t); +devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); +int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); +int xtalk_error_devenable(devfs_handle_t, int, int); +void xtalk_provider_startup(devfs_handle_t); +void xtalk_provider_shutdown(devfs_handle_t); +devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t); +xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); +xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); +iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); +void *xtalk_intr_sfarg_get(xtalk_intr_t); +devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t); +xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); +iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); +ulong xtalk_pio_mapsz_get(xtalk_piomap_t); +caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); +devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t); +xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); +xwidget_info_t xwidget_info_chk(devfs_handle_t); +xwidget_info_t xwidget_info_get(devfs_handle_t); +void xwidget_info_set(devfs_handle_t, xwidget_info_t); +devfs_handle_t xwidget_info_dev_get(xwidget_info_t); +xwidgetnum_t xwidget_info_id_get(xwidget_info_t); +devfs_handle_t xwidget_info_master_get(xwidget_info_t); +xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); +xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); +xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); +char *xwidget_info_name_get(xwidget_info_t); +void xtalk_init(void); +void xtalk_provider_register(devfs_handle_t, xtalk_provider_t *); +void xtalk_provider_unregister(devfs_handle_t); +xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t); +int xwidget_driver_register(xwidget_part_num_t, + xwidget_mfg_num_t, + char *, unsigned); +void xwidget_driver_unregister(char *); +int xwidget_register(xwidget_hwid_t, devfs_handle_t, + xwidgetnum_t, devfs_handle_t, + xwidgetnum_t, async_attach_t); +int xwidget_unregister(devfs_handle_t); +void xwidget_reset(devfs_handle_t); +char *xwidget_name_get(devfs_handle_t); +#if !defined(DEV_FUNC) +/* + * There is more than one possible provider + * for this platform. We need to examine the + * master vertex of the current vertex for + * a provider function structure, and indirect + * through the appropriately named member. + */ +#define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func +#define CAST_PIOMAP(x) ((xtalk_piomap_t)(x)) +#define CAST_DMAMAP(x) ((xtalk_dmamap_t)(x)) +#define CAST_INTR(x) ((xtalk_intr_t)(x)) + +static xtalk_provider_t * +xwidget_to_provider_fns(devfs_handle_t xconn) +{ + xwidget_info_t widget_info; + xtalk_provider_t *provider_fns; + + widget_info = xwidget_info_get(xconn); + ASSERT(widget_info != NULL); + + provider_fns = xwidget_info_pops_get(widget_info); + ASSERT(provider_fns != NULL); + + return (provider_fns); +} +#endif + +/* + * Many functions are not passed their vertex + * information directly; rather, they must + * dive through a resource map. These macros + * are available to coordinate this detail. + */ +#define PIOMAP_FUNC(map,func) DEV_FUNC(map->xp_dev,func) +#define DMAMAP_FUNC(map,func) DEV_FUNC(map->xd_dev,func) +#define INTR_FUNC(intr,func) DEV_FUNC(intr_hdl->xi_dev,func) + +/* ===================================================================== + * PIO MANAGEMENT + * + * For mapping system virtual address space to + * xtalk space on a specified widget + */ + +xtalk_piomap_t +xtalk_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ + device_desc_t dev_desc, /* device descriptor */ + iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ + size_t byte_count, + size_t byte_count_max, /* maximum size of a mapping */ + unsigned flags) +{ /* defined in sys/pio.h */ + return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc) + (dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags); +} + + +void +xtalk_piomap_free(xtalk_piomap_t xtalk_piomap) +{ + PIOMAP_FUNC(xtalk_piomap, piomap_free) + (CAST_PIOMAP(xtalk_piomap)); +} + + +caddr_t +xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap, /* mapping resources */ + iopaddr_t xtalk_addr, /* map for this xtalk address */ + size_t byte_count) +{ /* map this many bytes */ + return PIOMAP_FUNC(xtalk_piomap, piomap_addr) + (CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count); +} + + +void +xtalk_piomap_done(xtalk_piomap_t xtalk_piomap) +{ + PIOMAP_FUNC(xtalk_piomap, piomap_done) + (CAST_PIOMAP(xtalk_piomap)); +} + + +caddr_t +xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + iopaddr_t xtalk_addr, /* Crosstalk address */ + size_t byte_count, /* map this many bytes */ + unsigned flags) +{ /* (currently unused) */ + return DEV_FUNC(dev, piotrans_addr) + (dev, dev_desc, xtalk_addr, byte_count, flags); +} + +caddr_t +xtalk_pio_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + iopaddr_t addr, /* starting address (or offset in window) */ + size_t byte_count, /* map this many bytes */ + xtalk_piomap_t *mapp, /* where to return the map pointer */ + unsigned flags) +{ /* PIO flags */ + xtalk_piomap_t map = 0; + caddr_t res; + + if (mapp) + *mapp = 0; /* record "no map used" */ + + res = xtalk_piotrans_addr + (dev, dev_desc, addr, byte_count, flags); + if (res) + return res; /* xtalk_piotrans worked */ + + map = xtalk_piomap_alloc + (dev, dev_desc, addr, byte_count, byte_count, flags); + if (!map) + return res; /* xtalk_piomap_alloc failed */ + + res = xtalk_piomap_addr + (map, addr, byte_count); + if (!res) { + xtalk_piomap_free(map); + return res; /* xtalk_piomap_addr failed */ + } + if (mapp) + *mapp = map; /* pass back map used */ + + return res; /* xtalk_piomap_addr succeeded */ +} + +/* ===================================================================== + * EARLY PIOTRANS SUPPORT + * + * There are places where drivers (mgras, for instance) + * need to get PIO translations before the infrastructure + * is extended to them (setting up textports, for + * instance). These drivers should call + * xtalk_early_piotrans_addr with their xtalk ID + * information, a sequence number (so we can use the second + * mgras for instance), and the usual piotrans parameters. + * + * Machine specific code should provide an implementation + * of early_piotrans_addr, and present a pointer to this + * function to xtalk_set_early_piotrans_addr so it can be + * used by clients without the clients having to know what + * platform or what xtalk provider is in use. + */ + +static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr; + +xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr; + +/* xtalk_set_early_piotrans_addr: + * specify the early_piotrans_addr implementation function. + */ +void +xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl) +{ + impl_early_piotrans_addr = impl; +} + +/* xtalk_early_piotrans_addr: + * figure out a PIO address for the "nth" crosstalk widget that + * matches the specified part and mfgr number. Returns NULL if + * there is no such widget, or if the requested mapping can not + * be constructed. + * Limitations on which crosstalk slots (and busses) are + * checked, and definitions of the ordering of the search across + * the crosstalk slots, are defined by the platform. + */ +caddr_t +xtalk_early_piotrans_addr(xwidget_part_num_t part_num, + xwidget_mfg_num_t mfg_num, + int which, + iopaddr_t xtalk_addr, + size_t byte_count, + unsigned flags) +{ + return impl_early_piotrans_addr + (part_num, mfg_num, which, xtalk_addr, byte_count, flags); +} + +/* null_xtalk_early_piotrans_addr: + * used as the early_piotrans_addr implementation until and + * unless a real implementation is provided. In DEBUG kernels, + * we want to know who is calling before the implementation is + * registered; in non-DEBUG kernels, return NULL representing + * lack of mapping support. + */ +/*ARGSUSED */ +static caddr_t +null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num, + xwidget_mfg_num_t mfg_num, + int which, + iopaddr_t xtalk_addr, + size_t byte_count, + unsigned flags) +{ +#if DEBUG + PRINT_PANIC("null_xtalk_early_piotrans_addr"); +#endif + return NULL; +} + +/* ===================================================================== + * DMA MANAGEMENT + * + * For mapping from crosstalk space to system + * physical space. + */ + +xtalk_dmamap_t +xtalk_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ + device_desc_t dev_desc, /* device descriptor */ + size_t byte_count_max, /* max size of a mapping */ + unsigned flags) +{ /* defined in dma.h */ + return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc) + (dev, dev_desc, byte_count_max, flags); +} + + +void +xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap) +{ + DMAMAP_FUNC(xtalk_dmamap, dmamap_free) + (CAST_DMAMAP(xtalk_dmamap)); +} + + +iopaddr_t +xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ + paddr_t paddr, /* map for this address */ + size_t byte_count) +{ /* map this many bytes */ + return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr) + (CAST_DMAMAP(xtalk_dmamap), paddr, byte_count); +} + + +alenlist_t +xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ + alenlist_t alenlist, /* map this Address/Length List */ + unsigned flags) +{ + return DMAMAP_FUNC(xtalk_dmamap, dmamap_list) + (CAST_DMAMAP(xtalk_dmamap), alenlist, flags); +} + + +void +xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) +{ + DMAMAP_FUNC(xtalk_dmamap, dmamap_done) + (CAST_DMAMAP(xtalk_dmamap)); +} + + +iopaddr_t +xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + paddr_t paddr, /* system physical address */ + size_t byte_count, /* length */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_addr) + (dev, dev_desc, paddr, byte_count, flags); +} + + +alenlist_t +xtalk_dmatrans_list(devfs_handle_t dev, /* translate for this device */ + device_desc_t dev_desc, /* device descriptor */ + alenlist_t palenlist, /* system address/length list */ + unsigned flags) +{ /* defined in dma.h */ + return DEV_FUNC(dev, dmatrans_list) + (dev, dev_desc, palenlist, flags); +} + +void +xtalk_dmamap_drain(xtalk_dmamap_t map) +{ + DMAMAP_FUNC(map, dmamap_drain) + (CAST_DMAMAP(map)); +} + +void +xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +{ + DEV_FUNC(dev, dmaaddr_drain) + (dev, addr, size); +} + +void +xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) +{ + DEV_FUNC(dev, dmalist_drain) + (dev, list); +} + +/* ===================================================================== + * INTERRUPT MANAGEMENT + * + * Allow crosstalk devices to establish interrupts + */ + +/* + * Allocate resources required for an interrupt as specified in intr_desc. + * Return resource handle in intr_hdl. + */ +xtalk_intr_t +xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) +{ /* owner of this interrupt */ + return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) + (dev, dev_desc, owner_dev); +} + +/* + * Allocate resources required for an interrupt as specified in dev_desc. + * Unconditionally setup resources to be non-threaded. + * Return resource handle in intr_hdl. + */ +xtalk_intr_t +xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev) /* owner of this interrupt */ +{ + return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) + (dev, dev_desc, owner_dev); +} + +/* + * Free resources consumed by intr_alloc. + */ +void +xtalk_intr_free(xtalk_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_free) + (CAST_INTR(intr_hdl)); +} + + +/* + * Associate resources allocated with a previous xtalk_intr_alloc call with the + * described handler, arg, name, etc. + * + * Returns 0 on success, returns <0 on failure. + */ +int +xtalk_intr_connect(xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ + intr_func_t intr_func, /* xtalk intr handler */ + intr_arg_t intr_arg, /* arg to intr handler */ + xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ + void *setfunc_arg) /* arg to setfunc */ +{ + return INTR_FUNC(intr_hdl, intr_connect) + (CAST_INTR(intr_hdl), intr_func, intr_arg, setfunc, setfunc_arg); +} + + +/* + * Disassociate handler with the specified interrupt. + */ +void +xtalk_intr_disconnect(xtalk_intr_t intr_hdl) +{ + INTR_FUNC(intr_hdl, intr_disconnect) + (CAST_INTR(intr_hdl)); +} + + +/* + * Return a hwgraph vertex that represents the CPU currently + * targeted by an interrupt. + */ +devfs_handle_t +xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) +{ + return INTR_FUNC(intr_hdl, intr_cpu_get) + (CAST_INTR(intr_hdl)); +} + + +/* + * ===================================================================== + * ERROR MANAGEMENT + */ + +/* + * xtalk_error_handler: + * pass this error on to the handler registered + * at the specified xtalk connecdtion point, + * or complain about it here if there is no handler. + * + * This routine plays two roles during error delivery + * to most widgets: first, the external agent (heart, + * hub, or whatever) calls in with the error and the + * connect point representing the crosstalk switch, + * or whatever crosstalk device is directly connected + * to the agent. + * + * If there is a switch, it will generally look at the + * widget number stashed in the ioerror structure; and, + * if the error came from some widget other than the + * switch, it will call back into xtalk_error_handler + * with the connection point of the offending port. + */ +int +xtalk_error_handler( + devfs_handle_t xconn, + int error_code, + ioerror_mode_t mode, + ioerror_t *ioerror) +{ + xwidget_info_t xwidget_info; + + xwidget_info = xwidget_info_get(xconn); + /* Make sure that xwidget_info is a valid pointer before derefencing it. + * We could come in here during very early initialization. + */ + if (xwidget_info && xwidget_info->w_efunc) + return xwidget_info->w_efunc + (xwidget_info->w_einfo, + error_code, mode, ioerror); + /* + * no error handler registered for + * the offending port. it's not clear + * what needs to be done, but reporting + * it would be a good thing, unless it + * is a mode that requires nothing. + */ + if ((mode == MODE_DEVPROBE) || (mode == MODE_DEVUSERERROR) || + (mode == MODE_DEVREENABLE)) + return IOERROR_HANDLED; + +#if defined(SUPPORT_PRINTING_V_FORMAT) + printk(KERN_WARNING "Xbow at %v encountered Fatal error", xconn); +#else + printk(KERN_WARNING "Xbow at 0x%p encountered Fatal error", xconn); +#endif + ioerror_dump("xtalk", error_code, mode, ioerror); + + return IOERROR_UNHANDLED; +} + +int +xtalk_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) +{ + return DEV_FUNC(xconn_vhdl, error_devenable) (xconn_vhdl, devnum, error_code); +} + + +/* ===================================================================== + * CONFIGURATION MANAGEMENT + */ + +/* + * Startup a crosstalk provider + */ +void +xtalk_provider_startup(devfs_handle_t xtalk_provider) +{ + DEV_FUNC(xtalk_provider, provider_startup) + (xtalk_provider); +} + + +/* + * Shutdown a crosstalk provider + */ +void +xtalk_provider_shutdown(devfs_handle_t xtalk_provider) +{ + DEV_FUNC(xtalk_provider, provider_shutdown) + (xtalk_provider); +} + +/* + * Enable a device on a xtalk widget + */ +void +xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) +{ + DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum); +} + +/* + * Shutdown a device on a xtalk widget + */ +void +xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) +{ + DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum); +} + +int +xtalk_dma_enabled(devfs_handle_t xconn_vhdl) +{ + return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl); +} +/* + * Generic crosstalk functions, for use with all crosstalk providers + * and all crosstalk devices. + */ + +/****** Generic crosstalk interrupt interfaces ******/ +devfs_handle_t +xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_dev); +} + +xwidgetnum_t +xtalk_intr_target_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_target); +} + +xtalk_intr_vector_t +xtalk_intr_vector_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_vector); +} + +iopaddr_t +xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr) +{ + return (xtalk_intr->xi_addr); +} + +void * +xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr) +{ + return (xtalk_intr->xi_sfarg); +} + +/****** Generic crosstalk pio interfaces ******/ +devfs_handle_t +xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_dev); +} + +xwidgetnum_t +xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_target); +} + +iopaddr_t +xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_xtalk_addr); +} + +ulong +xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_mapsz); +} + +caddr_t +xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap) +{ + return (xtalk_piomap->xp_kvaddr); +} + + +/****** Generic crosstalk dma interfaces ******/ +devfs_handle_t +xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) +{ + return (xtalk_dmamap->xd_dev); +} + +xwidgetnum_t +xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap) +{ + return (xtalk_dmamap->xd_target); +} + + +/****** Generic crosstalk widget information interfaces ******/ + +/* xwidget_info_chk: + * check to see if this vertex is a widget; + * if so, return its widget_info (if any). + * if not, return NULL. + */ +xwidget_info_t +xwidget_info_chk(devfs_handle_t xwidget) +{ + arbitrary_info_t ainfo = 0; + + hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo); + return (xwidget_info_t) ainfo; +} + + +xwidget_info_t +xwidget_info_get(devfs_handle_t xwidget) +{ + xwidget_info_t widget_info; + + widget_info = (xwidget_info_t) + hwgraph_fastinfo_get(xwidget); + +#ifdef LATER + if ((widget_info != NULL) && + (widget_info->w_fingerprint != widget_info_fingerprint)) +#ifdef SUPPORT_PRINTING_V_FORMAT + PRINT_PANIC("%v bad xwidget_info", xwidget); +#else + PRINT_PANIC("%x bad xwidget_info", xwidget); +#endif +#endif /* LATER */ + + return (widget_info); +} + +void +xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) +{ + if (widget_info != NULL) + widget_info->w_fingerprint = widget_info_fingerprint; + + hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info); + + /* Also, mark this vertex as an xwidget, + * and use the widget_info, so xwidget_info_chk + * can work (and be fairly efficient). + */ + hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET, + (arbitrary_info_t) widget_info); +} + +devfs_handle_t +xwidget_info_dev_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_vertex); +} + +xwidgetnum_t +xwidget_info_id_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_id); +} + + +devfs_handle_t +xwidget_info_master_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_master); +} + +xwidgetnum_t +xwidget_info_masterid_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_masterid); +} + +xwidget_part_num_t +xwidget_info_part_num_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_hwid.part_num); +} + +xwidget_mfg_num_t +xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget_info"); + return (xwidget_info->w_hwid.mfg_num); +} +/* Extract the widget name from the widget information + * for the xtalk widget. + */ +char * +xwidget_info_name_get(xwidget_info_t xwidget_info) +{ + if (xwidget_info == NULL) + panic("null xwidget info"); + return(xwidget_info->w_name); +} +/****** Generic crosstalk initialization interfaces ******/ + +/* + * One-time initialization needed for systems that support crosstalk. + */ +void +xtalk_init(void) +{ + cdl_p cp; + +#if DEBUG && ATTACH_DEBUG + printf("xtalk_init\n"); +#endif + /* Allocate the registry. + * We might already have one. + * If we don't, go get one. + * MPness: someone might have + * set one up for us while we + * were not looking; use an atomic + * compare-and-swap to commit to + * using the new registry if and + * only if nobody else did first. + * If someone did get there first, + * toss the one we allocated back + * into the pool. + */ + if (xtalk_registry == NULL) { + cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr"); + if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) { + cdl_del(cp); + } + } + ASSERT(xtalk_registry != NULL); +} + +/* + * Associate a set of xtalk_provider functions with a vertex. + */ +void +xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) +{ + hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); +} + +/* + * Disassociate a set of xtalk_provider functions with a vertex. + */ +void +xtalk_provider_unregister(devfs_handle_t provider) +{ + hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); +} + +/* + * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk + * provider. + */ +xtalk_provider_t * +xtalk_provider_fns_get(devfs_handle_t provider) +{ + return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); +} + +/* + * Announce a driver for a particular crosstalk part. + * Returns 0 on success or -1 on failure. Failure occurs if the + * specified hardware already has a driver. + */ +/*ARGSUSED4 */ +int +xwidget_driver_register(xwidget_part_num_t part_num, + xwidget_mfg_num_t mfg_num, + char *driver_prefix, + unsigned flags) +{ + /* a driver's init routine could call + * xwidget_driver_register before the + * system calls xtalk_init; so, we + * make the call here. + */ + if (xtalk_registry == NULL) + xtalk_init(); + + return cdl_add_driver(xtalk_registry, + part_num, mfg_num, + driver_prefix, flags, NULL); +} + +/* + * Inform xtalk infrastructure that a driver is no longer available for + * handling any widgets. + */ +void +xwidget_driver_unregister(char *driver_prefix) +{ + /* before a driver calls unregister, + * it must have called registger; so we + * can assume we have a registry here. + */ + ASSERT(xtalk_registry != NULL); + + cdl_del_driver(xtalk_registry, driver_prefix, NULL); +} + +/* + * Call some function with each vertex that + * might be one of this driver's attach points. + */ +void +xtalk_iterate(char *driver_prefix, + xtalk_iter_f *func) +{ + ASSERT(xtalk_registry != NULL); + + cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func); +} + +/* + * xwidget_register: + * Register a xtalk device (xwidget) by doing the following. + * -allocate and initialize xwidget_info data + * -allocate a hwgraph vertex with name based on widget number (id) + * -look up the widget's initialization function and call it, + * or remember the vertex for later initialization. + * + */ +int +xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ + devfs_handle_t widget, /* widget to initialize */ + xwidgetnum_t id, /* widget's target id (0..f) */ + devfs_handle_t master, /* widget's master vertex */ + xwidgetnum_t targetid, /* master's target id (9/a) */ + async_attach_t aa) +{ + xwidget_info_t widget_info; + char *s,devnm[MAXDEVNAME]; + + /* Allocate widget_info and associate it with widget vertex */ + NEW(widget_info); + + /* Initialize widget_info */ + widget_info->w_vertex = widget; + widget_info->w_id = id; + widget_info->w_master = master; + widget_info->w_masterid = targetid; + widget_info->w_hwid = *hwid; /* structure copy */ + widget_info->w_efunc = 0; + widget_info->w_einfo = 0; + /* + * get the name of this xwidget vertex and keep the info. + * This is needed during errors and interupts, but as + * long as we have it, we can use it elsewhere. + */ + s = dev_to_name(widget,devnm,MAXDEVNAME); + widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); + strcpy(widget_info->w_name,s); + + xwidget_info_set(widget, widget_info); + + device_master_set(widget, master); + + /* All the driver init routines (including + * xtalk_init) are called before we get into + * attaching devices, so we can assume we + * have a registry here. + */ + ASSERT(xtalk_registry != NULL); + + /* + * Add pointer to async attach info -- tear down will be done when + * the particular descendant is done with the info. + */ + if (aa) + async_attach_add_info(widget, aa); + + return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); +} + +/* + * xwidget_unregister : + * Unregister the xtalk device and detach all its hwgraph namespace. + */ +int +xwidget_unregister(devfs_handle_t widget) +{ + xwidget_info_t widget_info; + xwidget_hwid_t hwid; + + /* Make sure that we have valid widget information initialized */ + if (!(widget_info = xwidget_info_get(widget))) + return(1); + + /* Remove the inventory information associated + * with the widget. + */ + hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1); + + hwid = &(widget_info->w_hwid); + + cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + widget, 0); + + /* Clean out the xwidget information */ + (void)kfree(widget_info->w_name); + BZERO((void *)widget_info, sizeof(widget_info)); + DEL(widget_info); + + return(0); +} + +void +xwidget_error_register(devfs_handle_t xwidget, + error_handler_f *efunc, + error_handler_arg_t einfo) +{ + xwidget_info_t xwidget_info; + + xwidget_info = xwidget_info_get(xwidget); + ASSERT(xwidget_info != NULL); + xwidget_info->w_efunc = efunc; + xwidget_info->w_einfo = einfo; +} + +/* + * Issue a link reset to a widget. + */ +void +xwidget_reset(devfs_handle_t xwidget) +{ + xswitch_reset_link(xwidget); + +} + + +void +xwidget_gfx_reset(devfs_handle_t xwidget) +{ + xwidget_info_t info; + + xswitch_reset_link(xwidget); + info = xwidget_info_get(xwidget); +#ifdef LATER + ASSERT_ALWAYS(info != NULL); +#endif + + /* + * Enable this for other architectures once we add widget_reset to the + * xtalk provider interface. + */ + DEV_FUNC(xtalk_provider, widget_reset) + (xwidget_info_master_get(info), xwidget_info_id_get(info)); +} + +#define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ + +/* Get the canonical hwgraph name of xtalk widget */ +char * +xwidget_name_get(devfs_handle_t xwidget_vhdl) +{ + xwidget_info_t info; + + /* If we have a bogus widget handle then return + * a default anonymous widget name. + */ + if (xwidget_vhdl == GRAPH_VERTEX_NONE) + return(ANON_XWIDGET_NAME); + /* Read the widget name stored in the widget info + * for the widget setup during widget initialization. + */ + info = xwidget_info_get(xwidget_vhdl); + ASSERT(info != NULL); + return(xwidget_info_name_get(info)); +} diff -Nur linux-2.4.19/arch/ia64/sn/io/stubs.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/stubs.c --- linux-2.4.19/arch/ia64/sn/io/stubs.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/stubs.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -28,8 +28,8 @@ int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev; int default_intr_pri; -int force_fire_and_forget; -int ignore_conveyor_override; +int force_fire_and_forget = 1; +int ignore_conveyor_override = 0; devfs_handle_t dummy_vrtx; /* Needed for cpuid_to_vertex() in hack.h */ @@ -53,36 +53,6 @@ return(0); } -char * -nic_bridge_vertex_info(devfs_handle_t v, nic_data_t mcr) -{ - FIXME("nic_bridge_vertex_info : returns NULL"); - return((char *)0); -} - -void * -snia_kmem_alloc_node(register size_t size, register int flags, cnodeid_t node) -{ - /* Allocates on node 'node' */ - FIXME("snia_kmem_alloc_node : use kmalloc"); - return(kmalloc(size, GFP_KERNEL)); -} - -void * -snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node) -{ - FIXME("snia_kmem_zalloc_node : use kmalloc"); - return(kmalloc(size, GFP_KERNEL)); -} - -void -snia_kmem_free(void *where, int size) -{ - FIXME("snia_kmem_free : use kfree"); - return(kfree(where)); -} - - void * snia_kmem_zone_alloc(register zone_t *zone, int flags) { @@ -115,13 +85,6 @@ return(0); } -void * -swap_ptr(void **loc, void *new) -{ - FIXME("swap_ptr : returns null"); - return((void *)0); -} - /* For ml/SN/SN1/slots.c */ /* ARGSUSED */ slotid_t get_widget_slotnum(int xbow, int widget) @@ -153,10 +116,8 @@ char * nic_vertex_info_get(devfs_handle_t v) { - FIXME("nic_vertex_info_get\n"); return(NULL); - } int diff -Nur linux-2.4.19/arch/ia64/sn/io/xbow.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/xbow.c --- linux-2.4.19/arch/ia64/sn/io/xbow.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/xbow.c Wed Dec 31 16:00:00 1969 @@ -1,1325 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define DEBUG 1 */ -/* #define XBOW_DEBUG 1 */ - - -/* - * Files needed to get the device driver entry points - */ - -#include -#include -#include -#include - -#include -#include - - -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) - -int xbow_devflag = D_MP; - -/* - * This file supports the Xbow chip. Main functions: initializtion, - * error handling, and GBR. - */ - -/* - * each vertex corresponding to an xbow chip - * has a "fastinfo" pointer pointing at one - * of these things. - */ -typedef struct xbow_soft_s *xbow_soft_t; - -struct xbow_soft_s { - devfs_handle_t conn; /* our connection point */ - devfs_handle_t vhdl; /* xbow's private vertex */ - devfs_handle_t busv; /* the xswitch vertex */ - xbow_t *base; /* PIO pointer to crossbow chip */ - char *name; /* hwgraph name */ - - xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; - xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; - xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; - spinlock_t xbow_perf_lock; - int link_monitor; - widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ - - /* Bandwidth allocation state. Bandwidth values are for the - * destination port since contention happens there. - * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. - */ - spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ - unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ - unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ -}; - -#define xbow_soft_set(v,i) hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)) -#define xbow_soft_get(v) ((xbow_soft_t)hwgraph_fastinfo_get((v))) - -/* - * Function Table of Contents - */ - -void xbow_mlreset(xbow_t *); -void xbow_init(void); -int xbow_attach(devfs_handle_t); - -int xbow_open(devfs_handle_t *, int, int, cred_t *); -int xbow_close(devfs_handle_t, int, int, cred_t *); - -int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int xbow_unmap(devfs_handle_t, vhandl_t *); -int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); - -int xbow_widget_present(xbow_t *, int); -static int xbow_link_alive(xbow_t *, int); -devfs_handle_t xbow_widget_lookup(devfs_handle_t, int); - -#ifdef LATER -static void xbow_setwidint(xtalk_intr_t); -static void xbow_errintr_handler(intr_arg_t); -#endif -void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); - - - -void xbow_update_perf_counters(devfs_handle_t); -xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); -int xbow_enable_perf_counter(devfs_handle_t, int, int, int); -xbow_link_status_t *xbow_get_llp_status(devfs_handle_t); -void xbow_update_llp_status(devfs_handle_t); - -int xbow_disable_llp_monitor(devfs_handle_t); -int xbow_enable_llp_monitor(devfs_handle_t); -int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, - unsigned long long, unsigned long long); - -xswitch_reset_link_f xbow_reset_link; - -void idbg_xbowregs(int64_t); - -xswitch_provider_t xbow_provider = -{ - xbow_reset_link, -}; - -/* - * xbow_mlreset: called at mlreset time if the - * platform specific code determines that there is - * a crossbow in a critical path that must be - * functional before the driver would normally get - * the device properly set up. - * - * what do we need to do, that the boot prom can - * not be counted on to have already done, that is - * generic across all platforms using crossbows? - */ -/*ARGSUSED */ -void -xbow_mlreset(xbow_t * xbow) -{ -} - -/* - * xbow_init: called with the rest of the device - * driver XXX_init routines. This platform *might* - * have a Crossbow chip, or even several, but it - * might have none. Register with the crosstalk - * generic provider so when we encounter the chip - * the right magic happens. - */ -void -xbow_init(void) -{ - -#if DEBUG && ATTACH_DEBUG - printf("xbow_init\n"); -#endif - - xwidget_driver_register(XXBOW_WIDGET_PART_NUM, - 0, /* XXBOW_WIDGET_MFGR_NUM, */ - "xbow_", - CDL_PRI_HI); /* attach before friends */ - - xwidget_driver_register(XBOW_WIDGET_PART_NUM, - XBOW_WIDGET_MFGR_NUM, - "xbow_", - CDL_PRI_HI); /* attach before friends */ -} - -#ifdef XBRIDGE_REGS_SIM -/* xbow_set_simulated_regs: sets xbow regs as needed - * for powering through the boot - */ -void -xbow_set_simulated_regs(xbow_t *xbow, int port) -{ - /* - * turn on link - */ - xbow->xb_link(port).link_status = (1<<31); - /* - * and give it a live widget too - */ - xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT; - /* - * zero the link control reg - */ - xbow->xb_link(port).link_control = 0x0; -} -#endif /* XBRIDGE_REGS_SIM */ - -/* - * xbow_attach: the crosstalk provider has - * determined that there is a crossbow widget - * present, and has handed us the connection - * point for that vertex. - * - * We not only add our own vertex, but add - * some "xtalk switch" data to the switch - * vertex (at the connect point's parent) if - * it does not have any. - */ - -/*ARGSUSED */ -int -xbow_attach(devfs_handle_t conn) -{ - /*REFERENCED */ - devfs_handle_t vhdl; - devfs_handle_t busv; - xbow_t *xbow; - xbow_soft_t soft; - int port; - xswitch_info_t info; -#ifdef LATER - xtalk_intr_t intr_hdl; - device_desc_t dev_desc; -#endif - char devnm[MAXDEVNAME], *s; - xbowreg_t id; - int rev; - int i; - int xbow_num; - -#if DEBUG && ATTACH_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT - printk("%v: xbow_attach\n", conn); -#else - printk("0x%x: xbow_attach\n", conn); -#endif -#endif - - /* - * Get a PIO pointer to the base of the crossbow - * chip. - */ -#ifdef XBRIDGE_REGS_SIM - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t)); - xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL); - /* - * turn on ports e and f like in a real live ibrick - */ - xbow_set_simulated_regs(xbow, 0xe); - xbow_set_simulated_regs(xbow, 0xf); -#else - xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0); -#endif /* XBRIDGE_REGS_SIM */ - - /* - * Locate the "switch" vertex: it is the parent - * of our connection point. - */ - busv = hwgraph_connectpt_get(conn); -#if DEBUG && ATTACH_DEBUG - printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); -#endif - - ASSERT(busv != GRAPH_VERTEX_NONE); - - /* - * Create our private vertex, and connect our - * driver information to it. This makes it possible - * for diagnostic drivers to open the crossbow - * vertex for access to registers. - */ - - /* - * We need to teach xbow drivers to provide the right set of - * file ops. - */ - vhdl = NULL; - vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - /* &hcl_fops */ (void *)&vhdl, NULL); - if (!vhdl) { - printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", - (void *)conn); - } - - /* - * Allocate the soft state structure and attach - * it to the xbow's vertex - */ - NEW(soft); - soft->conn = conn; - soft->vhdl = vhdl; - soft->busv = busv; - soft->base = xbow; - /* does the universe really need another macro? */ - /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */ - hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft); - -#define XBOW_NUM_SUFFIX_FORMAT "[xbow# %d]" - - /* Add xbow number as a suffix to the hwgraph name of the xbow. - * This is helpful while looking at the error/warning messages. - */ - xbow_num = 0; - - /* - * get the name of this xbow vertex and keep the info. - * This is needed during errors and interupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(vhdl, devnm, MAXDEVNAME); - soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, - GFP_KERNEL); - sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num); - -#ifdef XBRIDGE_REGS_SIM - /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined - * as 0xd000, so I'm using that for the partnum bitfield. - */ - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n"); - id = 0x2d000049; -#else - id = xbow->xb_wid_id; -#endif /* XBRIDGE_REGS_SIM */ - rev = XWIDGET_PART_REV_NUM(id); - - /* - * Print the revision if DEBUG, or SHOW_REVS and kdebug, - * or the xbow is downrev. - * - * If xbow is downrev, make it a WARNING that the - * Crossbow is DOWNREV: these chips are not good - * to have around, and the operator should be told. - */ -#ifdef LATER -#if !DEBUG - if ( -#if SHOW_REVS - (kdebug) || -#endif /* SHOW_REVS */ - (rev < XBOW_REV_1_1)) -#endif /* !DEBUG */ - printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s", - (rev < XBOW_REV_1_1) ? "DOWNREV " : "", - (rev == XBOW_REV_1_0) ? "1.0" : - (rev == XBOW_REV_1_1) ? "1.1" : - (rev == XBOW_REV_1_2) ? "1.2" : - (rev == XBOW_REV_1_3) ? "1.3" : - (rev == XBOW_REV_2_0) ? "2.0" : - (rev == XXBOW_PART_REV_1_0) ? "Xbridge 1.0" : - (rev == XXBOW_PART_REV_2_0) ? "Xbridge 2.0" : - "unknown", - rev, soft->name, - (rev < XBOW_REV_1_1) ? "" : "\n"); -#endif /* LATER */ - mutex_spinlock_init(&soft->xbow_perf_lock); - soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; - soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; - - /* Initialization for GBR bw allocation */ - mutex_spinlock_init(&soft->xbow_bw_alloc_lock); - -#define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */ -#define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ - - /* Set bandwidth hiwatermark and current values */ - for (i = 0; i < MAX_XBOW_PORTS; i++) { - soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX; /* for now */ - soft->bw_cur_used[i] = 0; - } - - /* - * Enable xbow error interrupts - */ - xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); - - /* - * take a census of the widgets present, - * leaving notes at the switch vertex. - */ - info = xswitch_info_new(busv); - - for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; - port < MAX_PORT_NUM; ++port) { - if (!xbow_link_alive(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is not alive\n", - busv, port); -#endif - continue; - } - if (!xbow_widget_present(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", busv, port); -#endif - continue; - } -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d has a widget\n", - busv, port); -#endif - - xswitch_info_link_is_ok(info, port); - /* - * Turn some error interrupts on - * and turn others off. The PROM has - * some things turned on we don't - * want to see (bandwidth allocation - * errors for instance); so if it - * is not listed here, it is not on. - */ - xbow->xb_link(port).link_control = - ( (xbow->xb_link(port).link_control - /* - * Turn off these bits; they are non-fatal, - * but we might want to save some statistics - * on the frequency of these errors. - * XXX FIXME XXX - */ - & ~XB_CTRL_RCV_CNT_OFLOW_IE - & ~XB_CTRL_XMT_CNT_OFLOW_IE - & ~XB_CTRL_BNDWDTH_ALLOC_IE - & ~XB_CTRL_RCV_IE) - /* - * These are the ones we want to turn on. - */ - | (XB_CTRL_ILLEGAL_DST_IE - | XB_CTRL_OALLOC_IBUF_IE - | XB_CTRL_XMT_MAX_RTRY_IE - | XB_CTRL_MAXREQ_TOUT_IE - | XB_CTRL_XMT_RTRY_IE - | XB_CTRL_SRC_TOUT_IE) ); - } - - xswitch_provider_register(busv, &xbow_provider); - - return 0; /* attach successful */ -} - -/*ARGSUSED */ -int -xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; - -} - -/*ARGSUSED */ -int -xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - xbow_soft_t soft = xbow_soft_get(vhdl); - int error; - - ASSERT(soft); - len = ctob(btoc(len)); - /* XXX- this ignores the offset!!! */ - error = v_mapphys(vt, (void *) soft->base, len); - return error; -} - -/*ARGSUSED */ -int -xbow_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - -/* This contains special-case code for grio. There are plans to make - * this general sometime in the future, but till then this should - * be good enough. - */ -xwidgetnum_t -xbow_widget_num_get(devfs_handle_t dev) -{ - devfs_handle_t tdev; - char devname[MAXDEVNAME]; - xwidget_info_t xwidget_info; - int i; - - vertex_to_name(dev, devname, MAXDEVNAME); - - /* If this is a pci controller vertex, traverse up using - * the ".." links to get to the widget. - */ - if (strstr(devname, EDGE_LBL_PCI) && - strstr(devname, EDGE_LBL_CONTROLLER)) { - tdev = dev; - for (i=0; i< 2; i++) { - if (hwgraph_edge_get(tdev, - HWGRAPH_EDGELBL_DOTDOT, &tdev) != - GRAPH_SUCCESS) - return XWIDGET_NONE; - } - - if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) { - return (xwidget_info_id_get(xwidget_info)); - } else { - return XWIDGET_NONE; - } - } - - return XWIDGET_NONE; -} - -int -xbow_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t vhdl; - int error = 0; - -#if defined (DEBUG) - int rc; - devfs_handle_t conn; - struct xwidget_info_s *xwidget_info; - xbow_soft_t xbow_soft; -#endif - *rvalp = 0; - - vhdl = dev_to_vhdl(dev); -#if defined (DEBUG) - xbow_soft = xbow_soft_get(vhdl); - conn = xbow_soft->conn; - - xwidget_info = xwidget_info_get(conn); - ASSERT_ALWAYS(xwidget_info != NULL); - - rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid); - ASSERT_ALWAYS(rc != 0); -#endif - switch (cmd) { -#ifdef LATER - case XBOWIOC_PERF_ENABLE: - case XBOWIOC_PERF_DISABLE: - { - struct xbow_perfarg_t xbow_perf_en; - - if (!_CAP_CRABLE(cr, CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if ((flag & FWRITE) == 0) { - error = EBADF; - break; - } - if (COPYIN(arg, &xbow_perf_en, sizeof(xbow_perf_en))) { - error = EFAULT; - break; - } - if (error = xbow_enable_perf_counter(vhdl, - xbow_perf_en.link, - (cmd == XBOWIOC_PERF_DISABLE) ? 0 : xbow_perf_en.mode, - xbow_perf_en.counter)) { - error = EINVAL; - break; - } - break; - } -#endif - -#ifdef LATER - case XBOWIOC_PERF_GET: - { - xbow_perf_link_t *xbow_perf_cnt; - - if ((flag & FREAD) == 0) { - error = EBADF; - break; - } - xbow_perf_cnt = xbow_get_perf_counters(vhdl); - ASSERT_ALWAYS(xbow_perf_cnt != NULL); - - if (COPYOUT((void *) xbow_perf_cnt, (void *) arg, - MAX_XBOW_PORTS * sizeof(xbow_perf_link_t))) { - error = EFAULT; - break; - } - break; - } -#endif - - case XBOWIOC_LLP_ERROR_ENABLE: - if ((error = xbow_enable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - - case XBOWIOC_LLP_ERROR_DISABLE: - - if ((error = xbow_disable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - -#ifdef LATER - case XBOWIOC_LLP_ERROR_GET: - { - xbow_link_status_t *xbow_llp_status; - - if ((flag & FREAD) == 0) { - error = EBADF; - break; - } - xbow_llp_status = xbow_get_llp_status(vhdl); - ASSERT_ALWAYS(xbow_llp_status != NULL); - - if (COPYOUT((void *) xbow_llp_status, (void *) arg, - MAX_XBOW_PORTS * sizeof(xbow_link_status_t))) { - error = EFAULT; - break; - } - break; - } -#endif - -#ifdef LATER - case GIOCSETBW: - { - grio_ioctl_info_t info; - xwidgetnum_t src_widgetnum, dest_widgetnum; - - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.next_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - src_widgetnum = xbow_widget_num_get(info.prev_vhdl); - dest_widgetnum = xbow_widget_num_get(info.next_vhdl); - - /* Bandwidth allocation is bi-directional. Since bandwidth - * reservations have already been done at an earlier stage, - * we cannot fail here for lack of bandwidth. - */ - xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum, - 0, info.reqbw); - xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum, - 0, info.reqbw); - - break; - } - - case GIOCRELEASEBW: - { - grio_ioctl_info_t info; - xwidgetnum_t src_widgetnum, dest_widgetnum; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.next_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - src_widgetnum = xbow_widget_num_get(info.prev_vhdl); - dest_widgetnum = xbow_widget_num_get(info.next_vhdl); - - /* Bandwidth reservation is bi-directional. Hence, remove - * bandwidth reservations for both directions. - */ - xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum, - info.reqbw, (-1 * info.reqbw)); - xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum, - info.reqbw, (-1 * info.reqbw)); - - break; - } -#endif - - default: - break; - - } - return error; -} - -/* - * xbow_widget_present: See if a device is present - * on the specified port of this crossbow. - */ -int -xbow_widget_present(xbow_t * xbow, int port) -{ - if ( IS_RUNNING_ON_SIMULATOR() ) { - if ( (port == 14) || (port == 15) ) { - return 1; - } - else { - return 0; - } - } - else { - return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT; - } -} - -static int -xbow_link_alive(xbow_t * xbow, int port) -{ - xbwX_stat_t xbow_linkstat; - - xbow_linkstat.linkstatus = xbow->xb_link(port).link_status; - return (xbow_linkstat.link_alive); -} - -/* - * xbow_widget_lookup - * Lookup the edges connected to the xbow specified, and - * retrieve the handle corresponding to the widgetnum - * specified. - * If not found, return 0. - */ -devfs_handle_t -xbow_widget_lookup(devfs_handle_t vhdl, - int widgetnum) -{ - xswitch_info_t xswitch_info; - devfs_handle_t conn; - - xswitch_info = xswitch_info_get(vhdl); - conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); - return conn; -} - -/* - * xbow_setwidint: called when xtalk - * is establishing or migrating our - * interrupt service. - */ -#ifdef LATER -static void -xbow_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - xbow_t *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr); - - xbow_intr_preset((void *) xbow, 0, targ, addr, vect); -} -#endif /* LATER */ - -/* - * xbow_intr_preset: called during mlreset time - * if the platform specific code needs to route - * an xbow interrupt before the xtalk infrastructure - * is available for use. - * - * Also called from xbow_setwidint, so we don't - * replicate the guts of the routine. - * - * XXX- probably should be renamed xbow_wid_intr_set or - * something to reduce confusion. - */ -/*ARGSUSED3 */ -void -xbow_intr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - xbow_t *xbow = (xbow_t *) which_widget; - - xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) | - (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); -} - -#define XEM_ADD_STR(s) printk("%s", (s)) -#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%x\n", (n), (v)) -#define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v)) -#define XEM_ADD_IOEF(n) if (IOERROR_FIELDVALID(ioe,n)) \ - XEM_ADD_NVAR("ioe." #n, \ - IOERROR_GETVALUE(ioe,n)) - -#ifdef LATER -static void -xem_add_ioe(ioerror_t *ioe) -{ - XEM_ADD_IOEF(errortype); - XEM_ADD_IOEF(widgetnum); - XEM_ADD_IOEF(widgetdev); - XEM_ADD_IOEF(srccpu); - XEM_ADD_IOEF(srcnode); - XEM_ADD_IOEF(errnode); - XEM_ADD_IOEF(sysioaddr); - XEM_ADD_IOEF(xtalkaddr); - XEM_ADD_IOEF(busspace); - XEM_ADD_IOEF(busaddr); - XEM_ADD_IOEF(vaddr); - XEM_ADD_IOEF(memaddr); - XEM_ADD_IOEF(epc); - XEM_ADD_IOEF(ef); -} - -#define XEM_ADD_IOE() (xem_add_ioe(ioe)) -#endif /* LATER */ - -int xbow_xmit_retry_errors = 0; - -int -xbow_xmit_retry_error(xbow_soft_t soft, - int port) -{ - xswitch_info_t info; - devfs_handle_t vhdl; - widget_cfg_t *wid; - widgetreg_t id; - int part; - int mfgr; - - wid = soft->wpio[port - BASE_XBOW_PORT]; - if (wid == NULL) { - /* If we can't track down a PIO - * pointer to our widget yet, - * leave our caller knowing that - * we are interested in this - * interrupt if it occurs in - * the future. - */ - info = xswitch_info_get(soft->busv); - if (!info) - return 1; - vhdl = xswitch_info_vhdl_get(info, port); - if (vhdl == GRAPH_VERTEX_NONE) - return 1; - wid = (widget_cfg_t *) xtalk_piotrans_addr - (vhdl, 0, 0, sizeof *wid, 0); - if (!wid) - return 1; - soft->wpio[port - BASE_XBOW_PORT] = wid; - } - id = wid->w_id; - part = XWIDGET_PART_NUM(id); - mfgr = XWIDGET_MFG_NUM(id); - - /* If this thing is not a Bridge, - * do not activate the WAR, and - * tell our caller we do not need - * to be called again. - */ - if ((part != BRIDGE_WIDGET_PART_NUM) || - (mfgr != BRIDGE_WIDGET_MFGR_NUM)) { - /* FIXME: add Xbridge to the WAR. - * Shouldn't hurt anything. Later need to - * check if we can remove this. - */ - if ((part != XBRIDGE_WIDGET_PART_NUM) || - (mfgr != XBRIDGE_WIDGET_MFGR_NUM)) - return 0; - } - - /* count how many times we - * have picked up after - * LLP Transmit problems. - */ - xbow_xmit_retry_errors++; - - /* rewrite the control register - * to fix things up. - */ - wid->w_control = wid->w_control; - wid->w_control; - - return 1; -} - -void -xbow_update_perf_counters(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; - xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; - xbow_perfcount_t perf_reg; - unsigned long s; - int link, i; - - for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { - if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) - continue; - - s = mutex_spinlock(&xbow_soft->xbow_perf_lock); - - perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; - - link = perf_reg.xb_perf.link_select; - - (xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] += - ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK); - xbow_perf->xp_current = perf_reg.xb_perf.count; - - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - } - /* Do port /mode multiplexing here */ - -#ifdef LATER - (void) timeout(xbow_update_perf_counters, - (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); -#endif - -} - -xbow_perf_link_t * -xbow_get_perf_counters(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; - - return xbow_perf_link; -} - -int -xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; - xbow_linkctrl_t xbow_link_ctrl; - xbow_t *xbow = xbow_soft->base; - xbow_perfcount_t perf_reg; - unsigned long s; - int i; - - link -= BASE_XBOW_PORT; - if ((link < 0) || (link >= MAX_XBOW_PORTS)) - return -1; - - if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK)) - return -1; - - if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS)) - return -1; - - s = mutex_spinlock(&xbow_soft->xbow_perf_lock); - - if ((xbow_perf + counter)->xp_mode && mode) { - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - return -1; - } - for (i = 0; i < XBOW_PERF_COUNTERS; i++) { - if (i == counter) - continue; - if (((xbow_perf + i)->xp_link == link) && - ((xbow_perf + i)->xp_mode)) { - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - return -1; - } - } - xbow_perf += counter; - - xbow_perf->xp_curlink = xbow_perf->xp_link = link; - xbow_perf->xp_curmode = xbow_perf->xp_mode = mode; - - xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control; - xbow_link_ctrl.xb_linkcontrol.perf_mode = mode; - xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword; - - perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; - perf_reg.xb_perf.link_select = link; - *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; - xbow_perf->xp_current = perf_reg.xb_perf.count; - -#ifdef LATER - (void) timeout(xbow_update_perf_counters, - (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); -#endif - - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - - return 0; -} - -xbow_link_status_t * -xbow_get_llp_status(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; - - return xbow_llp_status; -} - -void -xbow_update_llp_status(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; - xbow_t *xbow; - xbwX_stat_t lnk_sts; - xbow_aux_link_status_t aux_sts; - int link; - devfs_handle_t xwidget_vhdl; - char *xwidget_name; - - xbow = (xbow_t *) xbow_soft->base; - for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) { - /* Get the widget name corresponding the current link. - * Note : 0 <= link < MAX_XBOW_PORTS(8). - * BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10) - */ - xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT); - xwidget_name = xwidget_name_get(xwidget_vhdl); - aux_sts.aux_linkstatus - = xbow->xb_link_raw[link].link_aux_status; - lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr; - - if (lnk_sts.link_alive == 0) - continue; - - xbow_llp_status->rx_err_count += - aux_sts.xb_aux_linkstatus.rx_err_cnt; - - xbow_llp_status->tx_retry_count += - aux_sts.xb_aux_linkstatus.tx_retry_cnt; - - if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { -#ifdef LATER - printk(KERN_WARNING "link %d[%s]: bad status 0x%x\n", - link, xwidget_name, lnk_sts.linkstatus); -#endif - } - } -#ifdef LATER - if (xbow_soft->link_monitor) - (void) timeout(xbow_update_llp_status, - (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); -#endif -} - -int -xbow_disable_llp_monitor(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - int port; - - for (port = 0; port < MAX_XBOW_PORTS; port++) { - xbow_soft->xbow_link_status[port].rx_err_count = 0; - xbow_soft->xbow_link_status[port].tx_retry_count = 0; - } - - xbow_soft->link_monitor = 0; - return 0; -} - -int -xbow_enable_llp_monitor(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - -#ifdef LATER - (void) timeout(xbow_update_llp_status, - (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); -#endif - xbow_soft->link_monitor = 1; - return 0; -} - - -int -xbow_reset_link(devfs_handle_t xconn_vhdl) -{ - xwidget_info_t widget_info; - xwidgetnum_t port; - xbow_t *xbow; - xbowreg_t ctrl; - xbwX_stat_t stat; - unsigned itick; - unsigned dtick; - static int ticks_per_ms = 0; - - if (!ticks_per_ms) { - itick = get_timestamp(); - us_delay(1000); - ticks_per_ms = get_timestamp() - itick; - } - widget_info = xwidget_info_get(xconn_vhdl); - port = xwidget_info_id_get(widget_info); - -#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ - xbow = XBOW_K1PTR; -#else - { - devfs_handle_t xbow_vhdl; - xbow_soft_t xbow_soft; - - hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); - xbow_soft = xbow_soft_get(xbow_vhdl); - xbow = xbow_soft->base; - } -#endif - - /* - * This requires three PIOs (reset the link, check for the - * reset, restore the control register for the link) plus - * 10us to wait for the reset. We allow up to 1ms for the - * widget to come out of reset before giving up and - * returning a failure. - */ - ctrl = xbow->xb_link(port).link_control; - xbow->xb_link(port).link_reset = 0; - itick = get_timestamp(); - while (1) { - stat.linkstatus = xbow->xb_link(port).link_status; - if (stat.link_alive) - break; - dtick = get_timestamp() - itick; - if (dtick > ticks_per_ms) { - return -1; /* never came out of reset */ - } - DELAY(2); /* don't beat on link_status */ - } - xbow->xb_link(port).link_control = ctrl; - return 0; -} - -/* - * Dump xbow registers. - * input parameter is either a pointer to - * the xbow chip or the vertex handle for - * an xbow vertex. - */ -void -idbg_xbowregs(int64_t regs) -{ - xbow_t *xbow; - int i; - xb_linkregs_t *link; - -#ifdef LATER - if (dev_is_vertex((devfs_handle_t) regs)) { - devfs_handle_t vhdl = (devfs_handle_t) regs; - xbow_soft_t soft = xbow_soft_get(vhdl); - - xbow = soft->base; - } else -#endif - { - xbow = (xbow_t *) regs; - } - -#ifdef LATER - qprintf("Printing xbow registers starting at 0x%x\n", xbow); - qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", - xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, - xbow->xb_wid_err_lower, xbow->xb_wid_control, - xbow->xb_wid_req_timeout); - qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", - xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, - xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, - xbow->xb_wid_arb_reload); -#endif - - for (i = 8; i <= 0xf; i++) { - link = &xbow->xb_link(i); -#ifdef LATER - qprintf("Link %d registers\n", i); - qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", - link->link_control, link->link_status, - link->link_arb_upper, link->link_arb_lower, - link->link_aux_status); -#endif - } -} - - -#define XBOW_ARB_RELOAD_TICKS 25 - /* granularity: 4 MB/s, max: 124 MB/s */ -#define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS) - -#define XBOW_BYTES_TO_GBR(BYTES_per_s) (int) (BYTES_per_s / GRANULARITY) - -#define XBOW_GBR_TO_BYTES(cnt) (bandwidth_t) ((cnt) * GRANULARITY) - -#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec) \ - ((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr) - -#define XBOW_ARB_GBR_MAX 31 - -#define ABS(x) ((x > 0) ? (x) : (-1 * x)) - /* absolute value */ - -int -xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec) -{ - int gbr_granted; - int new_total_gbr; - int change_gbr; - bandwidth_t new_total_bw; - -#ifdef GRIO_DEBUG - printf("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n", - old_bytes_per_sec, bytes_per_sec); -#endif /* GRIO_DEBUG */ - - gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)), - old_bytes_per_sec); - new_total_bw = old_bytes_per_sec + bytes_per_sec; - new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)), - new_total_bw); - - change_gbr = new_total_gbr - gbr_granted; - -#ifdef GRIO_DEBUG - printf("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n", - gbr_granted, new_total_gbr, change_gbr); -#endif /* GRIO_DEBUG */ - - return (change_gbr); -} - -/* Conversion from GBR to bytes */ -bandwidth_t -xbow_gbr_to_bytes(int gbr) -{ - return (XBOW_GBR_TO_BYTES(gbr)); -} - -/* Given the vhdl for the desired xbow, the src and dest. widget ids - * and the req_bw value, this xbow driver entry point accesses the - * xbow registers and allocates the desired bandwidth if available. - * - * If bandwidth allocation is successful, return success else return failure. - */ -int -xbow_prio_bw_alloc(devfs_handle_t vhdl, - xwidgetnum_t src_wid, - xwidgetnum_t dest_wid, - unsigned long long old_alloc_bw, - unsigned long long req_bw) -{ - xbow_soft_t soft = xbow_soft_get(vhdl); - volatile xbowreg_t *xreg; - xbowreg_t mask; - unsigned long s; - int error = 0; - bandwidth_t old_bw_BYTES, req_bw_BYTES; - xbowreg_t old_xreg; - int old_bw_GBR, req_bw_GBR, new_bw_GBR; - -#ifdef GRIO_DEBUG - printf("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n", - (int) vhdl, (int) src_wid, (int) dest_wid, req_bw); -#endif - - ASSERT(XBOW_WIDGET_IS_VALID(src_wid)); - ASSERT(XBOW_WIDGET_IS_VALID(dest_wid)); - - s = mutex_spinlock(&soft->xbow_bw_alloc_lock); - - /* Get pointer to the correct register */ - xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid); - - /* Get mask for GBR count value */ - mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid); - - req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw); - req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR))) - : xbow_gbr_to_bytes(req_bw_GBR); - -#ifdef GRIO_DEBUG - printf("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n", - req_bw, req_bw_BYTES, req_bw_GBR); -#endif /* GRIO_DEBUG */ - - old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS]; - old_xreg = *xreg; - old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid)); - -#ifdef GRIO_DEBUG - ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR); - - printf("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR); - - printf("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n", - req_bw_BYTES, old_bw_BYTES, - soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]); - -#endif /* GRIO_DEBUG */ - - /* Accept the request only if we don't exceed the destination - * port HIWATER_MARK *AND* the max. link GBR arbitration count - */ - if (((old_bw_BYTES + req_bw_BYTES) <= - soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) && - (req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) { - - new_bw_GBR = (old_bw_GBR + req_bw_GBR); - - /* Set this in the xbow link register */ - *xreg = (old_xreg & ~mask) | \ - (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask); - - soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] = - xbow_gbr_to_bytes(new_bw_GBR); - } else { - error = 1; - } - - mutex_spinunlock(&soft->xbow_bw_alloc_lock, s); - - return (error); -} diff -Nur linux-2.4.19/arch/ia64/sn/io/xswitch.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/xswitch.c --- linux-2.4.19/arch/ia64/sn/io/xswitch.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/xswitch.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/arch/ia64/sn/io/xtalk.c linux-2.4.19-sgi211r3/arch/ia64/sn/io/xtalk.c --- linux-2.4.19/arch/ia64/sn/io/xtalk.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/io/xtalk.c Wed Dec 31 16:00:00 1969 @@ -1,1024 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Implement crosstalk provider operations. The xtalk* layer provides a - * platform-independent interface for crosstalk devices. This layer - * switches among the possible implementations of a crosstalk adapter. - * - * On platforms with only one possible xtalk provider, macros can be - * set up at the top that cause the table lookups and indirections to - * completely disappear. - */ - -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) - -char widget_info_fingerprint[] = "widget_info"; - -cdl_p xtalk_registry = NULL; - -#define DEV_FUNC(dev,func) hub_##func -#define CAST_PIOMAP(x) ((hub_piomap_t)(x)) -#define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) -#define CAST_INTR(x) ((hub_intr_t)(x)) - -/* ===================================================================== - * Function Table of Contents - */ -xtalk_piomap_t xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); -void xtalk_piomap_free(xtalk_piomap_t); -caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); -void xtalk_piomap_done(xtalk_piomap_t); -caddr_t xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned); -caddr_t xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); -void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); -caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -xtalk_dmamap_t xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void xtalk_dmamap_free(xtalk_dmamap_t); -iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); -alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); -void xtalk_dmamap_done(xtalk_dmamap_t); -iopaddr_t xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void xtalk_dmamap_drain(xtalk_dmamap_t); -void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); -void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); -xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); -xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); -void xtalk_intr_free(xtalk_intr_t); -int xtalk_intr_connect(xtalk_intr_t, xtalk_intr_setfunc_t, void *); -void xtalk_intr_disconnect(xtalk_intr_t); -devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); -int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -int xtalk_error_devenable(devfs_handle_t, int, int); -void xtalk_provider_startup(devfs_handle_t); -void xtalk_provider_shutdown(devfs_handle_t); -devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t); -xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); -xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); -iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); -void *xtalk_intr_sfarg_get(xtalk_intr_t); -devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t); -xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); -iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); -ulong xtalk_pio_mapsz_get(xtalk_piomap_t); -caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); -devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t); -xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); -xwidget_info_t xwidget_info_chk(devfs_handle_t); -xwidget_info_t xwidget_info_get(devfs_handle_t); -void xwidget_info_set(devfs_handle_t, xwidget_info_t); -devfs_handle_t xwidget_info_dev_get(xwidget_info_t); -xwidgetnum_t xwidget_info_id_get(xwidget_info_t); -devfs_handle_t xwidget_info_master_get(xwidget_info_t); -xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); -xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); -xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); -char *xwidget_info_name_get(xwidget_info_t); -void xtalk_init(void); -void xtalk_provider_register(devfs_handle_t, xtalk_provider_t *); -void xtalk_provider_unregister(devfs_handle_t); -xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t); -int xwidget_driver_register(xwidget_part_num_t, - xwidget_mfg_num_t, - char *, unsigned); -void xwidget_driver_unregister(char *); -int xwidget_register(xwidget_hwid_t, devfs_handle_t, - xwidgetnum_t, devfs_handle_t, - xwidgetnum_t, async_attach_t); -int xwidget_unregister(devfs_handle_t); -void xwidget_reset(devfs_handle_t); -char *xwidget_name_get(devfs_handle_t); -#if !defined(DEV_FUNC) -/* - * There is more than one possible provider - * for this platform. We need to examine the - * master vertex of the current vertex for - * a provider function structure, and indirect - * through the appropriately named member. - */ -#define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((xtalk_piomap_t)(x)) -#define CAST_DMAMAP(x) ((xtalk_dmamap_t)(x)) -#define CAST_INTR(x) ((xtalk_intr_t)(x)) - -static xtalk_provider_t * -xwidget_to_provider_fns(devfs_handle_t xconn) -{ - xwidget_info_t widget_info; - xtalk_provider_t *provider_fns; - - widget_info = xwidget_info_get(xconn); - ASSERT(widget_info != NULL); - - provider_fns = xwidget_info_pops_get(widget_info); - ASSERT(provider_fns != NULL); - - return (provider_fns); -} -#endif - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC(map->xp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC(map->xd_dev,func) -#define INTR_FUNC(intr,func) DEV_FUNC(intr_hdl->xi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * xtalk space on a specified widget - */ - -xtalk_piomap_t -xtalk_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ - size_t byte_count, - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags); -} - - -void -xtalk_piomap_free(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_free) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap, /* mapping resources */ - iopaddr_t xtalk_addr, /* map for this xtalk address */ - size_t byte_count) -{ /* map this many bytes */ - return PIOMAP_FUNC(xtalk_piomap, piomap_addr) - (CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count); -} - - -void -xtalk_piomap_done(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_done) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* Crosstalk address */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, xtalk_addr, byte_count, flags); -} - -caddr_t -xtalk_pio_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - xtalk_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - xtalk_piomap_t map = 0; - caddr_t res; - - if (mapp) - *mapp = 0; /* record "no map used" */ - - res = xtalk_piotrans_addr - (dev, dev_desc, addr, byte_count, flags); - if (res) - return res; /* xtalk_piotrans worked */ - - map = xtalk_piomap_alloc - (dev, dev_desc, addr, byte_count, byte_count, flags); - if (!map) - return res; /* xtalk_piomap_alloc failed */ - - res = xtalk_piomap_addr - (map, addr, byte_count); - if (!res) { - xtalk_piomap_free(map); - return res; /* xtalk_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* xtalk_piomap_addr succeeded */ -} - -/* ===================================================================== - * EARLY PIOTRANS SUPPORT - * - * There are places where drivers (mgras, for instance) - * need to get PIO translations before the infrastructure - * is extended to them (setting up textports, for - * instance). These drivers should call - * xtalk_early_piotrans_addr with their xtalk ID - * information, a sequence number (so we can use the second - * mgras for instance), and the usual piotrans parameters. - * - * Machine specific code should provide an implementation - * of early_piotrans_addr, and present a pointer to this - * function to xtalk_set_early_piotrans_addr so it can be - * used by clients without the clients having to know what - * platform or what xtalk provider is in use. - */ - -static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr; - -xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr; - -/* xtalk_set_early_piotrans_addr: - * specify the early_piotrans_addr implementation function. - */ -void -xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl) -{ - impl_early_piotrans_addr = impl; -} - -/* xtalk_early_piotrans_addr: - * figure out a PIO address for the "nth" crosstalk widget that - * matches the specified part and mfgr number. Returns NULL if - * there is no such widget, or if the requested mapping can not - * be constructed. - * Limitations on which crosstalk slots (and busses) are - * checked, and definitions of the ordering of the search across - * the crosstalk slots, are defined by the platform. - */ -caddr_t -xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ - return impl_early_piotrans_addr - (part_num, mfg_num, which, xtalk_addr, byte_count, flags); -} - -/* null_xtalk_early_piotrans_addr: - * used as the early_piotrans_addr implementation until and - * unless a real implementation is provided. In DEBUG kernels, - * we want to know who is calling before the implementation is - * registered; in non-DEBUG kernels, return NULL representing - * lack of mapping support. - */ -/*ARGSUSED */ -static caddr_t -null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ -#if DEBUG - PRINT_PANIC("null_xtalk_early_piotrans_addr"); -#endif - return NULL; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from crosstalk space to system - * physical space. - */ - -xtalk_dmamap_t -xtalk_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - - -void -xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_free) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr) - (CAST_DMAMAP(xtalk_dmamap), paddr, byte_count); -} - - -alenlist_t -xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_list) - (CAST_DMAMAP(xtalk_dmamap), alenlist, flags); -} - - -void -xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_done) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - - -alenlist_t -xtalk_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - -void -xtalk_dmamap_drain(xtalk_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -void -xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow crosstalk devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) -{ /* owner of this interrupt */ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, owner_dev); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Unconditionally setup resources to be non-threaded. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt */ -{ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) - (dev, dev_desc, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -xtalk_intr_free(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - - -/* - * Associate resources allocated with a previous xtalk_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -xtalk_intr_connect(xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ - xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg) /* arg to setfunc */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl), setfunc, setfunc_arg); -} - - -/* - * Disassociate handler with the specified interrupt. - */ -void -xtalk_intr_disconnect(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) -{ - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); -} - - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup a crosstalk provider - */ -void -xtalk_provider_startup(devfs_handle_t xtalk_provider) -{ - DEV_FUNC(xtalk_provider, provider_startup) - (xtalk_provider); -} - - -/* - * Shutdown a crosstalk provider - */ -void -xtalk_provider_shutdown(devfs_handle_t xtalk_provider) -{ - DEV_FUNC(xtalk_provider, provider_shutdown) - (xtalk_provider); -} - -/* - * Enable a device on a xtalk widget - */ -void -xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) -{ - DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum); -} - -/* - * Shutdown a device on a xtalk widget - */ -void -xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) -{ - DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum); -} - -int -xtalk_dma_enabled(devfs_handle_t xconn_vhdl) -{ - return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl); -} -/* - * Generic crosstalk functions, for use with all crosstalk providers - * and all crosstalk devices. - */ - -/****** Generic crosstalk interrupt interfaces ******/ -devfs_handle_t -xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_dev); -} - -xwidgetnum_t -xtalk_intr_target_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_target); -} - -xtalk_intr_vector_t -xtalk_intr_vector_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_vector); -} - -iopaddr_t -xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr) -{ - return (xtalk_intr->xi_addr); -} - -void * -xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_sfarg); -} - -/****** Generic crosstalk pio interfaces ******/ -devfs_handle_t -xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_dev); -} - -xwidgetnum_t -xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_target); -} - -iopaddr_t -xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_xtalk_addr); -} - -ulong -xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_mapsz); -} - -caddr_t -xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_kvaddr); -} - - -/****** Generic crosstalk dma interfaces ******/ -devfs_handle_t -xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_dev); -} - -xwidgetnum_t -xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_target); -} - - -/****** Generic crosstalk widget information interfaces ******/ - -/* xwidget_info_chk: - * check to see if this vertex is a widget; - * if so, return its widget_info (if any). - * if not, return NULL. - */ -xwidget_info_t -xwidget_info_chk(devfs_handle_t xwidget) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo); - return (xwidget_info_t) ainfo; -} - - -xwidget_info_t -xwidget_info_get(devfs_handle_t xwidget) -{ - xwidget_info_t widget_info; - - widget_info = (xwidget_info_t) - hwgraph_fastinfo_get(xwidget); - -#ifdef LATER - if ((widget_info != NULL) && - (widget_info->w_fingerprint != widget_info_fingerprint)) -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_PANIC("%v bad xwidget_info", xwidget); -#else - PRINT_PANIC("%x bad xwidget_info", xwidget); -#endif -#endif /* LATER */ - - return (widget_info); -} - -void -xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) -{ - if (widget_info != NULL) - widget_info->w_fingerprint = widget_info_fingerprint; - - hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info); - - /* Also, mark this vertex as an xwidget, - * and use the widget_info, so xwidget_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET, - (arbitrary_info_t) widget_info); -} - -devfs_handle_t -xwidget_info_dev_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_vertex); -} - -xwidgetnum_t -xwidget_info_id_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_id); -} - - -devfs_handle_t -xwidget_info_master_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_master); -} - -xwidgetnum_t -xwidget_info_masterid_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_masterid); -} - -xwidget_part_num_t -xwidget_info_part_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_hwid.part_num); -} - -xwidget_mfg_num_t -xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_hwid.mfg_num); -} -/* Extract the widget name from the widget information - * for the xtalk widget. - */ -char * -xwidget_info_name_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget info"); - return(xwidget_info->w_name); -} -/****** Generic crosstalk initialization interfaces ******/ - -/* - * One-time initialization needed for systems that support crosstalk. - */ -void -xtalk_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("xtalk_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (xtalk_registry == NULL) { - cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr"); - if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(xtalk_registry != NULL); -} - -/* - * Associate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); -} - -/* - * Disassociate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_unregister(devfs_handle_t provider) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); -} - -/* - * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk - * provider. - */ -xtalk_provider_t * -xtalk_provider_fns_get(devfs_handle_t provider) -{ - return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); -} - -/* - * Announce a driver for a particular crosstalk part. - * Returns 0 on success or -1 on failure. Failure occurs if the - * specified hardware already has a driver. - */ -/*ARGSUSED4 */ -int -xwidget_driver_register(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine could call - * xwidget_driver_register before the - * system calls xtalk_init; so, we - * make the call here. - */ - if (xtalk_registry == NULL) - xtalk_init(); - - return cdl_add_driver(xtalk_registry, - part_num, mfg_num, - driver_prefix, flags, NULL); -} - -/* - * Inform xtalk infrastructure that a driver is no longer available for - * handling any widgets. - */ -void -xwidget_driver_unregister(char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called registger; so we - * can assume we have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - cdl_del_driver(xtalk_registry, driver_prefix, NULL); -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -xtalk_iterate(char *driver_prefix, - xtalk_iter_f *func) -{ - ASSERT(xtalk_registry != NULL); - - cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func); -} - -/* - * xwidget_register: - * Register a xtalk device (xwidget) by doing the following. - * -allocate and initialize xwidget_info data - * -allocate a hwgraph vertex with name based on widget number (id) - * -look up the widget's initialization function and call it, - * or remember the vertex for later initialization. - * - */ -int -xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ - devfs_handle_t widget, /* widget to initialize */ - xwidgetnum_t id, /* widget's target id (0..f) */ - devfs_handle_t master, /* widget's master vertex */ - xwidgetnum_t targetid, /* master's target id (9/a) */ - async_attach_t aa) -{ - xwidget_info_t widget_info; - char *s,devnm[MAXDEVNAME]; - - /* Allocate widget_info and associate it with widget vertex */ - NEW(widget_info); - - /* Initialize widget_info */ - widget_info->w_vertex = widget; - widget_info->w_id = id; - widget_info->w_master = master; - widget_info->w_masterid = targetid; - widget_info->w_hwid = *hwid; /* structure copy */ - widget_info->w_efunc = 0; - widget_info->w_einfo = 0; - /* - * get the name of this xwidget vertex and keep the info. - * This is needed during errors and interupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(widget,devnm,MAXDEVNAME); - widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(widget_info->w_name,s); - - xwidget_info_set(widget, widget_info); - - device_master_set(widget, master); - - /* All the driver init routines (including - * xtalk_init) are called before we get into - * attaching devices, so we can assume we - * have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - /* - * Add pointer to async attach info -- tear down will be done when - * the particular descendant is done with the info. - */ - if (aa) - async_attach_add_info(widget, aa); - - return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); -} - -/* - * xwidget_unregister : - * Unregister the xtalk device and detach all its hwgraph namespace. - */ -int -xwidget_unregister(devfs_handle_t widget) -{ - xwidget_info_t widget_info; - xwidget_hwid_t hwid; - - /* Make sure that we have valid widget information initialized */ - if (!(widget_info = xwidget_info_get(widget))) - return(1); - - /* Remove the inventory information associated - * with the widget. - */ - hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1); - - hwid = &(widget_info->w_hwid); - - cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); - - /* Clean out the xwidget information */ - (void)kfree(widget_info->w_name); - BZERO((void *)widget_info, sizeof(widget_info)); - DEL(widget_info); - - return(0); -} - -/* - * Issue a link reset to a widget. - */ -void -xwidget_reset(devfs_handle_t xwidget) -{ - xswitch_reset_link(xwidget); - -} - - -void -xwidget_gfx_reset(devfs_handle_t xwidget) -{ - xwidget_info_t info; - - xswitch_reset_link(xwidget); - info = xwidget_info_get(xwidget); -#ifdef LATER - ASSERT_ALWAYS(info != NULL); -#endif - - /* - * Enable this for other architectures once we add widget_reset to the - * xtalk provider interface. - */ - DEV_FUNC(xtalk_provider, widget_reset) - (xwidget_info_master_get(info), xwidget_info_id_get(info)); -} - -#define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ - -/* Get the canonical hwgraph name of xtalk widget */ -char * -xwidget_name_get(devfs_handle_t xwidget_vhdl) -{ - xwidget_info_t info; - - /* If we have a bogus widget handle then return - * a default anonymous widget name. - */ - if (xwidget_vhdl == GRAPH_VERTEX_NONE) - return(ANON_XWIDGET_NAME); - /* Read the widget name stored in the widget info - * for the widget setup during widget initialization. - */ - info = xwidget_info_get(xwidget_vhdl); - ASSERT(info != NULL); - return(xwidget_info_name_get(info)); -} - -/* - * xtalk_device_shutdown - * Disable the specified xtalk widget and clean out all the software - * state associated with it. - */ -int -xtalk_device_shutdown(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ - devfs_handle_t widget_vhdl; - char edge_name[8]; - - sprintf(edge_name, "%d", widget); - if (hwgraph_traverse(xbus_vhdl, edge_name, &widget_vhdl) - != GRAPH_SUCCESS) - return(1); - - xwidget_unregister(widget_vhdl); - - return(0); -} diff -Nur linux-2.4.19/arch/ia64/sn/kernel/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/Makefile --- linux-2.4.19/arch/ia64/sn/kernel/Makefile Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/Makefile Mon Dec 30 14:16:56 2002 @@ -1,6 +1,6 @@ -# arch/ia64/sn/Makefile +# arch/ia64/sn/kernel/Makefile # -# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. +# Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of version 2 of the GNU General Public License @@ -40,9 +40,7 @@ O_TARGET = sn.o -ifeq ($(CONFIG_MODULES),y) -export-objs = sn_ksyms.o -endif +export-objs = sn_ksyms.o iomv.o subdir-$(CONFIG_IA64_SGI_SN1) = sn1 subdir-$(CONFIG_IA64_SGI_SN2) = sn2 @@ -51,12 +49,12 @@ obj-$(CONFIG_IA64_SGI_SN1) += irq.o mca.o obj-$(CONFIG_IA64_SGI_SN2) += irq.o mca.o -obj-$(CONFIG_IA64_SGI_SN1) += sn1/sn1.a -obj-$(CONFIG_IA64_SGI_SN2) += sn2/sn2.a +obj-$(CONFIG_IA64_SGI_SN1) += sn1/sn1.o +obj-$(CONFIG_IA64_SGI_SN2) += sn2/sn2.o obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o misctest.o obj-$(CONFIG_IA64_GENERIC) += machvec.o obj-$(CONFIG_MODULES) += sn_ksyms.o - +obj-$(CONFIG_IA64_SGI_SN_BRT) += bte_regr_test.o include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/sn/kernel/bte.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/bte.c --- linux-2.4.19/arch/ia64/sn/kernel/bte.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/bte.c Tue Jan 14 15:58:22 2003 @@ -1,16 +1,46 @@ /* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ +#include #include #include #include #include #include +#ifdef CONFIG_IA64_SGI_SN2 +#include +#endif #include #include @@ -20,64 +50,203 @@ #include int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; +#define BTE_SELECT(_x) ((_x) % BTES_PER_NODE) /* - * bte_init_node(nodepda, cnode, cmdline_p) + * bte_init_node(nodepda, cnode) * * Initialize the nodepda structure with BTE base addresses and * spinlocks. * + * NOTE: The kernel parameter btetest will cause the initialization + * code to reserve blocks of physically contiguous memory to be + * used by the bte test module. */ void -bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode, char **cmdline_p) +bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) { - int bteTestMode = 0; - int cmdoffset = 0; int i; + struct bte_recover_s *bte_recover; -#ifdef ZZZ - if (!cmdoffset) { - for (;cmdline_p[cmdoffset]; cmdoffset++) { - if (strstr(cmdline_p[cmdoffset], "btetest")) { - bteTestMode = 1; - break; - } - } - } -#endif /* * Indicate that all the block transfer engines on this node * are available. */ + + /* + * Allocate one bte_recover_t structure per node. It holds + * the recovery lock for node. All the bte interface structures + * will point at this one bte_recover structure to get the lock. + */ + bte_recover = alloc_bootmem_node(NODE_DATA(cnode), sizeof(struct bte_recover_s)); + spin_lock_init(&(bte_recover->bte_recover_lock)); + for (i = 0; i < BTES_PER_NODE; i++) { #ifdef CONFIG_IA64_SGI_SN2 /* >>> Don't know why the 0x1800000L is here. Robin */ - mynodepda->node_bte_info[i].bte_base_addr = + mynodepda->bte_if[i].bte_base_addr = (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); + #elif CONFIG_IA64_SGI_SN1 - mynodepda->node_bte_info[i].bte_base_addr = + mynodepda->bte_if[i].bte_base_addr = (char *)LOCAL_HUB_ADDR(bte_offsets[i]); #else #error BTE Not defined for this hardware platform. #endif + /* + * Initialize the notification and spinlock + * so the first transfer can occur. + */ + mynodepda->bte_if[i].most_rcnt_na = + &(mynodepda->bte_if[i].notify); + mynodepda->bte_if[i].notify = 0L; #ifdef CONFIG_IA64_SGI_BTE_LOCKING - /* Initialize the notification and spinlock */ - /* so the first transfer can occur. */ - mynodepda->node_bte_info[i].mostRecentNotification = - &(mynodepda->node_bte_info[i].notify); - mynodepda->node_bte_info[i].notify = 0L; - spin_lock_init(&mynodepda->node_bte_info[i].spinlock); + spin_lock_init(&mynodepda->bte_if[i].spinlock); #endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - if (bteTestMode) { - mynodepda->node_bte_info[i].bteTestBuf = - alloc_bootmem_node(NODE_DATA(cnode), - BTE_MAX_XFER); + mynodepda->bte_if[i].bte_test_buf = + alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER); + mynodepda->bte_if[i].bte_recover = bte_recover; + mynodepda->bte_if[i].bte_cnode = cnode; + mynodepda->bte_if[i].bte_error_count = 0; + mynodepda->bte_if[i].bte_num = i; + mynodepda->bte_if[i].bh_error = 0; + mynodepda->bte_if[i].npda = mynodepda; + mynodepda->bte_if[i].bte_cnode = cnode; + mynodepda->bte_if[i].bte_timeout = 0xFFFFFFFF; /* FIXME */ + } + +} + +/* + * bte_get_all_interfaces() + * When recovering from a BTE failure, we must grab all the BTE + * interfaces, because cleaning up one has side effects on the + * others if they are in the middle of a transfer. + */ +int +bte_get_all_interfaces(bteinfo_t *bteinfo) +{ + bteinfo_t *binfo[BTES_PER_NODE]; + hubreg_t bte_status; + int i; + + /* + * Grab all the locks in order. + * Make sure any transfers have completed. + */ + for (i = 0; i < BTES_PER_NODE; i++) { + if (i == bteinfo->bte_num) { + continue; /* We already have our lock */ + } + binfo[i] = NODE_BTE_INFO(((nodepda_t *)bteinfo->npda), i); + /* + * Set the error bit on the other interface. This will + * avoid having to wait for them to time out before they + * free up their lock and we can continue with the cleanup. + */ + binfo[i]->notify = IBLS_ERROR; + while (!BTE_TRYLOCK(binfo[i])) { + us_delay(1); + } + } + + for (i = 0; i < BTES_PER_NODE; i++) { + u64 local_RTC = 0; + u64 stop_RTC = 0; + BTE_TIME_DECLARE() + + if (binfo[i]){ + if (i == bteinfo->bte_num) { + continue; /* We already know our bte is not busy */ + } + bte_status = BTE_LOAD(binfo[i]->bte_base_addr,BTEOFF_STAT); + local_RTC = ia64_get_itc(); + stop_RTC = local_RTC + binfo[i]->bte_timeout; + while (BTE_IS_BUSY(bte_status)) { + if (BTE_ERROR(bte_status)) { + break; } + if (binfo[i]->notify == IBLS_ERROR) { + break; + } + local_RTC = ia64_get_itc(); + if (stop_RTC < local_RTC) { + /* + * This software timer is used in case the BTE + * is always busy. + */ + break; /* time out */ + } + us_delay(1); /* FIXME - rja needed? */ + bte_status = BTE_LOAD(binfo[i]->bte_base_addr,BTEOFF_STAT); + } + } + } + return(0); +} + +void +bte_free_interfaces(bteinfo_t *bteinfo, int bte_num) +{ + int i; + bteinfo_t *binfo; + + /* + * Unlock all other interfaces except our own. + */ + for (i = 0; i < BTES_PER_NODE; i++) { + if (i == bte_num) continue; + binfo = NODE_BTE_INFO(((nodepda_t *)bteinfo->npda), i); + binfo->notify = 0; /* clear the error bit */ + BTE_UNLOCK(binfo); + } +} + +#if RJA +/* + * bte_reset_nasid(nasid_t) + * + * Does a soft reset of the BTEs on the specified nasid. + * This is followed by a one-line transfer from each of the + * virtual interfaces. + */ +void +bte_reset_nasid(nasid_t n) +{ + ii_ibcr_u_t ibcr; + + ibcr.ii_ibcr_regval = REMOTE_HUB_L(n, IIO_IBCR); + ibcr.ii_ibcr_fld_s.i_soft_reset = 1; + REMOTE_HUB_S(n, IIO_IBCR, ibcr.ii_ibcr_regval); + + /* One line transfer on virtual interface 0 */ + REMOTE_HUB_S(n, IIO_IBLS_0, IBLS_BUSY | 1); + REMOTE_HUB_S(n, IIO_IBSA_0, TO_PHYS(__pa(&nodepda->bte_cleanup))); + REMOTE_HUB_S(n, IIO_IBDA_0, + TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); + REMOTE_HUB_S(n, IIO_IBNA_0, + TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); + REMOTE_HUB_S(n, IIO_IBCT_0, BTE_NOTIFY); + while (REMOTE_HUB_L(n, IIO_IBLS0)) { + /* >>> Need some way out in case of hang... */ + } + + /* One line transfer on virtual interface 1 */ + REMOTE_HUB_S(n, IIO_IBLS_1, IBLS_BUSY | 1); + REMOTE_HUB_S(n, IIO_IBSA_1, TO_PHYS(__pa(nodepda->bte_cleanup))); + REMOTE_HUB_S(n, IIO_IBDA_1, + TO_PHYS(__pa(nodepda->bte_cleanup[4 * L1_CACHE_BYTES]))); + REMOTE_HUB_S(n, IIO_IBNA_1, + TO_PHYS(__pa(nodepda->bte_cleanup[5 * L1_CACHE_BYTES]))); + REMOTE_HUB_S(n, IIO_IBCT_1, BTE_NOTIFY); + while (REMOTE_HUB_L(n, IIO_IBLS1)) { + /* >>> Need some way out in case of hang... */ } } +#endif /* RJA */ /* * bte_init_cpu() @@ -91,11 +260,11 @@ { /* Called by setup.c as each cpu is being added to the nodepda */ if (local_node_data->active_cpu_count & 0x1) { - pda.cpubte[0] = &(nodepda->node_bte_info[0]); - pda.cpubte[1] = &(nodepda->node_bte_info[1]); + pda.cpu_bte_if[0] = &(nodepda->bte_if[0]); + pda.cpu_bte_if[1] = &(nodepda->bte_if[1]); } else { - pda.cpubte[0] = &(nodepda->node_bte_info[1]); - pda.cpubte[1] = &(nodepda->node_bte_info[0]); + pda.cpu_bte_if[0] = &(nodepda->bte_if[1]); + pda.cpu_bte_if[1] = &(nodepda->bte_if[0]); } } @@ -112,14 +281,12 @@ * len - number of bytes to transfer from source to dest. * mode - hardware defined. See reference information * for IBCT0/1 in the SGI documentation. - * bteBlock - kernel virtual address of a temporary - * buffer used during unaligned transfers. * * NOTE: If the source, dest, and len are all cache line aligned, * then it would be _FAR_ preferrable to use bte_copy instead. */ bte_result_t -bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode, char *bteBlock) +bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) { int destFirstCacheOffset; u64 headBteSource; @@ -132,11 +299,19 @@ u64 footBcopyDest; u64 footBcopyLen; bte_result_t rv; + char *bteBlock; if (len == 0) { return (BTE_SUCCESS); } +#ifdef CONFIG_IA64_SGI_BTE_LOCKING +#error bte_unaligned_copy() assumes single BTE selection in bte_copy(). +#else + /* temporary buffer used during unaligned transfers */ + bteBlock = pda.cpu_bte_if[0]->bte_test_buf; +#endif + headBcopySrcOffset = src & L1_CACHE_MASK; destFirstCacheOffset = dest & L1_CACHE_MASK; @@ -261,3 +436,218 @@ } return (BTE_SUCCESS); } + +/* + * bte_copy(src, dest, len, mode, notification) + * + * use the block transfer engine to move kernel + * memory from src to dest using the assigned mode. + * + * Paramaters: + * src - physical address of the transfer source. + * dest - physical address of the transfer destination. + * len - number of bytes to transfer from source to dest. + * mode - hardware defined. See reference information + * for IBCT0/1 in the SHUB Programmers Reference + * notification - kernel virtual address of the notification cache + * line. If NULL, the default is used and + * the bte_copy is synchronous. + * + * NOTE: This function requires src, dest, and len to + * be cache line aligned. + */ +bte_result_t +bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) +{ +#ifdef CONFIG_IA64_SGI_BTE_LOCKING + int bte_to_use; +#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ + u64 transfer_size; + u64 lines_remaining; + bteinfo_t *bte; + BTE_TIME_DECLARE(); + BTE_TIME_START(); + BTE_PRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", + src, dest, len, mode, notification)); + + if (len == 0) { + BTE_TIME_STOP(); + return (BTE_SUCCESS); + } + + ASSERT(!((len & L1_CACHE_MASK) || + (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK))); + ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)); + +#ifdef CONFIG_IA64_SGI_BTE_LOCKING + { + bte_to_use = 0; + /* Attempt to lock one of the BTE interfaces */ + while ((bte_to_use < BTES_PER_NODE) && + BTE_LOCK_IF_AVAIL(bte_to_use)) { + bte_to_use++; + } + + if ((bte_to_use >= BTES_PER_NODE) && + !(mode & BTE_WACQUIRE)) { + BTE_TIME_STOP(); + return (BTEFAIL_NOTAVAIL); + } + + /* Wait until a bte is available. */ + } + while (bte_to_use >= BTES_PER_NODE); + + bte = pda.cpu_bte_if[bte_to_use]; + BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use)); +#else + /* Assuming one BTE per CPU. */ + bte = pda.cpu_bte_if[0]; +#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ + /* + * The following are removed for optimization but is + * available in the event that the SHUB exhibits + * notification problems similar to the hub, bedrock et al. + * + * bte->mostRecentSrc = src; + * bte->mostRecentDest = dest; + * bte->mostRecentLen = len; + * bte->mostRecentMode = mode; + */ + if (notification == NULL) { + /* User does not want to be notified. */ + bte->most_rcnt_na = &bte->notify; + } else { + bte->most_rcnt_na = notification; + } + + /* Calculate the number of cache lines to transfer. */ + transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); + BTE_PRINTKV(("Calculated transfer size of %d cache lines\n", + transfer_size)); + /* Initialize the notification to a known value. */ + *bte->most_rcnt_na = -1L; + + BTE_PRINTKV(("Before, status is 0x%lx and notify is 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), + *bte->most_rcnt_na)); + + /* Set the status reg busy bit and transfer length */ + BTE_PRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)\n", + BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size)); + HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size)); + + /* Set the source and destination registers */ + BTE_PRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_SRC_ADDR, + (TO_PHYS(src)))); + HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src))); + BTE_PRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_DEST_ADDR, + (TO_PHYS(dest)))); + HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest))); + + /* Set the notification register */ + BTE_PRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_NOTIF_ADDR, + (TO_PHYS(__pa(bte->most_rcnt_na))))); + HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(__pa(bte->most_rcnt_na)))); + + + /* Initiate the transfer */ + BTE_PRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)\n", BTEREG_CTRL_ADDR, mode)); + BTE_TIME_XFR_START(); + HUB_S(BTEREG_CTRL_ADDR, BTE_VLD_MODE(mode)); + + BTE_PRINTKV(("Initiated, status is 0x%lx and notify is 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), + *bte->most_rcnt_na)); + + if (notification == NULL) { + /* + * Calculate our timeout + * + * What are we doing here? We are trying to determine + * the fastest time the BTE could have transfered our + * block of data. By takine the clock frequency (ticks/sec) + * divided by the BTE MaxT Transfer Rate (lines/sec) + * times the transfer size (lines), we get a tick + * offset from current time that the transfer should + * complete. + * + * Why do this? We are watching for a notification + * failure from the BTE. This behaviour has been + * seen in the SN0 and SN1 hardware on rare circumstances + * and is expected in SN2. By checking at the + * ideal transfer timeout, we minimize our time + * delay from hardware completing our request and + * our detecting the failure. + */ + bte->ideal_xfr_tmo = BTE_IDEAL_TMO(transfer_size); + + while (bte->notify == -1UL) { + /* + * Notification Workaround: When the max + * theoretical time has elapsed, read the hub + * status register into the notification area. + * This fakes the shub performing the copy. + */ + BTE_PRINTKV((" Timing. IBLS = 0x%lx, " + "notify= 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), + bte->notify)); + if (time_after(jiffies, bte->ideal_xfr_tmo)) { + lines_remaining = HUB_L(BTEREG_LNSTAT_ADDR) & + BTE_LEN_MASK; + bte->ideal_xfr_tmo_cnt++; + bte->ideal_xfr_tmo = + BTE_IDEAL_TMO(lines_remaining); + + BTE_PRINTKV((" Timeout. cpu %d " + "IBLS = 0x%lx, " + "notify= 0x%lx, " + "Lines remaining = %d. " + "New timeout = %d.\n", + smp_processor_id(), + HUB_L(BTEREG_LNSTAT_ADDR), + bte->notify, + lines_remaining, + bte->ideal_xfr_tmo)); + } + } + BTE_PRINTKV((" Delay Done. IBLS = 0x%lx, notify= 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), + bte->notify)); + BTE_TIME_XFR_STOP(); + if (bte->notify & IBLS_ERROR) { +#ifdef CONFIG_IA64_SGI_SN2 + bte_result_t bte_status; + + bte_status = bte_error_handler(bte); +#endif + transfer_size = 0; +#ifdef CONFIG_IA64_SGI_BTE_LOCKING + spin_unlock(&(bte->spinlock)); +#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ + BTE_PRINTKV(("Erroring status is 0x%lx and " + "notify is 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), + bte->notify)); + + BTE_TIME_STOP(); + bte->notify = 0L; + return (BTEFAIL_ERROR); + } + } + /* + * Success! Transfer complete + */ +#ifdef CONFIG_IA64_SGI_BTE_LOCKING + spin_unlock(&(bte->spinlock)); +#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ + BTE_TIME_STOP(); + BTE_PRINTKV(("Returning status is 0x%lx and notify is 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), + *bte->most_rcnt_na)); + + return (BTE_SUCCESS); +} + + diff -Nur linux-2.4.19/arch/ia64/sn/kernel/bte_regr_test.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/bte_regr_test.c --- linux-2.4.19/arch/ia64/sn/kernel/bte_regr_test.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/bte_regr_test.c Mon Dec 30 14:16:56 2002 @@ -0,0 +1,1062 @@ +/* + * + * + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +/*********************************************************************** + * Block Transfer Engine regression tests. + * + * The following set of tests can be used to test for regressions. + * It is implemented as a loadable module. + * + * To enable the tests, the kernel must be booted with the + * "btetest" command line flag. If the tests are compiled into the + * kernel, additional values may be passed with + * "bte_test=t,v,ht,tn,tx,ti,ta,tc" + * where: + * t = Bitmask of tests to run. + * v = Level of verbosity. + * ht = Number of seconds to try to force a notification hang. + * hu = Number of uSecs to wait until warning of hang. + * tn = Min number of lines to rate test with (2 raised to). + * tx = Max number of lines to rate test with (2 raised to). + * ti = Number of iterations per timing. + * ta = Aternate through cpus on each pass. + * tc = Use/Don't Use memcopy + * + * When loaded as a module, each of those values has a seperate + * parameter. Just do a modinfo bte_test.o to get those names + * and valid ranges. + * + * Tests are performed in the following order. + * + * Standard Transfer Test - Just transfers a block of initialized + * data to a cleared block and ensures that memory before and after + * is untouched, but that the body has all the correct values. + * + * Transfer Rate Test - Data is transfered from node to node + * to ensure every node is able to BTE data. Timings are created + * for each node. + * + * Notification Hang Test - Attempts to force the Notification + * hang problem to arise. A hang occurs when the BTE fails + * to invalidate a processors cache line for the notification + * word, resulting in the processor not seeing the updated + * value. + * + * Invalid Transfer Test - In this test, we attempt to transfer + * data from a valid address to a nasid which does not exist. + * + **********************************************************************/ + + +#define BTE_TIME 1 /* Needed to ensure bte_copy records + * timings */ +// #define BTE_DEBUG +// #define BTE_DEBUG_VERBOSE + +#include +#include +#include +#include +#include +#include +#include + +#include + + +/*********************************************************************** + * Local defines, structs, and typedefs. + * + **********************************************************************/ + + +/* + * The following struct defines standard transfers to use while + * testing. + */ +typedef struct brt_xfer_entry_s { + int source_offset; + int dest_offset; + int length; +} brt_xfer_entry_t; + +/* + * BRT_TEST_BLOCK_SIZE needs to accomodate the largest transfer that + * is found in brt_xfer_tests. + */ +#define BRT_TEST_BLOCK_SIZE 1024 + +/* Flags for selecting tests to run. */ +#define TEST_REGRESSION 0x00000001 /* Standard Transfer */ +#define TEST_TIME 0x00000002 /* Timed Transfer */ +#define TEST_NOTIFY 0x00000004 /* Notification Hang */ +#define TEST_NONODE 0x00000008 /* Invalid Nasid Xfer */ + + +/*********************************************************************** + * Global variables. + * + **********************************************************************/ + + +/* + * bte_setup_time - Time it takes for bte_copy to get locks + * acquired and values into SHUB registers to start the + * xfer. + * + * bte_transfer_time - Time where hardware is doing the xfer. + * + * bte_tear_down_time - Time to unlock and return. + * + * bte_execute_time - Time from first call until return. + */ +volatile static u64 bte_setup_time; +volatile static u64 bte_transfer_time; +volatile static u64 bte_tear_down_time; +volatile static u64 bte_execute_time; + +/* Tests to run during standard transfer tests. */ +static brt_xfer_entry_t brt_xfer_tests[] = { + {0, 0, 2 * L1_CACHE_BYTES}, /* The ideal case. */ + + {0, 0, 35}, /* Symetrical aligned test. */ + {L1_CACHE_BYTES, L1_CACHE_BYTES, 35}, + {0, 0, L1_CACHE_BYTES + 35}, + {L1_CACHE_BYTES, L1_CACHE_BYTES, L1_CACHE_BYTES + 35}, + {0, 0, (2 * L1_CACHE_BYTES) + 35}, + {L1_CACHE_BYTES, L1_CACHE_BYTES, (2 * L1_CACHE_BYTES) + 35}, + {0, 0, (4 * L1_CACHE_BYTES) + 35}, + {L1_CACHE_BYTES, L1_CACHE_BYTES, (4 * L1_CACHE_BYTES) + 35}, + + {(0 + 25), (0 + 25), 35}, /* Symetrical unaligned test. */ + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25), 35}, + {(0 + 25), (0 + 25), L1_CACHE_BYTES + 35}, + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25), + (L1_CACHE_BYTES + 25) + 35}, + {(0 + 25), (0 + 25), (2 * L1_CACHE_BYTES) + 35}, + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25), + (2 * L1_CACHE_BYTES) + 35}, + {(0 + 25), (0 + 25), (4 * L1_CACHE_BYTES) + 35}, + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25), + (4 * L1_CACHE_BYTES) + 35}, + + {(0 + 25), (0 + 26), 35}, /* Asymetrical unaligned test. */ + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26), 35}, + {(0 + 25), (0 + 26), L1_CACHE_BYTES + 35}, + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26), + (L1_CACHE_BYTES + 25) + 35}, + {(0 + 25), (0 + 26), (2 * L1_CACHE_BYTES) + 35}, + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26), + (2 * L1_CACHE_BYTES) + 35}, + {(0 + 25), (0 + 26), (4 * L1_CACHE_BYTES) + 35}, + {(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26), + (4 * L1_CACHE_BYTES) + 35}, + + {0, 0, 0} /* Terminator */ +}; + +static atomic_t brt_thread_cnt; /* Threads in test. */ +volatile static int brt_exit_flag; /* Flag termination of hang test */ + +/* command line/module parameters */ +static int selected_tests = 0; +static int verbose = 0; +static int hang_timeout = 10; +static int hang_usec = 12; +static int tm_min_lines = 1; +static int tm_max_lines = 3; +static int tm_iterations = 1; +static int tm_alternate = 0; +static int tm_memcpy = 1; +static int ix_iterations = 1000; +static int ix_srcnasid = -1; + + +/*********************************************************************** + * Local Function Prototypes. + * + **********************************************************************/ + + +static int __init brt_test_init(void); +static void __exit brt_test_exit(void); + +/* Standard Transfer Test related functions. */ +static int brt_tst_std_xfer(void); +static int brt_std_xfer(char *, char *, int, int, int, int); +static void brt_hex_dump(char *, int); + +/* Timed Transfer Test related functions. */ +static int brt_tst_time_xfers(void); +static void brt_time_xfer(int, int, int); + +/* Notification Hang Test related functions. */ +static int brt_tst_notify_hang(void); +static int brt_notify_thrd(void *); + +/* Transfers to Invalid Nasid Test related functions. */ +static int brt_tst_invalid_xfers(void); + +#if !defined(MODULE) +/* Kernel command line handler. */ +static int __init brt_setup(char *); +#endif /* !defined(MODULE) */ + + +/*********************************************************************** + * Module Load/Unload. + * + **********************************************************************/ + + +#define brt_marker() \ + printk("**************************************************" \ + "**********************.\n"); \ + printk("\n"); \ + printk("**************************************************" \ + "**********************.\n"); \ + printk("\n"); \ + printk("**************************************************" \ + "**********************.\n"); \ + printk("\n"); + + +static int __init +brt_test_init(void) +{ + int some_tests_removed; + + if (numnodes < 2) { + printk("These tests are best run on multinode " + "systems.\n"); + } + + if (!pda.cpu_bte_if[0]->bte_test_buf) { + some_tests_removed = 0; + + /* Timed Transfers go node-to-node. */ + if (selected_tests & TEST_TIME) { + some_tests_removed = 1; + selected_tests &= ~(TEST_TIME); + } + + /* Notification Hang runs on all cpus simultaneously */ + if (selected_tests & TEST_NOTIFY) { + some_tests_removed = 1; + selected_tests &= ~(TEST_NOTIFY); + } + + /* Invalid Tests */ + if (selected_tests & TEST_NONODE) { + some_tests_removed = 1; + selected_tests &= ~(TEST_NONODE); + } + + if (some_tests_removed) { + printk("Test Buffers were not allocated.\n"); + printk("Please reboot the system and supply " + "the \"btetest\" kernel flag\n"); + printk("Some tests were removed.\n"); + } + } + + brt_marker(); + + printk("brt_test(): Starting.\n"); + + if (selected_tests & TEST_REGRESSION) { + if (brt_tst_std_xfer()) { + printk("Standard Transfers had errors.\n"); + } + + } + + if (selected_tests & TEST_TIME) { + if (tm_min_lines < 0) { + tm_min_lines = 0; + } + if (tm_max_lines < 0) { + tm_max_lines = 0; + } + + if (tm_max_lines > BTE_LEN_MASK) { + tm_max_lines = BTE_LEN_MASK; + } + if (tm_min_lines > tm_max_lines) { + tm_min_lines = tm_max_lines; + } + + if (brt_tst_time_xfers()) { + printk("Timed transfers had errors.\n"); + } + + } + + if (selected_tests & TEST_NOTIFY) { + if (hang_usec < 8) { + hang_usec = 8; + } + if (hang_usec > 256) { + hang_usec = 256; + } + + if (brt_tst_notify_hang()) { + printk("Notification Hang test had errors.\n"); + } + } + + if (selected_tests & TEST_NONODE) { + if (brt_tst_invalid_xfers()) { + printk("Invalid Nasid test had errors.\n"); + } + } + + return (1); /* Prevent module load. */ +} + + +static void __exit +brt_test_exit(void) +{ +} + + +/*********************************************************************** + * Standard Transfer Test. + * + * This test has a table of transfers defined above. For each + * transfer, it calls bte_unaligned_copy. It compares the actual + * result with the expected result. If they differ, it prints out + * information about the transfer and hex dumps the actual block + * + **********************************************************************/ + + +/* + * Allocate the needed buffers and then initiate each xfer specified + * by brt_xfer_tests. + */ +static int +brt_tst_std_xfer(void) +{ + char *block_1; + char *block_2; + int iteration = 0; + brt_xfer_entry_t *cur_test; + int cpu; + int err_cnt; + + block_1 = kmalloc(BRT_TEST_BLOCK_SIZE, GFP_KERNEL); + ASSERT(!((u64) block_1 & L1_CACHE_MASK)); + block_2 = kmalloc(BRT_TEST_BLOCK_SIZE, GFP_KERNEL); + ASSERT(!((u64) block_2 & L1_CACHE_MASK)); + + cur_test = brt_xfer_tests; + + err_cnt = 0; + while (cur_test->length) { + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + set_cpus_allowed(current, (1UL << cpu)); + + if (verbose > 1) { + printk("Cpu %d Transfering %d from " + "%d to %d.\n", + smp_processor_id(), + cur_test->length, + cur_test->source_offset, + cur_test->dest_offset); + } + + err_cnt += brt_std_xfer(block_1, block_2, + cur_test->source_offset, + cur_test->dest_offset, + cur_test->length, + ++iteration); + + } + cur_test++; + } + + kfree(block_2); + kfree(block_1); + + return ((err_cnt ? 1 : 0)); +} + + +/* + * Perform a single transfer and ensure the result matches + * the expected. Returns the number of differences found. + * + * Testing is performed by setting the source buffer to a + * known value, and zeroing out the destination. + * + * After the copy, if the destination has only the known + * source values at the correct place, we know we had a + * good transfer. + * + */ +static int +brt_std_xfer(char *src, char *dst, + int src_offset, int dst_offset, int len, + int magic) +{ + int i, ret; + int err_cnt = 0; + + if (verbose > 3) { + printk("brt_test(src=0x%lx, dst=0x%lx, src_offset=%d, " + "dst_offset=%d, len=%d, magic=%d\n", + (u64) src, (u64) dst, src_offset, + dst_offset, len, magic); + } + + memset(src, ((magic + 1) & 0xff), BRT_TEST_BLOCK_SIZE); + memset((src + src_offset), magic, len); + if (verbose > 8) { + printk("Before transfer: Source is\n"); + brt_hex_dump(src, BRT_TEST_BLOCK_SIZE); + } + memset(dst, 0, BRT_TEST_BLOCK_SIZE); + if (verbose > 8) { + printk("Before transfer: dest is\n"); + brt_hex_dump(dst, BRT_TEST_BLOCK_SIZE); + } + + ret = BTE_UNALIGNED_COPY(__pa(src + src_offset), + __pa(dst + dst_offset), + len, BTE_NOTIFY); + if (ret != BTE_SUCCESS) { + printk("brt_test: BTE_UNALIGNED_COPY() error: %d\n", ret); + return (1); + } + + /* Check head */ + for (i = 0; i < dst_offset; i++) { + if ((dst[i] & 0xff) != 0) { + err_cnt++; + } + } + /* Check body */ + for (i = 0; i < len; i++) { + if ((dst[dst_offset + i] & 0xff) != (magic & 0xff)) { + err_cnt++; + } + } + /* Check foot */ + for (i = (dst_offset + len); i < BRT_TEST_BLOCK_SIZE; i++) { + if ((dst[i] & 0xff) != 0) { + err_cnt++; + } + } + + if ((verbose > 3) || err_cnt) { + printk("brt_test: %d errors during basic " + "transfer test.\n", err_cnt); + brt_hex_dump(dst, BRT_TEST_BLOCK_SIZE); + } + + return (err_cnt); +} + + +/* + * Dump a block of data to console as hex. + */ +static void +brt_hex_dump(char *block_to_dump, int block_len) +{ + int i; + char fmt_line[128]; + char *fmt_eol = fmt_line; + + for (i = 0; i < block_len; i++) { + if (!(i % 16)) { + if (i > 0) { + printk("%s\n", fmt_line); + } + sprintf(fmt_line, "0x%lx %05d ", + __pa(&block_to_dump[i]), i); + fmt_eol = fmt_line; + } + while (*fmt_eol++) { /* empty */ + }; + fmt_eol--; + sprintf(fmt_eol, "%s%02x", + (!(i % 4) ? " " : ""), (block_to_dump[i] & 0xff)); + } + printk("%s\n", fmt_line); +} + + +/*********************************************************************** + * Transfer Rate Test. + * + * This test migrates to each cpu one at a time. This is done to + * get a complete view of how each of the bte engines is performing + * and help ensure that each virtual interface is being used. + * NOTE: All virtual interfaces will not necessarily be used. + * + * Now that we have migrated to the desired cpu, we transfer from + * our node to all the other nodes (including ourself). We + * accomplish this with both a memcpy and a bte_copy. Timings + * for both are printed. + * + **********************************************************************/ + + +#define NSEC(x) ((x) * (1000000000UL / local_cpu_data->itc_freq)) + + +/* + * Migrate to each cpu. When on the desired cpu, time transfers to + * each node by calling brt_time_xfer. + */ +static int +brt_tst_time_xfers(void) +{ + int tst_cpu; + int dest_node; + int xfer_lines; + int i; + + if (tm_memcpy) { + printk("Cpu,Src,Dst,Lines,Stup,Transfr,Fin,Execute," + "Overall,Memcpy\n"); + } else { + printk("Cpu,Src,Dst,Lines,Stup,Transfr,Fin,Execute," + "Overall\n"); + } + + if (tm_alternate) { + /* Now transfer from this node to all the others. */ + for (dest_node = 0; dest_node < numnodes; dest_node++) { + for (xfer_lines = tm_min_lines; + xfer_lines <= tm_max_lines;) { + + for (i = 0; i < tm_iterations; i++) { + for (tst_cpu = 0; + tst_cpu < smp_num_cpus; + tst_cpu++) { + /* Move to the desired CPU. */ + set_cpus_allowed(current, + (1UL << tst_cpu)); + + brt_time_xfer(dest_node, + 1, + xfer_lines); + + } + } + /* Handle a min of 0 */ + if (xfer_lines < 1) { + xfer_lines = 1; + } else { + xfer_lines *= 2; + } + } + } + } else { + for (tst_cpu = 0; tst_cpu < smp_num_cpus; tst_cpu++) { + /* Move to the desired CPU. */ + set_cpus_allowed(current, (1UL << tst_cpu)); + + /* Now transfer from this node to all the others. */ + for (dest_node = 0; dest_node < numnodes; + dest_node++) { + for (xfer_lines = tm_min_lines; + xfer_lines <= tm_max_lines;) { + + brt_time_xfer(dest_node, + tm_iterations, + xfer_lines); + + /* Handle a min of 0 */ + if (xfer_lines < 1) { + xfer_lines = 1; + } else { + xfer_lines *= 2; + } + } + } + } + } + return (0); +} + + +/* + * Transfer the bte_test_buffer from our node to the specified + * destination and print out timing results. + */ +static void +brt_time_xfer(int dest_node, int iterations, int xfer_lines) +{ + int iteration; + char *src, *dst; + u64 xfer_len, src_phys, dst_phys; + u64 itc_before, itc_after, mem_intvl, bte_intvl; + + + xfer_len = xfer_lines * L1_CACHE_BYTES; + + src = nodepda->bte_if[0].bte_test_buf; + src_phys = __pa(src); + dst = NODEPDA(dest_node)->bte_if[1].bte_test_buf; + dst_phys = __pa(dst); + mem_intvl = 0; + + for (iteration = 0; iteration < iterations; iteration++) { + if (tm_memcpy) { + itc_before = ia64_get_itc(); + memcpy(dst, src, xfer_len); + itc_after = ia64_get_itc(); + mem_intvl = itc_after - itc_before; + } + + itc_before = ia64_get_itc(); + bte_copy(src_phys, dst_phys, xfer_len, BTE_NOTIFY, NULL); + itc_after = ia64_get_itc(); + bte_intvl = itc_after - itc_before; + + if (tm_memcpy) { + printk("%3d,%3d,%3d,%5d,%4ld,%7ld,%3ld," + "%7ld,%7ld,%7ld\n", + smp_processor_id(), NASID_GET(src), + NASID_GET(dst), xfer_lines, + NSEC(bte_setup_time), + NSEC(bte_transfer_time), + NSEC(bte_tear_down_time), + NSEC(bte_execute_time), NSEC(bte_intvl), + NSEC(mem_intvl)); + } else { + printk("%3d,%3d,%3d,%5d,%4ld,%7ld,%3ld," + "%7ld,%7ld\n", + smp_processor_id(), NASID_GET(src), + NASID_GET(dst), xfer_lines, + NSEC(bte_setup_time), + NSEC(bte_transfer_time), + NSEC(bte_tear_down_time), + NSEC(bte_execute_time), NSEC(bte_intvl)); + } + } + +} + + +/*********************************************************************** + * Notification Hang Test. -- NOTE: Has never actually caused a hang. + * + * The next set of code checks to see if the Notification Hang + * occurs. It does this by starting one thread per cpu, pinning + * the thread to its assigned cpu. After it is pinned, we lock + * the associated bte. Source, Dest, and Notification are + * assigned. + * + * Inside of a loop, we set the length and trigger the + * transfer. We use the ITC to determine when the transfer should + * complete. Whenever the IBLS_BUSY bit is cleared, the transfer + * has completed. We occasionally call schedule (Since all CPUs + * have a pinned process The machine will be doing nothing but + * out tranfers) and loop. + * + * If twice max normal time has passed without seeing the + * notification, we check the Length/Status register to see if + * IBLS_BUSY is still asserted and length is zero. This is an + * indication of the hang. + * + **********************************************************************/ + + +/* + * Launch one thread per cpu. When all threads are started, sleep + * the specified timeout and then notify the other threads that it + * is time to exit. + */ +static int +brt_tst_notify_hang(void) +{ + int tst_cpu; + + printk("Waiting %d seconds to complete test.\n", hang_timeout); + + atomic_set(&brt_thread_cnt, 0); + brt_exit_flag = 0; + + for (tst_cpu = 0; tst_cpu < smp_num_cpus; tst_cpu++) { + if ((kernel_thread(brt_notify_thrd, + (void *)(long)tst_cpu, 0)) < 0) { + printk("Failed to start thread.\n"); + } + } + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(hang_timeout * HZ); + set_current_state(TASK_RUNNING); + + printk("Flagging an exit.\n"); + brt_exit_flag = 1; + + while (atomic_read(&brt_thread_cnt)) { + /* Wait until everyone else is done. */ + schedule(); + } + + printk("All threads have exited.\n"); + return (0); +} + + +/* + * One of these threads is started per cpu. Each thread is responsible + * for loading that cpu's bte interface and then writing to the + * test buffer. The transfers are set in a round-robin fashion. + * The end result is that each test buffer is being written into + * by the previous node and both cpu's at the same time as the + * local bte is transferring it to the next node. + */ +static int +brt_notify_thrd(void *__bind_cpu) +{ + int bind_cpu = (long int)__bind_cpu; + int cpu = cpu_logical_map(bind_cpu); + nodepda_t *nxt_node; + long tmout_itc_intvls; + long tmout; + long passes; + long good_xfer_cnt; + u64 src_phys, dst_phys; + int i; + volatile char *src_buf; + u64 *notify; + + atomic_inc(&brt_thread_cnt); + daemonize(); + set_user_nice(current, 19); + sigfillset(¤t->blocked); + + /* Migrate to the right CPU */ + set_cpus_allowed(current, 1UL << cpu); + + /* Calculate the uSec timeout itc offset. */ + tmout_itc_intvls = local_cpu_data->cyc_per_usec * hang_usec; + + if (local_cnodeid() == (numnodes - 1)) { + nxt_node = NODEPDA(0); + } else { + nxt_node = NODEPDA(local_cnodeid() + 1); + } + + src_buf = nodepda->bte_if[0].bte_test_buf; + src_phys = __pa(src_buf); + dst_phys = __pa(nxt_node->bte_if[0].bte_test_buf); + + notify = kmalloc(L1_CACHE_BYTES, GFP_KERNEL); + ASSERT(!((u64) notify & L1_CACHE_MASK)); + + printk("BTE Hang %d xfer 0x%lx -> 0x%lx, Notify=0x%lx\n", + smp_processor_id(), src_phys, dst_phys, (u64) notify); + + passes = 0; + good_xfer_cnt = 0; + + /* Loop until signalled to exit. */ + while (!brt_exit_flag) { + /* + * A hang will prevent further transfers. + * NOTE: Sometimes, it appears like a hang occurred and + * then transfers begin again. This just means that + * there is NUMA congestion and the hang_usec param + * should be increased. + */ + if (!(*notify & IBLS_BUSY)) { + if ((bte_copy(src_phys, + dst_phys, + 4UL * L1_CACHE_BYTES, + BTE_NOTIFY, + (void *)notify)) != BTE_SUCCESS) { + printk("<0>Cpu %d Could not " + "allocate a bte.\n", + smp_processor_id()); + continue; + } + + tmout = ia64_get_itc() + tmout_itc_intvls; + + while ((*notify & IBLS_BUSY) && + (ia64_get_itc() < tmout)) { + + + /* Push data out with the processor. */ + for (i = 0; i < (4 * L1_CACHE_BYTES); + i += L1_CACHE_BYTES) { + src_buf[i] = (passes % 128); + } + }; + + if (*notify & IBLS_BUSY) { + printk("<0>Cpu %d BTE appears to have " + "hung.\n", smp_processor_id()); + } else { + good_xfer_cnt++; + } + } + + /* Every x passes, take a little break. */ + if (!(++passes % 40)) { + passes = 0; + schedule_timeout(0.01 * HZ); + } + } + + kfree(notify); + + printk("Cpu %d had %ld good passes\n", + smp_processor_id(), good_xfer_cnt); + + atomic_dec(&brt_thread_cnt); + return (0); +} + + +/*********************************************************************** + * Invalid Transfer Test. + * + * Just transfer from the local node to a nasid which does not + * exist. + * + * >>> Potential Problem: on SN1, HUB interrupt doesn't always + * occurr. + * + **********************************************************************/ + + +/* + * Locate a nasid which doesn't exist. Perform a bte_copy from that + * node to our local node. + */ +static int +brt_tst_invalid_xfers(void) +{ + int i; + int free_nasid = -1; + int cpu; + int error_cnt; + + u64 ret_code; + + if (ix_srcnasid != -1) { + free_nasid = ix_srcnasid; + } else { + /* Only looking for nasids from C-Nodes. */ + for (i = 0; i < PLAT_MAX_NODE_NUMBER; i += 2) { + if (local_node_data->physical_node_map[i] == -1) { + free_nasid = i; + break; + } + } + } + + if (free_nasid == -1) { + printk("tst_invalid_xfers: No free nodes found. " + "Exiting.\n"); + return (0); + } + + printk("tst_invalid_xfers: Using source nasid of %d\n", + free_nasid); + + error_cnt = 0; + + for (i = 0; i < ix_iterations; i++) { + if (verbose >= 1) { + printk("-------------------------------" + "-------------------------------" + "--------------\n"); + } + if ((verbose >= 1) || !(i % 10)) { + printk(" Loop %d\n", i); + } + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + set_cpus_allowed(current, (1UL << cpu)); + + if (verbose > 1) { + printk("Testing with CPU %d\n", + smp_processor_id()); + } + + /* >>> Need a better means of calculating a + * remote addr. */ + ret_code = bte_copy(TO_NODE(free_nasid, 0), + __pa(nodepda->bte_if[0]. + bte_test_buf), + 4 * L1_CACHE_BYTES, + BTE_NOTIFY, + NULL); + error_cnt += (ret_code ? 1 : 0); + } + } + + ret_code = ((error_cnt != (ix_iterations * smp_num_cpus)) ? + 1 : 0); + return (ret_code); +} + + +/*********************************************************************** + * Kernel command line handler. + * + **********************************************************************/ + + +#if !defined(MODULE) +static int __init +brt_setup(char *str) +{ + int cur_val; + + if (get_option(&str, &cur_val)) { + selected_tests = cur_val; + } + if (get_option(&str, &cur_val)) { + verbose = cur_val; + } + if (get_option(&str, &cur_val)) { + hang_timeout = cur_val; + } + if (get_option(&str, &cur_val)) { + hang_usec = cur_val; + } + if (get_option(&str, &cur_val)) { + tm_min_lines = cur_val; + } + if (get_option(&str, &cur_val)) { + tm_max_lines = cur_val; + } + if (get_option(&str, &cur_val)) { + tm_iterations = cur_val; + } + if (get_option(&str, &cur_val)) { + tm_alternate = cur_val; + } + if (get_option(&str, &cur_val)) { + tm_memcpy = cur_val; + } + if (get_option(&str, &cur_val)) { + ix_iterations = cur_val; + } + if (get_option(&str, &cur_val)) { + ix_srcnasid = cur_val; + } + + return (1); +} +#endif /* !defined(MODULE) */ + + +/*********************************************************************** + * Module parameters. + * + * The two supported cases are loadable module parms and kernel + * command line support. + * + * The loadable module options are specified below in the + * MODULE_PARM macros and have associated descriptions. + * + * The kernel command line option is btetest=x[,y[,z]] etc. The + * individual setting order is constant. NOTE: The btetest flag + * is checked for in the bte_init_node function. + * + **********************************************************************/ + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Silicon Graphics, Inc."); +MODULE_DESCRIPTION("Test the Block Transfer Engine(BTE) " + "present on SGI machines."); + +MODULE_PARM(selected_tests, "1i"); +MODULE_PARM_DESC(selected_tests, "Bitmask of tests to run."); + +MODULE_PARM(verbose, "1i"); +MODULE_PARM_DESC(verbose, + "How much information should be " + "printed during the tests."); + +MODULE_PARM(hang_timeout, "1i"); +MODULE_PARM_DESC(hang_timeout, + "Number of seconds to wait for the Bte " + "Notification Failure."); + +MODULE_PARM(hang_usec, "1i"); +MODULE_PARM_DESC(hang_usec, + "Number of micro-seconds to wait for the 4-line Bte " + "transfer to complete."); + +MODULE_PARM(tm_min_lines, "1i"); +MODULE_PARM_DESC(tm_min_lines, "Minimum number of cache lines" + " to time with."); + +MODULE_PARM(tm_max_lines, "1i"); +MODULE_PARM_DESC(tm_max_lines, "Maximum number of cache lines" + " to time with."); + +MODULE_PARM(tm_iterations, "1i"); +MODULE_PARM_DESC(tm_iterations, "Rerun each timed transfer this " + "many times."); + +MODULE_PARM(tm_alternate, "1i"); +MODULE_PARM_DESC(tm_alternate, "Cycle across cpus between each " + "iteration"); + +MODULE_PARM(tm_memcpy, "1i"); +MODULE_PARM_DESC(tm_memcpy, "Use memcpy as a comparison to BTE"); + +MODULE_PARM(ix_iterations, "1i"); +MODULE_PARM_DESC(ix_iterations, "Rerun each transfer from an " + "invalid nasid this many times."); + +MODULE_PARM(ix_srcnasid, "1i"); +MODULE_PARM_DESC(ix_srcnasid, "Nasid to attempt xfer from."); + + +#if !defined(MODULE) +__setup("btetest=", brt_setup); +#endif /* !defined(MODULE) */ + + +module_init(brt_test_init); +module_exit(brt_test_exit); diff -Nur linux-2.4.19/arch/ia64/sn/kernel/iomv.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/iomv.c --- linux-2.4.19/arch/ia64/sn/kernel/iomv.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/iomv.c Mon Dec 30 14:16:56 2002 @@ -3,19 +3,11 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include - -#if 1 /* ##jh */ -#ifdef CONFIG_IA64_SGI_SN1 -#define mmiob sn1_mmiob -#else -#define mmiob sn2_mmiob -#endif -extern void mmiob(void); -#endif /* ##jh */ +#include extern void * sn_io_addr(unsigned long port); /* defined in sn[12]/iomv.c */ @@ -83,7 +75,6 @@ volatile unsigned char *addr = sn_io_addr(port); *addr = val; - mmiob(); } /** @@ -99,7 +90,6 @@ volatile unsigned short *addr = sn_io_addr(port); *addr = val; - mmiob(); } /** @@ -115,5 +105,11 @@ volatile unsigned int *addr = sn_io_addr(port); *addr = val; - mmiob(); } + +EXPORT_SYMBOL(sn_inb); +EXPORT_SYMBOL(sn_inw); +EXPORT_SYMBOL(sn_inl); +EXPORT_SYMBOL(sn_outb); +EXPORT_SYMBOL(sn_outw); +EXPORT_SYMBOL(sn_outl); diff -Nur linux-2.4.19/arch/ia64/sn/kernel/irq.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/irq.c --- linux-2.4.19/arch/ia64/sn/kernel/irq.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/irq.c Thu Feb 13 10:59:52 2003 @@ -1,7 +1,7 @@ /* * Platform dependent support for SGI SN1 * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -49,18 +49,23 @@ #include #include #include -#ifdef ajmtestintr #include #include -#endif /* ajmtestintr */ #include #include #include #include #include #include +#include +#include +#include +#include int irq_to_bit_pos(int irq); +static void force_interrupt(int irq); +extern void pcibr_force_interrupt(pcibr_intr_t intr); +extern int sn_force_interrupt_flag; @@ -156,13 +161,14 @@ int subnode; #endif int nasid; + int ivec; #ifdef CONFIG_IA64_SGI_SN2 unsigned long event_occurred; #endif - irq = irq & 0xff; + ivec = irq & 0xff; #ifdef CONFIG_IA64_SGI_SN1 - if (irq == SGI_UART_IRQ) { + if (ivec == SGI_UART_IRQ) { nasid = smp_physical_node_id(); subnode = cpuid_to_subnode(smp_processor_id()); intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); @@ -172,7 +178,7 @@ } #endif #ifdef CONFIG_IA64_SGI_SN2 - if (irq == SGI_UART_VECTOR) { + if (ivec == SGI_UART_VECTOR) { nasid = smp_physical_node_id(); event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) ); // If the UART bit is set here, we may have received an interrupt from the @@ -182,6 +188,8 @@ platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0); } } + if (sn_force_interrupt_flag) + force_interrupt(irq); #endif } @@ -226,12 +234,6 @@ return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); } -int -sn_valid_irq(u8 irq) { - - return( ((irq & 0xff) < NR_IRQS) && ((irq >> 8) < NR_CPUS) ); -} - void *kmalloc(size_t, int); void @@ -240,7 +242,7 @@ int i; irq_desc_t *base_desc = _irq_desc; - for (i=IA64_FIRST_DEVICE_VECTOR; inext) list = list->next; + list->next = p; + p->next = NULL; + p->intr = intr; + } else { + pcibr_intr_list[irq] = p; + p->next = NULL; + p->intr = intr; + } +} + +void +force_polled_int(void) { + int cpu = smp_processor_id(); + int i; + struct pcibr_intr_list_t *p; + + cpu = cpu << 8; + for (i=cpu; iintr){ + pcibr_force_interrupt(p->intr); + } + p = p->next; + } + } +} + +static void +force_interrupt(int irq) { + struct pcibr_intr_list_t *p = pcibr_intr_list[irq]; + + while (p) { + if (p->intr) { + pcibr_force_interrupt(p->intr); + } + p = p->next; + } +} + +static inline int +sn_get_next_bit(void) { + int i; + int bit; + + for (i = 3; i >= 0; i--) { + if (pda.sn_soft_irr[i] != 0) { + bit = (i * 64) + __ffs(pda.sn_soft_irr[i]); + __change_bit(bit, (volatile void *)pda.sn_soft_irr); + return(bit); + } + } + return IA64_SPURIOUS_INT_VECTOR; +} + +void +sn_set_tpr(int vector) { + if (vector > IA64_LAST_DEVICE_VECTOR || vector < IA64_FIRST_DEVICE_VECTOR) { + ia64_set_tpr(vector); + } else { + ia64_set_tpr(IA64_LAST_DEVICE_VECTOR); + } +} + +static inline void +sn_get_all_ivr(void) { + int vector; + + vector = ia64_get_ivr(); + while (vector != IA64_SPURIOUS_INT_VECTOR) { + __set_bit(vector, (volatile void *)pda.sn_soft_irr); + ia64_eoi(); + if (vector > IA64_LAST_DEVICE_VECTOR) return; + vector = ia64_get_ivr(); + } +} + +int +sn_get_ivr(void) { + int vector; + unsigned long flags; + + vector = sn_get_next_bit(); + if (vector == IA64_SPURIOUS_INT_VECTOR) { + sn_get_all_ivr(); + vector = sn_get_next_bit(); + } + return vector; } #ifdef ajmtestintr diff -Nur linux-2.4.19/arch/ia64/sn/kernel/llsc4.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/llsc4.c --- linux-2.4.19/arch/ia64/sn/kernel/llsc4.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/llsc4.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff -Nur linux-2.4.19/arch/ia64/sn/kernel/llsc4.h linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/llsc4.h --- linux-2.4.19/arch/ia64/sn/kernel/llsc4.h Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/llsc4.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifdef STANDALONE diff -Nur linux-2.4.19/arch/ia64/sn/kernel/machvec.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/machvec.c --- linux-2.4.19/arch/ia64/sn/kernel/machvec.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/machvec.c Mon Dec 30 14:16:56 2002 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff -Nur linux-2.4.19/arch/ia64/sn/kernel/mca.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/mca.c --- linux-2.4.19/arch/ia64/sn/kernel/mca.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/mca.c Mon Dec 30 14:16:56 2002 @@ -2,7 +2,7 @@ * File: mca.c * Purpose: SN specific MCA code. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -34,199 +34,80 @@ */ #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include - -static char *shub_mmr_names[] = { - "sh_event_occurred", - "sh_first_error", - "sh_event_overflow", - -/* PI */ - "sh_pi_first_error", - "sh_pi_error_summary", - "sh_pi_error_overflow", - -/* PI HW */ - "sh_pi_error_detail_1", - "sh_pi_error_detail_2", - "sh_pi_hw_time_stamp", - -/* PI UCE */ - "sh_pi_uncorrected_detail_1", - "sh_pi_uncorrected_detail_2", - "sh_pi_uncorrected_detail_3", - "sh_pi_uncorrected_detail_4", - "sh_pi_uncor_time_stamp", - -/* PI CE */ - "sh_pi_corrected_detail_1", - "sh_pi_corrected_detail_2", - "sh_pi_corrected_detail_3", - "sh_pi_corrected_detail_4", - "sh_pi_cor_time_stamp", - -/* MD */ - "sh_mem_error_summary", - "sh_mem_error_overflow", -/* MD HW */ - "sh_misc_err_hdr_upper", - "sh_misc_err_hdr_lower", - "sh_md_dqlp_mmr_xperr_val", - "sh_md_dqlp_mmr_yperr_val", - "sh_md_dqrp_mmr_xperr_val", - "sh_md_dqrp_mmr_yperr_val", - "sh_md_hw_time_stamp", - -/* MD UCE */ - "sh_dir_uc_err_hdr_lower", - "sh_dir_uc_err_hdr_upper", - "sh_md_dqlp_mmr_xuerr1", - "sh_md_dqlp_mmr_xuerr2", - "sh_md_dqlp_mmr_yuerr1", - "sh_md_dqlp_mmr_yuerr2", - "sh_md_dqrp_mmr_xuerr1", - "sh_md_dqrp_mmr_xuerr2", - "sh_md_dqrp_mmr_yuerr1", - "sh_md_dqrp_mmr_yuerr2", - "sh_md_uncor_time_stamp", - -/* MD CE */ - "sh_dir_cor_err_hdr_lower", - "sh_dir_cor_err_hdr_upper", - "sh_md_dqlp_mmr_xcerr1", - "sh_md_dqlp_mmr_xcerr2", - "sh_md_dqlp_mmr_ycerr1", - "sh_md_dqlp_mmr_ycerr2", - "sh_md_dqrp_mmr_xcerr1", - "sh_md_dqrp_mmr_xcerr2", - "sh_md_dqrp_mmr_ycerr1", - "sh_md_dqrp_mmr_ycerr2", - "sh_md_cor_time_stamp", - -/* MD CE, UCE */ - "sh_md_dqls_mmr_xamopw_err", - "sh_md_dqrs_mmr_yamopw_err", - -/* XN */ - "sh_xn_error_summary", - "sh_xn_first_error", - "sh_xn_error_overflow", - -/* XN HW */ - "sh_xniilb_error_summary", - "sh_xniilb_first_error", - "sh_xniilb_error_overflow", - "sh_xniilb_error_detail_1", - "sh_xniilb_error_detail_2", - "sh_xniilb_error_detail_3", - - "sh_ni0_error_summary_1", - "sh_ni0_first_error_1", - "sh_ni0_error_overflow_1", - - "sh_ni0_error_summary_2", - "sh_ni0_first_error_2", - "sh_ni0_error_overflow_2", - "sh_ni0_error_detail_1", - "sh_ni0_error_detail_2", - "sh_ni0_error_detail_3", - - "sh_ni1_error_summary_1", - "sh_ni1_first_error_1", - "sh_ni1_error_overflow_1", - - "sh_ni1_error_summary_2", - "sh_ni1_first_error_2", - "sh_ni1_error_overflow_2", - - "sh_ni1_error_detail_1", - "sh_ni1_error_detail_2", - "sh_ni1_error_detail_3", - - "sh_xn_hw_time_stamp", - -/* XN HW & UCE & SBE */ - "sh_xnpi_error_summary", - "sh_xnpi_first_error", - "sh_xnpi_error_overflow", - "sh_xnpi_error_detail_1", - - "sh_xnmd_error_summary", - "sh_xnmd_first_error", - "sh_xnmd_error_overflow", - "sh_xnmd_ecc_err_report", - "sh_xnmd_error_detail_1", - -/* XN UCE */ - "sh_xn_uncorrected_detail_1", - "sh_xn_uncorrected_detail_2", - "sh_xn_uncorrected_detail_3", - "sh_xn_uncorrected_detail_4", - "sh_xn_uncor_time_stamp", - -/* XN CE */ - "sh_xn_corrected_detail_1", - "sh_xn_corrected_detail_2", - "sh_xn_corrected_detail_3", - "sh_xn_corrected_detail_4", - "sh_xn_cor_time_stamp", - -/* LB HW */ - "sh_lb_error_summary", - "sh_lb_first_error", - "sh_lb_error_overflow", - "sh_lb_error_detail_1", - "sh_lb_error_detail_2", - "sh_lb_error_detail_3", - "sh_lb_error_detail_4", - "sh_lb_error_detail_5", - "sh_junk_error_status", -}; -void -sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) + +/* + * Interval for calling SAL to poll for errors that do NOT cause error + * interrupts. SAL will raise a CPEI if any errors are present that + * need to be logged. + */ +#define CPEI_INTERVAL (5*HZ) + + +struct timer_list sn_cpei_timer; +void sn_init_cpei_timer(void); + + +/* + * print_hook + * + * This function is the callback routine that SAL calls to log error + * info for platform errors. + */ +static int +print_hook(const char *fmt, ...) { - sal_log_plat_info_t *sh_info = (sal_log_plat_info_t *) p_data; - u64 *mmr_val = (u64 *)&(sh_info->shub_state); - char **mmr_name = shub_mmr_names; - int mmr_count = sizeof(sal_log_shub_state_t)>>3; - - while(mmr_count) { - if(*mmr_val) { - prfunc("%-40s: %#016lx\n",*mmr_name, *mmr_val); - } - mmr_name++; - mmr_val++; - mmr_count--; + static int newline=1; + char buf[400], *p; + va_list args; + int len=0; + + + va_start(args, fmt); + if (newline) { + strcpy(buf, "+ "); + len += 2; } + len += vsnprintf(buf+len, sizeof(buf)-len, fmt, args); + /* Prefix each line with "+ " to be consistent with mca.c. */ + p = buf; + while ((p=strchr(p, '\n')) && *++p != '\0') { + memmove(p+2, p, 1+strlen(p)); + strncpy(p, "+ ", 2); + len += 2; + } + newline = (p != 0); + + va_end(args); + printk("%s", buf); + return len; } -sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) + + +/* + * ia64_sn2_platform_plat_specific_err_print + * + * Called by the MCA handler to log platform-specific errors. + */ +void +ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) { - struct ia64_sal_retval isrv; + ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len); +} + + +static void +sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) +{ /* * this function's sole purpose is to call SAL when we receive * a CE interrupt from SHUB or when the timer routine decides @@ -234,46 +115,45 @@ */ /* CALL SAL_LOG_CE */ - SAL_CALL(isrv, SN_SAL_LOG_CE, irq, 0, 0, 0, 0, 0, 0); -} -#include + ia64_sn_plat_cpei_handler(); +} -#define CPEI_INTERVAL (HZ/100) -struct timer_list sn_cpei_timer; -void sn_init_cpei_timer(void); -void +static void sn_cpei_timer_handler(unsigned long dummy) { - sn_cpei_handler(-1, NULL, NULL); - del_timer(&sn_cpei_timer); - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; + sn_cpei_handler(-1, NULL, NULL); + del_timer(&sn_cpei_timer); + sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; add_timer(&sn_cpei_timer); } void sn_init_cpei_timer() { - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; + sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; sn_cpei_timer.function = sn_cpei_timer_handler; add_timer(&sn_cpei_timer); } + + + #ifdef ajmtestceintr struct timer_list sn_ce_timer; void sn_ce_timer_handler(long dummy) { - unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00; + unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00; - *pi_ce_error_inject_reg = 0x0000000000000100; - del_timer(&sn_ce_timer); - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; + *pi_ce_error_inject_reg = 0x0000000000000100; + del_timer(&sn_ce_timer); + sn_ce_timer.expires = jiffies + CPEI_INTERVAL; add_timer(&sn_ce_timer); } sn_init_ce_timer() { - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; + sn_ce_timer.expires = jiffies + CPEI_INTERVAL; sn_ce_timer.function = sn_ce_timer_handler; add_timer(&sn_ce_timer); } diff -Nur linux-2.4.19/arch/ia64/sn/kernel/misctest.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/misctest.c --- linux-2.4.19/arch/ia64/sn/kernel/misctest.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/misctest.c Mon Dec 30 14:16:56 2002 @@ -4,119 +4,368 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include #include #include #include #include - +#include +#include +#include +#include +#include +#include +#include extern int autotest_enabled; -int mcatest=0; - +long mcatest=0, debug0, debug1, debug2, debug3; +#define HDELAY(t) (IS_RUNNING_ON_SIMULATOR() ? udelay(1) : udelay(t)) /* * mcatest - * 1 = expected MCA - * 2 = unexpected MCA - * 3 = expected MCA + unexpected MCA - * 4 = INIT - * 5 = speculative load to garbage memory address - * 6 = speculative load with ld8.s (needs poison hack in PROM) - * 7 = speculative load from mis-predicted branch (needs poison hack in PROM) + * mactest contains a decimal number (RPTT) where + * R - flag, if non zero, run forever + * + * P - identifies when to run the test + * 0 execute test at cpu 0 early init + * 1 execute test at cpu 0 idle + * 2 execute test at last (highest numbered) cpu idle + * 3 execute test on all cpus at idle + * + * TT- identifies test to run + * 01 = MCA via dup TLB dropin + * 02 = MCA via garbage address + * 03 = lfetch via garbage address + * 05 = INIT self + * 06 = INIT other cpu + * 07 = INIT non-existent cpu + * 10 = IPI stress test. Target cpu 0 + * 11 = IPI stress test. Target all cpus + * 12 = TLB stress test + * 13 = Park cpu (spinloop) + * 14 = One shot TLB test with tlb spinlock + * 15 = One shot TLB test + * 16 = One shot TLB test sync'ed with RTC + * 20 = set led to the cpuid & spin. + * 21 = Try mixed cache/uncached refs & see what happens + * 22 = Call SAL reboot + * 23 = Call PAL halt */ static int __init set_mcatest(char *str) { - get_option(&str, &mcatest); + int val; + get_option(&str, &val); + mcatest = val; return 1; } - __setup("mcatest=", set_mcatest); +static int __init set_debug0(char *str) +{ + int val; + get_option(&str, &val); + debug0 = val; + return 1; +} +__setup("debug0=", set_debug0); + +static int __init set_debug1(char *str) +{ + int val; + get_option(&str, &val); + debug1 = val; + return 1; +} +__setup("debug1=", set_debug1); + +static int __init set_debug2(char *str) +{ + int val; + get_option(&str, &val); + debug2 = val; + return 1; +} +__setup("debug2=", set_debug2); + +static int __init set_debug3(char *str) +{ + int val; + get_option(&str, &val); + debug3 = val; + return 1; +} +__setup("debug3=", set_debug3); + +static volatile int go; + +static void +do_sync(int pos) { + if (pos != 3) + return; + else if (smp_processor_id() == 0) + go = 1; + else + while (!go); +} + +static void +sgi_mcatest_bkpt(void) +{ +} + + +/* + * Optional test + * pos - 0 called from early init + * pos - called when cpu about to go idle (fully initialized + */ void -sgi_mcatest(void) +sgi_mcatest(int pos) { - if (mcatest == 1 || mcatest == 3) { - long *p, result, adrs[] = {0xc0000a000f021004UL, 0xc0000a000f026004UL, 0x800000000, 0x500000, 0}; - long size[] = {1,2,4,8}; - int r, i, j; - p = (long*)0xc000000000000000UL; - ia64_fc(p); - *p = 0x0123456789abcdefL; - for (i=0; i<5; i++) { - for (j=0; j<4; j++) { - printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]); - result = -1; - r = ia64_sn_probe_io_slot (adrs[i], size[j], &result); - printk(" status %d, val 0x%lx\n", r, result); + long spos, test, repeat; + int cpu, curcpu, i, n; + + //if (IS_RUNNING_ON_SIMULATOR()) mcatest=1323; + repeat = mcatest/1000; + spos = (mcatest/100)%10; + test = mcatest % 100; + curcpu = smp_processor_id(); + + if ( mcatest == 0 || !((pos == 0 && spos == 0) || + (pos == 1 && spos == 3) || + (pos == 1 && spos == 1 && curcpu == 0) || + (pos == 1 && spos == 2 && curcpu == smp_num_cpus-1))) + return; + +again: + if (test == 1 || test == 2 || test == 3) { + void zzzmca(int); + printk("CPU %d: About to cause unexpected MCA\n", curcpu); + HDELAY(100000); + sgi_mcatest_bkpt(); + do_sync(spos); + + zzzmca(test-1); + + HDELAY(100000); + } + + if (test == 4) { + long result, adrs[] = {0xe0021000009821e0UL, 0xc0003f3000000000UL, 0xc0000081101c0000UL, 0xc00000180e021004UL, 0xc00000180e022004UL, 0xc00000180e023004UL }; + long size[] = {1,2,4,8}; + int r, i, j, k; + + for (k=0; k<2; k++) { + for (i=0; i<6; i++) { + for (j=0; j<4; j++) { + printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]); + result = -1; + r = ia64_sn_probe_io_slot (adrs[i], size[j], &result); + printk(" status %d, val 0x%lx\n", r, result); + udelay(100000); + } } } + } - if (mcatest == 2 || mcatest == 3) { - void zzzmca(int, int, int); - printk("About to cause unexpected MCA\n"); - zzzmca(mcatest, 0x32dead, 0x33dead); - } - if (mcatest == 4) { - long *p; - int delivery_mode = 5; - printk("About to try to cause an INIT on cpu 0\n"); - p = (long*)((0xc0000a0000000000LL | ((long)get_nasid())<<33) | 0x1800080); - *p = (delivery_mode << 8); - udelay(10000); - printk("Returned from INIT\n"); - } - if (mcatest == 5) { - int zzzspec(long); - int i; - long flags, dcr, res, val, addr=0xff00000000UL; - - dcr = ia64_get_dcr(); - for (i=0; i<5; i++) { - printk("Default DCR: 0x%lx\n", ia64_get_dcr()); - printk("zzzspec: 0x%x\n", zzzspec(addr)); - ia64_set_dcr(0); - printk("New DCR: 0x%lx\n", ia64_get_dcr()); - printk("zzzspec: 0x%x\n", zzzspec(addr)); - ia64_set_dcr(dcr); - res = ia64_sn_probe_io_slot(0xff00000000UL, 8, &val); - printk("zzzspec: probe %ld, 0x%lx\n", res, val); - ia64_clear_ic(flags); - ia64_itc(0x2, 0xe00000ff00000000UL, - pte_val(mk_pte_phys(0xff00000000UL, - __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), _PAGE_SIZE_256M); - local_irq_restore(flags); - ia64_srlz_i (); - } + if (test == 5) { + cpu = curcpu; + printk("CPU %d: About to send INIT to self (cpu %d)\n", curcpu, cpu); + HDELAY(100000); + sgi_mcatest_bkpt(); + do_sync(spos); + + platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); + + HDELAY(100000); + printk("CPU %d: Returned from INIT\n", curcpu); } - if (mcatest == 6) { - int zzzspec(long); - int i; - long dcr, addr=0xe000000008000000UL; - - dcr = ia64_get_dcr(); - for (i=0; i<5; i++) { - printk("zzzspec: 0x%x\n", zzzspec(addr)); - ia64_set_dcr(0); - } - ia64_set_dcr(dcr); - } - if (mcatest == 7) { - int zzzspec2(long, long); - int i; - long addr=0xe000000008000000UL; - long addr2=0xe000000007000000UL; - - for (i=0; i<5; i++) { - printk("zzzspec2\n"); - zzzspec2(addr, addr2); + + if (test == 6) { + cpu = curcpu ^ 1; + printk("CPU %d: About to send INIT to other cpu (cpu %d)\n", curcpu, cpu); + HDELAY(100000); + sgi_mcatest_bkpt(); + do_sync(spos); + + platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); + + HDELAY(100000); + printk("CPU %d: Done\n", curcpu); + } + + if (test == 7) { + printk("CPU %d: About to send INIT to non-existent cpu\n", curcpu); + HDELAY(100000); + sgi_mcatest_bkpt(); + do_sync(spos); + + sn_send_IPI_phys(0xffff, 0, IA64_IPI_DM_INIT); + + HDELAY(100000); + printk("CPU %d: Done\n", curcpu); + } + + if (test == 10) { + n = IS_RUNNING_ON_SIMULATOR() ? 10 : 10000000; + cpu = 0; + printk("CPU %d: IPI stress test. Target cpu 0\n", curcpu); + HDELAY(100000); + sgi_mcatest_bkpt(); + do_sync(spos); + + for (i=0; i 2 && cpu != curcpu) + platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); + + HDELAY(100000); + printk("CPU %d: Done\n", curcpu); + } + + if (test == 12) { + long adr = 0xe002200000000000UL; + n = IS_RUNNING_ON_SIMULATOR() ? 1000 : 100000; + printk("CPU %d: TLB flush stress test\n", curcpu); + HDELAY(100000); + sgi_mcatest_bkpt(); + do_sync(spos); + + for (i=0; i= smp_num_cpus-2) { + printk("Parking cpu %d\n", curcpu); + local_irq_disable(); + while(1); + } else { + printk("Waiting cpu %d\n", curcpu); + HDELAY(1000000); + } + HDELAY(1000000); + inited = 1; + } + if (test == 16 || test == 17) { + unsigned long t, shift, mask; + mask = (smp_num_cpus > 16) ? 0x1f : 0xf; + shift = 25-debug1; + do { + t = get_cycles(); + if (IS_RUNNING_ON_SIMULATOR()) + t = (t>>8); + else + t = (t>>shift); + t = t & mask; + } while (t == curcpu); + do { + t = get_cycles(); + if (IS_RUNNING_ON_SIMULATOR()) + t = (t>>8); + else + t = (t>>shift); + t = t & mask; + } while (t != curcpu); + } + if(debug3) printk("CPU %d: One TLB start\n", curcpu); + if (test != 17) platform_global_tlb_purge(adr, adr+PAGE_SIZE*debug0, 14); + if(debug3) printk("CPU %d: One TLB flush done\n", curcpu); + } + if (test == 20) { + local_irq_disable(); + set_led_bits(smp_processor_id(), 0xff); + while(1); + } + if (test == 21) { + extern long ia64_mca_stack[]; + int i, n; + volatile long *p, *up; + p = (volatile long*)__imva(ia64_mca_stack); + up = (volatile long*)(__pa(p) | __IA64_UNCACHED_OFFSET); + + if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ get data in cache\n"); + for (n=0, i=0; i<100; i++) + n += *(p+i); + if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); + for (n=0, i=0; i<100; i++) + n += *(up+i); + if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ dirty the data via cached refs\n"); + for (n=0, i=0; i<100; i++) + *(p+i) = i; + if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); + for (n=0, i=0; i<100; i++) + n += *(up+i); + if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Flushing cache\n"); + for (n=0, i=0; i<100; i++) + ia64_fc((void*)(p+i)); + printk("ZZZ done\n"); + } + if (test == 21) { + int i; + volatile long tb, t[10]; + for (i=0; i<10; i++) { + tb = debug3+ia64_get_itc(); + sgi_mcatest_bkpt(); + t[i] = ia64_get_itc() - tb; + } + for (i=0; i<10; i++) { + printk("ZZZ NULL 0x%lx\n", t[i]); + } + for (i=0; i<10; i++) { + tb = debug3+ia64_get_itc(); + ia64_pal_call_static(PAL_MC_DRAIN, 0, 0, 0, 0); + t[i] = ia64_get_itc() - tb; } + for (i=0; i<10; i++) { + printk("ZZZ DRAIN 0x%lx\n", t[i]); + } + } + if (test == 22) { + extern void machine_restart(char*); + printk("ZZZ machine_restart\n"); + machine_restart(0); } + if (test == 23) { + printk("ZZZ ia64_pal_halt_light\n"); + ia64_pal_halt_light(); + } + if (repeat) + goto again; + } diff -Nur linux-2.4.19/arch/ia64/sn/kernel/probe.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/probe.c --- linux-2.4.19/arch/ia64/sn/kernel/probe.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/probe.c Mon Dec 30 14:16:56 2002 @@ -1,7 +1,7 @@ /* * Platform dependent support for IO probing. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff -Nur linux-2.4.19/arch/ia64/sn/kernel/setup.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/setup.c --- linux-2.4.19/arch/ia64/sn/kernel/setup.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/setup.c Fri Feb 14 13:25:16 2003 @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -47,14 +47,14 @@ #include #include #include +#include +#include +#include #include #include #include #include -#ifdef CONFIG_IA64_MCA -#include -#endif #include #include #include @@ -68,15 +68,21 @@ #include #include #include +#include #ifdef CONFIG_IA64_SGI_SN2 #include #endif -extern void bte_init_node (nodepda_t *, cnodeid_t, char **); +extern void bte_init_node (nodepda_t *, cnodeid_t); extern void bte_init_cpu (void); -long sn_rtc_cycles_per_second; +unsigned long sn_rtc_cycles_per_second; +unsigned long sn_rtc_usec_per_cyc; + +partid_t sn_partid = -1; +char sn_system_serial_number_string[128]; +u64 sn_partition_serial_number; /* * This is the address of the RRegs in the HSpace of the global @@ -149,10 +155,43 @@ * for bringup, it's only called if %BRINGUP and %CONFIG_IA64_EARLY_PRINTK * are turned on. See start_kernel() in init/main.c. */ -#if defined(CONFIG_IA64_EARLY_PRINTK) && defined(CONFIG_IA64_SGI_SN) +#if defined(CONFIG_IA64_EARLY_PRINTK) + void __init early_sn_setup(void) { + void ia64_sal_handler_init (void *entry_point, void *gpval); + efi_system_table_t *efi_systab; + efi_config_table_t *config_tables; + struct ia64_sal_systab *sal_systab; + struct ia64_sal_desc_entry_point *ep; + char *p; + int i; + + /* + * Parse enough of the SAL tables to locate the SAL entry point. Since, console + * IO on SN2 is done via SAL calls, early_printk wont work without this. + * + * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c. + * Any changes to those file may have to be made hereas well. + */ + efi_systab = (efi_system_table_t*)__va(ia64_boot_param->efi_systab); + config_tables = __va(efi_systab->tables); + for (i = 0; i < efi_systab->nr_tables; i++) { + if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) { + sal_systab = __va(config_tables[i].table); + p = (char*)(sal_systab+1); + for (i = 0; i < sal_systab->entry_count; i++) { + if (*p == SAL_DESC_ENTRY_POINT) { + ep = (struct ia64_sal_desc_entry_point *) p; + ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp)); + break; + } + p += SAL_DESC_SIZE(*p); + } + } + } + if ( IS_RUNNING_ON_SIMULATOR() ) { #if defined(CONFIG_IA64_SGI_SN1) master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); @@ -162,18 +201,10 @@ printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); } } -#endif /* CONFIG_IA64_EARLY_PRINTK && CONFIG_IA64_SGI_SN */ +#endif /* CONFIG_IA64_SGI_SN1 */ -#ifdef NOT_YET_CONFIG_IA64_MCA -extern void ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs); -static struct irqaction mca_cpe_irqaction = { - handler: ia64_mca_cpe_int_handler, - flags: SA_INTERRUPT, - name: "cpe_hndlr" -}; -#endif #ifdef CONFIG_IA64_MCA -extern int platform_irq_list[]; +extern int platform_intr_list[]; #endif extern nasid_t master_nasid; @@ -191,22 +222,56 @@ { long status, ticks_per_sec, drift; int i; + int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); + + printk("SGI SAL version %x.%02x\n", major, minor); + + /* + * Confirm the SAL we're running on is recent enough... + */ + if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR && + minor < SN_SAL_MIN_MINOR)) { + printk(KERN_ERR "This kernel needs SGI SAL version >= " + "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR); + panic("PROM version too old\n"); + } + +#ifdef CONFIG_IA64_SGI_SN2 + { + extern void io_sh_swapper(int, int); + io_sh_swapper(get_nasid(), 0); + } +#endif master_nasid = get_nasid(); (void)get_console_nasid(); +#ifndef CONFIG_IA64_SGI_SN1 + { + extern nasid_t get_master_baseio_nasid(void); + (void)get_master_baseio_nasid(); + } +#endif status = ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, &drift); - if (status != 0 || ticks_per_sec < 100000) - printk(KERN_WARNING "unable to determine platform RTC clock frequency\n"); + if (status != 0 || ticks_per_sec < 100000) { + printk(KERN_WARNING "unable to determine platform RTC clock frequency, guessing.\n"); + /* PROM gives wrong value for clock freq. so guess */ + sn_rtc_cycles_per_second = 1000000000000UL/30000UL; + } else sn_rtc_cycles_per_second = ticks_per_sec; + +#ifdef CONFIG_IA64_SGI_SN1 + /* PROM has wrong value on SN1 */ + sn_rtc_cycles_per_second = 990177; +#endif + sn_rtc_usec_per_cyc = ((1000000UL< PAGE_SIZE) panic("overflow of cpu_data page"); + memset(pda.cnodeid_to_nasid_table, -1, sizeof(pda.cnodeid_to_nasid_table)); + for (cnode=0; cnodeactive_cpu_count == 1) nodepda->node_first_cpu = cpuid; @@ -359,9 +439,35 @@ irqpdaindr[cpuid] = alloc_bootmem_node(NODE_DATA(cpuid_to_cnodeid(cpuid)),sizeof(irqpda_t)); else irqpdaindr[cpuid] = page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL, get_order(sizeof(irqpda_t)))); + memset(irqpdaindr[cpuid], 0, sizeof(irqpda_t)); pda.p_irqpda = irqpdaindr[cpuid]; - pda.pio_write_status_addr = (volatile unsigned long *)LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) ); + + pda.pio_write_status_addr = (volatile unsigned long *) + LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) ); + pda.mem_write_status_addr = (volatile u64 *) + LOCAL_MMR_ADDR((slice < 2 ? SH_MEMORY_WRITE_STATUS_0 : SH_MEMORY_WRITE_STATUS_1 ) ); + + if (nodepda->node_first_cpu == cpuid) { + int buddy_nasid; + buddy_nasid = cnodeid_to_nasid(local_cnodeid() == numnodes-1 ? 0 : local_cnodeid()+ 1); + pda.pio_shub_war_cam_addr = (volatile unsigned long*)GLOBAL_MMR_ADDR(nasid, SH_PI_CAM_CONTROL); + } + +#ifdef BRINGUP2 + /* + * Zero out the counters used for counting MCAs + * ZZZZZ temp + */ + { + long *p; + p = (long*)LOCAL_MMR_ADDR(SH_XN_IILB_LB_CMP_ENABLE0); + *p = 0; + p = (long*)LOCAL_MMR_ADDR(SH_XN_IILB_LB_CMP_ENABLE1); + *p = 0; + } + +#endif #endif #ifdef CONFIG_IA64_SGI_SN1 @@ -401,7 +507,6 @@ return cpu; } -#if 0 /* ##jh */ /** * get_cycles - return a non-decreasing timestamp * @@ -412,4 +517,186 @@ { return GET_RTC_COUNTER(); } + +/** + * gettimeoffset - number of usecs elapsed since &xtime was last updated + * + * This function is used by do_gettimeofday() to determine the number + * of usecs that have elapsed since the last update to &xtime. On SN + * this is accomplished using the RTC built in to each Hub chip; each + * is guaranteed to be synchronized by the PROM, so a local read will + * suffice (get_cycles() does this for us). A snapshot of the RTC value + * is taken on every timer interrupt and this function more or less + * subtracts that snapshot value from the current value. + * + * Note that if a lot of processing was done during the last timer + * interrupt then &xtime may be some number of jiffies out of date. + * This function must account for that. + */ +unsigned long +gettimeoffset(void) +{ + unsigned long current_rtc_val, local_last_rtc_val; + unsigned long usec; + + local_last_rtc_val = last_rtc_val; + current_rtc_val = get_cycles(); + usec = last_itc_lost_usec; + + /* If the RTC has wrapped around, compensate */ + if (unlikely(current_rtc_val < local_last_rtc_val)) { + printk(KERN_NOTICE "RTC wrapped cpu:%d current:0x%lx last:0x%lx\n", + smp_processor_id(), current_rtc_val, + local_last_rtc_val); + current_rtc_val += RTC_MASK; + } + + usec += ((current_rtc_val - local_last_rtc_val)*sn_rtc_usec_per_cyc) >> + IA64_USEC_PER_CYC_SHIFT; + + /* + * usec is the number of microseconds into the current clock interval. Every + * clock tick, xtime is advanced by "tick" microseconds. If "usec" + * is allowed to get larger than "tick", the time value returned by gettimeofday + * will go backward. + */ + if (usec >= tick) + usec = tick-1; + + return usec; +} + +#ifdef II_PRTE_TLB_WAR +long iiprt_lock[16*64] __cacheline_aligned; /* allow for NASIDs up to 64 */ +#endif + +#ifdef BUS_INT_WAR + +#include +#include + +void ia64_handle_irq (ia64_vector vector, struct pt_regs *regs); + +static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; + +#define IRQCPU(irq) ((irq)>>8) + +void +sn_add_polled_interrupt(int irq, int interval) +{ + unsigned long flags, irq_cnt; + sn_poll_entry_t *irq_list; + + irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;; + + spin_lock_irqsave(&irq_lock, flags); + irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; + irq_list[irq_cnt].irq = irq; + irq_list[irq_cnt].interval = interval; + irq_list[irq_cnt].tick = interval; + pdacpu(IRQCPU(irq)).pda_poll_entry_count++; + spin_unlock_irqrestore(&irq_lock, flags); + + +} + +void +sn_delete_polled_interrupt(int irq) +{ + unsigned long flags, i, irq_cnt; + sn_poll_entry_t *irq_list; + + irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries; + + spin_lock_irqsave(&irq_lock, flags); + irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; + for (i=0; itick <= 0) { +#ifdef CONFIG_SHUB_1_0_SPECIFIC + irq_list->tick = irq_list->interval; +#else + irq_list->tick = sn_int_poll_ticks; +#endif + local_irq_save(flags); + ia64_handle_irq(irq_to_vector(irq_list->irq), 0); + local_irq_restore(flags); + } + } +} + +#define PROCFILENAME "sn_int_poll_ticks" + +static struct proc_dir_entry *proc_op; + + +static int +read_proc(char *buffer, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + + len += sprintf(buffer + len, "Poll hack: interval %ld ticks\n", sn_int_poll_ticks); + + if (len <= off+count) *eof = 1; + *start = buffer + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int +write_proc (struct file *file, const char *userbuf, unsigned long count, void *data) +{ + extern long atoi(char *); + char buf[80]; + + if (copy_from_user(buf, userbuf, count < sizeof(buf) ? count : sizeof(buf))) + return -EFAULT; + + sn_int_poll_ticks = atoi(buf); + + return count; +} + + +int __init +sn_poll_init(void) +{ + if ((proc_op = create_proc_entry(PROCFILENAME, 0644, NULL)) == NULL) { + printk("%s: unable to create proc entry", PROCFILENAME); + return -1; + } + proc_op->read_proc = read_proc; + proc_op->write_proc = write_proc; + return 0; +} + +module_init(sn_poll_init); #endif diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn1/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/Makefile --- linux-2.4.19/arch/ia64/sn/kernel/sn1/Makefile Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/Makefile Mon Dec 30 14:16:56 2002 @@ -1,7 +1,7 @@ # -# ia64/platform/sn/sn1/Makefile +# arch/ia64/sn/kernel/sn1/Makefile # -# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. +# Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of version 2 of the GNU General Public License @@ -40,12 +40,8 @@ .S.o: $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< -all: sn1.a - -O_TARGET = sn1.a +O_TARGET = sn1.o obj-y = cache.o error.o iomv.o synergy.o sn1_smp.o - -clean:: include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn1/cache.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/cache.c --- linux-2.4.19/arch/ia64/sn/kernel/sn1/cache.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/cache.c Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. * */ diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn1/error.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/error.c --- linux-2.4.19/arch/ia64/sn/kernel/sn1/error.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/error.c Mon Dec 30 14:16:56 2002 @@ -1,7 +1,7 @@ /* * SN1 Platform specific error Support * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn1/iomv.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/iomv.c --- linux-2.4.19/arch/ia64/sn/kernel/sn1/iomv.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/iomv.c Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn1/sn1_smp.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/sn1_smp.c --- linux-2.4.19/arch/ia64/sn/kernel/sn1/sn1_smp.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/sn1_smp.c Mon Dec 30 14:16:56 2002 @@ -1,7 +1,7 @@ /* * SN1 Platform specific SMP Support * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -59,11 +59,16 @@ * to other cpus for flushing TLB ranges. */ typedef struct { - unsigned long start; - unsigned long end; - unsigned long nbits; - unsigned int rid; - atomic_t unfinished_count; + union { + struct { + unsigned long start; + unsigned long end; + unsigned long nbits; + unsigned int rid; + atomic_t unfinished_count; + } ptc; + char pad[SMP_CACHE_BYTES]; + }; } ptc_params_t; #define NUMPTC 512 @@ -149,11 +154,11 @@ return; do { - start = ptcParams->start; + start = ptcParams->ptc.start; saved_rid = (unsigned int) ia64_get_rr(start); - end = ptcParams->end; - nbits = ptcParams->nbits; - rid = ptcParams->rid; + end = ptcParams->ptc.end; + nbits = ptcParams->ptc.nbits; + rid = ptcParams->ptc.rid; if (saved_rid != rid) { ia64_set_rr(start, (unsigned long)rid); @@ -167,7 +172,7 @@ ia64_srlz_i(); - result = atomic_dec(&ptcParams->unfinished_count); + result = atomic_dec(&ptcParams->ptc.unfinished_count); #ifdef PTCDEBUG { int i = ptcParams-&ptcParamArray[0]; @@ -256,7 +261,7 @@ /* check the current pointer to the beginning */ ptr = params; while(--ptr >= &ptcParamArray[0]) { - if (atomic_read(&ptr->unfinished_count) == 0) + if (atomic_read(&ptr->ptc.unfinished_count) == 0) break; ++backlog; } @@ -265,7 +270,7 @@ /* check the end of the array */ ptr = &ptcParamArray[NUMPTC]; while (--ptr > params) { - if (atomic_read(&ptr->unfinished_count) == 0) + if (atomic_read(&ptr->ptc.unfinished_count) == 0) break; ++backlog; } @@ -275,12 +280,12 @@ #endif /* PTCDEBUG */ /* wait for the next entry to clear...should be rare */ - if (atomic_read(&next->unfinished_count) > 0) { + if (atomic_read(&next->ptc.unfinished_count) > 0) { #ifdef PTCDEBUG ptcParamsAllBusy++; - if (atomic_read(&nextnext->unfinished_count) == 0) { - if (atomic_read(&next->unfinished_count) > 0) { + if (atomic_read(&nextnext->ptc.unfinished_count) == 0) { + if (atomic_read(&next->ptc.unfinished_count) > 0) { panic("\nnonzero next zero nextnext %lx %lx\n", (long)next, (long)nextnext); } @@ -293,16 +298,16 @@ local_irq_restore(irqflags); /* now we know it's not this cpu, so just wait */ - while (atomic_read(&next->unfinished_count) > 0) { + while (atomic_read(&next->ptc.unfinished_count) > 0) { barrier(); } } - params->start = start; - params->end = end; - params->nbits = nbits; - params->rid = (unsigned int) ia64_get_rr(start); - atomic_set(¶ms->unfinished_count, smp_num_cpus); + params->ptc.start = start; + params->ptc.end = end; + params->ptc.nbits = nbits; + params->ptc.rid = (unsigned int) ia64_get_rr(start); + atomic_set(¶ms->ptc.unfinished_count, smp_num_cpus); /* The atomic_set above can hit memory *after* the update * to ptcParamsEmpty below, which opens a timing window @@ -335,13 +340,11 @@ * shouldn't be using user TLB entries. To change this to wait * for all the flushes to complete, enable the following code. */ -#ifdef SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE +#if defined(SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE) || defined(BUS_INT_WAR) /* this code is not tested */ /* wait for the flush to complete */ - while (atomic_read(¶ms.unfinished_count) > 1) + while (atomic_read(¶ms->ptc.unfinished_count) > 0) barrier(); - - atomic_set(¶ms->unfinished_count, 0); #endif } @@ -369,18 +372,17 @@ static int off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088}; +#ifdef BUS_INT_WAR + if (vector != ap_wakeup_vector) { + return; + } +#endif + nasid = cpu_physical_id_to_nasid(physid); slice = cpu_physical_id_to_slice(physid); p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]); -#if defined(ZZZBRINGUP) - { - static int count=0; - if (count++ < 10) printk("ZZ sendIPI 0x%x vec %d, nasid 0x%lx, slice %ld, adr 0x%lx\n", - smp_processor_id(), vector, nasid, slice, (long)p); - } -#endif mb(); *p = (delivery_mode << 8) | (vector & 0xff); } diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn1/synergy.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/synergy.c --- linux-2.4.19/arch/ia64/sn/kernel/sn1/synergy.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn1/synergy.c Mon Dec 30 14:16:56 2002 @@ -1,7 +1,7 @@ /* * SN1 Platform specific synergy Support * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -240,6 +240,7 @@ synergy_perf_t *p; int checked = 0; int err = 0; + unsigned long flags; /* bit 45 is enable */ modesel |= (1UL << 45); @@ -279,7 +280,7 @@ memset(p, 0, sizeof(synergy_perf_t)); p->modesel = modesel; - spin_lock_irq(&npdap->synergy_perf_lock); + spin_lock_irqsave(&npdap->synergy_perf_lock, flags); if (npdap->synergy_perf_data == NULL) { /* circular list */ p->next = p; @@ -290,7 +291,7 @@ p->next = npdap->synergy_perf_data->next; npdap->synergy_perf_data->next = p; } - spin_unlock_irq(&npdap->synergy_perf_lock); + spin_unlock_irqrestore(&npdap->synergy_perf_lock, flags); } } diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn2/Makefile linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/Makefile --- linux-2.4.19/arch/ia64/sn/kernel/sn2/Makefile Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/Makefile Mon Dec 30 14:16:56 2002 @@ -1,7 +1,7 @@ # -# ia64/platform/sn/sn1/Makefile +# arch/ia64/sn/kernel/sn2/Makefile # -# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. +# Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of version 2 of the GNU General Public License @@ -40,12 +40,8 @@ .S.o: $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< -all: sn2.a +O_TARGET = sn2.o -O_TARGET = sn2.a - -obj-y = cache.o iomv.o sn2_smp.o - -clean:: +obj-y = cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn2/cache.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/cache.c --- linux-2.4.19/arch/ia64/sn/kernel/sn2/cache.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/cache.c Wed Jan 1 14:28:41 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. * */ @@ -24,6 +24,8 @@ sn_flush_all_caches(long flush_addr, long bytes) { flush_icache_range(flush_addr, flush_addr+bytes); + flush_icache_range(flush_addr, flush_addr+bytes); + mb(); } diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn2/iomv.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/iomv.c --- linux-2.4.19/arch/ia64/sn/kernel/sn2/iomv.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/iomv.c Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -56,10 +56,13 @@ * a chipset register to ensure ordering. * * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear. + * See PV 871084 for details about the WAR about zero value. + * */ void sn2_mmiob (void) { - while ( !((volatile unsigned long) (*pda.pio_write_status_addr)) & 0x8000000000000000) - udelay(5); + while ((((volatile unsigned long) (*pda.pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != + SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) + udelay(1); } diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn2/ptc_deadlock.S linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/ptc_deadlock.S --- linux-2.4.19/arch/ia64/sn/kernel/sn2/ptc_deadlock.S Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/ptc_deadlock.S Mon Dec 30 14:16:56 2002 @@ -0,0 +1,82 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include + +#define ZEROVAL 0x3f // "zero" value for outstanding PIO requests +#define DEADLOCKBIT SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_SHFT +#define WRITECOUNT SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_SHFT +#define ALIAS_OFFSET (SH_PIO_WRITE_STATUS_0_ALIAS-SH_PIO_WRITE_STATUS_0) + + + .global sn2_ptc_deadlock_recovery_core + .proc sn2_ptc_deadlock_recovery_core + +sn2_ptc_deadlock_recovery_core: + .regstk 5,0,0,0 + + ptc0 = in0 + data0 = in1 + ptc1 = in2 + data1 = in3 + piowc = in4 + piowcphy = r30 + psrsave = r2 + zeroval = r3 + scr1 = r16 + scr2 = r17 + + + extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address + dep piowcphy=-1,piowcphy,63,1 + + mov zeroval=ZEROVAL // "zero" value for PIO write count + +1: + add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register + mov scr1=7;; // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR + st8.rel [scr2]=scr1;; + +5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete. + extr.u scr2=scr1,WRITECOUNT,7;;// PIO count + cmp.ne p6,p0=zeroval,scr2 +(p6) br.cond.sptk 5b + + + + ////////////// BEGIN PHYSICAL MODE //////////////////// + mov psrsave=psr // Disable IC (no PMIs) + rsm psr.i | psr.dt | psr.ic;; + srlz.i;; + + st8.rel [ptc0]=data0 // Write PTC0 & wait for completion. + +5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. + extr.u scr2=scr1,WRITECOUNT,7;;// PIO count + cmp.ne p6,p0=zeroval,scr2 +(p6) br.cond.sptk 5b;; + + tbit.nz p8,p7=scr1,DEADLOCKBIT;;// Test for DEADLOCK + +(p7) st8.rel [ptc1]=data1;; // Now write PTC1. + +5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. + extr.u scr2=scr1,WRITECOUNT,7;;// PIO count + cmp.ne p6,p0=zeroval,scr2 +(p6) br.cond.sptk 5b + + tbit.nz p8,p0=scr1,DEADLOCKBIT;;// Test for DEADLOCK + + mov psr.l=psrsave;; // Reenable IC + srlz.i;; + ////////////// END PHYSICAL MODE //////////////////// + +(p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred. + + br.ret.sptk rp + .endp sn2_ptc_deadlock_recovery_core diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn2/sn2_smp.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/sn2_smp.c --- linux-2.4.19/arch/ia64/sn/kernel/sn2/sn2_smp.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn2/sn2_smp.c Fri Jan 3 14:08:18 2003 @@ -1,7 +1,7 @@ /* * SN2 Platform specific SMP Support * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,32 @@ #include #include #include +#include +#include + +void sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1); + + +static spinlock_t sn2_global_ptc_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; + +static unsigned long sn2_ptc_deadlock_count; + + +static inline unsigned long +wait_piowc(void) +{ + volatile unsigned long *piows; + unsigned long ws; + + piows = pda.pio_write_status_addr; + do { + __asm__ __volatile__ ("mf.a" ::: "memory"); + } while (((ws = *piows) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != + SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK); + return ws; +} + + /** * sn2_global_tlb_purge - globally purge translation cache of virtual address range @@ -63,42 +90,83 @@ * Purges the translation caches of all processors of the given virtual address * range. */ + void sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) { - int cnode, nasid; - volatile long *ptc0, *ptc1, *piows; - unsigned long ws, next, data0, data1; + int cnode, mycnode, nasid; + volatile unsigned long *ptc0, *ptc1; + unsigned long flags=0, data0, data1; - piows = (long*)LOCAL_MMR_ADDR(get_slice() ? SH_PIO_WRITE_STATUS_1 : SH_PIO_WRITE_STATUS_0); data0 = (1UL<>8)< + +#ifdef CONFIG_PROC_FS +#include +#include + + +static int partition_id_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { + + return sprintf(page, "%d\n", sn_local_partid()); +} + +struct proc_dir_entry * sgi_proc_dir = NULL; + +void +register_sn_partition_id(void) { + struct proc_dir_entry *entry; + + if (!sgi_proc_dir) { + sgi_proc_dir = proc_mkdir("sgi_sn", 0); + } + entry = create_proc_entry("partition_id", 0444, sgi_proc_dir); + if (entry) { + entry->nlink = 1; + entry->data = 0; + entry->read_proc = partition_id_read_proc; + entry->write_proc = NULL; + } +} + +static int +system_serial_number_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { + return sprintf(page, "%s\n", sn_system_serial_number()); +} + +static int +licenseID_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { + return sprintf(page, "0x%lx\n",sn_partition_serial_number_val()); +} + +void +register_sn_serial_numbers(void) { + struct proc_dir_entry *entry; + + if (!sgi_proc_dir) { + sgi_proc_dir = proc_mkdir("sgi_sn", 0); + } + entry = create_proc_entry("system_serial_number", 0444, sgi_proc_dir); + if (entry) { + entry->nlink = 1; + entry->data = 0; + entry->read_proc = system_serial_number_read_proc; + entry->write_proc = NULL; + } + entry = create_proc_entry("licenseID", 0444, sgi_proc_dir); + if (entry) { + entry->nlink = 1; + entry->data = 0; + entry->read_proc = licenseID_read_proc; + entry->write_proc = NULL; + } +} + +// Disable forced interrupts, but leave the code in, just in case. +int sn_force_interrupt_flag = 0; + +static int +sn_force_interrupt_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { + if (sn_force_interrupt_flag) { + return sprintf(page, "Force interrupt is enabled\n"); + } + return sprintf(page, "Force interrupt is disabled\n"); +} + +static int +sn_force_interrupt_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + if (*buffer == '0') { + sn_force_interrupt_flag = 0; + } else { + sn_force_interrupt_flag = 1; + } + return 1; +} + +void +register_sn_force_interrupt(void) { + struct proc_dir_entry *entry; + + if (!sgi_proc_dir) { + sgi_proc_dir = proc_mkdir("sgi_sn", 0); + } + entry = create_proc_entry("sn_force_interrupt",0444, sgi_proc_dir); + if (entry) { + entry->nlink = 1; + entry->data = 0; + entry->read_proc = sn_force_interrupt_read_proc; + entry->write_proc = sn_force_interrupt_write_proc; + } +} +void +register_sn_procfs(void) { + register_sn_partition_id(); + register_sn_serial_numbers(); + register_sn_force_interrupt(); +} + +#endif /* CONFIG_PROC_FS */ diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn_asm.S linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn_asm.S --- linux-2.4.19/arch/ia64/sn/kernel/sn_asm.S Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn_asm.S Mon Dec 30 14:16:56 2002 @@ -1,6 +1,33 @@ - /* - * Copyright (c) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ #include @@ -8,9 +35,10 @@ // Testing only. // Routine will cause MCAs -// zzzmsa(n) +// zzzmca(n) // n=0 MCA via duplicate TLB dropin -// n=0 MCA via read of garbage address +// n=1 MCA via read of garbage address +// n=2 MCA via lfetch read of garbage address // #define ITIR(key, ps) ((key<<8) | (ps<<2)) @@ -45,20 +73,30 @@ rsm 0x2000;; srlz.d; - mov r11 = 1 + mov r11 = 5 mov r3 = ITIR(0,TLB_PAGESIZE);; mov cr.itir = r3 mov r10 = 0;; itr.d dtr[r11] = r10;; - mov r11 = 2 + mov r11 = 6 itr.d dtr[r11] = r10;; br 9f -1: movl r8=0xfe00000048;; - ld8 r9=[r8];; +1: + cmp.eq p6,p7=1,r32 +#ifdef CONFIG_IA64_SGI_SN1 + movl r8=0xe00000fe00000048;; +#else + movl r8=0xe0007fb000000048;; +#endif + (p6) ld8 r9=[r8] + (p7) lfetch.fault.nt2 [r8] + ;; mf + ;; mf.a + ;; srlz.d 9: mov ar.pfs=loc4 @@ -66,83 +104,4 @@ .endp zzzmca - .global zzzspec - .proc zzzspec -zzzspec: - mov r8=r32 - movl r9=0xe000000000000000 - movl r10=0x4000;; - ld8.s r16=[r8];; - ld8.s r17=[r9];; - add r8=r8,r10;; - ld8.s r18=[r8];; - add r8=r8,r10;; - ld8.s r19=[r8];; - add r8=r8,r10;; - ld8.s r20=[r8];; - mov r8=r0 - tnat.nz p6,p0=r16 - tnat.nz p7,p0=r17 - tnat.nz p8,p0=r18 - tnat.nz p9,p0=r19 - tnat.nz p10,p0=r20;; - (p6) dep r8=-1,r8,0,1;; - (p7) dep r8=-1,r8,1,1;; - (p8) dep r8=-1,r8,2,1;; - (p9) dep r8=-1,r8,3,1;; - (p10) dep r8=-1,r8,4,1;; - br.ret.sptk rp - .endp zzzspec - - .global zzzspec2 - .proc zzzspec2 -zzzspec2: - cmp.eq p6,p7=r2,r2 - movl r16=0xc0000a0001000020 - ;; - mf - ;; - ld8 r9=[r16] - (p6) br.spnt 1f - ld8 r10=[r32] - ;; - 1: mf.a - mf - - ld8 r9=[r16];; - cmp.ne p6,p7=r9,r16 - (p6) br.spnt 1f - ld8 r10=[r32] - ;; - 1: mf.a - mf - - ld8 r9=[r33];; - cmp.ne p6,p7=r9,r33 - (p6) br.spnt 1f - ld8 r10=[r32] - ;; - 1: mf.a - mf - - tpa r23=r32 - add r20=512,r33 - add r21=1024,r33;; - ld8 r9=[r20] - ld8 r10=[r21];; - nop.i 0 - { .mib - nop.m 0 - cmp.ne p6,p7=r10,r33 - (p6) br.spnt 1f - } - ld8 r10=[r32] - ;; - 1: mf.a - mf - br.ret.sptk rp - - .endp zzzspec - #endif - diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sn_ksyms.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn_ksyms.c --- linux-2.4.19/arch/ia64/sn/kernel/sn_ksyms.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sn_ksyms.c Tue Jan 14 10:15:52 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -17,15 +17,6 @@ #include #include -/* - * other stuff (more to be added later, cleanup then) - */ -EXPORT_SYMBOL(sn_pci_map_sg); -EXPORT_SYMBOL(sn_pci_unmap_sg); -EXPORT_SYMBOL(sn_pci_alloc_consistent); -EXPORT_SYMBOL(sn_pci_free_consistent); -EXPORT_SYMBOL(sn_dma_address); - #include #include extern devfs_handle_t base_io_scsi_ctlr_vhdl[]; @@ -53,6 +44,7 @@ EXPORT_SYMBOL(hwgraph_edge_add); EXPORT_SYMBOL(pciio_info_master_get); EXPORT_SYMBOL(pciio_info_get); + #ifdef CONFIG_IA64_SGI_SN_DEBUG EXPORT_SYMBOL(__pa_debug); EXPORT_SYMBOL(__va_debug); @@ -61,7 +53,36 @@ /* Support IPIs for loaded modules. */ EXPORT_SYMBOL(sn_send_IPI_phys); +/* symbols referenced by partitioning modules */ +#include +EXPORT_SYMBOL(bte_unaligned_copy); +#include +EXPORT_SYMBOL(ia64_sal); + +#ifdef CONFIG_IA64_SGI_SN2 +#include +EXPORT_SYMBOL(sal_lock); +EXPORT_SYMBOL(sn_partid); +EXPORT_SYMBOL(sn_local_partid); +EXPORT_SYMBOL(sn_system_serial_number_string); +EXPORT_SYMBOL(sn_partition_serial_number); + +EXPORT_SYMBOL(sn2_mmiob); +#endif + +/* added by tduffy 04.08.01 to fix depmod issues */ #include -EXPORT_SYMBOL(sn_pci_unmap_single); -EXPORT_SYMBOL(sn_pci_map_single); -EXPORT_SYMBOL(sn_pci_dma_sync_single); + +#ifdef BUS_INT_WAR +extern void sn_add_polled_interrupt(int, int); +extern void sn_delete_polled_interrupt(int); +EXPORT_SYMBOL(sn_add_polled_interrupt); +EXPORT_SYMBOL(sn_delete_polled_interrupt); +#endif + +extern nasid_t master_nasid; +EXPORT_SYMBOL(master_nasid); + +EXPORT_SYMBOL(sn_flush_all_caches); +#include +EXPORT_SYMBOL(bte_copy); diff -Nur linux-2.4.19/arch/ia64/sn/kernel/sv.c linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sv.c --- linux-2.4.19/arch/ia64/sn/kernel/sv.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/kernel/sv.c Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This implemenation of synchronization variables is heavily based on * one done by Steve Lord diff -Nur linux-2.4.19/arch/ia64/sn/tools/make_textsym linux-2.4.19-sgi211r3/arch/ia64/sn/tools/make_textsym --- linux-2.4.19/arch/ia64/sn/tools/make_textsym Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ia64/sn/tools/make_textsym Mon Dec 30 14:16:56 2002 @@ -7,7 +7,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. +# Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. # help() { @@ -44,7 +44,7 @@ [ -f $VMLINUX ] || help -$OBJDUMP -t $LINUX | sort > $TMPSYM +$OBJDUMP -t $LINUX | egrep -v '__ks' | sort > $TMPSYM SN1=`egrep "dig_setup|Synergy_da_indr" $TMPSYM|wc -l` # Dataprefix and textprefix correspond to the VGLOBAL_BASE and VPERNODE_BASE. @@ -58,74 +58,74 @@ # pipe everything thru sort echo "TEXTSYM V1.0" (cat < +#include #include #include +#include OUTPUT_FORMAT("elf64-ia64-little") OUTPUT_ARCH(ia64) ENTRY(phys_start) + +PHDRS +{ + headers PT_PHDR PHDRS; + pernode PT_LOAD; + global PT_LOAD; +} + +#define PERNODEADDR(section) KERNPHYSBASE + ADDR(section) - VPERNODE_BASE +#define GLOBALADDR(section) KERNPHYSBASE + ADDR(section) - VGLOBAL_BASE + SECTIONS { /* Sections to be discarded */ @@ -13,36 +26,91 @@ *(.text.exit) *(.data.exit) *(.exitcall.exit) + *(.kdb_exitcall.exit) *(.IA_64.unwind.text.exit) *(.IA_64.unwind_info.text.exit) } v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ - phys_start = _start - PAGE_OFFSET; + phys_start = KERNPHYSBASE + _start - VPERNODE_BASE; - . = KERNEL_START; + . = VPERNODE_BASE; _text = .; _stext = .; - .text : AT(ADDR(.text) - PAGE_OFFSET) + .text : AT(PERNODEADDR(.text)) { *(.text.ivt) - /* these are not really text pages, but they need to be page aligned: */ - *(__special_page_section) + . = ALIGN(PAGE_SIZE); __start_gate_section = .; *(.text.gate) __stop_gate_section = .; *(.text) - } - .text2 : AT(ADDR(.text2) - PAGE_OFFSET) - { *(.text2) } + } :pernode + .text2 : AT(PERNODEADDR(.text2)) + { *(.text2) } :pernode #ifdef CONFIG_SMP - .text.lock : AT(ADDR(.text.lock) - PAGE_OFFSET) - { *(.text.lock) } + .text.lock : AT(PERNODEADDR(.text.lock)) + { *(.text.lock) } :pernode #endif _etext = .; /* Read-only data */ + .rodata : AT(PERNODEADDR(.rodata)) + { *(.rodata) *(.rodata.*) } :pernode + + /* Unwind info & table: */ + . = ALIGN(8); + .IA_64.unwind_info : AT(PERNODEADDR(.IA_64.unwind_info)) + { *(.IA_64.unwind_info*) } + . = ALIGN(8); + ia64_unw_start = .; + .IA_64.unwind : AT(PERNODEADDR(.IA_64.unwind)) + { *(.IA_64.unwind*) } + ia64_unw_end = .; + . = ALIGN(16); + + /* Initialization code (must be last in :pernode area) */ + + . = ALIGN(PAGE_SIZE); + __init_begin = .; + .text.init : AT(PERNODEADDR(.text.init)) + { *(.text.init) } :pernode + + __init_etext = .; + /* Jump virtual address from pernode to global area */ + . = VGLOBAL_BASE + (. - VPERNODE_BASE); + __init_sdata = .; + + /* Initialization data (must be first in :global area) */ + + .data.init : AT(GLOBALADDR(.data.init)) + { *(.data.init) } :global + . = ALIGN(16); + __setup_start = .; + .setup.init : AT(GLOBALADDR(.setup.init)) + { *(.setup.init) } + __setup_end = .; + __kdb_initcall_start = .; + .kdb_initcall.init : AT(GLOBALADDR(.kdb_initcall.init)) + { *(.kdb_initcall.init) } + __kdb_initcall_end = .; + __initcall_start = .; + .initcall.init : AT(GLOBALADDR(.initcall.init)) + { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(PAGE_SIZE); + __init_end = .; + + /* The initial task and kernel stack */ + init_task : AT(GLOBALADDR(init_task)) + { *(init_task) } + + .data.page_aligned : AT(GLOBALADDR(.data.page_aligned)) + { + *(.data.idt) + *(__special_page_section) + } __gp = ALIGN(16) + 0x200000; /* gp must be 16-byte aligned for exc. table */ @@ -52,98 +120,59 @@ /* Exception table */ . = ALIGN(16); __start___ex_table = .; - __ex_table : AT(ADDR(__ex_table) - PAGE_OFFSET) - { *(__ex_table) } + __ex_table : AT(GLOBALADDR(__ex_table)) + { *(__ex_table) } :global __stop___ex_table = .; #if defined(CONFIG_IA64_GENERIC) /* Machine Vector */ . = ALIGN(16); machvec_start = .; - .machvec : AT(ADDR(.machvec) - PAGE_OFFSET) + .machvec : AT(GLOBALADDR(.machvec)) { *(.machvec) } machvec_end = .; #endif __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : AT(ADDR(__ksymtab) - PAGE_OFFSET) + __ksymtab : AT(GLOBALADDR(__ksymtab)) { *(__ksymtab) } __stop___ksymtab = .; __start___kallsyms = .; /* All kernel symbols for debugging */ - __kallsyms : AT(ADDR(__kallsyms) - PAGE_OFFSET) + __kallsyms : AT(GLOBALADDR(__kallsyms)) { *(__kallsyms) } __stop___kallsyms = .; - /* Unwind info & table: */ - . = ALIGN(8); - .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) - { *(.IA_64.unwind_info*) } - ia64_unw_start = .; - .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET) - { *(.IA_64.unwind*) } - ia64_unw_end = .; - - .rodata : AT(ADDR(.rodata) - PAGE_OFFSET) - { *(.rodata) *(.rodata.*) } - .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET) + .kstrtab : AT(GLOBALADDR(.kstrtab)) { *(.kstrtab) } - .opd : AT(ADDR(.opd) - PAGE_OFFSET) + .opd : AT(GLOBALADDR(.opd)) { *(.opd) } - /* Initialization code and data: */ - - . = ALIGN(PAGE_SIZE); - __init_begin = .; - .text.init : AT(ADDR(.text.init) - PAGE_OFFSET) - { *(.text.init) } - - .data.init : AT(ADDR(.data.init) - PAGE_OFFSET) - { *(.data.init) } - . = ALIGN(16); - __setup_start = .; - .setup.init : AT(ADDR(.setup.init) - PAGE_OFFSET) - { *(.setup.init) } - __setup_end = .; - __initcall_start = .; - .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET) - { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(PAGE_SIZE); - __init_end = .; - - /* The initial task and kernel stack */ - init_task : AT(ADDR(init_task) - PAGE_OFFSET) - { *(init_task) } - - .data.page_aligned : AT(ADDR(.data.page_aligned) - PAGE_OFFSET) - { *(.data.idt) } - - . = ALIGN(64); - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - PAGE_OFFSET) + . = ALIGN(L1_CACHE_BYTES); + .data.cacheline_aligned : AT(GLOBALADDR(.data.cacheline_aligned)) { *(.data.cacheline_aligned) } /* Kernel symbol names for modules: */ - .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET) + .kstrtab : AT(GLOBALADDR(.kstrtab)) { *(.kstrtab) } - .data : AT(ADDR(.data) - PAGE_OFFSET) + .data : AT(GLOBALADDR(.data)) { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } - .got : AT(ADDR(.got) - PAGE_OFFSET) + .got : AT(GLOBALADDR(.got)) { *(.got.plt) *(.got) } /* 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 : AT(ADDR(.sdata) - PAGE_OFFSET) + .sdata : AT(GLOBALADDR(.sdata)) { *(.sdata) } _edata = .; _bss = .; - .sbss : AT(ADDR(.sbss) - PAGE_OFFSET) + .sbss : AT(GLOBALADDR(.sbss)) { *(.sbss) *(.scommon) } - .bss : AT(ADDR(.bss) - PAGE_OFFSET) + .bss : AT(GLOBALADDR(.bss)) { *(.bss) *(COMMON) } - . = ALIGN(64 / 8); + . = ALIGN(L1_CACHE_BYTES / 8); _end = .; /* Stabs debugging sections. */ diff -Nur linux-2.4.19/arch/m68k/defconfig linux-2.4.19-sgi211r3/arch/m68k/defconfig --- linux-2.4.19/arch/m68k/defconfig Mon Jun 19 12:56:08 2000 +++ linux-2.4.19-sgi211r3/arch/m68k/defconfig Wed Jan 30 16:28:11 2002 @@ -327,3 +327,13 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/mips/defconfig linux-2.4.19-sgi211r3/arch/mips/defconfig --- linux-2.4.19/arch/mips/defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/mips/defconfig Wed Oct 16 14:02:58 2002 @@ -601,3 +601,13 @@ # CONFIG_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/mips64/defconfig linux-2.4.19-sgi211r3/arch/mips64/defconfig --- linux-2.4.19/arch/mips64/defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/mips64/defconfig Wed Oct 16 14:02:58 2002 @@ -525,3 +525,13 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/parisc/defconfig linux-2.4.19-sgi211r3/arch/parisc/defconfig --- linux-2.4.19/arch/parisc/defconfig Tue Dec 5 12:29:39 2000 +++ linux-2.4.19-sgi211r3/arch/parisc/defconfig Wed Jan 30 16:28:11 2002 @@ -361,3 +361,13 @@ # Kernel hacking # CONFIG_MAGIC_SYSRQ=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/ppc/configs/IVMS8_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/IVMS8_defconfig --- linux-2.4.19/arch/ppc/configs/IVMS8_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/IVMS8_defconfig Wed Oct 16 14:02:58 2002 @@ -632,3 +632,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/SM850_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/SM850_defconfig --- linux-2.4.19/arch/ppc/configs/SM850_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/SM850_defconfig Wed Oct 16 14:02:58 2002 @@ -594,3 +594,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/SPD823TS_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/SPD823TS_defconfig --- linux-2.4.19/arch/ppc/configs/SPD823TS_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/SPD823TS_defconfig Wed Oct 16 14:02:58 2002 @@ -593,3 +593,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/TQM823L_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/TQM823L_defconfig --- linux-2.4.19/arch/ppc/configs/TQM823L_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/TQM823L_defconfig Wed Oct 16 14:02:58 2002 @@ -594,3 +594,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/TQM850L_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/TQM850L_defconfig --- linux-2.4.19/arch/ppc/configs/TQM850L_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/TQM850L_defconfig Wed Oct 16 14:02:58 2002 @@ -594,3 +594,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/TQM860L_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/TQM860L_defconfig --- linux-2.4.19/arch/ppc/configs/TQM860L_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/TQM860L_defconfig Wed Oct 16 14:02:58 2002 @@ -641,3 +641,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/apus_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/apus_defconfig --- linux-2.4.19/arch/ppc/configs/apus_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/apus_defconfig Wed Oct 16 14:02:58 2002 @@ -974,3 +974,12 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/bseip_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/bseip_defconfig --- linux-2.4.19/arch/ppc/configs/bseip_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/bseip_defconfig Wed Oct 16 14:02:58 2002 @@ -593,3 +593,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/common_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/common_defconfig --- linux-2.4.19/arch/ppc/configs/common_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/common_defconfig Wed Oct 16 14:02:58 2002 @@ -993,3 +993,12 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/est8260_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/est8260_defconfig --- linux-2.4.19/arch/ppc/configs/est8260_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/est8260_defconfig Wed Oct 16 14:02:58 2002 @@ -564,3 +564,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/gemini_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/gemini_defconfig --- linux-2.4.19/arch/ppc/configs/gemini_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/gemini_defconfig Wed Oct 16 14:02:58 2002 @@ -649,3 +649,12 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/ibmchrp_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/ibmchrp_defconfig --- linux-2.4.19/arch/ppc/configs/ibmchrp_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/ibmchrp_defconfig Wed Oct 16 14:02:58 2002 @@ -838,3 +838,12 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/mbx_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/mbx_defconfig --- linux-2.4.19/arch/ppc/configs/mbx_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/mbx_defconfig Wed Oct 16 14:02:58 2002 @@ -589,3 +589,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/oak_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/oak_defconfig --- linux-2.4.19/arch/ppc/configs/oak_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/oak_defconfig Wed Oct 16 14:02:58 2002 @@ -546,3 +546,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/power3_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/power3_defconfig --- linux-2.4.19/arch/ppc/configs/power3_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/power3_defconfig Wed Oct 16 14:02:58 2002 @@ -858,3 +858,12 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/rpxcllf_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/rpxcllf_defconfig --- linux-2.4.19/arch/ppc/configs/rpxcllf_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/rpxcllf_defconfig Wed Oct 16 14:02:58 2002 @@ -594,3 +594,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/rpxlite_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/rpxlite_defconfig --- linux-2.4.19/arch/ppc/configs/rpxlite_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/rpxlite_defconfig Wed Oct 16 14:02:58 2002 @@ -591,3 +591,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/configs/walnut_defconfig linux-2.4.19-sgi211r3/arch/ppc/configs/walnut_defconfig --- linux-2.4.19/arch/ppc/configs/walnut_defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/configs/walnut_defconfig Wed Oct 16 14:02:58 2002 @@ -550,3 +550,12 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_DMAPI=y diff -Nur linux-2.4.19/arch/ppc/defconfig linux-2.4.19-sgi211r3/arch/ppc/defconfig --- linux-2.4.19/arch/ppc/defconfig Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-sgi211r3/arch/ppc/defconfig Fri Apr 26 11:07:18 2002 @@ -978,3 +978,13 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/ppc/kernel/ppc_htab.c linux-2.4.19-sgi211r3/arch/ppc/kernel/ppc_htab.c --- linux-2.4.19/arch/ppc/kernel/ppc_htab.c Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-sgi211r3/arch/ppc/kernel/ppc_htab.c Mon Oct 28 20:43:23 2002 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -430,18 +431,20 @@ static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig) { + long long ret = -EINVAL; + + lock_kernel(); switch (orig) { case 0: file->f_pos = offset; - return(file->f_pos); + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return(file->f_pos); - case 2: - return(-EINVAL); - default: - return(-EINVAL); + ret = file->f_pos; } + unlock_kernel(); + return ret; } int proc_dol2crvec(ctl_table *table, int write, struct file *filp, diff -Nur linux-2.4.19/arch/ppc/mm/fault.c linux-2.4.19-sgi211r3/arch/ppc/mm/fault.c --- linux-2.4.19/arch/ppc/mm/fault.c Tue Oct 2 09:12:44 2001 +++ linux-2.4.19-sgi211r3/arch/ppc/mm/fault.c Mon Oct 28 20:43:23 2002 @@ -197,8 +197,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -Nur linux-2.4.19/arch/s390/defconfig linux-2.4.19-sgi211r3/arch/s390/defconfig --- linux-2.4.19/arch/s390/defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/s390/defconfig Wed Oct 16 14:02:58 2002 @@ -268,3 +268,13 @@ # Kernel hacking # CONFIG_MAGIC_SYSRQ=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/s390/mm/fault.c linux-2.4.19-sgi211r3/arch/s390/mm/fault.c --- linux-2.4.19/arch/s390/mm/fault.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/s390/mm/fault.c Mon Oct 28 20:43:23 2002 @@ -293,8 +293,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -Nur linux-2.4.19/arch/s390x/defconfig linux-2.4.19-sgi211r3/arch/s390x/defconfig --- linux-2.4.19/arch/s390x/defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/s390x/defconfig Wed Oct 16 14:02:58 2002 @@ -268,3 +268,13 @@ # Kernel hacking # CONFIG_MAGIC_SYSRQ=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/s390x/kernel/linux32.c linux-2.4.19-sgi211r3/arch/s390x/kernel/linux32.c --- linux-2.4.19/arch/s390x/kernel/linux32.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/s390x/kernel/linux32.c Wed Oct 16 14:02:58 2002 @@ -912,63 +912,96 @@ return sys32_fcntl(fd, cmd, arg); } -struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; - __u32 dqb_ihardlimit; - __u32 dqb_isoftlimit; - __u32 dqb_curinodes; - __kernel_time_t32 dqb_btime; - __kernel_time_t32 dqb_itime; -}; - extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); -asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) +#ifdef CONFIG_QIFACE_COMPAT +#ifdef CONFIG_QIFACE_V1 +struct user_dqblk32 { + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v1c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V1_GETQUOTA +#define Q_COMP_SETQUOTA Q_V1_SETQUOTA +#define Q_COMP_SETQLIM Q_V1_SETQLIM +#define Q_COMP_SETUSE Q_V1_SETUSE +#else +struct user_dqblk32 { + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u64 dqb_curspace; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v2c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V2_GETQUOTA +#define Q_COMP_SETQUOTA Q_V2_SETQUOTA +#define Q_COMP_SETQLIM Q_V2_SETQLIM +#define Q_COMP_SETUSE Q_V2_SETUSE +#endif + +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) { int cmds = cmd >> SUBCMDSHIFT; int err; - struct dqblk d; + comp_dqblk_t d; mm_segment_t old_fs; char *spec; switch (cmds) { - case Q_GETQUOTA: - break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) - return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; - break; + case Q_COMP_GETQUOTA: + break; + case Q_COMP_SETQUOTA: + case Q_COMP_SETUSE: + case Q_COMP_SETQLIM: + if (copy_from_user(&d, (struct user_dqblk32 *)addr, + sizeof (struct user_dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime; + break; default: - return sys_quotactl(cmd, special, - id, (caddr_t)addr); + return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr); } spec = getname (special); err = PTR_ERR(spec); if (IS_ERR(spec)) return err; - old_fs = get_fs (); + old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); + err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); set_fs (old_fs); putname (spec); if (err) return err; - if (cmds == Q_GETQUOTA) { + if (cmds == Q_COMP_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) + ((struct user_dqblk32 *)&d)->dqb_itime = i; + ((struct user_dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct user_dqblk32 *)addr, &d, + sizeof (struct user_dqblk32))) return -EFAULT; } return 0; } + +#else +/* No conversion needed for new interface */ +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) +{ + return sys_quotactl(cmd, special, id, addr); +} +#endif static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { diff -Nur linux-2.4.19/arch/s390x/mm/fault.c linux-2.4.19-sgi211r3/arch/s390x/mm/fault.c --- linux-2.4.19/arch/s390x/mm/fault.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/s390x/mm/fault.c Mon Oct 28 20:43:23 2002 @@ -293,8 +293,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -Nur linux-2.4.19/arch/sh/defconfig linux-2.4.19-sgi211r3/arch/sh/defconfig --- linux-2.4.19/arch/sh/defconfig Mon Oct 15 13:36:48 2001 +++ linux-2.4.19-sgi211r3/arch/sh/defconfig Wed Jan 30 16:28:11 2002 @@ -202,3 +202,13 @@ # CONFIG_MAGIC_SYSRQ is not set CONFIG_SH_STANDARD_BIOS=y CONFIG_SH_EARLY_PRINTK=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/sh/mm/fault.c linux-2.4.19-sgi211r3/arch/sh/mm/fault.c --- linux-2.4.19/arch/sh/mm/fault.c Mon Oct 15 13:36:48 2001 +++ linux-2.4.19-sgi211r3/arch/sh/mm/fault.c Mon Oct 28 20:43:23 2002 @@ -207,8 +207,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -Nur linux-2.4.19/arch/sparc/defconfig linux-2.4.19-sgi211r3/arch/sparc/defconfig --- linux-2.4.19/arch/sparc/defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/sparc/defconfig Wed Oct 16 14:02:58 2002 @@ -416,3 +416,13 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set + diff -Nur linux-2.4.19/arch/sparc64/defconfig linux-2.4.19-sgi211r3/arch/sparc64/defconfig --- linux-2.4.19/arch/sparc64/defconfig Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/sparc64/defconfig Wed Oct 16 14:02:58 2002 @@ -893,3 +893,12 @@ # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_DCFLUSH is not set # CONFIG_STACK_DEBUG is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_DMAPI is not set diff -Nur linux-2.4.19/arch/sparc64/kernel/sys_sparc32.c linux-2.4.19-sgi211r3/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.19/arch/sparc64/kernel/sys_sparc32.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/sparc64/kernel/sys_sparc32.c Wed Oct 16 14:02:58 2002 @@ -888,61 +888,96 @@ return sys32_fcntl(fd, cmd, arg); } -struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; - __u32 dqb_ihardlimit; - __u32 dqb_isoftlimit; - __u32 dqb_curinodes; - __kernel_time_t32 dqb_btime; - __kernel_time_t32 dqb_itime; -}; - extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); -asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) +#ifdef CONFIG_QIFACE_COMPAT +#ifdef CONFIG_QIFACE_V1 +struct user_dqblk32 { + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v1c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V1_GETQUOTA +#define Q_COMP_SETQUOTA Q_V1_SETQUOTA +#define Q_COMP_SETQLIM Q_V1_SETQLIM +#define Q_COMP_SETUSE Q_V1_SETUSE +#else +struct user_dqblk32 { + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u64 dqb_curspace; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v2c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V2_GETQUOTA +#define Q_COMP_SETQUOTA Q_V2_SETQUOTA +#define Q_COMP_SETQLIM Q_V2_SETQLIM +#define Q_COMP_SETUSE Q_V2_SETUSE +#endif + +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) { int cmds = cmd >> SUBCMDSHIFT; int err; - struct dqblk d; + comp_dqblk_t d; mm_segment_t old_fs; char *spec; switch (cmds) { - case Q_GETQUOTA: - break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) - return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; - break; + case Q_COMP_GETQUOTA: + break; + case Q_COMP_SETQUOTA: + case Q_COMP_SETUSE: + case Q_COMP_SETQLIM: + if (copy_from_user(&d, (struct user_dqblk32 *)addr, + sizeof (struct user_dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime; + break; default: - return sys_quotactl(cmd, special, - id, (caddr_t)addr); + return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr); } spec = getname (special); err = PTR_ERR(spec); if (IS_ERR(spec)) return err; - old_fs = get_fs (); + old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); + err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); set_fs (old_fs); putname (spec); - if (cmds == Q_GETQUOTA) { + if (err) + return err; + if (cmds == Q_COMP_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) + ((struct user_dqblk32 *)&d)->dqb_itime = i; + ((struct user_dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct user_dqblk32 *)addr, &d, + sizeof (struct user_dqblk32))) return -EFAULT; } - return err; + return 0; +} + +#else +/* No conversion needed for new interface */ +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) +{ + return sys_quotactl(cmd, special, id, addr); } +#endif static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { diff -Nur linux-2.4.19/arch/sparc64/kernel/systbls.S linux-2.4.19-sgi211r3/arch/sparc64/kernel/systbls.S --- linux-2.4.19/arch/sparc64/kernel/systbls.S Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/arch/sparc64/kernel/systbls.S Wed Oct 16 14:02:58 2002 @@ -194,7 +194,7 @@ .word sunos_getdirentries, sys32_statfs, sys32_fstatfs .word sys_oldumount, sunos_nosys, sunos_nosys .word sys_getdomainname, sys_setdomainname - .word sunos_nosys, sys32_quotactl, sunos_nosys + .word sunos_nosys, sys_quotactl, sunos_nosys .word sunos_mount, sys_ustat, sunos_semsys .word sunos_nosys, sunos_shmsys, sunos_audit .word sunos_nosys, sunos_getdents, sys_setsid diff -Nur linux-2.4.19/drivers/Makefile linux-2.4.19-sgi211r3/drivers/Makefile --- linux-2.4.19/drivers/Makefile Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/Makefile Thu Feb 20 19:55:58 2003 @@ -1,14 +1,14 @@ # # Makefile for the Linux kernel device drivers. # -# 15 Sep 2000, Christoph Hellwig +# 15 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi ide \ - message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ - fc4 net/hamradio i2c acpi bluetooth + message/i2o message/fusion scsi md ieee1394 pnp isdn dump atm \ + fc4 net/hamradio i2c acpi bluetooth xscsi subdir-y := parport char block net sound misc media cdrom hotplug subdir-m := $(subdir-y) @@ -30,6 +30,7 @@ subdir-$(CONFIG_PHONE) += telephony subdir-$(CONFIG_SGI) += sgi subdir-$(CONFIG_IDE) += ide +subdir-$(CONFIG_XSCSI) += xscsi subdir-$(CONFIG_SCSI) += scsi subdir-$(CONFIG_I2O) += message/i2o subdir-$(CONFIG_FUSION) += message/fusion @@ -38,7 +39,9 @@ subdir-$(CONFIG_PNP) += pnp subdir-$(CONFIG_ISDN_BOOL) += isdn subdir-$(CONFIG_ATM) += atm +subdir-$(CONFIG_DUMP) += dump subdir-$(CONFIG_FC4) += fc4 +subdir-$(CONFIG_IA64_SGI_SN) += sgi/sn # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set -- ch subdir-$(CONFIG_HAMRADIO) += net/hamradio diff -Nur linux-2.4.19/drivers/acpi/Config.help linux-2.4.19-sgi211r3/drivers/acpi/Config.help --- linux-2.4.19/drivers/acpi/Config.help Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/Config.help Tue Aug 27 19:53:13 2002 @@ -0,0 +1,93 @@ +CONFIG_ACPI_ENABLE + Advanced Configuration and Power Interface (ACPI) support for + Linux requires an ACPI compliant platform (hardware/firmware), + and assumes the presence of OS-directed configuration and power + management (OSPM) software. This option will enlarge your + kernel by about 70K. + + Linux ACPI provides a robust functional replacement for several + legacy configuration and power management intefaces, including + the Plug-and-Play BIOS specification (PnP BIOS), the + MultiProcessor Specification (MPS), and the Advanced Power + Management (APM) specification. If both ACPI and APM support + are configured, whichever is loaded first shall be used. + + Add "acpi=off" to the kernel command line to disable this feature. + (Try "man bootparam" or see the documentation of your boot loader + about how to pass options to the kernel at boot time.) + + Add "acpi=ht-only" to the kernel command line to limit ACPI + support to processor enumeration only (see CONFIG_ACPI_HT_ONLY). + + ---------- + + The ACPI SourceForge project contains the latest source code, + documentation, tools, mailing list subscription, and other + information. This project is available at: + + + Linux support for ACPI is based on Intel Corporation's ACPI + Component Architecture (ACPI CA). For more information see: + + + ACPI is an open industry specification co-developed by Compaq, + Intel, Microsoft, Phoenix, and Toshiba. The specification is + available at: + + +CONFIG_ACPI_HT_ONLY + This option enables limited ACPI support -- just enough to + enumerate processors from the ACPI Multiple APIC Description + Table (MADT). Note that ACPI supports both logical (e.g. Hyper- + Threading) and physical processors, where the MultiProcessor + Specification (MPS) table only supports physical processors. + + Full ACPI support (CONFIG_ACPI) is preferred. Use this option + only if you wish to limit ACPI's role to processor enumeration. + +CONFIG_ACPI_AC + This driver adds support for the AC Adapter object, which indicates + whether a system is on AC, or not. Typically, only mobile systems + have this object, since desktops are always on AC. + +CONFIG_ACPI_BATTERY + This driver adds support for battery information through + /proc/acpi/battery. If you have a mobile system with a battery, + say Y. + +CONFIG_ACPI_BUTTON + This driver registers for events based on buttons, such as the + power, sleep, and lid switch. In the future, a daemon will read + /proc/acpi/event and perform user-defined actions such as shutting + down the system. Until then, you can cat it, and see output when + a button is pressed. + +CONFIG_ACPI_EC + This driver is required on some systems for the proper operation of + the battery and thermal drivers. If you are compiling for a + mobile system, say Y. + +CONFIG_ACPI_PROCESSOR + This driver installs ACPI as the idle handler for Linux, and uses + ACPI C2 and C3 processor states to save power, on systems that + support it. + +CONFIG_ACPI_THERMAL + This driver adds support for ACPI thermal zones. Most mobile and + some desktop systems support ACPI thermal zones. It is HIGHLY + recommended that this option be enabled, as your processor(s) + may be damaged without it. + +CONFIG_ACPI_FAN + This driver adds support for ACPI fan devices, allowing user-mode + applications to perform basic fan control (on, off, status). + +CONFIG_ACPI_SYSTEM + This driver will enable your system to shut down using ACPI, and + dump your ACPI DSDT table using /proc/acpi/dsdt. + +CONFIG_ACPI_DEBUG + The ACPI driver can optionally report errors with a great deal + of verbosity. Saying Y enables these statements. This will increase + your kernel size by around 50K. + diff -Nur linux-2.4.19/drivers/acpi/Config.in linux-2.4.19-sgi211r3/drivers/acpi/Config.in --- linux-2.4.19/drivers/acpi/Config.in Wed Jun 20 17:47:39 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/Config.in Thu Oct 31 10:53:27 2002 @@ -1,17 +1,123 @@ # -# ACPI configuration +# ACPI Configuration # -#mainmenu_option next_comment -#comment 'ACPI Configuration' -dep_bool ' ACPI Debug Statements' CONFIG_ACPI_DEBUG $CONFIG_ACPI -dep_tristate ' ACPI Bus Manager' CONFIG_ACPI_BUSMGR $CONFIG_ACPI +if [ "$CONFIG_X86" = "y" ]; then -dep_tristate ' System' CONFIG_ACPI_SYS $CONFIG_ACPI_BUSMGR $CONFIG_ACPI -dep_tristate ' Processor' CONFIG_ACPI_CPU $CONFIG_ACPI_BUSMGR $CONFIG_ACPI -dep_tristate ' Button' CONFIG_ACPI_BUTTON $CONFIG_ACPI_BUSMGR $CONFIG_ACPI -dep_tristate ' AC Adapter' CONFIG_ACPI_AC $CONFIG_ACPI_BUSMGR $CONFIG_ACPI -dep_tristate ' Embedded Controller' CONFIG_ACPI_EC $CONFIG_ACPI_BUSMGR $CONFIG_ACPI -dep_tristate ' Control Method Battery' CONFIG_ACPI_CMBATT $CONFIG_ACPI_BUSMGR $CONFIG_ACPI $CONFIG_ACPI_EC -dep_tristate ' Thermal' CONFIG_ACPI_THERMAL $CONFIG_ACPI_BUSMGR $CONFIG_ACPI $CONFIG_ACPI_EC -#endmenu + mainmenu_option next_comment + comment 'ACPI Support' + + if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then + choice 'ACPI Support' \ + "Enable CONFIG_ACPI_ENABLE \ + HyperThreading-Only CONFIG_ACPI_HT_ONLY \ + Disable CONFIG_ACPI_DISABLE" Disable + else + choice 'ACPI Support' \ + "Enable CONFIG_ACPI_ENABLE \ + Disable CONFIG_ACPI_DISABLE" Disable + fi + + if [ "$CONFIG_ACPI_ENABLE" = "y" ]; then + define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_BOOT y + define_bool CONFIG_ACPI_BUS y + define_bool CONFIG_ACPI_INTERPRETER y + define_bool CONFIG_ACPI_EC y + define_bool CONFIG_ACPI_POWER y + if [ "$CONFIG_PCI" = "y" ]; then + define_bool CONFIG_ACPI_PCI y + fi + define_bool CONFIG_ACPI_SLEEP y + define_bool CONFIG_ACPI_SYSTEM y + tristate ' AC Adapter' CONFIG_ACPI_AC + tristate ' Battery' CONFIG_ACPI_BATTERY + tristate ' Button' CONFIG_ACPI_BUTTON + tristate ' Fan' CONFIG_ACPI_FAN + tristate ' Processor' CONFIG_ACPI_PROCESSOR + dep_tristate ' Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR + bool ' Debug Statements' CONFIG_ACPI_DEBUG + fi + + if [ "$CONFIG_ACPI_HT_ONLY" = "y" ]; then + define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_BOOT y + define_bool CONFIG_ACPI_BUS n + define_bool CONFIG_ACPI_INTERPRETER n + define_bool CONFIG_ACPI_EC n + define_bool CONFIG_ACPI_PCI n + define_bool CONFIG_ACPI_POWER n + define_bool CONFIG_ACPI_SYSTEM n + define_bool CONFIG_ACPI_SLEEP n + define_bool CONFIG_ACPI_AC n + define_bool CONFIG_ACPI_BATTERY n + define_bool CONFIG_ACPI_BUTTON n + define_bool CONFIG_ACPI_FAN n + define_bool CONFIG_ACPI_PROCESSOR n + define_bool CONFIG_ACPI_THERMAL n + define_bool CONFIG_ACPI_DEBUG n + fi + + if [ "$CONFIG_ACPI_DISABLE" = "y" ]; then + define_bool CONFIG_ACPI n + define_bool CONFIG_ACPI_BOOT n + define_bool CONFIG_ACPI_BUS n + define_bool CONFIG_ACPI_INTERPRETER n + define_bool CONFIG_ACPI_EC n + define_bool CONFIG_ACPI_PCI n + define_bool CONFIG_ACPI_POWER n + define_bool CONFIG_ACPI_SYSTEM n + define_bool CONFIG_ACPI_SLEEP n + define_bool CONFIG_ACPI_AC n + define_bool CONFIG_ACPI_BATTERY n + define_bool CONFIG_ACPI_BUTTON n + define_bool CONFIG_ACPI_FAN n + define_bool CONFIG_ACPI_PROCESSOR n + define_bool CONFIG_ACPI_THERMAL n + define_bool CONFIG_ACPI_DEBUG n + fi + + endmenu + +fi + + +if [ "$CONFIG_IA64" = "y" ]; then + + if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + mainmenu_option next_comment + comment 'ACPI Support' + if [ "$CONFIG_IA64_SGI_SN" = "y" ]; then + define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_EFI y + define_bool CONFIG_ACPI_BOOT y + define_bool CONFIG_ACPI_BUS n + define_bool CONFIG_ACPI_INTERPRETER n + define_bool CONFIG_ACPI_PCI n + define_bool CONFIG_ACPI_POWER n + define_bool CONFIG_ACPI_SYSTEM n + define_bool CONFIG_ACPI_BUTTON n + define_bool CONFIG_ACPI_FAN n + define_bool CONFIG_ACPI_PROCESSOR n + define_bool CONFIG_ACPI_THERMAL n + else + if [ "$CONFIG_PCI" = "y" ]; then + define_bool CONFIG_ACPI_PCI y + fi + define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_EFI y + define_bool CONFIG_ACPI_BOOT y + define_bool CONFIG_ACPI_BUS y + define_bool CONFIG_ACPI_INTERPRETER y + define_bool CONFIG_ACPI_POWER y + define_bool CONFIG_ACPI_SYSTEM y + tristate ' Button' CONFIG_ACPI_BUTTON + tristate ' Fan' CONFIG_ACPI_FAN + tristate ' Processor' CONFIG_ACPI_PROCESSOR + dep_tristate ' Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR + fi + bool ' Debug Statements' CONFIG_ACPI_DEBUG + endmenu + fi + +fi diff -Nur linux-2.4.19/drivers/acpi/Makefile linux-2.4.19-sgi211r3/drivers/acpi/Makefile --- linux-2.4.19/drivers/acpi/Makefile Wed Oct 24 14:06:21 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/Makefile Tue Aug 27 19:53:13 2002 @@ -4,51 +4,52 @@ O_TARGET := acpi.o -export-objs := acpi_ksyms.o - export ACPI_CFLAGS -ACPI_CFLAGS := -D_LINUX -I$(CURDIR)/include - -# -# CONFIG_ACPI_KERNEL_CONFIG is currently only IA64 -# -ifdef CONFIG_ACPI_KERNEL_CONFIG - ACPI_CFLAGS += -DCONFIG_ACPI_KERNEL_CONFIG_ONLY -endif - -acpi-subdirs := utilities dispatcher events hardware \ - executer namespace parser resources tables +ACPI_CFLAGS := -D_LINUX -I$(CURDIR)/include ifdef CONFIG_ACPI_DEBUG - ACPI_CFLAGS += -DACPI_DEBUG -Wno-unused -endif - -ifdef CONFIG_ACPI_DEBUGGER - ACPI_CFLAGS += -DENABLE_DEBUGGER - acpi-subdirs += debugger + ACPI_CFLAGS += -DACPI_DEBUG endif -EXTRA_CFLAGS += $(ACPI_CFLAGS) +EXTRA_CFLAGS += $(ACPI_CFLAGS) -mod-subdirs := ospm +export-objs := acpi_ksyms.o -subdir-$(CONFIG_ACPI) += $(acpi-subdirs) -subdir-$(CONFIG_ACPI_BUSMGR) += ospm +obj-y := acpi_ksyms.o -obj-$(CONFIG_ACPI) += driver.o os.o acpi_ksyms.o -obj-$(CONFIG_ACPI) += $(foreach dir,$(acpi-subdirs),$(dir)/$(dir).o) -ifdef CONFIG_ACPI_KERNEL_CONFIG - obj-$(CONFIG_ACPI) += acpiconf.o osconf.o +# +# ACPI Boot-Time Table Parsing +# +ifeq ($(CONFIG_ACPI_BOOT),y) + obj-y += tables.o endif -ifeq ($(CONFIG_ACPI_BUSMGR),y) - obj-y += ospm/ospm.o +# +# ACPI Core Subsystem (Interpreter) +# +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + obj-y += osl.o utils.o + subdir-y += dispatcher events executer hardware namespace parser \ + resources tables utilities + obj-y += $(foreach dir,$(subdir-y),$(dir)/$(dir).o) endif -# commented out until we distribute it -ASG -#ifeq ($(CONFIG_KDB),y) -# obj-m += kdb/kdbm_acpi.o -#endif +# +# ACPI Bus and Device Drivers +# +ifeq ($(CONFIG_ACPI_BUS),y) + obj-y += bus.o + obj-$(CONFIG_ACPI_AC) += ac.o + obj-$(CONFIG_ACPI_BATTERY) += battery.o + obj-$(CONFIG_ACPI_BUTTON) += button.o + obj-$(CONFIG_ACPI_EC) += ec.o + obj-$(CONFIG_ACPI_FAN) += fan.o + obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o + obj-$(CONFIG_ACPI_POWER) += power.o + obj-$(CONFIG_ACPI_PROCESSOR) += processor.o + obj-$(CONFIG_ACPI_THERMAL) += thermal.o + obj-$(CONFIG_ACPI_SYSTEM) += system.o +endif include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ac.c linux-2.4.19-sgi211r3/drivers/acpi/ac.c --- linux-2.4.19/drivers/acpi/ac.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/ac.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,352 @@ +/* + * acpi_ac.c - ACPI AC Adapter Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_AC_COMPONENT +ACPI_MODULE_NAME ("acpi_ac") + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +#define PREFIX "ACPI: " + + +int acpi_ac_add (struct acpi_device *device); +int acpi_ac_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_ac_driver = { + name: ACPI_AC_DRIVER_NAME, + class: ACPI_AC_CLASS, + ids: ACPI_AC_HID, + ops: { + add: acpi_ac_add, + remove: acpi_ac_remove, + }, +}; + +struct acpi_ac { + acpi_handle handle; + unsigned long state; +}; + + +/* -------------------------------------------------------------------------- + AC Adapter Management + -------------------------------------------------------------------------- */ + +static int +acpi_ac_get_state ( + struct acpi_ac *ac) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE("acpi_ac_get_state"); + + if (!ac) + return_VALUE(-EINVAL); + + status = acpi_evaluate_integer(ac->handle, "_PSR", NULL, &ac->state); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error reading AC Adapter state\n")); + ac->state = ACPI_AC_STATUS_UNKNOWN; + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +struct proc_dir_entry *acpi_ac_dir = NULL; + +static int +acpi_ac_read_state ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_ac *ac = (struct acpi_ac *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_ac_read_state"); + + if (!ac || (off != 0)) + goto end; + + if (0 != acpi_ac_get_state(ac)) { + p += sprintf(p, "ERROR: Unable to read AC Adapter state\n"); + goto end; + } + + p += sprintf(p, "state: "); + switch (ac->state) { + case ACPI_AC_STATUS_OFFLINE: + p += sprintf(p, "off-line\n"); + break; + case ACPI_AC_STATUS_ONLINE: + p += sprintf(p, "on-line\n"); + break; + default: + p += sprintf(p, "unknown\n"); + break; + } + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_ac_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_ac_add_fs"); + + if (!acpi_ac_dir) { + acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); + if (!acpi_ac_dir) + return_VALUE(-ENODEV); + } + + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_ac_dir); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + } + + /* 'state' [R] */ + entry = create_proc_entry(ACPI_AC_FILE_STATE, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_AC_FILE_STATE)); + else { + entry->read_proc = acpi_ac_read_state; + entry->data = acpi_driver_data(device); + } + + return_VALUE(0); +} + + +static int +acpi_ac_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_ac_remove_fs"); + + if (!acpi_ac_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_ac_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Model + -------------------------------------------------------------------------- */ + +void +acpi_ac_notify ( + acpi_handle handle, + u32 event, + void *data) +{ + struct acpi_ac *ac = (struct acpi_ac *) data; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_ac_notify"); + + if (!ac) + return; + + if (0 != acpi_bus_get_device(ac->handle, &device)) + return_VOID; + + switch (event) { + case ACPI_AC_NOTIFY_STATUS: + acpi_ac_get_state(ac); + acpi_bus_generate_event(device, event, (u32) ac->state); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + return_VOID; +} + + +int +acpi_ac_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_ac *ac = NULL; + + ACPI_FUNCTION_TRACE("acpi_ac_add"); + + if (!device) + return_VALUE(-EINVAL); + + ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL); + if (!ac) + return_VALUE(-ENOMEM); + memset(ac, 0, sizeof(struct acpi_ac)); + + ac->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_AC_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_AC_CLASS); + acpi_driver_data(device) = ac; + + result = acpi_ac_get_state(ac); + if (0 != result) + goto end; + + result = acpi_ac_add_fs(device); + if (0 != result) + goto end; + + status = acpi_install_notify_handler(ac->handle, + ACPI_DEVICE_NOTIFY, acpi_ac_notify, ac); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error installing notify handler\n")); + result = -ENODEV; + goto end; + } + + printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + acpi_device_name(device), acpi_device_bid(device), + ac->state?"on-line":"off-line"); + +end: + if (0 != result) { + acpi_ac_remove_fs(device); + kfree(ac); + } + + return_VALUE(result); +} + + +int +acpi_ac_remove ( + struct acpi_device *device, + int type) +{ + acpi_status status = AE_OK; + struct acpi_ac *ac = NULL; + + ACPI_FUNCTION_TRACE("acpi_ac_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + ac = (struct acpi_ac *) acpi_driver_data(device); + + status = acpi_remove_notify_handler(ac->handle, + ACPI_DEVICE_NOTIFY, acpi_ac_notify); + if (ACPI_FAILURE(status)) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error removing notify handler\n")); + + acpi_ac_remove_fs(device); + + kfree(ac); + + return_VALUE(0); +} + + +int __init +acpi_ac_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_ac_init"); + + result = acpi_bus_register_driver(&acpi_ac_driver); + if (0 > result) { + remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + + +void __exit +acpi_ac_exit (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_ac_exit"); + + result = acpi_bus_unregister_driver(&acpi_ac_driver); + if (0 == result) + remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); + + return_VOID; +} + + +module_init(acpi_ac_init); +module_exit(acpi_ac_exit); diff -Nur linux-2.4.19/drivers/acpi/acpi_bus.h linux-2.4.19-sgi211r3/drivers/acpi/acpi_bus.h --- linux-2.4.19/drivers/acpi/acpi_bus.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/acpi_bus.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,321 @@ +/* + * acpi_bus.h - ACPI Bus Driver ($Revision: 21 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#ifndef __ACPI_BUS_H__ +#define __ACPI_BUS_H__ + +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,4)) +#include +#define CONFIG_LDM +#endif + +#include "include/acpi.h" + + +/* TBD: Make dynamic */ +#define ACPI_MAX_HANDLES 10 +struct acpi_handle_list { + u32 count; + acpi_handle handles[ACPI_MAX_HANDLES]; +}; + + +/* acpi_utils.h */ +acpi_status acpi_extract_package (acpi_object *, acpi_buffer *, acpi_buffer *); +acpi_status acpi_evaluate (acpi_handle, acpi_string, acpi_object_list *, acpi_buffer *); +acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *); +acpi_status acpi_evaluate_reference (acpi_handle, acpi_string, acpi_object_list *, struct acpi_handle_list *); + + +#ifdef CONFIG_ACPI_BUS + +#include + +#define ACPI_BUS_FILE_ROOT "acpi" +extern struct proc_dir_entry *acpi_root_dir; +extern FADT_DESCRIPTOR acpi_fadt; + +enum acpi_bus_removal_type { + ACPI_BUS_REMOVAL_NORMAL = 0, + ACPI_BUS_REMOVAL_EJECT, + ACPI_BUS_REMOVAL_SUPRISE, + ACPI_BUS_REMOVAL_TYPE_COUNT +}; + +enum acpi_bus_device_type { + ACPI_BUS_TYPE_DEVICE = 0, + ACPI_BUS_TYPE_POWER, + ACPI_BUS_TYPE_PROCESSOR, + ACPI_BUS_TYPE_THERMAL, + ACPI_BUS_TYPE_SYSTEM, + ACPI_BUS_TYPE_POWER_BUTTON, + ACPI_BUS_TYPE_SLEEP_BUTTON, + ACPI_BUS_DEVICE_TYPE_COUNT +}; + +struct acpi_driver; +struct acpi_device; + + +/* + * ACPI Driver + * ----------- + */ + +typedef int (*acpi_op_add) (struct acpi_device *device); +typedef int (*acpi_op_remove) (struct acpi_device *device, int type); +typedef int (*acpi_op_lock) (struct acpi_device *device, int type); +typedef int (*acpi_op_start) (struct acpi_device *device); +typedef int (*acpi_op_stop) (struct acpi_device *device, int type); +typedef int (*acpi_op_suspend) (struct acpi_device *device, int state); +typedef int (*acpi_op_resume) (struct acpi_device *device, int state); +typedef int (*acpi_op_scan) (struct acpi_device *device); +typedef int (*acpi_op_bind) (struct acpi_device *device); + +struct acpi_device_ops { + acpi_op_add add; + acpi_op_remove remove; + acpi_op_lock lock; + acpi_op_start start; + acpi_op_stop stop; + acpi_op_suspend suspend; + acpi_op_resume resume; + acpi_op_scan scan; + acpi_op_bind bind; +}; + +struct acpi_driver { + struct list_head node; + char name[80]; + char class[80]; + int references; + char *ids; /* Supported Hardware IDs */ + struct acpi_device_ops ops; +}; + +enum acpi_blacklist_predicates +{ + all_versions, + less_than_or_equal, + equal, + greater_than_or_equal, +}; + +struct acpi_blacklist_item +{ + char oem_id[7]; + char oem_table_id[9]; + u32 oem_revision; + acpi_table_type table; + enum acpi_blacklist_predicates oem_revision_predicate; + char *reason; + u32 is_critical_error; +}; + + +/* + * ACPI Device + * ----------- + */ + +/* Status (_STA) */ + +struct acpi_device_status { + u32 present:1; + u32 enabled:1; + u32 show_in_ui:1; + u32 functional:1; + u32 battery_present:1; + u32 reserved:27; +}; + + +/* Flags */ + +struct acpi_device_flags { + u32 dynamic_status:1; + u32 hardware_id:1; + u32 compatible_ids:1; + u32 bus_address:1; + u32 unique_id:1; + u32 removable:1; + u32 ejectable:1; + u32 lockable:1; + u32 suprise_removal_ok:1; + u32 power_manageable:1; + u32 performance_manageable:1; + u32 reserved:21; +}; + + +/* File System */ + +struct acpi_device_dir { + struct proc_dir_entry *entry; +}; + +#define acpi_device_dir(d) ((d)->dir.entry) + + +/* Plug and Play */ + +typedef char acpi_bus_id[5]; +typedef unsigned long acpi_bus_address; +typedef char acpi_hardware_id[9]; +typedef char acpi_unique_id[9]; +typedef char acpi_device_name[40]; +typedef char acpi_device_class[20]; + +struct acpi_device_pnp { + acpi_bus_id bus_id; /* Object name */ + acpi_bus_address bus_address; /* _ADR */ + acpi_hardware_id hardware_id; /* _HID */ + acpi_unique_id unique_id; /* _UID */ + acpi_device_name device_name; /* Driver-determined */ + acpi_device_class device_class; /* " */ +}; + +#define acpi_device_bid(d) ((d)->pnp.bus_id) +#define acpi_device_adr(d) ((d)->pnp.bus_address) +#define acpi_device_hid(d) ((d)->pnp.hardware_id) +#define acpi_device_uid(d) ((d)->pnp.unique_id) +#define acpi_device_name(d) ((d)->pnp.device_name) +#define acpi_device_class(d) ((d)->pnp.device_class) + + +/* Power Management */ + +struct acpi_device_power_flags { + u32 explicit_get:1; /* _PSC present? */ + u32 power_resources:1; /* Power resources */ + u32 inrush_current:1; /* Serialize Dx->D0 */ + u32 wake_capable:1; /* Wakeup supported? */ + u32 wake_enabled:1; /* Enabled for wakeup */ + u32 power_removed:1; /* Optimize Dx->D0 */ + u32 reserved:26; +}; + +struct acpi_device_power_state { + struct { + u8 valid:1; + u8 explicit_set:1; /* _PSx present? */ + u8 reserved:6; + } flags; + int power; /* % Power (compared to D0) */ + int latency; /* Dx->D0 time (microseconds) */ + struct acpi_handle_list resources; /* Power resources referenced */ +}; + +struct acpi_device_power { + int state; /* Current state */ + struct acpi_device_power_flags flags; + struct acpi_device_power_state states[4]; /* Power states (D0-D3) */ +}; + + +/* Performance Management */ + +struct acpi_device_perf_flags { + u8 reserved:8; +}; + +struct acpi_device_perf_state { + struct { + u8 valid:1; + u8 reserved:7; + } flags; + u8 power; /* % Power (compared to P0) */ + u8 performance; /* % Performance ( " ) */ + int latency; /* Px->P0 time (microseconds) */ +}; + +struct acpi_device_perf { + int state; + struct acpi_device_perf_flags flags; + int state_count; + struct acpi_device_perf_state *states; +}; + + +/* Device */ + +struct acpi_device { + acpi_handle handle; + struct acpi_device *parent; + struct list_head children; + struct list_head node; + struct acpi_device_status status; + struct acpi_device_flags flags; + struct acpi_device_pnp pnp; + struct acpi_device_power power; + struct acpi_device_perf performance; + struct acpi_device_dir dir; + struct acpi_device_ops ops; + struct acpi_driver *driver; + void *driver_data; +#ifdef CONFIG_LDM + struct device dev; +#endif +}; + +#define acpi_driver_data(d) ((d)->driver_data) + + +/* + * Events + * ------ + */ + +struct acpi_bus_event { + struct list_head node; + acpi_device_class device_class; + acpi_bus_id bus_id; + u32 type; + u32 data; +}; + + +/* + * External Functions + */ + +int acpi_bus_get_device(acpi_handle, struct acpi_device **device); +int acpi_bus_get_status (struct acpi_device *device); +int acpi_bus_get_power (acpi_handle handle, int *state); +int acpi_bus_set_power (acpi_handle handle, int state); +int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data); +int acpi_bus_receive_event (struct acpi_bus_event *event); +int acpi_bus_register_driver (struct acpi_driver *driver); +int acpi_bus_unregister_driver (struct acpi_driver *driver); +int acpi_bus_scan (struct acpi_device *device); +int acpi_init (void); +void acpi_exit (void); + + +#endif /*CONFIG_ACPI_BUS*/ + +#endif /*__ACPI_BUS_H__*/ diff -Nur linux-2.4.19/drivers/acpi/acpi_drivers.h linux-2.4.19-sgi211r3/drivers/acpi/acpi_drivers.h --- linux-2.4.19/drivers/acpi/acpi_drivers.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/acpi_drivers.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,345 @@ +/* + * acpi_drivers.h ($Revision: 29 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#ifndef __ACPI_DRIVERS_H__ +#define __ACPI_DRIVERS_H__ + +#include +#include "acpi_bus.h" + + +#define ACPI_MAX_STRING 80 + + +/* -------------------------------------------------------------------------- + ACPI Bus + -------------------------------------------------------------------------- */ + +#define ACPI_BUS_COMPONENT 0x00010000 +#define ACPI_BUS_CLASS "system_bus" +#define ACPI_BUS_HID "ACPI_BUS" +#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" +#define ACPI_BUS_DEVICE_NAME "System Bus" + + +/* -------------------------------------------------------------------------- + AC Adapter + -------------------------------------------------------------------------- */ + +#define ACPI_AC_COMPONENT 0x00020000 +#define ACPI_AC_CLASS "ac_adapter" +#define ACPI_AC_HID "ACPI0003" +#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" +#define ACPI_AC_DEVICE_NAME "AC Adapter" +#define ACPI_AC_FILE_STATE "state" +#define ACPI_AC_NOTIFY_STATUS 0x80 +#define ACPI_AC_STATUS_OFFLINE 0x00 +#define ACPI_AC_STATUS_ONLINE 0x01 +#define ACPI_AC_STATUS_UNKNOWN 0xFF + + +/* -------------------------------------------------------------------------- + Battery + -------------------------------------------------------------------------- */ + +#define ACPI_BATTERY_COMPONENT 0x00040000 +#define ACPI_BATTERY_CLASS "battery" +#define ACPI_BATTERY_HID "PNP0C0A" +#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" +#define ACPI_BATTERY_DEVICE_NAME "Battery" +#define ACPI_BATTERY_FILE_INFO "info" +#define ACPI_BATTERY_FILE_STATUS "state" +#define ACPI_BATTERY_FILE_ALARM "alarm" +#define ACPI_BATTERY_NOTIFY_STATUS 0x80 +#define ACPI_BATTERY_NOTIFY_INFO 0x81 +#define ACPI_BATTERY_UNITS_WATTS "mW" +#define ACPI_BATTERY_UNITS_AMPS "mA" + + +/* -------------------------------------------------------------------------- + Button + -------------------------------------------------------------------------- */ + +#define ACPI_BUTTON_COMPONENT 0x00080000 +#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" +#define ACPI_BUTTON_CLASS "button" +#define ACPI_BUTTON_FILE_INFO "info" +#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 +#define ACPI_BUTTON_NOTIFY_STATUS 0x80 + +#define ACPI_BUTTON_SUBCLASS_POWER "power" +#define ACPI_BUTTON_HID_POWER "PNP0C0C" +#define ACPI_BUTTON_HID_POWERF "ACPI_FPB" +#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)" +#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)" +#define ACPI_BUTTON_TYPE_POWER 0x01 +#define ACPI_BUTTON_TYPE_POWERF 0x02 + +#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" +#define ACPI_BUTTON_HID_SLEEP "PNP0C0E" +#define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB" +#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)" +#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)" +#define ACPI_BUTTON_TYPE_SLEEP 0x03 +#define ACPI_BUTTON_TYPE_SLEEPF 0x04 + +#define ACPI_BUTTON_SUBCLASS_LID "lid" +#define ACPI_BUTTON_HID_LID "PNP0C0D" +#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" +#define ACPI_BUTTON_TYPE_LID 0x05 + + +/* -------------------------------------------------------------------------- + Embedded Controller + -------------------------------------------------------------------------- */ + +#define ACPI_EC_COMPONENT 0x00100000 +#define ACPI_EC_CLASS "embedded_controller" +#define ACPI_EC_HID "PNP0C09" +#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" +#define ACPI_EC_DEVICE_NAME "Embedded Controller" +#define ACPI_EC_FILE_INFO "info" + +#ifdef CONFIG_ACPI_EC + +int acpi_ec_init (void); +void acpi_ec_exit (void); + +#endif + + +/* -------------------------------------------------------------------------- + Fan + -------------------------------------------------------------------------- */ + +#define ACPI_FAN_COMPONENT 0x00200000 +#define ACPI_FAN_CLASS "fan" +#define ACPI_FAN_HID "PNP0C0B" +#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" +#define ACPI_FAN_DEVICE_NAME "Fan" +#define ACPI_FAN_FILE_STATE "state" +#define ACPI_FAN_NOTIFY_STATUS 0x80 + + +/* -------------------------------------------------------------------------- + PCI + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_PCI + +#define ACPI_PCI_COMPONENT 0x00400000 + +/* ACPI PCI Root Bridge (pci_root.c) */ + +#define ACPI_PCI_ROOT_CLASS "pci_bridge" +#define ACPI_PCI_ROOT_HID "PNP0A03" +#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" +#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" + +int acpi_pci_root_init (void); +void acpi_pci_root_exit (void); + +/* ACPI PCI Interrupt Link (pci_link.c) */ + +#define ACPI_PCI_LINK_CLASS "pci_irq_routing" +#define ACPI_PCI_LINK_HID "PNP0C0F" +#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" +#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" +#define ACPI_PCI_LINK_FILE_INFO "info" +#define ACPI_PCI_LINK_FILE_STATUS "state" + +int acpi_pci_link_check (void); +int acpi_pci_link_get_irq (acpi_handle handle, int index); +int acpi_pci_link_init (void); +void acpi_pci_link_exit (void); + +/* ACPI PCI Interrupt Routing (pci_irq.c) */ + +int acpi_pci_irq_add_prt (acpi_handle handle, int segment, int bus); + +/* ACPI PCI Device Binding (pci_bind.c) */ + +struct pci_bus; + +int acpi_pci_bind (struct acpi_device *device); +int acpi_pci_bind_root (struct acpi_device *device, acpi_pci_id *id, struct pci_bus *bus); + +#endif /*CONFIG_ACPI_PCI*/ + + +/* -------------------------------------------------------------------------- + Power Resource + -------------------------------------------------------------------------- */ + +#define ACPI_POWER_COMPONENT 0x00800000 +#define ACPI_POWER_CLASS "power_resource" +#define ACPI_POWER_HID "ACPI_PWR" +#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" +#define ACPI_POWER_DEVICE_NAME "Power Resource" +#define ACPI_POWER_FILE_INFO "info" +#define ACPI_POWER_FILE_STATUS "state" +#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 +#define ACPI_POWER_RESOURCE_STATE_ON 0x01 +#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF + +#ifdef CONFIG_ACPI_POWER + +int acpi_power_get_inferred_state (struct acpi_device *device); +int acpi_power_transition (struct acpi_device *device, int state); +int acpi_power_init (void); +void acpi_power_exit (void); + +#endif + + +/* -------------------------------------------------------------------------- + Processor + -------------------------------------------------------------------------- */ + +#define ACPI_PROCESSOR_COMPONENT 0x01000000 +#define ACPI_PROCESSOR_CLASS "processor" +#define ACPI_PROCESSOR_HID "ACPI_CPU" +#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" +#define ACPI_PROCESSOR_DEVICE_NAME "Processor" +#define ACPI_PROCESSOR_FILE_INFO "info" +#define ACPI_PROCESSOR_FILE_POWER "power" +#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" +#define ACPI_PROCESSOR_FILE_THROTTLING "throttling" +#define ACPI_PROCESSOR_FILE_LIMIT "limit" +#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 +#define ACPI_PROCESSOR_NOTIFY_POWER 0x81 +#define ACPI_PROCESSOR_LIMIT_NONE 0x00 +#define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01 +#define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02 + +int acpi_processor_set_thermal_limit(acpi_handle handle, int type); + + +/* -------------------------------------------------------------------------- + System + -------------------------------------------------------------------------- */ + +#define ACPI_SYSTEM_COMPONENT 0x02000000 +#define ACPI_SYSTEM_CLASS "system" +#define ACPI_SYSTEM_HID "ACPI_SYS" +#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" +#define ACPI_SYSTEM_DEVICE_NAME "System" +#define ACPI_SYSTEM_FILE_INFO "info" +#define ACPI_SYSTEM_FILE_EVENT "event" +#define ACPI_SYSTEM_FILE_ALARM "alarm" +#define ACPI_SYSTEM_FILE_DSDT "dsdt" +#define ACPI_SYSTEM_FILE_FADT "fadt" +#define ACPI_SYSTEM_FILE_SLEEP "sleep" +#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" +#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" + +#ifdef CONFIG_ACPI_SYSTEM + +int acpi_system_init (void); +void acpi_system_exit (void); + +#endif + + +/* -------------------------------------------------------------------------- + Thermal Zone + -------------------------------------------------------------------------- */ + +#define ACPI_THERMAL_COMPONENT 0x04000000 +#define ACPI_THERMAL_CLASS "thermal_zone" +#define ACPI_THERMAL_HID "ACPI_THM" +#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" +#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" +#define ACPI_THERMAL_FILE_STATE "state" +#define ACPI_THERMAL_FILE_TEMPERATURE "temperature" +#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points" +#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode" +#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency" +#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 +#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81 +#define ACPI_THERMAL_NOTIFY_DEVICES 0x82 +#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0 +#define ACPI_THERMAL_NOTIFY_HOT 0xF1 +#define ACPI_THERMAL_MODE_ACTIVE 0x00 +#define ACPI_THERMAL_MODE_PASSIVE 0x01 +#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" + + +/* -------------------------------------------------------------------------- + Debug Support + -------------------------------------------------------------------------- */ + +#define ACPI_DEBUG_RESTORE 0 +#define ACPI_DEBUG_LOW 1 +#define ACPI_DEBUG_MEDIUM 2 +#define ACPI_DEBUG_HIGH 3 +#define ACPI_DEBUG_DRIVERS 4 + +extern u32 acpi_dbg_level; +extern u32 acpi_dbg_layer; + +static inline void +acpi_set_debug ( + u32 flag) +{ + static u32 layer_save; + static u32 level_save; + + switch (flag) { + case ACPI_DEBUG_RESTORE: + acpi_dbg_layer = layer_save; + acpi_dbg_level = level_save; + break; + case ACPI_DEBUG_LOW: + case ACPI_DEBUG_MEDIUM: + case ACPI_DEBUG_HIGH: + case ACPI_DEBUG_DRIVERS: + layer_save = acpi_dbg_layer; + level_save = acpi_dbg_level; + break; + } + + switch (flag) { + case ACPI_DEBUG_LOW: + acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; + acpi_dbg_level = DEBUG_DEFAULT; + break; + case ACPI_DEBUG_MEDIUM: + acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; + acpi_dbg_level = ACPI_LV_FUNCTIONS | ACPI_LV_ALL_EXCEPTIONS; + break; + case ACPI_DEBUG_HIGH: + acpi_dbg_layer = 0xFFFFFFFF; + acpi_dbg_level = 0xFFFFFFFF; + break; + case ACPI_DEBUG_DRIVERS: + acpi_dbg_layer = ACPI_ALL_DRIVERS; + acpi_dbg_level = 0xFFFFFFFF; + break; + } +} + + +#endif /*__ACPI_DRIVERS_H__*/ diff -Nur linux-2.4.19/drivers/acpi/acpi_ksyms.c linux-2.4.19-sgi211r3/drivers/acpi/acpi_ksyms.c --- linux-2.4.19/drivers/acpi/acpi_ksyms.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/acpi/acpi_ksyms.c Wed Oct 16 14:02:58 2002 @@ -1,64 +1,58 @@ /* - * ksyms.c - ACPI exported symbols + * acpi_ksyms.c - ACPI Kernel Symbols ($Revision: 14 $) * - * Copyright (C) 2000 Andrew Grover + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#include #include -#include -#include -#include -#include -#include "acpi.h" -#include "acdebug.h" +#include "include/acpi.h" +#include "acpi_bus.h" -extern int acpi_in_debugger; -extern FADT_DESCRIPTOR acpi_fadt; -#define _COMPONENT OS_DEPENDENT - MODULE_NAME ("symbols") +#ifdef CONFIG_ACPI_INTERPRETER + +/* ACPI Debugger */ #ifdef ENABLE_DEBUGGER + +extern int acpi_in_debugger; + EXPORT_SYMBOL(acpi_in_debugger); EXPORT_SYMBOL(acpi_db_user_commands); -#endif + +#endif /* ENABLE_DEBUGGER */ + +/* ACPI Core Subsystem */ #ifdef ACPI_DEBUG +EXPORT_SYMBOL(acpi_dbg_layer); +EXPORT_SYMBOL(acpi_dbg_level); EXPORT_SYMBOL(acpi_ut_debug_print_raw); EXPORT_SYMBOL(acpi_ut_debug_print); EXPORT_SYMBOL(acpi_ut_status_exit); +EXPORT_SYMBOL(acpi_ut_value_exit); EXPORT_SYMBOL(acpi_ut_exit); EXPORT_SYMBOL(acpi_ut_trace); -#endif - -EXPORT_SYMBOL(acpi_gbl_FADT); - -EXPORT_SYMBOL(acpi_os_free); -EXPORT_SYMBOL(acpi_os_printf); -EXPORT_SYMBOL(acpi_os_callocate); -EXPORT_SYMBOL(acpi_os_sleep); -EXPORT_SYMBOL(acpi_os_stall); -EXPORT_SYMBOL(acpi_os_queue_for_execution); - -EXPORT_SYMBOL(acpi_dbg_layer); -EXPORT_SYMBOL(acpi_dbg_level); - -EXPORT_SYMBOL(acpi_format_exception); +#endif /*ACPI_DEBUG*/ EXPORT_SYMBOL(acpi_get_handle); EXPORT_SYMBOL(acpi_get_parent); @@ -68,7 +62,6 @@ EXPORT_SYMBOL(acpi_get_next_object); EXPORT_SYMBOL(acpi_evaluate_object); EXPORT_SYMBOL(acpi_get_table); - EXPORT_SYMBOL(acpi_install_notify_handler); EXPORT_SYMBOL(acpi_remove_notify_handler); EXPORT_SYMBOL(acpi_install_gpe_handler); @@ -77,40 +70,62 @@ EXPORT_SYMBOL(acpi_remove_address_space_handler); EXPORT_SYMBOL(acpi_install_fixed_event_handler); EXPORT_SYMBOL(acpi_remove_fixed_event_handler); - EXPORT_SYMBOL(acpi_acquire_global_lock); EXPORT_SYMBOL(acpi_release_global_lock); - EXPORT_SYMBOL(acpi_get_current_resources); EXPORT_SYMBOL(acpi_get_possible_resources); EXPORT_SYMBOL(acpi_set_current_resources); - EXPORT_SYMBOL(acpi_enable_event); EXPORT_SYMBOL(acpi_disable_event); EXPORT_SYMBOL(acpi_clear_event); - EXPORT_SYMBOL(acpi_get_timer_duration); EXPORT_SYMBOL(acpi_get_timer); +EXPORT_SYMBOL(acpi_get_sleep_type_data); +EXPORT_SYMBOL(acpi_get_register); +EXPORT_SYMBOL(acpi_set_register); +EXPORT_SYMBOL(acpi_enter_sleep_state); +EXPORT_SYMBOL(acpi_get_system_info); +EXPORT_SYMBOL(acpi_walk_namespace); +/* ACPI OS Services Layer (acpi_osl.c) */ + +EXPORT_SYMBOL(acpi_os_free); +EXPORT_SYMBOL(acpi_os_printf); +EXPORT_SYMBOL(acpi_os_sleep); +EXPORT_SYMBOL(acpi_os_stall); +EXPORT_SYMBOL(acpi_os_signal); +EXPORT_SYMBOL(acpi_os_queue_for_execution); EXPORT_SYMBOL(acpi_os_signal_semaphore); EXPORT_SYMBOL(acpi_os_create_semaphore); EXPORT_SYMBOL(acpi_os_delete_semaphore); EXPORT_SYMBOL(acpi_os_wait_semaphore); -EXPORT_SYMBOL(acpi_os_read_port); -EXPORT_SYMBOL(acpi_os_write_port); +/* ACPI Utilities (acpi_utils.c) */ + +EXPORT_SYMBOL(acpi_extract_package); +EXPORT_SYMBOL(acpi_evaluate); +EXPORT_SYMBOL(acpi_evaluate_integer); +EXPORT_SYMBOL(acpi_evaluate_reference); + +#endif /*CONFIG_ACPI_INTERPRETER*/ + + +/* ACPI Bus Driver (acpi_bus.c) */ + +#ifdef CONFIG_ACPI_BUS EXPORT_SYMBOL(acpi_fadt); -EXPORT_SYMBOL(acpi_hw_register_bit_access); -EXPORT_SYMBOL(acpi_hw_obtain_sleep_type_register_data); -EXPORT_SYMBOL(acpi_enter_sleep_state); -EXPORT_SYMBOL(acpi_get_system_info); -EXPORT_SYMBOL(acpi_leave_sleep_state); -EXPORT_SYMBOL(acpi_walk_namespace); -/*EXPORT_SYMBOL(acpi_save_state_mem);*/ -/*EXPORT_SYMBOL(acpi_save_state_disk);*/ -EXPORT_SYMBOL(acpi_hw_register_read); -EXPORT_SYMBOL(acpi_set_firmware_waking_vector); -EXPORT_SYMBOL(acpi_subsystem_status); +EXPORT_SYMBOL(acpi_root_dir); +EXPORT_SYMBOL(acpi_bus_get_device); +EXPORT_SYMBOL(acpi_bus_get_status); +EXPORT_SYMBOL(acpi_bus_get_power); +EXPORT_SYMBOL(acpi_bus_set_power); +EXPORT_SYMBOL(acpi_bus_generate_event); +EXPORT_SYMBOL(acpi_bus_receive_event); +EXPORT_SYMBOL(acpi_bus_register_driver); +EXPORT_SYMBOL(acpi_bus_unregister_driver); +EXPORT_SYMBOL(acpi_bus_scan); +EXPORT_SYMBOL(acpi_init); + +#endif /*CONFIG_ACPI_BUS*/ -EXPORT_SYMBOL(acpi_os_signal); diff -Nur linux-2.4.19/drivers/acpi/battery.c linux-2.4.19-sgi211r3/drivers/acpi/battery.c --- linux-2.4.19/drivers/acpi/battery.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/battery.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,831 @@ +/* + * acpi_battery.c - ACPI Battery Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_BATTERY_COMPONENT +ACPI_MODULE_NAME ("acpi_battery") + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +#define PREFIX "ACPI: " + + +#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF + +#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS" +#define ACPI_BATTERY_FORMAT_BST "NNNN" + +static int acpi_battery_add (struct acpi_device *device); +static int acpi_battery_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_battery_driver = { + name: ACPI_BATTERY_DRIVER_NAME, + class: ACPI_BATTERY_CLASS, + ids: ACPI_BATTERY_HID, + ops: { + add: acpi_battery_add, + remove: acpi_battery_remove, + }, +}; + +struct acpi_battery_status { + acpi_integer state; + acpi_integer present_rate; + acpi_integer remaining_capacity; + acpi_integer present_voltage; +}; + +struct acpi_battery_info { + acpi_integer power_unit; + acpi_integer design_capacity; + acpi_integer last_full_capacity; + acpi_integer battery_technology; + acpi_integer design_voltage; + acpi_integer design_capacity_warning; + acpi_integer design_capacity_low; + acpi_integer battery_capacity_granularity_1; + acpi_integer battery_capacity_granularity_2; + acpi_string model_number; + acpi_string serial_number; + acpi_string battery_type; + acpi_string oem_info; +}; + +struct acpi_battery_flags { + u8 present:1; /* Bay occupied? */ + u8 power_unit:1; /* 0=watts, 1=apms */ + u8 alarm:1; /* _BTP present? */ + u8 reserved:5; +}; + +struct acpi_battery_trips { + unsigned long warning; + unsigned long low; +}; + +struct acpi_battery { + acpi_handle handle; + struct acpi_battery_flags flags; + struct acpi_battery_trips trips; + unsigned long alarm; + struct acpi_battery_info *info; +}; + + +/* -------------------------------------------------------------------------- + Battery Management + -------------------------------------------------------------------------- */ + +static int +acpi_battery_get_info ( + struct acpi_battery *battery, + struct acpi_battery_info **bif) +{ + int result = 0; + acpi_status status = 0; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_buffer format = {sizeof(ACPI_BATTERY_FORMAT_BIF), + ACPI_BATTERY_FORMAT_BIF}; + acpi_buffer data = {0, NULL}; + acpi_object *package = NULL; + + ACPI_FUNCTION_TRACE("acpi_battery_get_info"); + + if (!battery || !bif) + return_VALUE(-EINVAL); + + /* Evalute _BIF */ + + status = acpi_evaluate_object(battery->handle, "_BIF", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BIF\n")); + return_VALUE(-ENODEV); + } + + package = (acpi_object *) buffer.pointer; + + /* Extract Package Data */ + + status = acpi_extract_package(package, &format, &data); + if (status != AE_BUFFER_OVERFLOW) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n")); + result = -ENODEV; + goto end; + } + + data.pointer = kmalloc(data.length, GFP_KERNEL); + if (!data.pointer) { + result = -ENOMEM; + goto end; + } + memset(data.pointer, 0, data.length); + + status = acpi_extract_package(package, &format, &data); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n")); + kfree(data.pointer); + result = -ENODEV; + goto end; + } + +end: + kfree(buffer.pointer); + + if (0 == result) + (*bif) = (struct acpi_battery_info *) data.pointer; + + return_VALUE(result); +} + +static int +acpi_battery_get_status ( + struct acpi_battery *battery, + struct acpi_battery_status **bst) +{ + int result = 0; + acpi_status status = 0; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_buffer format = {sizeof(ACPI_BATTERY_FORMAT_BST), + ACPI_BATTERY_FORMAT_BST}; + acpi_buffer data = {0, NULL}; + acpi_object *package = NULL; + + ACPI_FUNCTION_TRACE("acpi_battery_get_status"); + + if (!battery || !bst) + return_VALUE(-EINVAL); + + /* Evalute _BST */ + + status = acpi_evaluate_object(battery->handle, "_BST", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BST\n")); + return_VALUE(-ENODEV); + } + + package = (acpi_object *) buffer.pointer; + + /* Extract Package Data */ + + status = acpi_extract_package(package, &format, &data); + if (status != AE_BUFFER_OVERFLOW) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n")); + result = -ENODEV; + goto end; + } + + data.pointer = kmalloc(data.length, GFP_KERNEL); + if (!data.pointer) { + result = -ENOMEM; + goto end; + } + memset(data.pointer, 0, data.length); + + status = acpi_extract_package(package, &format, &data); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n")); + kfree(data.pointer); + result = -ENODEV; + goto end; + } + +end: + kfree(buffer.pointer); + + if (0 == result) + (*bst) = (struct acpi_battery_status *) data.pointer; + + return_VALUE(result); +} + + +static int +acpi_battery_set_alarm ( + struct acpi_battery *battery, + unsigned long alarm) +{ + acpi_status status = 0; + acpi_object arg0 = {ACPI_TYPE_INTEGER}; + acpi_object_list arg_list = {1, &arg0}; + + ACPI_FUNCTION_TRACE("acpi_battery_set_alarm"); + + if (!battery) + return_VALUE(-EINVAL); + + if (!battery->flags.alarm) + return_VALUE(-ENODEV); + + arg0.integer.value = alarm; + + status = acpi_evaluate(battery->handle, "_BTP", &arg_list, NULL); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm)); + + battery->alarm = alarm; + + return_VALUE(0); +} + + +static int +acpi_battery_check ( + struct acpi_battery *battery) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_handle handle = NULL; + struct acpi_device *device = NULL; + struct acpi_battery_info *bif = NULL; + + ACPI_FUNCTION_TRACE("acpi_battery_check"); + + if (!battery) + return_VALUE(-EINVAL); + + result = acpi_bus_get_device(battery->handle, &device); + if (0 != result) + return_VALUE(result); + + result = acpi_bus_get_status(device); + if (0 != result) + return_VALUE(result); + + /* Insertion? */ + + if (!battery->flags.present && device->status.battery_present) { + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n")); + + /* Evalute _BIF to get certain static information */ + + result = acpi_battery_get_info(battery, &bif); + if (0 != result) + return_VALUE(result); + + battery->flags.power_unit = bif->power_unit; + battery->trips.warning = bif->design_capacity_warning; + battery->trips.low = bif->design_capacity_low; + kfree(bif); + + /* See if alarms are supported, and if so, set default */ + + status = acpi_get_handle(battery->handle, "_BTP", &handle); + if (ACPI_SUCCESS(status)) { + battery->flags.alarm = 1; + acpi_battery_set_alarm(battery, battery->trips.warning); + } + } + + /* Removal? */ + + else if (battery->flags.present && !device->status.battery_present) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n")); + } + + battery->flags.present = device->status.battery_present; + + return_VALUE(result); +} + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +struct proc_dir_entry *acpi_battery_dir = NULL; + +static int +acpi_battery_read_info ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + int result = 0; + struct acpi_battery *battery = (struct acpi_battery *) data; + struct acpi_battery_info *bif = NULL; + char *units = "?"; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_battery_read_info"); + + if (!battery) + goto end; + + if (battery->flags.present) + p += sprintf(p, "present: yes\n"); + else { + p += sprintf(p, "present: no\n"); + goto end; + } + + /* Battery Info (_BIF) */ + + result = acpi_battery_get_info(battery, &bif); + if ((0 != result) || !bif) { + p += sprintf(p, "ERROR: Unable to read battery information\n"); + goto end; + } + + units = bif->power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; + + if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + p += sprintf(p, "design capacity: unknown\n"); + else + p += sprintf(p, "design capacity: %d %sh\n", + (u32) bif->design_capacity, units); + + if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + p += sprintf(p, "last full capacity: unknown\n"); + else + p += sprintf(p, "last full capacity: %d %sh\n", + (u32) bif->last_full_capacity, units); + + switch ((u32) bif->battery_technology) { + case 0: + p += sprintf(p, "battery technology: non-rechargeable\n"); + break; + case 1: + p += sprintf(p, "battery technology: rechargeable\n"); + break; + default: + p += sprintf(p, "battery technology: unknown\n"); + break; + } + + if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + p += sprintf(p, "design voltage: unknown\n"); + else + p += sprintf(p, "design voltage: %d mV\n", + (u32) bif->design_voltage); + + p += sprintf(p, "design capacity warning: %d %sh\n", + (u32) bif->design_capacity_warning, units); + p += sprintf(p, "design capacity low: %d %sh\n", + (u32) bif->design_capacity_low, units); + p += sprintf(p, "capacity granularity 1: %d %sh\n", + (u32) bif->battery_capacity_granularity_1, units); + p += sprintf(p, "capacity granularity 2: %d %sh\n", + (u32) bif->battery_capacity_granularity_2, units); + p += sprintf(p, "model number: %s\n", + bif->model_number); + p += sprintf(p, "serial number: %s\n", + bif->serial_number); + p += sprintf(p, "battery type: %s\n", + bif->battery_type); + p += sprintf(p, "OEM info: %s\n", + bif->oem_info); + +end: + kfree(bif); + + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_battery_read_state ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + int result = 0; + struct acpi_battery *battery = (struct acpi_battery *) data; + struct acpi_battery_status *bst = NULL; + char *units = "?"; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_battery_read_state"); + + if (!battery) + goto end; + + if (battery->flags.present) + p += sprintf(p, "present: yes\n"); + else { + p += sprintf(p, "present: no\n"); + goto end; + } + + /* Battery Units */ + + units = battery->flags.power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; + + /* Battery Status (_BST) */ + + result = acpi_battery_get_status(battery, &bst); + if ((0 != result) || !bst) { + p += sprintf(p, "ERROR: Unable to read battery status\n"); + goto end; + } + + if (!(bst->state & 0x04)) + p += sprintf(p, "capacity state: ok\n"); + else + p += sprintf(p, "capacity state: critical\n"); + + if ((bst->state & 0x01) && (bst->state & 0x02)) + p += sprintf(p, "charging state: charging/discharging\n"); + else if (bst->state & 0x01) + p += sprintf(p, "charging state: discharging\n"); + else if (bst->state & 0x02) + p += sprintf(p, "charging state: charging\n"); + else + p += sprintf(p, "charging state: unknown\n"); + + if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) + p += sprintf(p, "present rate: unknown\n"); + else + p += sprintf(p, "present rate: %d %s\n", + (u32) bst->present_rate, units); + + if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + p += sprintf(p, "remaining capacity: unknown\n"); + else + p += sprintf(p, "remaining capacity: %d %sh\n", + (u32) bst->remaining_capacity, units); + + if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + p += sprintf(p, "present voltage: unknown\n"); + else + p += sprintf(p, "present voltage: %d mV\n", + (u32) bst->present_voltage); + +end: + kfree(bst); + + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_battery_read_alarm ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_battery *battery = (struct acpi_battery *) data; + char *units = "?"; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_battery_read_alarm"); + + if (!battery) + goto end; + + if (!battery->flags.present) { + p += sprintf(p, "present: no\n"); + goto end; + } + + /* Battery Units */ + + units = battery->flags.power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; + + /* Battery Alarm */ + + p += sprintf(p, "alarm: "); + if (!battery->alarm) + p += sprintf(p, "unsupported\n"); + else + p += sprintf(p, "%d %sh\n", (u32) battery->alarm, units); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_battery_write_alarm ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + struct acpi_battery *battery = (struct acpi_battery *) data; + char alarm_string[12] = {'\0'}; + + ACPI_FUNCTION_TRACE("acpi_battery_write_alarm"); + + if (!battery || (count > sizeof(alarm_string) - 1)) + return_VALUE(-EINVAL); + + if (!battery->flags.present) + return_VALUE(-ENODEV); + + if (copy_from_user(alarm_string, buffer, count)) + return_VALUE(-EFAULT); + + alarm_string[count] = '\0'; + + result = acpi_battery_set_alarm(battery, + simple_strtoul(alarm_string, NULL, 0)); + if (0 != result) + return_VALUE(result); + + return_VALUE(count); +} + + +static int +acpi_battery_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_battery_add_fs"); + + if (!acpi_battery_dir) { + acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); + if (!acpi_battery_dir) + return_VALUE(-ENODEV); + } + + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_battery_dir); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + } + + /* 'info' [R] */ + entry = create_proc_entry(ACPI_BATTERY_FILE_INFO, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_BATTERY_FILE_INFO)); + else { + entry->read_proc = acpi_battery_read_info; + entry->data = acpi_driver_data(device); + } + + /* 'status' [R] */ + entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_BATTERY_FILE_STATUS)); + else { + entry->read_proc = acpi_battery_read_state; + entry->data = acpi_driver_data(device); + } + + /* 'alarm' [R/W] */ + entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_BATTERY_FILE_ALARM)); + else { + entry->read_proc = acpi_battery_read_alarm; + entry->write_proc = acpi_battery_write_alarm; + entry->data = acpi_driver_data(device); + } + + return_VALUE(0); +} + + +static int +acpi_battery_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_battery_remove_fs"); + + if (!acpi_battery_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +static void +acpi_battery_notify ( + acpi_handle handle, + u32 event, + void *data) +{ + struct acpi_battery *battery = (struct acpi_battery *) data; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_battery_notify"); + + if (!battery) + return_VOID; + + if (0 != acpi_bus_get_device(handle, &device)) + return_VOID; + + switch (event) { + case ACPI_BATTERY_NOTIFY_STATUS: + case ACPI_BATTERY_NOTIFY_INFO: + acpi_battery_check(battery); + acpi_bus_generate_event(device, event, battery->flags.present); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + return_VOID; +} + + +static int +acpi_battery_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = 0; + struct acpi_battery *battery = NULL; + + ACPI_FUNCTION_TRACE("acpi_battery_add"); + + if (!device) + return_VALUE(-EINVAL); + + battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL); + if (!battery) + return_VALUE(-ENOMEM); + memset(battery, 0, sizeof(struct acpi_battery)); + + battery->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_BATTERY_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_BATTERY_CLASS); + acpi_driver_data(device) = battery; + + result = acpi_battery_check(battery); + if (0 != result) + goto end; + + result = acpi_battery_add_fs(device); + if (0 != result) + goto end; + + status = acpi_install_notify_handler(battery->handle, + ACPI_DEVICE_NOTIFY, acpi_battery_notify, battery); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error installing notify handler\n")); + result = -ENODEV; + goto end; + } + + printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), + device->status.battery_present?"present":"absent"); + +end: + if (0 != result) { + acpi_battery_remove_fs(device); + kfree(battery); + } + + return_VALUE(result); +} + + +static int +acpi_battery_remove ( + struct acpi_device *device, + int type) +{ + acpi_status status = 0; + struct acpi_battery *battery = NULL; + + ACPI_FUNCTION_TRACE("acpi_battery_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + battery = (struct acpi_battery *) acpi_driver_data(device); + + status = acpi_remove_notify_handler(battery->handle, + ACPI_DEVICE_NOTIFY, acpi_battery_notify); + if (ACPI_FAILURE(status)) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error removing notify handler\n")); + + acpi_battery_remove_fs(device); + + kfree(battery); + + return_VALUE(0); +} + + +static int __init +acpi_battery_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_battery_init"); + + result = acpi_bus_register_driver(&acpi_battery_driver); + if (0 > result) { + remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + + +static void __exit +acpi_battery_exit (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_battery_exit"); + + result = acpi_bus_unregister_driver(&acpi_battery_driver); + if (0 == result) + remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); + + return_VOID; +} + + +module_init(acpi_battery_init); +module_exit(acpi_battery_exit); diff -Nur linux-2.4.19/drivers/acpi/bus.c linux-2.4.19-sgi211r3/drivers/acpi/bus.c --- linux-2.4.19/drivers/acpi/bus.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/bus.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,2200 @@ +/* + * acpi_bus.c - ACPI Bus Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" +#include "include/acinterp.h" /* for acpi_ex_eisa_id_to_string() */ + + +#define _COMPONENT ACPI_BUS_COMPONENT +ACPI_MODULE_NAME ("acpi_bus") + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION(ACPI_BUS_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +#define PREFIX "ACPI: " + +FADT_DESCRIPTOR acpi_fadt; +static u8 acpi_disabled; +struct acpi_device *acpi_root; +struct proc_dir_entry *acpi_root_dir; + +#define STRUCT_TO_INT(s) (*((int*)&s)) + +/* + * POLICY: If *anything* doesn't work, put it on the blacklist. + * If they are critical errors, mark it critical, and abort driver load. + */ +static struct acpi_blacklist_item acpi_blacklist[] __initdata = +{ + /* Portege 7020, BIOS 8.10 */ + {"TOSHIB", "7020CT ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0}, + /* Portege 4030 */ + {"TOSHIB", "4030 ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0}, + /* Portege 310/320, BIOS 7.1 */ + {"TOSHIB", "310 ", 0x19990511, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0}, + /* Seattle 2, old bios rev. */ + {"INTEL ", "440BX ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0}, + /* ASUS K7M */ + {"ASUS ", "K7M ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0}, + /* Intel 810 Motherboard? */ + {"MNTRAL", "MO81010A", 0x00000012, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0}, + /* Compaq Presario 1700 */ + {"PTLTD ", " DSDT ", 0x06040000, ACPI_TABLE_DSDT, less_than_or_equal, "Multiple problems", 1}, + /* Sony FX120, FX140, FX150? */ + {"SONY ", "U0 ", 0x20010313, ACPI_TABLE_DSDT, less_than_or_equal, "ACPI driver problem", 1}, + /* Compaq Presario 800, Insyde BIOS */ + {"INT440", "SYSFexxx", 0x00001001, ACPI_TABLE_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1}, + /* IBM 600E - _ADR should return 7, but it returns 1 */ + {"IBM ", "TP600E ", 0x00000105, ACPI_TABLE_DSDT, less_than_or_equal, "Incorrect _ADR", 1}, + {""} +}; + + +/* -------------------------------------------------------------------------- + Linux Driver Model (LDM) Support + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_LDM + +static int acpi_device_probe(struct device *dev); +static int acpi_device_remove(struct device *dev, u32 flags); +static int acpi_device_suspend(struct device *dev, u32 state, u32 stage); +static int acpi_device_resume(struct device *dev, u32 stage); + +static struct device_driver acpi_bus_driver = { + probe: acpi_device_probe, + remove: acpi_device_remove, + suspend: acpi_device_suspend, + resume: acpi_device_resume, +}; + + +static int +acpi_device_probe ( + struct device *dev) +{ + ACPI_FUNCTION_TRACE("acpi_device_probe"); + + if (!dev) + return_VALUE(-EINVAL); + + /* TBD */ + + return_VALUE(0); +} + + +static int +acpi_device_remove ( + struct device *dev, + u32 flags) +{ + ACPI_FUNCTION_TRACE("acpi_device_remove"); + + if (!dev) + return_VALUE(-EINVAL); + + /* TBD */ + + return_VALUE(0); +} + + +static int +acpi_device_suspend ( + struct device *dev, + u32 state, + u32 stage) +{ + ACPI_FUNCTION_TRACE("acpi_device_suspend"); + + if (!dev) + return_VALUE(-EINVAL); + + /* TBD */ + + return_VALUE(0); +} + + +static int +acpi_device_resume ( + struct device *dev, + u32 stage) +{ + ACPI_FUNCTION_TRACE("acpi_device_resume"); + + if (!dev) + return_VALUE(-EINVAL); + + /* TBD */ + + return_VALUE(0); +} + +#if 0 /* not used ATM */ +static int +acpi_platform_add ( + struct device *dev) +{ + ACPI_FUNCTION_TRACE("acpi_platform_add"); + + if (!dev) + return -EINVAL; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) added\n", + dev->name, dev->bus_id)); + + /* TBD */ + + return_VALUE(0); +} + + +static int +acpi_platform_remove ( + struct device *dev) +{ + ACPI_FUNCTION_TRACE("acpi_platform_add"); + + if (!dev) + return -EINVAL; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) removed\n", + dev->name, dev->bus_id)); + + /* TBD */ + + return_VALUE(0); +} +#endif /* unused */ + + +#endif /*CONFIG_LDM*/ + + +static int +acpi_device_register ( + struct acpi_device *device, + struct acpi_device *parent) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_device_register"); + + if (!device) + return_VALUE(-EINVAL); + +#ifdef CONFIG_LDM + sprintf(device->dev.name, "ACPI device %s:%s", + device->pnp.hardware_id, device->pnp.unique_id); + strncpy(device->dev.bus_id, device->pnp.bus_id, sizeof(acpi_bus_id)); + if (parent) + device->dev.parent = &parent->dev; + device->dev.driver = &acpi_bus_driver; + + result = device_register(&device->dev); +#endif /*CONFIG_LDM*/ + + return_VALUE(result); +} + + +static int +acpi_device_unregister ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_device_unregister"); + + if (!device) + return_VALUE(-EINVAL); + +#ifdef CONFIG_LDM + put_device(&device->dev); +#endif /*CONFIG_LDM*/ + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Device Management + -------------------------------------------------------------------------- */ + +static void +acpi_bus_data_handler ( + acpi_handle handle, + u32 function, + void *context) +{ + ACPI_FUNCTION_TRACE("acpi_bus_data_handler"); + + /* TBD */ + + return_VOID; +} + + +int +acpi_bus_get_device ( + acpi_handle handle, + struct acpi_device **device) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE("acpi_bus_get_device"); + + if (!device) + return_VALUE(-EINVAL); + + /* TBD: Support fixed-feature devices */ + + status = acpi_get_data(handle, acpi_bus_data_handler, (void**) device); + if (ACPI_FAILURE(status) || !*device) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error getting context for object [%p]\n", + handle)); + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + +int +acpi_bus_get_status ( + struct acpi_device *device) +{ + acpi_status status = AE_OK; + unsigned long sta = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_get_status"); + + if (!device) + return_VALUE(-EINVAL); + + /* + * Evaluate _STA if present. + */ + if (device->flags.dynamic_status) { + status = acpi_evaluate_integer(device->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + STRUCT_TO_INT(device->status) = (int) sta; + } + + /* + * Otherwise we assume the status of our parent (unless we don't + * have one, in which case status is implied). + */ + else if (device->parent) + device->status = device->parent->status; + else + STRUCT_TO_INT(device->status) = 0x0F; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", + device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status))); + + return_VALUE(0); +} + + +/* +static int +acpi_bus_create_device_fs (struct device *device) +{ + ACPI_FUNCTION_TRACE("acpi_bus_create_device_fs"); + + if (!device) + return_VALUE(-EINVAL); + + if (device->dir.entry) + return_VALUE(-EEXIST); + + if (!device->parent) + device->dir.entry = proc_mkdir(device->pnp.bus_id, NULL); + else + device->dir.entry = proc_mkdir(device->pnp.bus_id, + device->parent->fs.entry); + + if (!device->dir.entry) { + printk(KERN_ERR PREFIX "Unable to create fs entry '%s'\n", + device->pnp.bus_id); + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + + +static int +acpi_bus_remove_device_fs (struct device *device) +{ + ACPI_FUNCTION_TRACE("acpi_bus_create_device_fs"); + + if (!device) + return_VALUE(-EINVAL); + + if (!device->dir.entry) + return_VALUE(-ENODEV); + + if (!device->parent) + remove_proc_entry(device->pnp_bus_id, NULL); + else + remove_proc_entry(device->pnp.bus_id, device->parent->fs.entry); + + device->dir.entry = NULL; + + return_VALUE(0); +} +*/ + + +/* -------------------------------------------------------------------------- + Power Management + -------------------------------------------------------------------------- */ + +int +acpi_bus_get_power ( + acpi_handle handle, + int *state) +{ + int result = 0; + acpi_status status = 0; + struct acpi_device *device = NULL; + unsigned long psc = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_get_power"); + + result = acpi_bus_get_device(handle, &device); + if (0 != result) + return_VALUE(result); + + *state = ACPI_STATE_UNKNOWN; + + if (!device->flags.power_manageable) { + /* TBD: Non-recursive algorithm for walking up hierarchy */ + if (device->parent) + *state = device->parent->power.state; + else + *state = ACPI_STATE_D0; + } + else { + /* + * Get the device's power state either directly (via _PSC) or + * indirectly (via power resources). + */ + if (device->power.flags.explicit_get) { + status = acpi_evaluate_integer(device->handle, "_PSC", + NULL, &psc); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + device->power.state = (int) psc; + } + else if (device->power.flags.power_resources) { + result = acpi_power_get_inferred_state(device); + if (0 != result) + return_VALUE(result); + } + + *state = device->power.state; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", + device->pnp.bus_id, device->power.state)); + + return_VALUE(0); +} + + +int +acpi_bus_set_power ( + acpi_handle handle, + int state) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_device *device = NULL; + char object_name[5] = {'_','P','S','0'+state,'\0'}; + + ACPI_FUNCTION_TRACE("acpi_bus_set_power"); + + result = acpi_bus_get_device(handle, &device); + if (0 != result) + return_VALUE(result); + + if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) + return_VALUE(-EINVAL); + + /* Make sure this is a valid target state */ + + if (!device->flags.power_manageable) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n")); + return_VALUE(-ENODEV); + } + if (state == device->power.state) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); + return_VALUE(0); + } + if (!device->power.states[state].flags.valid) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n", state)); + return_VALUE(-ENODEV); + } + if (device->parent && (state < device->parent->power.state)) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Cannot set device to a higher-powered state than parent\n")); + return_VALUE(-ENODEV); + } + + /* + * Transition Power + * ---------------- + * On transitions to a high-powered state we first apply power (via + * power resources) then evalute _PSx. Conversly for transitions to + * a lower-powered state. + */ + if (state < device->power.state) { + if (device->power.flags.power_resources) { + result = acpi_power_transition(device, state); + if (0 != result) + goto end; + } + if (device->power.states[state].flags.explicit_set) { + status = acpi_evaluate_object(device->handle, + object_name, NULL, NULL); + if (ACPI_FAILURE(status)) { + result = -ENODEV; + goto end; + } + } + } + else { + if (device->power.states[state].flags.explicit_set) { + status = acpi_evaluate_object(device->handle, + object_name, NULL, NULL); + if (ACPI_FAILURE(status)) { + result = -ENODEV; + goto end; + } + } + if (device->power.flags.power_resources) { + result = acpi_power_transition(device, state); + if (0 != result) + goto end; + } + } + +end: + if (0 != result) + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error transitioning device [%s] to D%d\n", + device->pnp.bus_id, state)); + else + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to D%d\n", + device->pnp.bus_id, state)); + + return_VALUE(result); +} + + +static int +acpi_bus_get_power_flags ( + struct acpi_device *device) +{ + acpi_status status = 0; + acpi_handle handle = 0; + u32 i = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags"); + + if (!device) + return -ENODEV; + + /* + * Power Management Flags + */ + status = acpi_get_handle(device->handle, "_PSC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.explicit_get = 1; + status = acpi_get_handle(device->handle, "_IRC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.inrush_current = 1; + status = acpi_get_handle(device->handle, "_PRW", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.wake_capable = 1; + + /* + * Enumerate supported power management states + */ + for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { + struct acpi_device_power_state *ps = &device->power.states[i]; + char object_name[5] = {'_','P','R','0'+i,'\0'}; + + /* Evaluate "_PRx" to se if power resources are referenced */ + acpi_evaluate_reference(device->handle, object_name, NULL, + &ps->resources); + if (ps->resources.count) { + device->power.flags.power_resources = 1; + ps->flags.valid = 1; + } + + /* Evaluate "_PSx" to see if we can do explicit sets */ + object_name[2] = 'S'; + status = acpi_get_handle(device->handle, object_name, &handle); + if (ACPI_SUCCESS(status)) { + ps->flags.explicit_set = 1; + ps->flags.valid = 1; + } + + /* State is valid if we have some power control */ + if (ps->resources.count || ps->flags.explicit_set) + ps->flags.valid = 1; + + ps->power = -1; /* Unknown - driver assigned */ + ps->latency = -1; /* Unknown - driver assigned */ + } + + /* Set defaults for D0 and D3 states (always valid) */ + device->power.states[ACPI_STATE_D0].flags.valid = 1; + device->power.states[ACPI_STATE_D0].power = 100; + device->power.states[ACPI_STATE_D3].flags.valid = 1; + device->power.states[ACPI_STATE_D3].power = 0; + + /* + * System Power States + * ------------------- + */ + /* TBD: S1-S4 power state support and resource requirements. */ + /* + for (i=ACPI_STATE_S1; ihandle, name, NULL, + &state); + if (ACPI_FAILURE(status)) + continue; + } + */ + + /* TBD: System wake support and resource requirements. */ + + device->power.state = ACPI_STATE_UNKNOWN; + + return 0; +} + + +/* -------------------------------------------------------------------------- + Performance Management + -------------------------------------------------------------------------- */ + +static int +acpi_bus_get_perf_flags ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_bus_get_perf_flags"); + + if (!device) + return -ENODEV; + + device->performance.state = ACPI_STATE_UNKNOWN; + + return 0; +} + + +/* -------------------------------------------------------------------------- + Event Management + -------------------------------------------------------------------------- */ + +static spinlock_t acpi_bus_event_lock = SPIN_LOCK_UNLOCKED; + +LIST_HEAD(acpi_bus_event_list); +DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); + +extern int event_is_open; + +int +acpi_bus_generate_event ( + struct acpi_device *device, + u8 type, + int data) +{ + struct acpi_bus_event *event = NULL; + u32 flags = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_generate_event"); + + if (!device) + return_VALUE(-EINVAL); + + /* drop event on the floor if no one's listening */ + if (!event_is_open) + return_VALUE(0); + + event = kmalloc(sizeof(struct acpi_bus_event), GFP_KERNEL); + if (!event) + return_VALUE(-ENOMEM); + + sprintf(event->device_class, "%s", device->pnp.device_class); + sprintf(event->bus_id, "%s", device->pnp.bus_id); + event->type = type; + event->data = data; + + spin_lock_irqsave(&acpi_bus_event_lock, flags); + list_add_tail(&event->node, &acpi_bus_event_list); + spin_unlock_irqrestore(&acpi_bus_event_lock, flags); + + wake_up_interruptible(&acpi_bus_event_queue); + + return_VALUE(0); +} + +int +acpi_bus_receive_event ( + struct acpi_bus_event *event) +{ + u32 flags = 0; + struct acpi_bus_event *entry = NULL; + + DECLARE_WAITQUEUE(wait, current); + + ACPI_FUNCTION_TRACE("acpi_bus_receive_event"); + + if (!event) + return -EINVAL; + + if (list_empty(&acpi_bus_event_list)) { + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&acpi_bus_event_queue, &wait); + + if (list_empty(&acpi_bus_event_list)) + schedule(); + + remove_wait_queue(&acpi_bus_event_queue, &wait); + set_current_state(TASK_RUNNING); + + if (signal_pending(current)) + return_VALUE(-ERESTARTSYS); + } + + spin_lock_irqsave(&acpi_bus_event_lock, flags); + entry = list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node); + if (entry) + list_del(&entry->node); + spin_unlock_irqrestore(&acpi_bus_event_lock, flags); + + if (!entry) + return_VALUE(-ENODEV); + + memcpy(event, entry, sizeof(struct acpi_bus_event)); + + kfree(entry); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Namespace Management + -------------------------------------------------------------------------- */ + +#define WALK_UP 0 +#define WALK_DOWN 1 + +typedef int (*acpi_bus_walk_callback)(struct acpi_device*, int, void*); + +#define HAS_CHILDREN(d) ((d)->children.next != &((d)->children)) +#define HAS_SIBLINGS(d) (((d)->parent) && ((d)->node.next != &(d)->parent->children)) +#define NODE_TO_DEVICE(n) (list_entry(n, struct acpi_device, node)) + + +/** + * acpi_bus_walk + * ------------- + * Used to walk the ACPI Bus's device namespace. Can walk down (depth-first) + * or up. Able to parse starting at any node in the namespace. Note that a + * callback return value of -ELOOP will terminate the walk. + * + * @start: starting point + * callback: function to call for every device encountered while parsing + * direction: direction to parse (up or down) + * @data: context for this search operation + */ +static int +acpi_bus_walk ( + struct acpi_device *start, + acpi_bus_walk_callback callback, + int direction, + void *data) +{ + int result = 0; + int level = 0; + struct acpi_device *device = NULL; + + if (!start || !callback) + return -EINVAL; + + device = start; + + /* + * Parse Namespace + * --------------- + * Parse a given subtree (specified by start) in the given direction. + * Walking 'up' simply means that we execute the callback on leaf + * devices prior to their parents (useful for things like removing + * or powering down a subtree). + */ + + while (device) { + + if (direction == WALK_DOWN) + if (-ELOOP == callback(device, level, data)) + break; + + /* Depth First */ + + if (HAS_CHILDREN(device)) { + device = NODE_TO_DEVICE(device->children.next); + ++level; + continue; + } + + if (direction == WALK_UP) + if (-ELOOP == callback(device, level, data)) + break; + + /* Now Breadth */ + + if (HAS_SIBLINGS(device)) { + device = NODE_TO_DEVICE(device->node.next); + continue; + } + + /* Scope Exhausted - Find Next */ + + while ((device = device->parent)) { + --level; + if (HAS_SIBLINGS(device)) { + device = NODE_TO_DEVICE(device->node.next); + break; + } + } + } + + if ((direction == WALK_UP) && (result == 0)) + callback(start, level, data); + + return result; +} + + +/* -------------------------------------------------------------------------- + Notification Handling + -------------------------------------------------------------------------- */ + +static int +acpi_bus_check_device ( + struct acpi_device *device, + int *status_changed) +{ + acpi_status status = 0; + struct acpi_device_status old_status; + + ACPI_FUNCTION_TRACE("acpi_bus_check_device"); + + if (!device) + return_VALUE(-EINVAL); + + if (status_changed) + *status_changed = 0; + + old_status = device->status; + + /* + * Make sure this device's parent is present before we go about + * messing with the device. + */ + if (device->parent && !device->parent->status.present) { + device->status = device->parent->status; + if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) { + if (status_changed) + *status_changed = 1; + } + return_VALUE(0); + } + + status = acpi_bus_get_status(device); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) + return_VALUE(0); + + if (status_changed) + *status_changed = 1; + + /* + * Device Insertion/Removal + */ + if ((device->status.present) && !(old_status.present)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n")); + /* TBD: Handle device insertion */ + } + else if (!(device->status.present) && (old_status.present)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n")); + /* TBD: Handle device removal */ + } + + return_VALUE(0); +} + + +static int +acpi_bus_check_scope ( + struct acpi_device *device) +{ + int result = 0; + int status_changed = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_check_scope"); + + if (!device) + return_VALUE(-EINVAL); + + /* Status Change? */ + result = acpi_bus_check_device(device, &status_changed); + if (0 != result) + return_VALUE(result); + + if (!status_changed) + return_VALUE(0); + + /* + * TBD: Enumerate child devices within this device's scope and + * run acpi_bus_check_device()'s on them. + */ + + return_VALUE(0); +} + + +/** + * acpi_bus_notify + * --------------- + * Callback for all 'system-level' device notifications (values 0x00-0x7F). + */ +static void +acpi_bus_notify ( + acpi_handle handle, + u32 type, + void *data) +{ + int result = 0; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_notify"); + + if (0 != acpi_bus_get_device(handle, &device)) + return_VOID; + + switch (type) { + + case ACPI_NOTIFY_BUS_CHECK: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received BUS CHECK notification for device [%s]\n", + device->pnp.bus_id)); + result = acpi_bus_check_scope(device); + /* + * TBD: We'll need to outsource certain events to non-ACPI + * drivers via the device manager (device.c). + */ + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received DEVICE CHECK notification for device [%s]\n", + device->pnp.bus_id)); + result = acpi_bus_check_device(device, NULL); + /* + * TBD: We'll need to outsource certain events to non-ACPI + * drivers via the device manager (device.c). + */ + break; + + case ACPI_NOTIFY_DEVICE_WAKE: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received DEVICE WAKE notification for device [%s]\n", + device->pnp.bus_id)); + /* TBD */ + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received EJECT REQUEST notification for device [%s]\n", + device->pnp.bus_id)); + /* TBD */ + break; + + case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received DEVICE CHECK LIGHT notification for device [%s]\n", + device->pnp.bus_id)); + /* TBD: Exactly what does 'light' mean? */ + break; + + case ACPI_NOTIFY_FREQUENCY_MISMATCH: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received FREQUENCY MISMATCH notification for device [%s]\n", + device->pnp.bus_id)); + /* TBD */ + break; + + case ACPI_NOTIFY_BUS_MODE_MISMATCH: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received BUS MODE MISMATCH notification for device [%s]\n", + device->pnp.bus_id)); + /* TBD */ + break; + + case ACPI_NOTIFY_POWER_FAULT: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received POWER FAULT notification for device [%s]\n", + device->pnp.bus_id)); + /* TBD */ + break; + + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received unknown/unsupported notification [%08x]\n", + type)); + break; + } + + return_VOID; +} + + +/* -------------------------------------------------------------------------- + Driver Management + -------------------------------------------------------------------------- */ + +static LIST_HEAD(acpi_bus_drivers); +static DECLARE_MUTEX(acpi_bus_drivers_lock); + + +/** + * acpi_bus_match + * -------------- + * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it + * matches the specified driver's criteria. + */ +static int +acpi_bus_match ( + struct acpi_device *device, + struct acpi_driver *driver) +{ + + if (!device || !driver) + return -EINVAL; + + if (device->flags.hardware_id) { + if (0 != strstr(driver->ids, device->pnp.hardware_id)) + return 0; + } + + if (device->flags.compatible_ids) { + acpi_status status = AE_OK; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_object *object = NULL; + char cid[256]; + + memset(cid, 0, sizeof(cid)); + + status = acpi_evaluate_object(device->handle, "_CID", NULL, + &buffer); + if (ACPI_FAILURE(status) || !buffer.pointer) + return -ENOENT; + + object = (acpi_object *) buffer.pointer; + + switch (object->type) { + case ACPI_TYPE_INTEGER: + acpi_ex_eisa_id_to_string((u32) object->integer.value, + cid); + break; + case ACPI_TYPE_STRING: + strncpy(cid, object->string.pointer, sizeof(cid) - 1); + break; + case ACPI_TYPE_PACKAGE: + /* TBD: Support CID packages */ + break; + } + + if (!cid[0]) + return -ENOENT; + + if (0 != strstr(driver->ids, cid)) + return 0; + } + + return -ENOENT; +} + + +/** + * acpi_bus_driver_init + * -------------------- + * Used to initialize a device via its device driver. Called whenever a + * driver is bound to a device. Invokes the driver's add() and start() ops. + */ +static int +acpi_bus_driver_init ( + struct acpi_device *device, + struct acpi_driver *driver) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_driver_init"); + + if (!device || !driver) + return_VALUE(-EINVAL); + + if (!driver->ops.add) + return_VALUE(-ENOSYS); + + result = driver->ops.add(device); + if (0 != result) { + device->driver = NULL; + acpi_driver_data(device) = NULL; + return_VALUE(result); + } + + /* + * TBD - Configuration Management: Assign resources to device based + * upon possible configuration and currently allocated resources. + */ + + if (driver->ops.start) { + result = driver->ops.start(device); + if ((0 != result) && (driver->ops.remove)) + driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); + return_VALUE(result); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); + +#ifdef CONFIG_LDM + /* + * Update the device information (in the global device hierarchy) now + * that there's a driver bound to it. + */ + strncpy(device->dev.name, device->pnp.device_name, + sizeof(device->dev.name)); +#endif + + if (driver->ops.scan) { + driver->ops.scan(device); + } + + return_VALUE(0); +} + + +/** + * acpi_bus_attach + * ------------- + * Callback for acpi_bus_walk() used to find devices that match a specific + * driver's criteria and then attach the driver. + */ +static int +acpi_bus_attach ( + struct acpi_device *device, + int level, + void *data) +{ + int result = 0; + struct acpi_driver *driver = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_attach"); + + if (!device || !data) + return_VALUE(-EINVAL); + + driver = (struct acpi_driver *) data; + + if (device->driver) + return_VALUE(-EEXIST); + + if (!device->status.present) + return_VALUE(-ENODEV); + + result = acpi_bus_match(device, driver); + if (0 != result) + return_VALUE(result); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", + driver->name, device->pnp.bus_id)); + + result = acpi_bus_driver_init(device, driver); + if (0 != result) + return_VALUE(result); + + down(&acpi_bus_drivers_lock); + ++driver->references; + up(&acpi_bus_drivers_lock); + + return_VALUE(0); +} + + +/** + * acpi_bus_unattach + * ----------------- + * Callback for acpi_bus_walk() used to find devices that match a specific + * driver's criteria and unattach the driver. + */ +static int +acpi_bus_unattach ( + struct acpi_device *device, + int level, + void *data) +{ + int result = 0; + struct acpi_driver *driver = (struct acpi_driver *) data; + + ACPI_FUNCTION_TRACE("acpi_bus_unattach"); + + if (!device || !driver) + return_VALUE(-EINVAL); + + if (device->driver != driver) + return_VALUE(-ENOENT); + + if (!driver->ops.remove) + return_VALUE(-ENOSYS); + + result = driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); + if (0 != result) + return_VALUE(result); + + device->driver = NULL; + acpi_driver_data(device) = NULL; + + down(&acpi_bus_drivers_lock); + driver->references--; + up(&acpi_bus_drivers_lock); + + return_VALUE(0); +} + + +/** + * acpi_bus_find_driver + * -------------------- + * Parses the list of registered drivers looking for a driver applicable for + * the specified device. + */ +static int +acpi_bus_find_driver ( + struct acpi_device *device) +{ + int result = -ENODEV; + struct list_head *entry = NULL; + struct acpi_driver *driver = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_find_driver"); + + if (!device || device->driver) + return_VALUE(-EINVAL); + + down(&acpi_bus_drivers_lock); + + list_for_each(entry, &acpi_bus_drivers) { + + driver = list_entry(entry, struct acpi_driver, node); + + if (0 != acpi_bus_match(device, driver)) + continue; + + result = acpi_bus_driver_init(device, driver); + if (0 == result) + ++driver->references; + + break; + } + + up(&acpi_bus_drivers_lock); + + return_VALUE(result); +} + + +/** + * acpi_bus_register_driver + * ------------------------ + * Registers a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and binds. + */ +int +acpi_bus_register_driver ( + struct acpi_driver *driver) +{ + ACPI_FUNCTION_TRACE("acpi_bus_register_driver"); + + if (!driver) + return_VALUE(-EINVAL); + + down(&acpi_bus_drivers_lock); + list_add_tail(&driver->node, &acpi_bus_drivers); + up(&acpi_bus_drivers_lock); + + acpi_bus_walk(acpi_root, acpi_bus_attach, + WALK_DOWN, driver); + + return_VALUE(driver->references); +} + + +/** + * acpi_bus_unregister_driver + * -------------------------- + * Unregisters a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and unbinds. + */ +int +acpi_bus_unregister_driver ( + struct acpi_driver *driver) +{ + ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver"); + + if (!driver) + return_VALUE(-EINVAL); + + acpi_bus_walk(acpi_root, acpi_bus_unattach, WALK_UP, driver); + + if (driver->references) + return_VALUE(driver->references); + + down(&acpi_bus_drivers_lock); + list_del(&driver->node); + up(&acpi_bus_drivers_lock); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Device Enumeration + -------------------------------------------------------------------------- */ + +static int +acpi_bus_get_flags ( + struct acpi_device *device) +{ + acpi_status status = AE_OK; + acpi_handle temp = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_get_flags"); + + /* Presence of _STA indicates 'dynamic_status' */ + status = acpi_get_handle(device->handle, "_STA", &temp); + if (ACPI_SUCCESS(status)) + device->flags.dynamic_status = 1; + + /* Presence of _CID indicates 'compatible_ids' */ + status = acpi_get_handle(device->handle, "_CID", &temp); + if (ACPI_SUCCESS(status)) + device->flags.compatible_ids = 1; + + /* Presence of _RMV indicates 'removable' */ + status = acpi_get_handle(device->handle, "_RMV", &temp); + if (ACPI_SUCCESS(status)) + device->flags.removable = 1; + + /* Presence of _EJD|_EJ0 indicates 'ejectable' */ + status = acpi_get_handle(device->handle, "_EJD", &temp); + if (ACPI_SUCCESS(status)) + device->flags.ejectable = 1; + else { + status = acpi_get_handle(device->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + device->flags.ejectable = 1; + } + + /* Presence of _LCK indicates 'lockable' */ + status = acpi_get_handle(device->handle, "_LCK", &temp); + if (ACPI_SUCCESS(status)) + device->flags.lockable = 1; + + /* Presence of _PS0|_PR0 indicates 'power manageable' */ + status = acpi_get_handle(device->handle, "_PS0", &temp); + if (ACPI_FAILURE(status)) + status = acpi_get_handle(device->handle, "_PR0", &temp); + if (ACPI_SUCCESS(status)) + device->flags.power_manageable = 1; + + /* TBD: Peformance management */ + + return_VALUE(0); +} + + +static int +acpi_bus_add ( + struct acpi_device **child, + struct acpi_device *parent, + acpi_handle handle, + int type) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_device *device = NULL; + char bus_id[5] = {'?',0}; + acpi_buffer buffer = {sizeof(bus_id), bus_id}; + acpi_device_info info; + char *hid = NULL; + char *uid = NULL; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_add"); + + if (!child) + return_VALUE(-EINVAL); + + device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL); + if (!device) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n")); + return_VALUE(-ENOMEM); + } + memset(device, 0, sizeof(struct acpi_device)); + + device->handle = handle; + device->parent = parent; + + memset(&info, 0, sizeof(acpi_device_info)); + + /* + * Bus ID + * ------ + * The device's Bus ID is simply the object name. + * TBD: Shouldn't this value be unique (within the ACPI namespace)? + */ + switch (type) { + case ACPI_BUS_TYPE_SYSTEM: + sprintf(device->pnp.bus_id, "%s", "ACPI"); + break; + case ACPI_BUS_TYPE_POWER_BUTTON: + sprintf(device->pnp.bus_id, "%s", "PWRF"); + break; + case ACPI_BUS_TYPE_SLEEP_BUTTON: + sprintf(device->pnp.bus_id, "%s", "SLPF"); + break; + default: + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + /* Clean up trailing underscores (if any) */ + for (i = 3; i > 1; i--) { + if (bus_id[i] == '_') + bus_id[i] = '\0'; + else + break; + } + sprintf(device->pnp.bus_id, "%s", bus_id); + break; + } + + /* + * Flags + * ----- + * Get prior to calling acpi_bus_get_status() so we know whether + * or not _STA is present. Note that we only look for object + * handles -- cannot evaluate objects until we know the device is + * present and properly initialized. + */ + result = acpi_bus_get_flags(device); + if (0 != result) + goto end; + + /* + * Status + * ------ + * See if the device is present. We always assume that non-Device() + * objects (e.g. thermal zones, power resources, processors, etc.) are + * present, functioning, etc. (at least when parent object is present). + * Note that _STA has a different meaning for some objects (e.g. + * power resources) so we need to be careful how we use it. + */ + switch (type) { + case ACPI_BUS_TYPE_DEVICE: + result = acpi_bus_get_status(device); + if (0 != result) + goto end; + break; + default: + STRUCT_TO_INT(device->status) = 0x0F; + break; + } + if (!device->status.present) { + result = -ENOENT; + goto end; + } + + /* + * Initialize Device + * ----------------- + * TBD: Synch with Core's enumeration/initialization process. + */ + + /* + * Hardware ID, Unique ID, & Bus Address + * ------------------------------------- + */ + switch (type) { + case ACPI_BUS_TYPE_DEVICE: + status = acpi_get_object_info(handle, &info); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error reading device info\n")); + result = -ENODEV; + goto end; + } + /* Clean up info strings (not NULL terminated) */ + info.hardware_id[sizeof(info.hardware_id)-1] = '\0'; + info.unique_id[sizeof(info.unique_id)-1] = '\0'; + if (info.valid & ACPI_VALID_HID) + hid = info.hardware_id; + if (info.valid & ACPI_VALID_UID) + uid = info.unique_id; + if (info.valid & ACPI_VALID_ADR) { + device->pnp.bus_address = info.address; + device->flags.bus_address = 1; + } + break; + case ACPI_BUS_TYPE_POWER: + hid = ACPI_POWER_HID; + break; + case ACPI_BUS_TYPE_PROCESSOR: + hid = ACPI_PROCESSOR_HID; + break; + case ACPI_BUS_TYPE_SYSTEM: + hid = ACPI_SYSTEM_HID; + break; + case ACPI_BUS_TYPE_THERMAL: + hid = ACPI_THERMAL_HID; + break; + case ACPI_BUS_TYPE_POWER_BUTTON: + hid = ACPI_BUTTON_HID_POWERF; + break; + case ACPI_BUS_TYPE_SLEEP_BUTTON: + hid = ACPI_BUTTON_HID_SLEEPF; + break; + } + + /* + * \_SB + * ---- + * Fix for the system root bus device -- the only root-level device. + */ + if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { + hid = ACPI_BUS_HID; + sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME); + sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS); + } + + if (hid) { + sprintf(device->pnp.hardware_id, "%s", hid); + device->flags.hardware_id = 1; + } + if (uid) { + sprintf(device->pnp.unique_id, "%s", uid); + device->flags.unique_id = 1; + } + + /* + * Power Management + * ---------------- + */ + if (device->flags.power_manageable) { + result = acpi_bus_get_power_flags(device); + if (0 != result) + goto end; + } + + /* + * Performance Management + * ---------------------- + */ + if (device->flags.performance_manageable) { + result = acpi_bus_get_perf_flags(device); + if (0 != result) + goto end; + } + + /* + * Context + * ------- + * Attach this 'struct acpi_device' to the ACPI object. This makes + * resolutions from handle->device very efficient. Note that we need + * to be careful with fixed-feature devices as they all attach to the + * root object. + */ + switch (type) { + case ACPI_BUS_TYPE_POWER_BUTTON: + case ACPI_BUS_TYPE_SLEEP_BUTTON: + break; + default: + status = acpi_attach_data(device->handle, + acpi_bus_data_handler, device); + break; + } + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error attaching device data\n")); + result = -ENODEV; + goto end; + } + + /* + * Linkage + * ------- + * Link this device to its parent and siblings. + */ + INIT_LIST_HEAD(&device->children); + if (!device->parent) + INIT_LIST_HEAD(&device->node); + else + list_add_tail(&device->node, &device->parent->children); + +#ifdef CONFIG_ACPI_DEBUG + { + char *type_string = NULL; + char name[80] = {'?','\0'}; + acpi_buffer buffer = {sizeof(name), name}; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + switch (type) { + case ACPI_BUS_TYPE_DEVICE: + type_string = "Device"; + break; + case ACPI_BUS_TYPE_POWER: + type_string = "Power Resource"; + break; + case ACPI_BUS_TYPE_PROCESSOR: + type_string = "Processor"; + break; + case ACPI_BUS_TYPE_SYSTEM: + type_string = "System"; + break; + case ACPI_BUS_TYPE_THERMAL: + type_string = "Thermal Zone"; + break; + case ACPI_BUS_TYPE_POWER_BUTTON: + type_string = "Power Button"; + sprintf(name, "PWRB"); + break; + case ACPI_BUS_TYPE_SLEEP_BUTTON: + type_string = "Sleep Button"; + sprintf(name, "SLPB"); + break; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s %s [%p]\n", + type_string, name, handle)); + } +#endif /*CONFIG_ACPI_DEBUG*/ + + /* + * Global Device Hierarchy: + * ------------------------ + * Register this device with the global device hierarchy. + */ + acpi_device_register(device, parent); + + /* + * Bind _ADR-Based Devices + * ----------------------- + * If there's a a bus address (_ADR) then we utilize the parent's + * 'bind' function (if exists) to bind the ACPI- and natively- + * enumerated device representations. + */ + if (device->flags.bus_address) { + if (device->parent && device->parent->ops.bind) + device->parent->ops.bind(device); + } + + /* + * Locate & Attach Driver + * ---------------------- + * If there's a hardware id (_HID) or compatible ids (_CID) we check + * to see if there's a driver installed for this kind of device. Note + * that drivers can install before or after a device in enumerated. + * + * TBD: Assumes LDM provides driver hot-plug capability. + */ + if (device->flags.hardware_id || device->flags.compatible_ids) + acpi_bus_find_driver(device); + +end: + if (0 != result) { + kfree(device); + return_VALUE(result); + } + + *child = device; + + return_VALUE(0); +} + + +static int +acpi_bus_remove ( + struct acpi_device *device, + int type) +{ + ACPI_FUNCTION_TRACE("acpi_bus_remove"); + + if (!device) + return_VALUE(-ENODEV); + + acpi_device_unregister(device); + + kfree(device); + + return_VALUE(0); +} + + +int +acpi_bus_scan ( + struct acpi_device *start) +{ + acpi_status status = AE_OK; + struct acpi_device *parent = NULL; + struct acpi_device *child = NULL; + acpi_handle phandle = 0; + acpi_handle chandle = 0; + acpi_object_type type = 0; + u32 level = 1; + + ACPI_FUNCTION_TRACE("acpi_bus_scan"); + + if (!start) + return_VALUE(-EINVAL); + + parent = start; + phandle = start->handle; + + /* + * Parse through the ACPI namespace, identify all 'devices', and + * create a new 'struct acpi_device' for each. + */ + while ((level > 0) && parent) { + + status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, + chandle, &chandle); + + /* + * If this scope is exhausted then move our way back up. + */ + if (ACPI_FAILURE(status)) { + level--; + chandle = phandle; + acpi_get_parent(phandle, &phandle); + if (parent->parent) + parent = parent->parent; + continue; + } + + status = acpi_get_type(chandle, &type); + if (ACPI_FAILURE(status)) + continue; + + /* + * If this is a scope object then parse it (depth-first). + */ + if (type == ACPI_TYPE_ANY) { + /* Hack to get around scope identity problem */ + status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, 0, NULL); + if (ACPI_SUCCESS(status)) { + level++; + phandle = chandle; + chandle = 0; + } + continue; + } + + /* + * We're only interested in objects that we consider 'devices'. + */ + switch (type) { + case ACPI_TYPE_DEVICE: + type = ACPI_BUS_TYPE_DEVICE; + break; + case ACPI_TYPE_PROCESSOR: + type = ACPI_BUS_TYPE_PROCESSOR; + break; + case ACPI_TYPE_THERMAL: + type = ACPI_BUS_TYPE_THERMAL; + break; + case ACPI_TYPE_POWER: + type = ACPI_BUS_TYPE_POWER; + break; + default: + continue; + } + + status = acpi_bus_add(&child, parent, chandle, type); + if (ACPI_FAILURE(status)) + continue; + + /* + * If the device is present, enabled, and functioning then + * parse its scope (depth-first). Note that we need to + * represent absent devices to facilitate PnP notifications + * -- but only the subtree head (not all of its children, + * which will be enumerated when the parent is inserted). + * + * TBD: Need notifications and other detection mechanisms + * in place before we can fully implement this. + */ + if (child->status.present) { + status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, + 0, NULL); + if (ACPI_SUCCESS(status)) { + level++; + phandle = chandle; + chandle = 0; + parent = child; + } + } + } + + return_VALUE(0); +} + + +static int +acpi_bus_scan_fixed ( + struct acpi_device *root) +{ + int result = 0; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_scan"); + + if (!root) + return_VALUE(-ENODEV); + + /* + * Enumerate all fixed-feature devices. + */ + if (acpi_fadt.pwr_button == 0) + result = acpi_bus_add(&device, acpi_root, + ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_POWER_BUTTON); + + if (acpi_fadt.sleep_button == 0) + result = acpi_bus_add(&device, acpi_root, + ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SLEEP_BUTTON); + + return_VALUE(result); +} + + +/* -------------------------------------------------------------------------- + Initialization/Cleanup + -------------------------------------------------------------------------- */ + +int __init +acpi_blacklisted(void) +{ + int i = 0; + int blacklisted = 0; + acpi_table_header table_header; + + while (acpi_blacklist[i].oem_id[0] != '\0') + { + if (!ACPI_SUCCESS(acpi_get_table_header(acpi_blacklist[i].table, 1, &table_header))) { + i++; + continue; + } + + if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) { + i++; + continue; + } + + if (strncmp(acpi_blacklist[i].oem_table_id, table_header.oem_table_id, 8)) { + i++; + continue; + } + + if ((acpi_blacklist[i].oem_revision_predicate == all_versions) + || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal + && table_header.oem_revision <= acpi_blacklist[i].oem_revision) + || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal + && table_header.oem_revision >= acpi_blacklist[i].oem_revision) + || (acpi_blacklist[i].oem_revision_predicate == equal + && table_header.oem_revision == acpi_blacklist[i].oem_revision)) { + + printk(KERN_ERR PREFIX "Vendor \"%6.6s\" System \"%8.8s\" " + "Revision 0x%x has a known ACPI BIOS problem.\n", + acpi_blacklist[i].oem_id, + acpi_blacklist[i].oem_table_id, + acpi_blacklist[i].oem_revision); + + printk(KERN_ERR PREFIX "Reason: %s. This is a %s error\n", + acpi_blacklist[i].reason, + (acpi_blacklist[i].is_critical_error ? "non-recoverable" : "recoverable")); + + blacklisted = acpi_blacklist[i].is_critical_error; + break; + } + else { + i++; + } + } + + return blacklisted; +} + +static int __init +acpi_bus_init_irq (void) +{ + acpi_status status = AE_OK; + acpi_object arg = {ACPI_TYPE_INTEGER}; + acpi_object_list arg_list = {1, &arg}; + char *message = NULL; + + ACPI_FUNCTION_TRACE("acpi_bus_init_irq"); + + /* + * Let the system know what interrupt model we are using by + * evaluating the \_PIC object, if exists. + */ + + switch (acpi_irq_model) { + case ACPI_IRQ_MODEL_PIC: + message = "PIC"; + break; + case ACPI_IRQ_MODEL_IOAPIC: + message = "IOAPIC"; + break; + case ACPI_IRQ_MODEL_IOSAPIC: + message = "IOSAPIC"; + break; + default: + printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n"); + return_VALUE(-ENODEV); + } + + printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message); + + arg.integer.value = acpi_irq_model; + + status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL); + if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n")); + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + + +static int __init +acpi_bus_init (void) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_buffer buffer = {sizeof(acpi_fadt), &acpi_fadt}; + int progress = 0; + + ACPI_FUNCTION_TRACE("acpi_bus_init"); + + /* + * [0] Initailize the ACPI Core Subsystem. + */ + status = acpi_initialize_subsystem(); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to initialize the ACPI Interpreter\n"); + result = -ENODEV; + goto end; + } + + progress++; + + /* + * [1] Load the ACPI tables. + */ + status = acpi_load_tables(); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to load the System Description Tables\n"); + result = -ENODEV; + goto end; + } + + progress++; + + /* + * [2] Check the blacklist + */ + if (acpi_blacklisted()) { + result = -ENODEV; + goto end; + } + + progress++; + + /* + * [3] Get a separate copy of the FADT for use by other drivers. + */ + status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to get the FADT\n"); + result = -ENODEV; + goto end; + } + + progress++; + + /* + * [4] Enable the ACPI Core Subsystem. + */ + status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); + result = -ENODEV; + goto end; + } + + printk(KERN_INFO PREFIX "Interpreter enabled\n"); + + progress++; + + /* + * [5] Get the system interrupt model and evaluate \_PIC. + */ + result = acpi_bus_init_irq(); + if (0 != result) + goto end; + + progress++; + + /* + * [6] Register for all standard device notifications. + */ + status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Unable to register for device notifications\n"); + result = -ENODEV; + goto end; + } + + progress++; + + /* + * [7] Create the root device. + */ + result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, + ACPI_BUS_TYPE_SYSTEM); + if (0 != result) + goto end; + + progress++; + + /* + * [8] Create the root file system. + */ + acpi_device_dir(acpi_root) = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); + if (!acpi_root) { + result = -ENODEV; + goto end; + } + acpi_root_dir = acpi_device_dir(acpi_root); + + progress++; + + /* + * [9] Install drivers required for proper enumeration of the + * ACPI namespace. + */ + acpi_system_init(); /* ACPI System */ + acpi_power_init(); /* ACPI Bus Power Management */ +#ifdef CONFIG_ACPI_EC + acpi_ec_init(); /* ACPI Embedded Controller */ +#endif +#ifdef CONFIG_ACPI_PCI + acpi_pci_link_init(); /* ACPI PCI Interrupt Link */ + acpi_pci_root_init(); /* ACPI PCI Root Bridge */ +#endif + progress++; + + /* + * [10] Enumerate devices in the ACPI namespace. + */ + result = acpi_bus_scan_fixed(acpi_root); + if (0 != result) + goto end; + result = acpi_bus_scan(acpi_root); + if (0 != result) + goto end; + +end: + /* + * Clean up if anything went awry. + */ + if (0 != result) { + switch (progress) { + case 10: + case 9: remove_proc_entry("ACPI", NULL); + case 8: acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL); + case 7: acpi_remove_notify_handler(ACPI_ROOT_OBJECT, + ACPI_SYSTEM_NOTIFY, &acpi_bus_notify); + case 6: + case 5: + case 4: + case 3: + case 2: acpi_terminate(); + case 1: + case 0: + default: return_VALUE(-ENODEV); + } + } + + return_VALUE(0); +} + + +static void __exit +acpi_bus_exit (void) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE("acpi_bus_exit"); + + status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, + ACPI_SYSTEM_NOTIFY, acpi_bus_notify); + if (ACPI_FAILURE(status)) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error removing notify handler\n")); + +#ifdef CONFIG_ACPI_PCI + acpi_pci_root_exit(); + acpi_pci_link_exit(); +#endif +#ifdef CONFIG_ACPI_EC + acpi_ec_exit(); +#endif + acpi_power_exit(); + acpi_system_exit(); + + acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL); + + remove_proc_entry(ACPI_BUS_FILE_ROOT, NULL); + + status = acpi_terminate(); + if (ACPI_FAILURE(status)) + printk(KERN_ERR PREFIX "Unable to terminate the ACPI Interpreter\n"); + else + printk(KERN_ERR PREFIX "Interpreter disabled\n"); + + return_VOID; +} + + +int __init +acpi_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_init"); + acpi_dbg_level = NORMAL_DEFAULT; + + memset(&acpi_fadt, 0, sizeof(FADT_DESCRIPTOR)); + + printk(KERN_INFO PREFIX "Subsystem revision %08x\n", + ACPI_CA_VERSION); + + /* Initial core debug level excludes drivers, so include them now */ + acpi_set_debug(ACPI_DEBUG_LOW); + + if (acpi_disabled) { + printk(KERN_INFO PREFIX "Disabled via command line (acpi=off)\n"); + return -ENODEV; + } + +#ifdef CONFIG_PM + if (PM_IS_ACTIVE()) { + printk(KERN_INFO PREFIX "APM is already active, exiting\n"); + return -ENODEV; + } +#endif + + result = acpi_bus_init(); + if (0 != result) + return_VALUE(result); + +#ifdef CONFIG_PM + pm_active = 1; +#endif + + return_VALUE(0); +} + + +void __exit +acpi_exit (void) +{ + ACPI_FUNCTION_TRACE("acpi_exit"); + +#ifdef CONFIG_PM + pm_active = 0; +#endif + + acpi_bus_exit(); + + return_VOID; +} + + +int __init +acpi_setup(char *str) +{ + while (str && *str) { + if (strncmp(str, "off", 3) == 0) + acpi_disabled = 1; + str = strchr(str, ','); + if (str) + str += strspn(str, ", \t"); + } + return 1; +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +subsys_initcall(acpi_init); +#endif + +__setup("acpi=", acpi_setup); + diff -Nur linux-2.4.19/drivers/acpi/button.c linux-2.4.19-sgi211r3/drivers/acpi/button.c --- linux-2.4.19/drivers/acpi/button.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/button.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,420 @@ +/* + * acpi_button.c - ACPI Button Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_BUTTON_COMPONENT +ACPI_MODULE_NAME ("acpi_button") + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +#define PREFIX "ACPI: " + + +int acpi_button_add (struct acpi_device *device); +int acpi_button_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_button_driver = { + name: ACPI_BUTTON_DRIVER_NAME, + class: ACPI_BUTTON_CLASS, + ids: "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E", + ops: { + add: acpi_button_add, + remove: acpi_button_remove, + }, +}; + +struct acpi_button { + acpi_handle handle; + struct acpi_device *device; /* Fixed button kludge */ + u8 type; + unsigned long pushed; +}; + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +static struct proc_dir_entry *acpi_button_dir = NULL; + + +static int +acpi_button_read_info ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_button *button = (struct acpi_button *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_button_read_info"); + + if (!button || !button->device) + goto end; + + p += sprintf(p, "type: %s\n", + acpi_device_name(button->device)); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_button_add_fs ( + struct acpi_device *device) +{ + static struct proc_dir_entry *power_entry; + static struct proc_dir_entry *sleep_entry; + static struct proc_dir_entry *lid_entry; + struct proc_dir_entry *entry = NULL; + struct acpi_button *button = NULL; + + ACPI_FUNCTION_TRACE("acpi_button_add_fs"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + button = acpi_driver_data(device); + + if (!acpi_button_dir) { + acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); + if (!acpi_button_dir) + return_VALUE(-ENODEV); + } + + switch (button->type) { + case ACPI_BUTTON_TYPE_POWER: + case ACPI_BUTTON_TYPE_POWERF: + if (!power_entry) + power_entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, + acpi_button_dir); + entry = power_entry; + break; + case ACPI_BUTTON_TYPE_SLEEP: + case ACPI_BUTTON_TYPE_SLEEPF: + if (!sleep_entry) + sleep_entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, + acpi_button_dir); + entry = sleep_entry; + break; + case ACPI_BUTTON_TYPE_LID: + if (!lid_entry) + lid_entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, + acpi_button_dir); + entry = lid_entry; + break; + } + + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + + /* 'info' [R] */ + entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_BUTTON_FILE_INFO)); + else { + entry->read_proc = acpi_button_read_info; + entry->data = acpi_driver_data(device); + } + + return_VALUE(0); +} + + +static int +acpi_button_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_button_remove_fs"); + + if (!acpi_button_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_button_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +void +acpi_button_notify ( + acpi_handle handle, + u32 event, + void *data) +{ + struct acpi_button *button = (struct acpi_button *) data; + + ACPI_FUNCTION_TRACE("acpi_button_notify"); + + if (!button || !button->device) + return_VOID; + + switch (event) { + case ACPI_BUTTON_NOTIFY_STATUS: + acpi_bus_generate_event(button->device, event, ++button->pushed); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + return_VOID; +} + + +acpi_status +acpi_button_notify_fixed ( + void *data) +{ + struct acpi_button *button = (struct acpi_button *) data; + + ACPI_FUNCTION_TRACE("acpi_button_notify_fixed"); + + if (!button) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button); + + return_ACPI_STATUS(AE_OK); +} + + +int +acpi_button_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_button *button = NULL; + + ACPI_FUNCTION_TRACE("acpi_button_add"); + + if (!device) + return_VALUE(-EINVAL); + + button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL); + if (!button) + return_VALUE(-ENOMEM); + memset(button, 0, sizeof(struct acpi_button)); + + button->device = device; + button->handle = device->handle; + acpi_driver_data(device) = button; + + /* + * Determine the button type (via hid), as fixed-feature buttons + * need to be handled a bit differently than generic-space. + */ + if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) { + button->type = ACPI_BUTTON_TYPE_POWER; + sprintf(acpi_device_name(device), "%s", + ACPI_BUTTON_DEVICE_NAME_POWER); + sprintf(acpi_device_class(device), "%s/%s", + ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); + } + else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) { + button->type = ACPI_BUTTON_TYPE_POWERF; + sprintf(acpi_device_name(device), "%s", + ACPI_BUTTON_DEVICE_NAME_POWERF); + sprintf(acpi_device_class(device), "%s/%s", + ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); + } + else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) { + button->type = ACPI_BUTTON_TYPE_SLEEP; + sprintf(acpi_device_name(device), "%s", + ACPI_BUTTON_DEVICE_NAME_SLEEP); + sprintf(acpi_device_class(device), "%s/%s", + ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); + } + else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) { + button->type = ACPI_BUTTON_TYPE_SLEEPF; + sprintf(acpi_device_name(device), "%s", + ACPI_BUTTON_DEVICE_NAME_SLEEPF); + sprintf(acpi_device_class(device), "%s/%s", + ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); + } + else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) { + button->type = ACPI_BUTTON_TYPE_LID; + sprintf(acpi_device_name(device), "%s", + ACPI_BUTTON_DEVICE_NAME_LID); + sprintf(acpi_device_class(device), "%s/%s", + ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); + } + else { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n", + acpi_device_hid(device))); + result = -ENODEV; + goto end; + } + + result = acpi_button_add_fs(device); + if (0 != result) + goto end; + + switch (button->type) { + case ACPI_BUTTON_TYPE_POWERF: + status = acpi_install_fixed_event_handler ( + ACPI_EVENT_POWER_BUTTON, + acpi_button_notify_fixed, + button); + break; + case ACPI_BUTTON_TYPE_SLEEPF: + status = acpi_install_fixed_event_handler ( + ACPI_EVENT_SLEEP_BUTTON, + acpi_button_notify_fixed, + button); + break; + default: + status = acpi_install_notify_handler ( + button->handle, + ACPI_DEVICE_NOTIFY, + acpi_button_notify, + button); + break; + } + + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error installing notify handler\n")); + result = -ENODEV; + goto end; + } + + printk(KERN_INFO PREFIX "%s [%s]\n", + acpi_device_name(device), acpi_device_bid(device)); + +end: + if (0 != result) { + acpi_button_remove_fs(device); + kfree(button); + } + + return_VALUE(result); +} + + +int +acpi_button_remove (struct acpi_device *device, int type) +{ + acpi_status status = 0; + struct acpi_button *button = NULL; + + ACPI_FUNCTION_TRACE("acpi_button_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + button = acpi_driver_data(device); + + /* Unregister for device notifications. */ + switch (button->type) { + case ACPI_BUTTON_TYPE_POWERF: + status = acpi_remove_fixed_event_handler( + ACPI_EVENT_POWER_BUTTON, acpi_button_notify_fixed); + break; + case ACPI_BUTTON_TYPE_SLEEPF: + status = acpi_remove_fixed_event_handler( + ACPI_EVENT_SLEEP_BUTTON, acpi_button_notify_fixed); + break; + default: + status = acpi_remove_notify_handler(button->handle, + ACPI_DEVICE_NOTIFY, acpi_button_notify); + break; + } + + if (ACPI_FAILURE(status)) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error removing notify handler\n")); + + acpi_button_remove_fs(device); + + kfree(button); + + return_VALUE(0); +} + + +static int __init +acpi_button_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_button_init"); + + result = acpi_bus_register_driver(&acpi_button_driver); + if (0 > result) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +static void __exit +acpi_button_exit (void) +{ + ACPI_FUNCTION_TRACE("acpi_button_exit"); + + acpi_bus_unregister_driver(&acpi_button_driver); + + return_VOID; +} + + +module_init(acpi_button_init); +module_exit(acpi_button_exit); diff -Nur linux-2.4.19/drivers/acpi/debugger/Makefile linux-2.4.19-sgi211r3/drivers/acpi/debugger/Makefile --- linux-2.4.19/drivers/acpi/debugger/Makefile Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/debugger/dbcmds.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbcmds.c --- linux-2.4.19/drivers/acpi/debugger/dbcmds.c Wed Oct 24 14:06:21 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbcmds.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbcmds - debug commands and output routines - * $Revision: 66 $ + * $Revision: 83 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,21 +25,17 @@ #include "acpi.h" -#include "acparser.h" #include "acdispat.h" #include "amlcode.h" #include "acnamesp.h" -#include "acparser.h" #include "acevents.h" -#include "acinterp.h" #include "acdebug.h" -#include "actables.h" #include "acresrc.h" #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbcmds") + ACPI_MODULE_NAME ("dbcmds") /* @@ -47,7 +43,7 @@ * These object types map directly to the ACPI_TYPES */ -ARGUMENT_INFO acpi_db_object_types [] = +static ARGUMENT_INFO acpi_db_object_types [] = { {"ANY"}, {"NUMBERS"}, {"STRINGS"}, @@ -79,6 +75,8 @@ * DESCRIPTION: Check if this namespace object refers to the target object * that is passed in as the context value. * + * Note: Currently doesn't check subobjects within the Node's object + * ******************************************************************************/ acpi_status @@ -95,20 +93,13 @@ /* Check for match against the namespace node itself */ if (node == (void *) obj_desc) { - acpi_os_printf ("Object is a Node [%4.4s]\n", &node->name); + acpi_os_printf ("Object is a Node [%4.4s]\n", node->name.ascii); } /* Check for match against the object attached to the node */ - if (node->object == obj_desc) { - acpi_os_printf ("Reference at Node->Object %p [%4.4s]\n", node, &node->name); - } - - /* Check first child for a match */ - /* TBD: [Investigate] probably now obsolete with new datastructure */ - - if (node->child == (void *) obj_desc) { - acpi_os_printf ("Reference at Node->Child %p [%4.4s]\n", node, &node->name); + if (acpi_ns_get_attached_object (node) == obj_desc) { + acpi_os_printf ("Reference at Node->Object %p [%4.4s]\n", node, node->name.ascii); } return (AE_OK); @@ -136,11 +127,11 @@ /* Convert string to object pointer */ - obj_desc = (acpi_operand_object *) STRTOUL (object_arg, NULL, 16); + obj_desc = ACPI_TO_POINTER (ACPI_STRTOUL (object_arg, NULL, 16)); /* Search all nodes in namespace */ - acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + (void) acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_db_walk_for_references, (void *) obj_desc, NULL); } @@ -227,7 +218,7 @@ /* Search all tables for the target type */ for (i = 0; i < NUM_ACPI_TABLES; i++) { - if (!STRNCMP (table_arg, acpi_gbl_acpi_table_data[i].signature, + if (!ACPI_STRNCMP (table_arg, acpi_gbl_acpi_table_data[i].signature, acpi_gbl_acpi_table_data[i].sig_length)) { /* Found the table, unload it */ @@ -279,14 +270,14 @@ /* Get and verify the breakpoint address */ - address = STRTOUL (location, NULL, 16); - if (address <= op->aml_offset) { - acpi_os_printf ("Breakpoint %X is beyond current address %X\n", address, op->aml_offset); + address = ACPI_STRTOUL (location, NULL, 16); + if (address <= op->common.aml_offset) { + acpi_os_printf ("Breakpoint %X is beyond current address %X\n", address, op->common.aml_offset); } /* Save breakpoint in current walk */ - walk_state->method_breakpoint = address; + walk_state->user_breakpoint = address; acpi_os_printf ("Breakpoint set at AML offset %X\n", address); } @@ -348,10 +339,9 @@ } if (statements) { - num_statements = STRTOUL (statements, NULL, 0); + num_statements = ACPI_STRTOUL (statements, NULL, 0); } - acpi_db_display_op (NULL, op, num_statements); } @@ -385,13 +375,13 @@ /* Check if numeric argument, must be a Node */ if ((start_arg[0] >= 0x30) && (start_arg[0] <= 0x39)) { - subtree_entry = (acpi_handle) STRTOUL (start_arg, NULL, 16); + subtree_entry = ACPI_TO_POINTER (ACPI_STRTOUL (start_arg, NULL, 16)); if (!acpi_os_readable (subtree_entry, sizeof (acpi_namespace_node))) { acpi_os_printf ("Address %p is invalid in this address space\n", subtree_entry); return; } - if (!VALID_DESCRIPTOR_TYPE ((subtree_entry), ACPI_DESC_TYPE_NAMED)) { + if (ACPI_GET_DESCRIPTOR_TYPE (subtree_entry) != ACPI_DESC_TYPE_NAMED) { acpi_os_printf ("Address %p is not a valid Named object\n", subtree_entry); return; } @@ -411,19 +401,18 @@ /* Now we can check for the depth argument */ if (depth_arg) { - max_depth = STRTOUL (depth_arg, NULL, 0); + max_depth = ACPI_STRTOUL (depth_arg, NULL, 0); } } - - acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT); acpi_os_printf ("ACPI Namespace (from %p subtree):\n", subtree_entry); /* Display the subtree */ - acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT); acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, ACPI_UINT32_MAX, subtree_entry); - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); } @@ -450,24 +439,22 @@ u16 owner_id; - owner_id = (u16) STRTOUL (owner_arg, NULL, 0); - + owner_id = (u16) ACPI_STRTOUL (owner_arg, NULL, 0); /* Now we can check for the depth argument */ if (depth_arg) { - max_depth = STRTOUL (depth_arg, NULL, 0); + max_depth = ACPI_STRTOUL (depth_arg, NULL, 0); } - - acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT); acpi_os_printf ("ACPI Namespace by owner %X:\n", owner_id); /* Display the subtree */ - acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT); acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, owner_id, subtree_entry); - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); } @@ -491,6 +478,7 @@ u32 value) { acpi_namespace_node *node; + acpi_status status; /* Translate name to an Named object */ @@ -508,7 +496,10 @@ /* Send the notify */ - acpi_ev_queue_notify_request (node, value); + status = acpi_ev_queue_notify_request (node, value); + if (ACPI_FAILURE (status)) { + acpi_os_printf ("Could not queue notify\n"); + } break; default: @@ -545,11 +536,12 @@ u32 value; acpi_walk_state *walk_state; acpi_operand_object *obj_desc; + acpi_status status; /* Validate Type_arg */ - STRUPR (type_arg); + ACPI_STRUPR (type_arg); type = type_arg[0]; if ((type != 'L') && (type != 'A')) { @@ -559,8 +551,8 @@ /* Get the index and value */ - index = STRTOUL (index_arg, NULL, 16); - value = STRTOUL (value_arg, NULL, 16); + index = ACPI_STRTOUL (index_arg, NULL, 16); + value = ACPI_STRTOUL (value_arg, NULL, 16); walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list); if (!walk_state) { @@ -587,12 +579,16 @@ /* Set a method argument */ - if (index > MTH_NUM_ARGS) { + if (index > MTH_MAX_ARG) { acpi_os_printf ("Arg%d - Invalid argument name\n", index); return; } - acpi_ds_store_object_to_local (AML_ARG_OP, index, obj_desc, walk_state); + status = acpi_ds_store_object_to_local (AML_ARG_OP, index, obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + return; + } + obj_desc = walk_state->arguments[index].object; acpi_os_printf ("Arg%d: ", index); @@ -603,12 +599,16 @@ /* Set a method local */ - if (index > MTH_NUM_LOCALS) { + if (index > MTH_MAX_LOCAL) { acpi_os_printf ("Local%d - Invalid local variable name\n", index); return; } - acpi_ds_store_object_to_local (AML_LOCAL_OP, index, obj_desc, walk_state); + status = acpi_ds_store_object_to_local (AML_LOCAL_OP, index, obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + return; + } + obj_desc = walk_state->local_variables[index].object; acpi_os_printf ("Local%d: ", index); @@ -642,23 +642,22 @@ { acpi_operand_object *obj_desc; acpi_status status; - u32 buf_size; - NATIVE_CHAR buffer[64]; + acpi_buffer buffer; - obj_desc = ((acpi_namespace_node *)obj_handle)->object; - buf_size = sizeof (buffer) / sizeof (*buffer); + obj_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) obj_handle); /* Get and display the full pathname to this object */ - status = acpi_ns_handle_to_pathname (obj_handle, &buf_size, buffer); - + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_ns_handle_to_pathname (obj_handle, &buffer); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could Not get pathname for object %p\n", obj_handle); return (AE_OK); } - acpi_os_printf ("%32s", buffer); + acpi_os_printf ("%32s", buffer.pointer); + ACPI_MEM_FREE (buffer.pointer); /* Display short information about the object */ @@ -688,6 +687,10 @@ case ACPI_TYPE_BUFFER: acpi_os_printf (" Length %X", obj_desc->buffer.length); break; + + default: + /* Ignore other object types */ + break; } } @@ -714,7 +717,7 @@ NATIVE_CHAR *obj_type_arg, NATIVE_CHAR *display_count_arg) { - acpi_object_type8 type; + acpi_object_type type; /* Get the object type */ @@ -725,17 +728,17 @@ return (AE_OK); } - acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT); acpi_os_printf ("Objects of type [%s] defined in the current ACPI Namespace: \n", acpi_ut_get_type_name (type)); - acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT); /* Walk the namespace from the root */ - acpi_walk_namespace (type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + (void) acpi_walk_namespace (type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_db_walk_for_specific_objects, (void *) &type, NULL); - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); return (AE_OK); } @@ -763,8 +766,7 @@ acpi_status status; NATIVE_CHAR *requested_name = (NATIVE_CHAR *) context; u32 i; - u32 buf_size; - NATIVE_CHAR buffer[96]; + acpi_buffer buffer; /* Check for a name match */ @@ -773,7 +775,7 @@ /* Wildcard support */ if ((requested_name[i] != '?') && - (requested_name[i] != ((NATIVE_CHAR *) (&((acpi_namespace_node *) obj_handle)->name))[i])) { + (requested_name[i] != ((acpi_namespace_node *) obj_handle)->name.ascii[i])) { /* No match, just exit */ return (AE_OK); @@ -783,16 +785,15 @@ /* Get the full pathname to this object */ - buf_size = sizeof (buffer) / sizeof (*buffer); - - status = acpi_ns_handle_to_pathname (obj_handle, &buf_size, buffer); + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_ns_handle_to_pathname (obj_handle, &buffer); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could Not get pathname for object %p\n", obj_handle); } - else { - acpi_os_printf ("%32s (%p) - %s\n", buffer, obj_handle, + acpi_os_printf ("%32s (%p) - %s\n", buffer.pointer, obj_handle, acpi_ut_get_type_name (((acpi_namespace_node *) obj_handle)->type)); + ACPI_MEM_FREE (buffer.pointer); } return (AE_OK); @@ -817,17 +818,17 @@ NATIVE_CHAR *name_arg) { - if (STRLEN (name_arg) > 4) { + if (ACPI_STRLEN (name_arg) > 4) { acpi_os_printf ("Name must be no longer than 4 characters\n"); return (AE_OK); } /* Walk the namespace from the root */ - acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + (void) acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_db_walk_and_match_name, name_arg, NULL); - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); return (AE_OK); } @@ -849,6 +850,9 @@ acpi_db_set_scope ( NATIVE_CHAR *name) { + acpi_status status; + acpi_namespace_node *node; + if (!name || name[0] == 0) { acpi_os_printf ("Current scope: %s\n", acpi_gbl_db_scope_buf); @@ -857,19 +861,38 @@ acpi_db_prep_namestring (name); - /* TBD: [Future] Validate scope here */ if (name[0] == '\\') { - STRCPY (acpi_gbl_db_scope_buf, name); - STRCAT (acpi_gbl_db_scope_buf, "\\"); - } + /* Validate new scope from the root */ + + status = acpi_ns_get_node_by_path (name, acpi_gbl_root_node, ACPI_NS_NO_UPSEARCH, &node); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + ACPI_STRCPY (acpi_gbl_db_scope_buf, name); + ACPI_STRCAT (acpi_gbl_db_scope_buf, "\\"); + } else { - STRCAT (acpi_gbl_db_scope_buf, name); - STRCAT (acpi_gbl_db_scope_buf, "\\"); + /* Validate new scope relative to old scope */ + + status = acpi_ns_get_node_by_path (name, acpi_gbl_db_scope_node, ACPI_NS_NO_UPSEARCH, &node); + if (ACPI_FAILURE (status)) { + goto error_exit; + } + + ACPI_STRCAT (acpi_gbl_db_scope_buf, name); + ACPI_STRCAT (acpi_gbl_db_scope_buf, "\\"); } + acpi_gbl_db_scope_node = node; acpi_os_printf ("New scope: %s\n", acpi_gbl_db_scope_buf); + return; + + +error_exit: + + acpi_os_printf ("Could not attach scope: %s, %s\n", name, acpi_format_exception (status)); } @@ -889,24 +912,25 @@ acpi_db_display_resources ( NATIVE_CHAR *object_arg) { -#ifndef _IA16 +#if ACPI_MACHINE_WIDTH != 16 + acpi_operand_object *obj_desc; acpi_status status; acpi_buffer return_obj; - acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT); + acpi_dbg_level |= ACPI_LV_RESOURCES; /* Convert string to object pointer */ - obj_desc = (acpi_operand_object *) STRTOUL (object_arg, NULL, 16); + obj_desc = ACPI_TO_POINTER (ACPI_STRTOUL (object_arg, NULL, 16)); /* Prepare for a return object of arbitrary size */ return_obj.pointer = acpi_gbl_db_buffer; return_obj.length = ACPI_DEBUG_BUFFER_SIZE; - /* _PRT */ acpi_os_printf ("Evaluating _PRT\n"); @@ -950,10 +974,17 @@ status = acpi_get_current_resources (obj_desc, &return_obj); if (ACPI_FAILURE (status)) { acpi_os_printf ("Acpi_get_current_resources failed: %s\n", acpi_format_exception (status)); + goto get_prs; } else { - acpi_rs_dump_resource_list ((acpi_resource *) acpi_gbl_db_buffer); + acpi_rs_dump_resource_list (ACPI_CAST_PTR (acpi_resource, acpi_gbl_db_buffer)); + } + + status = acpi_set_current_resources (obj_desc, &return_obj); + if (ACPI_FAILURE (status)) { + acpi_os_printf ("Acpi_set_current_resources failed: %s\n", acpi_format_exception (status)); + goto get_prs; } @@ -980,17 +1011,102 @@ } else { - acpi_rs_dump_resource_list ((acpi_resource *) acpi_gbl_db_buffer); + acpi_rs_dump_resource_list (ACPI_CAST_PTR (acpi_resource, acpi_gbl_db_buffer)); } cleanup: - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); return; #endif } + +typedef struct +{ + u32 nodes; + u32 objects; +} ACPI_INTEGRITY_INFO; + +/******************************************************************************* + * + * FUNCTION: Acpi_db_integrity_walk + * + * PARAMETERS: Callback from Walk_namespace + * + * RETURN: Status + * + * DESCRIPTION: Examine one NS node for valid values. + * + ******************************************************************************/ + +acpi_status +acpi_db_integrity_walk ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + ACPI_INTEGRITY_INFO *info = (ACPI_INTEGRITY_INFO *) context; + acpi_namespace_node *node = (acpi_namespace_node *) obj_handle; + acpi_operand_object *object; + + + info->nodes++; + if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { + acpi_os_printf ("Invalid Descriptor Type for Node %p, Type = %X\n", + node, ACPI_GET_DESCRIPTOR_TYPE (node)); + } + + if (node->type > INTERNAL_TYPE_MAX) { + acpi_os_printf ("Invalid Object Type for Node %p, Type = %X\n", + node, node->type); + } + + if (!acpi_ut_valid_acpi_name (node->name.integer)) { + acpi_os_printf ("Invalid Acpi_name for Node %p\n", node); + } + + object = acpi_ns_get_attached_object (node); + if (object) { + info->objects++; + if (ACPI_GET_DESCRIPTOR_TYPE (object) != ACPI_DESC_TYPE_OPERAND) { + acpi_os_printf ("Invalid Descriptor Type for Object %p, Type = %X\n", + object, ACPI_GET_DESCRIPTOR_TYPE (object)); + } + } + + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_db_check_integrity + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Check entire namespace for data structure integrity + * + ******************************************************************************/ + +void +acpi_db_check_integrity (void) +{ + ACPI_INTEGRITY_INFO info = {0,0}; + + /* Search all nodes in namespace */ + + (void) acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + acpi_db_integrity_walk, (void *) &info, NULL); + + acpi_os_printf ("Verified %d namespace nodes with %d Objects\n", info.nodes, info.objects); + +} #endif /* ENABLE_DEBUGGER */ diff -Nur linux-2.4.19/drivers/acpi/debugger/dbdisasm.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbdisasm.c --- linux-2.4.19/drivers/acpi/debugger/dbdisasm.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbdisasm.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbdisasm - parser op tree display routines - * $Revision: 50 $ + * $Revision: 66 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,14 +34,13 @@ #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbdisasm") + ACPI_MODULE_NAME ("dbdisasm") -#define MAX_SHOW_ENTRY 128 #define BLOCK_PAREN 1 #define BLOCK_BRACE 2 #define DB_NO_OP_INFO " [%2.2d] " -#define DB_FULL_OP_INFO "%5.5X #%4.4X [%2.2d] " +#define DB_FULL_OP_INFO "%5.5X #%4.4hX [%2.2d] " NATIVE_CHAR *acpi_gbl_db_disasm_indent = "...."; @@ -64,17 +63,15 @@ acpi_parse_object *op) { - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_METHOD_OP: return (BLOCK_BRACE); - break; default: break; } return (BLOCK_PAREN); - } @@ -101,11 +98,23 @@ acpi_parse_object *op) { acpi_parse_object *target_op; + char *name; + if (op->common.flags & ACPI_PARSEOP_GENERIC) { + name = op->common.value.name; + if (name[0] == '\\') { + acpi_os_printf (" (Fully Qualified Pathname)"); + return (AE_OK); + } + } + else { + name = (char *) &op->named.name; + } + /* Search parent tree up to the root if necessary */ - target_op = acpi_ps_find (op, op->value.name, 0, 0); + target_op = acpi_ps_find (op, name, 0, 0); if (!target_op) { /* * Didn't find the name in the parse tree. This may be @@ -115,7 +124,6 @@ */ acpi_os_printf (" **** Path not found in parse tree"); } - else { /* The target was found, print the name and complete path */ @@ -136,8 +144,7 @@ { acpi_status status; acpi_namespace_node *node; - NATIVE_CHAR buffer[MAX_SHOW_ENTRY]; - u32 buffer_size = MAX_SHOW_ENTRY; + acpi_buffer buffer; u32 debug_level; @@ -148,12 +155,12 @@ /* Just get the Node out of the Op object */ - node = op->node; + node = op->common.node; if (!node) { /* Node not defined in this scope, look it up */ - status = acpi_ns_lookup (walk_state->scope_info, op->value.string, ACPI_TYPE_ANY, - IMODE_EXECUTE, NS_SEARCH_PARENT, walk_state, &(node)); + status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); if (ACPI_FAILURE (status)) { /* @@ -167,18 +174,20 @@ /* Save it for next time. */ - op->node = node; + op->common.node = node; } /* Convert Named_desc/handle to a full pathname */ - status = acpi_ns_handle_to_pathname (node, &buffer_size, buffer); + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_ns_handle_to_pathname (node, &buffer); if (ACPI_FAILURE (status)) { acpi_os_printf ("****Could not get pathname****)"); goto exit; } - acpi_os_printf (" (Path %s)", buffer); + acpi_os_printf (" (Path %s)", buffer.pointer); + ACPI_MEM_FREE (buffer.pointer); exit: @@ -219,118 +228,116 @@ u32 j; - if (op) { - while (op) { - /* indentation */ - - depth_count = 0; - if (!acpi_gbl_db_opt_verbose) { - depth_count++; + if (!op) { + acpi_db_display_opcode (walk_state, op); + return; + } + + + while (op) { + /* Indentation */ + + depth_count = 0; + if (!acpi_gbl_db_opt_verbose) { + depth_count++; + } + + /* Determine the nesting depth of this argument */ + + for (depth = op->common.parent; depth; depth = depth->common.parent) { + arg = acpi_ps_get_arg (depth, 0); + while (arg && arg != origin) { + arg = arg->common.next; } - /* Determine the nesting depth of this argument */ + if (arg) { + break; + } - for (depth = op->parent; depth; depth = depth->parent) { - arg = acpi_ps_get_arg (depth, 0); - while (arg && arg != origin) { - arg = arg->next; - } + depth_count++; + } - if (arg) { - break; - } + /* Open a new block if we are nested further than last time */ - depth_count++; + if (depth_count > last_depth) { + VERBOSE_PRINT ((DB_NO_OP_INFO, last_depth)); + for (i = 0; i < last_depth; i++) { + acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); } + if (acpi_db_block_type (op) == BLOCK_PAREN) { + acpi_os_printf ("(\n"); + } + else { + acpi_os_printf ("{\n"); + } + } - /* Open a new block if we are nested further than last time */ + /* Close a block if we are nested less than last time */ - if (depth_count > last_depth) { - VERBOSE_PRINT ((DB_NO_OP_INFO, last_depth)); - for (i = 0; i < last_depth; i++) { + else if (depth_count < last_depth) { + for (j = last_depth; j >= (depth_count + 1); j--) { + VERBOSE_PRINT ((DB_NO_OP_INFO, (j - 1))); + for (i = 1; i < j; i++) { acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); } if (acpi_db_block_type (op) == BLOCK_PAREN) { - acpi_os_printf ("(\n"); + acpi_os_printf (")\n"); } else { - acpi_os_printf ("{\n"); + acpi_os_printf ("}\n"); } } + } - /* Close a block if we are nested less than last time */ - - else if (depth_count < last_depth) { - for (j = 0; j < (last_depth - depth_count); j++) { - VERBOSE_PRINT ((DB_NO_OP_INFO, last_depth - j)); - for (i = 0; i < (last_depth - j - 1); i++) { - acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); - } - - if (acpi_db_block_type (op) == BLOCK_PAREN) { - acpi_os_printf (")\n"); - } - else { - acpi_os_printf ("}\n"); - } - } - } - - /* In verbose mode, print the AML offset, opcode and depth count */ - - VERBOSE_PRINT ((DB_FULL_OP_INFO, (unsigned) op->aml_offset, op->opcode, depth_count)); + /* In verbose mode, print the AML offset, opcode and depth count */ + VERBOSE_PRINT ((DB_FULL_OP_INFO, (u32) op->common.aml_offset, + op->common.aml_opcode, depth_count)); - /* Indent the output according to the depth count */ - for (i = 0; i < depth_count; i++) { - acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); - } + /* Indent the output according to the depth count */ + for (i = 0; i < depth_count; i++) { + acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); + } - /* Now print the opcode */ + /* Now print the opcode */ - acpi_db_display_opcode (walk_state, op); + acpi_db_display_opcode (walk_state, op); - /* Resolve a name reference */ + /* Resolve a name reference */ - if ((op->opcode == AML_INT_NAMEPATH_OP && op->value.name) && - (op->parent) && - (acpi_gbl_db_opt_verbose)) { - acpi_ps_display_object_pathname (walk_state, op); - } + if ((op->common.aml_opcode == AML_INT_NAMEPATH_OP && op->common.value.name) && + (op->common.parent) && + (acpi_gbl_db_opt_verbose)) { + (void) acpi_ps_display_object_pathname (walk_state, op); + } - acpi_os_printf ("\n"); + acpi_os_printf ("\n"); - /* Get the next node in the tree */ + /* Get the next node in the tree */ - op = acpi_ps_get_depth_next (origin, op); - last_depth = depth_count; + op = acpi_ps_get_depth_next (origin, op); + last_depth = depth_count; - num_opcodes--; - if (!num_opcodes) { - op = NULL; - } + num_opcodes--; + if (!num_opcodes) { + op = NULL; } + } - /* Close the last block(s) */ + /* Close the last block(s) */ - depth_count = last_depth -1; - for (i = 0; i < last_depth; i++) { - VERBOSE_PRINT ((DB_NO_OP_INFO, last_depth - i)); - for (j = 0; j < depth_count; j++) { - acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); - } - acpi_os_printf ("}\n"); - depth_count--; + depth_count = last_depth -1; + for (i = 0; i < last_depth; i++) { + VERBOSE_PRINT ((DB_NO_OP_INFO, last_depth - i)); + for (j = 0; j < depth_count; j++) { + acpi_os_printf ("%s", acpi_gbl_db_disasm_indent); } - - } - - else { - acpi_db_display_opcode (walk_state, op); + acpi_os_printf ("}\n"); + depth_count--; } } @@ -352,7 +359,6 @@ NATIVE_CHAR *name) { u32 seg_count; - u8 do_dot = FALSE; if (!name) { @@ -360,21 +366,27 @@ return; } - if (acpi_ps_is_prefix_char (GET8 (name))) { - /* append prefix character */ + /* Handle all Scope Prefix operators */ + + while (acpi_ps_is_prefix_char (ACPI_GET8 (name))) { + /* Append prefix character */ - acpi_os_printf ("%1c", GET8 (name)); + acpi_os_printf ("%1c", ACPI_GET8 (name)); name++; } - switch (GET8 (name)) { + switch (ACPI_GET8 (name)) { + case 0: + seg_count = 0; + break; + case AML_DUAL_NAME_PREFIX: seg_count = 2; name++; break; case AML_MULTI_NAME_PREFIX_OP: - seg_count = (u32) GET8 (name + 1); + seg_count = (u32) ACPI_GET8 (name + 1); name += 2; break; @@ -383,19 +395,18 @@ break; } - while (seg_count--) { - /* append Name segment */ + while (seg_count) { + /* Append Name segment */ + + acpi_os_printf ("%4.4s", name); - if (do_dot) { - /* append dot */ + seg_count--; + if (seg_count) { + /* Not last name, append dot separator */ acpi_os_printf ("."); } - - acpi_os_printf ("%4.4s", name); - do_dot = TRUE; - - name += 4; + name += ACPI_NAME_SIZE; } } @@ -428,16 +439,15 @@ /* We are only interested in named objects */ - op_info = acpi_ps_get_opcode_info (op->opcode); + op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (!(op_info->flags & AML_NSNODE)) { return; } - if (op_info->flags & AML_CREATE) { /* Field creation - check for a fully qualified namepath */ - if (op->opcode == AML_CREATE_FIELD_OP) { + if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { name_path = acpi_ps_get_arg (op, 3); } else { @@ -445,9 +455,9 @@ } if ((name_path) && - (name_path->value.string) && - (name_path->value.string[0] == '\\')) { - acpi_db_display_namestring (name_path->value.string); + (name_path->common.value.string) && + (name_path->common.value.string[0] == '\\')) { + acpi_db_display_namestring (name_path->common.value.string); return; } } @@ -459,17 +469,17 @@ search = op; for (; ;) { - if (search->parent == prev) { + if (search->common.parent == prev) { break; } /* Go up one level */ - search = search->parent; + search = search->common.parent; } if (prev) { - op_info = acpi_ps_get_opcode_info (search->opcode); + op_info = acpi_ps_get_opcode_info (search->common.aml_opcode); if (!(op_info->flags & AML_FIELD)) { /* below root scope, append scope name */ @@ -480,7 +490,7 @@ } if (op_info->flags & AML_CREATE) { - if (op->opcode == AML_CREATE_FIELD_OP) { + if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { name_path = acpi_ps_get_arg (op, 3); } else { @@ -488,11 +498,10 @@ } if ((name_path) && - (name_path->value.string)) { - acpi_os_printf ("%4.4s", name_path->value.string); + (name_path->common.value.string)) { + acpi_os_printf ("%4.4s", name_path->common.value.string); } } - else { name = acpi_ps_get_name (search); acpi_os_printf ("%4.4s", &name); @@ -536,134 +545,119 @@ if (!op) { acpi_os_printf (""); + return; } - /* op and arguments */ - switch (op->opcode) { - + switch (op->common.aml_opcode) { case AML_BYTE_OP: if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u8) 0x%2.2X", op->value.integer8); + acpi_os_printf ("(u8) 0x%2.2hX", op->common.value.integer8); } - else { - acpi_os_printf ("0x%2.2X", op->value.integer8); + acpi_os_printf ("0x%2.2hX", op->common.value.integer8); } - break; case AML_WORD_OP: if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u16) 0x%4.4X", op->value.integer16); + acpi_os_printf ("(u16) 0x%4.4hX", op->common.value.integer16); } - else { - acpi_os_printf ("0x%4.4X", op->value.integer16); + acpi_os_printf ("0x%4.4hX", op->common.value.integer16); } - break; case AML_DWORD_OP: if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u32) 0x%8.8X", op->value.integer32); + acpi_os_printf ("(u32) 0x%8.8X", op->common.value.integer32); } - else { - acpi_os_printf ("0x%8.8X", op->value.integer32); + acpi_os_printf ("0x%8.8X", op->common.value.integer32); } - break; case AML_QWORD_OP: if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("(u64) 0x%8.8X%8.8X", op->value.integer64.hi, - op->value.integer64.lo); + acpi_os_printf ("(u64) 0x%8.8X%8.8X", op->common.value.integer64.hi, + op->common.value.integer64.lo); } - else { - acpi_os_printf ("0x%8.8X%8.8X", op->value.integer64.hi, - op->value.integer64.lo); + acpi_os_printf ("0x%8.8X%8.8X", op->common.value.integer64.hi, + op->common.value.integer64.lo); } - break; case AML_STRING_OP: - if (op->value.string) { - acpi_os_printf ("\"%s\"", op->value.string); + if (op->common.value.string) { + acpi_os_printf ("\"%s\"", op->common.value.string); } - else { acpi_os_printf ("<\"NULL STRING PTR\">"); } - break; case AML_INT_STATICSTRING_OP: - if (op->value.string) { - acpi_os_printf ("\"%s\"", op->value.string); + if (op->common.value.string) { + acpi_os_printf ("\"%s\"", op->common.value.string); } - else { acpi_os_printf ("\"\""); } - break; case AML_INT_NAMEPATH_OP: - acpi_db_display_namestring (op->value.name); + acpi_db_display_namestring (op->common.value.name); break; case AML_INT_NAMEDFIELD_OP: - acpi_os_printf ("Named_field (Length 0x%8.8X) ", op->value.integer32); + acpi_os_printf ("Named_field (Length 0x%8.8X) ", op->common.value.integer32); break; case AML_INT_RESERVEDFIELD_OP: - acpi_os_printf ("Reserved_field (Length 0x%8.8X) ", op->value.integer32); + acpi_os_printf ("Reserved_field (Length 0x%8.8X) ", op->common.value.integer32); break; case AML_INT_ACCESSFIELD_OP: - acpi_os_printf ("Access_field (Length 0x%8.8X) ", op->value.integer32); + acpi_os_printf ("Access_field (Length 0x%8.8X) ", op->common.value.integer32); break; case AML_INT_BYTELIST_OP: if (acpi_gbl_db_opt_verbose) { - acpi_os_printf ("Byte_list (Length 0x%8.8X) ", op->value.integer32); + acpi_os_printf ("Byte_list (Length 0x%8.8X) ", op->common.value.integer32); } - else { - acpi_os_printf ("0x%2.2X", op->value.integer32); + acpi_os_printf ("0x%2.2X", op->common.value.integer32); - byte_count = op->value.integer32; - byte_data = ((acpi_parse2_object *) op)->data; + byte_count = op->common.value.integer32; + byte_data = op->named.data; for (i = 0; i < byte_count; i++) { acpi_os_printf (", 0x%2.2X", byte_data[i]); } } - break; @@ -671,25 +665,25 @@ /* Just get the opcode name and print it */ - op_info = acpi_ps_get_opcode_info (op->opcode); + op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); acpi_os_printf ("%s", op_info->name); #ifndef PARSER_ONLY - if ((op->opcode == AML_INT_RETURN_VALUE_OP) && + if ((op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) && + (walk_state) && (walk_state->results) && (walk_state->results->results.num_results)) { acpi_db_decode_internal_object (walk_state->results->results.obj_desc [walk_state->results->results.num_results-1]); } #endif - break; } if (!op_info) { /* If there is another element in the list, add a comma */ - if (op->next) { + if (op->common.next) { acpi_os_printf (","); } } @@ -697,19 +691,16 @@ /* * If this is a named opcode, print the associated name value */ - op_info = acpi_ps_get_opcode_info (op->opcode); + op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (op && (op_info->flags & AML_NAMED)) { name = acpi_ps_get_name (op); acpi_os_printf (" %4.4s", &name); - if (acpi_gbl_db_opt_verbose) { - acpi_os_printf (" (Path \\"); - acpi_db_display_path (op); - acpi_os_printf (")"); + if ((acpi_gbl_db_opt_verbose) && (op->common.aml_opcode != AML_INT_NAMEDFIELD_OP)) { + (void) acpi_ps_display_object_pathname (walk_state, op); } } } - #endif /* ENABLE_DEBUGGER */ diff -Nur linux-2.4.19/drivers/acpi/debugger/dbdisply.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbdisply.c --- linux-2.4.19/drivers/acpi/debugger/dbdisply.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbdisply.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbdisply - debug display commands - * $Revision: 57 $ + * $Revision: 73 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,12 +25,10 @@ #include "acpi.h" -#include "acparser.h" #include "amlcode.h" #include "acdispat.h" #include "acnamesp.h" #include "acparser.h" -#include "acevents.h" #include "acinterp.h" #include "acdebug.h" @@ -39,7 +37,7 @@ #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbdisply") + ACPI_MODULE_NAME ("dbdisply") /****************************************************************************** @@ -61,7 +59,7 @@ void *obj_ptr; -#ifdef _IA16 +#if ACPI_MACHINE_WIDTH == 16 #include /* Have to handle 16-bit pointers of the form segment:offset */ @@ -75,8 +73,7 @@ /* Simple flat pointer */ - obj_ptr = (void *) STRTOUL (target, NULL, 16); - + obj_ptr = ACPI_TO_POINTER (ACPI_STRTOUL (target, NULL, 16)); #endif return (obj_ptr); @@ -102,16 +99,16 @@ const acpi_opcode_info *info; - info = acpi_ps_get_opcode_info (op->opcode); + info = acpi_ps_get_opcode_info (op->common.aml_opcode); acpi_os_printf ("Parser Op Descriptor:\n"); - acpi_os_printf ("%20.20s : %4.4X\n", "Opcode", op->opcode); + acpi_os_printf ("%20.20s : %4.4X\n", "Opcode", op->common.aml_opcode); - DEBUG_ONLY_MEMBERS (acpi_os_printf ("%20.20s : %s\n", "Opcode Name", info->name)); + ACPI_DEBUG_ONLY_MEMBERS (acpi_os_printf ("%20.20s : %s\n", "Opcode Name", info->name)); - acpi_os_printf ("%20.20s : %p\n", "Value/Arg_list", op->value); - acpi_os_printf ("%20.20s : %p\n", "Parent", op->parent); - acpi_os_printf ("%20.20s : %p\n", "Next_op", op->next); + acpi_os_printf ("%20.20s : %p\n", "Value/Arg_list", op->common.value.arg); + acpi_os_printf ("%20.20s : %p\n", "Parent", op->common.parent); + acpi_os_printf ("%20.20s : %p\n", "Next_op", op->common.next); } @@ -136,6 +133,7 @@ { void *obj_ptr; acpi_namespace_node *node; + acpi_operand_object *obj_desc; u32 display = DB_BYTE_DISPLAY; NATIVE_CHAR buffer[80]; acpi_buffer ret_buf; @@ -150,7 +148,7 @@ /* Decode the output type */ if (output_type) { - STRUPR (output_type); + ACPI_STRUPR (output_type); if (output_type[0] == 'W') { display = DB_WORD_DISPLAY; } @@ -162,7 +160,6 @@ } } - ret_buf.length = sizeof (buffer); ret_buf.pointer = buffer; @@ -177,8 +174,10 @@ /* Decode the object type */ - if (VALID_DESCRIPTOR_TYPE ((obj_ptr), ACPI_DESC_TYPE_NAMED)) { - /* This is a Node */ + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_ptr)) { + case ACPI_DESC_TYPE_NAMED: + + /* This is a namespace Node */ if (!acpi_os_readable (obj_ptr, sizeof (acpi_namespace_node))) { acpi_os_printf ("Cannot read entire Named object at address %p\n", obj_ptr); @@ -187,10 +186,11 @@ node = obj_ptr; goto dump_nte; - } - else if (VALID_DESCRIPTOR_TYPE ((obj_ptr), ACPI_DESC_TYPE_INTERNAL)) { - /* This is an ACPI OBJECT */ + + case ACPI_DESC_TYPE_OPERAND: + + /* This is a ACPI OPERAND OBJECT */ if (!acpi_os_readable (obj_ptr, sizeof (acpi_operand_object))) { acpi_os_printf ("Cannot read entire ACPI object at address %p\n", obj_ptr); @@ -199,22 +199,27 @@ acpi_ut_dump_buffer (obj_ptr, sizeof (acpi_operand_object), display, ACPI_UINT32_MAX); acpi_ex_dump_object_descriptor (obj_ptr, 1); - } + break; - else if (VALID_DESCRIPTOR_TYPE ((obj_ptr), ACPI_DESC_TYPE_PARSER)) { - /* This is an Parser Op object */ + + case ACPI_DESC_TYPE_PARSER: + + /* This is a Parser Op object */ if (!acpi_os_readable (obj_ptr, sizeof (acpi_parse_object))) { acpi_os_printf ("Cannot read entire Parser object at address %p\n", obj_ptr); return; } - acpi_ut_dump_buffer (obj_ptr, sizeof (acpi_parse_object), display, ACPI_UINT32_MAX); acpi_db_dump_parser_descriptor ((acpi_parse_object *) obj_ptr); - } + break; + + + default: + + /* Is not a recognizeable object */ - else { size = 16; if (acpi_os_readable (obj_ptr, 64)) { size = 64; @@ -223,12 +228,12 @@ /* Just dump some memory */ acpi_ut_dump_buffer (obj_ptr, size, display, ACPI_UINT32_MAX); + break; } return; } - /* The parameter is a name string that must be resolved to a Named obj */ node = acpi_db_local_ns_lookup (target); @@ -257,15 +262,16 @@ acpi_ut_dump_buffer ((void *) node, sizeof (acpi_namespace_node), display, ACPI_UINT32_MAX); acpi_ex_dump_node (node, 1); - if (node->object) { - acpi_os_printf ("\n_attached Object (%p):\n", node->object); - if (!acpi_os_readable (node->object, sizeof (acpi_operand_object))) { - acpi_os_printf ("Invalid internal ACPI Object at address %p\n", node->object); + obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { + acpi_os_printf ("\n_attached Object (%p):\n", obj_desc); + if (!acpi_os_readable (obj_desc, sizeof (acpi_operand_object))) { + acpi_os_printf ("Invalid internal ACPI Object at address %p\n", obj_desc); return; } - acpi_ut_dump_buffer ((void *) node->object, sizeof (acpi_operand_object), display, ACPI_UINT32_MAX); - acpi_ex_dump_object_descriptor (node->object, 1); + acpi_ut_dump_buffer ((void *) obj_desc, sizeof (acpi_operand_object), display, ACPI_UINT32_MAX); + acpi_ex_dump_object_descriptor (obj_desc, 1); } } @@ -290,6 +296,7 @@ if (!obj_desc) { + acpi_os_printf (" Uninitialized\n"); return; } @@ -298,8 +305,8 @@ switch (obj_desc->common.type) { case ACPI_TYPE_INTEGER: - acpi_os_printf (" %.8X%.8X", HIDWORD (obj_desc->integer.value), - LODWORD (obj_desc->integer.value)); + acpi_os_printf (" %8.8X%8.8X", ACPI_HIDWORD (obj_desc->integer.value), + ACPI_LODWORD (obj_desc->integer.value)); break; @@ -326,6 +333,11 @@ acpi_os_printf (" %2.2X", obj_desc->buffer.pointer[i]); } break; + + + default: + /* No additional display for other types */ + break; } } @@ -358,29 +370,35 @@ return; } - /* Decode the object type */ - else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_PARSER)) { + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_PARSER: + acpi_os_printf (" "); - } + break; + + + case ACPI_DESC_TYPE_NAMED: - else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { acpi_os_printf (" Name %4.4s Type-%s", - &((acpi_namespace_node *)obj_desc)->name, + ((acpi_namespace_node *)obj_desc)->name.ascii, acpi_ut_get_type_name (((acpi_namespace_node *) obj_desc)->type)); + if (((acpi_namespace_node *) obj_desc)->flags & ANOBJ_METHOD_ARG) { acpi_os_printf (" [Method Arg]"); } if (((acpi_namespace_node *) obj_desc)->flags & ANOBJ_METHOD_LOCAL) { acpi_os_printf (" [Method Local]"); } - } + break; + + + case ACPI_DESC_TYPE_OPERAND: - else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { type = obj_desc->common.type; if (type > INTERNAL_TYPE_MAX) { - acpi_os_printf (" Type %x [Invalid Type]", type); + acpi_os_printf (" Type %hX [Invalid Type]", type); return; } @@ -406,10 +424,10 @@ break; case AML_LOCAL_OP: - acpi_os_printf ("[Local%d]", obj_desc->reference.offset); + acpi_os_printf ("[Local%d] ", obj_desc->reference.offset); if (walk_state) { obj_desc = walk_state->local_variables[obj_desc->reference.offset].object; - acpi_os_printf (" %p", obj_desc); + acpi_os_printf ("%p", obj_desc); acpi_db_decode_internal_object (obj_desc); } break; @@ -418,7 +436,7 @@ acpi_os_printf ("[Arg%d] ", obj_desc->reference.offset); if (walk_state) { obj_desc = walk_state->arguments[obj_desc->reference.offset].object; - acpi_os_printf (" %p", obj_desc); + acpi_os_printf ("%p", obj_desc); acpi_db_decode_internal_object (obj_desc); } break; @@ -428,7 +446,7 @@ break; case AML_INDEX_OP: - acpi_os_printf ("[Index] "); + acpi_os_printf ("[Index] "); acpi_db_decode_internal_object (obj_desc->reference.object); break; @@ -444,10 +462,13 @@ acpi_db_decode_internal_object (obj_desc); break; } - } + break; + + + default: - else { acpi_os_printf (" "); + break; } acpi_os_printf ("\n"); @@ -494,18 +515,18 @@ } obj_desc = walk_state->method_desc; - node = walk_state->method_node; + node = walk_state->method_node; - num_args = obj_desc->method.param_count; + num_args = obj_desc->method.param_count; concurrency = obj_desc->method.concurrency; - acpi_os_printf ("Currently executing control method is [%4.4s]\n", &node->name); + acpi_os_printf ("Currently executing control method is [%4.4s]\n", node->name.ascii); acpi_os_printf ("%X arguments, max concurrency = %X\n", num_args, concurrency); root_op = start_op; - while (root_op->parent) { - root_op = root_op->parent; + while (root_op->common.parent) { + root_op = root_op->common.parent; } op = root_op; @@ -522,7 +543,7 @@ /* Decode the opcode */ - op_info = acpi_ps_get_opcode_info (op->opcode); + op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); switch (op_info->class) { case AML_CLASS_ARGUMENT: if (count_remaining) { @@ -546,7 +567,6 @@ break; } - op = acpi_ps_get_depth_next (start_op, op); } @@ -587,9 +607,7 @@ obj_desc = walk_state->method_desc; node = walk_state->method_node; - - - acpi_os_printf ("Local Variables for method [%4.4s]:\n", &node->name); + acpi_os_printf ("Local Variables for method [%4.4s]:\n", node->name.ascii); for (i = 0; i < MTH_NUM_LOCALS; i++) { obj_desc = walk_state->local_variables[i].object; @@ -629,12 +647,13 @@ } obj_desc = walk_state->method_desc; - node = walk_state->method_node; + node = walk_state->method_node; - num_args = obj_desc->method.param_count; + num_args = obj_desc->method.param_count; concurrency = obj_desc->method.concurrency; - acpi_os_printf ("Method [%4.4s] has %X arguments, max concurrency = %X\n", &node->name, num_args, concurrency); + acpi_os_printf ("Method [%4.4s] has %X arguments, max concurrency = %X\n", + node->name.ascii, num_args, concurrency); for (i = 0; i < num_args; i++) { obj_desc = walk_state->arguments[i].object; @@ -679,7 +698,8 @@ num_results = walk_state->results->results.num_results; } - acpi_os_printf ("Method [%4.4s] has %X stacked result objects\n", &node->name, num_results); + acpi_os_printf ("Method [%4.4s] has %X stacked result objects\n", + node->name.ascii, num_results); for (i = 0; i < num_results; i++) { obj_desc = walk_state->results->results.obj_desc[i]; @@ -704,7 +724,6 @@ void acpi_db_display_calling_tree (void) { - u32 i; acpi_walk_state *walk_state; acpi_namespace_node *node; @@ -716,13 +735,12 @@ } node = walk_state->method_node; - acpi_os_printf ("Current Control Method Call Tree\n"); - for (i = 0; walk_state; i++) { + while (walk_state) { node = walk_state->method_node; - acpi_os_printf (" [%4.4s]\n", &node->name); + acpi_os_printf (" [%4.4s]\n", node->name.ascii); walk_state = walk_state->next; } @@ -740,6 +758,10 @@ * * DESCRIPTION: Display the result of an AML opcode * + * Note: Curently only displays the result object if we are single stepping. + * However, this output may be useful in other contexts and could be enabled + * to do so if needed. + * ******************************************************************************/ void @@ -748,10 +770,8 @@ acpi_walk_state *walk_state) { - /* TBD: [Future] We don't always want to display the result. - * For now, only display if single stepping - * however, this output is very useful in other contexts also - */ + /* Only display if single stepping */ + if (!acpi_gbl_cm_single_step) { return; } @@ -780,7 +800,6 @@ acpi_operand_object *obj_desc, acpi_walk_state *walk_state) { - if (!acpi_gbl_cm_single_step) { return; diff -Nur linux-2.4.19/drivers/acpi/debugger/dbexec.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbexec.c --- linux-2.4.19/drivers/acpi/debugger/dbexec.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbexec.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbexec - debugger control method execution - * $Revision: 34 $ + * $Revision: 41 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,23 +25,15 @@ #include "acpi.h" -#include "acparser.h" -#include "acdispat.h" -#include "amlcode.h" -#include "acnamesp.h" -#include "acparser.h" -#include "acevents.h" -#include "acinterp.h" #include "acdebug.h" -#include "actables.h" #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbexec") + ACPI_MODULE_NAME ("dbexec") -db_method_info acpi_gbl_db_method_info; +static acpi_db_method_info acpi_gbl_db_method_info; /******************************************************************************* @@ -59,7 +51,7 @@ acpi_status acpi_db_execute_method ( - db_method_info *info, + acpi_db_method_info *info, acpi_buffer *return_obj) { acpi_status status; @@ -77,13 +69,12 @@ if (info->args && info->args[0]) { for (i = 0; info->args[i] && i < MTH_NUM_ARGS; i++) { params[i].type = ACPI_TYPE_INTEGER; - params[i].integer.value = STRTOUL (info->args[i], NULL, 16); + params[i].integer.value = ACPI_STRTOUL (info->args[i], NULL, 16); } param_objects.pointer = params; param_objects.count = i; } - else { /* Setup default parameters */ @@ -103,7 +94,6 @@ return_obj->pointer = acpi_gbl_db_buffer; return_obj->length = ACPI_DEBUG_BUFFER_SIZE; - /* Do the actual method execution */ status = acpi_evaluate_object (NULL, info->pathname, ¶m_objects, return_obj); @@ -129,7 +119,7 @@ void acpi_db_execute_setup ( - db_method_info *info) + acpi_db_method_info *info) { /* Catenate the current scope to the supplied name */ @@ -137,24 +127,24 @@ info->pathname[0] = 0; if ((info->name[0] != '\\') && (info->name[0] != '/')) { - STRCAT (info->pathname, acpi_gbl_db_scope_buf); + ACPI_STRCAT (info->pathname, acpi_gbl_db_scope_buf); } - STRCAT (info->pathname, info->name); + ACPI_STRCAT (info->pathname, info->name); acpi_db_prep_namestring (info->pathname); - acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT); acpi_os_printf ("Executing %s\n", info->pathname); if (info->flags & EX_SINGLE_STEP) { acpi_gbl_cm_single_step = TRUE; - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); } else { /* No single step, allow redirection to a file */ - acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT); } } @@ -174,13 +164,14 @@ ******************************************************************************/ u32 -acpi_db_get_outstanding_allocations (void) +acpi_db_get_outstanding_allocations ( + void) { - u32 i; u32 outstanding = 0; - #ifdef ACPI_DBG_TRACK_ALLOCATIONS + u32 i; + for (i = ACPI_MEM_LIST_FIRST_CACHE_LIST; i < ACPI_NUM_MEM_LISTS; i++) { outstanding += (acpi_gbl_memory_lists[i].total_allocated - @@ -248,7 +239,7 @@ allocations = acpi_db_get_outstanding_allocations () - previous_allocations; - acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT); if (allocations > 0) { acpi_os_printf ("Outstanding: %ld allocations after execution\n", @@ -271,7 +262,7 @@ } } - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); } @@ -288,12 +279,12 @@ * ******************************************************************************/ -void +void ACPI_SYSTEM_XFACE acpi_db_method_thread ( void *context) { acpi_status status; - db_method_info *info = context; + acpi_db_method_info *info = context; u32 i; acpi_buffer return_obj; @@ -311,7 +302,10 @@ /* Signal our completion */ - acpi_os_signal_semaphore (info->thread_gate, 1); + status = acpi_os_signal_semaphore (info->thread_gate, 1); + if (ACPI_FAILURE (status)) { + acpi_os_printf ("Could not signal debugger semaphore\n"); + } } @@ -344,15 +338,14 @@ /* Get the arguments */ - num_threads = STRTOUL (num_threads_arg, NULL, 0); - num_loops = STRTOUL (num_loops_arg, NULL, 0); + num_threads = ACPI_STRTOUL (num_threads_arg, NULL, 0); + num_loops = ACPI_STRTOUL (num_loops_arg, NULL, 0); if (!num_threads || !num_loops) { acpi_os_printf ("Bad argument: Threads %X, Loops %X\n", num_threads, num_loops); return; } - /* Create the synchronization semaphore */ status = acpi_os_create_semaphore (1, 0, &thread_gate); @@ -371,16 +364,17 @@ acpi_db_execute_setup (&acpi_gbl_db_method_info); - /* Create the threads */ acpi_os_printf ("Creating %X threads to execute %X times each\n", num_threads, num_loops); for (i = 0; i < (num_threads); i++) { - acpi_os_queue_for_execution (OSD_PRIORITY_MED, acpi_db_method_thread, &acpi_gbl_db_method_info); + status = acpi_os_queue_for_execution (OSD_PRIORITY_MED, acpi_db_method_thread, &acpi_gbl_db_method_info); + if (ACPI_FAILURE (status)) { + break; + } } - /* Wait for all threads to complete */ i = num_threads; @@ -391,11 +385,11 @@ /* Cleanup and exit */ - acpi_os_delete_semaphore (thread_gate); + (void) acpi_os_delete_semaphore (thread_gate); - acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT); acpi_os_printf ("All threads (%X) have completed\n", num_threads); - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); } diff -Nur linux-2.4.19/drivers/acpi/debugger/dbfileio.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbfileio.c --- linux-2.4.19/drivers/acpi/debugger/dbfileio.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbfileio.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: dbfileio - Debugger file I/O commands. These can't usually * be used when running the debugger in Ring 0 (Kernel mode) - * $Revision: 53 $ + * $Revision: 63 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,14 +28,12 @@ #include "acpi.h" #include "acdebug.h" #include "acnamesp.h" -#include "acparser.h" -#include "acevents.h" #include "actables.h" #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbfileio") + ACPI_MODULE_NAME ("dbfileio") /* @@ -64,7 +62,7 @@ * ******************************************************************************/ -acpi_object_type8 +acpi_object_type acpi_db_match_argument ( NATIVE_CHAR *user_argument, ARGUMENT_INFO *arguments) @@ -77,8 +75,8 @@ } for (i = 0; arguments[i].name; i++) { - if (STRSTR (arguments[i].name, user_argument) == arguments[i].name) { - return ((acpi_object_type8) i); + if (ACPI_STRSTR (arguments[i].name, user_argument) == arguments[i].name) { + return (i); } } @@ -141,7 +139,7 @@ acpi_gbl_debug_file = fopen (name, "w+"); if (acpi_gbl_debug_file) { acpi_os_printf ("Debug output file %s opened\n", name); - STRCPY (acpi_gbl_db_debug_filename, name); + ACPI_STRCPY (acpi_gbl_db_debug_filename, name); acpi_gbl_db_output_to_file = TRUE; } else { @@ -167,7 +165,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_db_load_table( FILE *fp, acpi_table_header **table_ptr, @@ -200,11 +198,11 @@ /* We only support a limited number of table types */ - if (STRNCMP ((char *) table_header.signature, DSDT_SIG, 4) && - STRNCMP ((char *) table_header.signature, PSDT_SIG, 4) && - STRNCMP ((char *) table_header.signature, SSDT_SIG, 4)) { + if (ACPI_STRNCMP ((char *) table_header.signature, DSDT_SIG, 4) && + ACPI_STRNCMP ((char *) table_header.signature, PSDT_SIG, 4) && + ACPI_STRNCMP ((char *) table_header.signature, SSDT_SIG, 4)) { acpi_os_printf ("Table signature is invalid\n"); - DUMP_BUFFER (&table_header, sizeof (acpi_table_header)); + ACPI_DUMP_BUFFER (&table_header, sizeof (acpi_table_header)); return (AE_ERROR); } @@ -224,7 +222,7 @@ /* Copy the header to the buffer */ - MEMCPY (*table_ptr, &table_header, sizeof (table_header)); + ACPI_MEMCPY (*table_ptr, &table_header, sizeof (table_header)); /* Get the rest of the table */ @@ -275,7 +273,7 @@ acpi_table_desc table_info; - FUNCTION_TRACE ("Ae_local_load_table"); + ACPI_FUNCTION_TRACE ("Ae_local_load_table"); if (!table_ptr) { return_ACPI_STATUS (AE_BAD_PARAMETER); @@ -285,7 +283,7 @@ table_info.pointer = table_ptr; - status = acpi_tb_install_table (NULL, &table_info); + status = acpi_tb_install_table (&table_info); if (ACPI_FAILURE (status)) { /* Free table allocated by Acpi_tb_get_table */ @@ -308,27 +306,14 @@ } -/******************************************************************************* - * - * FUNCTION: Acpi_db_load_acpi_table - * - * PARAMETERS: Filname - File where table is located - * - * RETURN: Status - * - * DESCRIPTION: Load an ACPI table from a file - * - ******************************************************************************/ - +#ifdef ACPI_APPLICATION acpi_status -acpi_db_load_acpi_table ( +acpi_db_get_acpi_table ( NATIVE_CHAR *filename) { -#ifdef ACPI_APPLICATION FILE *fp; - acpi_status status; u32 table_length; - + acpi_status status; /* Open the file */ @@ -350,25 +335,52 @@ return (status); } - /* Attempt to recognize and install the table */ + return (AE_OK); + } +#endif + +/******************************************************************************* + * + * FUNCTION: Acpi_db_load_acpi_table + * + * PARAMETERS: Filname - File where table is located + * + * RETURN: Status + * + * DESCRIPTION: Load an ACPI table from a file + * + ******************************************************************************/ + +acpi_status +acpi_db_load_acpi_table ( + NATIVE_CHAR *filename) { +#ifdef ACPI_APPLICATION + acpi_status status; + + + status = acpi_db_get_acpi_table (filename); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Attempt to recognize and install the table */ status = ae_local_load_table (acpi_gbl_db_table_ptr); if (ACPI_FAILURE (status)) { - if (status == AE_EXIST) { + if (status == AE_ALREADY_EXISTS) { acpi_os_printf ("Table %4.4s is already installed\n", - &acpi_gbl_db_table_ptr->signature); + acpi_gbl_db_table_ptr->signature); } else { acpi_os_printf ("Could not install table, %s\n", acpi_format_exception (status)); } - acpi_os_free (acpi_gbl_db_table_ptr); return (status); } acpi_os_printf ("%4.4s at %p successfully installed and loaded\n", - &acpi_gbl_db_table_ptr->signature, acpi_gbl_db_table_ptr); + acpi_gbl_db_table_ptr->signature, acpi_gbl_db_table_ptr); acpi_gbl_acpi_hardware_present = FALSE; diff -Nur linux-2.4.19/drivers/acpi/debugger/dbhistry.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbhistry.c --- linux-2.4.19/drivers/acpi/debugger/dbhistry.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbhistry.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dbhistry - debugger HISTORY command - * $Revision: 19 $ + * $Revision: 24 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,20 +25,12 @@ #include "acpi.h" -#include "acparser.h" -#include "acdispat.h" -#include "amlcode.h" -#include "acnamesp.h" -#include "acparser.h" -#include "acevents.h" -#include "acinterp.h" #include "acdebug.h" -#include "actables.h" #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbhistry") + ACPI_MODULE_NAME ("dbhistry") #define HI_NO_HISTORY 0 @@ -54,11 +46,11 @@ } HISTORY_INFO; -HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE]; -u16 acpi_gbl_lo_history = 0; -u16 acpi_gbl_num_history = 0; -u16 acpi_gbl_next_history_index = 0; -u32 acpi_gbl_next_cmd_num = 1; +static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE]; +static u16 acpi_gbl_lo_history = 0; +static u16 acpi_gbl_num_history = 0; +static u16 acpi_gbl_next_history_index = 0; +static u32 acpi_gbl_next_cmd_num = 1; /******************************************************************************* @@ -78,10 +70,9 @@ NATIVE_CHAR *command_line) { - /* Put command into the next available slot */ - STRCPY (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command, command_line); + ACPI_STRCPY (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command, command_line); acpi_gbl_history_buffer[acpi_gbl_next_history_index].cmd_num = acpi_gbl_next_cmd_num; @@ -100,12 +91,10 @@ acpi_gbl_next_history_index = 0; } - acpi_gbl_next_cmd_num++; if (acpi_gbl_num_history < HISTORY_SIZE) { acpi_gbl_num_history++; } - } @@ -171,9 +160,8 @@ } else { - cmd_num = STRTOUL (command_num_arg, NULL, 0); + cmd_num = ACPI_STRTOUL (command_num_arg, NULL, 0); } - /* Search history buffer */ diff -Nur linux-2.4.19/drivers/acpi/debugger/dbinput.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbinput.c --- linux-2.4.19/drivers/acpi/debugger/dbinput.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbinput.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbinput - user front-end to the AML debugger - * $Revision: 72 $ + * $Revision: 86 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,66 +25,20 @@ #include "acpi.h" -#include "acparser.h" -#include "actables.h" -#include "acnamesp.h" -#include "acinterp.h" #include "acdebug.h" #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbinput") + ACPI_MODULE_NAME ("dbinput") /* - * Globals that are specific to the debugger - */ - -NATIVE_CHAR acpi_gbl_db_line_buf[80]; -NATIVE_CHAR acpi_gbl_db_parsed_buf[80]; -NATIVE_CHAR acpi_gbl_db_scope_buf[40]; -NATIVE_CHAR acpi_gbl_db_debug_filename[40]; -NATIVE_CHAR *acpi_gbl_db_args[DB_MAX_ARGS]; -NATIVE_CHAR *acpi_gbl_db_buffer = NULL; -NATIVE_CHAR *acpi_gbl_db_filename = NULL; -u8 acpi_gbl_db_output_to_file = FALSE; - -u32 acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2; -u32 acpi_gbl_db_console_debug_level = NORMAL_DEFAULT | ACPI_LV_TABLES; -u8 acpi_gbl_db_output_flags = DB_CONSOLE_OUTPUT; - - -u8 acpi_gbl_db_opt_tables = FALSE; -u8 acpi_gbl_db_opt_disasm = FALSE; -u8 acpi_gbl_db_opt_stats = FALSE; -u8 acpi_gbl_db_opt_parse_jit = FALSE; -u8 acpi_gbl_db_opt_verbose = TRUE; -u8 acpi_gbl_db_opt_ini_methods = TRUE; - -/* - * Statistic globals - */ -u16 acpi_gbl_obj_type_count[INTERNAL_TYPE_NODE_MAX+1]; -u16 acpi_gbl_node_type_count[INTERNAL_TYPE_NODE_MAX+1]; -u16 acpi_gbl_obj_type_count_misc; -u16 acpi_gbl_node_type_count_misc; -u32 acpi_gbl_num_nodes; -u32 acpi_gbl_num_objects; - - -u32 acpi_gbl_size_of_parse_tree; -u32 acpi_gbl_size_of_method_trees; -u32 acpi_gbl_size_of_node_entries; -u32 acpi_gbl_size_of_acpi_objects; - -/* * Top-level debugger commands. * * This list of commands must match the string table below it */ - enum acpi_ex_debugger_commands { CMD_NOT_FOUND = 0, @@ -109,6 +63,7 @@ CMD_HISTORY_EXE, CMD_HISTORY_LAST, CMD_INFORMATION, + CMD_INTEGRITY, CMD_INTO, CMD_LEVEL, CMD_LIST, @@ -139,7 +94,7 @@ #define CMD_FIRST_VALID 2 -const COMMAND_INFO acpi_gbl_db_commands[] = +static const COMMAND_INFO acpi_gbl_db_commands[] = { {"", 0}, {"", 0}, {"ALLOCATIONS", 0}, @@ -162,6 +117,7 @@ {"!", 1}, {"!!", 0}, {"INFORMATION", 0}, + {"INTEGRITY", 0}, {"INTO", 0}, {"LEVEL", 0}, {"LIST", 0}, @@ -224,13 +180,11 @@ } - /* * Parameter is the command class * * The idea here is to keep each class of commands smaller than a screenful */ - switch (help_type[0]) { case 'G': @@ -295,7 +249,7 @@ return; default: - acpi_os_printf ("Unrecognized Command Class: %x\n", help_type); + acpi_os_printf ("Unrecognized Command Class: %X\n", help_type); return; } } @@ -321,6 +275,7 @@ { NATIVE_CHAR *start; + /* At end of buffer? */ if (!string || !(*string)) @@ -328,7 +283,6 @@ return (NULL); } - /* Get rid of any spaces at the beginning */ if (*string == ' ') @@ -353,12 +307,10 @@ string++; } - if (!(*string)) { *next = NULL; } - else { *string = 0; @@ -392,11 +344,11 @@ NATIVE_CHAR *this; - STRCPY (acpi_gbl_db_parsed_buf, input_buffer); - STRUPR (acpi_gbl_db_parsed_buf); + ACPI_STRCPY (acpi_gbl_db_parsed_buf, input_buffer); + ACPI_STRUPR (acpi_gbl_db_parsed_buf); this = acpi_gbl_db_parsed_buf; - for (i = 0; i < DB_MAX_ARGS; i++) + for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++) { acpi_gbl_db_args[i] = acpi_db_get_next_token (this, &next); if (!acpi_gbl_db_args[i]) @@ -407,12 +359,11 @@ this = next; } - /* Uppercase the actual command */ if (acpi_gbl_db_args[0]) { - STRUPR (acpi_gbl_db_args[0]); + ACPI_STRUPR (acpi_gbl_db_args[0]); } count = i; @@ -451,7 +402,8 @@ for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++) { - if (STRSTR (acpi_gbl_db_commands[i].name, user_command) == acpi_gbl_db_commands[i].name) + if (ACPI_STRSTR (acpi_gbl_db_commands[i].name, user_command) == + acpi_gbl_db_commands[i].name) { return (i); } @@ -572,7 +524,7 @@ break; case CMD_FIND: - acpi_db_find_name_in_namespace (acpi_gbl_db_args[1]); + status = acpi_db_find_name_in_namespace (acpi_gbl_db_args[1]); break; case CMD_GO: @@ -601,7 +553,6 @@ status = AE_CTRL_TRUE; } return (status); - break; case CMD_HISTORY_LAST: command_line = acpi_db_get_from_history (NULL); @@ -621,13 +572,14 @@ acpi_db_display_method_info (op); break; + case CMD_INTEGRITY: + acpi_db_check_integrity (); + break; + case CMD_INTO: if (op) { acpi_gbl_cm_single_step = TRUE; - -/* TBD: Must get current walk state */ - /* Acpi_gbl_Method_breakpoint = 0; */ return (AE_OK); } break; @@ -641,13 +593,13 @@ else if (param_count == 2) { temp = acpi_gbl_db_console_debug_level; - acpi_gbl_db_console_debug_level = STRTOUL (acpi_gbl_db_args[1], NULL, 16); + acpi_gbl_db_console_debug_level = ACPI_STRTOUL (acpi_gbl_db_args[1], NULL, 16); acpi_os_printf ("Debug Level for console output was %8.8lX, now %8.8lX\n", temp, acpi_gbl_db_console_debug_level); } else { temp = acpi_gbl_db_debug_level; - acpi_gbl_db_debug_level = STRTOUL (acpi_gbl_db_args[1], NULL, 16); + acpi_gbl_db_debug_level = ACPI_STRTOUL (acpi_gbl_db_args[1], NULL, 16); acpi_os_printf ("Debug Level for file output was %8.8lX, now %8.8lX\n", temp, acpi_gbl_db_debug_level); } break; @@ -673,7 +625,7 @@ break; case CMD_METHODS: - acpi_db_display_objects ("METHOD", acpi_gbl_db_args[1]); + status = acpi_db_display_objects ("METHOD", acpi_gbl_db_args[1]); break; case CMD_NAMESPACE: @@ -681,12 +633,13 @@ break; case CMD_NOTIFY: - temp = STRTOUL (acpi_gbl_db_args[2], NULL, 0); + temp = ACPI_STRTOUL (acpi_gbl_db_args[2], NULL, 0); acpi_db_send_notify (acpi_gbl_db_args[1], temp); break; case CMD_OBJECT: - acpi_db_display_objects (STRUPR (acpi_gbl_db_args[1]), acpi_gbl_db_args[2]); + ACPI_STRUPR (acpi_gbl_db_args[1]); + status = acpi_db_display_objects (acpi_gbl_db_args[1], acpi_gbl_db_args[2]); break; case CMD_OPEN: @@ -718,19 +671,18 @@ break; case CMD_STATS: - acpi_db_display_statistics (acpi_gbl_db_args[1]); + status = acpi_db_display_statistics (acpi_gbl_db_args[1]); break; case CMD_STOP: - return (AE_AML_ERROR); - break; + return (AE_NOT_IMPLEMENTED); case CMD_TABLES: acpi_db_display_table_info (acpi_gbl_db_args[1]); break; case CMD_TERMINATE: - acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT); acpi_ut_subsystem_shutdown (); /* TBD: [Restructure] Need some way to re-initialize without re-creating the semaphores! */ @@ -773,6 +725,7 @@ return (AE_CTRL_TERMINATE); case CMD_NOT_FOUND: + default: acpi_os_printf ("Unknown Command\n"); return (AE_CTRL_TRUE); } @@ -798,11 +751,12 @@ * ******************************************************************************/ -void +void ACPI_SYSTEM_XFACE acpi_db_execute_thread ( void *context) { acpi_status status = AE_OK; + acpi_status Mstatus; while (status != AE_CTRL_TERMINATE) @@ -810,9 +764,19 @@ acpi_gbl_method_executing = FALSE; acpi_gbl_step_to_next_call = FALSE; - acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY); + Mstatus = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY); + if (ACPI_FAILURE (Mstatus)) + { + return; + } + status = acpi_db_command_dispatch (acpi_gbl_db_line_buf, NULL, NULL); - acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); + + Mstatus = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); + if (ACPI_FAILURE (Mstatus)) + { + return; + } } } @@ -834,13 +798,11 @@ acpi_db_single_thread ( void) { - acpi_status status = AE_OK; - acpi_gbl_method_executing = FALSE; acpi_gbl_step_to_next_call = FALSE; - status = acpi_db_command_dispatch (acpi_gbl_db_line_buf, NULL, NULL); + (void) acpi_db_command_dispatch (acpi_gbl_db_line_buf, NULL, NULL); } @@ -872,23 +834,22 @@ { /* Force output to console until a command is entered */ - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); /* Different prompt if method is executing */ if (!acpi_gbl_method_executing) { - acpi_os_printf ("%1c ", DB_COMMAND_PROMPT); + acpi_os_printf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); } else { - acpi_os_printf ("%1c ", DB_EXECUTE_PROMPT); + acpi_os_printf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); } /* Get the user input line */ - acpi_os_get_line (acpi_gbl_db_line_buf); - + (void) acpi_os_get_line (acpi_gbl_db_line_buf); /* Check for single or multithreaded debug */ @@ -898,10 +859,18 @@ * Signal the debug thread that we have a command to execute, * and wait for the command to complete. */ - acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_READY); - acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); + status = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_READY); + if (ACPI_FAILURE (status)) + { + return (status); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); + if (ACPI_FAILURE (status)) + { + return (status); + } } - else { /* Just call to the command line interpreter */ @@ -910,12 +879,11 @@ } } - /* * Only this thread (the original thread) should actually terminate the subsystem, * because all the semaphores are deleted during termination */ - acpi_terminate (); + status = acpi_terminate (); return (status); } diff -Nur linux-2.4.19/drivers/acpi/debugger/dbstats.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbstats.c --- linux-2.4.19/drivers/acpi/debugger/dbstats.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbstats.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbstats - Generation and display of ACPI table statistics - * $Revision: 47 $ + * $Revision: 59 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,19 +26,17 @@ #include #include -#include -#include #include #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbstats") + ACPI_MODULE_NAME ("dbstats") /* * Statistics subcommands */ -ARGUMENT_INFO acpi_db_stat_types [] = +static ARGUMENT_INFO acpi_db_stat_types [] = { {"ALLOCATIONS"}, {"OBJECTS"}, {"MEMORY"}, @@ -49,13 +47,13 @@ {NULL} /* Must be null terminated */ }; -#define CMD_ALLOCATIONS 0 -#define CMD_OBJECTS 1 -#define CMD_MEMORY 2 -#define CMD_MISC 3 -#define CMD_TABLES 4 -#define CMD_SIZES 5 -#define CMD_STACK 6 +#define CMD_STAT_ALLOCATIONS 0 +#define CMD_STAT_OBJECTS 1 +#define CMD_STAT_MEMORY 2 +#define CMD_STAT_MISC 3 +#define CMD_STAT_TABLES 4 +#define CMD_STAT_SIZES 5 +#define CMD_STAT_STACK 6 /******************************************************************************* @@ -67,9 +65,8 @@ * RETURN: None * * DESCRIPTION: Add this object to the global counts, by object type. - * Recursively handles subobjects and packages. - * - * [TBD] Restructure - remove recursion. + * Limited recursion handles subobjects and packages, and this + * is probably acceptable within the AML debugger only. * ******************************************************************************/ @@ -77,7 +74,6 @@ acpi_db_enumerate_object ( acpi_operand_object *obj_desc) { - u32 type; u32 i; @@ -91,22 +87,21 @@ acpi_gbl_num_objects++; - type = obj_desc->common.type; - if (type > INTERNAL_TYPE_NODE_MAX) + if (obj_desc->common.type > INTERNAL_TYPE_NODE_MAX) { acpi_gbl_obj_type_count_misc++; } else { - acpi_gbl_obj_type_count [type]++; + acpi_gbl_obj_type_count [obj_desc->common.type]++; } /* Count the sub-objects */ - switch (type) + switch (obj_desc->common.type) { case ACPI_TYPE_PACKAGE: - for (i = 0; i< obj_desc->package.count; i++) + for (i = 0; i < obj_desc->package.count; i++) { acpi_db_enumerate_object (obj_desc->package.elements[i]); } @@ -118,7 +113,15 @@ acpi_db_enumerate_object (obj_desc->device.addr_handler); break; + case ACPI_TYPE_BUFFER_FIELD: + if (acpi_ns_get_secondary_object (obj_desc)) + { + acpi_gbl_obj_type_count [ACPI_TYPE_BUFFER_FIELD]++; + } + break; + case ACPI_TYPE_REGION: + acpi_gbl_obj_type_count [INTERNAL_TYPE_REGION_FIELD ]++; acpi_db_enumerate_object (obj_desc->region.addr_handler); break; @@ -138,6 +141,9 @@ acpi_db_enumerate_object (obj_desc->thermal_zone.drv_handler); acpi_db_enumerate_object (obj_desc->thermal_zone.addr_handler); break; + + default: + break; } } @@ -172,7 +178,7 @@ acpi_gbl_num_nodes++; node = (acpi_namespace_node *) obj_handle; - obj_desc = ((acpi_namespace_node *) obj_handle)->object; + obj_desc = acpi_ns_get_attached_object (node); acpi_db_enumerate_object (obj_desc); @@ -227,7 +233,7 @@ * ******************************************************************************/ -acpi_status +void acpi_db_count_namespace_objects ( void) { @@ -244,10 +250,8 @@ acpi_gbl_node_type_count [i] = 0; } - acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + (void) acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, acpi_db_classify_one_object, NULL, NULL); - - return (AE_OK); } #endif @@ -271,8 +275,10 @@ { u32 i; u32 type; - u32 outstanding; u32 size; +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + u32 outstanding; +#endif if (!acpi_gbl_DSDT) @@ -286,7 +292,7 @@ return (AE_OK); } - STRUPR (type_arg); + ACPI_STRUPR (type_arg); type = acpi_db_match_argument (type_arg, acpi_db_stat_types); if (type == (u32) -1) { @@ -298,14 +304,14 @@ switch (type) { #ifndef PARSER_ONLY - case CMD_ALLOCATIONS: + case CMD_STAT_ALLOCATIONS: #ifdef ACPI_DBG_TRACK_ALLOCATIONS acpi_ut_dump_allocation_info (); #endif break; #endif - case CMD_TABLES: + case CMD_STAT_TABLES: acpi_os_printf ("ACPI Table Information:\n\n"); if (acpi_gbl_DSDT) @@ -314,7 +320,7 @@ } break; - case CMD_OBJECTS: + case CMD_STAT_OBJECTS: #ifndef PARSER_ONLY @@ -338,7 +344,7 @@ #endif break; - case CMD_MEMORY: + case CMD_STAT_MEMORY: #ifdef ACPI_DBG_TRACK_ALLOCATIONS acpi_os_printf ("\n----Object and Cache Statistics---------------------------------------------\n"); @@ -368,11 +374,11 @@ if (acpi_gbl_memory_lists[i].object_size) { - size = ROUND_UP_TO_1K (outstanding * acpi_gbl_memory_lists[i].object_size); + size = ACPI_ROUND_UP_TO_1K (outstanding * acpi_gbl_memory_lists[i].object_size); } else { - size = ROUND_UP_TO_1K (acpi_gbl_memory_lists[i].current_total_size); + size = ACPI_ROUND_UP_TO_1K (acpi_gbl_memory_lists[i].current_total_size); } acpi_os_printf (" Mem: [Alloc Free Outstanding Size] % 7d % 7d % 7d % 7d Kb\n", @@ -384,7 +390,7 @@ break; - case CMD_MISC: + case CMD_STAT_MISC: acpi_os_printf ("\n_miscellaneous Statistics:\n\n"); acpi_os_printf ("Calls to Acpi_ps_find:.. ........% 7ld\n", acpi_gbl_ps_find_count); @@ -400,7 +406,7 @@ break; - case CMD_SIZES: + case CMD_STAT_SIZES: acpi_os_printf ("\n_internal object sizes:\n\n"); @@ -425,26 +431,33 @@ acpi_os_printf ("Notify_handler %3d\n", sizeof (ACPI_OBJECT_NOTIFY_HANDLER)); acpi_os_printf ("Addr_handler %3d\n", sizeof (ACPI_OBJECT_ADDR_HANDLER)); acpi_os_printf ("Extra %3d\n", sizeof (ACPI_OBJECT_EXTRA)); + acpi_os_printf ("Data %3d\n", sizeof (ACPI_OBJECT_DATA)); acpi_os_printf ("\n"); - acpi_os_printf ("Parse_object %3d\n", sizeof (acpi_parse_object)); - acpi_os_printf ("Parse2_object %3d\n", sizeof (acpi_parse2_object)); + acpi_os_printf ("Parse_object %3d\n", sizeof (ACPI_PARSE_OBJ_COMMON)); + acpi_os_printf ("Parse_object_named %3d\n", sizeof (ACPI_PARSE_OBJ_NAMED)); + acpi_os_printf ("Parse_object_asl %3d\n", sizeof (ACPI_PARSE_OBJ_ASL)); acpi_os_printf ("Operand_object %3d\n", sizeof (acpi_operand_object)); acpi_os_printf ("Namespace_node %3d\n", sizeof (acpi_namespace_node)); break; - case CMD_STACK: + case CMD_STAT_STACK: +#if defined(ACPI_DEBUG) - size = acpi_gbl_entry_stack_pointer - acpi_gbl_lowest_stack_pointer; + size = (u32) (acpi_gbl_entry_stack_pointer - acpi_gbl_lowest_stack_pointer); acpi_os_printf ("\n_subsystem Stack Usage:\n\n"); acpi_os_printf ("Entry Stack Pointer %X\n", acpi_gbl_entry_stack_pointer); acpi_os_printf ("Lowest Stack Pointer %X\n", acpi_gbl_lowest_stack_pointer); acpi_os_printf ("Stack Use %X (%d)\n", size, size); acpi_os_printf ("Deepest Procedure Nesting %d\n", acpi_gbl_deepest_nesting); +#endif + break; + + default: break; } diff -Nur linux-2.4.19/drivers/acpi/debugger/dbutils.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbutils.c --- linux-2.4.19/drivers/acpi/debugger/dbutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbutils.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbutils - AML debugger utilities - * $Revision: 45 $ + * $Revision: 55 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,9 +28,6 @@ #include "acparser.h" #include "amlcode.h" #include "acnamesp.h" -#include "acparser.h" -#include "acevents.h" -#include "acinterp.h" #include "acdebug.h" #include "acdispat.h" @@ -38,7 +35,7 @@ #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbutils") + ACPI_MODULE_NAME ("dbutils") /******************************************************************************* @@ -61,10 +58,8 @@ acpi_gbl_db_output_flags = (u8) output_flags; - if (output_flags & DB_REDIRECTABLE_OUTPUT) { - if (acpi_gbl_db_output_to_file) { - acpi_dbg_level = acpi_gbl_db_debug_level; - } + if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) && acpi_gbl_db_output_to_file) { + acpi_dbg_level = acpi_gbl_db_debug_level; } else { acpi_dbg_level = acpi_gbl_db_console_debug_level; @@ -92,7 +87,7 @@ acpi_os_printf ("\n_location %X:\n", address); acpi_dbg_level |= ACPI_LV_TABLES; - acpi_ut_dump_buffer ((u8 *) address, 64, DB_BYTE_DISPLAY, ACPI_UINT32_MAX); + acpi_ut_dump_buffer (ACPI_TO_POINTER (address), 64, DB_BYTE_DISPLAY, ACPI_UINT32_MAX); } @@ -135,8 +130,9 @@ case ACPI_TYPE_INTEGER: - acpi_os_printf ("[Integer] = %8.8X%8.8X\n", HIDWORD (obj_desc->integer.value), - LODWORD (obj_desc->integer.value)); + acpi_os_printf ("[Integer] = %8.8X%8.8X\n", + ACPI_HIDWORD (obj_desc->integer.value), + ACPI_LODWORD (obj_desc->integer.value)); break; @@ -152,7 +148,7 @@ case ACPI_TYPE_BUFFER: - acpi_os_printf ("[Buffer] = "); + acpi_os_printf ("[Buffer] Length %.2X = ", obj_desc->buffer.length); acpi_ut_dump_buffer ((u8 *) obj_desc->buffer.pointer, obj_desc->buffer.length, DB_DWORD_DISPLAY, _COMPONENT); break; @@ -215,7 +211,7 @@ return; } - STRUPR (name); + ACPI_STRUPR (name); /* Convert a leading forward slash to a backslash */ @@ -260,7 +256,7 @@ acpi_parse_object *root) { acpi_parse_object *op = root; - acpi_parse2_object *method; + acpi_parse_object *method; acpi_parse_object *search_op; acpi_parse_object *start_op; acpi_status status = AE_OK; @@ -268,15 +264,16 @@ acpi_walk_state *walk_state; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("Pass two parse ....\n"); - while (op) { - if (op->opcode == AML_METHOD_OP) { - method = (acpi_parse2_object *) op; + if (op->common.aml_opcode == AML_METHOD_OP) { + method = op; + + /* Create a new walk state for the parse */ walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, NULL); @@ -284,32 +281,32 @@ return (AE_NO_MEMORY); } + /* Init the Walk State */ walk_state->parser_state.aml = - walk_state->parser_state.aml_start = method->data; + walk_state->parser_state.aml_start = method->named.data; walk_state->parser_state.aml_end = - walk_state->parser_state.pkg_end = method->data + method->length; + walk_state->parser_state.pkg_end = method->named.data + method->named.length; walk_state->parser_state.start_scope = op; walk_state->descending_callback = acpi_ds_load1_begin_op; walk_state->ascending_callback = acpi_ds_load1_end_op; + /* Perform the AML parse */ status = acpi_ps_parse_aml (walk_state); - - base_aml_offset = (method->value.arg)->aml_offset + 1; - start_op = (method->value.arg)->next; + base_aml_offset = (method->common.value.arg)->common.aml_offset + 1; + start_op = (method->common.value.arg)->common.next; search_op = start_op; while (search_op) { - search_op->aml_offset += base_aml_offset; + search_op->common.aml_offset += base_aml_offset; search_op = acpi_ps_get_depth_next (start_op, search_op); } - } - if (op->opcode == AML_REGION_OP) { + if (op->common.aml_opcode == AML_REGION_OP) { /* TBD: [Investigate] this isn't quite the right thing to do! */ /* * @@ -339,6 +336,9 @@ * * DESCRIPTION: Lookup a name in the ACPI namespace * + * Note: Currently begins search from the root. Could be enhanced to use + * the current prefix (scope) node as the search beginning point. + * ******************************************************************************/ acpi_namespace_node * @@ -360,21 +360,17 @@ return (NULL); } - /* Lookup the name */ - - /* TBD: [Investigate] what scope do we use? */ - /* Use the root scope for the start of the search */ - - status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, IMODE_EXECUTE, - NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, NULL, &node); - + /* + * Lookup the name. + * (Uses root node as the search starting point) + */ + status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could not locate name: %s %s\n", name, acpi_format_exception (status)); } - ACPI_MEM_FREE (internal_path); - return (node); } diff -Nur linux-2.4.19/drivers/acpi/debugger/dbxface.c linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbxface.c --- linux-2.4.19/drivers/acpi/debugger/dbxface.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/debugger/dbxface.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dbxface - AML Debugger external interfaces - * $Revision: 45 $ + * $Revision: 59 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,19 +25,14 @@ #include "acpi.h" -#include "acparser.h" #include "amlcode.h" -#include "acnamesp.h" -#include "acparser.h" -#include "acevents.h" -#include "acinterp.h" #include "acdebug.h" #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER - MODULE_NAME ("dbxface") + ACPI_MODULE_NAME ("dbxface") /******************************************************************************* @@ -64,30 +59,40 @@ acpi_status status = AE_OK; u32 original_debug_level; acpi_parse_object *display_op; + acpi_parse_object *parent_op; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - /* Is there a breakpoint set? */ + /* Check for single-step breakpoint */ - if (walk_state->method_breakpoint) { + if (walk_state->method_breakpoint && + (walk_state->method_breakpoint <= op->common.aml_offset)) { /* Check if the breakpoint has been reached or passed */ + /* Hit the breakpoint, resume single step, reset breakpoint */ - if (walk_state->method_breakpoint <= op->aml_offset) { - /* Hit the breakpoint, resume single step, reset breakpoint */ + acpi_os_printf ("***Break*** at AML offset %X\n", op->common.aml_offset); + acpi_gbl_cm_single_step = TRUE; + acpi_gbl_step_to_next_call = FALSE; + walk_state->method_breakpoint = 0; + } - acpi_os_printf ("***Break*** at AML offset %X\n", op->aml_offset); - acpi_gbl_cm_single_step = TRUE; - acpi_gbl_step_to_next_call = FALSE; - walk_state->method_breakpoint = 0; - } + /* Check for user breakpoint (Must be on exact Aml offset) */ + + else if (walk_state->user_breakpoint && + (walk_state->user_breakpoint == op->common.aml_offset)) { + acpi_os_printf ("***User_breakpoint*** at AML offset %X\n", op->common.aml_offset); + acpi_gbl_cm_single_step = TRUE; + acpi_gbl_step_to_next_call = FALSE; + walk_state->method_breakpoint = 0; } + /* * Check if this is an opcode that we are interested in -- * namely, opcodes that have arguments */ - if (op->opcode == AML_INT_NAMEDFIELD_OP) { + if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { return (AE_OK); } @@ -95,6 +100,9 @@ case AML_CLASS_UNKNOWN: case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */ return (AE_OK); + + default: + /* All other opcodes -- continue */ break; } @@ -116,15 +124,41 @@ */ original_debug_level = acpi_dbg_level; acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS); - next = op->next; - op->next = NULL; + next = op->common.next; + op->common.next = NULL; display_op = op; - if (op->parent) { - if ((op->parent->opcode == AML_IF_OP) || - (op->parent->opcode == AML_WHILE_OP)) { - display_op = op->parent; + parent_op = op->common.parent; + if (parent_op) { + if ((walk_state->control_state) && + (walk_state->control_state->common.state == ACPI_CONTROL_PREDICATE_EXECUTING)) { + /* + * We are executing the predicate of an IF or WHILE statement + * Search upwards for the containing IF or WHILE so that the + * entire predicate can be displayed. + */ + while (parent_op) { + if ((parent_op->common.aml_opcode == AML_IF_OP) || + (parent_op->common.aml_opcode == AML_WHILE_OP)) { + display_op = parent_op; + break; + } + parent_op = parent_op->common.parent; + } + } + else { + while (parent_op) { + if ((parent_op->common.aml_opcode == AML_IF_OP) || + (parent_op->common.aml_opcode == AML_ELSE_OP) || + (parent_op->common.aml_opcode == AML_SCOPE_OP) || + (parent_op->common.aml_opcode == AML_METHOD_OP) || + (parent_op->common.aml_opcode == AML_WHILE_OP)) { + break; + } + display_op = parent_op; + parent_op = parent_op->common.parent; + } } } @@ -132,23 +166,23 @@ acpi_db_display_op (walk_state, display_op, ACPI_UINT32_MAX); - if ((op->opcode == AML_IF_OP) || - (op->opcode == AML_WHILE_OP)) { + if ((op->common.aml_opcode == AML_IF_OP) || + (op->common.aml_opcode == AML_WHILE_OP)) { if (walk_state->control_state->common.value) { - acpi_os_printf ("Predicate was TRUE, executed block\n"); + acpi_os_printf ("Predicate = [True], IF block was executed\n"); } else { - acpi_os_printf ("Predicate is FALSE, skipping block\n"); + acpi_os_printf ("Predicate = [False], Skipping IF block\n"); } } - else if (op->opcode == AML_ELSE_OP) { - /* TBD */ + else if (op->common.aml_opcode == AML_ELSE_OP) { + acpi_os_printf ("Predicate = [False], ELSE block was executed\n"); } /* Restore everything */ - op->next = next; + op->common.next = next; acpi_os_printf ("\n"); acpi_dbg_level = original_debug_level; } @@ -159,13 +193,12 @@ return (AE_OK); } - /* * If we are executing a step-to-call command, * Check if this is a method call. */ if (acpi_gbl_step_to_next_call) { - if (op->opcode != AML_INT_METHODCALL_OP) { + if (op->common.aml_opcode != AML_INT_METHODCALL_OP) { /* Not a method call, just keep executing */ return (AE_OK); @@ -176,19 +209,16 @@ acpi_gbl_step_to_next_call = FALSE; } - /* * If the next opcode is a method call, we will "step over" it * by default. */ - if (op->opcode == AML_INT_METHODCALL_OP) { + if (op->common.aml_opcode == AML_INT_METHODCALL_OP) { acpi_gbl_cm_single_step = FALSE; /* No more single step while executing called method */ - /* Set the breakpoint on the call, it will stop execution as soon as we return */ - - /* TBD: [Future] don't kill the user breakpoint! */ + /* Set the breakpoint on/before the call, it will stop execution as soon as we return */ - walk_state->method_breakpoint = /* Op->Aml_offset + */ 1; /* Must be non-zero! */ + walk_state->method_breakpoint = 1; /* Must be non-zero! */ } @@ -204,8 +234,14 @@ if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) { /* Handshake with the front-end that gets user command lines */ - acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); - acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY); + status = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); + if (ACPI_FAILURE (status)) { + return (status); + } + status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY); + if (ACPI_FAILURE (status)) { + return (status); + } } else { @@ -213,20 +249,20 @@ /* Force output to console until a command is entered */ - acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); + acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT); /* Different prompt if method is executing */ if (!acpi_gbl_method_executing) { - acpi_os_printf ("%1c ", DB_COMMAND_PROMPT); + acpi_os_printf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); } else { - acpi_os_printf ("%1c ", DB_EXECUTE_PROMPT); + acpi_os_printf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); } /* Get the user input line */ - acpi_os_get_line (acpi_gbl_db_line_buf); + (void) acpi_os_get_line (acpi_gbl_db_line_buf); } status = acpi_db_command_dispatch (acpi_gbl_db_line_buf, walk_state, op); @@ -252,20 +288,39 @@ * ******************************************************************************/ -int +acpi_status acpi_db_initialize (void) { + acpi_status status; /* Init globals */ - acpi_gbl_db_buffer = acpi_os_callocate (ACPI_DEBUG_BUFFER_SIZE); + acpi_gbl_db_buffer = NULL; + acpi_gbl_db_filename = NULL; + acpi_gbl_db_output_to_file = FALSE; + + acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2; + acpi_gbl_db_console_debug_level = NORMAL_DEFAULT | ACPI_LV_TABLES; + acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; + + acpi_gbl_db_opt_tables = FALSE; + acpi_gbl_db_opt_disasm = FALSE; + acpi_gbl_db_opt_stats = FALSE; + acpi_gbl_db_opt_verbose = TRUE; + acpi_gbl_db_opt_ini_methods = TRUE; + + acpi_gbl_db_buffer = acpi_os_allocate (ACPI_DEBUG_BUFFER_SIZE); + if (!acpi_gbl_db_buffer) { + return (AE_NO_MEMORY); + } + ACPI_MEMSET (acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE); /* Initial scope is the root */ acpi_gbl_db_scope_buf [0] = '\\'; acpi_gbl_db_scope_buf [1] = 0; - + acpi_gbl_db_scope_node = acpi_gbl_root_node; /* * If configured for multi-thread support, the debug executor runs in @@ -275,12 +330,24 @@ if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { /* These were created with one unit, grab it */ - acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); - acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY); + status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE); + if (ACPI_FAILURE (status)) { + acpi_os_printf ("Could not get debugger mutex\n"); + return (status); + } + status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY); + if (ACPI_FAILURE (status)) { + acpi_os_printf ("Could not get debugger mutex\n"); + return (status); + } /* Create the debug execution thread to execute commands */ - acpi_os_queue_for_execution (0, acpi_db_execute_thread, NULL); + status = acpi_os_queue_for_execution (0, acpi_db_execute_thread, NULL); + if (ACPI_FAILURE (status)) { + acpi_os_printf ("Could not start debugger thread\n"); + return (status); + } } if (!acpi_gbl_db_opt_verbose) { @@ -289,7 +356,7 @@ acpi_gbl_db_opt_stats = FALSE; } - return (0); + return (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/dispatcher/Makefile linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/Makefile --- linux-2.4.19/drivers/acpi/dispatcher/Makefile Wed Jun 20 17:47:39 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dsfield.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsfield.c --- linux-2.4.19/drivers/acpi/dispatcher/dsfield.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsfield.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dsfield - Dispatcher field routines - * $Revision: 46 $ + * $Revision: 65 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dsfield") + ACPI_MODULE_NAME ("dsfield") /******************************************************************************* @@ -65,14 +65,16 @@ acpi_namespace_node *node; acpi_status status; acpi_operand_object *obj_desc; + acpi_operand_object *second_desc = NULL; + u32 flags; - FUNCTION_TRACE ("Ds_create_buffer_field"); + ACPI_FUNCTION_TRACE ("Ds_create_buffer_field"); /* Get the Name_string argument */ - if (op->opcode == AML_CREATE_FIELD_OP) { + if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { arg = acpi_ps_get_arg (op, 3); } else { @@ -86,12 +88,23 @@ } /* + * During the load phase, we want to enter the name of the field into + * the namespace. During the execute phase (when we evaluate the size + * operand), we want to lookup the name + */ + if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) { + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; + } + else { + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND; + } + + /* * Enter the Name_string into the namespace */ - status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, - INTERNAL_TYPE_DEF_ANY, IMODE_LOAD_PASS1, - NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - walk_state, &(node)); + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + INTERNAL_TYPE_DEF_ANY, ACPI_IMODE_LOAD_PASS1, + flags, walk_state, &(node)); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -100,14 +113,15 @@ * for now, we will put it in the "op" object that the parser uses, so we * can get it again at the end of this scope */ - op->node = node; + op->common.node = node; /* * If there is no object attached to the node, this node was just created and * we need to create the field object. Otherwise, this was a lookup of an * existing node and we don't want to create the field object again. */ - if (node->object) { + obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { return_ACPI_STATUS (AE_OK); } @@ -125,27 +139,21 @@ } /* - * Allocate a method object for this field unit - */ - obj_desc->buffer_field.extra = acpi_ut_create_internal_object ( - INTERNAL_TYPE_EXTRA); - if (!obj_desc->buffer_field.extra) { - status = AE_NO_MEMORY; - goto cleanup; - } - - /* * Remember location in AML stream of the field unit * opcode and operands -- since the buffer and index * operands must be evaluated. */ - obj_desc->buffer_field.extra->extra.aml_start = ((acpi_parse2_object *) op)->data; - obj_desc->buffer_field.extra->extra.aml_length = ((acpi_parse2_object *) op)->length; + second_desc = obj_desc->common.next_object; + second_desc->extra.aml_start = op->named.data; + second_desc->extra.aml_length = op->named.length; obj_desc->buffer_field.node = node; - /* Attach constructed field descriptor to parent node */ + /* Attach constructed field descriptors to parent node */ status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_BUFFER_FIELD); + if (ACPI_FAILURE (status)) { + goto cleanup; + } cleanup: @@ -179,9 +187,10 @@ acpi_parse_object *arg) { acpi_status status; + acpi_integer position; - FUNCTION_TRACE_U32 ("Ds_get_field_names", info); + ACPI_FUNCTION_TRACE_PTR ("Ds_get_field_names", info); /* First field starts at bit zero */ @@ -197,48 +206,75 @@ * 2) Access_as - changes the access mode * 3) Name - Enters a new named field into the namespace */ - switch (arg->opcode) { + switch (arg->common.aml_opcode) { case AML_INT_RESERVEDFIELD_OP: - info->field_bit_position += arg->value.size; + position = (acpi_integer) info->field_bit_position + + (acpi_integer) arg->common.value.size; + + if (position > ACPI_UINT32_MAX) { + ACPI_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n")); + return_ACPI_STATUS (AE_SUPPORT); + } + + info->field_bit_position = (u32) position; break; case AML_INT_ACCESSFIELD_OP: /* - * Get a new Access_type and Access_attribute for all - * entries (until end or another Access_as keyword) + * Get a new Access_type and Access_attribute -- to be used for all + * field units that follow, until field end or another Access_as keyword. + * + * In Field_flags, preserve the flag bits other than the ACCESS_TYPE bits */ - info->field_flags = (u8) ((info->field_flags & FIELD_ACCESS_TYPE_MASK) || - ((u8) (arg->value.integer >> 8))); + info->field_flags = (u8) ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | + ((u8) (arg->common.value.integer32 >> 8))); + + info->attribute = (u8) (arg->common.value.integer32); break; case AML_INT_NAMEDFIELD_OP: - /* Enter a new field name into the namespace */ + /* Lookup the name */ status = acpi_ns_lookup (walk_state->scope_info, - (NATIVE_CHAR *) &((acpi_parse2_object *)arg)->name, - info->field_type, IMODE_LOAD_PASS1, - NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &info->field_node); + (NATIVE_CHAR *) &arg->named.name, + info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE, + walk_state, &info->field_node); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + if (status != AE_ALREADY_EXISTS) { + return_ACPI_STATUS (status); + } + + ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n", + &arg->named.name)); + } + else { + arg->common.node = info->field_node; + info->field_bit_length = arg->common.value.size; + + /* Create and initialize an object for the new Field Node */ + + status = acpi_ex_prep_field_value (info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - /* Create and initialize an object for the new Field Node */ + /* Keep track of bit position for the next field */ - info->field_bit_length = arg->value.size; + position = (acpi_integer) info->field_bit_position + + (acpi_integer) arg->common.value.size; - status = acpi_ex_prep_field_value (info); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + if (position > ACPI_UINT32_MAX) { + ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", + &info->field_node->name)); + return_ACPI_STATUS (AE_SUPPORT); } - /* Keep track of bit position for the next field */ - info->field_bit_position += info->field_bit_length; break; @@ -246,12 +282,11 @@ default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n", - arg->opcode)); - return_ACPI_STATUS (AE_AML_ERROR); - break; + arg->common.aml_opcode)); + return_ACPI_STATUS (AE_AML_BAD_OPCODE); } - arg = arg->next; + arg = arg->common.next; } return_ACPI_STATUS (AE_OK); @@ -278,21 +313,21 @@ acpi_namespace_node *region_node, acpi_walk_state *walk_state) { - acpi_status status = AE_AML_ERROR; + acpi_status status; acpi_parse_object *arg; ACPI_CREATE_FIELD_INFO info; - FUNCTION_TRACE_PTR ("Ds_create_field", op); + ACPI_FUNCTION_TRACE_PTR ("Ds_create_field", op); /* First arg is the name of the parent Op_region (must already exist) */ - arg = op->value.arg; + arg = op->common.value.arg; if (!region_node) { - status = acpi_ns_lookup (walk_state->scope_info, arg->value.name, - ACPI_TYPE_REGION, IMODE_EXECUTE, - NS_SEARCH_PARENT, walk_state, ®ion_node); + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name, + ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, ®ion_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -300,15 +335,16 @@ /* Second arg is the field flags */ - arg = arg->next; - info.field_flags = arg->value.integer8; + arg = arg->common.next; + info.field_flags = arg->common.value.integer8; + info.attribute = 0; /* Each remaining arg is a Named Field */ info.field_type = INTERNAL_TYPE_REGION_FIELD; info.region_node = region_node; - status = acpi_ds_get_field_names (&info, walk_state, arg->next); + status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); return_ACPI_STATUS (status); } @@ -316,6 +352,92 @@ /******************************************************************************* * + * FUNCTION: Acpi_ds_init_field_objects + * + * PARAMETERS: Op - Op containing the Field definition and args + * ` Walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: For each "Field Unit" name in the argument list that is + * part of the field declaration, enter the name into the + * namespace. + * + ******************************************************************************/ + +acpi_status +acpi_ds_init_field_objects ( + acpi_parse_object *op, + acpi_walk_state *walk_state) +{ + acpi_status status; + acpi_parse_object *arg = NULL; + acpi_namespace_node *node; + u8 type = 0; + + + ACPI_FUNCTION_TRACE_PTR ("Ds_init_field_objects", op); + + + switch (walk_state->opcode) { + case AML_FIELD_OP: + arg = acpi_ps_get_arg (op, 2); + type = INTERNAL_TYPE_REGION_FIELD; + break; + + case AML_BANK_FIELD_OP: + arg = acpi_ps_get_arg (op, 4); + type = INTERNAL_TYPE_BANK_FIELD; + break; + + case AML_INDEX_FIELD_OP: + arg = acpi_ps_get_arg (op, 3); + type = INTERNAL_TYPE_INDEX_FIELD; + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Walk the list of entries in the Field_list + */ + while (arg) { + /* Ignore OFFSET and ACCESSAS terms here */ + + if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { + status = acpi_ns_lookup (walk_state->scope_info, + (NATIVE_CHAR *) &arg->named.name, + type, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, + walk_state, &node); + if (ACPI_FAILURE (status)) { + if (status != AE_ALREADY_EXISTS) { + return_ACPI_STATUS (status); + } + + ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n", + &arg->named.name)); + + /* Name already exists, just ignore this error */ + + status = AE_OK; + } + + arg->common.node = node; + } + + /* Move to next field in the list */ + + arg = arg->common.next; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: Acpi_ds_create_bank_field * * PARAMETERS: Op - Op containing the Field definition and args @@ -334,21 +456,21 @@ acpi_namespace_node *region_node, acpi_walk_state *walk_state) { - acpi_status status = AE_AML_ERROR; + acpi_status status; acpi_parse_object *arg; ACPI_CREATE_FIELD_INFO info; - FUNCTION_TRACE_PTR ("Ds_create_bank_field", op); + ACPI_FUNCTION_TRACE_PTR ("Ds_create_bank_field", op); /* First arg is the name of the parent Op_region (must already exist) */ - arg = op->value.arg; + arg = op->common.value.arg; if (!region_node) { - status = acpi_ns_lookup (walk_state->scope_info, arg->value.name, - ACPI_TYPE_REGION, IMODE_EXECUTE, - NS_SEARCH_PARENT, walk_state, ®ion_node); + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name, + ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, ®ion_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -356,30 +478,30 @@ /* Second arg is the Bank Register (must already exist) */ - arg = arg->next; - status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, - INTERNAL_TYPE_BANK_FIELD_DEFN, IMODE_EXECUTE, - NS_SEARCH_PARENT, walk_state, &info.register_node); + arg = arg->common.next; + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + INTERNAL_TYPE_BANK_FIELD_DEFN, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Third arg is the Bank_value */ - arg = arg->next; - info.bank_value = arg->value.integer32; + arg = arg->common.next; + info.bank_value = arg->common.value.integer32; /* Fourth arg is the field flags */ - arg = arg->next; - info.field_flags = arg->value.integer8; + arg = arg->common.next; + info.field_flags = arg->common.value.integer8; /* Each remaining arg is a Named Field */ info.field_type = INTERNAL_TYPE_BANK_FIELD; info.region_node = region_node; - status = acpi_ds_get_field_names (&info, walk_state, arg->next); + status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); return_ACPI_STATUS (status); } @@ -410,33 +532,33 @@ ACPI_CREATE_FIELD_INFO info; - FUNCTION_TRACE_PTR ("Ds_create_index_field", op); + ACPI_FUNCTION_TRACE_PTR ("Ds_create_index_field", op); /* First arg is the name of the Index register (must already exist) */ - arg = op->value.arg; - status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, - ACPI_TYPE_ANY, IMODE_EXECUTE, - NS_SEARCH_PARENT, walk_state, &info.register_node); + arg = op->common.value.arg; + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Second arg is the data register (must already exist) */ - arg = arg->next; - status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, - INTERNAL_TYPE_INDEX_FIELD_DEFN, IMODE_EXECUTE, - NS_SEARCH_PARENT, walk_state, &info.data_register_node); + arg = arg->common.next; + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + INTERNAL_TYPE_INDEX_FIELD_DEFN, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, &info.data_register_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Next arg is the field flags */ - arg = arg->next; - info.field_flags = arg->value.integer8; + arg = arg->common.next; + info.field_flags = arg->common.value.integer8; /* Each remaining arg is a Named Field */ @@ -444,7 +566,7 @@ info.field_type = INTERNAL_TYPE_INDEX_FIELD; info.region_node = region_node; - status = acpi_ds_get_field_names (&info, walk_state, arg->next); + status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dsmethod.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsmethod.c --- linux-2.4.19/drivers/acpi/dispatcher/dsmethod.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsmethod.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dsmethod - Parser/Interpreter interface - control method parsing - * $Revision: 69 $ + * $Revision: 86 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,12 +30,10 @@ #include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" -#include "actables.h" -#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dsmethod") + ACPI_MODULE_NAME ("dsmethod") /******************************************************************************* @@ -68,7 +66,7 @@ acpi_walk_state *walk_state; - FUNCTION_TRACE_PTR ("Ds_parse_method", obj_handle); + ACPI_FUNCTION_TRACE_PTR ("Ds_parse_method", obj_handle); /* Parameter Validation */ @@ -77,14 +75,13 @@ return_ACPI_STATUS (AE_NULL_ENTRY); } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Parsing [%4.4s] **** Named_obj=%p\n", - (char*)&((acpi_namespace_node *)obj_handle)->name, obj_handle)); - + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** Named_obj=%p\n", + ((acpi_namespace_node *) obj_handle)->name.ascii, obj_handle)); /* Extract the method object from the method Node */ node = (acpi_namespace_node *) obj_handle; - obj_desc = node->object; + obj_desc = acpi_ns_get_attached_object (node); if (!obj_desc) { return_ACPI_STATUS (AE_NULL_OBJECT); } @@ -112,13 +109,20 @@ /* Init new op with the method name and pointer back to the Node */ - acpi_ps_set_name (op, node->name); - op->node = node; + acpi_ps_set_name (op, node->name.integer); + op->common.node = node; + + /* + * Get a new Owner_id for objects created by this method. Namespace + * objects (such as Operation Regions) can be created during the + * first pass parse. + */ + owner_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD); + obj_desc->method.owning_id = owner_id; /* Create and initialize a new walk state */ - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, - NULL, NULL, NULL); + walk_state = acpi_ds_create_walk_state (owner_id, NULL, NULL, NULL); if (!walk_state) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -126,7 +130,7 @@ status = acpi_ds_init_aml_walk (walk_state, op, node, obj_desc->method.aml_start, obj_desc->method.aml_length, NULL, NULL, 1); if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ + acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); } @@ -145,16 +149,11 @@ return_ACPI_STATUS (status); } - /* Get a new Owner_id for objects created by this method */ - - owner_id = acpi_ut_allocate_owner_id (OWNER_TYPE_METHOD); - obj_desc->method.owning_id = owner_id; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** [%4.4s] Parsed **** Named_obj=%p Op=%p\n", - (char*)&((acpi_namespace_node *)obj_handle)->name, obj_handle, op)); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "**** [%4.4s] Parsed **** Named_obj=%p Op=%p\n", + ((acpi_namespace_node *) obj_handle)->name.ascii, obj_handle, op)); acpi_ps_delete_parse_tree (op); - return_ACPI_STATUS (status); } @@ -186,14 +185,13 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_PTR ("Ds_begin_method_execution", method_node); + ACPI_FUNCTION_TRACE_PTR ("Ds_begin_method_execution", method_node); if (!method_node) { return_ACPI_STATUS (AE_NULL_ENTRY); } - /* * If there is a concurrency limit on this method, we need to * obtain a unit from the method semaphore. @@ -221,13 +219,11 @@ WAIT_FOREVER); } - /* * Increment the method parse tree thread count since it has been * reentered one more time (even if it is the same thread) */ obj_desc->method.thread_count++; - return_ACPI_STATUS (status); } @@ -247,9 +243,9 @@ acpi_status acpi_ds_call_control_method ( - acpi_walk_list *walk_list, + ACPI_THREAD_STATE *thread, acpi_walk_state *this_walk_state, - acpi_parse_object *op) /* TBD: This operand is obsolete */ + acpi_parse_object *op) { acpi_status status; acpi_namespace_node *method_node; @@ -258,7 +254,7 @@ u32 i; - FUNCTION_TRACE_PTR ("Ds_call_control_method", this_walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_call_control_method", this_walk_state); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n", this_walk_state->prev_op, this_walk_state)); @@ -284,14 +280,12 @@ return_ACPI_STATUS (status); } - /* 1) Parse: Create a new walk state for the preempting walk */ next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, op, obj_desc, NULL); if (!next_walk_state) { return_ACPI_STATUS (AE_NO_MEMORY); - goto cleanup; } /* Create and init a Root Node */ @@ -306,7 +300,7 @@ obj_desc->method.aml_start, obj_desc->method.aml_length, NULL, NULL, 1); if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ + acpi_ds_delete_walk_state (next_walk_state); goto cleanup; } @@ -315,11 +309,10 @@ status = acpi_ps_parse_aml (next_walk_state); acpi_ps_delete_parse_tree (op); - /* 2) Execute: Create a new state for the preempting walk */ next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, - NULL, obj_desc, walk_list); + NULL, obj_desc, thread); if (!next_walk_state) { status = AE_NO_MEMORY; goto cleanup; @@ -353,8 +346,8 @@ this_walk_state->num_operands = 0; - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Starting nested execution, newstate=%p\n", - next_walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Starting nested execution, newstate=%p\n", next_walk_state)); return_ACPI_STATUS (AE_OK); @@ -362,7 +355,7 @@ /* On error, we must delete the new walk state */ cleanup: - acpi_ds_terminate_control_method (next_walk_state); + (void) acpi_ds_terminate_control_method (next_walk_state); acpi_ds_delete_walk_state (next_walk_state); return_ACPI_STATUS (status); @@ -390,7 +383,7 @@ acpi_status status; - FUNCTION_TRACE_PTR ("Ds_restart_control_method", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_restart_control_method", walk_state); if (return_desc) { @@ -405,7 +398,6 @@ return_ACPI_STATUS (status); } } - else { /* * Delete the return value if it will not be used by the @@ -413,7 +405,6 @@ */ acpi_ut_remove_reference (return_desc); } - } ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, @@ -421,7 +412,6 @@ walk_state->method_call_op, return_desc, walk_state->return_used, walk_state->results, walk_state)); - return_ACPI_STATUS (AE_OK); } @@ -446,12 +436,17 @@ { acpi_operand_object *obj_desc; acpi_namespace_node *method_node; + acpi_status status; - FUNCTION_TRACE_PTR ("Ds_terminate_control_method", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_terminate_control_method", walk_state); - /* The method object should be stored in the walk state */ + if (!walk_state) { + return (AE_BAD_PARAMETER); + } + + /* The current method object was saved in the walk state */ obj_desc = walk_state->method_desc; if (!obj_desc) { @@ -467,14 +462,22 @@ * If this is the last thread executing the method, * we have additional cleanup to perform */ - acpi_ut_acquire_mutex (ACPI_MTX_PARSER); - + status = acpi_ut_acquire_mutex (ACPI_MTX_PARSER); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Signal completion of the execution of this method if necessary */ if (walk_state->method_desc->method.semaphore) { - acpi_os_signal_semaphore ( - walk_state->method_desc->method.semaphore, 1); + status = acpi_os_signal_semaphore ( + walk_state->method_desc->method.semaphore, 1); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not signal method semaphore\n")); + status = AE_OK; + + /* Ignore error and continue cleanup */ + } } /* Decrement the thread count on the method parse tree */ @@ -493,7 +496,11 @@ * Delete any namespace entries created immediately underneath * the method */ - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + if (method_node->child) { acpi_ns_delete_namespace_subtree (method_node); } @@ -503,11 +510,14 @@ * the namespace */ acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id); - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - acpi_ut_release_mutex (ACPI_MTX_PARSER); - return_ACPI_STATUS (AE_OK); + status = acpi_ut_release_mutex (ACPI_MTX_PARSER); + return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dsmthdat.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsmthdat.c --- linux-2.4.19/drivers/acpi/dispatcher/dsmthdat.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsmthdat.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dsmthdat - control method arguments and local variables - * $Revision: 49 $ + * $Revision: 61 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,15 +25,13 @@ #include "acpi.h" -#include "acparser.h" #include "acdispat.h" -#include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dsmthdat") + ACPI_MODULE_NAME ("dsmthdat") /******************************************************************************* @@ -49,49 +47,48 @@ * This allows Ref_of and De_ref_of to work properly for these * special data types. * + * NOTES: Walk_state fields are initialized to zero by the + * ACPI_MEM_CALLOCATE(). + * + * A pseudo-Namespace Node is assigned to each argument and local + * so that Ref_of() can return a pointer to the Node. + * ******************************************************************************/ -acpi_status +void acpi_ds_method_data_init ( acpi_walk_state *walk_state) { u32 i; - FUNCTION_TRACE ("Ds_method_data_init"); + ACPI_FUNCTION_TRACE ("Ds_method_data_init"); - /* - * Walk_state fields are initialized to zero by the - * ACPI_MEM_CALLOCATE(). - * - * An Node is assigned to each argument and local so - * that Ref_of() can return a pointer to the Node. - */ /* Init the method arguments */ for (i = 0; i < MTH_NUM_ARGS; i++) { - MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name, + ACPI_MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name, NAMEOF_ARG_NTE); - walk_state->arguments[i].name |= (i << 24); - walk_state->arguments[i].data_type = ACPI_DESC_TYPE_NAMED; - walk_state->arguments[i].type = ACPI_TYPE_ANY; - walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG; + walk_state->arguments[i].name.integer |= (i << 24); + walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED; + walk_state->arguments[i].type = ACPI_TYPE_ANY; + walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG; } /* Init the method locals */ for (i = 0; i < MTH_NUM_LOCALS; i++) { - MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name, + ACPI_MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name, NAMEOF_LOCAL_NTE); - walk_state->local_variables[i].name |= (i << 24); - walk_state->local_variables[i].data_type = ACPI_DESC_TYPE_NAMED; - walk_state->local_variables[i].type = ACPI_TYPE_ANY; - walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL; + walk_state->local_variables[i].name.integer |= (i << 24); + walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED; + walk_state->local_variables[i].type = ACPI_TYPE_ANY; + walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL; } - return_ACPI_STATUS (AE_OK); + return_VOID; } @@ -101,64 +98,50 @@ * * PARAMETERS: Walk_state - Current walk state object * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Delete method locals and arguments. Arguments are only * deleted if this method was called from another method. * ******************************************************************************/ -acpi_status +void acpi_ds_method_data_delete_all ( acpi_walk_state *walk_state) { u32 index; - acpi_operand_object *object; - FUNCTION_TRACE ("Ds_method_data_delete_all"); + ACPI_FUNCTION_TRACE ("Ds_method_data_delete_all"); - /* Delete the locals */ - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting local variables in %p\n", walk_state)); + /* Detach the locals */ for (index = 0; index < MTH_NUM_LOCALS; index++) { - object = walk_state->local_variables[index].object; - if (object) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Local%d=%p\n", index, object)); - - /* Remove first */ + if (walk_state->local_variables[index].object) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Local%d=%p\n", + index, walk_state->local_variables[index].object)); - walk_state->local_variables[index].object = NULL; + /* Detach object (if present) and remove a reference */ - /* Was given a ref when stored */ - - acpi_ut_remove_reference (object); - } + acpi_ns_detach_object (&walk_state->local_variables[index]); + } } - - /* Delete the arguments */ - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting arguments in %p\n", walk_state)); + /* Detach the arguments */ for (index = 0; index < MTH_NUM_ARGS; index++) { - object = walk_state->arguments[index].object; - if (object) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Arg%d=%p\n", index, object)); - - /* Remove first */ - - walk_state->arguments[index].object = NULL; + if (walk_state->arguments[index].object) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Arg%d=%p\n", + index, walk_state->arguments[index].object)); - /* Was given a ref when stored */ + /* Detach object (if present) and remove a reference */ - acpi_ut_remove_reference (object); + acpi_ns_detach_object (&walk_state->arguments[index]); } } - return_ACPI_STATUS (AE_OK); + return_VOID; } @@ -172,7 +155,9 @@ * * RETURN: Status * - * DESCRIPTION: Initialize arguments for a method + * DESCRIPTION: Initialize arguments for a method. The parameter list is a list + * of ACPI operand objects, either null terminated or whose length + * is defined by Max_param_count. * ******************************************************************************/ @@ -183,11 +168,10 @@ acpi_walk_state *walk_state) { acpi_status status; - u32 mindex; - u32 pindex; + u32 index = 0; - FUNCTION_TRACE_PTR ("Ds_method_data_init_args", params); + ACPI_FUNCTION_TRACE_PTR ("Ds_method_data_init_args", params); if (!params) { @@ -197,106 +181,90 @@ /* Copy passed parameters into the new method stack frame */ - for (pindex = mindex = 0; - (mindex < MTH_NUM_ARGS) && (pindex < max_param_count); - mindex++) { - if (params[pindex]) { - /* - * A valid parameter. - * Set the current method argument to the - * Params[Pindex++] argument object descriptor - */ - status = acpi_ds_store_object_to_local (AML_ARG_OP, mindex, - params[pindex], walk_state); - if (ACPI_FAILURE (status)) { - break; - } - - pindex++; + while ((index < MTH_NUM_ARGS) && (index < max_param_count) && params[index]) { + /* + * A valid parameter. + * Store the argument in the method/walk descriptor + */ + status = acpi_ds_store_object_to_local (AML_ARG_OP, index, params[index], + walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - else { - break; - } + index++; } - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%d args passed to method\n", pindex)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%d args passed to method\n", index)); return_ACPI_STATUS (AE_OK); } /******************************************************************************* * - * FUNCTION: Acpi_ds_method_data_get_entry + * FUNCTION: Acpi_ds_method_data_get_node * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - Which local_var or argument to get - * Entry - Pointer to where a pointer to the stack - * entry is returned. + * Index - Which local_var or argument whose type + * to get * Walk_state - Current walk state object * - * RETURN: Status - * - * DESCRIPTION: Get the address of the object entry given by Opcode:Index + * RETURN: Get the Node associated with a local or arg. * ******************************************************************************/ acpi_status -acpi_ds_method_data_get_entry ( +acpi_ds_method_data_get_node ( u16 opcode, u32 index, acpi_walk_state *walk_state, - acpi_operand_object ***entry) + acpi_namespace_node **node) { - - FUNCTION_TRACE_U32 ("Ds_method_data_get_entry", index); + ACPI_FUNCTION_TRACE ("Ds_method_data_get_node"); /* - * Get the requested object. - * The stack "Opcode" is either a Local_variable or an Argument + * Method Locals and Arguments are supported */ switch (opcode) { - case AML_LOCAL_OP: if (index > MTH_MAX_LOCAL) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local_var index %d is invalid (max %d)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n", index, MTH_MAX_LOCAL)); - return_ACPI_STATUS (AE_BAD_PARAMETER); + return_ACPI_STATUS (AE_AML_INVALID_INDEX); } - *entry = (acpi_operand_object **) - &walk_state->local_variables[index].object; - break; + /* Return a pointer to the pseudo-node */ + *node = &walk_state->local_variables[index]; + break; case AML_ARG_OP: if (index > MTH_MAX_ARG) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n", index, MTH_MAX_ARG)); - return_ACPI_STATUS (AE_BAD_PARAMETER); + return_ACPI_STATUS (AE_AML_INVALID_INDEX); } - *entry = (acpi_operand_object **) - &walk_state->arguments[index].object; - break; + /* Return a pointer to the pseudo-node */ + *node = &walk_state->arguments[index]; + break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", opcode)); - return_ACPI_STATUS (AE_BAD_PARAMETER); + return_ACPI_STATUS (AE_AML_BAD_OPCODE); } - return_ACPI_STATUS (AE_OK); } /******************************************************************************* * - * FUNCTION: Acpi_ds_method_data_set_entry + * FUNCTION: Acpi_ds_method_data_set_value * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP * Index - Which local_var or argument to get @@ -310,22 +278,22 @@ ******************************************************************************/ acpi_status -acpi_ds_method_data_set_entry ( +acpi_ds_method_data_set_value ( u16 opcode, u32 index, acpi_operand_object *object, acpi_walk_state *walk_state) { acpi_status status; - acpi_operand_object **entry; + acpi_namespace_node *node; - FUNCTION_TRACE ("Ds_method_data_set_entry"); + ACPI_FUNCTION_TRACE ("Ds_method_data_set_value"); - /* Get a pointer to the stack entry to set */ + /* Get the namespace node for the arg/local */ - status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -336,8 +304,7 @@ /* Install the object into the stack entry */ - *entry = object; - + node->object = object; return_ACPI_STATUS (AE_OK); } @@ -351,105 +318,43 @@ * to get * Walk_state - Current walk state object * - * RETURN: Data type of selected Arg or Local - * Used only in Exec_monadic2()/Type_op. + * RETURN: Data type of current value of the selected Arg or Local * ******************************************************************************/ -acpi_object_type8 +acpi_object_type acpi_ds_method_data_get_type ( u16 opcode, u32 index, acpi_walk_state *walk_state) { acpi_status status; - acpi_operand_object **entry; + acpi_namespace_node *node; acpi_operand_object *object; - FUNCTION_TRACE ("Ds_method_data_get_type"); + ACPI_FUNCTION_TRACE ("Ds_method_data_get_type"); - /* Get a pointer to the requested stack entry */ + /* Get the namespace node for the arg/local */ - status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); if (ACPI_FAILURE (status)) { return_VALUE ((ACPI_TYPE_NOT_FOUND)); } - /* Get the object from the method stack */ - - object = *entry; - - /* Get the object type */ + /* Get the object */ + object = acpi_ns_get_attached_object (node); if (!object) { - /* Any == 0 => "uninitialized" -- see spec 15.2.3.5.2.28 */ - return_VALUE (ACPI_TYPE_ANY); - } - - return_VALUE (object->common.type); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ds_method_data_get_node - * - * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - Which local_var or argument whose type - * to get - * Walk_state - Current walk state object - * - * RETURN: Get the Node associated with a local or arg. - * - ******************************************************************************/ + /* Uninitialized local/arg, return TYPE_ANY */ -acpi_namespace_node * -acpi_ds_method_data_get_node ( - u16 opcode, - u32 index, - acpi_walk_state *walk_state) -{ - acpi_namespace_node *node = NULL; - - - FUNCTION_TRACE ("Ds_method_data_get_node"); - - - switch (opcode) { - - case AML_LOCAL_OP: - - if (index > MTH_MAX_LOCAL) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n", - index, MTH_MAX_LOCAL)); - return_PTR (node); - } - - node = &walk_state->local_variables[index]; - break; - - - case AML_ARG_OP: - - if (index > MTH_MAX_ARG) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n", - index, MTH_MAX_ARG)); - return_PTR (node); - } - - node = &walk_state->arguments[index]; - break; - - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", opcode)); - break; + return_VALUE (ACPI_TYPE_ANY); } + /* Get the object type */ - return_PTR (node); + return_VALUE (object->common.type); } @@ -479,11 +384,11 @@ acpi_operand_object **dest_desc) { acpi_status status; - acpi_operand_object **entry; + acpi_namespace_node *node; acpi_operand_object *object; - FUNCTION_TRACE ("Ds_method_data_get_value"); + ACPI_FUNCTION_TRACE ("Ds_method_data_get_value"); /* Validate the object descriptor */ @@ -493,24 +398,22 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } + /* Get the namespace node for the arg/local */ - /* Get a pointer to the requested method stack entry */ - - status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - /* Get the object from the method stack */ - - object = *entry; + /* Get the object from the node */ + object = node->object; /* Examine the returned object, it must be valid. */ if (!object) { /* - * Index points to uninitialized object stack value. + * Index points to uninitialized object. * This means that either 1) The expected argument was * not passed to the method, or 2) A local variable * was referenced by the method (via the ASL) @@ -519,25 +422,25 @@ switch (opcode) { case AML_ARG_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at entry %p\n", - index, entry)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n", + index, node)); return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG); - break; case AML_LOCAL_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at entry %p\n", - index, entry)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n", + index, node)); return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL); - break; + + default: + return_ACPI_STATUS (AE_AML_INTERNAL); } } - /* - * Index points to initialized and valid object stack value. + * The Index points to an initialized and valid object. * Return an additional reference to the object */ *dest_desc = object; @@ -555,56 +458,56 @@ * Index - Which local_var or argument to delete * Walk_state - Current walk state object * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts * a null into the stack slot after the object is deleted. * ******************************************************************************/ -acpi_status +void acpi_ds_method_data_delete_value ( u16 opcode, u32 index, acpi_walk_state *walk_state) { acpi_status status; - acpi_operand_object **entry; + acpi_namespace_node *node; acpi_operand_object *object; - FUNCTION_TRACE ("Ds_method_data_delete_value"); + ACPI_FUNCTION_TRACE ("Ds_method_data_delete_value"); - /* Get a pointer to the requested entry */ + /* Get the namespace node for the arg/local */ - status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + return_VOID; } - /* Get the current entry in this slot k */ + /* Get the associated object */ - object = *entry; + object = acpi_ns_get_attached_object (node); /* * Undefine the Arg or Local by setting its descriptor * pointer to NULL. Locals/Args can contain both * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs */ - *entry = NULL; + node->object = NULL; if ((object) && - (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL))) { + (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_OPERAND)) { /* - * There is a valid object in this slot + * There is a valid object. * Decrement the reference count by one to balance the - * increment when the object was stored in the slot. + * increment when the object was stored. */ acpi_ut_remove_reference (object); } - return_ACPI_STATUS (AE_OK); + return_VOID; } @@ -614,14 +517,14 @@ * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP * Index - Which local_var or argument to set - * Src_desc - Value to be stored + * Obj_desc - Value to be stored * Walk_state - Current walk state * * RETURN: Status * - * DESCRIPTION: Store a value in an Arg or Local. The Src_desc is installed + * DESCRIPTION: Store a value in an Arg or Local. The Obj_desc is installed * as the new value for the Arg or Local and the reference count - * for Src_desc is incremented. + * for Obj_desc is incremented. * ******************************************************************************/ @@ -629,45 +532,45 @@ acpi_ds_store_object_to_local ( u16 opcode, u32 index, - acpi_operand_object *src_desc, + acpi_operand_object *obj_desc, acpi_walk_state *walk_state) { acpi_status status; - acpi_operand_object **entry; + acpi_namespace_node *node; + acpi_operand_object *current_obj_desc; - FUNCTION_TRACE ("Ds_method_data_set_value"); + ACPI_FUNCTION_TRACE ("Ds_store_object_to_local"); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%d Idx=%d Obj=%p\n", - opcode, index, src_desc)); + opcode, index, obj_desc)); /* Parameter validation */ - if (!src_desc) { + if (!obj_desc) { return_ACPI_STATUS (AE_BAD_PARAMETER); } + /* Get the namespace node for the arg/local */ - /* Get a pointer to the requested method stack entry */ - - status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry); + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); if (ACPI_FAILURE (status)) { - goto cleanup; + return_ACPI_STATUS (status); } - if (*entry == src_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n", src_desc)); - goto cleanup; + current_obj_desc = acpi_ns_get_attached_object (node); + if (current_obj_desc == obj_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n", obj_desc)); + return_ACPI_STATUS (status); } - /* * If there is an object already in this slot, we either * have to delete it, or if this is an argument and there * is an object reference stored there, we have to do * an indirect store! */ - if (*entry) { + if (current_obj_desc) { /* * Check for an indirect store if an argument * contains an object reference (stored as an Node). @@ -685,36 +588,24 @@ * Weird, but true. */ if ((opcode == AML_ARG_OP) && - (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) { + (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) == ACPI_DESC_TYPE_NAMED)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Arg (%p) is an Obj_ref(Node), storing in %p\n", - src_desc, *entry)); + "Arg (%p) is an Obj_ref(Node), storing in node %p\n", + obj_desc, current_obj_desc)); /* Detach an existing object from the Node */ - acpi_ns_detach_object ((acpi_namespace_node *) *entry); + acpi_ns_detach_object ((acpi_namespace_node *) current_obj_desc); /* * Store this object into the Node - * (do the indirect store) + * (perform the indirect store) */ - status = acpi_ns_attach_object ((acpi_namespace_node *) *entry, src_desc, - src_desc->common.type); + status = acpi_ns_attach_object ((acpi_namespace_node *) current_obj_desc, + obj_desc, obj_desc->common.type); return_ACPI_STATUS (status); } - -#ifdef ACPI_ENABLE_IMPLICIT_CONVERSION - /* - * Perform "Implicit conversion" of the new object to the type of the - * existing object - */ - status = acpi_ex_convert_to_target_type ((*entry)->common.type, &src_desc, walk_state); - if (ACPI_FAILURE (status)) { - goto cleanup; - } -#endif - /* * Delete the existing object * before storing the new one @@ -722,27 +613,14 @@ acpi_ds_method_data_delete_value (opcode, index, walk_state); } - /* - * Install the Obj_stack descriptor (*Src_desc) into + * Install the Obj_stack descriptor (*Obj_desc) into * the descriptor for the Arg or Local. * Install the new object in the stack entry * (increments the object reference count by one) */ - status = acpi_ds_method_data_set_entry (opcode, index, src_desc, walk_state); - if (ACPI_FAILURE (status)) { - goto cleanup; - } - - /* Normal exit */ - - return_ACPI_STATUS (AE_OK); - - - /* Error exit */ - -cleanup: - + status = acpi_ds_method_data_set_value (opcode, index, obj_desc, walk_state); return_ACPI_STATUS (status); } + diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dsobject.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsobject.c --- linux-2.4.19/drivers/acpi/dispatcher/dsobject.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsobject.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dsobject - Dispatcher object management routines - * $Revision: 81 $ + * $Revision: 99 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,11 +28,10 @@ #include "acparser.h" #include "amlcode.h" #include "acdispat.h" -#include "acinterp.h" #include "acnamesp.h" #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dsobject") + ACPI_MODULE_NAME ("dsobject") /******************************************************************************* @@ -47,11 +46,11 @@ * RETURN: Status * * DESCRIPTION: Callback from Acpi_walk_namespace. Invoked for every object - * within the namespace. + * within the namespace. * * Currently, the only objects that require initialization are: * 1) Methods - * 2) Op Regions + * 2) Operation Regions * ******************************************************************************/ @@ -62,18 +61,14 @@ void *context, void **return_value) { - acpi_object_type8 type; + acpi_object_type type; acpi_status status; acpi_init_walk_info *info = (acpi_init_walk_info *) context; - u8 table_revision; - PROC_NAME ("Ds_init_one_object"); + ACPI_FUNCTION_NAME ("Ds_init_one_object"); - info->object_count++; - table_revision = info->table_desc->pointer->revision; - /* * We are only interested in objects owned by the table that * was just loaded @@ -83,16 +78,21 @@ return (AE_OK); } + info->object_count++; /* And even then, we are only interested in a few object types */ type = acpi_ns_get_type (obj_handle); switch (type) { - case ACPI_TYPE_REGION: - acpi_ds_initialize_region (obj_handle); + status = acpi_ds_initialize_region (obj_handle); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", + obj_handle, ((acpi_namespace_node *) obj_handle)->name.ascii, + acpi_format_exception (status))); + } info->op_region_count++; break; @@ -109,9 +109,11 @@ /* * Set the execution data width (32 or 64) based upon the * revision number of the parent ACPI table. + * TBD: This is really for possible future support of integer width + * on a per-table basis. Currently, we just use a global for the width. */ - if (table_revision == 1) { - ((acpi_namespace_node *)obj_handle)->flags |= ANOBJ_DATA_WIDTH_32; + if (info->table_desc->pointer->revision == 1) { + ((acpi_namespace_node *) obj_handle)->flags |= ANOBJ_DATA_WIDTH_32; } /* @@ -121,7 +123,7 @@ status = acpi_ds_parse_method (obj_handle); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", - obj_handle, (char*)&((acpi_namespace_node *)obj_handle)->name, + obj_handle, ((acpi_namespace_node *) obj_handle)->name.ascii, acpi_format_exception (status))); /* This parse failed, but we will continue parsing more methods */ @@ -134,8 +136,16 @@ * for every execution since there isn't much overhead */ acpi_ns_delete_namespace_subtree (obj_handle); + acpi_ns_delete_namespace_by_owner (((acpi_namespace_node *) obj_handle)->object->method.owning_id); + break; + + + case ACPI_TYPE_DEVICE: + + info->device_count++; break; + default: break; } @@ -152,12 +162,13 @@ * * FUNCTION: Acpi_ds_initialize_objects * - * PARAMETERS: None + * PARAMETERS: Table_desc - Descriptor for parent ACPI table + * Start_node - Root of subtree to be initialized. * * RETURN: Status * - * DESCRIPTION: Walk the entire namespace and perform any necessary - * initialization on the objects found therein + * DESCRIPTION: Walk the namespace starting at "Start_node" and perform any + * necessary initialization on the objects found therein * ******************************************************************************/ @@ -170,35 +181,35 @@ acpi_init_walk_info info; - FUNCTION_TRACE ("Ds_initialize_objects"); + ACPI_FUNCTION_TRACE ("Ds_initialize_objects"); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Parsing Methods:")); - info.method_count = 0; info.op_region_count = 0; info.object_count = 0; + info.device_count = 0; info.table_desc = table_desc; - /* Walk entire namespace from the supplied root */ status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, acpi_ds_init_one_object, &info, NULL); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Walk_namespace failed! %x\n", status)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Walk_namespace failed, %s\n", + acpi_format_exception (status))); } ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - "\n%d Control Methods found and parsed (%d nodes total)\n", - info.method_count, info.object_count)); - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "%d Control Methods found\n", info.method_count)); + "\n_table [%4.4s] - %hd Objects with %hd Devices %hd Methods %hd Regions\n", + table_desc->pointer->signature, info.object_count, + info.device_count, info.method_count, info.op_region_count)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "%d Op Regions found\n", info.op_region_count)); + "%hd Methods, %hd Regions\n", info.method_count, info.op_region_count)); return_ACPI_STATUS (AE_OK); } @@ -208,9 +219,10 @@ * * FUNCTION: Acpi_ds_init_object_from_op * - * PARAMETERS: Op - Parser op used to init the internal object + * PARAMETERS: Walk_state - Current walk state + * Op - Parser op used to init the internal object * Opcode - AML opcode associated with the object - * Obj_desc - Namespace object to be initialized + * Ret_obj_desc - Namespace object to be initialized * * RETURN: Status * @@ -227,15 +239,11 @@ u16 opcode, acpi_operand_object **ret_obj_desc) { - acpi_status status; - acpi_parse_object *arg; - acpi_parse2_object *byte_list; - acpi_operand_object *arg_desc; const acpi_opcode_info *op_info; acpi_operand_object *obj_desc; - PROC_NAME ("Ds_init_object_from_op"); + ACPI_FUNCTION_NAME ("Ds_init_object_from_op"); obj_desc = *ret_obj_desc; @@ -246,100 +254,41 @@ return (AE_TYPE); } - - /* Get and prepare the first argument */ + /* Perform per-object initialization */ switch (obj_desc->common.type) { case ACPI_TYPE_BUFFER: - /* First arg is a number */ - - acpi_ds_create_operand (walk_state, op->value.arg, 0); - arg_desc = walk_state->operands [walk_state->num_operands - 1]; - acpi_ds_obj_stack_pop (1, walk_state); - - /* Resolve the object (could be an arg or local) */ - - status = acpi_ex_resolve_to_value (&arg_desc, walk_state); - if (ACPI_FAILURE (status)) { - acpi_ut_remove_reference (arg_desc); - return (status); - } - - /* We are expecting a number */ - - if (arg_desc->common.type != ACPI_TYPE_INTEGER) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Expecting number, got obj: %p type %X\n", - arg_desc, arg_desc->common.type)); - acpi_ut_remove_reference (arg_desc); - return (AE_TYPE); - } - - /* Get the value, delete the internal object */ - - obj_desc->buffer.length = (u32) arg_desc->integer.value; - acpi_ut_remove_reference (arg_desc); - - /* Allocate the buffer */ - - if (obj_desc->buffer.length == 0) { - obj_desc->buffer.pointer = NULL; - REPORT_WARNING (("Buffer created with zero length in AML\n")); - break; - } - - else { - obj_desc->buffer.pointer = ACPI_MEM_CALLOCATE ( - obj_desc->buffer.length); - - if (!obj_desc->buffer.pointer) { - return (AE_NO_MEMORY); - } - } - /* - * Second arg is the buffer data (optional) Byte_list can be either - * individual bytes or a string initializer. + * Defer evaluation of Buffer Term_arg operand */ - arg = op->value.arg; /* skip first arg */ - - byte_list = (acpi_parse2_object *) arg->next; - if (byte_list) { - if (byte_list->opcode != AML_INT_BYTELIST_OP) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Expecting bytelist, got: %p\n", - byte_list)); - return (AE_TYPE); - } - - MEMCPY (obj_desc->buffer.pointer, byte_list->data, - obj_desc->buffer.length); - } - + obj_desc->buffer.node = (acpi_namespace_node *) walk_state->operands[0]; + obj_desc->buffer.aml_start = op->named.data; + obj_desc->buffer.aml_length = op->named.length; break; case ACPI_TYPE_PACKAGE: /* - * When called, an internal package object has already been built and - * is pointed to by Obj_desc. Acpi_ds_build_internal_object builds another - * internal package object, so remove reference to the original so - * that it is deleted. Error checking is done within the remove - * reference function. + * Defer evaluation of Package Term_arg operand */ - acpi_ut_remove_reference (obj_desc); - status = acpi_ds_build_internal_object (walk_state, op, ret_obj_desc); + obj_desc->package.node = (acpi_namespace_node *) walk_state->operands[0]; + obj_desc->package.aml_start = op->named.data; + obj_desc->package.aml_length = op->named.length; break; + case ACPI_TYPE_INTEGER: - obj_desc->integer.value = op->value.integer; + + obj_desc->integer.value = op->common.value.integer; break; case ACPI_TYPE_STRING: - obj_desc->string.pointer = op->value.string; - obj_desc->string.length = STRLEN (op->value.string); + + obj_desc->string.pointer = op->common.value.string; + obj_desc->string.length = ACPI_STRLEN (op->common.value.string); /* * The string is contained in the ACPI table, don't ever try @@ -376,22 +325,21 @@ default: /* Constants, Literals, etc.. */ - if (op->opcode == AML_INT_NAMEPATH_OP) { + if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { /* Node was saved in Op */ - obj_desc->reference.node = op->node; + obj_desc->reference.node = op->common.node; } obj_desc->reference.opcode = opcode; break; } - break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %x\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %X\n", obj_desc->common.type)); break; @@ -403,9 +351,10 @@ /***************************************************************************** * - * FUNCTION: Acpi_ds_build_internal_simple_obj + * FUNCTION: Acpi_ds_build_internal_object * - * PARAMETERS: Op - Parser object to be translated + * PARAMETERS: Walk_state - Current walk state + * Op - Parser object to be translated * Obj_desc_ptr - Where the ACPI internal object is returned * * RETURN: Status @@ -415,96 +364,76 @@ * ****************************************************************************/ -static acpi_status -acpi_ds_build_internal_simple_obj ( +acpi_status +acpi_ds_build_internal_object ( acpi_walk_state *walk_state, acpi_parse_object *op, acpi_operand_object **obj_desc_ptr) { acpi_operand_object *obj_desc; - acpi_object_type8 type; acpi_status status; - u32 length; char *name; - FUNCTION_TRACE ("Ds_build_internal_simple_obj"); + ACPI_FUNCTION_TRACE ("Ds_build_internal_object"); - if (op->opcode == AML_INT_NAMEPATH_OP) { + if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { /* - * This is an object reference. If The name was - * previously looked up in the NS, it is stored in this op. + * This is an object reference. If this name was + * previously looked up in the namespace, it was stored in this op. * Otherwise, go ahead and look it up now */ - if (!op->node) { - status = acpi_ns_lookup (walk_state->scope_info, - op->value.string, ACPI_TYPE_ANY, - IMODE_EXECUTE, - NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, - NULL, - (acpi_namespace_node **)&(op->node)); + if (!op->common.node) { + status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, + (acpi_namespace_node **) &(op->common.node)); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { name = NULL; - acpi_ns_externalize_name (ACPI_UINT32_MAX, op->value.string, &length, &name); - - if (name) { - REPORT_WARNING (("Reference %s at AML %X not found\n", - name, op->aml_offset)); + status = acpi_ns_externalize_name (ACPI_UINT32_MAX, op->common.value.string, NULL, &name); + if (ACPI_SUCCESS (status)) { + ACPI_REPORT_WARNING (("Reference %s at AML %X not found\n", + name, op->common.aml_offset)); ACPI_MEM_FREE (name); } - else { - REPORT_WARNING (("Reference %s at AML %X not found\n", - op->value.string, op->aml_offset)); + ACPI_REPORT_WARNING (("Reference %s at AML %X not found\n", + op->common.value.string, op->common.aml_offset)); } *obj_desc_ptr = NULL; } - else { return_ACPI_STATUS (status); } } } - - /* - * The reference will be a Reference - * TBD: [Restructure] unless we really need a separate - * type of INTERNAL_TYPE_REFERENCE change - * Acpi_ds_map_opcode_to_data_type to handle this case - */ - type = INTERNAL_TYPE_REFERENCE; - } - else { - type = acpi_ds_map_opcode_to_data_type (op->opcode, NULL); } - /* Create and init the internal ACPI object */ - obj_desc = acpi_ut_create_internal_object (type); + obj_desc = acpi_ut_create_internal_object ((acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type); if (!obj_desc) { return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_object_from_op (walk_state, op, op->opcode, &obj_desc); + status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, &obj_desc); if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); } *obj_desc_ptr = obj_desc; - return_ACPI_STATUS (AE_OK); } /***************************************************************************** * - * FUNCTION: Acpi_ds_build_internal_package_obj + * FUNCTION: Acpi_ds_build_internal_buffer_obj * * PARAMETERS: Op - Parser object to be translated * Obj_desc_ptr - Where the ACPI internal object is returned @@ -517,114 +446,211 @@ ****************************************************************************/ acpi_status -acpi_ds_build_internal_package_obj ( +acpi_ds_build_internal_buffer_obj ( acpi_walk_state *walk_state, acpi_parse_object *op, + u32 buffer_length, acpi_operand_object **obj_desc_ptr) { acpi_parse_object *arg; acpi_operand_object *obj_desc; - acpi_status status = AE_OK; + acpi_parse_object *byte_list; + u32 byte_list_length = 0; - FUNCTION_TRACE ("Ds_build_internal_package_obj"); + ACPI_FUNCTION_TRACE ("Ds_build_internal_buffer_obj"); - obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE); - *obj_desc_ptr = obj_desc; - if (!obj_desc) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - if (op->opcode == AML_VAR_PACKAGE_OP) { + obj_desc = *obj_desc_ptr; + if (obj_desc) { /* - * Variable length package parameters are evaluated JIT + * We are evaluating a Named buffer object "Name (xxxx, Buffer)". + * The buffer object already exists (from the NS node) */ - return_ACPI_STATUS (AE_OK); } + else { + /* Create a new buffer object */ - /* The first argument must be the package length */ - - arg = op->value.arg; - obj_desc->package.count = arg->value.integer32; + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); + *obj_desc_ptr = obj_desc; + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } /* - * Allocate the array of pointers (ptrs to the - * individual objects) Add an extra pointer slot so - * that the list is always null terminated. + * Second arg is the buffer data (optional) Byte_list can be either + * individual bytes or a string initializer. In either case, a + * Byte_list appears in the AML. */ - obj_desc->package.elements = ACPI_MEM_CALLOCATE ( - (obj_desc->package.count + 1) * sizeof (void *)); + arg = op->common.value.arg; /* skip first arg */ - if (!obj_desc->package.elements) { - acpi_ut_delete_object_desc (obj_desc); - return_ACPI_STATUS (AE_NO_MEMORY); - } + byte_list = arg->named.next; + if (byte_list) { + if (byte_list->common.aml_opcode != AML_INT_BYTELIST_OP) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Expecting bytelist, got AML opcode %X in op %p\n", + byte_list->common.aml_opcode, byte_list)); - obj_desc->package.next_element = obj_desc->package.elements; + acpi_ut_remove_reference (obj_desc); + return (AE_TYPE); + } + + byte_list_length = byte_list->common.value.integer32; + } /* - * Now init the elements of the package + * The buffer length (number of bytes) will be the larger of: + * 1) The specified buffer length and + * 2) The length of the initializer byte list */ - arg = arg->next; - while (arg) { - if (arg->opcode == AML_PACKAGE_OP) { - status = acpi_ds_build_internal_package_obj (walk_state, arg, - obj_desc->package.next_element); - } + obj_desc->buffer.length = buffer_length; + if (byte_list_length > buffer_length) { + obj_desc->buffer.length = byte_list_length; + } - else { - status = acpi_ds_build_internal_simple_obj (walk_state, arg, - obj_desc->package.next_element); - } + /* Allocate the buffer */ - obj_desc->package.next_element++; - arg = arg->next; + if (obj_desc->buffer.length == 0) { + obj_desc->buffer.pointer = NULL; + ACPI_REPORT_WARNING (("Buffer created with zero length in AML\n")); + return_ACPI_STATUS (AE_OK); } - obj_desc->package.flags |= AOPOBJ_DATA_VALID; - return_ACPI_STATUS (status); + obj_desc->buffer.pointer = ACPI_MEM_CALLOCATE ( + obj_desc->buffer.length); + if (!obj_desc->buffer.pointer) { + acpi_ut_delete_object_desc (obj_desc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize buffer from the Byte_list (if present) */ + + if (byte_list) { + ACPI_MEMCPY (obj_desc->buffer.pointer, byte_list->named.data, + byte_list_length); + } + + obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; + op->common.node = (acpi_namespace_node *) obj_desc; + return_ACPI_STATUS (AE_OK); } /***************************************************************************** * - * FUNCTION: Acpi_ds_build_internal_object + * FUNCTION: Acpi_ds_build_internal_package_obj * * PARAMETERS: Op - Parser object to be translated * Obj_desc_ptr - Where the ACPI internal object is returned * * RETURN: Status * - * DESCRIPTION: Translate a parser Op object to the equivalent namespace - * object + * DESCRIPTION: Translate a parser Op package object to the equivalent + * namespace object * ****************************************************************************/ acpi_status -acpi_ds_build_internal_object ( +acpi_ds_build_internal_package_obj ( acpi_walk_state *walk_state, acpi_parse_object *op, + u32 package_length, acpi_operand_object **obj_desc_ptr) { - acpi_status status; + acpi_parse_object *arg; + acpi_parse_object *parent; + acpi_operand_object *obj_desc = NULL; + u32 package_list_length; + acpi_status status = AE_OK; + u32 i; - switch (op->opcode) { - case AML_PACKAGE_OP: - case AML_VAR_PACKAGE_OP: + ACPI_FUNCTION_TRACE ("Ds_build_internal_package_obj"); - status = acpi_ds_build_internal_package_obj (walk_state, op, obj_desc_ptr); - break; + /* Find the parent of a possibly nested package */ - default: + parent = op->common.parent; + while ((parent->common.aml_opcode == AML_PACKAGE_OP) || + (parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { + parent = parent->common.parent; + } - status = acpi_ds_build_internal_simple_obj (walk_state, op, obj_desc_ptr); - break; + obj_desc = *obj_desc_ptr; + if (obj_desc) { + /* + * We are evaluating a Named package object "Name (xxxx, Package)". + * Get the existing package object from the NS node + */ + } + else { + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE); + *obj_desc_ptr = obj_desc; + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + obj_desc->package.node = parent->common.node; + } + + obj_desc->package.count = package_length; + + /* Count the number of items in the package list */ + + package_list_length = 0; + arg = op->common.value.arg; + arg = arg->common.next; + while (arg) { + package_list_length++; + arg = arg->common.next; + } + + /* + * The package length (number of elements) will be the greater + * of the specified length and the length of the initializer list + */ + if (package_list_length > package_length) { + obj_desc->package.count = package_list_length; } - return (status); + /* + * Allocate the pointer array (array of pointers to the + * individual objects). Add an extra pointer slot so + * that the list is always null terminated. + */ + obj_desc->package.elements = ACPI_MEM_CALLOCATE ( + ((ACPI_SIZE) obj_desc->package.count + 1) * sizeof (void *)); + + if (!obj_desc->package.elements) { + acpi_ut_delete_object_desc (obj_desc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Now init the elements of the package + */ + i = 0; + arg = op->common.value.arg; + arg = arg->common.next; + while (arg) { + if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { + /* Object (package or buffer) is already built */ + + obj_desc->package.elements[i] = ACPI_CAST_PTR (acpi_operand_object, arg->common.node); + } + else { + status = acpi_ds_build_internal_object (walk_state, arg, + &obj_desc->package.elements[i]); + } + + i++; + arg = arg->common.next; + } + + obj_desc->package.flags |= AOPOBJ_DATA_VALID; + op->common.node = (acpi_namespace_node *) obj_desc; + return_ACPI_STATUS (status); } @@ -651,7 +677,7 @@ acpi_operand_object *obj_desc; - FUNCTION_TRACE_PTR ("Ds_create_node", op); + ACPI_FUNCTION_TRACE_PTR ("Ds_create_node", op); /* @@ -659,11 +685,11 @@ * parts of the table, we can arrive here twice. Only init * the named object node the first time through */ - if (node->object) { + if (acpi_ns_get_attached_object (node)) { return_ACPI_STATUS (AE_OK); } - if (!op->value.arg) { + if (!op->common.value.arg) { /* No arguments, there is nothing to do */ return_ACPI_STATUS (AE_OK); @@ -671,7 +697,7 @@ /* Build an internal object for the argument(s) */ - status = acpi_ds_build_internal_object (walk_state, op->value.arg, &obj_desc); + status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -680,9 +706,9 @@ node->type = obj_desc->common.type; - /* Init obj */ + /* Attach obj to node */ - status = acpi_ns_attach_object (node, obj_desc, (u8) node->type); + status = acpi_ns_attach_object (node, obj_desc, node->type); /* Remove local reference to the object */ diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dsopcode.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsopcode.c --- linux-2.4.19/drivers/acpi/dispatcher/dsopcode.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsopcode.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: dsopcode - Dispatcher Op Region support and handling of * "control" opcodes - * $Revision: 56 $ + * $Revision: 79 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,96 +32,70 @@ #include "acinterp.h" #include "acnamesp.h" #include "acevents.h" -#include "actables.h" #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dsopcode") + ACPI_MODULE_NAME ("dsopcode") /***************************************************************************** * - * FUNCTION: Acpi_ds_get_buffer_field_arguments + * FUNCTION: Acpi_ds_execute_arguments * - * PARAMETERS: Obj_desc - A valid Buffer_field object + * PARAMETERS: Node - Parent NS node + * Aml_length - Length of executable AML + * Aml_start - Pointer to the AML * * RETURN: Status. * - * DESCRIPTION: Get Buffer_field Buffer and Index. This implements the late - * evaluation of these field attributes. + * DESCRIPTION: Late execution of region or field arguments * ****************************************************************************/ acpi_status -acpi_ds_get_buffer_field_arguments ( - acpi_operand_object *obj_desc) +acpi_ds_execute_arguments ( + acpi_namespace_node *node, + acpi_namespace_node *scope_node, + u32 aml_length, + u8 *aml_start) { - acpi_operand_object *extra_desc; - acpi_namespace_node *node; - acpi_parse_object *op; - acpi_parse_object *field_op; acpi_status status; - acpi_table_desc *table_desc; + acpi_parse_object *op; acpi_walk_state *walk_state; + acpi_parse_object *arg; - FUNCTION_TRACE_PTR ("Ds_get_buffer_field_arguments", obj_desc); - - - if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { - return_ACPI_STATUS (AE_OK); - } - - - /* Get the AML pointer (method object) and Buffer_field node */ - - extra_desc = obj_desc->buffer_field.extra; - node = obj_desc->buffer_field.node; - - DEBUG_EXEC(acpi_ut_display_init_pathname (node, " [Field]")); - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] Buffer_field JIT Init\n", - (char*)&node->name)); + ACPI_FUNCTION_TRACE ("Acpi_ds_execute_arguments"); /* - * Allocate a new parser op to be the root of the parsed - * Op_region tree + * Allocate a new parser op to be the root of the parsed tree */ - op = acpi_ps_alloc_op (AML_SCOPE_OP); + op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP); if (!op) { - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } /* Save the Node for use in Acpi_ps_parse_aml */ - op->node = acpi_ns_get_parent_object (node); - - /* Get a handle to the parent ACPI table */ - - status = acpi_tb_handle_to_object (node->owner_id, &table_desc); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + op->common.node = scope_node; /* Create and initialize a new parser state */ - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, - NULL, NULL, NULL); + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, NULL); if (!walk_state) { return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, op, NULL, extra_desc->extra.aml_start, - extra_desc->extra.aml_length, NULL, NULL, 1); + status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, + aml_length, NULL, NULL, 1); if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ + acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); } - /* TBD: No Walk flags?? */ - walk_state->parse_flags = 0; - /* Pass1: Parse the entire Buffer_field declaration */ + /* Pass1: Parse the entire declaration */ status = acpi_ps_parse_aml (walk_state); if (ACPI_FAILURE (status)) { @@ -129,182 +103,228 @@ return_ACPI_STATUS (status); } - /* Get and init the actual Field_unit Op created above */ - - field_op = op->value.arg; - op->node = node; - + /* Get and init the Op created above */ - field_op = op->value.arg; - field_op->node = node; + arg = op->common.value.arg; + op->common.node = node; + arg->common.node = node; acpi_ps_delete_parse_tree (op); - /* Evaluate the address and length arguments for the Op_region */ + /* Evaluate the address and length arguments for the Buffer Field */ - op = acpi_ps_alloc_op (AML_SCOPE_OP); + op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP); if (!op) { - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } - op->node = acpi_ns_get_parent_object (node); + op->common.node = scope_node; /* Create and initialize a new parser state */ - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, - NULL, NULL, NULL); + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, NULL); if (!walk_state) { return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, op, NULL, extra_desc->extra.aml_start, - extra_desc->extra.aml_length, NULL, NULL, 3); + status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, + aml_length, NULL, NULL, 3); if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ + acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); } status = acpi_ps_parse_aml (walk_state); acpi_ps_delete_parse_tree (op); - - /* - * The pseudo-method object is no longer needed since the region is - * now initialized - */ - acpi_ut_remove_reference (obj_desc->buffer_field.extra); - obj_desc->buffer_field.extra = NULL; - return_ACPI_STATUS (status); } /***************************************************************************** * - * FUNCTION: Acpi_ds_get_region_arguments + * FUNCTION: Acpi_ds_get_buffer_field_arguments * - * PARAMETERS: Obj_desc - A valid region object + * PARAMETERS: Obj_desc - A valid Buffer_field object * * RETURN: Status. * - * DESCRIPTION: Get region address and length. This implements the late - * evaluation of these region attributes. + * DESCRIPTION: Get Buffer_field Buffer and Index. This implements the late + * evaluation of these field attributes. * ****************************************************************************/ acpi_status -acpi_ds_get_region_arguments ( +acpi_ds_get_buffer_field_arguments ( acpi_operand_object *obj_desc) { - acpi_operand_object *extra_desc = NULL; + acpi_operand_object *extra_desc; acpi_namespace_node *node; - acpi_parse_object *op; - acpi_parse_object *region_op; acpi_status status; - acpi_table_desc *table_desc; - acpi_walk_state *walk_state; - FUNCTION_TRACE_PTR ("Ds_get_region_arguments", obj_desc); + ACPI_FUNCTION_TRACE_PTR ("Ds_get_buffer_field_arguments", obj_desc); - if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { return_ACPI_STATUS (AE_OK); } + /* Get the AML pointer (method object) and Buffer_field node */ - /* Get the AML pointer (method object) and region node */ + extra_desc = acpi_ns_get_secondary_object (obj_desc); + node = obj_desc->buffer_field.node; - extra_desc = obj_desc->region.extra; - node = obj_desc->region.node; + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (node, " [Field]")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] Buffer_field JIT Init\n", + node->name.ascii)); - DEBUG_EXEC(acpi_ut_display_init_pathname (node, " [Operation Region]")); + /* Execute the AML code for the Term_arg arguments */ - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] Op_region Init at AML %p\n", - (char*)&node->name, extra_desc->extra.aml_start)); + status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node), + extra_desc->extra.aml_length, extra_desc->extra.aml_start); + return_ACPI_STATUS (status); +} - /* - * Allocate a new parser op to be the root of the parsed - * Op_region tree - */ - op = acpi_ps_alloc_op (AML_SCOPE_OP); - if (!op) { - return (AE_NO_MEMORY); - } - /* Save the Node for use in Acpi_ps_parse_aml */ +/***************************************************************************** + * + * FUNCTION: Acpi_ds_get_buffer_arguments + * + * PARAMETERS: Obj_desc - A valid Bufferobject + * + * RETURN: Status. + * + * DESCRIPTION: Get Buffer length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ****************************************************************************/ - op->node = acpi_ns_get_parent_object (node); +acpi_status +acpi_ds_get_buffer_arguments ( + acpi_operand_object *obj_desc) +{ + acpi_namespace_node *node; + acpi_status status; - /* Get a handle to the parent ACPI table */ - status = acpi_tb_handle_to_object (node->owner_id, &table_desc); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + ACPI_FUNCTION_TRACE_PTR ("Ds_get_buffer_arguments", obj_desc); - /* Create and initialize a new parser state */ - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, - op, NULL, NULL); - if (!walk_state) { - return_ACPI_STATUS (AE_NO_MEMORY); + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS (AE_OK); } - status = acpi_ds_init_aml_walk (walk_state, op, NULL, extra_desc->extra.aml_start, - extra_desc->extra.aml_length, NULL, NULL, 1); - if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ - return_ACPI_STATUS (status); + /* Get the Buffer node */ + + node = obj_desc->buffer.node; + if (!node) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No pointer back to NS node in buffer %p\n", obj_desc)); + return_ACPI_STATUS (AE_AML_INTERNAL); } - /* TBD: No Walk flags?? */ + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer JIT Init\n")); - walk_state->parse_flags = 0; + /* Execute the AML code for the Term_arg arguments */ - /* Parse the entire Op_region declaration, creating a parse tree */ + status = acpi_ds_execute_arguments (node, node, + obj_desc->buffer.aml_length, obj_desc->buffer.aml_start); + return_ACPI_STATUS (status); +} - status = acpi_ps_parse_aml (walk_state); - if (ACPI_FAILURE (status)) { - acpi_ps_delete_parse_tree (op); - return_ACPI_STATUS (status); - } - /* Get and init the actual Region_op created above */ +/***************************************************************************** + * + * FUNCTION: Acpi_ds_get_package_arguments + * + * PARAMETERS: Obj_desc - A valid Packageobject + * + * RETURN: Status. + * + * DESCRIPTION: Get Package length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ****************************************************************************/ - region_op = op->value.arg; - op->node = node; +acpi_status +acpi_ds_get_package_arguments ( + acpi_operand_object *obj_desc) +{ + acpi_namespace_node *node; + acpi_status status; - region_op = op->value.arg; - region_op->node = node; - acpi_ps_delete_parse_tree (op); + ACPI_FUNCTION_TRACE_PTR ("Ds_get_package_arguments", obj_desc); - /* Evaluate the address and length arguments for the Op_region */ - op = acpi_ps_alloc_op (AML_SCOPE_OP); - if (!op) { - return (AE_NO_MEMORY); + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS (AE_OK); } - op->node = acpi_ns_get_parent_object (node); + /* Get the Package node */ - /* Create and initialize a new parser state */ + node = obj_desc->package.node; + if (!node) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No pointer back to NS node in package %p\n", obj_desc)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, - op, NULL, NULL); - if (!walk_state) { - return_ACPI_STATUS (AE_NO_MEMORY); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package JIT Init\n")); + + /* Execute the AML code for the Term_arg arguments */ + + status = acpi_ds_execute_arguments (node, node, + obj_desc->package.aml_length, obj_desc->package.aml_start); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: Acpi_ds_get_region_arguments + * + * PARAMETERS: Obj_desc - A valid region object + * + * RETURN: Status. + * + * DESCRIPTION: Get region address and length. This implements the late + * evaluation of these region attributes. + * + ****************************************************************************/ + +acpi_status +acpi_ds_get_region_arguments ( + acpi_operand_object *obj_desc) +{ + acpi_namespace_node *node; + acpi_status status; + acpi_operand_object *extra_desc; + + + ACPI_FUNCTION_TRACE_PTR ("Ds_get_region_arguments", obj_desc); + + + if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS (AE_OK); } - status = acpi_ds_init_aml_walk (walk_state, op, NULL, extra_desc->extra.aml_start, - extra_desc->extra.aml_length, NULL, NULL, 3); - if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ - return_ACPI_STATUS (status); + extra_desc = acpi_ns_get_secondary_object (obj_desc); + if (!extra_desc) { + return_ACPI_STATUS (AE_NOT_EXIST); } - status = acpi_ps_parse_aml (walk_state); - acpi_ps_delete_parse_tree (op); + /* Get the Region node */ + + node = obj_desc->region.node; + + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (node, " [Operation Region]")); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] Op_region Init at AML %p\n", + node->name.ascii, extra_desc->extra.aml_start)); + + status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node), + extra_desc->extra.aml_length, extra_desc->extra.aml_start); return_ACPI_STATUS (status); } @@ -317,7 +337,7 @@ * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Front end to Ev_initialize_region * ****************************************************************************/ @@ -334,301 +354,276 @@ /* Namespace is NOT locked */ status = acpi_ev_initialize_region (obj_desc, FALSE); - return (status); } /***************************************************************************** * - * FUNCTION: Acpi_ds_eval_buffer_field_operands + * FUNCTION: Acpi_ds_init_buffer_field * - * PARAMETERS: Op - A valid Buffer_field Op object + * PARAMETERS: Aml_opcode - Create_xxx_field + * Obj_desc - Buffer_field object + * Buffer_desc - Host Buffer + * Offset_desc - Offset into buffer + * Length - Length of field (CREATE_FIELD_OP only) + * Result - Where to store the result * * RETURN: Status * - * DESCRIPTION: Get Buffer_field Buffer and Index - * Called from Acpi_ds_exec_end_op during Buffer_field parse tree walk - * - * ACPI SPECIFICATION REFERENCES: - * Each of the Buffer Field opcodes is defined as specified in in-line - * comments below. For each one, use the following definitions. - * - * Def_bit_field := Bit_field_op Src_buf Bit_idx Destination - * Def_byte_field := Byte_field_op Src_buf Byte_idx Destination - * Def_create_field := Create_field_op Src_buf Bit_idx Num_bits Name_string - * Def_dWord_field := DWord_field_op Src_buf Byte_idx Destination - * Def_word_field := Word_field_op Src_buf Byte_idx Destination - * Bit_index := Term_arg=>Integer - * Byte_index := Term_arg=>Integer - * Destination := Name_string - * Num_bits := Term_arg=>Integer - * Source_buf := Term_arg=>Buffer + * DESCRIPTION: Perform actual initialization of a buffer field * ****************************************************************************/ acpi_status -acpi_ds_eval_buffer_field_operands ( - acpi_walk_state *walk_state, - acpi_parse_object *op) +acpi_ds_init_buffer_field ( + u16 aml_opcode, + acpi_operand_object *obj_desc, + acpi_operand_object *buffer_desc, + acpi_operand_object *offset_desc, + acpi_operand_object *length_desc, + acpi_operand_object *result_desc) { - acpi_status status; - acpi_operand_object *obj_desc; - acpi_namespace_node *node; - acpi_parse_object *next_op; u32 offset; u32 bit_offset; u32 bit_count; u8 field_flags; - acpi_operand_object *res_desc = NULL; - acpi_operand_object *cnt_desc = NULL; - acpi_operand_object *off_desc = NULL; - acpi_operand_object *src_desc = NULL; - - - FUNCTION_TRACE_PTR ("Ds_eval_buffer_field_operands", op); - - - /* - * This is where we evaluate the address and length fields of the - * Create_xxx_field declaration - */ - node = op->node; - - /* Next_op points to the op that holds the Buffer */ - - next_op = op->value.arg; - - /* Acpi_evaluate/create the address and length operands */ + acpi_status status; - status = acpi_ds_create_operands (walk_state, next_op); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - obj_desc = acpi_ns_get_attached_object (node); - if (!obj_desc) { - return_ACPI_STATUS (AE_NOT_EXIST); - } + ACPI_FUNCTION_TRACE_PTR ("Ds_init_buffer_field", obj_desc); - /* Resolve the operands */ + /* Host object must be a Buffer */ - status = acpi_ex_resolve_operands (op->opcode, WALK_OPERANDS, walk_state); - DUMP_OPERANDS (WALK_OPERANDS, IMODE_EXECUTE, acpi_ps_get_opcode_name (op->opcode), - walk_state->num_operands, "after Acpi_ex_resolve_operands"); - - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) bad operand(s) (%X)\n", - acpi_ps_get_opcode_name (op->opcode), status)); + if (buffer_desc->common.type != ACPI_TYPE_BUFFER) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Target of Create Field is not a Buffer object - %s\n", + acpi_ut_get_type_name (buffer_desc->common.type))); + status = AE_AML_OPERAND_TYPE; goto cleanup; } - /* Get the operands */ - - if (AML_CREATE_FIELD_OP == op->opcode) { - res_desc = walk_state->operands[3]; - cnt_desc = walk_state->operands[2]; - } - else { - res_desc = walk_state->operands[2]; - } - - off_desc = walk_state->operands[1]; - src_desc = walk_state->operands[0]; - - - offset = (u32) off_desc->integer.value; - /* - * If Res_desc is a Name, it will be a direct name pointer after - * Acpi_ex_resolve_operands() + * The last parameter to all of these opcodes (Result_desc) started + * out as a Name_string, and should therefore now be a NS node + * after resolution in Acpi_ex_resolve_operands(). */ - if (!VALID_DESCRIPTOR_TYPE (res_desc, ACPI_DESC_TYPE_NAMED)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination must be a Node\n", - acpi_ps_get_opcode_name (op->opcode))); + if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination must be a NS Node\n", + acpi_ps_get_opcode_name (aml_opcode))); status = AE_AML_OPERAND_TYPE; goto cleanup; } + offset = (u32) offset_desc->integer.value; + /* * Setup the Bit offsets and counts, according to the opcode */ - switch (op->opcode) { - - /* Def_create_field */ - + switch (aml_opcode) { case AML_CREATE_FIELD_OP: /* Offset is in bits, count is in bits */ - bit_offset = offset; - bit_count = (u32) cnt_desc->integer.value; - field_flags = ACCESS_BYTE_ACC; + bit_offset = offset; + bit_count = (u32) length_desc->integer.value; + field_flags = AML_FIELD_ACCESS_BYTE; break; - - /* Def_create_bit_field */ - case AML_CREATE_BIT_FIELD_OP: /* Offset is in bits, Field is one bit */ - bit_offset = offset; - bit_count = 1; - field_flags = ACCESS_BYTE_ACC; + bit_offset = offset; + bit_count = 1; + field_flags = AML_FIELD_ACCESS_BYTE; break; - - /* Def_create_byte_field */ - case AML_CREATE_BYTE_FIELD_OP: /* Offset is in bytes, field is one byte */ - bit_offset = 8 * offset; - bit_count = 8; - field_flags = ACCESS_BYTE_ACC; + bit_offset = 8 * offset; + bit_count = 8; + field_flags = AML_FIELD_ACCESS_BYTE; break; - - /* Def_create_word_field */ - case AML_CREATE_WORD_FIELD_OP: /* Offset is in bytes, field is one word */ - bit_offset = 8 * offset; - bit_count = 16; - field_flags = ACCESS_WORD_ACC; + bit_offset = 8 * offset; + bit_count = 16; + field_flags = AML_FIELD_ACCESS_WORD; break; - - /* Def_create_dWord_field */ - case AML_CREATE_DWORD_FIELD_OP: /* Offset is in bytes, field is one dword */ - bit_offset = 8 * offset; - bit_count = 32; - field_flags = ACCESS_DWORD_ACC; + bit_offset = 8 * offset; + bit_count = 32; + field_flags = AML_FIELD_ACCESS_DWORD; break; - - /* Def_create_qWord_field */ - case AML_CREATE_QWORD_FIELD_OP: /* Offset is in bytes, field is one qword */ - bit_offset = 8 * offset; - bit_count = 64; - field_flags = ACCESS_QWORD_ACC; + bit_offset = 8 * offset; + bit_count = 64; + field_flags = AML_FIELD_ACCESS_QWORD; break; - default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Internal error - unknown field creation opcode %02x\n", - op->opcode)); + "Unknown field creation opcode %02x\n", + aml_opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } + /* Entire field must fit within the current length of the buffer */ + + if ((bit_offset + bit_count) > + (8 * (u32) buffer_desc->buffer.length)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field size %d exceeds Buffer size %d (bits)\n", + bit_offset + bit_count, 8 * (u32) buffer_desc->buffer.length)); + status = AE_AML_BUFFER_LIMIT; + goto cleanup; + } + /* - * Setup field according to the object type + * Initialize areas of the field object that are common to all fields + * For Field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE) */ - switch (src_desc->common.type) { + status = acpi_ex_prep_common_field_object (obj_desc, field_flags, 0, + bit_offset, bit_count); + if (ACPI_FAILURE (status)) { + goto cleanup; + } - /* Source_buff := Term_arg=>Buffer */ + obj_desc->buffer_field.buffer_obj = buffer_desc; - case ACPI_TYPE_BUFFER: + /* Reference count for Buffer_desc inherits Obj_desc count */ - if ((bit_offset + bit_count) > - (8 * (u32) src_desc->buffer.length)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Field size %d exceeds Buffer size %d (bits)\n", - bit_offset + bit_count, 8 * (u32) src_desc->buffer.length)); - status = AE_AML_BUFFER_LIMIT; - goto cleanup; - } + buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count + + obj_desc->common.reference_count); - /* - * Initialize areas of the field object that are common to all fields - * For Field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE) - */ - status = acpi_ex_prep_common_field_object (obj_desc, field_flags, - bit_offset, bit_count); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } +cleanup: - obj_desc->buffer_field.buffer_obj = src_desc; + /* Always delete the operands */ - /* Reference count for Src_desc inherits Obj_desc count */ + acpi_ut_remove_reference (offset_desc); + acpi_ut_remove_reference (buffer_desc); - src_desc->common.reference_count = (u16) (src_desc->common.reference_count + - obj_desc->common.reference_count); + if (aml_opcode == AML_CREATE_FIELD_OP) { + acpi_ut_remove_reference (length_desc); + } - break; + /* On failure, delete the result descriptor */ + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (result_desc); /* Result descriptor */ + } + else { + /* Now the address and length are valid for this Buffer_field */ - /* Improper object type */ + obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; + } - default: + return_ACPI_STATUS (status); +} - if ((src_desc->common.type > (u8) INTERNAL_TYPE_REFERENCE) || !acpi_ut_valid_object_type (src_desc->common.type)) /* TBD: This line MUST be a single line until Acpi_src can handle it (block deletion) */ { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Tried to create field in invalid object type %X\n", - src_desc->common.type)); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Tried to create field in improper object type - %s\n", - acpi_ut_get_type_name (src_desc->common.type))); - } +/***************************************************************************** + * + * FUNCTION: Acpi_ds_eval_buffer_field_operands + * + * PARAMETERS: Walk_state - Current walk + * Op - A valid Buffer_field Op object + * + * RETURN: Status + * + * DESCRIPTION: Get Buffer_field Buffer and Index + * Called from Acpi_ds_exec_end_op during Buffer_field parse tree walk + * + ****************************************************************************/ - status = AE_AML_OPERAND_TYPE; - goto cleanup; - } +acpi_status +acpi_ds_eval_buffer_field_operands ( + acpi_walk_state *walk_state, + acpi_parse_object *op) +{ + acpi_status status; + acpi_operand_object *obj_desc; + acpi_namespace_node *node; + acpi_parse_object *next_op; - if (AML_CREATE_FIELD_OP == op->opcode) { - /* Delete object descriptor unique to Create_field */ + ACPI_FUNCTION_TRACE_PTR ("Ds_eval_buffer_field_operands", op); - acpi_ut_remove_reference (cnt_desc); - cnt_desc = NULL; - } + /* + * This is where we evaluate the address and length fields of the + * Create_xxx_field declaration + */ + node = op->common.node; + + /* Next_op points to the op that holds the Buffer */ -cleanup: + next_op = op->common.value.arg; - /* Always delete the operands */ + /* Evaluate/create the address and length operands */ - acpi_ut_remove_reference (off_desc); - acpi_ut_remove_reference (src_desc); + status = acpi_ds_create_operands (walk_state, next_op); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - if (AML_CREATE_FIELD_OP == op->opcode) { - acpi_ut_remove_reference (cnt_desc); + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + return_ACPI_STATUS (AE_NOT_EXIST); } - /* On failure, delete the result descriptor */ + /* Resolve the operands */ + + status = acpi_ex_resolve_operands (op->common.aml_opcode, + ACPI_WALK_OPERANDS, walk_state); + + ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name (op->common.aml_opcode), + walk_state->num_operands, "after Acpi_ex_resolve_operands"); if (ACPI_FAILURE (status)) { - acpi_ut_remove_reference (res_desc); /* Result descriptor */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) bad operand(s) (%X)\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), status)); + + return_ACPI_STATUS (status); } + /* Initialize the Buffer Field */ + + if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { + /* NOTE: Slightly different operands for this opcode */ + + status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc, + walk_state->operands[0], walk_state->operands[1], + walk_state->operands[2], walk_state->operands[3]); + } else { - /* Now the address and length are valid for this Buffer_field */ + /* All other, Create_xxx_field opcodes */ - obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; + status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc, + walk_state->operands[0], walk_state->operands[1], + NULL, walk_state->operands[2]); } return_ACPI_STATUS (status); @@ -639,7 +634,8 @@ * * FUNCTION: Acpi_ds_eval_region_operands * - * PARAMETERS: Op - A valid region Op object + * PARAMETERS: Walk_state - Current walk + * Op - A valid region Op object * * RETURN: Status * @@ -660,23 +656,23 @@ acpi_parse_object *next_op; - FUNCTION_TRACE_PTR ("Ds_eval_region_operands", op); + ACPI_FUNCTION_TRACE_PTR ("Ds_eval_region_operands", op); /* * This is where we evaluate the address and length fields of the Op_region declaration */ - node = op->node; + node = op->common.node; /* Next_op points to the op that holds the Space_iD */ - next_op = op->value.arg; + next_op = op->common.value.arg; /* Next_op points to address op */ - next_op = next_op->next; + next_op = next_op->common.next; - /* Acpi_evaluate/create the address and length operands */ + /* Evaluate/create the address and length operands */ status = acpi_ds_create_operands (walk_state, next_op); if (ACPI_FAILURE (status)) { @@ -685,16 +681,15 @@ /* Resolve the length and address operands to numbers */ - status = acpi_ex_resolve_operands (op->opcode, WALK_OPERANDS, walk_state); + status = acpi_ex_resolve_operands (op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - DUMP_OPERANDS (WALK_OPERANDS, IMODE_EXECUTE, - acpi_ps_get_opcode_name (op->opcode), + ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name (op->common.aml_opcode), 1, "after Acpi_ex_resolve_operands"); - obj_desc = acpi_ns_get_attached_object (node); if (!obj_desc) { return_ACPI_STATUS (AE_NOT_EXIST); @@ -718,9 +713,9 @@ obj_desc->region.address = (ACPI_PHYSICAL_ADDRESS) operand_desc->integer.value; acpi_ut_remove_reference (operand_desc); - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Rgn_obj %p Addr %8.8X%8.8X Len %X\n", - obj_desc, HIDWORD(obj_desc->region.address), LODWORD(obj_desc->region.address), + obj_desc, + ACPI_HIDWORD (obj_desc->region.address), ACPI_LODWORD (obj_desc->region.address), obj_desc->region.length)); /* Now the address and length are valid for this opregion */ @@ -731,6 +726,101 @@ } +/***************************************************************************** + * + * FUNCTION: Acpi_ds_eval_data_object_operands + * + * PARAMETERS: Walk_state - Current walk + * Op - A valid Data_object Op object + * Obj_desc - Data_object + * + * RETURN: Status + * + * DESCRIPTION: Get the operands and complete the following data objec types: + * Buffer + * Package + * + ****************************************************************************/ + +acpi_status +acpi_ds_eval_data_object_operands ( + acpi_walk_state *walk_state, + acpi_parse_object *op, + acpi_operand_object *obj_desc) +{ + acpi_status status; + acpi_operand_object *arg_desc; + u32 length; + + + ACPI_FUNCTION_TRACE ("Ds_eval_data_object_operands"); + + + /* The first operand (for all of these data objects) is the length */ + + status = acpi_ds_create_operand (walk_state, op->common.value.arg, 1); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ex_resolve_operands (walk_state->opcode, + &(walk_state->operands [walk_state->num_operands -1]), + walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Extract length operand */ + + arg_desc = walk_state->operands [walk_state->num_operands - 1]; + length = (u32) arg_desc->integer.value; + + /* Cleanup for length operand */ + + status = acpi_ds_obj_stack_pop (1, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + acpi_ut_remove_reference (arg_desc); + + /* + * Create the actual data object + */ + switch (op->common.aml_opcode) { + case AML_BUFFER_OP: + + status = acpi_ds_build_internal_buffer_obj (walk_state, op, length, &obj_desc); + break; + + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + status = acpi_ds_build_internal_package_obj (walk_state, op, length, &obj_desc); + break; + + default: + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + if (ACPI_SUCCESS (status)) { + /* + * Return the object in the Walk_state, unless the parent is a package -- + * in this case, the return object will be stored in the parse tree + * for the package. + */ + if ((!op->common.parent) || + ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && + (op->common.parent->common.aml_opcode != AML_VAR_PACKAGE_OP) && + (op->common.parent->common.aml_opcode != AML_NAME_OP))) { + walk_state->result_obj = obj_desc; + } + } + + return_ACPI_STATUS (status); +} + + /******************************************************************************* * * FUNCTION: Acpi_ds_exec_begin_control_op @@ -754,13 +844,13 @@ acpi_generic_state *control_state; - PROC_NAME ("Ds_exec_begin_control_op"); + ACPI_FUNCTION_NAME ("Ds_exec_begin_control_op"); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op, - op->opcode, walk_state)); + op->common.aml_opcode, walk_state)); - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_IF_OP: case AML_WHILE_OP: @@ -774,19 +864,19 @@ status = AE_NO_MEMORY; break; } - - acpi_ut_push_generic_state (&walk_state->control_state, control_state); - /* * Save a pointer to the predicate for multiple executions * of a loop */ - walk_state->control_state->control.aml_predicate_start = - walk_state->parser_state.aml - 1; - /* TBD: can this be removed? */ - /*Acpi_ps_pkg_length_encoding_size (GET8 (Walk_state->Parser_state->Aml));*/ - break; + control_state->control.aml_predicate_start = walk_state->parser_state.aml - 1; + control_state->control.package_end = walk_state->parser_state.pkg_end; + control_state->control.opcode = op->common.aml_opcode; + + + /* Push the control state on this walk's control stack */ + acpi_ut_push_generic_state (&walk_state->control_state, control_state); + break; case AML_ELSE_OP: @@ -799,12 +889,10 @@ break; - case AML_RETURN_OP: break; - default: break; } @@ -825,7 +913,6 @@ * DESCRIPTION: Handles all control ops encountered during control method * execution. * - * ******************************************************************************/ acpi_status @@ -837,10 +924,10 @@ acpi_generic_state *control_state; - PROC_NAME ("Ds_exec_end_control_op"); + ACPI_FUNCTION_NAME ("Ds_exec_end_control_op"); - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_IF_OP: ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op)); @@ -890,17 +977,17 @@ case AML_RETURN_OP: ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "[RETURN_OP] Op=%p Arg=%p\n",op, op->value.arg)); + "[RETURN_OP] Op=%p Arg=%p\n",op, op->common.value.arg)); /* * One optional operand -- the return value * It can be either an immediate operand or a result that * has been bubbled up the tree */ - if (op->value.arg) { + if (op->common.value.arg) { /* Return statement has an immediate operand */ - status = acpi_ds_create_operands (walk_state, op->value.arg); + status = acpi_ds_create_operands (walk_state, op->common.value.arg); if (ACPI_FAILURE (status)) { return (status); } @@ -922,7 +1009,6 @@ */ walk_state->return_desc = walk_state->operands[0]; } - else if ((walk_state->results) && (walk_state->results->results.num_results > 0)) { /* @@ -934,18 +1020,17 @@ * * Allow references created by the Index operator to return unchanged. */ - if (VALID_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc [0], ACPI_DESC_TYPE_INTERNAL) && + if ((ACPI_GET_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc[0]) == ACPI_DESC_TYPE_OPERAND) && ((walk_state->results->results.obj_desc [0])->common.type == INTERNAL_TYPE_REFERENCE) && ((walk_state->results->results.obj_desc [0])->reference.opcode != AML_INDEX_OP)) { - status = acpi_ex_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state); - if (ACPI_FAILURE (status)) { - return (status); - } + status = acpi_ex_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } } walk_state->return_desc = walk_state->results->results.obj_desc [0]; } - else { /* No return operand */ @@ -979,7 +1064,7 @@ /* Call up to the OS service layer to handle this */ - acpi_os_signal (ACPI_SIGNAL_BREAKPOINT, "Executed AML Breakpoint opcode"); + status = acpi_os_signal (ACPI_SIGNAL_BREAKPOINT, "Executed AML Breakpoint opcode"); /* If and when it returns, all done. */ @@ -987,42 +1072,46 @@ case AML_BREAK_OP: + case AML_CONTINUE_OP: /* ACPI 2.0 */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Break to end of current package, Op=%p\n", op)); - /* TBD: update behavior for ACPI 2.0 */ + /* Pop and delete control states until we find a while */ - /* - * As per the ACPI specification: - * "The break operation causes the current package - * execution to complete" - * "Break -- Stop executing the current code package - * at this point" - * - * Returning AE_FALSE here will cause termination of - * the current package, and execution will continue one - * level up, starting with the completion of the parent Op. - */ - status = AE_CTRL_FALSE; - break; + while (walk_state->control_state && + (walk_state->control_state->control.opcode != AML_WHILE_OP)) { + control_state = acpi_ut_pop_generic_state (&walk_state->control_state); + acpi_ut_delete_generic_state (control_state); + } + /* No while found? */ - case AML_CONTINUE_OP: /* ACPI 2.0 */ + if (!walk_state->control_state) { + return (AE_AML_NO_WHILE); + } + + /* Was: Walk_state->Aml_last_while = Walk_state->Control_state->Control.Aml_predicate_start; */ - status = AE_NOT_IMPLEMENTED; + walk_state->aml_last_while = walk_state->control_state->control.package_end; + + /* Return status depending on opcode */ + + if (op->common.aml_opcode == AML_BREAK_OP) { + status = AE_CTRL_BREAK; + } + else { + status = AE_CTRL_CONTINUE; + } break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown control opcode=%X Op=%p\n", - op->opcode, op)); + op->common.aml_opcode, op)); status = AE_AML_BAD_OPCODE; break; } - return (status); } diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dsutils.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsutils.c --- linux-2.4.19/drivers/acpi/dispatcher/dsutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dsutils.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: dsutils - Dispatcher utilities - * $Revision: 80 $ + * $Revision: 92 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ #include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dsutils") + ACPI_MODULE_NAME ("dsutils") /******************************************************************************* @@ -58,7 +58,7 @@ const acpi_opcode_info *parent_info; - FUNCTION_TRACE_PTR ("Ds_is_result_used", op); + ACPI_FUNCTION_TRACE_PTR ("Ds_is_result_used", op); /* Must have both an Op and a Result Object */ @@ -68,29 +68,25 @@ return_VALUE (TRUE); } - /* * If there is no parent, the result can't possibly be used! * (An executing method typically has no parent, since each * method is parsed separately) However, a method that is * invoked from another method has a parent. */ - if (!op->parent) { + if (!op->common.parent) { return_VALUE (FALSE); } - /* * Get info on the parent. The root Op is AML_SCOPE */ - - parent_info = acpi_ps_get_opcode_info (op->parent->opcode); + parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); if (parent_info->class == AML_CLASS_UNKNOWN) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op)); return_VALUE (FALSE); } - /* * Decide what to do with the result based on the parent. If * the parent opcode will not use the result, delete the object. @@ -98,78 +94,90 @@ * as an operand later. */ switch (parent_info->class) { - /* - * In these cases, the parent will never use the return object - */ - case AML_CLASS_CONTROL: /* IF, ELSE, WHILE only */ + case AML_CLASS_CONTROL: - switch (op->parent->opcode) { + switch (op->common.parent->common.aml_opcode) { case AML_RETURN_OP: /* Never delete the return value associated with a return opcode */ - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "Result used, [RETURN] opcode=%X Op=%p\n", op->opcode, op)); - return_VALUE (TRUE); - break; + goto result_used; case AML_IF_OP: case AML_WHILE_OP: /* * If we are executing the predicate AND this is the predicate op, - * we will use the return value! + * we will use the return value */ - if ((walk_state->control_state->common.state == CONTROL_PREDICATE_EXECUTING) && + if ((walk_state->control_state->common.state == ACPI_CONTROL_PREDICATE_EXECUTING) && (walk_state->control_state->control.predicate_op == op)) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "Result used as a predicate, [IF/WHILE] opcode=%X Op=%p\n", - op->opcode, op)); - return_VALUE (TRUE); + goto result_used; } + break; + default: + /* Ignore other control opcodes */ break; } + /* The general control opcode returns no result */ - /* Fall through to not used case below */ + goto result_not_used; - case AML_CLASS_NAMED_OBJECT: /* Scope, method, etc. */ case AML_CLASS_CREATE: /* * These opcodes allow Term_arg(s) as operands and therefore - * method calls. The result is used. + * the operands can be method calls. The result is used. */ - if ((op->parent->opcode == AML_REGION_OP) || - (op->parent->opcode == AML_CREATE_FIELD_OP) || - (op->parent->opcode == AML_CREATE_BIT_FIELD_OP) || - (op->parent->opcode == AML_CREATE_BYTE_FIELD_OP) || - (op->parent->opcode == AML_CREATE_WORD_FIELD_OP) || - (op->parent->opcode == AML_CREATE_DWORD_FIELD_OP) || - (op->parent->opcode == AML_CREATE_QWORD_FIELD_OP)) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "Result used, [Region or Create_field] opcode=%X Op=%p\n", - op->opcode, op)); - return_VALUE (TRUE); + goto result_used; + + + case AML_CLASS_NAMED_OBJECT: + + if ((op->common.parent->common.aml_opcode == AML_REGION_OP) || + (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) || + (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || + (op->common.parent->common.aml_opcode == AML_INT_EVAL_SUBTREE_OP)) { + /* + * These opcodes allow Term_arg(s) as operands and therefore + * the operands can be method calls. The result is used. + */ + goto result_used; } - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "Result not used, Parent opcode=%X Op=%p\n", op->opcode, op)); + goto result_not_used; - return_VALUE (FALSE); - break; - /* - * In all other cases. the parent will actually use the return - * object, so keep it. - */ default: - break; + + /* + * In all other cases. the parent will actually use the return + * object, so keep it. + */ + goto result_used; } + +result_used: + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + return_VALUE (TRUE); + + +result_not_used: + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + + return_VALUE (FALSE); + } @@ -200,7 +208,7 @@ acpi_status status; - FUNCTION_TRACE_PTR ("Ds_delete_result_if_not_used", result_obj); + ACPI_FUNCTION_TRACE_PTR ("Ds_delete_result_if_not_used", result_obj); if (!op) { @@ -250,29 +258,29 @@ u32 arg_index) { acpi_status status = AE_OK; + acpi_status status2; NATIVE_CHAR *name_string; u32 name_length; - acpi_object_type8 data_type; acpi_operand_object *obj_desc; acpi_parse_object *parent_op; u16 opcode; - u32 flags; - operating_mode interpreter_mode; + acpi_interpreter_mode interpreter_mode; const acpi_opcode_info *op_info; + char *name; - FUNCTION_TRACE_PTR ("Ds_create_operand", arg); + ACPI_FUNCTION_TRACE_PTR ("Ds_create_operand", arg); /* A valid name must be looked up in the namespace */ - if ((arg->opcode == AML_INT_NAMEPATH_OP) && - (arg->value.string)) { + if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && + (arg->common.value.string)) { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", arg)); /* Get the entire name string from the AML stream */ - status = acpi_ex_get_name_string (ACPI_TYPE_ANY, arg->value.buffer, + status = acpi_ex_get_name_string (ACPI_TYPE_ANY, arg->common.value.buffer, &name_string, &name_length); if (ACPI_FAILURE (status)) { @@ -290,46 +298,41 @@ * IMODE_EXECUTE) in order to support the creation of * namespace objects during the execution of control methods. */ - parent_op = arg->parent; - op_info = acpi_ps_get_opcode_info (parent_op->opcode); + parent_op = arg->common.parent; + op_info = acpi_ps_get_opcode_info (parent_op->common.aml_opcode); if ((op_info->flags & AML_NSNODE) && - (parent_op->opcode != AML_INT_METHODCALL_OP) && - (parent_op->opcode != AML_REGION_OP) && - (parent_op->opcode != AML_INT_NAMEPATH_OP)) { + (parent_op->common.aml_opcode != AML_INT_METHODCALL_OP) && + (parent_op->common.aml_opcode != AML_REGION_OP) && + (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) { /* Enter name into namespace if not found */ - interpreter_mode = IMODE_LOAD_PASS2; + interpreter_mode = ACPI_IMODE_LOAD_PASS2; } else { /* Return a failure if name not found */ - interpreter_mode = IMODE_EXECUTE; + interpreter_mode = ACPI_IMODE_EXECUTE; } status = acpi_ns_lookup (walk_state->scope_info, name_string, ACPI_TYPE_ANY, interpreter_mode, - NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, walk_state, - (acpi_namespace_node **) &obj_desc); - - /* Free the namestring created above */ - - ACPI_MEM_FREE (name_string); - + ACPI_CAST_INDIRECT_PTR (acpi_namespace_node, &obj_desc)); /* * The only case where we pass through (ignore) a NOT_FOUND * error is for the Cond_ref_of opcode. */ if (status == AE_NOT_FOUND) { - if (parent_op->opcode == AML_COND_REF_OF_OP) { + if (parent_op->common.aml_opcode == AML_COND_REF_OF_OP) { /* * For the Conditional Reference op, it's OK if * the name is not found; We just need a way to * indicate this to the interpreter, set the * object to the root */ - obj_desc = (acpi_operand_object *) acpi_gbl_root_node; + obj_desc = ACPI_CAST_PTR (acpi_operand_object, acpi_gbl_root_node); status = AE_OK; } @@ -340,13 +343,20 @@ */ status = AE_AML_NAME_NOT_FOUND; - /* TBD: Externalize Name_string and print */ - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Object name was not found in namespace\n")); + name = NULL; + status2 = acpi_ns_externalize_name (ACPI_UINT32_MAX, name_string, NULL, &name); + if (ACPI_SUCCESS (status2)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Object name [%s] was not found in namespace\n", name)); + ACPI_MEM_FREE (name); + } } } + /* Free the namestring created above */ + + ACPI_MEM_FREE (name_string); + /* Check status from the lookup */ if (ACPI_FAILURE (status)) { @@ -359,14 +369,14 @@ if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); + ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); } else { /* Check for null name case */ - if (arg->opcode == AML_INT_NAMEPATH_OP) { + if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) { /* * If the name is null, this means that this is an * optional result parameter that was not specified @@ -376,30 +386,25 @@ opcode = AML_ZERO_OP; /* Has no arguments! */ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg)); - - /* - * TBD: [Investigate] anything else needed for the - * zero op lvalue? - */ } else { - opcode = arg->opcode; + opcode = arg->common.aml_opcode; } + /* Get the object type of the argument */ - /* Get the data type of the argument */ - - data_type = acpi_ds_map_opcode_to_data_type (opcode, &flags); - if (data_type == INTERNAL_TYPE_INVALID) { + op_info = acpi_ps_get_opcode_info (opcode); + if (op_info->object_type == INTERNAL_TYPE_INVALID) { return_ACPI_STATUS (AE_NOT_IMPLEMENTED); } - if (flags & OP_HAS_RETURN_VALUE) { + if (op_info->flags & AML_HAS_RETVAL) { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Argument previously created, already stacked \n")); - DEBUGGER_EXEC (acpi_db_display_argument_object (walk_state->operands [walk_state->num_operands - 1], walk_state)); + ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object ( + walk_state->operands [walk_state->num_operands - 1], walk_state)); /* * Use value that was already previously returned @@ -415,13 +420,11 @@ acpi_format_exception (status))); return_ACPI_STATUS (status); } - } - else { /* Create an ACPI_INTERNAL_OBJECT for the argument */ - obj_desc = acpi_ut_create_internal_object (data_type); + obj_desc = acpi_ut_create_internal_object (op_info->object_type); if (!obj_desc) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -434,7 +437,7 @@ acpi_ut_delete_object_desc (obj_desc); return_ACPI_STATUS (status); } - } + } /* Put the operand object on the object stack */ @@ -443,7 +446,7 @@ return_ACPI_STATUS (status); } - DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); + ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); } return_ACPI_STATUS (AE_OK); @@ -474,7 +477,7 @@ u32 arg_count = 0; - FUNCTION_TRACE_PTR ("Ds_create_operands", first_arg); + ACPI_FUNCTION_TRACE_PTR ("Ds_create_operands", first_arg); /* For all arguments in the list... */ @@ -491,7 +494,7 @@ /* Move on to next argument, if any */ - arg = arg->next; + arg = arg->common.next; arg_count++; } @@ -504,7 +507,7 @@ * pop everything off of the operand stack and delete those * objects */ - acpi_ds_obj_stack_pop_and_delete (arg_count, walk_state); + (void) acpi_ds_obj_stack_pop_and_delete (arg_count, walk_state); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While creating Arg %d - %s\n", (arg_count + 1), acpi_format_exception (status))); @@ -534,18 +537,13 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_PTR ("Ds_resolve_operands", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_resolve_operands", walk_state); /* * Attempt to resolve each of the valid operands * Method arguments are passed by value, not by reference */ - - /* - * TBD: [Investigate] Note from previous parser: - * Ref_of problem with Acpi_ex_resolve_to_value() conversion. - */ for (i = 0; i < walk_state->num_operands; i++) { status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state); if (ACPI_FAILURE (status)) { @@ -555,264 +553,4 @@ return_ACPI_STATUS (status); } - - -/******************************************************************************* - * - * FUNCTION: Acpi_ds_map_opcode_to_data_type - * - * PARAMETERS: Opcode - AML opcode to map - * Out_flags - Additional info about the opcode - * - * RETURN: The ACPI type associated with the opcode - * - * DESCRIPTION: Convert a raw AML opcode to the associated ACPI data type, - * if any. If the opcode returns a value as part of the - * intepreter execution, a flag is returned in Out_flags. - * - ******************************************************************************/ - -acpi_object_type8 -acpi_ds_map_opcode_to_data_type ( - u16 opcode, - u32 *out_flags) -{ - acpi_object_type8 data_type = INTERNAL_TYPE_INVALID; - const acpi_opcode_info *op_info; - u32 flags = 0; - - - PROC_NAME ("Ds_map_opcode_to_data_type"); - - - op_info = acpi_ps_get_opcode_info (opcode); - if (op_info->class == AML_CLASS_UNKNOWN) { - /* Unknown opcode */ - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown AML opcode: %x\n", opcode)); - return (data_type); - } - - -/* - * TBD: Use op class - */ - - switch (op_info->type) { - - case AML_TYPE_LITERAL: - - switch (opcode) { - case AML_BYTE_OP: - case AML_WORD_OP: - case AML_DWORD_OP: - case AML_QWORD_OP: - - data_type = ACPI_TYPE_INTEGER; - break; - - - case AML_STRING_OP: - - data_type = ACPI_TYPE_STRING; - break; - - case AML_INT_NAMEPATH_OP: - data_type = INTERNAL_TYPE_REFERENCE; - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unknown (type LITERAL) AML opcode: %x\n", opcode)); - break; - } - break; - - - case AML_TYPE_DATA_TERM: - - switch (opcode) { - case AML_BUFFER_OP: - - data_type = ACPI_TYPE_BUFFER; - break; - - case AML_PACKAGE_OP: - case AML_VAR_PACKAGE_OP: - - data_type = ACPI_TYPE_PACKAGE; - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unknown (type DATA_TERM) AML opcode: %x\n", opcode)); - break; - } - break; - - - case AML_TYPE_CONSTANT: - case AML_TYPE_METHOD_ARGUMENT: - case AML_TYPE_LOCAL_VARIABLE: - - data_type = INTERNAL_TYPE_REFERENCE; - break; - - - case AML_TYPE_EXEC_1A_0T_1R: - case AML_TYPE_EXEC_1A_1T_1R: - case AML_TYPE_EXEC_2A_0T_1R: - case AML_TYPE_EXEC_2A_1T_1R: - case AML_TYPE_EXEC_2A_2T_1R: - case AML_TYPE_EXEC_3A_1T_1R: - case AML_TYPE_EXEC_6A_0T_1R: - case AML_TYPE_RETURN: - - flags = OP_HAS_RETURN_VALUE; - data_type = ACPI_TYPE_ANY; - break; - - - case AML_TYPE_METHOD_CALL: - - flags = OP_HAS_RETURN_VALUE; - data_type = ACPI_TYPE_METHOD; - break; - - - case AML_TYPE_NAMED_FIELD: - case AML_TYPE_NAMED_SIMPLE: - case AML_TYPE_NAMED_COMPLEX: - case AML_TYPE_NAMED_NO_OBJ: - - data_type = acpi_ds_map_named_opcode_to_data_type (opcode); - break; - - - case AML_TYPE_EXEC_1A_0T_0R: - case AML_TYPE_EXEC_2A_0T_0R: - case AML_TYPE_EXEC_3A_0T_0R: - case AML_TYPE_EXEC_1A_1T_0R: - case AML_TYPE_CONTROL: - - /* No mapping needed at this time */ - - break; - - - default: - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unimplemented data type opcode: %x\n", opcode)); - break; - } - - /* Return flags to caller if requested */ - - if (out_flags) { - *out_flags = flags; - } - - return (data_type); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ds_map_named_opcode_to_data_type - * - * PARAMETERS: Opcode - The Named AML opcode to map - * - * RETURN: The ACPI type associated with the named opcode - * - * DESCRIPTION: Convert a raw Named AML opcode to the associated data type. - * Named opcodes are a subsystem of the AML opcodes. - * - ******************************************************************************/ - -acpi_object_type8 -acpi_ds_map_named_opcode_to_data_type ( - u16 opcode) -{ - acpi_object_type8 data_type; - - - FUNCTION_ENTRY (); - - - /* Decode Opcode */ - - switch (opcode) { - case AML_SCOPE_OP: - data_type = INTERNAL_TYPE_SCOPE; - break; - - case AML_DEVICE_OP: - data_type = ACPI_TYPE_DEVICE; - break; - - case AML_THERMAL_ZONE_OP: - data_type = ACPI_TYPE_THERMAL; - break; - - case AML_METHOD_OP: - data_type = ACPI_TYPE_METHOD; - break; - - case AML_POWER_RES_OP: - data_type = ACPI_TYPE_POWER; - break; - - case AML_PROCESSOR_OP: - data_type = ACPI_TYPE_PROCESSOR; - break; - - case AML_FIELD_OP: /* Field_op */ - data_type = INTERNAL_TYPE_FIELD_DEFN; - break; - - case AML_INDEX_FIELD_OP: /* Index_field_op */ - data_type = INTERNAL_TYPE_INDEX_FIELD_DEFN; - break; - - case AML_BANK_FIELD_OP: /* Bank_field_op */ - data_type = INTERNAL_TYPE_BANK_FIELD_DEFN; - break; - - case AML_INT_NAMEDFIELD_OP: /* NO CASE IN ORIGINAL */ - data_type = ACPI_TYPE_ANY; - break; - - case AML_NAME_OP: /* Name_op - special code in original */ - case AML_INT_NAMEPATH_OP: - data_type = ACPI_TYPE_ANY; - break; - - case AML_ALIAS_OP: - data_type = INTERNAL_TYPE_ALIAS; - break; - - case AML_MUTEX_OP: - data_type = ACPI_TYPE_MUTEX; - break; - - case AML_EVENT_OP: - data_type = ACPI_TYPE_EVENT; - break; - - case AML_DATA_REGION_OP: - case AML_REGION_OP: - data_type = ACPI_TYPE_REGION; - break; - - - default: - data_type = ACPI_TYPE_ANY; - break; - - } - - return (data_type); -} - diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dswexec.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswexec.c --- linux-2.4.19/drivers/acpi/dispatcher/dswexec.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswexec.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: dswexec - Dispatcher method execution callbacks; * dispatch to interpreter. - * $Revision: 79 $ + * $Revision: 92 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,12 +35,12 @@ #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dswexec") + ACPI_MODULE_NAME ("dswexec") /* - * Dispatch tables for opcode classes + * Dispatch table for opcode classes */ -ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = { +static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = { acpi_ex_opcode_1A_0T_0R, acpi_ex_opcode_1A_0T_1R, acpi_ex_opcode_1A_1T_0R, @@ -68,17 +68,17 @@ acpi_status acpi_ds_get_predicate_value ( acpi_walk_state *walk_state, - u32 has_result_obj) { + acpi_operand_object *result_obj) { acpi_status status = AE_OK; acpi_operand_object *obj_desc; - FUNCTION_TRACE_PTR ("Ds_get_predicate_value", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_get_predicate_value", walk_state); walk_state->control_state->common.state = 0; - if (has_result_obj) { + if (result_obj) { status = acpi_ds_result_pop (&obj_desc, walk_state); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -88,7 +88,6 @@ return_ACPI_STATUS (status); } } - else { status = acpi_ds_create_operand (walk_state, walk_state->op, 0); if (ACPI_FAILURE (status)) { @@ -110,7 +109,6 @@ return_ACPI_STATUS (AE_AML_NO_OPERAND); } - /* * Result of predicate evaluation currently must * be a number @@ -124,7 +122,6 @@ goto cleanup; } - /* Truncate the predicate to 32-bits if necessary */ acpi_ex_truncate_for32bit_table (obj_desc, walk_state); @@ -136,7 +133,6 @@ if (obj_desc->integer.value) { walk_state->control_state->common.value = TRUE; } - else { /* * Predicate is FALSE, we will just toss the @@ -149,12 +145,12 @@ cleanup: - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%pn", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n", walk_state->control_state->common.value, walk_state->op)); /* Break to debugger to display result */ - DEBUGGER_EXEC (acpi_db_display_result_object (obj_desc, walk_state)); + ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (obj_desc, walk_state)); /* * Delete the predicate result object (we know that @@ -162,7 +158,7 @@ */ acpi_ut_remove_reference (obj_desc); - walk_state->control_state->common.state = CONTROL_NORMAL; + walk_state->control_state->common.state = ACPI_CONTROL_NORMAL; return_ACPI_STATUS (status); } @@ -192,7 +188,7 @@ u32 opcode_class; - FUNCTION_TRACE_PTR ("Ds_exec_begin_op", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_exec_begin_op", walk_state); op = walk_state->op; @@ -204,8 +200,18 @@ op = *out_op; walk_state->op = op; - walk_state->op_info = acpi_ps_get_opcode_info (op->opcode); - walk_state->opcode = op->opcode; + walk_state->opcode = op->common.aml_opcode; + walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); + + if (acpi_ns_opens_scope (walk_state->op_info->object_type)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", + acpi_ut_get_type_name (walk_state->op_info->object_type), op)); + + status = acpi_ds_scope_stack_pop (walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } } if (op == walk_state->origin) { @@ -223,11 +229,11 @@ */ if ((walk_state->control_state) && (walk_state->control_state->common.state == - CONTROL_CONDITIONAL_EXECUTING)) { + ACPI_CONTROL_CONDITIONAL_EXECUTING)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Exec predicate Op=%p State=%p\n", op, walk_state)); - walk_state->control_state->common.state = CONTROL_PREDICATE_EXECUTING; + walk_state->control_state->common.state = ACPI_CONTROL_PREDICATE_EXECUTING; /* Save start of predicate */ @@ -239,7 +245,7 @@ /* We want to send namepaths to the load code */ - if (op->opcode == AML_INT_NAMEPATH_OP) { + if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { opcode_class = AML_CLASS_NAMED_OBJECT; } @@ -260,7 +266,7 @@ case AML_CLASS_NAMED_OBJECT: - if (walk_state->walk_type == WALK_METHOD) { + if (walk_state->walk_type == ACPI_WALK_METHOD) { /* * Found a named object declaration during method * execution; we must enter this object into the @@ -271,19 +277,16 @@ status = acpi_ds_load2_begin_op (walk_state, NULL); } - - if (op->opcode == AML_REGION_OP) { + if (op->common.aml_opcode == AML_REGION_OP) { status = acpi_ds_result_stack_push (walk_state); } - break; - /* most operators with arguments */ - case AML_CLASS_EXECUTE: case AML_CLASS_CREATE: + /* most operators with arguments */ /* Start a new result/operand state */ status = acpi_ds_result_stack_push (walk_state); @@ -329,7 +332,7 @@ u32 i; - FUNCTION_TRACE_PTR ("Ds_exec_end_op", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_exec_end_op", walk_state); op = walk_state->op; @@ -337,11 +340,11 @@ op_class = walk_state->op_info->class; if (op_class == AML_CLASS_UNKNOWN) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode %X\n", op->opcode)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode %X\n", op->common.aml_opcode)); return_ACPI_STATUS (AE_NOT_IMPLEMENTED); } - first_arg = op->value.arg; + first_arg = op->common.value.arg; /* Init the walk state */ @@ -349,22 +352,19 @@ walk_state->return_desc = NULL; walk_state->result_obj = NULL; - /* Call debugger for single step support (DEBUG build only) */ - DEBUGGER_EXEC (status = acpi_db_single_step (walk_state, op, op_class)); - DEBUGGER_EXEC (if (ACPI_FAILURE (status)) {return_ACPI_STATUS (status);}); - + ACPI_DEBUGGER_EXEC (status = acpi_db_single_step (walk_state, op, op_class)); + ACPI_DEBUGGER_EXEC (if (ACPI_FAILURE (status)) {return_ACPI_STATUS (status);}); - switch (op_class) { /* Decode the Opcode Class */ - case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */ + switch (op_class) { + case AML_CLASS_ARGUMENT: /* constants, literals, etc. -- do nothing */ break; - /* most operators with arguments */ - case AML_CLASS_EXECUTE: + case AML_CLASS_EXECUTE: /* most operators with arguments */ /* Build resolved operand stack */ @@ -385,37 +385,26 @@ status = acpi_ex_resolve_operands (walk_state->opcode, &(walk_state->operands [walk_state->num_operands -1]), walk_state); - if (ACPI_FAILURE (status)) { - /* TBD: must pop and delete operands */ - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "[%s]: Could not resolve operands, %s\n", - acpi_ps_get_opcode_name (walk_state->opcode), acpi_format_exception (status))); + if (ACPI_SUCCESS (status)) { + ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name (walk_state->opcode), + walk_state->num_operands, "after Ex_resolve_operands"); /* - * On error, we must delete all the operands and clear the - * operand stack + * Dispatch the request to the appropriate interpreter handler + * routine. There is one routine per opcode "type" based upon the + * number of opcode arguments and return type. */ - for (i = 0; i < walk_state->num_operands; i++) { - acpi_ut_remove_reference (walk_state->operands[i]); - walk_state->operands[i] = NULL; - } - - walk_state->num_operands = 0; - goto cleanup; + status = acpi_gbl_op_type_dispatch [op_type] (walk_state); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "[%s]: Could not resolve operands, %s\n", + acpi_ps_get_opcode_name (walk_state->opcode), + acpi_format_exception (status))); } - DUMP_OPERANDS (WALK_OPERANDS, IMODE_EXECUTE, acpi_ps_get_opcode_name (walk_state->opcode), - walk_state->num_operands, "after Ex_resolve_operands"); - - /* - * Dispatch the request to the appropriate interpreter handler - * routine. There is one routine per opcode "type" based upon the - * number of opcode arguments and return type. - */ - status = acpi_gbl_op_type_dispatch [op_type] (walk_state); - - - /* Delete argument objects and clear the operand stack */ + /* Always delete the argument objects and clear the operand stack */ for (i = 0; i < walk_state->num_operands; i++) { /* @@ -425,7 +414,6 @@ acpi_ut_remove_reference (walk_state->operands[i]); walk_state->operands[i] = NULL; } - walk_state->num_operands = 0; /* @@ -448,8 +436,11 @@ /* 1 Operand, 0 External_result, 0 Internal_result */ status = acpi_ds_exec_end_control_op (walk_state, op); + if (ACPI_FAILURE (status)) { + break; + } - acpi_ds_result_stack_pop (walk_state); + status = acpi_ds_result_stack_pop (walk_state); break; @@ -467,7 +458,7 @@ /* Next_op points to first argument op */ - next_op = next_op->next; + next_op = next_op->common.next; /* * Get the method's arguments and put them on the operand stack @@ -478,10 +469,9 @@ } /* - * Since the operands will be passed to another - * control method, we must resolve all local - * references here (Local variables, arguments - * to *this* method, etc.) + * Since the operands will be passed to another control method, + * we must resolve all local references here (Local variables, + * arguments to *this* method, etc.) */ status = acpi_ds_resolve_operands (walk_state); if (ACPI_FAILURE (status)) { @@ -499,7 +489,6 @@ * especially the operand count! */ return_ACPI_STATUS (status); - break; case AML_TYPE_CREATE_FIELD: @@ -516,16 +505,63 @@ break; + case AML_TYPE_CREATE_OBJECT: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing Create_object (Buffer/Package) Op=%p\n", op)); + + switch (op->common.parent->common.aml_opcode) { + case AML_NAME_OP: + + /* + * Put the Node on the object stack (Contains the ACPI Name of + * this object) + */ + walk_state->operands[0] = (void *) op->common.parent->common.node; + walk_state->num_operands = 1; + + status = acpi_ds_create_node (walk_state, op->common.parent->common.node, op->common.parent); + if (ACPI_FAILURE (status)) { + break; + } + + /* Fall through */ + /*lint -fallthrough */ + + case AML_INT_EVAL_SUBTREE_OP: + + status = acpi_ds_eval_data_object_operands (walk_state, op, + acpi_ns_get_attached_object (op->common.parent->common.node)); + break; + + default: + + status = acpi_ds_eval_data_object_operands (walk_state, op, NULL); + break; + } + + /* + * If a result object was returned from above, push it on the + * current result stack + */ + if (ACPI_SUCCESS (status) && + walk_state->result_obj) { + status = acpi_ds_result_push (walk_state->result_obj, walk_state); + } + break; + + case AML_TYPE_NAMED_FIELD: case AML_TYPE_NAMED_COMPLEX: case AML_TYPE_NAMED_SIMPLE: + case AML_TYPE_NAMED_NO_OBJ: status = acpi_ds_load2_end_op (walk_state); if (ACPI_FAILURE (status)) { break; } - if (op->opcode == AML_REGION_OP) { + if (op->common.aml_opcode == AML_REGION_OP) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Executing Op_region Address/Length Op=%p\n", op)); @@ -539,23 +575,26 @@ break; + case AML_TYPE_UNDEFINED: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", op)); return_ACPI_STATUS (AE_NOT_IMPLEMENTED); - break; case AML_TYPE_BOGUS: - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Internal opcode=%X type Op=%p\n", + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Internal opcode=%X type Op=%p\n", walk_state->opcode, op)); break; + default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented opcode, class=%X type=%X Opcode=%X Op=%p\n", - op_class, op_type, op->opcode, op)); + op_class, op_type, op->common.aml_opcode, op)); status = AE_NOT_IMPLEMENTED; break; @@ -563,8 +602,8 @@ } /* - * ACPI 2.0 support for 64-bit integers: - * Truncate numeric result value if we are executing from a 32-bit ACPI table + * ACPI 2.0 support for 64-bit integers: Truncate numeric + * result value if we are executing from a 32-bit ACPI table */ acpi_ex_truncate_for32bit_table (walk_state->result_obj, walk_state); @@ -575,9 +614,9 @@ if ((walk_state->control_state) && (walk_state->control_state->common.state == - CONTROL_PREDICATE_EXECUTING) && + ACPI_CONTROL_PREDICATE_EXECUTING) && (walk_state->control_state->control.predicate_op == op)) { - status = acpi_ds_get_predicate_value (walk_state, (u32) walk_state->result_obj); + status = acpi_ds_get_predicate_value (walk_state, walk_state->result_obj); walk_state->result_obj = NULL; } @@ -586,7 +625,7 @@ if (walk_state->result_obj) { /* Break to debugger to display result */ - DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state)); + ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state)); /* * Delete the result op if and only if: @@ -598,10 +637,7 @@ /* Always clear the object stack */ - /* TBD: [Investigate] Clear stack of return value, - but don't delete it */ walk_state->num_operands = 0; - return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dswload.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswload.c --- linux-2.4.19/drivers/acpi/dispatcher/dswload.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswload.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dswload - Dispatcher namespace load callbacks - * $Revision: 50 $ + * $Revision: 66 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dswload") + ACPI_MODULE_NAME ("dswload") /******************************************************************************* @@ -77,7 +77,6 @@ default: return (AE_BAD_PARAMETER); - break; } return (AE_OK); @@ -106,27 +105,31 @@ acpi_parse_object *op; acpi_namespace_node *node; acpi_status status; - acpi_object_type8 data_type; + acpi_object_type object_type; NATIVE_CHAR *path; - PROC_NAME ("Ds_load1_begin_op"); + ACPI_FUNCTION_NAME ("Ds_load1_begin_op"); op = walk_state->op; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); + if (op && (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); + } + /* We are only interested in opcodes that have an associated name */ - if (walk_state->op) { - if (!(walk_state->op_info->flags & AML_NAMED)) { + if (op) { + if (!(walk_state->op_info->flags & AML_NAMED)) { *out_op = op; return (AE_OK); } /* Check if this object has already been installed in the namespace */ - if (op->node) { + if (op->common.node) { *out_op = op; return (AE_OK); } @@ -136,25 +139,18 @@ /* Map the raw opcode into an internal object type */ - data_type = acpi_ds_map_named_opcode_to_data_type (walk_state->opcode); - + object_type = walk_state->op_info->object_type; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "State=%p Op=%p Type=%x\n", walk_state, op, data_type)); - - - if (walk_state->opcode == AML_SCOPE_OP) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "State=%p Op=%p Type=%x\n", walk_state, op, data_type)); - } + "State=%p Op=%p Type=%X\n", walk_state, op, object_type)); /* * Enter the named type into the internal namespace. We enter the name * as we go downward in the parse tree. Any necessary subobjects that involve * arguments to the opcode must be created as we go back up the parse tree later. */ - status = acpi_ns_lookup (walk_state->scope_info, path, data_type, - IMODE_LOAD_PASS1, NS_NO_UPSEARCH, walk_state, &(node)); + status = acpi_ns_lookup (walk_state->scope_info, path, object_type, + ACPI_IMODE_LOAD_PASS1, ACPI_NS_NO_UPSEARCH, walk_state, &(node)); if (ACPI_FAILURE (status)) { return (status); @@ -171,13 +167,13 @@ /* Initialize */ - ((acpi_parse2_object *)op)->name = node->name; + op->named.name = node->name.integer; /* * Put the Node in the "op" object that the parser uses, so we * can get it again quickly when this scope is closed */ - op->node = node; + op->common.node = node; acpi_ps_append_arg (acpi_ps_get_parent_scope (&walk_state->parser_state), op); *out_op = op; @@ -205,10 +201,11 @@ acpi_walk_state *walk_state) { acpi_parse_object *op; - acpi_object_type8 data_type; + acpi_object_type object_type; + acpi_status status = AE_OK; - PROC_NAME ("Ds_load1_end_op"); + ACPI_FUNCTION_NAME ("Ds_load1_end_op"); op = walk_state->op; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); @@ -216,35 +213,51 @@ /* We are only interested in opcodes that have an associated name */ - if (!(walk_state->op_info->flags & AML_NAMED)) { + if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) { return (AE_OK); } - /* Get the type to determine if we should pop the scope */ + /* Get the object type to determine if we should pop the scope */ + + object_type = walk_state->op_info->object_type; - data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); + if (walk_state->op_info->flags & AML_FIELD) { + if (walk_state->opcode == AML_FIELD_OP || + walk_state->opcode == AML_BANK_FIELD_OP || + walk_state->opcode == AML_INDEX_FIELD_OP) { + status = acpi_ds_init_field_objects (op, walk_state); + } + return (status); + } + + + if (op->common.aml_opcode == AML_REGION_OP) { + status = acpi_ex_create_region (op->named.data, op->named.length, + (ACPI_ADR_SPACE_TYPE) ((op->common.value.arg)->common.value.integer), walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } + } - if (op->opcode == AML_NAME_OP) { - /* For Name opcode, check the argument */ + if (op->common.aml_opcode == AML_NAME_OP) { + /* For Name opcode, get the object type from the argument */ - if (op->value.arg) { - data_type = acpi_ds_map_opcode_to_data_type ( - (op->value.arg)->opcode, NULL); - ((acpi_namespace_node *)op->node)->type = - (u8) data_type; + if (op->common.value.arg) { + object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type; + op->common.node->type = (u8) object_type; } } /* Pop the scope stack */ - if (acpi_ns_opens_scope (data_type)) { + if (acpi_ns_opens_scope (object_type)) { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n", - acpi_ut_get_type_name (data_type), op)); + acpi_ut_get_type_name (object_type), op)); - acpi_ds_scope_stack_pop (walk_state); + status = acpi_ds_scope_stack_pop (walk_state); } - return (AE_OK); + return (status); } @@ -270,28 +283,21 @@ acpi_parse_object *op; acpi_namespace_node *node; acpi_status status; - acpi_object_type8 data_type; + acpi_object_type object_type; NATIVE_CHAR *buffer_ptr; - void *original = NULL; - PROC_NAME ("Ds_load2_begin_op"); + ACPI_FUNCTION_NAME ("Ds_load2_begin_op"); + op = walk_state->op; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); - if (op) { /* We only care about Namespace opcodes here */ - if (!(walk_state->op_info->flags & AML_NSOPCODE) && - walk_state->opcode != AML_INT_NAMEPATH_OP) { - return (AE_OK); - } - - /* TBD: [Restructure] Temp! same code as in psparse */ - - if (!(walk_state->op_info->flags & AML_NAMED)) { + if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) || + (!(walk_state->op_info->flags & AML_NAMED))) { return (AE_OK); } @@ -301,7 +307,7 @@ if (walk_state->opcode == AML_INT_NAMEPATH_OP) { /* For Namepath op, get the path string */ - buffer_ptr = op->value.string; + buffer_ptr = op->common.value.string; if (!buffer_ptr) { /* No name, just exit */ @@ -311,20 +317,21 @@ else { /* Get name from the op */ - buffer_ptr = (NATIVE_CHAR *) &((acpi_parse2_object *)op)->name; + buffer_ptr = (NATIVE_CHAR *) &op->named.name; } } else { + /* Get the namestring from the raw AML */ + buffer_ptr = acpi_ps_get_next_namestring (&walk_state->parser_state); } + /* Map the opcode into an internal object type */ - /* Map the raw opcode into an internal object type */ - - data_type = acpi_ds_map_named_opcode_to_data_type (walk_state->opcode); + object_type = walk_state->op_info->object_type; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "State=%p Op=%p Type=%x\n", walk_state, op, data_type)); + "State=%p Op=%p Type=%X\n", walk_state, op, object_type)); if (walk_state->opcode == AML_FIELD_OP || @@ -333,23 +340,24 @@ node = NULL; status = AE_OK; } - else if (walk_state->opcode == AML_INT_NAMEPATH_OP) { /* * The Name_path is an object reference to an existing object. Don't enter the * name into the namespace, but look it up for use later */ - status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, data_type, - IMODE_EXECUTE, NS_SEARCH_PARENT, walk_state, &(node)); + status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); } - else { - if (op && op->node) { - original = op->node; - node = op->node; + /* All other opcodes */ + + if (op && op->common.node) { + /* This op/node was previously entered into the namespace */ + + node = op->common.node; - if (acpi_ns_opens_scope (data_type)) { - status = acpi_ds_scope_stack_push (node, data_type, walk_state); + if (acpi_ns_opens_scope (object_type)) { + status = acpi_ds_scope_stack_push (node, object_type, walk_state); if (ACPI_FAILURE (status)) { return (status); } @@ -363,8 +371,8 @@ * as we go downward in the parse tree. Any necessary subobjects that involve * arguments to the opcode must be created as we go back up the parse tree later. */ - status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, data_type, - IMODE_EXECUTE, NS_NO_UPSEARCH, walk_state, &(node)); + status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node)); } if (ACPI_SUCCESS (status)) { @@ -376,26 +384,21 @@ return (AE_NO_MEMORY); } - /* Initialize */ + /* Initialize the new op */ - ((acpi_parse2_object *)op)->name = node->name; - *out_op = op; + if (node) { + op->named.name = node->name.integer; + } + if (out_op) { + *out_op = op; + } } /* * Put the Node in the "op" object that the parser uses, so we * can get it again quickly when this scope is closed */ - op->node = node; - - if (original) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "old %p new %p\n", original, node)); - - if (original != node) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Lookup match error: old %p new %p\n", original, node)); - } - } + op->common.node = node; } return (status); @@ -423,18 +426,18 @@ { acpi_parse_object *op; acpi_status status = AE_OK; - acpi_object_type8 data_type; + acpi_object_type object_type; acpi_namespace_node *node; acpi_parse_object *arg; acpi_namespace_node *new_node; u32 i; - PROC_NAME ("Ds_load2_end_op"); + ACPI_FUNCTION_NAME ("Ds_load2_end_op"); op = walk_state->op; - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); - + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", + walk_state->op_info->name, op, walk_state)); /* Only interested in opcodes that have namespace objects */ @@ -442,11 +445,11 @@ return (AE_OK); } - if (op->opcode == AML_SCOPE_OP) { + if (op->common.aml_opcode == AML_SCOPE_OP) { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Ending scope Op=%p State=%p\n", op, walk_state)); - if (((acpi_parse2_object *)op)->name == -1) { + if (op->named.name == ACPI_UINT16_MAX) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unnamed scope! Op=%p State=%p\n", op, walk_state)); return (AE_OK); @@ -454,13 +457,13 @@ } - data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); + object_type = walk_state->op_info->object_type; /* * Get the Node/name from the earlier lookup * (It was saved in the *op structure) */ - node = op->node; + node = op->common.node; /* * Put the Node on the object stack (Contains the ACPI Name of @@ -471,11 +474,14 @@ /* Pop the scope stack */ - if (acpi_ns_opens_scope (data_type)) { - + if (acpi_ns_opens_scope (object_type)) { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", - acpi_ut_get_type_name (data_type), op)); - acpi_ds_scope_stack_pop (walk_state); + acpi_ut_get_type_name (object_type), op)); + + status = acpi_ds_scope_stack_pop (walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } } /* @@ -508,11 +514,11 @@ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Create-Load [%s] State=%p Op=%p Named_obj=%p\n", - acpi_ps_get_opcode_name (op->opcode), walk_state, op, node)); + acpi_ps_get_opcode_name (op->common.aml_opcode), walk_state, op, node)); /* Decode the opcode */ - arg = op->value.arg; + arg = op->common.value.arg; switch (walk_state->op_info->type) { case AML_TYPE_CREATE_FIELD: @@ -527,24 +533,25 @@ case AML_TYPE_NAMED_FIELD: - arg = op->value.arg; - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_INDEX_FIELD_OP: - status = acpi_ds_create_index_field (op, (acpi_handle) arg->node, + status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node, walk_state); break; - case AML_BANK_FIELD_OP: - status = acpi_ds_create_bank_field (op, arg->node, walk_state); + status = acpi_ds_create_bank_field (op, arg->common.node, walk_state); break; - case AML_FIELD_OP: - status = acpi_ds_create_field (op, arg->node, walk_state); + status = acpi_ds_create_field (op, arg->common.node, walk_state); + break; + + default: + /* All NAMED_FIELD opcodes must be handled above */ break; } break; @@ -557,31 +564,27 @@ goto cleanup; } - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_PROCESSOR_OP: status = acpi_ex_create_processor (walk_state); break; - case AML_POWER_RES_OP: status = acpi_ex_create_power_resource (walk_state); break; - case AML_MUTEX_OP: status = acpi_ex_create_mutex (walk_state); break; - case AML_EVENT_OP: status = acpi_ex_create_event (walk_state); break; - case AML_DATA_REGION_OP: status = acpi_ex_create_table_region (walk_state); @@ -597,7 +600,6 @@ status = AE_OK; goto cleanup; - break; } /* Delete operands */ @@ -612,24 +614,23 @@ case AML_TYPE_NAMED_COMPLEX: - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_METHOD_OP: /* - * Method_op Pkg_length Names_string Method_flags Term_list + * Method_op Pkg_length Name_string Method_flags Term_list */ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "LOADING-Method: State=%p Op=%p Named_obj=%p\n", walk_state, op, node)); - if (!node->object) { + if (!acpi_ns_get_attached_object (node)) { status = acpi_ds_create_operands (walk_state, arg); if (ACPI_FAILURE (status)) { goto cleanup; } - status = acpi_ex_create_method (((acpi_parse2_object *) op)->data, - ((acpi_parse2_object *) op)->length, - walk_state); + status = acpi_ex_create_method (op->named.data, + op->named.length, walk_state); } break; @@ -639,9 +640,21 @@ * The Op_region is not fully parsed at this time. Only valid argument is the Space_id. * (We must save the address of the AML of the address and length operands) */ - status = acpi_ex_create_region (((acpi_parse2_object *) op)->data, - ((acpi_parse2_object *) op)->length, - (ACPI_ADR_SPACE_TYPE) arg->value.integer, walk_state); + /* + * If we have a valid region, initialize it + * Namespace is NOT locked at this point. + */ + status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE); + if (ACPI_FAILURE (status)) { + /* + * If AE_NOT_EXIST is returned, it is not fatal + * because many regions get created before a handler + * is installed for said region. + */ + if (AE_NOT_EXIST == status) { + status = AE_OK; + } + } break; @@ -649,6 +662,11 @@ status = acpi_ds_create_node (walk_state, node, op); break; + + + default: + /* All NAMED_COMPLEX opcodes must be handled above */ + break; } break; @@ -668,21 +686,24 @@ /* * Lookup the method name and save the Node */ - status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, - ACPI_TYPE_ANY, IMODE_LOAD_PASS2, - NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS2, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, walk_state, &(new_node)); if (ACPI_SUCCESS (status)) { - /* TBD: has name already been resolved by here ??*/ - - /* TBD: [Restructure] Make sure that what we found is indeed a method! */ - /* We didn't search for a method on purpose, to see if the name would resolve! */ + /* + * Make sure that what we found is indeed a method + * We didn't search for a method on purpose, to see if the name would resolve + */ + if (new_node->type != ACPI_TYPE_METHOD) { + status = AE_AML_OPERAND_TYPE; + } /* We could put the returned object (Node) on the object stack for later, but * for now, we will put it in the "op" object that the parser uses, so we * can get it again at the end of this scope */ - op->node = new_node; + op->common.node = new_node; } break; diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dswscope.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswscope.c --- linux-2.4.19/drivers/acpi/dispatcher/dswscope.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswscope.c Fri Apr 26 11:07:18 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dswscope - Scope stack manipulation - * $Revision: 49 $ + * $Revision: 52 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dswscope") + ACPI_MODULE_NAME ("dswscope") #define STACK_POP(head) head @@ -53,7 +53,7 @@ { acpi_generic_state *scope_info; - PROC_NAME ("Ds_scope_stack_clear"); + ACPI_FUNCTION_NAME ("Ds_scope_stack_clear"); while (walk_state->scope_info) { @@ -84,26 +84,26 @@ acpi_status acpi_ds_scope_stack_push ( acpi_namespace_node *node, - acpi_object_type8 type, + acpi_object_type type, acpi_walk_state *walk_state) { acpi_generic_state *scope_info; - FUNCTION_TRACE ("Ds_scope_stack_push"); + ACPI_FUNCTION_TRACE ("Ds_scope_stack_push"); if (!node) { /* Invalid scope */ - REPORT_ERROR (("Ds_scope_stack_push: null scope passed\n")); + ACPI_REPORT_ERROR (("Ds_scope_stack_push: null scope passed\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Make sure object type is valid */ if (!acpi_ex_validate_object_type (type)) { - REPORT_WARNING (("Ds_scope_stack_push: type code out of range\n")); + ACPI_REPORT_WARNING (("Ds_scope_stack_push: type code out of range\n")); } @@ -152,7 +152,7 @@ acpi_generic_state *scope_info; - FUNCTION_TRACE ("Ds_scope_stack_pop"); + ACPI_FUNCTION_TRACE ("Ds_scope_stack_pop"); /* diff -Nur linux-2.4.19/drivers/acpi/dispatcher/dswstate.c linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswstate.c --- linux-2.4.19/drivers/acpi/dispatcher/dswstate.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/dispatcher/dswstate.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: dswstate - Dispatcher parse tree walk management routines - * $Revision: 54 $ + * $Revision: 64 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +25,12 @@ #include "acpi.h" -#include "amlcode.h" #include "acparser.h" #include "acdispat.h" #include "acnamesp.h" -#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER - MODULE_NAME ("dswstate") + ACPI_MODULE_NAME ("dswstate") /******************************************************************************* @@ -57,7 +55,7 @@ acpi_generic_state *state; - PROC_NAME ("Ds_result_insert"); + ACPI_FUNCTION_NAME ("Ds_result_insert"); state = walk_state->results; @@ -116,7 +114,7 @@ acpi_generic_state *state; - PROC_NAME ("Ds_result_remove"); + ACPI_FUNCTION_NAME ("Ds_result_remove"); state = walk_state->results; @@ -126,13 +124,12 @@ return (AE_NOT_EXIST); } - if (index >= OBJ_NUM_OPERANDS) { + if (index >= OBJ_MAX_OPERAND) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index out of range: %X State=%p Num=%X\n", index, walk_state, state->results.num_results)); } - /* Check for a valid result object */ if (!state->results.obj_desc [index]) { @@ -181,7 +178,7 @@ acpi_generic_state *state; - PROC_NAME ("Ds_result_pop"); + ACPI_FUNCTION_NAME ("Ds_result_pop"); state = walk_state->results; @@ -237,11 +234,11 @@ acpi_operand_object **object, acpi_walk_state *walk_state) { - u32 index; + NATIVE_UINT index; acpi_generic_state *state; - PROC_NAME ("Ds_result_pop_from_bottom"); + ACPI_FUNCTION_NAME ("Ds_result_pop_from_bottom"); state = walk_state->results; @@ -251,7 +248,6 @@ return (AE_NOT_EXIST); } - if (!state->results.num_results) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); return (AE_AML_NO_RETURN_VALUE); @@ -273,7 +269,7 @@ if (!*object) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null operand! State=%p #Ops=%X, Index=%X\n", - walk_state, state->results.num_results, index)); + walk_state, state->results.num_results, (u32) index)); return (AE_AML_NO_RETURN_VALUE); } @@ -307,7 +303,7 @@ acpi_generic_state *state; - PROC_NAME ("Ds_result_push"); + ACPI_FUNCTION_NAME ("Ds_result_push"); state = walk_state->results; @@ -329,7 +325,6 @@ return (AE_BAD_PARAMETER); } - state->results.obj_desc [state->results.num_results] = object; state->results.num_results++; @@ -360,7 +355,7 @@ { acpi_generic_state *state; - PROC_NAME ("Ds_result_stack_push"); + ACPI_FUNCTION_NAME ("Ds_result_stack_push"); state = acpi_ut_create_generic_state (); @@ -396,7 +391,7 @@ { acpi_generic_state *state; - PROC_NAME ("Ds_result_stack_pop"); + ACPI_FUNCTION_NAME ("Ds_result_stack_pop"); /* Check for stack underflow */ @@ -440,7 +435,7 @@ u32 i; - FUNCTION_TRACE_PTR ("Ds_obj_stack_delete_all", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_obj_stack_delete_all", walk_state); /* The stack size is configurable, but fixed */ @@ -474,7 +469,7 @@ void *object, acpi_walk_state *walk_state) { - PROC_NAME ("Ds_obj_stack_push"); + ACPI_FUNCTION_NAME ("Ds_obj_stack_push"); /* Check for stack overflow */ @@ -519,7 +514,7 @@ acpi_operand_object **object, acpi_walk_state *walk_state) { - PROC_NAME ("Ds_obj_stack_pop_object"); + ACPI_FUNCTION_NAME ("Ds_obj_stack_pop_object"); /* Check for stack underflow */ @@ -580,7 +575,7 @@ { u32 i; - PROC_NAME ("Ds_obj_stack_pop"); + ACPI_FUNCTION_NAME ("Ds_obj_stack_pop"); for (i = 0; i < pop_count; i++) { @@ -628,7 +623,7 @@ u32 i; acpi_operand_object *obj_desc; - PROC_NAME ("Ds_obj_stack_pop_and_delete"); + ACPI_FUNCTION_NAME ("Ds_obj_stack_pop_and_delete"); for (i = 0; i < pop_count; i++) { @@ -679,7 +674,7 @@ acpi_walk_state *walk_state) { - FUNCTION_TRACE_PTR ("Ds_obj_stack_get_value", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_obj_stack_get_value", walk_state); /* Can't do it if the stack is empty */ @@ -694,7 +689,6 @@ return_PTR (NULL); } - return_PTR (walk_state->operands[(NATIVE_UINT)(walk_state->num_operands - 1) - index]); } @@ -704,31 +698,31 @@ * * FUNCTION: Acpi_ds_get_current_walk_state * - * PARAMETERS: Walk_list - Get current active state for this walk list + * PARAMETERS: Thread - Get current active state for this Thread * * RETURN: Pointer to the current walk state * * DESCRIPTION: Get the walk state that is at the head of the list (the "current" - * walk state. + * walk state.) * ******************************************************************************/ acpi_walk_state * acpi_ds_get_current_walk_state ( - acpi_walk_list *walk_list) + ACPI_THREAD_STATE *thread) { - PROC_NAME ("Ds_get_current_walk_state"); + ACPI_FUNCTION_NAME ("Ds_get_current_walk_state"); - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Ds_get_current_walk_state, =%p\n", - walk_list->walk_state)); - - if (!walk_list) { + if (!thread) { return (NULL); } - return (walk_list->walk_state); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Ds_get_current_walk_state, =%p\n", + thread->walk_state_list)); + + return (thread->walk_state_list); } @@ -748,13 +742,13 @@ void acpi_ds_push_walk_state ( acpi_walk_state *walk_state, - acpi_walk_list *walk_list) + ACPI_THREAD_STATE *thread) { - FUNCTION_TRACE ("Ds_push_walk_state"); + ACPI_FUNCTION_TRACE ("Ds_push_walk_state"); - walk_state->next = walk_list->walk_state; - walk_list->walk_state = walk_state; + walk_state->next = thread->walk_state_list; + thread->walk_state_list = walk_state; return_VOID; } @@ -776,25 +770,25 @@ acpi_walk_state * acpi_ds_pop_walk_state ( - acpi_walk_list *walk_list) + ACPI_THREAD_STATE *thread) { acpi_walk_state *walk_state; - FUNCTION_TRACE ("Ds_pop_walk_state"); + ACPI_FUNCTION_TRACE ("Ds_pop_walk_state"); - walk_state = walk_list->walk_state; + walk_state = thread->walk_state_list; if (walk_state) { /* Next walk state becomes the current walk state */ - walk_list->walk_state = walk_state->next; + thread->walk_state_list = walk_state->next; /* * Don't clear the NEXT field, this serves as an indicator * that there is a parent WALK STATE - * Walk_state->Next = NULL; + * NO: Walk_state->Next = NULL; */ } @@ -807,12 +801,12 @@ * FUNCTION: Acpi_ds_create_walk_state * * PARAMETERS: Origin - Starting point for this walk - * Walk_list - Owning walk list + * Thread - Current thread state * * RETURN: Pointer to the new walk state. * - * DESCRIPTION: Allocate and initialize a new walk state. The current walk state - * is set to this new state. + * DESCRIPTION: Allocate and initialize a new walk state. The current walk + * state is set to this new state. * ******************************************************************************/ @@ -821,13 +815,13 @@ acpi_owner_id owner_id, acpi_parse_object *origin, acpi_operand_object *mth_desc, - acpi_walk_list *walk_list) + ACPI_THREAD_STATE *thread) { acpi_walk_state *walk_state; acpi_status status; - FUNCTION_TRACE ("Ds_create_walk_state"); + ACPI_FUNCTION_TRACE ("Ds_create_walk_state"); walk_state = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_WALK); @@ -839,7 +833,7 @@ walk_state->owner_id = owner_id; walk_state->origin = origin; walk_state->method_desc = mth_desc; - walk_state->walk_list = walk_list; + walk_state->thread = thread; /* Init the method args/local */ @@ -856,8 +850,8 @@ /* Put the new state at the head of the walk list */ - if (walk_list) { - acpi_ds_push_walk_state (walk_state, walk_list); + if (thread) { + acpi_ds_push_walk_state (walk_state, thread); } return_PTR (walk_state); @@ -892,7 +886,7 @@ acpi_parse_state *parser_state = &walk_state->parser_state; - FUNCTION_TRACE ("Ds_init_aml_walk"); + ACPI_FUNCTION_TRACE ("Ds_init_aml_walk"); walk_state->parser_state.aml = @@ -901,7 +895,6 @@ walk_state->parser_state.pkg_end = aml_start + aml_length; /* The Next_op of the Next_walk will be the beginning of the method */ - /* TBD: [Restructure] -- obsolete? */ walk_state->next_op = NULL; walk_state->params = params; @@ -914,11 +907,10 @@ if (method_node) { walk_state->parser_state.start_node = method_node; - walk_state->walk_type = WALK_METHOD; + walk_state->walk_type = ACPI_WALK_METHOD; walk_state->method_node = method_node; walk_state->method_desc = acpi_ns_get_attached_object (method_node); - /* Push start scope on scope stack and make it current */ status = acpi_ds_scope_stack_push (method_node, ACPI_TYPE_METHOD, walk_state); @@ -928,13 +920,15 @@ /* Init the method arguments */ - acpi_ds_method_data_init_args (params, MTH_NUM_ARGS, walk_state); + status = acpi_ds_method_data_init_args (params, MTH_NUM_ARGS, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - else { /* Setup the current scope */ - parser_state->start_node = parser_state->start_op->node; + parser_state->start_node = parser_state->start_op->common.node; if (parser_state->start_node) { /* Push start scope on scope stack and make it current */ @@ -946,9 +940,8 @@ } } - acpi_ds_init_callbacks (walk_state, pass_number); - - return_ACPI_STATUS (AE_OK); + status = acpi_ds_init_callbacks (walk_state, pass_number); + return_ACPI_STATUS (status); } #endif @@ -972,7 +965,7 @@ acpi_generic_state *state; - FUNCTION_TRACE_PTR ("Ds_delete_walk_state", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ds_delete_walk_state", walk_state); if (!walk_state) { @@ -984,7 +977,6 @@ return; } - if (walk_state->parser_state.scope) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state)); } @@ -1038,7 +1030,7 @@ acpi_ds_delete_walk_state_cache ( void) { - FUNCTION_TRACE ("Ds_delete_walk_state_cache"); + ACPI_FUNCTION_TRACE ("Ds_delete_walk_state_cache"); acpi_ut_delete_generic_cache (ACPI_MEM_LIST_WALK); diff -Nur linux-2.4.19/drivers/acpi/driver.c linux-2.4.19-sgi211r3/drivers/acpi/driver.c --- linux-2.4.19/drivers/acpi/driver.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/driver.c Wed Dec 31 16:00:00 1969 @@ -1,217 +0,0 @@ -/* - * driver.c - ACPI driver - * - * Copyright (C) 2000 Andrew Henroid - * Copyright (C) 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * Changes - * David Woodhouse 2000-12-6 - * - Fix interruptible_sleep_on() races - * Andrew Grover 2001-2-28 - * - Major revamping - * Peter Breuer 2001-5-20 - * - parse boot time params. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "acpi.h" - - -#define _COMPONENT OS_DEPENDENT - MODULE_NAME ("driver") - -FADT_DESCRIPTOR acpi_fadt; - -static int acpi_disabled = 0; - -enum acpi_blacklist_predicates -{ - all_versions, - less_than_or_equal, - equal, - greater_than_or_equal, -}; - -struct acpi_blacklist_item -{ - char oem_id[7]; - char oem_table_id[9]; - u32 oem_revision; - enum acpi_blacklist_predicates oem_revision_predicate; -}; - -/* - * Currently, this blacklists based on items in the FADT. We may want to - * expand this to using other ACPI tables in the future, too. - */ -static struct acpi_blacklist_item acpi_blacklist[] __initdata = -{ - {"TOSHIB", "750 ", 0x970814, less_than_or_equal}, /* Portege 7020, BIOS 8.10 */ - {""} -}; - -int -acpi_blacklisted(FADT_DESCRIPTOR *fadt) -{ - int i = 0; - - while (acpi_blacklist[i].oem_id[0] != '\0') - { - if (strncmp(acpi_blacklist[i].oem_id, fadt->header.oem_id, 6)) { - i++; - continue; - } - - if (strncmp(acpi_blacklist[i].oem_table_id, fadt->header.oem_table_id, 8)) { - i++; - continue; - } - - if (acpi_blacklist[i].oem_revision_predicate == all_versions) - return TRUE; - - if (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal - && fadt->header.oem_revision <= acpi_blacklist[i].oem_revision) - return TRUE; - - if (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal - && fadt->header.oem_revision >= acpi_blacklist[i].oem_revision) - return TRUE; - - if (acpi_blacklist[i].oem_revision_predicate == equal - && fadt->header.oem_revision == acpi_blacklist[i].oem_revision) - return TRUE; - - i++; - } - - return FALSE; -} - -/* - * Start the interpreter - */ -int -acpi_init(void) -{ - acpi_buffer buffer; - acpi_system_info sys_info; - - if (PM_IS_ACTIVE()) { - printk(KERN_NOTICE "ACPI: APM is already active, exiting\n"); - return -ENODEV; - } - - if (acpi_disabled) { - printk(KERN_NOTICE "ACPI: disabled by cmdline, exiting\n"); - return -ENODEV; - } - - if (!ACPI_SUCCESS(acpi_initialize_subsystem())) { - printk(KERN_ERR "ACPI: Driver initialization failed\n"); - return -ENODEV; - } - - /* from this point on, on error we must call acpi_terminate() */ - if (!ACPI_SUCCESS(acpi_load_tables())) { - printk(KERN_ERR "ACPI: System description table load failed\n"); - acpi_terminate(); - return -ENODEV; - } - - /* get a separate copy of the FADT for use by other drivers */ - memset(&acpi_fadt, 0, sizeof(acpi_fadt)); - buffer.pointer = &acpi_fadt; - buffer.length = sizeof(acpi_fadt); - - if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FADT, 1, &buffer))) { - printk(KERN_ERR "ACPI: Could not get FADT\n"); - acpi_terminate(); - return -ENODEV; - } - - if (acpi_blacklisted(&acpi_fadt)) { - printk(KERN_ERR "ACPI: On blacklist -- BIOS not fully ACPI compliant\n"); - acpi_terminate(); - return -ENODEV; - } - - buffer.length = sizeof(sys_info); - buffer.pointer = &sys_info; - - if (!ACPI_SUCCESS (acpi_get_system_info(&buffer))) { - printk(KERN_ERR "ACPI: Could not get system info\n"); - acpi_terminate(); - return -ENODEV; - } - - printk(KERN_INFO "ACPI: Core Subsystem version [%x]\n", sys_info.acpi_ca_version); - - if (!ACPI_SUCCESS(acpi_enable_subsystem(ACPI_FULL_INITIALIZATION))) { - printk(KERN_ERR "ACPI: Subsystem enable failed\n"); - acpi_terminate(); - return -ENODEV; - } - - printk(KERN_INFO "ACPI: Subsystem enabled\n"); - - pm_active = 1; - - return 0; -} - -/* - * Terminate the interpreter - */ -void -acpi_exit(void) -{ - acpi_terminate(); - - pm_active = 0; - - printk(KERN_ERR "ACPI: Subsystem disabled\n"); -} - -module_init(acpi_init); -module_exit(acpi_exit); - -#ifndef MODULE -static int __init acpi_setup(char *str) { - while (str && *str) { - if (strncmp(str, "off", 3) == 0) - acpi_disabled = 1; - str = strchr(str, ','); - if (str) - str += strspn(str, ", \t"); - } - return 1; -} - -__setup("acpi=", acpi_setup); -#endif diff -Nur linux-2.4.19/drivers/acpi/ec.c linux-2.4.19-sgi211r3/drivers/acpi/ec.c --- linux-2.4.19/drivers/acpi/ec.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/ec.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,736 @@ +/* + * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_EC_COMPONENT +ACPI_MODULE_NAME ("acpi_ec") + +#define PREFIX "ACPI: " + + +#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ +#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ +#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ + +#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ +#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ + +#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ +#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ +#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ + +#define ACPI_EC_COMMAND_READ 0x80 +#define ACPI_EC_COMMAND_WRITE 0x81 +#define ACPI_EC_COMMAND_QUERY 0x84 + +static int acpi_ec_add (struct acpi_device *device); +static int acpi_ec_remove (struct acpi_device *device, int type); +static int acpi_ec_start (struct acpi_device *device); +static int acpi_ec_stop (struct acpi_device *device, int type); + +static struct acpi_driver acpi_ec_driver = { + name: ACPI_EC_DRIVER_NAME, + class: ACPI_EC_CLASS, + ids: ACPI_EC_HID, + ops: { + add: acpi_ec_add, + remove: acpi_ec_remove, + start: acpi_ec_start, + stop: acpi_ec_stop, + }, +}; + +struct acpi_ec { + acpi_handle handle; + unsigned long gpe_bit; + unsigned long status_port; + unsigned long command_port; + unsigned long data_port; + unsigned long global_lock; + spinlock_t lock; +}; + + +/* -------------------------------------------------------------------------- + Transaction Management + -------------------------------------------------------------------------- */ + +static int +acpi_ec_wait ( + struct acpi_ec *ec, + u8 event) +{ + u8 acpi_ec_status = 0; + u32 i = ACPI_EC_UDELAY_COUNT; + + if (!ec) + return -EINVAL; + + /* Poll the EC status register waiting for the event to occur. */ + switch (event) { + case ACPI_EC_EVENT_OBF: + do { + acpi_ec_status = inb(ec->status_port); + if (acpi_ec_status & ACPI_EC_FLAG_OBF) + return 0; + udelay(ACPI_EC_UDELAY); + } while (--i>0); + break; + case ACPI_EC_EVENT_IBE: + do { + acpi_ec_status = inb(ec->status_port); + if (!(acpi_ec_status & ACPI_EC_FLAG_IBF)) + return 0; + udelay(ACPI_EC_UDELAY); + } while (--i>0); + break; + default: + return -EINVAL; + } + + return -ETIME; +} + + +static int +acpi_ec_read ( + struct acpi_ec *ec, + u8 address, + u8 *data) +{ + acpi_status status = AE_OK; + int result = 0; + unsigned long flags = 0; + u32 glk = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_read"); + + if (!ec || !data) + return_VALUE(-EINVAL); + + *data = 0; + + if (ec->global_lock) { + status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + } + + spin_lock_irqsave(&ec->lock, flags); + + outb(ACPI_EC_COMMAND_READ, ec->command_port); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (0 != result) + goto end; + + outb(address, ec->data_port); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (0 != result) + goto end; + + *data = inb(ec->data_port); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", + *data, address)); + +end: + spin_unlock_irqrestore(&ec->lock, flags); + + if (ec->global_lock) + acpi_release_global_lock(glk); + + return_VALUE(result); +} + + +static int +acpi_ec_write ( + struct acpi_ec *ec, + u8 address, + u8 data) +{ + int result = 0; + acpi_status status = AE_OK; + unsigned long flags = 0; + u32 glk = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_write"); + + if (!ec) + return_VALUE(-EINVAL); + + if (ec->global_lock) { + status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + } + + spin_lock_irqsave(&ec->lock, flags); + + outb(ACPI_EC_COMMAND_WRITE, ec->command_port); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (0 != result) + goto end; + + outb(address, ec->data_port); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (0 != result) + goto end; + + outb(data, ec->data_port); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (0 != result) + goto end; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", + data, address)); + +end: + spin_unlock_irqrestore(&ec->lock, flags); + + if (ec->global_lock) + acpi_release_global_lock(glk); + + return_VALUE(result); +} + + +static int +acpi_ec_query ( + struct acpi_ec *ec, + u8 *data) +{ + int result = 0; + acpi_status status = AE_OK; + unsigned long flags = 0; + u32 glk = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_query"); + + if (!ec || !data) + return_VALUE(-EINVAL); + + *data = 0; + + if (ec->global_lock) { + status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + } + + /* + * Query the EC to find out which _Qxx method we need to evaluate. + * Note that successful completion of the query causes the ACPI_EC_SCI + * bit to be cleared (and thus clearing the interrupt source). + */ + + spin_lock_irqsave(&ec->lock, flags); + + outb(ACPI_EC_COMMAND_QUERY, ec->command_port); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (0 != result) + goto end; + + *data = inb(ec->data_port); + if (!*data) + result = -ENODATA; + +end: + spin_unlock_irqrestore(&ec->lock, flags); + + if (ec->global_lock) + acpi_release_global_lock(glk); + + return_VALUE(result); +} + + +/* -------------------------------------------------------------------------- + Event Management + -------------------------------------------------------------------------- */ + +struct acpi_ec_query_data { + acpi_handle handle; + u8 data; +}; + + +static void +acpi_ec_gpe_query ( + void *data) +{ + struct acpi_ec_query_data *query_data = NULL; + static char object_name[5] = {'_','Q','0','0','\0'}; + const char hex[] = {'0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F'}; + + ACPI_FUNCTION_TRACE("acpi_ec_gpe_query"); + + if (!data) + return; + + query_data = (struct acpi_ec_query_data *) data; + + object_name[2] = hex[((query_data->data >> 4) & 0x0F)]; + object_name[3] = hex[(query_data->data & 0x0F)]; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); + + acpi_evaluate(query_data->handle, object_name, NULL, NULL); + + kfree(query_data); + + return; +} + + +static void +acpi_ec_gpe_handler ( + void *data) +{ + acpi_status status = AE_OK; + struct acpi_ec *ec = (struct acpi_ec *) data; + u8 value = 0; + unsigned long flags = 0; + struct acpi_ec_query_data *query_data = NULL; + + if (!ec) + return; + + spin_lock_irqsave(&ec->lock, flags); + value = inb(ec->command_port); + spin_unlock_irqrestore(&ec->lock, flags); + + /* TBD: Implement asynch events! + * NOTE: All we care about are EC-SCI's. Other EC events are + * handled via polling (yuck!). This is because some systems + * treat EC-SCIs as level (versus EDGE!) triggered, preventing + * a purely interrupt-driven approach (grumble, grumble). + */ + + if (!(value & ACPI_EC_FLAG_SCI)) + return; + + if (0 != acpi_ec_query(ec, &value)) + return; + + query_data = kmalloc(sizeof(struct acpi_ec_query_data), GFP_ATOMIC); + if (!query_data) + return; + query_data->handle = ec->handle; + query_data->data = value; + + status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, + acpi_ec_gpe_query, query_data); + if (ACPI_FAILURE(status)) + kfree(query_data); + + return; +} + + +/* -------------------------------------------------------------------------- + Address Space Management + -------------------------------------------------------------------------- */ + +static acpi_status +acpi_ec_space_setup ( + acpi_handle region_handle, + u32 function, + void *handler_context, + void **return_context) +{ + /* + * The EC object is in the handler context and is needed + * when calling the acpi_ec_space_handler. + */ + *return_context = handler_context; + + return AE_OK; +} + + +static acpi_status +acpi_ec_space_handler ( + u32 function, + ACPI_PHYSICAL_ADDRESS address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + int result = 0; + struct acpi_ec *ec = NULL; + + ACPI_FUNCTION_TRACE("acpi_ec_space_handler"); + + if ((address > 0xFF) || (bit_width != 8) || !value || !handler_context) + return_VALUE(AE_BAD_PARAMETER); + + ec = (struct acpi_ec *) handler_context; + + switch (function) { + case ACPI_READ: + result = acpi_ec_read(ec, (u8) address, (u8*) value); + break; + case ACPI_WRITE: + result = acpi_ec_write(ec, (u8) address, (u8) *value); + break; + default: + result = -EINVAL; + break; + } + + switch (result) { + case -EINVAL: + return_VALUE(AE_BAD_PARAMETER); + break; + case -ENODEV: + return_VALUE(AE_NOT_FOUND); + break; + case -ETIME: + return_VALUE(AE_TIME); + break; + default: + return_VALUE(AE_OK); + } + +} + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +struct proc_dir_entry *acpi_ec_dir = NULL; + + +static int +acpi_ec_read_info ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_ec *ec = (struct acpi_ec *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_read_info"); + + if (!ec || (off != 0)) + goto end; + + p += sprintf(p, "gpe bit: 0x%02x\n", + (u32) ec->gpe_bit); + p += sprintf(p, "ports: 0x%02x, 0x%02x\n", + (u32) ec->status_port, (u32) ec->data_port); + p += sprintf(p, "use global lock: %s\n", + ec->global_lock?"yes":"no"); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_ec_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_ec_add_fs"); + + if (!acpi_ec_dir) { + acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir); + if (!acpi_ec_dir) + return_VALUE(-ENODEV); + } + + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_ec_dir); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + } + + entry = create_proc_read_entry(ACPI_EC_FILE_INFO, S_IRUGO, + acpi_device_dir(device), acpi_ec_read_info, + acpi_driver_data(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Unable to create '%s' fs entry\n", + ACPI_EC_FILE_INFO)); + + return_VALUE(0); +} + + +static int +acpi_ec_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_ec_remove_fs"); + + if (!acpi_ec_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_ec_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +static int +acpi_ec_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_ec *ec = NULL; + + ACPI_FUNCTION_TRACE("acpi_ec_add"); + + if (!device) + return_VALUE(-EINVAL); + + ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); + if (!ec) + return_VALUE(-ENOMEM); + memset(ec, 0, sizeof(struct acpi_ec)); + + ec->handle = device->handle; + ec->lock = SPIN_LOCK_UNLOCKED; + sprintf(acpi_device_name(device), "%s", ACPI_EC_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_EC_CLASS); + acpi_driver_data(device) = ec; + + /* Use the global lock for all EC transactions? */ + acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock); + + /* Get GPE bit assignment (EC events). */ + status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe_bit); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error obtaining GPE bit assignment\n")); + result = -ENODEV; + goto end; + } + + result = acpi_ec_add_fs(device); + if (0 != result) + goto end; + + printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n", + acpi_device_name(device), acpi_device_bid(device), + (u32) ec->gpe_bit); + +end: + if (0 != result) + kfree(ec); + + return_VALUE(result); +} + + +static int +acpi_ec_remove ( + struct acpi_device *device, + int type) +{ + struct acpi_ec *ec = NULL; + + ACPI_FUNCTION_TRACE("acpi_ec_remove"); + + if (!device) + return_VALUE(-EINVAL); + + ec = (struct acpi_ec *) acpi_driver_data(device); + + acpi_ec_remove_fs(device); + + kfree(ec); + + return_VALUE(0); +} + + +static int +acpi_ec_start ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_ec *ec = NULL; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_resource *resource = NULL; + + ACPI_FUNCTION_TRACE("acpi_ec_start"); + + if (!device) + return_VALUE(-EINVAL); + + ec = (struct acpi_ec *) acpi_driver_data(device); + + if (!ec) + return_VALUE(-EINVAL); + + /* + * Get I/O port addresses + */ + + status = acpi_get_current_resources(ec->handle, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error getting I/O port addresses")); + return_VALUE(-ENODEV); + } + + resource = (acpi_resource *) buffer.pointer; + if (!resource || (resource->id != ACPI_RSTYPE_IO)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid or missing resource\n")); + result = -ENODEV; + goto end; + } + ec->data_port = resource->data.io.min_base_address; + + resource = ACPI_NEXT_RESOURCE(resource); + if (!resource || (resource->id != ACPI_RSTYPE_IO)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid or missing resource\n")); + result = -ENODEV; + goto end; + } + ec->command_port = ec->status_port = resource->data.io.min_base_address; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n", + (u32) ec->gpe_bit, (u32) ec->command_port, (u32) ec->data_port)); + + /* + * Install GPE handler + */ + + status = acpi_install_gpe_handler(ec->gpe_bit, + ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + status = acpi_install_address_space_handler (ec->handle, + ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, + &acpi_ec_space_setup, ec); + if (ACPI_FAILURE(status)) { + acpi_remove_address_space_handler(ec->handle, + ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); + return_VALUE(-ENODEV); + } +end: + kfree(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_ec_stop ( + struct acpi_device *device, + int type) +{ + acpi_status status = AE_OK; + struct acpi_ec *ec = NULL; + + ACPI_FUNCTION_TRACE("acpi_ec_stop"); + + if (!device) + return_VALUE(-EINVAL); + + ec = (struct acpi_ec *) acpi_driver_data(device); + + status = acpi_remove_address_space_handler(ec->handle, + ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + status = acpi_remove_gpe_handler(ec->gpe_bit, &acpi_ec_gpe_handler); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +int __init +acpi_ec_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_init"); + + result = acpi_bus_register_driver(&acpi_ec_driver); + if (0 > result) { + remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + + +void __exit +acpi_ec_exit (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_exit"); + + result = acpi_bus_unregister_driver(&acpi_ec_driver); + if (0 == result) + remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); + + return_VOID; +} diff -Nur linux-2.4.19/drivers/acpi/events/Makefile linux-2.4.19-sgi211r3/drivers/acpi/events/Makefile --- linux-2.4.19/drivers/acpi/events/Makefile Wed Jun 20 17:47:39 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/events/evevent.c linux-2.4.19-sgi211r3/drivers/acpi/events/evevent.c --- linux-2.4.19/drivers/acpi/events/evevent.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evevent.c Wed Oct 16 14:02:58 2002 @@ -1,13 +1,12 @@ /****************************************************************************** * - * Module Name: evevent - Fixed and General Purpose Acpi_event - * handling and dispatch - * $Revision: 51 $ + * Module Name: evevent - Fixed and General Purpose Even handling and dispatch + * $Revision: 88 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,12 +24,11 @@ */ #include "acpi.h" -#include "achware.h" #include "acevents.h" #include "acnamesp.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evevent") + ACPI_MODULE_NAME ("evevent") /******************************************************************************* @@ -41,9 +39,7 @@ * * RETURN: Status * - * DESCRIPTION: Ensures that the system control interrupt (SCI) is properly - * configured, disables SCI event sources, installs the SCI - * handler + * DESCRIPTION: Initialize global data structures for events. * ******************************************************************************/ @@ -54,7 +50,7 @@ acpi_status status; - FUNCTION_TRACE ("Ev_initialize"); + ACPI_FUNCTION_TRACE ("Ev_initialize"); /* Make sure we have ACPI tables */ @@ -64,17 +60,6 @@ return_ACPI_STATUS (AE_NO_ACPI_TABLES); } - - /* Make sure the BIOS supports ACPI mode */ - - if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities()) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "ACPI Mode is not supported!\n")); - return_ACPI_STATUS (AE_ERROR); - } - - - acpi_gbl_original_mode = acpi_hw_get_mode(); - /* * Initialize the Fixed and General Purpose Acpi_events prior. This is * done prior to enabling SCIs to prevent interrupts from occuring @@ -82,30 +67,63 @@ */ status = acpi_ev_fixed_event_initialize (); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize fixed events.\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize fixed events, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } status = acpi_ev_gpe_initialize (); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize general purpose events.\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize general purpose events, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ev_handler_initialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install handlers for the SCI, Global Lock, and GPEs. + * + ******************************************************************************/ + +acpi_status +acpi_ev_handler_initialize ( + void) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Ev_initialize"); + + /* Install the SCI handler */ status = acpi_ev_install_sci_handler (); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to install System Control Interrupt Handler\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to install System Control Interrupt Handler, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } - /* Install handlers for control method GPE handlers (_Lxx, _Exx) */ status = acpi_ev_init_gpe_control_methods (); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize Gpe control methods\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize GPE control methods, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -113,11 +131,12 @@ status = acpi_ev_init_global_lock_handler (); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize Global Lock handler\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize Global Lock handler, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } - return_ACPI_STATUS (status); } @@ -130,27 +149,36 @@ * * RETURN: Status * - * DESCRIPTION: Initialize the Fixed Acpi_event data structures + * DESCRIPTION: Install the fixed event handlers and enable the fixed events. * ******************************************************************************/ acpi_status -acpi_ev_fixed_event_initialize(void) +acpi_ev_fixed_event_initialize ( + void) { - int i = 0; + NATIVE_UINT i; + acpi_status status; - /* Initialize the structure that keeps track of fixed event handlers */ + /* + * Initialize the structure that keeps track of fixed event handlers + * and enable the fixed events. + */ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { acpi_gbl_fixed_event_handlers[i].handler = NULL; acpi_gbl_fixed_event_handlers[i].context = NULL; - } - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, TMR_EN, 0); - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, GBL_EN, 0); - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, PWRBTN_EN, 0); - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, SLPBTN_EN, 0); - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, RTC_EN, 0); + /* Enable the fixed event */ + + if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { + status = acpi_set_register (acpi_gbl_fixed_event_info[i].enable_register_id, + 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return (status); + } + } + } return (AE_OK); } @@ -169,54 +197,41 @@ ******************************************************************************/ u32 -acpi_ev_fixed_event_detect (void) +acpi_ev_fixed_event_detect ( + void) { - u32 int_status = INTERRUPT_NOT_HANDLED; - u32 status_register; - u32 enable_register; + u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; + u32 gpe_status; + u32 gpe_enable; + NATIVE_UINT_MAX32 i; - PROC_NAME ("Ev_fixed_event_detect"); + ACPI_FUNCTION_NAME ("Ev_fixed_event_detect"); /* * Read the fixed feature status and enable registers, as all the cases - * depend on their values. + * depend on their values. Ignore errors here. */ - status_register = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_STS); - enable_register = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_EN); + (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, &gpe_status); + (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &gpe_enable); ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "Fixed Acpi_event Block: Enable %08X Status %08X\n", - enable_register, status_register)); - - - /* power management timer roll over */ - - if ((status_register & ACPI_STATUS_PMTIMER) && - (enable_register & ACPI_ENABLE_PMTIMER)) { - int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_PMTIMER); - } - - /* global event (BIOS wants the global lock) */ + gpe_enable, gpe_status)); - if ((status_register & ACPI_STATUS_GLOBAL) && - (enable_register & ACPI_ENABLE_GLOBAL)) { - int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_GLOBAL); - } - - /* power button event */ - - if ((status_register & ACPI_STATUS_POWER_BUTTON) && - (enable_register & ACPI_ENABLE_POWER_BUTTON)) { - int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_POWER_BUTTON); - } + /* + * Check for all possible Fixed Events and dispatch those that are active + */ + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { + /* Both the status and enable bits must be on for this event */ - /* sleep button event */ + if ((gpe_status & acpi_gbl_fixed_event_info[i].status_bit_mask) && + (gpe_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) { + /* Found an active (signalled) event */ - if ((status_register & ACPI_STATUS_SLEEP_BUTTON) && - (enable_register & ACPI_ENABLE_SLEEP_BUTTON)) { - int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_SLEEP_BUTTON); + int_status |= acpi_ev_fixed_event_dispatch (i); + } } return (int_status); @@ -240,60 +255,32 @@ acpi_ev_fixed_event_dispatch ( u32 event) { - u32 register_id; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* Clear the status bit */ - switch (event) { - case ACPI_EVENT_PMTIMER: - register_id = TMR_STS; - break; - - case ACPI_EVENT_GLOBAL: - register_id = GBL_STS; - break; - - case ACPI_EVENT_POWER_BUTTON: - register_id = PWRBTN_STS; - break; - - case ACPI_EVENT_SLEEP_BUTTON: - register_id = SLPBTN_STS; - break; - - case ACPI_EVENT_RTC: - register_id = RTC_STS; - break; - - default: - return 0; - break; - } - - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, register_id, 1); + (void) acpi_set_register (acpi_gbl_fixed_event_info[event].status_register_id, + 1, ACPI_MTX_DO_NOT_LOCK); /* * Make sure we've got a handler. If not, report an error. * The event is disabled to prevent further interrupts. */ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) { - register_id = (PM1_EN | REGISTER_BIT_ID(register_id)); - - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, - register_id, 0); + (void) acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 0, ACPI_MTX_DO_NOT_LOCK); - REPORT_ERROR ( + ACPI_REPORT_ERROR ( ("Ev_gpe_dispatch: No installed handler for fixed event [%08X]\n", event)); - return (INTERRUPT_NOT_HANDLED); + return (ACPI_INTERRUPT_NOT_HANDLED); } - /* Invoke the handler */ + /* Invoke the Fixed Event handler */ return ((acpi_gbl_fixed_event_handlers[event].handler)( acpi_gbl_fixed_event_handlers[event].context)); @@ -315,138 +302,217 @@ acpi_status acpi_ev_gpe_initialize (void) { - u32 i; - u32 j; - u32 register_index; + NATIVE_UINT_MAX32 i; + NATIVE_UINT_MAX32 j; + u32 gpe_block; + u32 gpe_register; + u32 gpe_number_index; u32 gpe_number; - u16 gpe0register_count; - u16 gpe1_register_count; + ACPI_GPE_REGISTER_INFO *gpe_register_info; + acpi_status status; - FUNCTION_TRACE ("Ev_gpe_initialize"); + ACPI_FUNCTION_TRACE ("Ev_gpe_initialize"); + /* - * Set up various GPE counts + * Initialize the GPE Block globals * - * You may ask,why are the GPE register block lengths divided by 2? - * From the ACPI 2.0 Spec, section, 4.7.1.6 General-Purpose Event - * Registers, we have, + * Why the GPE register block lengths divided by 2: From the ACPI Spec, + * section "General-Purpose Event Registers", we have: * * "Each register block contains two registers of equal length - * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the - * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN - * The length of the GPE1_STS and GPE1_EN registers is equal to - * half the GPE1_LEN. If a generic register block is not supported - * then its respective block pointer and block length values in the - * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need - * to be the same size." - */ - gpe0register_count = (u16) DIV_2 (acpi_gbl_FADT->gpe0blk_len); - gpe1_register_count = (u16) DIV_2 (acpi_gbl_FADT->gpe1_blk_len); - acpi_gbl_gpe_register_count = gpe0register_count + gpe1_register_count; + * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the + * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN + * The length of the GPE1_STS and GPE1_EN registers is equal to + * half the GPE1_LEN. If a generic register block is not supported + * then its respective block pointer and block length values in the + * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need + * to be the same size." + */ + if ((acpi_gbl_FADT->Xgpe0_blk.register_bit_width != 0) || + (acpi_gbl_FADT->Xgpe0_blk.register_bit_offset != 0) || + (acpi_gbl_FADT->Xgpe0_blk.address != 0)) { + acpi_gbl_gpe_block_info[0].address_space_id = acpi_gbl_FADT->Xgpe0_blk.address_space_id; + acpi_gbl_gpe_block_info[0].register_count = (u16) ACPI_DIV_16 (acpi_gbl_FADT->Xgpe0_blk.register_bit_width); + + if (acpi_gbl_gpe_block_info[0].register_count == 0) + acpi_gbl_gpe_block_info[0].register_count = 1; + acpi_gbl_gpe_block_info[0].block_address = &acpi_gbl_FADT->Xgpe0_blk; + acpi_gbl_gpe_block_info[0].block_base_number = 0; + } + + if ((acpi_gbl_FADT->Xgpe1_blk.register_bit_width != 0) || + (acpi_gbl_FADT->Xgpe1_blk.register_bit_offset != 0) || + (acpi_gbl_FADT->Xgpe1_blk.address != 0)) { + acpi_gbl_gpe_block_info[1].address_space_id = acpi_gbl_FADT->Xgpe1_blk.address_space_id; + acpi_gbl_gpe_block_info[1].register_count = (u16) ACPI_DIV_16 (acpi_gbl_FADT->Xgpe1_blk.register_bit_width); + + if (acpi_gbl_gpe_block_info[1].register_count == 0) + acpi_gbl_gpe_block_info[1].register_count = 1; + acpi_gbl_gpe_block_info[1].block_address = &acpi_gbl_FADT->Xgpe1_blk; + acpi_gbl_gpe_block_info[1].block_base_number = acpi_gbl_FADT->gpe1_base; + } + acpi_gbl_gpe_register_count = acpi_gbl_gpe_block_info[0].register_count + + acpi_gbl_gpe_block_info[1].register_count; if (!acpi_gbl_gpe_register_count) { - REPORT_WARNING (("Zero GPEs are defined in the FADT\n")); + ACPI_REPORT_WARNING (("Zero GPEs are defined in the FADT\n")); return_ACPI_STATUS (AE_OK); } + /* Determine the maximum GPE number for this machine */ + + acpi_gbl_gpe_number_max = ACPI_MUL_8 (acpi_gbl_gpe_block_info[0].register_count) - 1; + + if (acpi_gbl_gpe_block_info[1].register_count) { + /* Check for GPE0/GPE1 overlap */ + + if (acpi_gbl_gpe_number_max >= acpi_gbl_FADT->gpe1_base) { + ACPI_REPORT_ERROR (("GPE0 block overlaps the GPE1 block\n")); + return_ACPI_STATUS (AE_BAD_VALUE); + } + + /* GPE0 and GPE1 do not have to be contiguous in the GPE number space */ + + acpi_gbl_gpe_number_max = acpi_gbl_FADT->gpe1_base + (ACPI_MUL_8 (acpi_gbl_gpe_block_info[1].register_count) - 1); + } + + /* Check for Max GPE number out-of-range */ + + if (acpi_gbl_gpe_number_max > ACPI_GPE_MAX) { + ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n", acpi_gbl_gpe_number_max)); + return_ACPI_STATUS (AE_BAD_VALUE); + } + /* - * Allocate the Gpe information block + * Allocate the GPE number-to-index translation table */ - acpi_gbl_gpe_registers = ACPI_MEM_CALLOCATE (acpi_gbl_gpe_register_count * - sizeof (acpi_gpe_registers)); - if (!acpi_gbl_gpe_registers) { + acpi_gbl_gpe_number_to_index = ACPI_MEM_CALLOCATE ( + sizeof (ACPI_GPE_INDEX_INFO) * + ((ACPI_SIZE) acpi_gbl_gpe_number_max + 1)); + if (!acpi_gbl_gpe_number_to_index) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not allocate the Gpe_registers block\n")); + "Could not allocate the Gpe_number_to_index table\n")); return_ACPI_STATUS (AE_NO_MEMORY); } + /* Set the Gpe index table to GPE_INVALID */ + + ACPI_MEMSET (acpi_gbl_gpe_number_to_index, (int) ACPI_GPE_INVALID, + sizeof (ACPI_GPE_INDEX_INFO) * ((ACPI_SIZE) acpi_gbl_gpe_number_max + 1)); + /* - * Allocate the Gpe dispatch handler block - * There are eight distinct GP events per register. - * Initialization to zeros is sufficient - */ - acpi_gbl_gpe_info = ACPI_MEM_CALLOCATE (MUL_8 (acpi_gbl_gpe_register_count) * - sizeof (acpi_gpe_level_info)); - if (!acpi_gbl_gpe_info) { - ACPI_MEM_FREE (acpi_gbl_gpe_registers); - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the Gpe_info block\n")); - return_ACPI_STATUS (AE_NO_MEMORY); + * Allocate the GPE register information block + */ + acpi_gbl_gpe_register_info = ACPI_MEM_CALLOCATE ( + (ACPI_SIZE) acpi_gbl_gpe_register_count * + sizeof (ACPI_GPE_REGISTER_INFO)); + if (!acpi_gbl_gpe_register_info) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not allocate the Gpe_register_info table\n")); + goto error_exit1; } - /* Set the Gpe validation table to GPE_INVALID */ - - MEMSET (acpi_gbl_gpe_valid, (int) ACPI_GPE_INVALID, ACPI_NUM_GPE); + /* + * Allocate the GPE dispatch handler block. There are eight distinct GPEs + * per register. Initialization to zeros is sufficient. + */ + acpi_gbl_gpe_number_info = ACPI_MEM_CALLOCATE ( + (ACPI_SIZE) ACPI_MUL_8 (acpi_gbl_gpe_register_count) * + sizeof (ACPI_GPE_NUMBER_INFO)); + if (!acpi_gbl_gpe_number_info) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the Gpe_number_info table\n")); + goto error_exit2; + } /* - * Initialize the Gpe information and validation blocks. A goal of these - * blocks is to hide the fact that there are two separate GPE register sets - * In a given block, the status registers occupy the first half, and - * the enable registers occupy the second half. + * Initialize the GPE information and validation tables. A goal of these + * tables is to hide the fact that there are two separate GPE register sets + * in a given gpe hardware block, the status registers occupy the first half, + * and the enable registers occupy the second half. Another goal is to hide + * the fact that there may be multiple GPE hardware blocks. */ + gpe_register = 0; + gpe_number_index = 0; - /* GPE Block 0 */ + for (gpe_block = 0; gpe_block < ACPI_MAX_GPE_BLOCKS; gpe_block++) { + for (i = 0; i < acpi_gbl_gpe_block_info[gpe_block].register_count; i++) { + gpe_register_info = &acpi_gbl_gpe_register_info[gpe_register]; - register_index = 0; + /* Init the Register info for this entire GPE register (8 GPEs) */ - for (i = 0; i < gpe0register_count; i++) { - acpi_gbl_gpe_registers[register_index].status_addr = - (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + i); + gpe_register_info->base_gpe_number = (u8) (acpi_gbl_gpe_block_info[gpe_block].block_base_number + + (ACPI_MUL_8 (i))); - acpi_gbl_gpe_registers[register_index].enable_addr = - (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + i + gpe0register_count); + ACPI_STORE_ADDRESS (gpe_register_info->status_address.address, + (ACPI_GET_ADDRESS (acpi_gbl_gpe_block_info[gpe_block].block_address->address) + + i)); - acpi_gbl_gpe_registers[register_index].gpe_base = (u8) MUL_8 (i); + ACPI_STORE_ADDRESS (gpe_register_info->enable_address.address, + (ACPI_GET_ADDRESS (acpi_gbl_gpe_block_info[gpe_block].block_address->address) + + i + + acpi_gbl_gpe_block_info[gpe_block].register_count)); - for (j = 0; j < 8; j++) { - gpe_number = acpi_gbl_gpe_registers[register_index].gpe_base + j; - acpi_gbl_gpe_valid[gpe_number] = (u8) register_index; - } + gpe_register_info->status_address.address_space_id = acpi_gbl_gpe_block_info[gpe_block].address_space_id; + gpe_register_info->enable_address.address_space_id = acpi_gbl_gpe_block_info[gpe_block].address_space_id; + gpe_register_info->status_address.register_bit_width = 8; + gpe_register_info->enable_address.register_bit_width = 8; + gpe_register_info->status_address.register_bit_offset = 8; + gpe_register_info->enable_address.register_bit_offset = 8; - /* - * Clear the status/enable registers. Note that status registers - * are cleared by writing a '1', while enable registers are cleared - * by writing a '0'. - */ - acpi_os_write_port (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00, 8); - acpi_os_write_port (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF, 8); + /* Init the Index mapping info for each GPE number within this register */ - register_index++; - } + for (j = 0; j < 8; j++) { + gpe_number = gpe_register_info->base_gpe_number + j; + acpi_gbl_gpe_number_to_index[gpe_number].number_index = (u8) gpe_number_index; - /* GPE Block 1 */ + acpi_gbl_gpe_number_info[gpe_number_index].bit_mask = acpi_gbl_decode_to8bit[j]; + gpe_number_index++; + } - for (i = 0; i < gpe1_register_count; i++) { - acpi_gbl_gpe_registers[register_index].status_addr = - (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + i); + /* + * Clear the status/enable registers. Note that status registers + * are cleared by writing a '1', while enable registers are cleared + * by writing a '0'. + */ - acpi_gbl_gpe_registers[register_index].enable_addr = - (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + i + gpe1_register_count); + status = acpi_hw_low_level_write (8, 0x00, &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_gbl_gpe_registers[register_index].gpe_base = - (u8) (acpi_gbl_FADT->gpe1_base + MUL_8 (i)); + status = acpi_hw_low_level_write (8, 0xFF, &gpe_register_info->status_address, 0); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - for (j = 0; j < 8; j++) { - gpe_number = acpi_gbl_gpe_registers[register_index].gpe_base + j; - acpi_gbl_gpe_valid[gpe_number] = (u8) register_index; + gpe_register++; } - /* - * Clear the status/enable registers. Note that status registers - * are cleared by writing a '1', while enable registers are cleared - * by writing a '0'. - */ - acpi_os_write_port (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00, 8); - acpi_os_write_port (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF, 8); - - register_index++; + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "GPE Block%d: %X registers at %8.8X%8.8X\n", + (s32) gpe_block, acpi_gbl_gpe_block_info[0].register_count, + ACPI_HIDWORD (ACPI_GET_ADDRESS (acpi_gbl_gpe_block_info[gpe_block].block_address->address)), + ACPI_LODWORD (ACPI_GET_ADDRESS (acpi_gbl_gpe_block_info[gpe_block].block_address->address)))); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "GPE Block%d Range GPE #%2.2X to GPE #%2.2X\n", + (s32) gpe_block, + acpi_gbl_gpe_block_info[gpe_block].block_base_number, + acpi_gbl_gpe_block_info[gpe_block].block_base_number + + ((acpi_gbl_gpe_block_info[gpe_block].register_count * 8) -1))); } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "GPE registers: %X@%8.8X%8.8X (Blk0) %X@%8.8X%8.8X (Blk1)\n", - gpe0register_count, HIDWORD(acpi_gbl_FADT->Xgpe0blk.address), LODWORD(acpi_gbl_FADT->Xgpe0blk.address), - gpe1_register_count, HIDWORD(acpi_gbl_FADT->Xgpe1_blk.address), LODWORD(acpi_gbl_FADT->Xgpe1_blk.address))); - return_ACPI_STATUS (AE_OK); + + + /* Error cleanup */ + +error_exit2: + ACPI_MEM_FREE (acpi_gbl_gpe_register_info); + +error_exit1: + ACPI_MEM_FREE (acpi_gbl_gpe_number_to_index); + return_ACPI_STATUS (AE_NO_MEMORY); } @@ -468,7 +534,7 @@ * Where: * L - means that the GPE is level triggered * E - means that the GPE is edge triggered - * nn - is the GPE number + * nn - is the GPE number [in HEX] * ******************************************************************************/ @@ -480,28 +546,34 @@ void **return_value) { u32 gpe_number; + u32 gpe_number_index; NATIVE_CHAR name[ACPI_NAME_SIZE + 1]; u8 type; + acpi_status status; - PROC_NAME ("Ev_save_method_info"); + ACPI_FUNCTION_NAME ("Ev_save_method_info"); /* Extract the name from the object and convert to a string */ - MOVE_UNALIGNED32_TO_32 (name, &((acpi_namespace_node *) obj_handle)->name); + ACPI_MOVE_UNALIGNED32_TO_32 (name, + &((acpi_namespace_node *) obj_handle)->name.integer); name[ACPI_NAME_SIZE] = 0; /* - * Edge/Level determination is based on the 2nd s8 of the method name + * Edge/Level determination is based on the 2nd character of the method name */ - if (name[1] == 'L') { + switch (name[1]) { + case 'L': type = ACPI_EVENT_LEVEL_TRIGGERED; - } - else if (name[1] == 'E') { + break; + + case 'E': type = ACPI_EVENT_EDGE_TRIGGERED; - } - else { + break; + + default: /* Unknown method type, just ignore it! */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -510,9 +582,9 @@ return (AE_OK); } - /* Convert the last two characters of the name to the Gpe Number */ + /* Convert the last two characters of the name to the GPE Number */ - gpe_number = STRTOUL (&name[2], NULL, 16); + gpe_number = ACPI_STRTOUL (&name[2], NULL, 16); if (gpe_number == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ @@ -522,9 +594,10 @@ return (AE_OK); } - /* Ensure that we have a valid GPE number */ + /* Get GPE index and ensure that we have a valid GPE number */ - if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { + gpe_number_index = acpi_ev_get_gpe_number_index (gpe_number); + if (gpe_number_index == ACPI_GPE_INVALID) { /* Not valid, all we can do here is ignore it */ return (AE_OK); @@ -534,14 +607,16 @@ * Now we can add this information to the Gpe_info block * for use during dispatch of this GPE. */ - acpi_gbl_gpe_info [gpe_number].type = type; - acpi_gbl_gpe_info [gpe_number].method_handle = obj_handle; - + acpi_gbl_gpe_number_info [gpe_number_index].type = type; + acpi_gbl_gpe_number_info [gpe_number_index].method_handle = obj_handle; /* * Enable the GPE (SCIs should be disabled at this point) */ - acpi_hw_enable_gpe (gpe_number); + status = acpi_hw_enable_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + return (status); + } ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Registered GPE method %s as GPE number %X\n", name, gpe_number)); @@ -555,10 +630,9 @@ * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Obtain the control methods associated with the GPEs. - * * NOTE: Must be called AFTER namespace initialization! * ******************************************************************************/ @@ -569,7 +643,7 @@ acpi_status status; - FUNCTION_TRACE ("Ev_init_gpe_control_methods"); + ACPI_FUNCTION_TRACE ("Ev_init_gpe_control_methods"); /* Get a permanent handle to the _GPE object */ @@ -597,21 +671,25 @@ * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Detect if any GP events have occurred + * DESCRIPTION: Detect if any GP events have occurred. This function is + * executed at interrupt level. * ******************************************************************************/ u32 acpi_ev_gpe_detect (void) { - u32 int_status = INTERRUPT_NOT_HANDLED; + u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u32 i; u32 j; u8 enabled_status_byte; u8 bit_mask; + ACPI_GPE_REGISTER_INFO *gpe_register_info; + u32 in_value; + acpi_status status; - PROC_NAME ("Ev_gpe_detect"); + ACPI_FUNCTION_NAME ("Ev_gpe_detect"); /* @@ -620,23 +698,31 @@ * Find all currently active GP events. */ for (i = 0; i < acpi_gbl_gpe_register_count; i++) { - acpi_os_read_port (acpi_gbl_gpe_registers[i].status_addr, - &acpi_gbl_gpe_registers[i].status, 8); + gpe_register_info = &acpi_gbl_gpe_register_info[i]; + + status = acpi_hw_low_level_read (8, &in_value, &gpe_register_info->status_address, 0); + gpe_register_info->status = (u8) in_value; + if (ACPI_FAILURE (status)) { + return (ACPI_INTERRUPT_NOT_HANDLED); + } - acpi_os_read_port (acpi_gbl_gpe_registers[i].enable_addr, - &acpi_gbl_gpe_registers[i].enable, 8); + status = acpi_hw_low_level_read (8, &in_value, &gpe_register_info->enable_address, 0); + gpe_register_info->enable = (u8) in_value; + if (ACPI_FAILURE (status)) { + return (ACPI_INTERRUPT_NOT_HANDLED); + } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, - "GPE block at %X - Enable %08X Status %08X\n", - acpi_gbl_gpe_registers[i].enable_addr, - acpi_gbl_gpe_registers[i].status, - acpi_gbl_gpe_registers[i].enable)); + "GPE block at %8.8X%8.8X - Values: Enable %02X Status %02X\n", + ACPI_HIDWORD (ACPI_GET_ADDRESS (gpe_register_info->enable_address.address)), + ACPI_LODWORD (ACPI_GET_ADDRESS (gpe_register_info->enable_address.address)), + gpe_register_info->enable, + gpe_register_info->status)); /* First check if there is anything active at all in this register */ - enabled_status_byte = (u8) (acpi_gbl_gpe_registers[i].status & - acpi_gbl_gpe_registers[i].enable); - + enabled_status_byte = (u8) (gpe_register_info->status & + gpe_register_info->enable); if (!enabled_status_byte) { /* No active GPEs in this register, move on */ @@ -654,7 +740,7 @@ * or method. */ int_status |= acpi_ev_gpe_dispatch ( - acpi_gbl_gpe_registers[i].gpe_base + j); + gpe_register_info->base_gpe_number + j); } } } @@ -667,7 +753,7 @@ * * FUNCTION: Acpi_ev_asynch_execute_gpe_method * - * PARAMETERS: Gpe_number - The 0-based Gpe number + * PARAMETERS: Gpe_number - The 0-based GPE number * * RETURN: None * @@ -679,46 +765,66 @@ * ******************************************************************************/ -static void +static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method ( void *context) { - u32 gpe_number = (u32) context; - acpi_gpe_level_info gpe_info; + u32 gpe_number = (u32) ACPI_TO_INTEGER (context); + u32 gpe_number_index; + ACPI_GPE_NUMBER_INFO gpe_info; + acpi_status status; - FUNCTION_TRACE ("Ev_asynch_execute_gpe_method"); + ACPI_FUNCTION_TRACE ("Ev_asynch_execute_gpe_method"); - /* - * Take a snapshot of the GPE info for this level - */ - acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); - gpe_info = acpi_gbl_gpe_info [gpe_number]; - acpi_ut_release_mutex (ACPI_MTX_EVENTS); + + gpe_number_index = acpi_ev_get_gpe_number_index (gpe_number); + if (gpe_number_index == ACPI_GPE_INVALID) { + return_VOID; + } /* - * Method Handler (_Lxx, _Exx): - * ---------------------------- - * Evaluate the _Lxx/_Exx control method that corresponds to this GPE. + * Take a snapshot of the GPE info for this level - we copy the + * info to prevent a race condition with Remove_handler. */ + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_VOID; + } + + gpe_info = acpi_gbl_gpe_number_info [gpe_number_index]; + status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_VOID; + } + if (gpe_info.method_handle) { - acpi_ns_evaluate_by_handle (gpe_info.method_handle, NULL, NULL); + /* + * Invoke the GPE Method (_Lxx, _Exx): + * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) + */ + status = acpi_ns_evaluate_by_handle (gpe_info.method_handle, NULL, NULL); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("%s while evaluated GPE%X method\n", + acpi_format_exception (status), gpe_number)); + } } - /* - * Level-Triggered? - * ---------------- - * If level-triggered we clear the GPE status bit after handling the event. - */ if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) { - acpi_hw_clear_gpe (gpe_number); + /* + * GPE is level-triggered, we clear the GPE status bit after handling + * the event. + */ + status = acpi_hw_clear_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + return_VOID; + } } /* * Enable the GPE. */ - acpi_hw_enable_gpe (gpe_number); - + (void) acpi_hw_enable_gpe (gpe_number); return_VOID; } @@ -727,18 +833,13 @@ * * FUNCTION: Acpi_ev_gpe_dispatch * - * PARAMETERS: Gpe_number - The 0-based Gpe number + * PARAMETERS: Gpe_number - The 0-based GPE number * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Handle and dispatch a General Purpose Acpi_event. - * Clears the status bit for the requested event. - * - * TBD: [Investigate] is this still valid or necessary: - * The Gpe handler differs from the fixed events in that it clears the enable - * bit rather than the status bit to clear the interrupt. This allows - * software outside of interrupt context to determine what caused the SCI and - * dispatch the correct AML. + * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) + * or method (e.g. _Lxx/_Exx) handler. This function executes + * at interrupt level. * ******************************************************************************/ @@ -746,82 +847,96 @@ acpi_ev_gpe_dispatch ( u32 gpe_number) { - acpi_gpe_level_info gpe_info; + u32 gpe_number_index; + ACPI_GPE_NUMBER_INFO *gpe_info; + acpi_status status; - FUNCTION_TRACE ("Ev_gpe_dispatch"); + ACPI_FUNCTION_TRACE ("Ev_gpe_dispatch"); - /* - * Valid GPE number? - */ - if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid GPE bit [%X].\n", gpe_number)); - return_VALUE (INTERRUPT_NOT_HANDLED); + gpe_number_index = acpi_ev_get_gpe_number_index (gpe_number); + if (gpe_number_index == ACPI_GPE_INVALID) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid event, GPE[%X].\n", gpe_number)); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } /* - * Disable the GPE. + * We don't have to worry about mutex on Gpe_info because we are + * executing at interrupt level. */ - acpi_hw_disable_gpe (gpe_number); - - gpe_info = acpi_gbl_gpe_info [gpe_number]; + gpe_info = &acpi_gbl_gpe_number_info [gpe_number_index]; /* - * Edge-Triggered? - * --------------- * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ - if (gpe_info.type & ACPI_EVENT_EDGE_TRIGGERED) { - acpi_hw_clear_gpe (gpe_number); + if (gpe_info->type & ACPI_EVENT_EDGE_TRIGGERED) { + status = acpi_hw_clear_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to clear GPE[%X]\n", gpe_number)); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); + } } - /* - * Function Handler (e.g. EC)? - */ - if (gpe_info.handler) { - /* Invoke function handler (at interrupt level). */ - - gpe_info.handler (gpe_info.context); - /* Level-Triggered? */ + /* + * Dispatch the GPE to either an installed handler, or the control + * method associated with this GPE (_Lxx or _Exx). + * If a handler exists, we invoke it and do not attempt to run the method. + * If there is neither a handler nor a method, we disable the level to + * prevent further events from coming in here. + */ + if (gpe_info->handler) { + /* Invoke the installed handler (at interrupt level) */ - if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) { - acpi_hw_clear_gpe (gpe_number); + gpe_info->handler (gpe_info->context); + } + else if (gpe_info->method_handle) { + /* + * Disable GPE, so it doesn't keep firing before the method has a + * chance to run. + */ + status = acpi_hw_disable_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to disable GPE[%X]\n", gpe_number)); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } - /* Enable GPE */ - - acpi_hw_enable_gpe (gpe_number); + /* + * Execute the method associated with the GPE. + */ + if (ACPI_FAILURE (acpi_os_queue_for_execution (OSD_PRIORITY_GPE, + acpi_ev_asynch_execute_gpe_method, + ACPI_TO_POINTER (gpe_number)))) { + ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%X], event is disabled\n", gpe_number)); + } } + else { + /* No handler or method to run! */ - /* - * Method Handler (e.g. _Exx/_Lxx)? - */ - else if (gpe_info.method_handle) { - if (ACPI_FAILURE(acpi_os_queue_for_execution (OSD_PRIORITY_GPE, - acpi_ev_asynch_execute_gpe_method, (void*) gpe_number))) { - /* - * Shoudn't occur, but if it does report an error. Note that - * the GPE will remain disabled until the ACPI Core Subsystem - * is restarted, or the handler is removed/reinstalled. - */ - REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to queue handler for GPE bit [%X]\n", gpe_number)); + ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: No handler or method for GPE[%X], disabling event\n", gpe_number)); + + /* + * Disable the GPE. The GPE will remain disabled until the ACPI + * Core Subsystem is restarted, or the handler is reinstalled. + */ + status = acpi_hw_disable_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to disable GPE[%X]\n", gpe_number)); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } } /* - * No Handler? Report an error and leave the GPE disabled. + * It is now safe to clear level-triggered evnets. */ - else { - REPORT_ERROR (("Acpi_ev_gpe_dispatch: No installed handler for GPE [%X]\n", gpe_number)); - - /* Level-Triggered? */ - - if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) { - acpi_hw_clear_gpe (gpe_number); + if (gpe_info->type & ACPI_EVENT_LEVEL_TRIGGERED) { + status = acpi_hw_clear_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to clear GPE[%X]\n", gpe_number)); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } } - return_VALUE (INTERRUPT_HANDLED); + return_VALUE (ACPI_INTERRUPT_HANDLED); } diff -Nur linux-2.4.19/drivers/acpi/events/evmisc.c linux-2.4.19-sgi211r3/drivers/acpi/events/evmisc.c --- linux-2.4.19/drivers/acpi/events/evmisc.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evmisc.c Tue Aug 27 19:53:13 2002 @@ -1,13 +1,12 @@ /****************************************************************************** * - * Module Name: evmisc - ACPI device notification handler dispatch - * and ACPI Global Lock support - * $Revision: 35 $ + * Module Name: evmisc - Miscellaneous event manager support functions + * $Revision: 53 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,10 +27,95 @@ #include "acevents.h" #include "acnamesp.h" #include "acinterp.h" -#include "achware.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evmisc") + ACPI_MODULE_NAME ("evmisc") + + +/******************************************************************************* + * + * FUNCTION: Acpi_ev_is_notify_object + * + * PARAMETERS: Node - Node to check + * + * RETURN: TRUE if notifies allowed on this object + * + * DESCRIPTION: Check type of node for a object that supports notifies. + * + * TBD: This could be replaced by a flag bit in the node. + * + ******************************************************************************/ + +u8 +acpi_ev_is_notify_object ( + acpi_namespace_node *node) +{ + switch (node->type) { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + case ACPI_TYPE_THERMAL: + /* + * These are the ONLY objects that can receive ACPI notifications + */ + return (TRUE); + + default: + return (FALSE); + } +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ev_get_gpe_register_index + * + * PARAMETERS: Gpe_number - Raw GPE number + * + * RETURN: None. + * + * DESCRIPTION: Returns the register index (index into the GPE register info + * table) associated with this GPE. + * + ******************************************************************************/ + +u32 +acpi_ev_get_gpe_register_index ( + u32 gpe_number) +{ + + if (gpe_number > acpi_gbl_gpe_number_max) { + return (ACPI_GPE_INVALID); + } + + return (ACPI_DIV_8 (acpi_gbl_gpe_number_to_index[gpe_number].number_index)); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ev_get_gpe_number_index + * + * PARAMETERS: Gpe_number - Raw GPE number + * + * RETURN: None. + * + * DESCRIPTION: Returns the number index (index into the GPE number info table) + * associated with this GPE. + * + ******************************************************************************/ + +u32 +acpi_ev_get_gpe_number_index ( + u32 gpe_number) +{ + + if (gpe_number > acpi_gbl_gpe_number_max) { + return (ACPI_GPE_INVALID); + } + + return (acpi_gbl_gpe_number_to_index[gpe_number].number_index); +} /******************************************************************************* @@ -58,7 +142,7 @@ acpi_status status = AE_OK; - PROC_NAME ("Ev_queue_notify_request"); + ACPI_FUNCTION_NAME ("Ev_queue_notify_request"); /* @@ -92,43 +176,38 @@ break; } - /* - * Get the notify object attached to the device Node + * Get the notify object attached to the NS Node */ obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { - /* We have the notify object, Get the right handler */ switch (node->type) { case ACPI_TYPE_DEVICE: - if (notify_value <= MAX_SYS_NOTIFY) { - handler_obj = obj_desc->device.sys_handler; - } - else { - handler_obj = obj_desc->device.drv_handler; - } - break; - case ACPI_TYPE_THERMAL: - if (notify_value <= MAX_SYS_NOTIFY) { - handler_obj = obj_desc->thermal_zone.sys_handler; + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + + if (notify_value <= ACPI_MAX_SYS_NOTIFY) { + handler_obj = obj_desc->common_notify.sys_handler; } else { - handler_obj = obj_desc->thermal_zone.drv_handler; + handler_obj = obj_desc->common_notify.drv_handler; } break; + + default: + /* All other types are not supported */ + return (AE_TYPE); } } - /* If there is any handler to run, schedule the dispatcher */ - if ((acpi_gbl_sys_notify.handler && (notify_value <= MAX_SYS_NOTIFY)) || - (acpi_gbl_drv_notify.handler && (notify_value > MAX_SYS_NOTIFY)) || + if ((acpi_gbl_sys_notify.handler && (notify_value <= ACPI_MAX_SYS_NOTIFY)) || + (acpi_gbl_drv_notify.handler && (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) { - notify_info = acpi_ut_create_generic_state (); if (!notify_info) { return (AE_NO_MEMORY); @@ -169,7 +248,7 @@ * ******************************************************************************/ -void +void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch ( void *context) { @@ -179,14 +258,14 @@ acpi_operand_object *handler_obj; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* * We will invoke a global notify handler if installed. * This is done _before_ we invoke the per-device handler attached to the device. */ - if (notify_info->notify.value <= MAX_SYS_NOTIFY) { + if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) { /* Global system notification handler */ if (acpi_gbl_sys_notify.handler) { @@ -194,7 +273,6 @@ global_context = acpi_gbl_sys_notify.context; } } - else { /* Global driver notification handler */ @@ -204,7 +282,6 @@ } } - /* Invoke the system handler first, if present */ if (global_handler) { @@ -237,18 +314,23 @@ * ******************************************************************************/ -static void +static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread ( void *context) { + acpi_status status; + /* Signal threads that are waiting for the lock */ if (acpi_gbl_global_lock_thread_count) { /* Send sufficient units to the semaphore */ - acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore, + status = acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore, acpi_gbl_global_lock_thread_count); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not signal Global Lock semaphore\n")); + } } } @@ -270,7 +352,7 @@ void *context) { u8 acquired = FALSE; - void *global_lock; + acpi_status status; /* @@ -278,8 +360,7 @@ * If we don't get it now, it will be marked pending and we will * take another interrupt when it becomes free. */ - global_lock = acpi_gbl_FACS->global_lock; - ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, acquired); if (acquired) { /* Got the lock, now wake all threads waiting for it */ @@ -287,11 +368,17 @@ /* Run the Global Lock thread which will signal all waiting threads */ - acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, acpi_ev_global_lock_thread, - context); + status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, + acpi_ev_global_lock_thread, context); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not queue Global Lock thread, %s\n", + acpi_format_exception (status))); + + return (ACPI_INTERRUPT_NOT_HANDLED); + } } - return (INTERRUPT_HANDLED); + return (ACPI_INTERRUPT_HANDLED); } @@ -311,7 +398,7 @@ acpi_status status; - FUNCTION_TRACE ("Ev_init_global_lock_handler"); + ACPI_FUNCTION_TRACE ("Ev_init_global_lock_handler"); acpi_gbl_global_lock_present = TRUE; @@ -320,7 +407,7 @@ /* * If the global lock does not exist on this platform, the attempt - * to enable GBL_STS will fail (the GBL_EN bit will not stick) + * to enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick) * Map to AE_OK, but mark global lock as not present. * Any attempt to actually use the global lock will be flagged * with an error. @@ -345,14 +432,15 @@ *****************************************************************************/ acpi_status -acpi_ev_acquire_global_lock(void) +acpi_ev_acquire_global_lock ( + u32 timeout) { acpi_status status = AE_OK; u8 acquired = FALSE; - void *global_lock; - FUNCTION_TRACE ("Ev_acquire_global_lock"); + ACPI_FUNCTION_TRACE ("Ev_acquire_global_lock"); + /* Make sure that we actually have a global lock */ @@ -364,46 +452,36 @@ acpi_gbl_global_lock_thread_count++; - - /* If we (OS side) have the hardware lock already, we are done */ + /* If we (OS side vs. BIOS side) have the hardware lock already, we are done */ if (acpi_gbl_global_lock_acquired) { return_ACPI_STATUS (AE_OK); } - /* Only if the FACS is valid */ - - if (!acpi_gbl_FACS) { - return_ACPI_STATUS (AE_OK); - } - - /* We must acquire the actual hardware lock */ - global_lock = acpi_gbl_FACS->global_lock; - ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, acquired); if (acquired) { /* We got the lock */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Acquired the Global Lock\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Acquired the HW Global Lock\n")); acpi_gbl_global_lock_acquired = TRUE; return_ACPI_STATUS (AE_OK); } - /* * Did not get the lock. The pending bit was set above, and we must now * wait until we get the global lock released interrupt. */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Waiting for the HW Global Lock\n")); - /* - * Acquire the global lock semaphore first. - * Since this wait will block, we must release the interpreter - */ + /* + * Acquire the global lock semaphore first. + * Since this wait will block, we must release the interpreter + */ status = acpi_ex_system_wait_semaphore (acpi_gbl_global_lock_semaphore, - ACPI_UINT32_MAX); + timeout); return_ACPI_STATUS (status); } @@ -416,45 +494,86 @@ * ******************************************************************************/ -void +acpi_status acpi_ev_release_global_lock (void) { u8 pending = FALSE; - void *global_lock; + acpi_status status = AE_OK; - FUNCTION_TRACE ("Ev_release_global_lock"); + ACPI_FUNCTION_TRACE ("Ev_release_global_lock"); if (!acpi_gbl_global_lock_thread_count) { - REPORT_WARNING(("Global Lock has not be acquired, cannot release\n")); - return_VOID; + ACPI_REPORT_WARNING(("Cannot release HW Global Lock, it has not been acquired\n")); + return_ACPI_STATUS (AE_NOT_ACQUIRED); } - /* One fewer thread has the global lock */ + /* One fewer thread has the global lock */ acpi_gbl_global_lock_thread_count--; + if (acpi_gbl_global_lock_thread_count) { + /* There are still some threads holding the lock, cannot release */ - /* Have all threads released the lock? */ + return_ACPI_STATUS (AE_OK); + } - if (!acpi_gbl_global_lock_thread_count) { - /* - * No more threads holding lock, we can do the actual hardware - * release - */ - global_lock = acpi_gbl_FACS->global_lock; - ACPI_RELEASE_GLOBAL_LOCK (global_lock, pending); - acpi_gbl_global_lock_acquired = FALSE; + /* + * No more threads holding lock, we can do the actual hardware + * release + */ + ACPI_RELEASE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, pending); + acpi_gbl_global_lock_acquired = FALSE; - /* - * If the pending bit was set, we must write GBL_RLS to the control - * register - */ - if (pending) { - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, - GBL_RLS, 1); - } + /* + * If the pending bit was set, we must write GBL_RLS to the control + * register + */ + if (pending) { + status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, 1, ACPI_MTX_LOCK); + } + + return_ACPI_STATUS (status); +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_ev_terminate + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: free memory allocated for table storage. + * + ******************************************************************************/ + +void +acpi_ev_terminate (void) +{ + + ACPI_FUNCTION_TRACE ("Ev_terminate"); + + + /* + * Free global tables, etc. + */ + if (acpi_gbl_gpe_register_info) { + ACPI_MEM_FREE (acpi_gbl_gpe_register_info); + acpi_gbl_gpe_register_info = NULL; + } + + if (acpi_gbl_gpe_number_info) { + ACPI_MEM_FREE (acpi_gbl_gpe_number_info); + acpi_gbl_gpe_number_info = NULL; + } + + if (acpi_gbl_gpe_number_to_index) { + ACPI_MEM_FREE (acpi_gbl_gpe_number_to_index); + acpi_gbl_gpe_number_to_index = NULL; } return_VOID; } + diff -Nur linux-2.4.19/drivers/acpi/events/evregion.c linux-2.4.19-sgi211r3/drivers/acpi/events/evregion.c --- linux-2.4.19/drivers/acpi/events/evregion.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evregion.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch - * $Revision: 113 $ + * $Revision: 133 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,15 +28,14 @@ #include "acevents.h" #include "acnamesp.h" #include "acinterp.h" -#include "amlcode.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evregion") + ACPI_MODULE_NAME ("evregion") /******************************************************************************* * - * FUNCTION: Acpi_ev_install_default_address_space_handlers + * FUNCTION: Acpi_ev_init_address_spaces * * PARAMETERS: * @@ -47,13 +46,13 @@ ******************************************************************************/ acpi_status -acpi_ev_install_default_address_space_handlers ( +acpi_ev_init_address_spaces ( void) { acpi_status status; - FUNCTION_TRACE ("Ev_install_default_address_space_handlers"); + ACPI_FUNCTION_TRACE ("Ev_init_address_spaces"); /* @@ -68,40 +67,46 @@ * space must be always available -- even though we are nowhere * near ready to find the PCI root buses at this point. * - * NOTE: We ignore AE_EXIST because this means that a handler has - * already been installed (via Acpi_install_address_space_handler) + * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler + * has already been installed (via Acpi_install_address_space_handler) */ - status = acpi_install_address_space_handler (acpi_gbl_root_node, + + status = acpi_install_address_space_handler ((acpi_handle) acpi_gbl_root_node, ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); if ((ACPI_FAILURE (status)) && - (status != AE_EXIST)) { + (status != AE_ALREADY_EXISTS)) { return_ACPI_STATUS (status); } - status = acpi_install_address_space_handler (acpi_gbl_root_node, + status = acpi_install_address_space_handler ((acpi_handle) acpi_gbl_root_node, ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL); if ((ACPI_FAILURE (status)) && - (status != AE_EXIST)) { + (status != AE_ALREADY_EXISTS)) { return_ACPI_STATUS (status); } - status = acpi_install_address_space_handler (acpi_gbl_root_node, + status = acpi_install_address_space_handler ((acpi_handle) acpi_gbl_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if ((ACPI_FAILURE (status)) && - (status != AE_EXIST)) { + (status != AE_ALREADY_EXISTS)) { return_ACPI_STATUS (status); } + status = acpi_install_address_space_handler ((acpi_handle) acpi_gbl_root_node, + ACPI_ADR_SPACE_DATA_TABLE, + ACPI_DEFAULT_HANDLER, NULL, NULL); + if ((ACPI_FAILURE (status)) && + (status != AE_ALREADY_EXISTS)) { + return_ACPI_STATUS (status); + } return_ACPI_STATUS (AE_OK); } -/* TBD: [Restructure] Move elsewhere */ - /******************************************************************************* * * FUNCTION: Acpi_ev_execute_reg_method @@ -121,13 +126,19 @@ u32 function) { acpi_operand_object *params[3]; + acpi_operand_object *region_obj2; acpi_status status; - FUNCTION_TRACE ("Ev_execute_reg_method"); + ACPI_FUNCTION_TRACE ("Ev_execute_reg_method"); - if (region_obj->region.extra->extra.method_REG == NULL) { + region_obj2 = acpi_ns_get_secondary_object (region_obj); + if (!region_obj2) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + if (region_obj2->extra.method_REG == NULL) { return_ACPI_STATUS (AE_OK); } @@ -154,15 +165,15 @@ /* * Set up the parameter objects */ - params[0]->integer.value = region_obj->region.space_id; + params[0]->integer.value = region_obj->region.space_id; params[1]->integer.value = function; params[2] = NULL; /* * Execute the method, no return value */ - DEBUG_EXEC(acpi_ut_display_init_pathname (region_obj->region.extra->extra.method_REG, " [Method]")); - status = acpi_ns_evaluate_by_handle (region_obj->region.extra->extra.method_REG, params, NULL); + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (region_obj2->extra.method_REG, " [Method]")); + status = acpi_ns_evaluate_by_handle (region_obj2->extra.method_REG, params, NULL); acpi_ut_remove_reference (params[1]); @@ -181,7 +192,7 @@ * Space_id - ID of the address space (0-255) * Function - Read or Write operation * Address - Where in the space to read or write - * Bit_width - Field width in bits (8, 16, or 32) + * Bit_width - Field width in bits (8, 16, 32, or 64) * Value - Pointer to in or out value * * RETURN: Status @@ -197,18 +208,25 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value) + void *value) { acpi_status status; + acpi_status status2; acpi_adr_space_handler handler; acpi_adr_space_setup region_setup; acpi_operand_object *handler_desc; + acpi_operand_object *region_obj2; void *region_context = NULL; - FUNCTION_TRACE ("Ev_address_space_dispatch"); + ACPI_FUNCTION_TRACE ("Ev_address_space_dispatch"); + region_obj2 = acpi_ns_get_secondary_object (region_obj); + if (!region_obj2) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + /* * Ensure that there is a handler associated with this region */ @@ -217,14 +235,14 @@ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "no handler for region(%p) [%s]\n", region_obj, acpi_ut_get_region_name (region_obj->region.space_id))); - return_ACPI_STATUS(AE_NOT_EXIST); + return_ACPI_STATUS (AE_NOT_EXIST); } /* * It may be the case that the region has never been initialized * Some types of regions require special init code */ - if (!(region_obj->region.flags & AOPOBJ_INITIALIZED)) { + if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { /* * This region has not been initialized yet, do it */ @@ -249,7 +267,10 @@ /* Re-enter the interpreter */ - acpi_ex_enter_interpreter (); + status2 = acpi_ex_enter_interpreter (); + if (ACPI_FAILURE (status2)) { + return_ACPI_STATUS (status2); + } /* * Init routine may fail @@ -258,16 +279,16 @@ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region Init: %s [%s]\n", acpi_format_exception (status), acpi_ut_get_region_name (region_obj->region.space_id))); - return_ACPI_STATUS(status); + return_ACPI_STATUS (status); } - region_obj->region.flags |= AOPOBJ_INITIALIZED; + region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; /* * Save the returned context for use in all accesses to * this particular region. */ - region_obj->region.extra->extra.region_context = region_context; + region_obj2->extra.region_context = region_context; } /* @@ -277,10 +298,10 @@ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Addrhandler %p (%p), Address %8.8X%8.8X\n", - ®ion_obj->region.addr_handler->addr_handler, handler, HIDWORD(address), - LODWORD(address))); + ®ion_obj->region.addr_handler->addr_handler, handler, + ACPI_HIDWORD (address), ACPI_LODWORD (address))); - if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->addr_handler.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * For handlers other than the default (supplied) handlers, we must * exit the interpreter because the handler *might* block -- we don't @@ -294,20 +315,23 @@ */ status = handler (function, address, bit_width, value, handler_desc->addr_handler.context, - region_obj->region.extra->extra.region_context); + region_obj2->extra.region_context); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region handler: %s [%s]\n", - acpi_format_exception (status), - acpi_ut_get_region_name (region_obj->region.space_id))); + ACPI_REPORT_ERROR (("Handler for [%s] returned %s\n", + acpi_ut_get_region_name (region_obj->region.space_id), + acpi_format_exception (status))); } - if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->addr_handler.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * We just returned from a non-default handler, we must re-enter the * interpreter */ - acpi_ex_enter_interpreter (); + status2 = acpi_ex_enter_interpreter (); + if (ACPI_FAILURE (status2)) { + return_ACPI_STATUS (status2); + } } return_ACPI_STATUS (status); @@ -315,7 +339,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_ev_disassociate_region_from_handler + * FUNCTION: Acpi_ev_detach_region * * PARAMETERS: Region_obj - Region Object * Acpi_ns_is_locked - Namespace Region Already Locked? @@ -328,7 +352,7 @@ ******************************************************************************/ void -acpi_ev_disassociate_region_from_handler( +acpi_ev_detach_region( acpi_operand_object *region_obj, u8 acpi_ns_is_locked) { @@ -337,13 +361,18 @@ acpi_operand_object **last_obj_ptr; acpi_adr_space_setup region_setup; void *region_context; + acpi_operand_object *region_obj2; acpi_status status; - FUNCTION_TRACE ("Ev_disassociate_region_from_handler"); + ACPI_FUNCTION_TRACE ("Ev_detach_region"); - region_context = region_obj->region.extra->extra.region_context; + region_obj2 = acpi_ns_get_secondary_object (region_obj); + if (!region_obj2) { + return_VOID; + } + region_context = region_obj2->extra.region_context; /* * Get the address handler from the region object @@ -378,16 +407,27 @@ obj_desc->region.next = NULL; /* Must clear field */ if (acpi_ns_is_locked) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_VOID; + } } /* * Now stop region accesses by executing the _REG method */ - acpi_ev_execute_reg_method (region_obj, 0); + status = acpi_ev_execute_reg_method (region_obj, 0); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s from region _REG, [%s]\n", + acpi_format_exception (status), + acpi_ut_get_region_name (region_obj->region.space_id))); + } if (acpi_ns_is_locked) { - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_VOID; + } } /* @@ -406,7 +446,7 @@ acpi_ut_get_region_name (region_obj->region.space_id))); } - region_obj->region.flags &= ~(AOPOBJ_INITIALIZED); + region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE); /* * Remove handler reference in the region @@ -444,7 +484,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_ev_associate_region_and_handler + * FUNCTION: Acpi_ev_attach_region * * PARAMETERS: Handler_obj - Handler Object * Region_obj - Region Object @@ -458,15 +498,16 @@ ******************************************************************************/ acpi_status -acpi_ev_associate_region_and_handler ( +acpi_ev_attach_region ( acpi_operand_object *handler_obj, acpi_operand_object *region_obj, u8 acpi_ns_is_locked) { - acpi_status status; + acpi_status status; + acpi_status status2; - FUNCTION_TRACE ("Ev_associate_region_and_handler"); + ACPI_FUNCTION_TRACE ("Ev_attach_region"); ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, @@ -475,27 +516,34 @@ /* - * Link this region to the front of the handler's list + * Link this region to the front of the handler's list */ region_obj->region.next = handler_obj->addr_handler.region_list; handler_obj->addr_handler.region_list = region_obj; /* - * set the region's handler + * Set the region's handler */ region_obj->region.addr_handler = handler_obj; /* - * Last thing, tell all users that this region is usable + * Tell all users that this region is usable by running the _REG + * method */ if (acpi_ns_is_locked) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status2 = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status2)) { + return_ACPI_STATUS (status2); + } } status = acpi_ev_execute_reg_method (region_obj, 1); if (acpi_ns_is_locked) { - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status2 = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status2)) { + return_ACPI_STATUS (status2); + } } return_ACPI_STATUS (status); @@ -510,8 +558,8 @@ * Level - Nesting level of the handle * Context - Passed into Acpi_ns_walk_namespace * - * DESCRIPTION: This routine checks to see if the object is a Region if it - * is then the address handler is installed in it. + * DESCRIPTION: This routine installs an address handler into objects that are + * of type Region. * * If the Object is a Device, and the device has a handler of * the same type then the search is terminated in that branch. @@ -535,7 +583,7 @@ acpi_status status; - PROC_NAME ("Ev_addr_handler_helper"); + ACPI_FUNCTION_NAME ("Ev_addr_handler_helper"); handler_obj = (acpi_operand_object *) context; @@ -576,7 +624,7 @@ /* * Devices are handled different than regions */ - if (IS_THIS_OBJECT_TYPE (obj_desc, ACPI_TYPE_DEVICE)) { + if (obj_desc->common.type == ACPI_TYPE_DEVICE) { /* * See if this guy has any handlers */ @@ -635,12 +683,12 @@ * * First disconnect region for any previous handler (if any) */ - acpi_ev_disassociate_region_from_handler (obj_desc, FALSE); + acpi_ev_detach_region (obj_desc, FALSE); /* * Then connect the region to the new handler */ - status = acpi_ev_associate_region_and_handler (handler_obj, obj_desc, FALSE); + status = acpi_ev_attach_region (handler_obj, obj_desc, FALSE); return (status); } diff -Nur linux-2.4.19/drivers/acpi/events/evrgnini.c linux-2.4.19-sgi211r3/drivers/acpi/events/evrgnini.c --- linux-2.4.19/drivers/acpi/events/evrgnini.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evrgnini.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evrgnini- ACPI Address_space (Op_region) init - * $Revision: 48 $ + * $Revision: 61 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,11 +27,9 @@ #include "acpi.h" #include "acevents.h" #include "acnamesp.h" -#include "acinterp.h" -#include "amlcode.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evrgnini") + ACPI_MODULE_NAME ("evrgnini") /******************************************************************************* @@ -56,7 +54,10 @@ void *handler_context, void **region_context) { - FUNCTION_TRACE ("Ev_system_memory_region_setup"); + acpi_operand_object *region_desc = (acpi_operand_object *) handle; + acpi_mem_space_context *local_region_context; + + ACPI_FUNCTION_TRACE ("Ev_system_memory_region_setup"); if (function == ACPI_REGION_DEACTIVATE) { @@ -70,11 +71,17 @@ /* Activate. Create a new context */ - *region_context = ACPI_MEM_CALLOCATE (sizeof (acpi_mem_space_context)); - if (!(*region_context)) { + local_region_context = ACPI_MEM_CALLOCATE (sizeof (acpi_mem_space_context)); + if (!(local_region_context)) { return_ACPI_STATUS (AE_NO_MEMORY); } + /* Save the region length and address for use in the handler */ + + local_region_context->length = region_desc->region.length; + local_region_context->address = region_desc->region.address; + + *region_context = local_region_context; return_ACPI_STATUS (AE_OK); } @@ -101,7 +108,7 @@ void *handler_context, void **region_context) { - FUNCTION_TRACE ("Ev_io_space_region_setup"); + ACPI_FUNCTION_TRACE ("Ev_io_space_region_setup"); if (function == ACPI_REGION_DEACTIVATE) { @@ -148,7 +155,7 @@ acpi_device_id object_hID; - FUNCTION_TRACE ("Ev_pci_config_region_setup"); + ACPI_FUNCTION_TRACE ("Ev_pci_config_region_setup"); handler_obj = region_obj->region.addr_handler; @@ -188,7 +195,7 @@ * First get device and function numbers from the _ADR object * in the parent's scope. */ - node = acpi_ns_get_parent_object (region_obj->region.node); + node = acpi_ns_get_parent_node (region_obj->region.node); /* Acpi_evaluate the _ADR object */ @@ -196,12 +203,12 @@ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node, &temp); /* - * The default is zero, since the allocation above zeroed the data, just - * do nothing on failures. + * The default is zero, and since the allocation above zeroed + * the data, just do nothing on failure. */ if (ACPI_SUCCESS (status)) { - pci_id->device = HIWORD (temp); - pci_id->function = LOWORD (temp); + pci_id->device = ACPI_HIWORD (ACPI_LODWORD (temp)); + pci_id->function = ACPI_LOWORD (ACPI_LODWORD (temp)); } /* @@ -224,16 +231,20 @@ while (node != acpi_gbl_root_node) { status = acpi_ut_execute_HID (node, &object_hID); if (ACPI_SUCCESS (status)) { - if (!(STRNCMP (object_hID.buffer, PCI_ROOT_HID_STRING, + if (!(ACPI_STRNCMP (object_hID.buffer, PCI_ROOT_HID_STRING, sizeof (PCI_ROOT_HID_STRING)))) { - acpi_install_address_space_handler (node, + status = acpi_install_address_space_handler ((acpi_handle) node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not install handler for %4.4s, %s\n", + node->name.ascii, acpi_format_exception (status))); + } break; } } - node = acpi_ns_get_parent_object (node); + node = acpi_ns_get_parent_node (node); } } else { @@ -245,7 +256,7 @@ */ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__SEG, node, &temp); if (ACPI_SUCCESS (status)) { - pci_id->segment = LOWORD (temp); + pci_id->segment = ACPI_LOWORD (temp); } /* @@ -253,7 +264,7 @@ */ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__BBN, node, &temp); if (ACPI_SUCCESS (status)) { - pci_id->bus = LOWORD (temp); + pci_id->bus = ACPI_LOWORD (temp); } *region_context = pci_id; @@ -286,7 +297,7 @@ void **region_context) { - FUNCTION_TRACE ("Ev_pci_bar_region_setup"); + ACPI_FUNCTION_TRACE ("Ev_pci_bar_region_setup"); return_ACPI_STATUS (AE_OK); @@ -318,7 +329,7 @@ void **region_context) { - FUNCTION_TRACE ("Ev_cmos_region_setup"); + ACPI_FUNCTION_TRACE ("Ev_cmos_region_setup"); return_ACPI_STATUS (AE_OK); @@ -347,7 +358,7 @@ void *handler_context, void **region_context) { - FUNCTION_TRACE ("Ev_default_region_setup"); + ACPI_FUNCTION_TRACE ("Ev_default_region_setup"); if (function == ACPI_REGION_DEACTIVATE) { @@ -394,21 +405,33 @@ acpi_status status; acpi_namespace_node *method_node; acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; + acpi_operand_object *region_obj2; - FUNCTION_TRACE_U32 ("Ev_initialize_region", acpi_ns_locked); + ACPI_FUNCTION_TRACE_U32 ("Ev_initialize_region", acpi_ns_locked); if (!region_obj) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - node = acpi_ns_get_parent_object (region_obj->region.node); + if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { + return_ACPI_STATUS (AE_OK); + } + + region_obj2 = acpi_ns_get_secondary_object (region_obj); + if (!region_obj2) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + node = acpi_ns_get_parent_node (region_obj->region.node); + + space_id = region_obj->region.space_id; region_obj->region.addr_handler = NULL; - region_obj->region.extra->extra.method_REG = NULL; - region_obj->region.flags &= ~(AOPOBJ_INITIALIZED); + region_obj2->extra.method_REG = NULL; + region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); + region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; /* * Find any "_REG" associated with this region definition @@ -421,7 +444,7 @@ * definition. This will be executed when the handler is attached * or removed */ - region_obj->region.extra->extra.method_REG = method_node; + region_obj2->extra.method_REG = method_node; } /* @@ -436,7 +459,7 @@ obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { /* - * can only be a handler if the object exists + * Can only be a handler if the object exists */ switch (node->type) { case ACPI_TYPE_DEVICE: @@ -453,6 +476,10 @@ handler_obj = obj_desc->thermal_zone.addr_handler; break; + + default: + /* Ignore other objects */ + break; } while (handler_obj) { @@ -468,8 +495,9 @@ /* * Found it! Now update the region and the handler */ - acpi_ev_associate_region_and_handler (handler_obj, region_obj, - acpi_ns_locked); + status = acpi_ev_attach_region (handler_obj, region_obj, + acpi_ns_locked); + return_ACPI_STATUS (AE_OK); } @@ -482,7 +510,7 @@ * This one does not have the handler we need * Pop up one level */ - node = acpi_ns_get_parent_object (node); + node = acpi_ns_get_parent_node (node); } /* while Node != ROOT */ diff -Nur linux-2.4.19/drivers/acpi/events/evsci.c linux-2.4.19-sgi211r3/drivers/acpi/events/evsci.c --- linux-2.4.19/drivers/acpi/events/evsci.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evsci.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: evsci - System Control Interrupt configuration and * legacy to ACPI mode state transition functions - * $Revision: 74 $ + * $Revision: 86 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,23 +25,11 @@ */ #include "acpi.h" -#include "acnamesp.h" -#include "achware.h" #include "acevents.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evsci") - - -/* - * Elements correspond to counts for TMR, NOT_USED, GBL, PWR_BTN, SLP_BTN, RTC, - * and GENERAL respectively. These counts are modified by the ACPI interrupt - * handler. - * - * TBD: [Investigate] Note that GENERAL should probably be split out into - * one element for each bit in the GPE registers - */ + ACPI_MODULE_NAME ("evsci") /******************************************************************************* @@ -58,23 +46,31 @@ * ******************************************************************************/ -static u32 -acpi_ev_sci_handler (void *context) +static u32 ACPI_SYSTEM_XFACE +acpi_ev_sci_handler ( + void *context) { - u32 interrupt_handled = INTERRUPT_NOT_HANDLED; + u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; + u32 value; + acpi_status status; - FUNCTION_TRACE("Ev_sci_handler"); + ACPI_FUNCTION_TRACE("Ev_sci_handler"); /* * Make sure that ACPI is enabled by checking SCI_EN. Note that we are * required to treat the SCI interrupt as sharable, level, active low. */ - if (!acpi_hw_register_bit_access (ACPI_READ, ACPI_MTX_DO_NOT_LOCK, SCI_EN)) { + status = acpi_get_register (ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return (ACPI_INTERRUPT_NOT_HANDLED); + } + + if (!value) { /* ACPI is not enabled; this interrupt cannot be for us */ - return_VALUE (INTERRUPT_NOT_HANDLED); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } /* @@ -113,7 +109,7 @@ u32 status = AE_OK; - FUNCTION_TRACE ("Ev_install_sci_handler"); + ACPI_FUNCTION_TRACE ("Ev_install_sci_handler"); status = acpi_os_install_interrupt_handler ((u32) acpi_gbl_FADT->sci_int, @@ -123,7 +119,6 @@ /****************************************************************************** - * * FUNCTION: Acpi_ev_remove_sci_handler * @@ -132,151 +127,31 @@ * RETURN: E_OK if handler uninstalled OK, E_ERROR if handler was not * installed to begin with * - * DESCRIPTION: Restores original status of all fixed event enable bits and - * removes SCI handler. + * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be + * taken. + * + * Note: It doesn't seem important to disable all events or set the event + * enable registers to their original values. The OS should disable + * the SCI interrupt level when the handler is removed, so no more + * events will come in. * ******************************************************************************/ acpi_status acpi_ev_remove_sci_handler (void) { - FUNCTION_TRACE ("Ev_remove_sci_handler"); + acpi_status status; -#if 0 - /* TBD:[Investigate] Figure this out!! Disable all events first ??? */ - - if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (TMR_FIXED_EVENT)) { - acpi_event_disable_event (TMR_FIXED_EVENT); - } - - if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (GBL_FIXED_EVENT)) { - acpi_event_disable_event (GBL_FIXED_EVENT); - } - - if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (PWR_BTN_FIXED_EVENT)) { - acpi_event_disable_event (PWR_BTN_FIXED_EVENT); - } - - if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (SLP_BTN_FIXED_EVENT)) { - acpi_event_disable_event (SLP_BTN_FIXED_EVENT); - } - - if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (RTC_FIXED_EVENT)) { - acpi_event_disable_event (RTC_FIXED_EVENT); - } + ACPI_FUNCTION_TRACE ("Ev_remove_sci_handler"); - original_fixed_enable_bit_status = 0; -#endif + /* Just let the OS remove the handler and disable the level */ - acpi_os_remove_interrupt_handler ((u32) acpi_gbl_FADT->sci_int, + status = acpi_os_remove_interrupt_handler ((u32) acpi_gbl_FADT->sci_int, acpi_ev_sci_handler); - return_ACPI_STATUS (AE_OK); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ev_restore_acpi_state - * - * PARAMETERS: none - * - * RETURN: none - * - * DESCRIPTION: Restore the original ACPI state of the machine - * - ******************************************************************************/ - -void -acpi_ev_restore_acpi_state (void) -{ - u32 index; - - - FUNCTION_TRACE ("Ev_restore_acpi_state"); - - - /* Restore the state of the chipset enable bits. */ - - if (acpi_gbl_restore_acpi_chipset == TRUE) { - /* Restore the fixed events */ - - if (acpi_hw_register_read (ACPI_MTX_LOCK, PM1_EN) != - acpi_gbl_pm1_enable_register_save) { - acpi_hw_register_write (ACPI_MTX_LOCK, PM1_EN, - acpi_gbl_pm1_enable_register_save); - } - - - /* Ensure that all status bits are clear */ - - acpi_hw_clear_acpi_status (); - - - /* Now restore the GPEs */ - - for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe0blk_len); index++) { - if (acpi_hw_register_read (ACPI_MTX_LOCK, GPE0_EN_BLOCK | index) != - acpi_gbl_gpe0enable_register_save[index]) { - acpi_hw_register_write (ACPI_MTX_LOCK, GPE0_EN_BLOCK | index, - acpi_gbl_gpe0enable_register_save[index]); - } - } - - /* GPE 1 present? */ - - if (acpi_gbl_FADT->gpe1_blk_len) { - for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe1_blk_len); index++) { - if (acpi_hw_register_read (ACPI_MTX_LOCK, GPE1_EN_BLOCK | index) != - acpi_gbl_gpe1_enable_register_save[index]) { - acpi_hw_register_write (ACPI_MTX_LOCK, GPE1_EN_BLOCK | index, - acpi_gbl_gpe1_enable_register_save[index]); - } - } - } - - if (acpi_hw_get_mode() != acpi_gbl_original_mode) { - acpi_hw_set_mode (acpi_gbl_original_mode); - } - } - - return_VOID; -} - - -/****************************************************************************** - * - * FUNCTION: Acpi_ev_terminate - * - * PARAMETERS: none - * - * RETURN: none - * - * DESCRIPTION: free memory allocated for table storage. - * - ******************************************************************************/ - -void -acpi_ev_terminate (void) -{ - - FUNCTION_TRACE ("Ev_terminate"); - - - /* - * Free global tables, etc. - */ - if (acpi_gbl_gpe_registers) { - ACPI_MEM_FREE (acpi_gbl_gpe_registers); - } - - if (acpi_gbl_gpe_info) { - ACPI_MEM_FREE (acpi_gbl_gpe_info); - } - - return_VOID; + return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/events/evxface.c linux-2.4.19-sgi211r3/drivers/acpi/events/evxface.c --- linux-2.4.19/drivers/acpi/events/evxface.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evxface.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evxface - External interfaces for ACPI events - * $Revision: 116 $ + * $Revision: 128 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +25,12 @@ #include "acpi.h" -#include "achware.h" #include "acnamesp.h" #include "acevents.h" -#include "amlcode.h" #include "acinterp.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evxface") + ACPI_MODULE_NAME ("evxface") /******************************************************************************* @@ -60,7 +58,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_install_fixed_event_handler"); + ACPI_FUNCTION_TRACE ("Acpi_install_fixed_event_handler"); /* Parameter validation */ @@ -69,12 +67,15 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Don't allow two handlers. */ if (NULL != acpi_gbl_fixed_event_handlers[event].handler) { - status = AE_EXIST; + status = AE_ALREADY_EXISTS; goto cleanup; } @@ -85,7 +86,7 @@ acpi_gbl_fixed_event_handlers[event].context = context; status = acpi_enable_event (event, ACPI_EVENT_FIXED, 0); - if (!ACPI_SUCCESS (status)) { + if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not enable fixed event.\n")); /* Remove the handler */ @@ -93,7 +94,6 @@ acpi_gbl_fixed_event_handlers[event].handler = NULL; acpi_gbl_fixed_event_handlers[event].context = NULL; } - else { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Enabled fixed event %X, Handler=%p\n", event, handler)); @@ -101,7 +101,7 @@ cleanup: - acpi_ut_release_mutex (ACPI_MTX_EVENTS); + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); } @@ -127,7 +127,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Acpi_remove_fixed_event_handler"); + ACPI_FUNCTION_TRACE ("Acpi_remove_fixed_event_handler"); /* Parameter validation */ @@ -136,7 +136,10 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Disable the event before removing the handler */ @@ -147,7 +150,7 @@ acpi_gbl_fixed_event_handlers[event].handler = NULL; acpi_gbl_fixed_event_handlers[event].context = NULL; - if (!ACPI_SUCCESS (status)) { + if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not write to fixed event enable register.\n")); } @@ -155,7 +158,7 @@ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Disabled fixed event %X.\n", event)); } - acpi_ut_release_mutex (ACPI_MTX_EVENTS); + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); } @@ -186,26 +189,30 @@ { acpi_operand_object *obj_desc; acpi_operand_object *notify_obj; - acpi_namespace_node *device_node; - acpi_status status = AE_OK; + acpi_namespace_node *node; + acpi_status status; - FUNCTION_TRACE ("Acpi_install_notify_handler"); + ACPI_FUNCTION_TRACE ("Acpi_install_notify_handler"); /* Parameter validation */ - if ((!handler) || + if ((!device) || + (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Convert and validate the device handle */ - device_node = acpi_ns_map_handle_to_node (device); - if (!device_node) { + node = acpi_ns_map_handle_to_node (device); + if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -223,17 +230,17 @@ acpi_gbl_sys_notify.handler) || ((handler_type == ACPI_DEVICE_NOTIFY) && acpi_gbl_drv_notify.handler)) { - status = AE_EXIST; + status = AE_ALREADY_EXISTS; goto unlock_and_exit; } if (handler_type == ACPI_SYSTEM_NOTIFY) { - acpi_gbl_sys_notify.node = device_node; + acpi_gbl_sys_notify.node = node; acpi_gbl_sys_notify.handler = handler; acpi_gbl_sys_notify.context = context; } else /* ACPI_DEVICE_NOTIFY */ { - acpi_gbl_drv_notify.node = device_node; + acpi_gbl_drv_notify.node = node; acpi_gbl_drv_notify.handler = handler; acpi_gbl_drv_notify.context = context; } @@ -247,37 +254,32 @@ * Note that only certain object types can receive notifications. */ else { - /* - * These are the ONLY objects that can receive ACPI notifications - */ - if ((device_node->type != ACPI_TYPE_DEVICE) && - (device_node->type != ACPI_TYPE_PROCESSOR) && - (device_node->type != ACPI_TYPE_POWER) && - (device_node->type != ACPI_TYPE_THERMAL)) { - status = AE_BAD_PARAMETER; + /* Notifies allowed on this object? */ + + if (!acpi_ev_is_notify_object (node)) { + status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ - obj_desc = acpi_ns_get_attached_object (device_node); + obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { /* Object exists - make sure there's no handler */ if (((handler_type == ACPI_SYSTEM_NOTIFY) && - obj_desc->device.sys_handler) || + obj_desc->common_notify.sys_handler) || ((handler_type == ACPI_DEVICE_NOTIFY) && - obj_desc->device.drv_handler)) { - status = AE_EXIST; + obj_desc->common_notify.drv_handler)) { + status = AE_ALREADY_EXISTS; goto unlock_and_exit; } } - else { /* Create a new object */ - obj_desc = acpi_ut_create_internal_object (device_node->type); + obj_desc = acpi_ut_create_internal_object (node->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; @@ -285,7 +287,7 @@ /* Attach new object to the Node */ - status = acpi_ns_attach_object (device, obj_desc, (u8) device_node->type); + status = acpi_ns_attach_object (device, obj_desc, node->type); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -299,23 +301,21 @@ goto unlock_and_exit; } - notify_obj->notify_handler.node = device_node; + notify_obj->notify_handler.node = node; notify_obj->notify_handler.handler = handler; notify_obj->notify_handler.context = context; - if (handler_type == ACPI_SYSTEM_NOTIFY) { - obj_desc->device.sys_handler = notify_obj; + obj_desc->common_notify.sys_handler = notify_obj; } - else /* ACPI_DEVICE_NOTIFY */ { - obj_desc->device.drv_handler = notify_obj; + obj_desc->common_notify.drv_handler = notify_obj; } } unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } @@ -343,26 +343,30 @@ { acpi_operand_object *notify_obj; acpi_operand_object *obj_desc; - acpi_namespace_node *device_node; - acpi_status status = AE_OK; + acpi_namespace_node *node; + acpi_status status; - FUNCTION_TRACE ("Acpi_remove_notify_handler"); + ACPI_FUNCTION_TRACE ("Acpi_remove_notify_handler"); /* Parameter validation */ - if ((!handler) || + if ((!device) || + (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Convert and validate the device handle */ - device_node = acpi_ns_map_handle_to_node (device); - if (!device_node) { + node = acpi_ns_map_handle_to_node (device); + if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -397,20 +401,16 @@ * All Other Objects */ else { - /* - * These are the ONLY objects that can receive ACPI notifications - */ - if ((device_node->type != ACPI_TYPE_DEVICE) && - (device_node->type != ACPI_TYPE_PROCESSOR) && - (device_node->type != ACPI_TYPE_POWER) && - (device_node->type != ACPI_TYPE_THERMAL)) { - status = AE_BAD_PARAMETER; + /* Notifies allowed on this object? */ + + if (!acpi_ev_is_notify_object (node)) { + status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ - obj_desc = acpi_ns_get_attached_object (device_node); + obj_desc = acpi_ns_get_attached_object (node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; @@ -419,10 +419,10 @@ /* Object exists - make sure there's an existing handler */ if (handler_type == ACPI_SYSTEM_NOTIFY) { - notify_obj = obj_desc->device.sys_handler; + notify_obj = obj_desc->common_notify.sys_handler; } else { - notify_obj = obj_desc->device.drv_handler; + notify_obj = obj_desc->common_notify.drv_handler; } if ((!notify_obj) || @@ -434,10 +434,10 @@ /* Remove the handler */ if (handler_type == ACPI_SYSTEM_NOTIFY) { - obj_desc->device.sys_handler = NULL; + obj_desc->common_notify.sys_handler = NULL; } else { - obj_desc->device.drv_handler = NULL; + obj_desc->common_notify.drv_handler = NULL; } acpi_ut_remove_reference (notify_obj); @@ -445,7 +445,7 @@ unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } @@ -474,47 +474,56 @@ acpi_gpe_handler handler, void *context) { - acpi_status status = AE_OK; + acpi_status status; + u32 gpe_number_index; - FUNCTION_TRACE ("Acpi_install_gpe_handler"); + ACPI_FUNCTION_TRACE ("Acpi_install_gpe_handler"); /* Parameter validation */ - if (!handler || (gpe_number > ACPI_GPE_MAX)) { + if (!handler) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Ensure that we have a valid GPE number */ - if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { + gpe_number_index = acpi_ev_get_gpe_number_index (gpe_number); + if (gpe_number_index == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Make sure that there isn't a handler there already */ - if (acpi_gbl_gpe_info[gpe_number].handler) { - status = AE_EXIST; + if (acpi_gbl_gpe_number_info[gpe_number_index].handler) { + status = AE_ALREADY_EXISTS; goto cleanup; } /* Install the handler */ - acpi_gbl_gpe_info[gpe_number].handler = handler; - acpi_gbl_gpe_info[gpe_number].context = context; - acpi_gbl_gpe_info[gpe_number].type = (u8) type; + acpi_gbl_gpe_number_info[gpe_number_index].handler = handler; + acpi_gbl_gpe_number_info[gpe_number_index].context = context; + acpi_gbl_gpe_number_info[gpe_number_index].type = (u8) type; /* Clear the GPE (of stale events), the enable it */ - acpi_hw_clear_gpe (gpe_number); - acpi_hw_enable_gpe (gpe_number); + status = acpi_hw_clear_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_hw_enable_gpe (gpe_number); cleanup: - acpi_ut_release_mutex (ACPI_MTX_EVENTS); + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); } @@ -537,46 +546,54 @@ u32 gpe_number, acpi_gpe_handler handler) { - acpi_status status = AE_OK; + acpi_status status; + u32 gpe_number_index; - FUNCTION_TRACE ("Acpi_remove_gpe_handler"); + ACPI_FUNCTION_TRACE ("Acpi_remove_gpe_handler"); /* Parameter validation */ - if (!handler || (gpe_number > ACPI_GPE_MAX)) { + if (!handler) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Ensure that we have a valid GPE number */ - if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { + gpe_number_index = acpi_ev_get_gpe_number_index (gpe_number); + if (gpe_number_index == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Disable the GPE before removing the handler */ - acpi_hw_disable_gpe (gpe_number); + status = acpi_hw_disable_gpe (gpe_number); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Make sure that the installed handler is the same */ - if (acpi_gbl_gpe_info[gpe_number].handler != handler) { - acpi_hw_enable_gpe (gpe_number); + if (acpi_gbl_gpe_number_info[gpe_number_index].handler != handler) { + (void) acpi_hw_enable_gpe (gpe_number); status = AE_BAD_PARAMETER; goto cleanup; } /* Remove the handler */ - acpi_gbl_gpe_info[gpe_number].handler = NULL; - acpi_gbl_gpe_info[gpe_number].context = NULL; + acpi_gbl_gpe_number_info[gpe_number_index].handler = NULL; + acpi_gbl_gpe_number_info[gpe_number_index].context = NULL; cleanup: - acpi_ut_release_mutex (ACPI_MTX_EVENTS); + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); } @@ -596,23 +613,29 @@ acpi_status acpi_acquire_global_lock ( - void) + u32 timeout, + u32 *handle) { acpi_status status; + if (!handle) { + return (AE_BAD_PARAMETER); + } + status = acpi_ex_enter_interpreter (); if (ACPI_FAILURE (status)) { return (status); } - /* - * TBD: [Restructure] add timeout param to internal interface, and - * perhaps INTERPRETER_LOCKED - */ - status = acpi_ev_acquire_global_lock (); + status = acpi_ev_acquire_global_lock (timeout); acpi_ex_exit_interpreter (); + if (ACPI_SUCCESS (status)) { + acpi_gbl_global_lock_handle++; + *handle = acpi_gbl_global_lock_handle; + } + return (status); } @@ -631,11 +654,17 @@ acpi_status acpi_release_global_lock ( - void) + u32 handle) { + acpi_status status; + - acpi_ev_release_global_lock (); - return (AE_OK); + if (handle != acpi_gbl_global_lock_handle) { + return (AE_NOT_ACQUIRED); + } + + status = acpi_ev_release_global_lock (); + return (status); } diff -Nur linux-2.4.19/drivers/acpi/events/evxfevnt.c linux-2.4.19-sgi211r3/drivers/acpi/events/evxfevnt.c --- linux-2.4.19/drivers/acpi/events/evxfevnt.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evxfevnt.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable - * $Revision: 38 $ + * $Revision: 55 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +25,10 @@ #include "acpi.h" -#include "achware.h" -#include "acnamesp.h" #include "acevents.h" -#include "amlcode.h" -#include "acinterp.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evxfevnt") + ACPI_MODULE_NAME ("evxfevnt") /******************************************************************************* @@ -50,36 +46,36 @@ acpi_status acpi_enable (void) { - acpi_status status; + acpi_status status = AE_OK; - FUNCTION_TRACE ("Acpi_enable"); + ACPI_FUNCTION_TRACE ("Acpi_enable"); - /* Make sure we've got ACPI tables */ + /* Make sure we have ACPI tables */ if (!acpi_gbl_DSDT) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No ACPI tables present!\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } - /* Make sure the BIOS supports ACPI mode */ + acpi_gbl_original_mode = acpi_hw_get_mode (); - if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities()) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Only legacy mode supported!\n")); - return_ACPI_STATUS (AE_ERROR); + if (acpi_gbl_original_mode == ACPI_SYS_MODE_ACPI) { + ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Already in ACPI mode.\n")); } + else { + /* Transition to ACPI mode */ - /* Transition to ACPI mode */ + status = acpi_hw_set_mode (ACPI_SYS_MODE_ACPI); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Could not transition to ACPI mode.\n")); + return_ACPI_STATUS (status); + } - status = acpi_hw_set_mode (SYS_MODE_ACPI); - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Could not transition to ACPI mode.\n")); - return_ACPI_STATUS (status); + ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Transition to ACPI mode successful\n")); } - ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Transition to ACPI mode successful\n")); - return_ACPI_STATUS (status); } @@ -100,25 +96,25 @@ acpi_status acpi_disable (void) { - acpi_status status; + acpi_status status = AE_OK; - FUNCTION_TRACE ("Acpi_disable"); + ACPI_FUNCTION_TRACE ("Acpi_disable"); - /* Restore original mode */ + if (acpi_hw_get_mode () != acpi_gbl_original_mode) { + /* Restore original mode */ - status = acpi_hw_set_mode (acpi_gbl_original_mode); - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to transition to original mode")); - return_ACPI_STATUS (status); + status = acpi_hw_set_mode (acpi_gbl_original_mode); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to transition to original mode")); + return_ACPI_STATUS (status); + } } /* Unload the SCI interrupt handler */ - acpi_ev_remove_sci_handler (); - acpi_ev_restore_acpi_state (); - + status = acpi_ev_remove_sci_handler (); return_ACPI_STATUS (status); } @@ -144,58 +140,46 @@ u32 flags) { acpi_status status = AE_OK; - u32 register_id; + u32 value; - FUNCTION_TRACE ("Acpi_enable_event"); + ACPI_FUNCTION_TRACE ("Acpi_enable_event"); - /* The Type must be either Fixed Acpi_event or GPE */ + /* The Type must be either Fixed Event or GPE */ switch (type) { - case ACPI_EVENT_FIXED: - /* Decode the Fixed Acpi_event */ + /* Decode the Fixed Event */ - switch (event) { - case ACPI_EVENT_PMTIMER: - register_id = TMR_EN; - break; - - case ACPI_EVENT_GLOBAL: - register_id = GBL_EN; - break; - - case ACPI_EVENT_POWER_BUTTON: - register_id = PWRBTN_EN; - break; - - case ACPI_EVENT_SLEEP_BUTTON: - register_id = SLPBTN_EN; - break; - - case ACPI_EVENT_RTC: - register_id = RTC_EN; - break; - - default: + if (event > ACPI_EVENT_MAX) { return_ACPI_STATUS (AE_BAD_PARAMETER); - break; } /* * Enable the requested fixed event (by writing a one to the * enable register bit) */ - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, register_id, 1); + status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 1, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - if (1 != acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, register_id)) { + /* Make sure that the hardware responded */ + + status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, + &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (value != 1) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Fixed event bit clear when it should be set\n")); + "Could not enable %s event\n", acpi_ut_get_event_name (event))); return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); } - break; @@ -203,21 +187,20 @@ /* Ensure that we have a valid GPE number */ - if ((event > ACPI_GPE_MAX) || - (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + if (acpi_ev_get_gpe_number_index (event) == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Enable the requested GPE number */ - if (flags & ACPI_EVENT_ENABLE) { - acpi_hw_enable_gpe (event); + status = acpi_hw_enable_gpe (event); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } + if (flags & ACPI_EVENT_WAKE_ENABLE) { acpi_hw_enable_gpe_for_wakeup (event); } - break; @@ -226,7 +209,6 @@ status = AE_BAD_PARAMETER; } - return_ACPI_STATUS (status); } @@ -252,58 +234,44 @@ u32 flags) { acpi_status status = AE_OK; - u32 register_id; + u32 value; - FUNCTION_TRACE ("Acpi_disable_event"); + ACPI_FUNCTION_TRACE ("Acpi_disable_event"); - /* The Type must be either Fixed Acpi_event or GPE */ + /* The Type must be either Fixed Event or GPE */ switch (type) { - case ACPI_EVENT_FIXED: - /* Decode the Fixed Acpi_event */ - - switch (event) { - case ACPI_EVENT_PMTIMER: - register_id = TMR_EN; - break; - - case ACPI_EVENT_GLOBAL: - register_id = GBL_EN; - break; - - case ACPI_EVENT_POWER_BUTTON: - register_id = PWRBTN_EN; - break; - - case ACPI_EVENT_SLEEP_BUTTON: - register_id = SLPBTN_EN; - break; - - case ACPI_EVENT_RTC: - register_id = RTC_EN; - break; + /* Decode the Fixed Event */ - default: + if (event > ACPI_EVENT_MAX) { return_ACPI_STATUS (AE_BAD_PARAMETER); - break; } /* * Disable the requested fixed event (by writing a zero to the * enable register bit) */ - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, register_id, 0); + status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, + &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - if (0 != acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, register_id)) { + if (value != 0) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Fixed event bit set when it should be clear,\n")); + "Could not disable %s events\n", acpi_ut_get_event_name (event))); return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); } - break; @@ -311,20 +279,21 @@ /* Ensure that we have a valid GPE number */ - if ((event > ACPI_GPE_MAX) || - (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + if (acpi_ev_get_gpe_number_index (event) == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Disable the requested GPE number */ + /* + * Only disable the requested GPE number for wake if specified. + * Otherwise, turn it totally off + */ - if (flags & ACPI_EVENT_DISABLE) { - acpi_hw_disable_gpe (event); - } if (flags & ACPI_EVENT_WAKE_DISABLE) { acpi_hw_disable_gpe_for_wakeup (event); } - + else { + status = acpi_hw_disable_gpe (event); + } break; @@ -355,51 +324,28 @@ u32 type) { acpi_status status = AE_OK; - u32 register_id; - FUNCTION_TRACE ("Acpi_clear_event"); + ACPI_FUNCTION_TRACE ("Acpi_clear_event"); - /* The Type must be either Fixed Acpi_event or GPE */ + /* The Type must be either Fixed Event or GPE */ switch (type) { - case ACPI_EVENT_FIXED: - /* Decode the Fixed Acpi_event */ - - switch (event) { - case ACPI_EVENT_PMTIMER: - register_id = TMR_STS; - break; - - case ACPI_EVENT_GLOBAL: - register_id = GBL_STS; - break; - - case ACPI_EVENT_POWER_BUTTON: - register_id = PWRBTN_STS; - break; - - case ACPI_EVENT_SLEEP_BUTTON: - register_id = SLPBTN_STS; - break; - - case ACPI_EVENT_RTC: - register_id = RTC_STS; - break; + /* Decode the Fixed Event */ - default: + if (event > ACPI_EVENT_MAX) { return_ACPI_STATUS (AE_BAD_PARAMETER); - break; } /* * Clear the requested fixed event (By writing a one to the * status register bit) */ - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, register_id, 1); + status = acpi_set_register (acpi_gbl_fixed_event_info[event].status_register_id, + 1, ACPI_MTX_LOCK); break; @@ -407,13 +353,11 @@ /* Ensure that we have a valid GPE number */ - if ((event > ACPI_GPE_MAX) || - (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + if (acpi_ev_get_gpe_number_index (event) == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - - acpi_hw_clear_gpe (event); + status = acpi_hw_clear_gpe (event); break; @@ -449,10 +393,9 @@ acpi_event_status *event_status) { acpi_status status = AE_OK; - u32 register_id; - FUNCTION_TRACE ("Acpi_get_event_status"); + ACPI_FUNCTION_TRACE ("Acpi_get_event_status"); if (!event_status) { @@ -460,43 +403,21 @@ } - /* The Type must be either Fixed Acpi_event or GPE */ + /* The Type must be either Fixed Event or GPE */ switch (type) { - case ACPI_EVENT_FIXED: - /* Decode the Fixed Acpi_event */ + /* Decode the Fixed Event */ - switch (event) { - case ACPI_EVENT_PMTIMER: - register_id = TMR_STS; - break; - - case ACPI_EVENT_GLOBAL: - register_id = GBL_STS; - break; - - case ACPI_EVENT_POWER_BUTTON: - register_id = PWRBTN_STS; - break; - - case ACPI_EVENT_SLEEP_BUTTON: - register_id = SLPBTN_STS; - break; - - case ACPI_EVENT_RTC: - register_id = RTC_STS; - break; - - default: + if (event > ACPI_EVENT_MAX) { return_ACPI_STATUS (AE_BAD_PARAMETER); - break; } /* Get the status of the requested fixed event */ - *event_status = acpi_hw_register_bit_access (ACPI_READ, ACPI_MTX_LOCK, register_id); + status = acpi_get_register (acpi_gbl_fixed_event_info[event].status_register_id, + event_status, ACPI_MTX_LOCK); break; @@ -504,15 +425,13 @@ /* Ensure that we have a valid GPE number */ - if ((event > ACPI_GPE_MAX) || - (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID)) { + if (acpi_ev_get_gpe_number_index (event) == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Obtain status on the requested GPE number */ - acpi_hw_get_gpe_status (event, event_status); + status = acpi_hw_get_gpe_status (event, event_status); break; diff -Nur linux-2.4.19/drivers/acpi/events/evxfregn.c linux-2.4.19-sgi211r3/drivers/acpi/events/evxfregn.c --- linux-2.4.19/drivers/acpi/events/evxfregn.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/events/evxfregn.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and * Address Spaces. - * $Revision: 40 $ + * $Revision: 50 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,14 +26,12 @@ #include "acpi.h" -#include "achware.h" #include "acnamesp.h" #include "acevents.h" -#include "amlcode.h" #include "acinterp.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evxfregn") + ACPI_MODULE_NAME ("evxfregn") /******************************************************************************* @@ -63,23 +61,24 @@ acpi_operand_object *obj_desc; acpi_operand_object *handler_obj; acpi_namespace_node *node; - acpi_status status = AE_OK; - acpi_object_type8 type; + acpi_status status; + acpi_object_type type; u16 flags = 0; - FUNCTION_TRACE ("Acpi_install_address_space_handler"); + ACPI_FUNCTION_TRACE ("Acpi_install_address_space_handler"); /* Parameter validation */ - if ((!device) || - ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) || - (space_id > ACPI_MAX_ADDRESS_SPACE)) { + if (!device) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Convert and validate the device handle */ @@ -103,7 +102,7 @@ } if (handler == ACPI_DEFAULT_HANDLER) { - flags = ADDR_HANDLER_DEFAULT_INSTALLED; + flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; switch (space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: @@ -131,10 +130,14 @@ setup = acpi_ev_pci_bar_region_setup; break; + case ACPI_ADR_SPACE_DATA_TABLE: + handler = acpi_ex_data_table_space_handler; + setup = NULL; + break; + default: status = AE_NOT_EXIST; goto unlock_and_exit; - break; } } @@ -164,7 +167,7 @@ * address space. */ if(handler_obj->addr_handler.space_id == space_id) { - status = AE_EXIST; + status = AE_ALREADY_EXISTS; goto unlock_and_exit; } @@ -174,7 +177,6 @@ handler_obj = handler_obj->addr_handler.next; } } - else { ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Creating object on Device %p while installing handler\n", node)); @@ -200,7 +202,7 @@ /* Attach the new object to the Node */ - status = acpi_ns_attach_object (node, obj_desc, (u8) type); + status = acpi_ns_attach_object (node, obj_desc, type); if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (obj_desc); goto unlock_and_exit; @@ -246,7 +248,7 @@ * of the branch */ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, - ACPI_UINT32_MAX, NS_WALK_UNLOCK, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_addr_handler_helper, handler_obj, NULL); @@ -260,7 +262,7 @@ unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } @@ -289,21 +291,22 @@ acpi_operand_object *region_obj; acpi_operand_object **last_obj_ptr; acpi_namespace_node *node; - acpi_status status = AE_OK; + acpi_status status; - FUNCTION_TRACE ("Acpi_remove_address_space_handler"); + ACPI_FUNCTION_TRACE ("Acpi_remove_address_space_handler"); /* Parameter validation */ - if ((!device) || - ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) || - (space_id > ACPI_MAX_ADDRESS_SPACE)) { + if (!device) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Convert and validate the device handle */ @@ -313,7 +316,6 @@ goto unlock_and_exit; } - /* Make sure the internal object exists */ obj_desc = acpi_ns_get_attached_object (node); @@ -352,7 +354,7 @@ * The region is just inaccessible as indicated to * the _REG method */ - acpi_ev_disassociate_region_from_handler(region_obj, TRUE); + acpi_ev_detach_region (region_obj, TRUE); /* * Walk the list, since we took the first region and it @@ -396,7 +398,7 @@ unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/executer/Makefile linux-2.4.19-sgi211r3/drivers/acpi/executer/Makefile --- linux-2.4.19/drivers/acpi/executer/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/executer/exconfig.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exconfig.c --- linux-2.4.19/drivers/acpi/executer/exconfig.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exconfig.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) - * $Revision: 44 $ + * $Revision: 65 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,161 +25,365 @@ #include "acpi.h" -#include "acparser.h" #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" #include "acevents.h" #include "actables.h" -#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exconfig") + ACPI_MODULE_NAME ("exconfig") -/***************************************************************************** +/******************************************************************************* + * + * FUNCTION: Acpi_ex_add_table + * + * PARAMETERS: Table - Pointer to raw table + * Parent_node - Where to load the table (scope) + * Ddb_handle - Where to return the table handle. + * + * RETURN: Status + * + * DESCRIPTION: Common function to Install and Load an ACPI table with a + * returned table handle. + * + ******************************************************************************/ + +acpi_status +acpi_ex_add_table ( + acpi_table_header *table, + acpi_namespace_node *parent_node, + acpi_operand_object **ddb_handle) +{ + acpi_status status; + acpi_table_desc table_info; + acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE ("Ex_add_table"); + + + /* Create an object to be the table handle */ + + obj_desc = acpi_ut_create_internal_object (INTERNAL_TYPE_REFERENCE); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Install the new table into the local data structures */ + + table_info.pointer = table; + table_info.length = (ACPI_SIZE) table->length; + table_info.allocation = ACPI_MEM_ALLOCATED; + table_info.base_pointer = table; + + status = acpi_tb_install_table (&table_info); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Add the table to the namespace */ + + status = acpi_ns_load_table (table_info.installed_desc, parent_node); + if (ACPI_FAILURE (status)) { + /* Uninstall table on error */ + + (void) acpi_tb_uninstall_table (table_info.installed_desc); + goto cleanup; + } + + /* Init the table handle */ + + obj_desc->reference.opcode = AML_LOAD_OP; + obj_desc->reference.object = table_info.installed_desc; + *ddb_handle = obj_desc; + return_ACPI_STATUS (AE_OK); + + +cleanup: + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* * * FUNCTION: Acpi_ex_load_table_op * - * PARAMETERS: Rgn_desc - Op region where the table will be obtained - * Ddb_handle - Where a handle to the table will be returned + * PARAMETERS: Walk_state - Current state with operands + * Return_desc - Where to store the return object * * RETURN: Status * * DESCRIPTION: Load an ACPI table * - ****************************************************************************/ + ******************************************************************************/ acpi_status -acpi_ex_load_op ( - acpi_operand_object *rgn_desc, - acpi_operand_object *ddb_handle) +acpi_ex_load_table_op ( + acpi_walk_state *walk_state, + acpi_operand_object **return_desc) { acpi_status status; - acpi_operand_object *table_desc = NULL; - u8 *table_ptr; - u8 *table_data_ptr; - acpi_table_header table_header; - acpi_table_desc table_info; - u32 i; + acpi_operand_object **operand = &walk_state->operands[0]; + acpi_table_header *table; + acpi_namespace_node *parent_node; + acpi_namespace_node *start_node; + acpi_namespace_node *parameter_node = NULL; + acpi_operand_object *ddb_handle; + + + ACPI_FUNCTION_TRACE ("Ex_load_table_op"); + + + /* + * Make sure that the signature does not match one of the tables that + * is already loaded. + */ + status = acpi_tb_match_signature (operand[0]->string.pointer, NULL); + if (status == AE_OK) { + /* Signature matched -- don't allow override */ + + return_ACPI_STATUS (AE_ALREADY_EXISTS); + } + + /* Find the ACPI table */ + + status = acpi_tb_find_table (operand[0]->string.pointer, + operand[1]->string.pointer, + operand[2]->string.pointer, &table); + if (ACPI_FAILURE (status)) { + if (status != AE_NOT_FOUND) { + return_ACPI_STATUS (status); + } + /* Not found, return an Integer=0 and AE_OK */ - FUNCTION_TRACE ("Ex_load_op"); + ddb_handle = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!ddb_handle) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ddb_handle->integer.value = 0; + *return_desc = ddb_handle; - /* TBD: [Unhandled] Object can be either a field or an opregion */ + return_ACPI_STATUS (AE_OK); + } + /* Default nodes */ - /* Get the table header */ + start_node = walk_state->scope_info->scope.node; + parent_node = acpi_gbl_root_node; - table_header.length = 0; - for (i = 0; i < sizeof (acpi_table_header); i++) { - status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_READ_ADR_SPACE, - (ACPI_PHYSICAL_ADDRESS) i, 8, - (u32 *) ((u8 *) &table_header + i)); + /* Root_path (optional parameter) */ + + if (operand[3]->string.length > 0) { + /* + * Find the node referenced by the Root_path_string. This is the + * location within the namespace where the table will be loaded. + */ + status = acpi_ns_get_node_by_path (operand[3]->string.pointer, start_node, + ACPI_NS_SEARCH_PARENT, &parent_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } - /* Allocate a buffer for the entire table */ + /* Parameter_path (optional parameter) */ - table_ptr = ACPI_MEM_ALLOCATE (table_header.length); - if (!table_ptr) { - return_ACPI_STATUS (AE_NO_MEMORY); + if (operand[4]->string.length > 0) { + if ((operand[4]->string.pointer[0] != '\\') && + (operand[4]->string.pointer[0] != '^')) { + /* + * Path is not absolute, so it will be relative to the node + * referenced by the Root_path_string (or the NS root if omitted) + */ + start_node = parent_node; + } + + /* + * Find the node referenced by the Parameter_path_string + */ + status = acpi_ns_get_node_by_path (operand[4]->string.pointer, start_node, + ACPI_NS_SEARCH_PARENT, ¶meter_node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - /* Copy the header to the buffer */ + /* Load the table into the namespace */ - MEMCPY (table_ptr, &table_header, sizeof (acpi_table_header)); - table_data_ptr = table_ptr + sizeof (acpi_table_header); + status = acpi_ex_add_table (table, parent_node, &ddb_handle); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* Parameter Data (optional) */ - /* Get the table from the op region */ + if (parameter_node) { + /* Store the parameter data into the optional parameter object */ - for (i = 0; i < table_header.length; i++) { - status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_READ_ADR_SPACE, - (ACPI_PHYSICAL_ADDRESS) i, 8, - (u32 *) (table_data_ptr + i)); + status = acpi_ex_store (operand[5], ACPI_CAST_PTR (acpi_operand_object, parameter_node), + walk_state); if (ACPI_FAILURE (status)) { - goto cleanup; + (void) acpi_ex_unload_table (ddb_handle); } } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ex_load_op + * + * PARAMETERS: Obj_desc - Region or Field where the table will be + * obtained + * Target - Where a handle to the table will be stored + * Walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Load an ACPI table from a field or operation region + * + ******************************************************************************/ + +acpi_status +acpi_ex_load_op ( + acpi_operand_object *obj_desc, + acpi_operand_object *target, + acpi_walk_state *walk_state) +{ + acpi_status status; + acpi_operand_object *ddb_handle; + acpi_operand_object *buffer_desc = NULL; + acpi_table_header *table_ptr = NULL; + u8 *table_data_ptr; + acpi_table_header table_header; + u32 i; + + ACPI_FUNCTION_TRACE ("Ex_load_op"); + + + /* Object can be either an Op_region or a Field */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_REGION: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Region %p %s\n", + obj_desc, acpi_ut_get_type_name (obj_desc->common.type))); - /* Table must be either an SSDT or a PSDT */ + /* Get the table header */ - if ((!STRNCMP (table_header.signature, + table_header.length = 0; + for (i = 0; i < sizeof (acpi_table_header); i++) { + status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, + (ACPI_PHYSICAL_ADDRESS) i, 8, + ((u8 *) &table_header) + i); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Allocate a buffer for the entire table */ + + table_ptr = ACPI_MEM_ALLOCATE (table_header.length); + if (!table_ptr) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the header to the buffer */ + + ACPI_MEMCPY (table_ptr, &table_header, sizeof (acpi_table_header)); + table_data_ptr = ACPI_PTR_ADD (u8, table_ptr, sizeof (acpi_table_header)); + + /* Get the table from the op region */ + + for (i = 0; i < table_header.length; i++) { + status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, + (ACPI_PHYSICAL_ADDRESS) i, 8, + ((u8 *) table_data_ptr + i)); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + } + break; + + + case ACPI_TYPE_BUFFER_FIELD: + case INTERNAL_TYPE_REGION_FIELD: + case INTERNAL_TYPE_BANK_FIELD: + case INTERNAL_TYPE_INDEX_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Field %p %s\n", + obj_desc, acpi_ut_get_type_name (obj_desc->common.type))); + + /* + * The length of the field must be at least as large as the table. + * Read the entire field and thus the entire table. Buffer is + * allocated during the read. + */ + status = acpi_ex_read_data_from_field (walk_state, obj_desc, &buffer_desc); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + table_ptr = ACPI_CAST_PTR (acpi_table_header, buffer_desc->buffer.pointer); + break; + + + default: + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* The table must be either an SSDT or a PSDT */ + + if ((!ACPI_STRNCMP (table_ptr->signature, acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].signature, acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].sig_length)) && - (!STRNCMP (table_header.signature, + (!ACPI_STRNCMP (table_ptr->signature, acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].signature, acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].sig_length))) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Table has invalid signature [%4.4s], must be SSDT or PSDT\n", - (char*)table_header.signature)); + table_ptr->signature)); status = AE_BAD_SIGNATURE; goto cleanup; } - /* Create an object to be the table handle */ - - table_desc = acpi_ut_create_internal_object (INTERNAL_TYPE_REFERENCE); - if (!table_desc) { - status = AE_NO_MEMORY; - goto cleanup; - } - - /* Install the new table into the local data structures */ - table_info.pointer = (acpi_table_header *) table_ptr; - table_info.length = table_header.length; - table_info.allocation = ACPI_MEM_ALLOCATED; - table_info.base_pointer = table_ptr; - - status = acpi_tb_install_table (NULL, &table_info); + status = acpi_ex_add_table (table_ptr, acpi_gbl_root_node, &ddb_handle); if (ACPI_FAILURE (status)) { goto cleanup; } - /* Add the table to the namespace */ + /* Store the Ddb_handle into the Target operand */ - /* TBD: [Restructure] - change to whatever new interface is appropriate */ -/* - Status = Acpi_load_namespace (); - if (ACPI_FAILURE (Status)) - { -*/ - /* TBD: [Errors] Unload the table on failure ? */ -/* - goto Cleanup; + status = acpi_ex_store (ddb_handle, target, walk_state); + if (ACPI_FAILURE (status)) { + (void) acpi_ex_unload_table (ddb_handle); } -*/ - - - /* TBD: [Investigate] we need a pointer to the table desc */ - - /* Init the table handle */ - - table_desc->reference.opcode = AML_LOAD_OP; - table_desc->reference.object = table_info.installed_desc; - - /* TBD: store the tabledesc into the Ddb_handle target */ - /* Ddb_handle = Table_desc; */ return_ACPI_STATUS (status); cleanup: - ACPI_MEM_FREE (table_desc); - ACPI_MEM_FREE (table_ptr); + if (buffer_desc) { + acpi_ut_remove_reference (buffer_desc); + } + else { + ACPI_MEM_FREE (table_ptr); + } return_ACPI_STATUS (status); } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ex_unload_table * @@ -189,7 +393,7 @@ * * DESCRIPTION: Unload an ACPI table * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_unload_table ( @@ -200,7 +404,7 @@ acpi_table_desc *table_info; - FUNCTION_TRACE ("Ex_unload_table"); + ACPI_FUNCTION_TRACE ("Ex_unload_table"); /* @@ -210,7 +414,7 @@ * validated here. */ if ((!ddb_handle) || - (!VALID_DESCRIPTOR_TYPE (ddb_handle, ACPI_DESC_TYPE_INTERNAL)) || + (ACPI_GET_DESCRIPTOR_TYPE (ddb_handle) != ACPI_DESC_TYPE_OPERAND) || (((acpi_operand_object *)ddb_handle)->common.type != INTERNAL_TYPE_REFERENCE)) { return_ACPI_STATUS (AE_BAD_PARAMETER); @@ -224,19 +428,15 @@ * Delete the entire namespace under this table Node * (Offset contains the Table_id) */ - status = acpi_ns_delete_namespace_by_owner (table_info->table_id); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + acpi_ns_delete_namespace_by_owner (table_info->table_id); /* Delete the table itself */ - acpi_tb_uninstall_table (table_info->installed_desc); + (void) acpi_tb_uninstall_table (table_info->installed_desc); /* Delete the table descriptor (Ddb_handle) */ acpi_ut_remove_reference (table_desc); - return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/executer/exconvrt.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exconvrt.c --- linux-2.4.19/drivers/acpi/executer/exconvrt.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exconvrt.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: exconvrt - Object conversion routines - * $Revision: 24 $ + * $Revision: 36 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,16 +25,12 @@ #include "acpi.h" -#include "acparser.h" -#include "acnamesp.h" #include "acinterp.h" -#include "acevents.h" #include "amlcode.h" -#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exconvrt") + ACPI_MODULE_NAME ("exconvrt") /******************************************************************************* @@ -60,53 +56,33 @@ u32 i; acpi_operand_object *ret_desc; u32 count; - char *pointer; + u8 *pointer; acpi_integer result; - u32 integer_size = sizeof (acpi_integer); + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_TRACE_PTR ("Ex_convert_to_integer", obj_desc); switch (obj_desc->common.type) { case ACPI_TYPE_INTEGER: *result_desc = obj_desc; - return (AE_OK); + return_ACPI_STATUS (AE_OK); case ACPI_TYPE_STRING: - pointer = obj_desc->string.pointer; + pointer = (u8 *) obj_desc->string.pointer; count = obj_desc->string.length; break; case ACPI_TYPE_BUFFER: - pointer = (char *) obj_desc->buffer.pointer; + pointer = obj_desc->buffer.pointer; count = obj_desc->buffer.length; break; default: - return (AE_TYPE); - } - - /* - * Create a new integer - */ - ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); - if (!ret_desc) { - return (AE_NO_MEMORY); - } - - - /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ - - if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { - /* - * We are running a method that exists in a 32-bit ACPI table. - * Truncate the value to 32 bits by zeroing out the upper 32-bit field - */ - integer_size = sizeof (u32); + return_ACPI_STATUS (AE_TYPE); } - /* * Convert the buffer/string to an integer. Note that both buffers and * strings are treated as raw data - we don't convert ascii to hex for @@ -120,8 +96,8 @@ /* Transfer no more than an integer's worth of data */ - if (count > integer_size) { - count = integer_size; + if (count > acpi_gbl_integer_byte_width) { + count = acpi_gbl_integer_byte_width; } /* @@ -130,13 +106,14 @@ switch (obj_desc->common.type) { case ACPI_TYPE_STRING: - /* TBD: Need to use 64-bit STRTOUL */ - /* * Convert string to an integer * String must be hexadecimal as per the ACPI specification */ - result = STRTOUL (pointer, NULL, 16); + status = acpi_ut_strtoul64 ((char *) pointer, 16, &result); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } break; @@ -154,10 +131,22 @@ */ result |= (((acpi_integer) pointer[i]) << (i * 8)); } + break; + + default: + /* No other types can get here */ break; } + /* + * Create a new integer + */ + ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!ret_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + /* Save the Result, delete original descriptor, store new descriptor */ ret_desc->integer.value = result; @@ -169,7 +158,7 @@ } *result_desc = ret_desc; - return (AE_OK); + return_ACPI_STATUS (AE_OK); } @@ -195,61 +184,47 @@ { acpi_operand_object *ret_desc; u32 i; - u32 integer_size = sizeof (acpi_integer); u8 *new_buf; - FUNCTION_ENTRY (); + ACPI_FUNCTION_TRACE_PTR ("Ex_convert_to_buffer", obj_desc); switch (obj_desc->common.type) { case ACPI_TYPE_INTEGER: /* - * Create a new Buffer + * Create a new Buffer object */ ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); if (!ret_desc) { - return (AE_NO_MEMORY); - } - - /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ - - if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { - /* - * We are running a method that exists in a 32-bit ACPI table. - * Truncate the value to 32 bits by zeroing out the upper - * 32-bit field - */ - integer_size = sizeof (u32); + return_ACPI_STATUS (AE_NO_MEMORY); } - /* Need enough space for one integers */ + /* Need enough space for one integer */ - ret_desc->buffer.length = integer_size; - new_buf = ACPI_MEM_CALLOCATE (integer_size); + new_buf = ACPI_MEM_CALLOCATE (acpi_gbl_integer_byte_width); if (!new_buf) { - REPORT_ERROR + ACPI_REPORT_ERROR (("Ex_convert_to_buffer: Buffer allocation failure\n")); acpi_ut_remove_reference (ret_desc); - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } /* Copy the integer to the buffer */ - for (i = 0; i < integer_size; i++) { + for (i = 0; i < acpi_gbl_integer_byte_width; i++) { new_buf[i] = (u8) (obj_desc->integer.value >> (i * 8)); } + + /* Complete buffer object initialization */ + + ret_desc->buffer.flags |= AOPOBJ_DATA_VALID; ret_desc->buffer.pointer = new_buf; + ret_desc->buffer.length = acpi_gbl_integer_byte_width; /* Return the new buffer descriptor */ - if (*result_desc == obj_desc) { - if (walk_state->opcode != AML_STORE_OP) { - acpi_ut_remove_reference (obj_desc); - } - } - *result_desc = ret_desc; break; @@ -265,11 +240,13 @@ default: - return (AE_TYPE); - break; - } + return_ACPI_STATUS (AE_TYPE); + } + + /* Mark buffer initialized */ - return (AE_OK); + (*result_desc)->common.flags |= AOPOBJ_DATA_VALID; + return_ACPI_STATUS (AE_OK); } @@ -294,14 +271,14 @@ u32 i; u32 j; u32 k = 0; - u8 hex_digit; + char hex_digit; acpi_integer digit; u32 remainder; u32 length = sizeof (acpi_integer); u8 leading_zero = TRUE; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); switch (base) { @@ -313,7 +290,7 @@ digit = integer; for (j = 1; j < i; j++) { - acpi_ut_short_divide (&digit, 10, &digit, &remainder); + (void) acpi_ut_short_divide (&digit, 10, &digit, &remainder); } /* Create the decimal digit */ @@ -323,7 +300,7 @@ } if (!leading_zero) { - string[k] = (u8) (ASCII_ZERO + remainder); + string[k] = (u8) (ACPI_ASCII_ZERO + remainder); k++; } } @@ -336,12 +313,12 @@ for (i = 0, j = ((length * 2) -1); i < (length * 2); i++, j--) { hex_digit = acpi_ut_hex_to_ascii_char (integer, (j * 4)); - if (hex_digit != ASCII_ZERO) { + if (hex_digit != ACPI_ASCII_ZERO) { leading_zero = FALSE; } if (!leading_zero) { - string[k] = hex_digit; + string[k] = (u8) hex_digit; k++; } } @@ -358,7 +335,7 @@ * Finally, null terminate the string and return the length */ if (!k) { - string [0] = ASCII_ZERO; + string [0] = ACPI_ASCII_ZERO; k = 1; } string [k] = 0; @@ -393,29 +370,17 @@ u32 i; u32 index; u32 string_length; - u32 integer_size = sizeof (acpi_integer); u8 *new_buf; u8 *pointer; - FUNCTION_ENTRY (); + ACPI_FUNCTION_TRACE_PTR ("Ex_convert_to_string", obj_desc); switch (obj_desc->common.type) { case ACPI_TYPE_INTEGER: - /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ - - if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { - /* - * We are running a method that exists in a 32-bit ACPI table. - * Truncate the value to 32 bits by zeroing out the upper - * 32-bit field - */ - integer_size = sizeof (u32); - } - - string_length = integer_size * 2; + string_length = acpi_gbl_integer_byte_width * 2; if (base == 10) { string_length = ACPI_MAX_DECIMAL_DIGITS; } @@ -425,20 +390,19 @@ */ ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING); if (!ret_desc) { - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } /* Need enough space for one ASCII integer plus null terminator */ - new_buf = ACPI_MEM_CALLOCATE (string_length + 1); + new_buf = ACPI_MEM_CALLOCATE ((ACPI_SIZE) string_length + 1); if (!new_buf) { - REPORT_ERROR + ACPI_REPORT_ERROR (("Ex_convert_to_string: Buffer allocation failure\n")); acpi_ut_remove_reference (ret_desc); - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } - /* Convert */ i = acpi_ex_convert_to_ascii (obj_desc->integer.value, base, new_buf); @@ -477,7 +441,7 @@ if (max_length > ACPI_MAX_STRING_CONVERSION) { if (string_length > ACPI_MAX_STRING_CONVERSION) { - return (AE_AML_STRING_LIMIT); + return_ACPI_STATUS (AE_AML_STRING_LIMIT); } } @@ -486,7 +450,7 @@ */ ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING); if (!ret_desc) { - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } /* String length is the lesser of the Max or the actual length */ @@ -495,12 +459,12 @@ string_length = max_length; } - new_buf = ACPI_MEM_CALLOCATE (string_length + 1); + new_buf = ACPI_MEM_CALLOCATE ((ACPI_SIZE) string_length + 1); if (!new_buf) { - REPORT_ERROR + ACPI_REPORT_ERROR (("Ex_convert_to_string: Buffer allocation failure\n")); acpi_ut_remove_reference (ret_desc); - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } /* @@ -509,7 +473,7 @@ pointer = obj_desc->buffer.pointer; index = 0; for (i = 0, index = 0; i < obj_desc->buffer.length; i++) { - index = acpi_ex_convert_to_ascii (pointer[i], base, &new_buf[index]); + index = acpi_ex_convert_to_ascii ((acpi_integer) pointer[i], base, &new_buf[index]); new_buf[index] = ' '; index++; @@ -519,8 +483,7 @@ new_buf [index-1] = 0; ret_desc->buffer.pointer = new_buf; - ret_desc->string.length = STRLEN ((char *) new_buf); - + ret_desc->string.length = ACPI_STRLEN ((char *) new_buf); /* Return the new buffer descriptor */ @@ -543,17 +506,16 @@ else { /* Must copy the string first and then truncate it */ - return (AE_NOT_IMPLEMENTED); + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); } break; default: - return (AE_TYPE); - break; - } + return_ACPI_STATUS (AE_TYPE); + } - return (AE_OK); + return_ACPI_STATUS (AE_OK); } @@ -561,26 +523,32 @@ * * FUNCTION: Acpi_ex_convert_to_target_type * - * PARAMETERS: *Obj_desc - Object to be converted. - * Walk_state - Current method state + * PARAMETERS: Destination_type - Current type of the destination + * Source_desc - Source object to be converted. + * Walk_state - Current method state * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Implements "implicit conversion" rules for storing an object. * ******************************************************************************/ acpi_status acpi_ex_convert_to_target_type ( - acpi_object_type8 destination_type, - acpi_operand_object **obj_desc, + acpi_object_type destination_type, + acpi_operand_object *source_desc, + acpi_operand_object **result_desc, acpi_walk_state *walk_state) { acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_convert_to_target_type"); + ACPI_FUNCTION_TRACE ("Ex_convert_to_target_type"); + + /* Default behavior */ + + *result_desc = source_desc; /* * If required by the target, @@ -601,10 +569,10 @@ default: /* No conversion allowed for these types */ - if (destination_type != (*obj_desc)->common.type) { + if (destination_type != source_desc->common.type) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Target does not allow conversion of type %s to %s\n", - acpi_ut_get_type_name ((*obj_desc)->common.type), + acpi_ut_get_type_name ((source_desc)->common.type), acpi_ut_get_type_name (destination_type))); status = AE_TYPE; } @@ -623,7 +591,7 @@ * These types require an Integer operand. We can convert * a Buffer or a String to an Integer if necessary. */ - status = acpi_ex_convert_to_integer (*obj_desc, obj_desc, walk_state); + status = acpi_ex_convert_to_integer (source_desc, result_desc, walk_state); break; @@ -633,17 +601,22 @@ * The operand must be a String. We can convert an * Integer or Buffer if necessary */ - status = acpi_ex_convert_to_string (*obj_desc, obj_desc, 16, ACPI_UINT32_MAX, walk_state); + status = acpi_ex_convert_to_string (source_desc, result_desc, 16, ACPI_UINT32_MAX, walk_state); break; case ACPI_TYPE_BUFFER: /* - * The operand must be a String. We can convert an - * Integer or Buffer if necessary + * The operand must be a Buffer. We can convert an + * Integer or String if necessary */ - status = acpi_ex_convert_to_buffer (*obj_desc, obj_desc, walk_state); + status = acpi_ex_convert_to_buffer (source_desc, result_desc, walk_state); + break; + + + default: + status = AE_AML_INTERNAL; break; } break; @@ -664,7 +637,6 @@ status = AE_AML_INTERNAL; } - /* * Source-to-Target conversion semantics: diff -Nur linux-2.4.19/drivers/acpi/executer/excreate.c linux-2.4.19-sgi211r3/drivers/acpi/executer/excreate.c --- linux-2.4.19/drivers/acpi/executer/excreate.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/excreate.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: excreate - Named object creation - * $Revision: 71 $ + * $Revision: 91 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,16 +25,15 @@ #include "acpi.h" -#include "acparser.h" #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" #include "acevents.h" -#include "acdispat.h" +#include "actables.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("excreate") + ACPI_MODULE_NAME ("excreate") /***************************************************************************** @@ -58,7 +57,7 @@ acpi_status status; - FUNCTION_TRACE ("Ex_create_alias"); + ACPI_FUNCTION_TRACE ("Ex_create_alias"); /* Get the source/alias operands (both namespace nodes) */ @@ -69,7 +68,7 @@ /* Attach the original source object to the new Alias Node */ status = acpi_ns_attach_object ((acpi_namespace_node *) walk_state->operands[0], - source_node->object, + acpi_ns_get_attached_object (source_node), source_node->type); /* @@ -105,7 +104,7 @@ acpi_operand_object *obj_desc; - FUNCTION_TRACE ("Ex_create_event"); + ACPI_FUNCTION_TRACE ("Ex_create_event"); obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_EVENT); @@ -114,11 +113,11 @@ goto cleanup; } - /* Create the actual OS semaphore */ - - /* TBD: [Investigate] should be created with 0 or 1 units? */ - - status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 1, + /* + * Create the actual OS semaphore, with zero initial units -- meaning + * that the event is created in an unsignalled state + */ + status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, &obj_desc->event.semaphore); if (ACPI_FAILURE (status)) { goto cleanup; @@ -127,7 +126,7 @@ /* Attach object to the Node */ status = acpi_ns_attach_object ((acpi_namespace_node *) walk_state->operands[0], - obj_desc, (u8) ACPI_TYPE_EVENT); + obj_desc, ACPI_TYPE_EVENT); cleanup: /* @@ -161,7 +160,7 @@ acpi_operand_object *obj_desc; - FUNCTION_TRACE_PTR ("Ex_create_mutex", WALK_OPERANDS); + ACPI_FUNCTION_TRACE_PTR ("Ex_create_mutex", ACPI_WALK_OPERANDS); /* Create the new mutex object */ @@ -172,8 +171,11 @@ goto cleanup; } - /* Create the actual OS semaphore */ - + /* + * Create the actual OS semaphore. + * One unit max to make it a mutex, with one initial unit to allow + * the mutex to be acquired. + */ status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore); if (ACPI_FAILURE (status)) { goto cleanup; @@ -184,7 +186,7 @@ obj_desc->mutex.sync_level = (u8) walk_state->operands[1]->integer.value; status = acpi_ns_attach_object ((acpi_namespace_node *) walk_state->operands[0], - obj_desc, (u8) ACPI_TYPE_MUTEX); + obj_desc, ACPI_TYPE_MUTEX); cleanup: @@ -222,20 +224,21 @@ acpi_status status; acpi_operand_object *obj_desc; acpi_namespace_node *node; + acpi_operand_object *region_obj2; - FUNCTION_TRACE ("Ex_create_region"); + ACPI_FUNCTION_TRACE ("Ex_create_region"); /* Get the Node from the object stack */ - node = (acpi_namespace_node *) walk_state->operands[0]; + node = walk_state->op->common.node; /* * If the region object is already attached to this node, * just return */ - if (node->object) { + if (acpi_ns_get_attached_object (node)) { return_ACPI_STATUS (AE_OK); } @@ -243,9 +246,9 @@ * Space ID must be one of the predefined IDs, or in the user-defined * range */ - if ((region_space >= NUM_REGION_TYPES) && - (region_space < USER_REGION_BEGIN)) { - REPORT_ERROR (("Invalid Address_space type %X\n", region_space)); + if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) && + (region_space < ACPI_USER_REGION_BEGIN)) { + ACPI_REPORT_ERROR (("Invalid Address_space type %X\n", region_space)); return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID); } @@ -261,21 +264,13 @@ goto cleanup; } - /* Allocate a method object for this region */ - - obj_desc->region.extra = acpi_ut_create_internal_object ( - INTERNAL_TYPE_EXTRA); - if (!obj_desc->region.extra) { - status = AE_NO_MEMORY; - goto cleanup; - } - /* * Remember location in AML stream of address & length * operands since they need to be evaluated at run time. */ - obj_desc->region.extra->extra.aml_start = aml_start; - obj_desc->region.extra->extra.aml_length = aml_length; + region_obj2 = obj_desc->common.next_object; + region_obj2->extra.aml_start = aml_start; + region_obj2->extra.aml_length = aml_length; /* Init the region from the operands */ @@ -286,34 +281,14 @@ /* Install the new region object in the parent Node */ - status = acpi_ns_attach_object (node, obj_desc, - (u8) ACPI_TYPE_REGION); - if (ACPI_FAILURE (status)) { - goto cleanup; - } + status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION); - /* - * If we have a valid region, initialize it - * Namespace is NOT locked at this point. - */ - status = acpi_ev_initialize_region (obj_desc, FALSE); - if (ACPI_FAILURE (status)) { - /* - * If AE_NOT_EXIST is returned, it is not fatal - * because many regions get created before a handler - * is installed for said region. - */ - if (AE_NOT_EXIST == status) { - status = AE_OK; - } - } cleanup: /* Remove local reference to the object */ acpi_ut_remove_reference (obj_desc); - return_ACPI_STATUS (status); } @@ -334,24 +309,81 @@ acpi_ex_create_table_region ( acpi_walk_state *walk_state) { - acpi_status status = AE_OK; + acpi_status status; + acpi_operand_object **operand = &walk_state->operands[0]; + acpi_operand_object *obj_desc; + acpi_namespace_node *node; + acpi_table_header *table; + acpi_operand_object *region_obj2; - FUNCTION_TRACE ("Ex_create_table_region"); + ACPI_FUNCTION_TRACE ("Ex_create_table_region"); -/* - acpi_operand_object *Obj_desc; - Obj_desc = Acpi_ut_create_internal_object (ACPI_TYPE_REGION); - if (!Obj_desc) - { - Status = AE_NO_MEMORY; - goto Cleanup; + /* Get the Node from the object stack */ + + node = walk_state->op->common.node; + + /* + * If the region object is already attached to this node, + * just return + */ + if (acpi_ns_get_attached_object (node)) { + return_ACPI_STATUS (AE_OK); + } + + /* Find the ACPI table */ + + status = acpi_tb_find_table (operand[1]->string.pointer, + operand[2]->string.pointer, + operand[3]->string.pointer, &table); + + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } + /* Create the region descriptor */ -Cleanup: -*/ + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + region_obj2 = obj_desc->common.next_object; + region_obj2->extra.region_context = NULL; + + /* Init the region from the operands */ + + obj_desc->region.space_id = REGION_DATA_TABLE; + obj_desc->region.address = (ACPI_PHYSICAL_ADDRESS) ACPI_TO_INTEGER (table); + obj_desc->region.length = table->length; + obj_desc->region.node = node; + obj_desc->region.flags = AOPOBJ_DATA_VALID; + + /* Install the new region object in the parent Node */ + status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_ev_initialize_region (obj_desc, FALSE); + if (ACPI_FAILURE (status)) { + if (status == AE_NOT_EXIST) { + status = AE_OK; + } + else { + goto cleanup; + } + } + + obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE; + + +cleanup: + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); } @@ -381,7 +413,7 @@ acpi_status status; - FUNCTION_TRACE_PTR ("Ex_create_processor", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ex_create_processor", walk_state); /* Create the processor object */ @@ -401,7 +433,7 @@ /* Install the processor object in the parent Node */ status = acpi_ns_attach_object ((acpi_namespace_node *) operand[0], - obj_desc, (u8) ACPI_TYPE_PROCESSOR); + obj_desc, ACPI_TYPE_PROCESSOR); /* Remove local reference to the object */ @@ -436,7 +468,7 @@ acpi_operand_object *obj_desc; - FUNCTION_TRACE_PTR ("Ex_create_power_resource", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ex_create_power_resource", walk_state); /* Create the power resource object */ @@ -454,7 +486,7 @@ /* Install the power resource object in the parent Node */ status = acpi_ns_attach_object ((acpi_namespace_node *) operand[0], - obj_desc, (u8) ACPI_TYPE_POWER); + obj_desc, ACPI_TYPE_POWER); /* Remove local reference to the object */ @@ -491,7 +523,7 @@ u8 method_flags; - FUNCTION_TRACE_PTR ("Ex_create_method", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ex_create_method", walk_state); /* Create a new method object */ @@ -533,7 +565,7 @@ /* Attach the new object to the method Node */ status = acpi_ns_attach_object ((acpi_namespace_node *) operand[0], - obj_desc, (u8) ACPI_TYPE_METHOD); + obj_desc, ACPI_TYPE_METHOD); /* Remove local reference to the object */ diff -Nur linux-2.4.19/drivers/acpi/executer/exdump.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exdump.c --- linux-2.4.19/drivers/acpi/executer/exdump.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exdump.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: exdump - Interpreter debug output routines - * $Revision: 126 $ + * $Revision: 153 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,11 +28,10 @@ #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" -#include "actables.h" #include "acparser.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exdump") + ACPI_MODULE_NAME ("exdump") /* @@ -43,229 +42,155 @@ /***************************************************************************** * - * FUNCTION: Acpi_ex_show_hex_value - * - * PARAMETERS: Byte_count - Number of bytes to print (1, 2, or 4) - * *Aml_start - Address in AML stream of bytes to print - * Interpreter_mode - Current running mode (load1/Load2/Exec) - * Lead_space - # of spaces to print ahead of value - * 0 => none ahead but one behind - * - * DESCRIPTION: Print Byte_count byte(s) starting at Aml_start as a single - * value, in hex. If Byte_count > 1 or the value printed is > 9, also - * print in decimal. - * - ****************************************************************************/ - -void -acpi_ex_show_hex_value ( - u32 byte_count, - u8 *aml_start, - u32 lead_space) -{ - u32 value; /* Value retrieved from AML stream */ - u32 show_decimal_value; - u32 length; /* Length of printed field */ - u8 *current_aml_ptr = NULL; /* Pointer to current byte of AML value */ - - - FUNCTION_TRACE ("Ex_show_hex_value"); - - - if (!aml_start) { - REPORT_ERROR (("Ex_show_hex_value: null pointer\n")); - } - - /* - * AML numbers are always stored little-endian, - * even if the processor is big-endian. - */ - for (current_aml_ptr = aml_start + byte_count, - value = 0; - current_aml_ptr > aml_start; ) { - value = (value << 8) + (u32)* --current_aml_ptr; - } - - length = lead_space * byte_count + 2; - if (byte_count > 1) { - length += (byte_count - 1); - } - - show_decimal_value = (byte_count > 1 || value > 9); - if (show_decimal_value) { - length += 3 + acpi_ex_digits_needed (value, 10); - } - - for (length = lead_space; length; --length ) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_LOAD, " ")); - } - - while (byte_count--) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_LOAD, "%02x", *aml_start++)); - - if (byte_count) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_LOAD, " ")); - } - } - - if (show_decimal_value) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_LOAD, " [%d]", value)); - } - - if (0 == lead_space) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_LOAD, " ")); - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_LOAD, "\n")); - return_VOID; -} - - -/***************************************************************************** - * * FUNCTION: Acpi_ex_dump_operand * - * PARAMETERS: *Entry_desc - Pointer to entry to be dumped + * PARAMETERS: *Obj_desc - Pointer to entry to be dumped * * RETURN: Status * - * DESCRIPTION: Dump a stack entry + * DESCRIPTION: Dump an operand object * ****************************************************************************/ -acpi_status +void acpi_ex_dump_operand ( - acpi_operand_object *entry_desc) + acpi_operand_object *obj_desc) { u8 *buf = NULL; u32 length; u32 i; + acpi_operand_object **element; + u16 element_index; + + ACPI_FUNCTION_NAME ("Ex_dump_operand") - PROC_NAME ("Ex_dump_operand") + if (!((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { + return; + } - if (!entry_desc) { + if (!obj_desc) { /* * This usually indicates that something serious is wrong -- * since most (if not all) * code that dumps the stack expects something to be there! */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Null stack entry ptr\n")); - return (AE_OK); + acpi_os_printf ("Null stack entry ptr\n"); + return; } - if (VALID_DESCRIPTOR_TYPE (entry_desc, ACPI_DESC_TYPE_NAMED)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%p NS Node: ", entry_desc)); - DUMP_ENTRY (entry_desc, ACPI_LV_INFO); - return (AE_OK); + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p NS Node: ", obj_desc)); + ACPI_DUMP_ENTRY (obj_desc, ACPI_LV_EXEC); + return; } - if (!VALID_DESCRIPTOR_TYPE (entry_desc, ACPI_DESC_TYPE_INTERNAL)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%p Is not a local object \n", entry_desc)); - DUMP_BUFFER (entry_desc, sizeof (acpi_operand_object)); - return (AE_OK); + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p is not a local object\n", obj_desc)); + ACPI_DUMP_BUFFER (obj_desc, sizeof (acpi_operand_object)); + return; } - /* Entry_desc is a valid object */ + /* Obj_desc is a valid object */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%p ", entry_desc)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc)); - switch (entry_desc->common.type) { + switch (obj_desc->common.type) { case INTERNAL_TYPE_REFERENCE: - switch (entry_desc->reference.opcode) { + switch (obj_desc->reference.opcode) { case AML_ZERO_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: Zero\n")); + acpi_os_printf ("Reference: Zero\n"); break; case AML_ONE_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: One\n")); + acpi_os_printf ("Reference: One\n"); break; case AML_ONES_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: Ones\n")); + acpi_os_printf ("Reference: Ones\n"); break; case AML_REVISION_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: Revision\n")); + acpi_os_printf ("Reference: Revision\n"); break; case AML_DEBUG_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: Debug\n")); + acpi_os_printf ("Reference: Debug\n"); break; case AML_NAME_OP: - DUMP_PATHNAME (entry_desc->reference.object, "Reference: Name: ", + ACPI_DUMP_PATHNAME (obj_desc->reference.object, "Reference: Name: ", ACPI_LV_INFO, _COMPONENT); - DUMP_ENTRY (entry_desc->reference.object, ACPI_LV_INFO); + ACPI_DUMP_ENTRY (obj_desc->reference.object, ACPI_LV_INFO); break; case AML_INDEX_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: Index %p\n", - entry_desc->reference.object)); + acpi_os_printf ("Reference: Index %p\n", + obj_desc->reference.object); break; case AML_ARG_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: Arg%d", - entry_desc->reference.offset)); + acpi_os_printf ("Reference: Arg%d", + obj_desc->reference.offset); - if (ACPI_TYPE_INTEGER == entry_desc->common.type) { + if (ACPI_TYPE_INTEGER == obj_desc->common.type) { /* Value is a Number */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, " value is [%8.8X%8.8x]", - HIDWORD(entry_desc->integer.value), - LODWORD(entry_desc->integer.value))); + acpi_os_printf (" value is [%8.8X%8.8x]", + ACPI_HIDWORD(obj_desc->integer.value), + ACPI_LODWORD(obj_desc->integer.value)); } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n")); + acpi_os_printf ("\n"); break; case AML_LOCAL_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference: Local%d", - entry_desc->reference.offset)); + acpi_os_printf ("Reference: Local%d", + obj_desc->reference.offset); - if (ACPI_TYPE_INTEGER == entry_desc->common.type) { + if (ACPI_TYPE_INTEGER == obj_desc->common.type) { /* Value is a Number */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, " value is [%8.8X%8.8x]", - HIDWORD(entry_desc->integer.value), - LODWORD(entry_desc->integer.value))); + acpi_os_printf (" value is [%8.8X%8.8x]", + ACPI_HIDWORD(obj_desc->integer.value), + ACPI_LODWORD(obj_desc->integer.value)); } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n")); + acpi_os_printf ("\n"); break; case AML_INT_NAMEPATH_OP: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Reference.Node->Name %X\n", - entry_desc->reference.node->name)); + acpi_os_printf ("Reference.Node->Name %X\n", + obj_desc->reference.node->name.integer); break; default: /* unknown opcode */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Unknown opcode=%X\n", - entry_desc->reference.opcode)); + acpi_os_printf ("Unknown opcode=%X\n", + obj_desc->reference.opcode); break; } @@ -275,11 +200,11 @@ case ACPI_TYPE_BUFFER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Buffer len %X @ %p \n", - entry_desc->buffer.length, - entry_desc->buffer.pointer)); + acpi_os_printf ("Buffer len %X @ %p \n", + obj_desc->buffer.length, + obj_desc->buffer.pointer); - length = entry_desc->buffer.length; + length = obj_desc->buffer.length; if (length > 64) { length = 64; @@ -287,13 +212,13 @@ /* Debug only -- dump the buffer contents */ - if (entry_desc->buffer.pointer) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Buffer Contents: ")); + if (obj_desc->buffer.pointer) { + acpi_os_printf ("Buffer Contents: "); - for (buf = entry_desc->buffer.pointer; length--; ++buf) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, " %02x", *buf)); + for (buf = obj_desc->buffer.pointer; length--; ++buf) { + acpi_os_printf (" %02x", *buf); } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO,"\n")); + acpi_os_printf ("\n"); } break; @@ -301,135 +226,128 @@ case ACPI_TYPE_INTEGER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Integer %8.8X%8.8X\n", - HIDWORD (entry_desc->integer.value), - LODWORD (entry_desc->integer.value))); + acpi_os_printf ("Integer %8.8X%8.8X\n", + ACPI_HIDWORD (obj_desc->integer.value), + ACPI_LODWORD (obj_desc->integer.value)); break; case INTERNAL_TYPE_IF: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "If [Integer] %8.8X%8.8X\n", - HIDWORD (entry_desc->integer.value), - LODWORD (entry_desc->integer.value))); + acpi_os_printf ("If [Integer] %8.8X%8.8X\n", + ACPI_HIDWORD (obj_desc->integer.value), + ACPI_LODWORD (obj_desc->integer.value)); break; case INTERNAL_TYPE_WHILE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "While [Integer] %8.8X%8.8X\n", - HIDWORD (entry_desc->integer.value), - LODWORD (entry_desc->integer.value))); + acpi_os_printf ("While [Integer] %8.8X%8.8X\n", + ACPI_HIDWORD (obj_desc->integer.value), + ACPI_LODWORD (obj_desc->integer.value)); break; case ACPI_TYPE_PACKAGE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Package count %X @ %p\n", - entry_desc->package.count, entry_desc->package.elements)); + acpi_os_printf ("Package count %X @ %p\n", + obj_desc->package.count, obj_desc->package.elements); /* * If elements exist, package vector pointer is valid, * and debug_level exceeds 1, dump package's elements. */ - if (entry_desc->package.count && - entry_desc->package.elements && + if (obj_desc->package.count && + obj_desc->package.elements && acpi_dbg_level > 1) { - acpi_operand_object**element; - u16 element_index; - - for (element_index = 0, element = entry_desc->package.elements; - element_index < entry_desc->package.count; + for (element_index = 0, element = obj_desc->package.elements; + element_index < obj_desc->package.count; ++element_index, ++element) { acpi_ex_dump_operand (*element); } } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n")); - + acpi_os_printf ("\n"); break; case ACPI_TYPE_REGION: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Region %s (%X)", - acpi_ut_get_region_name (entry_desc->region.space_id), - entry_desc->region.space_id)); + acpi_os_printf ("Region %s (%X)", + acpi_ut_get_region_name (obj_desc->region.space_id), + obj_desc->region.space_id); /* * If the address and length have not been evaluated, * don't print them. */ - if (!(entry_desc->region.flags & AOPOBJ_DATA_VALID)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n")); + if (!(obj_desc->region.flags & AOPOBJ_DATA_VALID)) { + acpi_os_printf ("\n"); } else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, " base %8.8X%8.8X Length %X\n", - HIDWORD(entry_desc->region.address), - LODWORD(entry_desc->region.address), - entry_desc->region.length)); + acpi_os_printf (" base %8.8X%8.8X Length %X\n", + ACPI_HIDWORD (obj_desc->region.address), + ACPI_LODWORD (obj_desc->region.address), + obj_desc->region.length); } break; case ACPI_TYPE_STRING: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "String length %X @ %p \"", - entry_desc->string.length, entry_desc->string.pointer)); + acpi_os_printf ("String length %X @ %p \"", + obj_desc->string.length, obj_desc->string.pointer); - for (i = 0; i < entry_desc->string.length; i++) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "%c", - entry_desc->string.pointer[i])); + for (i = 0; i < obj_desc->string.length; i++) { + acpi_os_printf ("%c", + obj_desc->string.pointer[i]); } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\"\n")); + acpi_os_printf ("\"\n"); break; case INTERNAL_TYPE_BANK_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Bank_field\n")); + acpi_os_printf ("Bank_field\n"); break; case INTERNAL_TYPE_REGION_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, - "Region_field: bits=%X bitaccwidth=%X lock=%X update=%X at byte=%X bit=%X of below:\n", - entry_desc->field.bit_length, entry_desc->field.access_bit_width, - entry_desc->field.lock_rule, entry_desc->field.update_rule, - entry_desc->field.base_byte_offset, entry_desc->field.start_field_bit_offset)); - DUMP_STACK_ENTRY (entry_desc->field.region_obj); + acpi_os_printf ( + "Region_field: Bits=%X Acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n", + obj_desc->field.bit_length, obj_desc->field.access_byte_width, + obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK, + obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK, + obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset); + ACPI_DUMP_STACK_ENTRY (obj_desc->field.region_obj); break; case INTERNAL_TYPE_INDEX_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Index_field\n")); + acpi_os_printf ("Index_field\n"); break; case ACPI_TYPE_BUFFER_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, + acpi_os_printf ( "Buffer_field: %X bits at byte %X bit %X of \n", - entry_desc->buffer_field.bit_length, entry_desc->buffer_field.base_byte_offset, - entry_desc->buffer_field.start_field_bit_offset)); + obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset, + obj_desc->buffer_field.start_field_bit_offset); - if (!entry_desc->buffer_field.buffer_obj) + if (!obj_desc->buffer_field.buffer_obj) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "*NULL* \n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n")); } - else if (ACPI_TYPE_BUFFER != - entry_desc->buffer_field.buffer_obj->common.type) + obj_desc->buffer_field.buffer_obj->common.type) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "*not a Buffer* \n")); + acpi_os_printf ("*not a Buffer* \n"); } - else { - DUMP_STACK_ENTRY (entry_desc->buffer_field.buffer_obj); + ACPI_DUMP_STACK_ENTRY (obj_desc->buffer_field.buffer_obj); } break; @@ -437,71 +355,57 @@ case ACPI_TYPE_EVENT: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Event\n")); + acpi_os_printf ("Event\n"); break; case ACPI_TYPE_METHOD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, + acpi_os_printf ( "Method(%X) @ %p:%X\n", - entry_desc->method.param_count, - entry_desc->method.aml_start, entry_desc->method.aml_length)); + obj_desc->method.param_count, + obj_desc->method.aml_start, obj_desc->method.aml_length); break; case ACPI_TYPE_MUTEX: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Mutex\n")); + acpi_os_printf ("Mutex\n"); break; case ACPI_TYPE_DEVICE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Device\n")); + acpi_os_printf ("Device\n"); break; case ACPI_TYPE_POWER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Power\n")); + acpi_os_printf ("Power\n"); break; case ACPI_TYPE_PROCESSOR: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Processor\n")); + acpi_os_printf ("Processor\n"); break; case ACPI_TYPE_THERMAL: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Thermal\n")); + acpi_os_printf ("Thermal\n"); break; default: - /* unknown Entry_desc->Common.Type value */ - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "Unknown Type %X\n", - entry_desc->common.type)); - - /* Back up to previous entry */ - - entry_desc--; + /* Unknown Obj_desc->Common.Type value */ - - /* TBD: [Restructure] Change to use dump object routine !! */ - /* What is all of this?? */ - - DUMP_BUFFER (entry_desc, sizeof (acpi_operand_object)); - DUMP_BUFFER (++entry_desc, sizeof (acpi_operand_object)); - DUMP_BUFFER (++entry_desc, sizeof (acpi_operand_object)); + acpi_os_printf ("Unknown Type %X\n", obj_desc->common.type); break; - } - return (AE_OK); + return; } @@ -521,7 +425,7 @@ void acpi_ex_dump_operands ( acpi_operand_object **operands, - operating_mode interpreter_mode, + acpi_interpreter_mode interpreter_mode, NATIVE_CHAR *ident, u32 num_levels, NATIVE_CHAR *note, @@ -529,10 +433,10 @@ u32 line_number) { NATIVE_UINT i; - acpi_operand_object **entry_desc; + acpi_operand_object **obj_desc; - PROC_NAME ("Ex_dump_operands"); + ACPI_FUNCTION_NAME ("Ex_dump_operands"); if (!ident) @@ -545,8 +449,7 @@ note = "?"; } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "************* Operand Stack Contents (Opcode [%s], %d Operands)\n", ident, num_levels)); @@ -555,19 +458,15 @@ num_levels = 1; } - /* Dump the stack starting at the top, working down */ + /* Dump the operand stack starting at the top */ for (i = 0; num_levels > 0; i--, num_levels--) { - entry_desc = &operands[i]; - - if (ACPI_FAILURE (acpi_ex_dump_operand (*entry_desc))) - { - break; - } + obj_desc = &operands[i]; + acpi_ex_dump_operand (*obj_desc); } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "************* Stack dump from %s(%d), %s\n", module_name, line_number, note)); return; @@ -576,6 +475,58 @@ /***************************************************************************** * + * FUNCTION: Acpi_ex_out* + * + * PARAMETERS: Title - Descriptive text + * Value - Value to be displayed + * + * DESCRIPTION: Object dump output formatting functions. These functions + * reduce the number of format strings required and keeps them + * all in one place for easy modification. + * + ****************************************************************************/ + +void +acpi_ex_out_string ( + char *title, + char *value) +{ + acpi_os_printf ("%20s : %s\n", title, value); +} + +void +acpi_ex_out_pointer ( + char *title, + void *value) +{ + acpi_os_printf ("%20s : %p\n", title, value); +} + +void +acpi_ex_out_integer ( + char *title, + u32 value) +{ + acpi_os_printf ("%20s : %X\n", title, value); +} + +void +acpi_ex_out_address ( + char *title, + ACPI_PHYSICAL_ADDRESS value) +{ + +#if ACPI_MACHINE_WIDTH == 16 + acpi_os_printf ("%20s : %p\n", title, value); +#else + acpi_os_printf ("%20s : %8.8X%8.8X\n", title, + ACPI_HIDWORD (value), ACPI_LODWORD (value)); +#endif +} + + +/***************************************************************************** + * * FUNCTION: Acpi_ex_dump_node * * PARAMETERS: *Node - Descriptor to dump @@ -591,7 +542,7 @@ u32 flags) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (!flags) @@ -602,16 +553,15 @@ } } - - acpi_os_printf ("%20s : %4.4s\n", "Name", (char*)&node->name); - acpi_os_printf ("%20s : %s\n", "Type", acpi_ut_get_type_name (node->type)); - acpi_os_printf ("%20s : %X\n", "Flags", node->flags); - acpi_os_printf ("%20s : %X\n", "Owner Id", node->owner_id); - acpi_os_printf ("%20s : %X\n", "Reference Count", node->reference_count); - acpi_os_printf ("%20s : %p\n", "Attached Object", node->object); - acpi_os_printf ("%20s : %p\n", "Child_list", node->child); - acpi_os_printf ("%20s : %p\n", "Next_peer", node->peer); - acpi_os_printf ("%20s : %p\n", "Parent", acpi_ns_get_parent_object (node)); + acpi_os_printf ("%20s : %4.4s\n", "Name", node->name.ascii); + acpi_ex_out_string ("Type", acpi_ut_get_type_name (node->type)); + acpi_ex_out_integer ("Flags", node->flags); + acpi_ex_out_integer ("Owner Id", node->owner_id); + acpi_ex_out_integer ("Reference Count", node->reference_count); + acpi_ex_out_pointer ("Attached Object", acpi_ns_get_attached_object (node)); + acpi_ex_out_pointer ("Child_list", node->child); + acpi_ex_out_pointer ("Next_peer", node->peer); + acpi_ex_out_pointer ("Parent", acpi_ns_get_parent_node (node)); } @@ -631,10 +581,10 @@ acpi_operand_object *obj_desc, u32 flags) { - const acpi_opcode_info *op_info; + u32 i; - FUNCTION_TRACE ("Ex_dump_object_descriptor"); + ACPI_FUNCTION_TRACE ("Ex_dump_object_descriptor"); if (!flags) @@ -645,16 +595,17 @@ } } - if (!(VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL))) + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { - acpi_os_printf ("%p is not a valid ACPI object\n", obj_desc); + acpi_os_printf ("Ex_dump_object_descriptor: %p is not a valid ACPI object\n", obj_desc); return; } /* Common Fields */ - acpi_os_printf ("%20s : %X\n", "Reference Count", obj_desc->common.reference_count); - acpi_os_printf ("%20s : %X\n", "Flags", obj_desc->common.flags); + acpi_ex_out_string ("Type", acpi_ut_get_type_name (obj_desc->common.type)); + acpi_ex_out_integer ("Reference Count", obj_desc->common.reference_count); + acpi_ex_out_integer ("Flags", obj_desc->common.flags); /* Object-specific Fields */ @@ -662,198 +613,192 @@ { case ACPI_TYPE_INTEGER: - acpi_os_printf ("%20s : %s\n", "Type", "Integer"); - acpi_os_printf ("%20s : %X%8.8X\n", "Value", HIDWORD (obj_desc->integer.value), - LODWORD (obj_desc->integer.value)); + acpi_os_printf ("%20s : %8.8X%8.8X\n", "Value", + ACPI_HIDWORD (obj_desc->integer.value), + ACPI_LODWORD (obj_desc->integer.value)); break; case ACPI_TYPE_STRING: - acpi_os_printf ("%20s : %s\n", "Type", "String"); - acpi_os_printf ("%20s : %X\n", "Length", obj_desc->string.length); - acpi_os_printf ("%20s : %p\n", "Pointer", obj_desc->string.pointer); + acpi_ex_out_integer ("Length", obj_desc->string.length); + acpi_ex_out_pointer ("Pointer", obj_desc->string.pointer); break; case ACPI_TYPE_BUFFER: - acpi_os_printf ("%20s : %s\n", "Type", "Buffer"); - acpi_os_printf ("%20s : %X\n", "Length", obj_desc->buffer.length); - acpi_os_printf ("%20s : %p\n", "Pointer", obj_desc->buffer.pointer); + acpi_ex_out_integer ("Length", obj_desc->buffer.length); + acpi_ex_out_pointer ("Pointer", obj_desc->buffer.pointer); break; case ACPI_TYPE_PACKAGE: - acpi_os_printf ("%20s : %s\n", "Type", "Package"); - acpi_os_printf ("%20s : %X\n", "Flags", obj_desc->package.flags); - acpi_os_printf ("%20s : %X\n", "Count", obj_desc->package.count); - acpi_os_printf ("%20s : %p\n", "Elements", obj_desc->package.elements); - acpi_os_printf ("%20s : %p\n", "Next_element", obj_desc->package.next_element); - break; + acpi_ex_out_integer ("Flags", obj_desc->package.flags); + acpi_ex_out_integer ("Count", obj_desc->package.count); + acpi_ex_out_pointer ("Elements", obj_desc->package.elements); + /* Dump the package contents */ - case ACPI_TYPE_BUFFER_FIELD: - - acpi_os_printf ("%20s : %s\n", "Type", "Buffer_field"); - acpi_os_printf ("%20s : %X\n", "Bit_length", obj_desc->buffer_field.bit_length); - acpi_os_printf ("%20s : %X\n", "Bit_offset", obj_desc->buffer_field.start_field_bit_offset); - acpi_os_printf ("%20s : %X\n", "Base_byte_offset",obj_desc->buffer_field.base_byte_offset); - acpi_os_printf ("%20s : %p\n", "Buffer_obj", obj_desc->buffer_field.buffer_obj); + if (obj_desc->package.count > 0) + { + acpi_os_printf ("\n_package Contents:\n"); + for (i = 0; i < obj_desc->package.count; i++) + { + acpi_os_printf ("[%.3d] %p", i, obj_desc->package.elements[i]); + if (obj_desc->package.elements[i]) + { + acpi_os_printf (" %s", acpi_ut_get_type_name ((obj_desc->package.elements[i])->common.type)); + } + acpi_os_printf ("\n"); + } + } break; case ACPI_TYPE_DEVICE: - acpi_os_printf ("%20s : %s\n", "Type", "Device"); - acpi_os_printf ("%20s : %p\n", "Addr_handler", obj_desc->device.addr_handler); - acpi_os_printf ("%20s : %p\n", "Sys_handler", obj_desc->device.sys_handler); - acpi_os_printf ("%20s : %p\n", "Drv_handler", obj_desc->device.drv_handler); + acpi_ex_out_pointer ("Addr_handler", obj_desc->device.addr_handler); + acpi_ex_out_pointer ("Sys_handler", obj_desc->device.sys_handler); + acpi_ex_out_pointer ("Drv_handler", obj_desc->device.drv_handler); break; + case ACPI_TYPE_EVENT: - acpi_os_printf ("%20s : %s\n", "Type", "Event"); - acpi_os_printf ("%20s : %X\n", "Semaphore", obj_desc->event.semaphore); + acpi_ex_out_pointer ("Semaphore", obj_desc->event.semaphore); break; case ACPI_TYPE_METHOD: - acpi_os_printf ("%20s : %s\n", "Type", "Method"); - acpi_os_printf ("%20s : %X\n", "Param_count", obj_desc->method.param_count); - acpi_os_printf ("%20s : %X\n", "Concurrency", obj_desc->method.concurrency); - acpi_os_printf ("%20s : %p\n", "Semaphore", obj_desc->method.semaphore); - acpi_os_printf ("%20s : %X\n", "Aml_length", obj_desc->method.aml_length); - acpi_os_printf ("%20s : %X\n", "Aml_start", obj_desc->method.aml_start); + acpi_ex_out_integer ("Param_count", obj_desc->method.param_count); + acpi_ex_out_integer ("Concurrency", obj_desc->method.concurrency); + acpi_ex_out_pointer ("Semaphore", obj_desc->method.semaphore); + acpi_ex_out_integer ("Owning_id", obj_desc->method.owning_id); + acpi_ex_out_integer ("Aml_length", obj_desc->method.aml_length); + acpi_ex_out_pointer ("Aml_start", obj_desc->method.aml_start); break; case ACPI_TYPE_MUTEX: - acpi_os_printf ("%20s : %s\n", "Type", "Mutex"); - acpi_os_printf ("%20s : %X\n", "Sync_level", obj_desc->mutex.sync_level); - acpi_os_printf ("%20s : %p\n", "Owner", obj_desc->mutex.owner); - acpi_os_printf ("%20s : %X\n", "Acquisition_depth", obj_desc->mutex.acquisition_depth); - acpi_os_printf ("%20s : %p\n", "Semaphore", obj_desc->mutex.semaphore); + acpi_ex_out_integer ("Sync_level", obj_desc->mutex.sync_level); + acpi_ex_out_pointer ("Owner_thread", obj_desc->mutex.owner_thread); + acpi_ex_out_integer ("Acquisition_depth",obj_desc->mutex.acquisition_depth); + acpi_ex_out_pointer ("Semaphore", obj_desc->mutex.semaphore); break; case ACPI_TYPE_REGION: - acpi_os_printf ("%20s : %s\n", "Type", "Region"); - acpi_os_printf ("%20s : %X\n", "Space_id", obj_desc->region.space_id); - acpi_os_printf ("%20s : %X\n", "Flags", obj_desc->region.flags); - acpi_os_printf ("%20s : %X\n", "Address", obj_desc->region.address); - acpi_os_printf ("%20s : %X\n", "Length", obj_desc->region.length); - acpi_os_printf ("%20s : %p\n", "Addr_handler", obj_desc->region.addr_handler); - acpi_os_printf ("%20s : %p\n", "Next", obj_desc->region.next); + acpi_ex_out_integer ("Space_id", obj_desc->region.space_id); + acpi_ex_out_integer ("Flags", obj_desc->region.flags); + acpi_ex_out_address ("Address", obj_desc->region.address); + acpi_ex_out_integer ("Length", obj_desc->region.length); + acpi_ex_out_pointer ("Addr_handler", obj_desc->region.addr_handler); + acpi_ex_out_pointer ("Next", obj_desc->region.next); break; case ACPI_TYPE_POWER: - acpi_os_printf ("%20s : %s\n", "Type", "Power_resource"); - acpi_os_printf ("%20s : %X\n", "System_level", obj_desc->power_resource.system_level); - acpi_os_printf ("%20s : %X\n", "Resource_order", obj_desc->power_resource.resource_order); - acpi_os_printf ("%20s : %p\n", "Sys_handler", obj_desc->power_resource.sys_handler); - acpi_os_printf ("%20s : %p\n", "Drv_handler", obj_desc->power_resource.drv_handler); + acpi_ex_out_integer ("System_level", obj_desc->power_resource.system_level); + acpi_ex_out_integer ("Resource_order", obj_desc->power_resource.resource_order); + acpi_ex_out_pointer ("Sys_handler", obj_desc->power_resource.sys_handler); + acpi_ex_out_pointer ("Drv_handler", obj_desc->power_resource.drv_handler); break; case ACPI_TYPE_PROCESSOR: - acpi_os_printf ("%20s : %s\n", "Type", "Processor"); - acpi_os_printf ("%20s : %X\n", "Processor ID", obj_desc->processor.proc_id); - acpi_os_printf ("%20s : %X\n", "Length", obj_desc->processor.length); - acpi_os_printf ("%20s : %X\n", "Address", obj_desc->processor.address); - acpi_os_printf ("%20s : %p\n", "Sys_handler", obj_desc->processor.sys_handler); - acpi_os_printf ("%20s : %p\n", "Drv_handler", obj_desc->processor.drv_handler); - acpi_os_printf ("%20s : %p\n", "Addr_handler", obj_desc->processor.addr_handler); + acpi_ex_out_integer ("Processor ID", obj_desc->processor.proc_id); + acpi_ex_out_integer ("Length", obj_desc->processor.length); + acpi_ex_out_address ("Address", (ACPI_PHYSICAL_ADDRESS) obj_desc->processor.address); + acpi_ex_out_pointer ("Sys_handler", obj_desc->processor.sys_handler); + acpi_ex_out_pointer ("Drv_handler", obj_desc->processor.drv_handler); + acpi_ex_out_pointer ("Addr_handler", obj_desc->processor.addr_handler); break; case ACPI_TYPE_THERMAL: - acpi_os_printf ("%20s : %s\n", "Type", "Thermal_zone"); - acpi_os_printf ("%20s : %p\n", "Sys_handler", obj_desc->thermal_zone.sys_handler); - acpi_os_printf ("%20s : %p\n", "Drv_handler", obj_desc->thermal_zone.drv_handler); - acpi_os_printf ("%20s : %p\n", "Addr_handler", obj_desc->thermal_zone.addr_handler); + acpi_ex_out_pointer ("Sys_handler", obj_desc->thermal_zone.sys_handler); + acpi_ex_out_pointer ("Drv_handler", obj_desc->thermal_zone.drv_handler); + acpi_ex_out_pointer ("Addr_handler", obj_desc->thermal_zone.addr_handler); break; + case ACPI_TYPE_BUFFER_FIELD: case INTERNAL_TYPE_REGION_FIELD: + case INTERNAL_TYPE_BANK_FIELD: + case INTERNAL_TYPE_INDEX_FIELD: - acpi_os_printf ("%20s : %p\n", "Access_bit_width", obj_desc->field.access_bit_width); - acpi_os_printf ("%20s : %p\n", "Bit_length", obj_desc->field.bit_length); - acpi_os_printf ("%20s : %p\n", "Base_byte_offset",obj_desc->field.base_byte_offset); - acpi_os_printf ("%20s : %p\n", "Bit_offset", obj_desc->field.start_field_bit_offset); - acpi_os_printf ("%20s : %p\n", "Region_obj", obj_desc->field.region_obj); - break; - + acpi_ex_out_integer ("Field_flags", obj_desc->common_field.field_flags); + acpi_ex_out_integer ("Access_byte_width", obj_desc->common_field.access_byte_width); + acpi_ex_out_integer ("Bit_length", obj_desc->common_field.bit_length); + acpi_ex_out_integer ("Fld_bit_offset", obj_desc->common_field.start_field_bit_offset); + acpi_ex_out_integer ("Base_byte_offset", obj_desc->common_field.base_byte_offset); + acpi_ex_out_integer ("Datum_valid_bits", obj_desc->common_field.datum_valid_bits); + acpi_ex_out_integer ("End_fld_valid_bits", obj_desc->common_field.end_field_valid_bits); + acpi_ex_out_integer ("End_buf_valid_bits", obj_desc->common_field.end_buffer_valid_bits); + acpi_ex_out_pointer ("Parent_node", obj_desc->common_field.node); - case INTERNAL_TYPE_BANK_FIELD: + switch (obj_desc->common.type) + { + case ACPI_TYPE_BUFFER_FIELD: + acpi_ex_out_pointer ("Buffer_obj", obj_desc->buffer_field.buffer_obj); + break; - acpi_os_printf ("%20s : %s\n", "Type", "Bank_field"); - acpi_os_printf ("%20s : %X\n", "Access_bit_width", obj_desc->bank_field.access_bit_width); - acpi_os_printf ("%20s : %X\n", "Lock_rule", obj_desc->bank_field.lock_rule); - acpi_os_printf ("%20s : %X\n", "Update_rule", obj_desc->bank_field.update_rule); - acpi_os_printf ("%20s : %X\n", "Bit_length", obj_desc->bank_field.bit_length); - acpi_os_printf ("%20s : %X\n", "Bit_offset", obj_desc->bank_field.start_field_bit_offset); - acpi_os_printf ("%20s : %X\n", "Base_byte_offset", obj_desc->bank_field.base_byte_offset); - acpi_os_printf ("%20s : %X\n", "Value", obj_desc->bank_field.value); - acpi_os_printf ("%20s : %p\n", "Region_obj", obj_desc->bank_field.region_obj); - acpi_os_printf ("%20s : %X\n", "Bank_register_obj", obj_desc->bank_field.bank_register_obj); - break; + case INTERNAL_TYPE_REGION_FIELD: + acpi_ex_out_pointer ("Region_obj", obj_desc->field.region_obj); + break; + case INTERNAL_TYPE_BANK_FIELD: + acpi_ex_out_integer ("Value", obj_desc->bank_field.value); + acpi_ex_out_pointer ("Region_obj", obj_desc->bank_field.region_obj); + acpi_ex_out_pointer ("Bank_obj", obj_desc->bank_field.bank_obj); + break; - case INTERNAL_TYPE_INDEX_FIELD: + case INTERNAL_TYPE_INDEX_FIELD: + acpi_ex_out_integer ("Value", obj_desc->index_field.value); + acpi_ex_out_pointer ("Index", obj_desc->index_field.index_obj); + acpi_ex_out_pointer ("Data", obj_desc->index_field.data_obj); + break; - acpi_os_printf ("%20s : %s\n", "Type", "Index_field"); - acpi_os_printf ("%20s : %X\n", "Access_bit_width", obj_desc->index_field.access_bit_width); - acpi_os_printf ("%20s : %X\n", "Lock_rule", obj_desc->index_field.lock_rule); - acpi_os_printf ("%20s : %X\n", "Update_rule", obj_desc->index_field.update_rule); - acpi_os_printf ("%20s : %X\n", "Bit_length", obj_desc->index_field.bit_length); - acpi_os_printf ("%20s : %X\n", "Bit_offset", obj_desc->index_field.start_field_bit_offset); - acpi_os_printf ("%20s : %X\n", "Value", obj_desc->index_field.value); - acpi_os_printf ("%20s : %X\n", "Index", obj_desc->index_field.index_obj); - acpi_os_printf ("%20s : %X\n", "Data", obj_desc->index_field.data_obj); + default: + /* All object types covered above */ + break; + } break; case INTERNAL_TYPE_REFERENCE: - op_info = acpi_ps_get_opcode_info (obj_desc->reference.opcode); - - acpi_os_printf ("%20s : %s\n", "Type", "Reference"); - acpi_os_printf ("%20s : %X\n", "Target_type", obj_desc->reference.target_type); - acpi_os_printf ("%20s : %s\n", "Opcode", op_info->name); - acpi_os_printf ("%20s : %X\n", "Offset", obj_desc->reference.offset); - acpi_os_printf ("%20s : %p\n", "Obj_desc", obj_desc->reference.object); - acpi_os_printf ("%20s : %p\n", "Node", obj_desc->reference.node); - acpi_os_printf ("%20s : %p\n", "Where", obj_desc->reference.where); + acpi_ex_out_integer ("Target_type", obj_desc->reference.target_type); + acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name); + acpi_ex_out_integer ("Offset", obj_desc->reference.offset); + acpi_ex_out_pointer ("Obj_desc", obj_desc->reference.object); + acpi_ex_out_pointer ("Node", obj_desc->reference.node); + acpi_ex_out_pointer ("Where", obj_desc->reference.where); break; case INTERNAL_TYPE_ADDRESS_HANDLER: - acpi_os_printf ("%20s : %s\n", "Type", "Address Handler"); - acpi_os_printf ("%20s : %X\n", "Space_id", obj_desc->addr_handler.space_id); - acpi_os_printf ("%20s : %p\n", "Next", obj_desc->addr_handler.next); - acpi_os_printf ("%20s : %p\n", "Region_list", obj_desc->addr_handler.region_list); - acpi_os_printf ("%20s : %p\n", "Node", obj_desc->addr_handler.node); - acpi_os_printf ("%20s : %p\n", "Handler", obj_desc->addr_handler.handler); - acpi_os_printf ("%20s : %p\n", "Context", obj_desc->addr_handler.context); + acpi_ex_out_integer ("Space_id", obj_desc->addr_handler.space_id); + acpi_ex_out_pointer ("Next", obj_desc->addr_handler.next); + acpi_ex_out_pointer ("Region_list", obj_desc->addr_handler.region_list); + acpi_ex_out_pointer ("Node", obj_desc->addr_handler.node); + acpi_ex_out_pointer ("Context", obj_desc->addr_handler.context); break; case INTERNAL_TYPE_NOTIFY: - acpi_os_printf ("%20s : %s\n", "Type", "Notify Handler"); - acpi_os_printf ("%20s : %p\n", "Node", obj_desc->notify_handler.node); - acpi_os_printf ("%20s : %p\n", "Handler", obj_desc->notify_handler.handler); - acpi_os_printf ("%20s : %p\n", "Context", obj_desc->notify_handler.context); + acpi_ex_out_pointer ("Node", obj_desc->notify_handler.node); + acpi_ex_out_pointer ("Context", obj_desc->notify_handler.context); break; @@ -866,15 +811,17 @@ case INTERNAL_TYPE_WHILE: case INTERNAL_TYPE_SCOPE: case INTERNAL_TYPE_DEF_ANY: + case INTERNAL_TYPE_EXTRA: + case INTERNAL_TYPE_DATA: - acpi_os_printf ("*** Structure display not implemented for type %X! ***\n", + acpi_os_printf ("Ex_dump_object_descriptor: Display not implemented for object type %X\n", obj_desc->common.type); break; default: - acpi_os_printf ("*** Cannot display unknown type %X! ***\n", obj_desc->common.type); + acpi_os_printf ("Ex_dump_object_descriptor: Unknown object type %X\n", obj_desc->common.type); break; } diff -Nur linux-2.4.19/drivers/acpi/executer/exfield.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exfield.c --- linux-2.4.19/drivers/acpi/executer/exfield.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exfield.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: exfield - ACPI AML (p-code) execution - field manipulation - * $Revision: 95 $ + * $Revision: 110 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,33 +27,30 @@ #include "acpi.h" #include "acdispat.h" #include "acinterp.h" -#include "amlcode.h" -#include "acnamesp.h" -#include "achware.h" -#include "acevents.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exfield") + ACPI_MODULE_NAME ("exfield") /******************************************************************************* * * FUNCTION: Acpi_ex_read_data_from_field * - * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE - * *Field_node - Parent node for field to be accessed - * *Buffer - Value(s) to be read or written - * Buffer_length - Number of bytes to transfer + * PARAMETERS: Walk_state - Current execution state + * Obj_desc - The named field + * Ret_buffer_desc - Where the return data object is stored * - * RETURN: Status3 + * RETURN: Status * - * DESCRIPTION: Read or write a named field + * DESCRIPTION: Read from a named field. Returns either an Integer or a + * Buffer, depending on the size of the field. * ******************************************************************************/ acpi_status acpi_ex_read_data_from_field ( + acpi_walk_state *walk_state, acpi_operand_object *obj_desc, acpi_operand_object **ret_buffer_desc) { @@ -61,9 +58,10 @@ acpi_operand_object *buffer_desc; u32 length; void *buffer; + u8 locked; - FUNCTION_TRACE_PTR ("Ex_read_data_from_field", obj_desc); + ACPI_FUNCTION_TRACE_PTR ("Ex_read_data_from_field", obj_desc); /* Parameter validation */ @@ -72,6 +70,19 @@ return_ACPI_STATUS (AE_AML_NO_OPERAND); } + if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { + /* + * If the Buffer_field arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_buffer_field_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } + /* * Allocate a buffer for the contents of the field. * @@ -82,9 +93,8 @@ * * Note: Field.length is in bits. */ - length = ROUND_BITS_UP_TO_BYTES (obj_desc->field.bit_length); - - if (length > sizeof (acpi_integer)) { + length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->field.bit_length); + if (length > acpi_gbl_integer_byte_width) { /* Field is too large for an Integer, create a Buffer instead */ buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); @@ -100,10 +110,10 @@ return_ACPI_STATUS (AE_NO_MEMORY); } + buffer_desc->common.flags = AOPOBJ_DATA_VALID; buffer_desc->buffer.length = length; buffer = buffer_desc->buffer.pointer; } - else { /* Field will fit within an Integer (normal case) */ @@ -112,39 +122,34 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - length = sizeof (buffer_desc->integer.value); + length = acpi_gbl_integer_byte_width; + buffer_desc->integer.value = 0; buffer = &buffer_desc->integer.value; } + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Obj=%p Type=%X Buf=%p Len=%X\n", + obj_desc, obj_desc->common.type, buffer, length)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field_write: Bit_len=%X Bit_off=%X Byte_off=%X\n", + obj_desc->common_field.bit_length, + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.base_byte_offset)); - /* Read from the appropriate field */ - - switch (obj_desc->common.type) { - case ACPI_TYPE_BUFFER_FIELD: - status = acpi_ex_access_buffer_field (ACPI_READ, obj_desc, buffer, length); - break; - - case INTERNAL_TYPE_REGION_FIELD: - status = acpi_ex_access_region_field (ACPI_READ, obj_desc, buffer, length); - break; - - case INTERNAL_TYPE_BANK_FIELD: - status = acpi_ex_access_bank_field (ACPI_READ, obj_desc, buffer, length); - break; + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); - case INTERNAL_TYPE_INDEX_FIELD: - status = acpi_ex_access_index_field (ACPI_READ, obj_desc, buffer, length); - break; + /* Read from the field */ - default: - status = AE_AML_INTERNAL; - } + status = acpi_ex_extract_from_field (obj_desc, buffer, length); + /* + * Release global lock if we acquired it earlier + */ + acpi_ex_release_global_lock (locked); if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (buffer_desc); } - else if (ret_buffer_desc) { *ret_buffer_desc = buffer_desc; } @@ -157,18 +162,15 @@ * * FUNCTION: Acpi_ex_write_data_to_field * - * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE - * *Field_node - Parent node for field to be accessed - * *Buffer - Value(s) to be read or written - * Buffer_length - Number of bytes to transfer + * PARAMETERS: Source_desc - Contains data to write + * Obj_desc - The named field * * RETURN: Status * - * DESCRIPTION: Read or write a named field + * DESCRIPTION: Write to a named field * ******************************************************************************/ - acpi_status acpi_ex_write_data_to_field ( acpi_operand_object *source_desc, @@ -176,10 +178,13 @@ { acpi_status status; u32 length; + u32 required_length; void *buffer; + void *new_buffer; + u8 locked; - FUNCTION_TRACE_PTR ("Ex_write_data_to_field", obj_desc); + ACPI_FUNCTION_TRACE_PTR ("Ex_write_data_to_field", obj_desc); /* Parameter validation */ @@ -188,6 +193,18 @@ return_ACPI_STATUS (AE_AML_NO_OPERAND); } + if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { + /* + * If the Buffer_field arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_buffer_field_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } /* * Get a pointer to the data to be written @@ -212,315 +229,61 @@ return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } - /* - * Decode the type of field to be written + * We must have a buffer that is at least as long as the field + * we are writing to. This is because individual fields are + * indivisible and partial writes are not supported -- as per + * the ACPI specification. */ - switch (obj_desc->common.type) { - case ACPI_TYPE_BUFFER_FIELD: - status = acpi_ex_access_buffer_field (ACPI_WRITE, obj_desc, buffer, length); - break; - - case INTERNAL_TYPE_REGION_FIELD: - status = acpi_ex_access_region_field (ACPI_WRITE, obj_desc, buffer, length); - break; - - case INTERNAL_TYPE_BANK_FIELD: - status = acpi_ex_access_bank_field (ACPI_WRITE, obj_desc, buffer, length); - break; - - case INTERNAL_TYPE_INDEX_FIELD: - status = acpi_ex_access_index_field (ACPI_WRITE, obj_desc, buffer, length); - break; - - default: - return_ACPI_STATUS (AE_AML_INTERNAL); - } - - - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_access_buffer_field - * - * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE - * *Field_node - Parent node for field to be accessed - * *Buffer - Value(s) to be read or written - * Buffer_length - Number of bytes to transfer - * - * RETURN: Status - * - * DESCRIPTION: Read or write a named field - * - ******************************************************************************/ - -acpi_status -acpi_ex_access_buffer_field ( - u32 mode, - acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length) -{ - acpi_status status; - + new_buffer = NULL; + required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); - FUNCTION_TRACE_PTR ("Ex_access_buffer_field", obj_desc); + if (length < required_length) { + /* We need to create a new buffer */ - - /* - * If the Buffer_field arguments have not been previously evaluated, - * evaluate them now and save the results. - */ - if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { - status = acpi_ds_get_buffer_field_arguments (obj_desc); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + new_buffer = ACPI_MEM_CALLOCATE (required_length); + if (!new_buffer) { + return_ACPI_STATUS (AE_NO_MEMORY); } - } - - status = acpi_ex_common_access_field (mode, obj_desc, buffer, buffer_length); - - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_access_region_field - * - * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE - * *Field_node - Parent node for field to be accessed - * *Buffer - Value(s) to be read or written - * Buffer_length - Number of bytes to transfer - * - * RETURN: Status - * - * DESCRIPTION: Read or write a named field - * - ******************************************************************************/ - -acpi_status -acpi_ex_access_region_field ( - u32 mode, - acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length) -{ - acpi_status status; - u8 locked; - - - FUNCTION_TRACE_PTR ("Ex_access_region_field", obj_desc); - - - /* - * Get the global lock if needed - */ - locked = acpi_ex_acquire_global_lock (obj_desc->field.lock_rule); - - status = acpi_ex_common_access_field (mode, obj_desc, buffer, buffer_length); - - - /* - * Release global lock if we acquired it earlier - */ - acpi_ex_release_global_lock (locked); - - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_access_bank_field - * - * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE - * *Field_node - Parent node for field to be accessed - * *Buffer - Value(s) to be read or written - * Buffer_length - Number of bytes to transfer - * - * RETURN: Status - * - * DESCRIPTION: Read or write a Bank Field - * - ******************************************************************************/ - -acpi_status -acpi_ex_access_bank_field ( - u32 mode, - acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length) -{ - acpi_status status; - u8 locked; - - - FUNCTION_TRACE_PTR ("Ex_access_bank_field", obj_desc); - - - /* - * Get the global lock if needed - */ - locked = acpi_ex_acquire_global_lock (obj_desc->bank_field.lock_rule); + /* + * Copy the original data to the new buffer, starting + * at Byte zero. All unused (upper) bytes of the + * buffer will be 0. + */ + ACPI_MEMCPY ((char *) new_buffer, (char *) buffer, length); + buffer = new_buffer; + length = required_length; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Obj=%p Type=%X Buf=%p Len=%X\n", + obj_desc, obj_desc->common.type, buffer, length)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field_read: Bit_len=%X Bit_off=%X Byte_off=%X\n", + obj_desc->common_field.bit_length, + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.base_byte_offset)); + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); /* - * Write the Bank_value to the Bank_register to select the bank. - * The Bank_value for this Bank_field is specified in the - * Bank_field ASL declaration. The Bank_register is always a Field in - * an operation region. + * Write to the field */ - status = acpi_ex_common_access_field (ACPI_WRITE, - obj_desc->bank_field.bank_register_obj, - &obj_desc->bank_field.value, - sizeof (obj_desc->bank_field.value)); - if (ACPI_FAILURE (status)) { - goto cleanup; - } + status = acpi_ex_insert_into_field (obj_desc, buffer, length); /* - * The bank was successfully selected, now read or write the actual - * data. - */ - status = acpi_ex_common_access_field (mode, obj_desc, buffer, buffer_length); - - -cleanup: - /* * Release global lock if we acquired it earlier */ acpi_ex_release_global_lock (locked); - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_access_index_field - * - * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE - * *Field_node - Parent node for field to be accessed - * *Buffer - Value(s) to be read or written - * Buffer_length - Number of bytes to transfer - * - * RETURN: Status - * - * DESCRIPTION: Read or write a Index Field - * - ******************************************************************************/ - -acpi_status -acpi_ex_access_index_field ( - u32 mode, - acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length) -{ - acpi_status status; - u8 locked; - - - FUNCTION_TRACE_PTR ("Ex_access_index_field", obj_desc); - - - /* - * Get the global lock if needed - */ - locked = acpi_ex_acquire_global_lock (obj_desc->index_field.lock_rule); + /* Free temporary buffer if we used one */ - - /* - * Set Index value to select proper Data register - */ - status = acpi_ex_common_access_field (ACPI_WRITE, - obj_desc->index_field.index_obj, - &obj_desc->index_field.value, - sizeof (obj_desc->index_field.value)); - if (ACPI_FAILURE (status)) { - goto cleanup; + if (new_buffer) { + ACPI_MEM_FREE (new_buffer); } - /* Now read/write the data register */ - - status = acpi_ex_common_access_field (mode, obj_desc->index_field.data_obj, - buffer, buffer_length); - -cleanup: - /* - * Release global lock if we acquired it earlier - */ - acpi_ex_release_global_lock (locked); - return_ACPI_STATUS (status); } - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_common_access_field - * - * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE - * *Field_node - Parent node for field to be accessed - * *Buffer - Value(s) to be read or written - * Buffer_length - Size of buffer, in bytes. Must be large - * enough for all bits of the field. - * - * RETURN: Status - * - * DESCRIPTION: Read or write a named field - * - ******************************************************************************/ - -acpi_status -acpi_ex_common_access_field ( - u32 mode, - acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length) -{ - acpi_status status; - - - FUNCTION_TRACE_PTR ("Ex_common_access_field", obj_desc); - - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj=%p Type=%X Buf=%p Len=%X\n", - obj_desc, obj_desc->common.type, buffer, buffer_length)); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode=%d Bit_len=%X Bit_off=%X Byte_off=%X\n", - mode, obj_desc->common_field.bit_length, - obj_desc->common_field.start_field_bit_offset, - obj_desc->common_field.base_byte_offset)); - - - /* Perform the actual read or write of the field */ - - switch (mode) { - case ACPI_READ: - - status = acpi_ex_extract_from_field (obj_desc, buffer, buffer_length); - break; - - - case ACPI_WRITE: - - status = acpi_ex_insert_into_field (obj_desc, buffer, buffer_length); - break; - - - default: - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown I/O Mode: %X\n", mode)); - status = AE_BAD_PARAMETER; - break; - } - - - return_ACPI_STATUS (status); -} diff -Nur linux-2.4.19/drivers/acpi/executer/exfldio.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exfldio.c --- linux-2.4.19/drivers/acpi/executer/exfldio.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exfldio.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: exfldio - Aml Field I/O - * $Revision: 66 $ + * $Revision: 86 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,32 +27,31 @@ #include "acpi.h" #include "acinterp.h" #include "amlcode.h" -#include "acnamesp.h" -#include "achware.h" #include "acevents.h" #include "acdispat.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exfldio") + ACPI_MODULE_NAME ("exfldio") /******************************************************************************* * - * FUNCTION: Acpi_ex_setup_field + * FUNCTION: Acpi_ex_setup_region * - * PARAMETERS: *Obj_desc - Field to be read or written - * Field_datum_byte_offset - Current offset into the field + * PARAMETERS: *Obj_desc - Field to be read or written + * Field_datum_byte_offset - Byte offset of this datum within the + * parent field * * RETURN: Status * * DESCRIPTION: Common processing for Acpi_ex_extract_from_field and - * Acpi_ex_insert_into_field + * Acpi_ex_insert_into_field. Initialize the * ******************************************************************************/ acpi_status -acpi_ex_setup_field ( +acpi_ex_setup_region ( acpi_operand_object *obj_desc, u32 field_datum_byte_offset) { @@ -60,13 +59,13 @@ acpi_operand_object *rgn_desc; - FUNCTION_TRACE_U32 ("Ex_setup_field", field_datum_byte_offset); + ACPI_FUNCTION_TRACE_U32 ("Ex_setup_region", field_datum_byte_offset); rgn_desc = obj_desc->common_field.region_obj; if (ACPI_TYPE_REGION != rgn_desc->common.type) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %x %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", rgn_desc->common.type, acpi_ut_get_type_name (rgn_desc->common.type))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } @@ -76,7 +75,6 @@ * evaluate them now and save the results. */ if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) { - status = acpi_ds_get_region_arguments (rgn_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -88,9 +86,9 @@ * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ - if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + - field_datum_byte_offset + - obj_desc->common_field.access_byte_width)) { + if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + + field_datum_byte_offset + + obj_desc->common_field.access_byte_width)) { if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { /* * This is the case where the Access_type (Acc_word, etc.) is wider @@ -98,8 +96,9 @@ * byte, and a field with Dword access specified. */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Field access width (%d bytes) too large for region size (%X)\n", - obj_desc->common_field.access_byte_width, rgn_desc->region.length)); + "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", + obj_desc->common_field.node->name.ascii, obj_desc->common_field.access_byte_width, + rgn_desc->region.node->name.ascii, rgn_desc->region.length)); } /* @@ -107,10 +106,10 @@ * exceeds region length, indicate an error */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Field base+offset+width %X+%X+%X exceeds region size (%X bytes) field=%p region=%p\n", - obj_desc->common_field.base_byte_offset, field_datum_byte_offset, - obj_desc->common_field.access_byte_width, - rgn_desc->region.length, obj_desc, rgn_desc)); + "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", + obj_desc->common_field.node->name.ascii, obj_desc->common_field.base_byte_offset, + field_datum_byte_offset, obj_desc->common_field.access_byte_width, + rgn_desc->region.node->name.ascii, rgn_desc->region.length)); return_ACPI_STATUS (AE_AML_REGION_LIMIT); } @@ -121,116 +120,410 @@ /******************************************************************************* * - * FUNCTION: Acpi_ex_read_field_datum + * FUNCTION: Acpi_ex_access_region * - * PARAMETERS: *Obj_desc - Field to be read - * *Value - Where to store value (must be 32 bits) + * PARAMETERS: *Obj_desc - Field to be read + * Field_datum_byte_offset - Byte offset of this datum within the + * parent field + * *Value - Where to store value (must be 32 bits) + * Read_write - Read or Write flag * * RETURN: Status * - * DESCRIPTION: Retrieve the value of the given field + * DESCRIPTION: Read or Write a single field datum to an Operation Region. * ******************************************************************************/ acpi_status -acpi_ex_read_field_datum ( +acpi_ex_access_region ( acpi_operand_object *obj_desc, u32 field_datum_byte_offset, - u32 *value) + acpi_integer *value, + u32 read_write) { acpi_status status; acpi_operand_object *rgn_desc; ACPI_PHYSICAL_ADDRESS address; - u32 local_value; - FUNCTION_TRACE_U32 ("Ex_read_field_datum", field_datum_byte_offset); + ACPI_FUNCTION_TRACE ("Ex_access_region"); + + + /* + * The physical address of this field datum is: + * + * 1) The base of the region, plus + * 2) The base offset of the field, plus + * 3) The current offset into the field + */ + rgn_desc = obj_desc->common_field.region_obj; + address = rgn_desc->region.address + + obj_desc->common_field.base_byte_offset + + field_datum_byte_offset; + + if (read_write == ACPI_READ) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, + " Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n", + acpi_ut_get_region_name (rgn_desc->region.space_id), + rgn_desc->region.space_id, + obj_desc->common_field.access_byte_width, + obj_desc->common_field.base_byte_offset, + field_datum_byte_offset, + ACPI_HIDWORD (address), ACPI_LODWORD (address))); + + /* Invoke the appropriate Address_space/Op_region handler */ + + status = acpi_ev_address_space_dispatch (rgn_desc, read_write, + address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); + + if (ACPI_FAILURE (status)) { + if (status == AE_NOT_IMPLEMENTED) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Region %s(%X) not implemented\n", + acpi_ut_get_region_name (rgn_desc->region.space_id), + rgn_desc->region.space_id)); + } + + else if (status == AE_NOT_EXIST) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Region %s(%X) has no handler\n", + acpi_ut_get_region_name (rgn_desc->region.space_id), + rgn_desc->region.space_id)); + } + } + + return_ACPI_STATUS (status); +} + +/******************************************************************************* + * + * FUNCTION: Acpi_ex_register_overflow + * + * PARAMETERS: *Obj_desc - Register(Field) to be written + * Value - Value to be stored + * + * RETURN: TRUE if value overflows the field, FALSE otherwise + * + * DESCRIPTION: Check if a value is out of range of the field being written. + * Used to check if the values written to Index and Bank registers + * are out of range. Normally, the value is simply truncated + * to fit the field, but this case is most likely a serious + * coding error in the ASL. + * + ******************************************************************************/ + +u8 +acpi_ex_register_overflow ( + acpi_operand_object *obj_desc, + acpi_integer value) +{ - if (!value) { - local_value = 0; - value = &local_value; /* support reads without saving value */ + if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) { + /* + * The field is large enough to hold the maximum integer, so we can + * never overflow it. + */ + return (FALSE); } - /* Clear the entire return buffer first, [Very Important!] */ + if (value >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) { + /* + * The Value is larger than the maximum value that can fit into + * the register. + */ + return (TRUE); + } + + /* The Value will fit into the field with no truncation */ + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ex_field_datum_io + * + * PARAMETERS: *Obj_desc - Field to be read + * Field_datum_byte_offset - Byte offset of this datum within the + * parent field + * *Value - Where to store value (must be 64 bits) + * Read_write - Read or Write flag + * + * RETURN: Status + * + * DESCRIPTION: Read or Write a single datum of a field. The Field_type is + * demultiplexed here to handle the different types of fields + * (Buffer_field, Region_field, Index_field, Bank_field) + * + ******************************************************************************/ + +acpi_status +acpi_ex_field_datum_io ( + acpi_operand_object *obj_desc, + u32 field_datum_byte_offset, + acpi_integer *value, + u32 read_write) +{ + acpi_status status; + acpi_integer local_value; + + + ACPI_FUNCTION_TRACE_U32 ("Ex_field_datum_io", field_datum_byte_offset); + + + if (read_write == ACPI_READ) { + if (!value) { + local_value = 0; + value = &local_value; /* To support reads without saving return value */ + } + + /* Clear the entire return buffer first, [Very Important!] */ - *value = 0; + *value = 0; + } /* - * Buffer_fields - Read from a Buffer - * Other Fields - Read from a Operation Region. + * The four types of fields are: + * + * Buffer_fields - Read/write from/to a Buffer + * Region_fields - Read/write from/to a Operation Region. + * Bank_fields - Write to a Bank Register, then read/write from/to an Op_region + * Index_fields - Write to an Index Register, then read/write from/to a Data Register */ switch (obj_desc->common.type) { case ACPI_TYPE_BUFFER_FIELD: - /* - * For Buffer_fields, we only need to copy the data from the - * source buffer. Length is the field width in bytes. + * If the Buffer_field arguments have not been previously evaluated, + * evaluate them now and save the results. */ - MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer - + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, - obj_desc->common_field.access_byte_width); + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_buffer_field_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + if (read_write == ACPI_READ) { + /* + * Copy the data from the source buffer. + * Length is the field width in bytes. + */ + ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + obj_desc->common_field.access_byte_width); + } + else { + /* + * Copy the data to the target buffer. + * Length is the field width in bytes. + */ + ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + value, obj_desc->common_field.access_byte_width); + } + status = AE_OK; break; - case INTERNAL_TYPE_REGION_FIELD: case INTERNAL_TYPE_BANK_FIELD: + /* Ensure that the Bank_value is not beyond the capacity of the register */ + + if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj, + (acpi_integer) obj_desc->bank_field.value)) { + return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); + } + /* - * For other fields, we need to go through an Operation Region - * (Only types that will get here are Region_fields and Bank_fields) + * For Bank_fields, we must write the Bank_value to the Bank_register + * (itself a Region_field) before we can access the data. */ - status = acpi_ex_setup_field (obj_desc, field_datum_byte_offset); + status = acpi_ex_insert_into_field (obj_desc->bank_field.bank_obj, + &obj_desc->bank_field.value, + sizeof (obj_desc->bank_field.value)); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* - * The physical address of this field datum is: - * - * 1) The base of the region, plus - * 2) The base offset of the field, plus - * 3) The current offset into the field - */ - rgn_desc = obj_desc->common_field.region_obj; - address = rgn_desc->region.address + obj_desc->common_field.base_byte_offset + - field_datum_byte_offset; - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Region %s(%X) width %X base:off %X:%X at %8.8X%8.8X\n", - acpi_ut_get_region_name (rgn_desc->region.space_id), - rgn_desc->region.space_id, obj_desc->common_field.access_bit_width, - obj_desc->common_field.base_byte_offset, field_datum_byte_offset, - HIDWORD(address), LODWORD(address))); + * Now that the Bank has been selected, fall through to the + * Region_field case and write the datum to the Operation Region + */ - /* Invoke the appropriate Address_space/Op_region handler */ + /*lint -fallthrough */ - status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_READ_ADR_SPACE, - address, obj_desc->common_field.access_bit_width, value); - if (status == AE_NOT_IMPLEMENTED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) not implemented\n", - acpi_ut_get_region_name (rgn_desc->region.space_id), - rgn_desc->region.space_id)); + + case INTERNAL_TYPE_REGION_FIELD: + /* + * For simple Region_fields, we just directly access the owning + * Operation Region. + */ + status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - else if (status == AE_NOT_EXIST) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) has no handler\n", - acpi_ut_get_region_name (rgn_desc->region.space_id), - rgn_desc->region.space_id)); + status = acpi_ex_access_region (obj_desc, field_datum_byte_offset, value, + read_write); + break; + + + case INTERNAL_TYPE_INDEX_FIELD: + + + /* Ensure that the Index_value is not beyond the capacity of the register */ + + if (acpi_ex_register_overflow (obj_desc->index_field.index_obj, + (acpi_integer) obj_desc->index_field.value)) { + return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); + } + + /* Write the index value to the Index_register (itself a Region_field) */ + + status = acpi_ex_insert_into_field (obj_desc->index_field.index_obj, + &obj_desc->index_field.value, + sizeof (obj_desc->index_field.value)); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (read_write == ACPI_READ) { + /* Read the datum from the Data_register */ + + status = acpi_ex_extract_from_field (obj_desc->index_field.data_obj, + value, obj_desc->common_field.access_byte_width); + } + else { + /* Write the datum to the Data register */ + + status = acpi_ex_insert_into_field (obj_desc->index_field.data_obj, + value, obj_desc->common_field.access_byte_width); } break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, wrong source type - %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n", obj_desc, acpi_ut_get_type_name (obj_desc->common.type))); status = AE_AML_INTERNAL; break; } + if (ACPI_SUCCESS (status)) { + if (read_write == ACPI_READ) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n", + ACPI_HIDWORD (*value), ACPI_LODWORD (*value))); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n", + ACPI_HIDWORD (*value), ACPI_LODWORD (*value))); + } + } + + return_ACPI_STATUS (status); +} - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Returned value=%08X \n", *value)); + +/******************************************************************************* + * + * FUNCTION: Acpi_ex_write_with_update_rule + * + * PARAMETERS: *Obj_desc - Field to be set + * Value - Value to store + * + * RETURN: Status + * + * DESCRIPTION: Apply the field update rule to a field write + * + ******************************************************************************/ + +acpi_status +acpi_ex_write_with_update_rule ( + acpi_operand_object *obj_desc, + acpi_integer mask, + acpi_integer field_value, + u32 field_datum_byte_offset) +{ + acpi_status status = AE_OK; + acpi_integer merged_value; + acpi_integer current_value; + + + ACPI_FUNCTION_TRACE_U32 ("Ex_write_with_update_rule", mask); + + + /* Start with the new bits */ + + merged_value = field_value; + + /* If the mask is all ones, we don't need to worry about the update rule */ + + if (mask != ACPI_INTEGER_MAX) { + /* Decode the update rule */ + + switch (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK) { + case AML_FIELD_UPDATE_PRESERVE: + /* + * Check if update rule needs to be applied (not if mask is all + * ones) The left shift drops the bits we want to ignore. + */ + if ((~mask << (ACPI_MUL_8 (sizeof (mask)) - + ACPI_MUL_8 (obj_desc->common_field.access_byte_width))) != 0) { + /* + * Read the current contents of the byte/word/dword containing + * the field, and merge with the new field value. + */ + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + ¤t_value, ACPI_READ); + merged_value |= (current_value & ~mask); + } + break; + + case AML_FIELD_UPDATE_WRITE_AS_ONES: + + /* Set positions outside the field to all ones */ + + merged_value |= ~mask; + break; + + case AML_FIELD_UPDATE_WRITE_AS_ZEROS: + + /* Set positions outside the field to all zeros */ + + merged_value &= mask; + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Write_with_update_rule: Unknown Update_rule setting: %X\n", + (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK))); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + } + + /* Write the merged value */ + + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + &merged_value, ACPI_WRITE); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Mask %8.8X%8.8X Datum_offset %X Value %8.8X%8.8X, Merged_value %8.8X%8.8X\n", + ACPI_HIDWORD (mask), ACPI_LODWORD (mask), + field_datum_byte_offset, + ACPI_HIDWORD (field_value), ACPI_LODWORD (field_value), + ACPI_HIDWORD (merged_value),ACPI_LODWORD (merged_value))); return_ACPI_STATUS (status); } @@ -240,41 +533,53 @@ * * FUNCTION: Acpi_ex_get_buffer_datum * - * PARAMETERS: Merged_datum - Value to store - * Buffer - Receiving buffer - * Byte_granularity - 1/2/4 Granularity of the field + * PARAMETERS: Datum - Where the Datum is returned + * Buffer - Raw field buffer + * Byte_granularity - 1/2/4/8 Granularity of the field * (aka Datum Size) * Offset - Datum offset into the buffer * * RETURN: none * - * DESCRIPTION: Store the merged datum to the buffer according to the + * DESCRIPTION: Get a datum from the buffer according to the buffer field * byte granularity * ******************************************************************************/ -static void +void acpi_ex_get_buffer_datum( - u32 *datum, + acpi_integer *datum, void *buffer, u32 byte_granularity, u32 offset) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); switch (byte_granularity) { case ACPI_FIELD_BYTE_GRANULARITY: + *datum = ((u8 *) buffer) [offset]; break; case ACPI_FIELD_WORD_GRANULARITY: - MOVE_UNALIGNED16_TO_32 (datum, &(((u16 *) buffer) [offset])); + + ACPI_MOVE_UNALIGNED16_TO_32 (datum, &(((u16 *) buffer) [offset])); break; case ACPI_FIELD_DWORD_GRANULARITY: - MOVE_UNALIGNED32_TO_32 (datum, &(((u32 *) buffer) [offset])); + + ACPI_MOVE_UNALIGNED32_TO_32 (datum, &(((u32 *) buffer) [offset])); + break; + + case ACPI_FIELD_QWORD_GRANULARITY: + + ACPI_MOVE_UNALIGNED64_TO_64 (datum, &(((u64 *) buffer) [offset])); + break; + + default: + /* Should not get here */ break; } } @@ -286,7 +591,7 @@ * * PARAMETERS: Merged_datum - Value to store * Buffer - Receiving buffer - * Byte_granularity - 1/2/4 Granularity of the field + * Byte_granularity - 1/2/4/8 Granularity of the field * (aka Datum Size) * Offset - Datum offset into the buffer * @@ -297,28 +602,40 @@ * ******************************************************************************/ -static void +void acpi_ex_set_buffer_datum ( - u32 merged_datum, + acpi_integer merged_datum, void *buffer, u32 byte_granularity, u32 offset) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); switch (byte_granularity) { case ACPI_FIELD_BYTE_GRANULARITY: + ((u8 *) buffer) [offset] = (u8) merged_datum; break; case ACPI_FIELD_WORD_GRANULARITY: - MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer)[offset]), &merged_datum); + + ACPI_MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer)[offset]), &merged_datum); break; case ACPI_FIELD_DWORD_GRANULARITY: - MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer)[offset]), &merged_datum); + + ACPI_MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer)[offset]), &merged_datum); + break; + + case ACPI_FIELD_QWORD_GRANULARITY: + + ACPI_MOVE_UNALIGNED64_TO_64 (&(((u64 *) buffer)[offset]), &merged_datum); + break; + + default: + /* Should not get here */ break; } } @@ -346,22 +663,23 @@ acpi_status status; u32 field_datum_byte_offset; u32 datum_offset; - u32 previous_raw_datum; - u32 this_raw_datum = 0; - u32 merged_datum = 0; + acpi_integer previous_raw_datum; + acpi_integer this_raw_datum = 0; + acpi_integer merged_datum = 0; u32 byte_field_length; u32 datum_count; - FUNCTION_TRACE ("Ex_extract_from_field"); + ACPI_FUNCTION_TRACE ("Ex_extract_from_field"); /* * The field must fit within the caller's buffer */ - byte_field_length = ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); + byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); if (byte_field_length > buffer_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Field size %X (bytes) too large for buffer (%X)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field size %X (bytes) too large for buffer (%X)\n", byte_field_length, buffer_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); @@ -369,26 +687,27 @@ /* Convert field byte count to datum count, round up if necessary */ - datum_count = ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); + datum_count = ACPI_ROUND_UP_TO (byte_field_length, + obj_desc->common_field.access_byte_width); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Byte_len=%x, Datum_len=%x, Bit_gran=%x, Byte_gran=%x\n", - byte_field_length, datum_count, obj_desc->common_field.access_bit_width, - obj_desc->common_field.access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Byte_len=%X, Datum_len=%X, Byte_gran=%X\n", + byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where a byte is read, * but the buffer is really a u32 (4 bytes). */ - MEMSET (buffer, 0, buffer_length); + ACPI_MEMSET (buffer, 0, buffer_length); /* Read the first raw datum to prime the loop */ field_datum_byte_offset = 0; datum_offset= 0; - status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, &previous_raw_datum); + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + &previous_raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -397,7 +716,7 @@ /* We might actually be done if the request fits in one datum */ if ((datum_count == 1) && - (obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM)) { + (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { /* 1) Shift the valid data bits down to start at bit 0 */ merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); @@ -405,7 +724,7 @@ /* 2) Mask off any upper unused bits (bits not part of the field) */ if (obj_desc->common_field.end_buffer_valid_bits) { - merged_datum &= MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); + merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); } /* Store the datum to the caller buffer */ @@ -427,17 +746,18 @@ * to perform a final read, since this would potentially read * past the end of the region. * - * TBD: [Investigate] It may make more sense to just split the aligned - * and non-aligned cases since the aligned case is so very simple, + * We could just split the aligned and non-aligned cases since the + * aligned case is so very simple, but this would require more code. */ - if ((obj_desc->common_field.start_field_bit_offset != 0) || + if ((obj_desc->common_field.start_field_bit_offset != 0) || ((obj_desc->common_field.start_field_bit_offset == 0) && (datum_offset < (datum_count -1)))) { /* * Get the next raw datum, it contains some or all bits * of the current field datum */ - status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, &this_raw_datum); + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + &this_raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -451,7 +771,6 @@ merged_datum = previous_raw_datum; } - else { /* * Put together the appropriate bits of the two raw data to make a @@ -474,7 +793,7 @@ */ if (obj_desc->common_field.end_buffer_valid_bits) { merged_datum &= - MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); + ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); } } } @@ -483,8 +802,8 @@ * Store the merged field datum in the caller's buffer, according to * the granularity of the field (size of each datum). */ - acpi_ex_set_buffer_datum (merged_datum, buffer, obj_desc->common_field.access_byte_width, - datum_offset); + acpi_ex_set_buffer_datum (merged_datum, buffer, + obj_desc->common_field.access_byte_width, datum_offset); /* * Save the raw datum that was just acquired since it may contain bits @@ -500,211 +819,6 @@ /******************************************************************************* * - * FUNCTION: Acpi_ex_write_field_datum - * - * PARAMETERS: *Obj_desc - Field to be set - * Value - Value to store - * - * RETURN: Status - * - * DESCRIPTION: Store the value into the given field - * - ******************************************************************************/ - -static acpi_status -acpi_ex_write_field_datum ( - acpi_operand_object *obj_desc, - u32 field_datum_byte_offset, - u32 value) -{ - acpi_status status = AE_OK; - acpi_operand_object *rgn_desc = NULL; - ACPI_PHYSICAL_ADDRESS address; - - - FUNCTION_TRACE_U32 ("Ex_write_field_datum", field_datum_byte_offset); - - - /* - * Buffer_fields - Read from a Buffer - * Other Fields - Read from a Operation Region. - */ - switch (obj_desc->common.type) { - case ACPI_TYPE_BUFFER_FIELD: - - /* - * For Buffer_fields, we only need to copy the data to the - * target buffer. Length is the field width in bytes. - */ - MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer - + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, - &value, obj_desc->common_field.access_byte_width); - status = AE_OK; - break; - - - case INTERNAL_TYPE_REGION_FIELD: - case INTERNAL_TYPE_BANK_FIELD: - - /* - * For other fields, we need to go through an Operation Region - * (Only types that will get here are Region_fields and Bank_fields) - */ - status = acpi_ex_setup_field (obj_desc, field_datum_byte_offset); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - /* - * The physical address of this field datum is: - * - * 1) The base of the region, plus - * 2) The base offset of the field, plus - * 3) The current offset into the field - */ - rgn_desc = obj_desc->common_field.region_obj; - address = rgn_desc->region.address + - obj_desc->common_field.base_byte_offset + - field_datum_byte_offset; - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Store %X in Region %s(%X) at %8.8X%8.8X width %X\n", - value, acpi_ut_get_region_name (rgn_desc->region.space_id), - rgn_desc->region.space_id, HIDWORD(address), LODWORD(address), - obj_desc->common_field.access_bit_width)); - - /* Invoke the appropriate Address_space/Op_region handler */ - - status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_WRITE_ADR_SPACE, - address, obj_desc->common_field.access_bit_width, &value); - - if (status == AE_NOT_IMPLEMENTED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "**** Region type %s(%X) not implemented\n", - acpi_ut_get_region_name (rgn_desc->region.space_id), - rgn_desc->region.space_id)); - } - - else if (status == AE_NOT_EXIST) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "**** Region type %s(%X) does not have a handler\n", - acpi_ut_get_region_name (rgn_desc->region.space_id), - rgn_desc->region.space_id)); - } - - break; - - - default: - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, wrong source type - %s\n", - obj_desc, acpi_ut_get_type_name (obj_desc->common.type))); - status = AE_AML_INTERNAL; - break; - } - - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value written=%08X \n", value)); - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_write_field_datum_with_update_rule - * - * PARAMETERS: *Obj_desc - Field to be set - * Value - Value to store - * - * RETURN: Status - * - * DESCRIPTION: Apply the field update rule to a field write - * - ******************************************************************************/ - -static acpi_status -acpi_ex_write_field_datum_with_update_rule ( - acpi_operand_object *obj_desc, - u32 mask, - u32 field_value, - u32 field_datum_byte_offset) -{ - acpi_status status = AE_OK; - u32 merged_value; - u32 current_value; - - - FUNCTION_TRACE ("Ex_write_field_datum_with_update_rule"); - - - /* Start with the new bits */ - - merged_value = field_value; - - /* If the mask is all ones, we don't need to worry about the update rule */ - - if (mask != ACPI_UINT32_MAX) { - /* Decode the update rule */ - - switch (obj_desc->common_field.update_rule) { - case UPDATE_PRESERVE: - /* - * Check if update rule needs to be applied (not if mask is all - * ones) The left shift drops the bits we want to ignore. - */ - if ((~mask << (sizeof (mask) * 8 - - obj_desc->common_field.access_bit_width)) != 0) { - /* - * Read the current contents of the byte/word/dword containing - * the field, and merge with the new field value. - */ - status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, - ¤t_value); - merged_value |= (current_value & ~mask); - } - break; - - - case UPDATE_WRITE_AS_ONES: - - /* Set positions outside the field to all ones */ - - merged_value |= ~mask; - break; - - - case UPDATE_WRITE_AS_ZEROS: - - /* Set positions outside the field to all zeros */ - - merged_value &= mask; - break; - - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Write_with_update_rule: Unknown Update_rule setting: %x\n", - obj_desc->common_field.update_rule)); - return_ACPI_STATUS (AE_AML_OPERAND_VALUE); - break; - } - } - - - /* Write the merged value */ - - status = acpi_ex_write_field_datum (obj_desc, field_datum_byte_offset, - merged_value); - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Mask %X Datum_offset %X Value %X, Merged_value %X\n", - mask, field_datum_byte_offset, field_value, merged_value)); - - return_ACPI_STATUS (status); -} - - -/******************************************************************************* - * * FUNCTION: Acpi_ex_insert_into_field * * PARAMETERS: *Obj_desc - Field to be set @@ -725,15 +839,15 @@ acpi_status status; u32 field_datum_byte_offset; u32 datum_offset; - u32 mask; - u32 merged_datum; - u32 previous_raw_datum; - u32 this_raw_datum; + acpi_integer mask; + acpi_integer merged_datum; + acpi_integer previous_raw_datum; + acpi_integer this_raw_datum; u32 byte_field_length; u32 datum_count; - FUNCTION_TRACE ("Ex_insert_into_field"); + ACPI_FUNCTION_TRACE ("Ex_insert_into_field"); /* @@ -742,24 +856,21 @@ * larger than the field, this typically happens when an integer is * written to a field that is actually smaller than an integer. */ - byte_field_length = ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); + byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); if (buffer_length < byte_field_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Buffer length %X too small for field %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n", buffer_length, byte_field_length)); - /* TBD: Need a better error code */ - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } /* Convert byte count to datum count, round up if necessary */ - datum_count = ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); + datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Byte_len=%x, Datum_len=%x, Bit_gran=%x, Byte_gran=%x\n", - byte_field_length, datum_count, obj_desc->common_field.access_bit_width, - obj_desc->common_field.access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Byte_len=%X, Datum_len=%X, Byte_gran=%X\n", + byte_field_length, datum_count, obj_desc->common_field.access_byte_width)); /* * Break the request into up to three parts (similar to an I/O request): @@ -785,15 +896,15 @@ * * Mask off bits that are "below" the field (if any) */ - mask = MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset); + mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset); /* If the field fits in one datum, may need to mask upper bits */ - if ((obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM) && + if ((obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM) && obj_desc->common_field.end_field_valid_bits) { /* There are bits above the field, mask them off also */ - mask &= MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); + mask &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); } /* Shift and mask the value into the field position */ @@ -803,7 +914,7 @@ /* Apply the update rule (if necessary) and write the datum to the field */ - status = acpi_ex_write_field_datum_with_update_rule (obj_desc, mask, merged_datum, + status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_datum_byte_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -812,7 +923,7 @@ /* If the entire field fits within one datum, we are done. */ if ((datum_count == 1) && - (obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM)) { + (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { return_ACPI_STATUS (AE_OK); } @@ -849,7 +960,6 @@ (previous_raw_datum >> obj_desc->common_field.datum_valid_bits) | (this_raw_datum << obj_desc->common_field.start_field_bit_offset); } - else { /* Field began aligned on datum boundary */ @@ -874,24 +984,23 @@ * * Mask off the unused bits above (after) the end-of-field */ - mask = MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); + mask = ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); merged_datum &= mask; /* Write the last datum with the update rule */ - status = acpi_ex_write_field_datum_with_update_rule (obj_desc, mask, - merged_datum, field_datum_byte_offset); + status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, + field_datum_byte_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } } - else { /* Normal case -- write the completed datum */ - status = acpi_ex_write_field_datum (obj_desc, - field_datum_byte_offset, merged_datum); + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + &merged_datum, ACPI_WRITE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/executer/exmisc.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exmisc.c --- linux-2.4.19/drivers/acpi/executer/exmisc.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exmisc.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes - * $Revision: 92 $ + * $Revision: 105 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,14 +26,13 @@ #include "acpi.h" -#include "acparser.h" #include "acinterp.h" #include "amlcode.h" #include "acdispat.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exmisc") + ACPI_MODULE_NAME ("exmisc") /******************************************************************************* @@ -59,10 +58,12 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_PTR ("Ex_get_object_reference", obj_desc); + ACPI_FUNCTION_TRACE_PTR ("Ex_get_object_reference", obj_desc); - if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_OPERAND: + if (obj_desc->common.type != INTERNAL_TYPE_REFERENCE) { *return_desc = NULL; status = AE_TYPE; @@ -77,8 +78,9 @@ case AML_LOCAL_OP: case AML_ARG_OP: - *return_desc = (void *) acpi_ds_method_data_get_node (obj_desc->reference.opcode, - obj_desc->reference.offset, walk_state); + status = acpi_ds_method_data_get_node (obj_desc->reference.opcode, + obj_desc->reference.offset, walk_state, + ACPI_CAST_INDIRECT_PTR (acpi_namespace_node, return_desc)); break; default: @@ -89,18 +91,22 @@ status = AE_AML_INTERNAL; goto cleanup; } + break; - } - else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { + case ACPI_DESC_TYPE_NAMED: + /* Must be a named object; Just return the Node */ *return_desc = obj_desc; - } + break; + + + default: - else { *return_desc = NULL; status = AE_TYPE; + break; } @@ -113,7 +119,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_ex_do_concatenate + * FUNCTION: Acpi_ex_concat_template * * PARAMETERS: *Obj_desc - Object to be converted. Must be an * Integer, Buffer, or String @@ -121,13 +127,106 @@ * * RETURN: Status * + * DESCRIPTION: Concatenate two resource templates + * + ******************************************************************************/ + +acpi_status +acpi_ex_concat_template ( + acpi_operand_object *obj_desc1, + acpi_operand_object *obj_desc2, + acpi_operand_object **actual_return_desc, + acpi_walk_state *walk_state) +{ + acpi_status status; + acpi_operand_object *return_desc; + NATIVE_CHAR *new_buf; + u8 *end_tag1; + u8 *end_tag2; + ACPI_SIZE length1; + ACPI_SIZE length2; + + + ACPI_FUNCTION_TRACE ("Ex_concat_template"); + + + /* Find the End_tags in each resource template */ + + end_tag1 = acpi_ut_get_resource_end_tag (obj_desc1); + end_tag2 = acpi_ut_get_resource_end_tag (obj_desc2); + if (!end_tag1 || !end_tag2) { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Create a new buffer object for the result */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Allocate a new buffer for the result */ + + length1 = ACPI_PTR_DIFF (end_tag1, obj_desc1->buffer.pointer); + length2 = ACPI_PTR_DIFF (end_tag2, obj_desc2->buffer.pointer) + + 2; /* Size of END_TAG */ + + new_buf = ACPI_MEM_ALLOCATE (length1 + length2); + if (!new_buf) { + ACPI_REPORT_ERROR + (("Ex_concat_template: Buffer allocation failure\n")); + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Copy the templates to the new descriptor */ + + ACPI_MEMCPY (new_buf, obj_desc1->buffer.pointer, length1); + ACPI_MEMCPY (new_buf + length1, obj_desc2->buffer.pointer, length2); + + /* Complete the buffer object initialization */ + + return_desc->common.flags = AOPOBJ_DATA_VALID; + return_desc->buffer.pointer = (u8 *) new_buf; + return_desc->buffer.length = (u32) (length1 + length2); + + /* Compute the new checksum */ + + new_buf[return_desc->buffer.length - 1] = (NATIVE_CHAR) + acpi_ut_generate_checksum (return_desc->buffer.pointer, + (return_desc->buffer.length - 1)); + + /* Return the completed template descriptor */ + + *actual_return_desc = return_desc; + return_ACPI_STATUS (AE_OK); + + +cleanup: + + acpi_ut_remove_reference (return_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ex_do_concatenate + * + * PARAMETERS: Obj_desc1 - First source object + * Obj_desc2 - Second source object + * Actual_return_desc - Where to place the return object + * Walk_state - Current walk state + * + * RETURN: Status + * * DESCRIPTION: Concatenate two objects OF THE SAME TYPE. * ******************************************************************************/ acpi_status acpi_ex_do_concatenate ( - acpi_operand_object *obj_desc, + acpi_operand_object *obj_desc1, acpi_operand_object *obj_desc2, acpi_operand_object **actual_return_desc, acpi_walk_state *walk_state) @@ -137,73 +236,66 @@ acpi_integer this_integer; acpi_operand_object *return_desc; NATIVE_CHAR *new_buf; - u32 integer_size = sizeof (acpi_integer); - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* * There are three cases to handle: - * 1) Two Integers concatenated to produce a buffer - * 2) Two Strings concatenated to produce a string - * 3) Two Buffers concatenated to produce a buffer + * + * 1) Two Integers concatenated to produce a new Buffer + * 2) Two Strings concatenated to produce a new String + * 3) Two Buffers concatenated to produce a new Buffer */ - switch (obj_desc->common.type) { + switch (obj_desc1->common.type) { case ACPI_TYPE_INTEGER: - /* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */ - - if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { - /* - * We are running a method that exists in a 32-bit ACPI table. - * Truncate the value to 32 bits by zeroing out the upper - * 32-bit field - */ - integer_size = sizeof (u32); - } - - /* Result of two integers is a buffer */ + /* Result of two Integers is a Buffer */ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); if (!return_desc) { return (AE_NO_MEMORY); } - /* Need enough space for two integers */ + /* Need enough buffer space for two integers */ - return_desc->buffer.length = integer_size * 2; + return_desc->buffer.length = acpi_gbl_integer_byte_width * 2; new_buf = ACPI_MEM_CALLOCATE (return_desc->buffer.length); if (!new_buf) { - REPORT_ERROR + ACPI_REPORT_ERROR (("Ex_do_concatenate: Buffer allocation failure\n")); status = AE_NO_MEMORY; goto cleanup; } - return_desc->buffer.pointer = (u8 *) new_buf; - /* Convert the first integer */ - this_integer = obj_desc->integer.value; - for (i = 0; i < integer_size; i++) { - new_buf[i] = (u8) this_integer; + this_integer = obj_desc1->integer.value; + for (i = 0; i < acpi_gbl_integer_byte_width; i++) { + new_buf[i] = (NATIVE_CHAR) this_integer; this_integer >>= 8; } /* Convert the second integer */ this_integer = obj_desc2->integer.value; - for (; i < (integer_size * 2); i++) { - new_buf[i] = (u8) this_integer; + for (; i < (ACPI_MUL_2 (acpi_gbl_integer_byte_width)); i++) { + new_buf[i] = (NATIVE_CHAR) this_integer; this_integer >>= 8; } + /* Complete the buffer object initialization */ + + return_desc->common.flags = AOPOBJ_DATA_VALID; + return_desc->buffer.pointer = (u8 *) new_buf; break; case ACPI_TYPE_STRING: + /* Result of two Strings is a String */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING); if (!return_desc) { return (AE_NO_MEMORY); @@ -211,66 +303,71 @@ /* Operand0 is string */ - new_buf = ACPI_MEM_ALLOCATE (obj_desc->string.length + - obj_desc2->string.length + 1); + new_buf = ACPI_MEM_ALLOCATE ((ACPI_SIZE) obj_desc1->string.length + + (ACPI_SIZE) obj_desc2->string.length + 1); if (!new_buf) { - REPORT_ERROR + ACPI_REPORT_ERROR (("Ex_do_concatenate: String allocation failure\n")); status = AE_NO_MEMORY; goto cleanup; } - STRCPY (new_buf, obj_desc->string.pointer); - STRCPY (new_buf + obj_desc->string.length, + /* Concatenate the strings */ + + ACPI_STRCPY (new_buf, obj_desc1->string.pointer); + ACPI_STRCPY (new_buf + obj_desc1->string.length, obj_desc2->string.pointer); - /* Point the return object to the new string */ + /* Complete the String object initialization */ return_desc->string.pointer = new_buf; - return_desc->string.length = obj_desc->string.length += - obj_desc2->string.length; + return_desc->string.length = obj_desc1->string.length + + obj_desc2->string.length; break; case ACPI_TYPE_BUFFER: - /* Operand0 is a buffer */ + /* Result of two Buffers is a Buffer */ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); if (!return_desc) { return (AE_NO_MEMORY); } - new_buf = ACPI_MEM_ALLOCATE (obj_desc->buffer.length + - obj_desc2->buffer.length); + new_buf = ACPI_MEM_ALLOCATE ((ACPI_SIZE) obj_desc1->buffer.length + + (ACPI_SIZE) obj_desc2->buffer.length); if (!new_buf) { - REPORT_ERROR + ACPI_REPORT_ERROR (("Ex_do_concatenate: Buffer allocation failure\n")); status = AE_NO_MEMORY; goto cleanup; } - MEMCPY (new_buf, obj_desc->buffer.pointer, - obj_desc->buffer.length); - MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer, + /* Concatenate the buffers */ + + ACPI_MEMCPY (new_buf, obj_desc1->buffer.pointer, + obj_desc1->buffer.length); + ACPI_MEMCPY (new_buf + obj_desc1->buffer.length, obj_desc2->buffer.pointer, obj_desc2->buffer.length); - /* - * Point the return object to the new buffer - */ + /* Complete the buffer object initialization */ - return_desc->buffer.pointer = (u8 *) new_buf; - return_desc->buffer.length = obj_desc->buffer.length + - obj_desc2->buffer.length; + return_desc->common.flags = AOPOBJ_DATA_VALID; + return_desc->buffer.pointer = (u8 *) new_buf; + return_desc->buffer.length = obj_desc1->buffer.length + + obj_desc2->buffer.length; break; default: + + /* Invalid object type, should not happen here */ + status = AE_AML_INTERNAL; return_desc = NULL; } - *actual_return_desc = return_desc; return (AE_OK); @@ -288,7 +385,7 @@ * * PARAMETERS: Opcode - AML opcode * Operand0 - Integer operand #0 - * Operand0 - Integer operand #1 + * Operand1 - Integer operand #1 * * RETURN: Integer result of the operation * @@ -369,7 +466,7 @@ * * PARAMETERS: Opcode - AML opcode * Operand0 - Integer operand #0 - * Operand0 - Integer operand #1 + * Operand1 - Integer operand #1 * * RETURN: TRUE/FALSE result of the operation * @@ -431,6 +528,9 @@ if (operand0 || operand1) { return (TRUE); } + break; + + default: break; } diff -Nur linux-2.4.19/drivers/acpi/executer/exmutex.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exmutex.c --- linux-2.4.19/drivers/acpi/executer/exmutex.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exmutex.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exmutex - ASL Mutex Acquire/Release functions - * $Revision: 7 $ + * $Revision: 13 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,12 +27,9 @@ #include "acpi.h" #include "acinterp.h" -#include "acnamesp.h" -#include "achware.h" -#include "acevents.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exmutex") + ACPI_MODULE_NAME ("exmutex") /******************************************************************************* @@ -51,13 +48,23 @@ acpi_ex_unlink_mutex ( acpi_operand_object *obj_desc) { + ACPI_THREAD_STATE *thread = obj_desc->mutex.owner_thread; + + + if (!thread) { + return; + } if (obj_desc->mutex.next) { (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; } + if (obj_desc->mutex.prev) { (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; } + else { + thread->acquired_mutex_list = obj_desc->mutex.next; + } } @@ -77,23 +84,27 @@ void acpi_ex_link_mutex ( acpi_operand_object *obj_desc, - acpi_operand_object *list_head) + ACPI_THREAD_STATE *thread) { + acpi_operand_object *list_head; + + + list_head = thread->acquired_mutex_list; /* This object will be the first object in the list */ - obj_desc->mutex.prev = list_head; - obj_desc->mutex.next = list_head->mutex.next; + obj_desc->mutex.prev = NULL; + obj_desc->mutex.next = list_head; /* Update old first object to point back to this object */ - if (list_head->mutex.next) { - (list_head->mutex.next)->mutex.prev = obj_desc; + if (list_head) { + list_head->mutex.prev = obj_desc; } /* Update list head */ - list_head->mutex.next = obj_desc; + thread->acquired_mutex_list = obj_desc; } @@ -119,7 +130,7 @@ acpi_status status; - FUNCTION_TRACE_PTR ("Ex_acquire_mutex", obj_desc); + ACPI_FUNCTION_TRACE_PTR ("Ex_acquire_mutex", obj_desc); if (!obj_desc) { return_ACPI_STATUS (AE_BAD_PARAMETER); @@ -129,15 +140,18 @@ * Current Sync must be less than or equal to the sync level of the * mutex. This mechanism provides some deadlock prevention */ - if (walk_state->current_sync_level > obj_desc->mutex.sync_level) { + if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } /* - * If the mutex is already owned by this thread, - * just increment the acquisition depth + * Support for multiple acquires by the owning thread */ - if (obj_desc->mutex.owner == walk_state) { + if (obj_desc->mutex.owner_thread == walk_state->thread) { + /* + * The mutex is already owned by this thread, + * just increment the acquisition depth + */ obj_desc->mutex.acquisition_depth++; return_ACPI_STATUS (AE_OK); } @@ -153,14 +167,14 @@ /* Have the mutex, update mutex and walk info */ - obj_desc->mutex.owner = walk_state; + obj_desc->mutex.owner_thread = walk_state->thread; obj_desc->mutex.acquisition_depth = 1; - walk_state->current_sync_level = obj_desc->mutex.sync_level; - /* Link the mutex to the walk state for force-unlock at method exit */ + walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; + + /* Link the mutex to the current thread for force-unlock at method exit */ - acpi_ex_link_mutex (obj_desc, (acpi_operand_object *) - &(walk_state->walk_list->acquired_mutex_list)); + acpi_ex_link_mutex (obj_desc, walk_state->thread); return_ACPI_STATUS (AE_OK); } @@ -186,7 +200,7 @@ acpi_status status; - FUNCTION_TRACE ("Ex_release_mutex"); + ACPI_FUNCTION_TRACE ("Ex_release_mutex"); if (!obj_desc) { @@ -195,13 +209,13 @@ /* The mutex must have been previously acquired in order to release it */ - if (!obj_desc->mutex.owner) { + if (!obj_desc->mutex.owner_thread) { return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED); } /* The Mutex is owned, but this thread must be the owner */ - if (obj_desc->mutex.owner != walk_state) { + if (obj_desc->mutex.owner_thread != walk_state->thread) { return_ACPI_STATUS (AE_AML_NOT_OWNER); } @@ -209,7 +223,7 @@ * The sync level of the mutex must be less than or * equal to the current sync level */ - if (obj_desc->mutex.sync_level > walk_state->current_sync_level) { + if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } @@ -223,6 +237,9 @@ return_ACPI_STATUS (AE_OK); } + /* Unlink the mutex from the owner's list */ + + acpi_ex_unlink_mutex (obj_desc); /* Release the mutex */ @@ -230,12 +247,8 @@ /* Update the mutex and walk state */ - obj_desc->mutex.owner = NULL; - walk_state->current_sync_level = obj_desc->mutex.sync_level; - - /* Unlink the mutex from the owner's list */ - - acpi_ex_unlink_mutex (obj_desc); + obj_desc->mutex.owner_thread = NULL; + walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; return_ACPI_STATUS (status); } @@ -253,15 +266,16 @@ * ******************************************************************************/ -acpi_status +void acpi_ex_release_all_mutexes ( - acpi_operand_object *list_head) + ACPI_THREAD_STATE *thread) { - acpi_operand_object *next = list_head->mutex.next; + acpi_operand_object *next = thread->acquired_mutex_list; acpi_operand_object *this; + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* @@ -271,19 +285,21 @@ this = next; next = this->mutex.next; - /* Mark mutex un-owned */ - - this->mutex.owner = NULL; - this->mutex.prev = NULL; - this->mutex.next = NULL; - this->mutex.acquisition_depth = 0; + this->mutex.acquisition_depth = 1; + this->mutex.prev = NULL; + this->mutex.next = NULL; /* Release the mutex */ - acpi_ex_system_release_mutex (this); - } + status = acpi_ex_system_release_mutex (this); + if (ACPI_FAILURE (status)) { + continue; + } - return (AE_OK); + /* Mark mutex unowned */ + + this->mutex.owner_thread = NULL; + } } diff -Nur linux-2.4.19/drivers/acpi/executer/exnames.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exnames.c --- linux-2.4.19/drivers/acpi/executer/exnames.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exnames.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exnames - interpreter/scanner name load/execute - * $Revision: 83 $ + * $Revision: 91 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,10 +28,9 @@ #include "acpi.h" #include "acinterp.h" #include "amlcode.h" -#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exnames") + ACPI_MODULE_NAME ("exnames") /* AML Package Length encodings */ @@ -67,7 +66,7 @@ NATIVE_CHAR *name_string; u32 size_needed; - FUNCTION_TRACE ("Ex_allocate_name_string"); + ACPI_FUNCTION_TRACE ("Ex_allocate_name_string"); /* @@ -75,7 +74,7 @@ * Also, one byte for the null terminator. * This may actually be somewhat longer than needed. */ - if (prefix_count == (u32) -1) { + if (prefix_count == ACPI_UINT32_MAX) { /* Special case for root */ size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; @@ -90,7 +89,7 @@ */ name_string = ACPI_MEM_ALLOCATE (size_needed); if (!name_string) { - REPORT_ERROR (("Ex_allocate_name_string: Could not allocate size %d\n", size_needed)); + ACPI_REPORT_ERROR (("Ex_allocate_name_string: Could not allocate size %d\n", size_needed)); return_PTR (NULL); } @@ -98,10 +97,9 @@ /* Set up Root or Parent prefixes if needed */ - if (prefix_count == (u32) -1) { + if (prefix_count == ACPI_UINT32_MAX) { *temp_ptr++ = AML_ROOT_PREFIX; } - else { while (prefix_count--) { *temp_ptr++ = AML_PARENT_PREFIX; @@ -117,7 +115,6 @@ *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP; *temp_ptr++ = (char) num_name_segs; } - else if (2 == num_name_segs) { /* Set up dual prefixes */ @@ -150,13 +147,13 @@ u8 **in_aml_address, NATIVE_CHAR *name_string) { - u8 *aml_address = *in_aml_address; + char *aml_address = (void *) *in_aml_address; acpi_status status = AE_OK; u32 index; - NATIVE_CHAR char_buf[5]; + char char_buf[5]; - FUNCTION_TRACE ("Ex_name_segment"); + ACPI_FUNCTION_TRACE ("Ex_name_segment"); /* @@ -172,34 +169,32 @@ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Bytes from stream:\n")); - for (index = 4; - (index > 0) && (acpi_ut_valid_acpi_character (*aml_address)); - --index) { - char_buf[4 - index] = *aml_address++; - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "%c\n", char_buf[4 - index])); + for (index = 0; + (index < ACPI_NAME_SIZE) && (acpi_ut_valid_acpi_character (*aml_address)); + index++) { + char_buf[index] = *aml_address++; + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "%c\n", char_buf[index])); } /* Valid name segment */ - if (0 == index) { + if (index == 4) { /* Found 4 valid characters */ char_buf[4] = '\0'; if (name_string) { - STRCAT (name_string, char_buf); + ACPI_STRCAT (name_string, char_buf); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Appended to - %s \n", name_string)); } - else { ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "No Name string - %s \n", char_buf)); } } - - else if (4 == index) { + else if (index == 0) { /* * First character was not a valid name character, * so we are looking at something other than a name. @@ -209,7 +204,6 @@ char_buf[0])); status = AE_CTRL_PENDING; } - else { /* Segment started with one or more valid characters, but fewer than 4 */ @@ -218,7 +212,7 @@ *aml_address, aml_address)); } - *in_aml_address = aml_address; + *in_aml_address = (u8 *) aml_address; return_ACPI_STATUS (status); } @@ -235,10 +229,9 @@ * ******************************************************************************/ - acpi_status acpi_ex_get_name_string ( - acpi_object_type8 data_type, + acpi_object_type data_type, u8 *in_aml_address, NATIVE_CHAR **out_name_string, u32 *out_name_length) @@ -248,11 +241,10 @@ NATIVE_CHAR *name_string = NULL; u32 num_segments; u32 prefix_count = 0; - u8 prefix = 0; u8 has_prefix = FALSE; - FUNCTION_TRACE_PTR ("Ex_get_name_string", aml_address); + ACPI_FUNCTION_TRACE_PTR ("Ex_get_name_string", aml_address); if (INTERNAL_TYPE_REGION_FIELD == data_type || @@ -268,24 +260,22 @@ status = acpi_ex_name_segment (&aml_address, name_string); } } - else { /* * Data_type is not a field name. * Examine first character of name for root or parent prefix operators */ switch (*aml_address) { - case AML_ROOT_PREFIX: - prefix = *aml_address++; - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Root_prefix: %x\n", prefix)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Root_prefix(\\) at %p\n", aml_address)); /* * Remember that we have a Root_prefix -- * see comment in Acpi_ex_allocate_name_string() */ - prefix_count = (u32) -1; + aml_address++; + prefix_count = ACPI_UINT32_MAX; has_prefix = TRUE; break; @@ -295,18 +285,21 @@ /* Increment past possibly multiple parent prefixes */ do { - prefix = *aml_address++; - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Parent_prefix: %x\n", prefix)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Parent_prefix (^) at %p\n", aml_address)); - ++prefix_count; + aml_address++; + prefix_count++; } while (*aml_address == AML_PARENT_PREFIX); + has_prefix = TRUE; break; default: + /* Not a prefix character */ + break; } @@ -314,12 +307,11 @@ /* Examine first character of name for name segment prefix operator */ switch (*aml_address) { - case AML_DUAL_NAME_PREFIX: - prefix = *aml_address++; - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Dual_name_prefix: %x\n", prefix)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Dual_name_prefix at %p\n", aml_address)); + aml_address++; name_string = acpi_ex_allocate_name_string (prefix_count, 2); if (!name_string) { status = AE_NO_MEMORY; @@ -339,12 +331,12 @@ case AML_MULTI_NAME_PREFIX_OP: - prefix = *aml_address++; - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Multi_name_prefix: %x\n", prefix)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Multi_name_prefix at %p\n", aml_address)); /* Fetch count of segments remaining in name path */ - num_segments = *aml_address++; + aml_address++; + num_segments = *aml_address; name_string = acpi_ex_allocate_name_string (prefix_count, num_segments); if (!name_string) { @@ -354,11 +346,12 @@ /* Indicate that we processed a prefix */ + aml_address++; has_prefix = TRUE; while (num_segments && (status = acpi_ex_name_segment (&aml_address, name_string)) == AE_OK) { - --num_segments; + num_segments--; } break; @@ -368,7 +361,7 @@ /* Null_name valid as of 8-12-98 ASL/AML Grammar Update */ - if (-1 == prefix_count) { + if (prefix_count == ACPI_UINT32_MAX) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Name_seg is \"\\\" followed by NULL\n")); } @@ -396,19 +389,16 @@ status = acpi_ex_name_segment (&aml_address, name_string); break; - - } /* Switch (Peek_op ()) */ + } } - if (AE_CTRL_PENDING == status && has_prefix) { /* Ran out of segments after processing a prefix */ - REPORT_ERROR ( + ACPI_REPORT_ERROR ( ("Ex_do_name: Malformed Name at %p\n", name_string)); status = AE_AML_BAD_NAME; } - *out_name_string = name_string; *out_name_length = (u32) (aml_address - in_aml_address); diff -Nur linux-2.4.19/drivers/acpi/executer/exoparg1.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg1.c --- linux-2.4.19/drivers/acpi/executer/exoparg1.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg1.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exoparg1 - AML execution - opcodes with 1 argument - * $Revision: 120 $ + * $Revision: 137 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exoparg1") + ACPI_MODULE_NAME ("exoparg1") /*! @@ -81,10 +81,10 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_STR ("Ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); - /* Examine the opcode */ + /* Examine the AML opcode */ switch (walk_state->opcode) { case AML_RELEASE_OP: /* Release (Mutex_object) */ @@ -107,13 +107,13 @@ case AML_SLEEP_OP: /* Sleep (Msec_time) */ - acpi_ex_system_do_suspend ((u32) operand[0]->integer.value); + status = acpi_ex_system_do_suspend ((u32) operand[0]->integer.value); break; case AML_STALL_OP: /* Stall (Usec_time) */ - acpi_ex_system_do_stall ((u32) operand[0]->integer.value); + status = acpi_ex_system_do_stall ((u32) operand[0]->integer.value); break; @@ -125,7 +125,7 @@ default: /* Unknown opcode */ - REPORT_ERROR (("Acpi_ex_opcode_1A_0T_0R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_1A_0T_0R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; break; @@ -156,19 +156,20 @@ acpi_operand_object **operand = &walk_state->operands[0]; - FUNCTION_TRACE_STR ("Ex_opcode_1A_1T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_1A_1T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); - switch (walk_state->opcode) { + /* Examine the AML opcode */ + switch (walk_state->opcode) { case AML_LOAD_OP: - status = acpi_ex_load_op (operand[0], operand[1]); + status = acpi_ex_load_op (operand[0], operand[1], walk_state); break; default: /* Unknown opcode */ - REPORT_ERROR (("Acpi_ex_opcode_1A_1T_0R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_1A_1T_0R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; @@ -208,10 +209,10 @@ acpi_integer digit; - FUNCTION_TRACE_STR ("Ex_opcode_1A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_1A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); - /* Create a return object of type Integer for most opcodes */ + /* Examine the AML opcode */ switch (walk_state->opcode) { case AML_BIT_NOT_OP: @@ -221,156 +222,158 @@ case AML_TO_BCD_OP: case AML_COND_REF_OF_OP: + /* Create a return object of type Integer for these opcodes */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } - break; - } + switch (walk_state->opcode) { + case AML_BIT_NOT_OP: /* Not (Operand, Result) */ + return_desc->integer.value = ~operand[0]->integer.value; + break; - switch (walk_state->opcode) { - case AML_BIT_NOT_OP: /* Not (Operand, Result) */ + case AML_FIND_SET_LEFT_BIT_OP: /* Find_set_left_bit (Operand, Result) */ - return_desc->integer.value = ~operand[0]->integer.value; - break; + return_desc->integer.value = operand[0]->integer.value; + /* + * Acpi specification describes Integer type as a little + * endian unsigned value, so this boundary condition is valid. + */ + for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { + return_desc->integer.value >>= 1; + } - case AML_FIND_SET_LEFT_BIT_OP: /* Find_set_left_bit (Operand, Result) */ + return_desc->integer.value = temp32; + break; - return_desc->integer.value = operand[0]->integer.value; + case AML_FIND_SET_RIGHT_BIT_OP: /* Find_set_right_bit (Operand, Result) */ - /* - * Acpi specification describes Integer type as a little - * endian unsigned value, so this boundary condition is valid. - */ - for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { - return_desc->integer.value >>= 1; - } + return_desc->integer.value = operand[0]->integer.value; - return_desc->integer.value = temp32; - break; + /* + * The Acpi specification describes Integer type as a little + * endian unsigned value, so this boundary condition is valid. + */ + for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { + return_desc->integer.value <<= 1; + } + /* Since the bit position is one-based, subtract from 33 (65) */ - case AML_FIND_SET_RIGHT_BIT_OP: /* Find_set_right_bit (Operand, Result) */ + return_desc->integer.value = temp32 == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32; + break; - return_desc->integer.value = operand[0]->integer.value; + case AML_FROM_BCD_OP: /* From_bcd (BCDValue, Result) */ - /* - * The Acpi specification describes Integer type as a little - * endian unsigned value, so this boundary condition is valid. - */ - for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { - return_desc->integer.value <<= 1; - } + /* + * The 64-bit ACPI integer can hold 16 4-bit BCD integers + */ + return_desc->integer.value = 0; + for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { + /* Get one BCD digit */ - /* Since the bit position is one-based, subtract from 33 (65) */ + digit = (acpi_integer) ((operand[0]->integer.value >> (i * 4)) & 0xF); - return_desc->integer.value = temp32 == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32; - break; + /* Check the range of the digit */ + + if (digit > 9) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD digit too large: %d\n", + (u32) digit)); + status = AE_AML_NUMERIC_OVERFLOW; + goto cleanup; + } + if (digit > 0) { + /* Sum into the result with the appropriate power of 10 */ - case AML_FROM_BCD_OP: /* From_bcd (BCDValue, Result) */ + for (j = 0; j < i; j++) { + digit *= 10; + } - /* - * The 64-bit ACPI integer can hold 16 4-bit BCD integers - */ - return_desc->integer.value = 0; - for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { - /* Get one BCD digit */ + return_desc->integer.value += digit; + } + } + break; - digit = (acpi_integer) ((operand[0]->integer.value >> (i * 4)) & 0xF); - /* Check the range of the digit */ + case AML_TO_BCD_OP: /* To_bcd (Operand, Result) */ - if (digit > 9) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD digit too large: %d\n", - (u32) digit)); + if (operand[0]->integer.value > ACPI_MAX_BCD_VALUE) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD overflow: %8.8X%8.8X\n", + ACPI_HIDWORD(operand[0]->integer.value), + ACPI_LODWORD(operand[0]->integer.value))); status = AE_AML_NUMERIC_OVERFLOW; goto cleanup; } - if (digit > 0) { - /* Sum into the result with the appropriate power of 10 */ + return_desc->integer.value = 0; + for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { + /* Divide by nth factor of 10 */ + temp32 = 0; + digit = operand[0]->integer.value; for (j = 0; j < i; j++) { - digit *= 10; + (void) acpi_ut_short_divide (&digit, 10, &digit, &temp32); } - return_desc->integer.value += digit; - } - } - break; + /* Create the BCD digit from the remainder above */ + if (digit > 0) { + return_desc->integer.value += ((acpi_integer) temp32 << (i * 4)); + } + } + break; - case AML_TO_BCD_OP: /* To_bcd (Operand, Result) */ - if (operand[0]->integer.value > ACPI_MAX_BCD_VALUE) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD overflow: %8.8X%8.8X\n", - HIDWORD(operand[0]->integer.value), LODWORD(operand[0]->integer.value))); - status = AE_AML_NUMERIC_OVERFLOW; - goto cleanup; - } + case AML_COND_REF_OF_OP: /* Cond_ref_of (Source_object, Result) */ - return_desc->integer.value = 0; - for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { - /* Divide by nth factor of 10 */ + /* + * This op is a little strange because the internal return value is + * different than the return value stored in the result descriptor + * (There are really two return values) + */ + if ((acpi_namespace_node *) operand[0] == acpi_gbl_root_node) { + /* + * This means that the object does not exist in the namespace, + * return FALSE + */ + return_desc->integer.value = 0; - temp32 = 0; - digit = operand[0]->integer.value; - for (j = 0; j < i; j++) { - acpi_ut_short_divide (&digit, 10, &digit, &temp32); + /* + * Must delete the result descriptor since there is no reference + * being returned + */ + acpi_ut_remove_reference (operand[1]); + goto cleanup; } - /* Create the BCD digit from the remainder above */ + /* Get the object reference and store it */ - if (digit > 0) { - return_desc->integer.value += (temp32 << (i * 4)); + status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; } - } - break; - - case AML_COND_REF_OF_OP: /* Cond_ref_of (Source_object, Result) */ + status = acpi_ex_store (return_desc2, operand[1], walk_state); - /* - * This op is a little strange because the internal return value is - * different than the return value stored in the result descriptor - * (There are really two return values) - */ - if ((acpi_namespace_node *) operand[0] == acpi_gbl_root_node) { - /* - * This means that the object does not exist in the namespace, - * return FALSE - */ - return_desc->integer.value = 0; + /* The object exists in the namespace, return TRUE */ - /* - * Must delete the result descriptor since there is no reference - * being returned - */ - acpi_ut_remove_reference (operand[1]); + return_desc->integer.value = ACPI_INTEGER_MAX; goto cleanup; - } - /* Get the object reference and store it */ - status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state); - if (ACPI_FAILURE (status)) { - goto cleanup; + default: + /* No other opcodes get here */ + break; } - - status = acpi_ex_store (return_desc2, operand[1], walk_state); - - /* The object exists in the namespace, return TRUE */ - - return_desc->integer.value = ACPI_INTEGER_MAX; - goto cleanup; break; @@ -395,7 +398,6 @@ walk_state->result_obj = operand[0]; walk_state->operands[0] = NULL; /* Prevent deletion */ return_ACPI_STATUS (status); - break; /* @@ -403,8 +405,7 @@ */ case AML_COPY_OP: /* Copy (Source, Target) */ - status = AE_NOT_IMPLEMENTED; - goto cleanup; + status = acpi_ut_copy_iobject_to_iobject (operand[0], &return_desc, walk_state); break; @@ -432,29 +433,26 @@ break; - /* - * These are two obsolete opcodes - */ case AML_SHIFT_LEFT_BIT_OP: /* Shift_left_bit (Source, Bit_num) */ case AML_SHIFT_RIGHT_BIT_OP: /* Shift_right_bit (Source, Bit_num) */ - + /* + * These are two obsolete opcodes + */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s is obsolete and not implemented\n", acpi_ps_get_opcode_name (walk_state->opcode))); status = AE_SUPPORT; goto cleanup; - break; default: /* Unknown opcode */ - REPORT_ERROR (("Acpi_ex_opcode_1A_1T_1R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_1A_1T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } - /* * Store the return value computed above into the target object */ @@ -499,13 +497,12 @@ acpi_integer value; - FUNCTION_TRACE_STR ("Ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); - /* Get the operand and decode the opcode */ + /* Examine the AML opcode */ switch (walk_state->opcode) { - case AML_LNOT_OP: /* LNot (Operand) */ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); @@ -523,10 +520,10 @@ /* * Since we are expecting a Reference operand, it - * can be either a Node or an internal object. + * can be either a NS Node or an internal object. */ return_desc = operand[0]; - if (VALID_DESCRIPTOR_TYPE (operand[0], ACPI_DESC_TYPE_INTERNAL)) { + if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_OPERAND) { /* Internal reference object - prevent deletion */ acpi_ut_add_reference (return_desc); @@ -582,7 +579,7 @@ case AML_DEBUG_OP: - /* Per 1.0b spec, Debug object is of type "Debug_object" */ + /* The Debug Object is of type "Debug_object" */ type = ACPI_TYPE_DEBUG_OBJECT; break; @@ -601,7 +598,6 @@ */ type = (*(operand[0]->reference.where))->common.type; } - break; @@ -615,13 +611,12 @@ default: - REPORT_ERROR (("Acpi_ex_opcode_1A_0T_1R/Type_op: Internal error - Unknown Reference subtype %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_1A_0T_1R/Type_op: Internal error - Unknown Reference subtype %X\n", operand[0]->reference.opcode)); status = AE_AML_INTERNAL; goto cleanup; } } - else { /* * It's not a Reference, so it must be a direct name pointer. @@ -636,6 +631,11 @@ case INTERNAL_TYPE_INDEX_FIELD: type = ACPI_TYPE_FIELD_UNIT; + break; + + default: + /* No change to Type required */ + break; } } @@ -655,15 +655,19 @@ case AML_SIZE_OF_OP: /* Size_of (Source_object) */ temp_desc = operand[0]; - if (VALID_DESCRIPTOR_TYPE (operand[0], ACPI_DESC_TYPE_NAMED)) { + if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_NAMED) { temp_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) operand[0]); } if (!temp_desc) { value = 0; } - else { + /* + * Type is guaranteed to be a buffer, string, or package at this + * point (even if the original operand was an object reference, it + * will be resolved and typechecked during operand resolution.) + */ switch (temp_desc->common.type) { case ACPI_TYPE_BUFFER: value = temp_desc->buffer.length; @@ -677,16 +681,9 @@ value = temp_desc->package.count; break; - case INTERNAL_TYPE_REFERENCE: - - /* TBD: this must be a reference to a buf/str/pkg?? */ - - value = 4; - break; - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Not Buf/Str/Pkg - found type %X\n", - temp_desc->common.type)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Size_of, Not Buf/Str/Pkg - found type %s\n", + acpi_ut_get_type_name (temp_desc->common.type))); status = AE_AML_OPERAND_TYPE; goto cleanup; } @@ -715,79 +712,113 @@ break; - case AML_DEREF_OF_OP: /* Deref_of (Obj_reference) */ + case AML_DEREF_OF_OP: /* Deref_of (Obj_reference | String) */ - /* Check for a method local or argument */ + /* Check for a method local or argument, or standalone String */ - if (!VALID_DESCRIPTOR_TYPE (operand[0], ACPI_DESC_TYPE_NAMED)) { - /* - * Must resolve/dereference the local/arg reference first - */ - switch (operand[0]->reference.opcode) { - /* Set Operand[0] to the value of the local/arg */ + if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) != ACPI_DESC_TYPE_NAMED) { + switch (ACPI_GET_OBJECT_TYPE (operand[0])) { + case INTERNAL_TYPE_REFERENCE: + /* + * This is a Deref_of (Local_x | Arg_x) + * + * Must resolve/dereference the local/arg reference first + */ + switch (operand[0]->reference.opcode) { + case AML_LOCAL_OP: + case AML_ARG_OP: + + /* Set Operand[0] to the value of the local/arg */ + + status = acpi_ds_method_data_get_value (operand[0]->reference.opcode, + operand[0]->reference.offset, walk_state, &temp_desc); + if (ACPI_FAILURE (status)) { + goto cleanup; + } - case AML_LOCAL_OP: - case AML_ARG_OP: + /* + * Delete our reference to the input object and + * point to the object just retrieved + */ + acpi_ut_remove_reference (operand[0]); + operand[0] = temp_desc; + break; - acpi_ds_method_data_get_value (operand[0]->reference.opcode, - operand[0]->reference.offset, walk_state, &temp_desc); + default: + + /* Must be an Index op - handled below */ + break; + } + break; + + + case ACPI_TYPE_STRING: /* - * Delete our reference to the input object and - * point to the object just retrieved + * This is a Deref_of (String). The string is a reference to a named ACPI object. + * + * 1) Find the owning Node + * 2) Dereference the node to an actual object. Could be a Field, so we nee + * to resolve the node to a value. */ - acpi_ut_remove_reference (operand[0]); - operand[0] = temp_desc; - break; + status = acpi_ns_get_node_by_path (operand[0]->string.pointer, + walk_state->scope_info->scope.node, ACPI_NS_SEARCH_PARENT, + ACPI_CAST_INDIRECT_PTR (acpi_namespace_node, &return_desc)); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_ex_resolve_node_to_value ( + ACPI_CAST_INDIRECT_PTR (acpi_namespace_node, &return_desc), walk_state); + goto cleanup; + default: - /* Index op - handled below */ - break; + status = AE_AML_OPERAND_TYPE; + goto cleanup; } } - /* Operand[0] may have changed from the code above */ - if (VALID_DESCRIPTOR_TYPE (operand[0], ACPI_DESC_TYPE_NAMED)) { - /* Get the actual object from the Node (This is the dereference) */ - - return_desc = ((acpi_namespace_node *) operand[0])->object; - - /* Returning a pointer to the object, add another reference! */ - - acpi_ut_add_reference (return_desc); + if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_NAMED) { + /* + * This is a Deref_of (Object_reference) + * Get the actual object from the Node (This is the dereference). + * -- This case may only happen when a Local_x or Arg_x is dereferenced above. + */ + return_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) operand[0]); } - else { /* - * This must be a reference object produced by the Index - * ASL operation -- check internal opcode + * This must be a reference object produced by either the Index() or + * Ref_of() operator */ - if ((operand[0]->reference.opcode != AML_INDEX_OP) && - (operand[0]->reference.opcode != AML_REF_OF_OP)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode in ref(%p) - %X\n", - operand[0], operand[0]->reference.opcode)); - - status = AE_TYPE; - goto cleanup; - } - - switch (operand[0]->reference.opcode) { case AML_INDEX_OP: /* - * Supported target types for the Index operator are - * 1) A Buffer - * 2) A Package + * The target type for the Index operator must be + * either a Buffer or a Package */ - if (operand[0]->reference.target_type == ACPI_TYPE_BUFFER_FIELD) { + switch (operand[0]->reference.target_type) { + case ACPI_TYPE_BUFFER_FIELD: + + /* Ensure that the Buffer arguments are evaluated */ + + temp_desc = operand[0]->reference.object; +#if 0 + + status = acpi_ds_get_buffer_arguments (temp_desc); + if (ACPI_FAILURE (status)) { + goto cleanup; + } +#endif + /* - * The target is a buffer, we must create a new object that - * contains one element of the buffer, the element pointed - * to by the index. + * Create a new object that contains one element of the + * buffer -- the element pointed to by the index. * * NOTE: index into a buffer is NOT a pointer to a * sub-buffer of the main buffer, it is only a pointer to a @@ -799,20 +830,29 @@ goto cleanup; } - temp_desc = operand[0]->reference.object; + /* + * Since we are returning the value of the buffer at the + * indexed location, we don't need to add an additional + * reference to the buffer itself. + */ return_desc->integer.value = temp_desc->buffer.pointer[operand[0]->reference.offset]; + break; - /* TBD: [Investigate] (see below) Don't add an additional - * ref! - */ - } - else if (operand[0]->reference.target_type == ACPI_TYPE_PACKAGE) { + case ACPI_TYPE_PACKAGE: + +#if 0 + /* Ensure that the Package arguments are evaluated */ + + status = acpi_ds_get_package_arguments (operand[0]->reference.object); + if (ACPI_FAILURE (status)) { + goto cleanup; + } +#endif /* - * The target is a package, we want to return the referenced - * element of the package. We must add another reference to - * this object, however. + * Return the referenced element of the package. We must add + * another reference to the referenced object, however. */ return_desc = *(operand[0]->reference.where); if (!return_desc) { @@ -821,7 +861,6 @@ * an uninitialized package element and is thus a * severe error. */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "NULL package element obj %p\n", operand[0])); status = AE_AML_UNINITIALIZED_ELEMENT; @@ -829,15 +868,16 @@ } acpi_ut_add_reference (return_desc); - } + break; + + + default: - else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Target_type %X in obj %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Index Target_type %X in obj %p\n", operand[0]->reference.target_type, operand[0])); status = AE_AML_OPERAND_TYPE; goto cleanup; } - break; @@ -849,15 +889,22 @@ acpi_ut_add_reference (return_desc); break; + + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode in ref(%p) - %X\n", + operand[0], operand[0]->reference.opcode)); + + status = AE_TYPE; + goto cleanup; } } - break; default: - REPORT_ERROR (("Acpi_ex_opcode_1A_0T_1R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_1A_0T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; diff -Nur linux-2.4.19/drivers/acpi/executer/exoparg2.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg2.c --- linux-2.4.19/drivers/acpi/executer/exoparg2.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg2.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: exoparg2 - AML execution - opcodes with 2 arguments - * $Revision: 97 $ + * $Revision: 106 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,15 +26,13 @@ #include "acpi.h" #include "acparser.h" -#include "acnamesp.h" #include "acinterp.h" #include "acevents.h" #include "amlcode.h" -#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exoparg2") + ACPI_MODULE_NAME ("exoparg2") /*! @@ -84,50 +82,45 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_STR ("Ex_opcode_2A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_2A_0T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the opcode */ switch (walk_state->opcode) { - case AML_NOTIFY_OP: /* Notify (Notify_object, Notify_value) */ /* The first operand is a namespace node */ node = (acpi_namespace_node *) operand[0]; - /* The node must refer to a device or thermal zone */ - - if (node && operand[1]) /* TBD: is this check necessary? */ { - switch (node->type) { - case ACPI_TYPE_DEVICE: - case ACPI_TYPE_THERMAL: + /* Notifies allowed on this object? */ - /* - * Dispatch the notify to the appropriate handler - * NOTE: the request is queued for execution after this method - * completes. The notify handlers are NOT invoked synchronously - * from this thread -- because handlers may in turn run other - * control methods. - */ - status = acpi_ev_queue_notify_request (node, - (u32) operand[1]->integer.value); - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unexpected notify object type %X\n", - node->type)); + if (!acpi_ev_is_notify_object (node)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unexpected notify object type [%s]\n", + acpi_ut_get_type_name (node->type))); - status = AE_AML_OPERAND_TYPE; - break; - } + status = AE_AML_OPERAND_TYPE; + break; } + + /* + * Dispatch the notify to the appropriate handler + * NOTE: the request is queued for execution after this method + * completes. The notify handlers are NOT invoked synchronously + * from this thread -- because handlers may in turn run other + * control methods. + */ + status = acpi_ev_queue_notify_request (node, + (u32) operand[1]->integer.value); break; + default: - REPORT_ERROR (("Acpi_ex_opcode_2A_0T_0R: Unknown opcode %X\n", walk_state->opcode)); + ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_0T_0R: Unknown opcode %X\n", + walk_state->opcode)); status = AE_AML_BAD_OPCODE; } @@ -158,7 +151,7 @@ acpi_status status; - FUNCTION_TRACE_STR ("Ex_opcode_2A_2T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_2A_2T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); /* @@ -191,11 +184,10 @@ default: - REPORT_ERROR (("Acpi_ex_opcode_2A_2T_1R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_2T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; - break; } @@ -257,7 +249,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_STR ("Ex_opcode_2A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_2A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); /* @@ -344,7 +336,7 @@ case AML_CONCAT_RES_OP: /* Concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ - status = AE_NOT_IMPLEMENTED; + status = acpi_ex_concat_template (operand[0], operand[1], &return_desc, walk_state); break; @@ -424,12 +416,11 @@ walk_state->result_obj = return_desc; goto cleanup; - break; default: - REPORT_ERROR (("Acpi_ex_opcode_2A_1T_1R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_1T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; break; @@ -486,7 +477,7 @@ u8 logical_result = FALSE; - FUNCTION_TRACE_STR ("Ex_opcode_2A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_2A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); /* Create the internal return object */ @@ -531,10 +522,9 @@ default: - REPORT_ERROR (("Acpi_ex_opcode_2A_0T_1R: Unknown opcode %X\n", walk_state->opcode)); + ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_0T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; - break; } diff -Nur linux-2.4.19/drivers/acpi/executer/exoparg3.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg3.c --- linux-2.4.19/drivers/acpi/executer/exoparg3.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg3.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exoparg3 - AML execution - opcodes with 3 arguments - * $Revision: 3 $ + * $Revision: 13 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +32,7 @@ #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exoparg3") + ACPI_MODULE_NAME ("exoparg3") /*! @@ -79,7 +79,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_STR ("Ex_opcode_3A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_3A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { @@ -87,7 +87,7 @@ case AML_FATAL_OP: /* Fatal (Fatal_type Fatal_code Fatal_arg) */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Fatal_op: Type %x Code %x Arg %x <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", + "Fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", (u32) operand[0]->integer.value, (u32) operand[1]->integer.value, (u32) operand[2]->integer.value)); @@ -102,7 +102,7 @@ /* * Always signal the OS! */ - acpi_os_signal (ACPI_SIGNAL_FATAL, fatal); + status = acpi_os_signal (ACPI_SIGNAL_FATAL, fatal); /* Might return while OS is shutting down, just continue */ @@ -112,11 +112,10 @@ default: - REPORT_ERROR (("Acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; - break; } @@ -146,11 +145,11 @@ acpi_operand_object *return_desc = NULL; char *buffer; acpi_status status = AE_OK; - u32 index; - u32 length; + NATIVE_UINT index; + ACPI_SIZE length; - FUNCTION_TRACE_STR ("Ex_opcode_3A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_3A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { @@ -168,8 +167,8 @@ /* Get the Integer values from the objects */ - index = (u32) operand[1]->integer.value; - length = (u32) operand[2]->integer.value; + index = (NATIVE_UINT) operand[1]->integer.value; + length = (ACPI_SIZE) operand[2]->integer.value; /* * If the index is beyond the length of the String/Buffer, or if the @@ -181,37 +180,36 @@ if ((index + length) > operand[0]->string.length) { - length = operand[0]->string.length - index; + length = (ACPI_SIZE) operand[0]->string.length - index; } /* Allocate a new buffer for the String/Buffer */ - buffer = ACPI_MEM_CALLOCATE (length + 1); + buffer = ACPI_MEM_CALLOCATE ((ACPI_SIZE) length + 1); if (!buffer) { - return (AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto cleanup; } /* Copy the portion requested */ - MEMCPY (buffer, operand[0]->string.pointer + index, - length); + ACPI_MEMCPY (buffer, operand[0]->string.pointer + index, + length); /* Set the length of the new String/Buffer */ return_desc->string.pointer = buffer; - return_desc->string.length = length; + return_desc->string.length = (u32) length; } - break; default: - REPORT_ERROR (("Acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; - break; } /* Store the result in the target */ diff -Nur linux-2.4.19/drivers/acpi/executer/exoparg6.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg6.c --- linux-2.4.19/drivers/acpi/executer/exoparg6.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exoparg6.c Fri Apr 26 11:07:18 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exoparg6 - AML execution - opcodes with 6 arguments - * $Revision: 4 $ + * $Revision: 10 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +32,7 @@ #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exoparg6") + ACPI_MODULE_NAME ("exoparg6") /*! @@ -158,7 +158,7 @@ acpi_operand_object *this_element; - FUNCTION_TRACE_STR ("Ex_opcode_6A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("Ex_opcode_6A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { @@ -199,6 +199,7 @@ * Examine each element until a match is found. Within the loop, * "continue" signifies that the current element does not match * and the next should be examined. + * * Upon finding a match, the loop will terminate via "break" at * the bottom. If it terminates "normally", Match_value will be -1 * (its initial value) indicating that no match was found. When @@ -209,27 +210,21 @@ /* * Treat any NULL or non-numeric elements as non-matching. - * TBD [Unhandled] - if an element is a Name, - * should we examine its value? */ if (!this_element || this_element->common.type != ACPI_TYPE_INTEGER) { continue; } - /* - * Within these switch statements: - * "break" (exit from the switch) signifies a match; - * "continue" (proceed to next iteration of enclosing - * "for" loop) signifies a non-match. + * "continue" (proceed to next iteration of enclosing + * "for" loop) signifies a non-match. */ if (!acpi_ex_do_match ((u32) operand[1]->integer.value, this_element->integer.value, operand[2]->integer.value)) { continue; } - if (!acpi_ex_do_match ((u32) operand[3]->integer.value, this_element->integer.value, operand[4]->integer.value)) { continue; @@ -246,18 +241,16 @@ case AML_LOAD_TABLE_OP: - status = AE_NOT_IMPLEMENTED; - goto cleanup; + status = acpi_ex_load_table_op (walk_state, &return_desc); break; default: - REPORT_ERROR (("Acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("Acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; - break; } diff -Nur linux-2.4.19/drivers/acpi/executer/exprep.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exprep.c --- linux-2.4.19/drivers/acpi/executer/exprep.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exprep.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities - * $Revision: 99 $ + * $Revision: 117 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,88 +29,128 @@ #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" -#include "acparser.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exprep") + ACPI_MODULE_NAME ("exprep") /******************************************************************************* * - * FUNCTION: Acpi_ex_decode_field_access_type + * FUNCTION: Acpi_ex_decode_field_access * * PARAMETERS: Access - Encoded field access bits * Length - Field length. * - * RETURN: Field granularity (8, 16, 32 or 64) + * RETURN: Field granularity (8, 16, 32 or 64) and + * Byte_alignment (1, 2, 3, or 4) * * DESCRIPTION: Decode the Access_type bits of a field definition. * ******************************************************************************/ static u32 -acpi_ex_decode_field_access_type ( - u32 access, - u16 length, - u32 *alignment) +acpi_ex_decode_field_access ( + acpi_operand_object *obj_desc, + u8 field_flags, + u32 *return_byte_alignment) { - PROC_NAME ("Ex_decode_field_access_type"); + u32 access; + u8 byte_alignment; + u8 bit_length; +/* u32 Length; */ + + + ACPI_FUNCTION_NAME ("Ex_decode_field_access"); + + access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK); switch (access) { - case ACCESS_ANY_ACC: + case AML_FIELD_ACCESS_ANY: - *alignment = 8; + byte_alignment = 1; + bit_length = 8; + +#if 0 + /* + * TBD: optimize + * + * Any attempt to optimize the access size to the size of the field + * must take into consideration the length of the region and take + * care that an access to the field will not attempt to access + * beyond the end of the region. + */ /* Use the length to set the access type */ + length = obj_desc->common_field.bit_length; + if (length <= 8) { - return (8); + bit_length = 8; } else if (length <= 16) { - return (16); + bit_length = 16; } else if (length <= 32) { - return (32); + bit_length = 32; } else if (length <= 64) { - return (64); + bit_length = 64; } + else { + /* Larger than Qword - just use byte-size chunks */ - /* Default is 8 (byte) */ + bit_length = 8; + } +#endif + break; - return (8); + case AML_FIELD_ACCESS_BYTE: + byte_alignment = 1; + bit_length = 8; break; - case ACCESS_BYTE_ACC: - *alignment = 8; - return (8); + case AML_FIELD_ACCESS_WORD: + byte_alignment = 2; + bit_length = 16; break; - case ACCESS_WORD_ACC: - *alignment = 16; - return (16); + case AML_FIELD_ACCESS_DWORD: + byte_alignment = 4; + bit_length = 32; break; - case ACCESS_DWORD_ACC: - *alignment = 32; - return (32); + case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ + byte_alignment = 8; + bit_length = 64; break; - case ACCESS_QWORD_ACC: /* ACPI 2.0 */ - *alignment = 64; - return (64); + case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 */ + byte_alignment = 8; + bit_length = 8; break; default: /* Invalid field access type */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unknown field access type %x\n", + "Unknown field access type %X\n", access)); return (0); } + + if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { + /* + * Buffer_field access can be on any byte boundary, so the + * Byte_alignment is always 1 byte -- regardless of any Byte_alignment + * implied by the field access type. + */ + byte_alignment = 1; + } + + *return_byte_alignment = byte_alignment; + return (bit_length); } @@ -128,7 +168,9 @@ * RETURN: Status * * DESCRIPTION: Initialize the areas of the field object that are common - * to the various types of fields. + * to the various types of fields. Note: This is very "sensitive" + * code because we are solving the general case for field + * alignment. * ******************************************************************************/ @@ -136,107 +178,106 @@ acpi_ex_prep_common_field_object ( acpi_operand_object *obj_desc, u8 field_flags, + u8 field_attribute, u32 field_bit_position, u32 field_bit_length) { u32 access_bit_width; - u32 alignment; + u32 byte_alignment; u32 nearest_byte_address; - FUNCTION_TRACE ("Ex_prep_common_field_object"); + ACPI_FUNCTION_TRACE ("Ex_prep_common_field_object"); /* * Note: the structure being initialized is the - * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common area - * are initialized by this procedure. + * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common + * area are initialized by this procedure. */ - - /* Demultiplex the Field_flags byte */ - - obj_desc->common_field.lock_rule = (u8) ((field_flags & LOCK_RULE_MASK) - >> LOCK_RULE_SHIFT); - obj_desc->common_field.update_rule = (u8) ((field_flags & UPDATE_RULE_MASK) - >> UPDATE_RULE_SHIFT); - /* Other misc fields */ - - obj_desc->common_field.bit_length = (u16) field_bit_length; + obj_desc->common_field.field_flags = field_flags; + obj_desc->common_field.attribute = field_attribute; + obj_desc->common_field.bit_length = field_bit_length; /* * Decode the access type so we can compute offsets. The access type gives * two pieces of information - the width of each field access and the - * necessary alignment of the access. For Any_acc, the width used is the - * largest necessary/possible in an attempt to access the whole field in one - * I/O operation. However, for Any_acc, the alignment is 8. For all other - * access types (Byte, Word, Dword, Qword), the width is the same as the - * alignment. + * necessary Byte_alignment (address granularity) of the access. + * + * For Any_acc, the Access_bit_width is the largest width that is both + * necessary and possible in an attempt to access the whole field in one + * I/O operation. However, for Any_acc, the Byte_alignment is always one + * byte. + * + * For all Buffer Fields, the Byte_alignment is always one byte. + * + * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is + * the same (equivalent) as the Byte_alignment. */ - access_bit_width = acpi_ex_decode_field_access_type ( - ((field_flags & ACCESS_TYPE_MASK) >> ACCESS_TYPE_SHIFT), - obj_desc->field.bit_length, &alignment); + access_bit_width = acpi_ex_decode_field_access (obj_desc, field_flags, + &byte_alignment); if (!access_bit_width) { return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } /* Setup width (access granularity) fields */ - obj_desc->common_field.access_bit_width = (u8) access_bit_width; /* 8, 16, 32, 64 */ - obj_desc->common_field.access_byte_width = (u8) DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ - - if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { - /* - * Buffer_field access can be on any byte boundary, so the - * alignment is always 8 (regardless of any alignment implied by the - * field access type.) - */ - alignment = 8; - } - + obj_desc->common_field.access_byte_width = (u8) + ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ /* - * Base_byte_offset is the address of the start of the field within the region. It is - * the byte address of the first *datum* (field-width data unit) of the field. - * (i.e., the first datum that contains at least the first *bit* of the field.) + * Base_byte_offset is the address of the start of the field within the + * region. It is the byte address of the first *datum* (field-width data + * unit) of the field. (i.e., the first datum that contains at least the + * first *bit* of the field.) + * + * Note: Byte_alignment is always either equal to the Access_bit_width or 8 + * (Byte access), and it defines the addressing granularity of the parent + * region or buffer. */ - nearest_byte_address = ROUND_BITS_DOWN_TO_BYTES (field_bit_position); - obj_desc->common_field.base_byte_offset = ROUND_DOWN (nearest_byte_address, - DIV_8 (alignment)); + nearest_byte_address = + ACPI_ROUND_BITS_DOWN_TO_BYTES (field_bit_position); + obj_desc->common_field.base_byte_offset = + ACPI_ROUND_DOWN (nearest_byte_address, byte_alignment); /* - * Start_field_bit_offset is the offset of the first bit of the field within a field datum. - * This is calculated as the number of bits from the Base_byte_offset. In other words, - * the start of the field is relative to a byte address, regardless of the access type - * of the field. + * Start_field_bit_offset is the offset of the first bit of the field within + * a field datum. */ - obj_desc->common_field.start_field_bit_offset = (u8) (MOD_8 (field_bit_position)); + obj_desc->common_field.start_field_bit_offset = (u8) + (field_bit_position - ACPI_MUL_8 (obj_desc->common_field.base_byte_offset)); /* - * Datum_valid_bits is the number of valid field bits in the first field datum. + * Valid bits -- the number of bits that compose a partial datum, + * 1) At the end of the field within the region (arbitrary starting bit + * offset) + * 2) At the end of a buffer used to contain the field (starting offset + * always zero) */ - obj_desc->common_field.datum_valid_bits = (u8) (access_bit_width - - obj_desc->common_field.start_field_bit_offset); + obj_desc->common_field.end_field_valid_bits = (u8) + ((obj_desc->common_field.start_field_bit_offset + field_bit_length) % + access_bit_width); + /* Start_buffer_bit_offset always = 0 */ + + obj_desc->common_field.end_buffer_valid_bits = (u8) + (field_bit_length % access_bit_width); /* - * Valid bits -- the number of bits that compose a partial datum, - * 1) At the end of the field within the region (arbitrary starting bit offset) - * 2) At the end of a buffer used to contain the field (starting offset always zero) + * Datum_valid_bits is the number of valid field bits in the first + * field datum. */ - obj_desc->common_field.end_field_valid_bits = (u8) ((obj_desc->common_field.start_field_bit_offset + - field_bit_length) % access_bit_width); - obj_desc->common_field.end_buffer_valid_bits = (u8) (field_bit_length % access_bit_width); /* Start_buffer_bit_offset always = 0 */ - + obj_desc->common_field.datum_valid_bits = (u8) + (access_bit_width - obj_desc->common_field.start_field_bit_offset); /* - * Does the entire field fit within a single field access element - * (datum)? (without crossing a datum boundary) + * Does the entire field fit within a single field access element? (datum) + * (i.e., without crossing a datum boundary) */ - if ((obj_desc->common_field.start_field_bit_offset + obj_desc->common_field.bit_length) <= - (u16) obj_desc->common_field.access_bit_width) { - obj_desc->common_field.access_flags |= AFIELD_SINGLE_DATUM; + if ((obj_desc->common_field.start_field_bit_offset + field_bit_length) <= + (u16) access_bit_width) { + obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM; } - return_ACPI_STATUS (AE_OK); } @@ -267,7 +308,7 @@ acpi_status status; - FUNCTION_TRACE ("Ex_prep_field_value"); + ACPI_FUNCTION_TRACE ("Ex_prep_field_value"); /* Parameter validation */ @@ -280,14 +321,15 @@ type = acpi_ns_get_type (info->region_node); if (type != ACPI_TYPE_REGION) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed Region, found type %X %s\n", type, acpi_ut_get_type_name (type))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } } - /* Allocate a new region object */ + /* Allocate a new field object */ obj_desc = acpi_ut_create_internal_object (info->field_type); if (!obj_desc) { @@ -296,8 +338,9 @@ /* Initialize areas of the object that are common to all fields */ + obj_desc->common_field.node = info->field_node; status = acpi_ex_prep_common_field_object (obj_desc, info->field_flags, - info->field_bit_position, info->field_bit_length); + info->attribute, info->field_bit_position, info->field_bit_length); if (ACPI_FAILURE (status)) { acpi_ut_delete_object_desc (obj_desc); return_ACPI_STATUS (status); @@ -308,33 +351,37 @@ switch (info->field_type) { case INTERNAL_TYPE_REGION_FIELD: - obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node); + obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node); /* An additional reference for the container */ acpi_ut_add_reference (obj_desc->field.region_obj); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Region_field: Bitoff=%X Off=%X Gran=%X Region %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Region_field: Bitoff=%X Off=%X Gran=%X Region %p\n", obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, - obj_desc->field.access_bit_width, obj_desc->field.region_obj)); + obj_desc->field.access_byte_width, obj_desc->field.region_obj)); break; case INTERNAL_TYPE_BANK_FIELD: - obj_desc->bank_field.value = info->bank_value; - obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node); - obj_desc->bank_field.bank_register_obj = acpi_ns_get_attached_object (info->register_node); + obj_desc->bank_field.value = info->bank_value; + obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node); + obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (info->register_node); /* An additional reference for the attached objects */ acpi_ut_add_reference (obj_desc->bank_field.region_obj); - acpi_ut_add_reference (obj_desc->bank_field.bank_register_obj); + acpi_ut_add_reference (obj_desc->bank_field.bank_obj); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Bank Field: Bit_off=%X Off=%X Gran=%X Region %p Bank_reg %p\n", - obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset, - obj_desc->field.access_bit_width, obj_desc->bank_field.region_obj, - obj_desc->bank_field.bank_register_obj)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Bank Field: Bit_off=%X Off=%X Gran=%X Region %p Bank_reg %p\n", + obj_desc->bank_field.start_field_bit_offset, + obj_desc->bank_field.base_byte_offset, + obj_desc->field.access_byte_width, + obj_desc->bank_field.region_obj, + obj_desc->bank_field.bank_obj)); break; @@ -342,8 +389,8 @@ obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node); obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node); - obj_desc->index_field.value = (u32) (info->field_bit_position / - obj_desc->field.access_bit_width); + obj_desc->index_field.value = (u32) + (info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width)); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Index Object\n")); @@ -355,11 +402,18 @@ acpi_ut_add_reference (obj_desc->index_field.data_obj); acpi_ut_add_reference (obj_desc->index_field.index_obj); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Index_field: bitoff=%X off=%X gran=%X Index %p Data %p\n", - obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, - obj_desc->field.access_bit_width, obj_desc->index_field.index_obj, + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Index_field: bitoff=%X off=%X gran=%X Index %p Data %p\n", + obj_desc->index_field.start_field_bit_offset, + obj_desc->index_field.base_byte_offset, + obj_desc->field.access_byte_width, + obj_desc->index_field.index_obj, obj_desc->index_field.data_obj)); break; + + default: + /* No other types should get here */ + break; } /* @@ -367,10 +421,10 @@ * preserving the current type of that Named_obj. */ status = acpi_ns_attach_object (info->field_node, obj_desc, - (u8) acpi_ns_get_type (info->field_node)); + acpi_ns_get_type (info->field_node)); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "set Named_obj %p (%4.4s) val = %p\n", - info->field_node, (char*)&(info->field_node->name), obj_desc)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "set Named_obj %p (%4.4s) val = %p\n", + info->field_node, info->field_node->name.ascii, obj_desc)); /* Remove local reference to the object */ diff -Nur linux-2.4.19/drivers/acpi/executer/exregion.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exregion.c --- linux-2.4.19/drivers/acpi/executer/exregion.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exregion.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exregion - ACPI default Op_region (address space) handlers - * $Revision: 61 $ + * $Revision: 79 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,14 +27,10 @@ #include "acpi.h" #include "acinterp.h" -#include "amlcode.h" -#include "acnamesp.h" -#include "achware.h" -#include "acevents.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exregion") + ACPI_MODULE_NAME ("exregion") /******************************************************************************* @@ -60,7 +56,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context) { @@ -68,9 +64,12 @@ void *logical_addr_ptr = NULL; acpi_mem_space_context *mem_info = region_context; u32 length; + ACPI_SIZE window_size; +#ifndef _HW_ALIGNMENT_SUPPORT + u32 remainder; +#endif - - FUNCTION_TRACE ("Ex_system_memory_space_handler"); + ACPI_FUNCTION_TRACE ("Ex_system_memory_space_handler"); /* Validate and translate the bit width */ @@ -88,14 +87,28 @@ length = 4; break; + case 64: + length = 8; + break; + default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid System_memory width %d\n", bit_width)); return_ACPI_STATUS (AE_AML_OPERAND_VALUE); - break; } +#ifndef _HW_ALIGNMENT_SUPPORT + /* + * Hardware does not support non-aligned data transfers, we must verify + * the request. + */ + (void) acpi_ut_short_divide ((acpi_integer *) &address, length, NULL, &remainder); + if (remainder != 0) { + return_ACPI_STATUS (AE_AML_ALIGNMENT); + } +#endif + /* * Does the request fit into the cached memory mapping? * Is 1) Address below the current mapping? OR @@ -115,61 +128,80 @@ mem_info->mapped_length); } - mem_info->mapped_length = 0; /* In case of failure below */ + /* + * Don't attempt to map memory beyond the end of the region, and + * constrain the maximum mapping size to something reasonable. + */ + window_size = (ACPI_SIZE) ((mem_info->address + mem_info->length) - address); + if (window_size > SYSMEM_REGION_WINDOW_SIZE) { + window_size = SYSMEM_REGION_WINDOW_SIZE; + } /* Create a new mapping starting at the address given */ - status = acpi_os_map_memory (address, SYSMEM_REGION_WINDOW_SIZE, + status = acpi_os_map_memory (address, window_size, (void **) &mem_info->mapped_logical_address); if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n", + ACPI_HIDWORD (address), ACPI_LODWORD (address), (u32) window_size)); + mem_info->mapped_length = 0; return_ACPI_STATUS (status); } /* Save the physical address and mapping size */ mem_info->mapped_physical_address = address; - mem_info->mapped_length = SYSMEM_REGION_WINDOW_SIZE; + mem_info->mapped_length = window_size; } - /* * Generate a logical pointer corresponding to the address we want to * access */ - - /* TBD: should these pointers go to 64-bit in all cases ? */ - logical_addr_ptr = mem_info->mapped_logical_address + ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "System_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, - HIDWORD (address), LODWORD (address))); - - /* Perform the memory read or write */ + ACPI_HIDWORD (address), ACPI_LODWORD (address))); + /* + * Perform the memory read or write + * + * Note: For machines that do not support non-aligned transfers, the target + * address was checked for alignment above. We do not attempt to break the + * transfer up into smaller (byte-size) chunks because the AML specifically + * asked for a transfer width that the hardware may require. + */ switch (function) { + case ACPI_READ: - case ACPI_READ_ADR_SPACE: - + *value = 0; switch (bit_width) { case 8: - *value = (u32)* (u8 *) logical_addr_ptr; + *value = (acpi_integer) *((u8 *) logical_addr_ptr); break; case 16: - MOVE_UNALIGNED16_TO_32 (value, logical_addr_ptr); + *value = (acpi_integer) *((u16 *) logical_addr_ptr); break; case 32: - MOVE_UNALIGNED32_TO_32 (value, logical_addr_ptr); + *value = (acpi_integer) *((u32 *) logical_addr_ptr); break; - } +#if ACPI_MACHINE_WIDTH != 16 + case 64: + *value = (acpi_integer) *((u64 *) logical_addr_ptr); + break; +#endif + default: + /* Bit_width was already validated */ + break; + } break; - - case ACPI_WRITE_ADR_SPACE: + case ACPI_WRITE: switch (bit_width) { case 8: @@ -177,16 +209,24 @@ break; case 16: - MOVE_UNALIGNED16_TO_16 (logical_addr_ptr, value); + *(u16 *) logical_addr_ptr = (u16) *value; break; case 32: - MOVE_UNALIGNED32_TO_32 (logical_addr_ptr, value); + *(u32 *) logical_addr_ptr = (u32) *value; break; - } - break; +#if ACPI_MACHINE_WIDTH != 16 + case 64: + *(u64 *) logical_addr_ptr = (u64) *value; + break; +#endif + default: + /* Bit_width was already validated */ + break; + } + break; default: status = AE_BAD_PARAMETER; @@ -220,37 +260,34 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_system_io_space_handler"); + ACPI_FUNCTION_TRACE ("Ex_system_io_space_handler"); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "System_iO %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, - HIDWORD (address), LODWORD (address))); + ACPI_HIDWORD (address), ACPI_LODWORD (address))); /* Decode the function parameter */ switch (function) { - - case ACPI_READ_ADR_SPACE: + case ACPI_READ: *value = 0; status = acpi_os_read_port ((ACPI_IO_ADDRESS) address, value, bit_width); break; - - case ACPI_WRITE_ADR_SPACE: + case ACPI_WRITE: status = acpi_os_write_port ((ACPI_IO_ADDRESS) address, *value, bit_width); break; - default: status = AE_BAD_PARAMETER; break; @@ -283,7 +320,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context) { @@ -292,11 +329,11 @@ u16 pci_register; - FUNCTION_TRACE ("Ex_pci_config_space_handler"); + ACPI_FUNCTION_TRACE ("Ex_pci_config_space_handler"); /* - * The arguments to Acpi_os(Read|Write)Pci_cfg(Byte|Word|Dword) are: + * The arguments to Acpi_os(Read|Write)Pci_configuration are: * * Pci_segment is the PCI bus segment range 0-31 * Pci_bus is the PCI bus number range 0-255 @@ -308,7 +345,7 @@ * */ pci_id = (acpi_pci_id *) region_context; - pci_register = (u16) address; + pci_register = (u16) (u32) address; ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Pci_config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n", @@ -316,20 +353,17 @@ pci_id->function, pci_register)); switch (function) { - - case ACPI_READ_ADR_SPACE: + case ACPI_READ: *value = 0; status = acpi_os_read_pci_configuration (pci_id, pci_register, value, bit_width); break; - - case ACPI_WRITE_ADR_SPACE: + case ACPI_WRITE: status = acpi_os_write_pci_configuration (pci_id, pci_register, *value, bit_width); break; - default: status = AE_BAD_PARAMETER; @@ -363,14 +397,14 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_cmos_space_handler"); + ACPI_FUNCTION_TRACE ("Ex_cmos_space_handler"); return_ACPI_STATUS (status); @@ -400,16 +434,76 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_pci_bar_space_handler"); + ACPI_FUNCTION_TRACE ("Ex_pci_bar_space_handler"); return_ACPI_STATUS (status); } + + +/******************************************************************************* + * + * FUNCTION: Acpi_ex_data_table_space_handler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * Bit_width - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * Handler_context - Pointer to Handler's context + * Region_context - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the Data Table address space (Op Region) + * + ******************************************************************************/ + +acpi_status +acpi_ex_data_table_space_handler ( + u32 function, + ACPI_PHYSICAL_ADDRESS address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + acpi_status status = AE_OK; + u32 byte_width = ACPI_DIV_8 (bit_width); + u32 i; + char *logical_addr_ptr; + + + ACPI_FUNCTION_TRACE ("Ex_data_table_space_handler"); + + + logical_addr_ptr = ACPI_PHYSADDR_TO_PTR (address); + + + /* Perform the memory read or write */ + + switch (function) { + case ACPI_READ: + + for (i = 0; i < byte_width; i++) { + ((char *) value) [i] = logical_addr_ptr[i]; + } + break; + + case ACPI_WRITE: + default: + + return_ACPI_STATUS (AE_SUPPORT); + } + + return_ACPI_STATUS (status); +} + diff -Nur linux-2.4.19/drivers/acpi/executer/exresnte.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exresnte.c --- linux-2.4.19/drivers/acpi/executer/exresnte.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exresnte.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exresnte - AML Interpreter object resolution - * $Revision: 43 $ + * $Revision: 53 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,16 +27,13 @@ #include "acpi.h" #include "amlcode.h" -#include "acparser.h" #include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" -#include "actables.h" -#include "acevents.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exresnte") + ACPI_MODULE_NAME ("exresnte") /******************************************************************************* @@ -75,25 +72,24 @@ acpi_operand_object *source_desc; acpi_operand_object *obj_desc = NULL; acpi_namespace_node *node; - acpi_object_type8 entry_type; + acpi_object_type entry_type; acpi_integer temp_val; - FUNCTION_TRACE ("Ex_resolve_node_to_value"); + ACPI_FUNCTION_TRACE ("Ex_resolve_node_to_value"); /* * The stack pointer points to a acpi_namespace_node (Node). Get the * object that is attached to the Node. */ - node = *object_ptr; - source_desc = acpi_ns_get_attached_object (node); + node = *object_ptr; + source_desc = acpi_ns_get_attached_object (node); entry_type = acpi_ns_get_type ((acpi_handle) node); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p Source_desc=%p Type=%X\n", node, source_desc, entry_type)); - /* * Several object types require no further processing: * 1) Devices rarely have an attached object, return the Node @@ -115,7 +111,6 @@ * of the attached object or pointer */ switch (entry_type) { - case ACPI_TYPE_PACKAGE: if (ACPI_TYPE_PACKAGE != source_desc->common.type) { @@ -124,10 +119,13 @@ return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } - /* Return an additional reference to the object */ + status = acpi_ds_get_package_arguments (source_desc); + if (ACPI_SUCCESS (status)) { + /* Return an additional reference to the object */ - obj_desc = source_desc; - acpi_ut_add_reference (obj_desc); + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + } break; @@ -139,10 +137,13 @@ return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } - /* Return an additional reference to the object */ + status = acpi_ds_get_buffer_arguments (source_desc); + if (ACPI_SUCCESS (status)) { + /* Return an additional reference to the object */ - obj_desc = source_desc; - acpi_ut_add_reference (obj_desc); + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + } break; @@ -184,10 +185,9 @@ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Field_read Node=%p Source_desc=%p Type=%X\n", node, source_desc, entry_type)); - status = acpi_ex_read_data_from_field (source_desc, &obj_desc); + status = acpi_ex_read_data_from_field (walk_state, source_desc, &obj_desc); break; - /* * For these objects, just return the object attached to the Node */ @@ -214,7 +214,6 @@ node)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ - break; /* diff -Nur linux-2.4.19/drivers/acpi/executer/exresolv.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exresolv.c --- linux-2.4.19/drivers/acpi/executer/exresolv.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exresolv.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exresolv - AML Interpreter object resolution - * $Revision: 101 $ + * $Revision: 111 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,121 +27,12 @@ #include "acpi.h" #include "amlcode.h" -#include "acparser.h" #include "acdispat.h" #include "acinterp.h" -#include "acnamesp.h" -#include "actables.h" -#include "acevents.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exresolv") - - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_get_buffer_field_value - * - * PARAMETERS: *Obj_desc - Pointer to a Buffer_field - * *Result_desc - Pointer to an empty descriptor which will - * become an Integer with the field's value - * - * RETURN: Status - * - * DESCRIPTION: Retrieve the value from a Buffer_field - * - ******************************************************************************/ - -acpi_status -acpi_ex_get_buffer_field_value ( - acpi_operand_object *obj_desc, - acpi_operand_object *result_desc) -{ - acpi_status status; - u32 mask; - u8 *location; - - - FUNCTION_TRACE ("Ex_get_buffer_field_value"); - - - /* - * Parameter validation - */ - if (!obj_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null field pointer\n")); - return_ACPI_STATUS (AE_AML_NO_OPERAND); - } - - if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { - status = acpi_ds_get_buffer_field_arguments (obj_desc); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - } - - if (!obj_desc->buffer_field.buffer_obj) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null container pointer\n")); - return_ACPI_STATUS (AE_AML_INTERNAL); - } - - if (ACPI_TYPE_BUFFER != obj_desc->buffer_field.buffer_obj->common.type) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - container is not a Buffer\n")); - return_ACPI_STATUS (AE_AML_OPERAND_TYPE); - } - - if (!result_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null result pointer\n")); - return_ACPI_STATUS (AE_AML_INTERNAL); - } - - - /* Field location is (base of buffer) + (byte offset) */ - - location = obj_desc->buffer_field.buffer_obj->buffer.pointer - + obj_desc->buffer_field.base_byte_offset; - - /* - * Construct Mask with as many 1 bits as the field width - * - * NOTE: Only the bottom 5 bits are valid for a shift operation, so - * special care must be taken for any shift greater than 31 bits. - * - * TBD: [Unhandled] Fields greater than 32 bits will not work. - */ - if (obj_desc->buffer_field.bit_length < 32) { - mask = ((u32) 1 << obj_desc->buffer_field.bit_length) - (u32) 1; - } - else { - mask = ACPI_UINT32_MAX; - } - - result_desc->integer.type = (u8) ACPI_TYPE_INTEGER; - - /* Get the 32 bit value at the location */ - - MOVE_UNALIGNED32_TO_32 (&result_desc->integer.value, location); - - /* - * Shift the 32-bit word containing the field, and mask off the - * resulting value - */ - result_desc->integer.value = - (result_desc->integer.value >> obj_desc->buffer_field.start_field_bit_offset) & mask; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "** Read from buffer %p byte %d bit %d width %d addr %p mask %08X val %8.8X%8.8X\n", - obj_desc->buffer_field.buffer_obj->buffer.pointer, - obj_desc->buffer_field.base_byte_offset, - obj_desc->buffer_field.start_field_bit_offset, - obj_desc->buffer_field.bit_length, - location, mask, - HIDWORD(result_desc->integer.value), - LODWORD(result_desc->integer.value))); - - return_ACPI_STATUS (AE_OK); -} + ACPI_MODULE_NAME ("exresolv") /******************************************************************************* @@ -167,7 +58,7 @@ acpi_status status; - FUNCTION_TRACE_PTR ("Ex_resolve_to_value", stack_ptr); + ACPI_FUNCTION_TRACE_PTR ("Ex_resolve_to_value", stack_ptr); if (!stack_ptr || !*stack_ptr) { @@ -175,13 +66,12 @@ return_ACPI_STATUS (AE_AML_NO_OPERAND); } - /* * The entity pointed to by the Stack_ptr can be either * 1) A valid acpi_operand_object, or * 2) A acpi_namespace_node (Named_obj) */ - if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_INTERNAL)) { + if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_OPERAND) { status = acpi_ex_resolve_object_to_value (stack_ptr, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -192,16 +82,16 @@ * Object on the stack may have changed if Acpi_ex_resolve_object_to_value() * was called (i.e., we can't use an _else_ here.) */ - if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_NAMED)) { - status = acpi_ex_resolve_node_to_value ((acpi_namespace_node **) stack_ptr, + if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_NAMED) { + status = acpi_ex_resolve_node_to_value ( + ACPI_CAST_INDIRECT_PTR (acpi_namespace_node, stack_ptr), walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Resolved object %p\n", *stack_ptr)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr)); return_ACPI_STATUS (AE_OK); } @@ -233,7 +123,7 @@ u16 opcode; - FUNCTION_TRACE ("Ex_resolve_object_to_value"); + ACPI_FUNCTION_TRACE ("Ex_resolve_object_to_value"); stack_desc = *stack_ptr; @@ -241,13 +131,11 @@ /* This is an acpi_operand_object */ switch (stack_desc->common.type) { - case INTERNAL_TYPE_REFERENCE: opcode = stack_desc->reference.opcode; switch (opcode) { - case AML_NAME_OP: /* @@ -286,11 +174,10 @@ acpi_ut_remove_reference (stack_desc); *stack_ptr = obj_desc; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "[Arg/Local %d] Value_obj is %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %d] Value_obj is %p\n", stack_desc->reference.offset, obj_desc)); break; - /* * For constants, we must change the reference/constant object * to a real integer object @@ -327,6 +214,10 @@ case AML_REVISION_OP: obj_desc->integer.value = ACPI_CA_SUPPORT_LEVEL; break; + + default: + /* No other opcodes can get here */ + break; } /* @@ -359,7 +250,6 @@ acpi_ut_add_reference (obj_desc); *stack_ptr = obj_desc; } - else { /* * A NULL object descriptor means an unitialized element of @@ -381,7 +271,6 @@ status = AE_AML_INTERNAL; break; } - break; @@ -403,50 +292,36 @@ break; /* case INTERNAL_TYPE_REFERENCE */ - case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_BUFFER: - obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_ANY); - if (!obj_desc) { - return_ACPI_STATUS (AE_NO_MEMORY); - } + status = acpi_ds_get_buffer_arguments (stack_desc); + break; - status = acpi_ex_get_buffer_field_value (stack_desc, obj_desc); - if (ACPI_FAILURE (status)) { - acpi_ut_remove_reference (obj_desc); - obj_desc = NULL; - } - *stack_ptr = (void *) obj_desc; + case ACPI_TYPE_PACKAGE: + + status = acpi_ds_get_package_arguments (stack_desc); break; + /* + * These cases may never happen here, but just in case.. + */ + case ACPI_TYPE_BUFFER_FIELD: + case INTERNAL_TYPE_REGION_FIELD: case INTERNAL_TYPE_BANK_FIELD: + case INTERNAL_TYPE_INDEX_FIELD: - obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_ANY); - if (!obj_desc) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - /* TBD: WRONG! */ - - status = acpi_ex_get_buffer_field_value (stack_desc, obj_desc); - if (ACPI_FAILURE (status)) { - acpi_ut_remove_reference (obj_desc); - obj_desc = NULL; - } + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Field_read Source_desc=%p Type=%X\n", + stack_desc, stack_desc->common.type)); + status = acpi_ex_read_data_from_field (walk_state, stack_desc, &obj_desc); *stack_ptr = (void *) obj_desc; break; - - /* TBD: [Future] - may need to handle Index_field, and Def_field someday */ - default: - break; - - } /* switch (Stack_desc->Common.Type) */ - + } return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/executer/exresop.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exresop.c --- linux-2.4.19/drivers/acpi/executer/exresop.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exresop.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exresop - AML Interpreter operand/object resolution - * $Revision: 41 $ + * $Revision: 50 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,15 +28,12 @@ #include "acpi.h" #include "amlcode.h" #include "acparser.h" -#include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" -#include "actables.h" -#include "acevents.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exresop") + ACPI_MODULE_NAME ("exresop") /******************************************************************************* @@ -59,7 +56,7 @@ acpi_object_type this_type, void *object) { - PROC_NAME ("Ex_check_object_type"); + ACPI_FUNCTION_NAME ("Ex_check_object_type"); if (type_needed == ACPI_TYPE_ANY) { @@ -69,7 +66,7 @@ } if (type_needed != this_type) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed [%s], found [%s] %p\n", acpi_ut_get_type_name (type_needed), acpi_ut_get_type_name (this_type), object)); @@ -85,18 +82,21 @@ * * FUNCTION: Acpi_ex_resolve_operands * - * PARAMETERS: Opcode Opcode being interpreted - * Stack_ptr Top of operand stack + * PARAMETERS: Opcode - Opcode being interpreted + * Stack_ptr - Pointer to the operand stack to be + * resolved + * Walk_state - Current stateu * * RETURN: Status * - * DESCRIPTION: Convert stack entries to required types + * DESCRIPTION: Convert multiple input operands to the types required by the + * target operator. * - * Each nibble in Arg_types represents one required operand - * and indicates the required Type: + * Each nibble (actually 5 bits) in Arg_types represents one required + * operand and indicates the required Type: * - * The corresponding stack entry will be converted to the - * required type if possible, else return an exception + * The corresponding operand will be converted to the required type if + * possible, otherwise we abort with an exception. * ******************************************************************************/ @@ -116,7 +116,7 @@ acpi_object_type type_needed; - FUNCTION_TRACE_U32 ("Ex_resolve_operands", opcode); + ACPI_FUNCTION_TRACE_U32 ("Ex_resolve_operands", opcode); op_info = acpi_ps_get_opcode_info (opcode); @@ -124,7 +124,6 @@ return_ACPI_STATUS (AE_AML_BAD_OPCODE); } - arg_types = op_info->runtime_args; if (arg_types == ARGI_INVALID_OPCODE) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - %X is not a valid AML opcode\n", @@ -133,9 +132,8 @@ return_ACPI_STATUS (AE_AML_INTERNAL); } - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X Operand_types=%X \n", - opcode, arg_types)); - + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] Operand_types=%X \n", + opcode, op_info->name, arg_types)); /* * Normal exit is with (Arg_types == 0) at end of argument list. @@ -158,13 +156,17 @@ /* Decode the descriptor type */ - if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_NAMED: + /* Node */ object_type = ((acpi_namespace_node *) obj_desc)->type; - } + break; + + + case ACPI_DESC_TYPE_OPERAND: - else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { /* ACPI internal object */ object_type = obj_desc->common.type; @@ -187,7 +189,6 @@ return_ACPI_STATUS (AE_AML_BAD_OPCODE); } - switch (obj_desc->reference.opcode) { case AML_ZERO_OP: case AML_ONE_OP: @@ -199,27 +200,28 @@ case AML_LOCAL_OP: case AML_REVISION_OP: - DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Reference Opcode: %s\n", op_info->name))); break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Reference Opcode: Unknown [%02x]\n", obj_desc->reference.opcode)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); - break; } } - } + break; + + + default: - else { /* Invalid descriptor */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad descriptor type %X in Obj %p\n", - obj_desc->common.data_type, obj_desc)); + ACPI_GET_DESCRIPTOR_TYPE (obj_desc), obj_desc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } @@ -231,24 +233,36 @@ this_arg_type = GET_CURRENT_ARG_TYPE (arg_types); INCREMENT_ARG_LIST (arg_types); - /* * Handle cases where the object does not need to be * resolved to a value */ switch (this_arg_type) { + case ARGI_REF_OR_STRING: /* Can be a String or Reference */ - case ARGI_REFERENCE: /* References */ + if ((ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_STRING)) { + /* + * String found - the string references a named object and must be + * resolved to a node + */ + goto next_operand; + } + + /* Else not a string - fall through to the normal Reference case below */ + /*lint -fallthrough */ + + case ARGI_REFERENCE: /* References: */ case ARGI_INTEGER_REF: case ARGI_OBJECT_REF: case ARGI_DEVICE_REF: - case ARGI_TARGETREF: /* TBD: must implement implicit conversion rules before store */ + case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ - case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ + case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ /* Need an operand of type INTERNAL_TYPE_REFERENCE */ - if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) /* direct name ptr OK as-is */ { + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) /* Node (name) ptr OK as-is */ { goto next_operand; } @@ -258,7 +272,6 @@ return_ACPI_STATUS (status); } - if (AML_NAME_OP == obj_desc->reference.opcode) { /* * Convert an indirect name ptr to direct name ptr and put @@ -268,9 +281,7 @@ acpi_ut_remove_reference (obj_desc); (*stack_ptr) = temp_node; } - goto next_operand; - break; case ARGI_ANYTYPE: @@ -287,6 +298,10 @@ goto next_operand; } break; + + default: + /* All cases covered above */ + break; } @@ -298,7 +313,6 @@ return_ACPI_STATUS (status); } - /* * Check the resulting object (value) type */ @@ -362,7 +376,7 @@ status = acpi_ex_convert_to_integer (*stack_ptr, stack_ptr, walk_state); if (ACPI_FAILURE (status)) { if (status == AE_TYPE) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed [Integer/String/Buffer], found [%s] %p\n", acpi_ut_get_type_name ((*stack_ptr)->common.type), *stack_ptr)); @@ -371,9 +385,7 @@ return_ACPI_STATUS (status); } - goto next_operand; - break; case ARGI_BUFFER: @@ -385,7 +397,7 @@ status = acpi_ex_convert_to_buffer (*stack_ptr, stack_ptr, walk_state); if (ACPI_FAILURE (status)) { if (status == AE_TYPE) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed [Integer/String/Buffer], found [%s] %p\n", acpi_ut_get_type_name ((*stack_ptr)->common.type), *stack_ptr)); @@ -394,9 +406,7 @@ return_ACPI_STATUS (status); } - goto next_operand; - break; case ARGI_STRING: @@ -408,7 +418,7 @@ status = acpi_ex_convert_to_string (*stack_ptr, stack_ptr, 16, ACPI_UINT32_MAX, walk_state); if (ACPI_FAILURE (status)) { if (status == AE_TYPE) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed [Integer/String/Buffer], found [%s] %p\n", acpi_ut_get_type_name ((*stack_ptr)->common.type), *stack_ptr)); @@ -417,82 +427,109 @@ return_ACPI_STATUS (status); } - goto next_operand; - break; case ARGI_COMPUTEDATA: /* Need an operand of type INTEGER, STRING or BUFFER */ - if ((ACPI_TYPE_INTEGER != (*stack_ptr)->common.type) && - (ACPI_TYPE_STRING != (*stack_ptr)->common.type) && - (ACPI_TYPE_BUFFER != (*stack_ptr)->common.type)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + switch ((*stack_ptr)->common.type) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed [Integer/String/Buffer], found [%s] %p\n", acpi_ut_get_type_name ((*stack_ptr)->common.type), *stack_ptr)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto next_operand; - break; case ARGI_DATAOBJECT: /* * ARGI_DATAOBJECT is only used by the Size_of operator. + * Need a buffer, string, package, or Node reference. * - * The ACPI specification allows Size_of to return the size of - * a Buffer, String or Package. However, the MS ACPI.SYS AML - * Interpreter also allows an Node reference to return without - * error with a size of 4. - */ - - /* Need a buffer, string, package or Node reference */ - - if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) && - ((*stack_ptr)->common.type != ACPI_TYPE_STRING) && - ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE) && - ((*stack_ptr)->common.type != INTERNAL_TYPE_REFERENCE)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Needed [Buf/Str/Pkg/Ref], found [%s] %p\n", - acpi_ut_get_type_name ((*stack_ptr)->common.type), *stack_ptr)); - - return_ACPI_STATUS (AE_AML_OPERAND_TYPE); - } - - /* - * If this is a reference, only allow a reference to an Node. + * The only reference allowed here is a direct reference to + * a namespace node. */ if ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) { if (!(*stack_ptr)->reference.node) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed [Node Reference], found [%p]\n", *stack_ptr)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } + + /* Get the object attached to the node */ + + temp_node = acpi_ns_get_attached_object ((*stack_ptr)->reference.node); + if (!temp_node) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Node [%p] has no attached object\n", + (*stack_ptr)->reference.node)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * Swap the reference object with the node's object. Must add + * a reference to the node object, and remove a reference from + * the original reference object. + */ + acpi_ut_add_reference (temp_node); + acpi_ut_remove_reference (*stack_ptr); + (*stack_ptr) = temp_node; + } + + /* Need a buffer, string, package */ + + switch ((*stack_ptr)->common.type) { + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Buf/Str/Pkg], found [%s] %p\n", + acpi_ut_get_type_name ((*stack_ptr)->common.type), *stack_ptr)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto next_operand; - break; case ARGI_COMPLEXOBJ: /* Need a buffer or package or (ACPI 2.0) String */ - if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) && - ((*stack_ptr)->common.type != ACPI_TYPE_STRING) && - ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Needed [Buf/Pkg], found [%s] %p\n", + switch ((*stack_ptr)->common.type) { + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Buf/Str/Pkg], found [%s] %p\n", acpi_ut_get_type_name ((*stack_ptr)->common.type), *stack_ptr)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto next_operand; - break; default: @@ -506,7 +543,6 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* * Make sure that the original object was resolved to the * required object type (Simple cases only). @@ -517,7 +553,6 @@ return_ACPI_STATUS (status); } - next_operand: /* * If more operands needed, decrement Stack_ptr to point @@ -528,7 +563,6 @@ } } /* while (*Types) */ - return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/executer/exstore.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exstore.c --- linux-2.4.19/drivers/acpi/executer/exstore.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exstore.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exstore - AML Interpreter object store support - * $Revision: 150 $ + * $Revision: 164 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,16 +26,14 @@ #include "acpi.h" -#include "acparser.h" #include "acdispat.h" #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" -#include "actables.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exstore") + ACPI_MODULE_NAME ("exstore") /******************************************************************************* @@ -46,13 +44,15 @@ * *Dest_desc - Where to store it. Must be an NS node * or an acpi_operand_object of type * Reference; + * Walk_state - Current walk state * * RETURN: Status * * DESCRIPTION: Store the value described by Source_desc into the location * described by Dest_desc. Called by various interpreter * functions to store the result of an operation into - * the destination operand. + * the destination operand -- not just simply the actual "Store" + * ASL operator. * ******************************************************************************/ @@ -66,19 +66,19 @@ acpi_operand_object *ref_desc = dest_desc; - FUNCTION_TRACE_PTR ("Ex_store", dest_desc); + ACPI_FUNCTION_TRACE_PTR ("Ex_store", dest_desc); /* Validate parameters */ if (!source_desc || !dest_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null parameter\n")); return_ACPI_STATUS (AE_AML_NO_OPERAND); } /* Dest_desc can be either a namespace node or an ACPI object */ - if (VALID_DESCRIPTOR_TYPE (dest_desc, ACPI_DESC_TYPE_NAMED)) { + if (ACPI_GET_DESCRIPTOR_TYPE (dest_desc) == ACPI_DESC_TYPE_NAMED) { /* * Dest is a namespace node, * Storing an object into a Name "container" @@ -86,12 +86,9 @@ status = acpi_ex_store_object_to_node (source_desc, (acpi_namespace_node *) dest_desc, walk_state); - /* All done, that's it */ - return_ACPI_STATUS (status); } - /* Destination object must be an object of type Reference */ if (dest_desc->common.type != INTERNAL_TYPE_REFERENCE) { @@ -100,15 +97,14 @@ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Destination is not a Reference_obj [%p]\n", dest_desc)); - DUMP_STACK_ENTRY (source_desc); - DUMP_STACK_ENTRY (dest_desc); - DUMP_OPERANDS (&dest_desc, IMODE_EXECUTE, "Ex_store", + ACPI_DUMP_STACK_ENTRY (source_desc); + ACPI_DUMP_STACK_ENTRY (dest_desc); + ACPI_DUMP_OPERANDS (&dest_desc, ACPI_IMODE_EXECUTE, "Ex_store", 2, "Target is not a Reference_obj"); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } - /* * Examine the Reference opcode. These cases are handled: * @@ -119,7 +115,6 @@ * 5) Store to a constant -- a noop */ switch (ref_desc->reference.opcode) { - case AML_NAME_OP: /* Storing an object into a Name "container" */ @@ -153,7 +148,7 @@ * Storing to the Debug object causes the value stored to be * displayed and otherwise has no effect -- see ACPI Specification */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Write to Debug Object: ****:\n\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "**** Write to Debug Object: ****:\n\n")); ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ", acpi_ut_get_type_name (source_desc->common.type))); @@ -161,15 +156,16 @@ switch (source_desc->common.type) { case ACPI_TYPE_INTEGER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%X (%d)\n", - (u32) source_desc->integer.value, (u32) source_desc->integer.value)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%8.8X%8.8X\n", + ACPI_HIWORD (source_desc->integer.value), + ACPI_LOWORD (source_desc->integer.value))); break; case ACPI_TYPE_BUFFER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length 0x%X\n", - (u32) source_desc->buffer.length)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length %.2X\n", + (u32) source_desc->buffer.length)); break; @@ -181,18 +177,19 @@ case ACPI_TYPE_PACKAGE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Elements - 0x%X\n", - (u32) source_desc->package.elements)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Elements Ptr - %p\n", + source_desc->package.elements)); break; default: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "@0x%p\n", source_desc)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Type %s %p\n", + acpi_ut_get_type_name (source_desc->common.type), source_desc)); break; } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n")); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n")); break; @@ -202,27 +199,23 @@ case AML_REVISION_OP: /* - * Storing to a constant is a no-op -- see ACPI Specification - * Delete the reference descriptor, however + * Storing to a constant is a no-op according to the ACPI + * Specification. (Delete the reference descriptor, however.) */ break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - Unknown Reference subtype %02x\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference subtype %02x\n", ref_desc->reference.opcode)); - - /* TBD: [Restructure] use object dump routine !! */ - - DUMP_BUFFER (ref_desc, sizeof (acpi_operand_object)); + ACPI_DUMP_ENTRY (ref_desc, ACPI_LV_ERROR); status = AE_AML_INTERNAL; break; } /* switch (Ref_desc->Reference.Opcode) */ - return_ACPI_STATUS (status); } @@ -231,36 +224,36 @@ * * FUNCTION: Acpi_ex_store_object_to_index * - * PARAMETERS: *Source_desc - Value to be stored - * *Node - Named object to receive the value + * PARAMETERS: *Source_desc - Value to be stored + * *Dest_desc - Named object to receive the value + * Walk_state - Current walk state * * RETURN: Status * - * DESCRIPTION: Store the object to the named object. + * DESCRIPTION: Store the object to indexed Buffer or Package element * ******************************************************************************/ acpi_status acpi_ex_store_object_to_index ( acpi_operand_object *source_desc, - acpi_operand_object *dest_desc, + acpi_operand_object *index_desc, acpi_walk_state *walk_state) { acpi_status status = AE_OK; acpi_operand_object *obj_desc; - u32 length; - u32 i; + acpi_operand_object *new_desc; u8 value = 0; - FUNCTION_TRACE ("Ex_store_object_to_index"); + ACPI_FUNCTION_TRACE ("Ex_store_object_to_index"); /* * Destination must be a reference pointer, and * must point to either a buffer or a package */ - switch (dest_desc->reference.target_type) { + switch (index_desc->reference.target_type) { case ACPI_TYPE_PACKAGE: /* * Storing to a package element is not simple. The source must be @@ -268,95 +261,48 @@ * source is copied into the destination - we can't just point to the * source object. */ - if (dest_desc->reference.target_type == ACPI_TYPE_PACKAGE) { - /* - * The object at *(Dest_desc->Reference.Where) is the - * element within the package that is to be modified. - */ - obj_desc = *(dest_desc->reference.where); - if (obj_desc) { - /* - * If the Destination element is a package, we will delete - * that object and construct a new one. - * - * TBD: [Investigate] Should both the src and dest be required - * to be packages? - * && (Source_desc->Common.Type == ACPI_TYPE_PACKAGE) - */ - if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { - /* Take away the reference for being part of a package */ - - acpi_ut_remove_reference (obj_desc); - obj_desc = NULL; - } - } - - if (!obj_desc) { - /* - * If the Obj_desc is NULL, it means that an uninitialized package - * element has been used as a destination (this is OK), therefore, - * we must create the destination element to match the type of the - * source element NOTE: Source_desccan be of any type. - */ - obj_desc = acpi_ut_create_internal_object (source_desc->common.type); - if (!obj_desc) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - /* - * If the source is a package, copy the source to the new dest - */ - if (ACPI_TYPE_PACKAGE == obj_desc->common.type) { - status = acpi_ut_copy_ipackage_to_ipackage (source_desc, obj_desc, walk_state); - if (ACPI_FAILURE (status)) { - acpi_ut_remove_reference (obj_desc); - return_ACPI_STATUS (status); - } - } - - /* Install the new descriptor into the package */ - - *(dest_desc->reference.where) = obj_desc; - } - - if (ACPI_TYPE_PACKAGE != obj_desc->common.type) { - /* - * The destination element is not a package, so we need to - * convert the contents of the source (Source_desc) and copy into - * the destination (Obj_desc) - */ - status = acpi_ex_store_object_to_object (source_desc, obj_desc, - walk_state); - if (ACPI_FAILURE (status)) { - /* - * An error occurrered when copying the internal object - * so delete the reference. - */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unable to copy the internal object\n")); - return_ACPI_STATUS (AE_AML_OPERAND_TYPE); - } - } + /* + * The object at *(Index_desc->Reference.Where) is the + * element within the package that is to be modified. + */ + obj_desc = *(index_desc->reference.where); + + /* Do the conversion/store */ + + status = acpi_ex_store_object_to_object (source_desc, obj_desc, &new_desc, + walk_state); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not store object to indexed package element\n")); + return_ACPI_STATUS (status); + } + + /* + * If a new object was created, we must install it as the new + * package element + */ + if (new_desc != obj_desc) { + acpi_ut_remove_reference (obj_desc); + *(index_desc->reference.where) = new_desc; } break; case ACPI_TYPE_BUFFER_FIELD: - - /* TBD: can probably call the generic Buffer/Field routines */ - /* - * Storing into a buffer at a location defined by an Index. + * Store into a Buffer (not actually a real Buffer_field) at a + * location defined by an Index. * - * Each 8-bit element of the source object is written to the - * 8-bit Buffer Field of the Index destination object. + * The first 8-bit element of the source object is written to the + * 8-bit Buffer location defined by the Index destination object, + * according to the ACPI 2.0 specification. */ /* - * Set the Obj_desc to the destination object and type check. + * Make sure the target is a Buffer */ - obj_desc = dest_desc->reference.object; + obj_desc = index_desc->reference.object; if (obj_desc->common.type != ACPI_TYPE_BUFFER) { return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } @@ -367,65 +313,45 @@ */ switch (source_desc->common.type) { case ACPI_TYPE_INTEGER: - /* - * Type is Integer, assign bytewise - * This loop to assign each of the elements is somewhat - * backward because of the Big Endian-ness of IA-64 - */ - length = sizeof (acpi_integer); - for (i = length; i != 0; i--) { - value = (u8)(source_desc->integer.value >> (MUL_8 (i - 1))); - obj_desc->buffer.pointer[dest_desc->reference.offset] = value; - } - break; + /* Use the least-significant byte of the integer */ - case ACPI_TYPE_BUFFER: - /* - * Type is Buffer, the Length is in the structure. - * Just loop through the elements and assign each one in turn. - */ - length = source_desc->buffer.length; - for (i = 0; i < length; i++) { - value = source_desc->buffer.pointer[i]; - obj_desc->buffer.pointer[dest_desc->reference.offset] = value; - } + value = (u8) (source_desc->integer.value); break; + case ACPI_TYPE_BUFFER: - case ACPI_TYPE_STRING: - /* - * Type is String, the Length is in the structure. - * Just loop through the elements and assign each one in turn. - */ - length = source_desc->string.length; - for (i = 0; i < length; i++) { - value = source_desc->string.pointer[i]; - obj_desc->buffer.pointer[dest_desc->reference.offset] = value; - } + value = source_desc->buffer.pointer[0]; break; + case ACPI_TYPE_STRING: + + value = (u8) source_desc->string.pointer[0]; + break; default: - /* Other types are invalid */ + /* All other types are invalid */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Source must be Number/Buffer/String type, not %X\n", - source_desc->common.type)); - status = AE_AML_OPERAND_TYPE; - break; + "Source must be Integer/Buffer/String type, not %s\n", + acpi_ut_get_type_name (source_desc->common.type))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } + + /* Store the source value into the target buffer byte */ + + obj_desc->buffer.pointer[index_desc->reference.offset] = value; break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Target is not a Package or Buffer_field\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Target is not a Package or Buffer_field\n")); status = AE_AML_OPERAND_TYPE; break; } - return_ACPI_STATUS (status); } @@ -434,15 +360,16 @@ * * FUNCTION: Acpi_ex_store_object_to_node * - * PARAMETERS: *Source_desc - Value to be stored - * *Node - Named object to receive the value + * PARAMETERS: Source_desc - Value to be stored + * Node - Named object to receive the value + * Walk_state - Current walk state * * RETURN: Status * * DESCRIPTION: Store the object to the named object. * * The Assignment of an object to a named object is handled here - * The val passed in will replace the current value (if any) + * The value passed in will replace the current value (if any) * with the input value. * * When storing into an object the data is converted to the @@ -450,10 +377,7 @@ * that the target object type (for an initialized target) will * not be changed by a store operation. * - * NOTE: the global lock is acquired early. This will result - * in the global lock being held a bit longer. Also, if the - * function fails during set up we may get the lock when we - * don't really need it. I don't think we care. + * Assumes parameters are already validated. * ******************************************************************************/ @@ -465,15 +389,12 @@ { acpi_status status = AE_OK; acpi_operand_object *target_desc; - acpi_object_type8 target_type = ACPI_TYPE_ANY; - + acpi_operand_object *new_desc; + acpi_object_type target_type; - FUNCTION_TRACE ("Ex_store_object_to_node"); + ACPI_FUNCTION_TRACE_PTR ("Ex_store_object_to_node", source_desc); - /* - * Assuming the parameters were already validated - */ /* * Get current type of the node, and object attached to Node @@ -481,10 +402,9 @@ target_type = acpi_ns_get_type (node); target_desc = acpi_ns_get_attached_object (node); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Storing %p(%s) into node %p(%s)\n", - node, acpi_ut_get_type_name (source_desc->common.type), - source_desc, acpi_ut_get_type_name (target_type))); - + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n", + source_desc, acpi_ut_get_type_name (source_desc->common.type), + node, acpi_ut_get_type_name (target_type))); /* * Resolve the source object to an actual value @@ -495,7 +415,6 @@ return_ACPI_STATUS (status); } - /* * Do the actual store operation */ @@ -522,28 +441,30 @@ * * Copy and/or convert the source object to a new target object */ - status = acpi_ex_store_object (source_desc, target_type, &target_desc, walk_state); + status = acpi_ex_store_object_to_object (source_desc, target_desc, &new_desc, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - /* - * Store the new Target_desc as the new value of the Name, and set - * the Name's type to that of the value being stored in it. - * Source_desc reference count is incremented by Attach_object. - */ - status = acpi_ns_attach_object (node, target_desc, target_type); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Store %s into %s via Convert/Attach\n", - acpi_ut_get_type_name (target_desc->common.type), - acpi_ut_get_type_name (target_type))); + if (new_desc != target_desc) { + /* + * Store the new New_desc as the new value of the Name, and set + * the Name's type to that of the value being stored in it. + * Source_desc reference count is incremented by Attach_object. + */ + status = acpi_ns_attach_object (node, new_desc, target_type); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Store %s into %s via Convert/Attach\n", + acpi_ut_get_type_name (source_desc->common.type), + acpi_ut_get_type_name (new_desc->common.type))); + } break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %s (%p) directly into node (%p), no implicit conversion\n", acpi_ut_get_type_name (source_desc->common.type), source_desc, node)); @@ -553,91 +474,7 @@ break; } - return_ACPI_STATUS (status); } - -/******************************************************************************* - * - * FUNCTION: Acpi_ex_store_object_to_object - * - * PARAMETERS: *Source_desc - Value to be stored - * *Dest_desc - Object to receive the value - * - * RETURN: Status - * - * DESCRIPTION: Store an object to another object. - * - * The Assignment of an object to another (not named) object - * is handled here. - * The val passed in will replace the current value (if any) - * with the input value. - * - * When storing into an object the data is converted to the - * target object type then stored in the object. This means - * that the target object type (for an initialized target) will - * not be changed by a store operation. - * - * This module allows destination types of Number, String, - * and Buffer. - * - ******************************************************************************/ - -acpi_status -acpi_ex_store_object_to_object ( - acpi_operand_object *source_desc, - acpi_operand_object *dest_desc, - acpi_walk_state *walk_state) -{ - acpi_status status = AE_OK; - acpi_object_type8 destination_type = dest_desc->common.type; - - - FUNCTION_TRACE ("Ex_store_object_to_object"); - - - /* - * Assuming the parameters are valid! - */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Storing %p(%s) to %p(%s)\n", - source_desc, acpi_ut_get_type_name (source_desc->common.type), - dest_desc, acpi_ut_get_type_name (dest_desc->common.type))); - - - /* - * From this interface, we only support Integers/Strings/Buffers - */ - switch (destination_type) { - case ACPI_TYPE_INTEGER: - case ACPI_TYPE_STRING: - case ACPI_TYPE_BUFFER: - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Store into %s not implemented\n", - acpi_ut_get_type_name (dest_desc->common.type))); - - return_ACPI_STATUS (AE_NOT_IMPLEMENTED); - } - - - /* - * Resolve the source object to an actual value - * (If it is a reference object) - */ - status = acpi_ex_resolve_object (&source_desc, destination_type, walk_state); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - - /* - * Copy and/or convert the source object to the destination object - */ - status = acpi_ex_store_object (source_desc, destination_type, &dest_desc, walk_state); - - - return_ACPI_STATUS (status); -} diff -Nur linux-2.4.19/drivers/acpi/executer/exstoren.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exstoren.c --- linux-2.4.19/drivers/acpi/executer/exstoren.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exstoren.c Tue Aug 27 19:53:13 2002 @@ -3,12 +3,12 @@ * * Module Name: exstoren - AML Interpreter object store support, * Store to Node (namespace object) - * $Revision: 40 $ + * $Revision: 48 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,16 +27,11 @@ #include "acpi.h" -#include "acparser.h" -#include "acdispat.h" #include "acinterp.h" -#include "amlcode.h" -#include "acnamesp.h" -#include "actables.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exstoren") + ACPI_MODULE_NAME ("exstoren") /******************************************************************************* @@ -57,66 +52,61 @@ acpi_status acpi_ex_resolve_object ( acpi_operand_object **source_desc_ptr, - acpi_object_type8 target_type, + acpi_object_type target_type, acpi_walk_state *walk_state) { acpi_operand_object *source_desc = *source_desc_ptr; acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_resolve_object"); + ACPI_FUNCTION_TRACE ("Ex_resolve_object"); /* - * Ensure we have a Source that can be stored in the target + * Ensure we have a Target that can be stored to */ switch (target_type) { - - /* This case handles the "interchangeable" types Integer, String, and Buffer. */ - - /* - * These cases all require only Integers or values that - * can be converted to Integers (Strings or Buffers) - */ case ACPI_TYPE_BUFFER_FIELD: case INTERNAL_TYPE_REGION_FIELD: case INTERNAL_TYPE_BANK_FIELD: case INTERNAL_TYPE_INDEX_FIELD: + /* + * These cases all require only Integers or values that + * can be converted to Integers (Strings or Buffers) + */ - /* - * Stores into a Field/Region or into a Buffer/String - * are all essentially the same. - */ case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: + /* + * Stores into a Field/Region or into a Integer/Buffer/String + * are all essentially the same. This case handles the + * "interchangeable" types Integer, String, and Buffer. + */ + if (source_desc->common.type == INTERNAL_TYPE_REFERENCE) { + /* Resolve a reference object first */ - /* TBD: FIX - check for source==REF, resolve, then check type */ + status = acpi_ex_resolve_to_value (source_desc_ptr, walk_state); + if (ACPI_FAILURE (status)) { + break; + } + } /* - * If Source_desc is not a valid type, try to resolve it to one. + * Must have a Integer, Buffer, or String */ if ((source_desc->common.type != ACPI_TYPE_INTEGER) && (source_desc->common.type != ACPI_TYPE_BUFFER) && (source_desc->common.type != ACPI_TYPE_STRING)) { /* - * Initially not a valid type, convert + * Conversion successful but still not a valid type */ - status = acpi_ex_resolve_to_value (source_desc_ptr, walk_state); - if (ACPI_SUCCESS (status) && - (source_desc->common.type != ACPI_TYPE_INTEGER) && - (source_desc->common.type != ACPI_TYPE_BUFFER) && - (source_desc->common.type != ACPI_TYPE_STRING)) { - /* - * Conversion successful but still not a valid type - */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Cannot assign type %s to %s (must be type Int/Str/Buf)\n", - acpi_ut_get_type_name ((*source_desc_ptr)->common.type), - acpi_ut_get_type_name (target_type))); - status = AE_AML_OPERAND_TYPE; - } + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Cannot assign type %s to %s (must be type Int/Str/Buf)\n", + acpi_ut_get_type_name (source_desc->common.type), + acpi_ut_get_type_name (target_type))); + status = AE_AML_OPERAND_TYPE; } break; @@ -147,11 +137,11 @@ /******************************************************************************* * - * FUNCTION: Acpi_ex_store_object + * FUNCTION: Acpi_ex_store_object_to_object * * PARAMETERS: Source_desc - Object to store - * Target_type - Current type of the target - * Target_desc_ptr - Pointer to the target + * Dest_desc - Object to receive a copy of the source + * New_desc - New object if Dest_desc is obsoleted * Walk_state - Current walk state * * RETURN: Status @@ -161,93 +151,114 @@ * conversion), and a copy of the value of the source to * the target. * + * The Assignment of an object to another (not named) object + * is handled here. + * The Source passed in will replace the current value (if any) + * with the input value. + * + * When storing into an object the data is converted to the + * target object type then stored in the object. This means + * that the target object type (for an initialized target) will + * not be changed by a store operation. + * + * This module allows destination types of Number, String, + * Buffer, and Package. + * + * Assumes parameters are already validated. NOTE: Source_desc + * resolution (from a reference object) must be performed by + * the caller if necessary. + * ******************************************************************************/ acpi_status -acpi_ex_store_object ( +acpi_ex_store_object_to_object ( acpi_operand_object *source_desc, - acpi_object_type8 target_type, - acpi_operand_object **target_desc_ptr, + acpi_operand_object *dest_desc, + acpi_operand_object **new_desc, acpi_walk_state *walk_state) { - acpi_operand_object *target_desc = *target_desc_ptr; + acpi_operand_object *actual_src_desc; acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_store_object"); + ACPI_FUNCTION_TRACE_PTR ("Acpi_ex_store_object_to_object", source_desc); - /* - * Perform the "implicit conversion" of the source to the current type - * of the target - As per the ACPI specification. - * - * If no conversion performed, Source_desc is left alone, otherwise it - * is updated with a new object. - */ - status = acpi_ex_convert_to_target_type (target_type, &source_desc, walk_state); - if (ACPI_FAILURE (status)) { + actual_src_desc = source_desc; + if (!dest_desc) { + /* + * There is no destination object (An uninitialized node or + * package element), so we can simply copy the source object + * creating a new destination object + */ + status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, new_desc, walk_state); return_ACPI_STATUS (status); } + if (source_desc->common.type != dest_desc->common.type) { + /* + * The source type does not match the type of the destination. + * Perform the "implicit conversion" of the source to the current type + * of the target as per the ACPI specification. + * + * If no conversion performed, Actual_src_desc = Source_desc. + * Otherwise, Actual_src_desc is a temporary object to hold the + * converted object. + */ + status = acpi_ex_convert_to_target_type (dest_desc->common.type, source_desc, + &actual_src_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + /* * We now have two objects of identical types, and we can perform a * copy of the *value* of the source object. */ - switch (target_type) { - case ACPI_TYPE_ANY: - case INTERNAL_TYPE_DEF_ANY: - - /* - * The target namespace node is uninitialized (has no target object), - * and will take on the type of the source object - */ - *target_desc_ptr = source_desc; - break; - - + switch (dest_desc->common.type) { case ACPI_TYPE_INTEGER: - target_desc->integer.value = source_desc->integer.value; + dest_desc->integer.value = actual_src_desc->integer.value; /* Truncate value if we are executing from a 32-bit ACPI table */ - acpi_ex_truncate_for32bit_table (target_desc, walk_state); + acpi_ex_truncate_for32bit_table (dest_desc, walk_state); break; case ACPI_TYPE_STRING: - status = acpi_ex_copy_string_to_string (source_desc, target_desc); + status = acpi_ex_store_string_to_string (actual_src_desc, dest_desc); break; - case ACPI_TYPE_BUFFER: - status = acpi_ex_copy_buffer_to_buffer (source_desc, target_desc); + status = acpi_ex_store_buffer_to_buffer (actual_src_desc, dest_desc); break; - case ACPI_TYPE_PACKAGE: - /* - * TBD: [Unhandled] Not real sure what to do here - */ - status = AE_NOT_IMPLEMENTED; + status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, &dest_desc, walk_state); break; - default: - /* * All other types come here. */ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Store into type %s not implemented\n", - acpi_ut_get_type_name (target_type))); + acpi_ut_get_type_name (dest_desc->common.type))); status = AE_NOT_IMPLEMENTED; break; } + if (actual_src_desc != source_desc) { + /* Delete the intermediate (temporary) source object */ + + acpi_ut_remove_reference (actual_src_desc); + } + *new_desc = dest_desc; return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/executer/exstorob.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exstorob.c --- linux-2.4.19/drivers/acpi/executer/exstorob.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exstorob.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exstorob - AML Interpreter object store support, store to object - * $Revision: 37 $ + * $Revision: 44 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,21 +26,16 @@ #include "acpi.h" -#include "acparser.h" -#include "acdispat.h" #include "acinterp.h" -#include "amlcode.h" -#include "acnamesp.h" -#include "actables.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exstorob") + ACPI_MODULE_NAME ("exstorob") /******************************************************************************* * - * FUNCTION: Acpi_ex_copy_buffer_to_buffer + * FUNCTION: Acpi_ex_store_buffer_to_buffer * * PARAMETERS: Source_desc - Source object to copy * Target_desc - Destination object of the copy @@ -52,7 +47,7 @@ ******************************************************************************/ acpi_status -acpi_ex_copy_buffer_to_buffer ( +acpi_ex_store_buffer_to_buffer ( acpi_operand_object *source_desc, acpi_operand_object *target_desc) { @@ -60,7 +55,7 @@ u8 *buffer; - PROC_NAME ("Ex_copy_buffer_to_buffer"); + ACPI_FUNCTION_NAME ("Ex_store_buffer_to_buffer"); /* @@ -89,28 +84,32 @@ if (length <= target_desc->buffer.length) { /* Clear existing buffer and copy in the new one */ - MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length); - MEMCPY (target_desc->buffer.pointer, buffer, length); + ACPI_MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length); + ACPI_MEMCPY (target_desc->buffer.pointer, buffer, length); } else { /* * Truncate the source, copy only what will fit */ - MEMCPY (target_desc->buffer.pointer, buffer, target_desc->buffer.length); + ACPI_MEMCPY (target_desc->buffer.pointer, buffer, target_desc->buffer.length); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Truncating src buffer from %X to %X\n", length, target_desc->buffer.length)); } + /* Copy flags */ + + target_desc->buffer.flags = source_desc->buffer.flags; + return (AE_OK); } /******************************************************************************* * - * FUNCTION: Acpi_ex_copy_string_to_string + * FUNCTION: Acpi_ex_store_string_to_string * * PARAMETERS: Source_desc - Source object to copy * Target_desc - Destination object of the copy @@ -122,7 +121,7 @@ ******************************************************************************/ acpi_status -acpi_ex_copy_string_to_string ( +acpi_ex_store_string_to_string ( acpi_operand_object *source_desc, acpi_operand_object *target_desc) { @@ -130,7 +129,7 @@ u8 *buffer; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* @@ -145,8 +144,8 @@ if (length < target_desc->string.length) { /* Clear old string and copy in the new one */ - MEMSET (target_desc->string.pointer, 0, target_desc->string.length); - MEMCPY (target_desc->string.pointer, buffer, length); + ACPI_MEMSET (target_desc->string.pointer, 0, target_desc->string.length); + ACPI_MEMCPY (target_desc->string.pointer, buffer, length); } else { @@ -162,13 +161,13 @@ ACPI_MEM_FREE (target_desc->string.pointer); } - target_desc->string.pointer = ACPI_MEM_ALLOCATE (length + 1); + target_desc->string.pointer = ACPI_MEM_ALLOCATE ((ACPI_SIZE) length + 1); if (!target_desc->string.pointer) { return (AE_NO_MEMORY); } target_desc->string.length = length; - MEMCPY (target_desc->string.pointer, buffer, length); + ACPI_MEMCPY (target_desc->string.pointer, buffer, length); } return (AE_OK); diff -Nur linux-2.4.19/drivers/acpi/executer/exsystem.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exsystem.c --- linux-2.4.19/drivers/acpi/executer/exsystem.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exsystem.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exsystem - Interface to OS services - * $Revision: 67 $ + * $Revision: 73 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,12 +27,10 @@ #include "acpi.h" #include "acinterp.h" -#include "acnamesp.h" -#include "achware.h" #include "acevents.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exsystem") + ACPI_MODULE_NAME ("exsystem") /******************************************************************************* @@ -56,9 +54,10 @@ u32 timeout) { acpi_status status; + acpi_status status2; - FUNCTION_TRACE ("Ex_system_wait_semaphore"); + ACPI_FUNCTION_TRACE ("Ex_system_wait_semaphore"); status = acpi_os_wait_semaphore (semaphore, 1, 0); @@ -78,11 +77,11 @@ /* Reacquire the interpreter */ - status = acpi_ex_enter_interpreter (); - if (ACPI_SUCCESS (status)) { - /* Restore the timeout exception */ + status2 = acpi_ex_enter_interpreter (); + if (ACPI_FAILURE (status2)) { + /* Report fatal error, could not acquire interpreter */ - status = AE_TIME; + return_ACPI_STATUS (status2); } } @@ -96,17 +95,20 @@ * * PARAMETERS: How_long - The amount of time to stall * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Suspend running thread for specified amount of time. * ******************************************************************************/ -void +acpi_status acpi_ex_system_do_stall ( u32 how_long) { - FUNCTION_ENTRY (); + acpi_status status = AE_OK; + + + ACPI_FUNCTION_ENTRY (); if (how_long > 1000) /* 1 millisecond */ { @@ -118,12 +120,14 @@ /* And now we must get the interpreter again */ - acpi_ex_enter_interpreter (); + status = acpi_ex_enter_interpreter (); } else { acpi_os_sleep (0, (how_long / 1000) + 1); } + + return (status); } @@ -139,12 +143,14 @@ * ******************************************************************************/ -void +acpi_status acpi_ex_system_do_suspend ( u32 how_long) { + acpi_status status; - FUNCTION_ENTRY (); + + ACPI_FUNCTION_ENTRY (); /* Since this thread will sleep, we must release the interpreter */ @@ -156,7 +162,8 @@ /* And now we must get the interpreter again */ - acpi_ex_enter_interpreter (); + status = acpi_ex_enter_interpreter (); + return (status); } @@ -183,7 +190,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_PTR ("Ex_system_acquire_mutex", obj_desc); + ACPI_FUNCTION_TRACE_PTR ("Ex_system_acquire_mutex", obj_desc); if (!obj_desc) { @@ -194,7 +201,7 @@ * Support for the _GL_ Mutex object -- go get the global lock */ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { - status = acpi_ev_acquire_global_lock (); + status = acpi_ev_acquire_global_lock ((u32) time_desc->integer.value); return_ACPI_STATUS (status); } @@ -226,7 +233,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_system_release_mutex"); + ACPI_FUNCTION_TRACE ("Ex_system_release_mutex"); if (!obj_desc) { @@ -237,8 +244,8 @@ * Support for the _GL_ Mutex object -- release the global lock */ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { - acpi_ev_release_global_lock (); - return_ACPI_STATUS (AE_OK); + status = acpi_ev_release_global_lock (); + return_ACPI_STATUS (status); } status = acpi_os_signal_semaphore (obj_desc->mutex.semaphore, 1); @@ -266,7 +273,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_system_signal_event"); + ACPI_FUNCTION_TRACE ("Ex_system_signal_event"); if (obj_desc) { @@ -300,7 +307,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Ex_system_wait_event"); + ACPI_FUNCTION_TRACE ("Ex_system_wait_event"); if (obj_desc) { @@ -308,7 +315,6 @@ (u32) time_desc->integer.value); } - return_ACPI_STATUS (status); } @@ -333,7 +339,7 @@ void *temp_semaphore; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* @@ -342,7 +348,7 @@ */ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore); if (ACPI_SUCCESS (status)) { - acpi_os_delete_semaphore (obj_desc->event.semaphore); + (void) acpi_os_delete_semaphore (obj_desc->event.semaphore); obj_desc->event.semaphore = temp_semaphore; } diff -Nur linux-2.4.19/drivers/acpi/executer/exutils.c linux-2.4.19-sgi211r3/drivers/acpi/executer/exutils.c --- linux-2.4.19/drivers/acpi/executer/exutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/executer/exutils.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: exutils - interpreter/scanner utilities - * $Revision: 85 $ + * $Revision: 98 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,15 +42,12 @@ #define DEFINE_AML_GLOBALS #include "acpi.h" -#include "acparser.h" #include "acinterp.h" #include "amlcode.h" -#include "acnamesp.h" #include "acevents.h" -#include "acparser.h" #define _COMPONENT ACPI_EXECUTER - MODULE_NAME ("exutils") + ACPI_MODULE_NAME ("exutils") /******************************************************************************* @@ -59,8 +56,8 @@ * * PARAMETERS: None * - * DESCRIPTION: Enter the interpreter execution region - * TBD: should be a macro + * DESCRIPTION: Enter the interpreter execution region. Failure to enter + * the interpreter region is a fatal system error * ******************************************************************************/ @@ -69,10 +66,14 @@ { acpi_status status; - FUNCTION_TRACE ("Ex_enter_interpreter"); + ACPI_FUNCTION_TRACE ("Ex_enter_interpreter"); status = acpi_ut_acquire_mutex (ACPI_MTX_EXECUTE); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not acquire interpreter mutex\n")); + } + return_ACPI_STATUS (status); } @@ -95,17 +96,21 @@ * already executing * 7) About to invoke a user-installed opregion handler * - * TBD: should be a macro - * ******************************************************************************/ void acpi_ex_exit_interpreter (void) { - FUNCTION_TRACE ("Ex_exit_interpreter"); + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Ex_exit_interpreter"); - acpi_ut_release_mutex (ACPI_MTX_EXECUTE); + status = acpi_ut_release_mutex (ACPI_MTX_EXECUTE); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not release interpreter mutex\n")); + } return_VOID; } @@ -126,7 +131,7 @@ acpi_object_type type) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if ((type > ACPI_TYPE_MAX && type < INTERNAL_TYPE_BEGIN) || @@ -159,7 +164,7 @@ acpi_walk_state *walk_state) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* @@ -172,7 +177,7 @@ return; } - if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) { + if (acpi_gbl_integer_byte_width == 4) { /* * We are running a method that exists in a 32-bit ACPI table. * Truncate the value to 32 bits by zeroing out the upper 32-bit field @@ -186,7 +191,8 @@ * * FUNCTION: Acpi_ex_acquire_global_lock * - * PARAMETERS: Rule - Lock rule: Always_lock, Never_lock + * PARAMETERS: Field_flags - Flags with Lock rule: + * Always_lock or Never_lock * * RETURN: TRUE/FALSE indicating whether the lock was actually acquired * @@ -198,25 +204,24 @@ u8 acpi_ex_acquire_global_lock ( - u32 rule) + u32 field_flags) { u8 locked = FALSE; acpi_status status; - FUNCTION_TRACE ("Ex_acquire_global_lock"); + ACPI_FUNCTION_TRACE ("Ex_acquire_global_lock"); - /* Only attempt lock if the Rule says so */ + /* Only attempt lock if the Always_lock bit is set */ - if (rule == (u32) GLOCK_ALWAYS_LOCK) { - /* We should attempt to get the lock */ + if (field_flags & AML_FIELD_LOCK_RULE_MASK) { + /* We should attempt to get the lock, wait forever */ - status = acpi_ev_acquire_global_lock (); + status = acpi_ev_acquire_global_lock (ACPI_UINT32_MAX); if (ACPI_SUCCESS (status)) { locked = TRUE; } - else { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not acquire Global Lock, %s\n", acpi_format_exception (status))); @@ -240,12 +245,14 @@ * ******************************************************************************/ -acpi_status +void acpi_ex_release_global_lock ( u8 locked_by_me) { + acpi_status status; + - FUNCTION_TRACE ("Ex_release_global_lock"); + ACPI_FUNCTION_TRACE ("Ex_release_global_lock"); /* Only attempt unlock if the caller locked it */ @@ -253,11 +260,13 @@ if (locked_by_me) { /* OK, now release the lock */ - acpi_ev_release_global_lock (); - } - + status = acpi_ev_release_global_lock (); + if (ACPI_FAILURE (status)) { + /* Report the error, but there isn't much else we can do */ - return_ACPI_STATUS (AE_OK); + ACPI_REPORT_ERROR (("Could not release ACPI Global Lock\n")); + } + } } @@ -277,23 +286,24 @@ acpi_integer value, u32 base) { - u32 num_digits = 0; + u32 num_digits; + acpi_integer current_value; + acpi_integer quotient; - FUNCTION_TRACE ("Ex_digits_needed"); + ACPI_FUNCTION_TRACE ("Ex_digits_needed"); - if (base < 1) { - REPORT_ERROR (("Ex_digits_needed: Internal error - Invalid base\n")); - } + /* + * acpi_integer is unsigned, so we don't worry about a '-' + */ + current_value = value; + num_digits = 0; - else { - /* - * acpi_integer is unsigned, which is why we don't worry about a '-' - */ - for (num_digits = 1; - (acpi_ut_short_divide (&value, base, &value, NULL)); - ++num_digits) { ; } + while (current_value) { + (void) acpi_ut_short_divide (¤t_value, base, "ient, NULL); + num_digits++; + current_value = quotient; } return_VALUE (num_digits); @@ -302,45 +312,6 @@ /******************************************************************************* * - * FUNCTION: ntohl - * - * PARAMETERS: Value - Value to be converted - * - * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) - * - ******************************************************************************/ - -static u32 -_ntohl ( - u32 value) -{ - union { - u32 value; - u8 bytes[4]; - } out; - - union { - u32 value; - u8 bytes[4]; - } in; - - - FUNCTION_ENTRY (); - - - in.value = value; - - out.bytes[0] = in.bytes[3]; - out.bytes[1] = in.bytes[2]; - out.bytes[2] = in.bytes[1]; - out.bytes[3] = in.bytes[0]; - - return (out.value); -} - - -/******************************************************************************* - * * FUNCTION: Acpi_ex_eisa_id_to_string * * PARAMETERS: Numeric_id - EISA ID to be converted @@ -350,31 +321,29 @@ * ******************************************************************************/ -acpi_status +void acpi_ex_eisa_id_to_string ( u32 numeric_id, NATIVE_CHAR *out_string) { - u32 id; + u32 eisa_id; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - /* swap to big-endian to get contiguous bits */ + /* Swap ID to big-endian to get contiguous bits */ - id = _ntohl (numeric_id); + eisa_id = acpi_ut_dword_byte_swap (numeric_id); - out_string[0] = (char) ('@' + ((id >> 26) & 0x1f)); - out_string[1] = (char) ('@' + ((id >> 21) & 0x1f)); - out_string[2] = (char) ('@' + ((id >> 16) & 0x1f)); - out_string[3] = acpi_ut_hex_to_ascii_char (id, 12); - out_string[4] = acpi_ut_hex_to_ascii_char (id, 8); - out_string[5] = acpi_ut_hex_to_ascii_char (id, 4); - out_string[6] = acpi_ut_hex_to_ascii_char (id, 0); + out_string[0] = (char) ('@' + ((eisa_id >> 26) & 0x1f)); + out_string[1] = (char) ('@' + ((eisa_id >> 21) & 0x1f)); + out_string[2] = (char) ('@' + ((eisa_id >> 16) & 0x1f)); + out_string[3] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 12); + out_string[4] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 8); + out_string[5] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 4); + out_string[6] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 0); out_string[7] = 0; - - return (AE_OK); } @@ -389,7 +358,7 @@ * ******************************************************************************/ -acpi_status +void acpi_ex_unsigned_integer_to_string ( acpi_integer value, NATIVE_CHAR *out_string) @@ -397,20 +366,20 @@ u32 count; u32 digits_needed; u32 remainder; + acpi_integer quotient; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); digits_needed = acpi_ex_digits_needed (value, 10); out_string[digits_needed] = 0; for (count = digits_needed; count > 0; count--) { - acpi_ut_short_divide (&value, 10, &value, &remainder); - out_string[count-1] = (NATIVE_CHAR) ('0' + remainder); + (void) acpi_ut_short_divide (&value, 10, "ient, &remainder); + out_string[count-1] = (NATIVE_CHAR) ('0' + remainder);\ + value = quotient; } - - return (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/fan.c linux-2.4.19-sgi211r3/drivers/acpi/fan.c --- linux-2.4.19/drivers/acpi/fan.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/fan.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,300 @@ +/* + * acpi_fan.c - ACPI Fan Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_FAN_COMPONENT +ACPI_MODULE_NAME ("acpi_fan") + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +#define PREFIX "ACPI: " + + +int acpi_fan_add (struct acpi_device *device); +int acpi_fan_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_fan_driver = { + name: ACPI_FAN_DRIVER_NAME, + class: ACPI_FAN_CLASS, + ids: ACPI_FAN_HID, + ops: { + add: acpi_fan_add, + remove: acpi_fan_remove, + }, +}; + +struct acpi_fan { + acpi_handle handle; +}; + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +struct proc_dir_entry *acpi_fan_dir = NULL; + + +static int +acpi_fan_read_state ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_fan *fan = (struct acpi_fan *) data; + char *p = page; + int len = 0; + int state = 0; + + ACPI_FUNCTION_TRACE("acpi_fan_read_state"); + + if (!fan || (off != 0)) + goto end; + + if (0 != acpi_bus_get_power(fan->handle, &state)) + goto end; + + p += sprintf(p, "status: %s\n", + !state?"on":"off"); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_fan_write_state ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + struct acpi_fan *fan = (struct acpi_fan *) data; + char state_string[12] = {'\0'}; + + ACPI_FUNCTION_TRACE("acpi_fan_write_state"); + + if (!fan || (count > sizeof(state_string) - 1)) + return_VALUE(-EINVAL); + + if (copy_from_user(state_string, buffer, count)) + return_VALUE(-EFAULT); + + state_string[count] = '\0'; + + result = acpi_bus_set_power(fan->handle, + simple_strtoul(state_string, NULL, 0)); + if (0 != result) + return_VALUE(result); + + return_VALUE(count); +} + + +static int +acpi_fan_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_fan_add_fs"); + + if (!device) + return_VALUE(-EINVAL); + + if (!acpi_fan_dir) { + acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir); + if (!acpi_fan_dir) + return_VALUE(-ENODEV); + } + + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_fan_dir); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + } + + /* 'status' [R/W] */ + entry = create_proc_entry(ACPI_FAN_FILE_STATE, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_FAN_FILE_STATE)); + else { + entry->read_proc = acpi_fan_read_state; + entry->write_proc = acpi_fan_write_state; + entry->data = acpi_driver_data(device); + } + + return_VALUE(0); +} + + +static int +acpi_fan_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_fan_remove_fs"); + + if (!acpi_fan_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_fan_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +int +acpi_fan_add ( + struct acpi_device *device) +{ + int result = 0; + struct acpi_fan *fan = NULL; + int state = 0; + + ACPI_FUNCTION_TRACE("acpi_fan_add"); + + if (!device) + return_VALUE(-EINVAL); + + fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL); + if (!fan) + return_VALUE(-ENOMEM); + memset(fan, 0, sizeof(struct acpi_fan)); + + fan->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_FAN_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_FAN_CLASS); + acpi_driver_data(device) = fan; + + result = acpi_bus_get_power(fan->handle, &state); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error reading power state\n")); + goto end; + } + + result = acpi_fan_add_fs(device); + if (0 != result) + goto end; + + printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + acpi_device_name(device), acpi_device_bid(device), + !device->power.state?"on":"off"); + +end: + if (0 != result) + kfree(fan); + + return_VALUE(result); +} + + +int +acpi_fan_remove ( + struct acpi_device *device, + int type) +{ + struct acpi_fan *fan = NULL; + + ACPI_FUNCTION_TRACE("acpi_fan_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + fan = (struct acpi_fan *) acpi_driver_data(device); + + acpi_fan_remove_fs(device); + + kfree(fan); + + return_VALUE(0); +} + + +int __init +acpi_fan_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_fan_init"); + + result = acpi_bus_register_driver(&acpi_fan_driver); + if (0 > result) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +void __exit +acpi_fan_exit (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_fan_exit"); + + result = acpi_bus_unregister_driver(&acpi_fan_driver); + if (0 == result) + remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir); + + return_VOID; +} + + +module_init(acpi_fan_init); +module_exit(acpi_fan_exit); + diff -Nur linux-2.4.19/drivers/acpi/hardware/Makefile linux-2.4.19-sgi211r3/drivers/acpi/hardware/Makefile --- linux-2.4.19/drivers/acpi/hardware/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/hardware/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/hardware/hwacpi.c linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwacpi.c --- linux-2.4.19/drivers/acpi/hardware/hwacpi.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwacpi.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface - * $Revision: 46 $ + * $Revision: 58 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,11 +26,10 @@ #include "acpi.h" -#include "achware.h" #define _COMPONENT ACPI_HARDWARE - MODULE_NAME ("hwacpi") + ACPI_MODULE_NAME ("hwacpi") /****************************************************************************** @@ -49,131 +48,28 @@ acpi_hw_initialize ( void) { - acpi_status status = AE_OK; - u32 index; + acpi_status status; - FUNCTION_TRACE ("Hw_initialize"); + ACPI_FUNCTION_TRACE ("Hw_initialize"); /* We must have the ACPI tables by the time we get here */ if (!acpi_gbl_FADT) { - acpi_gbl_restore_acpi_chipset = FALSE; - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No FADT!\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "A FADT is not loaded\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } - /* Identify current ACPI/legacy mode */ - - switch (acpi_gbl_system_flags & SYS_MODES_MASK) { - case (SYS_MODE_ACPI): - - acpi_gbl_original_mode = SYS_MODE_ACPI; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "System supports ACPI mode only.\n")); - break; - - - case (SYS_MODE_LEGACY): - - acpi_gbl_original_mode = SYS_MODE_LEGACY; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Tables loaded from buffer, hardware assumed to support LEGACY mode only.\n")); - break; - - - case (SYS_MODE_ACPI | SYS_MODE_LEGACY): - - if (acpi_hw_get_mode () == SYS_MODE_ACPI) { - acpi_gbl_original_mode = SYS_MODE_ACPI; - } - else { - acpi_gbl_original_mode = SYS_MODE_LEGACY; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "System supports both ACPI and LEGACY modes.\n")); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "System is currently in %s mode.\n", - (acpi_gbl_original_mode == SYS_MODE_ACPI) ? "ACPI" : "LEGACY")); - break; - } - - - if (acpi_gbl_system_flags & SYS_MODE_ACPI) { - /* Target system supports ACPI mode */ - - /* - * The purpose of this code is to save the initial state - * of the ACPI event enable registers. An exit function will be - * registered which will restore this state when the application - * exits. The exit function will also clear all of the ACPI event - * status bits prior to restoring the original mode. - * - * The location of the PM1a_evt_blk enable registers is defined as the - * base of PM1a_evt_blk + DIV_2(PM1a_evt_blk_length). Since the spec further - * fully defines the PM1a_evt_blk to be a total of 4 bytes, the offset - * for the enable registers is always 2 from the base. It is hard - * coded here. If this changes in the spec, this code will need to - * be modified. The PM1b_evt_blk behaves as expected. - */ - acpi_gbl_pm1_enable_register_save = (u16) acpi_hw_register_read ( - ACPI_MTX_LOCK, PM1_EN); - - - /* - * The GPEs behave similarly, except that the length of the register - * block is not fixed, so the buffer must be allocated with malloc - */ - if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) && - acpi_gbl_FADT->gpe0blk_len) { - /* GPE0 specified in FADT */ - - acpi_gbl_gpe0enable_register_save = ACPI_MEM_ALLOCATE ( - DIV_2 (acpi_gbl_FADT->gpe0blk_len)); - if (!acpi_gbl_gpe0enable_register_save) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - /* Save state of GPE0 enable bits */ - - for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe0blk_len); index++) { - acpi_gbl_gpe0enable_register_save[index] = - (u8) acpi_hw_register_read (ACPI_MTX_LOCK, GPE0_EN_BLOCK | index); - } - } - - else { - acpi_gbl_gpe0enable_register_save = NULL; - } + /* Sanity check the FADT for valid values */ - if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) && - acpi_gbl_FADT->gpe1_blk_len) { - /* GPE1 defined */ - - acpi_gbl_gpe1_enable_register_save = ACPI_MEM_ALLOCATE ( - DIV_2 (acpi_gbl_FADT->gpe1_blk_len)); - if (!acpi_gbl_gpe1_enable_register_save) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - /* save state of GPE1 enable bits */ - - for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe1_blk_len); index++) { - acpi_gbl_gpe1_enable_register_save[index] = - (u8) acpi_hw_register_read (ACPI_MTX_LOCK, GPE1_EN_BLOCK | index); - } - } - - else { - acpi_gbl_gpe1_enable_register_save = NULL; - } + status = acpi_ut_validate_fadt (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - return_ACPI_STATUS (status); + return_ACPI_STATUS (AE_OK); } @@ -185,8 +81,7 @@ * * RETURN: Status * - * DESCRIPTION: Transitions the system into the requested mode or does nothing - * if the system is already in that mode. + * DESCRIPTION: Transitions the system into the requested mode. * ******************************************************************************/ @@ -195,36 +90,68 @@ u32 mode) { - acpi_status status = AE_NO_HARDWARE_RESPONSE; + acpi_status status; + u32 retry; - FUNCTION_TRACE ("Hw_set_mode"); + ACPI_FUNCTION_TRACE ("Hw_set_mode"); - if (mode == SYS_MODE_ACPI) { + if (mode == acpi_hw_get_mode()) + return_ACPI_STATUS (AE_OK); + + /* If no SMI_CMD, system does not support SMI */ + if (!acpi_gbl_FADT->smi_cmd) + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + + switch (mode) { + case ACPI_SYS_MODE_ACPI: + /* BIOS should have disabled ALL fixed and GP events */ - acpi_os_write_port (acpi_gbl_FADT->smi_cmd, acpi_gbl_FADT->acpi_enable, 8); + status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, + (acpi_integer) acpi_gbl_FADT->acpi_enable, 8); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Attempting to enable ACPI mode\n")); - } + break; - else if (mode == SYS_MODE_LEGACY) { + case ACPI_SYS_MODE_LEGACY: + + /* If both enable/disable are zero, legacy mode is not supported */ + if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + /* * BIOS should clear all fixed status bits and restore fixed event * enable bits to default */ - acpi_os_write_port (acpi_gbl_FADT->smi_cmd, acpi_gbl_FADT->acpi_disable, 8); + status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, + (acpi_integer) acpi_gbl_FADT->acpi_disable, 8); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Attempting to enable Legacy (non-ACPI) mode\n")); + break; + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Give the platform some time to react */ + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_os_stall (20000); + /* + * Some hardware takes a LONG time to switch modes. Give them 3 sec to + * do so, but allow faster systems to proceed more quickly. + */ + retry = 3000; + while (retry) { + status = AE_NO_HARDWARE_RESPONSE; - if (acpi_hw_get_mode () == mode) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode)); - status = AE_OK; + if (acpi_hw_get_mode() == mode) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode)); + status = AE_OK; + break; + } + acpi_os_stall(1000); + retry--; } return_ACPI_STATUS (status); @@ -247,74 +174,33 @@ u32 acpi_hw_get_mode (void) { + acpi_status status; + u32 value; - FUNCTION_TRACE ("Hw_get_mode"); + ACPI_FUNCTION_TRACE ("Hw_get_mode"); - if (acpi_hw_register_bit_access (ACPI_READ, ACPI_MTX_LOCK, SCI_EN)) { - return_VALUE (SYS_MODE_ACPI); + status = acpi_get_register (ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_VALUE (ACPI_SYS_MODE_LEGACY); } - else { - return_VALUE (SYS_MODE_LEGACY); - } -} - - -/****************************************************************************** - * - * FUNCTION: Acpi_hw_get_mode_capabilities - * - * PARAMETERS: none - * - * RETURN: logical OR of SYS_MODE_ACPI and SYS_MODE_LEGACY determined at initial - * system state. - * - * DESCRIPTION: Returns capablities of system - * - ******************************************************************************/ - -u32 -acpi_hw_get_mode_capabilities (void) -{ - - FUNCTION_TRACE ("Hw_get_mode_capabilities"); - - if (!(acpi_gbl_system_flags & SYS_MODES_MASK)) { - if (acpi_hw_get_mode () == SYS_MODE_LEGACY) { - /* - * Assume that if this call is being made, Acpi_init has been called - * and ACPI support has been established by the presence of the - * tables. Therefore since we're in SYS_MODE_LEGACY, the system - * must support both modes - */ - acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY); + if (value) { + return_VALUE (ACPI_SYS_MODE_ACPI); + } + else { +#ifdef CONFIG_IA64_HP_PROTO + /* + * If enable/disable are zero, the system doesn't support + * legacy mode, so the SCI_EN is wrong. + */ + if (!acpi_gbl_FADT->acpi_enable && + !acpi_gbl_FADT->acpi_disable) { + printk("Warning: Ignoring bogus SCI_EN value\n"); + return_VALUE (ACPI_SYS_MODE_ACPI); } +#endif - else { - /* TBD: [Investigate] !!! this may be unsafe... */ - /* - * system is is ACPI mode, so try to switch back to LEGACY to see if - * it is supported - */ - acpi_hw_set_mode (SYS_MODE_LEGACY); - - if (acpi_hw_get_mode () == SYS_MODE_LEGACY) { - /* Now in SYS_MODE_LEGACY, so both are supported */ - - acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY); - acpi_hw_set_mode (SYS_MODE_ACPI); - } - - else { - /* Still in SYS_MODE_ACPI so this must be an ACPI only system */ - - acpi_gbl_system_flags |= SYS_MODE_ACPI; - } - } + return_VALUE (ACPI_SYS_MODE_LEGACY); } - - return_VALUE (acpi_gbl_system_flags & SYS_MODES_MASK); } - - diff -Nur linux-2.4.19/drivers/acpi/hardware/hwgpe.c linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwgpe.c --- linux-2.4.19/drivers/acpi/hardware/hwgpe.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwgpe.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Module Name: hwgpe - Low level GPE enable/disable/clear functions - * $Revision: 35 $ + * $Revision: 41 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,12 +25,30 @@ */ #include "acpi.h" -#include "achware.h" -#include "acnamesp.h" #include "acevents.h" #define _COMPONENT ACPI_HARDWARE - MODULE_NAME ("hwgpe") + ACPI_MODULE_NAME ("hwgpe") + + +/****************************************************************************** + * + * FUNCTION: Acpi_hw_get_gpe_bit_mask + * + * PARAMETERS: Gpe_number - The GPE + * + * RETURN: Gpe register bitmask for this gpe level + * + * DESCRIPTION: Get the bitmask for this GPE + * + ******************************************************************************/ + +u8 +acpi_hw_get_gpe_bit_mask ( + u32 gpe_number) +{ + return (acpi_gbl_gpe_number_info [acpi_ev_get_gpe_number_index (gpe_number)].bit_mask); +} /****************************************************************************** @@ -45,38 +63,44 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_enable_gpe ( u32 gpe_number) { u32 in_byte; u32 register_index; - u32 bit_mask; + u8 bit_mask; + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - /* - * Translate GPE number to index into global registers array. - */ - register_index = acpi_gbl_gpe_valid[gpe_number]; + /* Translate GPE number to index into global registers array. */ - /* - * Figure out the bit offset for this GPE within the target register. - */ - bit_mask = acpi_gbl_decode_to8bit [MOD_8 (gpe_number)]; + register_index = acpi_ev_get_gpe_register_index (gpe_number); + + /* Get the register bitmask for this GPE */ + + bit_mask = acpi_hw_get_gpe_bit_mask (gpe_number); /* * Read the current value of the register, set the appropriate bit * to enable the GPE, and write out the new register. */ - in_byte = 0; - acpi_os_read_port (acpi_gbl_gpe_registers[register_index].enable_addr, &in_byte, 8); - acpi_os_write_port (acpi_gbl_gpe_registers[register_index].enable_addr, - (in_byte | bit_mask), 8); + status = acpi_hw_low_level_read (8, &in_byte, + &acpi_gbl_gpe_register_info[register_index].enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } + + status = acpi_hw_low_level_write (8, (in_byte | bit_mask), + &acpi_gbl_gpe_register_info[register_index].enable_address, 0); + + return (status); } + /****************************************************************************** * * FUNCTION: Acpi_hw_enable_gpe_for_wakeup @@ -95,28 +119,27 @@ u32 gpe_number) { u32 register_index; - u32 bit_mask; + u8 bit_mask; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - /* - * Translate GPE number to index into global registers array. - */ - register_index = acpi_gbl_gpe_valid[gpe_number]; + /* Translate GPE number to index into global registers array. */ - /* - * Figure out the bit offset for this GPE within the target register. - */ - bit_mask = acpi_gbl_decode_to8bit [MOD_8 (gpe_number)]; + register_index = acpi_ev_get_gpe_register_index (gpe_number); + + /* Get the register bitmask for this GPE */ + + bit_mask = acpi_hw_get_gpe_bit_mask (gpe_number); /* * Set the bit so we will not disable this when sleeping */ - acpi_gbl_gpe_registers[register_index].wake_enable |= bit_mask; + acpi_gbl_gpe_register_info[register_index].wake_enable |= bit_mask; } + /****************************************************************************** * * FUNCTION: Acpi_hw_disable_gpe @@ -129,40 +152,48 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_disable_gpe ( u32 gpe_number) { u32 in_byte; u32 register_index; - u32 bit_mask; + u8 bit_mask; + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - /* - * Translate GPE number to index into global registers array. - */ - register_index = acpi_gbl_gpe_valid[gpe_number]; + /* Translate GPE number to index into global registers array. */ - /* - * Figure out the bit offset for this GPE within the target register. - */ - bit_mask = acpi_gbl_decode_to8bit [MOD_8 (gpe_number)]; + register_index = acpi_ev_get_gpe_register_index (gpe_number); + + /* Get the register bitmask for this GPE */ + + bit_mask = acpi_hw_get_gpe_bit_mask (gpe_number); /* * Read the current value of the register, clear the appropriate bit, * and write out the new register value to disable the GPE. */ - in_byte = 0; - acpi_os_read_port (acpi_gbl_gpe_registers[register_index].enable_addr, &in_byte, 8); - acpi_os_write_port (acpi_gbl_gpe_registers[register_index].enable_addr, - (in_byte & ~bit_mask), 8); + status = acpi_hw_low_level_read (8, &in_byte, + &acpi_gbl_gpe_register_info[register_index].enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } + + status = acpi_hw_low_level_write (8, (in_byte & ~bit_mask), + &acpi_gbl_gpe_register_info[register_index].enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } acpi_hw_disable_gpe_for_wakeup(gpe_number); + return (AE_OK); } + /****************************************************************************** * * FUNCTION: Acpi_hw_disable_gpe_for_wakeup @@ -181,28 +212,27 @@ u32 gpe_number) { u32 register_index; - u32 bit_mask; + u8 bit_mask; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - /* - * Translate GPE number to index into global registers array. - */ - register_index = acpi_gbl_gpe_valid[gpe_number]; + /* Translate GPE number to index into global registers array. */ - /* - * Figure out the bit offset for this GPE within the target register. - */ - bit_mask = acpi_gbl_decode_to8bit [MOD_8 (gpe_number)]; + register_index = acpi_ev_get_gpe_register_index (gpe_number); + + /* Get the register bitmask for this GPE */ + + bit_mask = acpi_hw_get_gpe_bit_mask (gpe_number); /* * Clear the bit so we will disable this when sleeping */ - acpi_gbl_gpe_registers[register_index].wake_enable &= ~bit_mask; + acpi_gbl_gpe_register_info[register_index].wake_enable &= ~bit_mask; } + /****************************************************************************** * * FUNCTION: Acpi_hw_clear_gpe @@ -215,32 +245,34 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_clear_gpe ( u32 gpe_number) { u32 register_index; - u32 bit_mask; + u8 bit_mask; + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - /* - * Translate GPE number to index into global registers array. - */ - register_index = acpi_gbl_gpe_valid[gpe_number]; + /* Translate GPE number to index into global registers array. */ - /* - * Figure out the bit offset for this GPE within the target register. - */ - bit_mask = acpi_gbl_decode_to8bit [MOD_8 (gpe_number)]; + register_index = acpi_ev_get_gpe_register_index (gpe_number); + + /* Get the register bitmask for this GPE */ + + bit_mask = acpi_hw_get_gpe_bit_mask (gpe_number); /* * Write a one to the appropriate bit in the status register to * clear this GPE. */ - acpi_os_write_port (acpi_gbl_gpe_registers[register_index].status_addr, bit_mask, 8); + status = acpi_hw_low_level_write (8, bit_mask, + &acpi_gbl_gpe_register_info[register_index].status_address, 0); + + return (status); } @@ -256,61 +288,67 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_get_gpe_status ( u32 gpe_number, acpi_event_status *event_status) { u32 in_byte = 0; u32 register_index = 0; - u32 bit_mask = 0; + u8 bit_mask = 0; + ACPI_GPE_REGISTER_INFO *gpe_register_info; + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (!event_status) { - return; + return (AE_BAD_PARAMETER); } (*event_status) = 0; - /* - * Translate GPE number to index into global registers array. - */ - register_index = acpi_gbl_gpe_valid[gpe_number]; + /* Translate GPE number to index into global registers array. */ - /* - * Figure out the bit offset for this GPE within the target register. - */ - bit_mask = acpi_gbl_decode_to8bit [MOD_8 (gpe_number)]; + register_index = acpi_ev_get_gpe_register_index (gpe_number); + gpe_register_info = &acpi_gbl_gpe_register_info[register_index]; + + /* Get the register bitmask for this GPE */ + + bit_mask = acpi_hw_get_gpe_bit_mask (gpe_number); + + /* GPE Enabled? */ + + status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } - /* - * Enabled?: - */ - in_byte = 0; - acpi_os_read_port (acpi_gbl_gpe_registers[register_index].enable_addr, &in_byte, 8); if (bit_mask & in_byte) { (*event_status) |= ACPI_EVENT_FLAG_ENABLED; } - /* - * Enabled for wake?: - */ - if (bit_mask & acpi_gbl_gpe_registers[register_index].wake_enable) { + /* GPE Enabled for wake? */ + + if (bit_mask & gpe_register_info->wake_enable) { (*event_status) |= ACPI_EVENT_FLAG_WAKE_ENABLED; } - /* - * Set? - */ - in_byte = 0; - acpi_os_read_port (acpi_gbl_gpe_registers[register_index].status_addr, &in_byte, 8); + /* GPE active (set)? */ + + status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } + if (bit_mask & in_byte) { (*event_status) |= ACPI_EVENT_FLAG_SET; } + return (AE_OK); } + /****************************************************************************** * * FUNCTION: Acpi_hw_disable_non_wakeup_gpes @@ -321,36 +359,53 @@ * * DESCRIPTION: Disable all non-wakeup GPEs * Call with interrupts disabled. The interrupt handler also - * modifies Acpi_gbl_Gpe_registers[i].Enable, so it should not be + * modifies Acpi_gbl_Gpe_register_info[i].Enable, so it should not be * given the chance to run until after non-wake GPEs are * re-enabled. * ******************************************************************************/ -void +acpi_status acpi_hw_disable_non_wakeup_gpes ( void) { u32 i; + ACPI_GPE_REGISTER_INFO *gpe_register_info; + u32 in_value; + acpi_status status; + + + ACPI_FUNCTION_ENTRY (); - FUNCTION_ENTRY (); for (i = 0; i < acpi_gbl_gpe_register_count; i++) { + gpe_register_info = &acpi_gbl_gpe_register_info[i]; + /* * Read the enabled status of all GPEs. We * will be using it to restore all the GPEs later. */ - acpi_os_read_port (acpi_gbl_gpe_registers[i].enable_addr, - &acpi_gbl_gpe_registers[i].enable, 8); + status = acpi_hw_low_level_read (8, &in_value, + &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } + + gpe_register_info->enable = (u8) in_value; /* - * Disable all GPEs but wakeup GPEs. + * Disable all GPEs except wakeup GPEs. */ - acpi_os_write_port(acpi_gbl_gpe_registers[i].enable_addr, - acpi_gbl_gpe_registers[i].wake_enable, 8); + status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable, + &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } } + return (AE_OK); } + /****************************************************************************** * * FUNCTION: Acpi_hw_enable_non_wakeup_gpes @@ -363,20 +418,30 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_enable_non_wakeup_gpes ( void) { u32 i; + ACPI_GPE_REGISTER_INFO *gpe_register_info; + acpi_status status; + + + ACPI_FUNCTION_ENTRY (); - FUNCTION_ENTRY (); for (i = 0; i < acpi_gbl_gpe_register_count; i++) { + gpe_register_info = &acpi_gbl_gpe_register_info[i]; + /* * We previously stored the enabled status of all GPEs. * Blast them back in. */ - acpi_os_write_port(acpi_gbl_gpe_registers[i].enable_addr, - acpi_gbl_gpe_registers[i].enable, 8); + status = acpi_hw_low_level_write (8, gpe_register_info->enable, + &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } } + return (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/hardware/hwregs.c linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwregs.c --- linux-2.4.19/drivers/acpi/hardware/hwregs.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwregs.c Tue Aug 27 19:53:13 2002 @@ -3,12 +3,12 @@ * * Module Name: hwregs - Read/write access functions for the various ACPI * control and status registers. - * $Revision: 110 $ + * $Revision: 130 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,40 +27,10 @@ #include "acpi.h" -#include "achware.h" #include "acnamesp.h" #define _COMPONENT ACPI_HARDWARE - MODULE_NAME ("hwregs") - - -/******************************************************************************* - * - * FUNCTION: Acpi_hw_get_bit_shift - * - * PARAMETERS: Mask - Input mask to determine bit shift from. - * Must have at least 1 bit set. - * - * RETURN: Bit location of the lsb of the mask - * - * DESCRIPTION: Returns the bit number for the low order bit that's set. - * - ******************************************************************************/ - -u32 -acpi_hw_get_bit_shift ( - u32 mask) -{ - u32 shift; - - - FUNCTION_TRACE ("Hw_get_bit_shift"); - - - for (shift = 0; ((mask >> shift) & 1) == 0; shift++) { ; } - - return_VALUE (shift); -} + ACPI_MODULE_NAME ("hwregs") /******************************************************************************* @@ -75,92 +45,94 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_clear_acpi_status (void) { - u16 gpe_length; - u16 index; + NATIVE_UINT_MAX32 i; + NATIVE_UINT gpe_block; + acpi_status status; - FUNCTION_TRACE ("Hw_clear_acpi_status"); + ACPI_FUNCTION_TRACE ("Hw_clear_acpi_status"); ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %04X\n", - ALL_FIXED_STS_BITS, + ACPI_BITMASK_ALL_FIXED_STATUS, (u16) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm1a_evt_blk.address))); - acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); - - acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_STS, ALL_FIXED_STS_BITS); - - - if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address)) { - acpi_os_write_port ((ACPI_IO_ADDRESS) - ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address), - ALL_FIXED_STS_BITS, 16); + status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - /* now clear the GPE Bits */ + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, + ACPI_BITMASK_ALL_FIXED_STATUS); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - if (acpi_gbl_FADT->gpe0blk_len) { - gpe_length = (u16) DIV_2 (acpi_gbl_FADT->gpe0blk_len); + /* Clear the fixed events */ - for (index = 0; index < gpe_length; index++) { - acpi_os_write_port ((ACPI_IO_ADDRESS) ( - ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + index), - 0xFF, 8); + if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address)) { + status = acpi_hw_low_level_write (16, ACPI_BITMASK_ALL_FIXED_STATUS, + &acpi_gbl_FADT->Xpm1b_evt_blk, 0); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; } } - if (acpi_gbl_FADT->gpe1_blk_len) { - gpe_length = (u16) DIV_2 (acpi_gbl_FADT->gpe1_blk_len); + /* Clear the GPE Bits */ - for (index = 0; index < gpe_length; index++) { - acpi_os_write_port ((ACPI_IO_ADDRESS) ( - ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + index), - 0xFF, 8); + for (gpe_block = 0; gpe_block < ACPI_MAX_GPE_BLOCKS; gpe_block++) { + for (i = 0; i < acpi_gbl_gpe_block_info[gpe_block].register_count; i++) { + status = acpi_hw_low_level_write (8, 0xFF, + acpi_gbl_gpe_block_info[gpe_block].block_address, i); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } } } - acpi_ut_release_mutex (ACPI_MTX_HARDWARE); - return_VOID; +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: Acpi_hw_obtain_sleep_type_register_data + * FUNCTION: Acpi_get_sleep_type_data * - * PARAMETERS: Sleep_state - Numeric state requested - * *Slp_Typ_a - Pointer to byte to receive SLP_TYPa value - * *Slp_Typ_b - Pointer to byte to receive SLP_TYPb value + * PARAMETERS: Sleep_state - Numeric sleep state + * *Sleep_type_a - Where SLP_TYPa is returned + * *Sleep_type_b - Where SLP_TYPb is returned * * RETURN: Status - ACPI status * - * DESCRIPTION: Acpi_hw_obtain_sleep_type_register_data() obtains the SLP_TYP and - * SLP_TYPb values for the sleep state requested. + * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep + * state. * ******************************************************************************/ acpi_status -acpi_hw_obtain_sleep_type_register_data ( +acpi_get_sleep_type_data ( u8 sleep_state, - u8 *slp_typ_a, - u8 *slp_typ_b) + u8 *sleep_type_a, + u8 *sleep_type_b) { acpi_status status = AE_OK; acpi_operand_object *obj_desc; - FUNCTION_TRACE ("Hw_obtain_sleep_type_register_data"); + ACPI_FUNCTION_TRACE ("Acpi_get_sleep_type_data"); /* * Validate parameters */ if ((sleep_state > ACPI_S_STATES_MAX) || - !slp_typ_a || !slp_typ_b) { + !sleep_type_a || !sleep_type_b) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -174,7 +146,7 @@ } if (!obj_desc) { - REPORT_ERROR (("Missing Sleep State object\n")); + ACPI_REPORT_ERROR (("Missing Sleep State object\n")); return_ACPI_STATUS (AE_NOT_EXIST); } @@ -185,387 +157,281 @@ */ /* Even though Acpi_evaluate_object resolves package references, - * Ns_evaluate dpesn't. So, we do it here. + * Ns_evaluate doesn't. So, we do it here. */ status = acpi_ut_resolve_package_references(obj_desc); if (obj_desc->package.count < 2) { /* Must have at least two elements */ - REPORT_ERROR (("Sleep State package does not have at least two elements\n")); - status = AE_ERROR; + ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n")); + status = AE_AML_NO_OPERAND; } - - else if (((obj_desc->package.elements[0])->common.type != - ACPI_TYPE_INTEGER) || - ((obj_desc->package.elements[1])->common.type != - ACPI_TYPE_INTEGER)) { + else if (((obj_desc->package.elements[0])->common.type != ACPI_TYPE_INTEGER) || + ((obj_desc->package.elements[1])->common.type != ACPI_TYPE_INTEGER)) { /* Must have two */ - REPORT_ERROR (("Sleep State package elements are not both of type Number\n")); - status = AE_ERROR; + ACPI_REPORT_ERROR (("Sleep State package elements are not both of type Number\n")); + status = AE_AML_OPERAND_TYPE; } - else { /* * Valid _Sx_ package size, type, and value */ - *slp_typ_a = (u8) (obj_desc->package.elements[0])->integer.value; - - *slp_typ_b = (u8) (obj_desc->package.elements[1])->integer.value; + *sleep_type_a = (u8) (obj_desc->package.elements[0])->integer.value; + *sleep_type_b = (u8) (obj_desc->package.elements[1])->integer.value; } - if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad Sleep object %p type %X\n", obj_desc, obj_desc->common.type)); } acpi_ut_remove_reference (obj_desc); - return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: Acpi_hw_register_bit_access + * FUNCTION: Acpi_hw_get_register_bit_mask * - * PARAMETERS: Read_write - Either ACPI_READ or ACPI_WRITE. - * Use_lock - Lock the hardware - * Register_id - index of ACPI Register to access - * Value - (only used on write) value to write to the - * Register. Shifted all the way right. + * PARAMETERS: Register_id - index of ACPI Register to access * - * RETURN: Value written to or read from specified Register. This value - * is shifted all the way right. + * RETURN: The bit mask to be used when accessing the register * - * DESCRIPTION: Generic ACPI Register read/write function. + * DESCRIPTION: Map Register_id into a register bit mask. * ******************************************************************************/ -u32 -acpi_hw_register_bit_access ( - NATIVE_UINT read_write, - u8 use_lock, - u32 register_id, - ...) /* Value (only used on write) */ +ACPI_BIT_REGISTER_INFO * +acpi_hw_get_bit_register_info ( + u32 register_id) { - u32 register_value = 0; - u32 mask = 0; - u32 value = 0; - va_list marker; - + ACPI_FUNCTION_NAME ("Hw_get_bit_register_info"); - FUNCTION_TRACE ("Hw_register_bit_access"); - - - if (read_write == ACPI_WRITE) { - va_start (marker, register_id); - value = va_arg (marker, u32); - va_end (marker); - } - if (ACPI_MTX_LOCK == use_lock) { - acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (register_id > ACPI_BITREG_MAX) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid Bit_register ID: %X\n", register_id)); + return (NULL); } - /* - * Decode the Register ID - * Register id = Register block id | bit id - * - * Check bit id to fine locate Register offset. - * Check Mask to determine Register offset, and then read-write. - */ - switch (REGISTER_BLOCK_ID (register_id)) { - case PM1_STS: - - switch (register_id) { - case TMR_STS: - mask = TMR_STS_MASK; - break; - - case BM_STS: - mask = BM_STS_MASK; - break; - - case GBL_STS: - mask = GBL_STS_MASK; - break; - - case PWRBTN_STS: - mask = PWRBTN_STS_MASK; - break; - - case SLPBTN_STS: - mask = SLPBTN_STS_MASK; - break; - - case RTC_STS: - mask = RTC_STS_MASK; - break; - - case WAK_STS: - mask = WAK_STS_MASK; - break; - - default: - mask = 0; - break; - } - - register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_STS); - - if (read_write == ACPI_WRITE) { - /* - * Status Registers are different from the rest. Clear by - * writing 1, writing 0 has no effect. So, the only relevent - * information is the single bit we're interested in, all - * others should be written as 0 so they will be left - * unchanged - */ - value <<= acpi_hw_get_bit_shift (mask); - value &= mask; - - if (value) { - acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_STS, - (u16) value); - register_value = 0; - } - } - - break; - - - case PM1_EN: + return (&acpi_gbl_bit_register_info[register_id]); +} - switch (register_id) { - case TMR_EN: - mask = TMR_EN_MASK; - break; - case GBL_EN: - mask = GBL_EN_MASK; - break; +/******************************************************************************* + * + * FUNCTION: Acpi_get_register + * + * PARAMETERS: Register_id - index of ACPI Register to access + * Use_lock - Lock the hardware + * + * RETURN: Value is read from specified Register. Value returned is + * normalized to bit0 (is shifted all the way right) + * + * DESCRIPTION: ACPI Bit_register read function. + * + ******************************************************************************/ - case PWRBTN_EN: - mask = PWRBTN_EN_MASK; - break; +acpi_status +acpi_get_register ( + u32 register_id, + u32 *return_value, + u32 flags) +{ + u32 register_value = 0; + ACPI_BIT_REGISTER_INFO *bit_reg_info; + acpi_status status; - case SLPBTN_EN: - mask = SLPBTN_EN_MASK; - break; - case RTC_EN: - mask = RTC_EN_MASK; - break; + ACPI_FUNCTION_TRACE ("Acpi_get_register"); - default: - mask = 0; - break; - } - register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_EN); + /* Get the info structure corresponding to the requested ACPI Register */ - if (read_write == ACPI_WRITE) { - register_value &= ~mask; - value <<= acpi_hw_get_bit_shift (mask); - value &= mask; - register_value |= value; + bit_reg_info = acpi_hw_get_bit_register_info (register_id); + if (!bit_reg_info) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } - acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_EN, (u16) register_value); + if (flags & ACPI_MTX_LOCK) { + status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } + } - break; - - - case PM1_CONTROL: + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, + bit_reg_info->parent_register, ®ister_value); - switch (register_id) { - case SCI_EN: - mask = SCI_EN_MASK; - break; + if (flags & ACPI_MTX_LOCK) { + (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + } - case BM_RLD: - mask = BM_RLD_MASK; - break; + if (ACPI_SUCCESS (status)) { + /* Normalize the value that was read */ - case GBL_RLS: - mask = GBL_RLS_MASK; - break; + register_value = ((register_value & bit_reg_info->access_bit_mask) + >> bit_reg_info->bit_position); - case SLP_TYPE_A: - case SLP_TYPE_B: - mask = SLP_TYPE_X_MASK; - break; + *return_value = register_value; - case SLP_EN: - mask = SLP_EN_MASK; - break; + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %X\n", register_value)); + } - default: - mask = 0; - break; - } + return_ACPI_STATUS (status); +} - /* - * Read the PM1 Control register. - * Note that at this level, the fact that there are actually TWO - * registers (A and B) and that B may not exist, are abstracted. - */ - register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_CONTROL); +/******************************************************************************* + * + * FUNCTION: Acpi_set_register + * + * PARAMETERS: Register_id - ID of ACPI Bit_register to access + * Value - (only used on write) value to write to the + * Register, NOT pre-normalized to the bit pos. + * Flags - Lock the hardware or not + * + * RETURN: None + * + * DESCRIPTION: ACPI Bit Register write function. + * + ******************************************************************************/ - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM1 control: Read %X\n", register_value)); +acpi_status +acpi_set_register ( + u32 register_id, + u32 value, + u32 flags) +{ + u32 register_value = 0; + ACPI_BIT_REGISTER_INFO *bit_reg_info; + acpi_status status; - if (read_write == ACPI_WRITE) { - register_value &= ~mask; - value <<= acpi_hw_get_bit_shift (mask); - value &= mask; - register_value |= value; - /* - * SLP_TYPE_x Registers are written differently - * than any other control Registers with - * respect to A and B Registers. The value - * for A may be different than the value for B - * - * Therefore, pass the Register_id, not just generic PM1_CONTROL, - * because we need to do different things. Yuck. - */ - acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, register_id, - (u16) register_value); - } - break; + ACPI_FUNCTION_TRACE_U32 ("Acpi_set_register", register_id); - case PM2_CONTROL: + /* Get the info structure corresponding to the requested ACPI Register */ - switch (register_id) { - case ARB_DIS: - mask = ARB_DIS_MASK; - break; + bit_reg_info = acpi_hw_get_bit_register_info (register_id); + if (!bit_reg_info) { + ACPI_REPORT_ERROR (("Bad ACPI HW Register_id: %X\n", register_id)); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } - default: - mask = 0; - break; + if (flags & ACPI_MTX_LOCK) { + status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } + } - register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM2_CONTROL); - - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", - register_value, HIDWORD(acpi_gbl_FADT->Xpm2_cnt_blk.address), - LODWORD(acpi_gbl_FADT->Xpm2_cnt_blk.address))); + /* Always do a register read first so we can insert the new bits */ - if (read_write == ACPI_WRITE) { - register_value &= ~mask; - value <<= acpi_hw_get_bit_shift (mask); - value &= mask; - register_value |= value; + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, + bit_reg_info->parent_register, ®ister_value); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", - register_value, - HIDWORD(acpi_gbl_FADT->Xpm2_cnt_blk.address), - LODWORD(acpi_gbl_FADT->Xpm2_cnt_blk.address))); + /* + * Decode the Register ID + * Register id = Register block id | bit id + * + * Check bit id to fine locate Register offset. + * Check Mask to determine Register offset, and then read-write. + */ + switch (bit_reg_info->parent_register) { + case ACPI_REGISTER_PM1_STATUS: - acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, - PM2_CONTROL, (u8) (register_value)); + /* + * Status Registers are different from the rest. Clear by + * writing 1, writing 0 has no effect. So, the only relevent + * information is the single bit we're interested in, all others should + * be written as 0 so they will be left unchanged + */ + value = ACPI_REGISTER_PREPARE_BITS (value, + bit_reg_info->bit_position, bit_reg_info->access_bit_mask); + if (value) { + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_STATUS, (u16) value); + register_value = 0; } break; - case PM_TIMER: + case ACPI_REGISTER_PM1_ENABLE: - mask = TMR_VAL_MASK; - register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, - PM_TIMER); - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM_TIMER: Read %X from %8.8X%8.8X\n", - register_value, - HIDWORD(acpi_gbl_FADT->Xpm_tmr_blk.address), - LODWORD(acpi_gbl_FADT->Xpm_tmr_blk.address))); + ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, + bit_reg_info->access_bit_mask, value); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_ENABLE, (u16) register_value); break; - case GPE1_EN_BLOCK: - case GPE1_STS_BLOCK: - case GPE0_EN_BLOCK: - case GPE0_STS_BLOCK: - - /* Determine the bit to be accessed - * - * (u32) Register_id: - * 31 24 16 8 0 - * +--------+--------+--------+--------+ - * | gpe_block_id | gpe_bit_number | - * +--------+--------+--------+--------+ - * - * gpe_block_id is one of GPE[01]_EN_BLOCK and GPE[01]_STS_BLOCK - * gpe_bit_number is relative from the gpe_block (0x00~0xFF) - */ - mask = REGISTER_BIT_ID(register_id); /* gpe_bit_number */ - register_id = REGISTER_BLOCK_ID(register_id) | (mask >> 3); - mask = acpi_gbl_decode_to8bit [mask % 8]; + case ACPI_REGISTER_PM1_CONTROL: /* - * The base address of the GPE 0 Register Block - * Plus 1/2 the length of the GPE 0 Register Block - * The enable Register is the Register following the Status Register - * and each Register is defined as 1/2 of the total Register Block + * Read the PM1 Control register. + * Note that at this level, the fact that there are actually TWO + * registers (A and B - and that B may not exist) is abstracted. */ + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM1 control: Read %X\n", register_value)); - /* - * This sets the bit within Enable_bit that needs to be written to - * the Register indicated in Mask to a 1, all others are 0 - */ + ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, + bit_reg_info->access_bit_mask, value); - /* Now get the current Enable Bits in the selected Reg */ + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, register_id, + (u16) register_value); + break; - register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, register_id); - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "GPE Enable bits: Read %X from %X\n", - register_value, register_id)); - if (read_write == ACPI_WRITE) { - register_value &= ~mask; - value <<= acpi_hw_get_bit_shift (mask); - value &= mask; - register_value |= value; + case ACPI_REGISTER_PM2_CONTROL: - /* - * This write will put the Action state into the General Purpose - * Enable Register indexed by the value in Mask - */ - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %04X\n", - register_value, register_id)); - acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, register_id, - (u8) register_value); - register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, - register_id); + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM2_CONTROL, ®ister_value); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; } - break; + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", + register_value, + ACPI_HIDWORD (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address)), + ACPI_LODWORD (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address)))); - case SMI_CMD_BLOCK: - case PROCESSOR_BLOCK: + ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, + bit_reg_info->access_bit_mask, value); - /* Not used by any callers at this time - therefore, not implemented */ + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n", + register_value, + ACPI_HIDWORD (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address)), + ACPI_LODWORD (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address)))); + + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); + break; - default: - mask = 0; + default: break; } - if (ACPI_MTX_LOCK == use_lock) { - acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + +unlock_and_exit: + + if (flags & ACPI_MTX_LOCK) { + (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); } + /* Normalize the value that was read */ - register_value &= mask; - register_value >>= acpi_hw_get_bit_shift (mask); + ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position)); - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Register I/O: returning %X\n", register_value)); - return_VALUE (register_value); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "ACPI Register Write actual %X\n", register_value)); + return_ACPI_STATUS (status); } @@ -583,103 +449,98 @@ * ******************************************************************************/ -u32 +acpi_status acpi_hw_register_read ( u8 use_lock, - u32 register_id) + u32 register_id, + u32 *return_value) { - u32 value = 0; + u32 value1 = 0; + u32 value2 = 0; u32 bank_offset; + acpi_status status; - FUNCTION_TRACE ("Hw_register_read"); + ACPI_FUNCTION_TRACE ("Hw_register_read"); if (ACPI_MTX_LOCK == use_lock) { - acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } + switch (register_id) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ - switch (REGISTER_BLOCK_ID(register_id)) { - case PM1_STS: /* 16-bit access */ + status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->Xpm1a_evt_blk, 0); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - value = acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1a_evt_blk, 0); - value |= acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1b_evt_blk, 0); + status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->Xpm1b_evt_blk, 0); + value1 |= value2; break; - case PM1_EN: /* 16-bit access*/ - - bank_offset = DIV_2 (acpi_gbl_FADT->pm1_evt_len); - value = acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1a_evt_blk, bank_offset); - value |= acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1b_evt_blk, bank_offset); - break; - + case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access*/ - case PM1_CONTROL: /* 16-bit access */ + bank_offset = ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len); + status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->Xpm1a_evt_blk, bank_offset); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - value = acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); - value |= acpi_hw_low_level_read (16, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); + status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->Xpm1b_evt_blk, bank_offset); + value1 |= value2; break; - case PM2_CONTROL: /* 8-bit access */ + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ - value = acpi_hw_low_level_read (8, &acpi_gbl_FADT->Xpm2_cnt_blk, 0); - break; - - - case PM_TIMER: /* 32-bit access */ + status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - value = acpi_hw_low_level_read (32, &acpi_gbl_FADT->Xpm_tmr_blk, 0); + status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); + value1 |= value2; break; - /* - * For the GPE? Blocks, the lower word of Register_id contains the - * byte offset for which to read, as each part of each block may be - * several bytes long. - */ - case GPE0_STS_BLOCK: /* 8-bit access */ + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ - bank_offset = REGISTER_BIT_ID(register_id); - value = acpi_hw_low_level_read (8, &acpi_gbl_FADT->Xgpe0blk, bank_offset); + status = acpi_hw_low_level_read (8, &value1, &acpi_gbl_FADT->Xpm2_cnt_blk, 0); break; - case GPE0_EN_BLOCK: /* 8-bit access */ - - bank_offset = DIV_2 (acpi_gbl_FADT->gpe0blk_len) + REGISTER_BIT_ID(register_id); - value = acpi_hw_low_level_read (8, &acpi_gbl_FADT->Xgpe0blk, bank_offset); - break; - case GPE1_STS_BLOCK: /* 8-bit access */ + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - bank_offset = REGISTER_BIT_ID(register_id); - value = acpi_hw_low_level_read (8, &acpi_gbl_FADT->Xgpe1_blk, bank_offset); + status = acpi_hw_low_level_read (32, &value1, &acpi_gbl_FADT->Xpm_tmr_blk, 0); break; - case GPE1_EN_BLOCK: /* 8-bit access */ + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ - bank_offset = DIV_2 (acpi_gbl_FADT->gpe1_blk_len) + REGISTER_BIT_ID(register_id); - value = acpi_hw_low_level_read (8, &acpi_gbl_FADT->Xgpe1_blk, bank_offset); - break; - - case SMI_CMD_BLOCK: /* 8bit */ - - acpi_os_read_port (acpi_gbl_FADT->smi_cmd, &value, 8); + status = acpi_os_read_port (acpi_gbl_FADT->smi_cmd, &value1, 8); break; default: - /* Value will be returned as 0 */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", register_id)); + status = AE_BAD_PARAMETER; break; } - +unlock_and_exit: if (ACPI_MTX_LOCK == use_lock) { - acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + } + + if (ACPI_SUCCESS (status)) { + *return_value = value1; } - return_VALUE (value); + return_ACPI_STATUS (status); } @@ -697,118 +558,104 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_register_write ( u8 use_lock, u32 register_id, u32 value) { u32 bank_offset; + acpi_status status; - FUNCTION_TRACE ("Hw_register_write"); + ACPI_FUNCTION_TRACE ("Hw_register_write"); if (ACPI_MTX_LOCK == use_lock) { - acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } + switch (register_id) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ - switch (REGISTER_BLOCK_ID (register_id)) { - case PM1_STS: /* 16-bit access */ - - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_evt_blk, 0); - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_evt_blk, 0); - break; - - - case PM1_EN: /* 16-bit access*/ - - bank_offset = DIV_2 (acpi_gbl_FADT->pm1_evt_len); - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_evt_blk, bank_offset); - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_evt_blk, bank_offset); - break; - - - case PM1_CONTROL: /* 16-bit access */ + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_evt_blk, 0); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_evt_blk, 0); break; - case PM1A_CONTROL: /* 16-bit access */ + case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access*/ - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); - break; - - - case PM1B_CONTROL: /* 16-bit access */ + bank_offset = ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len); + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_evt_blk, bank_offset); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_evt_blk, bank_offset); break; - case PM2_CONTROL: /* 8-bit access */ - - acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->Xpm2_cnt_blk, 0); - break; - + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ - case PM_TIMER: /* 32-bit access */ + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - acpi_hw_low_level_write (32, value, &acpi_gbl_FADT->Xpm_tmr_blk, 0); + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); break; - case GPE0_STS_BLOCK: /* 8-bit access */ + case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ - bank_offset = REGISTER_BIT_ID(register_id); - acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->Xgpe0blk, bank_offset); + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1a_cnt_blk, 0); break; - case GPE0_EN_BLOCK: /* 8-bit access */ + case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ - bank_offset = DIV_2 (acpi_gbl_FADT->gpe0blk_len) + REGISTER_BIT_ID(register_id); - acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->Xgpe0blk, bank_offset); + status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->Xpm1b_cnt_blk, 0); break; - case GPE1_STS_BLOCK: /* 8-bit access */ + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ - bank_offset = REGISTER_BIT_ID(register_id); - acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->Xgpe1_blk, bank_offset); + status = acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->Xpm2_cnt_blk, 0); break; - case GPE1_EN_BLOCK: /* 8-bit access */ + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - bank_offset = DIV_2 (acpi_gbl_FADT->gpe1_blk_len) + REGISTER_BIT_ID(register_id); - acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->Xgpe1_blk, bank_offset); + status = acpi_hw_low_level_write (32, value, &acpi_gbl_FADT->Xpm_tmr_blk, 0); break; - case SMI_CMD_BLOCK: /* 8bit */ + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ - /* For 2.0, SMI_CMD is always in IO space */ - /* TBD: what about 1.0? 0.71? */ + /* SMI_CMD is currently always in IO space */ - acpi_os_write_port (acpi_gbl_FADT->smi_cmd, value, 8); + status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (acpi_integer) value, 8); break; default: - value = 0; + status = AE_BAD_PARAMETER; break; } - +unlock_and_exit: if (ACPI_MTX_LOCK == use_lock) { - acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); } - return_VOID; + return_ACPI_STATUS (status); } @@ -826,31 +673,33 @@ * ******************************************************************************/ -u32 +acpi_status acpi_hw_low_level_read ( u32 width, + u32 *value, acpi_generic_address *reg, u32 offset) { - u32 value = 0; ACPI_PHYSICAL_ADDRESS mem_address; ACPI_IO_ADDRESS io_address; acpi_pci_id pci_id; u16 pci_register; + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_NAME ("Hw_low_level_read"); /* * Must have a valid pointer to a GAS structure, and - * a non-zero address within + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. */ if ((!reg) || (!ACPI_VALID_ADDRESS (reg->address))) { - return 0; + return (AE_OK); } - + *value = 0; /* * Three address spaces supported: @@ -859,17 +708,19 @@ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: - mem_address = (ACPI_PHYSICAL_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + mem_address = (ACPI_GET_ADDRESS (reg->address) + + (ACPI_PHYSICAL_ADDRESS) offset); - acpi_os_read_memory (mem_address, &value, width); + status = acpi_os_read_memory (mem_address, value, width); break; case ACPI_ADR_SPACE_SYSTEM_IO: - io_address = (ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + io_address = (ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + + (ACPI_PHYSICAL_ADDRESS) offset); - acpi_os_read_port (io_address, &value, width); + status = acpi_os_read_port (io_address, value, width); break; @@ -879,13 +730,20 @@ pci_id.bus = 0; pci_id.device = ACPI_PCI_DEVICE (ACPI_GET_ADDRESS (reg->address)); pci_id.function = ACPI_PCI_FUNCTION (ACPI_GET_ADDRESS (reg->address)); - pci_register = (u16) (ACPI_PCI_REGISTER (ACPI_GET_ADDRESS (reg->address)) + offset); + pci_register = (u16) (ACPI_PCI_REGISTER (ACPI_GET_ADDRESS (reg->address)) + + offset); - acpi_os_read_pci_configuration (&pci_id, pci_register, &value, width); + status = acpi_os_read_pci_configuration (&pci_id, pci_register, value, width); + break; + + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); + status = AE_BAD_PARAMETER; break; } - return value; + return (status); } @@ -905,7 +763,7 @@ * ******************************************************************************/ -void +acpi_status acpi_hw_low_level_write ( u32 width, u32 value, @@ -916,21 +774,21 @@ ACPI_IO_ADDRESS io_address; acpi_pci_id pci_id; u16 pci_register; + acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_NAME ("Hw_low_level_write"); /* * Must have a valid pointer to a GAS structure, and - * a non-zero address within + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. */ if ((!reg) || (!ACPI_VALID_ADDRESS (reg->address))) { - return; + return (AE_OK); } - - /* * Three address spaces supported: * Memory, Io, or PCI config. @@ -938,17 +796,19 @@ switch (reg->address_space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: - mem_address = (ACPI_PHYSICAL_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + mem_address = (ACPI_GET_ADDRESS (reg->address) + + (ACPI_PHYSICAL_ADDRESS) offset); - acpi_os_write_memory (mem_address, value, width); + status = acpi_os_write_memory (mem_address, (acpi_integer) value, width); break; case ACPI_ADR_SPACE_SYSTEM_IO: - io_address = (ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + offset); + io_address = (ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (reg->address) + + (ACPI_PHYSICAL_ADDRESS) offset); - acpi_os_write_port (io_address, value, width); + status = acpi_os_write_port (io_address, (acpi_integer) value, width); break; @@ -958,9 +818,18 @@ pci_id.bus = 0; pci_id.device = ACPI_PCI_DEVICE (ACPI_GET_ADDRESS (reg->address)); pci_id.function = ACPI_PCI_FUNCTION (ACPI_GET_ADDRESS (reg->address)); - pci_register = (u16) (ACPI_PCI_REGISTER (ACPI_GET_ADDRESS (reg->address)) + offset); + pci_register = (u16) (ACPI_PCI_REGISTER (ACPI_GET_ADDRESS (reg->address)) + + offset); + + status = acpi_os_write_pci_configuration (&pci_id, pci_register, (acpi_integer) value, width); + break; - acpi_os_write_pci_configuration (&pci_id, pci_register, value, width); + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); + status = AE_BAD_PARAMETER; break; } + + return (status); } diff -Nur linux-2.4.19/drivers/acpi/hardware/hwsleep.c linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwsleep.c --- linux-2.4.19/drivers/acpi/hardware/hwsleep.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwsleep.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface - * $Revision: 22 $ + * $Revision: 45 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,11 +25,9 @@ */ #include "acpi.h" -#include "acnamesp.h" -#include "achware.h" #define _COMPONENT ACPI_HARDWARE - MODULE_NAME ("hwsleep") + ACPI_MODULE_NAME ("hwsleep") /****************************************************************************** @@ -39,7 +37,7 @@ * PARAMETERS: Physical_address - Physical address of ACPI real mode * entry point. * - * RETURN: AE_OK or AE_ERROR + * RETURN: Status * * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS * @@ -50,22 +48,18 @@ ACPI_PHYSICAL_ADDRESS physical_address) { - FUNCTION_TRACE ("Acpi_set_firmware_waking_vector"); - + ACPI_FUNCTION_TRACE ("Acpi_set_firmware_waking_vector"); - /* Make sure that we have an FACS */ - - if (!acpi_gbl_FACS) { - return_ACPI_STATUS (AE_NO_ACPI_TABLES); - } /* Set the vector */ - if (acpi_gbl_FACS->vector_width == 32) { - * (u32 *) acpi_gbl_FACS->firmware_waking_vector = (u32) physical_address; + if (acpi_gbl_common_fACS.vector_width == 32) { + *(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector)) + = (u32) physical_address; } else { - *acpi_gbl_FACS->firmware_waking_vector = physical_address; + *acpi_gbl_common_fACS.firmware_waking_vector + = physical_address; } return_ACPI_STATUS (AE_OK); @@ -82,7 +76,7 @@ * * RETURN: Status * - * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS + * DESCRIPTION: Access function for Firmware_waking_vector field in FACS * ******************************************************************************/ @@ -91,141 +85,229 @@ ACPI_PHYSICAL_ADDRESS *physical_address) { - FUNCTION_TRACE ("Acpi_get_firmware_waking_vector"); + ACPI_FUNCTION_TRACE ("Acpi_get_firmware_waking_vector"); if (!physical_address) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Make sure that we have an FACS */ - - if (!acpi_gbl_FACS) { - return_ACPI_STATUS (AE_NO_ACPI_TABLES); - } - /* Get the vector */ - if (acpi_gbl_FACS->vector_width == 32) { - *physical_address = * (u32 *) acpi_gbl_FACS->firmware_waking_vector; + if (acpi_gbl_common_fACS.vector_width == 32) { + *physical_address = (ACPI_PHYSICAL_ADDRESS) + *(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector)); } else { - *physical_address = *acpi_gbl_FACS->firmware_waking_vector; + *physical_address = + *acpi_gbl_common_fACS.firmware_waking_vector; } return_ACPI_STATUS (AE_OK); } + /****************************************************************************** * - * FUNCTION: Acpi_enter_sleep_state + * FUNCTION: Acpi_enter_sleep_state_prep * * PARAMETERS: Sleep_state - Which sleep state to enter * * RETURN: Status * - * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231) + * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231) + * This function must execute with interrupts enabled. + * We break sleeping into 2 stages so that OSPM can handle + * various OS-specific tasks between the two steps. * ******************************************************************************/ acpi_status -acpi_enter_sleep_state ( +acpi_enter_sleep_state_prep ( u8 sleep_state) { acpi_status status; acpi_object_list arg_list; acpi_object arg; - u8 type_a; - u8 type_b; - u16 PM1Acontrol; - u16 PM1Bcontrol; - FUNCTION_TRACE ("Acpi_enter_sleep_state"); + ACPI_FUNCTION_TRACE ("Acpi_enter_sleep_state_prep"); /* * _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */ - status = acpi_hw_obtain_sleep_type_register_data (sleep_state, &type_a, &type_b); - if (!ACPI_SUCCESS (status)) { - return status; + status = acpi_get_sleep_type_data (sleep_state, + &acpi_gbl_sleep_type_a, &acpi_gbl_sleep_type_b); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - /* run the _PTS and _GTS methods */ + /* Setup parameter object */ - MEMSET(&arg_list, 0, sizeof(arg_list)); arg_list.count = 1; arg_list.pointer = &arg; - MEMSET(&arg, 0, sizeof(arg)); arg.type = ACPI_TYPE_INTEGER; arg.integer.value = sleep_state; - acpi_evaluate_object (NULL, "\\_PTS", &arg_list, NULL); - acpi_evaluate_object (NULL, "\\_GTS", &arg_list, NULL); + /* Run the _PTS and _GTS methods */ + + status = acpi_evaluate_object (NULL, "\\_PTS", &arg_list, NULL); + if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { + return_ACPI_STATUS (status); + } + + status = acpi_evaluate_object (NULL, "\\_GTS", &arg_list, NULL); + if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { + return_ACPI_STATUS (status); + } + + return_ACPI_STATUS (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_enter_sleep_state + * + * PARAMETERS: Sleep_state - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231) + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +acpi_status +acpi_enter_sleep_state ( + u8 sleep_state) +{ + u32 PM1Acontrol; + u32 PM1Bcontrol; + ACPI_BIT_REGISTER_INFO *sleep_type_reg_info; + ACPI_BIT_REGISTER_INFO *sleep_enable_reg_info; + u32 in_value; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Acpi_enter_sleep_state"); + + + if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || + (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { + ACPI_REPORT_ERROR (("Sleep values out of range: A=%X B=%X\n", + acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b)); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + + + sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); + sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); + + /* Clear wake status */ - /* clear wake status */ + status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_hw_clear_acpi_status(); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, WAK_STS, 1); + /* Disable BM arbitration */ - disable (); + status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_hw_disable_non_wakeup_gpes(); + status = acpi_hw_disable_non_wakeup_gpes(); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - PM1Acontrol = (u16) acpi_hw_register_read (ACPI_MTX_LOCK, PM1_CONTROL); + /* Get current value of PM1A control */ + status = acpi_hw_register_read (ACPI_MTX_LOCK, ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Entering S%d\n", sleep_state)); - /* mask off SLP_EN and SLP_TYP fields */ + /* Clear SLP_EN and SLP_TYP fields */ - PM1Acontrol &= ~(SLP_TYPE_X_MASK | SLP_EN_MASK); + PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask); PM1Bcontrol = PM1Acontrol; - /* mask in SLP_TYP */ + /* Insert SLP_TYP bits */ - PM1Acontrol |= (type_a << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK)); - PM1Bcontrol |= (type_b << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK)); + PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position); + PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position); - /* write #1: fill in SLP_TYP data */ + /* Write #1: fill in SLP_TYP data */ + + status = acpi_hw_register_write (ACPI_MTX_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_hw_register_write (ACPI_MTX_LOCK, PM1A_CONTROL, PM1Acontrol); - acpi_hw_register_write (ACPI_MTX_LOCK, PM1B_CONTROL, PM1Bcontrol); + status = acpi_hw_register_write (ACPI_MTX_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - /* mask in SLP_EN */ + /* Insert SLP_ENABLE bit */ - PM1Acontrol |= (1 << acpi_hw_get_bit_shift (SLP_EN_MASK)); - PM1Bcontrol |= (1 << acpi_hw_get_bit_shift (SLP_EN_MASK)); + PM1Acontrol |= sleep_enable_reg_info->access_bit_mask; + PM1Bcontrol |= sleep_enable_reg_info->access_bit_mask; - /* flush caches */ + /* Write #2: SLP_TYP + SLP_EN */ - wbinvd(); + ACPI_FLUSH_CPU_CACHE (); - /* write #2: SLP_TYP + SLP_EN */ + status = acpi_hw_register_write (ACPI_MTX_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_hw_register_write (ACPI_MTX_LOCK, PM1A_CONTROL, PM1Acontrol); - acpi_hw_register_write (ACPI_MTX_LOCK, PM1B_CONTROL, PM1Bcontrol); + status = acpi_hw_register_write (ACPI_MTX_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* * Wait a second, then try again. This is to get S4/5 to work on all machines. */ if (sleep_state > ACPI_STATE_S3) { - acpi_os_stall(1000000); - - acpi_hw_register_write (ACPI_MTX_LOCK, PM1_CONTROL, - (1 << acpi_hw_get_bit_shift (SLP_EN_MASK))); + /* + * We wait so long to allow chipsets that poll this reg very slowly to + * still read the right value. Ideally, this entire block would go + * away entirely. + */ + acpi_os_stall (10000000); + + status = acpi_hw_register_write (ACPI_MTX_LOCK, ACPI_REGISTER_PM1_CONTROL, + sleep_enable_reg_info->access_bit_mask); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - /* wait until we enter sleep state */ + /* Wait until we enter sleep state */ do { - acpi_os_stall(10000); - } - while (!acpi_hw_register_bit_access (ACPI_READ, ACPI_MTX_LOCK, WAK_STS)); + status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_hw_enable_non_wakeup_gpes(); + /* Spin until we wake */ - enable (); + } while (!in_value); return_ACPI_STATUS (AE_OK); } @@ -248,25 +330,45 @@ { acpi_object_list arg_list; acpi_object arg; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Acpi_leave_sleep_state"); - FUNCTION_TRACE ("Acpi_leave_sleep_state"); + /* Ensure Enter_sleep_state_prep -> Enter_sleep_state ordering */ + acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; + + /* Setup parameter object */ - MEMSET (&arg_list, 0, sizeof(arg_list)); arg_list.count = 1; arg_list.pointer = &arg; - MEMSET (&arg, 0, sizeof(arg)); arg.type = ACPI_TYPE_INTEGER; arg.integer.value = sleep_state; - acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL); - acpi_evaluate_object (NULL, "\\_WAK", &arg_list, NULL); + /* Ignore any errors from these methods */ + + status = acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL); + if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { + ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status))); + } + + status = acpi_evaluate_object (NULL, "\\_WAK", &arg_list, NULL); + if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { + ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status))); + } /* _WAK returns stuff - do we want to look at it? */ - acpi_hw_enable_non_wakeup_gpes(); + status = acpi_hw_enable_non_wakeup_gpes(); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Disable BM arbitration */ + status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK); - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/hardware/hwtimer.c linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwtimer.c --- linux-2.4.19/drivers/acpi/hardware/hwtimer.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/hardware/hwtimer.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Name: hwtimer.c - ACPI Power Management Timer Interface - * $Revision: 14 $ + * $Revision: 21 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,10 +25,9 @@ */ #include "acpi.h" -#include "achware.h" #define _COMPONENT ACPI_HARDWARE - MODULE_NAME ("hwtimer") + ACPI_MODULE_NAME ("hwtimer") /****************************************************************************** @@ -47,7 +46,7 @@ acpi_get_timer_resolution ( u32 *resolution) { - FUNCTION_TRACE ("Acpi_get_timer_resolution"); + ACPI_FUNCTION_TRACE ("Acpi_get_timer_resolution"); if (!resolution) { @@ -57,7 +56,6 @@ if (0 == acpi_gbl_FADT->tmr_val_ext) { *resolution = 24; } - else { *resolution = 32; } @@ -82,17 +80,19 @@ acpi_get_timer ( u32 *ticks) { - FUNCTION_TRACE ("Acpi_get_timer"); + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Acpi_get_timer"); if (!ticks) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_os_read_port ((ACPI_IO_ADDRESS) - ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address), ticks, 32); + status = acpi_hw_low_level_read (32, ticks, &acpi_gbl_FADT->Xpm_tmr_blk, 0); - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } @@ -129,13 +129,12 @@ u32 *time_elapsed) { u32 delta_ticks = 0; - u32 seconds = 0; - u32 milliseconds = 0; - u32 microseconds = 0; - u32 remainder = 0; + uint64_overlay normalized_ticks; + acpi_status status; + acpi_integer out_quotient; - FUNCTION_TRACE ("Acpi_get_timer_duration"); + ACPI_FUNCTION_TRACE ("Acpi_get_timer_duration"); if (!time_elapsed) { @@ -150,21 +149,18 @@ if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } - else if (start_ticks > end_ticks) { - /* 24-bit Timer */ - if (0 == acpi_gbl_FADT->tmr_val_ext) { + /* 24-bit Timer */ + delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF); } - - /* 32-bit Timer */ - else { + /* 32-bit Timer */ + delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; } } - else { *time_elapsed = 0; return_ACPI_STATUS (AE_OK); @@ -173,49 +169,18 @@ /* * Compute Duration: * ----------------- - * Since certain compilers (gcc/Linux, argh!) don't support 64-bit - * divides in kernel-space we have to do some trickery to preserve - * accuracy while using 32-bit math. - * - * TBD: Change to use 64-bit math when supported. * - * The process is as follows: - * 1. Compute the number of seconds by dividing Delta Ticks by - * the timer frequency. - * 2. Compute the number of milliseconds in the remainder from step #1 - * by multiplying by 1000 and then dividing by the timer frequency. - * 3. Compute the number of microseconds in the remainder from step #2 - * by multiplying by 1000 and then dividing by the timer frequency. - * 4. Add the results from steps 1, 2, and 3 to get the total duration. + * Requires a 64-bit divide: * - * Example: The time elapsed for Delta_ticks = 0xFFFFFFFF should be - * 1199864031 microseconds. This is computed as follows: - * Step #1: Seconds = 1199; Remainder = 3092840 - * Step #2: Milliseconds = 864; Remainder = 113120 - * Step #3: Microseconds = 31; Remainder = + * Time_elapsed = (Delta_ticks * 1000000) / PM_TIMER_FREQUENCY; */ + normalized_ticks.full = ((u64) delta_ticks) * 1000000; - /* Step #1 */ - - seconds = delta_ticks / PM_TIMER_FREQUENCY; - remainder = delta_ticks % PM_TIMER_FREQUENCY; - - /* Step #2 */ - - milliseconds = (remainder * 1000) / PM_TIMER_FREQUENCY; - remainder = (remainder * 1000) % PM_TIMER_FREQUENCY; + status = acpi_ut_short_divide (&normalized_ticks.full, PM_TIMER_FREQUENCY, + &out_quotient, NULL); - /* Step #3 */ - - microseconds = (remainder * 1000) / PM_TIMER_FREQUENCY; - - /* Step #4 */ - - *time_elapsed = seconds * 1000000; - *time_elapsed += milliseconds * 1000; - *time_elapsed += microseconds; - - return_ACPI_STATUS (AE_OK); + *time_elapsed = (u32) out_quotient; + return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/include/acconfig.h linux-2.4.19-sgi211r3/drivers/acpi/include/acconfig.h --- linux-2.4.19/drivers/acpi/include/acconfig.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acconfig.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acconfig.h - Global configuration constants - * $Revision: 74 $ + * $Revision: 102 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,12 +34,13 @@ *****************************************************************************/ /* - * ACPI_DEBUG - This switch enables all the debug facilities of the ACPI - * subsystem. This includes the DEBUG_PRINT output statements - * When disabled, all DEBUG_PRINT statements are compiled out. + * ACPI_DEBUG - This switch enables all the debug facilities of the + * ACPI subsystem. This includes the DEBUG_PRINT output + * statements. When disabled, all DEBUG_PRINT + * statements are compiled out. * * ACPI_APPLICATION - Use this switch if the subsystem is going to be run - * at the application level. + * at the application level. * */ @@ -53,43 +54,44 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20011018 +#define ACPI_CA_VERSION 0x20020517 /* Version of ACPI supported */ #define ACPI_CA_SUPPORT_LEVEL 2 - /* Maximum objects in the various object caches */ -#define MAX_STATE_CACHE_DEPTH 64 /* State objects for stacks */ +#define MAX_STATE_CACHE_DEPTH 64 /* State objects for stacks */ #define MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ #define MAX_EXTPARSE_CACHE_DEPTH 64 /* Parse tree objects */ #define MAX_OBJECT_CACHE_DEPTH 64 /* Interpreter operand objects */ -#define MAX_WALK_CACHE_DEPTH 4 /* Objects for parse tree walks (method execution) */ - +#define MAX_WALK_CACHE_DEPTH 4 /* Objects for parse tree walks */ /* String size constants */ #define MAX_STRING_LENGTH 512 -#define PATHNAME_MAX 256 /* A full namespace pathname */ - +#define PATHNAME_MAX 256 /* A full namespace pathname */ /* Maximum count for a semaphore object */ #define MAX_SEMAPHORE_COUNT 256 - /* Max reference count (for debug only) */ #define MAX_REFERENCE_COUNT 0x400 - /* Size of cached memory mapping for system memory operation region */ #define SYSMEM_REGION_WINDOW_SIZE 4096 +/****************************************************************************** + * + * Configuration of subsystem behavior + * + *****************************************************************************/ + /* * Debugger threading model * Use single threaded if the entire subsystem is contained in an application @@ -98,7 +100,6 @@ * By default the model is single threaded if ACPI_APPLICATION is set, * multi-threaded if ACPI_APPLICATION is not set. */ - #define DEBUGGER_SINGLE_THREADED 0 #define DEBUGGER_MULTI_THREADED 1 @@ -109,6 +110,12 @@ #define DEBUGGER_THREADING DEBUGGER_MULTI_THREADED #endif +/* + * Should the subystem abort the loading of an ACPI table if the + * table checksum is incorrect? + */ +#define ACPI_CHECKSUM_ABORT FALSE + /****************************************************************************** * @@ -116,10 +123,13 @@ * *****************************************************************************/ +/* Number of distinct GPE register blocks */ + +#define ACPI_MAX_GPE_BLOCKS 2 + /* * Method info (in WALK_STATE), containing local variables and argumetns */ - #define MTH_NUM_LOCALS 8 #define MTH_MAX_LOCAL 7 @@ -133,17 +143,15 @@ /* * Operand Stack (in WALK_STATE), Must be large enough to contain MTH_MAX_ARG */ - #define OBJ_NUM_OPERANDS 8 #define OBJ_MAX_OPERAND 7 /* Names within the namespace are 4 bytes long */ #define ACPI_NAME_SIZE 4 -#define PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 s8 for separator */ +#define PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ #define PATH_SEPARATOR '.' - /* Constants used in searching for the RSDP in low memory */ #define LO_RSDP_WINDOW_BASE 0 /* Physical Address */ @@ -152,10 +160,32 @@ #define HI_RSDP_WINDOW_SIZE 0x20000 #define RSDP_SCAN_STEP 16 +/* Operation regions */ + +#define ACPI_NUM_PREDEFINED_REGIONS 8 +#define ACPI_USER_REGION_BEGIN 0x80 + /* Maximum Space_ids for Operation Regions */ #define ACPI_MAX_ADDRESS_SPACE 255 -#define ACPI_NUM_ADDRESS_SPACES 256 + +/* RSDP checksums */ + +#define ACPI_RSDP_CHECKSUM_LENGTH 20 +#define ACPI_RSDP_XCHECKSUM_LENGTH 36 + + +/****************************************************************************** + * + * ACPI AML Debugger + * + *****************************************************************************/ + + +#define ACPI_DEBUGGER_MAX_ARGS 8 /* Must be max method args + 1 */ + +#define ACPI_DEBUGGER_COMMAND_PROMPT '-' +#define ACPI_DEBUGGER_EXECUTE_PROMPT '%' #endif /* _ACCONFIG_H */ diff -Nur linux-2.4.19/drivers/acpi/include/acdebug.h linux-2.4.19-sgi211r3/drivers/acpi/include/acdebug.h --- linux-2.4.19/drivers/acpi/include/acdebug.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acdebug.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acdebug.h - ACPI/AML debugger - * $Revision: 50 $ + * $Revision: 61 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,61 +27,8 @@ #define __ACDEBUG_H__ -#define DB_MAX_ARGS 8 /* Must be max method args + 1 */ - -#define DB_COMMAND_PROMPT '-' -#define DB_EXECUTE_PROMPT '%' - - -extern int optind; -extern NATIVE_CHAR *optarg; -extern u8 *aml_start; -extern u32 aml_length; - -extern u8 acpi_gbl_db_opt_tables; -extern u8 acpi_gbl_db_opt_disasm; -extern u8 acpi_gbl_db_opt_stats; -extern u8 acpi_gbl_db_opt_parse_jit; -extern u8 acpi_gbl_db_opt_verbose; -extern u8 acpi_gbl_db_opt_ini_methods; - - -extern NATIVE_CHAR *acpi_gbl_db_args[DB_MAX_ARGS]; -extern NATIVE_CHAR acpi_gbl_db_line_buf[80]; -extern NATIVE_CHAR acpi_gbl_db_scope_buf[40]; -extern NATIVE_CHAR acpi_gbl_db_debug_filename[40]; -extern u8 acpi_gbl_db_output_to_file; -extern NATIVE_CHAR *acpi_gbl_db_buffer; -extern NATIVE_CHAR *acpi_gbl_db_filename; -extern NATIVE_CHAR *acpi_gbl_db_disasm_indent; -extern u8 acpi_gbl_db_output_flags; -extern u32 acpi_gbl_db_debug_level; -extern u32 acpi_gbl_db_console_debug_level; -extern acpi_table_header *acpi_gbl_db_table_ptr; - -/* - * Statistic globals - */ -extern u16 acpi_gbl_obj_type_count[INTERNAL_TYPE_NODE_MAX+1]; -extern u16 acpi_gbl_node_type_count[INTERNAL_TYPE_NODE_MAX+1]; -extern u16 acpi_gbl_obj_type_count_misc; -extern u16 acpi_gbl_node_type_count_misc; -extern u32 acpi_gbl_num_nodes; -extern u32 acpi_gbl_num_objects; - - -extern u32 acpi_gbl_size_of_parse_tree; -extern u32 acpi_gbl_size_of_method_trees; -extern u32 acpi_gbl_size_of_node_entries; -extern u32 acpi_gbl_size_of_acpi_objects; - - #define ACPI_DEBUG_BUFFER_SIZE 4196 -#define DB_REDIRECTABLE_OUTPUT 0x01 -#define DB_CONSOLE_OUTPUT 0x02 -#define DB_DUPLICATE_OUTPUT 0x03 - typedef struct command_info { @@ -116,7 +63,7 @@ * dbapi - external debugger interfaces */ -int +acpi_status acpi_db_initialize ( void); @@ -135,7 +82,6 @@ * dbcmds - debug commands and output routines */ - void acpi_db_display_table_info ( NATIVE_CHAR *table_arg); @@ -206,6 +152,38 @@ acpi_db_display_resources ( NATIVE_CHAR *object_arg); +void +acpi_db_check_integrity ( + void); + +acpi_status +acpi_db_integrity_walk ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value); + +acpi_status +acpi_db_walk_and_match_name ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value); + +acpi_status +acpi_db_walk_for_references ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value); + +acpi_status +acpi_db_walk_for_specific_objects ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value); + /* * dbdisasm - AML disassembler @@ -234,12 +212,20 @@ acpi_db_decode_internal_object ( acpi_operand_object *obj_desc); +u32 +acpi_db_block_type ( + acpi_parse_object *op); + +acpi_status +acpi_ps_display_object_pathname ( + acpi_walk_state *walk_state, + acpi_parse_object *op); + /* * dbdisply - debug display commands */ - void acpi_db_display_method_info ( acpi_parse_object *op); @@ -284,6 +270,14 @@ acpi_operand_object *obj_desc, acpi_walk_state *walk_state); +void +acpi_db_dump_parser_descriptor ( + acpi_parse_object *op); + +void * +acpi_db_get_pointer ( + void *target); + /* * dbexec - debugger control method execution @@ -301,16 +295,36 @@ NATIVE_CHAR *num_loops_arg, NATIVE_CHAR *method_name_arg); +acpi_status +acpi_db_execute_method ( + acpi_db_method_info *info, + acpi_buffer *return_obj); + +void +acpi_db_execute_setup ( + acpi_db_method_info *info); + +u32 +acpi_db_get_outstanding_allocations ( + void); + +void ACPI_SYSTEM_XFACE +acpi_db_method_thread ( + void *context); + /* * dbfileio - Debugger file I/O commands */ -acpi_object_type8 +acpi_object_type acpi_db_match_argument ( NATIVE_CHAR *user_argument, ARGUMENT_INFO *arguments); +acpi_status +ae_local_load_table ( + acpi_table_header *table_ptr); void acpi_db_close_debug_file ( @@ -324,6 +338,9 @@ acpi_db_load_acpi_table ( NATIVE_CHAR *filename); +acpi_status +acpi_db_get_acpi_table ( + NATIVE_CHAR *filename); /* * dbhistry - debugger HISTORY command @@ -351,7 +368,7 @@ acpi_walk_state *walk_state, acpi_parse_object *op); -void +void ACPI_SYSTEM_XFACE acpi_db_execute_thread ( void *context); @@ -360,6 +377,27 @@ NATIVE_CHAR prompt, acpi_parse_object *op); +void +acpi_db_display_help ( + NATIVE_CHAR *help_type); + +NATIVE_CHAR * +acpi_db_get_next_token ( + NATIVE_CHAR *string, + NATIVE_CHAR **next); + +u32 +acpi_db_get_line ( + NATIVE_CHAR *input_buffer); + +u32 +acpi_db_match_command ( + NATIVE_CHAR *user_command); + +void +acpi_db_single_thread ( + void); + /* * dbstats - Generation and display of ACPI table statistics @@ -374,6 +412,21 @@ acpi_status acpi_db_display_statistics ( NATIVE_CHAR *type_arg); + +acpi_status +acpi_db_classify_one_object ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value); + +void +acpi_db_count_namespace_objects ( + void); + +void +acpi_db_enumerate_object ( + acpi_operand_object *obj_desc); /* diff -Nur linux-2.4.19/drivers/acpi/include/acdispat.h linux-2.4.19-sgi211r3/drivers/acpi/include/acdispat.h --- linux-2.4.19/drivers/acpi/include/acdispat.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acdispat.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acdispat.h - dispatcher (parser to interpreter interface) - * $Revision: 45 $ + * $Revision: 54 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,6 +58,13 @@ /* dsopcode - support for late evaluation */ acpi_status +acpi_ds_execute_arguments ( + acpi_namespace_node *node, + acpi_namespace_node *scope_node, + u32 aml_length, + u8 *aml_start); + +acpi_status acpi_ds_get_buffer_field_arguments ( acpi_operand_object *obj_desc); @@ -65,6 +72,43 @@ acpi_ds_get_region_arguments ( acpi_operand_object *rgn_desc); +acpi_status +acpi_ds_get_buffer_arguments ( + acpi_operand_object *obj_desc); + +acpi_status +acpi_ds_get_package_arguments ( + acpi_operand_object *obj_desc); + +acpi_status +acpi_ds_init_buffer_field ( + u16 aml_opcode, + acpi_operand_object *obj_desc, + acpi_operand_object *buffer_desc, + acpi_operand_object *offset_desc, + acpi_operand_object *length_desc, + acpi_operand_object *result_desc); + +acpi_status +acpi_ds_eval_buffer_field_operands ( + acpi_walk_state *walk_state, + acpi_parse_object *op); + +acpi_status +acpi_ds_eval_region_operands ( + acpi_walk_state *walk_state, + acpi_parse_object *op); + +acpi_status +acpi_ds_eval_data_object_operands ( + acpi_walk_state *walk_state, + acpi_parse_object *op, + acpi_operand_object *obj_desc); + +acpi_status +acpi_ds_initialize_region ( + acpi_handle obj_handle); + /* dsctrl - Parser/Interpreter interface, control stack routines */ @@ -86,7 +130,7 @@ acpi_status acpi_ds_get_predicate_value ( acpi_walk_state *walk_state, - u32 has_result_obj); + acpi_operand_object *result_obj); acpi_status acpi_ds_exec_begin_op ( @@ -101,6 +145,12 @@ /* dsfield - Parser/Interpreter interface for AML fields */ acpi_status +acpi_ds_get_field_names ( + ACPI_CREATE_FIELD_INFO *info, + acpi_walk_state *walk_state, + acpi_parse_object *arg); + +acpi_status acpi_ds_create_field ( acpi_parse_object *op, acpi_namespace_node *region_node, @@ -123,6 +173,11 @@ acpi_parse_object *op, acpi_walk_state *walk_state); +acpi_status +acpi_ds_init_field_objects ( + acpi_parse_object *op, + acpi_walk_state *walk_state); + /* dsload - Parser/Interpreter interface, namespace load callbacks */ @@ -167,7 +222,7 @@ acpi_walk_state *walk_state, acpi_operand_object ***node); -acpi_status +void acpi_ds_method_data_delete_all ( acpi_walk_state *walk_state); @@ -175,7 +230,7 @@ acpi_ds_is_method_value ( acpi_operand_object *obj_desc); -acpi_object_type8 +acpi_object_type acpi_ds_method_data_get_type ( u16 opcode, u32 index, @@ -188,7 +243,7 @@ acpi_walk_state *walk_state, acpi_operand_object **dest_desc); -acpi_status +void acpi_ds_method_data_delete_value ( u16 opcode, u32 index, @@ -200,18 +255,19 @@ u32 max_param_count, acpi_walk_state *walk_state); -acpi_namespace_node * +acpi_status acpi_ds_method_data_get_node ( u16 opcode, u32 index, - acpi_walk_state *walk_state); + acpi_walk_state *walk_state, + acpi_namespace_node **node); -acpi_status +void acpi_ds_method_data_init ( acpi_walk_state *walk_state); acpi_status -acpi_ds_method_data_set_entry ( +acpi_ds_method_data_set_value ( u16 opcode, u32 index, acpi_operand_object *object, @@ -226,7 +282,7 @@ acpi_status acpi_ds_call_control_method ( - acpi_walk_list *walk_list, + ACPI_THREAD_STATE *thread, acpi_walk_state *walk_state, acpi_parse_object *op); @@ -261,9 +317,17 @@ acpi_namespace_node *start_node); acpi_status +acpi_ds_build_internal_buffer_obj ( + acpi_walk_state *walk_state, + acpi_parse_object *op, + u32 buffer_length, + acpi_operand_object **obj_desc_ptr); + +acpi_status acpi_ds_build_internal_package_obj ( acpi_walk_state *walk_state, acpi_parse_object *op, + u32 package_length, acpi_operand_object **obj_desc); acpi_status @@ -286,23 +350,6 @@ acpi_parse_object *op); -/* dsregn - Parser/Interpreter interface - Op Region parsing */ - -acpi_status -acpi_ds_eval_buffer_field_operands ( - acpi_walk_state *walk_state, - acpi_parse_object *op); - -acpi_status -acpi_ds_eval_region_operands ( - acpi_walk_state *walk_state, - acpi_parse_object *op); - -acpi_status -acpi_ds_initialize_region ( - acpi_handle obj_handle); - - /* dsutils - Parser/Interpreter interface utility routines */ u8 @@ -331,15 +378,6 @@ acpi_ds_resolve_operands ( acpi_walk_state *walk_state); -acpi_object_type8 -acpi_ds_map_opcode_to_data_type ( - u16 opcode, - u32 *out_flags); - -acpi_object_type8 -acpi_ds_map_named_opcode_to_data_type ( - u16 opcode); - /* * dswscope - Scope Stack manipulation @@ -348,7 +386,7 @@ acpi_status acpi_ds_scope_stack_push ( acpi_namespace_node *node, - acpi_object_type8 type, + acpi_object_type type, acpi_walk_state *walk_state); @@ -368,7 +406,7 @@ acpi_owner_id owner_id, acpi_parse_object *origin, acpi_operand_object *mth_desc, - acpi_walk_list *walk_list); + ACPI_THREAD_STATE *thread); acpi_status acpi_ds_init_aml_walk ( @@ -396,12 +434,12 @@ acpi_walk_state * acpi_ds_pop_walk_state ( - acpi_walk_list *walk_list); + ACPI_THREAD_STATE *thread); void acpi_ds_push_walk_state ( acpi_walk_state *walk_state, - acpi_walk_list *walk_list); + ACPI_THREAD_STATE *thread); acpi_status acpi_ds_result_stack_pop ( @@ -417,7 +455,7 @@ acpi_walk_state * acpi_ds_get_current_walk_state ( - acpi_walk_list *walk_list); + ACPI_THREAD_STATE *thread); void acpi_ds_delete_walk_state_cache ( diff -Nur linux-2.4.19/drivers/acpi/include/acevents.h linux-2.4.19-sgi211r3/drivers/acpi/include/acevents.h --- linux-2.4.19/drivers/acpi/include/acevents.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acevents.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acevents.h - Event subcomponent prototypes and defines - * $Revision: 66 $ + * $Revision: 79 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,9 +31,13 @@ acpi_ev_initialize ( void); +acpi_status +acpi_ev_handler_initialize ( + void); + /* - * Acpi_evfixed - Fixed event handling + * Evfixed - Fixed event handling */ acpi_status @@ -46,18 +50,22 @@ u32 acpi_ev_fixed_event_dispatch ( - u32 acpi_event); + u32 event); /* - * Acpi_evglock - Global Lock support + * Evmisc */ +u8 +acpi_ev_is_notify_object ( + acpi_namespace_node *node); + acpi_status acpi_ev_acquire_global_lock( - void); + u32 timeout); -void +acpi_status acpi_ev_release_global_lock( void); @@ -65,9 +73,26 @@ acpi_ev_init_global_lock_handler ( void); +u32 +acpi_ev_get_gpe_register_index ( + u32 gpe_number); + +u32 +acpi_ev_get_gpe_number_index ( + u32 gpe_number); + +acpi_status +acpi_ev_queue_notify_request ( + acpi_namespace_node *node, + u32 notify_value); + +void ACPI_SYSTEM_XFACE +acpi_ev_notify_dispatch ( + void *context); + /* - * Acpi_evgpe - GPE handling and dispatch + * Evgpe - GPE handling and dispatch */ acpi_status @@ -86,26 +111,12 @@ acpi_ev_gpe_detect ( void); - /* - * Acpi_evnotify - Device Notify handling and dispatch + * Evregion - Address Space handling */ acpi_status -acpi_ev_queue_notify_request ( - acpi_namespace_node *node, - u32 notify_value); - -void -acpi_ev_notify_dispatch ( - void *context); - -/* - * Acpi_evregion - Address Space handling - */ - -acpi_status -acpi_ev_install_default_address_space_handlers ( +acpi_ev_init_address_spaces ( void); acpi_status @@ -114,8 +125,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value); - + void *value); acpi_status acpi_ev_addr_handler_helper ( @@ -124,21 +134,20 @@ void *context, void **return_value); -void -acpi_ev_disassociate_region_from_handler( - acpi_operand_object *region_obj, - u8 acpi_ns_is_locked); - - acpi_status -acpi_ev_associate_region_and_handler ( +acpi_ev_attach_region ( acpi_operand_object *handler_obj, acpi_operand_object *region_obj, u8 acpi_ns_is_locked); +void +acpi_ev_detach_region ( + acpi_operand_object *region_obj, + u8 acpi_ns_is_locked); + /* - * Acpi_evregini - Region initialization and setup + * Evregini - Region initialization and setup */ acpi_status @@ -204,10 +213,6 @@ u32 acpi_ev_initialize_sCI ( u32 program_sCI); - -void -acpi_ev_restore_acpi_state ( - void); void acpi_ev_terminate ( diff -Nur linux-2.4.19/drivers/acpi/include/acexcep.h linux-2.4.19-sgi211r3/drivers/acpi/include/acexcep.h --- linux-2.4.19/drivers/acpi/include/acexcep.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acexcep.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acexcep.h - Exception codes returned by the ACPI subsystem - * $Revision: 50 $ + * $Revision: 63 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,7 +54,7 @@ #define AE_NO_MEMORY (acpi_status) (0x0004 | AE_CODE_ENVIRONMENTAL) #define AE_NOT_FOUND (acpi_status) (0x0005 | AE_CODE_ENVIRONMENTAL) #define AE_NOT_EXIST (acpi_status) (0x0006 | AE_CODE_ENVIRONMENTAL) -#define AE_EXIST (acpi_status) (0x0007 | AE_CODE_ENVIRONMENTAL) +#define AE_ALREADY_EXISTS (acpi_status) (0x0007 | AE_CODE_ENVIRONMENTAL) #define AE_TYPE (acpi_status) (0x0008 | AE_CODE_ENVIRONMENTAL) #define AE_NULL_OBJECT (acpi_status) (0x0009 | AE_CODE_ENVIRONMENTAL) #define AE_NULL_ENTRY (acpi_status) (0x000A | AE_CODE_ENVIRONMENTAL) @@ -74,8 +74,9 @@ #define AE_ALREADY_ACQUIRED (acpi_status) (0x0018 | AE_CODE_ENVIRONMENTAL) #define AE_NO_HARDWARE_RESPONSE (acpi_status) (0x0019 | AE_CODE_ENVIRONMENTAL) #define AE_NO_GLOBAL_LOCK (acpi_status) (0x001A | AE_CODE_ENVIRONMENTAL) +#define AE_LOGICAL_ADDRESS (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL) -#define AE_CODE_ENV_MAX 0x001A +#define AE_CODE_ENV_MAX 0x001B /* * Programmer exceptions @@ -85,8 +86,12 @@ #define AE_BAD_PATHNAME (acpi_status) (0x0003 | AE_CODE_PROGRAMMER) #define AE_BAD_DATA (acpi_status) (0x0004 | AE_CODE_PROGRAMMER) #define AE_BAD_ADDRESS (acpi_status) (0x0005 | AE_CODE_PROGRAMMER) +#define AE_ALIGNMENT (acpi_status) (0x0006 | AE_CODE_PROGRAMMER) +#define AE_BAD_HEX_CONSTANT (acpi_status) (0x0007 | AE_CODE_PROGRAMMER) +#define AE_BAD_OCTAL_CONSTANT (acpi_status) (0x0008 | AE_CODE_PROGRAMMER) +#define AE_BAD_DECIMAL_CONSTANT (acpi_status) (0x0009 | AE_CODE_PROGRAMMER) -#define AE_CODE_PGM_MAX 0x0005 +#define AE_CODE_PGM_MAX 0x0009 /* @@ -96,8 +101,10 @@ #define AE_BAD_HEADER (acpi_status) (0x0002 | AE_CODE_ACPI_TABLES) #define AE_BAD_CHECKSUM (acpi_status) (0x0003 | AE_CODE_ACPI_TABLES) #define AE_BAD_VALUE (acpi_status) (0x0004 | AE_CODE_ACPI_TABLES) +#define AE_TABLE_NOT_SUPPORTED (acpi_status) (0x0005 | AE_CODE_ACPI_TABLES) +#define AE_INVALID_TABLE_LENGTH (acpi_status) (0x0006 | AE_CODE_ACPI_TABLES) -#define AE_CODE_TBL_MAX 0x0003 +#define AE_CODE_TBL_MAX 0x0006 /* @@ -129,8 +136,14 @@ #define AE_AML_MUTEX_ORDER (acpi_status) (0x0017 | AE_CODE_AML) #define AE_AML_MUTEX_NOT_ACQUIRED (acpi_status) (0x0018 | AE_CODE_AML) #define AE_AML_INVALID_RESOURCE_TYPE (acpi_status) (0x0019 | AE_CODE_AML) +#define AE_AML_INVALID_INDEX (acpi_status) (0x001A | AE_CODE_AML) +#define AE_AML_REGISTER_LIMIT (acpi_status) (0x001B | AE_CODE_AML) +#define AE_AML_NO_WHILE (acpi_status) (0x001C | AE_CODE_AML) +#define AE_AML_ALIGNMENT (acpi_status) (0x001D | AE_CODE_AML) +#define AE_AML_NO_RESOURCE_END_TAG (acpi_status) (0x001E | AE_CODE_AML) +#define AE_AML_BAD_RESOURCE_VALUE (acpi_status) (0x001F | AE_CODE_AML) -#define AE_CODE_AML_MAX 0x0019 +#define AE_CODE_AML_MAX 0x001F /* * Internal exceptions used for control @@ -143,8 +156,10 @@ #define AE_CTRL_DEPTH (acpi_status) (0x0006 | AE_CODE_CONTROL) #define AE_CTRL_END (acpi_status) (0x0007 | AE_CODE_CONTROL) #define AE_CTRL_TRANSFER (acpi_status) (0x0008 | AE_CODE_CONTROL) +#define AE_CTRL_BREAK (acpi_status) (0x0009 | AE_CODE_CONTROL) +#define AE_CTRL_CONTINUE (acpi_status) (0x000A | AE_CODE_CONTROL) -#define AE_CODE_CTRL_MAX 0x0008 +#define AE_CODE_CTRL_MAX 0x000A #ifdef DEFINE_ACPI_GLOBALS @@ -162,7 +177,7 @@ "AE_NO_MEMORY", "AE_NOT_FOUND", "AE_NOT_EXIST", - "AE_EXIST", + "AE_ALREADY_EXISTS", "AE_TYPE", "AE_NULL_OBJECT", "AE_NULL_ENTRY", @@ -182,6 +197,7 @@ "AE_ALREADY_ACQUIRED", "AE_NO_HARDWARE_RESPONSE", "AE_NO_GLOBAL_LOCK", + "AE_LOGICAL_ADDRESS" }; NATIVE_CHAR const *acpi_gbl_exception_names_pgm[] = @@ -191,6 +207,10 @@ "AE_BAD_PATHNAME", "AE_BAD_DATA", "AE_BAD_ADDRESS", + "AE_ALIGNMENT", + "AE_BAD_HEX_CONSTANT", + "AE_BAD_OCTAL_CONSTANT", + "AE_BAD_DECIMAL_CONSTANT" }; NATIVE_CHAR const *acpi_gbl_exception_names_tbl[] = @@ -199,6 +219,8 @@ "AE_BAD_HEADER", "AE_BAD_CHECKSUM", "AE_BAD_VALUE", + "AE_TABLE_NOT_SUPPORTED", + "AE_INVALID_TABLE_LENGTH" }; NATIVE_CHAR const *acpi_gbl_exception_names_aml[] = @@ -228,6 +250,12 @@ "AE_AML_MUTEX_ORDER", "AE_AML_MUTEX_NOT_ACQUIRED", "AE_AML_INVALID_RESOURCE_TYPE", + "AE_AML_INVALID_INDEX", + "AE_AML_REGISTER_LIMIT", + "AE_AML_NO_WHILE", + "AE_AML_ALIGNMENT", + "AE_AML_NO_RESOURCE_END_TAG", + "AE_AML_BAD_RESOURCE_VALUE" }; NATIVE_CHAR const *acpi_gbl_exception_names_ctrl[] = @@ -240,6 +268,8 @@ "AE_CTRL_DEPTH", "AE_CTRL_END", "AE_CTRL_TRANSFER", + "AE_CTRL_BREAK", + "AE_CTRL_CONTINUE" }; #endif /* ACPI GLOBALS */ diff -Nur linux-2.4.19/drivers/acpi/include/acglobal.h linux-2.4.19-sgi211r3/drivers/acpi/include/acglobal.h --- linux-2.4.19/drivers/acpi/include/acglobal.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acglobal.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acglobal.h - Declarations for global variables - * $Revision: 106 $ + * $Revision: 125 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -71,11 +71,21 @@ * of each in the system. Each global points to the actual table. * */ -ACPI_EXTERN RSDP_DESCRIPTOR *acpi_gbl_RSDP; -ACPI_EXTERN xsdt_descriptor *acpi_gbl_XSDT; -ACPI_EXTERN FADT_DESCRIPTOR *acpi_gbl_FADT; -ACPI_EXTERN acpi_table_header *acpi_gbl_DSDT; -ACPI_EXTERN acpi_common_facs *acpi_gbl_FACS; +ACPI_EXTERN u32 acpi_gbl_table_flags; +ACPI_EXTERN RSDP_DESCRIPTOR *acpi_gbl_RSDP; +ACPI_EXTERN xsdt_descriptor *acpi_gbl_XSDT; +ACPI_EXTERN FADT_DESCRIPTOR *acpi_gbl_FADT; +ACPI_EXTERN acpi_table_header *acpi_gbl_DSDT; +ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS; +ACPI_EXTERN acpi_common_facs acpi_gbl_common_fACS; + +/* + * Handle both ACPI 1.0 and ACPI 2.0 Integer widths + * If we are running a method that exists in a 32-bit ACPI table. + * Use only 32 bits of the Integer for conversion. + */ +ACPI_EXTERN u8 acpi_gbl_integer_bit_width; +ACPI_EXTERN u8 acpi_gbl_integer_byte_width; /* * Since there may be multiple SSDTs and PSDTS, a single pointer is not @@ -107,22 +117,19 @@ ACPI_EXTERN ACPI_MEMORY_LIST acpi_gbl_memory_lists[ACPI_NUM_MEM_LISTS]; ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_drv_notify; ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_sys_notify; -ACPI_EXTERN u8 *acpi_gbl_gpe0enable_register_save; -ACPI_EXTERN u8 *acpi_gbl_gpe1_enable_register_save; +ACPI_EXTERN ACPI_INIT_HANDLER acpi_gbl_init_handler; ACPI_EXTERN acpi_walk_state *acpi_gbl_breakpoint_walk; ACPI_EXTERN acpi_handle acpi_gbl_global_lock_semaphore; ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count; -ACPI_EXTERN u32 acpi_gbl_restore_acpi_chipset; ACPI_EXTERN u32 acpi_gbl_original_mode; -ACPI_EXTERN u32 acpi_gbl_edge_level_save; -ACPI_EXTERN u32 acpi_gbl_irq_enable_save; ACPI_EXTERN u32 acpi_gbl_rsdp_original_location; ACPI_EXTERN u32 acpi_gbl_ns_lookup_count; ACPI_EXTERN u32 acpi_gbl_ps_find_count; ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save; ACPI_EXTERN u16 acpi_gbl_next_table_owner_id; ACPI_EXTERN u16 acpi_gbl_next_method_owner_id; +ACPI_EXTERN u16 acpi_gbl_global_lock_handle; ACPI_EXTERN u8 acpi_gbl_debugger_configuration; ACPI_EXTERN u8 acpi_gbl_global_lock_acquired; ACPI_EXTERN u8 acpi_gbl_step_to_next_call; @@ -130,10 +137,10 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_present; extern u8 acpi_gbl_shutdown; -extern u32 acpi_gbl_system_flags; extern u32 acpi_gbl_startup_flags; extern const u8 acpi_gbl_decode_to8bit[8]; extern const NATIVE_CHAR *acpi_gbl_db_sleep_states[ACPI_NUM_SLEEP_STATES]; +extern const acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; /***************************************************************************** @@ -150,14 +157,14 @@ ACPI_EXTERN acpi_namespace_node *acpi_gbl_root_node; extern const u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; -extern const predefined_names acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; +extern const acpi_predefined_names acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; #ifdef ACPI_DEBUG ACPI_EXTERN u32 acpi_gbl_current_node_count; ACPI_EXTERN u32 acpi_gbl_current_node_size; ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count; -ACPI_EXTERN u32 acpi_gbl_entry_stack_pointer; -ACPI_EXTERN u32 acpi_gbl_lowest_stack_pointer; +ACPI_EXTERN ACPI_SIZE acpi_gbl_entry_stack_pointer; +ACPI_EXTERN ACPI_SIZE acpi_gbl_lowest_stack_pointer; ACPI_EXTERN u32 acpi_gbl_deepest_nesting; #endif @@ -168,11 +175,7 @@ ****************************************************************************/ -ACPI_EXTERN acpi_walk_list *acpi_gbl_current_walk_list; - -/* Address Space handlers */ - -ACPI_EXTERN acpi_adr_space_info acpi_gbl_address_spaces[ACPI_NUM_ADDRESS_SPACES]; +ACPI_EXTERN ACPI_THREAD_STATE *acpi_gbl_current_walk_list; /* Control method single step flag */ @@ -187,34 +190,41 @@ ACPI_EXTERN acpi_parse_object *acpi_gbl_parsed_namespace_root; +/***************************************************************************** + * + * Hardware globals + * + ****************************************************************************/ + +extern ACPI_BIT_REGISTER_INFO acpi_gbl_bit_register_info[ACPI_NUM_BITREG]; +ACPI_EXTERN u8 acpi_gbl_sleep_type_a; +ACPI_EXTERN u8 acpi_gbl_sleep_type_b; + /***************************************************************************** * - * Event globals + * Event and GPE globals * ****************************************************************************/ -ACPI_EXTERN acpi_fixed_event_info acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]; +extern acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS]; +ACPI_EXTERN ACPI_FIXED_EVENT_HANDLER acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]; + ACPI_EXTERN acpi_handle acpi_gbl_gpe_obj_handle; ACPI_EXTERN u32 acpi_gbl_gpe_register_count; -ACPI_EXTERN acpi_gpe_registers *acpi_gbl_gpe_registers; -ACPI_EXTERN acpi_gpe_level_info *acpi_gbl_gpe_info; +ACPI_EXTERN u32 acpi_gbl_gpe_number_max; +ACPI_EXTERN ACPI_GPE_REGISTER_INFO *acpi_gbl_gpe_register_info; +ACPI_EXTERN ACPI_GPE_NUMBER_INFO *acpi_gbl_gpe_number_info; +ACPI_EXTERN ACPI_GPE_BLOCK_INFO acpi_gbl_gpe_block_info[ACPI_MAX_GPE_BLOCKS]; /* - * Gpe validation and translation table - * Indexed by the GPE number, returns GPE_INVALID if the GPE is not supported. - * Otherwise, returns a valid index into the global GPE table. + * GPE translation table + * Indexed by the GPE number, returns a valid index into the global GPE tables. * * This table is needed because the GPE numbers supported by block 1 do not * have to be contiguous with the GPE numbers supported by block 0. */ -ACPI_EXTERN u8 acpi_gbl_gpe_valid [ACPI_NUM_GPE]; - -/* Acpi_event counter for debug only */ - -#ifdef ACPI_DEBUG -ACPI_EXTERN u32 acpi_gbl_event_count[ACPI_NUM_FIXED_EVENTS]; -#endif +ACPI_EXTERN ACPI_GPE_INDEX_INFO *acpi_gbl_gpe_number_to_index; /***************************************************************************** @@ -223,10 +233,56 @@ * ****************************************************************************/ + +ACPI_EXTERN u8 acpi_gbl_db_output_flags; + + #ifdef ENABLE_DEBUGGER -ACPI_EXTERN u8 acpi_gbl_method_executing; -ACPI_EXTERN u8 acpi_gbl_db_terminate_threads; -#endif + +extern u8 acpi_gbl_method_executing; +extern u8 acpi_gbl_db_terminate_threads; + +ACPI_EXTERN int optind; +ACPI_EXTERN NATIVE_CHAR *optarg; + +ACPI_EXTERN u8 acpi_gbl_db_opt_tables; +ACPI_EXTERN u8 acpi_gbl_db_opt_disasm; +ACPI_EXTERN u8 acpi_gbl_db_opt_stats; +ACPI_EXTERN u8 acpi_gbl_db_opt_verbose; +ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; + + +ACPI_EXTERN NATIVE_CHAR *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]; +ACPI_EXTERN NATIVE_CHAR acpi_gbl_db_line_buf[80]; +ACPI_EXTERN NATIVE_CHAR acpi_gbl_db_parsed_buf[80]; +ACPI_EXTERN NATIVE_CHAR acpi_gbl_db_scope_buf[40]; +ACPI_EXTERN NATIVE_CHAR acpi_gbl_db_debug_filename[40]; +ACPI_EXTERN u8 acpi_gbl_db_output_to_file; +ACPI_EXTERN NATIVE_CHAR *acpi_gbl_db_buffer; +ACPI_EXTERN NATIVE_CHAR *acpi_gbl_db_filename; +ACPI_EXTERN NATIVE_CHAR *acpi_gbl_db_disasm_indent; +ACPI_EXTERN u32 acpi_gbl_db_debug_level; +ACPI_EXTERN u32 acpi_gbl_db_console_debug_level; +ACPI_EXTERN acpi_table_header *acpi_gbl_db_table_ptr; +ACPI_EXTERN acpi_namespace_node *acpi_gbl_db_scope_node; + +/* + * Statistic globals + */ +ACPI_EXTERN u16 acpi_gbl_obj_type_count[INTERNAL_TYPE_NODE_MAX+1]; +ACPI_EXTERN u16 acpi_gbl_node_type_count[INTERNAL_TYPE_NODE_MAX+1]; +ACPI_EXTERN u16 acpi_gbl_obj_type_count_misc; +ACPI_EXTERN u16 acpi_gbl_node_type_count_misc; +ACPI_EXTERN u32 acpi_gbl_num_nodes; +ACPI_EXTERN u32 acpi_gbl_num_objects; + + +ACPI_EXTERN u32 acpi_gbl_size_of_parse_tree; +ACPI_EXTERN u32 acpi_gbl_size_of_method_trees; +ACPI_EXTERN u32 acpi_gbl_size_of_node_entries; +ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects; + +#endif /* ENABLE_DEBUGGER */ #endif /* __ACGLOBAL_H__ */ diff -Nur linux-2.4.19/drivers/acpi/include/achware.h linux-2.4.19-sgi211r3/drivers/acpi/include/achware.h --- linux-2.4.19/drivers/acpi/include/achware.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/achware.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: achware.h -- hardware specific interfaces - * $Revision: 56 $ + * $Revision: 60 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,50 +60,48 @@ /* Register I/O Prototypes */ +ACPI_BIT_REGISTER_INFO * +acpi_hw_get_bit_register_info ( + u32 register_id); -u32 -acpi_hw_register_bit_access ( - NATIVE_UINT read_write, - u8 use_lock, - u32 register_id, - ... /* DWORD Write Value */); - -u32 +acpi_status acpi_hw_register_read ( u8 use_lock, - u32 register_id); + u32 register_id, + u32 *return_value); -void +acpi_status acpi_hw_register_write ( u8 use_lock, u32 register_id, u32 value); -u32 +acpi_status acpi_hw_low_level_read ( u32 width, + u32 *value, acpi_generic_address *reg, u32 offset); -void +acpi_status acpi_hw_low_level_write ( u32 width, u32 value, acpi_generic_address *reg, u32 offset); -void +acpi_status acpi_hw_clear_acpi_status ( void); -u32 -acpi_hw_get_bit_shift ( - u32 mask); - /* GPE support */ -void +u8 +acpi_hw_get_gpe_bit_mask ( + u32 gpe_number); + +acpi_status acpi_hw_enable_gpe ( u32 gpe_number); @@ -111,7 +109,7 @@ acpi_hw_enable_gpe_for_wakeup ( u32 gpe_number); -void +acpi_status acpi_hw_disable_gpe ( u32 gpe_number); @@ -119,31 +117,22 @@ acpi_hw_disable_gpe_for_wakeup ( u32 gpe_number); -void +acpi_status acpi_hw_clear_gpe ( u32 gpe_number); -void +acpi_status acpi_hw_get_gpe_status ( u32 gpe_number, acpi_event_status *event_status); -void +acpi_status acpi_hw_disable_non_wakeup_gpes ( void); -void +acpi_status acpi_hw_enable_non_wakeup_gpes ( void); - - -/* Sleep Prototypes */ - -acpi_status -acpi_hw_obtain_sleep_type_register_data ( - u8 sleep_state, - u8 *slp_typ_a, - u8 *slp_typ_b); /* ACPI Timer prototypes */ diff -Nur linux-2.4.19/drivers/acpi/include/acinterp.h linux-2.4.19-sgi211r3/drivers/acpi/include/acinterp.h --- linux-2.4.19/drivers/acpi/include/acinterp.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acinterp.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acinterp.h - Interpreter subcomponent prototypes and defines - * $Revision: 116 $ + * $Revision: 137 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,24 +27,7 @@ #define __ACINTERP_H__ -#define WALK_OPERANDS &(walk_state->operands [walk_state->num_operands -1]) - - -/* Interpreter constants */ - -#define AML_END_OF_BLOCK -1 -#define PUSH_PKG_LENGTH 1 -#define DO_NOT_PUSH_PKG_LENGTH 0 - - -#define STACK_TOP 0 -#define STACK_BOTTOM (u32) -1 - -/* Constants for global "When_to_parse_methods" */ - -#define METHOD_PARSE_AT_INIT 0x0 -#define METHOD_PARSE_JUST_IN_TIME 0x1 -#define METHOD_DELETE_AT_COMPLETION 0x2 +#define ACPI_WALK_OPERANDS (&(walk_state->operands [walk_state->num_operands -1])) acpi_status @@ -53,9 +36,14 @@ acpi_operand_object **stack_ptr, acpi_walk_state *walk_state); +acpi_status +acpi_ex_check_object_type ( + acpi_object_type type_needed, + acpi_object_type this_type, + void *object); /* - * amxface - External interpreter interfaces + * exxface - External interpreter interfaces */ acpi_status @@ -70,7 +58,7 @@ /* - * amconvrt - object conversion + * exconvrt - object conversion */ acpi_status @@ -95,13 +83,19 @@ acpi_status acpi_ex_convert_to_target_type ( - acpi_object_type8 destination_type, - acpi_operand_object **obj_desc, + acpi_object_type destination_type, + acpi_operand_object *source_desc, + acpi_operand_object **result_desc, acpi_walk_state *walk_state); +u32 +acpi_ex_convert_to_ascii ( + acpi_integer integer, + u32 base, + u8 *string); /* - * amfield - ACPI AML (p-code) execution - field manipulation + * exfield - ACPI AML (p-code) execution - field manipulation */ acpi_status @@ -117,55 +111,53 @@ u32 buffer_length); acpi_status -acpi_ex_setup_field ( +acpi_ex_setup_region ( acpi_operand_object *obj_desc, - u32 field_byte_offset); + u32 field_datum_byte_offset); acpi_status -acpi_ex_read_field_datum ( +acpi_ex_access_region ( acpi_operand_object *obj_desc, - u32 field_byte_offset, - u32 *value); + u32 field_datum_byte_offset, + acpi_integer *value, + u32 read_write); -acpi_status -acpi_ex_common_access_field ( - u32 mode, +u8 +acpi_ex_register_overflow ( acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length); - + acpi_integer value); acpi_status -acpi_ex_access_index_field ( - u32 mode, +acpi_ex_field_datum_io ( acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length); + u32 field_datum_byte_offset, + acpi_integer *value, + u32 read_write); acpi_status -acpi_ex_access_bank_field ( - u32 mode, +acpi_ex_write_with_update_rule ( acpi_operand_object *obj_desc, - void *buffer, - u32 buffer_length); + acpi_integer mask, + acpi_integer field_value, + u32 field_datum_byte_offset); -acpi_status -acpi_ex_access_region_field ( - u32 mode, - acpi_operand_object *obj_desc, +void +acpi_ex_get_buffer_datum( + acpi_integer *datum, void *buffer, - u32 buffer_length); - + u32 byte_granularity, + u32 offset); -acpi_status -acpi_ex_access_buffer_field ( - u32 mode, - acpi_operand_object *obj_desc, +void +acpi_ex_set_buffer_datum ( + acpi_integer merged_datum, void *buffer, - u32 buffer_length); + u32 byte_granularity, + u32 offset); acpi_status acpi_ex_read_data_from_field ( + acpi_walk_state *walk_state, acpi_operand_object *obj_desc, acpi_operand_object **ret_buffer_desc); @@ -175,7 +167,7 @@ acpi_operand_object *obj_desc); /* - * ammisc - ACPI AML (p-code) execution - specific opcodes + * exmisc - ACPI AML (p-code) execution - specific opcodes */ acpi_status @@ -190,6 +182,12 @@ acpi_ex_opcode_6A_0T_1R ( acpi_walk_state *walk_state); +u8 +acpi_ex_do_match ( + u32 match_op, + acpi_integer package_value, + acpi_integer match_value); + acpi_status acpi_ex_get_object_reference ( acpi_operand_object *obj_desc, @@ -197,6 +195,13 @@ acpi_walk_state *walk_state); acpi_status +acpi_ex_concat_template ( + acpi_operand_object *obj_desc, + acpi_operand_object *obj_desc2, + acpi_operand_object **actual_return_desc, + acpi_walk_state *walk_state); + +acpi_status acpi_ex_do_concatenate ( acpi_operand_object *obj_desc, acpi_operand_object *obj_desc2, @@ -216,15 +221,6 @@ acpi_integer operand1); acpi_status -acpi_ex_load_op ( - acpi_operand_object *rgn_desc, - acpi_operand_object *ddb_handle); - -acpi_status -acpi_ex_unload_table ( - acpi_operand_object *ddb_handle); - -acpi_status acpi_ex_create_mutex ( acpi_walk_state *walk_state); @@ -263,7 +259,33 @@ /* - * ammutex - mutex support + * exconfig - dynamic table load/unload + */ + +acpi_status +acpi_ex_add_table ( + acpi_table_header *table, + acpi_namespace_node *parent_node, + acpi_operand_object **ddb_handle); + +acpi_status +acpi_ex_load_op ( + acpi_operand_object *obj_desc, + acpi_operand_object *target, + acpi_walk_state *walk_state); + +acpi_status +acpi_ex_load_table_op ( + acpi_walk_state *walk_state, + acpi_operand_object **return_desc); + +acpi_status +acpi_ex_unload_table ( + acpi_operand_object *ddb_handle); + + +/* + * exmutex - mutex support */ acpi_status @@ -277,59 +299,37 @@ acpi_operand_object *obj_desc, acpi_walk_state *walk_state); -acpi_status +void acpi_ex_release_all_mutexes ( - acpi_operand_object *mutex_list); + ACPI_THREAD_STATE *thread); void acpi_ex_unlink_mutex ( acpi_operand_object *obj_desc); +void +acpi_ex_link_mutex ( + acpi_operand_object *obj_desc, + ACPI_THREAD_STATE *thread); /* - * amprep - ACPI AML (p-code) execution - prep utilities + * exprep - ACPI AML (p-code) execution - prep utilities */ acpi_status acpi_ex_prep_common_field_object ( acpi_operand_object *obj_desc, u8 field_flags, - u32 field_position, - u32 field_length); - -acpi_status -acpi_ex_prep_region_field_value ( - acpi_namespace_node *node, - acpi_handle region, - u8 field_flags, - u32 field_position, - u32 field_length); - -acpi_status -acpi_ex_prep_bank_field_value ( - acpi_namespace_node *node, - acpi_namespace_node *region_node, - acpi_namespace_node *bank_register_node, - u32 bank_val, - u8 field_flags, - u32 field_position, - u32 field_length); - -acpi_status -acpi_ex_prep_index_field_value ( - acpi_namespace_node *node, - acpi_namespace_node *index_reg, - acpi_namespace_node *data_reg, - u8 field_flags, - u32 field_position, - u32 field_length); + u8 field_attribute, + u32 field_bit_position, + u32 field_bit_length); acpi_status acpi_ex_prep_field_value ( ACPI_CREATE_FIELD_INFO *info); /* - * amsystem - Interface to OS services + * exsystem - Interface to OS services */ acpi_status @@ -337,11 +337,11 @@ acpi_operand_object *value, acpi_operand_object *obj_desc); -void +acpi_status acpi_ex_system_do_suspend( u32 time); -void +acpi_status acpi_ex_system_do_stall ( u32 time); @@ -374,7 +374,7 @@ /* - * ammonadic - ACPI AML (p-code) execution, monadic operators + * exmonadic - ACPI AML (p-code) execution, monadic operators */ acpi_status @@ -394,7 +394,7 @@ acpi_walk_state *walk_state); /* - * amdyadic - ACPI AML (p-code) execution, dyadic operators + * exdyadic - ACPI AML (p-code) execution, dyadic operators */ acpi_status @@ -415,7 +415,7 @@ /* - * amresolv - Object resolution and get value functions + * exresolv - Object resolution and get value functions */ acpi_status @@ -433,31 +433,19 @@ acpi_operand_object **stack_ptr, acpi_walk_state *walk_state); -acpi_status -acpi_ex_get_buffer_field_value ( - acpi_operand_object *field_desc, - acpi_operand_object *result_desc); - /* - * amdump - Scanner debug output routines + * exdump - Scanner debug output routines */ void -acpi_ex_show_hex_value ( - u32 byte_count, - u8 *aml_start, - u32 lead_space); - - -acpi_status acpi_ex_dump_operand ( acpi_operand_object *entry_desc); void acpi_ex_dump_operands ( acpi_operand_object **operands, - operating_mode interpreter_mode, + acpi_interpreter_mode interpreter_mode, NATIVE_CHAR *ident, u32 num_levels, NATIVE_CHAR *note, @@ -469,15 +457,34 @@ acpi_operand_object *object, u32 flags); - void acpi_ex_dump_node ( acpi_namespace_node *node, u32 flags); +void +acpi_ex_out_string ( + char *title, + char *value); + +void +acpi_ex_out_pointer ( + char *title, + void *value); + +void +acpi_ex_out_integer ( + char *title, + u32 value); + +void +acpi_ex_out_address ( + char *title, + ACPI_PHYSICAL_ADDRESS value); + /* - * amnames - interpreter/scanner name load/execute + * exnames - interpreter/scanner name load/execute */ NATIVE_CHAR * @@ -496,7 +503,7 @@ acpi_status acpi_ex_get_name_string ( - acpi_object_type8 data_type, + acpi_object_type data_type, u8 *in_aml_address, NATIVE_CHAR **out_name_string, u32 *out_name_length); @@ -504,11 +511,11 @@ acpi_status acpi_ex_do_name ( acpi_object_type data_type, - operating_mode load_exec_mode); + acpi_interpreter_mode load_exec_mode); /* - * amstore - Object store support + * exstore - Object store support */ acpi_status @@ -529,42 +536,36 @@ acpi_namespace_node *node, acpi_walk_state *walk_state); -acpi_status -acpi_ex_store_object_to_object ( - acpi_operand_object *source_desc, - acpi_operand_object *dest_desc, - acpi_walk_state *walk_state); - /* - * + * exstoren */ acpi_status acpi_ex_resolve_object ( acpi_operand_object **source_desc_ptr, - acpi_object_type8 target_type, + acpi_object_type target_type, acpi_walk_state *walk_state); acpi_status -acpi_ex_store_object ( +acpi_ex_store_object_to_object ( acpi_operand_object *source_desc, - acpi_object_type8 target_type, - acpi_operand_object **target_desc_ptr, + acpi_operand_object *dest_desc, + acpi_operand_object **new_desc, acpi_walk_state *walk_state); /* - * amcopy - object copy + * excopy - object copy */ acpi_status -acpi_ex_copy_buffer_to_buffer ( +acpi_ex_store_buffer_to_buffer ( acpi_operand_object *source_desc, acpi_operand_object *target_desc); acpi_status -acpi_ex_copy_string_to_string ( +acpi_ex_store_string_to_string ( acpi_operand_object *source_desc, acpi_operand_object *target_desc); @@ -589,7 +590,7 @@ acpi_operand_object *target_desc); /* - * amutils - interpreter/scanner utilities + * exutils - interpreter/scanner utilities */ acpi_status @@ -613,7 +614,7 @@ acpi_ex_acquire_global_lock ( u32 rule); -acpi_status +void acpi_ex_release_global_lock ( u8 locked); @@ -622,19 +623,19 @@ acpi_integer value, u32 base); -acpi_status +void acpi_ex_eisa_id_to_string ( u32 numeric_id, NATIVE_CHAR *out_string); -acpi_status +void acpi_ex_unsigned_integer_to_string ( acpi_integer value, NATIVE_CHAR *out_string); /* - * amregion - default Op_region handlers + * exregion - default Op_region handlers */ acpi_status @@ -642,7 +643,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); @@ -651,7 +652,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); @@ -660,7 +661,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); @@ -669,7 +670,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); @@ -678,7 +679,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); @@ -687,7 +688,7 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); @@ -696,9 +697,18 @@ u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); + +acpi_status +acpi_ex_data_table_space_handler ( + u32 function, + ACPI_PHYSICAL_ADDRESS address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context); #endif /* __INTERP_H__ */ diff -Nur linux-2.4.19/drivers/acpi/include/aclocal.h linux-2.4.19-sgi211r3/drivers/acpi/include/aclocal.h --- linux-2.4.19/drivers/acpi/include/aclocal.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/aclocal.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: aclocal.h - Internal data types used across the ACPI subsystem - * $Revision: 138 $ + * $Revision: 167 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,22 +37,9 @@ #define ACPI_LOGICAL_ADDRESSING 0x00 #define ACPI_PHYSICAL_ADDRESSING 0x01 -/* Object descriptor types */ +/* Total number of aml opcodes defined */ -#define ACPI_CACHED_OBJECT 0x11 /* ORed in when object is cached */ -#define ACPI_DESC_TYPE_STATE 0x20 -#define ACPI_DESC_TYPE_STATE_UPDATE 0x21 -#define ACPI_DESC_TYPE_STATE_PACKAGE 0x22 -#define ACPI_DESC_TYPE_STATE_CONTROL 0x23 -#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x24 -#define ACPI_DESC_TYPE_STATE_PSCOPE 0x25 -#define ACPI_DESC_TYPE_STATE_WSCOPE 0x26 -#define ACPI_DESC_TYPE_STATE_RESULT 0x27 -#define ACPI_DESC_TYPE_STATE_NOTIFY 0x28 -#define ACPI_DESC_TYPE_WALK 0x44 -#define ACPI_DESC_TYPE_PARSER 0x66 -#define ACPI_DESC_TYPE_INTERNAL 0x88 -#define ACPI_DESC_TYPE_NAMED 0xAA +#define AML_NUM_OPCODES 0x7E /***************************************************************************** @@ -138,10 +125,10 @@ typedef u16 acpi_owner_id; -#define OWNER_TYPE_TABLE 0x0 -#define OWNER_TYPE_METHOD 0x1 -#define FIRST_METHOD_ID 0x0000 -#define FIRST_TABLE_ID 0x8000 +#define ACPI_OWNER_TYPE_TABLE 0x0 +#define ACPI_OWNER_TYPE_METHOD 0x1 +#define ACPI_FIRST_METHOD_ID 0x0000 +#define ACPI_FIRST_TABLE_ID 0x8000 /* TBD: [Restructure] get rid of the need for this! */ @@ -166,11 +153,11 @@ typedef enum { - IMODE_LOAD_PASS1 = 0x01, - IMODE_LOAD_PASS2 = 0x02, - IMODE_EXECUTE = 0x0E + ACPI_IMODE_LOAD_PASS1 = 0x01, + ACPI_IMODE_LOAD_PASS2 = 0x02, + ACPI_IMODE_EXECUTE = 0x0E -} operating_mode; +} acpi_interpreter_mode; /* @@ -181,12 +168,18 @@ * be the first byte in this structure. */ +typedef union acpi_name_union +{ + u32 integer; + char ascii[4]; +} ACPI_NAME_UNION; + typedef struct acpi_node { - u8 data_type; + u8 descriptor; /* Used to differentiate object descriptor types */ u8 type; /* Type associated with this name */ u16 owner_id; - u32 name; /* ACPI Name, always 4 chars per ACPI spec */ + ACPI_NAME_UNION name; /* ACPI Name, always 4 chars per ACPI spec */ union acpi_operand_obj *object; /* Pointer to attached ACPI object (optional) */ @@ -198,12 +191,12 @@ } acpi_namespace_node; -#define ENTRY_NOT_FOUND NULL +#define ACPI_ENTRY_NOT_FOUND NULL /* Node flags */ -#define ANOBJ_AML_ATTACHMENT 0x01 +#define ANOBJ_RESERVED 0x01 #define ANOBJ_END_OF_PEER_LIST 0x02 #define ANOBJ_DATA_WIDTH_32 0x04 /* Parent table is 64-bits */ #define ANOBJ_METHOD_ARG 0x08 @@ -227,7 +220,7 @@ u8 *aml_start; u64 physical_address; u32 aml_length; - u32 length; + ACPI_SIZE length; u32 count; acpi_owner_id table_id; u8 type; @@ -243,13 +236,13 @@ acpi_handle *list; u32 *count; -} find_context; +} acpi_find_context; typedef struct { acpi_namespace_node *node; -} ns_search_data; +} acpi_ns_search_data; /* @@ -258,10 +251,10 @@ typedef struct { NATIVE_CHAR *name; - acpi_object_type8 type; + u8 type; NATIVE_CHAR *val; -} predefined_names; +} acpi_predefined_names; /* Object types used during package copies */ @@ -297,20 +290,11 @@ u32 field_bit_position; u32 field_bit_length; u8 field_flags; + u8 attribute; u8 field_type; } ACPI_CREATE_FIELD_INFO; -/* - * Field flags: Bits 00 - 03 : Access_type (Any_acc, Byte_acc, etc.) - * 04 : Lock_rule (1 == Lock) - * 05 - 06 : Update_rule - */ - -#define FIELD_ACCESS_TYPE_MASK 0x0F -#define FIELD_LOCK_RULE_MASK 0x10 -#define FIELD_UPDATE_RULE_MASK 0x60 - /***************************************************************************** * @@ -318,49 +302,29 @@ * ****************************************************************************/ - -/* Status bits. */ - -#define ACPI_STATUS_PMTIMER 0x0001 -#define ACPI_STATUS_BUSMASTER 0x0010 -#define ACPI_STATUS_GLOBAL 0x0020 -#define ACPI_STATUS_POWER_BUTTON 0x0100 -#define ACPI_STATUS_SLEEP_BUTTON 0x0200 -#define ACPI_STATUS_RTC_ALARM 0x0400 - -/* Enable bits. */ - -#define ACPI_ENABLE_PMTIMER 0x0001 -#define ACPI_ENABLE_GLOBAL 0x0020 -#define ACPI_ENABLE_POWER_BUTTON 0x0100 -#define ACPI_ENABLE_SLEEP_BUTTON 0x0200 -#define ACPI_ENABLE_RTC_ALARM 0x0400 - - -/* - * Entry in the Address_space (AKA Operation Region) table - */ +/* Information about each GPE register block */ typedef struct { - acpi_adr_space_handler handler; - void *context; + u8 address_space_id; + acpi_generic_address *block_address; + u16 register_count; + u8 block_base_number; -} acpi_adr_space_info; +} ACPI_GPE_BLOCK_INFO; - -/* Values and addresses of the GPE registers (both banks) */ +/* Information about a particular GPE register pair */ typedef struct { - u16 status_addr; /* Address of status reg */ - u16 enable_addr; /* Address of enable reg */ + acpi_generic_address status_address; /* Address of status reg */ + acpi_generic_address enable_address; /* Address of enable reg */ u8 status; /* Current value of status reg */ u8 enable; /* Current value of enable reg */ u8 wake_enable; /* Mask of bits to keep enabled when sleeping */ - u8 gpe_base; /* Base GPE number */ + u8 base_gpe_number; /* Base GPE number for this register */ -} acpi_gpe_registers; +} ACPI_GPE_REGISTER_INFO; #define ACPI_GPE_LEVEL_TRIGGERED 1 @@ -371,15 +335,22 @@ typedef struct { - u8 type; /* Level or Edge */ - acpi_handle method_handle; /* Method handle for direct (fast) execution */ acpi_gpe_handler handler; /* Address of handler, if any */ void *context; /* Context to be passed to handler */ + u8 type; /* Level or Edge */ + u8 bit_mask; + -} acpi_gpe_level_info; +} ACPI_GPE_NUMBER_INFO; +typedef struct +{ + u8 number_index; + +} ACPI_GPE_INDEX_INFO; + /* Information about each particular fixed event */ typedef struct @@ -387,9 +358,18 @@ acpi_event_handler handler; /* Address of handler. */ void *context; /* Context to be passed to handler */ -} acpi_fixed_event_info; +} ACPI_FIXED_EVENT_HANDLER; +typedef struct +{ + u8 status_register_id; + u8 enable_register_id; + u16 status_bit_mask; + u16 enable_bit_mask; + +} acpi_fixed_event_info; + /* Information used during field processing */ typedef struct @@ -408,27 +388,26 @@ ****************************************************************************/ -#define CONTROL_NORMAL 0xC0 -#define CONTROL_CONDITIONAL_EXECUTING 0xC1 -#define CONTROL_PREDICATE_EXECUTING 0xC2 -#define CONTROL_PREDICATE_FALSE 0xC3 -#define CONTROL_PREDICATE_TRUE 0xC4 +#define ACPI_CONTROL_NORMAL 0xC0 +#define ACPI_CONTROL_CONDITIONAL_EXECUTING 0xC1 +#define ACPI_CONTROL_PREDICATE_EXECUTING 0xC2 +#define ACPI_CONTROL_PREDICATE_FALSE 0xC3 +#define ACPI_CONTROL_PREDICATE_TRUE 0xC4 /* Forward declarations */ struct acpi_walk_state; -struct acpi_walk_list; -struct acpi_parse_obj; struct acpi_obj_mutex; +union acpi_parse_obj; #define ACPI_STATE_COMMON /* Two 32-bit fields and a pointer */\ u8 data_type; /* To differentiate various internal objs */\ - u8 flags; \ - u16 value; \ - u16 state; \ - u16 acpi_eval; \ - void *next; \ + u8 flags; \ + u16 value; \ + u16 state; \ + u16 reserved; \ + void *next; \ typedef struct acpi_common_state { @@ -470,8 +449,10 @@ typedef struct acpi_control_state { ACPI_STATE_COMMON - struct acpi_parse_obj *predicate_op; - u8 *aml_predicate_start; /* Start of if/while predicate */ + union acpi_parse_obj *predicate_op; + u8 *aml_predicate_start; /* Start of if/while predicate */ + u8 *package_end; /* End of if/while block */ + u16 opcode; } acpi_control_state; @@ -490,16 +471,31 @@ typedef struct acpi_pscope_state { ACPI_STATE_COMMON - struct acpi_parse_obj *op; /* current op being parsed */ - u8 *arg_end; /* current argument end */ - u8 *pkg_end; /* current package end */ - u32 arg_list; /* next argument to parse */ - u32 arg_count; /* Number of fixed arguments */ + union acpi_parse_obj *op; /* current op being parsed */ + u8 *arg_end; /* current argument end */ + u8 *pkg_end; /* current package end */ + u32 arg_list; /* next argument to parse */ + u32 arg_count; /* Number of fixed arguments */ } acpi_pscope_state; /* + * Thread state - one per thread across multiple walk states. Multiple walk + * states are created when there are nested control methods executing. + */ +typedef struct acpi_thread_state +{ + ACPI_STATE_COMMON + struct acpi_walk_state *walk_state_list; /* Head of list of Walk_states for this thread */ + union acpi_operand_obj *acquired_mutex_list; /* List of all currently acquired mutexes */ + u32 thread_id; /* Running thread ID */ + u16 current_sync_level; /* Mutex Sync (nested acquire) level */ + +} ACPI_THREAD_STATE; + + +/* * Result values - used to accumulate the results of nested * AML arguments */ @@ -516,7 +512,7 @@ typedef acpi_status (*acpi_parse_downwards) ( struct acpi_walk_state *walk_state, - struct acpi_parse_obj **out_op); + union acpi_parse_obj **out_op); typedef acpi_status (*acpi_parse_upwards) ( @@ -546,6 +542,7 @@ acpi_scope_state scope; acpi_pscope_state parse_scope; acpi_pkg_state pkg; + ACPI_THREAD_STATE thread; acpi_result_values results; acpi_notify_info notify; @@ -574,16 +571,16 @@ */ typedef struct acpi_opcode_info { +#ifdef _OPCODE_NAMES + NATIVE_CHAR *name; /* Opcode name (debug only) */ +#endif u32 parse_args; /* Grammar/Parse time arguments */ u32 runtime_args; /* Interpret time arguments */ - u16 flags; /* Misc flags */ + u32 flags; /* Misc flags */ + u8 object_type; /* Corresponding internal object type */ u8 class; /* Opcode class */ u8 type; /* Opcode type */ -#ifdef _OPCODE_NAMES - NATIVE_CHAR *name; /* op name (debug only) */ -#endif - } acpi_opcode_info; @@ -598,7 +595,7 @@ NATIVE_CHAR *string; /* NULL terminated string */ u8 *buffer; /* buffer or string */ NATIVE_CHAR *name; /* NULL terminated string */ - struct acpi_parse_obj *arg; /* arguments and contained ops */ + union acpi_parse_obj *arg; /* arguments and contained ops */ } acpi_parse_value; @@ -606,12 +603,12 @@ #define ACPI_PARSE_COMMON \ u8 data_type; /* To differentiate various internal objs */\ u8 flags; /* Type of Op */\ - u16 opcode; /* AML opcode */\ + u16 aml_opcode; /* AML opcode */\ u32 aml_offset; /* offset of declaration in AML */\ - struct acpi_parse_obj *parent; /* parent op */\ - struct acpi_parse_obj *next; /* next op */\ - DEBUG_ONLY_MEMBERS (\ - NATIVE_CHAR op_name[16]) /* op name (debug only) */\ + union acpi_parse_obj *parent; /* parent op */\ + union acpi_parse_obj *next; /* next op */\ + ACPI_DEBUG_ONLY_MEMBERS (\ + NATIVE_CHAR aml_op_name[16]) /* op name (debug only) */\ /* NON-DEBUG members below: */\ acpi_namespace_node *node; /* for use by interpreter */\ acpi_parse_value value; /* Value or args associated with the opcode */\ @@ -620,24 +617,68 @@ /* * generic operation (eg. If, While, Store) */ -typedef struct acpi_parse_obj +typedef struct acpi_parseobj_common { ACPI_PARSE_COMMON -} acpi_parse_object; +} ACPI_PARSE_OBJ_COMMON; /* * Extended Op for named ops (Scope, Method, etc.), deferred ops (Methods and Op_regions), * and bytelists. */ -typedef struct acpi_parse2_obj +typedef struct acpi_parseobj_named { ACPI_PARSE_COMMON u8 *data; /* AML body or bytelist data */ u32 length; /* AML length */ u32 name; /* 4-byte name or zero if no name */ -} acpi_parse2_object; +} ACPI_PARSE_OBJ_NAMED; + + +/* The parse node is the fundamental element of the parse tree */ + +typedef struct acpi_parseobj_asl +{ + ACPI_PARSE_COMMON + + union acpi_parse_obj *child; + + + union acpi_parse_obj *parent_method; + char *filename; + char *external_name; + char *namepath; + u32 extra_value; + u32 column; + u32 line_number; + u32 logical_line_number; + u32 logical_byte_offset; + u32 end_line; + u32 end_logical_line; + u16 parse_opcode; + u32 acpi_btype; + u32 aml_length; + u32 aml_subtree_length; + u32 final_aml_length; + u32 final_aml_offset; + u8 aml_opcode_length; + u8 aml_pkg_len_bytes; + u16 compile_flags; + u8 extra; + char parse_op_name[12]; + +} ACPI_PARSE_OBJ_ASL; + + +typedef union acpi_parse_obj +{ + ACPI_PARSE_OBJ_COMMON common; + ACPI_PARSE_OBJ_NAMED named; + ACPI_PARSE_OBJ_ASL asl; + +} acpi_parse_object; /* @@ -652,153 +693,111 @@ u8 *aml_end; /* (last + 1) AML byte */ u8 *pkg_start; /* current package begin */ u8 *pkg_end; /* current package end */ - - struct acpi_parse_obj *start_op; /* root of parse tree */ + union acpi_parse_obj *start_op; /* root of parse tree */ struct acpi_node *start_node; union acpi_gen_state *scope; /* current scope */ + union acpi_parse_obj *start_scope; +} acpi_parse_state; - struct acpi_parse_obj *start_scope; +/* Parse object flags */ -} acpi_parse_state; +#define ACPI_PARSEOP_GENERIC 0x01 +#define ACPI_PARSEOP_NAMED 0x02 +#define ACPI_PARSEOP_DEFERRED 0x04 +#define ACPI_PARSEOP_BYTELIST 0x08 +#define ACPI_PARSEOP_IN_CACHE 0x80 /***************************************************************************** * - * Hardware and PNP + * Hardware (ACPI registers) and PNP * ****************************************************************************/ +#define PCI_ROOT_HID_STRING "PNP0A03" -/* PCI */ -#define PCI_ROOT_HID_STRING "PNP0A03" - -/* - * The #define's and enum below establish an abstract way of identifying what - * register block and register is to be accessed. Do not change any of the - * values as they are used in switch statements and offset calculations. - */ - -#define REGISTER_BLOCK_MASK 0xFF00 /* Register Block Id */ -#define BIT_IN_REGISTER_MASK 0x00FF /* Bit Id in the Register Block Id */ -#define BYTE_IN_REGISTER_MASK 0x00FF /* Register Offset in the Register Block */ - -#define REGISTER_BLOCK_ID(reg_id) (reg_id & REGISTER_BLOCK_MASK) -#define REGISTER_BIT_ID(reg_id) (reg_id & BIT_IN_REGISTER_MASK) -#define REGISTER_OFFSET(reg_id) (reg_id & BYTE_IN_REGISTER_MASK) - -/* - * Access Rule - * To access a Register Bit: - * -> Use Bit Name (= Register Block Id | Bit Id) defined in the enum. - * - * To access a Register: - * -> Use Register Id (= Register Block Id | Register Offset) - */ - - -/* - * Register Block Id - */ -#define PM1_STS 0x0100 -#define PM1_EN 0x0200 -#define PM1_CONTROL 0x0300 -#define PM1A_CONTROL 0x0400 -#define PM1B_CONTROL 0x0500 -#define PM2_CONTROL 0x0600 -#define PM_TIMER 0x0700 -#define PROCESSOR_BLOCK 0x0800 -#define GPE0_STS_BLOCK 0x0900 -#define GPE0_EN_BLOCK 0x0A00 -#define GPE1_STS_BLOCK 0x0B00 -#define GPE1_EN_BLOCK 0x0C00 -#define SMI_CMD_BLOCK 0x0D00 +typedef struct +{ + u8 parent_register; + u8 bit_position; + u16 access_bit_mask; -/* - * Address space bitmasks for mmio or io spaces - */ +} ACPI_BIT_REGISTER_INFO; -#define SMI_CMD_ADDRESS_SPACE 0x01 -#define PM1_BLK_ADDRESS_SPACE 0x02 -#define PM2_CNT_BLK_ADDRESS_SPACE 0x04 -#define PM_TMR_BLK_ADDRESS_SPACE 0x08 -#define GPE0_BLK_ADDRESS_SPACE 0x10 -#define GPE1_BLK_ADDRESS_SPACE 0x20 /* - * Control bit definitions + * Register IDs + * These are the full ACPI registers */ -#define TMR_STS (PM1_STS | 0x01) -#define BM_STS (PM1_STS | 0x02) -#define GBL_STS (PM1_STS | 0x03) -#define PWRBTN_STS (PM1_STS | 0x04) -#define SLPBTN_STS (PM1_STS | 0x05) -#define RTC_STS (PM1_STS | 0x06) -#define WAK_STS (PM1_STS | 0x07) - -#define TMR_EN (PM1_EN | 0x01) - /* no BM_EN */ -#define GBL_EN (PM1_EN | 0x03) -#define PWRBTN_EN (PM1_EN | 0x04) -#define SLPBTN_EN (PM1_EN | 0x05) -#define RTC_EN (PM1_EN | 0x06) -#define WAK_EN (PM1_EN | 0x07) - -#define SCI_EN (PM1_CONTROL | 0x01) -#define BM_RLD (PM1_CONTROL | 0x02) -#define GBL_RLS (PM1_CONTROL | 0x03) -#define SLP_TYPE_A (PM1_CONTROL | 0x04) -#define SLP_TYPE_B (PM1_CONTROL | 0x05) -#define SLP_EN (PM1_CONTROL | 0x06) - -#define ARB_DIS (PM2_CONTROL | 0x01) +#define ACPI_REGISTER_PM1_STATUS 0x01 +#define ACPI_REGISTER_PM1_ENABLE 0x02 +#define ACPI_REGISTER_PM1_CONTROL 0x03 +#define ACPI_REGISTER_PM1A_CONTROL 0x04 +#define ACPI_REGISTER_PM1B_CONTROL 0x05 +#define ACPI_REGISTER_PM2_CONTROL 0x06 +#define ACPI_REGISTER_PM_TIMER 0x07 +#define ACPI_REGISTER_PROCESSOR_BLOCK 0x08 +#define ACPI_REGISTER_SMI_COMMAND_BLOCK 0x09 -#define TMR_VAL (PM_TIMER | 0x01) -#define GPE0_STS (GPE0_STS_BLOCK | 0x01) -#define GPE0_EN (GPE0_EN_BLOCK | 0x01) +/* Masks used to access the Bit_registers */ -#define GPE1_STS (GPE1_STS_BLOCK | 0x01) -#define GPE1_EN (GPE1_EN_BLOCK | 0x01) +#define ACPI_BITMASK_TIMER_STATUS 0x0001 +#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 +#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 +#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 +#define ACPI_BITMASK_WAKE_STATUS 0x8000 +#define ACPI_BITMASK_ALL_FIXED_STATUS (ACPI_BITMASK_TIMER_STATUS | \ + ACPI_BITMASK_BUS_MASTER_STATUS | \ + ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ + ACPI_BITMASK_POWER_BUTTON_STATUS | \ + ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ + ACPI_BITMASK_RT_CLOCK_STATUS | \ + ACPI_BITMASK_WAKE_STATUS) -#define TMR_STS_MASK 0x0001 -#define BM_STS_MASK 0x0010 -#define GBL_STS_MASK 0x0020 -#define PWRBTN_STS_MASK 0x0100 -#define SLPBTN_STS_MASK 0x0200 -#define RTC_STS_MASK 0x0400 -#define WAK_STS_MASK 0x8000 +#define ACPI_BITMASK_TIMER_ENABLE 0x0001 +#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200 +#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400 -#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK \ - | PWRBTN_STS_MASK | SLPBTN_STS_MASK \ - | RTC_STS_MASK | WAK_STS_MASK) +#define ACPI_BITMASK_SCI_ENABLE 0x0001 +#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002 +#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004 +#define ACPI_BITMASK_SLEEP_TYPE_X 0x1C00 +#define ACPI_BITMASK_SLEEP_ENABLE 0x2000 -#define TMR_EN_MASK 0x0001 -#define GBL_EN_MASK 0x0020 -#define PWRBTN_EN_MASK 0x0100 -#define SLPBTN_EN_MASK 0x0200 -#define RTC_EN_MASK 0x0400 +#define ACPI_BITMASK_ARB_DISABLE 0x0001 -#define SCI_EN_MASK 0x0001 -#define BM_RLD_MASK 0x0002 -#define GBL_RLS_MASK 0x0004 -#define SLP_TYPE_X_MASK 0x1C00 -#define SLP_EN_MASK 0x2000 -#define ARB_DIS_MASK 0x0001 -#define TMR_VAL_MASK 0xFFFFFFFF +/* Raw bit position of each Bit_register */ -#define GPE0_STS_MASK -#define GPE0_EN_MASK +#define ACPI_BITPOSITION_TIMER_STATUS 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_STATUS 0x04 +#define ACPI_BITPOSITION_GLOBAL_LOCK_STATUS 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_STATUS 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_STATUS 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_STATUS 0x0A +#define ACPI_BITPOSITION_WAKE_STATUS 0x0F -#define GPE1_STS_MASK -#define GPE1_EN_MASK +#define ACPI_BITPOSITION_TIMER_ENABLE 0x00 +#define ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_ENABLE 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_ENABLE 0x0A +#define ACPI_BITPOSITION_SCI_ENABLE 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_RLD 0x01 +#define ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE 0x02 +#define ACPI_BITPOSITION_SLEEP_TYPE_X 0x0A +#define ACPI_BITPOSITION_SLEEP_ENABLE 0x0D -#define ACPI_READ 1 -#define ACPI_WRITE 2 +#define ACPI_BITPOSITION_ARB_DISABLE 0x00 /***************************************************************************** @@ -810,45 +809,45 @@ /* Resource_type values */ -#define RESOURCE_TYPE_MEMORY_RANGE 0 -#define RESOURCE_TYPE_IO_RANGE 1 -#define RESOURCE_TYPE_BUS_NUMBER_RANGE 2 +#define ACPI_RESOURCE_TYPE_MEMORY_RANGE 0 +#define ACPI_RESOURCE_TYPE_IO_RANGE 1 +#define ACPI_RESOURCE_TYPE_BUS_NUMBER_RANGE 2 /* Resource descriptor types and masks */ -#define RESOURCE_DESC_TYPE_LARGE 0x80 -#define RESOURCE_DESC_TYPE_SMALL 0x00 +#define ACPI_RDESC_TYPE_LARGE 0x80 +#define ACPI_RDESC_TYPE_SMALL 0x00 -#define RESOURCE_DESC_TYPE_MASK 0x80 -#define RESOURCE_DESC_SMALL_MASK 0x78 /* Only bits 6:3 contain the type */ +#define ACPI_RDESC_TYPE_MASK 0x80 +#define ACPI_RDESC_SMALL_MASK 0x78 /* Only bits 6:3 contain the type */ /* * Small resource descriptor types * Note: The 3 length bits (2:0) must be zero */ -#define RESOURCE_DESC_IRQ_FORMAT 0x20 -#define RESOURCE_DESC_DMA_FORMAT 0x28 -#define RESOURCE_DESC_START_DEPENDENT 0x30 -#define RESOURCE_DESC_END_DEPENDENT 0x38 -#define RESOURCE_DESC_IO_PORT 0x40 -#define RESOURCE_DESC_FIXED_IO_PORT 0x48 -#define RESOURCE_DESC_SMALL_VENDOR 0x70 -#define RESOURCE_DESC_END_TAG 0x78 +#define ACPI_RDESC_TYPE_IRQ_FORMAT 0x20 +#define ACPI_RDESC_TYPE_DMA_FORMAT 0x28 +#define ACPI_RDESC_TYPE_START_DEPENDENT 0x30 +#define ACPI_RDESC_TYPE_END_DEPENDENT 0x38 +#define ACPI_RDESC_TYPE_IO_PORT 0x40 +#define ACPI_RDESC_TYPE_FIXED_IO_PORT 0x48 +#define ACPI_RDESC_TYPE_SMALL_VENDOR 0x70 +#define ACPI_RDESC_TYPE_END_TAG 0x78 /* * Large resource descriptor types */ -#define RESOURCE_DESC_MEMORY_24 0x81 -#define RESOURCE_DESC_GENERAL_REGISTER 0x82 -#define RESOURCE_DESC_LARGE_VENDOR 0x84 -#define RESOURCE_DESC_MEMORY_32 0x85 -#define RESOURCE_DESC_FIXED_MEMORY_32 0x86 -#define RESOURCE_DESC_DWORD_ADDRESS_SPACE 0x87 -#define RESOURCE_DESC_WORD_ADDRESS_SPACE 0x88 -#define RESOURCE_DESC_EXTENDED_XRUPT 0x89 -#define RESOURCE_DESC_QWORD_ADDRESS_SPACE 0x8A +#define ACPI_RDESC_TYPE_MEMORY_24 0x81 +#define ACPI_RDESC_TYPE_GENERAL_REGISTER 0x82 +#define ACPI_RDESC_TYPE_LARGE_VENDOR 0x84 +#define ACPI_RDESC_TYPE_MEMORY_32 0x85 +#define ACPI_RDESC_TYPE_FIXED_MEMORY_32 0x86 +#define ACPI_RDESC_TYPE_DWORD_ADDRESS_SPACE 0x87 +#define ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE 0x88 +#define ACPI_RDESC_TYPE_EXTENDED_XRUPT 0x89 +#define ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE 0x8A /* String version of device HIDs and UIDs */ @@ -868,7 +867,8 @@ * ****************************************************************************/ -#define ASCII_ZERO 0x30 +#define ACPI_ASCII_ZERO 0x30 + /***************************************************************************** * @@ -885,7 +885,12 @@ u32 num_loops; NATIVE_CHAR pathname[128]; -} db_method_info; +} acpi_db_method_info; + + +#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 +#define ACPI_DB_CONSOLE_OUTPUT 0x02 +#define ACPI_DB_DUPLICATE_OUTPUT 0x03 /***************************************************************************** @@ -905,10 +910,9 @@ /* Entry for a memory allocation (debug only) */ - -#define MEM_MALLOC 0 -#define MEM_CALLOC 1 -#define MAX_MODULE_NAME 16 +#define ACPI_MEM_MALLOC 0 +#define ACPI_MEM_CALLOC 1 +#define ACPI_MAX_MODULE_NAME 16 #define ACPI_COMMON_DEBUG_MEM_HEADER \ struct acpi_debug_mem_block *previous; \ @@ -916,9 +920,8 @@ u32 size; \ u32 component; \ u32 line; \ - NATIVE_CHAR module[MAX_MODULE_NAME]; \ + NATIVE_CHAR module[ACPI_MAX_MODULE_NAME]; \ u8 alloc_type; - typedef struct { diff -Nur linux-2.4.19/drivers/acpi/include/acmacros.h linux-2.4.19-sgi211r3/drivers/acpi/include/acmacros.h --- linux-2.4.19/drivers/acpi/include/acmacros.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acmacros.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acmacros.h - C macros for the entire subsystem. - * $Revision: 97 $ + * $Revision: 123 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,54 +31,23 @@ * Data manipulation macros */ -#ifndef LOWORD -#define LOWORD(l) ((u16)(NATIVE_UINT)(l)) -#endif - -#ifndef HIWORD -#define HIWORD(l) ((u16)((((NATIVE_UINT)(l)) >> 16) & 0xFFFF)) -#endif - -#ifndef LOBYTE -#define LOBYTE(l) ((u8)(u16)(l)) -#endif +#define ACPI_LOWORD(l) ((u16)(u32)(l)) +#define ACPI_HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF)) +#define ACPI_LOBYTE(l) ((u8)(u16)(l)) +#define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) -#ifndef HIBYTE -#define HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) -#endif - -#define BIT0(x) ((((x) & 0x01) > 0) ? 1 : 0) -#define BIT1(x) ((((x) & 0x02) > 0) ? 1 : 0) -#define BIT2(x) ((((x) & 0x04) > 0) ? 1 : 0) - -#define BIT3(x) ((((x) & 0x08) > 0) ? 1 : 0) -#define BIT4(x) ((((x) & 0x10) > 0) ? 1 : 0) -#define BIT5(x) ((((x) & 0x20) > 0) ? 1 : 0) -#define BIT6(x) ((((x) & 0x40) > 0) ? 1 : 0) -#define BIT7(x) ((((x) & 0x80) > 0) ? 1 : 0) -#define LOW_BASE(w) ((u16) ((w) & 0x0000FFFF)) -#define MID_BASE(b) ((u8) (((b) & 0x00FF0000) >> 16)) -#define HI_BASE(b) ((u8) (((b) & 0xFF000000) >> 24)) -#define LOW_LIMIT(w) ((u16) ((w) & 0x0000FFFF)) -#define HI_LIMIT(b) ((u8) (((b) & 0x00FF0000) >> 16)) +#if ACPI_MACHINE_WIDTH == 16 - -#ifdef _IA16 /* * For 16-bit addresses, we have to assume that the upper 32 bits * are zero. */ -#ifndef LODWORD -#define LODWORD(l) (l) -#endif - -#ifndef HIDWORD -#define HIDWORD(l) (0) -#endif +#define ACPI_LODWORD(l) ((u32)(l)) +#define ACPI_HIDWORD(l) ((u32)(0)) #define ACPI_GET_ADDRESS(a) ((a).lo) -#define ACPI_STORE_ADDRESS(a,b) {(a).hi=0;(a).lo=(b);} +#define ACPI_STORE_ADDRESS(a,b) {(a).hi=0;(a).lo=(u32)(b);} #define ACPI_VALID_ADDRESS(a) ((a).hi | (a).lo) #else @@ -86,13 +55,8 @@ /* * acpi_integer is 32-bits, no 64-bit support on this platform */ -#ifndef LODWORD -#define LODWORD(l) ((u32)(l)) -#endif - -#ifndef HIDWORD -#define HIDWORD(l) (0) -#endif +#define ACPI_LODWORD(l) ((u32)(l)) +#define ACPI_HIDWORD(l) ((u32)(0)) #define ACPI_GET_ADDRESS(a) (a) #define ACPI_STORE_ADDRESS(a,b) ((a)=(b)) @@ -103,16 +67,11 @@ /* * Full 64-bit address/integer on both 32-bit and 64-bit platforms */ -#ifndef LODWORD -#define LODWORD(l) ((u32)(u64)(l)) -#endif - -#ifndef HIDWORD -#define HIDWORD(l) ((u32)(((*(uint64_struct *)(&l))).hi)) -#endif +#define ACPI_LODWORD(l) ((u32)(u64)(l)) +#define ACPI_HIDWORD(l) ((u32)(((*(uint64_struct *)(void *)(&l))).hi)) #define ACPI_GET_ADDRESS(a) (a) -#define ACPI_STORE_ADDRESS(a,b) ((a)=(b)) +#define ACPI_STORE_ADDRESS(a,b) ((a)=(ACPI_PHYSICAL_ADDRESS)(b)) #define ACPI_VALID_ADDRESS(a) (a) #endif #endif @@ -121,13 +80,31 @@ * Extract a byte of data using a pointer. Any more than a byte and we * get into potential aligment issues -- see the STORE macros below */ -#define GET8(addr) (*(u8*)(addr)) +#define ACPI_GET8(addr) (*(u8*)(addr)) /* Pointer arithmetic */ +#define ACPI_PTR_ADD(t,a,b) (t *) (void *)((char *)(a) + (NATIVE_UINT)(b)) +#define ACPI_PTR_DIFF(a,b) (NATIVE_UINT) ((char *)(a) - (char *)(b)) -#define POINTER_ADD(t,a,b) (t *) ((NATIVE_UINT)(a) + (NATIVE_UINT)(b)) -#define POINTER_DIFF(a,b) ((u32) ((NATIVE_UINT)(a) - (NATIVE_UINT)(b))) +/* Pointer/Integer type conversions */ + +#define ACPI_TO_POINTER(i) ACPI_PTR_ADD (void, (void *) NULL,(NATIVE_UINT)i) +#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p,(void *) NULL) +#define ACPI_OFFSET(d,f) (ACPI_SIZE) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL) +#define ACPI_FADT_OFFSET(f) ACPI_OFFSET (FADT_DESCRIPTOR, f) + +#define ACPI_CAST_PTR(t, p) ((t *)(void *)(p)) +#define ACPI_CAST_INDIRECT_PTR(t, p) ((t **)(void *)(p)) + +#if ACPI_MACHINE_WIDTH == 16 +#define ACPI_STORE_POINTER(d,s) ACPI_MOVE_UNALIGNED32_TO_32(d,s) +#define ACPI_PHYSADDR_TO_PTR(i) (void *)(i) +#define ACPI_PTR_TO_PHYSADDR(i) (u32) (char *)(i) +#else +#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) +#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) +#endif /* * Macros for moving data around to/from buffers that are possibly unaligned. @@ -139,10 +116,10 @@ /* The hardware supports unaligned transfers, just do the move */ -#define MOVE_UNALIGNED16_TO_16(d,s) *(u16*)(d) = *(u16*)(s) -#define MOVE_UNALIGNED32_TO_32(d,s) *(u32*)(d) = *(u32*)(s) -#define MOVE_UNALIGNED16_TO_32(d,s) *(u32*)(d) = *(u16*)(s) -#define MOVE_UNALIGNED64_TO_64(d,s) *(u64*)(d) = *(u64*)(s) +#define ACPI_MOVE_UNALIGNED16_TO_16(d,s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s) +#define ACPI_MOVE_UNALIGNED32_TO_32(d,s) *(u32 *)(void *)(d) = *(u32 *)(void *)(s) +#define ACPI_MOVE_UNALIGNED16_TO_32(d,s) *(u32 *)(void *)(d) = *(u16 *)(void *)(s) +#define ACPI_MOVE_UNALIGNED64_TO_64(d,s) *(u64 *)(void *)(d) = *(u64 *)(void *)(s) #else /* @@ -151,24 +128,24 @@ * the destination (or both) is/are unaligned. */ -#define MOVE_UNALIGNED16_TO_16(d,s) {((u8 *)(d))[0] = ((u8 *)(s))[0];\ - ((u8 *)(d))[1] = ((u8 *)(s))[1];} +#define ACPI_MOVE_UNALIGNED16_TO_16(d,s) {((u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ + ((u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];} -#define MOVE_UNALIGNED32_TO_32(d,s) {((u8 *)(d))[0] = ((u8 *)(s))[0];\ - ((u8 *)(d))[1] = ((u8 *)(s))[1];\ - ((u8 *)(d))[2] = ((u8 *)(s))[2];\ - ((u8 *)(d))[3] = ((u8 *)(s))[3];} - -#define MOVE_UNALIGNED16_TO_32(d,s) {(*(u32*)(d)) = 0; MOVE_UNALIGNED16_TO_16(d,s);} - -#define MOVE_UNALIGNED64_TO_64(d,s) {((u8 *)(d))[0] = ((u8 *)(s))[0];\ - ((u8 *)(d))[1] = ((u8 *)(s))[1];\ - ((u8 *)(d))[2] = ((u8 *)(s))[2];\ - ((u8 *)(d))[3] = ((u8 *)(s))[3];\ - ((u8 *)(d))[4] = ((u8 *)(s))[4];\ - ((u8 *)(d))[5] = ((u8 *)(s))[5];\ - ((u8 *)(d))[6] = ((u8 *)(s))[6];\ - ((u8 *)(d))[7] = ((u8 *)(s))[7];} +#define ACPI_MOVE_UNALIGNED32_TO_32(d,s) {((u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ + ((u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\ + ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];} + +#define ACPI_MOVE_UNALIGNED16_TO_32(d,s) {(*(u32*)(void *)(d)) = 0; ACPI_MOVE_UNALIGNED16_TO_16(d,s);} + +#define ACPI_MOVE_UNALIGNED64_TO_64(d,s) {((u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ + ((u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\ + ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];\ + ((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[4];\ + ((u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[5];\ + ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[6];\ + ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[7];} #endif @@ -177,52 +154,50 @@ * Fast power-of-two math macros for non-optimized compilers */ -#define _DIV(value,power_of2) ((u32) ((value) >> (power_of2))) -#define _MUL(value,power_of2) ((u32) ((value) << (power_of2))) -#define _MOD(value,divisor) ((u32) ((value) & ((divisor) -1))) - -#define DIV_2(a) _DIV(a,1) -#define MUL_2(a) _MUL(a,1) -#define MOD_2(a) _MOD(a,2) - -#define DIV_4(a) _DIV(a,2) -#define MUL_4(a) _MUL(a,2) -#define MOD_4(a) _MOD(a,4) - -#define DIV_8(a) _DIV(a,3) -#define MUL_8(a) _MUL(a,3) -#define MOD_8(a) _MOD(a,8) - -#define DIV_16(a) _DIV(a,4) -#define MUL_16(a) _MUL(a,4) -#define MOD_16(a) _MOD(a,16) +#define _ACPI_DIV(value,power_of2) ((u32) ((value) >> (power_of2))) +#define _ACPI_MUL(value,power_of2) ((u32) ((value) << (power_of2))) +#define _ACPI_MOD(value,divisor) ((u32) ((value) & ((divisor) -1))) + +#define ACPI_DIV_2(a) _ACPI_DIV(a,1) +#define ACPI_MUL_2(a) _ACPI_MUL(a,1) +#define ACPI_MOD_2(a) _ACPI_MOD(a,2) + +#define ACPI_DIV_4(a) _ACPI_DIV(a,2) +#define ACPI_MUL_4(a) _ACPI_MUL(a,2) +#define ACPI_MOD_4(a) _ACPI_MOD(a,4) + +#define ACPI_DIV_8(a) _ACPI_DIV(a,3) +#define ACPI_MUL_8(a) _ACPI_MUL(a,3) +#define ACPI_MOD_8(a) _ACPI_MOD(a,8) + +#define ACPI_DIV_16(a) _ACPI_DIV(a,4) +#define ACPI_MUL_16(a) _ACPI_MUL(a,4) +#define ACPI_MOD_16(a) _ACPI_MOD(a,16) /* * Rounding macros (Power of two boundaries only) */ -#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) -#define ROUND_UP(value,boundary) (((value) + ((boundary)-1)) & (~((boundary)-1))) +#define ACPI_ROUND_DOWN(value,boundary) (((NATIVE_UINT)(value)) & (~(((NATIVE_UINT) boundary)-1))) +#define ACPI_ROUND_UP(value,boundary) ((((NATIVE_UINT)(value)) + (((NATIVE_UINT) boundary)-1)) & (~(((NATIVE_UINT) boundary)-1))) -#define ROUND_DOWN_TO_32_BITS(a) ROUND_DOWN(a,4) -#define ROUND_DOWN_TO_64_BITS(a) ROUND_DOWN(a,8) -#define ROUND_DOWN_TO_NATIVE_WORD(a) ROUND_DOWN(a,ALIGNED_ADDRESS_BOUNDARY) +#define ACPI_ROUND_DOWN_TO_32_BITS(a) ACPI_ROUND_DOWN(a,4) +#define ACPI_ROUND_DOWN_TO_64_BITS(a) ACPI_ROUND_DOWN(a,8) +#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,ALIGNED_ADDRESS_BOUNDARY) -#define ROUND_UP_TO_32_bITS(a) ROUND_UP(a,4) -#define ROUND_UP_TO_64_bITS(a) ROUND_UP(a,8) -#define ROUND_UP_TO_NATIVE_WORD(a) ROUND_UP(a,ALIGNED_ADDRESS_BOUNDARY) +#define ACPI_ROUND_UP_TO_32_bITS(a) ACPI_ROUND_UP(a,4) +#define ACPI_ROUND_UP_TO_64_bITS(a) ACPI_ROUND_UP(a,8) +#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,ALIGNED_ADDRESS_BOUNDARY) -#define ROUND_PTR_UP_TO_4(a,b) ((b *)(((NATIVE_UINT)(a) + 3) & ~3)) -#define ROUND_PTR_UP_TO_8(a,b) ((b *)(((NATIVE_UINT)(a) + 7) & ~7)) -#define ROUND_BITS_UP_TO_BYTES(a) DIV_8((a) + 7) -#define ROUND_BITS_DOWN_TO_BYTES(a) DIV_8((a)) +#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) +#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a)) -#define ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) +#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) /* Generic (non-power-of-two) rounding */ -#define ROUND_UP_TO(value,boundary) (((value) + ((boundary)-1)) / (boundary)) +#define ACPI_ROUND_UP_TO(value,boundary) (((value) + ((boundary)-1)) / (boundary)) /* * Bitmask creation @@ -230,21 +205,33 @@ * MASK_BITS_ABOVE creates a mask starting AT the position and above * MASK_BITS_BELOW creates a mask starting one bit BELOW the position */ -#define MASK_BITS_ABOVE(position) (~(((u32)(-1)) << ((u32) (position)))) -#define MASK_BITS_BELOW(position) (((u32)(-1)) << ((u32) (position))) +#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position)))) +#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position))) +#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) /* Macros for GAS addressing */ -#ifndef _IA16 +#if ACPI_MACHINE_WIDTH != 16 #define ACPI_PCI_DEVICE_MASK (u64) 0x0000FFFF00000000 #define ACPI_PCI_FUNCTION_MASK (u64) 0x00000000FFFF0000 #define ACPI_PCI_REGISTER_MASK (u64) 0x000000000000FFFF -#define ACPI_PCI_FUNCTION(a) (u16) ((((a) & ACPI_PCI_FUNCTION_MASK) >> 16)) -#define ACPI_PCI_DEVICE(a) (u16) ((((a) & ACPI_PCI_DEVICE_MASK) >> 32)) -#define ACPI_PCI_REGISTER(a) (u16) (((a) & ACPI_PCI_REGISTER_MASK)) +/* + * Obsolete + */ + +/* +#define ACPI_PCI_FUNCTION(a) (u16) ((((u64)((u64)(a) & ACPI_PCI_FUNCTION_MASK)) >> 16)) +#define ACPI_PCI_DEVICE(a) (u16) ((((u64)((u64)(a) & ACPI_PCI_DEVICE_MASK)) >> 32)) +#define ACPI_PCI_REGISTER(a) (u16) (((u64)((u64)(a) & ACPI_PCI_REGISTER_MASK))) +*/ + + +#define ACPI_PCI_DEVICE(a) (u16) ((ACPI_HIDWORD ((a))) & 0x0000FFFF) +#define ACPI_PCI_FUNCTION(a) (u16) ((ACPI_LODWORD ((a))) >> 16) +#define ACPI_PCI_REGISTER(a) (u16) ((ACPI_LODWORD ((a))) & 0x0000FFFF) #else @@ -256,23 +243,30 @@ #endif + +/* Bitfields within ACPI registers */ + +#define ACPI_REGISTER_PREPARE_BITS(val, pos, mask) ((val << pos) & mask) +#define ACPI_REGISTER_INSERT_VALUE(reg, pos, mask, val) reg = (reg & (~(mask))) | ACPI_REGISTER_PREPARE_BITS(val, pos, mask) + /* - * An acpi_handle (which is actually an acpi_namespace_node *) can appear in some contexts, - * such as on ap_obj_stack, where a pointer to an acpi_operand_object can also + * An acpi_namespace_node * can appear in some contexts, + * where a pointer to an acpi_operand_object can also * appear. This macro is used to distinguish them. * - * The Data_type field is the first field in both structures. + * The "Descriptor" field is the first field in both structures. */ -#define VALID_DESCRIPTOR_TYPE(d,t) (((acpi_namespace_node *)d)->data_type == t) +#define ACPI_GET_DESCRIPTOR_TYPE(d) (((ACPI_DESCRIPTOR *)(void *)(d))->descriptor_id) +#define ACPI_SET_DESCRIPTOR_TYPE(d,t) (((ACPI_DESCRIPTOR *)(void *)(d))->descriptor_id = t) /* Macro to test the object type */ -#define IS_THIS_OBJECT_TYPE(d,t) (((acpi_operand_object *)d)->common.type == (u8)t) +#define ACPI_GET_OBJECT_TYPE(d) (((acpi_operand_object *)(void *)d)->common.type) /* Macro to check the table flags for SINGLE or MULTIPLE tables are allowed */ -#define IS_SINGLE_TABLE(x) (((x) & 0x01) == ACPI_TABLE_SINGLE ? 1 : 0) +#define ACPI_IS_SINGLE_TABLE(x) (((x) & 0x01) == ACPI_TABLE_SINGLE ? 1 : 0) /* * Macro to check if a pointer is within an ACPI table. @@ -280,12 +274,12 @@ * as a pointer to an acpi_table_header. (b+1) then points past the header, * and ((u8 *)b+b->Length) points one byte past the end of the table. */ -#ifndef _IA16 -#define IS_IN_ACPI_TABLE(a,b) (((u8 *)(a) >= (u8 *)(b + 1)) &&\ - ((u8 *)(a) < ((u8 *)b + b->length))) +#if ACPI_MACHINE_WIDTH != 16 +#define ACPI_IS_IN_ACPI_TABLE(a,b) (((u8 *)(a) >= (u8 *)(b + 1)) &&\ + ((u8 *)(a) < ((u8 *)b + b->length))) #else -#define IS_IN_ACPI_TABLE(a,b) (_segment)(a) == (_segment)(b) &&\ +#define ACPI_IS_IN_ACPI_TABLE(a,b) (_segment)(a) == (_segment)(b) &&\ (((u8 *)(a) >= (u8 *)(b + 1)) &&\ ((u8 *)(a) < ((u8 *)b + b->length))) #endif @@ -293,10 +287,10 @@ /* * Macros for the master AML opcode table */ -#ifdef ACPI_DEBUG -#define ACPI_OP(name,Pargs,Iargs,class,type,flags) {Pargs,Iargs,flags,class,type,name} +#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) +#define ACPI_OP(name,Pargs,Iargs,obj_type,class,type,flags) {name,Pargs,Iargs,flags,obj_type,class,type} #else -#define ACPI_OP(name,Pargs,Iargs,class,type,flags) {Pargs,Iargs,flags,class,type} +#define ACPI_OP(name,Pargs,Iargs,obj_type,class,type,flags) {Pargs,Iargs,flags,obj_type,class,type} #endif #define ARG_TYPE_WIDTH 5 @@ -335,10 +329,10 @@ * 5) Expand address to 64 bits */ #define ASL_BUILD_GAS_FROM_ENTRY(a,b,c,d) {a.address_space_id = (u8) d;\ - a.register_bit_width = (u8) MUL_8 (b);\ + a.register_bit_width = (u8) ACPI_MUL_8 (b);\ a.register_bit_offset = 0;\ a.reserved = 0;\ - ACPI_STORE_ADDRESS (a.address,c);} + ACPI_STORE_ADDRESS (a.address,(ACPI_PHYSICAL_ADDRESS) c);} /* ACPI V1.0 entries -- address space is always I/O */ @@ -349,7 +343,7 @@ * Reporting macros that are never compiled out */ -#define PARAM_LIST(pl) pl +#define ACPI_PARAM_LIST(pl) pl /* * Error reporting. These versions add callers module and line#. Since @@ -359,32 +353,32 @@ #ifdef ACPI_DEBUG -#define REPORT_INFO(fp) {acpi_ut_report_info(_THIS_MODULE,__LINE__,_COMPONENT); \ - acpi_os_printf PARAM_LIST(fp);} -#define REPORT_ERROR(fp) {acpi_ut_report_error(_THIS_MODULE,__LINE__,_COMPONENT); \ - acpi_os_printf PARAM_LIST(fp);} -#define REPORT_WARNING(fp) {acpi_ut_report_warning(_THIS_MODULE,__LINE__,_COMPONENT); \ - acpi_os_printf PARAM_LIST(fp);} +#define ACPI_REPORT_INFO(fp) {acpi_ut_report_info(_THIS_MODULE,__LINE__,_COMPONENT); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} +#define ACPI_REPORT_ERROR(fp) {acpi_ut_report_error(_THIS_MODULE,__LINE__,_COMPONENT); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} +#define ACPI_REPORT_WARNING(fp) {acpi_ut_report_warning(_THIS_MODULE,__LINE__,_COMPONENT); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} #else -#define REPORT_INFO(fp) {acpi_ut_report_info("ACPI",__LINE__,_COMPONENT); \ - acpi_os_printf PARAM_LIST(fp);} -#define REPORT_ERROR(fp) {acpi_ut_report_error("ACPI",__LINE__,_COMPONENT); \ - acpi_os_printf PARAM_LIST(fp);} -#define REPORT_WARNING(fp) {acpi_ut_report_warning("ACPI",__LINE__,_COMPONENT); \ - acpi_os_printf PARAM_LIST(fp);} +#define ACPI_REPORT_INFO(fp) {acpi_ut_report_info("ACPI",__LINE__,_COMPONENT); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} +#define ACPI_REPORT_ERROR(fp) {acpi_ut_report_error("ACPI",__LINE__,_COMPONENT); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} +#define ACPI_REPORT_WARNING(fp) {acpi_ut_report_warning("ACPI",__LINE__,_COMPONENT); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} #endif /* Error reporting. These versions pass thru the module and line# */ -#define _REPORT_INFO(a,b,c,fp) {acpi_ut_report_info(a,b,c); \ - acpi_os_printf PARAM_LIST(fp);} -#define _REPORT_ERROR(a,b,c,fp) {acpi_ut_report_error(a,b,c); \ - acpi_os_printf PARAM_LIST(fp);} -#define _REPORT_WARNING(a,b,c,fp) {acpi_ut_report_warning(a,b,c); \ - acpi_os_printf PARAM_LIST(fp);} +#define _ACPI_REPORT_INFO(a,b,c,fp) {acpi_ut_report_info(a,b,c); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} +#define _ACPI_REPORT_ERROR(a,b,c,fp) {acpi_ut_report_error(a,b,c); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} +#define _ACPI_REPORT_WARNING(a,b,c,fp) {acpi_ut_report_warning(a,b,c); \ + acpi_os_printf ACPI_PARAM_LIST(fp);} /* * Debug macros that are conditionally compiled @@ -392,7 +386,7 @@ #ifdef ACPI_DEBUG -#define MODULE_NAME(name) static char *_THIS_MODULE = name; +#define ACPI_MODULE_NAME(name) static char *_THIS_MODULE = name; /* * Function entry tracing. @@ -400,21 +394,21 @@ * as a local string ("_Proc_name) so that it can be also used by the function exit macros below. */ -#define PROC_NAME(a) acpi_debug_print_info _dbg; \ +#define ACPI_FUNCTION_NAME(a) acpi_debug_print_info _dbg; \ _dbg.component_id = _COMPONENT; \ _dbg.proc_name = a; \ _dbg.module_name = _THIS_MODULE; -#define FUNCTION_TRACE(a) PROC_NAME(a)\ - acpi_ut_trace(__LINE__,&_dbg) -#define FUNCTION_TRACE_PTR(a,b) PROC_NAME(a)\ - acpi_ut_trace_ptr(__LINE__,&_dbg,(void *)b) -#define FUNCTION_TRACE_U32(a,b) PROC_NAME(a)\ - acpi_ut_trace_u32(__LINE__,&_dbg,(u32)b) -#define FUNCTION_TRACE_STR(a,b) PROC_NAME(a)\ - acpi_ut_trace_str(__LINE__,&_dbg,(NATIVE_CHAR *)b) +#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a)\ + acpi_ut_trace(__LINE__,&_dbg) +#define ACPI_FUNCTION_TRACE_PTR(a,b) ACPI_FUNCTION_NAME(a)\ + acpi_ut_trace_ptr(__LINE__,&_dbg,(void *)b) +#define ACPI_FUNCTION_TRACE_U32(a,b) ACPI_FUNCTION_NAME(a)\ + acpi_ut_trace_u32(__LINE__,&_dbg,(u32)b) +#define ACPI_FUNCTION_TRACE_STR(a,b) ACPI_FUNCTION_NAME(a)\ + acpi_ut_trace_str(__LINE__,&_dbg,(NATIVE_CHAR *)b) -#define FUNCTION_ENTRY() acpi_ut_track_stack_ptr() +#define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr() /* * Function exit tracing. @@ -423,46 +417,52 @@ * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros * so that "_Proc_name" is defined. */ -#define return_VOID {acpi_ut_exit(__LINE__,&_dbg);return;} -#define return_ACPI_STATUS(s) {acpi_ut_status_exit(__LINE__,&_dbg,s);return(s);} -#define return_VALUE(s) {acpi_ut_value_exit(__LINE__,&_dbg,s);return(s);} -#define return_PTR(s) {acpi_ut_ptr_exit(__LINE__,&_dbg,(u8 *)s);return(s);} +#ifdef ACPI_USE_DO_WHILE_0 +#define ACPI_DO_WHILE0(a) do a while(0) +#else +#define ACPI_DO_WHILE0(a) a +#endif +#define return_VOID ACPI_DO_WHILE0 ({acpi_ut_exit(__LINE__,&_dbg);return;}) +#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({acpi_ut_status_exit(__LINE__,&_dbg,(s));return((s));}) +#define return_VALUE(s) ACPI_DO_WHILE0 ({acpi_ut_value_exit(__LINE__,&_dbg,(acpi_integer)(s));return((s));}) +#define return_PTR(s) ACPI_DO_WHILE0 ({acpi_ut_ptr_exit(__LINE__,&_dbg,(u8 *)(s));return((s));}) /* Conditional execution */ -#define DEBUG_EXEC(a) a -#define NORMAL_EXEC(a) +#define ACPI_DEBUG_EXEC(a) a +#define ACPI_NORMAL_EXEC(a) -#define DEBUG_DEFINE(a) a; -#define DEBUG_ONLY_MEMBERS(a) a; +#define ACPI_DEBUG_DEFINE(a) a; +#define ACPI_DEBUG_ONLY_MEMBERS(a) a; #define _OPCODE_NAMES #define _VERBOSE_STRUCTURES /* Stack and buffer dumping */ -#define DUMP_STACK_ENTRY(a) acpi_ex_dump_operand(a) -#define DUMP_OPERANDS(a,b,c,d,e) acpi_ex_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__) +#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand(a) +#define ACPI_DUMP_OPERANDS(a,b,c,d,e) acpi_ex_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__) -#define DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b) -#define DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b) -#define DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d) -#define DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) -#define DUMP_BUFFER(a,b) acpi_ut_dump_buffer((u8 *)a,b,DB_BYTE_DISPLAY,_COMPONENT) -#define BREAK_MSG(a) acpi_os_signal (ACPI_SIGNAL_BREAKPOINT,(a)) +#define ACPI_DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b) +#define ACPI_DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b) +#define ACPI_DUMP_PATHNAME(a,b,c,d) (void) acpi_ns_dump_pathname(a,b,c,d) +#define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) +#define ACPI_DUMP_BUFFER(a,b) acpi_ut_dump_buffer((u8 *)a,b,DB_BYTE_DISPLAY,_COMPONENT) +#define ACPI_BREAK_MSG(a) acpi_os_signal (ACPI_SIGNAL_BREAKPOINT,(a)) /* * Generate INT3 on ACPI_ERROR (Debug only!) */ -#define ERROR_BREAK -#ifdef ERROR_BREAK -#define BREAK_ON_ERROR(lvl) if ((lvl)&ACPI_ERROR) acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,"Fatal error encountered\n") +#define ACPI_ERROR_BREAK +#ifdef ACPI_ERROR_BREAK +#define ACPI_BREAK_ON_ERROR(lvl) if ((lvl)&ACPI_ERROR) \ + acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,"Fatal error encountered\n") #else -#define BREAK_ON_ERROR(lvl) +#define ACPI_BREAK_ON_ERROR(lvl) #endif /* @@ -472,8 +472,8 @@ * 2) Debug error level or trace level for the print statement is enabled */ -#define ACPI_DEBUG_PRINT(pl) acpi_ut_debug_print PARAM_LIST(pl) -#define ACPI_DEBUG_PRINT_RAW(pl) acpi_ut_debug_print_raw PARAM_LIST(pl) +#define ACPI_DEBUG_PRINT(pl) acpi_ut_debug_print ACPI_PARAM_LIST(pl) +#define ACPI_DEBUG_PRINT_RAW(pl) acpi_ut_debug_print_raw ACPI_PARAM_LIST(pl) #else @@ -482,39 +482,43 @@ * leaving no executable debug code! */ -#define MODULE_NAME(name) +#define ACPI_MODULE_NAME(name) #define _THIS_MODULE "" -#define DEBUG_EXEC(a) -#define NORMAL_EXEC(a) a; +#define ACPI_DEBUG_EXEC(a) +#define ACPI_NORMAL_EXEC(a) a; -#define DEBUG_DEFINE(a) -#define DEBUG_ONLY_MEMBERS(a) -#define PROC_NAME(a) -#define FUNCTION_TRACE(a) -#define FUNCTION_TRACE_PTR(a,b) -#define FUNCTION_TRACE_U32(a,b) -#define FUNCTION_TRACE_STR(a,b) -#define FUNCTION_EXIT -#define FUNCTION_STATUS_EXIT(s) -#define FUNCTION_VALUE_EXIT(s) -#define FUNCTION_ENTRY() -#define DUMP_STACK_ENTRY(a) -#define DUMP_OPERANDS(a,b,c,d,e) -#define DUMP_ENTRY(a,b) -#define DUMP_TABLES(a,b) -#define DUMP_PATHNAME(a,b,c,d) -#define DUMP_RESOURCE_LIST(a) -#define DUMP_BUFFER(a,b) +#define ACPI_DEBUG_DEFINE(a) +#define ACPI_DEBUG_ONLY_MEMBERS(a) +#define ACPI_FUNCTION_NAME(a) +#define ACPI_FUNCTION_TRACE(a) +#define ACPI_FUNCTION_TRACE_PTR(a,b) +#define ACPI_FUNCTION_TRACE_U32(a,b) +#define ACPI_FUNCTION_TRACE_STR(a,b) +#define ACPI_FUNCTION_EXIT +#define ACPI_FUNCTION_STATUS_EXIT(s) +#define ACPI_FUNCTION_VALUE_EXIT(s) +#define ACPI_FUNCTION_ENTRY() +#define ACPI_DUMP_STACK_ENTRY(a) +#define ACPI_DUMP_OPERANDS(a,b,c,d,e) +#define ACPI_DUMP_ENTRY(a,b) +#define ACPI_DUMP_TABLES(a,b) +#define ACPI_DUMP_PATHNAME(a,b,c,d) +#define ACPI_DUMP_RESOURCE_LIST(a) +#define ACPI_DUMP_BUFFER(a,b) #define ACPI_DEBUG_PRINT(pl) #define ACPI_DEBUG_PRINT_RAW(pl) -#define BREAK_MSG(a) +#define ACPI_BREAK_MSG(a) #define return_VOID return #define return_ACPI_STATUS(s) return(s) #define return_VALUE(s) return(s) #define return_PTR(s) return(s) +#ifdef ENABLE_DEBUGGER +#define _OPCODE_NAMES +#endif + #endif /* @@ -523,9 +527,9 @@ * DEBUG_PRINT stuff (set by ACPI_DEBUG) is on, or not. */ #ifdef ENABLE_DEBUGGER -#define DEBUGGER_EXEC(a) a +#define ACPI_DEBUGGER_EXEC(a) a #else -#define DEBUGGER_EXEC(a) +#define ACPI_DEBUGGER_EXEC(a) #endif @@ -533,10 +537,10 @@ * For 16-bit code, we want to shrink some things even though * we are using ACPI_DEBUG to get the debug output */ -#ifdef _IA16 -#undef DEBUG_ONLY_MEMBERS +#if ACPI_MACHINE_WIDTH == 16 +#undef ACPI_DEBUG_ONLY_MEMBERS #undef _VERBOSE_STRUCTURES -#define DEBUG_ONLY_MEMBERS(a) +#define ACPI_DEBUG_ONLY_MEMBERS(a) #endif @@ -545,11 +549,11 @@ * 1) Set name to blanks * 2) Copy the object name */ -#define ADD_OBJECT_NAME(a,b) MEMSET (a->common.name, ' ', sizeof (a->common.name));\ - STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name)) +#define ACPI_ADD_OBJECT_NAME(a,b) ACPI_MEMSET (a->common.name, ' ', sizeof (a->common.name));\ + ACPI_STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name)) #else -#define ADD_OBJECT_NAME(a,b) +#define ACPI_ADD_OBJECT_NAME(a,b) #endif @@ -561,8 +565,8 @@ /* Memory allocation */ -#define ACPI_MEM_ALLOCATE(a) acpi_os_allocate(a) -#define ACPI_MEM_CALLOCATE(a) acpi_os_callocate(a) +#define ACPI_MEM_ALLOCATE(a) acpi_ut_allocate((ACPI_SIZE)(a),_COMPONENT,_THIS_MODULE,__LINE__) +#define ACPI_MEM_CALLOCATE(a) acpi_ut_callocate((ACPI_SIZE)(a), _COMPONENT,_THIS_MODULE,__LINE__) #define ACPI_MEM_FREE(a) acpi_os_free(a) #define ACPI_MEM_TRACKING(a) @@ -571,9 +575,9 @@ /* Memory allocation */ -#define ACPI_MEM_ALLOCATE(a) acpi_ut_allocate(a,_COMPONENT,_THIS_MODULE,__LINE__) -#define ACPI_MEM_CALLOCATE(a) acpi_ut_callocate(a, _COMPONENT,_THIS_MODULE,__LINE__) -#define ACPI_MEM_FREE(a) acpi_ut_free(a,_COMPONENT,_THIS_MODULE,__LINE__) +#define ACPI_MEM_ALLOCATE(a) acpi_ut_allocate_and_track((ACPI_SIZE)(a),_COMPONENT,_THIS_MODULE,__LINE__) +#define ACPI_MEM_CALLOCATE(a) acpi_ut_callocate_and_track((ACPI_SIZE)(a), _COMPONENT,_THIS_MODULE,__LINE__) +#define ACPI_MEM_FREE(a) acpi_ut_free_and_track(a,_COMPONENT,_THIS_MODULE,__LINE__) #define ACPI_MEM_TRACKING(a) a #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ diff -Nur linux-2.4.19/drivers/acpi/include/acnamesp.h linux-2.4.19-sgi211r3/drivers/acpi/include/acnamesp.h --- linux-2.4.19/drivers/acpi/include/acnamesp.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acnamesp.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acnamesp.h - Namespace subcomponent prototypes and defines - * $Revision: 110 $ + * $Revision: 125 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,37 +29,37 @@ /* To search the entire name space, pass this as Search_base */ -#define NS_ALL ((acpi_handle)0) +#define ACPI_NS_ALL ((acpi_handle)0) /* * Elements of Acpi_ns_properties are bit significant * and should be one-to-one with values of acpi_object_type */ -#define NSP_NORMAL 0 -#define NSP_NEWSCOPE 1 /* a definition of this type opens a name scope */ -#define NSP_LOCAL 2 /* suppress search of enclosing scopes */ +#define ACPI_NS_NORMAL 0 +#define ACPI_NS_NEWSCOPE 1 /* a definition of this type opens a name scope */ +#define ACPI_NS_LOCAL 2 /* suppress search of enclosing scopes */ /* Definitions of the predefined namespace names */ -#define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */ -#define ACPI_ROOT_NAME (u32) 0x2F202020 /* Root name is "/ " */ -#define ACPI_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */ +#define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */ +#define ACPI_ROOT_NAME (u32) 0x2F202020 /* Root name is "/ " */ +#define ACPI_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */ -#define NS_ROOT_PATH "/" -#define NS_SYSTEM_BUS "_SB_" +#define ACPI_NS_ROOT_PATH "\\" +#define ACPI_NS_SYSTEM_BUS "_SB_" /* Flags for Acpi_ns_lookup, Acpi_ns_search_and_enter */ -#define NS_NO_UPSEARCH 0 -#define NS_SEARCH_PARENT 0x01 -#define NS_DONT_OPEN_SCOPE 0x02 -#define NS_NO_PEER_SEARCH 0x04 -#define NS_ERROR_IF_FOUND 0x08 +#define ACPI_NS_NO_UPSEARCH 0 +#define ACPI_NS_SEARCH_PARENT 0x01 +#define ACPI_NS_DONT_OPEN_SCOPE 0x02 +#define ACPI_NS_NO_PEER_SEARCH 0x04 +#define ACPI_NS_ERROR_IF_FOUND 0x08 -#define NS_WALK_UNLOCK TRUE -#define NS_WALK_NO_UNLOCK FALSE +#define ACPI_NS_WALK_UNLOCK TRUE +#define ACPI_NS_WALK_NO_UNLOCK FALSE acpi_status @@ -94,7 +94,7 @@ acpi_status acpi_ns_walk_namespace ( - acpi_object_type8 type, + acpi_object_type type, acpi_handle start_object, u32 max_depth, u8 unlock_before_callback, @@ -104,11 +104,11 @@ acpi_namespace_node * acpi_ns_get_next_node ( - acpi_object_type8 type, + acpi_object_type type, acpi_namespace_node *parent, acpi_namespace_node *child); -acpi_status +void acpi_ns_delete_namespace_by_owner ( u16 table_id); @@ -139,7 +139,6 @@ * Top-level namespace access - nsaccess */ - acpi_status acpi_ns_root_initialize ( void); @@ -148,8 +147,8 @@ acpi_ns_lookup ( acpi_generic_state *scope_info, NATIVE_CHAR *name, - acpi_object_type8 type, - operating_mode interpreter_mode, + acpi_object_type type, + acpi_interpreter_mode interpreter_mode, u32 flags, acpi_walk_state *walk_state, acpi_namespace_node **ret_node); @@ -159,7 +158,6 @@ * Named object allocation/deallocation - nsalloc */ - acpi_namespace_node * acpi_ns_create_node ( u32 name); @@ -168,7 +166,7 @@ acpi_ns_delete_node ( acpi_namespace_node *node); -acpi_status +void acpi_ns_delete_namespace_subtree ( acpi_namespace_node *parent_handle); @@ -216,12 +214,31 @@ u32 component); void +acpi_ns_print_pathname ( + u32 num_segments, + char *pathname); + +acpi_status +acpi_ns_dump_one_device ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + +void acpi_ns_dump_root_devices ( void); +acpi_status +acpi_ns_dump_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + void acpi_ns_dump_objects ( - acpi_object_type8 type, + acpi_object_type type, u8 display_type, u32 max_depth, u32 ownder_id, @@ -277,15 +294,21 @@ /* - * Scope manipulation - nsscope + * Name and Scope manipulation - nsnames */ u32 acpi_ns_opens_scope ( - acpi_object_type8 type); + acpi_object_type type); + +void +acpi_ns_build_external_path ( + acpi_namespace_node *node, + ACPI_SIZE size, + NATIVE_CHAR *name_buffer); NATIVE_CHAR * -acpi_ns_get_table_pathname ( +acpi_ns_get_external_pathname ( acpi_namespace_node *node); NATIVE_CHAR * @@ -294,9 +317,8 @@ acpi_status acpi_ns_handle_to_pathname ( - acpi_handle obj_handle, - u32 *buf_size, - NATIVE_CHAR *user_buffer); + acpi_handle target_handle, + acpi_buffer *buffer); u8 acpi_ns_pattern_match ( @@ -304,25 +326,51 @@ NATIVE_CHAR *search_for); acpi_status -acpi_ns_get_node ( - NATIVE_CHAR *pathname, +acpi_ns_get_node_by_path ( + NATIVE_CHAR *external_pathname, acpi_namespace_node *in_prefix_node, + u32 flags, acpi_namespace_node **out_node); -u32 +ACPI_SIZE acpi_ns_get_pathname_length ( acpi_namespace_node *node); /* - * Object management for NTEs - nsobject + * Object management for namespace nodes - nsobject */ acpi_status acpi_ns_attach_object ( acpi_namespace_node *node, acpi_operand_object *object, - acpi_object_type8 type); + acpi_object_type type); + +acpi_operand_object * +acpi_ns_get_attached_object ( + acpi_namespace_node *node); + +acpi_operand_object * +acpi_ns_get_secondary_object ( + acpi_operand_object *obj_desc); + +acpi_status +acpi_ns_attach_data ( + acpi_namespace_node *node, + ACPI_OBJECT_HANDLER handler, + void *data); + +acpi_status +acpi_ns_detach_data ( + acpi_namespace_node *node, + ACPI_OBJECT_HANDLER handler); + +acpi_status +acpi_ns_get_attached_data ( + acpi_namespace_node *node, + ACPI_OBJECT_HANDLER handler, + void **data); /* @@ -334,8 +382,8 @@ u32 entry_name, acpi_walk_state *walk_state, acpi_namespace_node *node, - operating_mode interpreter_mode, - acpi_object_type8 type, + acpi_interpreter_mode interpreter_mode, + acpi_object_type type, u32 flags, acpi_namespace_node **ret_node); @@ -343,7 +391,7 @@ acpi_ns_search_node ( u32 entry_name, acpi_namespace_node *node, - acpi_object_type8 type, + acpi_object_type type, acpi_namespace_node **ret_node); void @@ -351,7 +399,7 @@ acpi_walk_state *walk_state, acpi_namespace_node *parent_node, /* Parent */ acpi_namespace_node *node, /* New Child*/ - acpi_object_type8 type); + acpi_object_type type); /* @@ -366,23 +414,19 @@ acpi_ns_valid_path_separator ( NATIVE_CHAR sep); -acpi_object_type8 +acpi_object_type acpi_ns_get_type ( acpi_namespace_node *node); -void * -acpi_ns_get_attached_object ( - acpi_namespace_node *node); - u32 acpi_ns_local ( - acpi_object_type8 type); + acpi_object_type type); acpi_status acpi_ns_build_internal_name ( acpi_namestring_info *info); -acpi_status +void acpi_ns_get_internal_name_length ( acpi_namestring_info *info); @@ -411,7 +455,7 @@ void); acpi_namespace_node * -acpi_ns_get_parent_object ( +acpi_ns_get_parent_node ( acpi_namespace_node *node); diff -Nur linux-2.4.19/drivers/acpi/include/acobject.h linux-2.4.19-sgi211r3/drivers/acpi/include/acobject.h --- linux-2.4.19/drivers/acpi/include/acobject.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acobject.h Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ /****************************************************************************** * * Name: acobject.h - Definition of acpi_operand_object (Internal object only) - * $Revision: 93 $ + * $Revision: 111 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,23 +32,14 @@ * The acpi_operand_object is used to pass AML operands from the dispatcher * to the interpreter, and to keep track of the various handlers such as * address space handlers and notify handlers. The object is a constant - * size in order to allow them to be cached and reused. - * - * All variants of the acpi_operand_object are defined with the same - * sequence of field types, with fields that are not used in a particular - * variant being named "Reserved". This is not strictly necessary, but - * may in some circumstances simplify understanding if these structures - * need to be displayed in a debugger having limited (or no) support for - * union types. It also simplifies some debug code in Dump_table() which - * dumps multi-level values: fetching Buffer.Pointer suffices to pick up - * the value or next level for any of several types. + * size in order to allow it to be cached and reused. */ -/****************************************************************************** +/******************************************************************************* * * Common Descriptors * - *****************************************************************************/ + ******************************************************************************/ /* * Common area for all objects. @@ -56,46 +47,40 @@ * Data_type is used to differentiate between internal descriptors, and MUST * be the first byte in this structure. */ - - -#define ACPI_OBJECT_COMMON_HEADER /* SIZE/ALIGNMENT: 32-bits plus trailing 8-bit flag */\ - u8 data_type; /* To differentiate various internal objs */\ +#define ACPI_OBJECT_COMMON_HEADER /* SIZE/ALIGNMENT: 32 bits, one ptr plus trailing 8-bit flag */\ + u8 descriptor; /* To differentiate various internal objs */\ u8 type; /* acpi_object_type */\ u16 reference_count; /* For object deletion management */\ + union acpi_operand_obj *next_object; /* Objects linked to parent NS node */\ u8 flags; \ -/* Defines for flag byte above */ +/* Values for flag byte above */ -#define AOPOBJ_STATIC_ALLOCATION 0x1 -#define AOPOBJ_STATIC_POINTER 0x2 -#define AOPOBJ_DATA_VALID 0x4 -#define AOPOBJ_ZERO_CONST 0x4 -#define AOPOBJ_INITIALIZED 0x8 +#define AOPOBJ_RESERVED 0x01 +#define AOPOBJ_STATIC_POINTER 0x02 +#define AOPOBJ_DATA_VALID 0x04 +#define AOPOBJ_OBJECT_INITIALIZED 0x08 +#define AOPOBJ_SETUP_COMPLETE 0x10 +#define AOPOBJ_SINGLE_DATUM 0x20 /* * Common bitfield for the field objects - * "Field Datum" -- a datum from the actual field object - * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field + * "Field Datum" -- a datum from the actual field object + * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field */ #define ACPI_COMMON_FIELD_INFO /* SIZE/ALIGNMENT: 24 bits + three 32-bit values */\ - u8 access_flags;\ - u16 bit_length; /* Length of field in bits */\ - u32 base_byte_offset; /* Byte offset within containing object */\ - u8 access_bit_width; /* Read/Write size in bits (from ASL Access_type)*/\ + u8 field_flags; /* Access, update, and lock bits */\ + u8 attribute; /* From Access_as keyword */\ u8 access_byte_width; /* Read/Write size in bytes */\ - u8 update_rule; /* How neighboring field bits are handled */\ - u8 lock_rule; /* Global Lock: 1 = "Must Lock" */\ + u32 bit_length; /* Length of field in bits */\ + u32 base_byte_offset; /* Byte offset within containing object */\ u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ u8 datum_valid_bits; /* Valid bit in first "Field datum" */\ u8 end_field_valid_bits; /* Valid bits in the last "field datum" */\ u8 end_buffer_valid_bits; /* Valid bits in the last "buffer datum" */\ - u32 value; /* Value to store into the Bank or Index register */ - - -/* Access flag bits */ - -#define AFIELD_SINGLE_DATUM 0x1 + u32 value; /* Value to store into the Bank or Index register */\ + acpi_namespace_node *node; /* Link back to parent node */ /* @@ -105,29 +90,29 @@ u32 length; +/* + * Common fields for objects that support ASL notifications + */ +#define ACPI_COMMON_NOTIFY_INFO \ + union acpi_operand_obj *sys_handler; /* Handler for system notifies */\ + union acpi_operand_obj *drv_handler; /* Handler for driver notifies */\ + union acpi_operand_obj *addr_handler; /* Handler for Address space */ + + /****************************************************************************** * - * Individual Object Descriptors + * Basic data types * *****************************************************************************/ - -typedef struct /* COMMON */ +typedef struct acpi_object_common { ACPI_OBJECT_COMMON_HEADER } ACPI_OBJECT_COMMON; -typedef struct /* CACHE_LIST */ -{ - ACPI_OBJECT_COMMON_HEADER - union acpi_operand_obj *next; /* Link for object cache and internal lists*/ - -} ACPI_OBJECT_CACHE_LIST; - - -typedef struct /* NUMBER - has value */ +typedef struct acpi_object_integer { ACPI_OBJECT_COMMON_HEADER @@ -136,47 +121,47 @@ } ACPI_OBJECT_INTEGER; -typedef struct /* STRING - has length and pointer - Null terminated, ASCII characters only */ +typedef struct acpi_object_string /* Null terminated, ASCII characters only */ { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO - NATIVE_CHAR *pointer; /* String value in AML stream or in allocated space */ + NATIVE_CHAR *pointer; /* String in AML stream or allocated string */ } ACPI_OBJECT_STRING; -typedef struct /* BUFFER - has length and pointer - not null terminated */ +typedef struct acpi_object_buffer { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO - u8 *pointer; /* Buffer value in AML stream or in allocated space */ + u8 *pointer; /* Buffer in AML stream or allocated buffer */ + acpi_namespace_node *node; /* Link back to parent node */ + u8 *aml_start; + u32 aml_length; } ACPI_OBJECT_BUFFER; -typedef struct /* PACKAGE - has count, elements, next element */ +typedef struct acpi_object_package { ACPI_OBJECT_COMMON_HEADER u32 count; /* # of elements in package */ + u32 aml_length; + u8 *aml_start; + acpi_namespace_node *node; /* Link back to parent node */ union acpi_operand_obj **elements; /* Array of pointers to Acpi_objects */ - union acpi_operand_obj **next_element; /* used only while initializing */ } ACPI_OBJECT_PACKAGE; -typedef struct /* DEVICE - has handle and notification handler/context */ -{ - ACPI_OBJECT_COMMON_HEADER - - union acpi_operand_obj *sys_handler; /* Handler for system notifies */ - union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ - union acpi_operand_obj *addr_handler; /* Handler for Address space */ - -} ACPI_OBJECT_DEVICE; - +/****************************************************************************** + * + * Complex data types + * + *****************************************************************************/ -typedef struct /* EVENT */ +typedef struct acpi_object_event { ACPI_OBJECT_COMMON_HEADER void *semaphore; @@ -186,7 +171,7 @@ #define INFINITE_CONCURRENCY 0xFF -typedef struct /* METHOD */ +typedef struct acpi_object_method { ACPI_OBJECT_COMMON_HEADER u8 method_flags; @@ -204,80 +189,96 @@ } ACPI_OBJECT_METHOD; -typedef struct acpi_obj_mutex /* MUTEX */ +typedef struct acpi_object_mutex { ACPI_OBJECT_COMMON_HEADER u16 sync_level; u16 acquisition_depth; + struct acpi_thread_state *owner_thread; void *semaphore; - void *owner; union acpi_operand_obj *prev; /* Link for list of acquired mutexes */ union acpi_operand_obj *next; /* Link for list of acquired mutexes */ } ACPI_OBJECT_MUTEX; -typedef struct /* REGION */ +typedef struct acpi_object_region { ACPI_OBJECT_COMMON_HEADER u8 space_id; - u32 length; - ACPI_PHYSICAL_ADDRESS address; - union acpi_operand_obj *extra; /* Pointer to executable AML (in region definition) */ union acpi_operand_obj *addr_handler; /* Handler for system notifies */ acpi_namespace_node *node; /* containing object */ union acpi_operand_obj *next; + u32 length; + ACPI_PHYSICAL_ADDRESS address; } ACPI_OBJECT_REGION; -typedef struct /* POWER RESOURCE - has Handle and notification handler/context*/ +/****************************************************************************** + * + * Objects that can be notified. All share a common Notify_info area. + * + *****************************************************************************/ + +typedef struct acpi_object_notify_common /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + +} ACPI_OBJECT_NOTIFY_COMMON; + + +typedef struct acpi_object_device { ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO + +} ACPI_OBJECT_DEVICE; + + +typedef struct acpi_object_power_resource +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO u32 system_level; u32 resource_order; - union acpi_operand_obj *sys_handler; /* Handler for system notifies */ - union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ - } ACPI_OBJECT_POWER_RESOURCE; -typedef struct /* PROCESSOR - has Handle and notification handler/context*/ +typedef struct acpi_object_processor { ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO u32 proc_id; u32 length; ACPI_IO_ADDRESS address; - union acpi_operand_obj *sys_handler; /* Handler for system notifies */ - union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ - union acpi_operand_obj *addr_handler; /* Handler for Address space */ - } ACPI_OBJECT_PROCESSOR; -typedef struct /* THERMAL ZONE - has Handle and Handler/Context */ +typedef struct acpi_object_thermal_zone { ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO - union acpi_operand_obj *sys_handler; /* Handler for system notifies */ - union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ - union acpi_operand_obj *addr_handler; /* Handler for Address space */ } ACPI_OBJECT_THERMAL_ZONE; -/* +/****************************************************************************** + * * Fields. All share a common header/info field. - */ + * + *****************************************************************************/ -typedef struct /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ +typedef struct acpi_object_field_common /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO @@ -286,7 +287,7 @@ } ACPI_OBJECT_FIELD_COMMON; -typedef struct /* REGION FIELD */ +typedef struct acpi_object_region_field { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO @@ -295,18 +296,18 @@ } ACPI_OBJECT_REGION_FIELD; -typedef struct /* BANK FIELD */ +typedef struct acpi_object_bank_field { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_obj *region_obj; /* Containing Op_region object */ - union acpi_operand_obj *bank_register_obj; /* Bank_select Register object */ + union acpi_operand_obj *bank_obj; /* Bank_select Register object */ } ACPI_OBJECT_BANK_FIELD; -typedef struct /* INDEX FIELD */ +typedef struct acpi_object_index_field { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO @@ -324,23 +325,23 @@ /* The Buffer_field is different in that it is part of a Buffer, not an Op_region */ -typedef struct /* BUFFER FIELD */ +typedef struct acpi_object_buffer_field { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO - union acpi_operand_obj *extra; /* Pointer to executable AML (in field definition) */ - acpi_namespace_node *node; /* Parent (containing) object node */ union acpi_operand_obj *buffer_obj; /* Containing Buffer object */ } ACPI_OBJECT_BUFFER_FIELD; -/* - * Handlers - */ +/****************************************************************************** + * + * Objects for handlers + * + *****************************************************************************/ -typedef struct /* NOTIFY HANDLER */ +typedef struct acpi_object_notify_handler { ACPI_OBJECT_COMMON_HEADER @@ -353,10 +354,10 @@ /* Flags for address handler */ -#define ADDR_HANDLER_DEFAULT_INSTALLED 0x1 +#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x1 -typedef struct /* ADDRESS HANDLER */ +typedef struct acpi_object_addr_handler { ACPI_OBJECT_COMMON_HEADER @@ -373,12 +374,17 @@ } ACPI_OBJECT_ADDR_HANDLER; +/****************************************************************************** + * + * Special internal objects + * + *****************************************************************************/ + /* * The Reference object type is used for these opcodes: * Arg[0-6], Local[0-7], Index_op, Name_op, Zero_op, One_op, Ones_op, Debug_op */ - -typedef struct /* Reference - Local object type */ +typedef struct acpi_object_reference { ACPI_OBJECT_COMMON_HEADER @@ -400,8 +406,7 @@ * * Currently: Region and Field_unit types */ - -typedef struct /* EXTRA */ +typedef struct acpi_object_extra { ACPI_OBJECT_COMMON_HEADER u8 byte_fill1; @@ -414,38 +419,104 @@ } ACPI_OBJECT_EXTRA; +/* Additional data that can be attached to namespace nodes */ + +typedef struct acpi_object_data +{ + ACPI_OBJECT_COMMON_HEADER + ACPI_OBJECT_HANDLER handler; + void *pointer; + +} ACPI_OBJECT_DATA; + + +/* Structure used when objects are cached for reuse */ + +typedef struct acpi_object_cache_list +{ + ACPI_OBJECT_COMMON_HEADER + union acpi_operand_obj *next; /* Link for object cache and internal lists*/ + +} ACPI_OBJECT_CACHE_LIST; + + /****************************************************************************** * - * acpi_operand_object Descriptor - a giant union of all of the above + * acpi_operand_object Descriptor - a giant union of all of the above * *****************************************************************************/ typedef union acpi_operand_obj { ACPI_OBJECT_COMMON common; - ACPI_OBJECT_CACHE_LIST cache; + ACPI_OBJECT_INTEGER integer; ACPI_OBJECT_STRING string; ACPI_OBJECT_BUFFER buffer; ACPI_OBJECT_PACKAGE package; - ACPI_OBJECT_BUFFER_FIELD buffer_field; - ACPI_OBJECT_DEVICE device; + ACPI_OBJECT_EVENT event; ACPI_OBJECT_METHOD method; ACPI_OBJECT_MUTEX mutex; ACPI_OBJECT_REGION region; + + ACPI_OBJECT_NOTIFY_COMMON common_notify; + ACPI_OBJECT_DEVICE device; ACPI_OBJECT_POWER_RESOURCE power_resource; ACPI_OBJECT_PROCESSOR processor; ACPI_OBJECT_THERMAL_ZONE thermal_zone; + ACPI_OBJECT_FIELD_COMMON common_field; ACPI_OBJECT_REGION_FIELD field; + ACPI_OBJECT_BUFFER_FIELD buffer_field; ACPI_OBJECT_BANK_FIELD bank_field; ACPI_OBJECT_INDEX_FIELD index_field; - ACPI_OBJECT_REFERENCE reference; + ACPI_OBJECT_NOTIFY_HANDLER notify_handler; ACPI_OBJECT_ADDR_HANDLER addr_handler; + + ACPI_OBJECT_REFERENCE reference; ACPI_OBJECT_EXTRA extra; + ACPI_OBJECT_DATA data; + ACPI_OBJECT_CACHE_LIST cache; } acpi_operand_object; + + +/****************************************************************************** + * + * ACPI_DESCRIPTOR - objects that share a common descriptor identifier + * + *****************************************************************************/ + + +/* Object descriptor types */ + +#define ACPI_DESC_TYPE_CACHED 0x11 /* Used only when object is cached */ +#define ACPI_DESC_TYPE_STATE 0x20 +#define ACPI_DESC_TYPE_STATE_UPDATE 0x21 +#define ACPI_DESC_TYPE_STATE_PACKAGE 0x22 +#define ACPI_DESC_TYPE_STATE_CONTROL 0x23 +#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x24 +#define ACPI_DESC_TYPE_STATE_PSCOPE 0x25 +#define ACPI_DESC_TYPE_STATE_WSCOPE 0x26 +#define ACPI_DESC_TYPE_STATE_RESULT 0x27 +#define ACPI_DESC_TYPE_STATE_NOTIFY 0x28 +#define ACPI_DESC_TYPE_STATE_THREAD 0x29 +#define ACPI_DESC_TYPE_WALK 0x44 +#define ACPI_DESC_TYPE_PARSER 0x66 +#define ACPI_DESC_TYPE_OPERAND 0x88 +#define ACPI_DESC_TYPE_NAMED 0xAA + + +typedef union acpi_desc +{ + u8 descriptor_id; /* To differentiate various internal objs */\ + acpi_operand_object object; + acpi_namespace_node node; + acpi_parse_object op; + +} ACPI_DESCRIPTOR; + #endif /* _ACOBJECT_H */ diff -Nur linux-2.4.19/drivers/acpi/include/acoutput.h linux-2.4.19-sgi211r3/drivers/acpi/include/acoutput.h --- linux-2.4.19/drivers/acpi/include/acoutput.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acoutput.h Fri Apr 26 11:07:18 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acoutput.h -- debug output - * $Revision: 84 $ + * $Revision: 86 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,25 +46,18 @@ #define ACPI_DEBUGGER 0x00000200 #define ACPI_OS_SERVICES 0x00000400 -#define ACPI_BUS 0x00010000 -#define ACPI_SYSTEM 0x00020000 -#define ACPI_POWER 0x00040000 -#define ACPI_EC 0x00080000 -#define ACPI_AC_ADAPTER 0x00100000 -#define ACPI_BATTERY 0x00200000 -#define ACPI_BUTTON 0x00400000 -#define ACPI_PROCESSOR 0x00800000 -#define ACPI_THERMAL 0x01000000 -#define ACPI_FAN 0x02000000 - -#define ACPI_ALL_COMPONENTS 0x0FFFFFFF +#define ACPI_ALL_COMPONENTS 0x00000FFF #define ACPI_COMPONENT_DEFAULT (ACPI_ALL_COMPONENTS) +/* Component IDs for ACPI tools and utilities */ + +#define ACPI_COMPILER 0x00001000 +#define ACPI_TOOLS 0x00002000 -#define ACPI_COMPILER 0x10000000 -#define ACPI_TOOLS 0x20000000 +/* Component IDs reserved for ACPI drivers */ +#define ACPI_ALL_DRIVERS 0xFFFF0000 /* * Raw debug output levels, do not use these in the DEBUG_PRINT macros diff -Nur linux-2.4.19/drivers/acpi/include/acparser.h linux-2.4.19-sgi211r3/drivers/acpi/include/acparser.h --- linux-2.4.19/drivers/acpi/include/acparser.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acparser.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: acparser.h - AML Parser subcomponent prototypes and defines - * $Revision: 54 $ + * $Revision: 59 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,15 +28,11 @@ #define __ACPARSER_H__ -#define OP_HAS_RETURN_VALUE 1 +#define OP_HAS_RETURN_VALUE 1 /* variable # arguments */ -#define ACPI_VAR_ARGS ACPI_UINT32_MAX - -/* maximum virtual address */ - -#define ACPI_MAX_AML ((u8 *)(~0UL)) +#define ACPI_VAR_ARGS ACPI_UINT32_MAX #define ACPI_PARSE_DELETE_TREE 0x0001 @@ -48,7 +44,8 @@ #define ACPI_PARSE_EXECUTE 0x0030 #define ACPI_PARSE_MODE_MASK 0x0030 -/* psapi - Parser external interfaces */ + +/* Parser external interfaces */ acpi_status acpi_psx_load_table ( @@ -61,6 +58,7 @@ acpi_operand_object **params, acpi_operand_object **return_obj_desc); + /****************************************************************************** * * Parser interfaces @@ -85,8 +83,8 @@ void acpi_ps_get_next_simple_arg ( acpi_parse_state *parser_state, - u32 arg_type, /* type of argument */ - acpi_parse_object *arg); /* (OUT) argument data */ + u32 arg_type, + acpi_parse_object *arg); void acpi_ps_get_next_namepath ( @@ -106,6 +104,19 @@ u32 *arg_count); +/* psfind */ + +acpi_parse_object * +acpi_ps_find_name ( + acpi_parse_object *scope, + u32 name, + u32 opcode); + +acpi_parse_object* +acpi_ps_get_parent ( + acpi_parse_object *op); + + /* psopcode - AML Opcode information */ const acpi_opcode_info * @@ -119,6 +130,21 @@ /* psparse - top level parsing routines */ +u32 +acpi_ps_get_opcode_size ( + u32 opcode); + +void +acpi_ps_complete_this_op ( + acpi_walk_state *walk_state, + acpi_parse_object *op); + +acpi_status +acpi_ps_next_parse_state ( + acpi_walk_state *walk_state, + acpi_parse_object *op, + acpi_status callback_status); + acpi_status acpi_ps_find_object ( acpi_walk_state *walk_state, @@ -232,6 +258,10 @@ acpi_walk_state *walk_state, acpi_parse_object *op, acpi_parse_upwards ascending_callback); + +acpi_status +acpi_ps_delete_completed_op ( + acpi_walk_state *walk_state); /* psutils - parser utilities */ diff -Nur linux-2.4.19/drivers/acpi/include/acpi.h linux-2.4.19-sgi211r3/drivers/acpi/include/acpi.h --- linux-2.4.19/drivers/acpi/include/acpi.h Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acpi.h Fri Apr 26 11:07:18 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acpi.h - Master include file, Publics and external data. - * $Revision: 54 $ + * $Revision: 55 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff -Nur linux-2.4.19/drivers/acpi/include/acpiosxf.h linux-2.4.19-sgi211r3/drivers/acpi/include/acpiosxf.h --- linux-2.4.19/drivers/acpi/include/acpiosxf.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acpiosxf.h Fri Apr 26 11:07:18 2002 @@ -9,7 +9,7 @@ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,12 +62,12 @@ * Types specific to the OS service interfaces */ -typedef -u32 (*OSD_HANDLER) ( +typedef u32 +(ACPI_SYSTEM_XFACE *OSD_HANDLER) ( void *context); -typedef -void (*OSD_EXECUTION_CALLBACK) ( +typedef void +(ACPI_SYSTEM_XFACE *OSD_EXECUTION_CALLBACK) ( void *context); @@ -83,10 +83,20 @@ acpi_os_terminate ( void); + +/* + * ACPI Table interfaces + */ + acpi_status acpi_os_get_root_pointer ( u32 flags, - ACPI_PHYSICAL_ADDRESS *rsdp_physical_address); + ACPI_POINTER *address); + +acpi_status +acpi_os_table_override ( + acpi_table_header *existing_table, + acpi_table_header **new_table); /* @@ -121,11 +131,7 @@ void * acpi_os_allocate ( - u32 size); - -void * -acpi_os_callocate ( - u32 size); + ACPI_SIZE size); void acpi_os_free ( @@ -134,13 +140,13 @@ acpi_status acpi_os_map_memory ( ACPI_PHYSICAL_ADDRESS physical_address, - u32 length, + ACPI_SIZE size, void **logical_address); void acpi_os_unmap_memory ( void *logical_address, - u32 length); + ACPI_SIZE size); acpi_status acpi_os_get_physical_address ( @@ -202,7 +208,7 @@ acpi_status acpi_os_write_port ( ACPI_IO_ADDRESS address, - NATIVE_UINT value, + acpi_integer value, u32 width); @@ -220,7 +226,7 @@ acpi_status acpi_os_write_memory ( ACPI_PHYSICAL_ADDRESS address, - NATIVE_UINT value, + acpi_integer value, u32 width); @@ -240,7 +246,7 @@ acpi_os_write_pci_configuration ( acpi_pci_id *pci_id, u32 register, - NATIVE_UINT value, + acpi_integer value, u32 width); @@ -272,12 +278,12 @@ * Debug print routines */ -s32 +void ACPI_INTERNAL_VAR_XFACE acpi_os_printf ( const NATIVE_CHAR *format, ...); -s32 +void acpi_os_vprintf ( const NATIVE_CHAR *format, va_list args); diff -Nur linux-2.4.19/drivers/acpi/include/acpixf.h linux-2.4.19-sgi211r3/drivers/acpi/include/acpixf.h --- linux-2.4.19/drivers/acpi/include/acpixf.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acpixf.h Tue Aug 27 19:53:13 2002 @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,6 +67,14 @@ acpi_format_exception ( acpi_status exception); +acpi_status +acpi_purge_cached_objects ( + void); + +acpi_status +acpi_install_initialization_handler ( + ACPI_INIT_HANDLER handler, + u32 function); /* * ACPI Memory manager @@ -92,7 +100,7 @@ acpi_status acpi_find_root_pointer ( u32 flags, - ACPI_PHYSICAL_ADDRESS *rsdp_physical_address); + ACPI_POINTER *rsdp_address); acpi_status acpi_load_tables ( @@ -158,6 +166,23 @@ acpi_string pathname, acpi_handle *ret_handle); +acpi_status +acpi_attach_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler, + void *data); + +acpi_status +acpi_detach_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler); + +acpi_status +acpi_get_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler, + void **data); + /* * Object manipulation and enumeration @@ -244,11 +269,12 @@ acpi_status acpi_acquire_global_lock ( - void); + u32 timeout, + u32 *handle); acpi_status acpi_release_global_lock ( - void); + u32 handle); acpi_status acpi_remove_gpe_handler ( @@ -308,6 +334,18 @@ */ acpi_status +acpi_get_register ( + u32 register_id, + u32 *return_value, + u32 flags); + +acpi_status +acpi_set_register ( + u32 register_id, + u32 value, + u32 flags); + +acpi_status acpi_set_firmware_waking_vector ( ACPI_PHYSICAL_ADDRESS physical_address); @@ -316,11 +354,22 @@ ACPI_PHYSICAL_ADDRESS *physical_address); acpi_status +acpi_get_sleep_type_data ( + u8 sleep_state, + u8 *slp_typ_a, + u8 *slp_typ_b); + +acpi_status +acpi_enter_sleep_state_prep ( + u8 sleep_state); + +acpi_status acpi_enter_sleep_state ( - u8 sleep_state); + u8 sleep_state); acpi_status acpi_leave_sleep_state ( - u8 sleep_state); + u8 sleep_state); + #endif /* __ACXFACE_H__ */ diff -Nur linux-2.4.19/drivers/acpi/include/acresrc.h linux-2.4.19-sgi211r3/drivers/acpi/include/acresrc.h --- linux-2.4.19/drivers/acpi/include/acresrc.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acresrc.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acresrc.h - Resource Manager function prototypes - * $Revision: 25 $ + * $Revision: 33 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,25 +55,73 @@ acpi_status acpi_rs_create_resource_list ( acpi_operand_object *byte_stream_buffer, - u8 *output_buffer, - u32 *output_buffer_length); + acpi_buffer *output_buffer); acpi_status acpi_rs_create_byte_stream ( acpi_resource *linked_list_buffer, - u8 *output_buffer, - u32 *output_buffer_length); + acpi_buffer *output_buffer); acpi_status acpi_rs_create_pci_routing_table ( - acpi_operand_object *method_return_object, - u8 *output_buffer, - u32 *output_buffer_length); + acpi_operand_object *package_object, + acpi_buffer *output_buffer); /* - *Function prototypes called from Acpi_rs_create*APIs + * Function prototypes called from Acpi_rs_create* */ +void +acpi_rs_dump_irq ( + acpi_resource_data *data); + +void +acpi_rs_dump_address16 ( + acpi_resource_data *data); + +void +acpi_rs_dump_address32 ( + acpi_resource_data *data); + +void +acpi_rs_dump_address64 ( + acpi_resource_data *data); + +void +acpi_rs_dump_dma ( + acpi_resource_data *data); + +void +acpi_rs_dump_io ( + acpi_resource_data *data); + +void +acpi_rs_dump_extended_irq ( + acpi_resource_data *data); + +void +acpi_rs_dump_fixed_io ( + acpi_resource_data *data); + +void +acpi_rs_dump_fixed_memory32 ( + acpi_resource_data *data); + +void +acpi_rs_dump_memory24 ( + acpi_resource_data *data); + +void +acpi_rs_dump_memory32 ( + acpi_resource_data *data); + +void +acpi_rs_dump_start_depend_fns ( + acpi_resource_data *data); + +void +acpi_rs_dump_vendor_specific ( + acpi_resource_data *data); void acpi_rs_dump_resource_list ( @@ -90,228 +138,227 @@ u32 *size); acpi_status -acpi_rs_calculate_list_length ( +acpi_rs_get_list_length ( u8 *byte_stream_buffer, u32 byte_stream_buffer_length, - u32 *size_needed); + ACPI_SIZE *size_needed); acpi_status -acpi_rs_calculate_byte_stream_length ( +acpi_rs_get_byte_stream_length ( acpi_resource *linked_list_buffer, - u32 *size_needed); + ACPI_SIZE *size_needed); acpi_status -acpi_rs_calculate_pci_routing_table_length ( +acpi_rs_get_pci_routing_table_length ( acpi_operand_object *package_object, - u32 *buffer_size_needed); + ACPI_SIZE *buffer_size_needed); acpi_status acpi_rs_byte_stream_to_list ( u8 *byte_stream_buffer, u32 byte_stream_buffer_length, - u8 **output_buffer); + u8 *output_buffer); acpi_status acpi_rs_list_to_byte_stream ( acpi_resource *linked_list, - u32 byte_stream_size_needed, - u8 **output_buffer); + ACPI_SIZE byte_stream_size_needed, + u8 *output_buffer); acpi_status acpi_rs_io_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_fixed_io_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_io_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_fixed_io_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_irq_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_irq_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_dma_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_dma_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_address16_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_address16_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_address32_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_address32_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_address64_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_address64_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status -acpi_rs_start_dependent_functions_resource ( +acpi_rs_start_depend_fns_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status -acpi_rs_end_dependent_functions_resource ( +acpi_rs_end_depend_fns_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status -acpi_rs_start_dependent_functions_stream ( +acpi_rs_start_depend_fns_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status -acpi_rs_end_dependent_functions_stream ( +acpi_rs_end_depend_fns_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_memory24_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_memory24_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_memory32_range_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size -); + ACPI_SIZE *structure_size); acpi_status acpi_rs_fixed_memory32_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_memory32_range_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_fixed_memory32_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_extended_irq_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_extended_irq_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_end_tag_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_end_tag_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); acpi_status acpi_rs_vendor_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size); + ACPI_SIZE *structure_size); acpi_status acpi_rs_vendor_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed); + ACPI_SIZE *bytes_consumed); u8 acpi_rs_get_resource_type ( diff -Nur linux-2.4.19/drivers/acpi/include/acstruct.h linux-2.4.19-sgi211r3/drivers/acpi/include/acstruct.h --- linux-2.4.19/drivers/acpi/include/acstruct.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acstruct.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acstruct.h - Internal structs - * $Revision: 10 $ + * $Revision: 19 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,12 +39,14 @@ * the tree (for whatever reason), and for control method execution. */ -#define NEXT_OP_DOWNWARD 1 -#define NEXT_OP_UPWARD 2 +#define ACPI_NEXT_OP_DOWNWARD 1 +#define ACPI_NEXT_OP_UPWARD 2 -#define WALK_NON_METHOD 0 -#define WALK_METHOD 1 -#define WALK_METHOD_RESTART 2 +#define ACPI_WALK_NON_METHOD 0 +#define ACPI_WALK_METHOD 1 +#define ACPI_WALK_METHOD_RESTART 2 +#define ACPI_WALK_CONST_REQUIRED 3 +#define ACPI_WALK_CONST_OPTIONAL 4 typedef struct acpi_walk_state { @@ -56,12 +58,12 @@ u8 num_operands; /* Stack pointer for Operands[] array */ u8 return_used; u8 walk_type; - u16 current_sync_level; /* Mutex Sync (nested acquire) level */ u16 opcode; /* Current AML opcode */ u32 arg_count; /* push for fixed or var args */ u32 aml_offset; u32 arg_types; u32 method_breakpoint; /* For single stepping */ + u32 user_breakpoint; /* User AML breakpoint */ u32 parse_flags; u32 prev_arg_types; @@ -86,49 +88,38 @@ union acpi_operand_obj *return_desc; /* Return object, if any */ acpi_generic_state *scope_info; /* Stack of nested scopes */ -/* TBD: Obsolete with removal of WALK procedure ? */ acpi_parse_object *prev_op; /* Last op that was processed */ acpi_parse_object *next_op; /* next op to be processed */ - - acpi_parse_downwards descending_callback; acpi_parse_upwards ascending_callback; - struct acpi_walk_list *walk_list; + ACPI_THREAD_STATE *thread; struct acpi_walk_state *next; /* Next Walk_state in list */ } acpi_walk_state; -/* - * Walk list - head of a tree of walk states. Multiple walk states are created when there - * are nested control methods executing. - */ -typedef struct acpi_walk_list -{ - - acpi_walk_state *walk_state; - ACPI_OBJECT_MUTEX acquired_mutex_list; /* List of all currently acquired mutexes */ - -} acpi_walk_list; - - /* Info used by Acpi_ps_init_objects */ typedef struct acpi_init_walk_info { u16 method_count; + u16 device_count; u16 op_region_count; u16 field_count; + u16 buffer_count; + u16 package_count; u16 op_region_init; u16 field_init; + u16 buffer_init; + u16 package_init; u16 object_count; acpi_table_desc *table_desc; } acpi_init_walk_info; -/* Info used by TBD */ +/* Info used by Acpi_ns_initialize_devices */ typedef struct acpi_device_walk_info { diff -Nur linux-2.4.19/drivers/acpi/include/actables.h linux-2.4.19-sgi211r3/drivers/acpi/include/actables.h --- linux-2.4.19/drivers/acpi/include/actables.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/actables.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actables.h - ACPI table management - * $Revision: 32 $ + * $Revision: 41 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,6 +63,15 @@ * tbget - Table "get" routines */ +void +acpi_tb_table_override ( + acpi_table_desc *table_info); + +acpi_status +acpi_tb_get_table_with_override ( + ACPI_POINTER *address, + acpi_table_desc *table_info); + acpi_status acpi_tb_get_table_ptr ( acpi_table_type table_type, @@ -71,22 +80,16 @@ acpi_status acpi_tb_get_table ( - ACPI_PHYSICAL_ADDRESS physical_address, - acpi_table_header *buffer_ptr, + ACPI_POINTER *address, acpi_table_desc *table_info); acpi_status acpi_tb_verify_rsdp ( - ACPI_PHYSICAL_ADDRESS RSDP_physical_address); - -acpi_status -acpi_tb_get_table_facs ( - acpi_table_header *buffer_ptr, - acpi_table_desc *table_info); + ACPI_POINTER *address); -ACPI_PHYSICAL_ADDRESS +void acpi_tb_get_rsdt_address ( - void); + ACPI_POINTER *out_address); acpi_status acpi_tb_validate_rsdt ( @@ -94,9 +97,9 @@ acpi_status acpi_tb_get_table_pointer ( - ACPI_PHYSICAL_ADDRESS physical_address, + ACPI_POINTER *address, u32 flags, - u32 *size, + ACPI_SIZE *size, acpi_table_header **table_ptr); /* @@ -105,8 +108,7 @@ acpi_status acpi_tb_get_all_tables ( - u32 number_of_tables, - acpi_table_header *buffer_ptr); + u32 number_of_tables); /* @@ -115,12 +117,15 @@ acpi_status acpi_tb_install_table ( - acpi_table_header *table_ptr, + acpi_table_desc *table_info); + +acpi_status +acpi_tb_match_signature ( + NATIVE_CHAR *signature, acpi_table_desc *table_info); acpi_status acpi_tb_recognize_table ( - acpi_table_header *table_ptr, acpi_table_desc *table_info); acpi_status @@ -178,9 +183,16 @@ */ acpi_status +acpi_tb_find_table ( + NATIVE_CHAR *signature, + NATIVE_CHAR *oem_id, + NATIVE_CHAR *oem_table_id, + acpi_table_header **table_ptr); + +acpi_status acpi_tb_map_acpi_table ( ACPI_PHYSICAL_ADDRESS physical_address, - u32 *size, + ACPI_SIZE *size, acpi_table_header **logical_address); acpi_status diff -Nur linux-2.4.19/drivers/acpi/include/actbl.h linux-2.4.19-sgi211r3/drivers/acpi/include/actbl.h --- linux-2.4.19/drivers/acpi/include/actbl.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/actbl.h Fri Apr 26 11:07:18 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actbl.h - Table data structures defined in ACPI specification - * $Revision: 46 $ + * $Revision: 52 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,6 @@ /* * Values for description table header signatures */ - #define RSDP_NAME "RSDP" #define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */ #define APIC_SIG "APIC" /* Multiple APIC Description Table */ @@ -42,7 +41,7 @@ #define XSDT_SIG "XSDT" /* Extended System Description Table */ #define SSDT_SIG "SSDT" /* Secondary System Description Table */ #define SBST_SIG "SBST" /* Smart Battery Specification Table */ -#define SPIC_SIG "SPIC" /* iosapic table */ +#define SPIC_SIG "SPIC" /* IOSAPIC table */ #define BOOT_SIG "BOOT" /* Boot table */ @@ -75,29 +74,27 @@ * Architecture-independent tables * The architecture dependent tables are in separate files */ - typedef struct /* Root System Descriptor Pointer */ { - NATIVE_CHAR signature [8]; /* contains "RSD PTR " */ - u8 checksum; /* to make sum of struct == 0 */ + NATIVE_CHAR signature [8]; /* ACPI signature, contains "RSD PTR " */ + u8 checksum; /* To make sum of struct == 0 */ NATIVE_CHAR oem_id [6]; /* OEM identification */ u8 revision; /* Must be 0 for 1.0, 2 for 2.0 */ u32 rsdt_physical_address; /* 32-bit physical address of RSDT */ u32 length; /* XSDT Length in bytes including hdr */ u64 xsdt_physical_address; /* 64-bit physical address of XSDT */ u8 extended_checksum; /* Checksum of entire table */ - NATIVE_CHAR reserved [3]; /* reserved field must be 0 */ + NATIVE_CHAR reserved [3]; /* Reserved field must be 0 */ } RSDP_DESCRIPTOR; typedef struct /* ACPI common table header */ { - NATIVE_CHAR signature [4]; /* identifies type of table */ - u32 length; /* length of table, in bytes, - * including header */ - u8 revision; /* specification minor version # */ - u8 checksum; /* to make sum of entire table == 0 */ + NATIVE_CHAR signature [4]; /* ACPI signature (4 ASCII characters) */ + u32 length; /* Length of table, in bytes, including header */ + u8 revision; /* ACPI Specification minor version # */ + u8 checksum; /* To make sum of entire table == 0 */ NATIVE_CHAR oem_id [6]; /* OEM identification */ NATIVE_CHAR oem_table_id [8]; /* OEM table identification */ u32 oem_revision; /* OEM revision number */ @@ -118,7 +115,7 @@ typedef struct /* APIC Table */ { - acpi_table_header header; /* table header */ + acpi_table_header header; /* ACPI table header */ u32 local_apic_address; /* Physical address for accessing local APICs */ u32 PCATcompat : 1; /* a one indicates system also has dual 8259s */ u32 reserved1 : 31; @@ -138,7 +135,7 @@ { APIC_HEADER header; u8 processor_apic_id; /* ACPI processor id */ - u8 local_apic_id; /* processor's local APIC id */ + u8 local_apic_id; /* Processor's local APIC id */ u32 processor_enabled: 1; /* Processor is usable if set */ u32 reserved1 : 31; @@ -149,21 +146,21 @@ { APIC_HEADER header; u8 io_apic_id; /* I/O APIC ID */ - u8 reserved; /* reserved - must be zero */ + u8 reserved; /* Reserved - must be zero */ u32 io_apic_address; /* APIC's physical address */ - u32 vector; /* interrupt vector index where INTI + u32 vector; /* Interrupt vector index where INTI * lines start */ } IO_APIC; /* -** IA64 TODO: Add SAPIC Tables -*/ + * IA64 TBD: Add SAPIC Tables + */ /* -** IA64 TODO: Modify Smart Battery Description to comply with ACPI IA64 -** extensions. -*/ + * IA64 TBD: Modify Smart Battery Description to comply with ACPI IA64 + * extensions. + */ typedef struct /* Smart Battery Description Table */ { acpi_table_header header; @@ -182,7 +179,6 @@ * and type of memory allocation (mapped or allocated) for each * table for 1) when we exit, and 2) if a new table is installed */ - #define ACPI_MEM_NOT_ALLOCATED 0 #define ACPI_MEM_ALLOCATED 1 #define ACPI_MEM_MAPPED 2 @@ -191,7 +187,7 @@ #define ACPI_TABLE_SINGLE 0 #define ACPI_TABLE_MULTIPLE 1 - +#define ACPI_TABLE_EXECUTABLE 2 /* Data about each known table type */ @@ -199,19 +195,17 @@ { NATIVE_CHAR *name; NATIVE_CHAR *signature; + void **global_ptr; u8 sig_length; u8 flags; - u16 status; - void **global_ptr; } ACPI_TABLE_SUPPORT; + /* * Get the architecture-specific tables */ - -#include "actbl1.h" /* Acpi 1.0 table defintions */ -#include "actbl71.h" /* Acpi 0.71 IA-64 Extension table defintions */ +#include "actbl1.h" /* Acpi 1.0 table definitions */ #include "actbl2.h" /* Acpi 2.0 table definitions */ #endif /* __ACTBL_H__ */ diff -Nur linux-2.4.19/drivers/acpi/include/actbl1.h linux-2.4.19-sgi211r3/drivers/acpi/include/actbl1.h --- linux-2.4.19/drivers/acpi/include/actbl1.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/actbl1.h Fri Apr 26 11:07:18 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actbl1.h - ACPI 1.0 tables - * $Revision: 17 $ + * $Revision: 21 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,91 +28,88 @@ #pragma pack(1) -/*************************************/ -/* ACPI Specification Rev 1.0 for */ -/* the Root System Description Table */ -/*************************************/ +/* + * ACPI 1.0 Root System Description Table (RSDT) + */ typedef struct { - acpi_table_header header; /* Table header */ + acpi_table_header header; /* ACPI Table header */ u32 table_offset_entry [1]; /* Array of pointers to other */ /* ACPI tables */ } RSDT_DESCRIPTOR_REV1; -/***************************************/ -/* ACPI Specification Rev 1.0 for */ -/* the Firmware ACPI Control Structure */ -/***************************************/ +/* + * ACPI 1.0 Firmware ACPI Control Structure (FACS) + */ typedef struct { - NATIVE_CHAR signature[4]; /* signature "FACS" */ - u32 length; /* length of structure, in bytes */ - u32 hardware_signature; /* hardware configuration signature */ + NATIVE_CHAR signature[4]; /* ACPI Signature */ + u32 length; /* Length of structure, in bytes */ + u32 hardware_signature; /* Hardware configuration signature */ u32 firmware_waking_vector; /* ACPI OS waking vector */ u32 global_lock; /* Global Lock */ u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ - u32 reserved1 : 31; /* must be 0 */ - u8 resverved3 [40]; /* reserved - must be zero */ + u32 reserved1 : 31; /* Must be 0 */ + u8 resverved3 [40]; /* Reserved - must be zero */ } facs_descriptor_rev1; -/************************************/ -/* ACPI Specification Rev 1.0 for */ -/* the Fixed ACPI Description Table */ -/************************************/ +/* + * ACPI 1.0 Fixed ACPI Description Table (FADT) + */ typedef struct { - acpi_table_header header; /* table header */ + acpi_table_header header; /* ACPI Table header */ u32 firmware_ctrl; /* Physical address of FACS */ u32 dsdt; /* Physical address of DSDT */ u8 model; /* System Interrupt Model */ - u8 reserved1; /* reserved */ + u8 reserved1; /* Reserved */ u16 sci_int; /* System vector of SCI interrupt */ u32 smi_cmd; /* Port address of SMI command port */ - u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */ - u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */ + u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ + u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - u8 reserved2; /* reserved - must be zero */ + u8 reserved2; /* Reserved - must be zero */ u32 pm1a_evt_blk; /* Port address of Power Mgt 1a Acpi_event Reg Blk */ u32 pm1b_evt_blk; /* Port address of Power Mgt 1b Acpi_event Reg Blk */ u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u32 gpe0blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ + u32 gpe0_blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ u32 gpe1_blk; /* Port addr of General Purpose Acpi_event 1 Reg Blk */ u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0blk_len; /* Byte Length of ports at gpe0_blk */ + u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - u8 gpe1_base; /* offset in gpe model where gpe1 events start */ - u8 reserved3; /* reserved */ - u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */ - u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */ + u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ + u8 reserved3; /* Reserved */ + u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ + u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ u16 flush_size; /* Size of area read to flush caches */ u16 flush_stride; /* Stride used in flushing caches */ - u8 duty_offset; /* bit location of duty cycle field in p_cnt reg */ - u8 duty_width; /* bit width of duty cycle field in p_cnt reg */ - u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */ - u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* index to century in RTC CMOS RAM */ - u8 reserved4; /* reserved */ - u8 reserved4a; /* reserved */ - u8 reserved4b; /* reserved */ - u32 wb_invd : 1; /* wbinvd instruction works properly */ - u32 wb_invd_flush : 1; /* wbinvd flushes but does not invalidate */ - u32 proc_c1 : 1; /* all processors support C1 state */ + u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */ + u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */ + u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ + u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ + u8 century; /* Index to century in RTC CMOS RAM */ + u8 reserved4; /* Reserved */ + u8 reserved4a; /* Reserved */ + u8 reserved4b; /* Reserved */ + u32 wb_invd : 1; /* The wbinvd instruction works properly */ + u32 wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ + u32 proc_c1 : 1; /* All processors support C1 state */ u32 plvl2_up : 1; /* C2 state works on MP system */ u32 pwr_button : 1; /* Power button is handled as a generic feature */ u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ - u32 tmr_val_ext : 1; /* tmr_val is 32 bits */ - u32 reserved5 : 23; /* reserved - must be zero */ + u32 tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ + u32 reserved5 : 23; /* Reserved - must be zero */ } fadt_descriptor_rev1; diff -Nur linux-2.4.19/drivers/acpi/include/actbl2.h linux-2.4.19-sgi211r3/drivers/acpi/include/actbl2.h --- linux-2.4.19/drivers/acpi/include/actbl2.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/actbl2.h Fri Apr 26 11:07:18 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actbl2.h - ACPI Specification Revision 2.0 Tables - * $Revision: 24 $ + * $Revision: 27 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,48 +49,48 @@ #pragma pack(1) /* - * ACPI Specification Rev 2.0 for the Root System Description Table + * ACPI 2.0 Root System Description Table (RSDT) */ typedef struct { - acpi_table_header header; /* Table header */ + acpi_table_header header; /* ACPI table header */ u32 table_offset_entry [1]; /* Array of pointers to */ - /* other tables' headers */ + /* ACPI table headers */ } RSDT_DESCRIPTOR_REV2; /* - * ACPI Specification Rev 2.0 for the Extended System Description Table (XSDT) + * ACPI 2.0 Extended System Description Table (XSDT) */ typedef struct { - acpi_table_header header; /* Table header */ + acpi_table_header header; /* ACPI table header */ u64 table_offset_entry [1]; /* Array of pointers to */ - /* other tables' headers */ + /* ACPI table headers */ } XSDT_DESCRIPTOR_REV2; /* - * ACPI Specification Rev 2.0 for the Firmware ACPI Control Structure + * ACPI 2.0 Firmware ACPI Control Structure (FACS) */ typedef struct { - NATIVE_CHAR signature[4]; /* signature "FACS" */ - u32 length; /* length of structure, in bytes */ - u32 hardware_signature; /* hardware configuration signature */ + NATIVE_CHAR signature[4]; /* ACPI signature */ + u32 length; /* Length of structure, in bytes */ + u32 hardware_signature; /* Hardware configuration signature */ u32 firmware_waking_vector; /* 32bit physical address of the Firmware Waking Vector. */ u32 global_lock; /* Global Lock used to synchronize access to shared hardware resources */ - u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ - u32 reserved1 : 31; /* must be 0 */ + u32 S4bios_f : 1; /* S4Bios_f - Indicates if S4BIOS support is present */ + u32 reserved1 : 31; /* Must be 0 */ u64 Xfirmware_waking_vector; /* 64bit physical address of the Firmware Waking Vector. */ u8 version; /* Version of this table */ - u8 reserved3 [31]; /* reserved - must be zero */ + u8 reserved3 [31]; /* Reserved - must be zero */ } facs_descriptor_rev2; /* - * ACPI Specification Rev 2.0 for the Generic Address Structure (GAS) + * ACPI 2.0 Generic Address Structure (GAS) */ typedef struct { @@ -104,64 +104,64 @@ /* - * ACPI Specification Rev 2.0 for the Fixed ACPI Description Table + * ACPI 2.0 Fixed ACPI Description Table (FADT) */ typedef struct { - acpi_table_header header; /* table header */ + acpi_table_header header; /* ACPI table header */ u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ u32 V1_dsdt; /* 32-bit physical address of DSDT */ u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ u16 sci_int; /* System vector of SCI interrupt */ u32 smi_cmd; /* Port address of SMI command port */ - u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */ - u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */ + u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ + u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - u8 pstate_cnt; /* processor performance state control*/ + u8 pstate_cnt; /* Processor performance state control*/ u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a Acpi_event Reg Blk */ u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b Acpi_event Reg Blk */ u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u32 V1_gpe0blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ + u32 V1_gpe0_blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ u32 V1_gpe1_blk; /* Port addr of General Purpose Acpi_event 1 Reg Blk */ u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0blk_len; /* Byte Length of ports at gpe0_blk */ + u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - u8 gpe1_base; /* offset in gpe model where gpe1 events start */ + u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ - u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */ - u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */ - u16 flush_size; /* number of flush strides that need to be read */ + u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ + u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ + u16 flush_size; /* Number of flush strides that need to be read */ u16 flush_stride; /* Processor's memory cache line width, in bytes */ u8 duty_offset; /* Processor_’s duty cycle index in processor's P_CNT reg*/ u8 duty_width; /* Processor_’s duty cycle value bit width in P_CNT register.*/ - u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */ - u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* index to century in RTC CMOS RAM */ + u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ + u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ + u8 century; /* Index to century in RTC CMOS RAM */ u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ - u8 reserved2; /* reserved */ - u32 wb_invd : 1; /* wbinvd instruction works properly */ - u32 wb_invd_flush : 1; /* wbinvd flushes but does not invalidate */ - u32 proc_c1 : 1; /* all processors support C1 state */ + u8 reserved2; /* Reserved */ + u32 wb_invd : 1; /* The wbinvd instruction works properly */ + u32 wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ + u32 proc_c1 : 1; /* All processors support C1 state */ u32 plvl2_up : 1; /* C2 state works on MP system */ u32 pwr_button : 1; /* Power button is handled as a generic feature */ u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ - u32 tmr_val_ext : 1; /* tmr_val is 32 bits */ + u32 tmr_val_ext : 1; /* Indicates tmr_val is 32 bits 0=24-bits*/ u32 dock_cap : 1; /* Supports Docking */ u32 reset_reg_sup : 1; /* Indicates system supports system reset via the FADT RESET_REG*/ u32 sealed_case : 1; /* Indicates system has no internal expansion capabilities and case is sealed. */ u32 headless : 1; /* Indicates system does not have local video capabilities or local input devices.*/ u32 cpu_sw_sleep : 1; /* Indicates to OSPM that a processor native instruction */ - /* must be executed after writing the SLP_TYPx register. */ - u32 reserved6 : 18; /* reserved - must be zero */ + /* Must be executed after writing the SLP_TYPx register. */ + u32 reserved6 : 18; /* Reserved - must be zero */ acpi_generic_address reset_register; /* Reset register address in GAS format */ u8 reset_value; /* Value to write to the Reset_register port to reset the system. */ @@ -174,7 +174,7 @@ acpi_generic_address Xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */ acpi_generic_address Xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */ acpi_generic_address Xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */ - acpi_generic_address Xgpe0blk; /* Extended General Purpose Acpi_event 0 Reg Blk address */ + acpi_generic_address Xgpe0_blk; /* Extended General Purpose Acpi_event 0 Reg Blk address */ acpi_generic_address Xgpe1_blk; /* Extended General Purpose Acpi_event 1 Reg Blk address */ } fadt_descriptor_rev2; diff -Nur linux-2.4.19/drivers/acpi/include/actbl71.h linux-2.4.19-sgi211r3/drivers/acpi/include/actbl71.h --- linux-2.4.19/drivers/acpi/include/actbl71.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/actbl71.h Fri Apr 26 11:07:18 2002 @@ -3,12 +3,12 @@ * Name: actbl71.h - IA-64 Extensions to the ACPI Spec Rev. 0.71 * This file includes tables specific to this * specification revision. - * $Revision: 11 $ + * $Revision: 12 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -111,13 +111,13 @@ u64 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ u64 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ u64 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u64 gpe0blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ + u64 gpe0_blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */ u64 gpe1_blk; /* Port addr of General Purpose Acpi_event 1 Reg Blk */ u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0blk_len; /* Byte Length of ports at gpe0_blk */ + u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ u8 gpe1_base; /* offset in gpe model where gpe1 events start */ u8 reserved3; /* reserved */ diff -Nur linux-2.4.19/drivers/acpi/include/actypes.h linux-2.4.19-sgi211r3/drivers/acpi/include/actypes.h --- linux-2.4.19/drivers/acpi/include/actypes.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/actypes.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: actypes.h - Common data types for the entire ACPI subsystem - * $Revision: 193 $ + * $Revision: 237 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,13 +28,23 @@ /*! [Begin] no source code translation (keep the typedefs) */ + + +/* + * Data type ranges + */ +#define ACPI_UINT8_MAX (UINT8) 0xFF +#define ACPI_UINT16_MAX (UINT16) 0xFFFF +#define ACPI_UINT32_MAX (UINT32) 0xFFFFFFFF +#define ACPI_UINT64_MAX (UINT64) 0xFFFFFFFFFFFFFFFF +#define ACPI_ASCII_MAX 0x7F + + + /* * Data types - Fixed across all compilation models * * BOOLEAN Logical Boolean. - * 1 byte value containing a 0 for FALSE or a 1 for TRUE. - * Other values are undefined. - * * INT8 8-bit (1 byte) signed value * UINT8 8-bit (1 byte) unsigned value * INT16 16-bit (2 byte) signed value @@ -45,40 +55,47 @@ * UINT64 64-bit (8 byte) unsigned value * NATIVE_INT 32-bit on IA-32, 64-bit on IA-64 signed value * NATIVE_UINT 32-bit on IA-32, 64-bit on IA-64 unsigned value - * UCHAR Character. 1 byte unsigned value. */ +#ifndef ACPI_MACHINE_WIDTH +#error ACPI_MACHINE_WIDTH not defined +#endif -#ifdef _IA64 +#if ACPI_MACHINE_WIDTH == 64 /* * 64-bit type definitions */ typedef unsigned char UINT8; typedef unsigned char BOOLEAN; -typedef unsigned char UCHAR; typedef unsigned short UINT16; typedef int INT32; typedef unsigned int UINT32; +typedef COMPILER_DEPENDENT_INT64 INT64; typedef COMPILER_DEPENDENT_UINT64 UINT64; -typedef UINT64 NATIVE_UINT; typedef INT64 NATIVE_INT; +typedef UINT64 NATIVE_UINT; -typedef NATIVE_UINT ACPI_TBLPTR; +typedef UINT32 NATIVE_UINT_MAX32; +typedef UINT64 NATIVE_UINT_MIN32; + +typedef UINT64 ACPI_TBLPTR; typedef UINT64 ACPI_IO_ADDRESS; typedef UINT64 ACPI_PHYSICAL_ADDRESS; +typedef UINT64 ACPI_SIZE; #define ALIGNED_ADDRESS_BOUNDARY 0x00000008 /* No hardware alignment support in IA64 */ #define ACPI_USE_NATIVE_DIVIDE /* Native 64-bit integer support */ +#define ACPI_MAX_PTR ACPI_UINT64_MAX +#define ACPI_SIZE_MAX ACPI_UINT64_MAX -#elif _IA16 +#elif ACPI_MACHINE_WIDTH == 16 /* * 16-bit type definitions */ typedef unsigned char UINT8; typedef unsigned char BOOLEAN; -typedef unsigned char UCHAR; typedef unsigned int UINT16; typedef long INT32; typedef int INT16; @@ -94,13 +111,19 @@ typedef UINT16 NATIVE_UINT; typedef INT16 NATIVE_INT; +typedef UINT16 NATIVE_UINT_MAX32; +typedef UINT32 NATIVE_UINT_MIN32; + typedef UINT32 ACPI_TBLPTR; typedef UINT32 ACPI_IO_ADDRESS; typedef char *ACPI_PHYSICAL_ADDRESS; +typedef UINT16 ACPI_SIZE; #define ALIGNED_ADDRESS_BOUNDARY 0x00000002 #define _HW_ALIGNMENT_SUPPORT #define ACPI_USE_NATIVE_DIVIDE /* No 64-bit integers, ok to use native divide */ +#define ACPI_MAX_PTR ACPI_UINT16_MAX +#define ACPI_SIZE_MAX ACPI_UINT16_MAX /* * (16-bit only) internal integers must be 32-bits, so @@ -109,29 +132,37 @@ #define ACPI_NO_INTEGER64_SUPPORT -#else +#elif ACPI_MACHINE_WIDTH == 32 /* * 32-bit type definitions (default) */ typedef unsigned char UINT8; typedef unsigned char BOOLEAN; -typedef unsigned char UCHAR; typedef unsigned short UINT16; typedef int INT32; typedef unsigned int UINT32; +typedef COMPILER_DEPENDENT_INT64 INT64; typedef COMPILER_DEPENDENT_UINT64 UINT64; -typedef UINT32 NATIVE_UINT; typedef INT32 NATIVE_INT; +typedef UINT32 NATIVE_UINT; -typedef NATIVE_UINT ACPI_TBLPTR; +typedef UINT32 NATIVE_UINT_MAX32; +typedef UINT32 NATIVE_UINT_MIN32; + +typedef UINT64 ACPI_TBLPTR; typedef UINT32 ACPI_IO_ADDRESS; typedef UINT64 ACPI_PHYSICAL_ADDRESS; +typedef UINT32 ACPI_SIZE; #define ALIGNED_ADDRESS_BOUNDARY 0x00000004 #define _HW_ALIGNMENT_SUPPORT -#endif +#define ACPI_MAX_PTR ACPI_UINT32_MAX +#define ACPI_SIZE_MAX ACPI_UINT32_MAX +#else +#error unknown ACPI_MACHINE_WIDTH +#endif /* @@ -143,19 +174,10 @@ typedef char NATIVE_CHAR; -/* - * Data type ranges - */ - -#define ACPI_UINT8_MAX (UINT8) 0xFF -#define ACPI_UINT16_MAX (UINT16) 0xFFFF -#define ACPI_UINT32_MAX (UINT32) 0xFFFFFFFF -#define ACPI_UINT64_MAX (UINT64) 0xFFFFFFFFFFFFFFFF - - #ifdef DEFINE_ALTERNATE_TYPES /* - * Types used only in translated source + * Types used only in translated source, defined here to enable + * cross-platform compilation only. */ typedef INT32 s32; typedef UINT8 u8; @@ -167,6 +189,31 @@ /* + * Pointer overlays to avoid lots of typecasting for + * code that accepts both physical and logical pointers. + */ +typedef union acpi_ptrs +{ + ACPI_PHYSICAL_ADDRESS physical; + void *logical; + ACPI_TBLPTR value; + +} ACPI_POINTERS; + +typedef struct acpi_pointer +{ + u32 pointer_type; + union acpi_ptrs pointer; + +} ACPI_POINTER; + +/* Pointer_types for above */ + +#define ACPI_LOGICAL_POINTER 0x01 +#define ACPI_PHYSICAL_POINTER 0x02 + + +/* * Useful defines */ @@ -208,6 +255,13 @@ } uint64_overlay; +typedef struct +{ + u32 lo; + u32 hi; + +} UINT32_STRUCT; + /* * Acpi integer width. In ACPI version 1, integers are @@ -241,7 +295,7 @@ #define ACPI_MAX_BCD_DIGITS 16 #define ACPI_MAX_DECIMAL_DIGITS 19 -#ifdef _IA64 +#if ACPI_MACHINE_WIDTH == 64 #define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 64-bit divide */ #endif #endif @@ -251,7 +305,7 @@ * Constants with special meanings */ -#define ACPI_ROOT_OBJECT (acpi_handle)(-1) +#define ACPI_ROOT_OBJECT (acpi_handle) ACPI_PTR_ADD (char, NULL, ACPI_MAX_PTR) /* @@ -261,9 +315,10 @@ #define ACPI_NO_ADDRESS_SPACE_INIT 0x01 #define ACPI_NO_HARDWARE_INIT 0x02 #define ACPI_NO_EVENT_INIT 0x04 -#define ACPI_NO_ACPI_ENABLE 0x08 -#define ACPI_NO_DEVICE_INIT 0x10 -#define ACPI_NO_OBJECT_INIT 0x20 +#define ACPI_NO_HANDLER_INIT 0x08 +#define ACPI_NO_ACPI_ENABLE 0x10 +#define ACPI_NO_DEVICE_INIT 0x20 +#define ACPI_NO_OBJECT_INIT 0x40 /* * Initialization state @@ -292,6 +347,19 @@ #define ACPI_D_STATES_MAX ACPI_STATE_D3 #define ACPI_D_STATE_COUNT 4 +#define ACPI_STATE_C0 (u8) 0 +#define ACPI_STATE_C1 (u8) 1 +#define ACPI_STATE_C2 (u8) 2 +#define ACPI_STATE_C3 (u8) 3 +#define ACPI_C_STATES_MAX ACPI_STATE_C3 +#define ACPI_C_STATE_COUNT 4 + +/* + * Sleep type invalid value + */ +#define ACPI_SLEEP_TYPE_MAX 0x7 +#define ACPI_SLEEP_TYPE_INVALID 0xFF + /* * Standard notify values */ @@ -326,35 +394,33 @@ * Types associated with names. The first group of * values correspond to the definition of the ACPI * Object_type operator (See the ACPI Spec). Therefore, - * only add to the first group if the spec changes! + * only add to the first group if the spec changes. * * Types must be kept in sync with the Acpi_ns_properties * and Acpi_ns_type_names arrays */ typedef u32 acpi_object_type; -typedef u8 acpi_object_type8; +#define ACPI_TYPE_ANY 0x00 +#define ACPI_TYPE_INTEGER 0x01 /* Byte/Word/Dword/Zero/One/Ones */ +#define ACPI_TYPE_STRING 0x02 +#define ACPI_TYPE_BUFFER 0x03 +#define ACPI_TYPE_PACKAGE 0x04 /* Byte_const, multiple Data_term/Constant/Super_name */ +#define ACPI_TYPE_FIELD_UNIT 0x05 +#define ACPI_TYPE_DEVICE 0x06 /* Name, multiple Node */ +#define ACPI_TYPE_EVENT 0x07 +#define ACPI_TYPE_METHOD 0x08 /* Name, Byte_const, multiple Code */ +#define ACPI_TYPE_MUTEX 0x09 +#define ACPI_TYPE_REGION 0x0A +#define ACPI_TYPE_POWER 0x0B /* Name,Byte_const,Word_const,multi Node */ +#define ACPI_TYPE_PROCESSOR 0x0C /* Name,Byte_const,DWord_const,Byte_const,multi Nm_o */ +#define ACPI_TYPE_THERMAL 0x0D /* Name, multiple Node */ +#define ACPI_TYPE_BUFFER_FIELD 0x0E +#define ACPI_TYPE_DDB_HANDLE 0x0F +#define ACPI_TYPE_DEBUG_OBJECT 0x10 -#define ACPI_TYPE_ANY 0 /* 0x00 */ -#define ACPI_TYPE_INTEGER 1 /* 0x01 Byte/Word/Dword/Zero/One/Ones */ -#define ACPI_TYPE_STRING 2 /* 0x02 */ -#define ACPI_TYPE_BUFFER 3 /* 0x03 */ -#define ACPI_TYPE_PACKAGE 4 /* 0x04 Byte_const, multiple Data_term/Constant/Super_name */ -#define ACPI_TYPE_FIELD_UNIT 5 /* 0x05 */ -#define ACPI_TYPE_DEVICE 6 /* 0x06 Name, multiple Node */ -#define ACPI_TYPE_EVENT 7 /* 0x07 */ -#define ACPI_TYPE_METHOD 8 /* 0x08 Name, Byte_const, multiple Code */ -#define ACPI_TYPE_MUTEX 9 /* 0x09 */ -#define ACPI_TYPE_REGION 10 /* 0x0A */ -#define ACPI_TYPE_POWER 11 /* 0x0B Name,Byte_const,Word_const,multi Node */ -#define ACPI_TYPE_PROCESSOR 12 /* 0x0C Name,Byte_const,DWord_const,Byte_const,multi Nm_o */ -#define ACPI_TYPE_THERMAL 13 /* 0x0D Name, multiple Node */ -#define ACPI_TYPE_BUFFER_FIELD 14 /* 0x0E */ -#define ACPI_TYPE_DDB_HANDLE 15 /* 0x0F */ -#define ACPI_TYPE_DEBUG_OBJECT 16 /* 0x10 */ - -#define ACPI_TYPE_MAX 16 +#define ACPI_TYPE_MAX 0x10 /* * This section contains object types that do not relate to the ACPI Object_type operator. @@ -363,36 +429,37 @@ * Also, values exceeding the largest official ACPI Object_type must not overlap with * defined AML opcodes. */ -#define INTERNAL_TYPE_BEGIN 17 +#define INTERNAL_TYPE_BEGIN 0x11 -#define INTERNAL_TYPE_REGION_FIELD 17 /* 0x11 */ -#define INTERNAL_TYPE_BANK_FIELD 18 /* 0x12 */ -#define INTERNAL_TYPE_INDEX_FIELD 19 /* 0x13 */ -#define INTERNAL_TYPE_REFERENCE 20 /* 0x14 Arg#, Local#, Name, Debug; used only in descriptors */ -#define INTERNAL_TYPE_ALIAS 21 /* 0x15 */ -#define INTERNAL_TYPE_NOTIFY 22 /* 0x16 */ -#define INTERNAL_TYPE_ADDRESS_HANDLER 23 /* 0x17 */ -#define INTERNAL_TYPE_RESOURCE 24 /* 0x18 */ -#define INTERNAL_TYPE_RESOURCE_FIELD 25 /* 0x19 */ +#define INTERNAL_TYPE_REGION_FIELD 0x11 +#define INTERNAL_TYPE_BANK_FIELD 0x12 +#define INTERNAL_TYPE_INDEX_FIELD 0x13 +#define INTERNAL_TYPE_REFERENCE 0x14 /* Arg#, Local#, Name, Debug; used only in descriptors */ +#define INTERNAL_TYPE_ALIAS 0x15 +#define INTERNAL_TYPE_NOTIFY 0x16 +#define INTERNAL_TYPE_ADDRESS_HANDLER 0x17 +#define INTERNAL_TYPE_RESOURCE 0x18 +#define INTERNAL_TYPE_RESOURCE_FIELD 0x19 -#define INTERNAL_TYPE_NODE_MAX 25 +#define INTERNAL_TYPE_NODE_MAX 0x19 /* These are pseudo-types because there are never any namespace nodes with these types */ -#define INTERNAL_TYPE_FIELD_DEFN 26 /* 0x1A Name, Byte_const, multiple Field_element */ -#define INTERNAL_TYPE_BANK_FIELD_DEFN 27 /* 0x1B 2 Name,DWord_const,Byte_const,multi Field_element */ -#define INTERNAL_TYPE_INDEX_FIELD_DEFN 28 /* 0x1C 2 Name, Byte_const, multiple Field_element */ -#define INTERNAL_TYPE_IF 29 /* 0x1D */ -#define INTERNAL_TYPE_ELSE 30 /* 0x1E */ -#define INTERNAL_TYPE_WHILE 31 /* 0x1F */ -#define INTERNAL_TYPE_SCOPE 32 /* 0x20 Name, multiple Node */ -#define INTERNAL_TYPE_DEF_ANY 33 /* 0x21 type is Any, suppress search of enclosing scopes */ -#define INTERNAL_TYPE_EXTRA 34 /* 0x22 */ +#define INTERNAL_TYPE_FIELD_DEFN 0x1A /* Name, Byte_const, multiple Field_element */ +#define INTERNAL_TYPE_BANK_FIELD_DEFN 0x1B /* 2 Name,DWord_const,Byte_const,multi Field_element */ +#define INTERNAL_TYPE_INDEX_FIELD_DEFN 0x1C /* 2 Name, Byte_const, multiple Field_element */ +#define INTERNAL_TYPE_IF 0x1D +#define INTERNAL_TYPE_ELSE 0x1E +#define INTERNAL_TYPE_WHILE 0x1F +#define INTERNAL_TYPE_SCOPE 0x20 /* Name, multiple Node */ +#define INTERNAL_TYPE_DEF_ANY 0x21 /* type is Any, suppress search of enclosing scopes */ +#define INTERNAL_TYPE_EXTRA 0x22 +#define INTERNAL_TYPE_DATA 0x23 -#define INTERNAL_TYPE_MAX 34 +#define INTERNAL_TYPE_MAX 0x23 -#define INTERNAL_TYPE_INVALID 35 +#define INTERNAL_TYPE_INVALID 0x24 #define ACPI_TYPE_NOT_FOUND 0xFF @@ -428,51 +495,48 @@ #define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */ #define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF +/* + * All I/O + */ +#define ACPI_READ 0 +#define ACPI_WRITE 1 + /* - * Acpi_event Types: - * ------------ - * Fixed & general purpose... + * Acpi_event Types: Fixed & General Purpose */ typedef u32 acpi_event_type; -#define ACPI_EVENT_FIXED (acpi_event_type) 0 -#define ACPI_EVENT_GPE (acpi_event_type) 1 +#define ACPI_EVENT_FIXED 0 +#define ACPI_EVENT_GPE 1 /* * Fixed events */ -#define ACPI_EVENT_PMTIMER (acpi_event_type) 0 - /* - * There's no bus master event so index 1 is used for IRQ's that are not - * handled by the SCI handler - */ -#define ACPI_EVENT_NOT_USED (acpi_event_type) 1 -#define ACPI_EVENT_GLOBAL (acpi_event_type) 2 -#define ACPI_EVENT_POWER_BUTTON (acpi_event_type) 3 -#define ACPI_EVENT_SLEEP_BUTTON (acpi_event_type) 4 -#define ACPI_EVENT_RTC (acpi_event_type) 5 -#define ACPI_EVENT_GENERAL (acpi_event_type) 6 -#define ACPI_EVENT_MAX 6 -#define ACPI_NUM_FIXED_EVENTS (acpi_event_type) 7 +#define ACPI_EVENT_PMTIMER 0 +#define ACPI_EVENT_GLOBAL 1 +#define ACPI_EVENT_POWER_BUTTON 2 +#define ACPI_EVENT_SLEEP_BUTTON 3 +#define ACPI_EVENT_RTC 4 +#define ACPI_EVENT_MAX 4 +#define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1 #define ACPI_GPE_INVALID 0xFF #define ACPI_GPE_MAX 0xFF #define ACPI_NUM_GPE 256 -#define ACPI_EVENT_LEVEL_TRIGGERED (acpi_event_type) 1 -#define ACPI_EVENT_EDGE_TRIGGERED (acpi_event_type) 2 +#define ACPI_EVENT_LEVEL_TRIGGERED 1 +#define ACPI_EVENT_EDGE_TRIGGERED 2 /* * GPEs */ -#define ACPI_EVENT_ENABLE 0x1 -#define ACPI_EVENT_WAKE_ENABLE 0x2 -#define ACPI_EVENT_DISABLE 0x1 -#define ACPI_EVENT_WAKE_DISABLE 0x2 +#define ACPI_EVENT_WAKE_ENABLE 0x1 + +#define ACPI_EVENT_WAKE_DISABLE 0x1 /* @@ -504,7 +568,7 @@ #define ACPI_DEVICE_NOTIFY 1 #define ACPI_MAX_NOTIFY_HANDLER_TYPE 1 -#define MAX_SYS_NOTIFY 0x7f +#define ACPI_MAX_SYS_NOTIFY 0x7f /* Address Space (Operation Region) Types */ @@ -518,9 +582,41 @@ #define ACPI_ADR_SPACE_SMBUS (ACPI_ADR_SPACE_TYPE) 4 #define ACPI_ADR_SPACE_CMOS (ACPI_ADR_SPACE_TYPE) 5 #define ACPI_ADR_SPACE_PCI_BAR_TARGET (ACPI_ADR_SPACE_TYPE) 6 +#define ACPI_ADR_SPACE_DATA_TABLE (ACPI_ADR_SPACE_TYPE) 7 /* + * Bit_register IDs + * These are bitfields defined within the full ACPI registers + */ +#define ACPI_BITREG_TIMER_STATUS 0x00 +#define ACPI_BITREG_BUS_MASTER_STATUS 0x01 +#define ACPI_BITREG_GLOBAL_LOCK_STATUS 0x02 +#define ACPI_BITREG_POWER_BUTTON_STATUS 0x03 +#define ACPI_BITREG_SLEEP_BUTTON_STATUS 0x04 +#define ACPI_BITREG_RT_CLOCK_STATUS 0x05 +#define ACPI_BITREG_WAKE_STATUS 0x06 + +#define ACPI_BITREG_TIMER_ENABLE 0x07 +#define ACPI_BITREG_GLOBAL_LOCK_ENABLE 0x08 +#define ACPI_BITREG_POWER_BUTTON_ENABLE 0x09 +#define ACPI_BITREG_SLEEP_BUTTON_ENABLE 0x0A +#define ACPI_BITREG_RT_CLOCK_ENABLE 0x0B +#define ACPI_BITREG_WAKE_ENABLE 0x0C + +#define ACPI_BITREG_SCI_ENABLE 0x0D +#define ACPI_BITREG_BUS_MASTER_RLD 0x0E +#define ACPI_BITREG_GLOBAL_LOCK_RELEASE 0x0F +#define ACPI_BITREG_SLEEP_TYPE_A 0x10 +#define ACPI_BITREG_SLEEP_TYPE_B 0x11 +#define ACPI_BITREG_SLEEP_ENABLE 0x12 + +#define ACPI_BITREG_ARB_DISABLE 0x13 + +#define ACPI_BITREG_MAX 0x13 +#define ACPI_NUM_BITREG ACPI_BITREG_MAX + 1 + +/* * External ACPI object definition */ @@ -576,7 +672,7 @@ u32 resource_order; } power_resource; -} acpi_object, *PACPI_OBJECT; +} acpi_object; /* @@ -588,16 +684,20 @@ u32 count; acpi_object *pointer; -} acpi_object_list, *PACPI_OBJECT_LIST; +} acpi_object_list; /* * Miscellaneous common Data Structures used by the interfaces */ +#define ACPI_NO_BUFFER 0 +#define ACPI_ALLOCATE_BUFFER (ACPI_SIZE) (-1) +#define ACPI_ALLOCATE_LOCAL_BUFFER (ACPI_SIZE) (-2) + typedef struct { - u32 length; /* Length in bytes of the buffer */ + ACPI_SIZE length; /* Length in bytes of the buffer */ void *pointer; /* pointer to buffer */ } acpi_buffer; @@ -616,10 +716,10 @@ * Structure and flags for Acpi_get_system_info */ -#define SYS_MODE_UNKNOWN 0x0000 -#define SYS_MODE_ACPI 0x0001 -#define SYS_MODE_LEGACY 0x0002 -#define SYS_MODES_MASK 0x0003 +#define ACPI_SYS_MODE_UNKNOWN 0x0000 +#define ACPI_SYS_MODE_ACPI 0x0001 +#define ACPI_SYS_MODE_LEGACY 0x0002 +#define ACPI_SYS_MODES_MASK 0x0003 /* @@ -669,22 +769,32 @@ u32 value, void *context); +typedef +void (*ACPI_OBJECT_HANDLER) ( + acpi_handle object, + u32 function, + void *data); + +typedef +acpi_status (*ACPI_INIT_HANDLER) ( + acpi_handle object, + u32 function); + +#define ACPI_INIT_DEVICE_INI 1 -/* Address Spaces (Operation Regions */ -#define ACPI_READ_ADR_SPACE 1 -#define ACPI_WRITE_ADR_SPACE 2 +/* Address Spaces (Operation Regions */ typedef acpi_status (*acpi_adr_space_handler) ( u32 function, ACPI_PHYSICAL_ADDRESS address, u32 bit_width, - u32 *value, + acpi_integer *value, void *handler_context, void *region_context); -#define ACPI_DEFAULT_HANDLER ((acpi_adr_space_handler) NULL) +#define ACPI_DEFAULT_HANDLER NULL typedef @@ -707,8 +817,8 @@ /* Interrupt handler return values */ -#define INTERRUPT_NOT_HANDLED 0x00 -#define INTERRUPT_HANDLED 0x01 +#define ACPI_INTERRUPT_NOT_HANDLED 0x00 +#define ACPI_INTERRUPT_HANDLED 0x01 /* Structure and flags for Acpi_get_device_info */ @@ -755,9 +865,11 @@ typedef struct { + u32 length; + ACPI_PHYSICAL_ADDRESS address; ACPI_PHYSICAL_ADDRESS mapped_physical_address; u8 *mapped_logical_address; - u32 mapped_length; + ACPI_SIZE mapped_length; } acpi_mem_space_context; @@ -773,78 +885,78 @@ /* * Memory Attributes */ -#define READ_ONLY_MEMORY (u8) 0x00 -#define READ_WRITE_MEMORY (u8) 0x01 +#define ACPI_READ_ONLY_MEMORY (u8) 0x00 +#define ACPI_READ_WRITE_MEMORY (u8) 0x01 -#define NON_CACHEABLE_MEMORY (u8) 0x00 -#define CACHABLE_MEMORY (u8) 0x01 -#define WRITE_COMBINING_MEMORY (u8) 0x02 -#define PREFETCHABLE_MEMORY (u8) 0x03 +#define ACPI_NON_CACHEABLE_MEMORY (u8) 0x00 +#define ACPI_CACHABLE_MEMORY (u8) 0x01 +#define ACPI_WRITE_COMBINING_MEMORY (u8) 0x02 +#define ACPI_PREFETCHABLE_MEMORY (u8) 0x03 /* * IO Attributes - * The ISA IO ranges are: n000-n0FFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh. + * The ISA IO ranges are: n000-n0_fFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh. * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cD0-n_fFFh. */ -#define NON_ISA_ONLY_RANGES (u8) 0x01 -#define ISA_ONLY_RANGES (u8) 0x02 -#define ENTIRE_RANGE (NON_ISA_ONLY_RANGES | ISA_ONLY_RANGES) +#define ACPI_NON_ISA_ONLY_RANGES (u8) 0x01 +#define ACPI_ISA_ONLY_RANGES (u8) 0x02 +#define ACPI_ENTIRE_RANGE (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES) /* * IO Port Descriptor Decode */ -#define DECODE_10 (u8) 0x00 /* 10-bit IO address decode */ -#define DECODE_16 (u8) 0x01 /* 16-bit IO address decode */ +#define ACPI_DECODE_10 (u8) 0x00 /* 10-bit IO address decode */ +#define ACPI_DECODE_16 (u8) 0x01 /* 16-bit IO address decode */ /* * IRQ Attributes */ -#define EDGE_SENSITIVE (u8) 0x00 -#define LEVEL_SENSITIVE (u8) 0x01 +#define ACPI_EDGE_SENSITIVE (u8) 0x00 +#define ACPI_LEVEL_SENSITIVE (u8) 0x01 -#define ACTIVE_HIGH (u8) 0x00 -#define ACTIVE_LOW (u8) 0x01 +#define ACPI_ACTIVE_HIGH (u8) 0x00 +#define ACPI_ACTIVE_LOW (u8) 0x01 -#define EXCLUSIVE (u8) 0x00 -#define SHARED (u8) 0x01 +#define ACPI_EXCLUSIVE (u8) 0x00 +#define ACPI_SHARED (u8) 0x01 /* * DMA Attributes */ -#define COMPATIBILITY (u8) 0x00 -#define TYPE_A (u8) 0x01 -#define TYPE_B (u8) 0x02 -#define TYPE_F (u8) 0x03 - -#define NOT_BUS_MASTER (u8) 0x00 -#define BUS_MASTER (u8) 0x01 - -#define TRANSFER_8 (u8) 0x00 -#define TRANSFER_8_16 (u8) 0x01 -#define TRANSFER_16 (u8) 0x02 +#define ACPI_COMPATIBILITY (u8) 0x00 +#define ACPI_TYPE_A (u8) 0x01 +#define ACPI_TYPE_B (u8) 0x02 +#define ACPI_TYPE_F (u8) 0x03 + +#define ACPI_NOT_BUS_MASTER (u8) 0x00 +#define ACPI_BUS_MASTER (u8) 0x01 + +#define ACPI_TRANSFER_8 (u8) 0x00 +#define ACPI_TRANSFER_8_16 (u8) 0x01 +#define ACPI_TRANSFER_16 (u8) 0x02 /* * Start Dependent Functions Priority definitions */ -#define GOOD_CONFIGURATION (u8) 0x00 -#define ACCEPTABLE_CONFIGURATION (u8) 0x01 -#define SUB_OPTIMAL_CONFIGURATION (u8) 0x02 +#define ACPI_GOOD_CONFIGURATION (u8) 0x00 +#define ACPI_ACCEPTABLE_CONFIGURATION (u8) 0x01 +#define ACPI_SUB_OPTIMAL_CONFIGURATION (u8) 0x02 /* * 16, 32 and 64-bit Address Descriptor resource types */ -#define MEMORY_RANGE (u8) 0x00 -#define IO_RANGE (u8) 0x01 -#define BUS_NUMBER_RANGE (u8) 0x02 +#define ACPI_MEMORY_RANGE (u8) 0x00 +#define ACPI_IO_RANGE (u8) 0x01 +#define ACPI_BUS_NUMBER_RANGE (u8) 0x02 -#define ADDRESS_NOT_FIXED (u8) 0x00 -#define ADDRESS_FIXED (u8) 0x01 +#define ACPI_ADDRESS_NOT_FIXED (u8) 0x00 +#define ACPI_ADDRESS_FIXED (u8) 0x01 -#define POS_DECODE (u8) 0x00 -#define SUB_DECODE (u8) 0x01 +#define ACPI_POS_DECODE (u8) 0x00 +#define ACPI_SUB_DECODE (u8) 0x01 -#define PRODUCER (u8) 0x00 -#define CONSUMER (u8) 0x01 +#define ACPI_PRODUCER (u8) 0x00 +#define ACPI_CONSUMER (u8) 0x01 /* @@ -908,6 +1020,12 @@ typedef struct { + u8 checksum; + +} ACPI_RESOURCE_END_TAG; + +typedef struct +{ u32 read_write_attribute; u32 min_base_address; u32 max_base_address; @@ -1053,7 +1171,7 @@ #define ACPI_RSTYPE_ADDRESS64 13 #define ACPI_RSTYPE_EXT_IRQ 14 -typedef u32 acpi_resource_type; +typedef u32 acpi_resource_type; typedef union { @@ -1063,6 +1181,7 @@ acpi_resource_io io; acpi_resource_fixed_io fixed_io; acpi_resource_vendor vendor_specific; + ACPI_RESOURCE_END_TAG end_tag; acpi_resource_mem24 memory24; acpi_resource_mem32 memory32; acpi_resource_fixed_mem32 fixed_memory32; @@ -1081,20 +1200,25 @@ } acpi_resource; -#define ACPI_RESOURCE_LENGTH 12 -#define ACPI_RESOURCE_LENGTH_NO_DATA 8 /* Id + Length fields */ +#define ACPI_RESOURCE_LENGTH 12 +#define ACPI_RESOURCE_LENGTH_NO_DATA 8 /* Id + Length fields */ -#define SIZEOF_RESOURCE(type) (ACPI_RESOURCE_LENGTH_NO_DATA + sizeof (type)) +#define ACPI_SIZEOF_RESOURCE(type) (ACPI_RESOURCE_LENGTH_NO_DATA + sizeof (type)) -#define NEXT_RESOURCE(res) (acpi_resource *)((u8 *) res + res->length) +#define ACPI_NEXT_RESOURCE(res) (acpi_resource *)((u8 *) res + res->length) +#ifdef _HW_ALIGNMENT_SUPPORT +#define ACPI_ALIGN_RESOURCE_SIZE(length) (length) +#else +#define ACPI_ALIGN_RESOURCE_SIZE(length) ACPI_ROUND_UP_TO_NATIVE_WORD(length) +#endif /* - * END: Definitions for Resource Attributes + * END: of definitions for Resource Attributes */ -typedef struct pci_routing_table +typedef struct acpi_pci_routing_table { u32 length; u32 pin; @@ -1102,11 +1226,11 @@ u32 source_index; NATIVE_CHAR source[4]; /* pad to 64 bits so sizeof() works in all cases */ -} pci_routing_table; - +} acpi_pci_routing_table; /* - * END: Definitions for PCI Routing tables + * END: of definitions for PCI Routing tables */ + #endif /* __ACTYPES_H__ */ diff -Nur linux-2.4.19/drivers/acpi/include/acutils.h linux-2.4.19-sgi211r3/drivers/acpi/include/acutils.h --- linux-2.4.19/drivers/acpi/include/acutils.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/acutils.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures - * $Revision: 117 $ + * $Revision: 137 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,7 +46,7 @@ typedef struct acpi_pkg_info { u8 *free_space; - u32 length; + ACPI_SIZE length; u32 object_space; u32 num_packages; } acpi_pkg_info; @@ -82,7 +82,7 @@ acpi_ut_hardware_initialize ( void); -acpi_status +void acpi_ut_subsystem_shutdown ( void); @@ -94,7 +94,7 @@ * Ut_global - Global data structures and procedures */ -#ifdef ACPI_DEBUG +#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) NATIVE_CHAR * acpi_ut_get_mutex_name ( @@ -102,23 +102,27 @@ NATIVE_CHAR * acpi_ut_get_type_name ( - u32 type); + acpi_object_type type); + +#endif + NATIVE_CHAR * acpi_ut_get_region_name ( u8 space_id); -#endif - +NATIVE_CHAR * +acpi_ut_get_event_name ( + u32 event_id); -u8 +char acpi_ut_hex_to_ascii_char ( acpi_integer integer, u32 position); u8 acpi_ut_valid_object_type ( - u32 type); + acpi_object_type type); acpi_owner_id acpi_ut_allocate_owner_id ( @@ -146,7 +150,7 @@ const NATIVE_CHAR *src_string, NATIVE_UINT count); -u32 +int acpi_ut_strncmp ( const NATIVE_CHAR *string1, const NATIVE_CHAR *string2, @@ -191,13 +195,32 @@ NATIVE_UINT value, NATIVE_UINT count); -u32 +int acpi_ut_to_upper ( - u32 c); + int c); -u32 +int acpi_ut_to_lower ( - u32 c); + int c); + +extern const u8 _acpi_ctype[]; + +#define _ACPI_XA 0x00 /* extra alphabetic - not supported */ +#define _ACPI_XS 0x40 /* extra space */ +#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */ +#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */ +#define _ACPI_DI 0x04 /* '0'-'9' */ +#define _ACPI_LO 0x02 /* 'a'-'z' */ +#define _ACPI_PU 0x10 /* punctuation */ +#define _ACPI_SP 0x08 /* space */ +#define _ACPI_UP 0x01 /* 'A'-'Z' */ +#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ + +#define ACPI_IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) +#define ACPI_IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) +#define ACPI_IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) +#define ACPI_IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) +#define ACPI_IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) #endif /* ACPI_USE_SYSTEM_CLIBRARY */ @@ -219,6 +242,20 @@ u32 *space_used); acpi_status +acpi_ut_copy_ielement_to_eelement ( + u8 object_type, + acpi_operand_object *source_object, + acpi_generic_state *state, + void *context); + +acpi_status +acpi_ut_copy_ielement_to_ielement ( + u8 object_type, + acpi_operand_object *source_object, + acpi_generic_state *state, + void *context); + +acpi_status acpi_ut_copy_iobject_to_eobject ( acpi_operand_object *obj, acpi_buffer *ret_buffer); @@ -244,6 +281,17 @@ acpi_operand_object *dest_obj, acpi_walk_state *walk_state); +acpi_status +acpi_ut_copy_simple_object ( + acpi_operand_object *source_desc, + acpi_operand_object *dest_desc); + +acpi_status +acpi_ut_copy_iobject_to_iobject ( + acpi_operand_object *source_desc, + acpi_operand_object **dest_desc, + acpi_walk_state *walk_state); + /* * Ut_create - Object creation @@ -338,7 +386,7 @@ u32 display, u32 component_id); -void +void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print ( u32 requested_debug_level, u32 line_number, @@ -346,7 +394,7 @@ char *format, ...) ACPI_PRINTF_LIKE_FUNC; -void +void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print_raw ( u32 requested_debug_level, u32 line_number, @@ -371,7 +419,7 @@ acpi_ut_delete_internal_simple_object ( acpi_operand_object *object); -acpi_status +void acpi_ut_delete_internal_object_list ( acpi_operand_object **obj_list); @@ -383,6 +431,7 @@ /* Method name strings */ #define METHOD_NAME__HID "_HID" +#define METHOD_NAME__CID "_CID" #define METHOD_NAME__UID "_UID" #define METHOD_NAME__ADR "_ADR" #define METHOD_NAME__STA "_STA" @@ -404,6 +453,11 @@ acpi_device_id *hid); acpi_status +acpi_ut_execute_CID ( + acpi_namespace_node *device_node, + acpi_device_id *cid); + +acpi_status acpi_ut_execute_STA ( acpi_namespace_node *device_node, u32 *status_flags); @@ -452,7 +506,7 @@ NATIVE_CHAR *module_name, u32 line_number, u32 component_id, - acpi_object_type8 type); + acpi_object_type type); void * acpi_ut_allocate_object_desc_dbg ( @@ -491,17 +545,24 @@ acpi_status acpi_ut_get_simple_object_size ( acpi_operand_object *obj, - u32 *obj_length); + ACPI_SIZE *obj_length); acpi_status acpi_ut_get_package_object_size ( acpi_operand_object *obj, - u32 *obj_length); + ACPI_SIZE *obj_length); acpi_status acpi_ut_get_object_size( acpi_operand_object *obj, - u32 *obj_length); + ACPI_SIZE *obj_length); + +acpi_status +acpi_ut_get_element_length ( + u8 object_type, + acpi_operand_object *source_object, + acpi_generic_state *state, + void *context); /* @@ -522,6 +583,10 @@ acpi_ut_create_generic_state ( void); +ACPI_THREAD_STATE * +acpi_ut_create_thread_state ( + void); + acpi_generic_state * acpi_ut_create_update_state ( acpi_operand_object *object, @@ -588,6 +653,12 @@ acpi_ut_valid_acpi_character ( NATIVE_CHAR character); +acpi_status +acpi_ut_strtoul64 ( + NATIVE_CHAR *string, + u32 base, + acpi_integer *ret_integer); + NATIVE_CHAR * acpi_ut_strupr ( NATIVE_CHAR *src_string); @@ -596,6 +667,29 @@ acpi_ut_resolve_package_references ( acpi_operand_object *obj_desc); +acpi_status +acpi_ut_resolve_reference ( + u8 object_type, + acpi_operand_object *source_object, + acpi_generic_state *state, + void *context); + +u8 * +acpi_ut_get_resource_end_tag ( + acpi_operand_object *obj_desc); + +u8 +acpi_ut_generate_checksum ( + u8 *buffer, + u32 length); + +u32 +acpi_ut_dword_byte_swap ( + u32 value); + +void +acpi_ut_set_integer_width ( + u8 revision); #ifdef ACPI_DEBUG void @@ -623,31 +717,79 @@ acpi_ut_delete_generic_cache ( u32 list_id); +acpi_status +acpi_ut_validate_buffer ( + acpi_buffer *buffer); + +acpi_status +acpi_ut_initialize_buffer ( + acpi_buffer *buffer, + ACPI_SIZE required_length); + -/* Debug Memory allocation functions */ +/* Memory allocation functions */ void * acpi_ut_allocate ( - u32 size, + ACPI_SIZE size, u32 component, NATIVE_CHAR *module, u32 line); void * acpi_ut_callocate ( - u32 size, + ACPI_SIZE size, + u32 component, + NATIVE_CHAR *module, + u32 line); + + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +void * +acpi_ut_allocate_and_track ( + ACPI_SIZE size, + u32 component, + NATIVE_CHAR *module, + u32 line); + +void * +acpi_ut_callocate_and_track ( + ACPI_SIZE size, u32 component, NATIVE_CHAR *module, u32 line); void -acpi_ut_free ( +acpi_ut_free_and_track ( void *address, u32 component, NATIVE_CHAR *module, u32 line); -#ifdef ACPI_DBG_TRACK_ALLOCATIONS +acpi_debug_mem_block * +acpi_ut_find_allocation ( + u32 list_id, + void *allocation); + +acpi_status +acpi_ut_track_allocation ( + u32 list_id, + acpi_debug_mem_block *address, + ACPI_SIZE size, + u8 alloc_type, + u32 component, + NATIVE_CHAR *module, + u32 line); + +acpi_status +acpi_ut_remove_allocation ( + u32 list_id, + acpi_debug_mem_block *address, + u32 component, + NATIVE_CHAR *module, + u32 line); + void acpi_ut_dump_allocation_info ( void); diff -Nur linux-2.4.19/drivers/acpi/include/adisasm.h linux-2.4.19-sgi211r3/drivers/acpi/include/adisasm.h --- linux-2.4.19/drivers/acpi/include/adisasm.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/adisasm.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * Module Name: adisasm - AML disassembler + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2002, R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ADISASM +#define _ADISASM + + +extern u8 *dsdt_ptr; +extern u32 acpi_dsdt_length; +extern int optind; +extern char *optarg; +extern u8 *aml_start; +extern u32 aml_length; + + +int +getopt ( + int argc, + char **argv, + char *opts); + + +acpi_status +ad_aml_disassemble ( + char *filename); + +void +ad_print_statistics (void); + + +acpi_status +ad_find_dsdt( + u8 **dsdt_ptr, + u32 *dsdt_length); + +void +ad_dump_tables (void); + + +acpi_status +ad_get_tables ( + char *filename); + +acpi_status +ad_parse_tables (void); + +acpi_status +ad_display_tables (void); + +acpi_status +ad_display_statistics (void); + + +#endif + diff -Nur linux-2.4.19/drivers/acpi/include/amlcode.h linux-2.4.19-sgi211r3/drivers/acpi/include/amlcode.h --- linux-2.4.19/drivers/acpi/include/amlcode.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/amlcode.h Tue Aug 27 19:53:13 2002 @@ -3,12 +3,12 @@ * Name: amlcode.h - Definitions for AML, as included in "definition blocks" * Declarations and definitions contained herein are derived * directly from the ACPI specification. - * $Revision: 58 $ + * $Revision: 68 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,6 @@ #ifndef __AMLCODE_H__ #define __AMLCODE_H__ - /* primary opcodes */ #define AML_NULL_CHAR (u16) 0x00 @@ -185,6 +184,7 @@ #define AML_INT_STATICSTRING_OP (u16) 0x0034 #define AML_INT_METHODCALL_OP (u16) 0x0035 #define AML_INT_RETURN_VALUE_OP (u16) 0x0036 +#define AML_INT_EVAL_SUBTREE_OP (u16) 0x0037 #define ARG_NONE 0x0 @@ -218,6 +218,9 @@ * Resolved argument types for the AML Interpreter * Each field in the Arg_types u32 is 5 bits, allowing for a maximum of 6 arguments. * There can be up to 31 unique argument types (0 is end-of-arg-list indicator) + * + * Note: If and when 5 bits becomes insufficient, it would probably be best + * to convert to a 6-byte array of argument types, allowing 8 bits per argument. */ /* "Standard" ACPI types are 1-15 (0x0F) */ @@ -247,6 +250,7 @@ #define ARGI_FIXED_TARGET 0x1B /* Target, no implicit conversion */ #define ARGI_SIMPLE_TARGET 0x1C /* Name, Local, Arg -- no implicit conversion */ #define ARGI_BUFFERSTRING 0x1D +#define ARGI_REF_OR_STRING 0x1E /* Reference or String (Used by DEREFOF op only) */ #define ARGI_INVALID_OPCODE 0xFFFFFFFF @@ -285,6 +289,7 @@ #define AML_CREATE 0x0004 #define AML_MATH 0x0002 #define AML_LOGICAL 0x0001 +#define AML_CONSTANT 0x1000 /* Convenient flag groupings */ @@ -331,15 +336,16 @@ /* Misc */ #define AML_TYPE_CREATE_FIELD 0x11 -#define AML_TYPE_CONTROL 0x12 -#define AML_TYPE_NAMED_NO_OBJ 0x13 -#define AML_TYPE_NAMED_FIELD 0x14 -#define AML_TYPE_NAMED_SIMPLE 0x15 -#define AML_TYPE_NAMED_COMPLEX 0x16 -#define AML_TYPE_RETURN 0x17 +#define AML_TYPE_CREATE_OBJECT 0x12 +#define AML_TYPE_CONTROL 0x13 +#define AML_TYPE_NAMED_NO_OBJ 0x14 +#define AML_TYPE_NAMED_FIELD 0x15 +#define AML_TYPE_NAMED_SIMPLE 0x16 +#define AML_TYPE_NAMED_COMPLEX 0x17 +#define AML_TYPE_RETURN 0x18 -#define AML_TYPE_UNDEFINED 0x18 -#define AML_TYPE_BOGUS 0x19 +#define AML_TYPE_UNDEFINED 0x19 +#define AML_TYPE_BOGUS 0x1A /* @@ -369,7 +375,8 @@ REGION_SMBUS, REGION_CMOS, REGION_PCI_BAR, - REGION_FIXED_HW = 0x7F, + REGION_DATA_TABLE, /* Internal use only */ + REGION_FIXED_HW = 0x7F } AML_REGION_TYPES; @@ -390,52 +397,76 @@ #define MAX_MATCH_OPERATOR 5 -/* Field Access Types */ +/* + * Field_flags + * + * This byte is extracted from the AML and includes three separate + * pieces of information about the field: + * 1) The field access type + * 2) The field update rule + * 3) The lock rule for the field + * + * Bits 00 - 03 : Access_type (Any_acc, Byte_acc, etc.) + * 04 : Lock_rule (1 == Lock) + * 05 - 06 : Update_rule + */ +#define AML_FIELD_ACCESS_TYPE_MASK 0x0F +#define AML_FIELD_LOCK_RULE_MASK 0x10 +#define AML_FIELD_UPDATE_RULE_MASK 0x60 + -#define ACCESS_TYPE_MASK 0x0f -#define ACCESS_TYPE_SHIFT 0 +/* 1) Field Access Types */ typedef enum { - ACCESS_ANY_ACC = 0, - ACCESS_BYTE_ACC = 1, - ACCESS_WORD_ACC = 2, - ACCESS_DWORD_ACC = 3, - ACCESS_QWORD_ACC = 4, /* ACPI 2.0 */ - ACCESS_BLOCK_ACC = 4, - ACCESS_SMBSEND_RECV_ACC = 5, - ACCESS_SMBQUICK_ACC = 6 + AML_FIELD_ACCESS_ANY = 0x00, + AML_FIELD_ACCESS_BYTE = 0x01, + AML_FIELD_ACCESS_WORD = 0x02, + AML_FIELD_ACCESS_DWORD = 0x03, + AML_FIELD_ACCESS_QWORD = 0x04, /* ACPI 2.0 */ + AML_FIELD_ACCESS_BUFFER = 0x05 /* ACPI 2.0 */ } AML_ACCESS_TYPE; -/* Field Lock Rules */ - -#define LOCK_RULE_MASK 0x10 -#define LOCK_RULE_SHIFT 4 +/* 2) Field Lock Rules */ typedef enum { - GLOCK_NEVER_LOCK = 0, - GLOCK_ALWAYS_LOCK = 1 + AML_FIELD_LOCK_NEVER = 0x00, + AML_FIELD_LOCK_ALWAYS = 0x10 } AML_LOCK_RULE; -/* Field Update Rules */ - -#define UPDATE_RULE_MASK 0x060 -#define UPDATE_RULE_SHIFT 5 +/* 3) Field Update Rules */ typedef enum { - UPDATE_PRESERVE = 0, - UPDATE_WRITE_AS_ONES = 1, - UPDATE_WRITE_AS_ZEROS = 2 + AML_FIELD_UPDATE_PRESERVE = 0x00, + AML_FIELD_UPDATE_WRITE_AS_ONES = 0x20, + AML_FIELD_UPDATE_WRITE_AS_ZEROS = 0x40 } AML_UPDATE_RULE; +/* + * Field Access Attributes. + * This byte is extracted from the AML via the + * Access_as keyword + */ +typedef enum +{ + AML_FIELD_ATTRIB_SMB_QUICK = 0x02, + AML_FIELD_ATTRIB_SMB_SEND_RCV = 0x04, + AML_FIELD_ATTRIB_SMB_BYTE = 0x06, + AML_FIELD_ATTRIB_SMB_WORD = 0x08, + AML_FIELD_ATTRIB_SMB_BLOCK = 0x0A, + AML_FIELD_ATTRIB_SMB_CALL = 0x0E + +} AML_ACCESS_ATTRIBUTE; + + /* bit fields in Method_flags byte */ #define METHOD_FLAGS_ARG_COUNT 0x07 @@ -445,15 +476,11 @@ /* Array sizes. Used for range checking also */ -#define NUM_REGION_TYPES 7 -#define NUM_ACCESS_TYPES 7 +#define NUM_ACCESS_TYPES 6 #define NUM_UPDATE_RULES 3 #define NUM_MATCH_OPS 7 #define NUM_OPCODES 256 #define NUM_FIELD_NAMES 2 - - -#define USER_REGION_BEGIN 0x80 #endif /* __AMLCODE_H__ */ diff -Nur linux-2.4.19/drivers/acpi/include/platform/acenv.h linux-2.4.19-sgi211r3/drivers/acpi/include/platform/acenv.h --- linux-2.4.19/drivers/acpi/include/platform/acenv.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/platform/acenv.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acenv.h - Generation environment specific items - * $Revision: 77 $ + * $Revision: 94 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,7 +51,7 @@ #ifdef _ACPI_ASL_COMPILER #define ACPI_DEBUG #define ACPI_APPLICATION -#define ENABLE_DEBUGGER +/* #define ENABLE_DEBUGGER */ #define ACPI_USE_SYSTEM_CLIBRARY #endif @@ -61,7 +61,7 @@ * 2) This is NOT a 16-bit version of the code (not enough real-mode memory) */ #ifdef ACPI_DEBUG -#ifndef _IA16 +#if ACPI_MACHINE_WIDTH != 16 #define ACPI_DBG_TRACK_ALLOCATIONS #endif #endif @@ -105,24 +105,40 @@ /*! [Begin] no source code translation */ -#ifdef _LINUX +#if defined(_LINUX) #include "aclinux.h" -#elif _AED_EFI +#elif defined(_AED_EFI) #include "acefi.h" -#elif WIN32 +#elif defined(WIN32) #include "acwin.h" -#elif __FreeBSD__ +#elif defined(WIN64) +#include "acwin64.h" + +#elif defined(MSDOS) /* Must appear after WIN32 and WIN64 check */ +#include "acdos16.h" + +#elif defined(__FreeBSD__) #include "acfreebsd.h" +#elif defined(MODESTO) +#include "acmodesto.h" + +#elif defined(NETWARE) +#include "acnetware.h" + #else /* All other environments */ #define ACPI_USE_STANDARD_HEADERS +#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long + + /* Name of host operating system (returned by the _OS_ namespace object) */ #define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" @@ -135,7 +151,6 @@ #endif - /*! [End] no source code translation !*/ /****************************************************************************** @@ -166,21 +181,24 @@ * We will be linking to the standard Clib functions */ -#define STRSTR(s1,s2) strstr((s1), (s2)) -#define STRUPR(s) acpi_ut_strupr ((s)) -#define STRLEN(s) (u32) strlen((s)) -#define STRCPY(d,s) strcpy((d), (s)) -#define STRNCPY(d,s,n) strncpy((d), (s), (NATIVE_INT)(n)) -#define STRNCMP(d,s,n) strncmp((d), (s), (NATIVE_INT)(n)) -#define STRCMP(d,s) strcmp((d), (s)) -#define STRCAT(d,s) strcat((d), (s)) -#define STRNCAT(d,s,n) strncat((d), (s), (NATIVE_INT)(n)) -#define STRTOUL(d,s,n) strtoul((d), (s), (NATIVE_INT)(n)) -#define MEMCPY(d,s,n) memcpy((d), (s), (NATIVE_INT)(n)) -#define MEMSET(d,s,n) memset((d), (s), (NATIVE_INT)(n)) -#define TOUPPER toupper -#define TOLOWER tolower -#define IS_XDIGIT isxdigit +#define ACPI_STRSTR(s1,s2) strstr((s1), (s2)) +#define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s)) +#define ACPI_STRLEN(s) (ACPI_SIZE) strlen((s)) +#define ACPI_STRCPY(d,s) (void) strcpy((d), (s)) +#define ACPI_STRNCPY(d,s,n) (void) strncpy((d), (s), (ACPI_SIZE)(n)) +#define ACPI_STRNCMP(d,s,n) strncmp((d), (s), (ACPI_SIZE)(n)) +#define ACPI_STRCMP(d,s) strcmp((d), (s)) +#define ACPI_STRCAT(d,s) (void) strcat((d), (s)) +#define ACPI_STRNCAT(d,s,n) strncat((d), (s), (ACPI_SIZE)(n)) +#define ACPI_STRTOUL(d,s,n) strtoul((d), (s), (ACPI_SIZE)(n)) +#define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (ACPI_SIZE)(n)) +#define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (ACPI_SIZE)(n)) +#define ACPI_TOUPPER toupper +#define ACPI_TOLOWER tolower +#define ACPI_IS_XDIGIT isxdigit +#define ACPI_IS_DIGIT isdigit +#define ACPI_IS_SPACE isspace +#define ACPI_IS_UPPER isupper /****************************************************************************** * @@ -207,35 +225,35 @@ * Storage alignment properties */ -#define _AUPBND (sizeof (NATIVE_INT) - 1) -#define _ADNBND (sizeof (NATIVE_INT) - 1) +#define _AUPBND (sizeof (NATIVE_INT) - 1) +#define _ADNBND (sizeof (NATIVE_INT) - 1) /* * Variable argument list macro definitions */ -#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) -#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) -#define va_end(ap) (void) 0 -#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) +#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) +#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) +#define va_end(ap) (void) 0 +#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) #endif /* va_arg */ -#define STRSTR(s1,s2) acpi_ut_strstr ((s1), (s2)) -#define STRUPR(s) acpi_ut_strupr ((s)) -#define STRLEN(s) acpi_ut_strlen ((s)) -#define STRCPY(d,s) acpi_ut_strcpy ((d), (s)) -#define STRNCPY(d,s,n) acpi_ut_strncpy ((d), (s), (n)) -#define STRNCMP(d,s,n) acpi_ut_strncmp ((d), (s), (n)) -#define STRCMP(d,s) acpi_ut_strcmp ((d), (s)) -#define STRCAT(d,s) acpi_ut_strcat ((d), (s)) -#define STRNCAT(d,s,n) acpi_ut_strncat ((d), (s), (n)) -#define STRTOUL(d,s,n) acpi_ut_strtoul ((d), (s),(n)) -#define MEMCPY(d,s,n) acpi_ut_memcpy ((d), (s), (n)) -#define MEMSET(d,v,n) acpi_ut_memset ((d), (v), (n)) -#define TOUPPER acpi_ut_to_upper -#define TOLOWER acpi_ut_to_lower +#define ACPI_STRSTR(s1,s2) acpi_ut_strstr ((s1), (s2)) +#define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s)) +#define ACPI_STRLEN(s) (ACPI_SIZE) acpi_ut_strlen ((s)) +#define ACPI_STRCPY(d,s) (void) acpi_ut_strcpy ((d), (s)) +#define ACPI_STRNCPY(d,s,n) (void) acpi_ut_strncpy ((d), (s), (ACPI_SIZE)(n)) +#define ACPI_STRNCMP(d,s,n) acpi_ut_strncmp ((d), (s), (ACPI_SIZE)(n)) +#define ACPI_STRCMP(d,s) acpi_ut_strcmp ((d), (s)) +#define ACPI_STRCAT(d,s) (void) acpi_ut_strcat ((d), (s)) +#define ACPI_STRNCAT(d,s,n) acpi_ut_strncat ((d), (s), (ACPI_SIZE)(n)) +#define ACPI_STRTOUL(d,s,n) acpi_ut_strtoul ((d), (s), (ACPI_SIZE)(n)) +#define ACPI_MEMCPY(d,s,n) (void) acpi_ut_memcpy ((d), (s), (ACPI_SIZE)(n)) +#define ACPI_MEMSET(d,v,n) (void) acpi_ut_memset ((d), (v), (ACPI_SIZE)(n)) +#define ACPI_TOUPPER acpi_ut_to_upper +#define ACPI_TOLOWER acpi_ut_to_lower #endif /* ACPI_USE_SYSTEM_CLIBRARY */ @@ -256,14 +274,26 @@ */ /* Unrecognized compiler, use defaults */ + #ifndef ACPI_ASM_MACROS +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + #define ACPI_ASM_MACROS -#define causeinterrupt(level) #define BREAKPOINT3 -#define disable() -#define enable() -#define halt() +#define ACPI_DISABLE_IRQS() +#define ACPI_ENABLE_IRQS() #define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acq) #define ACPI_RELEASE_GLOBAL_LOCK(Glptr, acq) @@ -274,21 +304,15 @@ /* Don't want software interrupts within a ring3 application */ -#undef causeinterrupt #undef BREAKPOINT3 -#define causeinterrupt(level) #define BREAKPOINT3 #endif /****************************************************************************** * - * Compiler-specific + * Compiler-specific information is contained in the compiler-specific + * headers. * *****************************************************************************/ - -/* this has been moved to compiler-specific headers, which are included from the - platform header. */ - - #endif /* __ACENV_H__ */ diff -Nur linux-2.4.19/drivers/acpi/include/platform/acgcc.h linux-2.4.19-sgi211r3/drivers/acpi/include/platform/acgcc.h --- linux-2.4.19/drivers/acpi/include/platform/acgcc.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/platform/acgcc.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: acgcc.h - GCC specific defines, etc. - * $Revision: 14 $ + * $Revision: 23 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,140 +25,6 @@ #ifndef __ACGCC_H__ #define __ACGCC_H__ - - -#ifdef __ia64__ -#define _IA64 - -#define COMPILER_DEPENDENT_UINT64 unsigned long -/* Single threaded */ -#define ACPI_APPLICATION - -#define ACPI_ASM_MACROS -#define causeinterrupt(level) -#define BREAKPOINT3 -#define disable() __cli() -#define enable() __sti() - -/*! [Begin] no source code translation */ - -#include - -#define halt() ia64_pal_halt_light() /* PAL_HALT[_LIGHT] */ -#define safe_halt() ia64_pal_halt(1) /* PAL_HALT */ - - -#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - __asm__ volatile ("1: ld4 r29=%1\n" \ - ";;\n" \ - "mov ar.ccv=r29\n" \ - "mov r2=r29\n" \ - "shr.u r30=r29,1\n" \ - "and r29=-4,r29\n" \ - ";;\n" \ - "add r29=2,r29\n" \ - "and r30=1,r30\n" \ - ";;\n" \ - "add r29=r29,r30\n" \ - ";;\n" \ - "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ - ";;\n" \ - "cmp.eq p6,p7=r2,r30\n" \ - "(p7) br.dpnt.few 1b\n" \ - "cmp.gt p8,p9=3,r29\n" \ - ";;\n" \ - "(p8) mov %0=-1\n" \ - "(p9) mov %0=r0\n" \ - :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ - } while (0) - -#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - __asm__ volatile ("1: ld4 r29=%1\n" \ - ";;\n" \ - "mov ar.ccv=r29\n" \ - "mov r2=r29\n" \ - "and r29=-4,r29\n" \ - ";;\n" \ - "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ - ";;\n" \ - "cmp.eq p6,p7=r2,r30\n" \ - "(p7) br.dpnt.few 1b\n" \ - "and %0=1,r2\n" \ - ";;\n" \ - :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ - } while (0) -/*! [End] no source code translation !*/ - - -#else /* DO IA32 */ - -#define COMPILER_DEPENDENT_UINT64 unsigned long long -#define ACPI_ASM_MACROS -#define causeinterrupt(level) -#define BREAKPOINT3 -#define disable() __cli() -#define enable() __sti() -#define halt() __asm__ __volatile__ ("sti; hlt":::"memory") - -/*! [Begin] no source code translation - * - * A brief explanation as GNU inline assembly is a bit hairy - * %0 is the output parameter in EAX ("=a") - * %1 and %2 are the input parameters in ECX ("c") - * and an immediate value ("i") respectively - * All actual register references are preceded with "%%" as in "%%edx" - * Immediate values in the assembly are preceded by "$" as in "$0x1" - * The final asm parameter are the operation altered non-output registers. - */ -#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - int dummy; \ - asm("1: movl (%1),%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "btsl $0x1,%%edx;" \ - "adcl $0x0,%%edx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "cmpb $0x3,%%dl;" \ - "sbbl %%eax,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \ - } while(0) - -#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - int dummy; \ - asm("1: movl (%1),%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "andl $0x1,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \ - } while(0) - - -/* - * Math helper asm macros - */ -#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ - asm("divl %2;" \ - :"=a"(q32), "=d"(r32) \ - :"r"(d32), \ - "0"(n_lo), "1"(n_hi)) - - -#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ - asm("shrl $1,%2;" \ - "rcrl $1,%3;" \ - :"=r"(n_hi), "=r"(n_lo) \ - :"0"(n_hi), "1"(n_lo)) - -/*! [End] no source code translation !*/ - -#endif /* IA 32 */ /* This macro is used to tag functions as "printf-like" because * some compilers (like GCC) can catch printf format string problems. diff -Nur linux-2.4.19/drivers/acpi/include/platform/aclinux.h linux-2.4.19-sgi211r3/drivers/acpi/include/platform/aclinux.h --- linux-2.4.19/drivers/acpi/include/platform/aclinux.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/include/platform/aclinux.h Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Name: aclinux.h - OS specific defines, etc. - * $Revision: 14 $ + * $Revision: 25 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,24 +39,37 @@ #include #include #include +#include #define strtoul simple_strtoul -#else +#define ACPI_MACHINE_WIDTH BITS_PER_LONG + +#else /* !__KERNEL__ */ #include #include #include #include +#if defined(__ia64__) || defined(__x86_64__) +#define ACPI_MACHINE_WIDTH 64 +#define COMPILER_DEPENDENT_INT64 long +#define COMPILER_DEPENDENT_UINT64 unsigned long +#else +#define ACPI_MACHINE_WIDTH 32 +#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long +#define ACPI_USE_NATIVE_DIVIDE #endif +#endif /* __KERNEL__ */ + /* Linux uses GCC */ #include "acgcc.h" #undef DEBUGGER_THREADING -#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED - +#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED #endif /* __ACLINUX_H__ */ diff -Nur linux-2.4.19/drivers/acpi/kdb/README.txt linux-2.4.19-sgi211r3/drivers/acpi/kdb/README.txt --- linux-2.4.19/drivers/acpi/kdb/README.txt Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/kdb/README.txt Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -Using the ACPI debugger with kdb --------------------------------- - -ACPI CA includes a full-featured debugger, which allows the examination of -a running system's ACPI tables, as well as running and stepping through -control methods. - -Configuration -------------- -1) Edit the main acpi Makefile. On the ACPI_CFLAGS line, remove the '#', thus - enabling the debugger. - -2) Download the latest kdb patch from: - - ftp://oss.sgi.com/www/projects/kdb/download/ix86/ - - Follow the instructions at http://oss.sgi.com/projects/kdb/ on how to - install the patch and configure KDB. - -3) This would probably be a good time to recompile the kernel, and make sure - kdb works (Hitting the Pause key should drop you into it. Type "go" to exit - it. - -4) The kdb <--> ACPI debugger interface is a module. Type "make modules", and - it will be built and placed in drivers/acpi/kdb. - -5) Change to that directory and type "insmod kdbm_acpi.o". This loads the - module we just built. - -6) Break back into kdb. If you type help, you should now see "acpi" listed as - a command, at the bottom. - -7) Type "acpi". You are now in the ACPI debugger. While hosted by kdb, it is - wholly separate, and has many ACPI-specific commands. Type "?" or "help" - to get a listing of the command categories, and then "help " for - a list of commands and their descriptions diff -Nur linux-2.4.19/drivers/acpi/kdb/kdbm_acpi.c linux-2.4.19-sgi211r3/drivers/acpi/kdb/kdbm_acpi.c --- linux-2.4.19/drivers/acpi/kdb/kdbm_acpi.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/kdb/kdbm_acpi.c Wed Dec 31 16:00:00 1969 @@ -1,54 +0,0 @@ -/* - * kdbm_acpi.c - kdb debugger module interface for ACPI debugger - * - * Copyright (C) 2000 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#include "acpi.h" -#include "acdebug.h" - -extern int acpi_in_debugger; - -static int -kdbm_acpi(int argc, const char **argv, const char **envp, struct pt_regs *regs) -{ - acpi_in_debugger = 1; - - acpi_db_user_commands(DB_COMMAND_PROMPT, NULL); - - acpi_in_debugger = 0; - - return 0; -} - -int -init_module(void) -{ - kdb_register("acpi", kdbm_acpi, "", "Enter ACPI debugger", 0); - - return 0; -} - -void -cleanup_module(void) -{ - kdb_unregister("acpi"); -} diff -Nur linux-2.4.19/drivers/acpi/namespace/Makefile linux-2.4.19-sgi211r3/drivers/acpi/namespace/Makefile --- linux-2.4.19/drivers/acpi/namespace/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/namespace/nsaccess.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsaccess.c --- linux-2.4.19/drivers/acpi/namespace/nsaccess.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsaccess.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nsaccess - Top-level functions for accessing ACPI namespace - * $Revision: 135 $ + * $Revision: 155 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,13 +26,12 @@ #include "acpi.h" #include "amlcode.h" -#include "acinterp.h" #include "acnamesp.h" #include "acdispat.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsaccess") + ACPI_MODULE_NAME ("nsaccess") /******************************************************************************* @@ -52,16 +51,19 @@ acpi_status acpi_ns_root_initialize (void) { - acpi_status status = AE_OK; - const predefined_names *init_val = NULL; - acpi_namespace_node *new_node; - acpi_operand_object *obj_desc; + acpi_status status; + const acpi_predefined_names *init_val = NULL; + acpi_namespace_node *new_node; + acpi_operand_object *obj_desc; - FUNCTION_TRACE ("Ns_root_initialize"); + ACPI_FUNCTION_TRACE ("Ns_root_initialize"); - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* * The global root ptr is initially NULL, so a non-NULL value indicates @@ -72,22 +74,20 @@ goto unlock_and_exit; } - /* * Tell the rest of the subsystem that the root is initialized * (This is OK because the namespace is locked) */ acpi_gbl_root_node = &acpi_gbl_root_node_struct; - /* Enter the pre-defined names in the name table */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Entering predefined entries into namespace\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Entering predefined entries into namespace\n")); for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { status = acpi_ns_lookup (NULL, init_val->name, init_val->type, - IMODE_LOAD_PASS2, NS_NO_UPSEARCH, - NULL, &new_node); + ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); if (ACPI_FAILURE (status) || (!new_node)) /* Must be on same line for code converter */ { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -116,13 +116,11 @@ * internal representation. Only types actually * used for initial values are implemented here. */ - switch (init_val->type) { - case ACPI_TYPE_INTEGER: obj_desc->integer.value = - (acpi_integer) STRTOUL (init_val->val, NULL, 10); + (acpi_integer) ACPI_STRTOUL (init_val->val, NULL, 10); break; @@ -131,7 +129,7 @@ /* * Build an object around the static string */ - obj_desc->string.length = STRLEN (init_val->val); + obj_desc->string.length = ACPI_STRLEN (init_val->val); obj_desc->string.pointer = init_val->val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; @@ -140,16 +138,15 @@ case ACPI_TYPE_MUTEX: obj_desc->mutex.sync_level = - (u16) STRTOUL (init_val->val, NULL, 10); + (u16) ACPI_STRTOUL (init_val->val, NULL, 10); - if (STRCMP (init_val->name, "_GL_") == 0) { + if (ACPI_STRCMP (init_val->name, "_GL_") == 0) { /* * Create a counting semaphore for the * global lock */ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 1, &obj_desc->mutex.semaphore); - if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -160,13 +157,11 @@ */ acpi_gbl_global_lock_semaphore = obj_desc->mutex.semaphore; } - else { /* Create a mutex */ status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore); - if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -175,7 +170,7 @@ default: - REPORT_ERROR (("Unsupported initial type value %X\n", + ACPI_REPORT_ERROR (("Unsupported initial type value %X\n", init_val->type)); acpi_ut_remove_reference (obj_desc); obj_desc = NULL; @@ -184,7 +179,7 @@ /* Store pointer to value descriptor in the Node */ - acpi_ns_attach_object (new_node, obj_desc, obj_desc->common.type); + status = acpi_ns_attach_object (new_node, obj_desc, obj_desc->common.type); /* Remove local reference to the object */ @@ -194,7 +189,7 @@ unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } @@ -226,8 +221,8 @@ acpi_ns_lookup ( acpi_generic_state *scope_info, NATIVE_CHAR *pathname, - acpi_object_type8 type, - operating_mode interpreter_mode, + acpi_object_type type, + acpi_interpreter_mode interpreter_mode, u32 flags, acpi_walk_state *walk_state, acpi_namespace_node **return_node) @@ -235,33 +230,26 @@ acpi_status status; acpi_namespace_node *prefix_node; acpi_namespace_node *current_node = NULL; - acpi_namespace_node *scope_to_push = NULL; acpi_namespace_node *this_node = NULL; u32 num_segments; acpi_name simple_name; - u8 null_name_path = FALSE; - acpi_object_type8 type_to_check_for; - acpi_object_type8 this_search_type; - u32 local_flags = flags & ~NS_ERROR_IF_FOUND; + acpi_object_type type_to_check_for; + acpi_object_type this_search_type; + u32 local_flags = flags & ~ACPI_NS_ERROR_IF_FOUND; - DEBUG_EXEC (u32 i;) - - FUNCTION_TRACE ("Ns_lookup"); + ACPI_FUNCTION_TRACE ("Ns_lookup"); if (!return_node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_gbl_ns_lookup_count++; - - *return_node = ENTRY_NOT_FOUND; - + *return_node = ACPI_ENTRY_NOT_FOUND; if (!acpi_gbl_root_node) { - return (AE_NO_NAMESPACE); + return_ACPI_STATUS (AE_NO_NAMESPACE); } /* @@ -270,7 +258,8 @@ */ if ((!scope_info) || (!scope_info->scope.node)) { - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Null scope prefix, using root node (%p)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Null scope prefix, using root node (%p)\n", acpi_gbl_root_node)); prefix_node = acpi_gbl_root_node; @@ -279,7 +268,6 @@ prefix_node = scope_info->scope.node; } - /* * This check is explicitly split to relax the Type_to_check_for * conditions for Bank_field_defn. Originally, both Bank_field_defn and @@ -292,210 +280,201 @@ type_to_check_for = ACPI_TYPE_REGION; } - else if (INTERNAL_TYPE_BANK_FIELD_DEFN == type) { /* Bank_field_defn defines data fields in a Field Object */ type_to_check_for = ACPI_TYPE_ANY; } - else { type_to_check_for = type; } - - /* TBD: [Restructure] - Move the pathname stuff into a new procedure */ - - /* Examine the name pointer */ - + /* + * Begin examination of the actual pathname + */ if (!pathname) { - /* 8-12-98 ASL Grammar Update supports null Name_path */ + /* A Null Name_path is allowed and refers to the root */ - null_name_path = TRUE; num_segments = 0; - this_node = acpi_gbl_root_node; + this_node = acpi_gbl_root_node; + pathname = ""; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, - "Null Pathname (Zero segments), Flags=%x\n", flags)); + "Null Pathname (Zero segments), Flags=%X\n", flags)); } - else { /* - * Valid name pointer (Internal name format) + * Name pointer is valid (and must be in internal name format) * - * Check for prefixes. As represented in the AML stream, a - * Pathname consists of an optional scope prefix followed by - * a segment part. + * Check for scope prefixes: * - * If present, the scope prefix is either a Root_prefix (in - * which case the name is fully qualified), or zero or more - * Parent_prefixes (in which case the name's scope is relative - * to the current scope). + * As represented in the AML stream, a namepath consists of an + * optional scope prefix followed by a name segment part. * - * The segment part consists of either: - * - A single 4-byte name segment, or - * - A Dual_name_prefix followed by two 4-byte name segments, or - * - A Multi_name_prefix_op, followed by a byte indicating the - * number of segments and the segments themselves. + * If present, the scope prefix is either a Root Prefix (in + * which case the name is fully qualified), or one or more + * Parent Prefixes (in which case the name's scope is relative + * to the current scope). */ - if (*pathname == AML_ROOT_PREFIX) { - /* Pathname is fully qualified, look in root name table */ + if (*pathname == (u8) AML_ROOT_PREFIX) { + /* Pathname is fully qualified, start from the root */ - current_node = acpi_gbl_root_node; + this_node = acpi_gbl_root_node; - /* point to segment part */ + /* Point to name segment part */ pathname++; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching from root [%p]\n", - current_node)); - - /* Direct reference to root, "\" */ - - if (!(*pathname)) { - this_node = acpi_gbl_root_node; - goto check_for_new_scope_and_exit; - } + this_node)); } - else { /* Pathname is relative to current scope, start there */ - current_node = prefix_node; - - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching relative to pfx scope [%p]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Searching relative to pfx scope [%p]\n", prefix_node)); /* - * Handle up-prefix (carat). More than one prefix - * is supported + * Handle multiple Parent Prefixes (carat) by just getting + * the parent node for each prefix instance. */ - while (*pathname == AML_PARENT_PREFIX) { - /* Point to segment part or next Parent_prefix */ - + this_node = prefix_node; + while (*pathname == (u8) AML_PARENT_PREFIX) { + /* + * Point past this prefix to the name segment + * part or the next Parent Prefix + */ pathname++; - /* Backup to the parent's scope */ + /* Backup to the parent node */ - this_node = acpi_ns_get_parent_object (current_node); + this_node = acpi_ns_get_parent_node (this_node); if (!this_node) { /* Current scope has no parent scope */ - REPORT_ERROR ( - ("Too many parent prefixes (^) - reached root\n")); + ACPI_REPORT_ERROR ( + ("ACPI path has too many parent prefixes (^) - reached beyond root node\n")); return_ACPI_STATUS (AE_NOT_FOUND); } - - current_node = this_node; } } - /* - * Examine the name prefix opcode, if any, - * to determine the number of segments + * Determine the number of ACPI name segments in this pathname. + * + * The segment part consists of either: + * - A Null name segment (0) + * - A Dual_name_prefix followed by two 4-byte name segments + * - A Multi_name_prefix followed by a byte indicating the + * number of segments and the segments themselves. + * - A single 4-byte name segment + * + * Examine the name prefix opcode, if any, to determine the number of + * segments. */ - if (*pathname == AML_DUAL_NAME_PREFIX) { - num_segments = 2; + switch (*pathname) { + case 0: + /* + * Null name after a root or parent prefixes. We already + * have the correct target node and there are no name segments. + */ + num_segments = 0; - /* point to first segment */ + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Prefix-only Pathname (Zero name segments), Flags=%X\n", flags)); + break; + + case AML_DUAL_NAME_PREFIX: + + /* Two segments, point to first name segment */ + num_segments = 2; pathname++; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Dual Pathname (2 segments, Flags=%X)\n", flags)); - } + break; - else if (*pathname == AML_MULTI_NAME_PREFIX_OP) { - num_segments = (u32)* (u8 *) ++pathname; + case AML_MULTI_NAME_PREFIX_OP: - /* point to first segment */ + /* Extract segment count, point to first name segment */ pathname++; + num_segments = (u32) (u8) *pathname; + pathname++; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Multi Pathname (%d Segments, Flags=%X) \n", num_segments, flags)); - } + break; - else { + default: /* - * No Dual or Multi prefix, hence there is only one - * segment and Pathname is already pointing to it. + * Not a Null name, no Dual or Multi prefix, hence there is + * only one name segment and Pathname is already pointing to it. */ num_segments = 1; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Simple Pathname (1 segment, Flags=%X)\n", flags)); + break; } -#ifdef ACPI_DEBUG - - /* TBD: [Restructure] Make this a procedure */ - - /* Debug only: print the entire name that we are about to lookup */ - - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[")); - - for (i = 0; i < num_segments; i++) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES, "%4.4s/", (char*)&pathname[i * 4])); - } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES, "]\n")); -#endif + ACPI_DEBUG_EXEC (acpi_ns_print_pathname (num_segments, pathname)); } - /* - * Search namespace for each segment of the name. - * Loop through and verify/add each name segment. + * Search namespace for each segment of the name. Loop through and + * verify/add each name segment. */ - while (num_segments-- && current_node) { + current_node = this_node; + while (num_segments && current_node) { /* * Search for the current name segment under the current - * named object. The Type is significant only at the last (topmost) - * level. (We don't care about the types along the path, only + * named object. The Type is significant only at the last name + * segment. (We don't care about the types along the path, only * the type of the final target object.) */ this_search_type = ACPI_TYPE_ANY; + num_segments--; if (!num_segments) { this_search_type = type; local_flags = flags; } - /* Pluck one ACPI name from the front of the pathname */ + /* Extract one ACPI name from the front of the pathname */ - MOVE_UNALIGNED32_TO_32 (&simple_name, pathname); + ACPI_MOVE_UNALIGNED32_TO_32 (&simple_name, pathname); /* Try to find the ACPI name */ - status = acpi_ns_search_and_enter (simple_name, walk_state, - current_node, interpreter_mode, - this_search_type, local_flags, - &this_node); - + status = acpi_ns_search_and_enter (simple_name, walk_state, current_node, + interpreter_mode, this_search_type, local_flags, &this_node); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { - /* Name not found in ACPI namespace */ + /* Name not found in ACPI namespace */ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, - "Name [%4.4s] not found in scope %p\n", - (char*)&simple_name, current_node)); + "Name [%4.4s] not found in scope [%4.4s] %p\n", + (char *) &simple_name, (char *) ¤t_node->name, current_node)); } return_ACPI_STATUS (status); } - /* + * Sanity typecheck of the target object: + * * If 1) This is the last segment (Num_segments == 0) - * 2) and looking for a specific type + * 2) And we are looking for a specific type * (Not checking for TYPE_ANY) * 3) Which is not an alias - * 4) which is not a local type (TYPE_DEF_ANY) - * 5) which is not a local type (TYPE_SCOPE) - * 6) which is not a local type (TYPE_INDEX_FIELD_DEFN) - * 7) and type of object is known (not TYPE_ANY) - * 8) and object does not match request + * 4) Which is not a local type (TYPE_DEF_ANY) + * 5) Which is not a local type (TYPE_SCOPE) + * 6) Which is not a local type (TYPE_INDEX_FIELD_DEFN) + * 7) And the type of target object is known (not TYPE_ANY) + * 8) And target object does not match what we are looking for * * Then we have a type mismatch. Just warn and ignore it. */ @@ -509,9 +488,9 @@ (this_node->type != type_to_check_for)) { /* Complain about a type mismatch */ - REPORT_WARNING ( + ACPI_REPORT_WARNING ( ("Ns_lookup: %4.4s, type %X, checking for type %X\n", - (char*)&simple_name, this_node->type, type_to_check_for)); + (char *) &simple_name, this_node->type, type_to_check_for)); } /* @@ -519,57 +498,33 @@ * specific type, but the type of found object is known, use that type * to see if it opens a scope. */ - if ((0 == num_segments) && (ACPI_TYPE_ANY == type)) { + if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) { type = this_node->type; } - if ((num_segments || acpi_ns_opens_scope (type)) && - (this_node->child == NULL)) { - /* - * More segments or the type implies enclosed scope, - * and the next scope has not been allocated. - */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Load mode=%X This_node=%p\n", - interpreter_mode, this_node)); - } - - current_node = this_node; - - /* point to next name segment */ + /* Point to next name segment and make this node current */ pathname += ACPI_NAME_SIZE; + current_node = this_node; } - /* * Always check if we need to open a new scope */ -check_for_new_scope_and_exit: - - if (!(flags & NS_DONT_OPEN_SCOPE) && (walk_state)) { + if (!(flags & ACPI_NS_DONT_OPEN_SCOPE) && (walk_state)) { /* - * If entry is a type which opens a scope, - * push the new scope on the scope stack. + * If entry is a type which opens a scope, push the new scope on the + * scope stack. */ if (acpi_ns_opens_scope (type_to_check_for)) { - /* 8-12-98 ASL Grammar Update supports null Name_path */ - - if (null_name_path) { - /* TBD: [Investigate] - is this the correct thing to do? */ - - scope_to_push = NULL; - } - else { - scope_to_push = this_node; - } - - status = acpi_ds_scope_stack_push (scope_to_push, type, - walk_state); + status = acpi_ds_scope_stack_push (this_node, type, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Set global scope to %p\n", scope_to_push)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Setting current scope to [%4.4s] (%p)\n", + this_node->name.ascii, this_node)); } } diff -Nur linux-2.4.19/drivers/acpi/namespace/nsalloc.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsalloc.c --- linux-2.4.19/drivers/acpi/namespace/nsalloc.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsalloc.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nsalloc - Namespace allocation and deletion utilities - * $Revision: 60 $ + * $Revision: 74 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,11 +26,10 @@ #include "acpi.h" #include "acnamesp.h" -#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsalloc") + ACPI_MODULE_NAME ("nsalloc") /******************************************************************************* @@ -52,7 +51,7 @@ acpi_namespace_node *node; - FUNCTION_TRACE ("Ns_create_node"); + ACPI_FUNCTION_TRACE ("Ns_create_node"); node = ACPI_MEM_CALLOCATE (sizeof (acpi_namespace_node)); @@ -62,9 +61,9 @@ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_allocated++); - node->data_type = ACPI_DESC_TYPE_NAMED; - node->name = name; + node->name.integer = name; node->reference_count = 1; + ACPI_SET_DESCRIPTOR_TYPE (node, ACPI_DESC_TYPE_NAMED); return_PTR (node); } @@ -91,10 +90,10 @@ acpi_namespace_node *next_node; - FUNCTION_TRACE_PTR ("Ns_delete_node", node); + ACPI_FUNCTION_TRACE_PTR ("Ns_delete_node", node); - parent_node = acpi_ns_get_parent_object (node); + parent_node = acpi_ns_get_parent_node (node); prev_node = NULL; next_node = parent_node->child; @@ -118,12 +117,9 @@ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); /* - * Detach an object if there is one + * Detach an object if there is one then delete the node */ - if (node->object) { - acpi_ns_detach_object (node); - } - + acpi_ns_detach_object (node); ACPI_MEM_FREE (node); return_VOID; } @@ -140,7 +136,11 @@ * * RETURN: None * - * DESCRIPTION: Initialize a new entry within a namespace table. + * DESCRIPTION: Initialize a new namespace node and install it amongst + * its peers. + * + * Note: Current namespace lookup is linear search, so the nodes + * are not linked in any particular order. * ******************************************************************************/ @@ -149,13 +149,13 @@ acpi_walk_state *walk_state, acpi_namespace_node *parent_node, /* Parent */ acpi_namespace_node *node, /* New Child*/ - acpi_object_type8 type) + acpi_object_type type) { u16 owner_id = TABLE_ID_DSDT; acpi_namespace_node *child_node; - FUNCTION_TRACE ("Ns_install_node"); + ACPI_FUNCTION_TRACE ("Ns_install_node"); /* @@ -167,16 +167,12 @@ owner_id = walk_state->owner_id; } - - /* link the new entry into the parent and existing children */ - - /* TBD: Could be first, last, or alphabetic */ + /* Link the new entry into the parent and existing children */ child_node = parent_node->child; if (!child_node) { parent_node->child = node; } - else { while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) { child_node = child_node->peer; @@ -209,8 +205,8 @@ * We will fill in the actual type when the * real definition is found later. */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "[%4.4s] is a forward reference\n", - (char*)&node->name)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] is a forward reference\n", + node->name.ascii)); } /* @@ -235,13 +231,13 @@ } ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s added to %p at %p\n", - (char*)&node->name, parent_node, node)); + node->name.ascii, parent_node, node)); /* * Increment the reference count(s) of all parents up to * the root! */ - while ((node = acpi_ns_get_parent_object (node)) != NULL) { + while ((node = acpi_ns_get_parent_node (node)) != NULL) { node->reference_count++; } @@ -257,8 +253,8 @@ * * RETURN: None. * - * DESCRIPTION: Delete all children of the parent object. Deletes a - * "scope". + * DESCRIPTION: Delete all children of the parent object. In other words, + * deletes a "scope". * ******************************************************************************/ @@ -271,7 +267,7 @@ u8 flags; - FUNCTION_TRACE_PTR ("Ns_delete_children", parent_node); + ACPI_FUNCTION_TRACE_PTR ("Ns_delete_children", parent_node); if (!parent_node) { @@ -305,7 +301,7 @@ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object %p, Remaining %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p, Remaining %X\n", child_node, acpi_gbl_current_node_count)); /* @@ -338,11 +334,11 @@ * RETURN: None. * * DESCRIPTION: Delete a subtree of the namespace. This includes all objects - * stored within the subtree. Scope tables are deleted also + * stored within the subtree. * ******************************************************************************/ -acpi_status +void acpi_ns_delete_namespace_subtree ( acpi_namespace_node *parent_node) { @@ -350,11 +346,11 @@ u32 level = 1; - FUNCTION_TRACE ("Ns_delete_namespace_subtree"); + ACPI_FUNCTION_TRACE ("Ns_delete_namespace_subtree"); if (!parent_node) { - return_ACPI_STATUS (AE_OK); + return_VOID; } /* @@ -383,7 +379,6 @@ child_node = 0; } } - else { /* * No more children of this parent node. @@ -403,11 +398,11 @@ /* Move up the tree to the grandparent */ - parent_node = acpi_ns_get_parent_object (parent_node); + parent_node = acpi_ns_get_parent_node (parent_node); } } - return_ACPI_STATUS (AE_OK); + return_VOID; } @@ -430,34 +425,37 @@ acpi_ns_remove_reference ( acpi_namespace_node *node) { - acpi_namespace_node *next_node; + acpi_namespace_node *parent_node; + acpi_namespace_node *this_node; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* * Decrement the reference count(s) of this node and all * nodes up to the root, Delete anything with zero remaining references. */ - next_node = node; - while (next_node) { - /* Decrement the reference count on this node*/ + this_node = node; + while (this_node) { + /* Prepare to move up to parent */ - next_node->reference_count--; + parent_node = acpi_ns_get_parent_node (this_node); + + /* Decrement the reference count on this node */ + + this_node->reference_count--; /* Delete the node if no more references */ - if (!next_node->reference_count) { + if (!this_node->reference_count) { /* Delete all children and delete the node */ - acpi_ns_delete_children (next_node); - acpi_ns_delete_node (next_node); + acpi_ns_delete_children (this_node); + acpi_ns_delete_node (this_node); } - /* Move up to parent */ - - next_node = acpi_ns_get_parent_object (next_node); + this_node = parent_node; } } @@ -476,65 +474,71 @@ * ******************************************************************************/ -acpi_status +void acpi_ns_delete_namespace_by_owner ( u16 owner_id) { acpi_namespace_node *child_node; + acpi_namespace_node *deletion_node; u32 level; acpi_namespace_node *parent_node; - FUNCTION_TRACE ("Ns_delete_namespace_by_owner"); + ACPI_FUNCTION_TRACE_U32 ("Ns_delete_namespace_by_owner", owner_id); - parent_node = acpi_gbl_root_node; - child_node = 0; - level = 1; + parent_node = acpi_gbl_root_node; + child_node = NULL; + deletion_node = NULL; + level = 1; /* * Traverse the tree of nodes until we bubble back up * to where we started. */ while (level > 0) { - /* Get the next node in this scope (NULL if none) */ + /* + * Get the next child of this parent node. When Child_node is NULL, + * the first child of the parent is returned + */ + child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node, child_node); + + if (deletion_node) { + acpi_ns_remove_reference (deletion_node); + deletion_node = NULL; + } - child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node, - child_node); if (child_node) { if (child_node->owner_id == owner_id) { - /* Found a child node - detach any attached object */ + /* Found a matching child node - detach any attached object */ acpi_ns_detach_object (child_node); } /* Check if this node has any children */ - if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, 0)) { + if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) { /* * There is at least one child of this node, * visit the node */ level++; parent_node = child_node; - child_node = 0; + child_node = NULL; } - else if (child_node->owner_id == owner_id) { - acpi_ns_remove_reference (child_node); + deletion_node = child_node; } } - else { /* * No more children of this parent node. * Move up to the grandparent. */ level--; - if (level != 0) { if (parent_node->owner_id == owner_id) { - acpi_ns_remove_reference (parent_node); + deletion_node = parent_node; } } @@ -544,11 +548,11 @@ /* Move up the tree to the grandparent */ - parent_node = acpi_ns_get_parent_object (parent_node); + parent_node = acpi_ns_get_parent_node (parent_node); } } - return_ACPI_STATUS (AE_OK); + return_VOID; } diff -Nur linux-2.4.19/drivers/acpi/namespace/nsdump.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsdump.c --- linux-2.4.19/drivers/acpi/namespace/nsdump.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsdump.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: nsdump - table dumping routines for debug - * $Revision: 105 $ + * $Revision: 135 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,18 +25,57 @@ #include "acpi.h" -#include "acinterp.h" #include "acnamesp.h" -#include "actables.h" #include "acparser.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsdump") - + ACPI_MODULE_NAME ("nsdump") #if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_print_pathname + * + * PARAMETERS: Num_segment - Number of ACPI name segments + * Pathname - The compressed (internal) path + * + * DESCRIPTION: Print an object's full namespace pathname + * + ******************************************************************************/ + +void +acpi_ns_print_pathname ( + u32 num_segments, + char *pathname) +{ + ACPI_FUNCTION_NAME ("Ns_print_pathname"); + + + if (!(acpi_dbg_level & ACPI_LV_NAMES) || !(acpi_dbg_layer & ACPI_NAMESPACE)) { + return; + } + + /* Print the entire name */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[")); + + while (num_segments) { + acpi_os_printf ("%4.4s", pathname); + pathname += ACPI_NAME_SIZE; + + num_segments--; + if (num_segments) { + acpi_os_printf ("."); + } + } + + acpi_os_printf ("]\n"); +} + + /******************************************************************************* * * FUNCTION: Acpi_ns_dump_pathname @@ -58,11 +97,11 @@ u32 level, u32 component) { - NATIVE_CHAR *buffer; - u32 length; + acpi_buffer buffer; + acpi_status status; - FUNCTION_TRACE ("Ns_dump_pathname"); + ACPI_FUNCTION_TRACE ("Ns_dump_pathname"); /* Do this only if the requested debug level and component are enabled */ @@ -71,21 +110,17 @@ return_ACPI_STATUS (AE_OK); } - buffer = ACPI_MEM_ALLOCATE (PATHNAME_MAX); - if (!buffer) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - /* Convert handle to a full pathname and print it (with supplied message) */ - length = PATHNAME_MAX; - if (ACPI_SUCCESS (acpi_ns_handle_to_pathname (handle, &length, buffer))) { - acpi_os_printf ("%s %s (%p)\n", msg, buffer, handle); - } + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - ACPI_MEM_FREE (buffer); + status = acpi_ns_handle_to_pathname (handle, &buffer); + if (ACPI_SUCCESS (status)) { + acpi_os_printf ("%s %s (Node %p)\n", msg, buffer.pointer, handle); + ACPI_MEM_FREE (buffer.pointer); + } - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } @@ -112,16 +147,17 @@ acpi_walk_info *info = (acpi_walk_info *) context; acpi_namespace_node *this_node; acpi_operand_object *obj_desc = NULL; - acpi_object_type8 obj_type; - acpi_object_type8 type; + acpi_object_type obj_type; + acpi_object_type type; u32 bytes_to_dump; u32 downstream_sibling_mask = 0; u32 level_tmp; u32 which_bit; u32 i; + u32 dbg_level; - PROC_NAME ("Ns_dump_one_object"); + ACPI_FUNCTION_NAME ("Ns_dump_one_object"); this_node = acpi_ns_map_handle_to_node (obj_handle); @@ -147,68 +183,63 @@ return (AE_OK); } - /* Indent the object according to the level */ while (level_tmp--) { - /* Print appropriate characters to form tree structure */ if (level_tmp) { if (downstream_sibling_mask & which_bit) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "|")); + acpi_os_printf ("|"); } - else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ")); + acpi_os_printf (" "); } which_bit <<= 1; } - else { if (acpi_ns_exist_downstream_sibling (this_node + 1)) { - downstream_sibling_mask |= (1 << (level - 1)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "+")); + downstream_sibling_mask |= ((u32) 1 << (level - 1)); + acpi_os_printf ("+"); } - else { - downstream_sibling_mask &= ACPI_UINT32_MAX ^ (1 << (level - 1)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "+")); + downstream_sibling_mask &= ACPI_UINT32_MAX ^ ((u32) 1 << (level - 1)); + acpi_os_printf ("+"); } if (this_node->child == NULL) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "-")); + acpi_os_printf ("-"); } - else if (acpi_ns_exist_downstream_sibling (this_node->child)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "+")); + acpi_os_printf ("+"); } - else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "-")); + acpi_os_printf ("-"); } } } - /* Check the integrity of our data */ if (type > INTERNAL_TYPE_MAX) { - type = INTERNAL_TYPE_DEF_ANY; /* prints as *ERROR* */ + type = INTERNAL_TYPE_DEF_ANY; /* prints as *ERROR* */ } - if (!acpi_ut_valid_acpi_name (this_node->name)) { - REPORT_WARNING (("Invalid ACPI Name %08X\n", this_node->name)); + if (!acpi_ut_valid_acpi_name (this_node->name.integer)) { + ACPI_REPORT_WARNING (("Invalid ACPI Name %08X\n", this_node->name.integer)); } /* * Now we can print out the pertinent information */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " %4.4s %-12s %p", - (char*)&this_node->name, acpi_ut_get_type_name (type), this_node)); + acpi_os_printf (" %4.4s %-12s %p", + this_node->name.ascii, acpi_ut_get_type_name (type), this_node); - obj_desc = this_node->object; + dbg_level = acpi_dbg_level; + acpi_dbg_level = 0; + obj_desc = acpi_ns_get_attached_object (this_node); + acpi_dbg_level = dbg_level; switch (info->display_type) { case ACPI_DISPLAY_SUMMARY: @@ -216,110 +247,149 @@ if (!obj_desc) { /* No attached object, we are done */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "\n")); + acpi_os_printf ("\n"); return (AE_OK); } - switch (type) { case ACPI_TYPE_PROCESSOR: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ID %d Addr %.4X Len %.4X\n", + + acpi_os_printf (" ID %hd Addr %.4X Len %.4X\n", obj_desc->processor.proc_id, obj_desc->processor.address, - obj_desc->processor.length)); + obj_desc->processor.length); break; + case ACPI_TYPE_DEVICE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Notification object: %p", obj_desc)); + + acpi_os_printf (" Notification object: %p", obj_desc); break; + case ACPI_TYPE_METHOD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Args %d Len %.4X Aml %p \n", + + acpi_os_printf (" Args %hd Len %.4X Aml %p \n", obj_desc->method.param_count, obj_desc->method.aml_length, - obj_desc->method.aml_start)); + obj_desc->method.aml_start); break; + case ACPI_TYPE_INTEGER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " = %8.8X%8.8X\n", - HIDWORD (obj_desc->integer.value), - LODWORD (obj_desc->integer.value))); + + acpi_os_printf (" = %8.8X%8.8X\n", + ACPI_HIDWORD (obj_desc->integer.value), + ACPI_LODWORD (obj_desc->integer.value)); break; + case ACPI_TYPE_PACKAGE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Elements %.2X\n", - obj_desc->package.count)); + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + acpi_os_printf (" Elements %.2X\n", + obj_desc->package.count); + } + else { + acpi_os_printf (" [Length not yet evaluated]\n"); + } break; - case ACPI_TYPE_BUFFER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Len %.2X", - obj_desc->buffer.length)); - /* Dump some of the buffer */ + case ACPI_TYPE_BUFFER: - if (obj_desc->buffer.length > 0) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " =")); - for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " %.2X", - obj_desc->buffer.pointer[i])); + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + acpi_os_printf (" Len %.2X", + obj_desc->buffer.length); + + /* Dump some of the buffer */ + + if (obj_desc->buffer.length > 0) { + acpi_os_printf (" ="); + for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) { + acpi_os_printf (" %.2hX", obj_desc->buffer.pointer[i]); + } } + acpi_os_printf ("\n"); + } + else { + acpi_os_printf (" [Length not yet evaluated]\n"); } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "\n")); break; + case ACPI_TYPE_STRING: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Len %.2X", - obj_desc->string.length)); + + acpi_os_printf (" Len %.2X", obj_desc->string.length); if (obj_desc->string.length > 0) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " = \"%.32s\"...", - obj_desc->string.pointer)); + acpi_os_printf (" = \"%.32s\"", obj_desc->string.pointer); + if (obj_desc->string.length > 32) { + acpi_os_printf ("..."); + } } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "\n")); + acpi_os_printf ("\n"); break; + case ACPI_TYPE_REGION: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " [%s]", - acpi_ut_get_region_name (obj_desc->region.space_id))); + + acpi_os_printf (" [%s]", acpi_ut_get_region_name (obj_desc->region.space_id)); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Addr %8.8X%8.8X Len %.4X\n", - HIDWORD(obj_desc->region.address), - LODWORD(obj_desc->region.address), - obj_desc->region.length)); + acpi_os_printf (" Addr %8.8X%8.8X Len %.4X\n", + ACPI_HIDWORD (obj_desc->region.address), + ACPI_LODWORD (obj_desc->region.address), + obj_desc->region.length); } else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " [Address/Length not evaluated]\n")); + acpi_os_printf (" [Address/Length not yet evaluated]\n"); } break; + case INTERNAL_TYPE_REFERENCE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " [%s]\n", - acpi_ps_get_opcode_name (obj_desc->reference.opcode))); + + acpi_os_printf (" [%s]\n", + acpi_ps_get_opcode_name (obj_desc->reference.opcode)); break; + case ACPI_TYPE_BUFFER_FIELD: - /* TBD: print Buffer name when we can easily get it */ + if (obj_desc->buffer_field.buffer_obj && + obj_desc->buffer_field.buffer_obj->buffer.node) { + acpi_os_printf (" Buf [%4.4s]", + obj_desc->buffer_field.buffer_obj->buffer.node->name.ascii); + } break; + case INTERNAL_TYPE_REGION_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Rgn [%4.4s]", - (char *) &obj_desc->common_field.region_obj->region.node->name)); + + acpi_os_printf (" Rgn [%4.4s]", + obj_desc->common_field.region_obj->region.node->name.ascii); break; + case INTERNAL_TYPE_BANK_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Rgn [%4.4s]", - (char *) &obj_desc->common_field.region_obj->region.node->name)); + + acpi_os_printf (" Rgn [%4.4s] Bnk [%4.4s]", + obj_desc->common_field.region_obj->region.node->name.ascii, + obj_desc->bank_field.bank_obj->common_field.node->name.ascii); break; + case INTERNAL_TYPE_INDEX_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Rgn [%4.4s]", - (char *) &obj_desc->index_field.index_obj->common_field.region_obj->region.node->name)); + + acpi_os_printf (" Idx [%4.4s] Dat [%4.4s]", + obj_desc->index_field.index_obj->common_field.node->name.ascii, + obj_desc->index_field.data_obj->common_field.node->name.ascii); break; + default: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Object %p\n", obj_desc)); + acpi_os_printf (" Object %p\n", obj_desc); break; } @@ -330,74 +400,72 @@ case INTERNAL_TYPE_REGION_FIELD: case INTERNAL_TYPE_BANK_FIELD: case INTERNAL_TYPE_INDEX_FIELD: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Off %.2X Len %.2X Acc %.2d\n", - (obj_desc->common_field.base_byte_offset * 8) + obj_desc->common_field.start_field_bit_offset, - obj_desc->common_field.bit_length, - obj_desc->common_field.access_bit_width)); + acpi_os_printf (" Off %.2X Len %.2X Acc %.2hd\n", + (obj_desc->common_field.base_byte_offset * 8) + + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.bit_length, + obj_desc->common_field.access_byte_width); break; - } + default: + break; + } break; case ACPI_DISPLAY_OBJECTS: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "%p O:%p", - this_node, obj_desc)); + acpi_os_printf ("%p O:%p", + this_node, obj_desc); if (!obj_desc) { /* No attached object, we are done */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "\n")); + acpi_os_printf ("\n"); return (AE_OK); } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "(R%d)", - obj_desc->common.reference_count)); + acpi_os_printf ("(R%d)", + obj_desc->common.reference_count); switch (type) { - case ACPI_TYPE_METHOD: /* Name is a Method and its AML offset/length are set */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " M:%p-%X\n", - obj_desc->method.aml_start, - obj_desc->method.aml_length)); - + acpi_os_printf (" M:%p-%X\n", obj_desc->method.aml_start, + obj_desc->method.aml_length); break; - case ACPI_TYPE_INTEGER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " N:%X%X\n", - HIDWORD(obj_desc->integer.value), - LODWORD(obj_desc->integer.value))); + acpi_os_printf (" N:%X%X\n", ACPI_HIDWORD(obj_desc->integer.value), + ACPI_LODWORD(obj_desc->integer.value)); break; - case ACPI_TYPE_STRING: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " S:%p-%X\n", - obj_desc->string.pointer, - obj_desc->string.length)); + acpi_os_printf (" S:%p-%X\n", obj_desc->string.pointer, + obj_desc->string.length); break; - case ACPI_TYPE_BUFFER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " B:%p-%X\n", - obj_desc->buffer.pointer, - obj_desc->buffer.length)); + acpi_os_printf (" B:%p-%X\n", obj_desc->buffer.pointer, + obj_desc->buffer.length); break; - default: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "\n")); + acpi_os_printf ("\n"); break; } break; + + + default: + acpi_os_printf ("\n"); + break; } /* If debug turned off, done */ @@ -409,48 +477,55 @@ /* If there is an attached object, display it */ - obj_desc = this_node->object; + dbg_level = acpi_dbg_level; + acpi_dbg_level = 0; + obj_desc = acpi_ns_get_attached_object (this_node); + acpi_dbg_level = dbg_level; /* Dump attached objects */ while (obj_desc) { obj_type = INTERNAL_TYPE_INVALID; + acpi_os_printf (" Attached Object %p: ", obj_desc); /* Decode the type of attached object and dump the contents */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " Attached Object %p: ", obj_desc)); + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_NAMED: - if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "(Ptr to Node)\n")); + acpi_os_printf ("(Ptr to Node)\n"); bytes_to_dump = sizeof (acpi_namespace_node); - } + break; + + case ACPI_DESC_TYPE_OPERAND: - else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { obj_type = obj_desc->common.type; if (obj_type > INTERNAL_TYPE_MAX) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "(Ptr to ACPI Object type %X [UNKNOWN])\n", obj_type)); + acpi_os_printf ("(Ptr to ACPI Object type %X [UNKNOWN])\n", obj_type); bytes_to_dump = 32; } - else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "(Ptr to ACPI Object type %2.2X [%s])\n", - obj_type, acpi_ut_get_type_name (obj_type))); + acpi_os_printf ("(Ptr to ACPI Object type %s, %X)\n", + acpi_ut_get_type_name (obj_type), obj_type); bytes_to_dump = sizeof (acpi_operand_object); } - } + break; - else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "(String or Buffer - not descriptor)\n")); + + default: + + acpi_os_printf ("(String or Buffer ptr - not an object descriptor)\n"); bytes_to_dump = 16; + break; } - DUMP_BUFFER (obj_desc, bytes_to_dump); + ACPI_DUMP_BUFFER (obj_desc, bytes_to_dump); /* If value is NOT an internal object, we are done */ - if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { goto cleanup; } @@ -459,11 +534,11 @@ */ switch (obj_type) { case ACPI_TYPE_STRING: - obj_desc = (acpi_operand_object *) obj_desc->string.pointer; + obj_desc = (void *) obj_desc->string.pointer; break; case ACPI_TYPE_BUFFER: - obj_desc = (acpi_operand_object *) obj_desc->buffer.pointer; + obj_desc = (void *) obj_desc->buffer.pointer; break; case ACPI_TYPE_BUFFER_FIELD: @@ -471,34 +546,34 @@ break; case ACPI_TYPE_PACKAGE: - obj_desc = (acpi_operand_object *) obj_desc->package.elements; + obj_desc = (void *) obj_desc->package.elements; break; case ACPI_TYPE_METHOD: - obj_desc = (acpi_operand_object *) obj_desc->method.aml_start; + obj_desc = (void *) obj_desc->method.aml_start; break; case INTERNAL_TYPE_REGION_FIELD: - obj_desc = (acpi_operand_object *) obj_desc->field.region_obj; + obj_desc = (void *) obj_desc->field.region_obj; break; case INTERNAL_TYPE_BANK_FIELD: - obj_desc = (acpi_operand_object *) obj_desc->bank_field.region_obj; + obj_desc = (void *) obj_desc->bank_field.region_obj; break; case INTERNAL_TYPE_INDEX_FIELD: - obj_desc = (acpi_operand_object *) obj_desc->index_field.index_obj; + obj_desc = (void *) obj_desc->index_field.index_obj; break; - default: + default: goto cleanup; } - obj_type = INTERNAL_TYPE_INVALID; /* Terminate loop after next pass */ + obj_type = INTERNAL_TYPE_INVALID; /* Terminate loop after next pass */ } cleanup: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, "\n")); + acpi_os_printf ("\n"); return (AE_OK); } @@ -521,7 +596,7 @@ void acpi_ns_dump_objects ( - acpi_object_type8 type, + acpi_object_type type, u8 display_type, u32 max_depth, u32 owner_id, @@ -530,7 +605,7 @@ acpi_walk_info info; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); info.debug_level = ACPI_LV_TABLES; @@ -538,8 +613,9 @@ info.display_type = display_type; - acpi_ns_walk_namespace (type, start_handle, max_depth, NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object, - (void *) &info, NULL); + (void) acpi_ns_walk_namespace (type, start_handle, max_depth, + ACPI_NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object, + (void *) &info, NULL); } @@ -569,7 +645,7 @@ u32 i; - PROC_NAME ("Ns_dump_one_device"); + ACPI_FUNCTION_NAME ("Ns_dump_one_device"); status = acpi_ns_dump_one_object (obj_handle, level, context, return_value); @@ -580,8 +656,10 @@ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ")); } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " HID: %s, ADR: %8.8X%8.8X, Status: %x\n", - info.hardware_id, HIDWORD(info.address), LODWORD(info.address), info.current_status)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " HID: %s, ADR: %8.8X%8.8X, Status: %X\n", + info.hardware_id, + ACPI_HIDWORD (info.address), ACPI_LODWORD (info.address), + info.current_status)); } return (status); @@ -602,9 +680,10 @@ acpi_ns_dump_root_devices (void) { acpi_handle sys_bus_handle; + acpi_status status; - PROC_NAME ("Ns_dump_root_devices"); + ACPI_FUNCTION_NAME ("Ns_dump_root_devices"); /* Only dump the table if tracing is enabled */ @@ -613,11 +692,16 @@ return; } - acpi_get_handle (0, NS_SYSTEM_BUS, &sys_bus_handle); + status = acpi_get_handle (0, ACPI_NS_SYSTEM_BUS, &sys_bus_handle); + if (ACPI_FAILURE (status)) { + return; + } ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Display of all devices in the namespace:\n")); - acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, sys_bus_handle, ACPI_UINT32_MAX, NS_WALK_NO_UNLOCK, - acpi_ns_dump_one_device, NULL, NULL); + + status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, sys_bus_handle, + ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, + acpi_ns_dump_one_device, NULL, NULL); } #endif @@ -643,7 +727,7 @@ acpi_handle search_handle = search_base; - FUNCTION_TRACE ("Ns_dump_tables"); + ACPI_FUNCTION_TRACE ("Ns_dump_tables"); if (!acpi_gbl_root_node) { @@ -655,7 +739,7 @@ return_VOID; } - if (NS_ALL == search_base) { + if (ACPI_NS_ALL == search_base) { /* entire namespace */ search_handle = acpi_gbl_root_node; @@ -688,13 +772,14 @@ acpi_walk_info info; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); info.debug_level = debug_level; info.owner_id = ACPI_UINT32_MAX; + info.display_type = ACPI_DISPLAY_SUMMARY; - acpi_ns_dump_one_object (handle, 1, &info, NULL); + (void) acpi_ns_dump_one_object (handle, 1, &info, NULL); } #endif diff -Nur linux-2.4.19/drivers/acpi/namespace/nseval.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nseval.c --- linux-2.4.19/drivers/acpi/namespace/nseval.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nseval.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: nseval - Object evaluation interfaces -- includes control * method lookup and execution. - * $Revision: 102 $ + * $Revision: 114 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,14 +26,13 @@ #include "acpi.h" -#include "amlcode.h" #include "acparser.h" #include "acinterp.h" #include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nseval") + ACPI_MODULE_NAME ("nseval") /******************************************************************************* @@ -72,7 +71,7 @@ acpi_generic_state scope_info; - FUNCTION_TRACE ("Ns_evaluate_relative"); + ACPI_FUNCTION_TRACE ("Ns_evaluate_relative"); /* @@ -91,11 +90,14 @@ /* Get the prefix handle and Node */ - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } prefix_node = acpi_ns_map_handle_to_node (handle); if (!prefix_node) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); status = AE_BAD_PARAMETER; goto cleanup; } @@ -104,13 +106,13 @@ scope_info.scope.node = prefix_node; status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY, - IMODE_EXECUTE, NS_NO_UPSEARCH, NULL, + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, &node); - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object [%s] not found [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object [%s] not found [%s]\n", pathname, acpi_format_exception (status))); goto cleanup; } @@ -119,12 +121,12 @@ * Now that we have a handle to the object, we can attempt * to evaluate it. */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s [%p] Value %p\n", - pathname, node, node->object)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", + pathname, node, acpi_ns_get_attached_object (node))); status = acpi_ns_evaluate_by_handle (node, params, return_object); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "*** Completed eval of object %s ***\n", + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); cleanup: @@ -165,7 +167,7 @@ NATIVE_CHAR *internal_path = NULL; - FUNCTION_TRACE ("Ns_evaluate_by_name"); + ACPI_FUNCTION_TRACE ("Ns_evaluate_by_name"); /* Build an internal name string for the method */ @@ -175,18 +177,21 @@ return_ACPI_STATUS (status); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Lookup the name in the namespace */ status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, - IMODE_EXECUTE, NS_NO_UPSEARCH, NULL, + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, &node); - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object at [%s] was not found, status=%.4X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object at [%s] was not found, status=%.4X\n", pathname, status)); goto cleanup; } @@ -195,12 +200,12 @@ * Now that we have a handle to the object, we can attempt * to evaluate it. */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s [%p] Value %p\n", - pathname, node, node->object)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", + pathname, node, acpi_ns_get_attached_object (node))); status = acpi_ns_evaluate_by_handle (node, params, return_object); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "*** Completed eval of object %s ***\n", + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); @@ -246,7 +251,7 @@ acpi_operand_object *local_return_object; - FUNCTION_TRACE ("Ns_evaluate_by_handle"); + ACPI_FUNCTION_TRACE ("Ns_evaluate_by_handle"); /* Check if namespace has been initialized */ @@ -269,11 +274,14 @@ /* Get the prefix handle and Node */ - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } node = acpi_ns_map_handle_to_node (handle); if (!node) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -323,12 +331,9 @@ *return_object = local_return_object; } + /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ - /* Map AE_RETURN_VALUE to AE_OK, we are done with it */ - - if (status == AE_CTRL_RETURN_VALUE) { - status = AE_OK; - } + status = AE_OK; } /* @@ -368,7 +373,7 @@ acpi_operand_object *obj_desc; - FUNCTION_TRACE ("Ns_execute_control_method"); + ACPI_FUNCTION_TRACE ("Ns_execute_control_method"); /* Verify that there is a method associated with this object */ @@ -377,21 +382,16 @@ if (!obj_desc) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No attached method object\n")); - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_NULL_OBJECT); } + ACPI_DUMP_PATHNAME (method_node, "Ns_execute_control_method: Executing", + ACPI_LV_INFO, _COMPONENT); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Control method at Offset %p Length %x]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %X\n", obj_desc->method.aml_start + 1, obj_desc->method.aml_length - 1)); - DUMP_PATHNAME (method_node, "Ns_execute_control_method: Executing", - ACPI_LV_NAMES, _COMPONENT); - - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "At offset %p\n", - obj_desc->method.aml_start + 1)); - - /* * Unlock the namespace before execution. This allows namespace access * via the external Acpi* interfaces while a method is being executed. @@ -399,7 +399,10 @@ * interpreter locks to ensure that no thread is using the portion of the * namespace that is being deleted. */ - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* * Execute the method via the interpreter. The interpreter is locked @@ -427,7 +430,7 @@ * * DESCRIPTION: Return the current value of the object * - * MUTEX: Assumes namespace is locked + * MUTEX: Assumes namespace is locked, leaves namespace unlocked * ******************************************************************************/ @@ -437,111 +440,59 @@ acpi_operand_object **return_obj_desc) { acpi_status status = AE_OK; - acpi_operand_object *obj_desc; - acpi_operand_object *source_desc; + acpi_namespace_node *resolved_node = node; - FUNCTION_TRACE ("Ns_get_object_value"); + ACPI_FUNCTION_TRACE ("Ns_get_object_value"); /* - * We take the value from certain objects directly + * Objects require additional resolution steps (e.g., the + * Node may be a field that must be read, etc.) -- we can't just grab + * the object out of the node. */ - if ((node->type == ACPI_TYPE_PROCESSOR) || - (node->type == ACPI_TYPE_POWER)) { - /* - * Create a Reference object to contain the object - */ - obj_desc = acpi_ut_create_internal_object (node->type); - if (!obj_desc) { - status = AE_NO_MEMORY; - goto unlock_and_exit; - } - - /* - * Get the attached object - */ - source_desc = acpi_ns_get_attached_object (node); - if (!source_desc) { - status = AE_NULL_OBJECT; - goto unlock_and_exit; - } - - /* - * Just copy from the original to the return object - * - * TBD: [Future] - need a low-level object copy that handles - * the reference count automatically. (Don't want to copy it) - */ - MEMCPY (obj_desc, source_desc, sizeof (acpi_operand_object)); - obj_desc->common.reference_count = 1; - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - } - /* - * Other objects require a reference object wrapper which we - * then attempt to resolve. + * Use Resolve_node_to_value() to get the associated value. This call + * always deletes Obj_desc (allocated above). + * + * NOTE: we can get away with passing in NULL for a walk state + * because Obj_desc is guaranteed to not be a reference to either + * a method local or a method argument (because this interface can only be + * called from the Acpi_evaluate external interface, never called from + * a running control method.) + * + * Even though we do not directly invoke the interpreter + * for this, we must enter it because we could access an opregion. + * The opregion access code assumes that the interpreter + * is locked. + * + * We must release the namespace lock before entering the + * intepreter. */ - else { - /* Create an Reference object to contain the object */ - - obj_desc = acpi_ut_create_internal_object (INTERNAL_TYPE_REFERENCE); - if (!obj_desc) { - status = AE_NO_MEMORY; - goto unlock_and_exit; - } - - /* Construct a descriptor pointing to the name */ - - obj_desc->reference.opcode = (u8) AML_NAME_OP; - obj_desc->reference.object = (void *) node; + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + status = acpi_ex_enter_interpreter (); + if (ACPI_SUCCESS (status)) { + status = acpi_ex_resolve_node_to_value (&resolved_node, NULL); /* - * Use Resolve_to_value() to get the associated value. This call - * always deletes Obj_desc (allocated above). - * - * NOTE: we can get away with passing in NULL for a walk state - * because Obj_desc is guaranteed to not be a reference to either - * a method local or a method argument - * - * Even though we do not directly invoke the interpreter - * for this, we must enter it because we could access an opregion. - * The opregion access code assumes that the interpreter - * is locked. - * - * We must release the namespace lock before entering the - * intepreter. + * If Acpi_ex_resolve_node_to_value() succeeded, the return value was + * placed in Resolved_node. */ - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - status = acpi_ex_enter_interpreter (); - if (ACPI_SUCCESS (status)) { - status = acpi_ex_resolve_to_value (&obj_desc, NULL); + acpi_ex_exit_interpreter (); - acpi_ex_exit_interpreter (); + if (ACPI_SUCCESS (status)) { + status = AE_CTRL_RETURN_VALUE; + *return_obj_desc = ACPI_CAST_PTR (acpi_operand_object, resolved_node); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning obj %p\n", resolved_node)); } } - /* - * If Acpi_ex_resolve_to_value() succeeded, the return value was - * placed in Obj_desc. - */ - if (ACPI_SUCCESS (status)) { - status = AE_CTRL_RETURN_VALUE; - - *return_obj_desc = obj_desc; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Returning obj %p\n", *return_obj_desc)); - } - /* Namespace is unlocked */ return_ACPI_STATUS (status); - - -unlock_and_exit: - - /* Unlock the namespace */ - - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return_ACPI_STATUS (status); } + diff -Nur linux-2.4.19/drivers/acpi/namespace/nsinit.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsinit.c --- linux-2.4.19/drivers/acpi/namespace/nsinit.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsinit.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: nsinit - namespace initialization - * $Revision: 33 $ + * $Revision: 47 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsinit") + ACPI_MODULE_NAME ("nsinit") /******************************************************************************* @@ -54,20 +54,16 @@ acpi_init_walk_info info; - FUNCTION_TRACE ("Ns_initialize_objects"); + ACPI_FUNCTION_TRACE ("Ns_initialize_objects"); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Completing Region and Field initialization:")); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Completing Region/Field/Buffer/Package initialization:")); + /* Set all init info to zero */ - info.field_count = 0; - info.field_init = 0; - info.op_region_count = 0; - info.op_region_init = 0; - info.object_count = 0; - + ACPI_MEMSET (&info, 0, sizeof (acpi_init_walk_info)); /* Walk entire namespace from the supplied root */ @@ -75,17 +71,20 @@ ACPI_UINT32_MAX, acpi_ns_init_one_object, &info, NULL); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Walk_namespace failed! %x\n", status)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Walk_namespace failed! %s\n", + acpi_format_exception (status))); } ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - "\n%d/%d Regions, %d/%d Fields initialized (%d nodes total)\n", - info.op_region_init, info.op_region_count, info.field_init, - info.field_count, info.object_count)); + "\n_initialized %hd/%hd Regions %hd/%hd Fields %hd/%hd Buffers %hd/%hd Packages (%hd nodes)\n", + info.op_region_init, info.op_region_count, + info.field_init, info.field_count, + info.buffer_init, info.buffer_count, + info.package_init, info.package_count, info.object_count)); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "%d Control Methods found\n", info.method_count)); + "%hd Control Methods found\n", info.method_count)); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "%d Op Regions found\n", info.op_region_count)); + "%hd Op Regions found\n", info.op_region_count)); return_ACPI_STATUS (AE_OK); } @@ -115,26 +114,29 @@ acpi_device_walk_info info; - FUNCTION_TRACE ("Ns_initialize_devices"); + ACPI_FUNCTION_TRACE ("Ns_initialize_devices"); + + /* Init counters */ info.device_count = 0; info.num_STA = 0; info.num_INI = 0; + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Executing all Device _STA and_INI methods:")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Executing device _INI methods:")); + /* Walk namespace for all objects of type Device */ status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, acpi_ns_init_one_device, &info, NULL); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Walk_namespace failed! %x\n", status)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Walk_namespace failed! %s\n", + acpi_format_exception (status))); } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - "\n%d Devices found: %d _STA, %d _INI\n", + "\n%hd Devices found containing: %hd _STA, %hd _INI methods\n", info.device_count, info.num_STA, info.num_INI)); return_ACPI_STATUS (status); @@ -168,32 +170,57 @@ void *context, void **return_value) { - acpi_object_type8 type; + acpi_object_type type; acpi_status status; acpi_init_walk_info *info = (acpi_init_walk_info *) context; acpi_namespace_node *node = (acpi_namespace_node *) obj_handle; acpi_operand_object *obj_desc; - PROC_NAME ("Ns_init_one_object"); + ACPI_FUNCTION_NAME ("Ns_init_one_object"); info->object_count++; - /* And even then, we are only interested in a few object types */ type = acpi_ns_get_type (obj_handle); - obj_desc = node->object; + obj_desc = acpi_ns_get_attached_object (node); if (!obj_desc) { return (AE_OK); } - if ((type != ACPI_TYPE_REGION) && - (type != ACPI_TYPE_BUFFER_FIELD)) { + /* Increment counters for object types we are looking for */ + + switch (type) { + case ACPI_TYPE_REGION: + info->op_region_count++; + break; + + case ACPI_TYPE_BUFFER_FIELD: + info->field_count++; + break; + + case ACPI_TYPE_BUFFER: + info->buffer_count++; + break; + + case ACPI_TYPE_PACKAGE: + info->package_count++; + break; + + default: + + /* No init required, just exit now */ return (AE_OK); } + /* + * If the object is already initialized, nothing else to do + */ + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return (AE_OK); + } /* * Must lock the interpreter before executing AML code @@ -203,61 +230,57 @@ return (status); } + /* + * Each of these types can contain executable AML code within + * the declaration. + */ switch (type) { - case ACPI_TYPE_REGION: - info->op_region_count++; - if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { - break; - } - info->op_region_init++; status = acpi_ds_get_region_arguments (obj_desc); - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "%s while getting region arguments [%4.4s]\n", - acpi_format_exception (status), (char*)&node->name)); - } - - if (!(acpi_dbg_level & ACPI_LV_INIT)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, ".")); - } - break; case ACPI_TYPE_BUFFER_FIELD: - info->field_count++; - if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { - break; - } - info->field_init++; status = acpi_ds_get_buffer_field_arguments (obj_desc); - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "%s while getting buffer field arguments [%4.4s]\n", - acpi_format_exception (status), (char*)&node->name)); - } - if (!(acpi_dbg_level & ACPI_LV_INIT)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, ".")); - } + break; + case ACPI_TYPE_BUFFER: + + info->buffer_init++; + status = acpi_ds_get_buffer_arguments (obj_desc); + break; + + + case ACPI_TYPE_PACKAGE: + + info->package_init++; + status = acpi_ds_get_package_arguments (obj_desc); break; default: + /* No other types can get here */ break; } + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not execute arguments for [%4.4s] (%s), %s\n", + node->name.ascii, acpi_ut_get_type_name (type), acpi_format_exception (status))); + } + + if (!(acpi_dbg_level & ACPI_LV_INIT)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, ".")); + } /* * We ignore errors from above, and always return OK, since - * we don't want to abort the walk on a single error. + * we don't want to abort the walk on any single error. */ acpi_ex_exit_interpreter (); return (AE_OK); @@ -291,7 +314,7 @@ acpi_device_walk_info *info = (acpi_device_walk_info *) context; - FUNCTION_TRACE ("Ns_init_one_device"); + ACPI_FUNCTION_TRACE ("Ns_init_one_device"); if (!(acpi_dbg_level & ACPI_LV_INIT)) { @@ -300,20 +323,26 @@ info->device_count++; - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } node = acpi_ns_map_handle_to_node (obj_handle); if (!node) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return (AE_BAD_PARAMETER); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (AE_BAD_PARAMETER); } - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* * Run _STA to determine if we can run _INI on the device. */ - DEBUG_EXEC (acpi_ut_display_init_pathname (node, "_STA [Method]")); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (node, "_STA [Method]")); status = acpi_ut_execute_STA (node, &flags); if (ACPI_FAILURE (status)) { /* Ignore error and move on to next device */ @@ -329,36 +358,41 @@ return_ACPI_STATUS(AE_CTRL_DEPTH); } - /* * The device is present. Run _INI. */ - DEBUG_EXEC (acpi_ut_display_init_pathname (obj_handle, "_INI [Method]")); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (obj_handle, "_INI [Method]")); status = acpi_ns_evaluate_relative (obj_handle, "_INI", NULL, NULL); - if (AE_NOT_FOUND == status) { - /* No _INI means device requires no initialization */ + if (ACPI_FAILURE (status)) { + /* No _INI (AE_NOT_FOUND) means device requires no initialization */ - status = AE_OK; - } + if (status != AE_NOT_FOUND) { + /* Ignore error and move on to next device */ - else if (ACPI_FAILURE (status)) { - /* Ignore error and move on to next device */ + #ifdef ACPI_DEBUG + NATIVE_CHAR *scope_name = acpi_ns_get_external_pathname (obj_handle); -#ifdef ACPI_DEBUG - NATIVE_CHAR *scope_name = acpi_ns_get_table_pathname (obj_handle); + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n", + scope_name, acpi_format_exception (status))); - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n", - scope_name, acpi_format_exception (status))); + ACPI_MEM_FREE (scope_name); + #endif + } - ACPI_MEM_FREE (scope_name); -#endif + status = AE_OK; } - else { /* Count of successful INIs */ info->num_INI++; } - return_ACPI_STATUS (AE_OK); + if (acpi_gbl_init_handler) { + /* External initialization handler is present, call it */ + + status = acpi_gbl_init_handler (obj_handle, ACPI_INIT_DEVICE_INI); + } + + + return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/namespace/nsload.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsload.c --- linux-2.4.19/drivers/acpi/namespace/nsload.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsload.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: nsload - namespace loading/expanding/contracting procedures - * $Revision: 47 $ + * $Revision: 55 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,23 +25,21 @@ #include "acpi.h" -#include "acinterp.h" #include "acnamesp.h" #include "amlcode.h" #include "acparser.h" #include "acdispat.h" -#include "acdebug.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsload") + ACPI_MODULE_NAME ("nsload") /******************************************************************************* * * FUNCTION: Acpi_load_namespace * - * PARAMETERS: Display_aml_during_load + * PARAMETERS: None * * RETURN: Status * @@ -57,7 +55,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_load_name_space"); + ACPI_FUNCTION_TRACE ("Acpi_load_name_space"); /* There must be at least a DSDT installed */ @@ -67,7 +65,6 @@ return_ACPI_STATUS (AE_NO_ACPI_TABLES); } - /* * Load the namespace. The DSDT is required, * but the SSDT and PSDT tables are optional. @@ -79,15 +76,13 @@ /* Ignore exceptions from these */ - acpi_ns_load_table_by_type (ACPI_TABLE_SSDT); - acpi_ns_load_table_by_type (ACPI_TABLE_PSDT); - + (void) acpi_ns_load_table_by_type (ACPI_TABLE_SSDT); + (void) acpi_ns_load_table_by_type (ACPI_TABLE_PSDT); ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "ACPI Namespace successfully loaded at root %p\n", acpi_gbl_root_node)); - return_ACPI_STATUS (status); } @@ -96,11 +91,12 @@ * * FUNCTION: Acpi_ns_one_parse_pass * - * PARAMETERS: + * PARAMETERS: Pass_number - 1 or 2 + * Table_desc - The table to be parsed. * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Perform one complete parse of an ACPI/AML table. * ******************************************************************************/ @@ -114,7 +110,7 @@ acpi_walk_state *walk_state; - FUNCTION_TRACE ("Ns_one_complete_parse"); + ACPI_FUNCTION_TRACE ("Ns_one_complete_parse"); /* Create and init a Root Node */ @@ -124,8 +120,7 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - ((acpi_parse2_object *) parse_root)->name = ACPI_ROOT_NAME; - + parse_root->named.name = ACPI_ROOT_NAME; /* Create and initialize a new walk state */ @@ -174,7 +169,7 @@ acpi_status status; - FUNCTION_TRACE ("Ns_parse_table"); + ACPI_FUNCTION_TRACE ("Ns_parse_table"); /* @@ -192,7 +187,6 @@ return_ACPI_STATUS (status); } - /* * AML Parse, pass 2 * @@ -232,8 +226,18 @@ acpi_status status; - FUNCTION_TRACE ("Ns_load_table"); + ACPI_FUNCTION_TRACE ("Ns_load_table"); + + /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */ + + if (!(acpi_gbl_acpi_table_data[table_desc->type].flags & ACPI_TABLE_EXECUTABLE)) { + /* Just ignore this table */ + + return_ACPI_STATUS (AE_OK); + } + + /* Check validity of the AML start and length */ if (!table_desc->aml_start) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null AML pointer\n")); @@ -242,13 +246,11 @@ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AML block at %p\n", table_desc->aml_start)); - if (!table_desc->aml_length) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Zero-length AML block\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed @@ -260,9 +262,13 @@ */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Loading table into namespace ****\n")); - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + status = acpi_ns_parse_table (table_desc, node->child); - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -305,22 +311,23 @@ acpi_table_type table_type) { u32 i; - acpi_status status = AE_OK; + acpi_status status; acpi_table_desc *table_desc; - FUNCTION_TRACE ("Ns_load_table_by_type"); + ACPI_FUNCTION_TRACE ("Ns_load_table_by_type"); - acpi_ut_acquire_mutex (ACPI_MTX_TABLES); - + status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* * Table types supported are: * DSDT (one), SSDT/PSDT (multiple) */ switch (table_type) { - case ACPI_TABLE_DSDT: ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading DSDT\n")); @@ -408,11 +415,8 @@ unlock_and_exit: - - acpi_ut_release_mutex (ACPI_MTX_TABLES); - + (void) acpi_ut_release_mutex (ACPI_MTX_TABLES); return_ACPI_STATUS (status); - } @@ -427,8 +431,8 @@ * DESCRIPTION: Walks the namespace starting at the given handle and deletes * all objects, entries, and scopes in the entire subtree. * - * TBD: [Investigate] What if any part of this subtree is in use? - * (i.e. on one of the object stacks?) + * Namespace/Interpreter should be locked or the subsystem should + * be in shutdown before this routine is called. * ******************************************************************************/ @@ -444,7 +448,7 @@ u32 level; - FUNCTION_TRACE ("Ns_delete_subtree"); + ACPI_FUNCTION_TRACE ("Ns_delete_subtree"); parent_handle = start_handle; @@ -463,7 +467,6 @@ child_handle = next_child_handle; - /* Did we get a new object? */ if (ACPI_SUCCESS (status)) { @@ -480,7 +483,6 @@ child_handle = 0; } } - else { /* * No more children in this object, go back up to @@ -493,7 +495,10 @@ acpi_ns_delete_children (child_handle); child_handle = parent_handle; - acpi_get_parent (parent_handle, &parent_handle); + status = acpi_get_parent (parent_handle, &parent_handle); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } } @@ -526,7 +531,7 @@ acpi_status status; - FUNCTION_TRACE ("Ns_unload_name_space"); + ACPI_FUNCTION_TRACE ("Ns_unload_name_space"); /* Parameter validation */ @@ -538,7 +543,6 @@ if (!handle) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* This function does the real work */ diff -Nur linux-2.4.19/drivers/acpi/namespace/nsnames.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsnames.c --- linux-2.4.19/drivers/acpi/namespace/nsnames.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsnames.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nsnames - Name manipulation and search - * $Revision: 64 $ + * $Revision: 77 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,96 +26,127 @@ #include "acpi.h" #include "amlcode.h" -#include "acinterp.h" #include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsnames") + ACPI_MODULE_NAME ("nsnames") /******************************************************************************* * - * FUNCTION: Acpi_ns_get_table_pathname + * FUNCTION: Acpi_ns_build_external_path * - * PARAMETERS: Node - Scope whose name is needed + * PARAMETERS: Node - NS node whose pathname is needed + * Size - Size of the pathname + * *Name_buffer - Where to return the pathname * - * RETURN: Pointer to storage containing the fully qualified name of - * the scope, in Label format (all segments strung together - * with no separators) + * RETURN: Places the pathname into the Name_buffer, in external format + * (name segments separated by path separators) * - * DESCRIPTION: Used for debug printing in Acpi_ns_search_table(). + * DESCRIPTION: Generate a full pathaname * ******************************************************************************/ -NATIVE_CHAR * -acpi_ns_get_table_pathname ( - acpi_namespace_node *node) +void +acpi_ns_build_external_path ( + acpi_namespace_node *node, + ACPI_SIZE size, + NATIVE_CHAR *name_buffer) { - NATIVE_CHAR *name_buffer; - u32 size; - acpi_name name; - acpi_namespace_node *child_node; + ACPI_SIZE index; acpi_namespace_node *parent_node; - FUNCTION_TRACE_PTR ("Ns_get_table_pathname", node); + ACPI_FUNCTION_NAME ("Ns_build_external_path"); - if (!acpi_gbl_root_node || !node) { - /* - * If the name space has not been initialized, - * this function should not have been called. - */ - return_PTR (NULL); + /* Special case for root */ + + index = size - 1; + if (index < ACPI_NAME_SIZE) { + name_buffer[0] = AML_ROOT_PREFIX; + name_buffer[1] = 0; + return; } - child_node = node->child; + /* Store terminator byte, then build name backwards */ + + parent_node = node; + name_buffer[index] = 0; + while ((index > ACPI_NAME_SIZE) && (parent_node != acpi_gbl_root_node)) { + index -= ACPI_NAME_SIZE; - /* Calculate required buffer size based on depth below root */ + /* Put the name into the buffer */ + + ACPI_MOVE_UNALIGNED32_TO_32 ((name_buffer + index), &parent_node->name); + parent_node = acpi_ns_get_parent_node (parent_node); - size = 1; - parent_node = child_node; - while (parent_node) { - parent_node = acpi_ns_get_parent_object (parent_node); - if (parent_node) { - size += ACPI_NAME_SIZE; - } + /* Prefix name with the path separator */ + + index--; + name_buffer[index] = PATH_SEPARATOR; } + /* Overwrite final separator with the root prefix character */ - /* Allocate a buffer to be returned to caller */ + name_buffer[index] = AML_ROOT_PREFIX; - name_buffer = ACPI_MEM_CALLOCATE (size + 1); - if (!name_buffer) { - REPORT_ERROR (("Ns_get_table_pathname: allocation failure\n")); - return_PTR (NULL); + if (index != 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not construct pathname; index=%X, size=%X, Path=%s\n", + (u32) index, (u32) size, &name_buffer[size])); } + return; +} - /* Store terminator byte, then build name backwards */ - name_buffer[size] = '\0'; - while ((size > ACPI_NAME_SIZE) && - acpi_ns_get_parent_object (child_node)) { - size -= ACPI_NAME_SIZE; - name = acpi_ns_find_parent_name (child_node); +#ifdef ACPI_DEBUG +/******************************************************************************* + * + * FUNCTION: Acpi_ns_get_external_pathname + * + * PARAMETERS: Node - NS node whose pathname is needed + * + * RETURN: Pointer to storage containing the fully qualified name of + * the node, In external format (name segments separated by path + * separators.) + * + * DESCRIPTION: Used for debug printing in Acpi_ns_search_table(). + * + ******************************************************************************/ - /* Put the name into the buffer */ +NATIVE_CHAR * +acpi_ns_get_external_pathname ( + acpi_namespace_node *node) +{ + NATIVE_CHAR *name_buffer; + ACPI_SIZE size; + + + ACPI_FUNCTION_TRACE_PTR ("Ns_get_external_pathname", node); - MOVE_UNALIGNED32_TO_32 ((name_buffer + size), &name); - child_node = acpi_ns_get_parent_object (child_node); - } - name_buffer[--size] = AML_ROOT_PREFIX; + /* Calculate required buffer size based on depth below root */ + + size = acpi_ns_get_pathname_length (node); + + /* Allocate a buffer to be returned to caller */ - if (size != 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad pointer returned; size=%X\n", size)); + name_buffer = ACPI_MEM_CALLOCATE (size); + if (!name_buffer) { + ACPI_REPORT_ERROR (("Ns_get_table_pathname: allocation failure\n")); + return_PTR (NULL); } + /* Build the path in the allocated buffer */ + + acpi_ns_build_external_path (node, size, name_buffer); return_PTR (name_buffer); } +#endif /******************************************************************************* @@ -130,31 +161,27 @@ * ******************************************************************************/ -u32 +ACPI_SIZE acpi_ns_get_pathname_length ( acpi_namespace_node *node) { - u32 size; + ACPI_SIZE size; acpi_namespace_node *next_node; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* * Compute length of pathname as 5 * number of name segments. * Go back up the parent tree to the root */ - for (size = 0, next_node = node; - acpi_ns_get_parent_object (next_node); - next_node = acpi_ns_get_parent_object (next_node)) { - size += PATH_SEGMENT_LENGTH; - } - - /* Special case for size still 0 - no parent for "special" nodes */ + size = 0; + next_node = node; - if (!size) { - size = PATH_SEGMENT_LENGTH; + while (next_node != acpi_gbl_root_node) { + size += PATH_SEGMENT_LENGTH; + next_node = acpi_ns_get_parent_node (next_node); } return (size + 1); @@ -167,96 +194,49 @@ * * PARAMETERS: Target_handle - Handle of named object whose name is * to be found - * Buf_size - Size of the buffer provided - * User_buffer - Where the pathname is returned + * Buffer - Where the pathname is returned * * RETURN: Status, Buffer is filled with pathname if status is AE_OK * * DESCRIPTION: Build and return a full namespace pathname * - * MUTEX: Locks Namespace - * ******************************************************************************/ acpi_status acpi_ns_handle_to_pathname ( acpi_handle target_handle, - u32 *buf_size, - NATIVE_CHAR *user_buffer) + acpi_buffer *buffer) { - acpi_status status = AE_OK; + acpi_status status; acpi_namespace_node *node; - u32 path_length; - u32 user_buf_size; - acpi_name name; - u32 size; + ACPI_SIZE required_size; - FUNCTION_TRACE_PTR ("Ns_handle_to_pathname", target_handle); + ACPI_FUNCTION_TRACE_PTR ("Ns_handle_to_pathname", target_handle); - if (!acpi_gbl_root_node) { - /* - * If the name space has not been initialized, - * this function should not have been called. - */ - return_ACPI_STATUS (AE_NO_NAMESPACE); - } - node = acpi_ns_map_handle_to_node (target_handle); if (!node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } + /* Determine size required for the caller buffer */ - /* Set return length to the required path length */ - - path_length = acpi_ns_get_pathname_length (node); - size = path_length - 1; - - user_buf_size = *buf_size; - *buf_size = path_length; + required_size = acpi_ns_get_pathname_length (node); - /* Check if the user buffer is sufficiently large */ + /* Validate/Allocate/Clear caller buffer */ - if (path_length > user_buf_size) { - status = AE_BUFFER_OVERFLOW; - goto exit; + status = acpi_ut_initialize_buffer (buffer, required_size); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - /* Store null terminator */ - - user_buffer[size] = 0; - size -= ACPI_NAME_SIZE; - - /* Put the original ACPI name at the end of the path */ - - MOVE_UNALIGNED32_TO_32 ((user_buffer + size), - &node->name); - - user_buffer[--size] = PATH_SEPARATOR; - - /* Build name backwards, putting "." between segments */ - - while ((size > ACPI_NAME_SIZE) && node) { - size -= ACPI_NAME_SIZE; - name = acpi_ns_find_parent_name (node); - MOVE_UNALIGNED32_TO_32 ((user_buffer + size), &name); - - user_buffer[--size] = PATH_SEPARATOR; - node = acpi_ns_get_parent_object (node); - } - - /* - * Overlay the "." preceding the first segment with - * the root name "\" - */ - user_buffer[size] = '\\'; + /* Build the path in the caller buffer */ - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Len=%X, %s \n", path_length, user_buffer)); + acpi_ns_build_external_path (node, required_size, buffer->pointer); -exit: - return_ACPI_STATUS (status); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%X] \n", (char *) buffer->pointer, (u32) required_size)); + return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/namespace/nsobject.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsobject.c --- linux-2.4.19/drivers/acpi/namespace/nsobject.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsobject.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: nsobject - Utilities for objects attached to namespace * table entries - * $Revision: 67 $ + * $Revision: 82 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,14 +26,11 @@ #include "acpi.h" -#include "amlcode.h" #include "acnamesp.h" -#include "acinterp.h" -#include "actables.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsobject") + ACPI_MODULE_NAME ("nsobject") /******************************************************************************* @@ -48,6 +45,8 @@ * DESCRIPTION: Record the given object as the value associated with the * name whose acpi_handle is passed. If Object is NULL * and Type is ACPI_TYPE_ANY, set the name as having no value. + * Note: Future may require that the Node->Flags field be passed + * as a parameter. * * MUTEX: Assumes namespace is locked * @@ -57,45 +56,37 @@ acpi_ns_attach_object ( acpi_namespace_node *node, acpi_operand_object *object, - acpi_object_type8 type) + acpi_object_type type) { acpi_operand_object *obj_desc; - acpi_operand_object *previous_obj_desc; - acpi_object_type8 obj_type = ACPI_TYPE_ANY; - u8 flags; + acpi_operand_object *last_obj_desc; + acpi_object_type object_type = ACPI_TYPE_ANY; - FUNCTION_TRACE ("Ns_attach_object"); + ACPI_FUNCTION_TRACE ("Ns_attach_object"); /* * Parameter validation */ - if (!acpi_gbl_root_node) { - /* Name space not initialized */ - - REPORT_ERROR (("Ns_attach_object: Namespace not initialized\n")); - return_ACPI_STATUS (AE_NO_NAMESPACE); - } - if (!node) { /* Invalid handle */ - REPORT_ERROR (("Ns_attach_object: Null Named_obj handle\n")); + ACPI_REPORT_ERROR (("Ns_attach_object: Null Named_obj handle\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } if (!object && (ACPI_TYPE_ANY != type)) { /* Null object */ - REPORT_ERROR (("Ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n")); + ACPI_REPORT_ERROR (("Ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } - if (!VALID_DESCRIPTOR_TYPE (node, ACPI_DESC_TYPE_NAMED)) { + if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { /* Not a name handle */ - REPORT_ERROR (("Ns_attach_object: Invalid handle\n")); + ACPI_REPORT_ERROR (("Ns_attach_object: Invalid handle\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -108,42 +99,27 @@ return_ACPI_STATUS (AE_OK); } - - /* Get the current flags field of the Node */ - - flags = node->flags; - flags &= ~ANOBJ_AML_ATTACHMENT; - - /* If null object, we will just install it */ if (!object) { - obj_desc = NULL; - obj_type = ACPI_TYPE_ANY; + obj_desc = NULL; + object_type = ACPI_TYPE_ANY; } /* * If the source object is a namespace Node with an attached object, * we will use that (attached) object */ - else if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED) && + else if ((ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) && ((acpi_namespace_node *) object)->object) { /* * Value passed is a name handle and that name has a * non-null value. Use that name's value and type. */ - obj_desc = ((acpi_namespace_node *) object)->object; - obj_type = ((acpi_namespace_node *) object)->type; - - /* - * Copy appropriate flags - */ - if (((acpi_namespace_node *) object)->flags & ANOBJ_AML_ATTACHMENT) { - flags |= ANOBJ_AML_ATTACHMENT; - } + obj_desc = ((acpi_namespace_node *) object)->object; + object_type = ((acpi_namespace_node *) object)->type; } - /* * Otherwise, we will use the parameter object, but we must type * it first @@ -154,68 +130,46 @@ /* If a valid type (non-ANY) was given, just use it */ if (ACPI_TYPE_ANY != type) { - obj_type = type; + object_type = type; } - else { - /* - * Cannot figure out the type -- set to Def_any which - * will print as an error in the name table dump - */ - if (acpi_dbg_level > 0) { - DUMP_PATHNAME (node, - "Ns_attach_object confused: setting bogus type for ", - ACPI_LV_INFO, _COMPONENT); - - if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED)) { - DUMP_PATHNAME (object, "name ", ACPI_LV_INFO, _COMPONENT); - } - - else { - DUMP_PATHNAME (object, "object ", ACPI_LV_INFO, _COMPONENT); - DUMP_STACK_ENTRY (object); - } - } - - obj_type = INTERNAL_TYPE_DEF_ANY; + object_type = INTERNAL_TYPE_DEF_ANY; } } - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Installing %p into Node %p [%4.4s]\n", - obj_desc, node, (char*)&node->name)); - - - /* - * Must increment the new value's reference count - * (if it is an internal object) - */ - acpi_ut_add_reference (obj_desc); - - /* Save the existing object (if any) for deletion later */ + obj_desc, node, node->name.ascii)); - previous_obj_desc = node->object; - - /* Install the object and set the type, flags */ - - node->object = obj_desc; - node->type = (u8) obj_type; - node->flags |= flags; + /* Detach an existing attached object if present */ + if (node->object) { + acpi_ns_detach_object (node); + } - /* - * Delete an existing attached object. - */ - if (previous_obj_desc) { - /* One for the attach to the Node */ + if (obj_desc) { + /* + * Must increment the new value's reference count + * (if it is an internal object) + */ + acpi_ut_add_reference (obj_desc); - acpi_ut_remove_reference (previous_obj_desc); + /* + * Handle objects with multiple descriptors - walk + * to the end of the descriptor list + */ + last_obj_desc = obj_desc; + while (last_obj_desc->common.next_object) { + last_obj_desc = last_obj_desc->common.next_object; + } - /* Now delete */ + /* Install the object at the front of the object list */ - acpi_ut_remove_reference (previous_obj_desc); + last_obj_desc->common.next_object = node->object; } + node->type = (u8) object_type; + node->object = obj_desc; + return_ACPI_STATUS (AE_OK); } @@ -241,20 +195,32 @@ acpi_operand_object *obj_desc; - FUNCTION_TRACE ("Ns_detach_object"); + ACPI_FUNCTION_TRACE ("Ns_detach_object"); obj_desc = node->object; - if (!obj_desc) { + if (!obj_desc || + (obj_desc->common.type == INTERNAL_TYPE_DATA)) { return_VOID; } /* Clear the entry in all cases */ node->object = NULL; + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) { + node->object = obj_desc->common.next_object; + if (node->object && + (node->object->common.type != INTERNAL_TYPE_DATA)) { + node->object = node->object->common.next_object; + } + } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object=%p Value=%p Name %4.4s\n", - node, obj_desc, (char*)&node->name)); + /* Reset the node type to untyped */ + + node->type = ACPI_TYPE_ANY; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", + node, node->name.ascii, obj_desc)); /* Remove one reference on the object (and all subobjects) */ @@ -274,21 +240,197 @@ * ******************************************************************************/ -void * +acpi_operand_object * acpi_ns_get_attached_object ( acpi_namespace_node *node) { - FUNCTION_TRACE_PTR ("Ns_get_attached_object", node); + ACPI_FUNCTION_TRACE_PTR ("Ns_get_attached_object", node); if (!node) { - /* handle invalid */ - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Null Node ptr\n")); return_PTR (NULL); } + if (!node->object || + ((ACPI_GET_DESCRIPTOR_TYPE (node->object) != ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_DESCRIPTOR_TYPE (node->object) != ACPI_DESC_TYPE_NAMED)) || + (node->object->common.type == INTERNAL_TYPE_DATA)) { + return_PTR (NULL); + } + return_PTR (node->object); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_get_secondary_object + * + * PARAMETERS: Node - Parent Node to be examined + * + * RETURN: Current value of the object field from the Node whose + * handle is passed + * + ******************************************************************************/ + +acpi_operand_object * +acpi_ns_get_secondary_object ( + acpi_operand_object *obj_desc) +{ + ACPI_FUNCTION_TRACE_PTR ("Ns_get_secondary_object", obj_desc); + + + if ((!obj_desc) || + (obj_desc->common.type == INTERNAL_TYPE_DATA) || + (!obj_desc->common.next_object) || + (obj_desc->common.next_object->common.type == INTERNAL_TYPE_DATA)) { + return_PTR (NULL); + } + + return_PTR (obj_desc->common.next_object); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_attach_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_ns_attach_data ( + acpi_namespace_node *node, + ACPI_OBJECT_HANDLER handler, + void *data) +{ + acpi_operand_object *prev_obj_desc; + acpi_operand_object *obj_desc; + acpi_operand_object *data_desc; + + + /* */ + prev_obj_desc = NULL; + obj_desc = node->object; + while (obj_desc) { + if ((obj_desc->common.type == INTERNAL_TYPE_DATA) && + (obj_desc->data.handler == handler)) { + return (AE_ALREADY_EXISTS); + } + + prev_obj_desc = obj_desc; + obj_desc = obj_desc->common.next_object; + } + + + /* Create an internal object for the data */ + + data_desc = acpi_ut_create_internal_object (INTERNAL_TYPE_DATA); + if (!data_desc) { + return (AE_NO_MEMORY); + } + + data_desc->data.handler = handler; + data_desc->data.pointer = data; + + + /* Install the data object */ + + if (prev_obj_desc) { + prev_obj_desc->common.next_object = data_desc; + } + else { + node->object = data_desc; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_detach_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_ns_detach_data ( + acpi_namespace_node *node, + ACPI_OBJECT_HANDLER handler) +{ + acpi_operand_object *obj_desc; + acpi_operand_object *prev_obj_desc; + + + prev_obj_desc = NULL; + obj_desc = node->object; + while (obj_desc) { + if ((obj_desc->common.type == INTERNAL_TYPE_DATA) && + (obj_desc->data.handler == handler)) { + if (prev_obj_desc) { + prev_obj_desc->common.next_object = obj_desc->common.next_object; + } + else { + node->object = obj_desc->common.next_object; + } + + acpi_ut_remove_reference (obj_desc); + return (AE_OK); + } + + prev_obj_desc = obj_desc; + obj_desc = obj_desc->common.next_object; + } + + return (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_get_attached_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_ns_get_attached_data ( + acpi_namespace_node *node, + ACPI_OBJECT_HANDLER handler, + void **data) +{ + acpi_operand_object *obj_desc; + + + obj_desc = node->object; + while (obj_desc) { + if ((obj_desc->common.type == INTERNAL_TYPE_DATA) && + (obj_desc->data.handler == handler)) { + *data = obj_desc->data.pointer; + return (AE_OK); + } + + obj_desc = obj_desc->common.next_object; + } + + return (AE_NOT_FOUND); } diff -Nur linux-2.4.19/drivers/acpi/namespace/nssearch.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nssearch.c --- linux-2.4.19/drivers/acpi/namespace/nssearch.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nssearch.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: nssearch - Namespace search - * $Revision: 75 $ + * $Revision: 85 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,11 @@ #include "acpi.h" -#include "amlcode.h" -#include "acinterp.h" #include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nssearch") + ACPI_MODULE_NAME ("nssearch") /******************************************************************************* @@ -64,30 +62,29 @@ acpi_ns_search_node ( u32 target_name, acpi_namespace_node *node, - acpi_object_type8 type, + acpi_object_type type, acpi_namespace_node **return_node) { acpi_namespace_node *next_node; - FUNCTION_TRACE ("Ns_search_node"); + ACPI_FUNCTION_TRACE ("Ns_search_node"); #ifdef ACPI_DEBUG if (ACPI_LV_NAMES & acpi_dbg_level) { NATIVE_CHAR *scope_name; - scope_name = acpi_ns_get_table_pathname (node); + scope_name = acpi_ns_get_external_pathname (node); if (scope_name) { - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching %s [%p] For %4.4s (type %X)\n", - scope_name, node, (char*)&target_name, type)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching %s [%p] For %4.4s (type %s)\n", + scope_name, node, (char *) &target_name, acpi_ut_get_type_name (type))); ACPI_MEM_FREE (scope_name); } } #endif - /* * Search for name in this table, which is to say that we must search * for the name among the children of this object @@ -96,7 +93,7 @@ while (next_node) { /* Check for match against the name */ - if (next_node->name == target_name) { + if (next_node->name.integer == target_name) { /* * Found matching entry. Capture the type if appropriate, before * returning the entry. @@ -123,14 +120,13 @@ } ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, - "Name %4.4s (actual type %X) found at %p\n", - (char*)&target_name, next_node->type, next_node)); + "Name %4.4s Type [%s] found at %p\n", + (char *) &target_name, acpi_ut_get_type_name (next_node->type), next_node)); *return_node = next_node; return_ACPI_STATUS (AE_OK); } - /* * The last entry in the list points back to the parent, * so a flag is used to indicate the end-of-list @@ -146,11 +142,10 @@ next_node = next_node->peer; } - /* Searched entire table, not found */ - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Name %4.4s (type %X) not found at %p\n", - (char*)&target_name, type, next_node)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Name %4.4s Type [%s] not found at %p\n", + (char *) &target_name, acpi_ut_get_type_name (type), next_node)); return_ACPI_STATUS (AE_NOT_FOUND); } @@ -185,17 +180,17 @@ acpi_ns_search_parent_tree ( u32 target_name, acpi_namespace_node *node, - acpi_object_type8 type, + acpi_object_type type, acpi_namespace_node **return_node) { acpi_status status; acpi_namespace_node *parent_node; - FUNCTION_TRACE ("Ns_search_parent_tree"); + ACPI_FUNCTION_TRACE ("Ns_search_parent_tree"); - parent_node = acpi_ns_get_parent_object (node); + parent_node = acpi_ns_get_parent_node (node); /* * If there is no parent (at the root) or type is "local", we won't be @@ -205,33 +200,33 @@ (!parent_node)) { if (!parent_node) { ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] has no parent\n", - (char*)&target_name)); + (char *) &target_name)); } if (acpi_ns_local (type)) { - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] type %X is local(no search)\n", - (char*)&target_name, type)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] type [%s] must be local to this scope (no parent search)\n", + (char *) &target_name, acpi_ut_get_type_name (type))); } return_ACPI_STATUS (AE_NOT_FOUND); } - /* Search the parent tree */ - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching parent for %4.4s\n", (char*)&target_name)); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Searching parent for %4.4s\n", (char *) &target_name)); /* * Search parents until found the target or we have backed up to * the root */ while (parent_node) { - /* Search parent scope */ - /* TBD: [Investigate] Why ACPI_TYPE_ANY? */ - + /* + * Search parent scope. Use TYPE_ANY because we don't care about the + * object type at this point, we only care about the existence of + * the actual name we are searching for. Typechecking comes later. + */ status = acpi_ns_search_node (target_name, parent_node, ACPI_TYPE_ANY, return_node); - if (ACPI_SUCCESS (status)) { return_ACPI_STATUS (status); } @@ -240,10 +235,9 @@ * Not found here, go up another level * (until we reach the root) */ - parent_node = acpi_ns_get_parent_object (parent_node); + parent_node = acpi_ns_get_parent_node (parent_node); } - /* Not found in parent tree */ return_ACPI_STATUS (AE_NOT_FOUND); @@ -280,8 +274,8 @@ u32 target_name, acpi_walk_state *walk_state, acpi_namespace_node *node, - operating_mode interpreter_mode, - acpi_object_type8 type, + acpi_interpreter_mode interpreter_mode, + acpi_object_type type, u32 flags, acpi_namespace_node **return_node) { @@ -289,7 +283,7 @@ acpi_namespace_node *new_node; - FUNCTION_TRACE ("Ns_search_and_enter"); + ACPI_FUNCTION_TRACE ("Ns_search_and_enter"); /* Parameter validation */ @@ -298,25 +292,23 @@ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null param- Table %p Name %X Return %p\n", node, target_name, return_node)); - REPORT_ERROR (("Ns_search_and_enter: bad (null) parameter\n")); + ACPI_REPORT_ERROR (("Ns_search_and_enter: bad (null) parameter\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Name must consist of printable characters */ if (!acpi_ut_valid_acpi_name (target_name)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "*** Bad character in name: %08x *** \n", target_name)); - REPORT_ERROR (("Ns_search_and_enter: Bad character in ACPI Name\n")); + ACPI_REPORT_ERROR (("Ns_search_and_enter: Bad character in ACPI Name\n")); return_ACPI_STATUS (AE_BAD_CHARACTER); } - /* Try to find the name in the table specified by the caller */ - *return_node = ENTRY_NOT_FOUND; + *return_node = ACPI_ENTRY_NOT_FOUND; status = acpi_ns_search_node (target_name, node, type, return_node); if (status != AE_NOT_FOUND) { /* @@ -324,8 +316,8 @@ * return the error */ if ((status == AE_OK) && - (flags & NS_ERROR_IF_FOUND)) { - status = AE_EXIST; + (flags & ACPI_NS_ERROR_IF_FOUND)) { + status = AE_ALREADY_EXISTS; } /* @@ -335,9 +327,8 @@ return_ACPI_STATUS (status); } - /* - * Not found in the table. If we are NOT performing the + * The name was not found. If we are NOT performing the * first pass (name entry) of loading the namespace, search * the parent tree (all the way to the root if necessary.) * We don't want to perform the parent search when the @@ -345,8 +336,8 @@ * the search when namespace references are being resolved * (load pass 2) and during the execution phase. */ - if ((interpreter_mode != IMODE_LOAD_PASS1) && - (flags & NS_SEARCH_PARENT)) { + if ((interpreter_mode != ACPI_IMODE_LOAD_PASS1) && + (flags & ACPI_NS_SEARCH_PARENT)) { /* * Not found in table - search parent tree according * to ACPI specification @@ -358,17 +349,15 @@ } } - /* * In execute mode, just search, never add names. Exit now. */ - if (interpreter_mode == IMODE_EXECUTE) { + if (interpreter_mode == ACPI_IMODE_EXECUTE) { ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s Not found in %p [Not adding]\n", - (char*)&target_name, node)); + (char *) &target_name, node)); return_ACPI_STATUS (AE_NOT_FOUND); } - /* Create the new named object */ diff -Nur linux-2.4.19/drivers/acpi/namespace/nsutils.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsutils.c --- linux-2.4.19/drivers/acpi/namespace/nsutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsutils.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing * parents and siblings and Scope manipulation - * $Revision: 92 $ + * $Revision: 109 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,12 +27,11 @@ #include "acpi.h" #include "acnamesp.h" -#include "acinterp.h" #include "amlcode.h" #include "actables.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsutils") + ACPI_MODULE_NAME ("nsutils") /******************************************************************************* @@ -87,19 +86,19 @@ * ******************************************************************************/ -acpi_object_type8 +acpi_object_type acpi_ns_get_type ( acpi_namespace_node *node) { - FUNCTION_TRACE ("Ns_get_type"); + ACPI_FUNCTION_TRACE ("Ns_get_type"); if (!node) { - REPORT_WARNING (("Ns_get_type: Null Node ptr")); + ACPI_REPORT_WARNING (("Ns_get_type: Null Node ptr")); return_VALUE (ACPI_TYPE_ANY); } - return_VALUE (node->type); + return_VALUE ((acpi_object_type) node->type); } @@ -116,19 +115,19 @@ u32 acpi_ns_local ( - acpi_object_type8 type) + acpi_object_type type) { - FUNCTION_TRACE ("Ns_local"); + ACPI_FUNCTION_TRACE ("Ns_local"); if (!acpi_ut_valid_object_type (type)) { /* Type code out of range */ - REPORT_WARNING (("Ns_local: Invalid Object Type\n")); - return_VALUE (NSP_NORMAL); + ACPI_REPORT_WARNING (("Ns_local: Invalid Object Type\n")); + return_VALUE (ACPI_NS_NORMAL); } - return_VALUE ((u32) acpi_gbl_ns_properties[type] & NSP_LOCAL); + return_VALUE ((u32) acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL); } @@ -146,7 +145,7 @@ * ******************************************************************************/ -acpi_status +void acpi_ns_get_internal_name_length ( acpi_namestring_info *info) { @@ -154,7 +153,7 @@ u32 i; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); next_external_char = info->external_name; @@ -175,7 +174,6 @@ info->fully_qualified = TRUE; next_external_char++; } - else { /* * Handle Carat prefixes @@ -205,8 +203,6 @@ 4 + info->num_carats; info->next_external_char = next_external_char; - - return (AE_OK); } @@ -231,10 +227,10 @@ NATIVE_CHAR *internal_name = info->internal_name; NATIVE_CHAR *external_name = info->next_external_char; NATIVE_CHAR *result = NULL; - u32 i; + NATIVE_UINT_MIN32 i; - FUNCTION_TRACE ("Ns_build_internal_name"); + ACPI_FUNCTION_TRACE ("Ns_build_internal_name"); /* Setup the correct prefixes, counts, and pointers */ @@ -255,7 +251,6 @@ result = &internal_name[3]; } } - else { /* * Not fully qualified. @@ -268,15 +263,13 @@ } } - if (num_segments == 1) { + if (num_segments <= 1) { result = &internal_name[i]; } - else if (num_segments == 2) { internal_name[i] = AML_DUAL_NAME_PREFIX; result = &internal_name[i+1]; } - else { internal_name[i] = AML_MULTI_NAME_PREFIX_OP; internal_name[i+1] = (char) num_segments; @@ -284,7 +277,6 @@ } } - /* Build the name (minus path separators) */ for (; num_segments; num_segments--) { @@ -295,11 +287,10 @@ result[i] = '_'; } - else { /* Convert the character to uppercase and save it */ - result[i] = (char) TOUPPER (*external_name); + result[i] = (char) ACPI_TOUPPER ((int) *external_name); external_name++; } } @@ -317,18 +308,17 @@ result += ACPI_NAME_SIZE; } - /* Terminate the string */ *result = 0; if (info->fully_qualified) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "returning [%p] (abs) \"\\%s\"\n", - internal_name, &internal_name[0])); + internal_name, internal_name)); } else { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "returning [%p] (rel) \"%s\"\n", - internal_name, &internal_name[2])); + internal_name, internal_name)); } return_ACPI_STATUS (AE_OK); @@ -360,7 +350,7 @@ acpi_status status; - FUNCTION_TRACE ("Ns_internalize_name"); + ACPI_FUNCTION_TRACE ("Ns_internalize_name"); if ((!external_name) || @@ -369,7 +359,6 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Get the length of the new internal name */ info.external_name = external_name; @@ -418,24 +407,23 @@ u32 *converted_name_length, char **converted_name) { - u32 prefix_length = 0; - u32 names_index = 0; - u32 names_count = 0; - u32 i = 0; - u32 j = 0; + NATIVE_UINT_MIN32 prefix_length = 0; + NATIVE_UINT_MIN32 names_index = 0; + NATIVE_UINT_MIN32 num_segments = 0; + NATIVE_UINT_MIN32 i = 0; + NATIVE_UINT_MIN32 j = 0; + NATIVE_UINT_MIN32 required_length; - FUNCTION_TRACE ("Ns_externalize_name"); + ACPI_FUNCTION_TRACE ("Ns_externalize_name"); if (!internal_name_length || !internal_name || - !converted_name_length || !converted_name) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* * Check for a prefix (one '\' | one or more '^'). */ @@ -456,6 +444,9 @@ } break; + + default: + break; } /* @@ -464,36 +455,36 @@ */ if (prefix_length < internal_name_length) { switch (internal_name[prefix_length]) { + case AML_MULTI_NAME_PREFIX_OP: - /* 4-byte names */ + /* 4-byte names */ - case AML_MULTI_NAME_PREFIX_OP: names_index = prefix_length + 2; - names_count = (u32) internal_name[prefix_length + 1]; + num_segments = (u32) (u8) internal_name[prefix_length + 1]; break; + case AML_DUAL_NAME_PREFIX: - /* two 4-byte names */ + /* Two 4-byte names */ - case AML_DUAL_NAME_PREFIX: names_index = prefix_length + 1; - names_count = 2; + num_segments = 2; break; + case 0: - /* Null_name */ + /* Null_name */ - case 0: names_index = 0; - names_count = 0; + num_segments = 0; break; + default: - /* one 4-byte name */ + /* one 4-byte name */ - default: names_index = prefix_length; - names_count = 1; + num_segments = 1; break; } } @@ -503,23 +494,22 @@ * of the prefix, length of all object names, length of any required * punctuation ('.') between object names, plus the NULL terminator. */ - *converted_name_length = prefix_length + (4 * names_count) + - ((names_count > 0) ? (names_count - 1) : 0) + 1; + required_length = prefix_length + (4 * num_segments) + + ((num_segments > 0) ? (num_segments - 1) : 0) + 1; /* * Check to see if we're still in bounds. If not, there's a problem * with Internal_name (invalid format). */ - if (*converted_name_length > internal_name_length) { - REPORT_ERROR (("Ns_externalize_name: Invalid internal name\n")); + if (required_length > internal_name_length) { + ACPI_REPORT_ERROR (("Ns_externalize_name: Invalid internal name\n")); return_ACPI_STATUS (AE_BAD_PATHNAME); } /* * Build Converted_name... */ - - (*converted_name) = ACPI_MEM_CALLOCATE (*converted_name_length); + *converted_name = ACPI_MEM_CALLOCATE (required_length); if (!(*converted_name)) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -530,8 +520,8 @@ (*converted_name)[j++] = internal_name[i]; } - if (names_count > 0) { - for (i = 0; i < names_count; i++) { + if (num_segments > 0) { + for (i = 0; i < num_segments; i++) { if (i > 0) { (*converted_name)[j++] = '.'; } @@ -543,6 +533,10 @@ } } + if (converted_name_length) { + *converted_name_length = (u32) required_length; + } + return_ACPI_STATUS (AE_OK); } @@ -557,6 +551,9 @@ * * DESCRIPTION: Convert a namespace handle to a real Node * + * Note: Real integer handles allow for more verification + * and keep all pointers within this subsystem. + * ******************************************************************************/ acpi_namespace_node * @@ -564,13 +561,11 @@ acpi_handle handle) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* - * Simple implementation for now; - * TBD: [Future] Real integer handles allow for more verification - * and keep all pointers within this subsystem! + * Simple implementation. */ if (!handle) { return (NULL); @@ -580,10 +575,9 @@ return (acpi_gbl_root_node); } - /* We can at least attempt to verify the handle */ - if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) { + if (ACPI_GET_DESCRIPTOR_TYPE (handle) != ACPI_DESC_TYPE_NAMED) { return (NULL); } @@ -611,8 +605,6 @@ /* * Simple implementation for now; - * TBD: [Future] Real integer handles allow for more verification - * and keep all pointers within this subsystem! */ return ((acpi_handle) node); @@ -654,7 +646,7 @@ acpi_namespace_node *this_node; - FUNCTION_TRACE ("Ns_terminate"); + ACPI_FUNCTION_TRACE ("Ns_terminate"); this_node = acpi_gbl_root_node; @@ -702,25 +694,25 @@ u32 acpi_ns_opens_scope ( - acpi_object_type8 type) + acpi_object_type type) { - FUNCTION_TRACE_U32 ("Ns_opens_scope", type); + ACPI_FUNCTION_TRACE_U32 ("Ns_opens_scope", type); if (!acpi_ut_valid_object_type (type)) { /* type code out of range */ - REPORT_WARNING (("Ns_opens_scope: Invalid Object Type\n")); - return_VALUE (NSP_NORMAL); + ACPI_REPORT_WARNING (("Ns_opens_scope: Invalid Object Type %X\n", type)); + return_VALUE (ACPI_NS_NORMAL); } - return_VALUE (((u32) acpi_gbl_ns_properties[type]) & NSP_NEWSCOPE); + return_VALUE (((u32) acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE); } /******************************************************************************* * - * FUNCTION: Acpi_ns_get_node + * FUNCTION: Acpi_ns_get_node_by_path * * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The * \ (backslash) and ^ (carat) prefixes, and the @@ -729,6 +721,8 @@ * root of the name space. If Name is fully * qualified (first s8 is '\'), the passed value * of Scope will not be accessed. + * Flags - Used to indicate whether to perform upsearch or + * not. * Return_node - Where the Node is returned * * DESCRIPTION: Look up a name relative to a given scope and return the @@ -739,9 +733,10 @@ ******************************************************************************/ acpi_status -acpi_ns_get_node ( +acpi_ns_get_node_by_path ( NATIVE_CHAR *pathname, acpi_namespace_node *start_node, + u32 flags, acpi_namespace_node **return_node) { acpi_generic_state scope_info; @@ -749,20 +744,13 @@ NATIVE_CHAR *internal_path = NULL; - FUNCTION_TRACE_PTR ("Ns_get_node", pathname); + ACPI_FUNCTION_TRACE_PTR ("Ns_get_node_by_path", pathname); - /* Ensure that the namespace has been initialized */ - - if (!acpi_gbl_root_node) { - return_ACPI_STATUS (AE_NO_NAMESPACE); - } - if (!pathname) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Convert path to internal representation */ status = acpi_ns_internalize_name (pathname, &internal_path); @@ -770,8 +758,12 @@ return_ACPI_STATUS (status); } + /* Must lock namespace during lookup */ - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Setup lookup scope (search starting point) */ @@ -780,20 +772,17 @@ /* Lookup the name in the namespace */ status = acpi_ns_lookup (&scope_info, internal_path, - ACPI_TYPE_ANY, IMODE_EXECUTE, - NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + (flags | ACPI_NS_DONT_OPEN_SCOPE), NULL, return_node); - if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s, %s\n", internal_path, acpi_format_exception (status))); } - - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - /* Cleanup */ + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); ACPI_MEM_FREE (internal_path); return_ACPI_STATUS (status); } @@ -820,24 +809,25 @@ acpi_namespace_node *parent_node; - FUNCTION_TRACE ("Ns_find_parent_name"); + ACPI_FUNCTION_TRACE ("Ns_find_parent_name"); if (child_node) { /* Valid entry. Get the parent Node */ - parent_node = acpi_ns_get_parent_object (child_node); + parent_node = acpi_ns_get_parent_node (child_node); if (parent_node) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Parent of %p [%4.4s] is %p [%4.4s]\n", - child_node, (char*)&child_node->name, parent_node, (char*)&parent_node->name)); + child_node, child_node->name.ascii, + parent_node, parent_node->name.ascii)); - if (parent_node->name) { - return_VALUE (parent_node->name); + if (parent_node->name.integer) { + return_VALUE ((acpi_name) parent_node->name.integer); } } ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "unable to find parent of %p (%4.4s)\n", - child_node, (char*)&child_node->name)); + child_node, child_node->name.ascii)); } return_VALUE (ACPI_UNKNOWN_NAME); @@ -871,7 +861,7 @@ return (FALSE); } - if (node->name) { + if (node->name.integer) { return (TRUE); } @@ -883,7 +873,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_ns_get_parent_object + * FUNCTION: Acpi_ns_get_parent_node * * PARAMETERS: Node - Current table entry * @@ -895,12 +885,10 @@ acpi_namespace_node * -acpi_ns_get_parent_object ( +acpi_ns_get_parent_node ( acpi_namespace_node *node) { - - - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (!node) { diff -Nur linux-2.4.19/drivers/acpi/namespace/nswalk.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nswalk.c --- linux-2.4.19/drivers/acpi/namespace/nswalk.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nswalk.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: nswalk - Functions for walking the ACPI namespace - * $Revision: 26 $ + * $Revision: 33 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,12 +25,11 @@ #include "acpi.h" -#include "acinterp.h" #include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nswalk") + ACPI_MODULE_NAME ("nswalk") /******************************************************************************* @@ -54,14 +53,14 @@ acpi_namespace_node * acpi_ns_get_next_node ( - acpi_object_type8 type, + acpi_object_type type, acpi_namespace_node *parent_node, acpi_namespace_node *child_node) { acpi_namespace_node *next_node = NULL; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (!child_node) { @@ -138,7 +137,7 @@ acpi_status acpi_ns_walk_namespace ( - acpi_object_type8 type, + acpi_object_type type, acpi_handle start_node, u32 max_depth, u8 unlock_before_callback, @@ -149,11 +148,11 @@ acpi_status status; acpi_namespace_node *child_node; acpi_namespace_node *parent_node; - acpi_object_type8 child_type; + acpi_object_type child_type; u32 level; - FUNCTION_TRACE ("Ns_walk_namespace"); + ACPI_FUNCTION_TRACE ("Ns_walk_namespace"); /* Special case for the namespace Root Node */ @@ -194,14 +193,20 @@ * callback function */ if (unlock_before_callback) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } status = user_function (child_node, level, context, return_value); if (unlock_before_callback) { - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } switch (status) { @@ -216,14 +221,12 @@ /* Exit now, with OK status */ return_ACPI_STATUS (AE_OK); - break; default: /* All others are valid exceptions */ return_ACPI_STATUS (status); - break; } } @@ -247,7 +250,6 @@ } } } - else { /* * No more children of this node (Acpi_ns_get_next_node @@ -256,7 +258,7 @@ */ level--; child_node = parent_node; - parent_node = acpi_ns_get_parent_object (parent_node); + parent_node = acpi_ns_get_parent_node (parent_node); } } diff -Nur linux-2.4.19/drivers/acpi/namespace/nsxfname.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsxfname.c --- linux-2.4.19/drivers/acpi/namespace/nsxfname.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsxfname.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: nsxfname - Public interfaces to the ACPI subsystem * ACPI Namespace oriented interfaces - * $Revision: 82 $ + * $Revision: 91 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,16 +26,11 @@ #include "acpi.h" -#include "acinterp.h" #include "acnamesp.h" -#include "amlcode.h" -#include "acparser.h" -#include "acdispat.h" -#include "acevents.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsxfname") + ACPI_MODULE_NAME ("nsxfname") /**************************************************************************** @@ -67,7 +62,7 @@ acpi_namespace_node *prefix_node = NULL; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* Parameter Validation */ @@ -79,20 +74,26 @@ /* Convert a parent handle to a prefix node */ if (parent) { - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } prefix_node = acpi_ns_map_handle_to_node (parent); if (!prefix_node) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } } /* Special case for root, since we can't search for it */ - if (STRCMP (pathname, NS_ROOT_PATH) == 0) { + if (ACPI_STRCMP (pathname, ACPI_NS_ROOT_PATH) == 0) { *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_node); return (AE_OK); } @@ -100,7 +101,7 @@ /* * Find the Node and convert to a handle */ - status = acpi_ns_get_node (pathname, prefix_node, &node); + status = acpi_ns_get_node_by_path (pathname, prefix_node, ACPI_NS_NO_UPSEARCH, &node); *ret_handle = NULL; if (ACPI_SUCCESS (status)) { @@ -117,7 +118,7 @@ * * PARAMETERS: Handle - Handle to be converted to a pathname * Name_type - Full pathname or single segment - * Ret_path_ptr - Buffer for returned path + * Buffer - Buffer for returned path * * RETURN: Pointer to a string containing the fully qualified Name. * @@ -131,63 +132,63 @@ acpi_get_name ( acpi_handle handle, u32 name_type, - acpi_buffer *ret_path_ptr) + acpi_buffer *buffer) { acpi_status status; acpi_namespace_node *node; - /* Buffer pointer must be valid always */ + /* Parameter validation */ - if (!ret_path_ptr || (name_type > ACPI_NAME_TYPE_MAX)) { + if (name_type > ACPI_NAME_TYPE_MAX) { return (AE_BAD_PARAMETER); } - /* Allow length to be zero and ignore the pointer */ - - if ((ret_path_ptr->length) && - (!ret_path_ptr->pointer)) { - return (AE_BAD_PARAMETER); + status = acpi_ut_validate_buffer (buffer); + if (ACPI_FAILURE (status)) { + return (status); } if (name_type == ACPI_FULL_PATHNAME) { /* Get the full pathname (From the namespace root) */ - status = acpi_ns_handle_to_pathname (handle, &ret_path_ptr->length, - ret_path_ptr->pointer); + status = acpi_ns_handle_to_pathname (handle, buffer); return (status); } /* * Wants the single segment ACPI name. - * Validate handle and convert to an Node + * Validate handle and convert to a namespace Node */ - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + node = acpi_ns_map_handle_to_node (handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } - /* Check if name will fit in buffer */ + /* Validate/Allocate/Clear caller buffer */ - if (ret_path_ptr->length < PATH_SEGMENT_LENGTH) { - ret_path_ptr->length = PATH_SEGMENT_LENGTH; - status = AE_BUFFER_OVERFLOW; + status = acpi_ut_initialize_buffer (buffer, PATH_SEGMENT_LENGTH); + if (ACPI_FAILURE (status)) { goto unlock_and_exit; } /* Just copy the ACPI name from the Node and zero terminate it */ - STRNCPY (ret_path_ptr->pointer, (NATIVE_CHAR *) &node->name, + ACPI_STRNCPY (buffer->pointer, node->name.ascii, ACPI_NAME_SIZE); - ((NATIVE_CHAR *) ret_path_ptr->pointer) [ACPI_NAME_SIZE] = 0; + ((NATIVE_CHAR *) buffer->pointer) [ACPI_NAME_SIZE] = 0; status = AE_OK; unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); } @@ -226,18 +227,24 @@ return (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } node = acpi_ns_map_handle_to_node (handle); if (!node) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } - info->type = node->type; - info->name = node->name; + info->type = node->type; + info->name = node->name.integer; - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } /* * If not a device, we are all done. @@ -260,8 +267,7 @@ status = acpi_ut_execute_HID (node, &hid); if (ACPI_SUCCESS (status)) { - STRNCPY (info->hardware_id, hid.buffer, sizeof(info->hardware_id)); - + ACPI_STRNCPY (info->hardware_id, hid.buffer, sizeof(info->hardware_id)); info->valid |= ACPI_VALID_HID; } @@ -269,8 +275,7 @@ status = acpi_ut_execute_UID (node, &uid); if (ACPI_SUCCESS (status)) { - STRCPY (info->unique_id, uid.buffer); - + ACPI_STRCPY (info->unique_id, uid.buffer); info->valid |= ACPI_VALID_UID; } diff -Nur linux-2.4.19/drivers/acpi/namespace/nsxfobj.c linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsxfobj.c --- linux-2.4.19/drivers/acpi/namespace/nsxfobj.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/namespace/nsxfobj.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: nsxfobj - Public interfaces to the ACPI subsystem * ACPI Object oriented interfaces - * $Revision: 95 $ + * $Revision: 112 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,13 +26,104 @@ #include "acpi.h" -#include "acinterp.h" #include "acnamesp.h" -#include "acdispat.h" #define _COMPONENT ACPI_NAMESPACE - MODULE_NAME ("nsxfobj") + ACPI_MODULE_NAME ("nsxfobj") + + +/******************************************************************************* + * + * FUNCTION: Acpi_evaluate_object_typed + * + * PARAMETERS: Handle - Object handle (optional) + * *Pathname - Object pathname (optional) + * **External_params - List of parameters to pass to method, + * terminated by NULL. May be NULL + * if no parameters are being passed. + * *Return_buffer - Where to put method's return value (if + * any). If NULL, no value is returned. + * Return_type - Expected type of return object + * + * RETURN: Status + * + * DESCRIPTION: Find and evaluate the given object, passing the given + * parameters if necessary. One of "Handle" or "Pathname" must + * be valid (non-null) + * + ******************************************************************************/ + +acpi_status +acpi_evaluate_object_typed ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *external_params, + acpi_buffer *return_buffer, + acpi_object_type return_type) +{ + acpi_status status; + u8 must_free = FALSE; + + + ACPI_FUNCTION_TRACE ("Acpi_evaluate_object_typed"); + + + /* Return buffer must be valid */ + + if (!return_buffer) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (return_buffer->length == ACPI_ALLOCATE_BUFFER) { + must_free = TRUE; + } + + /* Evaluate the object */ + + status = acpi_evaluate_object (handle, pathname, external_params, return_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Type ANY means "don't care" */ + + if (return_type == ACPI_TYPE_ANY) { + return_ACPI_STATUS (AE_OK); + } + + if (return_buffer->length == 0) { + /* Error because caller specifically asked for a return value */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No return value\n")); + + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Examine the object type returned from Evaluate_object */ + + if (((acpi_object *) return_buffer->pointer)->type == return_type) { + return_ACPI_STATUS (AE_OK); + } + + /* Return object type does not match requested type */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Incorrect return type [%s] requested [%s]\n", + acpi_ut_get_type_name (((acpi_object *) return_buffer->pointer)->type), + acpi_ut_get_type_name (return_type))); + + if (must_free) { + /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */ + + acpi_os_free (return_buffer->pointer); + return_buffer->pointer = NULL; + } + + return_buffer->length = 0; + return_ACPI_STATUS (AE_TYPE); +} /******************************************************************************* @@ -65,12 +156,11 @@ acpi_status status; acpi_operand_object **internal_params = NULL; acpi_operand_object *internal_return_obj = NULL; - u32 buffer_space_needed; - u32 user_buffer_length; + ACPI_SIZE buffer_space_needed; u32 i; - FUNCTION_TRACE ("Acpi_evaluate_object"); + ACPI_FUNCTION_TRACE ("Acpi_evaluate_object"); /* @@ -83,12 +173,12 @@ * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ - internal_params = ACPI_MEM_CALLOCATE ((external_params->count + 1) * sizeof (void *)); + internal_params = ACPI_MEM_CALLOCATE (((ACPI_SIZE) external_params->count + 1) * + sizeof (void *)); if (!internal_params) { return_ACPI_STATUS (AE_NO_MEMORY); } - /* * Convert each external object in the list to an * internal object @@ -96,7 +186,6 @@ for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], &internal_params[i]); - if (ACPI_FAILURE (status)) { acpi_ut_delete_internal_object_list (internal_params); return_ACPI_STATUS (status); @@ -105,7 +194,6 @@ internal_params[external_params->count] = NULL; } - /* * Three major cases: * 1) Fully qualified pathname @@ -117,9 +205,9 @@ /* * The path is fully qualified, just evaluate by name */ - status = acpi_ns_evaluate_by_name (pathname, internal_params, &internal_return_obj); + status = acpi_ns_evaluate_by_name (pathname, internal_params, + &internal_return_obj); } - else if (!handle) { /* * A handle is optional iff a fully qualified pathname @@ -127,16 +215,16 @@ * qualified names above, this is an error */ if (!pathname) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Both Handle and Pathname are NULL\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Both Handle and Pathname are NULL\n")); } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Handle is NULL and Pathname is relative\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Handle is NULL and Pathname is relative\n")); } status = AE_BAD_PARAMETER; } - else { /* * We get here if we have a handle -- and if we have a @@ -148,15 +236,15 @@ * The null pathname case means the handle is for * the actual object to be evaluated */ - status = acpi_ns_evaluate_by_handle (handle, internal_params, &internal_return_obj); + status = acpi_ns_evaluate_by_handle (handle, internal_params, + &internal_return_obj); } - else { /* * Both a Handle and a relative Pathname */ status = acpi_ns_evaluate_relative (handle, pathname, internal_params, - &internal_return_obj); + &internal_return_obj); } } @@ -165,26 +253,23 @@ * If we are expecting a return value, and all went well above, * copy the return value to an external object. */ - if (return_buffer) { - user_buffer_length = return_buffer->length; - return_buffer->length = 0; - - if (internal_return_obj) { - if (VALID_DESCRIPTOR_TYPE (internal_return_obj, ACPI_DESC_TYPE_NAMED)) { + if (!internal_return_obj) { + return_buffer->length = 0; + } + else { + if (ACPI_GET_DESCRIPTOR_TYPE (internal_return_obj) == ACPI_DESC_TYPE_NAMED) { /* - * If we got an Node as a return object, - * this means the object we are evaluating - * has nothing interesting to return (such - * as a mutex, etc.) We return an error - * because these types are essentially - * unsupported by this interface. We - * don't check up front because this makes - * it easier to add support for various - * types at a later date if necessary. + * If we received a NS Node as a return object, this means that + * the object we are evaluating has nothing interesting to + * return (such as a mutex, etc.) We return an error because + * these types are essentially unsupported by this interface. + * We don't check up front because this makes it easier to add + * support for various types at a later date if necessary. */ status = AE_TYPE; - internal_return_obj = NULL; /* No need to delete an Node */ + internal_return_obj = NULL; /* No need to delete a NS Node */ + return_buffer->length = 0; } if (ACPI_SUCCESS (status)) { @@ -195,38 +280,29 @@ status = acpi_ut_get_object_size (internal_return_obj, &buffer_space_needed); if (ACPI_SUCCESS (status)) { - /* - * Check if there is enough room in the - * caller's buffer - */ - if (user_buffer_length < buffer_space_needed) { + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); + if (ACPI_FAILURE (status)) { /* - * Caller's buffer is too small, can't - * give him partial results fail the call - * but return the buffer size needed + * Caller's buffer is too small or a new one can't be allocated */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Needed buffer size %X, received %X\n", - buffer_space_needed, user_buffer_length)); - - return_buffer->length = buffer_space_needed; - status = AE_BUFFER_OVERFLOW; + "Needed buffer size %X, %s\n", + (u32) buffer_space_needed, acpi_format_exception (status))); } - else { /* * We have enough space for the object, build it */ status = acpi_ut_copy_iobject_to_eobject (internal_return_obj, return_buffer); - return_buffer->length = buffer_space_needed; } } } } } - /* Delete the return and parameter objects */ if (internal_return_obj) { @@ -275,7 +351,7 @@ acpi_handle child, acpi_handle *ret_handle) { - acpi_status status = AE_OK; + acpi_status status; acpi_namespace_node *node; acpi_namespace_node *parent_node = NULL; acpi_namespace_node *child_node = NULL; @@ -287,7 +363,10 @@ return (AE_BAD_PARAMETER); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } /* If null handle, use the parent */ @@ -300,10 +379,8 @@ goto unlock_and_exit; } } - - /* Non-null handle, ignore the parent */ - else { + /* Non-null handle, ignore the parent */ /* Convert and validate the handle */ child_node = acpi_ns_map_handle_to_node (child); @@ -313,11 +390,9 @@ } } - /* Internal function does the real work */ - node = acpi_ns_get_next_node ((acpi_object_type8) type, - parent_node, child_node); + node = acpi_ns_get_next_node (type, parent_node, child_node); if (!node) { status = AE_NOT_FOUND; goto unlock_and_exit; @@ -330,7 +405,7 @@ unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); } @@ -354,6 +429,7 @@ acpi_object_type *ret_type) { acpi_namespace_node *node; + acpi_status status; /* Parameter Validation */ @@ -371,21 +447,24 @@ return (AE_OK); } - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } /* Convert and validate the handle */ node = acpi_ns_map_handle_to_node (handle); if (!node) { - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } *ret_type = node->type; - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - return (AE_OK); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); } @@ -409,7 +488,7 @@ acpi_handle *ret_handle) { acpi_namespace_node *node; - acpi_status status = AE_OK; + acpi_status status; if (!ret_handle) { @@ -422,8 +501,10 @@ return (AE_NULL_ENTRY); } - - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } /* Convert and validate the handle */ @@ -433,22 +514,21 @@ goto unlock_and_exit; } - /* Get the parent entry */ *ret_handle = - acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_object (node)); + acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_node (node)); /* Return exeption if parent is null */ - if (!acpi_ns_get_parent_object (node)) { + if (!acpi_ns_get_parent_node (node)) { status = AE_NULL_ENTRY; } unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); } @@ -495,7 +575,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_walk_namespace"); + ACPI_FUNCTION_TRACE ("Acpi_walk_namespace"); /* Parameter validation */ @@ -512,13 +592,15 @@ * to the user function - since this function * must be allowed to make Acpi calls itself. */ - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - status = acpi_ns_walk_namespace ((acpi_object_type8) type, start_object, - max_depth, NS_WALK_UNLOCK, user_function, context, - return_value); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK, + user_function, context, return_value); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } @@ -547,15 +629,23 @@ acpi_status status; acpi_namespace_node *node; u32 flags; - acpi_device_id device_id; + acpi_device_id hid; + acpi_device_id cid; acpi_get_devices_info *info; info = context; - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + node = acpi_ns_map_handle_to_node (obj_handle); - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } if (!node) { return (AE_BAD_PARAMETER); @@ -570,30 +660,41 @@ } if (!(flags & 0x01)) { - /* don't return at the device or children of the device if not there */ + /* Don't return at the device or children of the device if not there */ return (AE_CTRL_DEPTH); } /* - * Filter based on device HID + * Filter based on device HID & CID */ if (info->hid != NULL) { - status = acpi_ut_execute_HID (node, &device_id); + status = acpi_ut_execute_HID (node, &hid); if (status == AE_NOT_FOUND) { return (AE_OK); } - else if (ACPI_FAILURE (status)) { return (AE_CTRL_DEPTH); } - if (STRNCMP (device_id.buffer, info->hid, sizeof (device_id.buffer)) != 0) { - return (AE_OK); + if (ACPI_STRNCMP (hid.buffer, info->hid, sizeof (hid.buffer)) != 0) { + status = acpi_ut_execute_CID (node, &cid); + if (status == AE_NOT_FOUND) { + return (AE_OK); + } + else if (ACPI_FAILURE (status)) { + return (AE_CTRL_DEPTH); + } + + /* TBD: Handle CID packages */ + + if (ACPI_STRNCMP (cid.buffer, info->hid, sizeof (cid.buffer)) != 0) { + return (AE_OK); + } } } - info->user_function (obj_handle, nesting_level, info->context, return_value); - return (AE_OK); + status = info->user_function (obj_handle, nesting_level, info->context, return_value); + return (status); } @@ -633,7 +734,7 @@ acpi_get_devices_info info; - FUNCTION_TRACE ("Acpi_get_devices"); + ACPI_FUNCTION_TRACE ("Acpi_get_devices"); /* Parameter validation */ @@ -656,14 +757,170 @@ * to the user function - since this function * must be allowed to make Acpi calls itself. */ - acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - NS_WALK_UNLOCK, + ACPI_NS_WALK_UNLOCK, acpi_ns_get_device_callback, &info, return_value); - acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } + + +/******************************************************************************* + * + * FUNCTION: Acpi_attach_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_attach_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler, + void *data) +{ + acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler || + !data) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_attach_data (node, handler, data); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_detach_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_detach_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler) +{ + acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_detach_data (node, handler); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_get_data + * + * PARAMETERS: + * + * RETURN: Status + * + * DESCRIPTION: + * + ******************************************************************************/ + +acpi_status +acpi_get_data ( + acpi_handle obj_handle, + ACPI_OBJECT_HANDLER handler, + void **data) +{ + acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler || + !data) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_get_attached_data (node, handler, data); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + diff -Nur linux-2.4.19/drivers/acpi/os.c linux-2.4.19-sgi211r3/drivers/acpi/os.c --- linux-2.4.19/drivers/acpi/os.c Fri Nov 9 13:39:25 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/os.c Wed Dec 31 16:00:00 1969 @@ -1,920 +0,0 @@ -/****************************************************************************** - * - * Module Name: os.c - Linux OSL functions - * $Revision: 49 $ - * - *****************************************************************************/ - -/* - * os.c - OS-dependent functions - * - * Copyright (C) 2000 Andrew Henroid - * Copyright (C) 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* Changes - * - * Christopher Liebman 2001-5-15 - * - Fixed improper kernel_thread parameters - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_ACPI_EFI -#include -#endif - -#ifdef _IA64 -#include -#endif - -#define _COMPONENT ACPI_OS_SERVICES - MODULE_NAME ("os") - -typedef struct -{ - OSD_EXECUTION_CALLBACK function; - void *context; -} ACPI_OS_DPC; - - -/***************************************************************************** - * Debugger Stuff - *****************************************************************************/ - -#ifdef ENABLE_DEBUGGER - -#include - -/* stuff for debugger support */ -int acpi_in_debugger = 0; -extern NATIVE_CHAR line_buf[80]; - -#endif - - -/***************************************************************************** - * Globals - *****************************************************************************/ - -static int acpi_irq_irq = 0; -static OSD_HANDLER acpi_irq_handler = NULL; -static void *acpi_irq_context = NULL; - - -/****************************************************************************** - * Functions - *****************************************************************************/ - -acpi_status -acpi_os_initialize(void) -{ - return AE_OK; -} - -acpi_status -acpi_os_terminate(void) -{ - if (acpi_irq_handler) { - acpi_os_remove_interrupt_handler(acpi_irq_irq, - acpi_irq_handler); - } - - return AE_OK; -} - -s32 -acpi_os_printf(const NATIVE_CHAR *fmt,...) -{ - s32 size; - va_list args; - va_start(args, fmt); - size = acpi_os_vprintf(fmt, args); - va_end(args); - - return size; -} - -s32 -acpi_os_vprintf(const NATIVE_CHAR *fmt, va_list args) -{ - static char buffer[512]; - int size = vsprintf(buffer, fmt, args); - -#ifdef ENABLE_DEBUGGER - if (acpi_in_debugger) { - kdb_printf("%s", buffer); - } else { - printk("%s", buffer); - } -#else - printk("%s", buffer); -#endif - - return size; -} - -void * -acpi_os_allocate(u32 size) -{ - return kmalloc(size, GFP_KERNEL); -} - -void * -acpi_os_callocate(u32 size) -{ - void *ptr = acpi_os_allocate(size); - if (ptr) - memset(ptr, 0, size); - - return ptr; -} - -void -acpi_os_free(void *ptr) -{ - kfree(ptr); -} - - -acpi_status -acpi_os_get_root_pointer(u32 flags, ACPI_PHYSICAL_ADDRESS *phys_addr) -{ -#ifndef CONFIG_ACPI_EFI - if (ACPI_FAILURE(acpi_find_root_pointer(flags, phys_addr))) { - printk(KERN_ERR "ACPI: System description tables not found\n"); - return AE_ERROR; - } -#else /*CONFIG_ACPI_EFI*/ - if (efi.acpi20) - *phys_addr = (ACPI_PHYSICAL_ADDRESS) efi.acpi20; - else if (efi.acpi) - *phys_addr = (ACPI_PHYSICAL_ADDRESS) efi.acpi; - else { - printk(KERN_ERR "ACPI: System description tables not found\n"); - *phys_addr = NULL; - return AE_ERROR; - } -#endif /*CONFIG_ACPI_EFI*/ - - return AE_OK; -} - -acpi_status -acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, u32 size, void **virt) -{ - if (phys > ULONG_MAX) { - printk(KERN_ERR "ACPI: Cannot map memory that high\n"); - return AE_ERROR; - } - - *virt = ioremap((unsigned long) phys, size); - if (!*virt) - return AE_ERROR; - - return AE_OK; -} - -void -acpi_os_unmap_memory(void *virt, u32 size) -{ - iounmap(virt); -} - -acpi_status -acpi_os_get_physical_address(void *virt, ACPI_PHYSICAL_ADDRESS *phys) -{ - if(!phys || !virt) - return AE_BAD_PARAMETER; - - *phys = virt_to_phys(virt); - - return AE_OK; -} - -static void -acpi_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - (*acpi_irq_handler)(acpi_irq_context); -} - -acpi_status -acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context) -{ -#ifdef _IA64 - irq = isa_irq_to_vector(irq); -#endif /*_IA64*/ - acpi_irq_irq = irq; - acpi_irq_handler = handler; - acpi_irq_context = context; - if (request_irq(irq, - acpi_irq, - SA_SHIRQ, - "acpi", - acpi_irq)) { - printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq); - return AE_ERROR; - } - - return AE_OK; -} - -acpi_status -acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler) -{ - if (acpi_irq_handler) { -#ifdef _IA64 - irq = isa_irq_to_vector(irq); -#endif /*_IA64*/ - free_irq(irq, acpi_irq); - acpi_irq_handler = NULL; - } - - return AE_OK; -} - -/* - * Running in interpreter thread context, safe to sleep - */ - -void -acpi_os_sleep(u32 sec, u32 ms) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ * sec + (ms * HZ) / 1000); -} - -void -acpi_os_stall(u32 us) -{ - if (us > 10000) { - mdelay(us / 1000); - } - else { - udelay(us); - } -} - -acpi_status -acpi_os_read_port( - ACPI_IO_ADDRESS port, - void *value, - u32 width) -{ - u32 dummy; - - if (!value) - value = &dummy; - - switch (width) - { - case 8: - *(u8*) value = inb(port); - break; - case 16: - *(u16*) value = inw(port); - break; - case 32: - *(u32*) value = inl(port); - break; - default: - BUG(); - } - - return AE_OK; -} - -acpi_status -acpi_os_write_port( - ACPI_IO_ADDRESS port, - NATIVE_UINT value, - u32 width) -{ - switch (width) - { - case 8: - outb(value, port); - break; - case 16: - outw(value, port); - break; - case 32: - outl(value, port); - break; - default: - BUG(); - } - - return AE_OK; -} - -acpi_status -acpi_os_read_memory( - ACPI_PHYSICAL_ADDRESS phys_addr, - void *value, - u32 width) -{ - u32 dummy; - - if (!value) - value = &dummy; - - switch (width) - { - case 8: - *(u8*) value = *(u8*) phys_to_virt(phys_addr); - break; - case 16: - *(u16*) value = *(u16*) phys_to_virt(phys_addr); - break; - case 32: - *(u32*) value = *(u32*) phys_to_virt(phys_addr); - break; - default: - BUG(); - } - - return AE_OK; -} - -acpi_status -acpi_os_write_memory( - ACPI_PHYSICAL_ADDRESS phys_addr, - u32 value, - u32 width) -{ - switch (width) - { - case 8: - *(u8*) phys_to_virt(phys_addr) = value; - break; - case 16: - *(u16*) phys_to_virt(phys_addr) = value; - break; - case 32: - *(u32*) phys_to_virt(phys_addr) = value; - break; - default: - BUG(); - } - - return AE_OK; -} - - -#ifdef CONFIG_ACPI_PCI - -/* Architecture-dependent low-level PCI configuration access functions. */ -extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *val); -extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 val); - -acpi_status -acpi_os_read_pci_configuration ( - acpi_pci_id *pci_id, - u32 reg, - void *value, - u32 width) -{ - int result = 0; - if (!value) - return AE_ERROR; - - switch (width) - { - case 8: - result = pci_config_read(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 1, value); - break; - case 16: - result = pci_config_read(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 2, value); - break; - case 32: - result = pci_config_read(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 4, value); - break; - default: - BUG(); - } - - return (result ? AE_ERROR : AE_OK); -} - -acpi_status -acpi_os_write_pci_configuration ( - acpi_pci_id *pci_id, - u32 reg, - NATIVE_UINT value, - u32 width) -{ - int result = 0; - - switch (width) - { - case 8: - result = pci_config_write(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 1, value); - break; - case 16: - result = pci_config_write(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 2, value); - break; - case 32: - result = pci_config_write(pci_id->segment, pci_id->bus, - pci_id->device, pci_id->function, reg, 4, value); - break; - default: - BUG(); - } - - return (result ? AE_ERROR : AE_OK); -} - -#else /*CONFIG_ACPI_PCI*/ - -acpi_status -acpi_os_read_pci_configuration ( - acpi_pci_id *pci_id, - u32 reg, - void *value, - u32 width) -{ - int devfn = PCI_DEVFN(pci_id->device, pci_id->function); - struct pci_dev *dev = pci_find_slot(pci_id->bus, devfn); - - if (!value || !dev) - return AE_ERROR; - - switch (width) - { - case 8: - if (pci_read_config_byte(dev, reg, (u8*) value)) - return AE_ERROR; - break; - case 16: - if (pci_read_config_word(dev, reg, (u16*) value)) - return AE_ERROR; - break; - case 32: - if (pci_read_config_dword(dev, reg, (u32*) value)) - return AE_ERROR; - break; - default: - BUG(); - } - - return AE_OK; -} - -acpi_status -acpi_os_write_pci_configuration ( - acpi_pci_id *pci_id, - u32 reg, - u32 value, - u32 width) -{ - int devfn = PCI_DEVFN(pci_id->device, pci_id->function); - struct pci_dev *dev = pci_find_slot(pci_id->bus, devfn); - - if (!dev) - return AE_ERROR; - - switch (width) - { - case 8: - if (pci_write_config_byte(dev, reg, value)) - return AE_ERROR; - break; - case 16: - if (pci_write_config_word(dev, reg, value)) - return AE_ERROR; - break; - case 32: - if (pci_write_config_dword(dev, reg, value)) - return AE_ERROR; - break; - default: - BUG(); - } - - return AE_OK; -} - -#endif /*CONFIG_ACPI_PCI*/ - - -acpi_status -acpi_os_load_module ( - char *module_name) -{ - PROC_NAME("acpi_os_load_module"); - - if (!module_name) - return AE_BAD_PARAMETER; - - if (0 > request_module(module_name)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to load module [%s].\n", module_name)); - return AE_ERROR; - } - - return AE_OK; -} - -acpi_status -acpi_os_unload_module ( - char *module_name) -{ - if (!module_name) - return AE_BAD_PARAMETER; - - /* TODO: How on Linux? */ - /* this is done automatically for all modules with - use_count = 0, I think. see: MOD_INC_USE_COUNT -ASG */ - - return AE_OK; -} - - -/* - * See acpi_os_queue_for_execution() - */ -static int -acpi_os_queue_exec ( - void *context) -{ - ACPI_OS_DPC *dpc = (ACPI_OS_DPC*)context; - - PROC_NAME("acpi_os_queue_exec"); - - daemonize(); - strcpy(current->comm, "kacpidpc"); - - if (!dpc || !dpc->function) - return AE_BAD_PARAMETER; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Executing function [%p(%p)].\n", dpc->function, dpc->context)); - - dpc->function(dpc->context); - - kfree(dpc); - - return 1; -} - -static void -acpi_os_schedule_exec ( - void *context) -{ - ACPI_OS_DPC *dpc = NULL; - int thread_pid = -1; - - PROC_NAME("acpi_os_schedule_exec"); - - dpc = (ACPI_OS_DPC*)context; - if (!dpc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); - return; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating new thread to run function [%p(%p)].\n", dpc->function, dpc->context)); - - thread_pid = kernel_thread(acpi_os_queue_exec, dpc, - (CLONE_FS | CLONE_FILES | SIGCHLD)); - if (thread_pid < 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to kernel_thread() failed.\n")); - acpi_os_free(dpc); - } -} - -acpi_status -acpi_os_queue_for_execution( - u32 priority, - OSD_EXECUTION_CALLBACK function, - void *context) -{ - acpi_status status = AE_OK; - ACPI_OS_DPC *dpc = NULL; - - PROC_NAME("acpi_os_queue_for_execution"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); - - if (!function) - return AE_BAD_PARAMETER; - - /* - * Queue via DPC: - * -------------- - * Note that we have to use two different processes for queuing DPCs: - * Interrupt-Level: Use schedule_task; can't spawn a new thread. - * Kernel-Level: Spawn a new kernel thread, as schedule_task has - * its limitations (e.g. single-threaded model), and - * all other task queues run at interrupt-level. - */ - switch (priority) { - - case OSD_PRIORITY_GPE: - { - static struct tq_struct task; - - /* - * Allocate/initialize DPC structure. Note that this memory will be - * freed by the callee. - */ - dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_ATOMIC); - if (!dpc) - return AE_NO_MEMORY; - - dpc->function = function; - dpc->context = context; - - memset(&task, 0, sizeof(struct tq_struct)); - - task.routine = acpi_os_schedule_exec; - task.data = (void*)dpc; - - if (schedule_task(&task) < 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to schedule_task() failed.\n")); - status = AE_ERROR; - } - } - break; - - default: - /* - * Allocate/initialize DPC structure. Note that this memory will be - * freed by the callee. - */ - dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_KERNEL); - if (!dpc) - return AE_NO_MEMORY; - - dpc->function = function; - dpc->context = context; - - acpi_os_schedule_exec(dpc); - break; - } - - return status; -} - - -acpi_status -acpi_os_create_semaphore( - u32 max_units, - u32 initial_units, - acpi_handle *handle) -{ - struct semaphore *sem = NULL; - - PROC_NAME("acpi_os_create_semaphore"); - - sem = acpi_os_callocate(sizeof(struct semaphore)); - if (!sem) - return AE_NO_MEMORY; - - sema_init(sem, initial_units); - - *handle = (acpi_handle*)sem; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating semaphore[%p|%d].\n", *handle, initial_units)); - - return AE_OK; -} - - -/* - * TODO: A better way to delete semaphores? Linux doesn't have a - * 'delete_semaphore()' function -- may result in an invalid - * pointer dereference for non-synchronized consumers. Should - * we at least check for blocked threads and signal/cancel them? - */ - -acpi_status -acpi_os_delete_semaphore( - acpi_handle handle) -{ - struct semaphore *sem = (struct semaphore*) handle; - - PROC_NAME("acpi_os_delete_semaphore"); - - if (!sem) - return AE_BAD_PARAMETER; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting semaphore[%p].\n", handle)); - - acpi_os_free(sem); sem = NULL; - - return AE_OK; -} - - -/* - * TODO: The kernel doesn't have a 'down_timeout' function -- had to - * improvise. The process is to sleep for one scheduler quantum - * until the semaphore becomes available. Downside is that this - * may result in starvation for timeout-based waits when there's - * lots of semaphore activity. - * - * TODO: Support for units > 1? - */ -acpi_status -acpi_os_wait_semaphore( - acpi_handle handle, - u32 units, - u32 timeout) -{ - acpi_status status = AE_OK; - struct semaphore *sem = (struct semaphore*)handle; - int ret = 0; - - PROC_NAME("acpi_os_wait_semaphore"); - - if (!sem || (units < 1)) - return AE_BAD_PARAMETER; - - if (units > 1) - return AE_SUPPORT; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); - - switch (timeout) - { - /* - * No Wait: - * -------- - * A zero timeout value indicates that we shouldn't wait - just - * acquire the semaphore if available otherwise return AE_TIME - * (a.k.a. 'would block'). - */ - case 0: - if(down_trylock(sem)) - status = AE_TIME; - break; - - /* - * Wait Indefinitely: - * ------------------ - */ - case WAIT_FOREVER: - ret = down_interruptible(sem); - if (ret < 0) - status = AE_ERROR; - break; - - /* - * Wait w/ Timeout: - * ---------------- - */ - default: - // TODO: A better timeout algorithm? - { - int i = 0; - static const int quantum_ms = 1000/HZ; - - ret = down_trylock(sem); - for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - ret = down_trylock(sem); - } - - if (ret != 0) - status = AE_TIME; - } - break; - } - - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Failed to acquire semaphore[%p|%d|%d]\n", handle, units, timeout)); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Acquired semaphore[%p|%d|%d]\n", handle, units, timeout)); - } - - return status; -} - - -/* - * TODO: Support for units > 1? - */ -acpi_status -acpi_os_signal_semaphore( - acpi_handle handle, - u32 units) -{ - struct semaphore *sem = (struct semaphore *) handle; - - PROC_NAME("acpi_os_signal_semaphore"); - - if (!sem || (units < 1)) - return AE_BAD_PARAMETER; - - if (units > 1) - return AE_SUPPORT; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Signaling semaphore[%p|%d]\n", handle, units)); - - up(sem); - - return AE_OK; -} - -u32 -acpi_os_get_line(NATIVE_CHAR *buffer) -{ - -#ifdef ENABLE_DEBUGGER - if (acpi_in_debugger) { - u32 chars; - - kdb_read(buffer, sizeof(line_buf)); - - /* remove the CR kdb includes */ - chars = strlen(buffer) - 1; - buffer[chars] = '\0'; - } -#endif - - return 0; -} - -/* - * We just have to assume we're dealing with valid memory - */ - -BOOLEAN -acpi_os_readable(void *ptr, u32 len) -{ - return 1; -} - -BOOLEAN -acpi_os_writable(void *ptr, u32 len) -{ - return 1; -} - -u32 -acpi_os_get_thread_id (void) -{ - if (!in_interrupt()) - return current->pid; - - return 0; -} - -acpi_status -acpi_os_signal ( - u32 function, - void *info) -{ - switch (function) - { - case ACPI_SIGNAL_FATAL: - printk(KERN_ERR "ACPI: Fatal opcode executed\n"); - break; - case ACPI_SIGNAL_BREAKPOINT: - { - char *bp_info = (char*) info; - - printk(KERN_ERR "ACPI breakpoint: %s\n", bp_info); - } - default: - break; - } - - return AE_OK; -} - -acpi_status -acpi_os_breakpoint(NATIVE_CHAR *msg) -{ - acpi_os_printf("breakpoint: %s", msg); - - return AE_OK; -} - diff -Nur linux-2.4.19/drivers/acpi/osl.c linux-2.4.19-sgi211r3/drivers/acpi/osl.c --- linux-2.4.19/drivers/acpi/osl.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/osl.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,913 @@ +/* + * acpi_osl.c - OS-dependent functions ($Revision: 1.2 $) + * + * Copyright (C) 2000 Andrew Henroid + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi.h" + +#ifdef CONFIG_ACPI_EFI +#include +u64 efi_mem_attributes (u64 phys_addr); +#endif + + +#define _COMPONENT ACPI_OS_SERVICES +ACPI_MODULE_NAME ("osl") + +#define PREFIX "ACPI: " + +typedef struct +{ + OSD_EXECUTION_CALLBACK function; + void *context; +} ACPI_OS_DPC; + + +#ifdef ENABLE_DEBUGGER +#include +/* stuff for debugger support */ +int acpi_in_debugger = 0; +extern NATIVE_CHAR line_buf[80]; +#endif /*ENABLE_DEBUGGER*/ + +static int acpi_irq_irq = 0; +static OSD_HANDLER acpi_irq_handler = NULL; +static void *acpi_irq_context = NULL; + + +acpi_status +acpi_os_initialize(void) +{ + /* + * Initialize PCI configuration space access, as we'll need to access + * it while walking the namespace (bus 0 and root bridges w/ _BBNs). + */ +#ifdef CONFIG_ACPI_PCI + pcibios_config_init(); + if (!pci_config_read || !pci_config_write) { + printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); + return AE_NULL_ENTRY; + } +#endif + + return AE_OK; +} + +acpi_status +acpi_os_terminate(void) +{ + if (acpi_irq_handler) { + acpi_os_remove_interrupt_handler(acpi_irq_irq, + acpi_irq_handler); + } + + return AE_OK; +} + +void +acpi_os_printf(const NATIVE_CHAR *fmt,...) +{ + va_list args; + va_start(args, fmt); + acpi_os_vprintf(fmt, args); + va_end(args); +} + +void +acpi_os_vprintf(const NATIVE_CHAR *fmt, va_list args) +{ + static char buffer[512]; + + vsprintf(buffer, fmt, args); + +#ifdef ENABLE_DEBUGGER + if (acpi_in_debugger) { + kdb_printf("%s", buffer); + } else { + printk("%s", buffer); + } +#else + printk("%s", buffer); +#endif +} + +void * +acpi_os_allocate(ACPI_SIZE size) +{ + return kmalloc(size, GFP_KERNEL); +} + +void * +acpi_os_callocate(ACPI_SIZE size) +{ + void *ptr = acpi_os_allocate(size); + if (ptr) + memset(ptr, 0, size); + + return ptr; +} + +void +acpi_os_free(void *ptr) +{ + kfree(ptr); +} + +acpi_status +acpi_os_get_root_pointer(u32 flags, ACPI_POINTER *addr) +{ +#ifdef CONFIG_ACPI_EFI + addr->pointer_type = ACPI_PHYSICAL_POINTER; + if (efi.acpi20) + addr->pointer.physical = (ACPI_PHYSICAL_ADDRESS) virt_to_phys(efi.acpi20); + else if (efi.acpi) + addr->pointer.physical = (ACPI_PHYSICAL_ADDRESS) virt_to_phys(efi.acpi); + else { + printk(KERN_ERR PREFIX "System description tables not found\n"); + return AE_NOT_FOUND; + } +#else + if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) { + printk(KERN_ERR PREFIX "System description tables not found\n"); + return AE_NOT_FOUND; + } +#endif /*CONFIG_ACPI_EFI*/ + + return AE_OK; +} + +acpi_status +acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size, void **virt) +{ +#ifdef CONFIG_ACPI_EFI + if (EFI_MEMORY_WB & efi_mem_attributes(phys)) { + *virt = phys_to_virt(phys); + } else { + *virt = ioremap(phys, size); + } +#else + if (phys > ULONG_MAX) { + printk(KERN_ERR PREFIX "Cannot map memory that high\n"); + return AE_BAD_PARAMETER; + } + /* + * ioremap checks to ensure this is in reserved space + */ + *virt = ioremap((unsigned long) phys, size); +#endif + + if (!*virt) + return AE_NO_MEMORY; + + return AE_OK; +} + +void +acpi_os_unmap_memory(void *virt, ACPI_SIZE size) +{ + iounmap(virt); +} + +acpi_status +acpi_os_get_physical_address(void *virt, ACPI_PHYSICAL_ADDRESS *phys) +{ + if(!phys || !virt) + return AE_BAD_PARAMETER; + + *phys = virt_to_phys(virt); + + return AE_OK; +} + +acpi_status +acpi_os_table_override (acpi_table_header *existing_table, acpi_table_header **new_table) +{ + if (!existing_table || !new_table) + return AE_BAD_PARAMETER; + + *new_table = NULL; + return AE_OK; +} + +static void +acpi_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + (*acpi_irq_handler)(acpi_irq_context); +} + +acpi_status +acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context) +{ +#ifdef CONFIG_IA64 + int vector; + + vector = acpi_irq_to_vector(irq); + if (vector < 0) { + printk(KERN_ERR PREFIX "SCI (IRQ%d) not registerd\n", irq); + return AE_OK; + } + irq = vector; +#endif + acpi_irq_irq = irq; + acpi_irq_handler = handler; + acpi_irq_context = context; + if (request_irq(irq, acpi_irq, SA_SHIRQ, "acpi", acpi_irq)) { + printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); + return AE_NOT_ACQUIRED; + } + + return AE_OK; +} + +acpi_status +acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler) +{ + if (acpi_irq_handler) { +#ifdef CONFIG_IA64 + irq = acpi_irq_to_vector(irq); +#endif + free_irq(irq, acpi_irq); + acpi_irq_handler = NULL; + } + + return AE_OK; +} + +/* + * Running in interpreter thread context, safe to sleep + */ + +void +acpi_os_sleep(u32 sec, u32 ms) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ * sec + (ms * HZ) / 1000); +} + +void +acpi_os_stall(u32 us) +{ + if (us > 10000) { + mdelay(us / 1000); + } + else { + udelay(us); + } +} + +acpi_status +acpi_os_read_port( + ACPI_IO_ADDRESS port, + void *value, + u32 width) +{ + u32 dummy; + + if (!value) + value = &dummy; + + switch (width) + { + case 8: + *(u8*) value = inb(port); + break; + case 16: + *(u16*) value = inw(port); + break; + case 32: + *(u32*) value = inl(port); + break; + default: + BUG(); + } + + return AE_OK; +} + +acpi_status +acpi_os_write_port( + ACPI_IO_ADDRESS port, + acpi_integer value, + u32 width) +{ + switch (width) + { + case 8: + outb(value, port); + break; + case 16: + outw(value, port); + break; + case 32: + outl(value, port); + break; + default: + BUG(); + } + + return AE_OK; +} + +acpi_status +acpi_os_read_memory( + ACPI_PHYSICAL_ADDRESS phys_addr, + void *value, + u32 width) +{ + u32 dummy; + void *virt_addr; + +#ifdef CONFIG_ACPI_EFI + int iomem = 0; + + if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { + virt_addr = phys_to_virt(phys_addr); + } else { + iomem = 1; + virt_addr = ioremap(phys_addr, width); + } +#else + virt_addr = phys_to_virt(phys_addr); +#endif + if (!value) + value = &dummy; + + switch (width) { + case 8: + *(u8*) value = *(u8*) virt_addr; + break; + case 16: + *(u16*) value = *(u16*) virt_addr; + break; + case 32: + *(u32*) value = *(u32*) virt_addr; + break; + default: + BUG(); + } + +#ifdef CONFIG_ACPI_EFI + if (iomem) + iounmap(virt_addr); +#endif + + return AE_OK; +} + +acpi_status +acpi_os_write_memory( + ACPI_PHYSICAL_ADDRESS phys_addr, + acpi_integer value, + u32 width) +{ + void *virt_addr; + +#ifdef CONFIG_ACPI_EFI + int iomem = 0; + + if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { + virt_addr = phys_to_virt(phys_addr); + } else { + iomem = 1; + virt_addr = ioremap(phys_addr,width); + } +#else + virt_addr = phys_to_virt(phys_addr); +#endif + + switch (width) { + case 8: + *(u8*) virt_addr = value; + break; + case 16: + *(u16*) virt_addr = value; + break; + case 32: + *(u32*) virt_addr = value; + break; + default: + BUG(); + } + +#ifdef CONFIG_ACPI_EFI + if (iomem) + iounmap(virt_addr); +#endif + + return AE_OK; +} + +#ifdef CONFIG_ACPI_PCI + +acpi_status +acpi_os_read_pci_configuration ( + acpi_pci_id *pci_id, + u32 reg, + void *value, + u32 width) +{ + int result = 0; + if (!value) + return AE_BAD_PARAMETER; + + switch (width) + { + case 8: + result = pci_config_read(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, 1, value); + break; + case 16: + result = pci_config_read(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, 2, value); + break; + case 32: + result = pci_config_read(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, 4, value); + break; + default: + BUG(); + } + + return (result ? AE_ERROR : AE_OK); +} + +acpi_status +acpi_os_write_pci_configuration ( + acpi_pci_id *pci_id, + u32 reg, + acpi_integer value, + u32 width) +{ + int result = 0; + + switch (width) + { + case 8: + result = pci_config_write(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, 1, value); + break; + case 16: + result = pci_config_write(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, 2, value); + break; + case 32: + result = pci_config_write(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, 4, value); + break; + default: + BUG(); + } + + return (result ? AE_ERROR : AE_OK); +} + +#else /*!CONFIG_ACPI_PCI*/ + +acpi_status +acpi_os_write_pci_configuration ( + acpi_pci_id *pci_id, + u32 reg, + acpi_integer value, + u32 width) +{ + return (AE_SUPPORT); +} + +acpi_status +acpi_os_read_pci_configuration ( + acpi_pci_id *pci_id, + u32 reg, + void *value, + u32 width) +{ + return (AE_SUPPORT); +} + +#endif /*CONFIG_ACPI_PCI*/ + +acpi_status +acpi_os_load_module ( + char *module_name) +{ + ACPI_FUNCTION_TRACE ("os_load_module"); + + if (!module_name) + return_ACPI_STATUS (AE_BAD_PARAMETER); + + if (0 > request_module(module_name)) { + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to load module [%s].\n", module_name)); + return_ACPI_STATUS (AE_ERROR); + } + + return_ACPI_STATUS (AE_OK); +} + +acpi_status +acpi_os_unload_module ( + char *module_name) +{ + if (!module_name) + return AE_BAD_PARAMETER; + + /* TODO: How on Linux? */ + /* this is done automatically for all modules with + use_count = 0, I think. see: MOD_INC_USE_COUNT -ASG */ + + return AE_OK; +} + + +/* + * See acpi_os_queue_for_execution() + */ +static int +acpi_os_queue_exec ( + void *context) +{ + ACPI_OS_DPC *dpc = (ACPI_OS_DPC*)context; + + ACPI_FUNCTION_TRACE ("os_queue_exec"); + + daemonize(); + strcpy(current->comm, "kacpidpc"); + + if (!dpc || !dpc->function) + return_ACPI_STATUS (AE_BAD_PARAMETER); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Executing function [%p(%p)].\n", dpc->function, dpc->context)); + + dpc->function(dpc->context); + + kfree(dpc); + + return_ACPI_STATUS (AE_OK); +} + +static void +acpi_os_schedule_exec ( + void *context) +{ + ACPI_OS_DPC *dpc = NULL; + int thread_pid = -1; + + ACPI_FUNCTION_TRACE ("os_schedule_exec"); + + dpc = (ACPI_OS_DPC*)context; + if (!dpc) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); + return_VOID; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating new thread to run function [%p(%p)].\n", dpc->function, dpc->context)); + + thread_pid = kernel_thread(acpi_os_queue_exec, dpc, + (CLONE_FS | CLONE_FILES | SIGCHLD)); + if (thread_pid < 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to kernel_thread() failed.\n")); + acpi_os_free(dpc); + } + return_VOID; +} + +acpi_status +acpi_os_queue_for_execution( + u32 priority, + OSD_EXECUTION_CALLBACK function, + void *context) +{ + acpi_status status = AE_OK; + ACPI_OS_DPC *dpc = NULL; + + ACPI_FUNCTION_TRACE ("os_queue_for_execution"); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); + + if (!function) + return_ACPI_STATUS (AE_BAD_PARAMETER); + + /* + * Queue via DPC: + * -------------- + * Note that we have to use two different processes for queuing DPCs: + * Interrupt-Level: Use schedule_task; can't spawn a new thread. + * Kernel-Level: Spawn a new kernel thread, as schedule_task has + * its limitations (e.g. single-threaded model), and + * all other task queues run at interrupt-level. + */ + switch (priority) { + + case OSD_PRIORITY_GPE: + { + static struct tq_struct task; + + /* + * Allocate/initialize DPC structure. Note that this memory will be + * freed by the callee. + */ + dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_ATOMIC); + if (!dpc) + return_ACPI_STATUS (AE_NO_MEMORY); + + dpc->function = function; + dpc->context = context; + + memset(&task, 0, sizeof(struct tq_struct)); + + task.routine = acpi_os_schedule_exec; + task.data = (void*)dpc; + + if (schedule_task(&task) < 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to schedule_task() failed.\n")); + status = AE_ERROR; + } + } + break; + + default: + /* + * Allocate/initialize DPC structure. Note that this memory will be + * freed by the callee. + */ + dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_KERNEL); + if (!dpc) + return_ACPI_STATUS (AE_NO_MEMORY); + + dpc->function = function; + dpc->context = context; + + acpi_os_schedule_exec(dpc); + break; + } + + return_ACPI_STATUS (status); +} + + +acpi_status +acpi_os_create_semaphore( + u32 max_units, + u32 initial_units, + acpi_handle *handle) +{ + struct semaphore *sem = NULL; + + ACPI_FUNCTION_TRACE ("os_create_semaphore"); + + sem = acpi_os_callocate(sizeof(struct semaphore)); + if (!sem) + return_ACPI_STATUS (AE_NO_MEMORY); + + sema_init(sem, initial_units); + + *handle = (acpi_handle*)sem; + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating semaphore[%p|%d].\n", *handle, initial_units)); + + return_ACPI_STATUS (AE_OK); +} + + +/* + * TODO: A better way to delete semaphores? Linux doesn't have a + * 'delete_semaphore()' function -- may result in an invalid + * pointer dereference for non-synchronized consumers. Should + * we at least check for blocked threads and signal/cancel them? + */ + +acpi_status +acpi_os_delete_semaphore( + acpi_handle handle) +{ + struct semaphore *sem = (struct semaphore*) handle; + + ACPI_FUNCTION_TRACE ("os_delete_semaphore"); + + if (!sem) + return_ACPI_STATUS (AE_BAD_PARAMETER); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting semaphore[%p].\n", handle)); + + acpi_os_free(sem); sem = NULL; + + return_ACPI_STATUS (AE_OK); +} + + +/* + * TODO: The kernel doesn't have a 'down_timeout' function -- had to + * improvise. The process is to sleep for one scheduler quantum + * until the semaphore becomes available. Downside is that this + * may result in starvation for timeout-based waits when there's + * lots of semaphore activity. + * + * TODO: Support for units > 1? + */ +acpi_status +acpi_os_wait_semaphore( + acpi_handle handle, + u32 units, + u32 timeout) +{ + acpi_status status = AE_OK; + struct semaphore *sem = (struct semaphore*)handle; + int ret = 0; + + ACPI_FUNCTION_TRACE ("os_wait_semaphore"); + + if (!sem || (units < 1)) + return_ACPI_STATUS (AE_BAD_PARAMETER); + + if (units > 1) + return_ACPI_STATUS (AE_SUPPORT); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); + + switch (timeout) + { + /* + * No Wait: + * -------- + * A zero timeout value indicates that we shouldn't wait - just + * acquire the semaphore if available otherwise return AE_TIME + * (a.k.a. 'would block'). + */ + case 0: + if(down_trylock(sem)) + status = AE_TIME; + break; + + /* + * Wait Indefinitely: + * ------------------ + */ + case WAIT_FOREVER: + ret = down_interruptible(sem); + if (ret < 0) + status = AE_ERROR; + break; + + /* + * Wait w/ Timeout: + * ---------------- + */ + default: + // TODO: A better timeout algorithm? + { + int i = 0; + static const int quantum_ms = 1000/HZ; + + ret = down_trylock(sem); + for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + ret = down_trylock(sem); + } + + if (ret != 0) + status = AE_TIME; + } + break; + } + + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Failed to acquire semaphore[%p|%d|%d]\n", handle, units, timeout)); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Acquired semaphore[%p|%d|%d]\n", handle, units, timeout)); + } + + return_ACPI_STATUS (status); +} + + +/* + * TODO: Support for units > 1? + */ +acpi_status +acpi_os_signal_semaphore( + acpi_handle handle, + u32 units) +{ + struct semaphore *sem = (struct semaphore *) handle; + + ACPI_FUNCTION_TRACE ("os_signal_semaphore"); + + if (!sem || (units < 1)) + return_ACPI_STATUS (AE_BAD_PARAMETER); + + if (units > 1) + return_ACPI_STATUS (AE_SUPPORT); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Signaling semaphore[%p|%d]\n", handle, units)); + + up(sem); + + return_ACPI_STATUS (AE_OK); +} + +u32 +acpi_os_get_line(NATIVE_CHAR *buffer) +{ + +#ifdef ENABLE_DEBUGGER + if (acpi_in_debugger) { + u32 chars; + + kdb_read(buffer, sizeof(line_buf)); + + /* remove the CR kdb includes */ + chars = strlen(buffer) - 1; + buffer[chars] = '\0'; + } +#endif + + return 0; +} + +/* + * We just have to assume we're dealing with valid memory + */ + +BOOLEAN +acpi_os_readable(void *ptr, u32 len) +{ + return 1; +} + +BOOLEAN +acpi_os_writable(void *ptr, u32 len) +{ + return 1; +} + +u32 +acpi_os_get_thread_id (void) +{ + if (!in_interrupt()) + return current->pid; + + return 0; +} + +acpi_status +acpi_os_signal ( + u32 function, + void *info) +{ + switch (function) + { + case ACPI_SIGNAL_FATAL: + printk(KERN_ERR PREFIX "Fatal opcode executed\n"); + break; + case ACPI_SIGNAL_BREAKPOINT: + { + char *bp_info = (char*) info; + + printk(KERN_ERR "ACPI breakpoint: %s\n", bp_info); + } + default: + break; + } + + return AE_OK; +} + +acpi_status +acpi_os_breakpoint(NATIVE_CHAR *msg) +{ + acpi_os_printf("breakpoint: %s", msg); + + return AE_OK; +} + diff -Nur linux-2.4.19/drivers/acpi/ospm/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/Makefile --- linux-2.4.19/drivers/acpi/ospm/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/Makefile Wed Dec 31 16:00:00 1969 @@ -1,22 +0,0 @@ -# -# Makefile for the Linux OSPM code. -# - -O_TARGET := $(notdir $(CURDIR)).o - -ACPI_CFLAGS += -I$(CURDIR)/include - -EXTRA_CFLAGS += $(ACPI_CFLAGS) - -subdir-$(CONFIG_ACPI_BUSMGR) += busmgr -subdir-$(CONFIG_ACPI_EC) += ec -subdir-$(CONFIG_ACPI_SYS) += system -subdir-$(CONFIG_ACPI_CPU) += processor -subdir-$(CONFIG_ACPI_CMBATT) += battery -subdir-$(CONFIG_ACPI_AC) += ac_adapter -subdir-$(CONFIG_ACPI_BUTTON) += button -subdir-$(CONFIG_ACPI_THERMAL) += thermal - -obj-y += $(foreach dir,$(subdir-y),$(dir)/ospm_$(dir).o) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/ac_adapter/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/ac_adapter/Makefile --- linux-2.4.19/drivers/acpi/ospm/ac_adapter/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ac_adapter/Makefile Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/ac_adapter/ac.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/ac_adapter/ac.c --- linux-2.4.19/drivers/acpi/ospm/ac_adapter/ac.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ac_adapter/ac.c Wed Dec 31 16:00:00 1969 @@ -1,398 +0,0 @@ -/***************************************************************************** - * - * Module Name: ac.c - * $Revision: 23 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include "ac.h" - - -#define _COMPONENT ACPI_AC_ADAPTER - MODULE_NAME ("ac") - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: ac_print - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Prints out information on a specific ac_adapter. - * - ****************************************************************************/ - -void -ac_print ( - AC_CONTEXT *ac_adapter) -{ -#ifdef ACPI_DEBUG - - acpi_buffer buffer; - - PROC_NAME("ac_print"); - - if (!ac_adapter) { - return; - } - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - /* - * Get the full pathname for this ACPI object. - */ - acpi_get_name(ac_adapter->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - /* - * Print out basic adapter information. - */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| AC Adapter[%02x]:[%p] %s\n", ac_adapter->device_handle, ac_adapter->acpi_handle, (char*)buffer.pointer)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); -#endif /*ACPI_DEBUG*/ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: ac_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ac_add_device( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - AC_CONTEXT *ac_adapter = NULL; - acpi_device_info info; - - FUNCTION_TRACE("ac_add_device"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding ac_adapter device [%02x].\n", device_handle)); - - if (!context || *context) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Get information on this device. - */ - status = bm_get_device_info(device_handle, &device); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Allocate a new AC_CONTEXT structure. - */ - ac_adapter = acpi_os_callocate(sizeof(AC_CONTEXT)); - if (!ac_adapter) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - ac_adapter->device_handle = device->handle; - ac_adapter->acpi_handle = device->acpi_handle; - - /* - * Get information on this object. - */ - status = acpi_get_object_info(ac_adapter->acpi_handle, &info); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to get object info for ac_adapter device.")); - goto end; - } - - /* - * _UID? - * ----- - */ - if (info.valid & ACPI_VALID_UID) { - strncpy(ac_adapter->uid, info.unique_id, sizeof(info.unique_id)); - } - else { - strncpy(ac_adapter->uid, "0", sizeof("0")); - } - - /* - * _STA? - * ----- - */ - if (!(info.valid & ACPI_VALID_STA)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Must have valid _STA.\n")); - status = AE_ERROR; - goto end; - } - - status = ac_osl_add_device(ac_adapter); - if (ACPI_FAILURE(status)) { - goto end; - } - - *context = ac_adapter; - - ac_print(ac_adapter); - -end: - if (ACPI_FAILURE(status)) { - acpi_os_free(ac_adapter); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ac_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ac_remove_device ( - void **context) -{ - acpi_status status = AE_OK; - AC_CONTEXT *ac_adapter = NULL; - - FUNCTION_TRACE("ac_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ac_adapter = (AC_CONTEXT*)*context; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing ac_adapter device [%02x].\n", ac_adapter->device_handle)); - - ac_osl_remove_device(ac_adapter); - - acpi_os_free(ac_adapter); - - *context = NULL; - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: ac_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ac_initialize (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("ac_initialize"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - driver.notify = &ac_notify; - driver.request = &ac_request; - - /* - * Register driver for AC Adapter devices. - */ - MEMCPY(criteria.hid, AC_HID_AC_ADAPTER, sizeof(AC_HID_AC_ADAPTER)); - - status = bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ac_terminate - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ac_terminate (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("ac_terminate"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Unregister driver for AC Adapter devices. - */ - MEMCPY(criteria.hid, AC_HID_AC_ADAPTER, sizeof(AC_HID_AC_ADAPTER)); - - driver.notify = &ac_notify; - driver.request = &ac_request; - - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/***************************************************************************** - * - * FUNCTION: ac_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ -acpi_status -ac_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ac_notify"); - - if (!context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - switch (notify_type) { - - case BM_NOTIFY_DEVICE_ADDED: - status = ac_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = ac_remove_device(context); - break; - - case AC_NOTIFY_STATUS_CHANGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status change event detected.\n")); - status = ac_osl_generate_event(notify_type, - ((AC_CONTEXT*)*context)); - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ac_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ac_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ac_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Handle Request: - * --------------- - */ - switch (request->command) { - - default: - status = AE_SUPPORT; - break; - } - - request->status = status; - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/ac_adapter/ac_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/ac_adapter/ac_osl.c --- linux-2.4.19/drivers/acpi/ospm/ac_adapter/ac_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ac_adapter/ac_osl.c Wed Dec 31 16:00:00 1969 @@ -1,257 +0,0 @@ -/***************************************************************************** - * - * Module Name: ac_osl.c - * $Revision: 10 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include "ac.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - AC Adapter Driver"); -MODULE_LICENSE("GPL"); - - -#define AC_PROC_ROOT "ac_adapter" -#define AC_PROC_STATUS "status" -#define AC_ON_LINE "on-line" -#define AC_OFF_LINE "off-line" - -extern struct proc_dir_entry *bm_proc_root; -static struct proc_dir_entry *ac_proc_root = NULL; - - -/**************************************************************************** - * - * FUNCTION: ac_osl_proc_read_status - * - ****************************************************************************/ - -static int -ac_osl_proc_read_status ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - acpi_status status = AE_OK; - AC_CONTEXT *ac_adapter = NULL; - char *p = page; - int len; - - if (!context) { - goto end; - } - - ac_adapter = (AC_CONTEXT*)context; - - /* don't get status more than once for a single proc read */ - if (off != 0) { - goto end; - } - - status = bm_evaluate_simple_integer(ac_adapter->acpi_handle, - "_PSR", &(ac_adapter->is_online)); - if (ACPI_FAILURE(status)) { - p += sprintf(p, "Error reading AC Adapter status\n"); - goto end; - } - - if (ac_adapter->is_online) { - p += sprintf(p, "Status: %s\n", - AC_ON_LINE); - } - else { - p += sprintf(p, "Status: %s\n", - AC_OFF_LINE); - } - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - return(len); -} - - -/**************************************************************************** - * - * FUNCTION: ac_osl_add_device - * - ****************************************************************************/ - -acpi_status -ac_osl_add_device( - AC_CONTEXT *ac_adapter) -{ - struct proc_dir_entry *proc_entry = NULL; - - if (!ac_adapter) { - return(AE_BAD_PARAMETER); - } - - printk(KERN_INFO "ACPI: AC Adapter found\n"); - - proc_entry = proc_mkdir(ac_adapter->uid, ac_proc_root); - if (!proc_entry) { - return(AE_ERROR); - } - - create_proc_read_entry(AC_PROC_STATUS, S_IFREG | S_IRUGO, - proc_entry, ac_osl_proc_read_status, (void*)ac_adapter); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: ac_osl_remove_device - * - ****************************************************************************/ - -acpi_status -ac_osl_remove_device ( - AC_CONTEXT *ac_adapter) -{ - char proc_entry[64]; - - if (!ac_adapter) { - return(AE_BAD_PARAMETER); - } - - sprintf(proc_entry, "%s/%s", ac_adapter->uid, AC_PROC_STATUS); - remove_proc_entry(proc_entry, ac_proc_root); - - sprintf(proc_entry, "%s", ac_adapter->uid); - remove_proc_entry(proc_entry, ac_proc_root); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: ac_osl_generate_event - * - ****************************************************************************/ - -acpi_status -ac_osl_generate_event ( - u32 event, - AC_CONTEXT *ac_adapter) -{ - acpi_status status = AE_OK; - - if (!ac_adapter) { - return(AE_BAD_PARAMETER); - } - - switch (event) { - - case AC_NOTIFY_STATUS_CHANGE: - status = bm_osl_generate_event(ac_adapter->device_handle, - AC_PROC_ROOT, ac_adapter->uid, event, 0); - break; - - default: - return(AE_BAD_PARAMETER); - break; - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: ac_osl_init - * - * PARAMETERS: - * - * RETURN: 0: Success - * - * DESCRIPTION: Module initialization. - * - ****************************************************************************/ - -static int __init -ac_osl_init (void) -{ - acpi_status status = AE_OK; - - ac_proc_root = proc_mkdir(AC_PROC_ROOT, bm_proc_root); - if (!ac_proc_root) { - status = AE_ERROR; - } - else { - status = ac_initialize(); - if (ACPI_FAILURE(status)) { - remove_proc_entry(AC_PROC_ROOT, bm_proc_root); - } - - } - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - - -/**************************************************************************** - * - * FUNCTION: ac_osl_cleanup - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Module cleanup. - * - ****************************************************************************/ - -static void __exit -ac_osl_cleanup (void) -{ - ac_terminate(); - - if (ac_proc_root) { - remove_proc_entry(AC_PROC_ROOT, bm_proc_root); - } - - return; -} - - -module_init(ac_osl_init); -module_exit(ac_osl_cleanup); diff -Nur linux-2.4.19/drivers/acpi/ospm/battery/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/battery/Makefile --- linux-2.4.19/drivers/acpi/ospm/battery/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/battery/Makefile Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/battery/bt.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/battery/bt.c --- linux-2.4.19/drivers/acpi/ospm/battery/bt.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/battery/bt.c Wed Dec 31 16:00:00 1969 @@ -1,654 +0,0 @@ -/***************************************************************************** - * - * Module Name: bt.c - * $Revision: 29 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include "bt.h" - - -#define _COMPONENT ACPI_BATTERY - MODULE_NAME ("bt") - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bt_print - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Prints out information on a specific battery. - * - ****************************************************************************/ - -void -bt_print ( - BT_CONTEXT *battery) -{ -#ifdef ACPI_DEBUG - acpi_buffer buffer; - - PROC_NAME("bt_print"); - - if (!battery) { - return; - } - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - /* - * Get the full pathname for this ACPI object. - */ - acpi_get_name(battery->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - /* - * Print out basic battery information. - */ - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Battery[%02x]:[%p] %s\n", battery->device_handle, battery->acpi_handle, (char*)buffer.pointer)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| uid[%s] is_present[%d] power_units[%s]\n", battery->uid, battery->is_present, battery->power_units)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); -#endif /*ACPI_DEBUG*/ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: bt_get_info - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - * NOTES: Allocates battery_info - which must be freed by the caller. - * - ****************************************************************************/ - -acpi_status -bt_get_info ( - BT_CONTEXT *battery, - BT_BATTERY_INFO **battery_info) -{ - acpi_status status = AE_OK; - acpi_buffer bif_buffer, package_format, package_data; - acpi_object *package = NULL; - - FUNCTION_TRACE("bt_get_info"); - - if (!battery || !battery_info || *battery_info) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - memset(&bif_buffer, 0, sizeof(acpi_buffer)); - - /* - * Evalute _BIF: - * ------------- - * And be sure to deallocate bif_buffer.pointer! - */ - status = bm_evaluate_object(battery->acpi_handle, "_BIF", NULL, - &bif_buffer); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Extract Package Data: - * --------------------- - * Type-cast this bif_buffer to a package and use helper - * functions to convert results into BT_BATTERY_INFO structure. - * The first attempt is just to get the size of the package - * data; the second gets the data (once we know the required - * bif_buffer size). - */ - status = bm_cast_buffer(&bif_buffer, (void**)&package, - sizeof(acpi_object)); - if (ACPI_FAILURE(status)) { - goto end; - } - - package_format.length = sizeof("NNNNNNNNNSSSS"); - package_format.pointer = "NNNNNNNNNSSSS"; - - memset(&package_data, 0, sizeof(acpi_buffer)); - - status = bm_extract_package_data(package, &package_format, - &package_data); - if (status != AE_BUFFER_OVERFLOW) { - if (status == AE_OK) { - status = AE_ERROR; - } - goto end; - } - - package_data.pointer = acpi_os_callocate(package_data.length); - if (!package_data.pointer) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - status = bm_extract_package_data(package, &package_format, - &package_data); - if (ACPI_FAILURE(status)) { - acpi_os_free(package_data.pointer); - goto end; - } - - *battery_info = package_data.pointer; - -end: - acpi_os_free(bif_buffer.pointer); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bt_get_status - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_get_status ( - BT_CONTEXT *battery, - BT_BATTERY_STATUS **battery_status) -{ - acpi_status status = AE_OK; - acpi_buffer bst_buffer, package_format, package_data; - acpi_object *package = NULL; - - FUNCTION_TRACE("bt_get_status"); - - if (!battery || !battery_status || *battery_status) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - memset(&bst_buffer, 0, sizeof(acpi_buffer)); - - /* - * Evalute _BST: - * ------------- - * And be sure to deallocate bst_buffer.pointer! - */ - status = bm_evaluate_object(battery->acpi_handle, "_BST", - NULL, &bst_buffer); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Extract Package Data: - * --------------------- - * Type-cast this bst_buffer to a package and use helper - * functions to convert results into BT_BATTERY_STATUS structure. - * The first attempt is just to get the size of the package data; - * the second gets the data (once we know the required bst_buffer - * size). - */ - status = bm_cast_buffer(&bst_buffer, (void**)&package, - sizeof(acpi_object)); - if (ACPI_FAILURE(status)) { - goto end; - } - - package_format.length = sizeof("NNNN"); - package_format.pointer = "NNNN"; - - memset(&package_data, 0, sizeof(acpi_buffer)); - - status = bm_extract_package_data(package, &package_format, - &package_data); - if (status != AE_BUFFER_OVERFLOW) { - if (status == AE_OK) { - status = AE_ERROR; - } - goto end; - } - - package_data.pointer = acpi_os_callocate(package_data.length); - if (!package_data.pointer) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - status = bm_extract_package_data(package, &package_format, - &package_data); - if (ACPI_FAILURE(status)) { - acpi_os_free(package_data.pointer); - goto end; - } - - *battery_status = package_data.pointer; - -end: - acpi_os_free(bst_buffer.pointer); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bt_check_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_check_device ( - BT_CONTEXT *battery) -{ - acpi_status status = AE_OK; - BM_DEVICE_STATUS battery_status = BM_STATUS_UNKNOWN; - u32 was_present = FALSE; - BT_BATTERY_INFO *battery_info = NULL; - - FUNCTION_TRACE("bt_check_device"); - - if (!battery) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - was_present = battery->is_present; - - /* - * Battery Present? - * ---------------- - * Get the device status and check if battery slot is occupied. - */ - status = bm_get_device_status(battery->device_handle, &battery_status); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unable to get battery status.\n")); - return_ACPI_STATUS(status); - } - - if (battery_status & BM_STATUS_BATTERY_PRESENT) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery socket occupied.\n")); - battery->is_present = TRUE; - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery socket not occupied.\n")); - battery->is_present = FALSE; - } - - /* - * Battery Appeared? - * ----------------- - */ - if (!was_present && battery->is_present) { - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery insertion detected.\n")); - - /* - * Units of Power? - * --------------- - * Get the 'units of power', as we'll need this to report - * status information. - */ - status = bt_get_info(battery, &battery_info); - if (ACPI_SUCCESS(status)) { - battery->power_units = (battery_info->power_unit) - ? BT_POWER_UNITS_AMPS : BT_POWER_UNITS_WATTS; - acpi_os_free(battery_info); - } - } - - /* - * Battery Disappeared? - * -------------------- - */ - else if (was_present && !battery->is_present) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery removal detected.\n")); - battery->power_units = BT_POWER_UNITS_DEFAULT; - } - - return_ACPI_STATUS(status); -} - - -/***************************************************************************** - * - * FUNCTION: bt_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_add_device ( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - BT_CONTEXT *battery = NULL; - - FUNCTION_TRACE("bt_add_device"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding battery device [%02x].\n", device_handle)); - - if (!context || *context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Get information on this device. - */ - status = bm_get_device_info(device_handle, &device); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Allocate a new BT_CONTEXT structure. - */ - battery = acpi_os_callocate(sizeof(BT_CONTEXT)); - if (!battery) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - battery->device_handle = device->handle; - battery->acpi_handle = device->acpi_handle; - strncpy(battery->uid, device->id.uid, sizeof(battery->uid)); - - battery->power_units = BT_POWER_UNITS_DEFAULT; - battery->is_present = FALSE; - - /* - * See if battery is really present. - */ - status = bt_check_device(battery); - if (ACPI_FAILURE(status)) { - goto end; - } - - status = bt_osl_add_device(battery); - if (ACPI_FAILURE(status)) { - goto end; - } - - *context = battery; - - bt_print(battery); - -end: - if (ACPI_FAILURE(status)) { - acpi_os_free(battery); - } - - return_ACPI_STATUS(status); -} - - -/***************************************************************************** - * - * FUNCTION: bt_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_remove_device ( - void **context) -{ - acpi_status status = AE_OK; - BT_CONTEXT *battery = NULL; - - FUNCTION_TRACE("bt_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - battery = (BT_CONTEXT*)*context; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing battery device [%02x].\n", battery->device_handle)); - - bt_osl_remove_device(battery); - - acpi_os_free(battery); - - *context = NULL; - - return_ACPI_STATUS(status); -} - - -/***************************************************************************** - * External Functions - *****************************************************************************/ - -/***************************************************************************** - * - * FUNCTION: bt_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_initialize (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("bt_initialize"); - - memset(&criteria, 0, sizeof(BM_DEVICE_ID)); - memset(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Register driver for driver method battery devices. - */ - MEMCPY(criteria.hid, BT_HID_CM_BATTERY, sizeof(BT_HID_CM_BATTERY)); - - driver.notify = &bt_notify; - driver.request = &bt_request; - - status = bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bt_terminate - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_terminate (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("bt_terminate"); - - memset(&criteria, 0, sizeof(BM_DEVICE_ID)); - memset(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Unregister driver for driver method battery devices. - */ - MEMCPY(criteria.hid, BT_HID_CM_BATTERY, sizeof(BT_HID_CM_BATTERY)); - - driver.notify = &bt_notify; - driver.request = &bt_request; - - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bt_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bt_notify"); - - if (!context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - switch (notify_type) { - - case BM_NOTIFY_DEVICE_ADDED: - status = bt_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = bt_remove_device(context); - break; - - case BT_NOTIFY_STATUS_CHANGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status change (_BST) event detected.\n")); - status = bt_osl_generate_event(notify_type, - ((BT_CONTEXT*)*context)); - break; - - case BT_NOTIFY_INFORMATION_CHANGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Information change (_BIF) event detected.\n")); - status = bt_check_device((BT_CONTEXT*)*context); - if (ACPI_SUCCESS(status)) { - status = bt_osl_generate_event(notify_type, - ((BT_CONTEXT*)*context)); - } - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bt_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bt_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bt_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) - return_ACPI_STATUS(AE_BAD_PARAMETER); - - /* - * Handle request: - * --------------- - */ - switch (request->command) { - - default: - status = AE_SUPPORT; - break; - } - - request->status = status; - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/battery/bt_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/battery/bt_osl.c --- linux-2.4.19/drivers/acpi/ospm/battery/bt_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/battery/bt_osl.c Wed Dec 31 16:00:00 1969 @@ -1,443 +0,0 @@ -/****************************************************************************** - * - * Module Name: bt_osl.c - * $Revision: 24 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Changes: - * Brendan Burns 2000-11-15 - * - added proc battery interface - * - parse returned data from _BST and _BIF - * Andy Grover 2000-12-8 - * - improved proc interface - */ - - -#include -#include -#include -#include -#include -#include -#include "bt.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Control Method Battery Driver"); -MODULE_LICENSE("GPL"); - - -#define BT_PROC_ROOT "battery" -#define BT_PROC_STATUS "status" -#define BT_PROC_INFO "info" - -extern struct proc_dir_entry *bm_proc_root; -static struct proc_dir_entry *bt_proc_root = NULL; - - -/**************************************************************************** - * - * FUNCTION: bt_osl_proc_read_info - * - ****************************************************************************/ - -static int -bt_osl_proc_read_info ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - BT_CONTEXT *battery = NULL; - BT_BATTERY_INFO *battery_info = NULL; - char *p = page; - int len = 0; - - if (!context || (off != 0)) { - goto end; - } - - battery = (BT_CONTEXT*)context; - - /* - * Battery Present? - * ---------------- - */ - if (!battery->is_present) { - p += sprintf(p, "Present: no\n"); - goto end; - } - else { - p += sprintf(p, "Present: yes\n"); - } - - /* - * Get Battery Information: - * ------------------------ - */ - if (ACPI_FAILURE(bt_get_info(battery, &battery_info))) { - p += sprintf(p, "Error reading battery information (_BIF)\n"); - goto end; - } - - if (battery_info->design_capacity == BT_UNKNOWN) { - p += sprintf(p, "Design Capacity: unknown\n"); - } - else { - p += sprintf(p, "Design Capacity: %d %sh\n", - (u32)battery_info->design_capacity, - battery->power_units); - } - - if (battery_info->last_full_capacity == BT_UNKNOWN) { - p += sprintf(p, "Last Full Capacity: unknown\n"); - } - else { - p += sprintf(p, "Last Full Capacity: %d %sh\n", - (u32)battery_info->last_full_capacity, - battery->power_units); - } - - if (battery_info->battery_technology == 0) { - p += sprintf(p, "Battery Technology: primary (non-rechargeable)\n"); - } - else if (battery_info->battery_technology == 1) { - p += sprintf(p, "Battery Technology: secondary (rechargeable)\n"); - } - else { - p += sprintf(p, "Battery Technology: unknown\n"); - } - - if (battery_info->design_voltage == BT_UNKNOWN) { - p += sprintf(p, "Design Voltage: unknown\n"); - } - else { - p += sprintf(p, "Design Voltage: %d mV\n", - (u32)battery_info->design_voltage); - } - - p += sprintf(p, "Design Capacity Warning: %d %sh\n", - (u32)battery_info->design_capacity_warning, - battery->power_units); - p += sprintf(p, "Design Capacity Low: %d %sh\n", - (u32)battery_info->design_capacity_low, - battery->power_units); - p += sprintf(p, "Capacity Granularity 1: %d %sh\n", - (u32)battery_info->battery_capacity_granularity_1, - battery->power_units); - p += sprintf(p, "Capacity Granularity 2: %d %sh\n", - (u32)battery_info->battery_capacity_granularity_2, - battery->power_units); - p += sprintf(p, "Model Number: %s\n", - battery_info->model_number); - p += sprintf(p, "Serial Number: %s\n", - battery_info->serial_number); - p += sprintf(p, "Battery Type: %s\n", - battery_info->battery_type); - p += sprintf(p, "OEM Info: %s\n", - battery_info->oem_info); - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - acpi_os_free(battery_info); - - return(len); -} - - -/**************************************************************************** - * - * FUNCTION: bt_osl_proc_read_status - * - ****************************************************************************/ - -static int -bt_osl_proc_read_status ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - BT_CONTEXT *battery = NULL; - BT_BATTERY_STATUS *battery_status = NULL; - char *p = page; - int len = 0; - - if (!context || (off != 0)) { - goto end; - } - - battery = (BT_CONTEXT*)context; - - /* - * Battery Present? - * ---------------- - */ - if (!battery->is_present) { - p += sprintf(p, "Present: no\n"); - goto end; - } - else { - p += sprintf(p, "Present: yes\n"); - } - - /* - * Get Battery Status: - * ------------------- - */ - if (ACPI_FAILURE(bt_get_status(battery, &battery_status))) { - p += sprintf(p, "Error reading battery status (_BST)\n"); - goto end; - } - - /* - * Store Data: - * ----------- - */ - - if (!battery_status->state) { - p += sprintf(p, "State: ok\n"); - } - else { - if (battery_status->state & 0x1) - p += sprintf(p, "State: discharging\n"); - if (battery_status->state & 0x2) - p += sprintf(p, "State: charging\n"); - if (battery_status->state & 0x4) - p += sprintf(p, "State: critically low\n"); - } - - if (battery_status->present_rate == BT_UNKNOWN) { - p += sprintf(p, "Present Rate: unknown\n"); - } - else { - p += sprintf(p, "Present Rate: %d %s\n", - (u32)battery_status->present_rate, - battery->power_units); - } - - if (battery_status->remaining_capacity == BT_UNKNOWN) { - p += sprintf(p, "Remaining Capacity: unknown\n"); - } - else { - p += sprintf(p, "Remaining Capacity: %d %sh\n", - (u32)battery_status->remaining_capacity, - battery->power_units); - } - - if (battery_status->present_voltage == BT_UNKNOWN) { - p += sprintf(p, "Battery Voltage: unknown\n"); - } - else { - p += sprintf(p, "Battery Voltage: %d mV\n", - (u32)battery_status->present_voltage); - } - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - acpi_os_free(battery_status); - - return(len); -} - - -/**************************************************************************** - * - * FUNCTION: bt_osl_add_device - * - ****************************************************************************/ - -acpi_status -bt_osl_add_device( - BT_CONTEXT *battery) -{ - struct proc_dir_entry *proc_entry = NULL; - - if (!battery) { - return(AE_BAD_PARAMETER); - } - - if (battery->is_present) { - printk("ACPI: Battery socket found, battery present\n"); - } - else { - printk("ACPI: Battery socket found, battery absent\n"); - } - - proc_entry = proc_mkdir(battery->uid, bt_proc_root); - if (!proc_entry) { - return(AE_ERROR); - } - - create_proc_read_entry(BT_PROC_STATUS, S_IFREG | S_IRUGO, - proc_entry, bt_osl_proc_read_status, (void*)battery); - - create_proc_read_entry(BT_PROC_INFO, S_IFREG | S_IRUGO, - proc_entry, bt_osl_proc_read_info, (void*)battery); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bt_osl_remove_device - * - ****************************************************************************/ - -acpi_status -bt_osl_remove_device ( - BT_CONTEXT *battery) -{ - char proc_entry[64]; - - if (!battery) { - return(AE_BAD_PARAMETER); - } - - sprintf(proc_entry, "%s/%s", battery->uid, BT_PROC_INFO); - remove_proc_entry(proc_entry, bt_proc_root); - - sprintf(proc_entry, "%s/%s", battery->uid, BT_PROC_STATUS); - remove_proc_entry(proc_entry, bt_proc_root); - - sprintf(proc_entry, "%s", battery->uid); - remove_proc_entry(proc_entry, bt_proc_root); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bt_osl_generate_event - * - ****************************************************************************/ - -acpi_status -bt_osl_generate_event ( - u32 event, - BT_CONTEXT *battery) -{ - acpi_status status = AE_OK; - - if (!battery) { - return(AE_BAD_PARAMETER); - } - - switch (event) { - - case BT_NOTIFY_STATUS_CHANGE: - case BT_NOTIFY_INFORMATION_CHANGE: - status = bm_osl_generate_event(battery->device_handle, - BT_PROC_ROOT, battery->uid, event, 0); - break; - - default: - return(AE_BAD_PARAMETER); - break; - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: bt_osl_init - * - * PARAMETERS: - * - * RETURN: 0: Success - * - * DESCRIPTION: Module initialization. - * - ****************************************************************************/ - -static int __init -bt_osl_init (void) -{ - acpi_status status = AE_OK; - - /* abort if no busmgr */ - if (!bm_proc_root) - return -ENODEV; - - bt_proc_root = proc_mkdir(BT_PROC_ROOT, bm_proc_root); - if (!bt_proc_root) { - status = AE_ERROR; - } - else { - status = bt_initialize(); - if (ACPI_FAILURE(status)) { - remove_proc_entry(BT_PROC_ROOT, bm_proc_root); - } - } - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - - -/**************************************************************************** - * - * FUNCTION: bt_osl_cleanup - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Module cleanup. - * - ****************************************************************************/ - -static void __exit -bt_osl_cleanup (void) -{ - bt_terminate(); - - if (bt_proc_root) { - remove_proc_entry(BT_PROC_ROOT, bm_proc_root); - } - - return; -} - - -module_init(bt_osl_init); -module_exit(bt_osl_cleanup); diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/Makefile --- linux-2.4.19/drivers/acpi/ospm/busmgr/Makefile Sun Sep 2 07:48:02 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/Makefile Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -export-objs := bm_osl.o - -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bm.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bm.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bm.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bm.c Wed Dec 31 16:00:00 1969 @@ -1,1146 +0,0 @@ -/****************************************************************************** - * - * Module Name: bm.c - * $Revision: 48 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include "bm.h" - - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bm") - - -/**************************************************************************** - * Globals - ****************************************************************************/ - -extern fadt_descriptor_rev2 acpi_fadt; -/* TBD: Make dynamically sizeable. */ -BM_NODE_LIST node_list; - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/***************************************************************************** - * - * FUNCTION: bm_print_object - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -bm_print_object ( - acpi_handle handle) -{ - acpi_buffer buffer; - acpi_handle parent; - acpi_object_type type; - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - acpi_get_parent(handle, &parent); - acpi_get_type(handle, &type); - - /* - * TBD: Hack to get around scope identification problem. - */ - if (type == ACPI_TYPE_ANY) { - if (ACPI_SUCCESS(acpi_get_next_object(ACPI_TYPE_ANY, - handle, 0, NULL))) { - type = INTERNAL_TYPE_SCOPE; - } - } - - switch (type) - { - case INTERNAL_TYPE_SCOPE: - acpi_os_printf("SCOPE: "); - break; - case ACPI_TYPE_INTEGER: - acpi_os_printf("SIMPLE (number): "); - break; - case ACPI_TYPE_STRING: - acpi_os_printf("SIMPLE (string): "); - break; - case ACPI_TYPE_BUFFER: - acpi_os_printf("SIMPLE (buffer): "); - break; - case ACPI_TYPE_PACKAGE: - acpi_os_printf("SIMPLE (package): "); - break; - case ACPI_TYPE_FIELD_UNIT: - acpi_os_printf("FIELD UNIT: "); - break; - case ACPI_TYPE_DEVICE: - acpi_os_printf("DEVICE: "); - break; - case ACPI_TYPE_EVENT: - acpi_os_printf("EVENT: "); - break; - case ACPI_TYPE_METHOD: - acpi_os_printf("CONTROL METHOD: "); - break; - case ACPI_TYPE_MUTEX: - acpi_os_printf("MUTEX: "); - break; - case ACPI_TYPE_REGION: - acpi_os_printf("OPERATION REGION: "); - break; - case ACPI_TYPE_POWER: - acpi_os_printf("POWER RESOURCE: "); - break; - case ACPI_TYPE_PROCESSOR: - acpi_os_printf("PROCESSOR: "); - break; - case ACPI_TYPE_THERMAL: - acpi_os_printf("THERMAL ZONE: "); - break; - case ACPI_TYPE_BUFFER_FIELD: - acpi_os_printf("BUFFER FIELD: "); - break; - case ACPI_TYPE_DDB_HANDLE: - acpi_os_printf("DDB HANDLE: "); - break; - default: - acpi_os_printf("OTHER (%d): ", type); - break; - } - - acpi_os_printf("Object[%p][%s] parent[%p].\n", handle, (char*)buffer.pointer, parent); - - acpi_os_free(buffer.pointer); -} - - -/**************************************************************************** - * - * FUNCTION: bm_print_node - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -bm_print_node ( - BM_NODE *node, - u32 flags) -{ -#ifdef ACPI_DEBUG - acpi_buffer buffer; - BM_DEVICE *device = NULL; - char *type_string = NULL; - - PROC_NAME("bm_print_node"); - - if (!node) { - return; - } - - device = &(node->device); - - if (flags & BM_PRINT_PRESENT) { - if (!BM_DEVICE_PRESENT(device)) { - return; - } - } - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - acpi_get_name(device->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - switch(device->id.type) { - case BM_TYPE_SYSTEM: - type_string = " System"; - break; - case BM_TYPE_SCOPE: - type_string = " Scope"; - break; - case BM_TYPE_PROCESSOR: - type_string = " Proc"; - break; - case BM_TYPE_THERMAL_ZONE: - type_string = "Thermal"; - break; - case BM_TYPE_POWER_RESOURCE: - type_string = " Power"; - break; - case BM_TYPE_FIXED_BUTTON: - type_string = " Button"; - break; - case BM_TYPE_DEVICE: - type_string = " Device"; - break; - default: - type_string = "Unknown"; - break; - } - - if (!(flags & BM_PRINT_GROUP)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+-------------------------------------------------------------------------------\n")); - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| %s[%02x]:[%p] flags[%02x] hid[%s] %s\n", type_string, device->handle, device->acpi_handle, device->flags, (device->id.hid[0] ? device->id.hid : " "), (char*)buffer.pointer)); - - if (flags & BM_PRINT_IDENTIFICATION) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| identification: uid[%s] adr[%08x]\n", device->id.uid, device->id.adr)); - } - - if (flags & BM_PRINT_LINKAGE) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| linkage: this[%p] parent[%p] next[%p]\n", node, node->parent, node->next)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| scope.head[%p] scope.tail[%p]\n", node->scope.head, node->scope.tail)); - } - - if (flags & BM_PRINT_POWER) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| power: state[D%d] flags[%08x]\n", device->power.state, device->power.flags)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| S0[%02x] S1[%02x] S2[%02x] S3[%02x] S4[%02x] S5[%02x]\n", device->power.dx_supported[0], device->power.dx_supported[1], device->power.dx_supported[2], device->power.dx_supported[3], device->power.dx_supported[4], device->power.dx_supported[5])); - } - - if (!(flags & BM_PRINT_GROUP)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+-------------------------------------------------------------------------------\n")); - } - - acpi_os_free(buffer.pointer); -#endif /*ACPI_DEBUG*/ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: bm_print_hierarchy - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -bm_print_hierarchy (void) -{ -#ifdef ACPI_DEBUG - u32 i = 0; - - FUNCTION_TRACE("bm_print_hierarchy"); - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - for (i = 0; i < node_list.count; i++) { - bm_print_node(node_list.nodes[i], BM_PRINT_GROUP | BM_PRINT_PRESENT); - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); -#endif /*ACPI_DEBUG*/ - - return_VOID; -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_status - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_status ( - BM_DEVICE *device) -{ - acpi_status status = AE_OK; - - if (!device) { - return AE_BAD_PARAMETER; - } - - device->status = BM_STATUS_UNKNOWN; - - /* - * Dynamic Status? - * --------------- - * If _STA isn't present we just return the default status. - */ - if (!(device->flags & BM_FLAGS_DYNAMIC_STATUS)) { - device->status = BM_STATUS_DEFAULT; - return AE_OK; - } - - /* - * Evaluate _STA: - * -------------- - */ - status = bm_evaluate_simple_integer(device->acpi_handle, "_STA", - &(device->status)); - - return status; -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_identification - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_identification ( - BM_DEVICE *device) -{ - acpi_status status = AE_OK; - acpi_device_info info; - - if (!device) { - return AE_BAD_PARAMETER; - } - - if (!(device->flags & BM_FLAGS_IDENTIFIABLE)) { - return AE_OK; - } - - device->id.uid[0] = BM_UID_UNKNOWN; - device->id.hid[0] = BM_HID_UNKNOWN; - device->id.adr = BM_ADDRESS_UNKNOWN; - - /* - * Get Object Info: - * ---------------- - * Evalute _UID, _HID, and _ADR... - */ - status = acpi_get_object_info(device->acpi_handle, &info); - if (ACPI_FAILURE(status)) { - return status; - } - - if (info.valid & ACPI_VALID_UID) { - MEMCPY((void*)device->id.uid, (void*)info.unique_id, - sizeof(BM_DEVICE_UID)); - } - - if (info.valid & ACPI_VALID_HID) { - MEMCPY((void*)device->id.hid, (void*)info.hardware_id, - sizeof(BM_DEVICE_HID)); - } - - if (info.valid & ACPI_VALID_ADR) { - device->id.adr = info.address; - } - - return status; -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_flags - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_flags ( - BM_DEVICE *device) -{ - acpi_handle acpi_handle = NULL; - - if (!device) { - return AE_BAD_PARAMETER; - } - - device->flags = BM_FLAGS_UNKNOWN; - - switch (device->id.type) { - - case BM_TYPE_DEVICE: - - /* - * Presence of _DCK indicates a docking station. - */ - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_DCK", &acpi_handle))) { - device->flags |= BM_FLAGS_DOCKING_STATION; - } - - /* - * Presence of _EJD and/or _EJx indicates 'ejectable'. - * TBD: _EJx... - */ - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_EJD", &acpi_handle))) { - device->flags |= BM_FLAGS_EJECTABLE; - } - - /* - * Presence of _PR0 or _PS0 indicates 'power manageable'. - */ - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_PR0", &acpi_handle)) || - ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_PS0", &acpi_handle))) { - device->flags |= BM_FLAGS_POWER_CONTROL; - } - - /* - * Presence of _CRS indicates 'configurable'. - */ - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_CRS", &acpi_handle))) { - device->flags |= BM_FLAGS_CONFIGURABLE; - } - - /* Fall through to next case statement. */ - - case BM_TYPE_PROCESSOR: - case BM_TYPE_THERMAL_ZONE: - case BM_TYPE_POWER_RESOURCE: - /* - * Presence of _HID or _ADR indicates 'identifiable'. - */ - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_HID", &acpi_handle)) || - ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_ADR", &acpi_handle))) { - device->flags |= BM_FLAGS_IDENTIFIABLE; - } - - /* - * Presence of _STA indicates 'dynamic status'. - */ - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, - "_STA", &acpi_handle))) { - device->flags |= BM_FLAGS_DYNAMIC_STATUS; - } - - break; - } - - return AE_OK; -} - - -/**************************************************************************** - * - * FUNCTION: bm_add_namespace_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_add_namespace_device ( - acpi_handle acpi_handle, - acpi_object_type acpi_type, - BM_NODE *parent, - BM_NODE **child) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - BM_DEVICE *device = NULL; - - FUNCTION_TRACE("bm_add_namespace_device"); - - if (!parent || !child) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (node_list.count > BM_HANDLES_MAX) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - (*child) = NULL; - - /* - * Create Node: - * ------------ - */ - node = acpi_os_callocate(sizeof(BM_NODE)); - if (!node) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - node->parent = parent; - node->next = NULL; - - device = &(node->device); - - device->handle = node_list.count; - device->acpi_handle = acpi_handle; - - /* - * Device Type: - * ------------ - */ - switch (acpi_type) { - case INTERNAL_TYPE_SCOPE: - device->id.type = BM_TYPE_SCOPE; - break; - case ACPI_TYPE_PROCESSOR: - device->id.type = BM_TYPE_PROCESSOR; - break; - case ACPI_TYPE_THERMAL: - device->id.type = BM_TYPE_THERMAL_ZONE; - break; - case ACPI_TYPE_POWER: - device->id.type = BM_TYPE_POWER_RESOURCE; - break; - case ACPI_TYPE_DEVICE: - device->id.type = BM_TYPE_DEVICE; - break; - } - - /* - * Get Other Device Info: - * ---------------------- - * But only if this device's parent is present (which implies - * this device MAY be present). - */ - if (BM_NODE_PRESENT(node->parent)) { - /* - * Device Flags - */ - status = bm_get_flags(device); - if (ACPI_FAILURE(status)) { - goto end; - } - - /* - * Device Identification - */ - status = bm_get_identification(device); - if (ACPI_FAILURE(status)) { - goto end; - } - - /* - * Device Status - */ - status = bm_get_status(device); - if (ACPI_FAILURE(status)) { - goto end; - } - - /* - * Power Management: - * ----------------- - * If this node doesn't provide direct power control - * then we inherit PM capabilities from its parent. - * - * TBD: Inherit! - */ - if (BM_IS_POWER_CONTROL(device)) { - status = bm_get_pm_capabilities(node); - if (ACPI_FAILURE(status)) { - goto end; - } - } - } - -end: - if (ACPI_FAILURE(status)) { - acpi_os_free(node); - } - else { - /* - * Add to the node_list. - */ - node_list.nodes[node_list.count++] = node; - - /* - * Formulate Hierarchy: - * -------------------- - * Arrange within the namespace by assigning the parent and - * adding to the parent device's list of children (scope). - */ - if (!parent->scope.head) { - parent->scope.head = node; - } - else { - if (!parent->scope.tail) { - (parent->scope.head)->next = node; - } - else { - (parent->scope.tail)->next = node; - } - } - parent->scope.tail = node; - - (*child) = node; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_enumerate_namespace - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_enumerate_namespace (void) -{ - acpi_status status = AE_OK; - acpi_handle parent_handle = ACPI_ROOT_OBJECT; - acpi_handle child_handle = NULL; - BM_NODE *parent = NULL; - BM_NODE *child = NULL; - acpi_object_type acpi_type = 0; - u32 level = 1; - - FUNCTION_TRACE("bm_enumerate_namespace"); - - parent = node_list.nodes[0]; - - /* - * Enumerate ACPI Namespace: - * ------------------------- - * Parse through the ACPI namespace, identify all 'devices', - * and create a new entry for each in our collection. - */ - while (level > 0) { - - /* - * Get the next object at this level. - */ - status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, child_handle, &child_handle); - if (ACPI_SUCCESS(status)) { - /* - * TBD: This is a hack to get around the problem - * identifying scope objects. Scopes - * somehow need to be uniquely identified. - */ - status = acpi_get_type(child_handle, &acpi_type); - if (ACPI_SUCCESS(status) && (acpi_type == ACPI_TYPE_ANY)) { - status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL); - if (ACPI_SUCCESS(status)) { - acpi_type = INTERNAL_TYPE_SCOPE; - } - } - - /* - * Device? - * ------- - * If this object is a 'device', insert into the - * ACPI Bus Manager's local hierarchy and search - * the object's scope for any child devices (a - * depth-first search). - */ - switch (acpi_type) { - case INTERNAL_TYPE_SCOPE: - case ACPI_TYPE_DEVICE: - case ACPI_TYPE_PROCESSOR: - case ACPI_TYPE_THERMAL: - case ACPI_TYPE_POWER: - status = bm_add_namespace_device(child_handle, acpi_type, parent, &child); - if (ACPI_SUCCESS(status)) { - status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL); - if (ACPI_SUCCESS(status)) { - level++; - parent_handle = child_handle; - child_handle = 0; - parent = child; - } - } - break; - } - } - - /* - * Scope Exhausted: - * ---------------- - * No more children in this object's scope, Go back up - * in the namespace tree to the object's parent. - */ - else { - level--; - child_handle = parent_handle; - acpi_get_parent(parent_handle, - &parent_handle); - - if (parent) { - parent = parent->parent; - } - else { - return_ACPI_STATUS(AE_NULL_ENTRY); - } - } - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_add_fixed_feature_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_add_fixed_feature_device ( - BM_NODE *parent, - BM_DEVICE_TYPE device_type, - char *device_hid) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_add_fixed_feature_device"); - - if (!parent) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (node_list.count > BM_HANDLES_MAX) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* - * Allocate the new device and add to the device array. - */ - node = acpi_os_callocate(sizeof(BM_NODE)); - if (!node) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* - * Get device info. - */ - node->device.handle = node_list.count; - node->device.acpi_handle = ACPI_ROOT_OBJECT; - node->device.id.type = BM_TYPE_FIXED_BUTTON; - if (device_hid) { - MEMCPY((void*)node->device.id.hid, device_hid, - sizeof(node->device.id.hid)); - } - node->device.flags = BM_FLAGS_FIXED_FEATURE; - node->device.status = BM_STATUS_DEFAULT; - /* TBD: Device PM capabilities */ - - /* - * Add to the node_list. - */ - node_list.nodes[node_list.count++] = node; - - /* - * Formulate Hierarchy: - * -------------------- - * Arrange within the namespace by assigning the parent and - * adding to the parent device's list of children (scope). - */ - node->parent = parent; - node->next = NULL; - - if (parent) { - if (!parent->scope.head) { - parent->scope.head = node; - } - else { - if (!parent->scope.tail) { - (parent->scope.head)->next = node; - } - else { - (parent->scope.tail)->next = node; - } - } - parent->scope.tail = node; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_enumerate_fixed_features - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_enumerate_fixed_features (void) -{ - FUNCTION_TRACE("bm_enumerate_fixed_features"); - - /* - * Root Object: - * ------------ - * Fabricate the root object, which happens to always get a - * device_handle of zero. - */ - node_list.nodes[0] = acpi_os_callocate(sizeof(BM_NODE)); - if (NULL == (node_list.nodes[0])) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - node_list.nodes[0]->device.handle = BM_HANDLE_ROOT; - node_list.nodes[0]->device.acpi_handle = ACPI_ROOT_OBJECT; - node_list.nodes[0]->device.flags = BM_FLAGS_UNKNOWN; - node_list.nodes[0]->device.status = BM_STATUS_DEFAULT; - node_list.nodes[0]->device.id.type = BM_TYPE_SYSTEM; - /* TBD: Get system PM capabilities (Sx states?) */ - - node_list.count++; - - /* - * Fixed Features: - * --------------- - * Enumerate fixed-feature devices (e.g. power and sleep buttons). - */ - if (acpi_fadt.pwr_button == 0) { - bm_add_fixed_feature_device(node_list.nodes[0], - BM_TYPE_FIXED_BUTTON, BM_HID_POWER_BUTTON); - } - - if (acpi_fadt.sleep_button == 0) { - bm_add_fixed_feature_device(node_list.nodes[0], - BM_TYPE_FIXED_BUTTON, BM_HID_SLEEP_BUTTON); - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_handle - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_handle ( - acpi_handle acpi_handle, - BM_HANDLE *device_handle) -{ - acpi_status status = AE_NOT_FOUND; - u32 i = 0; - - FUNCTION_TRACE("bm_get_handle"); - - if (!device_handle) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - *device_handle = BM_HANDLE_UNKNOWN; - - /* - * Search all devices for a match on the ACPI handle. - */ - for (i=0; idevice.acpi_handle == acpi_handle) { - *device_handle = node_list.nodes[i]->device.handle; - status = AE_OK; - break; - } - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_node - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_node ( - BM_HANDLE device_handle, - acpi_handle acpi_handle, - BM_NODE **node) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bm_get_node"); - - if (!node) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* busmgr failed to init, but we're being called by subordinate drivers */ - if (node_list.count < 1) { - return_ACPI_STATUS(AE_NOT_FOUND); - } - - /* - * If no device handle, resolve acpi handle to device handle. - */ - if (!device_handle && acpi_handle) { - status = bm_get_handle(acpi_handle, &device_handle); - if (ACPI_FAILURE(status)) - return_ACPI_STATUS(status); - } - - /* - * Valid device handle? - */ - if (device_handle > BM_HANDLES_MAX) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid node handle [%02x] detected.\n", device_handle)); - return_ACPI_STATUS(AE_ERROR); - } - - *node = node_list.nodes[device_handle]; - - /* - * Valid node? - */ - if (!(*node)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) node entry [%02x] detected.\n", device_handle)); - return_ACPI_STATUS(AE_NULL_ENTRY); - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_initialize - * - * PARAMETERS: - * - * RETURN: Exception code. - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_initialize (void) -{ - acpi_status status = AE_OK; - u32 start = 0; - u32 stop = 0; - u32 elapsed = 0; - - FUNCTION_TRACE("bm_initialize"); - - MEMSET(&node_list, 0, sizeof(BM_NODE_LIST)); - - status = acpi_get_timer(&start); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Building device hierarchy.\n")); - - /* - * Enumerate ACPI fixed-feature devices. - */ - status = bm_enumerate_fixed_features(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Enumerate the ACPI namespace. - */ - status = bm_enumerate_namespace(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - acpi_get_timer(&stop); - acpi_get_timer_duration(start, stop, &elapsed); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Building device hierarchy took [%d] microseconds.\n", elapsed)); - - /* - * Display hierarchy. - */ - bm_print_hierarchy(); - - /* - * Register for all standard and device-specific notifications. - */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Registering for all device notifications.\n")); - - status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, - ACPI_SYSTEM_NOTIFY, &bm_notify, NULL); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to register for standard notifications.\n")); - return_ACPI_STATUS(status); - } - - status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, - ACPI_DEVICE_NOTIFY, &bm_notify, NULL); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to register for device-specific notifications.\n")); - return_ACPI_STATUS(status); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Bus Manager enabled.\n")); - - /* - * Initialize built-in power resource driver. - */ - bm_pr_initialize(); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_terminate - * - * PARAMETERS: - * - * RETURN: Exception code. - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_terminate (void) -{ - acpi_status status = AE_OK; - u32 i = 0; - - FUNCTION_TRACE("bm_terminate"); - - /* - * Terminate built-in power resource driver. - */ - bm_pr_terminate(); - - /* - * Unregister for all notifications. - */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unregistering for device notifications.\n")); - - status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, - ACPI_SYSTEM_NOTIFY, &bm_notify); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to un-register for standard notifications.\n")); - } - - status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, - ACPI_DEVICE_NOTIFY, &bm_notify); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to un-register for device-specific notifications.\n")); - } - - /* - * Parse through the device array, freeing all entries. - */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing device hierarchy.\n")); - for (i = 0; i < node_list.count; i++) { - if (node_list.nodes[i]) { - acpi_os_free(node_list.nodes[i]); - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Bus Manager disabled.\n")); - - return_ACPI_STATUS(AE_OK); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bm_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bm_osl.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bm_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bm_osl.c Wed Dec 31 16:00:00 1969 @@ -1,390 +0,0 @@ -/***************************************************************************** - * - * Module Name: bm_osl.c - * $Revision: 17 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bm.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI Bus Manager"); -MODULE_LICENSE("GPL"); - - -/***************************************************************************** - * Types & Defines - *****************************************************************************/ - -typedef struct -{ - BM_HANDLE device_handle; - char *device_type; - char *device_instance; - u32 event_type; - u32 event_data; - struct list_head list; -} BM_OSL_EVENT; - - -#define BM_PROC_ROOT "acpi" -#define BM_PROC_EVENT "event" -#define BM_PROC_DEVICES "devices" - -#define BM_MAX_STRING_LENGTH 80 - - -/**************************************************************************** - * Globals - ****************************************************************************/ - -struct proc_dir_entry *bm_proc_root = NULL; -static struct proc_dir_entry *bm_proc_event = NULL; - -#ifdef ACPI_DEBUG -static u32 save_dbg_layer; -static u32 save_dbg_level; -#endif /*ACPI_DEBUG*/ - -extern BM_NODE_LIST node_list; - -static spinlock_t bm_osl_event_lock = SPIN_LOCK_UNLOCKED; - -static LIST_HEAD(bm_event_list); - -static DECLARE_WAIT_QUEUE_HEAD(bm_event_wait_queue); - -static int event_is_open = 0; - - -/**************************************************************************** - * Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_osl_generate_event - * - * DESCRIPTION: Generates an event for user-space consumption by writing - * the event data to the 'event' file. - * - ****************************************************************************/ - -acpi_status -bm_osl_generate_event ( - BM_HANDLE device_handle, - char *device_type, - char *device_instance, - u32 event_type, - u32 event_data) -{ - BM_OSL_EVENT *event = NULL; - u32 flags = 0; - - /* drop event on the floor if no one's listening */ - if (!event_is_open) - return (AE_OK); - - /* - * Allocate a new event structure. - */ - event = acpi_os_callocate(sizeof(BM_OSL_EVENT)); - if (!event) - goto alloc_error; - - event->device_type = acpi_os_callocate(strlen(device_type) - + sizeof(char)); - if (!event->device_type) - goto alloc_error; - - event->device_instance = acpi_os_callocate(strlen(device_instance) - + sizeof(char)); - if (!event->device_instance) - goto alloc_error; - - /* - * Set event data. - */ - event->device_handle = device_handle; - strcpy(event->device_type, device_type); - strcpy(event->device_instance, device_instance); - event->event_type = event_type; - event->event_data = event_data; - - /* - * Add to the end of our event list. - */ - spin_lock_irqsave(&bm_osl_event_lock, flags); - list_add_tail(&event->list, &bm_event_list); - spin_unlock_irqrestore(&bm_osl_event_lock, flags); - - /* - * Signal waiting threads (if any). - */ - wake_up_interruptible(&bm_event_wait_queue); - - return(AE_OK); - -alloc_error: - if (event->device_instance) - acpi_os_free(event->device_instance); - - if (event->device_type) - acpi_os_free(event->device_type); - - if (event) - acpi_os_free(event); - - return (AE_NO_MEMORY); -} - -static int bm_osl_open_event(struct inode *inode, struct file *file) -{ - spin_lock_irq (&bm_osl_event_lock); - - if(event_is_open) - goto out_busy; - - event_is_open = 1; - - spin_unlock_irq (&bm_osl_event_lock); - return 0; - -out_busy: - spin_unlock_irq (&bm_osl_event_lock); - return -EBUSY; -} - - -static int bm_osl_close_event(struct inode *inode, struct file *file) -{ - event_is_open = 0; - return 0; -} - -/**************************************************************************** - * - * FUNCTION: bm_osl_read_event - * - * DESCRIPTION: Handles reads to the 'event' file by blocking user-mode - * threads until data (an event) is generated. - * - ****************************************************************************/ -static ssize_t -bm_osl_read_event( - struct file *file, - char *buf, - size_t count, - loff_t *ppos) -{ - BM_OSL_EVENT *event = NULL; - unsigned long flags = 0; - static char str[BM_MAX_STRING_LENGTH]; - static int chars_remaining = 0; - static char *ptr; - - if (!chars_remaining) { - DECLARE_WAITQUEUE(wait, current); - - if (list_empty(&bm_event_list)) { - - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&bm_event_wait_queue, &wait); - - if (list_empty(&bm_event_list)) { - schedule(); - } - - remove_wait_queue(&bm_event_wait_queue, &wait); - set_current_state(TASK_RUNNING); - - if (signal_pending(current)) { - return -ERESTARTSYS; - } - } - - spin_lock_irqsave(&bm_osl_event_lock, flags); - event = list_entry(bm_event_list.next, BM_OSL_EVENT, list); - list_del(&event->list); - spin_unlock_irqrestore(&bm_osl_event_lock, flags); - - chars_remaining = sprintf(str, "%s %s %08x %08x\n", - event->device_type, event->device_instance, - event->event_type, event->event_data); - ptr = str; - - acpi_os_free(event->device_type); - acpi_os_free(event->device_instance); - acpi_os_free(event); - } - - if (chars_remaining < count) - count = chars_remaining; - - if (copy_to_user(buf, ptr, count)) - return -EFAULT; - - *ppos += count; - chars_remaining -= count; - ptr += count; - - return count; -} - -/**************************************************************************** - * - * FUNCTION: bm_osl_poll_event - * - * DESCRIPTION: Handles poll() of the 'event' file by blocking user-mode - * threads until data (an event) is generated. - * - ****************************************************************************/ -static unsigned int -bm_osl_poll_event( - struct file *file, - poll_table *wait) -{ - poll_wait(file, &bm_event_wait_queue, wait); - if (!list_empty(&bm_event_list)) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations proc_event_operations = { - open: bm_osl_open_event, - read: bm_osl_read_event, - release: bm_osl_close_event, - poll: bm_osl_poll_event, -}; - -/**************************************************************************** - * - * FUNCTION: bm_osl_init - * - ****************************************************************************/ - -int -bm_osl_init(void) -{ - acpi_status status = AE_OK; - - status = acpi_subsystem_status(); - if (ACPI_FAILURE(status)) - return -ENODEV; - - bm_proc_root = proc_mkdir(BM_PROC_ROOT, NULL); - if (!bm_proc_root) { - return(AE_ERROR); - } - - bm_proc_event = create_proc_entry(BM_PROC_EVENT, S_IRUSR, bm_proc_root); - if (bm_proc_event) { - bm_proc_event->proc_fops = &proc_event_operations; - } - - status = bm_initialize(); - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - - -/**************************************************************************** - * - * FUNCTION: bm_osl_cleanup - * - ****************************************************************************/ - -void -bm_osl_cleanup(void) -{ - bm_terminate(); - - if (bm_proc_event) { - remove_proc_entry(BM_PROC_EVENT, bm_proc_root); - bm_proc_event = NULL; - } - - if (bm_proc_root) { - remove_proc_entry(BM_PROC_ROOT, NULL); - bm_proc_root = NULL; - } - - return; -} - - -module_init(bm_osl_init); -module_exit(bm_osl_cleanup); - - -/**************************************************************************** - * Symbols - ****************************************************************************/ - -/* bm.c */ - -EXPORT_SYMBOL(bm_get_node); - -/* bmdriver.c */ - -EXPORT_SYMBOL(bm_get_device_power_state); -EXPORT_SYMBOL(bm_set_device_power_state); -EXPORT_SYMBOL(bm_get_device_info); -EXPORT_SYMBOL(bm_get_device_status); -EXPORT_SYMBOL(bm_get_device_context); -EXPORT_SYMBOL(bm_register_driver); -EXPORT_SYMBOL(bm_unregister_driver); - -/* bmsearch.c */ - -EXPORT_SYMBOL(bm_search); - -/* bmrequest.c */ - -EXPORT_SYMBOL(bm_request); - -/* bmutils.c */ - -EXPORT_SYMBOL(bm_extract_package_data); -EXPORT_SYMBOL(bm_evaluate_object); -EXPORT_SYMBOL(bm_evaluate_simple_integer); -EXPORT_SYMBOL(bm_evaluate_reference_list); -EXPORT_SYMBOL(bm_copy_to_buffer); -EXPORT_SYMBOL(bm_cast_buffer); - -/* bm_proc.c */ - -EXPORT_SYMBOL(bm_osl_generate_event); -EXPORT_SYMBOL(bm_proc_root); diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bmdriver.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmdriver.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bmdriver.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmdriver.c Wed Dec 31 16:00:00 1969 @@ -1,469 +0,0 @@ -/***************************************************************************** - * - * Module Name: bmdriver.c - * $Revision: 21 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "bm.h" - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bmdriver") - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_get_device_power_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_device_power_state ( - BM_HANDLE device_handle, - BM_POWER_STATE *state) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_get_device_power_state"); - - if (!state) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - *state = ACPI_STATE_UNKNOWN; - - /* - * Resolve device handle to node. - */ - status = bm_get_node(device_handle, 0, &node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Get the current power state. - */ - status = bm_get_power_state(node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - *state = node->device.power.state; - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_set_device_power_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_set_device_power_state ( - BM_HANDLE device_handle, - BM_POWER_STATE state) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_set_device_power_state"); - - /* - * Resolve device handle to node. - */ - status = bm_get_node(device_handle, 0, &node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Set the current power state. - */ - status = bm_set_power_state(node, state); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_device_status - * - * PARAMETERS: - * device_handle is really an index number into the array of BM_DEVICE - * structures in info_list. This data item is passed to - * the registered program's "notify" callback. It is used - * to retrieve the specific BM_DEVICE structure instance - * associated with the callback. - * device_status is a pointer that receives the result of processing - * the device's associated ACPI _STA. - * - * RETURN: - * The acpi_status value indicates success AE_OK or failure of the function - * - * DESCRIPTION: Evaluates the device's ACPI _STA, if it is present. - * - ****************************************************************************/ - -acpi_status -bm_get_device_status ( - BM_HANDLE device_handle, - BM_DEVICE_STATUS *device_status) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_get_device_status"); - - if (!device_status) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - *device_status = BM_STATUS_UNKNOWN; - - /* - * Resolve device handle to node. - */ - status = bm_get_node(device_handle, 0, &node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Parent Present? - * --------------- - * If the parent isn't present we can't evalute _STA on the child. - * Return an unknown status. - */ - if (!BM_NODE_PRESENT(node->parent)) { - return_ACPI_STATUS(AE_OK); - } - - /* - * Dynamic Status? - * --------------- - * If _STA isn't present we just return the default status. - */ - if (!(node->device.flags & BM_FLAGS_DYNAMIC_STATUS)) { - *device_status = BM_STATUS_DEFAULT; - return_ACPI_STATUS(AE_OK); - } - - /* - * Evaluate _STA: - * -------------- - */ - status = bm_evaluate_simple_integer(node->device.acpi_handle, "_STA", - &(node->device.status)); - if (ACPI_SUCCESS(status)) { - *device_status = node->device.status; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_device_info - * - * PARAMETERS: - * device_handle An index used to retrieve the associated BM_DEVICE info. - * device A pointer to a BM_DEVICE structure instance pointer. - * This pointed to BM_DEVICE structure will contain the - * this device's information. - * - * RETURN: - * The acpi_status value indicates success AE_OK or failure of the function - * - * DESCRIPTION: - * Using the device_handle this function retrieves this device's - * BM_DEVICE structure instance and save's it in device. - * - ****************************************************************************/ - -acpi_status -bm_get_device_info ( - BM_HANDLE device_handle, - BM_DEVICE **device) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_get_device_info"); - - if (!device) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Resolve device handle to internal device. - */ - status = bm_get_node(device_handle, 0, &node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - *device = &(node->device); - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_device_context - * - * device_handle An index used to retrieve the associated BM_DEVICE info. - * context A pointer to a BM_DRIVER_CONTEXT structure instance. - * - * RETURN: - * The acpi_status value indicates success AE_OK or failure of the function - * - * DESCRIPTION: - * Using the device_handle this function retrieves this device's - * BM_DRIVER_CONTEXT structure instance and save's it in context. - * - ****************************************************************************/ - -acpi_status -bm_get_device_context ( - BM_HANDLE device_handle, - BM_DRIVER_CONTEXT *context) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_get_device_context"); - - if (!context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - *context = NULL; - - /* - * Resolve device handle to internal device. - */ - status = bm_get_node(device_handle, 0, &node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - if (!node->driver.context) { - return_ACPI_STATUS(AE_NULL_ENTRY); - } - - *context = node->driver.context; - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_register_driver - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_register_driver ( - BM_DEVICE_ID *criteria, - BM_DRIVER *driver) -{ - acpi_status status = AE_NOT_FOUND; - BM_HANDLE_LIST device_list; - BM_NODE *node = NULL; - BM_DEVICE *device = NULL; - u32 i = 0; - - FUNCTION_TRACE("bm_register_driver"); - - if (!criteria || !driver || !driver->notify || !driver->request) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(&device_list, 0, sizeof(BM_HANDLE_LIST)); - - /* - * Find Matches: - * ------------- - * Search through the entire device hierarchy for matches against - * the given device criteria. - */ - status = bm_search(BM_HANDLE_ROOT, criteria, &device_list); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Install driver: - * ---------------- - * For each match, record the driver information and execute the - * driver's Notify() funciton (if present) to notify the driver - * of the device's presence. - */ - for (i = 0; i < device_list.count; i++) { - - /* Resolve the device handle. */ - status = bm_get_node(device_list.handles[i], 0, &node); - if (ACPI_FAILURE(status)) { - continue; - } - - device = &(node->device); - - /* - * Make sure another driver hasn't already registered for - * this device. - */ - if (BM_IS_DRIVER_CONTROL(device)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Another driver has already registered for device [%02x].\n", device->handle)); - continue; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Registering driver for device [%02x].\n", device->handle)); - - /* Notify driver of new device. */ - status = driver->notify(BM_NOTIFY_DEVICE_ADDED, - node->device.handle, &(node->driver.context)); - if (ACPI_SUCCESS(status)) { - node->driver.notify = driver->notify; - node->driver.request = driver->request; - node->device.flags |= BM_FLAGS_DRIVER_CONTROL; - } - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_unregister_driver - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_unregister_driver ( - BM_DEVICE_ID *criteria, - BM_DRIVER *driver) -{ - acpi_status status = AE_NOT_FOUND; - BM_HANDLE_LIST device_list; - BM_NODE *node = NULL; - BM_DEVICE *device = NULL; - u32 i = 0; - - FUNCTION_TRACE("bm_unregister_driver"); - - if (!criteria || !driver || !driver->notify || !driver->request) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(&device_list, 0, sizeof(BM_HANDLE_LIST)); - - /* - * Find Matches: - * ------------- - * Search through the entire device hierarchy for matches against - * the given device criteria. - */ - status = bm_search(BM_HANDLE_ROOT, criteria, &device_list); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Remove driver: - * --------------- - * For each match, execute the driver's Notify() function to allow - * the driver to cleanup each device instance. - */ - for (i = 0; i < device_list.count; i++) { - - /* Resolve the device handle. */ - status = bm_get_node(device_list.handles[i], 0, &node); - if (ACPI_FAILURE(status)) { - continue; - } - - device = &(node->device); - - /* - * Make sure driver has really registered for this device. - */ - if (!BM_IS_DRIVER_CONTROL(device)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Driver hasn't registered for device [%02x].\n", device->handle)); - continue; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unregistering driver for device [%02x].\n", device->handle)); - - /* Notify driver of device removal. */ - status = node->driver.notify(BM_NOTIFY_DEVICE_REMOVED, - node->device.handle, &(node->driver.context)); - if (ACPI_SUCCESS(status)) { - node->driver.notify = NULL; - node->driver.request = NULL; - node->driver.context = NULL; - node->device.flags &= ~BM_FLAGS_DRIVER_CONTROL; - } - } - - return_ACPI_STATUS(AE_OK); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bmnotify.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmnotify.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bmnotify.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmnotify.c Wed Dec 31 16:00:00 1969 @@ -1,312 +0,0 @@ -/***************************************************************************** - * - * Module Name: bmnotify.c - * $Revision: 21 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "bm.h" - - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bmnotify") - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_generate_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_generate_notify ( - BM_NODE *node, - u32 notify_type) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - - FUNCTION_TRACE("bm_generate_notify"); - - if (!node) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - device = &(node->device); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Sending notify [%02x] to device [%02x].\n", notify_type, node->device.handle)); - - if (!BM_IS_DRIVER_CONTROL(device)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "No driver installed for device [%02x].\n", device->handle)); - return_ACPI_STATUS(AE_NOT_EXIST); - } - - status = node->driver.notify(notify_type, node->device.handle, - &(node->driver.context)); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_device_check - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_device_check ( - BM_NODE *node, - u32 *status_change) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - BM_DEVICE_STATUS old_status = BM_STATUS_UNKNOWN; - - FUNCTION_TRACE("bm_device_check"); - - if (!node) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - device = &(node->device); - - if (status_change) { - *status_change = FALSE; - } - - old_status = device->status; - - /* - * Parent Present? - * --------------- - * Only check this device if its parent is present (which implies - * this device MAY be present). - */ - if (!BM_NODE_PRESENT(node->parent)) { - return_ACPI_STATUS(AE_OK); - } - - /* - * Get Status: - * ----------- - * And see if the status has changed. - */ - status = bm_get_status(device); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - if (old_status == node->device.status) { - return_ACPI_STATUS(AE_OK); - } - - if (status_change) { - *status_change = TRUE; - } - - /* - * Device Insertion? - * ----------------- - */ - if ((device->status & BM_STATUS_PRESENT) && - !(old_status & BM_STATUS_PRESENT)) { - /* TBD: Make sure driver is loaded, and if not, load. */ - status = bm_generate_notify(node, BM_NOTIFY_DEVICE_ADDED); - } - - /* - * Device Removal? - * --------------- - */ - else if (!(device->status & BM_STATUS_PRESENT) && - (old_status & BM_STATUS_PRESENT)) { - /* TBD: Unload driver if last device instance. */ - status = bm_generate_notify(node, BM_NOTIFY_DEVICE_REMOVED); - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_bus_check - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_bus_check ( - BM_NODE *parent_node) -{ - acpi_status status = AE_OK; - u32 status_change = FALSE; - - FUNCTION_TRACE("bm_bus_check"); - - if (!parent_node) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Status Change? - * -------------- - */ - status = bm_device_check(parent_node, &status_change); - if (ACPI_FAILURE(status) || !status_change) { - return_ACPI_STATUS(status); - } - - /* - * Enumerate Scope: - * ---------------- - * TBD: Enumerate child devices within this device's scope and - * run bm_device_check()'s on them... - */ - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -bm_notify ( - acpi_handle acpi_handle, - u32 notify_value, - void *context) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_notify"); - - /* - * Resolve the ACPI handle. - */ - status = bm_get_node(0, acpi_handle, &node); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Recieved notify [%02x] for unknown device [%p].\n", notify_value, acpi_handle)); - return_VOID; - } - - /* - * Device-Specific or Standard? - * ---------------------------- - * Device-specific notifies are forwarded to the control module's - * notify() function for processing. Standard notifies are handled - * internally. - */ - if (notify_value > 0x7F) { - status = bm_generate_notify(node, notify_value); - } - else { - switch (notify_value) { - - case BM_NOTIFY_BUS_CHECK: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received BUS CHECK notification for device [%02x].\n", node->device.handle)); - status = bm_bus_check(node); - break; - - case BM_NOTIFY_DEVICE_CHECK: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received DEVICE CHECK notification for device [%02x].\n", node->device.handle)); - status = bm_device_check(node, NULL); - break; - - case BM_NOTIFY_DEVICE_WAKE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received DEVICE WAKE notification for device [%02x].\n", node->device.handle)); - /* TBD */ - break; - - case BM_NOTIFY_EJECT_REQUEST: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received EJECT REQUEST notification for device [%02x].\n", node->device.handle)); - /* TBD */ - break; - - case BM_NOTIFY_DEVICE_CHECK_LIGHT: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received DEVICE CHECK LIGHT notification for device [%02x].\n", node->device.handle)); - /* TBD: Exactly what does the 'light' mean? */ - status = bm_device_check(node, NULL); - break; - - case BM_NOTIFY_FREQUENCY_MISMATCH: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received FREQUENCY MISMATCH notification for device [%02x].\n", node->device.handle)); - /* TBD */ - break; - - case BM_NOTIFY_BUS_MODE_MISMATCH: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received BUS MODE MISMATCH notification for device [%02x].\n", node->device.handle)); - /* TBD */ - break; - - case BM_NOTIFY_POWER_FAULT: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received POWER FAULT notification.\n")); - /* TBD */ - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received unknown/unsupported notification.\n")); - break; - } - } - - return_VOID; -} - - diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bmpm.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmpm.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bmpm.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmpm.c Wed Dec 31 16:00:00 1969 @@ -1,442 +0,0 @@ -/***************************************************************************** - * - * Module Name: bmpm.c - * $Revision: 14 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "bm.h" -#include "bmpower.h" - - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bmpm") - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_get_inferred_power_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_inferred_power_state ( - BM_DEVICE *device) -{ - acpi_status status = AE_OK; - BM_HANDLE_LIST pr_list; - BM_POWER_STATE list_state = ACPI_STATE_UNKNOWN; - char object_name[5] = {'_','P','R','0','\0'}; - u32 i = 0; - - FUNCTION_TRACE("bm_get_inferred_power_state"); - - if (!device) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(&pr_list, 0, sizeof(BM_HANDLE_LIST)); - - device->power.state = ACPI_STATE_D3; - - /* - * Calculate Power State: - * ---------------------- - * Try to infer the devices's power state by checking the state of - * the devices's power resources. We start by evaluating _PR0 - * (resource requirements at D0) and work through _PR1 and _PR2. - * We know the current devices power state when all resources (for - * a give Dx state) are ON. If no power resources are on then the - * device is assumed to be off (D3). - */ - for (i=ACPI_STATE_D0; iacpi_handle, - object_name, &pr_list); - - if (ACPI_SUCCESS(status)) { - - status = bm_pr_list_get_state(&pr_list, &list_state); - - if (ACPI_SUCCESS(status)) { - - if (list_state == ACPI_STATE_D0) { - device->power.state = i; - break; - } - } - } - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_get_power_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_power_state ( - BM_NODE *node) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - - FUNCTION_TRACE("bm_get_power_state"); - - if (!node || !node->parent) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - device = &(node->device); - - device->power.state = ACPI_STATE_UNKNOWN; - - /* - * Power Control? - * -------------- - * If this device isn't directly power manageable (e.g. doesn't - * include _PR0/_PS0) then there's nothing to do (state is static). - */ - if (!BM_IS_POWER_CONTROL(device)) { - return_ACPI_STATUS(AE_OK); - } - - /* - * Parent Present? - * --------------- - * Make sure the parent is present before mucking with the child. - */ - if (!BM_NODE_PRESENT(node->parent)) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* - * Get Power State: - * ---------------- - * Either directly (via _PSC) or inferred (via power resource - * dependencies). - */ - if (BM_IS_POWER_STATE(device)) { - status = bm_evaluate_simple_integer(device->acpi_handle, - "_PSC", &(device->power.state)); - } - else { - status = bm_get_inferred_power_state(device); - } - - if (ACPI_SUCCESS(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Device [%02x] is at power state [D%d].\n", device->handle, device->power.state)); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Error getting power state for device [%02x]\n", device->handle)); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_set_power_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_set_power_state ( - BM_NODE *node, - BM_POWER_STATE state) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - BM_DEVICE *parent_device = NULL; - BM_HANDLE_LIST current_list; - BM_HANDLE_LIST target_list; - char object_name[5] = {'_','P','R','0','\0'}; - - FUNCTION_TRACE("bm_set_power_state"); - - if (!node || !node->parent || (state > ACPI_STATE_D3)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(¤t_list, 0, sizeof(BM_HANDLE_LIST)); - MEMSET(&target_list, 0, sizeof(BM_HANDLE_LIST)); - - device = &(node->device); - parent_device = &(node->parent->device); - - /* - * Power Control? - * -------------- - * If this device isn't directly power manageable (e.g. doesn't - * include _PR0/_PS0) then return an error (can't set state). - */ - if (!BM_IS_POWER_CONTROL(device)) { - return_ACPI_STATUS(AE_ERROR); - } - - /* - * Parent Present? - * --------------- - * Make sure the parent is present before mucking with the child. - */ - if (!BM_NODE_PRESENT(node->parent)) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* - * Check Parent's Power State: - * --------------------------- - * Can't be in a higher power state (lower Dx value) than parent. - */ - if (state < parent_device->power.state) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Cannot set device [%02x] to a higher-powered state than parent_device.\n", device->handle)); - return_ACPI_STATUS(AE_ERROR); - } - - /* - * Get Resources: - * -------------- - * Get the power resources associated with the device's current - * and target power states. - */ - if (device->power.state != ACPI_STATE_UNKNOWN) { - object_name[3] = '0' + device->power.state; - bm_evaluate_reference_list(device->acpi_handle, - object_name, ¤t_list); - } - - object_name[3] = '0' + state; - bm_evaluate_reference_list(device->acpi_handle, object_name, - &target_list); - - /* - * Transition Resources: - * --------------------- - * Transition all power resources referenced by this device to - * the correct power state (taking into consideration sequencing - * and dependencies to other devices). - */ - if (current_list.count || target_list.count) { - status = bm_pr_list_transition(¤t_list, &target_list); - } - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Execute _PSx: - * ------------- - * Execute the _PSx method corresponding to the target Dx state, - * if it exists. - */ - object_name[2] = 'S'; - object_name[3] = '0' + state; - bm_evaluate_object(device->acpi_handle, object_name, NULL, NULL); - - if (ACPI_SUCCESS(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Device [%02x] is now at [D%d].\n", device->handle, state)); - device->power.state = state; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_get_pm_capabilities - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_get_pm_capabilities ( - BM_NODE *node) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - BM_DEVICE *parent_device = NULL; - acpi_handle acpi_handle = NULL; - BM_POWER_STATE dx_supported = ACPI_STATE_UNKNOWN; - char object_name[5] = {'_','S','0','D','\0'}; - u32 i = 0; - - FUNCTION_TRACE("bm_get_pm_capabilities"); - - if (!node || !node->parent) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - device = &(node->device); - parent_device = &(node->parent->device); - - /* - * Power Management Flags: - * ----------------------- - */ - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PSC", - &acpi_handle))) { - device->power.flags |= BM_FLAGS_POWER_STATE; - } - - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_IRC", - &acpi_handle))) { - device->power.flags |= BM_FLAGS_INRUSH_CURRENT; - } - - if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PRW", - &acpi_handle))) { - device->power.flags |= BM_FLAGS_WAKE_CAPABLE; - } - - /* - * Device Power State: - * ------------------- - * Note that we can't get the device's power state until we've - * initialized all power resources, so for now we just set to - * unknown. - */ - device->power.state = ACPI_STATE_UNKNOWN; - - /* - * Dx Supported in S0: - * ------------------- - * Figure out which Dx states are supported by this device for the - * S0 (working) state. Note that D0 and D3 are required (assumed). - */ - device->power.dx_supported[ACPI_STATE_S0] = BM_FLAGS_D0_SUPPORT | - BM_FLAGS_D3_SUPPORT; - - if ((ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PR1", - &acpi_handle))) || - (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PS1", - &acpi_handle)))) { - device->power.dx_supported[ACPI_STATE_S0] |= - BM_FLAGS_D1_SUPPORT; - } - - if ((ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PR2", - &acpi_handle))) || - (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PS2", - &acpi_handle)))) { - device->power.dx_supported[ACPI_STATE_S0] |= - BM_FLAGS_D2_SUPPORT; - } - - /* - * Dx Supported in S1-S5: - * ---------------------- - * Figure out which Dx states are supported by this device for - * all other Sx states. - */ - for (i = ACPI_STATE_S1; i <= ACPI_STATE_S5; i++) { - - /* - * D3 support is assumed (off is always possible!). - */ - device->power.dx_supported[i] = BM_FLAGS_D3_SUPPORT; - - /* - * Evalute _Sx_d: - * ------------- - * Which returns the highest (power) Dx state supported in - * this system (Sx) state. We convert this value to a bit - * mask of supported states (conceptually simpler). - */ - status = bm_evaluate_simple_integer(device->acpi_handle, - object_name, &dx_supported); - if (ACPI_SUCCESS(status)) { - switch (dx_supported) { - case 0: - device->power.dx_supported[i] |= - BM_FLAGS_D0_SUPPORT; - /* fall through */ - case 1: - device->power.dx_supported[i] |= - BM_FLAGS_D1_SUPPORT; - /* fall through */ - case 2: - device->power.dx_supported[i] |= - BM_FLAGS_D2_SUPPORT; - /* fall through */ - case 3: - device->power.dx_supported[i] |= - BM_FLAGS_D3_SUPPORT; - break; - } - - /* - * Validate: - * --------- - * Mask of any states that _Sx_d falsely advertises - * (e.g.claims D1 support but neither _PR2 or _PS2 - * exist). In other words, S1-S5 can't offer a Dx - * state that isn't supported by S0. - */ - device->power.dx_supported[i] &= - device->power.dx_supported[ACPI_STATE_S0]; - } - - object_name[2]++; - } - - return_ACPI_STATUS(AE_OK); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bmpower.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmpower.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bmpower.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmpower.c Wed Dec 31 16:00:00 1969 @@ -1,664 +0,0 @@ -/**************************************************************************** - * - * Module Name: bmpower.c - Driver for ACPI Power Resource 'devices' - * $Revision: 20 $ - * - ****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * TBD: 1. Sequencing of power resource list transitions. - * 2. Global serialization of power resource transtions (see ACPI - * spec section 7.1.2/7.1.3). - * 3. Better error handling. - */ - - -#include -#include "bm.h" -#include "bmpower.h" - - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bmpower") - - -/**************************************************************************** - * Function Prototypes - ****************************************************************************/ - -acpi_status -bm_pr_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context); - -acpi_status -bm_pr_request ( - BM_REQUEST *request, - void *context); - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_pr_print - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_print ( - BM_POWER_RESOURCE *pr) -{ - acpi_buffer buffer; - - PROC_NAME("bm_pr_print"); - - if (!pr) { - return(AE_BAD_PARAMETER); - } - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return(AE_NO_MEMORY); - } - - acpi_get_name(pr->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - acpi_os_printf("Power Resource: found\n"); - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Power_resource[%02x]:[%p] %s\n", pr->device_handle, pr->acpi_handle, (char*)buffer.pointer)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| system_level[S%d] resource_order[%d]\n", pr->system_level, pr->resource_order)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| state[D%d] reference_count[%d]\n", pr->state, pr->reference_count)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_get_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_get_state ( - BM_POWER_RESOURCE *pr) -{ - acpi_status status = AE_OK; - BM_DEVICE_STATUS device_status = BM_STATUS_UNKNOWN; - - FUNCTION_TRACE("bm_pr_get_state"); - - if (!pr) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - pr->state = ACPI_STATE_UNKNOWN; - - /* - * Evaluate _STA: - * -------------- - * Evalute _STA to determine whether the power resource is ON or OFF. - * Note that if the power resource isn't present we'll get AE_OK but - * an unknown status. - */ - status = bm_get_device_status(pr->device_handle, &device_status); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Error reading status for power resource [%02x].\n", pr->device_handle)); - return_ACPI_STATUS(status); - } - - /* - * Mask off all bits but the first as some systems return non-standard - * values (e.g. 0x51). - */ - switch (device_status & 0x01) { - case 0: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Power resource [%02x] is OFF.\n", pr->device_handle)); - pr->state = ACPI_STATE_D3; - break; - case 1: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Power resource [%02x] is ON.\n", pr->device_handle)); - pr->state = ACPI_STATE_D0; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_set_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_set_state ( - BM_POWER_RESOURCE *pr, - BM_POWER_STATE target_state) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bm_pr_set_state"); - - if (!pr) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - status = bm_pr_get_state(pr); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - if (target_state == pr->state) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Power resource [%02x] already at target power state [D%d].\n", pr->device_handle, pr->state)); - return_ACPI_STATUS(AE_OK); - } - - switch (target_state) { - - case ACPI_STATE_D0: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Turning power resource [%02x] ON.\n", pr->device_handle)); - status = bm_evaluate_object(pr->acpi_handle, "_ON", NULL, NULL); - break; - - case ACPI_STATE_D3: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Turning power resource [%02x] OFF.\n", pr->device_handle)); - status = bm_evaluate_object(pr->acpi_handle, "_OFF", NULL, NULL); - break; - - default: - status = AE_BAD_PARAMETER; - break; - } - - status = bm_pr_get_state(pr); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_list_get_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_list_get_state ( - BM_HANDLE_LIST *pr_list, - BM_POWER_STATE *power_state) -{ - acpi_status status = AE_OK; - BM_POWER_RESOURCE *pr = NULL; - u32 i = 0; - - FUNCTION_TRACE("bm_pr_list_get_state"); - - if (!pr_list || !power_state) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (pr_list->count < 1) { - pr->state = ACPI_STATE_UNKNOWN; - return_ACPI_STATUS(AE_ERROR); - } - - (*power_state) = ACPI_STATE_D0; - - /* - * Calculate Current power_state: - * ----------------------------- - * The current state of a list of power resources is ON if all - * power resources are currently in the ON state. In other words, - * if any power resource in the list is OFF then the collection - * isn't fully ON. - */ - for (i = 0; i < pr_list->count; i++) { - - status = bm_get_device_context(pr_list->handles[i], - (BM_DRIVER_CONTEXT*)(&pr)); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Invalid reference to power resource [%02x].\n", pr_list->handles[i])); - (*power_state) = ACPI_STATE_UNKNOWN; - break; - } - - status = bm_pr_get_state(pr); - if (ACPI_FAILURE(status)) { - (*power_state) = ACPI_STATE_UNKNOWN; - break; - } - - if (pr->state != ACPI_STATE_D0) { - (*power_state) = pr->state; - break; - } - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_list_transition - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_list_transition ( - BM_HANDLE_LIST *current_list, - BM_HANDLE_LIST *target_list) -{ - acpi_status status = AE_OK; - BM_POWER_RESOURCE *pr = NULL; - u32 i = 0; - - FUNCTION_TRACE("bm_pr_list_transition"); - - if (!current_list || !target_list) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Reference Target: - * ----------------- - * Reference all resources for the target power state first (so - * the device doesn't get turned off while transitioning). Power - * resources that aren't on (new reference count of 1) are turned on. - */ - for (i = 0; i < target_list->count; i++) { - - status = bm_get_device_context(target_list->handles[i], - (BM_DRIVER_CONTEXT*)(&pr)); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Invalid reference to power resource [%02x].\n", target_list->handles[i])); - continue; - } - - if (++pr->reference_count == 1) { - /* TBD: Need ordering based upon resource_order */ - status = bm_pr_set_state(pr, ACPI_STATE_D0); - if (ACPI_FAILURE(status)) { - /* TBD: How do we handle this? */ - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to change power state for power resource [%02x].\n", target_list->handles[i])); - } - } - } - - /* - * Dereference Current: - * -------------------- - * Dereference all resources for the current power state. Power - * resources no longer referenced (new reference count of 0) are - * turned off. - */ - for (i = 0; i < current_list->count; i++) { - - status = bm_get_device_context(current_list->handles[i], - (BM_DRIVER_CONTEXT*)(&pr)); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Invalid reference to power resource [%02x].\n", target_list->handles[i])); - continue; - } - - if (--pr->reference_count == 0) { - /* TBD: Need ordering based upon resource_order */ - status = bm_pr_set_state(pr, ACPI_STATE_D3); - if (ACPI_FAILURE(status)) { - /* TBD: How do we handle this? */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unable to change power state for power resource [%02x].\n", current_list->handles[i])); - } - } - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_add_device ( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - BM_POWER_RESOURCE *pr = NULL; - BM_DEVICE *device = NULL; - acpi_buffer buffer; - acpi_object acpi_object; - - FUNCTION_TRACE("bm_pr_add_device"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding power resource [%02x].\n", device_handle)); - - if (!context || *context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - buffer.length = sizeof(acpi_object); - buffer.pointer = &acpi_object; - - /* - * Get information on this device. - */ - status = bm_get_device_info(device_handle, &device); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Allocate a new BM_POWER_RESOURCE structure. - */ - pr = acpi_os_callocate(sizeof(BM_POWER_RESOURCE)); - if (!pr) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - pr->device_handle = device->handle; - pr->acpi_handle = device->acpi_handle; - - /* - * Get information on this power resource. - */ - status = acpi_evaluate_object(pr->acpi_handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) { - goto end; - } - - pr->system_level = acpi_object.power_resource.system_level; - pr->resource_order = acpi_object.power_resource.resource_order; - pr->state = ACPI_STATE_UNKNOWN; - pr->reference_count = 0; - - /* - * Get the power resource's current state (ON|OFF). - */ - status = bm_pr_get_state(pr); - -end: - if (ACPI_FAILURE(status)) { - acpi_os_free(pr); - } - else { - *context = pr; - bm_pr_print(pr); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_remove_device ( - void **context) -{ - acpi_status status = AE_OK; - BM_POWER_RESOURCE *pr = NULL; - - FUNCTION_TRACE("bm_pr_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - pr = (BM_POWER_RESOURCE*)*context; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing power resource [%02x].\n", pr->device_handle)); - - acpi_os_free(pr); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_pr_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_initialize (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("bm_pr_initialize"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - criteria.type = BM_TYPE_POWER_RESOURCE; - - driver.notify = &bm_pr_notify; - driver.request = &bm_pr_request; - - status = bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_terminate - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_terminate (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("bm_pr_terminate"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - criteria.type = BM_TYPE_POWER_RESOURCE; - - driver.notify = &bm_pr_notify; - driver.request = &bm_pr_request; - - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bm_pr_notify"); - - switch (notify_type) { - - case BM_NOTIFY_DEVICE_ADDED: - status = bm_pr_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = bm_pr_remove_device(context); - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_pr_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_pr_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - BM_POWER_RESOURCE *pr = NULL; - - FUNCTION_TRACE("bm_pr_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * context contains information specific to this power resource. - */ - pr = (BM_POWER_RESOURCE*)context; - - /* - * Handle request: - * --------------- - */ - switch (request->command) { - - default: - status = AE_SUPPORT; - break; - } - - request->status = status; - - return_ACPI_STATUS(status); -} - - diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bmrequest.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmrequest.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bmrequest.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmrequest.c Wed Dec 31 16:00:00 1969 @@ -1,164 +0,0 @@ -/****************************************************************************** - * - * Module Name: bmrequest.c - * $Revision: 16 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "bm.h" - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bmrequest") - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_generate_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_generate_request ( - BM_NODE *node, - BM_REQUEST *request) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - - FUNCTION_TRACE("bm_generate_request"); - - if (!node || !request) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - device = &(node->device); - - if (!BM_IS_DRIVER_CONTROL(device)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No driver installed for device [%02x].\n", device->handle)); - return_ACPI_STATUS(AE_NOT_EXIST); - } - - status = node->driver.request(request, node->driver.context); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_request ( - BM_REQUEST *request) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - BM_DEVICE *device = NULL; - - FUNCTION_TRACE("bm_request"); - - /* - * Must have a valid request structure. - */ - if (!request) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Received request for device [%02x] command [%02x].\n", request->handle, request->command)); - - /* - * Resolve the node. - */ - status = bm_get_node(request->handle, 0, &node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - device = &(node->device); - - /* - * Device-Specific Request? - * ------------------------ - * If a device-specific command (>=0x80) forward this request to - * the appropriate driver. - */ - if (request->command & BM_COMMAND_DEVICE_SPECIFIC) { - status = bm_generate_request(node, request); - return_ACPI_STATUS(status); - } - - /* - * Bus-Specific Requests: - * ---------------------- - */ - switch (request->command) { - - case BM_COMMAND_GET_POWER_STATE: - status = bm_get_power_state(node); - if (ACPI_FAILURE(status)) { - break; - } - status = bm_copy_to_buffer(&(request->buffer), - &(device->power.state), sizeof(BM_POWER_STATE)); - break; - - case BM_COMMAND_SET_POWER_STATE: - { - BM_POWER_STATE *power_state = NULL; - - status = bm_cast_buffer(&(request->buffer), - (void**)&power_state, sizeof(BM_POWER_STATE)); - if (ACPI_FAILURE(status)) { - break; - } - status = bm_set_power_state(node, *power_state); - } - break; - - default: - status = AE_SUPPORT; - request->status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bmsearch.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmsearch.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bmsearch.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmsearch.c Wed Dec 31 16:00:00 1969 @@ -1,192 +0,0 @@ -/****************************************************************************** - * - * Module Name: bmsearch.c - * $Revision: 16 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "bm.h" - - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bmsearch") - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_compare - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_compare ( - BM_DEVICE *device, - BM_DEVICE_ID *criteria) -{ - if (!device || !criteria) { - return AE_BAD_PARAMETER; - } - - /* - * Present? - * -------- - * We're only going to match on devices that are present. - * TBD: Optimize in bm_search (don't have to call here). - */ - if (!BM_DEVICE_PRESENT(device)) { - return AE_NOT_FOUND; - } - - /* - * Type? - */ - if (criteria->type && (criteria->type != device->id.type)) { - return AE_NOT_FOUND; - } - - /* - * HID? - */ - if ((criteria->hid[0]) && (0 != STRNCMP(criteria->hid, - device->id.hid, sizeof(BM_DEVICE_HID)))) { - return AE_NOT_FOUND; - } - - /* - * ADR? - */ - if ((criteria->adr) && (criteria->adr != device->id.adr)) { - return AE_NOT_FOUND; - } - - return AE_OK; -} - - -/**************************************************************************** - * - * FUNCTION: bm_search - * - * PARAMETERS: - * - * RETURN: AE_BAD_PARAMETER- invalid input parameter - * AE_NOT_EXIST - start_device_handle doesn't exist - * AE_NOT_FOUND - no matches to Search_info.criteria found - * AE_OK - success - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_search( - BM_HANDLE device_handle, - BM_DEVICE_ID *criteria, - BM_HANDLE_LIST *results) -{ - acpi_status status = AE_OK; - BM_NODE *node = NULL; - - FUNCTION_TRACE("bm_search"); - - if (!criteria || !results) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - results->count = 0; - - /* - * Locate Starting Point: - * ---------------------- - * Locate the node in the hierarchy where we'll begin our search. - */ - status = bm_get_node(device_handle, 0, &node); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Parse Hierarchy: - * ---------------- - * Parse through the node hierarchy looking for matches. - */ - while (node && (results->count<=BM_HANDLES_MAX)) { - /* - * Depth-first: - * ------------ - * Searches are always performed depth-first. - */ - if (node->scope.head) { - status = bm_compare(&(node->device), criteria); - if (ACPI_SUCCESS(status)) { - results->handles[results->count++] = - node->device.handle; - } - node = node->scope.head; - } - - /* - * Now Breadth: - * ------------ - * Search all peers until scope is exhausted. - */ - else { - status = bm_compare(&(node->device), criteria); - if (ACPI_SUCCESS(status)) { - results->handles[results->count++] = - node->device.handle; - } - - /* - * Locate Next Device: - * ------------------- - * The next node is either a peer at this level - * (node->next is valid), or we work are way back - * up the tree until we either find a non-parsed - * peer or hit the top (node->parent is NULL). - */ - while (!node->next && node->parent) { - node = node->parent; - } - node = node->next; - } - } - - if (results->count == 0) { - return_ACPI_STATUS(AE_NOT_FOUND); - } - else { - return_ACPI_STATUS(AE_OK); - } -} - diff -Nur linux-2.4.19/drivers/acpi/ospm/busmgr/bmutils.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmutils.c --- linux-2.4.19/drivers/acpi/ospm/busmgr/bmutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/busmgr/bmutils.c Wed Dec 31 16:00:00 1969 @@ -1,611 +0,0 @@ -/***************************************************************************** - * - * Module Name: bmutils.c - * $Revision: 43 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "bm.h" - - -#define _COMPONENT ACPI_BUS - MODULE_NAME ("bmutils") - - -#ifdef ACPI_DEBUG -#define DEBUG_EVAL_ERROR(l,h,p,s) bm_print_eval_error(l,h,p,s) -#else -#define DEBUG_EVAL_ERROR(l,h,p,s) -#endif - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: bm_print_eval_error - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -bm_print_eval_error ( - u32 debug_level, - acpi_handle handle, - acpi_string pathname, - acpi_status status) -{ - acpi_buffer buffer; - acpi_status local_status; - - PROC_NAME("bm_print_eval_error"); - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - local_status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - if (ACPI_FAILURE(local_status)) { - ACPI_DEBUG_PRINT((ACPI_DEBUG_LEVEL(debug_level), "Evaluate object [%p], %s\n", handle, - acpi_format_exception(status))); - return; - } - - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate object [%s.%s], %s\n", (char*)buffer.pointer, pathname, - acpi_format_exception(status))); - } - else { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate object [%s], %s\n", (char*)buffer.pointer, - acpi_format_exception(status))); - } - - acpi_os_free(buffer.pointer); -} - - -/**************************************************************************** - * - * FUNCTION: bm_copy_to_buffer - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_copy_to_buffer ( - acpi_buffer *buffer, - void *data, - u32 length) -{ - FUNCTION_TRACE("bm_copy_to_buffer"); - - if (!buffer || (!buffer->pointer) || !data || (length == 0)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (length > buffer->length) { - buffer->length = length; - return_ACPI_STATUS(AE_BUFFER_OVERFLOW); - } - - buffer->length = length; - MEMCPY(buffer->pointer, data, length); - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_cast_buffer - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_cast_buffer ( - acpi_buffer *buffer, - void **pointer, - u32 length) -{ - FUNCTION_TRACE("bm_cast_buffer"); - - if (!buffer || !buffer->pointer || !pointer || length == 0) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (length > buffer->length) { - return_ACPI_STATUS(AE_BAD_DATA); - } - - *pointer = buffer->pointer; - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_extract_package_data - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_extract_package_data ( - acpi_object *package, - acpi_buffer *format, - acpi_buffer *buffer) -{ - u32 tail_offset = 0; - u32 size_required = 0; - char *format_string = NULL; - u32 format_count = 0; - u32 i = 0; - u8 *head = NULL; - u8 *tail = NULL; - - FUNCTION_TRACE("bm_extract_package_data"); - - if (!package || (package->type != ACPI_TYPE_PACKAGE) || (package->package.count < 1)) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'package' argument\n")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (!format || !format->pointer || (format->length < 1)) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'format' argument\n")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (!buffer) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'buffer' argument\n")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - format_count = (format->length/sizeof(char)) - 1; - if (format_count > package->package.count) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Format specifies more objects [%d] than exist in package [%d].", format_count, package->package.count)); - return_ACPI_STATUS(AE_BAD_DATA); - } - - format_string = (char*)format->pointer; - - /* - * Calculate size_required. - */ - for (i=0; ipackage.elements[i]); - - if (!element) { - return_ACPI_STATUS(AE_BAD_DATA); - } - - switch (element->type) { - - case ACPI_TYPE_INTEGER: - switch (format_string[i]) { - case 'N': - size_required += sizeof(acpi_integer); - tail_offset += sizeof(acpi_integer); - break; - case 'S': - size_required += sizeof(char*) + sizeof(acpi_integer) + sizeof(char); - tail_offset += sizeof(char*); - break; - default: - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d]: got number, expecing [%c].\n", i, format_string[i])); - return_ACPI_STATUS(AE_BAD_DATA); - break; - } - break; - - case ACPI_TYPE_STRING: - case ACPI_TYPE_BUFFER: - switch (format_string[i]) { - case 'S': - size_required += sizeof(char*) + (element->string.length * sizeof(char)) + sizeof(char); - tail_offset += sizeof(char*); - break; - case 'B': - size_required += sizeof(u8*) + (element->buffer.length * sizeof(u8)); - tail_offset += sizeof(u8*); - break; - default: - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d] got string/buffer, expecing [%c].\n", i, format_string[i])); - return_ACPI_STATUS(AE_BAD_DATA); - break; - } - break; - - case ACPI_TYPE_PACKAGE: - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unsupported element at index=%d\n", i)); - /* TBD: handle nested packages... */ - return_ACPI_STATUS(AE_SUPPORT); - break; - } - } - - /* - * Validate output buffer. - */ - if (buffer->length < size_required) { - buffer->length = size_required; - return_ACPI_STATUS(AE_BUFFER_OVERFLOW); - } - else if (buffer->length != size_required || !buffer->pointer) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - head = buffer->pointer; - tail = buffer->pointer + tail_offset; - - /* - * Extract package data. - */ - for (i=0; ipackage.elements[i]); - - switch (element->type) { - - case ACPI_TYPE_INTEGER: - switch (format_string[i]) { - case 'N': - *((acpi_integer*)head) = element->integer.value; - head += sizeof(acpi_integer); - break; - case 'S': - pointer = (u8**)head; - *pointer = tail; - *((acpi_integer*)tail) = element->integer.value; - head += sizeof(acpi_integer*); - tail += sizeof(acpi_integer); - /* NULL terminate string */ - *tail = (char)0; - tail += sizeof(char); - break; - default: - /* Should never get here */ - break; - } - break; - - case ACPI_TYPE_STRING: - case ACPI_TYPE_BUFFER: - switch (format_string[i]) { - case 'S': - pointer = (u8**)head; - *pointer = tail; - memcpy(tail, element->string.pointer, element->string.length); - head += sizeof(char*); - tail += element->string.length * sizeof(char); - /* NULL terminate string */ - *tail = (char)0; - tail += sizeof(char); - break; - case 'B': - pointer = (u8**)head; - *pointer = tail; - memcpy(tail, element->buffer.pointer, element->buffer.length); - head += sizeof(u8*); - tail += element->buffer.length * sizeof(u8); - break; - default: - /* Should never get here */ - break; - } - break; - - case ACPI_TYPE_PACKAGE: - /* TBD: handle nested packages... */ - default: - /* Should never get here */ - break; - } - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bm_evaluate_object - * - * PARAMETERS: - * - * RETURN: AE_OK - * AE_BUFFER_OVERFLOW Evaluated object returned data, but - * caller did not provide buffer. - * - * DESCRIPTION: Helper for acpi_evaluate_object that handles buffer - * allocation. Note that the caller is responsible for - * freeing buffer->pointer! - * - ****************************************************************************/ - -acpi_status -bm_evaluate_object ( - acpi_handle handle, - acpi_string pathname, - acpi_object_list *arguments, - acpi_buffer *buffer) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bm_evaluate_object"); - - /* If caller provided a buffer it must be unallocated/zero'd. */ - if ((buffer) && (buffer->length != 0 || buffer->pointer)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Evalute Object: - * --------------- - * The first attempt is just to get the size of the object data - * (that is unless there's no return data, e.g. _INI); the second - * gets the data. - */ - status = acpi_evaluate_object(handle, pathname, arguments, buffer); - if (ACPI_SUCCESS(status)) { - return_ACPI_STATUS(status); - } - else if ((buffer) && (status == AE_BUFFER_OVERFLOW)) { - - /* Gotta allocate -- CALLER MUST FREE! */ - buffer->pointer = acpi_os_callocate(buffer->length); - if (!buffer->pointer) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Re-evaluate -- this time it should work */ - status = acpi_evaluate_object(handle, pathname, - arguments, buffer); - } - - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - DEBUG_EVAL_ERROR(ACPI_LV_WARN, handle, pathname, - status); - } - if (buffer && buffer->pointer) { - acpi_os_free(buffer->pointer); - buffer->pointer = NULL; - buffer->length = 0; - } - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_evaluate_simple_integer - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_evaluate_simple_integer ( - acpi_handle handle, - acpi_string pathname, - u32 *data) -{ - acpi_status status = AE_OK; - acpi_object *element = NULL; - acpi_buffer buffer; - - FUNCTION_TRACE("bm_evaluate_simple_integer"); - - if (!data) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(&buffer, 0, sizeof(acpi_buffer)); - - /* - * Evaluate Object: - * ---------------- - */ - status = bm_evaluate_object(handle, pathname, NULL, &buffer); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "failed to evaluate object (%s)\n", - acpi_format_exception(status))); - goto end; - } - - /* - * Validate Data: - * -------------- - */ - status = bm_cast_buffer(&buffer, (void**)&element, - sizeof(acpi_object)); - if (ACPI_FAILURE(status)) { - DEBUG_EVAL_ERROR(ACPI_LV_WARN, handle, pathname, status); - goto end; - } - - if (element->type != ACPI_TYPE_INTEGER) { - status = AE_BAD_DATA; - DEBUG_EVAL_ERROR(ACPI_LV_WARN, handle, pathname, status); - goto end; - } - - *data = element->integer.value; - -end: - acpi_os_free(buffer.pointer); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bm_evaluate_reference_list - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bm_evaluate_reference_list ( - acpi_handle handle, - acpi_string pathname, - BM_HANDLE_LIST *reference_list) -{ - acpi_status status = AE_OK; - acpi_object *package = NULL; - acpi_object *element = NULL; - acpi_handle reference_handle = NULL; - acpi_buffer buffer; - u32 i = 0; - - FUNCTION_TRACE("bm_evaluate_reference_list"); - - if (!reference_list) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(&buffer, 0, sizeof(acpi_buffer)); - - /* - * Evaluate Object: - * ---------------- - */ - status = bm_evaluate_object(handle, pathname, NULL, &buffer); - if (ACPI_FAILURE(status)) { - goto end; - } - - /* - * Validate Package: - * ----------------- - */ - status = bm_cast_buffer(&buffer, (void**)&package, - sizeof(acpi_object)); - if (ACPI_FAILURE(status)) { - DEBUG_EVAL_ERROR(ACPI_LV_WARN, handle, pathname, status); - goto end; - } - - if (package->type != ACPI_TYPE_PACKAGE) { - status = AE_BAD_DATA; - DEBUG_EVAL_ERROR(ACPI_LV_WARN, handle, pathname, status); - goto end; - } - - if (package->package.count > BM_HANDLES_MAX) { - package->package.count = BM_HANDLES_MAX; - } - - /* - * Parse Package Data: - * ------------------- - */ - for (i = 0; i < package->package.count; i++) { - - element = &(package->package.elements[i]); - - if (!element || (element->type != ACPI_TYPE_STRING)) { - status = AE_BAD_DATA; - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid element in package (not a device reference).\n")); - DEBUG_EVAL_ERROR (ACPI_LV_WARN, handle, pathname, status); - break; - } - - /* - * Resolve reference string (e.g. "\_PR_.CPU_") to an - * acpi_handle. - */ - status = acpi_get_handle(handle, - element->string.pointer, &reference_handle); - if (ACPI_FAILURE(status)) { - status = AE_BAD_DATA; - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to resolve device reference [%s].\n", element->string.pointer)); - DEBUG_EVAL_ERROR (ACPI_LV_WARN, handle, pathname, status); - break; - } - - /* - * Resolve acpi_handle to BM_HANDLE. - */ - status = bm_get_handle(reference_handle, - &(reference_list->handles[i])); - if (ACPI_FAILURE(status)) { - status = AE_BAD_DATA; - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to resolve device reference for [%p].\n", reference_handle)); - DEBUG_EVAL_ERROR (ACPI_LV_WARN, handle, pathname, status); - break; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resolved reference [%s]->[%p]->[%02x]\n", element->string.pointer, reference_handle, reference_list->handles[i])); - - (reference_list->count)++; - } - -end: - acpi_os_free(buffer.pointer); - - return_ACPI_STATUS(status); -} - - diff -Nur linux-2.4.19/drivers/acpi/ospm/button/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/button/Makefile --- linux-2.4.19/drivers/acpi/ospm/button/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/button/Makefile Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/button/bn.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/button/bn.c --- linux-2.4.19/drivers/acpi/ospm/button/bn.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/button/bn.c Wed Dec 31 16:00:00 1969 @@ -1,507 +0,0 @@ -/***************************************************************************** - * - * Module Name: bn.c - * $Revision: 27 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Plxxe, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "bn.h" - - -#define _COMPONENT ACPI_BUTTON - MODULE_NAME ("bn") - - -/***************************************************************************** - * Internal Functions - *****************************************************************************/ - -/***************************************************************************** - * - * FUNCTION: bn_print - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Prints out information on a specific button. - * - ****************************************************************************/ - -void -bn_print ( - BN_CONTEXT *button) -{ -#ifdef ACPI_DEBUG - acpi_buffer buffer; - - PROC_NAME("bn_print"); - - if (!button) { - return; - } - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - /* - * Get the full pathname for this ACPI object. - */ - acpi_get_name(button->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - /* - * Print out basic button information. - */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - switch (button->type) { - - case BN_TYPE_POWER_BUTTON: - case BN_TYPE_POWER_BUTTON_FIXED: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Power_button[%02x]:[%p] %s\n", button->device_handle, button->acpi_handle, (char*)buffer.pointer)); - break; - - case BN_TYPE_SLEEP_BUTTON: - case BN_TYPE_SLEEP_BUTTON_FIXED: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Sleep_button[%02x]:[%p] %s\n", button->device_handle, button->acpi_handle, (char*)buffer.pointer)); - break; - - case BN_TYPE_LID_SWITCH: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Lid_switch[%02x]:[%p] %s\n", button->device_handle, button->acpi_handle, (char*)buffer.pointer)); - break; - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); -#endif /*ACPI_DEBUG*/ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: bn_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bn_add_device( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - BN_CONTEXT *button = NULL; - - FUNCTION_TRACE("bn_add_device"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding button device [%02x].\n", device_handle)); - - if (!context || *context) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid context.\n")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Get information on this device. - */ - status = bm_get_device_info( device_handle, &device ); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Allocate a new BN_CONTEXT structure. - */ - button = acpi_os_callocate(sizeof(BN_CONTEXT)); - if (!button) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - button->device_handle = device->handle; - button->acpi_handle = device->acpi_handle; - - /* - * Power Button? - * ------------- - * Either fixed-feature or generic (namespace) types. - */ - if (strncmp(device->id.hid, BN_HID_POWER_BUTTON, - sizeof(BM_DEVICE_HID)) == 0) { - - if (device->id.type == BM_TYPE_FIXED_BUTTON) { - - button->type = BN_TYPE_POWER_BUTTON_FIXED; - - /* Register for fixed-feature events. */ - status = acpi_install_fixed_event_handler( - ACPI_EVENT_POWER_BUTTON, bn_notify_fixed, - (void*)button); - } - else { - button->type = BN_TYPE_POWER_BUTTON; - } - - } - - /* - * Sleep Button? - * ------------- - * Either fixed-feature or generic (namespace) types. - */ - else if (strncmp( device->id.hid, BN_HID_SLEEP_BUTTON, - sizeof(BM_DEVICE_HID)) == 0) { - - if (device->id.type == BM_TYPE_FIXED_BUTTON) { - - button->type = BN_TYPE_SLEEP_BUTTON_FIXED; - - /* Register for fixed-feature events. */ - status = acpi_install_fixed_event_handler( - ACPI_EVENT_SLEEP_BUTTON, bn_notify_fixed, - (void*)button); - } - else { - button->type = BN_TYPE_SLEEP_BUTTON; - } - } - - /* - * LID Switch? - * ----------- - */ - else if (strncmp( device->id.hid, BN_HID_LID_SWITCH, - sizeof(BM_DEVICE_HID)) == 0) { - button->type = BN_TYPE_LID_SWITCH; - } - - status = bn_osl_add_device(button); - if (ACPI_FAILURE(status)) { - goto end; - } - - *context = button; - - bn_print(button); - -end: - if (ACPI_FAILURE(status)) { - acpi_os_free(button); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bn_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bn_remove_device( - void **context) -{ - acpi_status status = AE_OK; - BN_CONTEXT *button = NULL; - - FUNCTION_TRACE("bn_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - button = (BN_CONTEXT*)*context; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing button device [%02x].\n", button->device_handle)); - - /* - * Unregister for fixed-feature events. - */ - switch (button->type) { - case BN_TYPE_POWER_BUTTON_FIXED: - status = acpi_remove_fixed_event_handler( - ACPI_EVENT_POWER_BUTTON, bn_notify_fixed); - break; - case BN_TYPE_SLEEP_BUTTON_FIXED: - status = acpi_remove_fixed_event_handler( - ACPI_EVENT_SLEEP_BUTTON, bn_notify_fixed); - break; - } - - bn_osl_remove_device(button); - - acpi_os_free(button); - - *context = NULL; - - return_ACPI_STATUS(status); -} - - -/***************************************************************************** - * External Functions - *****************************************************************************/ - -/***************************************************************************** - * - * FUNCTION: bn_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - - ****************************************************************************/ - -acpi_status -bn_initialize (void) -{ - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("bn_initialize"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - driver.notify = &bn_notify; - driver.request = &bn_request; - - /* - * Register for power buttons. - */ - MEMCPY(criteria.hid, BN_HID_POWER_BUTTON, sizeof(BN_HID_POWER_BUTTON)); - bm_register_driver(&criteria, &driver); - - /* - * Register for sleep buttons. - */ - MEMCPY(criteria.hid, BN_HID_SLEEP_BUTTON, sizeof(BN_HID_SLEEP_BUTTON)); - bm_register_driver(&criteria, &driver); - - /* - * Register for LID switches. - */ - MEMCPY(criteria.hid, BN_HID_LID_SWITCH, sizeof(BN_HID_LID_SWITCH)); - bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bn_terminate - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bn_terminate (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("bn_terminate"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - driver.notify = &bn_notify; - driver.request = &bn_request; - - /* - * Unregister for power buttons. - */ - MEMCPY(criteria.hid, BN_HID_POWER_BUTTON, sizeof(BN_HID_POWER_BUTTON)); - status = bm_unregister_driver(&criteria, &driver); - - /* - * Unregister for sleep buttons. - */ - MEMCPY(criteria.hid, BN_HID_SLEEP_BUTTON, sizeof(BN_HID_SLEEP_BUTTON)); - status = bm_unregister_driver(&criteria, &driver); - - /* - * Unregister for LID switches. - */ - MEMCPY(criteria.hid, BN_HID_LID_SWITCH, sizeof(BN_HID_LID_SWITCH)); - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bn_notify_fixed - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bn_notify_fixed ( - void *context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bn_notify_fixed"); - - if (!context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status change event detected.\n")); - - status = bn_osl_generate_event(BN_NOTIFY_STATUS_CHANGE, - ((BN_CONTEXT*)context)); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bn_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bn_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bn_notify"); - - if (!context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - switch (notify_type) { - case BM_NOTIFY_DEVICE_ADDED: - status = bn_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = bn_remove_device(context); - break; - - case BN_NOTIFY_STATUS_CHANGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status change event detected.\n")); - status = bn_osl_generate_event(BN_NOTIFY_STATUS_CHANGE, - ((BN_CONTEXT*)*context)); - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: bn_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -bn_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("bn_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Handle Request: - * --------------- - */ - switch (request->command) { - - default: - status = AE_SUPPORT; - break; - } - - request->status = status; - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/button/bn_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/button/bn_osl.c --- linux-2.4.19/drivers/acpi/ospm/button/bn_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/button/bn_osl.c Wed Dec 31 16:00:00 1969 @@ -1,311 +0,0 @@ -/****************************************************************************** - * - * Module Name: bn_osl.c - * $Revision: 16 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include "bn.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Button Driver"); -MODULE_LICENSE("GPL"); - - -#define BN_PROC_ROOT "button" -#define BN_PROC_POWER_BUTTON "power" -#define BN_PROC_SLEEP_BUTTON "sleep" -#define BN_PROC_LID_SWITCH "lid" - -extern struct proc_dir_entry *bm_proc_root; -static struct proc_dir_entry *bn_proc_root = NULL; - - -#define BN_TYPE_UNKNOWN 0 -#define BN_TYPE_FIXED 1 -#define BN_TYPE_GENERIC 2 - -static int bn_power_button = BN_TYPE_UNKNOWN; -static int bn_sleep_button = BN_TYPE_UNKNOWN; -static int bn_lid_switch = BN_TYPE_UNKNOWN; - - -/**************************************************************************** - * - * FUNCTION: bn_osl_add_device - * - ****************************************************************************/ - -acpi_status -bn_osl_add_device( - BN_CONTEXT *button) -{ - acpi_status status = AE_OK; - - if (!button) { - return(AE_BAD_PARAMETER); - } - - switch (button->type) { - - case BN_TYPE_POWER_BUTTON_FIXED: - bn_power_button = BN_TYPE_FIXED; - printk(KERN_INFO "ACPI: Power Button (FF) found\n"); - if (!proc_mkdir(BN_PROC_POWER_BUTTON, bn_proc_root)) { - status = AE_ERROR; - } - break; - - case BN_TYPE_POWER_BUTTON: - /* - * Avoid creating multiple /proc entries when (buggy) ACPI - * BIOS tables erroneously list both fixed- and generic- - * feature buttons. Note that fixed-feature buttons are - * always enumerated first (and there can only be one) so - * we only need to check here. - */ - switch (bn_power_button) { - case BN_TYPE_GENERIC: - printk(KERN_WARNING "ACPI: Multiple generic-space power buttons detected, using first\n"); - break; - case BN_TYPE_FIXED: - printk(KERN_WARNING "ACPI: Multiple power buttons detected, ignoring fixed-feature\n"); - default: - printk(KERN_INFO "ACPI: Power Button (CM) found\n"); - bn_power_button = BN_TYPE_GENERIC; - if (!proc_mkdir(BN_PROC_POWER_BUTTON, bn_proc_root)) { - status = AE_ERROR; - } - break; - } - break; - - case BN_TYPE_SLEEP_BUTTON_FIXED: - bn_sleep_button = BN_TYPE_FIXED; - printk(KERN_INFO "ACPI: Sleep Button (FF) found\n"); - if (!proc_mkdir(BN_PROC_SLEEP_BUTTON, bn_proc_root)) { - status = AE_ERROR; - } - break; - - case BN_TYPE_SLEEP_BUTTON: - /* - * Avoid creating multiple /proc entries when (buggy) ACPI - * BIOS tables erroneously list both fixed- and generic- - * feature buttons. Note that fixed-feature buttons are - * always enumerated first (and there can only be one) so - * we only need to check here. - */ - switch (bn_sleep_button) { - case BN_TYPE_GENERIC: - printk(KERN_WARNING "ACPI: Multiple generic-space sleep buttons detected, using first\n"); - break; - case BN_TYPE_FIXED: - printk(KERN_WARNING "ACPI: Multiple sleep buttons detected, ignoring fixed-feature\n"); - default: - bn_sleep_button = BN_TYPE_GENERIC; - printk(KERN_INFO "ACPI: Sleep Button (CM) found\n"); - if (!proc_mkdir(BN_PROC_SLEEP_BUTTON, bn_proc_root)) { - status = AE_ERROR; - } - break; - } - break; - - case BN_TYPE_LID_SWITCH: - if (bn_lid_switch) { - printk(KERN_WARNING "ACPI: Multiple generic-space lid switches detected, using first\n"); - break; - } - bn_lid_switch = BN_TYPE_GENERIC; - printk(KERN_INFO "ACPI: Lid Switch (CM) found\n"); - if (!proc_mkdir(BN_PROC_LID_SWITCH, bn_proc_root)) { - status = AE_ERROR; - } - break; - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: bn_osl_remove_device - * - ****************************************************************************/ - -acpi_status -bn_osl_remove_device ( - BN_CONTEXT *button) -{ - if (!button) { - return(AE_BAD_PARAMETER); - } - - switch (button->type) { - - case BN_TYPE_POWER_BUTTON: - case BN_TYPE_POWER_BUTTON_FIXED: - remove_proc_entry(BN_PROC_POWER_BUTTON, bn_proc_root); - break; - - case BN_TYPE_SLEEP_BUTTON: - case BN_TYPE_SLEEP_BUTTON_FIXED: - remove_proc_entry(BN_PROC_SLEEP_BUTTON, bn_proc_root); - break; - - case BN_TYPE_LID_SWITCH: - remove_proc_entry(BN_PROC_LID_SWITCH, bn_proc_root); - break; - } - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: bn_osl_generate_event - * - ****************************************************************************/ - -acpi_status -bn_osl_generate_event ( - u32 event, - BN_CONTEXT *button) -{ - acpi_status status = AE_OK; - - if (!button) { - return(AE_BAD_PARAMETER); - } - - switch (event) { - - case BN_NOTIFY_STATUS_CHANGE: - - switch(button->type) { - - case BN_TYPE_POWER_BUTTON: - case BN_TYPE_POWER_BUTTON_FIXED: - status = bm_osl_generate_event(button->device_handle, - BN_PROC_ROOT, BN_PROC_POWER_BUTTON, event, 0); - break; - - case BN_TYPE_SLEEP_BUTTON: - case BN_TYPE_SLEEP_BUTTON_FIXED: - status = bm_osl_generate_event(button->device_handle, - BN_PROC_ROOT, BN_PROC_SLEEP_BUTTON, event, 0); - break; - - case BN_TYPE_LID_SWITCH: - status = bm_osl_generate_event(button->device_handle, - BN_PROC_ROOT, BN_PROC_LID_SWITCH, event, 0); - break; - - default: - status = AE_SUPPORT; - break; - } - - break; - - default: - return(AE_BAD_PARAMETER); - break; - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: bn_osl_init - * - * PARAMETERS: - * - * RETURN: 0: Success - * - * DESCRIPTION: Module initialization. - * - ****************************************************************************/ - -static int __init -bn_osl_init (void) -{ - acpi_status status = AE_OK; - - /* abort if no busmgr */ - if (!bm_proc_root) - return -ENODEV; - - bn_proc_root = proc_mkdir(BN_PROC_ROOT, bm_proc_root); - if (!bn_proc_root) { - status = AE_ERROR; - } - else { - status = bn_initialize(); - if (ACPI_FAILURE(status)) { - remove_proc_entry(BN_PROC_ROOT, bm_proc_root); - } - } - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - - -/**************************************************************************** - * - * FUNCTION: bn_osl_cleanup - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Module cleanup. - * - ****************************************************************************/ - -static void __exit -bn_osl_cleanup (void) -{ - bn_terminate(); - - if (bn_proc_root) { - remove_proc_entry(BN_PROC_ROOT, bm_proc_root); - } - - return; -} - - -module_init(bn_osl_init); -module_exit(bn_osl_cleanup); diff -Nur linux-2.4.19/drivers/acpi/ospm/ec/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/Makefile --- linux-2.4.19/drivers/acpi/ospm/ec/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/Makefile Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/ec/ec_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ec_osl.c --- linux-2.4.19/drivers/acpi/ospm/ec/ec_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ec_osl.c Wed Dec 31 16:00:00 1969 @@ -1,91 +0,0 @@ -/***************************************************************************** - * - * Module Name: ec_osl.c - * $Revision: 11 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include "ec.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Embedded Controller Driver"); -MODULE_LICENSE("GPL"); - -extern struct proc_dir_entry *bm_proc_root; - - -/**************************************************************************** - * - * FUNCTION: ec_osl_init - * - * PARAMETERS: - * - * RETURN: 0: Success - * - * DESCRIPTION: Module initialization. - * - ****************************************************************************/ - -static int __init -ec_osl_init (void) -{ - acpi_status status = AE_OK; - - /* abort if no busmgr */ - if (!bm_proc_root) - return -ENODEV; - - status = ec_initialize(); - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - -/**************************************************************************** - * - * FUNCTION: ec_osl_cleanup - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Module cleanup. - * - ****************************************************************************/ - -static void __exit -ec_osl_cleanup(void) -{ - ec_terminate(); - - return; -} - -module_init(ec_osl_init); -module_exit(ec_osl_cleanup); diff -Nur linux-2.4.19/drivers/acpi/ospm/ec/ecgpe.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ecgpe.c --- linux-2.4.19/drivers/acpi/ospm/ec/ecgpe.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ecgpe.c Wed Dec 31 16:00:00 1969 @@ -1,249 +0,0 @@ -/***************************************************************************** - * - * Module Name: ecgpe.c - * $Revision: 28 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "ec.h" - -#define _COMPONENT ACPI_EC - MODULE_NAME ("ecgpe") - - -/**************************************************************************** - * - * FUNCTION: ec_query_handler - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -ec_query_handler ( - void *context) -{ - EC_CONTEXT *ec = (EC_CONTEXT*)context; - static char object_name[5] = {'_','Q','0','0','\0'}; - const char hex[] = {'0','1','2','3','4','5','6','7','8', - '9','A','B','C','D','E','F'}; - - FUNCTION_TRACE("ec_query_handler"); - - if (!ec) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); - return_VOID; - } - - /* - * Evaluate _Qxx: - * -------------- - * Evaluate corresponding _Qxx method. Note that a zero query value - * indicates a spurious EC_SCI (no such thing as _Q00). - */ - object_name[2] = hex[((ec->query_data >> 4) & 0x0F)]; - object_name[3] = hex[(ec->query_data & 0x0F)]; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Evaluating [%s] for ec [%02x].\n", object_name, ec->device_handle)); - - bm_evaluate_object(ec->acpi_handle, object_name, NULL, NULL); - - return_VOID; -} - - -/**************************************************************************** - * - * FUNCTION: ec_gpe_handler - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -ec_gpe_handler ( - void *context) -{ - acpi_status status = AE_OK; - EC_CONTEXT *ec = (EC_CONTEXT*)context; - EC_STATUS ec_status = 0; - - FUNCTION_TRACE("ec_gpe_handler"); - - if (!ec) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); - return_VOID; - } - - /* TBD: synchronize w/ transaction (ectransx). */ - - /* - * EC_SCI? - * ------- - * Check the EC_SCI bit to see if this is an EC_SCI event. If not (e.g. - * OBF/IBE) just return, as we already poll to detect these events. - */ - acpi_os_read_port(ec->status_port, &ec_status, 8); - if (!(ec_status & EC_FLAG_SCI)) { - return_VOID; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "EC_SCI event detected on ec [%02x] - running query.\n", ec->device_handle)); - - /* - * Run Query: - * ---------- - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ - status = ec_io_write(ec, ec->command_port, EC_COMMAND_QUERY, - EC_EVENT_OUTPUT_BUFFER_FULL); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'query command' to EC.\n")); - return_VOID; - } - - status = ec_io_read(ec, ec->data_port, &(ec->query_data), - EC_EVENT_NONE); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Error reading query data.\n")); - return_VOID; - } - - /* TBD: un-synchronize w/ transaction (ectransx). */ - - /* - * Spurious EC_SCI? - * ---------------- - */ - if (!ec->query_data) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Spurious EC SCI detected.\n")); - return_VOID; - } - - /* - * Defer _Qxx Execution: - * --------------------- - * Can't evaluate this method now 'cause we're at interrupt-level. - */ - status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, - ec_query_handler, ec); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to defer _Qxx method evaluation.\n")); - return_VOID; - } - - return_VOID; -} - - -/**************************************************************************** - * - * FUNCTION: ec_install_gpe_handler - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_install_gpe_handler ( - EC_CONTEXT *ec) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_install_gpe_handler"); - - if (!ec) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Evaluate _GPE: - * -------------- - * Evaluate the "_GPE" object (required) to find out which GPE bit - * is used by this EC to signal events (SCIs). - */ - status = bm_evaluate_simple_integer(ec->acpi_handle, - "_GPE", &(ec->gpe_bit)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Install GPE Handler: - * -------------------- - * Install a handler for this EC's GPE bit. - */ - status = acpi_install_gpe_handler(ec->gpe_bit, ACPI_EVENT_EDGE_TRIGGERED, - &ec_gpe_handler, ec); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "acpi_install_gpe_handler() failed for GPE bit [%02x] with status [%08x].\n", ec->gpe_bit, status)); - ec->gpe_bit = EC_GPE_UNKNOWN; - return_ACPI_STATUS(status); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_remove_gpe_handler - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_remove_gpe_handler ( - EC_CONTEXT *ec) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_remove_gpe_handler"); - - if (!ec) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - status = acpi_remove_gpe_handler(ec->gpe_bit, &ec_gpe_handler); - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/ec/ecmain.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ecmain.c --- linux-2.4.19/drivers/acpi/ospm/ec/ecmain.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ecmain.c Wed Dec 31 16:00:00 1969 @@ -1,498 +0,0 @@ -/***************************************************************************** - * - * Module Name: ecmain.c - * $Revision: 29 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "ec.h" - -#define _COMPONENT ACPI_EC - MODULE_NAME ("ecmain") - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: ec_print - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Prints out information on a specific ec. - * - ****************************************************************************/ - -void -ec_print ( - EC_CONTEXT *ec) -{ -#ifdef ACPI_DEBUG - acpi_buffer buffer; -#endif /*ACPI_DEBUG*/ - - PROC_NAME("ec_print"); - - if (!ec) { - return; - } - - acpi_os_printf("EC: found, GPE %d\n", ec->gpe_bit); - -#ifdef ACPI_DEBUG - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - /* - * Get the full pathname for this ACPI object. - */ - acpi_get_name(ec->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - /* - * Print out basic thermal zone information. - */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Embedded_controller[%02x]:[%p] %s\n", ec->device_handle, ec->acpi_handle, (char*)buffer.pointer)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| gpe_bit[%02x] status/command_port[%02x] data_port[%02x]\n", ec->gpe_bit, ec->status_port, ec->data_port)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); -#endif /*ACPI_DEBUG*/ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: ec_get_port_values - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Evaluate _CRS to get the current resources (I/O port - * addresses) for this EC. - * - ****************************************************************************/ - -acpi_status -ec_get_port_values( - EC_CONTEXT *ec) -{ - acpi_status status = AE_OK; - acpi_buffer buffer; - acpi_resource *resource = NULL; - - FUNCTION_TRACE("ec_get_port_values"); - - if (!ec) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - buffer.length = 0; - buffer.pointer = NULL; - - status = acpi_get_current_resources(ec->acpi_handle, &buffer); - if (status != AE_BUFFER_OVERFLOW) { - return_ACPI_STATUS(status); - } - - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - status = acpi_get_current_resources(ec->acpi_handle, &buffer); - if (ACPI_FAILURE(status)) { - goto end; - } - - resource = (acpi_resource *) buffer.pointer; - ec->data_port = resource->data.io.min_base_address; - - resource = NEXT_RESOURCE(resource); - - ec->status_port = ec->command_port = - resource->data.io.min_base_address; -end: - acpi_os_free(buffer.pointer); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_add_device( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - EC_CONTEXT *ec = NULL; - u8 gpe_handler = FALSE; - u8 space_handler = FALSE; - - FUNCTION_TRACE("ec_add_device"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding EC device [%02x].\n", device_handle)); - - if (!context || *context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Get information on this device. - */ - status = bm_get_device_info(device_handle, &device); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Allocate a new EC_CONTEXT structure. - */ - ec = acpi_os_callocate(sizeof(EC_CONTEXT)); - if (!ec) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - ec->device_handle = device->handle; - ec->acpi_handle = device->acpi_handle; - - /* - * Get the I/O port addresses for the command/status and data ports. - */ - status = ec_get_port_values(ec); - if (ACPI_FAILURE(status)) { - goto end; - } - - /* - * See if we need to obtain the global lock for EC transactions. - */ - status = bm_evaluate_simple_integer(ec->acpi_handle, "_GLK", - &ec->use_global_lock); - if (status == AE_NOT_FOUND) { - ec->use_global_lock = 0; - } - else if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "EC _GLK failed\n")); - goto end; - } - - /* - * Install a handler for servicing this EC's GPE. - */ - status = ec_install_gpe_handler(ec); - if (ACPI_FAILURE(status)) { - goto end; - } - else { - gpe_handler = TRUE; - } - - /* - * Install a handler for servicing this EC's address space. - */ - status = ec_install_space_handler(ec); - if (ACPI_FAILURE(status)) { - goto end; - } - else { - space_handler = TRUE; - } - - /* - * Create a semaphore to serialize EC transactions. - */ - status = acpi_os_create_semaphore(1,1, &(ec->mutex)); - if (ACPI_FAILURE(status)) { - goto end; - } - - /* - * Context now contains information specific to this EC. Note - * that we'll get this pointer back on every ec_request() and - * ec_notify(). - */ - *context = ec; - - ec_print(ec); - -end: - if (ACPI_FAILURE(status)) { - - if (gpe_handler) { - ec_remove_gpe_handler(ec); - } - - if (space_handler) { - ec_remove_space_handler(ec); - } - - if (ec->mutex) { - acpi_os_delete_semaphore(ec->mutex); - } - - acpi_os_free(ec); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_remove_device( - void **context) -{ - acpi_status status = AE_OK; - EC_CONTEXT *ec = NULL; - - FUNCTION_TRACE("ec_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ec = (EC_CONTEXT*)*context; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing EC device [%02x].\n", ec->device_handle)); - - ec_remove_space_handler(ec); - - ec_remove_gpe_handler(ec); - - if (ec->mutex) { - acpi_os_delete_semaphore(ec->mutex); - } - - acpi_os_free(ec); - - *context = NULL; - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: ec_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_initialize (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("ec_initialize"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Register driver for AC Adapter devices. - */ - MEMCPY(criteria.hid, EC_HID_EC, sizeof(EC_HID_EC)); - - driver.notify = &ec_notify; - driver.request = &ec_request; - - status = bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_terminate - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_terminate(void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("ec_terminate"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Unregister driver for AC Adapter devices. - */ - MEMCPY(criteria.hid, EC_HID_EC, sizeof(EC_HID_EC)); - - driver.notify = &ec_notify; - driver.request = &ec_request; - - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_notify ( - BM_NOTIFY notify, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_notify"); - - switch (notify) { - - case BM_NOTIFY_DEVICE_ADDED: - status = ec_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = ec_remove_device(context); - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - EC_REQUEST *ec_request = NULL; - EC_CONTEXT *ec = NULL; - - FUNCTION_TRACE("ec_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) - return_ACPI_STATUS(AE_BAD_PARAMETER); - - /* - * buffer must contain a valid EC_REQUEST structure. - */ - status = bm_cast_buffer(&(request->buffer), (void**)&ec_request, - sizeof(EC_REQUEST)); - if (ACPI_FAILURE(status)) - return_ACPI_STATUS(status); - - /* - * context contains information specific to this EC. - */ - ec = (EC_CONTEXT*)context; - - /* - * Perform the Transaction. - */ - status = ec_transaction(ec, ec_request); - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/ec/ecspace.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ecspace.c --- linux-2.4.19/drivers/acpi/ospm/ec/ecspace.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ecspace.c Wed Dec 31 16:00:00 1969 @@ -1,192 +0,0 @@ -/***************************************************************************** - * - * Module Name: ecspace.c - * $Revision: 23 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "ec.h" - -#define _COMPONENT ACPI_EC - MODULE_NAME ("ecspace") - - -/**************************************************************************** - * - * FUNCTION: ec_space_setup - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_space_setup ( - acpi_handle region_handle, - u32 function, - void *handler_context, - void **return_context) -{ - /* - * The EC object is in the handler context and is needed - * when calling the ec_space_handler. - */ - *return_context = handler_context; - - return AE_OK; -} - - -/**************************************************************************** - * - * FUNCTION: ec_space_handler - * - * PARAMETERS: function - Read or Write operation - * address - Where in the space to read or write - * bit_width - Field width in bits (should be 8) - * value - Pointer to in or out value - * context - context pointer - * - * RETURN: - * - * DESCRIPTION: Handler for the Embedded Controller (EC) address space - * (Op Region) - * - ****************************************************************************/ - -acpi_status -ec_space_handler ( - u32 function, - ACPI_PHYSICAL_ADDRESS address, - u32 bit_width, - u32 *value, - void *handler_context, - void *region_context) -{ - acpi_status status = AE_OK; - EC_CONTEXT *ec = NULL; - EC_REQUEST ec_request; - - FUNCTION_TRACE("ec_space_handler"); - - if (address > 0xFF || bit_width != 8 || !value || !handler_context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ec = (EC_CONTEXT*)handler_context; - - switch (function) { - - case ACPI_READ_ADR_SPACE: - ec_request.command = EC_COMMAND_READ; - ec_request.address = address; - ec_request.data = 0; - break; - - case ACPI_WRITE_ADR_SPACE: - ec_request.command = EC_COMMAND_WRITE; - ec_request.address = address; - ec_request.data = (u8)(*value); - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Received request with invalid function [%X].\n", function)); - return_ACPI_STATUS(AE_BAD_PARAMETER); - break; - } - - /* - * Perform the Transaction. - */ - status = ec_transaction(ec, &ec_request); - if (ACPI_SUCCESS(status)) { - (*value) = (u32)ec_request.data; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_install_space_handler - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_install_space_handler ( - EC_CONTEXT *ec) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_install_space_handler"); - - if (!ec) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - status = acpi_install_address_space_handler (ec->acpi_handle, - ACPI_ADR_SPACE_EC, &ec_space_handler, &ec_space_setup, ec); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_remove_space_handler - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_remove_space_handler ( - EC_CONTEXT *ec) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_remove_space_handler"); - - if (!ec) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - status = acpi_remove_address_space_handler(ec->acpi_handle, - ACPI_ADR_SPACE_EC, &ec_space_handler); - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/ec/ectransx.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ectransx.c --- linux-2.4.19/drivers/acpi/ospm/ec/ectransx.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/ec/ectransx.c Wed Dec 31 16:00:00 1969 @@ -1,343 +0,0 @@ -/***************************************************************************** - * - * Module Name: ectransx.c - * $Revision: 24 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include "ec.h" - -#define _COMPONENT ACPI_EC - MODULE_NAME ("ectransx") - - -/**************************************************************************** - * - * FUNCTION: ec_io_wait - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_io_wait ( - EC_CONTEXT *ec, - EC_EVENT wait_event) -{ - EC_STATUS ec_status = 0; - u32 i = 100; - - if (!ec || ((wait_event != EC_EVENT_OUTPUT_BUFFER_FULL) - && (wait_event != EC_EVENT_INPUT_BUFFER_EMPTY))) { - return(AE_BAD_PARAMETER); - } - - /* - * Wait for Event: - * --------------- - * Poll the EC status register waiting for the event to occur. - * Note that we'll wait a maximum of 1ms in 10us chunks. - */ - switch (wait_event) { - - case EC_EVENT_OUTPUT_BUFFER_FULL: - do { - acpi_os_read_port(ec->status_port, &ec_status, 8); - if (ec_status & EC_FLAG_OUTPUT_BUFFER) { - return(AE_OK); - } - acpi_os_stall(10); - } while (--i>0); - break; - - case EC_EVENT_INPUT_BUFFER_EMPTY: - do { - acpi_os_read_port(ec->status_port, &ec_status, 8); - if (!(ec_status & EC_FLAG_INPUT_BUFFER)) { - return(AE_OK); - } - acpi_os_stall(10); - } while (--i>0); - break; - } - - return(AE_TIME); -} - - -/**************************************************************************** - * - * FUNCTION: ec_io_read - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_io_read ( - EC_CONTEXT *ec, - ACPI_IO_ADDRESS io_port, - u8 *data, - EC_EVENT wait_event) -{ - acpi_status status = AE_OK; - - if (!ec || !data) { - return(AE_BAD_PARAMETER); - } - - acpi_os_read_port(io_port, (u32*) data, 8); - - if (wait_event) { - status = ec_io_wait(ec, wait_event); - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_io_write - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_io_write ( - EC_CONTEXT *ec, - ACPI_IO_ADDRESS io_port, - u8 data, - EC_EVENT wait_event) -{ - acpi_status status = AE_OK; - - if (!ec) { - return(AE_BAD_PARAMETER); - } - - acpi_os_write_port(io_port, data, 8); - - if (wait_event) { - status = ec_io_wait(ec, wait_event); - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_read - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_read ( - EC_CONTEXT *ec, - u8 address, - u8 *data) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_read"); - - if (!ec || !data) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (ec->use_global_lock) { - status = acpi_acquire_global_lock(); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not acquire Global Lock\n")); - return_ACPI_STATUS(status); - } - } - - status = ec_io_write(ec, ec->command_port, EC_COMMAND_READ, - EC_EVENT_INPUT_BUFFER_EMPTY); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'read command' to EC.\n")); - return_ACPI_STATUS(status); - } - - status = ec_io_write(ec, ec->data_port, address, - EC_EVENT_OUTPUT_BUFFER_FULL); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'read address' to EC.\n")); - return_ACPI_STATUS(status); - } - - status = ec_io_read(ec, ec->data_port, data, EC_EVENT_NONE); - - if (ec->use_global_lock) { - acpi_release_global_lock(); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Read data [%02x] from address [%02x] on ec [%02x].\n", (*data), address, ec->device_handle)); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_write - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_write ( - EC_CONTEXT *ec, - u8 address, - u8 data) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_write"); - - if (!ec) - return_ACPI_STATUS(AE_BAD_PARAMETER); - - if (ec->use_global_lock) { - status = acpi_acquire_global_lock(); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not acquire Global Lock\n")); - return_ACPI_STATUS(status); - } - } - - status = ec_io_write(ec, ec->command_port, EC_COMMAND_WRITE, - EC_EVENT_INPUT_BUFFER_EMPTY); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'write command' to EC.\n")); - return_ACPI_STATUS(status); - } - - status = ec_io_write(ec, ec->data_port, address, - EC_EVENT_INPUT_BUFFER_EMPTY); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'write address' to EC.\n")); - return_ACPI_STATUS(status); - } - - status = ec_io_write(ec, ec->data_port, data, - EC_EVENT_INPUT_BUFFER_EMPTY); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to send 'write data' to EC.\n")); - return_ACPI_STATUS(status); - } - - if (ec->use_global_lock) { - acpi_release_global_lock(); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Wrote data [%02x] to address [%02x] on ec [%02x].\n", data, address, ec->device_handle)); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: ec_transaction - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -ec_transaction ( - EC_CONTEXT *ec, - EC_REQUEST *request) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("ec_transaction"); - - if (!ec || !request) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Obtain mutex to serialize all EC transactions. - */ - status = acpi_os_wait_semaphore(ec->mutex, 1, EC_DEFAULT_TIMEOUT); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Perform the transaction. - */ - switch (request->command) { - - case EC_COMMAND_READ: - status = ec_read(ec, request->address, &(request->data)); - break; - - case EC_COMMAND_WRITE: - status = ec_write(ec, request->address, request->data); - break; - - default: - status = AE_SUPPORT; - break; - } - - /* - * Signal the mutex to indicate transaction completion. - */ - acpi_os_signal_semaphore(ec->mutex, 1); - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/include/ac.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/ac.h --- linux-2.4.19/drivers/acpi/ospm/include/ac.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/ac.h Wed Dec 31 16:00:00 1969 @@ -1,102 +0,0 @@ -/***************************************************************************** - * - * Module Name: ac.h - * $Revision: 6 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __AC_H__ -#define __AC_H__ - -#include -#include -#include - - -/***************************************************************************** - * Types & Other Defines - *****************************************************************************/ - -/* - * Notifications: - * -------------- - */ -#define AC_NOTIFY_STATUS_CHANGE ((BM_NOTIFY) 0x80) - -/* - * Hardware IDs: - * ------------- - */ -#define AC_HID_AC_ADAPTER "ACPI0003" - - -/* - * Device Context: - * --------------- - */ -typedef struct -{ - BM_HANDLE device_handle; - acpi_handle acpi_handle; - char uid[9]; - u32 is_online; -} AC_CONTEXT; - - -/***************************************************************************** - * Function Prototypes - *****************************************************************************/ - -acpi_status -ac_initialize (void); - -acpi_status -ac_terminate (void); - -acpi_status -ac_notify ( - u32 notify_type, - u32 device, - void **context); - -acpi_status -ac_request( - BM_REQUEST *request_info, - void *context); - -/* AC Adapter Driver OSL */ - -acpi_status -ac_osl_add_device ( - AC_CONTEXT *ac_adapter); - -acpi_status -ac_osl_remove_device ( - AC_CONTEXT *ac_adapter); - -acpi_status -ac_osl_generate_event ( - u32 event, - AC_CONTEXT *ac_adapter); - - -#endif /* __AC_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/bm.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bm.h --- linux-2.4.19/drivers/acpi/ospm/include/bm.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bm.h Wed Dec 31 16:00:00 1969 @@ -1,583 +0,0 @@ -/***************************************************************************** - * - * Module name: bm.h - * $Revision: 41 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BM_H__ -#define __BM_H__ - -#include -#include - - -/***************************************************************************** - * Types & Defines - *****************************************************************************/ - -/* - * Output Flags (Debug): - * --------------------- - */ -#define BM_PRINT_ALL (0x00000000) -#define BM_PRINT_GROUP (0x00000001) -#define BM_PRINT_LINKAGE (0x00000002) -#define BM_PRINT_IDENTIFICATION (0x00000004) -#define BM_PRINT_POWER (0x00000008) -#define BM_PRINT_PRESENT (0x00000010) - - -/* - * BM_COMMAND: - * ----------- - */ -typedef u32 BM_COMMAND; - -#define BM_COMMAND_UNKNOWN ((BM_COMMAND) 0x00) - -#define BM_COMMAND_GET_POWER_STATE ((BM_COMMAND) 0x01) -#define BM_COMMAND_SET_POWER_STATE ((BM_COMMAND) 0x02) - -#define BM_COMMAND_DEVICE_SPECIFIC ((BM_COMMAND) 0x80) - -/* - * BM_NOTIFY: - * ---------- - * Standard ACPI notification values, from section 5.6.3 of the ACPI 2.0 - * specification. Note that the Bus Manager internally handles all - * standard ACPI notifications -- driver modules are never sent these - * values (see "Bus Manager Notifications", below). - */ -typedef u32 BM_NOTIFY; - -#define BM_NOTIFY_BUS_CHECK ((BM_NOTIFY) 0x00) -#define BM_NOTIFY_DEVICE_CHECK ((BM_NOTIFY) 0x01) -#define BM_NOTIFY_DEVICE_WAKE ((BM_NOTIFY) 0x02) -#define BM_NOTIFY_EJECT_REQUEST ((BM_NOTIFY) 0x03) -#define BM_NOTIFY_DEVICE_CHECK_LIGHT ((BM_NOTIFY) 0x04) -#define BM_NOTIFY_FREQUENCY_MISMATCH ((BM_NOTIFY) 0x05) -#define BM_NOTIFY_BUS_MODE_MISMATCH ((BM_NOTIFY) 0x06) -#define BM_NOTIFY_POWER_FAULT ((BM_NOTIFY) 0x07) - -/* - * These are a higher-level abstraction of ACPI notifications, intended - * for consumption by driver modules to facilitate Pn_p. - */ -#define BM_NOTIFY_UNKNOWN ((BM_NOTIFY) 0x00) -#define BM_NOTIFY_DEVICE_ADDED ((BM_NOTIFY) 0x01) -#define BM_NOTIFY_DEVICE_REMOVED ((BM_NOTIFY) 0x02) - - -/* - * BM_HANDLE: - * ---------- - */ -typedef u32 BM_HANDLE; - -#define BM_HANDLE_ROOT ((BM_HANDLE) 0x00000000) -#define BM_HANDLE_UNKNOWN ((BM_HANDLE) 0xFFFFFFFF) -#define BM_HANDLES_MAX 100 - - -/* - * BM_HANDLE_LIST: - * --------------- - */ -typedef struct -{ - u32 count; - BM_HANDLE handles[BM_HANDLES_MAX]; -} BM_HANDLE_LIST; - - -/* - * BM_DEVICE_TYPE: - * --------------- - */ -typedef u32 BM_DEVICE_TYPE; - -#define BM_TYPE_UNKNOWN ((BM_DEVICE_TYPE) 0x00000000) - -#define BM_TYPE_SYSTEM ((BM_DEVICE_TYPE) 0x00000001) -#define BM_TYPE_SCOPE ((BM_DEVICE_TYPE) 0x00000002) -#define BM_TYPE_PROCESSOR ((BM_DEVICE_TYPE) 0x00000003) -#define BM_TYPE_THERMAL_ZONE ((BM_DEVICE_TYPE) 0x00000004) -#define BM_TYPE_POWER_RESOURCE ((BM_DEVICE_TYPE) 0x00000005) -#define BM_TYPE_DEVICE ((BM_DEVICE_TYPE) 0x00000006) -#define BM_TYPE_FIXED_BUTTON ((BM_DEVICE_TYPE) 0x00000007) - - -/* - * BM_DEVICE_UID: - * -------------- - */ -typedef char BM_DEVICE_UID[9]; - -#define BM_UID_UNKNOWN '0' - - -/* - * BM_DEVICE_HID: - * -------------- - */ -typedef char BM_DEVICE_HID[9]; - -#define BM_HID_UNKNOWN '\0' -#define BM_HID_POWER_BUTTON "PNP0C0C" -#define BM_HID_SLEEP_BUTTON "PNP0C0E" - -/* - * BM_DEVICE_ADR: - * -------------- - */ -typedef u32 BM_DEVICE_ADR; - -#define BM_ADDRESS_UNKNOWN 0 - - -/* - * BM_DEVICE_FLAGS: - * ---------------- - * The encoding of BM_DEVICE_FLAGS is illustrated below. - * Note that a set bit (1) indicates the property is TRUE - * (e.g. if bit 0 is set then the device has dynamic status). - * +--+------------+-+-+-+-+-+-+-+ - * |31| Bits 30:7 |6|5|4|3|2|1|0| - * +--+------------+-+-+-+-+-+-+-+ - * | | | | | | | | | - * | | | | | | | | +- Dynamic status? - * | | | | | | | +--- Identifiable? - * | | | | | | +----- Configurable? - * | | | | | +------- Power Control? - * | | | | +--------- Ejectable? - * | | | +----------- Docking Station? - * | | +------------- Fixed-Feature? - * | +-------------------- - * +---------------------------- Driver Control? - * - * Dynamic status: Device has a _STA object. - * Identifiable: Device has a _HID and/or _ADR and possibly other - * identification objects defined. - * Configurable: Device has a _CRS and possibly other configuration - * objects defined. - * Power Control: Device has a _PR0 and/or _PS0 and possibly other - * power management objects defined. - * Ejectable: Device has an _EJD and/or _EJx and possibly other - * dynamic insertion/removal objects defined. - * Docking Station: Device has a _DCK object defined. - * Fixed-Feature: Device does not exist in the namespace; was - * enumerated as a fixed-feature (e.g. power button). - * Driver Control: A driver has been installed for this device. - */ -typedef u32 BM_DEVICE_FLAGS; - -#define BM_FLAGS_UNKNOWN ((BM_DEVICE_FLAGS) 0x00000000) - -#define BM_FLAGS_DYNAMIC_STATUS ((BM_DEVICE_FLAGS) 0x00000001) -#define BM_FLAGS_IDENTIFIABLE ((BM_DEVICE_FLAGS) 0x00000002) -#define BM_FLAGS_CONFIGURABLE ((BM_DEVICE_FLAGS) 0x00000004) -#define BM_FLAGS_POWER_CONTROL ((BM_DEVICE_FLAGS) 0x00000008) -#define BM_FLAGS_EJECTABLE ((BM_DEVICE_FLAGS) 0x00000010) -#define BM_FLAGS_DOCKING_STATION ((BM_DEVICE_FLAGS) 0x00000020) -#define BM_FLAGS_FIXED_FEATURE ((BM_DEVICE_FLAGS) 0x00000040) -#define BM_FLAGS_DRIVER_CONTROL ((BM_DEVICE_FLAGS) 0x80000000) - - -/* - * Device PM Flags: - * ---------------- - * +-----------+-+-+-+-+-+-+-+ - * | Bits 31:7 |6|5|4|3|2|1|0| - * +-----------+-+-+-+-+-+-+-+ - * | | | | | | | | - * | | | | | | | +- D0 Support? - * | | | | | | +--- D1 Support? - * | | | | | +----- D2 Support? - * | | | | +------- D3 Support? - * | | | +--------- Power State Queriable? - * | | +----------- Inrush Current? - * | +------------- Wake Capable? - * +-------------------- - * - * D0-D3 Support: Device supports corresponding Dx state. - * Power State: Device has a _PSC (current power state) object defined. - * Inrush Current: Device has an _IRC (inrush current) object defined. - * Wake Capable: Device has a _PRW (wake-capable) object defined. - */ -#define BM_FLAGS_D0_SUPPORT ((BM_DEVICE_FLAGS) 0x00000001) -#define BM_FLAGS_D1_SUPPORT ((BM_DEVICE_FLAGS) 0x00000002) -#define BM_FLAGS_D2_SUPPORT ((BM_DEVICE_FLAGS) 0x00000004) -#define BM_FLAGS_D3_SUPPORT ((BM_DEVICE_FLAGS) 0x00000008) -#define BM_FLAGS_POWER_STATE ((BM_DEVICE_FLAGS) 0x00000010) -#define BM_FLAGS_INRUSH_CURRENT ((BM_DEVICE_FLAGS) 0x00000020) -#define BM_FLAGS_WAKE_CAPABLE ((BM_DEVICE_FLAGS) 0x00000040) - - -/* - * BM_DEVICE_STATUS: - * ----------------- - * The encoding of BM_DEVICE_STATUS is illustrated below. - * Note that a set bit (1) indicates the property is TRUE - * (e.g. if bit 0 is set then the device is present). - * +-----------+-+-+-+-+-+ - * | Bits 31:4 |4|3|2|1|0| - * +-----------+-+-+-+-+-+ - * | | | | | | - * | | | | | +- Present? - * | | | | +--- Enabled? - * | | | +----- Show in UI? - * | | +------- Functioning? - * | +--------- Battery Present? - * +---------------- - */ -typedef u32 BM_DEVICE_STATUS; - -#define BM_STATUS_UNKNOWN ((BM_DEVICE_STATUS) 0x00000000) -#define BM_STATUS_PRESENT ((BM_DEVICE_STATUS) 0x00000001) -#define BM_STATUS_ENABLED ((BM_DEVICE_STATUS) 0x00000002) -#define BM_STATUS_SHOW_UI ((BM_DEVICE_STATUS) 0x00000004) -#define BM_STATUS_FUNCTIONING ((BM_DEVICE_STATUS) 0x00000008) -#define BM_STATUS_BATTERY_PRESENT ((BM_DEVICE_STATUS) 0x00000010) -#define BM_STATUS_DEFAULT ((BM_DEVICE_STATUS) 0x0000000F) - - -/* - * BM_POWER_STATE: - * --------------- - */ -typedef u32 BM_POWER_STATE; - - -/* - * BM_DEVICE_ID: - * ------------- - */ -typedef struct -{ - BM_DEVICE_TYPE type; - BM_DEVICE_UID uid; - BM_DEVICE_HID hid; - BM_DEVICE_ADR adr; -} BM_DEVICE_ID; - - -/* - * BM_DEVICE_POWER: - * ---------------- - * Structure containing basic device power management information. - */ -typedef struct -{ - BM_DEVICE_FLAGS flags; - BM_POWER_STATE state; - BM_DEVICE_FLAGS dx_supported[ACPI_S_STATE_COUNT]; -} BM_DEVICE_POWER; - - -/* - * BM_DEVICE: - * ---------- - */ -typedef struct -{ - BM_HANDLE handle; - acpi_handle acpi_handle; - BM_DEVICE_FLAGS flags; - BM_DEVICE_STATUS status; - BM_DEVICE_ID id; - BM_DEVICE_POWER power; -} BM_DEVICE; - - -/* - * BM_SEARCH: - * ---------- - * Structure used for searching the ACPI Bus Manager's device hierarchy. - */ -typedef struct -{ - BM_DEVICE_ID criteria; - BM_HANDLE_LIST results; -} BM_SEARCH; - - -/* - * BM_REQUEST: - * ----------- - * Structure used for sending requests to/through the ACPI Bus Manager. - */ -typedef struct -{ - acpi_status status; - BM_COMMAND command; - BM_HANDLE handle; - acpi_buffer buffer; -} BM_REQUEST; - - -/* - * Driver Registration: - * -------------------- - */ - -/* Driver Context */ -typedef void * BM_DRIVER_CONTEXT; - -/* Notification Callback Function */ -typedef -acpi_status (*BM_DRIVER_NOTIFY) ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - BM_DRIVER_CONTEXT *context); - -/* Request Callback Function */ -typedef -acpi_status (*BM_DRIVER_REQUEST) ( - BM_REQUEST *request, - BM_DRIVER_CONTEXT context); - -/* Driver Registration */ -typedef struct -{ - BM_DRIVER_NOTIFY notify; - BM_DRIVER_REQUEST request; - BM_DRIVER_CONTEXT context; -} BM_DRIVER; - - -/* - * BM_NODE: - * -------- - * Structure used to maintain the device hierarchy. - */ -typedef struct _BM_NODE -{ - BM_DEVICE device; - BM_DRIVER driver; - struct _BM_NODE *parent; - struct _BM_NODE *next; - struct - { - struct _BM_NODE *head; - struct _BM_NODE *tail; - } scope; -} BM_NODE; - - -/* - * BM_NODE_LIST: - * ------------- - * Structure used to maintain an array of node pointers. - */ -typedef struct -{ - u32 count; - BM_NODE *nodes[BM_HANDLES_MAX]; -} BM_NODE_LIST; - - -/***************************************************************************** - * Macros - *****************************************************************************/ - -/* - * Device Presence: - * ---------------- - * Note that status (_STA) means something different for power resources - * (they're assumed to always be present). - */ -#define BM_DEVICE_PRESENT(d) ((d->id.type!=BM_TYPE_POWER_RESOURCE)?(d->status & BM_STATUS_PRESENT):TRUE) -#define BM_NODE_PRESENT(n) ((n->device.id.type!=BM_TYPE_POWER_RESOURCE)?(n->device.status & BM_STATUS_PRESENT):TRUE) - -/* - * Device Flags: - * ------------- - */ -#define BM_IS_DRIVER_CONTROL(d) (d->flags & BM_FLAGS_DRIVER_CONTROL) -#define BM_IS_POWER_CONTROL(d) (d->flags & BM_FLAGS_POWER_CONTROL) - - /* - * Device Power Flags: - * ------------------- - */ -#define BM_IS_POWER_STATE(d) (d->power.flags & BM_FLAGS_POWER_STATE) - -/***************************************************************************** - * Function Prototypes - *****************************************************************************/ - -/* bm.c */ - -acpi_status -bm_initialize (void); - -acpi_status -bm_terminate (void); - -acpi_status -bm_get_status ( - BM_DEVICE *device); - -acpi_status -bm_get_handle ( - acpi_handle acpi_handle, - BM_HANDLE *device_handle); - -acpi_status -bm_get_node ( - BM_HANDLE device_handle, - acpi_handle acpi_handle, - BM_NODE **node); - -/* bmsearch.c */ - -acpi_status -bm_search( - BM_HANDLE device_handle, - BM_DEVICE_ID *criteria, - BM_HANDLE_LIST *results); - -/* bmnotify.c */ - -void -bm_notify ( - acpi_handle acpi_handle, - u32 notify_value, - void *context); - -/* bm_request.c */ - -acpi_status -bm_request ( - BM_REQUEST *request_info); - -/* bmdriver.c */ - -acpi_status -bm_get_device_power_state ( - BM_HANDLE device_handle, - BM_POWER_STATE *state); - -acpi_status -bm_set_device_power_state ( - BM_HANDLE device_handle, - BM_POWER_STATE state); - -acpi_status -bm_get_device_status ( - BM_HANDLE device_handle, - BM_DEVICE_STATUS *device_status); - -acpi_status -bm_get_device_info ( - BM_HANDLE device_handle, - BM_DEVICE **device_info); - -acpi_status -bm_get_device_context ( - BM_HANDLE device_handle, - BM_DRIVER_CONTEXT *context); - -acpi_status -bm_register_driver ( - BM_DEVICE_ID *criteria, - BM_DRIVER *driver); - -acpi_status -bm_unregister_driver ( - BM_DEVICE_ID *criteria, - BM_DRIVER *driver); - -/* bmpm.c */ - -acpi_status -bm_get_pm_capabilities ( - BM_NODE *node); - -acpi_status -bm_get_power_state ( - BM_NODE *node); - -acpi_status -bm_set_power_state ( - BM_NODE *node, - BM_POWER_STATE target_state); - -/* bmpower.c */ - -acpi_status -bm_pr_initialize (void); - -acpi_status -bm_pr_terminate (void); - -/* bmutils.c */ - -acpi_status -bm_cast_buffer ( - acpi_buffer *buffer, - void **pointer, - u32 length); - -acpi_status -bm_copy_to_buffer ( - acpi_buffer *buffer, - void *data, - u32 length); - -acpi_status -bm_extract_package_data ( - acpi_object *package, - acpi_buffer *format, - acpi_buffer *buffer); - -acpi_status -bm_evaluate_object ( - acpi_handle acpi_handle, - acpi_string pathname, - acpi_object_list *arguments, - acpi_buffer *buffer); - -acpi_status -bm_evaluate_simple_integer ( - acpi_handle acpi_handle, - acpi_string pathname, - u32 *data); - -acpi_status -bm_evaluate_reference_list ( - acpi_handle acpi_handle, - acpi_string pathname, - BM_HANDLE_LIST *reference_list); - -/* ACPI Bus Driver OSL */ - -acpi_status -bm_osl_generate_event ( - BM_HANDLE device_handle, - char *device_type, - char *device_instance, - u32 event_type, - u32 event_data); - - -#endif /* __BM_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/bmpower.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bmpower.h --- linux-2.4.19/drivers/acpi/ospm/include/bmpower.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bmpower.h Wed Dec 31 16:00:00 1969 @@ -1,75 +0,0 @@ -/***************************************************************************** - * - * Module name: bmpower.h - * $Revision: 9 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BMPOWER_H__ -#define __BMPOWER_H__ - -#include "bm.h" - - -/***************************************************************************** - * Types & Defines - *****************************************************************************/ - - -/* - * BM_POWER_RESOURCE: - * ------------------ - */ -typedef struct -{ - BM_HANDLE device_handle; - acpi_handle acpi_handle; - BM_POWER_STATE system_level; - u32 resource_order; - BM_POWER_STATE state; - u32 reference_count; -} BM_POWER_RESOURCE; - - -/***************************************************************************** - * Function Prototypes - *****************************************************************************/ - -/* bmpower.c */ - -acpi_status -bm_pr_initialize (void); - -acpi_status -bm_pr_terminate (void); - -acpi_status -bm_pr_list_get_state ( - BM_HANDLE_LIST *resource_list, - BM_POWER_STATE *power_state); - -acpi_status -bm_pr_list_transition ( - BM_HANDLE_LIST *current_list, - BM_HANDLE_LIST *target_list); - - -#endif /* __BMPOWER_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/bn.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bn.h --- linux-2.4.19/drivers/acpi/ospm/include/bn.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bn.h Wed Dec 31 16:00:00 1969 @@ -1,122 +0,0 @@ -/****************************************************************************** - * - * Module Name: bn.h - * $Revision: 12 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __BN_H__ -#define __BN_H__ - -#include -#include -#include - - -/***************************************************************************** - * Types & Other Defines - *****************************************************************************/ - -/* - * Notifications: - * --------------------- - */ -#define BN_NOTIFY_STATUS_CHANGE ((BM_NOTIFY) 0x80) - - -/* - * Types: - * ------ - */ -#define BN_TYPE_POWER_BUTTON 0x01 -#define BN_TYPE_POWER_BUTTON_FIXED 0x02 -#define BN_TYPE_SLEEP_BUTTON 0x03 -#define BN_TYPE_SLEEP_BUTTON_FIXED 0x04 -#define BN_TYPE_LID_SWITCH 0x05 - - -/* - * Hardware IDs: - * ------------- - * TBD: Power and Sleep button HIDs also exist in . Should all - * HIDs (ACPI well-known devices) exist in one place (e.g. - * acpi_hid.h)? - */ -#define BN_HID_POWER_BUTTON "PNP0C0C" -#define BN_HID_SLEEP_BUTTON "PNP0C0E" -#define BN_HID_LID_SWITCH "PNP0C0D" - - -/* - * Device Context: - * --------------- - */ -typedef struct -{ - BM_HANDLE device_handle; - acpi_handle acpi_handle; - u32 type; -} BN_CONTEXT; - - -/****************************************************************************** - * Function Prototypes - *****************************************************************************/ - -acpi_status -bn_initialize (void); - -acpi_status -bn_terminate (void); - -acpi_status -bn_notify_fixed ( - void *context); - -acpi_status -bn_notify ( - u32 notify_type, - u32 device, - void **context); - -acpi_status -bn_request( - BM_REQUEST *request_info, - void *context); - -/* Button OSL */ - -acpi_status -bn_osl_add_device ( - BN_CONTEXT *button); - -acpi_status -bn_osl_remove_device ( - BN_CONTEXT *button); - -acpi_status -bn_osl_generate_event ( - u32 event, - BN_CONTEXT *button); - - -#endif /* __BN_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/bt.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bt.h --- linux-2.4.19/drivers/acpi/ospm/include/bt.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/bt.h Wed Dec 31 16:00:00 1969 @@ -1,164 +0,0 @@ -/****************************************************************************** - * - * Module Name: bt.h - * $Revision: 18 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __BT_H__ -#define __BT_H__ - -#include -#include -#include - - -/***************************************************************************** - * Types & Other Defines - *****************************************************************************/ - -/*! [Begin] no source code translation */ - -#define BT_UNKNOWN 0xFFFFFFFF -#define BT_POWER_UNITS_DEFAULT "?" -#define BT_POWER_UNITS_WATTS "mW" -#define BT_POWER_UNITS_AMPS "mA" - -/*! [End] no source code translation !*/ - -/* - * Battery Notifications: - * ---------------------- - */ -#define BT_NOTIFY_STATUS_CHANGE ((BM_NOTIFY) 0x80) -#define BT_NOTIFY_INFORMATION_CHANGE ((BM_NOTIFY) 0x81) - - -/* - * Hardware IDs: - * ------------- - */ -#define BT_HID_CM_BATTERY "PNP0C0A" - - -/* - * BT_CM_BATTERY_INFO: - * ------------------- - */ -typedef struct -{ - acpi_integer power_unit; - acpi_integer design_capacity; - acpi_integer last_full_capacity; - acpi_integer battery_technology; - acpi_integer design_voltage; - acpi_integer design_capacity_warning; - acpi_integer design_capacity_low; - acpi_integer battery_capacity_granularity_1; - acpi_integer battery_capacity_granularity_2; - acpi_string model_number; - acpi_string serial_number; - acpi_string battery_type; - acpi_string oem_info; - -} BT_BATTERY_INFO; - - -/* - * BT_CM_BATTERY_STATUS: - * --------------------- - */ -typedef struct -{ - acpi_integer state; - acpi_integer present_rate; - acpi_integer remaining_capacity; - acpi_integer present_voltage; - -} BT_BATTERY_STATUS; - - -/* - * BT_CONTEXT: - * ----------- - */ -typedef struct -{ - BM_HANDLE device_handle; - acpi_handle acpi_handle; - char uid[9]; - acpi_string power_units; - u8 is_present; - -} BT_CONTEXT; - - -/***************************************************************************** - * Function Prototypes - *****************************************************************************/ - -/* bt.c */ - -acpi_status -bt_initialize (void); - -acpi_status -bt_terminate (void); - -acpi_status -bt_notify ( - u32 notify_type, - u32 device, - void **context); - -acpi_status -bt_request( - BM_REQUEST *request_info, - void *context); - -acpi_status -bt_get_status ( - BT_CONTEXT *battery, - BT_BATTERY_STATUS **battery_status); - -acpi_status -bt_get_info ( - BT_CONTEXT *battery, - BT_BATTERY_INFO **battery_info); - -/* Battery OSL */ - -acpi_status -bt_osl_add_device ( - BT_CONTEXT *battery); - -acpi_status -bt_osl_remove_device ( - BT_CONTEXT *battery); - -acpi_status -bt_osl_generate_event ( - u32 event, - BT_CONTEXT *battery); - - -#endif /* __BT_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/ec.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/ec.h --- linux-2.4.19/drivers/acpi/ospm/include/ec.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/ec.h Wed Dec 31 16:00:00 1969 @@ -1,202 +0,0 @@ -/***************************************************************************** - * - * Module Name: ec.h - * $Revision: 19 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __EC_H__ -#define __EC_H__ - -#include -#include -#include -#include -#include - - -/***************************************************************************** - * Types & Other Defines - *****************************************************************************/ - -#define EC_DEFAULT_TIMEOUT 1000 /* 1 second */ -#define EC_GPE_UNKNOWN 0xFFFFFFFF -#define EC_PORT_UNKNOWN 0x00000000 -#define EC_BURST_ENABLE_ACKNOWLEDGE 0x90 - - -/* - * Commands: - * --------- - */ -typedef u8 EC_COMMAND; - -#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00) -#define EC_COMMAND_READ ((EC_COMMAND) 0x80) -#define EC_COMMAND_WRITE ((EC_COMMAND) 0x81) -#define EC_COMMAND_QUERY ((EC_COMMAND) 0x84) - - -/* - * EC_STATUS: - * ---------- - * The encoding of the EC status register is illustrated below. - * Note that a set bit (1) indicates the property is TRUE - * (e.g. if bit 0 is set then the output buffer is full). - * +-+-+-+-+-+-+-+-+ - * |7|6|5|4|3|2|1|0| - * +-+-+-+-+-+-+-+-+ - * | | | | | | | | - * | | | | | | | +- Output Buffer Full (OBF)? - * | | | | | | +--- Input Buffer Full (IBF)? - * | | | | | +----- - * | | | | +------- data Register is command Byte? - * | | | +--------- Burst Mode Enabled? - * | | +----------- SCI event? - * | +------------- SMI event? - * +--------------- - * - */ -typedef u32 EC_STATUS; - -#define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01) -#define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02) -#define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10) -#define EC_FLAG_SCI ((EC_STATUS) 0x20) - - -/* - * EC_EVENT: - * --------- - */ -typedef u32 EC_EVENT; - -#define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00) -#define EC_EVENT_NONE ((EC_EVENT) 0x00) -#define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01) -#define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02) -#define EC_EVENT_SCI ((EC_EVENT) 0x03) - - -/* - * Hardware IDs: - * ------------- - */ -#define EC_HID_EC "PNP0C09" - - -/* - * EC_REQUEST: - * ----------- - */ -typedef struct -{ - EC_COMMAND command; - u8 address; - u8 data; -} EC_REQUEST; - - -/* - * Device Context: - * --------------- - */ -typedef struct -{ - BM_HANDLE device_handle; - acpi_handle acpi_handle; - u32 gpe_bit; - u32 status_port; - u32 command_port; - u32 data_port; - u32 use_global_lock; - u8 query_data; - acpi_handle mutex; -} EC_CONTEXT; - - -/***************************************************************************** - * Function Prototypes - *****************************************************************************/ - -/* ec.c */ - -acpi_status -ec_initialize(void); - -acpi_status -ec_terminate(void); - -acpi_status -ec_notify ( - u32 notify_type, - u32 device, - void **context); - -acpi_status -ec_request( - BM_REQUEST *request_info, - void *context); - -/* ectransx.c */ - -acpi_status -ec_transaction ( - EC_CONTEXT *ec, - EC_REQUEST *ec_request); - -acpi_status -ec_io_read ( - EC_CONTEXT *ec, - u32 io_port, - u8 *data, - EC_EVENT wait_event); - -acpi_status -ec_io_write ( - EC_CONTEXT *ec, - u32 io_port, - u8 data, - EC_EVENT wait_event); - -/* ecgpe.c */ - -acpi_status -ec_install_gpe_handler ( - EC_CONTEXT *ec); - -acpi_status -ec_remove_gpe_handler ( - EC_CONTEXT *ec); - -/* ecspace.c */ - -acpi_status -ec_install_space_handler ( - EC_CONTEXT *ec); - -acpi_status -ec_remove_space_handler ( - EC_CONTEXT *ec); - - -#endif /* __EC_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/pr.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/pr.h --- linux-2.4.19/drivers/acpi/ospm/include/pr.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/pr.h Wed Dec 31 16:00:00 1969 @@ -1,265 +0,0 @@ -/****************************************************************************** - * - * Module Name: processor.h - * $Revision: 13 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PR_H__ -#define __PR_H__ - -#include - - -/***************************************************************************** - * Types & Other Defines - *****************************************************************************/ - - -#define PR_MAX_POWER_STATES 4 -#define PR_MAX_THROTTLE_STATES 8 -#define PR_MAX_PERF_STATES 32 -#define PR_MAX_C2_LATENCY 100 -#define PR_MAX_C3_LATENCY 1000 - - -/* - * Commands: - * --------- - */ -#define PR_COMMAND_GET_POWER_INFO ((BM_COMMAND) 0x80) -#define PR_COMMAND_SET_POWER_INFO ((BM_COMMAND) 0x81) -#define PR_COMMAND_GET_PERF_INFO ((BM_COMMAND) 0x82) -#define PR_COMMAND_GET_PERF_STATE ((BM_COMMAND) 0x83) -#define PR_COMMAND_SET_PERF_LIMIT ((BM_COMMAND) 0x84) - - -/* - * Notifications: - * -------------- - */ -#define PR_NOTIFY_PERF_STATES ((BM_NOTIFY) 0x80) -#define PR_NOTIFY_POWER_STATES ((BM_NOTIFY) 0x81) - - -/* - * Performance Control: - * -------------------- - */ -#define PR_PERF_DEC 0x00 -#define PR_PERF_INC 0x01 -#define PR_PERF_MAX 0xFF - - -/* - * Power States: - * ------------- - */ -#define PR_C0 0x00 -#define PR_C1 0x01 -#define PR_C2 0x02 -#define PR_C3 0x03 - -#define PR_C1_FLAG 0x01; -#define PR_C2_FLAG 0x02; -#define PR_C3_FLAG 0x04; - - -/* - * PR_CX_POLICY_VALUES: - * -------------------- - */ -typedef struct -{ - u32 time_threshold; - u32 count_threshold; - u32 bm_threshold; - u32 target_state; - u32 count; -} PR_CX_POLICY_VALUES; - - -/* - * PR_CX: - * ------ - */ -typedef struct -{ - u32 latency; - u32 utilization; - u8 is_valid; - PR_CX_POLICY_VALUES promotion; - PR_CX_POLICY_VALUES demotion; -} PR_CX; - - -/* - * PR_POWER: - * --------- - */ -typedef struct -{ - ACPI_PHYSICAL_ADDRESS p_lvl2; - ACPI_PHYSICAL_ADDRESS p_lvl3; - u32 bm_activity; - u32 active_state; - u32 default_state; - u32 busy_metric; - u32 state_count; - PR_CX state[PR_MAX_POWER_STATES]; -} PR_POWER; - - -/* - * PR_PERFORMANCE_STATE: - * --------------------- - */ -typedef struct -{ - u32 performance; - u32 power; -} PR_PERFORMANCE_STATE; - - -/* - * PR_PERFORMANCE: - * --------------- - */ -typedef struct -{ - u32 active_state; - u32 thermal_limit; - u32 power_limit; - u32 state_count; - PR_PERFORMANCE_STATE state[PR_MAX_PERF_STATES]; -} PR_PERFORMANCE; - - -/* - * PR_PBLOCK: - * ---------- - */ -typedef struct -{ - u32 length; - ACPI_PHYSICAL_ADDRESS address; -} PR_PBLOCK; - - -/* - * PR_CONTEXT: - * ----------- - */ -typedef struct -{ - BM_HANDLE device_handle; - acpi_handle acpi_handle; - u32 uid; - PR_PBLOCK pblk; - PR_POWER power; - PR_PERFORMANCE performance; -} PR_CONTEXT; - - -/****************************************************************************** - * Function Prototypes - *****************************************************************************/ - -/* processor.c */ - -acpi_status -pr_initialize(void); - -acpi_status -pr_terminate(void); - -acpi_status -pr_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context); - -acpi_status -pr_request( - BM_REQUEST *request, - void *context); - -/* prpower.c */ - -void -pr_power_idle (void); - -acpi_status -pr_power_add_device ( - PR_CONTEXT *processor); - -acpi_status -pr_power_remove_device ( - PR_CONTEXT *processor); - -acpi_status -pr_power_initialize (void); - -acpi_status -pr_power_terminate (void); - -/* prperf.c */ - -acpi_status -pr_perf_get_state ( - PR_CONTEXT *processor, - u32 *state); - -acpi_status -pr_perf_set_state ( - PR_CONTEXT *processor, - u32 state); - -acpi_status -pr_perf_set_limit ( - PR_CONTEXT *processor, - u32 limit); - -acpi_status -pr_perf_add_device ( - PR_CONTEXT *processor); - -acpi_status -pr_perf_remove_device ( - PR_CONTEXT *processor); - -/* Processor Driver OSL */ - -acpi_status -pr_osl_add_device ( - PR_CONTEXT *processor); - -acpi_status -pr_osl_remove_device ( - PR_CONTEXT *processor); - -acpi_status -pr_osl_generate_event ( - u32 event, - PR_CONTEXT *processor); - - -#endif /* __PR_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/sm.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/sm.h --- linux-2.4.19/drivers/acpi/ospm/include/sm.h Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/sm.h Wed Dec 31 16:00:00 1969 @@ -1,91 +0,0 @@ -/***************************************************************************** - * - * Module Name: sm.h - * $Revision: 3 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __SM_H__ -#define __SM_H__ - -#include -#include -#include - - -/***************************************************************************** - * Types & Other Defines - *****************************************************************************/ - -#define SM_MAX_SYSTEM_STATES 6 /* S0-S5 */ - - - /* - * Device Context: - * --------------- - */ -typedef struct -{ - BM_HANDLE device_handle; - acpi_handle acpi_handle; - u8 states[SM_MAX_SYSTEM_STATES]; -} SM_CONTEXT; - - -/***************************************************************************** - * Function Prototypes - *****************************************************************************/ - -acpi_status -sm_initialize (void); - -acpi_status -sm_terminate (void); - -acpi_status -sm_notify ( - u32 notify_type, - u32 device, - void **context); - -acpi_status -sm_request( - BM_REQUEST *request_info, - void *context); - -/* System Driver OSL */ - -acpi_status -sm_osl_add_device ( - SM_CONTEXT *system); - -acpi_status -sm_osl_remove_device ( - SM_CONTEXT *system); - -acpi_status -sm_osl_generate_event ( - u32 event, - SM_CONTEXT *system); - - -#endif /* __SM_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/include/tz.h linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/tz.h --- linux-2.4.19/drivers/acpi/ospm/include/tz.h Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/include/tz.h Wed Dec 31 16:00:00 1969 @@ -1,252 +0,0 @@ -/***************************************************************************** - * - * Module Name: tz.h - * $Revision: 24 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __TZ_H__ -#define __TZ_H__ - -/* TBD: Linux-specific */ -#include -#include - -#include -#include - - -/***************************************************************************** - * Types & Other Defines - *****************************************************************************/ - -#define TZ_MAX_THRESHOLDS 12 /* _AC0 through _AC9 + _CRT + _PSV */ -#define TZ_MAX_ACTIVE_THRESHOLDS 10 /* _AC0 through _AC9 */ -#define TZ_MAX_COOLING_DEVICES 10 /* TBD: Make size dynamic */ - - -/* - * Notifications: - * -------------- - */ -#define TZ_NOTIFY_TEMPERATURE_CHANGE ((BM_NOTIFY) 0x80) -#define TZ_NOTIFY_THRESHOLD_CHANGE ((BM_NOTIFY) 0x81) -#define TZ_NOTIFY_DEVICE_LISTS_CHANGE ((BM_NOTIFY) 0x82) - - -/* - * TZ_THRESHOLD_TYPE: - * ------------------ - */ -typedef u32 TZ_THRESHOLD_TYPE; - -#define TZ_THRESHOLD_UNKNOWN ((TZ_THRESHOLD_TYPE) 0x00) -#define TZ_THRESHOLD_CRITICAL ((TZ_THRESHOLD_TYPE) 0x01) - -#define TZ_THRESHOLD_PASSIVE ((TZ_THRESHOLD_TYPE) 0x02) -#define TZ_THRESHOLD_ACTIVE ((TZ_THRESHOLD_TYPE) 0x03) - - -/* - * TZ_COOLING_STATE: - * ----------------- - */ -typedef u32 TZ_COOLING_STATE; - -#define TZ_COOLING_UNKNOWN ((TZ_COOLING_STATE) 0x00) -#define TZ_COOLING_ENABLED ((TZ_COOLING_STATE) 0x01) -#define TZ_COOLING_DISABLED ((TZ_COOLING_STATE) 0x02) - - -/* - * TZ_COOLING_MODE: - * ---------------- - */ -typedef u32 TZ_COOLING_MODE; - -#define TZ_COOLING_MODE_ACTIVE ((TZ_COOLING_MODE) 0x00) -#define TZ_COOLING_MODE_PASSIVE ((TZ_COOLING_MODE) 0x01) - - -/* - * Thermal State: - * -------------- - * The encoding of TZ_STATE is illustrated below. - * Note that a set bit (1) indicates the property is TRUE - * (e.g. if bit 0 is set then the device has dynamic status). - * No bits set indicates an OK cooling state. - * +--+--+--+-----------+----------+ - * |31|30|29| Bits 27:4 | Bits 3:0 | - * +--+--+--+-----------+----------+ - * | | | | | - * | | | | +------ Active Index - * | | | +----------------- - * | | +------------------------- Active - * | +---------------------------- Passive - * +------------------------------- Critical - * - * Active Index: Value representing the level of active cooling - * presently applied (e.g. 0=_AL0, 9=_AL9). Only - * valid when 'Active' is set. - * Active: If set, indicates that the system temperature - * has crossed at least one active threshold (_ALx). - * Passive: If set, indicates that the system temperature - * has crossed the passive threshold (_PSL). - * Passive: If set, indicates that the system temperature - * has crossed the critical threshold (_CRT). - */ -typedef u32 TZ_STATE; - -#define TZ_STATE_OK ((TZ_STATE) 0x00000000) -#define TZ_STATE_HOT ((TZ_STATE) 0x10000000) -#define TZ_STATE_ACTIVE ((TZ_STATE) 0x20000000) -#define TZ_STATE_PASSIVE ((TZ_STATE) 0x40000000) -#define TZ_STATE_CRITICAL ((TZ_STATE) 0x80000000) - -typedef struct { - u32 temperature; -} TZ_CRITICAL_THRESHOLD; - -typedef struct { - u8 is_valid; - u32 temperature; -} TZ_HOT_THRESHOLD; - -typedef struct { - u8 is_valid; - u32 temperature; - u32 tc1; - u32 tc2; - u32 tsp; - BM_HANDLE_LIST devices; -} TZ_PASSIVE_THRESHOLD; - -typedef struct { - u8 is_valid; - u32 temperature; - TZ_COOLING_STATE cooling_state; - BM_HANDLE_LIST devices; -} TZ_ACTIVE_THRESHOLD; - -typedef struct { - TZ_CRITICAL_THRESHOLD critical; - TZ_HOT_THRESHOLD hot; - TZ_PASSIVE_THRESHOLD passive; - TZ_ACTIVE_THRESHOLD active[TZ_MAX_ACTIVE_THRESHOLDS]; -} TZ_THRESHOLDS; - -/* - * TZ_POLICY: - * --------- - */ -typedef struct { - u32 temperature; - TZ_STATE state; - TZ_COOLING_MODE cooling_mode; - u32 polling_freq; - TZ_THRESHOLDS thresholds; - struct timer_list timer; -} TZ_POLICY; - - -/* - * TZ_CONTEXT: - * ----------- - */ -typedef struct { - BM_HANDLE device_handle; - acpi_handle acpi_handle; - char uid[9]; - TZ_POLICY policy; -} TZ_CONTEXT; - - -/***************************************************************************** - * Function Prototypes - *****************************************************************************/ - -/* tz.c */ - -acpi_status -tz_initialize (void); - -acpi_status -tz_terminate (void); - -acpi_status -tz_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - BM_DRIVER_CONTEXT *context); - -acpi_status -tz_request ( - BM_REQUEST *request, - BM_DRIVER_CONTEXT context); - -acpi_status -tz_get_temperature ( - TZ_CONTEXT *tz); - -acpi_status -tz_get_thresholds ( - TZ_CONTEXT *tz); - -acpi_status -tz_set_cooling_preference ( - TZ_CONTEXT *tz, - TZ_COOLING_MODE cooling_mode); - -void -tz_print ( - TZ_CONTEXT *tz); - -/* tzpolicy.c */ - -acpi_status -tz_policy_add_device ( - TZ_CONTEXT *tz); - -acpi_status -tz_policy_remove_device ( - TZ_CONTEXT *tz); - -void -tz_policy_check ( - void *context); - -/* tz_osl.c */ - -acpi_status -tz_osl_add_device ( - TZ_CONTEXT *tz); - -acpi_status -tz_osl_remove_device ( - TZ_CONTEXT *tz); - -acpi_status -tz_osl_generate_event ( - u32 event, - TZ_CONTEXT *tz); - - -#endif /* __TZ_H__ */ diff -Nur linux-2.4.19/drivers/acpi/ospm/processor/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/Makefile --- linux-2.4.19/drivers/acpi/ospm/processor/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/Makefile Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/processor/pr.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/pr.c --- linux-2.4.19/drivers/acpi/ospm/processor/pr.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/pr.c Wed Dec 31 16:00:00 1969 @@ -1,497 +0,0 @@ -/***************************************************************************** - * - * Module Name: pr.c - * $Revision: 34 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include "pr.h" - - -#define _COMPONENT ACPI_PROCESSOR - MODULE_NAME ("pr") - - -/**************************************************************************** - * Globals - ****************************************************************************/ - -extern fadt_descriptor_rev2 acpi_fadt; - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: pr_print - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Prints out information on a specific thermal zone. - * - ****************************************************************************/ - -void -pr_print ( - PR_CONTEXT *processor) -{ -#ifdef ACPI_DEBUG - acpi_buffer buffer; - - FUNCTION_TRACE("pr_print"); - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - /* - * Get the full pathname for this ACPI object. - */ - acpi_get_name(processor->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - /* - * Print out basic processor information. - */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Processor[%02x]:[%p] uid[%02x] %s\n", processor->device_handle, processor->acpi_handle, processor->uid, (char*)buffer.pointer)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| power: %cC0 %cC1 %cC2[%d] %cC3[%d]\n", (processor->power.state[0].is_valid?'+':'-'), (processor->power.state[1].is_valid?'+':'-'), (processor->power.state[2].is_valid?'+':'-'), processor->power.state[2].latency, (processor->power.state[3].is_valid?'+':'-'), processor->power.state[3].latency)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| performance: states[%d]\n", processor->performance.state_count)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); -#endif /* ACPI_DEBUG */ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: pr_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_add_device( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - PR_CONTEXT *processor = NULL; - BM_DEVICE *device = NULL; - acpi_buffer buffer; - acpi_object acpi_object; - static u32 processor_count = 0; - - - FUNCTION_TRACE("pr_add_device"); - - if (!context || *context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - status = bm_get_device_info(device_handle, &device); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - processor = acpi_os_callocate(sizeof(PR_CONTEXT)); - if (!processor) { - return AE_NO_MEMORY; - } - - processor->device_handle = device->handle; - processor->acpi_handle = device->acpi_handle; - - /* - * Processor Block: - * ---------------- - */ - memset(&acpi_object, 0, sizeof(acpi_object)); - - buffer.length = sizeof(acpi_object); - buffer.pointer = &acpi_object; - - status = acpi_evaluate_object(processor->acpi_handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) { - goto end; - } - - /* - * Processor ID: - * ------------- - * TBD: We need to synchronize the processor ID values in ACPI - * with those of the APIC. For example, an IBM T20 has a - * proc_id value of '1', where the Linux value for the - * first CPU on this system is '0'. Since x86 CPUs are - * mapped 1:1 we can simply use a zero-based counter. Note - * that this assumes that processor objects are enumerated - * in the proper order. - */ - /* processor->uid = acpi_object.processor.proc_id; */ - processor->uid = processor_count++; - - processor->pblk.length = acpi_object.processor.pblk_length; - processor->pblk.address = acpi_object.processor.pblk_address; - - status = pr_power_add_device(processor); - if (ACPI_FAILURE(status)) { - goto end; - } - - status = pr_perf_add_device(processor); - if (ACPI_FAILURE(status)) { - goto end; - } - - status = pr_osl_add_device(processor); - if (ACPI_FAILURE(status)) { - goto end; - } - - *context = processor; - - pr_print(processor); - -end: - if (ACPI_FAILURE(status)) { - acpi_os_free(processor); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: pr_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_remove_device ( - void **context) -{ - acpi_status status = AE_OK; - PR_CONTEXT *processor= NULL; - - FUNCTION_TRACE("pr_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - processor = (PR_CONTEXT*)(*context); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing processor device [%02x].\n", processor->device_handle)); - - pr_osl_remove_device(processor); - - pr_perf_remove_device(processor); - - pr_power_remove_device(processor); - - acpi_os_free(processor); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: pr_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_initialize (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("pr_initialize"); - - memset(&criteria, 0, sizeof(BM_DEVICE_ID)); - memset(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Initialize power (Cx state) policy. - */ - status = pr_power_initialize(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Register driver for processor devices. - */ - criteria.type = BM_TYPE_PROCESSOR; - - driver.notify = &pr_notify; - driver.request = &pr_request; - - status = bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: pr_terminate - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_terminate (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("pr_terminate"); - - memset(&criteria, 0, sizeof(BM_DEVICE_ID)); - memset(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Terminate power (Cx state) policy. - */ - status = pr_power_terminate(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Unegister driver for processor devices. - */ - criteria.type = BM_TYPE_PROCESSOR; - - driver.notify = &pr_notify; - driver.request = &pr_request; - - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: pr_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - PR_CONTEXT *processor = NULL; - - FUNCTION_TRACE("pr_notify"); - - processor = (PR_CONTEXT*)*context; - - switch (notify_type) { - - case BM_NOTIFY_DEVICE_ADDED: - status = pr_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = pr_remove_device(context); - break; - - case PR_NOTIFY_PERF_STATES: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Performance states change event detected on processor [%02x].\n", device_handle)); - /* TBD: Streamline (this is simple but overkill). */ - status = pr_perf_remove_device(processor); - if (ACPI_SUCCESS(status)) { - status = pr_perf_add_device(processor); - } - if (ACPI_SUCCESS(status)) { - status = pr_osl_generate_event(notify_type, - (processor)); - } - break; - - case PR_NOTIFY_POWER_STATES: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Power states change event detected on processor [%02x].\n", device_handle)); - /* TBD: Streamline (this is simple but overkill). */ - status = pr_power_remove_device(processor); - if (ACPI_SUCCESS(status)) { - status = pr_power_add_device(processor); - } - if (ACPI_SUCCESS(status)) { - status = pr_osl_generate_event(notify_type, - (processor)); - } - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: pr_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - PR_CONTEXT *processor = NULL; - - FUNCTION_TRACE("pr_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - processor = (PR_CONTEXT*)context; - - /* - * Handle request: - * --------------- - */ - switch (request->command) { - - case PR_COMMAND_GET_POWER_INFO: - status = bm_copy_to_buffer(&(request->buffer), - &(processor->power), sizeof(PR_POWER)); - break; - - case PR_COMMAND_SET_POWER_INFO: - { - PR_POWER *power_info = NULL; - u32 i = 0; - - status = bm_cast_buffer(&(request->buffer), - (void**)&power_info, sizeof(PR_POWER)); - if (ACPI_SUCCESS(status)) { - for (i=0; ipower.state_count; i++) { - MEMCPY(&(processor->power.state[i].promotion), - &(power_info->state[i].promotion), - sizeof(PR_CX_POLICY_VALUES)); - MEMCPY(&(processor->power.state[i].demotion), - &(power_info->state[i].demotion), - sizeof(PR_CX_POLICY_VALUES)); - } - } - } - break; - - case PR_COMMAND_GET_PERF_INFO: - status = bm_copy_to_buffer(&(request->buffer), - &(processor->performance), sizeof(PR_PERFORMANCE)); - break; - - case PR_COMMAND_GET_PERF_STATE: - status = bm_copy_to_buffer(&(request->buffer), - &(processor->performance.active_state), sizeof(u32)); - break; - - case PR_COMMAND_SET_PERF_LIMIT: - { - u32 *limit = NULL; - - status = bm_cast_buffer(&(request->buffer), - (void**)&limit, sizeof(u32)); - if (ACPI_SUCCESS(status)) { - status = pr_perf_set_limit(processor, *limit); - } - } - break; - - default: - status = AE_SUPPORT; - break; - } - - request->status = status; - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/processor/pr_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/pr_osl.c --- linux-2.4.19/drivers/acpi/ospm/processor/pr_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/pr_osl.c Wed Dec 31 16:00:00 1969 @@ -1,344 +0,0 @@ -/****************************************************************************** - * - * Module Name: pr_osl.c - * $Revision: 21 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "pr.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - IA32 Processor Driver"); -MODULE_LICENSE("GPL"); - - -#define PR_PROC_ROOT "processor" -#define PR_PROC_STATUS "status" -#define PR_PROC_INFO "info" - -extern struct proc_dir_entry *bm_proc_root; -static struct proc_dir_entry *pr_proc_root = NULL; -extern unsigned short acpi_piix4_bmisx; - - -/**************************************************************************** - * - * FUNCTION: pr_osl_proc_read_status - * - ****************************************************************************/ - -static int -pr_osl_proc_read_status ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - PR_CONTEXT *processor = NULL; - char *p = page; - int len = 0; - - if (!context || (off != 0)) { - goto end; - } - - processor = (PR_CONTEXT*)context; - - p += sprintf(p, "Bus Mastering Activity: %08x\n", - processor->power.bm_activity); - - p += sprintf(p, "C-State Utilization: C1[%d] C2[%d] C3[%d]\n", - processor->power.state[PR_C1].utilization, - processor->power.state[PR_C2].utilization, - processor->power.state[PR_C3].utilization); - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - return(len); -} - - -/**************************************************************************** - * - * FUNCTION: pr_osl_proc_read_info - * - ****************************************************************************/ - -static int -pr_osl_proc_read_info ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - PR_CONTEXT *processor = NULL; - char *p = page; - int len = 0; - - if (!context || (off != 0)) { - goto end; - } - - processor = (PR_CONTEXT*)context; - - p += sprintf(p, "\n"); - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - return(len); -} - - -/**************************************************************************** - * - * FUNCTION: pr_osl_add_device - * - ****************************************************************************/ - -acpi_status -pr_osl_add_device( - PR_CONTEXT *processor) -{ - u32 i = 0; - struct proc_dir_entry *proc_entry = NULL, *proc; - char processor_uid[16]; - - if (!processor) { - return(AE_BAD_PARAMETER); - } - - printk("Processor[%x]:", processor->uid); - for (i=0; ipower.state_count; i++) { - if (processor->power.state[i].is_valid) { - printk(" C%d", i); - } - } - if (processor->performance.state_count > 1) - printk(", %d throttling states", processor->performance.state_count); - if (acpi_piix4_bmisx && processor->power.state[3].is_valid) - printk(" (PIIX errata enabled)"); - printk("\n"); - - sprintf(processor_uid, "%d", processor->uid); - - proc_entry = proc_mkdir(processor_uid, pr_proc_root); - if (!proc_entry) - return(AE_ERROR); - - proc = create_proc_read_entry(PR_PROC_STATUS, S_IFREG | S_IRUGO, - proc_entry, pr_osl_proc_read_status, (void*)processor); - if (!proc_entry) - return(AE_ERROR); - - proc = create_proc_read_entry(PR_PROC_INFO, S_IFREG | S_IRUGO, - proc_entry, pr_osl_proc_read_info, (void*)processor); - if (!proc_entry) - return(AE_ERROR); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: pr_osl_remove_device - * - ****************************************************************************/ - -acpi_status -pr_osl_remove_device ( - PR_CONTEXT *processor) -{ - char proc_entry[64]; - - if (!processor) { - return(AE_BAD_PARAMETER); - } - - sprintf(proc_entry, "%d/%s", processor->uid, PR_PROC_INFO); - remove_proc_entry(proc_entry, pr_proc_root); - - sprintf(proc_entry, "%d/%s", processor->uid, PR_PROC_STATUS); - remove_proc_entry(proc_entry, pr_proc_root); - - sprintf(proc_entry, "%d", processor->uid); - remove_proc_entry(proc_entry, pr_proc_root); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: pr_osl_generate_event - * - ****************************************************************************/ - -acpi_status -pr_osl_generate_event ( - u32 event, - PR_CONTEXT *processor) -{ - acpi_status status = AE_OK; - char processor_uid[16]; - - if (!processor) { - return(AE_BAD_PARAMETER); - } - - switch (event) { - - case PR_NOTIFY_PERF_STATES: - case PR_NOTIFY_POWER_STATES: - sprintf(processor_uid, "%d", processor->uid); - status = bm_osl_generate_event(processor->device_handle, - PR_PROC_ROOT, processor_uid, event, 0); - break; - - default: - return(AE_BAD_PARAMETER); - break; - } - - return(status); -} - - -/**************************************************************************** - * Errata Handling - ****************************************************************************/ - -void acpi_pr_errata (void) -{ - struct pci_dev *dev = NULL; - - while ((dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, - PCI_ANY_ID, PCI_ANY_ID, dev))) { - switch (dev->device) { - case PCI_DEVICE_ID_INTEL_82801BA_8: /* PIIX4U4 */ - case PCI_DEVICE_ID_INTEL_82801BA_9: /* PIIX4U3 */ - case PCI_DEVICE_ID_INTEL_82451NX: /* PIIX4NX */ - case PCI_DEVICE_ID_INTEL_82372FB_1: /* PIIX4U2 */ - case PCI_DEVICE_ID_INTEL_82801AA_1: /* PIIX4U */ - case PCI_DEVICE_ID_INTEL_82443MX_1: /* PIIX4E2 */ - case PCI_DEVICE_ID_INTEL_82801AB_1: /* PIIX4E */ - case PCI_DEVICE_ID_INTEL_82371AB: /* PIIX4 */ - acpi_piix4_bmisx = pci_resource_start(dev, 4); - return; - } - } - - return; -} - - -/**************************************************************************** - * - * FUNCTION: pr_osl_init - * - * PARAMETERS: - * - * RETURN: 0: Success - * - * DESCRIPTION: Module initialization. - * - ****************************************************************************/ - -static int __init -pr_osl_init (void) -{ - acpi_status status = AE_OK; - - /* abort if no busmgr */ - if (!bm_proc_root) - return -ENODEV; - - acpi_pr_errata(); - - pr_proc_root = proc_mkdir(PR_PROC_ROOT, bm_proc_root); - if (!pr_proc_root) { - status = AE_ERROR; - } - else { - status = pr_initialize(); - if (ACPI_FAILURE(status)) { - remove_proc_entry(PR_PROC_ROOT, bm_proc_root); - } - - } - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - - -/**************************************************************************** - * - * FUNCTION: pr_osl_cleanup - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Module cleanup. - * - ****************************************************************************/ - -static void __exit -pr_osl_cleanup (void) -{ - pr_terminate(); - - if (pr_proc_root) { - remove_proc_entry(PR_PROC_ROOT, bm_proc_root); - } - - return; -} - - -module_init(pr_osl_init); -module_exit(pr_osl_cleanup); diff -Nur linux-2.4.19/drivers/acpi/ospm/processor/prperf.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/prperf.c --- linux-2.4.19/drivers/acpi/ospm/processor/prperf.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/prperf.c Wed Dec 31 16:00:00 1969 @@ -1,456 +0,0 @@ -/***************************************************************************** - * - * Module Name: prperf.c - * $Revision: 21 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * TBD: 1. Support ACPI 2.0 processor performance states (not just throttling). - * 2. Fully implement thermal -vs- power management limit control. - */ - - -#include -#include -#include "pr.h" - -#define _COMPONENT ACPI_PROCESSOR - MODULE_NAME ("prperf") - - -/**************************************************************************** - * Globals - ****************************************************************************/ - -extern fadt_descriptor_rev2 acpi_fadt; -const u32 POWER_OF_2[] = {1,2,4,8,16,32,64,128,256,512}; - - -/**************************************************************************** - * - * FUNCTION: pr_perf_get_frequency - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_perf_get_frequency ( - PR_CONTEXT *processor, - u32 *frequency) { - acpi_status status = AE_OK; - - FUNCTION_TRACE("pr_perf_get_frequency"); - - if (!processor || !frequency) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* TBD: Generic method to calculate processor frequency. */ - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: pr_perf_get_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -/* TBD: Include support for _real_ performance states (not just throttling). */ - -acpi_status -pr_perf_get_state ( - PR_CONTEXT *processor, - u32 *state) -{ - u32 pblk_value = 0; - u32 duty_mask = 0; - u32 duty_cycle = 0; - - FUNCTION_TRACE("pr_perf_get_state"); - - if (!processor || !state) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (processor->performance.state_count == 1) { - *state = 0; - return_ACPI_STATUS(AE_OK); - } - - acpi_os_read_port(processor->pblk.address, &pblk_value, 32); - - /* - * Throttling Enabled? - * ------------------- - * If so, calculate the current throttling state, otherwise return - * '100% performance' (state 0). - */ - if (pblk_value & 0x00000010) { - - duty_mask = processor->performance.state_count - 1; - duty_mask <<= acpi_fadt.duty_offset; - - duty_cycle = pblk_value & duty_mask; - duty_cycle >>= acpi_fadt.duty_offset; - - if (duty_cycle == 0) { - *state = 0; - } - else { - *state = processor->performance.state_count - - duty_cycle; - } - } - else { - *state = 0; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Processor [%02x] is at performance state [%d%%].\n", processor->device_handle, processor->performance.state[*state].performance)); - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: pr_perf_set_state - * - * PARAMETERS: - * - * RETURN: AE_OK - * AE_BAD_PARAMETER - * AE_BAD_DATA Invalid target throttling state. - * - * DESCRIPTION: - * - ****************************************************************************/ - -/* TBD: Includes support for _real_ performance states (not just throttling). */ - -acpi_status -pr_perf_set_state ( - PR_CONTEXT *processor, - u32 state) -{ - u32 pblk_value = 0; - u32 duty_mask = 0; - u32 duty_cycle = 0; - u32 i = 0; - - FUNCTION_TRACE ("pr_perf_set_state"); - - if (!processor) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (state > (processor->performance.state_count - 1)) { - return_ACPI_STATUS(AE_BAD_DATA); - } - - if ((state == processor->performance.active_state) || - (processor->performance.state_count == 1)) { - return_ACPI_STATUS(AE_OK); - } - - /* - * Calculate Duty Cycle/Mask: - * -------------------------- - * Note that we don't support duty_cycle values that span bit 4. - */ - if (state) { - duty_cycle = processor->performance.state_count - state; - duty_cycle <<= acpi_fadt.duty_offset; - } - else { - duty_cycle = 0; - } - - duty_mask = ~((u32)(processor->performance.state_count - 1)); - for (i=0; ipblk.address, &pblk_value, 32); - if (pblk_value & 0x00000010) { - pblk_value &= 0xFFFFFFEF; - acpi_os_write_port(processor->pblk.address, pblk_value, 32); - } - - /* - * Set Duty Cycle: - * --------------- - * Mask off the old duty_cycle value, mask in the new. - */ - pblk_value &= duty_mask; - pblk_value |= duty_cycle; - acpi_os_write_port(processor->pblk.address, pblk_value, 32); - - /* - * Enable Throttling: - * ------------------ - * But only for non-zero (non-100% performance) states. - */ - if (state) { - pblk_value |= 0x00000010; - acpi_os_write_port(processor->pblk.address, pblk_value, 32); - } - - processor->performance.active_state = state; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Processor [%02x] set to performance state [%d%%].\n", processor->device_handle, processor->performance.state[state].performance)); - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: pr_perf_set_limit - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_perf_set_limit ( - PR_CONTEXT *processor, - u32 limit) -{ - acpi_status status = AE_OK; - PR_PERFORMANCE *performance = NULL; - - FUNCTION_TRACE ("pr_perf_set_limit"); - - if (!processor) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - performance = &(processor->performance); - - /* - * Set Limit: - * ---------- - * TBD: Properly manage thermal and power limits (only set - * performance state iff...). - */ - switch (limit) { - - case PR_PERF_DEC: - if (performance->active_state < - (performance->state_count-1)) { - status = pr_perf_set_state(processor, - (performance->active_state+1)); - } - break; - - case PR_PERF_INC: - if (performance->active_state > 0) { - status = pr_perf_set_state(processor, - (performance->active_state-1)); - } - break; - - case PR_PERF_MAX: - if (performance->active_state != 0) { - status = pr_perf_set_state(processor, 0); - } - break; - - default: - return_ACPI_STATUS(AE_BAD_DATA); - break; - } - - if (ACPI_SUCCESS(status)) { - performance->thermal_limit = performance->active_state; - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Processor [%02x] thermal performance limit set to [%d%%].\n", processor->device_handle, processor->performance.state[performance->active_state].performance)); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: pr_perf_add_device - * - * PARAMETERS: processor Our processor-specific context. - * - * RETURN: AE_OK - * AE_BAD_PARAMETER - * - * DESCRIPTION: Calculates the number of throttling states and the state - * performance/power values. - * - ****************************************************************************/ - -/* TBD: Support duty_cycle values that span bit 4. */ - -acpi_status -pr_perf_add_device ( - PR_CONTEXT *processor) -{ - acpi_status status = AE_OK; - u32 i = 0; - u32 performance_step = 0; - u32 percentage = 0; - - FUNCTION_TRACE("pr_perf_add_device"); - - if (!processor) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Valid PBLK? - * ----------- - * For SMP it is common to have the first (boot) processor have a - * valid PBLK while all others do not -- which implies that - * throttling has system-wide effects (duty_cycle programmed into - * the chipset effects all processors). - */ - if ((processor->pblk.length < 6) || !processor->pblk.address) { - processor->performance.state_count = 1; - } - - /* - * Valid Duty Offset/Width? - * ------------------------ - * We currently only support duty_cycle values that fall within - * bits 0-3, as things get complicated when this value spans bit 4 - * (the throttling enable/disable bit). - */ - else if ((acpi_fadt.duty_offset + acpi_fadt.duty_width) > 4) { - processor->performance.state_count = 1; - } - - /* - * Compute State Count: - * -------------------- - * The number of throttling states is computed as 2^duty_width, - * but limited by PR_MAX_THROTTLE_STATES. Note that a duty_width - * of zero results is one throttling state (100%). - */ - else { - processor->performance.state_count = - POWER_OF_2[acpi_fadt.duty_width]; - } - - if (processor->performance.state_count > PR_MAX_THROTTLE_STATES) { - processor->performance.state_count = PR_MAX_THROTTLE_STATES; - } - - /* - * Compute State Values: - * --------------------- - * Note that clock throttling displays a linear power/performance - * relationship (at 50% performance the CPU will consume 50% power). - */ - performance_step = (1000 / processor->performance.state_count); - - for (i=0; iperformance.state_count; i++) { - percentage = (1000 - (performance_step * i))/10; - processor->performance.state[i].performance = percentage; - processor->performance.state[i].power = percentage; - } - - /* - * Get Current State: - * ------------------ - */ - status = pr_perf_get_state(processor, &(processor->performance.active_state)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Set to Maximum Performance: - * --------------------------- - * We'll let subsequent policy (e.g. thermal/power) decide to lower - * performance if it so chooses, but for now crank up the speed. - */ - if (0 != processor->performance.active_state) { - status = pr_perf_set_state(processor, 0); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: pr_perf_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_perf_remove_device ( - PR_CONTEXT *processor) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("pr_perf_remove_device"); - - if (!processor) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(&(processor->performance), 0, sizeof(PR_PERFORMANCE)); - - return_ACPI_STATUS(status); -} - diff -Nur linux-2.4.19/drivers/acpi/ospm/processor/prpower.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/prpower.c --- linux-2.4.19/drivers/acpi/ospm/processor/prpower.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/processor/prpower.c Wed Dec 31 16:00:00 1969 @@ -1,665 +0,0 @@ -/***************************************************************************** - * - * Module Name: prpower.c - * $Revision: 32 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -/* TBD: Linux specific */ -#include -#include -#include - -#include -#include -#include "pr.h" - -#define _COMPONENT ACPI_PROCESSOR - MODULE_NAME ("prpower") - - -/**************************************************************************** - * Globals - ****************************************************************************/ - -extern FADT_DESCRIPTOR acpi_fadt; -static u32 last_idle_jiffies = 0; -static PR_CONTEXT *processor_list[NR_CPUS]; -static void (*pr_pm_idle_save)(void) = NULL; -static u8 bm_control = 0; - - -/* Used for PIIX4 errata handling. */ -unsigned short acpi_piix4_bmisx = 0; - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: pr_power_activate_state - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -pr_power_activate_state ( - PR_CONTEXT *processor, - u32 next_state) -{ - - PROC_NAME("pr_power_activate_state"); - - if (!processor) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); - return; - } - - processor->power.state[processor->power.active_state].promotion.count = 0; - processor->power.state[processor->power.active_state].demotion.count = 0; - - /* - * Cleanup from old state. - */ - switch (processor->power.active_state) { - - case PR_C3: - /* Disable bus master reload */ - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, - BM_RLD, 0); - break; - } - - /* - * Prepare to use new state. - */ - switch (next_state) { - - case PR_C3: - /* Enable bus master reload */ - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, - BM_RLD, 1); - break; - } - - processor->power.active_state = next_state; - - return; -} - - -/**************************************************************************** - * - * FUNCTION: pr_power_idle - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -void -pr_power_idle (void) -{ - PR_CX *c_state = NULL; - u32 next_state = 0; - u32 start_ticks, end_ticks, time_elapsed; - PR_CONTEXT *processor = NULL; - - PROC_NAME("pr_power_idle"); - - processor = processor_list[smp_processor_id()]; - - if (!processor || processor->power.active_state == PR_C0) { - return; - } - - next_state = processor->power.active_state; - - /* - * Check OS Idleness: - * ------------------ - * If the OS has been busy (hasn't called the idle handler in a while) - * then automatically demote to the default power state (e.g. C1). - * - * TBD: Optimize by having scheduler determine business instead - * of having us try to calculate it. - */ - if (processor->power.active_state != processor->power.default_state) { - if ((jiffies - last_idle_jiffies) >= processor->power.busy_metric) { - next_state = processor->power.default_state; - if (next_state != processor->power.active_state) { - pr_power_activate_state(processor, next_state); - } - } - } - - disable(); - - /* - * Log BM Activity: - * ---------------- - * Read BM_STS and record its value for later use by C3 policy. - * (Note that we save the BM_STS values for the last 32 cycles). - */ - if (bm_control) { - processor->power.bm_activity <<= 1; - if (acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_DO_NOT_LOCK, BM_STS)) { - processor->power.bm_activity |= 1; - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, - BM_STS, 1); - } - else if (acpi_piix4_bmisx) { - /* - * PIIX4 Errata: - * ------------- - * This code is a workaround for errata #18 "C3 Power State/ - * BMIDE and Type-F DMA Livelock" from the July '01 PIIX4 - * specification update. Note that BM_STS doesn't always - * reflect the true state of bus mastering activity; forcing - * us to manually check the BMIDEA bit of each IDE channel. - */ - if ((inb_p(acpi_piix4_bmisx + 0x02) & 0x01) || - (inb_p(acpi_piix4_bmisx + 0x0A) & 0x01)) - processor->power.bm_activity |= 1; - } - } - - c_state = &(processor->power.state[processor->power.active_state]); - - c_state->utilization++; - - /* - * Sleep: - * ------ - * Invoke the current Cx state to put the processor to sleep. - */ - switch (processor->power.active_state) { - - case PR_C1: - /* Invoke C1 */ - enable(); halt(); - /* - * TBD: Can't get time duration while in C1, as resumes - * go to an ISR rather than here. - */ - time_elapsed = 0xFFFFFFFF; - break; - - case PR_C2: - /* See how long we're asleep for */ - acpi_get_timer(&start_ticks); - /* Invoke C2 */ - acpi_os_read_port(processor->power.p_lvl2, NULL, 8); - /* Dummy op - must do something useless after P_LVL2 read */ - acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_DO_NOT_LOCK, BM_STS); - /* Compute time elapsed */ - acpi_get_timer(&end_ticks); - /* Re-enable interrupts */ - enable(); - acpi_get_timer_duration(start_ticks, end_ticks, &time_elapsed); - break; - - case PR_C3: - /* Disable bus master arbitration */ - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, ARB_DIS, 1); - /* See how long we're asleep for */ - acpi_get_timer(&start_ticks); - /* Invoke C3 */ - acpi_os_read_port(processor->power.p_lvl3, NULL, 8); - /* Dummy op - must do something useless after P_LVL3 read */ - acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_DO_NOT_LOCK, BM_STS); - /* Compute time elapsed */ - acpi_get_timer(&end_ticks); - /* Enable bus master arbitration */ - acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, - ARB_DIS, 0); - /* Re-enable interrupts */ - enable(); - acpi_get_timer_duration(start_ticks, end_ticks, &time_elapsed); - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Attempt to use unsupported power state C%d.\n", processor->power.active_state)); - enable(); - break; - } - - /* - * Promotion? - * ---------- - * Track the number of successful sleeps (time asleep is greater - * than time_threshold) and promote when count_threshold is - * reached. - */ - if ((c_state->promotion.target_state) && - (time_elapsed >= c_state->promotion.time_threshold)) { - - c_state->promotion.count++; - c_state->demotion.count = 0; - - if (c_state->promotion.count >= c_state->promotion.count_threshold) { - /* - * Bus Mastering Activity, if active and used - * by this state's promotion policy, prevents - * promotions from occuring. - */ - if (!bm_control || !(processor->power.bm_activity & c_state->promotion.bm_threshold)) - next_state = c_state->promotion.target_state; - } - } - - /* - * Demotion? - * --------- - * Track the number of shorts (time asleep is less than - * time_threshold) and demote when count_threshold is reached. - */ - if (c_state->demotion.target_state) { - - if (time_elapsed < c_state->demotion.time_threshold) { - - c_state->demotion.count++; - c_state->promotion.count = 0; - - if (c_state->demotion.count >= - c_state->demotion.count_threshold) { - next_state = c_state->demotion.target_state; - } - } - - /* - * Bus Mastering Activity, if active and used by this - * state's promotion policy, causes an immediate demotion - * to occur. - */ - if (bm_control && (processor->power.bm_activity & c_state->demotion.bm_threshold)) - next_state = c_state->demotion.target_state; - } - - /* - * New Cx State? - * ------------- - * If we're going to start using a new Cx state we must clean up - * from the previous and prepare to use the new. - */ - if (next_state != processor->power.active_state) { - pr_power_activate_state(processor, next_state); - processor->power.active_state = processor->power.active_state; - } - - /* - * Track OS Idleness: - * ------------------ - * Record a jiffies timestamp to compute time elapsed between calls - * to the idle handler. - */ - last_idle_jiffies = jiffies; - - return; -} - - -/***************************************************************************** - * - * FUNCTION: pr_power_set_default_policy - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Sets the default Cx state policy (OS idle handler). Our - * scheme is to promote quickly to C2 but more conservatively - * to C3. We're favoring C2 for its characteristics of low - * latency (quick response), good power savings, and ability - * to allow bus mastering activity. - * - * Note that Cx state policy is completely customizable, with - * the goal of having heuristics to alter policy dynamically. - * - ****************************************************************************/ - -acpi_status -pr_power_set_default_policy ( - PR_CONTEXT *processor) -{ - FUNCTION_TRACE("pr_power_set_default_policy"); - - if (!processor) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Busy Metric: - * ------------ - * Used to determine when the OS has been busy and thus when - * policy should return to using the default Cx state (e.g. C1). - * On Linux we use the number of jiffies (scheduler quantums) - * that transpire between calls to the idle handler. - * - * TBD: Linux-specific. - */ - processor->power.busy_metric = 2; - - /* - * C1: - * --- - * C1 serves as our default state. It must be valid. - */ - if (processor->power.state[PR_C1].is_valid) { - processor->power.active_state = - processor->power.default_state = PR_C1; - } - else { - processor->power.active_state = - processor->power.default_state = PR_C0; - return_ACPI_STATUS(AE_OK); - } - - /* - * C2: - * --- - * Set default C1 promotion and C2 demotion policies. - */ - if (processor->power.state[PR_C2].is_valid) { - /* - * Promote from C1 to C2 anytime we're asleep in C1 for - * longer than two times the C2 latency (to amortize cost - * of transition). Demote from C2 to C1 anytime we're - * asleep in C2 for less than this time. - */ - processor->power.state[PR_C1].promotion.count_threshold = 10; - processor->power.state[PR_C1].promotion.time_threshold = - 2 * processor->power.state[PR_C2].latency; - processor->power.state[PR_C1].promotion.target_state = PR_C2; - - processor->power.state[PR_C2].demotion.count_threshold = 1; - processor->power.state[PR_C2].demotion.time_threshold = - 2 * processor->power.state[PR_C2].latency; - processor->power.state[PR_C2].demotion.target_state = PR_C1; - } - - /* - * C3: - * --- - * Set default C2 promotion and C3 demotion policies. - */ - if ((processor->power.state[PR_C2].is_valid) && - (processor->power.state[PR_C3].is_valid)) { - /* - * Promote from C2 to C3 after 4 cycles of no bus - * mastering activity (while maintaining sleep time - * criteria). Demote immediately on a short or - * whenever bus mastering activity occurs. - */ - processor->power.state[PR_C2].promotion.count_threshold = 1; - processor->power.state[PR_C2].promotion.time_threshold = - 2 * processor->power.state[PR_C3].latency; - processor->power.state[PR_C2].promotion.bm_threshold = - 0x0000000F; - processor->power.state[PR_C2].promotion.target_state = - PR_C3; - - processor->power.state[PR_C3].demotion.count_threshold = 1; - processor->power.state[PR_C3].demotion.time_threshold = - 2 * processor->power.state[PR_C3].latency; - processor->power.state[PR_C3].demotion.bm_threshold = - 0x0000000F; - processor->power.state[PR_C3].demotion.target_state = - PR_C2; - } - - return_ACPI_STATUS(AE_OK); -} - -/***************************************************************************** - * - * FUNCTION: pr_power_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -/* - * TBD: 1. PROC_C1 support. - * 2. Symmetric Cx state support (different Cx states supported - * by different CPUs results in lowest common denominator). - */ - -acpi_status -pr_power_add_device ( - PR_CONTEXT *processor) -{ - FUNCTION_TRACE("pr_power_add_device"); - - if (!processor) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * State Count: - * ------------ - * Fixed at four (C0-C3). We use is_valid to determine whether or - * not a state actually gets used. - */ - processor->power.state_count = PR_MAX_POWER_STATES; - - /* - * C0: - * --- - * C0 exists only as filler in our array. (Let's assume its valid!) - */ - processor->power.state[PR_C0].is_valid = TRUE; - - /* - * C1: - * --- - * ACPI states that C1 must be supported by all processors - * with a latency so small that it can be ignored. - * - * TBD: What about PROC_C1 support? - */ - processor->power.state[PR_C1].is_valid = TRUE; - - /* - * C2: - * --- - * We're only supporting C2 on UP systems with latencies <= 100us. - * - * TBD: Support for C2 on MP (P_LVL2_UP) -- I'm taking the - * conservative approach for now. - */ - processor->power.state[PR_C2].latency = acpi_fadt.plvl2_lat; - -#ifdef CONFIG_SMP - if (smp_num_cpus == 1) { -#endif /*CONFIG_SMP*/ - if (acpi_fadt.plvl2_lat <= PR_MAX_C2_LATENCY) { - processor->power.state[PR_C2].is_valid = TRUE; - processor->power.p_lvl2 = processor->pblk.address + 4; - } -#ifdef CONFIG_SMP - } -#endif /*CONFIG_SMP*/ - - - /* - * C3: - * --- - * We're only supporting C3 on UP systems with latencies <= 1000us, - * and that include the ability to disable bus mastering while in - * C3 (ARB_DIS) but allows bus mastering requests to wake the system - * from C3 (BM_RLD). Note his method of maintaining cache coherency - * (disabling of bus mastering) cannot be used on SMP systems, and - * flushing caches (e.g. WBINVD) is simply too costly at this time. - * - * TBD: Support for C3 on MP -- I'm taking the conservative - * approach for now. - */ - processor->power.state[PR_C3].latency = acpi_fadt.plvl3_lat; - -#ifdef CONFIG_SMP - if (smp_num_cpus == 1) { -#endif /*CONFIG_SMP*/ - if ((acpi_fadt.plvl3_lat <= PR_MAX_C3_LATENCY) && bm_control) { - processor->power.state[PR_C3].is_valid = TRUE; - processor->power.p_lvl3 = processor->pblk.address + 5; - } -#ifdef CONFIG_SMP - } -#endif /*CONFIG_SMP*/ - - /* - * Set Default Policy: - * ------------------- - * Now that we know which state are supported, set the default - * policy. Note that this policy can be changed dynamically - * (e.g. encourage deeper sleeps to conserve battery life when - * not on AC). - */ - pr_power_set_default_policy(processor); - - /* - * Save Processor Context: - * ----------------------- - * TBD: Enhance Linux idle handler to take processor context - * parameter. - */ - processor_list[processor->uid] = processor; - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: pr_power_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_power_remove_device ( - PR_CONTEXT *processor) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("pr_power_remove_device"); - - if (!processor) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - MEMSET(&(processor->power), 0, sizeof(PR_POWER)); - - processor_list[processor->uid] = NULL; - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: pr_power_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_power_initialize (void) -{ - u32 i = 0; - - FUNCTION_TRACE("pr_power_initialize"); - - /* TBD: Linux-specific. */ - for (i=0; i - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -pr_power_terminate (void) -{ - FUNCTION_TRACE("pr_power_terminate"); - - /* - * Remove idle handler. - * - * TBD: Linux-specific (need OSL function). - */ - pm_idle = pr_pm_idle_save; - - return_ACPI_STATUS(AE_OK); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/system/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/system/Makefile --- linux-2.4.19/drivers/acpi/ospm/system/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/system/Makefile Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/system/sm.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/system/sm.c --- linux-2.4.19/drivers/acpi/ospm/system/sm.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/system/sm.c Wed Dec 31 16:00:00 1969 @@ -1,373 +0,0 @@ -/***************************************************************************** - * - * Module Name: sm.c - * $Revision: 20 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include "sm.h" - - -#define _COMPONENT ACPI_SYSTEM - MODULE_NAME ("sm") - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: sm_print - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Prints out information on a specific system. - * - ****************************************************************************/ - -void -sm_print ( - SM_CONTEXT *system) -{ -#ifdef ACPI_DEBUG - acpi_buffer buffer; - - PROC_NAME("sm_print"); - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) { - return; - } - - /* - * Get the full pathname for this ACPI object. - */ - acpi_get_name(system->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - /* - * Print out basic system information. - */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| System[%02x]:[%p] %s\n", system->device_handle, system->acpi_handle, (char*)buffer.pointer)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| states: %cS0 %cS1 %cS2 %cS3 %cS4 %cS5\n", (system->states[0]?'+':'-'), (system->states[1]?'+':'-'), (system->states[2]?'+':'-'), (system->states[3]?'+':'-'), (system->states[4]?'+':'-'), (system->states[5]?'+':'-'))); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); -#endif /*ACPI_DEBUG*/ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: sm_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -sm_add_device( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - BM_DEVICE *device = NULL; - SM_CONTEXT *system = NULL; - u8 i, type_a, type_b; - - - FUNCTION_TRACE("sm_add_device"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding system device [%02x].\n", device_handle)); - - if (!context || *context) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Allocate a new SM_CONTEXT structure. - */ - system = acpi_os_callocate(sizeof(SM_CONTEXT)); - if (!system) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* - * Get information on this device. - */ - status = bm_get_device_info(device_handle, &device); - if (ACPI_FAILURE(status)) { - goto end; - } - - system->device_handle = device->handle; - system->acpi_handle = device->acpi_handle; - - /* - * Sx States: - * ---------- - * Figure out which Sx states are supported. - */ - for (i=0; istates[i] = TRUE; - } - } - - status = sm_osl_add_device(system); - if (ACPI_FAILURE(status)) { - goto end; - } - - *context = system; - - sm_print(system); - -end: - if (ACPI_FAILURE(status)) { - acpi_os_free(system); - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: sm_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -sm_remove_device ( - void **context) -{ - acpi_status status = AE_OK; - SM_CONTEXT *system = NULL; - - FUNCTION_TRACE("sm_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - system = (SM_CONTEXT*)*context; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing system device [%02x].\n", system->device_handle)); - - status = sm_osl_remove_device(system); - - acpi_os_free(system); - - *context = NULL; - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: sm_initialize - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -sm_initialize (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("sm_initialize"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Register driver for the System device. - */ - criteria.type = BM_TYPE_SYSTEM; - - driver.notify = &sm_notify; - driver.request = &sm_request; - - status = bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: sm_terminate - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -sm_terminate (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("sm_terminate"); - - MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID)); - MEMSET(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Unregister driver for System devices. - */ - criteria.type = BM_TYPE_SYSTEM; - - driver.notify = &sm_notify; - driver.request = &sm_request; - - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/***************************************************************************** - * - * FUNCTION: sm_notify - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ -acpi_status -sm_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("sm_notify"); - - if (!context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - switch (notify_type) { - - case BM_NOTIFY_DEVICE_ADDED: - status = sm_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = sm_remove_device(context); - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: sm_request - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -sm_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("sm_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Handle Request: - * --------------- - */ - switch (request->command) { - - default: - status = AE_SUPPORT; - break; - } - - request->status = status; - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/system/sm_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/system/sm_osl.c --- linux-2.4.19/drivers/acpi/ospm/system/sm_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/system/sm_osl.c Wed Dec 31 16:00:00 1969 @@ -1,919 +0,0 @@ -/****************************************************************************** - * - * Module Name: sm_osl.c - * $Revision: 16 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "sm.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI System Driver"); -MODULE_LICENSE("GPL"); - - -#define SM_PROC_INFO "info" -#define SM_PROC_DSDT "dsdt" - -extern struct proc_dir_entry *bm_proc_root; -struct proc_dir_entry *sm_proc_root = NULL; -static void (*sm_pm_power_off)(void) = NULL; - -static ssize_t sm_osl_read_dsdt(struct file *, char *, size_t, loff_t *); - -static struct file_operations proc_dsdt_operations = { - read: sm_osl_read_dsdt, -}; - -static acpi_status sm_osl_suspend(u32 state); - -struct proc_dir_entry *bm_proc_sleep; -struct proc_dir_entry *bm_proc_alarm; -struct proc_dir_entry *bm_proc_gpe; - -static int -sm_osl_proc_read_sleep ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - SM_CONTEXT *system = (SM_CONTEXT*) context; - char *str = page; - int len; - int i; - - if (!system) - goto end; - - if (off != 0) - goto end; - - for (i = 0; i <= ACPI_S5; i++) { - if (system->states[i]) - str += sprintf(str,"S%d ", i); - } - - str += sprintf(str, "\n"); - -end: - - len = (str - page); - if (len < (off + count)) - *eof = 1; - - *start = page + off; - len -= off; - - if (len > count) - len = count; - - if (len < 0) - len = 0; - - return (len); -} - -int sm_osl_proc_write_sleep (struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - SM_CONTEXT *system = (SM_CONTEXT*) data; - char str[10]; - char *strend; - unsigned long value; - - if (count > (sizeof(str) - 1)) - return -EINVAL; - - if (copy_from_user(str,buffer,count)) - return -EFAULT; - - str[count] = '\0'; - - value = simple_strtoul(str,&strend,0); - if (str == strend) - return -EINVAL; - - if (value == 0 || value >= ACPI_S5) - return -EINVAL; - - /* - * make sure that the sleep state is supported - */ - if (system->states[value] != TRUE) - return -EINVAL; - - sm_osl_suspend(value); - - return (count); -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_proc_read_info - * - ****************************************************************************/ - -static int -sm_osl_proc_read_info ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - acpi_status status = AE_OK; - SM_CONTEXT *system = NULL; - char *p = page; - int len; - acpi_system_info system_info; - acpi_buffer buffer; - u32 i = 0; - - if (!context) { - goto end; - } - - system = (SM_CONTEXT*) context; - - /* don't get status more than once for a single proc read */ - if (off != 0) { - goto end; - } - - /* - * Get ACPI CA Information. - */ - buffer.length = sizeof(system_info); - buffer.pointer = &system_info; - - status = acpi_get_system_info(&buffer); - if (ACPI_FAILURE(status)) { - p += sprintf(p, "ACPI-CA Version: unknown\n"); - } - else { - p += sprintf(p, "ACPI-CA Version: %x\n", - system_info.acpi_ca_version); - } - - p += sprintf(p, "Sx States Supported: "); - for (i=0; istates[i]) { - p += sprintf(p, "S%d ", i); - } - } - p += sprintf(p, "\n"); - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - return(len); -} - -/**************************************************************************** - * - * FUNCTION: sm_osl_read_dsdt - * - ****************************************************************************/ - -static ssize_t -sm_osl_read_dsdt( - struct file *file, - char *buf, - size_t count, - loff_t *ppos) -{ - acpi_buffer acpi_buf; - void *data; - size_t size = 0; - - acpi_buf.length = 0; - acpi_buf.pointer = NULL; - - - /* determine what buffer size we will need */ - if (acpi_get_table(ACPI_TABLE_DSDT, 1, &acpi_buf) != AE_BUFFER_OVERFLOW) { - return 0; - } - - acpi_buf.pointer = kmalloc(acpi_buf.length, GFP_KERNEL); - if (!acpi_buf.pointer) { - return -ENOMEM; - } - - /* get the table for real */ - if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_DSDT, 1, &acpi_buf))) { - kfree(acpi_buf.pointer); - return 0; - } - - if (*ppos < acpi_buf.length) { - data = acpi_buf.pointer + file->f_pos; - size = acpi_buf.length - file->f_pos; - if (size > count) - size = count; - if (copy_to_user(buf, data, size)) { - kfree(acpi_buf.pointer); - return -EFAULT; - } - } - - kfree(acpi_buf.pointer); - - *ppos += size; - - return size; -} - -static int -sm_osl_proc_read_alarm ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - char *str = page; - int len; - u32 sec,min,hr; - u32 day,mo,yr; - - if (off != 0) goto out; - - spin_lock(&rtc_lock); - sec = CMOS_READ(RTC_SECONDS_ALARM); - min = CMOS_READ(RTC_MINUTES_ALARM); - hr = CMOS_READ(RTC_HOURS_ALARM); - -#if 0 - /* if I ever get an FACP with proper values, maybe I'll enable this code */ - if (acpi_gbl_FADT->day_alrm) - day = CMOS_READ(acpi_gbl_FADT->day_alrm); - else - day = CMOS_READ(RTC_DAY_OF_MONTH); - if (acpi_gbl_FADT->mon_alrm) - mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); - else - mo = CMOS_READ(RTC_MONTH);; - if (acpi_gbl_FADT->century) - yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR); - else - yr = CMOS_READ(RTC_YEAR); -#else - day = CMOS_READ(RTC_DAY_OF_MONTH); - mo = CMOS_READ(RTC_MONTH); - yr = CMOS_READ(RTC_YEAR); -#endif - spin_unlock(&rtc_lock); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hr); - BCD_TO_BIN(day); - BCD_TO_BIN(mo); - BCD_TO_BIN(yr); - - str += sprintf(str,"%4.4u-",yr); - - str += (mo > 12) ? - sprintf(str,"**-") : - sprintf(str,"%2.2u-",mo); - - str += (day > 31) ? - sprintf(str,"** ") : - sprintf(str,"%2.2u ",day); - - str += (hr > 23) ? - sprintf(str,"**:") : - sprintf(str,"%2.2u:",hr); - - str += (min > 59) ? - sprintf(str,"**:") : - sprintf(str,"%2.2u:",min); - - str += (sec > 59) ? - sprintf(str,"**\n") : - sprintf(str,"%2.2u\n",sec); - - out: - len = str - page; - - if (len < count) *eof = 1; - else if (len > count) len = count; - - if (len < 0) len = 0; - - *start = page; - - return len; -} - -static int get_date_field(char **str, u32 *value) -{ - char *next,*strend; - int error = -EINVAL; - - /* try to find delimeter, only to insert null; - * the end of string won't have one, but is still valid - */ - next = strpbrk(*str,"- :"); - if (next) *next++ = '\0'; - - *value = simple_strtoul(*str,&strend,10); - - /* signal success if we got a good digit */ - if (strend != *str) error = 0; - - if (next) *str = next; - return error; -} - - - -int sm_osl_proc_write_alarm ( - struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - char buf[30]; - char *str = buf; - u32 sec,min,hr; - u32 day,mo,yr; - int adjust = 0; - unsigned char rtc_control; - int error = -EINVAL; - - if (count > sizeof(buf) - 1) return -EINVAL; - - if (copy_from_user(str,buffer,count)) return -EFAULT; - - str[count] = '\0'; - /* check for time adjustment */ - if (str[0] == '+') { - str++; - adjust = 1; - } - - if ((error = get_date_field(&str,&yr))) goto out; - if ((error = get_date_field(&str,&mo))) goto out; - if ((error = get_date_field(&str,&day))) goto out; - if ((error = get_date_field(&str,&hr))) goto out; - if ((error = get_date_field(&str,&min))) goto out; - if ((error = get_date_field(&str,&sec))) goto out; - - - if (sec > 59) { - min += 1; - sec -= 60; - } - if (min > 59) { - hr += 1; - min -= 60; - } - if (hr > 23) { - day += 1; - hr -= 24; - } - if (day > 31) { - mo += 1; - day -= 31; - } - if (mo > 12) { - yr += 1; - mo -= 12; - } - - spin_lock_irq(&rtc_lock); - rtc_control = CMOS_READ(RTC_CONTROL); - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(yr); - BIN_TO_BCD(mo); - BIN_TO_BCD(day); - BIN_TO_BCD(hr); - BIN_TO_BCD(min); - BIN_TO_BCD(sec); - } - - if (adjust) { - yr += CMOS_READ(RTC_YEAR); - mo += CMOS_READ(RTC_MONTH); - day += CMOS_READ(RTC_DAY_OF_MONTH); - hr += CMOS_READ(RTC_HOURS); - min += CMOS_READ(RTC_MINUTES); - sec += CMOS_READ(RTC_SECONDS); - } - spin_unlock_irq(&rtc_lock); - - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(yr); - BCD_TO_BIN(mo); - BCD_TO_BIN(day); - BCD_TO_BIN(hr); - BCD_TO_BIN(min); - BCD_TO_BIN(sec); - } - - if (sec > 59) { - min++; - sec -= 60; - } - if (min > 59) { - hr++; - min -= 60; - } - if (hr > 23) { - day++; - hr -= 24; - } - if (day > 31) { - mo++; - day -= 31; - } - if (mo > 12) { - yr++; - mo -= 12; - } - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(yr); - BIN_TO_BCD(mo); - BIN_TO_BCD(day); - BIN_TO_BCD(hr); - BIN_TO_BCD(min); - BIN_TO_BCD(sec); - } - - spin_lock_irq(&rtc_lock); - /* write the fields the rtc knows about */ - CMOS_WRITE(hr,RTC_HOURS_ALARM); - CMOS_WRITE(min,RTC_MINUTES_ALARM); - CMOS_WRITE(sec,RTC_SECONDS_ALARM); - - /* If the system supports an enhanced alarm, it will have non-zero - * offsets into the CMOS RAM here. - * Which for some reason are pointing to the RTC area of memory. - */ -#if 0 - if (acpi_gbl_FADT->day_alrm) CMOS_WRITE(day,acpi_gbl_FADT->day_alrm); - if (acpi_gbl_FADT->mon_alrm) CMOS_WRITE(mo,acpi_gbl_FADT->mon_alrm); - if (acpi_gbl_FADT->century) CMOS_WRITE(yr / 100,acpi_gbl_FADT->century); -#endif - /* enable the rtc alarm interrupt */ - if (!(rtc_control & RTC_AIE)) { - rtc_control |= RTC_AIE; - CMOS_WRITE(rtc_control,RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - } - - /* unlock the lock on the rtc now that we're done with it */ - spin_unlock_irq(&rtc_lock); - - acpi_hw_register_bit_access(ACPI_WRITE,ACPI_MTX_LOCK, RTC_EN, 1); - - file->f_pos += count; - - error = 0; - out: - return error ? error : count; -} - -static int -sm_osl_proc_read_gpe( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - char *str = page; - int size; - int length; - int i; - u32 addr,data; - - if (off) goto out; - - if (acpi_gbl_FADT->V1_gpe0blk) { - length = acpi_gbl_FADT->gpe0blk_len / 2; - - str += sprintf(str,"GPE0: "); - - for (i = length; i > 0; i--) { - addr = GPE0_EN_BLOCK | (i - 1); - data = acpi_hw_register_read(ACPI_MTX_LOCK,addr); - str += sprintf(str,"%2.2x ",data); - } - str += sprintf(str,"\n"); - - str += sprintf(str,"Status: "); - for (i = length; i > 0; i--) { - addr = GPE0_STS_BLOCK | (i - 1); - data = acpi_hw_register_read(ACPI_MTX_LOCK,addr); - str += sprintf(str,"%2.2x ",data); - } - str += sprintf(str,"\n"); - } - - if (acpi_gbl_FADT->V1_gpe1_blk) { - length = acpi_gbl_FADT->gpe1_blk_len / 2; - - - str += sprintf(str,"GPE1: "); - for (i = length; i > 0; i--) { - addr = GPE1_EN_BLOCK | (i - 1); - data = acpi_hw_register_read(ACPI_MTX_LOCK,addr); - str += sprintf(str,"%2.2x",data); - } - str += sprintf(str,"\n"); - - str += sprintf(str,"Status: "); - for (i = length; i > 0; i--) { - addr = GPE1_STS_BLOCK | (i - 1); - data = acpi_hw_register_read(ACPI_MTX_LOCK,addr); - str += sprintf(str,"%2.2x",data); - } - str += sprintf(str,"\n"); - } - out: - size = str - page; - if (size < count) *eof = 1; - else if (size > count) size = count; - - if (size < 0) size = 0; - *start = page; - - return size; -} - -static int -sm_osl_proc_write_gpe ( - struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - char buf[256]; - char *str = buf; - char *next; - int error = -EINVAL; - u32 addr,value = 0; - - if (count > sizeof(buf) + 1) return -EINVAL; - - if (copy_from_user(str,buffer,count)) return -EFAULT; - - str[count] = '\0'; - - /* set addr to which block to refer to */ - if (!strncmp(str,"GPE0 ",5)) addr = GPE0_EN_BLOCK; - else if (!strncmp(str,"GPE1 ",5)) addr = GPE1_EN_BLOCK; - else goto out; - - str += 5; - - /* set low order bits to index of bit to set */ - addr |= simple_strtoul(str,&next,0); - if (next == str) goto out; - - if (next) { - str = ++next; - value = simple_strtoul(str,&next,0); - if (next == str) value = 1; - } - - value = acpi_hw_register_bit_access(ACPI_WRITE,ACPI_MTX_LOCK,addr,(value ? 1 : 0)); - - error = 0; - out: - return error ? error : count; -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_suspend - * - * PARAMETERS: %state: Sleep state to enter. Assumed that caller has filtered - * out bogus values, so it's one of S1, S2, S3 or S4 - * - * RETURN: ACPI_STATUS, whether or not we successfully entered and - * exited sleep. - * - * DESCRIPTION: - * This function is the meat of the sleep routine, as far as the ACPI-CA is - * concerned. - * - * See Chapter 9 of the ACPI 2.0 spec for details concerning the methodology here. - * - * It will do the following things: - * - Call arch-specific routines to save the processor and kernel state - * - Call acpi_enter_sleep_state to actually go to sleep - * .... - * When we wake back up, we will: - * - Restore the processor and kernel state - * - Return to the user - * - * By having this routine in here, it hides it from every part of the CA, - * so it can remain OS-independent. The only function that calls this is - * sm_proc_write_sleep, which gets the sleep state to enter from the user. - * - ****************************************************************************/ -static acpi_status -sm_osl_suspend(u32 state) -{ - acpi_status status = AE_ERROR; - unsigned long wakeup_address; - - /* get out if state is invalid */ - if (state < ACPI_S1 || state > ACPI_S5) - goto acpi_sleep_done; - - /* make sure we don't get any suprises */ - disable(); - - /* TODO: save device state and suspend them */ - - /* save the processor state to memory if going into S2 or S3; - * save it to disk if going into S4. - * Also, set the FWV if going into an STR state - */ - if (state == ACPI_S2 || state == ACPI_S3) { -#ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS - wakeup_address = acpi_save_state_mem((unsigned long)&&acpi_sleep_done); - - if (!wakeup_address) goto acpi_sleep_done; - - acpi_set_firmware_waking_vector( - (ACPI_PHYSICAL_ADDRESS)wakeup_address); -#endif - } else if (state == ACPI_S4) -#ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS - if (acpi_save_state_disk((unsigned long)&&acpi_sleep_done)) - goto acpi_sleep_done; -#endif - - /* set status, since acpi_enter_sleep_state won't return unless something - * goes wrong, or it's just S1. - */ - status = AE_OK; - - mdelay(10); - status = acpi_enter_sleep_state(state); - - acpi_sleep_done: - - /* pause for a bit to allow devices to come back on */ - mdelay(10); - - /* make sure that the firmware waking vector is reset */ - acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS)0); - - acpi_leave_sleep_state(state); - - /* TODO: resume devices and restore their state */ - - enable(); - return status; -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_power_down - * - ****************************************************************************/ - -void -sm_osl_power_down (void) -{ - /* Power down the system (S5 = soft off). */ - sm_osl_suspend(ACPI_S5); -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_add_device - * - ****************************************************************************/ - -acpi_status -sm_osl_add_device( - SM_CONTEXT *system) -{ - u32 i = 0; - struct proc_dir_entry *bm_proc_dsdt; - - if (!system) { - return(AE_BAD_PARAMETER); - } - - printk("ACPI: System firmware supports"); - for (i=0; istates[i]) { - printk(" S%d", i); - } - } - printk("\n"); - - if (system->states[ACPI_STATE_S5]) { - sm_pm_power_off = pm_power_off; - pm_power_off = sm_osl_power_down; - } - - create_proc_read_entry(SM_PROC_INFO, S_IRUGO, - sm_proc_root, sm_osl_proc_read_info, (void*)system); - - bm_proc_sleep = create_proc_read_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, - sm_proc_root, sm_osl_proc_read_sleep, (void*)system); - if (bm_proc_sleep) - bm_proc_sleep->write_proc = sm_osl_proc_write_sleep; - - bm_proc_alarm = create_proc_read_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, - sm_proc_root,sm_osl_proc_read_alarm, NULL); - if (bm_proc_alarm) - bm_proc_alarm->write_proc = sm_osl_proc_write_alarm; - - bm_proc_gpe = create_proc_read_entry("gpe", S_IFREG | S_IRUGO | S_IWUSR, - sm_proc_root,sm_osl_proc_read_gpe,NULL); - if (bm_proc_gpe) - bm_proc_gpe->write_proc = sm_osl_proc_write_gpe; - - /* - * Get a wakeup address for use when we come back from sleep. - * At least on IA-32, this needs to be in low memory. - * When sleep is supported on other arch's, then we may want - * to move this out to another place, but GFP_LOW should suffice - * for now. - */ -#if 0 - if (system->states[ACPI_S3] || system->states[ACPI_S4]) { - acpi_wakeup_address = (unsigned long)virt_to_phys(get_free_page(GFP_LOWMEM)); - printk(KERN_INFO "ACPI: Have wakeup address 0x%8.8x\n",acpi_wakeup_address); - } -#endif - - /* - * This returns more than a page, so we need to use our own file ops, - * not proc's generic ones - */ - bm_proc_dsdt = create_proc_entry(SM_PROC_DSDT, S_IRUSR, sm_proc_root); - if (bm_proc_dsdt) { - bm_proc_dsdt->proc_fops = &proc_dsdt_operations; - } - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_remove_device - * - ****************************************************************************/ - -acpi_status -sm_osl_remove_device ( - SM_CONTEXT *system) -{ - if (!system) { - return(AE_BAD_PARAMETER); - } - - remove_proc_entry(SM_PROC_INFO, sm_proc_root); - remove_proc_entry(SM_PROC_DSDT, sm_proc_root); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_generate_event - * - ****************************************************************************/ - -acpi_status -sm_osl_generate_event ( - u32 event, - SM_CONTEXT *system) -{ - acpi_status status = AE_OK; - - if (!system) { - return(AE_BAD_PARAMETER); - } - - switch (event) { - - default: - return(AE_BAD_PARAMETER); - break; - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_init - * - * PARAMETERS: - * - * RETURN: 0: Success - * - * DESCRIPTION: Module initialization. - * - ****************************************************************************/ - -static int __init -sm_osl_init (void) -{ - acpi_status status = AE_OK; - - /* abort if no busmgr */ - if (!bm_proc_root) - return -ENODEV; - - sm_proc_root = bm_proc_root; - if (!sm_proc_root) { - status = AE_ERROR; - } - else { - status = sm_initialize(); - } - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - - -/**************************************************************************** - * - * FUNCTION: sm_osl_cleanup - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Module cleanup. - * - ****************************************************************************/ - -static void __exit -sm_osl_cleanup (void) -{ - sm_terminate(); - - return; -} - - -module_init(sm_osl_init); -module_exit(sm_osl_cleanup); diff -Nur linux-2.4.19/drivers/acpi/ospm/thermal/Makefile linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/Makefile --- linux-2.4.19/drivers/acpi/ospm/thermal/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/Makefile Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -O_TARGET := ospm_$(notdir $(CURDIR)).o -obj-m := $(O_TARGET) -EXTRA_CFLAGS += $(ACPI_CFLAGS) -obj-y := $(patsubst %.c,%.o,$(wildcard *.c)) - -include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/acpi/ospm/thermal/tz.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/tz.c --- linux-2.4.19/drivers/acpi/ospm/thermal/tz.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/tz.c Wed Dec 31 16:00:00 1969 @@ -1,642 +0,0 @@ -/***************************************************************************** - * - * Module Name: tz.c - * $Revision: 44 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include "tz.h" - - -#define _COMPONENT ACPI_THERMAL - MODULE_NAME ("tz") - - -/**************************************************************************** - * Globals - ****************************************************************************/ - -extern int TZP; - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: tz_print - * - ****************************************************************************/ - -void -tz_print ( - TZ_CONTEXT *tz) -{ -#ifdef ACPI_DEBUG - acpi_buffer buffer; - u32 i,j = 0; - TZ_THRESHOLDS *thresholds = NULL; - - FUNCTION_TRACE("tz_print"); - - if (!tz) - return; - - thresholds = &(tz->policy.thresholds); - - buffer.length = 256; - buffer.pointer = acpi_os_callocate(buffer.length); - if (!buffer.pointer) - return; - - /* - * Get the full pathname for this ACPI object. - */ - acpi_get_name(tz->acpi_handle, ACPI_FULL_PATHNAME, &buffer); - - /* - * Print out basic thermal zone information. - */ - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Thermal_zone[%02x]:[%p] %s\n", tz->device_handle, tz->acpi_handle, (char*)buffer.pointer)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| temperature[%d] state[%08x]\n", tz->policy.temperature, tz->policy.state)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| cooling_mode[%08x] polling_freq[%d]\n", tz->policy.cooling_mode, tz->policy.polling_freq)); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| critical[%d]\n", thresholds->critical.temperature)); - if (thresholds->hot.is_valid) - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| hot[%d]\n", thresholds->hot.temperature)); - if (thresholds->passive.is_valid) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| passive[%d]: tc1[%d] tc2[%d] tsp[%d]\n", thresholds->passive.temperature, thresholds->passive.tc1, thresholds->passive.tc2, thresholds->passive.tsp)); - if (thresholds->passive.devices.count > 0) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| devices")); - for (j=0; (jpassive.devices.count && j<10); j++) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "[%02x]", thresholds->passive.devices.handles[j])); - } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n")); - } - } - for (i=0; iactive[i].is_valid) - break; - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| active[%d]: index[%d]\n", thresholds->active[i].temperature, i)); - if (thresholds->active[i].devices.count > 0) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| devices")); - for (j=0; (jactive[i].devices.count && j<10); j++) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "[%02x]", thresholds->active[i].devices.handles[j])); - } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n")); - } - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n")); - - acpi_os_free(buffer.pointer); -#endif /*ACPI_DEBUG*/ - - return; -} - - -/**************************************************************************** - * - * FUNCTION: tz_get_temperaturee - * - ****************************************************************************/ - -acpi_status -tz_get_temperature ( - TZ_CONTEXT *tz) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("tz_get_temperature"); - - if (!tz) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Evaluate the _TMP method to get the current temperature. - */ - status = bm_evaluate_simple_integer(tz->acpi_handle, "_TMP", &(tz->policy.temperature)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %d d_k\n", tz->policy.temperature)); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: tz_set_cooling_preference - * - ****************************************************************************/ - -acpi_status -tz_set_cooling_preference ( - TZ_CONTEXT *tz, - TZ_COOLING_MODE cooling_mode) -{ - acpi_status status = AE_OK; - acpi_object_list arg_list; - acpi_object arg0; - - FUNCTION_TRACE("tz_set_cooling_preference"); - - if (!tz || ((cooling_mode != TZ_COOLING_MODE_ACTIVE) && (cooling_mode != TZ_COOLING_MODE_PASSIVE))) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Build the argument list, which simply consists of the current - * cooling preference. - */ - memset(&arg_list, 0, sizeof(acpi_object)); - arg_list.count = 1; - arg_list.pointer = &arg0; - - memset(&arg0, 0, sizeof(acpi_object)); - arg0.type = ACPI_TYPE_INTEGER; - arg0.integer.value = cooling_mode; - - /* - * Evaluate "_SCP" - setting the new cooling preference. - */ - status = acpi_evaluate_object(tz->acpi_handle, "_SCP", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - tz->policy.cooling_mode = -1; - return_ACPI_STATUS(status); - } - - tz->policy.cooling_mode = cooling_mode; - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: tz_get_thresholds - * - ****************************************************************************/ - -acpi_status -tz_get_thresholds ( - TZ_CONTEXT *tz) -{ - acpi_status status = AE_OK; - TZ_THRESHOLDS *thresholds = NULL; - u32 value = 0; - u32 i = 0; - - FUNCTION_TRACE("acpi_tz_get_thresholds"); - - if (!tz) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - thresholds = &(tz->policy.thresholds); - - /* Critical Shutdown (required) */ - - status = bm_evaluate_simple_integer(tz->acpi_handle, "_CRT", &value); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n")); - return_ACPI_STATUS(status); - } - else { - thresholds->critical.temperature = value; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found critical threshold [%d]\n", thresholds->critical.temperature)); - - } - - /* Critical Sleep (optional) */ - - status = bm_evaluate_simple_integer(tz->acpi_handle, "_HOT", &value); - if (ACPI_FAILURE(status)) { - thresholds->hot.is_valid = 0; - thresholds->hot.temperature = 0; - } - else { - thresholds->hot.is_valid = 1; - thresholds->hot.temperature = value; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%d]\n", thresholds->hot.temperature)); - } - - /* Passive: Processors (optional) */ - - status = bm_evaluate_simple_integer(tz->acpi_handle, "_PSV", &value); - if (ACPI_FAILURE(status)) { - thresholds->passive.is_valid = 0; - thresholds->passive.temperature = 0; - } - else { - thresholds->passive.is_valid = 1; - thresholds->passive.temperature = value; - - status = bm_evaluate_simple_integer(tz->acpi_handle, "_TC1", &value); - if (ACPI_FAILURE(status)) { - thresholds->passive.is_valid = 0; - } - thresholds->passive.tc1 = value; - - status = bm_evaluate_simple_integer(tz->acpi_handle, "_TC2", &value); - if (ACPI_FAILURE(status)) { - thresholds->passive.is_valid = 0; - } - thresholds->passive.tc2 = value; - - status = bm_evaluate_simple_integer(tz->acpi_handle, "_TSP", &value); - if (ACPI_FAILURE(status)) { - thresholds->passive.is_valid = 0; - } - thresholds->passive.tsp = value; - - status = bm_evaluate_reference_list(tz->acpi_handle, "_PSL", &(thresholds->passive.devices)); - if (ACPI_FAILURE(status)) { - thresholds->passive.is_valid = 0; - } - - if (thresholds->passive.is_valid) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found passive threshold [%d]\n", thresholds->passive.temperature)); - } - else { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid passive threshold\n")); - } - } - - /* Active: Fans, etc. (optional) */ - - for (i=0; iacpi_handle, name, &value); - if (ACPI_FAILURE(status)) { - thresholds->active[i].is_valid = 0; - thresholds->active[i].temperature = 0; - break; - } - - thresholds->active[i].temperature = value; - name[2] = 'L'; - - status = bm_evaluate_reference_list(tz->acpi_handle, name, &(thresholds->active[i].devices)); - if (ACPI_SUCCESS(status)) { - thresholds->active[i].is_valid = 1; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found active threshold [%d]:[%d]\n", i, thresholds->active[i].temperature)); - } - else { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid active threshold [%d]\n", i)); - } - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: tz_add_device - * - ****************************************************************************/ - -acpi_status -tz_add_device ( - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - TZ_CONTEXT *tz = NULL; - BM_DEVICE *device = NULL; - acpi_handle tmp_handle = NULL; - static u32 zone_count = 0; - - FUNCTION_TRACE("tz_add_device"); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding thermal zone [%02x].\n", device_handle)); - - if (!context || *context) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Invalid context for device [%02x].\n", device_handle)); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Get information on this device. - */ - status = bm_get_device_info(device_handle, &device); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Allocate a new Thermal Zone device. - */ - tz = acpi_os_callocate(sizeof(TZ_CONTEXT)); - if (!tz) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - tz->device_handle = device->handle; - tz->acpi_handle = device->acpi_handle; - - /* TBD: How to manage 'uid' when zones are Pn_p? */ - sprintf(tz->uid, "%d", zone_count++); - - /* - * Temperature: - * ------------ - * Make sure we can read the zone's current temperature (_TMP). - * If we can't, there's no use in doing any policy (abort). - */ - status = tz_get_temperature(tz); - if (ACPI_FAILURE(status)) - goto end; - - /* - * Polling Frequency: - * ------------------ - * If _TZP doesn't exist use the OS default polling frequency. - */ - status = bm_evaluate_simple_integer(tz->acpi_handle, "_TZP", &(tz->policy.polling_freq)); - if (ACPI_FAILURE(status)) { - tz->policy.polling_freq = TZP; - } - status = AE_OK; - - /* - * Cooling Preference: - * ------------------- - * Default to ACTIVE (noisy) cooling until policy decides otherwise. - * Note that _SCP is optional. - */ - tz_set_cooling_preference(tz, TZ_COOLING_MODE_ACTIVE); - - /* - * Start Policy: - * ------------- - * Thermal policy is included in the kernel (this driver) because - * of the critical role it plays in avoiding nuclear meltdown. =O - */ - status = tz_policy_add_device(tz); - if (ACPI_FAILURE(status)) - goto end; - - status = tz_osl_add_device(tz); - if (ACPI_FAILURE(status)) - goto end; - - *context = tz; - - tz_print(tz); - -end: - if (ACPI_FAILURE(status)) - acpi_os_free(tz); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: tz_remove_device - * - ****************************************************************************/ - -acpi_status -tz_remove_device ( - void **context) -{ - acpi_status status = AE_OK; - TZ_CONTEXT *tz = NULL; - - FUNCTION_TRACE("tz_remove_device"); - - if (!context || !*context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - tz = (TZ_CONTEXT*)(*context); - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing thermal zone [%02x].\n", tz->device_handle)); - - status = tz_osl_remove_device(tz); - - /* - * Remove Policy: - * -------------- - * TBD: Move all thermal zone policy to user-mode daemon... - */ - status = tz_policy_remove_device(tz); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - acpi_os_free(tz); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * External Functions - ****************************************************************************/ - -/**************************************************************************** - * - * FUNCTION: tz_initialize - * - ****************************************************************************/ - -acpi_status -tz_initialize (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("tz_initialize"); - - memset(&criteria, 0, sizeof(BM_DEVICE_ID)); - memset(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Register driver for thermal zone devices. - */ - criteria.type = BM_TYPE_THERMAL_ZONE; - - driver.notify = &tz_notify; - driver.request = &tz_request; - - status = bm_register_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: tz_terminate - * - ****************************************************************************/ - -acpi_status -tz_terminate (void) -{ - acpi_status status = AE_OK; - BM_DEVICE_ID criteria; - BM_DRIVER driver; - - FUNCTION_TRACE("tz_terminate"); - - memset(&criteria, 0, sizeof(BM_DEVICE_ID)); - memset(&driver, 0, sizeof(BM_DRIVER)); - - /* - * Unregister driver for thermal zone devices. - */ - criteria.type = BM_TYPE_THERMAL_ZONE; - - driver.notify = &tz_notify; - driver.request = &tz_request; - - status = bm_unregister_driver(&criteria, &driver); - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: tz_notify - * - ****************************************************************************/ - -acpi_status -tz_notify ( - BM_NOTIFY notify_type, - BM_HANDLE device_handle, - void **context) -{ - acpi_status status = AE_OK; - TZ_CONTEXT *tz = NULL; - - FUNCTION_TRACE("tz_notify"); - - if (!context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - tz = (TZ_CONTEXT*)*context; - - switch (notify_type) { - - case BM_NOTIFY_DEVICE_ADDED: - status = tz_add_device(device_handle, context); - break; - - case BM_NOTIFY_DEVICE_REMOVED: - status = tz_remove_device(context); - break; - - case TZ_NOTIFY_TEMPERATURE_CHANGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Temperature (_TMP) change event detected.\n")); - tz_policy_check(*context); - status = tz_get_temperature(tz); - if (ACPI_SUCCESS(status)) { - status = tz_osl_generate_event(notify_type, tz); - } - break; - - case TZ_NOTIFY_THRESHOLD_CHANGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Threshold (_SCP) change event detected.\n")); - status = tz_policy_remove_device(tz); - if (ACPI_SUCCESS(status)) { - status = tz_policy_add_device(tz); - } - status = tz_osl_generate_event(notify_type, tz); - break; - - case TZ_NOTIFY_DEVICE_LISTS_CHANGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Device lists (_ALx, _PSL, _TZD) change event detected.\n")); - status = tz_policy_remove_device(tz); - if (ACPI_SUCCESS(status)) { - status = tz_policy_add_device(tz); - } - status = tz_osl_generate_event(notify_type, tz); - break; - - default: - status = AE_SUPPORT; - break; - } - - return_ACPI_STATUS(status); -} - - -/**************************************************************************** - * - * FUNCTION: tz_request - * - ****************************************************************************/ - -acpi_status -tz_request ( - BM_REQUEST *request, - void *context) -{ - acpi_status status = AE_OK; - TZ_CONTEXT *tz = NULL; - - FUNCTION_TRACE("tz_request"); - - /* - * Must have a valid request structure and context. - */ - if (!request || !context) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - tz = (TZ_CONTEXT*)context; - - /* - * Handle request: - * --------------- - */ - switch (request->command) { - - default: - status = AE_SUPPORT; - break; - } - - request->status = status; - - return_ACPI_STATUS(status); -} diff -Nur linux-2.4.19/drivers/acpi/ospm/thermal/tz_osl.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/tz_osl.c --- linux-2.4.19/drivers/acpi/ospm/thermal/tz_osl.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/tz_osl.c Wed Dec 31 16:00:00 1969 @@ -1,398 +0,0 @@ -/****************************************************************************** - * - * Module Name: tz_osl.c - * $Revision: 25 $ - * - *****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include "tz.h" - - -MODULE_AUTHOR("Andrew Grover"); -MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Thermal Zone Driver"); -MODULE_LICENSE("GPL"); - -int TZP = 0; -MODULE_PARM(TZP, "i"); -MODULE_PARM_DESC(TZP, "Thermal zone polling frequency, in 1/10 seconds.\n"); - - -#define TZ_PROC_ROOT "thermal" -#define TZ_PROC_STATUS "status" -#define TZ_PROC_INFO "info" - -extern struct proc_dir_entry *bm_proc_root; -static struct proc_dir_entry *tz_proc_root = NULL; - - -/**************************************************************************** - * - * FUNCTION: tz_osl_proc_read_info - * - ****************************************************************************/ - -static int -tz_osl_proc_read_info ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - acpi_status status = AE_OK; - char name[5]; - acpi_buffer buffer = {sizeof(name), &name}; - TZ_CONTEXT *tz = NULL; - TZ_THRESHOLDS *thresholds = NULL; - char *p = page; - int len = 0; - u32 i,j; - u32 t = 0; - - if (!context || (off != 0)) - goto end; - - tz = (TZ_CONTEXT*)context; - - thresholds = &(tz->policy.thresholds); - - p += sprintf(p, "critical (S5): trip=%d\n", thresholds->critical.temperature); - - if (thresholds->hot.is_valid) - p += sprintf(p, "critical (S4): trip=%d\n", thresholds->hot.temperature); - - if (thresholds->passive.is_valid) { - p += sprintf(p, "passive: trip=%d tc1=%d tc2=%d tsp=%d devices=", thresholds->passive.temperature, thresholds->passive.tc1, thresholds->passive.tc2, thresholds->passive.tsp); - for (j=0; jpassive.devices.count; j++) - p += sprintf(p, "%08x%c", thresholds->passive.devices.handles[j], (j==thresholds->passive.devices.count-1)?'\n':','); - } - - for (i=0; iactive[i].is_valid)) - break; - p += sprintf(p, "active[%d]: trip=%d devices=", i, thresholds->active[i].temperature); - for (j=0; jactive[i].devices.count; j++) - p += sprintf(p, "%08x%c", thresholds->active[i].devices.handles[j], (j==thresholds->passive.devices.count-1)?'\n':','); - } - - p += sprintf(p, "cooling mode: "); - switch (tz->policy.cooling_mode) { - case TZ_COOLING_MODE_ACTIVE: - p += sprintf(p, "active (noisy)\n"); - break; - case TZ_COOLING_MODE_PASSIVE: - p += sprintf(p, "passive (quiet)\n"); - break; - default: - p += sprintf(p, "unknown\n"); - break; - } - - p += sprintf(p, "polling: "); - switch (tz->policy.polling_freq) { - case 0: - p += sprintf(p, "disabled\n"); - break; - default: - p += sprintf(p, "%d dS\n", tz->policy.polling_freq); - break; - } - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - return len; -} - - -/**************************************************************************** - * - * FUNCTION: tz_osl_proc_write_info - * - ****************************************************************************/ - -static int tz_osl_proc_write_info ( - struct file *file, - const char *buffer, - unsigned long count, - void *data) -{ - TZ_CONTEXT *tz = NULL; - u32 state = 0; - u32 size = 0; - - if (!buffer || (count==0) || !data) { - goto end; - } - - tz = (TZ_CONTEXT*)data; - - size = strlen(buffer); - if (size < 4) - goto end; - - /* Cooling preference: "scp=0" (active) or "scp=1" (passive) */ - if (0 == strncmp(buffer, "scp=", 4)) { - tz_set_cooling_preference(tz, (buffer[4] - '0')); - } - - /* Polling frequency: "tzp=X" (poll every X [0-9] seconds) */ - else if (0 == strncmp(buffer, "tzp=", 4)) { - tz->policy.polling_freq = (buffer[4] - '0') * 10; - tz_policy_check(tz); - } - -end: - return count; -} - - -/**************************************************************************** - * - * FUNCTION: tz_osl_proc_read_status - * - ****************************************************************************/ - -static int -tz_osl_proc_read_status ( - char *page, - char **start, - off_t off, - int count, - int *eof, - void *context) -{ - TZ_CONTEXT *tz = NULL; - char *p = page; - int len = 0; - - if (!context || (off != 0)) { - goto end; - } - - tz = (TZ_CONTEXT*)context; - - /* Temperature */ - - tz_get_temperature(tz); - - p += sprintf(p, "temperature: %d dK\n", tz->policy.temperature); - - p += sprintf(p, "state: "); - if (tz->policy.state == 0) - p += sprintf(p, "ok\n"); - else if (tz->policy.state & TZ_STATE_CRITICAL) - p += sprintf(p, "critical\n"); - else if (tz->policy.state & TZ_STATE_HOT) - p += sprintf(p, "hot\n"); - else { - if (tz->policy.state & TZ_STATE_ACTIVE) - p += sprintf(p, "active[%d] ", tz->policy.state & 0x07); - if (tz->policy.state & TZ_STATE_PASSIVE) - p += sprintf(p, "passive "); - p += sprintf(p, "\n"); - } - -end: - len = (p - page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - - return(len); -} - - -/**************************************************************************** - * - * FUNCTION: tz_osl_add_device - * - ****************************************************************************/ - -acpi_status -tz_osl_add_device( - TZ_CONTEXT *tz) -{ - struct proc_dir_entry *proc_entry = NULL; - struct proc_dir_entry *proc_child_entry = NULL; - - if (!tz) { - return(AE_BAD_PARAMETER); - } - - printk("ACPI: Thermal Zone found\n"); - - proc_entry = proc_mkdir(tz->uid, tz_proc_root); - if (!proc_entry) - return(AE_ERROR); - - proc_child_entry = create_proc_read_entry(TZ_PROC_STATUS, S_IFREG | S_IRUGO, proc_entry, tz_osl_proc_read_status, (void*)tz); - if (!proc_child_entry) - return(AE_ERROR); - - proc_child_entry = create_proc_entry(TZ_PROC_INFO, S_IFREG | 0644, proc_entry); - if (!proc_child_entry) - return(AE_ERROR); - - proc_child_entry->read_proc = tz_osl_proc_read_info; - proc_child_entry->write_proc = tz_osl_proc_write_info; - proc_child_entry->data = (void*)tz; - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: tz_osl_remove_device - * - ****************************************************************************/ - -acpi_status -tz_osl_remove_device ( - TZ_CONTEXT *tz) -{ - char proc_entry[64]; - - if (!tz) { - return(AE_BAD_PARAMETER); - } - - sprintf(proc_entry, "%s/%s", tz->uid, TZ_PROC_INFO); - remove_proc_entry(proc_entry, tz_proc_root); - - sprintf(proc_entry, "%s/%s", tz->uid, TZ_PROC_STATUS); - remove_proc_entry(proc_entry, tz_proc_root); - - sprintf(proc_entry, "%s", tz->uid); - remove_proc_entry(proc_entry, tz_proc_root); - - return(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: tz_osl_generate_event - * - ****************************************************************************/ - -acpi_status -tz_osl_generate_event ( - u32 event, - TZ_CONTEXT *tz) -{ - acpi_status status = AE_OK; - - if (!tz) { - return(AE_BAD_PARAMETER); - } - - switch (event) { - - case TZ_NOTIFY_TEMPERATURE_CHANGE: - status = bm_osl_generate_event(tz->device_handle, - TZ_PROC_ROOT, tz->uid, event, - tz->policy.temperature); - break; - - case TZ_NOTIFY_THRESHOLD_CHANGE: - case TZ_NOTIFY_DEVICE_LISTS_CHANGE: - status = bm_osl_generate_event(tz->device_handle, - TZ_PROC_ROOT, tz->uid, event, 0); - break; - - default: - return(AE_BAD_PARAMETER); - break; - } - - return(status); -} - - -/**************************************************************************** - * - * FUNCTION: tz_osl_init - * - ****************************************************************************/ - -static int __init -tz_osl_init (void) -{ - acpi_status status = AE_OK; - - /* abort if no busmgr */ - if (!bm_proc_root) - return -ENODEV; - - tz_proc_root = proc_mkdir(TZ_PROC_ROOT, bm_proc_root); - if (!tz_proc_root) { - status = AE_ERROR; - } - else { - status = tz_initialize(); - if (ACPI_FAILURE(status)) { - remove_proc_entry(TZ_PROC_ROOT, bm_proc_root); - } - - } - - return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; -} - - -/**************************************************************************** - * - * FUNCTION: tz_osl_cleanup - * - ****************************************************************************/ - -static void __exit -tz_osl_cleanup (void) -{ - tz_terminate(); - - if (tz_proc_root) { - remove_proc_entry(TZ_PROC_ROOT, bm_proc_root); - } - - return; -} - - -module_init(tz_osl_init); -module_exit(tz_osl_cleanup); diff -Nur linux-2.4.19/drivers/acpi/ospm/thermal/tzpolicy.c linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/tzpolicy.c --- linux-2.4.19/drivers/acpi/ospm/thermal/tzpolicy.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/ospm/thermal/tzpolicy.c Wed Dec 31 16:00:00 1969 @@ -1,578 +0,0 @@ -/**************************************************************************** - * - * Module Name: tzpolicy.c - - * $Revision: 30 $ - * - ****************************************************************************/ - -/* - * Copyright (C) 2000, 2001 Andrew Grover - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * TBD: 1. Support performance-limit control for non-processor devices - * (those listed in _TZD, e.g. graphics). - */ - -#include -#include -#include - -#include -#include -#include "tz.h" - - -#define _COMPONENT ACPI_THERMAL - MODULE_NAME ("tzpolicy") - - -/**************************************************************************** - * Globals - ****************************************************************************/ - -void -tz_policy_run ( - unsigned long data); - - -/**************************************************************************** - * Internal Functions - ****************************************************************************/ - -acpi_status -set_performance_limit ( - BM_HANDLE device_handle, - u32 flag) -{ - acpi_status status; - BM_REQUEST request; - - request.status = AE_OK; - request.handle = device_handle; - request.command = PR_COMMAND_SET_PERF_LIMIT; - request.buffer.length = sizeof(u32); - request.buffer.pointer = &flag; - - status = bm_request(&request); - - if (ACPI_FAILURE(status)) - return status; - else - return request.status; -} - - -/**************************************************************************** - * - * FUNCTION: tz_policy_critical - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -tz_policy_critical( - TZ_CONTEXT *tz) -{ - FUNCTION_TRACE("tz_policy_critical"); - - if (!tz) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (tz->policy.temperature >= tz->policy.thresholds.critical.temperature) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Critical (S5) threshold reached.\n")); - /* TBD: Need method for shutting down system. */ - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: tz_policy_hot - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -tz_policy_hot( - TZ_CONTEXT *tz) -{ - FUNCTION_TRACE("tz_policy_hot"); - - if (!tz || !tz->policy.thresholds.hot.is_valid) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (tz->policy.temperature >= tz->policy.thresholds.hot.temperature) { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Critical (S4) threshold reached.\n")); - /* TBD: Need method for invoking OS-level critical suspend. */ - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: tz_policy_passive - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -tz_policy_passive( - TZ_CONTEXT *tz) -{ - TZ_PASSIVE_THRESHOLD *passive = NULL; - static u32 last_temperature = 0; - s32 trend = 0; - u32 i = 0; - - FUNCTION_TRACE("tz_policy_passive"); - - if (!tz || !tz->policy.thresholds.passive.is_valid) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - passive = &(tz->policy.thresholds.passive); - - if (tz->policy.temperature >= passive->temperature) { - /* - * Thermal trend? - * -------------- - * Using the passive cooling equation (see the ACPI - * Specification), calculate the current thermal trend - * (a.k.a. performance delta). - */ - trend = passive->tc1 * (tz->policy.temperature - last_temperature) + passive->tc2 * (tz->policy.temperature - passive->temperature); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "trend[%d] = TC1[%d]*(temp[%d]-last[%d]) + TC2[%d]*(temp[%d]-passive[%d])\n", trend, passive->tc1, tz->policy.temperature, last_temperature, passive->tc2, tz->policy.temperature, passive->temperature)); - - last_temperature = tz->policy.temperature; - - /* - * Heating Up? - * ----------- - * Decrease thermal performance limit on all passive - * cooling devices (processors). - */ - if (trend > 0) { - for (i=0; idevices.count; i++) - set_performance_limit(passive->devices.handles[i], PR_PERF_DEC); - } - /* - * Cooling Off? - * ------------ - * Increase thermal performance limit on all passive - * cooling devices (processors). - */ - else if (trend < 0) { - for (i=0; idevices.count; i++) - set_performance_limit(passive->devices.handles[i], PR_PERF_INC); - } - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: tz_policy_active - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -tz_policy_active( - TZ_CONTEXT *tz) -{ - acpi_status status = AE_OK; - TZ_ACTIVE_THRESHOLD *active = NULL; - u32 i,j = 0; - - FUNCTION_TRACE("tz_policy_active"); - - if (!tz || !tz->policy.thresholds.active[0].is_valid) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - for (i=0; ipolicy.thresholds.active[i]); - if (!active || !active->is_valid) - break; - - /* - * Above Threshold? - * ---------------- - * If not already enabled, turn ON all cooling devices - * associated with this active threshold. - */ - if ((tz->policy.temperature >= active->temperature) && (active->cooling_state != TZ_COOLING_ENABLED)) { - for (j = 0; j < active->devices.count; j++) { - status = bm_set_device_power_state(active->devices.handles[j], ACPI_STATE_D0); - if (ACPI_SUCCESS(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Cooling device [%02x] now ON.\n", active->devices.handles[j])); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to turn ON cooling device [%02x].\n", active->devices.handles[j])); - } - } - active->cooling_state = TZ_COOLING_ENABLED; - } - /* - * Below Threshold? - * ---------------- - * Turn OFF all cooling devices associated with this - * threshold. Note that by checking "if not disabled" we - * turn off all cooling devices for thresholds in the - * TZ_COOLING_STATE_UNKNOWN state, useful as a level-set - * during the first pass. - */ - else if (active->cooling_state != TZ_COOLING_DISABLED) { - for (j = 0; j < active->devices.count; j++) { - status = bm_set_device_power_state(active->devices.handles[j], ACPI_STATE_D3); - if (ACPI_SUCCESS(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Cooling device [%02x] now OFF.\n", active->devices.handles[j])); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unable to turn OFF cooling device [%02x].\n", active->devices.handles[j])); - } - } - active->cooling_state = TZ_COOLING_DISABLED; - } - } - - return_ACPI_STATUS(AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: tz_policy_check - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: Note that this function will get called whenever: - * 1. A thermal event occurs. - * 2. The polling/sampling time period expires. - * - ****************************************************************************/ - -void -tz_policy_check ( - void *context) -{ - acpi_status status = AE_OK; - TZ_CONTEXT *tz = NULL; - TZ_POLICY *policy = NULL; - TZ_THRESHOLDS *thresholds = NULL; - u32 previous_temperature = 0; - u32 previous_state = 0; - u32 active_index = 0; - u32 i = 0; - u32 sleep_time = 0; - - FUNCTION_TRACE("tz_policy_check"); - - if (!context) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); - return_VOID; - } - - tz = (TZ_CONTEXT*)context; - policy = &(tz->policy); - thresholds = &(tz->policy.thresholds); - - /* - * Preserve Previous State: - * ------------------------ - */ - previous_temperature = tz->policy.temperature; - previous_state = tz->policy.state; - - /* - * Get Temperature: - * ---------------- - */ - status = tz_get_temperature(tz); - if (ACPI_FAILURE(status)) { - return_VOID; - } - - /* - * Calculate State: - * ---------------- - */ - policy->state = TZ_STATE_OK; - - /* Critical? */ - if (policy->temperature >= thresholds->critical.temperature) - policy->state |= TZ_STATE_CRITICAL; - - /* Hot? */ - if ((thresholds->hot.is_valid) && (policy->temperature >= thresholds->hot.temperature)) - policy->state |= TZ_STATE_CRITICAL; - - /* Passive? */ - if ((thresholds->passive.is_valid) && (policy->temperature >= thresholds->passive.temperature)) - policy->state |= TZ_STATE_PASSIVE; - - /* Active? */ - if (thresholds->active[0].is_valid) { - for (i=0; iactive[i].is_valid) && (policy->temperature >= thresholds->active[i].temperature)) { - policy->state |= TZ_STATE_ACTIVE; - if (i > active_index) - active_index = i; - } - } - policy->state |= active_index; - } - - /* - * Invoke Policy: - * -------------- - * Note that policy must be invoked both when 'going into' a - * policy state (e.g. to allow fans to be turned on) and 'going - * out of' a policy state (e.g. to allow fans to be turned off); - * thus we must preserve the previous state. - */ - if (policy->state & TZ_STATE_CRITICAL) - tz_policy_critical(tz); - if (policy->state & TZ_STATE_HOT) - tz_policy_hot(tz); - if ((policy->state & TZ_STATE_PASSIVE) || (previous_state & TZ_STATE_PASSIVE)) - tz_policy_passive(tz); - if ((policy->state & TZ_STATE_ACTIVE) || (previous_state & TZ_STATE_ACTIVE)) - tz_policy_active(tz); - - /* - * Calculate Sleep Time: - * --------------------- - * If we're in the passive state, use _TSP's value. Otherwise - * use _TZP or the OS's default polling frequency. If no polling - * frequency is specified then we'll wait forever (that is, until - * a thermal event occurs -- e.g. never poll). Note that _TSP - * and _TZD values are given in 1/10th seconds. - */ - if (policy->state & TZ_STATE_PASSIVE) - sleep_time = thresholds->passive.tsp * 100; - else if (policy->polling_freq > 0) - sleep_time = policy->polling_freq * 100; - else - sleep_time = WAIT_FOREVER; - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Thermal_zone[%02x]: temperature[%d] state[%08x]\n", tz->device_handle, policy->temperature, policy->state)); - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Scheduling next poll in [%d]ms.\n", sleep_time)); - - /* - * Schedule Next Poll: - * ------------------- - */ - if (sleep_time < WAIT_FOREVER) { - if (timer_pending(&(policy->timer))) - mod_timer(&(policy->timer), (HZ*sleep_time)/1000); - else { - policy->timer.data = (u32)tz; - policy->timer.function = tz_policy_run; - policy->timer.expires = jiffies + (HZ*sleep_time)/1000; - add_timer(&(policy->timer)); - } - } - else { - if (timer_pending(&(policy->timer))) - del_timer(&(policy->timer)); - } - - return_VOID; -} - - -/**************************************************************************** - * - * FUNCTION: tz_policy_run - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - - -void -tz_policy_run ( - unsigned long data) -{ - acpi_status status = AE_OK; - - FUNCTION_TRACE("tz_policy_run"); - - if (!data) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); - return_VOID; - } - - /* - * Defer to Non-Interrupt Level: - * ----------------------------- - * Note that all Linux kernel timers run at interrupt-level (ack!). - */ - status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, tz_policy_check, (void*)data); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Error invoking thermal policy.\n")); - } - - return_VOID; -} - - -/**************************************************************************** - * - * FUNCTION: tz_policy_add_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -tz_policy_add_device ( - TZ_CONTEXT *tz) -{ - acpi_status status = AE_OK; - TZ_THRESHOLDS *thresholds = NULL; - u32 i,j = 0; - - FUNCTION_TRACE("tz_policy_add_device"); - - if (!tz) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding policy for thermal zone [%02x].\n", tz->device_handle)); - - /* - * Get Thresholds: - * --------------- - */ - status = tz_get_thresholds(tz); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Initialize Policies: - * -------------------- - */ - if (tz->policy.thresholds.passive.is_valid) { - for (i=0; ipolicy.thresholds.passive.devices.count; i++) - set_performance_limit(tz->policy.thresholds.passive.devices.handles[i], PR_PERF_MAX); - tz_policy_passive(tz); - } - if (tz->policy.thresholds.active[0].is_valid) - tz_policy_active(tz); - - /* - * Initialize Policy Timer: - * ------------------------ - */ - init_timer(&(tz->policy.timer)); - - /* - * Start Policy: - * ------------- - * Run an initial check using this zone's policy. - */ - tz_policy_check(tz); - - return_ACPI_STATUS(AE_OK); -} - - -/***************************************************************************** - * - * FUNCTION: tz_policy_remove_device - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ****************************************************************************/ - -acpi_status -tz_policy_remove_device( - TZ_CONTEXT *tz) -{ - u32 i = 0; - - FUNCTION_TRACE("tz_remove_device"); - - if (!tz) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing policy for thermal zone [%02x].\n", tz->device_handle)); - - /* - * Delete the thermal zone policy timer entry, if exists. - */ - if (timer_pending(&(tz->policy.timer))) - del_timer(&(tz->policy.timer)); - - /* - * Reset thermal performance limit on all processors back to max. - */ - if (tz->policy.thresholds.passive.is_valid) { - for (i=0; ipolicy.thresholds.passive.devices.count; i++) - set_performance_limit(tz->policy.thresholds.passive.devices.handles[i], PR_PERF_MAX); - } - - return_ACPI_STATUS(AE_OK); -} diff -Nur linux-2.4.19/drivers/acpi/parser/Makefile linux-2.4.19-sgi211r3/drivers/acpi/parser/Makefile --- linux-2.4.19/drivers/acpi/parser/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/parser/psargs.c linux-2.4.19-sgi211r3/drivers/acpi/parser/psargs.c --- linux-2.4.19/drivers/acpi/parser/psargs.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/psargs.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psargs - Parse AML opcode arguments - * $Revision: 52 $ + * $Revision: 61 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #include "acnamesp.h" #define _COMPONENT ACPI_PARSER - MODULE_NAME ("psargs") + ACPI_MODULE_NAME ("psargs") /******************************************************************************* @@ -54,10 +54,10 @@ u32 length = 0; - FUNCTION_TRACE ("Ps_get_next_package_length"); + ACPI_FUNCTION_TRACE ("Ps_get_next_package_length"); - encoded_length = (u32) GET8 (parser_state->aml); + encoded_length = (u32) ACPI_GET8 (parser_state->aml); parser_state->aml++; @@ -70,7 +70,7 @@ case 1: /* 2-byte encoding (next byte + bits 0-3) */ - length = ((GET8 (parser_state->aml) << 04) | + length = ((ACPI_GET8 (parser_state->aml) << 04) | (encoded_length & 0x0F)); parser_state->aml++; break; @@ -78,8 +78,8 @@ case 2: /* 3-byte encoding (next 2 bytes + bits 0-3) */ - length = ((GET8 (parser_state->aml + 1) << 12) | - (GET8 (parser_state->aml) << 04) | + length = ((ACPI_GET8 (parser_state->aml + 1) << 12) | + (ACPI_GET8 (parser_state->aml) << 04) | (encoded_length & 0x0F)); parser_state->aml += 2; break; @@ -87,12 +87,16 @@ case 3: /* 4-byte encoding (next 3 bytes + bits 0-3) */ - length = ((GET8 (parser_state->aml + 2) << 20) | - (GET8 (parser_state->aml + 1) << 12) | - (GET8 (parser_state->aml) << 04) | + length = ((ACPI_GET8 (parser_state->aml + 2) << 20) | + (ACPI_GET8 (parser_state->aml + 1) << 12) | + (ACPI_GET8 (parser_state->aml) << 04) | (encoded_length & 0x0F)); parser_state->aml += 3; break; + + default: + /* Can't get here, only 2 bits / 4 cases */ + break; } return_VALUE (length); @@ -120,7 +124,7 @@ NATIVE_UINT length; - FUNCTION_TRACE ("Ps_get_next_package_end"); + ACPI_FUNCTION_TRACE ("Ps_get_next_package_end"); length = (NATIVE_UINT) acpi_ps_get_next_package_length (parser_state); @@ -148,17 +152,16 @@ acpi_ps_get_next_namestring ( acpi_parse_state *parser_state) { - u8 *start = parser_state->aml; - u8 *end = parser_state->aml; - u32 length; + u8 *start = parser_state->aml; + u8 *end = parser_state->aml; - FUNCTION_TRACE ("Ps_get_next_namestring"); + ACPI_FUNCTION_TRACE ("Ps_get_next_namestring"); /* Handle multiple prefix characters */ - while (acpi_ps_is_prefix_char (GET8 (end))) { + while (acpi_ps_is_prefix_char (ACPI_GET8 (end))) { /* include prefix '\\' or '^' */ end++; @@ -166,7 +169,7 @@ /* Decode the path */ - switch (GET8 (end)) { + switch (ACPI_GET8 (end)) { case 0: /* Null_name */ @@ -177,35 +180,29 @@ end++; break; - case AML_DUAL_NAME_PREFIX: - /* two name segments */ + /* Two name segments */ end += 9; break; - case AML_MULTI_NAME_PREFIX_OP: - /* multiple name segments */ + /* Multiple name segments, 4 chars each */ - length = (u32) GET8 (end + 1) * 4; - end += 2 + length; + end += 2 + ((ACPI_SIZE) ACPI_GET8 (end + 1) * 4); break; - default: - /* single name segment */ - /* assert (Acpi_ps_is_lead (GET8 (End))); */ + /* Single name segment */ end += 4; break; } parser_state->aml = (u8*) end; - return_PTR ((NATIVE_CHAR *) start); } @@ -247,7 +244,7 @@ acpi_parse_object *count; - FUNCTION_TRACE ("Ps_get_next_namepath"); + ACPI_FUNCTION_TRACE ("Ps_get_next_namepath"); path = acpi_ps_get_next_namestring (parser_state); @@ -255,7 +252,7 @@ /* Null name case, create a null namepath object */ acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP); - arg->value.name = path; + arg->common.value.name = path; return_VOID; } @@ -271,7 +268,7 @@ } if (op) { - if (op->opcode == AML_METHOD_OP) { + if (op->common.aml_opcode == AML_METHOD_OP) { /* * The name refers to a control method, so this namepath is a * method invocation. We need to 1) Get the number of arguments @@ -279,21 +276,21 @@ * object into a METHODCALL object. */ count = acpi_ps_get_arg (op, 0); - if (count && count->opcode == AML_BYTE_OP) { + if (count && count->common.aml_opcode == AML_BYTE_OP) { name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP); if (name_op) { /* Change arg into a METHOD CALL and attach the name */ acpi_ps_init_op (arg, AML_INT_METHODCALL_OP); - name_op->value.name = path; + name_op->common.value.name = path; /* Point METHODCALL/NAME to the METHOD Node */ - name_op->node = (acpi_namespace_node *) op; + name_op->common.node = (acpi_namespace_node *) op; acpi_ps_append_arg (arg, name_op); - *arg_count = (u32) count->value.integer & + *arg_count = (u32) count->common.value.integer & METHOD_FLAGS_ARG_COUNT; } } @@ -315,7 +312,7 @@ * pathname */ acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP); - arg->value.name = path; + arg->common.value.name = path; return_VOID; @@ -340,7 +337,7 @@ acpi_generic_state scope_info; - FUNCTION_TRACE ("Ps_get_next_namepath"); + ACPI_FUNCTION_TRACE ("Ps_get_next_namepath"); path = acpi_ps_get_next_namestring (parser_state); @@ -348,65 +345,62 @@ /* Null name case, create a null namepath object */ acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP); - arg->value.name = path; + arg->common.value.name = path; return_VOID; } + /* + * Lookup the name in the internal namespace + */ + scope_info.scope.node = NULL; + node = parser_state->start_node; + if (node) { + scope_info.scope.node = node; + } - if (method_call) { - /* - * Lookup the name in the internal namespace - */ - scope_info.scope.node = NULL; - node = parser_state->start_node; - if (node) { - scope_info.scope.node = node; - } - - /* - * Lookup object. We don't want to add anything new to the namespace - * here, however. So we use MODE_EXECUTE. Allow searching of the - * parent tree, but don't open a new scope -- we just want to lookup the - * object (MUST BE mode EXECUTE to perform upsearch) - */ - status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, IMODE_EXECUTE, - NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, NULL, - &node); - if (ACPI_SUCCESS (status)) { - if (node->type == ACPI_TYPE_METHOD) { - method_node = node; - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "method - %p Path=%p\n", - method_node, path)); - - name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP); - if (name_op) { - /* Change arg into a METHOD CALL and attach name to it */ - - acpi_ps_init_op (arg, AML_INT_METHODCALL_OP); - - name_op->value.name = path; - - /* Point METHODCALL/NAME to the METHOD Node */ + /* + * Lookup object. We don't want to add anything new to the namespace + * here, however. So we use MODE_EXECUTE. Allow searching of the + * parent tree, but don't open a new scope -- we just want to lookup the + * object (MUST BE mode EXECUTE to perform upsearch) + */ + status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, + &node); + if (ACPI_SUCCESS (status)) { + if (node->type == ACPI_TYPE_METHOD) { + method_node = node; + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "method - %p Path=%p\n", + method_node, path)); + + name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP); + if (name_op) { + /* Change arg into a METHOD CALL and attach name to it */ + + acpi_ps_init_op (arg, AML_INT_METHODCALL_OP); + + name_op->common.value.name = path; - name_op->node = method_node; - acpi_ps_append_arg (arg, name_op); + /* Point METHODCALL/NAME to the METHOD Node */ - if (!method_node->object) { - return_VOID; - } + name_op->common.node = method_node; + acpi_ps_append_arg (arg, name_op); - *arg_count = (method_node->object)->method.param_count; + if (!acpi_ns_get_attached_object (method_node)) { + return_VOID; } - return_VOID; + *arg_count = (acpi_ns_get_attached_object (method_node))->method.param_count; } - /* - * Else this is normal named object reference. - * Just init the NAMEPATH object with the pathname. - * (See code below) - */ + return_VOID; } + + /* + * Else this is normal named object reference. + * Just init the NAMEPATH object with the pathname. + * (See code below) + */ } /* @@ -415,7 +409,7 @@ * pathname. */ acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP); - arg->value.name = path; + arg->common.value.name = path; return_VOID; @@ -444,15 +438,14 @@ acpi_parse_object *arg) { - FUNCTION_TRACE_U32 ("Ps_get_next_simple_arg", arg_type); + ACPI_FUNCTION_TRACE_U32 ("Ps_get_next_simple_arg", arg_type); switch (arg_type) { - case ARGP_BYTEDATA: acpi_ps_init_op (arg, AML_BYTE_OP); - arg->value.integer = (u32) GET8 (parser_state->aml); + arg->common.value.integer = (u32) ACPI_GET8 (parser_state->aml); parser_state->aml++; break; @@ -463,7 +456,7 @@ /* Get 2 bytes from the AML stream */ - MOVE_UNALIGNED16_TO_32 (&arg->value.integer, parser_state->aml); + ACPI_MOVE_UNALIGNED16_TO_32 (&arg->common.value.integer, parser_state->aml); parser_state->aml += 2; break; @@ -474,7 +467,7 @@ /* Get 4 bytes from the AML stream */ - MOVE_UNALIGNED32_TO_32 (&arg->value.integer, parser_state->aml); + ACPI_MOVE_UNALIGNED32_TO_32 (&arg->common.value.integer, parser_state->aml); parser_state->aml += 4; break; @@ -485,7 +478,7 @@ /* Get 8 bytes from the AML stream */ - MOVE_UNALIGNED64_TO_64 (&arg->value.integer, parser_state->aml); + ACPI_MOVE_UNALIGNED64_TO_64 (&arg->common.value.integer, parser_state->aml); parser_state->aml += 8; break; @@ -493,9 +486,9 @@ case ARGP_CHARLIST: acpi_ps_init_op (arg, AML_STRING_OP); - arg->value.string = (char*) parser_state->aml; + arg->common.value.string = (char *) parser_state->aml; - while (GET8 (parser_state->aml) != '\0') { + while (ACPI_GET8 (parser_state->aml) != '\0') { parser_state->aml++; } parser_state->aml++; @@ -506,7 +499,12 @@ case ARGP_NAMESTRING: acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP); - arg->value.name = acpi_ps_get_next_namestring (parser_state); + arg->common.value.name = acpi_ps_get_next_namestring (parser_state); + break; + + + default: + ACPI_REPORT_ERROR (("Invalid Arg_type %X\n", arg_type)); break; } @@ -530,33 +528,30 @@ acpi_ps_get_next_field ( acpi_parse_state *parser_state) { - u32 aml_offset = parser_state->aml - - parser_state->aml_start; + u32 aml_offset = ACPI_PTR_DIFF (parser_state->aml, + parser_state->aml_start); acpi_parse_object *field; u16 opcode; u32 name; - FUNCTION_TRACE ("Ps_get_next_field"); + ACPI_FUNCTION_TRACE ("Ps_get_next_field"); /* determine field type */ - switch (GET8 (parser_state->aml)) { - + switch (ACPI_GET8 (parser_state->aml)) { default: opcode = AML_INT_NAMEDFIELD_OP; break; - case 0x00: opcode = AML_INT_RESERVEDFIELD_OP; parser_state->aml++; break; - case 0x01: opcode = AML_INT_ACCESSFIELD_OP; @@ -568,43 +563,52 @@ /* Allocate a new field op */ field = acpi_ps_alloc_op (opcode); - if (field) { - field->aml_offset = aml_offset; + if (!field) { + return_PTR (NULL); + } - /* Decode the field type */ + field->common.aml_offset = aml_offset; - switch (opcode) { - case AML_INT_NAMEDFIELD_OP: + /* Decode the field type */ - /* Get the 4-character name */ + switch (opcode) { + case AML_INT_NAMEDFIELD_OP: - MOVE_UNALIGNED32_TO_32 (&name, parser_state->aml); - acpi_ps_set_name (field, name); - parser_state->aml += 4; + /* Get the 4-character name */ - /* Get the length which is encoded as a package length */ + ACPI_MOVE_UNALIGNED32_TO_32 (&name, parser_state->aml); + acpi_ps_set_name (field, name); + parser_state->aml += 4; - field->value.size = acpi_ps_get_next_package_length (parser_state); - break; + /* Get the length which is encoded as a package length */ + field->common.value.size = acpi_ps_get_next_package_length (parser_state); + break; - case AML_INT_RESERVEDFIELD_OP: - /* Get the length which is encoded as a package length */ + case AML_INT_RESERVEDFIELD_OP: - field->value.size = acpi_ps_get_next_package_length (parser_state); - break; + /* Get the length which is encoded as a package length */ + field->common.value.size = acpi_ps_get_next_package_length (parser_state); + break; - case AML_INT_ACCESSFIELD_OP: - /* Get Access_type and Access_atrib and merge into the field Op */ + case AML_INT_ACCESSFIELD_OP: - field->value.integer = ((GET8 (parser_state->aml) << 8) | - GET8 (parser_state->aml)); - parser_state->aml += 2; - break; - } + /* + * Get Access_type and Access_attrib and merge into the field Op + * Access_type is first operand, Access_attribute is second + */ + field->common.value.integer32 = (ACPI_GET8 (parser_state->aml) << 8); + parser_state->aml++; + field->common.value.integer32 |= ACPI_GET8 (parser_state->aml); + parser_state->aml++; + break; + + default: + /* Opcode was set in previous switch */ + break; } return_PTR (field); @@ -639,7 +643,7 @@ u32 subop; - FUNCTION_TRACE_PTR ("Ps_get_next_arg", parser_state); + ACPI_FUNCTION_TRACE_PTR ("Ps_get_next_arg", parser_state); switch (arg_type) { @@ -679,7 +683,7 @@ } if (prev) { - prev->next = field; + prev->common.next = field; } else { @@ -705,8 +709,8 @@ if (arg) { /* fill in bytelist data */ - arg->value.size = (parser_state->pkg_end - parser_state->aml); - ((acpi_parse2_object *) arg)->data = parser_state->aml; + arg->common.value.size = ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml); + arg->named.data = parser_state->aml; } /* skip to End of byte data */ @@ -717,7 +721,8 @@ case ARGP_TARGET: - case ARGP_SUPERNAME: { + case ARGP_SUPERNAME: + case ARGP_SIMPLENAME: { subop = acpi_ps_peek_opcode (parser_state); if (subop == 0 || acpi_ps_is_leading_char (subop) || @@ -757,6 +762,10 @@ *arg_count = ACPI_VAR_ARGS; } + break; + + default: + ACPI_REPORT_ERROR (("Invalid Arg_type: %X\n", arg_type)); break; } diff -Nur linux-2.4.19/drivers/acpi/parser/psopcode.c linux-2.4.19-sgi211r3/drivers/acpi/parser/psopcode.c --- linux-2.4.19/drivers/acpi/parser/psopcode.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/psopcode.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psopcode - Parser/Interpreter opcode information table - * $Revision: 49 $ + * $Revision: 69 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #define _COMPONENT ACPI_PARSER - MODULE_NAME ("psopcode") + ACPI_MODULE_NAME ("psopcode") #define _UNK 0x6B @@ -45,9 +45,9 @@ #define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */ #define MAX_EXTENDED_OPCODE 0x88 -#define NUM_EXTENDED_OPCODE MAX_EXTENDED_OPCODE + 1 +#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1) #define MAX_INTERNAL_OPCODE -#define NUM_INTERNAL_OPCODE MAX_INTERNAL_OPCODE + 1 +#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1) /******************************************************************************* @@ -184,7 +184,7 @@ #define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) +#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) #define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) #define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) #define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) @@ -219,7 +219,7 @@ #define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_BREAK_OP ARG_NONE #define ARGI_BREAK_POINT_OP ARG_NONE -#define ARGI_BUFFER_OP ARGI_INVALID_OPCODE +#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_BYTE_OP ARGI_INVALID_OPCODE #define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE #define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) @@ -236,7 +236,7 @@ #define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) #define ARGI_DEBUG_OP ARG_NONE #define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) -#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REFERENCE) +#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) #define ARGI_DEVICE_OP ARGI_INVALID_OPCODE #define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) #define ARGI_DWORD_OP ARGI_INVALID_OPCODE @@ -260,7 +260,7 @@ #define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE #define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION, ARGI_TARGETREF) -#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_TARGETREF) +#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) #define ARGI_LOCAL0 ARG_NONE #define ARGI_LOCAL1 ARG_NONE #define ARGI_LOCAL2 ARG_NONE @@ -284,7 +284,7 @@ #define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) #define ARGI_ONE_OP ARG_NONE #define ARGI_ONES_OP ARG_NONE -#define ARGI_PACKAGE_OP ARGI_INVALID_OPCODE +#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE #define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE #define ARGI_QWORD_OP ARGI_INVALID_OPCODE @@ -315,7 +315,7 @@ #define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) #define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) #define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) -#define ARGI_VAR_PACKAGE_OP ARGI_INVALID_OPCODE +#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) #define ARGI_WHILE_OP ARGI_INVALID_OPCODE #define ARGI_WORD_OP ARGI_INVALID_OPCODE @@ -328,7 +328,7 @@ /****************************************************************************** - Opcodes that have associated namespace objects + Opcodes that have associated namespace objects (AML_NSOBJECT flag) AML_SCOPE_OP AML_DEVICE_OP @@ -354,7 +354,7 @@ AML_INT_METHODCALL_OP AML_INT_NAMEPATH_OP - Opcodes that are "namespace" opcodes + Opcodes that are "namespace" opcodes (AML_NSOPCODE flag) AML_SCOPE_OP AML_DEVICE_OP @@ -372,7 +372,7 @@ AML_REGION_OP AML_INT_NAMEDFIELD_OP - Opcodes that have an associated namespace node + Opcodes that have an associated namespace node (AML_NSNODE flag) AML_SCOPE_OP AML_DEVICE_OP @@ -395,7 +395,7 @@ AML_INT_METHODCALL_OP AML_INT_NAMEPATH_OP - Opcodes that define named ACPI objects + Opcodes that define named ACPI objects (AML_NAMED flag) AML_SCOPE_OP AML_DEVICE_OP @@ -410,8 +410,8 @@ AML_REGION_OP AML_INT_NAMEDFIELD_OP - Opcodes that contain executable AML as part of the definition that - must be deferred until needed + Opcodes that contain executable AML as part of the definition that + must be deferred until needed AML_METHOD_OP AML_VAR_PACKAGE_OP @@ -422,6 +422,7 @@ AML_CREATE_DWORD_FIELD_OP AML_CREATE_QWORD_FIELD_OP AML_REGION_OP + AML_BUFFER_OP Field opcodes @@ -447,146 +448,149 @@ */ -static const acpi_opcode_info aml_op_info[] = +const acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { -/* Index Name Parser Args Interpreter Args Class Type Flags */ +/*! [Begin] no source code translation */ +/* Index Name Parser Args Interpreter Args ObjectType Class Type Flags */ -/* 00 */ ACPI_OP ("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), -/* 01 */ ACPI_OP ("One", ARGP_ONE_OP, ARGI_ONE_OP, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), -/* 02 */ ACPI_OP ("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 03 */ ACPI_OP ("Name", ARGP_NAME_OP, ARGI_NAME_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 04 */ ACPI_OP ("Byte_const", ARGP_BYTE_OP, ARGI_BYTE_OP, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), -/* 05 */ ACPI_OP ("Word_const", ARGP_WORD_OP, ARGI_WORD_OP, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), -/* 06 */ ACPI_OP ("Dword_const", ARGP_DWORD_OP, ARGI_DWORD_OP, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), -/* 07 */ ACPI_OP ("String", ARGP_STRING_OP, ARGI_STRING_OP, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), -/* 08 */ ACPI_OP ("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 09 */ ACPI_OP ("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP, AML_CLASS_ARGUMENT, AML_TYPE_DATA_TERM, AML_HAS_ARGS), -/* 0A */ ACPI_OP ("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP, AML_CLASS_ARGUMENT, AML_TYPE_DATA_TERM, AML_HAS_ARGS), -/* 0B */ ACPI_OP ("Method", ARGP_METHOD_OP, ARGI_METHOD_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER), -/* 0C */ ACPI_OP ("Local0", ARGP_LOCAL0, ARGI_LOCAL0, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 0D */ ACPI_OP ("Local1", ARGP_LOCAL1, ARGI_LOCAL1, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 0E */ ACPI_OP ("Local2", ARGP_LOCAL2, ARGI_LOCAL2, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 0F */ ACPI_OP ("Local3", ARGP_LOCAL3, ARGI_LOCAL3, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 10 */ ACPI_OP ("Local4", ARGP_LOCAL4, ARGI_LOCAL4, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 11 */ ACPI_OP ("Local5", ARGP_LOCAL5, ARGI_LOCAL5, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 12 */ ACPI_OP ("Local6", ARGP_LOCAL6, ARGI_LOCAL6, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 13 */ ACPI_OP ("Local7", ARGP_LOCAL7, ARGI_LOCAL7, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), -/* 14 */ ACPI_OP ("Arg0", ARGP_ARG0, ARGI_ARG0, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), -/* 15 */ ACPI_OP ("Arg1", ARGP_ARG1, ARGI_ARG1, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), -/* 16 */ ACPI_OP ("Arg2", ARGP_ARG2, ARGI_ARG2, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), -/* 17 */ ACPI_OP ("Arg3", ARGP_ARG3, ARGI_ARG3, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), -/* 18 */ ACPI_OP ("Arg4", ARGP_ARG4, ARGI_ARG4, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), -/* 19 */ ACPI_OP ("Arg5", ARGP_ARG5, ARGI_ARG5, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), -/* 1_a */ ACPI_OP ("Arg6", ARGP_ARG6, ARGI_ARG6, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), -/* 1_b */ ACPI_OP ("Store", ARGP_STORE_OP, ARGI_STORE_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 1_c */ ACPI_OP ("Ref_of", ARGP_REF_OF_OP, ARGI_REF_OF_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), -/* 1_d */ ACPI_OP ("Add", ARGP_ADD_OP, ARGI_ADD_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 1_e */ ACPI_OP ("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R), -/* 1_f */ ACPI_OP ("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 20 */ ACPI_OP ("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), -/* 21 */ ACPI_OP ("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), -/* 22 */ ACPI_OP ("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 23 */ ACPI_OP ("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_2T_1R, AML_FLAGS_EXEC_2A_2T_1R), -/* 24 */ ACPI_OP ("Shift_left", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 25 */ ACPI_OP ("Shift_right", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 26 */ ACPI_OP ("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 27 */ ACPI_OP ("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 28 */ ACPI_OP ("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 29 */ ACPI_OP ("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 2_a */ ACPI_OP ("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH), -/* 2_b */ ACPI_OP ("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 2_c */ ACPI_OP ("Find_set_left_bit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 2_d */ ACPI_OP ("Find_set_right_bit", ARGP_FIND_SET_RIGHT_BIT_OP,ARGI_FIND_SET_RIGHT_BIT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 2_e */ ACPI_OP ("Deref_of", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), -/* 2_f */ ACPI_OP ("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), -/* 30 */ ACPI_OP ("Size_of", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), -/* 31 */ ACPI_OP ("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R), -/* 32 */ ACPI_OP ("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), -/* 33 */ ACPI_OP ("Create_dWord_field", ARGP_CREATE_DWORD_FIELD_OP,ARGI_CREATE_DWORD_FIELD_OP, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), -/* 34 */ ACPI_OP ("Create_word_field", ARGP_CREATE_WORD_FIELD_OP, ARGI_CREATE_WORD_FIELD_OP, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), -/* 35 */ ACPI_OP ("Create_byte_field", ARGP_CREATE_BYTE_FIELD_OP, ARGI_CREATE_BYTE_FIELD_OP, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), -/* 36 */ ACPI_OP ("Create_bit_field", ARGP_CREATE_BIT_FIELD_OP, ARGI_CREATE_BIT_FIELD_OP, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), -/* 37 */ ACPI_OP ("Object_type", ARGP_TYPE_OP, ARGI_TYPE_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), -/* 38 */ ACPI_OP ("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL), -/* 39 */ ACPI_OP ("LOr", ARGP_LOR_OP, ARGI_LOR_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL), -/* 3_a */ ACPI_OP ("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), -/* 3_b */ ACPI_OP ("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL), -/* 3_c */ ACPI_OP ("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL), -/* 3_d */ ACPI_OP ("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL), -/* 3_e */ ACPI_OP ("If", ARGP_IF_OP, ARGI_IF_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), -/* 3_f */ ACPI_OP ("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), -/* 40 */ ACPI_OP ("While", ARGP_WHILE_OP, ARGI_WHILE_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), -/* 41 */ ACPI_OP ("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), -/* 42 */ ACPI_OP ("Return", ARGP_RETURN_OP, ARGI_RETURN_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), -/* 43 */ ACPI_OP ("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), -/* 44 */ ACPI_OP ("Break_point", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), -/* 45 */ ACPI_OP ("Ones", ARGP_ONES_OP, ARGI_ONES_OP, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), +/* 00 */ ACPI_OP ("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), +/* 01 */ ACPI_OP ("One", ARGP_ONE_OP, ARGI_ONE_OP, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), +/* 02 */ ACPI_OP ("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP, INTERNAL_TYPE_ALIAS, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 03 */ ACPI_OP ("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 04 */ ACPI_OP ("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 05 */ ACPI_OP ("WordConst", ARGP_WORD_OP, ARGI_WORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 06 */ ACPI_OP ("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 07 */ ACPI_OP ("String", ARGP_STRING_OP, ARGI_STRING_OP, ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 08 */ ACPI_OP ("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP, INTERNAL_TYPE_SCOPE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 09 */ ACPI_OP ("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP, ACPI_TYPE_BUFFER, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), +/* 0A */ ACPI_OP ("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), +/* 0B */ ACPI_OP ("Method", ARGP_METHOD_OP, ARGI_METHOD_OP, ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER), +/* 0C */ ACPI_OP ("Local0", ARGP_LOCAL0, ARGI_LOCAL0, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 0D */ ACPI_OP ("Local1", ARGP_LOCAL1, ARGI_LOCAL1, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 0E */ ACPI_OP ("Local2", ARGP_LOCAL2, ARGI_LOCAL2, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 0F */ ACPI_OP ("Local3", ARGP_LOCAL3, ARGI_LOCAL3, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 10 */ ACPI_OP ("Local4", ARGP_LOCAL4, ARGI_LOCAL4, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 11 */ ACPI_OP ("Local5", ARGP_LOCAL5, ARGI_LOCAL5, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 12 */ ACPI_OP ("Local6", ARGP_LOCAL6, ARGI_LOCAL6, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 13 */ ACPI_OP ("Local7", ARGP_LOCAL7, ARGI_LOCAL7, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0), +/* 14 */ ACPI_OP ("Arg0", ARGP_ARG0, ARGI_ARG0, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 15 */ ACPI_OP ("Arg1", ARGP_ARG1, ARGI_ARG1, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 16 */ ACPI_OP ("Arg2", ARGP_ARG2, ARGI_ARG2, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 17 */ ACPI_OP ("Arg3", ARGP_ARG3, ARGI_ARG3, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 18 */ ACPI_OP ("Arg4", ARGP_ARG4, ARGI_ARG4, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 19 */ ACPI_OP ("Arg5", ARGP_ARG5, ARGI_ARG5, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 1A */ ACPI_OP ("Arg6", ARGP_ARG6, ARGI_ARG6, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0), +/* 1B */ ACPI_OP ("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), +/* 1C */ ACPI_OP ("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), +/* 1D */ ACPI_OP ("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 1E */ ACPI_OP ("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 1F */ ACPI_OP ("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 20 */ ACPI_OP ("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), +/* 21 */ ACPI_OP ("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), +/* 22 */ ACPI_OP ("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 23 */ ACPI_OP ("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_2T_1R, AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT), +/* 24 */ ACPI_OP ("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 25 */ ACPI_OP ("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 26 */ ACPI_OP ("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 27 */ ACPI_OP ("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 28 */ ACPI_OP ("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 29 */ ACPI_OP ("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 2A */ ACPI_OP ("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), +/* 2B */ ACPI_OP ("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 2C */ ACPI_OP ("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 2D */ ACPI_OP ("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP,ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 2E */ ACPI_OP ("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), +/* 2F */ ACPI_OP ("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), +/* 30 */ ACPI_OP ("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), +/* 31 */ ACPI_OP ("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 32 */ ACPI_OP ("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT), +/* 33 */ ACPI_OP ("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP,ARGI_CREATE_DWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 34 */ ACPI_OP ("CreateWordField", ARGP_CREATE_WORD_FIELD_OP, ARGI_CREATE_WORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 35 */ ACPI_OP ("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP, ARGI_CREATE_BYTE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 36 */ ACPI_OP ("CreateBitField", ARGP_CREATE_BIT_FIELD_OP, ARGI_CREATE_BIT_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 37 */ ACPI_OP ("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), +/* 38 */ ACPI_OP ("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 39 */ ACPI_OP ("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 3A */ ACPI_OP ("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), +/* 3B */ ACPI_OP ("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 3C */ ACPI_OP ("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 3D */ ACPI_OP ("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), +/* 3E */ ACPI_OP ("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 3F */ ACPI_OP ("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 40 */ ACPI_OP ("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 41 */ ACPI_OP ("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 42 */ ACPI_OP ("Return", ARGP_RETURN_OP, ARGI_RETURN_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), +/* 43 */ ACPI_OP ("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 44 */ ACPI_OP ("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 45 */ ACPI_OP ("Ones", ARGP_ONES_OP, ARGI_ONES_OP, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), /* Prefixed opcodes (Two-byte opcodes with a prefix op) */ -/* 46 */ ACPI_OP ("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 47 */ ACPI_OP ("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ), -/* 48 */ ACPI_OP ("Cond_ref_of", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 49 */ ACPI_OP ("Create_field", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_FIELD | AML_CREATE), -/* 4_a */ ACPI_OP ("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, AML_FLAGS_EXEC_1A_1T_0R), -/* 4_b */ ACPI_OP ("Stall", ARGP_STALL_OP, ARGI_STALL_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), -/* 4_c */ ACPI_OP ("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), -/* 4_d */ ACPI_OP ("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), -/* 4_e */ ACPI_OP ("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), -/* 4_f */ ACPI_OP ("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), -/* 50 */ ACPI_OP ("Reset", ARGP_RESET_OP, ARGI_RESET_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), -/* 51 */ ACPI_OP ("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), -/* 52 */ ACPI_OP ("From_bCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 53 */ ACPI_OP ("To_bCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 54 */ ACPI_OP ("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), -/* 55 */ ACPI_OP ("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), -/* 56 */ ACPI_OP ("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), -/* 57 */ ACPI_OP ("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R), -/* 58 */ ACPI_OP ("Op_region", ARGP_REGION_OP, ARGI_REGION_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER), -/* 59 */ ACPI_OP ("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), -/* 5_a */ ACPI_OP ("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 5_b */ ACPI_OP ("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 5_c */ ACPI_OP ("Power_resource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 5_d */ ACPI_OP ("Thermal_zone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), -/* 5_e */ ACPI_OP ("Index_field", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), -/* 5_f */ ACPI_OP ("Bank_field", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), +/* 46 */ ACPI_OP ("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 47 */ ACPI_OP ("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ), +/* 48 */ ACPI_OP ("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), +/* 49 */ ACPI_OP ("CreateField", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_FIELD | AML_CREATE), +/* 4A */ ACPI_OP ("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, AML_FLAGS_EXEC_1A_1T_0R), +/* 4B */ ACPI_OP ("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 4C */ ACPI_OP ("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 4D */ ACPI_OP ("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), +/* 4E */ ACPI_OP ("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 4F */ ACPI_OP ("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), +/* 50 */ ACPI_OP ("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 51 */ ACPI_OP ("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 52 */ ACPI_OP ("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 53 */ ACPI_OP ("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 54 */ ACPI_OP ("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), +/* 55 */ ACPI_OP ("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), +/* 56 */ ACPI_OP ("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0), +/* 57 */ ACPI_OP ("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R), +/* 58 */ ACPI_OP ("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP, ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER), +/* 59 */ ACPI_OP ("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, INTERNAL_TYPE_FIELD_DEFN,AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), +/* 5A */ ACPI_OP ("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5B */ ACPI_OP ("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP, ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5C */ ACPI_OP ("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP, ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5D */ ACPI_OP ("ThermalZone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 5E */ ACPI_OP ("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, INTERNAL_TYPE_INDEX_FIELD_DEFN,AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), +/* 5F */ ACPI_OP ("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, INTERNAL_TYPE_BANK_FIELD_DEFN,AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), /* Internal opcodes that map to invalid AML opcodes */ -/* 60 */ ACPI_OP ("LNot_equal", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS), -/* 61 */ ACPI_OP ("LLess_equal", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS), -/* 62 */ ACPI_OP ("LGreater_equal", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS), -/* 63 */ ACPI_OP ("[Name_path]", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE ), -/* 64 */ ACPI_OP ("[Method_call]", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP, AML_CLASS_METHOD_CALL, AML_TYPE_METHOD_CALL, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), -/* 65 */ ACPI_OP ("[Byte_list]", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), -/* 66 */ ACPI_OP ("[Reserved_field]", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), -/* 67 */ ACPI_OP ("[Named_field]", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ), -/* 68 */ ACPI_OP ("[Access_field]", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), -/* 69 */ ACPI_OP ("[Static_string", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), -/* 6_a */ ACPI_OP ("[Return Value]", ARG_NONE, ARG_NONE, AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, AML_HAS_ARGS | AML_HAS_RETVAL), -/* 6_b */ ACPI_OP ("UNKNOWN_OP!", ARG_NONE, ARG_NONE, AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), -/* 6_c */ ACPI_OP ("ASCII_ONLY!", ARG_NONE, ARG_NONE, AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), -/* 6_d */ ACPI_OP ("PREFIX_ONLY!", ARG_NONE, ARG_NONE, AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 60 */ ACPI_OP ("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), +/* 61 */ ACPI_OP ("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), +/* 62 */ ACPI_OP ("LGreaterEqual", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), +/* 63 */ ACPI_OP ("[NamePath]", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP, INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE ), +/* 64 */ ACPI_OP ("[MethodCall]", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP, ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, AML_TYPE_METHOD_CALL, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), +/* 65 */ ACPI_OP ("[ByteList]", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP, ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), +/* 66 */ ACPI_OP ("[ReservedField]", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), +/* 67 */ ACPI_OP ("[NamedField]", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ), +/* 68 */ ACPI_OP ("[AccessField]", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), +/* 69 */ ACPI_OP ("[StaticString", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), +/* 6A */ ACPI_OP ("[Return Value]", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, AML_HAS_ARGS | AML_HAS_RETVAL), +/* 6B */ ACPI_OP ("UNKNOWN_OP!", ARG_NONE, ARG_NONE, INTERNAL_TYPE_INVALID, AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 6C */ ACPI_OP ("ASCII_ONLY!", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 6D */ ACPI_OP ("PREFIX_ONLY!", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), /* ACPI 2.0 opcodes */ -/* 6_e */ ACPI_OP ("Qword_const", ARGP_QWORD_OP, ARGI_QWORD_OP, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0), -/* 6_f */ ACPI_OP ("Var_package", ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP, AML_CLASS_ARGUMENT, AML_TYPE_DATA_TERM, AML_HAS_ARGS | AML_DEFER), -/* 70 */ ACPI_OP ("Concat_res", ARGP_CONCAT_RES_OP, ARGI_CONCAT_RES_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R), -/* 71 */ ACPI_OP ("Mod", ARGP_MOD_OP, ARGI_MOD_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R), -/* 72 */ ACPI_OP ("Create_qWord_field", ARGP_CREATE_QWORD_FIELD_OP,ARGI_CREATE_QWORD_FIELD_OP, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), -/* 73 */ ACPI_OP ("To_buffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 74 */ ACPI_OP ("To_decimal_string", ARGP_TO_DEC_STR_OP, ARGI_TO_DEC_STR_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 75 */ ACPI_OP ("To_hex_string", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 76 */ ACPI_OP ("To_integer", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 77 */ ACPI_OP ("To_string", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R), -/* 78 */ ACPI_OP ("Copy_object", ARGP_COPY_OP, ARGI_COPY_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), -/* 79 */ ACPI_OP ("Mid", ARGP_MID_OP, ARGI_MID_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, AML_FLAGS_EXEC_3A_1T_1R), -/* 7_a */ ACPI_OP ("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), -/* 7_b */ ACPI_OP ("Load_table", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), -/* 7_c */ ACPI_OP ("Data_op_region", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), +/* 6E */ ACPI_OP ("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT), +/* 6F */ ACPI_OP ("Package /*Var*/", ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER), +/* 70 */ ACPI_OP ("ConcatenateResTemplate", ARGP_CONCAT_RES_OP, ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 71 */ ACPI_OP ("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 72 */ ACPI_OP ("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP,ARGI_CREATE_QWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), +/* 73 */ ACPI_OP ("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 74 */ ACPI_OP ("ToDecimalString", ARGP_TO_DEC_STR_OP, ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 75 */ ACPI_OP ("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 76 */ ACPI_OP ("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), +/* 77 */ ACPI_OP ("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), +/* 78 */ ACPI_OP ("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), +/* 79 */ ACPI_OP ("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT), +/* 7A */ ACPI_OP ("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), +/* 7B */ ACPI_OP ("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), +/* 7C */ ACPI_OP ("DataTableRegion", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), +/* 7D */ ACPI_OP ("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, INTERNAL_TYPE_SCOPE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE) +/*! [End] no source code translation !*/ }; /* @@ -594,7 +598,7 @@ * index into the table above */ -static const u8 aml_short_op_info_index[256] = +static const u8 acpi_gbl_short_op_index[256] = { /* 0 1 2 3 4 5 6 7 */ /* 8 9 A B C D E F */ @@ -604,7 +608,7 @@ /* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, -/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, _UNK, +/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D, /* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, /* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, @@ -633,7 +637,7 @@ }; -static const u8 aml_long_op_info_index[NUM_EXTENDED_OPCODE] = +static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = { /* 0 1 2 3 4 5 6 7 */ /* 8 9 A B C D E F */ @@ -676,57 +680,40 @@ acpi_ps_get_opcode_info ( u16 opcode) { - const acpi_opcode_info *op_info; - u8 upper_opcode; - u8 lower_opcode; - - - PROC_NAME ("Ps_get_opcode_info"); - - - /* Split the 16-bit opcode into separate bytes */ - - upper_opcode = (u8) (opcode >> 8); - lower_opcode = (u8) opcode; - - /* Default is "unknown opcode" */ - - op_info = &aml_op_info [_UNK]; + ACPI_FUNCTION_NAME ("Ps_get_opcode_info"); /* * Detect normal 8-bit opcode or extended 16-bit opcode */ - - switch (upper_opcode) { + switch ((u8) (opcode >> 8)) { case 0: /* Simple (8-bit) opcode: 0-255, can't index beyond table */ - op_info = &aml_op_info [aml_short_op_info_index [lower_opcode]]; - break; - + return (&acpi_gbl_aml_op_info [acpi_gbl_short_op_index [(u8) opcode]]); case AML_EXTOP: /* Extended (16-bit, prefix+opcode) opcode */ - if (lower_opcode <= MAX_EXTENDED_OPCODE) { - op_info = &aml_op_info [aml_long_op_info_index [lower_opcode]]; + if (((u8) opcode) <= MAX_EXTENDED_OPCODE) { + return (&acpi_gbl_aml_op_info [acpi_gbl_long_op_index [(u8) opcode]]); } - break; + /* Else fall through to error case below */ + /*lint -fallthrough */ default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown extended opcode=%X\n", opcode)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown extended opcode [%X]\n", opcode)); break; } - /* Get the Op info pointer for this opcode */ + /* Default is "unknown opcode" */ - return (op_info); + return (&acpi_gbl_aml_op_info [_UNK]); } @@ -747,6 +734,8 @@ acpi_ps_get_opcode_name ( u16 opcode) { +#ifdef ACPI_DEBUG + const acpi_opcode_info *op; @@ -754,11 +743,11 @@ /* Always guaranteed to return a valid pointer */ -#ifdef ACPI_DEBUG return (op->name); + #else return ("AE_NOT_CONFIGURED"); + #endif } - diff -Nur linux-2.4.19/drivers/acpi/parser/psparse.c linux-2.4.19-sgi211r3/drivers/acpi/parser/psparse.c --- linux-2.4.19/drivers/acpi/parser/psparse.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/psparse.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psparse - Parser top level AML parse routines - * $Revision: 104 $ + * $Revision: 127 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,15 +38,13 @@ #include "acdispat.h" #include "amlcode.h" #include "acnamesp.h" -#include "acdebug.h" #include "acinterp.h" #define _COMPONENT ACPI_PARSER - MODULE_NAME ("psparse") + ACPI_MODULE_NAME ("psparse") -u32 acpi_gbl_depth = 0; -extern u32 acpi_gbl_scope_depth; +static u32 acpi_gbl_depth = 0; /******************************************************************************* @@ -61,7 +59,7 @@ * ******************************************************************************/ -static u32 +u32 acpi_ps_get_opcode_size ( u32 opcode) { @@ -99,32 +97,16 @@ aml = parser_state->aml; - opcode = (u16) GET8 (aml); + opcode = (u16) ACPI_GET8 (aml); - aml++; - - /* - * Original code special cased LNOTEQUAL, LLESSEQUAL, LGREATEREQUAL. - * These opcodes are no longer recognized. Instead, they are broken into - * two opcodes. - * - * - * if (Opcode == AML_EXTOP - * || (Opcode == AML_LNOT - * && (GET8 (Aml) == AML_LEQUAL - * || GET8 (Aml) == AML_LGREATER - * || GET8 (Aml) == AML_LLESS))) - * - * extended Opcode, !=, <=, or >= - */ if (opcode == AML_EXTOP) { /* Extended opcode */ - opcode = (u16) ((opcode << 8) | GET8 (aml)); + aml++; + opcode = (u16) ((opcode << 8) | ACPI_GET8 (aml)); } - return (opcode); } @@ -188,13 +170,13 @@ * PARAMETERS: Walk_state - Current State * Op - Op to complete * - * RETURN: TRUE if Op and subtree was deleted + * RETURN: None. * * DESCRIPTION: Perform any cleanup at the completion of an Op. * ******************************************************************************/ -static u8 +void acpi_ps_complete_this_op ( acpi_walk_state *walk_state, acpi_parse_object *op) @@ -206,8 +188,14 @@ acpi_parse_object *replacement_op = NULL; - FUNCTION_TRACE_PTR ("Ps_complete_this_op", op); + ACPI_FUNCTION_TRACE_PTR ("Ps_complete_this_op", op); + + + /* Check for null Op, can happen if AML code is corrupt */ + if (!op) { + return_VOID; + } /* Delete this op and the subtree below it if asked to */ @@ -215,60 +203,84 @@ (walk_state->op_info->class != AML_CLASS_ARGUMENT)) { /* Make sure that we only delete this subtree */ - if (op->parent) { + if (op->common.parent) { /* * Check if we need to replace the operator and its subtree * with a return value op (placeholder op) */ - parent_info = acpi_ps_get_opcode_info (op->parent->opcode); + parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); switch (parent_info->class) { - case AML_CLASS_CONTROL: /* IF, ELSE, WHILE only */ + case AML_CLASS_CONTROL: break; - case AML_CLASS_NAMED_OBJECT: /* Scope, method, etc. */ case AML_CLASS_CREATE: /* * These opcodes contain Term_arg operands. The current - * op must be replace by a placeholder return op + * op must be replaced by a placeholder return op + */ + replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); + if (!replacement_op) { + return_VOID; + } + break; + + case AML_CLASS_NAMED_OBJECT: + + /* + * These opcodes contain Term_arg operands. The current + * op must be replaced by a placeholder return op */ - if ((op->parent->opcode == AML_REGION_OP) || - (op->parent->opcode == AML_CREATE_FIELD_OP) || - (op->parent->opcode == AML_CREATE_BIT_FIELD_OP) || - (op->parent->opcode == AML_CREATE_BYTE_FIELD_OP) || - (op->parent->opcode == AML_CREATE_WORD_FIELD_OP) || - (op->parent->opcode == AML_CREATE_DWORD_FIELD_OP) || - (op->parent->opcode == AML_CREATE_QWORD_FIELD_OP)) { + if ((op->common.parent->common.aml_opcode == AML_REGION_OP) || + (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) || + (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || + (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); if (!replacement_op) { - return_VALUE (FALSE); + return_VOID; } } + if ((op->common.parent->common.aml_opcode == AML_NAME_OP) && + (walk_state->descending_callback != acpi_ds_exec_begin_op)) { + if ((op->common.aml_opcode == AML_BUFFER_OP) || + (op->common.aml_opcode == AML_PACKAGE_OP) || + (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) { + replacement_op = acpi_ps_alloc_op (op->common.aml_opcode); + if (!replacement_op) { + return_VOID; + } + + replacement_op->named.data = op->named.data; + replacement_op->named.length = op->named.length; + } + } break; default: replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); if (!replacement_op) { - return_VALUE (FALSE); + return_VOID; } } /* We must unlink this op from the parent tree */ - prev = op->parent->value.arg; + prev = op->common.parent->common.value.arg; if (prev == op) { /* This op is the first in the list */ if (replacement_op) { - replacement_op->parent = op->parent; - replacement_op->value.arg = NULL; - op->parent->value.arg = replacement_op; - replacement_op->next = op->next; + replacement_op->common.parent = op->common.parent; + replacement_op->common.value.arg = NULL; + replacement_op->common.node = op->common.node; + op->common.parent->common.value.arg = replacement_op; + replacement_op->common.next = op->common.next; } else { - op->parent->value.arg = op->next; + op->common.parent->common.value.arg = op->common.next; } } @@ -277,37 +289,37 @@ else while (prev) { /* Traverse all siblings in the parent's argument list */ - next = prev->next; + next = prev->common.next; if (next == op) { if (replacement_op) { - replacement_op->parent = op->parent; - replacement_op->value.arg = NULL; - prev->next = replacement_op; - replacement_op->next = op->next; + replacement_op->common.parent = op->common.parent; + replacement_op->common.value.arg = NULL; + replacement_op->common.node = op->common.node; + prev->common.next = replacement_op; + replacement_op->common.next = op->common.next; next = NULL; } else { - prev->next = op->next; + prev->common.next = op->common.next; next = NULL; } } prev = next; } - } /* Now we can actually delete the subtree rooted at op */ acpi_ps_delete_parse_tree (op); - return_VALUE (TRUE); + return_VOID; } - return_VALUE (FALSE); + return_VOID; #else - return (FALSE); + return; #endif } @@ -318,13 +330,14 @@ * * PARAMETERS: Parser_state - Current parser state object * - * RETURN: + * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Update the parser state based upon the return exception from + * the parser callback. * ******************************************************************************/ -static acpi_status +acpi_status acpi_ps_next_parse_state ( acpi_walk_state *walk_state, acpi_parse_object *op, @@ -332,11 +345,9 @@ { acpi_parse_state *parser_state = &walk_state->parser_state; acpi_status status = AE_CTRL_PENDING; - u8 *start; - u32 package_length; - FUNCTION_TRACE_PTR ("Ps_next_parse_state", op); + ACPI_FUNCTION_TRACE_PTR ("Ps_next_parse_state", op); switch (callback_status) { @@ -351,32 +362,33 @@ break; - case AE_CTRL_PENDING: + case AE_CTRL_BREAK: - /* - * Predicate of a WHILE was true and the loop just completed an - * execution. Go back to the start of the loop and reevaluate the - * predicate. - */ + parser_state->aml = walk_state->aml_last_while; + walk_state->control_state->common.value = FALSE; + status = AE_CTRL_BREAK; + break; + + case AE_CTRL_CONTINUE: - /* TBD: How to handle a break within a while. */ - /* This code attempts it */ + + parser_state->aml = walk_state->aml_last_while; + status = AE_CTRL_CONTINUE; + break; + + case AE_CTRL_PENDING: parser_state->aml = walk_state->aml_last_while; break; case AE_CTRL_TRUE: + /* * Predicate of an IF was true, and we are at the matching ELSE. * Just close out this package - * - * Note: Parser_state->Aml is modified by the package length procedure - * TBD: [Investigate] perhaps it shouldn't, too much trouble */ - start = parser_state->aml; - package_length = acpi_ps_get_next_package_length (parser_state); - parser_state->aml = start + package_length; + parser_state->aml = acpi_ps_get_next_package_end (parser_state); break; @@ -406,7 +418,7 @@ status = AE_CTRL_TRANSFER; walk_state->prev_op = op; walk_state->method_call_op = op; - walk_state->method_call_node = (op->value.arg)->node; + walk_state->method_call_node = (op->common.value.arg)->common.node; /* Will return value (if any) be used by the caller? */ @@ -448,17 +460,21 @@ acpi_parse_object *arg = NULL; acpi_parse_object pre_op; acpi_parse_state *parser_state; - u8 *aml_op_start; + u8 *aml_op_start = NULL; - FUNCTION_TRACE_PTR ("Ps_parse_loop", walk_state); + ACPI_FUNCTION_TRACE_PTR ("Ps_parse_loop", walk_state); + + if (walk_state->descending_callback == NULL) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } parser_state = &walk_state->parser_state; walk_state->arg_types = 0; #ifndef PARSER_ONLY - if (walk_state->walk_type & WALK_METHOD_RESTART) { + if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { /* We are restarting a preempted control method */ if (acpi_ps_has_completed_scope (parser_state)) { @@ -467,18 +483,17 @@ * was just completed */ if ((parser_state->scope->parse_scope.op) && - ((parser_state->scope->parse_scope.op->opcode == AML_IF_OP) || - (parser_state->scope->parse_scope.op->opcode == AML_WHILE_OP)) && + ((parser_state->scope->parse_scope.op->common.aml_opcode == AML_IF_OP) || + (parser_state->scope->parse_scope.op->common.aml_opcode == AML_WHILE_OP)) && (walk_state->control_state) && (walk_state->control_state->common.state == - CONTROL_PREDICATE_EXECUTING)) { - + ACPI_CONTROL_PREDICATE_EXECUTING)) { /* * A predicate was just completed, get the value of the * predicate and branch based on that value */ walk_state->op = NULL; - status = acpi_ds_get_predicate_value (walk_state, TRUE); + status = acpi_ds_get_predicate_value (walk_state, ACPI_TO_POINTER (TRUE)); if (ACPI_FAILURE (status) && ((status & AE_CODE_MASK) != AE_CODE_CONTROL)) { if (status == AE_AML_NO_RETURN_VALUE) { @@ -498,7 +513,6 @@ acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); } - else if (walk_state->prev_op) { /* We were in the middle of an op */ @@ -512,12 +526,12 @@ * Iterative parsing loop, while there is more aml to process: */ while ((parser_state->aml < parser_state->aml_end) || (op)) { + aml_op_start = parser_state->aml; if (!op) { /* Get the next opcode from the AML stream */ - aml_op_start = parser_state->aml; - walk_state->aml_offset = parser_state->aml - parser_state->aml_start; - walk_state->opcode = acpi_ps_peek_opcode (parser_state); + walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); + walk_state->opcode = acpi_ps_peek_opcode (parser_state); /* * First cut to determine what we have found: @@ -542,10 +556,10 @@ /* The opcode is unrecognized. Just skip unknown opcodes */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Found unknown opcode %X at AML offset %X, ignoring\n", - walk_state->opcode, walk_state->aml_offset)); + "Found unknown opcode %X at AML address %p offset %X, ignoring\n", + walk_state->opcode, parser_state->aml, walk_state->aml_offset)); - DUMP_BUFFER (parser_state->aml, 128); + ACPI_DUMP_BUFFER (parser_state->aml, 128); /* Assume one-byte bad opcode */ @@ -559,15 +573,13 @@ parser_state->aml += acpi_ps_get_opcode_size (walk_state->opcode); walk_state->arg_types = walk_state->op_info->parse_args; break; - } - /* Create Op structure and append to parent's argument list */ if (walk_state->op_info->flags & AML_NAMED) { - pre_op.value.arg = NULL; - pre_op.opcode = walk_state->opcode; + pre_op.common.value.arg = NULL; + pre_op.common.aml_opcode = walk_state->opcode; while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) != ARGP_NAME) { arg = acpi_ps_get_next_arg (parser_state, @@ -577,47 +589,41 @@ INCREMENT_ARG_LIST (walk_state->arg_types); } - /* We know that this arg is a name, move to next arg */ INCREMENT_ARG_LIST (walk_state->arg_types); - if (walk_state->descending_callback != NULL) { - /* - * Find the object. This will either insert the object into - * the namespace or simply look it up - */ - walk_state->op = NULL; - - status = walk_state->descending_callback (walk_state, &op); + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + walk_state->op = NULL; - /* TBD: check status here? */ + status = walk_state->descending_callback (walk_state, &op); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "During name lookup/catalog, %s\n", + acpi_format_exception (status))); + goto close_this_op; + } - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "During name lookup/catalog, %s\n", - acpi_format_exception (status))); - goto close_this_op; - } + if (op == NULL) { + continue; + } - if (op == NULL) { - continue; - } - status = acpi_ps_next_parse_state (walk_state, op, status); - if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; - } + status = acpi_ps_next_parse_state (walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; + goto close_this_op; + } - if (ACPI_FAILURE (status)) { - goto close_this_op; - } + if (ACPI_FAILURE (status)) { + goto close_this_op; } - acpi_ps_append_arg (op, pre_op.value.arg); + acpi_ps_append_arg (op, pre_op.common.value.arg); acpi_gbl_depth++; - - if (op->opcode == AML_REGION_OP) { + if (op->common.aml_opcode == AML_REGION_OP) { /* * Defer final parsing of an Operation_region body, * because we don't have enough info in the first pass @@ -630,12 +636,10 @@ * * (Length is unknown until parse of the body complete) */ - ((acpi_parse2_object * ) op)->data = aml_op_start; - ((acpi_parse2_object * ) op)->length = 0; + op->named.data = aml_op_start; + op->named.length = 0; } } - - else { /* Not a named opcode, just allocate Op and append to parent */ @@ -645,14 +649,13 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - if (walk_state->op_info->flags & AML_CREATE) { /* * Backup to beginning of Create_xXXfield declaration * Body_length is unknown until we parse the body */ - ((acpi_parse2_object * ) op)->data = aml_op_start; - ((acpi_parse2_object * ) op)->length = 0; + op->named.data = aml_op_start; + op->named.length = 0; } acpi_ps_append_arg (acpi_ps_get_parent_scope (parser_state), op); @@ -662,7 +665,7 @@ * Find the object. This will either insert the object into * the namespace or simply look it up */ - walk_state->op = op; + walk_state->op = op; status = walk_state->descending_callback (walk_state, &op); status = acpi_ps_next_parse_state (walk_state, op, status); @@ -677,12 +680,13 @@ } } - op->aml_offset = walk_state->aml_offset; + op->common.aml_offset = walk_state->aml_offset; if (walk_state->op_info) { ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, - "Op=%p Opcode=%4.4X Aml %p Oft=%5.5X\n", - op, op->opcode, parser_state->aml, op->aml_offset)); + "Opcode %4.4hX [%s] Op %p Aml %p Aml_offset %5.5X\n", + op->common.aml_opcode, walk_state->op_info->name, + op, parser_state->aml, op->common.aml_offset)); } } @@ -691,18 +695,17 @@ walk_state->arg_count = 0; - if (walk_state->arg_types) /* Are there any arguments that must be processed? */ { - /* get arguments */ + /* Get arguments */ - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ case AML_WORD_OP: /* AML_WORDDATA_ARG */ case AML_DWORD_OP: /* AML_DWORDATA_ARG */ case AML_QWORD_OP: /* AML_QWORDATA_ARG */ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ - /* fill in constant or string argument directly */ + /* Fill in constant or string argument directly */ acpi_ps_get_next_simple_arg (parser_state, GET_CURRENT_ARG_TYPE (walk_state->arg_types), op); @@ -720,197 +723,251 @@ /* Op is not a constant or string, append each argument */ while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && !walk_state->arg_count) { - walk_state->aml_offset = parser_state->aml - parser_state->aml_start; + walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml, + parser_state->aml_start); arg = acpi_ps_get_next_arg (parser_state, GET_CURRENT_ARG_TYPE (walk_state->arg_types), &walk_state->arg_count); if (arg) { - arg->aml_offset = walk_state->aml_offset; + arg->common.aml_offset = walk_state->aml_offset; acpi_ps_append_arg (op, arg); } INCREMENT_ARG_LIST (walk_state->arg_types); } + switch (op->common.aml_opcode) { + case AML_METHOD_OP: - /* For a method, save the length and address of the body */ + /* For a method, save the length and address of the body */ - if (op->opcode == AML_METHOD_OP) { /* * Skip parsing of control method or opregion body, * because we don't have enough info in the first pass * to parse them correctly. */ - ((acpi_parse2_object * ) op)->data = parser_state->aml; - ((acpi_parse2_object * ) op)->length = (u32) (parser_state->pkg_end - - parser_state->aml); - + op->named.data = parser_state->aml; + op->named.length = (u32) (parser_state->pkg_end - parser_state->aml); /* * Skip body of method. For Op_regions, we must continue * parsing because the opregion is not a standalone * package (We don't know where the end is). */ parser_state->aml = parser_state->pkg_end; - walk_state->arg_count = 0; - } + walk_state->arg_count = 0; + break; + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + if ((op->common.parent) && + (op->common.parent->common.aml_opcode == AML_NAME_OP) && + (walk_state->descending_callback != acpi_ds_exec_begin_op)) { + /* + * Skip parsing of + * because we don't have enough info in the first pass + * to parse them correctly. + */ + op->named.data = aml_op_start; + op->named.length = (u32) (parser_state->pkg_end - aml_op_start); + /* + * Skip body + */ + parser_state->aml = parser_state->pkg_end; + walk_state->arg_count = 0; + } + break; + case AML_WHILE_OP: + + if (walk_state->control_state) { + walk_state->control_state->control.package_end = parser_state->pkg_end; + } + break; + + default: + /* No action for all other opcodes */ + break; + } break; } } + /* Check for arguments that need to be processed */ - /* - * Zero Arg_count means that all arguments for this op have been processed - */ - if (!walk_state->arg_count) { - /* completed Op, prepare for next */ + if (walk_state->arg_count) { + /* There are arguments (complex ones), push Op and prepare for argument */ - walk_state->op_info = acpi_ps_get_opcode_info (op->opcode); - if (walk_state->op_info->flags & AML_NAMED) { - if (acpi_gbl_depth) { - acpi_gbl_depth--; - } + status = acpi_ps_push_scope (parser_state, op, walk_state->arg_types, walk_state->arg_count); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + op = NULL; + continue; + } - if (op->opcode == AML_REGION_OP) { - /* - * Skip parsing of control method or opregion body, - * because we don't have enough info in the first pass - * to parse them correctly. - * - * Completed parsing an Op_region declaration, we now - * know the length. - */ - ((acpi_parse2_object * ) op)->length = (u32) (parser_state->aml - - ((acpi_parse2_object * ) op)->data); - } + /* All arguments have been processed -- Op is complete, prepare for next */ + + walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); + if (walk_state->op_info->flags & AML_NAMED) { + if (acpi_gbl_depth) { + acpi_gbl_depth--; } - if (walk_state->op_info->flags & AML_CREATE) { + if (op->common.aml_opcode == AML_REGION_OP) { /* - * Backup to beginning of Create_xXXfield declaration (1 for - * Opcode) + * Skip parsing of control method or opregion body, + * because we don't have enough info in the first pass + * to parse them correctly. * - * Body_length is unknown until we parse the body + * Completed parsing an Op_region declaration, we now + * know the length. */ - ((acpi_parse2_object * ) op)->length = (u32) (parser_state->aml - - ((acpi_parse2_object * ) op)->data); + op->named.length = (u32) (parser_state->aml - op->named.data); } + } - /* This op complete, notify the dispatcher */ + if (walk_state->op_info->flags & AML_CREATE) { + /* + * Backup to beginning of Create_xXXfield declaration (1 for + * Opcode) + * + * Body_length is unknown until we parse the body + */ + op->named.length = (u32) (parser_state->aml - op->named.data); + } - if (walk_state->ascending_callback != NULL) { - walk_state->op = op; - walk_state->opcode = op->opcode; + /* This op complete, notify the dispatcher */ - status = walk_state->ascending_callback (walk_state); - status = acpi_ps_next_parse_state (walk_state, op, status); - if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; - } + if (walk_state->ascending_callback != NULL) { + walk_state->op = op; + walk_state->opcode = op->common.aml_opcode; + + status = walk_state->ascending_callback (walk_state); + status = acpi_ps_next_parse_state (walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; + goto close_this_op; } + } close_this_op: + /* + * Finished one argument of the containing scope + */ + parser_state->scope->parse_scope.arg_count--; + + /* Close this Op (will result in parse subtree deletion) */ + + acpi_ps_complete_this_op (walk_state, op); + op = NULL; + + switch (status) { + case AE_OK: + break; + + + case AE_CTRL_TRANSFER: /* - * Finished one argument of the containing scope + * We are about to transfer to a called method. */ - parser_state->scope->parse_scope.arg_count--; + walk_state->prev_op = op; + walk_state->prev_arg_types = walk_state->arg_types; + return_ACPI_STATUS (status); - /* Close this Op (may result in parse subtree deletion) */ - if (acpi_ps_complete_this_op (walk_state, op)) { - op = NULL; - } + case AE_CTRL_END: + acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); - switch (status) { - case AE_OK: - break; + walk_state->op = op; + walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); + walk_state->opcode = op->common.aml_opcode; + status = walk_state->ascending_callback (walk_state); + status = acpi_ps_next_parse_state (walk_state, op, status); - case AE_CTRL_TRANSFER: + acpi_ps_complete_this_op (walk_state, op); + op = NULL; + status = AE_OK; + break; - /* - * We are about to transfer to a called method. - */ - walk_state->prev_op = op; - walk_state->prev_arg_types = walk_state->arg_types; - return_ACPI_STATUS (status); - break; + case AE_CTRL_BREAK: + case AE_CTRL_CONTINUE: - case AE_CTRL_END: + /* Pop off scopes until we find the While */ + while (!op || (op->common.aml_opcode != AML_WHILE_OP)) { acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + } - walk_state->op = op; - walk_state->op_info = acpi_ps_get_opcode_info (op->opcode); - walk_state->opcode = op->opcode; + /* Close this iteration of the While loop */ - status = walk_state->ascending_callback (walk_state); - status = acpi_ps_next_parse_state (walk_state, op, status); + walk_state->op = op; + walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); + walk_state->opcode = op->common.aml_opcode; - acpi_ps_complete_this_op (walk_state, op); - op = NULL; - status = AE_OK; - break; + status = walk_state->ascending_callback (walk_state); + status = acpi_ps_next_parse_state (walk_state, op, status); + acpi_ps_complete_this_op (walk_state, op); + op = NULL; - case AE_CTRL_TERMINATE: + status = AE_OK; + break; - status = AE_OK; - /* Clean up */ - do { - if (op) { - acpi_ps_complete_this_op (walk_state, op); - } + case AE_CTRL_TERMINATE: - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); - } while (op); + status = AE_OK; - return_ACPI_STATUS (status); - break; + /* Clean up */ + do { + if (op) { + acpi_ps_complete_this_op (walk_state, op); + } + acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + } while (op); - default: /* All other non-AE_OK status */ + return_ACPI_STATUS (status); - if (op == NULL) { - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); - } - walk_state->prev_op = op; - walk_state->prev_arg_types = walk_state->arg_types; - /* - * TEMP: - */ + default: /* All other non-AE_OK status */ - return_ACPI_STATUS (status); - break; - } + do { + if (op) { + acpi_ps_complete_this_op (walk_state, op); + } + acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); - /* This scope complete? */ + } while (op); - if (acpi_ps_has_completed_scope (parser_state)) { - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); - } - else { - op = NULL; + /* + * TBD: Cleanup parse ops on error + */ +#if 0 + if (op == NULL) { + acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); } - +#endif + walk_state->prev_op = op; + walk_state->prev_arg_types = walk_state->arg_types; + return_ACPI_STATUS (status); } + /* This scope complete? */ - /* Arg_count is non-zero */ - + if (acpi_ps_has_completed_scope (parser_state)) { + acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); + } else { - /* complex argument, push Op and prepare for argument */ - - acpi_ps_push_scope (parser_state, op, walk_state->arg_types, walk_state->arg_count); op = NULL; } @@ -928,8 +985,8 @@ if (op) { if (walk_state->ascending_callback != NULL) { walk_state->op = op; - walk_state->op_info = acpi_ps_get_opcode_info (op->opcode); - walk_state->opcode = op->opcode; + walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); + walk_state->opcode = op->common.aml_opcode; status = walk_state->ascending_callback (walk_state); status = acpi_ps_next_parse_state (walk_state, op, status); @@ -992,30 +1049,32 @@ acpi_walk_state *walk_state) { acpi_status status; - acpi_walk_list walk_list; - acpi_walk_list *prev_walk_list = acpi_gbl_current_walk_list; + ACPI_THREAD_STATE *thread; + ACPI_THREAD_STATE *prev_walk_list = acpi_gbl_current_walk_list; acpi_walk_state *previous_walk_state; - FUNCTION_TRACE ("Ps_parse_aml"); + ACPI_FUNCTION_TRACE ("Ps_parse_aml"); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Entered with Walk_state=%p Aml=%p size=%X\n", walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size)); - /* Create and initialize a new walk list */ - - walk_list.walk_state = NULL; - walk_list.acquired_mutex_list.prev = NULL; - walk_list.acquired_mutex_list.next = NULL; + /* Create and initialize a new thread state */ - walk_state->walk_list = &walk_list; - acpi_ds_push_walk_state (walk_state, &walk_list); + thread = acpi_ut_create_thread_state (); + if (!thread) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + walk_state->thread = thread; + acpi_ds_push_walk_state (walk_state, thread); - /* TBD: [Restructure] TEMP until we pass Walk_state to the interpreter + /* + * This global allows the AML debugger to get a handle to the currently + * executing control method. */ - acpi_gbl_current_walk_list = &walk_list; + acpi_gbl_current_walk_list = thread; /* * Execute the walk loop as long as there is a valid Walk State. This @@ -1041,13 +1100,13 @@ * A method call was detected. * Transfer control to the called control method */ - status = acpi_ds_call_control_method (&walk_list, walk_state, NULL); + status = acpi_ds_call_control_method (thread, walk_state, NULL); /* * If the transfer to the new method method call worked, a new walk * state was created -- get it */ - walk_state = acpi_ds_get_current_walk_state (&walk_list); + walk_state = acpi_ds_get_current_walk_state (thread); continue; } @@ -1057,7 +1116,7 @@ /* We are done with this walk, move on to the parent if any */ - walk_state = acpi_ds_pop_walk_state (&walk_list); + walk_state = acpi_ds_pop_walk_state (thread); /* Reset the current scope to the beginning of scope stack */ @@ -1068,7 +1127,13 @@ * there's lots of cleanup to do */ if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) { - acpi_ds_terminate_control_method (walk_state); + status = acpi_ds_terminate_control_method (walk_state); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not terminate control method properly\n")); + status = AE_OK; + + /* Ignore error and continue */ + } } /* Delete this walk state and all linked control states */ @@ -1082,17 +1147,27 @@ /* Check if we have restarted a preempted walk */ - walk_state = acpi_ds_get_current_walk_state (&walk_list); + walk_state = acpi_ds_get_current_walk_state (thread); if (walk_state) { if (ACPI_SUCCESS (status)) { - /* There is another walk state, restart it */ - /* - * If the method returned value is not used by the parent, + * There is another walk state, restart it. + * If the method return value is not used by the parent, * The object is deleted */ - acpi_ds_restart_control_method (walk_state, previous_walk_state->return_desc); - walk_state->walk_type |= WALK_METHOD_RESTART; + status = acpi_ds_restart_control_method (walk_state, previous_walk_state->return_desc); + if (ACPI_SUCCESS (status)) { + walk_state->walk_type |= ACPI_WALK_METHOD_RESTART; + } + } + else { + /* On error, delete any return object */ + + acpi_ut_remove_reference (previous_walk_state->return_desc); + + ACPI_REPORT_ERROR (("Method execution failed, %s\n", acpi_format_exception (status))); + ACPI_DUMP_PATHNAME (walk_state->method_node, "Method pathname: ", + ACPI_LV_ERROR, _COMPONENT); } } @@ -1113,10 +1188,10 @@ acpi_ds_delete_walk_state (previous_walk_state); } - /* Normal exit */ - acpi_ex_release_all_mutexes ((acpi_operand_object *) &walk_list.acquired_mutex_list); + acpi_ex_release_all_mutexes (thread); + acpi_ut_delete_generic_state (ACPI_CAST_PTR (acpi_generic_state, thread)); acpi_gbl_current_walk_list = prev_walk_list; return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/parser/psscope.c linux-2.4.19-sgi211r3/drivers/acpi/parser/psscope.c --- linux-2.4.19/drivers/acpi/parser/psscope.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/psscope.c Fri Apr 26 11:07:18 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psscope - Parser scope stack management routines - * $Revision: 30 $ + * $Revision: 35 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include "acparser.h" #define _COMPONENT ACPI_PARSER - MODULE_NAME ("psscope") + ACPI_MODULE_NAME ("psscope") /******************************************************************************* @@ -95,7 +95,7 @@ acpi_generic_state *scope; - FUNCTION_TRACE_PTR ("Ps_init_scope", root_op); + ACPI_FUNCTION_TRACE_PTR ("Ps_init_scope", root_op); scope = acpi_ut_create_generic_state (); @@ -141,12 +141,12 @@ acpi_generic_state *scope; - FUNCTION_TRACE_PTR ("Ps_push_scope", op); + ACPI_FUNCTION_TRACE_PTR ("Ps_push_scope", op); scope = acpi_ut_create_generic_state (); if (!scope) { - return (AE_NO_MEMORY); + return_ACPI_STATUS (AE_NO_MEMORY); } @@ -170,7 +170,7 @@ else { /* single argument */ - scope->parse_scope.arg_end = ACPI_MAX_AML; + scope->parse_scope.arg_end = ACPI_TO_POINTER (ACPI_MAX_PTR); } return_ACPI_STATUS (AE_OK); @@ -203,7 +203,7 @@ acpi_generic_state *scope = parser_state->scope; - FUNCTION_TRACE ("Ps_pop_scope"); + ACPI_FUNCTION_TRACE ("Ps_pop_scope"); /* @@ -257,7 +257,7 @@ { acpi_generic_state *scope; - FUNCTION_TRACE_PTR ("Ps_cleanup_scope", parser_state); + ACPI_FUNCTION_TRACE_PTR ("Ps_cleanup_scope", parser_state); if (!parser_state) { diff -Nur linux-2.4.19/drivers/acpi/parser/pstree.c linux-2.4.19-sgi211r3/drivers/acpi/parser/pstree.c --- linux-2.4.19/drivers/acpi/parser/pstree.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/pstree.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: pstree - Parser op tree manipulation/traversal/search - * $Revision: 35 $ + * $Revision: 39 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ #include "amlcode.h" #define _COMPONENT ACPI_PARSER - MODULE_NAME ("pstree") + ACPI_MODULE_NAME ("pstree") /******************************************************************************* @@ -54,12 +54,12 @@ const acpi_opcode_info *op_info; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* Get the info structure for this opcode */ - op_info = acpi_ps_get_opcode_info (op->opcode); + op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (op_info->class == AML_CLASS_UNKNOWN) { /* Invalid opcode or ASCII character */ @@ -76,10 +76,10 @@ /* Get the requested argument object */ - arg = op->value.arg; + arg = op->common.value.arg; while (arg && argn) { argn--; - arg = arg->next; + arg = arg->common.next; } return (arg); @@ -108,7 +108,7 @@ const acpi_opcode_info *op_info; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (!op) { @@ -117,11 +117,12 @@ /* Get the info structure for this opcode */ - op_info = acpi_ps_get_opcode_info (op->opcode); + op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (op_info->class == AML_CLASS_UNKNOWN) { /* Invalid opcode */ - REPORT_ERROR (("Ps_append_arg: Invalid AML Opcode: 0x%2.2X\n", op->opcode)); + ACPI_REPORT_ERROR (("Ps_append_arg: Invalid AML Opcode: 0x%2.2X\n", + op->common.aml_opcode)); return; } @@ -136,28 +137,28 @@ /* Append the argument to the linked argument list */ - if (op->value.arg) { + if (op->common.value.arg) { /* Append to existing argument list */ - prev_arg = op->value.arg; - while (prev_arg->next) { - prev_arg = prev_arg->next; + prev_arg = op->common.value.arg; + while (prev_arg->common.next) { + prev_arg = prev_arg->common.next; } - prev_arg->next = arg; + prev_arg->common.next = arg; } else { /* No argument list, this will be the first argument */ - op->value.arg = arg; + op->common.value.arg = arg; } /* Set the parent in this arg and any args linked after it */ while (arg) { - arg->parent = op; - arg = arg->next; + arg->common.parent = op; + arg = arg->common.next; } } @@ -181,10 +182,10 @@ acpi_parse_object *child = NULL; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - switch (op->opcode) { + switch (op->common.aml_opcode) { case AML_SCOPE_OP: case AML_ELSE_OP: case AML_DEVICE_OP: @@ -219,6 +220,10 @@ child = acpi_ps_get_arg (op, 3); break; + + default: + /* All others have no children */ + break; } return (child); @@ -249,7 +254,7 @@ acpi_parse_object *arg; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (!op) { @@ -265,19 +270,19 @@ /* look for a sibling */ - next = op->next; + next = op->common.next; if (next) { return (next); } /* look for a sibling of parent */ - parent = op->parent; + parent = op->common.parent; while (parent) { arg = acpi_ps_get_arg (parent, 0); while (arg && (arg != origin) && (arg != op)) { - arg = arg->next; + arg = arg->common.next; } if (arg == origin) { @@ -286,13 +291,14 @@ return (NULL); } - if (parent->next) { + if (parent->common.next) { /* found sibling of parent */ - return (parent->next); + + return (parent->common.next); } op = parent; - parent = parent->parent; + parent = parent->common.parent; } return (next); diff -Nur linux-2.4.19/drivers/acpi/parser/psutils.c linux-2.4.19-sgi211r3/drivers/acpi/parser/psutils.c --- linux-2.4.19/drivers/acpi/parser/psutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/psutils.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psutils - Parser miscellaneous utilities (Parser only) - * $Revision: 44 $ + * $Revision: 51 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,14 +29,7 @@ #include "amlcode.h" #define _COMPONENT ACPI_PARSER - MODULE_NAME ("psutils") - - -#define PARSEOP_GENERIC 0x01 -#define PARSEOP_NAMED 0x02 -#define PARSEOP_DEFERRED 0x04 -#define PARSEOP_BYTELIST 0x08 -#define PARSEOP_IN_CACHE 0x80 + ACPI_MODULE_NAME ("psutils") /******************************************************************************* @@ -58,19 +51,14 @@ acpi_parse_object *op, u16 opcode) { - const acpi_opcode_info *aml_op; - + ACPI_FUNCTION_ENTRY (); - FUNCTION_ENTRY (); + op->common.data_type = ACPI_DESC_TYPE_PARSER; + op->common.aml_opcode = opcode; - op->data_type = ACPI_DESC_TYPE_PARSER; - op->opcode = opcode; - - aml_op = acpi_ps_get_opcode_info (opcode); - - DEBUG_ONLY_MEMBERS (STRNCPY (op->op_name, aml_op->name, - sizeof (op->op_name))); + ACPI_DEBUG_ONLY_MEMBERS (ACPI_STRNCPY (op->common.aml_op_name, + (acpi_ps_get_opcode_info (opcode))->name, sizeof (op->common.aml_op_name))); } @@ -98,7 +86,7 @@ const acpi_opcode_info *op_info; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); op_info = acpi_ps_get_opcode_info (opcode); @@ -106,33 +94,28 @@ /* Allocate the minimum required size object */ if (op_info->flags & AML_DEFER) { - size = sizeof (acpi_parse2_object); - flags = PARSEOP_DEFERRED; + size = sizeof (ACPI_PARSE_OBJ_NAMED); + flags = ACPI_PARSEOP_DEFERRED; } - else if (op_info->flags & AML_NAMED) { - size = sizeof (acpi_parse2_object); - flags = PARSEOP_NAMED; + size = sizeof (ACPI_PARSE_OBJ_NAMED); + flags = ACPI_PARSEOP_NAMED; } - else if (opcode == AML_INT_BYTELIST_OP) { - size = sizeof (acpi_parse2_object); - flags = PARSEOP_BYTELIST; + size = sizeof (ACPI_PARSE_OBJ_NAMED); + flags = ACPI_PARSEOP_BYTELIST; } - else { - size = sizeof (acpi_parse_object); - flags = PARSEOP_GENERIC; + size = sizeof (ACPI_PARSE_OBJ_COMMON); + flags = ACPI_PARSEOP_GENERIC; } - - if (size == sizeof (acpi_parse_object)) { + if (size == sizeof (ACPI_PARSE_OBJ_COMMON)) { /* * The generic op is by far the most common (16 to 1) */ op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE); } - else { op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE_EXT); } @@ -141,7 +124,7 @@ if (op) { acpi_ps_init_op (op, opcode); - op->flags = flags; + op->common.flags = flags; } return (op); @@ -165,17 +148,16 @@ acpi_ps_free_op ( acpi_parse_object *op) { - PROC_NAME ("Ps_free_op"); + ACPI_FUNCTION_NAME ("Ps_free_op"); - if (op->opcode == AML_INT_RETURN_VALUE_OP) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Free retval op: %p\n", op)); + if (op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", op)); } - if (op->flags == PARSEOP_GENERIC) { + if (op->common.flags == ACPI_PARSEOP_GENERIC) { acpi_ut_release_to_cache (ACPI_MEM_LIST_PSNODE, op); } - else { acpi_ut_release_to_cache (ACPI_MEM_LIST_PSNODE_EXT, op); } @@ -198,7 +180,7 @@ acpi_ps_delete_parse_cache ( void) { - FUNCTION_TRACE ("Ps_delete_parse_cache"); + ACPI_FUNCTION_TRACE ("Ps_delete_parse_cache"); acpi_ut_delete_generic_cache (ACPI_MEM_LIST_PSNODE); @@ -249,13 +231,13 @@ /* The "generic" object has no name associated with it */ - if (op->flags & PARSEOP_GENERIC) { + if (op->common.flags & ACPI_PARSEOP_GENERIC) { return (0); } /* Only the "Extended" parse objects have a name */ - return (((acpi_parse2_object *) op)->name); + return (op->named.name); } @@ -270,10 +252,10 @@ /* The "generic" object has no name associated with it */ - if (op->flags & PARSEOP_GENERIC) { + if (op->common.flags & ACPI_PARSEOP_GENERIC) { return; } - ((acpi_parse2_object *) op)->name = name; + op->named.name = name; } diff -Nur linux-2.4.19/drivers/acpi/parser/pswalk.c linux-2.4.19-sgi211r3/drivers/acpi/parser/pswalk.c --- linux-2.4.19/drivers/acpi/parser/pswalk.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/pswalk.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: pswalk - Parser routines to walk parsed op tree(s) - * $Revision: 58 $ + * $Revision: 67 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +25,11 @@ #include "acpi.h" -#include "amlcode.h" #include "acparser.h" #include "acdispat.h" -#include "acnamesp.h" -#include "acinterp.h" #define _COMPONENT ACPI_PARSER - MODULE_NAME ("pswalk") + ACPI_MODULE_NAME ("pswalk") /******************************************************************************* @@ -61,12 +58,12 @@ acpi_status status; - FUNCTION_TRACE_PTR ("Ps_get_next_walk_op", op); + ACPI_FUNCTION_TRACE_PTR ("Ps_get_next_walk_op", op); /* Check for a argument only if we are descending in the tree */ - if (walk_state->next_op_info != NEXT_OP_UPWARD) { + if (walk_state->next_op_info != ACPI_NEXT_OP_UPWARD) { /* Look for an argument or child of the current op */ next = acpi_ps_get_arg (op, 0); @@ -75,22 +72,21 @@ walk_state->prev_op = op; walk_state->next_op = next; - walk_state->next_op_info = NEXT_OP_DOWNWARD; + walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD; return_ACPI_STATUS (AE_OK); } - /* * No more children, this Op is complete. Save Next and Parent * in case the Op object gets deleted by the callback routine */ - next = op->next; - parent = op->parent; + next = op->common.next; + parent = op->common.parent; walk_state->op = op; - walk_state->op_info = acpi_ps_get_opcode_info (op->opcode); - walk_state->opcode = op->opcode; + walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); + walk_state->opcode = op->common.aml_opcode; status = ascending_callback (walk_state); @@ -115,7 +111,7 @@ walk_state->prev_op = op; walk_state->next_op = next; - walk_state->next_op_info = NEXT_OP_DOWNWARD; + walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD; /* Continue downward */ @@ -127,7 +123,6 @@ * the tree */ } - else { /* * We are resuming a walk, and we were (are) going upward in the tree. @@ -136,7 +131,6 @@ parent = op; } - /* * Look for a sibling of the current Op's parent * Continue moving up the tree until we find a node that has not been @@ -145,12 +139,12 @@ while (parent) { /* We are moving up the tree, therefore this parent Op is complete */ - grand_parent = parent->parent; - next = parent->next; + grand_parent = parent->common.parent; + next = parent->common.next; walk_state->op = parent; - walk_state->op_info = acpi_ps_get_opcode_info (parent->opcode); - walk_state->opcode = parent->opcode; + walk_state->op_info = acpi_ps_get_opcode_info (parent->common.aml_opcode); + walk_state->opcode = parent->common.aml_opcode; status = ascending_callback (walk_state); @@ -175,7 +169,7 @@ walk_state->prev_op = parent; walk_state->next_op = next; - walk_state->next_op_info = NEXT_OP_DOWNWARD; + walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD; return_ACPI_STATUS (status); } @@ -188,9 +182,10 @@ } - /* Got all the way to the top of the tree, we must be done! */ - /* However, the code should have terminated in the loop above */ - + /* + * Got all the way to the top of the tree, we must be done! + * However, the code should have terminated in the loop above + */ walk_state->next_op = NULL; return_ACPI_STATUS (AE_OK); @@ -212,7 +207,7 @@ * ******************************************************************************/ -static acpi_status +acpi_status acpi_ps_delete_completed_op ( acpi_walk_state *walk_state) { @@ -239,10 +234,11 @@ acpi_parse_object *subtree_root) { acpi_walk_state *walk_state; - acpi_walk_list walk_list; + ACPI_THREAD_STATE *thread; + acpi_status status; - FUNCTION_TRACE_PTR ("Ps_delete_parse_tree", subtree_root); + ACPI_FUNCTION_TRACE_PTR ("Ps_delete_parse_tree", subtree_root); if (!subtree_root) { @@ -251,11 +247,12 @@ /* Create and initialize a new walk list */ - walk_list.walk_state = NULL; - walk_list.acquired_mutex_list.prev = NULL; - walk_list.acquired_mutex_list.next = NULL; + thread = acpi_ut_create_thread_state (); + if (!thread) { + return_VOID; + } - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, &walk_list); + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, thread); if (!walk_state) { return_VOID; } @@ -264,25 +261,26 @@ walk_state->descending_callback = NULL; walk_state->ascending_callback = NULL; - walk_state->origin = subtree_root; walk_state->next_op = subtree_root; - /* Head downward in the tree */ - walk_state->next_op_info = NEXT_OP_DOWNWARD; + walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD; /* Visit all nodes in the subtree */ while (walk_state->next_op) { - acpi_ps_get_next_walk_op (walk_state, walk_state->next_op, + status = acpi_ps_get_next_walk_op (walk_state, walk_state->next_op, acpi_ps_delete_completed_op); + if (ACPI_FAILURE (status)) { + break; + } } /* We are done with this walk */ - acpi_ex_release_all_mutexes ((acpi_operand_object *) &walk_list.acquired_mutex_list); + acpi_ut_delete_generic_state (ACPI_CAST_PTR (acpi_generic_state, thread)); acpi_ds_delete_walk_state (walk_state); return_VOID; diff -Nur linux-2.4.19/drivers/acpi/parser/psxface.c linux-2.4.19-sgi211r3/drivers/acpi/parser/psxface.c --- linux-2.4.19/drivers/acpi/parser/psxface.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/parser/psxface.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: psxface - Parser external interfaces - * $Revision: 52 $ + * $Revision: 64 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ #define _COMPONENT ACPI_PARSER - MODULE_NAME ("psxface") + ACPI_MODULE_NAME ("psxface") /******************************************************************************* @@ -67,7 +67,7 @@ acpi_walk_state *walk_state; - FUNCTION_TRACE ("Psx_execute"); + ACPI_FUNCTION_TRACE ("Psx_execute"); /* Validate the Node and get the attached object */ @@ -102,7 +102,7 @@ * 1) Perform the first pass parse of the method to enter any * named objects that it creates into the namespace */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Parse **** Entry=%p obj=%p\n", method_node, obj_desc)); @@ -113,9 +113,16 @@ return_ACPI_STATUS (AE_NO_MEMORY); } + /* + * Get a new Owner_id for objects created by this method. Namespace + * objects (such as Operation Regions) can be created during the + * first pass parse. + */ + obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD); + /* Create and initialize a new walk state */ - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, + walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, NULL, NULL, NULL); if (!walk_state) { return_ACPI_STATUS (AE_NO_MEMORY); @@ -124,7 +131,7 @@ status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, NULL, NULL, 1); if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ + acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); } @@ -133,11 +140,10 @@ status = acpi_ps_parse_aml (walk_state); acpi_ps_delete_parse_tree (op); - /* * 2) Execute the method. Performs second pass parse simultaneously */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Execution **** Entry=%p obj=%p\n", method_node, obj_desc)); @@ -150,13 +156,12 @@ /* Init new op with the method name and pointer back to the NS node */ - acpi_ps_set_name (op, method_node->name); - op->node = method_node; + acpi_ps_set_name (op, method_node->name.integer); + op->common.node = method_node; /* Create and initialize a new walk state */ - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, - NULL, NULL, NULL); + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, NULL); if (!walk_state) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -164,7 +169,7 @@ status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, params, return_obj_desc, 3); if (ACPI_FAILURE (status)) { - /* TBD: delete walk state */ + acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); } @@ -178,29 +183,23 @@ /* Take away the extra reference that we gave the parameters above */ for (i = 0; params[i]; i++) { - acpi_ut_update_object_reference (params[i], REF_DECREMENT); - } - } - + /* Ignore errors, just do them all */ - if (ACPI_FAILURE (status)) { - DUMP_PATHNAME (method_node, "Ps_execute: method failed -", - ACPI_LV_ERROR, _COMPONENT); + (void) acpi_ut_update_object_reference (params[i], REF_DECREMENT); + } } - /* * If the method has returned an object, signal this to the caller with * a control exception code */ if (*return_obj_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Method returned Obj_desc=%p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned Obj_desc=%p\n", *return_obj_desc)); - DUMP_STACK_ENTRY (*return_obj_desc); + ACPI_DUMP_STACK_ENTRY (*return_obj_desc); status = AE_CTRL_RETURN_VALUE; } - return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/pci_bind.c linux-2.4.19-sgi211r3/drivers/acpi/pci_bind.c --- linux-2.4.19/drivers/acpi/pci_bind.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/pci_bind.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,309 @@ +/* + * pci_bind.c - ACPI PCI Device Binding ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_PCI_COMPONENT +ACPI_MODULE_NAME ("pci_bind") + +#define PREFIX "ACPI: " + + +struct acpi_pci_data { + acpi_pci_id id; + struct pci_bus *bus; + struct pci_dev *dev; +}; + + +void +acpi_pci_data_handler ( + acpi_handle handle, + u32 function, + void *context) +{ + ACPI_FUNCTION_TRACE("acpi_pci_data_handler"); + + /* TBD: Anything we need to do here? */ + + return_VOID; +} + + +/** + * acpi_os_get_pci_id + * ------------------ + * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) + * to resolve PCI information for ACPI-PCI devices defined in the namespace. + * This typically occurs when resolving PCI operation region information. + */ +acpi_status +acpi_os_get_pci_id ( + acpi_handle handle, + acpi_pci_id *id) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_device *device = NULL; + struct acpi_pci_data *data = NULL; + + ACPI_FUNCTION_TRACE("acpi_os_get_pci_id"); + + if (!id) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + result = acpi_bus_get_device(handle, &device); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid ACPI Bus context for device %s\n", + acpi_device_bid(device))); + return_ACPI_STATUS(AE_NOT_EXIST); + } + + status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data); + if (ACPI_FAILURE(status) || !data || !data->dev) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid ACPI-PCI context for device %s\n", + acpi_device_bid(device))); + return_ACPI_STATUS(status); + } + + *id = data->id; + + /* + id->segment = data->id.segment; + id->bus = data->id.bus; + id->device = data->id.device; + id->function = data->id.function; + */ + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Device %s has PCI address %02x:%02x:%02x.%02x\n", + acpi_device_bid(device), id->segment, id->bus, + id->device, id->function)); + + return_ACPI_STATUS(AE_OK); +} + + +int +acpi_pci_bind ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_pci_data *data = NULL; + struct acpi_pci_data *pdata = NULL; + char pathname[PATHNAME_MAX] = {0}; + acpi_buffer buffer = {PATHNAME_MAX, pathname}; + acpi_handle handle = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_bind"); + + if (!device || !device->parent) + return_VALUE(-EINVAL); + + data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); + if (!data) + return_VALUE(-ENOMEM); + memset(data, 0, sizeof(struct acpi_pci_data)); + + acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", + pathname)); + + /* + * Segment & Bus + * ------------- + * These are obtained via the parent device's ACPI-PCI context. + */ + status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, + (void**) &pdata); + if (ACPI_FAILURE(status) || !pdata || !pdata->bus) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid ACPI-PCI context for parent device %s\n", + acpi_device_bid(device->parent))); + result = -ENODEV; + goto end; + } + data->id.segment = pdata->id.segment; + data->id.bus = pdata->bus->number; + + /* + * Device & Function + * ----------------- + * These are simply obtained from the device's _ADR method. Note + * that a value of zero is valid. + */ + data->id.device = device->pnp.bus_address >> 16; + data->id.function = device->pnp.bus_address & 0xFFFF; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %02x:%02x:%02x.%02x\n", + data->id.segment, data->id.bus, data->id.device, + data->id.function)); + + /* + * TBD: Support slot devices (e.g. function=0xFFFF). + */ + + /* + * Locate PCI Device + * ----------------- + * Locate matching device in PCI namespace. If it doesn't exist + * this typically means that the device isn't currently inserted + * (e.g. docking station, port replicator, etc.). + */ + data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function)); + if (!data->dev) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Device %02x:%02x:%02x.%02x not present in PCI namespace\n", + data->id.segment, data->id.bus, + data->id.device, data->id.function)); + result = -ENODEV; + goto end; + } + if (!data->dev->bus) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n", + data->id.segment, data->id.bus, + data->id.device, data->id.function)); + result = -ENODEV; + goto end; + } + + /* + * PCI Bridge? + * ----------- + * If so, set the 'bus' field and install the 'bind' function to + * facilitate callbacks for all of its children. + */ + if (data->dev->subordinate) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Device %02x:%02x:%02x.%02x is a PCI bridge\n", + data->id.segment, data->id.bus, + data->id.device, data->id.function)); + data->bus = data->dev->subordinate; + device->ops.bind = acpi_pci_bind; + } + + /* + * Attach ACPI-PCI Context + * ----------------------- + * Thus binding the ACPI and PCI devices. + */ + status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to attach ACPI-PCI context to device %s\n", + acpi_device_bid(device))); + result = -ENODEV; + goto end; + } + + /* + * PCI Routing Table + * ----------------- + * Evaluate and parse _PRT, if exists. This code is independent of + * PCI bridges (above) to allow parsing of _PRT objects within the + * scope of non-bridge devices. Note that _PRTs within the scope of + * a PCI bridge assume the bridge's subordinate bus number. + * + * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? + */ + status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); + if (ACPI_SUCCESS(status)) { + if (data->bus) /* PCI-PCI bridge */ + acpi_pci_irq_add_prt(device->handle, data->id.segment, + data->bus->number); + else /* non-bridge PCI device */ + acpi_pci_irq_add_prt(device->handle, data->id.segment, + data->id.bus); + } + +end: + if (0 != result) + kfree(data); + + return_VALUE(result); +} + + +int +acpi_pci_bind_root ( + struct acpi_device *device, + acpi_pci_id *id, + struct pci_bus *bus) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_pci_data *data = NULL; + char pathname[PATHNAME_MAX] = {0}; + acpi_buffer buffer = {PATHNAME_MAX, pathname}; + + ACPI_FUNCTION_TRACE("acpi_pci_bind_root"); + + if (!device || !id || !bus) + return_VALUE(-EINVAL); + + data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); + if (!data) + return_VALUE(-ENOMEM); + memset(data, 0, sizeof(struct acpi_pci_data)); + + data->id = *id; + data->bus = bus; + device->ops.bind = acpi_pci_bind; + + acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " + "%02x:%02x\n", pathname, id->segment, id->bus)); + + status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to attach ACPI-PCI context to device %s\n", + pathname)); + result = -ENODEV; + goto end; + } + +end: + if (result != 0) + kfree(data); + + return_VALUE(result); +} diff -Nur linux-2.4.19/drivers/acpi/pci_irq.c linux-2.4.19-sgi211r3/drivers/acpi/pci_irq.c --- linux-2.4.19/drivers/acpi/pci_irq.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/pci_irq.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,391 @@ +/* + * pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2002 Dominik Brodowski + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_PCI_COMPONENT +ACPI_MODULE_NAME ("pci_irq") + +#define PREFIX "PCI: " + +struct acpi_prt_list acpi_prt; + +#ifdef CONFIG_X86 +extern void eisa_set_level_irq(unsigned int irq); +#endif + + +/* -------------------------------------------------------------------------- + PCI IRQ Routing Table (PRT) Support + -------------------------------------------------------------------------- */ + +static struct acpi_prt_entry * +acpi_pci_irq_find_prt_entry ( + int segment, + int bus, + int device, + int pin) +{ + struct list_head *node = NULL; + struct acpi_prt_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_find_prt_entry"); + + /* + * Parse through all PRT entries looking for a match on the specified + * PCI device's segment, bus, device, and pin (don't care about func). + * + * TBD: Acquire/release lock + */ + list_for_each(node, &acpi_prt.entries) { + entry = list_entry(node, struct acpi_prt_entry, node); + if ((segment == entry->id.segment) + && (bus == entry->id.bus) + && (device == entry->id.device) + && (pin == entry->pin)) { + return_PTR(entry); + } + } + + return_PTR(NULL); +} + + +static int +acpi_pci_irq_add_entry ( + acpi_handle handle, + int segment, + int bus, + acpi_pci_routing_table *prt) +{ + struct acpi_prt_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_add_entry"); + + if (!prt) + return_VALUE(-EINVAL); + + entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); + if (!entry) + return_VALUE(-ENOMEM); + memset(entry, 0, sizeof(struct acpi_prt_entry)); + + entry->id.segment = segment; + entry->id.bus = bus; + entry->id.device = (prt->address >> 16) & 0xFFFF; + entry->id.function = prt->address & 0xFFFF; + entry->pin = prt->pin; + + /* + * Type 1: Dynamic + * --------------- + * The 'source' field specifies the PCI interrupt link device used to + * configure the IRQ assigned to this slot|dev|pin. The 'source_index' + * indicates which resource descriptor in the resource template (of + * the link device) this interrupt is allocated from. + * + * NOTE: Don't query the Link Device for IRQ information at this time + * because Link Device enumeration may not have occurred yet + * (e.g. exists somewhere 'below' this _PRT entry in the ACPI + * namespace). + */ + if (prt->source[0]) { + acpi_get_handle(handle, prt->source, &entry->link.handle); + entry->link.index = prt->source_index; + } + /* + * Type 2: Static + * -------------- + * The 'source' field is NULL, and the 'source_index' field specifies + * the IRQ value, which is hardwired to specific interrupt inputs on + * the interrupt controller. + */ + else + entry->link.index = prt->source_index; + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, + " %02X:%02X:%02X[%c] -> %s[%d]\n", + entry->id.segment, entry->id.bus, entry->id.device, + ('A' + entry->pin), prt->source, entry->link.index)); + + /* TBD: Acquire/release lock */ + list_add_tail(&entry->node, &acpi_prt.entries); + acpi_prt.count++; + + return_VALUE(0); +} + + +int +acpi_pci_irq_add_prt ( + acpi_handle handle, + int segment, + int bus) +{ + acpi_status status = AE_OK; + char pathname[PATHNAME_MAX] = {0}; + acpi_buffer buffer = {0, NULL}; + acpi_pci_routing_table *prt = NULL; + acpi_pci_routing_table *entry = NULL; + static int first_time = 1; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_add_prt"); + + if (first_time) { + acpi_prt.count = 0; + INIT_LIST_HEAD(&acpi_prt.entries); + first_time = 0; + } + + /* + * NOTE: We're given a 'handle' to the _PRT object's parent device + * (either a PCI root bridge or PCI-PCI bridge). + */ + + buffer.length = sizeof(pathname); + buffer.pointer = pathname; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", + pathname); + + /* + * Evaluate this _PRT and add its entries to our global list (acpi_prt). + */ + + buffer.length = 0; + buffer.pointer = NULL; + status = acpi_get_irq_routing_table(handle, &buffer); + if (status != AE_BUFFER_OVERFLOW) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", + acpi_format_exception(status))); + return_VALUE(-ENODEV); + } + + prt = kmalloc(buffer.length, GFP_KERNEL); + if (!prt) + return_VALUE(-ENOMEM); + memset(prt, 0, buffer.length); + buffer.pointer = prt; + + status = acpi_get_irq_routing_table(handle, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", + acpi_format_exception(status))); + kfree(buffer.pointer); + return_VALUE(-ENODEV); + } + + entry = prt; + + while (entry && (entry->length > 0)) { + acpi_pci_irq_add_entry(handle, segment, bus, entry); + entry = (acpi_pci_routing_table *) + ((unsigned long) entry + entry->length); + } + + kfree(prt); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + PCI Interrupt Routing Support + -------------------------------------------------------------------------- */ + +static int +acpi_pci_irq_lookup ( + int segment, + int bus, + int device, + int pin) +{ + struct acpi_prt_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup"); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Searching for PRT entry for %02x:%02x:%02x[%c]\n", + segment, bus, device, ('A' + pin))); + + entry = acpi_pci_irq_find_prt_entry(segment, bus, device, pin); + if (!entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n")); + return_VALUE(0); + } + + if (!entry->irq && entry->link.handle) + entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index); + else if (!entry->irq) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid static routing entry (IRQ 0)\n")); + return_VALUE(0); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", entry->irq)); + + return_VALUE(entry->irq); +} + + +static int +acpi_pci_irq_derive ( + struct pci_dev *dev, + int pin) +{ + struct pci_dev *bridge = dev; + int irq = 0; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_derive"); + + if (!dev) + return_VALUE(-EINVAL); + + /* + * Attempt to derive an IRQ for this device from a parent bridge's + * PCI interrupt routing entry (a.k.a. the "bridge swizzle"). + */ + while (!irq && (bridge = bridge->bus->self)) { + pin = (pin + PCI_SLOT(bridge->devfn)) % 4; + irq = acpi_pci_irq_lookup(0, bridge->bus->number, PCI_SLOT(bridge->devfn), pin); + } + + if (!irq) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to derive IRQ for device %s\n", dev->slot_name)); + return_VALUE(0); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derived IRQ %d\n", irq)); + + return_VALUE(irq); +} + + +int +acpi_pci_irq_enable ( + struct pci_dev *dev) +{ + int irq = 0; + u8 pin = 0; + static u16 irq_mask = 0; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_enable"); + + if (!dev) + return_VALUE(-EINVAL); + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (!pin) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No interrupt pin configured for device %s\n", dev->slot_name)); + return_VALUE(0); + } + pin--; + + if (!dev->bus) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) 'bus' field\n")); + return_VALUE(-ENODEV); + } + + /* + * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT + * values override any BIOS-assinged IRQs set during boot. + */ + irq = acpi_pci_irq_lookup(0, dev->bus->number, PCI_SLOT(dev->devfn), pin); + if (irq) + dev->irq = irq; + + /* + * If no PRT entry was found and the device wasn't assigned an IRQ + * during boot we'll try to derive an IRQ from the device's parent + * bridge. + */ + if (!dev->irq && dev->bus->self) { + irq = acpi_pci_irq_derive(dev, pin); + if (irq) + dev->irq = irq; + } + + + if (!dev->irq) { + printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s\n", ('A' + pin), dev->slot_name); + return_VALUE(0); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ %d\n", dev->slot_name, dev->irq)); + + /* + * Make sure all (legacy) PCI IRQs are set as level-triggered. + */ +#ifdef CONFIG_X86 + if ((dev->irq < 16) && !((1 << dev->irq) & irq_mask)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Setting IRQ %d as level-triggered\n", dev->irq)); + irq_mask |= (1 << dev->irq); + eisa_set_level_irq(dev->irq); + } +#endif + + return_VALUE(dev->irq); +} + + +int __init +acpi_pci_irq_init (void) +{ + struct pci_dev *dev = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_init"); + + if (!acpi_prt.count) { + printk(KERN_WARNING PREFIX "ACPI tables contain no PCI IRQ " + "routing entries\n"); + return_VALUE(-ENODEV); + } + + /* Make sure all link devices have a valid IRQ. */ + acpi_pci_link_check(); + +#ifdef CONFIG_X86_IO_APIC + /* Program IOAPICs using data from PRT entries. */ + if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) + mp_parse_prt(); +#endif + + pci_for_each_dev(dev) + acpi_pci_irq_enable(dev); + + return_VALUE(acpi_prt.count); +} diff -Nur linux-2.4.19/drivers/acpi/pci_link.c linux-2.4.19-sgi211r3/drivers/acpi/pci_link.c --- linux-2.4.19/drivers/acpi/pci_link.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/pci_link.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,581 @@ +/* + * pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2002 Dominik Brodowski + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * TBD: + * 1. Support more than one IRQ resource entry per link device (index). + * 2. Implement start/stop mechanism and use ACPI Bus Driver facilities + * for IRQ management (e.g. start()->_SRS). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_PCI_COMPONENT +ACPI_MODULE_NAME ("pci_link") + +#define PREFIX "ACPI: " + + +#define ACPI_PCI_LINK_MAX_POSSIBLE 16 + +static int acpi_pci_link_add (struct acpi_device *device); +static int acpi_pci_link_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_pci_link_driver = { + name: ACPI_PCI_LINK_DRIVER_NAME, + class: ACPI_PCI_LINK_CLASS, + ids: ACPI_PCI_LINK_HID, + ops: { + add: acpi_pci_link_add, + remove: acpi_pci_link_remove, + }, +}; + +struct acpi_pci_link_irq { + u8 active; /* Current IRQ */ + u8 possible_count; + u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; +}; + +struct acpi_pci_link { + struct list_head node; + struct acpi_device *device; + acpi_handle handle; + struct acpi_pci_link_irq irq; +}; + +static struct { + int count; + struct list_head entries; +} acpi_link; + + +/* -------------------------------------------------------------------------- + PCI Link Device Management + -------------------------------------------------------------------------- */ + +static int +acpi_pci_link_get_possible ( + struct acpi_pci_link *link) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_resource *resource = NULL; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible"); + + if (!link) + return_VALUE(-EINVAL); + + status = acpi_get_possible_resources(link->handle, &buffer); + if (ACPI_FAILURE(status) || !buffer.pointer) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n")); + result = -ENODEV; + goto end; + } + + resource = (acpi_resource *) buffer.pointer; + + switch (resource->id) { + case ACPI_RSTYPE_IRQ: + { + acpi_resource_irq *p = &resource->data.irq; + if (!p || !p->number_of_interrupts) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n")); + result = -ENODEV; + goto end; + } + for (i = 0; (inumber_of_interrupts && iinterrupts[i]) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i])); + continue; + } + link->irq.possible[i] = p->interrupts[i]; + link->irq.possible_count++; + } + break; + } + case ACPI_RSTYPE_EXT_IRQ: + { + acpi_resource_ext_irq *p = &resource->data.extended_irq; + if (!p || !p->number_of_interrupts) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Blank IRQ resource\n")); + result = -ENODEV; + goto end; + } + for (i = 0; (inumber_of_interrupts && iinterrupts[i]) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i])); + continue; + } + link->irq.possible[i] = p->interrupts[i]; + link->irq.possible_count++; + } + break; + } + default: + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Resource is not an IRQ entry\n")); + result = -ENODEV; + goto end; + break; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Found %d possible IRQs\n", link->irq.possible_count)); + +end: + kfree(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_pci_link_get_current ( + struct acpi_pci_link *link) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_resource *resource = NULL; + int irq = 0; + + ACPI_FUNCTION_TRACE("acpi_pci_link_get_current"); + + if (!link || !link->handle) + return_VALUE(-EINVAL); + + link->irq.active = 0; + + /* Make sure the link is enabled (no use querying if it isn't). */ + result = acpi_bus_get_status(link->device); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); + goto end; + } + if (!link->device->status.enabled) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); + return_VALUE(0); + } + + /* + * Query and parse _CRS to get the current IRQ assignment. + */ + + status = acpi_get_current_resources(link->handle, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n")); + result = -ENODEV; + goto end; + } + resource = (acpi_resource *) buffer.pointer; + + switch (resource->id) { + case ACPI_RSTYPE_IRQ: + { + acpi_resource_irq *p = &resource->data.irq; + if (!p || !p->number_of_interrupts) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Blank IRQ resource\n")); + result = -ENODEV; + goto end; + } + irq = p->interrupts[0]; + break; + } + case ACPI_RSTYPE_EXT_IRQ: + { + acpi_resource_ext_irq *p = &resource->data.extended_irq; + if (!p || !p->number_of_interrupts) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Blank IRQ resource\n")); + result = -ENODEV; + goto end; + } + irq = p->interrupts[0]; + break; + } + default: + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Resource isn't an IRQ\n")); + result = -ENODEV; + goto end; + } + + if (!irq) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid use of IRQ 0\n")); + result = -ENODEV; + goto end; + } + + /* + * Note that we don't validate that the current IRQ (_CRS) exists + * within the possible IRQs (_PRS): we blindly assume that whatever + * IRQ a boot-enabled Link device is set to is the correct one. + * (Required to support systems such as the Toshiba 5005-S504.) + */ + + link->irq.active = irq; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); + +end: + kfree(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_pci_link_set ( + struct acpi_pci_link *link, + int irq) +{ + int result = 0; + acpi_status status = AE_OK; + struct { + acpi_resource res; + acpi_resource end; + } resource; + acpi_buffer buffer = {sizeof(resource)+1, &resource}; + int i = 0; + int valid = 0; + + ACPI_FUNCTION_TRACE("acpi_pci_link_set"); + + if (!link || !irq) + return_VALUE(-EINVAL); + + /* See if we're already at the target IRQ. */ + if (irq == link->irq.active) + return_VALUE(0); + + /* Make sure the target IRQ in the list of possible IRQs. */ + for (i=0; iirq.possible_count; i++) { + if (irq == link->irq.possible[i]) + valid = 1; + } + if (!valid) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Target IRQ %d invalid\n", irq)); + return_VALUE(-EINVAL); + } + + memset(&resource, 0, sizeof(resource)); + + /* NOTE: PCI interrupts are always level / active_low / shared. */ + resource.res.id = ACPI_RSTYPE_IRQ; + resource.res.length = sizeof(acpi_resource); + resource.res.data.irq.edge_level = ACPI_LEVEL_SENSITIVE; + resource.res.data.irq.active_high_low = ACPI_ACTIVE_LOW; + resource.res.data.irq.shared_exclusive = ACPI_SHARED; + resource.res.data.irq.number_of_interrupts = 1; + resource.res.data.irq.interrupts[0] = irq; + resource.end.id = ACPI_RSTYPE_END_TAG; + + status = acpi_set_current_resources(link->handle, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n")); + return_VALUE(-ENODEV); + } + + /* Make sure the device is enabled. */ + result = acpi_bus_get_status(link->device); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); + return_VALUE(result); + } + if (!link->device->status.enabled) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n")); + return_VALUE(-ENODEV); + } + + /* Make sure the active IRQ is the one we requested. */ + result = acpi_pci_link_get_current(link); + if (0 != result) { + return_VALUE(result); + } + if (link->irq.active != irq) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Attempt to enable at IRQ %d resulted in IRQ %d\n", + irq, link->irq.active)); + link->irq.active = 0; + return_VALUE(-ENODEV); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + PCI Link IRQ Management + -------------------------------------------------------------------------- */ + +#define ACPI_MAX_IRQS 256 +#define ACPI_MAX_ISA_IRQ 16 + +/* + * IRQ penalties are used to promote PCI IRQ balancing. We set each ISA- + * possible IRQ (0-15) with a default penalty relative to its feasibility + * for PCI's use: + * + * Never use: 0, 1, 2 (timer, keyboard, and cascade) + * Avoid using: 13, 14, and 15 (FP error and IDE) + * Penalize: 3, 4, 6, 7, 12 (known ISA uses) + * + * Thus we're left with IRQs 5, 9, 10, 11, and everything above 15 (IO[S]APIC) + * as 'best bets' for PCI use. + */ + +static int acpi_irq_penalty[ACPI_MAX_IRQS] = { + 1000000, 1000000, 1000000, 10000, + 10000, 0, 10000, 10000, + 10000, 0, 0, 0, + 10000, 100000, 100000, 100000, +}; + + +int +acpi_pci_link_check (void) +{ + struct list_head *node = NULL; + struct acpi_pci_link *link = NULL; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_pci_link_check"); + + /* + * Pass #1: Update penalties to facilitate IRQ balancing. + */ + list_for_each(node, &acpi_link.entries) { + + link = list_entry(node, struct acpi_pci_link, node); + if (!link) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); + continue; + } + + if (link->irq.active) + acpi_irq_penalty[link->irq.active] += 100; + else { + int penalty = 100 / link->irq.possible_count; + for (i=0; iirq.possible_count; i++) { + if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) + acpi_irq_penalty[link->irq.possible[i]] += penalty; + } + } + } + + /* + * Pass #2: Enable boot-disabled Links at 'best' IRQ. + */ + list_for_each(node, &acpi_link.entries) { + int irq = 0; + int i = 0; + + link = list_entry(node, struct acpi_pci_link, node); + if (!link) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); + continue; + } + + if (link->irq.active) + continue; + + irq = link->irq.possible[0]; + + /* + * Select the best IRQ. This is done in reverse to promote + * the use of IRQs 9, 10, 11, and >15. + */ + for (i=(link->irq.possible_count-1); i>0; i--) { + if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]]) + irq = link->irq.possible[i]; + } + + /* Enable the link device at this IRQ. */ + acpi_pci_link_set(link, irq); + + acpi_irq_penalty[link->irq.active] += 100; + + printk(PREFIX "%s [%s] enabled at IRQ %d\n", + acpi_device_name(link->device), + acpi_device_bid(link->device), irq); + } + + return_VALUE(0); +} + + +int +acpi_pci_link_get_irq ( + acpi_handle handle, + int index) +{ + int result = 0; + struct acpi_device *device = NULL; + struct acpi_pci_link *link = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_link_get_irq"); + + result = acpi_bus_get_device(handle, &device); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n")); + return_VALUE(0); + } + + link = (struct acpi_pci_link *) acpi_driver_data(device); + if (!link) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); + return_VALUE(0); + } + + /* TBD: Support multiple index (IRQ) entries per Link Device */ + if (0 != index) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index)); + return_VALUE(0); + } + + if (!link->irq.active) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n")); + return_VALUE(0); + } + + return_VALUE(link->irq.active); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +static int +acpi_pci_link_add ( + struct acpi_device *device) +{ + int result = 0; + struct acpi_pci_link *link = NULL; + int i = 0; + int found = 0; + + ACPI_FUNCTION_TRACE("acpi_pci_link_add"); + + if (!device) + return_VALUE(-EINVAL); + + link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); + if (!link) + return_VALUE(-ENOMEM); + memset(link, 0, sizeof(struct acpi_pci_link)); + + link->device = device; + link->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_PCI_LINK_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_PCI_LINK_CLASS); + acpi_driver_data(device) = link; + + result = acpi_pci_link_get_possible(link); + if (0 != result) + goto end; + + acpi_pci_link_get_current(link); + + printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), acpi_device_bid(device)); + for (i = 0; i < link->irq.possible_count; i++) { + if (link->irq.active == link->irq.possible[i]) { + printk(" *%d", link->irq.possible[i]); + found = 1; + } + else + printk(" %d", link->irq.possible[i]); + } + if (!link->irq.active) + printk(", disabled"); + else if (!found) + printk(", enabled at IRQ %d", link->irq.active); + printk(")\n"); + + /* TBD: Acquire/release lock */ + list_add_tail(&link->node, &acpi_link.entries); + acpi_link.count++; + +end: + if (0 != result) + kfree(link); + + return_VALUE(result); +} + + +static int +acpi_pci_link_remove ( + struct acpi_device *device, + int type) +{ + struct acpi_pci_link *link = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_link_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + link = (struct acpi_pci_link *) acpi_driver_data(device); + + /* TBD: Acquire/release lock */ + list_del(&link->node); + + kfree(link); + + return_VALUE(0); +} + + +int __init +acpi_pci_link_init (void) +{ + ACPI_FUNCTION_TRACE("acpi_pci_link_init"); + + acpi_link.count = 0; + INIT_LIST_HEAD(&acpi_link.entries); + + if (0 > acpi_bus_register_driver(&acpi_pci_link_driver)) + return_VALUE(-ENODEV); + + return_VALUE(0); +} diff -Nur linux-2.4.19/drivers/acpi/pci_root.c linux-2.4.19-sgi211r3/drivers/acpi/pci_root.c --- linux-2.4.19/drivers/acpi/pci_root.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/pci_root.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,245 @@ +/* + * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_PCI_COMPONENT +ACPI_MODULE_NAME ("pci_root") + +extern struct pci_ops *pci_root_ops; + +#define PREFIX "ACPI: " + +static int acpi_pci_root_add (struct acpi_device *device); +static int acpi_pci_root_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_pci_root_driver = { + name: ACPI_PCI_ROOT_DRIVER_NAME, + class: ACPI_PCI_ROOT_CLASS, + ids: ACPI_PCI_ROOT_HID, + ops: { + add: acpi_pci_root_add, + remove: acpi_pci_root_remove, + }, +}; + +struct acpi_pci_root { + acpi_handle handle; + acpi_pci_id id; + struct pci_bus *bus; +}; + + +static int +acpi_pci_root_add ( + struct acpi_device *device) +{ + int result = 0; + struct acpi_pci_root *root = NULL; + acpi_status status = AE_OK; + unsigned long value = 0; + acpi_handle handle = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_root_add"); + + if (!device) + return_VALUE(-EINVAL); + + root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); + if (!root) + return_VALUE(-ENOMEM); + memset(root, 0, sizeof(struct acpi_pci_root)); + + root->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_PCI_ROOT_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_PCI_ROOT_CLASS); + acpi_driver_data(device) = root; + + /* + * TBD: Doesn't the bus driver automatically set this? + */ + device->ops.bind = acpi_pci_bind; + + /* + * Segment + * ------- + * Obtained via _SEG, if exists, otherwise assumed to be zero (0). + */ + status = acpi_evaluate_integer(root->handle, METHOD_NAME__SEG, NULL, + &value); + switch (status) { + case AE_OK: + root->id.segment = (u16) value; + break; + case AE_NOT_FOUND: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Assuming segment 0 (no _SEG)\n")); + root->id.segment = 0; + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SEG\n")); + result = -ENODEV; + goto end; + } + + /* + * Bus + * --- + * Obtained via _BBN, if exists, otherwise assumed to be zero (0). + */ + status = acpi_evaluate_integer(root->handle, METHOD_NAME__BBN, NULL, + &value); + switch (status) { + case AE_OK: + root->id.bus = (u16) value; + break; + case AE_NOT_FOUND: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n")); + root->id.bus = 0; + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BBN\n")); + result = -ENODEV; + goto end; + } + + /* + * Device & Function + * ----------------- + * Obtained from _ADR (which has already been evaluated for us). + */ + root->id.device = device->pnp.bus_address >> 16; + root->id.function = device->pnp.bus_address & 0xFFFF; + + /* + * TBD: Evaluate _CRS to get root bridge resources + * TBD: Need PCI interface for enumeration/configuration of roots. + */ + + printk(KERN_INFO PREFIX "%s [%s] (%02x:%02x)\n", + acpi_device_name(device), acpi_device_bid(device), + root->id.segment, root->id.bus); + + /* + * Scan the Root Bridge + * -------------------- + * Must do this prior to any attempt to bind the root device, as the + * PCI namespace does not get created until this call is made (and + * thus the root bridge's pci_dev does not exist). + */ + root->bus = pcibios_scan_root(root->handle, root->id.segment, + root->id.bus); + if (!root->bus) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Bus %02x:%02x not present in PCI namespace\n", + root->id.segment, root->id.bus)); + result = -ENODEV; + goto end; + } + + /* + * Attach ACPI-PCI Context + * ----------------------- + * Thus binding the ACPI and PCI devices. + */ + result = acpi_pci_bind_root(device, &root->id, root->bus); + if (0 != result) + goto end; + + /* + * PCI Routing Table + * ----------------- + * Evaluate and parse _PRT, if exists. + */ + status = acpi_get_handle(root->handle, METHOD_NAME__PRT, &handle); + if (ACPI_SUCCESS(status)) + result = acpi_pci_irq_add_prt(root->handle, root->id.segment, + root->id.bus); + +end: + if (0 != result) + kfree(root); + + return_VALUE(result); +} + + +static int +acpi_pci_root_remove ( + struct acpi_device *device, + int type) +{ + struct acpi_pci_root *root = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_root_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + root = (struct acpi_pci_root *) acpi_driver_data(device); + + kfree(root); + + return_VALUE(0); +} + + +int __init +acpi_pci_root_init (void) +{ + ACPI_FUNCTION_TRACE("acpi_pci_root_init"); + + /* DEBUG: + acpi_dbg_layer = ACPI_PCI_COMPONENT; + acpi_dbg_level = 0xFFFFFFFF; + */ + + if (0 > acpi_bus_register_driver(&acpi_pci_root_driver)) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +void __exit +acpi_pci_root_exit (void) +{ + ACPI_FUNCTION_TRACE("acpi_pci_root_exit"); + + acpi_bus_unregister_driver(&acpi_pci_root_driver); + + return_VOID; +} diff -Nur linux-2.4.19/drivers/acpi/power.c linux-2.4.19-sgi211r3/drivers/acpi/power.c --- linux-2.4.19/drivers/acpi/power.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/power.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,610 @@ +/* + * acpi_power.c - ACPI Bus Power Management ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_POWER_COMPONENT +ACPI_MODULE_NAME ("acpi_power") + +#define PREFIX "ACPI: " + + +int acpi_power_add (struct acpi_device *device); +int acpi_power_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_power_driver = { + name: ACPI_POWER_DRIVER_NAME, + class: ACPI_POWER_CLASS, + ids: ACPI_POWER_HID, + ops: { + add: acpi_power_add, + remove: acpi_power_remove, + }, +}; + +struct acpi_power_resource +{ + acpi_handle handle; + acpi_bus_id name; + u32 system_level; + u32 order; + int state; + int references; +}; + +static struct list_head acpi_power_resource_list; + + +/* -------------------------------------------------------------------------- + Power Resource Management + -------------------------------------------------------------------------- */ + +static int +acpi_power_get_context ( + acpi_handle handle, + struct acpi_power_resource **resource) +{ + int result = 0; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_power_get_context"); + + if (!resource) + return_VALUE(-ENODEV); + + result = acpi_bus_get_device(handle, &device); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error getting context [%p]\n", + handle)); + return_VALUE(result); + } + + *resource = (struct acpi_power_resource *) acpi_driver_data(device); + if (!resource) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +static int +acpi_power_get_state ( + struct acpi_power_resource *resource) +{ + acpi_status status = AE_OK; + unsigned long sta = 0; + + ACPI_FUNCTION_TRACE("acpi_power_get_state"); + + if (!resource) + return_VALUE(-EINVAL); + + status = acpi_evaluate_integer(resource->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + if (sta & 0x01) + resource->state = ACPI_POWER_RESOURCE_STATE_ON; + else + resource->state = ACPI_POWER_RESOURCE_STATE_OFF; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", + resource->name, resource->state?"on":"off")); + + return_VALUE(0); +} + + +static int +acpi_power_get_list_state ( + struct acpi_handle_list *list, + int *state) +{ + int result = 0; + struct acpi_power_resource *resource = NULL; + u32 i = 0; + + ACPI_FUNCTION_TRACE("acpi_power_get_list_state"); + + if (!list || !state) + return_VALUE(-EINVAL); + + /* The state of the list is 'on' IFF all resources are 'on'. */ + + for (i=0; icount; i++) { + result = acpi_power_get_context(list->handles[i], &resource); + if (0 != result) + return_VALUE(result); + result = acpi_power_get_state(resource); + if (0 != result) + return_VALUE(result); + + *state = resource->state; + + if (*state != ACPI_POWER_RESOURCE_STATE_ON) + break; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", + *state?"on":"off")); + + return_VALUE(result); +} + + +static int +acpi_power_on ( + acpi_handle handle) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_device *device = NULL; + struct acpi_power_resource *resource = NULL; + + ACPI_FUNCTION_TRACE("acpi_power_on"); + + result = acpi_power_get_context(handle, &resource); + if (0 != result) + return_VALUE(result); + + resource->references++; + + if ((resource->references > 1) + || (resource->state == ACPI_POWER_RESOURCE_STATE_ON)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n", + resource->name)); + return_VALUE(0); + } + + status = acpi_evaluate(resource->handle, "_ON", NULL, NULL); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + result = acpi_power_get_state(resource); + if (0 != result) + return_VALUE(result); + if (resource->state != ACPI_POWER_RESOURCE_STATE_ON) + return_VALUE(-ENOEXEC); + + /* Update the power resource's _device_ power state */ + result = acpi_bus_get_device(resource->handle, &device); + if (0 != result) + return_VALUE(result); + device->power.state = ACPI_STATE_D0; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n", + resource->name)); + + return_VALUE(0); +} + + +static int +acpi_power_off ( + acpi_handle handle) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_device *device = NULL; + struct acpi_power_resource *resource = NULL; + + ACPI_FUNCTION_TRACE("acpi_power_off"); + + result = acpi_power_get_context(handle, &resource); + if (0 != result) + return_VALUE(result); + + if (resource->references) + resource->references--; + + if (resource->references) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Resource [%s] is still in use, dereferencing\n", + device->pnp.bus_id)); + return_VALUE(0); + } + + if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n", + device->pnp.bus_id)); + return_VALUE(0); + } + + status = acpi_evaluate(resource->handle, "_OFF", NULL, NULL); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + result = acpi_power_get_state(resource); + if (0 != result) + return_VALUE(result); + if (resource->state != ACPI_POWER_RESOURCE_STATE_OFF) + return_VALUE(-ENOEXEC); + + /* Update the power resource's _device_ power state */ + result = acpi_bus_get_device(resource->handle, &device); + if (0 != result) + return_VALUE(result); + device->power.state = ACPI_STATE_D3; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n", + resource->name)); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Device Power Management + -------------------------------------------------------------------------- */ + +int +acpi_power_get_inferred_state ( + struct acpi_device *device) +{ + int result = 0; + struct acpi_handle_list *list = NULL; + int list_state = 0; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_power_get_inferred_state"); + + if (!device) + return_VALUE(-EINVAL); + + device->power.state = ACPI_STATE_UNKNOWN; + + /* + * We know a device's inferred power state when all the resources + * required for a given D-state are 'on'. + */ + for (i=ACPI_STATE_D0; ipower.states[i].resources; + if (list->count < 1) + continue; + + result = acpi_power_get_list_state(list, &list_state); + if (0 != result) + return_VALUE(result); + + if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { + device->power.state = i; + return_VALUE(0); + } + } + + device->power.state = ACPI_STATE_D3; + + return_VALUE(0); +} + + +int +acpi_power_transition ( + struct acpi_device *device, + int state) +{ + int result = 0; + struct acpi_handle_list *cl = NULL; /* Current Resources */ + struct acpi_handle_list *tl = NULL; /* Target Resources */ + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_power_transition"); + + if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) + return_VALUE(-EINVAL); + + cl = &device->power.states[device->power.state].resources; + tl = &device->power.states[state].resources; + + device->power.state = ACPI_STATE_UNKNOWN; + + if (!cl->count && !tl->count) { + result = -ENODEV; + goto end; + } + + /* TBD: Resources must be ordered. */ + + /* + * First we reference all power resources required in the target list + * (e.g. so the device doesn't loose power while transitioning). + */ + for (i=0; icount; i++) { + result = acpi_power_on(tl->handles[i]); + if (0 != result) + goto end; + } + + device->power.state = state; + + /* + * Then we dereference all power resources used in the current list. + */ + for (i=0; icount; i++) { + result = acpi_power_off(cl->handles[i]); + if (0 != result) + goto end; + } + +end: + if (0 != result) + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Error transitioning device [%s] to D%d\n", + device->pnp.bus_id, state)); + + return_VALUE(result); +} + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +struct proc_dir_entry *acpi_power_dir = NULL; + + +static int +acpi_power_read_status ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_power_resource *resource = NULL; + char *p = page; + int len; + + ACPI_FUNCTION_TRACE("acpi_power_read_status"); + + if (!data || (off != 0)) + goto end; + + resource = (struct acpi_power_resource *) data; + + p += sprintf(p, "state: "); + switch (resource->state) { + case ACPI_POWER_RESOURCE_STATE_ON: + p += sprintf(p, "on\n"); + break; + case ACPI_POWER_RESOURCE_STATE_OFF: + p += sprintf(p, "off\n"); + break; + default: + p += sprintf(p, "unknown\n"); + break; + } + + p += sprintf(p, "system level: S%d\n", + resource->system_level); + p += sprintf(p, "order: %d\n", + resource->order); + p += sprintf(p, "reference count: %d\n", + resource->references); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_power_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_power_add_fs"); + + if (!device) + return_VALUE(-EINVAL); + + if (!acpi_power_dir) { + acpi_power_dir = proc_mkdir(ACPI_POWER_CLASS, acpi_root_dir); + if (!acpi_power_dir) + return_VALUE(-ENODEV); + } + + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_power_dir); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + } + + /* 'status' [R] */ + entry = create_proc_entry(ACPI_POWER_FILE_STATUS, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_POWER_FILE_STATUS)); + else { + entry->read_proc = acpi_power_read_status; + entry->data = acpi_driver_data(device); + } + + return_VALUE(0); +} + + +static int +acpi_power_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_power_remove_fs"); + + if (!acpi_power_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_power_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +int +acpi_power_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_power_resource *resource = NULL; + acpi_object acpi_object; + acpi_buffer buffer = {sizeof(acpi_object), &acpi_object}; + + ACPI_FUNCTION_TRACE("acpi_power_add"); + + if (!device) + return_VALUE(-EINVAL); + + resource = kmalloc(sizeof(struct acpi_power_resource), GFP_KERNEL); + if (!resource) + return_VALUE(-ENOMEM); + memset(resource, 0, sizeof(struct acpi_power_resource)); + + resource->handle = device->handle; + sprintf(resource->name, "%s", device->pnp.bus_id); + sprintf(acpi_device_name(device), "%s", ACPI_POWER_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_POWER_CLASS); + acpi_driver_data(device) = resource; + + /* Evalute the object to get the system level and resource order. */ + status = acpi_evaluate_object(resource->handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) { + result = -ENODEV; + goto end; + } + resource->system_level = acpi_object.power_resource.system_level; + resource->order = acpi_object.power_resource.resource_order; + + result = acpi_power_get_state(resource); + if (0 != result) + goto end; + + switch (resource->state) { + case ACPI_POWER_RESOURCE_STATE_ON: + device->power.state = ACPI_STATE_D0; + break; + case ACPI_POWER_RESOURCE_STATE_OFF: + device->power.state = ACPI_STATE_D3; + break; + default: + device->power.state = ACPI_STATE_UNKNOWN; + break; + } + + result = acpi_power_add_fs(device); + if (0 != result) + goto end; + + printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), + acpi_device_bid(device), resource->state?"on":"off"); + +end: + if (0 != result) + kfree(resource); + + return_VALUE(result); +} + + +int +acpi_power_remove ( + struct acpi_device *device, + int type) +{ + struct acpi_power_resource *resource = NULL; + + ACPI_FUNCTION_TRACE("acpi_power_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + resource = (struct acpi_power_resource *) acpi_driver_data(device); + + acpi_power_remove_fs(device); + + kfree(resource); + + return_VALUE(0); +} + + +int __init +acpi_power_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_power_init"); + + INIT_LIST_HEAD(&acpi_power_resource_list); + + result = acpi_bus_register_driver(&acpi_power_driver); + if (0 > result) { + remove_proc_entry(ACPI_POWER_CLASS, acpi_root_dir); + return_VALUE(-ENODEV); + } + + return_VALUE(0); +} + + +void __exit +acpi_power_exit (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_power_exit"); + + /* TBD: Empty acpi_power_resource_list */ + + result = acpi_bus_unregister_driver(&acpi_power_driver); + if (0 == result) + remove_proc_entry(ACPI_POWER_CLASS, acpi_root_dir); + + return_VOID; +} diff -Nur linux-2.4.19/drivers/acpi/processor.c linux-2.4.19-sgi211r3/drivers/acpi/processor.c --- linux-2.4.19/drivers/acpi/processor.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/processor.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,2324 @@ +/* + * acpi_processor.c - ACPI Processor Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * TBD: + * 1. Make # power/performance states dynamic. + * 2. Support duty_cycle values that span bit 4. + * 3. Optimize by having scheduler determine business instead of + * having us try to calculate it here. + * 4. Need C1 timing -- must modify kernel (IRQ handler) to get this. + * 5. Convert time values to ticks (initially) to avoid having to do + * the math (acpi_get_timer_duration). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_PROCESSOR_COMPONENT +ACPI_MODULE_NAME ("acpi_processor") + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +#define PREFIX "ACPI: " + +#define US_TO_PM_TIMER_TICKS(t) ((t * PM_TIMER_FREQUENCY) / 1000000) +#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */ +#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */ + +#define ACPI_PROCESSOR_BUSY_METRIC 10 + +#define ACPI_PROCESSOR_MAX_POWER ACPI_C_STATE_COUNT +#define ACPI_PROCESSOR_MAX_C2_LATENCY 100 +#define ACPI_PROCESSOR_MAX_C3_LATENCY 1000 + +#define ACPI_PROCESSOR_MAX_PERFORMANCE 8 + +#define ACPI_PROCESSOR_MAX_THROTTLING 16 +#define ACPI_PROCESSOR_MAX_THROTTLE 250 /* 25% */ +#define ACPI_PROCESSOR_MAX_DUTY_WIDTH 4 + +const u32 POWER_OF_2[] = {1,2,4,8,16,32,64}; + +#define ACPI_PROCESSOR_LIMIT_USER 0 +#define ACPI_PROCESSOR_LIMIT_THERMAL 1 + +static int acpi_processor_add (struct acpi_device *device); +static int acpi_processor_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_processor_driver = { + name: ACPI_PROCESSOR_DRIVER_NAME, + class: ACPI_PROCESSOR_CLASS, + ids: ACPI_PROCESSOR_HID, + ops: { + add: acpi_processor_add, + remove: acpi_processor_remove, + }, +}; + +/* Power Management */ + +struct acpi_processor_cx_policy { + u32 count; + int state; + struct { + u32 time; + u32 ticks; + u32 count; + u32 bm; + } threshold; +}; + +struct acpi_processor_cx { + u8 valid; + u32 address; + u32 latency; + u32 latency_ticks; + u32 power; + u32 usage; + struct acpi_processor_cx_policy promotion; + struct acpi_processor_cx_policy demotion; +}; + +struct acpi_processor_power { + int state; + int default_state; + u32 bm_activity; + struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; +}; + +/* Performance Management */ + +struct acpi_pct_register { + u8 descriptor; + u16 length; + u8 space_id; + u8 bit_width; + u8 bit_offset; + u8 reserved; + u64 address; +} __attribute__ ((packed)); + +struct acpi_processor_px { + acpi_integer core_frequency; /* megahertz */ + acpi_integer power; /* milliWatts */ + acpi_integer transition_latency; /* microseconds */ + acpi_integer bus_master_latency; /* microseconds */ + acpi_integer control; /* control value */ + acpi_integer status; /* success indicator */ +}; + +struct acpi_processor_performance { + int state; + int platform_limit; + u16 control_register; + u16 status_register; + int state_count; + struct acpi_processor_px states[ACPI_PROCESSOR_MAX_PERFORMANCE]; +}; + + +/* Throttling Control */ + +struct acpi_processor_tx { + u16 power; + u16 performance; +}; + +struct acpi_processor_throttling { + int state; + u32 address; + u8 duty_offset; + u8 duty_width; + int state_count; + struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING]; +}; + +/* Limit Interface */ + +struct acpi_processor_lx { + int px; /* performace state */ + int tx; /* throttle level */ +}; + +struct acpi_processor_limit { + struct acpi_processor_lx state; /* current limit */ + struct acpi_processor_lx thermal; /* thermal limit */ + struct acpi_processor_lx user; /* user limit */ +}; + + +struct acpi_processor_flags { + u8 power:1; + u8 performance:1; + u8 throttling:1; + u8 limit:1; + u8 bm_control:1; + u8 bm_check:1; + u8 reserved:2; +}; + +struct acpi_processor { + acpi_handle handle; + u32 acpi_id; + u32 id; + struct acpi_processor_flags flags; + struct acpi_processor_power power; + struct acpi_processor_performance performance; + struct acpi_processor_throttling throttling; + struct acpi_processor_limit limit; +}; + +struct acpi_processor_errata { + u8 smp; + struct { + u8 throttle:1; + u8 fdma:1; + u8 reserved:6; + u32 bmisx; + } piix4; +}; + +static struct acpi_processor *processors[NR_CPUS]; +static struct acpi_processor_errata errata; +static void (*pm_idle_save)(void) = NULL; + + +/* -------------------------------------------------------------------------- + Errata Handling + -------------------------------------------------------------------------- */ + +int +acpi_processor_errata_piix4 ( + struct pci_dev *dev) +{ + u8 rev = 0; + u8 value1 = 0; + u8 value2 = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_errata_piix4"); + + if (!dev) + return_VALUE(-EINVAL); + + /* + * Note that 'dev' references the PIIX4 ACPI Controller. + */ + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + switch (rev) { + case 0: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n")); + break; + case 1: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n")); + break; + case 2: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n")); + break; + case 3: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n")); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n")); + break; + } + + switch (rev) { + + case 0: /* PIIX4 A-step */ + case 1: /* PIIX4 B-step */ + /* + * See specification changes #13 ("Manual Throttle Duty Cycle") + * and #14 ("Enabling and Disabling Manual Throttle"), plus + * erratum #5 ("STPCLK# Deassertion Time") from the January + * 2002 PIIX4 specification update. Applies to only older + * PIIX4 models. + */ + errata.piix4.throttle = 1; + + case 2: /* PIIX4E */ + case 3: /* PIIX4M */ + /* + * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA + * Livelock") from the January 2002 PIIX4 specification update. + * Applies to all PIIX4 models. + */ + + /* + * BM-IDE + * ------ + * Find the PIIX4 IDE Controller and get the Bus Master IDE + * Status register address. We'll use this later to read + * each IDE controller's DMA status to make sure we catch all + * DMA activity. + */ + dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB, + PCI_ANY_ID, PCI_ANY_ID, NULL); + if (dev) + errata.piix4.bmisx = pci_resource_start(dev, 4); + + /* + * Type-F DMA + * ---------- + * Find the PIIX4 ISA Controller and read the Motherboard + * DMA controller's status to see if Type-F (Fast) DMA mode + * is enabled (bit 7) on either channel. Note that we'll + * disable C3 support if this is enabled, as some legacy + * devices won't operate well if fast DMA is disabled. + */ + dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_0, + PCI_ANY_ID, PCI_ANY_ID, NULL); + if (dev) { + pci_read_config_byte(dev, 0x76, &value1); + pci_read_config_byte(dev, 0x77, &value2); + if ((value1 & 0x80) || (value2 & 0x80)) + errata.piix4.fdma = 1; + } + + break; + } + + if (errata.piix4.bmisx) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Bus master activity detection (BM-IDE) erratum enabled\n")); + if (errata.piix4.fdma) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Type-F DMA livelock erratum (C3 disabled)\n")); + + return_VALUE(0); +} + + +int +acpi_processor_errata ( + struct acpi_processor *pr) +{ + int result = 0; + struct pci_dev *dev = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_errata"); + + if (!pr) + return_VALUE(-EINVAL); + + /* + * PIIX4 + */ + dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, PCI_ANY_ID, NULL); + if (dev) + result = acpi_processor_errata_piix4(dev); + + return_VALUE(result); +} + + +/* -------------------------------------------------------------------------- + Power Management + -------------------------------------------------------------------------- */ + +static inline u32 +ticks_elapsed ( + u32 t1, + u32 t2) +{ + if (t2 >= t1) + return (t2 - t1); + else if (!acpi_fadt.tmr_val_ext) + return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF); + else + return ((0xFFFFFFFF - t1) + t2); +} + + +static void +acpi_processor_power_activate ( + struct acpi_processor *pr, + int state) +{ + if (!pr) + return; + + pr->power.states[pr->power.state].promotion.count = 0; + pr->power.states[pr->power.state].demotion.count = 0; + + /* Cleanup from old state. */ + switch (pr->power.state) { + case ACPI_STATE_C3: + /* Disable bus master reload */ + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, ACPI_MTX_DO_NOT_LOCK); + break; + } + + /* Prepare to use new state. */ + switch (state) { + case ACPI_STATE_C3: + /* Enable bus master reload */ + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1, ACPI_MTX_DO_NOT_LOCK); + break; + } + + pr->power.state = state; + + return; +} + + +static void +acpi_processor_idle (void) +{ + struct acpi_processor *pr = NULL; + struct acpi_processor_cx *cx = NULL; + int next_state = 0; + int sleep_ticks = 0; + u32 t1, t2 = 0; + + pr = processors[smp_processor_id()]; + if (!pr) + return; + + /* + * Interrupts must be disabled during bus mastering calculations and + * for C2/C3 transitions. + */ + __cli(); + + cx = &(pr->power.states[pr->power.state]); + + /* + * Check BM Activity + * ----------------- + * Check for bus mastering activity (if required), record, and check + * for demotion. + */ + if (pr->flags.bm_check) { + u32 bm_status = 0; + + pr->power.bm_activity <<= 1; + + acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, + &bm_status, ACPI_MTX_DO_NOT_LOCK); + if (bm_status) { + pr->power.bm_activity++; + acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, + 1, ACPI_MTX_DO_NOT_LOCK); + } + /* + * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect + * the true state of bus mastering activity; forcing us to + * manually check the BMIDEA bit of each IDE channel. + */ + else if (errata.piix4.bmisx) { + if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01) + || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01)) + pr->power.bm_activity++; + } + /* + * Apply bus mastering demotion policy. Automatically demote + * to avoid a faulty transition. Note that the processor + * won't enter a low-power state during this call (to this + * funciton) but should upon the next. + * + * TBD: A better policy might be to fallback to the demotion + * state (use it for this quantum only) istead of + * demoting -- and rely on duration as our sole demotion + * qualification. This may, however, introduce DMA + * issues (e.g. floppy DMA transfer overrun/underrun). + */ + if (pr->power.bm_activity & cx->demotion.threshold.bm) { + __sti(); + next_state = cx->demotion.state; + goto end; + } + } + + cx->usage++; + + /* + * Sleep: + * ------ + * Invoke the current Cx state to put the processor to sleep. + */ + switch (pr->power.state) { + + case ACPI_STATE_C1: + /* Invoke C1. */ + safe_halt(); + /* + * TBD: Can't get time duration while in C1, as resumes + * go to an ISR rather than here. Need to instrument + * base interrupt handler. + */ + sleep_ticks = 0xFFFFFFFF; + break; + + case ACPI_STATE_C2: + /* Get start time (ticks) */ + t1 = inl(acpi_fadt.Xpm_tmr_blk.address); + /* Invoke C2 */ + inb(pr->power.states[ACPI_STATE_C2].address); + /* Dummy op - must do something useless after P_LVL2 read */ + t2 = inl(acpi_fadt.Xpm_tmr_blk.address); + /* Get end time (ticks) */ + t2 = inl(acpi_fadt.Xpm_tmr_blk.address); + /* Re-enable interrupts */ + __sti(); + /* Compute time (ticks) that we were actually asleep */ + sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; + break; + + case ACPI_STATE_C3: + /* Disable bus master arbitration */ + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); + /* Get start time (ticks) */ + t1 = inl(acpi_fadt.Xpm_tmr_blk.address); + /* Invoke C3 */ + inb(pr->power.states[ACPI_STATE_C3].address); + /* Dummy op - must do something useless after P_LVL3 read */ + t2 = inl(acpi_fadt.Xpm_tmr_blk.address); + /* Get end time (ticks) */ + t2 = inl(acpi_fadt.Xpm_tmr_blk.address); + /* Enable bus master arbitration */ + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); + /* Re-enable interrupts */ + __sti(); + /* Compute time (ticks) that we were actually asleep */ + sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; + break; + + default: + __sti(); + return; + } + + next_state = pr->power.state; + + /* + * Promotion? + * ---------- + * Track the number of longs (time asleep is greater than threshold) + * and promote when the count threshold is reached. Note that bus + * mastering activity may prevent promotions. + */ + if (cx->promotion.state) { + if (sleep_ticks > cx->promotion.threshold.ticks) { + cx->promotion.count++; + cx->demotion.count = 0; + if (cx->promotion.count >= cx->promotion.threshold.count) { + if (pr->flags.bm_check) { + if (!(pr->power.bm_activity & cx->promotion.threshold.bm)) { + next_state = cx->promotion.state; + goto end; + } + } + else { + next_state = cx->promotion.state; + goto end; + } + } + } + } + + /* + * Demotion? + * --------- + * Track the number of shorts (time asleep is less than time threshold) + * and demote when the usage threshold is reached. + */ + if (cx->demotion.state) { + if (sleep_ticks < cx->demotion.threshold.ticks) { + cx->demotion.count++; + cx->promotion.count = 0; + if (cx->demotion.count >= cx->demotion.threshold.count) { + next_state = cx->demotion.state; + goto end; + } + } + } + +end: + /* + * New Cx State? + * ------------- + * If we're going to start using a new Cx state we must clean up + * from the previous and prepare to use the new. + */ + if (next_state != pr->power.state) + acpi_processor_power_activate(pr, next_state); + + return; +} + + +static int +acpi_processor_set_power_policy ( + struct acpi_processor *pr) +{ + ACPI_FUNCTION_TRACE("acpi_processor_set_power_policy"); + + /* + * This function sets the default Cx state policy (OS idle handler). + * Our scheme is to promote quickly to C2 but more conservatively + * to C3. We're favoring C2 for its characteristics of low latency + * (quick response), good power savings, and ability to allow bus + * mastering activity. Note that the Cx state policy is completely + * customizable and can be altered dynamically. + */ + + if (!pr) + return_VALUE(-EINVAL); + + /* + * C0/C1 + * ----- + */ + pr->power.state = ACPI_STATE_C1; + pr->power.default_state = ACPI_STATE_C1; + + /* + * C1/C2 + * ----- + * Set the default C1 promotion and C2 demotion policies, where we + * promote from C1 to C2 after several (10) successive C1 transitions, + * as we cannot (currently) measure the time spent in C1. Demote from + * C2 to C1 anytime we experience a 'short' (time spent in C2 is less + * than the C2 transtion latency). Note the simplifying assumption + * that the 'cost' of a transition is amortized when we sleep for at + * least as long as the transition's latency (thus the total transition + * time is two times the latency). + * + * TBD: Measure C1 sleep times by instrumenting the core IRQ handler. + * TBD: Demote to default C-State after long periods of activity. + * TBD: Investigate policy's use of CPU utilization -vs- sleep duration. + */ + if (pr->power.states[ACPI_STATE_C2].valid) { + pr->power.states[ACPI_STATE_C1].promotion.threshold.count = 10; + pr->power.states[ACPI_STATE_C1].promotion.threshold.ticks = + pr->power.states[ACPI_STATE_C2].latency_ticks; + pr->power.states[ACPI_STATE_C1].promotion.state = ACPI_STATE_C2; + + pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 1; + pr->power.states[ACPI_STATE_C2].demotion.threshold.ticks = + pr->power.states[ACPI_STATE_C2].latency_ticks; + pr->power.states[ACPI_STATE_C2].demotion.state = ACPI_STATE_C1; + } + + /* + * C2/C3 + * ----- + * Set default C2 promotion and C3 demotion policies, where we promote + * from C2 to C3 after several (4) cycles of no bus mastering activity + * while maintaining sleep time criteria. Demote immediately on a + * short or whenever bus mastering activity occurs. + */ + if ((pr->power.states[ACPI_STATE_C2].valid) && + (pr->power.states[ACPI_STATE_C3].valid)) { + pr->power.states[ACPI_STATE_C2].promotion.threshold.count = 4; + pr->power.states[ACPI_STATE_C2].promotion.threshold.ticks = + pr->power.states[ACPI_STATE_C3].latency_ticks; + pr->power.states[ACPI_STATE_C2].promotion.threshold.bm = 0x0F; + pr->power.states[ACPI_STATE_C2].promotion.state = ACPI_STATE_C3; + + pr->power.states[ACPI_STATE_C3].demotion.threshold.count = 1; + pr->power.states[ACPI_STATE_C3].demotion.threshold.ticks = + pr->power.states[ACPI_STATE_C3].latency_ticks; + pr->power.states[ACPI_STATE_C3].demotion.threshold.bm = 0x0F; + pr->power.states[ACPI_STATE_C3].demotion.state = ACPI_STATE_C2; + } + + return_VALUE(0); +} + + +int +acpi_processor_get_power_info ( + struct acpi_processor *pr) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_power_info"); + + if (!pr) + return_VALUE(-EINVAL); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "lvl2[0x%08x] lvl3[0x%08x]\n", + pr->power.states[ACPI_STATE_C2].address, + pr->power.states[ACPI_STATE_C3].address)); + + /* TBD: Support ACPI 2.0 objects */ + + /* + * C0 + * -- + * This state exists only as filler in our array. + */ + pr->power.states[ACPI_STATE_C0].valid = 1; + + /* + * C1 + * -- + * ACPI requires C1 support for all processors. + * + * TBD: What about PROC_C1? + */ + pr->power.states[ACPI_STATE_C1].valid = 1; + + /* + * C2 + * -- + * We're (currently) only supporting C2 on UP systems. + * + * TBD: Support for C2 on MP (P_LVL2_UP). + */ + if (pr->power.states[ACPI_STATE_C2].address) { + + pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat; + + /* + * C2 latency must be less than or equal to 100 microseconds. + */ + if (acpi_fadt.plvl2_lat >= ACPI_PROCESSOR_MAX_C2_LATENCY) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C2 latency too large [%d]\n", + acpi_fadt.plvl2_lat)); + /* + * Only support C2 on UP systems (see TBD above). + */ + else if (errata.smp) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C2 not supported in SMP mode\n")); + /* + * Otherwise we've met all of our C2 requirements. + * Normalize the C2 latency to expidite policy. + */ + else { + pr->power.states[ACPI_STATE_C2].valid = 1; + pr->power.states[ACPI_STATE_C2].latency_ticks = + US_TO_PM_TIMER_TICKS(acpi_fadt.plvl2_lat); + } + } + + /* + * C3 + * -- + * TBD: Investigate use of WBINVD on UP/SMP system in absence of + * bm_control. + */ + if (pr->power.states[ACPI_STATE_C3].address) { + + pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat; + + /* + * C3 latency must be less than or equal to 1000 microseconds. + */ + if (acpi_fadt.plvl3_lat >= ACPI_PROCESSOR_MAX_C3_LATENCY) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 latency too large [%d]\n", + acpi_fadt.plvl3_lat)); + /* + * Only support C3 when bus mastering arbitration control + * is present (able to disable bus mastering to maintain + * cache coherency while in C3). + */ + else if (!pr->flags.bm_control) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 support requires bus mastering control\n")); + /* + * Only support C3 on UP systems, as bm_control is only viable + * on a UP system and flushing caches (e.g. WBINVD) is simply + * too costly (at this time). + */ + else if (errata.smp) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 not supported in SMP mode\n")); + /* + * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) + * DMA transfers are used by any ISA device to avoid livelock. + * Note that we could disable Type-F DMA (as recommended by + * the erratum), but this is known to disrupt certain ISA + * devices thus we take the conservative approach. + */ + else if (errata.piix4.fdma) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 not supported on PIIX4 with Type-F DMA\n")); + } + /* + * Otherwise we've met all of our C3 requirements. + * Normalize the C2 latency to expidite policy. Enable + * checking of bus mastering status (bm_check) so we can + * use this in our C3 policy. + */ + else { + pr->power.states[ACPI_STATE_C3].valid = 1; + pr->power.states[ACPI_STATE_C3].latency_ticks = + US_TO_PM_TIMER_TICKS(acpi_fadt.plvl3_lat); + pr->flags.bm_check = 1; + } + } + + /* + * Set Default Policy + * ------------------ + * Now that we know which state are supported, set the default + * policy. Note that this policy can be changed dynamically + * (e.g. encourage deeper sleeps to conserve battery life when + * not on AC). + */ + result = acpi_processor_set_power_policy(pr); + if (0 != result) + return_VALUE(result); + + /* + * If this processor supports C2 or C3 we denote it as being 'power + * manageable'. Note that there's really no policy involved for + * when only C1 is supported. + */ + if (pr->power.states[ACPI_STATE_C2].valid + || pr->power.states[ACPI_STATE_C3].valid) + pr->flags.power = 1; + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Performance Management + -------------------------------------------------------------------------- */ + +static int +acpi_processor_get_platform_limit ( + struct acpi_processor* pr) +{ + acpi_status status = 0; + unsigned long ppc = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_platform_limit"); + + if (!pr) + return_VALUE(-EINVAL); + + /* + * _PPC indicates the maximum state currently supported by the platform + * (e.g. 0 = states 0..n; 1 = states 1..n; etc. + */ + status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc); + if(ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PPC\n")); + return_VALUE(-ENODEV); + } + + pr->performance.platform_limit = (int) ppc; + + return_VALUE(0); +} + + +static int +acpi_processor_get_performance_control ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = 0; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_object *pct = NULL; + acpi_object obj = {0}; + struct acpi_pct_register *reg = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control"); + + status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer); + if(ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n")); + return_VALUE(-ENODEV); + } + + pct = (acpi_object *) buffer.pointer; + if (!pct || (pct->type != ACPI_TYPE_PACKAGE) + || (pct->package.count != 2)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n")); + result = -EFAULT; + goto end; + } + + /* + * control_register + */ + + obj = pct->package.elements[0]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_pct_register)) + || (obj.buffer.pointer == NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid _PCT data (control_register)\n")); + result = -EFAULT; + goto end; + } + + reg = (struct acpi_pct_register *) (obj.buffer.pointer); + + if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unsupported address space [%d] (control_register)\n", + (u32) reg->space_id)); + result = -EFAULT; + goto end; + } + + pr->performance.control_register = (u16) reg->address; + + /* + * status_register + */ + + obj = pct->package.elements[1]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_pct_register)) + || (obj.buffer.pointer == NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid _PCT data (status_register)\n")); + result = -EFAULT; + goto end; + } + + reg = (struct acpi_pct_register *) (obj.buffer.pointer); + + if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unsupported address space [%d] (status_register)\n", + (u32) reg->space_id)); + result = -EFAULT; + goto end; + } + + pr->performance.status_register = (u16) reg->address; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "control_register[0x%04x] status_register[0x%04x]\n", + pr->performance.control_register, + pr->performance.status_register)); + +end: + kfree(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_processor_get_performance_states ( + struct acpi_processor* pr) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_buffer format = {sizeof("NNNNNN"), "NNNNNN"}; + acpi_buffer state = {0, NULL}; + acpi_object *pss = NULL; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states"); + + status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); + if(ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n")); + return_VALUE(-ENODEV); + } + + pss = (acpi_object *) buffer.pointer; + if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); + result = -EFAULT; + goto end; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", + pss->package.count)); + + if (pss->package.count > ACPI_PROCESSOR_MAX_PERFORMANCE) { + pr->performance.state_count = ACPI_PROCESSOR_MAX_PERFORMANCE; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Limiting number of states to max (%d)\n", + ACPI_PROCESSOR_MAX_PERFORMANCE)); + } + else + pr->performance.state_count = pss->package.count; + + if (pr->performance.state_count > 1) + pr->flags.performance = 1; + + for (i = 0; i < pr->performance.state_count; i++) { + + struct acpi_processor_px *px = &(pr->performance.states[i]); + + state.length = sizeof(struct acpi_processor_px); + state.pointer = px; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); + + status = acpi_extract_package(&(pss->package.elements[i]), + &format, &state); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); + result = -EFAULT; + goto end; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n", + i, + (u32) px->core_frequency, + (u32) px->power, + (u32) px->transition_latency, + (u32) px->bus_master_latency, + (u32) px->control, + (u32) px->status)); + } + +end: + kfree(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_processor_set_performance ( + struct acpi_processor *pr, + int state) +{ + u16 port = 0; + u8 value = 0; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_set_performance"); + + if (!pr) + return_VALUE(-EINVAL); + + if (!pr->flags.performance) + return_VALUE(-ENODEV); + + if (state >= pr->performance.state_count) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Invalid target state (P%d)\n", state)); + return_VALUE(-ENODEV); + } + + if (state < pr->performance.platform_limit) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Platform limit (P%d) overrides target state (P%d)\n", + pr->performance.platform_limit, state)); + return_VALUE(-ENODEV); + } + + if (state == pr->performance.state) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Already at target state (P%d)\n", state)); + return_VALUE(0); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n", + pr->performance.state, state)); + + /* + * First we write the target state's 'control' value to the + * control_register. + */ + + port = pr->performance.control_register; + value = (u16) pr->performance.states[state].control; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Writing 0x%02x to port 0x%04x\n", value, port)); + + outb(value, port); + + /* + * Then we read the 'status_register' and compare the value with the + * target state's 'status' to make sure the transition was successful. + * Note that we'll poll for up to 1ms (100 cycles of 10us) before + * giving up. + */ + + port = pr->performance.status_register; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Looking for 0x%02x from port 0x%04x\n", + (u8) pr->performance.states[state].status, port)); + + for (i=0; i<100; i++) { + value = inb(port); + if (value == (u8) pr->performance.states[state].status) + break; + udelay(10); + } + + if (value != pr->performance.states[state].status) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Transition failed\n")); + return_VALUE(-ENODEV); + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Transition successful after %d microseconds\n", + i * 10)); + + pr->performance.state = state; + + return_VALUE(0); +} + + +static int +acpi_processor_get_performance_info ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_handle handle = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info"); + + if (!pr) + return_VALUE(-EINVAL); + + status = acpi_get_handle(pr->handle, "_PCT", &handle); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "ACPI-based processor performance control unavailable\n")); + return_VALUE(0); + } + + result = acpi_processor_get_performance_control(pr); + if (0 != result) + return_VALUE(result); + + result = acpi_processor_get_performance_states(pr); + if (0 != result) + return_VALUE(result); + + result = acpi_processor_get_platform_limit(pr); + if (0 != result) + return_VALUE(result); + + /* + * TBD: Don't trust the latency values we get from BIOS, but rather + * measure the latencies during run-time (e.g. get_latencies). + */ + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Throttling Control + -------------------------------------------------------------------------- */ + +static int +acpi_processor_get_throttling ( + struct acpi_processor *pr) +{ + int state = 0; + u32 value = 0; + u32 duty_mask = 0; + u32 duty_value = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_throttling"); + + if (!pr) + return_VALUE(-EINVAL); + + if (!pr->flags.throttling) + return_VALUE(-ENODEV); + + pr->throttling.state = 0; + + __cli(); + + duty_mask = pr->throttling.state_count - 1; + + duty_mask <<= pr->throttling.duty_offset; + + value = inl(pr->throttling.address); + + /* + * Compute the current throttling state when throttling is enabled + * (bit 4 is on). + */ + if (value & 0x10) { + duty_value = value & duty_mask; + duty_value >>= pr->throttling.duty_offset; + + if (duty_value) + state = pr->throttling.state_count-duty_value; + } + + pr->throttling.state = state; + + __sti(); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Throttling state is T%d (%d%% throttling applied)\n", + state, pr->throttling.states[state].performance)); + + return_VALUE(0); +} + + +static int +acpi_processor_set_throttling ( + struct acpi_processor *pr, + int state) +{ + u32 value = 0; + u32 duty_mask = 0; + u32 duty_value = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_set_throttling"); + + if (!pr) + return_VALUE(-EINVAL); + + if ((state < 0) || (state > (pr->throttling.state_count - 1))) + return_VALUE(-EINVAL); + + if (!pr->flags.throttling) + return_VALUE(-ENODEV); + + if (state == pr->throttling.state) + return_VALUE(0); + + __cli(); + + /* + * Calculate the duty_value and duty_mask. + */ + if (state) { + duty_value = pr->throttling.state_count - state; + + duty_value <<= pr->throttling.duty_offset; + + /* Used to clear all duty_value bits */ + duty_mask = pr->throttling.state_count - 1; + + duty_mask <<= acpi_fadt.duty_offset; + duty_mask = ~duty_mask; + } + + /* + * Disable throttling by writing a 0 to bit 4. Note that we must + * turn it off before you can change the duty_value. + */ + value = inl(pr->throttling.address); + if (value & 0x10) { + value &= 0xFFFFFFEF; + outl(value, pr->throttling.address); + } + + /* + * Write the new duty_value and then enable throttling. Note + * that a state value of 0 leaves throttling disabled. + */ + if (state) { + value &= duty_mask; + value |= duty_value; + outl(value, pr->throttling.address); + + value |= 0x00000010; + outl(value, pr->throttling.address); + } + + pr->throttling.state = state; + + __sti(); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Throttling state set to T%d (%d%%)\n", state, + (pr->throttling.states[state].performance?pr->throttling.states[state].performance/10:0))); + + return_VALUE(0); +} + + +static int +acpi_processor_get_throttling_info ( + struct acpi_processor *pr) +{ + int result = 0; + int step = 0; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_throttling_info"); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", + pr->throttling.address, + pr->throttling.duty_offset, + pr->throttling.duty_width)); + + if (!pr) + return_VALUE(-EINVAL); + + /* TBD: Support ACPI 2.0 objects */ + + if (!pr->throttling.address) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n")); + return_VALUE(0); + } + else if (!pr->throttling.duty_width) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n")); + return_VALUE(0); + } + /* TBD: Support duty_cycle values that span bit 4. */ + else if ((pr->throttling.duty_offset + + pr->throttling.duty_width) > 4) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "duty_cycle spans bit 4\n")); + return_VALUE(0); + } + + /* + * PIIX4 Errata: We don't support throttling on the original PIIX4. + * This shouldn't be an issue as few (if any) mobile systems ever + * used this part. + */ + if (errata.piix4.throttle) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Throttling not supported on PIIX4 A- or B-step\n")); + return_VALUE(0); + } + + pr->throttling.state_count = POWER_OF_2[acpi_fadt.duty_width]; + + /* + * Compute state values. Note that throttling displays a linear power/ + * performance relationship (at 50% performance the CPU will consume + * 50% power). Values are in 1/10th of a percent to preserve accuracy. + */ + + step = (1000 / pr->throttling.state_count); + + for (i=0; ithrottling.state_count; i++) { + pr->throttling.states[i].performance = step * i; + pr->throttling.states[i].power = step * i; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n", + pr->throttling.state_count)); + + pr->flags.throttling = 1; + + /* + * Disable throttling (if enabled). We'll let subsequent policy (e.g. + * thermal) decide to lower performance if it so chooses, but for now + * we'll crank up the speed. + */ + + result = acpi_processor_get_throttling(pr); + if (0 != result) + goto end; + + if (pr->throttling.state) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabling throttling (was T%d)\n", + pr->throttling.state)); + result = acpi_processor_set_throttling(pr, 0); + if (0 != result) + goto end; + } + +end: + if (0 != result) + pr->flags.throttling = 0; + + return_VALUE(result); +} + + +/* -------------------------------------------------------------------------- + Limit Interface + -------------------------------------------------------------------------- */ + +static int +acpi_processor_apply_limit ( + struct acpi_processor* pr) +{ + int result = 0; + u16 px = 0; + u16 tx = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_apply_limit"); + + if (!pr) + return_VALUE(-EINVAL); + + if (!pr->flags.limit) + return_VALUE(-ENODEV); + + if (pr->flags.performance) { + px = pr->performance.platform_limit; + if (pr->limit.user.px > px) + px = pr->limit.user.px; + if (pr->limit.thermal.px > px) + px = pr->limit.thermal.px; + + result = acpi_processor_set_performance(pr, px); + if (0 != result) + goto end; + } + + if (pr->flags.throttling) { + if (pr->limit.user.tx > tx) + tx = pr->limit.user.tx; + if (pr->limit.thermal.tx > tx) + tx = pr->limit.thermal.tx; + + result = acpi_processor_set_throttling(pr, tx); + if (0 != result) + goto end; + } + + pr->limit.state.px = px; + pr->limit.state.tx = tx; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d] limit set to (P%d:T%d)\n", + pr->id, + pr->limit.state.px, + pr->limit.state.tx)); + +end: + if (0 != result) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n")); + + return_VALUE(result); +} + + +int +acpi_processor_set_thermal_limit ( + acpi_handle handle, + int type) +{ + int result = 0; + struct acpi_processor *pr = NULL; + struct acpi_device *device = NULL; + int px = 0; + int tx = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit"); + + if ((type < ACPI_PROCESSOR_LIMIT_NONE) + || (type > ACPI_PROCESSOR_LIMIT_DECREMENT)) + return_VALUE(-EINVAL); + + result = acpi_bus_get_device(handle, &device); + if (0 != result) + return_VALUE(result); + + pr = (struct acpi_processor *) acpi_driver_data(device); + if (!pr) + return_VALUE(-ENODEV); + + if (!pr->flags.limit) + return_VALUE(-ENODEV); + + /* Thermal limits are always relative to the current Px/Tx state. */ + if (pr->flags.performance) + pr->limit.thermal.px = pr->performance.state; + if (pr->flags.throttling) + pr->limit.thermal.tx = pr->throttling.state; + + /* + * Our default policy is to only use throttling at the lowest + * performance state. + */ + + switch (type) { + + case ACPI_PROCESSOR_LIMIT_NONE: + px = 0; + tx = 0; + break; + + case ACPI_PROCESSOR_LIMIT_INCREMENT: + if (pr->flags.performance) { + if (px == (pr->performance.state_count - 1)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "At maximum performance state\n")); + else { + px++; + goto end; + } + } + if (pr->flags.throttling) { + if (tx == (pr->throttling.state_count - 1)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "At maximum throttling state\n")); + else + tx++; + } + break; + + case ACPI_PROCESSOR_LIMIT_DECREMENT: + if (pr->flags.performance) { + if (px == pr->performance.platform_limit) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "At minimum performance state\n")); + else { + px--; + goto end; + } + } + if (pr->flags.throttling) { + if (tx == 0) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "At minimum throttling state\n")); + else + tx--; + } + break; + } + +end: + pr->limit.thermal.px = px; + pr->limit.thermal.tx = tx; + + result = acpi_processor_apply_limit(pr); + if (0 != result) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to set thermal limit\n")); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n", + pr->limit.thermal.px, + pr->limit.thermal.tx)); + + return_VALUE(result); +} + + +static int +acpi_processor_get_limit_info ( + struct acpi_processor *pr) +{ + ACPI_FUNCTION_TRACE("acpi_processor_get_limit_info"); + + if (!pr) + return_VALUE(-EINVAL); + + if (pr->flags.performance || pr->flags.throttling) + pr->flags.limit = 1; + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +struct proc_dir_entry *acpi_processor_dir = NULL; + +static int +acpi_processor_read_info ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_processor *pr = (struct acpi_processor *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_read_info"); + + if (!pr || (off != 0)) + goto end; + + p += sprintf(p, "processor id: %d\n", + pr->id); + + p += sprintf(p, "acpi id: %d\n", + pr->acpi_id); + + p += sprintf(p, "bus mastering control: %s\n", + pr->flags.bm_control ? "yes" : "no"); + + p += sprintf(p, "power management: %s\n", + pr->flags.power ? "yes" : "no"); + + p += sprintf(p, "throttling control: %s\n", + pr->flags.throttling ? "yes" : "no"); + + p += sprintf(p, "performance management: %s\n", + pr->flags.performance ? "yes" : "no"); + + p += sprintf(p, "limit interface: %s\n", + pr->flags.limit ? "yes" : "no"); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_processor_read_power ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_processor *pr = (struct acpi_processor *) data; + char *p = page; + int len = 0; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_read_power"); + + if (!pr || (off != 0)) + goto end; + + p += sprintf(p, "active state: C%d\n", + pr->power.state); + + p += sprintf(p, "default state: C%d\n", + pr->power.default_state); + + p += sprintf(p, "bus master activity: %08x\n", + pr->power.bm_activity); + + p += sprintf(p, "states:\n"); + + for (i=1; ipower.state?'*':' '), i); + + if (!pr->power.states[i].valid) { + p += sprintf(p, "\n"); + continue; + } + + if (pr->power.states[i].promotion.state) + p += sprintf(p, "promotion[C%d] ", + pr->power.states[i].promotion.state); + else + p += sprintf(p, "promotion[--] "); + + if (pr->power.states[i].demotion.state) + p += sprintf(p, "demotion[C%d] ", + pr->power.states[i].demotion.state); + else + p += sprintf(p, "demotion[--] "); + + p += sprintf(p, "latency[%03d] usage[%08d]\n", + pr->power.states[i].latency, + pr->power.states[i].usage); + } + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_processor_read_performance ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_processor *pr = (struct acpi_processor *) data; + char *p = page; + int len = 0; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_read_performance"); + + if (!pr || (off != 0)) + goto end; + + if (!pr->flags.performance) { + p += sprintf(p, "\n"); + goto end; + } + + p += sprintf(p, "state count: %d\n", + pr->performance.state_count); + + p += sprintf(p, "active state: P%d\n", + pr->performance.state); + + p += sprintf(p, "states:\n"); + + for (i=0; iperformance.state_count; i++) + p += sprintf(p, " %cP%d: %d MHz, %d mW, %d uS\n", + (i == pr->performance.state?'*':' '), i, + (u32) pr->performance.states[i].core_frequency, + (u32) pr->performance.states[i].power, + (u32) pr->performance.states[i].transition_latency); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_processor_write_performance ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + struct acpi_processor *pr = (struct acpi_processor *) data; + char state_string[12] = {'\0'}; + + ACPI_FUNCTION_TRACE("acpi_processor_write_performance"); + + if (!pr || (count > sizeof(state_string) - 1)) + return_VALUE(-EINVAL); + + if (copy_from_user(state_string, buffer, count)) + return_VALUE(-EFAULT); + + state_string[count] = '\0'; + + result = acpi_processor_set_performance(pr, + simple_strtoul(state_string, NULL, 0)); + if (0 != result) + return_VALUE(result); + + return_VALUE(count); +} + + +static int +acpi_processor_read_throttling ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_processor *pr = (struct acpi_processor *) data; + char *p = page; + int len = 0; + int i = 0; + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_read_throttling"); + + if (!pr || (off != 0)) + goto end; + + if (!(pr->throttling.state_count > 0)) { + p += sprintf(p, "\n"); + goto end; + } + + result = acpi_processor_get_throttling(pr); + + if (result) { + p += sprintf(p, "Could not determine current throttling state.\n"); + goto end; + } + + p += sprintf(p, "state count: %d\n", + pr->throttling.state_count); + + p += sprintf(p, "active state: T%d\n", + pr->throttling.state); + + p += sprintf(p, "states:\n"); + + for (i=0; ithrottling.state_count; i++) + p += sprintf(p, " %cT%d: %02d%%\n", + (i == pr->throttling.state?'*':' '), i, + (pr->throttling.states[i].performance?pr->throttling.states[i].performance/10:0)); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_processor_write_throttling ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + struct acpi_processor *pr = (struct acpi_processor *) data; + char state_string[12] = {'\0'}; + + ACPI_FUNCTION_TRACE("acpi_processor_write_throttling"); + + if (!pr || (count > sizeof(state_string) - 1)) + return_VALUE(-EINVAL); + + if (copy_from_user(state_string, buffer, count)) + return_VALUE(-EFAULT); + + state_string[count] = '\0'; + + result = acpi_processor_set_throttling(pr, + simple_strtoul(state_string, NULL, 0)); + if (0 != result) + return_VALUE(result); + + return_VALUE(count); +} + + +static int +acpi_processor_read_limit ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_processor *pr = (struct acpi_processor *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_read_limit"); + + if (!pr || (off != 0)) + goto end; + + if (!pr->flags.limit) { + p += sprintf(p, "\n"); + goto end; + } + + p += sprintf(p, "active limit: P%d:T%d\n", + pr->limit.state.px, pr->limit.state.tx); + + p += sprintf(p, "platform limit: P%d:T0\n", + pr->flags.performance?pr->performance.platform_limit:0); + + p += sprintf(p, "user limit: P%d:T%d\n", + pr->limit.user.px, pr->limit.user.tx); + + p += sprintf(p, "thermal limit: P%d:T%d\n", + pr->limit.thermal.px, pr->limit.thermal.tx); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_processor_write_limit ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + struct acpi_processor *pr = (struct acpi_processor *) data; + char limit_string[25] = {'\0'}; + int px = 0; + int tx = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_write_limit"); + + if (!pr || (count > sizeof(limit_string) - 1)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n")); + return_VALUE(-EINVAL); + } + + if (copy_from_user(limit_string, buffer, count)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n")); + return_VALUE(-EFAULT); + } + + limit_string[count] = '\0'; + + if (sscanf(limit_string, "%d:%d", &px, &tx) != 2) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n")); + return_VALUE(-EINVAL); + } + + if (pr->flags.performance) { + if ((px < pr->performance.platform_limit) + || (px > (pr->performance.state_count - 1))) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid px\n")); + return_VALUE(-EINVAL); + } + pr->limit.user.px = px; + } + + if (pr->flags.throttling) { + if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n")); + return_VALUE(-EINVAL); + } + pr->limit.user.tx = tx; + } + + result = acpi_processor_apply_limit(pr); + + return_VALUE(count); +} + + +static int +acpi_processor_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_add_fs"); + + if (!acpi_processor_dir) { + acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, + acpi_root_dir); + if (!acpi_processor_dir) + return_VALUE(-ENODEV); + } + + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_processor_dir); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + } + + /* 'info' [R] */ + entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_PROCESSOR_FILE_INFO)); + else { + entry->read_proc = acpi_processor_read_info; + entry->data = acpi_driver_data(device); + } + + /* 'power' [R] */ + entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_PROCESSOR_FILE_POWER)); + else { + entry->read_proc = acpi_processor_read_power; + entry->data = acpi_driver_data(device); + } + + /* 'performance' [R/W] */ + entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_PROCESSOR_FILE_PERFORMANCE)); + else { + entry->read_proc = acpi_processor_read_performance; + entry->write_proc = acpi_processor_write_performance; + entry->data = acpi_driver_data(device); + } + + /* 'throttling' [R/W] */ + entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_PROCESSOR_FILE_THROTTLING)); + else { + entry->read_proc = acpi_processor_read_throttling; + entry->write_proc = acpi_processor_write_throttling; + entry->data = acpi_driver_data(device); + } + + /* 'limit' [R/W] */ + entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_PROCESSOR_FILE_LIMIT)); + else { + entry->read_proc = acpi_processor_read_limit; + entry->write_proc = acpi_processor_write_limit; + entry->data = acpi_driver_data(device); + } + + return_VALUE(0); +} + + +static int +acpi_processor_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_processor_remove_fs"); + + if (!acpi_processor_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_processor_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +static int +acpi_processor_get_info ( + struct acpi_processor *pr) +{ + acpi_status status = 0; + acpi_object object = {0}; + acpi_buffer buffer = {sizeof(acpi_object), &object}; + static int cpu_count = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_info"); + + if (!pr) + return_VALUE(-EINVAL); + +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) + errata.smp = smp_num_cpus; +#endif + + acpi_processor_errata(pr); + + /* + * Check to see if we have bus mastering arbitration control. This + * is required for proper C3 usage (to maintain cache coherency). + */ + if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) { + pr->flags.bm_control = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Bus mastering arbitration control present\n")); + } + else + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "No bus mastering arbitration control\n")); + + /* + * Evalute the processor object. Note that it is common on SMP to + * have the first (boot) processor with a valid PBLK address while + * all others have a NULL address. + */ + status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error evaluating processor object\n")); + return_VALUE(-ENODEV); + } + + /* + * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. + * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c + */ + pr->id = cpu_count++; + pr->acpi_id = object.processor.proc_id; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, + pr->acpi_id)); + + if (!object.processor.pblk_address) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); + else if (object.processor.pblk_length < 6) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid PBLK length [%d]\n", + object.processor.pblk_length)); + else { + pr->throttling.address = object.processor.pblk_address; + pr->throttling.duty_offset = acpi_fadt.duty_offset; + pr->throttling.duty_width = acpi_fadt.duty_width; + pr->power.states[ACPI_STATE_C2].address = + object.processor.pblk_address + 4; + pr->power.states[ACPI_STATE_C3].address = + object.processor.pblk_address + 5; + } + + acpi_processor_get_power_info(pr); + acpi_processor_get_performance_info(pr); + acpi_processor_get_throttling_info(pr); + acpi_processor_get_limit_info(pr); + + return_VALUE(0); +} + + +static void +acpi_processor_notify ( + acpi_handle handle, + u32 event, + void *data) +{ + int result = 0; + struct acpi_processor *pr = (struct acpi_processor *) data; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_notify"); + + if (!pr) + return_VOID; + + if (0 != acpi_bus_get_device(pr->handle, &device)) + return_VOID; + + switch (event) { + case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: + result = acpi_processor_get_platform_limit(pr); + if (0 == result) + acpi_processor_apply_limit(pr); + + acpi_bus_generate_event(device, event, + pr->performance.platform_limit); + break; + case ACPI_PROCESSOR_NOTIFY_POWER: + /* TBD */ + acpi_bus_generate_event(device, event, 0); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + return_VOID; +} + + +static int +acpi_processor_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_processor *pr = NULL; + u32 i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_add"); + + if (!device) + return_VALUE(-EINVAL); + + pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL); + if (!pr) + return_VALUE(-ENOMEM); + memset(pr, 0, sizeof(struct acpi_processor)); + + pr->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_PROCESSOR_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_PROCESSOR_CLASS); + acpi_driver_data(device) = pr; + + result = acpi_processor_get_info(pr); + if (0 != result) + goto end; + + result = acpi_processor_add_fs(device); + if (0 != result) + goto end; + + status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, + acpi_processor_notify, pr); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error installing notify handler\n")); + result = -ENODEV; + goto end; + } + + processors[pr->id] = pr; + + /* + * Install the idle handler if processor power management is supported. + * Note that the default idle handler (default_idle) will be used on + * platforms that only support C1. + */ + if ((pr->id == 0) && (pr->flags.power)) { + pm_idle_save = pm_idle; + pm_idle = acpi_processor_idle; + } + + printk(KERN_INFO PREFIX "%s [%s] (supports", + acpi_device_name(device), acpi_device_bid(device)); + for (i=1; ipower.states[i].valid) + printk(" C%d", i); + if (pr->flags.performance) + printk(", %d performance states", pr->performance.state_count); + if (pr->flags.throttling) + printk(", %d throttling states", pr->throttling.state_count); + printk(")\n"); + +end: + if (0 != result) { + acpi_processor_remove_fs(device); + kfree(pr); + } + + return_VALUE(result); +} + + +static int +acpi_processor_remove ( + struct acpi_device *device, + int type) +{ + acpi_status status = AE_OK; + struct acpi_processor *pr = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + pr = (struct acpi_processor *) acpi_driver_data(device); + + /* Unregister the idle handler when processor #0 is removed. */ + if (pr->id == 0) + pm_idle = pm_idle_save; + + status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, + acpi_processor_notify); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error removing notify handler\n")); + return_VALUE(-ENODEV); + } + + acpi_processor_remove_fs(device); + + processors[pr->id] = NULL; + + kfree(pr); + + return_VALUE(0); +} + + +static int __init +acpi_processor_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_init"); + + memset(&processors, 0, sizeof(processors)); + memset(&errata, 0, sizeof(errata)); + + result = acpi_bus_register_driver(&acpi_processor_driver); + if (0 > result) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +static void __exit +acpi_processor_exit (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_exit"); + + result = acpi_bus_unregister_driver(&acpi_processor_driver); + if (0 == result) + remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); + + return_VOID; +} + + +module_init(acpi_processor_init); +module_exit(acpi_processor_exit); diff -Nur linux-2.4.19/drivers/acpi/resources/Makefile linux-2.4.19-sgi211r3/drivers/acpi/resources/Makefile --- linux-2.4.19/drivers/acpi/resources/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/resources/rsaddr.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsaddr.c --- linux-2.4.19/drivers/acpi/resources/rsaddr.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsaddr.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsaddr - Address resource descriptors (16/32/64) - * $Revision: 19 $ + * $Revision: 26 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsaddr") + ACPI_MODULE_NAME ("rsaddr") /******************************************************************************* @@ -37,13 +37,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -56,26 +55,26 @@ acpi_status acpi_rs_address16_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; - NATIVE_CHAR *temp_ptr; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_address16); + acpi_resource *output_struct = (void *) *output_buffer; + u8 *temp_ptr; + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_address16); u32 index; u16 temp16; u8 temp8; - FUNCTION_TRACE ("Rs_address16_resource"); + ACPI_FUNCTION_TRACE ("Rs_address16_resource"); /* * Point past the Descriptor to get the number of bytes consumed */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS16; @@ -87,6 +86,7 @@ temp8 = *buffer; /* Values 0-2 are valid */ + if (temp8 > 2) { return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } @@ -99,24 +99,20 @@ buffer += 1; temp8 = *buffer; - /* - * Producer / Consumer - */ + /* Producer / Consumer */ + output_struct->data.address16.producer_consumer = temp8 & 0x01; - /* - * Decode - */ + /* Decode */ + output_struct->data.address16.decode = (temp8 >> 1) & 0x01; - /* - * Min Address Fixed - */ + /* Min Address Fixed */ + output_struct->data.address16.min_address_fixed = (temp8 >> 2) & 0x01; - /* - * Max Address Fixed - */ + /* Max Address Fixed */ + output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01; /* @@ -125,19 +121,17 @@ buffer += 1; temp8 = *buffer; - if (MEMORY_RANGE == output_struct->data.address16.resource_type) { + if (ACPI_MEMORY_RANGE == output_struct->data.address16.resource_type) { output_struct->data.address16.attribute.memory.read_write_attribute = (u16) (temp8 & 0x01); output_struct->data.address16.attribute.memory.cache_attribute = (u16) ((temp8 >> 1) & 0x0F); } - else { - if (IO_RANGE == output_struct->data.address16.resource_type) { + if (ACPI_IO_RANGE == output_struct->data.address16.resource_type) { output_struct->data.address16.attribute.io.range_attribute = (u16) (temp8 & 0x03); } - else { /* BUS_NUMBER_RANGE == Address16.Data->Resource_type */ /* Nothing needs to be filled in */ @@ -148,35 +142,35 @@ * Get Granularity (Bytes 6-7) */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.granularity, + ACPI_MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.granularity, buffer); /* * Get Min_address_range (Bytes 8-9) */ buffer += 2; - MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.min_address_range, + ACPI_MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.min_address_range, buffer); /* * Get Max_address_range (Bytes 10-11) */ buffer += 2; - MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.max_address_range, + ACPI_MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.max_address_range, buffer); /* * Get Address_translation_offset (Bytes 12-13) */ buffer += 2; - MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.address_translation_offset, + ACPI_MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.address_translation_offset, buffer); /* * Get Address_length (Bytes 14-15) */ buffer += 2; - MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.address_length, + ACPI_MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.address_length, buffer); /* @@ -206,7 +200,7 @@ output_struct->data.address16.resource_source.string_ptr = (NATIVE_CHAR *)((u8 * )output_struct + struct_size); - temp_ptr = output_struct->data.address16.resource_source.string_ptr; + temp_ptr = (u8 *) output_struct->data.address16.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -233,9 +227,8 @@ * Struct_size to the next 32-bit boundary. */ temp8 = (u8) (index + 1); - struct_size += ROUND_UP_TO_32_bITS (temp8); + struct_size += ACPI_ROUND_UP_TO_32_bITS (temp8); } - else { output_struct->data.address16.resource_source.index = 0x00; output_struct->data.address16.resource_source.string_length = 0; @@ -245,7 +238,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -261,9 +254,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -276,16 +268,16 @@ acpi_rs_address16_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u8 *length_field; u8 temp8; NATIVE_CHAR *temp_pointer = NULL; - u32 actual_bytes; + ACPI_SIZE actual_bytes; - FUNCTION_TRACE ("Rs_address16_stream"); + ACPI_FUNCTION_TRACE ("Rs_address16_stream"); /* @@ -324,7 +316,7 @@ */ temp8 = 0; - if (MEMORY_RANGE == linked_list->data.address16.resource_type) { + if (ACPI_MEMORY_RANGE == linked_list->data.address16.resource_type) { temp8 = (u8) (linked_list->data.address16.attribute.memory.read_write_attribute & 0x01); @@ -333,8 +325,7 @@ (linked_list->data.address16.attribute.memory.cache_attribute & 0x0F) << 1; } - - else if (IO_RANGE == linked_list->data.address16.resource_type) { + else if (ACPI_IO_RANGE == linked_list->data.address16.resource_type) { temp8 = (u8) (linked_list->data.address16.attribute.io.range_attribute & 0x03); @@ -346,35 +337,35 @@ /* * Set the address space granularity */ - MOVE_UNALIGNED16_TO_16 (buffer, + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.address16.granularity); buffer += 2; /* * Set the address range minimum */ - MOVE_UNALIGNED16_TO_16 (buffer, + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.address16.min_address_range); buffer += 2; /* * Set the address range maximum */ - MOVE_UNALIGNED16_TO_16 (buffer, + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.address16.max_address_range); buffer += 2; /* * Set the address translation offset */ - MOVE_UNALIGNED16_TO_16 (buffer, + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.address16.address_translation_offset); buffer += 2; /* * Set the address length */ - MOVE_UNALIGNED16_TO_16 (buffer, + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.address16.address_length); buffer += 2; @@ -392,21 +383,20 @@ /* * Copy the string */ - STRCPY (temp_pointer, + ACPI_STRCPY (temp_pointer, linked_list->data.address16.resource_source.string_ptr); /* * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (STRLEN (linked_list->data.address16.resource_source.string_ptr) - + 1); + buffer += (ACPI_STRLEN (linked_list->data.address16.resource_source.string_ptr) + 1); } /* * Return the number of bytes consumed in this operation */ - actual_bytes = POINTER_DIFF (buffer, *output_buffer); + actual_bytes = ACPI_PTR_DIFF (buffer, *output_buffer); *bytes_consumed = actual_bytes; /* @@ -414,7 +404,7 @@ * minus the header size (3 bytes) */ actual_bytes -= 3; - MOVE_UNALIGNED16_TO_16 (length_field, &actual_bytes); + ACPI_MOVE_UNALIGNED16_TO_16 (length_field, &actual_bytes); return_ACPI_STATUS (AE_OK); } @@ -425,13 +415,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -444,33 +433,30 @@ acpi_status acpi_rs_address32_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer; - acpi_resource *output_struct; + acpi_resource *output_struct= (void *) *output_buffer; u16 temp16; u8 temp8; - NATIVE_CHAR *temp_ptr; - u32 struct_size; + u8 *temp_ptr; + ACPI_SIZE struct_size; u32 index; - FUNCTION_TRACE ("Rs_address32_resource"); + ACPI_FUNCTION_TRACE ("Rs_address32_resource"); buffer = byte_stream_buffer; - output_struct = (acpi_resource *) *output_buffer; - - struct_size = SIZEOF_RESOURCE (acpi_resource_address32); + struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_address32); /* * Point past the Descriptor to get the number of bytes consumed */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); - + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS32; @@ -520,20 +506,18 @@ buffer += 1; temp8 = *buffer; - if (MEMORY_RANGE == output_struct->data.address32.resource_type) { + if (ACPI_MEMORY_RANGE == output_struct->data.address32.resource_type) { output_struct->data.address32.attribute.memory.read_write_attribute = (u16) (temp8 & 0x01); output_struct->data.address32.attribute.memory.cache_attribute = (u16) ((temp8 >> 1) & 0x0F); } - else { - if (IO_RANGE == output_struct->data.address32.resource_type) { + if (ACPI_IO_RANGE == output_struct->data.address32.resource_type) { output_struct->data.address32.attribute.io.range_attribute = (u16) (temp8 & 0x03); } - else { /* BUS_NUMBER_RANGE == Output_struct->Data.Address32.Resource_type */ /* Nothing needs to be filled in */ @@ -544,35 +528,35 @@ * Get Granularity (Bytes 6-9) */ buffer += 1; - MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.granularity, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.granularity, buffer); /* * Get Min_address_range (Bytes 10-13) */ buffer += 4; - MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.min_address_range, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.min_address_range, buffer); /* * Get Max_address_range (Bytes 14-17) */ buffer += 4; - MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.max_address_range, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.max_address_range, buffer); /* * Get Address_translation_offset (Bytes 18-21) */ buffer += 4; - MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.address_translation_offset, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.address_translation_offset, buffer); /* * Get Address_length (Bytes 22-25) */ buffer += 4; - MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.address_length, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.address_length, buffer); /* @@ -601,12 +585,11 @@ output_struct->data.address32.resource_source.string_ptr = (NATIVE_CHAR *)((u8 *)output_struct + struct_size); - temp_ptr = output_struct->data.address32.resource_source.string_ptr; + temp_ptr = (u8 *) output_struct->data.address32.resource_source.string_ptr; /* Copy the string into the buffer */ index = 0; - while (0x00 != *buffer) { *temp_ptr = *buffer; @@ -627,9 +610,8 @@ * Struct_size to the next 32-bit boundary. */ temp8 = (u8) (index + 1); - struct_size += ROUND_UP_TO_32_bITS (temp8); + struct_size += ACPI_ROUND_UP_TO_32_bITS (temp8); } - else { output_struct->data.address32.resource_source.index = 0x00; output_struct->data.address32.resource_source.string_length = 0; @@ -639,7 +621,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -655,9 +637,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -670,7 +651,7 @@ acpi_rs_address32_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer; u16 *length_field; @@ -678,7 +659,7 @@ NATIVE_CHAR *temp_pointer; - FUNCTION_TRACE ("Rs_address32_stream"); + ACPI_FUNCTION_TRACE ("Rs_address32_stream"); buffer = *output_buffer; @@ -692,8 +673,7 @@ /* * Set a pointer to the Length field - to be filled in later */ - - length_field = (u16 *) buffer; + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; /* @@ -720,7 +700,7 @@ */ temp8 = 0; - if(MEMORY_RANGE == linked_list->data.address32.resource_type) { + if (ACPI_MEMORY_RANGE == linked_list->data.address32.resource_type) { temp8 = (u8) (linked_list->data.address32.attribute.memory.read_write_attribute & 0x01); @@ -729,8 +709,7 @@ (linked_list->data.address32.attribute.memory.cache_attribute & 0x0F) << 1; } - - else if (IO_RANGE == linked_list->data.address32.resource_type) { + else if (ACPI_IO_RANGE == linked_list->data.address32.resource_type) { temp8 = (u8) (linked_list->data.address32.attribute.io.range_attribute & 0x03); @@ -742,35 +721,35 @@ /* * Set the address space granularity */ - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.address32.granularity); buffer += 4; /* * Set the address range minimum */ - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.address32.min_address_range); buffer += 4; /* * Set the address range maximum */ - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.address32.max_address_range); buffer += 4; /* * Set the address translation offset */ - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.address32.address_translation_offset); buffer += 4; /* * Set the address length */ - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.address32.address_length); buffer += 4; @@ -788,20 +767,20 @@ /* * Copy the string */ - STRCPY (temp_pointer, + ACPI_STRCPY (temp_pointer, linked_list->data.address32.resource_source.string_ptr); /* * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (STRLEN (linked_list->data.address32.resource_source.string_ptr) + 1); + buffer += (ACPI_STRLEN (linked_list->data.address32.resource_source.string_ptr) + 1); } /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* * Set the length field to the number of bytes consumed @@ -818,13 +797,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -837,32 +815,30 @@ acpi_status acpi_rs_address64_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer; - acpi_resource *output_struct; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16; u8 temp8; - NATIVE_CHAR *temp_ptr; - u32 struct_size; + u8 *temp_ptr; + ACPI_SIZE struct_size; u32 index; - FUNCTION_TRACE ("Rs_address64_resource"); + ACPI_FUNCTION_TRACE ("Rs_address64_resource"); buffer = byte_stream_buffer; - output_struct = (acpi_resource *) *output_buffer; - - struct_size = SIZEOF_RESOURCE (acpi_resource_address64); + struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_address64); /* * Point past the Descriptor to get the number of bytes consumed */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS64; @@ -874,6 +850,7 @@ temp8 = *buffer; /* Values 0-2 are valid */ + if(temp8 > 2) { return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } @@ -912,20 +889,18 @@ buffer += 1; temp8 = *buffer; - if (MEMORY_RANGE == output_struct->data.address64.resource_type) { + if (ACPI_MEMORY_RANGE == output_struct->data.address64.resource_type) { output_struct->data.address64.attribute.memory.read_write_attribute = (u16) (temp8 & 0x01); output_struct->data.address64.attribute.memory.cache_attribute = (u16) ((temp8 >> 1) & 0x0F); } - else { - if (IO_RANGE == output_struct->data.address64.resource_type) { + if (ACPI_IO_RANGE == output_struct->data.address64.resource_type) { output_struct->data.address64.attribute.io.range_attribute = (u16) (temp8 & 0x03); } - else { /* BUS_NUMBER_RANGE == Output_struct->Data.Address64.Resource_type */ /* Nothing needs to be filled in */ @@ -936,35 +911,35 @@ * Get Granularity (Bytes 6-13) */ buffer += 1; - MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.granularity, + ACPI_MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.granularity, buffer); /* * Get Min_address_range (Bytes 14-21) */ buffer += 8; - MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.min_address_range, + ACPI_MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.min_address_range, buffer); /* * Get Max_address_range (Bytes 22-29) */ buffer += 8; - MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.max_address_range, + ACPI_MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.max_address_range, buffer); /* * Get Address_translation_offset (Bytes 30-37) */ buffer += 8; - MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.address_translation_offset, + ACPI_MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.address_translation_offset, buffer); /* * Get Address_length (Bytes 38-45) */ buffer += 8; - MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.address_length, + ACPI_MOVE_UNALIGNED64_TO_64 (&output_struct->data.address64.address_length, buffer); /* @@ -995,12 +970,11 @@ output_struct->data.address64.resource_source.string_ptr = (NATIVE_CHAR *)((u8 *)output_struct + struct_size); - temp_ptr = output_struct->data.address64.resource_source.string_ptr; + temp_ptr = (u8 *) output_struct->data.address64.resource_source.string_ptr; /* Copy the string into the buffer */ index = 0; - while (0x00 != *buffer) { *temp_ptr = *buffer; @@ -1022,9 +996,8 @@ * Struct_size to the next 32-bit boundary. */ temp8 = (u8) (index + 1); - struct_size += ROUND_UP_TO_32_bITS (temp8); + struct_size += ACPI_ROUND_UP_TO_32_bITS (temp8); } - else { output_struct->data.address64.resource_source.index = 0x00; output_struct->data.address64.resource_source.string_length = 0; @@ -1034,7 +1007,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -1050,9 +1023,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -1065,7 +1037,7 @@ acpi_rs_address64_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer; u16 *length_field; @@ -1073,7 +1045,7 @@ NATIVE_CHAR *temp_pointer; - FUNCTION_TRACE ("Rs_address64_stream"); + ACPI_FUNCTION_TRACE ("Rs_address64_stream"); buffer = *output_buffer; @@ -1088,7 +1060,7 @@ * Set a pointer to the Length field - to be filled in later */ - length_field = (u16 *)buffer; + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; /* @@ -1115,7 +1087,7 @@ */ temp8 = 0; - if(MEMORY_RANGE == linked_list->data.address64.resource_type) { + if (ACPI_MEMORY_RANGE == linked_list->data.address64.resource_type) { temp8 = (u8) (linked_list->data.address64.attribute.memory.read_write_attribute & 0x01); @@ -1124,8 +1096,7 @@ (linked_list->data.address64.attribute.memory.cache_attribute & 0x0F) << 1; } - - else if (IO_RANGE == linked_list->data.address64.resource_type) { + else if (ACPI_IO_RANGE == linked_list->data.address64.resource_type) { temp8 = (u8) (linked_list->data.address64.attribute.io.range_attribute & 0x03); @@ -1137,35 +1108,35 @@ /* * Set the address space granularity */ - MOVE_UNALIGNED64_TO_64 (buffer, + ACPI_MOVE_UNALIGNED64_TO_64 (buffer, &linked_list->data.address64.granularity); buffer += 8; /* * Set the address range minimum */ - MOVE_UNALIGNED64_TO_64 (buffer, + ACPI_MOVE_UNALIGNED64_TO_64 (buffer, &linked_list->data.address64.min_address_range); buffer += 8; /* * Set the address range maximum */ - MOVE_UNALIGNED64_TO_64 (buffer, + ACPI_MOVE_UNALIGNED64_TO_64 (buffer, &linked_list->data.address64.max_address_range); buffer += 8; /* * Set the address translation offset */ - MOVE_UNALIGNED64_TO_64 (buffer, + ACPI_MOVE_UNALIGNED64_TO_64 (buffer, &linked_list->data.address64.address_translation_offset); buffer += 8; /* * Set the address length */ - MOVE_UNALIGNED64_TO_64 (buffer, + ACPI_MOVE_UNALIGNED64_TO_64 (buffer, &linked_list->data.address64.address_length); buffer += 8; @@ -1183,19 +1154,19 @@ /* * Copy the string */ - STRCPY (temp_pointer, linked_list->data.address64.resource_source.string_ptr); + ACPI_STRCPY (temp_pointer, linked_list->data.address64.resource_source.string_ptr); /* * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1); + buffer += (ACPI_STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1); } /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* * Set the length field to the number of bytes consumed diff -Nur linux-2.4.19/drivers/acpi/resources/rscalc.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rscalc.c --- linux-2.4.19/drivers/acpi/resources/rscalc.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rscalc.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rscalc - Calculate stream and list lengths - * $Revision: 32 $ + * $Revision: 42 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,12 +30,12 @@ #include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rscalc") + ACPI_MODULE_NAME ("rscalc") /******************************************************************************* * - * FUNCTION: Acpi_rs_calculate_byte_stream_length + * FUNCTION: Acpi_rs_get_byte_stream_length * * PARAMETERS: Linked_list - Pointer to the resource linked list * Size_needed - u32 pointer of the size buffer needed @@ -50,17 +50,17 @@ ******************************************************************************/ acpi_status -acpi_rs_calculate_byte_stream_length ( +acpi_rs_get_byte_stream_length ( acpi_resource *linked_list, - u32 *size_needed) + ACPI_SIZE *size_needed) { - u32 byte_stream_size_needed = 0; - u32 segment_size; + ACPI_SIZE byte_stream_size_needed = 0; + ACPI_SIZE segment_size; acpi_resource_ext_irq *ex_irq = NULL; u8 done = FALSE; - FUNCTION_TRACE ("Rs_calculate_byte_stream_length"); + ACPI_FUNCTION_TRACE ("Rs_get_byte_stream_length"); while (!done) { @@ -180,9 +180,9 @@ */ segment_size = 16; - if (NULL != linked_list->data.address16.resource_source.string_ptr) { - segment_size += (1 + - linked_list->data.address16.resource_source.string_length); + if (linked_list->data.address16.resource_source.string_ptr) { + segment_size += linked_list->data.address16.resource_source.string_length; + segment_size++; } break; @@ -196,9 +196,9 @@ */ segment_size = 26; - if (NULL != linked_list->data.address32.resource_source.string_ptr) { - segment_size += (1 + - linked_list->data.address32.resource_source.string_length); + if (linked_list->data.address32.resource_source.string_ptr) { + segment_size += linked_list->data.address32.resource_source.string_length; + segment_size++; } break; @@ -212,9 +212,9 @@ */ segment_size = 46; - if (NULL != linked_list->data.address64.resource_source.string_ptr) { - segment_size += (1 + - linked_list->data.address64.resource_source.string_length); + if (linked_list->data.address64.resource_source.string_ptr) { + segment_size += linked_list->data.address64.resource_source.string_length; + segment_size++; } break; @@ -229,11 +229,11 @@ * Resource Source + 1 for the null. */ segment_size = 9 + - ((linked_list->data.extended_irq.number_of_interrupts - 1) * 4); + (((ACPI_SIZE) linked_list->data.extended_irq.number_of_interrupts - 1) * 4); - if (NULL != ex_irq->resource_source.string_ptr) { - segment_size += (1 + - linked_list->data.extended_irq.resource_source.string_length); + if (ex_irq && ex_irq->resource_source.string_ptr) { + segment_size += linked_list->data.extended_irq.resource_source.string_length; + segment_size++; } break; @@ -243,7 +243,6 @@ * so exit with an error */ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); - break; } /* switch (Linked_list->Id) */ @@ -255,7 +254,7 @@ /* * Point to the next object */ - linked_list = POINTER_ADD (acpi_resource, + linked_list = ACPI_PTR_ADD (acpi_resource, linked_list, linked_list->length); } @@ -269,7 +268,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_rs_calculate_list_length + * FUNCTION: Acpi_rs_get_list_length * * PARAMETERS: Byte_stream_buffer - Pointer to the resource byte stream * Byte_stream_buffer_length - Size of Byte_stream_buffer @@ -286,10 +285,10 @@ ******************************************************************************/ acpi_status -acpi_rs_calculate_list_length ( +acpi_rs_get_list_length ( u8 *byte_stream_buffer, u32 byte_stream_buffer_length, - u32 *size_needed) + ACPI_SIZE *size_needed) { u32 buffer_size = 0; u32 bytes_parsed = 0; @@ -305,7 +304,7 @@ u8 additional_bytes; - FUNCTION_TRACE ("Rs_calculate_list_length"); + ACPI_FUNCTION_TRACE ("Rs_get_list_length"); while (bytes_parsed < byte_stream_buffer_length) { @@ -315,65 +314,65 @@ resource_type = acpi_rs_get_resource_type (*byte_stream_buffer); switch (resource_type) { - case RESOURCE_DESC_MEMORY_24: + case ACPI_RDESC_TYPE_MEMORY_24: /* * 24-Bit Memory Resource */ bytes_consumed = 12; - structure_size = SIZEOF_RESOURCE (acpi_resource_mem24); + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_mem24); break; - case RESOURCE_DESC_LARGE_VENDOR: + case ACPI_RDESC_TYPE_LARGE_VENDOR: /* * Vendor Defined Resource */ buffer = byte_stream_buffer; ++buffer; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); bytes_consumed = temp16 + 3; /* * Ensure a 32-bit boundary for the structure */ - temp16 = (u16) ROUND_UP_TO_32_bITS (temp16); + temp16 = (u16) ACPI_ROUND_UP_TO_32_bITS (temp16); - structure_size = SIZEOF_RESOURCE (acpi_resource_vendor) + + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_vendor) + (temp16 * sizeof (u8)); break; - case RESOURCE_DESC_MEMORY_32: + case ACPI_RDESC_TYPE_MEMORY_32: /* * 32-Bit Memory Range Resource */ bytes_consumed = 20; - structure_size = SIZEOF_RESOURCE (acpi_resource_mem32); + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_mem32); break; - case RESOURCE_DESC_FIXED_MEMORY_32: + case ACPI_RDESC_TYPE_FIXED_MEMORY_32: /* * 32-Bit Fixed Memory Resource */ bytes_consumed = 12; - structure_size = SIZEOF_RESOURCE (acpi_resource_fixed_mem32); + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_fixed_mem32); break; - case RESOURCE_DESC_QWORD_ADDRESS_SPACE: + case ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE: /* * 64-Bit Address Resource */ buffer = byte_stream_buffer; ++buffer; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); bytes_consumed = temp16 + 3; @@ -397,21 +396,21 @@ /* * Ensure a 64-bit boundary for the structure */ - temp8 = (u8) ROUND_UP_TO_64_bITS (temp8); + temp8 = (u8) ACPI_ROUND_UP_TO_64_bITS (temp8); - structure_size = SIZEOF_RESOURCE (acpi_resource_address64) + + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_address64) + (temp8 * sizeof (u8)); break; - case RESOURCE_DESC_DWORD_ADDRESS_SPACE: + case ACPI_RDESC_TYPE_DWORD_ADDRESS_SPACE: /* * 32-Bit Address Resource */ buffer = byte_stream_buffer; ++buffer; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); bytes_consumed = temp16 + 3; @@ -435,21 +434,21 @@ /* * Ensure a 32-bit boundary for the structure */ - temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); + temp8 = (u8) ACPI_ROUND_UP_TO_32_bITS (temp8); - structure_size = SIZEOF_RESOURCE (acpi_resource_address32) + + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_address32) + (temp8 * sizeof (u8)); break; - case RESOURCE_DESC_WORD_ADDRESS_SPACE: + case ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE: /* * 16-Bit Address Resource */ buffer = byte_stream_buffer; ++buffer; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); bytes_consumed = temp16 + 3; @@ -473,21 +472,21 @@ /* * Ensure a 32-bit boundary for the structure */ - temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); + temp8 = (u8) ACPI_ROUND_UP_TO_32_bITS (temp8); - structure_size = SIZEOF_RESOURCE (acpi_resource_address16) + + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_address16) + (temp8 * sizeof (u8)); break; - case RESOURCE_DESC_EXTENDED_XRUPT: + case ACPI_RDESC_TYPE_EXTENDED_XRUPT: /* * Extended IRQ */ buffer = byte_stream_buffer; ++buffer; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); bytes_consumed = temp16 + 3; @@ -518,7 +517,6 @@ if (9 + additional_bytes < temp16) { temp8 = (u8) (temp16 - (9 + additional_bytes)); } - else { temp8 = 0; } @@ -526,15 +524,15 @@ /* * Ensure a 32-bit boundary for the structure */ - temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); + temp8 = (u8) ACPI_ROUND_UP_TO_32_bITS (temp8); - structure_size = SIZEOF_RESOURCE (acpi_resource_ext_irq) + + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_ext_irq) + (additional_bytes * sizeof (u8)) + (temp8 * sizeof (u8)); break; - case RESOURCE_DESC_IRQ_FORMAT: + case ACPI_RDESC_TYPE_IRQ_FORMAT: /* * IRQ Resource. * Determine if it there are two or three trailing bytes @@ -545,7 +543,6 @@ if(temp8 & 0x01) { bytes_consumed = 4; } - else { bytes_consumed = 3; } @@ -558,7 +555,7 @@ /* * Look at the number of bits set */ - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); for (index = 0; index < 16; index++) { if (temp16 & 0x1) { @@ -568,12 +565,12 @@ temp16 >>= 1; } - structure_size = SIZEOF_RESOURCE (acpi_resource_io) + + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_io) + (number_of_interrupts * sizeof (u32)); break; - case RESOURCE_DESC_DMA_FORMAT: + case ACPI_RDESC_TYPE_DMA_FORMAT: /* * DMA Resource */ @@ -598,12 +595,12 @@ temp8 >>= 1; } - structure_size = SIZEOF_RESOURCE (acpi_resource_dma) + + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_dma) + (number_of_channels * sizeof (u32)); break; - case RESOURCE_DESC_START_DEPENDENT: + case ACPI_RDESC_TYPE_START_DEPENDENT: /* * Start Dependent Functions Resource * Determine if it there are two or three trailing bytes @@ -618,11 +615,11 @@ bytes_consumed = 1; } - structure_size = SIZEOF_RESOURCE (acpi_resource_start_dpf); + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_start_dpf); break; - case RESOURCE_DESC_END_DEPENDENT: + case ACPI_RDESC_TYPE_END_DEPENDENT: /* * End Dependent Functions Resource */ @@ -631,25 +628,25 @@ break; - case RESOURCE_DESC_IO_PORT: + case ACPI_RDESC_TYPE_IO_PORT: /* * IO Port Resource */ bytes_consumed = 8; - structure_size = SIZEOF_RESOURCE (acpi_resource_io); + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_io); break; - case RESOURCE_DESC_FIXED_IO_PORT: + case ACPI_RDESC_TYPE_FIXED_IO_PORT: /* * Fixed IO Port Resource */ bytes_consumed = 4; - structure_size = SIZEOF_RESOURCE (acpi_resource_fixed_io); + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_fixed_io); break; - case RESOURCE_DESC_SMALL_VENDOR: + case ACPI_RDESC_TYPE_SMALL_VENDOR: /* * Vendor Specific Resource */ @@ -662,13 +659,13 @@ /* * Ensure a 32-bit boundary for the structure */ - temp8 = (u8) ROUND_UP_TO_32_bITS (temp8); - structure_size = SIZEOF_RESOURCE (acpi_resource_vendor) + + temp8 = (u8) ACPI_ROUND_UP_TO_32_bITS (temp8); + structure_size = ACPI_SIZEOF_RESOURCE (acpi_resource_vendor) + (temp8 * sizeof (u8)); break; - case RESOURCE_DESC_END_TAG: + case ACPI_RDESC_TYPE_END_TAG: /* * End Tag */ @@ -684,14 +681,12 @@ * so exit with an error */ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); - break; } - /* * Update the return value and counter */ - buffer_size += structure_size; + buffer_size += ACPI_ALIGN_RESOURCE_SIZE(structure_size); bytes_parsed += bytes_consumed; /* @@ -700,7 +695,6 @@ byte_stream_buffer += bytes_consumed; } - /* * This is the data the caller needs */ @@ -711,7 +705,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_rs_calculate_pci_routing_table_length + * FUNCTION: Acpi_rs_get_pci_routing_table_length * * PARAMETERS: Package_object - Pointer to the package object * Buffer_size_needed - u32 pointer of the size buffer @@ -727,12 +721,12 @@ ******************************************************************************/ acpi_status -acpi_rs_calculate_pci_routing_table_length ( +acpi_rs_get_pci_routing_table_length ( acpi_operand_object *package_object, - u32 *buffer_size_needed) + ACPI_SIZE *buffer_size_needed) { u32 number_of_elements; - u32 temp_size_needed = 0; + ACPI_SIZE temp_size_needed = 0; acpi_operand_object **top_object_list; u32 index; acpi_operand_object *package_element; @@ -741,7 +735,7 @@ u32 table_index; - FUNCTION_TRACE ("Rs_calculate_pci_routing_table_length"); + ACPI_FUNCTION_TRACE ("Rs_get_pci_routing_table_length"); number_of_elements = package_object->package.count; @@ -781,7 +775,6 @@ ((*sub_object_list)->reference.opcode == AML_INT_NAMEPATH_OP))) { name_found = TRUE; } - else { /* * Look at the next element @@ -790,12 +783,12 @@ } } - temp_size_needed += (sizeof (pci_routing_table) - 4); + temp_size_needed += (sizeof (acpi_pci_routing_table) - 4); /* * Was a String type found? */ - if (TRUE == name_found) { + if (name_found) { if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) { /* * The length String.Length field includes the @@ -803,13 +796,11 @@ */ temp_size_needed += (*sub_object_list)->string.length; } - else { temp_size_needed += acpi_ns_get_pathname_length ( (*sub_object_list)->reference.node); } } - else { /* * If no name was found, then this is a NULL, which is @@ -820,7 +811,7 @@ /* Round up the size since each element must be aligned */ - temp_size_needed = ROUND_UP_TO_64_bITS (temp_size_needed); + temp_size_needed = ACPI_ROUND_UP_TO_64_bITS (temp_size_needed); /* * Point to the next acpi_operand_object @@ -828,10 +819,9 @@ top_object_list++; } - /* * Adding an extra element to the end of the list, essentially a NULL terminator */ - *buffer_size_needed = temp_size_needed + sizeof (pci_routing_table); + *buffer_size_needed = temp_size_needed + sizeof (acpi_pci_routing_table); return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/resources/rscreate.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rscreate.c --- linux-2.4.19/drivers/acpi/resources/rscreate.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rscreate.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rscreate - Create resource lists/tables - * $Revision: 36 $ + * $Revision: 56 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rscreate") + ACPI_MODULE_NAME ("rscreate") /******************************************************************************* @@ -55,17 +55,16 @@ acpi_status acpi_rs_create_resource_list ( acpi_operand_object *byte_stream_buffer, - u8 *output_buffer, - u32 *output_buffer_length) + acpi_buffer *output_buffer) { acpi_status status; u8 *byte_stream_start; - u32 list_size_needed = 0; + ACPI_SIZE list_size_needed = 0; u32 byte_stream_buffer_length; - FUNCTION_TRACE ("Rs_create_resource_list"); + ACPI_FUNCTION_TRACE ("Rs_create_resource_list"); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Byte_stream_buffer = %p\n", byte_stream_buffer)); @@ -80,48 +79,32 @@ * Pass the Byte_stream_buffer into a module that can calculate * the buffer size needed for the linked list */ - status = acpi_rs_calculate_list_length (byte_stream_start, byte_stream_buffer_length, + status = acpi_rs_get_list_length (byte_stream_start, byte_stream_buffer_length, &list_size_needed); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status=%X List_size_needed=%X\n", - status, list_size_needed)); - - /* - * Exit with the error passed back - */ + status, (u32) list_size_needed)); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - /* - * If the linked list will fit into the available buffer - * call to fill in the list - */ - if (list_size_needed <= *output_buffer_length) { - /* - * Zero out the return buffer before proceeding - */ - MEMSET (output_buffer, 0x00, *output_buffer_length); - - status = acpi_rs_byte_stream_to_list (byte_stream_start, byte_stream_buffer_length, - &output_buffer); + /* Validate/Allocate/Clear caller buffer */ - /* - * Exit with the error passed back - */ - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Output_buffer = %p\n", output_buffer)); + status = acpi_ut_initialize_buffer (output_buffer, list_size_needed); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - else { - *output_buffer_length = list_size_needed; - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + /* Do the conversion */ + + status = acpi_rs_byte_stream_to_list (byte_stream_start, byte_stream_buffer_length, + output_buffer->pointer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - *output_buffer_length = list_size_needed; + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Output_buffer %p Length %X\n", + output_buffer->pointer, (u32) output_buffer->length)); return_ACPI_STATUS (AE_OK); } @@ -137,225 +120,203 @@ * * RETURN: Status AE_OK if okay, else a valid acpi_status code. * If the Output_buffer is too small, the error will be - * AE_BUFFER_OVERFLOW and Output_buffer_length will point + * AE_BUFFER_OVERFLOW and Output_buffer->Length will point * to the size buffer needed. * * DESCRIPTION: Takes the acpi_operand_object package and creates a * linked list of PCI interrupt descriptions * + * NOTE: It is the caller's responsibility to ensure that the start of the + * output buffer is aligned properly (if necessary). + * ******************************************************************************/ acpi_status acpi_rs_create_pci_routing_table ( acpi_operand_object *package_object, - u8 *output_buffer, - u32 *output_buffer_length) + acpi_buffer *output_buffer) { - u8 *buffer = output_buffer; + u8 *buffer; acpi_operand_object **top_object_list = NULL; acpi_operand_object **sub_object_list = NULL; acpi_operand_object *package_element = NULL; - u32 buffer_size_needed = 0; + ACPI_SIZE buffer_size_needed = 0; u32 number_of_elements = 0; u32 index = 0; - pci_routing_table *user_prt = NULL; + acpi_pci_routing_table *user_prt = NULL; acpi_namespace_node *node; acpi_status status; + acpi_buffer path_buffer; - FUNCTION_TRACE ("Rs_create_pci_routing_table"); + ACPI_FUNCTION_TRACE ("Rs_create_pci_routing_table"); + /* Params already validated, so we don't re-validate here */ + /* - * Params already validated, so we don't re-validate here + * Get the required buffer length */ - status = acpi_rs_calculate_pci_routing_table_length (package_object, + status = acpi_rs_get_pci_routing_table_length (package_object, &buffer_size_needed); - - if (!ACPI_SUCCESS(status)) { + if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Buffer_size_needed = %X\n", buffer_size_needed)); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Buffer_size_needed = %X\n", (u32) buffer_size_needed)); + + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (output_buffer, buffer_size_needed); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* - * If the data will fit into the available buffer - * call to fill in the list + * Loop through the ACPI_INTERNAL_OBJECTS - Each object should contain an + * acpi_integer Address, a u8 Pin, a Name and a u8 Source_index. */ - if (buffer_size_needed <= *output_buffer_length) { + top_object_list = package_object->package.elements; + number_of_elements = package_object->package.count; + buffer = output_buffer->pointer; + user_prt = ACPI_CAST_PTR (acpi_pci_routing_table, buffer); + + for (index = 0; index < number_of_elements; index++) { /* - * Zero out the return buffer before proceeding + * Point User_prt past this current structure + * + * NOTE: On the first iteration, User_prt->Length will + * be zero because we cleared the return buffer earlier */ - MEMSET (output_buffer, 0x00, *output_buffer_length); + buffer += user_prt->length; + user_prt = ACPI_CAST_PTR (acpi_pci_routing_table, buffer); /* - * Loop through the ACPI_INTERNAL_OBJECTS - Each object should - * contain a u32 Address, a u8 Pin, a Name and a u8 - * Source_index. + * Fill in the Length field with the information we have at this point. + * The minus four is to subtract the size of the u8 Source[4] member + * because it is added below. */ - top_object_list = package_object->package.elements; - number_of_elements = package_object->package.count; - user_prt = (pci_routing_table *) buffer; - - - buffer = ROUND_PTR_UP_TO_8 (buffer, u8); - - for (index = 0; index < number_of_elements; index++) { - /* - * Point User_prt past this current structure - * - * NOTE: On the first iteration, User_prt->Length will - * be zero because we cleared the return buffer earlier - */ - buffer += user_prt->length; - user_prt = (pci_routing_table *) buffer; + user_prt->length = (sizeof (acpi_pci_routing_table) -4); + /* + * Dereference the sub-package + */ + package_element = *top_object_list; - /* - * Fill in the Length field with the information we - * have at this point. - * The minus four is to subtract the size of the - * u8 Source[4] member because it is added below. - */ - user_prt->length = (sizeof (pci_routing_table) -4); - - /* - * Dereference the sub-package - */ - package_element = *top_object_list; + /* + * The Sub_object_list will now point to an array of the four IRQ + * elements: Address, Pin, Source and Source_index + */ + sub_object_list = package_element->package.elements; - /* - * The Sub_object_list will now point to an array of - * the four IRQ elements: Address, Pin, Source and - * Source_index - */ - sub_object_list = package_element->package.elements; + /* + * 1) First subobject: Dereference the Address + */ + if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { + user_prt->address = (*sub_object_list)->integer.value; + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", + acpi_ut_get_type_name ((*sub_object_list)->common.type))); + return_ACPI_STATUS (AE_BAD_DATA); + } - /* - * 1) First subobject: Dereference the Address - */ - if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { - user_prt->address = (*sub_object_list)->integer.value; - } + /* + * 2) Second subobject: Dereference the Pin + */ + sub_object_list++; - else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", - acpi_ut_get_type_name ((*sub_object_list)->common.type))); - return_ACPI_STATUS (AE_BAD_DATA); - } + if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { + user_prt->pin = (u32) (*sub_object_list)->integer.value; + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", + acpi_ut_get_type_name ((*sub_object_list)->common.type))); + return_ACPI_STATUS (AE_BAD_DATA); + } - /* - * 2) Second subobject: Dereference the Pin - */ - sub_object_list++; + /* + * 3) Third subobject: Dereference the Source Name + */ + sub_object_list++; - if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { - user_prt->pin = (u32) (*sub_object_list)->integer.value; - } + switch ((*sub_object_list)->common.type) { + case INTERNAL_TYPE_REFERENCE: - else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", - acpi_ut_get_type_name ((*sub_object_list)->common.type))); + if ((*sub_object_list)->reference.opcode != AML_INT_NAMEPATH_OP) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need name, found reference op %X\n", + (*sub_object_list)->reference.opcode)); return_ACPI_STATUS (AE_BAD_DATA); } - /* - * 3) Third subobject: Dereference the Source Name - */ - sub_object_list++; - - switch ((*sub_object_list)->common.type) { - case INTERNAL_TYPE_REFERENCE: + node = (*sub_object_list)->reference.node; - if ((*sub_object_list)->reference.opcode != AML_INT_NAMEPATH_OP) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need name, found reference op %X\n", - (*sub_object_list)->reference.opcode)); - return_ACPI_STATUS (AE_BAD_DATA); - } + /* Use *remaining* length of the buffer as max for pathname */ - node = (*sub_object_list)->reference.node; + path_buffer.length = output_buffer->length - + (u32) ((u8 *) user_prt->source - (u8 *) output_buffer->pointer); + path_buffer.pointer = user_prt->source; - /* TBD: use *remaining* length of the buffer! */ + status = acpi_ns_handle_to_pathname ((acpi_handle) node, &path_buffer); - status = acpi_ns_handle_to_pathname ((acpi_handle *) node, - output_buffer_length, user_prt->source); + user_prt->length += ACPI_STRLEN (user_prt->source) + 1; /* include null terminator */ + break; - user_prt->length += STRLEN (user_prt->source) + 1; /* include null terminator */ - break; + case ACPI_TYPE_STRING: - case ACPI_TYPE_STRING: + ACPI_STRCPY (user_prt->source, + (*sub_object_list)->string.pointer); - STRCPY (user_prt->source, - (*sub_object_list)->string.pointer); + /* Add to the Length field the length of the string */ - /* - * Add to the Length field the length of the string - */ - user_prt->length += (*sub_object_list)->string.length; - break; + user_prt->length += (*sub_object_list)->string.length; + break; - case ACPI_TYPE_INTEGER: - /* - * If this is a number, then the Source Name - * is NULL, since the entire buffer was zeroed - * out, we can leave this alone. - */ - /* - * Add to the Length field the length of - * the u32 NULL - */ - user_prt->length += sizeof (u32); - break; + case ACPI_TYPE_INTEGER: + /* + * If this is a number, then the Source Name is NULL, since the + * entire buffer was zeroed out, we can leave this alone. + * + * Add to the Length field the length of the u32 NULL + */ + user_prt->length += sizeof (u32); + break; - default: + default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", - acpi_ut_get_type_name ((*sub_object_list)->common.type))); - return_ACPI_STATUS (AE_BAD_DATA); - break; - } + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", + acpi_ut_get_type_name ((*sub_object_list)->common.type))); + return_ACPI_STATUS (AE_BAD_DATA); + } - /* Now align the current length */ + /* Now align the current length */ - user_prt->length = ROUND_UP_TO_64_bITS (user_prt->length); + user_prt->length = ACPI_ROUND_UP_TO_64_bITS (user_prt->length); - /* - * 4) Fourth subobject: Dereference the Source Index - */ - sub_object_list++; - - if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { - user_prt->source_index = (u32) (*sub_object_list)->integer.value; - } - - else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", - acpi_ut_get_type_name ((*sub_object_list)->common.type))); - return_ACPI_STATUS (AE_BAD_DATA); - } + /* + * 4) Fourth subobject: Dereference the Source Index + */ + sub_object_list++; - /* - * Point to the next acpi_operand_object - */ - top_object_list++; + if (ACPI_TYPE_INTEGER == (*sub_object_list)->common.type) { + user_prt->source_index = (u32) (*sub_object_list)->integer.value; + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need Integer, found %s\n", + acpi_ut_get_type_name ((*sub_object_list)->common.type))); + return_ACPI_STATUS (AE_BAD_DATA); } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Output_buffer = %p\n", output_buffer)); - } - - else { - *output_buffer_length = buffer_size_needed; + /* Point to the next acpi_operand_object */ - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + top_object_list++; } - /* - * Report the amount of buffer used - */ - *output_buffer_length = buffer_size_needed; + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Output_buffer %p Length %X\n", + output_buffer->pointer, (u32) output_buffer->length)); return_ACPI_STATUS (AE_OK); } @@ -366,11 +327,10 @@ * * PARAMETERS: Linked_list_buffer - Pointer to the resource linked list * Output_buffer - Pointer to the user's buffer - * Output_buffer_length - Size of Output_buffer * * RETURN: Status AE_OK if okay, else a valid acpi_status code. * If the Output_buffer is too small, the error will be - * AE_BUFFER_OVERFLOW and Output_buffer_length will point + * AE_BUFFER_OVERFLOW and Output_buffer->Length will point * to the size buffer needed. * * DESCRIPTION: Takes the linked list of device resources and @@ -382,14 +342,13 @@ acpi_status acpi_rs_create_byte_stream ( acpi_resource *linked_list_buffer, - u8 *output_buffer, - u32 *output_buffer_length) + acpi_buffer *output_buffer) { acpi_status status; - u32 byte_stream_size_needed = 0; + ACPI_SIZE byte_stream_size_needed = 0; - FUNCTION_TRACE ("Rs_create_byte_stream"); + ACPI_FUNCTION_TRACE ("Rs_create_byte_stream"); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Linked_list_buffer = %p\n", linked_list_buffer)); @@ -397,50 +356,35 @@ /* * Params already validated, so we don't re-validate here * - * Pass the Linked_list_buffer into a module that can calculate + * Pass the Linked_list_buffer into a module that calculates * the buffer size needed for the byte stream. */ - status = acpi_rs_calculate_byte_stream_length (linked_list_buffer, + status = acpi_rs_get_byte_stream_length (linked_list_buffer, &byte_stream_size_needed); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Byte_stream_size_needed=%X, %s\n", - byte_stream_size_needed, acpi_format_exception (status))); - - /* - * Exit with the error passed back - */ + (u32) byte_stream_size_needed, acpi_format_exception (status))); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - /* - * If the linked list will fit into the available buffer - * call to fill in the list - */ - if (byte_stream_size_needed <= *output_buffer_length) { - /* - * Zero out the return buffer before proceeding - */ - MEMSET (output_buffer, 0x00, *output_buffer_length); - - status = acpi_rs_list_to_byte_stream (linked_list_buffer, byte_stream_size_needed, - &output_buffer); + /* Validate/Allocate/Clear caller buffer */ - /* - * Exit with the error passed back - */ - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Output_buffer = %p\n", output_buffer)); + status = acpi_ut_initialize_buffer (output_buffer, byte_stream_size_needed); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - else { - *output_buffer_length = byte_stream_size_needed; - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + /* Do the conversion */ + + status = acpi_rs_list_to_byte_stream (linked_list_buffer, byte_stream_size_needed, + output_buffer->pointer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Output_buffer %p Length %X\n", + output_buffer->pointer, (u32) output_buffer->length)); return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/resources/rsdump.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsdump.c --- linux-2.4.19/drivers/acpi/resources/rsdump.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsdump.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsdump - Functions to display the resource structures. - * $Revision: 23 $ + * $Revision: 32 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,10 +28,10 @@ #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsdump") + ACPI_MODULE_NAME ("rsdump") -#ifdef ACPI_DEBUG +#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) /******************************************************************************* * @@ -53,19 +53,19 @@ u8 index = 0; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("IRQ Resource\n"); acpi_os_printf (" %s Triggered\n", - LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge"); + ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge"); acpi_os_printf (" Active %s\n", - ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High"); + ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High"); acpi_os_printf (" %s\n", - SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive"); + ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive"); acpi_os_printf (" %X Interrupts ( ", irq_data->number_of_interrupts); @@ -98,25 +98,25 @@ u8 index = 0; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("DMA Resource\n"); switch (dma_data->type) { - case COMPATIBILITY: + case ACPI_COMPATIBILITY: acpi_os_printf (" Compatibility mode\n"); break; - case TYPE_A: + case ACPI_TYPE_A: acpi_os_printf (" Type A\n"); break; - case TYPE_B: + case ACPI_TYPE_B: acpi_os_printf (" Type B\n"); break; - case TYPE_F: + case ACPI_TYPE_F: acpi_os_printf (" Type F\n"); break; @@ -126,19 +126,19 @@ } acpi_os_printf (" %sBus Master\n", - BUS_MASTER == dma_data->bus_master ? "" : "Not a "); + ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a "); switch (dma_data->transfer) { - case TRANSFER_8: + case ACPI_TRANSFER_8: acpi_os_printf (" 8-bit only transfer\n"); break; - case TRANSFER_8_16: + case ACPI_TRANSFER_8_16: acpi_os_printf (" 8 and 16-bit transfer\n"); break; - case TRANSFER_16: + case ACPI_TRANSFER_16: acpi_os_printf (" 16 bit only transfer\n"); break; @@ -160,7 +160,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_rs_dump_start_dependent_functions + * FUNCTION: Acpi_rs_dump_start_depend_fns * * PARAMETERS: Data - pointer to the resource structure to dump. * @@ -171,27 +171,27 @@ ******************************************************************************/ void -acpi_rs_dump_start_dependent_functions ( - acpi_resource_data *data) +acpi_rs_dump_start_depend_fns ( + acpi_resource_data *data) { - acpi_resource_start_dpf *sdf_data = (acpi_resource_start_dpf *) data; + acpi_resource_start_dpf *sdf_data = (acpi_resource_start_dpf *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("Start Dependent Functions Resource\n"); switch (sdf_data->compatibility_priority) { - case GOOD_CONFIGURATION: + case ACPI_GOOD_CONFIGURATION: acpi_os_printf (" Good configuration\n"); break; - case ACCEPTABLE_CONFIGURATION: + case ACPI_ACCEPTABLE_CONFIGURATION: acpi_os_printf (" Acceptable configuration\n"); break; - case SUB_OPTIMAL_CONFIGURATION: + case ACPI_SUB_OPTIMAL_CONFIGURATION: acpi_os_printf (" Sub-optimal configuration\n"); break; @@ -201,15 +201,15 @@ } switch(sdf_data->performance_robustness) { - case GOOD_CONFIGURATION: + case ACPI_GOOD_CONFIGURATION: acpi_os_printf (" Good configuration\n"); break; - case ACCEPTABLE_CONFIGURATION: + case ACPI_ACCEPTABLE_CONFIGURATION: acpi_os_printf (" Acceptable configuration\n"); break; - case SUB_OPTIMAL_CONFIGURATION: + case ACPI_SUB_OPTIMAL_CONFIGURATION: acpi_os_printf (" Sub-optimal configuration\n"); break; @@ -242,13 +242,13 @@ acpi_resource_io *io_data = (acpi_resource_io *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("Io Resource\n"); acpi_os_printf (" %d bit decode\n", - DECODE_16 == io_data->io_decode ? 16 : 10); + ACPI_DECODE_16 == io_data->io_decode ? 16 : 10); acpi_os_printf (" Range minimum base: %08X\n", io_data->min_base_address); @@ -285,7 +285,7 @@ acpi_resource_fixed_io *fixed_io_data = (acpi_resource_fixed_io *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("Fixed Io Resource\n"); @@ -319,7 +319,7 @@ u16 index = 0; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("Vendor Specific Resource\n"); @@ -354,13 +354,13 @@ acpi_resource_mem24 *memory24_data = (acpi_resource_mem24 *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("24-Bit Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - READ_WRITE_MEMORY == + ACPI_READ_WRITE_MEMORY == memory24_data->read_write_attribute ? "/Write" : " only"); @@ -399,13 +399,13 @@ acpi_resource_mem32 *memory32_data = (acpi_resource_mem32 *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("32-Bit Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - READ_WRITE_MEMORY == + ACPI_READ_WRITE_MEMORY == memory32_data->read_write_attribute ? "/Write" : " only"); @@ -444,13 +444,13 @@ acpi_resource_fixed_mem32 *fixed_memory32_data = (acpi_resource_fixed_mem32 *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("32-Bit Fixed Location Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - READ_WRITE_MEMORY == + ACPI_READ_WRITE_MEMORY == fixed_memory32_data->read_write_attribute ? "/Write" : " Only"); @@ -483,34 +483,34 @@ acpi_resource_address16 *address16_data = (acpi_resource_address16 *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("16-Bit Address Space Resource\n"); acpi_os_printf (" Resource Type: "); switch (address16_data->resource_type) { - case MEMORY_RANGE: + case ACPI_MEMORY_RANGE: acpi_os_printf ("Memory Range\n"); switch (address16_data->attribute.memory.cache_attribute) { - case NON_CACHEABLE_MEMORY: + case ACPI_NON_CACHEABLE_MEMORY: acpi_os_printf (" Type Specific: " "Noncacheable memory\n"); break; - case CACHABLE_MEMORY: + case ACPI_CACHABLE_MEMORY: acpi_os_printf (" Type Specific: " "Cacheable memory\n"); break; - case WRITE_COMBINING_MEMORY: + case ACPI_WRITE_COMBINING_MEMORY: acpi_os_printf (" Type Specific: " "Write-combining memory\n"); break; - case PREFETCHABLE_MEMORY: + case ACPI_PREFETCHABLE_MEMORY: acpi_os_printf (" Type Specific: " "Prefetchable memory\n"); break; @@ -522,27 +522,27 @@ } acpi_os_printf (" Type Specific: Read%s\n", - READ_WRITE_MEMORY == + ACPI_READ_WRITE_MEMORY == address16_data->attribute.memory.read_write_attribute ? "/Write" : " Only"); break; - case IO_RANGE: + case ACPI_IO_RANGE: acpi_os_printf ("I/O Range\n"); switch (address16_data->attribute.io.range_attribute) { - case NON_ISA_ONLY_RANGES: + case ACPI_NON_ISA_ONLY_RANGES: acpi_os_printf (" Type Specific: " "Non-ISA Io Addresses\n"); break; - case ISA_ONLY_RANGES: + case ACPI_ISA_ONLY_RANGES: acpi_os_printf (" Type Specific: " "ISA Io Addresses\n"); break; - case ENTIRE_RANGE: + case ACPI_ENTIRE_RANGE: acpi_os_printf (" Type Specific: " "ISA and non-ISA Io Addresses\n"); break; @@ -554,7 +554,7 @@ } break; - case BUS_NUMBER_RANGE: + case ACPI_BUS_NUMBER_RANGE: acpi_os_printf ("Bus Number Range\n"); break; @@ -566,19 +566,19 @@ } acpi_os_printf (" Resource %s\n", - CONSUMER == address16_data->producer_consumer ? + ACPI_CONSUMER == address16_data->producer_consumer ? "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - SUB_DECODE == address16_data->decode ? + ACPI_SUB_DECODE == address16_data->decode ? "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ADDRESS_FIXED == address16_data->min_address_fixed ? + ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ? "" : "not"); acpi_os_printf (" Max address is %s fixed\n", - ADDRESS_FIXED == address16_data->max_address_fixed ? + ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ? "" : "not"); acpi_os_printf (" Granularity: %08X\n", @@ -626,33 +626,33 @@ acpi_resource_address32 *address32_data = (acpi_resource_address32 *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("32-Bit Address Space Resource\n"); switch (address32_data->resource_type) { - case MEMORY_RANGE: + case ACPI_MEMORY_RANGE: acpi_os_printf (" Resource Type: Memory Range\n"); switch (address32_data->attribute.memory.cache_attribute) { - case NON_CACHEABLE_MEMORY: + case ACPI_NON_CACHEABLE_MEMORY: acpi_os_printf (" Type Specific: " "Noncacheable memory\n"); break; - case CACHABLE_MEMORY: + case ACPI_CACHABLE_MEMORY: acpi_os_printf (" Type Specific: " "Cacheable memory\n"); break; - case WRITE_COMBINING_MEMORY: + case ACPI_WRITE_COMBINING_MEMORY: acpi_os_printf (" Type Specific: " "Write-combining memory\n"); break; - case PREFETCHABLE_MEMORY: + case ACPI_PREFETCHABLE_MEMORY: acpi_os_printf (" Type Specific: " "Prefetchable memory\n"); break; @@ -664,27 +664,27 @@ } acpi_os_printf (" Type Specific: Read%s\n", - READ_WRITE_MEMORY == + ACPI_READ_WRITE_MEMORY == address32_data->attribute.memory.read_write_attribute ? "/Write" : " Only"); break; - case IO_RANGE: + case ACPI_IO_RANGE: acpi_os_printf (" Resource Type: Io Range\n"); switch (address32_data->attribute.io.range_attribute) { - case NON_ISA_ONLY_RANGES: + case ACPI_NON_ISA_ONLY_RANGES: acpi_os_printf (" Type Specific: " "Non-ISA Io Addresses\n"); break; - case ISA_ONLY_RANGES: + case ACPI_ISA_ONLY_RANGES: acpi_os_printf (" Type Specific: " "ISA Io Addresses\n"); break; - case ENTIRE_RANGE: + case ACPI_ENTIRE_RANGE: acpi_os_printf (" Type Specific: " "ISA and non-ISA Io Addresses\n"); break; @@ -696,7 +696,7 @@ } break; - case BUS_NUMBER_RANGE: + case ACPI_BUS_NUMBER_RANGE: acpi_os_printf (" Resource Type: Bus Number Range\n"); break; @@ -708,19 +708,19 @@ } acpi_os_printf (" Resource %s\n", - CONSUMER == address32_data->producer_consumer ? + ACPI_CONSUMER == address32_data->producer_consumer ? "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - SUB_DECODE == address32_data->decode ? + ACPI_SUB_DECODE == address32_data->decode ? "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ADDRESS_FIXED == address32_data->min_address_fixed ? + ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ? "" : "not "); acpi_os_printf (" Max address is %s fixed\n", - ADDRESS_FIXED == address32_data->max_address_fixed ? + ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ? "" : "not "); acpi_os_printf (" Granularity: %08X\n", @@ -768,33 +768,33 @@ acpi_resource_address64 *address64_data = (acpi_resource_address64 *) data; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("64-Bit Address Space Resource\n"); switch (address64_data->resource_type) { - case MEMORY_RANGE: + case ACPI_MEMORY_RANGE: acpi_os_printf (" Resource Type: Memory Range\n"); switch (address64_data->attribute.memory.cache_attribute) { - case NON_CACHEABLE_MEMORY: + case ACPI_NON_CACHEABLE_MEMORY: acpi_os_printf (" Type Specific: " "Noncacheable memory\n"); break; - case CACHABLE_MEMORY: + case ACPI_CACHABLE_MEMORY: acpi_os_printf (" Type Specific: " "Cacheable memory\n"); break; - case WRITE_COMBINING_MEMORY: + case ACPI_WRITE_COMBINING_MEMORY: acpi_os_printf (" Type Specific: " "Write-combining memory\n"); break; - case PREFETCHABLE_MEMORY: + case ACPI_PREFETCHABLE_MEMORY: acpi_os_printf (" Type Specific: " "Prefetchable memory\n"); break; @@ -806,27 +806,27 @@ } acpi_os_printf (" Type Specific: Read%s\n", - READ_WRITE_MEMORY == + ACPI_READ_WRITE_MEMORY == address64_data->attribute.memory.read_write_attribute ? "/Write" : " Only"); break; - case IO_RANGE: + case ACPI_IO_RANGE: acpi_os_printf (" Resource Type: Io Range\n"); switch (address64_data->attribute.io.range_attribute) { - case NON_ISA_ONLY_RANGES: + case ACPI_NON_ISA_ONLY_RANGES: acpi_os_printf (" Type Specific: " "Non-ISA Io Addresses\n"); break; - case ISA_ONLY_RANGES: + case ACPI_ISA_ONLY_RANGES: acpi_os_printf (" Type Specific: " "ISA Io Addresses\n"); break; - case ENTIRE_RANGE: + case ACPI_ENTIRE_RANGE: acpi_os_printf (" Type Specific: " "ISA and non-ISA Io Addresses\n"); break; @@ -838,7 +838,7 @@ } break; - case BUS_NUMBER_RANGE: + case ACPI_BUS_NUMBER_RANGE: acpi_os_printf (" Resource Type: Bus Number Range\n"); break; @@ -850,19 +850,19 @@ } acpi_os_printf (" Resource %s\n", - CONSUMER == address64_data->producer_consumer ? + ACPI_CONSUMER == address64_data->producer_consumer ? "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - SUB_DECODE == address64_data->decode ? + ACPI_SUB_DECODE == address64_data->decode ? "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ADDRESS_FIXED == address64_data->min_address_fixed ? + ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ? "" : "not "); acpi_os_printf (" Max address is %s fixed\n", - ADDRESS_FIXED == address64_data->max_address_fixed ? + ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ? "" : "not "); acpi_os_printf (" Granularity: %16X\n", @@ -911,25 +911,25 @@ u8 index = 0; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); acpi_os_printf ("Extended IRQ Resource\n"); acpi_os_printf (" Resource %s\n", - CONSUMER == ext_irq_data->producer_consumer ? + ACPI_CONSUMER == ext_irq_data->producer_consumer ? "Consumer" : "Producer"); acpi_os_printf (" %s\n", - LEVEL_SENSITIVE == ext_irq_data->edge_level ? + ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ? "Level" : "Edge"); acpi_os_printf (" Active %s\n", - ACTIVE_LOW == ext_irq_data->active_high_low ? + ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ? "low" : "high"); acpi_os_printf (" %s\n", - SHARED == ext_irq_data->shared_exclusive ? + ACPI_SHARED == ext_irq_data->shared_exclusive ? "Shared" : "Exclusive"); acpi_os_printf (" Interrupts : %X ( ", @@ -972,12 +972,12 @@ u8 done = FALSE; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (acpi_dbg_level & ACPI_LV_RESOURCES && _COMPONENT & acpi_dbg_layer) { while (!done) { - acpi_os_printf ("Resource structure %x.\n", count++); + acpi_os_printf ("Resource structure %X.\n", count++); switch (resource->id) { case ACPI_RSTYPE_IRQ: @@ -989,7 +989,7 @@ break; case ACPI_RSTYPE_START_DPF: - acpi_rs_dump_start_dependent_functions (&resource->data); + acpi_rs_dump_start_depend_fns (&resource->data); break; case ACPI_RSTYPE_END_DPF: @@ -1049,7 +1049,7 @@ } - resource = POINTER_ADD (acpi_resource, resource, resource->length); + resource = ACPI_PTR_ADD (acpi_resource, resource, resource->length); } } @@ -1070,25 +1070,26 @@ void acpi_rs_dump_irq_list ( - u8 *route_table) + u8 *route_table) { - u8 *buffer = route_table; - u8 count = 0; - u8 done = FALSE; - pci_routing_table *prt_element; + u8 *buffer = route_table; + u8 count = 0; + u8 done = FALSE; + acpi_pci_routing_table *prt_element; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (acpi_dbg_level & ACPI_LV_RESOURCES && _COMPONENT & acpi_dbg_layer) { - prt_element = (pci_routing_table *) buffer; + prt_element = ACPI_CAST_PTR (acpi_pci_routing_table, buffer); while (!done) { acpi_os_printf ("PCI IRQ Routing Table structure %X.\n", count++); - acpi_os_printf (" Address: %X\n", - prt_element->address); + acpi_os_printf (" Address: %8.8X%8.8X\n", + ACPI_HIDWORD (prt_element->address), + ACPI_LODWORD (prt_element->address)); acpi_os_printf (" Pin: %X\n", prt_element->pin); @@ -1099,7 +1100,7 @@ buffer += prt_element->length; - prt_element = (pci_routing_table *) buffer; + prt_element = ACPI_CAST_PTR (acpi_pci_routing_table, buffer); if(0 == prt_element->length) { done = TRUE; diff -Nur linux-2.4.19/drivers/acpi/resources/rsio.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsio.c --- linux-2.4.19/drivers/acpi/resources/rsio.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsio.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsio - IO and DMA resource descriptors - * $Revision: 14 $ + * $Revision: 20 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsio") + ACPI_MODULE_NAME ("rsio") /******************************************************************************* @@ -37,13 +37,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -56,18 +55,18 @@ acpi_status acpi_rs_io_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_io); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_io); - FUNCTION_TRACE ("Rs_io_resource"); + ACPI_FUNCTION_TRACE ("Rs_io_resource"); /* @@ -89,7 +88,7 @@ * Check Min_base Address */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.io.min_base_address = temp16; @@ -97,7 +96,7 @@ * Check Max_base Address */ buffer += 2; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.io.max_base_address = temp16; @@ -120,7 +119,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -136,13 +135,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -155,18 +153,18 @@ acpi_status acpi_rs_fixed_io_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_fixed_io); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_fixed_io); - FUNCTION_TRACE ("Rs_fixed_io_resource"); + ACPI_FUNCTION_TRACE ("Rs_fixed_io_resource"); /* @@ -180,7 +178,7 @@ * Check Range Base Address */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.fixed_io.base_address = temp16; @@ -195,7 +193,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -211,9 +209,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -226,14 +223,14 @@ acpi_rs_io_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - FUNCTION_TRACE ("Rs_io_stream"); + ACPI_FUNCTION_TRACE ("Rs_io_stream"); /* @@ -255,7 +252,7 @@ */ temp16 = (u16) linked_list->data.io.min_base_address; - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; /* @@ -263,7 +260,7 @@ */ temp16 = (u16) linked_list->data.io.max_base_address; - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; /* @@ -285,7 +282,7 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -296,9 +293,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -311,14 +307,14 @@ acpi_rs_fixed_io_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - FUNCTION_TRACE ("Rs_fixed_io_stream"); + ACPI_FUNCTION_TRACE ("Rs_fixed_io_stream"); /* @@ -333,7 +329,7 @@ */ temp16 = (u16) linked_list->data.fixed_io.base_address; - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; /* @@ -347,7 +343,7 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -358,13 +354,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -377,19 +372,19 @@ acpi_status acpi_rs_dma_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u8 temp8 = 0; u8 index; u8 i; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_dma); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_dma); - FUNCTION_TRACE ("Rs_dma_resource"); + ACPI_FUNCTION_TRACE ("Rs_dma_resource"); /* @@ -412,13 +407,18 @@ i++; } } + if (i == 0) { + /* Zero channels is invalid! */ + + return_ACPI_STATUS (AE_BAD_DATA); + } output_struct->data.dma.number_of_channels = i; /* * Calculate the structure size based upon the number of interrupts */ - struct_size += (output_struct->data.dma.number_of_channels - 1) * 4; + struct_size += ((ACPI_SIZE) output_struct->data.dma.number_of_channels - 1) * 4; /* * Point to Byte 2 @@ -448,7 +448,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -464,9 +464,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -479,7 +478,7 @@ acpi_rs_dma_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; @@ -487,7 +486,7 @@ u8 index; - FUNCTION_TRACE ("Rs_dma_stream"); + ACPI_FUNCTION_TRACE ("Rs_dma_stream"); /* @@ -523,7 +522,7 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/resources/rsirq.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsirq.c --- linux-2.4.19/drivers/acpi/resources/rsirq.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsirq.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsirq - IRQ resource descriptors - * $Revision: 18 $ + * $Revision: 28 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsirq") + ACPI_MODULE_NAME ("rsirq") /******************************************************************************* @@ -37,13 +37,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -56,20 +55,20 @@ acpi_status acpi_rs_irq_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; u8 index; u8 i; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_irq); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_irq); - FUNCTION_TRACE ("Rs_irq_resource"); + ACPI_FUNCTION_TRACE ("Rs_irq_resource"); /* @@ -84,24 +83,30 @@ * Point to the 16-bits of Bytes 1 and 2 */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.irq.number_of_interrupts = 0; /* Decode the IRQ bits */ for (i = 0, index = 0; index < 16; index++) { - if((temp16 >> index) & 0x01) { + if ((temp16 >> index) & 0x01) { output_struct->data.irq.interrupts[i] = index; i++; } } + + if (i == 0) { + /* Zero interrupts is invalid! */ + + return_ACPI_STATUS (AE_BAD_DATA); + } output_struct->data.irq.number_of_interrupts = i; /* * Calculate the structure size based upon the number of interrupts */ - struct_size += (output_struct->data.irq.number_of_interrupts - 1) * 4; + struct_size += ((ACPI_SIZE) output_struct->data.irq.number_of_interrupts - 1) * 4; /* * Point to Byte 3 if it is used @@ -114,16 +119,14 @@ * Check for HE, LL or HL */ if (temp8 & 0x01) { - output_struct->data.irq.edge_level = EDGE_SENSITIVE; - output_struct->data.irq.active_high_low = ACTIVE_HIGH; + output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE; + output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH; } - else { if (temp8 & 0x8) { - output_struct->data.irq.edge_level = LEVEL_SENSITIVE; - output_struct->data.irq.active_high_low = ACTIVE_LOW; + output_struct->data.irq.edge_level = ACPI_LEVEL_SENSITIVE; + output_struct->data.irq.active_high_low = ACPI_ACTIVE_LOW; } - else { /* * Only _LL and _HE polarity/trigger interrupts @@ -139,21 +142,20 @@ */ output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01; } - else { /* * Assume Edge Sensitive, Active High, Non-Sharable * per ACPI Specification */ - output_struct->data.irq.edge_level = EDGE_SENSITIVE; - output_struct->data.irq.active_high_low = ACTIVE_HIGH; - output_struct->data.irq.shared_exclusive = EXCLUSIVE; + output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE; + output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH; + output_struct->data.irq.shared_exclusive = ACPI_EXCLUSIVE; } /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -169,9 +171,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -184,7 +185,7 @@ acpi_rs_irq_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; @@ -193,20 +194,19 @@ u8 IRQinfo_byte_needed; - FUNCTION_TRACE ("Rs_irq_stream"); + ACPI_FUNCTION_TRACE ("Rs_irq_stream"); /* * The descriptor field is set based upon whether a third byte is * needed to contain the IRQ Information. */ - if (EDGE_SENSITIVE == linked_list->data.irq.edge_level && - ACTIVE_HIGH == linked_list->data.irq.active_high_low && - EXCLUSIVE == linked_list->data.irq.shared_exclusive) { + if (ACPI_EDGE_SENSITIVE == linked_list->data.irq.edge_level && + ACPI_ACTIVE_HIGH == linked_list->data.irq.active_high_low && + ACPI_EXCLUSIVE == linked_list->data.irq.shared_exclusive) { *buffer = 0x22; IRQinfo_byte_needed = FALSE; } - else { *buffer = 0x23; IRQinfo_byte_needed = TRUE; @@ -225,7 +225,7 @@ temp16 |= 0x1 << temp8; } - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; /* @@ -236,11 +236,10 @@ temp8 = (u8) ((linked_list->data.irq.shared_exclusive & 0x01) << 4); - if (LEVEL_SENSITIVE == linked_list->data.irq.edge_level && - ACTIVE_LOW == linked_list->data.irq.active_high_low) { + if (ACPI_LEVEL_SENSITIVE == linked_list->data.irq.edge_level && + ACPI_ACTIVE_LOW == linked_list->data.irq.active_high_low) { temp8 |= 0x08; } - else { temp8 |= 0x01; } @@ -252,7 +251,7 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -263,13 +262,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -282,27 +280,27 @@ acpi_status acpi_rs_extended_irq_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - NATIVE_CHAR *temp_ptr; + u8 *temp_ptr; u8 index; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_ext_irq); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_ext_irq); - FUNCTION_TRACE ("Rs_extended_irq_resource"); + ACPI_FUNCTION_TRACE ("Rs_extended_irq_resource"); /* * Point past the Descriptor to get the number of bytes consumed */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_EXT_IRQ; @@ -316,28 +314,20 @@ output_struct->data.extended_irq.producer_consumer = temp8 & 0x01; /* - * Check for HE, LL or HL + * Check for Interrupt Mode + * + * The definition of an Extended IRQ changed between ACPI spec v1.0b + * and ACPI spec 2.0 (section 6.4.3.6 in both). + * + * - Edge/Level are defined opposite in the table vs the headers */ - if(temp8 & 0x02) { - output_struct->data.extended_irq.edge_level = EDGE_SENSITIVE; - output_struct->data.extended_irq.active_high_low = ACTIVE_HIGH; - } - - else { - if(temp8 & 0x4) { - output_struct->data.extended_irq.edge_level = LEVEL_SENSITIVE; - output_struct->data.extended_irq.active_high_low = ACTIVE_LOW; - } + output_struct->data.extended_irq.edge_level = + (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; - else { - /* - * Only _LL and _HE polarity/trigger interrupts - * are allowed (ACPI spec v1.0b ection 6.4.2.1), - * so an error will occur if we reach this point - */ - return_ACPI_STATUS (AE_BAD_DATA); - } - } + /* + * Check Interrupt Polarity + */ + output_struct->data.extended_irq.active_high_low = (temp8 >> 2) & 0x1; /* * Check for sharable @@ -367,8 +357,8 @@ * Cycle through every IRQ in the table */ for (index = 0; index < temp8; index++) { - output_struct->data.extended_irq.interrupts[index] = - (u32)*buffer; + ACPI_MOVE_UNALIGNED32_TO_32 ( + &output_struct->data.extended_irq.interrupts[index], buffer); /* Point to the next IRQ */ @@ -383,7 +373,7 @@ * stream that are default. */ if (*bytes_consumed > - (u32)(output_struct->data.extended_irq.number_of_interrupts * 4) + 5) { + ((ACPI_SIZE) output_struct->data.extended_irq.number_of_interrupts * 4) + 5) { /* Dereference the Index */ temp8 = *buffer; @@ -399,12 +389,11 @@ output_struct->data.extended_irq.resource_source.string_ptr = (NATIVE_CHAR *)(output_struct + struct_size); - temp_ptr = output_struct->data.extended_irq.resource_source.string_ptr; + temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr; /* Copy the string into the buffer */ index = 0; - while (0x00 != *buffer) { *temp_ptr = *buffer; @@ -425,9 +414,8 @@ * Struct_size to the next 32-bit boundary. */ temp8 = (u8) (index + 1); - struct_size += ROUND_UP_TO_32_bITS (temp8); + struct_size += ACPI_ROUND_UP_TO_32_bITS (temp8); } - else { output_struct->data.extended_irq.resource_source.index = 0x00; output_struct->data.extended_irq.resource_source.string_length = 0; @@ -437,7 +425,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -453,9 +441,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -468,7 +455,7 @@ acpi_rs_extended_irq_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 *length_field; @@ -477,7 +464,7 @@ NATIVE_CHAR *temp_pointer = NULL; - FUNCTION_TRACE ("Rs_extended_irq_stream"); + ACPI_FUNCTION_TRACE ("Rs_extended_irq_stream"); /* @@ -489,7 +476,7 @@ /* * Set a pointer to the Length field - to be filled in later */ - length_field = (u16 *)buffer; + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; /* @@ -498,14 +485,24 @@ temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01); temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3); - if (LEVEL_SENSITIVE == linked_list->data.extended_irq.edge_level && - ACTIVE_LOW == linked_list->data.extended_irq.active_high_low) { - temp8 |= 0x04; - } - else { - temp8 |= 0x02; + /* + * Set the Interrupt Mode + * + * The definition of an Extended IRQ changed between ACPI spec v1.0b + * and ACPI spec 2.0 (section 6.4.3.6 in both). This code does not + * implement the more restrictive definition of 1.0b + * + * - Edge/Level are defined opposite in the table vs the headers + */ + if (ACPI_EDGE_SENSITIVE == linked_list->data.extended_irq.edge_level) { + temp8 |= 0x2; } + /* + * Set the Interrupt Polarity + */ + temp8 |= ((linked_list->data.extended_irq.active_high_low & 0x1) << 2); + *buffer = temp8; buffer += 1; @@ -519,7 +516,7 @@ for (index = 0; index < linked_list->data.extended_irq.number_of_interrupts; index++) { - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.extended_irq.interrupts[index]); buffer += 4; } @@ -536,20 +533,20 @@ /* * Copy the string */ - STRCPY (temp_pointer, + ACPI_STRCPY (temp_pointer, linked_list->data.extended_irq.resource_source.string_ptr); /* * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1); + buffer += (ACPI_STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1); } /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* * Set the length field to the number of bytes consumed diff -Nur linux-2.4.19/drivers/acpi/resources/rslist.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rslist.c --- linux-2.4.19/drivers/acpi/resources/rslist.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rslist.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rslist - Linked list utilities - * $Revision: 19 $ + * $Revision: 30 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rslist") + ACPI_MODULE_NAME ("rslist") /******************************************************************************* @@ -49,28 +49,31 @@ u8 resource_start_byte) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* * Determine if this is a small or large resource */ - switch (resource_start_byte & RESOURCE_DESC_TYPE_MASK) { - case RESOURCE_DESC_TYPE_SMALL: + switch (resource_start_byte & ACPI_RDESC_TYPE_MASK) { + case ACPI_RDESC_TYPE_SMALL: /* * Small Resource Type -- Only bits 6:3 are valid */ - return ((u8) (resource_start_byte & RESOURCE_DESC_SMALL_MASK)); - break; + return ((u8) (resource_start_byte & ACPI_RDESC_SMALL_MASK)); - case RESOURCE_DESC_TYPE_LARGE: + case ACPI_RDESC_TYPE_LARGE: /* * Large Resource Type -- All bits are valid */ return (resource_start_byte); + + + default: + /* No other types of resource descriptor */ break; } @@ -98,183 +101,182 @@ acpi_rs_byte_stream_to_list ( u8 *byte_stream_buffer, u32 byte_stream_buffer_length, - u8 **output_buffer) + u8 *output_buffer) { acpi_status status; - u32 bytes_parsed = 0; + ACPI_SIZE bytes_parsed = 0; u8 resource_type = 0; - u32 bytes_consumed = 0; - u8 **buffer = output_buffer; - u32 structure_size = 0; + ACPI_SIZE bytes_consumed = 0; + u8 *buffer = output_buffer; + ACPI_SIZE structure_size = 0; u8 end_tag_processed = FALSE; + acpi_resource *resource; - - FUNCTION_TRACE ("Rs_byte_stream_to_list"); + ACPI_FUNCTION_TRACE ("Rs_byte_stream_to_list"); while (bytes_parsed < byte_stream_buffer_length && - FALSE == end_tag_processed) { + !end_tag_processed) { /* * The next byte in the stream is the resource type */ resource_type = acpi_rs_get_resource_type (*byte_stream_buffer); switch (resource_type) { - case RESOURCE_DESC_MEMORY_24: + case ACPI_RDESC_TYPE_MEMORY_24: /* * 24-Bit Memory Resource */ status = acpi_rs_memory24_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_LARGE_VENDOR: + case ACPI_RDESC_TYPE_LARGE_VENDOR: /* * Vendor Defined Resource */ status = acpi_rs_vendor_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_MEMORY_32: + case ACPI_RDESC_TYPE_MEMORY_32: /* * 32-Bit Memory Range Resource */ status = acpi_rs_memory32_range_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_FIXED_MEMORY_32: + case ACPI_RDESC_TYPE_FIXED_MEMORY_32: /* * 32-Bit Fixed Memory Resource */ status = acpi_rs_fixed_memory32_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_QWORD_ADDRESS_SPACE: + case ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE: /* * 64-Bit Address Resource */ status = acpi_rs_address64_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_DWORD_ADDRESS_SPACE: + case ACPI_RDESC_TYPE_DWORD_ADDRESS_SPACE: /* * 32-Bit Address Resource */ status = acpi_rs_address32_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_WORD_ADDRESS_SPACE: + case ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE: /* * 16-Bit Address Resource */ status = acpi_rs_address16_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_EXTENDED_XRUPT: + case ACPI_RDESC_TYPE_EXTENDED_XRUPT: /* * Extended IRQ */ status = acpi_rs_extended_irq_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_IRQ_FORMAT: + case ACPI_RDESC_TYPE_IRQ_FORMAT: /* * IRQ Resource */ status = acpi_rs_irq_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_DMA_FORMAT: + case ACPI_RDESC_TYPE_DMA_FORMAT: /* * DMA Resource */ status = acpi_rs_dma_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_START_DEPENDENT: + case ACPI_RDESC_TYPE_START_DEPENDENT: /* * Start Dependent Functions Resource */ - status = acpi_rs_start_dependent_functions_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + status = acpi_rs_start_depend_fns_resource (byte_stream_buffer, + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_END_DEPENDENT: + case ACPI_RDESC_TYPE_END_DEPENDENT: /* * End Dependent Functions Resource */ - status = acpi_rs_end_dependent_functions_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + status = acpi_rs_end_depend_fns_resource (byte_stream_buffer, + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_IO_PORT: + case ACPI_RDESC_TYPE_IO_PORT: /* * IO Port Resource */ status = acpi_rs_io_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_FIXED_IO_PORT: + case ACPI_RDESC_TYPE_FIXED_IO_PORT: /* * Fixed IO Port Resource */ status = acpi_rs_fixed_io_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_SMALL_VENDOR: + case ACPI_RDESC_TYPE_SMALL_VENDOR: /* * Vendor Specific Resource */ status = acpi_rs_vendor_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; - case RESOURCE_DESC_END_TAG: + case ACPI_RDESC_TYPE_END_TAG: /* * End Tag */ end_tag_processed = TRUE; status = acpi_rs_end_tag_resource (byte_stream_buffer, - &bytes_consumed, buffer, &structure_size); + &bytes_consumed, &buffer, &structure_size); break; default: /* - * Invalid/Unknowns resource type + * Invalid/Unknown resource type */ - status = AE_AML_ERROR; + status = AE_AML_INVALID_RESOURCE_TYPE; break; } - - if (!ACPI_SUCCESS(status)) { + if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -291,15 +293,17 @@ /* * Set the Buffer to the next structure */ - *buffer += structure_size; + resource = ACPI_CAST_PTR (acpi_resource, buffer); + resource->length = ACPI_ALIGN_RESOURCE_SIZE(resource->length); + buffer += ACPI_ALIGN_RESOURCE_SIZE(structure_size); } /* end while */ /* * Check the reason for exiting the while loop */ - if (TRUE != end_tag_processed) { - return_ACPI_STATUS (AE_AML_ERROR); + if (!end_tag_processed) { + return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); } return_ACPI_STATUS (AE_OK); @@ -313,7 +317,7 @@ * PARAMETERS: Linked_list - Pointer to the resource linked list * Byte_steam_size_needed - Calculated size of the byte stream * needed from calling - * Acpi_rs_calculate_byte_stream_length() + * Acpi_rs_get_byte_stream_length() * The size of the Output_buffer is * guaranteed to be >= * Byte_stream_size_needed @@ -330,16 +334,16 @@ acpi_status acpi_rs_list_to_byte_stream ( acpi_resource *linked_list, - u32 byte_stream_size_needed, - u8 **output_buffer) + ACPI_SIZE byte_stream_size_needed, + u8 *output_buffer) { acpi_status status; - u8 *buffer = *output_buffer; - u32 bytes_consumed = 0; + u8 *buffer = output_buffer; + ACPI_SIZE bytes_consumed = 0; u8 done = FALSE; - FUNCTION_TRACE ("Rs_list_to_byte_stream"); + ACPI_FUNCTION_TRACE ("Rs_list_to_byte_stream"); while (!done) { @@ -362,7 +366,7 @@ /* * Start Dependent Functions Resource */ - status = acpi_rs_start_dependent_functions_stream (linked_list, + status = acpi_rs_start_depend_fns_stream (linked_list, &buffer, &bytes_consumed); break; @@ -370,7 +374,7 @@ /* * End Dependent Functions Resource */ - status = acpi_rs_end_dependent_functions_stream (linked_list, + status = acpi_rs_end_depend_fns_stream (linked_list, &buffer, &bytes_consumed); break; @@ -472,8 +476,7 @@ } /* switch (Linked_list->Id) */ - - if (!ACPI_SUCCESS(status)) { + if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -485,7 +488,7 @@ /* * Point to the next object */ - linked_list = POINTER_ADD (acpi_resource, + linked_list = ACPI_PTR_ADD (acpi_resource, linked_list, linked_list->length); } diff -Nur linux-2.4.19/drivers/acpi/resources/rsmemory.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsmemory.c --- linux-2.4.19/drivers/acpi/resources/rsmemory.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsmemory.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsmem24 - Memory resource descriptors - * $Revision: 14 $ + * $Revision: 20 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsmemory") + ACPI_MODULE_NAME ("rsmemory") /******************************************************************************* @@ -37,13 +37,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -56,18 +55,18 @@ acpi_status acpi_rs_memory24_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_mem24); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_mem24); - FUNCTION_TRACE ("Rs_memory24_resource"); + ACPI_FUNCTION_TRACE ("Rs_memory24_resource"); /* @@ -75,9 +74,9 @@ */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; - *bytes_consumed = temp16 + 3; + *bytes_consumed = (ACPI_SIZE) temp16 + 3; output_struct->id = ACPI_RSTYPE_MEM24; /* @@ -90,34 +89,34 @@ /* * Get Min_base_address (Bytes 4-5) */ - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.min_base_address = temp16; /* * Get Max_base_address (Bytes 6-7) */ - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.max_base_address = temp16; /* * Get Alignment (Bytes 8-9) */ - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.alignment = temp16; /* * Get Range_length (Bytes 10-11) */ - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.memory24.range_length = temp16; /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -133,9 +132,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -148,14 +146,14 @@ acpi_rs_memory24_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - FUNCTION_TRACE ("Rs_memory24_stream"); + ACPI_FUNCTION_TRACE ("Rs_memory24_stream"); /* @@ -168,7 +166,7 @@ * The length field is static */ temp16 = 0x09; - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; /* @@ -181,31 +179,31 @@ /* * Set the Range minimum base address */ - MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.min_base_address); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.min_base_address); buffer += 2; /* * Set the Range maximum base address */ - MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.max_base_address); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.max_base_address); buffer += 2; /* * Set the base alignment */ - MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.alignment); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.alignment); buffer += 2; /* * Set the range length */ - MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.range_length); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.range_length); buffer += 2; /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -216,13 +214,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -235,18 +232,18 @@ acpi_status acpi_rs_memory32_range_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_mem32); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_mem32); - FUNCTION_TRACE ("Rs_memory32_range_resource"); + ACPI_FUNCTION_TRACE ("Rs_memory32_range_resource"); /* @@ -254,9 +251,9 @@ */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; - *bytes_consumed = temp16 + 3; + *bytes_consumed = (ACPI_SIZE) temp16 + 3; output_struct->id = ACPI_RSTYPE_MEM32; @@ -281,32 +278,32 @@ /* * Get Min_base_address (Bytes 4-7) */ - MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.min_base_address, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.min_base_address, buffer); buffer += 4; /* * Get Max_base_address (Bytes 8-11) */ - MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.max_base_address, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.max_base_address, buffer); buffer += 4; /* * Get Alignment (Bytes 12-15) */ - MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.alignment, buffer); + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.alignment, buffer); buffer += 4; /* * Get Range_length (Bytes 16-19) */ - MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.range_length, buffer); + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.range_length, buffer); /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -322,13 +319,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -341,28 +337,28 @@ acpi_status acpi_rs_fixed_memory32_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_fixed_mem32); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_fixed_mem32); - FUNCTION_TRACE ("Rs_fixed_memory32_resource"); + ACPI_FUNCTION_TRACE ("Rs_fixed_memory32_resource"); /* * Point past the Descriptor to get the number of bytes consumed */ buffer += 1; - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; - *bytes_consumed = temp16 + 3; + *bytes_consumed = (ACPI_SIZE) temp16 + 3; output_struct->id = ACPI_RSTYPE_FIXED_MEM32; @@ -376,20 +372,20 @@ /* * Get Range_base_address (Bytes 4-7) */ - MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, buffer); buffer += 4; /* * Get Range_length (Bytes 8-11) */ - MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_length, + ACPI_MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_length, buffer); /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -405,9 +401,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -420,14 +415,14 @@ acpi_rs_memory32_range_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - FUNCTION_TRACE ("Rs_memory32_range_stream"); + ACPI_FUNCTION_TRACE ("Rs_memory32_range_stream"); /* @@ -441,7 +436,7 @@ */ temp16 = 0x11; - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; /* @@ -454,31 +449,31 @@ /* * Set the Range minimum base address */ - MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.min_base_address); + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.min_base_address); buffer += 4; /* * Set the Range maximum base address */ - MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.max_base_address); + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.max_base_address); buffer += 4; /* * Set the base alignment */ - MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.alignment); + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.alignment); buffer += 4; /* * Set the range length */ - MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.range_length); + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.range_length); buffer += 4; /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -489,9 +484,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -504,14 +498,14 @@ acpi_rs_fixed_memory32_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - FUNCTION_TRACE ("Rs_fixed_memory32_stream"); + ACPI_FUNCTION_TRACE ("Rs_fixed_memory32_stream"); /* @@ -525,7 +519,7 @@ */ temp16 = 0x09; - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; /* @@ -538,21 +532,21 @@ /* * Set the Range base address */ - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.fixed_memory32.range_base_address); buffer += 4; /* * Set the range length */ - MOVE_UNALIGNED32_TO_32 (buffer, + ACPI_MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.fixed_memory32.range_length); buffer += 4; /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/resources/rsmisc.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsmisc.c --- linux-2.4.19/drivers/acpi/resources/rsmisc.c Sun Sep 23 09:42:32 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsmisc.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsmisc - Miscellaneous resource descriptors - * $Revision: 16 $ + * $Revision: 24 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsmisc") + ACPI_MODULE_NAME ("rsmisc") /******************************************************************************* @@ -37,13 +37,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -56,15 +55,15 @@ acpi_status acpi_rs_end_tag_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { - acpi_resource *output_struct = (acpi_resource *) *output_buffer; - u32 struct_size = ACPI_RESOURCE_LENGTH; + acpi_resource *output_struct = (void *) *output_buffer; + ACPI_SIZE struct_size = ACPI_RESOURCE_LENGTH; - FUNCTION_TRACE ("Rs_end_tag_resource"); + ACPI_FUNCTION_TRACE ("Rs_end_tag_resource"); /* @@ -96,9 +95,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -111,13 +109,13 @@ acpi_rs_end_tag_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u8 temp8 = 0; - FUNCTION_TRACE ("Rs_end_tag_stream"); + ACPI_FUNCTION_TRACE ("Rs_end_tag_stream"); /* @@ -138,7 +136,7 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -149,13 +147,12 @@ * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -168,19 +165,19 @@ acpi_status acpi_rs_vendor_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; u8 index; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_vendor); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_vendor); - FUNCTION_TRACE ("Rs_vendor_resource"); + ACPI_FUNCTION_TRACE ("Rs_vendor_resource"); /* @@ -190,34 +187,31 @@ if (temp8 & 0x80) { /* - * Large Item - * Point to the length field + * Large Item, point to the length field */ buffer += 1; /* Dereference */ - MOVE_UNALIGNED16_TO_16 (&temp16, buffer); + ACPI_MOVE_UNALIGNED16_TO_16 (&temp16, buffer); /* Calculate bytes consumed */ - *bytes_consumed = temp16 + 3; + *bytes_consumed = (ACPI_SIZE) temp16 + 3; /* Point to the first vendor byte */ buffer += 2; } - else { /* - * Small Item - * Dereference the size + * Small Item, dereference the size */ temp16 = (u8)(*buffer & 0x07); /* Calculate bytes consumed */ - *bytes_consumed = temp16 + 1; + *bytes_consumed = (ACPI_SIZE) temp16 + 1; /* Point to the first vendor byte */ @@ -237,12 +231,12 @@ * calculate the length of the vendor string and expand the * Struct_size to the next 32-bit boundary. */ - struct_size += ROUND_UP_TO_32_bITS (temp16); + struct_size += ACPI_ROUND_UP_TO_32_bITS (temp16); /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -258,9 +252,8 @@ * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -273,7 +266,7 @@ acpi_rs_vendor_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u16 temp16 = 0; @@ -281,7 +274,7 @@ u8 index; - FUNCTION_TRACE ("Rs_vendor_stream"); + ACPI_FUNCTION_TRACE ("Rs_vendor_stream"); /* @@ -289,25 +282,22 @@ */ if(linked_list->data.vendor_specific.length > 7) { /* - * Large Item - * Set the descriptor field and length bytes + * Large Item, Set the descriptor field and length bytes */ *buffer = 0x84; buffer += 1; temp16 = (u16) linked_list->data.vendor_specific.length; - MOVE_UNALIGNED16_TO_16 (buffer, &temp16); + ACPI_MOVE_UNALIGNED16_TO_16 (buffer, &temp16); buffer += 2; } - else { /* - * Small Item - * Set the descriptor field + * Small Item, Set the descriptor field */ temp8 = 0x70; - temp8 |= linked_list->data.vendor_specific.length; + temp8 |= (u8) linked_list->data.vendor_specific.length; *buffer = temp8; buffer += 1; @@ -326,24 +316,23 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } /******************************************************************************* * - * FUNCTION: Acpi_rs_start_dependent_functions_resource + * FUNCTION: Acpi_rs_start_depend_fns_resource * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -354,19 +343,19 @@ ******************************************************************************/ acpi_status -acpi_rs_start_dependent_functions_resource ( +acpi_rs_start_depend_fns_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { u8 *buffer = byte_stream_buffer; - acpi_resource *output_struct = (acpi_resource *) *output_buffer; + acpi_resource *output_struct = (void *) *output_buffer; u8 temp8 = 0; - u32 struct_size = SIZEOF_RESOURCE (acpi_resource_start_dpf); + ACPI_SIZE struct_size = ACPI_SIZEOF_RESOURCE (acpi_resource_start_dpf); - FUNCTION_TRACE ("Rs_start_dependent_functions_resource"); + ACPI_FUNCTION_TRACE ("Rs_start_depend_fns_resource"); /* @@ -391,7 +380,7 @@ output_struct->data.start_dpf.compatibility_priority = temp8 & 0x03; if (3 == output_struct->data.start_dpf.compatibility_priority) { - return_ACPI_STATUS (AE_AML_ERROR); + return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE); } /* @@ -400,22 +389,21 @@ output_struct->data.start_dpf.performance_robustness = (temp8 >> 2) & 0x03; if (3 == output_struct->data.start_dpf.performance_robustness) { - return_ACPI_STATUS (AE_AML_ERROR); + return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE); } } - else { output_struct->data.start_dpf.compatibility_priority = - ACCEPTABLE_CONFIGURATION; + ACPI_ACCEPTABLE_CONFIGURATION; output_struct->data.start_dpf.performance_robustness = - ACCEPTABLE_CONFIGURATION; + ACPI_ACCEPTABLE_CONFIGURATION; } /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -427,17 +415,16 @@ /******************************************************************************* * - * FUNCTION: Acpi_rs_end_dependent_functions_resource + * FUNCTION: Acpi_rs_end_depend_fns_resource * * PARAMETERS: Byte_stream_buffer - Pointer to the resource input byte * stream - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes consumed from - * the Byte_stream_buffer - * Output_buffer - Pointer to the user's return buffer - * Structure_size - u32 pointer that is filled with - * the number of bytes in the filled - * in structure + * Bytes_consumed - Pointer to where the number of bytes + * consumed the Byte_stream_buffer is + * returned + * Output_buffer - Pointer to the return data buffer + * Structure_size - Pointer to where the number of bytes + * in the return data struct is returned * * RETURN: Status * @@ -448,17 +435,17 @@ ******************************************************************************/ acpi_status -acpi_rs_end_dependent_functions_resource ( +acpi_rs_end_depend_fns_resource ( u8 *byte_stream_buffer, - u32 *bytes_consumed, + ACPI_SIZE *bytes_consumed, u8 **output_buffer, - u32 *structure_size) + ACPI_SIZE *structure_size) { - acpi_resource *output_struct = (acpi_resource *) *output_buffer; - u32 struct_size = ACPI_RESOURCE_LENGTH; + acpi_resource *output_struct = (void *) *output_buffer; + ACPI_SIZE struct_size = ACPI_RESOURCE_LENGTH; - FUNCTION_TRACE ("Rs_end_dependent_functions_resource"); + ACPI_FUNCTION_TRACE ("Rs_end_depend_fns_resource"); /* @@ -474,7 +461,7 @@ /* * Set the Length parameter */ - output_struct->length = struct_size; + output_struct->length = (u32) struct_size; /* * Return the final size of the structure @@ -486,7 +473,7 @@ /******************************************************************************* * - * FUNCTION: Acpi_rs_start_dependent_functions_stream + * FUNCTION: Acpi_rs_start_depend_fns_stream * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer @@ -502,25 +489,25 @@ ******************************************************************************/ acpi_status -acpi_rs_start_dependent_functions_stream ( +acpi_rs_start_depend_fns_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; u8 temp8 = 0; - FUNCTION_TRACE ("Rs_start_dependent_functions_stream"); + ACPI_FUNCTION_TRACE ("Rs_start_depend_fns_stream"); /* * The descriptor field is set based upon whether a byte is needed * to contain Priority data. */ - if (ACCEPTABLE_CONFIGURATION == + if (ACPI_ACCEPTABLE_CONFIGURATION == linked_list->data.start_dpf.compatibility_priority && - ACCEPTABLE_CONFIGURATION == + ACPI_ACCEPTABLE_CONFIGURATION == linked_list->data.start_dpf.performance_robustness) { *buffer = 0x30; } @@ -544,20 +531,19 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } /******************************************************************************* * - * FUNCTION: Acpi_rs_end_dependent_functions_stream + * FUNCTION: Acpi_rs_end_depend_fns_stream * * PARAMETERS: Linked_list - Pointer to the resource linked list * Output_buffer - Pointer to the user's return buffer - * Bytes_consumed - u32 pointer that is filled with - * the number of bytes of the - * Output_buffer used + * Bytes_consumed - Pointer to where the number of bytes + * used in the Output_buffer is returned * * RETURN: Status * @@ -567,16 +553,15 @@ ******************************************************************************/ acpi_status -acpi_rs_end_dependent_functions_stream ( +acpi_rs_end_depend_fns_stream ( acpi_resource *linked_list, u8 **output_buffer, - u32 *bytes_consumed - ) + ACPI_SIZE *bytes_consumed) { u8 *buffer = *output_buffer; - FUNCTION_TRACE ("Rs_end_dependent_functions_stream"); + ACPI_FUNCTION_TRACE ("Rs_end_depend_fns_stream"); /* @@ -588,7 +573,7 @@ /* * Return the number of bytes consumed in this operation */ - *bytes_consumed = POINTER_DIFF (buffer, *output_buffer); + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/resources/rsutils.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsutils.c --- linux-2.4.19/drivers/acpi/resources/rsutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsutils.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsutils - Utilities for the resource manager - * $Revision: 23 $ + * $Revision: 30 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsutils") + ACPI_MODULE_NAME ("rsutils") /******************************************************************************* @@ -58,15 +58,12 @@ { acpi_operand_object *ret_obj; acpi_status status; - u32 buffer_space_needed; - FUNCTION_TRACE ("Rs_get_prt_method_data"); + ACPI_FUNCTION_TRACE ("Rs_get_prt_method_data"); - /* already validated params, so we won't repeat here */ - - buffer_space_needed = ret_buffer->length; + /* Parameters guaranteed valid by caller */ /* * Execute the method, no parameters @@ -83,34 +80,25 @@ return_ACPI_STATUS (AE_TYPE); } - /* - * The return object will be a package, so check the - * parameters. If the return object is not a package, - * then the underlying AML code is corrupt or improperly - * written. + * The return object will be a package, so check the parameters. If the + * return object is not a package, then the underlying AML code is corrupt + * or improperly written. */ if (ACPI_TYPE_PACKAGE != ret_obj->common.type) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_PRT did not return a Package, returned %s\n", + acpi_ut_get_type_name (ret_obj->common.type))); status = AE_AML_OPERAND_TYPE; goto cleanup; } /* - * Make the call to create a resource linked list from the - * byte stream buffer that comes back from the _CRS method - * execution. - */ - status = acpi_rs_create_pci_routing_table (ret_obj, ret_buffer->pointer, - &buffer_space_needed); - - /* - * Tell the user how much of the buffer we have used or is needed - * and return the final status. + * Create a resource linked list from the byte stream buffer that comes + * back from the _CRS method execution. */ - ret_buffer->length = buffer_space_needed; + status = acpi_rs_create_pci_routing_table (ret_obj, ret_buffer); - - /* On exit, we must delete the object returned by evaluate_object */ + /* On exit, we must delete the object returned by Evaluate_object */ cleanup: @@ -144,16 +132,15 @@ { acpi_operand_object *ret_obj; acpi_status status; - u32 buffer_space_needed = ret_buffer->length; - FUNCTION_TRACE ("Rs_get_crs_method_data"); + ACPI_FUNCTION_TRACE ("Rs_get_crs_method_data"); - /* already validated params, so we won't repeat here */ + /* Parameters guaranteed valid by caller */ /* - * Execute the method, no parameters + * Execute the method, no parameters */ status = acpi_ns_evaluate_relative (handle, "_CRS", NULL, &ret_obj); if (ACPI_FAILURE (status)) { @@ -169,30 +156,23 @@ /* * The return object will be a buffer, but check the - * parameters. If the return object is not a buffer, - * then the underlying AML code is corrupt or improperly - * written. + * parameters. If the return object is not a buffer, + * then the underlying AML code is corrupt or improperly + * written. */ if (ACPI_TYPE_BUFFER != ret_obj->common.type) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_CRS did not return a Buffer, returned %s\n", + acpi_ut_get_type_name (ret_obj->common.type))); status = AE_AML_OPERAND_TYPE; goto cleanup; } /* * Make the call to create a resource linked list from the - * byte stream buffer that comes back from the _CRS method - * execution. + * byte stream buffer that comes back from the _CRS method + * execution. */ - status = acpi_rs_create_resource_list (ret_obj, ret_buffer->pointer, - &buffer_space_needed); - - - /* - * Tell the user how much of the buffer we have used or is needed - * and return the final status. - */ - ret_buffer->length = buffer_space_needed; - + status = acpi_rs_create_resource_list (ret_obj, ret_buffer); /* On exit, we must delete the object returned by evaluate_object */ @@ -228,16 +208,15 @@ { acpi_operand_object *ret_obj; acpi_status status; - u32 buffer_space_needed = ret_buffer->length; - FUNCTION_TRACE ("Rs_get_prs_method_data"); + ACPI_FUNCTION_TRACE ("Rs_get_prs_method_data"); - /* already validated params, so we won't repeat here */ + /* Parameters guaranteed valid by caller */ /* - * Execute the method, no parameters + * Execute the method, no parameters */ status = acpi_ns_evaluate_relative (handle, "_PRS", NULL, &ret_obj); if (ACPI_FAILURE (status)) { @@ -253,29 +232,23 @@ /* * The return object will be a buffer, but check the - * parameters. If the return object is not a buffer, - * then the underlying AML code is corrupt or improperly - * written.. + * parameters. If the return object is not a buffer, + * then the underlying AML code is corrupt or improperly + * written.. */ if (ACPI_TYPE_BUFFER != ret_obj->common.type) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_PRS did not return a Buffer, returned %s\n", + acpi_ut_get_type_name (ret_obj->common.type))); status = AE_AML_OPERAND_TYPE; goto cleanup; } /* * Make the call to create a resource linked list from the - * byte stream buffer that comes back from the _CRS method - * execution. - */ - status = acpi_rs_create_resource_list (ret_obj, ret_buffer->pointer, - &buffer_space_needed); - - /* - * Tell the user how much of the buffer we have used or is needed - * and return the final status. + * byte stream buffer that comes back from the _CRS method + * execution. */ - ret_buffer->length = buffer_space_needed; - + status = acpi_rs_create_resource_list (ret_obj, ret_buffer); /* On exit, we must delete the object returned by evaluate_object */ @@ -311,50 +284,25 @@ { acpi_operand_object *params[2]; acpi_status status; - u8 *byte_stream = NULL; - u32 buffer_size_needed = 0; + acpi_buffer buffer; - FUNCTION_TRACE ("Rs_set_srs_method_data"); + ACPI_FUNCTION_TRACE ("Rs_set_srs_method_data"); - /* already validated params, so we won't repeat here */ + /* Parameters guaranteed valid by caller */ /* * The In_buffer parameter will point to a linked list of * resource parameters. It needs to be formatted into a - * byte stream to be sent in as an input parameter. - */ - buffer_size_needed = 0; - - /* - * First call is to get the buffer size needed - */ - status = acpi_rs_create_byte_stream (in_buffer->pointer, byte_stream, - &buffer_size_needed); - /* - * We expect a return of AE_BUFFER_OVERFLOW - * if not, exit with the error + * byte stream to be sent in as an input parameter to _SRS + * + * Convert the linked list into a byte stream */ - if (AE_BUFFER_OVERFLOW != status) { - return_ACPI_STATUS (status); - } - - /* - * Allocate the buffer needed - */ - byte_stream = ACPI_MEM_CALLOCATE (buffer_size_needed); - if (NULL == byte_stream) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - /* - * Now call to convert the linked list into a byte stream - */ - status = acpi_rs_create_byte_stream (in_buffer->pointer, byte_stream, - &buffer_size_needed); + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_rs_create_byte_stream (in_buffer->pointer, &buffer); if (ACPI_FAILURE (status)) { - goto cleanup; + return_ACPI_STATUS (status); } /* @@ -362,28 +310,26 @@ */ params[0] = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); if (!params[0]) { - status = AE_NO_MEMORY; - goto cleanup; + acpi_os_free (buffer.pointer); + return_ACPI_STATUS (AE_NO_MEMORY); } - params [1] = NULL; /* - * Set up the parameter object + * Set up the parameter object */ - params[0]->buffer.length = buffer_size_needed; - params[0]->buffer.pointer = byte_stream; + params[0]->buffer.length = (u32) buffer.length; + params[0]->buffer.pointer = buffer.pointer; + params[1] = NULL; /* * Execute the method, no return value */ status = acpi_ns_evaluate_relative (handle, "_SRS", params, NULL); - acpi_ut_remove_reference (params[0]); /* * Clean up and return the status from Acpi_ns_evaluate_relative */ -cleanup: - + acpi_ut_remove_reference (params[0]); return_ACPI_STATUS (status); } diff -Nur linux-2.4.19/drivers/acpi/resources/rsxface.c linux-2.4.19-sgi211r3/drivers/acpi/resources/rsxface.c --- linux-2.4.19/drivers/acpi/resources/rsxface.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/resources/rsxface.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: rsxface - Public interfaces to the resource manager - * $Revision: 15 $ + * $Revision: 19 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,12 +25,10 @@ #include "acpi.h" -#include "acinterp.h" -#include "acnamesp.h" #include "acresrc.h" #define _COMPONENT ACPI_RESOURCES - MODULE_NAME ("rsxface") + ACPI_MODULE_NAME ("rsxface") /******************************************************************************* @@ -64,7 +62,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_get_irq_routing_table "); + ACPI_FUNCTION_TRACE ("Acpi_get_irq_routing_table "); /* @@ -73,12 +71,15 @@ * we also need a valid pointer in the buffer. If it's a zero buffer length, * we'll be returning the needed buffer size, so keep going. */ - if ((!device_handle) || - (!ret_buffer) || - ((!ret_buffer->pointer) && (ret_buffer->length))) { + if (!device_handle) { return_ACPI_STATUS (AE_BAD_PARAMETER); } + status = acpi_ut_validate_buffer (ret_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + status = acpi_rs_get_prt_method_data (device_handle, ret_buffer); return_ACPI_STATUS (status); } @@ -116,7 +117,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_get_current_resources"); + ACPI_FUNCTION_TRACE ("Acpi_get_current_resources"); /* @@ -125,12 +126,15 @@ * we also need a valid pointer in the buffer. If it's a zero buffer length, * we'll be returning the needed buffer size, so keep going. */ - if ((!device_handle) || - (!ret_buffer) || - ((ret_buffer->length) && (!ret_buffer->pointer))) { + if (!device_handle) { return_ACPI_STATUS (AE_BAD_PARAMETER); } + status = acpi_ut_validate_buffer (ret_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + status = acpi_rs_get_crs_method_data (device_handle, ret_buffer); return_ACPI_STATUS (status); } @@ -165,7 +169,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_get_possible_resources"); + ACPI_FUNCTION_TRACE ("Acpi_get_possible_resources"); /* @@ -174,12 +178,15 @@ * we also need a valid pointer in the buffer. If it's a zero buffer length, * we'll be returning the needed buffer size, so keep going. */ - if ((!device_handle) || - (!ret_buffer) || - ((ret_buffer->length) && (!ret_buffer->pointer))) { + if (!device_handle) { return_ACPI_STATUS (AE_BAD_PARAMETER); } + status = acpi_ut_validate_buffer (ret_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + status = acpi_rs_get_prs_method_data (device_handle, ret_buffer); return_ACPI_STATUS (status); } @@ -211,7 +218,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_set_current_resources"); + ACPI_FUNCTION_TRACE ("Acpi_set_current_resources"); /* diff -Nur linux-2.4.19/drivers/acpi/system.c linux-2.4.19-sgi211r3/drivers/acpi/system.c --- linux-2.4.19/drivers/acpi/system.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/system.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,1282 @@ +/* + * acpi_system.c - ACPI System Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __i386__ +#include +#endif +#include "acpi_bus.h" +#include "acpi_drivers.h" + +#ifdef CONFIG_X86 +#ifdef CONFIG_ACPI_SLEEP +#include +#endif +#endif + + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("acpi_system") + +#define PREFIX "ACPI: " + +extern FADT_DESCRIPTOR acpi_fadt; + +static int acpi_system_add (struct acpi_device *device); +static int acpi_system_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_system_driver = { + name: ACPI_SYSTEM_DRIVER_NAME, + class: ACPI_SYSTEM_CLASS, + ids: ACPI_SYSTEM_HID, + ops: { + add: acpi_system_add, + remove: acpi_system_remove + }, +}; + +struct acpi_system +{ + acpi_handle handle; + u8 states[ACPI_S_STATE_COUNT]; +}; + +/* Global vars for handling event proc entry */ +static spinlock_t acpi_system_event_lock = SPIN_LOCK_UNLOCKED; +int event_is_open = 0; +extern struct list_head acpi_bus_event_list; +extern wait_queue_head_t acpi_bus_event_queue; + +/* -------------------------------------------------------------------------- + System Sleep + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_PM + +static void +acpi_power_off (void) +{ + acpi_enter_sleep_state_prep(ACPI_STATE_S5); + ACPI_DISABLE_IRQS(); + acpi_enter_sleep_state(ACPI_STATE_S5); +} + +#endif /*CONFIG_PM*/ + + +#ifdef CONFIG_ACPI_SLEEP + +/** + * acpi_system_restore_state - OS-specific restoration of state + * @state: sleep state we're exiting + * + * Note that if we're coming back from S4, the memory image should have already + * been loaded from the disk and is already in place. (Otherwise how else would we + * be here?). + */ +acpi_status +acpi_system_restore_state ( + u32 state) +{ + /* restore processor state + * We should only be here if we're coming back from STR or STD. + * And, in the case of the latter, the memory image should have already + * been loaded from disk. + */ + if (state > ACPI_STATE_S1) + acpi_restore_state_mem(); + + /* wait for power to come back */ + mdelay(10); +#ifdef HAVE_NEW_DEVICE_MODEL + /* turn all the devices back on */ + device_resume(RESUME_POWER_ON); + + /* enable interrupts once again */ + ACPI_ENABLE_IRQS(); + + /* restore device context */ + device_resume(RESUME_RESTORE_STATE); +#endif + return AE_OK; +} + +/** + * acpi_system_save_state - save OS specific state and power down devices + * @state: sleep state we're entering. + * + * This handles saving all context to memory, and possibly disk. + * First, we call to the device driver layer to save device state. + * Once we have that, we save whatevery processor and kernel state we + * need to memory. + * If we're entering S4, we then write the memory image to disk. + * + * Only then is it safe for us to power down devices, since we may need + * the disks and upstream buses to write to. + */ +acpi_status +acpi_system_save_state( + u32 state) +{ + int error = 0; + +#ifdef HAVE_NEW_DEVICE_MODEL + /* Send notification to devices that they will be suspended. + * If any device or driver cannot make the transition, either up + * or down, we'll get an error back. + */ + error = device_suspend(state, SUSPEND_NOTIFY); + if (error) + return AE_ERROR; +#endif + if (state < ACPI_STATE_S5) { + +#ifdef HAVE_NEW_DEVICE_MODEL + /* Tell devices to stop I/O and actually save their state. + * It is theoretically possible that something could fail, + * so handle that gracefully.. + */ + error = device_suspend(state, SUSPEND_SAVE_STATE); + if (error) { + /* tell devices to restore state if they have + * it saved and to start taking I/O requests. + */ + device_resume(RESUME_RESTORE_STATE); + return error; + } +#endif + + /* flush caches */ + ACPI_FLUSH_CPU_CACHE(); + + /* Do arch specific saving of state. */ + if (state > ACPI_STATE_S1) { + error = acpi_save_state_mem(); + + if (!error && (state == ACPI_STATE_S4)) + error = acpi_save_state_disk(); + +#ifdef HAVE_NEW_DEVICE_MODEL + if (error) { + device_resume(RESUME_RESTORE_STATE); + return error; + } +#endif + } + } +#ifdef HAVE_NEW_DEVICE_MODEL + /* disable interrupts + * Note that acpi_suspend -- our caller -- will do this once we return. + * But, we want it done early, so we don't get any suprises during + * the device suspend sequence. + */ + ACPI_DISABLE_IRQS(); + + /* Unconditionally turn off devices. + * Obvious if we enter a sleep state. + * If entering S5 (soft off), this should put devices in a + * quiescent state. + */ + error = device_suspend(state, SUSPEND_POWER_DOWN); + + /* We're pretty screwed if we got an error from this. + * We try to recover by simply calling our own restore_state + * function; see above for definition. + * + * If it's S5 though, go through with it anyway.. + */ + if (error && state != ACPI_STATE_S5) + acpi_system_restore_state(state); +#endif + return error ? AE_ERROR : AE_OK; +} + + +/**************************************************************************** + * + * FUNCTION: acpi_system_suspend + * + * PARAMETERS: %state: Sleep state to enter. + * + * RETURN: acpi_status, whether or not we successfully entered and + * exited sleep. + * + * DESCRIPTION: Perform OS-specific action to enter sleep state. + * This is the final step in going to sleep, per spec. If we + * know we're coming back (i.e. not entering S5), we save the + * processor flags. [ We'll have to save and restore them anyway, + * so we use the arch-agnostic save_flags and restore_flags + * here.] We then set the place to return to in arch-specific + * globals using arch_set_return_point. Finally, we call the + * ACPI function to write the proper values to I/O ports. + * + ****************************************************************************/ + +acpi_status +acpi_system_suspend( + u32 state) +{ + acpi_status status = AE_ERROR; + unsigned long flags = 0; + + save_flags(flags); + kernel_fpu_begin(); + + switch (state) + { + case ACPI_STATE_S1: + /* do nothing */ + break; + + case ACPI_STATE_S2: + case ACPI_STATE_S3: + save_register_state((unsigned long)&&acpi_sleep_done); + break; + } + + barrier(); + status = acpi_enter_sleep_state(state); + +acpi_sleep_done: + + restore_register_state(); + fix_processor_context(); + + kernel_fpu_end(); + restore_flags(flags); + + return status; +} + + +/** + * acpi_suspend - OS-agnostic system suspend/resume support (S? states) + * @state: state we're entering + * + */ +acpi_status +acpi_suspend ( + u32 state) +{ + acpi_status status; + + /* get out if state is invalid */ + if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5) + return AE_ERROR; + + /* do we have a wakeup address for S2 and S3? */ + if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3) { + if (!acpi_wakeup_address) + return AE_ERROR; + acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) acpi_wakeup_address); + } + + acpi_enter_sleep_state_prep(state); + + status = acpi_system_save_state(state); + if (!ACPI_SUCCESS(status)) + return status; + + /* disable interrupts and flush caches */ + ACPI_DISABLE_IRQS(); + ACPI_FLUSH_CPU_CACHE(); + + /* perform OS-specific sleep actions */ + status = acpi_system_suspend(state); + + /* Even if we failed to go to sleep, all of the devices are in an suspended + * mode. So, we run these unconditionaly to make sure we have a usable system + * no matter what. + */ + acpi_system_restore_state(state); + acpi_leave_sleep_state(state); + + /* make sure interrupts are enabled */ + ACPI_ENABLE_IRQS(); + + /* reset firmware waking vector */ + acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0); + + return status; +} + +#endif /* CONFIG_ACPI_SLEEP */ + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + + +static int +acpi_system_read_info ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_system *system = (struct acpi_system *) data; + char *p = page; + int size = 0; + u32 i = 0; + + ACPI_FUNCTION_TRACE("acpi_system_read_info"); + + if (!system || (off != 0)) + goto end; + + p += sprintf(p, "version: %x\n", ACPI_CA_VERSION); + + p += sprintf(p, "states: "); + for (i=0; istates[i]) + p += sprintf(p, "S%d ", i); + } + p += sprintf(p, "\n"); + +end: + size = (p - page); + if (size <= off+count) *eof = 1; + *start = page + off; + size -= off; + if (size>count) size = count; + if (size<0) size = 0; + + return_VALUE(size); +} + +static int acpi_system_open_event(struct inode *inode, struct file *file); +static ssize_t acpi_system_read_event (struct file*, char*, size_t, loff_t*); +static int acpi_system_close_event(struct inode *inode, struct file *file); +static unsigned int acpi_system_poll_event(struct file *file, poll_table *wait); + + +static struct file_operations acpi_system_event_ops = { + open: acpi_system_open_event, + read: acpi_system_read_event, + release: acpi_system_close_event, + poll: acpi_system_poll_event, +}; + +static int +acpi_system_open_event(struct inode *inode, struct file *file) +{ + spin_lock_irq (&acpi_system_event_lock); + + if(event_is_open) + goto out_busy; + + event_is_open = 1; + + spin_unlock_irq (&acpi_system_event_lock); + return 0; + +out_busy: + spin_unlock_irq (&acpi_system_event_lock); + return -EBUSY; +} + +static ssize_t +acpi_system_read_event ( + struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + int result = 0; + char outbuf[ACPI_MAX_STRING]; + int size = 0; + struct acpi_bus_event event; + + ACPI_FUNCTION_TRACE("acpi_system_read_event"); + + memset(&event, 0, sizeof(struct acpi_bus_event)); + + if (count < ACPI_MAX_STRING) + goto end; + + if ((file->f_flags & O_NONBLOCK) + && (list_empty(&acpi_bus_event_list))) + return_VALUE(-EAGAIN); + + result = acpi_bus_receive_event(&event); + if (0 != result) { + size = sprintf(outbuf, "error\n"); + goto end; + } + + size = sprintf(outbuf, "%s %s %08x %08x\n", + event.device_class?event.device_class:"", + event.bus_id?event.bus_id:"", + event.type, + event.data); + +end: + if (copy_to_user(buffer, outbuf, size)) + return_VALUE(-EFAULT); + + *ppos += size; + + return_VALUE(size); +} + +static int +acpi_system_close_event(struct inode *inode, struct file *file) +{ + spin_lock_irq (&acpi_system_event_lock); + event_is_open = 0; + spin_unlock_irq (&acpi_system_event_lock); + return 0; +} + +static unsigned int +acpi_system_poll_event( + struct file *file, + poll_table *wait) +{ + poll_wait(file, &acpi_bus_event_queue, wait); + if (!list_empty(&acpi_bus_event_list)) + return POLLIN | POLLRDNORM; + return 0; +} + +static ssize_t acpi_system_read_dsdt (struct file*, char*, size_t, loff_t*); + +static struct file_operations acpi_system_dsdt_ops = { + read: acpi_system_read_dsdt, +}; + +static ssize_t +acpi_system_read_dsdt ( + struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + acpi_status status = AE_OK; + acpi_buffer dsdt = {ACPI_ALLOCATE_BUFFER, NULL}; + void *data = 0; + size_t size = 0; + + ACPI_FUNCTION_TRACE("acpi_system_read_dsdt"); + + status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + if (*ppos < dsdt.length) { + data = dsdt.pointer + file->f_pos; + size = dsdt.length - file->f_pos; + if (size > count) + size = count; + if (copy_to_user(buffer, data, size)) { + kfree(dsdt.pointer); + return_VALUE(-EFAULT); + } + } + + kfree(dsdt.pointer); + + *ppos += size; + + return_VALUE(size); +} + + +static ssize_t acpi_system_read_fadt (struct file*, char*, size_t, loff_t*); + +static struct file_operations acpi_system_fadt_ops = { + read: acpi_system_read_fadt, +}; + +static ssize_t +acpi_system_read_fadt ( + struct file *file, + char *buffer, + size_t count, + loff_t *ppos) +{ + acpi_status status = AE_OK; + acpi_buffer fadt = {ACPI_ALLOCATE_BUFFER, NULL}; + void *data = 0; + size_t size = 0; + + ACPI_FUNCTION_TRACE("acpi_system_read_fadt"); + + status = acpi_get_table(ACPI_TABLE_FADT, 1, &fadt); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + if (*ppos < fadt.length) { + data = fadt.pointer + file->f_pos; + size = fadt.length - file->f_pos; + if (size > count) + size = count; + if (copy_to_user(buffer, data, size)) { + kfree(fadt.pointer); + return_VALUE(-EFAULT); + } + } + + kfree(fadt.pointer); + + *ppos += size; + + return_VALUE(size); +} + + +#ifdef ACPI_DEBUG + +static int +acpi_system_read_debug ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + char *p = page; + int size = 0; + + if (off != 0) + goto end; + + switch ((unsigned long) data) { + case 0: + p += sprintf(p, "0x%08x\n", acpi_dbg_layer); + break; + case 1: + p += sprintf(p, "0x%08x\n", acpi_dbg_level); + break; + default: + p += sprintf(p, "Invalid debug option\n"); + break; + } + +end: + size = (p - page); + if (size <= off+count) *eof = 1; + *start = page + off; + size -= off; + if (size>count) size = count; + if (size<0) size = 0; + + return size; +} + + +static int +acpi_system_write_debug ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + char debug_string[12] = {'\0'}; + + ACPI_FUNCTION_TRACE("acpi_system_write_debug"); + + if (count > sizeof(debug_string) - 1) + return_VALUE(-EINVAL); + + if (copy_from_user(debug_string, buffer, count)) + return_VALUE(-EFAULT); + + debug_string[count] = '\0'; + + switch ((unsigned long) data) { + case 0: + acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0); + break; + case 1: + acpi_dbg_level = simple_strtoul(debug_string, NULL, 0); + break; + default: + return_VALUE(-EINVAL); + } + + return_VALUE(count); +} + +#endif /* ACPI_DEBUG */ + + +#ifdef CONFIG_ACPI_SLEEP + +static int +acpi_system_read_sleep ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_system *system = (struct acpi_system *) data; + char *p = page; + int size; + int i; + + ACPI_FUNCTION_TRACE("acpi_system_read_sleep"); + + if (!system || (off != 0)) + goto end; + + for (i = 0; i <= ACPI_STATE_S5; i++) { + if (system->states[i]) + p += sprintf(p,"S%d ", i); + } + + p += sprintf(p, "\n"); + +end: + size = (p - page); + if (size <= off+count) *eof = 1; + *start = page + off; + size -= off; + if (size>count) size = count; + if (size<0) size = 0; + + return_VALUE(size); +} + + +static int +acpi_system_write_sleep ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + acpi_status status = AE_OK; + struct acpi_system *system = (struct acpi_system *) data; + char state_string[12] = {'\0'}; + u32 state = 0; + + ACPI_FUNCTION_TRACE("acpi_system_write_sleep"); + + if (!system || (count > sizeof(state_string) - 1)) + return_VALUE(-EINVAL); + + if (copy_from_user(state_string, buffer, count)) + return_VALUE(-EFAULT); + + state_string[count] = '\0'; + + state = simple_strtoul(state_string, NULL, 0); + + if (!system->states[state]) + return_VALUE(-ENODEV); + + status = acpi_suspend(state); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + return_VALUE(count); +} + + +static int +acpi_system_read_alarm ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *context) +{ + char *p = page; + int size = 0; + u32 sec, min, hr; + u32 day, mo, yr; + + ACPI_FUNCTION_TRACE("acpi_system_read_alarm"); + + if (off != 0) + goto end; + + spin_lock(&rtc_lock); + + sec = CMOS_READ(RTC_SECONDS_ALARM); + min = CMOS_READ(RTC_MINUTES_ALARM); + hr = CMOS_READ(RTC_HOURS_ALARM); + +#if 0 /* If we ever get an FACP with proper values... */ + if (acpi_gbl_FADT->day_alrm) + day = CMOS_READ(acpi_gbl_FADT->day_alrm); + else + day = CMOS_READ(RTC_DAY_OF_MONTH); + if (acpi_gbl_FADT->mon_alrm) + mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); + else + mo = CMOS_READ(RTC_MONTH);; + if (acpi_gbl_FADT->century) + yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR); + else + yr = CMOS_READ(RTC_YEAR); +#else + day = CMOS_READ(RTC_DAY_OF_MONTH); + mo = CMOS_READ(RTC_MONTH); + yr = CMOS_READ(RTC_YEAR); +#endif + + spin_unlock(&rtc_lock); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hr); + BCD_TO_BIN(day); + BCD_TO_BIN(mo); + BCD_TO_BIN(yr); + +#if 0 + /* we're trusting the FADT (see above)*/ +#else + /* If we're not trusting the FADT, we should at least make it + * right for _this_ century... ehm, what is _this_ century? + * + * TBD: + * ASAP: find piece of code in the kernel, e.g. star tracker driver, + * which we can trust to determine the century correctly. Atom + * watch driver would be nice, too... + * + * if that has not happened, change for first release in 2050: + * if (yr<50) + * yr += 2100; + * else + * yr += 2000; // current line of code + * + * if that has not happened either, please do on 2099/12/31:23:59:59 + * s/2000/2100 + * + */ + yr += 2000; +#endif + + p += sprintf(p,"%4.4u-", yr); + p += (mo > 12) ? sprintf(p, "**-") : sprintf(p, "%2.2u-", mo); + p += (day > 31) ? sprintf(p, "** ") : sprintf(p, "%2.2u ", day); + p += (hr > 23) ? sprintf(p, "**:") : sprintf(p, "%2.2u:", hr); + p += (min > 59) ? sprintf(p, "**:") : sprintf(p, "%2.2u:", min); + p += (sec > 59) ? sprintf(p, "**\n") : sprintf(p, "%2.2u\n", sec); + + end: + size = p - page; + if (size < count) *eof = 1; + else if (size > count) size = count; + if (size < 0) size = 0; + *start = page; + + return_VALUE(size); +} + + +static int +get_date_field ( + char **p, + u32 *value) +{ + char *next = NULL; + char *string_end = NULL; + int result = -EINVAL; + + /* + * Try to find delimeter, only to insert null. The end of the + * string won't have one, but is still valid. + */ + next = strpbrk(*p, "- :"); + if (next) + *next++ = '\0'; + + *value = simple_strtoul(*p, &string_end, 10); + + /* Signal success if we got a good digit */ + if (string_end != *p) + result = 0; + + if (next) + *p = next; + + return result; +} + + +static int +acpi_system_write_alarm ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + char alarm_string[30] = {'\0'}; + char *p = alarm_string; + u32 sec, min, hr, day, mo, yr; + int adjust = 0; + unsigned char rtc_control = 0; + + ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); + + if (count > sizeof(alarm_string) - 1) + return_VALUE(-EINVAL); + + if (copy_from_user(alarm_string, buffer, count)) + return_VALUE(-EFAULT); + + alarm_string[count] = '\0'; + + /* check for time adjustment */ + if (alarm_string[0] == '+') { + p++; + adjust = 1; + } + + if ((result = get_date_field(&p, &yr))) + goto end; + if ((result = get_date_field(&p, &mo))) + goto end; + if ((result = get_date_field(&p, &day))) + goto end; + if ((result = get_date_field(&p, &hr))) + goto end; + if ((result = get_date_field(&p, &min))) + goto end; + if ((result = get_date_field(&p, &sec))) + goto end; + + if (sec > 59) { + min += 1; + sec -= 60; + } + if (min > 59) { + hr += 1; + min -= 60; + } + if (hr > 23) { + day += 1; + hr -= 24; + } + if (day > 31) { + mo += 1; + day -= 31; + } + if (mo > 12) { + yr += 1; + mo -= 12; + } + + spin_lock_irq(&rtc_lock); + + rtc_control = CMOS_READ(RTC_CONTROL); + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(yr); + BIN_TO_BCD(mo); + BIN_TO_BCD(day); + BIN_TO_BCD(hr); + BIN_TO_BCD(min); + BIN_TO_BCD(sec); + } + + if (adjust) { + yr += CMOS_READ(RTC_YEAR); + mo += CMOS_READ(RTC_MONTH); + day += CMOS_READ(RTC_DAY_OF_MONTH); + hr += CMOS_READ(RTC_HOURS); + min += CMOS_READ(RTC_MINUTES); + sec += CMOS_READ(RTC_SECONDS); + } + + spin_unlock_irq(&rtc_lock); + + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(yr); + BCD_TO_BIN(mo); + BCD_TO_BIN(day); + BCD_TO_BIN(hr); + BCD_TO_BIN(min); + BCD_TO_BIN(sec); + } + + if (sec > 59) { + min++; + sec -= 60; + } + if (min > 59) { + hr++; + min -= 60; + } + if (hr > 23) { + day++; + hr -= 24; + } + if (day > 31) { + mo++; + day -= 31; + } + if (mo > 12) { + yr++; + mo -= 12; + } + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(yr); + BIN_TO_BCD(mo); + BIN_TO_BCD(day); + BIN_TO_BCD(hr); + BIN_TO_BCD(min); + BIN_TO_BCD(sec); + } + + spin_lock_irq(&rtc_lock); + + /* write the fields the rtc knows about */ + CMOS_WRITE(hr, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + CMOS_WRITE(sec, RTC_SECONDS_ALARM); + + /* + * If the system supports an enhanced alarm it will have non-zero + * offsets into the CMOS RAM here -- which for some reason are pointing + * to the RTC area of memory. + */ +#if 0 + if (acpi_gbl_FADT->day_alrm) + CMOS_WRITE(day, acpi_gbl_FADT->day_alrm); + if (acpi_gbl_FADT->mon_alrm) + CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm); + if (acpi_gbl_FADT->century) + CMOS_WRITE(yr/100, acpi_gbl_FADT->century); +#endif + /* enable the rtc alarm interrupt */ + if (!(rtc_control & RTC_AIE)) { + rtc_control |= RTC_AIE; + CMOS_WRITE(rtc_control,RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + } + + spin_unlock_irq(&rtc_lock); + + acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK); + + file->f_pos += count; + + result = 0; +end: + return_VALUE(result ? result : count); +} + +#endif /*CONFIG_ACPI_SLEEP*/ + + +static int +acpi_system_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_system_add_fs"); + + if (!device) + return_VALUE(-EINVAL); + + /* 'info' [R] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_INFO, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_INFO)); + else { + entry->read_proc = acpi_system_read_info; + entry->data = acpi_driver_data(device); + } + + /* 'dsdt' [R] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_DSDT, + S_IRUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_DSDT)); + else + entry->proc_fops = &acpi_system_dsdt_ops; + + /* 'fadt' [R] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_FADT, + S_IRUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_FADT)); + else + entry->proc_fops = &acpi_system_fadt_ops; + + /* 'event' [R] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_EVENT, + S_IRUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_EVENT)); + else + entry->proc_fops = &acpi_system_event_ops; + +#ifdef CONFIG_ACPI_SLEEP + + /* 'sleep' [R/W]*/ + entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_SLEEP)); + else { + entry->read_proc = acpi_system_read_sleep; + entry->write_proc = acpi_system_write_sleep; + entry->data = acpi_driver_data(device); + } + + /* 'alarm' [R/W] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_ALARM)); + else { + entry->read_proc = acpi_system_read_alarm; + entry->write_proc = acpi_system_write_alarm; + entry->data = acpi_driver_data(device); + } + +#endif /*CONFIG_ACPI_SLEEP*/ + +#ifdef ACPI_DEBUG + + /* 'debug_layer' [R/W] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_DEBUG_LAYER)); + else { + entry->read_proc = acpi_system_read_debug; + entry->write_proc = acpi_system_write_debug; + entry->data = (void *) 0; + } + + /* 'debug_level' [R/W] */ + entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_SYSTEM_FILE_DEBUG_LEVEL)); + else { + entry->read_proc = acpi_system_read_debug; + entry->write_proc = acpi_system_write_debug; + entry->data = (void *) 1; + } + +#endif /*ACPI_DEBUG*/ + + return_VALUE(0); +} + + +static int +acpi_system_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_system_remove_fs"); + + if (!device) + return_VALUE(-EINVAL); + + remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_device_dir(device)); + remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_device_dir(device)); + remove_proc_entry(ACPI_SYSTEM_FILE_EVENT, acpi_device_dir(device)); +#ifdef CONFIG_ACPI_SLEEP + remove_proc_entry(ACPI_SYSTEM_FILE_SLEEP, acpi_device_dir(device)); + remove_proc_entry(ACPI_SYSTEM_FILE_ALARM, acpi_device_dir(device)); +#endif +#ifdef ACPI_DEBUG + remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, + acpi_device_dir(device)); + remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, + acpi_device_dir(device)); +#endif + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM) + +/* Simple wrapper calling power down function. */ +static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) +{ + acpi_power_off(); +} + +struct sysrq_key_op sysrq_acpi_poweroff_op = { + handler: &acpi_sysrq_power_off, + help_msg: "Off", + action_msg: "Power Off\n" +}; + +#endif /* CONFIG_MAGIC_SYSRQ */ + +static int +acpi_system_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_system *system = NULL; + u8 i = 0; + + ACPI_FUNCTION_TRACE("acpi_system_add"); + + if (!device) + return_VALUE(-EINVAL); + + system = kmalloc(sizeof(struct acpi_system), GFP_KERNEL); + if (!system) + return_VALUE(-ENOMEM); + memset(system, 0, sizeof(struct acpi_system)); + + system->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_SYSTEM_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_SYSTEM_CLASS); + acpi_driver_data(device) = system; + + result = acpi_system_add_fs(device); + if (0 != result) + goto end; + + printk(KERN_INFO PREFIX "%s [%s] (supports", + acpi_device_name(device), acpi_device_bid(device)); + for (i=0; istates[i] = 1; + printk(" S%d", i); + } + } + printk(")\n"); + +#ifdef CONFIG_PM + /* Install the soft-off (S5) handler. */ + if (system->states[ACPI_STATE_S5]) { + pm_power_off = acpi_power_off; + register_sysrq_key('o', &sysrq_acpi_poweroff_op); + } +#endif + +end: + if (0 != result) + kfree(system); + + return_VALUE(result); +} + + +static int +acpi_system_remove ( + struct acpi_device *device, + int type) +{ + struct acpi_system *system = NULL; + + ACPI_FUNCTION_TRACE("acpi_system_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + system = (struct acpi_system *) acpi_driver_data(device); + +#ifdef CONFIG_PM + /* Remove the soft-off (S5) handler. */ + if (system->states[ACPI_STATE_S5]) { + unregister_sysrq_key('o', &sysrq_acpi_poweroff_op); + pm_power_off = NULL; + } +#endif + + acpi_system_remove_fs(device); + + kfree(system); + + return 0; +} + + +int __init +acpi_system_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_system_init"); + + result = acpi_bus_register_driver(&acpi_system_driver); + if (0 > result) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +void __exit +acpi_system_exit (void) +{ + ACPI_FUNCTION_TRACE("acpi_system_exit"); + acpi_bus_unregister_driver(&acpi_system_driver); + return_VOID; +} diff -Nur linux-2.4.19/drivers/acpi/tables/Makefile linux-2.4.19-sgi211r3/drivers/acpi/tables/Makefile --- linux-2.4.19/drivers/acpi/tables/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/tables/tbconvrt.c linux-2.4.19-sgi211r3/drivers/acpi/tables/tbconvrt.c --- linux-2.4.19/drivers/acpi/tables/tbconvrt.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables/tbconvrt.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbconvrt - ACPI Table conversion utilities - * $Revision: 28 $ + * $Revision: 41 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,11 @@ #include "acpi.h" -#include "achware.h" #include "actables.h" -#include "actbl.h" #define _COMPONENT ACPI_TABLES - MODULE_NAME ("tbconvrt") + ACPI_MODULE_NAME ("tbconvrt") /******************************************************************************* @@ -54,15 +52,14 @@ u32 pointer_size; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); -#ifndef _IA64 +#if ACPI_MACHINE_WIDTH != 64 if (RSDP->revision < 2) { pointer_size = sizeof (u32); } - else #endif { @@ -96,21 +93,21 @@ acpi_table_desc *table_info, u32 *number_of_tables) { - u32 table_size; + ACPI_SIZE table_size; u32 i; xsdt_descriptor *new_table; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - *number_of_tables = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info->pointer); + /* Get the number of tables defined in the RSDT or XSDT */ + *number_of_tables = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info->pointer); /* Compute size of the converted XSDT */ - table_size = (*number_of_tables * sizeof (u64)) + sizeof (acpi_table_header); - + table_size = ((ACPI_SIZE) *number_of_tables * sizeof (u64)) + sizeof (acpi_table_header); /* Allocate an XSDT */ @@ -121,20 +118,15 @@ /* Copy the header and set the length */ - MEMCPY (new_table, table_info->pointer, sizeof (acpi_table_header)); - new_table->header.length = table_size; + ACPI_MEMCPY (new_table, table_info->pointer, sizeof (acpi_table_header)); + new_table->header.length = (u32) table_size; /* Copy the table pointers */ for (i = 0; i < *number_of_tables; i++) { if (acpi_gbl_RSDP->revision < 2) { -#ifdef _IA64 - new_table->table_offset_entry[i] = - ((RSDT_DESCRIPTOR_REV071 *) table_info->pointer)->table_offset_entry[i]; -#else ACPI_STORE_ADDRESS (new_table->table_offset_entry[i], ((RSDT_DESCRIPTOR_REV1 *) table_info->pointer)->table_offset_entry[i]); -#endif } else { new_table->table_offset_entry[i] = @@ -142,12 +134,10 @@ } } - /* Delete the original table (either mapped or in a buffer) */ acpi_tb_delete_single_table (table_info); - /* Point the table descriptor to the new table */ table_info->pointer = (acpi_table_header *) new_table; @@ -161,325 +151,254 @@ /******************************************************************************* * - * FUNCTION: Acpi_tb_convert_table_fadt + * FUNCTION: Acpi_tb_convert_fadt1 * - * PARAMETERS: + * PARAMETERS: Local_fadt - Pointer to new FADT + * Original_fadt - Pointer to old FADT * - * RETURN: + * RETURN: Populates Local_fadt * - * DESCRIPTION: - * Converts BIOS supplied 1.0 and 0.71 ACPI FADT to an intermediate - * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply - * copied to the intermediate FADT. The ACPI CA software uses this - * intermediate FADT. Thus a significant amount of special #ifdef - * type codeing is saved. This intermediate FADT will need to be - * freed at some point. + * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format * ******************************************************************************/ -acpi_status -acpi_tb_convert_table_fadt (void) +static void +acpi_tb_convert_fadt1 ( + fadt_descriptor_rev2 *local_fadt, + fadt_descriptor_rev1 *original_fadt) { -#ifdef _IA64 - fadt_descriptor_rev071 *FADT71; - u8 pm1_address_space; - u8 pm2_address_space; - u8 pm_timer_address_space; - u8 gpe0address_space; - u8 gpe1_address_space; -#else - fadt_descriptor_rev1 *FADT1; -#endif - - fadt_descriptor_rev2 *FADT2; - acpi_table_desc *table_desc; - - - FUNCTION_TRACE ("Tb_convert_table_fadt"); - - - /* Acpi_gbl_FADT is valid */ - /* Allocate and zero the 2.0 buffer */ - - FADT2 = ACPI_MEM_CALLOCATE (sizeof (fadt_descriptor_rev2)); - if (FADT2 == NULL) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - - /* The ACPI FADT revision number is FADT2_REVISION_ID=3 */ - /* So, if the current table revision is less than 3 it is type 1.0 or 0.71 */ - - if (acpi_gbl_FADT->header.revision >= FADT2_REVISION_ID) { - /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */ - - *FADT2 = *((fadt_descriptor_rev2*) acpi_gbl_FADT); - - } - - else { - -#ifdef _IA64 - /* - * For the 64-bit case only, a revision ID less than V2.0 means the - * tables are the 0.71 extensions - */ - - /* The BIOS stored FADT should agree with Revision 0.71 */ - - FADT71 = (fadt_descriptor_rev071 *) acpi_gbl_FADT; - - /* Copy the table header*/ - - FADT2->header = FADT71->header; - - /* Copy the common fields */ - - FADT2->sci_int = FADT71->sci_int; - FADT2->acpi_enable = FADT71->acpi_enable; - FADT2->acpi_disable = FADT71->acpi_disable; - FADT2->S4bios_req = FADT71->S4bios_req; - FADT2->plvl2_lat = FADT71->plvl2_lat; - FADT2->plvl3_lat = FADT71->plvl3_lat; - FADT2->day_alrm = FADT71->day_alrm; - FADT2->mon_alrm = FADT71->mon_alrm; - FADT2->century = FADT71->century; - FADT2->gpe1_base = FADT71->gpe1_base; - - /* - * We still use the block length registers even though - * the GAS structure should obsolete them. This is because - * these registers are byte lengths versus the GAS which - * contains a bit width - */ - FADT2->pm1_evt_len = FADT71->pm1_evt_len; - FADT2->pm1_cnt_len = FADT71->pm1_cnt_len; - FADT2->pm2_cnt_len = FADT71->pm2_cnt_len; - FADT2->pm_tm_len = FADT71->pm_tm_len; - FADT2->gpe0blk_len = FADT71->gpe0blk_len; - FADT2->gpe1_blk_len = FADT71->gpe1_blk_len; - FADT2->gpe1_base = FADT71->gpe1_base; - - /* Copy the existing 0.71 flags to 2.0. The other bits are zero.*/ - - FADT2->wb_invd = FADT71->flush_cash; - FADT2->proc_c1 = FADT71->proc_c1; - FADT2->plvl2_up = FADT71->plvl2_up; - FADT2->pwr_button = FADT71->pwr_button; - FADT2->sleep_button = FADT71->sleep_button; - FADT2->fixed_rTC = FADT71->fixed_rTC; - FADT2->rtcs4 = FADT71->rtcs4; - FADT2->tmr_val_ext = FADT71->tmr_val_ext; - FADT2->dock_cap = FADT71->dock_cap; - - - /* We should not use these next two addresses */ - /* Since our buffer is pre-zeroed nothing to do for */ - /* the next three data items in the structure */ - /* FADT2->Firmware_ctrl = 0; */ - /* FADT2->Dsdt = 0; */ - - /* System Interrupt Model isn't used in ACPI 2.0*/ - /* FADT2->Reserved1 = 0; */ - - /* This field is set by the OEM to convey the preferred */ - /* power management profile to OSPM. It doesn't have any*/ - /* 0.71 equivalence. Since we don't know what kind of */ - /* 64-bit system this is, we will pick unspecified. */ - - FADT2->prefer_PM_profile = PM_UNSPECIFIED; - - - /* Port address of SMI command port */ - /* We shouldn't use this port because IA64 doesn't */ - /* have or use SMI. It has PMI. */ - - FADT2->smi_cmd = (u32)(FADT71->smi_cmd & 0xFFFFFFFF); - - /* processor performance state control*/ - /* The value OSPM writes to the SMI_CMD register to assume */ - /* processor performance state control responsibility. */ - /* There isn't any equivalence in 0.71 */ - /* Again this should be meaningless for IA64 */ - /* FADT2->Pstate_cnt = 0; */ + /* ACPI 1.0 FACS */ + /* The BIOS stored FADT should agree with Revision 1.0 */ - /* The 32-bit Power management and GPE registers are */ - /* not valid in IA-64 and we are not going to use them */ - /* so leaving them pre-zeroed. */ - - /* Support for the _CST object and C States change notification.*/ - /* This data item hasn't any 0.71 equivalence so leaving it zero.*/ - /* FADT2->Cst_cnt = 0; */ - - /* number of flush strides that need to be read */ - /* No 0.71 equivalence. Leave pre-zeroed. */ - /* FADT2->Flush_size = 0; */ - - /* Processor's memory cache line width, in bytes */ - /* No 0.71 equivalence. Leave pre-zeroed. */ - /* FADT2->Flush_stride = 0; */ - - /* Processor's duty cycle index in processor's P_CNT reg*/ - /* No 0.71 equivalence. Leave pre-zeroed. */ - /* FADT2->Duty_offset = 0; */ + /* + * Copy the table header and the common part of the tables. + * + * The 2.0 table is an extension of the 1.0 table, so the entire 1.0 + * table can be copied first, then expand some fields to 64 bits. + */ + ACPI_MEMCPY (local_fadt, original_fadt, sizeof (fadt_descriptor_rev1)); - /* Processor's duty cycle value bit width in P_CNT register.*/ - /* No 0.71 equivalence. Leave pre-zeroed. */ - /* FADT2->Duty_width = 0; */ + /* Convert table pointers to 64-bit fields */ + ACPI_STORE_ADDRESS (local_fadt->Xfirmware_ctrl, local_fadt->V1_firmware_ctrl); + ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); - /* Since there isn't any equivalence in 0.71 */ - /* and since Big_sur had to support legacy */ + /* + * System Interrupt Model isn't used in ACPI 2.0 (Local_fadt->Reserved1 = 0;) + */ - FADT2->iapc_boot_arch = BAF_LEGACY_DEVICES; + /* + * This field is set by the OEM to convey the preferred power management + * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't + * know what kind of 32-bit system this is, we will use "unspecified". + */ + local_fadt->prefer_PM_profile = PM_UNSPECIFIED; - /* Copy to ACPI 2.0 64-BIT Extended Addresses */ + /* + * Processor Performance State Control. This is the value OSPM writes to + * the SMI_CMD register to assume processor performance state control + * responsibility. There isn't any equivalence in 1.0, leave it zeroed. + */ + local_fadt->pstate_cnt = 0; - FADT2->Xfirmware_ctrl = FADT71->firmware_ctrl; - FADT2->Xdsdt = FADT71->dsdt; + /* + * Support for the _CST object and C States change notification. + * This data item hasn't any 1.0 equivalence so leave it zero. + */ + local_fadt->cst_cnt = 0; + /* + * Since there isn't any equivalence in 1.0 and since it highly likely + * that a 1.0 system has legacy support. + */ + local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES; - /* Extract the address space IDs */ + /* + * Convert the V1.0 block addresses to V2.0 GAS structures + */ + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1a_evt_blk, local_fadt->pm1_evt_len, local_fadt->V1_pm1a_evt_blk); + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1b_evt_blk, local_fadt->pm1_evt_len, local_fadt->V1_pm1b_evt_blk); + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1a_cnt_blk, local_fadt->pm1_cnt_len, local_fadt->V1_pm1a_cnt_blk); + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1b_cnt_blk, local_fadt->pm1_cnt_len, local_fadt->V1_pm1b_cnt_blk); + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm2_cnt_blk, local_fadt->pm2_cnt_len, local_fadt->V1_pm2_cnt_blk); + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm_tmr_blk, local_fadt->pm_tm_len, local_fadt->V1_pm_tmr_blk); + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xgpe0_blk, local_fadt->gpe0_blk_len, local_fadt->V1_gpe0_blk); + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xgpe1_blk, local_fadt->gpe1_blk_len, local_fadt->V1_gpe1_blk); - pm1_address_space = (u8)((FADT71->address_space & PM1_BLK_ADDRESS_SPACE) >> 1); - pm2_address_space = (u8)((FADT71->address_space & PM2_CNT_BLK_ADDRESS_SPACE) >> 2); - pm_timer_address_space = (u8)((FADT71->address_space & PM_TMR_BLK_ADDRESS_SPACE) >> 3); - gpe0address_space = (u8)((FADT71->address_space & GPE0_BLK_ADDRESS_SPACE) >> 4); - gpe1_address_space = (u8)((FADT71->address_space & GPE1_BLK_ADDRESS_SPACE) >> 5); +} - /* - * Convert the 0.71 (non-GAS style) Block addresses to V2.0 GAS structures, - * in this order: - * - * PM 1_a Events - * PM 1_b Events - * PM 1_a Control - * PM 1_b Control - * PM 2 Control - * PM Timer Control - * GPE Block 0 - * GPE Block 1 - */ - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xpm1a_evt_blk, FADT71->pm1_evt_len, FADT71->pm1a_evt_blk, pm1_address_space); - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xpm1b_evt_blk, FADT71->pm1_evt_len, FADT71->pm1b_evt_blk, pm1_address_space); - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xpm1a_cnt_blk, FADT71->pm1_cnt_len, FADT71->pm1a_cnt_blk, pm1_address_space); - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xpm1b_cnt_blk, FADT71->pm1_cnt_len, FADT71->pm1b_cnt_blk, pm1_address_space); - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xpm2_cnt_blk, FADT71->pm2_cnt_len, FADT71->pm2_cnt_blk, pm2_address_space); - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xpm_tmr_blk, FADT71->pm_tm_len, FADT71->pm_tmr_blk, pm_timer_address_space); - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xgpe0blk, FADT71->gpe0blk_len, FADT71->gpe0blk, gpe0address_space); - ASL_BUILD_GAS_FROM_ENTRY (FADT2->Xgpe1_blk, FADT71->gpe1_blk_len, FADT71->gpe1_blk, gpe1_address_space); +/******************************************************************************* + * + * FUNCTION: Acpi_tb_convert_fadt2 + * + * PARAMETERS: Local_fadt - Pointer to new FADT + * Original_fadt - Pointer to old FADT + * + * RETURN: Populates Local_fadt + * + * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format. + * Handles optional "X" fields. + * + ******************************************************************************/ -#else +static void +acpi_tb_convert_fadt2 ( + fadt_descriptor_rev2 *local_fadt, + fadt_descriptor_rev2 *original_fadt) +{ - /* ACPI 1.0 FACS */ + /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */ + ACPI_MEMCPY (local_fadt, original_fadt, sizeof (fadt_descriptor_rev2)); - /* The BIOS stored FADT should agree with Revision 1.0 */ + /* + * "X" fields are optional extensions to the original V1.0 fields, so + * we must selectively expand V1.0 fields if the corresponding X field + * is zero. + */ + if (!(ACPI_GET_ADDRESS (local_fadt->Xfirmware_ctrl))) { + ACPI_STORE_ADDRESS (local_fadt->Xfirmware_ctrl, local_fadt->V1_firmware_ctrl); + } - FADT1 = (fadt_descriptor_rev1*) acpi_gbl_FADT; + if (!(ACPI_GET_ADDRESS (local_fadt->Xdsdt))) { + ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); + } - /* - * Copy the table header and the common part of the tables - * The 2.0 table is an extension of the 1.0 table, so the - * entire 1.0 table can be copied first, then expand some - * fields to 64 bits. - */ - MEMCPY (FADT2, FADT1, sizeof (fadt_descriptor_rev1)); + if (!(ACPI_GET_ADDRESS (local_fadt->Xpm1a_evt_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1a_evt_blk, + local_fadt->pm1_evt_len, local_fadt->V1_pm1a_evt_blk); + } + if (!(ACPI_GET_ADDRESS (local_fadt->Xpm1b_evt_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1b_evt_blk, + local_fadt->pm1_evt_len, local_fadt->V1_pm1b_evt_blk); + } - /* Convert table pointers to 64-bit fields */ + if (!(ACPI_GET_ADDRESS (local_fadt->Xpm1a_cnt_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1a_cnt_blk, + local_fadt->pm1_cnt_len, local_fadt->V1_pm1a_cnt_blk); + } - ACPI_STORE_ADDRESS (FADT2->Xfirmware_ctrl, FADT1->firmware_ctrl); - ACPI_STORE_ADDRESS (FADT2->Xdsdt, FADT1->dsdt); + if (!(ACPI_GET_ADDRESS (local_fadt->Xpm1b_cnt_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm1b_cnt_blk, + local_fadt->pm1_cnt_len, local_fadt->V1_pm1b_cnt_blk); + } - /* System Interrupt Model isn't used in ACPI 2.0*/ - /* FADT2->Reserved1 = 0; */ + if (!(ACPI_GET_ADDRESS (local_fadt->Xpm2_cnt_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm2_cnt_blk, + local_fadt->pm2_cnt_len, local_fadt->V1_pm2_cnt_blk); + } - /* This field is set by the OEM to convey the preferred */ - /* power management profile to OSPM. It doesn't have any*/ - /* 1.0 equivalence. Since we don't know what kind of */ - /* 32-bit system this is, we will pick unspecified. */ + if (!(ACPI_GET_ADDRESS (local_fadt->Xpm_tmr_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xpm_tmr_blk, + local_fadt->pm_tm_len, local_fadt->V1_pm_tmr_blk); + } - FADT2->prefer_PM_profile = PM_UNSPECIFIED; + if (!(ACPI_GET_ADDRESS (local_fadt->Xgpe0_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xgpe0_blk, + local_fadt->gpe0_blk_len, local_fadt->V1_gpe0_blk); + } + if (!(ACPI_GET_ADDRESS (local_fadt->Xgpe1_blk.address))) { + ASL_BUILD_GAS_FROM_V1_ENTRY (local_fadt->Xgpe1_blk, + local_fadt->gpe1_blk_len, local_fadt->V1_gpe1_blk); + } +} - /* Processor Performance State Control. This is the value */ - /* OSPM writes to the SMI_CMD register to assume processor */ - /* performance state control responsibility. There isn't */ - /* any equivalence in 1.0. So leave it zeroed. */ +/******************************************************************************* + * + * FUNCTION: Acpi_tb_convert_table_fadt + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: + * Converts a BIOS supplied ACPI 1.0 FADT to an intermediate + * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply + * copied to the intermediate FADT. The ACPI CA software uses this + * intermediate FADT. Thus a significant amount of special #ifdef + * type codeing is saved. This intermediate FADT will need to be + * freed at some point. + * + ******************************************************************************/ - FADT2->pstate_cnt = 0; +acpi_status +acpi_tb_convert_table_fadt (void) +{ + fadt_descriptor_rev2 *local_fadt; + acpi_table_desc *table_desc; - /* Support for the _CST object and C States change notification.*/ - /* This data item hasn't any 1.0 equivalence so leaving it zero.*/ + ACPI_FUNCTION_TRACE ("Tb_convert_table_fadt"); - FADT2->cst_cnt = 0; + /* + * Acpi_gbl_FADT is valid + * Allocate and zero the 2.0 FADT buffer + */ + local_fadt = ACPI_MEM_CALLOCATE (sizeof (fadt_descriptor_rev2)); + if (local_fadt == NULL) { + return_ACPI_STATUS (AE_NO_MEMORY); + } - /* Since there isn't any equivalence in 1.0 and since it */ - /* is highly likely that a 1.0 system has legacy support. */ + /* + * FADT length and version validation. The table must be at least as + * long as the version 1.0 FADT + */ + if (acpi_gbl_FADT->header.length < sizeof (fadt_descriptor_rev1)) { + ACPI_REPORT_ERROR (("Invalid FADT table length: 0x%X\n", acpi_gbl_FADT->header.length)); + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); + } - FADT2->iapc_boot_arch = BAF_LEGACY_DEVICES; + if (acpi_gbl_FADT->header.revision >= FADT2_REVISION_ID) { + if (acpi_gbl_FADT->header.length < sizeof (fadt_descriptor_rev2)) { + /* Length is too short to be a V2.0 table */ + ACPI_REPORT_WARNING (("Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n", + acpi_gbl_FADT->header.length, acpi_gbl_FADT->header.revision)); - /* - * Convert the V1.0 Block addresses to V2.0 GAS structures - * in this order: - * - * PM 1_a Events - * PM 1_b Events - * PM 1_a Control - * PM 1_b Control - * PM 2 Control - * PM Timer Control - * GPE Block 0 - * GPE Block 1 - */ + acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); + } + else { + /* Valid V2.0 table */ - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xpm1a_evt_blk, FADT1->pm1_evt_len, FADT1->pm1a_evt_blk); - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xpm1b_evt_blk, FADT1->pm1_evt_len, FADT1->pm1b_evt_blk); - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xpm1a_cnt_blk, FADT1->pm1_cnt_len, FADT1->pm1a_cnt_blk); - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xpm1b_cnt_blk, FADT1->pm1_cnt_len, FADT1->pm1b_cnt_blk); - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xpm2_cnt_blk, FADT1->pm2_cnt_len, FADT1->pm2_cnt_blk); - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xpm_tmr_blk, FADT1->pm_tm_len, FADT1->pm_tmr_blk); - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xgpe0blk, FADT1->gpe0blk_len, FADT1->gpe0blk); - ASL_BUILD_GAS_FROM_V1_ENTRY (FADT2->Xgpe1_blk, FADT1->gpe1_blk_len, FADT1->gpe1_blk); -#endif + acpi_tb_convert_fadt2 (local_fadt, acpi_gbl_FADT); + } } + else { + /* Valid V1.0 table */ + acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); + } /* - * Global FADT pointer will point to the common V2.0 FADT + * Global FADT pointer will point to the new common V2.0 FADT */ - acpi_gbl_FADT = FADT2; + acpi_gbl_FADT = local_fadt; acpi_gbl_FADT->header.length = sizeof (FADT_DESCRIPTOR); - /* Free the original table */ table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_FADT]; acpi_tb_delete_single_table (table_desc); - /* Install the new table */ - table_desc->pointer = (acpi_table_header *) acpi_gbl_FADT; + table_desc->pointer = (acpi_table_header *) acpi_gbl_FADT; table_desc->base_pointer = acpi_gbl_FADT; - table_desc->allocation = ACPI_MEM_ALLOCATED; - table_desc->length = sizeof (fadt_descriptor_rev2); - + table_desc->allocation = ACPI_MEM_ALLOCATED; + table_desc->length = sizeof (fadt_descriptor_rev2); /* Dump the entire FADT */ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Hex dump of common internal FADT, size %d (%X)\n", acpi_gbl_FADT->header.length, acpi_gbl_FADT->header.length)); - DUMP_BUFFER ((u8 *) (acpi_gbl_FADT), acpi_gbl_FADT->header.length); - + ACPI_DUMP_BUFFER ((u8 *) (acpi_gbl_FADT), acpi_gbl_FADT->header.length); return_ACPI_STATUS (AE_OK); } @@ -489,11 +408,12 @@ * * FUNCTION: Acpi_tb_convert_table_facs * - * PARAMETERS: + * PARAMETERS: Table_info - Info for currently installad FACS * - * RETURN: + * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal + * table format. * ******************************************************************************/ @@ -501,68 +421,42 @@ acpi_tb_build_common_facs ( acpi_table_desc *table_info) { - acpi_common_facs *common_facs; - -#ifdef _IA64 - facs_descriptor_rev071 *FACS71; -#else - facs_descriptor_rev1 *FACS1; -#endif - facs_descriptor_rev2 *FACS2; + ACPI_FUNCTION_TRACE ("Tb_build_common_facs"); - FUNCTION_TRACE ("Tb_build_common_facs"); + /* Absolute minimum length is 24, but the ACPI spec says 64 */ - - /* Allocate a common FACS */ - - common_facs = ACPI_MEM_CALLOCATE (sizeof (acpi_common_facs)); - if (!common_facs) { - return_ACPI_STATUS (AE_NO_MEMORY); + if (acpi_gbl_FACS->length < 24) { + ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", acpi_gbl_FACS->length)); + return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } + if (acpi_gbl_FACS->length < 64) { + ACPI_REPORT_WARNING (("FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n", + acpi_gbl_FACS->length)); + } /* Copy fields to the new FACS */ - if (acpi_gbl_RSDP->revision < 2) { -#ifdef _IA64 - /* 0.71 FACS */ - - FACS71 = (facs_descriptor_rev071 *) acpi_gbl_FACS; - - common_facs->global_lock = (u32 *) &(FACS71->global_lock); - common_facs->firmware_waking_vector = &FACS71->firmware_waking_vector; - common_facs->vector_width = 64; -#else - /* ACPI 1.0 FACS */ - - FACS1 = (facs_descriptor_rev1 *) acpi_gbl_FACS; - - common_facs->global_lock = &(FACS1->global_lock); - common_facs->firmware_waking_vector = (u64 *) &FACS1->firmware_waking_vector; - common_facs->vector_width = 32; + acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock); -#endif - } + if ((acpi_gbl_RSDP->revision < 2) || + (acpi_gbl_FACS->length < 32) || + (!(ACPI_GET_ADDRESS (acpi_gbl_FACS->Xfirmware_waking_vector)))) { + /* ACPI 1.0 FACS or short table or optional X_ field is zero */ + acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, &(acpi_gbl_FACS->firmware_waking_vector)); + acpi_gbl_common_fACS.vector_width = 32; + } else { - /* ACPI 2.0 FACS */ + /* ACPI 2.0 FACS with valid X_ field */ - FACS2 = (facs_descriptor_rev2 *) acpi_gbl_FACS; - - common_facs->global_lock = &(FACS2->global_lock); - common_facs->firmware_waking_vector = &FACS2->Xfirmware_waking_vector; - common_facs->vector_width = 64; + acpi_gbl_common_fACS.firmware_waking_vector = &acpi_gbl_FACS->Xfirmware_waking_vector; + acpi_gbl_common_fACS.vector_width = 64; } - - /* Set the global FACS pointer to point to the common FACS */ - - - acpi_gbl_FACS = common_facs; - - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/tables/tbget.c linux-2.4.19-sgi211r3/drivers/acpi/tables/tbget.c --- linux-2.4.19/drivers/acpi/tables/tbget.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables/tbget.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbget - ACPI Table get* routines - * $Revision: 56 $ + * $Revision: 77 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +25,128 @@ #include "acpi.h" -#include "achware.h" #include "actables.h" #define _COMPONENT ACPI_TABLES - MODULE_NAME ("tbget") + ACPI_MODULE_NAME ("tbget") -#define RSDP_CHECKSUM_LENGTH 20 + +/******************************************************************************* + * + * FUNCTION: Acpi_tb_table_override + * + * PARAMETERS: *Table_info - Info for current table + * + * RETURN: None + * + * DESCRIPTION: Attempts override of current table with a new one if provided + * by the host OS. + * + ******************************************************************************/ + +void +acpi_tb_table_override ( + acpi_table_desc *table_info) +{ + acpi_table_header *new_table; + acpi_status status; + ACPI_POINTER address; + acpi_table_desc new_table_info; + + + ACPI_FUNCTION_TRACE ("Acpi_tb_table_override"); + + + status = acpi_os_table_override (table_info->pointer, &new_table); + if (ACPI_FAILURE (status)) { + /* Some severe error from the OSL, but we basically ignore it */ + + ACPI_REPORT_ERROR (("Could not override ACPI table, %s\n", + acpi_format_exception (status))); + return_VOID; + } + + if (!new_table) { + /* No table override */ + + return_VOID; + } + + /* + * We have a new table to override the old one. Get a copy of + * the new one. We know that the new table has a logical pointer. + */ + address.pointer_type = ACPI_LOGICAL_POINTER; + address.pointer.logical = new_table; + + status = acpi_tb_get_table (&address, &new_table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not copy ACPI table override\n")); + return_VOID; + } + + /* + * Delete the original table + */ + acpi_tb_delete_single_table (table_info); + + /* Copy the table info */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Successful table override [%4.4s]\n", + ((acpi_table_header *) new_table_info.pointer)->signature)); + + ACPI_MEMCPY (table_info, &new_table_info, sizeof (acpi_table_desc)); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_tb_get_table_with_override + * + * PARAMETERS: Address - Physical or logical address of table + * *Table_info - Where the table info is returned + * + * RETURN: Status + * + * DESCRIPTION: Gets and installs the table with possible table override by OS. + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_table_with_override ( + ACPI_POINTER *address, + acpi_table_desc *table_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Acpi_tb_get_table_with_override"); + + + status = acpi_tb_get_table (address, table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not get ACPI table, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + + /* + * Attempt override. It either happens or it doesn't, no status + */ + acpi_tb_table_override (table_info); + + /* Install the table */ + + status = acpi_tb_install_table (table_info); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not install ACPI table, %s\n", + acpi_format_exception (status))); + } + + return_ACPI_STATUS (status); +} /******************************************************************************* @@ -60,7 +174,7 @@ u32 i; - FUNCTION_TRACE ("Tb_get_table_ptr"); + ACPI_FUNCTION_TRACE ("Tb_get_table_ptr"); if (!acpi_gbl_DSDT) { @@ -71,7 +185,6 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* * For all table types (Single/Multiple), the first * instance is always in the list head. @@ -85,7 +198,6 @@ return_ACPI_STATUS (AE_OK); } - /* * Check for instance out of range */ @@ -117,10 +229,8 @@ * * FUNCTION: Acpi_tb_get_table * - * PARAMETERS: Physical_address - Physical address of table to retrieve - * *Buffer_ptr - If Buffer_ptr is valid, read data from - * buffer rather than searching memory - * *Table_info - Where the table info is returned + * PARAMETERS: Address - Physical address of table to retrieve + * *Table_info - Where the table info is returned * * RETURN: Status * @@ -130,36 +240,30 @@ acpi_status acpi_tb_get_table ( - ACPI_PHYSICAL_ADDRESS physical_address, - acpi_table_header *buffer_ptr, + ACPI_POINTER *address, acpi_table_desc *table_info) { acpi_table_header *table_header = NULL; acpi_table_header *full_table = NULL; - u32 size; + ACPI_SIZE size; u8 allocation; acpi_status status = AE_OK; - FUNCTION_TRACE ("Tb_get_table"); + ACPI_FUNCTION_TRACE ("Tb_get_table"); - if (!table_info) { + if (!table_info || !address) { return_ACPI_STATUS (AE_BAD_PARAMETER); } + switch (address->pointer_type) { + case ACPI_LOGICAL_POINTER: - if (buffer_ptr) { /* * Getting data from a buffer, not BIOS tables */ - table_header = buffer_ptr; - status = acpi_tb_validate_table_header (table_header); - if (ACPI_FAILURE (status)) { - /* Table failed verification, map all errors to BAD_DATA */ - - return_ACPI_STATUS (AE_BAD_DATA); - } + table_header = address->pointer.logical; /* Allocate buffer for the entire table */ @@ -170,23 +274,24 @@ /* Copy the entire table (including header) to the local buffer */ - size = table_header->length; - MEMCPY (full_table, buffer_ptr, size); + size = (ACPI_SIZE) table_header->length; + ACPI_MEMCPY (full_table, table_header, size); /* Save allocation type */ allocation = ACPI_MEM_ALLOCATED; - } + break; - /* - * Not reading from a buffer, just map the table's physical memory - * into our address space. - */ - else { + case ACPI_PHYSICAL_POINTER: + + /* + * Not reading from a buffer, just map the table's physical memory + * into our address space. + */ size = SIZE_IN_HEADER; - status = acpi_tb_map_acpi_table (physical_address, &size, &full_table); + status = acpi_tb_map_acpi_table (address->pointer.physical, &size, &full_table); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -194,9 +299,13 @@ /* Save allocation type */ allocation = ACPI_MEM_MAPPED; - } + break; + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + /* Return values */ table_info->pointer = full_table; @@ -204,6 +313,12 @@ table_info->allocation = allocation; table_info->base_pointer = full_table; + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n", + full_table->signature, + ACPI_HIDWORD (address->pointer.physical), + ACPI_LODWORD (address->pointer.physical), full_table)); + return_ACPI_STATUS (status); } @@ -213,26 +328,31 @@ * FUNCTION: Acpi_tb_get_all_tables * * PARAMETERS: Number_of_tables - Number of tables to get - * Table_ptr - Input buffer pointer, optional * * RETURN: Status * - * DESCRIPTION: Load and validate all tables other than the RSDT. The RSDT must + * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must * already be loaded and validated. * + * Get the minimum set of ACPI tables, namely: + * + * 1) FADT (via RSDT in loop below) + * 2) FACS (via FADT) + * 3) DSDT (via FADT) + * ******************************************************************************/ acpi_status acpi_tb_get_all_tables ( - u32 number_of_tables, - acpi_table_header *table_ptr) + u32 number_of_tables) { acpi_status status = AE_OK; u32 index; acpi_table_desc table_info; + ACPI_POINTER address; - FUNCTION_TRACE ("Tb_get_all_tables"); + ACPI_FUNCTION_TRACE ("Tb_get_all_tables"); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Number of tables: %d\n", number_of_tables)); @@ -240,44 +360,43 @@ /* * Loop through all table pointers found in RSDT. * This will NOT include the FACS and DSDT - we must get - * them after the loop + * them after the loop. + * + * The ONLY table we are interested in getting here is the FADT. */ for (index = 0; index < number_of_tables; index++) { /* Clear the Table_info each time */ - MEMSET (&table_info, 0, sizeof (acpi_table_desc)); + ACPI_MEMSET (&table_info, 0, sizeof (acpi_table_desc)); /* Get the table via the XSDT */ - status = acpi_tb_get_table ((ACPI_PHYSICAL_ADDRESS) - ACPI_GET_ADDRESS (acpi_gbl_XSDT->table_offset_entry[index]), - table_ptr, &table_info); - - /* Ignore a table that failed verification */ - - if (status == AE_BAD_DATA) { - continue; - } - - /* However, abort on serious errors */ + address.pointer_type = acpi_gbl_table_flags; + address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_XSDT->table_offset_entry[index]); + status = acpi_tb_get_table (&address, &table_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Recognize and install the table */ - status = acpi_tb_install_table (table_ptr, &table_info); + status = acpi_tb_install_table (&table_info); if (ACPI_FAILURE (status)) { /* * Unrecognized or unsupported table, delete it and ignore the * error. Just get as many tables as we can, later we will * determine if there are enough tables to continue. */ - acpi_tb_uninstall_table (&table_info); + (void) acpi_tb_uninstall_table (&table_info); + status = AE_OK; } } + if (!acpi_gbl_FADT) { + ACPI_REPORT_ERROR (("No FADT present in R/XSDT\n")); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } /* * Convert the FADT to a common format. This allows earlier revisions of the @@ -285,32 +404,30 @@ */ status = acpi_tb_convert_table_fadt (); if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n")); return_ACPI_STATUS (status); } - - /* - * Get the minimum set of ACPI tables, namely: - * - * 1) FADT (via RSDT in loop above) - * 2) FACS - * 3) DSDT - * - */ - /* * Get the FACS (must have the FADT first, from loop above) * Acpi_tb_get_table_facs will fail if FADT pointer is not valid */ - status = acpi_tb_get_table_facs (table_ptr, &table_info); + address.pointer_type = acpi_gbl_table_flags; + address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xfirmware_ctrl); + + status = acpi_tb_get_table (&address, &table_info); if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not get the FACS, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } /* Install the FACS */ - status = acpi_tb_install_table (table_ptr, &table_info); + status = acpi_tb_install_table (&table_info); if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not install the FACS, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -323,46 +440,32 @@ return_ACPI_STATUS (status); } - /* - * Get the DSDT (We know that the FADT is valid now) + * Get/install the DSDT (We know that the FADT is valid now) */ - status = acpi_tb_get_table ((ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xdsdt), - table_ptr, &table_info); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - /* Install the DSDT */ + address.pointer_type = acpi_gbl_table_flags; + address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xdsdt); - status = acpi_tb_install_table (table_ptr, &table_info); + status = acpi_tb_get_table_with_override (&address, &table_info); if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not get the DSDT\n")); return_ACPI_STATUS (status); } - /* Dump the DSDT Header */ + /* Set Integer Width (32/64) based upon DSDT revision */ - ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Hex dump of DSDT Header:\n")); - DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, sizeof (acpi_table_header)); + acpi_ut_set_integer_width (acpi_gbl_DSDT->revision); /* Dump the entire DSDT */ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, - "Hex dump of DSDT (After header), size %d (%x)\n", - acpi_gbl_DSDT->length, acpi_gbl_DSDT->length)); - DUMP_BUFFER ((u8 *) (acpi_gbl_DSDT + 1), acpi_gbl_DSDT->length); - - /* - * Initialize the capabilities flags. - * Assumes that platform supports ACPI_MODE since we have tables! - */ - acpi_gbl_system_flags |= acpi_hw_get_mode_capabilities (); - + "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n", + acpi_gbl_DSDT->length, acpi_gbl_DSDT->length, acpi_gbl_integer_bit_width)); + ACPI_DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, acpi_gbl_DSDT->length); /* Always delete the RSDP mapping, we are done with it */ acpi_tb_delete_acpi_table (ACPI_TABLE_RSDP); - return_ACPI_STATUS (status); } @@ -381,50 +484,69 @@ acpi_status acpi_tb_verify_rsdp ( - ACPI_PHYSICAL_ADDRESS rsdp_physical_address) + ACPI_POINTER *address) { acpi_table_desc table_info; acpi_status status; - u8 *table_ptr; + RSDP_DESCRIPTOR *rsdp; - FUNCTION_TRACE ("Tb_verify_rsdp"); + ACPI_FUNCTION_TRACE ("Tb_verify_rsdp"); - /* - * Obtain access to the RSDP structure - */ - status = acpi_os_map_memory (rsdp_physical_address, sizeof (RSDP_DESCRIPTOR), - (void **) &table_ptr); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + switch (address->pointer_type) { + case ACPI_LOGICAL_POINTER: + + rsdp = address->pointer.logical; + break; + + case ACPI_PHYSICAL_POINTER: + /* + * Obtain access to the RSDP structure + */ + status = acpi_os_map_memory (address->pointer.physical, sizeof (RSDP_DESCRIPTOR), + (void **) &rsdp); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); } /* * The signature and checksum must both be correct */ - if (STRNCMP ((NATIVE_CHAR *) table_ptr, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + if (ACPI_STRNCMP ((NATIVE_CHAR *) rsdp, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { /* Nope, BAD Signature */ status = AE_BAD_SIGNATURE; goto cleanup; } - if (acpi_tb_checksum (table_ptr, RSDP_CHECKSUM_LENGTH) != 0) { - /* Nope, BAD Checksum */ + /* Check the standard checksum */ + if (acpi_tb_checksum (rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { status = AE_BAD_CHECKSUM; goto cleanup; } - /* TBD: Check extended checksum if table version >= 2 */ + /* Check extended checksum if table version >= 2 */ + + if (rsdp->revision >= 2) { + if (acpi_tb_checksum (rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) { + status = AE_BAD_CHECKSUM; + goto cleanup; + } + } /* The RSDP supplied is OK */ - table_info.pointer = (acpi_table_header *) table_ptr; + table_info.pointer = ACPI_CAST_PTR (acpi_table_header, rsdp); table_info.length = sizeof (RSDP_DESCRIPTOR); table_info.allocation = ACPI_MEM_MAPPED; - table_info.base_pointer = table_ptr; + table_info.base_pointer = rsdp; /* Save the table pointers and allocation info */ @@ -433,17 +555,18 @@ goto cleanup; } - /* Save the RSDP in a global for easy access */ - acpi_gbl_RSDP = (RSDP_DESCRIPTOR *) table_info.pointer; + acpi_gbl_RSDP = ACPI_CAST_PTR (RSDP_DESCRIPTOR, table_info.pointer); return_ACPI_STATUS (status); /* Error exit */ cleanup: - acpi_os_unmap_memory (table_ptr, sizeof (RSDP_DESCRIPTOR)); + if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) { + acpi_os_unmap_memory (rsdp, sizeof (RSDP_DESCRIPTOR)); + } return_ACPI_STATUS (status); } @@ -461,34 +584,26 @@ * ******************************************************************************/ -ACPI_PHYSICAL_ADDRESS -acpi_tb_get_rsdt_address (void) +void +acpi_tb_get_rsdt_address ( + ACPI_POINTER *out_address) { - ACPI_PHYSICAL_ADDRESS physical_address; + ACPI_FUNCTION_ENTRY (); - FUNCTION_ENTRY (); + out_address->pointer_type = acpi_gbl_table_flags; /* * For RSDP revision 0 or 1, we use the RSDT. * For RSDP revision 2 (and above), we use the XSDT */ if (acpi_gbl_RSDP->revision < 2) { -#ifdef _IA64 - /* 0.71 RSDP has 64bit Rsdt address field */ - physical_address = ((RSDP_DESCRIPTOR_REV071 *)acpi_gbl_RSDP)->rsdt_physical_address; -#else - physical_address = (ACPI_PHYSICAL_ADDRESS) acpi_gbl_RSDP->rsdt_physical_address; -#endif + out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address; } - else { - physical_address = (ACPI_PHYSICAL_ADDRESS) - ACPI_GET_ADDRESS (acpi_gbl_RSDP->xsdt_physical_address); + out_address->pointer.value = ACPI_GET_ADDRESS (acpi_gbl_RSDP->xsdt_physical_address); } - - return (physical_address); } @@ -508,36 +623,36 @@ acpi_tb_validate_rsdt ( acpi_table_header *table_ptr) { - u32 no_match; + int no_match; - PROC_NAME ("Tb_validate_rsdt"); + ACPI_FUNCTION_NAME ("Tb_validate_rsdt"); /* * For RSDP revision 0 or 1, we use the RSDT. - * For RSDP revision 2 (and above), we use the XSDT + * For RSDP revision 2 and above, we use the XSDT */ if (acpi_gbl_RSDP->revision < 2) { - no_match = STRNCMP ((char *) table_ptr, RSDT_SIG, + no_match = ACPI_STRNCMP ((char *) table_ptr, RSDT_SIG, sizeof (RSDT_SIG) -1); } else { - no_match = STRNCMP ((char *) table_ptr, XSDT_SIG, + no_match = ACPI_STRNCMP ((char *) table_ptr, XSDT_SIG, sizeof (XSDT_SIG) -1); } - if (no_match) { /* Invalid RSDT or XSDT signature */ - REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n")); + ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n")); - DUMP_BUFFER (acpi_gbl_RSDP, 20); + ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20); ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, - "RSDT/XSDT signature at %X is invalid\n", - acpi_gbl_RSDP->rsdt_physical_address)); + "RSDT/XSDT signature at %X (%p) is invalid\n", + acpi_gbl_RSDP->rsdt_physical_address, + (void *) (NATIVE_UINT) acpi_gbl_RSDP->rsdt_physical_address)); return (AE_BAD_SIGNATURE); } @@ -562,27 +677,57 @@ acpi_status acpi_tb_get_table_pointer ( - ACPI_PHYSICAL_ADDRESS physical_address, + ACPI_POINTER *address, u32 flags, - u32 *size, + ACPI_SIZE *size, acpi_table_header **table_ptr) { - acpi_status status; + acpi_status status = AE_OK; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); + /* + * What mode is the processor in? (Virtual or Physical addressing) + */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - *size = SIZE_IN_HEADER; - status = acpi_tb_map_acpi_table (physical_address, size, table_ptr); - } + /* Incoming pointer can be either logical or physical */ + + switch (address->pointer_type) { + case ACPI_PHYSICAL_POINTER: + *size = SIZE_IN_HEADER; + status = acpi_tb_map_acpi_table (address->pointer.physical, size, table_ptr); + break; + + case ACPI_LOGICAL_POINTER: + + *table_ptr = address->pointer.logical; + *size = 0; + break; + + default: + return (AE_BAD_PARAMETER); + } + } else { - *size = 0; - *table_ptr = (acpi_table_header *) (ACPI_TBLPTR) physical_address; + /* In Physical addressing mode, all pointers must be physical */ + + switch (address->pointer_type) { + case ACPI_PHYSICAL_POINTER: + *size = 0; + *table_ptr = address->pointer.logical; + break; + + case ACPI_LOGICAL_POINTER: - status = AE_OK; + status = AE_BAD_PARAMETER; + break; + + default: + return (AE_BAD_PARAMETER); + } } return (status); @@ -607,33 +752,27 @@ { acpi_table_desc table_info; acpi_status status; - ACPI_PHYSICAL_ADDRESS physical_address; + ACPI_POINTER address; - FUNCTION_TRACE ("Tb_get_table_rsdt"); + ACPI_FUNCTION_TRACE ("Tb_get_table_rsdt"); - /* - * Get the RSDT from the RSDP - */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", - acpi_gbl_RSDP, HIDWORD(acpi_gbl_RSDP->rsdt_physical_address), - LODWORD(acpi_gbl_RSDP->rsdt_physical_address))); - + /* Get the RSDT/XSDT from the RSDP */ - physical_address = acpi_tb_get_rsdt_address (); - - - /* Get the RSDT/XSDT */ - - status = acpi_tb_get_table (physical_address, NULL, &table_info); + acpi_tb_get_rsdt_address (&address); + status = acpi_tb_get_table (&address, &table_info); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the R/XSDT, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", + acpi_gbl_RSDP, + ACPI_HIDWORD (address.pointer.value), + ACPI_LODWORD (address.pointer.value))); /* Check the RSDT or XSDT signature */ @@ -642,14 +781,12 @@ return_ACPI_STATUS (status); } - /* * Valid RSDT signature, verify the checksum. If it fails, just * print a warning and ignore it. */ status = acpi_tb_verify_table_checksum (table_info.pointer); - /* Convert and/or copy to an XSDT structure */ status = acpi_tb_convert_to_xsdt (&table_info, number_of_tables); @@ -667,88 +804,7 @@ acpi_gbl_XSDT = (xsdt_descriptor *) table_info.pointer; ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); - return_ACPI_STATUS (status); } - -/****************************************************************************** - * - * FUNCTION: Acpi_tb_get_table_facs - * - * PARAMETERS: *Buffer_ptr - If Buffer_ptr is valid, read data from - * buffer rather than searching memory - * *Table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Returns a pointer to the FACS as defined in FADT. This - * function assumes the global variable FADT has been - * correctly initialized. The value of FADT->Firmware_ctrl - * into a far pointer which is returned. - * - *****************************************************************************/ - -acpi_status -acpi_tb_get_table_facs ( - acpi_table_header *buffer_ptr, - acpi_table_desc *table_info) -{ - acpi_table_header *table_ptr = NULL; - u32 size; - u8 allocation; - acpi_status status = AE_OK; - - - FUNCTION_TRACE ("Tb_get_table_facs"); - - - /* Must have a valid FADT pointer */ - - if (!acpi_gbl_FADT) { - return_ACPI_STATUS (AE_NO_ACPI_TABLES); - } - - size = sizeof (FACS_DESCRIPTOR); - if (buffer_ptr) { - /* - * Getting table from a file -- allocate a buffer and - * read the table. - */ - table_ptr = ACPI_MEM_ALLOCATE (size); - if(!table_ptr) { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - MEMCPY (table_ptr, buffer_ptr, size); - - /* Save allocation type */ - - allocation = ACPI_MEM_ALLOCATED; - } - - else { - /* Just map the physical memory to our address space */ - - status = acpi_tb_map_acpi_table ((ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xfirmware_ctrl), - &size, &table_ptr); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - /* Save allocation type */ - - allocation = ACPI_MEM_MAPPED; - } - - - /* Return values */ - - table_info->pointer = table_ptr; - table_info->length = size; - table_info->allocation = allocation; - table_info->base_pointer = table_ptr; - - return_ACPI_STATUS (status); -} diff -Nur linux-2.4.19/drivers/acpi/tables/tbinstal.c linux-2.4.19-sgi211r3/drivers/acpi/tables/tbinstal.c --- linux-2.4.19/drivers/acpi/tables/tbinstal.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables/tbinstal.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbinstal - ACPI table installation and removal - * $Revision: 45 $ + * $Revision: 61 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,20 +25,66 @@ #include "acpi.h" -#include "achware.h" #include "actables.h" #define _COMPONENT ACPI_TABLES - MODULE_NAME ("tbinstal") + ACPI_MODULE_NAME ("tbinstal") + + +/******************************************************************************* + * + * FUNCTION: Acpi_tb_match_signature + * + * PARAMETERS: Signature - Table signature to match + * Table_info - Return data + * + * RETURN: Status + * + * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned" + * tables (DSDT/FADT/SSDT, etc.) Returns the Table_type_iD on match. + * + ******************************************************************************/ + +acpi_status +acpi_tb_match_signature ( + NATIVE_CHAR *signature, + acpi_table_desc *table_info) +{ + NATIVE_UINT i; + + + ACPI_FUNCTION_TRACE ("Tb_match_signature"); + + + /* + * Search for a signature match among the known table types + */ + for (i = 0; i < NUM_ACPI_TABLES; i++) { + if (!ACPI_STRNCMP (signature, acpi_gbl_acpi_table_data[i].signature, + acpi_gbl_acpi_table_data[i].sig_length)) { + /* Found a signature match, return index if requested */ + + if (table_info) { + table_info->type = (u8) i; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Signature match %4.4s\n", + (char *) acpi_gbl_acpi_table_data[i].signature)); + + return_ACPI_STATUS (AE_OK); + } + } + + return_ACPI_STATUS (AE_TABLE_NOT_SUPPORTED); +} /******************************************************************************* * * FUNCTION: Acpi_tb_install_table * - * PARAMETERS: Table_ptr - Input buffer pointer, optional - * Table_info - Return value from Acpi_tb_get_table + * PARAMETERS: Table_info - Return value from Acpi_tb_get_table * * RETURN: Status * @@ -50,26 +96,28 @@ acpi_status acpi_tb_install_table ( - acpi_table_header *table_ptr, acpi_table_desc *table_info) { acpi_status status; - FUNCTION_TRACE ("Tb_install_table"); + ACPI_FUNCTION_TRACE ("Tb_install_table"); /* * Check the table signature and make sure it is recognized * Also checks the header checksum */ - status = acpi_tb_recognize_table (table_ptr, table_info); + status = acpi_tb_recognize_table (table_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Lock tables while installing */ - acpi_ut_acquire_mutex (ACPI_MTX_TABLES); + status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Install the table into the global data structure */ @@ -78,7 +126,7 @@ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s located at %p\n", acpi_gbl_acpi_table_data[table_info->type].name, table_info->pointer)); - acpi_ut_release_mutex (ACPI_MTX_TABLES); + (void) acpi_ut_release_mutex (ACPI_MTX_TABLES); return_ACPI_STATUS (status); } @@ -87,8 +135,7 @@ * * FUNCTION: Acpi_tb_recognize_table * - * PARAMETERS: Table_ptr - Input buffer pointer, optional - * Table_info - Return value from Acpi_tb_get_table + * PARAMETERS: Table_info - Return value from Acpi_tb_get_table * * RETURN: Status * @@ -106,16 +153,13 @@ acpi_status acpi_tb_recognize_table ( - acpi_table_header *table_ptr, acpi_table_desc *table_info) { acpi_table_header *table_header; acpi_status status; - acpi_table_type table_type = 0; - u32 i; - FUNCTION_TRACE ("Tb_recognize_table"); + ACPI_FUNCTION_TRACE ("Tb_recognize_table"); /* Ensure that we have a valid table pointer */ @@ -126,52 +170,41 @@ } /* - * Search for a signature match among the known table types - * Start at index one -> Skip the RSDP + * We only "recognize" a limited number of ACPI tables -- namely, the + * ones that are used by the subsystem (DSDT, FADT, etc.) + * + * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized. + * This can be any one of many valid ACPI tables, it just isn't one of + * the tables that is consumed by the core subsystem */ - status = AE_SUPPORT; - for (i = 1; i < NUM_ACPI_TABLES; i++) { - if (!STRNCMP (table_header->signature, - acpi_gbl_acpi_table_data[i].signature, - acpi_gbl_acpi_table_data[i].sig_length)) { - /* - * Found a signature match, get the pertinent info from the - * Table_data structure - */ - table_type = i; - status = acpi_gbl_acpi_table_data[i].status; + status = acpi_tb_match_signature (table_header->signature, table_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Found %4.4s\n", - (char*)acpi_gbl_acpi_table_data[i].signature)); - break; - } + status = acpi_tb_validate_table_header (table_header); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } /* Return the table type and length via the info struct */ - table_info->type = (u8) table_type; - table_info->length = table_header->length; - + table_info->length = (ACPI_SIZE) table_header->length; /* * Validate checksum for _most_ tables, * even the ones whose signature we don't recognize */ - if (table_type != ACPI_TABLE_FACS) { - /* But don't abort if the checksum is wrong */ - /* TBD: [Future] make this a configuration option? */ + if (table_info->type != ACPI_TABLE_FACS) { + status = acpi_tb_verify_table_checksum (table_header); - acpi_tb_verify_table_checksum (table_header); - } +#if (!ACPI_CHECKSUM_ABORT) + if (ACPI_FAILURE (status)) { + /* Ignore the error if configuration says so */ - /* - * An AE_SUPPORT means that the table was not recognized. - * We basically ignore this; just print a debug message - */ - if (status == AE_SUPPORT) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "Unsupported table %s (Type %X) was found and discarded\n", - acpi_gbl_acpi_table_data[table_type].name, table_type)); + status = AE_OK; + } +#endif } return_ACPI_STATUS (status); @@ -200,7 +233,7 @@ acpi_table_desc *table_desc; - FUNCTION_TRACE_U32 ("Tb_init_table_descriptor", table_type); + ACPI_FUNCTION_TRACE_U32 ("Tb_init_table_descriptor", table_type); /* * Install the table into the global data structure @@ -208,25 +241,24 @@ list_head = &acpi_gbl_acpi_tables[table_type]; table_desc = list_head; - /* * Two major types of tables: 1) Only one instance is allowed. This * includes most ACPI tables such as the DSDT. 2) Multiple instances of * the table are allowed. This includes SSDT and PSDTs. */ - if (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags)) { + if (ACPI_IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags)) { /* * Only one table allowed, and a table has alread been installed * at this location, so return an error. */ if (list_head->pointer) { - return_ACPI_STATUS (AE_EXIST); + return_ACPI_STATUS (AE_ALREADY_EXISTS); } table_desc->count = 1; + table_desc->prev = NULL; + table_desc->next = NULL; } - - else { /* * Multiple tables allowed for this table type, we must link @@ -253,15 +285,14 @@ list_head->prev = table_desc; } - else { table_desc->count = 1; } } - /* Common initialization of the table descriptor */ + table_desc->type = table_info->type; table_desc->pointer = table_info->pointer; table_desc->base_pointer = table_info->base_pointer; table_desc->length = table_info->length; @@ -269,7 +300,7 @@ table_desc->aml_start = (u8 *) (table_desc->pointer + 1), table_desc->aml_length = (u32) (table_desc->length - (u32) sizeof (acpi_table_header)); - table_desc->table_id = acpi_ut_allocate_owner_id (OWNER_TYPE_TABLE); + table_desc->table_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_TABLE); table_desc->loaded_into_namespace = FALSE; /* @@ -280,7 +311,6 @@ *(acpi_gbl_acpi_table_data[table_type].global_ptr) = table_info->pointer; } - /* Return Data */ table_info->table_id = table_desc->table_id; @@ -315,7 +345,6 @@ for (type = 0; type < NUM_ACPI_TABLES; type++) { acpi_tb_delete_acpi_table (type); } - } @@ -336,20 +365,17 @@ acpi_tb_delete_acpi_table ( acpi_table_type type) { - FUNCTION_TRACE_U32 ("Tb_delete_acpi_table", type); + + ACPI_FUNCTION_TRACE_U32 ("Tb_delete_acpi_table", type); if (type > ACPI_TABLE_MAX) { return_VOID; } - - acpi_ut_acquire_mutex (ACPI_MTX_TABLES); - - /* Free the table */ - - acpi_tb_free_acpi_tables_of_type (&acpi_gbl_acpi_tables[type]); - + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_TABLES))) { + return; + } /* Clear the appropriate "typed" global table pointer */ @@ -380,8 +406,11 @@ break; } - acpi_ut_release_mutex (ACPI_MTX_TABLES); + /* Free the table */ + + acpi_tb_free_acpi_tables_of_type (&acpi_gbl_acpi_tables[type]); + (void) acpi_ut_release_mutex (ACPI_MTX_TABLES); return_VOID; } @@ -408,7 +437,7 @@ u32 i; - FUNCTION_TRACE_PTR ("Tb_free_acpi_tables_of_type", list_head); + ACPI_FUNCTION_TRACE_PTR ("Tb_free_acpi_tables_of_type", list_head); /* Get the head of the list */ @@ -454,21 +483,21 @@ /* Valid table, determine type of memory allocation */ switch (table_desc->allocation) { - case ACPI_MEM_NOT_ALLOCATED: break; - case ACPI_MEM_ALLOCATED: ACPI_MEM_FREE (table_desc->base_pointer); break; - case ACPI_MEM_MAPPED: acpi_os_unmap_memory (table_desc->base_pointer, table_desc->length); break; + + default: + break; } } } @@ -480,7 +509,7 @@ * * PARAMETERS: Table_info - A table info struct * - * RETURN: None. + * RETURN: Pointer to the next table in the list (of same type) * * DESCRIPTION: Free the memory associated with an internal ACPI table that * is either installed or has never been installed. @@ -495,14 +524,13 @@ acpi_table_desc *next_desc; - FUNCTION_TRACE_PTR ("Tb_delete_single_table", table_desc); + ACPI_FUNCTION_TRACE_PTR ("Acpi_tb_uninstall_table", table_desc); if (!table_desc) { return_PTR (NULL); } - /* Unlink the descriptor */ if (table_desc->prev) { @@ -513,16 +541,13 @@ table_desc->next->prev = table_desc->prev; } - /* Free the memory allocated for the table itself */ acpi_tb_delete_single_table (table_desc); - /* Free the table descriptor (Don't delete the list head, tho) */ if ((table_desc->prev) == (table_desc->next)) { - next_desc = NULL; /* Clear the list head */ @@ -530,16 +555,13 @@ table_desc->pointer = NULL; table_desc->length = 0; table_desc->count = 0; - } - else { /* Free the table descriptor */ next_desc = table_desc->next; ACPI_MEM_FREE (table_desc); } - return_PTR (next_desc); } diff -Nur linux-2.4.19/drivers/acpi/tables/tbutils.c linux-2.4.19-sgi211r3/drivers/acpi/tables/tbutils.c --- linux-2.4.19/drivers/acpi/tables/tbutils.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables/tbutils.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbutils - Table manipulation utilities - * $Revision: 42 $ + * $Revision: 53 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,11 +26,10 @@ #include "acpi.h" #include "actables.h" -#include "acinterp.h" #define _COMPONENT ACPI_TABLES - MODULE_NAME ("tbutils") + ACPI_MODULE_NAME ("tbutils") /******************************************************************************* @@ -55,7 +54,7 @@ acpi_table_desc *list_head; - PROC_NAME ("Tb_handle_to_object"); + ACPI_FUNCTION_NAME ("Tb_handle_to_object"); for (i = 0; i < ACPI_TABLE_MAX; i++) { @@ -71,7 +70,6 @@ } while (list_head != &acpi_gbl_acpi_tables[i]); } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Table_id=%X does not exist\n", table_id)); return (AE_BAD_PARAMETER); } @@ -79,81 +77,6 @@ /******************************************************************************* * - * FUNCTION: Acpi_tb_system_table_pointer - * - * PARAMETERS: *Where - Pointer to be examined - * - * RETURN: TRUE if Where is within the AML stream (in one of the ACPI - * system tables such as the DSDT or an SSDT.) - * FALSE otherwise - * - ******************************************************************************/ - -u8 -acpi_tb_system_table_pointer ( - void *where) -{ - u32 i; - acpi_table_desc *table_desc; - acpi_table_header *table; - - - /* No function trace, called too often! */ - - - /* Ignore null pointer */ - - if (!where) { - return (FALSE); - } - - - /* Check for a pointer within the DSDT */ - - if ((acpi_gbl_DSDT) && - (IS_IN_ACPI_TABLE (where, acpi_gbl_DSDT))) { - return (TRUE); - } - - - /* Check each of the loaded SSDTs (if any)*/ - - table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_SSDT]; - - for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_SSDT].count; i++) { - table = table_desc->pointer; - - if (IS_IN_ACPI_TABLE (where, table)) { - return (TRUE); - } - - table_desc = table_desc->next; - } - - - /* Check each of the loaded PSDTs (if any)*/ - - table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_PSDT]; - - for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_PSDT].count; i++) { - table = table_desc->pointer; - - if (IS_IN_ACPI_TABLE (where, table)) { - return (TRUE); - } - - table_desc = table_desc->next; - } - - - /* Pointer does not point into any system table */ - - return (FALSE); -} - - -/******************************************************************************* - * * FUNCTION: Acpi_tb_validate_table_header * * PARAMETERS: Table_header - Logical pointer to the table @@ -179,7 +102,7 @@ acpi_name signature; - PROC_NAME ("Tb_validate_table_header"); + ACPI_FUNCTION_NAME ("Tb_validate_table_header"); /* Verify that this is a valid address */ @@ -190,30 +113,28 @@ return (AE_BAD_ADDRESS); } - /* Ensure that the signature is 4 ASCII characters */ - MOVE_UNALIGNED32_TO_32 (&signature, &table_header->signature); + ACPI_MOVE_UNALIGNED32_TO_32 (&signature, table_header->signature); if (!acpi_ut_valid_acpi_name (signature)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Table signature at %p [%p] has invalid characters\n", table_header, &signature)); - REPORT_WARNING (("Invalid table signature %4.4s found\n", (char*)&signature)); - DUMP_BUFFER (table_header, sizeof (acpi_table_header)); + ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n", (char *) &signature)); + ACPI_DUMP_BUFFER (table_header, sizeof (acpi_table_header)); return (AE_BAD_SIGNATURE); } - /* Validate the table length */ if (table_header->length < sizeof (acpi_table_header)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid length in table header %p name %4.4s\n", - table_header, (char*)&signature)); + table_header, (char *) &signature)); - REPORT_WARNING (("Invalid table header length found\n")); - DUMP_BUFFER (table_header, sizeof (acpi_table_header)); + ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n", table_header->length)); + ACPI_DUMP_BUFFER (table_header, sizeof (acpi_table_header)); return (AE_BAD_HEADER); } @@ -240,15 +161,15 @@ acpi_status acpi_tb_map_acpi_table ( ACPI_PHYSICAL_ADDRESS physical_address, - u32 *size, + ACPI_SIZE *size, acpi_table_header **logical_address) { acpi_table_header *table; - u32 table_size = *size; + ACPI_SIZE table_size = *size; acpi_status status = AE_OK; - PROC_NAME ("Tb_map_acpi_table"); + ACPI_FUNCTION_NAME ("Tb_map_acpi_table"); /* If size is zero, look at the table header to get the actual size */ @@ -264,7 +185,7 @@ /* Extract the full table length before we delete the mapping */ - table_size = table->length; + table_size = (ACPI_SIZE) table->length; /* * Validate the header and delete the mapping. @@ -283,10 +204,10 @@ } } - /* Map the physical memory for the correct length */ - status = acpi_os_map_memory (physical_address, table_size, (void **) &table); + status = acpi_os_map_memory (physical_address, table_size, + (void **) &table); if (ACPI_FAILURE (status)) { return (status); } @@ -297,7 +218,6 @@ *size = table_size; *logical_address = table; - return (status); } @@ -323,7 +243,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Tb_verify_table_checksum"); + ACPI_FUNCTION_TRACE ("Tb_verify_table_checksum"); /* Compute the checksum on the table */ @@ -333,13 +253,11 @@ /* Return the appropriate exception */ if (checksum) { - REPORT_WARNING (("Invalid checksum (%X) in table %4.4s\n", - checksum, (char*)&table_header->signature)); + ACPI_REPORT_WARNING (("Invalid checksum (%X) in table %4.4s\n", + checksum, table_header->signature)); status = AE_BAD_CHECKSUM; } - - return_ACPI_STATUS (status); } @@ -362,8 +280,8 @@ void *buffer, u32 length) { - u8 *limit; - u8 *rover; + const u8 *limit; + const u8 *rover; u8 sum = 0; @@ -376,7 +294,6 @@ sum = (u8) (sum + *rover); } } - return (sum); } diff -Nur linux-2.4.19/drivers/acpi/tables/tbxface.c linux-2.4.19-sgi211r3/drivers/acpi/tables/tbxface.c --- linux-2.4.19/drivers/acpi/tables/tbxface.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables/tbxface.c Tue Aug 27 19:53:13 2002 @@ -2,12 +2,12 @@ * * Module Name: tbxface - Public interfaces to the ACPI subsystem * ACPI table oriented interfaces - * $Revision: 45 $ + * $Revision: 57 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,12 +27,11 @@ #include "acpi.h" #include "acnamesp.h" -#include "acinterp.h" #include "actables.h" #define _COMPONENT ACPI_TABLES - MODULE_NAME ("tbxface") + ACPI_MODULE_NAME ("tbxface") /******************************************************************************* @@ -51,29 +50,31 @@ acpi_status acpi_load_tables (void) { - ACPI_PHYSICAL_ADDRESS rsdp_physical_address; + ACPI_POINTER rsdp_address; acpi_status status; u32 number_of_tables = 0; - FUNCTION_TRACE ("Acpi_load_tables"); + ACPI_FUNCTION_TRACE ("Acpi_load_tables"); /* Get the RSDP */ status = acpi_os_get_root_pointer (ACPI_LOGICAL_ADDRESSING, - &rsdp_physical_address); + &rsdp_address); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("Acpi_load_tables: Could not get RSDP, %s\n", + ACPI_REPORT_ERROR (("Acpi_load_tables: Could not get RSDP, %s\n", acpi_format_exception (status))); goto error_exit; } /* Map and validate the RSDP */ - status = acpi_tb_verify_rsdp (rsdp_physical_address); + acpi_gbl_table_flags = rsdp_address.pointer_type; + + status = acpi_tb_verify_rsdp (&rsdp_address); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("Acpi_load_tables: RSDP Failed validation: %s\n", + ACPI_REPORT_ERROR (("Acpi_load_tables: RSDP Failed validation: %s\n", acpi_format_exception (status))); goto error_exit; } @@ -82,16 +83,16 @@ status = acpi_tb_get_table_rsdt (&number_of_tables); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("Acpi_load_tables: Could not load RSDT: %s\n", + ACPI_REPORT_ERROR (("Acpi_load_tables: Could not load RSDT: %s\n", acpi_format_exception (status))); goto error_exit; } /* Now get the rest of the tables */ - status = acpi_tb_get_all_tables (number_of_tables, NULL); + status = acpi_tb_get_all_tables (number_of_tables); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("Acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n", + ACPI_REPORT_ERROR (("Acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n", acpi_format_exception (status))); goto error_exit; } @@ -103,7 +104,7 @@ status = acpi_ns_load_namespace (); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("Acpi_load_tables: Could not load namespace: %s\n", + ACPI_REPORT_ERROR (("Acpi_load_tables: Could not load namespace: %s\n", acpi_format_exception (status))); goto error_exit; } @@ -112,7 +113,7 @@ error_exit: - REPORT_ERROR (("Acpi_load_tables: Could not load tables: %s\n", + ACPI_REPORT_ERROR (("Acpi_load_tables: Could not load tables: %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); @@ -141,9 +142,10 @@ { acpi_status status; acpi_table_desc table_info; + ACPI_POINTER address; - FUNCTION_TRACE ("Acpi_load_table"); + ACPI_FUNCTION_TRACE ("Acpi_load_table"); if (!table_ptr) { @@ -152,14 +154,17 @@ /* Copy the table to a local buffer */ - status = acpi_tb_get_table (0, table_ptr, &table_info); + address.pointer_type = ACPI_LOGICAL_POINTER; + address.pointer.logical = table_ptr; + + status = acpi_tb_get_table (&address, &table_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Install the new table into the local data structures */ - status = acpi_tb_install_table (NULL, &table_info); + status = acpi_tb_install_table (&table_info); if (ACPI_FAILURE (status)) { /* Free table allocated by Acpi_tb_get_table */ @@ -167,16 +172,32 @@ return_ACPI_STATUS (status); } + /* Convert the table to common format if necessary */ + + switch (table_info.type) { + case ACPI_TABLE_FADT: + + status = acpi_tb_convert_table_fadt (); + break; + + case ACPI_TABLE_FACS: + + status = acpi_tb_build_common_facs (&table_info); + break; + + default: + /* Load table into namespace if it contains executable AML */ + + status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node); + break; + } - status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node); if (ACPI_FAILURE (status)) { /* Uninstall table and free the buffer */ - acpi_tb_uninstall_table (table_info.installed_desc); - return_ACPI_STATUS (status); + (void) acpi_tb_uninstall_table (table_info.installed_desc); } - return_ACPI_STATUS (status); } @@ -200,7 +221,7 @@ acpi_table_desc *list_head; - FUNCTION_TRACE ("Acpi_unload_table"); + ACPI_FUNCTION_TRACE ("Acpi_unload_table"); /* Parameter validation */ @@ -263,7 +284,7 @@ acpi_status status; - FUNCTION_TRACE ("Acpi_get_table_header"); + ACPI_FUNCTION_TRACE ("Acpi_get_table_header"); if ((instance == 0) || @@ -275,7 +296,7 @@ /* Check the table type and instance */ if ((table_type > ACPI_TABLE_MAX) || - (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && + (ACPI_IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && instance > 1)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -298,7 +319,7 @@ /* * Copy the header to the caller's buffer */ - MEMCPY ((void *) out_table_header, (void *) tbl_ptr, + ACPI_MEMCPY ((void *) out_table_header, (void *) tbl_ptr, sizeof (acpi_table_header)); return_ACPI_STATUS (status); @@ -336,25 +357,27 @@ { acpi_table_header *tbl_ptr; acpi_status status; - u32 ret_buf_len; + ACPI_SIZE table_length; - FUNCTION_TRACE ("Acpi_get_table"); + ACPI_FUNCTION_TRACE ("Acpi_get_table"); - /* - * If we have a buffer, we must have a length too - */ - if ((instance == 0) || - (!ret_buffer) || - ((!ret_buffer->pointer) && (ret_buffer->length))) { + /* Parameter validation */ + + if (instance == 0) { return_ACPI_STATUS (AE_BAD_PARAMETER); } + status = acpi_ut_validate_buffer (ret_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* Check the table type and instance */ if ((table_type > ACPI_TABLE_MAX) || - (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && + (ACPI_IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && instance > 1)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -375,31 +398,28 @@ return_ACPI_STATUS (AE_NOT_EXIST); } - /* - * Got a table ptr, assume it's ok and copy it to the user's buffer - */ + /* Get the table length */ + if (table_type == ACPI_TABLE_RSDP) { /* * RSD PTR is the only "table" without a header */ - ret_buf_len = sizeof (RSDP_DESCRIPTOR); + table_length = sizeof (RSDP_DESCRIPTOR); } else { - ret_buf_len = tbl_ptr->length; + table_length = (ACPI_SIZE) tbl_ptr->length; } - /* - * Verify we have space in the caller's buffer for the table - */ - if (ret_buffer->length < ret_buf_len) { - ret_buffer->length = ret_buf_len; - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); - } + /* Validate/Allocate/Clear caller buffer */ - ret_buffer->length = ret_buf_len; + status = acpi_ut_initialize_buffer (ret_buffer, table_length); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - MEMCPY ((void *) ret_buffer->pointer, (void *) tbl_ptr, ret_buf_len); + /* Copy the table to the buffer */ + ACPI_MEMCPY ((void *) ret_buffer->pointer, (void *) tbl_ptr, table_length); return_ACPI_STATUS (AE_OK); } diff -Nur linux-2.4.19/drivers/acpi/tables/tbxfroot.c linux-2.4.19-sgi211r3/drivers/acpi/tables/tbxfroot.c --- linux-2.4.19/drivers/acpi/tables/tbxfroot.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables/tbxfroot.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: tbxfroot - Find the root ACPI table (RSDT) - * $Revision: 52 $ + * $Revision: 63 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,22 +25,261 @@ #include "acpi.h" -#include "achware.h" #include "actables.h" #define _COMPONENT ACPI_TABLES - MODULE_NAME ("tbxfroot") + ACPI_MODULE_NAME ("tbxfroot") -#define RSDP_CHECKSUM_LENGTH 20 +/******************************************************************************* + * + * FUNCTION: Acpi_tb_find_table + * + * PARAMETERS: Signature - String with ACPI table signature + * Oem_id - String with the table OEM ID + * Oem_table_id - String with the OEM Table ID. + * + * RETURN: Status + * + * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the + * Signature, OEM ID and OEM Table ID. + * + ******************************************************************************/ + +acpi_status +acpi_tb_find_table ( + NATIVE_CHAR *signature, + NATIVE_CHAR *oem_id, + NATIVE_CHAR *oem_table_id, + acpi_table_header **table_ptr) +{ + acpi_status status; + acpi_table_header *table; + + + ACPI_FUNCTION_TRACE ("Tb_find_table"); + + + /* Validate string lengths */ + + if ((ACPI_STRLEN (signature) > 4) || + (ACPI_STRLEN (oem_id) > 6) || + (ACPI_STRLEN (oem_table_id) > 8)) { + return_ACPI_STATUS (AE_AML_STRING_LIMIT); + } + + /* Find the table */ + + status = acpi_get_firmware_table (signature, 1, + ACPI_LOGICAL_ADDRESSING, &table); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Check Oem_id and Oem_table_id */ + + if ((oem_id[0] && ACPI_STRCMP (oem_id, table->oem_id)) || + (oem_table_id[0] && ACPI_STRCMP (oem_table_id, table->oem_table_id))) { + return_ACPI_STATUS (AE_AML_NAME_NOT_FOUND); + } + + *table_ptr = table; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_get_firmware_table + * + * PARAMETERS: Signature - Any ACPI table signature + * Instance - the non zero instance of the table, allows + * support for multiple tables of the same type + * Flags - 0: Physical/Virtual support + * Ret_buffer - pointer to a structure containing a buffer to + * receive the table + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get an ACPI table. The caller + * supplies an Out_buffer large enough to contain the entire ACPI + * table. Upon completion + * the Out_buffer->Length field will indicate the number of bytes + * copied into the Out_buffer->Buf_ptr buffer. This table will be + * a complete table including the header. + * + ******************************************************************************/ + +acpi_status +acpi_get_firmware_table ( + acpi_string signature, + u32 instance, + u32 flags, + acpi_table_header **table_pointer) +{ + ACPI_POINTER rsdp_address; + ACPI_POINTER address; + acpi_table_header *rsdt_ptr = NULL; + acpi_table_header *table_ptr; + acpi_status status; + ACPI_SIZE rsdt_size = 0; + ACPI_SIZE table_size; + u32 table_count; + u32 i; + u32 j; + + + ACPI_FUNCTION_TRACE ("Acpi_get_firmware_table"); + + + /* + * Ensure that at least the table manager is initialized. We don't + * require that the entire ACPI subsystem is up for this interface + */ + + /* + * If we have a buffer, we must have a length too + */ + if ((instance == 0) || + (!signature) || + (!table_pointer)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (!acpi_gbl_RSDP) { + /* Get the RSDP */ + + status = acpi_os_get_root_pointer (flags, &rsdp_address); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* Map and validate the RSDP */ + + if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { + status = acpi_os_map_memory (rsdp_address.pointer.physical, sizeof (RSDP_DESCRIPTOR), + (void **) &acpi_gbl_RSDP); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + else { + acpi_gbl_RSDP = rsdp_address.pointer.logical; + } + + /* + * The signature and checksum must both be correct + */ + if (ACPI_STRNCMP ((NATIVE_CHAR *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + /* Nope, BAD Signature */ + + status = AE_BAD_SIGNATURE; + goto cleanup; + } + + if (acpi_tb_checksum (acpi_gbl_RSDP, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { + /* Nope, BAD Checksum */ + + status = AE_BAD_CHECKSUM; + goto cleanup; + } + } + + /* Get the RSDT and validate it */ + + acpi_tb_get_rsdt_address (&address); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", + acpi_gbl_RSDP, + ACPI_HIDWORD (address.pointer.value), + ACPI_LODWORD (address.pointer.value))); + + status = acpi_tb_get_table_pointer (&address, flags, &rsdt_size, &rsdt_ptr); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_tb_validate_rsdt (rsdt_ptr); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Get the number of table pointers within the RSDT */ + + table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_ptr); + + + /* + * Search the RSDT/XSDT for the correct instance of the + * requested table + */ + for (i = 0, j = 0; i < table_count; i++) { + /* Get the next table pointer */ + + address.pointer_type = acpi_gbl_table_flags; + if (acpi_gbl_RSDP->revision < 2) { + address.pointer.value = ((RSDT_DESCRIPTOR *) rsdt_ptr)->table_offset_entry[i]; + } + else { + address.pointer.value = ACPI_GET_ADDRESS ( + ((xsdt_descriptor *) rsdt_ptr)->table_offset_entry[i]); + } + + /* Get addressibility if necessary */ + + status = acpi_tb_get_table_pointer (&address, flags, &table_size, &table_ptr); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Compare table signatures and table instance */ + + if (!ACPI_STRNCMP ((char *) table_ptr, signature, ACPI_STRLEN (signature))) { + /* An instance of the table was found */ + + j++; + if (j >= instance) { + /* Found the correct instance */ + + *table_pointer = table_ptr; + goto cleanup; + } + } + + /* Delete table mapping if using virtual addressing */ + + if ((table_size) && + ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING)) { + acpi_os_unmap_memory (table_ptr, table_size); + } + } + + /* Did not find the table */ + + status = AE_NOT_EXIST; + + +cleanup: + if (rsdt_size) { + acpi_os_unmap_memory (rsdt_ptr, rsdt_size); + } + return_ACPI_STATUS (status); +} + + +/* TBD: Move to a new file */ + +#if ACPI_MACHINE_WIDTH != 16 /******************************************************************************* * * FUNCTION: Acpi_find_root_pointer * - * PARAMETERS: **Rsdp_physical_address - Where to place the RSDP address - * Flags - Logical/Physical addressing + * PARAMETERS: **Rsdp_address - Where to place the RSDP address + * Flags - Logical/Physical addressing * * RETURN: Status, Physical address of the RSDP * @@ -51,13 +290,13 @@ acpi_status acpi_find_root_pointer ( u32 flags, - ACPI_PHYSICAL_ADDRESS *rsdp_physical_address) + ACPI_POINTER *rsdp_address) { acpi_table_desc table_info; acpi_status status; - FUNCTION_TRACE ("Acpi_find_root_pointer"); + ACPI_FUNCTION_TRACE ("Acpi_find_root_pointer"); /* Get the RSDP */ @@ -68,8 +307,8 @@ return_ACPI_STATUS (AE_NO_ACPI_TABLES); } - *rsdp_physical_address = table_info.physical_address; - + rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER; + rsdp_address->pointer.physical = table_info.physical_address; return_ACPI_STATUS (AE_OK); } @@ -96,7 +335,7 @@ u8 *mem_rover; - FUNCTION_TRACE ("Tb_scan_memory_for_rsdp"); + ACPI_FUNCTION_TRACE ("Tb_scan_memory_for_rsdp"); /* Search from given start addr for the requested length */ @@ -107,9 +346,9 @@ /* The signature and checksum must both be correct */ - if (STRNCMP ((NATIVE_CHAR *) mem_rover, + if (ACPI_STRNCMP ((NATIVE_CHAR *) mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) == 0 && - acpi_tb_checksum (mem_rover, RSDP_CHECKSUM_LENGTH) == 0) { + acpi_tb_checksum (mem_rover, ACPI_RSDP_CHECKSUM_LENGTH) == 0) { /* If so, we have found the RSDP */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, @@ -121,7 +360,6 @@ /* Searched entire block, no RSDP was found */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,"Searched entire block, no RSDP was found.\n")); - return_PTR (NULL); } @@ -156,7 +394,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Tb_find_rsdp"); + ACPI_FUNCTION_TRACE ("Tb_find_rsdp"); /* @@ -166,7 +404,7 @@ /* * 1) Search EBDA (low memory) paragraphs */ - status = acpi_os_map_memory (LO_RSDP_WINDOW_BASE, LO_RSDP_WINDOW_SIZE, + status = acpi_os_map_memory ((u64) LO_RSDP_WINDOW_BASE, LO_RSDP_WINDOW_SIZE, (void **) &table_ptr); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -179,17 +417,16 @@ /* Found it, return the physical address */ phys_addr = LO_RSDP_WINDOW_BASE; - phys_addr += (mem_rover - table_ptr); + phys_addr += ACPI_PTR_DIFF (mem_rover,table_ptr); table_info->physical_address = phys_addr; - return_ACPI_STATUS (AE_OK); } /* * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h */ - status = acpi_os_map_memory (HI_RSDP_WINDOW_BASE, HI_RSDP_WINDOW_SIZE, + status = acpi_os_map_memory ((u64) HI_RSDP_WINDOW_BASE, HI_RSDP_WINDOW_SIZE, (void **) &table_ptr); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -202,15 +439,13 @@ /* Found it, return the physical address */ phys_addr = HI_RSDP_WINDOW_BASE; - phys_addr += (mem_rover - table_ptr); + phys_addr += ACPI_PTR_DIFF (mem_rover, table_ptr); table_info->physical_address = phys_addr; - return_ACPI_STATUS (AE_OK); } } - /* * Physical addressing */ @@ -218,212 +453,32 @@ /* * 1) Search EBDA (low memory) paragraphs */ - mem_rover = acpi_tb_scan_memory_for_rsdp ((u8 *) LO_RSDP_WINDOW_BASE, + mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (LO_RSDP_WINDOW_BASE), LO_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ - table_info->physical_address = (ACPI_TBLPTR) mem_rover; + table_info->physical_address = ACPI_TO_INTEGER (mem_rover); return_ACPI_STATUS (AE_OK); } /* * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h */ - mem_rover = acpi_tb_scan_memory_for_rsdp ((u8 *) HI_RSDP_WINDOW_BASE, + mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (HI_RSDP_WINDOW_BASE), HI_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ - table_info->physical_address = (ACPI_TBLPTR) mem_rover; + table_info->physical_address = ACPI_TO_INTEGER (mem_rover); return_ACPI_STATUS (AE_OK); } } - /* RSDP signature was not found */ return_ACPI_STATUS (AE_NOT_FOUND); } - -/******************************************************************************* - * - * FUNCTION: Acpi_get_firmware_table - * - * PARAMETERS: Signature - Any ACPI table signature - * Instance - the non zero instance of the table, allows - * support for multiple tables of the same type - * Flags - 0: Physical/Virtual support - * Ret_buffer - pointer to a structure containing a buffer to - * receive the table - * - * RETURN: Status - * - * DESCRIPTION: This function is called to get an ACPI table. The caller - * supplies an Out_buffer large enough to contain the entire ACPI - * table. Upon completion - * the Out_buffer->Length field will indicate the number of bytes - * copied into the Out_buffer->Buf_ptr buffer. This table will be - * a complete table including the header. - * - ******************************************************************************/ - -acpi_status -acpi_get_firmware_table ( - acpi_string signature, - u32 instance, - u32 flags, - acpi_table_header **table_pointer) -{ - ACPI_PHYSICAL_ADDRESS physical_address; - acpi_table_header *rsdt_ptr = NULL; - acpi_table_header *table_ptr; - acpi_status status; - u32 rsdt_size = 0; - u32 table_size; - u32 table_count; - u32 i; - u32 j; - - - FUNCTION_TRACE ("Acpi_get_firmware_table"); - - - /* - * Ensure that at least the table manager is initialized. We don't - * require that the entire ACPI subsystem is up for this interface - */ - - /* - * If we have a buffer, we must have a length too - */ - if ((instance == 0) || - (!signature) || - (!table_pointer)) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - - if (!acpi_gbl_RSDP) { - /* Get the RSDP */ - - status = acpi_os_get_root_pointer (flags, &physical_address); - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n")); - return_ACPI_STATUS (AE_NO_ACPI_TABLES); - } - - /* Map and validate the RSDP */ - - if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - status = acpi_os_map_memory (physical_address, sizeof (RSDP_DESCRIPTOR), - (void **) &acpi_gbl_RSDP); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - } - else { - acpi_gbl_RSDP = (void *) (NATIVE_UINT) physical_address; - } - - /* - * The signature and checksum must both be correct - */ - if (STRNCMP ((NATIVE_CHAR *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { - /* Nope, BAD Signature */ - - status = AE_BAD_SIGNATURE; - goto cleanup; - } - - if (acpi_tb_checksum (acpi_gbl_RSDP, RSDP_CHECKSUM_LENGTH) != 0) { - /* Nope, BAD Checksum */ - - status = AE_BAD_CHECKSUM; - goto cleanup; - } - } - - - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "RSDP located at %p, RSDT physical=%8.8X%8.8X \n", - acpi_gbl_RSDP, HIDWORD(acpi_gbl_RSDP->rsdt_physical_address), - LODWORD(acpi_gbl_RSDP->rsdt_physical_address))); - - - /* Get the RSDT and validate it */ - - physical_address = acpi_tb_get_rsdt_address (); - status = acpi_tb_get_table_pointer (physical_address, flags, &rsdt_size, &rsdt_ptr); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - status = acpi_tb_validate_rsdt (rsdt_ptr); - if (ACPI_FAILURE (status)) { - goto cleanup; - } - - - /* Get the number of table pointers within the RSDT */ - - table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_ptr); - - - /* - * Search the RSDT/XSDT for the correct instance of the - * requested table - */ - for (i = 0, j = 0; i < table_count; i++) { - /* Get the next table pointer */ - - if (acpi_gbl_RSDP->revision < 2) { - physical_address = ((RSDT_DESCRIPTOR *) rsdt_ptr)->table_offset_entry[i]; - } - else { - physical_address = (ACPI_PHYSICAL_ADDRESS) - ACPI_GET_ADDRESS (((xsdt_descriptor *) rsdt_ptr)->table_offset_entry[i]); - } - - /* Get addressibility if necessary */ - - status = acpi_tb_get_table_pointer (physical_address, flags, &table_size, &table_ptr); - if (ACPI_FAILURE (status)) { - goto cleanup; - } - - /* Compare table signatures and table instance */ - - if (!STRNCMP ((char *) table_ptr, signature, STRLEN (signature))) { - /* An instance of the table was found */ - - j++; - if (j >= instance) { - /* Found the correct instance */ - - *table_pointer = table_ptr; - goto cleanup; - } - } - - /* Delete table mapping if using virtual addressing */ - - if ((table_size) && - ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING)) { - acpi_os_unmap_memory (table_ptr, table_size); - } - } - - /* Did not find the table */ - - status = AE_NOT_EXIST; - - -cleanup: - if (rsdt_size) { - acpi_os_unmap_memory (rsdt_ptr, rsdt_size); - } - return_ACPI_STATUS (status); -} - +#endif diff -Nur linux-2.4.19/drivers/acpi/tables.c linux-2.4.19-sgi211r3/drivers/acpi/tables.c --- linux-2.4.19/drivers/acpi/tables.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/tables.c Fri Nov 15 18:23:19 2002 @@ -0,0 +1,480 @@ +/* + * acpi_tables.c - ACPI Boot-Time Table Parsing + * + * Copyright (C) 2001 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PREFIX "ACPI: " + +#define ACPI_MAX_TABLES ACPI_TABLE_COUNT + +static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { + [ACPI_TABLE_UNKNOWN] = "????", + [ACPI_APIC] = "APIC", + [ACPI_BOOT] = "BOOT", + [ACPI_DBGP] = "DBGP", + [ACPI_DSDT] = "DSDT", + [ACPI_ECDT] = "ECDT", + [ACPI_ETDT] = "ETDT", + [ACPI_FACP] = "FACP", + [ACPI_FACS] = "FACS", + [ACPI_OEMX] = "OEM", + [ACPI_PSDT] = "PSDT", + [ACPI_SBST] = "SBST", + [ACPI_SLIT] = "SLIT", + [ACPI_SPCR] = "SPCR", + [ACPI_SRAT] = "SRAT", + [ACPI_SSDT] = "SSDT", + [ACPI_SPMI] = "SPMI" +}; + +/* System Description Table (RSDT/XSDT) */ +struct acpi_table_sdt { + unsigned long pa; /* Physical Address */ + unsigned long count; /* Table count */ + struct { + unsigned long pa; + enum acpi_table_id id; + unsigned long size; + } entry[ACPI_MAX_TABLES]; +} __attribute__ ((packed)); + +static struct acpi_table_sdt sdt; + +acpi_madt_entry_handler madt_handlers[ACPI_MADT_ENTRY_COUNT]; + + +void +acpi_table_print ( + struct acpi_table_header *header, + unsigned long phys_addr) +{ + char *name = NULL; + + if (!header) + return; + + /* Some table signatures aren't good table names */ + + if (0 == strncmp((char *) &header->signature, + acpi_table_signatures[ACPI_APIC], + sizeof(header->signature))) { + name = "MADT"; + } + else if (0 == strncmp((char *) &header->signature, + acpi_table_signatures[ACPI_FACP], + sizeof(header->signature))) { + name = "FADT"; + } + else + name = header->signature; + + printk(KERN_INFO PREFIX "%.4s (v%3.3d %6.6s %8.8s %5.5d.%5.5d) @ 0x%p\n", + name, header->revision, header->oem_id, + header->oem_table_id, header->oem_revision >> 16, + header->oem_revision & 0xffff, (void *) phys_addr); +} + + +void +acpi_table_print_madt_entry ( + acpi_table_entry_header *header) +{ + if (!header) + return; + + switch (header->type) { + + case ACPI_MADT_LAPIC: + { + struct acpi_table_lapic *p = + (struct acpi_table_lapic*) header; + printk(KERN_INFO PREFIX "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", + p->acpi_id, p->id, p->flags.enabled?"enabled":"disabled"); + } + break; + + case ACPI_MADT_IOAPIC: + { + struct acpi_table_ioapic *p = + (struct acpi_table_ioapic*) header; + printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] global_irq_base[0x%x])\n", + p->id, p->address, p->global_irq_base); + } + break; + + case ACPI_MADT_INT_SRC_OVR: + { + struct acpi_table_int_src_ovr *p = + (struct acpi_table_int_src_ovr*) header; + printk(KERN_INFO PREFIX "INT_SRC_OVR (bus[%d] irq[0x%x] global_irq[0x%x] polarity[0x%x] trigger[0x%x])\n", + p->bus, p->bus_irq, p->global_irq, p->flags.polarity, p->flags.trigger); + } + break; + + case ACPI_MADT_NMI_SRC: + { + struct acpi_table_nmi_src *p = + (struct acpi_table_nmi_src*) header; + printk(KERN_INFO PREFIX "NMI_SRC (polarity[0x%x] trigger[0x%x] global_irq[0x%x])\n", + p->flags.polarity, p->flags.trigger, p->global_irq); + } + break; + + case ACPI_MADT_LAPIC_NMI: + { + struct acpi_table_lapic_nmi *p = + (struct acpi_table_lapic_nmi*) header; + printk(KERN_INFO PREFIX "LAPIC_NMI (acpi_id[0x%02x] polarity[0x%x] trigger[0x%x] lint[0x%x])\n", + p->acpi_id, p->flags.polarity, p->flags.trigger, p->lint); + } + break; + + case ACPI_MADT_LAPIC_ADDR_OVR: + { + struct acpi_table_lapic_addr_ovr *p = + (struct acpi_table_lapic_addr_ovr*) header; + printk(KERN_INFO PREFIX "LAPIC_ADDR_OVR (address[%p])\n", + (void *) (unsigned long) p->address); + } + break; + + case ACPI_MADT_IOSAPIC: + { + struct acpi_table_iosapic *p = + (struct acpi_table_iosapic*) header; + printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] global_irq_base[0x%x] address[%p])\n", + p->id, p->global_irq_base, (void *) (unsigned long) p->address); + } + break; + + case ACPI_MADT_LSAPIC: + { + struct acpi_table_lsapic *p = + (struct acpi_table_lsapic*) header; + printk(KERN_INFO PREFIX "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", + p->acpi_id, p->id, p->eid, p->flags.enabled?"enabled":"disabled"); + } + break; + + case ACPI_MADT_PLAT_INT_SRC: + { + struct acpi_table_plat_int_src *p = + (struct acpi_table_plat_int_src*) header; + printk(KERN_INFO PREFIX "PLAT_INT_SRC (polarity[0x%x] trigger[0x%x] type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", + p->flags.polarity, p->flags.trigger, p->type, p->id, p->eid, p->iosapic_vector, p->global_irq); + } + break; + + default: + printk(KERN_WARNING PREFIX "Found unsupported MADT entry (type = 0x%x)\n", + header->type); + break; + } +} + + +static int +acpi_table_compute_checksum ( + void *table_pointer, + unsigned long length) +{ + u8 *p = (u8 *) table_pointer; + unsigned long remains = length; + unsigned long sum = 0; + + if (!p || !length) + return -EINVAL; + + while (remains--) + sum += *p++; + + return (sum & 0xFF); +} + + +int __init +acpi_table_parse_madt ( + enum acpi_table_id id, + acpi_madt_entry_handler handler) +{ + struct acpi_table_madt *madt = NULL; + acpi_table_entry_header *entry = NULL; + unsigned long count = 0; + unsigned long madt_end = 0; + int i = 0; + + if (!handler) + return -EINVAL; + + /* Locate the MADT (if exists). There should only be one. */ + + for (i = 0; i < sdt.count; i++) { + if (sdt.entry[i].id != ACPI_APIC) + continue; + madt = (struct acpi_table_madt *) + __acpi_map_table(sdt.entry[i].pa, sdt.entry[i].size); + if (!madt) { + printk(KERN_WARNING PREFIX "Unable to map MADT\n"); + return -ENODEV; + } + break; + } + + if (!madt) { + printk(KERN_WARNING PREFIX "MADT not present\n"); + return -ENODEV; + } + + madt_end = (unsigned long) madt + sdt.entry[i].size; + + /* Parse all entries looking for a match. */ + + entry = (acpi_table_entry_header *) + ((unsigned long) madt + sizeof(struct acpi_table_madt)); + + while (((unsigned long) entry) < madt_end) { + if (entry->type == id) { + count++; + handler(entry); + } + entry = (acpi_table_entry_header *) + ((unsigned long) entry += entry->length); + } + + return count; +} + + +int __init +acpi_table_parse ( + enum acpi_table_id id, + acpi_table_handler handler) +{ + int count = 0; + int i = 0; + + if (!handler) + return -EINVAL; + + for (i = 0; i < sdt.count; i++) { + if (sdt.entry[i].id != id) + continue; + handler(sdt.entry[i].pa, sdt.entry[i].size); + count++; + } + + return count; +} + + +static int __init +acpi_table_get_sdt ( + struct acpi_table_rsdp *rsdp) +{ + struct acpi_table_header *header = NULL; + int i, id = 0; + + if (!rsdp) + return -EINVAL; + + /* First check XSDT (but only on ACPI 2.0-compatible systems) */ + +#ifdef CONFIG_IA64_SGI_SN1 + if (rsdp->revision < 2) { + rsdp->revision = 2; + } +#endif + if ((rsdp->revision >= 2) && + (((struct acpi20_table_rsdp*)rsdp)->xsdt_address)) { + + struct acpi_table_xsdt *mapped_xsdt = NULL; + + sdt.pa = ((struct acpi20_table_rsdp*)rsdp)->xsdt_address; + + header = (struct acpi_table_header *) + __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header)); + + if (!header) { + printk(KERN_WARNING PREFIX "Unable to map XSDT header\n"); + return -ENODEV; + } + + if (strncmp(header->signature, "XSDT", 4)) { + printk(KERN_WARNING PREFIX "XSDT signature incorrect\n"); + return -ENODEV; + } + + sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3; + if (sdt.count > ACPI_MAX_TABLES) { + printk(KERN_WARNING PREFIX "Truncated %lu XSDT entries\n", + (ACPI_MAX_TABLES - sdt.count)); + sdt.count = ACPI_MAX_TABLES; + } + + mapped_xsdt = (struct acpi_table_xsdt *) + __acpi_map_table(sdt.pa, header->length); + if (!mapped_xsdt) { + printk(KERN_WARNING PREFIX "Unable to map XSDT\n"); + return -ENODEV; + } + + header = &mapped_xsdt->header; + + for (i = 0; i < sdt.count; i++) + sdt.entry[i].pa = (unsigned long) mapped_xsdt->entry[i]; + } + + /* Then check RSDT */ + + else if (rsdp->rsdt_address) { + + struct acpi_table_rsdt *mapped_rsdt = NULL; + + sdt.pa = rsdp->rsdt_address; + + header = (struct acpi_table_header *) + __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header)); + if (!header) { + printk(KERN_WARNING PREFIX "Unable to map RSDT header\n"); + return -ENODEV; + } + + if (strncmp(header->signature, "RSDT", 4)) { + printk(KERN_WARNING PREFIX "RSDT signature incorrect\n"); + return -ENODEV; + } + + sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 2; + if (sdt.count > ACPI_MAX_TABLES) { + printk(KERN_WARNING PREFIX "Truncated %lu RSDT entries\n", + (ACPI_TABLE_COUNT - sdt.count)); + sdt.count = ACPI_MAX_TABLES; + } + + mapped_rsdt = (struct acpi_table_rsdt *) + __acpi_map_table(sdt.pa, header->length); + if (!mapped_rsdt) { + printk(KERN_WARNING PREFIX "Unable to map RSDT\n"); + return -ENODEV; + } + + header = &mapped_rsdt->header; + + for (i = 0; i < sdt.count; i++) + sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i]; + } + + else { + printk(KERN_WARNING PREFIX "No System Description Table (RSDT/XSDT) specified in RSDP\n"); + return -ENODEV; + } + + acpi_table_print(header, sdt.pa); + + for (i = 0; i < sdt.count; i++) { + + header = (struct acpi_table_header *) + __acpi_map_table(sdt.entry[i].pa, + sizeof(struct acpi_table_header)); + if (!header) + continue; + + acpi_table_print(header, sdt.entry[i].pa); + + if (0 != acpi_table_compute_checksum(header, header->length)) { + printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); + continue; + } + + sdt.entry[i].size = header->length; + + for (id = 0; id < ACPI_TABLE_COUNT; id++) { + if (0 == strncmp((char *) &header->signature, + acpi_table_signatures[id], + sizeof(header->signature))) { + sdt.entry[i].id = id; + } + } + } + + return 0; +} + + +int __init +acpi_table_init ( + char *cmdline) +{ + struct acpi_table_rsdp *rsdp = NULL; + unsigned long rsdp_phys = 0; + int result = 0; + + memset(&sdt, 0, sizeof(struct acpi_table_sdt)); + memset(&madt_handlers, 0, sizeof(madt_handlers)); + + /* Locate and map the Root System Description Table (RSDP) */ + + rsdp_phys = acpi_find_rsdp(); + if (!rsdp_phys) { + printk(KERN_ERR PREFIX "Unable to locate RSDP\n"); + return -ENODEV; + } + + rsdp = (struct acpi_table_rsdp *) __va(rsdp_phys); + if (!rsdp) { + printk(KERN_WARNING PREFIX "Unable to map RSDP\n"); + return -ENODEV; + } + + printk(KERN_INFO PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", + rsdp->revision, rsdp->oem_id, (void *) rsdp_phys); + + if (rsdp->revision < 2) + result = acpi_table_compute_checksum(rsdp, sizeof(struct acpi_table_rsdp)); + else + result = acpi_table_compute_checksum(rsdp, ((struct acpi20_table_rsdp *)rsdp)->length); + + if (0 != result) { + printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); + return -ENODEV; + } + + /* Locate and map the System Description table (RSDT/XSDT) */ + + if (0 != acpi_table_get_sdt(rsdp)) + return -ENODEV; + + return 0; +} + diff -Nur linux-2.4.19/drivers/acpi/thermal.c linux-2.4.19-sgi211r3/drivers/acpi/thermal.c --- linux-2.4.19/drivers/acpi/thermal.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/thermal.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,1318 @@ +/* + * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This driver fully implements the ACPI thermal policy as described in the + * ACPI 2.0 Specification. + * + * TBD: 1. Implement passive cooling hysteresis. + * 2. Enhance passive cooling (CPU) states/limit interface to support + * concepts of 'multiple limiters', upper/lower limits, etc. + * + */ + +#include +#include +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_THERMAL_COMPONENT +ACPI_MODULE_NAME ("acpi_thermal") + +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +static int tzp = 0; +MODULE_PARM(tzp, "i"); +MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n"); + +#define PREFIX "ACPI: " + + +#define ACPI_THERMAL_MAX_ACTIVE 10 + +#define KELVIN_TO_CELSIUS(t) ((t-2732+5)/10) + +static int acpi_thermal_add (struct acpi_device *device); +static int acpi_thermal_remove (struct acpi_device *device, int type); + +static struct acpi_driver acpi_thermal_driver = { + name: ACPI_THERMAL_DRIVER_NAME, + class: ACPI_THERMAL_CLASS, + ids: ACPI_THERMAL_HID, + ops: { + add: acpi_thermal_add, + remove: acpi_thermal_remove, + }, +}; + +struct acpi_thermal_state { + u8 critical:1; + u8 hot:1; + u8 passive:1; + u8 active:1; + u8 reserved:4; + int active_index; +}; + +struct acpi_thermal_state_flags { + u8 valid:1; + u8 enabled:1; + u8 reserved:6; +}; + +struct acpi_thermal_critical { + struct acpi_thermal_state_flags flags; + unsigned long temperature; +}; + +struct acpi_thermal_hot { + struct acpi_thermal_state_flags flags; + unsigned long temperature; +}; + +struct acpi_thermal_passive { + struct acpi_thermal_state_flags flags; + unsigned long temperature; + unsigned long tc1; + unsigned long tc2; + unsigned long tsp; + struct acpi_handle_list devices; +}; + +struct acpi_thermal_active { + struct acpi_thermal_state_flags flags; + unsigned long temperature; + struct acpi_handle_list devices; +}; + +struct acpi_thermal_trips { + struct acpi_thermal_critical critical; + struct acpi_thermal_hot hot; + struct acpi_thermal_passive passive; + struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE]; +}; + +struct acpi_thermal_flags { + u8 cooling_mode:1; /* _SCP */ + u8 devices:1; /* _TZD */ + u8 reserved:6; +}; + +struct acpi_thermal { + acpi_handle handle; + acpi_bus_id name; + unsigned long temperature; + unsigned long last_temperature; + unsigned long polling_frequency; + u8 cooling_mode; + struct acpi_thermal_flags flags; + struct acpi_thermal_state state; + struct acpi_thermal_trips trips; + struct acpi_handle_list devices; + struct timer_list timer; +}; + + +/* -------------------------------------------------------------------------- + Thermal Zone Management + -------------------------------------------------------------------------- */ + +static int +acpi_thermal_get_temperature ( + struct acpi_thermal *tz) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE("acpi_thermal_get_temperature"); + + if (!tz) + return_VALUE(-EINVAL); + + tz->last_temperature = tz->temperature; + + status = acpi_evaluate_integer(tz->handle, "_TMP", NULL, &tz->temperature); + if (ACPI_FAILURE(status)) + return -ENODEV; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n", tz->temperature)); + + return_VALUE(0); +} + + +static int +acpi_thermal_get_polling_frequency ( + struct acpi_thermal *tz) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE("acpi_thermal_get_polling_frequency"); + + if (!tz) + return_VALUE(-EINVAL); + + status = acpi_evaluate_integer(tz->handle, "_TZP", NULL, &tz->polling_frequency); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n", tz->polling_frequency)); + + return_VALUE(0); +} + + +static int +acpi_thermal_set_polling ( + struct acpi_thermal *tz, + int seconds) +{ + ACPI_FUNCTION_TRACE("acpi_thermal_set_polling"); + + if (!tz) + return_VALUE(-EINVAL); + + tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */ + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", tz->polling_frequency)); + + return_VALUE(0); +} + + +static int +acpi_thermal_set_cooling_mode ( + struct acpi_thermal *tz, + int mode) +{ + acpi_status status = AE_OK; + acpi_object arg0 = {ACPI_TYPE_INTEGER}; + acpi_object_list arg_list= {1, &arg0}; + acpi_handle handle = NULL; + + ACPI_FUNCTION_TRACE("acpi_thermal_set_cooling_mode"); + + if (!tz) + return_VALUE(-EINVAL); + + status = acpi_get_handle(tz->handle, "_SCP", &handle); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n")); + return_VALUE(-ENODEV); + } + + arg0.integer.value = mode; + + status = acpi_evaluate(handle, NULL, &arg_list, NULL); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + tz->cooling_mode = mode; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n", + mode?"passive":"active")); + + return_VALUE(0); +} + + +static int +acpi_thermal_get_trip_points ( + struct acpi_thermal *tz) +{ + acpi_status status = AE_OK; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_get_trip_points"); + + if (!tz) + return_VALUE(-EINVAL); + + /* Critical Shutdown (required) */ + + status = acpi_evaluate_integer(tz->handle, "_CRT", NULL, + &tz->trips.critical.temperature); + if (ACPI_FAILURE(status)) { + tz->trips.critical.flags.valid = 0; + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n")); + return -ENODEV; + } + else { + tz->trips.critical.flags.valid = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found critical threshold [%lu]\n", tz->trips.critical.temperature)); + } + + /* Critical Sleep (optional) */ + + status = acpi_evaluate_integer(tz->handle, "_HOT", NULL, &tz->trips.hot.temperature); + if (ACPI_FAILURE(status)) { + tz->trips.hot.flags.valid = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n")); + } + else { + tz->trips.hot.flags.valid = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", tz->trips.hot.temperature)); + } + + /* Passive: Processors (optional) */ + + status = acpi_evaluate_integer(tz->handle, "_PSV", NULL, &tz->trips.passive.temperature); + if (ACPI_FAILURE(status)) { + tz->trips.passive.flags.valid = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n")); + } + else { + tz->trips.passive.flags.valid = 1; + + status = acpi_evaluate_integer(tz->handle, "_TC1", NULL, &tz->trips.passive.tc1); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; + + status = acpi_evaluate_integer(tz->handle, "_TC2", NULL, &tz->trips.passive.tc2); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; + + status = acpi_evaluate_integer(tz->handle, "_TSP", NULL, &tz->trips.passive.tsp); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; + + status = acpi_evaluate_reference(tz->handle, "_PSL", NULL, &tz->trips.passive.devices); + if (ACPI_FAILURE(status)) + tz->trips.passive.flags.valid = 0; + + if (!tz->trips.passive.flags.valid) + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid passive threshold\n")); + else + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found passive threshold [%lu]\n", tz->trips.passive.temperature)); + } + + /* Active: Fans, etc. (optional) */ + + for (i=0; ihandle, name, NULL, &tz->trips.active[i].temperature); + if (ACPI_FAILURE(status)) + break; + + name[2] = 'L'; + status = acpi_evaluate_reference(tz->handle, name, NULL, &tz->trips.active[i].devices); + if (ACPI_SUCCESS(status)) { + tz->trips.active[i].flags.valid = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found active threshold [%d]:[%lu]\n", i, tz->trips.active[i].temperature)); + } + else + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid active threshold [%d]\n", i)); + } + + return_VALUE(0); +} + + +static int +acpi_thermal_get_devices ( + struct acpi_thermal *tz) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE("acpi_thermal_get_devices"); + + if (!tz) + return_VALUE(-EINVAL); + + status = acpi_evaluate_reference(tz->handle, "_TZD", NULL, &tz->devices); + if (ACPI_FAILURE(status)) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +static int +acpi_thermal_call_usermode ( + char *path) +{ + char *argv[2] = {NULL, NULL}; + char *envp[3] = {NULL, NULL, NULL}; + + ACPI_FUNCTION_TRACE("acpi_thermal_call_usermode"); + + if (!path) + return_VALUE(-EINVAL);; + + argv[0] = path; + + /* minimal command environment */ + envp[0] = "HOME=/"; + envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + + call_usermodehelper(argv[0], argv, envp); + + return_VALUE(0); +} + + +static int +acpi_thermal_critical ( + struct acpi_thermal *tz) +{ + int result = 0; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_thermal_critical"); + + if (!tz || !tz->trips.critical.flags.valid) + return_VALUE(-EINVAL); + + if (tz->temperature >= tz->trips.critical.temperature) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Critical trip point\n")); + tz->trips.critical.flags.enabled = 1; + } + else if (tz->trips.critical.flags.enabled) + tz->trips.critical.flags.enabled = 0; + + result = acpi_bus_get_device(tz->handle, &device); + if (0 != result) + return_VALUE(result); + + acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL, tz->trips.critical.flags.enabled); + + acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF); + + return_VALUE(0); +} + + +static int +acpi_thermal_hot ( + struct acpi_thermal *tz) +{ + int result = 0; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_thermal_hot"); + + if (!tz || !tz->trips.hot.flags.valid) + return_VALUE(-EINVAL); + + if (tz->temperature >= tz->trips.hot.temperature) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Hot trip point\n")); + tz->trips.hot.flags.enabled = 1; + } + else if (tz->trips.hot.flags.enabled) + tz->trips.hot.flags.enabled = 0; + + result = acpi_bus_get_device(tz->handle, &device); + if (0 != result) + return_VALUE(result); + + acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_HOT, tz->trips.hot.flags.enabled); + + /* TBD: Call user-mode "sleep(S4)" function */ + + return_VALUE(0); +} + + +static int +acpi_thermal_passive ( + struct acpi_thermal *tz) +{ + int result = 0; + struct acpi_thermal_passive *passive = NULL; + int trend = 0; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_passive"); + + if (!tz || !tz->trips.passive.flags.valid) + return_VALUE(-EINVAL); + + passive = &(tz->trips.passive); + + /* + * Above Trip? + * ----------- + * Calculate the thermal trend (using the passive cooling equation) + * and modify the performance limit for all passive cooling devices + * accordingly. Note that we assume symmetry. + */ + if (tz->temperature >= passive->temperature) { + trend = (passive->tc1 * (tz->temperature - tz->last_temperature)) + (passive->tc2 * (tz->temperature - passive->temperature)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n", + trend, passive->tc1, tz->temperature, + tz->last_temperature, passive->tc2, + tz->temperature, passive->temperature)); + /* Heating up? */ + if (trend > 0) + for (i=0; idevices.count; i++) + acpi_processor_set_thermal_limit( + passive->devices.handles[i], + ACPI_PROCESSOR_LIMIT_INCREMENT); + /* Cooling off? */ + else if (trend < 0) + for (i=0; idevices.count; i++) + acpi_processor_set_thermal_limit( + passive->devices.handles[i], + ACPI_PROCESSOR_LIMIT_DECREMENT); + } + + /* + * Below Trip? + * ----------- + * Implement passive cooling hysteresis to slowly increase performance + * and avoid thrashing around the passive trip point. Note that we + * assume symmetry. + */ + else if (tz->trips.passive.flags.enabled) { + for (i=0; idevices.count; i++) + result = acpi_processor_set_thermal_limit( + passive->devices.handles[i], + ACPI_PROCESSOR_LIMIT_DECREMENT); + if (1 == result) { + tz->trips.passive.flags.enabled = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Disabling passive cooling (zone is cool)\n")); + } + } + + return_VALUE(0); +} + + +static int +acpi_thermal_active ( + struct acpi_thermal *tz) +{ + int result = 0; + struct acpi_thermal_active *active = NULL; + int i = 0; + int j = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_active"); + + if (!tz) + return_VALUE(-EINVAL); + + for (i=0; itrips.active[i]); + if (!active || !active->flags.valid) + break; + + /* + * Above Threshold? + * ---------------- + * If not already enabled, turn ON all cooling devices + * associated with this active threshold. + */ + if (tz->temperature >= active->temperature) { + tz->state.active_index = i; + if (!active->flags.enabled) { + for (j = 0; j < active->devices.count; j++) { + result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D0); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'on'\n", active->devices.handles[j])); + continue; + } + active->flags.enabled = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'on'\n", active->devices.handles[j])); + } + } + } + /* + * Below Threshold? + * ---------------- + * Turn OFF all cooling devices associated with this + * threshold. + */ + else if (active->flags.enabled) { + for (j = 0; j < active->devices.count; j++) { + result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D3); + if (0 != result) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'off'\n", active->devices.handles[j])); + continue; + } + active->flags.enabled = 0; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'off'\n", active->devices.handles[j])); + } + } + } + + return_VALUE(0); +} + + +static void acpi_thermal_check (void *context); + +static void +acpi_thermal_run ( + unsigned long data) +{ + acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_thermal_check, (void *) data); +} + + +static void +acpi_thermal_check ( + void *data) +{ + int result = 0; + struct acpi_thermal *tz = (struct acpi_thermal *) data; + unsigned long sleep_time = 0; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_check"); + + if (!tz) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n")); + return_VOID; + } + + result = acpi_thermal_get_temperature(tz); + if (0 != result) + return_VOID; + + memset(&tz->state, 0, sizeof(tz->state)); + + /* + * Check Trip Points + * ----------------- + * Compare the current temperature to the trip point values to see + * if we've entered one of the thermal policy states. Note that + * this function determines when a state is entered, but the + * individual policy decides when it is exited (e.g. hysteresis). + */ + if ((tz->trips.critical.flags.valid) && (tz->temperature >= tz->trips.critical.temperature)) + tz->trips.critical.flags.enabled = 1; + if ((tz->trips.hot.flags.valid) && (tz->temperature >= tz->trips.hot.temperature)) + tz->trips.hot.flags.enabled = 1; + if ((tz->trips.passive.flags.valid) && (tz->temperature >= tz->trips.passive.temperature)) + tz->trips.passive.flags.enabled = 1; + for (i=0; itrips.active[i].flags.valid) && (tz->temperature >= tz->trips.active[i].temperature)) + tz->trips.active[i].flags.enabled = 1; + + /* + * Invoke Policy + * ------------- + * Separated from the above check to allow individual policy to + * determine when to exit a given state. + */ + if (tz->trips.critical.flags.enabled) + acpi_thermal_critical(tz); + if (tz->trips.hot.flags.enabled) + acpi_thermal_hot(tz); + if (tz->trips.passive.flags.enabled) + acpi_thermal_passive(tz); + if (tz->trips.active[0].flags.enabled) + acpi_thermal_active(tz); + + /* + * Calculate State + * --------------- + * Again, separated from the above two to allow independent policy + * decisions. + */ + if (tz->trips.critical.flags.enabled) + tz->state.critical = 1; + if (tz->trips.hot.flags.enabled) + tz->state.hot = 1; + if (tz->trips.passive.flags.enabled) + tz->state.passive = 1; + for (i=0; itrips.active[i].flags.enabled) + tz->state.active = 1; + + /* + * Calculate Sleep Time + * -------------------- + * If we're in the passive state, use _TSP's value. Otherwise + * use the default polling frequency (e.g. _TZP). If no polling + * frequency is specified then we'll wait forever (at least until + * a thermal event occurs). Note that _TSP and _TZD values are + * given in 1/10th seconds (we must covert to milliseconds). + */ + if (tz->state.passive) + sleep_time = tz->trips.passive.tsp * 100; + else if (tz->polling_frequency > 0) + sleep_time = tz->polling_frequency * 100; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n", + tz->name, tz->temperature, sleep_time)); + + /* + * Schedule Next Poll + * ------------------ + */ + if (!sleep_time) { + if (timer_pending(&(tz->timer))) + del_timer(&(tz->timer)); + } + else { + if (timer_pending(&(tz->timer))) + mod_timer(&(tz->timer), (HZ * sleep_time) / 1000); + else { + tz->timer.data = (unsigned long) tz; + tz->timer.function = acpi_thermal_run; + tz->timer.expires = jiffies + (HZ * sleep_time) / 1000; + add_timer(&(tz->timer)); + } + } + + return_VOID; +} + + +/* -------------------------------------------------------------------------- + FS Interface (/proc) + -------------------------------------------------------------------------- */ + +#include +#include + +struct proc_dir_entry *acpi_thermal_dir = NULL; + + +static int +acpi_thermal_read_state ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_thermal *tz = (struct acpi_thermal *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_read_state"); + + if (!tz || (off != 0)) + goto end; + + p += sprintf(p, "state: "); + + if (!tz->state.critical && !tz->state.hot && !tz->state.passive && !tz->state.active) + p += sprintf(p, "ok\n"); + else { + if (tz->state.critical) + p += sprintf(p, "critical "); + if (tz->state.hot) + p += sprintf(p, "hot "); + if (tz->state.passive) + p += sprintf(p, "passive "); + if (tz->state.active) + p += sprintf(p, "active[%d]", tz->state.active_index); + p += sprintf(p, "\n"); + } + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_thermal_read_temperature ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + int result = 0; + struct acpi_thermal *tz = (struct acpi_thermal *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_read_temperature"); + + if (!tz || (off != 0)) + goto end; + + result = acpi_thermal_get_temperature(tz); + if (0 != result) + goto end; + + p += sprintf(p, "temperature: %lu C\n", + KELVIN_TO_CELSIUS(tz->temperature)); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_thermal_read_trip_points ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_thermal *tz = (struct acpi_thermal *) data; + char *p = page; + int len = 0; + int i = 0; + int j = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_read_trip_points"); + + if (!tz || (off != 0)) + goto end; + + if (tz->trips.critical.flags.valid) + p += sprintf(p, "critical (S5): %lu C\n", + KELVIN_TO_CELSIUS(tz->trips.critical.temperature)); + + if (tz->trips.hot.flags.valid) + p += sprintf(p, "hot (S4): %lu C\n", + KELVIN_TO_CELSIUS(tz->trips.hot.temperature)); + + if (tz->trips.passive.flags.valid) { + p += sprintf(p, "passive: %lu C: tc1=%lu tc2=%lu tsp=%lu devices=", + KELVIN_TO_CELSIUS(tz->trips.passive.temperature), + tz->trips.passive.tc1, + tz->trips.passive.tc2, + tz->trips.passive.tsp); + for (j=0; jtrips.passive.devices.count; j++) { + + p += sprintf(p, "0x%p ", tz->trips.passive.devices.handles[j]); + } + p += sprintf(p, "\n"); + } + + for (i=0; itrips.active[i].flags.valid)) + break; + p += sprintf(p, "active[%d]: %lu C: devices=", + i, KELVIN_TO_CELSIUS(tz->trips.active[i].temperature)); + for (j=0; jtrips.active[i].devices.count; j++) + p += sprintf(p, "0x%p ", + tz->trips.active[i].devices.handles[j]); + p += sprintf(p, "\n"); + } + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_thermal_read_cooling_mode ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_thermal *tz = (struct acpi_thermal *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_read_cooling_mode"); + + if (!tz || (off != 0)) + goto end; + + if (!tz->flags.cooling_mode) { + p += sprintf(p, "\n"); + goto end; + } + + p += sprintf(p, "cooling mode: %s\n", + tz->cooling_mode?"passive":"active"); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_thermal_write_cooling_mode ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + struct acpi_thermal *tz = (struct acpi_thermal *) data; + char mode_string[12] = {'\0'}; + + ACPI_FUNCTION_TRACE("acpi_thermal_write_cooling_mode"); + + if (!tz || (count > sizeof(mode_string) - 1)) + return_VALUE(-EINVAL); + + if (!tz->flags.cooling_mode) + return_VALUE(-ENODEV); + + if (copy_from_user(mode_string, buffer, count)) + return_VALUE(-EFAULT); + + mode_string[count] = '\0'; + + result = acpi_thermal_set_cooling_mode(tz, + simple_strtoul(mode_string, NULL, 0)); + if (0 != result) + return_VALUE(result); + + return_VALUE(count); +} + + +static int +acpi_thermal_read_polling ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + struct acpi_thermal *tz = (struct acpi_thermal *) data; + char *p = page; + int len = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_read_polling"); + + if (!tz || (off != 0)) + goto end; + + if (!tz->polling_frequency) { + p += sprintf(p, "\n"); + goto end; + } + + p += sprintf(p, "polling frequency: %lu seconds\n", + (tz->polling_frequency / 10)); + +end: + len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + + return_VALUE(len); +} + + +static int +acpi_thermal_write_polling ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + struct acpi_thermal *tz = (struct acpi_thermal *) data; + char polling_string[12] = {'\0'}; + int seconds = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_write_polling"); + + if (!tz || (count > sizeof(polling_string) - 1)) + return_VALUE(-EINVAL); + + if (copy_from_user(polling_string, buffer, count)) + return_VALUE(-EFAULT); + + polling_string[count] = '\0'; + + seconds = simple_strtoul(polling_string, NULL, 0); + + result = acpi_thermal_set_polling(tz, seconds); + if (0 != result) + return_VALUE(result); + + acpi_thermal_check(tz); + + return_VALUE(count); +} + + +static int +acpi_thermal_add_fs ( + struct acpi_device *device) +{ + struct proc_dir_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_thermal_add_fs"); + + if (!acpi_thermal_dir) { + acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, + acpi_root_dir); + if (!acpi_thermal_dir) + return_VALUE(-ENODEV); + } + + if (!acpi_device_dir(device)) { + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), + acpi_thermal_dir); + if (!acpi_device_dir(device)) + return_VALUE(-ENODEV); + } + + /* 'state' [R] */ + entry = create_proc_entry(ACPI_THERMAL_FILE_STATE, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_THERMAL_FILE_STATE)); + else { + entry->read_proc = acpi_thermal_read_state; + entry->data = acpi_driver_data(device); + } + + /* 'temperature' [R] */ + entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_THERMAL_FILE_TEMPERATURE)); + else { + entry->read_proc = acpi_thermal_read_temperature; + entry->data = acpi_driver_data(device); + } + + /* 'trip_points' [R] */ + entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS, + S_IRUGO, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_THERMAL_FILE_POLLING_FREQ)); + else { + entry->read_proc = acpi_thermal_read_trip_points; + entry->data = acpi_driver_data(device); + } + + /* 'cooling_mode' [R/W] */ + entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_THERMAL_FILE_COOLING_MODE)); + else { + entry->read_proc = acpi_thermal_read_cooling_mode; + entry->write_proc = acpi_thermal_write_cooling_mode; + entry->data = acpi_driver_data(device); + } + + /* 'polling_frequency' [R/W] */ + entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_THERMAL_FILE_POLLING_FREQ)); + else { + entry->read_proc = acpi_thermal_read_polling; + entry->write_proc = acpi_thermal_write_polling; + entry->data = acpi_driver_data(device); + } + + return_VALUE(0); +} + + +static int +acpi_thermal_remove_fs ( + struct acpi_device *device) +{ + ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs"); + + if (!acpi_thermal_dir) + return_VALUE(-ENODEV); + + if (acpi_device_dir(device)) + remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir); + + return_VALUE(0); +} + + +/* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ + +static void +acpi_thermal_notify ( + acpi_handle handle, + u32 event, + void *data) +{ + struct acpi_thermal *tz = (struct acpi_thermal *) data; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_thermal_notify"); + + if (!tz) + return_VOID; + + if (0 != acpi_bus_get_device(tz->handle, &device)) + return_VOID; + + switch (event) { + case ACPI_THERMAL_NOTIFY_TEMPERATURE: + acpi_thermal_check(tz); + break; + case ACPI_THERMAL_NOTIFY_THRESHOLDS: + acpi_thermal_get_trip_points(tz); + acpi_thermal_check(tz); + acpi_bus_generate_event(device, event, 0); + break; + case ACPI_THERMAL_NOTIFY_DEVICES: + if (tz->flags.devices) + acpi_thermal_get_devices(tz); + acpi_bus_generate_event(device, event, 0); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + return_VOID; +} + + +static int +acpi_thermal_get_info ( + struct acpi_thermal *tz) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_get_info"); + + if (!tz) + return_VALUE(-EINVAL); + + /* Get temperature [_TMP] (required) */ + result = acpi_thermal_get_temperature(tz); + if (0 != result) + return_VALUE(result); + + /* Set the cooling mode [_SCP] to active cooling (default) */ + result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); + if (0 == result) + tz->flags.cooling_mode = 1; + + /* Get trip points [_CRT, _PSV, etc.] (required) */ + result = acpi_thermal_get_trip_points(tz); + if (0 != result) + return_VALUE(result); + + /* Get default polling frequency [_TZP] (optional) */ + if (tzp) + tz->polling_frequency = tzp; + else + acpi_thermal_get_polling_frequency(tz); + + /* Get devices in this thermal zone [_TZD] (optional) */ + result = acpi_thermal_get_devices(tz); + if (0 == result) + tz->flags.devices = 1; + + return_VALUE(0); +} + + +static int +acpi_thermal_add ( + struct acpi_device *device) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_thermal *tz = NULL; + + ACPI_FUNCTION_TRACE("acpi_thermal_add"); + + if (!device) + return_VALUE(-EINVAL); + + tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL); + if (!tz) + return_VALUE(-ENOMEM); + memset(tz, 0, sizeof(struct acpi_thermal)); + + tz->handle = device->handle; + sprintf(tz->name, "%s", device->pnp.bus_id); + sprintf(acpi_device_name(device), "%s", ACPI_THERMAL_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_THERMAL_CLASS); + acpi_driver_data(device) = tz; + + result = acpi_thermal_get_info(tz); + if (0 != result) + goto end; + + result = acpi_thermal_add_fs(device); + if (0 != result) + return_VALUE(result); + + acpi_thermal_check(tz); + + status = acpi_install_notify_handler(tz->handle, + ACPI_DEVICE_NOTIFY, acpi_thermal_notify, tz); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error installing notify handler\n")); + result = -ENODEV; + goto end; + } + + init_timer(&tz->timer); + + printk(KERN_INFO PREFIX "%s [%s] (%lu C)\n", + acpi_device_name(device), acpi_device_bid(device), + KELVIN_TO_CELSIUS(tz->temperature)); + +end: + if (result) { + acpi_thermal_remove_fs(device); + kfree(tz); + } + + return_VALUE(result); +} + + +static int +acpi_thermal_remove ( + struct acpi_device *device, + int type) +{ + acpi_status status = AE_OK; + struct acpi_thermal *tz = NULL; + + ACPI_FUNCTION_TRACE("acpi_thermal_remove"); + + if (!device || !acpi_driver_data(device)) + return_VALUE(-EINVAL); + + tz = (struct acpi_thermal *) acpi_driver_data(device); + + if (timer_pending(&(tz->timer))) + del_timer(&(tz->timer)); + + status = acpi_remove_notify_handler(tz->handle, + ACPI_DEVICE_NOTIFY, acpi_thermal_notify); + if (ACPI_FAILURE(status)) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error removing notify handler\n")); + + /* Terminate policy */ + if (tz->trips.passive.flags.valid + && tz->trips.passive.flags.enabled) { + tz->trips.passive.flags.enabled = 0; + acpi_thermal_passive(tz); + } + if (tz->trips.active[0].flags.valid + && tz->trips.active[0].flags.enabled) { + tz->trips.active[0].flags.enabled = 0; + acpi_thermal_active(tz); + } + + acpi_thermal_remove_fs(device); + + return_VALUE(0); +} + + +static int __init +acpi_thermal_init (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_init"); + + result = acpi_bus_register_driver(&acpi_thermal_driver); + if (0 > result) + return_VALUE(-ENODEV); + + return_VALUE(0); +} + + +static void __exit +acpi_thermal_exit (void) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_thermal_exit"); + + result = acpi_bus_unregister_driver(&acpi_thermal_driver); + if (0 == result) + remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir); + + return_VOID; +} + + +module_init(acpi_thermal_init); +module_exit(acpi_thermal_exit); diff -Nur linux-2.4.19/drivers/acpi/utilities/Makefile linux-2.4.19-sgi211r3/drivers/acpi/utilities/Makefile --- linux-2.4.19/drivers/acpi/utilities/Makefile Wed Jun 20 17:47:40 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/Makefile Fri Apr 26 11:07:18 2002 @@ -1,11 +1,10 @@ # # Makefile for all Linux ACPI interpreter subdirectories -# EXCEPT for the ospm directory # O_TARGET := $(notdir $(CURDIR)).o -obj-$(CONFIG_ACPI) := $(patsubst %.c,%.o,$(wildcard *.c)) +obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c)) EXTRA_CFLAGS += $(ACPI_CFLAGS) diff -Nur linux-2.4.19/drivers/acpi/utilities/utalloc.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utalloc.c --- linux-2.4.19/drivers/acpi/utilities/utalloc.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utalloc.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: utalloc - local cache and memory allocation routines - * $Revision: 106 $ + * $Revision: 127 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,9 @@ #include "acpi.h" -#include "acparser.h" -#include "acinterp.h" -#include "acnamesp.h" -#include "acglobal.h" #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utalloc") + ACPI_MODULE_NAME ("utalloc") /****************************************************************************** @@ -56,7 +52,7 @@ ACPI_MEMORY_LIST *cache_info; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* If walk cache is full, just free this wallkstate object */ @@ -70,20 +66,22 @@ /* Otherwise put this object back into the cache */ else { - acpi_ut_acquire_mutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) { + return; + } /* Mark the object as cached */ - MEMSET (object, 0xCA, cache_info->object_size); - ((acpi_operand_object *) object)->common.data_type = ACPI_CACHED_OBJECT; + ACPI_MEMSET (object, 0xCA, cache_info->object_size); + ACPI_SET_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_CACHED); /* Put the object at the head of the cache list */ - * (char **) (((char *) object) + cache_info->link_offset) = cache_info->list_head; + * (ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head; cache_info->list_head = object; cache_info->cache_depth++; - acpi_ut_release_mutex (ACPI_MTX_CACHES); + (void) acpi_ut_release_mutex (ACPI_MTX_CACHES); } } @@ -110,11 +108,14 @@ void *object; - PROC_NAME ("Ut_acquire_from_cache"); + ACPI_FUNCTION_NAME ("Ut_acquire_from_cache"); cache_info = &acpi_gbl_memory_lists[list_id]; - acpi_ut_acquire_mutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) { + return (NULL); + } + ACPI_MEM_TRACKING (cache_info->cache_requests++); /* Check the cache first */ @@ -123,7 +124,7 @@ /* There is an object available, use it */ object = cache_info->list_head; - cache_info->list_head = * (char **) (((char *) object) + cache_info->link_offset); + cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))); ACPI_MEM_TRACKING (cache_info->cache_hits++); cache_info->cache_depth--; @@ -133,11 +134,13 @@ object, acpi_gbl_memory_lists[list_id].list_name)); #endif - acpi_ut_release_mutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (acpi_ut_release_mutex (ACPI_MTX_CACHES))) { + return (NULL); + } /* Clear (zero) the previously used Object */ - MEMSET (object, 0, cache_info->object_size); + ACPI_MEMSET (object, 0, cache_info->object_size); } else { @@ -145,7 +148,9 @@ /* Avoid deadlock with ACPI_MEM_CALLOCATE */ - acpi_ut_release_mutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (acpi_ut_release_mutex (ACPI_MTX_CACHES))) { + return (NULL); + } object = ACPI_MEM_CALLOCATE (cache_info->object_size); ACPI_MEM_TRACKING (cache_info->total_allocated++); @@ -175,14 +180,14 @@ char *next; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); cache_info = &acpi_gbl_memory_lists[list_id]; while (cache_info->list_head) { /* Delete one cached state object */ - next = * (char **) (((char *) cache_info->list_head) + cache_info->link_offset); + next = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) cache_info->list_head)[cache_info->link_offset]))); ACPI_MEM_FREE (cache_info->list_head); cache_info->list_head = next; @@ -191,9 +196,230 @@ } -#ifdef ACPI_DBG_TRACK_ALLOCATIONS +/******************************************************************************* + * + * FUNCTION: Acpi_ut_validate_buffer + * + * PARAMETERS: Buffer - Buffer descriptor to be validated + * + * RETURN: Status + * + * DESCRIPTION: Perform parameter validation checks on an acpi_buffer + * + ******************************************************************************/ + +acpi_status +acpi_ut_validate_buffer ( + acpi_buffer *buffer) +{ + + /* Obviously, the structure pointer must be valid */ + + if (!buffer) { + return (AE_BAD_PARAMETER); + } + + /* Special semantics for the length */ + + if ((buffer->length == ACPI_NO_BUFFER) || + (buffer->length == ACPI_ALLOCATE_BUFFER) || + (buffer->length == ACPI_ALLOCATE_LOCAL_BUFFER)) { + return (AE_OK); + } + + /* Length is valid, the buffer pointer must be also */ + + if (!buffer->pointer) { + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_initialize_buffer + * + * PARAMETERS: Required_length - Length needed + * Buffer - Buffer to be validated + * + * RETURN: Status + * + * DESCRIPTION: Validate that the buffer is of the required length or + * allocate a new buffer. + * + ******************************************************************************/ + +acpi_status +acpi_ut_initialize_buffer ( + acpi_buffer *buffer, + ACPI_SIZE required_length) +{ + acpi_status status = AE_OK; + + + switch (buffer->length) { + case ACPI_NO_BUFFER: + + /* Set the exception and returned the required length */ + + status = AE_BUFFER_OVERFLOW; + break; + + + case ACPI_ALLOCATE_BUFFER: + + /* Allocate a new buffer */ + + buffer->pointer = acpi_os_allocate (required_length); + if (!buffer->pointer) { + return (AE_NO_MEMORY); + } + + /* Clear the buffer */ + + ACPI_MEMSET (buffer->pointer, 0, required_length); + break; + + + case ACPI_ALLOCATE_LOCAL_BUFFER: + /* Allocate a new buffer with local interface to allow tracking */ + + buffer->pointer = ACPI_MEM_ALLOCATE (required_length); + if (!buffer->pointer) { + return (AE_NO_MEMORY); + } + + /* Clear the buffer */ + + ACPI_MEMSET (buffer->pointer, 0, required_length); + break; + + + default: + + /* Validate the size of the buffer */ + + if (buffer->length < required_length) { + status = AE_BUFFER_OVERFLOW; + } + + /* Clear the buffer */ + + ACPI_MEMSET (buffer->pointer, 0, required_length); + break; + } + + buffer->length = required_length; + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_allocate + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: The subsystem's equivalent of malloc. + * + ******************************************************************************/ + +void * +acpi_ut_allocate ( + ACPI_SIZE size, + u32 component, + NATIVE_CHAR *module, + u32 line) +{ + void *allocation; + + + ACPI_FUNCTION_TRACE_U32 ("Ut_allocate", size); + + + /* Check for an inadvertent size of zero bytes */ + + if (!size) { + _ACPI_REPORT_ERROR (module, line, component, + ("Ut_allocate: Attempt to allocate zero bytes\n")); + size = 1; + } + + allocation = acpi_os_allocate (size); + if (!allocation) { + /* Report allocation error */ + + _ACPI_REPORT_ERROR (module, line, component, + ("Ut_allocate: Could not allocate size %X\n", (u32) size)); + + return_PTR (NULL); + } + return_PTR (allocation); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_callocate + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. + * + ******************************************************************************/ + +void * +acpi_ut_callocate ( + ACPI_SIZE size, + u32 component, + NATIVE_CHAR *module, + u32 line) +{ + void *allocation; + + + ACPI_FUNCTION_TRACE_U32 ("Ut_callocate", size); + + + /* Check for an inadvertent size of zero bytes */ + + if (!size) { + _ACPI_REPORT_ERROR (module, line, component, + ("Ut_callocate: Attempt to allocate zero bytes\n")); + return_PTR (NULL); + } + + allocation = acpi_os_allocate (size); + if (!allocation) { + /* Report allocation error */ + + _ACPI_REPORT_ERROR (module, line, component, + ("Ut_callocate: Could not allocate size %X\n", (u32) size)); + return_PTR (NULL); + } + + /* Clear the memory block */ + + ACPI_MEMSET (allocation, 0, size); + return_PTR (allocation); +} + + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS /* * These procedures are used for tracking memory leaks in the subsystem, and * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. @@ -208,9 +434,162 @@ /******************************************************************************* * + * FUNCTION: Acpi_ut_allocate_and_track + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: The subsystem's equivalent of malloc. + * + ******************************************************************************/ + +void * +acpi_ut_allocate_and_track ( + ACPI_SIZE size, + u32 component, + NATIVE_CHAR *module, + u32 line) +{ + acpi_debug_mem_block *allocation; + acpi_status status; + + + allocation = acpi_ut_allocate (size + sizeof (acpi_debug_mem_block), component, + module, line); + if (!allocation) { + return (NULL); + } + + status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, allocation, size, + ACPI_MEM_MALLOC, component, module, line); + if (ACPI_FAILURE (status)) { + acpi_os_free (allocation); + return (NULL); + } + + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++; + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += (u32) size; + + return ((void *) &allocation->user_space); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_callocate_and_track + * + * PARAMETERS: Size - Size of the allocation + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. + * + ******************************************************************************/ + +void * +acpi_ut_callocate_and_track ( + ACPI_SIZE size, + u32 component, + NATIVE_CHAR *module, + u32 line) +{ + acpi_debug_mem_block *allocation; + acpi_status status; + + + allocation = acpi_ut_callocate (size + sizeof (acpi_debug_mem_block), component, + module, line); + if (!allocation) { + /* Report allocation error */ + + _ACPI_REPORT_ERROR (module, line, component, + ("Ut_callocate: Could not allocate size %X\n", (u32) size)); + return (NULL); + } + + status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, allocation, size, + ACPI_MEM_CALLOC, component, module, line); + if (ACPI_FAILURE (status)) { + acpi_os_free (allocation); + return (NULL); + } + + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++; + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += (u32) size; + + return ((void *) &allocation->user_space); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_free_and_track + * + * PARAMETERS: Allocation - Address of the memory to deallocate + * Component - Component type of caller + * Module - Source file name of caller + * Line - Line number of caller + * + * RETURN: None + * + * DESCRIPTION: Frees the memory at Allocation + * + ******************************************************************************/ + +void +acpi_ut_free_and_track ( + void *allocation, + u32 component, + NATIVE_CHAR *module, + u32 line) +{ + acpi_debug_mem_block *debug_block; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("Ut_free", allocation); + + + if (NULL == allocation) { + _ACPI_REPORT_ERROR (module, line, component, + ("Acpi_ut_free: Attempt to delete a NULL address\n")); + + return_VOID; + } + + debug_block = ACPI_CAST_PTR (acpi_debug_mem_block, + (((char *) allocation) - sizeof (acpi_debug_mem_header))); + + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_freed++; + acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size -= debug_block->size; + + status = acpi_ut_remove_allocation (ACPI_MEM_LIST_GLOBAL, debug_block, + component, module, line); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not free memory, %s\n", + acpi_format_exception (status))); + } + + acpi_os_free (debug_block); + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation)); + + return_VOID; +} + + +/******************************************************************************* + * * FUNCTION: Acpi_ut_find_allocation * - * PARAMETERS: Address - Address of allocated memory + * PARAMETERS: Allocation - Address of allocated memory * * RETURN: A list element if found; NULL otherwise. * @@ -221,12 +600,12 @@ acpi_debug_mem_block * acpi_ut_find_allocation ( u32 list_id, - void *address) + void *allocation) { acpi_debug_mem_block *element; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); if (list_id > ACPI_MEM_LIST_MAX) { @@ -238,7 +617,7 @@ /* Search for the address. */ while (element) { - if (element == address) { + if (element == allocation) { return (element); } @@ -253,7 +632,7 @@ * * FUNCTION: Acpi_ut_track_allocation * - * PARAMETERS: Address - Address of allocated memory + * PARAMETERS: Allocation - Address of allocated memory * Size - Size of the allocation * Alloc_type - MEM_MALLOC or MEM_CALLOC * Component - Component type of caller @@ -269,8 +648,8 @@ acpi_status acpi_ut_track_allocation ( u32 list_id, - acpi_debug_mem_block *address, - u32 size, + acpi_debug_mem_block *allocation, + ACPI_SIZE size, u8 alloc_type, u32 component, NATIVE_CHAR *module, @@ -281,7 +660,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_PTR ("Ut_track_allocation", address); + ACPI_FUNCTION_TRACE_PTR ("Ut_track_allocation", allocation); if (list_id > ACPI_MEM_LIST_MAX) { @@ -289,46 +668,49 @@ } mem_list = &acpi_gbl_memory_lists[list_id]; - acpi_ut_acquire_mutex (ACPI_MTX_MEMORY); + status = acpi_ut_acquire_mutex (ACPI_MTX_MEMORY); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* * Search list for this address to make sure it is not already on the list. * This will catch several kinds of problems. */ - element = acpi_ut_find_allocation (list_id, address); + element = acpi_ut_find_allocation (list_id, allocation); if (element) { - REPORT_ERROR (("Ut_track_allocation: Address already present in list! (%p)\n", - address)); + ACPI_REPORT_ERROR (("Ut_track_allocation: Allocation already present in list! (%p)\n", + allocation)); - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", element, address)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", element, allocation)); goto unlock_and_exit; } /* Fill in the instance data. */ - address->size = size; - address->alloc_type = alloc_type; - address->component = component; - address->line = line; + allocation->size = (u32) size; + allocation->alloc_type = alloc_type; + allocation->component = component; + allocation->line = line; - STRNCPY (address->module, module, MAX_MODULE_NAME); + ACPI_STRNCPY (allocation->module, module, ACPI_MAX_MODULE_NAME); /* Insert at list head */ if (mem_list->list_head) { - ((acpi_debug_mem_block *)(mem_list->list_head))->previous = address; + ((acpi_debug_mem_block *)(mem_list->list_head))->previous = allocation; } - address->next = mem_list->list_head; - address->previous = NULL; + allocation->next = mem_list->list_head; + allocation->previous = NULL; - mem_list->list_head = address; + mem_list->list_head = allocation; unlock_and_exit: - acpi_ut_release_mutex (ACPI_MTX_MEMORY); + status = acpi_ut_release_mutex (ACPI_MTX_MEMORY); return_ACPI_STATUS (status); } @@ -337,7 +719,7 @@ * * FUNCTION: Acpi_ut_remove_allocation * - * PARAMETERS: Address - Address of allocated memory + * PARAMETERS: Allocation - Address of allocated memory * Component - Component type of caller * Module - Source file name of caller * Line - Line number of caller @@ -351,15 +733,16 @@ acpi_status acpi_ut_remove_allocation ( u32 list_id, - acpi_debug_mem_block *address, + acpi_debug_mem_block *allocation, u32 component, NATIVE_CHAR *module, u32 line) { ACPI_MEMORY_LIST *mem_list; + acpi_status status; - FUNCTION_TRACE ("Ut_remove_allocation"); + ACPI_FUNCTION_TRACE ("Ut_remove_allocation"); if (list_id > ACPI_MEM_LIST_MAX) { @@ -370,37 +753,38 @@ if (NULL == mem_list->list_head) { /* No allocations! */ - _REPORT_ERROR (module, line, component, + _ACPI_REPORT_ERROR (module, line, component, ("Ut_remove_allocation: Empty allocation list, nothing to free!\n")); return_ACPI_STATUS (AE_OK); } - - acpi_ut_acquire_mutex (ACPI_MTX_MEMORY); + status = acpi_ut_acquire_mutex (ACPI_MTX_MEMORY); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* Unlink */ - if (address->previous) { - (address->previous)->next = address->next; + if (allocation->previous) { + (allocation->previous)->next = allocation->next; } else { - mem_list->list_head = address->next; + mem_list->list_head = allocation->next; } - if (address->next) { - (address->next)->previous = address->previous; + if (allocation->next) { + (allocation->next)->previous = allocation->previous; } - /* Mark the segment as deleted */ - MEMSET (&address->user_space, 0xEA, address->size); + ACPI_MEMSET (&allocation->user_space, 0xEA, allocation->size); - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size %X\n", address->size)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size %X\n", allocation->size)); - acpi_ut_release_mutex (ACPI_MTX_MEMORY); - return_ACPI_STATUS (AE_OK); + status = acpi_ut_release_mutex (ACPI_MTX_MEMORY); + return_ACPI_STATUS (status); } @@ -424,7 +808,7 @@ ACPI_MEMORY_LIST *Mem_list; */ - FUNCTION_TRACE ("Ut_dump_allocation_info"); + ACPI_FUNCTION_TRACE ("Ut_dump_allocation_info"); /* ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, @@ -482,302 +866,120 @@ NATIVE_CHAR *module) { acpi_debug_mem_block *element; - u32 i; + ACPI_DESCRIPTOR *descriptor; + u32 num_outstanding = 0; - FUNCTION_TRACE ("Ut_dump_allocations"); - - - element = acpi_gbl_memory_lists[0].list_head; - if (element == NULL) { - ACPI_DEBUG_PRINT ((ACPI_DB_OK, - "No outstanding allocations.\n")); - return_VOID; - } + ACPI_FUNCTION_TRACE ("Ut_dump_allocations"); /* * Walk the allocation list. */ - acpi_ut_acquire_mutex (ACPI_MTX_MEMORY); - - ACPI_DEBUG_PRINT ((ACPI_DB_OK, - "Outstanding allocations:\n")); + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_MEMORY))) { + return; + } - for (i = 1; ; i++) /* Just a counter */ { + element = acpi_gbl_memory_lists[0].list_head; + while (element) { if ((element->component & component) && - ((module == NULL) || (0 == STRCMP (module, element->module)))) { - if (((acpi_operand_object *)(&element->user_space))->common.type != ACPI_CACHED_OBJECT) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - "%p Len %04X %9.9s-%d", - &element->user_space, element->size, element->module, - element->line)); + ((module == NULL) || (0 == ACPI_STRCMP (module, element->module)))) { + /* Ignore allocated objects that are in a cache */ + + descriptor = ACPI_CAST_PTR (ACPI_DESCRIPTOR, &element->user_space); + if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) { + acpi_os_printf ("%p Len %04X %9.9s-%d ", + descriptor, element->size, element->module, + element->line); /* Most of the elements will be internal objects. */ - switch (((acpi_operand_object *) - (&element->user_space))->common.data_type) { - case ACPI_DESC_TYPE_INTERNAL: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " Obj_type %12.12s R%d", - acpi_ut_get_type_name (((acpi_operand_object *)(&element->user_space))->common.type), - ((acpi_operand_object *)(&element->user_space))->common.reference_count)); + switch (ACPI_GET_DESCRIPTOR_TYPE (descriptor)) { + case ACPI_DESC_TYPE_OPERAND: + acpi_os_printf ("Obj_type %12.12s R%hd", + acpi_ut_get_type_name (descriptor->object.common.type), + descriptor->object.common.reference_count); break; case ACPI_DESC_TYPE_PARSER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " Parse_obj Opcode %04X", - ((acpi_parse_object *)(&element->user_space))->opcode)); + acpi_os_printf ("Parse_obj Aml_opcode %04hX", + descriptor->op.asl.aml_opcode); break; case ACPI_DESC_TYPE_NAMED: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " Node %4.4s", - (char*)&((acpi_namespace_node *)(&element->user_space))->name)); + acpi_os_printf ("Node %4.4s", + descriptor->node.name.ascii); break; case ACPI_DESC_TYPE_STATE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " Untyped State_obj")); + acpi_os_printf ("Untyped State_obj"); break; case ACPI_DESC_TYPE_STATE_UPDATE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " UPDATE State_obj")); + acpi_os_printf ("UPDATE State_obj"); break; case ACPI_DESC_TYPE_STATE_PACKAGE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " PACKAGE State_obj")); + acpi_os_printf ("PACKAGE State_obj"); break; case ACPI_DESC_TYPE_STATE_CONTROL: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " CONTROL State_obj")); + acpi_os_printf ("CONTROL State_obj"); break; case ACPI_DESC_TYPE_STATE_RPSCOPE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " ROOT-PARSE-SCOPE State_obj")); + acpi_os_printf ("ROOT-PARSE-SCOPE State_obj"); break; case ACPI_DESC_TYPE_STATE_PSCOPE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " PARSE-SCOPE State_obj")); + acpi_os_printf ("PARSE-SCOPE State_obj"); break; case ACPI_DESC_TYPE_STATE_WSCOPE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " WALK-SCOPE State_obj")); + acpi_os_printf ("WALK-SCOPE State_obj"); break; case ACPI_DESC_TYPE_STATE_RESULT: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " RESULT State_obj")); + acpi_os_printf ("RESULT State_obj"); break; case ACPI_DESC_TYPE_STATE_NOTIFY: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, - " NOTIFY State_obj")); + acpi_os_printf ("NOTIFY State_obj"); + break; + + case ACPI_DESC_TYPE_STATE_THREAD: + acpi_os_printf ("THREAD State_obj"); + break; + + default: + /* All types should appear above */ break; } - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "\n")); + acpi_os_printf ( "\n"); + num_outstanding++; } } - - if (element->next == NULL) { - break; - } - element = element->next; } - acpi_ut_release_mutex (ACPI_MTX_MEMORY); - - ACPI_DEBUG_PRINT ((ACPI_DB_OK, - "Total number of unfreed allocations = %d(%X)\n", i,i)); - - - return_VOID; - -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ut_allocate - * - * PARAMETERS: Size - Size of the allocation - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: Address of the allocated memory on success, NULL on failure. - * - * DESCRIPTION: The subsystem's equivalent of malloc. - * - ******************************************************************************/ - -void * -acpi_ut_allocate ( - u32 size, - u32 component, - NATIVE_CHAR *module, - u32 line) -{ - acpi_debug_mem_block *address; - acpi_status status; - + (void) acpi_ut_release_mutex (ACPI_MTX_MEMORY); - FUNCTION_TRACE_U32 ("Ut_allocate", size); + /* Print summary */ - - /* Check for an inadvertent size of zero bytes */ - - if (!size) { - _REPORT_ERROR (module, line, component, - ("Ut_allocate: Attempt to allocate zero bytes\n")); - size = 1; - } - - address = acpi_os_allocate (size + sizeof (acpi_debug_mem_block)); - if (!address) { - /* Report allocation error */ - - _REPORT_ERROR (module, line, component, - ("Ut_allocate: Could not allocate size %X\n", size)); - - return_PTR (NULL); - } - - status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, address, size, - MEM_MALLOC, component, module, line); - if (ACPI_FAILURE (status)) { - acpi_os_free (address); - return_PTR (NULL); - } - - acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++; - acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += size; - - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p Size %X\n", address, size)); - - return_PTR ((void *) &address->user_space); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ut_callocate - * - * PARAMETERS: Size - Size of the allocation - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: Address of the allocated memory on success, NULL on failure. - * - * DESCRIPTION: Subsystem equivalent of calloc. - * - ******************************************************************************/ - -void * -acpi_ut_callocate ( - u32 size, - u32 component, - NATIVE_CHAR *module, - u32 line) -{ - acpi_debug_mem_block *address; - acpi_status status; - - - FUNCTION_TRACE_U32 ("Ut_callocate", size); - - - /* Check for an inadvertent size of zero bytes */ - - if (!size) { - _REPORT_ERROR (module, line, component, - ("Ut_callocate: Attempt to allocate zero bytes\n")); - return_PTR (NULL); - } - - - address = acpi_os_callocate (size + sizeof (acpi_debug_mem_block)); - if (!address) { - /* Report allocation error */ - - _REPORT_ERROR (module, line, component, - ("Ut_callocate: Could not allocate size %X\n", size)); - return_PTR (NULL); - } - - status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, address, size, - MEM_CALLOC, component, module, line); - if (ACPI_FAILURE (status)) { - acpi_os_free (address); - return_PTR (NULL); + if (!num_outstanding) { + ACPI_DEBUG_PRINT ((ACPI_DB_OK, + "No outstanding allocations.\n")); } - - acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++; - acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += size; - - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p Size %X\n", address, size)); - return_PTR ((void *) &address->user_space); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_ut_free - * - * PARAMETERS: Address - Address of the memory to deallocate - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: None - * - * DESCRIPTION: Frees the memory at Address - * - ******************************************************************************/ - -void -acpi_ut_free ( - void *address, - u32 component, - NATIVE_CHAR *module, - u32 line) -{ - acpi_debug_mem_block *debug_block; - - - FUNCTION_TRACE_PTR ("Ut_free", address); - - - if (NULL == address) { - _REPORT_ERROR (module, line, component, - ("Acpi_ut_free: Trying to delete a NULL address\n")); - - return_VOID; + else { + ACPI_DEBUG_PRINT ((ACPI_DB_OK, + "%d(%X) Outstanding allocations\n", + num_outstanding, num_outstanding)); } - debug_block = (acpi_debug_mem_block *) - (((char *) address) - sizeof (acpi_debug_mem_header)); - - acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_freed++; - acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size -= debug_block->size; - - acpi_ut_remove_allocation (ACPI_MEM_LIST_GLOBAL, debug_block, - component, module, line); - acpi_os_free (debug_block); - - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed\n", address)); - return_VOID; } + #endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */ diff -Nur linux-2.4.19/drivers/acpi/utilities/utcopy.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utcopy.c --- linux-2.4.19/drivers/acpi/utilities/utcopy.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utcopy.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: utcopy - Internal to external object translation utilities - * $Revision: 83 $ + * $Revision: 98 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,12 @@ #include "acpi.h" -#include "acinterp.h" #include "acnamesp.h" #include "amlcode.h" #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utcopy") + ACPI_MODULE_NAME ("utcopy") /******************************************************************************* @@ -56,27 +55,28 @@ acpi_operand_object *internal_object, acpi_object *external_object, u8 *data_space, - u32 *buffer_space_used) + ACPI_SIZE *buffer_space_used) { - u32 length = 0; + acpi_buffer buffer; acpi_status status = AE_OK; - FUNCTION_TRACE ("Ut_copy_isimple_to_esimple"); + ACPI_FUNCTION_TRACE ("Ut_copy_isimple_to_esimple"); + + *buffer_space_used = 0; /* * Check for NULL object case (could be an uninitialized * package element */ if (!internal_object) { - *buffer_space_used = 0; return_ACPI_STATUS (AE_OK); } /* Always clear the external object */ - MEMSET (external_object, 0, sizeof (acpi_object)); + ACPI_MEMSET (external_object, 0, sizeof (acpi_object)); /* * In general, the external object will be the same type as @@ -87,28 +87,31 @@ /* However, only a limited number of external types are supported */ switch (internal_object->common.type) { - case ACPI_TYPE_STRING: - length = internal_object->string.length + 1; - external_object->string.length = internal_object->string.length; external_object->string.pointer = (NATIVE_CHAR *) data_space; - MEMCPY ((void *) data_space, (void *) internal_object->string.pointer, length); + external_object->string.length = internal_object->string.length; + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ((ACPI_SIZE) internal_object->string.length + 1); + + ACPI_MEMCPY ((void *) data_space, (void *) internal_object->string.pointer, + (ACPI_SIZE) internal_object->string.length + 1); break; case ACPI_TYPE_BUFFER: - length = internal_object->buffer.length; - external_object->buffer.length = internal_object->buffer.length; external_object->buffer.pointer = data_space; - MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer, length); + external_object->buffer.length = internal_object->buffer.length; + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (internal_object->string.length); + + ACPI_MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer, + internal_object->buffer.length); break; case ACPI_TYPE_INTEGER: - external_object->integer.value= internal_object->integer.value; + external_object->integer.value = internal_object->integer.value; break; @@ -143,15 +146,19 @@ * This is a named reference, get the string. We already know that * we have room for it, use max length */ - length = MAX_STRING_LENGTH; external_object->type = ACPI_TYPE_STRING; external_object->string.pointer = (NATIVE_CHAR *) data_space; - status = acpi_ns_handle_to_pathname ((acpi_handle *) internal_object->reference.node, - &length, (char *) data_space); + + buffer.length = MAX_STRING_LENGTH; + buffer.pointer = data_space; + + status = acpi_ns_handle_to_pathname ((acpi_handle) internal_object->reference.node, + &buffer); /* Converted (external) string length is returned from above */ - external_object->string.length = length; + external_object->string.length = (u32) buffer.length; + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (buffer.length); break; default: @@ -189,12 +196,8 @@ * There is no corresponding external object type */ return_ACPI_STATUS (AE_SUPPORT); - break; } - - *buffer_space_used = (u32) ROUND_UP_TO_NATIVE_WORD (length); - return_ACPI_STATUS (status); } @@ -220,12 +223,12 @@ { acpi_status status = AE_OK; acpi_pkg_info *info = (acpi_pkg_info *) context; - u32 object_space; + ACPI_SIZE object_space; u32 this_index; acpi_object *target_object; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); this_index = state->pkg.index; @@ -236,16 +239,16 @@ case ACPI_COPY_TYPE_SIMPLE: /* - * This is a simple or null object -- get the size + * This is a simple or null object */ status = acpi_ut_copy_isimple_to_esimple (source_object, target_object, info->free_space, &object_space); if (ACPI_FAILURE (status)) { return (status); } - break; + case ACPI_COPY_TYPE_PACKAGE: /* @@ -253,7 +256,7 @@ */ target_object->type = ACPI_TYPE_PACKAGE; target_object->package.count = source_object->package.count; - target_object->package.elements = (acpi_object *) info->free_space; + target_object->package.elements = ACPI_CAST_PTR (acpi_object, info->free_space); /* * Pass the new package object back to the package walk routine @@ -264,18 +267,17 @@ * Save space for the array of objects (Package elements) * update the buffer length counter */ - object_space = (u32) ROUND_UP_TO_NATIVE_WORD ( - target_object->package.count * sizeof (acpi_object)); + object_space = ACPI_ROUND_UP_TO_NATIVE_WORD ( + (ACPI_SIZE) target_object->package.count * sizeof (acpi_object)); break; + default: return (AE_BAD_PARAMETER); } - info->free_space += object_space; info->length += object_space; - return (status); } @@ -303,20 +305,20 @@ acpi_ut_copy_ipackage_to_epackage ( acpi_operand_object *internal_object, u8 *buffer, - u32 *space_used) + ACPI_SIZE *space_used) { acpi_object *external_object; acpi_status status; acpi_pkg_info info; - FUNCTION_TRACE ("Ut_copy_ipackage_to_epackage"); + ACPI_FUNCTION_TRACE ("Ut_copy_ipackage_to_epackage"); /* * First package at head of the buffer */ - external_object = (acpi_object *) buffer; + external_object = ACPI_CAST_PTR (acpi_object, buffer); /* * Free space begins right after the first package @@ -324,31 +326,27 @@ info.length = 0; info.object_space = 0; info.num_packages = 1; - info.free_space = buffer + ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object)); - + info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object)); external_object->type = internal_object->common.type; external_object->package.count = internal_object->package.count; - external_object->package.elements = (acpi_object *) info.free_space; - + external_object->package.elements = ACPI_CAST_PTR (acpi_object, info.free_space); /* * Build an array of ACPI_OBJECTS in the buffer * and move the free space past it */ info.free_space += external_object->package.count * - ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object)); - + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object)); status = acpi_ut_walk_package_tree (internal_object, external_object, acpi_ut_copy_ielement_to_eelement, &info); *space_used = info.length; - return_ACPI_STATUS (status); - } + /******************************************************************************* * * FUNCTION: Acpi_ut_copy_iobject_to_eobject @@ -371,10 +369,10 @@ acpi_status status; - FUNCTION_TRACE ("Ut_copy_iobject_to_eobject"); + ACPI_FUNCTION_TRACE ("Ut_copy_iobject_to_eobject"); - if (IS_THIS_OBJECT_TYPE (internal_object, ACPI_TYPE_PACKAGE)) { + if (internal_object->common.type == ACPI_TYPE_PACKAGE) { /* * Package object: Copy all subobjects (including * nested packages) @@ -382,7 +380,6 @@ status = acpi_ut_copy_ipackage_to_epackage (internal_object, ret_buffer->pointer, &ret_buffer->length); } - else { /* * Build a simple object (no nested objects) @@ -390,7 +387,7 @@ status = acpi_ut_copy_isimple_to_esimple (internal_object, (acpi_object *) ret_buffer->pointer, ((u8 *) ret_buffer->pointer + - ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object))), + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object))), &ret_buffer->length); /* * build simple does not include the object size in the length @@ -427,7 +424,7 @@ acpi_operand_object *internal_object; - FUNCTION_TRACE ("Ut_copy_esimple_to_isimple"); + ACPI_FUNCTION_TRACE ("Ut_copy_esimple_to_isimple"); /* @@ -449,7 +446,6 @@ * Whatever other type -- it is not supported */ return_ACPI_STATUS (AE_SUPPORT); - break; } @@ -459,14 +455,14 @@ case ACPI_TYPE_STRING: - internal_object->string.pointer = ACPI_MEM_CALLOCATE (external_object->string.length + 1); + internal_object->string.pointer = ACPI_MEM_CALLOCATE ((ACPI_SIZE) external_object->string.length + 1); if (!internal_object->string.pointer) { return_ACPI_STATUS (AE_NO_MEMORY); } - MEMCPY (internal_object->string.pointer, - external_object->string.pointer, - external_object->string.length); + ACPI_MEMCPY (internal_object->string.pointer, + external_object->string.pointer, + external_object->string.length); internal_object->string.length = external_object->string.length; break; @@ -479,9 +475,9 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - MEMCPY (internal_object->buffer.pointer, - external_object->buffer.pointer, - external_object->buffer.length); + ACPI_MEMCPY (internal_object->buffer.pointer, + external_object->buffer.pointer, + external_object->buffer.length); internal_object->buffer.length = external_object->buffer.length; break; @@ -491,8 +487,11 @@ internal_object->integer.value = external_object->integer.value; break; - } + default: + /* Other types can't get here */ + break; + } *ret_internal_object = internal_object; return_ACPI_STATUS (AE_OK); @@ -537,7 +536,7 @@ acpi_object *this_external_obj; - FUNCTION_TRACE ("Ut_copy_epackage_to_ipackage"); + ACPI_FUNCTION_TRACE ("Ut_copy_epackage_to_ipackage"); /* @@ -591,23 +590,13 @@ acpi_status status; - FUNCTION_TRACE ("Ut_copy_eobject_to_iobject"); + ACPI_FUNCTION_TRACE ("Ut_copy_eobject_to_iobject"); if (external_object->type == ACPI_TYPE_PACKAGE) { /* - * Package objects contain other objects (which can be objects) - * buildpackage does it all - * - * TBD: Package conversion must be completed and tested - * NOTE: this code converts packages as input parameters to - * control methods only. This is a very, very rare case. + * Packages as external input to control methods are not supported, */ -/* - Status = Acpi_ut_copy_epackage_to_ipackage(Internal_object, - Ret_buffer->Pointer, - &Ret_buffer->Length); -*/ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Packages as parameters not implemented!\n")); @@ -627,11 +616,88 @@ /******************************************************************************* * + * FUNCTION: Acpi_ut_copy_simple_object + * + * PARAMETERS: Source_desc - The internal object to be copied + * Dest_desc - New target object + * + * RETURN: Status + * + * DESCRIPTION: Simple copy of one internal object to another. Reference count + * of the destination object is preserved. + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_simple_object ( + acpi_operand_object *source_desc, + acpi_operand_object *dest_desc) +{ + u16 reference_count; + acpi_operand_object *next_object; + + + /* Save fields from destination that we don't want to overwrite */ + + reference_count = dest_desc->common.reference_count; + next_object = dest_desc->common.next_object; + + /* Copy the entire source object over the destination object*/ + + ACPI_MEMCPY ((char *) dest_desc, (char *) source_desc, sizeof (acpi_operand_object)); + + /* Restore the saved fields */ + + dest_desc->common.reference_count = reference_count; + dest_desc->common.next_object = next_object; + + /* Handle the objects with extra data */ + + switch (dest_desc->common.type) { + case ACPI_TYPE_BUFFER: + + dest_desc->buffer.node = NULL; + dest_desc->common.flags = source_desc->common.flags; + + /* Fall through to common string/buffer case */ + /*lint -fallthrough */ + + case ACPI_TYPE_STRING: + + /* + * Allocate and copy the actual string if and only if: + * 1) There is a valid string (length > 0) + * 2) The string is not static (not in an ACPI table) (in this case, + * the actual pointer was already copied above) + */ + if ((source_desc->string.length) && + (!(source_desc->common.flags & AOPOBJ_STATIC_POINTER))) { + dest_desc->string.pointer = ACPI_MEM_ALLOCATE (source_desc->string.length); + if (!dest_desc->string.pointer) { + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY (dest_desc->string.pointer, source_desc->string.pointer, + source_desc->string.length); + } + break; + + default: + /* Nothing to do for other simple objects */ + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: Acpi_ut_copy_ielement_to_ielement * * PARAMETERS: ACPI_PKG_CALLBACK * - * RETURN: Status - the status of the call + * RETURN: Status * * DESCRIPTION: Copy one package element to another package element * @@ -650,7 +716,7 @@ acpi_operand_object *target_object; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); this_index = state->pkg.index; @@ -668,8 +734,7 @@ return (AE_NO_MEMORY); } - status = acpi_ex_store_object_to_object (source_object, target_object, - (acpi_walk_state *) context); + status = acpi_ut_copy_simple_object (source_object, target_object); if (ACPI_FAILURE (status)) { return (status); } @@ -679,18 +744,18 @@ case 1: + /* * This object is a package - go down another nesting level * Create and build the package object */ target_object = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE); if (!target_object) { - /* TBD: must delete package created up to this point */ - return (AE_NO_MEMORY); } target_object->package.count = source_object->package.count; + target_object->common.flags = source_object->common.flags; /* * Pass the new package object back to the package walk routine @@ -703,11 +768,11 @@ *this_target_ptr = target_object; break; + default: return (AE_BAD_PARAMETER); } - return (status); } @@ -735,30 +800,85 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Ut_copy_ipackage_to_ipackage"); + ACPI_FUNCTION_TRACE ("Ut_copy_ipackage_to_ipackage"); dest_obj->common.type = source_obj->common.type; + dest_obj->common.flags = source_obj->common.flags; dest_obj->package.count = source_obj->package.count; /* * Create the object array and walk the source package tree */ - dest_obj->package.elements = ACPI_MEM_CALLOCATE ((source_obj->package.count + 1) * + dest_obj->package.elements = ACPI_MEM_CALLOCATE (((ACPI_SIZE) source_obj->package.count + 1) * sizeof (void *)); - dest_obj->package.next_element = dest_obj->package.elements; - if (!dest_obj->package.elements) { - REPORT_ERROR ( + ACPI_REPORT_ERROR ( ("Aml_build_copy_internal_package_object: Package allocation failure\n")); return_ACPI_STATUS (AE_NO_MEMORY); } - + /* + * Copy the package element-by-element by walking the package "tree". + * This handles nested packages of arbitrary depth. + */ status = acpi_ut_walk_package_tree (source_obj, dest_obj, acpi_ut_copy_ielement_to_ielement, walk_state); + if (ACPI_FAILURE (status)) { + /* On failure, delete the destination package object */ + + acpi_ut_remove_reference (dest_obj); + } return_ACPI_STATUS (status); } + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_copy_iobject_to_iobject + * + * PARAMETERS: Walk_state - Current walk state + * Source_desc - The internal object to be copied + * Dest_desc - Where the copied object is returned + * + * RETURN: Status + * + * DESCRIPTION: Copy an internal object to a new internal object + * + ******************************************************************************/ + +acpi_status +acpi_ut_copy_iobject_to_iobject ( + acpi_operand_object *source_desc, + acpi_operand_object **dest_desc, + acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("Ut_copy_iobject_to_iobject"); + + + /* Create the top level object */ + + *dest_desc = acpi_ut_create_internal_object (source_desc->common.type); + if (!*dest_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the object and possible subobjects */ + + if (source_desc->common.type == ACPI_TYPE_PACKAGE) { + status = acpi_ut_copy_ipackage_to_ipackage (source_desc, *dest_desc, + walk_state); + } + else { + status = acpi_ut_copy_simple_object (source_desc, *dest_desc); + } + + return_ACPI_STATUS (status); +} + diff -Nur linux-2.4.19/drivers/acpi/utilities/utdebug.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utdebug.c --- linux-2.4.19/drivers/acpi/utilities/utdebug.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utdebug.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: utdebug - Debug print routines - * $Revision: 90 $ + * $Revision: 103 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,16 +27,15 @@ #include "acpi.h" #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utdebug") - - -u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF; -char *acpi_gbl_fn_entry_str = "----Entry"; -char *acpi_gbl_fn_exit_str = "----Exit-"; + ACPI_MODULE_NAME ("utdebug") #ifdef ACPI_DEBUG +static u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF; +static char *acpi_gbl_fn_entry_str = "----Entry"; +static char *acpi_gbl_fn_exit_str = "----Exit-"; + /***************************************************************************** * @@ -57,7 +56,7 @@ u32 current_sp; - acpi_gbl_entry_stack_pointer = (u32) ¤t_sp; + acpi_gbl_entry_stack_pointer = ACPI_PTR_DIFF (¤t_sp, NULL); } @@ -77,9 +76,10 @@ acpi_ut_track_stack_ptr ( void) { - u32 current_sp; + ACPI_SIZE current_sp; - current_sp = (u32) ¤t_sp; + + current_sp = ACPI_PTR_DIFF (¤t_sp, NULL); if (current_sp < acpi_gbl_lowest_stack_pointer) { acpi_gbl_lowest_stack_pointer = current_sp; @@ -111,7 +111,7 @@ * ****************************************************************************/ -void +void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print ( u32 requested_debug_level, u32 line_number, @@ -131,7 +131,6 @@ return; } - /* * Thread tracking and context switch notification */ @@ -150,14 +149,13 @@ * Display the module name, current line number, thread ID (if requested), * current procedure nesting level, and the current procedure name */ - acpi_os_printf ("%8s-%04d ", dbg_info->module_name, line_number); + acpi_os_printf ("%8s-%04ld ", dbg_info->module_name, line_number); if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf ("[%04X] ", thread_id, acpi_gbl_nesting_level, dbg_info->proc_name); + acpi_os_printf ("[%04lX] ", thread_id, acpi_gbl_nesting_level, dbg_info->proc_name); } - acpi_os_printf ("[%02d] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name); - + acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name); va_start (args, format); acpi_os_vprintf (format, args); @@ -184,7 +182,7 @@ * ****************************************************************************/ -void +void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print_raw ( u32 requested_debug_level, u32 line_number, @@ -201,7 +199,6 @@ } va_start (args, format); - acpi_os_vprintf (format, args); } @@ -431,7 +428,8 @@ { acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info, - "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str, HIDWORD(value), LODWORD(value)); + "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str, + ACPI_HIDWORD (value), ACPI_LODWORD (value)); acpi_gbl_nesting_level--; } @@ -493,8 +491,8 @@ u32 display, u32 component_id) { - u32 i = 0; - u32 j; + NATIVE_UINT i = 0; + NATIVE_UINT j; u32 temp32; u8 buf_char; @@ -506,6 +504,11 @@ return; } + if ((count < 4) || (count & 0x01)) { + display = DB_BYTE_DISPLAY; + } + + acpi_os_printf ("\n_offset Value\n"); /* * Nasty little dump buffer routine! @@ -515,7 +518,6 @@ acpi_os_printf ("%05X ", i); - /* Print 16 hex chars */ for (j = 0; j < 16;) { @@ -539,8 +541,8 @@ case DB_WORD_DISPLAY: - MOVE_UNALIGNED16_TO_32 (&temp32, - &buffer[i + j]); + ACPI_MOVE_UNALIGNED16_TO_32 (&temp32, + &buffer[i + j]); acpi_os_printf ("%04X ", temp32); j += 2; break; @@ -548,8 +550,8 @@ case DB_DWORD_DISPLAY: - MOVE_UNALIGNED32_TO_32 (&temp32, - &buffer[i + j]); + ACPI_MOVE_UNALIGNED32_TO_32 (&temp32, + &buffer[i + j]); acpi_os_printf ("%08X ", temp32); j += 4; break; @@ -557,24 +559,22 @@ case DB_QWORD_DISPLAY: - MOVE_UNALIGNED32_TO_32 (&temp32, - &buffer[i + j]); + ACPI_MOVE_UNALIGNED32_TO_32 (&temp32, + &buffer[i + j]); acpi_os_printf ("%08X", temp32); - MOVE_UNALIGNED32_TO_32 (&temp32, - &buffer[i + j + 4]); + ACPI_MOVE_UNALIGNED32_TO_32 (&temp32, + &buffer[i + j + 4]); acpi_os_printf ("%08X ", temp32); j += 8; break; } } - /* * Print the ASCII equivalent characters * But watch out for the bad unprintable ones... */ - for (j = 0; j < 16; j++) { if (i + j >= count) { acpi_os_printf ("\n"); diff -Nur linux-2.4.19/drivers/acpi/utilities/utdelete.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utdelete.c --- linux-2.4.19/drivers/acpi/utilities/utdelete.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utdelete.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: utdelete - object deletion and reference count utilities - * $Revision: 81 $ + * $Revision: 90 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,11 +27,9 @@ #include "acpi.h" #include "acinterp.h" #include "acnamesp.h" -#include "actables.h" -#include "acparser.h" #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utdelete") + ACPI_MODULE_NAME ("utdelete") /******************************************************************************* @@ -53,9 +51,10 @@ { void *obj_pointer = NULL; acpi_operand_object *handler_desc; + acpi_operand_object *second_desc; - FUNCTION_TRACE_PTR ("Ut_delete_internal_obj", object); + ACPI_FUNCTION_TRACE_PTR ("Ut_delete_internal_obj", object); if (!object) { @@ -67,10 +66,9 @@ * actual ACPI objects (for example, a raw buffer pointer). */ switch (object->common.type) { - case ACPI_TYPE_STRING: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** String %p, ptr %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** String %p, ptr %p\n", object, object->string.pointer)); /* Free the actual string buffer */ @@ -83,7 +81,7 @@ case ACPI_TYPE_BUFFER: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Buffer %p, ptr %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** Buffer %p, ptr %p\n", object, object->buffer.pointer)); /* Free the actual buffer */ @@ -94,7 +92,7 @@ case ACPI_TYPE_PACKAGE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, " **** Package of count %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, " **** Package of count %X\n", object->package.count)); /* @@ -110,43 +108,43 @@ case ACPI_TYPE_MUTEX: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Mutex %p, Semaphore %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Mutex %p, Semaphore %p\n", object, object->mutex.semaphore)); acpi_ex_unlink_mutex (object); - acpi_os_delete_semaphore (object->mutex.semaphore); + (void) acpi_os_delete_semaphore (object->mutex.semaphore); break; case ACPI_TYPE_EVENT: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Event %p, Semaphore %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Event %p, Semaphore %p\n", object, object->event.semaphore)); - acpi_os_delete_semaphore (object->event.semaphore); + (void) acpi_os_delete_semaphore (object->event.semaphore); object->event.semaphore = NULL; break; case ACPI_TYPE_METHOD: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Method %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object)); /* Delete the method semaphore if it exists */ if (object->method.semaphore) { - acpi_os_delete_semaphore (object->method.semaphore); + (void) acpi_os_delete_semaphore (object->method.semaphore); object->method.semaphore = NULL; } - break; case ACPI_TYPE_REGION: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Region %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); - if (object->region.extra) { + second_desc = acpi_ns_get_secondary_object (object); + if (second_desc) { /* * Free the Region_context if and only if the handler is one of the * default handlers -- and therefore, we created the context object @@ -154,53 +152,47 @@ */ handler_desc = object->region.addr_handler; if ((handler_desc) && - (handler_desc->addr_handler.hflags == ADDR_HANDLER_DEFAULT_INSTALLED)) { - obj_pointer = object->region.extra->extra.region_context; + (handler_desc->addr_handler.hflags == ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + obj_pointer = second_desc->extra.region_context; } /* Now we can free the Extra object */ - acpi_ut_delete_object_desc (object->region.extra); + acpi_ut_delete_object_desc (second_desc); } break; case ACPI_TYPE_BUFFER_FIELD: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Buffer Field %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object)); - if (object->buffer_field.extra) { - acpi_ut_delete_object_desc (object->buffer_field.extra); + second_desc = acpi_ns_get_secondary_object (object); + if (second_desc) { + acpi_ut_delete_object_desc (second_desc); } break; + default: break; } - /* - * Delete any allocated memory found above - */ + /* Free any allocated memory (pointer within the object) found above */ + if (obj_pointer) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting Obj Ptr %p \n", obj_pointer)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n", + obj_pointer)); ACPI_MEM_FREE (obj_pointer); } - /* Only delete the object if it was dynamically allocated */ - - if (object->common.flags & AOPOBJ_STATIC_ALLOCATION) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object %p [%s] static allocation, no delete\n", - object, acpi_ut_get_type_name (object->common.type))); - } + /* Now the object can be safely deleted */ - if (!(object->common.flags & AOPOBJ_STATIC_ALLOCATION)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting object %p [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n", object, acpi_ut_get_type_name (object->common.type))); - acpi_ut_delete_object_desc (object); - } - + acpi_ut_delete_object_desc (object); return_VOID; } @@ -211,21 +203,21 @@ * * PARAMETERS: *Obj_list - Pointer to the list to be deleted * - * RETURN: Status - the status of the call + * RETURN: None * * DESCRIPTION: This function deletes an internal object list, including both * simple objects and package objects * ******************************************************************************/ -acpi_status +void acpi_ut_delete_internal_object_list ( acpi_operand_object **obj_list) { acpi_operand_object **internal_obj; - FUNCTION_TRACE ("Ut_delete_internal_object_list"); + ACPI_FUNCTION_TRACE ("Ut_delete_internal_object_list"); /* Walk the null-terminated internal list */ @@ -237,8 +229,7 @@ /* Free the combined parameter pointer list and object array */ ACPI_MEM_FREE (obj_list); - - return_ACPI_STATUS (AE_OK); + return_VOID; } @@ -264,13 +255,13 @@ u16 new_count; - PROC_NAME ("Ut_update_ref_count"); + ACPI_FUNCTION_NAME ("Ut_update_ref_count"); + if (!object) { return; } - count = object->common.reference_count; new_count = count; @@ -284,7 +275,7 @@ new_count++; object->common.reference_count = new_count; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, [Incremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Incremented]\n", object, new_count)); break; @@ -292,21 +283,20 @@ case REF_DECREMENT: if (count < 1) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, can't decrement! (Set to 0)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, can't decrement! (Set to 0)\n", object, new_count)); new_count = 0; } - else { new_count--; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, [Decremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Decremented]\n", object, new_count)); } if (object->common.type == ACPI_TYPE_METHOD) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Method Obj %p Refs=%X, [Decremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Method Obj %p Refs=%X, [Decremented]\n", object, new_count)); } @@ -320,7 +310,7 @@ case REF_FORCE_DELETE: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, Force delete! (Set to 0)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, Force delete! (Set to 0)\n", object, count)); new_count = 0; @@ -335,7 +325,6 @@ break; } - /* * Sanity check the reference count, for debug purposes only. * (A deleted object will have a huge reference count) @@ -386,7 +375,7 @@ acpi_generic_state *state; - FUNCTION_TRACE_PTR ("Ut_update_object_reference", object); + ACPI_FUNCTION_TRACE_PTR ("Ut_update_object_reference", object); /* Ignore a null object ptr */ @@ -395,16 +384,14 @@ return_ACPI_STATUS (AE_OK); } - /* - * Make sure that this isn't a namespace handle or an AML pointer + * Make sure that this isn't a namespace handle */ - if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object %p is NS handle\n", object)); + if (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p is NS handle\n", object)); return_ACPI_STATUS (AE_OK); } - state = acpi_ut_create_update_state (object, action); while (state) { @@ -417,13 +404,12 @@ * Different object types have different subobjects. */ switch (object->common.type) { - case ACPI_TYPE_DEVICE: status = acpi_ut_create_update_state_and_push (object->device.addr_handler, action, &state_list); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } acpi_ut_update_ref_count (object->device.sys_handler, action); @@ -460,7 +446,7 @@ status = acpi_ut_create_update_state_and_push ( object->package.elements[i], action, &state_list); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } } break; @@ -470,9 +456,8 @@ status = acpi_ut_create_update_state_and_push ( object->buffer_field.buffer_obj, action, &state_list); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } break; @@ -482,7 +467,7 @@ status = acpi_ut_create_update_state_and_push ( object->field.region_obj, action, &state_list); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } break; @@ -490,15 +475,15 @@ case INTERNAL_TYPE_BANK_FIELD: status = acpi_ut_create_update_state_and_push ( - object->bank_field.bank_register_obj, action, &state_list); + object->bank_field.bank_obj, action, &state_list); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } status = acpi_ut_create_update_state_and_push ( object->bank_field.region_obj, action, &state_list); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } break; @@ -508,25 +493,25 @@ status = acpi_ut_create_update_state_and_push ( object->index_field.index_obj, action, &state_list); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } status = acpi_ut_create_update_state_and_push ( object->index_field.data_obj, action, &state_list); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto error_exit; } break; case ACPI_TYPE_REGION: case INTERNAL_TYPE_REFERENCE: + default: /* No subobjects */ break; } - /* * Now we can update the count in the main object. This can only * happen after we update the sub-objects in case this causes the @@ -534,14 +519,20 @@ */ acpi_ut_update_ref_count (object, action); - /* Move on to the next object to be updated */ state = acpi_ut_pop_generic_state (&state_list); } - return_ACPI_STATUS (AE_OK); + + +error_exit: + + ACPI_REPORT_ERROR (("Could not update object reference count, %s\n", + acpi_format_exception (status))); + + return_ACPI_STATUS (status); } @@ -563,7 +554,7 @@ acpi_operand_object *object) { - FUNCTION_TRACE_PTR ("Ut_add_reference", object); + ACPI_FUNCTION_TRACE_PTR ("Ut_add_reference", object); /* @@ -576,8 +567,7 @@ /* * We have a valid ACPI internal object, now increment the reference count */ - acpi_ut_update_object_reference (object, REF_INCREMENT); - + (void) acpi_ut_update_object_reference (object, REF_INCREMENT); return_VOID; } @@ -599,7 +589,7 @@ acpi_operand_object *object) { - FUNCTION_TRACE_PTR ("Ut_remove_reference", object); + ACPI_FUNCTION_TRACE_PTR ("Ut_remove_reference", object); /* * Allow a NULL pointer to be passed in, just ignore it. This saves @@ -607,7 +597,7 @@ * */ if (!object || - (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED))) { + (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED)) { return_VOID; } @@ -618,7 +608,7 @@ return_VOID; } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X\n", object, object->common.reference_count)); /* @@ -626,7 +616,7 @@ * if the reference count becomes 0. (Must also decrement the ref count * of all subobjects!) */ - acpi_ut_update_object_reference (object, REF_DECREMENT); + (void) acpi_ut_update_object_reference (object, REF_DECREMENT); return_VOID; } diff -Nur linux-2.4.19/drivers/acpi/utilities/uteval.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/uteval.c --- linux-2.4.19/drivers/acpi/utilities/uteval.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/uteval.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: uteval - Object evaluation - * $Revision: 31 $ + * $Revision: 39 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("uteval") + ACPI_MODULE_NAME ("uteval") /******************************************************************************* @@ -60,7 +60,7 @@ acpi_status status; - FUNCTION_TRACE ("Ut_evaluate_numeric_object"); + ACPI_FUNCTION_TRACE ("Ut_evaluate_numeric_object"); /* Execute the method */ @@ -68,12 +68,12 @@ status = acpi_ns_evaluate_relative (device_node, object_name, NULL, &obj_desc); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s on %4.4s was not found\n", - object_name, (char*)&device_node->name)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s on %4.4s was not found\n", + object_name, device_node->name.ascii)); } else { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s on %4.4s failed with status %s\n", - object_name, (char*)&device_node->name, + object_name, device_node->name.ascii, acpi_format_exception (status))); } @@ -138,7 +138,7 @@ acpi_status status; - FUNCTION_TRACE ("Ut_execute_HID"); + ACPI_FUNCTION_TRACE ("Ut_execute_HID"); /* Execute the method */ @@ -147,13 +147,12 @@ METHOD_NAME__HID, NULL, &obj_desc); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "_HID on %4.4s was not found\n", - (char*)&device_node->name)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_HID on %4.4s was not found\n", + device_node->name.ascii)); } - else { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_HID on %4.4s failed %s\n", - (char*)&device_node->name, acpi_format_exception (status))); + device_node->name.ascii, acpi_format_exception (status))); } return_ACPI_STATUS (status); @@ -177,21 +176,111 @@ "Type returned from _HID not a number or string: %s(%X) \n", acpi_ut_get_type_name (obj_desc->common.type), obj_desc->common.type)); } - else { if (obj_desc->common.type == ACPI_TYPE_INTEGER) { /* Convert the Numeric HID to string */ acpi_ex_eisa_id_to_string ((u32) obj_desc->integer.value, hid->buffer); } - else { /* Copy the String HID from the returned object */ - STRNCPY(hid->buffer, obj_desc->string.pointer, sizeof(hid->buffer)); + ACPI_STRNCPY (hid->buffer, obj_desc->string.pointer, sizeof(hid->buffer)); + } + } + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference (obj_desc); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_execute_CID + * + * PARAMETERS: Device_node - Node for the device + * *Cid - Where the CID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _CID control method that returns one or more + * compatible hardware IDs for the device. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_CID ( + acpi_namespace_node *device_node, + acpi_device_id *cid) +{ + acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("Ut_execute_CID"); + + /* Execute the method */ + + status = acpi_ns_evaluate_relative (device_node, + METHOD_NAME__CID, NULL, &obj_desc); + if (ACPI_FAILURE (status)) { + if (status == AE_NOT_FOUND) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_CID on %4.4s was not found\n", + device_node->name.ascii)); } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_CID on %4.4s failed %s\n", + device_node->name.ascii, acpi_format_exception (status))); + } + + return_ACPI_STATUS (status); } + /* Did we get a return object? */ + + if (!obj_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No object was returned from _CID\n")); + return_ACPI_STATUS (AE_TYPE); + } + + /* + * A _CID can return either a single compatible ID or a package of compatible + * IDs. Each compatible ID can be a Number (32 bit compressed EISA ID) or + * string (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss"). + */ + switch (obj_desc->common.type) { + case ACPI_TYPE_INTEGER: + + /* Convert the Numeric CID to string */ + + acpi_ex_eisa_id_to_string ((u32) obj_desc->integer.value, cid->buffer); + break; + + case ACPI_TYPE_STRING: + + /* Copy the String CID from the returned object */ + + ACPI_STRNCPY (cid->buffer, obj_desc->string.pointer, sizeof(cid->buffer)); + break; + + case ACPI_TYPE_PACKAGE: + + /* TBD: Parse package elements; need different return struct, etc. */ + break; + + default: + + status = AE_TYPE; + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Type returned from _CID not a number, string, or package: %s(%X) \n", + acpi_ut_get_type_name (obj_desc->common.type), obj_desc->common.type)); + break; + } /* On exit, we must delete the return object */ @@ -226,7 +315,7 @@ acpi_status status; - PROC_NAME ("Ut_execute_UID"); + ACPI_FUNCTION_NAME ("Ut_execute_UID"); /* Execute the method */ @@ -235,14 +324,13 @@ METHOD_NAME__UID, NULL, &obj_desc); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "_UID on %4.4s was not found\n", - (char*)&device_node->name)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_UID on %4.4s was not found\n", + device_node->name.ascii)); } - else { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_UID on %4.4s failed %s\n", - (char*)&device_node->name, acpi_format_exception (status))); + device_node->name.ascii, acpi_format_exception (status))); } return (status); @@ -266,18 +354,16 @@ "Type returned from _UID was not a number or string: %X \n", obj_desc->common.type)); } - else { if (obj_desc->common.type == ACPI_TYPE_INTEGER) { /* Convert the Numeric UID to string */ acpi_ex_unsigned_integer_to_string (obj_desc->integer.value, uid->buffer); } - else { /* Copy the String UID from the returned object */ - STRNCPY(uid->buffer, obj_desc->string.pointer, sizeof(uid->buffer)); + ACPI_STRNCPY (uid->buffer, obj_desc->string.pointer, sizeof(uid->buffer)); } } @@ -315,7 +401,7 @@ acpi_status status; - FUNCTION_TRACE ("Ut_execute_STA"); + ACPI_FUNCTION_TRACE ("Ut_execute_STA"); /* Execute the method */ @@ -323,9 +409,9 @@ status = acpi_ns_evaluate_relative (device_node, METHOD_NAME__STA, NULL, &obj_desc); if (AE_NOT_FOUND == status) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_STA on %4.4s was not found, assuming present.\n", - (char*)&device_node->name)); + device_node->name.ascii)); *flags = 0x0F; status = AE_OK; @@ -333,7 +419,7 @@ else if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "_STA on %4.4s failed %s\n", - (char*)&device_node->name, + device_node->name.ascii, acpi_format_exception (status))); } @@ -353,7 +439,6 @@ "Type returned from _STA was not a number: %X \n", obj_desc->common.type)); } - else { /* Extract the status flags */ diff -Nur linux-2.4.19/drivers/acpi/utilities/utglobal.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utglobal.c --- linux-2.4.19/drivers/acpi/utilities/utglobal.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utglobal.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: utglobal - Global variables for the ACPI subsystem - * $Revision: 133 $ + * $Revision: 161 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,14 +26,10 @@ #define DEFINE_ACPI_GLOBALS #include "acpi.h" -#include "acevents.h" #include "acnamesp.h" -#include "acinterp.h" -#include "amlcode.h" - #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utglobal") + ACPI_MODULE_NAME ("utglobal") /****************************************************************************** @@ -56,51 +52,63 @@ acpi_status sub_status; - sub_status = (status & ~AE_CODE_MASK); + ACPI_FUNCTION_NAME ("Format_exception"); + sub_status = (status & ~AE_CODE_MASK); + switch (status & AE_CODE_MASK) { case AE_CODE_ENVIRONMENTAL: if (sub_status <= AE_CODE_ENV_MAX) { exception = acpi_gbl_exception_names_env [sub_status]; + break; } - break; + goto unknown; case AE_CODE_PROGRAMMER: if (sub_status <= AE_CODE_PGM_MAX) { exception = acpi_gbl_exception_names_pgm [sub_status -1]; + break; } - break; + goto unknown; case AE_CODE_ACPI_TABLES: if (sub_status <= AE_CODE_TBL_MAX) { exception = acpi_gbl_exception_names_tbl [sub_status -1]; + break; } - break; + goto unknown; case AE_CODE_AML: if (sub_status <= AE_CODE_AML_MAX) { exception = acpi_gbl_exception_names_aml [sub_status -1]; + break; } - break; + goto unknown; case AE_CODE_CONTROL: if (sub_status <= AE_CODE_CTRL_MAX) { exception = acpi_gbl_exception_names_ctrl [sub_status -1]; + break; } - break; + goto unknown; default: - break; + goto unknown; } return ((const char *) exception); + +unknown: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown exception code: 0x%8.8X\n", status)); + return ((const char *) exception); } @@ -136,10 +144,9 @@ /* System flags */ -u32 acpi_gbl_system_flags = 0; u32 acpi_gbl_startup_flags = 0; -/* System starts unitialized! */ +/* System starts uninitialized */ u8 acpi_gbl_shutdown = TRUE; @@ -168,16 +175,16 @@ * during the initialization sequence. */ -const predefined_names acpi_gbl_pre_defined_names[] = -{ {"_GPE", INTERNAL_TYPE_DEF_ANY}, - {"_PR_", INTERNAL_TYPE_DEF_ANY}, - {"_SB_", ACPI_TYPE_DEVICE}, - {"_SI_", INTERNAL_TYPE_DEF_ANY}, - {"_TZ_", INTERNAL_TYPE_DEF_ANY}, - {"_REV", ACPI_TYPE_INTEGER, "2"}, - {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, - {"_GL_", ACPI_TYPE_MUTEX, "0"}, - {NULL, ACPI_TYPE_ANY} /* Table terminator */ +const acpi_predefined_names acpi_gbl_pre_defined_names[] = +{ {"_GPE", INTERNAL_TYPE_DEF_ANY, NULL}, + {"_PR_", INTERNAL_TYPE_DEF_ANY, NULL}, + {"_SB_", ACPI_TYPE_DEVICE, NULL}, + {"_SI_", INTERNAL_TYPE_DEF_ANY, NULL}, + {"_TZ_", INTERNAL_TYPE_DEF_ANY, NULL}, + {"_REV", ACPI_TYPE_INTEGER, "2"}, + {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, + {"_GL_", ACPI_TYPE_MUTEX, "0"}, + {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */ }; @@ -188,52 +195,53 @@ * and the table is indexed by values of acpi_object_type */ -const u8 acpi_gbl_ns_properties[] = +const u8 acpi_gbl_ns_properties[] = { - NSP_NORMAL, /* 00 Any */ - NSP_NORMAL, /* 01 Number */ - NSP_NORMAL, /* 02 String */ - NSP_NORMAL, /* 03 Buffer */ - NSP_LOCAL, /* 04 Package */ - NSP_NORMAL, /* 05 Field_unit */ - NSP_NEWSCOPE | NSP_LOCAL, /* 06 Device */ - NSP_LOCAL, /* 07 Acpi_event */ - NSP_NEWSCOPE | NSP_LOCAL, /* 08 Method */ - NSP_LOCAL, /* 09 Mutex */ - NSP_LOCAL, /* 10 Region */ - NSP_NEWSCOPE | NSP_LOCAL, /* 11 Power */ - NSP_NEWSCOPE | NSP_LOCAL, /* 12 Processor */ - NSP_NEWSCOPE | NSP_LOCAL, /* 13 Thermal */ - NSP_NORMAL, /* 14 Buffer_field */ - NSP_NORMAL, /* 15 Ddb_handle */ - NSP_NORMAL, /* 16 Debug Object */ - NSP_NORMAL, /* 17 Def_field */ - NSP_NORMAL, /* 18 Bank_field */ - NSP_NORMAL, /* 19 Index_field */ - NSP_NORMAL, /* 20 Reference */ - NSP_NORMAL, /* 21 Alias */ - NSP_NORMAL, /* 22 Notify */ - NSP_NORMAL, /* 23 Address Handler */ - NSP_NEWSCOPE | NSP_LOCAL, /* 24 Resource Desc */ - NSP_NEWSCOPE | NSP_LOCAL, /* 25 Resource Field */ - NSP_NORMAL, /* 26 Def_field_defn */ - NSP_NORMAL, /* 27 Bank_field_defn */ - NSP_NORMAL, /* 28 Index_field_defn */ - NSP_NORMAL, /* 29 If */ - NSP_NORMAL, /* 30 Else */ - NSP_NORMAL, /* 31 While */ - NSP_NEWSCOPE, /* 32 Scope */ - NSP_LOCAL, /* 33 Def_any */ - NSP_NORMAL, /* 34 Extra */ - NSP_NORMAL /* 35 Invalid */ + ACPI_NS_NORMAL, /* 00 Any */ + ACPI_NS_NORMAL, /* 01 Number */ + ACPI_NS_NORMAL, /* 02 String */ + ACPI_NS_NORMAL, /* 03 Buffer */ + ACPI_NS_NORMAL, /* 04 Package */ + ACPI_NS_NORMAL, /* 05 Field_unit */ + ACPI_NS_NEWSCOPE, /* 06 Device */ + ACPI_NS_NORMAL, /* 07 Event */ + ACPI_NS_NEWSCOPE, /* 08 Method */ + ACPI_NS_NORMAL, /* 09 Mutex */ + ACPI_NS_NORMAL, /* 10 Region */ + ACPI_NS_NEWSCOPE, /* 11 Power */ + ACPI_NS_NEWSCOPE, /* 12 Processor */ + ACPI_NS_NEWSCOPE, /* 13 Thermal */ + ACPI_NS_NORMAL, /* 14 Buffer_field */ + ACPI_NS_NORMAL, /* 15 Ddb_handle */ + ACPI_NS_NORMAL, /* 16 Debug Object */ + ACPI_NS_NORMAL, /* 17 Def_field */ + ACPI_NS_NORMAL, /* 18 Bank_field */ + ACPI_NS_NORMAL, /* 19 Index_field */ + ACPI_NS_NORMAL, /* 20 Reference */ + ACPI_NS_NORMAL, /* 21 Alias */ + ACPI_NS_NORMAL, /* 22 Notify */ + ACPI_NS_NORMAL, /* 23 Address Handler */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 24 Resource Desc */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Field */ + ACPI_NS_NORMAL, /* 26 Def_field_defn */ + ACPI_NS_NORMAL, /* 27 Bank_field_defn */ + ACPI_NS_NORMAL, /* 28 Index_field_defn */ + ACPI_NS_NORMAL, /* 29 If */ + ACPI_NS_NORMAL, /* 30 Else */ + ACPI_NS_NORMAL, /* 31 While */ + ACPI_NS_NEWSCOPE, /* 32 Scope */ + ACPI_NS_LOCAL, /* 33 Def_any */ + ACPI_NS_NORMAL, /* 34 Extra */ + ACPI_NS_NORMAL, /* 35 Data */ + ACPI_NS_NORMAL /* 36 Invalid */ }; /* Hex to ASCII conversion table */ -const NATIVE_CHAR acpi_gbl_hex_to_ascii[] = +static const NATIVE_CHAR acpi_gbl_hex_to_ascii[] = {'0','1','2','3','4','5','6','7', - '8','9','A','B','C','D','E','F'}; + '8','9','A','B','C','D','E','F'}; /***************************************************************************** * @@ -249,7 +257,7 @@ * ****************************************************************************/ -u8 +char acpi_ut_hex_to_ascii_char ( acpi_integer integer, u32 position) @@ -261,12 +269,15 @@ /****************************************************************************** * - * Table globals + * Table name globals * * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes. * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables * that are not used by the subsystem are simply ignored. * + * Do NOT add any table to this list that is not consumed directly by this + * subsystem. + * ******************************************************************************/ @@ -275,19 +286,148 @@ ACPI_TABLE_SUPPORT acpi_gbl_acpi_table_data[NUM_ACPI_TABLES] = { - /*********** Name, Signature, Signature size, How many allowed?, Supported? Global typed pointer */ + /*********** Name, Signature, Global typed pointer Signature size, How many allowed?, Contains valid AML? */ - /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, sizeof (RSDP_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL}, - /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, sizeof (DSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_DSDT}, - /* FADT 2 */ {FADT_SIG, FADT_SIG, sizeof (FADT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FADT}, - /* FACS 3 */ {FACS_SIG, FACS_SIG, sizeof (FACS_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FACS}, - /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, sizeof (PSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL}, - /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, sizeof (SSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL}, - /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, sizeof (RSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL}, + /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof (RSDP_SIG)-1, ACPI_TABLE_SINGLE}, + /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void **) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SINGLE | ACPI_TABLE_EXECUTABLE}, + /* FADT 2 */ {FADT_SIG, FADT_SIG, (void **) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_SINGLE}, + /* FACS 3 */ {FACS_SIG, FACS_SIG, (void **) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SINGLE}, + /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof (PSDT_SIG)-1, ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE}, + /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof (SSDT_SIG)-1, ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE}, + /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof (RSDT_SIG)-1, ACPI_TABLE_SINGLE}, }; -#ifdef ACPI_DEBUG +/****************************************************************************** + * + * Event and Hardware globals + * + ******************************************************************************/ + +ACPI_BIT_REGISTER_INFO acpi_gbl_bit_register_info[ACPI_NUM_BITREG] = +{ + /* Name Parent Register Register Bit Position Register Bit Mask */ + + /* ACPI_BITREG_TIMER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_TIMER_STATUS, ACPI_BITMASK_TIMER_STATUS}, + /* ACPI_BITREG_BUS_MASTER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_BUS_MASTER_STATUS, ACPI_BITMASK_BUS_MASTER_STATUS}, + /* ACPI_BITREG_GLOBAL_LOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_STATUS}, + /* ACPI_BITREG_POWER_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_STATUS}, + /* ACPI_BITREG_SLEEP_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_STATUS}, + /* ACPI_BITREG_RT_CLOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_STATUS}, + /* ACPI_BITREG_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_WAKE_STATUS, ACPI_BITMASK_WAKE_STATUS}, + + /* ACPI_BITREG_TIMER_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_TIMER_ENABLE, ACPI_BITMASK_TIMER_ENABLE}, + /* ACPI_BITREG_GLOBAL_LOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, + /* ACPI_BITREG_POWER_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_ENABLE}, + /* ACPI_BITREG_SLEEP_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, + /* ACPI_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_ENABLE}, + /* ACPI_BITREG_WAKE_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, 0, 0}, + + /* ACPI_BITREG_SCI_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SCI_ENABLE, ACPI_BITMASK_SCI_ENABLE}, + /* ACPI_BITREG_BUS_MASTER_RLD */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_BUS_MASTER_RLD, ACPI_BITMASK_BUS_MASTER_RLD}, + /* ACPI_BITREG_GLOBAL_LOCK_RELEASE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE, ACPI_BITMASK_GLOBAL_LOCK_RELEASE}, + /* ACPI_BITREG_SLEEP_TYPE_A */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_TYPE_X, ACPI_BITMASK_SLEEP_TYPE_X}, + /* ACPI_BITREG_SLEEP_TYPE_B */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_TYPE_X, ACPI_BITMASK_SLEEP_TYPE_X}, + /* ACPI_BITREG_SLEEP_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_ENABLE, ACPI_BITMASK_SLEEP_ENABLE}, + + /* ACPI_BITREG_ARB_DIS */ {ACPI_REGISTER_PM2_CONTROL, ACPI_BITPOSITION_ARB_DISABLE, ACPI_BITMASK_ARB_DISABLE} +}; + + +acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] = +{ + /* ACPI_EVENT_PMTIMER */ {ACPI_BITREG_TIMER_STATUS, ACPI_BITREG_TIMER_ENABLE, ACPI_BITMASK_TIMER_STATUS, ACPI_BITMASK_TIMER_ENABLE}, + /* ACPI_EVENT_GLOBAL */ {ACPI_BITREG_GLOBAL_LOCK_STATUS, ACPI_BITREG_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_ENABLE}, + /* ACPI_EVENT_POWER_BUTTON */ {ACPI_BITREG_POWER_BUTTON_STATUS, ACPI_BITREG_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_ENABLE}, + /* ACPI_EVENT_SLEEP_BUTTON */ {ACPI_BITREG_SLEEP_BUTTON_STATUS, ACPI_BITREG_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_ENABLE}, + /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, 0, 0}, +}; + +/***************************************************************************** + * + * FUNCTION: Acpi_ut_get_region_name + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Translate a Space ID into a name string (Debug only) + * + ****************************************************************************/ + +/* Region type decoding */ + +static const NATIVE_CHAR *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = +{ + "System_memory", + "System_iO", + "PCIConfig", + "Embedded_control", + "SMBus", + "CMOS", + "PCIBar_target", + "Data_table", +}; + + +NATIVE_CHAR * +acpi_ut_get_region_name ( + u8 space_id) +{ + + if (space_id >= ACPI_USER_REGION_BEGIN) + { + return ("User_defined_region"); + } + + else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) + { + return ("Invalid_space_iD"); + } + + return ((NATIVE_CHAR *) acpi_gbl_region_types[space_id]); +} + + +/***************************************************************************** + * + * FUNCTION: Acpi_ut_get_event_name + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Translate a Event ID into a name string (Debug only) + * + ****************************************************************************/ + +/* Event type decoding */ + +static const NATIVE_CHAR *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = +{ + "PM_Timer", + "Global_lock", + "Power_button", + "Sleep_button", + "Real_time_clock", +}; + + +NATIVE_CHAR * +acpi_ut_get_event_name ( + u32 event_id) +{ + + if (event_id > ACPI_EVENT_MAX) + { + return ("Invalid_event_iD"); + } + + return ((NATIVE_CHAR *) acpi_gbl_event_types[event_id]); +} + + +#if defined(ACPI_DEBUG) || defined(ENABLE_DEBUGGER) /* * Strings and procedures used for debug only @@ -321,6 +461,18 @@ } +/***************************************************************************** + * + * FUNCTION: Acpi_ut_get_type_name + * + * PARAMETERS: None. + * + * RETURN: Status + * + * DESCRIPTION: Translate a Type ID into a name string (Debug only) + * + ****************************************************************************/ + /* * Elements of Acpi_gbl_Ns_type_names below must match * one-to-one with values of acpi_object_type @@ -370,25 +522,14 @@ /* 32 */ "Scope", /* 33 */ "Def_any", /* 34 */ "Extra", - /* 35 */ "Invalid" + /* 35 */ "Data", + /* 36 */ "Invalid" }; -/***************************************************************************** - * - * FUNCTION: Acpi_ut_get_type_name - * - * PARAMETERS: None. - * - * RETURN: Status - * - * DESCRIPTION: Translate a Type ID into a name string (Debug only) - * - ****************************************************************************/ - NATIVE_CHAR * acpi_ut_get_type_name ( - u32 type) + acpi_object_type type) { if (type > INTERNAL_TYPE_INVALID) @@ -400,61 +541,21 @@ } -/* Region type decoding */ - -const NATIVE_CHAR *acpi_gbl_region_types[NUM_REGION_TYPES] = -{ - "System_memory", - "System_iO", - "PCIConfig", - "Embedded_control", - "SMBus", - "CMOS", - "PCIBar_target", -}; - - -/***************************************************************************** - * - * FUNCTION: Acpi_ut_get_region_name - * - * PARAMETERS: None. - * - * RETURN: Status - * - * DESCRIPTION: Translate a Space ID into a name string (Debug only) - * - ****************************************************************************/ - -NATIVE_CHAR * -acpi_ut_get_region_name ( - u8 space_id) -{ - - if (space_id >= USER_REGION_BEGIN) - { - return ("User_defined_region"); - } - - else if (space_id >= NUM_REGION_TYPES) - { - return ("Invalid_space_iD"); - } - - return ((NATIVE_CHAR *) acpi_gbl_region_types[space_id]); -} +/* Various strings for future use */ +#if 0 +#include "amlcode.h" /* Data used in keeping track of fields */ -const NATIVE_CHAR *acpi_gbl_FEnames[NUM_FIELD_NAMES] = +static const NATIVE_CHAR *acpi_gbl_FEnames[NUM_FIELD_NAMES] = { "skip", "?access?" }; /* FE = Field Element */ -const NATIVE_CHAR *acpi_gbl_match_ops[NUM_MATCH_OPS] = +static const NATIVE_CHAR *acpi_gbl_match_ops[NUM_MATCH_OPS] = { "Error", "MTR", @@ -468,26 +569,26 @@ /* Access type decoding */ -const NATIVE_CHAR *acpi_gbl_access_types[NUM_ACCESS_TYPES] = +static const NATIVE_CHAR *acpi_gbl_access_types[NUM_ACCESS_TYPES] = { "Any_acc", "Byte_acc", "Word_acc", "DWord_acc", - "Block_acc", - "SMBSend_recv_acc", - "SMBQuick_acc" + "QWord_acc", + "Buffer_acc", }; /* Update rule decoding */ -const NATIVE_CHAR *acpi_gbl_update_rules[NUM_UPDATE_RULES] = +static const NATIVE_CHAR *acpi_gbl_update_rules[NUM_UPDATE_RULES] = { "Preserve", "Write_as_ones", "Write_as_zeros" }; +#endif /* Future use */ #endif @@ -506,7 +607,7 @@ u8 acpi_ut_valid_object_type ( - u32 type) + acpi_object_type type) { if (type > ACPI_TYPE_MAX) @@ -539,40 +640,44 @@ acpi_owner_id owner_id = 0xFFFF; - FUNCTION_TRACE ("Ut_allocate_owner_id"); + ACPI_FUNCTION_TRACE ("Ut_allocate_owner_id"); - acpi_ut_acquire_mutex (ACPI_MTX_CACHES); + if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) + { + return (0); + } switch (id_type) { - case OWNER_TYPE_TABLE: + case ACPI_OWNER_TYPE_TABLE: owner_id = acpi_gbl_next_table_owner_id; acpi_gbl_next_table_owner_id++; - if (acpi_gbl_next_table_owner_id == FIRST_METHOD_ID) + if (acpi_gbl_next_table_owner_id == ACPI_FIRST_METHOD_ID) { - acpi_gbl_next_table_owner_id = FIRST_TABLE_ID; + acpi_gbl_next_table_owner_id = ACPI_FIRST_TABLE_ID; } break; - case OWNER_TYPE_METHOD: + case ACPI_OWNER_TYPE_METHOD: owner_id = acpi_gbl_next_method_owner_id; acpi_gbl_next_method_owner_id++; - if (acpi_gbl_next_method_owner_id == FIRST_TABLE_ID) + if (acpi_gbl_next_method_owner_id == ACPI_FIRST_TABLE_ID) { - acpi_gbl_next_method_owner_id = FIRST_METHOD_ID; + acpi_gbl_next_method_owner_id = ACPI_FIRST_METHOD_ID; } break; - } - - acpi_ut_release_mutex (ACPI_MTX_CACHES); + default: + break; + } + (void) acpi_ut_release_mutex (ACPI_MTX_CACHES); return_VALUE (owner_id); } @@ -595,22 +700,22 @@ u32 i; - FUNCTION_TRACE ("Ut_init_globals"); + ACPI_FUNCTION_TRACE ("Ut_init_globals"); /* Memory allocation and cache lists */ - MEMSET (acpi_gbl_memory_lists, 0, sizeof (ACPI_MEMORY_LIST) * ACPI_NUM_MEM_LISTS); + ACPI_MEMSET (acpi_gbl_memory_lists, 0, sizeof (ACPI_MEMORY_LIST) * ACPI_NUM_MEM_LISTS); - acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].link_offset = (u16) (NATIVE_UINT) &(((acpi_generic_state *) NULL)->common.next); - acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].link_offset = (u16) (NATIVE_UINT) &(((acpi_parse_object *) NULL)->next); - acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].link_offset = (u16) (NATIVE_UINT) &(((acpi_parse2_object *) NULL)->next); - acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].link_offset = (u16) (NATIVE_UINT) &(((acpi_operand_object *) NULL)->cache.next); - acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].link_offset = (u16) (NATIVE_UINT) &(((acpi_walk_state *) NULL)->next); + acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].link_offset = (u16) ACPI_PTR_DIFF (&(((acpi_generic_state *) NULL)->common.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].link_offset = (u16) ACPI_PTR_DIFF (&(((acpi_parse_object *) NULL)->common.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].link_offset = (u16) ACPI_PTR_DIFF (&(((acpi_parse_object *) NULL)->common.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].link_offset = (u16) ACPI_PTR_DIFF (&(((acpi_operand_object *) NULL)->cache.next), NULL); + acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].link_offset = (u16) ACPI_PTR_DIFF (&(((acpi_walk_state *) NULL)->next), NULL); acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].object_size = sizeof (acpi_namespace_node); acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].object_size = sizeof (acpi_generic_state); - acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].object_size = sizeof (acpi_parse_object); - acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].object_size = sizeof (acpi_parse2_object); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].object_size = sizeof (ACPI_PARSE_OBJ_COMMON); + acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].object_size = sizeof (ACPI_PARSE_OBJ_NAMED); acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].object_size = sizeof (acpi_operand_object); acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].object_size = sizeof (acpi_walk_state); @@ -640,15 +745,6 @@ acpi_gbl_acpi_tables[i].count = 0; } - - /* Address Space handler array */ - - for (i = 0; i < ACPI_NUM_ADDRESS_SPACES; i++) - { - acpi_gbl_address_spaces[i].handler = NULL; - acpi_gbl_address_spaces[i].context = NULL; - } - /* Mutex locked flags */ for (i = 0; i < NUM_MTX; i++) @@ -662,6 +758,7 @@ acpi_gbl_sys_notify.handler = NULL; acpi_gbl_drv_notify.handler = NULL; + acpi_gbl_init_handler = NULL; /* Global "typed" ACPI table pointers */ @@ -675,11 +772,11 @@ acpi_gbl_global_lock_acquired = FALSE; acpi_gbl_global_lock_thread_count = 0; + acpi_gbl_global_lock_handle = 0; /* Miscellaneous variables */ - acpi_gbl_system_flags = 0; - acpi_gbl_startup_flags = 0; + acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER; acpi_gbl_rsdp_original_location = 0; acpi_gbl_cm_single_step = FALSE; acpi_gbl_db_terminate_threads = FALSE; @@ -687,24 +784,22 @@ acpi_gbl_ns_lookup_count = 0; acpi_gbl_ps_find_count = 0; acpi_gbl_acpi_hardware_present = TRUE; - acpi_gbl_next_table_owner_id = FIRST_TABLE_ID; - acpi_gbl_next_method_owner_id = FIRST_METHOD_ID; + acpi_gbl_next_table_owner_id = ACPI_FIRST_TABLE_ID; + acpi_gbl_next_method_owner_id = ACPI_FIRST_METHOD_ID; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; + acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; /* Hardware oriented */ - acpi_gbl_gpe0enable_register_save = NULL; - acpi_gbl_gpe1_enable_register_save = NULL; - acpi_gbl_original_mode = SYS_MODE_UNKNOWN; /* original ACPI/legacy mode */ - acpi_gbl_gpe_registers = NULL; - acpi_gbl_gpe_info = NULL; + acpi_gbl_gpe_register_info = NULL; + acpi_gbl_gpe_number_info = NULL; /* Namespace */ acpi_gbl_root_node = NULL; - acpi_gbl_root_node_struct.name = ACPI_ROOT_NAME; - acpi_gbl_root_node_struct.data_type = ACPI_DESC_TYPE_NAMED; + acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; + acpi_gbl_root_node_struct.descriptor = ACPI_DESC_TYPE_NAMED; acpi_gbl_root_node_struct.type = ACPI_TYPE_ANY; acpi_gbl_root_node_struct.child = NULL; acpi_gbl_root_node_struct.peer = NULL; @@ -713,7 +808,7 @@ #ifdef ACPI_DEBUG - acpi_gbl_lowest_stack_pointer = ACPI_UINT32_MAX; + acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX; #endif return_VOID; diff -Nur linux-2.4.19/drivers/acpi/utilities/utinit.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utinit.c --- linux-2.4.19/drivers/acpi/utilities/utinit.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utinit.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: utinit - Common ACPI subsystem initialization - * $Revision: 102 $ + * $Revision: 112 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,18 +25,11 @@ #include "acpi.h" -#include "achware.h" #include "acnamesp.h" #include "acevents.h" -#include "acparser.h" -#include "acdispat.h" #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utinit") - - -#define ACPI_OFFSET(d,o) ((u32) &(((d *)0)->o)) -#define ACPI_FADT_OFFSET(o) ACPI_OFFSET (FADT_DESCRIPTOR, o) + ACPI_MODULE_NAME ("utinit") /******************************************************************************* @@ -54,19 +47,16 @@ * ******************************************************************************/ -static acpi_status +static void acpi_ut_fadt_register_error ( NATIVE_CHAR *register_name, u32 value, - u32 offset) + ACPI_SIZE offset) { - REPORT_ERROR ( - ("Invalid FADT value %s=%lX at offset %lX FADT=%p\n", + ACPI_REPORT_WARNING ( + ("Invalid FADT value %s=%X at offset %X FADT=%p\n", register_name, value, offset, acpi_gbl_FADT)); - - - return (AE_BAD_VALUE); } @@ -86,69 +76,67 @@ acpi_ut_validate_fadt ( void) { - acpi_status status = AE_OK; - /* * Verify Fixed ACPI Description Table fields, * but don't abort on any problems, just display error */ if (acpi_gbl_FADT->pm1_evt_len < 4) { - status = acpi_ut_fadt_register_error ("PM1_EVT_LEN", + acpi_ut_fadt_register_error ("PM1_EVT_LEN", (u32) acpi_gbl_FADT->pm1_evt_len, ACPI_FADT_OFFSET (pm1_evt_len)); } if (!acpi_gbl_FADT->pm1_cnt_len) { - status = acpi_ut_fadt_register_error ("PM1_CNT_LEN", 0, + acpi_ut_fadt_register_error ("PM1_CNT_LEN", 0, ACPI_FADT_OFFSET (pm1_cnt_len)); } if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_evt_blk.address)) { - status = acpi_ut_fadt_register_error ("X_PM1a_EVT_BLK", 0, + acpi_ut_fadt_register_error ("X_PM1a_EVT_BLK", 0, ACPI_FADT_OFFSET (Xpm1a_evt_blk.address)); } if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1a_cnt_blk.address)) { - status = acpi_ut_fadt_register_error ("X_PM1a_CNT_BLK", 0, + acpi_ut_fadt_register_error ("X_PM1a_CNT_BLK", 0, ACPI_FADT_OFFSET (Xpm1a_cnt_blk.address)); } if (!ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address)) { - status = acpi_ut_fadt_register_error ("X_PM_TMR_BLK", 0, + acpi_ut_fadt_register_error ("X_PM_TMR_BLK", 0, ACPI_FADT_OFFSET (Xpm_tmr_blk.address)); } if ((ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm2_cnt_blk.address) && !acpi_gbl_FADT->pm2_cnt_len)) { - status = acpi_ut_fadt_register_error ("PM2_CNT_LEN", + acpi_ut_fadt_register_error ("PM2_CNT_LEN", (u32) acpi_gbl_FADT->pm2_cnt_len, ACPI_FADT_OFFSET (pm2_cnt_len)); } if (acpi_gbl_FADT->pm_tm_len < 4) { - status = acpi_ut_fadt_register_error ("PM_TM_LEN", + acpi_ut_fadt_register_error ("PM_TM_LEN", (u32) acpi_gbl_FADT->pm_tm_len, ACPI_FADT_OFFSET (pm_tm_len)); } - /* length of GPE blocks must be a multiple of 2 */ + /* Length of GPE blocks must be a multiple of 2 */ - if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) && - (acpi_gbl_FADT->gpe0blk_len & 1)) { - status = acpi_ut_fadt_register_error ("(x)GPE0_BLK_LEN", - (u32) acpi_gbl_FADT->gpe0blk_len, - ACPI_FADT_OFFSET (gpe0blk_len)); + if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0_blk.address) && + (acpi_gbl_FADT->gpe0_blk_len & 1)) { + acpi_ut_fadt_register_error ("(x)GPE0_BLK_LEN", + (u32) acpi_gbl_FADT->gpe0_blk_len, + ACPI_FADT_OFFSET (gpe0_blk_len)); } if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) && (acpi_gbl_FADT->gpe1_blk_len & 1)) { - status = acpi_ut_fadt_register_error ("(x)GPE1_BLK_LEN", + acpi_ut_fadt_register_error ("(x)GPE1_BLK_LEN", (u32) acpi_gbl_FADT->gpe1_blk_len, ACPI_FADT_OFFSET (gpe1_blk_len)); } - return (status); + return (AE_OK); } @@ -168,19 +156,12 @@ acpi_ut_terminate (void) { - FUNCTION_TRACE ("Ut_terminate"); + ACPI_FUNCTION_TRACE ("Ut_terminate"); /* Free global tables, etc. */ - if (acpi_gbl_gpe0enable_register_save) { - ACPI_MEM_FREE (acpi_gbl_gpe0enable_register_save); - } - - if (acpi_gbl_gpe1_enable_register_save) { - ACPI_MEM_FREE (acpi_gbl_gpe1_enable_register_save); - } - + /* Nothing to do at this time */ return_VOID; } @@ -199,17 +180,17 @@ * ******************************************************************************/ -acpi_status +void acpi_ut_subsystem_shutdown (void) { - FUNCTION_TRACE ("Ut_subsystem_shutdown"); + ACPI_FUNCTION_TRACE ("Ut_subsystem_shutdown"); /* Just exit if subsystem is already shutdown */ if (acpi_gbl_shutdown) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "ACPI Subsystem is already terminated\n")); - return_ACPI_STATUS (AE_OK); + return_VOID; } /* Subsystem appears active, go ahead and shut it down */ @@ -217,7 +198,6 @@ acpi_gbl_shutdown = TRUE; ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem...\n")); - /* Close the Namespace */ acpi_ns_terminate (); @@ -230,17 +210,9 @@ acpi_ut_terminate (); - /* Flush the local cache(s) */ + /* Purge the local caches */ - acpi_ut_delete_generic_state_cache (); - acpi_ut_delete_object_cache (); - acpi_ds_delete_walk_state_cache (); - - /* Close the Parser */ - - /* TBD: [Restructure] Acpi_ps_terminate () */ - - acpi_ps_delete_parse_cache (); + (void) acpi_purge_cached_objects (); /* Debug only - display leftover memory allocation, if any */ @@ -248,7 +220,7 @@ acpi_ut_dump_allocations (ACPI_UINT32_MAX, NULL); #endif - return_ACPI_STATUS (AE_OK); + return_VOID; } diff -Nur linux-2.4.19/drivers/acpi/utilities/utmath.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utmath.c --- linux-2.4.19/drivers/acpi/utilities/utmath.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utmath.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: utmath - Integer math support routines - * $Revision: 7 $ + * $Revision: 11 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utmath") + ACPI_MODULE_NAME ("utmath") /* * Support for double-precision integer divide. This code is included here @@ -66,14 +66,14 @@ u32 remainder32; - FUNCTION_TRACE ("Ut_short_divide"); + ACPI_FUNCTION_TRACE ("Ut_short_divide"); dividend.full = *in_dividend; /* Always check for a zero divisor */ if (divisor == 0) { - REPORT_ERROR (("Acpi_ut_short_divide: Divide by zero\n")); + ACPI_REPORT_ERROR (("Acpi_ut_short_divide: Divide by zero\n")); return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); } @@ -132,13 +132,13 @@ uint64_overlay partial3; - FUNCTION_TRACE ("Ut_divide"); + ACPI_FUNCTION_TRACE ("Ut_divide"); /* Always check for a zero divisor */ if (*in_divisor == 0) { - REPORT_ERROR (("Acpi_ut_divide: Divide by zero\n")); + ACPI_REPORT_ERROR (("Acpi_ut_divide: Divide by zero\n")); return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); } @@ -193,7 +193,7 @@ */ partial1 = quotient.part.lo * divisor.part.hi; partial2.full = (acpi_integer) quotient.part.lo * divisor.part.lo; - partial3.full = partial2.part.hi + partial1; + partial3.full = (acpi_integer) partial2.part.hi + partial1; remainder.part.hi = partial3.part.lo; remainder.part.lo = partial2.part.lo; @@ -213,8 +213,8 @@ } remainder.full = remainder.full - dividend.full; - remainder.part.hi = -((s32) remainder.part.hi); - remainder.part.lo = -((s32) remainder.part.lo); + remainder.part.hi = (u32) -((s32) remainder.part.hi); + remainder.part.lo = (u32) -((s32) remainder.part.lo); if (remainder.part.lo) { remainder.part.hi--; @@ -257,13 +257,13 @@ u32 *out_remainder) { - FUNCTION_TRACE ("Ut_short_divide"); + ACPI_FUNCTION_TRACE ("Ut_short_divide"); /* Always check for a zero divisor */ if (divisor == 0) { - REPORT_ERROR (("Acpi_ut_short_divide: Divide by zero\n")); + ACPI_REPORT_ERROR (("Acpi_ut_short_divide: Divide by zero\n")); return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); } @@ -286,13 +286,13 @@ acpi_integer *out_quotient, acpi_integer *out_remainder) { - FUNCTION_TRACE ("Ut_divide"); + ACPI_FUNCTION_TRACE ("Ut_divide"); /* Always check for a zero divisor */ if (*in_divisor == 0) { - REPORT_ERROR (("Acpi_ut_divide: Divide by zero\n")); + ACPI_REPORT_ERROR (("Acpi_ut_divide: Divide by zero\n")); return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); } diff -Nur linux-2.4.19/drivers/acpi/utilities/utmisc.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utmisc.c --- linux-2.4.19/drivers/acpi/utilities/utmisc.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utmisc.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * * Module Name: utmisc - common utility procedures - * $Revision: 52 $ + * $Revision: 75 $ * ******************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,16 +25,125 @@ #include "acpi.h" -#include "acevents.h" -#include "achware.h" #include "acnamesp.h" -#include "acinterp.h" #include "amlcode.h" -#include "acdebug.h" #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utmisc") + ACPI_MODULE_NAME ("utmisc") + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_dword_byte_swap + * + * PARAMETERS: Value - Value to be converted + * + * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) + * + ******************************************************************************/ + +u32 +acpi_ut_dword_byte_swap ( + u32 value) +{ + union { + u32 value; + u8 bytes[4]; + } out; + + union { + u32 value; + u8 bytes[4]; + } in; + + + ACPI_FUNCTION_ENTRY (); + + + in.value = value; + + out.bytes[0] = in.bytes[3]; + out.bytes[1] = in.bytes[2]; + out.bytes[2] = in.bytes[1]; + out.bytes[3] = in.bytes[0]; + + return (out.value); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_set_integer_width + * + * PARAMETERS: Revision From DSDT header + * + * RETURN: None + * + * DESCRIPTION: Set the global integer bit width based upon the revision + * of the DSDT. For Revision 1 and 0, Integers are 32 bits. + * For Revision 2 and above, Integers are 64 bits. Yes, this + * makes a difference. + * + ******************************************************************************/ + +void +acpi_ut_set_integer_width ( + u8 revision) +{ + + if (revision <= 1) { + acpi_gbl_integer_bit_width = 32; + acpi_gbl_integer_byte_width = 4; + } + else { + acpi_gbl_integer_bit_width = 64; + acpi_gbl_integer_byte_width = 8; + } +} + + +#ifdef ACPI_DEBUG +/******************************************************************************* + * + * FUNCTION: Acpi_ut_display_init_pathname + * + * PARAMETERS: Obj_handle - Handle whose pathname will be displayed + * Path - Additional path string to be appended + * + * RETURN: acpi_status + * + * DESCRIPTION: Display full pathnbame of an object, DEBUG ONLY + * + ******************************************************************************/ + +void +acpi_ut_display_init_pathname ( + acpi_handle obj_handle, + char *path) +{ + acpi_status status; + acpi_buffer buffer; + + + ACPI_FUNCTION_NAME ("Ut_display_init_pathname"); + + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + + status = acpi_ns_handle_to_pathname (obj_handle, &buffer); + if (ACPI_SUCCESS (status)) { + if (path) { + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "%s.%s\n", (char *) buffer.pointer, path)); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "%s\n", (char *) buffer.pointer)); + } + + ACPI_MEM_FREE (buffer.pointer); + } +} +#endif /******************************************************************************* @@ -60,7 +169,7 @@ u32 i; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); for (i = 0; i < ACPI_NAME_SIZE; i++) { @@ -92,7 +201,7 @@ NATIVE_CHAR character) { - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); return ((u8) ((character == '_') || (character >= 'A' && character <= 'Z') || @@ -102,6 +211,152 @@ /******************************************************************************* * + * FUNCTION: Acpi_ut_strtoul64 + * + * PARAMETERS: String - Null terminated string + * Terminater - Where a pointer to the terminating byte is returned + * Base - Radix of the string + * + * RETURN: Converted value + * + * DESCRIPTION: Convert a string into an unsigned value. + * + ******************************************************************************/ +#define NEGATIVE 1 +#define POSITIVE 0 + +acpi_status +acpi_ut_strtoul64 ( + NATIVE_CHAR *string, + u32 base, + acpi_integer *ret_integer) +{ + u32 index; + acpi_integer return_value = 0; + acpi_status status = AE_OK; + acpi_integer dividend; + acpi_integer quotient; + + + *ret_integer = 0; + + switch (base) { + case 0: + case 8: + case 10: + case 16: + break; + + default: + /* + * The specified Base parameter is not in the domain of + * this function: + */ + return (AE_BAD_PARAMETER); + } + + /* + * skip over any white space in the buffer: + */ + while (ACPI_IS_SPACE (*string) || *string == '\t') { + ++string; + } + + /* + * If the input parameter Base is zero, then we need to + * determine if it is octal, decimal, or hexadecimal: + */ + if (base == 0) { + if (*string == '0') { + if (ACPI_TOLOWER (*(++string)) == 'x') { + base = 16; + ++string; + } + else { + base = 8; + } + } + else { + base = 10; + } + } + + /* + * For octal and hexadecimal bases, skip over the leading + * 0 or 0x, if they are present. + */ + if (base == 8 && *string == '0') { + string++; + } + + if (base == 16 && + *string == '0' && + ACPI_TOLOWER (*(++string)) == 'x') { + string++; + } + + /* Main loop: convert the string to an unsigned long */ + + while (*string) { + if (ACPI_IS_DIGIT (*string)) { + index = ((u8) *string) - '0'; + } + else { + index = (u8) ACPI_TOUPPER (*string); + if (ACPI_IS_UPPER ((char) index)) { + index = index - 'A' + 10; + } + else { + goto error_exit; + } + } + + if (index >= base) { + goto error_exit; + } + + /* Check to see if value is out of range: */ + + dividend = ACPI_INTEGER_MAX - (acpi_integer) index; + (void) acpi_ut_short_divide (÷nd, base, "ient, NULL); + if (return_value > quotient) { + goto error_exit; + } + + return_value *= base; + return_value += index; + ++string; + } + + *ret_integer = return_value; + return (status); + + +error_exit: + switch (base) { + case 8: + status = AE_BAD_OCTAL_CONSTANT; + break; + + case 10: + status = AE_BAD_DECIMAL_CONSTANT; + break; + + case 16: + status = AE_BAD_HEX_CONSTANT; + break; + + default: + /* Base validated above */ + break; + } + + return (status); +} + + +/******************************************************************************* + * * FUNCTION: Acpi_ut_strupr * * PARAMETERS: Src_string - The source string to convert to @@ -119,13 +374,13 @@ NATIVE_CHAR *string; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* Walk entire string, uppercasing the letters */ for (string = src_string; *string; ) { - *string = (char) TOUPPER (*string); + *string = (char) ACPI_TOUPPER (*string); string++; } @@ -153,7 +408,7 @@ acpi_status status; - FUNCTION_TRACE ("Ut_mutex_initialize"); + ACPI_FUNCTION_TRACE ("Ut_mutex_initialize"); /* @@ -189,14 +444,14 @@ u32 i; - FUNCTION_TRACE ("Ut_mutex_terminate"); + ACPI_FUNCTION_TRACE ("Ut_mutex_terminate"); /* * Delete each predefined mutex object */ for (i = 0; i < NUM_MTX; i++) { - acpi_ut_delete_mutex (i); + (void) acpi_ut_delete_mutex (i); } return_VOID; @@ -222,7 +477,7 @@ acpi_status status = AE_OK; - FUNCTION_TRACE_U32 ("Ut_create_mutex", mutex_id); + ACPI_FUNCTION_TRACE_U32 ("Ut_create_mutex", mutex_id); if (mutex_id > MAX_MTX) { @@ -260,7 +515,7 @@ acpi_status status; - FUNCTION_TRACE_U32 ("Ut_delete_mutex", mutex_id); + ACPI_FUNCTION_TRACE_U32 ("Ut_delete_mutex", mutex_id); if (mutex_id > MAX_MTX) { @@ -298,7 +553,7 @@ u32 this_thread_id; - PROC_NAME ("Ut_acquire_mutex"); + ACPI_FUNCTION_NAME ("Ut_acquire_mutex"); if (mutex_id > MAX_MTX) { @@ -340,7 +595,6 @@ status = acpi_os_wait_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, 1, WAIT_FOREVER); - if (ACPI_SUCCESS (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n", this_thread_id, acpi_ut_get_mutex_name (mutex_id))); @@ -380,7 +634,7 @@ u32 this_thread_id; - PROC_NAME ("Ut_release_mutex"); + ACPI_FUNCTION_NAME ("Ut_release_mutex"); this_thread_id = acpi_os_get_thread_id (); @@ -469,7 +723,7 @@ acpi_generic_state *state; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* Ignore null objects; these are expected */ @@ -513,7 +767,7 @@ acpi_generic_state *state; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); state = acpi_ut_create_pkg_state (internal_object, external_object, index); @@ -545,7 +799,7 @@ acpi_generic_state **list_head, acpi_generic_state *state) { - FUNCTION_TRACE ("Ut_push_generic_state"); + ACPI_FUNCTION_TRACE ("Ut_push_generic_state"); /* Push the state object onto the front of the list (stack) */ @@ -576,7 +830,7 @@ acpi_generic_state *state; - FUNCTION_TRACE ("Ut_pop_generic_state"); + ACPI_FUNCTION_TRACE ("Ut_pop_generic_state"); /* Remove the state object at the head of the list (stack) */ @@ -611,7 +865,7 @@ acpi_generic_state *state; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); state = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_STATE); @@ -628,6 +882,45 @@ /******************************************************************************* * + * FUNCTION: Acpi_ut_create_thread_state + * + * PARAMETERS: None + * + * RETURN: Thread State + * + * DESCRIPTION: Create a "Thread State" - a flavor of the generic state used + * to track per-thread info during method execution + * + ******************************************************************************/ + +ACPI_THREAD_STATE * +acpi_ut_create_thread_state ( + void) +{ + acpi_generic_state *state; + + + ACPI_FUNCTION_TRACE ("Ut_create_thread_state"); + + + /* Create the generic state object */ + + state = acpi_ut_create_generic_state (); + if (!state) { + return_PTR (NULL); + } + + /* Init fields specific to the update struct */ + + state->common.data_type = ACPI_DESC_TYPE_STATE_THREAD; + state->thread.thread_id = acpi_os_get_thread_id (); + + return_PTR ((ACPI_THREAD_STATE *) state); +} + + +/******************************************************************************* + * * FUNCTION: Acpi_ut_create_update_state * * PARAMETERS: Object - Initial Object to be installed in the @@ -650,14 +943,14 @@ acpi_generic_state *state; - FUNCTION_TRACE_PTR ("Ut_create_update_state", object); + ACPI_FUNCTION_TRACE_PTR ("Ut_create_update_state", object); /* Create the generic state object */ state = acpi_ut_create_generic_state (); if (!state) { - return (NULL); + return_PTR (NULL); } /* Init fields specific to the update struct */ @@ -693,14 +986,14 @@ acpi_generic_state *state; - FUNCTION_TRACE_PTR ("Ut_create_pkg_state", internal_object); + ACPI_FUNCTION_TRACE_PTR ("Ut_create_pkg_state", internal_object); /* Create the generic state object */ state = acpi_ut_create_generic_state (); if (!state) { - return (NULL); + return_PTR (NULL); } /* Init fields specific to the update struct */ @@ -735,21 +1028,21 @@ acpi_generic_state *state; - FUNCTION_TRACE ("Ut_create_control_state"); + ACPI_FUNCTION_TRACE ("Ut_create_control_state"); /* Create the generic state object */ state = acpi_ut_create_generic_state (); if (!state) { - return (NULL); + return_PTR (NULL); } /* Init fields specific to the control struct */ state->common.data_type = ACPI_DESC_TYPE_STATE_CONTROL; - state->common.state = CONTROL_CONDITIONAL_EXECUTING; + state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING; return_PTR (state); } @@ -772,7 +1065,7 @@ acpi_ut_delete_generic_state ( acpi_generic_state *state) { - FUNCTION_TRACE ("Ut_delete_generic_state"); + ACPI_FUNCTION_TRACE ("Ut_delete_generic_state"); acpi_ut_release_to_cache (ACPI_MEM_LIST_STATE, state); @@ -797,7 +1090,7 @@ acpi_ut_delete_generic_state_cache ( void) { - FUNCTION_TRACE ("Ut_delete_generic_state_cache"); + ACPI_FUNCTION_TRACE ("Ut_delete_generic_state_cache"); acpi_ut_delete_generic_cache (ACPI_MEM_LIST_STATE); @@ -807,100 +1100,116 @@ /******************************************************************************* * - * FUNCTION: Acpi_ut_resolve_package_references + * FUNCTION: Acpi_ut_resolve_reference * - * PARAMETERS: Obj_desc - The Package object on which to resolve refs + * PARAMETERS: ACPI_PKG_CALLBACK * - * RETURN: Status + * RETURN: Status - the status of the call * - * DESCRIPTION: Walk through a package and turn internal references into values + * DESCRIPTION: Resolve a reference object to an actual value * ******************************************************************************/ acpi_status -acpi_ut_resolve_package_references ( - acpi_operand_object *obj_desc) +acpi_ut_resolve_reference ( + u8 object_type, + acpi_operand_object *source_object, + acpi_generic_state *state, + void *context) { - u32 count; - acpi_operand_object *sub_object; - + acpi_pkg_info *info = (acpi_pkg_info *) context; - FUNCTION_TRACE ("Ut_resolve_package_references"); + switch (object_type) { + case ACPI_COPY_TYPE_SIMPLE: - if (obj_desc->common.type != ACPI_TYPE_PACKAGE) { - /* The object must be a package */ + /* + * Simple object - check for a reference + */ + if (source_object->common.type == INTERNAL_TYPE_REFERENCE) { + switch (source_object->reference.opcode) { + case AML_ZERO_OP: - REPORT_ERROR (("Must resolve Package Refs on a Package\n")); - return_ACPI_STATUS(AE_ERROR); - } + source_object->common.type = ACPI_TYPE_INTEGER; + source_object->integer.value = 0; + break; - /* - * TBD: what about nested packages? */ + case AML_ONE_OP: - for (count = 0; count < obj_desc->package.count; count++) { - sub_object = obj_desc->package.elements[count]; + source_object->common.type = ACPI_TYPE_INTEGER; + source_object->integer.value = 1; + break; - if (sub_object->common.type == INTERNAL_TYPE_REFERENCE) { - if (sub_object->reference.opcode == AML_ZERO_OP) { - sub_object->common.type = ACPI_TYPE_INTEGER; - sub_object->integer.value = 0; - } + case AML_ONES_OP: - else if (sub_object->reference.opcode == AML_ONE_OP) { - sub_object->common.type = ACPI_TYPE_INTEGER; - sub_object->integer.value = 1; - } + source_object->common.type = ACPI_TYPE_INTEGER; + source_object->integer.value = ACPI_INTEGER_MAX; + break; - else if (sub_object->reference.opcode == AML_ONES_OP) { - sub_object->common.type = ACPI_TYPE_INTEGER; - sub_object->integer.value = ACPI_INTEGER_MAX; + default: + /* Other types not supported */ + return (AE_SUPPORT); } } + break; + + + case ACPI_COPY_TYPE_PACKAGE: + + /* Package object - nothing much to do here, let the walk handle it */ + + info->num_packages++; + state->pkg.this_target_obj = NULL; + break; + + default: + return (AE_BAD_PARAMETER); } - return_ACPI_STATUS(AE_OK); + return (AE_OK); } -#ifdef ACPI_DEBUG /******************************************************************************* * - * FUNCTION: Acpi_ut_display_init_pathname + * FUNCTION: Acpi_ut_resolve_package_references * - * PARAMETERS: Obj_handle - Handle whose pathname will be displayed - * Path - Additional path string to be appended + * PARAMETERS: Obj_desc - The Package object on which to resolve refs * - * RETURN: acpi_status + * RETURN: Status * - * DESCRIPTION: Display full pathnbame of an object, DEBUG ONLY + * DESCRIPTION: Walk through a package and turn internal references into values * ******************************************************************************/ -void -acpi_ut_display_init_pathname ( - acpi_handle obj_handle, - char *path) +acpi_status +acpi_ut_resolve_package_references ( + acpi_operand_object *obj_desc) { + acpi_pkg_info info; acpi_status status; - u32 length = 128; - char buffer[128]; - PROC_NAME ("Ut_display_init_pathname"); + ACPI_FUNCTION_TRACE ("Ut_resolve_package_references"); - status = acpi_ns_handle_to_pathname (obj_handle, &length, buffer); - if (ACPI_SUCCESS (status)) { - if (path) { - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "%s.%s\n", buffer, path)); - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "%s\n", buffer)); - } + if (obj_desc->common.type != ACPI_TYPE_PACKAGE) { + /* The object must be a package */ + + ACPI_REPORT_ERROR (("Expecting a Package object\n")); + return_ACPI_STATUS (AE_TYPE); } + + info.length = 0; + info.object_space = 0; + info.num_packages = 1; + + status = acpi_ut_walk_package_tree (obj_desc, NULL, + acpi_ut_resolve_reference, &info); + + return_ACPI_STATUS (status); } -#endif + /******************************************************************************* * @@ -928,7 +1237,7 @@ acpi_operand_object *this_source_obj; - FUNCTION_TRACE ("Ut_walk_package_tree"); + ACPI_FUNCTION_TRACE ("Ut_walk_package_tree"); state = acpi_ut_create_pkg_state (source_object, target_object, 0); @@ -942,24 +1251,19 @@ state->pkg.source_object->package.elements[this_index]; /* - * Check for + * Check for: * 1) An uninitialized package element. It is completely - * legal to declare a package and leave it uninitialized + * legal to declare a package and leave it uninitialized * 2) Not an internal object - can be a namespace node instead * 3) Any type other than a package. Packages are handled in else - * case below. + * case below. */ if ((!this_source_obj) || - (!VALID_DESCRIPTOR_TYPE ( - this_source_obj, ACPI_DESC_TYPE_INTERNAL)) || - (!IS_THIS_OBJECT_TYPE ( - this_source_obj, ACPI_TYPE_PACKAGE))) { - + (ACPI_GET_DESCRIPTOR_TYPE (this_source_obj) != ACPI_DESC_TYPE_OPERAND) || + (this_source_obj->common.type != ACPI_TYPE_PACKAGE)) { status = walk_callback (ACPI_COPY_TYPE_SIMPLE, this_source_obj, state, context); if (ACPI_FAILURE (status)) { - /* TBD: must delete package created up to this point */ - return_ACPI_STATUS (status); } @@ -975,7 +1279,6 @@ acpi_ut_delete_generic_state (state); state = acpi_ut_pop_generic_state (&state_list); - /* Finished when there are no more states */ if (!state) { @@ -994,32 +1297,23 @@ state->pkg.index++; } } - else { - /* This is a sub-object of type package */ + /* This is a subobject of type package */ status = walk_callback (ACPI_COPY_TYPE_PACKAGE, this_source_obj, state, context); if (ACPI_FAILURE (status)) { - /* TBD: must delete package created up to this point */ - return_ACPI_STATUS (status); } - - /* - * The callback above returned a new target package object. - */ - /* * Push the current state and create a new one + * The callback above returned a new target package object. */ acpi_ut_push_generic_state (&state_list, state); state = acpi_ut_create_pkg_state (this_source_obj, state->pkg.this_target_obj, 0); if (!state) { - /* TBD: must delete package created up to this point */ - return_ACPI_STATUS (AE_NO_MEMORY); } } @@ -1027,7 +1321,89 @@ /* We should never get here */ - return (AE_AML_INTERNAL); + return_ACPI_STATUS (AE_AML_INTERNAL); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_generate_checksum + * + * PARAMETERS: Buffer - Buffer to be scanned + * Length - number of bytes to examine + * + * RETURN: checksum + * + * DESCRIPTION: Generate a checksum on a raw buffer + * + ******************************************************************************/ + +u8 +acpi_ut_generate_checksum ( + u8 *buffer, + u32 length) +{ + u32 i; + signed char sum = 0; + + for (i = 0; i < length; i++) { + sum = (signed char) (sum + buffer[i]); + } + + return ((u8) (0 - sum)); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ut_get_resource_end_tag + * + * PARAMETERS: Obj_desc - The resource template buffer object + * + * RETURN: Pointer to the end tag + * + * DESCRIPTION: Find the END_TAG resource descriptor in a resource template + * + ******************************************************************************/ + + +u8 * +acpi_ut_get_resource_end_tag ( + acpi_operand_object *obj_desc) +{ + u8 buffer_byte; + u8 *buffer; + u8 *end_buffer; + + + buffer = obj_desc->buffer.pointer; + end_buffer = buffer + obj_desc->buffer.length; + + while (buffer < end_buffer) { + buffer_byte = *buffer; + if (buffer_byte & ACPI_RDESC_TYPE_MASK) { + /* Large Descriptor - Length is next 2 bytes */ + + buffer += ((*(buffer+1) | (*(buffer+2) << 8)) + 3); + } + else { + /* Small Descriptor. End Tag will be found here */ + + if ((buffer_byte & ACPI_RDESC_SMALL_MASK) == ACPI_RDESC_TYPE_END_TAG) { + /* Found the end tag descriptor, all done. */ + + return (buffer); + } + + /* Length is in the header */ + + buffer += ((buffer_byte & 0x07) + 1); + } + } + + /* End tag not found */ + + return (NULL); } diff -Nur linux-2.4.19/drivers/acpi/utilities/utobject.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utobject.c --- linux-2.4.19/drivers/acpi/utilities/utobject.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utobject.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: utobject - ACPI object create/delete/size/cache routines - * $Revision: 57 $ + * $Revision: 73 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +25,12 @@ #include "acpi.h" -#include "acinterp.h" #include "acnamesp.h" -#include "actables.h" #include "amlcode.h" #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utobject") + ACPI_MODULE_NAME ("utobject") /******************************************************************************* @@ -62,26 +60,50 @@ NATIVE_CHAR *module_name, u32 line_number, u32 component_id, - acpi_object_type8 type) + acpi_object_type type) { acpi_operand_object *object; + acpi_operand_object *second_object; - FUNCTION_TRACE_STR ("Ut_create_internal_object_dbg", acpi_ut_get_type_name (type)); + ACPI_FUNCTION_TRACE_STR ("Ut_create_internal_object_dbg", acpi_ut_get_type_name (type)); /* Allocate the raw object descriptor */ object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id); if (!object) { - /* Allocation failure */ - return_PTR (NULL); } + switch (type) { + case ACPI_TYPE_REGION: + case ACPI_TYPE_BUFFER_FIELD: + + /* These types require a secondary object */ + + second_object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id); + if (!second_object) { + acpi_ut_delete_object_desc (object); + return_PTR (NULL); + } + + second_object->common.type = INTERNAL_TYPE_EXTRA; + second_object->common.reference_count = 1; + + /* Link the second object to the first */ + + object->common.next_object = second_object; + break; + + default: + /* All others have no secondary object */ + break; + } + /* Save the object type in the object descriptor */ - object->common.type = type; + object->common.type = (u8) type; /* Init the reference count */ @@ -108,7 +130,7 @@ void *object) { - PROC_NAME ("Ut_valid_internal_object"); + ACPI_FUNCTION_NAME ("Ut_valid_internal_object"); /* Check for a null pointer */ @@ -121,31 +143,33 @@ /* Check the descriptor type field */ - if (!VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL)) { - /* Not an ACPI internal object, do some further checking */ + switch (ACPI_GET_DESCRIPTOR_TYPE (object)) { + case ACPI_DESC_TYPE_OPERAND: - if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "**** Obj %p is a named obj, not ACPI obj\n", object)); - } + /* The object appears to be a valid acpi_operand_object */ - else if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_PARSER)) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "**** Obj %p is a parser obj, not ACPI obj\n", object)); - } + return (TRUE); - else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "**** Obj %p is of unknown type\n", object)); - } + case ACPI_DESC_TYPE_NAMED: - return (FALSE); - } + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Obj %p is a named obj, not ACPI obj\n", object)); + break; + case ACPI_DESC_TYPE_PARSER: - /* The object appears to be a valid acpi_operand_object */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Obj %p is a parser obj, not ACPI obj\n", object)); + break; - return (TRUE); + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Obj %p is of unknown type\n", object)); + break; + } + + return (FALSE); } @@ -174,12 +198,12 @@ acpi_operand_object *object; - FUNCTION_TRACE ("Ut_allocate_object_desc_dbg"); + ACPI_FUNCTION_TRACE ("Ut_allocate_object_desc_dbg"); object = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_OPERAND); if (!object) { - _REPORT_ERROR (module_name, line_number, component_id, + _ACPI_REPORT_ERROR (module_name, line_number, component_id, ("Could not allocate an object descriptor\n")); return_PTR (NULL); @@ -188,10 +212,10 @@ /* Mark the descriptor type */ - object->common.data_type = ACPI_DESC_TYPE_INTERNAL; + ACPI_SET_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_OPERAND); ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p Size %X\n", - object, sizeof (acpi_operand_object))); + object, (u32) sizeof (acpi_operand_object))); return_PTR (object); } @@ -213,12 +237,12 @@ acpi_ut_delete_object_desc ( acpi_operand_object *object) { - FUNCTION_TRACE_PTR ("Ut_delete_object_desc", object); + ACPI_FUNCTION_TRACE_PTR ("Ut_delete_object_desc", object); /* Object must be an acpi_operand_object */ - if (object->common.data_type != ACPI_DESC_TYPE_INTERNAL) { + if (ACPI_GET_DESCRIPTOR_TYPE (object) != ACPI_DESC_TYPE_OPERAND) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Obj %p is not an ACPI object\n", object)); return_VOID; @@ -247,7 +271,7 @@ acpi_ut_delete_object_cache ( void) { - FUNCTION_TRACE ("Ut_delete_object_cache"); + ACPI_FUNCTION_TRACE ("Ut_delete_object_cache"); acpi_ut_delete_generic_cache (ACPI_MEM_LIST_OPERAND); @@ -275,13 +299,13 @@ acpi_status acpi_ut_get_simple_object_size ( acpi_operand_object *internal_object, - u32 *obj_length) + ACPI_SIZE *obj_length) { - u32 length; + ACPI_SIZE length; acpi_status status = AE_OK; - FUNCTION_TRACE_PTR ("Ut_get_simple_object_size", internal_object); + ACPI_FUNCTION_TRACE_PTR ("Ut_get_simple_object_size", internal_object); /* Handle a null object (Could be a uninitialized package element -- which is legal) */ @@ -296,10 +320,10 @@ length = sizeof (acpi_object); - if (VALID_DESCRIPTOR_TYPE (internal_object, ACPI_DESC_TYPE_NAMED)) { + if (ACPI_GET_DESCRIPTOR_TYPE (internal_object) == ACPI_DESC_TYPE_NAMED) { /* Object is a named object (reference), just return the length */ - *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length); + *obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD (length); return_ACPI_STATUS (status); } @@ -315,13 +339,13 @@ case ACPI_TYPE_STRING: - length += internal_object->string.length + 1; + length += (ACPI_SIZE) internal_object->string.length + 1; break; case ACPI_TYPE_BUFFER: - length += internal_object->buffer.length; + length += (ACPI_SIZE) internal_object->buffer.length; break; @@ -337,23 +361,37 @@ case INTERNAL_TYPE_REFERENCE: - /* - * The only type that should be here is internal opcode NAMEPATH_OP -- since - * this means an object reference - */ - if (internal_object->reference.opcode != AML_INT_NAMEPATH_OP) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unsupported Reference opcode=%X in object %p\n", - internal_object->reference.opcode, internal_object)); - status = AE_TYPE; - } + switch (internal_object->reference.opcode) { + case AML_ZERO_OP: + case AML_ONE_OP: + case AML_ONES_OP: + case AML_REVISION_OP: + + /* These Constant opcodes will be resolved to Integers */ + + break; + + case AML_INT_NAMEPATH_OP: - else { /* * Get the actual length of the full pathname to this object. * The reference will be converted to the pathname to the object */ - length += ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node)); + length += ACPI_ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node)); + break; + + default: + + /* + * No other reference opcodes are supported. + * Notably, Locals and Args are not supported, by this may be + * required eventually. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unsupported Reference opcode=%X in object %p\n", + internal_object->reference.opcode, internal_object)); + status = AE_TYPE; + break; } break; @@ -373,8 +411,7 @@ * on a machine word boundary. (preventing alignment faults on some * machines.) */ - *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length); - + *obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD (length); return_ACPI_STATUS (status); } @@ -400,11 +437,11 @@ { acpi_status status = AE_OK; acpi_pkg_info *info = (acpi_pkg_info *) context; - u32 object_space; + ACPI_SIZE object_space; switch (object_type) { - case 0: + case ACPI_COPY_TYPE_SIMPLE: /* * Simple object - just get the size (Null object/entry is handled @@ -419,18 +456,22 @@ break; - case 1: - /* Package - nothing much to do here, let the walk handle it */ + case ACPI_COPY_TYPE_PACKAGE: + + /* Package object - nothing much to do here, let the walk handle it */ info->num_packages++; state->pkg.this_target_obj = NULL; break; + default: + + /* No other types allowed */ + return (AE_BAD_PARAMETER); } - return (status); } @@ -455,13 +496,13 @@ acpi_status acpi_ut_get_package_object_size ( acpi_operand_object *internal_object, - u32 *obj_length) + ACPI_SIZE *obj_length) { acpi_status status; acpi_pkg_info info; - FUNCTION_TRACE_PTR ("Ut_get_package_object_size", internal_object); + ACPI_FUNCTION_TRACE_PTR ("Ut_get_package_object_size", internal_object); info.length = 0; @@ -470,14 +511,17 @@ status = acpi_ut_walk_package_tree (internal_object, NULL, acpi_ut_get_element_length, &info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } /* * We have handled all of the objects in all levels of the package. * just add the length of the package objects themselves. * Round up to the next machine word. */ - info.length += ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object)) * - info.num_packages; + info.length += ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object)) * + (ACPI_SIZE) info.num_packages; /* Return the total package length */ @@ -503,19 +547,18 @@ acpi_status acpi_ut_get_object_size( acpi_operand_object *internal_object, - u32 *obj_length) + ACPI_SIZE *obj_length) { acpi_status status; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); - if ((VALID_DESCRIPTOR_TYPE (internal_object, ACPI_DESC_TYPE_INTERNAL)) && - (IS_THIS_OBJECT_TYPE (internal_object, ACPI_TYPE_PACKAGE))) { + if ((ACPI_GET_DESCRIPTOR_TYPE (internal_object) == ACPI_DESC_TYPE_OPERAND) && + (internal_object->common.type == ACPI_TYPE_PACKAGE)) { status = acpi_ut_get_package_object_size (internal_object, obj_length); } - else { status = acpi_ut_get_simple_object_size (internal_object, obj_length); } diff -Nur linux-2.4.19/drivers/acpi/utilities/utxface.c linux-2.4.19-sgi211r3/drivers/acpi/utilities/utxface.c --- linux-2.4.19/drivers/acpi/utilities/utxface.c Wed Oct 24 14:06:22 2001 +++ linux-2.4.19-sgi211r3/drivers/acpi/utilities/utxface.c Tue Aug 27 19:53:13 2002 @@ -1,12 +1,12 @@ /****************************************************************************** * * Module Name: utxface - External interfaces for "global" ACPI functions - * $Revision: 82 $ + * $Revision: 96 $ * *****************************************************************************/ /* - * Copyright (C) 2000, 2001 R. Byron Moore + * Copyright (C) 2000 - 2002, R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,16 +26,13 @@ #include "acpi.h" #include "acevents.h" -#include "achware.h" #include "acnamesp.h" -#include "acinterp.h" -#include "amlcode.h" +#include "acparser.h" +#include "acdispat.h" #include "acdebug.h" -#include "acexcep.h" - #define _COMPONENT ACPI_UTILITIES - MODULE_NAME ("utxface") + ACPI_MODULE_NAME ("utxface") /******************************************************************************* @@ -57,10 +54,10 @@ { acpi_status status; - FUNCTION_TRACE ("Acpi_initialize_subsystem"); + ACPI_FUNCTION_TRACE ("Acpi_initialize_subsystem"); - DEBUG_EXEC(acpi_ut_init_stack_ptr_trace ()); + ACPI_DEBUG_EXEC (acpi_ut_init_stack_ptr_trace ()); /* Initialize all globals used by the subsystem */ @@ -71,7 +68,7 @@ status = acpi_os_initialize (); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("OSD failed to initialize, %s\n", + ACPI_REPORT_ERROR (("OSD failed to initialize, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -80,7 +77,7 @@ status = acpi_ut_mutex_initialize (); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("Global mutex creation failure, %s\n", + ACPI_REPORT_ERROR (("Global mutex creation failure, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -92,7 +89,7 @@ status = acpi_ns_root_initialize (); if (ACPI_FAILURE (status)) { - REPORT_ERROR (("Namespace initialization failure, %s\n", + ACPI_REPORT_ERROR (("Namespace initialization failure, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -100,7 +97,7 @@ /* If configured, initialize the AML debugger */ - DEBUGGER_EXEC (acpi_db_initialize ()); + ACPI_DEBUGGER_EXEC (status = acpi_db_initialize ()); return_ACPI_STATUS (status); } @@ -126,25 +123,18 @@ acpi_status status = AE_OK; - FUNCTION_TRACE ("Acpi_enable_subsystem"); - + ACPI_FUNCTION_TRACE ("Acpi_enable_subsystem"); - /* Sanity check the FADT for valid values */ - - status = acpi_ut_validate_fadt (); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } /* - * Install the default Op_region handlers. These are - * installed unless other handlers have already been - * installed via the Install_address_space_handler interface + * Install the default Op_region handlers. These are installed unless + * other handlers have already been installed via the + * Install_address_space_handler interface */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); - status = acpi_ev_install_default_address_space_handlers (); + status = acpi_ev_init_address_spaces (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -152,6 +142,7 @@ /* * We must initialize the hardware before we can enable ACPI. + * FADT values are validated here. */ if (!(flags & ACPI_NO_HARDWARE_INIT)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI hardware\n")); @@ -190,6 +181,16 @@ } } + /* Install SCI handler, Global Lock handler, GPE handlers */ + + if (!(flags & ACPI_NO_HANDLER_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL/GPE handlers\n")); + + status = acpi_ev_handler_initialize (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } /* * Initialize all device objects in the namespace @@ -204,7 +205,6 @@ } } - /* * Initialize the objects that remain uninitialized. This * runs the executable AML that is part of the declaration of Op_regions @@ -219,8 +219,14 @@ } } - acpi_gbl_startup_flags |= ACPI_INITIALIZED_OK; + /* + * Empty the caches (delete the cached objects) on the assumption that + * the table load filled them up more than they will be at runtime -- + * thus wasting non-paged memory. + */ + status = acpi_purge_cached_objects (); + acpi_gbl_startup_flags |= ACPI_INITIALIZED_OK; return_ACPI_STATUS (status); } @@ -240,16 +246,15 @@ acpi_status acpi_terminate (void) { - FUNCTION_TRACE ("Acpi_terminate"); + acpi_status status; - /* Terminate the AML Debugger if present */ + ACPI_FUNCTION_TRACE ("Acpi_terminate"); - DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE); - /* TBD: [Investigate] This is no longer needed?*/ -/* Acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_READY); */ + /* Terminate the AML Debugger if present */ + ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE); /* Shutdown and free all resources */ @@ -270,10 +275,8 @@ /* Now we can shutdown the OS-dependent layer */ - acpi_os_terminate (); - - - return_ACPI_STATUS (AE_OK); + status = acpi_os_terminate (); + return_ACPI_STATUS (status); } @@ -328,42 +331,39 @@ { acpi_system_info *info_ptr; u32 i; + acpi_status status; - FUNCTION_TRACE ("Acpi_get_system_info"); + ACPI_FUNCTION_TRACE ("Acpi_get_system_info"); - /* - * Must have a valid buffer - */ - if ((!out_buffer) || - (!out_buffer->pointer)) { - return_ACPI_STATUS (AE_BAD_PARAMETER); + /* Parameter validation */ + + status = acpi_ut_validate_buffer (out_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - if (out_buffer->length < sizeof (acpi_system_info)) { - /* - * Caller's buffer is too small - */ - out_buffer->length = sizeof (acpi_system_info); + /* Validate/Allocate/Clear caller buffer */ - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + status = acpi_ut_initialize_buffer (out_buffer, sizeof (acpi_system_info)); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - /* - * Set return length and get data + * Populate the return buffer */ - out_buffer->length = sizeof (acpi_system_info); info_ptr = (acpi_system_info *) out_buffer->pointer; info_ptr->acpi_ca_version = ACPI_CA_VERSION; /* System flags (ACPI capabilities) */ - info_ptr->flags = acpi_gbl_system_flags; + info_ptr->flags = ACPI_SYS_MODE_ACPI; /* Timer resolution - 24 or 32 bits */ + if (!acpi_gbl_FADT) { info_ptr->timer_resolution = 0; } @@ -395,3 +395,61 @@ } +/***************************************************************************** + * + * FUNCTION: Acpi_install_initialization_handler + * + * PARAMETERS: Handler - Callback procedure + * + * RETURN: Status + * + * DESCRIPTION: Install an initialization handler + * + * TBD: When a second function is added, must save the Function also. + * + ****************************************************************************/ + +acpi_status +acpi_install_initialization_handler ( + ACPI_INIT_HANDLER handler, + u32 function) +{ + + if (!handler) { + return (AE_BAD_PARAMETER); + } + + if (acpi_gbl_init_handler) { + return (AE_ALREADY_EXISTS); + } + + acpi_gbl_init_handler = handler; + return AE_OK; +} + + +/***************************************************************************** + * + * FUNCTION: Acpi_purge_cached_objects + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Empty all caches (delete the cached objects) + * + ****************************************************************************/ + +acpi_status +acpi_purge_cached_objects (void) +{ + ACPI_FUNCTION_TRACE ("Acpi_purge_cached_objects"); + + + acpi_ut_delete_generic_state_cache (); + acpi_ut_delete_object_cache (); + acpi_ds_delete_walk_state_cache (); + acpi_ps_delete_parse_cache (); + + return_ACPI_STATUS (AE_OK); +} diff -Nur linux-2.4.19/drivers/acpi/utils.c linux-2.4.19-sgi211r3/drivers/acpi/utils.c --- linux-2.4.19/drivers/acpi/utils.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/acpi/utils.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,460 @@ +/* + * acpi_utils.c - ACPI Utility Functions ($Revision: 1.1 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include "acpi_bus.h" +#include "acpi_drivers.h" + + +#define _COMPONENT ACPI_BUS_COMPONENT +ACPI_MODULE_NAME ("acpi_utils") + + +/* -------------------------------------------------------------------------- + Object Evaluation Helpers + -------------------------------------------------------------------------- */ + +#ifdef ACPI_DEBUG +#define acpi_util_eval_error(h,p,s) {\ + char prefix[80] = {'\0'};\ + acpi_buffer buffer = {sizeof(prefix), prefix};\ + acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",\ + (char *) prefix, p, acpi_format_exception(s))); } +#else +#define acpi_util_eval_error(h,p,s) +#endif + + +acpi_status +acpi_extract_package ( + acpi_object *package, + acpi_buffer *format, + acpi_buffer *buffer) +{ + u32 size_required = 0; + u32 tail_offset = 0; + char *format_string = NULL; + u32 format_count = 0; + u32 i = 0; + u8 *head = NULL; + u8 *tail = NULL; + + ACPI_FUNCTION_TRACE("acpi_extract_package"); + + if (!package || (package->type != ACPI_TYPE_PACKAGE) || (package->package.count < 1)) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'package' argument\n")); + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (!format || !format->pointer || (format->length < 1)) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'format' argument\n")); + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (!buffer) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'buffer' argument\n")); + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + format_count = (format->length/sizeof(char)) - 1; + if (format_count > package->package.count) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Format specifies more objects [%d] than exist in package [%d].", format_count, package->package.count)); + return_ACPI_STATUS(AE_BAD_DATA); + } + + format_string = (char*)format->pointer; + + /* + * Calculate size_required. + */ + for (i=0; ipackage.elements[i]); + + if (!element) { + return_ACPI_STATUS(AE_BAD_DATA); + } + + switch (element->type) { + + case ACPI_TYPE_INTEGER: + switch (format_string[i]) { + case 'N': + size_required += sizeof(acpi_integer); + tail_offset += sizeof(acpi_integer); + break; + case 'S': + size_required += sizeof(char*) + sizeof(acpi_integer) + sizeof(char); + tail_offset += sizeof(char*); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d]: got number, expecing [%c].\n", i, format_string[i])); + return_ACPI_STATUS(AE_BAD_DATA); + break; + } + break; + + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + switch (format_string[i]) { + case 'S': + size_required += sizeof(char*) + (element->string.length * sizeof(char)) + sizeof(char); + tail_offset += sizeof(char*); + break; + case 'B': + size_required += sizeof(u8*) + (element->buffer.length * sizeof(u8)); + tail_offset += sizeof(u8*); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d] got string/buffer, expecing [%c].\n", i, format_string[i])); + return_ACPI_STATUS(AE_BAD_DATA); + break; + } + break; + + case ACPI_TYPE_PACKAGE: + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unsupported element at index=%d\n", i)); + /* TBD: handle nested packages... */ + return_ACPI_STATUS(AE_SUPPORT); + break; + } + } + + /* + * Validate output buffer. + */ + if (buffer->length < size_required) { + buffer->length = size_required; + return_ACPI_STATUS(AE_BUFFER_OVERFLOW); + } + else if (buffer->length != size_required || !buffer->pointer) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + head = buffer->pointer; + tail = buffer->pointer + tail_offset; + + /* + * Extract package data. + */ + for (i=0; ipackage.elements[i]); + + if (!element) { + return_ACPI_STATUS(AE_BAD_DATA); + } + + switch (element->type) { + + case ACPI_TYPE_INTEGER: + switch (format_string[i]) { + case 'N': + *((acpi_integer*)head) = element->integer.value; + head += sizeof(acpi_integer); + break; + case 'S': + pointer = (u8**)head; + *pointer = tail; + *((acpi_integer*)tail) = element->integer.value; + head += sizeof(acpi_integer*); + tail += sizeof(acpi_integer); + /* NULL terminate string */ + *tail = (char)0; + tail += sizeof(char); + break; + default: + /* Should never get here */ + break; + } + break; + + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + switch (format_string[i]) { + case 'S': + pointer = (u8**)head; + *pointer = tail; + memcpy(tail, element->string.pointer, element->string.length); + head += sizeof(char*); + tail += element->string.length * sizeof(char); + /* NULL terminate string */ + *tail = (char)0; + tail += sizeof(char); + break; + case 'B': + pointer = (u8**)head; + *pointer = tail; + memcpy(tail, element->buffer.pointer, element->buffer.length); + head += sizeof(u8*); + tail += element->buffer.length * sizeof(u8); + break; + default: + /* Should never get here */ + break; + } + break; + + case ACPI_TYPE_PACKAGE: + /* TBD: handle nested packages... */ + default: + /* Should never get here */ + break; + } + } + + return_ACPI_STATUS(AE_OK); +} + + +acpi_status +acpi_evaluate ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *arguments, + acpi_buffer *buffer) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE("acpi_evaluate"); + + /* If caller provided a buffer it must be unallocated/zero'd. */ + if (buffer && (buffer->length != 0 || buffer->pointer)) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + /* + * Evalute object. The first attempt is just to get the size of the + * object data (that is unless there's no return data); the second + * gets the data. + */ + status = acpi_evaluate_object(handle, pathname, arguments, buffer); + + if (ACPI_SUCCESS(status)) { + return_ACPI_STATUS(status); + } + + else if (buffer && (status == AE_BUFFER_OVERFLOW)) { + + /* Gotta allocate - CALLER MUST FREE! */ + buffer->pointer = kmalloc(buffer->length, GFP_KERNEL); + if (!buffer->pointer) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + memset(buffer->pointer, 0, buffer->length); + + /* Re-evaluate - this time it should work. */ + status = acpi_evaluate_object(handle, pathname, arguments, + buffer); + } + + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + acpi_util_eval_error(handle, pathname, status); + if (buffer && buffer->pointer) { + kfree(buffer->pointer); + buffer->length = 0; + } + } + + return_ACPI_STATUS(status); +} + + +acpi_status +acpi_evaluate_integer ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *arguments, + unsigned long *data) +{ + acpi_status status = AE_OK; + acpi_object element; + acpi_buffer buffer = {sizeof(acpi_object), &element}; + + ACPI_FUNCTION_TRACE("acpi_evaluate_integer"); + + if (!data) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + status = acpi_evaluate_object(handle, pathname, arguments, &buffer); + if (ACPI_FAILURE(status)) { + acpi_util_eval_error(handle, pathname, status); + return_ACPI_STATUS(status); + } + + if (element.type != ACPI_TYPE_INTEGER) { + acpi_util_eval_error(handle, pathname, AE_BAD_DATA); + return_ACPI_STATUS(AE_BAD_DATA); + } + + *data = element.integer.value; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data)); + + return_ACPI_STATUS(AE_OK); +} + + +#if 0 +acpi_status +acpi_evaluate_string ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *arguments, + acpi_string *data) +{ + acpi_status status = AE_OK; + acpi_object *element = NULL; + acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + + ACPI_FUNCTION_TRACE("acpi_evaluate_string"); + + if (!data) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + status = acpi_evaluate_object(handle, pathname, arguments, &buffer); + if (ACPI_FAILURE(status)) { + acpi_util_eval_error(handle, pathname, status); + return_ACPI_STATUS(status); + } + + element = (acpi_object *) buffer.pointer; + + if ((element->type != ACPI_TYPE_STRING) + || (element->type != ACPI_TYPE_BUFFER) + || !element->string.length) { + acpi_util_eval_error(handle, pathname, AE_BAD_DATA); + return_ACPI_STATUS(AE_BAD_DATA); + } + + *data = kmalloc(element->string.length + 1, GFP_KERNEL); + if (!data) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n")); + return_VALUE(-ENOMEM); + } + memset(*data, 0, element->string.length + 1); + + memcpy(*data, element->string.pointer, element->string.length); + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data)); + + return_ACPI_STATUS(AE_OK); +} +#endif + + +acpi_status +acpi_evaluate_reference ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *arguments, + struct acpi_handle_list *list) +{ + acpi_status status = AE_OK; + acpi_object *package = NULL; + acpi_object *element = NULL; + acpi_buffer buffer = {0, NULL}; + u32 i = 0; + + ACPI_FUNCTION_TRACE("acpi_evaluate_reference"); + + if (!list) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + /* Evaluate object. */ + + status = acpi_evaluate(handle, pathname, arguments, &buffer); + if (ACPI_FAILURE(status)) + goto end; + + package = (acpi_object *) buffer.pointer; + + if (!package || (package->type != ACPI_TYPE_PACKAGE) + || (package->package.count == 0)) { + status = AE_BAD_DATA; + acpi_util_eval_error(handle, pathname, status); + goto end; + } + + /* Allocate list - CALLER MUST FREE! */ + list->count = package->package.count; + if (list->count > 10) { + return AE_NO_MEMORY; + } + /* TBD: dynamically allocate */ + /* + list->handles = kmalloc(sizeof(acpi_handle)*(list->count), GFP_KERNEL); + if (!list->handles) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + memset(list->handles, 0, sizeof(acpi_handle)*(list->count)); + */ + + /* Parse package data. */ + + for (i = 0; i < list->count; i++) { + + element = &(package->package.elements[i]); + + if (!element || (element->type != ACPI_TYPE_STRING)) { + status = AE_BAD_DATA; + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid element in package (not a device reference)\n")); + acpi_util_eval_error(handle, pathname, status); + break; + } + + /* Convert reference (e.g. "\_PR_.CPU_") to acpi_handle. */ + + status = acpi_get_handle(handle, element->string.pointer, + &(list->handles[i])); + if (ACPI_FAILURE(status)) { + status = AE_BAD_DATA; + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to resolve device reference [%s]\n", element->string.pointer)); + acpi_util_eval_error(handle, pathname, status); + break; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resolved reference [%s]->[%p]\n", element->string.pointer, list->handles[i])); + } + +end: + if (ACPI_FAILURE(status)) { + list->count = 0; + //kfree(list->handles); + } + + kfree(buffer.pointer); + + return_ACPI_STATUS(status); +} + + diff -Nur linux-2.4.19/drivers/block/blkpg.c linux-2.4.19-sgi211r3/drivers/block/blkpg.c --- linux-2.4.19/drivers/block/blkpg.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/block/blkpg.c Tue Dec 3 18:34:00 2002 @@ -39,6 +39,9 @@ #include +static int set_last_sector( kdev_t dev, const void *param ); +static int get_last_sector( kdev_t dev, const void *param ); + /* * What is the data describing a partition? * @@ -205,6 +208,16 @@ return -EINVAL; switch (cmd) { + case BLKGETLASTSECT: + return get_last_sector(dev, (char *)(arg)); + + case BLKSETLASTSECT: + if( is_read_only(dev) ) + return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return set_last_sector(dev, (char *)(arg)); + case BLKROSET: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -296,3 +309,209 @@ } EXPORT_SYMBOL(blk_ioctl); + + /********************* + * get_last_sector() + * + * Description: This function will read any inaccessible blocks at the end + * of a device + * Why: Normal read/write calls through the block layer will not read the + * last sector of an odd-size disk. + * parameters: + * dev: kdev_t -- which device to read + * param: a pointer to a userspace struct. The struct has these members: + * block: an int which denotes which block to return: + * 0 == Last block + * 1 == Last block - 1 + * n == Last block - n + * This is validated so that only values of + * <= ((total_sects + 1) % logical_block_size) || 0 + * are allowed. + * block_contents: a pointer to userspace char*, this is where we write + * returned blocks to. + * content_length: How big the userspace buffer is. + * return: + * 0 on success + * -ERRVAL on error. + *********************/ +int get_last_sector( kdev_t dev, const void *param ) +{ + struct buffer_head *bh; + struct gendisk *g; + int rc = 0; + unsigned int lastlba, readlba; + int orig_blksize = BLOCK_SIZE; + int hardblocksize; + + struct { + unsigned int block; + size_t content_length; + char *block_contents; + } blk_ioctl_parameter; + + if( !dev ) return -EINVAL; + + if(copy_from_user(&blk_ioctl_parameter, param, sizeof(blk_ioctl_parameter))) + return -EFAULT; + + g = get_gendisk( dev ); + + if( !g ) return -EINVAL; + + lastlba = g->part[MINOR(dev)].nr_sects; + + if( !lastlba ) return -EINVAL; + + hardblocksize = get_hardsect_size(dev); + if( ! hardblocksize ) hardblocksize = 512; + + /* Need to change the block size that the block layer uses */ + if (blksize_size[MAJOR(dev)]){ + orig_blksize = blksize_size[MAJOR(dev)][MINOR(dev)]; + } + + /* validate userspace input */ + if( blk_ioctl_parameter.block == 0 ) + goto good_params; + + /* so we don't divide by zero below */ + if(orig_blksize == 0) + return -EINVAL; + + if( blk_ioctl_parameter.block <= (lastlba % (orig_blksize / hardblocksize))) + goto good_params; + + return -EINVAL; + +good_params: + readlba = lastlba - blk_ioctl_parameter.block - 1; + + if (orig_blksize != hardblocksize) + set_blocksize(dev, hardblocksize); + + bh = bread(dev, readlba, hardblocksize); + if (!bh) { + /* We hit the end of the disk */ + printk(KERN_WARNING + "get_last_sector ioctl: bread returned NULL.\n"); + return -1; + } + + rc = copy_to_user(blk_ioctl_parameter.block_contents, bh->b_data, + (bh->b_size > blk_ioctl_parameter.content_length) ? + blk_ioctl_parameter.content_length : bh->b_size); + + brelse(bh); + + /* change block size back */ + if (orig_blksize != hardblocksize) + set_blocksize(dev, orig_blksize); + + return rc; +} + + /********************* + * set_last_sector() + * + * Description: This function will write to any inaccessible blocks at the end + * of a device + * Why: Normal read/write calls through the block layer will not read the + * last sector of an odd-size disk. + * parameters: + * dev: kdev_t -- which device to read + * sect: a pointer to a userspace struct. The struct has these members: + * block: an int which denotes which block to return: + * 0 == Last block + * 1 == Last block - 1 + * n == Last block - n + * This is validated so that only values of + * <= ((total_sects + 1) % logical_block_size) || 0 + * are allowed. + * block_contents: a pointer to userspace char*, this is where we write + * returned blocks to. + * content_length: How big the userspace buffer is. + * return: + * 0 on success + * -ERRVAL on error. + *********************/ +int set_last_sector( kdev_t dev, const void *param ) +{ + struct buffer_head *bh; + struct gendisk *g; + int rc = 0; + unsigned int lastlba, writelba; + int orig_blksize = BLOCK_SIZE; + int hardblocksize; + + struct { + unsigned int block; + size_t content_length; + char *block_contents; + } blk_ioctl_parameter; + + if( !dev ) return -EINVAL; + + if(copy_from_user(&blk_ioctl_parameter, param, sizeof(blk_ioctl_parameter))) + return -EFAULT; + + g = get_gendisk( dev ); + + if( !g ) return -EINVAL; + + lastlba = g->part[MINOR(dev)].nr_sects ; + + if( !lastlba ) return -EINVAL; + + hardblocksize = get_hardsect_size(dev); + if( ! hardblocksize ) hardblocksize = 512; + + /* Need to change the block size that the block layer uses */ + if (blksize_size[MAJOR(dev)]){ + orig_blksize = blksize_size[MAJOR(dev)][MINOR(dev)]; + } + + /* validate userspace input */ + if( blk_ioctl_parameter.block == 0 ) + goto good_params; + + /* so we don't divide by zero below */ + if(orig_blksize == 0) + return -EINVAL; + + if( blk_ioctl_parameter.block <= (lastlba % (orig_blksize / hardblocksize))) + goto good_params; + + return -EINVAL; + +good_params: + writelba = lastlba - blk_ioctl_parameter.block - 1; + + if (orig_blksize != hardblocksize) + set_blocksize(dev, hardblocksize); + + bh = bread(dev, writelba, hardblocksize); + if (!bh) { + /* We hit the end of the disk */ + printk(KERN_WARNING + "get_last_sector ioctl: getblk returned NULL.\n"); + return -1; + } + + copy_from_user(bh->b_data, blk_ioctl_parameter.block_contents, + (bh->b_size > blk_ioctl_parameter.content_length) ? + blk_ioctl_parameter.content_length : bh->b_size); + + mark_buffer_dirty(bh); + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + if (!buffer_uptodate(bh)) + rc=-1; + + brelse(bh); + + /* change block size back */ + if (orig_blksize != hardblocksize) + set_blocksize(dev, orig_blksize); + + return rc; +} diff -Nur linux-2.4.19/drivers/block/genhd.c linux-2.4.19-sgi211r3/drivers/block/genhd.c --- linux-2.4.19/drivers/block/genhd.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/block/genhd.c Thu Feb 6 16:27:15 2003 @@ -22,6 +22,7 @@ #include #include #include +#include static rwlock_t gendisk_lock; @@ -153,46 +154,74 @@ return error; } - #ifdef CONFIG_PROC_FS -int -get_partition_list(char *page, char **start, off_t offset, int count) +/* iterator */ +static void *part_start(struct seq_file *s, loff_t *ppos) { struct gendisk *gp; - struct hd_struct *hd; - char buf[64]; - int len, n; + loff_t pos = *ppos; - len = sprintf(page, "major minor #blocks name\n\n"); - read_lock(&gendisk_lock); - for (gp = gendisk_head; gp; gp = gp->next) { - for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) { - if (gp->part[n].nr_sects == 0) - continue; - - hd = &gp->part[n]; disk_round_stats(hd); - len += sprintf(page + len, - "%4d %4d %10d %s\n", gp->major, - n, gp->sizes[n], disk_name(gp, n, buf)); - - if (len < offset) - offset -= len, len = 0; - else if (len >= offset + count) - goto out; + for (gp = gendisk_head; gp; gp = gp->next) + if (!pos--) + return gp; + return NULL; +} + +static void *part_next(struct seq_file *s, void *v, loff_t *pos) +{ + ++*pos; + return ((struct gendisk *)v)->next; +} + +static void part_stop(struct seq_file *s, void *v) +{ + read_unlock(&gendisk_lock); +} + +static int part_show(struct seq_file *s, void *v) +{ + struct gendisk *gp = v; + char buf[64]; + int n; + + if (gp == gendisk_head) { + seq_puts(s, "major minor #blocks name" + " rio rmerge rsect ruse wio wmerge " + "wsect wuse running use aveq" + "\n\n"); + } + + /* show the full disk and all non-0 size partitions of it */ + for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) { + if (gp->part[n].nr_sects) { + struct hd_struct *hd = &gp->part[n]; + + disk_round_stats(hd); + seq_printf(s, "%4d %4d %10d %s " + "%d %d %d %d %d %d %d %d %d %d %d\n", + gp->major, n, gp->sizes[n], + disk_name(gp, n, buf), + hd->rd_ios, hd->rd_merges, +#define MSEC(x) ((x) * 1000 / HZ) + hd->rd_sectors, MSEC(hd->rd_ticks), + hd->wr_ios, hd->wr_merges, + hd->wr_sectors, MSEC(hd->wr_ticks), + hd->ios_in_flight, MSEC(hd->io_ticks), + MSEC(hd->aveq)); } } -out: - read_unlock(&gendisk_lock); - *start = page + offset; - len -= offset; - if (len < 0) - len = 0; - return len > count ? count : len; + return 0; } -#endif +struct seq_operations partitions_op = { + .start = part_start, + .next = part_next, + .stop = part_stop, + .show = part_show, +}; +#endif extern int blk_dev_init(void); extern int net_dev_init(void); diff -Nur linux-2.4.19/drivers/block/ll_rw_blk.c linux-2.4.19-sgi211r3/drivers/block/ll_rw_blk.c --- linux-2.4.19/drivers/block/ll_rw_blk.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/block/ll_rw_blk.c Wed Oct 16 14:02:58 2002 @@ -531,6 +531,7 @@ static struct request *__get_request_wait(request_queue_t *q, int rw) { register struct request *rq; + unsigned long start_wait = jiffies; DECLARE_WAITQUEUE(wait, current); generic_unplug_device(q); @@ -545,6 +546,7 @@ } while (rq == NULL); remove_wait_queue(&q->wait_for_requests[rw], &wait); current->state = TASK_RUNNING; + current->bwtime += jiffies - start_wait; return rq; } @@ -587,9 +589,11 @@ if (rw == READ) { kstat.dk_drive_rio[major][index] += new_io; kstat.dk_drive_rblk[major][index] += nr_sectors; + current->rblk += nr_sectors; } else if (rw == WRITE) { kstat.dk_drive_wio[major][index] += new_io; kstat.dk_drive_wblk[major][index] += nr_sectors; + current->wblk += nr_sectors; } else printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n"); } @@ -1110,6 +1114,9 @@ int count = bh->b_size >> 9; if (!test_bit(BH_Lock, &bh->b_state)) + BUG(); + + if (buffer_delay(bh) || !buffer_mapped(bh)) BUG(); set_bit(BH_Req, &bh->b_state); diff -Nur linux-2.4.19/drivers/block/loop.c linux-2.4.19-sgi211r3/drivers/block/loop.c --- linux-2.4.19/drivers/block/loop.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/block/loop.c Fri Nov 1 12:55:48 2002 @@ -39,6 +39,10 @@ * Support up to 256 loop devices * Heinz Mauelshagen , Feb 2002 * + * Changing of backing file/device during operation for read-only loopback. + * Jakub Jelinek , Mar 31, 2000 + * AV: ported the above to Jens' variant, Jan 2001 + * * Still To Fix: * - Advisory locking is ignored here. * - Should use an own CAP_* category instead of CAP_SYS_ADMIN @@ -78,6 +82,8 @@ #define MAJOR_NR LOOP_MAJOR +#define LOOP_BH_Set 7 /* it's ugly, but... */ + static int max_loop = 8; static struct loop_device *loop_dev; static int *loop_sizes; @@ -266,12 +272,23 @@ return size; } +static inline void lo_drop(struct loop_device *lo, int set) +{ + spin_lock_irq(&lo->lo_lock); + if (!--lo->lo_pending_reads[set] && set !=lo->lo_current && + lo->lo_change) + up(lo->lo_change); + spin_unlock_irq(&lo->lo_lock); +} + + static int lo_receive(struct loop_device *lo, struct buffer_head *bh, int bsize, loff_t pos) { struct lo_read_data cookie; read_descriptor_t desc; struct file *file; + int lo_current; cookie.lo = lo; cookie.data = bh->b_data; @@ -281,9 +298,12 @@ desc.buf = (char*)&cookie; desc.error = 0; spin_lock_irq(&lo->lo_lock); + lo_current = lo->lo_current; + lo->lo_pending_reads[lo_current]++; file = lo->lo_backing_file; spin_unlock_irq(&lo->lo_lock); do_generic_file_read(file, &pos, &desc, lo_read_actor); + lo_drop(lo, lo_current); return desc.error; } @@ -400,9 +420,11 @@ } static struct buffer_head *loop_get_buffer(struct loop_device *lo, - struct buffer_head *rbh) + struct buffer_head *rbh, + int rw) { struct buffer_head *bh; + int lo_current; /* * for xfer_funcs that can operate on the same bh, do that @@ -448,8 +470,12 @@ out_bh: bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9); spin_lock_irq(&lo->lo_lock); + lo_current = lo->lo_current; + if (rw != WRITE) + lo->lo_pending_reads[lo_current]++; bh->b_rdev = lo->lo_device; spin_unlock_irq(&lo->lo_lock); + bh->b_state |= (lo_current << LOOP_BH_Set); return bh; } @@ -504,7 +530,7 @@ /* * piggy old buffer on original, and submit for I/O */ - bh = loop_get_buffer(lo, rbh); + bh = loop_get_buffer(lo, rbh, rw); IV = loop_get_iv(lo, rbh->b_rsector); if (rw == WRITE) { set_bit(BH_Dirty, &bh->b_state); @@ -548,6 +574,7 @@ bh->b_size, IV); rbh->b_end_io(rbh, !ret); + lo_drop(lo, (bh->b_state >> LOOP_BH_Set) & 1); loop_put_buffer(bh); } } @@ -573,8 +600,7 @@ flush_signals(current); spin_unlock_irq(¤t->sigmask_lock); - current->policy = SCHED_OTHER; - current->nice = -20; + set_user_nice(current, -20); spin_lock_irq(&lo->lo_lock); lo->lo_state = Lo_bound; @@ -616,8 +642,7 @@ return 0; } -static int loop_set_fd(struct loop_device *lo, struct file *lo_file, kdev_t dev, - unsigned int arg) +static int loop_change_fd(struct loop_device *lo, struct file *lo_file, kdev_t dev, unsigned int arg, int set) { struct file *file; struct inode *inode; @@ -626,11 +651,18 @@ int error; int bs; - MOD_INC_USE_COUNT; + if(set) { + MOD_INC_USE_COUNT; - error = -EBUSY; - if (lo->lo_state != Lo_unbound) - goto out; + error = -EBUSY; + if (lo->lo_state != Lo_unbound) + goto out; + } else { + /* Changing backing file is only allowed for read-only devices now. */ + error = -EINVAL; + if (lo->lo_state != Lo_bound || !(lo->lo_flags & LO_FLAGS_READ_ONLY)) + goto out; + } error = -EBADF; file = fget(arg); @@ -669,41 +701,83 @@ get_file(file); - if (IS_RDONLY (inode) || is_read_only(lo_device) - || !(lo_file->f_mode & FMODE_WRITE)) - lo_flags |= LO_FLAGS_READ_ONLY; - - set_device_ro(dev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); - - lo->lo_device = lo_device; - lo->lo_flags = lo_flags; - lo->lo_backing_file = file; - lo->transfer = NULL; - lo->ioctl = NULL; - figure_loop_size(lo); - lo->old_gfp_mask = inode->i_mapping->gfp_mask; - inode->i_mapping->gfp_mask = GFP_NOIO; - - bs = 0; - if (blksize_size[MAJOR(lo_device)]) - bs = blksize_size[MAJOR(lo_device)][MINOR(lo_device)]; - if (!bs) - bs = BLOCK_SIZE; - - set_blocksize(dev, bs); - - lo->lo_bh = lo->lo_bhtail = NULL; - kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - down(&lo->lo_sem); - - fput(file); - return 0; - + if (set) { + if (IS_RDONLY (inode) || is_read_only(lo_device) + || !(lo_file->f_mode & FMODE_WRITE)) + lo_flags |= LO_FLAGS_READ_ONLY; + + set_device_ro(dev, (lo_flags & LO_FLAGS_READ_ONLY)!=0); + + lo->lo_current = 0; + lo->lo_pending_reads [0] = 0; + lo->lo_pending_reads [1] = 0; + lo->lo_device = lo_device; + lo->lo_flags = lo_flags; + lo->lo_backing_file = file; + lo->lo_change = NULL; + lo->transfer = NULL; + lo->ioctl = NULL; + figure_loop_size(lo); + lo->old_gfp_mask = inode->i_mapping->gfp_mask; + inode->i_mapping->gfp_mask = GFP_NOIO; + + bs = 0; + if (blksize_size[MAJOR(inode->i_rdev)]) + bs = blksize_size[MAJOR(inode->i_rdev)][MINOR(inode->i_rdev)]; + if (!bs) + bs = BLOCK_SIZE; + + lo->lo_blksize = bs; + set_blocksize(dev, bs); + + lo->lo_bh = lo->lo_bhtail = NULL; + kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + down(&lo->lo_sem); + } else { + int size = compute_loop_size(lo, file->f_dentry, lo_device); + struct semaphore sem; + kdev_t old_device; + struct file *old_backing_file; + + error = -EINVAL; + if (size != loop_sizes[lo->lo_number]) + /* Loop size has changed. Don't allow it. */ + goto out_put_all; + + init_MUTEX(&sem); + + spin_lock_irq(&lo->lo_lock); + if (lo->lo_pending_reads [lo->lo_current]) { + lo->lo_current ^= 1; + lo->lo_change = &sem; + down(&sem); + } + old_device = lo->lo_device; + old_backing_file = lo->lo_backing_file; + lo->lo_device = lo_device; + lo->lo_backing_file = file; + lo->lo_flags = lo_flags | LO_FLAGS_READ_ONLY; + spin_unlock_irq(&lo->lo_lock); + + /* Wait until there are no more outstanding requests to the + old backing file/device */ + down(&sem); + lo->lo_change = NULL; + fput(old_backing_file); + error = 0; + } + + out_put_all: + fput(file); + return 0; + out_putf: - fput(file); + fput(file); + out: - MOD_DEC_USE_COUNT; - return error; + if (set) + MOD_DEC_USE_COUNT; + return error; } static int loop_release_xfer(struct loop_device *lo) @@ -866,7 +940,10 @@ down(&lo->lo_ctl_mutex); switch (cmd) { case LOOP_SET_FD: - err = loop_set_fd(lo, file, inode->i_rdev, arg); + err = loop_change_fd(lo, file, inode->i_rdev, arg, 1); + break; + case LOOP_CHANGE_FD: + err = loop_change_fd(lo, file, inode->i_rdev, arg, 0); break; case LOOP_CLR_FD: err = loop_clr_fd(lo, inode->i_bdev); diff -Nur linux-2.4.19/drivers/cdrom/Makefile linux-2.4.19-sgi211r3/drivers/cdrom/Makefile --- linux-2.4.19/drivers/cdrom/Makefile Fri Dec 29 14:07:21 2000 +++ linux-2.4.19-sgi211r3/drivers/cdrom/Makefile Thu Aug 29 11:09:51 2002 @@ -27,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_IDECD) += cdrom.o obj-$(CONFIG_BLK_DEV_SR) += cdrom.o obj-$(CONFIG_PARIDE_PCD) += cdrom.o +obj-$(CONFIG_XSCSI_MMSC) += cdrom.o obj-$(CONFIG_AZTCD) += aztcd.o obj-$(CONFIG_CDU31A) += cdu31a.o cdrom.o diff -Nur linux-2.4.19/drivers/char/Config.in linux-2.4.19-sgi211r3/drivers/char/Config.in --- linux-2.4.19/drivers/char/Config.in Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/Config.in Wed Oct 16 14:02:58 2002 @@ -13,6 +13,9 @@ bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE if [ "$CONFIG_IA64" = "y" ]; then bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP + if [ "$CONFIG_ACPI" = "y" ]; then + bool 'Support for serial ports described by ACPI table' CONFIG_SERIAL_ACPI + fi fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL @@ -261,6 +264,7 @@ bool ' ALI chipset support' CONFIG_AGP_ALI bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS if [ "$CONFIG_IA64" = "y" ]; then + bool ' Intel 460GX support' CONFIG_AGP_I460 bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 fi fi diff -Nur linux-2.4.19/drivers/char/Makefile linux-2.4.19-sgi211r3/drivers/char/Makefile --- linux-2.4.19/drivers/char/Makefile Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/Makefile Wed Oct 16 14:02:58 2002 @@ -108,6 +108,13 @@ endif endif +ifeq ($(CONFIG_IA64_SGI_SN),y) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = sgi-l1_protocol.o +endif + ifeq ($(CONFIG_DECSTATION),y) KEYMAP = KEYBD = @@ -138,6 +145,7 @@ obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) +obj-$(CONFIG_SERIAL_ACPI) += acpi_serial.o obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o obj-$(CONFIG_SERIAL_21285) += serial_21285.o obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o @@ -152,6 +160,7 @@ obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o +obj-$(CONFIG_SIM_SERIAL) += simserial.o obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o diff -Nur linux-2.4.19/drivers/char/acpi_serial.c linux-2.4.19-sgi211r3/drivers/char/acpi_serial.c --- linux-2.4.19/drivers/char/acpi_serial.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/char/acpi_serial.c Fri Nov 30 09:08:26 2001 @@ -0,0 +1,203 @@ +/* + * linux/drivers/char/acpi_serial.c + * + * Copyright (C) 2000 Hewlett-Packard Co. + * Copyright (C) 2000 Khalid Aziz + * + * Detect and initialize the headless console serial port defined in + * SPCR table and debug serial port defined in DBGP table + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ + +#undef SERIAL_DEBUG_ACPI + +/* + * Query ACPI tables for a debug and a headless console serial + * port. If found, add them to rs_table[]. A pointer to either SPCR + * or DBGP table is passed as parameter. This function should be called + * before serial_console_init() is called to make sure the SPCR serial + * console will be available for use. IA-64 kernel calls this function + * from within acpi.c when it encounters SPCR or DBGP tables as it parses + * the ACPI 2.0 tables during bootup. + * + */ +void __init setup_serial_acpi(void *tablep) +{ + acpi_ser_t *acpi_ser_p; + struct serial_struct serial_req; + unsigned long iobase; + int global_sys_irq; + +#ifdef SERIAL_DEBUG_ACPI + printk("Entering setup_serial_acpi()\n"); +#endif + + /* Now get the table */ + if (tablep == NULL) { + return; + } + + acpi_ser_p = (acpi_ser_t *)tablep; + + /* + * Perform a sanity check on the table. Table should have a + * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes + * long. + */ + if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, + ACPI_SIG_LEN) != 0) && + (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, + ACPI_SIG_LEN) != 0)) { + return; + } + if (acpi_ser_p->length < 52) { + return; + } + + iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl; + global_sys_irq = (acpi_ser_p->global_int[3] << 24) | + (acpi_ser_p->global_int[2] << 16) | + (acpi_ser_p->global_int[1] << 8) | + acpi_ser_p->global_int[0]; + +#ifdef SERIAL_DEBUG_ACPI + printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p); + printk(" sig = '%c%c%c%c'\n", + acpi_ser_p->signature[0], + acpi_ser_p->signature[1], + acpi_ser_p->signature[2], + acpi_ser_p->signature[3]); + printk(" length = %d\n", acpi_ser_p->length); + printk(" Rev = %d\n", acpi_ser_p->rev); + printk(" Interface type = %d\n", acpi_ser_p->intfc_type); + printk(" Base address = 0x%lX\n", iobase); + printk(" IRQ = %d\n", acpi_ser_p->irq); + printk(" Global System Int = %d\n", global_sys_irq); + printk(" Baud rate = "); + switch (acpi_ser_p->baud) { + case ACPI_SERIAL_BAUD_9600: + printk("9600\n"); + break; + + case ACPI_SERIAL_BAUD_19200: + printk("19200\n"); + break; + + case ACPI_SERIAL_BAUD_57600: + printk("57600\n"); + break; + + case ACPI_SERIAL_BAUD_115200: + printk("115200\n"); + break; + + default: + printk("Huh (%d)\n", acpi_ser_p->baud); + break; + + } + if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { + printk(" PCI serial port:\n"); + printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n", + acpi_ser_p->pci_bus, acpi_ser_p->pci_dev, + acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id); + } +#endif + + /* + * Now build a serial_req structure to update the entry in + * rs_table for the headless console port. + */ + switch (acpi_ser_p->intfc_type) { + case ACPI_SERIAL_INTFC_16550: + serial_req.type = PORT_16550; + serial_req.baud_base = BASE_BAUD; + break; + + case ACPI_SERIAL_INTFC_16450: + serial_req.type = PORT_16450; + serial_req.baud_base = BASE_BAUD; + break; + + default: + serial_req.type = PORT_UNKNOWN; + break; + } + if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, + ACPI_SIG_LEN) == 0) { + serial_req.line = ACPI_SERIAL_CONSOLE_PORT; + } + else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, + ACPI_SIG_LEN) == 0) { + serial_req.line = ACPI_SERIAL_DEBUG_PORT; + } + /* + * Check if this is an I/O mapped address or a memory mapped address + */ + if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) { + serial_req.port = 0; + serial_req.port_high = 0; + serial_req.iomem_base = (void *)ioremap(iobase, 64); + serial_req.io_type = SERIAL_IO_MEM; + } + else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) { + serial_req.port = (unsigned long) iobase & 0xffffffff; + serial_req.port_high = (unsigned long)(((u64)iobase) >> 32); + serial_req.iomem_base = NULL; + serial_req.io_type = SERIAL_IO_PORT; + } + else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { + printk("WARNING: No support for PCI serial console\n"); + return; + } + + /* + * If the table does not have IRQ information, use 0 for IRQ. + * This will force rs_init() to probe for IRQ. + */ + if (acpi_ser_p->length < 53) { + serial_req.irq = 0; + } + else { + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF | + ASYNC_AUTO_IRQ; + if (acpi_ser_p->int_type & + (ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) { + serial_req.irq = global_sys_irq; + } + else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) { + serial_req.irq = acpi_ser_p->irq; + } + else { + /* + * IRQ type not being set would mean UART will + * run in polling mode. Do not probe for IRQ in + * that case. + */ + serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF; + } + } + + serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; + serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; + serial_req.iomem_reg_shift = 0; + if (early_serial_setup(&serial_req) < 0) { + printk("early_serial_setup() for ACPI serial console port failed\n"); + return; + } + +#ifdef SERIAL_DEBUG_ACPI + printk("Leaving setup_serial_acpi()\n"); +#endif +} diff -Nur linux-2.4.19/drivers/char/agp/agp.h linux-2.4.19-sgi211r3/drivers/char/agp/agp.h --- linux-2.4.19/drivers/char/agp/agp.h Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/agp/agp.h Wed Oct 16 14:02:58 2002 @@ -84,8 +84,8 @@ void *dev_private_data; struct pci_dev *dev; gatt_mask *masks; - unsigned long *gatt_table; - unsigned long *gatt_table_real; + u32 *gatt_table; + u32 *gatt_table_real; unsigned long scratch_page; unsigned long gart_bus_addr; unsigned long gatt_bus_addr; @@ -99,7 +99,6 @@ int needs_scratch_page; int aperture_size_idx; int num_aperture_sizes; - int num_of_masks; int capndx; int cant_use_aperture; @@ -111,6 +110,7 @@ void (*cleanup) (void); void (*tlb_flush) (agp_memory *); unsigned long (*mask_memory) (unsigned long, int); + unsigned long (*unmask_memory) (unsigned long); void (*cache_flush) (void); int (*create_gatt_table) (void); int (*free_gatt_table) (void); @@ -229,6 +229,9 @@ #ifndef PCI_DEVICE_ID_INTEL_82443GX_1 #define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 #endif +#ifndef PCI_DEVICE_ID_INTEL_460GX +#define PCI_DEVICE_ID_INTEL_460GX 0x84ea +#endif #ifndef PCI_DEVICE_ID_AMD_IRONGATE_0 #define PCI_DEVICE_ID_AMD_IRONGATE_0 0x7006 #endif @@ -276,6 +279,15 @@ #define INTEL_AGPCTRL 0xb0 #define INTEL_NBXCFG 0x50 #define INTEL_ERRSTS 0x91 + +/* Intel 460GX Registers */ +#define INTEL_I460_APBASE 0x10 +#define INTEL_I460_BAPBASE 0x98 +#define INTEL_I460_GXBCTL 0xa0 +#define INTEL_I460_AGPSIZ 0xa2 +#define INTEL_I460_ATTBASE 0xfe200000 +#define INTEL_I460_GATT_VALID (1UL << 24) +#define INTEL_I460_GATT_COHERENT (1UL << 25) /* intel i830 registers */ #define I830_GMCH_CTRL 0x52 diff -Nur linux-2.4.19/drivers/char/agp/agpgart_be.c linux-2.4.19-sgi211r3/drivers/char/agp/agpgart_be.c --- linux-2.4.19/drivers/char/agp/agpgart_be.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/agp/agpgart_be.c Wed Oct 16 14:02:58 2002 @@ -22,6 +22,7 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * 460GX support by Chris Ahna */ #include #include @@ -43,6 +44,9 @@ #include #include #include +#include +#include +#include #include #include "agp.h" @@ -60,7 +64,7 @@ EXPORT_SYMBOL(agp_backend_release); static void flush_cache(void); - + static struct agp_bridge_data agp_bridge; static int agp_try_unsupported __initdata = 0; @@ -205,19 +209,54 @@ agp_bridge.free_by_type(curr); return; } - if (curr->page_count != 0) { - for (i = 0; i < curr->page_count; i++) { - curr->memory[i] &= ~(0x00000fff); - agp_bridge.agp_destroy_page((unsigned long) - phys_to_virt(curr->memory[i])); + if(agp_bridge.cant_use_aperture == 0) { + if (curr->page_count != 0) { + for (i = 0; i < curr->page_count; i++) { + agp_bridge.agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[i])); + } } + } else { + vfree(curr->vmptr); } + agp_free_key(curr->key); vfree(curr->memory); kfree(curr); MOD_DEC_USE_COUNT; } +#define IN_VMALLOC(_x) (((_x) >= VMALLOC_START) && ((_x) < VMALLOC_END)) + +/* + * Look up and return the pte corresponding to addr. We only do this for + * agp_ioremap'ed addresses. + */ +static pte_t * agp_lookup_pte(unsigned long addr) { + + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + + if(!IN_VMALLOC(addr)) + return NULL; + + dir = pgd_offset_k(addr); + pmd = pmd_offset(dir, addr); + + if(pmd) { + pte = pte_offset(pmd, addr); + + if(pte) { + return pte; + } else { + return NULL; + } + } else { + return NULL; + } +} + #define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) agp_memory *agp_allocate_memory(size_t page_count, u32 type) @@ -247,24 +286,53 @@ scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; new = agp_create_memory(scratch_pages); - if (new == NULL) { MOD_DEC_USE_COUNT; return NULL; } - for (i = 0; i < page_count; i++) { - new->memory[i] = agp_bridge.agp_alloc_page(); - if (new->memory[i] == 0) { - /* Free this structure */ - agp_free_memory(new); + if(agp_bridge.cant_use_aperture == 0) { + for (i = 0; i < page_count; i++) { + new->memory[i] = agp_bridge.agp_alloc_page(); + + if (new->memory[i] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[i] = virt_to_phys((void *) new->memory[i]); + new->page_count++; + } + } else { + void *vmblock; + unsigned long vaddr, paddr; + pte_t *pte; + + vmblock = __vmalloc(page_count << PAGE_SHIFT, GFP_KERNEL, +#if 0/*XXX non-coherent AGP DMA*/ + pgprot_writecombine(PAGE_KERNEL)); +#else + PAGE_KERNEL); +#endif + if(vmblock == NULL) { + MOD_DEC_USE_COUNT; return NULL; } - new->memory[i] = - agp_bridge.mask_memory( - virt_to_phys((void *) new->memory[i]), - type); - new->page_count++; + + new->vmptr = vmblock; + vaddr = (unsigned long) vmblock; + + for(i = 0; i < page_count; i++, vaddr += PAGE_SIZE) { + pte = agp_lookup_pte(vaddr); + if(pte == NULL) { + MOD_DEC_USE_COUNT; + return NULL; + } + paddr = __pa(page_address(pte_page(*pte))); + new->memory[i] = paddr; + } + + new->page_count = page_count; } return new; @@ -307,9 +375,6 @@ void agp_copy_info(agp_kern_info * info) { - unsigned long page_mask = 0; - int i; - memset(info, 0, sizeof(agp_kern_info)); if (agp_bridge.type == NOT_SUPPORTED) { info->chipset = agp_bridge.type; @@ -325,11 +390,7 @@ info->max_memory = agp_bridge.max_memory_agp; info->current_memory = atomic_read(&agp_bridge.current_memory_agp); info->cant_use_aperture = agp_bridge.cant_use_aperture; - - for(i = 0; i < agp_bridge.num_of_masks; i++) - page_mask |= agp_bridge.mask_memory(page_mask, i); - - info->page_mask = ~page_mask; + info->page_mask = ~0UL; } /* End - Routine to copy over information structure */ @@ -353,12 +414,13 @@ curr->is_flushed = TRUE; } ret_val = agp_bridge.insert_memory(curr, pg_start, curr->type); - + if (ret_val != 0) { return ret_val; } curr->is_bound = TRUE; curr->pg_start = pg_start; + return 0; } @@ -377,6 +439,7 @@ if (ret_val != 0) { return ret_val; } + curr->is_bound = FALSE; curr->pg_start = 0; return 0; @@ -387,9 +450,9 @@ /* * Driver routines - start * Currently this module supports the following chipsets: - * i810, i815, 440lx, 440bx, 440gx, i830, i840, i845, i850, i860, via vp3, + * i810, i815, 440lx, 440bx, 440gx, 460gx, i830, i840, i845, i850, i860, via vp3, * via mvp3, via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541, - * and generic support for the SiS chipsets. + * chipsets. */ /* Generic Agp routines - Start */ @@ -397,7 +460,7 @@ static void agp_generic_agp_enable(u32 mode) { struct pci_dev *device = NULL; - u32 command, scratch, cap_id; + u32 command, scratch; u8 cap_ptr; pci_read_config_dword(agp_bridge.dev, @@ -480,6 +543,7 @@ * command registers. */ + pci_for_each_dev(device) { cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) @@ -581,7 +645,7 @@ for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) SetPageReserved(page); - agp_bridge.gatt_table_real = (unsigned long *) table; + agp_bridge.gatt_table_real = (u32 *) table; CACHE_FLUSH(); agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), (PAGE_SIZE * (1 << page_order))); @@ -713,7 +777,8 @@ mem->is_flushed = TRUE; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - agp_bridge.gatt_table[j] = mem->memory[i]; + agp_bridge.gatt_table[j] = + agp_bridge.mask_memory(mem->memory[i], mem->type); } agp_bridge.tlb_flush(mem); @@ -799,6 +864,11 @@ agp_bridge.agp_enable(mode); } +static unsigned long agp_generic_unmask_memory(unsigned long addr) +{ + return addr & ~(0x00000fff); +} + /* End - Generic Agp routines */ #ifdef CONFIG_AGP_I810 @@ -949,7 +1019,8 @@ CACHE_FLUSH(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (j * 4), mem->memory[i]); + I810_PTE_BASE + (j * 4), + agp_bridge.mask_memory(mem->memory[i], mem->type)); } CACHE_FLUSH(); @@ -1015,10 +1086,7 @@ agp_free_memory(new); return NULL; } - new->memory[0] = - agp_bridge.mask_memory( - virt_to_phys((void *) new->memory[0]), - type); + new->memory[0] = virt_to_phys((void *) new->memory[0]); new->page_count = 1; new->num_scratch_pages = 1; new->type = AGP_PHYS_MEMORY; @@ -1052,7 +1120,6 @@ intel_i810_private.i810_dev = i810_dev; agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 2; agp_bridge.aperture_sizes = (void *) intel_i810_sizes; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -1063,6 +1130,7 @@ agp_bridge.cleanup = intel_i810_cleanup; agp_bridge.tlb_flush = intel_i810_tlbflush; agp_bridge.mask_memory = intel_i810_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = intel_i810_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; @@ -1255,7 +1323,8 @@ CACHE_FLUSH(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]); + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), + agp_bridge.mask_memory(mem->memory[i], mem->type)); CACHE_FLUSH(); @@ -1316,7 +1385,7 @@ return(NULL); } - nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) nw->memory[0]),type); + nw->memory[0] = virt_to_phys((void *) nw->memory[0]); nw->page_count = 1; nw->num_scratch_pages = 1; nw->type = AGP_PHYS_MEMORY; @@ -1332,7 +1401,6 @@ intel_i830_private.i830_dev = i830_dev; agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 3; agp_bridge.aperture_sizes = (void *) intel_i830_sizes; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -1367,9 +1435,638 @@ #endif /* CONFIG_AGP_I810 */ - #ifdef CONFIG_AGP_INTEL +#ifdef CONFIG_AGP_I460 -#endif /* CONFIG_AGP_I810 */ +/* BIOS configures the chipset so that one of two apbase registers are used */ +static u8 intel_i460_dynamic_apbase = 0x10; + +/* 460 supports multiple GART page sizes, so GART pageshift is dynamic */ +static u8 intel_i460_pageshift = 12; +static u32 intel_i460_pagesize; + +/* Keep track of which is larger, chipset or kernel page size. */ +static u32 intel_i460_cpk = 1; + +/* Structure for tracking partial use of 4MB GART pages */ +static u32 **i460_pg_detail = NULL; +static u32 *i460_pg_count = NULL; + +#define I460_CPAGES_PER_KPAGE (PAGE_SIZE >> intel_i460_pageshift) +#define I460_KPAGES_PER_CPAGE ((1 << intel_i460_pageshift) >> PAGE_SHIFT) + +#define I460_SRAM_IO_DISABLE (1 << 4) +#define I460_BAPBASE_ENABLE (1 << 3) +#define I460_AGPSIZ_MASK 0x7 +#define I460_4M_PS (1 << 1) + +#define log2(x) ffz(~(x)) + +static int intel_i460_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + /* Determine the GART page size */ + pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp); + intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12; + intel_i460_pagesize = 1UL << intel_i460_pageshift; + + values = A_SIZE_8(agp_bridge.aperture_sizes); + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); + + /* Exit now if the IO drivers for the GART SRAMS are turned off */ + if(temp & I460_SRAM_IO_DISABLE) { + printk("[agpgart] GART SRAMS disabled on 460GX chipset\n"); + printk("[agpgart] AGPGART operation not possible\n"); + return 0; + } + + /* Make sure we don't try to create an 2 ^ 23 entry GATT */ + if((intel_i460_pageshift == 0) && ((temp & I460_AGPSIZ_MASK) == 4)) { + printk("[agpgart] We can't have a 32GB aperture with 4KB" + " GART pages\n"); + return 0; + } + + /* Determine the proper APBASE register */ + if(temp & I460_BAPBASE_ENABLE) + intel_i460_dynamic_apbase = INTEL_I460_BAPBASE; + else intel_i460_dynamic_apbase = INTEL_I460_APBASE; + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + + /* + * Dynamically calculate the proper num_entries and page_order + * values for the define aperture sizes. Take care not to + * shift off the end of values[i].size. + */ + values[i].num_entries = (values[i].size << 8) >> + (intel_i460_pageshift - 12); + values[i].page_order = log2((sizeof(u32)*values[i].num_entries) + >> PAGE_SHIFT); + } + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + /* Neglect control bits when matching up size_value */ + if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +/* There isn't anything to do here since 460 has no GART TLB. */ +static void intel_i460_tlb_flush(agp_memory * mem) +{ + return; +} + +/* + * This utility function is needed to prevent corruption of the control bits + * which are stored along with the aperture size in 460's AGPSIZ register + */ +static void intel_i460_write_agpsiz(u8 size_value) +{ + u8 temp; + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp); + pci_write_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, + ((temp & ~I460_AGPSIZ_MASK) | size_value)); +} + +static void intel_i460_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + intel_i460_write_agpsiz(previous_size->size_value); + + if(intel_i460_cpk == 0) + { + vfree(i460_pg_detail); + vfree(i460_pg_count); + } +} + + +/* Control bits for Out-Of-GART coherency and Burst Write Combining */ +#define I460_GXBCTL_OOG (1UL << 0) +#define I460_GXBCTL_BWC (1UL << 2) + +static int intel_i460_configure(void) +{ + union { + u32 small[2]; + u64 large; + } temp; + u8 scratch; + int i; + + aper_size_info_8 *current_size; + + temp.large = 0; + + current_size = A_SIZE_8(agp_bridge.current_size); + intel_i460_write_agpsiz(current_size->size_value); + + /* + * Do the necessary rigmarole to read all eight bytes of APBASE. + * This has to be done since the AGP aperture can be above 4GB on + * 460 based systems. + */ + pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase, + &(temp.small[0])); + pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase + 4, + &(temp.small[1])); + + /* Clear BAR control bits */ + agp_bridge.gart_bus_addr = temp.large & ~((1UL << 3) - 1); + + pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &scratch); + pci_write_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, + (scratch & 0x02) | I460_GXBCTL_OOG | I460_GXBCTL_BWC); + + /* + * Initialize partial allocation trackers if a GART page is bigger than + * a kernel page. + */ + if(I460_CPAGES_PER_KPAGE >= 1) { + intel_i460_cpk = 1; + } else { + intel_i460_cpk = 0; + + i460_pg_detail = (void *) vmalloc(sizeof(*i460_pg_detail) * + current_size->num_entries); + i460_pg_count = (void *) vmalloc(sizeof(*i460_pg_count) * + current_size->num_entries); + + for (i = 0; i < current_size->num_entries; i++) { + i460_pg_count[i] = 0; + i460_pg_detail[i] = NULL; + } + } + + return 0; +} + +static int intel_i460_create_gatt_table(void) { + + char *table; + int i; + int page_order; + int num_entries; + void *temp; + unsigned int read_back; + + /* + * Load up the fixed address of the GART SRAMS which hold our + * GATT table. + */ + table = (char *) __va(INTEL_I460_ATTBASE); + + temp = agp_bridge.current_size; + page_order = A_SIZE_8(temp)->page_order; + num_entries = A_SIZE_8(temp)->num_entries; + + agp_bridge.gatt_table_real = (u32 *) table; + agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), + (PAGE_SIZE * (1 << page_order))); + agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real); + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = 0; + } + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[i - 1]; + + return 0; +} + +static int intel_i460_free_gatt_table(void) +{ + int num_entries; + int i; + void *temp; + unsigned int read_back; + + temp = agp_bridge.current_size; + + num_entries = A_SIZE_8(temp)->num_entries; + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = 0; + } + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[i - 1]; + + iounmap(agp_bridge.gatt_table); + + return 0; +} + +/* These functions are called when PAGE_SIZE exceeds the GART page size */ + +static int intel_i460_insert_memory_cpk(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, k, num_entries; + void *temp; + unsigned long paddr; + unsigned int read_back; + + /* + * The rest of the kernel will compute page offsets in terms of + * PAGE_SIZE. + */ + pg_start = I460_CPAGES_PER_KPAGE * pg_start; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + if((pg_start + I460_CPAGES_PER_KPAGE * mem->page_count) > num_entries) { + printk("[agpgart] Looks like we're out of AGP memory\n"); + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count)) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + j++; + } + +#if 0 + /* not necessary since 460 GART is operated in coherent mode... */ + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } +#endif + + for (i = 0, j = pg_start; i < mem->page_count; i++) { + + paddr = mem->memory[i]; + + for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, paddr += intel_i460_pagesize) + agp_bridge.gatt_table[j] = (unsigned int) + agp_bridge.mask_memory(paddr, mem->type); + } + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[j - 1]; + + return 0; +} + +static int intel_i460_remove_memory_cpk(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned int read_back; + + pg_start = I460_CPAGES_PER_KPAGE * pg_start; + + for (i = pg_start; i < (pg_start + I460_CPAGES_PER_KPAGE * + mem->page_count); i++) + agp_bridge.gatt_table[i] = 0; + + /* + * The 460 spec says we have to read the last location written to + * make sure that all writes have taken effect + */ + read_back = agp_bridge.gatt_table[i - 1]; + + return 0; +} + +/* + * These functions are called when the GART page size exceeds PAGE_SIZE. + * + * This situation is interesting since AGP memory allocations that are + * smaller than a single GART page are possible. The structures i460_pg_count + * and i460_pg_detail track partial allocation of the large GART pages to + * work around this issue. + * + * i460_pg_count[pg_num] tracks the number of kernel pages in use within + * GART page pg_num. i460_pg_detail[pg_num] is an array containing a + * psuedo-GART entry for each of the aforementioned kernel pages. The whole + * of i460_pg_detail is equivalent to a giant GATT with page size equal to + * that of the kernel. + */ + +static void *intel_i460_alloc_large_page(int pg_num) +{ + int i; + void *bp, *bp_end; + struct page *page; + + i460_pg_detail[pg_num] = (void *) vmalloc(sizeof(u32) * + I460_KPAGES_PER_CPAGE); + if(i460_pg_detail[pg_num] == NULL) { + printk("[agpgart] Out of memory, we're in trouble...\n"); + return NULL; + } + + for(i = 0; i < I460_KPAGES_PER_CPAGE; i++) + i460_pg_detail[pg_num][i] = 0; + + bp = (void *) __get_free_pages(GFP_KERNEL, + intel_i460_pageshift - PAGE_SHIFT); + if(bp == NULL) { + printk("[agpgart] Couldn't alloc 4M GART page...\n"); + return NULL; + } + + bp_end = bp + ((PAGE_SIZE * + (1 << (intel_i460_pageshift - PAGE_SHIFT))) - 1); + + for (page = virt_to_page(bp); page <= virt_to_page(bp_end); page++) + { + atomic_inc(&page->count); + set_bit(PG_locked, &page->flags); + atomic_inc(&agp_bridge.current_memory_agp); + } + + return bp; +} + +static void intel_i460_free_large_page(int pg_num, unsigned long addr) +{ + struct page *page; + void *bp, *bp_end; + + bp = (void *) __va(addr); + bp_end = bp + (PAGE_SIZE * + (1 << (intel_i460_pageshift - PAGE_SHIFT))); + + vfree(i460_pg_detail[pg_num]); + i460_pg_detail[pg_num] = NULL; + + for (page = virt_to_page(bp); page < virt_to_page(bp_end); page++) + { + put_page(page); + UnlockPage(page); + atomic_dec(&agp_bridge.current_memory_agp); + } + + free_pages((unsigned long) bp, intel_i460_pageshift - PAGE_SHIFT); +} + +static int intel_i460_insert_memory_kpc(agp_memory * mem, + off_t pg_start, int type) +{ + int i, pg, start_pg, end_pg, start_offset, end_offset, idx; + int num_entries; + void *temp; + unsigned int read_back; + unsigned long paddr; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + /* Figure out what pg_start means in terms of our large GART pages */ + start_pg = pg_start / I460_KPAGES_PER_CPAGE; + start_offset = pg_start % I460_KPAGES_PER_CPAGE; + end_pg = (pg_start + mem->page_count - 1) / + I460_KPAGES_PER_CPAGE; + end_offset = (pg_start + mem->page_count - 1) % + I460_KPAGES_PER_CPAGE; + + if(end_pg > num_entries) + { + printk("[agpgart] Looks like we're out of AGP memory\n"); + return -EINVAL; + } + + /* Check if the requested region of the aperture is free */ + for(pg = start_pg; pg <= end_pg; pg++) + { + /* Allocate new GART pages if necessary */ + if(i460_pg_detail[pg] == NULL) { + temp = intel_i460_alloc_large_page(pg); + if(temp == NULL) + return -ENOMEM; + agp_bridge.gatt_table[pg] = agp_bridge.mask_memory( + (unsigned long) temp, 0); + read_back = agp_bridge.gatt_table[pg]; + } + + for(idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) + : I460_KPAGES_PER_CPAGE); + idx++) + { + if(i460_pg_detail[pg][idx] != 0) + return -EBUSY; + } + } + +#if 0 + /* not necessary since 460 GART is operated in coherent mode... */ + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } +#endif + + for(pg = start_pg, i = 0; pg <= end_pg; pg++) + { + paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]); + for(idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) + : I460_KPAGES_PER_CPAGE); + idx++, i++) + { + mem->memory[i] = paddr + (idx * PAGE_SIZE); + i460_pg_detail[pg][idx] = + agp_bridge.mask_memory(mem->memory[i], mem->type); + + i460_pg_count[pg]++; + } + } + + return 0; +} + +static int intel_i460_remove_memory_kpc(agp_memory * mem, + off_t pg_start, int type) +{ + int i, pg, start_pg, end_pg, start_offset, end_offset, idx; + int num_entries; + void *temp; + unsigned int read_back; + unsigned long paddr; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_8(temp)->num_entries; + + /* Figure out what pg_start means in terms of our large GART pages */ + start_pg = pg_start / I460_KPAGES_PER_CPAGE; + start_offset = pg_start % I460_KPAGES_PER_CPAGE; + end_pg = (pg_start + mem->page_count - 1) / + I460_KPAGES_PER_CPAGE; + end_offset = (pg_start + mem->page_count - 1) % + I460_KPAGES_PER_CPAGE; + + for(i = 0, pg = start_pg; pg <= end_pg; pg++) + { + for(idx = ((pg == start_pg) ? start_offset : 0); + idx < ((pg == end_pg) ? (end_offset + 1) + : I460_KPAGES_PER_CPAGE); + idx++, i++) + { + mem->memory[i] = 0; + i460_pg_detail[pg][idx] = 0; + i460_pg_count[pg]--; + } + + /* Free GART pages if they are unused */ + if(i460_pg_count[pg] == 0) { + paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]); + agp_bridge.gatt_table[pg] = agp_bridge.scratch_page; + read_back = agp_bridge.gatt_table[pg]; + + intel_i460_free_large_page(pg, paddr); + } + } + + return 0; +} + +/* Dummy routines to call the approriate {cpk,kpc} function */ + +static int intel_i460_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + if(intel_i460_cpk) + return intel_i460_insert_memory_cpk(mem, pg_start, type); + else + return intel_i460_insert_memory_kpc(mem, pg_start, type); +} + +static int intel_i460_remove_memory(agp_memory * mem, + off_t pg_start, int type) +{ + if(intel_i460_cpk) + return intel_i460_remove_memory_cpk(mem, pg_start, type); + else + return intel_i460_remove_memory_kpc(mem, pg_start, type); +} + +/* + * If the kernel page size is smaller that the chipset page size, we don't + * want to allocate memory until we know where it is to be bound in the + * aperture (a multi-kernel-page alloc might fit inside of an already + * allocated GART page). Consequently, don't allocate or free anything + * if i460_cpk (meaning chipset pages per kernel page) isn't set. + * + * Let's just hope nobody counts on the allocated AGP memory being there + * before bind time (I don't think current drivers do)... + */ +static unsigned long intel_i460_alloc_page(void) +{ + if(intel_i460_cpk) + return agp_generic_alloc_page(); + + /* Returning NULL would cause problems */ + return ((unsigned long) ~0UL); +} + +static void intel_i460_destroy_page(unsigned long page) +{ + if(intel_i460_cpk) + agp_generic_destroy_page(page); +} + +static gatt_mask intel_i460_masks[] = +{ + { + INTEL_I460_GATT_VALID | INTEL_I460_GATT_COHERENT, + 0 + } +}; + +static unsigned long intel_i460_mask_memory(unsigned long addr, int type) +{ + /* Make sure the returned address is a valid GATT entry */ + return (agp_bridge.masks[0].mask | (((addr & + ~((1 << intel_i460_pageshift) - 1)) & 0xffffff000) >> 12)); +} + +static unsigned long intel_i460_unmask_memory(unsigned long addr) +{ + /* Turn a GATT entry into a physical address */ + return ((addr & 0xffffff) << 12); +} + +static aper_size_info_8 intel_i460_sizes[3] = +{ + /* + * The 32GB aperture is only available with a 4M GART page size. + * Due to the dynamic GART page size, we can't figure out page_order + * or num_entries until runtime. + */ + {32768, 0, 0, 4}, + {1024, 0, 0, 2}, + {256, 0, 0, 1} +}; + +static int __init intel_i460_setup (struct pci_dev *pdev) +{ + + agp_bridge.masks = intel_i460_masks; + agp_bridge.aperture_sizes = (void *) intel_i460_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 3; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_i460_configure; + agp_bridge.fetch_size = intel_i460_fetch_size; + agp_bridge.cleanup = intel_i460_cleanup; + agp_bridge.tlb_flush = intel_i460_tlb_flush; + agp_bridge.mask_memory = intel_i460_mask_memory; + agp_bridge.unmask_memory = intel_i460_unmask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = intel_i460_create_gatt_table; + agp_bridge.free_gatt_table = intel_i460_free_gatt_table; + agp_bridge.insert_memory = intel_i460_insert_memory; + agp_bridge.remove_memory = intel_i460_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = intel_i460_alloc_page; + agp_bridge.agp_destroy_page = intel_i460_destroy_page; +#if 0 + agp_bridge.suspend = ??; + agp_bridge.resume = ??; +#endif + agp_bridge.cant_use_aperture = 1; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_I460 */ #ifdef CONFIG_AGP_INTEL @@ -1808,7 +2505,6 @@ static int __init intel_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_generic_sizes; agp_bridge.size_type = U16_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1819,6 +2515,7 @@ agp_bridge.cleanup = intel_cleanup; agp_bridge.tlb_flush = intel_tlbflush; agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; @@ -1841,7 +2538,6 @@ static int __init intel_815_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_815_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -1874,7 +2570,6 @@ static int __init intel_820_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1907,7 +2602,6 @@ static int __init intel_830mp_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_830mp_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 4; @@ -1939,7 +2633,6 @@ static int __init intel_840_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1972,7 +2665,6 @@ static int __init intel_845_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1983,6 +2675,7 @@ agp_bridge.cleanup = intel_8xx_cleanup; agp_bridge.tlb_flush = intel_8xx_tlbflush; agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; @@ -2005,7 +2698,6 @@ static int __init intel_850_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2016,6 +2708,7 @@ agp_bridge.cleanup = intel_8xx_cleanup; agp_bridge.tlb_flush = intel_8xx_tlbflush; agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; @@ -2038,7 +2731,6 @@ static int __init intel_860_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2158,7 +2850,6 @@ static int __init via_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = via_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) via_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2169,6 +2860,7 @@ agp_bridge.cleanup = via_cleanup; agp_bridge.tlb_flush = via_tlbflush; agp_bridge.mask_memory = via_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; @@ -2272,7 +2964,6 @@ static int __init sis_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = sis_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) sis_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2283,6 +2974,7 @@ agp_bridge.cleanup = sis_cleanup; agp_bridge.tlb_flush = sis_tlbflush; agp_bridge.mask_memory = sis_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; @@ -2305,8 +2997,8 @@ #ifdef CONFIG_AGP_AMD typedef struct _amd_page_map { - unsigned long *real; - unsigned long *remapped; + u32 *real; + u32 *remapped; } amd_page_map; static struct _amd_irongate_private { @@ -2319,7 +3011,7 @@ { int i; - page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + page_map->real = (u32 *) __get_free_page(GFP_KERNEL); if (page_map->real == NULL) { return -ENOMEM; } @@ -2572,7 +3264,7 @@ off_t pg_start, int type) { int i, j, num_entries; - unsigned long *cur_gatt; + u32 *cur_gatt; unsigned long addr; num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; @@ -2602,7 +3294,8 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + cur_gatt[GET_GATT_OFF(addr)] = + agp_bridge.mask_memory(mem->memory[i], mem->type); } agp_bridge.tlb_flush(mem); return 0; @@ -2612,7 +3305,7 @@ int type) { int i; - unsigned long *cur_gatt; + u32 *cur_gatt; unsigned long addr; if (type != 0 || mem->type != 0) { @@ -2648,7 +3341,6 @@ static int __init amd_irongate_setup (struct pci_dev *pdev) { agp_bridge.masks = amd_irongate_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2659,6 +3351,7 @@ agp_bridge.cleanup = amd_irongate_cleanup; agp_bridge.tlb_flush = amd_irongate_tlbflush; agp_bridge.mask_memory = amd_irongate_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = amd_create_gatt_table; @@ -2895,7 +3588,6 @@ static int __init ali_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = ali_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) ali_generic_sizes; agp_bridge.size_type = U32_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -2906,6 +3598,7 @@ agp_bridge.cleanup = ali_cleanup; agp_bridge.tlb_flush = ali_tlbflush; agp_bridge.mask_memory = ali_mask_memory; + agp_bridge.unmask_memory = agp_generic_unmask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = ali_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; @@ -3301,7 +3994,8 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + cur_gatt[GET_GATT_OFF(addr)] = + agp_bridge.mask_memory(mem->memory[i], mem->type); } agp_bridge.tlb_flush(mem); return 0; @@ -3458,7 +4152,6 @@ serverworks_private.svrwrks_dev = pdev; agp_bridge.masks = serverworks_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) serverworks_sizes; agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -3542,11 +4235,6 @@ {0, 0, 0}, /* filled in by hp_zx1_fetch_size() */ }; -static gatt_mask hp_zx1_masks[] = -{ - {HP_ZX1_PDIR_VALID_BIT, 0} -}; - static struct _hp_private { struct pci_dev *ioc; volatile u8 *registers; @@ -3612,7 +4300,7 @@ return 0; } -static int __init hp_zx1_ioc_owner(u8 ioc_rev) +static int __init hp_zx1_ioc_owner(void) { struct _hp_private *hp = &hp_private; @@ -3652,7 +4340,6 @@ struct _hp_private *hp = &hp_private; struct pci_dev *ioc; int i; - u8 ioc_rev; ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL); if (!ioc) { @@ -3661,8 +4348,6 @@ } hp->ioc = ioc; - pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev); - for (i = 0; i < PCI_NUM_RESOURCES; i++) { if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) { hp->registers = (u8 *) ioremap(pci_resource_start(ioc, @@ -3684,7 +4369,7 @@ hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0; if (hp->io_pdir_owner) - return hp_zx1_ioc_owner(ioc_rev); + return hp_zx1_ioc_owner(); return hp_zx1_ioc_shared(); } @@ -3804,10 +4489,13 @@ j++; } +#if 0 + /* Not necessary since zx1 agp is coherent */ if (mem->is_flushed == FALSE) { CACHE_FLUSH(); mem->is_flushed = TRUE; } +#endif for (i = 0, j = io_pg_start; i < mem->page_count; i++) { unsigned long paddr; @@ -3855,8 +4543,6 @@ static int __init hp_zx1_setup (struct pci_dev *pdev) { - agp_bridge.masks = hp_zx1_masks; - agp_bridge.num_of_masks = 1; agp_bridge.dev_private_data = NULL; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.needs_scratch_page = FALSE; @@ -4075,6 +4761,15 @@ #endif /* CONFIG_AGP_INTEL */ +#ifdef CONFIG_AGP_I460 + { PCI_DEVICE_ID_INTEL_460GX, + PCI_VENDOR_ID_INTEL, + INTEL_460GX, + "Intel", + "460GX", + intel_i460_setup }, +#endif + #ifdef CONFIG_AGP_SIS { PCI_DEVICE_ID_SI_740, PCI_VENDOR_ID_SI, @@ -4210,6 +4905,15 @@ hp_zx1_setup }, #endif +#ifdef CONFIG_AGP_HP_ZX1 + { PCI_DEVICE_ID_HP_ZX1_LBA, + PCI_VENDOR_ID_HP, + HP_ZX1, + "HP", + "ZX1", + hp_zx1_setup }, +#endif + { 0, }, /* dummy final entry, always present */ }; @@ -4288,6 +4992,18 @@ return -ENODEV; } +static int agp_check_supported_device(struct pci_dev *dev) { + + int i; + + for(i = 0; i < ARRAY_SIZE (agp_bridge_info); i++) { + if(dev->vendor == agp_bridge_info[i].vendor_id && + dev->device == agp_bridge_info[i].device_id) + return 1; + } + + return 0; +} /* Supported Device Scanning routine */ @@ -4295,10 +5011,15 @@ { struct pci_dev *dev = NULL; u8 cap_ptr = 0x00; - u32 cap_id, scratch; - if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL) - return -ENODEV; + /* + * Some systems have multiple host bridges (i.e. BigSur), so + * we can't just use the first one we find. + */ + do { + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev)) == NULL) + return -ENODEV; + } while(!agp_check_supported_device(dev)); agp_bridge.dev = dev; @@ -4475,6 +5196,23 @@ } #endif /* CONFIG_AGP_HP_ZX1 */ +#ifdef CONFIG_AGP_HP_ZX1 + if (dev->vendor == PCI_VENDOR_ID_HP) { + do { + /* ZX1 LBAs can be either PCI or AGP bridges */ + if (pci_find_capability(dev, PCI_CAP_ID_AGP)) { + printk(KERN_INFO PFX "Detected HP ZX1 AGP " + "chipset at %s\n", dev->slot_name); + agp_bridge.type = HP_ZX1; + agp_bridge.dev = dev; + return hp_zx1_setup(dev); + } + dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev); + } while (dev); + return -ENODEV; + } +#endif /* CONFIG_AGP_HP_ZX1 */ + /* find capndx */ cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); if (cap_ptr == 0x00) @@ -4512,7 +5250,7 @@ { long memory, index, result; - memory = virt_to_phys(high_memory) >> 20; + memory = (num_physpages << PAGE_SHIFT) >> 20; index = 1; while ((memory > maxes_table[index].mem) && diff -Nur linux-2.4.19/drivers/char/drm/ati_pcigart.h linux-2.4.19-sgi211r3/drivers/char/drm/ati_pcigart.h --- linux-2.4.19/drivers/char/drm/ati_pcigart.h Thu Nov 22 11:46:37 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/ati_pcigart.h Tue Aug 27 19:53:13 2002 @@ -30,14 +30,20 @@ #define __NO_VERSION__ #include "drmP.h" -#if PAGE_SIZE == 8192 +#if PAGE_SIZE == 65536 +# define ATI_PCIGART_TABLE_ORDER 0 +# define ATI_PCIGART_TABLE_PAGES (1 << 0) +#elif PAGE_SIZE == 16384 +# define ATI_PCIGART_TABLE_ORDER 1 +# define ATI_PCIGART_TABLE_PAGES (1 << 1) +#elif PAGE_SIZE == 8192 # define ATI_PCIGART_TABLE_ORDER 2 # define ATI_PCIGART_TABLE_PAGES (1 << 2) #elif PAGE_SIZE == 4096 # define ATI_PCIGART_TABLE_ORDER 3 # define ATI_PCIGART_TABLE_PAGES (1 << 3) #else -# error - PAGE_SIZE not 8K or 4K +# error - PAGE_SIZE not 64K, 16K, 8K or 4K #endif # define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture, 4K pages */ @@ -103,6 +109,7 @@ goto done; } +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) if ( !dev->pdev ) { DRM_ERROR( "PCI device unknown!\n" ); goto done; @@ -117,6 +124,9 @@ address = 0; goto done; } +#else + bus_address = virt_to_bus( (void *)address ); +#endif pci_gart = (u32 *)address; @@ -126,6 +136,7 @@ memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) ); for ( i = 0 ; i < pages ; i++ ) { +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) /* we need to support large memory configurations */ entry->busaddr[i] = pci_map_single(dev->pdev, page_address( entry->pagelist[i] ), @@ -139,7 +150,9 @@ goto done; } page_base = (u32) entry->busaddr[i]; - +#else + page_base = page_to_bus( entry->pagelist[i] ); +#endif for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { *pci_gart++ = cpu_to_le32( page_base ); page_base += ATI_PCIGART_PAGE_SIZE; @@ -164,6 +177,7 @@ unsigned long addr, dma_addr_t bus_addr) { +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) drm_sg_mem_t *entry = dev->sg; unsigned long pages; int i; @@ -188,6 +202,8 @@ PAGE_SIZE, PCI_DMA_TODEVICE); } } + +#endif if ( addr ) { DRM(ati_free_pcigart_table)( addr ); diff -Nur linux-2.4.19/drivers/char/drm/drmP.h linux-2.4.19-sgi211r3/drivers/char/drm/drmP.h --- linux-2.4.19/drivers/char/drm/drmP.h Thu Nov 22 11:46:37 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/drmP.h Tue Jan 8 17:05:38 2002 @@ -366,13 +366,13 @@ if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; } /* Mapping helper macros */ -#define DRM_IOREMAP(map) \ - (map)->handle = DRM(ioremap)( (map)->offset, (map)->size ) +#define DRM_IOREMAP(map, dev) \ + (map)->handle = DRM(ioremap)( (map)->offset, (map)->size, (dev) ) -#define DRM_IOREMAPFREE(map) \ +#define DRM_IOREMAPFREE(map, dev) \ do { \ if ( (map)->handle && (map)->size ) \ - DRM(ioremapfree)( (map)->handle, (map)->size ); \ + DRM(ioremapfree)( (map)->handle, (map)->size, (dev) ); \ } while (0) #define DRM_FIND_MAP(_map, _o) \ @@ -826,8 +826,8 @@ extern unsigned long DRM(alloc_pages)(int order, int area); extern void DRM(free_pages)(unsigned long address, int order, int area); -extern void *DRM(ioremap)(unsigned long offset, unsigned long size); -extern void DRM(ioremapfree)(void *pt, unsigned long size); +extern void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev); +extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); #if __REALLY_HAVE_AGP extern agp_memory *DRM(alloc_agp)(int pages, u32 type); diff -Nur linux-2.4.19/drivers/char/drm/drm_agpsupport.h linux-2.4.19-sgi211r3/drivers/char/drm/drm_agpsupport.h --- linux-2.4.19/drivers/char/drm/drm_agpsupport.h Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm/drm_agpsupport.h Wed Oct 16 14:02:58 2002 @@ -277,6 +277,7 @@ case INTEL_I840: head->chipset = "Intel i840"; break; case INTEL_I845: head->chipset = "Intel i845"; break; case INTEL_I850: head->chipset = "Intel i850"; break; + case INTEL_460GX: head->chipset = "Intel 460GX"; break; #endif case VIA_GENERIC: head->chipset = "VIA"; break; diff -Nur linux-2.4.19/drivers/char/drm/drm_bufs.h linux-2.4.19-sgi211r3/drivers/char/drm/drm_bufs.h --- linux-2.4.19/drivers/char/drm/drm_bufs.h Thu Nov 22 11:46:37 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/drm_bufs.h Tue Jan 8 17:05:38 2002 @@ -107,7 +107,7 @@ switch ( map->type ) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if !defined(__sparc__) && !defined(__alpha__) +#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) if ( map->offset + map->size < map->offset || map->offset < virt_to_phys(high_memory) ) { DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); @@ -124,7 +124,7 @@ MTRR_TYPE_WRCOMB, 1 ); } #endif - map->handle = DRM(ioremap)( map->offset, map->size ); + map->handle = DRM(ioremap)( map->offset, map->size, dev ); break; case _DRM_SHM: @@ -249,7 +249,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size); + DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: vfree(map->handle); diff -Nur linux-2.4.19/drivers/char/drm/drm_drv.h linux-2.4.19-sgi211r3/drivers/char/drm/drm_drv.h --- linux-2.4.19/drivers/char/drm/drm_drv.h Sun Oct 21 10:40:36 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/drm_drv.h Tue Jan 8 17:05:38 2002 @@ -439,7 +439,7 @@ DRM_DEBUG( "mtrr_del=%d\n", retcode ); } #endif - DRM(ioremapfree)( map->handle, map->size ); + DRM(ioremapfree)( map->handle, map->size, dev ); break; case _DRM_SHM: vfree(map->handle); diff -Nur linux-2.4.19/drivers/char/drm/drm_memory.h linux-2.4.19-sgi211r3/drivers/char/drm/drm_memory.h --- linux-2.4.19/drivers/char/drm/drm_memory.h Thu Nov 22 11:46:37 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/drm_memory.h Fri Apr 26 11:07:18 2002 @@ -306,9 +306,14 @@ } } -void *DRM(ioremap)(unsigned long offset, unsigned long size) +void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev) { void *pt; +#if __REALLY_HAVE_AGP + drm_map_t *map = NULL; + drm_map_list_t *r_list; + struct list_head *list; +#endif if (!size) { DRM_MEM_ERROR(DRM_MEM_MAPPINGS, @@ -316,12 +321,51 @@ return NULL; } +#if __REALLY_HAVE_AGP + if(!dev->agp || dev->agp->cant_use_aperture == 0) + goto standard_ioremap; + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + map = r_list->map; + if (!map) continue; + if (map->offset <= offset && + (map->offset + map->size) >= (offset + size)) + break; + } + + if(map && map->type == _DRM_AGP) { + struct drm_agp_mem *agpmem; + + for(agpmem = dev->agp->memory; agpmem; + agpmem = agpmem->next) { + if(agpmem->bound <= offset && + (agpmem->bound + (agpmem->pages + << PAGE_SHIFT)) >= (offset + size)) + break; + } + + if(agpmem == NULL) + goto ioremap_failure; + + pt = agpmem->memory->vmptr + (offset - agpmem->bound); + goto ioremap_success; + } + +standard_ioremap: +#endif if (!(pt = ioremap(offset, size))) { +#if __REALLY_HAVE_AGP +ioremap_failure: +#endif spin_lock(&DRM(mem_lock)); ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; spin_unlock(&DRM(mem_lock)); return NULL; } +#if __REALLY_HAVE_AGP +ioremap_success: +#endif spin_lock(&DRM(mem_lock)); ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; @@ -329,7 +373,7 @@ return pt; } -void DRM(ioremapfree)(void *pt, unsigned long size) +void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) { int alloc_count; int free_count; @@ -337,7 +381,11 @@ if (!pt) DRM_MEM_ERROR(DRM_MEM_MAPPINGS, "Attempt to free NULL pointer\n"); +#if __REALLY_HAVE_AGP + else if(!dev->agp || dev->agp->cant_use_aperture == 0) +#else else +#endif iounmap(pt); spin_lock(&DRM(mem_lock)); diff -Nur linux-2.4.19/drivers/char/drm/drm_scatter.h linux-2.4.19-sgi211r3/drivers/char/drm/drm_scatter.h --- linux-2.4.19/drivers/char/drm/drm_scatter.h Thu Nov 22 11:46:37 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/drm_scatter.h Tue Jan 8 17:05:38 2002 @@ -47,9 +47,11 @@ vfree( entry->virtual ); +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) DRM(free)( entry->busaddr, entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); +#endif DRM(free)( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); @@ -97,6 +99,7 @@ return -ENOMEM; } +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); if ( !entry->busaddr ) { @@ -109,12 +112,15 @@ return -ENOMEM; } memset( (void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr) ); +#endif entry->virtual = vmalloc_32( pages << PAGE_SHIFT ); if ( !entry->virtual ) { +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) DRM(free)( entry->busaddr, entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); +#endif DRM(free)( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); diff -Nur linux-2.4.19/drivers/char/drm/drm_vm.h linux-2.4.19-sgi211r3/drivers/char/drm/drm_vm.h --- linux-2.4.19/drivers/char/drm/drm_vm.h Thu Nov 22 11:46:37 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/drm_vm.h Tue Aug 27 19:53:13 2002 @@ -78,7 +78,7 @@ * Find the right map */ - if(!dev->agp->cant_use_aperture) goto vm_nopage_error; + if(!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; list_for_each(list, &dev->maplist->head) { r_list = (drm_map_list_t *)list; @@ -255,7 +255,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size); + DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: vfree(map->handle); @@ -456,6 +456,7 @@ drm_map_list_t *r_list; unsigned long offset = 0; struct list_head *list; + struct page *page; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", vma->vm_start, vma->vm_end, VM_OFFSET(vma)); @@ -502,28 +503,34 @@ switch (map->type) { case _DRM_AGP: -#if defined(__alpha__) - /* - * On Alpha we can't talk to bus dma address from the - * CPU, so for memory of type DRM_AGP, we'll deal with - * sorting out the real physical pages and mappings - * in nopage() - */ - vma->vm_ops = &DRM(vm_ops); - break; +#if __REALLY_HAVE_AGP + if(dev->agp->cant_use_aperture == 1) { + /* + * On some systems we can't talk to bus dma address from + * the CPU, so for memory of type DRM_AGP, we'll deal + * with sorting out the real physical pages and mappings + * in nopage() + */ + vma->vm_ops = &DRM(vm_ops); +#if 0/*XXX non-coherent AGP DMA*/ + vma->vm_page_prot = + pgprot_writecombine(vma->vm_page_prot); +#endif + goto mapswitch_out; + } #endif /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: - if (VM_OFFSET(vma) >= __pa(high_memory)) { + page = virt_to_page(__va(VM_OFFSET(vma))); + if (!VALID_PAGE(page) || PageReserved(page)) { #if defined(__i386__) if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; } #elif defined(__ia64__) - if (map->type != _DRM_AGP) - vma->vm_page_prot = + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #elif defined(__powerpc__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED; @@ -567,11 +574,14 @@ #else vma->vm_pte = (unsigned long)map; #endif - vma->vm_flags |= VM_RESERVED; + vma->vm_flags |= VM_RESERVED; break; default: return -EINVAL; /* This should never happen. */ } +#if __REALLY_HAVE_AGP +mapswitch_out: +#endif vma->vm_flags |= VM_RESERVED; /* Don't swap */ #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ diff -Nur linux-2.4.19/drivers/char/drm/i810_dma.c linux-2.4.19-sgi211r3/drivers/char/drm/i810_dma.c --- linux-2.4.19/drivers/char/drm/i810_dma.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm/i810_dma.c Wed Oct 16 14:02:58 2002 @@ -313,7 +313,7 @@ if(dev_priv->ring.virtual_start) { DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, - dev_priv->ring.Size); + dev_priv->ring.Size, dev); } if(dev_priv->hw_status_page != 0UL) { i810_free_page(dev, dev_priv->hw_status_page); @@ -327,7 +327,8 @@ for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total); + DRM(ioremapfree)(buf_priv->kernel_virtual, + buf->total, dev); } } return 0; @@ -400,7 +401,7 @@ *buf_priv->in_use = I810_BUF_FREE; buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, - buf->total); + buf->total, dev); } return 0; } @@ -456,7 +457,7 @@ dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + init->ring_start, - init->ring_size); + init->ring_size, dev); if (dev_priv->ring.virtual_start == NULL) { dev->dev_private = (void *) dev_priv; diff -Nur linux-2.4.19/drivers/char/drm/mga_dma.c linux-2.4.19-sgi211r3/drivers/char/drm/mga_dma.c --- linux-2.4.19/drivers/char/drm/mga_dma.c Wed Aug 8 09:42:15 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/mga_dma.c Tue Jan 8 17:05:38 2002 @@ -557,9 +557,9 @@ (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DRM_IOREMAP( dev_priv->warp ); - DRM_IOREMAP( dev_priv->primary ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->warp, dev ); + DRM_IOREMAP( dev_priv->primary, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->warp->handle || !dev_priv->primary->handle || @@ -647,9 +647,9 @@ if ( dev->dev_private ) { drm_mga_private_t *dev_priv = dev->dev_private; - DRM_IOREMAPFREE( dev_priv->warp ); - DRM_IOREMAPFREE( dev_priv->primary ); - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPFREE( dev_priv->warp, dev ); + DRM_IOREMAPFREE( dev_priv->primary, dev ); + DRM_IOREMAPFREE( dev_priv->buffers, dev ); if ( dev_priv->head != NULL ) { mga_freelist_cleanup( dev ); diff -Nur linux-2.4.19/drivers/char/drm/r128_cce.c linux-2.4.19-sgi211r3/drivers/char/drm/r128_cce.c --- linux-2.4.19/drivers/char/drm/r128_cce.c Mon Aug 27 07:40:33 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/r128_cce.c Mon Oct 21 10:27:27 2002 @@ -216,7 +216,22 @@ int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { +#ifndef CONFIG_AGP_I460 if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail ) { +#else + /* + * XXX - this is (I think) a 460GX specific hack + * + * When doing texturing, ring.tail sometimes gets ahead of + * PM4_BUFFER_DL_WPTR by 2; consequently, the card processes + * its whole quota of instructions and *ring.head is still 2 + * short of ring.tail. Work around this for now in lieu of + * a better solution. + */ + if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail || + ( dev_priv->ring.tail - + GET_RING_HEAD( &dev_priv->ring ) ) == 2 ) { +#endif int pm4stat = R128_READ( R128_PM4_STAT ); if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size ) && @@ -317,7 +332,7 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev, drm_r128_private_t *dev_priv ) { - u32 ring_start; + u32 ring_start, rptr_addr; u32 tmp; DRM_DEBUG( "%s\n", __FUNCTION__ ); @@ -341,8 +356,28 @@ SET_RING_HEAD( &dev_priv->ring, 0 ); if ( !dev_priv->is_pci ) { - R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, - dev_priv->ring_rptr->offset ); +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * XXX - This is a 460GX specific hack + * + * We have to hack this right now. 460GX isn't claiming PCI + * writes from the card into the AGP aperture. Because of this, + * we have to get space outside of the aperture for RPTR_ADDR. + */ + if( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off; + + alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(alt_rh_off)->count); + set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + + dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off; + SET_RING_HEAD( &dev_priv->ring, 0 ); + rptr_addr = __pa( dev_priv->ring.head ); + } else +#endif + rptr_addr = dev_priv->ring_rptr->offset; + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, rptr_addr ); } else { drm_sg_mem_t *entry = dev->sg; unsigned long tmp_ofs, page_ofs; @@ -350,11 +385,20 @@ tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; page_ofs = tmp_ofs >> PAGE_SHIFT; +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, entry->busaddr[page_ofs]); DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", entry->busaddr[page_ofs], entry->handle + tmp_ofs ); +#else + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, + page_to_bus(entry->pagelist[page_ofs])); + + DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n", + page_to_bus(entry->pagelist[page_ofs]), + entry->handle + tmp_ofs ); +#endif } /* Set watermark control */ @@ -550,9 +594,9 @@ init->sarea_priv_offset); if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cce_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->cce_ring, dev ); + DRM_IOREMAP( dev_priv->ring_rptr, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->cce_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { @@ -624,9 +668,9 @@ drm_r128_private_t *dev_priv = dev->dev_private; if ( !dev_priv->is_pci ) { - DRM_IOREMAPFREE( dev_priv->cce_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPFREE( dev_priv->cce_ring, dev ); + DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); + DRM_IOREMAPFREE( dev_priv->buffers, dev ); } else { if (!DRM(ati_pcigart_cleanup)( dev, dev_priv->phys_pci_gart, @@ -634,6 +678,21 @@ DRM_ERROR( "failed to cleanup PCI GART!\n" ); } +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * Free the page we grabbed for RPTR_ADDR + */ + if( !dev_priv->is_pci && dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off = + (unsigned long) dev_priv->ring.head; + struct page *p = virt_to_page((void *)alt_rh_off); + + put_page(p); + unlock_page(p); + free_page(alt_rh_off); + } +#endif + DRM(free)( dev->dev_private, sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -Nur linux-2.4.19/drivers/char/drm/radeon_cp.c linux-2.4.19-sgi211r3/drivers/char/drm/radeon_cp.c --- linux-2.4.19/drivers/char/drm/radeon_cp.c Fri Sep 14 14:29:41 2001 +++ linux-2.4.19-sgi211r3/drivers/char/drm/radeon_cp.c Tue Jan 8 17:05:38 2002 @@ -575,7 +575,7 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, drm_radeon_private_t *dev_priv ) { - u32 ring_start, cur_read_ptr; + u32 ring_start, cur_read_ptr, rptr_addr; u32 tmp; /* Initialize the memory controller */ @@ -612,8 +612,28 @@ dev_priv->ring.tail = cur_read_ptr; if ( !dev_priv->is_pci ) { - RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, - dev_priv->ring_rptr->offset ); +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * XXX - This is a 460GX specific hack + * + * We have to hack this right now. 460GX isn't claiming PCI + * writes from the card into the AGP aperture. Because of this, + * we have to get space outside of the aperture for RPTR_ADDR. + */ + if( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off; + + alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(alt_rh_off)->count); + set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + + dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off; + *dev_priv->ring.head = cur_read_ptr; + rptr_addr = __pa( dev_priv->ring.head ); + } else +#endif + rptr_addr = dev_priv->ring_rptr->offset; + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, rptr_addr ); } else { drm_sg_mem_t *entry = dev->sg; unsigned long tmp_ofs, page_ofs; @@ -621,11 +641,19 @@ tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; page_ofs = tmp_ofs >> PAGE_SHIFT; +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, entry->busaddr[page_ofs]); DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", entry->busaddr[page_ofs], entry->handle + tmp_ofs ); +#else + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, + entry->busaddr[page_ofs]); + DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", + entry->busaddr[page_ofs], + entry->handle + tmp_ofs ); +#endif } /* Set ring buffer size */ @@ -836,9 +864,9 @@ init->sarea_priv_offset); if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cp_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->cp_ring, dev ); + DRM_IOREMAP( dev_priv->ring_rptr, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { @@ -983,9 +1011,9 @@ drm_radeon_private_t *dev_priv = dev->dev_private; if ( !dev_priv->is_pci ) { - DRM_IOREMAPFREE( dev_priv->cp_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPFREE( dev_priv->cp_ring, dev ); + DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); + DRM_IOREMAPFREE( dev_priv->buffers, dev ); } else { if (!DRM(ati_pcigart_cleanup)( dev, dev_priv->phys_pci_gart, @@ -993,6 +1021,21 @@ DRM_ERROR( "failed to cleanup PCI GART!\n" ); } +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * Free the page we grabbed for RPTR_ADDR + */ + if( !dev_priv->is_pci && dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off = + (unsigned long) dev_priv->ring.head; + + atomic_dec(&virt_to_page(alt_rh_off)->count); + clear_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + wake_up(&virt_to_page(alt_rh_off)->wait); + free_page(alt_rh_off); + } +#endif + DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -Nur linux-2.4.19/drivers/char/drm-4.0/agpsupport.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/agpsupport.c --- linux-2.4.19/drivers/char/drm-4.0/agpsupport.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/agpsupport.c Tue Jan 8 17:05:38 2002 @@ -30,6 +30,7 @@ #define __NO_VERSION__ #include "drmP.h" +#include #include #if LINUX_VERSION_CODE < 0x020400 #include "agpsupport-pre24.h" @@ -264,6 +265,7 @@ #if LINUX_VERSION_CODE >= 0x020400 case INTEL_I840: head->chipset = "Intel i840"; break; #endif + case INTEL_460GX: head->chipset = "Intel 460GX"; break; case VIA_GENERIC: head->chipset = "VIA"; break; case VIA_VP3: head->chipset = "VIA VP3"; break; @@ -297,6 +299,14 @@ default: head->chipset = "Unknown"; break; } +#if LINUX_VERSION_CODE <= 0x020408 + head->cant_use_aperture = 0; + head->page_mask = ~(0xfff); +#else + head->cant_use_aperture = head->agp_info.cant_use_aperture; + head->page_mask = head->agp_info.page_mask; +#endif + DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n", head->agp_info.version.major, head->agp_info.version.minor, diff -Nur linux-2.4.19/drivers/char/drm-4.0/bufs.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/bufs.c --- linux-2.4.19/drivers/char/drm-4.0/bufs.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/bufs.c Tue Jan 8 17:05:38 2002 @@ -73,7 +73,7 @@ switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#ifndef __sparc__ +#if !defined(__sparc__) && !defined(__ia64__) if (map->offset + map->size < map->offset || map->offset < virt_to_phys(high_memory)) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); @@ -87,7 +87,7 @@ MTRR_TYPE_WRCOMB, 1); } #endif - map->handle = drm_ioremap(map->offset, map->size); + map->handle = drm_ioremap(map->offset, map->size, dev); break; diff -Nur linux-2.4.19/drivers/char/drm-4.0/drmP.h linux-2.4.19-sgi211r3/drivers/char/drm-4.0/drmP.h --- linux-2.4.19/drivers/char/drm-4.0/drmP.h Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/drmP.h Fri Apr 26 11:07:18 2002 @@ -510,6 +510,8 @@ int acquired; unsigned long base; int agp_mtrr; + int cant_use_aperture; + unsigned long page_mask; } drm_agp_head_t; #endif @@ -679,8 +681,10 @@ extern unsigned long drm_alloc_pages(int order, int area); extern void drm_free_pages(unsigned long address, int order, int area); -extern void *drm_ioremap(unsigned long offset, unsigned long size); -extern void drm_ioremapfree(void *pt, unsigned long size); +extern void *drm_ioremap(unsigned long offset, unsigned long size, + drm_device_t *dev); +extern void drm_ioremapfree(void *pt, unsigned long size, + drm_device_t *dev); #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) extern agp_memory *drm_alloc_agp(int pages, u32 type); diff -Nur linux-2.4.19/drivers/char/drm-4.0/ffb_drv.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/ffb_drv.c --- linux-2.4.19/drivers/char/drm-4.0/ffb_drv.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/ffb_drv.c Mon Oct 28 20:43:23 2002 @@ -158,7 +158,7 @@ switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: @@ -710,8 +710,7 @@ /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - current->policy |= SCHED_YIELD; - schedule(); + yield(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; diff -Nur linux-2.4.19/drivers/char/drm-4.0/gamma_drv.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/gamma_drv.c --- linux-2.4.19/drivers/char/drm-4.0/gamma_drv.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/gamma_drv.c Fri Apr 26 11:07:18 2002 @@ -258,7 +258,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -Nur linux-2.4.19/drivers/char/drm-4.0/i810_dma.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/i810_dma.c --- linux-2.4.19/drivers/char/drm-4.0/i810_dma.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/i810_dma.c Wed Oct 16 14:02:58 2002 @@ -309,7 +309,7 @@ if(dev_priv->ring.virtual_start) { drm_ioremapfree((void *) dev_priv->ring.virtual_start, - dev_priv->ring.Size); + dev_priv->ring.Size, dev); } if(dev_priv->hw_status_page != 0UL) { i810_free_page(dev, dev_priv->hw_status_page); @@ -323,7 +323,8 @@ for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - drm_ioremapfree(buf_priv->kernel_virtual, buf->total); + drm_ioremapfree(buf_priv->kernel_virtual, + buf->total, dev); } } return 0; @@ -397,7 +398,7 @@ *buf_priv->in_use = I810_BUF_FREE; buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, - buf->total); + buf->total, dev); } return 0; } @@ -434,7 +435,7 @@ dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + init->ring_start, - init->ring_size); + init->ring_size, dev); dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; diff -Nur linux-2.4.19/drivers/char/drm-4.0/i810_drv.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/i810_drv.c --- linux-2.4.19/drivers/char/drm-4.0/i810_drv.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/i810_drv.c Fri Apr 26 11:07:18 2002 @@ -286,7 +286,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -Nur linux-2.4.19/drivers/char/drm-4.0/memory.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/memory.c --- linux-2.4.19/drivers/char/drm-4.0/memory.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/memory.c Tue Jan 8 17:05:38 2002 @@ -296,7 +296,7 @@ } } -void *drm_ioremap(unsigned long offset, unsigned long size) +void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev) { void *pt; @@ -306,12 +306,50 @@ return NULL; } + if(dev->agp->cant_use_aperture == 0) { + goto standard_ioremap; + } else { + drm_map_t *map = NULL; + int i; + + for(i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (!map) continue; + if (map->offset <= offset && + (map->offset + map->size) >= (offset + size)) + break; + } + + if(map && map->type == _DRM_AGP) { + struct drm_agp_mem *agpmem; + + for(agpmem = dev->agp->memory; agpmem; + agpmem = agpmem->next) { + if(agpmem->bound <= offset && + (agpmem->bound + (agpmem->pages + << PAGE_SHIFT)) >= (offset + size)) + break; + } + + if(agpmem == NULL) + goto standard_ioremap; + + pt = agpmem->memory->vmptr + (offset - agpmem->bound); + goto ioremap_success; + } else { + goto standard_ioremap; + } + } + +standard_ioremap: if (!(pt = ioremap(offset, size))) { spin_lock(&drm_mem_lock); ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; spin_unlock(&drm_mem_lock); return NULL; } + +ioremap_success: spin_lock(&drm_mem_lock); ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; @@ -319,7 +357,7 @@ return pt; } -void drm_ioremapfree(void *pt, unsigned long size) +void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev) { int alloc_count; int free_count; @@ -327,7 +365,7 @@ if (!pt) DRM_MEM_ERROR(DRM_MEM_MAPPINGS, "Attempt to free NULL pointer\n"); - else + else if(dev->agp->cant_use_aperture == 0) iounmap(pt); spin_lock(&drm_mem_lock); diff -Nur linux-2.4.19/drivers/char/drm-4.0/mga_dma.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/mga_dma.c --- linux-2.4.19/drivers/char/drm-4.0/mga_dma.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/mga_dma.c Tue Jan 8 17:05:38 2002 @@ -308,7 +308,7 @@ temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, - temp); + temp, dev); if(dev_priv->ioremap == NULL) { DRM_ERROR("Ioremap failed\n"); return -ENOMEM; @@ -635,7 +635,7 @@ dev_priv->primary_size + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; - drm_ioremapfree((void *) dev_priv->ioremap, temp); + drm_ioremapfree((void *) dev_priv->ioremap, temp, dev); } if(dev_priv->status_page != NULL) { iounmap(dev_priv->status_page); @@ -741,10 +741,18 @@ return -ENOMEM; } - /* Write status page when secend or softrap occurs */ + /* Write status page when secend or softrap occurs + * + * Disable this on ia64 on the off chance that real status page will be + * above 4GB. + */ +#if defined(__ia64__) + MGA_WRITE(MGAREG_PRIMPTR, + virt_to_bus((void *)dev_priv->real_status_page)); +#else MGA_WRITE(MGAREG_PRIMPTR, virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); - +#endif /* Private is now filled in, initialize the hardware */ { diff -Nur linux-2.4.19/drivers/char/drm-4.0/mga_drv.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/mga_drv.c --- linux-2.4.19/drivers/char/drm-4.0/mga_drv.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/mga_drv.c Fri Apr 26 11:07:18 2002 @@ -286,7 +286,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -Nur linux-2.4.19/drivers/char/drm-4.0/mga_drv.h linux-2.4.19-sgi211r3/drivers/char/drm-4.0/mga_drv.h --- linux-2.4.19/drivers/char/drm-4.0/mga_drv.h Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/mga_drv.h Tue Jan 8 17:05:38 2002 @@ -295,7 +295,7 @@ num_dwords + 1 + outcount, ADRINDEX(reg), val); \ if( ++outcount == 4) { \ outcount = 0; \ - dma_ptr[0] = *(unsigned long *)tempIndex; \ + dma_ptr[0] = *(u32 *)tempIndex; \ dma_ptr+=5; \ num_dwords += 5; \ } \ diff -Nur linux-2.4.19/drivers/char/drm-4.0/r128_cce.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/r128_cce.c --- linux-2.4.19/drivers/char/drm-4.0/r128_cce.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/r128_cce.c Tue Jan 8 17:05:38 2002 @@ -86,12 +86,13 @@ }; -#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) +#define DO_REMAP(_m, _d) (_m)->handle = drm_ioremap((_m)->offset, \ + (_m)->size, (_d)) -#define DO_REMAPFREE(_m) \ +#define DO_REMAPFREE(_m, _d) \ do { \ if ((_m)->handle && (_m)->size) \ - drm_ioremapfree((_m)->handle, (_m)->size); \ + drm_ioremapfree((_m)->handle, (_m)->size, (_d)); \ } while (0) #define DO_FIND_MAP(_m, _o) \ @@ -229,7 +230,21 @@ int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { +#ifndef CONFIG_AGP_I460 if ( *dev_priv->ring.head == dev_priv->ring.tail ) { +#else + /* + * XXX - this is (I think) a 460GX specific hack + * + * When doing texturing, ring.tail sometimes gets ahead of + * PM4_BUFFER_DL_WPTR by 2; consequently, the card processes + * its whole quota of instructions and *ring.head is still 2 + * short of ring.tail. Work around this for now in lieu of + * a better solution. + */ + if ( (*dev_priv->ring.head == dev_priv->ring.tail) || + ((dev_priv->ring.tail - *dev_priv->ring.head) == 2) ) { +#endif int pm4stat = R128_READ( R128_PM4_STAT ); if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size ) && @@ -342,10 +357,34 @@ R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * XXX - This is a 460GX specific hack + * + * We have to hack this right now. 460GX isn't claiming PCI writes + * from the card into the AGP aperture. Because of this, we have + * to get space outside of the aperture for RPTR_ADDR. + */ + if(dev->agp->agp_info.chipset == INTEL_460GX) { + dev_priv->ring.head = (void *) + __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(dev_priv->ring.head)->count); + set_bit(PG_locked, &virt_to_page(dev_priv->ring.head)->flags); + dev_priv->ring.head = __va(dev_priv->ring.head); + + *dev_priv->ring.head = 0; + R128_WRITE(R128_PM4_BUFFER_DL_RPTR_ADDR, + __pa(dev_priv->ring.head)); + } else { +#else /* DL_RPTR_ADDR is a physical address in AGP space. */ *dev_priv->ring.head = 0; R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, dev_priv->ring_rptr->offset ); +#endif +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + } +#endif /* Set watermark control */ R128_WRITE( R128_PM4_BUFFER_WM_CNTL, @@ -481,12 +520,12 @@ (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DO_REMAP( dev_priv->cce_ring ); - DO_REMAP( dev_priv->ring_rptr ); - DO_REMAP( dev_priv->buffers ); + DO_REMAP( dev_priv->cce_ring, dev ); + DO_REMAP( dev_priv->ring_rptr, dev ); + DO_REMAP( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_REMAP( dev_priv->agp_textures ); + DO_REMAP( dev_priv->agp_textures, dev ); } #endif @@ -521,15 +560,28 @@ if ( dev->dev_private ) { drm_r128_private_t *dev_priv = dev->dev_private; - DO_REMAPFREE( dev_priv->cce_ring ); - DO_REMAPFREE( dev_priv->ring_rptr ); - DO_REMAPFREE( dev_priv->buffers ); + DO_REMAPFREE( dev_priv->cce_ring, dev ); + DO_REMAPFREE( dev_priv->ring_rptr, dev ); + DO_REMAPFREE( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_REMAPFREE( dev_priv->agp_textures ); + DO_REMAPFREE( dev_priv->agp_textures, dev ); } #endif +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * Free the page we grabbed for RPTR_ADDR + */ + if(dev->agp->agp_info.chipset == INTEL_460GX) { + atomic_dec(&virt_to_page(dev_priv->ring.head)->count); + clear_bit(PG_locked, + &virt_to_page(dev_priv->ring.head)->flags); + wake_up(&virt_to_page(dev_priv->ring.head)->wait); + free_page((unsigned long) dev_priv->ring.head); + } +#endif + drm_free( dev->dev_private, sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -Nur linux-2.4.19/drivers/char/drm-4.0/r128_drv.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/r128_drv.c --- linux-2.4.19/drivers/char/drm-4.0/r128_drv.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/r128_drv.c Fri Apr 26 11:07:18 2002 @@ -296,7 +296,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -Nur linux-2.4.19/drivers/char/drm-4.0/radeon_cp.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/radeon_cp.c --- linux-2.4.19/drivers/char/drm-4.0/radeon_cp.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/radeon_cp.c Tue Jan 8 17:05:38 2002 @@ -300,12 +300,13 @@ }; -#define DO_IOREMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) +#define DO_IOREMAP(_m, _d) (_m)->handle = drm_ioremap((_m)->offset, \ + (_m)->size, (_d)) -#define DO_IOREMAPFREE(_m) \ +#define DO_IOREMAPFREE(_m, _d) \ do { \ if ((_m)->handle && (_m)->size) \ - drm_ioremapfree((_m)->handle, (_m)->size); \ + drm_ioremapfree((_m)->handle, (_m)->size, (_d));\ } while (0) #define DO_FIND_MAP(_m, _o) \ @@ -592,11 +593,36 @@ /* Initialize the ring buffer's read and write pointers */ cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR ); RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr ); + +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * XXX - This is a 460GX specific hack + * + * We have to hack this right now. The GXB isn't claiming PCI writes + * from the card into the AGP aperture. Because of this, we have + * to get space outside of the aperture for RPTR_ADDR. + */ + if(dev->agp->agp_info.chipset == INTEL_460GX) { + dev_priv->ring.head = (void *) + __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(dev_priv->ring.head)->count); + set_bit(PG_locked, &virt_to_page(dev_priv->ring.head)->flags); + dev_priv->ring.head = __va(dev_priv->ring.head); + + *dev_priv->ring.head = cur_read_ptr; + dev_priv->ring.tail = cur_read_ptr; + + RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, __pa(dev_priv->ring.head)); + } else { +#else *dev_priv->ring.head = cur_read_ptr; dev_priv->ring.tail = cur_read_ptr; RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset ); - +#endif +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + } +#endif /* Set ring buffer size */ RADEON_WRITE( RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw ); @@ -757,12 +783,12 @@ (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DO_IOREMAP( dev_priv->cp_ring ); - DO_IOREMAP( dev_priv->ring_rptr ); - DO_IOREMAP( dev_priv->buffers ); + DO_IOREMAP( dev_priv->cp_ring, dev ); + DO_IOREMAP( dev_priv->ring_rptr, dev ); + DO_IOREMAP( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_IOREMAP( dev_priv->agp_textures ); + DO_IOREMAP( dev_priv->agp_textures, dev ); } #endif @@ -828,15 +854,28 @@ if ( dev->dev_private ) { drm_radeon_private_t *dev_priv = dev->dev_private; - DO_IOREMAPFREE( dev_priv->cp_ring ); - DO_IOREMAPFREE( dev_priv->ring_rptr ); - DO_IOREMAPFREE( dev_priv->buffers ); + DO_IOREMAPFREE( dev_priv->cp_ring, dev ); + DO_IOREMAPFREE( dev_priv->ring_rptr, dev ); + DO_IOREMAPFREE( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_IOREMAPFREE( dev_priv->agp_textures ); + DO_IOREMAPFREE( dev_priv->agp_textures, dev ); } #endif +#if defined(CONFIG_AGP_I460) && defined(__ia64__) + /* + * Free the page we grabbed for RPTR_ADDR. + */ + if(dev->agp->agp_info.chipset == INTEL_460GX) { + atomic_dec(&virt_to_page(dev_priv->ring.head)->count); + clear_bit(PG_locked, + &virt_to_page(dev_priv->ring.head)->flags); + wake_up(&virt_to_page(dev_priv->ring.head)->wait); + free_page((unsigned long) dev_priv->ring.head); + } +#endif + drm_free( dev->dev_private, sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -Nur linux-2.4.19/drivers/char/drm-4.0/radeon_drv.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/radeon_drv.c --- linux-2.4.19/drivers/char/drm-4.0/radeon_drv.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/radeon_drv.c Fri Apr 26 11:07:18 2002 @@ -294,7 +294,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -Nur linux-2.4.19/drivers/char/drm-4.0/radeon_drv.h linux-2.4.19-sgi211r3/drivers/char/drm-4.0/radeon_drv.h --- linux-2.4.19/drivers/char/drm-4.0/radeon_drv.h Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/radeon_drv.h Tue Jan 8 17:05:38 2002 @@ -535,7 +535,7 @@ #define RADEON_MAX_VB_VERTS (0xffff) -#define RADEON_BASE(reg) ((u32)(dev_priv->mmio->handle)) +#define RADEON_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) #define RADEON_ADDR(reg) (RADEON_BASE(reg) + reg) #define RADEON_DEREF(reg) *(__volatile__ u32 *)RADEON_ADDR(reg) diff -Nur linux-2.4.19/drivers/char/drm-4.0/tdfx_drv.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/tdfx_drv.c --- linux-2.4.19/drivers/char/drm-4.0/tdfx_drv.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/tdfx_drv.c Mon Oct 28 20:43:23 2002 @@ -264,7 +264,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, @@ -554,7 +554,6 @@ lock.context, current->pid, j, dev->lock.lock_time, jiffies); current->state = TASK_INTERRUPTIBLE; - current->policy |= SCHED_YIELD; schedule_timeout(DRM_LOCK_SLICE-j); DRM_DEBUG("jiffies=%d\n", jiffies); } @@ -578,10 +577,7 @@ /* Contention */ atomic_inc(&dev->total_sleeps); -#if 1 - current->policy |= SCHED_YIELD; -#endif - schedule(); + yield(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; @@ -604,8 +600,7 @@ when dev->last_context == lock.context NOTE WE HOLD THE LOCK THROUGHOUT THIS TIME! */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); current->state = TASK_RUNNING; remove_wait_queue(&dev->context_wait, &entry); if (signal_pending(current)) { diff -Nur linux-2.4.19/drivers/char/drm-4.0/vm.c linux-2.4.19-sgi211r3/drivers/char/drm-4.0/vm.c --- linux-2.4.19/drivers/char/drm-4.0/vm.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/drm-4.0/vm.c Tue Aug 27 19:53:13 2002 @@ -30,6 +30,7 @@ */ #define __NO_VERSION__ +#include #include "drmP.h" struct vm_operations_struct drm_vm_ops = { @@ -67,6 +68,65 @@ int write_access) #endif { +#if defined(__ia64__) + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + int i; + + /* + * Find the right map + */ + + if(!dev->agp->cant_use_aperture) goto vm_nopage_error; + + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (!map) continue; + if (map->offset == VM_OFFSET(vma)) break; + } + + if (map && map->type == _DRM_AGP) { + unsigned long offset = address - vma->vm_start; + unsigned long baddr = VM_OFFSET(vma) + offset, paddr; + struct drm_agp_mem *agpmem; + struct page *page; + + /* + * It's AGP memory - find the real physical page to map + */ + for(agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { + if (agpmem->bound <= baddr && + agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) + break; + } + + if (!agpmem) goto vm_nopage_error; + + /* + * Get the page, inc the use count, and return it + */ + offset = (baddr - agpmem->bound) >> PAGE_SHIFT; + + /* + * This is bad. What we really want to do here is unmask + * the GART table entry held in the agp_memory structure. + * There isn't a convenient way to call agp_bridge.unmask_ + * memory from here, so hard code it for now. + */ + paddr = (agpmem->memory->memory[offset] & 0xffffff) << 12; + + page = virt_to_page(__va(paddr)); + get_page(page); + +#if LINUX_VERSION_CODE < 0x020317 + return page_address(page); +#else + return page; +#endif + } +vm_nopage_error: +#endif return NOPAGE_SIGBUS; /* Disallow mremap */ } @@ -272,6 +332,7 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_map_t *map = NULL; + unsigned long off; int i; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", @@ -288,7 +349,16 @@ bit longer. */ for (i = 0; i < dev->map_count; i++) { map = dev->maplist[i]; - if (map->offset == VM_OFFSET(vma)) break; + off = map->offset ^ VM_OFFSET(vma); +#ifdef __ia64__ + /* + * Ignore region bits, makes IA32 processes happier + * XXX This is a hack... + */ + off &= ~0xe000000000000000; +#endif // __ia64__ + if (off == 0) + break; } if (i >= dev->map_count) return -EINVAL; @@ -312,11 +382,21 @@ } switch (map->type) { + case _DRM_AGP: +#if defined(__ia64__) + /* + * On ia64 we can't talk to bus dma address from + * the CPU, so for memory of type DRM_AGP, we'll deal with + * sorting out the real physical pages and mappings in + * in nopage() + */ + vma->vm_ops = &drm_vm_ops; + break; +#endif case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: - case _DRM_AGP: if (VM_OFFSET(vma) >= __pa(high_memory)) { -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; diff -Nur linux-2.4.19/drivers/char/efirtc.c linux-2.4.19-sgi211r3/drivers/char/efirtc.c --- linux-2.4.19/drivers/char/efirtc.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/efirtc.c Wed Oct 16 14:02:58 2002 @@ -35,8 +35,8 @@ #include #include #include +#include -#include #include #include diff -Nur linux-2.4.19/drivers/char/hcdp_serial.c linux-2.4.19-sgi211r3/drivers/char/hcdp_serial.c --- linux-2.4.19/drivers/char/hcdp_serial.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/hcdp_serial.c Wed Oct 16 14:02:58 2002 @@ -15,9 +15,9 @@ #include #include #include +#include #include #include -#include #include #undef SERIAL_DEBUG_HCDP @@ -219,3 +219,41 @@ printk("Leaving setup_serial_hcdp()\n"); #endif } + +#ifdef CONFIG_IA64_EARLY_PRINTK_UART +unsigned long hcdp_early_uart(void) +{ + efi_system_table_t *systab; + efi_config_table_t *config_tables; + hcdp_t *hcdp = 0; + hcdp_dev_t *dev; + int i; + + systab = (efi_system_table_t *) ia64_boot_param->efi_systab; + if (!systab) + return 0; + systab = __va(systab); + + config_tables = (efi_config_table_t *) systab->tables; + if (!config_tables) + return 0; + config_tables = __va(config_tables); + + for (i = 0; i < systab->nr_tables; i++) { + if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) { + hcdp = (hcdp_t *) config_tables[i].table; + break; + } + } + if (!hcdp) + return 0; + hcdp = __va(hcdp); + + for (i = 0, dev = hcdp->hcdp_dev; i < hcdp->num_entries; i++, dev++) { + if (dev->type == HCDP_DEV_CONSOLE) + return (u64) dev->base_addr.addrhi << 32 + | dev->base_addr.addrlo; + } + return 0; +} +#endif diff -Nur linux-2.4.19/drivers/char/keyboard.c linux-2.4.19-sgi211r3/drivers/char/keyboard.c --- linux-2.4.19/drivers/char/keyboard.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/keyboard.c Wed Oct 16 14:02:58 2002 @@ -42,6 +42,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -238,6 +241,13 @@ up_flag = kbd_unexpected_up(keycode); } else rep = test_and_set_bit(keycode, key_down); + +#ifdef CONFIG_KDB + if (!up_flag && (keycode == E1_PAUSE) && kdb_on) { + kdb(KDB_REASON_KEYBOARD, 0, kbd_pt_regs); + return; + } +#endif /* CONFIG_KDB */ #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) { diff -Nur linux-2.4.19/drivers/char/mem.c linux-2.4.19-sgi211r3/drivers/char/mem.c --- linux-2.4.19/drivers/char/mem.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/mem.c Mon Oct 28 20:43:23 2002 @@ -21,11 +21,16 @@ #include #include #include +#include #include #include #include +#ifdef CONFIG_IA64_SGI_SN2 +#include +#endif + #ifdef CONFIG_I2C extern int i2c_init_all(void); #endif @@ -177,6 +182,13 @@ test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) || test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) && addr >= __pa(high_memory); +#elif defined(CONFIG_IA64_SGI_SN2) + return !IS_CACHED_ADDRESS(addr); +#elif defined(__ia64__) + struct page *page; + + page = virt_to_page(__va(addr)); + return !VALID_PAGE(page) || PageReserved(page); #else return addr >= __pa(high_memory); #endif @@ -191,9 +203,15 @@ * through a file pointer that was marked O_SYNC will be * done non-cached. */ - if (noncached_address(offset) || (file->f_flags & O_SYNC)) + if (noncached_address(offset) || (file->f_flags & O_SYNC) + || (vma->vm_flags & VM_NONCACHED)) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#ifdef MAP_WRITECOMBINED + if (vma->vm_flags & VM_WRITECOMBINED) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#endif + /* Don't try to swap out physical pages.. */ vma->vm_flags |= VM_RESERVED; @@ -503,16 +521,24 @@ */ static loff_t memory_lseek(struct file * file, loff_t offset, int orig) { + loff_t ret; + + lock_kernel(); switch (orig) { case 0: file->f_pos = offset; - return file->f_pos; + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return file->f_pos; + ret = file->f_pos; + break; default: - return -EINVAL; + ret = -EINVAL; } + force_successful_syscall_return(); + unlock_kernel(); + return ret; } static int open_port(struct inode * inode, struct file * filp) diff -Nur linux-2.4.19/drivers/char/mwave/mwavedd.c linux-2.4.19-sgi211r3/drivers/char/mwave/mwavedd.c --- linux-2.4.19/drivers/char/mwave/mwavedd.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-sgi211r3/drivers/char/mwave/mwavedd.c Mon Oct 28 20:43:23 2002 @@ -279,7 +279,6 @@ pDrvData->IPCs[ipcnum].bIsHere = FALSE; pDrvData->IPCs[ipcnum].bIsEnabled = TRUE; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - current->nice = -20; /* boost to provide priority timing */ #else current->priority = 0x28; /* boost to provide priority timing */ #endif diff -Nur linux-2.4.19/drivers/char/n_tty.c linux-2.4.19-sgi211r3/drivers/char/n_tty.c --- linux-2.4.19/drivers/char/n_tty.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/n_tty.c Wed Feb 5 13:36:49 2003 @@ -119,7 +119,7 @@ */ static void check_unthrottle(struct tty_struct * tty) { - if (tty->count && + if (READ_THE_COUNTER(tty->count) && test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); @@ -828,7 +828,7 @@ I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { - cli(); + spin_lock_irq(&tty->struct_lock); memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) @@ -864,7 +864,7 @@ set_bit(SUSP_CHAR(tty), &tty->process_char_map); } clear_bit(__DISABLED_CHAR, &tty->process_char_map); - sti(); + spin_unlock_irq(&tty->struct_lock); tty->raw = 0; tty->real_raw = 0; } else { @@ -1170,7 +1170,7 @@ retval = -ERESTARTSYS; break; } - if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { + if (tty_hung_up_p(file) || (tty->link && !READ_THE_COUNTER(tty->link->count))) { retval = -EIO; break; } diff -Nur linux-2.4.19/drivers/char/nvram.c linux-2.4.19-sgi211r3/drivers/char/nvram.c --- linux-2.4.19/drivers/char/nvram.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/nvram.c Mon Oct 28 20:43:23 2002 @@ -213,6 +213,7 @@ static long long nvram_llseek(struct file *file,loff_t offset, int origin ) { + lock_kernel(); switch( origin ) { case 0: /* nothing to do */ @@ -224,6 +225,7 @@ offset += NVRAM_BYTES; break; } + unlock_kernel(); return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL ); } diff -Nur linux-2.4.19/drivers/char/nwflash.c linux-2.4.19-sgi211r3/drivers/char/nwflash.c --- linux-2.4.19/drivers/char/nwflash.c Fri Oct 12 13:48:42 2001 +++ linux-2.4.19-sgi211r3/drivers/char/nwflash.c Mon Oct 28 20:43:23 2002 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -301,30 +302,45 @@ */ static long long flash_llseek(struct file *file, long long offset, int orig) { + long long ret; + + lock_kernel(); if (flashdebug) printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n", (unsigned int) offset, orig); switch (orig) { case 0: - if (offset < 0) - return -EINVAL; + if (offset < 0) { + ret = -EINVAL; + break; + } - if ((unsigned int) offset > gbFlashSize) - return -EINVAL; + if ((unsigned int) offset > gbFlashSize) { + ret = -EINVAL; + break; + } file->f_pos = (unsigned int) offset; - return file->f_pos; + ret = file->f_pos; + break; case 1: - if ((file->f_pos + offset) > gbFlashSize) - return -EINVAL; - if ((file->f_pos + offset) < 0) - return -EINVAL; + if ((file->f_pos + offset) > gbFlashSize) { + ret = -EINVAL; + break; + } + if ((file->f_pos + offset) < 0) { + ret = -EINVAL; + break; + } file->f_pos += offset; - return file->f_pos; + ret = file->f_pos; + break; default: - return -EINVAL; + ret = -EINVAL; } + unlock_kernel(); + return ret; } diff -Nur linux-2.4.19/drivers/char/pc_keyb.c linux-2.4.19-sgi211r3/drivers/char/pc_keyb.c --- linux-2.4.19/drivers/char/pc_keyb.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/pc_keyb.c Wed Oct 16 14:02:58 2002 @@ -69,6 +69,9 @@ static int aux_reconnect = 0; #endif +#ifndef kbd_controller_present +#define kbd_controller_present() 1 +#endif static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; static unsigned char handle_kbd_event(void); @@ -895,6 +898,11 @@ void __init pckbd_init_hw(void) { + if (!kbd_controller_present()) { + kbd_exists = 0; + return; + } + kbd_request_region(); /* Flush any pending input. */ diff -Nur linux-2.4.19/drivers/char/pty.c linux-2.4.19-sgi211r3/drivers/char/pty.c --- linux-2.4.19/drivers/char/pty.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/pty.c Wed Oct 16 14:02:58 2002 @@ -73,10 +73,10 @@ if (!tty) return; if (tty->driver.subtype == PTY_TYPE_MASTER) { - if (tty->count > 1) - printk("master pty_close: count = %d!!\n", tty->count); + if (READ_THE_COUNTER(tty->count) > 1) + printk("master pty_close: count = %d!!\n", READ_THE_COUNTER(tty->count)); } else { - if (tty->count > 2) + if (READ_THE_COUNTER(tty->count) > 2) return; } wake_up_interruptible(&tty->read_wait); @@ -329,7 +329,7 @@ goto out; if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) goto out; - if (tty->link->count != 1) + if (READ_THE_COUNTER(tty->link->count) != 1) goto out; clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); diff -Nur linux-2.4.19/drivers/char/serial.c linux-2.4.19-sgi211r3/drivers/char/serial.c --- linux-2.4.19/drivers/char/serial.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/serial.c Wed Jan 22 16:59:02 2003 @@ -223,6 +223,29 @@ #include #endif +#ifdef CONFIG_KDB +#include +/* + * kdb_serial_line records the serial line number of the first serial console. + * NOTE: The kernel ignores characters on the serial line unless a user space + * program has opened the line first. To enter kdb before user space has opened + * the serial line, you can use the 'kdb=early' flag to lilo and set the + * appropriate breakpoints. + * + * kdb_serial_str[] is the sequence that the user must enter on the serial + * console to invoke kdb. It can be a single character such as "\001" + * (control-A) or multiple characters such as "\eKdB". NOTE: All except the + * last character are passed through to the application reading from the serial + * console. + * + * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope + * with '\' in strings, CML2 should be able to do it. KAO. + */ + +static int kdb_serial_line = -1; +static char kdb_serial_str[] = "\eKDB"; +static char *kdb_serial_ptr = kdb_serial_str; +#endif /* CONFIG_KDB */ /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h @@ -281,7 +304,9 @@ static int lsr_break_flag; #endif #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -static unsigned long break_pressed; /* break, really ... */ +static char sysrq_serial_str[] = "\eSYS"; +static char *sysrq_serial_ptr = sysrq_serial_str; +static unsigned long sysrq_requested; #endif static unsigned detect_uart_irq (struct serial_state * state); @@ -577,6 +602,18 @@ return; // if TTY_DONT_FLIP is set } ch = serial_inp(info, UART_RX); +#ifdef CONFIG_KDB + if ((info->line == kdb_serial_line) && kdb_on) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + kdb(KDB_REASON_KEYBOARD, 0, regs); + kdb_serial_ptr = kdb_serial_str; + break; + } + } else + kdb_serial_ptr = kdb_serial_str; + } +#endif /* CONFIG_KDB */ *tty->flip.char_buf_ptr = ch; icount->rx++; @@ -593,20 +630,11 @@ *status &= ~(UART_LSR_FE | UART_LSR_PE); icount->brk++; /* - * We do the SysRQ and SAK checking + * We do the SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask. */ -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (info->line == sercons.index) { - if (!break_pressed) { - break_pressed = jiffies; - goto ignore_char; - } - break_pressed = 0; - } -#endif if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (*status & UART_LSR_PE) @@ -639,16 +667,24 @@ *tty->flip.flag_buf_ptr = TTY_FRAME; } #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (break_pressed && info->line == sercons.index) { - if (ch != 0 && - time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); - break_pressed = 0; - goto ignore_char; + if (info->line == sercons.index) { + if (sysrq_requested) { + unsigned long sysrq_timeout = sysrq_requested + HZ*5; + sysrq_requested = 0; + if (ch && time_before(jiffies, sysrq_timeout)) { + handle_sysrq(ch, regs, NULL, NULL); + goto ignore_char; + } } - break_pressed = 0; + if (ch == *sysrq_serial_ptr) { + if (!(*++sysrq_serial_ptr)) { + sysrq_requested = jiffies; + sysrq_serial_ptr = sysrq_serial_str; + } + } else + sysrq_serial_ptr = sysrq_serial_str; } -#endif +#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ if ((*status & info->ignore_status_mask) == 0) { tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; @@ -5987,6 +6023,24 @@ */ if (serial_in(info, UART_LSR) == 0xff) return -1; + +#ifdef CONFIG_KDB + /* + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. + */ + if (kdb_serial_line == -1) { + kdb_serial_line = co->index; + kdb_serial.io_type = info->io_type; + if (info->io_type == SERIAL_IO_MEM) { + kdb_serial.iobase = (int)(info->iomem_base); + kdb_serial.ioreg_shift = info->iomem_reg_shift; + } else { + kdb_serial.iobase = state->port; + kdb_serial.ioreg_shift = 0; + } + } +#endif /* CONFIG_KDB */ return 0; } diff -Nur linux-2.4.19/drivers/char/sgi-l1_protocol.c linux-2.4.19-sgi211r3/drivers/char/sgi-l1_protocol.c --- linux-2.4.19/drivers/char/sgi-l1_protocol.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/char/sgi-l1_protocol.c Wed Jan 22 16:59:02 2003 @@ -0,0 +1,2471 @@ +/* + * $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. + * + * This driver was originally based off the drivers/char/serial.c driver. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, + * 1998, 1999 Theodore Ts'o + */ + +/* + * Serial driver configuration section. Here are the various options: + * + * SERIAL_PARANOIA_CHECK + * Check the magic number for the async_structure where + * ever possible. + */ + +#include +#include + +#undef SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_PCI +#undef SERIAL_DEBUG_AUTOCONF + +/* Sanity checks */ + +#define RS_STROBE_TIME (10*HZ) +#define RS_ISR_PASS_LIMIT 256 + +/* + * End of serial driver configuration section. + */ + +#ifdef MODVERSIONS +#include +#endif +#include + +#include +#ifdef LOCAL_HEADERS +#include "serial_local.h" +#else +#include +#include +#include +#include +#include +#define LOCAL_VERSTRING "" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= 131343) +#include +#endif +#if (LINUX_VERSION_CODE >= 131336) +#include +#endif +#include +#include +#ifdef CONFIG_MAGIC_SYSRQ +#include +#endif +#include + +#undef CONFIGURED_SERIAL_PORT +#define CONFIGURED_SERIAL_PORT(x) (1) + +static char *serial_name = "SGI L1 Protocol Serial driver"; +static char *serial_version = "2.3"; +static char *serial_revdate = "2002-12-02"; + +#define USING_L1_FUNCS 1 + +static DECLARE_TASK_QUEUE(tq_serial); + + +/* We need to know when it IS data and when it is not */ +#define L1_REG_DAT_BIT (0x800) +#define L1_REG_DAT (REG_DAT | L1_REG_DAT_BIT) + +#ifdef CONFIG_KDB +#include +/* + * kdb_serial_line records the serial line number of the first serial console. + * NOTE: The kernel ignores characters on the serial line unless a user space + * program has opened the line first. To enter kdb before user space has opened + * the serial line, you can use the 'kdb=early' flag to lilo and set the + * appropriate breakpoints. + * + * kdb_serial_str[] is the sequence that the user must enter on the serial + * console to invoke kdb. It can be a single character such as "\001" + * (control-A) or multiple characters such as "\eKdB". NOTE: All except the + * last character are passed through to the application reading from the serial + * console. + * + * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope + * with '\' in strings, CML2 should be able to do it. KAO. + */ + +static int kdb_serial_line = -1; +static char kdb_serial_str[] = "\eKDB"; +static char *kdb_serial_ptr = kdb_serial_str; +#endif /* CONFIG_KDB */ +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in serial_compat.h + */ +#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ +#include "serial_compat.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 2 +#else +#define SERIAL_DEV_OFFSET 0 +#endif + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#else +#define _INLINE_ +#endif + +#undef RS_TABLE_SIZE +#define RS_TABLE_SIZE 64 + +static struct tty_driver l1_serial_driver, l1_callout_driver; +static int l1_cons_serial_refcount; + +extern int l1_get_intr_value(void); + +static struct timer_list serial_timer; + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +static struct async_struct *IRQ_ports; +static int IRQ_timeout; +static struct console sgiconsole; +static int lsr_break_flag = 0; +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +static char sysrq_serial_str[] = "\eSYS"; +static char *sysrq_serial_ptr = sysrq_serial_str; +static unsigned long sysrq_requested; +#endif + +static void autoconfig(struct serial_state * state); +static void change_speed(struct async_struct *info, struct termios *old); +static void l1_cons_wait_until_sent(struct tty_struct *tty, int timeout); + +/* + * Here we define the default xmit fifo size used for each type of + * UART + */ +static struct serial_uart_config uart_config[] = { + { "unknown", 1, 0 }, + { "8250", 1, 0 }, + { "16450", 1, 0 }, + { "16550", 1, 0 }, + { "16550A", 100, 0 }, + { 0, 0} +}; + +static struct serial_state l1_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +#define NR_PORTS (sizeof(l1_table)/sizeof(struct serial_state)) + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + +static struct tty_struct *l1_cons_serial_table[NR_PORTS]; +static struct termios *l1_cons_serial_termios[NR_PORTS]; +static struct termios *l1_cons_serial_termios_locked[NR_PORTS]; +static spinlock_t l1_port_lock[NR_PORTS]; + + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), l1_cons_serial_refcount,READ_THE_COUNTER(info->count),READ_THE_COUNTER(tty->count),s) +#else +#define DBG_CNT(s) +#endif + +/* + * l1_tmp_buffer is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *l1_tmp_buffer; +static DECLARE_MUTEX(l1_tmp_buffer_sem); + +static inline int +serial_paranoia_check(struct async_struct *info, kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +static _INLINE_ unsigned int +serial_in(struct async_struct *info, int p_offset) +{ + int offset = p_offset & (L1_REG_DAT_BIT - 1); + + switch (info->io_type) { + case SERIAL_IO_MEM: +#if defined(CONFIG_IA64_SGI_SN1) + if ( IS_RUNNING_ON_SIMULATOR() ) { + return readb((unsigned long) info->iomem_base + + (offset<iomem_reg_shift)); + } else +#endif /* CONFIG_IA64_SGI_SN1 */ + { + if ( p_offset == L1_REG_DAT ) { + /* Text */ + unsigned int value = 0; + extern int l1_serial_in(void); + value = (unsigned int)l1_serial_in(); + return(value); + } + else { + int l1_control_in(int); + return(l1_control_in(offset)); + } + } + default: + return inb(info->port + offset); + } +} + +static _INLINE_ void +serial_out(struct async_struct *info, int p_offset, int value) +{ + int offset = p_offset & (L1_REG_DAT_BIT - 1); + + switch (info->io_type) { + case SERIAL_IO_MEM: +#if defined(CONFIG_IA64_SGI_SN1) + if ( IS_RUNNING_ON_SIMULATOR() ) { + writeb(value, (unsigned long) info->iomem_base + + (offset<iomem_reg_shift)); + } else +#endif /* CONFIG_IA64_SGI_SN1 */ + { + if ( p_offset == L1_REG_DAT ) { + /* Text */ + extern int l1_serial_out(char *, int); + char ch = (char)value; + (void)l1_serial_out(&ch, 1); + } + else { + void l1_control_out(int offset, int value); + l1_control_out(offset, value); + } + } + break; + default: + outb(value, info->port+offset); + } +} + +static void +l1_cons_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "l1_cons_start")) + return; +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void +l1_cons_sched_event(struct async_struct *info, int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static _INLINE_ void +receive_chars(struct async_struct *info, int *status, struct pt_regs * regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + struct async_icount *icount; + + icount = &info->state->icount; + do { + ch = (unsigned char)serial_in(info, L1_REG_DAT); +#ifdef CONFIG_KDB + if ((info->line == kdb_serial_line) && kdb_on) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + kdb(KDB_REASON_KEYBOARD, 0, regs); + kdb_serial_ptr = kdb_serial_str; + break; + } + } else + kdb_serial_ptr = kdb_serial_str; + } +#endif /* CONFIG_KDB */ +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (sysrq_requested) { + unsigned long sysrq_timeout = sysrq_requested + HZ*5; + sysrq_requested = 0; + if (ch && time_before(jiffies, sysrq_timeout)) { + handle_sysrq(ch, regs, NULL, NULL); + goto ignore_char; + } + } + if (ch == *sysrq_serial_ptr) { + if (!(*++sysrq_serial_ptr)) { + sysrq_requested = jiffies; + sysrq_serial_ptr = sysrq_serial_str; + } + } else + sysrq_serial_ptr = sysrq_serial_str; +#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ + *tty->flip.char_buf_ptr = ch; + icount->rx++; + + *tty->flip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + ignore_char: +#endif + *status = serial_in(info, REG_LSR); + } while (*status & LSR_RCA); +#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ + tty_flip_buffer_push(tty); +#else + queue_task(&tty->flip.tqueue, &tq_timer); +#endif +} + +static _INLINE_ void +transmit_chars(struct async_struct *info, int *intr_done) +{ + int xmit_count, tail, head; + char *start; + unsigned long flags; + extern int l1_serial_out(char *, int); + + if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { + /* Nothing to do */ + return; + } + + /* Make sure no one gets here until we have drained the buffer */ + + spin_lock_irqsave(&l1_port_lock[info->line], flags); + + head = info->xmit.head; + tail = info->xmit.tail; + start = (char *)&info->xmit.buf[tail]; + + if ( head < tail ) { + /* Empty to end of buffer */ + xmit_count = SERIAL_XMIT_SIZE - tail; + info->state->icount.tx += xmit_count; + (void)l1_serial_out(start, xmit_count); + tail = 0; + start = (char *)&info->xmit.buf[tail]; + /* fall thru to get the rest */ + } + xmit_count = head - tail; + if ( xmit_count > 0 ) { + info->state->icount.tx += xmit_count; + (void)l1_serial_out(start, xmit_count); + } + info->xmit.tail = head; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + + if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + l1_cons_sched_event(info, RS_EVENT_WRITE_WAKEUP); + + if (intr_done) + *intr_done = 0; +} + + +/* + * This is the serial driver's interrupt routine + */ + +static void +l1_cons_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int status; + struct async_struct * info; + + info = IRQ_ports; + if (!info || !info->tty) + return; + + status = serial_in(info, REG_LSR); + if (status & LSR_RCA) + receive_chars(info, &status, regs); + if (status & LSR_XHRE) + transmit_chars(info, 0); + + info->last_active = jiffies; +} + + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using l1_cons_sched_event(), and they get done here. + */ +static void +do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void +do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + } +} + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives barely + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). + */ +static void +l1_cons_timer(unsigned long dummy) +{ + /* Special case for irq == 0. That is the same as polled mode */ + if ( (IRQ_ports != (struct async_struct *)0) && IRQ_ports->state->irq == 0 ) { + l1_cons_interrupt(0, NULL, NULL); + mod_timer(&serial_timer, jiffies + IRQ_timeout); + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. Now only used for IRQ 0.... + */ +static void +figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 60*HZ; /* 60 seconds === a long time :-) */ + + info = IRQ_ports; + if (!info) { + IRQ_timeout = 60*HZ; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout = timeout ? timeout : 1; +} + +//#define CONSOLE_POLLING_ALSO + +#ifdef CONSOLE_POLLING_ALSO +static void +l1_cons_null(int irq, void *dev_id, struct pt_regs *regs) +{ + /* as the name implies */ +} +#endif + +static int +startup(struct async_struct * info) +{ + int retval=0; + struct serial_state *state= info->state; + unsigned long page; + unsigned long flags; + void l1_connect_intr(void *, void *); + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + spin_lock_irqsave(&l1_port_lock[info->line], flags); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!CONFIGURED_SERIAL_PORT(state) || !state->type) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports = info; + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; + + /* + * Set up serial timers... + */ + mod_timer(&serial_timer, jiffies + 2*HZ/100); + + /* + * Set up the tty->alt_speed kludge + */ +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } +#endif + + /* + * and set the speed of the serial port + */ + change_speed(info, 0); + + /* + * Call the lower-level callback function for incoming packets and + * register for the interrupt. + */ + figure_IRQ_timeout(state->irq); + + if ( state->irq ) { + if ( !(IS_RUNNING_ON_SIMULATOR()) ) + l1_connect_intr((void *)l1_cons_interrupt, (void *)l1_cons_interrupt); + } +#ifdef CONSOLE_POLLING_ALSO + if ( !(IS_RUNNING_ON_SIMULATOR()) ) + l1_connect_intr((void *)l1_cons_null, (void *)l1_cons_null); +#endif + info->flags |= ASYNC_INITIALIZED; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + return 0; + +errout: + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void +shutdown(struct async_struct * info) +{ + struct serial_state *state; + void l1_unconnect_intr(void); + unsigned long flags; + + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + spin_lock_irqsave(&l1_port_lock[info->line], flags); + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports = info->next_port; + figure_IRQ_timeout(state->irq); + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + if ( !(IS_RUNNING_ON_SIMULATOR()) ) + l1_unconnect_intr(); + info->flags &= ~ASYNC_INITIALIZED; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); +} + +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, + 600, 1200, 1800, 2400, 4800, 9600, 19200, + 38400, 57600, 115200, 230400, 460800, 0 }; + +static int +tty_get_baud_rate(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned int cflag, i; + + cflag = tty->termios->c_cflag; + + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 2) + tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 2; + } + return baud_table[i]; +} +#endif + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void +change_speed(struct async_struct *info, + struct termios *old_termios) +{ + int quot = 0, baud_base, baud; + unsigned cflag, cval; + int bits; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!CONFIGURED_SERIAL_PORT(info)) + return; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: cval = 0x00; bits = 7; break; + case CS6: cval = 0x01; bits = 8; break; + case CS7: cval = 0x02; bits = 9; break; + case CS8: cval = 0x03; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: cval = 0x00; bits = 7; break; + } + if (cflag & CSTOPB) { + cval |= 0x04; + bits++; + } + if (cflag & PARENB) { + cval |= LCR_PAREN; + bits++; + } + if (!(cflag & PARODD)) + cval |= LCR_PAREVN; +#ifdef CMSPAR + if (cflag & CMSPAR) + cval |= LCR_PARMARK; +#endif + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in l1_cons_set_termios */ + baud_base = info->state->baud_base; + + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = baud_base / 9600; + /* + * Work around a bug in the Oxford Semiconductor 952 rev B + * chip which causes it to seriously miscalculate baud rates + * when DLL is 0. + */ + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + } else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + } + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = LSR_OVRRUN | LSR_XHRE | LSR_RCA; + if (I_INPCK(info->tty)) + info->read_status_mask |= LSR_FRMERR | LSR_PARERR; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= LSR_BRKDET; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= LSR_PARERR | LSR_FRMERR; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= LSR_BRKDET; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= LSR_OVRRUN; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= LSR_RCA; + serial_out(info, REG_LCR, cval | LCR_DLAB); /* set DLAB */ + serial_out(info, REG_DLL, quot & 0xff); /* LS of divisor */ + serial_out(info, REG_DLH, quot >> 8); /* MS of divisor */ + serial_out(info, REG_LCR, cval); /* reset DLAB */ +} + +static void +l1_cons_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "l1_cons_put_char")) + return; + + if (!tty || !info->xmit.buf) + return; + + spin_lock_irqsave(&l1_port_lock[info->line], flags); + if (CIRC_SPACE(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) == 0) { + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + return; + } + + info->xmit.buf[info->xmit.head] = ch; + info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + transmit_chars(info, 0); +} + +static int +l1_cons_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "l1_cons_write")) + return 0; + + if (!tty || !info->xmit.buf || !l1_tmp_buffer) + return 0; + + if (from_user) { + down(&l1_tmp_buffer_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(l1_tmp_buffer, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + spin_lock_irqsave(&l1_port_lock[info->line], flags); + c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, l1_tmp_buffer, c); + info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1)); + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + buf += c; + count -= c; + ret += c; + } + up(&l1_tmp_buffer_sem); + } else { + spin_lock_irqsave(&l1_port_lock[info->line], flags); + while (1) { + c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1)); + buf += c; + count -= c; + ret += c; + } + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + } + if ( (info->xmit.head != info->xmit.tail) && !tty->stopped && !tty->hw_stopped ) { + transmit_chars(info, 0); + } + return ret; +} + +static int +l1_cons_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "l1_cons_write_room")) + return 0; + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static int +l1_cons_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "l1_cons_chars_in_buffer")) + return 0; + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static void +l1_cons_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "l1_cons_flush_buffer")) + return; + spin_lock_irqsave(&l1_port_lock[info->line], flags); + info->xmit.head = info->xmit.tail = 0; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * ------------------------------------------------------------ + * l1_cons_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int +get_serial_info(struct async_struct * info, struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct serial_state *state = info->state; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = state->type; + tmp.line = state->line; + tmp.port = state->port; + if (HIGH_BITS_OFFSET) + tmp.port_high = state->port >> HIGH_BITS_OFFSET; + else + tmp.port_high = 0; + tmp.irq = state->irq; + tmp.flags = state->flags; + tmp.xmit_fifo_size = state->xmit_fifo_size; + tmp.baud_base = state->baud_base; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + tmp.hub6 = state->hub6; + tmp.io_type = state->io_type; + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int +set_serial_info(struct async_struct * info, struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct serial_state old_state, *state; + unsigned int i,change_irq,change_port; + int retval = 0; + unsigned long new_port; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + state = info->state; + old_state = *state; + + new_port = new_serial.port; + if (HIGH_BITS_OFFSET) + new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + + change_irq = new_serial.irq != state->irq; + change_port = (new_port != ((int) state->port)) || + (new_serial.hub6 != state->hub6); + + if (!capable(CAP_SYS_ADMIN)) { + if (change_irq || change_port || + (new_serial.baud_base != state->baud_base) || + (new_serial.type != state->type) || + (new_serial.close_delay != state->close_delay) || + (new_serial.xmit_fifo_size != state->xmit_fifo_size) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (state->flags & ~ASYNC_USR_MASK))) + return -EPERM; + state->flags = ((state->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if ( IS_RUNNING_ON_SIMULATOR() ) + new_serial.irq = 0; + else + new_serial.irq = l1_get_intr_value(); + + if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || + (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || + (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || + (new_serial.type == PORT_STARTECH)) { + return -EINVAL; + } + + if ((new_serial.type != state->type) || (new_serial.xmit_fifo_size <= 0)) + new_serial.xmit_fifo_size = uart_config[new_serial.type].dfl_xmit_fifo_size; + + /* Make sure address is not already in use */ + if (new_serial.type) { + for (i = 0 ; i < NR_PORTS; i++) + if ((state != &l1_table[i]) && + (l1_table[i].port == new_port) && + l1_table[i].type) + return -EADDRINUSE; + } + + if ((change_port || change_irq) && (READ_THE_COUNTER(state->count) > 1)) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + state->baud_base = new_serial.baud_base; + state->flags = ((state->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | + (info->flags & ASYNC_INTERNAL_FLAGS)); + state->custom_divisor = new_serial.custom_divisor; + state->close_delay = new_serial.close_delay * HZ/100; + state->closing_wait = new_serial.closing_wait * HZ/100; +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + info->xmit_fifo_size = state->xmit_fifo_size = + new_serial.xmit_fifo_size; + + if ((state->type != PORT_UNKNOWN) && state->port) { + release_region(state->port,8); + } + state->type = new_serial.type; + if (change_port || change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info); + state->irq = new_serial.irq; + info->port = state->port = new_port; + } + if ((state->type != PORT_UNKNOWN) && state->port) { + request_region(state->port,8,"serial(set)"); + } + + +check_and_exit: + if (!state->port || !state->type) + return 0; + if (info->flags & ASYNC_INITIALIZED) { + if (((old_state.flags & ASYNC_SPD_MASK) != + (state->flags & ASYNC_SPD_MASK)) || + (old_state.custom_divisor != state->custom_divisor)) { +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; +#endif + /* Changing speeds is not allowed */ + change_speed(info, 0); + // retval = -EINVAL; + } + } else + retval = startup(info); + return retval; +} + + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int +get_lsr_info(struct async_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + + status = serial_in(info, REG_LSR); + result = ((status & LSR_XSRE) ? TIOCSER_TEMT : 0); + + /* + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ + if ( ((CIRC_CNT(info->xmit.head, info->xmit.tail, + SERIAL_XMIT_SIZE) > 0) && + !info->tty->stopped && !info->tty->hw_stopped)) + result &= TIOCSER_TEMT; + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + + +static int +do_autoconfig(struct async_struct * info) +{ + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (READ_THE_COUNTER(info->state->count) > 1) + return -EBUSY; + + shutdown(info); + + autoconfig(info->state); + if ( IS_RUNNING_ON_SIMULATOR() ) + info->state->irq = 0; + else + info->state->irq = l1_get_intr_value(); + + retval = startup(info); + if (retval) + return retval; + return 0; +} + +static int +l1_cons_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct icount; +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + int retval, tmp; +#endif + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "l1_cons_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(info, (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, (struct serial_struct *) arg); + case TIOCSERCONFIG: + return do_autoconfig(info); + + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + spin_lock_irqsave(&l1_port_lock[info->line], flags); + /* note the counters on entry */ + cprev = info->state->icount; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + spin_lock_irqsave(&l1_port_lock[info->line], flags); + cnow = info->state->icount; /* atomic copy */ + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + spin_lock_irqsave(&l1_port_lock[info->line], flags); + cnow = info->state->icount; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + if (copy_to_user((void *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void +l1_cons_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info, old_termios); + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + l1_cons_start(tty); + } +} + +/* + * ------------------------------------------------------------ + * l1_cons_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void +l1_cons_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "l1_cons_close")) + return; + + state = info->state; + + spin_lock_irqsave(&l1_port_lock[info->line], flags); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("l1_cons_close ttys%d, count = %d\n", info->line, READ_THE_COUNTER(state->count)); +#endif + if ((READ_THE_COUNTER(tty->count) == 1) && (READ_THE_COUNTER(state->count) != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("l1_cons_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", READ_THE_COUNTER(state->count)); + SET_THE_COUNTER(state->count, 1); + } + if ((DEC_THE_COUNTER(state->count)) < 0) { + printk("l1_cons_close: bad serial port count for ttys%d: %d\n", + info->line, READ_THE_COUNTER(state->count)); + SET_THE_COUNTER(state->count, 0); + } + if (READ_THE_COUNTER(state->count)) { + DBG_CNT("before DEC-2"); + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + return; + } + info->flags |= ASYNC_CLOSING; + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->read_status_mask &= ~LSR_RCA; + if (info->flags & ASYNC_INITIALIZED) { + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + l1_cons_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; +} + +/* + * l1_cons_wait_until_sent() --- wait until the transmitter is empty + */ +static void +l1_cons_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (serial_paranoia_check(info, tty->device, "l1_cons_wait_until_sent")) + return; + + if (info->state->type == PORT_UNKNOWN) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout && timeout < char_time) + char_time = timeout; + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In l1_cons_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((lsr = serial_in(info, REG_LSR)) & LSR_XSRE)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + set_current_state(TASK_RUNNING); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %x (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * l1_cons_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void +l1_cons_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "l1_cons_hangup")) + return; + + state = info->state; + + l1_cons_flush_buffer(tty); + if (info->flags & ASYNC_CLOSING) + return; + shutdown(info); + info->event = 0; + SET_THE_COUNTER(state->count, 0); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * l1_cons_open() and friends + * ------------------------------------------------------------ + */ +static int +block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * l1_cons_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, READ_THE_COUNTER(state->count)); +#endif + spin_lock_irqsave(&l1_port_lock[info->line], flags); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + DEC_THE_COUNTER(state->count); + } + spin_unlock_irqrestore(&l1_port_lock[info->line], flags); + info->blocked_open++; + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (serial_in(info, REG_MSR) & + MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, READ_THE_COUNTER(state->count)); +#endif + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) { + INC_THE_COUNTER(state->count); + } + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, READ_THE_COUNTER(state->count)); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int +get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = l1_table + line; + INC_THE_COUNTER(sstate->count); + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + DEC_THE_COUNTER(sstate->count); + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->io_type = sstate->io_type; + info->iomem_base = sstate->iomem_base; + info->iomem_reg_shift = sstate->iomem_reg_shift; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree(info); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int +l1_cons_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) + return retval; + tty->driver_data = info; + info->tty = tty; + if (serial_paranoia_check(info, tty->device, "l1_cons_open")) + return -ENODEV; + +#ifdef SERIAL_DEBUG_OPEN + printk("l1_cons_open %s%d, count = %d for 0x%x, tty count %d\n", tty->driver.name, info->line, + READ_THE_COUNTER(info->state->count), info->state, tty->count); +#endif +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + + if (!l1_tmp_buffer) { + page = get_zeroed_page(GFP_KERNEL); + if (!page) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + if (l1_tmp_buffer) + free_page(page); + else + l1_tmp_buffer = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* Start up serial port */ + + retval = startup(info); + if (retval) + return retval; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("l1_cons_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((READ_THE_COUNTER(info->state->count) == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info, 0); + } + if (sgiconsole.cflag && sgiconsole.index == line) { + tty->termios->c_cflag = sgiconsole.cflag; + sgiconsole.cflag = 0; + change_speed(info, 0); + } + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("l1_cons_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int +line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + char stat_buf[30], control, status; + int ret; + + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", + state->line, uart_config[state->type].name, + state->port, state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + status = serial_in(info, REG_MSR); + control = info != &scr_info ? info->MCR : serial_in(info, REG_MCR); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (control & MCR_RTS) + strcat(stat_buf, "|RTS"); + if (status & MSR_CTS) + strcat(stat_buf, "|CTS"); + if (control & MCR_DTR) + strcat(stat_buf, "|DTR"); + if (status & MSR_DSR) + strcat(stat_buf, "|DSR"); + if (status & MSR_DCD) + strcat(stat_buf, "|CD"); + if (status & MSR_RI) + strcat(stat_buf, "|RI"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +static int +l1_cons_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + extern nasid_t get_console_nasid(void); + + len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s console nasid %d\n", + serial_version, LOCAL_VERSTRING, serial_revdate, get_console_nasid()); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &l1_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * l1_cons_init() and friends + * + * l1_cons_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static char serial_options[] __initdata = +#ifdef SERIAL_OPT + " enabled\n"; +#else + " no serial options enabled\n"; +#endif +#undef SERIAL_OPT + +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name, + serial_version, LOCAL_VERSTRING, serial_revdate, + serial_options); +} + +#define SERIAL_IN(x,c) 0 +#define SERIAL_INP(x,c) 0 +#define SERIAL_OUT(x,c,v) +#define SERIAL_OUTP(x,c,v) + +/* + * This routine is called by l1_cons_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void +autoconfig(struct serial_state * state) +{ + struct async_struct *info, scr_info; + unsigned long flags; + + state->type = PORT_UNKNOWN; + +#ifdef SERIAL_DEBUG_AUTOCONF + printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line, + state->port, (unsigned) state->iomem_base); +#endif + + if (!CONFIGURED_SERIAL_PORT(state)) + return; + + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; + info->io_type = state->io_type; + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; + + spin_lock_irqsave(&l1_port_lock[state->line], flags); + state->type = PORT_16550A; + state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size; + + if (info->port) { + request_region(info->port,8,"serial(auto)"); + } + spin_unlock_irqrestore(&l1_port_lock[state->line], flags); +} + +/* + * The serial driver boot-time initialization code! + */ +static int __init +l1_cons_init(void) +{ + int i; + struct serial_state * state; + + if (serial_timer.function) { + printk("RS_TIMER already set, another serial driver " + "already loaded?\n"); +#ifdef MODULE + printk("Can't load serial driver module over built-in " + "serial driver\n"); +#endif + return -EBUSY; + } + + init_bh(SERIAL_BH, do_serial_bh); + init_timer(&serial_timer); + serial_timer.function = l1_cons_timer; + mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); + + IRQ_ports = (struct async_struct *)0; + IRQ_timeout = 0; + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&l1_serial_driver, 0, sizeof(struct tty_driver)); + l1_serial_driver.magic = TTY_DRIVER_MAGIC; +#if (LINUX_VERSION_CODE > 0x20100) + l1_serial_driver.driver_name = "serial"; +#endif +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + l1_serial_driver.name = "tts/%d"; +#else + l1_serial_driver.name = "ttyS"; +#endif + l1_serial_driver.major = TTY_MAJOR; + l1_serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + l1_serial_driver.num = NR_PORTS; + l1_serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + l1_serial_driver.subtype = SERIAL_TYPE_NORMAL; + l1_serial_driver.init_termios = tty_std_termios; + l1_serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + l1_serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + l1_serial_driver.refcount = &l1_cons_serial_refcount; + l1_serial_driver.table = l1_cons_serial_table; + l1_serial_driver.termios = l1_cons_serial_termios; + l1_serial_driver.termios_locked = l1_cons_serial_termios_locked; + + l1_serial_driver.open = l1_cons_open; + l1_serial_driver.close = l1_cons_close; + l1_serial_driver.write = l1_cons_write; + l1_serial_driver.put_char = l1_cons_put_char; + l1_serial_driver.write_room = l1_cons_write_room; + l1_serial_driver.chars_in_buffer = l1_cons_chars_in_buffer; + l1_serial_driver.flush_buffer = l1_cons_flush_buffer; + l1_serial_driver.ioctl = l1_cons_ioctl; + l1_serial_driver.set_termios = l1_cons_set_termios; + l1_serial_driver.hangup = l1_cons_hangup; +#if (LINUX_VERSION_CODE >= 131343) + l1_serial_driver.wait_until_sent = l1_cons_wait_until_sent; + l1_serial_driver.read_proc = l1_cons_read_proc; +#endif + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + l1_callout_driver = l1_serial_driver; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + l1_callout_driver.name = "cua/%d"; +#else + l1_callout_driver.name = "cua"; +#endif + l1_callout_driver.major = TTYAUX_MAJOR; + l1_callout_driver.subtype = SERIAL_TYPE_CALLOUT; +#if (LINUX_VERSION_CODE >= 131343) + l1_callout_driver.read_proc = 0; + l1_callout_driver.proc_entry = 0; +#endif + + if (tty_register_driver(&l1_serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&l1_callout_driver)) + panic("Couldn't register callout driver\n"); + + for (i = 0, state = l1_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + l1_port_lock[state->line] = SPIN_LOCK_UNLOCKED; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = l1_callout_driver.init_termios; + state->normal_termios = l1_serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = irq_cannonicalize(state->irq); + if (state->port && check_region(state->port,8)) + continue; + + if (state->flags & ASYNC_BOOT_AUTOCONF) + autoconfig(state); + } + for (i = 0, state = l1_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) + continue; + if ( IS_RUNNING_ON_SIMULATOR() ) + state->irq = 0; + else + state->irq = l1_get_intr_value(); + printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", + state->port, state->irq, + uart_config[state->type].name); + tty_register_devfs(&l1_serial_driver, 0, + l1_serial_driver.minor_start + state->line); + tty_register_devfs(&l1_callout_driver, 0, + l1_callout_driver.minor_start + state->line); + } + return 0; +} + +static void __exit +l1_cons_fini(void) +{ +} + +module_init(l1_cons_init); +module_exit(l1_cons_fini); + + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ + +#define BOTH_EMPTY (LSR_XSRE | LSR_XHRE) + +static struct async_struct async_sgiconsole; + +/* + * Wait for transmitter & holding register to empty + */ +static inline void +wait_for_xmitr(struct async_struct *info) +{ +#if defined(CONFIG_IA64_SGI_SN1) + if ( IS_RUNNING_ON_SIMULATOR() ) { + int status, tmout = 1000000; + + do { + status = serial_in(info, REG_LSR); + + if (status & LSR_BRKDET) + lsr_break_flag = LSR_BRKDET; + + if (--tmout == 0) + break; + } while((status & BOTH_EMPTY) != BOTH_EMPTY); + } +#endif /* CONFIG_IA64_SGI_SN1 */ + return; +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void +l1_cons_serial_console_write(struct console *co, const char *s, unsigned count) +{ + static struct async_struct *info = &async_sgiconsole; + unsigned i, xmit_count; + const char *start = s; + + + /* output adding in CRs if needed */ + for (xmit_count = 0, i = 0; i < count; i++, s++, xmit_count++) { + + /* + * Send the character out. + * If a LF, also do CR... + */ +#if defined(CONFIG_IA64_SGI_SN1) + if ( IS_RUNNING_ON_SIMULATOR() ) { + wait_for_xmitr(info); + serial_out(info, L1_REG_DAT, *s); + } +#endif /* CONFIG_IA64_SGI_SN1 */ + if (*s == 10) { + char ch = 13; + wait_for_xmitr(info); +#if defined(CONFIG_IA64_SGI_SN1) + if ( IS_RUNNING_ON_SIMULATOR() ) { + serial_out(info, L1_REG_DAT, 13); + } + else +#endif /* CONFIG_IA64_SGI_SN1 */ + { + extern int l1_serial_out(char *, int); + (void)l1_serial_out((char *)start, xmit_count); + start = s; + xmit_count = 0; + (void)l1_serial_out(&ch, 1); + } + } + } +#if defined(CONFIG_IA64_SGI_SN1) + if ( !IS_RUNNING_ON_SIMULATOR() ) +#endif /* CONFIG_IA64_SGI_SN1 */ + { + if ( xmit_count ) { + extern int l1_serial_out(char *, int); + (void)l1_serial_out((char *)start, xmit_count); + } + } +} + +static kdev_t +l1_cons_serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first l1_cons_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init +l1_cons_serial_console_setup(struct console *co, char *options) +{ + static struct async_struct *info; + struct serial_state *state; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + +/* + * Finally, I am trying for the l1_table to be exported, so that arch code + * can set the different fields in here. Without that, compile time knowledge + * is used to set port addresses, which is not possible on SN1. If this does + * not happen, we might want to do this via serial.h as before. + * Before, I used to encoded in the IO_SWIZ_BASE into the port address, + * so that check_region() on ioport_resource worked. serial_in/out had been + * properly hacked up to handle this port address. Currently, we put the + * serial port in io_mem mode, so check_region() does not happen, and we + * can remove the SN1 hacks from serial_in/out. + * Operate ttyS0 at irq=0, ie polled mode, else when users start using /dev/ + * console, the serial driver had to be hacked to do more frequent polling + * (not sure why, maybe SN1 was not allowing in serial intrs). + * Kanoj + */ + extern u64 master_node_bedrock_address; + + memset(l1_table, 0, sizeof(struct serial_state)*RS_TABLE_SIZE); + l1_table[0].magic = 0; + l1_table[0].baud_base = 124800; + l1_table[0].port = 0; + l1_table[0].irq = 0; + l1_table[0].io_type = SERIAL_IO_MEM; + l1_table[0].flags = (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST); +#if defined(CONFIG_IA64_SGI_SN2) + l1_table[0].iomem_base = (u8 *)master_node_bedrock_address; +#else + l1_table[0].iomem_base = (u8 *)(master_node_bedrock_address + 0x80); +#endif + l1_table[0].iomem_reg_shift = 3; + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + state = l1_table + co->index; + info = &async_sgiconsole; + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; + info->io_type = state->io_type; + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; + quot = state->baud_base / baud; + cval = cflag & (CSIZE | CSTOPB); + + cval >>= 4; + if (cflag & PARENB) + cval |= LCR_PAREN; + if (!(cflag & PARODD)) + cval |= LCR_PAREVN; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + serial_out(info, REG_LCR, cval | LCR_DLAB); /* set DLAB */ + serial_out(info, REG_DLL, quot & 0xff); /* LS of divisor */ + serial_out(info, REG_DLH, quot >> 8); /* MS of divisor */ + serial_out(info, REG_LCR, cval); /* reset DLAB */ + +#ifdef CONFIG_KDB + /* + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. + */ + if (kdb_serial_line == -1) { + kdb_serial_line = co->index; + kdb_serial.io_type = info->io_type; + if (info->io_type == SERIAL_IO_MEM) { + kdb_serial.iobase = info->iomem_base; + kdb_serial.ioreg_shift = info->iomem_reg_shift; + } else { + kdb_serial.iobase = state->port; + kdb_serial.ioreg_shift = 0; + } + } +#endif /* CONFIG_KDB */ + + return 0; +} + +static struct console sgiconsole = { + name: "ttyS", + write: l1_cons_serial_console_write, + device: l1_cons_serial_console_device, + setup: l1_cons_serial_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +#ifdef CONFIG_SERIAL_CONSOLE +/* + * Register console. + */ +void __init +serial_console_init(void) +{ + register_console(&sgiconsole); +} + +#endif /* CONFIG_SERIAL_CONSOLE */ + diff -Nur linux-2.4.19/drivers/char/simserial.c linux-2.4.19-sgi211r3/drivers/char/simserial.c --- linux-2.4.19/drivers/char/simserial.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/char/simserial.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,1095 @@ +/* + * Simulated Serial Driver (fake serial) + * + * This driver is mostly used for bringup purposes and will go away. + * It has a strong dependency on the system console. All outputs + * are rerouted to the same facility as the one used by printk which, in our + * case means sys_sim.c console (goes via the simulator). The code hereafter + * is completely leveraged from the serial.c driver. + * + * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co + * Stephane Eranian + * David Mosberger-Tang + * + * 02/04/00 D. Mosberger Merged in serial.c bug fixes in rs_close(). + * 02/25/00 D. Mosberger Synced up with 2.3.99pre-5 version of serial.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef SIMSERIAL_DEBUG /* define this to get some debug information */ + +#define KEYBOARD_INTR 3 /* must match with simulator! */ + +#define NR_PORTS 1 /* only one port for now */ +#define SERIAL_INLINE 1 + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define SSC_GETCHAR 21 + +extern long ia64_ssc (long, long, long, long, int); +extern void ia64_ssc_connect_irq (long intr, long irq); + +static char *serial_name = "SimSerial driver"; +static char *serial_version = "0.6"; + +/* + * This has been extracted from asm/serial.h. We need one eventually but + * I don't know exactly what we're going to put in it so just fake one + * for now. + */ +#define BASE_BAUD ( 1843200 / 16 ) + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +/* + * Most of the values here are meaningless to this particular driver. + * However some values must be preserved for the code (leveraged from serial.c + * to work correctly). + * port must not be 0 + * type must not be UNKNOWN + * So I picked arbitrary (guess from where?) values instead + */ +static struct serial_state rs_table[NR_PORTS]={ + /* UART CLK PORT IRQ FLAGS */ + { 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 } /* ttyS0 */ +}; + +/* + * Just for the fun of it ! + */ +static struct serial_uart_config uart_config[] = { + { "unknown", 1, 0 }, + { "8250", 1, 0 }, + { "16450", 1, 0 }, + { "16550", 1, 0 }, + { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "cirrus", 1, 0 }, + { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, + { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, + { 0, 0} +}; + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +static struct async_struct *IRQ_ports[NR_IRQS]; +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +static struct console *console; + +static unsigned char *tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); + +extern struct console *console_drivers; /* from kernel/printk.c */ + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ +#ifdef SIMSERIAL_DEBUG + printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", + tty->stopped, tty->hw_stopped, tty->flow_stopped); +#endif + +} + +static void rs_start(struct tty_struct *tty) +{ +#if SIMSERIAL_DEBUG + printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", + tty->stopped, tty->hw_stopped, tty->flow_stopped); +#endif +} + +static void receive_chars(struct tty_struct *tty, struct pt_regs *regs) +{ + unsigned char ch; + static unsigned char seen_esc = 0; + + while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { + if ( ch == 27 && seen_esc == 0 ) { + seen_esc = 1; + continue; + } else { + if ( seen_esc==1 && ch == 'O' ) { + seen_esc = 2; + continue; + } else if ( seen_esc == 2 ) { + if ( ch == 'P' ) show_state(); /* F1 key */ + if ( ch == 'Q' ) show_buffers(); /* F2 key */ + seen_esc = 0; + continue; + } + } + seen_esc = 0; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; + + *tty->flip.char_buf_ptr = ch; + + *tty->flip.flag_buf_ptr = 0; + + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + tty_flip_buffer_push(tty); +} + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +{ + struct async_struct * info; + + /* + * I don't know exactly why they don't use the dev_id opaque data + * pointer instead of this extra lookup table + */ + info = IRQ_ports[irq]; + if (!info || !info->tty) { + printk("simrs_interrupt_single: info|tty=0 info=%p problem\n", info); + return; + } + /* + * pretty simple in our case, because we only get interrupts + * on inbound traffic + */ + receive_chars(info->tty, regs); +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +#if 0 +/* + * not really used in our situation so keep them commented out for now + */ +static DECLARE_TASK_QUEUE(tq_serial); /* used to be at the top of the file */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); + printk("do_serial_bh: called\n"); +} +#endif + +static void do_softint(void *private_) +{ + printk("simserial: do_softint called\n"); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit.buf) return; + + save_flags(flags); cli(); + if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { + restore_flags(flags); + return; + } + info->xmit.buf[info->xmit.head] = ch; + info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); + restore_flags(flags); +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + unsigned long flags; + + save_flags(flags); cli(); + + if (info->x_char) { + char c = info->x_char; + + console->write(console, &c, 1); + + info->state->icount.tx++; + info->x_char = 0; + + goto out; + } + + if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { +#ifdef SIMSERIAL_DEBUG + printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", + info->xmit.head, info->xmit.tail, info->tty->stopped); +#endif + goto out; + } + /* + * We removed the loop and try to do it in to chunks. We need + * 2 operations maximum because it's a ring buffer. + * + * First from current to tail if possible. + * Then from the beginning of the buffer until necessary + */ + + count = MIN(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), + SERIAL_XMIT_SIZE - info->xmit.tail); + console->write(console, info->xmit.buf+info->xmit.tail, count); + + info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1); + + /* + * We have more at the beginning of the buffer + */ + count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count) { + console->write(console, info->xmit.buf, count); + info->xmit.tail += count; + } +out: + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || + !info->xmit.buf) + return; + + transmit_chars(info, NULL); +} + + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit.buf || !tmp_buf) return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + cli(); + while (1) { + c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + /* + * Hey, we transmit directly from here in our case + */ + if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) + && !tty->stopped && !tty->hw_stopped) { + transmit_chars(info, NULL); + } + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + save_flags(flags); cli(); + info->xmit.head = info->xmit.tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + info->x_char = ch; + if (ch) { + /* + * I guess we could call console->write() directly but + * let's do that for now. + */ + transmit_chars(info, NULL); + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); + + printk("simrs_throttle called\n"); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + printk("simrs_unthrottle called\n"); +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + printk("rs_ioctl: TIOCMGET called\n"); + return -EINVAL; + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + printk("rs_ioctl: TIOCMBIS/BIC/SET called\n"); + return -EINVAL; + case TIOCGSERIAL: + printk("simrs_ioctl TIOCGSERIAL called\n"); + return 0; + case TIOCSSERIAL: + printk("simrs_ioctl TIOCSSERIAL called\n"); + return 0; + case TIOCSERCONFIG: + printk("rs_ioctl: TIOCSERCONFIG called\n"); + return -EINVAL; + + case TIOCSERGETLSR: /* Get line status register */ + printk("rs_ioctl: TIOCSERGETLSR called\n"); + return -EINVAL; + + case TIOCSERGSTRUCT: + printk("rs_ioctl: TIOCSERGSTRUCT called\n"); +#if 0 + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; +#endif + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + printk("rs_ioctl: TIOCMIWAIT: called\n"); + return 0; + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + printk("rs_ioctl: TIOCGICOUNT called\n"); + return 0; + + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +} +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) return; + + state = info->state; + +#ifdef SIMSERIAL_DEBUG + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, NULL); + retval = request_irq(state->irq, rs_interrupt_single, + IRQ_T(info), "serial", NULL); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, NULL); + } + + if (info->xmit.buf) { + free_page((unsigned long) info->xmit.buf); + info->xmit.buf = 0; + } + + if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info ) return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { +#ifdef SIMSERIAL_DEBUG + printk("rs_close: hung_up\n"); +#endif + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } +#ifdef SIMSERIAL_DEBUG + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + restore_flags(flags); + + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + shutdown(info); + if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ +} + + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + +#ifdef SIMSERIAL_DEBUG + printk("rs_hangup: called\n"); +#endif + + state = info->state; + + rs_flush_buffer(tty); + if (info->flags & ASYNC_CLOSING) + return; + shutdown(info); + + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree(info); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +static int +startup(struct async_struct *info) +{ + unsigned long flags; + int retval=0; + void (*handler)(int, void *, struct pt_regs *); + struct serial_state *state= info->state; + unsigned long page; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!state->port || !state->type) { + if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SIMSERIAL_DEBUG + printk("startup: ttys%d (irq %d)...", info->line, state->irq); +#endif + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + retval = -EBUSY; + goto errout; + } else + handler = rs_interrupt_single; + + retval = request_irq(state->irq, handler, IRQ_T(info), + "simserial", NULL); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->xmit.head = info->xmit.tail = 0; + +#if 0 + /* + * Set up serial timers... + */ + timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; + timer_active |= 1 << RS_TIMER; +#endif + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + tty->driver_data = info; + info->tty = tty; + +#ifdef SIMSERIAL_DEBUG + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + } + + /* + * figure out which console to use (should be one already) + */ + console = console_drivers; + while (console) { + if ((console->flags & CON_ENABLED) && console->write) break; + console = console->next; + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SIMSERIAL_DEBUG + printk("rs_open ttys%d successful\n", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + return sprintf(buf, "%d: uart:%s port:%lX irq:%d\n", + state->line, uart_config[state->type].name, + state->port, state->irq); +} + +static int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "simserinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static inline void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s with", serial_name, serial_version); + printk(" no serial options enabled\n"); +} + +/* + * The serial driver boot-time initialization code! + */ +static int __init +simrs_init (void) +{ + int i; + struct serial_state *state; + + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "simserial"; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = 1; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.send_xchar = rs_send_xchar; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; + + /* + * Let's have a little bit of fun ! + */ + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + + if (state->type == PORT_UNKNOWN) continue; + + if (!state->irq) { + state->irq = ia64_alloc_irq(); + ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq); + } + + printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n", + state->line, + state->port, state->irq, + uart_config[state->type].name); + } + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register simserial driver\n"); + + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + return 0; +} + +#ifndef MODULE +__initcall(simrs_init); +#endif diff -Nur linux-2.4.19/drivers/char/sysrq.c linux-2.4.19-sgi211r3/drivers/char/sysrq.c --- linux-2.4.19/drivers/char/sysrq.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/sysrq.c Thu Oct 24 04:22:20 2002 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * - * $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $ + * $Id: sysrq.c,v 1.9 2002/01/24 09:44:12 yakker Exp $ * * Linux Magic System Request Key Hacks * @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -295,6 +296,38 @@ } } +static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + dump("sysrq", pt_regs); +#endif +} +static struct sysrq_key_op sysrq_crashdump_op = { + handler: sysrq_handle_crashdump, + help_msg: "Crash", + action_msg: "Start a Crash Dump (If Configured)", +}; + +static void sysrq_handle_dumpregs(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) { +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#if defined(CONFIG_X86) && defined(CONFIG_SMP) + extern void (*dump_trace_ptr)(struct pt_regs *); + printk("Show state of all cpus\n"); + if (dump_trace_ptr) { + dump_trace_ptr(pt_regs); + } else { + printk("Load dump module/configure first\n"); + } +#endif +#endif +} +static struct sysrq_key_op sysrq_dumpregs_op = { + handler: sysrq_handle_dumpregs, + help_msg: "Dumpregisters", + action_msg: "Dump CPU Registers (If Configured)" +}; + static void sysrq_handle_term(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) { send_sig_all(SIGTERM); @@ -338,8 +371,8 @@ it is handled specially on the spark and will never arive */ /* b */ &sysrq_reboot_op, -/* c */ NULL, -/* d */ NULL, +/* c */ &sysrq_crashdump_op, +/* d */ &sysrq_dumpregs_op, /* e */ &sysrq_term_op, /* f */ NULL, /* g */ NULL, diff -Nur linux-2.4.19/drivers/char/tty_io.c linux-2.4.19-sgi211r3/drivers/char/tty_io.c --- linux-2.4.19/drivers/char/tty_io.c Fri Aug 2 17:39:43 2002 +++ linux-2.4.19-sgi211r3/drivers/char/tty_io.c Wed Feb 5 13:36:49 2003 @@ -114,7 +114,9 @@ #undef TTY_DEBUG_HANGUP #define TTY_PARANOIA_CHECK 1 +#ifndef CONFIG_IA64_SGI_SN #define CHECK_TTY_COUNT 1 +#endif struct termios tty_std_termios; /* for the benefit of tty drivers */ struct tty_driver *tty_drivers; /* linked list of tty drivers */ @@ -236,7 +238,7 @@ #ifdef CHECK_TTY_COUNT struct list_head *p; int count = 0; - + file_list_lock(); for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) { if(list_entry(p, struct file, f_list)->private_data == tty) @@ -245,12 +247,12 @@ file_list_unlock(); if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_SLAVE && - tty->link && tty->link->count) + tty->link && READ_THE_COUNTER(tty->link->count)) count++; - if (tty->count != count) { + if (READ_THE_COUNTER(tty->count) != count) { printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) " - "!= #fd's(%d) in %s\n", - kdevname(tty->device), tty->count, count, routine); + "!= #fd's(%d) in %s\n", + kdevname(tty->device), tty->count, count, routine); return count; } #endif @@ -437,6 +439,7 @@ struct task_struct *p; struct list_head *l; int closecount = 0, n; + unsigned long flags; if (!tty) return; @@ -461,20 +464,15 @@ } file_list_unlock(); - /* FIXME! What are the locking issues here? This may me overdoing things.. */ - { - unsigned long flags; - - save_flags(flags); cli(); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - restore_flags(flags); - } + spin_lock_irqsave(&tty->struct_lock, flags); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + spin_unlock_irqrestore(&tty->struct_lock, flags); wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); @@ -575,6 +573,8 @@ struct task_struct *p; int tty_pgrp = -1; + lock_kernel(); + if (tty) { tty_pgrp = tty->pgrp; if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY) @@ -584,6 +584,7 @@ kill_pg(current->tty_old_pgrp, SIGHUP, on_exit); kill_pg(current->tty_old_pgrp, SIGCONT, on_exit); } + unlock_kernel(); return; } if (tty_pgrp > 0) { @@ -601,6 +602,7 @@ if (p->session == current->session) p->tty = NULL; read_unlock(&tasklist_lock); + unlock_kernel(); } void stop_tty(struct tty_struct *tty) @@ -901,8 +903,9 @@ o_tty->termios = *o_tp_loc; o_tty->termios_locked = *o_ltp_loc; (*driver->other->refcount)++; - if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; + if (driver->subtype == PTY_TYPE_MASTER) { + INC_THE_COUNTER(o_tty->count); + } /* Establish the links in both directions */ tty->link = o_tty; @@ -923,7 +926,7 @@ tty->termios = *tp_loc; tty->termios_locked = *ltp_loc; (*driver->refcount)++; - tty->count++; + INC_THE_COUNTER(tty->count); /* * Structures all installed ... call the ldisc open routines. @@ -962,13 +965,13 @@ * special case for PTY masters: only one open permitted, * and the slave side open count is incremented as well. */ - if (tty->count) { + if (READ_THE_COUNTER(tty->count)) { retval = -EIO; goto end_init; } - tty->link->count++; + INC_THE_COUNTER(tty->link->count); } - tty->count++; + INC_THE_COUNTER(tty->count); tty->driver = *driver; /* N.B. why do this every time?? */ success: @@ -1092,7 +1095,7 @@ #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", - tty_name(tty, buf), tty->count); + tty_name(tty, buf), READ_THE_COUNTER(tty->count)); #endif #ifdef TTY_PARANOIA_CHECK @@ -1144,9 +1147,8 @@ * each iteration we avoid any problems. */ while (1) { - tty_closing = tty->count <= 1; - o_tty_closing = o_tty && - (o_tty->count <= (pty_master ? 1 : 0)); + tty_closing = READ_THE_COUNTER(tty->count) <= 1; + o_tty_closing = o_tty && (READ_THE_COUNTER(o_tty->count) <= (pty_master ? 1 : 0)); do_sleep = 0; if (tty_closing) { @@ -1183,17 +1185,17 @@ * block, so it's safe to proceed with closing. */ if (pty_master) { - if (--o_tty->count < 0) { + if ((DEC_THE_COUNTER(o_tty->count)) < 0) { printk(KERN_WARNING "release_dev: bad pty slave count " "(%d) for %s\n", - o_tty->count, tty_name(o_tty, buf)); - o_tty->count = 0; + READ_THE_COUNTER(o_tty->count), tty_name(o_tty, buf)); + SET_THE_COUNTER(o_tty->count, 0); } } - if (--tty->count < 0) { + if ((DEC_THE_COUNTER(tty->count)) < 0) { printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", - tty->count, tty_name(tty, buf)); - tty->count = 0; + READ_THE_COUNTER(tty->count), tty_name(tty, buf)); + SET_THE_COUNTER(tty->count, 0); } /* @@ -1412,7 +1414,7 @@ } if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) && (tty->driver.subtype == SERIAL_TYPE_CALLOUT) && - (tty->count == 1)) { + (READ_THE_COUNTER(tty->count) == 1)) { static int nr_warns; if (nr_warns < 5) { printk(KERN_WARNING "tty_io.c: " @@ -1901,7 +1903,7 @@ fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; tty->flip.buf_num = 0; - save_flags(flags); cli(); + spin_lock_irqsave(&tty->struct_lock, flags); tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; } else { @@ -1909,13 +1911,13 @@ fp = tty->flip.flag_buf; tty->flip.buf_num = 1; - save_flags(flags); cli(); + spin_lock_irqsave(&tty->struct_lock, flags); tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; } count = tty->flip.count; tty->flip.count = 0; - restore_flags(flags); + spin_unlock_irqrestore(&tty->struct_lock, flags); tty->ldisc.receive_buf(tty, cp, fp, count); } @@ -1994,6 +1996,7 @@ sema_init(&tty->atomic_read, 1); sema_init(&tty->atomic_write, 1); spin_lock_init(&tty->read_lock); + spin_lock_init(&tty->struct_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_TQUEUE(&tty->SAK_tq, 0, 0); } diff -Nur linux-2.4.19/drivers/char/tty_ioctl.c linux-2.4.19-sgi211r3/drivers/char/tty_ioctl.c --- linux-2.4.19/drivers/char/tty_ioctl.c Mon Sep 17 22:52:35 2001 +++ linux-2.4.19-sgi211r3/drivers/char/tty_ioctl.c Wed Feb 5 13:36:49 2003 @@ -96,8 +96,9 @@ { int canon_change; struct termios old_termios = *tty->termios; + unsigned long flags; - cli(); + spin_lock_irqsave(&tty->struct_lock, flags); *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -107,7 +108,7 @@ tty->canon_data = 0; tty->erasing = 0; } - sti(); + spin_unlock_irqrestore(&tty->struct_lock, flags); if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ wake_up_interruptible(&tty->read_wait); diff -Nur linux-2.4.19/drivers/char/vc_screen.c linux-2.4.19-sgi211r3/drivers/char/vc_screen.c --- linux-2.4.19/drivers/char/vc_screen.c Sun Sep 16 21:22:40 2001 +++ linux-2.4.19-sgi211r3/drivers/char/vc_screen.c Mon Oct 28 20:43:23 2002 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -66,10 +67,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) { - int size = vcs_size(file->f_dentry->d_inode); + int size; + lock_kernel(); + size = vcs_size(file->f_dentry->d_inode); switch (orig) { default: + unlock_kernel(); return -EINVAL; case 2: offset += size; @@ -79,9 +83,12 @@ case 0: break; } - if (offset < 0 || offset > size) + if (offset < 0 || offset > size) { + unlock_kernel(); return -EINVAL; + } file->f_pos = offset; + unlock_kernel(); return file->f_pos; } diff -Nur linux-2.4.19/drivers/dump/Makefile linux-2.4.19-sgi211r3/drivers/dump/Makefile --- linux-2.4.19/drivers/dump/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/Makefile Thu Oct 24 04:22:20 2002 @@ -0,0 +1,36 @@ +# +# Makefile for the dump device drivers. +# +# 12 June 2000, Christoph Hellwig +# Rewritten by Matt D. Robinson (yakker@sourceforge.net) for +# the dump directory. +# + +O_TARGET := dumpdrv.o +export-objs := dump_base.o + +list-multi := dump.o +dump-objs := dump_base.o + +# get the base dump module and compression modules out of the way +obj-$(CONFIG_DUMP_COMPRESS_RLE) += dump_rle.o +obj-$(CONFIG_DUMP_COMPRESS_GZIP) += dump_gzip.o +obj-$(CONFIG_DUMP) += dump.o + +# now deal with each individual architecture. +ifeq ($(ARCH),i386) + dump-objs += dump_i386.o +endif + +ifeq ($(ARCH),alpha) + dump-objs += dump_alpha.o +endif + +ifeq ($(ARCH),ia64) + dump-objs += dump_ia64.o +endif + +include $(TOPDIR)/Rules.make + +dump.o: $(dump-objs) + $(LD) -r -o $@ $(dump-objs) diff -Nur linux-2.4.19/drivers/dump/dump_alpha.c linux-2.4.19-sgi211r3/drivers/dump/dump_alpha.c --- linux-2.4.19/drivers/dump/dump_alpha.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_alpha.c Tue Jan 28 18:24:28 2003 @@ -0,0 +1,100 @@ +/* + * Architecture specific (alpha) functions for Linux crash dumps. + * + * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com) + * Copyright 2000 TurboLinux, Inc. All rights reserved. + * 2.4 modifications by Matt D. Robinson (yakker@aparity.com) + * Copyright 2001 Matt D. Robinson. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* + * The hooks for dumping the kernel virtual memory to disk are in this + * file. Any time a modification is made to the virtual memory mechanism, + * these routines must be changed to use the new mechanisms. + */ +#include +#include +#include +#include + +/* + * Name: __dump_configure_header() + * Func: Configure the dump header with all proper values. + */ +int +__dump_configure_header(struct pt_regs *regs) +{ + dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER; + dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER; + dump_header_asm.dha_header_size = sizeof(dump_header_asm_t); + + /* copy the registers if they are valid */ + if (regs) { + memcpy((void *)&(dump_header_asm.dha_regs), + (const void *)regs, sizeof(struct pt_regs)); + } + + return (1); +} + +/* + * Name: __dump_write_header() + * Func: Update the header information with all architecture specific + * information. + */ +int +__dump_write_header(char *dpage) +{ + memcpy((void *)(dpage + sizeof(dump_header_t)), + (const void *)&dump_header_asm, sizeof(dump_header_asm_t)); + + return (1); +} + +/* + * Name: __dump_init() + * Func: Initialize the dumping routine process. This is in case + * it's necessary in the future. + */ +void +__dump_init(uint64_t local_memory_start) +{ + /* return */ + return; +} + +/* + * Name: __dump_open() + * Func: Open the dump device (architecture specific). This is in + * case it's necessary in the future. + */ +void +__dump_open(struct file *dump_file, uint64_t memory_size) +{ + /* return */ + return; +} + +/* + * Name: __dump_silence_system() + * Func: Do an architecture-specific silencing of the system. + */ +unsigned int +__dump_silence_system(unsigned int stage) +{ + /* return */ + return (0); +} + +/* + * Name: __dump_resume_system() + * Func: Resume the system state in an architecture-specific way. + */ +unsigned int +__dump_resume_system(unsigned int stage) +{ + /* return */ + return (0); +} diff -Nur linux-2.4.19/drivers/dump/dump_base.c linux-2.4.19-sgi211r3/drivers/dump/dump_base.c --- linux-2.4.19/drivers/dump/dump_base.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_base.c Thu Jan 16 18:45:04 2003 @@ -0,0 +1,2168 @@ +/* + * Standard kernel functions for Linux crash dumps. + * + * Created by: Matt Robinson (yakker@sourceforge.net) + * Contributions from SGI, IBM, HP, MCL, and others. + * + * Copyright (C) 1999 - 2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000 - 2002 TurboLinux, Inc. All rights reserved. + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved. + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* + * ----------------------------------------------------------------------- + * + * DUMP HISTORY + * + * This dump code goes back to SGI's first attempts at dumping system + * memory on SGI systems running IRIX. A few developers at SGI needed + * a way to take this system dump and analyze it, and created 'icrash', + * or IRIX Crash. The mechanism (the dumps and 'icrash') were used + * by support people to generate crash reports when a system failure + * occurred. This was vital for large system configurations that + * couldn't apply patch after patch after fix just to hope that the + * problems would go away. So the system memory, along with the crash + * dump analyzer, allowed support people to quickly figure out what the + * problem was on the system with the crash dump. + * + * In comes Linux. SGI started moving towards the open source community, + * and upon doing so, SGI wanted to take its support utilities into Linux + * with the hopes that they would end up the in kernel and user space to + * be used by SGI's customers buying SGI Linux systems. One of the first + * few products to be open sourced by SGI was LKCD, or Linux Kernel Crash + * Dumps. LKCD comprises of a patch to the kernel to enable system + * dumping, along with 'lcrash', or Linux Crash, to analyze the system + * memory dump. A few additional system scripts and kernel modifications + * are also included to make the dump mechanism and dump data easier to + * process and use. + * + * As soon as LKCD was released into the open source community, a number + * of larger companies started to take advantage of it. Today, there are + * many community members that contribute to LKCD, and it continues to + * flourish and grow as an open source project. + * + * ----------------------------------------------------------------------- + * + * SYSTEM DUMP LAYOUT + * + * System dumps are currently the combination of a dump header and a set + * of data pages which contain the system memory. The layout of the dump + * (for full dumps) is as follows: + * + * +-----------------------------+ + * | generic dump header | + * +-----------------------------+ + * | architecture dump header | + * +-----------------------------+ + * | page header | + * +-----------------------------+ + * | page data | + * +-----------------------------+ + * | page header | + * +-----------------------------+ + * | page data | + * +-----------------------------+ + * | | | + * | | | + * | | | + * | | | + * | V | + * +-----------------------------+ + * | PAGE_END header | + * +-----------------------------+ + * + * There are two dump headers, the first which is architecture + * independent, and the other which is architecture dependent. This + * allows different architectures to dump different data structures + * which are specific to their chip set, CPU, etc. + * + * After the dump headers come a succession of dump page headers along + * with dump pages. The page header contains information about the page + * size, any flags associated with the page (whether it's compressed or + * not), and the address of the page. After the page header is the page + * data, which is either compressed (or not). Each page of data is + * dumped in succession, until the final dump header (PAGE_END) is + * placed at the end of the dump, assuming the dump device isn't out + * of space. + * + * This mechanism allows for multiple compression types, different + * types of data structures, different page ordering, etc., etc., etc. + * It's a very straightforward mechanism for dumping system memory. + * ----------------------------------------------------------------------- + * + * DUMP IMPLEMENTATION + * + * Dumps are implemented using a "start at the top and work your way + * to the bottom" method. The starting location of kernel memory is + * determined, and each successive page is passed through to the + * dump_add_page() function, which determines whether to compress the + * page, throw it out, add the page header, etc. This mechanism is + * going to change over time as non-disruptive dumps are created, so + * it is best to read through the code (it is commented pretty well), + * and let the developers know if it isn't clear enough. We believe + * in well-documented, well-commented code. + * + * ----------------------------------------------------------------------- + * + * DUMP TUNABLES + * + * This is the list of system tunables (via /proc) that are available + * for Linux systems. All the read, write, etc., functions are listed + * here. Currently, there are a few different tunables for dumps: + * + * dump_device (used to be dumpdev): + * The device for dumping the memory pages out to. This is almost + * always the primary swap partition for disruptive dumps. + * + * dump_compress (used to be dump_compress_pages): + * This is the flag which indicates which compression mechanism + * to use. This is a BITMASK, not an index (0,1,2,4,8,16,etc.). + * This is the current set of values: + * + * 0: DUMP_COMPRESS_NONE -- Don't compress any pages. + * 1: DUMP_COMPRESS_RLE -- This uses RLE compression. + * 2: DUMP_COMPRESS_GZIP -- This uses GZIP compression. + * + * dump_level: + * The amount of effort the dump module should make to save + * information for post crash analysis. This value is now + * a BITMASK value, not an index: + * + * 0: Do nothing, no dumping. (DUMP_LEVEL_NONE) + * + * 1: Print out the dump information to the dump header, and + * write it out to the dump_device. (DUMP_LEVEL_HEADER) + * + * 2: Write out the dump header and all kernel memory pages. + * (DUMP_LEVEL_KERN) + * + * 4: Write out the dump header and all kernel and user + * memory pages. (DUMP_LEVEL_USED) + * + * 8: Write out the dump header and all conventional/cached + * memory (RAM) pages in the system (kernel, user, free). + * (DUMP_LEVEL_ALL_RAM) + * + * 16: Write out everything, including non-conventional memory + * like firmware, proms, I/O registers, uncached memory. + * (DUMP_LEVEL_ALL) + * + * The dump_level will default to 1. + * + * REMIND: How about we change these to 1, 3, 7, 15, 31. + * If we reserve the bits for individual passes + * it's easer to test things like non-conventional + * memory dump on systems with limited disk space. + * If would be more consistent with dump_level being + * a bitmask. We might also consider changing the name + * to 'dump_passes' to make it more clear that the bitmask + * is not a index. + * + * + * dump_flags: + * These are the flags to use when talking about dumps. There + * are lots of possibilities. This is a BITMASK value, not an index. + * + * 1: Try to keep the system running _after_ we are done + * dumping -- for non-disruptive dumps. (DUMP_FLAGS_NONDISRUPT) + * + * ----------------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------- + * H E A D E R F I L E S + * ----------------------------------------------------------------------- + */ + +/* header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * ----------------------------------------------------------------------- + * D E F I N I T I O N S + * ----------------------------------------------------------------------- + */ +#define DUMP_MODULE_NAME "dump" + +#if DUMP_DEBUG +#define DUMP_PREFIX __func__ +#else +#define DUMP_PREFIX DUMP_MODULE_NAME +#endif + + +#define DUMP_PRINTN(args...) { \ + printk("\n"); \ + DUMP_PRINTF(args); \ +} + +#define DUMP_PRINTF(args...) { \ + printk("%s: ", DUMP_PREFIX); \ + printk (args); \ +} + +#ifdef DUMP_DEBUG +#define DUMP_DPRINTF(args...) { \ + printk("%s: ", DUMP_PREFIX); \ + printk (args); \ +} +#else +#define DUMP_DPRINTF(args...) +#endif + +#define DUMP_PRINT(args...) { \ + printk(args); \ +} + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) +#endif + +/* + * Handle printing of 64-bit values + * + * NOTE: on ia64 %llx is recommended for ia32. + * on RedHat 7.2 %llx work in user space but not in the kernel. + * Perhaps this is dependent on the kernel version. + */ +#if BITS_PER_LONG == 64 +#define PU64X "%lx" +#else +#define PU64X "%Lx" +#endif + + +/* + * ----------------------------------------------------------------------- + * V A R I A B L E S + * ----------------------------------------------------------------------- + */ + +/* Dump tunables */ +kdev_t dump_device; /* the actual kdev_t device number */ +int dump_level; /* the current dump level */ +int dump_compress; /* whether to try to compress each page */ +int dump_flags; /* whether to try to compress each page */ + +/* Dump Notifier Tunables */ +long dump_scheduler_enabled = 0; /* Default: scheduler is disabled */ +long dump_interrupts_enabled = 1; /* Default: interrupts stay enabled */ +long dump_nondisruptive_enabled = 1; /* Default: non-disruptive enabled */ + +/* Other global fields */ +char dumpdev_name[PATH_MAX]; /* the name of the dump device */ +void *dump_page_buf; /* dump page buffer for memcpy()! */ +void *dump_page_buf_0; /* dump page buffer returned by kmalloc */ +int dump_blk_size; /* sector size for dump_device */ +int dump_blk_shift; /* shift need to convert to sector size */ +dump_header_t dump_header; /* the primary dump header */ +dump_header_asm_t dump_header_asm; /* the arch-specific dump header */ +struct kiobuf *dump_iobuf; /* kiobuf for raw I/O to disk */ +loff_t dump_fpos; /* the offset in the output device */ +int dump_mbanks; /* number of physical memory banks */ +dump_mbank_t dump_mbank[MAXCHUNKS];/* describes layout of physical memory */ +long dump_unreserved_mem = 0; /* Save Pages even if it isn't reserved */ +long dump_unreferenced_mem = 0; /* Save Pages even if page_count == 0 */ +long dump_nonconventional_mem = 0; /* Save non-conventional mem (firmware) */ + +static int dump_compress_none(char *old, int oldsize, char *new, int newsize); + +static dump_compress_t dump_none_compression = { + compress_type: DUMP_COMPRESS_NONE, + compress_func: dump_compress_none, +}; + +/* our device operations and functions */ +static int dump_open(struct inode *i, struct file *f); +static int dump_release(struct inode *i, struct file *f); +static int dump_ioctl(struct inode *i, struct file *f, + unsigned int cmd, unsigned long arg); + +static struct file_operations dump_fops = { + open: dump_open, + release: dump_release, + ioctl: dump_ioctl, +}; + +/* function pointers and prototypes */ +int (*dump_compress_func)(char *old, int oldsize, char *new, int newsize); + +/* proc entries */ +static struct proc_dir_entry *dump_root; /* /proc/sys/dump root dir */ +static struct proc_dir_entry *dump_dd; /* dump_device tunable */ +static struct proc_dir_entry *dump_cp; /* dump_compress tunable */ +static struct proc_dir_entry *dump_l; /* dump_level tunable */ +static struct proc_dir_entry *dump_f; /* dump_flags tunable */ + +/* static variables */ +static int dump_okay = FALSE; /* can we dump out to disk? */ +static char dpcpage[DUMP_DPC_PAGE_SIZE]; /* buffer used for compression */ +static unsigned long dump_save_flags; /* save_flags()/restore_flags() */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)) +static unsigned long dump_blocks[KIO_MAX_SECTORS]; +#endif + +/* for dumping from interrupt context (Fixme) */ +static int saved_irq_count; /* remember the current irq nesting level */ +static int saved_bh_count; /* remember if we were in soft irq context */ + +/* used for dump compressors */ +static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list); + +/* external variables */ +extern volatile int dumping_cpu; /* cpu on which dump is progressing */ +extern volatile int dump_in_progress; /* note when we're dumping */ +extern volatile int dump_started; +extern int panic_timeout; /* time before reboot */ +extern int *blk_size[]; /* device block size calculations */ +extern struct new_utsname system_utsname; /* system information */ + +#if !defined(irq_count) && !defined(bh_count) +extern irq_cpustat_t irq_stat[]; +#endif + +/* external functions */ +extern void si_meminfo(struct sysinfo *); +extern void *kmalloc(size_t, int); +extern void kfree(const void *); +extern unsigned long simple_strtoul(const char *,char **,unsigned int); + +/* lkcd info structure -- this is used by lcrash for basic system data */ +lkcdinfo_t lkcdinfo = { + 0, + (sizeof(void *) * 8), +#if defined(__LITTLE_ENDIAN) + __LITTLE_ENDIAN, +#else + __BIG_ENDIAN, +#endif + 0, + PAGE_SHIFT, + PAGE_SIZE, + PAGE_MASK, + PAGE_OFFSET, + 0 +}; + +#if DUMP_DEBUG +void dump_bp(void) {} +#endif + + +/* + * ----------------------------------------------------------------------- + * / P R O C T U N A B L E F U N C T I O N S + * ----------------------------------------------------------------------- + */ + +/* + * Name: dump_read_proc() + * Func: Read the proc data for dump tunables. + */ +static int +dump_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char *out = page; + struct proc_dir_entry *p = (struct proc_dir_entry *)data; + + + if (0 == strcmp(p->name, DUMP_LEVEL_NAME)) { + out += sprintf(out, "%d\n", dump_level); + len = out - page; + } else if (0 == strcmp(p->name, DUMP_FLAGS_NAME)) { + out += sprintf(out, "%d\n", dump_flags); + len = out - page; + } else if (0 == strcmp(p->name, DUMP_COMPRESS_NAME)) { + out += sprintf(out, "%d\n", dump_compress); + len = out - page; + } else if (0 == strcmp(p->name, DUMP_DEVICE_NAME)) { +#if 0 + len = strlen(dumpdev_name); + memcpy((void *)page, (const void *)dumpdev_name, len); +#else + out += sprintf(out, "%s\n", dumpdev_name); + len = out - page; +#endif + } else { + return (0); + } + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) return 0; + } else { + len = count; + } + *start = page + off; + return (len); +} + +/* + * ----------------------------------------------------------------------- + * C O M P R E S S I O N F U N C T I O N S + * ----------------------------------------------------------------------- + */ + +/* + * Name: dump_compress_none() + * Func: Don't do any compression, period. + */ +static int +dump_compress_none(char *old, int oldsize, char *new, int newsize) +{ + /* just return the old size */ + return (oldsize); +} + +/* + * ----------------------------------------------------------------------- + * U T I L I T Y F U N C T I O N S + * ----------------------------------------------------------------------- + */ + +/* + * Dump Notifier Callbacks: + * Used by disk drivers during the dump notification + * to tune the dump driver. Names and functions are obvious. + */ +void dump_scheduler_enable(void) { + DUMP_DPRINTF("setting dump_scheduler_enabled = 1\n"); + dump_scheduler_enabled = 1; +} + +void dump_interrupts_disable(void) { + DUMP_DPRINTF("setting dump_interrupts_enabled = 0\n"); + dump_interrupts_enabled = 0; +} + +void dump_nondisruptive_disable(void) { + DUMP_DPRINTF("setting dump_nondisruptive_enabled = 0\n"); + dump_nondisruptive_enabled = 0; +} + +/* + * Name: dump_kernel_write() + * + * Func: Write out kernel information, check the device limitations, + * block sizes, etc. The thing I don't like about this function + * is that most of it is a duplicate of what rw_raw_dev() does, + * but sct doesn't want rw_raw_dev() to do kernel kiobuf stuff, and + * brw_kiovec() isn't a good place to do device checks, since we'd + * have to check all this stuff anyway, and device block calculations + * are ugly in there for each call to the function. So we do it all + * here, call brw_kiovec() on our own, and return the results. + * + * Writes DUMP_BUFFER_SIZE bytes in page buffer + * + * Returns: number of bytes written or -ERRNO. + * At EOF it returns 0. + */ +static ssize_t +dump_kernel_write(int *eof) +{ + int err = 0, iosize, i; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)) + unsigned long *b = dump_blocks; +#else + unsigned long *b = dump_iobuf->blocks; +#endif + unsigned long blocknr, blocks, limit; + + /* check the device size to make sure we are in-line */ + if (blk_size[MAJOR(dump_device)]) { + limit = (((loff_t) blk_size[MAJOR(dump_device)][MINOR(dump_device)]) + << BLOCK_SIZE_BITS) >> dump_blk_shift; + } else { + limit = INT_MAX; + } + + /* not aligned? */ + if (dump_fpos & (dump_blk_size - 1)) { + DUMP_PRINTN("invalid buffer alignment!"); + return (-EINVAL); + } + + /* beyond the end of the device -- not really an error, per se */ + if ((dump_fpos >> dump_blk_shift) > limit) { + DUMP_PRINTN("no space left on device!"); + DUMP_BP(); + return (0); + } + + /* + * If near the end of the dump device we set *eof (if ptr provided) to + * let the caller know that it's near the EOF on the dump device. + */ + if ( ((dump_fpos + (4 * DUMP_BUFFER_SIZE)) >> dump_blk_shift) > limit) { + if(eof != NULL) { + *eof = 1; + } + DUMP_BP(); + } + /* + * If near the end of the dump device we set *eof (if ptr provided) to + * let the caller know that it's near the EOF on the dump device. + */ + else if ( ((dump_fpos + (2 * DUMP_BUFFER_SIZE)) >> dump_blk_shift) > limit) { + if(eof != NULL) { + *eof = 1; + } + DUMP_BP(); + } + + /* reset the block number values */ + blocknr = dump_fpos >> dump_blk_shift; + + /* calculate the number of blocks */ + blocks = DUMP_BUFFER_SIZE >> dump_blk_shift; + if (blocks > (KIO_MAX_SECTORS >> (dump_blk_shift - 9))) { + blocks = KIO_MAX_SECTORS >> (dump_blk_shift - 9); + } + + /* don't write more blocks than our max limit */ + if (blocks > limit - blocknr) { + blocks = limit - blocknr; + } + + /* make sure we have blocks to write! */ + if (!blocks) { + DUMP_PRINTN("no blocks left on dump device!"); + return (0); + } + + /* map the kernel kiobuf based on the iosize */ + iosize = blocks << dump_blk_shift; + + /* map the block numbers */ + for (i = 0; i < blocks; i++) { + b[i] = blocknr++; + } + + /* write out the data to disk */ + err = brw_kiovec(WRITE, 1, &dump_iobuf, dump_device, b, dump_blk_size); + + /* make sure our I/O size matches return from brw_kiovec() */ + if (err < 0) { + DUMP_PRINTN("brw_kiovec() returned %d!", err); + return (-EFAULT); + } + + if (err != DUMP_BUFFER_SIZE) { + DUMP_PRINTN("brw_kiovec() did not write out DUMP_BUFFER_SIZE!"); + return (-EFAULT); + } + + /* err is the transferred bytes -- return those */ + dump_fpos += err; + return (err); +} + +/* + * Name: dump_add_end_marker() + * Func: add last dump page marker to the end of the dump buffer. + */ +static void +dump_add_end_marker(unsigned long *toffset, int flags) +{ + dump_page_t dp; + + /* set the end marker */ + dp.dp_address = dp.dp_size = 0x0; + dp.dp_flags = flags; + +#if DUMP_DEBUG >= 6 + dp.dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE + PAGE_SIZE; + dp.dp_page_index = dump_header.dh_num_dump_pages; +#endif + + /* clear the buffer and copy the page header */ + memcpy((void *)(dump_page_buf + *toffset), + (const void *)&dp, sizeof(dump_page_t)); + *toffset += sizeof(dump_page_t); + +#if DUMP_DEBUG >= 6 + dump_header.dh_num_bytes += sizeof(dump_page_t); +#endif + dump_header.dh_num_dump_pages++; + + return; +} + +inline int kernel_page(struct page *p) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,15)) + if (PageReserved(p) == 0) + return 0; + return 1; +#else + if (PageReserved(p) || (!PageLRU(p) && PageInuse(p))) + return 1; + else + return 0; +#endif +} + +inline int referenced_page(struct page *p) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,15)) + if(PageReserved(p) || page_count(p) == 0) + return 0; + return 1; +#else + if (PageInuse(p)) { + if (!PageReserved(p) && PageLRU(p)) + return 1; + else + return 0; + } else + return 0; +#endif +} + +inline int unreferenced_page(struct page *p) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,15)) + if(PageReserved(p) || page_count(p) > 0) + return 0; + return 1; +#else + if (!PageInuse(p)) { + if (!PageReserved(p)) + return 1; + else + return 0; + } else + return 0; +#endif +} + +long dump_add_page_debug = 0; +long dump_add_page_test_pattern = 0; + +/* + * Name: dump_add_page() + * Func: Add a hardware page to the dump buffer. + * + * NB: page is a DUMP_PAGE_SIZE page, + * not a system page (PAGE_SIZE). + * + * REMIND: + * We should likely move some of this to + * arch specific code and/or clean it up. + */ +static int +dump_add_page(unsigned long page_index, unsigned long *toffset, int pass) +{ +#if defined(CONFIG_X86) || defined(CONFIG_ALPHA) + extern int page_is_ram(unsigned long); +#endif + unsigned long size; + dump_page_t dp; + void *vaddr; + u64 paddr = (((u64)page_index) << DUMP_PAGE_SHIFT); + struct page *p; + +#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_IA64) + p = (struct page *) &(mem_map[page_index]); + + /* + * If the address is in highmem, map it before copying to + * the dump buffer. In essence, the dump buffer is the + * bounce buffer. + */ +#ifdef CONFIG_HIGHMEM + if (PageHighMem(p)) { + /* + * Since this can be executed from IRQ context, + * reentrance on the same CPU must be avoided: + */ + vaddr = kmap_atomic(p, KM_USER0); + } + else +#endif +#if defined(CONFIG_X86) || defined(CONFIG_ALPHA) + if (!page_is_ram(page_index)) { + return (1); + } + else +#endif + /* low memory */ + vaddr = page_address(p); + +#else /* CONFIG_DISCONTIGMEM || CONFIG_IA64 */ + vaddr = __va(paddr); + p = virt_to_page(vaddr); +#endif + dp.dp_address = paddr; + dp.dp_flags = DUMP_DH_RAW; + + +#if DUMP_DEBUG >= 6 + /* + * Helpful when looking at hex dump of /dev/vdump. + * + * Dump Header Swap Header + */ + dp.dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE + DUMP_HEADER_OFFSET; + dp.dp_page_index = dump_header.dh_num_dump_pages; + + switch(pass) { + case 1: break; + case 2: return(1); /* Already Dumped */ + case 3: return(1); /* Already Dumped */ + case 4: break; + } +#else + /* + * Selective dump: + * Some systems, have huge memories, NUMA for example, where + * a dump of all of memory isn't likely to fit on a swap partition. + * This is a simple 1st attempt at ordering the dump so the most + * important pages are dumped first. + * + * pass1: Kernel Pages + * pass2: Remaining referenced pages + * pass3: the rest of conventional memory + * pass4: non-conventional memory, + */ + switch (pass) { + case 1: + if (kernel_page(p)) + break; + else + return(1); + case 2: + if (referenced_page(p)) + break; + else + return(1); + case 3: + if (unreferenced_page(p)) + break; + else + return(1); + case 4: + break; + + } +#endif + +#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_IA64) + if( !kern_addr_valid(dp.dp_address) ) { + /* dump of I/O memory not supported yet */ + printk(KERN_ALERT "dump_add_page: !kern_addr_valid(dp.dp_address: " PU64X "\n", + dp.dp_address); + return(1); + } +#endif + +#if DUMP_DEBUG + if(dump_add_page_debug) { + printk(KERN_ALERT "dump_add_page(page_index:%lx, *toffset:%lx):\n", + page_index, *toffset); + } +#endif + + /* + * Don't compress the page if any part of it overlaps + * with the current task_struct or current stack. + */ + if ((((unsigned long)vaddr < (unsigned long)current + THREAD_SIZE) && + ((unsigned long)vaddr + DUMP_PAGE_SIZE > + (unsigned long)current))) { + size = DUMP_PAGE_SIZE; + } + else { + size = dump_compress_func((char *)vaddr, DUMP_PAGE_SIZE, + (char *)dpcpage, DUMP_DPC_PAGE_SIZE); + if (!size) { + /* dump compression failed -- default to raw mode */ + size = DUMP_PAGE_SIZE; + } + /* set the compressed flag if the page did compress */ + if (size < DUMP_PAGE_SIZE) { + dp.dp_flags = DUMP_DH_COMPRESSED; + } + } + + /* set the universal size */ + dp.dp_size = size; + + /* copy the page header */ + memcpy((void *)(dump_page_buf + *toffset), (const void *)&dp, + sizeof(dump_page_t)); + + *toffset += sizeof(dump_page_t); + + if (dp.dp_flags & DUMP_DH_COMPRESSED) { + /* copy the compressed page */ + memcpy((void *)(dump_page_buf + *toffset), + (const void *)dpcpage, size); + } else { + /* copy directly from memory */ + DUMP_memcpy((void *)(dump_page_buf + *toffset), + (const void *)vaddr, size); + } + +#if DUMP_DEBUG + /* + * Write a Test Pattern: + * Page data is full of bytes with the page number. + */ + if (dump_add_page_test_pattern) { + unsigned char num_pages = (char) (dump_header.dh_num_dump_pages & 0Xff); + char *cp = (dump_page_buf + *toffset); + int i; + + for( i = 0; i < size; i++) { + *cp++ = num_pages; + } + } +#endif + +#ifdef CONFIG_HIGHMEM + if (PageHighMem(p)) { + /* + * Since this can be executed from IRQ context, + * reentrance on the same CPU must be avoided: + */ + kunmap_atomic(vaddr, KM_USER0); + } +#endif + *toffset += size; + +#if DUMP_DEBUG >= 6 + if (dump_add_page_debug) { + printk(KERN_ALERT "dump_add_page: *toffset:%lx += size:%lx:\n", + *toffset, size); + } + dump_header.dh_num_bytes += (size + sizeof(dump_page_t)); +#endif + + dump_header.dh_num_dump_pages++; + + return (0); +} + + +/* + * Name: dump_silence_system() + * Func: Silence the system, or make CPUs spin, etc. The intention + * here is to get things to a "quiet" state, so we can dump. + */ +void +dump_silence_system(void) +{ + unsigned int stage = 0; + int cpu = smp_processor_id(); + + if (in_interrupt()) { + printk(KERN_ALERT "Dumping from interrupt handler !\n"); + printk(KERN_ALERT "Uncertain scenario - but will try my best\n"); + /* + * Must be an unrelated interrupt, not in the middle of io ! + * If we've panic'ed in the middle of io we should take + * another approach + */ + } + /* see if there's something to do before we re-enable interrupts */ + (void)__dump_silence_system(stage); + + /* we set this to FALSE so we don't ever re-enter this code! */ + dump_okay = FALSE; + dumping_cpu = cpu; + dump_in_progress = TRUE; + save_flags(dump_save_flags); + + /* -------------------------------------------------- */ + /* Kludge - dump from interrupt context is unreliable (Fixme) + * + * We do this so that softirqs initiated for dump i/o + * get processed and we don't hang while waiting for i/o + * to complete or in any irq synchronization attempt. + * + * This is not quite legal of course, as it has the side + * effect of making all interrupts & softirqs triggered + * while dump is in progress complete before currently + * pending softirqs and the currently executing interrupt + * code. + */ + /* + * We use irq_stat directly instead of using local_irq_count + * and local_bh_count as they can't be used as Lvalues on + * uniprocessor machines. + */ +#if defined(irq_count) && defined(bh_count) + saved_irq_count = irq_count(cpu); + saved_bh_count = bh_count(cpu); + irq_count(cpu) = 0; + bh_count(cpu) = 0; +#else + saved_irq_count = irq_stat[cpu].__local_irq_count; + saved_bh_count = irq_stat[cpu].__local_bh_count; + irq_stat[cpu].__local_irq_count = 0; + irq_stat[cpu].__local_bh_count = 0; +#endif + /* -----------------------------------------------------*/ + + sti(); /* enable interrupts just in case ... */ + + /* now increment the stage and do stuff after interrupts are enabled */ + stage++; + (void)__dump_silence_system(stage); + + /* time to leave */ + return; +} + +/* + * Name: dump_resume_system() + * Func: Resume the system state. + */ +void +dump_resume_system(void) +{ + unsigned int stage = 0; + + /* let the architectures return their proper system state */ + (void)__dump_resume_system(stage); + + /* restore flags and other dump state fields */ + restore_flags(dump_save_flags); + +#if defined(irq_count) && defined(bh_count) + irq_count(dumping_cpu) = saved_irq_count; + bh_count(dumping_cpu) = saved_bh_count; +#else + irq_stat[dumping_cpu].__local_irq_count = saved_irq_count; + irq_stat[dumping_cpu].__local_bh_count = saved_bh_count; +#endif + + dump_in_progress = FALSE; + dump_okay = TRUE; + + return; +} + +static void +dump_speedo(void) +{ + static int i = 0; + + switch (++i%4) { + case 0: + printk("|\b"); + break; + case 1: + printk("\\\b"); + break; + case 2: + printk("-\b"); + break; + case 3: + printk("/\b"); + break; + } +} + +/* + * ----------------------------------------------------------------------- + * H E A D E R F U N C T I O N S + * ----------------------------------------------------------------------- + */ + +/* + * Name: dump_configure_header() + * Func: Update the header with the appropriate information. + */ +static int +dump_configure_header(char *panic_str, struct pt_regs *regs) +{ + /* make sure the dump header isn't TOO big */ + if ((sizeof(dump_header_t) + + sizeof(dump_header_asm_t)) > DUMP_BUFFER_SIZE) { + DUMP_PRINTN("dump_configure_header(): combined " + "headers larger than DUMP_BUFFER_SIZE!"); + return (0); + } + + /* configure dump header values */ + dump_header.dh_magic_number = DUMP_MAGIC_NUMBER; + dump_header.dh_version = DUMP_VERSION_NUMBER; + dump_header.dh_memory_start = PAGE_OFFSET; + dump_header.dh_memory_end = DUMP_MAGIC_NUMBER; + dump_header.dh_header_size = sizeof(dump_header_t); + dump_header.dh_dump_page_size = DUMP_PAGE_SIZE; + dump_header.dh_dump_level = dump_level; + dump_header.dh_current_task = current; + dump_header.dh_dump_compress = dump_compress; + dump_header.dh_dump_flags = dump_flags; + dump_header.dh_dump_device = dump_device; + +#if DUMP_DEBUG >= 6 + dump_header.dh_num_bytes = 0; +#endif + dump_header.dh_num_dump_pages = 0; + do_gettimeofday(&dump_header.dh_time); + +#ifndef UTSNAME_ENTRY_SZ +#define UTSNAME_ENTRY_SZ 65 +#endif + memcpy((void *)&(dump_header.dh_utsname_sysname), + (const void *)&(system_utsname.sysname), UTSNAME_ENTRY_SZ); + memcpy((void *)&(dump_header.dh_utsname_nodename), + (const void *)&(system_utsname.nodename), UTSNAME_ENTRY_SZ); + memcpy((void *)&(dump_header.dh_utsname_release), + (const void *)&(system_utsname.release), UTSNAME_ENTRY_SZ); + memcpy((void *)&(dump_header.dh_utsname_version), + (const void *)&(system_utsname.version), UTSNAME_ENTRY_SZ); + memcpy((void *)&(dump_header.dh_utsname_machine), + (const void *)&(system_utsname.machine), UTSNAME_ENTRY_SZ); + memcpy((void *)&(dump_header.dh_utsname_domainname), + (const void *)&(system_utsname.domainname), UTSNAME_ENTRY_SZ); + + if (panic_str) { + memcpy((void *)&(dump_header.dh_panic_string), + (const void *)panic_str, DUMP_PANIC_LEN); + } + + dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER; + dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER; + dump_header_asm.dha_header_size = sizeof(dump_header_asm_t); + + /* copy the registers if they are valid */ + if (regs) { + memcpy((void *)&(dump_header_asm.dha_regs), + (const void *)regs, sizeof(struct pt_regs)); + } + + /* configure architecture-specific dump header values */ + if (!__dump_configure_header(regs)) { + return (0); + } + return (1); +} + +/* + * Name: dump_write_header() + * Func: Write out the dump header. + * + * Returns: + * -1: failed + * 0: wrote o bytes (truncated) + * +1: wrote header + */ +static int +dump_write_header(void) +{ + int state; + loff_t toffset; + + /* clear the dump page buffer */ + memset(dump_page_buf, 0, DUMP_BUFFER_SIZE); + + /* copy the dump header directly into the dump page buffer */ + memcpy(dump_page_buf, (const void *)&dump_header, + sizeof(dump_header_t)); + + memcpy((void *)(dump_page_buf + sizeof(dump_header_t)), + (const void *)&dump_header_asm, sizeof(dump_header_asm_t)); + + /* save our file pointer */ + toffset = dump_fpos; + + /* + * ALWAYS write out the dump header at DUMP_HEADER_OFFSET, + * this is after the longest swap header possibly written by mkswap; + * likely the largest PAGE_SIZE supported by the architecture. + */ + dump_fpos = DUMP_HEADER_OFFSET; + + /* do the real write here */ + state = dump_kernel_write(NULL); + dump_fpos = toffset; + if (state < 0) { + DUMP_PRINTF("dump_kernel_write() failed!\n"); + return (-1); + } else if (!state) { + /* wrote zero bytes - failed */ + return (0); + } + /* Wrote the header - success */ + return (1); +} + +/* + * ----------------------------------------------------------------------- + * E X E C U T E F U N C T I O N S + * ----------------------------------------------------------------------- + */ + +/* + * Name: dump_execute_memdump() + * Func: Perform the actual memory dump. This walks through the + * memory pages and dumps the data to disk (using other functions). + * + * Returns: + * -1: failed + * 0: dump truncated + * 1: success + */ +static int +dump_execute_memdump(void) +{ + int counter = 0, n_bytes = 0, i; + unsigned long buf_loc; + u64 mem_loc; + int dump_truncated = 0; + int pass = 0; + + DUMP_PRINTN("Compression value is 0x%x, Writing dump header ", dump_compress); + + /* update the header to disk the first time */ + n_bytes = dump_write_header(); + DUMP_PRINT("\n"); + + if (n_bytes < 0) { + DUMP_PRINTF("Initial dump header update failed!\n"); + return (-1); + } else if (n_bytes == 0) { + return (0); + } + + /* if we only want the header, return */ + if (dump_level & DUMP_LEVEL_HEADER) { + return (1); + } + + /* set beginning offset to keep compats right with swap devices */ + dump_fpos = DUMP_HEADER_OFFSET + DUMP_BUFFER_SIZE; + + /* clear the dump page buffer */ + memset(dump_page_buf, 0, DUMP_BUFFER_SIZE); + + /* set the buffer location */ + buf_loc = 0; + + for (pass = 1; pass <= 4; pass++) { + + if( (pass == 2) && dump_unreserved_mem == 0) { + continue; + } + if( (pass == 3) && dump_unreferenced_mem == 0) { + continue; + } + if (pass == 4) { + if (dump_nonconventional_mem == 0) break; + if (dump_mbanks == 1) break; /* Contiguous Mem Sys have 1 mbank */ + } + /* Algorithm suggested by Jack Steiner > DUMP_PAGE_SHIFT), + &buf_loc, pass)) { + /* didn't add a page to buffer */ + continue; + } + + /* see if we've filled the buffer */ + if (buf_loc >= DUMP_BUFFER_SIZE) { + int near_eof = 0; + + /* write out the dump page buffer */ + n_bytes = dump_kernel_write(&near_eof); + if (n_bytes < 0) { + DUMP_PRINTN("Write of dump pages failed!"); + return(-1); + } else if (n_bytes == 0) { + DUMP_PRINTN("EOF on Write of dump pages; dump terminated!"); + return(0); + } + if( near_eof ) { + DUMP_PRINTN("Near EOF on Write of dump pages; truncating dump,"); + dump_truncated = 1; + } + + /* bump the counter for writing out the header */ + counter++; + + /* + * Update the header every once in a while -- this + * _must_ be done before we write the overflow end of + * the dump_page_buf into the top of dump_page_buf, + * as dump_write_header() uses dump_page_buf to + * write the default/asm dump headers. After we are + * done updating the header, _then_ we can move the + * leftover dump data into the top of dump_page_buf. + * + * NOTE: a period is printed to indicate that the header + * was updated. Speedo shows page out activity. + */ + if ((counter & 0x3f) == 0) { + n_bytes = dump_write_header(); + if (n_bytes < 0) { + DUMP_PRINTN("Dump header update failed!"); + return (-1); + } else if (n_bytes == 0) { + DUMP_PRINTN("Dump header update failed; bizarre"); + return (0); + } + DUMP_PRINT("."); + } else { + if ((counter & 0x07) == 0) { + dump_speedo(); + } + } + + /* clear the dump page buffer */ + memset(dump_page_buf, 0, DUMP_BUFFER_SIZE); + + /* adjust leftover data back to the top of the page */ + if (buf_loc > DUMP_BUFFER_SIZE) { + /* copy the dump page buffer remnants */ + memcpy((void *)dump_page_buf, + (const void *)(dump_page_buf + + DUMP_BUFFER_SIZE), + buf_loc - DUMP_BUFFER_SIZE); + + /* set the new buffer location */ + buf_loc -= DUMP_BUFFER_SIZE; + } else { + /* reset the buffer location counter */ + buf_loc = 0; + } + } + if (dump_truncated) { + break; + } + } + DUMP_PRINT(" "); + if (dump_truncated) { + break; + } + } + if (dump_truncated) { + break; + } + DUMP_PRINT("\n"); + } + + /* + * we have written out most of the dump pages, a few may still be in the + * page buffer and it's possible we had to truncate the dump because we + * got very close to the end of the dump partition. Now we add a EOF + * marker to the page out buffer and flush out the remaining pages. + * + * We need to write the DUMP_DH_END even for truncated data because + * the reader won't get an EOF if he reads the data in smaller chunks + * than the DUMP_BUFFER_SIZE it's written in. + */ + if (dump_truncated) { + dump_add_end_marker(&buf_loc, (DUMP_DH_END | DUMP_DH_TRUNCATED)); + } else { + dump_add_end_marker(&buf_loc, DUMP_DH_END); + } + n_bytes = dump_kernel_write(NULL); + + if (n_bytes < 0) { + DUMP_PRINTN("Final write of last of page buffer and DUMP_DH_END failed!"); + return (-1); + } else if (n_bytes == 0) { + DUMP_PRINTN("Hit EOF writing DUMP_DH_END; bad luck\n"); + return (0); + } + + /* + * Writing out DUMP_DH_END may have pushed us past the end of the first + * part of the page buffer, if it did we have to write out one last + * DUMP_BUFFER with the spill over page. + */ + if (buf_loc > DUMP_BUFFER_SIZE) { + /* clear the first part of the buffer */ + memset(dump_page_buf, 0, DUMP_BUFFER_SIZE); + + /* + * Copy the dump page buffer remnants in the second + * part of the buffer to the first part. + */ + memcpy((void *)dump_page_buf, + (const void *)(dump_page_buf + DUMP_BUFFER_SIZE), + buf_loc - DUMP_BUFFER_SIZE); + + n_bytes = dump_kernel_write(NULL); + if (n_bytes < 0) { + DUMP_PRINTN("Final write of spillover page failed!"); + return (-1); + } else if (n_bytes == 0) { + DUMP_PRINTN("Hit EOF writing spill over page with DUMP_DH_END; very bad luck!\n"); + return (0); + } + } + if (dump_truncated) { + return(0); + } + /* success */ + return (1); +} + +/* + * Name: dump_execute() + * Func: Execute the dumping process. This makes sure all the appropriate + * fields are updated correctly, and calls dump_execute_memdump(), + * which does the real work. + * + * if( dump_flags & DUMP_FLAGS_NONDISRUPT ) { + * Returns: + * -1: failed + * 0: dump truncated + * 1: success + * } + */ +int +dump_execute(char *panic_str, struct pt_regs *regs) +{ + int state = 1; + int scheduler_disabled = 1; + + dump_started = 1; + + /* make sure we can dump */ + if (dump_okay == FALSE) { + return(-1); + } + + if(!dump_configure_header(panic_str, regs)) { + DUMP_PRINTN("dump header could not be configured!"); + return(-1); + } + + /* silence the system */ + dump_silence_system(); + + /* tell interested parties that a dump is about to start */ + if (dump_flags & DUMP_FLAGS_NONDISRUPT) { + notifier_call_chain(&dump_notifier_list, DUMP_BEGIN_NONDISRUPT, &dump_device); + } else { + notifier_call_chain(&dump_notifier_list, DUMP_BEGIN, &dump_device); + } + + /* + * if dump device notifier indicated the scheduler needs to be + * enabled then we need to turn it back on. + */ + if (dump_scheduler_enabled) { + dump_resume_system(); + scheduler_disabled = 0; + } + + /* + * Make sure dump device notifier indicated that Non-Disruptive Dumps are Supported. + */ + if( !dump_nondisruptive_enabled && (dump_flags & DUMP_FLAGS_NONDISRUPT) ) { + DUMP_PRINTN("Non-Disruptive Dumps are not Supported by Dump Device 0x%x [%s]\n", + dump_device, bdevname(dump_device)); + + state = -1; /* Dump Aborted */ + } else { + /* + * bail out if we're not going to do any dumping. + */ + if (dump_level != DUMP_LEVEL_NONE) { + /* inform users of what we are about to do */ + DUMP_PRINTN("Dumping to device 0x%x [%s] on CPU %d ...", + dump_device, bdevname(dump_device), + smp_processor_id()); + + /* start walking through the page tables */ + state = dump_execute_memdump(); + + DUMP_PRINT("\n"); + + /* update header to disk for the last time */ + if (dump_write_header() < 0) { + DUMP_PRINTF("Final dump header update failed!\n"); + } + + if (state < 0) { + DUMP_PRINTF("Dump Failed!\n"); + } else if (state == 0) { + DUMP_PRINTF("Dump Truncated (likely out of space).\n"); + } else { + DUMP_PRINTF("Dump Complete; %d dump pages saved.\n", + dump_header.dh_num_dump_pages); + } + } + } + + /* tell interested parties that a dump has completed */ + notifier_call_chain(&dump_notifier_list, DUMP_END, &dump_device); + + /* put the system state back */ + if ( scheduler_disabled ) { + dump_resume_system(); + } + + /* + * Reboot the system if this is a disrupted dump. + * + * Non-disruptive dumps have to be set up with a + * special swap partition that isn't being used; + * so it can be used for testing and snapshots. + */ + if ( !(dump_flags & DUMP_FLAGS_NONDISRUPT) ) { + int timeout = (panic_timeout > 0) ? panic_timeout : 10; + + DUMP_PRINTF("Dump: Rebooting in %d seconds ...", timeout); + mdelay(timeout * 1000); + machine_restart(NULL); + } + dump_started = 0; + return (state); +} + +/* + * Name: dump_register_compression() + * Func: Register a dump compression mechanism. + */ +void +dump_register_compression(dump_compress_t *item) +{ + /* let's make sure our list is valid */ + if (!item) { + return; + } + + /* add our item */ + list_add(&(item->list), &dump_compress_list); + + /* print information to callers */ + DUMP_PRINTF("Registering dump compression type 0x%x\n", item->compress_type); +} + +/* + * Name: dump_unregister_compression() + * Func: Remove a dump compression mechanism, and re-assign the dump + * compression pointer if necessary. + */ +void +dump_unregister_compression(int compression_type) +{ + struct list_head *tmp; + dump_compress_t *dc; + + /* let's make sure our list is valid */ + if (compression_type == DUMP_COMPRESS_NONE) { + DUMP_PRINTN("Compression list is invalid!"); + return; + } + + /* try to remove the compression item */ + list_for_each(tmp, &dump_compress_list) { + dc = list_entry(tmp, dump_compress_t, list); + if (dc->compress_type == compression_type) { + list_del(&(dc->list)); + DUMP_PRINTN("De-registering dump compression type 0x%x\n", + compression_type); + return; + } + } +} + +/* + * Name: dump_compress_init() + * Func: Initialize (or re-initialize) compression scheme. + */ +static int +dump_compress_init(int compression_type) +{ + struct list_head *tmp; + dump_compress_t *dc; + + /* try to remove the compression item */ + list_for_each(tmp, &dump_compress_list) { + dc = list_entry(tmp, dump_compress_t, list); + if (dc->compress_type == compression_type) { + dump_compress_func = dc->compress_func; + dump_compress = compression_type; + + DUMP_PRINTF("dump_compress = %d\n", dump_compress); + DUMP_BP(); + return (0); + } + } + + /* + * nothing on the list -- return ENODATA to indicate an error + * + * NB: + * EAGAIN: reports "Resource temporarily unavailable" which + * isn't very enlightening. + */ + DUMP_PRINTF("compression_type:%d not found\n", compression_type); + DUMP_BP(); + + return (-ENODATA); +} + +void dump_iobuf_end_io(struct kiobuf *kiobuf) +{ + /* + * No wakeup needed if we've stopped scheduling + */ + if (!dump_scheduler_enabled && dump_in_progress == 0) { + wake_up(&kiobuf->wait_queue); + } + return; +} +/* + * Name: dump_open_kdev() + * Func: Try to open the kdev_t argument as the real dump device. + * This is where all the work is done for setting up the dump + * device. It's assumed at this point that by passing in the + * dump device's major/minor number, we can open it up, check + * it out, and use it for whatever purposes. + */ +static int +dump_open_kdev(kdev_t tmp_dump_device) +{ + int i; + unsigned long a; + unsigned long dump_page_addr; + + /* make sure this is a valid block device */ + if (!tmp_dump_device) { + return (-EINVAL); + } + + /* we'd better have a name here, or this isn't valid ... */ + if (!get_blkfops(MAJOR(tmp_dump_device))) { + return (-ENODEV); + } + + /* if this is the second call to this function, clean up ... */ + if ((dump_okay == TRUE) && (dump_page_buf_0 != (void *)NULL)) { + kfree((const void *)dump_page_buf_0); + } + + /* + * Allocate buffer to be used for copying pages (only once ...) + * + * An extra: + * 2 * DUMP_PAGE_SIZE: + * is needed for the page overflow of last page, it's page header + * and the EOF page header. + * + * and an extra: + * 1 * PAGE_SIZE: + * is needed for rounding up the start of the dump_page_buf to + * a system page (PAGE_SIZE) boundary. + * + */ + dump_page_buf = dump_page_buf_0 = (void *)kmalloc( + DUMP_BUFFER_SIZE + (DUMP_PAGE_SIZE * 2) + PAGE_SIZE, + GFP_KERNEL); + + + if (dump_page_buf_0 == (void *)0) { + DUMP_PRINTF("Cannot kmalloc() dump page buffer!\n"); + dump_okay = FALSE; + return (-ENOMEM); + } + + /* + * Allocate our kiobuf -- we used to do this in dump_execute(), + * but since the memory allocation schemes and the kiobuf code + * keeps changing out underneath us, we'll do it when we open + * up the dump device. + */ + dump_iobuf = (struct kiobuf *)NULL; + + /* allocate a new one for use */ + if (alloc_kiovec(1, &dump_iobuf)) { + DUMP_PRINTF("alloc_kiovec() call failed!\n"); + dump_okay = FALSE; + return (-ENOMEM); + } + + /* align the dump page addresses */ + dump_page_addr = (unsigned long) dump_page_buf; + if (dump_page_addr % PAGE_SIZE) { + dump_page_buf = (void *) PAGE_ALIGN(dump_page_addr); + } + + a = (unsigned long) dump_page_buf; + /* get the base address, and copy the number of total pages */ + for (i = 0; i < (DUMP_BUFFER_SIZE >> PAGE_SHIFT); i++, a += PAGE_SIZE) { + dump_iobuf->maplist[i] = (struct page *)virt_to_page(a); + } + dump_iobuf->locked = 1; + dump_iobuf->offset = 0; + dump_iobuf->length = DUMP_BUFFER_SIZE; + dump_iobuf->nr_pages = (DUMP_BUFFER_SIZE >> PAGE_SHIFT); + dump_iobuf->end_io = dump_iobuf_end_io; + + /* assign the new dump file structure */ + dump_device = tmp_dump_device; + memcpy(dumpdev_name, bdevname(dump_device), PATH_MAX); + + /* set the sector size information */ + dump_blk_size = PAGE_SIZE; + set_blocksize(dump_device, dump_blk_size); + + /* set the sector bits */ + i = dump_blk_size; + for (dump_blk_shift = 0; !(i & 1);) { + i >>= 1, dump_blk_shift++; + } + DUMP_PRINTF("dump_blk_shift:%d, PAGE_SHIFT:%d\n", + dump_blk_shift, PAGE_SHIFT); + + /* set the dump okay flag to 1, the dump device is valid */ + dump_okay = TRUE; + + DUMP_PRINTN("dump device 0x%x opened; Ready to take a save a core dump\n", dump_device); + + /* after opening the block device, return */ + return (0); +} + +/* + * Name: dump_release() + * Func: Release the dump device -- it's never necessary to call + * this function, but it's here regardless. + */ +static int +dump_release(struct inode *i, struct file *f) +{ + return (0); +} + +/* + * Name: dump_ioctl() + * Func: Allow all dump tunables through a standard ioctl() mechanism. + * This is far better than before, where we'd go through /proc, + * because now this will work for multiple OS and architectures. + */ +static int +dump_ioctl(struct inode *i, struct file *f, + unsigned int cmd, unsigned long arg) +{ + /* check capabilities */ + if (!capable(CAP_SYS_ADMIN)) { + return (-EPERM); + } + + /* + * This is the main mechanism for controlling get/set data + * for various dump device parameters. The real trick here + * is setting the dump device (DIOSDUMPDEV). That's what + * triggers everything else. + */ + switch (cmd) { + /* set dump_device */ + case DIOSDUMPDEV: + /* check flags */ + if (!(f->f_flags & O_RDWR)) { + return (-EPERM); + } + __dump_open(); + return (dump_open_kdev((kdev_t)arg)); + + /* get dump_device */ + case DIOGDUMPDEV: + return (put_user((long)dump_device, (long *)arg)); + + /* set dump_level */ + case DIOSDUMPLEVEL: + /* check flags */ + if (!(f->f_flags & O_RDWR)) { + return (-EPERM); + } + /* make sure we have a positive value */ + if (arg < 0) { + return (-EINVAL); + } + dump_level = (int)arg; + + /* + * REMIND: Still in development: + * + * We will consider reserved pages a initial proxy for kernel pages. + */ + if (dump_level > DUMP_LEVEL_KERN) { + dump_unreserved_mem = 1; + } else { + dump_unreserved_mem = 0; + } + + /* + * REMIND: Still in development: + * + * Using refcount > 1 as a proxy for kernel & user pages. + */ + if (dump_level > DUMP_LEVEL_USED) { + dump_unreferenced_mem = 1; + } else { + dump_unreferenced_mem = 0; + } + + /* + * REMIND: Still in development: + * + * This may not be 100% stable on all ia64 + * memory banks. Accessing uncached memory + * with cached accesses can cause subsequent + * bus errors when the cache is flushed. + */ + if( dump_level > DUMP_LEVEL_ALL_RAM ) { + dump_nonconventional_mem = 1; + } else { + dump_nonconventional_mem = 0; + } + break; + + /* get dump_level */ + case DIOGDUMPLEVEL: + return (put_user((long)dump_level, (long *)arg)); + + /* set dump_flags */ + case DIOSDUMPFLAGS: + /* check flags */ + if (!(f->f_flags & O_RDWR)) { + return (-EPERM); + } + /* make sure we have a positive value */ + if (arg < 0) { + return (-EINVAL); + } + dump_flags = (int)arg; + break; + + /* get dump_flags */ + case DIOGDUMPFLAGS: + return (put_user((long)dump_flags, (long *)arg)); + + /* set the dump_compress status */ + case DIOSDUMPCOMPRESS: + /* check flags */ + if (!(f->f_flags & O_RDWR)) { + return (-EPERM); + } + return (dump_compress_init((int)arg)); + + /* get the dump_compress status */ + case DIOGDUMPCOMPRESS: + return (put_user((long)dump_compress, (long *)arg)); + +#ifdef CONFIG_IA64 + case DIOGKERNELADDR: + return (put_user(__dump_kernel_addr(), (unsigned long *)arg)); +#endif + +#if DUMP_DEBUG + case DIODUMPTEST: + /* + * The lkcd_config cmd has a -t option available for testing dump + * when DUMP_DEBUG is defined in dump.h. The -t option is followed + * by a string that is parsed here. + * + * A string compare is used instead of more DUMP constants to make + * it easy to add new options quickly while debugging the dump driver. + */ + if (dump_okay) { + int saved_dump_flags = dump_flags; + char *bogus_pointer = 0; + char bogus_data; + char buffer[128]; + int dumps_wanted = 0; + int stop_wanted = 0; +#ifdef DUMP_IPI_FLUSH_TLB + int tlb_flush_wanted = 0; +#endif + char *dump_test = "test"; + int success; + + unlock_kernel(); + if( ((caddr_t) arg) == NULL ) { + DUMP_PRINTF("arg == NULL; default test is to do nothing"); + return (0); + } else { + /* + * These functions are suppose to be dynamic and configurable + * for your current needs; no sweet if you check in whats + * currently useful for you. Perhaps it should be checked in empty + * while no new platforms are being worked on. + */ + if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) { + DUMP_PRINTF("strncpy_from_user() failed\n"); + return( -EFAULT ); + } + buffer[sizeof(buffer) - 1] = (char) 0; + DUMP_PRINTF("buffer[]: '%s'\n", &buffer[0]); + + if (strncmp(&buffer[0], "panic", sizeof(buffer)) == 0) { + dump_flags |= DUMP_FLAGS_NONDISRUPT; + panic("test panic and dump"); + /* NOTREACHED */ + } + if (strncmp(&buffer[0], "dump", sizeof(buffer)) == 0) { /* dump */ + dumps_wanted = 1; + dump_test = "test dump"; + } +#ifdef CONFIG_SMP + if (strncmp(&buffer[0], "stop", sizeof(buffer)) == 0) { + dumps_wanted = 1; + stop_wanted = 1; + dump_test = "test dump with cpu's stopped"; + } +#ifdef DUMP_IPI_FLUSH_TLB + if (strncmp(&buffer[0], "flush", sizeof(buffer)) == 0) { /* OK */ + dumps_wanted = 1; + tlb_flush_wanted = 1; + dump_test = "test dump with cpu TLB's flushed"; + } +#endif /* DUMP_IPI_FLUSH_TLB */ +#endif /* CONFIG_SMP */ + if (strncmp(&buffer[0], "trap", sizeof(buffer)) == 0) { /* OK */ + *(int *)0 = 0; + DUMP_PRINTF("*(int *)0 = 0; should have cause a trap and died"); + bogus_data = *bogus_pointer; + DUMP_PRINTF("*bogus_pointer; should have taken a trap and died"); + BUG(); + return( -EFAULT ); + } + if (strncmp(&buffer[0], "forever", sizeof(buffer)) == 0) { /* OK */ + dumps_wanted = 0XEFFF; + dump_test = "test dump forever"; + } + } + if (dumps_wanted) { + int dumps = 0; + + dump_flags |= DUMP_FLAGS_NONDISRUPT; + /* + * REMIND: How to break loop on intr/ ? + */ + do { + +#if defined(CONFIG_SMP) + if( stop_wanted ) { + smp_send_stop(); + } +#ifdef DUMP_IPI_FLUSH_TLB + if( tlb_flush_wanted ) { + extern void smp_send_flush_tlb(void); + + smp_send_flush_tlb(); + } +#endif /* DUMP_IPI_FLUSH_TLB */ +#endif /* CONFIG_SMP */ + success = dump_execute(dump_test, NULL); + dumps++; + DUMP_PRINTF("Test '%s': success:%d, dumps:%d\n", dump_test, success, dumps); + } while (success && (dumps < dumps_wanted)); + + DUMP_PRINTF("success:%d\n", success); + dump_flags = saved_dump_flags; + + if( dumps >= dumps_wanted ) { + return ( 0 ); + } else { + return ( -EINTR ); + } + } + DUMP_PRINTF("Test '%s' not known.\n", &buffer[0]); + return( -ENOSYS ); + } else { + /* doing a panic when dump_okay == 0 is almost always a waste of time */ + DUMP_PRINTF("dump_okay == 0 (Not ready to dump memory).\n"); + } + break; +#endif /* DUMP_DEBUG */ + } + return (0); +} + +/* + * Name: dump_open() + * Func: Open the dump device for use when the system crashes. + */ +static int +dump_open(struct inode *i, struct file *f) +{ + /* opening a device is straightforward -- nothing to do here */ + return (0); +} + +/* + * ----------------------------------------------------------------------- + * I N I T F U N C T I O N S + * ----------------------------------------------------------------------- + */ + +/* + * Name: dump_init_proc_entry() + * Func: Create a dump proc entry based on the /proc dump root. + * Returns 1 on failure, 0 on success. + */ +int +dump_init_proc_entry(char *name, struct proc_dir_entry *dirent) +{ + if (!(dirent = create_proc_entry(name, + S_IFREG|S_IRUGO|S_IWUSR, dump_root))) { + DUMP_PRINT("unable to initialize " + "/proc/%s/%s!\n", DUMP_ROOT_NAME, name); + return (1); + } + dirent->data = (void *)dirent; + dirent->read_proc = &dump_read_proc; + dirent->write_proc = NULL; + dirent->size = 16; + return (0); +} + +/* + * Name: dump_proc_init() + * Func: Initialize the /proc interfaces for dumping. + * + * Typically: + * /proc/sys/dump/ + * dump_compress dump_device dump_flags dump_level + */ +int +dump_proc_init(void) +{ + /* create the proc entries for the various tunables */ + dump_root = create_proc_entry(DUMP_ROOT_NAME, S_IFDIR, 0); + if (dump_root) { + dump_root->owner = THIS_MODULE; + } else { + DUMP_PRINTF("unable to initialize /proc/%s!\n", DUMP_ROOT_NAME); + return (-EBUSY); + } + + if (dump_init_proc_entry(DUMP_DEVICE_NAME, dump_dd)) { + remove_proc_entry(DUMP_ROOT_NAME, 0); + return (-EBUSY); + } + if (dump_init_proc_entry(DUMP_LEVEL_NAME, dump_l)) { + remove_proc_entry(DUMP_ROOT_NAME, 0); + remove_proc_entry(DUMP_DEVICE_NAME, dump_root); + return (-EBUSY); + } + if (dump_init_proc_entry(DUMP_FLAGS_NAME, dump_f)) { + remove_proc_entry(DUMP_ROOT_NAME, 0); + remove_proc_entry(DUMP_DEVICE_NAME, dump_root); + remove_proc_entry(DUMP_LEVEL_NAME, dump_root); + return (-EBUSY); + } + if (dump_init_proc_entry(DUMP_COMPRESS_NAME, dump_cp)) { + remove_proc_entry(DUMP_ROOT_NAME, 0); + remove_proc_entry(DUMP_DEVICE_NAME, dump_root); + remove_proc_entry(DUMP_LEVEL_NAME, dump_root); + remove_proc_entry(DUMP_FLAGS_NAME, dump_root); + return (-EBUSY); + } + return (0); +} + +/* + * Name: dump_proc_cleanup() + * Func: Cleanup the /proc interfaces for dumping. + */ +void +dump_proc_cleanup(void) +{ + /* remove the proc entries */ + remove_proc_entry(DUMP_DEVICE_NAME, dump_root); + remove_proc_entry(DUMP_LEVEL_NAME, dump_root); + remove_proc_entry(DUMP_FLAGS_NAME, dump_root); + remove_proc_entry(DUMP_COMPRESS_NAME, dump_root); + remove_proc_entry(DUMP_ROOT_NAME, 0); + return; +} + +/* + * Name: dump_init() + * Func: Initialize the dump process. This will set up any architecture + * dependent code. The big key is we need the memory offsets before + * the page table is initialized, because the base memory offset + * is changed after paging_init() is called. + */ +int +dump_init(void) +{ + struct sysinfo info; +#if DUMP_DEBUG + int i; +#endif + + /* try to initialize /proc interfaces */ + if (dump_proc_init() < 0) { + DUMP_PRINTF("dump_proc_init failed!; dump not initialized\n"); + return (-EBUSY); + } + + /* try to create our dump device */ + if (devfs_register_chrdev(DUMP_MAJOR, "dump", &dump_fops)) { + DUMP_PRINTF("cannot register dump character device!\n"); + return (-EBUSY); + } + + /* initialize the dump headers to zero */ + memset(&dump_header, 0, sizeof(dump_header)); + memset(&dump_header_asm, 0, sizeof(dump_header_asm)); + +#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_IA64) + /* + * CONFIG_DISCONTIGMEM and CONFIG_IA64 systems are responsible + * for initializing dump_mbank[] in __dump_init(). + */ + dump_mbanks = 1; + dump_mbank[ 0 ].start = 0; + dump_mbank[ 0 ].end = (((u64) max_mapnr) << PAGE_SHIFT) - 1; + dump_mbank[ 0 ].type = DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY; +#endif + + /* + * initialize the dump device at the arch level. + * + * if defined(CONFIG_DISCONTIGMEM) { + * __dump_init() must set up dump_mbank[]. + * } + */ + __dump_init((u64)PAGE_OFFSET); + + /* initialize the dump page buffer */ + dump_page_buf = (void *)0; + + /* set the dump function pointer for dump execution */ + dump_function_ptr = dump_execute; + + /* set the dump_compression_list structure up */ + dump_compress = DUMP_COMPRESS_NONE; + dump_compress_func = dump_compress_none; + dump_register_compression(&dump_none_compression); + + /* initialize the dump flags, dump level and dump_compress fields */ + dump_flags = DUMP_FLAGS_NONE; + dump_level = DUMP_LEVEL_ALL; + + /* grab the total memory size now (not if/when we crash) */ + si_meminfo(&info); + + /* set the memory size */ + dump_header.dh_memory_size = (u64)info.totalram; + +#if DUMP_DEBUG + for (i = 0; i < dump_mbanks; i++) { + DUMP_PRINTF("mbank[%d]: type:%d, phys_addr: " PU64X " ... " PU64X "\n", + i, + dump_mbank[i].type, + dump_mbank[i].start, + dump_mbank[i].end); + + if (dump_mbank[i].start % DUMP_PAGE_SIZE) { + DUMP_PRINTF("oops, start is not DUMP_PAGE_SIZE:%x aligned!\n", (int) DUMP_PAGE_SIZE); + } + if ((dump_mbank[i].end + 1) % DUMP_PAGE_SIZE) { + DUMP_PRINTF("oops, end is not DUMP_PAGE_SIZE:%x aligned!\n", (int) DUMP_PAGE_SIZE); + } + } +#endif /* DUMP_DEBUG */ + DUMP_PRINTF("Crash dump driver initialized.\n"); + return (0); +} + +void +dump_cleanup(void) +{ + /* get rid of the allocated dump page buffer */ + if (dump_page_buf_0) { + kfree((const void *)dump_page_buf_0); + } + + /* arch-specific cleanup routine */ + __dump_cleanup(); + + /* remove the proc entries */ + dump_proc_cleanup(); + + /* try to create our dump device */ + if (devfs_unregister_chrdev(DUMP_MAJOR, "dump")) { + DUMP_PRINT("cannot unregister dump character device!\n"); + } + + /* reset the dump function pointer */ + dump_function_ptr = NULL; + + return; +} + +EXPORT_SYMBOL(dump_register_compression); +EXPORT_SYMBOL(dump_unregister_compression); + +#ifdef MODULE +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,16)) +#if !defined(MODULE_LICENSE) +#define MODULE_LICENSE(str) +#endif +#endif + +MODULE_AUTHOR("Matt D. Robinson "); +MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver"); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16)) +MODULE_LICENSE("GPL"); +#endif +module_init(dump_init); +module_exit(dump_cleanup); +#endif /* MODULE */ diff -Nur linux-2.4.19/drivers/dump/dump_gzip.c linux-2.4.19-sgi211r3/drivers/dump/dump_gzip.c --- linux-2.4.19/drivers/dump/dump_gzip.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_gzip.c Thu Oct 24 04:22:20 2002 @@ -0,0 +1,143 @@ +/* + * GZIP Compression functions for kernel crash dumps. + * + * Created by: Matt Robinson (yakker@sourceforge.net) + * Copyright 2001 Matt D. Robinson. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dump_zlib.c" + +MODULE_AUTHOR("Matt D. Robinson "); +MODULE_DESCRIPTION("GZIP Compression Module for LKCD"); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16)) +MODULE_LICENSE("GPL"); +#endif + +/* + * ----------------------------------------------------------------------- + * D E F I N I T I O N S + * ----------------------------------------------------------------------- + */ +#define DUMP_MODULE_NAME "dump_gzip" +#define DUMP_PRINTN(format, args...) \ + printk("%s: " format , DUMP_MODULE_NAME , ## args); +#define DUMP_PRINT(format, args...) \ + printk(format , ## args); + +/* + * Name: dump_compress_gzip_alloc() + * Func: The kmalloc function for gzip dump compression. + */ +static void * +dump_compress_gzip_alloc(void *arg, unsigned int items, unsigned int size) +{ + return ((void *)kmalloc((size * items), GFP_ATOMIC)); +} + +/* + * Name: dump_compress_gzip_free() + * Func: The kfree function for gzip dump compression. + */ +static void +dump_compress_gzip_free(void *arg, void *ptr) +{ + kfree(ptr); + return; +} + +/* + * Name: dump_compress_gzip() + * Func: Compress a DUMP_PAGE_SIZE page using gzip-style algorithms (the. + * deflate functions similar to what's used in PPP). + */ +static int +dump_compress_gzip(char *old, int oldsize, char *new, int newsize) +{ + /* error code and dump stream */ + int err; + z_stream dump_stream; + + /* setup the alloc/free functions */ + dump_stream.zalloc = dump_compress_gzip_alloc; + dump_stream.zfree = dump_compress_gzip_free; + dump_stream.opaque = (void *)0; + + if ((err = deflateInit(&dump_stream, Z_BEST_COMPRESSION)) != Z_OK) { + /* fall back to RLE compression */ + DUMP_PRINT("dump_compress_gzip(): deflateInit() " + "failed (%d)!\n", err); + return (0); + } + + /* use old (page of memory) and size (DUMP_PAGE_SIZE) as in-streams */ + dump_stream.next_in = old; + dump_stream.avail_in = oldsize; + + /* out streams are new (dpcpage) and new size (DUMP_DPC_PAGE_SIZE) */ + dump_stream.next_out = new; + dump_stream.avail_out = newsize; + + /* deflate the page -- check for error */ + err = deflate(&dump_stream, Z_FINISH); + if (err != Z_STREAM_END) { + /* zero is return code here */ + (void)deflateEnd(&dump_stream); + DUMP_PRINT("dump_compress_gzip(): deflate() failed (%d)!\n", + err); + return (0); + } + + /* let's end the deflated compression stream */ + if ((err = deflateEnd(&dump_stream)) != Z_OK) { + DUMP_PRINT("dump_compress_gzip(): deflateEnd() " + "failed (%d)!\n", err); + } + + /* return the compressed byte total (if it's smaller) */ + if (dump_stream.total_out >= oldsize) { + return (oldsize); + } + return (dump_stream.total_out); +} + +/* setup the gzip compression functionality */ +static dump_compress_t dump_gzip_compression = { + compress_type: DUMP_COMPRESS_GZIP, + compress_func: dump_compress_gzip, +}; + +/* + * Name: dump_compress_gzip_init() + * Func: Initialize gzip as a compression mechanism. + */ +int __init +dump_compress_gzip_init(void) +{ + dump_register_compression(&dump_gzip_compression); + return (0); +} + +/* + * Name: dump_compress_gzip_cleanup() + * Func: Remove gzip as a compression mechanism. + */ +void __init +dump_compress_gzip_cleanup(void) +{ + dump_unregister_compression(DUMP_COMPRESS_GZIP); +} + +/* module initialization */ +module_init(dump_compress_gzip_init); +module_exit(dump_compress_gzip_cleanup); diff -Nur linux-2.4.19/drivers/dump/dump_i386.c linux-2.4.19-sgi211r3/drivers/dump/dump_i386.c --- linux-2.4.19/drivers/dump/dump_i386.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_i386.c Thu Oct 24 04:22:20 2002 @@ -0,0 +1,316 @@ +/* + * Architecture specific (i386) functions for Linux crash dumps. + * + * Created by: Matt Robinson (yakker@sgi.com) + * + * Copyright 1999 Silicon Graphics, Inc. All rights reserved. + * + * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com) + * Copyright 2000 TurboLinux, Inc. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* + * The hooks for dumping the kernel virtual memory to disk are in this + * file. Any time a modification is made to the virtual memory mechanism, + * these routines must be changed to use the new mechanisms. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int alloc_dha_stack(void) +{ + int i; + void *ptr; + + if (dump_header_asm.dha_stack[0]) + return 0; + + ptr = vmalloc(THREAD_SIZE * smp_num_cpus); + if (!ptr) { + printk("vmalloc for dha_stacks failed\n"); + return -ENOMEM; + } + + for (i = 0; i < smp_num_cpus; i++) { + dump_header_asm.dha_stack[i] = (void *)((unsigned long)ptr + (i * THREAD_SIZE)); + } + return 0; +} + +static int free_dha_stack(void) +{ + if (dump_header_asm.dha_stack[0]) + vfree(dump_header_asm.dha_stack[0]); + return 0; +} + +/* In case of panic dumps, we collects regs on entry to panic. + * so, we shouldn't 'fix' ssesp here again. But it is hard to + * tell just looking at regs whether ssesp need fixing. We make + * this decision by looking at xss in regs. If we have better + * means to determine that ssesp are valid (by some flag which + * tells that we are here due to panic dump), then we can use + * that instead of this kludge. + */ +static inline void +fix_ssesp(struct pt_regs *regs, int cpu) +{ + if (!user_mode(regs)) { + if ((cpu == dump_header_asm.dha_dumping_cpu) && + regs->xss == __KERNEL_DS) + return; + dump_header_asm.dha_smp_regs[cpu].esp = + (unsigned long)&(regs->esp); + __asm__ __volatile__ ("movw %%ss, %%ax;" + :"=a"(dump_header_asm.dha_smp_regs[cpu].xss)); + } +} + +static void +save_this_cpu_state(int cpu, struct pt_regs *regs, struct task_struct *tsk) +{ + dump_header_asm.dha_smp_regs[cpu] = *regs; + dump_header_asm.dha_smp_current_task[cpu] = tsk; + fix_ssesp(regs, cpu); + + if (dump_header_asm.dha_stack[cpu]) { + memcpy(dump_header_asm.dha_stack[cpu], tsk, THREAD_SIZE); + } + return; +} + +#ifdef CONFIG_SMP +static int dump_expect_ipi[NR_CPUS]; +static atomic_t waiting_for_dump_ipi; +static int wait_for_dump_ipi = 1; /* always wait for ipi to to be handled */ +extern void (*dump_trace_ptr)(struct pt_regs *); +static unsigned long saved_affinity[NR_IRQS]; + +static int +dump_ipi_handler(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + if (!dump_expect_ipi[cpu]) { + return 0; + } + + save_this_cpu_state(cpu, regs, current); + + dump_expect_ipi[cpu] = 0; + atomic_dec(&waiting_for_dump_ipi); + return 1; +} + +/* save registers on other processors */ +void +save_other_cpu_states(void) +{ + int i; + + if (smp_num_cpus > 1) { + atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1); + for (i = 0; i < NR_CPUS; i++) + dump_expect_ipi[i] = 1; + + dump_ipi_function_ptr = dump_ipi_handler; + dump_send_ipi(); + /* may be we dont need to wait for NMI to be processed. + just write out the header at the end of dumping, if + this IPI is not processed untill then, there probably + is a problem and we just fail to capture state of + other cpus. */ + if (wait_for_dump_ipi) { + while(atomic_read(&waiting_for_dump_ipi)) + barrier(); + dump_ipi_function_ptr = NULL; + } + } + return; +} + +/* located in arch/i386/kernel/traps.c */ +extern void show_this_cpu_state(int cpu, struct pt_regs * regs, struct task_struct *tsk); + +void +show_cpu_state(struct pt_regs * regs) +{ + int i; + __dump_configure_header(regs); + for (i = 0; i < smp_num_cpus; i++) { + show_this_cpu_state(i, &dump_header_asm.dha_smp_regs[i], + dump_header_asm.dha_stack[i]); + } + return; +} + +/* + * Non dumping cpus will spin here. If a cpu is handling an irq when ipi is + * received, we let go of it here while making sure that it hits schedule + * on the way up and make it spin there instead. + */ +static void +__dump_spin(void *arg) +{ + if (in_irq()) { + current->need_resched = 1; + } else { + while (dump_in_progress) ; + } + return; +} + +/* + * Routine to save the old irq affinities and change affinities of all irqs to + * the dumping cpu. + */ +static void +__dump_set_irq_affinity(void) +{ + int i; + int cpu = smp_processor_id(); + + memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long)); + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == NULL) + continue; + irq_affinity[i] = 1UL << cpu; + if (irq_desc[i].handler->set_affinity != NULL) + irq_desc[i].handler->set_affinity(i, irq_affinity[i]); + } +} + +/* + * Restore old irq affinities. + */ +static void +__dump_reset_irq_affinity(void) +{ + int i; + + memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long)); + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == NULL) + continue; + if (irq_desc[i].handler->set_affinity != NULL) + irq_desc[i].handler->set_affinity(i, saved_affinity[i]); + } +} + +#else /* !CONFIG_SMP */ +#define save_other_cpu_states() +#endif /* !CONFIG_SMP */ + +/* + * Name: __dump_silence_system() + * Func: Do an architecture-specific silencing of the system. + * - Change irq affinities + * - Wait for other cpus to come out of irq handling + * - Send CALL_FUNCTION_VECTOR ipi to other cpus to put them to spin + */ +unsigned int +__dump_silence_system(unsigned int stage) +{ +#ifdef CONFIG_SMP + if (stage) { /* Do this after interrupts are enabled */ + /* read the comments above ... */ + __dump_set_irq_affinity(); + synchronize_irq(); + smp_call_function(__dump_spin, NULL, 0, 0); + } +#endif + + /* return */ + return (0); +} + +/* + * Name: __dump_resume_system() + * Func: Resume the system state in an architecture-specific way. + */ +unsigned int +__dump_resume_system(unsigned int stage) +{ +#ifdef CONFIG_SMP + /* put the irq affinity tables back */ + __dump_reset_irq_affinity(); +#endif + + /* return */ + return (0); +} + +/* + * Name: __dump_configure_header() + * Func: Configure the dump header with all proper values. + */ +int +__dump_configure_header(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + dump_header_asm.dha_smp_num_cpus = smp_num_cpus; + dump_header_asm.dha_dumping_cpu = cpu; + + save_this_cpu_state(cpu, regs, current); + + save_other_cpu_states(); + + return (1); +} + +/* + * Name: __dump_init() + * Func: Initialize the dumping routine process. This is in case + * it's necessary in the future. + */ +void +__dump_init(uint64_t local_memory_start) +{ + /* return */ + return; +} + +/* + * Name: __dump_open() + * Func: Open the dump device (architecture specific). This is in + * case it's necessary in the future. + */ +void +__dump_open(void) +{ + alloc_dha_stack(); +#ifdef CONFIG_SMP + dump_trace_ptr = show_cpu_state; +#endif + /* return */ + return; +} + +/* + * Name: __dump_cleanup() + * Func: Free any architecture specific data structures. This is called + * when the dump module is being removed. + */ +void +__dump_cleanup(void) +{ + free_dha_stack(); +#ifdef CONFIG_SMP + dump_trace_ptr = NULL; +#endif + /* return */ + return; +} + diff -Nur linux-2.4.19/drivers/dump/dump_ia64.c linux-2.4.19-sgi211r3/drivers/dump/dump_ia64.c --- linux-2.4.19/drivers/dump/dump_ia64.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_ia64.c Tue Jan 28 18:24:28 2003 @@ -0,0 +1,381 @@ +/* + * Architecture specific (ia64) functions for Linux crash dumps. + * + * Created by: Matt Robinson (yakker@sgi.com) + * Contributions from SGI, IBM, and others. + * + * 2.4 kernel modifications by: Matt D. Robinson (yakker@alacritech.com) + * ia64 kernel modifications by: Piet Delaney (piet@www.piet.net) + * + * Copyright (C) 2001 - 2002 Matt D. Robinson (yakker@alacritech.com) + * Copyright (C) 2002-2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* + * The hooks for dumping the kernel virtual memory to disk are in this + * file. Any time a modification is made to the virtual memory mechanism, + * these routines must be changed to use the new mechanisms. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* static variables */ +static unsigned long saved_affinity[NR_IRQS]; + +static int alloc_dha_stack(void) +{ + int i; + void *ptr; + + if (dump_header_asm.dha_stack[0]) + return 0; + + ptr = vmalloc(THREAD_SIZE * smp_num_cpus); + if (!ptr) { + printk("vmalloc for dha_stacks failed\n"); + return -ENOMEM; + } + + for (i = 0; i < smp_num_cpus; i++) { + dump_header_asm.dha_stack[i] = (void *)((unsigned long)ptr + (i * THREAD_SIZE)); + } + return 0; +} + +static int free_dha_stack(void) +{ + if (dump_header_asm.dha_stack[0]) + vfree(dump_header_asm.dha_stack[0]); + + return 0; +} + +static void +save_this_cpu_state(int cpu, struct pt_regs *regs, struct task_struct *tsk) +{ + if( regs ) { + dump_header_asm.dha_smp_regs[cpu] = *regs; + } + dump_header_asm.dha_smp_current_task[cpu] = tsk; + + if (tsk && dump_header_asm.dha_stack[cpu]) { + memcpy(dump_header_asm.dha_stack[cpu], tsk, THREAD_SIZE); + } + return; +} + +#ifdef CONFIG_SMP +static int dump_expect_ipi[NR_CPUS]; +static atomic_t waiting_for_dump_ipi; +static int wait_for_dump_ipi = 1; /* always wait for ipi to to be handled */ +extern void (*dump_trace_ptr)(struct pt_regs *); + +static int +dump_ipi_handler(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + if (!dump_expect_ipi[cpu]) { + return 0; + } + + save_this_cpu_state(cpu, regs, current); + + dump_expect_ipi[cpu] = 0; + atomic_dec(&waiting_for_dump_ipi); + return 1; +} + +/* save registers on other processors */ +void +save_other_cpu_states(void) +{ + int i; + + if (smp_num_cpus > 1) { + atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1); + for (i = 0; i < NR_CPUS; i++) + dump_expect_ipi[i] = 1; + + dump_ipi_function_ptr = dump_ipi_handler; + dump_send_ipi(); + /* + * may be we don't need to wait for NMI to be processed. + * just write out the header at the end of dumping, if + * this IPI is not processed until then, there probably + * is a problem and we just fail to capture state of + * other cpus. + */ + if (wait_for_dump_ipi) { + while(atomic_read(&waiting_for_dump_ipi)) + barrier(); + + dump_ipi_function_ptr = NULL; + } + } + return; +} + +#else +#define save_other_cpu_states() +#endif + +/* + * Name: __dump_kernel_addr() + * Func: Return kernel load address. + */ +unsigned long +__dump_kernel_addr(void) +{ + return __tpa(KERNEL_START); +} + +/* + * Name: __dump_configure_header() + * Func: Configure the dump header with all proper values. + */ +int +__dump_configure_header(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + /* flush the dirty registers to backing store */ + asm("flushrs"); + + dump_header_asm.dha_smp_num_cpus = smp_num_cpus; + dump_header_asm.dha_dumping_cpu = cpu; + + /* Save the pointer to the pt_regs struct */ + dump_header_asm.dha_pt_regs = regs; + dump_header_asm.dha_kernel_addr = __dump_kernel_addr(); + + save_this_cpu_state(cpu, regs, current); + + save_other_cpu_states(); + + /* return success */ + return (1); +} + + +#define dim(x) (sizeof(x)/sizeof(*(x))) + +void +__init_mem_banks(void) +{ + void *p; + int i = 0; + void *efi_map_start = __va(ia64_boot_param->efi_memmap); + void *efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + u64 efi_desc_size = ia64_boot_param->efi_memdesc_size; + + memset (dump_mbank, 0, sizeof dump_mbank); + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + efi_memory_desc_t *md = p; + u64 start = md->phys_addr; + u64 end = start + (md->num_pages << DUMP_EF_PAGE_SHIFT) - 1; + int type; + + if (i >= dim(dump_mbank)) { + break; + } + + /* + * NB: The attribute EFI_MEMORY_UC means the memory bank can support Uncached access, + * not that the memory us correctly running with Uncached access. + */ + if ( (md->attribute & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0 ) { + continue; + } + switch(md->type) { + case EFI_UNUSABLE_MEMORY: /* Ignore it */ + continue; + + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + type = DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY; + break; + + default: + type = DUMP_MBANK_TYPE_OTHER; + break; + + } + dump_mbank[ i ].type = type; + dump_mbank[ i ].start = start; + dump_mbank[ i ].end = end; + i++; + } + dump_mbanks = i; + return; +} + +/* + * Name: __dump_init() + * Func: Initialize the dumping routine process. This is in case + * it's necessary in the future. + */ +void +__dump_init(uint64_t local_memory_start) +{ + __init_mem_banks(); /* Initialize Memory Banks */ + return; +} + +/* + * Name: __dump_open() + * Func: Open the dump device (architecture specific). This is in + * case it's necessary in the future. + */ +void +__dump_open(void) +{ + alloc_dha_stack(); + + return; +} + + +/* + * Name: __dump_cleanup() + * Func: Free any architecture specific data structures. This is called + * when the dump module is being removed. + */ +void +__dump_cleanup(void) +{ + free_dha_stack(); + + return; +} + +#ifdef CONFIG_SMP +/* + * Non dumping cpus will spin here. If a cpu is handling an irq when ipi is + * received, we let go of it here while making sure that it hits schedule + * on the way up and make it spin there instead. + */ +static void +__dump_spin(void *arg) +{ + if (in_irq()) { + current->need_resched = 1; + } else { + while (dump_in_progress) ; + } + return; +} + +/* + * Routine to save the old irq affinities and change affinities of all irqs to + * the dumping cpu. + * + * NB: Need to be expanded to multiple nodes. + */ +static void +__dump_set_irq_affinity(void) +{ + int i; + int cpu = smp_processor_id(); + + memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long)); + + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc(i)->handler == NULL) { + continue; + } + irq_affinity[i] = 1UL << cpu; + if (irq_desc(i)->handler->set_affinity != NULL) { + irq_desc(i)->handler->set_affinity(i, irq_affinity[i]); + } + } +} + +/* + * Restore old irq affinities. + */ +static void +__dump_reset_irq_affinity(void) +{ + int i; + + memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long)); + + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc(i)->handler == NULL) { + continue; + } + if (irq_desc(i)->handler->set_affinity != NULL) { + irq_desc(i)->handler->set_affinity(i, saved_affinity[i]); + } + } +} +#endif + + +/* + * Name: __dump_silence_system() + * Func: Do an architecture-specific silencing of the system. + */ +unsigned int +__dump_silence_system(unsigned int stage) +{ +#ifdef CONFIG_SMP + if (stage) { /* Do this after interrupts are enabled */ + /* read the comments above ... */ + __dump_set_irq_affinity(); + synchronize_irq(); + smp_call_function(__dump_spin, NULL, 0, 0); + } +#endif + return (0); +} + +/* + * Name: __dump_resume_system() + * Func: Resume the system state in an architecture-specific way. + */ +unsigned int +__dump_resume_system(unsigned int stage) +{ +#ifdef CONFIG_SMP + /* put the irq affinity tables back */ + __dump_reset_irq_affinity(); +#endif + + return (0); +} + + +int __dump_memcpy_mc_expected = 0; /* Doesn't help yet */ + +/* + * An ia64 version of memcpy() that tries to avoid avoid problems. + * Might be used in the future to access I/O registers and + * uncached memory. + */ +void * __dump_memcpy(void * dest, const void *src, size_t count) +{ + void *vp; + + vp = memcpy(dest, src, count); + + return(vp); +} diff -Nur linux-2.4.19/drivers/dump/dump_rle.c linux-2.4.19-sgi211r3/drivers/dump/dump_rle.c --- linux-2.4.19/drivers/dump/dump_rle.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_rle.c Thu Oct 24 04:22:20 2002 @@ -0,0 +1,176 @@ +/* + * RLE Compression functions for kernel crash dumps. + * + * Created by: Matt Robinson (yakker@sourceforge.net) + * Copyright 2001 Matt D. Robinson. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* header files */ +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Matt D. Robinson "); +MODULE_DESCRIPTION("RLE Compression Module for LKCD"); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16)) +MODULE_LICENSE("GPL"); +#endif + +/* + * Name: dump_compress_rle() + * Func: Compress a DUMP_PAGE_SIZE (hardware) page down to something more reasonable, + * if possible. This is the same routine we use in IRIX. + */ +static int +dump_compress_rle(char *old, int oldsize, char *new, int newsize) +{ + int ri, wi, count = 0; + u_char value = 0, cur_byte; + + /* + * If the block should happen to "compress" to larger than the + * buffer size, allocate a larger one and change cur_buf_size. + */ + + wi = ri = 0; + + while (ri < oldsize) { + if (!ri) { + cur_byte = value = old[ri]; + count = 0; + } else { + if (count == 255) { + if (wi + 3 > oldsize) { + return oldsize; + } + new[wi++] = 0; + new[wi++] = count; + new[wi++] = value; + value = cur_byte = old[ri]; + count = 0; + } else { + if ((cur_byte = old[ri]) == value) { + count++; + } else { + if (count > 1) { + if (wi + 3 > oldsize) { + return oldsize; + } + new[wi++] = 0; + new[wi++] = count; + new[wi++] = value; + } else if (count == 1) { + if (value == 0) { + if (wi + 3 > oldsize) { + return oldsize; + } + new[wi++] = 0; + new[wi++] = 1; + new[wi++] = 0; + } else { + if (wi + 2 > oldsize) { + return oldsize; + } + new[wi++] = value; + new[wi++] = value; + } + } else { /* count == 0 */ + if (value == 0) { + if (wi + 2 > oldsize) { + return oldsize; + } + new[wi++] = value; + new[wi++] = value; + } else { + if (wi + 1 > oldsize) { + return oldsize; + } + new[wi++] = value; + } + } /* if count > 1 */ + + value = cur_byte; + count = 0; + + } /* if byte == value */ + + } /* if count == 255 */ + + } /* if ri == 0 */ + ri++; + + } + if (count > 1) { + if (wi + 3 > oldsize) { + return oldsize; + } + new[wi++] = 0; + new[wi++] = count; + new[wi++] = value; + } else if (count == 1) { + if (value == 0) { + if (wi + 3 > oldsize) + return oldsize; + new[wi++] = 0; + new[wi++] = 1; + new[wi++] = 0; + } else { + if (wi + 2 > oldsize) + return oldsize; + new[wi++] = value; + new[wi++] = value; + } + } else { /* count == 0 */ + if (value == 0) { + if (wi + 2 > oldsize) + return oldsize; + new[wi++] = value; + new[wi++] = value; + } else { + if (wi + 1 > oldsize) + return oldsize; + new[wi++] = value; + } + } /* if count > 1 */ + + value = cur_byte; + count = 0; + return (wi); +} + +/* setup the rle compression functionality */ +static dump_compress_t dump_rle_compression = { + compress_type: DUMP_COMPRESS_RLE, + compress_func: dump_compress_rle, +}; + +/* + * Name: dump_compress_rle_init() + * Func: Initialize rle compression for dumping. + */ +int __init +dump_compress_rle_init(void) +{ + dump_register_compression(&dump_rle_compression); + return (0); +} + +/* + * Name: dump_compress_rle_cleanup() + * Func: Remove rle compression for dumping. + */ +void +dump_compress_rle_cleanup(void) +{ + dump_unregister_compression(DUMP_COMPRESS_RLE); +} + +/* module initialization */ +module_init(dump_compress_rle_init); +module_exit(dump_compress_rle_cleanup); diff -Nur linux-2.4.19/drivers/dump/dump_zlib.c linux-2.4.19-sgi211r3/drivers/dump/dump_zlib.c --- linux-2.4.19/drivers/dump/dump_zlib.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_zlib.c Thu Oct 24 04:22:20 2002 @@ -0,0 +1,5374 @@ +/* + * This file is derived from various .h and .c files from the zlib-1.0.4 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. See zlib.h for conditions of + * distribution and use. + * + * Changes that have been made include: + * - added Z_PACKET_FLUSH (see zlib.h for details) + * - added inflateIncomp and deflateOutputPending + * - allow strm->next_out to be NULL, meaning discard the output + * + * $Id: dump_zlib.c,v 1.1 2001/10/27 23:43:41 yakker Exp $ + */ + +/* + * ==FILEVERSION 971210== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + +#define NO_DUMMY_DECL +#define NO_ZCFUNCS +#define MY_ZCALLOC + +#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) +#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */ +#endif + + +/* +++ zutil.h */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "dump_zlib.h" + +#if defined(KERNEL) || defined(_KERNEL) +/* Assume this is a *BSD or SVR4 kernel */ +#include +#include +#include +# define HAVE_MEMCPY +# define memcpy(d, s, n) bcopy((s), (d), (n)) +# define memset(d, v, n) bzero((d), (n)) +# define memcmp bcmp + +#else +#if defined(__KERNEL__) +/* Assume this is a Linux kernel */ +#include +#define HAVE_MEMCPY + +#else /* not kernel */ + +#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS) +# include +# include +#else + extern int errno; +#endif +#ifdef STDC +# include +# include +#endif +#endif /* __KERNEL__ */ +#endif /* _KERNEL || KERNEL */ + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# ifdef __TURBOC__ +# include +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define FOPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef MACOS +# define OS_CODE 0x07 +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef FOPEN +# define FOPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len)); + extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include +# ifndef verbose +# define verbose 0 +# endif + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len)); + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ +/* --- zutil.h */ + +/* +++ deflate.h */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +/* #include "zutil.h" */ + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct deflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + ulg compressed_len; /* total bit length of compressed file */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG_ZLIB + ulg bits_sent; /* bit length of the compressed data */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_stored_type_only OF((deflate_state *)); + +#endif +/* --- deflate.h */ + +/* +++ deflate.c */ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */ + +/* #include "deflate.h" */ + +char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_slow OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, charf *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG_ZLIB +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +local config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * IN assertion: all calls to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int noheader = 0; + static char* my_version = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; +#ifndef NO_ZCFUNCS + if (strm->zalloc == Z_NULL) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == Z_NULL) strm->zfree = zcfree; +#endif + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { /* undocumented feature: suppress zlib header */ + noheader = 1; + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->noheader = noheader; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + return Z_STREAM_ERROR; + + s = (deflate_state *) strm->state; + if (s->status != INIT_STATE) return Z_STREAM_ERROR; + + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy((charf *)s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->noheader < 0) { + s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + } + s->status = s->noheader ? BUSY_STATE : INIT_STATE; + strm->adler = 1; + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = (deflate_state *) strm->state; + + if (level == Z_DEFAULT_COMPRESSION) { + level = 6; + } + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + deflate_state *s = (deflate_state *) strm->state; + unsigned len = s->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + if (strm->next_out != Z_NULL) { + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + } + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* ========================================================================= */ +int deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) strm->state; + + if ((strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the zlib header */ + if (s->status == INIT_STATE) { + + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags = (s->level-1) >> 1; + + if (level_flags > 3) level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = 1L; + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUFF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush == Z_PACKET_FLUSH) { + /* Output just the 3-bit `stored' block type value, + but not a zero length. */ + _tr_stored_type_only(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + +// if (flush != Z_FINISH) return Z_OK; + if (flush != Z_FINISH) { + return Z_OK; + } + if (s->noheader) return Z_STREAM_END; + + /* Write the zlib trailer (adler32) */ + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + s->noheader = -1; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int deflateEnd (strm) + z_streamp strm; +{ + int status; + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = (deflate_state *) strm->state; + + status = s->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, s->pending_buf); + TRY_FREE(strm, s->head); + TRY_FREE(strm, s->prev); + TRY_FREE(strm, s->window); + + ZFREE(strm, s); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + */ +int deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) + return Z_STREAM_ERROR; + ss = (deflate_state *) source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* ??? following zmemcpy doesn't work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +} + +/* =========================================================================== + * Return the number of bytes of output which are immediately available + * for output from the decompressor. + */ +int deflateOutputPending (strm) + z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return 0; + + return ((deflate_state *)(strm->state))->pending; +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + charf *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (!((deflate_state *)(strm->state))->noheader) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#ifdef DEBUG_ZLIB +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp((charf *)s->window + match, + (charf *)s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + } else if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy((charf *)s->window, (charf *)s->window+wsize, + (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead, + more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + bflush = _tr_tally(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in hash table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + bflush = _tr_tally (s, 0, s->window[s->strstart]); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + bflush = _tr_tally(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + if (_tr_tally (s, 0, s->window[s->strstart-1])) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally (s, 0, s->window[s->strstart-1]); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +/* --- deflate.c */ + +/* +++ trees.c */ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */ + +/* #include "deflate.h" */ + +#ifdef DEBUG_ZLIB +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +local uch dist_code[512]; +/* distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +local uch length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +struct static_tree_desc_s { + ct_data *static_tree; /* static tree or NULL */ + intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifndef DEBUG_ZLIB +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG_ZLIB */ +# define send_code(s, c, tree) \ + { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +#define d_code(dist) \ + ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. dist_code[256] and dist_code[257] are never + * used. + */ + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG_ZLIB +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG_ZLIB */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG_ZLIB */ + + +#define MAX(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. In a multi-threaded environment, + * this function may be called by two threads concurrently, but this is + * harmless since both invocations do exactly the same thing. + */ +local void tr_static_init() +{ + static int static_init_done; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; +} + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->compressed_len = 0L; + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG_ZLIB + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + ct_data *stree = desc->stat_desc->static_tree; + intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* Send just the `stored block' type code without any length bytes or data. + */ +void _tr_stored_type_only(s) + deflate_state *s; +{ + send_bits(s, (STORED_BLOCK << 1), 3); + bi_windup(s); + s->compressed_len = (s->compressed_len + 3) & ~7L; +} + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. This function + * returns the total compressed length for the file so far. + */ +ulg _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + /* If compression failed and this is the first and last block, + * and if the .zip file can be seeked (to rewrite the local header), + * the whole file is transformed into a stored file: + */ +#ifdef STORED_FILE_OK +# ifdef FORCE_STORED_FILE + if (eof && s->compressed_len == 0L) { /* force stored file */ +# else + if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { +# endif + /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ + if (buf == (charf*)0) error ("block vanished"); + + copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ + s->compressed_len = stored_len << 3; + s->method = STORED; + } else +#endif /* STORED_FILE_OK */ + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); + s->compressed_len += 3 + s->static_len; + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); + s->compressed_len += 3 + s->opt_len; + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + init_block(s); + + if (eof) { + bi_windup(s); + s->compressed_len += 7; /* align on byte boundary */ + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); + + return s->compressed_len >> 3; +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + + /* Try to guess if it is profitable to stop the current block here */ + if (s->level > 2 && (s->last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG_ZLIB + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG_ZLIB + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG_ZLIB + s->bits_sent += (ulg)len<<3; +#endif + /* bundle up the put_byte(s, *buf++) calls */ + zmemcpy(&s->pending_buf[s->pending], buf, len); + s->pending += len; +} +/* --- trees.c */ + +/* +++ inflate.c */ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ + +/* +++ infblock.h */ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_addhistory OF(( + inflate_blocks_statef *, + z_streamp)); + +extern int inflate_packet_flush OF(( + inflate_blocks_statef *)); +/* --- infblock.h */ + +#ifndef NO_DUMMY_DECL +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ +#endif + +/* inflate private state */ +struct internal_state { + + /* mode */ + enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ + mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z) +z_streamp z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, &c); + Trace((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z) +z_streamp z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z, &c); + ZFREE(z, z->state); + z->state = Z_NULL; + Trace((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2_(z, w, version, stream_size) +z_streamp z; +int w; +const char *version; +int stream_size; +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; +#ifndef NO_ZCFUNCS + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; +#endif + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Trace((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z, version, stream_size) +z_streamp z; +const char *version; +int stream_size; +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z, f) +z_streamp z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0) + return Z_STREAM_ERROR; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) + r = inflate_packet_flush(z->state->blocks); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r != Z_STREAM_END) + return r; + r = Z_OK; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + + empty: + if (f != Z_PACKET_FLUSH) + return r; + z->state->mode = BAD; + z->msg = (char *)"need more for packet flush"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_DATA_ERROR; +} + + +int inflateSetDictionary(z, dictionary, dictLength) +z_streamp z; +const Bytef *dictionary; +uInt dictLength; +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ + +int inflateIncomp(z) +z_stream *z; +{ + if (z->state->mode != BLOCKS) + return Z_DATA_ERROR; + return inflate_addhistory(z->state->blocks, z); +} + + +int inflateSync(z) +z_streamp z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + if (*p == (Byte)(m < 2 ? 0 : 0xff)) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + +#undef NEEDBYTE +#undef NEXTBYTE +/* --- inflate.c */ + +/* +++ infblock.c */ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "infblock.h" */ + +/* +++ inftrees.h */ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit machines) */ + union { + uInt Base; /* literal, length base, or distance base */ + inflate_huft *Next; /* pointer to next level of table */ + } more; +}; + +#ifdef DEBUG_ZLIB + extern uInt inflate_hufts; +#endif + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *)); /* distance tree result */ + +extern int inflate_trees_free OF(( + inflate_huft *, /* tables to free */ + z_streamp )); /* for zfree function */ + +/* --- inftrees.h */ + +/* +++ infcodes.h */ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* --- infcodes.h */ + +/* +++ infutil.h */ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONEB, /* finished last block, done */ + BADB} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_huft *tl; + inflate_huft *td; /* trees to free */ + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#endif +/* --- infutil.h */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + if (s->checkfn != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + { + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + } + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0); + Trace((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_streamp z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Trace((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, &s->check); + return s; +} + + +#ifdef DEBUG_ZLIB + extern uInt inflate_hufts; +#endif +int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Trace((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Trace((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.tl = Z_NULL; /* don't try to free these */ + s->sub.decode.td = Z_NULL; + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Trace((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BADB; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BADB; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BADB; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (t < 19) + t = 19; + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BADB; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->word.what.Bits; + c = h->more.Base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + inflate_trees_free(s->sub.trees.tb, z); + ZFREE(z, s->sub.trees.blens); + s->mode = BADB; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + inflate_trees_free(s->sub.trees.tb, z); + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; +#ifdef DEBUG_ZLIB + inflate_hufts = 0; +#endif + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BADB; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n", + inflate_hufts, sizeof(inflate_huft))); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + inflate_trees_free(td, z); + inflate_trees_free(tl, z); + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONEB; + case DONEB: + r = Z_STREAM_END; + LEAVE + case BADB: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + inflate_blocks_reset(s, z, c); + ZFREE(z, s->window); + ZFREE(z, s); + Trace((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(s, d, n) +inflate_blocks_statef *s; +const Bytef *d; +uInt n; +{ + zmemcpy((charf *)s->window, d, n); + s->read = s->write = s->window + n; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ +int inflate_addhistory(s, z) +inflate_blocks_statef *s; +z_stream *z; +{ + uLong b; /* bit buffer */ /* NOT USED HERE */ + uInt k; /* bits in bit buffer */ /* NOT USED HERE */ + uInt t; /* temporary storage */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + if (s->read != s->write) + return Z_STREAM_ERROR; + if (s->mode != TYPE) + return Z_DATA_ERROR; + + /* we're ready to rock */ + LOAD + /* while there is input ready, copy to output buffer, moving + * pointers as needed. + */ + while (n) { + t = n; /* how many to do */ + /* is there room until end of buffer? */ + if (t > m) t = m; + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, t); + zmemcpy(q, p, t); + q += t; + p += t; + n -= t; + z->total_out += t; + s->read = q; /* drag read pointer forward */ +/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ + if (q == s->end) { + s->read = q = s->window; + m = WAVAIL; + } + } + UPDATE + return Z_OK; +} + + +/* + * At the end of a Deflate-compressed PPP packet, we expect to have seen + * a `stored' block type value but not the (zero) length bytes. + */ +int inflate_packet_flush(s) + inflate_blocks_statef *s; +{ + if (s->mode != LENS) + return Z_DATA_ERROR; + s->mode = TYPE; + return Z_OK; +} +/* --- infblock.c */ + +/* +++ inftrees.c */ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ + +char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + z_streamp )); /* for zalloc function */ + +local voidpf falloc OF(( + voidpf, /* opaque pointer (not used) */ + uInt, /* number of items */ + uInt)); /* size of item */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ +#define N_MAX 288 /* maximum number of codes in any set */ + +#ifdef DEBUG_ZLIB + uInt inflate_hufts; +#endif + +local int huft_build(b, n, s, d, e, t, m, zs) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= N_MAX) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +const uIntf *d; /* list of base values for non-simple codes */ +const uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +z_streamp zs; /* for zalloc function */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + uInt v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (inflate_huft *)ZALLOC + (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) + { + if (h) + inflate_trees_free(u[0], zs); + return Z_MEM_ERROR; /* not enough memory */ + } +#ifdef DEBUG_ZLIB + inflate_hufts += z + 1; +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->next)) = Z_NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + r.next = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(c, bb, tb, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +z_streamp z; /* for zfree function */ +{ + int r; + + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + inflate_trees_free(*tb, z); + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + return r; +} + + +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for zfree function */ +{ + int r; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + inflate_trees_free(*tl, z); + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + inflate_trees_free(*td, z); + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + inflate_trees_free(*tl, z); + return r; +#endif + } + + /* done */ + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +local int fixed_built = 0; +#define FIXEDH 530 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; + + +local voidpf falloc(q, n, s) +voidpf q; /* opaque pointer */ +uInt n; /* number of items */ +uInt s; /* size of item */ +{ + Assert(s == sizeof(inflate_huft) && n <= *(intf *)q, + "inflate_trees falloc overflow"); + *(intf *)q -= n+s-s; /* s-s to avoid warning */ + return (voidpf)(fixed_mem + *(intf *)q); +} + + +int inflate_trees_fixed(bl, bd, tl, td) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +{ + /* build fixed tables if not already (multiple overlapped executions ok) */ + if (!fixed_built) + { + int k; /* temporary variable */ + unsigned c[288]; /* length list for huft_build */ + z_stream z; /* for falloc function */ + int f = FIXEDH; /* number of hufts left in fixed_mem */ + + /* set up fake z_stream for memory routines */ + z.zalloc = falloc; + z.zfree = Z_NULL; + z.opaque = (voidpf)&f; + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 7; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + + /* done */ + Assert(f == 0, "invalid build of fixed tables"); + fixed_built = 1; + } + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +int inflate_trees_free(t, z) +inflate_huft *t; /* table to free */ +z_streamp z; /* for zfree function */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register inflate_huft *p, *q, *r; + + /* Reverse linked list */ + p = Z_NULL; + q = t; + while (q != Z_NULL) + { + r = (q - 1)->next; + (q - 1)->next = p; + p = q; + q = r; + } + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p != Z_NULL) + { + q = (--p)->next; + ZFREE(z,p); + p = q; + } + return Z_OK; +} +/* --- inftrees.c */ + +/* +++ infcodes.c */ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ +/* #include "infblock.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ + +/* +++ inffast.h */ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); +/* --- inffast.h */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ + mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +z_streamp z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_streamp z; +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} +/* --- infcodes.c */ + +/* +++ infutil.c */ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "infblock.h" */ +/* #include "inftrees.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + if (p != Z_NULL) { + zmemcpy(p, q, n); + p += n; + } + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + if (p != Z_NULL) { + zmemcpy(p, q, n); + p += n; + } + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} +/* --- infutil.c */ + +/* +++ inffast.c */ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ +/* #include "infblock.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ +/* #include "inffast.h" */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} +/* --- inffast.c */ + +/* +++ zutil.c */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ + +/* #include "zutil.h" */ + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char *zlibVersion() +{ + return ZLIB_VERSION; +} + +#ifdef DEBUG_ZLIB +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + Bytef* s1; + Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER < 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ +/* --- zutil.c */ + +/* +++ adler32.c */ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */ + +/* #include "zlib.h" */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} +/* --- adler32.c */ diff -Nur linux-2.4.19/drivers/dump/dump_zlib.h linux-2.4.19-sgi211r3/drivers/dump/dump_zlib.h --- linux-2.4.19/drivers/dump/dump_zlib.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/dump/dump_zlib.h Thu Oct 24 04:22:20 2002 @@ -0,0 +1,1010 @@ +/* $Id: dump_zlib.h,v 1.1 2001/09/24 09:39:01 yakker Exp $ */ + +/* + * This file is derived from zlib.h and zconf.h from the zlib-1.0.4 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. + */ + +/* + * ==FILEVERSION 971127== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + + +/* +++ zlib.h */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.0.4, Jul 24th, 1996. + + Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +++ zconf.h */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateReset z_inflateReset +# define compress z_compress +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC) +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + 1 << (windowBits+2) + 1 << (memLevel+9) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR __far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR __far +# endif +#endif +#ifndef FAR +# define FAR +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#if defined(__BORLANDC__) && defined(SMALL_MEDIUM) + /* Borland C/C++ ignores FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL) +# include +# define EXPORT WINAPI +#else +# define EXPORT +#endif + +#endif /* _ZCONF_H */ +/* --- zconf.h */ + +#define ZLIB_VERSION "1.0.4P" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms may be added later and will have the same + stream interface. + + For compression the application must provide the output buffer and + may optionally provide the input buffer for optimization. For decompression, + the application must provide the input buffer and may optionally provide + the output buffer for optimization. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library does not install any signal handler. It is recommended to + add at least a handler for SIGSEGV when decompressing; the library checks + the consistency of the input data whenever possible but may go nuts + for some forms of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_PACKET_FLUSH 2 +#define Z_SYNC_FLUSH 3 +#define Z_FULL_FLUSH 4 +#define Z_FINISH 5 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +extern const char * EXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +extern int EXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +extern int EXPORT deflate OF((z_streamp strm, int flush)); +/* + Performs one or both of the following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression + block is terminated and flushed to the output buffer so that the + decompressor can get all input data available so far. For method 9, a future + variant on method 8, the current block will be flushed but not terminated. + Z_SYNC_FLUSH has the same effect as partial flush except that the compressed + output is byte aligned (the compressor can clear its internal bit buffer) + and the current block is always terminated; this can be useful if the + compressor has to be restarted from scratch after an interruption (in which + case the internal state of the compressor may be lost). + If flush is set to Z_FULL_FLUSH, the compression block is terminated, a + special marker is output and the compression dictionary is discarded; this + is useful to allow the decompressor to synchronize if one compressed block + has been damaged (see inflateSync below). Flushing degrades compression and + so should be used only when necessary. Using Z_FULL_FLUSH too often can + seriously degrade the compression. If deflate returns with avail_out == 0, + this function must be called again with the same value of the flush + parameter and more output space (updated avail_out), until the flush is + complete (deflate returns with non-zero avail_out). + + If the parameter flush is set to Z_PACKET_FLUSH, the compression + block is terminated, and a zero-length stored block is output, + omitting the length bytes (the effect of this is that the 3-bit type + code 000 for a stored block is output, and the output is then + byte-aligned). This is designed for use at the end of a PPP packet. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. +*/ + + +extern int EXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +extern int EXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, inflateInit updates them to use default + allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_VERSION_ERROR if the zlib library version is incompatible + with the version assumed by the caller. msg is set to null if there is no + error message. inflateInit does not perform any decompression: this will be + done by inflate(). +*/ + + +extern int EXPORT inflate OF((z_streamp strm, int flush)); +/* + Performs one or both of the following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, + inflate flushes as much output as possible to the output buffer. The + flushing behavior of inflate is not specified for values of the flush + parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the + current implementation actually flushes as much output as possible + anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data + has been consumed, it is expecting to see the length field of a stored + block; if not, it returns Z_DATA_ERROR. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + inflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if the end of the + compressed data has been reached and all uncompressed output has been + produced, Z_NEED_DICT if a preset dictionary is needed at this point (see + inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted, + Z_STREAM_ERROR if the stream structure was inconsistent (for example if + next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in + the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the + application may then call inflateSync to look for a good compression block. + In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the + dictionary chosen by the compressor. +*/ + + +extern int EXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +extern int EXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. (Method 9 will allow a 64K history buffer and + partial block flushes.) + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library (the value 16 will be allowed for method 9). Larger + values of this parameter result in better compression at the expense of + memory usage. The default value is 15 if deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + If next_in is not null, the library will use this buffer to hold also + some history information; the buffer must either hold the entire input + data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in + is null, the library will allocate its own history buffer (and leave next_in + null). next_out need not be provided here but must be provided by the + application for the next call of deflate(). + + If the history buffer is provided by the application, next_in must + must never be changed by the application since the compressor maintains + information inside this buffer from call to call; the application + must provide more input only by increasing avail_in. next_in is always + reset by the library in this case. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was + not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as + an invalid method). msg is set to null if there is no error message. + deflateInit2 does not perform any compression: this will be done by + deflate(). +*/ + +extern int EXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary (history buffer) from the given + byte sequence without producing any compressed output. This function must + be called immediately after deflateInit or deflateInit2, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and + can be predicted with good accuracy; the data can then be compressed better + than with the default empty dictionary. In this version of the library, + only the last 32K bytes of the dictionary are used. + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state + is inconsistent (for example if deflate has already been called for this + stream). deflateSetDictionary does not perform any compression: this will + be done by deflate(). +*/ + +extern int EXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. If + the source stream is using an application-supplied history buffer, a new + buffer is allocated for the destination stream. The compressed output + buffer is always application-supplied. It's the responsibility of the + application to provide the correct values of next_out and avail_out for the + next call of deflate. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +extern int EXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy)); +/* + Dynamically update the compression level and compression strategy. + This can be used to switch between compression and straight copy of + the input data, or to switch to a different kind of input data requiring + a different strategy. If the compression level is changed, the input + available so far is compressed with the old level (and may be flushed); + the new level will take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +extern int EXPORT deflateOutputPending OF((z_streamp strm)); +/* + Returns the number of bytes of output which are immediately + available from the compressor (i.e. without any further input + or flush). +*/ + +/* +extern int EXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with more compression options. The + fields next_out, zalloc, zfree and opaque must be initialized before by + the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library (the value 16 will be allowed soon). The + default value is 15 if inflateInit is used instead. If a compressed stream + with a larger window size is given as input, inflate() will return with + the error code Z_DATA_ERROR instead of trying to allocate a larger window. + + If next_out is not null, the library will use this buffer for the history + buffer; the buffer must either be large enough to hold the entire output + data, or have at least 1<policy |= SCHED_YIELD; - schedule(); + yield(); } } return ptr; @@ -139,8 +138,7 @@ ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO); if (!ptr) { __set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } return ptr; diff -Nur linux-2.4.19/drivers/ide/ide-geometry.c linux-2.4.19-sgi211r3/drivers/ide/ide-geometry.c --- linux-2.4.19/drivers/ide/ide-geometry.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/ide/ide-geometry.c Wed Oct 16 14:02:58 2002 @@ -3,8 +3,11 @@ */ #include #include -#include #include + +#ifdef __i386__ +# include +#endif #ifdef CONFIG_BLK_DEV_IDE diff -Nur linux-2.4.19/drivers/ide/ide-probe.c linux-2.4.19-sgi211r3/drivers/ide/ide-probe.c --- linux-2.4.19/drivers/ide/ide-probe.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/ide/ide-probe.c Wed Oct 16 14:02:58 2002 @@ -52,6 +52,12 @@ #include #include +#ifdef BUS_INT_WAR +void sn_add_polled_interrupt(int irq, int interval); +void sn2_delete_polled_interrupt(int irq); +extern int bus_int_war_ide_irq; +#endif + static inline void do_identify (ide_drive_t *drive, byte cmd) { int bswap = 1; @@ -711,6 +717,11 @@ return 1; } } + +#ifdef BUS_INT_WAR + sn_add_polled_interrupt(hwif->irq, 1); + bus_int_war_ide_irq = hwif->irq; +#endif /* * Everything is okay, so link us into the hwgroup diff -Nur linux-2.4.19/drivers/ide/ide.c linux-2.4.19-sgi211r3/drivers/ide/ide.c --- linux-2.4.19/drivers/ide/ide.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/ide/ide.c Tue Dec 3 18:34:00 2002 @@ -157,6 +157,10 @@ #include #include +#ifdef CONFIG_IA64_SGI_SN_SIM +#include +#endif + #include "ide_modes.h" #ifdef CONFIG_KMOD @@ -2454,7 +2458,9 @@ return -1; memcpy(&hwif->hw, hw, sizeof(*hw)); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); +#ifndef CONFIG_IA64_SGI_SN_SIM hwif->irq = hw->irq; +#endif hwif->noprobe = 0; hwif->chipset = hw->chipset; @@ -2740,6 +2746,9 @@ void ide_delay_50ms (void) { #ifndef CONFIG_BLK_DEV_IDECS +#ifdef CONFIG_IA64_SGI_SN_SIM + SIMULATOR_SLEEP(); +#endif mdelay(50); #else __set_current_state(TASK_UNINTERRUPTIBLE); @@ -3044,6 +3053,8 @@ } case BLKROSET: case BLKROGET: + case BLKGETLASTSECT: + case BLKSETLASTSECT: case BLKFLSBUF: case BLKSSZGET: case BLKPG: diff -Nur linux-2.4.19/drivers/ieee1394/ieee1394-2.4.patch linux-2.4.19-sgi211r3/drivers/ieee1394/ieee1394-2.4.patch --- linux-2.4.19/drivers/ieee1394/ieee1394-2.4.patch Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/ieee1394/ieee1394-2.4.patch Fri Feb 1 11:39:38 2002 @@ -0,0 +1,316 @@ + +diff -ruN linux-2.4.orig/drivers/ieee1394/guid.c linux-2.4/drivers/ieee1394/guid.c +--- linux-2.4.orig/drivers/ieee1394/guid.c Mon Jan 1 23:17:36 2001 ++++ linux-2.4/drivers/ieee1394/guid.c Thu Jan 11 02:03:04 2001 +@@ -163,7 +163,7 @@ + return; + } + +- INIT_LIST_HEAD(&greq->tq.list); ++ INIT_TQ_LINK(greq->tq); + greq->tq.sync = 0; + greq->tq.routine = (void (*)(void*))pkt_complete; + greq->tq.data = greq; +diff -ruN linux-2.4.orig/drivers/ieee1394/hosts.c linux-2.4/drivers/ieee1394/hosts.c +--- linux-2.4.orig/drivers/ieee1394/hosts.c Mon Jan 1 23:15:56 2001 ++++ linux-2.4/drivers/ieee1394/hosts.c Thu Jan 11 01:55:50 2001 +@@ -106,6 +106,7 @@ + sema_init(&h->tlabel_count, 64); + spin_lock_init(&h->tlabel_lock); + ++ INIT_TQ_LINK(h->timeout_tq); + h->timeout_tq.routine = (void (*)(void*))abort_timedouts; + h->timeout_tq.data = h; + +diff -ruN linux-2.4.orig/drivers/ieee1394/ieee1394_core.c linux-2.4/drivers/ieee1394/ieee1394_core.c +--- linux-2.4.orig/drivers/ieee1394/ieee1394_core.c Mon Jan 1 23:15:56 2001 ++++ linux-2.4/drivers/ieee1394/ieee1394_core.c Thu Jan 11 01:52:21 2001 +@@ -98,6 +98,7 @@ + packet->data_size = data_size; + } + ++ INIT_TQ_HEAD(packet->complete_tq); + INIT_LIST_HEAD(&packet->list); + sema_init(&packet->state_change, 0); + packet->state = unused; +diff -ruN linux-2.4.orig/drivers/ieee1394/ieee1394_types.h linux-2.4/drivers/ieee1394/ieee1394_types.h +--- linux-2.4.orig/drivers/ieee1394/ieee1394_types.h Tue Jan 2 05:53:39 2001 ++++ linux-2.4/drivers/ieee1394/ieee1394_types.h Thu Jan 11 02:25:53 2001 +@@ -15,6 +15,9 @@ + #define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0) + #define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0) + #define OWNER_THIS_MODULE owner: THIS_MODULE, ++ ++#define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list) ++#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq)) + #endif + + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) +diff -ruN linux-2.4.orig/drivers/ieee1394/ohci1394.c linux-2.4/drivers/ieee1394/ohci1394.c +--- linux-2.4.orig/drivers/ieee1394/ohci1394.c Thu Jan 11 01:34:32 2001 ++++ linux-2.4/drivers/ieee1394/ohci1394.c Thu Jan 11 02:04:48 2001 +@@ -1641,7 +1641,7 @@ + + /* initialize bottom handler */ + d->task.sync = 0; +- INIT_LIST_HEAD(&d->task.list); ++ INIT_TQ_LINK(d->task); + d->task.routine = dma_rcv_bh; + d->task.data = (void*)d; + +@@ -1730,6 +1730,7 @@ + spin_lock_init(&d->lock); + + /* initialize bottom handler */ ++ INIT_TQ_LINK(d->task); + d->task.routine = dma_trm_bh; + d->task.data = (void*)d; + +diff -ruN linux-2.4.orig/drivers/ieee1394/pcilynx.c linux-2.4/drivers/ieee1394/pcilynx.c +--- linux-2.4.orig/drivers/ieee1394/pcilynx.c Mon Jan 1 23:17:36 2001 ++++ linux-2.4/drivers/ieee1394/pcilynx.c Thu Jan 11 02:00:27 2001 +@@ -289,7 +289,8 @@ + char phyreg[7]; + int i; + +- for (i = 0; i < 7; i++) { ++ phyreg[0] = lynx->phy_reg0; ++ for (i = 1; i < 7; i++) { + phyreg[i] = get_phy_reg(lynx, i); + } + +@@ -317,13 +318,18 @@ + return lsid; + } + +-static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t size) ++static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host) + { + quadlet_t *q = lynx->rcv_page; +- int phyid, isroot; ++ int phyid, isroot, size; + quadlet_t lsid = 0; + int i; + ++ if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return; ++ ++ size = lynx->selfid_size; ++ phyid = lynx->phy_reg0; ++ + i = (size > 16 ? 16 : size) / 4 - 1; + while (i >= 0) { + cpu_to_be32s(&q[i]); +@@ -334,7 +340,6 @@ + lsid = generate_own_selfid(lynx, host); + } + +- phyid = get_phy_reg(lynx, 0); + isroot = (phyid & 2) != 0; + phyid >>= 2; + PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)", +@@ -369,9 +374,14 @@ + hpsb_selfid_received(host, lsid); + } + +- if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); +- + hpsb_selfid_complete(host, phyid, isroot); ++ ++ if (host->in_bus_reset) return; ++ ++ if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); ++ reg_set_bits(lynx, LINK_CONTROL, ++ LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN ++ | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN); + } + + +@@ -456,6 +466,9 @@ + int i; + u32 *pcli; + ++ lynx->selfid_size = -1; ++ lynx->phy_reg0 = -1; ++ + lynx->async.queue = NULL; + spin_lock_init(&lynx->async.queue_lock); + spin_lock_init(&lynx->phy_reg_lock); +@@ -531,8 +544,8 @@ + reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4); + reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV), +- DMA_WORD1_CMP_MATCH_NODE_BCAST | DMA_WORD1_CMP_MATCH_BROADCAST +- | DMA_WORD1_CMP_MATCH_LOCAL | DMA_WORD1_CMP_MATCH_BUS_BCAST ++ DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST ++ | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST + | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER); + + run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); +@@ -547,12 +560,21 @@ + reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID + | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN + | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN +- | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX +- | LINK_CONTROL_CYCTIMEREN); +- +- /* attempt to enable contender bit -FIXME- would this work elsewhere? */ +- reg_set_bits(lynx, GPIO_CTRL_A, 0x1); +- reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); ++ | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX); ++ ++ if (!lynx->phyic.reg_1394a) { ++ /* attempt to enable contender bit -FIXME- would this work ++ * elsewhere? */ ++ reg_set_bits(lynx, GPIO_CTRL_A, 0x1); ++ reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); ++ } else { ++ /* set the contender bit in the extended PHY register ++ * set. (Should check that bis 0,1,2 (=0xE0) is set ++ * in register 2?) ++ */ ++ i = get_phy_reg(lynx, 4); ++ if (i != -1) set_phy_reg(lynx, 4, i | 0x40); ++ } + + return 1; + } +@@ -628,6 +650,11 @@ + + switch (cmd) { + case RESET_BUS: ++ if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) { ++ retval = 0; ++ break; ++ } ++ + if (arg) { + arg = 3 << 6; + } else { +@@ -642,6 +669,8 @@ + (host->attempt_root ? " and attempting to become root" + : "")); + ++ lynx->selfid_size = -1; ++ lynx->phy_reg0 = -1; + set_phy_reg(lynx, 1, arg); + break; + +@@ -1102,14 +1131,28 @@ + } + if (linkint & LINK_INT_PHY_BUSRESET) { + PRINT(KERN_INFO, lynx->id, "bus reset interrupt"); +- if (!host->in_bus_reset) { ++ lynx->selfid_size = -1; ++ lynx->phy_reg0 = -1; ++ if (!host->in_bus_reset) + hpsb_bus_reset(host); +- } + } + if (linkint & LINK_INT_PHY_REG_RCVD) { ++ u32 reg; ++ ++ spin_lock(&lynx->phy_reg_lock); ++ reg = reg_read(lynx, LINK_PHY); ++ spin_unlock(&lynx->phy_reg_lock); ++ + if (!host->in_bus_reset) { + PRINT(KERN_INFO, lynx->id, + "phy reg received without reset"); ++ } else if (reg & 0xf00) { ++ PRINT(KERN_INFO, lynx->id, ++ "unsolicited phy reg %d received", ++ (reg >> 8) & 0xf); ++ } else { ++ lynx->phy_reg0 = reg & 0xff; ++ handle_selfid(lynx, host); + } + } + if (linkint & LINK_INT_ISO_STUCK) { +@@ -1125,6 +1168,10 @@ + PRINT(KERN_INFO, lynx->id, "invalid transaction code"); + } + if (linkint & LINK_INT_GRF_OVERFLOW) { ++ /* flush FIFO if overflow happens during reset */ ++ if (host->in_bus_reset) ++ reg_write(lynx, FIFO_CONTROL, ++ FIFO_CONTROL_GRF_FLUSH); + PRINT(KERN_INFO, lynx->id, "GRF overflow"); + } + if (linkint & LINK_INT_ITF_UNDERFLOW) { +@@ -1227,11 +1274,8 @@ + stat & 0x1fff); + + if (stat & DMA_CHAN_STAT_SELFID) { +- handle_selfid(lynx, host, stat & 0x1fff); +- reg_set_bits(lynx, LINK_CONTROL, +- LINK_CONTROL_RCV_CMP_VALID +- | LINK_CONTROL_TX_ASYNC_EN +- | LINK_CONTROL_RX_ASYNC_EN); ++ lynx->selfid_size = stat & 0x1fff; ++ handle_selfid(lynx, host); + } else { + quadlet_t *q_data = lynx->rcv_page; + if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE +@@ -1415,13 +1459,15 @@ + + lynx->lock = SPIN_LOCK_UNLOCKED; + +- reg_write(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT | PCI_INT_DMA_ALL); ++ reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); + + #ifdef CONFIG_IEEE1394_PCILYNX_PORTS ++ reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT); + init_waitqueue_head(&lynx->mem_dma_intr_wait); + init_waitqueue_head(&lynx->aux_intr_wait); + #endif + ++ INIT_TQ_LINK(lynx->iso_rcv.tq); + lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh; + lynx->iso_rcv.tq.data = lynx; + lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED; +diff -ruN linux-2.4.orig/drivers/ieee1394/pcilynx.h linux-2.4/drivers/ieee1394/pcilynx.h +--- linux-2.4.orig/drivers/ieee1394/pcilynx.h Tue Jan 2 05:53:53 2001 ++++ linux-2.4/drivers/ieee1394/pcilynx.h Sun Jan 14 03:50:46 2001 +@@ -80,6 +80,8 @@ + struct hpsb_host *host; + + int phyid, isroot; ++ int selfid_size; ++ int phy_reg0; + + spinlock_t phy_reg_lock; + +@@ -248,9 +250,9 @@ + #define FIFO_SIZES 0xa00 + + #define FIFO_CONTROL 0xa10 +-#define GRF_FLUSH (1<<4) +-#define ITF_FLUSH (1<<3) +-#define ATF_FLUSH (1<<2) ++#define FIFO_CONTROL_GRF_FLUSH (1<<4) ++#define FIFO_CONTROL_ITF_FLUSH (1<<3) ++#define FIFO_CONTROL_ATF_FLUSH (1<<2) + + #define FIFO_XMIT_THRESHOLD 0xa14 + +@@ -285,8 +287,8 @@ + #define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15) + #define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14) + #define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13) +-#define DMA_WORD1_CMP_MATCH_NODE_BCAST (1<<12) +-#define DMA_WORD1_CMP_MATCH_LOCAL (1<<11) ++#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12) ++#define DMA_WORD1_CMP_MATCH_EXACT (1<<11) + #define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10) + #define DMA_WORD1_CMP_ENABLE_MASTER (1<<8) + +diff -ruN linux-2.4.orig/drivers/ieee1394/raw1394.c linux-2.4/drivers/ieee1394/raw1394.c +--- linux-2.4.orig/drivers/ieee1394/raw1394.c Mon Jan 1 23:17:36 2001 ++++ linux-2.4/drivers/ieee1394/raw1394.c Thu Jan 11 02:01:49 2001 +@@ -64,6 +64,7 @@ + if (req != NULL) { + memset(req, 0, sizeof(struct pending_request)); + INIT_LIST_HEAD(&req->list); ++ INIT_TQ_LINK(req->tq); + req->tq.routine = (void(*)(void*))queue_complete_cb; + } diff -Nur linux-2.4.19/drivers/ieee1394/pcilynx.c linux-2.4.19-sgi211r3/drivers/ieee1394/pcilynx.c --- linux-2.4.19/drivers/ieee1394/pcilynx.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/ieee1394/pcilynx.c Mon Oct 28 20:43:23 2002 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -796,8 +797,9 @@ loff_t mem_llseek(struct file *file, loff_t offs, int orig) { - loff_t newoffs; + loff_t newoffs = -1; + lock_kernel(); switch (orig) { case 0: newoffs = offs; @@ -807,12 +809,12 @@ break; case 2: newoffs = PCILYNX_MAX_MEMORY + 1 + offs; - break; - default: - return -EINVAL; } - if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL; + if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) { + lock_kernel(); + return -EINVAL; + } file->f_pos = newoffs; return newoffs; diff -Nur linux-2.4.19/drivers/ieee1394/sbp2_1394.c linux-2.4.19-sgi211r3/drivers/ieee1394/sbp2_1394.c --- linux-2.4.19/drivers/ieee1394/sbp2_1394.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/ieee1394/sbp2_1394.c Fri Feb 1 11:39:38 2002 @@ -0,0 +1,2725 @@ +/* + * sbp2_1394.c - SBP-2 protocol driver for IEEE-1394 + * + * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com) + * jamesg@filanet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Brief Description: + * + * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394 + * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level + * driver. It also registers as a SCSI lower-level driver in order to accept + * SCSI commands for transport using SBP-2. + * + * Driver Loading: + * + * Currently, the SBP-2 driver is supported only as a module. Because the + * Linux SCSI stack is not Plug-N-Play aware, module load order is + * important. Assuming the SCSI core drivers are either built into the + * kernel or already loaded as modules, you should load the IEEE-1394 modules + * in the following order: + * + * ieee1394 (e.g. insmod ieee1394) + * ohci1394 (e.g. insmod ohci1394) + * sbp2_1394 (e.g. insmod sbp2_1394) + * + * The SBP-2 driver will attempt to discover any attached SBP-2 devices when first + * loaded, or after any IEEE-1394 bus reset (e.g. a hot-plug). It will then print + * out a debug message indicating if it was able to discover a SBP-2 device. + * + * Currently, the SBP-2 driver registers with the SCSI stack "before" + * detecting SBP-2 devices on the IEEE-1394 bus. This means that we miss the + * initial SCSI bus scan. In order to actually let the scsi stack "detect" a + * SBP-2 device, you must either use the procfs add-single-device, + * remove-single-device, or a shell script such as rescan-scsi-bus.sh. + * + * The easiest way to add/detect new SBP-2 devices is to run the shell script + * rescan-scsi-bus.sh. + * + * As an alternative, you may manually add/remove SBP-2 devices via the procfs with + * add-single-device or remove-single-device , where: + * = host (starting at zero for first SCSI adapter) + * = bus (normally zero) + * = target (starting at zero for first SBP-2 device) + * - lun (normally zero) + * + * e.g. To manually add/detect a new SBP-2 device + * echo "scsi add-single-device 0 0 0 0" > /proc/scsi/scsi + * + * e.g. To manually remove a SBP-2 device after it's been unplugged + * echo "scsi remove-single-device 0 0 0 0" > /proc/scsi/scsi + * + * e.g. To check to see which SBP-2/SCSI devices are currently registered + * cat /proc/scsi/scsi + * + * After scanning for new SCSI devices (above), you may access any attached + * SBP-2 storage devices as if they were SCSI devices (e.g. mount /dev/sda1, + * fdisk, mkfs, etc.). + * + * Current Support: + * + * The SBP-2 driver is still in an early state, but supports a variety of devices. + * I have read/written many gigabytes of data from/to SBP-2 drives, and have seen + * performance of more than 16 MBytes/s on individual drives (limit of the media + * transfer rate). + * + * Following are the devices that have been tested successfully: + * + * - Western Digital (WD) IEEE-1394 hard drives + * - Maxtor IEEE-1394 hard drives + * - VST IEEE-1394 hard drives and Zip drives (several flavors) + * - LaCie IEEE-1394 hard drives (several flavors) + * - QPS IEEE-1394 CD-RW/DVD drives + * - Fujitsu IEEE-1394 MO drives + * - Sony IEEE-1394 CD-RW drives + * - Epson IEEE-1394 scanner + * - SBP-2 bridge-based devices (LSI and Oxford Semiconductor bridges) + * - Various other standard IEEE-1394 hard drives + * + * Current Issues: + * + * - Hot-Plugging: Additional testing/debugging is needed to fully support + * SBP-2 drive hot-plugging while the sbp2 module is loaded. Because the + * rest of the SCSI stack does not handle I/O errors well, hot-plugging + * of mounted devices is risky. + * + * - Error Handling: SCSI aborts and bus reset requests are handled somewhat + * but the code needs additional debugging. + * + * - Testing: Need to do additional hot-plug testing, stress testing, and + * device compatibility testing. + * + * - IEEE-1394 Bus Management: There is currently little bus management + * in the core IEEE-1394 stack. Because of this, the SBP-2 driver handles + * detection of SBP-2 devices itself. This should be moved to the core + * stack. + * + * - I/O is currently serialized because of some stress issues with ohci1394. + * Debugging in progress. + * + * - The SBP-2 driver is currently only supported as a module. It would not take + * much work to allow it to be compiled into the kernel, but you'd have to + * add some init code to the kernel to support this... and modules are much + * more flexible anyway. ;-) + * + * Core IEEE-1394 Stack Changes: + * + * - The IEEE-1394 core stack guid code attempts to read the node unique id from + * each attached device after a bus reset. It currently uses a block read + * request to do this, which "upsets" certain not-well-behaved devices, such as + * some CD-RW drives from QPS. If you have trouble with your IEEE-1394 storage + * device being detected after loading sbp2_1394, try commenting out the + * init_ieee1394_guid() lines at the bottom of ieee1394_core.c (and rebuild ieee1394.o). + * When an IEEE-1394 storage device is detected, you will see a message printed + * out by sbp2_1394. + * + * - SBP-2 driver should now support the TILynx adapter, although I do not have one to + * test with. Am not sure what the max real payload supported by this adapter is, + * but have heard it's somewhere around 512KB. You might need to either update + * the max_rec field in pcilynx.h (misc. settings of bus info block in config rom) + * from 0xf064a000 to something like 0xf0648000 (1KB payload) or 0xf0647000 (512 byte + * payload). Alternatively, you can tune max speed and payload with #defines below. + * + * History: + * + * 07/25/00 - Initial revision (JSG) + * 08/11/00 - Following changes/bug fixes were made (JSG): + * * Bug fix to SCSI procfs code (still needs to be synched with 2.4 kernel). + * * Bug fix where request sense commands were actually sent on the bus. + * * Changed bus reset/abort code to deal with devices that spin up quite + * slowly (which result in SCSI time-outs). + * * "More" properly pull information from device's config rom, for enumeration + * of SBP-2 devices, and determining SBP-2 register offsets. + * * Change Simplified Direct Access Device type to Direct Access Device type in + * returned inquiry data, in order to make the SCSI stack happy. + * * Modified driver to register with the SCSI stack "before" enumerating any attached + * SBP-2 devices. This means that you'll have to use procfs scsi-add-device or + * some sort of script to discover new SBP-2 devices. + * * Minor re-write of some code and other minor changes. + * 08/28/00 - Following changes/bug fixes were made (JSG): + * * Bug fixes to scatter/gather support (case of one s/g element) + * * Updated direction table for scsi commands (mostly DVD commands) + * * Retries when trying to detect SBP-2 devices (for slow devices) + * * Slightly better error handling (previously none) when commands time-out. + * * Misc. other bug fixes and code reorganization. + * 09/13/00 - Following changes/bug fixes were made (JSG) + * * Moved detection/enumeration code to a kernel thread which is woken up when IEEE-1394 + * bus resets occur. + * * Added code to handle bus resets and hot-plugging while devices are mounted, but full + * hot-plug support is not quite there yet. + * * Now use speed map to determine speed and max payload sizes for ORBs + * * Clean-up of code and reorganization + * 09/19/00 - Added better hot-plug support and other minor changes (JSG) + * 10/15/00 - Fixes for latest 2.4.0 test kernel, minor fix for hot-plug race. (JSG) + * 12/03/00 - Created pool of request packet structures for use in sending out sbp2 command + * and agent reset requests. This removes the kmallocs/kfrees in the critical I/O paths, + * and also deals with some subtle race conditions related to allocating and freeing + * packets. (JSG) + * 12/09/00 - Improved the sbp2 device detection by actually reading the root and unit + * directory (khk@khk.net) + * 12/23/00 - Following changes/enhancements were made (JSG) + * * Only do SCSI to RBC command conversion for Direct Access and Simplified + * Direct Access Devices (this is pulled from the config rom root directory). + * This is needed because doing the conversion for all device types broke the + * Epson scanner. Still looking for a better way of determining when to convert + * commands (for RBC devices). Thanks to khk for helping on this! + * * Added ability to "emulate" physical dma support, for host adapters such as TILynx. + * * Determine max payload and speed by also looking at the host adapter's max_rec field. + * 01/19/00 - Added checks to sbp2 login and made the login time-out longer. Also fixed a compile + * problem for 2.4.0. + */ + + +/* + * Change these defines if you have a bad IEEE-1394 controller that has trouble running + * 2KB packets at 400mb. May also want to bump these down if testing with pcilynx. + * + * NOTE: On certain OHCI parts I have seen short packets on async transmit (probably + * due to PCI latency/throughput issues with the part). You can bump down the speed or max + * payload if you are running into this problem (e.g. SPEED_S200, MAX_PAYLOAD_S200). + */ + #define SBP2_MAX_SPEED_ALLOWED SPEED_S400 /* 400mb */ + #define SBP2_MAX_PAYLOAD_ALLOWED MAX_PAYLOAD_S400 /* 2KB */ + +/* + * Define this so that the sbp2 driver will do internal command retries on unit attention + * check condition. A unit attention could happen if a bus reset occurs on 1394, and + * sometimes the upper scsi drivers do not properly deal with it (e.g. while file copies are + * happening). We work around this by clearing the unit attention and retrying the command + * that failed. + */ +#define SBP2_DO_RETRY_ON_UNIT_ATTENTION + +/* + * Define this if you'd like the sbp2 driver to work with 1394 adapters which do not support + * physical dma in hardware (such as the TILynx)... + */ +#define SBP2_EMULATE_PHYSICAL_DMA_SUPPORT + + +/* + * Includes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "ieee1394_core.h" +#include "hosts.h" +#include "highlevel.h" +#include "ieee1394_transactions.h" +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" +#include "sbp2_1394.h" + +/* + * Debug spewing control. Define SBP2_DEBUG_SPEWING or SBP2_DEBUG_SPEWING_MUCHO + * if you'd like to see lots of messages... + */ + +/* #define SBP2_DEBUG_SPEWING */ +/* #define SBP2_DEBUG_SPEWING_MUCHO */ + +#ifdef SBP2_DEBUG_SPEWING_MUCHO +#define SBP2_DEBUG(fmt, args...) HPSB_ERR(fmt, ## args) +#define SBP2_INFO(fmt, args...) HPSB_ERR(fmt, ## args) +#define SBP2_NOTICE(fmt, args...) HPSB_ERR(fmt, ## args) +#define SBP2_WARN(fmt, args...) HPSB_ERR(fmt, ## args) +#else +#ifdef SBP2_DEBUG_SPEWING +#define SBP2_DEBUG(fmt, args...) HPSB_DEBUG(fmt, ## args) +#define SBP2_INFO(fmt, args...) HPSB_INFO(fmt, ## args) +#define SBP2_NOTICE(fmt, args...) HPSB_NOTICE(fmt, ## args) +#define SBP2_WARN(fmt, args...) HPSB_WARN(fmt, ## args) +#else +#define SBP2_DEBUG(fmt, args...) +#define SBP2_INFO(fmt, args...) +#define SBP2_NOTICE(fmt, args...) +#define SBP2_WARN(fmt, args...) +#endif +#endif +#define SBP2_ERR(fmt, args...) HPSB_ERR(fmt, ## args) + +/* + * Globals + */ + +Scsi_Host_Template *global_scsi_tpnt = NULL; + +LIST_HEAD(sbp2_host_info_list); +static int sbp2_host_count = 0; +spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED; + +static struct hpsb_highlevel *sbp2_hl_handle = NULL; + +static struct hpsb_highlevel_ops sbp2_hl_ops = { + sbp2_add_host, + sbp2_remove_host, + sbp2_host_reset, + NULL, + NULL +}; + +static struct hpsb_address_ops sbp2_ops = { + write: sbp2_handle_status_write, +}; + +#ifdef SBP2_EMULATE_PHYSICAL_DMA_SUPPORT +static struct hpsb_address_ops sbp2_physdma_ops = { + read: sbp2_handle_physdma_read, + write: sbp2_handle_physdma_write, +}; +#endif + +/************************************** + * General utility functions + **************************************/ + +/* + * Converts a buffer from be32 to cpu byte ordering. Length is in bytes. + */ +static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length) +{ + u32 *temp = buffer; + int i; + + for (i=0; i<(length >> 2); i++) { + temp[i] = be32_to_cpu(temp[i]); + } + return; +} + +/* + * Converts a buffer from cpu to be32 byte ordering. Length is in bytes. + */ +static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length) +{ + u32 *temp = buffer; + int i; + + for (i=0; i<(length >> 2); i++) { + temp[i] = cpu_to_be32(temp[i]); + } + return; +} + +/* + * This function does quadlet sized reads (used by detection code) + */ +static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr, + quadlet_t *buffer) +{ + int retval = 0; + int retry_count = 3; + + /* + * Retry a couple times if needed (for slow devices) + */ + do { + + retval = hpsb_read(hi->host, node, addr, buffer, 4); + + if (retval) { + SBP2_DEBUG("sbp2: sbp2util_read_quadlet data packet error"); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/50); /* 20ms delay */ + } + + retry_count--; + + } while (retval && retry_count); + + return(retval); +} + +/* + * This function returns the address of the unit directory. + */ +static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node_id, u64 *unit_directory_addr) +{ + quadlet_t root_directory_length, current_quadlet; + u64 current_addr; + int length, i; + + /* + * First, read the first quadlet of the root directory to determine its size + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_ROOT_DIR_BASE, + &root_directory_length)) { + SBP2_DEBUG("sbp2: Error reading root directory length - bad status"); + return(-EIO); + } + + current_addr = CONFIG_ROM_ROOT_DIR_BASE; + length = be32_to_cpu(root_directory_length) >> 16; + + /* + * Step through the root directory and look for the "Unit_Directory entry", which + * contains the offset to the unit directory. + */ + for (i=0; i < length; i++) { + + current_addr += 4; + + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, ¤t_quadlet)) { + SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", + (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff)); + return(-EIO); + } + + /* + * Check for unit directory offset tag + */ + if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_DIRECTORY_OFFSET_KEY) { + *unit_directory_addr = current_addr + 4 * ((be32_to_cpu(current_quadlet) & 0xffffff)); + SBP2_DEBUG("sbp2: unit_directory_addr = %x", (unsigned int) unit_directory_addr); + } + } + + return(0); +} + +/* + * This function is called to initially create a packet pool for use in sbp2 I/O requests. + * This packet pool is used when sending out sbp2 command and agent reset requests, and + * allows us to remove all kmallocs/kfrees from the critical I/O paths. + */ +static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi) +{ + struct hpsb_packet *packet; + int i; + unsigned long flags; + + /* + * Create SBP2_MAX_REQUEST_PACKETS number of request packets. + */ + spin_lock_irqsave(&hi->sbp2_request_packet_lock, flags); + for (i=0; isbp2_request_packet_lock, flags); + return(-ENOMEM); + } + + /* + * Put these request packets into a free list + */ + INIT_LIST_HEAD(&hi->request_packet[i].list); + hi->request_packet[i].packet = packet; + list_add_tail(&hi->request_packet[i].list, &hi->sbp2_req_free); + + } + spin_unlock_irqrestore(&hi->sbp2_request_packet_lock, flags); + + return(0); +} + +/* + * This function is called to remove the packet pool. It is called when the sbp2 driver is unloaded. + */ +static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi) +{ + struct list_head *lh; + struct sbp2_request_packet *request_packet; + unsigned long flags; + + /* + * Go through free list releasing packets + */ + spin_lock_irqsave(&hi->sbp2_request_packet_lock, flags); + while (!list_empty(&hi->sbp2_req_free)) { + + lh = hi->sbp2_req_free.next; + list_del(lh); + + request_packet = list_entry(lh, struct sbp2_request_packet, list); + + /* + * Free the hpsb packets that we allocated for the pool + */ + if (request_packet) { + free_hpsb_packet(request_packet->packet); + } + + } + spin_unlock_irqrestore(&hi->sbp2_request_packet_lock, flags); + + return; +} + +/* + * This function is called to retrieve a block write packet from our packet pool. This function is + * used in place of calling alloc_hpsb_packet (which costs us three kmallocs). Instead we + * just pull out a free request packet and re-initialize values in it. I'm sure this can still + * stand some more optimization. + */ +static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, + nodeid_t node, u64 addr, + size_t data_size, + quadlet_t data) { + struct list_head *lh; + struct sbp2_request_packet *request_packet = NULL; + struct hpsb_packet *packet; + unsigned long flags; + + spin_lock_irqsave(&hi->sbp2_request_packet_lock, flags); + if (!list_empty(&hi->sbp2_req_free)) { + + /* + * Pull out a free request packet + */ + lh = hi->sbp2_req_free.next; + list_del(lh); + + request_packet = list_entry(lh, struct sbp2_request_packet, list); + packet = request_packet->packet; + + /* + * Initialize the packet (this is really initialization the core 1394 stack should do, + * but I'm doing it myself to avoid the overhead). + */ + packet->data_size = data_size; + INIT_LIST_HEAD(&packet->list); + sema_init(&packet->state_change, 0); + packet->state = unused; + packet->generation = get_hpsb_generation(); + packet->data_be = 1; + + packet->host = hi->host; + packet->tlabel = get_tlabel(hi->host, node, 1); + packet->node_id = node; + + if (!data_size) { + fill_async_writequad(packet, addr, data); + } else { + fill_async_writeblock(packet, addr, data_size); + } + + /* + * Set up a task queue completion routine, which returns the packet to the free list + * and releases the tlabel + */ + request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; + request_packet->tq.data = request_packet; + request_packet->hi_context = hi; + queue_task(&request_packet->tq, &packet->complete_tq); + + /* + * Now, put the packet on the in-use list + */ + list_add_tail(&request_packet->list, &hi->sbp2_req_inuse); + + } else { + SBP2_ERR("sbp2: sbp2util_allocate_request_packet - no packets available!"); + } + spin_unlock_irqrestore(&hi->sbp2_request_packet_lock, flags); + + return(request_packet); +} + +/* + * This function is called to return a packet to our packet pool. It is also called as a + * completion routine when a request packet is completed. + */ +static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet) +{ + unsigned long flags; + struct sbp2scsi_host_info *hi = request_packet->hi_context; + + /* + * Free the tlabel, and return the packet to the free pool + */ + spin_lock_irqsave(&hi->sbp2_request_packet_lock, flags); + free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id, request_packet->packet->tlabel); + list_del(&request_packet->list); + list_add_tail(&request_packet->list, &hi->sbp2_req_free); + spin_unlock_irqrestore(&hi->sbp2_request_packet_lock, flags); + + return; +} + + +/********************************************* + * IEEE-1394 core driver stack related section + *********************************************/ + +/* + * This function is called at SCSI init in order to register our driver with the + * IEEE-1394 stack + */ +int sbp2_init(void) +{ + SBP2_DEBUG("sbp2: sbp2_init"); + + /* + * Register our high level driver with 1394 stack + */ + sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, &sbp2_hl_ops); + + if (sbp2_hl_handle == NULL) { + SBP2_ERR("sbp2: sbp2 failed to register with ieee1394 highlevel"); + return(-ENOMEM); + } + + /* + * Register our sbp2 status address space... + */ + hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS, + SBP2_STATUS_FIFO_ADDRESS + sizeof(struct sbp2_status_block)); + + /* + * Register physical dma address space... used for adapters not supporting hardware phys dma. + */ +#ifdef SBP2_EMULATE_PHYSICAL_DMA_SUPPORT + hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL); +#endif + + return(0); +} + +/* + * This function is called from cleanup module, or during shut-down, in order to + * unregister our driver + */ +void sbp2_cleanup(void) +{ + SBP2_DEBUG("sbp2: sbp2_cleanup"); + + if (sbp2_hl_handle) { + hpsb_unregister_highlevel(sbp2_hl_handle); + sbp2_hl_handle = NULL; + } + return; +} + +/* + * This function is called after registering our operations in sbp2_init. We go ahead and + * allocate some memory for our host info structure, and init some structures. + */ +static void sbp2_add_host(struct hpsb_host *host) +{ + struct sbp2scsi_host_info *hi; + + SBP2_DEBUG("sbp2: sbp2_add_host"); + + /* + * Allocate some memory for our host info structure + */ + hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info), GFP_KERNEL); + + if (hi != NULL) { + + /* + * Initialize some host stuff + */ + memset(hi, 0, sizeof(struct sbp2scsi_host_info)); + INIT_LIST_HEAD(&hi->list); + INIT_LIST_HEAD(&hi->sbp2_req_inuse); + INIT_LIST_HEAD(&hi->sbp2_req_free); + hi->host = host; + hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED; + hi->sbp2_request_packet_lock = SPIN_LOCK_UNLOCKED; + + /* + * Create our request packet pool (pool of packets for use in I/O) + */ + if (sbp2util_create_request_packet_pool(hi)) { + SBP2_ERR("sbp2: sbp2util_create_request_packet_pool failed!"); + return; + } + + spin_lock_irq(&sbp2_host_info_lock); + list_add_tail(&hi->list, &sbp2_host_info_list); + sbp2_host_count++; + spin_unlock_irq(&sbp2_host_info_lock); + + /* + * Initialize us to bus reset in progress + */ + hi->bus_reset_in_progress = 1; + + /* + * Register our host with the SCSI stack. + */ + sbp2scsi_register_scsi_host(hi); + + /* + * Start our kernel thread to deal with sbp2 device detection + */ + init_waitqueue_head(&hi->sbp2_detection_wait); + hi->sbp2_detection_pid = 0; + hi->sbp2_detection_pid = kernel_thread(sbp2_detection_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + + } + + return; +} + +/* + * This fuction returns a host info structure from the host structure, in case we have multiple hosts + */ +static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host) { + struct list_head *lh; + struct sbp2scsi_host_info *hi; + + lh = sbp2_host_info_list.next; + while (lh != &sbp2_host_info_list) { + hi = list_entry(lh, struct sbp2scsi_host_info, list); + if (hi->host == host) { + return hi; + } + lh = lh->next; + } + + return(NULL); +} + +/* + * This function is called when the host is removed + */ +static void sbp2_remove_host(struct hpsb_host *host) +{ + struct sbp2scsi_host_info *hi; + int i; + + SBP2_DEBUG("sbp2: sbp2_remove_host"); + + spin_lock_irq(&sbp2_host_info_lock); + hi = sbp2_find_host_info(host); + + if (hi != NULL) { + + /* + * Need to remove any attached SBP-2 devices. Also make sure to logout of all devices. + */ + for (i=0; iscsi_id[i]) { + sbp2_logout_device(hi, hi->scsi_id[i]); + hi->scsi_id[i]->validated = 0; + } + } + + sbp2_remove_unvalidated_devices(hi); + + list_del(&hi->list); + sbp2_host_count--; + } + spin_unlock_irq(&sbp2_host_info_lock); + + if (hi == NULL) { + SBP2_ERR("sbp2: attempt to remove unknown host 0x%p", host); + return; + } + + /* + * Remove the packet pool (release the packets) + */ + sbp2util_remove_request_packet_pool(hi); + + /* + * Kill our detection thread + */ + if (hi->sbp2_detection_pid >= 0) { + kill_proc(hi->sbp2_detection_pid, SIGINT, 1); + } + + /* + * Give the detection thread a little time to exit + */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); /* 1 second delay */ + + kfree(hi); + hi = NULL; + + return; +} + +/* + * This is our sbp2 detection thread. It is signalled when bus resets occur + * so that we can find and initialize any sbp2 devices. + */ +static int sbp2_detection_thread(void *__hi) +{ + struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)__hi; + + SBP2_DEBUG("sbp2: sbp2_detection_thread"); + + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources + */ + exit_mm(current); + exit_files(current); + exit_fs(current); + + /* + * Set-up a nice name + */ + strcpy(current->comm, "sbp2_1394"); + + while ((!signal_pending(current)) && hi) { + + /* + * Process our bus reset now + */ + if (hi) { + MOD_INC_USE_COUNT; + sbp2_bus_reset_handler(hi); + MOD_DEC_USE_COUNT; + } + + /* + * Sleep until next bus reset + */ + if (hi) { + interruptible_sleep_on(&hi->sbp2_detection_wait); + } + } + + return(0); +} + +/* + * This function is where we first pull the node unique ids, and then allocate memory and register + * a SBP-2 device + */ +static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id) +{ + quadlet_t node_unique_id_lo, node_unique_id_hi; + u64 node_unique_id; + struct scsi_id_instance_data *scsi_id = NULL; + int i; + + SBP2_DEBUG("sbp2: sbp2_start_device"); + + /* + * Let's read the node unique id off of the device (using two quadlet reads for hi and lo) + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_NODE_UNIQUE_ID_HI_ADDRESS, + &node_unique_id_hi)) { + SBP2_DEBUG("sbp2: Error reading node unique id - bad status"); + return(-EIO); + } + + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_NODE_UNIQUE_ID_LO_ADDRESS, + &node_unique_id_lo)) { + SBP2_DEBUG("sbp2: Error reading node unique id - bad status"); + return(-EIO); + } + + /* + * Spit out the node unique ids we got + */ + SBP2_DEBUG("sbp2: Node %x, node unique id hi = %x", (LOCAL_BUS | node_id), (unsigned int) node_unique_id_hi); + SBP2_DEBUG("sbp2: Node %x, node unique id lo = %x", (LOCAL_BUS | node_id), (unsigned int) node_unique_id_lo); + + node_unique_id = (((u64)node_unique_id_hi) << 32) | ((u64)node_unique_id_lo); + + /* + * First, we need to find out whether this is a "new" SBP-2 device plugged in, or one that already + * exists and is initialized. We do this by looping through our scsi id instance data structures + * looking for matching node unique ids. + */ + for (i=0; iscsi_id[i]) { + + if (hi->scsi_id[i]->node_unique_id == node_unique_id) { + + /* + * Update our node id + */ + hi->scsi_id[i]->node_id = node_id; + + /* + * Mark the device as validated, since it still exists on the bus + */ + hi->scsi_id[i]->validated = 1; + SBP2_DEBUG("sbp2: SBP-2 device re-validated, SCSI ID = %x", (unsigned int) i); + + /* + * Reconnect to the sbp-2 device + */ + if (sbp2_reconnect_device(hi, hi->scsi_id[i])) { + + /* + * Ok, reconnect has failed. Perhaps we didn't reconnect fast enough. Try + * doing a regular login. + */ + if (sbp2_login_device(hi, hi->scsi_id[i])) { + + /* + * Login failed too... so, just mark him as unvalidated, so that he gets cleaned up + * later + */ + SBP2_ERR("sbp2: sbp2_reconnect_device failed!"); + hi->scsi_id[i]->validated = 0; + } + } + + if (hi->scsi_id[i]->validated) { + + /* + * Set max retries to something large on the device + */ + sbp2_set_busy_timeout(hi, hi->scsi_id[i]); + + /* + * Enable unsolicited status on the device (not needed right now) + */ +#ifdef SBP2_ENABLE_UNSOLICITED_STATUS + sbp2_enable_unsolicited_status(hi, hi->scsi_id[i]); +#endif + + /* + * Do a SBP-2 fetch agent reset + */ + sbp2_agent_reset(hi, hi->scsi_id[i], 0); + + /* + * Get the max speed and packet size that we can use + */ + sbp2_max_speed_and_size(hi, hi->scsi_id[i]); + + } + + /* + * Nothing more to do, since we found the device + */ + return(0); + + } + } + } + + /* + * This really is a "new" device plugged in. Let's allocate memory for our scsi id instance data + */ + scsi_id = (struct scsi_id_instance_data *)kmalloc(sizeof(struct scsi_id_instance_data), GFP_KERNEL); + + if (!scsi_id) { + SBP2_ERR("sbp2: Could not allocate scsi id instance data"); + return(-ENOMEM); + } + + /* + * Initialize some of the fields in this structure + */ + memset(scsi_id, 0, sizeof(struct scsi_id_instance_data)); + scsi_id->node_id = node_id; + scsi_id->node_unique_id = node_unique_id; + scsi_id->validated = 1; + scsi_id->speed_code = SPEED_S100; + scsi_id->max_payload_size = MAX_PAYLOAD_S100; + + init_waitqueue_head(&scsi_id->sbp2_login_wait); + + /* + * Find an empty spot to stick our scsi id instance data. + */ + for (i=0; iscsi_id[i]) { + hi->scsi_id[i] = scsi_id; + SBP2_DEBUG("sbp2: New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i); + break; + } + } + + /* + * Make sure we are not out of space + */ + if (i >= SBP2SCSI_MAX_SCSI_IDS) { + SBP2_ERR("sbp2: No slots left for SBP-2 device"); + return(-EBUSY); + } + + /* + * Login to the sbp-2 device + */ + if (sbp2_login_device(hi, hi->scsi_id[i])) { + + /* + * Login failed... so, just mark him as unvalidated, so that he gets cleaned up later + */ + SBP2_ERR("sbp2: sbp2_login_device failed"); + hi->scsi_id[i]->validated = 0; + } + + if (hi->scsi_id[i]->validated) { + + /* + * Set max retries to something large on the device + */ + sbp2_set_busy_timeout(hi, hi->scsi_id[i]); + + /* + * Enable unsolicited status on the device (not needed right now) + */ +#ifdef SBP2_ENABLE_UNSOLICITED_STATUS + sbp2_enable_unsolicited_status(hi, hi->scsi_id[i]); +#endif + + /* + * Do a SBP-2 fetch agent reset + */ + sbp2_agent_reset(hi, hi->scsi_id[i], 0); + + /* + * Get the max speed and packet size that we can use + */ + sbp2_max_speed_and_size(hi, hi->scsi_id[i]); + + } + + return(0); +} + +/* + * This function trys to determine if a device is a valid SBP-2 device + */ +static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id) +{ + quadlet_t unit_spec_id_data = 0, unit_sw_ver_data = 0; + quadlet_t unit_directory_length, current_quadlet; + u64 unit_directory_addr, current_addr; + unsigned int i, length; + + SBP2_DEBUG("sbp2: sbp2_check_device"); + + /* + * Let's try and read the unit spec id and unit sw ver to determine if this is an SBP2 device... + */ + + if (sbp2util_unit_directory(hi, LOCAL_BUS | node_id, &unit_directory_addr)) { + SBP2_DEBUG("sbp2: Error reading unit directory address - bad status"); + return(-EIO); + } + + /* + * Read the size of the unit directory + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, unit_directory_addr, + &unit_directory_length)) { + SBP2_DEBUG("sbp2: Error reading root directory length - bad status"); + return(-EIO); + } + + current_addr = unit_directory_addr; + length = be32_to_cpu(unit_directory_length) >> 16; + + /* + * Now, step through the unit directory and look for the unit_spec_ID and the unit_sw_version + */ + for (i=0; i < length; i++) { + + current_addr += 4; + + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, ¤t_quadlet)) { + SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", + (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff)); + return(-EIO); + } + + /* + * Check for unit_spec_ID tag + */ + if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SPEC_ID_KEY) { + unit_spec_id_data = current_quadlet; + SBP2_DEBUG("sbp2: Node %x, unit spec id = %x", (LOCAL_BUS | node_id), + (unsigned int) be32_to_cpu(unit_spec_id_data)); + } + + /* + * Check for unit_sw_version tag + */ + if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SW_VERSION_KEY) { + unit_sw_ver_data = current_quadlet; + SBP2_DEBUG("sbp2: Node %x, unit sw version = %x", (LOCAL_BUS | node_id), + (unsigned int) be32_to_cpu(unit_sw_ver_data)); + } + } + + /* + * Validate unit spec id and unit sw ver to see if this is an SBP-2 device + */ + if ((be32_to_cpu(unit_spec_id_data) != SBP2_UNIT_SPEC_ID_ENTRY) || + (be32_to_cpu(unit_sw_ver_data) != SBP2_SW_VERSION_ENTRY)) { + + /* + * Not an sbp2 device + */ + return(-ENXIO); + } + + /* + * This device is a valid SBP-2 device + */ + SBP2_ERR("sbp2: Node %x, Found SBP-2 device", (LOCAL_BUS | node_id)); + return(0); +} + +/* + * This function removes (cleans-up after) any unvalidated sbp2 devices + */ +static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi) +{ + int i; + + /* + * Loop through and free any unvalidated scsi id instance data structures + */ + for (i=0; iscsi_id[i]) { + if (!hi->scsi_id[i]->validated) { + + /* + * Complete any pending commands (which were not already completed) + */ + if (hi->scsi_id[i]->Current_SCpnt) { + sbp2scsi_complete_command(hi, hi->scsi_id[i], SBP2_SCSI_STATUS_SELECTION_TIMEOUT); + } + + /* + * Clean up any other structures + */ + kfree(hi->scsi_id[i]); + hi->scsi_id[i] = NULL; + SBP2_DEBUG("sbp2: Unvalidated SBP-2 device removed, SCSI ID = %x", (unsigned int) i); + } + } + } + + return; +} + +/* + * This function is our reset handler. It is run out of a thread, since we get + * notified of a bus reset from a bh (or interrupt). + */ +static void sbp2_bus_reset_handler(void *context) +{ + struct sbp2scsi_host_info *hi = context; + quadlet_t signature_data; + int i; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2_bus_reset_handler"); + + /* + * TODO. Check and keep track of generation number of all requests, in case a + * bus reset occurs while trying to find and login to SBP-2 devices. + */ + + /* + * First thing to do. Invalidate all SBP-2 devices. This is needed so that + * we stop sending down I/O requests to the device, and also so that we can + * figure out which devices have disappeared after a bus reset. + */ + for (i=0; iscsi_id[i]) { + hi->scsi_id[i]->validated = 0; + } + } + + /* + * Give the sbp2 devices a little time to recover after the bus reset + */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/2); /* 1/2 second delay */ + + /* + * Spit out what we know from the host + */ + SBP2_DEBUG("host: node_count = %x", (unsigned int) hi->host->node_count); + SBP2_DEBUG("host: selfid_count = %x", (unsigned int) hi->host->selfid_count); + SBP2_DEBUG("host: node_id = %x", (unsigned int) hi->host->node_id); + SBP2_DEBUG("host: irm_id = %x", (unsigned int) hi->host->irm_id); + SBP2_DEBUG("host: busmgr_id = %x", (unsigned int) hi->host->busmgr_id); + SBP2_DEBUG("host: is_root = %x", (unsigned int) hi->host->is_root); + SBP2_DEBUG("host: is_cycmst = %x", (unsigned int) hi->host->is_cycmst); + SBP2_DEBUG("host: is_irm = %x", (unsigned int) hi->host->is_irm); + SBP2_DEBUG("host: is_busmgr = %x", (unsigned int) hi->host->is_busmgr); + + /* + * Let's try and figure out which devices out there are SBP-2 devices! Loop through all + * nodes out there. + */ + for (i=0; ihost->node_count; i++) { + + /* + * Don't read from ourselves! + */ + if (i != ((hi->host->node_id) & NODE_MASK)) { + + /* + * Try and send a request for a config rom signature. This is expected to fail for + * some nodes, as they might be repeater phys or not be initialized. + */ + if (!sbp2util_read_quadlet(hi, LOCAL_BUS | i, CONFIG_ROM_SIGNATURE_ADDRESS, &signature_data)) { + + if (be32_to_cpu(signature_data) == IEEE1394_CONFIG_ROM_SIGNATURE) { + + /* + * Hey, we've got a valid responding IEEE1394 node. Need to now see if it's an SBP-2 device + */ + if (!sbp2_check_device(hi, i)) { + + /* + * Found an SBP-2 device. Now, actually start the device. + */ + sbp2_start_device(hi, i); + } + } + } + } + } + + /* + * This code needs protection + */ + spin_lock_irqsave(&hi->sbp2_command_lock, flags); + + /* + * Ok, we've discovered and re-validated all SBP-2 devices out there. Let's remove structures of all + * devices not re-validated (meaning they've been removed). + */ + sbp2_remove_unvalidated_devices(hi); + + /* + * Now, note that the bus reset is complete (finally!) + */ + hi->bus_reset_in_progress = 0; + + /* + * Let's run through any pending commands and re-execute them + */ + for (i=0; iscsi_id[i]) { + if (hi->scsi_id[i]->Current_SCpnt) { + if (sbp2_send_command(hi, hi->scsi_id[i])) { + SBP2_ERR("sbp2: Error sending SCSI command"); + sbp2scsi_complete_command(hi, hi->scsi_id[i], SBP2_SCSI_STATUS_SELECTION_TIMEOUT); + } + } + } + } + spin_unlock_irqrestore(&hi->sbp2_command_lock, flags); + + return; +} + + +/* + * This is called from the host's bh when a bus reset is complete. We wake up our detection thread + * to deal with the reset + */ +static void sbp2_host_reset(struct hpsb_host *host) +{ + unsigned long flags; + struct sbp2scsi_host_info *hi; + int i; + + SBP2_ERR("sbp2: IEEE-1394 bus reset"); + spin_lock_irqsave(&sbp2_host_info_lock, flags); + hi = sbp2_find_host_info(host); + + if (hi != NULL) { + + /* + * Wake up our detection thread, only if it's not already handling a reset + */ + if (!hi->bus_reset_in_progress) { + + /* + * First thing to do. Invalidate all SBP-2 devices. This is needed so that + * we stop sending down I/O requests to the device, and also so that we can + * figure out which devices have disappeared after a bus reset. + */ + for (i=0; iscsi_id[i]) { + hi->scsi_id[i]->validated = 0; + } + } + + hi->bus_reset_in_progress = 1; + + wake_up(&hi->sbp2_detection_wait); + } + } + spin_unlock_irqrestore(&sbp2_host_info_lock, flags); + return; +} + +/* + * This function deals with physical dma write requests (for adapters that do not support + * physical dma in hardware). + */ +#ifdef SBP2_EMULATE_PHYSICAL_DMA_SUPPORT +static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) +{ + + /* + * Manually put the data in the right place. + */ + memcpy(bus_to_virt((u32)addr), data, length); + return(RCODE_COMPLETE); +} +#endif + +/* + * This function deals with physical dma read requests (for adapters that do not support + * physical dma in hardware). + */ +#ifdef SBP2_EMULATE_PHYSICAL_DMA_SUPPORT +static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) +{ + + /* + * Grab data from memory and send a read response. + */ + memcpy(data, bus_to_virt((u32)addr), length); + return(RCODE_COMPLETE); +} +#endif + + +/************************************** + * SBP-2 protocol related section + **************************************/ + +/* + * This function is called in order to login to a particular SBP-2 device, after a bus reset + */ +static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data[2]; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2_login_device"); + + /* + * Make sure that we've gotten ahold of the sbp2 management agent address. Also figure out the + * command set being used (SCSI or RBC). + */ + if (sbp2_parse_unit_directory(hi, scsi_id)) { + SBP2_ERR("sbp2: Error while parsing sbp2 unit directory"); + return(-EIO); + } + + /* + * Set-up login ORB + */ + scsi_id->login_orb.password = 0x0ULL; + scsi_id->login_orb.login_response_lo = virt_to_bus(&scsi_id->login_response); + scsi_id->login_orb.login_response_hi = (hi->host->node_id) << 16; + scsi_id->login_orb.lun = 0x0; /* temporary, until we support multiple luns */ + scsi_id->login_orb.function = LOGIN_REQUEST; + scsi_id->login_orb.reconnect = 0x0; + scsi_id->login_orb.reserved = 0x0; + scsi_id->login_orb.x = 0x1; + scsi_id->login_orb.rq_fmt = 0x0; + scsi_id->login_orb.n = 0x1; + scsi_id->login_orb.login_response_length = sizeof(struct sbp2_login_response); + scsi_id->login_orb.password_length = 0x0; + scsi_id->login_orb.status_FIFO_lo = (u32)SBP2_STATUS_FIFO_ADDRESS; + scsi_id->login_orb.status_FIFO_hi = ((hi->host->node_id) << 16) | ((u32)(SBP2_STATUS_FIFO_ADDRESS >> 32)); + + /* + * Byte swap ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(&scsi_id->login_orb, sizeof(struct sbp2_login_orb)); + + /* + * Initialize login response and status fifo + */ + memset(&scsi_id->login_response, 0, sizeof(struct sbp2_login_response)); + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + + /* + * Ok, let's write to the target's management agent register + */ + data[0] = (hi->host->node_id) << 16; + data[1] = virt_to_bus(&scsi_id->login_orb); + sbp2util_cpu_to_be32_buffer(data, 8); + + hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + + /* + * Wait for login status... but, only if the device has not already logged-in (some devices are fast) + */ + save_flags(flags); + cli(); + if (bus_to_virt(scsi_id->status_block.ORB_offset_lo) != &scsi_id->login_orb) { + interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ); /* 20 second timeout */ + } + restore_flags(flags); + + /* + * Match status to the login orb. If they do not match, it's probably because the login timed-out + */ + if (bus_to_virt(scsi_id->status_block.ORB_offset_lo) != &scsi_id->login_orb) { + SBP2_ERR("sbp2: Error logging into SBP-2 device - login timed-out"); + return(-EIO); + } + + /* + * Check status + */ + if (scsi_id->status_block.resp || + scsi_id->status_block.d || + scsi_id->status_block.sbp_status) { + + SBP2_ERR("sbp2: Error logging into SBP-2 device - login failed"); + return(-EIO); + } + + /* + * Grab our command block agent address from the login response + */ + SBP2_DEBUG("sbp2: command_block_agent_hi = %x", (unsigned int)be32_to_cpu(scsi_id->login_response.command_block_agent_hi)); + SBP2_DEBUG("sbp2: command_block_agent_lo = %x", (unsigned int)be32_to_cpu(scsi_id->login_response.command_block_agent_lo)); + + scsi_id->sbp2_command_block_agent_addr = ((u64)(be32_to_cpu(scsi_id->login_response.command_block_agent_hi)) << 32); + scsi_id->sbp2_command_block_agent_addr |= ((u64)(be32_to_cpu(scsi_id->login_response.command_block_agent_lo))); + scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL; + + SBP2_DEBUG("sbp2: sbp2_command_block_agent_addr = %x", (unsigned int)scsi_id->sbp2_command_block_agent_addr); + + SBP2_ERR("sbp2: Logged into SBP-2 device"); + + return(0); + +} + +/* + * This function is called in order to logout from a particular SBP-2 device, usually called during driver + * unload + */ +static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data[2]; + + SBP2_DEBUG("sbp2: sbp2_logout_device"); + + /* + * Set-up logout ORB + */ + scsi_id->logout_orb.reserved1 = 0x0; + scsi_id->logout_orb.reserved2 = 0x0; + scsi_id->logout_orb.login_ID = be32_to_cpu(scsi_id->login_response.login_ID); + scsi_id->logout_orb.function = LOGOUT_REQUEST; + scsi_id->logout_orb.reserved3 = 0x0; + scsi_id->logout_orb.rq_fmt = 0x0; + scsi_id->logout_orb.n = 0x1; + scsi_id->logout_orb.reserved4 = 0; + scsi_id->logout_orb.status_FIFO_lo = (u32)SBP2_STATUS_FIFO_ADDRESS; + scsi_id->logout_orb.status_FIFO_hi = ((hi->host->node_id) << 16) | ((u32)(SBP2_STATUS_FIFO_ADDRESS >> 32)); + + /* + * Byte swap ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(&scsi_id->logout_orb, sizeof(struct sbp2_logout_orb)); + + /* + * Ok, let's write to the target's management agent register + */ + data[0] = (hi->host->node_id) << 16; + data[1] = virt_to_bus(&scsi_id->logout_orb); + sbp2util_cpu_to_be32_buffer(data, 8); + + hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + + /* + * Wait for device to logout... + */ + interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); /* 1 second timeout */ + + SBP2_ERR("sbp2: Logged out of SBP-2 device"); + + return(0); + +} + +/* + * This function is called in order to reconnect to a particular SBP-2 device, after a bus reset + */ +static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data[2]; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2_reconnect_device"); + + /* + * Set-up reconnect ORB + */ + scsi_id->reconnect_orb.reserved1 = 0x0; + scsi_id->reconnect_orb.reserved2 = 0x0; + scsi_id->reconnect_orb.login_ID = be32_to_cpu(scsi_id->login_response.login_ID); + scsi_id->reconnect_orb.function = RECONNECT_REQUEST; + scsi_id->reconnect_orb.reserved3 = 0x0; + scsi_id->reconnect_orb.rq_fmt = 0x0; + scsi_id->reconnect_orb.n = 0x1; + scsi_id->reconnect_orb.reserved4 = 0x0; + scsi_id->reconnect_orb.status_FIFO_lo = (u32)SBP2_STATUS_FIFO_ADDRESS; + scsi_id->reconnect_orb.status_FIFO_hi = ((hi->host->node_id) << 16) | ((u32)(SBP2_STATUS_FIFO_ADDRESS >> 32)); + + /* + * Byte swap ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(&scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb)); + + /* + * Initialize status fifo + */ + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + + /* + * Ok, let's write to the target's management agent register + */ + data[0] = (hi->host->node_id) << 16; + data[1] = virt_to_bus(&scsi_id->reconnect_orb); + sbp2util_cpu_to_be32_buffer(data, 8); + + hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + + /* + * Wait for reconnect status... but, only if the device has not already reconnected (some devices are fast) + */ + save_flags(flags); + cli(); + if (bus_to_virt(scsi_id->status_block.ORB_offset_lo) != &scsi_id->reconnect_orb) { + interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); /* one second timeout */ + } + restore_flags(flags); + + /* + * Match status to the reconnect orb. If they do not match, it's probably because the reconnect timed-out + */ + if (bus_to_virt(scsi_id->status_block.ORB_offset_lo) != &scsi_id->reconnect_orb) { + SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect timed-out"); + return(-EIO); + } + + /* + * Check status + */ + if (scsi_id->status_block.resp || + scsi_id->status_block.d || + scsi_id->status_block.sbp_status) { + + SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect failed"); + return(-EIO); + } + + SBP2_ERR("sbp2: Reconnected to SBP-2 device"); + + return(0); + +} + +/* + * This function is called in order to set the busy timeout (number of retries to attempt) on the sbp2 device. + */ +static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data; + + SBP2_DEBUG("sbp2: sbp2_set_busy_timeout"); + + /* + * Ok, let's write to the target's busy timeout register + */ + data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); + + if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) { + SBP2_ERR("sbp2: sbp2_set_busy_timeout error"); + } + + return(0); +} + +/* + * This function is called to parse sbp2 device's config rom unit directory. Used to determine + * things like sbp2 management agent offset, and command set used (SCSI or RBC). + */ +static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t unit_directory_length, unit_directory_data; + u64 unit_directory_addr; + u32 i; + + SBP2_DEBUG("sbp2: sbp2_parse_unit_directory"); + + if (sbp2util_unit_directory(hi, LOCAL_BUS | scsi_id->node_id, &unit_directory_addr)) { + SBP2_DEBUG("sbp2: Error reading unit directory address - bad status"); + return(-EIO); + } + + /* + * Read the size of the unit directory + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | scsi_id->node_id, unit_directory_addr, + &unit_directory_length)) { + SBP2_DEBUG("sbp2: Error reading unit directory length - bad status"); + return(-EIO); + } + + unit_directory_length = ((be32_to_cpu(unit_directory_length)) >> 16); + + /* + * Now, sweep through the unit directory looking for the management agent offset + * Give up if we hit any error or somehow miss it... + */ + for (i=0; inode_id, unit_directory_addr + (i<<2) + 4, + &unit_directory_data)) { + SBP2_DEBUG("sbp2: Error reading unit directory - bad status"); + return(-EIO); + } + + /* + * Handle different fields in the unit directory, based on keys + */ + unit_directory_data = be32_to_cpu(unit_directory_data); + switch (unit_directory_data >> 24) { + + case SBP2_CSR_OFFSET_KEY: + + /* + * Save off the management agent address + */ + scsi_id->sbp2_management_agent_addr = CONFIG_ROM_INITIAL_MEMORY_SPACE + + ((unit_directory_data & 0x00ffffff) << 2); + + SBP2_DEBUG("sbp2: sbp2_management_agent_addr = %x", (unsigned int) scsi_id->sbp2_management_agent_addr); + break; + + case SBP2_COMMAND_SET_SPEC_ID_KEY: + + /* + * Command spec organization + */ + scsi_id->sbp2_command_set_spec_id = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_command_set_spec_id = %x", (unsigned int) scsi_id->sbp2_command_set_spec_id); + break; + + case SBP2_COMMAND_SET_KEY: + + /* + * Command set used by sbp2 device + */ + scsi_id->sbp2_command_set = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_command_set = %x", (unsigned int) scsi_id->sbp2_command_set); + break; + + case SBP2_UNIT_CHARACTERISTICS_KEY: + + /* + * Unit characterisitcs (orb related stuff that I'm not yet paying attention to) + */ + scsi_id->sbp2_unit_characteristics = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_unit_characteristics = %x", (unsigned int) scsi_id->sbp2_unit_characteristics); + break; + + case SBP2_DEVICE_TYPE_AND_LUN_KEY: + + /* + * Device type and lun (used for detemining type of sbp2 device) + */ + scsi_id->sbp2_device_type_and_lun = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_device_type_and_lun = %x", (unsigned int) scsi_id->sbp2_device_type_and_lun); + break; + + case SBP2_UNIT_SPEC_ID_KEY: + + /* + * Unit spec id (used for protocol detection) + */ + scsi_id->sbp2_unit_spec_id = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_unit_spec_id = %x", (unsigned int) scsi_id->sbp2_unit_spec_id); + break; + + case SBP2_UNIT_SW_VERSION_KEY: + + /* + * Unit sw version (used for protocol detection) + */ + scsi_id->sbp2_unit_sw_version = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_unit_sw_version = %x", (unsigned int) scsi_id->sbp2_unit_sw_version); + break; + + default: + break; + } + + } + + return(0); +} + +/* + * This function is called in order to enable unsolicited status on the sbp2 device. + */ +#ifdef SBP2_ENABLE_UNSOLICITED_STATUS +static int sbp2_enable_unsolicited_status(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data; + + SBP2_DEBUG("sbp2: sbp2_enable_unsolicited_status"); + + /* + * Let's write to the target's unsolicited status enable address + */ + data = cpu_to_be32(SBP2_UNSOLICITED_STATUS_VALUE); + + if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, + scsi_id->sbp2_command_block_agent_addr + SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET, + &data, 4)) { + SBP2_ERR("sbp2: sbp2_enable_unsolicited_status error"); + } + + return(0); +} +#endif + +/* + * This function is called in order to determine the max speed and packet size we can use in our ORBs. + */ +static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t node_options, max_rec; + u8 speed_code; + + SBP2_DEBUG("sbp2: sbp2_max_speed_and_size"); + + /* + * Get speed code from internal host structure. There should be a better way to obtain this. + */ + speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64 + (scsi_id->node_id & NODE_MASK)]; + + switch (speed_code) { + case SPEED_S100: + scsi_id->speed_code = SPEED_S100; + scsi_id->max_payload_size = MAX_PAYLOAD_S100; + SBP2_ERR("sbp2: SBP-2 device max speed S100 and payload 512 bytes"); + break; + case SPEED_S200: + scsi_id->speed_code = SPEED_S200; + scsi_id->max_payload_size = MAX_PAYLOAD_S200; + SBP2_ERR("sbp2: SBP-2 device max speed S200 and payload 1KB"); + break; + case SPEED_S400: + scsi_id->speed_code = SPEED_S400; + scsi_id->max_payload_size = MAX_PAYLOAD_S400; + SBP2_ERR("sbp2: SBP-2 device max speed S400 and payload 2KB"); + break; + default: + scsi_id->speed_code = SPEED_S100; + scsi_id->max_payload_size = MAX_PAYLOAD_S100; + SBP2_ERR("sbp2: Undefined speed: Using SBP-2 device max speed S100 and payload 512 bytes"); + break; + } + + /* + * Device speed/payload hacks go here... + */ + if (scsi_id->speed_code > SBP2_MAX_SPEED_ALLOWED) { + scsi_id->speed_code = SBP2_MAX_SPEED_ALLOWED; + SBP2_ERR("sbp2: Reducing SBP-2 max speed allowed (%x)", SBP2_MAX_SPEED_ALLOWED); + } + + if (scsi_id->max_payload_size > SBP2_MAX_PAYLOAD_ALLOWED) { + scsi_id->max_payload_size = SBP2_MAX_PAYLOAD_ALLOWED; + SBP2_ERR("sbp2: Reducing SBP-2 max payload allowed (%x)", SBP2_MAX_PAYLOAD_ALLOWED); + } + + /* + * Finally, check the adapter's capabilities to further bump down our max payload size + * if necessary. For instance, TILynx may not support the default max payload at a + * particular speed. + */ + if (!hpsb_read(hi->host, hi->host->node_id | LOCAL_BUS, CONFIG_ROM_NODE_OPTIONS, &node_options, 4)) { + + /* + * Grab max_rec (max payload = 2 ^ (max_rec+1)) from node options. Sbp2 max payload is + * defined as 2 ^ (max_pay+2)... so, have to subtract one from max rec for comparison... + * confusing, eh? ;-) + */ + max_rec = (be32_to_cpu(node_options) & 0x0000f000) >> 12; + if (scsi_id->max_payload_size > (max_rec - 1)) { + scsi_id->max_payload_size = (max_rec - 1); + SBP2_ERR("sbp2: Reducing SBP-2 max payload allowed (%x)", (max_rec - 1)); + } + + } + + return(0); +} + +/* + * This function is called in order to perform a SBP-2 agent reset. + */ +static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags) +{ + struct sbp2_request_packet *agent_reset_request_packet; + + SBP2_DEBUG("sbp2: sbp2_agent_reset"); + + /* + * Ok, let's write to the target's management agent register + */ + agent_reset_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id, + scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET, + 0, ntohl(SBP2_AGENT_RESET_DATA)); + + if (!agent_reset_request_packet) { + SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed"); + return(-EIO); + } + + if (!hpsb_send_packet(agent_reset_request_packet->packet)) { + SBP2_ERR("sbp2: hpsb_send_packet failed"); + sbp2util_free_request_packet(agent_reset_request_packet); + return(-EIO); + } + + if (!(flags & SBP2_SEND_NO_WAIT)) { + down(&agent_reset_request_packet->packet->state_change); + down(&agent_reset_request_packet->packet->state_change); + } + + return(0); + +} + +/* + * This function is called in order to begin a regular SBP-2 command. + */ +static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + Scsi_Cmnd *SCpnt = scsi_id->Current_SCpnt; + unchar *cmd = (unchar *) SCpnt->cmnd; + struct scatterlist *sgpnt; + int i; + struct sbp2_request_packet *command_request_packet; + u32 device_type; + + SBP2_DEBUG("sbp2: sbp2_send_command"); + SBP2_DEBUG("sbp2: SCSI command = %02x", *cmd); + SBP2_DEBUG("sbp2: SCSI command length = %x", COMMAND_SIZE(*cmd)); + SBP2_DEBUG("sbp2: SCSI data transfer direction = %x", sbp2scsi_direction_table[*cmd]); + + /* + * Set-up our command ORB.. + * + * NOTE: We're doing unrestricted page tables (s/g), as this is best performance + * (at least with the devices I have). This means that data_size becomes the number + * of s/g elements, and page_size should be zero (for unrestricted). + */ + scsi_id->command_orb.next_ORB_hi = 0xffffffff; + scsi_id->command_orb.next_ORB_lo = 0xffffffff; + scsi_id->command_orb.page_size = 0x0; /* use unrestricted page tables (s/g) */ + scsi_id->command_orb.max_payload = scsi_id->max_payload_size; + scsi_id->command_orb.spd = scsi_id->speed_code; + scsi_id->command_orb.r = 0x0; + scsi_id->command_orb.rq_fmt = 0x0; + scsi_id->command_orb.n = 0x1; + + /* + * Set-up our pagetable stuff... + */ + if (sbp2scsi_direction_table[*cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) { + + SBP2_DEBUG("sbp2: No data transfer"); + + /* + * Handle no data transfer + */ + scsi_id->command_orb.p = 0x0; /* use page tables (s/g) */ + scsi_id->command_orb.data_size = 0x0; /* number of page table (s/g) elements */ + scsi_id->command_orb.data_descriptor_hi = 0xffffffff; + scsi_id->command_orb.data_descriptor_lo = 0xffffffff; + scsi_id->command_orb.d = sbp2scsi_direction_table[*cmd]; + + } else if (SCpnt->use_sg) { + + SBP2_DEBUG("sbp2: Use scatter/gather"); + + /* + * Get s/g list from request + */ + sgpnt = (struct scatterlist *) SCpnt->request_buffer; + + /* + * Special case if only one element + */ + if (SCpnt->use_sg == 1) { + + SBP2_DEBUG("sbp2: Only one s/g element"); + + scsi_id->command_orb.p = 0x0; + scsi_id->command_orb.data_descriptor_hi = (hi->host->node_id) << 16; + scsi_id->command_orb.data_descriptor_lo = virt_to_bus(sgpnt[0].address); + scsi_id->command_orb.data_size = sgpnt[0].length; + scsi_id->command_orb.d = sbp2scsi_direction_table[*cmd]; + + } else { + + scsi_id->command_orb.p = 0x1; /* use page tables (s/g) */ + scsi_id->command_orb.data_size = SCpnt->use_sg; /* number of page table (s/g) elements */ + scsi_id->command_orb.data_descriptor_hi = (hi->host->node_id) << 16; + scsi_id->command_orb.data_descriptor_lo = virt_to_bus(scsi_id->scatter_gather_element); + scsi_id->command_orb.d = sbp2scsi_direction_table[*cmd]; + + /* + * Loop through and fill out our sbp-2 page tables + */ + for (i=0; iuse_sg; i++) { + scsi_id->scatter_gather_element[i].segment_length = sgpnt[i].length; + scsi_id->scatter_gather_element[i].segment_base_hi = 0x0; + scsi_id->scatter_gather_element[i].segment_base_lo = virt_to_bus(sgpnt[i].address); + } + + /* + * Byte swap page tables if necessary + */ + sbp2util_cpu_to_be32_buffer(scsi_id->scatter_gather_element, + (sizeof(struct sbp2_unrestricted_page_table)) * scsi_id->command_orb.data_size); + + } + + } else { + + SBP2_DEBUG("sbp2: No scatter/gather"); + + /* + * Handle case where we get a command w/o s/g enabled + */ + scsi_id->command_orb.p = 0x0; + scsi_id->command_orb.data_descriptor_hi = (hi->host->node_id) << 16; + scsi_id->command_orb.data_descriptor_lo = virt_to_bus(SCpnt->request_buffer); + scsi_id->command_orb.data_size = SCpnt->request_bufflen; + scsi_id->command_orb.d = sbp2scsi_direction_table[*cmd]; + + /* + * Sanity, in case our direction table is not up-to-date + */ + if (!SCpnt->request_bufflen) { + scsi_id->command_orb.data_descriptor_hi = 0xffffffff; + scsi_id->command_orb.data_descriptor_lo = 0xffffffff; + scsi_id->command_orb.d = ORB_DIRECTION_NO_DATA_TRANSFER; + } + + } + + /* + * Byte swap command ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(&scsi_id->command_orb, sizeof(struct sbp2_command_orb)); + + /* + * Put our scsi command in the command ORB + */ + memset(scsi_id->command_orb.cdb, 0, 12); + memcpy(scsi_id->command_orb.cdb, cmd, COMMAND_SIZE(*cmd)); + + /* + * Update our cdb if necessary (to handle sbp2 RBC command set differences). + * This is where the command set hacks go! =) + */ + device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16; + if ((device_type == TYPE_DISK) || + (device_type == TYPE_SDAD)) { + sbp2_check_sbp2_command(scsi_id->command_orb.cdb); + } + + /* + * Initialize status fifo + */ + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + + /* + * Ok, let's write to the target's management agent register + */ + command_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id, + scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET, + 8, 0); + + if (!command_request_packet) { + SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed"); + return(-EIO); + } + + command_request_packet->packet->data[0] = (hi->host->node_id) << 16; + command_request_packet->packet->data[1] = virt_to_bus(&scsi_id->command_orb); + sbp2util_cpu_to_be32_buffer(command_request_packet->packet->data, 8); + + if (!hpsb_send_packet(command_request_packet->packet)) { + SBP2_ERR("sbp2: hpsb_send_packet failed"); + sbp2util_free_request_packet(command_request_packet); + return(-EIO); + } + + return(0); +} + +/* + * This function deals with command set differences between Linux scsi command set and sbp2 RBC + * command set. + */ +static void sbp2_check_sbp2_command(unchar *cmd) +{ + unchar new_cmd[16]; + + SBP2_DEBUG("sbp2: sbp2_check_sbp2_command"); + + switch (*cmd) { + + case READ_6: + + SBP2_DEBUG("sbp2: Convert READ_6 to READ_10"); + + /* + * Need to turn read_6 into read_10 + */ + new_cmd[0] = 0x28; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + break; + + case WRITE_6: + + SBP2_DEBUG("sbp2: Convert WRITE_6 to WRITE_10"); + + /* + * Need to turn write_6 into write_10 + */ + new_cmd[0] = 0x2a; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + break; + + case MODE_SENSE: + case MODE_SELECT: + + /* + * TODO. Probably need to change mode sense/select to 10 byte versions + */ + + default: + break; + } + + return; +} + +/* + * Translates SBP-2 status into SCSI sense data for check conditions + */ +static void sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data) +{ + SBP2_DEBUG("sbp2: sbp2_status_to_sense_data"); + + /* + * Ok, it's pretty ugly... ;-) + */ + sense_data[0] = 0x70; + sense_data[1] = 0x0; + sense_data[2] = sbp2_status[9]; + sense_data[3] = sbp2_status[12]; + sense_data[4] = sbp2_status[13]; + sense_data[5] = sbp2_status[14]; + sense_data[6] = sbp2_status[15]; + sense_data[7] = 10; + sense_data[8] = sbp2_status[16]; + sense_data[9] = sbp2_status[17]; + sense_data[10] = sbp2_status[18]; + sense_data[11] = sbp2_status[19]; + sense_data[12] = sbp2_status[10]; + sense_data[13] = sbp2_status[11]; + sense_data[14] = sbp2_status[20]; + sense_data[15] = sbp2_status[21]; + + return; +} + +/* + * This function is called after a command is completed, in order to do any necessary SBP-2 + * response data translations for the SCSI stack + */ +static void sbp2_check_sbp2_response(Scsi_Cmnd *SCpnt) +{ + u8 *scsi_buf = SCpnt->request_buffer; + + SBP2_DEBUG("sbp2: sbp2_check_sbp2_response"); + + switch (SCpnt->cmnd[0]) { + + case INQUIRY: + + SBP2_DEBUG("sbp2: Check Inquiry data"); + + /* + * Check for Simple Direct Access Device and change it to TYPE_DISK + */ + if ((scsi_buf[0] & 0x1f) == TYPE_SDAD) { + SBP2_DEBUG("sbp2: Changing TYPE_SDAD to TYPE_DISK"); + scsi_buf[0] &= 0xe0; + } + + /* + * Fix ansi revision and response data format + */ + scsi_buf[2] |= 2; + scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; + + break; + + case MODE_SENSE: + case MODE_SELECT: + + /* + * TODO. Probably need to change mode sense/select to 10 byte versions + */ + + default: + break; + } + return; +} + +/* + * This function deals with status writes from the SBP-2 device + */ +static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) +{ + struct sbp2scsi_host_info *hi = NULL; + struct scsi_id_instance_data *scsi_id = NULL; + int i; + unsigned long flags; + Scsi_Cmnd *SCpnt = NULL; + + SBP2_DEBUG("sbp2: sbp2_handle_status_write"); + + if (!host) { + SBP2_ERR("sbp2: host is NULL - this is bad!"); + return(RCODE_ADDRESS_ERROR); + } + + spin_lock_irqsave(&sbp2_host_info_lock, flags); + hi = sbp2_find_host_info(host); + spin_unlock_irqrestore(&sbp2_host_info_lock, flags); + + if (!hi) { + SBP2_ERR("sbp2: host info is NULL - this is bad!"); + return(RCODE_ADDRESS_ERROR); + } + + spin_lock_irqsave(&hi->sbp2_command_lock, flags); + + /* + * Find our scsi_id structure + */ + for (i=0; iscsi_id[i]) { + if (hi->scsi_id[i]->node_id == (nodeid & NODE_MASK)) { + scsi_id = hi->scsi_id[i]; + SBP2_DEBUG("sbp2: SBP-2 status write from node %x", scsi_id->node_id); + break; + } + } + } + + if (!scsi_id) { + SBP2_ERR("sbp2: scsi_id is NULL - device is gone?"); + spin_unlock_irqrestore(&hi->sbp2_command_lock, flags); + return(RCODE_ADDRESS_ERROR); + } + + /* + * Put response into scsi_id status fifo... + */ + memcpy(&scsi_id->status_block, data, length); + + /* + * Byte swap first two quadlets (8 bytes) of status for processing + */ + sbp2util_be32_to_cpu_buffer(&scsi_id->status_block, 8); + + /* + * Handle command ORB status here if necessary. First, need to match status with command. + */ + if (bus_to_virt(scsi_id->status_block.ORB_offset_lo) == &scsi_id->command_orb) { + + SBP2_DEBUG("sbp2: Found status for command ORB"); + + /* + * Matched status with command, now grab scsi command pointers and check status + */ + SCpnt = scsi_id->Current_SCpnt; + + if (SCpnt) { + + /* + * Handle check conditions + */ + if (scsi_id->status_block.sbp_status) { + + SBP2_DEBUG("sbp2: CHECK CONDITION"); + + /* + * Translate SBP-2 status to SCSI sense data + */ + sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer); + + /* + * Initiate a fetch agent reset. + */ + sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); + + } + + /* + * Complete the SCSI command + */ + SBP2_DEBUG("sbp2: Completing SCSI command"); + if (scsi_id->status_block.sbp_status) { + sbp2scsi_complete_command(hi, scsi_id, ((unchar *)&scsi_id->status_block)[8] & 0x3f); + } else { + sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_GOOD); + } + + } + + } + + spin_unlock_irqrestore(&hi->sbp2_command_lock, flags); + wake_up(&scsi_id->sbp2_login_wait); + return(RCODE_COMPLETE); +} + + +/************************************** + * SCSI interface related section + **************************************/ + +/* + * This routine is used to deal with the older sbp2scsi_command routine + * that expects to be completed synchronously. Note: Not used, only here + * for completeness. + */ +static void sbp2scsi_internal_done (Scsi_Cmnd *SCpnt) +{ + SCpnt->SCp.Status++; +} + +/* + * This routine handles the older scsi method of doing I/O (synchronous + * I/O). This routine is called directly by the SCSI stack. Note: Not used, + * only here for completeness. + */ +static int sbp2scsi_command (Scsi_Cmnd *SCpnt) +{ + + /* + * Queue up the command + */ + SCpnt->SCp.Status = 0; + sbp2scsi_queuecommand (SCpnt, sbp2scsi_internal_done); + + /* + * Spin on completion + */ + while (!SCpnt->SCp.Status); + + /* + * Return result + */ + return(SCpnt->result); +} + +/* + * This routine is the main request entry routine for doing I/O. It is + * called from the scsi stack directly. + */ +static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + struct sbp2scsi_host_info *hi = NULL; + struct scsi_id_instance_data *scsi_id = NULL; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2scsi_queuecommand"); + + /* + * Pull our host info and scsi id instance data from the scsi command + */ + hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0]; + + if (!hi) { + SBP2_ERR("sbp2: sbp2scsi_host_info is NULL - this is bad!"); + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return(0); + } + + scsi_id = hi->scsi_id[SCpnt->target]; + + /* + * If scsi_id is null, it means there is no device in this slot, so we should return + * selection timeout. + */ + if (!scsi_id) { + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return(0); + } + + /* + * Until we handle multiple luns, just return selection time-out to any IO directed at non-zero LUNs + */ + if (SCpnt->lun) { + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return(0); + } + + /* + * Sanity! Should not normally occur. + */ + if (scsi_id->Current_SCpnt || scsi_id->Current_done) { + SBP2_ERR("sbp2: Overlapped SCSI command to same scsi id - this is bad!"); + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return(0); + } + + /* + * Save off our current scsi command and done routine + */ + scsi_id->Current_SCpnt = SCpnt; + scsi_id->Current_done = done; + + /* + * Check for request sense command, and handle it here (autorequest sense) + */ + if (SCpnt->cmnd[0] == REQUEST_SENSE) { + SBP2_ERR("sbp2: REQUEST_SENSE"); + memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen); + memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_GOOD); + return(0); + } + + /* + * Check to see if there is a bus reset in progress. If so, we'll execute the command + * later after the bus reset is complete. + */ + if (hi->bus_reset_in_progress) { + SBP2_ERR("sbp2: Bus reset in progress - delaying request"); + return(0); + } + + /* + * Try and send our SCSI command + */ + spin_lock_irqsave(&hi->sbp2_command_lock, flags); + if (sbp2_send_command(hi, scsi_id)) { + SBP2_ERR("sbp2: Error sending SCSI command"); + sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT); + } + spin_unlock_irqrestore(&hi->sbp2_command_lock, flags); + + return(0); +} + +/* + * This function is called in order to complete a regular SBP-2 command. + */ +static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status) +{ + void (*done)(Scsi_Cmnd *) = scsi_id->Current_done; + Scsi_Cmnd *SCpnt = scsi_id->Current_SCpnt; + + SBP2_DEBUG("sbp2: sbp2scsi_complete_command"); + + /* + * Sanity + */ + if (!SCpnt) { + SBP2_ERR("sbp2: SCpnt is NULL"); + return; + } + + /* + * If a bus reset is in progress and there was an error, don't complete the command, + * just let it get retried at the end of the bus reset. + */ + if ((hi->bus_reset_in_progress) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { + SBP2_ERR("sbp2: Bus reset in progress - retry command later"); + return; + } + + /* + * Retry the command if the device returns unit attention... it could have happened because + * of a 1394 bus reset or hot-plug... + */ +#ifdef SBP2_DO_RETRY_ON_UNIT_ATTENTION + if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) { + SBP2_ERR("sbp2: UNIT ATTENTION - retry command"); + if (sbp2_send_command(hi, scsi_id)) { + SBP2_ERR("sbp2: Error sending SCSI command"); + } else { + return; + } + } +#endif + + /* + * Null out current scsi command pointers + */ + scsi_id->Current_SCpnt = NULL; + scsi_id->Current_done = NULL; + + /* + * Switch on scsi status + */ + switch (scsi_status) { + case SBP2_SCSI_STATUS_GOOD: + SCpnt->result = DID_OK; + break; + + case SBP2_SCSI_STATUS_BUSY: + SBP2_ERR("sbp2: SBP2_SCSI_STATUS_BUSY"); + SCpnt->result = DID_BUS_BUSY << 16; + break; + + case SBP2_SCSI_STATUS_CHECK_CONDITION: + SBP2_ERR("sbp2: SBP2_SCSI_STATUS_CHECK_CONDITION"); + SCpnt->result = CHECK_CONDITION << 1; + + /* + * Debug stuff + */ + print_sense("bh", SCpnt); + + break; + + case SBP2_SCSI_STATUS_SELECTION_TIMEOUT: + SBP2_ERR("sbp2: SBP2_SCSI_STATUS_SELECTION_TIMEOUT"); + SCpnt->result = DID_NO_CONNECT << 16; + break; + + case SBP2_SCSI_STATUS_CONDITION_MET: + case SBP2_SCSI_STATUS_RESERVATION_CONFLICT: + case SBP2_SCSI_STATUS_COMMAND_TERMINATED: + SBP2_ERR("sbp2: Bad SCSI status = %x", scsi_status); + SCpnt->result = DID_ERROR << 16; + break; + + default: + SBP2_ERR("sbp2: Unsupported SCSI status = %x", scsi_status); + SCpnt->result = DID_ERROR << 16; + } + + /* + * Take care of any sbp2 response data mucking here (RBC stuff, etc.) + */ + if (SCpnt->result == DID_OK) { + sbp2_check_sbp2_response(SCpnt); + } + + /* + * Tell scsi stack that we're done with this command + */ + done (SCpnt); + + return; +} + +/* + * Called by scsi stack when something has really gone wrong (enhanced version). + * Usually called when a command has timed-out for some reason. + */ +static int sbp2scsi_eh_abort (Scsi_Cmnd *SCpnt) { + sbp2scsi_abort(SCpnt); + return(SUCCESS); +} + +/* + * Called by scsi stack when something has really gone wrong. + * Usually called when a command has timed-out for some reason. + */ +static int sbp2scsi_abort (Scsi_Cmnd *SCpnt) +{ + struct sbp2scsi_host_info *hi = NULL; + struct scsi_id_instance_data *scsi_id = NULL; + void (*done)(Scsi_Cmnd *) = SCpnt->done; + unsigned long flags; + + SBP2_ERR("sbp2: aborting sbp2 command"); + + /* + * Pull our host info and scsi id instance data from the scsi command + */ + hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0]; + + if (!hi) { + SBP2_ERR("sbp2: sbp2scsi_host_info is NULL - this is bad!"); + SCpnt->result = DID_ABORT << 16; + return(SCSI_ABORT_SNOOZE); + } + + scsi_id = hi->scsi_id[SCpnt->target]; + + if (!scsi_id) { + done = SCpnt->done; + SCpnt->result = DID_ABORT << 16; + done (SCpnt); + return(SCSI_ABORT_SUCCESS); + } + + spin_lock_irqsave(&hi->sbp2_command_lock, flags); + + /* + * Initiate a fetch agent reset. + */ + sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); + + /* + * Null out current command and complete the request. If we are in the middle of a reset, complete + * with busy status. + */ + if (scsi_id->Current_done) { + done = scsi_id->Current_done; + scsi_id->Current_SCpnt = NULL; + scsi_id->Current_done = NULL; + SCpnt->result = DID_ABORT << 16; + done (SCpnt); + } + + spin_unlock_irqrestore(&hi->sbp2_command_lock, flags); + return(SCSI_ABORT_SUCCESS); +} + +/* + * Called by scsi stack when something has really gone wrong. + */ +static int sbp2scsi_eh_reset (Scsi_Cmnd *SCpnt) { + SBP2_ERR("sbp2: reset requested"); + return(SUCCESS); +} + +/* + * Called by scsi stack when something has really gone wrong. + */ +static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + SBP2_ERR("sbp2: reset requested"); + return(SCSI_RESET_SUCCESS); +} + +/* + * Called by scsi stack to get bios parameters (used by fdisk, and at boot). + */ +static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) +{ + int heads, sectors, cylinders; + + SBP2_ERR("sbp2: request for bios parameters"); + + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + if (cylinders > 1024) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return(0); +} + +/* + * This routine is called at setup (init) and does nothing. Not used here. =) + */ +void sbp2scsi_setup( char *str, int *ints) +{ + SBP2_DEBUG("sbp2: sbp2scsi_setup"); + return; +} + +/* + * This is our detection routine, and is where we init everything. + */ +static int sbp2scsi_detect (Scsi_Host_Template *tpnt) +{ + SBP2_DEBUG("sbp2: sbp2scsi_detect"); + + printk("SBP-2 protocol driver for IEEE-1394\n"); + + global_scsi_tpnt = tpnt; + +#if LINUX_VERSION_CODE < 0x20300 + global_scsi_tpnt->proc_dir = &proc_scsi_sbp2scsi; +#else + global_scsi_tpnt->proc_name = "sbp2"; +#endif + + sbp2_init(); + + if (!sbp2_host_count) { + printk("Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2_1394...\n"); + if (sbp2_hl_handle) { + hpsb_unregister_highlevel(sbp2_hl_handle); + sbp2_hl_handle = NULL; + } + } + + /* + * Since we are returning this count, it means that sbp2 must be loaded "after" the + * host adapter module... + */ + return(sbp2_host_count); +} + +/* + * This function is called from sbp2_add_host, and is where we register our scsi host + */ +static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi) +{ + struct Scsi_Host *shpnt = NULL; + + SBP2_DEBUG("sbp2: sbp2scsi_register_scsi_host"); + SBP2_DEBUG("sbp2: sbp2scsi_host_info = %x", (unsigned int) hi); + + /* + * Let's register with the scsi stack + */ + if (global_scsi_tpnt) { + + shpnt = scsi_register (global_scsi_tpnt, sizeof(void *)); + + /* + * If successful, save off a context (to be used when SCSI commands are received) + */ + if (shpnt) { + shpnt->hostdata[0] = (unsigned long)hi; + } + } + + return; +} + +/* + * Called when our module is released + */ +static int sbp2scsi_release(struct Scsi_Host *host) +{ + SBP2_DEBUG("sbp2: sbp2scsi_release"); + sbp2_cleanup(); + return(0); +} + +/* + * Called for contents of procfs + */ +static const char *sbp2scsi_info (struct Scsi_Host *host) +{ + return "IEEE-1394 SBP-2 protocol driver"; +} + +/* + * Module related section + */ + +#ifdef MODULE + +MODULE_AUTHOR("James Goodwin "); +MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); +MODULE_SUPPORTED_DEVICE("sbp2_1394"); + +/* + * SCSI host template + */ +Scsi_Host_Template driver_template = SBP2SCSI; +#include "../scsi/scsi_module.c" + +#endif diff -Nur linux-2.4.19/drivers/ieee1394/sbp2_1394.h linux-2.4.19-sgi211r3/drivers/ieee1394/sbp2_1394.h --- linux-2.4.19/drivers/ieee1394/sbp2_1394.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/ieee1394/sbp2_1394.h Fri Feb 1 11:39:38 2002 @@ -0,0 +1,548 @@ +/* + * sbp2_1394.h - Defines and prototypes for sbp2_1394.c + * + * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com) + * jamesg@filanet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SBP2_1394_H +#define SBP2_1394_H + +#define SBP2_DEVICE_NAME "sbp2_1394" +#define SBP2_DEVICE_NAME_SIZE 9 + +/* + * SBP2 specific structures and defines + */ + +#define ORB_FMT_CMD 0x0 +#define ORB_FMT_DUMMY 0x3 + +#define ORB_DIRECTION_WRITE_TO_MEDIA 0x0 +#define ORB_DIRECTION_READ_FROM_MEDIA 0x1 +#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2 + +#define SPEED_S100 0x0 +#define SPEED_S200 0x1 +#define SPEED_S400 0x2 +#define SPEED_S800 0x3 +#define SPEED_S1600 0x4 +#define SPEED_S3200 0x5 + +/* 2^(MAX_PAYLOAD+2) = Maximum data transfer length */ +#define MAX_PAYLOAD_S100 0x7 +#define MAX_PAYLOAD_S200 0x8 +#define MAX_PAYLOAD_S400 0x9 + +struct sbp2_dummy_orb { + u32 next_ORB_hi; + u32 next_ORB_lo; + u64 reserved; + u32 reserved2:29; + u32 rq_fmt:2; + u32 n:1; + u8 command_block[12]; +}; + +struct sbp2_command_orb { + u32 next_ORB_hi; + u32 next_ORB_lo; + u32 data_descriptor_hi; + u32 data_descriptor_lo; + u32 data_size:16; + u32 page_size:3; + u32 p:1; + u32 max_payload:4; + u32 spd:3; + u32 d:1; + u32 r:1; + u32 rq_fmt:2; + u32 n:1; + u8 cdb[12]; +}; + +#define LOGIN_REQUEST 0x0 +#define QUERY_LOGINS_REQUEST 0x1 +#define RECONNECT_REQUEST 0x3 +#define SET_PASSWORD_REQUEST 0x4 +#define LOGOUT_REQUEST 0x7 +#define ABORT_TASK_REQUEST 0xb +#define ABORT_TASK_SET 0xc +#define LOGICAL_UNIT_RESET 0xe +#define TARGET_RESET_REQUEST 0xf + +struct sbp2_login_orb { + u64 password; + u32 login_response_hi; + u32 login_response_lo; + u32 lun:16; + u32 function:4; + u32 reconnect:4; + u32 reserved:4; + u32 x:1; + u32 rq_fmt:2; + u32 n:1; + u32 login_response_length:16; + u32 password_length:16; + u32 status_FIFO_hi; + u32 status_FIFO_lo; +}; + +struct sbp2_login_response { + u32 login_ID:16; + u32 length:16; + u32 command_block_agent_hi; + u32 command_block_agent_lo; + u32 reconnect_hold:16; + u32 reserved:16; +}; + +struct sbp2_reconnect_orb { + u64 reserved1; + u64 reserved2; + u32 login_ID:16; + u32 function:4; + u32 reserved3:9; + u32 rq_fmt:2; + u32 n:1; + u32 reserved4; + u32 status_FIFO_hi; + u32 status_FIFO_lo; +}; + +struct sbp2_logout_orb { + u64 reserved1; + u64 reserved2; + u32 login_ID:16; + u32 function:4; + u32 reserved3:9; + u32 rq_fmt:2; + u32 n:1; + u32 reserved4; + u32 status_FIFO_hi; + u32 status_FIFO_lo; +}; + +struct sbp2_unrestricted_page_table { + u32 segment_base_hi:16; + u32 segment_length:16; + u32 segment_base_lo; +}; + +#define RESP_STATUS_REQUEST_COMPLETE 0x0 +#define RESP_STATUS_TRANSPORT_FAILURE 0x1 +#define RESP_STATUS_ILLEGAL_REQUEST 0x2 +#define RESP_STATUS_VENDOR_DEPENDENT 0x3 + +#define SBP2_STATUS_NO_ADDITIONAL_INFO 0x0 +#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED 0x1 +#define SBP2_STATUS_SPEED_NOT_SUPPORTED 0x2 +#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED 0x3 +#define SBP2_STATUS_ACCESS_DENIED 0x4 +#define SBP2_STATUS_LU_NOT_SUPPORTED 0x5 +#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL 0x6 +#define SBP2_STATUS_RESOURCES_UNAVAILABLE 0x8 +#define SBP2_STATUS_FUNCTION_REJECTED 0x9 +#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED 0xa +#define SBP2_STATUS_DUMMY_ORB_COMPLETED 0xb +#define SBP2_STATUS_REQUEST_ABORTED 0xc +#define SBP2_STATUS_UNSPECIFIED_ERROR 0xff + +#define SFMT_CURRENT_ERROR 0x0 +#define SFMT_DEFERRED_ERROR 0x1 +#define SFMT_VENDOR_DEPENDENT_STATUS 0x3 + +#define SBP2_SCSI_STATUS_GOOD 0x0 +#define SBP2_SCSI_STATUS_CHECK_CONDITION 0x2 +#define SBP2_SCSI_STATUS_CONDITION_MET 0x4 +#define SBP2_SCSI_STATUS_BUSY 0x8 +#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT 0x18 +#define SBP2_SCSI_STATUS_COMMAND_TERMINATED 0x22 + +#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff + +struct sbp2_status_block { + u32 ORB_offset_hi:16; + u32 sbp_status:8; + u32 len:3; + u32 d:1; + u32 resp:2; + u32 src:2; + u32 ORB_offset_lo; + u32 sense_qualifier:8; + u32 sense_code:8; + u32 sense_key:4; + u32 i:1; + u32 e:1; + u32 m:1; + u32 v:1; + u32 status:6; + u32 sfmt:2; + u32 information; + u32 CDB_dependent; + u32 sense_key_dependent:24; + u32 fru:8; + u32 vendor_dependent[2]; +}; + +/* + * Miscellaneous SBP2 related config rom defines + */ + +#define SBP2_STATUS_FIFO_ADDRESS 0xfffe00000000ULL /* for write posting! */ + +#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1 +#define SBP2_CSR_OFFSET_KEY 0x54 +#define SBP2_UNIT_SPEC_ID_KEY 0x12 +#define SBP2_UNIT_SW_VERSION_KEY 0x13 +#define SBP2_COMMAND_SET_SPEC_ID_KEY 0x38 +#define SBP2_COMMAND_SET_KEY 0x39 +#define SBP2_UNIT_CHARACTERISTICS_KEY 0x3a +#define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14 + +#define SBP2_AGENT_STATE_OFFSET 0x00ULL +#define SBP2_AGENT_RESET_OFFSET 0x04ULL +#define SBP2_ORB_POINTER_OFFSET 0x08ULL +#define SBP2_DOORBELL_OFFSET 0x10ULL +#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET 0x14ULL +#define SBP2_UNSOLICITED_STATUS_VALUE 0xf + +#define SBP2_BUSY_TIMEOUT_ADDRESS 0xfffff0000210ULL +#define SBP2_BUSY_TIMEOUT_VALUE 0xf + +#define SBP2_AGENT_RESET_DATA 0xf + +/* + * Unit spec id and sw version entry for SBP-2 devices + */ + +#define SBP2_UNIT_SPEC_ID_ENTRY 0x1200609e +#define SBP2_SW_VERSION_ENTRY 0x13010483 + +/* + * Miscellaneous general config rom related defines + */ + +#define CONFIG_ROM_INITIAL_MEMORY_SPACE 0xfffff0000000ULL + +#define CONFIG_ROM_BASE_ADDRESS 0xfffff0000400ULL +#define CONFIG_ROM_ROOT_DIR_BASE 0xfffff0000414ULL +#define CONFIG_ROM_NODE_UNIQUE_ID_HI_ADDRESS 0xfffff000040cULL +#define CONFIG_ROM_NODE_UNIQUE_ID_LO_ADDRESS 0xfffff0000410ULL +#define CONFIG_ROM_SIGNATURE_ADDRESS 0xfffff0000404ULL +#define CONFIG_ROM_NODE_OPTIONS 0xfffff0000408ULL +#define CONFIG_ROM_UNIT_DIRECTORY_OFFSET 0xfffff0000424ULL + +#define IEEE1394_CONFIG_ROM_SIGNATURE 0x31333934 + +/* + * Flags for SBP-2 functions + */ +#define SBP2_SEND_NO_WAIT 0x00000001 + +/* + * SCSI specific stuff + */ + +#define SBP2_MAX_SG_ELEMENTS 0xff +#define SBP2SCSI_MAX_SCSI_IDS 8 +#define SBP2SCSI_MAX_OUTSTANDING_CMDS 1 /* bump this up after testing/debugging */ +#define SBP2SCSI_MAX_CMDS_PER_LUN 1 + +#ifndef TYPE_SDAD +#define TYPE_SDAD 0x0e /* simplified direct access device */ +#endif + +/* + * SCSI direction table... since the scsi stack doesn't specify direction... =( + * + * DIN = IN data direction + * DOU = OUT data direction + * DNO = No data transfer + * DUN = Unknown data direction + */ +#define DIN ORB_DIRECTION_READ_FROM_MEDIA +#define DOU ORB_DIRECTION_WRITE_TO_MEDIA +#define DNO ORB_DIRECTION_NO_DATA_TRANSFER +#define DUN DIN + +static unchar sbp2scsi_direction_table[0x100] = { + DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN, + DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN, + DIN,DUN,DIN,DIN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU, + DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU, + DOU,DOU,DIN,DIN,DIN,DNO,DIN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DNO,DUN, + DUN,DIN,DIN,DNO,DOU,DOU,DUN,DUN,DNO,DIN,DIN,DNO,DIN,DOU,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DNO,DOU,DOU,DIN,DNO,DNO,DNO,DIN,DNO,DOU,DUN,DNO,DIN,DOU,DOU, + DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DIN,DNO,DNO,DNO,DIN,DIN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN +}; + + +/* + * Proc structure. + */ +#if LINUX_VERSION_CODE < 0x20300 +#define PROC_SCSI_SBP2 PROC_SCSI_NOT_PRESENT /* What should I use? */ +static struct proc_dir_entry proc_scsi_sbp2scsi = { + PROC_SCSI_SBP2, SBP2_DEVICE_NAME_SIZE, SBP2_DEVICE_NAME, + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif + +/* + * Scsi_Host structure + */ +#define SBP2SCSI {name: "IEEE1394 Storage", \ + detect: sbp2scsi_detect, \ + release: sbp2scsi_release, \ + info: sbp2scsi_info, \ + command: sbp2scsi_command, \ + queuecommand: sbp2scsi_queuecommand, \ + abort: sbp2scsi_abort, \ + reset: sbp2scsi_reset, \ + eh_abort_handler: sbp2scsi_eh_abort, \ + eh_device_reset_handler: sbp2scsi_eh_reset, \ + eh_bus_reset_handler: sbp2scsi_eh_reset, \ + eh_host_reset_handler: sbp2scsi_eh_reset, \ + bios_param: sbp2scsi_biosparam, \ + can_queue: SBP2SCSI_MAX_OUTSTANDING_CMDS, \ + this_id: -1, \ + sg_tablesize: SBP2_MAX_SG_ELEMENTS, \ + cmd_per_lun: SBP2SCSI_MAX_CMDS_PER_LUN, \ + use_clustering: ENABLE_CLUSTERING, \ + emulated: 1, \ + use_new_eh_code: 1} + +/* + * Number of request packets available for actual sbp2 I/O requests (these are used + * for sending command and agent reset packets). + */ +#define SBP2_MAX_REQUEST_PACKETS 16 + +/* + * Request packets structure (used for sending command and agent reset packets) + */ +struct sbp2_request_packet { + + struct list_head list; + struct hpsb_packet *packet; + struct tq_struct tq; + void *hi_context; + +}; + +/* + * Information needed on a per scsi id basis (one for each sbp2 device) + */ +struct scsi_id_instance_data { + + /* + * Various sbp2 specific structures + */ + struct sbp2_command_orb command_orb; + struct sbp2_login_orb login_orb; + struct sbp2_login_response login_response; + struct sbp2_reconnect_orb reconnect_orb; + struct sbp2_logout_orb logout_orb; + struct sbp2_status_block status_block; + struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS]; + + /* + * Stuff we need to know about the sbp2 device itself + */ + u64 node_unique_id; + u64 sbp2_management_agent_addr; + u64 sbp2_command_block_agent_addr; + u32 node_id; + u32 speed_code; + u32 max_payload_size; + + /* + * Values pulled from the device's unit directory + */ + u32 sbp2_unit_spec_id; + u32 sbp2_unit_sw_version; + u32 sbp2_command_set_spec_id; + u32 sbp2_command_set; + u32 sbp2_unit_characteristics; + u32 sbp2_device_type_and_lun; + + /* + * Current scsi command being processed. We only do one scsi command at a time + * (per scsi id). Someday this might change if we decide to support command + * tagged queuing. + */ + Scsi_Cmnd *Current_SCpnt; + void (*Current_done)(Scsi_Cmnd *); + + /* + * Wait queue used for logins, reconnects, logouts + */ + wait_queue_head_t sbp2_login_wait; + + /* + * Flag noting whether the sbp2 device is currently validated (for use during + * bus resets). + */ + u32 validated; + +}; + +/* + * Sbp2 host data structure (one per sbp2 host) + */ +struct sbp2scsi_host_info { + + /* + * For use in keeping track of hosts + */ + struct list_head list; + struct hpsb_host *host; + + /* + * Spin locks for command processing and packet pool management + */ + spinlock_t sbp2_command_lock; + spinlock_t sbp2_request_packet_lock; + + /* + * Flag indicating if a bus reset (or device detection) is in progress + */ + u32 bus_reset_in_progress; + + /* + * We currently use a kernel thread for dealing with bus resets and sbp2 + * device detection. We use this to wake up the thread when needed. + */ + wait_queue_head_t sbp2_detection_wait; + + /* + * PID of sbp2 detection kernel thread + */ + int sbp2_detection_pid; + + /* + * Lists keeping track of inuse/free sbp2_request_packets. These structures are + * used for sending out sbp2 command and agent reset packets. We initially create + * a pool of request packets so that we don't have to do any kmallocs while in critical + * I/O paths. + */ + struct list_head sbp2_req_inuse; + struct list_head sbp2_req_free; + + /* + * Here is the pool of request packets. All the hpsb packets (for 1394 bus transactions) + * are allocated at init and simply re-initialized when needed. + */ + struct sbp2_request_packet request_packet[SBP2_MAX_REQUEST_PACKETS]; + + /* + * SCSI ID instance data (one for each sbp2 device instance possible) + */ + struct scsi_id_instance_data *scsi_id[SBP2SCSI_MAX_SCSI_IDS]; + +}; + +/* + * Function prototypes + */ + +/* + * Various utility prototypes + */ +static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length); +static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length); +static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr, + quadlet_t *buffer); +static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node, u64 *addr); +static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi); +static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi); +static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, + nodeid_t node, u64 addr, + size_t data_size, + quadlet_t data); +static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet); + +/* + * IEEE-1394 core driver related prototypes + */ +static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi); +static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id); +static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id); +static void sbp2_bus_reset_handler(void *context); +static void sbp2_add_host(struct hpsb_host *host); +static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host); +static void sbp2_remove_host(struct hpsb_host *host); +static void sbp2_host_reset(struct hpsb_host *host); +static int sbp2_detection_thread(void *__sbp2); +int sbp2_init(void); +void sbp2_cleanup(void); +#ifdef SBP2_EMULATE_PHYSICAL_DMA_SUPPORT +static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length); +static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length); +#endif + + +/* + * SBP-2 protocol related prototypes + */ +static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length); +static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags); +static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static void sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data); +static void sbp2_check_sbp2_command(unchar *cmd); +static void sbp2_check_sbp2_response(Scsi_Cmnd *SCpnt); +static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +#ifdef SBP2_ENABLE_UNSOLICITED_STATUS +static int sbp2_enable_unsolicited_status(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +#endif +static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); + +/* + * Scsi interface related prototypes + */ +static int sbp2scsi_release(struct Scsi_Host *host); +static const char *sbp2scsi_info (struct Scsi_Host *host); +static int sbp2scsi_detect (Scsi_Host_Template *tpnt); +void sbp2scsi_setup(char *str, int *ints); +static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]); +static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); +static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags); +static int sbp2scsi_eh_abort (Scsi_Cmnd *SCpnt); +static int sbp2scsi_eh_reset (Scsi_Cmnd *SCpnt); +static void sbp2scsi_internal_done (Scsi_Cmnd *SCpnt); +static int sbp2scsi_command (Scsi_Cmnd *SCpnt); +static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); +static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status); +static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi); + +#endif /* SBP2_1394_H */ diff -Nur linux-2.4.19/drivers/input/joydev.c linux-2.4.19-sgi211r3/drivers/input/joydev.c --- linux-2.4.19/drivers/input/joydev.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/input/joydev.c Wed Oct 16 14:02:58 2002 @@ -87,6 +87,12 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("input/js"); +static inline unsigned long +jiffies_to_msec (unsigned long t) +{ + return 1000*(t / HZ) + 1000*(t % HZ)/HZ; +} + static int joydev_correct(int value, struct js_corr *corr) { switch (corr->type) { @@ -134,7 +140,7 @@ return; } - event.time = jiffies * (1000 / HZ); + event.time = jiffies_to_msec(jiffies); while (list) { @@ -279,7 +285,7 @@ struct js_event event; - event.time = jiffies * (1000/HZ); + event.time = jiffies_to_msec(jiffies); if (list->startup < joydev->nkey) { event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; diff -Nur linux-2.4.19/drivers/macintosh/nvram.c linux-2.4.19-sgi211r3/drivers/macintosh/nvram.c --- linux-2.4.19/drivers/macintosh/nvram.c Mon Oct 15 13:43:24 2001 +++ linux-2.4.19-sgi211r3/drivers/macintosh/nvram.c Mon Oct 28 20:43:23 2002 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) { + lock_kernel(); switch (origin) { case 1: offset += file->f_pos; @@ -28,9 +30,12 @@ offset += NVRAM_SIZE; break; } - if (offset < 0) + if (offset < 0) { + unlock_kernel(); return -EINVAL; + } file->f_pos = offset; + unlock_kernel(); return file->f_pos; } diff -Nur linux-2.4.19/drivers/md/md.c linux-2.4.19-sgi211r3/drivers/md/md.c --- linux-2.4.19/drivers/md/md.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/md/md.c Mon Oct 28 20:43:23 2002 @@ -2936,8 +2936,6 @@ * bdflush, otherwise bdflush will deadlock if there are too * many dirty RAID5 blocks. */ - current->policy = SCHED_OTHER; - current->nice = -20; md_unlock_kernel(); complete(thread->event); @@ -3391,11 +3389,6 @@ "(but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); - /* - * Resync has low priority. - */ - current->nice = 19; - is_mddev_idle(mddev); /* this also initializes IO event counters */ for (m = 0; m < SYNC_MARKS; m++) { mark[m] = jiffies; @@ -3473,16 +3466,13 @@ currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > sysctl_speed_limit_min) { - current->nice = 19; - if ((currspeed > sysctl_speed_limit_max) || !is_mddev_idle(mddev)) { current->state = TASK_INTERRUPTIBLE; md_schedule_timeout(HZ/4); goto repeat; } - } else - current->nice = -20; + } } printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); err = 0; diff -Nur linux-2.4.19/drivers/md/raid5.c linux-2.4.19-sgi211r3/drivers/md/raid5.c --- linux-2.4.19/drivers/md/raid5.c Mon Feb 25 11:37:58 2002 +++ linux-2.4.19-sgi211r3/drivers/md/raid5.c Fri Apr 26 11:07:18 2002 @@ -282,7 +282,7 @@ } if (conf->buffer_size != size) { - printk("raid5: switching cache buffer size, %d --> %d\n", oldsize, size); + PRINTK("raid5: switching cache buffer size, %d --> %d\n", oldsize, size); shrink_stripe_cache(conf); if (size==0) BUG(); conf->buffer_size = size; diff -Nur linux-2.4.19/drivers/media/radio/Makefile linux-2.4.19-sgi211r3/drivers/media/radio/Makefile --- linux-2.4.19/drivers/media/radio/Makefile Sun Aug 5 13:15:05 2001 +++ linux-2.4.19-sgi211r3/drivers/media/radio/Makefile Tue Jan 8 17:05:38 2002 @@ -11,7 +11,7 @@ # Object file lists. -obj-y := +obj-y := dummy.o obj-m := obj-n := obj- := diff -Nur linux-2.4.19/drivers/media/radio/dummy.c linux-2.4.19-sgi211r3/drivers/media/radio/dummy.c --- linux-2.4.19/drivers/media/radio/dummy.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/media/radio/dummy.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1 @@ +/* just so the linker knows what kind of object files it's dealing with... */ diff -Nur linux-2.4.19/drivers/media/video/Makefile linux-2.4.19-sgi211r3/drivers/media/video/Makefile --- linux-2.4.19/drivers/media/video/Makefile Fri Nov 9 14:01:22 2001 +++ linux-2.4.19-sgi211r3/drivers/media/video/Makefile Tue Jan 8 17:05:38 2002 @@ -11,7 +11,7 @@ # Object file lists. -obj-y := +obj-y := dummy.o obj-m := obj-n := obj- := diff -Nur linux-2.4.19/drivers/media/video/dummy.c linux-2.4.19-sgi211r3/drivers/media/video/dummy.c --- linux-2.4.19/drivers/media/video/dummy.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/media/video/dummy.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1 @@ +/* just so the linker knows what kind of object files it's dealing with... */ diff -Nur linux-2.4.19/drivers/misc/Config.in linux-2.4.19-sgi211r3/drivers/misc/Config.in --- linux-2.4.19/drivers/misc/Config.in Sat Dec 25 15:04:56 1999 +++ linux-2.4.19-sgi211r3/drivers/misc/Config.in Thu Aug 8 15:12:42 2002 @@ -4,4 +4,6 @@ mainmenu_option next_comment comment 'Misc devices' +tristate 'Debug Tool Kit support' CONFIG_DBGTK + endmenu diff -Nur linux-2.4.19/drivers/misc/Makefile linux-2.4.19-sgi211r3/drivers/misc/Makefile --- linux-2.4.19/drivers/misc/Makefile Fri Dec 29 14:07:22 2000 +++ linux-2.4.19-sgi211r3/drivers/misc/Makefile Thu Aug 8 15:12:42 2002 @@ -11,6 +11,13 @@ O_TARGET := misc.o +export-objs := job.o dbgtk.o + +obj-$(CONFIG_PAGG_JOB) += job.o +obj-$(CONFIG_CSA_JOB_ACCT) += csa_job_acct.o + +obj-$(CONFIG_DBGTK) += dbgtk.o + include $(TOPDIR)/Rules.make fastdep: diff -Nur linux-2.4.19/drivers/misc/csa_job_acct.c linux-2.4.19-sgi211r3/drivers/misc/csa_job_acct.c --- linux-2.4.19/drivers/misc/csa_job_acct.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/misc/csa_job_acct.c Fri Nov 1 12:55:48 2002 @@ -0,0 +1,1480 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc and LANL All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + */ + +/* + * Description: + * This file, drivers/misc/csa_job_acct.c, contains the procedures that + * do the real work of configuring CSA, writing CSA accounting + * records, and processing the acctctl syscall. This code can + * either be compiled directly into the kernel or compiled as + * a loadable module. + * + * During initialization, this code registers procedure callbacks + * with the PAGG job code and the kernel/csa.c code. + * + * Author: + * Marlys Kohnke (kohnke@sgi.com) + * + * Contributors: + * + * Changes: + * January 31, 2001 (kohnke) Changed to use semaphores rather than + * spinlocks. Was seeing a spinlock deadlock sometimes when an accounting + * record was being written to disk with 2.4.0 (didn't happen with + * 2.4.0-test7). + * + * February 2, 2001 (kohnke) Changed to handle being compiled directly + * into the kernel, not just compiled as a loadable module. Renamed + * init_module() as init_csa() and cleanup_module() as cleanup_csa(). + * Added calls to module_init() and module_exit(). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int csa_jstart(int, void *); +int csa_jexit(int, void *); +int do_acctctl(int, void *); +void do_csa_acct(int, struct task_struct *); +static int csa_modify_buf(char *, struct acctcsa *, struct acctmem *, + struct acctio *, int, int); +static int csa_write(char *, int, int, uint64_t, int, job_csa_t *); +static void csa_config_make(ac_eventtype, struct acctcfg *); +static int csa_config_write(ac_eventtype,struct file *); +static void csa_header(struct achead *, int, int, int); +static long int sc_CLK(long int); + +#if defined __ia64__ +#define JID_ERR1 "do_csa_acct: No job table entry for jid 0x%lx.\n" +#define JID_ERR2 "csa user job accounting write error %d, jid 0x%lx\n" +#define JID_ERR3 "Can't disable csa user job accounting jid 0x%lx\n" +#define JID_ERR4 "csa user job accounting disabled, jid 0x%lx\n" +#else +#define JID_ERR1 "do_csa_acct: No job table entry for jid 0x%llx.\n" +#define JID_ERR2 "csa user job accounting write error %d, jid 0x%llx\n" +#define JID_ERR3 "Can't disable csa user job accounting jid 0x%llx\n" +#define JID_ERR4 "csa user job accounting disabled, jid 0x%llx\n" +#endif + +/* this defines can be removed once they're available in kernel header files */ +#define USEC_PER_SEC 1000000L /* number of usecs for 1 second */ +#define USEC_PER_TICK (USEC_PER_SEC/HZ) +#define NBPC PAGE_SIZE /* Number of bytes per click */ +#define ctob(x) ((uint64_t)(x)*NBPC) + + +static struct file *csa_acctvp = (struct file *)NULL; +static time_t boottime = 0; + +struct timeval acct_now; /* present time (sec, usec) */ + +static DECLARE_MUTEX(csa_sem); +static DECLARE_MUTEX(csa_write_sem); + +static int csa_flag = 0; /* accounting start state flag */ +char csa_path[ACCT_PATH] = ""; /* current accounting file path name */ +char new_path[ACCT_PATH] = ""; /* new accounting file path name */ + +static job_acctmod_t csa_job_callbacks = { + JOB_ACCT_CSA, + csa_jstart, + csa_jexit, + THIS_MODULE +}; +static struct csa_module_s csa_callbacks = { + do_acctctl, + do_csa_acct, + THIS_MODULE +}; + +/* modify this when changes are made to ac_kdrcd in csa.h */ +char *acct_dmd_name[ACCT_MAXKDS] = + {"CSA", + "JOB", + "ASH", + "NQS", + "WORKLOAD MGMT", + "TAPE", + "DATA MIGRATION", + "SOCKET", + "SITE1", + "SITE2" }; + +typedef enum { + A_SYS, /* system accounting action (0) */ + A_CJA, /* Job accounting action (1) */ + A_DMD, /* daemon accounting action (2) */ + A_MAX} a_fnc; + +struct actstat acct_dmd[ACCT_MAXKDS][A_MAX]; +struct actstat acct_rcd[ACCT_MAXRCDS-ACCT_RCDS][A_MAX]; + +/* Initialize the CSA accounting state information. */ +#define INIT_DMD(t, i, s, p) acct_dmd[i][t].ac_ind = i; \ + acct_dmd[i][t].ac_state = s; \ + acct_dmd[i][t].ac_param = p; +#define INIT_RCD(t, i, s, p) acct_rcd[i-ACCT_RCDS][t].ac_ind = i; \ + acct_rcd[i-ACCT_RCDS][t].ac_state = s; \ + acct_rcd[i-ACCT_RCDS][t].ac_param = p; + +/* + * register procedure callbacks with the kernel/csa.c CSA + * code and with the PAGG job code + */ +static int __init +init_csa(void) +{ + int retval = 0; + + /* + * register callbacks with the CSA kernel/csa.c code to + * process the acctctl syscall and write end-of-process accounting + * records. + */ + retval = register_csa(&csa_callbacks); + if (retval != 0) { + /* no point in continuing */ + return retval; + } + /* + * register callbacks with the PAGG job code to process + * start-of-job and end-of-job accounting records. If this is a + * module, this registration will also increment the job module + * use count so the job module won't be unloaded out from under + * the CSA module. + */ + retval = job_register_acct(&csa_job_callbacks); + return retval; +} + +/* + * Do module cleanup before the module is removed; unregister + * procedure callbacks with the kernel non-module CSA code and + * with the PAGG job module (which decrements the job module use count). + */ +static void __exit +cleanup_csa(void) +{ + int retval = 0; + + unregister_csa(); + + retval = job_unregister_acct(&csa_job_callbacks); + if (retval < 0) { + printk(KERN_ERR "CSA module can't unregister with job module." + "Continuing with CSA module cleanup.\n"); + } + return; +} + +/* + * Initialize the CSA accounting state table. + * Modify this when changes are made to ac_kdrcd in csa.h + * + */ +static void +csa_init_acct(int flag) +{ + csa_flag = flag; + + boottime = xtime.tv_sec - (jiffies / HZ); + + /* Initialize system accounting states. */ + INIT_DMD(A_SYS, ACCT_KERN_CSA, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_KERN_JOB_PROC, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_KERN_ASH, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_DMD_NQS, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_DMD_WKMG, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_DMD_TAPE, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_DMD_SOCKET, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_DMD_DMIG, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_DMD_SITE1, ACS_OFF, 0); + INIT_DMD(A_SYS, ACCT_DMD_SITE2, ACS_OFF, 0); + + INIT_RCD(A_SYS, ACCT_RCD_MPPDET, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_MEM, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_IO, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_MT, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_MPP, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_THD_MEM, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_THD_TIME, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_INCACCT, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_APPACCT, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_SITE1, ACS_OFF, 0); + INIT_RCD(A_SYS, ACCT_RCD_SITE2, ACS_OFF, 0); + + return; +} + +/* + * convert ticks into microseconds; necessary kernel math ops not + * available on 32-bit systems, so can't use uint64_t + */ +static long int +sc_CLK(long int clock) +{ + long int sec, split; + + sec = clock / HZ; + split = (clock % HZ) * 1000000 / HZ; + + return ((sec * 1000000) + split); +} + +/* Initialize CSA accounting header. */ +static void +csa_header(struct achead *head, int revision, int type, int size) +{ + head->ah_magic = ACCT_MAGIC; + head->ah_revision = revision; + head->ah_type = type; + head->ah_flag = 0; + head->ah_size = size; + + return; +} + +/* + * Create a CSA end-of-process accounting record and write it to + * appropriate file(s) + */ +void +do_csa_acct(int exitcode, struct task_struct *p) +{ + char acctent[sizeof(struct acctcsa) + + sizeof(struct acctmem) + + sizeof(struct acctio) ]; + char modacctent[sizeof(struct acctcsa) + + sizeof(struct acctmem) + + sizeof(struct acctio) ]; + struct acctcsa *csa = NULL; + struct acctmem *mem = NULL; + struct acctio *io = NULL; + struct achead *hdr1, *hdr2; + char *cb = acctent; + job_csa_t job_acctbuf; + uint64_t jid = 0; + int len = 0; + int csa_enabled = 0; + int ja_enabled = 0; + int io_enabled = 0; + int mem_enabled = 0; + int retval = 0; + uint64_t memtime; + + if (p == NULL) { + printk(KERN_ERR "do_csa_acct: CSA null task pointer\n"); + return; + } + jid = job_getjid(p); + if (jid <= 0) { + /* no job table entry; not all processes are part of a job */ + return; + } + memset(&job_acctbuf, 0, sizeof(job_acctbuf)); + retval = job_getacct(jid, JOB_ACCT_CSA, &job_acctbuf); + if (retval != 0) { + /* couldn't get accounting info stored in the job table entry */ + printk(KERN_WARNING JID_ERR1, jid); + return; + } + + down(&csa_sem); + /* + * figure out what's turned on, which determines which record types + * need to be written. All records are written to a user job + * accounting file. Only those record types configured on are + * written to the system pacct file + */ + if (job_acctbuf.job_acctfile != (struct file *)NULL) { + ja_enabled = 1; + } + if (acct_dmd[ACCT_KERN_CSA][A_SYS].ac_state == ACS_ON) { + csa_enabled = 1; + } + if (acct_rcd[ACCT_RCD_IO-ACCT_RCDS][A_SYS].ac_state == ACS_ON) { + io_enabled = 1; + } + if (acct_rcd[ACCT_RCD_MEM-ACCT_RCDS][A_SYS].ac_state == ACS_ON) { + mem_enabled = 1; + } + + if (!ja_enabled && !csa_enabled) { + /* nothing to do */ + up(&csa_sem); + return; + } + up(&csa_sem); + + csa = (struct acctcsa *)acctent; + memset(csa, 0, sizeof(struct acctcsa)); + hdr1 = &csa->ac_hdr1; + csa_header(hdr1, REV_CSA, ACCT_KERNEL_CSA, sizeof(struct acctcsa) ); + hdr2 = &csa->ac_hdr2; + csa_header(hdr2, REV_CSA, ACCT_KERNEL_CSA, 0 ); + hdr2->ah_magic = ~ACCT_MAGIC; + + csa->ac_stat = exitcode; + csa->ac_uid = p->uid; + csa->ac_gid = p->gid; + + /* XXX change this when array session handle info available */ + csa->ac_ash = 0; + csa->ac_jid = job_acctbuf.job_id; + /* XXX change this when project ids are available */ + csa->ac_prid = 0; + csa->ac_nice = task_nice(p); + csa->ac_sched = p->policy; + + csa->ac_pid = p->pid; + csa->ac_ppid = (p->p_pptr) ? p->p_pptr->pid : 0; + if (p->flags & PF_FORKNOEXEC) { + csa->ac_hdr1.ah_flag |= AFORK; + } + if (p->flags & PF_SUPERPRIV) { + csa->ac_hdr1.ah_flag |= ASU; + } + if (p->flags & PF_DUMPCORE) { + csa->ac_hdr1.ah_flag |= ACORE; + } + if (p->flags & PF_SIGNALED) { + csa->ac_hdr1.ah_flag |= AXSIG; + } + csa->ac_hdr1.ah_flag &= ~ACKPT; + + strncpy(csa->ac_comm, p->comm, sizeof(csa->ac_comm)); + csa->ac_btime = CT_TO_SECS(p->start_time) + (xtime.tv_sec - + (jiffies / HZ)); + /* + * cpu usage is accumulated by the kernel in ticks. + * convert from clock ticks to microseconds; each process gets + * a minimum of a tick for elapsed time. If the granularity + * changes to something finer than a tick in the future, + * then these zero cpu and elapsed time modifications should be + * looked at again. + */ + csa->ac_etime = (jiffies - p->start_time == 0) ? (USEC_PER_TICK) : + ((uint64_t)(jiffies - p->start_time) * USEC_PER_TICK); + + cb += sizeof(struct acctcsa); + len += sizeof(struct acctcsa); + + /* convert from ticks to microseconds */ + csa->ac_utime = p->times.tms_utime * USEC_PER_TICK; + csa->ac_stime = p->times.tms_stime * USEC_PER_TICK; + /* Each process gets a minimum of a half tick cpu time */ + if ((csa->ac_utime == 0) && (csa->ac_stime == 0)) { + csa->ac_stime = USEC_PER_TICK/2; + } + + /* Create the memory record if needed */ + if (ja_enabled || mem_enabled) { + mem = (struct acctmem *)cb; + memset(mem, 0, sizeof(struct acctmem)); + hdr1->ah_flag |= AMORE; + hdr2->ah_type |= ACCT_MEM; + hdr1 = &mem->ac_hdr; + csa_header(hdr1, REV_MEM, ACCT_KERNEL_MEM, + sizeof(struct acctmem) ); + + /* adjust from pages/ticks to Mb/usec */ + memtime = sc_CLK((long int)p->csa_rss_mem1); + mem->ac_core.mem1 = ctob(memtime) / (1024 * 1024); + memtime = sc_CLK((long int)p->csa_vm_mem1); + mem->ac_virt.mem1 = ctob(memtime) / (1024 * 1024); + + /* adjust page size to 1K units */ + if (p->mm) { + mem->ac_virt.himem = p->mm->hiwater_vm * (PAGE_SIZE / 1024); + mem->ac_core.himem = p->mm->hiwater_rss * (PAGE_SIZE/1024); + /* + * For processes with zero systime, set the integral + * to the highwater mark rather than leave at zero + */ + if (mem->ac_core.mem1 == 0) { + mem->ac_core.mem1 = mem->ac_core.himem / 1024; + } + if (mem->ac_virt.mem1 == 0) { + mem->ac_virt.mem1 = mem->ac_virt.himem / 1024; + } + } + + mem->ac_pgswap = p->nswap; + mem->ac_minflt = p->min_flt; + mem->ac_majflt = p->maj_flt; + + cb += sizeof(struct acctmem); + hdr2->ah_size += sizeof(struct acctmem); + len += sizeof(struct acctmem); + } + /* Create the I/O record */ + if (ja_enabled || io_enabled) { + io = (struct acctio *)cb; + memset(io, 0, sizeof(struct acctio)); + hdr1->ah_flag |= AMORE; + hdr2->ah_type |= ACCT_IO; + hdr1 = &io->ac_hdr; + csa_header(hdr1, REV_IO, ACCT_KERNEL_IO, + sizeof(struct acctio) ); + + /* convert from ticks to microseconds */ + /* XXX when able to do kernel 64 bit divide, change type */ + io->ac_bwtime = CT_TO_USECS((unsigned long int)p->bwtime); + + io->ac_bkr = p->rblk; + io->ac_bkw = p->wblk; + + /* raw wait time; currently not used */ + io->ac_rwtime = 0; + + io->ac_chr = p->rchar; + io->ac_chw = p->wchar; + io->ac_scr = p->syscr; + io->ac_scw = p->syscw; + + cb += sizeof(struct acctio); + hdr2->ah_size += sizeof(struct acctio); + len += sizeof(struct acctio); + } + + /* record always written to a user job accounting file */ + if ((len > 0) && (job_acctbuf.job_acctfile != (struct file *)NULL) ) { + csa_write((caddr_t)&acctent, ACCT_KERN_CSA, + len, jid, A_CJA, &job_acctbuf); + } + /* + * check the cpu time and virtual memory thresholds before writing + * this record to the system pacct file + */ + if ((acct_rcd[ACCT_THD_MEM-ACCT_RCDS][A_SYS].ac_state == ACS_ON) && + (ja_enabled || mem_enabled)) { + if (mem->ac_virt.himem < + acct_rcd[ACCT_THD_MEM-ACCT_RCDS][A_SYS].ac_param) { + /* don't write record to pacct */ + return; + } + } + if ((acct_rcd[ACCT_THD_TIME-ACCT_RCDS][A_SYS].ac_state == ACS_ON)) { + if ((csa->ac_utime + csa->ac_stime) < + acct_rcd[ACCT_THD_TIME-ACCT_RCDS][A_SYS].ac_param) { + /* don't write record to pacct */ + return; + } + } + + if ((len > 0) && (csa_acctvp != (struct file *)NULL) && csa_enabled ) { + if (io_enabled && mem_enabled) { + /* write out buffer as is to system pacct file */ + csa_write((caddr_t)&acctent, ACCT_KERN_CSA, + len, jid, A_SYS, &job_acctbuf); + } else { + /* only write out record types turned on */ + len = csa_modify_buf(modacctent, csa, mem, io, + io_enabled, mem_enabled); + csa_write((caddr_t)&modacctent, ACCT_KERN_CSA, + len, jid, A_SYS, &job_acctbuf); + } + } + return; +} + +/* + * Copy needed accounting records into buffer, skipping record + * types which are not enabled. May need to adjust downward + * the second header size if not both memory and io continuation + * records are written, plus adjust the second header types and + * first header flags. + */ +static int +csa_modify_buf(char *modacctent, struct acctcsa *csa, struct acctmem *mem, + struct acctio *io, int io_enabled, int mem_enabled) +{ + int size = 0; + int len = 0; + char *bufptr; + struct achead *hdr1, *hdr2; + + size = sizeof(struct acctcsa) + sizeof(struct acctmem) + + sizeof(struct acctio); + memset(modacctent, 0, size); + bufptr = modacctent; + /* + * adjust values that might not be correct anymore if all of + * the continuation records aren't written out to the pacct file + */ + hdr1 = &csa->ac_hdr1; + hdr2 = &csa->ac_hdr2; + hdr1->ah_flag &= ~AMORE; + hdr2->ah_type = ACCT_KERNEL_CSA; + hdr2->ah_size = 0; + if (mem_enabled) { + hdr1->ah_flag |= AMORE; + hdr2->ah_type |= ACCT_MEM; + hdr2->ah_size += sizeof(struct acctmem); + hdr1 = &mem->ac_hdr; + hdr1->ah_flag &= ~AMORE; + } + if (io_enabled) { + hdr1->ah_flag |= AMORE; + hdr2->ah_type |= ACCT_IO; + hdr2->ah_size += sizeof(struct acctio); + hdr1 = &io->ac_hdr; + hdr1->ah_flag &= ~AMORE; + } + memcpy(bufptr, csa, sizeof(struct acctcsa)); + bufptr += sizeof(struct acctcsa); + len += sizeof(struct acctcsa); + + if (mem_enabled) { + memcpy(bufptr, mem, sizeof(struct acctmem)); + len += sizeof(struct acctmem); + bufptr += sizeof(struct acctmem); + } + if(io_enabled) { + memcpy(bufptr, io, sizeof(struct acctio)); + len += sizeof(struct acctio); + } + + return len; +} + +/* + * Process acctctl syscall from a user request. + */ +int +do_acctctl(int req, void *act) +{ + struct actctl actctl; + struct actstat actstat; + + int daemon = 0; + int error = 0; + int err = 0; + static int flag = 010000; + int ind; + int id; + int len; + int num; + + down(&csa_sem); + if (!csa_flag) { + csa_init_acct(flag++); + } + up(&csa_sem); + + if ((req < 0) || (req >= AC_MREQ) ) { + return -EINVAL; + } + + memset(&actctl, 0, sizeof(struct actctl)); + memset(&actstat, 0, sizeof(struct actstat)); + + switch (req) { + /* + * Start specified types of accounting. + */ + case AC_START: + { + int id, ind; + struct file *newvp; + + if (!capable(CAP_SYS_PACCT) ) { + error = -EPERM; + break; + } + + if (copy_from_user(&actctl, act, sizeof(int)) ) { + error = -EFAULT; + break; + } + + num = (actctl.ac_sttnum == 0) ? 1 : actctl.ac_sttnum; + if ((num < 0) || (num > NUM_KDRCDS) ) { + error = -EINVAL; + break; + + } + + len = sizeof(struct actctl) - + sizeof(struct actstat) * NUM_KDRCDS + + sizeof(struct actstat) * num; + if (copy_from_user(&actctl, act, len)) { + error = -EFAULT; + break; + } + /* + * Verify all indexes in actstat structures specified. + */ + for(ind = 0; ind < num; ind++) { + id = actctl.ac_stat[ind].ac_ind; + if ((id < 0) || (id >= ACCT_MAXRCDS) ) { + error = -EINVAL; + break; + } + + if (id == ACCT_MAXKDS) { + error = -EINVAL; + break; + } + } + down(&csa_sem); + /* + * If an accounting file was specified, make sure + * that we can access it. + */ + if (strlen(actctl.ac_path) ) { + strncpy(new_path, actctl.ac_path, ACCT_PATH); + newvp = filp_open(new_path,O_WRONLY|O_APPEND, 0); + if (IS_ERR(newvp)) { + error = PTR_ERR(newvp); + up(&csa_sem); + break; + } else if (!S_ISREG(newvp->f_dentry->d_inode->i_mode)) { + error = -EACCES; + filp_close(newvp, NULL); + up(&csa_sem); + break; + } else if (!newvp->f_op->write) { + error = -EIO; + filp_close(newvp, NULL); + up(&csa_sem); + break; + } + if ((csa_acctvp != (struct file *)NULL) && + csa_acctvp == newvp) { + /* + * this file already being used, so ignore + * request to use this file; just continue on + */ + filp_close(newvp, NULL); + newvp = (struct file *)NULL; + } + + } else { + newvp = (struct file *)NULL; + } + /* + * If a new accounting file was specified and there's + * an old accounting file, stop writing to it. + */ + if (newvp != (struct file *)NULL) { + if (csa_acctvp != (struct file *)NULL) { + error = csa_config_write(AC_CONFCHG_FILE,NULL); + filp_close(csa_acctvp, NULL); + } else if (!csa_flag) { + csa_init_acct(flag++); + } + + strncpy(csa_path, new_path, ACCT_PATH); + down(&csa_write_sem); + csa_acctvp = newvp; + up(&csa_write_sem); + + } else { + if (csa_acctvp == (struct file *)NULL) { + error = -EINVAL; + up(&csa_sem); + break; + } + } + + /* + * Loop through each actstat block and turn ON that accounting. + */ + for(ind = 0; ind < num; ind++) { + struct actstat *stat; + + id = actctl.ac_stat[ind].ac_ind; + stat = &actctl.ac_stat[ind]; + if (id < ACCT_RCDS) { + acct_dmd[id][A_SYS].ac_state = ACS_ON; + acct_dmd[id][A_SYS].ac_param = stat->ac_param; + + stat->ac_state = acct_dmd[id][A_SYS].ac_state; + stat->ac_param = acct_dmd[id][A_SYS].ac_param; + } else { + int tid = id -ACCT_RCDS; + + acct_rcd[tid][A_SYS].ac_state = ACS_ON; + acct_rcd[tid][A_SYS].ac_param = stat->ac_param; + + stat->ac_state = acct_rcd[tid][A_SYS].ac_state; + stat->ac_param = acct_rcd[tid][A_SYS].ac_param; + } + } + + up(&csa_sem); + error = csa_config_write(AC_CONFCHG_ON, NULL); + /* + * Return the accounting states to the user. + */ + if (copy_to_user(act, &actctl, len)) { + error = -EFAULT; + break; + } + } + break; + + /* + * Stop specified types of accounting. + */ + case AC_STOP: + { + int id, ind; + + if (!capable(CAP_SYS_PACCT) ) { + error = -EPERM; + break; + } + + if (copy_from_user(&actctl, act, sizeof(int)) ) { + error = -EFAULT; + break; + } + + num = (actctl.ac_sttnum == 0) ? 1 : actctl.ac_sttnum; + if ((num <= 0) || (num > NUM_KDRCDS) ) { + error = -EINVAL; + break; + } + + len = sizeof(struct actctl) - + sizeof(struct actstat) * NUM_KDRCDS + + sizeof(struct actstat) * num; + if (copy_from_user(&actctl, act, len)) { + error = -EFAULT; + break; + } + + /* + * Verify all of the indexes in actstat structures specified. + */ + for(ind = 0; ind < num; ind++) { + id = actctl.ac_stat[ind].ac_ind; + if ((id < 0) || (id >= NUM_KDRCDS) ) { + error = -EINVAL; + break; + } + } + + /* + * Loop through each actstat block and turn off that accounting. + */ + down(&csa_sem); + /* + * Disable accounting for this entry. + */ + for(ind = 0; ind < num; ind++) { + id = actctl.ac_stat[ind].ac_ind; + if (id < ACCT_RCDS) { + acct_dmd[id][A_SYS].ac_state = ACS_OFF; + acct_dmd[id][A_SYS].ac_param = 0; + + actctl.ac_stat[ind].ac_state = + acct_dmd[id][A_SYS].ac_state; + actctl.ac_stat[ind].ac_param = 0; + } else { + int tid = id -ACCT_RCDS; + + acct_rcd[tid][A_SYS].ac_state = ACS_OFF; + acct_rcd[tid][A_SYS].ac_param = 0; + actctl.ac_stat[ind].ac_state = + acct_rcd[tid][A_SYS].ac_state; + actctl.ac_stat[ind].ac_param = + acct_rcd[tid][A_SYS].ac_param; + } + } /* end of for(ind) */ + /* + * Check the daemons to see if any are still on. + */ + for(ind = 0; ind < ACCT_MAXKDS; ind++) { + if (acct_dmd[ind][A_SYS].ac_state == ACS_ON) { + daemon += 1<= 0) && (id < ACCT_MAXKDS) ) { + actstat.ac_state = acct_dmd[id][A_SYS].ac_state; + actstat.ac_param = acct_dmd[id][A_SYS].ac_param; + + } else if ((id >= ACCT_RCDS) && (id < ACCT_MAXRCDS) ) { + int tid = id-ACCT_RCDS; + + actstat.ac_state = acct_rcd[tid][A_SYS].ac_state; + actstat.ac_param = acct_rcd[tid][A_SYS].ac_param; + + } else { + error = -EINVAL; + break; + } + if (copy_to_user(act, &actstat, sizeof(struct actstat)) ) { + error = -EFAULT; + } + } + break; + + /* + * Process daemon status function. + */ + case AC_KDSTAT: + { + if (copy_from_user(&actctl, act, sizeof(int)) ) { + error = -EFAULT; + break; + } + + num = actctl.ac_sttnum; + + if (num <= 0) { + error = EINVAL; + break; + } else if (num > NUM_KDS) { + num = NUM_KDS; + } + for(ind = 0; ind < num; ind++) { + actctl.ac_stat[ind].ac_ind = + acct_dmd[ind][A_SYS].ac_ind; + actctl.ac_stat[ind].ac_state = + acct_dmd[ind][A_SYS].ac_state; + actctl.ac_stat[ind].ac_param = + acct_dmd[ind][A_SYS].ac_param; + } /* end of for(ind) */ + actctl.ac_sttnum = num; + strncpy(actctl.ac_path, csa_path, ACCT_PATH); + + len = sizeof(struct actctl) - + sizeof(struct actstat) * NUM_KDRCDS + + sizeof(struct actstat) * num; + if (copy_to_user(act, &actctl, len)) { + error = -EFAULT; + break; + } + } + break; + + /* + * Process record status function. + */ + case AC_RCDSTAT: + { + if (copy_from_user(&actctl, act, sizeof(int)) ) { + error = -EFAULT; + break; + } + num = actctl.ac_sttnum; + + if (num <= 0) { + error = -EINVAL; + break; + } else if (num > NUM_RCDS) { + num = NUM_RCDS; + } + for(ind = 0; ind < num; ind++) { + actctl.ac_stat[ind].ac_ind = + acct_rcd[ind][A_SYS].ac_ind; + actctl.ac_stat[ind].ac_state = + acct_rcd[ind][A_SYS].ac_state; + actctl.ac_stat[ind].ac_param = + acct_rcd[ind][A_SYS].ac_param; + } + actctl.ac_sttnum = num; + strncpy(actctl.ac_path, csa_path, ACCT_PATH); + len = sizeof(struct actctl) - + sizeof(struct actstat) * NUM_KDRCDS + + sizeof(struct actstat) * num; + if (copy_to_user(act, &actctl, len)) { + error = -EFAULT; + break; + } + } + break; + + /* + * Turn user job accounting ON or OFF. + */ + case AC_JASTART: + case AC_JASTOP: + { + char localpath[ACCT_PATH]; + struct file *newvp = NULL; + struct file *oldvp; + uint64_t jid; + job_csa_t job_acctbuf; + int retval = 0; + + len = sizeof(struct actctl) - + sizeof(struct actstat) * (NUM_KDRCDS -1); + if (copy_from_user(&actctl, act, len)) { + error = -EFAULT; + break; + } + /* + * If an accounting file was specified, make sure + * that we can access it. + */ + if (strlen(actctl.ac_path)) { + strncpy(localpath, actctl.ac_path, ACCT_PATH); + newvp = filp_open(localpath,O_WRONLY|O_APPEND,0); + if (IS_ERR(newvp)) { + error = PTR_ERR(newvp); + break; + } else if (!S_ISREG(newvp->f_dentry->d_inode->i_mode)) { + error = -EACCES; + filp_close(newvp, NULL); + break; + } else if (!newvp->f_op->write) { + error = -EIO; + filp_close(newvp, NULL); + break; + } + } else if (req == AC_JASTART) { + error = -EINVAL; + break; + } + if (req == AC_JASTOP) { + newvp = (struct file *)NULL; + } + jid = job_getjid(current); + if (jid <= 0) { + /* no job table entry */ + error = -ENOENT; + break; + } + memset(&job_acctbuf, 0, sizeof(job_acctbuf)); + retval = job_getacct(jid, JOB_ACCT_CSA, &job_acctbuf); + if (retval != 0) { + /* couldn't get csa info in the job table entry */ + error = retval; + break; + } + /* Use this semaphore since csa_write() can also change this + * file pointer. + */ + down(&csa_write_sem); + if ((oldvp = job_acctbuf.job_acctfile) != (struct file *)NULL) { + /* Stop writing to the old job accounting file */ + filp_close(oldvp, NULL); + } + + /* Establish new job accounting file or stop job accounting */ + job_acctbuf.job_acctfile = newvp; + + retval = job_setacct(jid, JOB_ACCT_CSA, JOB_CSA_ACCTFILE, + &job_acctbuf); + if (retval != 0) { + /* couldn't set the new file name in the job entry */ + error = retval; + up(&csa_write_sem); + break; + } + up(&csa_write_sem); + /* Write a config record so ja has uname info */ + if (req == AC_JASTART) { + error = csa_config_write(AC_CONFCHG_ON, + job_acctbuf.job_acctfile); + } + } + break; + + /* + * Write an accounting record for a system daemon. + */ + case AC_WRACCT: + { + int len; + int retval = 0; + uint64_t jid; + job_csa_t job_acctbuf; + struct actwra actwra; + + if (!capable(CAP_SYS_PACCT) ) { + error = -EPERM; + break; + } + if (copy_from_user(&actwra, act, sizeof(struct actwra))) { + error = -EFAULT; + break; + } + /* Verify the parameters. */ + jid = actwra.ac_jid; + if (jid < 0) { + error = -EINVAL; + break; + } + + id = actwra.ac_did; + if ((id < 0) || (id >= ACCT_MAXKDS) ) { + error = -EINVAL; + break; + } + + len = actwra.ac_len; + if ((len <= 0) || (len > MAX_WRACCT) ) { + error = -EINVAL; + break; + } + + if (actwra.ac_buf == (char *)NULL) { + error = -EINVAL; + break; + } + + /* If the daemon type is on, write out the daemon buffer. */ + if ((acct_dmd[id][A_SYS].ac_state == ACS_ON) && + (csa_acctvp != (struct file *)NULL) ) { + error = csa_write(actwra.ac_buf, id, len, + jid, A_DMD, NULL); + } + + /* get the job table entry for this jid */ + memset(&job_acctbuf, 0, sizeof(job_acctbuf)); + retval = job_getacct(jid, JOB_ACCT_CSA, &job_acctbuf); + if (retval != 0) { + /* couldn't get accounting info stored in job table */ + error = retval; + break; + } + + /* maybe write out daemon record to ja user accounting file */ + if (job_acctbuf.job_acctfile != NULL) { + error = csa_write(actwra.ac_buf, id, len, jid, A_CJA, + &job_acctbuf); + } + } + break; + + /* + * Return authorized state information. + */ + case AC_AUTH: + { + if (!capable(CAP_SYS_PACCT) ) { + error = -EPERM; + break; + } + /* + * Process user authorization request...If we get to this spot, + * the user is authorized. + */ + } + break; + + /* + * Process the incremental accounting request. + */ + case AC_INCACCT: + error = -EINVAL; + break; + + default: + error = -EINVAL; + + } /* end of switch(req) */ + + return(error ? error : err); +} + + +/* + * Create a configuration change accounting record. + */ +static void +csa_config_make(ac_eventtype event, struct acctcfg *cfg) +{ + int daemon = 0; + int record = 0; + int ind; + int nmsize = 0; + + memset(cfg, 0, sizeof(struct acctcfg)); + /* Setup the record and header. */ + csa_header(&cfg->ac_hdr, REV_CFG, ACCT_KERNEL_CFG, + sizeof(struct acctcfg) ); + cfg->ac_event = event; + if (!boottime) { + boottime = xtime.tv_sec - (jiffies / HZ); + } + cfg->ac_boottime = boottime; + cfg->ac_curtime = xtime.tv_sec; + + /* + * Create the masks of the types that are on. + */ + for(ind = 0; ind < ACCT_MAXKDS; ind++) { + if (acct_dmd[ind][A_SYS].ac_state == ACS_ON) { + daemon += 1<ac_kdmask = daemon; + cfg->ac_rmask = record; + + nmsize = sizeof(cfg->ac_uname.sysname); + memcpy(cfg->ac_uname.sysname, system_utsname.sysname, nmsize-1); + cfg->ac_uname.sysname[nmsize-1] = '\0'; + nmsize = sizeof(cfg->ac_uname.nodename); + memcpy(cfg->ac_uname.nodename, system_utsname.nodename, nmsize-1); + cfg->ac_uname.nodename[nmsize-1] = '\0'; + nmsize = sizeof(cfg->ac_uname.release); + memcpy(cfg->ac_uname.release, system_utsname.release, nmsize-1); + cfg->ac_uname.release[nmsize-1] = '\0'; + nmsize = sizeof(cfg->ac_uname.version); + memcpy(cfg->ac_uname.version, system_utsname.version, nmsize-1); + cfg->ac_uname.version[nmsize-1] = '\0'; + nmsize = sizeof(cfg->ac_uname.machine); + memcpy(cfg->ac_uname.machine, system_utsname.machine, nmsize-1); + cfg->ac_uname.machine[nmsize-1] = '\0'; + + return; +} + + +/* + * Create and write a configuration change accounting record. + */ +static int +csa_config_write(ac_eventtype event, struct file *job_acctfile) +{ + int error = 0; /* errno */ + struct acctcfg acctcfg; + mm_segment_t fs; + + /* write record to process accounting file. */ + csa_config_make(event, &acctcfg); + + down(&csa_write_sem); + if (csa_acctvp != (struct file *)NULL) { + fs = get_fs(); + set_fs(KERNEL_DS); + error = csa_acctvp->f_op->write(csa_acctvp, (char *)&acctcfg, + sizeof(struct acctcfg), &csa_acctvp->f_pos); + set_fs(fs); + } + if (job_acctfile != (struct file *)NULL) { + fs = get_fs(); + set_fs(KERNEL_DS); + error = job_acctfile->f_op->write(job_acctfile,(char *)&acctcfg, + sizeof(struct acctcfg), &job_acctfile->f_pos); + set_fs(fs); + } + if (error >= 0) { + error = 0; + } + up(&csa_write_sem); + return(error); +} + + + +/* + * When first process in a job is created. + */ +int +csa_jstart(int event, void *data) +{ + job_csa_t *job_sojbuf = (job_csa_t *)data; + struct acctsoj acctsoj; /* start of job record */ + + /* Are we doing any accounting? */ + if (csa_acctvp == (struct file *)NULL) { + return 0; + } + + if (!job_sojbuf) { + /* bad pointer */ + printk(KERN_ERR + "csa_jstart: Received bad soj pointer, pid %d.\n", + current->pid); + return -1; + } + + memset(&acctsoj, 0, sizeof(struct acctsoj)); + csa_header(&acctsoj.ac_hdr, REV_SOJ, ACCT_KERNEL_SOJ, + sizeof(struct acctsoj)); + acctsoj.ac_jid = job_sojbuf->job_id; + acctsoj.ac_uid = job_sojbuf->job_uid; + if (event == JOB_EVENT_START) { + acctsoj.ac_type = AC_SOJ; + acctsoj.ac_btime = CT_TO_SECS(job_sojbuf->job_start) + + (xtime.tv_sec - (jiffies / HZ) ); + } else if (event == JOB_EVENT_RESTART) { + acctsoj.ac_type = AC_ROJ; + acctsoj.ac_rstime = CT_TO_SECS(job_sojbuf->job_start) + + (xtime.tv_sec - (jiffies / HZ) ); + } else { + return -1; + } + + /* + * Write the accounting record to the process accounting + * file if any accounting is enabled. + */ + if (csa_acctvp != (struct file *)NULL) { + (void)csa_write((caddr_t)&acctsoj, ACCT_KERN_CSA, + sizeof(acctsoj), job_sojbuf->job_id, A_SYS, job_sojbuf); + } + + return 0; +} + +/* + * When last process in a job is done, write an EOJ record + */ +int +csa_jexit(int event, void *data) +{ + struct achead *hdr1, *hdr2; + struct accteoj eoj; /* end of job record */ + job_csa_t *job_eojbuf = (job_csa_t *)data; + + /* Are we doing any accounting? */ + if (csa_acctvp == (struct file *)NULL) { + return 0; + } + + if (!job_eojbuf) { + /* bad pointer */ + printk(KERN_ERR + "csa_jexit: Received bad eoj pointer, pid %d.\n", + current->pid); + return -1; + } + + memset(&eoj, 0, sizeof(struct accteoj)); + + /* Set up record. */ + hdr1 = &eoj.ac_hdr1; + csa_header(hdr1, REV_EOJ, ACCT_KERNEL_EOJ, sizeof(struct accteoj) ); + hdr2 = &eoj.ac_hdr2; + csa_header(hdr2, REV_EOJ, ACCT_KERNEL_EOJ, 0 ); + hdr2->ah_magic = ~ACCT_MAGIC; + + eoj.ac_nice = task_nice(current); + eoj.ac_uid = job_eojbuf->job_uid; + eoj.ac_gid = current->gid; + + eoj.ac_jid = job_eojbuf->job_id; + + eoj.ac_btime = CT_TO_SECS(job_eojbuf->job_start) + + (xtime.tv_sec - (jiffies / HZ) ); + eoj.ac_etime = xtime.tv_sec; + + /* + * XXX Once we have real values in these two fields, convert them + * to Kbytes. + */ + eoj.ac_corehimem = job_eojbuf->job_corehimem; + eoj.ac_virthimem = job_eojbuf->job_virthimem; + + /* + * Write the accounting record to the process accounting + * file if job accounting is enabled. + */ + if (csa_acctvp != (struct file *)NULL) { + (void) csa_write((caddr_t)&eoj, ACCT_KERN_CSA, + sizeof(struct accteoj), job_eojbuf->job_id, A_SYS, + job_eojbuf); + } + + return 0; +} + +/* + * Write buf out to the accounting file. + * If an error occurs, return the error code to the caller + */ +int +csa_write(char *buf, int did, int nbyte, uint64_t jid, int type, + job_csa_t *jp) +{ + int error = 0; /* errno */ + int retval = 0; + struct file *vp; /* acct file */ + mm_segment_t fs; + unsigned long limit; + + down(&csa_write_sem); + /* Locate the accounting type. */ + switch (type) { + case A_SYS: + case A_DMD: + vp = csa_acctvp; + break; + + case A_CJA: + if (jp != (job_csa_t *)NULL) { + vp = jp->job_acctfile; + } else { + vp = (struct file *)NULL; + } + break; + + default: + up(&csa_write_sem); + return -EINVAL; + + } /* end of switch(type) */ + + /* Check if this type of accounting is turned on. */ + if (vp == (struct file *)NULL) { + up(&csa_write_sem); + return 0; + } + fs = get_fs(); + set_fs(KERNEL_DS); + + /* make sure we don't get hit by a process file size limit */ + limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + error = vp->f_op->write(vp,buf, nbyte, &vp->f_pos); + current->rlim[RLIMIT_FSIZE].rlim_cur = limit; + + set_fs(fs); + if (error >= 0) { + error = 0; + } + /* If an error occurred, disable this type of accounting. */ + if (error) { + switch(type) { + + case A_SYS: + case A_DMD: + csa_acctvp = (struct file *)NULL; + acct_dmd[did][A_SYS].ac_state = ACS_ERROFF; + acct_dmd[ACCT_KERN_CSA][A_SYS].ac_state = ACS_ERROFF; + printk(KERN_ALERT + "csa accounting pacct write error %d; %s disabled\n", + error, acct_dmd_name[did]); + filp_close(vp, NULL); + break; + case A_CJA: + jp->job_acctfile = (struct file *)NULL; + retval = job_setacct(jid, JOB_ACCT_CSA, + JOB_CSA_ACCTFILE, jp); + printk(KERN_WARNING JID_ERR2, error, jid); + if (retval != 0) { + printk(KERN_WARNING JID_ERR3, jid); + } else { + printk(KERN_WARNING JID_ERR4, jid); + } + filp_close(vp, NULL); + break; + } + up(&csa_write_sem); + return(error); + } + up(&csa_write_sem); + return(error); +} + +module_init(init_csa); +module_exit(cleanup_csa); diff -Nur linux-2.4.19/drivers/misc/dbgtk.c linux-2.4.19-sgi211r3/drivers/misc/dbgtk.c --- linux-2.4.19/drivers/misc/dbgtk.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/misc/dbgtk.c Tue Jan 14 04:50:17 2003 @@ -0,0 +1,1439 @@ +/* + * + * + * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* directory under /proc where our entries are rooted */ +static struct proc_dir_entry *dbgtk_root_proc_dir; + + +LIST_HEAD(dbgtk_groups_list); +LIST_HEAD(dbgtk_dprintk_list); +LIST_HEAD(dbgtk_dtrace_list); +LIST_HEAD(dbgtk_dcount_list); + + +static spinlock_t dbgtk_reg_lock = SPIN_LOCK_UNLOCKED; + + +/*********************************************************************** + * Forward Declarations. + * + **********************************************************************/ + + +static int __init dbgtk_init(void); +static void __exit dbgtk_exit(void); + +void dbgtk_dprintk_reg(struct dbgtk_dprintk_s *, void *, unsigned long, + unsigned long, unsigned long); +void dbgtk_dprintk_unreg(struct dbgtk_dprintk_s *); +void dbgtk_dprintk_record(struct dbgtk_dprintk_s *, u64, const char *, + int, const char *, const char *, ...); + +void dbgtk_dtrace_reg(struct dbgtk_dtrace_s *, void *, unsigned long); +void dbgtk_dtrace_unreg(struct dbgtk_dtrace_s *); +void dbgtk_record_short(struct dbgtk_dtrace_s *, char *, u64, u64, u64); +void dbgtk_record_long(struct dbgtk_dtrace_s *, char *, u64, u64, u64, + u64, u64, u64, u64); +static int dbgtk_read_trace(char *, char **, off_t, int, int *, void *); +static u64 dbgtk_trace_max_time(int, int, struct dbgtk_trace_head_s **); +static struct dbgtk_trace_rec_s *dbgtk_trace_cur_rec(struct + dbgtk_trace_head_s *); +static int dbgtk_trace_format(struct dbgtk_trace_rec_s *, int, char *); +static void dbgtk_trace_reset(struct dbgtk_dtrace_s *); + +void dbgtk_dcounter_reg(struct dbgtk_dcounter_s *, void *); +void dbgtk_dcounter_unreg(struct dbgtk_dcounter_s *); +static int dbgtk_read_dcount(char *, char **, off_t, int, int *, void *); +static int dbgtk_write_dcount(struct file *, const char *, u64, void *); + +static int dbgtk_read_mask(char *, char **, off_t, int, int *, void *); +static int dbgtk_write_mask(struct file *, const char *, u64, void *); + +static struct dbgtk_group_s *dbgtk_create_log_group(char *); +static void dbgtk_remove_log_group(struct dbgtk_group_s *); +static long dbgtk_atol(register char *); + +#ifdef CONFIG_KDB +static int dbgtk_kdb_dprintk(int, const char **, const char **, + struct pt_regs *); +static int dbgtk_kdb_dprintk_clear(int, const char **, const char **, + struct pt_regs *); +static int dbgtk_kdb_dtrace(int, const char **, const char **, + struct pt_regs *); +static int dbgtk_kdb_dcount(int, const char **, const char **, + struct pt_regs *); +#endif + + +/*********************************************************************** + * Module load/unload. + * + **********************************************************************/ + + +static int __init +dbgtk_init(void) +{ + dbgtk_root_proc_dir = proc_mkdir(DBGTK_PROC_ROOT, NULL); + if (dbgtk_root_proc_dir == NULL) { + return -EBUSY; + } + dbgtk_root_proc_dir->owner = THIS_MODULE; + + +#ifdef CONFIG_KDB + kdb_register("dprintk", dbgtk_kdb_dprintk, "[ ]", + "Dump dprintk's history", 0); + kdb_register("dprintk_clear", dbgtk_kdb_dprintk_clear, + "", "Dump dprintk's history", 0); + kdb_register("dtrace", dbgtk_kdb_dtrace, "[ [ | * ]]", + "Dump trace name's (tn) buffers", 0); + kdb_register("dcount", dbgtk_kdb_dcount, "[counter]", + "Dump counter value", 0); +#endif /* CONFIG_KDB */ + return 0; +} + + +static void __exit +dbgtk_exit(void) +{ + if (dbgtk_root_proc_dir != NULL) { + remove_proc_entry(DBGTK_PROC_ROOT, NULL); + } + + +#ifdef CONFIG_KDB + kdb_unregister("dprintk"); + kdb_unregister("dprintk_clear"); + kdb_unregister("dtrace"); + kdb_unregister("dcount"); +#endif /* CONFIG_KDB */ +} + + +module_init(dbgtk_init); +module_exit(dbgtk_exit); + + +/*********************************************************************** + * DPRINTK related functions. + * + **********************************************************************/ + + +/* + * Initialize the DPRINTK control block. + */ +void +dbgtk_dprintk_reg(struct dbgtk_dprintk_s *dp_cb, void *user_module, + unsigned long bufs_requested, + unsigned long default_csets, unsigned long default_psets) +{ + struct proc_dir_entry *pe; + int bufs; + struct dbgtk_dprintk_rec_s *buf; + unsigned long sl_flags; + + + spin_lock(&dbgtk_reg_lock); + + dp_cb->capture_sets = default_csets; + dp_cb->console_sets = default_psets; + dp_cb->buffer_sets = default_psets; + + INIT_LIST_HEAD(&dp_cb->msg_hist); + INIT_LIST_HEAD(&dp_cb->free_msgs); + spin_lock_init(&dp_cb->msg_lock); + + + list_add(&dp_cb->dprintk_list, &dbgtk_dprintk_list); + + + /* fill the free list with available buffers */ + for (bufs = 0; bufs < bufs_requested; bufs++) { + buf = + kmalloc(sizeof(struct dbgtk_dprintk_rec_s), + GFP_KERNEL); + if (buf == NULL) { + break; + } + memset(buf, 0, sizeof(struct dbgtk_dprintk_rec_s)); + spin_lock_irqsave(&dp_cb->msg_lock, sl_flags); + list_add(&buf->attached_list, &dp_cb->free_msgs); + spin_unlock_irqrestore(&dp_cb->msg_lock, sl_flags); + } + + dp_cb->group = dbgtk_create_log_group(dp_cb->proc_dir); + if ((dp_cb->group == NULL) || (dp_cb->group->proc_base == NULL)) { + spin_unlock(&dbgtk_reg_lock); + return; + } + + pe = proc_mkdir(DBGTK_DPRINTK_DIR, dp_cb->group->proc_base); + dp_cb->proc_dprintk_base = pe; + + if (pe == NULL) { + spin_unlock(&dbgtk_reg_lock); + return; + } + + pe = create_proc_entry(DBGTK_DPRINTK_CONSOLE_SETS_FILE, 0644, + dp_cb->proc_dprintk_base); + dp_cb->proc_dprintk_console_sets = pe; + + /* configure the read/write handlers, etc. */ + if (pe) { + pe->data = &dp_cb->console_sets; + pe->read_proc = dbgtk_read_mask; + pe->write_proc = dbgtk_write_mask; + pe->owner = user_module; + } + + pe = create_proc_entry(DBGTK_DPRINTK_BUFFER_SETS_FILE, 0644, + dp_cb->proc_dprintk_base); + dp_cb->proc_dprintk_buffer_sets = pe; + + /* configure the read/write handlers, etc. */ + if (pe) { + pe->data = &dp_cb->buffer_sets; + pe->read_proc = dbgtk_read_mask; + pe->write_proc = dbgtk_write_mask; + pe->owner = user_module; + } + + pe = create_proc_entry(DBGTK_DPRINTK_CAPTURE_SETS_FILE, 0644, + dp_cb->proc_dprintk_base); + dp_cb->proc_dprintk_capture_sets = pe; + + /* configure the read/write handlers, etc. */ + if (pe) { + pe->data = &dp_cb->capture_sets; + pe->read_proc = dbgtk_read_mask; + pe->write_proc = dbgtk_write_mask; + pe->owner = user_module; + } + spin_unlock(&dbgtk_reg_lock); +} + +void +dbgtk_dprintk_unreg(struct dbgtk_dprintk_s *dp_cb) +{ + struct dbgtk_dprintk_rec_s *buf; + + + spin_lock(&dbgtk_reg_lock); + + list_del(&dp_cb->dprintk_list); + + + while (!list_empty(&dp_cb->free_msgs)) { + buf = list_entry(dp_cb->free_msgs.prev, + struct dbgtk_dprintk_rec_s, + attached_list); + list_del(&buf->attached_list); + kfree(buf); + } + while (!list_empty(&dp_cb->msg_hist)) { + buf = list_entry(dp_cb->msg_hist.prev, + struct dbgtk_dprintk_rec_s, + attached_list); + list_del(&buf->attached_list); + kfree(buf); + } + + + if (dp_cb->proc_dprintk_capture_sets != NULL) { + remove_proc_entry(DBGTK_DPRINTK_CAPTURE_SETS_FILE, + dp_cb->proc_dprintk_base); + dp_cb->proc_dprintk_capture_sets = NULL; + } + if (dp_cb->proc_dprintk_buffer_sets != NULL) { + remove_proc_entry(DBGTK_DPRINTK_BUFFER_SETS_FILE, + dp_cb->proc_dprintk_base); + dp_cb->proc_dprintk_buffer_sets = NULL; + } + if (dp_cb->proc_dprintk_console_sets != NULL) { + remove_proc_entry(DBGTK_DPRINTK_CONSOLE_SETS_FILE, + dp_cb->proc_dprintk_base); + dp_cb->proc_dprintk_console_sets = NULL; + } + if (dp_cb->proc_dprintk_base != NULL) { + remove_proc_entry(DBGTK_DPRINTK_DIR, + dp_cb->group->proc_base); + dp_cb->proc_dprintk_base = NULL; + } + dbgtk_remove_log_group(dp_cb->group); + + spin_unlock(&dbgtk_reg_lock); +} + + +void +dbgtk_dprintk_record(struct dbgtk_dprintk_s *dp_cb, u64 sets, + const char *file, int line, const char *func, + const char *fmt, ...) +{ + va_list args; + struct dbgtk_dprintk_rec_s *buf; + unsigned long sl_flags; + char *last_char; + + + spin_lock_irqsave(&dp_cb->msg_lock, sl_flags); + if (!list_empty(&dp_cb->free_msgs)) { + buf = list_entry(dp_cb->free_msgs.prev, + struct dbgtk_dprintk_rec_s, + attached_list); + list_del(&buf->attached_list); + } else { + if (!list_empty(&dp_cb->msg_hist)) { + buf = list_entry(dp_cb->msg_hist.prev, + struct dbgtk_dprintk_rec_s, + attached_list); + list_del(&buf->attached_list); + } else { + return; + } + } + spin_unlock_irqrestore(&dp_cb->msg_lock, sl_flags); + + + buf->member_of_sets = sets; + + + va_start(args, fmt); + vsnprintf(buf->message, sizeof(buf->message), fmt, args); + va_end(args); + last_char = &buf->message[strlen(buf->message) - 1]; + if (*last_char == '\n') { + *last_char = '\0'; + } + + do_gettimeofday(&buf->rec_time); + strncpy(buf->file, file, sizeof(buf->file)); + strncpy(buf->func, func, sizeof(buf->func)); + buf->line = line; + buf->pid = current->pid; + + spin_lock_irqsave(&dp_cb->msg_lock, sl_flags); + list_add(&buf->attached_list, &dp_cb->msg_hist); + spin_unlock_irqrestore(&dp_cb->msg_lock, sl_flags); + + if (dp_cb->console_sets & sets) { + printk("%s\n", buf->message); + } +} + + +/*********************************************************************** + * DTRACE related functions. + * + **********************************************************************/ + + +void +dbgtk_dtrace_reg(struct dbgtk_dtrace_s *dt_cb, + void *user_module, unsigned long default_mask) +{ + struct proc_dir_entry *pe; + + + spin_lock(&dbgtk_reg_lock); + + dt_cb->trace_mask = default_mask; + + list_add(&dt_cb->dtrace_list, &dbgtk_dtrace_list); + dbgtk_trace_reset(dt_cb); + + + dt_cb->group = dbgtk_create_log_group(dt_cb->proc_dir); + if ((dt_cb->group == NULL) || (dt_cb->group->proc_base == NULL)) { + spin_unlock(&dbgtk_reg_lock); + return; + } + + pe = proc_mkdir(DBGTK_DTRACE_DIR, dt_cb->group->proc_base); + dt_cb->proc_dtrace_base = pe; + if (dt_cb->proc_dtrace_base == NULL) { + spin_unlock(&dbgtk_reg_lock); + return; + } + + pe = create_proc_entry(DBGTK_DTRACE_TRACE_MASK_FILE, 0644, + dt_cb->proc_dtrace_base); + dt_cb->proc_dtrace_mask = pe; + + if (pe) { + pe->data = &dt_cb->trace_mask; + pe->read_proc = dbgtk_read_mask; + pe->write_proc = dbgtk_write_mask; + pe->owner = user_module; + } + + + pe = create_proc_entry(DBGTK_DTRACE_TRACE_FILE, 0644, + dt_cb->proc_dtrace_base); + dt_cb->proc_dtrace_trace = pe; + + if (pe) { + pe->data = dt_cb; + pe->read_proc = dbgtk_read_trace; + pe->write_proc = NULL; + pe->owner = user_module; + } + + spin_unlock(&dbgtk_reg_lock); +} + + +void +dbgtk_dtrace_unreg(struct dbgtk_dtrace_s *dt_cb) +{ + spin_lock(&dbgtk_reg_lock); + + list_del(&dt_cb->dtrace_list); + if (dt_cb->proc_dtrace_trace != NULL) { + remove_proc_entry(DBGTK_DTRACE_TRACE_FILE, + dt_cb->proc_dtrace_base); + dt_cb->proc_dtrace_trace = NULL; + } + if (dt_cb->proc_dtrace_mask != NULL) { + remove_proc_entry(DBGTK_DTRACE_TRACE_MASK_FILE, + dt_cb->proc_dtrace_base); + dt_cb->proc_dtrace_mask = NULL; + } + if (dt_cb->proc_dtrace_base != NULL) { + remove_proc_entry(DBGTK_DTRACE_DIR, + dt_cb->group->proc_base); + dt_cb->proc_dtrace_base = NULL; + } + dbgtk_remove_log_group(dt_cb->group); + + spin_unlock(&dbgtk_reg_lock); +} + + +void +dbgtk_record_short(struct dbgtk_dtrace_s *dt_cb, char *dmsg, + u64 p1, u64 p2, u64 time_stamp) +{ + int head_idx; + struct dbgtk_trace_head_s *head; + struct dbgtk_trace_rec_s *rec; + + + head = dt_cb->cpu_trace_bufs[smp_processor_id()]; + if (head == NULL) { + return; + } + // >>> Not using atomics operations. These cause about 18-35 + // >>> nSec slowdown over straight increment. Possibility of + // >>> losing _SOME_ records when interrupts are getting + // >>> processed. This should become worse when the kernel + // >>> becomes pre-emptible. Is it important enough to + // >>> waste the time? Should we disable/enable interrupts? + head_idx = head->head_idx++; + + head_idx = head_idx % head->max_recs; + head->rec_count++; + + rec = &head->trace_recs[head_idx]; + rec->clock = 0; + + rec->text = *(u64 *) dmsg; + + rec->v1 = p1; + rec->v2 = p2; + + rec->clock = time_stamp | DBGTK_SHORT_REC; +} + + +void +dbgtk_record_long(struct dbgtk_dtrace_s *dt_cb, char *dmsg, u64 p1, + u64 p2, u64 p3, u64 p4, u64 p5, u64 p6, u64 time_stamp) +{ + int head_idx; + struct dbgtk_trace_head_s *head; + struct dbgtk_trace_rec_s *rec; + + + head = dt_cb->cpu_trace_bufs[smp_processor_id()]; + if (head == NULL) { + return; + } + + head_idx = head->head_idx++; + + head_idx = head_idx % head->max_recs; + head->rec_count++; + + rec = &head->trace_recs[head_idx]; + rec->clock = 0; + + rec->text = *(u64 *) dmsg; + + rec->v1 = p1; + rec->v2 = p2; + rec->v3 = p3; + rec->v4 = p4; + rec->v5 = p5; + rec->v6 = p6; + + rec->clock = time_stamp; +} + + +/* + * >>> Rewrite, format, and document this steaming POS!!! + */ +static int +dbgtk_read_trace(char *page, char **start, + off_t off, int count, int *eof, void *_dt_cb) +{ + int len; + int cpu; + static u64 last_max_time; + u64 next_max_time, cur_time; + struct dbgtk_trace_head_s *cur_head; + struct dbgtk_trace_rec_s *cur_rec; + struct dbgtk_dtrace_s *dt_cb = (struct dbgtk_dtrace_s *) _dt_cb; + + + MOD_INC_USE_COUNT; + + if (!off) { + /* First time we were called. */ + len = sprintf(page, "Trace mask = 0x%lx.\n\n", + dt_cb->trace_mask); + + memcpy(dt_cb->old_trace_bufs, dt_cb->cpu_trace_bufs, + (NR_CPUS * sizeof(u64 *))); + dbgtk_trace_reset(dt_cb); + /* Just a little delay to ensure everyone is done writing. */ + schedule_timeout(1); + + + last_max_time = + dbgtk_trace_max_time(0, smp_num_cpus, + (struct dbgtk_trace_head_s **) + &dt_cb->old_trace_bufs); + } else { + len = off; + } + + while (last_max_time && (len < (off + count - 160))) { + next_max_time = 0; + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + + while (1) { + cur_head = dt_cb->old_trace_bufs[cpu]; + if (cur_head == NULL) { + cur_time = 0; + break; + } + + if (cur_head->format_count == + cur_head->rec_count) { + cur_time = 0; + break; + } + + cur_rec = dbgtk_trace_cur_rec(cur_head); + cur_time = + DBGTK_ACTUAL_CLOCK(cur_rec->clock); + if (cur_time != last_max_time) { + break; + } + + + if (len >= (off + count - 160)) { + break; + } + + len += dbgtk_trace_format(cur_rec, cpu, + &page[len]); + + cur_head->format_count++; + } + + if (next_max_time <= cur_time) { + next_max_time = cur_time; + } + } + + last_max_time = next_max_time; + } + + + if (!last_max_time) { + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (dt_cb->old_trace_bufs[cpu]) { + kfree(dt_cb->old_trace_bufs[cpu]); + dt_cb->old_trace_bufs[cpu] = NULL; + } + } + last_max_time = 0; + *eof = 1; + } else { + *eof = 0; + } + + + MOD_DEC_USE_COUNT; + + return len; +} + + +/* + * This function checks the most recent record in each of the trace + * buffers to locate the largest time. It also conditions the + * rec_count field in the buffers header and resets the format_count + * field. + */ +static u64 +dbgtk_trace_max_time(int start_cpu, int end_cpu, + struct dbgtk_trace_head_s *trace_bufs[]) +{ + int cpu; + u64 max_time, rec_time; + struct dbgtk_trace_head_s *cpu_trace_head; + struct dbgtk_trace_rec_s *cur_rec; + + + max_time = 0; + for (cpu = start_cpu; cpu < end_cpu; cpu++) { + cpu_trace_head = trace_bufs[cpu]; + + if (cpu_trace_head->rec_count > cpu_trace_head->max_recs) { + cpu_trace_head->rec_count = + cpu_trace_head->max_recs; + } + cpu_trace_head->format_count = 0; + + if (cpu_trace_head->rec_count < 1) { + continue; + } + + cur_rec = dbgtk_trace_cur_rec(cpu_trace_head); + rec_time = DBGTK_ACTUAL_CLOCK(cur_rec->clock); + + if (max_time < rec_time) { + max_time = rec_time; + } + } + return max_time; +} + + +/* + * Given a buffer head, this function locates the current record for that + * buffer. + */ +static struct dbgtk_trace_rec_s * +dbgtk_trace_cur_rec(struct dbgtk_trace_head_s *head) +{ + int cur_index; + + + cur_index = + (head->head_idx - head->format_count - 1) % head->max_recs; + if (cur_index < 0) { + cur_index += head->max_recs; + } + return &head->trace_recs[cur_index]; +} + + +/* + * Handle the formatting of both short and long records. Output is to + * the specified buffer. This allow us to use the same function for + * both the /proc read handler and the kdb handler. + */ +static int +dbgtk_trace_format(struct dbgtk_trace_rec_s *rec, int cpu, char *out_buf) +{ + char tmp_string[9]; + char clk_type; + int ret_len = 0; + + + memset(tmp_string, 0, 9); + memcpy(tmp_string, &rec->text, 8); + + if (rec->clock & DBGTK_ITC_REC) { + clk_type = 'i'; + } else { + clk_type = 'r'; + } + + ret_len = + sprintf(out_buf, "%03d%c 0x%016lx %8s 0x%016lx 0x%016lx\n", + cpu, clk_type, DBGTK_ACTUAL_CLOCK(rec->clock), + tmp_string, rec->v1, rec->v2); + + if (!(rec->clock & DBGTK_SHORT_REC)) { + ret_len += sprintf(&out_buf[ret_len], + "\t\t\t\t " + "0x%016lx 0x%016lx" + "\n\t\t\t\t " + "0x%016lx 0x%016lx\n", + rec->v3, rec->v4, rec->v5, rec->v6); + } + + return ret_len; +} + + +/* + * Allocate a trace buffer per cpu, initialize it, and add it to the + * tracebufs array very quickly. + */ +static void +dbgtk_trace_reset(struct dbgtk_dtrace_s *dt_cb) +{ + int cpu; + struct dbgtk_trace_head_s *new_bufs[NR_CPUS]; + unsigned long original_cpus_allowed; + + + original_cpus_allowed = current->cpus_allowed; + memset(new_bufs, 0, sizeof(void *) * NR_CPUS); + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + + /* migrate to desired cpu so memory is node local */ + set_cpus_allowed(current, (1UL << cpu)); + + new_bufs[cpu] = (struct dbgtk_trace_head_s *) + kmalloc(dt_cb->trace_buf_size, GFP_KERNEL); + + + if (new_bufs[cpu] == NULL) { + continue; + } + new_bufs[cpu]->head_idx = 0; + new_bufs[cpu]->rec_count = 0; + new_bufs[cpu]->max_recs = DBGTK_CPU_RECS(dt_cb); + } + + memcpy(dt_cb->cpu_trace_bufs, new_bufs, + (sizeof(void *) * NR_CPUS)); + + set_cpus_allowed(current, original_cpus_allowed); +} + + +/*********************************************************************** + * DCOUNTER related functions. + * + **********************************************************************/ + + +void +dbgtk_dcounter_reg(struct dbgtk_dcounter_s *dc_cb, void *user_module) +{ + struct proc_dir_entry *pe; + + + spin_lock(&dbgtk_reg_lock); + list_add(&dc_cb->dcount_list, &dbgtk_dcount_list); + + dc_cb->group = dbgtk_create_log_group(dc_cb->proc_dir); + if ((dc_cb->group == NULL) || (dc_cb->group->proc_base == NULL)) { + spin_unlock(&dbgtk_reg_lock); + return; + } + + + /* ensure the dcount subdir exists */ + if (dc_cb->group->proc_dcounter_base == NULL) { + atomic_set(&dc_cb->group->dcounter_use_count, 1); + + dc_cb->group->proc_dcounter_base = + proc_mkdir(DBGTK_DCOUNT_DIR, dc_cb->group->proc_base); + if (dc_cb->group->proc_dcounter_base == NULL) { + spin_unlock(&dbgtk_reg_lock); + return; + } + } else { + atomic_inc(&dc_cb->group->dcounter_use_count); + } + + pe = create_proc_entry(dc_cb->proc_name, 0644, + dc_cb->group->proc_dcounter_base); + dc_cb->proc_entry = pe; + + /* configure the read/write handlers, etc. */ + if (pe) { + pe->data = &dc_cb->counter; + pe->read_proc = dbgtk_read_dcount; + pe->write_proc = dbgtk_write_dcount; + pe->owner = user_module; + } + + spin_unlock(&dbgtk_reg_lock); +} + + +void +dbgtk_dcounter_unreg(struct dbgtk_dcounter_s *dc_cb) +{ + struct dbgtk_group_s *group; + + + spin_lock(&dbgtk_reg_lock); + + if (dc_cb->group != NULL) { + group = dc_cb->group; + + if (dc_cb->proc_entry != NULL) { + remove_proc_entry(dc_cb->proc_name, + group->proc_dcounter_base); + dc_cb->proc_entry = NULL; + } + + if (atomic_dec_return(&dc_cb->group->dcounter_use_count) == 0) { + remove_proc_entry(DBGTK_DCOUNT_DIR, + group->proc_base); + } + + list_del(&dc_cb->dcount_list); + + dbgtk_remove_log_group(dc_cb->group); + } + + spin_unlock(&dbgtk_reg_lock); +} + + +/* + * /proc read handler for dcounters. + */ +static int +dbgtk_read_dcount(char *page, char **start, + off_t off, int count, int *eof, void *_value) +{ + int len; + atomic_t *value = (atomic_t *) _value; + + + len = sprintf(page, "%d\n", atomic_read(value)); + + return len; +} + + +/* + * /proc write handler for dcounters. + */ +static int +dbgtk_write_dcount(struct file *file, + const char *buffer, u64 count, void *_value) +{ + atomic_t *value = (atomic_t *) _value; + + + /* no matter what user provided, zero the counter */ + atomic_set(value, 0); + + return count; +} + + +/*********************************************************************** + * General use functions. + * + **********************************************************************/ + + +/* + * /proc read handler for a mask value. + */ +static int +dbgtk_read_mask(char *page, char **start, + off_t off, int count, int *eof, void *_value) +{ + int len; + unsigned long *value = (unsigned long *) _value; + + + len = sprintf(page, "0x%lx\n", *value); + + return len; +} + + +/* + * /proc write handler for a mask value. + */ +static int +dbgtk_write_mask(struct file *file, + const char *buffer, u64 count, void *_value) +{ + char my_buf[32]; + int len; + unsigned long *value = (unsigned long *) _value; + + + len = ((count < 30) ? count : 30); + if (copy_from_user(my_buf, buffer, len)) { + return -EFAULT; + } + my_buf[len] = '\0'; + + *value = dbgtk_atol(my_buf); + + return len; +} + + +/* + * Check and create if needed this log groups /proc/dbgtk entry. + */ +static struct dbgtk_group_s * +dbgtk_create_log_group(char *proc_dir) +{ + struct list_head *entry; + struct dbgtk_group_s *group; + + + MOD_INC_USE_COUNT; + + /* search groups to see if this directory already exists */ + list_for_each(entry, &dbgtk_groups_list) { + group = list_entry(entry, + struct dbgtk_group_s, groups_list); + if (strcmp(group->proc_dir, proc_dir) == 0) { + /* Found our entry. Inc count and return. */ + atomic_inc(&group->base_use_count); + return group; + } + } + group = kmalloc(sizeof(struct dbgtk_group_s), GFP_KERNEL); + if (group == NULL) { + return NULL; + } + + memset(group, 0, sizeof(struct dbgtk_group_s)); + + group->proc_base = proc_mkdir(proc_dir, dbgtk_root_proc_dir); + atomic_set(&group->base_use_count, 1); + atomic_set(&group->dcounter_use_count, 0); + + strcpy(group->proc_dir, proc_dir); + list_add(&group->groups_list, &dbgtk_groups_list); + + return group; +} + + +/* + * Check and remove if unused this log groups /proc/debug entry. + */ +static void +dbgtk_remove_log_group(struct dbgtk_group_s *group) +{ + MOD_DEC_USE_COUNT; + + if (group == NULL) { + return; + } + + if (atomic_dec_return(&group->base_use_count) == 0) { + remove_proc_entry(group->proc_dir, dbgtk_root_proc_dir); + + list_del(&group->groups_list); + + kfree(group); + } +} + + +/* + * Convert ascii string to a long. + */ +#define xtod(c) ((c) <= '9' ? '0' - (c) : 'a' - (c) - 10) + +static long +dbgtk_atol(register char *p) +{ + register long n; + register int c, neg = 0; + + + if (p == NULL) + return 0; + + if (!isdigit(c = *p)) { + while (isspace(c)) + c = *++p; + switch (c) { + case '-': + neg++; + case '+': /* fall-through */ + c = *++p; + } + if (!isdigit(c)) + return 0; + } + if (c == '0' && *(p + 1) == 'x') { + p += 2; + c = *p; + n = xtod(c); + while ((c = *++p) && isxdigit(c)) { + n *= 16; /* two steps to avoid unnecessary overflow */ + n += xtod(c); /* accum neg to avoid surprises at MAX */ + } + } else { + n = '0' - c; + while ((c = *++p) && isdigit(c)) { + n *= 10; /* two steps to avoid unnecessary overflow */ + n += '0' - c; /* accum neg to avoid surprises at MAX */ + } + } + return (neg ? n : -n); +} + + +#ifdef CONFIG_KDB + + +/*********************************************************************** + * Kernel debugger related functions. + * + **********************************************************************/ + + +static int +dbgtk_kdb_dprintk(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int group_count; + struct list_head *entry; + struct dbgtk_dprintk_s *dp_cb; + struct dbgtk_dprintk_rec_s *buf; + char *sms; + u64 sets; + int recs_found, recs_printed; + int i; + + + dp_cb = NULL; + if (argc == 0) { + /* + * If the user did not specify a history, display the + * names for all historys. + */ + group_count = 0; + list_for_each(entry, &dbgtk_dprintk_list) { + dp_cb = list_entry(entry, + struct dbgtk_dprintk_s, + dprintk_list); + kdb_printf("Group %s\n", dp_cb->proc_dir); + group_count++; + } + + if (group_count != 1) { + return 0; + } + } else { + /* user specified a history */ + list_for_each(entry, &dbgtk_dprintk_list) { + dp_cb = list_entry(entry, + struct dbgtk_dprintk_s, + dprintk_list); + if (strcmp(argv[1], dp_cb->proc_dir)) { + /* they are different */ + dp_cb = NULL; + } else { + break; + } + } + } + + if (dp_cb == NULL) { + return 0; + } + + + sets = 0; + /* OR remaining paramaters into sets */ + for (i = 2; i <= argc; i++) { + sets |= dbgtk_atol((char *)argv[i]); + } + + + if (sets == 0) { + /* no sets selected yet. */ + sms = kdbgetenv("dprintk_sets_mask"); + if (sms == NULL) { + sets = dp_cb->buffer_sets; + } else { + sets = dbgtk_atol(sms); + } + } + + + for (i = 1; i <= argc; i++) { + if (strcmp(argv[i], "sets")) { + continue; + } + + kdb_printf("\n --> setenv dprintk_sets_mask=0x%lx%s\n", + sets, dp_cb->set_description); + + return 0; + } + + + recs_found = recs_printed = 0; + + + list_for_each_prev(entry, &dp_cb->msg_hist) { + buf = list_entry(entry, struct dbgtk_dprintk_rec_s, + attached_list); + + recs_found++; + if (buf->member_of_sets & sets) { + recs_printed++; + kdb_printf("%s()[%d]: %s\n", buf->func, buf->pid, + buf->message); + } + } + kdb_printf("\n --> dprintk %s printed %d of %d records.\n", + dp_cb->proc_dir, recs_printed, recs_found); + + return 0; +} + + +/* + * Handler behind the kdb dprintk_clear command. This handles the + * removing of all entries from the specified log buffer + */ +static int +dbgtk_kdb_dprintk_clear(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct dbgtk_dprintk_s *dp_cb; + struct list_head *entry; + struct dbgtk_dprintk_rec_s *buf; + + + if (argc != 1) { + return 0; + } + + dp_cb = NULL; + + list_for_each(entry, &dbgtk_dprintk_list) { + dp_cb = list_entry(entry, + struct dbgtk_dprintk_s, + dprintk_list); + if (strcmp(argv[1], dp_cb->proc_dir)) { + /* they are different */ + dp_cb = NULL; + } else { + break; + } + } + + if (dp_cb == NULL) { + kdb_printf("Did not find group %s\n", argv[1]); + return 0; + } + + /* Move the entries back to the free list */ + while (!list_empty(&dp_cb->msg_hist)) { + buf = list_entry(dp_cb->msg_hist.prev, + struct dbgtk_dprintk_rec_s, + attached_list); + list_del(&buf->attached_list); + list_add(&buf->attached_list, &dp_cb->free_msgs); + } + + return 0; +} + +/* + * Handler behind the kdb dtrace command. This handles the variants + * produced by the optional fields on the dtrace command. + */ +static int +dbgtk_kdb_dtrace(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct list_head *entry; + struct dbgtk_dtrace_s *group, *chk_group; + int group_count; + int active_cpu_count; + int cpu; + int ret; + unsigned long start_cpu, end_cpu; + struct dbgtk_trace_head_s *head; + struct dbgtk_trace_rec_s *cur_rec; + char format_buf[160]; + u64 last_max_time, next_max_time, cur_time; + + + if (argc > 2) { + return 0; + } + + group = NULL; + + if (argc == 0) { + /* + * If the user did not specify any log group, display the + * name for all log groups. + */ + group_count = 0; + list_for_each(entry, &dbgtk_dtrace_list) { + group = list_entry(entry, + struct dbgtk_dtrace_s, + dtrace_list); + kdb_printf("Group %s\n", group->proc_dir); + group_count++; + } + + + /* + * If the user did not specify a group, but there + * is only one, we might as well print that one + * now. + */ + if (group_count != 1) { + return 0; + } + } else { + /* + * If the user specified a log group, search for it. + */ + group = NULL; + + list_for_each(entry, &dbgtk_dtrace_list) { + chk_group = list_entry(entry, + struct dbgtk_dtrace_s, + dtrace_list); + + if (!strcmp(argv[1], chk_group->proc_dir)) { + group = chk_group; + break; + } + } + + if (group == NULL) { + kdb_printf("Did not find group %s\n", argv[1]); + return 0; + } + } + + + active_cpu_count = 0; + if (argc != 2) { + /* + * If cpus were not specified, just tell how many records + * each cpu has. + */ + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (group->cpu_trace_bufs[cpu]->rec_count > + ((group->trace_buf_size / DBGTK_REC_SIZE) - + 1)) { + + group->cpu_trace_bufs[cpu]->rec_count = + (group->trace_buf_size / + DBGTK_REC_SIZE) - 1; + } + + kdb_printf(" Cpu %d has %ld records\n", + cpu, + group->cpu_trace_bufs[cpu]->rec_count); + + if (group->cpu_trace_bufs[cpu]->rec_count > 0) { + start_cpu = cpu; + active_cpu_count++; + } + + } + if (active_cpu_count != 1) { + return 0; + } + } + + /* + * Determine which cpus to format for. If the user specified + * the '*', then all cpus are formatted, otherwise only a + * single is. + */ + if ((argc == 1) || (strcmp(argv[2], "*"))) { + /* + * If argc equals 1, then the loop above only found + * a single cpu that had any dtrace records and + * start_cpu is already set. + */ + if (argc != 1) { + ret = kdbgetularg(argv[2], &start_cpu); + if (ret) { + return ret; + } + } + + if ((start_cpu < 0) || (start_cpu >= smp_num_cpus)) { + return 0; + } + + head = group->cpu_trace_bufs[start_cpu]; + if (head->rec_count > head->max_recs) { + head->rec_count = head->max_recs; + } + head->format_count = 0; + + /* Go thru all records */ + while (head->rec_count > head->format_count) { + cur_rec = dbgtk_trace_cur_rec(head); + + dbgtk_trace_format(cur_rec, start_cpu, format_buf); + kdb_printf(format_buf); + + head->format_count++; + } + return 0; + } + + start_cpu = 0; + end_cpu = smp_num_cpus; + + last_max_time = dbgtk_trace_max_time(0, smp_num_cpus, + (struct dbgtk_trace_head_s **) + &group->cpu_trace_bufs); + + while (last_max_time) { + next_max_time = 0; + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + + while (1) { + head = group->cpu_trace_bufs[cpu]; + if (head->format_count == head->rec_count) { + cur_time = 0; + break; + } + + cur_rec = dbgtk_trace_cur_rec(head); + cur_time = + DBGTK_ACTUAL_CLOCK(cur_rec->clock); + + if (cur_time != last_max_time) { + break; + } + + + dbgtk_trace_format(cur_rec, cpu, + format_buf); + kdb_printf(format_buf); + + head->format_count++; + } + + if (next_max_time <= cur_time) { + next_max_time = cur_time; + } + } + + last_max_time = next_max_time; + } + return 0; +} + + +/* + * Handler behind the kdb dcount command. This handles the variants + * produced by the optional fields on the dtrace command. + */ +static int +dbgtk_kdb_dcount(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct list_head *entry; + struct dbgtk_dcounter_s *dc_cb; + + + if (argc > 1) { + return 0; + } + + list_for_each(entry, &dbgtk_dcount_list) { + dc_cb = list_entry(entry, + struct dbgtk_dcounter_s, dcount_list); + if ((argc == 0) || !strcmp(argv[1], dc_cb->proc_name)) { + kdb_printf("%s = %d\n", dc_cb->proc_name, + atomic_read(&dc_cb->counter)); + } + + } + return 0; +} + + +#endif /* CONFIG_KDB */ + + +EXPORT_SYMBOL(dbgtk_dprintk_reg); +EXPORT_SYMBOL(dbgtk_dprintk_unreg); +EXPORT_SYMBOL(dbgtk_dprintk_record); + +EXPORT_SYMBOL(dbgtk_dtrace_reg); +EXPORT_SYMBOL(dbgtk_dtrace_unreg); +EXPORT_SYMBOL(dbgtk_record_short); +EXPORT_SYMBOL(dbgtk_record_long); + +EXPORT_SYMBOL(dbgtk_dcounter_reg); +EXPORT_SYMBOL(dbgtk_dcounter_unreg); + +MODULE_LICENSE("GPL"); diff -Nur linux-2.4.19/drivers/misc/job.c linux-2.4.19-sgi211r3/drivers/misc/job.c --- linux-2.4.19/drivers/misc/job.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/misc/job.c Mon Oct 21 14:05:28 2002 @@ -0,0 +1,1963 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + * + * Description: This file, drivers/misc/job.c, implements a type + * of process grouping called jos. For further information + * about jobs, consult the file Documentation/job.txt. Jobs + * are implemented as a type of PAGG (process aggregate). + * For further information about PAGGs, consult the file + * Documentation/pagg.txt. + * + * Created: 2000.07.15 Sam Watters + * + * Changes: 2001.01.30 Sam Watters + * Change job module so that it can be compiled into + * The kernel & move file to drivers/misc/job.c + * 2001.04.15 Sam Watters + * Change to use semphores for locking. Also being + * using read/write_lock_pagg_list(task) finer grained + * locking. + * 2001.12.12 Sam Watters + * Change references to pagg_module_s to pagg_hook_s. Changed + * names of structure from paggmod to pagg_hook and updated names + * for register_pagg/unregister_pagg. Changes for move to 2.4.16. + */ + +/* + * LOCKING INFO + * + * There are currently two levels of locking in this module. So, we + * have two classes of locks: + * + * (1) job table lock (always, job_table_sem) + * (2) job entry lock (usually, job->sem) + * + * Most of the locking used is read/write sempahores. In rare cases, a + * spinlock is also used. Those cases requiring a spinlock concern when the + * tasklist_lock must be locked (such as when looping over all tasks on the + * system). + * + * There is only one job_table_sem. There is a job->sem for each job + * entry in the job_table. This job module is a PAGG module (Process + * Aggregation). Each task has a special lock that protects its PAGG + * information - this is called the pagg list lock. There are special macros + * used to lock/unlock a task's pagg list lock. The pagg list lock is really + * a semaphore. + * + * Purpose: + * + * (1) The job_table_sem protects all entries in the table. + * (2) The job->sem protects all data and task attachments for the job. + * + * Truths we hold to be self-evident: + * + * Only the holder of a write lock for the job_table_lock may add or + * delete a job entry from the job_table. The job_table includes all job + * entries in the hash table and chains off the hash table locations. + * + * Only the holder of a write lock for a job->lock may attach or detach + * processes/tasks from the attached list for the job. + * + * If you hold a read lock of job_table_lock, you can assume that the + * job entries in the table will not change. The link pointers for + * the chains of job entries will not change, the job ID (jid) value + * will not change, and data changes will be (mostly) atomic. + * + * If you hold a read lock of a job->lock, you can assume that the + * attachments to the job will not change. The link pointers for the + * attachment list will not change and the attachments will not change. + * + * If you are going to grab nested locks, the nesting order is: + * + * *_lock_pagg_list(task) * = read or write + * job_table_sem + * job->sem + * + * However, it is not strictly necessary to down the job_table_sem + * before downing job->sem. + * + * Also, the nesting order allows you to lock in this order: + * + * *_lock_pagg_list(task) + * job->sem + * + * without locking job_table_sem between the two. + * + */ + +/* standard for kernel modules */ +#include +#include +#include +#include +#include +#include + +#include /* for get_user & put_user */ + +#include /* for current */ +#include /* for the tty declarations */ +#include +#include + +#include + +#include +#include + +#include /* to use pagg hooks */ +#include +#include + +#define HASH_SIZE 1024 + +/* The states for a job */ +#define FETAL 1 /* being born, not ready for attachments yet */ +#define RUNNING 2 /* Running job */ +#define STOPPED 3 /* Stopped job */ +#define ZOMBIE 4 /* Dead job */ + +/* Job creation tags for the job HID (host ID) */ +#define DISABLED 0xffffffff /* New job creation disabled */ +#define LOCAL 0x0 /* Only creating local sys jobs */ + + +#ifdef __BIG_ENDIAN +#define iptr_hid(ll) ((uint32_t *)&(ll)) +#define iptr_sid(ll) (((uint32_t *)(&(ll) + 1)) - 1) +#else /* __LITTLE_ENDIAN */ +#define iptr_hid(ll) (((uint32_t *)(&(ll) + 1)) - 1) +#define iptr_sid(ll) ((uint32_t *)&(ll)) +#endif /* __BIG_ENDIAN */ + +#define jid_hash(ll) (*(iptr_sid(ll)) % HASH_SIZE) + + +/* Need to declare ahead the types for the job data structures */ +typedef struct job_attach_s job_attach_t; +typedef struct job_waitinfo_s job_waitinfo_t; +typedef struct job_csainfo_s job_csainfo_t; +typedef struct job_entry_s job_entry_t; + +/* Job info entry for member tasks */ +struct job_attach_s { + struct task_struct *task; /* task we are attaching to job */ + struct pagg_s *pagg; /* our pagg entry in the task */ + job_entry_t *job; /* the job we are attaching task to */ + struct list_head entry; /* list stuff */ +}; + +struct job_waitinfo_s { + int status; /* For tasks waiting on job exit */ +}; + +struct job_csainfo_s { + uint64_t corehimem; /* Accounting - highpoint, phys mem */ + uint64_t virthimem; /* Accounting - highpoint, virt mem */ + struct file *acctfile; /* The accounting file for job */ +}; + +/* Job table entry type */ +struct job_entry_s { + uint64_t jid; /* Our job ID */ + int refcnt; /* Number of tasks attached to job */ + int state; /* State of job - RUNNING,... */ + struct rw_semaphore sem; /* lock for the job */ + uid_t user; /* user that owns the job */ + time_t start; /* When the job began */ + job_csainfo_t csa; /* CSA accounting info */ + wait_queue_head_t zombie; /* queue last task - during wait */ + wait_queue_head_t wait; /* queue of tasks waiting on job */ + int waitcnt; /* Number of tasks waiting on job */ + job_waitinfo_t waitinfo; /* Status info for waiting tasks */ + struct list_head attached; /* List of attached tasks */ + struct list_head entry; /* List of other jobs - same hash */ +}; + + +/* Job container tables */ +static struct list_head job_table[HASH_SIZE]; +static int job_table_refcnt = 0; +static DECLARE_RWSEM(job_table_sem); + + +/* Accounting subscriber list */ +static job_acctmod_t *acct_list[JOB_ACCT_COUNT]; +static DECLARE_RWSEM(acct_list_sem); + + +/* Host ID for the localhost */ +static uint32_t jid_hid = DISABLED; + +static char *hid = NULL; +MODULE_PARM(hid, "s"); + +/* Function prototypes */ +int job_sys_create(job_create_t *); +int job_sys_getjid(job_getjid_t *); +int job_sys_waitjid(job_waitjid_t *); +int job_sys_killjid(job_killjid_t *); +int job_sys_getjidcnt(job_jidcnt_t *); +int job_sys_getjidlst(job_jidlst_t *); +int job_sys_getpidcnt(job_pidcnt_t *); +int job_sys_getpidlst(job_pidlst_t *); +int job_sys_getuser(job_user_t *); +int job_sys_getprimepid(job_primepid_t *); +int job_sys_sethid(job_sethid_t *); +int job_sys_detachjid(job_detachjid_t *); +int job_sys_detachpid(job_detachpid_t *); +int job_attach(struct task_struct *, struct pagg_s *, void *); +int job_detach(struct task_struct *, struct pagg_s *); +int job_paggctl(int, void *); +job_entry_t *job_getjob(uint64_t jid); +uint64_t job_getjid(struct task_struct *); + + +/* Job container kernel pagg entry */ +static struct pagg_hook_s pagg_hook = { + PAGG_JOB, + job_attach, + job_detach, + NULL, + job_paggctl, + &job_table, + THIS_MODULE, + LIST_HEAD_INIT(pagg_hook.entry) +}; + +#ifdef DEBUG + +#define DBG_PRINTINIT(s) \ + char *dbg_fname = s + +#define DBG_PRINTENTRY() \ +do { \ + printk(KERN_DEBUG "job: %s: entry\n", dbg_fname); \ +} while(0) + +#define DBG_PRINTEXIT(c) \ +do { \ + printk(KERN_DEBUG "job: %s: exit, code = %d\n", dbg_fname, c); \ +} while(0) + +/* write lock semaphore */ +#define JOB_WLOCK(l) \ +do { \ + printk(KERN_DEBUG "job: wlock = %p\n", l); \ + down_write(l); \ +} while(0); + +/* write unlock semaphore */ +#define JOB_WUNLOCK(l) \ +do { \ + printk(KERN_DEBUG "job: wunlock = %p\n", l); \ + up_write(l); \ +} while(0); + +/* read lock semaphore */ +#define JOB_RLOCK(l) \ +do { \ + printk(KERN_DEBUG "job: rlock = %p\n", l); \ + down_read(l); \ +} while(0); + +/* read unlock semaphore */ +#define JOB_RUNLOCK(l) \ +do { \ + printk(KERN_DEBUG "job: runlock = %p\n", l); \ + up_read(l); \ +} while(0); + + +#else /* #ifdef DEBUG */ + +#define DBG_PRINTINIT(s) + +#define DBG_PRINTENTRY() \ +do { \ +} while(0) + +#define DBG_PRINTEXIT(c) \ +do { \ +} while(0) + +/* write lock semaphore */ +#define JOB_WLOCK(l) \ +do { \ + down_write(l); \ +} while(0); + +/* write unlock semaphore */ +#define JOB_WUNLOCK(l) \ +do { \ + up_write(l); \ +} while(0); + +/* read lock semaphore */ +#define JOB_RLOCK(l) \ +do { \ + down_read(l); \ +} while(0); + +/* read unlock semaphore */ +#define JOB_RUNLOCK(l) \ +do { \ + up_read(l); \ +} while(0); + + +#endif /* #ifdef DEBUG */ + + + +/* + * job__getjob + * + * Given a jid value, find the entry in the job_table and return a pointer + * to the job entry or NULL if not found. + * + * You should normally JOB_RLOCK the job_table_sem before calling this + * function. + */ +job_entry_t * +job_getjob(uint64_t jid) +{ + struct list_head *entry = NULL; + job_entry_t *tjob = NULL; + job_entry_t *job = NULL; + + list_for_each(entry, &job_table[ jid_hash(jid) ]) { + tjob = list_entry(entry, job_entry_t, entry); + if (tjob->jid == jid) { + job = tjob; + break; + } + } + return job; +} + + +/* + * job_attach + * + * Attach the task to the job specified in the target data (old_data). + * This function will add the task to the list of attached tasks for the job. + * In addition, a link from the task to the job is created and added to the + * task via the data pointer reference. + * + * The process that owns the target data should be at least read locked (using + * read_lock_pagg_list(task)) during this call. This help in ensuring + * that the job cannot be removed since at least one process will + * still be referencing the job (the one owning the target_data). + * + * It is expected that this function will be called from within the + * attach_pagg_list() function in the kernel, when forking (do_fork) a child + * process represented by task. + * + * If this function is called form some other point, then it is possible that + * task and data could be altered while going through this function. In such + * a case, the caller should also lock the pagg list for the task + * task_struct. + * + * the function returns 0 upon success, and -1 upon failure. + */ +int +job_attach(struct task_struct *task, struct pagg_s *new_pagg, + void *old_data) +{ + job_entry_t *job = ((job_attach_t *)old_data)->job; + job_attach_t *attached = NULL; + int errcode = 0; + DBG_PRINTINIT("job_attach"); + + DBG_PRINTENTRY(); + + /* + * Lock the job for writing. The task owning target_data has its + * pagg_list locked, so we know there is at least one active reference + * to the job - therefore, it cannot have been removed before we + * have gotten this write lock established. + */ + JOB_WLOCK(&job->sem); + + if (job->state == ZOMBIE) { + /* If the job is a zombie (dying), bail out of the attach */ + printk(KERN_WARNING "Attach task(pid=%d) to job" + " failed - job is ZOMBIE\n", + task->pid); + errcode = -EINPROGRESS; + JOB_WUNLOCK(&job->sem); + goto error_return; + } + + + /* Allocate memory that we will need */ + + attached = (job_attach_t *)kmalloc(sizeof(job_attach_t *), + GFP_KERNEL); + if (!attached) { + /* error */ + printk(KERN_ERR "Attach task(pid=%d) to job" + " failed on memory error in kernel\n", + task->pid); + errcode = -ENOMEM; + goto error_return; + } + + + attached->task = task; + attached->pagg = new_pagg; + attached->job = job; + new_pagg->data = (void *)attached; + list_add_tail(&attached->entry, &job->attached); + ++job->refcnt; + + JOB_WUNLOCK(&job->sem); + + DBG_PRINTEXIT(0); + return 0; + +error_return: + DBG_PRINTEXIT(errcode); + if (attached) kfree(attached); + return errcode; +} + + +/* + * job_detach + * + * Detach the task from the job attached to via the pagg reference. + * This function will remove the task from the list of attached tasks for the + * job specified via the pagg pointer. In addition, the link to the job + * provided via the data pointer will also be removed. + * + * The pagg_list should be write locked for task before entering + * this function (using write_lock_pagg_list(task)). + * + * the function returns 0 uopn success, and -1 uopn failure. + */ +int +job_detach(struct task_struct *task, struct pagg_s *pagg) +{ + job_attach_t *attached = ((job_attach_t *)(pagg->data)); + job_entry_t *job = attached->job; + DBG_PRINTINIT("job_detach"); + + DBG_PRINTENTRY(); + + /* + * Obtain the lock on the the job_table_sem and the job->sem for + * this job. + */ + JOB_WLOCK(&job_table_sem); + JOB_WLOCK(&job->sem); + + job->refcnt--; + list_del(&attached->entry); + pagg->data = NULL; + kfree(attached); + + if (job->refcnt == 0) { + int waitcnt; + + list_del(&job->entry); + --job_table_refcnt; + + /* + * The job is removed from the job_table. + * We can remove the job_table_sem now since + * nobody can access the job via the table. + */ + JOB_WUNLOCK(&job_table_sem); + + job->state = ZOMBIE; + job->waitinfo.status = task->exit_code; + + waitcnt = job->waitcnt; + + /* + * Release the job semaphore. You cannot hold + * this lock if you want the wakeup to work + * properly. + */ + JOB_WUNLOCK(&job->sem); + + if (waitcnt > 0) { + wake_up_interruptible(&job->wait); + wait_event(job->zombie, job->waitcnt == 0); + } + + /* + * Job is exiting, all processes waiting for job to exit + * have been notified. Now we call the accounting + * subscribers. + */ + + /* - CSA accounting */ + if (acct_list[JOB_ACCT_CSA]) { + job_acctmod_t *acct = acct_list[JOB_ACCT_CSA]; + if (acct->module) + __MOD_INC_USE_COUNT(acct->module); + if (acct->do_jobend) { + int res = 0; + job_csa_t csa; + + csa.job_id = job->jid; + csa.job_uid = job->user; + csa.job_start = job->start; + csa.job_corehimem = job->csa.corehimem; + csa.job_virthimem = job->csa.virthimem; + csa.job_acctfile = job->csa.acctfile; + + res = acct->do_jobend(JOB_EVENT_END, + &csa); + if (res) { + printk(KERN_WARNING + "job_detach: CSA -" + " do_jobend failed.\n"); + } + } + if (acct->module) + __MOD_DEC_USE_COUNT(acct->module); + } else { + printk(KERN_WARNING "job_detach: CSA - attempt" + "to lock CSA modulefailed.\n"); + } + + + /* + * Every process attached or waiting on this job should be + * detached and finished waiting, so now we can free the + * memory for the job. + */ + kfree(job); + MOD_DEC_USE_COUNT; + + } else { + /* This is case where job->refcnt was greater than 1, so + * we were not going to delete the job after the detach. + * Therefore, only the job->sem is being held - the + * job_table_sem was released earlier. + */ + JOB_WUNLOCK(&job->sem); + JOB_WUNLOCK(&job_table_sem); + } + + DBG_PRINTEXIT(0); + + return 0; +} + +/* + * job_paggctl + * + * Function to handle paggctl system call requests. + * + * Returns 0 on success and -(ERRNO VALUE) upon failure. + */ +int +job_paggctl(int request, void *data) +{ + DBG_PRINTINIT("job_paggctl"); + + DBG_PRINTENTRY(); + + switch (request) { + case JOB_CREATE: + return job_sys_create((job_create_t *)data); + break; + case JOB_ATTACH: + case JOB_DETACH: + /* RESERVED */ + return -EBADRQC; + break; + case JOB_GETJID: + return job_sys_getjid((job_getjid_t *)data); + break; + case JOB_WAITJID: + return job_sys_waitjid((job_waitjid_t *)data); + break; + case JOB_KILLJID: + return job_sys_killjid((job_killjid_t *)data); + break; + case JOB_GETJIDCNT: + return job_sys_getjidcnt((job_jidcnt_t *)data); + break; + case JOB_GETJIDLST: + return job_sys_getjidlst((job_jidlst_t *)data); + break; + case JOB_GETPIDCNT: + return job_sys_getpidcnt((job_pidcnt_t *)data); + break; + case JOB_GETPIDLST: + return job_sys_getpidlst((job_pidlst_t *)data); + break; + case JOB_GETUSER: + return job_sys_getuser((job_user_t *)data); + break; + case JOB_GETPRIMEPID: + return job_sys_getprimepid((job_primepid_t *)data); + break; + case JOB_SETHID: + return job_sys_sethid((job_sethid_t *)data); + break; + case JOB_DETACHJID: + return job_sys_detachjid((job_detachjid_t *)data); + break; + case JOB_DETACHPID: + return job_sys_detachpid((job_detachpid_t *)data); + break; + case JOB_SETJLIMIT: + case JOB_GETJLIMIT: + case JOB_GETJUSAGE: + case JOB_FREE: + default: + /* For future enhancment */ + DBG_PRINTEXIT(-EBADRQC); + return -EBADRQC; + break; + } + + DBG_PRINTEXIT(0); + return 0; +} + + +/* + * job_sys_create + * + * This function is used to create a new job and attache the calling process + * to that new job. + * + * Returns 0 on success, and negative on failure (negative errno value). + */ +int +job_sys_create(job_create_t *create_args) +{ + job_create_t create; + job_entry_t *job = NULL; + job_attach_t *attached = NULL; + struct pagg_s *pagg = NULL; + int errcode = 0; + DBG_PRINTINIT("job_sys_create"); + + DBG_PRINTENTRY(); + + /* We are creating an new job. Increment the module use + * count to reflect that we have another user of the module + * (the new job container). If we have an error when creating + * the new job, this count will be decremented - since no new + * job will have been created. + */ + MOD_INC_USE_COUNT; + + /* + * if the job ID - host ID segment is set to DISABLED, we will + * not be creating new jobs. We don't mark it as an error, but + * the jid value returned will be 0. + */ + if (jid_hid == DISABLED) { + errcode = 0; + goto error_return; + } + + +#if 0 /* XXX - Use if capable is not present */ + if (current->euid != 0) + return -EPERM; +#else + if (!capable(CAP_SYS_RESOURCE)) { + errcode = -EPERM; + goto error_return; + } +#endif + if (!create_args) { + errcode = -EINVAL; + goto error_return; + } + + if (copy_from_user(&create, create_args, sizeof(create))) { + errcode = -EFAULT; + goto error_return; + } + + /* + * Allocate some of the memory we might need, before we start + * locking + */ + + attached = (job_attach_t *)kmalloc(sizeof(job_attach_t), GFP_KERNEL); + if (!attached) { + /* error */ + errcode = -ENOMEM; + goto error_return; + } + + job = (job_entry_t *)kmalloc(sizeof(job_entry_t), GFP_KERNEL); + if (!job) { + /* error */ + errcode = -ENOMEM; + goto error_return; + } + + write_lock_pagg_list(current); + pagg = get_pagg(current, pagg_hook.name); + if (pagg) { + /* + * Detaching paggs for jobs never has a failure case, + * so we don't need to worry about error codes. + */ + detach_pagg(current, pagg); + free_pagg(pagg); + } + pagg = alloc_pagg(current, &pagg_hook); + if (!pagg) { + /* error */ + write_unlock_pagg_list(current); + errcode = -ENOMEM; + goto error_return; + } + + + /* + * Lock the job_table and add the pointers for the new job. + * Since the job is new, we won't need to lock the job. + */ + JOB_WLOCK(&job_table_sem); + + /* + * Determine if create should use specified JID or one that is + * generated. + */ + if (create.jid != 0) { + /* We use the specified JID value */ + + if (job_getjob(create.jid)) { + /* JID already in use, bail */ + JOB_WUNLOCK(&job_table_sem); + errcode = -EBUSY; + goto error_return; + } else { + /* Using specifiec JID */ + job->jid = create.jid; + } + } else { + + /* We generate a new JID value */ + *(iptr_hid(job->jid)) = jid_hid; + *(iptr_sid(job->jid)) = current->pid; + } + + /* Initialize job entry values & lists */ + job->refcnt = 1; + job->user = create.user; + job->start = jiffies; + job->csa.corehimem = 0; + job->csa.virthimem = 0; + job->csa.acctfile = NULL; + job->state = RUNNING; + init_rwsem(&job->sem); + INIT_LIST_HEAD(&job->attached); + list_add_tail(&attached->entry, &job->attached); + init_waitqueue_head(&job->wait); + init_waitqueue_head(&job->zombie); + job->waitcnt = 0; + job->waitinfo.status = 0; + + /* set link from entry in attached list to task and job entry */ + attached->task = current; + attached->job = job; + attached->pagg = pagg; + set_pagg(pagg, attached); + + /* Insert new job into front of chain list */ + list_add_tail(&job->entry, &job_table[ jid_hash(job->jid) ]);; + ++job_table_refcnt; + + JOB_WUNLOCK(&job_table_sem); + write_unlock_pagg_list(current); + + /* Issue callbacks into accounting subscribers */ + + /* - CSA subscriber */ + if (acct_list[JOB_ACCT_CSA]) { + job_acctmod_t *acct = acct_list[JOB_ACCT_CSA]; + if (acct->module) + __MOD_INC_USE_COUNT(acct->module); + if (acct->do_jobstart) { + int res; + job_csa_t csa; + + csa.job_id = job->jid; + csa.job_uid = job->user; + csa.job_start = job->start; + csa.job_corehimem = job->csa.corehimem; + csa.job_virthimem = job->csa.virthimem; + csa.job_acctfile = job->csa.acctfile; + + res = acct->do_jobstart(JOB_EVENT_START, &csa); + if (res < 0) { + printk(KERN_WARNING "job_sys_create: CSA -" + " do_jobstart failed.\n"); + } + } + if (acct->module) + __MOD_DEC_USE_COUNT(acct->module); + } + + + create.r_jid = job->jid; + if (copy_to_user(create_args, &create, sizeof(create))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + DBG_PRINTEXIT(0); + return 0; + +error_return: + DBG_PRINTEXIT(errcode); + MOD_DEC_USE_COUNT; /* no new job, so decrement use count */ + if (attached) kfree(attached); + if (job) kfree(job); + if (pagg) { + detach_pagg(current, pagg); + free_pagg(pagg); + /* This was locked at alloc_pagg call */ + write_unlock_pagg_list(current); + } + create.r_jid = 0; + if (copy_to_user(create_args, &create, sizeof(create))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + return errcode; +} + + +/* + * job_sys_getjid + * + * Function retrieves the job ID (jid) for the specified process (pid). + * + * returns 0 on success, negative errno value on exit. + */ +int +job_sys_getjid(job_getjid_t *getjid_args) +{ + job_getjid_t getjid; + int errcode = 0; + struct task_struct *task; + DBG_PRINTINIT("job_sys_getjid"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&getjid, getjid_args, sizeof(getjid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + /* lock the tasklist while searching for task */ + read_lock(&tasklist_lock); + + if (getjid.pid == current->pid) { + task = current; + } else { + task = find_task_by_pid(getjid.pid); + } + if (task) { + getjid.r_jid = job_getjid(task); + read_unlock(&tasklist_lock); + if (getjid.r_jid == 0) { + errcode = -ENODATA; + } + } else { + read_unlock(&tasklist_lock); + getjid.r_jid = 0; + errcode = -ESRCH; + } + + + DBG_PRINTEXIT(errcode); + if (copy_to_user(getjid_args, &getjid, sizeof(getjid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return errcode; +} + + +/* + * job_sys_waitjid + * + * This job allows a process to wait until a job exits & it returns the + * status information for the last process to exit the job. + * + * On success returns 0, failure it returns the negative errno value. + */ +int +job_sys_waitjid(job_waitjid_t *waitjid_args) +{ + job_waitjid_t waitjid; + job_entry_t *job; + int retcode = 0; + DBG_PRINTINIT("job_sys_waitjid"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&waitjid, waitjid_args, sizeof(waitjid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + + waitjid.r_jid = waitjid.stat = 0; + + if (waitjid.options != 0) { + retcode = -EINVAL; + goto general_return; + } + + /* Lock the job table so that the current jobs don't change */ + JOB_RLOCK(&job_table_sem); + + + if ((job = job_getjob(waitjid.jid)) == NULL ) { + JOB_RUNLOCK(&job_table_sem); + retcode = -ENODATA; + goto general_return; + } + + /* + * We got the job we need, we can release the job_table_sem + */ + JOB_WLOCK(&job->sem); + JOB_RUNLOCK(&job_table_sem); + + ++job->waitcnt; + + JOB_WUNLOCK(&job->sem); + + /* We shouldn't hold any locks at this point! The increment of the + * jobs waitcnt will ensure that the job is not removed without + * first notifying this current task */ + retcode = wait_event_interruptible(job->wait, + job->refcnt == 0); + + if (!retcode) { + /* + * This data is static at this point, we will + * not need a lock to read it. + */ + waitjid.stat = job->waitinfo.status; + waitjid.r_jid = job->jid; + } + + JOB_WLOCK(&job->sem); + --job->waitcnt; + + if (job->waitcnt == 0) { + JOB_WUNLOCK(&job->sem); + + /* + * We shouldn't hold any locks at this point! Else, the + * last process in the job will not be able to remove the + * job entry. + * + * That process is stuck waiting for this wake_up, so the + * job shouldn't disappear until after this function call. + * The job entry is not longer in the job table, so no + * other process can get to the entry to foul things up. + */ + wake_up(&job->zombie); + } else { + JOB_WUNLOCK(&job->sem); + } + +general_return: + + DBG_PRINTEXIT(retcode); + if (copy_to_user(waitjid_args, &waitjid, sizeof(waitjid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return retcode; +} + + +/* + * job_sys_killjid + * + * This functions allows a signal to be sent to all processes in a job. + * + * returns 0 on success, negative of errno on failure. + */ +int +job_sys_killjid(job_killjid_t *killjid_args) +{ + job_killjid_t killjid; + job_entry_t *job; + struct list_head *attached_entry; + struct siginfo info; + int retcode = 0; + DBG_PRINTINIT("job_sys_killjid"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&killjid, killjid_args, sizeof(killjid))) { + retcode = -EFAULT; + goto cleanup_0locks_return; + } + + killjid.r_val = -1; + + if (killjid.sig <= 0) { + retcode = -EINVAL; + goto cleanup_0locks_return; + } + + JOB_RLOCK(&job_table_sem); + job = job_getjob(killjid.jid); + if (!job) { + /* Job not found, copy back data & bail with error */ + retcode = -ENODATA; + goto cleanup_1locks_return; + } + + JOB_RLOCK(&job->sem); + + /* + * Check capability to signal job. The signaling user must be + * the owner of the job or have CAP_SYS_RESOURCE capability. + */ +#if 0 /* Use this if not capability is available */ + if (current->uid != 0) { +#else + if (!capable(CAP_SYS_RESOURCE)) { +#endif + if (current->uid != job->user) { + retcode = -EPERM; + goto cleanup_2locks_return; + } + } + + info.si_signo = killjid.sig; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->pid; + info.si_uid = current->uid; + + list_for_each(attached_entry, &job->attached) { + int err; + job_attach_t *attached; + + attached = list_entry(attached_entry, job_attach_t, entry); + err = send_sig_info(killjid.sig, &info, + attached->task); + if (err != 0) { + /* + * XXX - the "prime" process, or initiating process + * for the job may not be owned by the user. So, + * we would get an error in this case. However, we + * ignore the error for that specific process - it + * should exit when all the child processes exit. It + * should ignore all signals from the user. + * + */ + if (attached->entry.prev != &job->attached) { + retcode = err; + } + } + + } + +cleanup_2locks_return: + JOB_RUNLOCK(&job->sem); +cleanup_1locks_return: + JOB_RUNLOCK(&job_table_sem); +cleanup_0locks_return: + killjid.r_val = retcode; + + DBG_PRINTEXIT(retcode); + if (copy_to_user(killjid_args, &killjid, sizeof(killjid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return retcode; +} + + +/* + * job_sys_getjidcnt + * + * Retun the number of jobs currently on the system. + * + * returns 0 on success & it always succeeds. + */ +int +job_sys_getjidcnt(job_jidcnt_t *jidcnt_args) +{ + job_jidcnt_t jidcnt; + DBG_PRINTINIT("job_sys_getjidcnt"); + + DBG_PRINTENTRY(); + + /* read lock might be overdoing it in this case */ + JOB_RLOCK(&job_table_sem); + jidcnt.r_val = job_table_refcnt; + JOB_RUNLOCK(&job_table_sem); + + DBG_PRINTEXIT(0); + + if (copy_to_user(jidcnt_args, &jidcnt, sizeof(jidcnt))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + return 0; +} + + +/* + * job_sys_getjidlst + * + * Get the list of all jids currently on the system (limited by the number of + * jobs there are and the number you say you can accept. + */ +int +job_sys_getjidlst(job_jidlst_t *jidlst_args) +{ + job_jidlst_t jidlst; + uint64_t *jid; + job_entry_t *job; + struct list_head *job_entry; + int i; + int count; + DBG_PRINTINIT("job_sys_getjidlst"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&jidlst, jidlst_args, sizeof(jidlst))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + + if (jidlst.r_val == 0) { + DBG_PRINTEXIT(0); + return 0; + } + + jid = (uint64_t *)kmalloc(sizeof(uint64_t *)*jidlst.r_val, GFP_KERNEL); + if (!jid) { + jidlst.r_val = 0; + DBG_PRINTEXIT(-ENOMEM); + if (copy_to_user(jidlst_args, &jidlst, sizeof(jidlst))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return -ENOMEM; + } + + + count = 0; + JOB_RLOCK(&job_table_sem); + for (i = 0; i < HASH_SIZE && count < jidlst.r_val; i++) { + list_for_each(job_entry, &job_table[i]) { + job = list_entry(job_entry, job_entry_t, entry); + jid[count++] = job->jid; + if (count == jidlst.r_val) { + break; + } + } + } + JOB_RUNLOCK(&job_table_sem); + + DBG_PRINTEXIT(0); + jidlst.r_val = count; + + for (i = 0; i < count; i++) { + if (copy_to_user(jidlst.jid+i, &jid[i], sizeof(uint64_t))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + } + + kfree(jid); + + if (copy_to_user(jidlst_args, &jidlst, sizeof(jidlst))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return 0; +} + + +/* + * job_sys_getpidcnt + * + * Get the number of processes currently attached to a specific job. + * + * returns 0 on success, or negative errno value on failure. + */ +int +job_sys_getpidcnt(job_pidcnt_t *pidcnt_args) +{ + job_pidcnt_t pidcnt; + job_entry_t *job; + int retcode = 0; + DBG_PRINTINIT("job_sys_getpidcnt"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&pidcnt, pidcnt_args, sizeof(pidcnt))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + pidcnt.r_val = 0; + + JOB_RLOCK(&job_table_sem); + job = job_getjob(pidcnt.jid); + if (!job) { + retcode = -ENODATA; + } else { + /* Read lock might be overdoing it for this case */ + JOB_RLOCK(&job->sem); + pidcnt.r_val = job->refcnt; + JOB_RUNLOCK(&job->sem); + } + JOB_RUNLOCK(&job_table_sem); + + DBG_PRINTEXIT(retcode); + + if (copy_to_user(pidcnt_args, &pidcnt, sizeof(pidcnt))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return retcode; +} + +/* + * job_getpidlst + * + * Get the list of processes (pids) currently attached to the specified + * job. The number of processes provided is limited by the number the user + * specivies that they can accept (have memory for) and the number currently + * attached. + * + * returns 0 on success, negative errno value on failure. + */ +int +job_sys_getpidlst(job_pidlst_t *pidlst_args) +{ + job_pidlst_t pidlst; + job_entry_t *job; + job_attach_t *attached; + struct list_head *attached_entry; + pid_t *pid; + int max; + int i; + DBG_PRINTINIT("job_sys_getpidlst"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&pidlst, pidlst_args, sizeof(pidlst))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + + if (pidlst.r_val == 0) { + DBG_PRINTEXIT(0); + return 0; + } + + max = pidlst.r_val; + pidlst.r_val = 0; + pid = (pid_t *)kmalloc(sizeof(pid_t)*max, GFP_KERNEL); + if (!pid) { + DBG_PRINTEXIT(-ENOMEM); + if (copy_to_user(pidlst_args, &pidlst, sizeof(pidlst))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return -ENOMEM; + } + + JOB_RLOCK(&job_table_sem); + + job = job_getjob(pidlst.jid); + if (!job) { + + JOB_RUNLOCK(&job_table_sem); + + DBG_PRINTEXIT(-ENODATA); + if (copy_to_user(pidlst_args, &pidlst, sizeof(pidlst))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return -ENODATA; + } else { + + JOB_RLOCK(&job->sem); + JOB_RUNLOCK(&job_table_sem); + + i = 0; + list_for_each(attached_entry, &job->attached) { + if (i == max) { + break; + } + attached = list_entry(attached_entry, job_attach_t, + entry); + pid[i++] = attached->task->pid; + } + pidlst.r_val = i; + + JOB_RUNLOCK(&job->sem); + } + + for (i = 0; i < pidlst.r_val; i++) { + if (copy_to_user(pidlst.pid+i, &pid[i], sizeof(pid_t))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + } + kfree(pid); + + DBG_PRINTEXIT(0); + copy_to_user(pidlst_args, &pidlst, sizeof(pidlst)); + return 0; +} + + +/* + * job_sys_getuser + * + * Get the uid of the user that owns the job. + * + * returns 0 on success, returns negative errno on failure. + */ +int +job_sys_getuser(job_user_t *user_args) +{ + job_entry_t *job; + job_user_t user; + int retcode = 0; + DBG_PRINTINIT("job_sys_getuser"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&user, user_args, sizeof(user))) { + DBG_PRINTEXIT(-EFAULT); + return(-EFAULT); + } + + user.r_user = 0; + + JOB_RLOCK(&job_table_sem); + + job = job_getjob(user.jid); + if (!job) { + retcode = -ENODATA; + } else { + JOB_RLOCK(&job->sem); + user.r_user = job->user; + JOB_RUNLOCK(&job->sem); + } + + JOB_RUNLOCK(&job_table_sem); + + if (copy_to_user(user_args, &user, sizeof(user))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + DBG_PRINTEXIT(retcode); + return retcode; +} + + +/* + * job_sys_getprimepid + * + * Get the primary process - the oldest process in the job. + * + * returns 0 on success, negative errno on failure. + */ +int +job_sys_getprimepid(job_primepid_t *primepid_args) +{ + job_primepid_t primepid; + job_entry_t *job = NULL; + job_attach_t *attached = NULL; + int retcode = 0; + DBG_PRINTINIT("getprimepid"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&primepid, primepid_args, sizeof(primepid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + primepid.r_pid = 0; + + JOB_RLOCK(&job_table_sem); + + job = job_getjob(primepid.jid); + if (!job) { + JOB_RUNLOCK(&job_table_sem); + /* Job not found, return INVALID VALUE */ + DBG_PRINTEXIT(-ENODATA); + return -ENODATA; + } + + /* + * Job found, now look at first pid entry in the + * attached list. + */ + JOB_RLOCK(&job->sem); + JOB_RUNLOCK(&job_table_sem); + if (list_empty(&job->attached)) { + retcode = -ESRCH; + primepid.r_pid = 0; + } else { + attached = list_entry(job->attached.next, job_attach_t, entry); + if (!attached->task) { + retcode = -ESRCH; + } else { + primepid.r_pid = attached->task->pid; + } + } + JOB_RUNLOCK(&job->sem); + + if (copy_to_user(primepid_args, &primepid, sizeof(primepid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + DBG_PRINTEXIT(retcode); + return retcode; +} + + +/* + * job_sys_sethid + * + * This function is used to set the host ID segment for the job IDs (jid). + * If this does not get set, then the jids upper 32 bits will be set to + * 0 and the jid cannot be used reliably in a cluster environment. + * + * returns -errno value on fail, 0 on success + */ +int +job_sys_sethid(job_sethid_t *sethid_args) +{ + job_sethid_t sethid; + int errcode = 0; + DBG_PRINTINIT("job_sys_sethid"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&sethid, sethid_args, sizeof(sethid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + if (!capable(CAP_SYS_RESOURCE)) { + errcode = -EPERM; + sethid.r_hid = 0; + goto cleanup_return; + } + + /* + * Set job_table_sem, so no jobs can be deleted while doing + * this operation. + */ + JOB_WLOCK(&job_table_sem); + + sethid.r_hid = jid_hid = sethid.hid; + + JOB_WUNLOCK(&job_table_sem); + +cleanup_return: + DBG_PRINTEXIT(errcode); + if (copy_to_user(sethid_args, &sethid, sizeof(sethid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return errcode; +} + + +/* + * job_sys_detachjid + * + * This function is detach all the processes from a job, but allows the + * processes to continue running. You need CAP_SYS_RESOURCE capability + * for this to succeed. Since all processes will be detached, the job will + * exit. + * + * returns -errno value on fail, 0 on success + */ +int +job_sys_detachjid(job_detachjid_t *detachjid_args) +{ + job_detachjid_t detachjid; + job_entry_t *job; + struct list_head *entry; + int count; + int errcode = 0; + DBG_PRINTINIT("job_sys_detachjid"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&detachjid, detachjid_args, sizeof(detachjid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + detachjid.r_val = 0; + + if (!capable(CAP_SYS_RESOURCE)) { + errcode = -EPERM; + goto cleanup_return; + } + + /* + * Set job_table_sem, so no jobs can be deleted while doing + * this operation. + */ + JOB_WLOCK(&job_table_sem); + + job = job_getjob(detachjid.jid); + + if (job) { + + JOB_WLOCK(&job->sem); + + /* Mark job as ZOMBIE so no new processes can attach to it */ + job->state = ZOMBIE; + + count = job->refcnt; + + /* Okay, no new processes can attach to the job. We can + * release the locks on the job_table and job since the only + * way for the job to change now is for tasks to detach and + * the job to be removed. And this is what we want to happen + */ + JOB_WUNLOCK(&job_table_sem); + JOB_WUNLOCK(&job->sem); + + /* Walk through list of attached tasks and unset the + * pagg entries. + */ + entry = job->attached.next; + list_for_each(entry, &job->attached) { + struct task_struct *task = (list_entry(entry, + job_attach_t, entry))->task; + struct pagg_s *pagg = (list_entry(entry, + job_attach_t, entry))->pagg; + + + write_lock_pagg_list(task); + detach_pagg(task, pagg); + free_pagg(pagg); + write_unlock_pagg_list(task); + entry = &job->attached; + } + detachjid.r_val = count; + } else { + errcode = -ENODATA; + JOB_WUNLOCK(&job_table_sem); + } + +cleanup_return: + DBG_PRINTEXIT(errcode); + if (copy_to_user(detachjid_args, &detachjid, sizeof(detachjid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return errcode; +} + + +/* + * job_sys_detachpid + * + * This function is detach a process from the job it is attached too, + * but allows the processes to continue running. You need + * CAP_SYS_RESOURCE capability for this to succeed. + * + * returns -errno value on fail, 0 on success + */ +int +job_sys_detachpid(job_detachpid_t *detachpid_args) +{ + job_detachpid_t detachpid; + struct task_struct *task; + struct pagg_s *pagg; + int errcode = 0; + DBG_PRINTINIT("job_sys_detachpid"); + + DBG_PRINTENTRY(); + + if (copy_from_user(&detachpid, detachpid_args, sizeof(detachpid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + + detachpid.r_jid = 0; + + if (!capable(CAP_SYS_RESOURCE)) { + errcode = -EPERM; + goto cleanup_return; + } + + read_lock(&tasklist_lock); + task = find_task_by_pid(detachpid.pid); + if (!task) { + errcode = -ESRCH; + goto cleanup_return; + } + + write_lock_pagg_list(task); + read_unlock(&tasklist_lock); + pagg = get_pagg(task, pagg_hook.name); + if (pagg) { + detachpid.r_jid = ((job_attach_t *)pagg->data)->job->jid; + detach_pagg(task, pagg); + free_pagg(pagg); + } else { + errcode = -ENODATA; + } + write_unlock_pagg_list(task); + +cleanup_return: + DBG_PRINTEXIT(errcode); + if (copy_to_user(detachpid_args, &detachpid, sizeof(detachpid))) { + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; + } + return errcode; +} + + +/* + * job_register_acct + * + * This function is used by modules that are registering to provide job + * accounting services. + * + * returns -errno value on fail, 0 on success. + */ +int +job_register_acct(job_acctmod_t *am) +{ + DBG_PRINTINIT("job_register_acct"); + + DBG_PRINTENTRY(); + + if (!am) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; /* error, invalid value */ + } + if (am->type < 0 || am->type > (JOB_ACCT_COUNT-1)) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; /* error, invalid value */ + } + + JOB_WLOCK(&acct_list_sem); + if (acct_list[am->type] != NULL) { + JOB_WUNLOCK(&acct_list_sem); + DBG_PRINTEXIT(-EBUSY); + return -EBUSY; /* error, duplicate entry */ + } + + acct_list[am->type] = am; + JOB_WUNLOCK(&acct_list_sem); + DBG_PRINTEXIT(0); + return 0; +} + + +/* + * job_unregister_acct + * + * This is used by accounting modules to unregister with the job module as + * subscribers for job accounting information. + * + * Returns -errno on failure and 0 on success. + */ +int +job_unregister_acct(job_acctmod_t *am) +{ + DBG_PRINTINIT("job_unregister_acct"); + + DBG_PRINTENTRY(); + + if (!am) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; /* error, invalid value */ + } + if (am->type < 0 || am->type > (JOB_ACCT_COUNT-1)) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; /* error, invalid value */ + } + + JOB_WLOCK(&acct_list_sem); + if (acct_list[am->type] != am) { + JOB_WUNLOCK(&acct_list_sem); + DBG_PRINTEXIT(-EFAULT); + return -EFAULT; /* error, not matching entry */ + } + + acct_list[am->type] = NULL; + JOB_WUNLOCK(&acct_list_sem); + DBG_PRINTEXIT(0); + return 0; +} + +/* + * job_getjid + * + * This function will return the Job ID for the given task. If + * the task is not attached to a job, then 0 is returned. + * + */ +uint64_t job_getjid(struct task_struct *task) +{ + struct pagg_s *pagg = NULL; + job_entry_t *job = NULL; + uint64_t jid = 0; + DBG_PRINTINIT("job_getjid"); + + DBG_PRINTENTRY(); + + read_lock_pagg_list(task); + pagg = get_pagg(task, pagg_hook.name); + if (pagg) { + job = ((job_attach_t *)pagg->data)->job; + JOB_RLOCK(&job->sem); + jid = job->jid; + JOB_RUNLOCK(&job->sem); + } + read_unlock_pagg_list(task); + + DBG_PRINTEXIT((int)jid); + return jid; +} + + +/* + * job_getacct + * + * This function is used by accounting subscribers to get accounting + * information about a job. + * + * The caller must supply the Job ID (jid) that specifies the job. The + * "type" argument indicates the type of accounting data to be returned. + * The data will be returned in the memory accessed via the data pointer + * argument. The data pointer is void so that this function interface + * can handle different types of accounting data. + */ +int job_getacct(uint64_t jid, int type, void *data) +{ + job_entry_t *job; + DBG_PRINTINIT("job_getacct"); + + DBG_PRINTENTRY(); + + if (!data) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; + } + + if (!jid) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; + } + + JOB_RLOCK(&job_table_sem); + job = job_getjob(jid); + if (!job) { + JOB_RUNLOCK(&job_table_sem); + DBG_PRINTEXIT(-ENODATA); + return -ENODATA; + } + + JOB_RLOCK(&job->sem); + JOB_RUNLOCK(&job_table_sem); + + switch (type) { + case JOB_ACCT_CSA: + { + job_csa_t *csa = (job_csa_t *)data; + + csa->job_id = job->jid; + csa->job_uid = job->user; + csa->job_start = job->start; + csa->job_corehimem = job->csa.corehimem; + csa->job_virthimem = job->csa.virthimem; + csa->job_acctfile = job->csa.acctfile; + break; + } + default: + JOB_RUNLOCK(&job->sem); + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; + break; + } + JOB_RUNLOCK(&job->sem); + DBG_PRINTEXIT(0); + return 0; +} + +/* + * job_setacct + * + * This function is used by accounting subscribers to set specific + * accounting information in the job (so that the job remembers it + * in relation to a specific job). + * + * The job is identified by the jid argument. The type indicates the + * type of accounting the information is associated with. The subfield + * is a bitmask that indicates exactly what subfields are to be changed. + * The data that is used to set the values is supplied by the data pointer. + * The data pointer is a void type so that the interface can be used for + * different types of accounting information. + */ +int job_setacct(uint64_t jid, int type, int subfield, void *data) +{ + job_entry_t *job; + DBG_PRINTINIT("job_setacct"); + + DBG_PRINTENTRY(); + + if (!data) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; + } + + if (!jid) { + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; + } + + JOB_RLOCK(&job_table_sem); + job = job_getjob(jid); + if (!job) { + JOB_RUNLOCK(&job_table_sem); + DBG_PRINTEXIT(-ENODATA); + return -ENODATA; + } + + JOB_RLOCK(&job->sem); + JOB_RUNLOCK(&job_table_sem); + + switch (type) { + case JOB_ACCT_CSA: + { + job_csa_t *csa = (job_csa_t *)data; + + if (subfield & JOB_CSA_ACCTFILE) { + job->csa.acctfile = csa->job_acctfile; + } + break; + } + default: + JOB_RUNLOCK(&job->sem); + DBG_PRINTEXIT(-EINVAL); + return -EINVAL; + break; + } + JOB_RUNLOCK(&job->sem); + DBG_PRINTEXIT(0); + return 0; +} + + + +/* + * init_module + * + * This function is called when a module is inserted into a kernel. This + * function allocates any necessary structures and sets initial values for + * module data. + * + * If the function succeeds, then 0 is returned. On failure, -1 is returned. + */ +static int __init +init_job(void) +{ + int i; + + + /* Initialize the job table chains */ + for (i = 0; i < HASH_SIZE; i++) { + INIT_LIST_HEAD(&job_table[i]); + } + + /* Initialize the list for accounting subscribers */ + for (i = 0; i < JOB_ACCT_COUNT; i++) { + acct_list[i] = NULL; + } + + /* Get hostID string and fill in jid_template hostID segment */ + if (hid) { + jid_hid = (int)simple_strtoul(hid, &hid, 16); + } else { + jid_hid = 0; + } + + return register_pagg_hook(&pagg_hook); +} + +/* + * cleanup_module + * + * This function is called to cleanup after a module when it is removed. + * All memory allocated for this module will be freed. + * + * This function does not take any inputs or produce and output. + */ +static void __exit +cleanup_job(void) +{ + unregister_pagg_hook(&pagg_hook); + return; +} + +module_init(init_job); +module_exit(cleanup_job); + +EXPORT_SYMBOL(job_register_acct); +EXPORT_SYMBOL(job_unregister_acct); +EXPORT_SYMBOL(job_getjid); +EXPORT_SYMBOL(job_getacct); +EXPORT_SYMBOL(job_setacct); + diff -Nur linux-2.4.19/drivers/mtd/mtdchar.c linux-2.4.19-sgi211r3/drivers/mtd/mtdchar.c --- linux-2.4.19/drivers/mtd/mtdchar.c Thu Oct 4 15:14:59 2001 +++ linux-2.4.19-sgi211r3/drivers/mtd/mtdchar.c Mon Oct 28 20:43:23 2002 @@ -10,6 +10,7 @@ #include #include #include +#include #include #ifdef CONFIG_DEVFS_FS @@ -31,6 +32,7 @@ { struct mtd_info *mtd=(struct mtd_info *)file->private_data; + lock_kernel(); switch (orig) { case 0: /* SEEK_SET */ @@ -45,6 +47,7 @@ file->f_pos =mtd->size + offset; break; default: + unlock_kernel(); return -EINVAL; } @@ -53,6 +56,7 @@ else if (file->f_pos >= mtd->size) file->f_pos = mtd->size - 1; + unlock_kernel(); return file->f_pos; } diff -Nur linux-2.4.19/drivers/net/Config.in linux-2.4.19-sgi211r3/drivers/net/Config.in --- linux-2.4.19/drivers/net/Config.in Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/Config.in Wed Oct 16 14:02:58 2002 @@ -240,8 +240,10 @@ if [ "$CONFIG_ACENIC" != "n" ]; then bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I fi +dep_tristate 'Broadcom BCM5700 support' CONFIG_NET_BROADCOM $CONFIG_PCI dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS +dep_tristate 'Intel Pro/1000 Gigabit Ethernet support' CONFIG_E1000 $CONFIG_PCI dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL diff -Nur linux-2.4.19/drivers/net/Makefile linux-2.4.19-sgi211r3/drivers/net/Makefile --- linux-2.4.19/drivers/net/Makefile Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/Makefile Wed Oct 16 14:02:58 2002 @@ -29,6 +29,14 @@ obj-$(CONFIG_ISDN) += slhc.o endif +ifeq ($(CONFIG_NET_BROADCOM),y) + obj-y += bcm/bcm5700.o +endif + +ifeq ($(CONFIG_E1000),y) + obj-y += e1000/e1000.o +endif + subdir-$(CONFIG_NET_PCMCIA) += pcmcia subdir-$(CONFIG_NET_WIRELESS) += wireless subdir-$(CONFIG_TULIP) += tulip @@ -40,6 +48,8 @@ subdir-$(CONFIG_DEV_APPLETALK) += appletalk subdir-$(CONFIG_SK98LIN) += sk98lin subdir-$(CONFIG_SKFP) += skfp +subdir-$(CONFIG_NET_BROADCOM) += bcm +subdir-$(CONFIG_E1000) += e1000 # # link order important here @@ -132,6 +142,7 @@ obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o +obj-$(CONFIG_SIMETH) += simeth.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o diff -Nur linux-2.4.19/drivers/net/acenic.c linux-2.4.19-sgi211r3/drivers/net/acenic.c --- linux-2.4.19/drivers/net/acenic.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/acenic.c Wed Oct 16 14:02:58 2002 @@ -112,6 +112,11 @@ #define PCI_DEVICE_ID_NETGEAR_GA620T 0x630a #endif +#ifdef BUS_INT_WAR +void sn_add_polled_interrupt(int irq, int interval); +void sn_delete_polled_interrupt(int irq); +#endif + /* * Farallon used the DEC vendor ID by mistake and they seem not @@ -634,6 +639,14 @@ SET_MODULE_OWNER(dev); + /* + * We need to tell the system that this is a 64bit card .. + * Really Jes, we need to set the mask in probe instead + * of init if you plan on allocating DMA Buffers here. + */ + pdev->dma_mask = 0xffffffffffffffff; + + if (!dev->priv) dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL); if (!dev->priv) { @@ -854,14 +867,20 @@ regs = ap->regs; +#ifdef BUS_INT_WAR + sn_delete_polled_interrupt(root_dev->irq); +#endif writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); if (ap->version >= 2) writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); + readl(®s->CpuCtrl); /* GGG flush write */ + /* * This clears any pending interrupts */ writel(1, ®s->Mb0Lo); + readl(®s->Mb0Lo); /* GGG flush write */ /* * Make sure no other CPUs are processing interrupts @@ -1094,6 +1113,10 @@ { struct ace_private *ap; +#ifdef BUS_INT_WAR + if (dev->irq) + sn_delete_polled_interrupt(dev->irq); +#endif ap = dev->priv; ace_free_descriptors(dev); @@ -1154,35 +1177,28 @@ * to any crashes involving the NIC */ writel(HW_RESET | (HW_RESET << 24), ®s->HostCtrl); - wmb(); + wmb(); readl(®s->HostCtrl); /* GGG flush write */ + mdelay(1); /* - * Don't access any other registes before this point! + * Don't access any other registers before this point! */ -#ifdef __BIG_ENDIAN /* * This will most likely need BYTE_SWAP once we switch * to using __raw_writel() */ -#ifdef __parisc__ - writel((WORD_SWAP | BYTE_SWAP | CLR_INT | - ((WORD_SWAP | BYTE_SWAP | CLR_INT) << 24)), - ®s->HostCtrl); -#else - writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)), - ®s->HostCtrl); -#endif -#else writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)), ®s->HostCtrl); -#endif - mb(); + mb(); readl(®s->HostCtrl); /* GGG flush write */ /* * Stop the NIC CPU and clear pending interrupts */ writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); + readl(®s->CpuCtrl); /* GGG flush write */ + writel(0, ®s->Mb0Lo); + readl(®s->Mb0Lo); /* GGG flush write */ tig_ver = readl(®s->HostCtrl) >> 28; @@ -1202,6 +1218,7 @@ tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor, tigon2FwReleaseFix); writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); + readl(®s->CpuBCtrl); /* GGG flush write */ /* * The SRAM bank size does _not_ indicate the amount * of memory on the card, it controls the _bank_ size! @@ -1233,7 +1250,7 @@ writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL | ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, ®s->ModeStat); #endif - mb(); + mb(); readl(®s->ModeStat); /* GGG flush write */ mac1 = 0; for(i = 0; i < 4; i++) { @@ -1371,7 +1388,7 @@ tmp &= ~DMA_READ_WRITE_MASK; tmp |= DMA_READ_MAX_128; /* - * All the docs sy MUST NOT. Well, I did. + * All the docs say MUST NOT. Well, I did. * Nothing terrible happens, if we load wrong size. * Bit w&i still works better! */ @@ -1380,6 +1397,12 @@ writel(tmp, ®s->PciState); #if 0 +/* The Host PCI bus controller driver has to set FBB. + * If all devices on that PCI bus support FBB, then the controller + * can enable FBB support in the Host PCI Bus controller (or on + * the PCI-PCI bridge if that applies). + * -ggg + */ /* * I have received reports from people having problems when this * bit is enabled. @@ -1439,6 +1462,10 @@ ap->next = root_dev; root_dev = dev; +#ifdef BUS_INT_WAR + sn_add_polled_interrupt(root_dev->irq, 1); +#endif + #ifdef INDEX_DEBUG spin_lock_init(&ap->debug_lock); ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1; @@ -1450,6 +1477,7 @@ memset(ap->skb, 0, sizeof(struct ace_skb)); ace_load_firmware(dev); + ap->fw_running = 0; tmp_ptr = ap->info_dma; @@ -1461,9 +1489,9 @@ set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma); info->evt_ctrl.flags = 0; - set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma); *(ap->evt_prd) = 0; - wmb(); + set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma); + writel(0, ®s->EvtCsm); set_aceaddr(&info->cmd_ctrl.rngptr, 0x100); @@ -1593,9 +1621,9 @@ writel(DMA_THRESH_8W, ®s->DmaWriteCfg); #endif - writel(0, ®s->MaskInt); writel(1, ®s->IfIdx); - writel(1, ®s->AssistState); + writel(0, ®s->MaskInt); + readl(®s->MaskInt); /* GGG flush write */ writel(DEF_STAT, ®s->TuneStatTicks); writel(DEF_TRACE, ®s->TuneTrace); @@ -1686,6 +1714,7 @@ writel(tigon2FwStartAddr, ®s->Pc); writel(0, ®s->Mb0Lo); + readl(®s->Mb0Lo); /* GGG flush write */ /* * Set tx_csm before we start receiving interrupts, otherwise @@ -1705,10 +1734,21 @@ */ memset(&ap->stats, 0, sizeof(ap->stats)); + /* + * Enable DMA engine now. + * If we do this sooner, Mckinley box pukes. + * I assume it's because Tigon II DMA engine wants to check + * *something* even before the CPU is started. + */ + writel(1, ®s->AssistState); /* enable DMA */ + readl(®s->AssistState); /* GGG flush write */ + mdelay(1); + /* * Start the NIC CPU */ writel(readl(®s->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), ®s->CpuCtrl); + readl(®s->CpuCtrl); /* GGG flush write */ /* * Wait for the firmware to spin up - max 3 seconds. @@ -1721,6 +1761,7 @@ ace_dump_trace(ap); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); + readl(®s->CpuCtrl); /* GGG flush write */ /* aman@sgi.com - account for badly behaving firmware/NIC: * - have observed that the NIC may continue to generate @@ -1735,6 +1776,7 @@ writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); writel(0, ®s->Mb0Lo); + readl(®s->Mb0Lo); /* GGG flush write */ ecode = -EBUSY; goto init_error; @@ -2409,6 +2451,7 @@ * threads and it is wrong even for that case. */ writel(0, ®s->Mb0Lo); + readl(®s->Mb0Lo); /* GGG flush write */ /* * There is no conflict between transmit handling in @@ -3251,6 +3294,7 @@ tigon2FwRodataLen); ace_copy(regs, tigon2FwData, tigon2FwDataAddr,tigon2FwDataLen); } + readl(®s->CpuCtrl); /* GGG flush write */ return 0; } @@ -3275,23 +3319,24 @@ { u32 local; + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); local = readl(®s->LocalCtrl); local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); local &= ~EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ } @@ -3305,7 +3350,7 @@ local &= ~EEPROM_DATA_OUT; local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ for (i = 0; i < 8; i++, magic <<= 1) { udelay(ACE_SHORT_DELAY); @@ -3314,16 +3359,16 @@ else local &= ~EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT); writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ } } @@ -3336,18 +3381,18 @@ local = readl(®s->LocalCtrl); local &= ~EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_LONG_DELAY); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); /* sample data in middle of high clk */ state = (readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0; udelay(ACE_SHORT_DELAY); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG flush write */ return state; } @@ -3402,7 +3447,7 @@ regs = ((struct ace_private *)dev->priv)->regs; /* - * Don't take interrupts on this CPU will bit banging + * Don't take interrupts on this CPU while bit banging * the %#%#@$ I2C device */ __save_flags(flags); @@ -3450,12 +3495,14 @@ local = readl(®s->LocalCtrl); local &= ~EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_LONG_DELAY); mb(); local |= EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); - mb(); + readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); + mb(); /* sample data mid high clk */ result = (result << 1) | ((readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0); @@ -3464,11 +3511,13 @@ local = readl(®s->LocalCtrl); local &= ~EEPROM_CLK_OUT; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); /* GGG flush write */ udelay(ACE_SHORT_DELAY); mb(); if (i == 7) { local |= EEPROM_WRITE_ENABLE; writel(local, ®s->LocalCtrl); + readl(®s->LocalCtrl); /* GGG flush write */ mb(); udelay(ACE_SHORT_DELAY); } @@ -3476,12 +3525,12 @@ local |= EEPROM_DATA_OUT; writel(local, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG Flush write */ udelay(ACE_SHORT_DELAY); writel(readl(®s->LocalCtrl) | EEPROM_CLK_OUT, ®s->LocalCtrl); udelay(ACE_LONG_DELAY); writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); - mb(); + mb(); readl(®s->LocalCtrl); /* GGG Flush write */ udelay(ACE_SHORT_DELAY); eeprom_stop(regs); diff -Nur linux-2.4.19/drivers/net/bcm/5701rls.c linux-2.4.19-sgi211r3/drivers/net/bcm/5701rls.c --- linux-2.4.19/drivers/net/bcm/5701rls.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/5701rls.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,48 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* */ +/******************************************************************************/ + +#if INCLUDE_5701_AX_FIX + +#include "mm.h" +#include "5701rls.h" + +LM_STATUS LM_LoadRlsFirmware(PLM_DEVICE_BLOCK pDevice) +{ + T3_FWIMG_INFO FwImgInfo; + + FwImgInfo.StartAddress = t3FwStartAddr; + FwImgInfo.Text.Buffer = (PLM_UINT8)t3FwText; + FwImgInfo.Text.Offset = t3FwTextAddr; + FwImgInfo.Text.Length = t3FwTextLen; + FwImgInfo.ROnlyData.Buffer = (PLM_UINT8)t3FwRodata; + FwImgInfo.ROnlyData.Offset = t3FwRodataAddr; + FwImgInfo.ROnlyData.Length = t3FwRodataLen; + FwImgInfo.Data.Buffer = (PLM_UINT8)t3FwData; + FwImgInfo.Data.Offset = t3FwDataAddr; + FwImgInfo.Data.Length = t3FwDataLen; + + if (LM_LoadFirmware(pDevice, + &FwImgInfo, + T3_RX_CPU_ID | T3_TX_CPU_ID, + T3_RX_CPU_ID) != LM_STATUS_SUCCESS) + { + DbgMessage(FATAL, ("Failed loading firmware.\n")); + DbgBreak(); + return LM_STATUS_FAILURE; + } + + return LM_STATUS_SUCCESS; +} + +#endif /* INCLUDE_5701_AX_FIX */ diff -Nur linux-2.4.19/drivers/net/bcm/5701rls.h linux-2.4.19-sgi211r3/drivers/net/bcm/5701rls.h --- linux-2.4.19/drivers/net/bcm/5701rls.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/5701rls.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,198 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + +typedef unsigned long U32; +int t3FwReleaseMajor = 0x0; +int t3FwReleaseMinor = 0x0; +int t3FwReleaseFix = 0x0; +U32 t3FwStartAddr = 0x08000000; +U32 t3FwTextAddr = 0x08000000; +int t3FwTextLen = 0x9c0; +U32 t3FwRodataAddr = 0x080009c0; +int t3FwRodataLen = 0x60; +U32 t3FwDataAddr = 0x08000a40; +int t3FwDataLen = 0x20; +U32 t3FwSbssAddr = 0x08000a60; +int t3FwSbssLen = 0xc; +U32 t3FwBssAddr = 0x08000a70; +int t3FwBssLen = 0x10; +U32 t3FwText[(0x9c0/4) + 1] = { +0x0, +0x10000003, 0x0, 0xd, 0xd, +0x3c1d0800, 0x37bd3ffc, 0x3a0f021, 0x3c100800, +0x26100000, 0xe000018, 0x0, 0xd, +0x3c1d0800, 0x37bd3ffc, 0x3a0f021, 0x3c100800, +0x26100034, 0xe00021c, 0x0, 0xd, +0x0, 0x0, 0x0, 0x27bdffe0, +0x3c1cc000, 0xafbf0018, 0xaf80680c, 0xe00004c, +0x241b2105, 0x97850000, 0x97870002, 0x9782002c, +0x9783002e, 0x3c040800, 0x248409c0, 0xafa00014, +0x21400, 0x621825, 0x52c00, 0xafa30010, +0x8f860010, 0xe52825, 0xe000060, 0x24070102, +0x3c02ac00, 0x34420100, 0x3c03ac01, 0x34630100, +0xaf820490, 0x3c02ffff, 0xaf820494, 0xaf830498, +0xaf82049c, 0x24020001, 0xaf825ce0, 0xe00003f, +0xaf825d00, 0xe000140, 0x0, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x2402ffff, 0xaf825404, +0x8f835400, 0x34630400, 0xaf835400, 0xaf825404, +0x3c020800, 0x24420034, 0xaf82541c, 0x3e00008, +0xaf805400, 0x0, 0x0, 0x3c020800, +0x34423000, 0x3c030800, 0x34633000, 0x3c040800, +0x348437ff, 0x3c010800, 0xac220a64, 0x24020040, +0x3c010800, 0xac220a68, 0x3c010800, 0xac200a60, +0xac600000, 0x24630004, 0x83102b, 0x5040fffd, +0xac600000, 0x3e00008, 0x0, 0x804821, +0x8faa0010, 0x3c020800, 0x8c420a60, 0x3c040800, +0x8c840a68, 0x8fab0014, 0x24430001, 0x44102b, +0x3c010800, 0xac230a60, 0x14400003, 0x4021, +0x3c010800, 0xac200a60, 0x3c020800, 0x8c420a60, +0x3c030800, 0x8c630a64, 0x91240000, 0x21140, +0x431021, 0x481021, 0x25080001, 0xa0440000, +0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, +0x8c420a60, 0x3c030800, 0x8c630a64, 0x8f84680c, +0x21140, 0x431021, 0xac440008, 0xac45000c, +0xac460010, 0xac470014, 0xac4a0018, 0x3e00008, +0xac4b001c, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x2000008, +0x0, 0xa0001e3, 0x3c0a0001, 0xa0001e3, +0x3c0a0002, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x3c0a0007, 0xa0001e3, 0x3c0a0008, 0xa0001e3, +0x3c0a0009, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x3c0a000b, 0xa0001e3, +0x3c0a000c, 0xa0001e3, 0x3c0a000d, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x3c0a000e, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x3c0a0013, 0xa0001e3, +0x3c0a0014, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x27bdffe0, +0x1821, 0x1021, 0xafbf0018, 0xafb10014, +0xafb00010, 0x3c010800, 0x220821, 0xac200a70, +0x3c010800, 0x220821, 0xac200a74, 0x3c010800, +0x220821, 0xac200a78, 0x24630001, 0x1860fff5, +0x2442000c, 0x24110001, 0x8f906810, 0x32020004, +0x14400005, 0x24040001, 0x3c020800, 0x8c420a78, +0x18400003, 0x2021, 0xe000182, 0x0, +0x32020001, 0x10400003, 0x0, 0xe000169, +0x0, 0xa000153, 0xaf915028, 0x8fbf0018, +0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0020, +0x3c050800, 0x8ca50a70, 0x3c060800, 0x8cc60a80, +0x3c070800, 0x8ce70a78, 0x27bdffe0, 0x3c040800, +0x248409d0, 0xafbf0018, 0xafa00010, 0xe000060, +0xafa00014, 0xe00017b, 0x2021, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x24020001, 0x8f836810, +0x821004, 0x21027, 0x621824, 0x3e00008, +0xaf836810, 0x27bdffd8, 0xafbf0024, 0x1080002e, +0xafb00020, 0x8f825cec, 0xafa20018, 0x8f825cec, +0x3c100800, 0x26100a78, 0xafa2001c, 0x34028000, +0xaf825cec, 0x8e020000, 0x18400016, 0x0, +0x3c020800, 0x94420a74, 0x8fa3001c, 0x221c0, +0xac830004, 0x8fa2001c, 0x3c010800, 0xe000201, +0xac220a74, 0x10400005, 0x0, 0x8e020000, +0x24420001, 0xa0001df, 0xae020000, 0x3c020800, +0x8c420a70, 0x21c02, 0x321c0, 0xa0001c5, +0xafa2001c, 0xe000201, 0x0, 0x1040001f, +0x0, 0x8e020000, 0x8fa3001c, 0x24420001, +0x3c010800, 0xac230a70, 0x3c010800, 0xac230a74, +0xa0001df, 0xae020000, 0x3c100800, 0x26100a78, +0x8e020000, 0x18400028, 0x0, 0xe000201, +0x0, 0x14400024, 0x0, 0x8e020000, +0x3c030800, 0x8c630a70, 0x2442ffff, 0xafa3001c, +0x18400006, 0xae020000, 0x31402, 0x221c0, +0x8c820004, 0x3c010800, 0xac220a70, 0x97a2001e, +0x2442ff00, 0x2c420300, 0x1440000b, 0x24024000, +0x3c040800, 0x248409dc, 0xafa00010, 0xafa00014, +0x8fa6001c, 0x24050008, 0xe000060, 0x3821, +0xa0001df, 0x0, 0xaf825cf8, 0x3c020800, +0x8c420a40, 0x8fa3001c, 0x24420001, 0xaf835cf8, +0x3c010800, 0xac220a40, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x27bdffe0, 0x3c040800, +0x248409e8, 0x2821, 0x3021, 0x3821, +0xafbf0018, 0xafa00010, 0xe000060, 0xafa00014, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f82680c, +0x8f85680c, 0x21827, 0x3182b, 0x31823, +0x431024, 0x441021, 0xa2282b, 0x10a00006, +0x0, 0x401821, 0x8f82680c, 0x43102b, +0x1440fffd, 0x0, 0x3e00008, 0x0, +0x3c040800, 0x8c840000, 0x3c030800, 0x8c630a40, +0x64102b, 0x54400002, 0x831023, 0x641023, +0x2c420008, 0x3e00008, 0x38420001, 0x27bdffe0, +0x802821, 0x3c040800, 0x24840a00, 0x3021, +0x3821, 0xafbf0018, 0xafa00010, 0xe000060, +0xafa00014, 0xa000216, 0x0, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x0, 0x27bdffe0, +0x3c1cc000, 0xafbf0018, 0xe00004c, 0xaf80680c, +0x3c040800, 0x24840a10, 0x3802821, 0x3021, +0x3821, 0xafa00010, 0xe000060, 0xafa00014, +0x2402ffff, 0xaf825404, 0x3c0200aa, 0xe000234, +0xaf825434, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x0, 0x0, 0x0, 0x27bdffe8, +0xafb00010, 0x24100001, 0xafbf0014, 0x3c01c003, +0xac200000, 0x8f826810, 0x30422000, 0x10400003, +0x0, 0xe000246, 0x0, 0xa00023a, +0xaf905428, 0x8fbf0014, 0x8fb00010, 0x3e00008, +0x27bd0018, 0x27bdfff8, 0x8f845d0c, 0x3c0200ff, +0x3c030800, 0x8c630a50, 0x3442fff8, 0x821024, +0x1043001e, 0x3c0500ff, 0x34a5fff8, 0x3c06c003, +0x3c074000, 0x851824, 0x8c620010, 0x3c010800, +0xac230a50, 0x30420008, 0x10400005, 0x871025, +0x8cc20000, 0x24420001, 0xacc20000, 0x871025, +0xaf825d0c, 0x8fa20000, 0x24420001, 0xafa20000, +0x8fa20000, 0x8fa20000, 0x24420001, 0xafa20000, +0x8fa20000, 0x8f845d0c, 0x3c030800, 0x8c630a50, +0x851024, 0x1443ffe8, 0x851824, 0x27bd0008, +0x3e00008, 0x0, 0x0, 0x0 }; +U32 t3FwRodata[(0x60/4) + 1] = { +0x35373031, 0x726c7341, 0x0, +0x0, 0x53774576, 0x656e7430, 0x0, +0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, +0x45766e74, 0x0, 0x0, 0x0, +0x0, 0x66617461, 0x6c457272, 0x0, +0x0, 0x4d61696e, 0x43707542, 0x0, +0x0, 0x0 }; +U32 t3FwData[(0x20/4) + 1] = { +0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0 }; diff -Nur linux-2.4.19/drivers/net/bcm/Makefile linux-2.4.19-sgi211r3/drivers/net/bcm/Makefile --- linux-2.4.19/drivers/net/bcm/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/Makefile Tue Aug 27 19:53:13 2002 @@ -0,0 +1,13 @@ + +# +# Makefile for linux/drivers/net/bcm +# + +O_TARGET := bcm5700.o +obj-y := b57um.o b57proc.o tigon3.o autoneg.o 5701rls.o +obj-m := $(O_TARGET) + +EXTRA_CFLAGS = -DDBG=0 -DT3_JUMBO_RCV_RCB_ENTRY_COUNT=256 -DNICE_SUPPORT -DPCIX_TARGET_WORKAROUND=1 -DINCLUDE_TBI_SUPPORT -DINCLUDE_5701_AX_FIX=1 + +include $(TOPDIR)/Rules.make + diff -Nur linux-2.4.19/drivers/net/bcm/autoneg.c linux-2.4.19-sgi211r3/drivers/net/bcm/autoneg.c --- linux-2.4.19/drivers/net/bcm/autoneg.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/autoneg.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,535 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2001 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + +#if INCLUDE_TBI_SUPPORT +#include "autoneg.h" +#include "mm.h" + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +MM_AnTxConfig( + PAN_STATE_INFO pAnInfo) +{ + PLM_DEVICE_BLOCK pDevice; + + pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext; + + REG_WR(pDevice, MacCtrl.TxAutoNeg, (LM_UINT32) pAnInfo->TxConfig.AsUSHORT); + + pDevice->MacMode |= MAC_MODE_SEND_CONFIGS; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +MM_AnTxIdle( + PAN_STATE_INFO pAnInfo) +{ + PLM_DEVICE_BLOCK pDevice; + + pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext; + + pDevice->MacMode &= ~MAC_MODE_SEND_CONFIGS; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +char +MM_AnRxConfig( + PAN_STATE_INFO pAnInfo, + unsigned short *pRxConfig) +{ + PLM_DEVICE_BLOCK pDevice; + LM_UINT32 Value32; + char Retcode; + + Retcode = AN_FALSE; + + pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext; + + Value32 = REG_RD(pDevice, MacCtrl.Status); + if(Value32 & MAC_STATUS_RECEIVING_CFG) + { + Value32 = REG_RD(pDevice, MacCtrl.RxAutoNeg); + *pRxConfig = (unsigned short) Value32; + + Retcode = AN_TRUE; + } + + return Retcode; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +AutonegInit( + PAN_STATE_INFO pAnInfo) +{ + unsigned long j; + + for(j = 0; j < sizeof(AN_STATE_INFO); j++) + { + ((unsigned char *) pAnInfo)[j] = 0; + } + + /* Initialize the default advertisement register. */ + pAnInfo->mr_adv_full_duplex = 1; + pAnInfo->mr_adv_sym_pause = 1; + pAnInfo->mr_adv_asym_pause = 1; + pAnInfo->mr_an_enable = 1; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +AUTONEG_STATUS +Autoneg8023z( + PAN_STATE_INFO pAnInfo) +{ + unsigned short RxConfig; + unsigned long Delta_us; + AUTONEG_STATUS AnRet; + + /* Get the current time. */ + if(pAnInfo->State == AN_STATE_UNKNOWN) + { + pAnInfo->RxConfig.AsUSHORT = 0; + pAnInfo->CurrentTime_us = 0; + pAnInfo->LinkTime_us = 0; + pAnInfo->AbilityMatchCfg = 0; + pAnInfo->AbilityMatchCnt = 0; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->IdleMatch = AN_FALSE; + pAnInfo->AckMatch = AN_FALSE; + } + + /* Increment the timer tick. This function is called every microsecon. */ +// pAnInfo->CurrentTime_us++; + + /* Set the AbilityMatch, IdleMatch, and AckMatch flags if their */ + /* corresponding conditions are satisfied. */ + if(MM_AnRxConfig(pAnInfo, &RxConfig)) + { + if(RxConfig != pAnInfo->AbilityMatchCfg) + { + pAnInfo->AbilityMatchCfg = RxConfig; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->AbilityMatchCnt = 0; + } + else + { + pAnInfo->AbilityMatchCnt++; + if(pAnInfo->AbilityMatchCnt > 1) + { + pAnInfo->AbilityMatch = AN_TRUE; + pAnInfo->AbilityMatchCfg = RxConfig; + } + } + + if(RxConfig & AN_CONFIG_ACK) + { + pAnInfo->AckMatch = AN_TRUE; + } + else + { + pAnInfo->AckMatch = AN_FALSE; + } + + pAnInfo->IdleMatch = AN_FALSE; + } + else + { + pAnInfo->IdleMatch = AN_TRUE; + + pAnInfo->AbilityMatchCfg = 0; + pAnInfo->AbilityMatchCnt = 0; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->AckMatch = AN_FALSE; + + RxConfig = 0; + } + + /* Save the last Config. */ + pAnInfo->RxConfig.AsUSHORT = RxConfig; + + /* Default return code. */ + AnRet = AUTONEG_STATUS_OK; + + /* Autoneg state machine as defined in 802.3z section 37.3.1.5. */ + switch(pAnInfo->State) + { + case AN_STATE_UNKNOWN: + if(pAnInfo->mr_an_enable || pAnInfo->mr_restart_an) + { + pAnInfo->CurrentTime_us = 0; + pAnInfo->State = AN_STATE_AN_ENABLE; + } + + /* Fall through.*/ + + case AN_STATE_AN_ENABLE: + pAnInfo->mr_an_complete = AN_FALSE; + pAnInfo->mr_page_rx = AN_FALSE; + + if(pAnInfo->mr_an_enable) + { + pAnInfo->LinkTime_us = 0; + pAnInfo->AbilityMatchCfg = 0; + pAnInfo->AbilityMatchCnt = 0; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->IdleMatch = AN_FALSE; + pAnInfo->AckMatch = AN_FALSE; + + pAnInfo->State = AN_STATE_AN_RESTART_INIT; + } + else + { + pAnInfo->State = AN_STATE_DISABLE_LINK_OK; + } + break; + + case AN_STATE_AN_RESTART_INIT: + pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us; + pAnInfo->mr_np_loaded = AN_FALSE; + + pAnInfo->TxConfig.AsUSHORT = 0; + MM_AnTxConfig(pAnInfo); + + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + + pAnInfo->State = AN_STATE_AN_RESTART; + + /* Fall through.*/ + + case AN_STATE_AN_RESTART: + /* Get the current time and compute the delta with the saved */ + /* link timer. */ + Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us; + if(Delta_us > AN_LINK_TIMER_INTERVAL_US) + { + pAnInfo->State = AN_STATE_ABILITY_DETECT_INIT; + } + else + { + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + } + break; + + case AN_STATE_DISABLE_LINK_OK: + AnRet = AUTONEG_STATUS_DONE; + break; + + case AN_STATE_ABILITY_DETECT_INIT: + /* Note: in the state diagram, this variable is set to */ + /* mr_adv_ability<12>. Is this right?. */ + pAnInfo->mr_toggle_tx = AN_FALSE; + +#if DBG + DbgMessage(INFORM, ("TxConfig: ")); + + if(pAnInfo->mr_adv_full_duplex) + { + DbgMessage(INFORM, ("FD ")); + } + + if(pAnInfo->mr_adv_half_duplex) + { + DbgMessage(INFORM, ("HD ")); + } + + if(pAnInfo->mr_adv_sym_pause) + { + DbgMessage(INFORM, ("PS1 ")); + } + + if(pAnInfo->mr_adv_asym_pause) + { + DbgMessage(INFORM, ("PS2 ")); + } + + if(pAnInfo->mr_adv_remote_fault1) + { + DbgMessage(INFORM, ("RF1 ")); + } + + if(pAnInfo->mr_adv_remote_fault2) + { + DbgMessage(INFORM, ("RF2 ")); + } + + if(pAnInfo->mr_adv_next_page) + { + DbgMessage(INFORM, ("NP ")); + } + + DbgMessage(INFORM, ("\n")); +#endif + + /* Send the config as advertised in the advertisement register. */ + pAnInfo->TxConfig.AsUSHORT = 0; + pAnInfo->TxConfig.D5_FD = pAnInfo->mr_adv_full_duplex; + pAnInfo->TxConfig.D6_HD = pAnInfo->mr_adv_half_duplex; + pAnInfo->TxConfig.D7_PS1 = pAnInfo->mr_adv_sym_pause; + pAnInfo->TxConfig.D8_PS2 = pAnInfo->mr_adv_asym_pause; + pAnInfo->TxConfig.D12_RF1 = pAnInfo->mr_adv_remote_fault1; + pAnInfo->TxConfig.D13_RF2 = pAnInfo->mr_adv_remote_fault2; + pAnInfo->TxConfig.D15_NP = pAnInfo->mr_adv_next_page; + + MM_AnTxConfig(pAnInfo); + + pAnInfo->State = AN_STATE_ABILITY_DETECT; + + break; + + case AN_STATE_ABILITY_DETECT: + if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT != 0) + { + pAnInfo->State = AN_STATE_ACK_DETECT_INIT; + } + + break; + + case AN_STATE_ACK_DETECT_INIT: + pAnInfo->TxConfig.D14_ACK = 1; + MM_AnTxConfig(pAnInfo); + + pAnInfo->State = AN_STATE_ACK_DETECT; + + /* Fall through. */ + + case AN_STATE_ACK_DETECT: + if(pAnInfo->AckMatch == AN_TRUE) + { + if((pAnInfo->RxConfig.AsUSHORT & ~AN_CONFIG_ACK) == + (pAnInfo->AbilityMatchCfg & ~AN_CONFIG_ACK)) + { + pAnInfo->State = AN_STATE_COMPLETE_ACK_INIT; + } + else + { + DbgMessage(FATAL, ("1 ACK_DETECT ===> AN_ENABLE.\n")); + pAnInfo->State = AN_STATE_AN_ENABLE; + } + } + else if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT == 0) + { + DbgMessage(FATAL, ("2 ACK_DETECT ===> AN_ENABLE.\n")); + pAnInfo->State = AN_STATE_AN_ENABLE; + } + + break; + + case AN_STATE_COMPLETE_ACK_INIT: + /* Make sure invalid bits are not set. */ + if(pAnInfo->RxConfig.bits.D0 || pAnInfo->RxConfig.bits.D1 || + pAnInfo->RxConfig.bits.D2 || pAnInfo->RxConfig.bits.D3 || + pAnInfo->RxConfig.bits.D4 || pAnInfo->RxConfig.bits.D9 || + pAnInfo->RxConfig.bits.D10 || pAnInfo->RxConfig.bits.D11) + { + DbgMessage(FATAL, ("Received an invalid Config.\n")); + DbgBreak(); + AnRet = AUTONEG_STATUS_FAILED; + break; + } + + /* Set up the link partner advertisement register. */ + pAnInfo->mr_lp_adv_full_duplex = pAnInfo->RxConfig.D5_FD; + pAnInfo->mr_lp_adv_half_duplex = pAnInfo->RxConfig.D6_HD; + pAnInfo->mr_lp_adv_sym_pause = pAnInfo->RxConfig.D7_PS1; + pAnInfo->mr_lp_adv_asym_pause = pAnInfo->RxConfig.D8_PS2; + pAnInfo->mr_lp_adv_remote_fault1 = pAnInfo->RxConfig.D12_RF1; + pAnInfo->mr_lp_adv_remote_fault2 = pAnInfo->RxConfig.D13_RF2; + pAnInfo->mr_lp_adv_next_page = pAnInfo->RxConfig.D15_NP; +#if DBG + DbgMessage(INFORM, ("RxConfig: ")); + + if(pAnInfo->mr_lp_adv_full_duplex) + { + DbgMessage(INFORM, ("FD ")); + } + + if(pAnInfo->mr_lp_adv_half_duplex) + { + DbgMessage(INFORM, ("HD ")); + } + + if(pAnInfo->mr_lp_adv_sym_pause) + { + DbgMessage(INFORM, ("PS1 ")); + } + + if(pAnInfo->mr_lp_adv_asym_pause) + { + DbgMessage(INFORM, ("PS2 ")); + } + + if(pAnInfo->mr_lp_adv_remote_fault1) + { + DbgMessage(INFORM, ("RF1 ")); + } + + if(pAnInfo->mr_lp_adv_remote_fault2) + { + DbgMessage(INFORM, ("RF2 ")); + } + + if(pAnInfo->mr_lp_adv_next_page) + { + DbgMessage(INFORM, ("NP ")); + } + + DbgMessage(INFORM, ("\n")); +#endif + + pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us; + + pAnInfo->mr_toggle_tx = !pAnInfo->mr_toggle_tx; + pAnInfo->mr_toggle_rx = pAnInfo->RxConfig.bits.D11; + pAnInfo->mr_np_rx = pAnInfo->RxConfig.D15_NP; + pAnInfo->mr_page_rx = AN_TRUE; + + pAnInfo->State = AN_STATE_COMPLETE_ACK; + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + + break; + + case AN_STATE_COMPLETE_ACK: + if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT == 0) + { + DbgMessage(FATAL, ("COMPLETE_ACK ===> AN_ENABLE.\n")); + pAnInfo->State = AN_STATE_AN_ENABLE; + break; + } + + Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us; + + if(Delta_us > AN_LINK_TIMER_INTERVAL_US) + { + if(pAnInfo->mr_adv_next_page == 0 || + pAnInfo->mr_lp_adv_next_page == 0) + { + pAnInfo->State = AN_STATE_IDLE_DETECT_INIT; + } + else + { + if(pAnInfo->TxConfig.bits.D15 == 0 && + pAnInfo->mr_np_rx == 0) + { + pAnInfo->State = AN_STATE_IDLE_DETECT_INIT; + } + else + { + DbgMessage(FATAL, ("Next page not implemented.\n")); + DbgBreak(); + AnRet = AUTONEG_STATUS_FAILED; + } + } + } + + break; + + case AN_STATE_IDLE_DETECT_INIT: + pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us; + + MM_AnTxIdle(pAnInfo); + + pAnInfo->State = AN_STATE_IDLE_DETECT; + + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + + break; + + case AN_STATE_IDLE_DETECT: + if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT == 0) + { + DbgMessage(FATAL, ("IDLE_DETECT ===> AN_ENABLE.\n")); + pAnInfo->State = AN_STATE_AN_ENABLE; + break; + } + + Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us; + if(Delta_us > AN_LINK_TIMER_INTERVAL_US) + { +// if(pAnInfo->IdleMatch == AN_TRUE) +// { + pAnInfo->State = AN_STATE_LINK_OK; +// } +// else +// { +// DbgMessage(FATAL, ("Autoneg failed in IDLE_DETECT.\n")); +// AnRet = AUTONEG_STATUS_FAILED; +// break; +// } + } + + break; + + case AN_STATE_LINK_OK: + pAnInfo->mr_an_complete = AN_TRUE; + pAnInfo->mr_link_ok = AN_TRUE; + AnRet = AUTONEG_STATUS_DONE; + + break; + + case AN_STATE_NEXT_PAGE_WAIT_INIT: + DbgMessage(FATAL, ("Not implemented.\n")); + DbgBreak(); + break; + + case AN_STATE_NEXT_PAGE_WAIT: + DbgMessage(FATAL, ("Not implemented.\n")); + DbgBreak(); + break; + + default: + DbgMessage(FATAL, ("Invalid AN state.\n")); + DbgBreak(); + AnRet = AUTONEG_STATUS_FAILED; + break; + } + + return AnRet; +} +#endif /* INCLUDE_TBI_SUPPORT */ + diff -Nur linux-2.4.19/drivers/net/bcm/autoneg.h linux-2.4.19-sgi211r3/drivers/net/bcm/autoneg.h --- linux-2.4.19/drivers/net/bcm/autoneg.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/autoneg.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,416 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2001 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + + +#ifndef AUTONEG_H +#define AUTONEG_H + + + +/******************************************************************************/ +/* Constants. */ +/******************************************************************************/ + +#define AN_LINK_TIMER_INTERVAL_US 12000 /* 10ms */ + +/* TRUE, FALSE */ +#define AN_TRUE 1 +#define AN_FALSE 0 + + + +/******************************************************************************/ +/* Main data structure for keeping track of 802.3z auto-negotation state */ +/* variables as shown in Figure 37-6 of the IEEE 802.3z specification. */ +/******************************************************************************/ + +typedef struct +{ + /* Current auto-negotiation state. */ + unsigned long State; + #define AN_STATE_UNKNOWN 0 + #define AN_STATE_AN_ENABLE 1 + #define AN_STATE_AN_RESTART_INIT 2 + #define AN_STATE_AN_RESTART 3 + #define AN_STATE_DISABLE_LINK_OK 4 + #define AN_STATE_ABILITY_DETECT_INIT 5 + #define AN_STATE_ABILITY_DETECT 6 + #define AN_STATE_ACK_DETECT_INIT 7 + #define AN_STATE_ACK_DETECT 8 + #define AN_STATE_COMPLETE_ACK_INIT 9 + #define AN_STATE_COMPLETE_ACK 10 + #define AN_STATE_IDLE_DETECT_INIT 11 + #define AN_STATE_IDLE_DETECT 12 + #define AN_STATE_LINK_OK 13 + #define AN_STATE_NEXT_PAGE_WAIT_INIT 14 + #define AN_STATE_NEXT_PAGE_WAIT 16 + + /* Link timer. */ + unsigned long LinkTime_us; + + /* Current time. */ + unsigned long CurrentTime_us; + + /* Need these values for consistency check. */ + unsigned short AbilityMatchCfg; + + /* Ability, idle, and ack match functions. */ + unsigned long AbilityMatchCnt; + char AbilityMatch; + char IdleMatch; + char AckMatch; + + /* Tx config data */ + union + { + /* The TxConfig register is arranged as follows: */ + /* */ + /* MSB LSB */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + /* | D7| D6| D5| D4| D3| D2| D1| D0|D15|D14|D13|D12|D11|D10| D9| D8| */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + struct + { +#ifdef BIG_ENDIAN_HOST + unsigned short D7:1; /* PS1 */ + unsigned short D6:1; /* HD */ + unsigned short D5:1; /* FD */ + unsigned short D4:1; + unsigned short D3:1; + unsigned short D2:1; + unsigned short D1:1; + unsigned short D0:1; + unsigned short D15:1; /* NP */ + unsigned short D14:1; /* ACK */ + unsigned short D13:1; /* RF2 */ + unsigned short D12:1; /* RF1 */ + unsigned short D11:1; + unsigned short D10:1; + unsigned short D9:1; + unsigned short D8:1; /* PS2 */ +#else /* BIG_ENDIAN_HOST */ + unsigned int D8:1; /* PS2 */ + unsigned int D9:1; + unsigned int D10:1; + unsigned int D11:1; + unsigned int D12:1; /* RF1 */ + unsigned int D13:1; /* RF2 */ + unsigned int D14:1; /* ACK */ + unsigned int D15:1; /* NP */ + unsigned int D0:1; + unsigned int D1:1; + unsigned int D2:1; + unsigned int D3:1; + unsigned int D4:1; + unsigned int D5:1; /* FD */ + unsigned int D6:1; /* HD */ + unsigned int D7:1; /* PS1 */ +#endif + } bits; + + unsigned short AsUSHORT; + + #define D8_PS2 bits.D8 + #define D12_RF1 bits.D12 + #define D13_RF2 bits.D13 + #define D14_ACK bits.D14 + #define D15_NP bits.D15 + #define D5_FD bits.D5 + #define D6_HD bits.D6 + #define D7_PS1 bits.D7 + } TxConfig; + + /* Rx config data */ + union + { + /* The RxConfig register is arranged as follows: */ + /* */ + /* MSB LSB */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + /* | D7| D6| D5| D4| D3| D2| D1| D0|D15|D14|D13|D12|D11|D10| D9| D8| */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + struct + { +#ifdef BIG_ENDIAN_HOST + unsigned short D7:1; /* PS1 */ + unsigned short D6:1; /* HD */ + unsigned short D5:1; /* FD */ + unsigned short D4:1; + unsigned short D3:1; + unsigned short D2:1; + unsigned short D1:1; + unsigned short D0:1; + unsigned short D15:1; /* NP */ + unsigned short D14:1; /* ACK */ + unsigned short D13:1; /* RF2 */ + unsigned short D12:1; /* RF1 */ + unsigned short D11:1; + unsigned short D10:1; + unsigned short D9:1; + unsigned short D8:1; /* PS2 */ +#else /* BIG_ENDIAN_HOST */ + unsigned int D8:1; /* PS2 */ + unsigned int D9:1; + unsigned int D10:1; + unsigned int D11:1; + unsigned int D12:1; /* RF1 */ + unsigned int D13:1; /* RF2 */ + unsigned int D14:1; /* ACK */ + unsigned int D15:1; /* NP */ + unsigned int D0:1; + unsigned int D1:1; + unsigned int D2:1; + unsigned int D3:1; + unsigned int D4:1; + unsigned int D5:1; /* FD */ + unsigned int D6:1; /* HD */ + unsigned int D7:1; /* PS1 */ +#endif + } bits; + + unsigned short AsUSHORT; + } RxConfig; + + #define AN_CONFIG_NP 0x0080 + #define AN_CONFIG_ACK 0x0040 + #define AN_CONFIG_RF2 0x0020 + #define AN_CONFIG_RF1 0x0010 + #define AN_CONFIG_PS2 0x0001 + #define AN_CONFIG_PS1 0x8000 + #define AN_CONFIG_HD 0x4000 + #define AN_CONFIG_FD 0x2000 + + + /* Management registers. */ + + /* Control register. */ + union + { + struct + { + unsigned int an_enable:1; + unsigned int loopback:1; + unsigned int reset:1; + unsigned int restart_an:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_an_enable Mr0.bits.an_enable + #define mr_loopback Mr0.bits.loopback + #define mr_main_reset Mr0.bits.reset + #define mr_restart_an Mr0.bits.restart_an + } Mr0; + + /* Status register. */ + union + { + struct + { + unsigned int an_complete:1; + unsigned int link_ok:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_an_complete Mr1.bits.an_complete + #define mr_link_ok Mr1.bits.link_ok + } Mr1; + + /* Advertisement register. */ + union + { + struct + { + unsigned int reserved_4:5; + unsigned int full_duplex:1; + unsigned int half_duplex:1; + unsigned int sym_pause:1; + unsigned int asym_pause:1; + unsigned int reserved_11:3; + unsigned int remote_fault1:1; + unsigned int remote_fault2:1; + unsigned int reserved_14:1; + unsigned int next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_adv_full_duplex Mr4.bits.full_duplex + #define mr_adv_half_duplex Mr4.bits.half_duplex + #define mr_adv_sym_pause Mr4.bits.sym_pause + #define mr_adv_asym_pause Mr4.bits.asym_pause + #define mr_adv_remote_fault1 Mr4.bits.remote_fault1 + #define mr_adv_remote_fault2 Mr4.bits.remote_fault2 + #define mr_adv_next_page Mr4.bits.next_page + } Mr4; + + /* Link partner advertisement register. */ + union + { + struct + { + unsigned int reserved_4:5; + unsigned int lp_full_duplex:1; + unsigned int lp_half_duplex:1; + unsigned int lp_sym_pause:1; + unsigned int lp_asym_pause:1; + unsigned int reserved_11:3; + unsigned int lp_remote_fault1:1; + unsigned int lp_remote_fault2:1; + unsigned int lp_ack:1; + unsigned int lp_next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_lp_adv_full_duplex Mr5.bits.lp_full_duplex + #define mr_lp_adv_half_duplex Mr5.bits.lp_half_duplex + #define mr_lp_adv_sym_pause Mr5.bits.lp_sym_pause + #define mr_lp_adv_asym_pause Mr5.bits.lp_asym_pause + #define mr_lp_adv_remote_fault1 Mr5.bits.lp_remote_fault1 + #define mr_lp_adv_remote_fault2 Mr5.bits.lp_remote_fault2 + #define mr_lp_adv_next_page Mr5.bits.lp_next_page + } Mr5; + + /* Auto-negotiation expansion register. */ + union + { + struct + { + unsigned int reserved_0:1; + unsigned int page_received:1; + unsigned int next_pageable:1; + unsigned int reserved_15:13; + } bits; + + unsigned short AsUSHORT; + } Mr6; + + /* Auto-negotiation next page transmit register. */ + union + { + struct + { + unsigned int code_field:11; + unsigned int toggle:1; + unsigned int ack2:1; + unsigned int message_page:1; + unsigned int reserved_14:1; + unsigned int next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_np_tx Mr7.AsUSHORT + } Mr7; + + /* Auto-negotiation link partner ability register. */ + union + { + struct + { + unsigned int code_field:11; + unsigned int toggle:1; + unsigned int ack2:1; + unsigned int message_page:1; + unsigned int ack:1; + unsigned int next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_lp_np_rx Mr8.AsUSHORT + } Mr8; + + /* Extended status register. */ + union + { + struct + { + unsigned int reserved_11:12; + unsigned int base1000_t_hd:1; + unsigned int base1000_t_fd:1; + unsigned int base1000_x_hd:1; + unsigned int base1000_x_fd:1; + } bits; + + unsigned short AsUSHORT; + } Mr15; + + /* Miscellaneous state variables. */ + union + { + struct + { + unsigned int toggle_tx:1; + unsigned int toggle_rx:1; + unsigned int np_rx:1; + unsigned int page_rx:1; + unsigned int np_loaded:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_toggle_tx MrMisc.bits.toggle_tx + #define mr_toggle_rx MrMisc.bits.toggle_rx + #define mr_np_rx MrMisc.bits.np_rx + #define mr_page_rx MrMisc.bits.page_rx + #define mr_np_loaded MrMisc.bits.np_loaded + } MrMisc; + + + /* Implement specifics */ + + /* Pointer to the operating system specific data structure. */ + void *pContext; +} AN_STATE_INFO, *PAN_STATE_INFO; + + + +/******************************************************************************/ +/* Return code of Autoneg8023z. */ +/******************************************************************************/ + +typedef enum +{ + AUTONEG_STATUS_OK = 0, + AUTONEG_STATUS_DONE = 1, + AUTONEG_STATUS_TIMER_ENABLED = 2, +// AUTONEG_STATUS_FAILED = 0xffffffff, + AUTONEG_STATUS_FAILED = 0xfffffff +} AUTONEG_STATUS, *PAUTONEG_STATUS; + + + +/******************************************************************************/ +/* Function prototypes. */ +/******************************************************************************/ + +AUTONEG_STATUS Autoneg8023z(PAN_STATE_INFO pAnInfo); +void AutonegInit(PAN_STATE_INFO pAnInfo); + + + +/******************************************************************************/ +/* The following functions are defined in the os-dependent module. */ +/******************************************************************************/ + +void MM_AnTxConfig(PAN_STATE_INFO pAnInfo); +void MM_AnTxIdle(PAN_STATE_INFO pAnInfo); +char MM_AnRxConfig(PAN_STATE_INFO pAnInfo, unsigned short *pRxConfig); + + + +#endif /* AUTONEG_H */ + diff -Nur linux-2.4.19/drivers/net/bcm/b57proc.c linux-2.4.19-sgi211r3/drivers/net/bcm/b57proc.c --- linux-2.4.19/drivers/net/bcm/b57proc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/b57proc.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,334 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* /proc file system handling code. */ +/* */ +/******************************************************************************/ + +#include "mm.h" +#ifdef CONFIG_PROC_FS + +#define NICINFO_PROC_DIR "nicinfo" + +static struct proc_dir_entry *bcm5700_procfs_dir; + +extern char bcm5700_driver[], bcm5700_version[]; + +extern LM_UINT32 bcm5700_crc_count(PUM_DEVICE_BLOCK pUmDevice); + +static struct proc_dir_entry * +proc_getdir(char *name, struct proc_dir_entry *proc_dir) +{ + struct proc_dir_entry *pde = proc_dir; + + lock_kernel(); + for (pde=pde->subdir; pde; pde = pde->next) { + if (pde->namelen && (strcmp(name, pde->name) == 0)) { + /* directory exists */ + break; + } + } + if (pde == (struct proc_dir_entry *) 0) + { + /* create the directory */ +#if (LINUX_VERSION_CODE > 0x20300) + pde = proc_mkdir(name, proc_dir); +#else + pde = create_proc_entry(name, S_IFDIR, proc_dir); +#endif + if (pde == (struct proc_dir_entry *) 0) { + unlock_kernel(); + return (pde); + } + } + unlock_kernel(); + return (pde); +} + +int +bcm5700_proc_create(void) +{ + bcm5700_procfs_dir = proc_getdir(NICINFO_PROC_DIR, proc_net); + + if (bcm5700_procfs_dir == (struct proc_dir_entry *) 0) { + printk(KERN_DEBUG "Could not create procfs nicinfo directory %s\n", NICINFO_PROC_DIR); + return -1; + } + return 0; +} + +int +bcm5700_read_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + struct net_device *dev = (struct net_device *) data; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt; + int len = 0; + LM_UINT32 rx_mac_errors, rx_crc_errors, rx_align_errors; + LM_UINT32 rx_runt_errors, rx_frag_errors, rx_long_errors; + LM_UINT32 rx_overrun_errors, rx_jabber_errors; + + if (pUmDevice->opened == 0) + pStats = 0; + + len += sprintf(page+len, "Description\t\t\t%s\n", pUmDevice->name); + len += sprintf(page+len, "Driver_Name\t\t\t%s\n", bcm5700_driver); + len += sprintf(page+len, "Driver_Version\t\t\t%s\n", bcm5700_version); + len += sprintf(page+len, "Bootcode_Version\t\t%s\n", pDevice->BootCodeVer); + len += sprintf(page+len, "PCI_Vendor\t\t\t0x%04x\n", pDevice->PciVendorId); + len += sprintf(page+len, "PCI_Device_ID\t\t\t0x%04x\n", + pDevice->PciDeviceId); + len += sprintf(page+len, "PCI_Subsystem_Vendor\t\t0x%04x\n", + pDevice->SubsystemVendorId); + len += sprintf(page+len, "PCI_Subsystem_ID\t\t0x%04x\n", + pDevice->SubsystemId); + len += sprintf(page+len, "PCI_Revision_ID\t\t\t0x%02x\n", + pDevice->PciRevId); + len += sprintf(page+len, "PCI_Slot\t\t\t%d\n", + PCI_SLOT(pUmDevice->pdev->devfn)); + len += sprintf(page+len, "PCI_Bus\t\t\t\t%d\n", + pUmDevice->pdev->bus->number); + + len += sprintf(page+len, "PCI_Bus_Speed\t\t\t%s\n", + pDevice->BusSpeedStr); + + len += sprintf(page+len, "Memory\t\t\t\t0x%lx\n", pUmDevice->dev->base_addr); + len += sprintf(page+len, "IRQ\t\t\t\t%d\n", dev->irq); + len += sprintf(page+len, "System_Device_Name\t\t%s\n", dev->name); + len += sprintf(page+len, "Current_HWaddr\t\t\t%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + len += sprintf(page+len, + "Permanent_HWaddr\t\t%02x:%02x:%02x:%02x:%02x:%02x\n", + pDevice->NodeAddress[0], pDevice->NodeAddress[1], + pDevice->NodeAddress[2], pDevice->NodeAddress[3], + pDevice->NodeAddress[4], pDevice->NodeAddress[5]); + len += sprintf(page+len, "Part_Number\t\t\t%s\n\n", pDevice->PartNo); + + len += sprintf(page+len, "Link\t\t\t\t%s\n", + (pUmDevice->opened == 0) ? "unknown" : + ((pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) ? "up" : + "down")); + len += sprintf(page+len, "Speed\t\t\t\t%s\n", + ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || + (pUmDevice->opened == 0)) ? "N/A" : + ((pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) ? "1000" : + ((pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) ? "100" : + (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) ? "10" : "N/A"))); + len += sprintf(page+len, "Duplex\t\t\t\t%s\n", + ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || + (pUmDevice->opened == 0)) ? "N/A" : + ((pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) ? "full" : + "half")); + len += sprintf(page+len, "Flow_Control\t\t\t%s\n", + ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || + (pUmDevice->opened == 0)) ? "N/A" : + ((pDevice->FlowControl == LM_FLOW_CONTROL_NONE) ? "off" : + (((pDevice->FlowControl & LM_FLOW_CONTROL_RX_TX_PAUSE) == + LM_FLOW_CONTROL_RX_TX_PAUSE) ? "receive/transmit" : + (pDevice->FlowControl & LM_FLOW_CONTROL_RECEIVE_PAUSE) ? + "receive" : "transmit"))); + len += sprintf(page+len, "State\t\t\t\t%s\n", + (dev->flags & IFF_UP) ? "up" : "down"); + len += sprintf(page+len, "MTU_Size\t\t\t%d\n\n", dev->mtu); + len += sprintf(page+len, "Rx_Packets\t\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->ifHCInUcastPkts.Low + + pStats->ifHCInMulticastPkts.Low + + pStats->ifHCInBroadcastPkts.Low)); + if (dev->mtu > 1500) { + len += sprintf(page+len, "Rx_Jumbo_Packets\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->etherStatsPkts1523Octetsto2047Octets.Low + + pStats->etherStatsPkts2048Octetsto4095Octets.Low + + pStats->etherStatsPkts4096Octetsto8191Octets.Low + + pStats->etherStatsPkts8192Octetsto9022Octets.Low)); + } + len += sprintf(page+len, "Tx_Packets\t\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->COSIfHCOutPkts[0].Low)); + len += sprintf(page+len, "Rx_Bytes\t\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->ifHCInOctets.Low)); + len += sprintf(page+len, "Tx_Bytes\t\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->ifHCOutOctets.Low)); + if (pStats == 0) { + rx_crc_errors = 0; + rx_align_errors = 0; + rx_runt_errors = 0; + rx_frag_errors = 0; + rx_long_errors = 0; + rx_overrun_errors = 0; + rx_jabber_errors = 0; + } + else { + rx_crc_errors = bcm5700_crc_count(pUmDevice); + rx_align_errors = pStats->dot3StatsAlignmentErrors.Low; + rx_runt_errors = pStats->etherStatsUndersizePkts.Low; + rx_frag_errors = pStats->etherStatsFragments.Low; + rx_long_errors = pStats->dot3StatsFramesTooLong.Low; + rx_overrun_errors = pStats->nicNoMoreRxBDs.Low; + rx_jabber_errors = pStats->etherStatsJabbers.Low; + } + rx_mac_errors = rx_crc_errors + rx_align_errors + rx_runt_errors + + rx_frag_errors + rx_long_errors + rx_jabber_errors; + len += sprintf(page+len, "Rx_Errors\t\t\t%u\n", + ((pStats == 0) ? 0 : + rx_mac_errors + rx_overrun_errors + pUmDevice->rx_misc_errors)); + len += sprintf(page+len, "Tx_Errors\t\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->ifOutErrors.Low)); + len += sprintf(page+len, "\nTx_Carrier_Errors\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->dot3StatsCarrierSenseErrors.Low)); + len += sprintf(page+len, "Tx_Abort_Excess_Coll\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->dot3StatsExcessiveCollisions.Low)); + len += sprintf(page+len, "Tx_Abort_Late_Coll\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->dot3StatsLateCollisions.Low)); + len += sprintf(page+len, "Tx_Deferred_Ok\t\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->dot3StatsDeferredTransmissions.Low)); + len += sprintf(page+len, "Tx_Single_Coll_Ok\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->dot3StatsSingleCollisionFrames.Low)); + len += sprintf(page+len, "Tx_Multi_Coll_Ok\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->dot3StatsMultipleCollisionFrames.Low)); + len += sprintf(page+len, "Tx_Total_Coll_Ok\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->etherStatsCollisions.Low)); + len += sprintf(page+len, "\nRx_CRC_Errors\t\t\t%u\n", rx_crc_errors); + len += sprintf(page+len, "Rx_Short_Fragment_Errors\t%u\n", + rx_frag_errors); + len += sprintf(page+len, "Rx_Short_Length_Errors\t\t%u\n", + rx_runt_errors); + len += sprintf(page+len, "Rx_Long_Length_Errors\t\t%u\n", + rx_long_errors); + len += sprintf(page+len, "Rx_Align_Errors\t\t\t%u\n", + rx_align_errors); + len += sprintf(page+len, "Rx_Overrun_Errors\t\t%u\n", + rx_overrun_errors); + len += sprintf(page+len, "\nTx_MAC_Errors\t\t\t%u\n", + ((pStats == 0) ? 0 : + pStats->dot3StatsInternalMacTransmitErrors.Low)); + len += sprintf(page+len, "Rx_MAC_Errors\t\t\t%u\n\n", + rx_mac_errors); + + len += sprintf(page+len, "Tx_Checksum\t\t\t%s\n", + ((pDevice->TaskToOffload & LM_TASK_OFFLOAD_TX_TCP_CHECKSUM) ? + "ON" : "OFF")); + len += sprintf(page+len, "Rx_Checksum\t\t\t%s\n", + ((pDevice->TaskToOffload & LM_TASK_OFFLOAD_RX_TCP_CHECKSUM) ? + "ON" : "OFF")); + len += sprintf(page+len, "Scatter_Gather\t\t\t%s\n", +#if (LINUX_VERSION_CODE >= 0x20400) + ((dev->features & NETIF_F_SG) ? "ON" : "OFF")); +#else + "OFF"); +#endif + len += sprintf(page+len, "Tx_Desc_Count\t\t\t%u\n", + pDevice->TxPacketDescCnt); + len += sprintf(page+len, "Rx_Desc_Count\t\t\t%u\n", + pDevice->RxStdDescCnt); + len += sprintf(page+len, "Rx_Jumbo_Desc_Count\t\t%u\n", + pDevice->RxJumboDescCnt); + len += sprintf(page+len, "Adaptive_Coalescing\t\t%s\n", + (pUmDevice->adaptive_coalesce ? "ON" : "OFF")); + len += sprintf(page+len, "Rx_Coalescing_Ticks\t\t%u\n", + pUmDevice->rx_curr_coalesce_ticks); + len += sprintf(page+len, "Rx_Coalesced_Frames\t\t%u\n", + pUmDevice->rx_curr_coalesce_frames); + len += sprintf(page+len, "Tx_Coalescing_Ticks\t\t%u\n", + pDevice->TxCoalescingTicks); + len += sprintf(page+len, "Tx_Coalesced_Frames\t\t%u\n", + pUmDevice->tx_curr_coalesce_frames); + len += sprintf(page+len, "Stats_Coalescing_Ticks\t\t%u\n", + pDevice->StatsCoalescingTicks); + len += sprintf(page+len, "Wake_On_LAN\t\t\t%s\n", + ((pDevice->WakeUpMode & LM_WAKE_UP_MODE_MAGIC_PACKET) ? + "ON" : "OFF")); +#if TIGON3_DEBUG + len += sprintf(page+len, "\nDmaReadWriteCtrl\t\t%x\n", + pDevice->DmaReadWriteCtrl); + len += sprintf(page+len, "\nTx_Zero_Copy_Packets\t\t%u\n", + pUmDevice->tx_zc_count); + len += sprintf(page+len, "Tx_Chksum_Packets\t\t%u\n", + pUmDevice->tx_chksum_count); + len += sprintf(page+len, "Tx_Highmem_Fragments\t\t%u\n", + pUmDevice->tx_himem_count); + len += sprintf(page+len, "Rx_Good_Chksum_Packets\t\t%u\n", + pUmDevice->rx_good_chksum_count); + len += sprintf(page+len, "Rx_Bad_Chksum_Packets\t\t%u\n", + pUmDevice->rx_bad_chksum_count); + if (!pDevice->EnableTbi) { + LM_UINT32 value32; + + LM_ReadPhy(pDevice, 0, &value32); + len += sprintf(page+len, "\nPhy_Register_0x00\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 1, &value32); + len += sprintf(page+len, "Phy_Register_0x01\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 2, &value32); + len += sprintf(page+len, "Phy_Register_0x02\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 3, &value32); + len += sprintf(page+len, "Phy_Register_0x03\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 4, &value32); + len += sprintf(page+len, "Phy_Register_0x04\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 5, &value32); + len += sprintf(page+len, "Phy_Register_0x05\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 9, &value32); + len += sprintf(page+len, "Phy_Register_0x09\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 0xa, &value32); + len += sprintf(page+len, "Phy_Register_0x0A\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 0xf, &value32); + len += sprintf(page+len, "Phy_Register_0x0F\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 0x10, &value32); + len += sprintf(page+len, "Phy_Register_0x10\t\t0x%x\n", value32); + LM_ReadPhy(pDevice, 0x19, &value32); + len += sprintf(page+len, "Phy_Register_0x19\t\t0x%x\n", value32); + } +#endif + + *eof = 1; + return len; +} + +int +bcm5700_proc_create_dev(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + if (!bcm5700_procfs_dir) + return -1; + + sprintf(pUmDevice->pfs_name, "%s.info", dev->name); + pUmDevice->pfs_entry = create_proc_entry(pUmDevice->pfs_name, + S_IFREG, bcm5700_procfs_dir); + if (pUmDevice->pfs_entry == 0) + return -1; + pUmDevice->pfs_entry->read_proc = bcm5700_read_pfs; + pUmDevice->pfs_entry->data = dev; + return 0; +} +int +bcm5700_proc_remove_dev(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + remove_proc_entry(pUmDevice->pfs_name, bcm5700_procfs_dir); + return 0; +} + +#endif diff -Nur linux-2.4.19/drivers/net/bcm/b57um.c linux-2.4.19-sgi211r3/drivers/net/bcm/b57um.c --- linux-2.4.19/drivers/net/bcm/b57um.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/b57um.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,3106 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2001 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/******************************************************************************/ + + +char bcm5700_driver[] = "bcm5700"; +char bcm5700_version[] = "2.2.27"; +char bcm5700_date[] = "(07/03/02)"; + +#define B57UM +#include "mm.h" + +#define TASKLET + +/* A few user-configurable values. */ + +#define MAX_UNITS 16 +/* Used to pass the full-duplex flag, etc. */ +static int line_speed[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static int auto_speed[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int full_duplex[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int rx_flow_control[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static int tx_flow_control[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static int auto_flow_control[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static int mtu[MAX_UNITS] = {1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500}; /* Jumbo MTU for interfaces. */ +static int tx_checksum[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int rx_checksum[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int scatter_gather[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + +#define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT +static unsigned int tx_pkt_desc_cnt[MAX_UNITS] = + {TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, + TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, + TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, + TX_DESC_CNT}; + +#define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT +static unsigned int rx_std_desc_cnt[MAX_UNITS] = + {RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT, + RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT, + RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT, + RX_DESC_CNT }; + +#define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT +static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] = + {JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT, + JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT, + JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT, + JBO_DESC_CNT }; + +#if INCLUDE_EXT_MEMORY_SUPPORT +#define MIN_DESC_CNT DEFAULT_MINI_RCV_DESC_COUNT +static unsigned int rx_mini_desc_cnt[MAX_UNITS] = + {MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT, + MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT, + MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT,MIN_DESC_CNT, + MIN_DESC_CNT }; + +#endif +static unsigned int adaptive_coalesce[MAX_UNITS] = + {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + +#define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS +static unsigned int rx_coalesce_ticks[MAX_UNITS] = + {RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK, + RX_COAL_TK, RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK, + RX_COAL_TK,RX_COAL_TK, RX_COAL_TK,RX_COAL_TK,RX_COAL_TK, + RX_COAL_TK}; + +#define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES +static unsigned int rx_max_coalesce_frames[MAX_UNITS] = + {RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM, + RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM, + RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM, + RX_COAL_FM}; + +#define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS +static unsigned int tx_coalesce_ticks[MAX_UNITS] = + {TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK, + TX_COAL_TK, TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK, + TX_COAL_TK,TX_COAL_TK, TX_COAL_TK,TX_COAL_TK,TX_COAL_TK, + TX_COAL_TK}; + +#define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES +static unsigned int tx_max_coalesce_frames[MAX_UNITS] = + {TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM, + TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM, + TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM, + TX_COAL_FM}; + +#define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS +static unsigned int stats_coalesce_ticks[MAX_UNITS] = + {ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK, + ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK, + ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK, + ST_COAL_TK,}; + +static int enable_wol[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#if (LINUX_VERSION_CODE < 0x02030d) +#define pci_resource_start(dev, bar) (dev->base_address[bar] & PCI_BASE_ADDRESS_MEM_MASK) +#elif (LINUX_VERSION_CODE < 0x02032b) +#define pci_resource_start(dev, bar) (dev->resource[bar] & PCI_BASE_ADDRESS_MEM_MASK) +#endif + +#if (LINUX_VERSION_CODE < 0x02032b) +#define dev_kfree_skb_irq(skb) dev_kfree_skb(skb) +#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy); mark_bh(NET_BH) +#define netif_stop_queue(dev) set_bit(0, &dev->tbusy) + +static inline void netif_start_queue(struct net_device *dev) +{ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; +} + +#define netif_queue_stopped(dev) dev->tbusy +#define netif_running(dev) dev->start + +static inline void tasklet_schedule(struct tasklet_struct *tasklet) +{ + queue_task(tasklet, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static inline void tasklet_init(struct tasklet_struct *tasklet, + void (*func)(unsigned long), + unsigned long data) +{ + tasklet->next = NULL; + tasklet->sync = 0; + tasklet->routine = (void (*)(void *))func; + tasklet->data = (void *)data; +} + +#define tasklet_kill(tasklet) + +#endif + +#if (LINUX_VERSION_CODE < 0x020300) +struct pci_device_id { + unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ + unsigned long driver_data; /* Data private to the driver */ +}; + +#define PCI_ANY_ID 0 + +#define pci_set_drvdata(pdev, dev) +#define pci_get_drvdata(pdev) 0 + +#define pci_enable_device(pdev) 0 + +#define __devinit __init +#define __devinitdata __initdata +#define __devexit + +#define SET_MODULE_OWNER(dev) +#define MODULE_DEVICE_TABLE(pci, pci_tbl) + +#endif + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(license) +#endif + +#if (LINUX_VERSION_CODE < 0x02032a) +static inline void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, + dma_addr_t *dma_handle) +{ + void *virt_ptr; + + /* Maximum in slab.c */ + if (size > 131072) + return 0; + + virt_ptr = kmalloc(size, GFP_KERNEL); + *dma_handle = virt_to_bus(virt_ptr); + return virt_ptr; +} +#define pci_free_consistent(dev, size, ptr, dma_ptr) kfree(ptr) + +#define pci_map_single(dev, address, size, dir) virt_to_bus(address) +#define pci_unmap_single(dev, dma_addr, size, dir) + +#endif /*#if (LINUX_VERSION_CODE < 0x02032a) */ + +#if MAX_SKB_FRAGS +#if (LINUX_VERSION_CODE >= 0x02040d) + +typedef dma_addr_t dmaaddr_high_t; + +#else + +#if defined(CONFIG_HIGHMEM) && defined(CONFIG_X86) + +#if defined(CONFIG_HIGHMEM64G) +typedef unsigned long long dmaaddr_high_t; +#else +typedef dma_addr_t dmaaddr_high_t; +#endif + +#ifndef pci_map_page +#define pci_map_page bcm_pci_map_page +#endif + +static inline dmaaddr_high_t +bcm_pci_map_page(struct pci_dev *dev, struct page *page, + int offset, size_t size, int dir) +{ + dmaaddr_high_t phys; + + phys = (page-mem_map) * (dmaaddr_high_t) PAGE_SIZE + offset; + + return phys; +} + +#define pci_unmap_page(dev, map, size, dir) + +#else + +typedef dma_addr_t dmaaddr_high_t; + +/* Warning - This may not work for all architectures if HIGHMEM is defined */ + +#ifndef pci_map_page +#define pci_map_page(dev, page, offset, size, dir) \ + pci_map_single(dev, page_address(page) + (offset), size, dir) +#endif +#ifndef pci_unmap_page +#define pci_unmap_page(dev, map, size, dir) \ + pci_unmap_single(dev, map, size, dir) +#endif + +#endif /* #if defined(CONFIG_HIGHMEM) && defined(CONFIG_X86)*/ + +#endif /* #if (LINUX_VERSION_CODE >= 0x02040d)*/ +#endif /* #if MAX_SKB_FRAGS*/ + +#if (LINUX_VERSION_CODE < 0x020329) +#define pci_set_dma_mask(pdev, mask) (0) +#else +#if (LINUX_VERSION_CODE < 0x020403) +int +pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) +{ + if(! pci_dma_supported(dev, mask)) + return -EIO; + + dev->dma_mask = mask; + + return 0; +} +#endif +#endif + +#if (LINUX_VERSION_CODE < 0x020402) +#define pci_request_regions(pdev, name) (0) +#define pci_release_regions(pdev) +#endif + +#define set_64bit_addr(paddr, low, high) \ + (paddr)->Low = low; \ + (paddr)->High = high; + +static inline void bcm_set_addr(LM_PHYSICAL_ADDRESS *paddr, dma_addr_t addr) +{ + unsigned long baddr = (unsigned long) addr; +#if (BITS_PER_LONG == 64) + set_64bit_addr(paddr, baddr & 0xffffffff, baddr >> 32); +#else + set_64bit_addr(paddr, baddr, 0); +#endif +} + +#if defined (CONFIG_X86) +#define NO_PCI_UNMAP 1 +#endif + +#if (LINUX_VERSION_CODE < 0x020412) +#if ! defined (NO_PCI_UNMAP) +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME; + +#define pci_unmap_addr(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) + +#define pci_unmap_len(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) + +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) + +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) +#else +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(ADDR_NAME) + +#define pci_unmap_addr(PTR, ADDR_NAME) 0 +#define pci_unmap_len(PTR, LEN_NAME) 0 +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) +#endif +#endif + +#if MAX_SKB_FRAGS +static inline void bcm_set_addr_high(LM_PHYSICAL_ADDRESS *paddr, dmaaddr_high_t addr) +{ +#if defined(CONFIG_HIGHMEM64G) && defined(CONFIG_X86) + set_64bit_addr(paddr, (unsigned long) (addr & 0xffffffff), + (unsigned long) (addr >> 32)); +#else + bcm_set_addr(paddr, (dma_addr_t) addr); +#endif +} +#endif + +#if ! defined(spin_is_locked) +#define spin_is_locked(lock) (test_bit(0,(lock))) +#endif + +inline long +bcm5700_lock(PUM_DEVICE_BLOCK pUmDevice) +{ + long flags; + + if (pUmDevice->do_global_lock) { + spin_lock_irqsave(&pUmDevice->global_lock, flags); + return flags; + } + return 0; +} + +inline void +bcm5700_unlock(PUM_DEVICE_BLOCK pUmDevice, long flags) +{ + if (pUmDevice->do_global_lock) { + spin_unlock_irqrestore(&pUmDevice->global_lock, flags); + } +} + +inline int +bcm5700_trylock(PUM_DEVICE_BLOCK pUmDevice, long *flags) +{ + if (pUmDevice->do_global_lock) { + if (spin_is_locked(&pUmDevice->global_lock)) + return 0; + spin_lock_irqsave(&pUmDevice->global_lock, *flags); + return 1; + } + return 1; +} + +inline void +bcm5700_intr_lock(PUM_DEVICE_BLOCK pUmDevice) +{ + if (pUmDevice->do_global_lock) { + spin_lock(&pUmDevice->global_lock); + } +} + +inline void +bcm5700_intr_unlock(PUM_DEVICE_BLOCK pUmDevice) +{ + if (pUmDevice->do_global_lock) { + spin_unlock(&pUmDevice->global_lock); + } +} + +long +bcm5700_phy_lock(PUM_DEVICE_BLOCK pUmDevice) +{ + long flags; + + if (pUmDevice->do_global_lock) { + spin_lock_irqsave(&pUmDevice->global_lock, flags); + return flags; + } + else { + spin_lock_irqsave(&pUmDevice->phy_lock, flags); + return flags; + } + return 0; +} + +void +bcm5700_phy_unlock(PUM_DEVICE_BLOCK pUmDevice, long flags) +{ + if (pUmDevice->do_global_lock) { + spin_unlock_irqrestore(&pUmDevice->global_lock, flags); + } + else { + spin_unlock_irqrestore(&pUmDevice->phy_lock, flags); + } +} + +void +bcm5700_intr_off(PUM_DEVICE_BLOCK pUmDevice) +{ + atomic_inc(&pUmDevice->intr_sem); + LM_DisableInterrupt(&pUmDevice->lm_dev); + synchronize_irq(); +} + +void +bcm5700_intr_on(PUM_DEVICE_BLOCK pUmDevice) +{ + if (atomic_dec_and_test(&pUmDevice->intr_sem)) { + LM_EnableInterrupt(&pUmDevice->lm_dev); + } +} + +/* + * Broadcom NIC Extension support + * -ffan + */ +#ifdef NICE_SUPPORT +#include "nicext.h" + +typedef struct { + ushort tag; + ushort signature; +} vlan_tag_t; + +#endif /* NICE_SUPPORT */ + +typedef struct _UM_PACKET { + LM_PACKET lm_packet; + struct sk_buff *skbuff; +#if MAX_SKB_FRAGS + DECLARE_PCI_UNMAP_ADDR(map[MAX_SKB_FRAGS + 1]) + DECLARE_PCI_UNMAP_LEN(map_len[MAX_SKB_FRAGS + 1]) +#else + DECLARE_PCI_UNMAP_ADDR(map[1]) + DECLARE_PCI_UNMAP_LEN(map_len[1]) +#endif + LM_FRAG_LIST frag_list; +#if MAX_SKB_FRAGS + LM_FRAG frag_list_bufs[MAX_SKB_FRAGS]; +#endif +} UM_PACKET, *PUM_PACKET; + +int MM_Packet_Desc_Size = sizeof(UM_PACKET); + +#if defined(MODULE) +MODULE_AUTHOR("Michael Chan "); +MODULE_DESCRIPTION("BCM5700 Driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM(line_speed, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(auto_speed, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(auto_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(mtu, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_checksum, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_checksum, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(scatter_gather, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_pkt_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_std_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_jumbo_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#if INCLUDE_EXT_MEMORY_SUPPORT +MODULE_PARM(rx_mini_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +MODULE_PARM(adaptive_coalesce, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_max_coalesce_frames, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_max_coalesce_frames, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(stats_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(enable_wol, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif + +#define RUN_AT(x) (jiffies + (x)) + +char kernel_version[] = UTS_RELEASE; + +#define PCI_SUPPORT_VER2 + +#if ! defined(CAP_NET_ADMIN) +#define capable(CAP_XXX) (suser()) +#endif + +#define tigon3_debug debug +#if TIGON3_DEBUG +static int tigon3_debug = TIGON3_DEBUG; +#else +static int tigon3_debug = 0; +#endif + + +#if DBG +#define STATIC +#else +#define STATIC static +#endif + +STATIC int bcm5700_open(struct net_device *dev); +STATIC void bcm5700_timer(unsigned long data); +STATIC void bcm5700_tx_timeout(struct net_device *dev); +STATIC int bcm5700_start_xmit(struct sk_buff *skb, struct net_device *dev); +STATIC void bcm5700_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +STATIC void bcm5700_tasklet(unsigned long data); +STATIC int bcm5700_close(struct net_device *dev); +STATIC struct net_device_stats *bcm5700_get_stats(struct net_device *dev); +STATIC int bcm5700_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +STATIC void bcm5700_set_rx_mode(struct net_device *dev); +STATIC int bcm5700_set_mac_addr(struct net_device *dev, void *p); +STATIC int replenish_rx_buffers(PUM_DEVICE_BLOCK pUmDevice); +STATIC int check_4G_boundary(PUM_DEVICE_BLOCK pUmDevice, PUM_PACKET pUmPacket); +STATIC int bcm5700_freemem(struct net_device *dev); +STATIC int bcm5700_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice); +#ifdef BCM_VLAN +STATIC void bcm5700_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp); +STATIC void bcm5700_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid); +#endif + + +/* A list of all installed bcm5700 devices. */ +static struct net_device *root_tigon3_dev = NULL; + +typedef enum { + BCM5700VIGIL = 0, + BCM5700A6, + BCM5700T6, + BCM5700A9, + BCM5700T9, + BCM5700, + BCM5701A5, + BCM5701T1, + BCM5701T8, + BCM5701A7, + BCM5701A10, + BCM5701A12, + BCM5701, + BCM5702, + BCM5703, + BCM5703A31, + TC996T, + TC996ST, + TC996SSX, + TC996SX, + TC996BT, + TC997T, + TC997SX, + TC1000T, + TC940BR01, + TC942BR01, + NC6770, + NC7760, + NC7770, + NC7771, + NC7780, + NC7781, +} board_t; + + +/* indexed by board_t, above */ +static struct { + char *name; +} board_info[] __devinitdata = { + { "Broadcom Vigil B5700 1000Base-T" }, + { "Broadcom BCM5700 1000Base-T" }, + { "Broadcom BCM5700 1000Base-SX" }, + { "Broadcom BCM5700 1000Base-SX" }, + { "Broadcom BCM5700 1000Base-T" }, + { "Broadcom BCM5700" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-SX" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701" }, + { "Broadcom BCM5702 1000Base-T" }, + { "Broadcom BCM5703 1000Base-T" }, + { "Broadcom BCM5703 1000Base-SX" }, + { "3Com 3C996 10/100/1000 Server NIC" }, + { "3Com 3C996 10/100/1000 Server NIC" }, + { "3Com 3C996 Gigabit Fiber-SX Server NIC" }, + { "3Com 3C996 Gigabit Fiber-SX Server NIC" }, + { "3Com 3C996B Gigabit Server NIC" }, + { "3Com 3C997 Gigabit Server NIC" }, + { "3Com 3C997 Gigabit Fiber-SX Server NIC" }, + { "3Com 3C1000 Gigabit NIC" }, + { "3Com 3C940 Gigabit LOM (21X21)" }, + { "3Com 3C942 Gigabit LOM (31X31)" }, + { "Compaq NC6770 Gigabit Server Adapter" }, + { "Compaq NC7760 Gigabit Server Adapter" }, + { "Compaq NC7770 Gigabit Server Adapter" }, + { "Compaq NC7771 Gigabit Server Adapter" }, + { "Compaq NC7780 Gigabit Server Adapter" }, + { "Compaq NC7781 Gigabit Server Adapter" }, + { 0 }, + }; + +static struct pci_device_id bcm5700_pci_tbl[] __devinitdata = { + {0x14e4, 0x1644, 0x1014, 0x0277, 0, 0, BCM5700VIGIL }, + {0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6 }, + {0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6 }, + {0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9 }, + {0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9 }, + {0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T }, + {0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST }, + {0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX }, + {0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T }, + {0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX }, + {0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01 }, + {0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700 }, + {0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5 }, + {0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1 }, + {0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8 }, + {0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7 }, + {0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10 }, + {0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12 }, + {0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770 }, + {0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770 }, + {0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780 }, + {0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701 }, + {0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX }, + {0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT }, + {0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T }, + {0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01 }, + {0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701 }, + {0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702 }, + {0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 }, + {0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702 }, + {0x14e4, 0x16a6, 0x14e4, 0x000c, 0, 0, BCM5702 }, + {0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760 }, + {0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 }, + {0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703 }, + {0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31 }, + {0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703 }, + {0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703 }, + {0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31 }, + {0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x0e11, 0xca, 0, 0, NC7771 }, + {0x14e4, 0x16a7, 0x0e11, 0xcb, 0, 0, NC7781 }, + {0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 }, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, bcm5700_pci_tbl); + +#ifdef CONFIG_PROC_FS +extern int bcm5700_proc_create(void); +extern int bcm5700_proc_create_dev(struct net_device *dev); +extern int bcm5700_proc_remove_dev(struct net_device *dev); +#endif + +static int __devinit bcm5700_init_board(struct pci_dev *pdev, + struct net_device **dev_out, + int board_idx) +{ + struct net_device *dev; + PUM_DEVICE_BLOCK pUmDevice; + PLM_DEVICE_BLOCK pDevice; + int rc; + + *dev_out = NULL; + + /* dev zeroed in init_etherdev */ + dev = init_etherdev(NULL, sizeof(*pUmDevice)); + if (dev == NULL) { + printk (KERN_ERR "%s: unable to alloc new ethernet\n", + bcm5700_driver); + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + /* enable device (incl. PCI PM wakeup), and bus-mastering */ + rc = pci_enable_device (pdev); + if (rc) + goto err_out; + + rc = pci_request_regions(pdev, bcm5700_driver); + if (rc) + goto err_out; + + pci_set_master(pdev); + + if (pci_set_dma_mask(pdev, ~(0UL)) != 0) { + printk(KERN_ERR "System does not support DMA\n"); + pci_release_regions(pdev); + goto err_out; + } + + pUmDevice->dev = dev; + pUmDevice->pdev = pdev; + pUmDevice->mem_list_num = 0; + pUmDevice->next_module = root_tigon3_dev; + pUmDevice->index = board_idx; + root_tigon3_dev = dev; + + spin_lock_init(&pUmDevice->global_lock); + + spin_lock_init(&pUmDevice->undi_lock); + + spin_lock_init(&pUmDevice->phy_lock); + + pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + + if (mtu[board_idx] > 1500) { + if (mtu[board_idx] > 9000) { + dev->mtu = 9000; + printk(KERN_WARNING "%s: Invalid mtu parameter (%d), using 9000\n", dev->name, mtu[board_idx]); + } + else + dev->mtu = mtu[board_idx]; + } + else if (mtu[board_idx] < 1500) { + printk(KERN_WARNING "%s: Invalid mtu parameter (%d), using 1500\n", dev->name, mtu[board_idx]); + } + + if (pci_find_device(0x8086, 0x2418, NULL) || + pci_find_device(0x8086, 0x2428, NULL)) { + + /* Found ICH or ICH0 */ + pDevice->UndiFix = 1; + } + + if (LM_GetAdapterInfo(pDevice) != LM_STATUS_SUCCESS) { + printk(KERN_ERR "Get Adapter info failed\n"); + rc = -ENODEV; + goto err_out_unmap; + } + + if (pci_find_device(0x1022, 0x700c, NULL) && + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703)) { + /* AMD762 writes I/O out of order */ + /* Setting bit 1 in 762's register 0x4C still doesn't work */ + /* for 5703 */ + pDevice->UndiFix = 1; + pDevice->EnablePciXFix = TRUE; + pDevice->NicSendBd = FALSE; + } + + pUmDevice->do_global_lock = 0; + if (T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) { + /* The 5700 chip works best without interleaved register */ + /* accesses on certain machines. */ + pUmDevice->do_global_lock = 1; + } + if ((T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5701) && + ((pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) == 0)) { + + pUmDevice->rx_buf_align = 0; + } + else { + pUmDevice->rx_buf_align = 2; + } +/* dev->base_addr = pci_resource_start(pdev, 0);*/ + dev->mem_start = pci_resource_start(pdev, 0); + dev->mem_end = dev->mem_start + pDevice->MemBaseSize; + dev->irq = pDevice->Irq = pdev->irq; + + *dev_out = dev; + return 0; + +err_out_unmap: + pci_release_regions(pdev); + bcm5700_freemem(dev); + +err_out: + unregister_netdev(dev); + kfree (dev); + return rc; +} + +static int __devinit +bcm5700_print_ver(void) +{ + printk(KERN_INFO "Broadcom Gigabit Ethernet Driver %s ", + bcm5700_driver); +#ifdef NICE_SUPPORT + printk("with Broadcom NIC Extension (NICE) "); +#endif + printk("ver. %s %s\n", bcm5700_version, bcm5700_date); + return 0; +} + +static int __devinit +bcm5700_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev = NULL; + PUM_DEVICE_BLOCK pUmDevice; + PLM_DEVICE_BLOCK pDevice; + int i; + static int board_idx = -1; + static int printed_version = 0; + struct pci_dev *amd_dev; + + board_idx++; + + if (!printed_version) { + bcm5700_print_ver(); +#ifdef CONFIG_PROC_FS + bcm5700_proc_create(); +#endif + printed_version = 1; + } + + i = bcm5700_init_board(pdev, &dev, board_idx); + if (i < 0) { + return i; + } + + if (dev == NULL) + return -ENOMEM; + + dev->open = bcm5700_open; + dev->hard_start_xmit = bcm5700_start_xmit; + dev->stop = bcm5700_close; + dev->get_stats = bcm5700_get_stats; + dev->set_multicast_list = bcm5700_set_rx_mode; + dev->do_ioctl = bcm5700_ioctl; + dev->set_mac_address = &bcm5700_set_mac_addr; +#if (LINUX_VERSION_CODE >= 0x20400) + dev->tx_timeout = bcm5700_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif +#ifdef BCM_VLAN + dev->vlan_rx_register = &bcm5700_vlan_rx_register; + dev->vlan_rx_kill_vid = &bcm5700_vlan_rx_kill_vid; +#endif + + pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + + dev->base_addr = pci_resource_start(pdev, 0); + dev->irq = pdev->irq; + + pci_set_drvdata(pdev, dev); + + memcpy(dev->dev_addr, pDevice->NodeAddress, 6); + pUmDevice->name = board_info[ent->driver_data].name, + printk(KERN_INFO "%s: %s found at mem %lx, IRQ %d, ", + dev->name, pUmDevice->name, dev->base_addr, + dev->irq); + printk("node addr "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + } + printk("\n"); + + printk(KERN_INFO "%s: ", dev->name); + if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID) + printk("Broadcom BCM5400 Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + printk("Broadcom BCM5401 Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID) + printk("Broadcom BCM5411 Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID) + printk("Broadcom BCM5701 Integrated Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID) + printk("Broadcom BCM5703 Integrated Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID) + printk("Broadcom BCM8002 SerDes "); + else if (pDevice->EnableTbi) + printk("Agilent HDMP-1636 SerDes "); + else + printk("Unknown "); + printk("transceiver found\n"); + + printk(KERN_INFO "%s: ", dev->name); +#if (LINUX_VERSION_CODE >= 0x20400) + if (scatter_gather[board_idx]) { + dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA; + } + if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && + tx_checksum[board_idx]) { + dev->features |= NETIF_F_IP_CSUM; + } +#ifdef BCM_VLAN + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +#endif + + printk("Scatter-gather %s, 64-bit DMA %s, Tx Checksum %s, ", + (char *) ((dev->features & NETIF_F_SG) ? "ON" : "OFF"), + (char *) ((dev->features & NETIF_F_HIGHDMA) ? "ON" : "OFF"), + (char *) ((dev->features & NETIF_F_IP_CSUM) ? "ON" : "OFF")); +#endif + if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && + rx_checksum[board_idx]) + printk("Rx Checksum ON"); + else + printk("Rx Checksum OFF"); + +#ifdef BCM_VLAN + printk(", 802.1Q VLAN ON\n"); +#else + printk("\n"); +#endif +#ifdef CONFIG_PROC_FS + bcm5700_proc_create_dev(dev); +#endif +#ifdef TASKLET + tasklet_init(&pUmDevice->tasklet, bcm5700_tasklet, + (unsigned long) pUmDevice); +#endif + if ((amd_dev = pci_find_device(0x1022, 0x700c, NULL))) { + u32 val; + + /* Found AMD 762 North bridge */ + pci_read_config_dword(amd_dev, 0x4c, &val); + if ((val & 0x02) == 0) { + pci_write_config_dword(amd_dev, 0x4c, val | 0x02); + printk(KERN_INFO "%s: Setting AMD762 Northbridge to enable PCI ordering compliance\n", bcm5700_driver); + } + } + return 0; + +} + + +static void __devexit +bcm5700_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata (pdev); + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + +#ifdef CONFIG_PROC_FS + bcm5700_proc_remove_dev(dev); +#endif + unregister_netdev(dev); + + if (pUmDevice->lm_dev.pMappedMemBase) + iounmap(pUmDevice->lm_dev.pMappedMemBase); + + pci_release_regions(pdev); + + kfree(dev); + + pci_set_drvdata(pdev, NULL); + +/* pci_power_off(pdev, -1);*/ + +} + +int __devinit +bcm5700_probe(struct net_device *dev) +{ + int cards_found = 0; + struct pci_dev *pdev = NULL; + struct pci_device_id *pci_tbl; + u16 ssvid, ssid; + + if ( ! pci_present()) + return -ENODEV; + + pci_tbl = bcm5700_pci_tbl; + while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { + int idx; + + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &ssvid); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &ssid); + for (idx = 0; pci_tbl[idx].vendor; idx++) { + if ((pci_tbl[idx].vendor == PCI_ANY_ID || + pci_tbl[idx].vendor == pdev->vendor) && + (pci_tbl[idx].device == PCI_ANY_ID || + pci_tbl[idx].device == pdev->device) && + (pci_tbl[idx].subvendor == PCI_ANY_ID || + pci_tbl[idx].subvendor == ssvid) && + (pci_tbl[idx].subdevice == PCI_ANY_ID || + pci_tbl[idx].subdevice == ssid)) + { + + break; + } + } + if (pci_tbl[idx].vendor == 0) + continue; + + + if (bcm5700_init_one(pdev, &pci_tbl[idx]) == 0) + cards_found++; + } + + return cards_found ? 0 : -ENODEV; +} + + + +STATIC int +bcm5700_open(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + int index; + + index = pUmDevice->index; + if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) { + pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE; + } + else { + if (rx_checksum[index]) { + pDevice->TaskToOffload |= + LM_TASK_OFFLOAD_RX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_RX_UDP_CHECKSUM; + } + if (tx_checksum[index]) { + pDevice->TaskToOffload |= + LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_TX_UDP_CHECKSUM; + pDevice->NoTxPseudoHdrChksum = TRUE; + } + } + /* delay for 4 seconds */ + pUmDevice->delayed_link_ind = (4 * HZ) / pUmDevice->timer_interval; + + pUmDevice->adaptive_expiry = HZ / pUmDevice->timer_interval; + +#if INCLUDE_TBI_SUPPORT + if(pDevice->PollTbiLink) + pUmDevice->poll_tbi_expiry = HZ / pUmDevice->timer_interval; +#endif + + /* Sometimes we get spurious ints. after reset when link is down. */ + /* This field tells the isr to service the int. even if there is */ + /* no status block update. */ + if (pDevice->LedMode != LED_MODE_LINK10) { + pUmDevice->adapter_just_inited = (3 * HZ) / + pUmDevice->timer_interval; + } + else { + pUmDevice->adapter_just_inited = 0; + } + + if (request_irq(dev->irq, &bcm5700_interrupt, SA_SHIRQ, dev->name, dev)) { + return -EAGAIN; + } + + pUmDevice->opened = 1; +#if TIGON3_DEBUG + pUmDevice->tx_zc_count = 0; + pUmDevice->tx_chksum_count = 0; + pUmDevice->tx_himem_count = 0; + pUmDevice->rx_good_chksum_count = 0; + pUmDevice->rx_bad_chksum_count = 0; +#endif + if (LM_InitializeAdapter(pDevice) != LM_STATUS_SUCCESS) { + free_irq(dev->irq, dev); + bcm5700_freemem(dev); + return -EAGAIN; + } + if (pDevice->UndiFix) { + printk(KERN_INFO "%s: Using indirect register access\n", dev->name); + } + + if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) { + LM_SetMacAddress(pDevice, dev->dev_addr); + } + + if (tigon3_debug > 1) + printk(KERN_DEBUG "%s: tigon3_open() irq %d.\n", dev->name, dev->irq); + + QQ_InitQueue(&pUmDevice->rx_out_of_buf_q.Container, + MAX_RX_PACKET_DESC_COUNT); + netif_start_queue(dev); + +#if (LINUX_VERSION_CODE < 0x020300) + MOD_INC_USE_COUNT; +#endif + + init_timer(&pUmDevice->timer); + pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval); + pUmDevice->timer.data = (unsigned long)dev; + pUmDevice->timer.function = &bcm5700_timer; + add_timer(&pUmDevice->timer); + + atomic_set(&pUmDevice->intr_sem, 0); + LM_EnableInterrupt(pDevice); + + return 0; +} + +STATIC void +bcm5700_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + long flags; + LM_UINT32 value32; + + if (!pUmDevice->opened) + return; + + if (atomic_read(&pUmDevice->intr_sem)) { + pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval); + add_timer(&pUmDevice->timer); + return; + } +#if INCLUDE_TBI_SUPPORT + if(pDevice->PollTbiLink && (--pUmDevice->poll_tbi_expiry == 0)) { + flags = bcm5700_phy_lock(pUmDevice); + value32 = REG_RD(pDevice, MacCtrl.Status); + if (((pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) && + ((value32 & MAC_STATUS_LINK_STATE_CHANGED) || + !(value32 & MAC_STATUS_PCS_SYNCED))) + || + ((pDevice->LinkStatus != LM_STATUS_LINK_ACTIVE) && + (value32 & MAC_STATUS_PCS_SYNCED))) + { + LM_SetupPhy(pDevice); + } + bcm5700_phy_unlock(pUmDevice, flags); + pUmDevice->poll_tbi_expiry = HZ / pUmDevice->timer_interval; + + } +#endif + + if (pUmDevice->delayed_link_ind > 0) { + if (pUmDevice->delayed_link_ind == 1) + MM_IndicateStatus(pDevice, pDevice->LinkStatus); + else + pUmDevice->delayed_link_ind--; + } + if (pUmDevice->adapter_just_inited > 0) { + pUmDevice->adapter_just_inited--; + if (pDevice->EnableTbi && !pUmDevice->adapter_just_inited && + !atomic_read(&pUmDevice->intr_sem)) { + LM_EnableInterrupt(pDevice); + } + } + + if (pUmDevice->crc_counter_expiry > 0) + pUmDevice->crc_counter_expiry--; + + if (!pUmDevice->interrupt) { + if (!pDevice->UseTaggedStatus) { + flags = bcm5700_lock(pUmDevice); + if (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) { + /* This will generate an interrupt */ + REG_WR(pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_SET_INT); + } + else { + REG_WR(pDevice, HostCoalesce.Mode, + HOST_COALESCE_ENABLE | + HOST_COALESCE_NOW); + } + if (!(REG_RD(pDevice, DmaWrite.Mode) & + DMA_WRITE_MODE_ENABLE)) { + + bcm5700_unlock(pUmDevice, flags); + bcm5700_tx_timeout(dev); + } + else { + bcm5700_unlock(pUmDevice, flags); + } + if (pUmDevice->tx_queued) { + pUmDevice->tx_queued = 0; + netif_wake_queue(dev); + } + } +#if (LINUX_VERSION_CODE < 0x02032b) + if ((QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) != + pDevice->TxPacketDescCnt) && + ((jiffies - dev->trans_start) > TX_TIMEOUT)) { + + printk(KERN_WARNING "%s: Tx hung\n", dev->name); + bcm5700_tx_timeout(dev); + } +#endif + } + if (pUmDevice->adaptive_coalesce) { + pUmDevice->adaptive_expiry--; + if (pUmDevice->adaptive_expiry == 0) { + pUmDevice->adaptive_expiry = HZ / + pUmDevice->timer_interval; + bcm5700_adapt_coalesce(pUmDevice); + } + } + if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container) > + pUmDevice->rx_buf_repl_panic_thresh) { + /* Generate interrupt and let isr allocate buffers */ + REG_WR(pDevice, HostCoalesce.Mode, + HOST_COALESCE_ENABLE | HOST_COALESCE_NOW); + } + + pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval); + add_timer(&pUmDevice->timer); + pUmDevice->spurious_int = 0; +} + +STATIC int +bcm5700_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice) +{ + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + uint rx_curr_cnt, tx_curr_cnt, rx_delta, tx_delta, total_delta; + int adapt = 0; + long flags; + + rx_curr_cnt = pDevice->pStatsBlkVirt->ifHCInUcastPkts.Low; + tx_curr_cnt = pDevice->pStatsBlkVirt->COSIfHCOutPkts[0].Low; + if ((rx_curr_cnt <= pUmDevice->rx_last_cnt) || + (tx_curr_cnt <= pUmDevice->tx_last_cnt)) { + + /* skip if there is counter rollover */ + pUmDevice->rx_last_cnt = rx_curr_cnt; + pUmDevice->tx_last_cnt = tx_curr_cnt; + return 0; + } + + rx_delta = rx_curr_cnt - pUmDevice->rx_last_cnt; + tx_delta = tx_curr_cnt - pUmDevice->tx_last_cnt; + total_delta = rx_delta + tx_delta; + + pUmDevice->rx_last_cnt = rx_curr_cnt; + pUmDevice->tx_last_cnt = tx_curr_cnt; + + if (total_delta < rx_delta) + return 0; + + if (total_delta < ADAPTIVE_LO_PKT_THRESH) { + if (pUmDevice->rx_curr_coalesce_frames != + ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES) { + + if (!bcm5700_trylock(pUmDevice, &flags)) + return 0; + + adapt = 1; + + pUmDevice->rx_curr_coalesce_frames = + ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES; + pUmDevice->rx_curr_coalesce_ticks = + ADAPTIVE_LO_RX_COALESCING_TICKS; + pUmDevice->tx_curr_coalesce_frames = + ADAPTIVE_LO_TX_MAX_COALESCED_FRAMES; + + } + } + else if (total_delta < ADAPTIVE_HI_PKT_THRESH) { + if (pUmDevice->rx_curr_coalesce_frames != + DEFAULT_RX_MAX_COALESCED_FRAMES) { + + if (!bcm5700_trylock(pUmDevice, &flags)) + return 0; + + adapt = 1; + + pUmDevice->rx_curr_coalesce_frames = + DEFAULT_RX_MAX_COALESCED_FRAMES; + pUmDevice->rx_curr_coalesce_ticks = + DEFAULT_RX_COALESCING_TICKS; + pUmDevice->tx_curr_coalesce_frames = + DEFAULT_TX_MAX_COALESCED_FRAMES; + + } + } + else { + if (pUmDevice->rx_curr_coalesce_frames != + ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES) { + + if (!bcm5700_trylock(pUmDevice, &flags)) + return 0; + + adapt = 1; + + pUmDevice->rx_curr_coalesce_frames = + ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES; + pUmDevice->rx_curr_coalesce_ticks = + ADAPTIVE_HI_RX_COALESCING_TICKS; + pUmDevice->tx_curr_coalesce_frames = + ADAPTIVE_HI_TX_MAX_COALESCED_FRAMES; + + } + } + if (adapt) { + REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFrames, + pUmDevice->rx_curr_coalesce_frames); + + REG_WR(pDevice, HostCoalesce.RxCoalescingTicks, + pUmDevice->rx_curr_coalesce_ticks); + + REG_WR(pDevice, HostCoalesce.TxMaxCoalescedFrames, + pUmDevice->tx_curr_coalesce_frames); + bcm5700_unlock(pUmDevice, flags); + } + return 0; +} + +STATIC void +bcm5700_tx_timeout(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + long flags; + + netif_stop_queue(dev); + bcm5700_intr_off(pUmDevice); + flags = bcm5700_phy_lock(pUmDevice); + LM_ResetAdapter(pDevice); + if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) { + LM_SetMacAddress(pDevice, dev->dev_addr); + } + bcm5700_phy_unlock(pUmDevice, flags); + bcm5700_intr_on(pUmDevice); + netif_wake_queue(dev); +} + +#ifdef BCM_VLAN +STATIC void +bcm5700_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + bcm5700_intr_off(pUmDevice); + pUmDevice->vlgrp = vlgrp; + bcm5700_intr_on(pUmDevice); +} + +STATIC void +bcm5700_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + bcm5700_intr_off(pUmDevice); + if (pUmDevice->vlgrp) { + pUmDevice->vlgrp->vlan_devices[vid] = NULL; + } + bcm5700_intr_on(pUmDevice); +} +#endif + +STATIC int +bcm5700_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + PLM_FRAG_LIST pfrag_list; + long flags; + unsigned int len; + dma_addr_t map; +#if MAX_SKB_FRAGS + skb_frag_t *frag; + int i; + int frag_no; + dmaaddr_high_t hi_map; +#endif +#ifdef NICE_SUPPORT + vlan_tag_t *vlan_tag; +#endif + + if ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || !pDevice->InitDone) + { + dev_kfree_skb(skb); + return 0; + } + +#if (LINUX_VERSION_CODE < 0x02032b) + if (test_and_set_bit(0, &dev->tbusy)) { + return 1; + } +#endif + + if (pUmDevice->do_global_lock && pUmDevice->interrupt) { + netif_stop_queue(dev); + pUmDevice->tx_queued = 1; + if (!pUmDevice->interrupt) { + netif_wake_queue(dev); + pUmDevice->tx_queued = 0; + } + return 1; + } + + pPacket = (PLM_PACKET) + QQ_PopHead(&pDevice->TxPacketFreeQ.Container); + if (pPacket == 0) { + netif_stop_queue(dev); + pUmDevice->tx_full = 1; + if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container)) { + netif_wake_queue(dev); + pUmDevice->tx_full = 0; + } + return 1; + } + pUmPacket = (PUM_PACKET) pPacket; + pUmPacket->skbuff = skb; + pfrag_list = &pUmPacket->frag_list; + pPacket->u.Tx.pFraglist = pfrag_list; + if (skb->ip_summed == CHECKSUM_HW) { + pPacket->Flags = SND_BD_FLAG_TCP_UDP_CKSUM; +#if TIGON3_DEBUG + pUmDevice->tx_chksum_count++; +#endif + } + else { + pPacket->Flags = 0; + } +#if MAX_SKB_FRAGS + if ((frag_no = skb_shinfo(skb)->nr_frags)) + len = skb->len - skb->data_len; + else + len = skb->len; + if (atomic_read(&pDevice->SendBdLeft) < (frag_no + 1)) { + netif_stop_queue(dev); + pUmDevice->tx_full = 1; + QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket); + if (atomic_read(&pDevice->SendBdLeft) >= (frag_no + 1)) { + netif_wake_queue(dev); + pUmDevice->tx_full = 0; + } + return 1; + } +#else + len = skb->len; + if (atomic_read(&pDevice->SendBdLeft) == 0) { + netif_stop_queue(dev); + pUmDevice->tx_full = 1; + QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket); + if (atomic_read(&pDevice->SendBdLeft)) { + netif_wake_queue(dev); + pUmDevice->tx_full = 0; + } + return 1; + } +#endif + + pfrag_list->Fragments[0].FragSize = len; + map = pci_map_single(pUmDevice->pdev, skb->data, len, PCI_DMA_TODEVICE); + bcm_set_addr(&pfrag_list->Fragments[0].FragBuf, map); + pci_unmap_addr_set(pUmPacket, map[0], map); + pci_unmap_len_set(pUmPacket, map_len[0], len); + +#if MAX_SKB_FRAGS + pPacket->u.Tx.FragCount = frag_no + 1; +#if TIGON3_DEBUG + if (pPacket->u.Tx.FragCount > 1) + pUmDevice->tx_zc_count++; +#endif + for (i = 1; i < pPacket->u.Tx.FragCount; i++) { + frag = &skb_shinfo(skb)->frags[i - 1]; + + hi_map = pci_map_page(pUmDevice->pdev, + frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + + pci_unmap_addr_set(pUmPacket, map[i], hi_map); + pci_unmap_len_set(pUmPacket, map_len[i], frag->size); + bcm_set_addr_high(&pfrag_list->Fragments[i].FragBuf, hi_map); +#if TIGON3_DEBUG + if (pfrag_list->Fragments[i].FragBuf.High) + pUmDevice->tx_himem_count++; +#endif + pfrag_list->Fragments[i].FragSize = frag->size; + } +#else + pPacket->u.Tx.FragCount = 1; +#endif + + /* Work around 4GB dma problem */ + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) { + if (check_4G_boundary(pUmDevice, pUmPacket) == 0) { + QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket); +#if (LINUX_VERSION_CODE < 0x02032b) + netif_wake_queue(dev); +#endif + return 0; + } + skb = pUmPacket->skbuff; + } + +#ifdef BCM_VLAN + if (pUmDevice->vlgrp && vlan_tx_tag_present(skb)) { + pPacket->VlanTag = vlan_tx_tag_get(skb); + pPacket->Flags |= SND_BD_FLAG_VLAN_TAG; + } +#endif +#ifdef NICE_SUPPORT + vlan_tag = (vlan_tag_t *) &skb->cb[0]; + if (vlan_tag->signature == 0x5555) { + pPacket->VlanTag = vlan_tag->tag; + pPacket->Flags |= SND_BD_FLAG_VLAN_TAG; + vlan_tag->signature = 0; + } +#endif + flags = bcm5700_lock(pUmDevice); + LM_SendPacket(pDevice, pPacket); + bcm5700_unlock(pUmDevice, flags); + if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) == 0) { + netif_stop_queue(dev); + pUmDevice->tx_full = 1; + if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) != 0) { + netif_wake_queue(dev); + pUmDevice->tx_full = 0; + } + } +#if (LINUX_VERSION_CODE < 0x02032b) + else { + netif_wake_queue(dev); + } +#endif + dev->trans_start = jiffies; + return 0; +} + +STATIC +int +check_4G_boundary(PUM_DEVICE_BLOCK pUmDevice, PUM_PACKET pUmPacket) +{ + u32 base; + int i; + PLM_FRAG_LIST pfrag_list = &pUmPacket->frag_list; + PLM_FRAG pfrag; + struct sk_buff *skb, *nskb; + dma_addr_t map; + int do_copy = 0; + + /* Work around 4GB dma problem */ + for (i = 0; i < pUmPacket->lm_packet.u.Tx.FragCount; i++) { + pfrag = &pfrag_list->Fragments[i]; + + if (((base = pfrag->FragBuf.Low) > 0xffffdcc0) && + (pfrag->FragBuf.High == 0) && + ((base + 8 + pfrag->FragSize) < base)) { + + do_copy = 1; + break; + } + } + if (do_copy) { + skb = pUmPacket->skbuff; +#if ! defined(NO_PCI_UNMAP) + pci_unmap_single(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[0]), + pci_unmap_len(pUmPacket, map_len[0]), + PCI_DMA_TODEVICE); +#if MAX_SKB_FRAGS + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + pci_unmap_page(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[i + 1]), + pci_unmap_len(pUmPacket, map_len[i + 1]), + PCI_DMA_TODEVICE); + } +#endif +#endif + if ((nskb = skb_copy(skb, GFP_ATOMIC))) { + pfrag_list->Fragments[0].FragSize = nskb->len; + map = pci_map_single(pUmDevice->pdev, nskb->data, + nskb->len, PCI_DMA_TODEVICE); + bcm_set_addr(&pfrag_list->Fragments[0].FragBuf, map); + pci_unmap_addr_set(pUmPacket, map[0], map); + pci_unmap_len_set(pUmPacket, map_len[0], nskb->len); + pUmPacket->lm_packet.u.Tx.FragCount = 1; + } + dev_kfree_skb(skb); + pUmPacket->skbuff = nskb; + if (nskb == 0) { + return 0; + } + } + return 1; +} + +STATIC void +bcm5700_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + LM_UINT32 oldtag, newtag; + int repl_buf_count, i; + + if (!pDevice->InitDone) + return; + + if (atomic_read(&pUmDevice->intr_sem)) + return; + + bcm5700_intr_lock(pUmDevice); + if (test_and_set_bit(0, (void*)&pUmDevice->interrupt)) { + printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by " + "processor %d.\n", + dev->name, hard_smp_processor_id()); + bcm5700_intr_unlock(pUmDevice); + return; + } + + if (pDevice->UseTaggedStatus) { + if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) || + pUmDevice->adapter_just_inited) { + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1); + oldtag = pDevice->pStatusBlkVirt->StatusTag; + + for (i = 0; ; i++) { + pDevice->pStatusBlkVirt->Status &= + ~STATUS_BLOCK_UPDATED; + + LM_ServiceInterrupts(pDevice); + newtag = pDevice->pStatusBlkVirt->StatusTag; + if ((newtag == oldtag) || (i > 50)) { + MB_REG_WR(pDevice, + Mailbox.Interrupt[0].Low, + newtag << 24); + if (pDevice->UndiFix) { + REG_WR(pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | 0x2); + } + break; + } + oldtag = newtag; + } + } + } + else if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) || + pUmDevice->adapter_just_inited) { + do { + uint dummy; + + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1); + pDevice->pStatusBlkVirt->Status &= ~STATUS_BLOCK_UPDATED; + LM_ServiceInterrupts(pDevice); + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 0); + dummy = MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low); + } + while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED); + if (pDevice->UndiFix) { + REG_WR(pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | 0x2); + } + } + if (pUmDevice->adapter_just_inited && pDevice->EnableTbi) { + if (pDevice->LinkStatus != LM_STATUS_LINK_ACTIVE) { + pUmDevice->spurious_int++; + if (pUmDevice->spurious_int > 25) { + LM_DisableInterrupt(pDevice); + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_LINK_POLARITY); + MM_Wait(1); + pUmDevice->spurious_int = 0; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + if ((pUmDevice->adapter_just_inited == 0) && + !atomic_read(&pUmDevice->intr_sem)) { + LM_EnableInterrupt(pDevice); + } + } + } + } +#ifdef TASKLET + repl_buf_count = QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container); + if (repl_buf_count > pUmDevice->rx_buf_repl_thresh) { + if ((repl_buf_count > pUmDevice->rx_buf_repl_panic_thresh) && + (!test_and_set_bit(0, &pUmDevice->tasklet_busy))) { + replenish_rx_buffers(pUmDevice); + clear_bit(0, (void*)&pUmDevice->tasklet_busy); + } + else if (!pUmDevice->tasklet_pending) { + pUmDevice->tasklet_pending = 1; + tasklet_schedule(&pUmDevice->tasklet); + } + } +#else + if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) { + replenish_rx_buffers(pUmDevice); + } + + if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container)) { + LM_QueueRxPackets(pDevice); + } +#endif + + clear_bit(0, (void*)&pUmDevice->interrupt); + bcm5700_intr_unlock(pUmDevice); + if (pUmDevice->tx_queued) { + pUmDevice->tx_queued = 0; + netif_wake_queue(dev); + } + return; +} + + +STATIC void +bcm5700_tasklet(unsigned long data) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)data; + + /* RH 7.2 Beta 3 tasklets are reentrant */ + if (test_and_set_bit(0, &pUmDevice->tasklet_busy)) { + pUmDevice->tasklet_pending = 0; + return; + } + + pUmDevice->tasklet_pending = 0; + replenish_rx_buffers(pUmDevice); + clear_bit(0, &pUmDevice->tasklet_busy); +} + +STATIC int +bcm5700_close(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + +#if (LINUX_VERSION_CODE < 0x02032b) + dev->start = 0; +#endif + netif_stop_queue(dev); + pUmDevice->opened = 0; + + if (tigon3_debug > 1) + printk(KERN_DEBUG "%s: Shutting down Tigon3\n", + dev->name); + + bcm5700_intr_off(pUmDevice); + netif_carrier_off(dev); +#ifdef TASKLET +// tasklet_disable(&pUmDevice->tasklet); + tasklet_kill(&pUmDevice->tasklet); +#endif + LM_Halt(pDevice); + pDevice->InitDone = 0; + del_timer(&pUmDevice->timer); + + free_irq(dev->irq, dev); +#if (LINUX_VERSION_CODE < 0x020300) + MOD_DEC_USE_COUNT; +#endif + LM_SetPowerState(pDevice, LM_POWER_STATE_D3); + bcm5700_freemem(dev); + + return 0; +} + +STATIC int +bcm5700_freemem(struct net_device *dev) +{ + int i; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + + for (i = 0; i < pUmDevice->mem_list_num; i++) { + if (pUmDevice->mem_size_list[i] == 0) { + kfree(pUmDevice->mem_list[i]); + } + else { + pci_free_consistent(pUmDevice->pdev, + (size_t) pUmDevice->mem_size_list[i], + pUmDevice->mem_list[i], + pUmDevice->dma_list[i]); + } + } + pUmDevice->mem_list_num = 0; + return 0; +} + +LM_UINT32 +bcm5700_crc_count(PUM_DEVICE_BLOCK pUmDevice) +{ + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + LM_UINT32 Value32; + PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt; + unsigned long flags; + +#if INCLUDE_TBI_SUPPORT + if(pDevice->EnableTbi) + return (pStats->dot3StatsFCSErrors.Low); +#endif + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) { + + if (!pUmDevice->opened || pUmDevice->adapter_just_inited) + return 0; + + /* regulate MDIO access during run time */ + if (pUmDevice->crc_counter_expiry > 0) + return pDevice->PhyCrcCount; + + pUmDevice->crc_counter_expiry = (5 * HZ) / + pUmDevice->timer_interval; + + flags = bcm5700_phy_lock(pUmDevice); + LM_ReadPhy(pDevice, 0x1e, &Value32); + if ((Value32 & 0x8000) == 0) + LM_WritePhy(pDevice, 0x1e, Value32 | 0x8000); + LM_ReadPhy(pDevice, 0x14, &Value32); + bcm5700_phy_unlock(pUmDevice, flags); + /* Sometimes data on the MDIO bus can be corrupted */ + if (Value32 != 0xffff) + pDevice->PhyCrcCount += Value32; + return pDevice->PhyCrcCount; + } + else if (pStats == 0) { + return 0; + } + else { + return (pStats->dot3StatsFCSErrors.Low); + } +} + +STATIC struct net_device_stats * +bcm5700_get_stats(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt; + struct net_device_stats *p_netstats = &pUmDevice->stats; + + if (pStats == 0) + return p_netstats; + + /* Get stats from LM */ + p_netstats->rx_packets = pStats->ifHCInUcastPkts.Low + + pStats->ifHCInMulticastPkts.Low + + pStats->ifHCInBroadcastPkts.Low; + p_netstats->tx_packets = pStats->COSIfHCOutPkts[0].Low; + p_netstats->rx_bytes = pStats->ifHCInOctets.Low; + p_netstats->tx_bytes = pStats->ifHCOutOctets.Low; + p_netstats->tx_errors = pStats->dot3StatsInternalMacTransmitErrors.Low + + pStats->dot3StatsCarrierSenseErrors.Low + + pStats->ifOutDiscards.Low + + pStats->ifOutErrors.Low; + p_netstats->multicast = pStats->ifHCInMulticastPkts.Low; + p_netstats->collisions = pStats->etherStatsCollisions.Low; + p_netstats->rx_length_errors = pStats->dot3StatsFramesTooLong.Low + + pStats->etherStatsUndersizePkts.Low; + p_netstats->rx_over_errors = pStats->nicNoMoreRxBDs.Low; + p_netstats->rx_frame_errors = pStats->dot3StatsAlignmentErrors.Low; + p_netstats->rx_crc_errors = bcm5700_crc_count(pUmDevice); + p_netstats->rx_errors = p_netstats->rx_length_errors + + p_netstats->rx_over_errors + + p_netstats->rx_frame_errors + + p_netstats->rx_crc_errors + + pStats->etherStatsFragments.Low + + pStats->etherStatsJabbers.Low; + + p_netstats->tx_aborted_errors = pStats->ifOutDiscards.Low; + p_netstats->tx_carrier_errors = pStats->dot3StatsCarrierSenseErrors.Low; + + return p_netstats; +} + +#ifdef SIOCETHTOOL +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct ethtool_cmd ethcmd; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd.cmd) { +#ifdef ETHTOOL_GDRVINFO + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + + strcpy(info.driver, bcm5700_driver); +#if INCLUDE_5701_AX_FIX + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0) { + extern int t3FwReleaseMajor; + extern int t3FwReleaseMinor; + extern int t3FwReleaseFix; + + sprintf(info.fw_version, "%i.%i.%i", + t3FwReleaseMajor, t3FwReleaseMinor, + t3FwReleaseFix); + } +#endif + strcpy(info.version, bcm5700_version); + strcpy(info.bus_info, pUmDevice->pdev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } +#endif + case ETHTOOL_GSET: { + if (pDevice->EnableTbi) { + ethcmd.supported = + (SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg); + ethcmd.supported |= SUPPORTED_FIBRE; + ethcmd.port = PORT_FIBRE; + } + else { + ethcmd.supported = + (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg); + ethcmd.supported |= SUPPORTED_TP; + ethcmd.port = PORT_TP; + } + + ethcmd.transceiver = XCVR_INTERNAL; + ethcmd.phy_address = 0; + + if (pUmDevice->line_speed == 1000) + ethcmd.speed = SPEED_1000; + else if (pUmDevice->line_speed == 100) + ethcmd.speed = SPEED_100; + else if (pUmDevice->line_speed == 10) + ethcmd.speed = SPEED_10; + else + ethcmd.speed = 0; + + if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) + ethcmd.duplex = DUPLEX_FULL; + else + ethcmd.duplex = DUPLEX_HALF; + + if (pDevice->DisableAutoNeg == FALSE) { + ethcmd.autoneg = AUTONEG_ENABLE; + ethcmd.advertising = ADVERTISED_Autoneg; + if (pDevice->EnableTbi) { + ethcmd.advertising |= + ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE; + } + else { + ethcmd.advertising |= + ADVERTISED_TP; + if (pDevice->advertising & + PHY_AN_AD_10BASET_HALF) { + + ethcmd.advertising |= + ADVERTISED_10baseT_Half; + } + if (pDevice->advertising & + PHY_AN_AD_10BASET_FULL) { + + ethcmd.advertising |= + ADVERTISED_10baseT_Full; + } + if (pDevice->advertising & + PHY_AN_AD_100BASETX_HALF) { + + ethcmd.advertising |= + ADVERTISED_100baseT_Half; + } + if (pDevice->advertising & + PHY_AN_AD_100BASETX_FULL) { + + ethcmd.advertising |= + ADVERTISED_100baseT_Full; + } + if (pDevice->advertising1000 & + BCM540X_AN_AD_1000BASET_HALF) { + + ethcmd.advertising |= + ADVERTISED_1000baseT_Half; + } + if (pDevice->advertising1000 & + BCM540X_AN_AD_1000BASET_FULL) { + + ethcmd.advertising |= + ADVERTISED_1000baseT_Full; + } + } + } + else { + ethcmd.autoneg = AUTONEG_DISABLE; + ethcmd.advertising = 0; + } + + ethcmd.maxtxpkt = pDevice->TxMaxCoalescedFrames; + ethcmd.maxrxpkt = pDevice->RxMaxCoalescedFrames; + + if(copy_to_user(useraddr, ðcmd, sizeof(ethcmd))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSET: { + long flags; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (ethcmd.autoneg == AUTONEG_ENABLE) { + if (pDevice->EnableTbi) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_AUTO; + } + else { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_AUTO; + } + pDevice->DisableAutoNeg = FALSE; + } + else if (ethcmd.speed == SPEED_1000) { + if (!pDevice->EnableTbi) + return -EINVAL; + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX; + pDevice->DisableAutoNeg = TRUE; + } + else if (ethcmd.speed == SPEED_100) { + if (ethcmd.duplex == DUPLEX_FULL) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX; + } + else { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS; + } + pDevice->DisableAutoNeg = TRUE; + } + else if (ethcmd.speed == SPEED_10) { + if (ethcmd.duplex == DUPLEX_FULL) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX; + } + else { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS; + } + pDevice->DisableAutoNeg = TRUE; + } + else { + return -EINVAL; + } + flags = bcm5700_phy_lock(pUmDevice); + LM_SetupPhy(pDevice); + bcm5700_phy_unlock(pUmDevice, flags); + return 0; + } +#ifdef ETHTOOL_GWOL + case ETHTOOL_GWOL: { + struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; + + if (pDevice->EnableTbi) { + wol.supported = 0; + wol.wolopts = 0; + } + else { + wol.supported = WAKE_MAGIC; + if (pDevice->WakeUpMode == LM_WAKE_UP_MODE_MAGIC_PACKET) + { + wol.wolopts = WAKE_MAGIC; + } + else { + wol.wolopts = 0; + } + } + if (copy_to_user(useraddr, &wol, sizeof(wol))) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: { + struct ethtool_wolinfo wol; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&wol, useraddr, sizeof(wol))) + return -EFAULT; + if (pDevice->EnableTbi && wol.wolopts) + return -EINVAL; + + if ((wol.wolopts & ~WAKE_MAGIC) != 0) { + return -EINVAL; + } + if (wol.wolopts & WAKE_MAGIC) { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET; + pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET; + } + else { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE; + pDevice->WakeUpMode = LM_WAKE_UP_MODE_NONE; + } + return 0; + } +#endif +#ifdef ETHTOOL_GLINK + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + + if (pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) + edata.data = 1; + else + edata.data = 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } +#endif +#ifdef ETHTOOL_NWAY_RST + case ETHTOOL_NWAY_RST: { + LM_UINT32 phyctrl; + long flags; + + if (pDevice->DisableAutoNeg) { + return -EINVAL; + } + flags = bcm5700_phy_lock(pUmDevice); + if (pDevice->EnableTbi) { + LM_SetupPhy(pDevice); + } + else { + LM_ReadPhy(pDevice, PHY_CTRL_REG, &phyctrl); + LM_WritePhy(pDevice, PHY_CTRL_REG, phyctrl | + PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_RESTART_AUTO_NEG); + } + bcm5700_phy_unlock(pUmDevice, flags); + return 0; + } +#endif + } + + return -EOPNOTSUPP; +} +#endif + +/* Provide ioctl() calls to examine the MII xcvr state. */ +STATIC int bcm5700_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + u16 *data = (u16 *)&rq->ifr_data; + u32 value; + unsigned long flags; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = pDevice->PhyAddr; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + flags = bcm5700_phy_lock(pUmDevice); + LM_ReadPhy(pDevice, data[1] & 0x1f, (LM_UINT32 *) &value); + bcm5700_phy_unlock(pUmDevice, flags); + data[3] = value & 0xffff; + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + flags = bcm5700_phy_lock(pUmDevice); + LM_WritePhy(pDevice, data[1] & 0x1f, data[2]); + bcm5700_phy_unlock(pUmDevice, flags); + return 0; +#ifdef NICE_SUPPORT + case SIOCNICE: + { + struct nice_req* nrq; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + nrq = (struct nice_req*)&rq->ifr_ifru; + if( nrq->cmd == NICE_CMD_QUERY_SUPPORT ) { + nrq->nrq_magic = NICE_DEVICE_MAGIC; + nrq->nrq_support_rx = 1; + nrq->nrq_support_vlan = 1; + nrq->nrq_support_get_speed = 1; + return 0; + } + else if( nrq->cmd == NICE_CMD_SET_RX ) { + pUmDevice->nice_rx = nrq->nrq_rx; + pUmDevice->nice_ctx = nrq->nrq_ctx; + return 0; + } + else if( nrq->cmd == NICE_CMD_GET_RX ) { + nrq->nrq_rx = pUmDevice->nice_rx; + nrq->nrq_ctx = pUmDevice->nice_ctx; + return 0; + } + else if( nrq->cmd == NICE_CMD_GET_SPEED ) { + nrq->nrq_speed = pUmDevice->line_speed; + return 0; + } + else if( nrq->cmd == NICE_CMD_BLINK_LED ) { + return LM_BlinkLED(pDevice, nrq->nrq_blink_time); + } + break; + } +#endif /* NICE_SUPPORT */ +#ifdef SIOCETHTOOL + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); +#endif + default: + return -EOPNOTSUPP; + } + return -EOPNOTSUPP; +} + +STATIC void bcm5700_set_rx_mode(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + int i; + struct dev_mc_list *mclist; + + LM_MulticastClear(pDevice); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + LM_MulticastAdd(pDevice, (PLM_UINT8) &mclist->dmi_addr); + } + if (dev->flags & IFF_ALLMULTI) { + if (!(pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST)) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST); + } + } + else if (pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask & ~LM_ACCEPT_ALL_MULTICAST); + } + if (dev->flags & IFF_PROMISC) { + if (!(pDevice->RxMode & RX_MODE_PROMISCUOUS_MODE)) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask | LM_PROMISCUOUS_MODE); + } + } + else if (pDevice->RxMode & RX_MODE_PROMISCUOUS_MODE) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask & ~LM_PROMISCUOUS_MODE); + } +} + +/* + * Set the hardware MAC address. + */ +STATIC int bcm5700_set_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr=p; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) dev->priv; + + if (netif_running(dev)) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); + LM_SetMacAddress(pDevice, dev->dev_addr); + return 0; +} + + +#if (LINUX_VERSION_CODE < 0x020300) +#ifdef MODULE +int init_module(void) +{ + return bcm5700_probe(NULL); +} + +void cleanup_module(void) +{ + struct net_device *next_dev; + PUM_DEVICE_BLOCK pUmDevice; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_tigon3_dev) { + pUmDevice = (PUM_DEVICE_BLOCK)root_tigon3_dev->priv; +#ifdef CONFIG_PROC_FS + bcm5700_proc_remove_dev(root_tigon3_dev); +#endif + next_dev = pUmDevice->next_module; + unregister_netdev(root_tigon3_dev); + if (pUmDevice->lm_dev.pMappedMemBase) + iounmap(pUmDevice->lm_dev.pMappedMemBase); + kfree(root_tigon3_dev); + root_tigon3_dev = next_dev; + } +} + +#endif /* MODULE */ +#else /* LINUX_VERSION_CODE < 0x020300 */ + +#if (LINUX_VERSION_CODE >= 0x020406) +static int bcm5700_suspend (struct pci_dev *pdev, u32 state) +#else +static void bcm5700_suspend (struct pci_dev *pdev) +#endif +{ + struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev); + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + + if (!netif_running(dev)) +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#else + return; +#endif + + bcm5700_intr_off(pUmDevice); + netif_carrier_off(dev); + netif_device_detach (dev); + + /* Disable interrupts, stop Tx and Rx. */ + LM_Halt(pDevice); + pDevice->InitDone = 0; + LM_SetPowerState(pDevice, LM_POWER_STATE_D3); + +/* pci_power_off(pdev, -1);*/ +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#endif +} + + +#if (LINUX_VERSION_CODE >= 0x020406) +static int bcm5700_resume(struct pci_dev *pdev) +#else +static void bcm5700_resume(struct pci_dev *pdev) +#endif +{ + struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev); + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + + if (!netif_running(dev)) +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#else + return; +#endif +/* pci_power_on(pdev);*/ + netif_device_attach(dev); + LM_InitializeAdapter(pDevice); + if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) { + LM_SetMacAddress(pDevice, dev->dev_addr); + } + atomic_set(&pUmDevice->intr_sem, 0); + LM_EnableInterrupt(pDevice); +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#endif +} + + +static struct pci_driver bcm5700_pci_driver = { + name: bcm5700_driver, + id_table: bcm5700_pci_tbl, + probe: bcm5700_init_one, + remove: bcm5700_remove_one, + suspend: bcm5700_suspend, + resume: bcm5700_resume, +}; + + +static int __init bcm5700_init_module (void) +{ + return pci_module_init(&bcm5700_pci_driver); +} + + +static void __exit bcm5700_cleanup_module (void) +{ + pci_unregister_driver(&bcm5700_pci_driver); +} + + +module_init(bcm5700_init_module); +module_exit(bcm5700_cleanup_module); +#endif + +/* + * Middle Module + * + */ + + +LM_STATUS +MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 *pValue16) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_read_config_word(pUmDevice->pdev, Offset, (u16 *) pValue16); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 *pValue32) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_read_config_dword(pUmDevice->pdev, Offset, (u32 *) pValue32); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 Value16) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_write_config_word(pUmDevice->pdev, Offset, Value16); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 Value32) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_write_config_dword(pUmDevice->pdev, Offset, Value32); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt, PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, + LM_BOOL Cached) +{ + PLM_VOID pvirt; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + dma_addr_t mapping; + + pvirt = pci_alloc_consistent(pUmDevice->pdev, BlockSize, + &mapping); + if (!pvirt) { + return LM_STATUS_FAILURE; + } + pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt; + pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping; + pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize; + memset(pvirt, 0, BlockSize); + *pMemoryBlockVirt = (PLM_VOID) pvirt; + bcm_set_addr(pMemoryBlockPhy, mapping); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt) +{ + PLM_VOID pvirt; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + + + /* Maximum in slab.c */ + if (BlockSize > 131072) { + goto MM_Alloc_error; + } + + pvirt = kmalloc(BlockSize, GFP_KERNEL); + if (!pvirt) { + goto MM_Alloc_error; + } + pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt; + pUmDevice->dma_list[pUmDevice->mem_list_num] = 0; + pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = 0; + /* mem_size_list[i] == 0 indicates that the memory should be freed */ + /* using kfree */ + memset(pvirt, 0, BlockSize); + *pMemoryBlockVirt = pvirt; + return LM_STATUS_SUCCESS; + +MM_Alloc_error: + printk(KERN_WARNING "%s: Memory allocation failed - buffer parameters may be set too high\n", pUmDevice->dev->name); + return LM_STATUS_FAILURE; +} + +LM_STATUS +MM_MapMemBase(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + + pDevice->pMappedMemBase = ioremap_nocache( + pci_resource_start(pUmDevice->pdev, 0), pDevice->MemBaseSize); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice) +{ + int i; + struct sk_buff *skb; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + PUM_PACKET pUmPacket; + PLM_PACKET pPacket; + dma_addr_t map; + + for (i = 0; i < pDevice->RxPacketDescCnt; i++) { + pPacket = QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + pUmPacket = (PUM_PACKET) pPacket; + if (pPacket == 0) { + printk(KERN_DEBUG "Bad RxPacketFreeQ\n"); + } + skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2); + if (skb == 0) { + pUmPacket->skbuff = 0; + QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket); + continue; + } + pUmPacket->skbuff = skb; + skb->dev = pUmDevice->dev; + skb_reserve(skb, pUmDevice->rx_buf_align); + map = pci_map_single(pUmDevice->pdev, skb->tail, + pPacket->u.Rx.RxBufferSize, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(pUmPacket, map[0], map); + bcm_set_addr(&pPacket->u.Rx.RxBufferPhy, map); + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } + if (T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) { + /* reallocate buffers in the ISR */ + pUmDevice->rx_buf_repl_thresh = 0; + pUmDevice->rx_buf_repl_panic_thresh = 0; + } + else { + pUmDevice->rx_buf_repl_thresh = pDevice->RxPacketDescCnt / 8; + pUmDevice->rx_buf_repl_panic_thresh = + pDevice->RxPacketDescCnt / 2; + + if (pDevice->RxJumboDescCnt != 0) { + if (pUmDevice->rx_buf_repl_thresh >= + pDevice->RxJumboDescCnt) { + + pUmDevice->rx_buf_repl_thresh = + pUmDevice->rx_buf_repl_panic_thresh = + pDevice->RxJumboDescCnt - 1; + } + if (pUmDevice->rx_buf_repl_thresh >= + pDevice->RxStdDescCnt) { + + pUmDevice->rx_buf_repl_thresh = + pUmDevice->rx_buf_repl_panic_thresh = + pDevice->RxStdDescCnt - 1; + } + } + } + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_GetConfig(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + int index = pUmDevice->index; + + if (auto_speed[index] == 0) + pDevice->DisableAutoNeg = TRUE; + else + pDevice->DisableAutoNeg = FALSE; + + if (line_speed[index] == 0) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_AUTO; + pDevice->DisableAutoNeg = FALSE; + } + else { + if (line_speed[index] == 1000) { + if (pDevice->EnableTbi) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX; + } + else if (full_duplex[index]) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX; + } + else { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS; + } + if (!pDevice->EnableTbi) + pDevice->DisableAutoNeg = FALSE; + } + else if (line_speed[index] == 100) { + if (full_duplex[index]) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX; + } + else { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS; + } + } + else if (line_speed[index] == 10) { + if (full_duplex[index]) { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX; + } + else { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS; + } + } + else { + pDevice->RequestedMediaType = + LM_REQUESTED_MEDIA_TYPE_AUTO; + pDevice->DisableAutoNeg = FALSE; + printk(KERN_WARNING "%s: Invalid line_speed parameter (%d), using 0\n", pUmDevice->dev->name, line_speed[index]); + } + + } + pDevice->FlowControlCap = 0; + if (rx_flow_control[index] != 0) { + pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + if (tx_flow_control[index] != 0) { + pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE; + } + if (auto_flow_control[index] != 0) { + if (pDevice->DisableAutoNeg == FALSE) { + + pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE; + if ((tx_flow_control[index] == 0) && + (rx_flow_control[index] == 0)) { + + pDevice->FlowControlCap |= + LM_FLOW_CONTROL_TRANSMIT_PAUSE | + LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + } + else { + printk(KERN_WARNING "%s: Conflicting auto_flow_control parameter (%d), using 0\n", + pUmDevice->dev->name, auto_flow_control[index]); + } + + } + + if (pUmDevice->dev->mtu > 1500) { + pDevice->RxMtu = pUmDevice->dev->mtu + 14; + } + + if (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) { + pDevice->UseTaggedStatus = TRUE; + pUmDevice->timer_interval = HZ; + } + else { + pUmDevice->timer_interval = HZ/10; + } + + if ((tx_pkt_desc_cnt[index] == 0) || + (tx_pkt_desc_cnt[index] > MAX_TX_PACKET_DESC_COUNT)) { + + printk(KERN_WARNING "%s: Invalid tx_pkt_desc_cnt parameter (%d), using %d\n", + pUmDevice->dev->name, tx_pkt_desc_cnt[index], + DEFAULT_TX_PACKET_DESC_COUNT); + + tx_pkt_desc_cnt[index] = DEFAULT_TX_PACKET_DESC_COUNT; + } + pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index]; + if ((rx_std_desc_cnt[index] == 0) || + (rx_std_desc_cnt[index] >= T3_STD_RCV_RCB_ENTRY_COUNT)) { + + printk(KERN_WARNING "%s: Invalid rx_std_desc_cnt parameter (%d), using %d\n", + pUmDevice->dev->name, rx_std_desc_cnt[index], + DEFAULT_RX_PACKET_DESC_COUNT); + + rx_std_desc_cnt[index] = DEFAULT_RX_PACKET_DESC_COUNT; + } + pDevice->RxStdDescCnt = rx_std_desc_cnt[index]; + + if (mtu[index] <= 1514) { + rx_jumbo_desc_cnt[index] = 0; + } + else if ((rx_jumbo_desc_cnt[index] == 0) || + (rx_jumbo_desc_cnt[index] >= T3_JUMBO_RCV_RCB_ENTRY_COUNT)) { + + printk(KERN_WARNING "%s: Invalid rx_jumbo_desc_cnt parameter (%d), using %d\n", + pUmDevice->dev->name, rx_jumbo_desc_cnt[index], + DEFAULT_JUMBO_RCV_DESC_COUNT); + + rx_jumbo_desc_cnt[index] = DEFAULT_JUMBO_RCV_DESC_COUNT; + } + pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index]; + +#if INCLUDE_EXT_MEMORY_SUPPORT + if ((rx_mini_desc_cnt[index] == 0) || + (rx_mini_desc_cnt[index] >= T3_MINI_RCV_RCB_ENTRY_COUNT)) { + + printk(KERN_WARNING "%s: Invalid rx_mini_desc_cnt parameter (%d), using %d\n", + pUmDevice->dev->name, rx_mini_desc_cnt[index], + DEFAULT_MINI_RCV_DESC_COUNT); + + rx_mini_desc_cnt[index] = DEFAULT_MINI_RCV_DESC_COUNT; + } + pDevice->RxMiniDescCnt = rx_mini_desc_cnt[index]; +#endif + + pUmDevice->adaptive_coalesce = adaptive_coalesce[index]; + if (!pUmDevice->adaptive_coalesce) { + if (rx_coalesce_ticks[index] > MAX_RX_COALESCING_TICKS) { + + printk(KERN_WARNING "%s: Invalid rx_coalesce_ticks parameter (%d), using %d\n", + pUmDevice->dev->name, + rx_coalesce_ticks[index], + MAX_RX_COALESCING_TICKS); + + rx_coalesce_ticks[index] = MAX_RX_COALESCING_TICKS; + } + else if ((rx_coalesce_ticks[index] == 0) && + (rx_max_coalesce_frames[index] == 0)) { + + printk(KERN_WARNING "%s: Conflicting rx_coalesce_ticks (0) and rx_max_coalesce_frames (0) parameters, using %d and %d respectively\n", + pUmDevice->dev->name, + DEFAULT_RX_COALESCING_TICKS, + DEFAULT_RX_MAX_COALESCED_FRAMES); + + rx_coalesce_ticks[index] = DEFAULT_RX_COALESCING_TICKS; + rx_max_coalesce_frames[index] = + DEFAULT_RX_MAX_COALESCED_FRAMES; + } + pDevice->RxCoalescingTicks = rx_coalesce_ticks[index]; + pUmDevice->rx_curr_coalesce_ticks = pDevice->RxCoalescingTicks; + + if (rx_max_coalesce_frames[index] > MAX_RX_MAX_COALESCED_FRAMES) + { + printk(KERN_WARNING "%s: Invalid rx_max_coalesce_frames parameter (%d), using %d\n", + pUmDevice->dev->name, + rx_max_coalesce_frames[index], + MAX_RX_MAX_COALESCED_FRAMES); + + rx_max_coalesce_frames[index] = + MAX_RX_MAX_COALESCED_FRAMES; + } + pDevice->RxMaxCoalescedFrames = rx_max_coalesce_frames[index]; + pUmDevice->rx_curr_coalesce_frames = + pDevice->RxMaxCoalescedFrames; + + if (tx_coalesce_ticks[index] > MAX_TX_COALESCING_TICKS) { + printk(KERN_WARNING "%s: Invalid tx_coalesce_ticks parameter (%d), using %d\n", + pUmDevice->dev->name, + tx_coalesce_ticks[index], + MAX_TX_COALESCING_TICKS); + + tx_coalesce_ticks[index] = MAX_TX_COALESCING_TICKS; + } + else if ((tx_coalesce_ticks[index] == 0) && + (tx_max_coalesce_frames[index] == 0)) { + + printk(KERN_WARNING "%s: Conflicting tx_coalesce_ticks (0) and tx_max_coalesce_frames (0) parameters, using %d and %d respectively\n", + pUmDevice->dev->name, + DEFAULT_TX_COALESCING_TICKS, + DEFAULT_TX_MAX_COALESCED_FRAMES); + + tx_coalesce_ticks[index] = DEFAULT_TX_COALESCING_TICKS; + tx_max_coalesce_frames[index] = + DEFAULT_TX_MAX_COALESCED_FRAMES; + } + pDevice->TxCoalescingTicks = tx_coalesce_ticks[index]; + if (tx_max_coalesce_frames[index] > MAX_TX_MAX_COALESCED_FRAMES) { + printk(KERN_WARNING "%s: Invalid tx_max_coalesce_frames parameter (%d), using %d\n", + pUmDevice->dev->name, + tx_max_coalesce_frames[index], + MAX_TX_MAX_COALESCED_FRAMES); + + tx_max_coalesce_frames[index] = MAX_TX_MAX_COALESCED_FRAMES; + } + pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index]; + pUmDevice->tx_curr_coalesce_frames = + pDevice->TxMaxCoalescedFrames; + + if (stats_coalesce_ticks[index] > MAX_STATS_COALESCING_TICKS) { + printk(KERN_WARNING "%s: Invalid stats_coalesce_ticks parameter (%d), using %d\n", + pUmDevice->dev->name, + stats_coalesce_ticks[index], + MAX_STATS_COALESCING_TICKS); + + stats_coalesce_ticks[index] = + MAX_STATS_COALESCING_TICKS; + } + pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index]; + } + else { + pUmDevice->rx_curr_coalesce_frames = + DEFAULT_RX_MAX_COALESCED_FRAMES; + pUmDevice->rx_curr_coalesce_ticks = + DEFAULT_RX_COALESCING_TICKS; + pUmDevice->tx_curr_coalesce_frames = + DEFAULT_TX_MAX_COALESCED_FRAMES; + } + + if (enable_wol[index]) { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET; + pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET; + } + if (pDevice->EnablePciXFix) + pDevice->NicSendBd = FALSE; + else + pDevice->NicSendBd = TRUE; +#ifdef BCM_VLAN + pDevice->NicSendBd = FALSE; +#endif +#if INCLUDE_TBI_SUPPORT + pDevice->PollTbiLink = TRUE; +#endif +#if INCLUDE_EXT_MEMORY_SUPPORT + pDevice->EnableExtMemory = TRUE; +#endif + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_StartTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) +{ + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_CompleteTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) +{ + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + struct sk_buff *skb; + int size; + + while (1) { + pPacket = (PLM_PACKET) + QQ_PopHead(&pDevice->RxPacketReceivedQ.Container); + if (pPacket == 0) + break; + pUmPacket = (PUM_PACKET) pPacket; +#if ! defined(NO_PCI_UNMAP) + pci_unmap_single(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[0]), + pPacket->u.Rx.RxBufferSize, + PCI_DMA_FROMDEVICE); +#endif + if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) || + ((size = pPacket->PacketSize) > pDevice->RxMtu)) { + + /* reuse skb */ +#ifdef TASKLET + QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket); +#else + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); +#endif + pUmDevice->rx_misc_errors++; + continue; + } + skb = pUmPacket->skbuff; + skb_put(skb, size); + skb->pkt_type = 0; + skb->protocol = eth_type_trans(skb, skb->dev); + if ((pPacket->Flags & RCV_BD_FLAG_TCP_UDP_CHKSUM_FIELD) && + (pDevice->TaskToOffload & + LM_TASK_OFFLOAD_RX_TCP_CHECKSUM)) { + if (pPacket->u.Rx.TcpUdpChecksum == 0xffff) { + + skb->ip_summed = CHECKSUM_UNNECESSARY; +#if TIGON3_DEBUG + pUmDevice->rx_good_chksum_count++; +#endif + } + else { + skb->ip_summed = CHECKSUM_NONE; + pUmDevice->rx_bad_chksum_count++; + } + } + else { + skb->ip_summed = CHECKSUM_NONE; + } +#ifdef NICE_SUPPORT + if( pUmDevice->nice_rx ) { + vlan_tag_t *vlan_tag; + + vlan_tag = (vlan_tag_t *) &skb->cb[0]; + if (pPacket->Flags & RCV_BD_FLAG_VLAN_TAG) { + vlan_tag->signature = 0x7777; + vlan_tag->tag = pPacket->VlanTag; + } + else { + vlan_tag->signature = 0; + } + pUmDevice->nice_rx(skb, pUmDevice->nice_ctx); + } + else +#endif + { +#ifdef BCM_VLAN + if (pUmDevice->vlgrp && + (pPacket->Flags & RCV_BD_FLAG_VLAN_TAG)) { + + vlan_hwaccel_rx(skb, pUmDevice->vlgrp, + pPacket->VlanTag); + } + else +#endif + { + netif_rx(skb); + } + } + + +#ifdef TASKLET + pUmPacket->skbuff = 0; + QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket); +#else + skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2); + if (skb == 0) { + pUmPacket->skbuff = 0; + QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket); + } + else { + pUmPacket->skbuff = skb; + skb->dev = pUmDevice->dev; + skb_reserve(skb, pUmDevice->rx_buf_align); + map = pci_map_single(pUmDevice->pdev, skb->tail, + pPacket->u.Rx.RxBufferSize, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(pUmPacket, map[0], map); + bcm_set_addr(&pPacket->u.Rx.RxBufferPhy, map); + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } +#endif + } + return LM_STATUS_SUCCESS; +} + +/* Returns 1 if not all buffers are allocated */ +STATIC int +replenish_rx_buffers(PUM_DEVICE_BLOCK pUmDevice) +{ + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + struct sk_buff *skb; + int queue_rx = 0; + int ret = 0; + dma_addr_t map; + + while ((pUmPacket = (PUM_PACKET) + QQ_PopHead(&pUmDevice->rx_out_of_buf_q.Container)) != 0) { + pPacket = (PLM_PACKET) pUmPacket; + if (pUmPacket->skbuff) { + /* reuse an old skb */ + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + queue_rx = 1; + continue; + } + if ((skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2)) == 0) { + QQ_PushHead(&pUmDevice->rx_out_of_buf_q.Container, + pPacket); + ret = 1; + break; + } + pUmPacket->skbuff = skb; + skb->dev = pUmDevice->dev; + skb_reserve(skb, pUmDevice->rx_buf_align); + map = pci_map_single(pUmDevice->pdev, skb->tail, + pPacket->u.Rx.RxBufferSize, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(pUmPacket, map[0], map); + bcm_set_addr(&pPacket->u.Rx.RxBufferPhy, map); + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + queue_rx = 1; + } + if (queue_rx) { + LM_QueueRxPackets(pDevice); + } + return ret; +} + +LM_STATUS +MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + struct sk_buff *skb; +#if ! defined(NO_PCI_UNMAP) && MAX_SKB_FRAGS + int i; +#endif + + while (1) { + pPacket = (PLM_PACKET) + QQ_PopHead(&pDevice->TxPacketXmittedQ.Container); + if (pPacket == 0) + break; + pUmPacket = (PUM_PACKET) pPacket; + skb = pUmPacket->skbuff; +#if ! defined(NO_PCI_UNMAP) + pci_unmap_single(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[0]), + pci_unmap_len(pUmPacket, map_len[0]), + PCI_DMA_TODEVICE); +#if MAX_SKB_FRAGS + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + pci_unmap_page(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[i + 1]), + pci_unmap_len(pUmPacket, map_len[i + 1]), + PCI_DMA_TODEVICE); + } +#endif +#endif + dev_kfree_skb_irq(skb); + pUmPacket->skbuff = 0; + QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket); + } + if (pUmDevice->tx_full) { + if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) >= + (pDevice->TxPacketDescCnt >> 1)) { + + pUmDevice->tx_full = 0; + netif_wake_queue(pUmDevice->dev); + } + } + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + struct net_device *dev = pUmDevice->dev; + LM_FLOW_CONTROL flow_control; + + if (!pUmDevice->opened) + return LM_STATUS_SUCCESS; + + if (pUmDevice->delayed_link_ind > 0) { + pUmDevice->delayed_link_ind = 0; + if (Status == LM_STATUS_LINK_DOWN) { + pUmDevice->line_speed = 0; + netif_carrier_off(dev); + printk(KERN_ERR "%s: %s NIC Link is DOWN\n", bcm5700_driver, dev->name); + } + else if (Status == LM_STATUS_LINK_ACTIVE) { + netif_carrier_on(dev); + printk(KERN_INFO "%s: %s NIC Link is UP, ", bcm5700_driver, dev->name); + } + } + else { + if (Status == LM_STATUS_LINK_DOWN) { + pUmDevice->line_speed = 0; + netif_carrier_off(dev); + printk(KERN_ERR "%s: %s NIC Link is Down\n", bcm5700_driver, dev->name); + } + else if (Status == LM_STATUS_LINK_ACTIVE) { + netif_carrier_on(dev); + printk(KERN_INFO "%s: %s NIC Link is Up, ", bcm5700_driver, dev->name); + } + } + + if (Status == LM_STATUS_LINK_ACTIVE) { + if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) + pUmDevice->line_speed = 1000; + else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) + pUmDevice->line_speed = 100; + else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) + pUmDevice->line_speed = 10; + + printk("%d Mbps ", pUmDevice->line_speed); + + if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) + printk("full duplex"); + else + printk("half duplex"); + + flow_control = pDevice->FlowControl & + (LM_FLOW_CONTROL_RECEIVE_PAUSE | + LM_FLOW_CONTROL_TRANSMIT_PAUSE); + if (flow_control) { + if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) { + printk(", receive "); + if (flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE) + printk("& transmit "); + } + else { + printk(", transmit "); + } + printk("flow control ON"); + } + printk("\n"); + } + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) +{ + PUM_PACKET pUmPacket; + struct sk_buff *skb; + + if (pPacket == 0) + return LM_STATUS_SUCCESS; + pUmPacket = (PUM_PACKET) pPacket; + if ((skb = pUmPacket->skbuff)) + dev_kfree_skb(skb); + pUmPacket->skbuff = 0; + return LM_STATUS_SUCCESS; +} + + diff -Nur linux-2.4.19/drivers/net/bcm/bits.h linux-2.4.19-sgi211r3/drivers/net/bcm/bits.h --- linux-2.4.19/drivers/net/bcm/bits.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/bits.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,62 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef BITS_H +#define BITS_H + + + +/******************************************************************************/ +/* Bit Mask definitions */ +/******************************************************************************/ + +#define BIT_NONE 0x00 +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x0100 +#define BIT_9 0x0200 +#define BIT_10 0x0400 +#define BIT_11 0x0800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x010000 +#define BIT_17 0x020000 +#define BIT_18 0x040000 +#define BIT_19 0x080000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x01000000 +#define BIT_25 0x02000000 +#define BIT_26 0x04000000 +#define BIT_27 0x08000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + + + +#endif /* BITS_H */ + diff -Nur linux-2.4.19/drivers/net/bcm/debug.h linux-2.4.19-sgi211r3/drivers/net/bcm/debug.h --- linux-2.4.19/drivers/net/bcm/debug.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/debug.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,108 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef DEBUG_H +#define DEBUG_H + + + +/******************************************************************************/ +/* Debug macros */ +/******************************************************************************/ + +/* Code path for controlling output debug messages. */ +/* Define your code path here. */ +#define CP_INIT 0x010000 +#define CP_SEND 0x020000 +#define CP_RCV 0x040000 +#define CP_INT 0x080000 +#define CP_UINIT 0x100000 +#define CP_RESET 0x200000 + +#define CP_ALL (CP_INIT | CP_SEND | CP_RCV | CP_INT | \ + CP_RESET | CP_UINIT) + +#define CP_MASK 0xffff0000 + + +/* Debug message levels. */ +#define LV_VERBOSE 0x03 +#define LV_INFORM 0x02 +#define LV_WARN 0x01 +#define LV_FATAL 0x00 + +#define LV_MASK 0xffff + + +/* Code path and messsage level combined. These are the first argument of */ +/* the DbgMessage macro. */ +#define INIT_V (CP_INIT | LV_VERBOSE) +#define INIT_I (CP_INIT | LV_INFORM) +#define INIT_W (CP_INIT | LV_WARN) +#define SEND_V (CP_SEND | LV_VERBOSE) +#define SEND_I (CP_SEND | LV_INFORM) +#define SEND_W (CP_SEND | LV_WARN) +#define RCV_V (CP_RCV | LV_VERBOSE) +#define RCV_I (CP_RCV | LV_INFORM) +#define RCV_W (CP_RCV | LV_WARN) +#define INT_V (CP_INT | LV_VERBOSE) +#define INT_I (CP_INT | LV_INFORM) +#define INT_W (CP_INT | LV_WARN) +#define UINIT_V (CP_UINIT | LV_VERBOSE) +#define UINIT_I (CP_UINIT | LV_INFORM) +#define UINIT_W (CP_UINIT | LV_WARN) +#define RESET_V (CP_RESET | LV_VERBOSE) +#define RESET_I (CP_RESET | LV_INFORM) +#define RESET_W (CP_RESET | LV_WARN) +#define CPALL_V (CP_ALL | LV_VERBOSE) +#define CPALL_I (CP_ALL | LV_INFORM) +#define CPALL_W (CP_ALL | LV_WARN) + + +/* All code path message levels. */ +#define FATAL (CP_ALL | LV_FATAL) +#define WARN (CP_ALL | LV_WARN) +#define INFORM (CP_ALL | LV_INFORM) +#define VERBOSE (CP_ALL | LV_VERBOSE) + + +/* These constants control the message output. */ +/* Set your debug message output level and code path here. */ +#ifndef DBG_MSG_CP +#define DBG_MSG_CP CP_ALL /* Where to output messages. */ +#endif + +#ifndef DBG_MSG_LV +#define DBG_MSG_LV LV_VERBOSE /* Level of message output. */ +#endif + + +/* DbgMessage macro. */ +#if DBG +#define DbgMessage(CNTRL, MESSAGE) \ + if((CNTRL & DBG_MSG_CP) && ((CNTRL & LV_MASK) <= DBG_MSG_LV)) \ + DbgPrint MESSAGE +#define DbgBreak() DbgBreakPoint() +#define STATIC +#else +#define DbgMessage(CNTRL, MESSAGE) +#define DbgBreak() +#define STATIC static +#endif /* DBG */ + + + +#endif /* DEBUG_H */ + diff -Nur linux-2.4.19/drivers/net/bcm/lm.h linux-2.4.19-sgi211r3/drivers/net/bcm/lm.h --- linux-2.4.19/drivers/net/bcm/lm.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/lm.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,478 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef LM_H +#define LM_H + +#include "debug.h" +#include "queue.h" +#include "bits.h" +#include "lmcfg.h" + + + +/******************************************************************************/ +/* Basic types. */ +/******************************************************************************/ + +typedef char LM_CHAR, *PLM_CHAR; +typedef unsigned int LM_UINT, *PLM_UINT; +typedef unsigned char LM_UINT8, *PLM_UINT8; +typedef unsigned short LM_UINT16, *PLM_UINT16; +typedef unsigned int LM_UINT32, *PLM_UINT32; +typedef unsigned int LM_COUNTER, *PLM_COUNTER; +typedef void LM_VOID, *PLM_VOID; +typedef char LM_BOOL, *PLM_BOOL; + +/* 64bit value. */ +typedef struct { +#ifdef BIG_ENDIAN_HOST + LM_UINT32 High; + LM_UINT32 Low; +#else /* BIG_ENDIAN_HOST */ + LM_UINT32 Low; + LM_UINT32 High; +#endif /* !BIG_ENDIAN_HOST */ +} LM_UINT64, *PLM_UINT64; + +typedef LM_UINT64 LM_PHYSICAL_ADDRESS, *PLM_PHYSICAL_ADDRESS; + +/* void LM_INC_PHYSICAL_ADDRESS(PLM_PHYSICAL_ADDRESS pAddr,LM_UINT32 IncSize) */ +#define LM_INC_PHYSICAL_ADDRESS(pAddr, IncSize) \ + { \ + LM_UINT32 OrgLow; \ + \ + OrgLow = (pAddr)->Low; \ + (pAddr)->Low += IncSize; \ + if((pAddr)->Low < OrgLow) { \ + (pAddr)->High++; /* Wrap around. */ \ + } \ + } + + +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif /* NULL */ + +#ifndef OFFSETOF +#define OFFSETOF(_s, _m) (MM_UINT_PTR(&(((_s *) 0)->_m))) +#endif /* OFFSETOF */ + + + +/******************************************************************************/ +/* Simple macros. */ +/******************************************************************************/ + +#define IS_ETH_BROADCAST(_pEthAddr) \ + (((unsigned char *) (_pEthAddr))[0] == ((unsigned char) 0xff)) + +#define IS_ETH_MULTICAST(_pEthAddr) \ + (((unsigned char *) (_pEthAddr))[0] & ((unsigned char) 0x01)) + +#define IS_ETH_ADDRESS_EQUAL(_pEtherAddr1, _pEtherAddr2) \ + ((((unsigned char *) (_pEtherAddr1))[0] == \ + ((unsigned char *) (_pEtherAddr2))[0]) && \ + (((unsigned char *) (_pEtherAddr1))[1] == \ + ((unsigned char *) (_pEtherAddr2))[1]) && \ + (((unsigned char *) (_pEtherAddr1))[2] == \ + ((unsigned char *) (_pEtherAddr2))[2]) && \ + (((unsigned char *) (_pEtherAddr1))[3] == \ + ((unsigned char *) (_pEtherAddr2))[3]) && \ + (((unsigned char *) (_pEtherAddr1))[4] == \ + ((unsigned char *) (_pEtherAddr2))[4]) && \ + (((unsigned char *) (_pEtherAddr1))[5] == \ + ((unsigned char *) (_pEtherAddr2))[5])) + +#define COPY_ETH_ADDRESS(_Src, _Dst) \ + ((unsigned char *) (_Dst))[0] = ((unsigned char *) (_Src))[0]; \ + ((unsigned char *) (_Dst))[1] = ((unsigned char *) (_Src))[1]; \ + ((unsigned char *) (_Dst))[2] = ((unsigned char *) (_Src))[2]; \ + ((unsigned char *) (_Dst))[3] = ((unsigned char *) (_Src))[3]; \ + ((unsigned char *) (_Dst))[4] = ((unsigned char *) (_Src))[4]; \ + ((unsigned char *) (_Dst))[5] = ((unsigned char *) (_Src))[5]; + + + +/******************************************************************************/ +/* Constants. */ +/******************************************************************************/ + +#define ETHERNET_ADDRESS_SIZE 6 +#define ETHERNET_PACKET_HEADER_SIZE 14 +#define MIN_ETHERNET_PACKET_SIZE 64 /* with 4 byte crc. */ +#define MAX_ETHERNET_PACKET_SIZE 1518 /* with 4 byte crc. */ +#define MIN_ETHERNET_PACKET_SIZE_NO_CRC 60 +#define MAX_ETHERNET_PACKET_SIZE_NO_CRC 1514 +#define MAX_ETHERNET_PACKET_BUFFER_SIZE 1536 /* A nice even number. */ + +#ifndef LM_MAX_MC_TABLE_SIZE +#define LM_MAX_MC_TABLE_SIZE 32 +#endif /* LM_MAX_MC_TABLE_SIZE */ +#define LM_MC_ENTRY_SIZE (ETHERNET_ADDRESS_SIZE+1) +#define LM_MC_INSTANCE_COUNT_INDEX (LM_MC_ENTRY_SIZE-1) + + +/* Receive filter masks. */ +#define LM_ACCEPT_UNICAST 0x0001 +#define LM_ACCEPT_MULTICAST 0x0002 +#define LM_ACCEPT_ALL_MULTICAST 0x0004 +#define LM_ACCEPT_BROADCAST 0x0008 +#define LM_ACCEPT_ERROR_PACKET 0x0010 + +#define LM_PROMISCUOUS_MODE 0x10000 + + + +/******************************************************************************/ +/* PCI registers. */ +/******************************************************************************/ + +#define PCI_VENDOR_ID_REG 0x00 +#define PCI_DEVICE_ID_REG 0x02 + +#define PCI_COMMAND_REG 0x04 +#define PCI_IO_SPACE_ENABLE 0x0001 +#define PCI_MEM_SPACE_ENABLE 0x0002 +#define PCI_BUSMASTER_ENABLE 0x0004 +#define PCI_MEMORY_WRITE_INVALIDATE 0x0010 +#define PCI_PARITY_ERROR_ENABLE 0x0040 +#define PCI_SYSTEM_ERROR_ENABLE 0x0100 +#define PCI_FAST_BACK_TO_BACK_ENABLE 0x0200 + +#define PCI_STATUS_REG 0x06 +#define PCI_REV_ID_REG 0x08 + +#define PCI_CACHE_LINE_SIZE_REG 0x0c + +#define PCI_IO_BASE_ADDR_REG 0x10 +#define PCI_IO_BASE_ADDR_MASK 0xfffffff0 + +#define PCI_MEM_BASE_ADDR_LOW 0x10 +#define PCI_MEM_BASE_ADDR_HIGH 0x14 + +#define PCI_SUBSYSTEM_VENDOR_ID_REG 0x2c +#define PCI_SUBSYSTEM_ID_REG 0x2e +#define PCI_INT_LINE_REG 0x3c + +#define PCIX_CAP_REG 0x40 +#define PCIX_ENABLE_RELAXED_ORDERING BIT_17 + +/******************************************************************************/ +/* Fragment structure. */ +/******************************************************************************/ + +typedef struct { + LM_UINT32 FragSize; + LM_PHYSICAL_ADDRESS FragBuf; +} LM_FRAG, *PLM_FRAG; + +typedef struct { + /* FragCount is initialized for the caller to the maximum array size, on */ + /* return FragCount is the number of the actual fragments in the array. */ + LM_UINT32 FragCount; + + /* Total buffer size. */ + LM_UINT32 TotalSize; + + /* Fragment array buffer. */ + LM_FRAG Fragments[1]; +} LM_FRAG_LIST, *PLM_FRAG_LIST; + +#define DECLARE_FRAG_LIST_BUFFER_TYPE(_FRAG_LIST_TYPE_NAME, _MAX_FRAG_COUNT) \ + typedef struct { \ + LM_FRAG_LIST FragList; \ + LM_FRAG FragListBuffer[_MAX_FRAG_COUNT-1]; \ + } _FRAG_LIST_TYPE_NAME, *P##_FRAG_LIST_TYPE_NAME + + + +/******************************************************************************/ +/* Status codes. */ +/******************************************************************************/ + +#define LM_STATUS_SUCCESS 0 +#define LM_STATUS_FAILURE 1 + +#define LM_STATUS_INTERRUPT_ACTIVE 2 +#define LM_STATUS_INTERRUPT_NOT_ACTIVE 3 + +#define LM_STATUS_LINK_ACTIVE 4 +#define LM_STATUS_LINK_DOWN 5 +#define LM_STATUS_LINK_SETTING_MISMATCH 6 + +#define LM_STATUS_TOO_MANY_FRAGMENTS 7 +#define LM_STATUS_TRANSMIT_ABORTED 8 +#define LM_STATUS_TRANSMIT_ERROR 9 +#define LM_STATUS_RECEIVE_ABORTED 10 +#define LM_STATUS_RECEIVE_ERROR 11 +#define LM_STATUS_INVALID_PACKET_SIZE 12 +#define LM_STATUS_OUT_OF_MAP_REGISTERS 13 +#define LM_STATUS_UNKNOWN_ADAPTER 14 + +typedef LM_UINT LM_STATUS, *PLM_STATUS; + + + +/******************************************************************************/ +/* Requested media type. */ +/******************************************************************************/ + +#define LM_REQUESTED_MEDIA_TYPE_AUTO 0 +#define LM_REQUESTED_MEDIA_TYPE_BNC 1 +#define LM_REQUESTED_MEDIA_TYPE_UTP_AUTO 2 +#define LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS 3 +#define LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX 4 +#define LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS 5 +#define LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX 6 +#define LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS 7 +#define LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX 8 +#define LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS 9 +#define LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS_FULL_DUPLEX 10 +#define LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS 11 +#define LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX 12 +#define LM_REQUESTED_MEDIA_TYPE_MAC_LOOPBACK 0xfffe +#define LM_REQUESTED_MEDIA_TYPE_PHY_LOOPBACK 0xffff + +typedef LM_UINT32 LM_REQUESTED_MEDIA_TYPE, *PLM_REQUESTED_MEDIA_TYPE; + + + +/******************************************************************************/ +/* Media type. */ +/******************************************************************************/ + +#define LM_MEDIA_TYPE_UNKNOWN -1 +#define LM_MEDIA_TYPE_AUTO 0 +#define LM_MEDIA_TYPE_UTP 1 +#define LM_MEDIA_TYPE_BNC 2 +#define LM_MEDIA_TYPE_AUI 3 +#define LM_MEDIA_TYPE_FIBER 4 + +typedef LM_UINT32 LM_MEDIA_TYPE, *PLM_MEDIA_TYPE; + + + +/******************************************************************************/ +/* Line speed. */ +/******************************************************************************/ + +#define LM_LINE_SPEED_UNKNOWN 0 +#define LM_LINE_SPEED_10MBPS 1 +#define LM_LINE_SPEED_100MBPS 2 +#define LM_LINE_SPEED_1000MBPS 3 + +typedef LM_UINT32 LM_LINE_SPEED, *PLM_LINE_SPEED; + + + +/******************************************************************************/ +/* Duplex mode. */ +/******************************************************************************/ + +#define LM_DUPLEX_MODE_UNKNOWN 0 +#define LM_DUPLEX_MODE_HALF 1 +#define LM_DUPLEX_MODE_FULL 2 + +typedef LM_UINT32 LM_DUPLEX_MODE, *PLM_DUPLEX_MODE; + + + +/******************************************************************************/ +/* Power state. */ +/******************************************************************************/ + +#define LM_POWER_STATE_D0 0 +#define LM_POWER_STATE_D1 1 +#define LM_POWER_STATE_D2 2 +#define LM_POWER_STATE_D3 3 + +typedef LM_UINT32 LM_POWER_STATE, *PLM_POWER_STATE; + + + +/******************************************************************************/ +/* Task offloading. */ +/******************************************************************************/ + +#define LM_TASK_OFFLOAD_NONE 0x0000 +#define LM_TASK_OFFLOAD_TX_IP_CHECKSUM 0x0001 +#define LM_TASK_OFFLOAD_RX_IP_CHECKSUM 0x0002 +#define LM_TASK_OFFLOAD_TX_TCP_CHECKSUM 0x0004 +#define LM_TASK_OFFLOAD_RX_TCP_CHECKSUM 0x0008 +#define LM_TASK_OFFLOAD_TX_UDP_CHECKSUM 0x0010 +#define LM_TASK_OFFLOAD_RX_UDP_CHECKSUM 0x0020 +#define LM_TASK_OFFLOAD_TCP_SEGMENTATION 0x0040 + +typedef LM_UINT32 LM_TASK_OFFLOAD, *PLM_TASK_OFFLOAD; + + + +/******************************************************************************/ +/* Flow control. */ +/******************************************************************************/ + +#define LM_FLOW_CONTROL_NONE 0x00 +#define LM_FLOW_CONTROL_RECEIVE_PAUSE 0x01 +#define LM_FLOW_CONTROL_TRANSMIT_PAUSE 0x02 +#define LM_FLOW_CONTROL_RX_TX_PAUSE (LM_FLOW_CONTROL_RECEIVE_PAUSE | \ + LM_FLOW_CONTROL_TRANSMIT_PAUSE) + +/* This value can be or-ed with RECEIVE_PAUSE and TRANSMIT_PAUSE. If the */ +/* auto-negotiation is disabled and the RECEIVE_PAUSE and TRANSMIT_PAUSE */ +/* bits are set, then flow control is enabled regardless of link partner's */ +/* flow control capability. */ +#define LM_FLOW_CONTROL_AUTO_PAUSE 0x80000000 + +typedef LM_UINT32 LM_FLOW_CONTROL, *PLM_FLOW_CONTROL; + + + +/******************************************************************************/ +/* Wake up mode. */ +/******************************************************************************/ + +#define LM_WAKE_UP_MODE_NONE 0 +#define LM_WAKE_UP_MODE_MAGIC_PACKET 1 +#define LM_WAKE_UP_MODE_NWUF 2 +#define LM_WAKE_UP_MODE_LINK_CHANGE 4 + +typedef LM_UINT32 LM_WAKE_UP_MODE, *PLM_WAKE_UP_MODE; + + + +/******************************************************************************/ +/* Counters. */ +/******************************************************************************/ + +#define LM_COUNTER_FRAMES_XMITTED_OK 0 +#define LM_COUNTER_FRAMES_RECEIVED_OK 1 +#define LM_COUNTER_ERRORED_TRANSMIT_COUNT 2 +#define LM_COUNTER_ERRORED_RECEIVE_COUNT 3 +#define LM_COUNTER_RCV_CRC_ERROR 4 +#define LM_COUNTER_ALIGNMENT_ERROR 5 +#define LM_COUNTER_SINGLE_COLLISION_FRAMES 6 +#define LM_COUNTER_MULTIPLE_COLLISION_FRAMES 7 +#define LM_COUNTER_FRAMES_DEFERRED 8 +#define LM_COUNTER_MAX_COLLISIONS 9 +#define LM_COUNTER_RCV_OVERRUN 10 +#define LM_COUNTER_XMIT_UNDERRUN 11 +#define LM_COUNTER_UNICAST_FRAMES_XMIT 12 +#define LM_COUNTER_MULTICAST_FRAMES_XMIT 13 +#define LM_COUNTER_BROADCAST_FRAMES_XMIT 14 +#define LM_COUNTER_UNICAST_FRAMES_RCV 15 +#define LM_COUNTER_MULTICAST_FRAMES_RCV 16 +#define LM_COUNTER_BROADCAST_FRAMES_RCV 17 + +typedef LM_UINT32 LM_COUNTER_TYPE, *PLM_COUNTER_TYPE; + + + +/******************************************************************************/ +/* Forward definition. */ +/******************************************************************************/ + +typedef struct _LM_DEVICE_BLOCK *PLM_DEVICE_BLOCK; +typedef struct _LM_PACKET *PLM_PACKET; + + + +/******************************************************************************/ +/* Function prototypes. */ +/******************************************************************************/ + +LM_STATUS LM_GetAdapterInfo(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_InitializeAdapter(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_ResetAdapter(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_DisableInterrupt(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_EnableInterrupt(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_SendPacket(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS LM_ServiceInterrupts(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_QueueRxPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_SetReceiveMask(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Mask); +LM_STATUS LM_Halt(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_Abort(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_MulticastAdd(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress); +LM_STATUS LM_MulticastDel(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress); +LM_STATUS LM_MulticastClear(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_SetMacAddress(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress); +LM_STATUS LM_LoopbackAddress(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pAddress); + +LM_UINT32 LM_GetCrcCounter(PLM_DEVICE_BLOCK pDevice); + +LM_WAKE_UP_MODE LM_PMCapabilities(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_NwufAdd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 ByteMaskSize, + LM_UINT8 *pByteMask, LM_UINT8 *pPattern); +LM_STATUS LM_NwufRemove(PLM_DEVICE_BLOCK pDevice, LM_UINT32 ByteMaskSize, + LM_UINT8 *pByteMask, LM_UINT8 *pPattern); +LM_STATUS LM_SetPowerState(PLM_DEVICE_BLOCK pDevice, LM_POWER_STATE PowerLevel); + +LM_VOID LM_ReadPhy(PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg, + PLM_UINT32 pData32); +LM_VOID LM_WritePhy(PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg, + LM_UINT32 Data32); + +LM_STATUS LM_ControlLoopBack(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Control); +LM_STATUS LM_SetupPhy(PLM_DEVICE_BLOCK pDevice); +int LM_BlinkLED(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlinkDuration); + + + +/******************************************************************************/ +/* These are the OS specific functions called by LMAC. */ +/******************************************************************************/ + +LM_STATUS MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 *pValue16); +LM_STATUS MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 Value16); +LM_STATUS MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 *pValue32); +LM_STATUS MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 Value32); +LM_STATUS MM_MapMemBase(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_MapIoBase(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_StartTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS MM_CompleteTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt); +LM_STATUS MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt, PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, + LM_BOOL Cached); +LM_STATUS MM_GetConfig(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status); +LM_STATUS MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS LM_MbufWorkAround(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_SetLinkSpeed(PLM_DEVICE_BLOCK pDevice, + LM_REQUESTED_MEDIA_TYPE RequestedMediaType); + +#if INCLUDE_5703_A0_FIX +LM_STATUS LM_Load5703DmaWFirmware(PLM_DEVICE_BLOCK pDevice); +#endif + + +#endif /* LM_H */ + diff -Nur linux-2.4.19/drivers/net/bcm/lmcfg.h linux-2.4.19-sgi211r3/drivers/net/bcm/lmcfg.h --- linux-2.4.19/drivers/net/bcm/lmcfg.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/lmcfg.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,39 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef LMCFG_H +#define LMCFG_H + + + +/******************************************************************************/ +/* Configurable constants */ +/******************************************************************************/ + +#define LM_MAJOR_VER 1 +#define LM_MINOR_VER 0 + +#define LM_SHORT_COMPANY_NAME_STR "Broadcom" +#define LM_LONG_COMPANY_NAME_STR "Broadcom Corporation" + +#define LM_LONG_COPYRIGHT_STR "Copyright \251 2000 Broadcom Corporation. All rights reserved." +#define LM_SHORT_COPYRIGHT_STR "Copyright \251 2000 Broadcom Corporation." + +#define LM_DRV_PRODUCT_NAME_STR "Gigabit Ethernet Driver" + + + +#endif /* LMCFG_H */ + diff -Nur linux-2.4.19/drivers/net/bcm/mm.h linux-2.4.19-sgi211r3/drivers/net/bcm/mm.h --- linux-2.4.19/drivers/net/bcm/mm.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/mm.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,213 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/******************************************************************************/ + +#ifndef MM_H +#define MM_H + +#include +#if defined(CONFIG_SMP) && ! defined(__SMP__) +#define __SMP__ +#endif +#if defined(CONFIG_MODVERSIONS) && defined(MODULE) && ! defined(MODVERSIONS) +#define MODVERSIONS +#endif + +#ifndef B57UM +#define __NO_VERSION__ +#endif +#include +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#define SET_MODULE_OWNER(dev) +#define MODULE_DEVICE_TABLE(pci, pci_tbl) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= 0x020400) +#include +#include +#endif +#ifdef CONFIG_PROC_FS +#include +#include +#endif +#ifdef NETIF_F_HW_VLAN_TX +#include +#define BCM_VLAN 1 +#endif + +#ifdef __BIG_ENDIAN +#define BIG_ENDIAN_HOST 1 +#endif + +#if (LINUX_VERSION_CODE < 0x020327) +#define __raw_readl readl +#define __raw_writel writel +#endif + +#include "lm.h" +#include "queue.h" +#include "tigon3.h" + +extern int MM_Packet_Desc_Size; + +#define MM_PACKET_DESC_SIZE MM_Packet_Desc_Size + +DECLARE_QUEUE_TYPE(UM_RX_PACKET_Q, MAX_RX_PACKET_DESC_COUNT+1); + +#define MAX_MEM 16 + +#if (LINUX_VERSION_CODE < 0x020211) +typedef u32 dma_addr_t; +#endif + +#if (LINUX_VERSION_CODE < 0x02030e) +#define net_device device +#define netif_carrier_on(dev) +#define netif_carrier_off(dev) +#endif + +#if (LINUX_VERSION_CODE < 0x02032b) +#define tasklet_struct tq_struct +#endif + +typedef struct _UM_DEVICE_BLOCK { + LM_DEVICE_BLOCK lm_dev; + struct net_device *dev; + struct pci_dev *pdev; + struct net_device *next_module; + char *name; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pfs_entry; + char pfs_name[32]; +#endif + void *mem_list[MAX_MEM]; + dma_addr_t dma_list[MAX_MEM]; + int mem_size_list[MAX_MEM]; + int mem_list_num; + int index; + int opened; + int delayed_link_ind; /* Delay link status during initial load */ + int adapter_just_inited; /* the first few seconds after init. */ + int spurious_int; + int timer_interval; + int adaptive_expiry; + int crc_counter_expiry; + int poll_tbi_expiry; + int tx_full; + int tx_queued; + int line_speed; /* in Mbps, 0 if link is down */ + UM_RX_PACKET_Q rx_out_of_buf_q; + int rx_out_of_buf; + int rx_buf_repl_thresh; + int rx_buf_repl_panic_thresh; + int rx_buf_align; + struct timer_list timer; + int do_global_lock; + spinlock_t global_lock; + spinlock_t undi_lock; + spinlock_t phy_lock; + long undi_flags; + volatile unsigned long interrupt; + atomic_t intr_sem; + int tasklet_pending; + int tasklet_busy; + struct tasklet_struct tasklet; + struct net_device_stats stats; +#ifdef NICE_SUPPORT + void (*nice_rx)( struct sk_buff*, void* ); + void* nice_ctx; +#endif /* NICE_SUPPORT */ +#ifdef NETIF_F_HW_VLAN_TX + struct vlan_group *vlgrp; +#endif + int adaptive_coalesce; + uint rx_last_cnt; + uint tx_last_cnt; + uint rx_curr_coalesce_frames; + uint rx_curr_coalesce_ticks; + uint tx_curr_coalesce_frames; +#if TIGON3_DEBUG + uint tx_zc_count; + uint tx_chksum_count; + uint tx_himem_count; + uint rx_good_chksum_count; +#endif + uint rx_bad_chksum_count; + uint rx_misc_errors; +} UM_DEVICE_BLOCK, *PUM_DEVICE_BLOCK; + +#define MM_ACQUIRE_UNDI_LOCK(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + long flags; \ + spin_lock_irqsave(&((PUM_DEVICE_BLOCK)(_pDevice))->undi_lock, flags); \ + ((PUM_DEVICE_BLOCK)(_pDevice))->undi_flags = flags; \ + } + +#define MM_RELEASE_UNDI_LOCK(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + long flags = ((PUM_DEVICE_BLOCK) (_pDevice))->undi_flags; \ + spin_unlock_irqrestore(&((PUM_DEVICE_BLOCK)(_pDevice))->undi_lock, flags); \ + } + +#define MM_ACQUIRE_PHY_LOCK_IN_IRQ(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + spin_lock(&((PUM_DEVICE_BLOCK)(_pDevice))->phy_lock); \ + } + +#define MM_RELEASE_PHY_LOCK_IN_IRQ(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + spin_unlock(&((PUM_DEVICE_BLOCK)(_pDevice))->phy_lock); \ + } + +#define MM_ACQUIRE_INT_LOCK(_pDevice) \ + while (((PUM_DEVICE_BLOCK) _pDevice)->interrupt) + +#define MM_RELEASE_INT_LOCK(_pDevice) + +#define MM_UINT_PTR(_ptr) ((unsigned long) (_ptr)) + +#define DbgPrint(fmt, arg...) printk(KERN_WARNING fmt, ##arg) +#if defined(CONFIG_X86) +#define DbgBreakPoint() __asm__("int $129") +#else +#define DbgBreakPoint() +#endif +#define MM_Wait(time) udelay(time) + +#endif diff -Nur linux-2.4.19/drivers/net/bcm/nicext.h linux-2.4.19-sgi211r3/drivers/net/bcm/nicext.h --- linux-2.4.19/drivers/net/bcm/nicext.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/nicext.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,110 @@ +/**************************************************************************** + * Copyright(c) 2000-2001 Broadcom Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Name: nicext.h + * + * Description: Broadcom Network Interface Card Extension (NICE) is an + * extension to Linux NET device kernel mode drivers. + * NICE is designed to provide additional functionalities, + * such as receive packet intercept. To support Broadcom NICE, + * the network device driver can be modified by adding an + * device ioctl handler and by indicating receiving packets + * to the NICE receive handler. Broadcom NICE will only be + * enabled by a NICE-aware intermediate driver, such as + * Broadcom Advanced Server Program Driver (BASP). When NICE + * is not enabled, the modified network device drivers + * functions exactly as other non-NICE aware drivers. + * + * Author: Frankie Fan + * + * Created: September 17, 2000 + * + ****************************************************************************/ +#ifndef _nicext_h_ +#define _nicext_h_ + +/* + * ioctl for NICE + */ +#define SIOCNICE SIOCDEVPRIVATE+7 + +/* + * SIOCNICE: + * + * The following structure needs to be less than IFNAMSIZ (16 bytes) because + * we're overloading ifreq.ifr_ifru. + * + * If 16 bytes is not enough, we should consider relaxing this because + * this is no field after ifr_ifru in the ifreq structure. But we may + * run into future compatiability problem in case of changing struct ifreq. + */ +struct nice_req +{ + __u32 cmd; + + union + { +#ifdef __KERNEL__ + /* cmd = NICE_CMD_SET_RX or NICE_CMD_GET_RX */ + struct + { + void (*nrqus1_rx)( struct sk_buff*, void* ); + void* nrqus1_ctx; + } nrqu_nrqus1; + + /* cmd = NICE_CMD_QUERY_SUPPORT */ + struct + { + __u32 nrqus2_magic; + __u32 nrqus2_support_rx:1; + __u32 nrqus2_support_vlan:1; + __u32 nrqus2_support_get_speed:1; + } nrqu_nrqus2; +#endif + + /* cmd = NICE_CMD_GET_SPEED */ + struct + { + unsigned int nrqus3_speed; /* 0 if link is down, */ + /* otherwise speed in Mbps */ + } nrqu_nrqus3; + + /* cmd = NICE_CMD_BLINK_LED */ + struct + { + unsigned int nrqus4_blink_time; /* blink duration in seconds */ + } nrqu_nrqus4; + + } nrq_nrqu; +}; + +#define nrq_rx nrq_nrqu.nrqu_nrqus1.nrqus1_rx +#define nrq_ctx nrq_nrqu.nrqu_nrqus1.nrqus1_ctx +#define nrq_support_rx nrq_nrqu.nrqu_nrqus2.nrqus2_support_rx +#define nrq_magic nrq_nrqu.nrqu_nrqus2.nrqus2_magic +#define nrq_support_vlan nrq_nrqu.nrqu_nrqus2.nrqus2_support_vlan +#define nrq_support_get_speed nrq_nrqu.nrqu_nrqus2.nrqus2_support_get_speed +#define nrq_speed nrq_nrqu.nrqu_nrqus3.nrqus3_speed +#define nrq_blink_time nrq_nrqu.nrqu_nrqus4.nrqus4_blink_time + +/* + * magic constants + */ +#define NICE_REQUESTOR_MAGIC 0x4543494E // NICE in ascii +#define NICE_DEVICE_MAGIC 0x4E494345 // ECIN in ascii + +/* + * command field + */ +#define NICE_CMD_QUERY_SUPPORT 0x00000001 +#define NICE_CMD_SET_RX 0x00000002 +#define NICE_CMD_GET_RX 0x00000003 +#define NICE_CMD_GET_SPEED 0x00000004 +#define NICE_CMD_BLINK_LED 0x00000005 + +#endif // _nicext_h_ + diff -Nur linux-2.4.19/drivers/net/bcm/queue.h linux-2.4.19-sgi211r3/drivers/net/bcm/queue.h --- linux-2.4.19/drivers/net/bcm/queue.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/queue.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,342 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* Queue functions. */ +/* void QQ_InitQueue(PQQ_CONTAINER pQueue) */ +/* char QQ_Full(PQQ_CONTAINER pQueue) */ +/* char QQ_Empty(PQQ_CONTAINER pQueue) */ +/* unsigned int QQ_GetSize(PQQ_CONTAINER pQueue) */ +/* unsigned int QQ_GetEntryCnt(PQQ_CONTAINER pQueue) */ +/* char QQ_PushHead(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ +/* char QQ_PushTail(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ +/* PQQ_ENTRY QQ_PopHead(PQQ_CONTAINER pQueue) */ +/* PQQ_ENTRY QQ_PopTail(PQQ_CONTAINER pQueue) */ +/* PQQ_ENTRY QQ_GetHead(PQQ_CONTAINER pQueue, unsigned int Idx) */ +/* PQQ_ENTRY QQ_GetTail(PQQ_CONTAINER pQueue, unsigned int Idx) */ +/* */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef BCM_QUEUE_H +#define BCM_QUEUE_H + + + +/******************************************************************************/ +/* Queue definitions. */ +/******************************************************************************/ + +/* Entry for queueing. */ +typedef void *PQQ_ENTRY; + + +/* Queue header -- base type. */ +typedef struct { + unsigned int Head; + unsigned int Tail; + unsigned int Size; + atomic_t EntryCnt; + PQQ_ENTRY Array[1]; +} QQ_CONTAINER, *PQQ_CONTAINER; + + +/* Declare queue type macro. */ +#define DECLARE_QUEUE_TYPE(_QUEUE_TYPE, _QUEUE_SIZE) \ + \ + typedef struct { \ + QQ_CONTAINER Container; \ + PQQ_ENTRY EntryBuffer[_QUEUE_SIZE]; \ + } _QUEUE_TYPE, *P##_QUEUE_TYPE + + + +/******************************************************************************/ +/* Compilation switches. */ +/******************************************************************************/ + +#if DBG +#undef QQ_NO_OVERFLOW_CHECK +#undef QQ_NO_UNDERFLOW_CHECK +#endif /* DBG */ + +#ifdef QQ_USE_MACROS +/* notdone */ +#else + +#ifdef QQ_NO_INLINE +#define __inline +#endif /* QQ_NO_INLINE */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static void +QQ_InitQueue( +PQQ_CONTAINER pQueue, +unsigned int QueueSize) { + pQueue->Head = 0; + pQueue->Tail = 0; + pQueue->Size = QueueSize+1; + atomic_set(&pQueue->EntryCnt, 0); +} /* QQ_InitQueue */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static char +QQ_Full( +PQQ_CONTAINER pQueue) { + unsigned int NewHead; + + NewHead = (pQueue->Head + 1) % pQueue->Size; + + return(NewHead == pQueue->Tail); +} /* QQ_Full */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static char +QQ_Empty( +PQQ_CONTAINER pQueue) { + return(pQueue->Head == pQueue->Tail); +} /* QQ_Empty */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static unsigned int +QQ_GetSize( +PQQ_CONTAINER pQueue) { + return pQueue->Size; +} /* QQ_GetSize */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static unsigned int +QQ_GetEntryCnt( +PQQ_CONTAINER pQueue) { + return atomic_read(&pQueue->EntryCnt); +} /* QQ_GetEntryCnt */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* TRUE entry was added successfully. */ +/* FALSE queue is full. */ +/******************************************************************************/ +__inline static char +QQ_PushHead( +PQQ_CONTAINER pQueue, +PQQ_ENTRY pEntry) { + unsigned int Head; + + Head = (pQueue->Head + 1) % pQueue->Size; + +#if !defined(QQ_NO_OVERFLOW_CHECK) + if(Head == pQueue->Tail) { + return 0; + } /* if */ +#endif /* QQ_NO_OVERFLOW_CHECK */ + + pQueue->Array[pQueue->Head] = pEntry; + wmb(); + pQueue->Head = Head; + atomic_inc(&pQueue->EntryCnt); + + return -1; +} /* QQ_PushHead */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* TRUE entry was added successfully. */ +/* FALSE queue is full. */ +/******************************************************************************/ +__inline static char +QQ_PushTail( +PQQ_CONTAINER pQueue, +PQQ_ENTRY pEntry) { + unsigned int Tail; + + Tail = pQueue->Tail; + if(Tail == 0) { + Tail = pQueue->Size; + } /* if */ + Tail--; + +#if !defined(QQ_NO_OVERFLOW_CHECK) + if(Tail == pQueue->Head) { + return 0; + } /* if */ +#endif /* QQ_NO_OVERFLOW_CHECK */ + + pQueue->Array[Tail] = pEntry; + wmb(); + pQueue->Tail = Tail; + atomic_inc(&pQueue->EntryCnt); + + return -1; +} /* QQ_PushTail */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_PopHead( +PQQ_CONTAINER pQueue) { + unsigned int Head; + PQQ_ENTRY Entry; + + Head = pQueue->Head; + +#if !defined(QQ_NO_UNDERFLOW_CHECK) + if(Head == pQueue->Tail) { + return (PQQ_ENTRY) 0; + } /* if */ +#endif /* QQ_NO_UNDERFLOW_CHECK */ + + if(Head == 0) { + Head = pQueue->Size; + } /* if */ + Head--; + + Entry = pQueue->Array[Head]; + mb(); + pQueue->Head = Head; + atomic_dec(&pQueue->EntryCnt); + + return Entry; +} /* QQ_PopHead */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_PopTail( +PQQ_CONTAINER pQueue) { + unsigned int Tail; + PQQ_ENTRY Entry; + + Tail = pQueue->Tail; + +#if !defined(QQ_NO_UNDERFLOW_CHECK) + if(Tail == pQueue->Head) { + return (PQQ_ENTRY) 0; + } /* if */ +#endif /* QQ_NO_UNDERFLOW_CHECK */ + + Entry = pQueue->Array[Tail]; + mb(); + pQueue->Tail = (Tail + 1) % pQueue->Size; + atomic_dec(&pQueue->EntryCnt); + + return Entry; +} /* QQ_PopTail */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_GetHead( + PQQ_CONTAINER pQueue, + unsigned int Idx) +{ + if(Idx >= atomic_read(&pQueue->EntryCnt)) + { + return (PQQ_ENTRY) 0; + } + + if(pQueue->Head > Idx) + { + Idx = pQueue->Head - Idx; + } + else + { + Idx = pQueue->Size - (Idx - pQueue->Head); + } + Idx--; + + return pQueue->Array[Idx]; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_GetTail( + PQQ_CONTAINER pQueue, + unsigned int Idx) +{ + if(Idx >= atomic_read(&pQueue->EntryCnt)) + { + return (PQQ_ENTRY) 0; + } + + Idx += pQueue->Tail; + if(Idx >= pQueue->Size) + { + Idx = Idx - pQueue->Size; + } + + return pQueue->Array[Idx]; +} + +#endif /* QQ_USE_MACROS */ + + + +#endif /* QUEUE_H */ diff -Nur linux-2.4.19/drivers/net/bcm/tigon3.c linux-2.4.19-sgi211r3/drivers/net/bcm/tigon3.c --- linux-2.4.19/drivers/net/bcm/tigon3.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/tigon3.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,6037 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + +#include "mm.h" + + + +/******************************************************************************/ +/* Local functions. */ +/******************************************************************************/ + +LM_STATUS LM_Abort(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_QueueRxPackets(PLM_DEVICE_BLOCK pDevice); + +static LM_STATUS LM_TranslateRequestedMediaType( + LM_REQUESTED_MEDIA_TYPE RequestedMediaType, + PLM_MEDIA_TYPE pMediaType, PLM_LINE_SPEED pLineSpeed, + PLM_DUPLEX_MODE pDuplexMode); + +static LM_STATUS LM_InitBcm540xPhy(PLM_DEVICE_BLOCK pDevice); + +__inline static LM_VOID LM_ServiceRxInterrupt(PLM_DEVICE_BLOCK pDevice); +__inline static LM_VOID LM_ServiceTxInterrupt(PLM_DEVICE_BLOCK pDevice); + +static LM_STATUS LM_ForceAutoNegBcm540xPhy(PLM_DEVICE_BLOCK pDevice, + LM_REQUESTED_MEDIA_TYPE RequestedMediaType, LM_BOOL WaitForLink); +static LM_STATUS LM_ForceAutoNeg(PLM_DEVICE_BLOCK pDevice, + LM_REQUESTED_MEDIA_TYPE RequestedMediaType, LM_BOOL WaitForLink); +static LM_UINT32 GetPhyAdFlowCntrlSettings(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_SetFlowControl(PLM_DEVICE_BLOCK pDevice, + LM_UINT32 LocalPhyAd, LM_UINT32 RemotePhyAd); +STATIC LM_STATUS LM_SetupFiberPhy(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_SetupCopperPhy(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_InitBcm800xPhy(PLM_DEVICE_BLOCK pDevice); +STATIC PLM_ADAPTER_INFO LM_GetAdapterInfoBySsid(LM_UINT16 Svid, LM_UINT16 Ssid); +STATIC LM_STATUS LM_DmaTest(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pBufferVirt, + LM_PHYSICAL_ADDRESS BufferPhy, LM_UINT32 BufferSize); +STATIC LM_STATUS LM_HaltCpu(PLM_DEVICE_BLOCK pDevice,LM_UINT32 cpu_number); +STATIC LM_STATUS LM_ResetChip(PLM_DEVICE_BLOCK pDevice); + + +/******************************************************************************/ +/* External functions. */ +/******************************************************************************/ + +LM_STATUS LM_LoadRlsFirmware(PLM_DEVICE_BLOCK pDevice); + + +LM_UINT32 +LM_RegRd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register) +{ +#if PCIX_TARGET_WORKAROUND + if (pDevice->UndiFix) + { + return (LM_RegRdInd(pDevice, Register)); + } + else +#endif + { + return (REG_RD_OFFSET(pDevice, Register)); + } +} + +LM_VOID +LM_RegWr(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register, LM_UINT32 Value32) +{ +#if PCIX_TARGET_WORKAROUND + if (pDevice->EnablePciXFix) + { + LM_RegWrInd(pDevice, Register, Value32); + } + else +#endif + { + REG_WR_OFFSET(pDevice, Register, Value32); + } +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_UINT32 +LM_RegRdInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 Register) { + LM_UINT32 Value32; + +#if PCIX_TARGET_WORKAROUND + MM_ACQUIRE_UNDI_LOCK(pDevice); +#endif + MM_WriteConfig32(pDevice, T3_PCI_REG_ADDR_REG, Register); + MM_ReadConfig32(pDevice, T3_PCI_REG_DATA_REG, &Value32); +#if PCIX_TARGET_WORKAROUND + MM_RELEASE_UNDI_LOCK(pDevice); +#endif + + return Value32; +} /* LM_RegRdInd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_RegWrInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 Register, +LM_UINT32 Value32) { + +#if PCIX_TARGET_WORKAROUND + MM_ACQUIRE_UNDI_LOCK(pDevice); +#endif + MM_WriteConfig32(pDevice, T3_PCI_REG_ADDR_REG, Register); + MM_WriteConfig32(pDevice, T3_PCI_REG_DATA_REG, Value32); +#if PCIX_TARGET_WORKAROUND + MM_RELEASE_UNDI_LOCK(pDevice); +#endif +} /* LM_RegWrInd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_UINT32 +LM_MemRdInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 MemAddr) { + LM_UINT32 Value32; + + MM_ACQUIRE_UNDI_LOCK(pDevice); +#ifdef BIG_ENDIAN_HOST + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr); + Value32 = REG_RD(pDevice, PciCfg.MemWindowData); + /* Value32 = REG_RD(pDevice,uIntMem.Mbuf[(MemAddr & 0x7fff)/4]); */ +#else + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr); + MM_ReadConfig32(pDevice, T3_PCI_MEM_WIN_DATA_REG, &Value32); +#endif + MM_RELEASE_UNDI_LOCK(pDevice); + + return Value32; +} /* LM_MemRdInd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_MemWrInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 MemAddr, +LM_UINT32 Value32) { + MM_ACQUIRE_UNDI_LOCK(pDevice); +#ifdef BIG_ENDIAN_HOST + REG_WR(pDevice,PciCfg.MemWindowBaseAddr,MemAddr); + REG_WR(pDevice,uIntMem.Mbuf[(MemAddr & 0x7fff)/4],Value32); +#else + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_DATA_REG, Value32); +#endif + MM_RELEASE_UNDI_LOCK(pDevice); +} /* LM_MemWrInd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_QueueRxPackets( +PLM_DEVICE_BLOCK pDevice) { + LM_STATUS Lmstatus; + PLM_PACKET pPacket; + PT3_RCV_BD pRcvBd; + LM_UINT32 StdBdAdded = 0; +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + LM_UINT32 JumboBdAdded = 0; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + Lmstatus = LM_STATUS_SUCCESS; + + pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + while(pPacket) { + switch(pPacket->u.Rx.RcvProdRing) { +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + case T3_JUMBO_RCV_PROD_RING: /* Jumbo Receive Ring. */ + /* Initialize the buffer descriptor. */ + pRcvBd = + &pDevice->pRxJumboBdVirt[pDevice->RxJumboProdIdx]; + pRcvBd->Flags = RCV_BD_FLAG_END | RCV_BD_FLAG_JUMBO_RING; + pRcvBd->Len = (LM_UINT16) pDevice->RxJumboBufferSize; + + /* Initialize the receive buffer pointer */ + pRcvBd->HostAddr.Low = pPacket->u.Rx.RxBufferPhy.Low; + pRcvBd->HostAddr.High = pPacket->u.Rx.RxBufferPhy.High; + + /* The opaque field may point to an offset from a fix addr. */ + pRcvBd->Opaque = (LM_UINT32) (MM_UINT_PTR(pPacket) - + MM_UINT_PTR(pDevice->pPacketDescBase)); + + /* Update the producer index. */ + pDevice->RxJumboProdIdx = (pDevice->RxJumboProdIdx + 1) & + T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK; + + JumboBdAdded++; + break; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + case T3_STD_RCV_PROD_RING: /* Standard Receive Ring. */ + /* Initialize the buffer descriptor. */ + pRcvBd = &pDevice->pRxStdBdVirt[pDevice->RxStdProdIdx]; + pRcvBd->Flags = RCV_BD_FLAG_END; + pRcvBd->Len = MAX_STD_RCV_BUFFER_SIZE; + + /* Initialize the receive buffer pointer */ + pRcvBd->HostAddr.Low = pPacket->u.Rx.RxBufferPhy.Low; + pRcvBd->HostAddr.High = pPacket->u.Rx.RxBufferPhy.High; + + /* The opaque field may point to an offset from a fix addr. */ + pRcvBd->Opaque = (LM_UINT32) (MM_UINT_PTR(pPacket) - + MM_UINT_PTR(pDevice->pPacketDescBase)); + + /* Update the producer index. */ + pDevice->RxStdProdIdx = (pDevice->RxStdProdIdx + 1) & + T3_STD_RCV_RCB_ENTRY_COUNT_MASK; + + StdBdAdded++; + break; + + case T3_UNKNOWN_RCV_PROD_RING: + default: + Lmstatus = LM_STATUS_FAILURE; + break; + } /* switch */ + + /* Bail out if there is any error. */ + if(Lmstatus != LM_STATUS_SUCCESS) + { + break; + } + + pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + } /* while */ + + wmb(); + /* Update the procedure index. */ + if(StdBdAdded) + { + MB_REG_WR(pDevice, Mailbox.RcvStdProdIdx.Low, pDevice->RxStdProdIdx); + } +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + if(JumboBdAdded) + { + MB_REG_WR(pDevice, Mailbox.RcvJumboProdIdx.Low, + pDevice->RxJumboProdIdx); + } +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + return Lmstatus; +} /* LM_QueueRxPackets */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_VOID +LM_NvramInit( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + LM_UINT32 j; + + /* Intialize clock period and state machine. */ + Value32 = SEEPROM_ADDR_CLK_PERD(SEEPROM_CLOCK_PERIOD) | + SEEPROM_ADDR_FSM_RESET; + REG_WR(pDevice, Grc.EepromAddr, Value32); + + for(j = 0; j < 100; j++) + { + MM_Wait(10); + } + + /* Serial eeprom access using the Grc.EepromAddr/EepromData registers. */ + Value32 = REG_RD(pDevice, Grc.LocalCtrl); + REG_WR(pDevice, Grc.LocalCtrl, Value32 | GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM); + + /* Set the 5701 compatibility mode if we are using EEPROM. */ + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && + T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701) + { + Value32 = REG_RD(pDevice, Nvram.Config1); + if((Value32 & FLASH_INTERFACE_ENABLE) == 0) + { + /* Use the new interface to read EEPROM. */ + Value32 &= ~FLASH_COMPAT_BYPASS; + + REG_WR(pDevice, Nvram.Config1, Value32); + } + } + for(j = 0; j < 100; j++) + { + MM_Wait(10); + } + +} /* LM_NvRamInit */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_EepromRead( + PLM_DEVICE_BLOCK pDevice, + LM_UINT32 Offset, + LM_UINT32 *pData) +{ + LM_UINT32 Value32; + LM_UINT32 Addr; + LM_UINT32 Dev; + LM_UINT32 j; + + if(Offset > SEEPROM_CHIP_SIZE) + { + return LM_STATUS_FAILURE; + } + + Dev = Offset / SEEPROM_CHIP_SIZE; + Addr = Offset % SEEPROM_CHIP_SIZE; + + Value32 = REG_RD(pDevice, Grc.EepromAddr); + Value32 &= ~(SEEPROM_ADDR_ADDRESS_MASK | SEEPROM_ADDR_DEV_ID_MASK | + SEEPROM_ADDR_RW_MASK); + REG_WR(pDevice, Grc.EepromAddr, Value32 | SEEPROM_ADDR_DEV_ID(Dev) | + SEEPROM_ADDR_ADDRESS(Addr) | SEEPROM_ADDR_START | SEEPROM_ADDR_READ); + + for(j = 0; j < 2000; j++) + { + Value32 = REG_RD(pDevice, Grc.EepromAddr); + if(Value32 & SEEPROM_ADDR_COMPLETE) + { + break; + } + MM_Wait(10); + } + + if(Value32 & SEEPROM_ADDR_COMPLETE) + { + Value32 = REG_RD(pDevice, Grc.EepromData); + *pData = Value32; + + return LM_STATUS_SUCCESS; + } + + return LM_STATUS_FAILURE; +} /* LM_EepromRead */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_NvramRead( + PLM_DEVICE_BLOCK pDevice, + LM_UINT32 Offset, + LM_UINT32 *pData) +{ + LM_UINT32 Value32; + LM_STATUS Status; + LM_UINT32 j; + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Status = LM_EepromRead(pDevice, Offset, pData); + } + else + { + /* Determine if we have flash or EEPROM. */ + Value32 = REG_RD(pDevice, Nvram.Config1); + if(Value32 & FLASH_INTERFACE_ENABLE) + { + if(Value32 & FLASH_SSRAM_BUFFERRED_MODE) + { + Offset = ((Offset/BUFFERED_FLASH_PAGE_SIZE) << + BUFFERED_FLASH_PAGE_POS) + + (Offset % BUFFERED_FLASH_PAGE_SIZE); + } + } + + REG_WR(pDevice, Nvram.SwArb, SW_ARB_REQ_SET1); + for (j = 0; j < 1000; j++) + { + if (REG_RD(pDevice, Nvram.SwArb) & SW_ARB_GNT1) + { + break; + } + MM_Wait(20); + } + if (j == 1000) + { + return LM_STATUS_FAILURE; + } + + /* Read from flash or EEPROM with the new 5703/02 interface. */ + REG_WR(pDevice, Nvram.Addr, Offset & NVRAM_ADDRESS_MASK); + + REG_WR(pDevice, Nvram.Cmd, NVRAM_CMD_RD | NVRAM_CMD_DO_IT | + NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE); + + /* Wait for the done bit to clear. */ + for(j = 0; j < 500; j++) + { + MM_Wait(10); + + Value32 = REG_RD(pDevice, Nvram.Cmd); + if(!(Value32 & NVRAM_CMD_DONE)) + { + break; + } + } + + /* Wait for the done bit. */ + if(!(Value32 & NVRAM_CMD_DONE)) + { + for(j = 0; j < 500; j++) + { + MM_Wait(10); + + Value32 = REG_RD(pDevice, Nvram.Cmd); + if(Value32 & NVRAM_CMD_DONE) + { + MM_Wait(10); + + *pData = REG_RD(pDevice, Nvram.ReadData); + + /* Change the endianess. */ + *pData = ((*pData & 0xff) << 24)| ((*pData & 0xff00) << 8)| + ((*pData & 0xff0000) >> 8) | ((*pData >> 24) & 0xff); + + break; + } + } + } + + REG_WR(pDevice, Nvram.SwArb, SW_ARB_REQ_CLR1); + if(Value32 & NVRAM_CMD_DONE) + { + Status = LM_STATUS_SUCCESS; + } + else + { + Status = LM_STATUS_FAILURE; + } + } + + return Status; +} /* LM_NvramRead */ + + + +STATIC void +LM_ReadVPD(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT8 Vpd[256]; + LM_UINT32 *Vpd_dptr = (LM_UINT32 *) Vpd; + LM_UINT32 Value32; + unsigned int j; + + /* Read PN from VPD */ + for (j = 0; j < 256; j += 4, Vpd_dptr++ ) + { + if (LM_NvramRead(pDevice, 0x100 + j, &Value32) != LM_STATUS_SUCCESS) { + printk(KERN_ERR "VPD read failed\n"); + return; + } + *Vpd_dptr = cpu_to_le32(Value32); + } + for (j = 0; j < 256; ) + { + unsigned int Vpd_r_len; + unsigned int Vpd_r_end; + + if ((Vpd[j] == 0x82) || (Vpd[j] == 0x91)) + { + j = j + 3 + Vpd[j + 1] + (Vpd[j + 2] << 8); + } + else if (Vpd[j] == 0x90) + { + Vpd_r_len = Vpd[j + 1] + (Vpd[j + 2] << 8); + j += 3; + Vpd_r_end = Vpd_r_len + j; + while (j < Vpd_r_end) + { + if ((Vpd[j] == 'P') && (Vpd[j + 1] == 'N')) + { + unsigned int len = Vpd[j + 2]; + + if (len <= 24) + { + memcpy(pDevice->PartNo, &Vpd[j + 3], len); + } + break; + } + else + { + if (Vpd[j + 2] == 0) + { + break; + } + j = j + Vpd[j + 2]; + } + } + break; + } + else { + break; + } + } +} + +STATIC void +LM_ReadBootCodeVersion(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32, offset, ver_offset; + int i; + + if (LM_NvramRead(pDevice, 0x0, &Value32) != LM_STATUS_SUCCESS) + return; + if (Value32 != 0xaa559966) + return; + if (LM_NvramRead(pDevice, 0xc, &offset) != LM_STATUS_SUCCESS) + return; + + offset = ((offset & 0xff) << 24)| ((offset & 0xff00) << 8)| + ((offset & 0xff0000) >> 8) | ((offset >> 24) & 0xff); + if (LM_NvramRead(pDevice, offset, &Value32) != LM_STATUS_SUCCESS) + return; + if ((Value32 == 0x0300000e) && + (LM_NvramRead(pDevice, offset + 4, &Value32) == LM_STATUS_SUCCESS) && + (Value32 == 0)) { + + if (LM_NvramRead(pDevice, offset + 8, &ver_offset) != LM_STATUS_SUCCESS) + return; + ver_offset = ((ver_offset & 0xff0000) >> 8) | + ((ver_offset >> 24) & 0xff); + for (i = 0; i < 16; i += 4) { + if (LM_NvramRead(pDevice, offset + ver_offset + i, &Value32) != + LM_STATUS_SUCCESS) + { + return; + } + *((LM_UINT32 *) &pDevice->BootCodeVer[i]) = cpu_to_le32(Value32); + } + } + else { + char c; + + if (LM_NvramRead(pDevice, 0x94, &Value32) != LM_STATUS_SUCCESS) + return; + + i = 0; + c = ((Value32 & 0xff0000) >> 16); + + if (c < 10) { + pDevice->BootCodeVer[i++] = c + '0'; + } + else { + pDevice->BootCodeVer[i++] = (c / 10) + '0'; + pDevice->BootCodeVer[i++] = (c % 10) + '0'; + } + pDevice->BootCodeVer[i++] = '.'; + c = (Value32 & 0xff000000) >> 24; + if (c < 10) { + pDevice->BootCodeVer[i++] = c + '0'; + } + else { + pDevice->BootCodeVer[i++] = (c / 10) + '0'; + pDevice->BootCodeVer[i++] = (c % 10) + '0'; + } + pDevice->BootCodeVer[i] = 0; + } +} + +STATIC void +LM_GetBusSpeed(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 PciState = pDevice->PciState; + LM_UINT32 ClockCtrl; + char *SpeedStr = ""; + + if (PciState & T3_PCI_STATE_32BIT_PCI_BUS) + { + strcpy(pDevice->BusSpeedStr, "32-bit "); + } + else + { + strcpy(pDevice->BusSpeedStr, "64-bit "); + } + if (PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) + { + strcat(pDevice->BusSpeedStr, "PCI "); + if (PciState & T3_PCI_STATE_HIGH_BUS_SPEED) + { + SpeedStr = "66MHz"; + } + else + { + SpeedStr = "33MHz"; + } + } + else + { + strcat(pDevice->BusSpeedStr, "PCIX "); + ClockCtrl = REG_RD(pDevice, PciCfg.ClockCtrl) & 0x1f; + switch (ClockCtrl) + { + case 0: + SpeedStr = "33MHz"; + break; + + case 2: + SpeedStr = "50MHz"; + break; + + case 4: + SpeedStr = "66MHz"; + break; + + case 6: + SpeedStr = "100MHz"; + break; + + case 7: + SpeedStr = "133MHz"; + break; + } + } + strcat(pDevice->BusSpeedStr, SpeedStr); +} + +/******************************************************************************/ +/* Description: */ +/* This routine initializes default parameters and reads the PCI */ +/* configurations. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_GetAdapterInfo( +PLM_DEVICE_BLOCK pDevice) +{ + PLM_ADAPTER_INFO pAdapterInfo; + LM_UINT32 Value32; + LM_STATUS Status; + LM_UINT32 j; + LM_UINT32 EeSigFound; + LM_UINT32 EePhyTypeSerdes = 0; + LM_UINT32 EePhyLedMode = 0; + LM_UINT32 EePhyId = 0; + + /* Get Device Id and Vendor Id */ + Status = MM_ReadConfig32(pDevice, PCI_VENDOR_ID_REG, &Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->PciVendorId = (LM_UINT16) Value32; + pDevice->PciDeviceId = (LM_UINT16) (Value32 >> 16); + + /* If we are not getting the write adapter, exit. */ + if((Value32 != T3_PCI_ID_BCM5700) && + (Value32 != T3_PCI_ID_BCM5701) && + (Value32 != T3_PCI_ID_BCM5702) && + (Value32 != T3_PCI_ID_BCM5702x) && + (Value32 != T3_PCI_ID_BCM5702FE) && + (Value32 != T3_PCI_ID_BCM5703) && + (Value32 != T3_PCI_ID_BCM5703x)) + { + return LM_STATUS_FAILURE; + } + + Status = MM_ReadConfig32(pDevice, PCI_REV_ID_REG, &Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->PciRevId = (LM_UINT8) Value32; + + /* Get IRQ. */ + Status = MM_ReadConfig32(pDevice, PCI_INT_LINE_REG, &Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->Irq = (LM_UINT8) Value32; + + /* Get interrupt pin. */ + pDevice->IntPin = (LM_UINT8) (Value32 >> 8); + + /* Get chip revision id. */ + Status = MM_ReadConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, &Value32); + pDevice->ChipRevId = Value32 >> 16; + + /* Get subsystem vendor. */ + Status = MM_ReadConfig32(pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, &Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->SubsystemVendorId = (LM_UINT16) Value32; + + /* Get PCI subsystem id. */ + pDevice->SubsystemId = (LM_UINT16) (Value32 >> 16); + + /* Get the cache line size. */ + MM_ReadConfig32(pDevice, PCI_CACHE_LINE_SIZE_REG, &Value32); + pDevice->CacheLineSize = (LM_UINT8) Value32; + pDevice->SavedCacheLineReg = Value32; + + /* Get PCI memory base. */ + MM_ReadConfig32(pDevice, PCI_MEM_BASE_ADDR_HIGH, &Value32); + pDevice->MemBaseHigh = Value32; + + MM_ReadConfig32(pDevice, PCI_MEM_BASE_ADDR_LOW, &Value32); + Value32 &= 0xfffffff0; + pDevice->MemBaseLow = Value32; + + /* Initialize require MemBase Size */ + pDevice->MemBaseSize = sizeof(T3_STD_MEM_MAP); + + if(pDevice->ChipRevId != T3_CHIP_ID_5703_A1 && + pDevice->ChipRevId != T3_CHIP_ID_5703_A2) + { + pDevice->UndiFix = FALSE; + } +#if !PCIX_TARGET_WORKAROUND + pDevice->UndiFix = FALSE; +#endif + /* Map the memory base to system address space. */ + if (!pDevice->UndiFix) + { + Status = MM_MapMemBase(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + /* Initialize the memory view pointer. */ + pDevice->pMemView = (PT3_STD_MEM_MAP) pDevice->pMappedMemBase; + } + +#if PCIX_TARGET_WORKAROUND + /* store whether we are in PCI are PCI-X mode */ + pDevice->EnablePciXFix = FALSE; + + MM_ReadConfig32(pDevice, T3_PCI_STATE_REG, &Value32); + if((Value32 & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) == 0) + { + /* Enable PCI-X workaround only if we are running on 5700 BX. */ + if(T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) + { + pDevice->EnablePciXFix = TRUE; + } + } + if (pDevice->UndiFix) + { + pDevice->EnablePciXFix = TRUE; + } +#endif + /* Bx bug: due to the "byte_enable bug" in PCI-X mode, the power */ + /* management register may be clobbered which may cause the */ + /* BCM5700 to go into D3 state. While in this state, we will */ + /* not have memory mapped register access. As a workaround, we */ + /* need to restore the device to D0 state. */ + MM_ReadConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, &Value32); + Value32 |= T3_PM_PME_ASSERTED; + Value32 &= ~T3_PM_POWER_STATE_MASK; + Value32 |= T3_PM_POWER_STATE_D0; + MM_WriteConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, Value32); + + /* read the current PCI command word */ + MM_ReadConfig32(pDevice, PCI_COMMAND_REG, &Value32); + + /* Make sure bus-mastering is enabled. */ + Value32 |= PCI_BUSMASTER_ENABLE; + +#if PCIX_TARGET_WORKAROUND + /* if we are in PCI-X mode, also make sure mem-mapping and SERR#/PERR# + are enabled */ + if (pDevice->EnablePciXFix == TRUE) + { + Value32 |= (PCI_MEM_SPACE_ENABLE | PCI_SYSTEM_ERROR_ENABLE | + PCI_PARITY_ERROR_ENABLE); + } + if (pDevice->UndiFix) + { + Value32 &= ~PCI_MEM_SPACE_ENABLE; + } + +#endif + + if(pDevice->EnableMWI) + { + Value32 |= PCI_MEMORY_WRITE_INVALIDATE; + } + else { + Value32 &= (~PCI_MEMORY_WRITE_INVALIDATE); + } + + /* save the value we are going to write into the PCI command word */ + pDevice->PciCommandStatusWords = Value32; + + Status = MM_WriteConfig32(pDevice, PCI_COMMAND_REG, Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + + /* Set power state to D0. */ + LM_SetPowerState(pDevice, LM_POWER_STATE_D0); + + /* Setup the mode registers. */ + pDevice->MiscHostCtrl = + MISC_HOST_CTRL_MASK_PCI_INT | + MISC_HOST_CTRL_ENABLE_ENDIAN_WORD_SWAP | +#ifdef BIG_ENDIAN_HOST + MISC_HOST_CTRL_ENABLE_ENDIAN_BYTE_SWAP | +#endif /* BIG_ENDIAN_HOST */ + MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS | + MISC_HOST_CTRL_ENABLE_PCI_STATE_REG_RW; + /* write to PCI misc host ctr first in order to enable indirect accesses */ + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, pDevice->MiscHostCtrl); + + REG_WR(pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl); + +#ifdef BIG_ENDIAN_HOST + Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | + GRC_MODE_WORD_SWAP_NON_FRAME_DATA; +#else + Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | GRC_MODE_BYTE_SWAP_DATA; +#endif + REG_WR(pDevice, Grc.Mode, Value32); + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + REG_WR(pDevice, Grc.LocalCtrl, GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1); + } + MM_Wait(40); + + /* Enable indirect memory access */ + REG_WR(pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE); + + if (REG_RD(pDevice, PciCfg.ClockCtrl) & T3_PCI_44MHZ_CORE_CLOCK) + { + REG_WR(pDevice, PciCfg.ClockCtrl, T3_PCI_44MHZ_CORE_CLOCK | + T3_PCI_SELECT_ALTERNATE_CLOCK); + MM_Wait(40); /* required delay is 27usec */ + REG_WR(pDevice, PciCfg.ClockCtrl, T3_PCI_SELECT_ALTERNATE_CLOCK); + MM_Wait(40); /* required delay is 27usec */ + } + REG_WR(pDevice, PciCfg.ClockCtrl, 0); + MM_Wait(40); /* required delay is 27usec */ + REG_WR(pDevice, PciCfg.MemWindowBaseAddr, 0); + +#if PCIX_TARGET_WORKAROUND + MM_ReadConfig32(pDevice, T3_PCI_STATE_REG, &Value32); + if ((pDevice->EnablePciXFix == FALSE) && + ((Value32 & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) == 0)) + { + if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B2 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B5) + { + __raw_writel(0, &(pDevice->pMemView->uIntMem.MemBlock32K[0x300])); + __raw_writel(0, &(pDevice->pMemView->uIntMem.MemBlock32K[0x301])); + __raw_writel(0xffffffff, &(pDevice->pMemView->uIntMem.MemBlock32K[0x301])); + if (__raw_readl(&(pDevice->pMemView->uIntMem.MemBlock32K[0x300]))) + { + pDevice->EnablePciXFix = TRUE; + } + } + } +#endif + + LM_NvramInit(pDevice); + + /* Get the node address. First try to get in from the shared memory. */ + /* If the signature is not present, then get it from the NVRAM. */ + Value32 = MEM_RD_OFFSET(pDevice, T3_MAC_ADDR_HIGH_MAILBOX); + if((Value32 >> 16) == 0x484b) + { + + pDevice->NodeAddress[0] = (LM_UINT8) (Value32 >> 8); + pDevice->NodeAddress[1] = (LM_UINT8) Value32; + + Value32 = MEM_RD_OFFSET(pDevice, T3_MAC_ADDR_LOW_MAILBOX); + + pDevice->NodeAddress[2] = (LM_UINT8) (Value32 >> 24); + pDevice->NodeAddress[3] = (LM_UINT8) (Value32 >> 16); + pDevice->NodeAddress[4] = (LM_UINT8) (Value32 >> 8); + pDevice->NodeAddress[5] = (LM_UINT8) Value32; + + Status = LM_STATUS_SUCCESS; + } + else + { + Status = LM_NvramRead(pDevice, 0x7c, &Value32); + if(Status == LM_STATUS_SUCCESS) + { + pDevice->NodeAddress[0] = (LM_UINT8) (Value32 >> 16); + pDevice->NodeAddress[1] = (LM_UINT8) (Value32 >> 24); + + Status = LM_NvramRead(pDevice, 0x80, &Value32); + + pDevice->NodeAddress[2] = (LM_UINT8) Value32; + pDevice->NodeAddress[3] = (LM_UINT8) (Value32 >> 8); + pDevice->NodeAddress[4] = (LM_UINT8) (Value32 >> 16); + pDevice->NodeAddress[5] = (LM_UINT8) (Value32 >> 24); + } + } + + /* Assign a default address. */ + if(Status != LM_STATUS_SUCCESS) + { + printk(KERN_ERR "Cannot get MAC addr from NVRAM\n"); + return LM_STATUS_FAILURE; + } + + pDevice->PermanentNodeAddress[0] = pDevice->NodeAddress[0]; + pDevice->PermanentNodeAddress[1] = pDevice->NodeAddress[1]; + pDevice->PermanentNodeAddress[2] = pDevice->NodeAddress[2]; + pDevice->PermanentNodeAddress[3] = pDevice->NodeAddress[3]; + pDevice->PermanentNodeAddress[4] = pDevice->NodeAddress[4]; + pDevice->PermanentNodeAddress[5] = pDevice->NodeAddress[5]; + + /* Initialize the default values. */ + pDevice->NoTxPseudoHdrChksum = FALSE; + pDevice->NoRxPseudoHdrChksum = FALSE; + pDevice->NicSendBd = FALSE; + pDevice->TxPacketDescCnt = DEFAULT_TX_PACKET_DESC_COUNT; + pDevice->RxStdDescCnt = DEFAULT_STD_RCV_DESC_COUNT; + pDevice->RxCoalescingTicks = DEFAULT_RX_COALESCING_TICKS; + pDevice->TxCoalescingTicks = DEFAULT_TX_COALESCING_TICKS; + pDevice->RxMaxCoalescedFrames = DEFAULT_RX_MAX_COALESCED_FRAMES; + pDevice->TxMaxCoalescedFrames = DEFAULT_TX_MAX_COALESCED_FRAMES; + pDevice->RxCoalescingTicksDuringInt = BAD_DEFAULT_VALUE; + pDevice->TxCoalescingTicksDuringInt = BAD_DEFAULT_VALUE; + pDevice->RxMaxCoalescedFramesDuringInt = BAD_DEFAULT_VALUE; + pDevice->TxMaxCoalescedFramesDuringInt = BAD_DEFAULT_VALUE; + pDevice->StatsCoalescingTicks = DEFAULT_STATS_COALESCING_TICKS; + pDevice->EnableMWI = FALSE; + pDevice->TxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + pDevice->DisableAutoNeg = FALSE; + pDevice->PhyIntMode = T3_PHY_INT_MODE_AUTO; + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_AUTO; + pDevice->LedMode = LED_MODE_AUTO; + pDevice->ResetPhyOnInit = TRUE; + pDevice->DelayPciGrant = TRUE; + pDevice->UseTaggedStatus = FALSE; + pDevice->OneDmaAtOnce = BAD_DEFAULT_VALUE; + + pDevice->DmaMbufLowMark = T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO; + pDevice->RxMacMbufLowMark = T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO; + pDevice->MbufHighMark = T3_DEF_MBUF_HIGH_WMARK_JUMBO; + + pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_AUTO; + pDevice->TaskOffloadCap = LM_TASK_OFFLOAD_NONE; + pDevice->FlowControlCap = LM_FLOW_CONTROL_AUTO_PAUSE; + pDevice->EnableTbi = FALSE; +#if INCLUDE_TBI_SUPPORT + pDevice->PollTbiLink = BAD_DEFAULT_VALUE; +#endif + + pDevice->MbufBase = T3_NIC_MBUF_POOL_ADDR; + pDevice->MbufSize = T3_NIC_MBUF_POOL_SIZE; + + pDevice->LinkStatus = LM_STATUS_LINK_DOWN; + pDevice->QueueRxPackets = TRUE; + + pDevice->EnableWireSpeed = TRUE; + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Make this is a known adapter. */ + pAdapterInfo = LM_GetAdapterInfoBySsid(pDevice->SubsystemVendorId, + pDevice->SubsystemId); + + pDevice->BondId = REG_RD(pDevice, Grc.MiscCfg) & GRC_MISC_BD_ID_MASK; + if(((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) && + ((pDevice->BondId == 0x10000) || (pDevice->BondId == 0x18000))) || + ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) && + ((pDevice->BondId == 0x14000) || (pDevice->BondId == 0x1c000)))) + { + return LM_STATUS_UNKNOWN_ADAPTER; + } + + /* Get Eeprom info. */ + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_SIG_ADDR); + if (Value32 == T3_NIC_DATA_SIG) + { + EeSigFound = TRUE; + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_NIC_CFG_ADDR); + + /* Determine PHY type. */ + switch (Value32 & T3_NIC_CFG_PHY_TYPE_MASK) + { + case T3_NIC_CFG_PHY_TYPE_COPPER: + EePhyTypeSerdes = FALSE; + break; + + case T3_NIC_CFG_PHY_TYPE_FIBER: + EePhyTypeSerdes = TRUE; + break; + + default: + EePhyTypeSerdes = FALSE; + break; + } + + /* Determine PHY led mode. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + switch(Value32 & T3_NIC_CFG_LED_MODE_MASK) + { + case T3_NIC_CFG_LED_MODE_TRIPLE_SPEED: + EePhyLedMode = LED_MODE_THREE_LINK; + break; + + case T3_NIC_CFG_LED_MODE_LINK_SPEED: + EePhyLedMode = LED_MODE_LINK10; + break; + + default: + EePhyLedMode = LED_MODE_AUTO; + break; + } + } + else + { + switch(Value32 & T3_NIC_CFG_LED_MODE_MASK) + { + case T3_NIC_CFG_LED_MODE_OPEN_DRAIN: + EePhyLedMode = LED_MODE_OPEN_DRAIN; + break; + + case T3_NIC_CFG_LED_MODE_OUTPUT: + EePhyLedMode = LED_MODE_OUTPUT; + break; + + default: + EePhyLedMode = LED_MODE_AUTO; + break; + } + } + if(pDevice->ChipRevId == T3_CHIP_ID_5703_A1 || + pDevice->ChipRevId == T3_CHIP_ID_5703_A2) + { + /* Enable EEPROM write protection. */ + if(Value32 & T3_NIC_EEPROM_WP) + { + pDevice->EepromWp = TRUE; + } + } + + /* Get the PHY Id. */ + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_PHY_ID_ADDR); + if (Value32) + { + EePhyId = (((Value32 & T3_NIC_PHY_ID1_MASK) >> 16) & + PHY_ID1_OUI_MASK) << 10; + + Value32 = Value32 & T3_NIC_PHY_ID2_MASK; + + EePhyId |= ((Value32 & PHY_ID2_OUI_MASK) << 16) | + (Value32 & PHY_ID2_MODEL_MASK) | (Value32 & PHY_ID2_REV_MASK); + } + else + { + EePhyId = 0; + } + } + else + { + EeSigFound = FALSE; + } + + /* Set the PHY address. */ + pDevice->PhyAddr = PHY_DEVICE_ID; + + /* Disable auto polling. */ + pDevice->MiMode = 0xc0000; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + MM_Wait(40); + + /* Get the PHY id. */ + LM_ReadPhy(pDevice, PHY_ID1_REG, &Value32); + pDevice->PhyId = (Value32 & PHY_ID1_OUI_MASK) << 10; + + LM_ReadPhy(pDevice, PHY_ID2_REG, &Value32); + pDevice->PhyId |= ((Value32 & PHY_ID2_OUI_MASK) << 16) | + (Value32 & PHY_ID2_MODEL_MASK) | (Value32 & PHY_ID2_REV_MASK); + + /* Set the EnableTbi flag to false if we have a copper PHY. */ + switch(pDevice->PhyId & PHY_ID_MASK) + { + case PHY_BCM5400_PHY_ID: + pDevice->EnableTbi = FALSE; + break; + + case PHY_BCM5401_PHY_ID: + pDevice->EnableTbi = FALSE; + break; + + case PHY_BCM5411_PHY_ID: + pDevice->EnableTbi = FALSE; + break; + + case PHY_BCM5701_PHY_ID: + pDevice->EnableTbi = FALSE; + break; + + case PHY_BCM5703_PHY_ID: + pDevice->EnableTbi = FALSE; + break; + + case PHY_BCM8002_PHY_ID: + pDevice->EnableTbi = TRUE; + break; + + default: + + if (pAdapterInfo) + { + pDevice->PhyId = pAdapterInfo->PhyId; + pDevice->EnableTbi = pAdapterInfo->Serdes; + } + else if (EeSigFound) + { + pDevice->PhyId = EePhyId; + pDevice->EnableTbi = EePhyTypeSerdes; + } + break; + } + + /* Bail out if we don't know the copper PHY id. */ + if(UNKNOWN_PHY_ID(pDevice->PhyId) && !pDevice->EnableTbi) + { + return LM_STATUS_FAILURE; + } + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) + { + if((pDevice->SavedCacheLineReg & 0xff00) < 0x4000) + { + pDevice->SavedCacheLineReg &= 0xffff00ff; + pDevice->SavedCacheLineReg |= 0x4000; + } + } + /* Change driver parameters. */ + Status = MM_GetConfig(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + +#if INCLUDE_5701_AX_FIX + if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0) + { + pDevice->ResetPhyOnInit = TRUE; + } +#endif + + /* Save the current phy link status. */ + if(!pDevice->EnableTbi) + { + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + /* If we don't have link reset the PHY. */ + if(!(Value32 & PHY_STATUS_LINK_PASS) || pDevice->ResetPhyOnInit) + { + + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_PHY_RESET); + + for(j = 0; j < 100; j++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if(Value32 && !(Value32 & PHY_CTRL_PHY_RESET)) + { + MM_Wait(40); + break; + } + } + + +#if INCLUDE_5701_AX_FIX + /* 5701_AX_BX bug: only advertises 10mb speed. */ + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0) + { + + Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD | + PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL | + PHY_AN_AD_100BASETX_FULL | PHY_AN_AD_100BASETX_HALF; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + + Value32 = BCM540X_AN_AD_1000BASET_HALF | + BCM540X_AN_AD_1000BASET_FULL | BCM540X_CONFIG_AS_MASTER | + BCM540X_ENABLE_CONFIG_AS_MASTER; + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, Value32); + pDevice->advertising1000 = Value32; + + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_RESTART_AUTO_NEG); + } +#endif + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) + { + LM_WritePhy(pDevice, 0x18, 0x0c00); + LM_WritePhy(pDevice, 0x17, 0x201f); + LM_WritePhy(pDevice, 0x15, 0x2aaa); + } + /* Enable Ethernet@WireSpeed. */ + if(pDevice->EnableWireSpeed) + { + LM_WritePhy(pDevice, 0x18, 0x7007); + LM_ReadPhy(pDevice, 0x18, &Value32); + LM_WritePhy(pDevice, 0x18, Value32 | BIT_15 | BIT_4); + } + } + } + + /* Turn off tap power management. */ + if((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x0c20); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0012); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1804); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0013); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1204); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0132); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0232); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x201f); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0a20); + + MM_Wait(40); + } + +#if INCLUDE_TBI_SUPPORT + if(pDevice->EnableTbi) + { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE; + pDevice->PhyIntMode = T3_PHY_INT_MODE_LINK_READY; + if ((pDevice->PollTbiLink == BAD_DEFAULT_VALUE) || + pDevice->DisableAutoNeg) + { + pDevice->PollTbiLink = FALSE; + } + } + else + { + pDevice->PollTbiLink = FALSE; + } +#endif /* INCLUDE_TBI_SUPPORT */ + + /* UseTaggedStatus is only valid for 5701 and later. */ + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->UseTaggedStatus = FALSE; + + pDevice->CoalesceMode = 0; + } + else + { + pDevice->CoalesceMode = HOST_COALESCE_CLEAR_TICKS_ON_RX_BD_EVENT | + HOST_COALESCE_CLEAR_TICKS_ON_TX_BD_EVENT; + } + + /* Set the status block size. */ + if(T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5700_AX && + T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5700_BX) + { + pDevice->CoalesceMode |= HOST_COALESCE_32_BYTE_STATUS_MODE; + } + + /* Check the DURING_INT coalescing ticks parameters. */ + if(pDevice->UseTaggedStatus) + { + if(pDevice->RxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxCoalescingTicksDuringInt = + DEFAULT_RX_COALESCING_TICKS_DURING_INT; + } + + if(pDevice->TxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxCoalescingTicksDuringInt = + DEFAULT_TX_COALESCING_TICKS_DURING_INT; + } + + if(pDevice->RxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxMaxCoalescedFramesDuringInt = + DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT; + } + + if(pDevice->TxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxMaxCoalescedFramesDuringInt = + DEFAULT_TX_MAX_COALESCED_FRAMES_DURING_INT; + } + } + else + { + if(pDevice->RxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxCoalescingTicksDuringInt = 0; + } + + if(pDevice->TxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxCoalescingTicksDuringInt = 0; + } + + if(pDevice->RxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxMaxCoalescedFramesDuringInt = 0; + } + + if(pDevice->TxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxMaxCoalescedFramesDuringInt = 0; + } + } + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + if(pDevice->RxMtu <= (MAX_STD_RCV_BUFFER_SIZE - 8 /* CRC */)) + { + pDevice->RxJumboDescCnt = 0; + if(pDevice->RxMtu <= MAX_ETHERNET_PACKET_SIZE_NO_CRC) + { + pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + } + } + else + { + pDevice->RxJumboBufferSize = (pDevice->RxMtu + 8 /* CRC + VLAN */ + + COMMON_CACHE_LINE_SIZE-1) & ~COMMON_CACHE_LINE_MASK; + + if(pDevice->RxJumboBufferSize > MAX_JUMBO_RCV_BUFFER_SIZE) + { + pDevice->RxJumboBufferSize = DEFAULT_JUMBO_RCV_BUFFER_SIZE; + pDevice->RxMtu = pDevice->RxJumboBufferSize - 8 /* CRC + VLAN */; + } + pDevice->TxMtu = pDevice->RxMtu; + + } +#else + pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + pDevice->RxPacketDescCnt = +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + pDevice->RxJumboDescCnt + +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + pDevice->RxStdDescCnt; + + if(pDevice->TxMtu < MAX_ETHERNET_PACKET_SIZE_NO_CRC) + { + pDevice->TxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + } + + if(pDevice->TxMtu > MAX_JUMBO_TX_BUFFER_SIZE) + { + pDevice->TxMtu = MAX_JUMBO_TX_BUFFER_SIZE; + } + + /* Configure the proper ways to get link change interrupt. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO) + { + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT; + } + else + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_LINK_READY; + } + } + else if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + /* Auto-polling does not work on 5700_AX and 5700_BX. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT; + } + } + + /* Determine the method to get link change status. */ + if(pDevice->LinkChngMode == T3_LINK_CHNG_MODE_AUTO) + { + /* The link status bit in the status block does not work on 5700_AX */ + /* and 5700_BX chips. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_REG; + } + else + { + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_BLOCK; + } + } + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_REG; + } + + /* Configure PHY led mode. */ + if(pDevice->LedMode == LED_MODE_AUTO) + { + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + if(pDevice->SubsystemVendorId == T3_SVID_DELL) + { + pDevice->LedMode = LED_MODE_LINK10; + } + else + { + pDevice->LedMode = LED_MODE_THREE_LINK; + + if(EeSigFound && EePhyLedMode != LED_MODE_AUTO) + { + pDevice->LedMode = EePhyLedMode; + } + } + + /* bug? 5701 in LINK10 mode does not seem to work when */ + /* PhyIntMode is LINK_READY. */ + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && +#if INCLUDE_TBI_SUPPORT + pDevice->EnableTbi == FALSE && +#endif + pDevice->LedMode == LED_MODE_LINK10) + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT; + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_REG; + } + + if(pDevice->EnableTbi) + { + pDevice->LedMode = LED_MODE_THREE_LINK; + } + } + else + { + if(EeSigFound && EePhyLedMode != LED_MODE_AUTO) + { + pDevice->LedMode = EePhyLedMode; + } + else + { + pDevice->LedMode = LED_MODE_OPEN_DRAIN; + } + } + } + + /* Enable OneDmaAtOnce. */ + if(pDevice->OneDmaAtOnce == BAD_DEFAULT_VALUE) + { + pDevice->OneDmaAtOnce = FALSE; + } + + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B2) + { + pDevice->WolSpeed = WOL_SPEED_10MB; + } + else + { + pDevice->WolSpeed = WOL_SPEED_100MB; + } + + /* Offloadings. */ + pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE; + + /* Turn off task offloading on Ax. */ + if(pDevice->ChipRevId == T3_CHIP_ID_5700_B0) + { + pDevice->TaskOffloadCap &= ~(LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_TX_UDP_CHECKSUM); + } + pDevice->PciState = REG_RD(pDevice, PciCfg.PciState); + LM_ReadVPD(pDevice); + LM_ReadBootCodeVersion(pDevice); + LM_GetBusSpeed(pDevice); + + return LM_STATUS_SUCCESS; +} /* LM_GetAdapterInfo */ + +STATIC PLM_ADAPTER_INFO +LM_GetAdapterInfoBySsid( + LM_UINT16 Svid, + LM_UINT16 Ssid) +{ + static LM_ADAPTER_INFO AdapterArr[] = + { + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700A6, PHY_BCM5401_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A5, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700T6, PHY_BCM8002_PHY_ID, 1}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700A9, 0, 1 }, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701T1, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701T8, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A7, 0, 1}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A10, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A12, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95703Ax1, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95703Ax2, PHY_BCM5701_PHY_ID, 0}, + + { T3_SVID_3COM, T3_SSID_3COM_3C996T, PHY_BCM5401_PHY_ID, 0 }, + { T3_SVID_3COM, T3_SSID_3COM_3C996BT, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_3COM, T3_SSID_3COM_3C996SX, 0, 1 }, + { T3_SVID_3COM, T3_SSID_3COM_3C1000T, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_3COM, T3_SSID_3COM_3C940BR01, PHY_BCM5701_PHY_ID, 0 }, + + { T3_SVID_DELL, T3_SSID_DELL_VIPER, PHY_BCM5401_PHY_ID, 0 }, + { T3_SVID_DELL, T3_SSID_DELL_JAGUAR, PHY_BCM5401_PHY_ID, 0 }, + { T3_SVID_DELL, T3_SSID_DELL_MERLOT, PHY_BCM5411_PHY_ID, 0 }, + { T3_SVID_DELL, T3_SSID_DELL_SLIM_MERLOT, PHY_BCM5411_PHY_ID, 0 }, + + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_BANSHEE, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_BANSHEE_2, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_CHANGELING, 0, 1 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_NC7780, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_NC7780_2, PHY_BCM5701_PHY_ID, 0 }, + + }; + LM_UINT32 j; + + for(j = 0; j < sizeof(AdapterArr)/sizeof(LM_ADAPTER_INFO); j++) + { + if(AdapterArr[j].Svid == Svid && AdapterArr[j].Ssid == Ssid) + { + return &AdapterArr[j]; + } + } + + return NULL; +} + + +/******************************************************************************/ +/* Description: */ +/* This routine sets up receive/transmit buffer descriptions queues. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_InitializeAdapter( +PLM_DEVICE_BLOCK pDevice) +{ + LM_PHYSICAL_ADDRESS MemPhy; + PLM_UINT8 pMemVirt; + PLM_PACKET pPacket; + LM_STATUS Status; + LM_UINT32 Size; + LM_UINT32 j; + + /* Set power state to D0. */ + LM_SetPowerState(pDevice, LM_POWER_STATE_D0); + + /* Intialize the queues. */ + QQ_InitQueue(&pDevice->RxPacketReceivedQ.Container, + MAX_RX_PACKET_DESC_COUNT); + QQ_InitQueue(&pDevice->RxPacketFreeQ.Container, + MAX_RX_PACKET_DESC_COUNT); + + QQ_InitQueue(&pDevice->TxPacketFreeQ.Container,MAX_TX_PACKET_DESC_COUNT); + QQ_InitQueue(&pDevice->TxPacketActiveQ.Container,MAX_TX_PACKET_DESC_COUNT); + QQ_InitQueue(&pDevice->TxPacketXmittedQ.Container,MAX_TX_PACKET_DESC_COUNT); + + /* Allocate shared memory for: status block, the buffers for receive */ + /* rings -- standard, mini, jumbo, and return rings. */ + Size = T3_STATUS_BLOCK_SIZE + sizeof(T3_STATS_BLOCK) + + T3_STD_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD) + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD) + +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + T3_RCV_RETURN_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD); + + /* Memory for host based Send BD. */ + if(pDevice->NicSendBd == FALSE) + { + Size += sizeof(T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT; + } + + /* Allocate the memory block. */ + Status = MM_AllocateSharedMemory(pDevice, Size, (PLM_VOID) &pMemVirt, &MemPhy, FALSE); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + + /* Program DMA Read/Write */ + if (pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) + { + pDevice->DmaReadWriteCtrl = 0x763f000f; + } + else + { + LM_UINT32 Value32; + + pDevice->DmaReadWriteCtrl = 0x761b000f; + Value32 = REG_RD(pDevice, PciCfg.ClockCtrl) & 0x1f; + if((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) && + ((Value32 == 6) || (Value32 == 7))) + { + pDevice->OneDmaAtOnce = TRUE; + } + } + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) + { + pDevice->DmaReadWriteCtrl &= 0xfffffff0; + } + + if(pDevice->OneDmaAtOnce) + { + pDevice->DmaReadWriteCtrl |= DMA_CTRL_WRITE_ONE_DMA_AT_ONCE; + } + REG_WR(pDevice, PciCfg.DmaReadWriteCtrl, pDevice->DmaReadWriteCtrl); + + if (LM_DmaTest(pDevice, pMemVirt, MemPhy, 0x400) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + /* Status block. */ + pDevice->pStatusBlkVirt = (PT3_STATUS_BLOCK) pMemVirt; + pDevice->StatusBlkPhy = MemPhy; + pMemVirt += T3_STATUS_BLOCK_SIZE; + LM_INC_PHYSICAL_ADDRESS(&MemPhy, T3_STATUS_BLOCK_SIZE); + + /* Statistics block. */ + pDevice->pStatsBlkVirt = (PT3_STATS_BLOCK) pMemVirt; + pDevice->StatsBlkPhy = MemPhy; + pMemVirt += sizeof(T3_STATS_BLOCK); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, sizeof(T3_STATS_BLOCK)); + + /* Receive standard BD buffer. */ + pDevice->pRxStdBdVirt = (PT3_RCV_BD) pMemVirt; + pDevice->RxStdBdPhy = MemPhy; + + pMemVirt += T3_STD_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + T3_STD_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD)); + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Receive jumbo BD buffer. */ + pDevice->pRxJumboBdVirt = (PT3_RCV_BD) pMemVirt; + pDevice->RxJumboBdPhy = MemPhy; + + pMemVirt += T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD)); +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Receive return BD buffer. */ + pDevice->pRcvRetBdVirt = (PT3_RCV_BD) pMemVirt; + pDevice->RcvRetBdPhy = MemPhy; + + pMemVirt += T3_RCV_RETURN_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + T3_RCV_RETURN_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD)); + + /* Set up Send BD. */ + if(pDevice->NicSendBd == FALSE) + { + pDevice->pSendBdVirt = (PT3_SND_BD) pMemVirt; + pDevice->SendBdPhy = MemPhy; + + pMemVirt += sizeof(T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT; + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + sizeof(T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT); + } + else + { + pDevice->pSendBdVirt = (PT3_SND_BD) + pDevice->pMemView->uIntMem.First32k.BufferDesc; + pDevice->SendBdPhy.High = 0; + pDevice->SendBdPhy.Low = T3_NIC_SND_BUFFER_DESC_ADDR; + } + + /* Allocate memory for packet descriptors. */ + Size = (pDevice->RxPacketDescCnt + + pDevice->TxPacketDescCnt) * MM_PACKET_DESC_SIZE; + Status = MM_AllocateMemory(pDevice, Size, (PLM_VOID *) &pPacket); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->pPacketDescBase = (PLM_VOID) pPacket; + + /* Create transmit packet descriptors from the memory block and add them */ + /* to the TxPacketFreeQ for each send ring. */ + for(j = 0; j < pDevice->TxPacketDescCnt; j++) + { + /* Ring index. */ + pPacket->Flags = 0; + + /* Queue the descriptor in the TxPacketFreeQ of the 'k' ring. */ + QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket); + + /* Get the pointer to the next descriptor. MM_PACKET_DESC_SIZE */ + /* is the total size of the packet descriptor including the */ + /* os-specific extensions in the UM_PACKET structure. */ + pPacket = (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE); + } /* for(j.. */ + + /* Create receive packet descriptors from the memory block and add them */ + /* to the RxPacketFreeQ. Create the Standard packet descriptors. */ + for(j = 0; j < pDevice->RxStdDescCnt; j++) + { + /* Receive producer ring. */ + pPacket->u.Rx.RcvProdRing = T3_STD_RCV_PROD_RING; + + /* Receive buffer size. */ + pPacket->u.Rx.RxBufferSize = MAX_STD_RCV_BUFFER_SIZE; + + /* Add the descriptor to RxPacketFreeQ. */ + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + + /* Get the pointer to the next descriptor. MM_PACKET_DESC_SIZE */ + /* is the total size of the packet descriptor including the */ + /* os-specific extensions in the UM_PACKET structure. */ + pPacket = (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE); + } /* for */ + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Create the Jumbo packet descriptors. */ + for(j = 0; j < pDevice->RxJumboDescCnt; j++) + { + /* Receive producer ring. */ + pPacket->u.Rx.RcvProdRing = T3_JUMBO_RCV_PROD_RING; + + /* Receive buffer size. */ + pPacket->u.Rx.RxBufferSize = pDevice->RxJumboBufferSize; + + /* Add the descriptor to RxPacketFreeQ. */ + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + + /* Get the pointer to the next descriptor. MM_PACKET_DESC_SIZE */ + /* is the total size of the packet descriptor including the */ + /* os-specific extensions in the UM_PACKET structure. */ + pPacket = (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE); + } /* for */ +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Initialize the rest of the packet descriptors. */ + Status = MM_InitializeUmPackets(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } /* if */ + + /* Default receive mask. */ + pDevice->ReceiveMask = LM_ACCEPT_MULTICAST | LM_ACCEPT_BROADCAST | + LM_ACCEPT_UNICAST; + + /* Make sure we are in the first 32k memory window or NicSendBd. */ + REG_WR(pDevice, PciCfg.MemWindowBaseAddr, 0); + + /* Initialize the hardware. */ + Status = LM_ResetAdapter(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + + /* We are done with initialization. */ + pDevice->InitDone = TRUE; + + return LM_STATUS_SUCCESS; +} /* LM_InitializeAdapter */ + + + +/******************************************************************************/ +/* Description: */ +/* This function Enables/Disables a given block. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_CntrlBlock( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 mask,LM_UINT32 cntrl) +{ + LM_UINT32 j,i,data; + LM_UINT32 MaxWaitCnt; + + MaxWaitCnt = 2; + j = 0; + + for(i = 0 ; i < 32; i++) + { + if(!(mask & (1 << i))) + continue; + + switch (1 << i) + { + case T3_BLOCK_DMA_RD: + data = REG_RD(pDevice, DmaRead.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~DMA_READ_MODE_ENABLE; + REG_WR(pDevice, DmaRead.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, DmaRead.Mode) & DMA_READ_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, DmaRead.Mode, data | DMA_READ_MODE_ENABLE); + break; + + case T3_BLOCK_DMA_COMP: + data = REG_RD(pDevice,DmaComp.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~DMA_COMP_MODE_ENABLE; + REG_WR(pDevice, DmaComp.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, DmaComp.Mode) & DMA_COMP_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, DmaComp.Mode, data | DMA_COMP_MODE_ENABLE); + break; + + case T3_BLOCK_RX_BD_INITIATOR: + data = REG_RD(pDevice, RcvBdIn.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~RCV_BD_IN_MODE_ENABLE; + REG_WR(pDevice, RcvBdIn.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, RcvBdIn.Mode) & RCV_BD_IN_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, RcvBdIn.Mode,data | RCV_BD_IN_MODE_ENABLE); + break; + + case T3_BLOCK_RX_BD_COMP: + data = REG_RD(pDevice, RcvBdComp.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~RCV_BD_COMP_MODE_ENABLE; + REG_WR(pDevice, RcvBdComp.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, RcvBdComp.Mode) & RCV_BD_COMP_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, RcvBdComp.Mode,data | RCV_BD_COMP_MODE_ENABLE); + break; + + case T3_BLOCK_DMA_WR: + data = REG_RD(pDevice, DmaWrite.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~DMA_WRITE_MODE_ENABLE; + REG_WR(pDevice, DmaWrite.Mode,data); + + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, DmaWrite.Mode) & DMA_WRITE_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, DmaWrite.Mode,data | DMA_WRITE_MODE_ENABLE); + break; + + case T3_BLOCK_MSI_HANDLER: + data = REG_RD(pDevice, Msi.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~MSI_MODE_ENABLE; + REG_WR(pDevice, Msi.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, Msi.Mode) & MSI_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, Msi.Mode, data |MSI_MODE_ENABLE); + break; + + case T3_BLOCK_RX_LIST_PLMT: + data = REG_RD(pDevice, RcvListPlmt.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~RCV_LIST_PLMT_MODE_ENABLE; + REG_WR(pDevice, RcvListPlmt.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, RcvListPlmt.Mode) & RCV_LIST_PLMT_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, RcvListPlmt.Mode,data | RCV_LIST_PLMT_MODE_ENABLE); + break; + + case T3_BLOCK_RX_LIST_SELECTOR: + data = REG_RD(pDevice, RcvListSel.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~RCV_LIST_SEL_MODE_ENABLE; + REG_WR(pDevice, RcvListSel.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, RcvListSel.Mode) & RCV_LIST_SEL_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, RcvListSel.Mode,data |RCV_LIST_SEL_MODE_ENABLE); + break; + + case T3_BLOCK_RX_DATA_INITIATOR: + data = REG_RD(pDevice, RcvDataBdIn.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~RCV_DATA_BD_IN_MODE_ENABLE; + REG_WR(pDevice, RcvDataBdIn.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, RcvDataBdIn.Mode) & RCV_DATA_BD_IN_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, RcvDataBdIn.Mode, data | RCV_DATA_BD_IN_MODE_ENABLE); + break; + + case T3_BLOCK_RX_DATA_COMP: + data = REG_RD(pDevice, RcvDataComp.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~RCV_DATA_COMP_MODE_ENABLE; + REG_WR(pDevice, RcvDataComp.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, RcvDataBdIn.Mode) & RCV_DATA_COMP_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, RcvDataComp.Mode,data | RCV_DATA_COMP_MODE_ENABLE); + break; + + case T3_BLOCK_HOST_COALESING: + data = REG_RD(pDevice, HostCoalesce.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~HOST_COALESCE_ENABLE; + REG_WR(pDevice, HostCoalesce.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, SndBdIn.Mode) & HOST_COALESCE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, HostCoalesce.Mode, data | HOST_COALESCE_ENABLE); + break; + + case T3_BLOCK_MAC_RX_ENGINE: + if(cntrl == LM_DISABLE) + { + pDevice->RxMode &= ~RX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, MacCtrl.RxMode) & RX_MODE_ENABLE)) + { + break; + } + MM_Wait(10); + } + } + else + { + pDevice->RxMode |= RX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + } + break; + + case T3_BLOCK_MBUF_CLUSTER_FREE: + data = REG_RD(pDevice, MbufClusterFree.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~MBUF_CLUSTER_FREE_MODE_ENABLE; + REG_WR(pDevice, MbufClusterFree.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, MbufClusterFree.Mode) & MBUF_CLUSTER_FREE_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, MbufClusterFree.Mode, data | MBUF_CLUSTER_FREE_MODE_ENABLE); + break; + + case T3_BLOCK_SEND_BD_INITIATOR: + data = REG_RD(pDevice, SndBdIn.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~SND_BD_IN_MODE_ENABLE; + REG_WR(pDevice, SndBdIn.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, SndBdIn.Mode) & SND_BD_IN_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, SndBdIn.Mode, data | SND_BD_IN_MODE_ENABLE); + break; + + case T3_BLOCK_SEND_BD_COMP: + data = REG_RD(pDevice, SndBdComp.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~SND_BD_COMP_MODE_ENABLE; + REG_WR(pDevice, SndBdComp.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, SndBdComp.Mode) & SND_BD_COMP_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, SndBdComp.Mode, data | SND_BD_COMP_MODE_ENABLE); + break; + + case T3_BLOCK_SEND_BD_SELECTOR: + data = REG_RD(pDevice, SndBdSel.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~SND_BD_SEL_MODE_ENABLE; + REG_WR(pDevice, SndBdSel.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, SndBdSel.Mode) & SND_BD_SEL_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, SndBdSel.Mode, data | SND_BD_SEL_MODE_ENABLE); + break; + + case T3_BLOCK_SEND_DATA_INITIATOR: + data = REG_RD(pDevice, SndDataIn.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~T3_SND_DATA_IN_MODE_ENABLE; + REG_WR(pDevice, SndDataIn.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, SndDataIn.Mode) & T3_SND_DATA_IN_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, SndDataIn.Mode,data | T3_SND_DATA_IN_MODE_ENABLE); + break; + + case T3_BLOCK_SEND_DATA_COMP: + data = REG_RD(pDevice, SndDataComp.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~SND_DATA_COMP_MODE_ENABLE; + REG_WR(pDevice, SndDataComp.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, SndDataComp.Mode) & SND_DATA_COMP_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, SndDataComp.Mode,data | SND_DATA_COMP_MODE_ENABLE); + break; + + case T3_BLOCK_MAC_TX_ENGINE: + if(cntrl == LM_DISABLE) + { + pDevice->TxMode &= ~TX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.TxMode, pDevice->TxMode); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, MacCtrl.TxMode) & TX_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + { + pDevice->TxMode |= TX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.TxMode, pDevice->TxMode); + } + break; + + case T3_BLOCK_MEM_ARBITOR: + data = REG_RD(pDevice, MemArbiter.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~T3_MEM_ARBITER_MODE_ENABLE; + REG_WR(pDevice, MemArbiter.Mode, data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, MemArbiter.Mode) & T3_MEM_ARBITER_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, MemArbiter.Mode,data|T3_MEM_ARBITER_MODE_ENABLE); + break; + + case T3_BLOCK_MBUF_MANAGER: + data = REG_RD(pDevice, BufMgr.Mode); + if (cntrl == LM_DISABLE) + { + data &= ~BUFMGR_MODE_ENABLE; + REG_WR(pDevice, BufMgr.Mode,data); + for(j = 0; j < MaxWaitCnt; j++) + { + if(!(REG_RD(pDevice, BufMgr.Mode) & BUFMGR_MODE_ENABLE)) + break; + MM_Wait(10); + } + } + else + REG_WR(pDevice, BufMgr.Mode,data | BUFMGR_MODE_ENABLE); + break; + + case T3_BLOCK_MAC_GLOBAL: + if(cntrl == LM_DISABLE) + { + pDevice->MacMode &= ~(MAC_MODE_ENABLE_TDE | + MAC_MODE_ENABLE_RDE | + MAC_MODE_ENABLE_FHDE); + } + else + { + pDevice->MacMode |= (MAC_MODE_ENABLE_TDE | + MAC_MODE_ENABLE_RDE | + MAC_MODE_ENABLE_FHDE); + } + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + break; + + default: + return LM_STATUS_FAILURE; + } /* switch */ + + if(j >= MaxWaitCnt) + { + return LM_STATUS_FAILURE; + } + } + + return LM_STATUS_SUCCESS; +} + +/******************************************************************************/ +/* Description: */ +/* This function reinitializes the adapter. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_ResetAdapter( +PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + LM_UINT32 j, k; + + /* Disable interrupt. */ + LM_DisableInterrupt(pDevice); + + /* May get a spurious interrupt */ + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED; + + /* Disable transmit and receive DMA engines. Abort all pending requests. */ + if(pDevice->InitDone) + { + LM_Abort(pDevice); + } + + pDevice->ShuttingDown = FALSE; + + LM_ResetChip(pDevice); + + /* Bug: Athlon fix for B3 silicon only. This bit does not do anything */ + /* in other chip revisions. */ + if(pDevice->DelayPciGrant) + { + Value32 = REG_RD(pDevice, PciCfg.ClockCtrl); + REG_WR(pDevice, PciCfg.ClockCtrl, Value32 | BIT_31); + } + + /* Enable TaggedStatus mode. */ + if(pDevice->UseTaggedStatus) + { + pDevice->MiscHostCtrl |= MISC_HOST_CTRL_ENABLE_TAGGED_STATUS_MODE; + } + + /* Restore PCI configuration registers. */ + MM_WriteConfig32(pDevice, PCI_CACHE_LINE_SIZE_REG, + pDevice->SavedCacheLineReg); +// LM_RegWrInd(pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, +// (pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId); + MM_WriteConfig32(pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, + (pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId); + + /* Clear the statistics block. */ + for(j = 0x0300; j < 0x0b00; j++) + { + MEM_WR_OFFSET(pDevice, j, 0); + } + + /* Initialize the statistis Block */ + pDevice->pStatusBlkVirt->Status = 0; + pDevice->pStatusBlkVirt->RcvStdConIdx = 0; + pDevice->pStatusBlkVirt->RcvJumboConIdx = 0; + pDevice->pStatusBlkVirt->RcvMiniConIdx = 0; + + for(j = 0; j < 16; j++) + { + pDevice->pStatusBlkVirt->Idx[j].RcvProdIdx = 0; + pDevice->pStatusBlkVirt->Idx[j].SendConIdx = 0; + } + + for(k = 0; k < T3_STD_RCV_RCB_ENTRY_COUNT ;k++) + { + pDevice->pRxStdBdVirt[k].HostAddr.High = 0; + pDevice->pRxStdBdVirt[k].HostAddr.Low = 0; + } + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Receive jumbo BD buffer. */ + for(k = 0; k < T3_JUMBO_RCV_RCB_ENTRY_COUNT; k++) + { + pDevice->pRxJumboBdVirt[k].HostAddr.High = 0; + pDevice->pRxJumboBdVirt[k].HostAddr.Low = 0; + } +#endif + + REG_WR(pDevice, PciCfg.DmaReadWriteCtrl, pDevice->DmaReadWriteCtrl); + + /* GRC mode control register. */ + Value32 = +#ifdef BIG_ENDIAN_HOST + GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | + GRC_MODE_WORD_SWAP_NON_FRAME_DATA | + GRC_MODE_BYTE_SWAP_DATA | + GRC_MODE_WORD_SWAP_DATA | +#else + GRC_MODE_WORD_SWAP_NON_FRAME_DATA | + GRC_MODE_BYTE_SWAP_DATA | + GRC_MODE_WORD_SWAP_DATA | +#endif + GRC_MODE_INT_ON_MAC_ATTN | + GRC_MODE_HOST_STACK_UP; + + /* Configure send BD mode. */ + if(pDevice->NicSendBd == FALSE) + { + Value32 |= GRC_MODE_HOST_SEND_BDS; + } + else + { + Value32 |= GRC_MODE_4X_NIC_BASED_SEND_RINGS; + } + + /* Configure pseudo checksum mode. */ + if(pDevice->NoTxPseudoHdrChksum) + { + Value32 |= GRC_MODE_TX_NO_PSEUDO_HEADER_CHKSUM; + } + + if(pDevice->NoRxPseudoHdrChksum) + { + Value32 |= GRC_MODE_RX_NO_PSEUDO_HEADER_CHKSUM; + } + + REG_WR(pDevice, Grc.Mode, Value32); + + /* Setup the timer prescalar register. */ + REG_WR(pDevice, Grc.MiscCfg, 65 << 1); /* Clock is alwasy 66Mhz. */ + + /* Set up the MBUF pool base address and size. */ + REG_WR(pDevice, BufMgr.MbufPoolAddr, pDevice->MbufBase); + REG_WR(pDevice, BufMgr.MbufPoolSize, pDevice->MbufSize); + + /* Set up the DMA descriptor pool base address and size. */ + REG_WR(pDevice, BufMgr.DmaDescPoolAddr, T3_NIC_DMA_DESC_POOL_ADDR); + REG_WR(pDevice, BufMgr.DmaDescPoolSize, T3_NIC_DMA_DESC_POOL_SIZE); + + /* Configure MBUF and Threshold watermarks */ + /* Configure the DMA read MBUF low water mark. */ + if(pDevice->DmaMbufLowMark) + { + REG_WR(pDevice, BufMgr.MbufReadDmaLowWaterMark, + pDevice->DmaMbufLowMark); + } + else + { + if(pDevice->TxMtu < MAX_ETHERNET_PACKET_BUFFER_SIZE) + { + REG_WR(pDevice, BufMgr.MbufReadDmaLowWaterMark, + T3_DEF_DMA_MBUF_LOW_WMARK); + } + else + { + REG_WR(pDevice, BufMgr.MbufReadDmaLowWaterMark, + T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO); + } + } + + /* Configure the MAC Rx MBUF low water mark. */ + if(pDevice->RxMacMbufLowMark) + { + REG_WR(pDevice, BufMgr.MbufMacRxLowWaterMark, + pDevice->RxMacMbufLowMark); + } + else + { + if(pDevice->TxMtu < MAX_ETHERNET_PACKET_BUFFER_SIZE) + { + REG_WR(pDevice, BufMgr.MbufMacRxLowWaterMark, + T3_DEF_RX_MAC_MBUF_LOW_WMARK); + } + else + { + REG_WR(pDevice, BufMgr.MbufMacRxLowWaterMark, + T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO); + } + } + + /* Configure the MBUF high water mark. */ + if(pDevice->MbufHighMark) + { + REG_WR(pDevice, BufMgr.MbufHighWaterMark, pDevice->MbufHighMark); + } + else + { + if(pDevice->TxMtu < MAX_ETHERNET_PACKET_BUFFER_SIZE) + { + REG_WR(pDevice, BufMgr.MbufHighWaterMark, + T3_DEF_MBUF_HIGH_WMARK); + } + else + { + REG_WR(pDevice, BufMgr.MbufHighWaterMark, + T3_DEF_MBUF_HIGH_WMARK_JUMBO); + } + } + + REG_WR(pDevice, BufMgr.DmaLowWaterMark, T3_DEF_DMA_DESC_LOW_WMARK); + REG_WR(pDevice, BufMgr.DmaHighWaterMark, T3_DEF_DMA_DESC_HIGH_WMARK); + + /* Enable buffer manager. */ + REG_WR(pDevice, BufMgr.Mode, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE); + + for(j = 0 ;j < 2000; j++) + { + if(REG_RD(pDevice, BufMgr.Mode) & BUFMGR_MODE_ENABLE) + break; + MM_Wait(10); + } + + if(j >= 2000) + { + return LM_STATUS_FAILURE; + } + + /* Enable the FTQs. */ + REG_WR(pDevice, Ftq.Reset, 0xffffffff); + REG_WR(pDevice, Ftq.Reset, 0); + + /* Wait until FTQ is ready */ + for(j = 0; j < 2000; j++) + { + if(REG_RD(pDevice, Ftq.Reset) == 0) + break; + MM_Wait(10); + } + + if(j >= 2000) + { + return LM_STATUS_FAILURE; + } + + /* Initialize the Standard Receive RCB. */ + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.HostRingAddr.High, + pDevice->RxStdBdPhy.High); + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.HostRingAddr.Low, + pDevice->RxStdBdPhy.Low); + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.u.MaxLen_Flags, + MAX_STD_RCV_BUFFER_SIZE << 16); + + /* Initialize the Jumbo Receive RCB. */ + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.u.MaxLen_Flags, + T3_RCB_FLAG_RING_DISABLED); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.HostRingAddr.High, + pDevice->RxJumboBdPhy.High); + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.HostRingAddr.Low, + pDevice->RxJumboBdPhy.Low); + + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.u.MaxLen_Flags, 0); + +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Initialize the Mini Receive RCB. */ + REG_WR(pDevice, RcvDataBdIn.MiniRcvRcb.u.MaxLen_Flags, + T3_RCB_FLAG_RING_DISABLED); + + { + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.NicRingAddr, + (LM_UINT32) T3_NIC_STD_RCV_BUFFER_DESC_ADDR); + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.NicRingAddr, + (LM_UINT32) T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR); + } + + /* Receive BD Ring replenish threshold. */ + REG_WR(pDevice, RcvBdIn.StdRcvThreshold, pDevice->RxStdDescCnt/8); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + REG_WR(pDevice, RcvBdIn.JumboRcvThreshold, pDevice->RxJumboDescCnt/8); +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Disable all the unused rings. */ + for(j = 0; j < T3_MAX_SEND_RCB_COUNT; j++) { + MEM_WR(pDevice, SendRcb[j].u.MaxLen_Flags, T3_RCB_FLAG_RING_DISABLED); + } /* for */ + + /* Initialize the indices. */ + pDevice->SendProdIdx = 0; + pDevice->SendConIdx = 0; + + MB_REG_WR(pDevice, Mailbox.SendHostProdIdx[0].Low, 0); + MB_REG_WR(pDevice, Mailbox.SendNicProdIdx[0].Low, 0); + + /* Set up host or NIC based send RCB. */ + if(pDevice->NicSendBd == FALSE) + { + MEM_WR(pDevice, SendRcb[0].HostRingAddr.High, + pDevice->SendBdPhy.High); + MEM_WR(pDevice, SendRcb[0].HostRingAddr.Low, + pDevice->SendBdPhy.Low); + + /* Set up the NIC ring address in the RCB. */ + MEM_WR(pDevice, SendRcb[0].NicRingAddr,T3_NIC_SND_BUFFER_DESC_ADDR); + + /* Setup the RCB. */ + MEM_WR(pDevice, SendRcb[0].u.MaxLen_Flags, + T3_SEND_RCB_ENTRY_COUNT << 16); + + for(k = 0; k < T3_SEND_RCB_ENTRY_COUNT; k++) + { + pDevice->pSendBdVirt[k].HostAddr.High = 0; + pDevice->pSendBdVirt[k].HostAddr.Low = 0; + } + } + else + { + MEM_WR(pDevice, SendRcb[0].HostRingAddr.High, 0); + MEM_WR(pDevice, SendRcb[0].HostRingAddr.Low, 0); + MEM_WR(pDevice, SendRcb[0].NicRingAddr, + pDevice->SendBdPhy.Low); + + for(k = 0; k < T3_SEND_RCB_ENTRY_COUNT; k++) + { + __raw_writel(0, &(pDevice->pSendBdVirt[k].HostAddr.High)); + __raw_writel(0, &(pDevice->pSendBdVirt[k].HostAddr.Low)); + __raw_writel(0, &(pDevice->pSendBdVirt[k].u1.Len_Flags)); + pDevice->ShadowSendBd[k].HostAddr.High = 0; + pDevice->ShadowSendBd[k].u1.Len_Flags = 0; + } + } + atomic_set(&pDevice->SendBdLeft, T3_SEND_RCB_ENTRY_COUNT-1); + + /* Configure the receive return rings. */ + for(j = 0; j < T3_MAX_RCV_RETURN_RCB_COUNT; j++) + { + MEM_WR(pDevice, RcvRetRcb[j].u.MaxLen_Flags, T3_RCB_FLAG_RING_DISABLED); + } + + pDevice->RcvRetConIdx = 0; + + MEM_WR(pDevice, RcvRetRcb[0].HostRingAddr.High, + pDevice->RcvRetBdPhy.High); + MEM_WR(pDevice, RcvRetRcb[0].HostRingAddr.Low, + pDevice->RcvRetBdPhy.Low); + + /* Set up the NIC ring address in the RCB. */ + /* Not very clear from the spec. I am guessing that for Receive */ + /* Return Ring, NicRingAddr is not used. */ + MEM_WR(pDevice, RcvRetRcb[0].NicRingAddr, 0); + + /* Setup the RCB. */ + MEM_WR(pDevice, RcvRetRcb[0].u.MaxLen_Flags, + T3_RCV_RETURN_RCB_ENTRY_COUNT << 16); + + /* Reinitialize RX ring producer index */ + MB_REG_WR(pDevice, Mailbox.RcvStdProdIdx.Low, 0); + MB_REG_WR(pDevice, Mailbox.RcvJumboProdIdx.Low, 0); + MB_REG_WR(pDevice, Mailbox.RcvMiniProdIdx.Low, 0); + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + pDevice->RxJumboProdIdx = 0; + pDevice->RxJumboQueuedCnt = 0; +#endif + + /* Reinitialize our copy of the indices. */ + pDevice->RxStdProdIdx = 0; + pDevice->RxStdQueuedCnt = 0; + +#if T3_JUMBO_RCV_ENTRY_COUNT + pDevice->RxJumboProdIdx = 0; +#endif /* T3_JUMBO_RCV_ENTRY_COUNT */ + + /* Configure the MAC address. */ + LM_SetMacAddress(pDevice, pDevice->NodeAddress); + + /* Initialize the transmit random backoff seed. */ + Value32 = (pDevice->NodeAddress[0] + pDevice->NodeAddress[1] + + pDevice->NodeAddress[2] + pDevice->NodeAddress[3] + + pDevice->NodeAddress[4] + pDevice->NodeAddress[5]) & + MAC_TX_BACKOFF_SEED_MASK; + REG_WR(pDevice, MacCtrl.TxBackoffSeed, Value32); + + /* Receive MTU. Frames larger than the MTU is marked as oversized. */ + REG_WR(pDevice, MacCtrl.MtuSize, pDevice->RxMtu + 8); /* CRC + VLAN. */ + + /* Configure Time slot/IPG per 802.3 */ + REG_WR(pDevice, MacCtrl.TxLengths, 0x2620); + + /* + * Configure Receive Rules so that packets don't match + * Programmble rule will be queued to Return Ring 1 + */ + REG_WR(pDevice, MacCtrl.RcvRuleCfg, RX_RULE_DEFAULT_CLASS); + + /* + * Configure to have 16 Classes of Services (COS) and one + * queue per class. Bad frames are queued to RRR#1. + * And frames don't match rules are also queued to COS#1. + */ + REG_WR(pDevice, RcvListPlmt.Config, 0x181); + + /* Enable Receive Placement Statistics */ + REG_WR(pDevice, RcvListPlmt.StatsEnableMask,0xffffff); + REG_WR(pDevice, RcvListPlmt.StatsCtrl, RCV_LIST_STATS_ENABLE); + + /* Enable Send Data Initator Statistics */ + REG_WR(pDevice, SndDataIn.StatsEnableMask,0xffffff); + REG_WR(pDevice, SndDataIn.StatsCtrl, + T3_SND_DATA_IN_STATS_CTRL_ENABLE | \ + T3_SND_DATA_IN_STATS_CTRL_FASTER_UPDATE); + + /* Disable the host coalescing state machine before configuring it's */ + /* parameters. */ + REG_WR(pDevice, HostCoalesce.Mode, 0); + for(j = 0; j < 2000; j++) + { + Value32 = REG_RD(pDevice, HostCoalesce.Mode); + if(!(Value32 & HOST_COALESCE_ENABLE)) + { + break; + } + MM_Wait(10); + } + + /* Host coalescing configurations. */ + REG_WR(pDevice, HostCoalesce.RxCoalescingTicks, pDevice->RxCoalescingTicks); + REG_WR(pDevice, HostCoalesce.TxCoalescingTicks, pDevice->TxCoalescingTicks); + REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFrames, + pDevice->RxMaxCoalescedFrames); + REG_WR(pDevice, HostCoalesce.TxMaxCoalescedFrames, + pDevice->TxMaxCoalescedFrames); + REG_WR(pDevice, HostCoalesce.RxCoalescedTickDuringInt, + pDevice->RxCoalescingTicksDuringInt); + REG_WR(pDevice, HostCoalesce.TxCoalescedTickDuringInt, + pDevice->TxCoalescingTicksDuringInt); + REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFramesDuringInt, + pDevice->RxMaxCoalescedFramesDuringInt); + REG_WR(pDevice, HostCoalesce.TxMaxCoalescedFramesDuringInt, + pDevice->TxMaxCoalescedFramesDuringInt); + + /* Initialize the address of the status block. The NIC will DMA */ + /* the status block to this memory which resides on the host. */ + REG_WR(pDevice, HostCoalesce.StatusBlkHostAddr.High, + pDevice->StatusBlkPhy.High); + REG_WR(pDevice, HostCoalesce.StatusBlkHostAddr.Low, + pDevice->StatusBlkPhy.Low); + + /* Initialize the address of the statistics block. The NIC will DMA */ + /* the statistics to this block of memory. */ + REG_WR(pDevice, HostCoalesce.StatsBlkHostAddr.High, + pDevice->StatsBlkPhy.High); + REG_WR(pDevice, HostCoalesce.StatsBlkHostAddr.Low, + pDevice->StatsBlkPhy.Low); + + REG_WR(pDevice, HostCoalesce.StatsCoalescingTicks, + pDevice->StatsCoalescingTicks); + + REG_WR(pDevice, HostCoalesce.StatsBlkNicAddr, 0x300); + REG_WR(pDevice, HostCoalesce.StatusBlkNicAddr,0xb00); + + /* Enable Host Coalesing state machine */ + REG_WR(pDevice, HostCoalesce.Mode, HOST_COALESCE_ENABLE | + pDevice->CoalesceMode); + + /* Enable the Receive BD Completion state machine. */ + REG_WR(pDevice, RcvBdComp.Mode, RCV_BD_COMP_MODE_ENABLE | + RCV_BD_COMP_MODE_ATTN_ENABLE); + + /* Enable the Receive List Placement state machine. */ + REG_WR(pDevice, RcvListPlmt.Mode, RCV_LIST_PLMT_MODE_ENABLE); + + /* Enable the Receive List Selector state machine. */ + REG_WR(pDevice, RcvListSel.Mode, RCV_LIST_SEL_MODE_ENABLE | + RCV_LIST_SEL_MODE_ATTN_ENABLE); + + /* Enable transmit DMA, clear statistics. */ + pDevice->MacMode = MAC_MODE_ENABLE_TX_STATISTICS | + MAC_MODE_ENABLE_RX_STATISTICS | MAC_MODE_ENABLE_TDE | + MAC_MODE_ENABLE_RDE | MAC_MODE_ENABLE_FHDE; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_CLEAR_RX_STATISTICS | MAC_MODE_CLEAR_TX_STATISTICS); + + /* GRC miscellaneous local control register. */ + pDevice->GrcLocalCtrl = GRC_MISC_LOCAL_CTRL_INT_ON_ATTN | + GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM; + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->GrcLocalCtrl |= GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1; + } + + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl); + MM_Wait(40); + + /* Reset RX counters. */ + for(j = 0; j < sizeof(LM_RX_COUNTERS); j++) + { + ((PLM_UINT8) &pDevice->RxCounters)[j] = 0; + } + + /* Reset TX counters. */ + for(j = 0; j < sizeof(LM_TX_COUNTERS); j++) + { + ((PLM_UINT8) &pDevice->TxCounters)[j] = 0; + } + + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 0); + + /* Enable the DMA Completion state machine. */ + REG_WR(pDevice, DmaComp.Mode, DMA_COMP_MODE_ENABLE); + + /* Enable the DMA Write state machine. */ + Value32 = DMA_WRITE_MODE_ENABLE | + DMA_WRITE_MODE_TARGET_ABORT_ATTN_ENABLE | + DMA_WRITE_MODE_MASTER_ABORT_ATTN_ENABLE | + DMA_WRITE_MODE_PARITY_ERROR_ATTN_ENABLE | + DMA_WRITE_MODE_ADDR_OVERFLOW_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_OVERRUN_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_UNDERRUN_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_OVERREAD_ATTN_ENABLE | + DMA_WRITE_MODE_LONG_READ_ATTN_ENABLE; + REG_WR(pDevice, DmaWrite.Mode, Value32); + + /* Enable the Read DMA state machine. */ + Value32 = DMA_READ_MODE_ENABLE | + DMA_READ_MODE_TARGET_ABORT_ATTN_ENABLE | + DMA_READ_MODE_MASTER_ABORT_ATTN_ENABLE | + DMA_READ_MODE_PARITY_ERROR_ATTN_ENABLE | + DMA_READ_MODE_ADDR_OVERFLOW_ATTN_ENABLE | + DMA_READ_MODE_FIFO_OVERRUN_ATTN_ENABLE | + DMA_READ_MODE_FIFO_UNDERRUN_ATTN_ENABLE | + DMA_READ_MODE_FIFO_OVERREAD_ATTN_ENABLE | + DMA_READ_MODE_LONG_READ_ATTN_ENABLE; + REG_WR(pDevice, DmaRead.Mode, Value32); + + /* Enable the Receive Data Completion state machine. */ + REG_WR(pDevice, RcvDataComp.Mode, RCV_DATA_COMP_MODE_ENABLE | + RCV_DATA_COMP_MODE_ATTN_ENABLE); + + /* Enable the Mbuf Cluster Free state machine. */ + REG_WR(pDevice, MbufClusterFree.Mode, MBUF_CLUSTER_FREE_MODE_ENABLE); + + /* Enable the Send Data Completion state machine. */ + REG_WR(pDevice, SndDataComp.Mode, SND_DATA_COMP_MODE_ENABLE); + + /* Enable the Send BD Completion state machine. */ + REG_WR(pDevice, SndBdComp.Mode, SND_BD_COMP_MODE_ENABLE | + SND_BD_COMP_MODE_ATTN_ENABLE); + + /* Enable the Receive BD Initiator state machine. */ + REG_WR(pDevice, RcvBdIn.Mode, RCV_BD_IN_MODE_ENABLE | + RCV_BD_IN_MODE_BD_IN_DIABLED_RCB_ATTN_ENABLE); + + /* Enable the Receive Data and Receive BD Initiator state machine. */ + REG_WR(pDevice, RcvDataBdIn.Mode, RCV_DATA_BD_IN_MODE_ENABLE | + RCV_DATA_BD_IN_MODE_INVALID_RING_SIZE); + + /* Enable the Send Data Initiator state machine. */ + REG_WR(pDevice, SndDataIn.Mode, T3_SND_DATA_IN_MODE_ENABLE); + + /* Enable the Send BD Initiator state machine. */ + REG_WR(pDevice, SndBdIn.Mode, SND_BD_IN_MODE_ENABLE | + SND_BD_IN_MODE_ATTN_ENABLE); + + /* Enable the Send BD Selector state machine. */ + REG_WR(pDevice, SndBdSel.Mode, SND_BD_SEL_MODE_ENABLE | + SND_BD_SEL_MODE_ATTN_ENABLE); + +#if INCLUDE_5701_AX_FIX + /* Load the firmware for the 5701_A0 workaround. */ + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0) + { + LM_LoadRlsFirmware(pDevice); + } +#endif + + /* Enable the transmitter. */ + pDevice->TxMode = TX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.TxMode, pDevice->TxMode); + + /* Enable the receiver. */ + pDevice->RxMode = RX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + + if (pDevice->RestoreOnWakeUp) + { + pDevice->RestoreOnWakeUp = FALSE; + pDevice->DisableAutoNeg = pDevice->WakeUpDisableAutoNeg; + pDevice->RequestedMediaType = pDevice->WakeUpRequestedMediaType; + } + + /* Disable auto polling. */ + pDevice->MiMode = 0xc0000; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = LED_CTRL_PHY_MODE_1; + } + else + { + if(pDevice->LedMode == LED_MODE_OUTPUT) + { + Value32 = LED_CTRL_PHY_MODE_2; + } + else + { + Value32 = LED_CTRL_PHY_MODE_1; + } + } + REG_WR(pDevice, MacCtrl.LedCtrl, Value32); + + /* Activate Link to enable MAC state machine */ + REG_WR(pDevice, MacCtrl.MiStatus, MI_STATUS_ENABLE_LINK_STATUS_ATTN); + + if (pDevice->EnableTbi) + { + REG_WR(pDevice, MacCtrl.RxMode, RX_MODE_RESET); + MM_Wait(10); + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + if (pDevice->ChipRevId == T3_CHIP_ID_5703_A1) + { + REG_WR(pDevice, MacCtrl.SerdesCfg, 0x616000); + } + } + /* Setup the phy chip. */ + LM_SetupPhy(pDevice); + + if (!pDevice->EnableTbi) { + /* Clear CRC stats */ + LM_ReadPhy(pDevice, 0x1e, &Value32); + LM_WritePhy(pDevice, 0x1e, Value32 | 0x8000); + LM_ReadPhy(pDevice, 0x14, &Value32); + } + + /* Set up the receive mask. */ + LM_SetReceiveMask(pDevice, pDevice->ReceiveMask); + + /* Queue Rx packet buffers. */ + if(pDevice->QueueRxPackets) + { + LM_QueueRxPackets(pDevice); + } + + return LM_STATUS_SUCCESS; +} /* LM_ResetAdapter */ + + +/******************************************************************************/ +/* Description: */ +/* This routine disables the adapter from generating interrupts. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_DisableInterrupt( + PLM_DEVICE_BLOCK pDevice) +{ + REG_WR(pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl | + MISC_HOST_CTRL_MASK_PCI_INT); + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1); + + return LM_STATUS_SUCCESS; +} + + + +/******************************************************************************/ +/* Description: */ +/* This routine enables the adapter to generate interrupts. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_EnableInterrupt( + PLM_DEVICE_BLOCK pDevice) +{ + REG_WR(pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl & + ~MISC_HOST_CTRL_MASK_PCI_INT); + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 0); + + if(pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) + { + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_SET_INT); + } + + return LM_STATUS_SUCCESS; +} + + + +/******************************************************************************/ +/* Description: */ +/* This routine puts a packet on the wire if there is a transmit DMA */ +/* descriptor available; otherwise the packet is queued for later */ +/* transmission. If the second argue is NULL, this routine will put */ +/* the queued packet on the wire if possible. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_SendPacket(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) +{ + LM_UINT32 FragCount; + PT3_SND_BD pSendBd; + PT3_SND_BD pShadowSendBd; + LM_UINT32 Value32; + LM_UINT32 Idx; + + /* Update the SendBdLeft count. */ + atomic_sub(pPacket->u.Tx.FragCount, &pDevice->SendBdLeft); + + /* Initalize the send buffer descriptors. */ + Idx = pDevice->SendProdIdx; + + pSendBd = &pDevice->pSendBdVirt[Idx]; + + /* Next producer index. */ + if (pDevice->NicSendBd == TRUE) + { + pShadowSendBd = &pDevice->ShadowSendBd[Idx]; + for(FragCount = 0; ; ) + { + /* Initialize the pointer to the send buffer fragment. */ + Value32 = + pPacket->u.Tx.pFraglist->Fragments[FragCount].FragBuf.High; + if (Value32 != pShadowSendBd->HostAddr.High) + { + __raw_writel(Value32, &(pSendBd->HostAddr.High)); + pShadowSendBd->HostAddr.High = Value32; + } + __raw_writel(pPacket->u.Tx.pFraglist->Fragments[FragCount].FragBuf.Low, + &(pSendBd->HostAddr.Low)); + + /* Setup the control flags and send buffer size. */ + Value32 = (pPacket->u.Tx.pFraglist->Fragments[FragCount]. + FragSize << 16) | pPacket->Flags; + + Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK; + + FragCount++; + if (FragCount >= pPacket->u.Tx.FragCount) + { + Value32 |= SND_BD_FLAG_END; + if (Value32 != pShadowSendBd->u1.Len_Flags) + { + __raw_writel(Value32, &(pSendBd->u1.Len_Flags)); + pShadowSendBd->u1.Len_Flags = Value32; + } + if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) { + __raw_writel(pPacket->VlanTag, &(pSendBd->u2.VlanTag)); + } + break; + } + else + { + if (Value32 != pShadowSendBd->u1.Len_Flags) + { + __raw_writel(Value32, &(pSendBd->u1.Len_Flags)); + pShadowSendBd->u1.Len_Flags = Value32; + } + if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) { + __raw_writel(pPacket->VlanTag, &(pSendBd->u2.VlanTag)); + } + } + + pSendBd++; + pShadowSendBd++; + if (Idx == 0) + { + pSendBd = &pDevice->pSendBdVirt[0]; + pShadowSendBd = &pDevice->ShadowSendBd[0]; + } + } /* for */ + + /* Put the packet descriptor in the ActiveQ. */ + QQ_PushTail(&pDevice->TxPacketActiveQ.Container, pPacket); + + wmb(); + MB_REG_WR(pDevice, Mailbox.SendNicProdIdx[0].Low, Idx); + + if(T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) + { + MB_REG_WR(pDevice, Mailbox.SendNicProdIdx[0].Low, Idx); + } + } + else + { + for(FragCount = 0; ; ) + { + /* Initialize the pointer to the send buffer fragment. */ + pSendBd->HostAddr.High = + pPacket->u.Tx.pFraglist->Fragments[FragCount].FragBuf.High; + pSendBd->HostAddr.Low = + pPacket->u.Tx.pFraglist->Fragments[FragCount].FragBuf.Low; + + /* Setup the control flags and send buffer size. */ + Value32 = (pPacket->u.Tx.pFraglist->Fragments[FragCount]. + FragSize << 16) | pPacket->Flags; + + Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK; + + FragCount++; + if (FragCount >= pPacket->u.Tx.FragCount) + { + pSendBd->u1.Len_Flags = Value32 | SND_BD_FLAG_END; + if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) + pSendBd->u2.VlanTag = pPacket->VlanTag; + break; + } + else + { + pSendBd->u1.Len_Flags = Value32; + if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) + pSendBd->u2.VlanTag = pPacket->VlanTag; + } + pSendBd++; + if (Idx == 0) + { + pSendBd = &pDevice->pSendBdVirt[0]; + } + } /* for */ + + /* Put the packet descriptor in the ActiveQ. */ + QQ_PushTail(&pDevice->TxPacketActiveQ.Container, pPacket); + + wmb(); + MB_REG_WR(pDevice, Mailbox.SendHostProdIdx[0].Low, Idx); + + if(T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) + { + MB_REG_WR(pDevice, Mailbox.SendHostProdIdx[0].Low, Idx); + } + } + + /* Update the producer index. */ + pDevice->SendProdIdx = Idx; + + return LM_STATUS_SUCCESS; +} + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static unsigned long +ComputeCrc32( +unsigned char *pBuffer, +unsigned long BufferSize) { + unsigned long Reg; + unsigned long Tmp; + unsigned long j, k; + + Reg = 0xffffffff; + + for(j = 0; j < BufferSize; j++) + { + Reg ^= pBuffer[j]; + + for(k = 0; k < 8; k++) + { + Tmp = Reg & 0x01; + + Reg >>= 1; + + if(Tmp) + { + Reg ^= 0xedb88320; + } + } + } + + return ~Reg; +} /* ComputeCrc32 */ + + + +/******************************************************************************/ +/* Description: */ +/* This routine sets the receive control register according to ReceiveMask */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_SetReceiveMask( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 Mask) { + LM_UINT32 ReceiveMask; + LM_UINT32 RxMode; + LM_UINT32 j, k; + + ReceiveMask = Mask; + + RxMode = pDevice->RxMode; + + if(Mask & LM_ACCEPT_UNICAST) + { + Mask &= ~LM_ACCEPT_UNICAST; + } + + if(Mask & LM_ACCEPT_MULTICAST) + { + Mask &= ~LM_ACCEPT_MULTICAST; + } + + if(Mask & LM_ACCEPT_ALL_MULTICAST) + { + Mask &= ~LM_ACCEPT_ALL_MULTICAST; + } + + if(Mask & LM_ACCEPT_BROADCAST) + { + Mask &= ~LM_ACCEPT_BROADCAST; + } + + RxMode &= ~RX_MODE_PROMISCUOUS_MODE; + if(Mask & LM_PROMISCUOUS_MODE) + { + RxMode |= RX_MODE_PROMISCUOUS_MODE; + Mask &= ~LM_PROMISCUOUS_MODE; + } + + RxMode &= ~(RX_MODE_ACCEPT_RUNTS | RX_MODE_ACCEPT_OVERSIZED); + if(Mask & LM_ACCEPT_ERROR_PACKET) + { + RxMode |= RX_MODE_ACCEPT_RUNTS | RX_MODE_ACCEPT_OVERSIZED; + Mask &= ~LM_ACCEPT_ERROR_PACKET; + } + + /* Make sure all the bits are valid before committing changes. */ + if(Mask) + { + return LM_STATUS_FAILURE; + } + + /* Commit the new filter. */ + pDevice->RxMode = RxMode; + REG_WR(pDevice, MacCtrl.RxMode, RxMode); + + pDevice->ReceiveMask = ReceiveMask; + + /* Set up the MC hash table. */ + if(ReceiveMask & LM_ACCEPT_ALL_MULTICAST) + { + for(k = 0; k < 4; k++) + { + REG_WR(pDevice, MacCtrl.HashReg[k], 0xffffffff); + } + } + else if(ReceiveMask & LM_ACCEPT_MULTICAST) + { + LM_UINT32 HashReg[4]; + + HashReg[0] = 0; HashReg[1] = 0; HashReg[2] = 0; HashReg[3] = 0; + for(j = 0; j < pDevice->McEntryCount; j++) + { + LM_UINT32 RegIndex; + LM_UINT32 Bitpos; + LM_UINT32 Crc32; + + Crc32 = ComputeCrc32(pDevice->McTable[j], ETHERNET_ADDRESS_SIZE); + + /* The most significant 7 bits of the CRC32 (no inversion), */ + /* are used to index into one of the possible 128 bit positions. */ + Bitpos = ~Crc32 & 0x7f; + + /* Hash register index. */ + RegIndex = (Bitpos & 0x60) >> 5; + + /* Bit to turn on within a hash register. */ + Bitpos &= 0x1f; + + /* Enable the multicast bit. */ + HashReg[RegIndex] |= (1 << Bitpos); + } + + /* REV_AX has problem with multicast filtering where it uses both */ + /* DA and SA to perform hashing. */ + for(k = 0; k < 4; k++) + { + REG_WR(pDevice, MacCtrl.HashReg[k], HashReg[k]); + } + } + else + { + /* Reject all multicast frames. */ + for(j = 0; j < 4; j++) + { + REG_WR(pDevice, MacCtrl.HashReg[j], 0); + } + } + + /* By default, Tigon3 will accept broadcast frames. We need to setup */ + if(ReceiveMask & LM_ACCEPT_BROADCAST) + { + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE1_RULE & RCV_DISABLE_RULE_MASK); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE1_VALUE & RCV_DISABLE_RULE_MASK); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE1_RULE & RCV_DISABLE_RULE_MASK); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE1_VALUE & RCV_DISABLE_RULE_MASK); + } + else + { + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE1_RULE); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE1_VALUE); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE2_RULE); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE2_VALUE); + } + + /* disable the rest of the rules. */ + for(j = RCV_LAST_RULE_IDX; j < 16; j++) + { + REG_WR(pDevice, MacCtrl.RcvRules[j].Rule, 0); + REG_WR(pDevice, MacCtrl.RcvRules[j].Value, 0); + } + + return LM_STATUS_SUCCESS; +} /* LM_SetReceiveMask */ + + + +/******************************************************************************/ +/* Description: */ +/* Disable the interrupt and put the transmitter and receiver engines in */ +/* an idle state. Also aborts all pending send requests and receive */ +/* buffers. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_Abort( +PLM_DEVICE_BLOCK pDevice) +{ + PLM_PACKET pPacket; + LM_UINT Idx; + + LM_DisableInterrupt(pDevice); + + /* Disable all the state machines. */ + LM_CntrlBlock(pDevice,T3_BLOCK_MAC_RX_ENGINE,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_RX_BD_INITIATOR,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_RX_LIST_PLMT,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_RX_LIST_SELECTOR,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_RX_DATA_INITIATOR,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_RX_DATA_COMP,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_RX_BD_COMP,LM_DISABLE); + + LM_CntrlBlock(pDevice,T3_BLOCK_SEND_BD_SELECTOR,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_SEND_BD_INITIATOR,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_SEND_DATA_INITIATOR,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_DMA_RD,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_SEND_DATA_COMP,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_DMA_COMP,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_SEND_BD_COMP,LM_DISABLE); + + /* Clear TDE bit */ + pDevice->MacMode &= ~MAC_MODE_ENABLE_TDE; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + + LM_CntrlBlock(pDevice,T3_BLOCK_MAC_TX_ENGINE,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_HOST_COALESING,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_DMA_WR,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_MBUF_CLUSTER_FREE,LM_DISABLE); + + /* Reset all FTQs */ + REG_WR(pDevice, Ftq.Reset, 0xffffffff); + REG_WR(pDevice, Ftq.Reset, 0x0); + + LM_CntrlBlock(pDevice,T3_BLOCK_MBUF_MANAGER,LM_DISABLE); + LM_CntrlBlock(pDevice,T3_BLOCK_MEM_ARBITOR,LM_DISABLE); + + MM_ACQUIRE_INT_LOCK(pDevice); + + /* Abort packets that have already queued to go out. */ + pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->TxPacketActiveQ.Container); + while(pPacket) + { +// MM_CompleteTxDma(pDevice, pPacket); + + pPacket->PacketStatus = LM_STATUS_TRANSMIT_ABORTED; + pDevice->TxCounters.TxPacketAbortedCnt++; + + atomic_add(pPacket->u.Tx.FragCount, &pDevice->SendBdLeft); + + QQ_PushTail(&pDevice->TxPacketXmittedQ.Container, pPacket); + + pPacket = (PLM_PACKET) + QQ_PopHead(&pDevice->TxPacketActiveQ.Container); + } + + /* Cleanup the receive return rings. */ + LM_ServiceRxInterrupt(pDevice); + + /* Don't want to indicate rx packets in Ndis miniport shutdown context. */ + /* Doing so may cause system crash. */ + if(!pDevice->ShuttingDown) + { + /* Indicate packets to the protocol. */ + MM_IndicateTxPackets(pDevice); + + /* Indicate received packets to the protocols. */ + MM_IndicateRxPackets(pDevice); + } + else + { + /* Move the receive packet descriptors in the ReceivedQ to the */ + /* free queue. */ + for(; ;) + { + pPacket = (PLM_PACKET) QQ_PopHead( + &pDevice->RxPacketReceivedQ.Container); + if(pPacket == NULL) + { + break; + } + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } + } + + /* Clean up the Std Receive Producer ring. */ + Idx = pDevice->pStatusBlkVirt->RcvStdConIdx; + + while(Idx != pDevice->RxStdProdIdx) { + pPacket = (PLM_PACKET) (MM_UINT_PTR(pDevice->pPacketDescBase) + + MM_UINT_PTR(pDevice->pRxStdBdVirt[Idx].Opaque)); + + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + + Idx = (Idx + 1) & T3_STD_RCV_RCB_ENTRY_COUNT_MASK; + } /* while */ + + /* Reinitialize our copy of the indices. */ + pDevice->RxStdProdIdx = 0; + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Clean up the Jumbo Receive Producer ring. */ + Idx = pDevice->pStatusBlkVirt->RcvJumboConIdx; + + while(Idx != pDevice->RxJumboProdIdx) { + pPacket = (PLM_PACKET) (MM_UINT_PTR(pDevice->pPacketDescBase) + + MM_UINT_PTR(pDevice->pRxJumboBdVirt[Idx].Opaque)); + + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + + Idx = (Idx + 1) & T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK; + } /* while */ + + /* Reinitialize our copy of the indices. */ + pDevice->RxJumboProdIdx = 0; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + MM_RELEASE_INT_LOCK(pDevice); + + /* Initialize the statistis Block */ + pDevice->pStatusBlkVirt->Status = 0; + pDevice->pStatusBlkVirt->RcvStdConIdx = 0; + pDevice->pStatusBlkVirt->RcvJumboConIdx = 0; + pDevice->pStatusBlkVirt->RcvMiniConIdx = 0; + + return LM_STATUS_SUCCESS; +} /* LM_Abort */ + + + +/******************************************************************************/ +/* Description: */ +/* Disable the interrupt and put the transmitter and receiver engines in */ +/* an idle state. Aborts all pending send requests and receive buffers. */ +/* Also free all the receive buffers. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_Halt( +PLM_DEVICE_BLOCK pDevice) { + PLM_PACKET pPacket; + LM_UINT32 EntryCnt; + + LM_Abort(pDevice); + + /* Get the number of entries in the queue. */ + EntryCnt = QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container); + + /* Make sure all the packets have been accounted for. */ + for(EntryCnt = 0; EntryCnt < pDevice->RxPacketDescCnt; EntryCnt++) + { + pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + if (pPacket == 0) + break; + + MM_FreeRxBuffer(pDevice, pPacket); + + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } + + LM_ResetChip(pDevice); + + /* Restore PCI configuration registers. */ + MM_WriteConfig32(pDevice, PCI_CACHE_LINE_SIZE_REG, + pDevice->SavedCacheLineReg); + LM_RegWrInd(pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, + (pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId); + + /* Reprogram the MAC address. */ + LM_SetMacAddress(pDevice, pDevice->NodeAddress); + + return LM_STATUS_SUCCESS; +} /* LM_Halt */ + + +STATIC LM_STATUS +LM_ResetChip(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + LM_UINT32 j; + + /* Wait for access to the nvram interface before resetting. This is */ + /* a workaround to prevent EEPROM corruption. */ + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && + T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701) + { + /* Request access to the flash interface. */ + REG_WR(pDevice, Nvram.SwArb, SW_ARB_REQ_SET1); + + for(j = 0; j < 100000; j++) + { + Value32 = REG_RD(pDevice, Nvram.SwArb); + if(Value32 & SW_ARB_GNT1) + { + break; + } + MM_Wait(10); + } + } + + /* Global reset. */ + REG_WR(pDevice, Grc.MiscCfg, GRC_MISC_CFG_CORE_CLOCK_RESET); + MM_Wait(40); MM_Wait(40); MM_Wait(40); + + /* make sure we re-enable indirect accesses */ + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, + pDevice->MiscHostCtrl); + + /* Set MAX PCI retry to zero. */ + MM_WriteConfig32(pDevice, T3_PCI_STATE_REG, + T3_PCI_STATE_PCI_ROM_ENABLE | T3_PCI_STATE_PCI_ROM_RETRY_ENABLE); + + /* Restore PCI command register. */ + MM_WriteConfig32(pDevice, PCI_COMMAND_REG, + pDevice->PciCommandStatusWords); + + /* Disable PCI-X relaxed ordering bit. */ + MM_ReadConfig32(pDevice, PCIX_CAP_REG, &Value32); + Value32 &= ~PCIX_ENABLE_RELAXED_ORDERING; + MM_WriteConfig32(pDevice, PCIX_CAP_REG, Value32); + + /* Enable memory arbiter. */ + REG_WR(pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE); + +#ifdef BIG_ENDIAN_HOST + /* Reconfigure the mode register. */ + Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | + GRC_MODE_WORD_SWAP_NON_FRAME_DATA | + GRC_MODE_BYTE_SWAP_DATA | + GRC_MODE_WORD_SWAP_DATA; +#else + /* Reconfigure the mode register. */ + Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | GRC_MODE_BYTE_SWAP_DATA; +#endif + REG_WR(pDevice, Grc.Mode, Value32); + + /* Prevent PXE from restarting. */ + MEM_WR_OFFSET(pDevice, 0x0b50, T3_MAGIC_NUM); + + if(pDevice->EnableTbi) { + pDevice->MacMode = MAC_MODE_PORT_MODE_TBI; + REG_WR(pDevice, MacCtrl.Mode, MAC_MODE_PORT_MODE_TBI); + } + else { + REG_WR(pDevice, MacCtrl.Mode, 0); + } + + /* Wait for the firmware to finish initialization. */ + for(j = 0; j < 100000; j++) + { + MM_Wait(10); + + Value32 = MEM_RD_OFFSET(pDevice, 0x0b50); + if(Value32 == ~T3_MAGIC_NUM) + { + break; + } + } + return LM_STATUS_SUCCESS; +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static void +LM_ServiceTxInterrupt( +PLM_DEVICE_BLOCK pDevice) { + PLM_PACKET pPacket; + LM_UINT32 HwConIdx; + LM_UINT32 SwConIdx; + + HwConIdx = pDevice->pStatusBlkVirt->Idx[0].SendConIdx; + + /* Get our copy of the consumer index. The buffer descriptors */ + /* that are in between the consumer indices are freed. */ + SwConIdx = pDevice->SendConIdx; + + /* Move the packets from the TxPacketActiveQ that are sent out to */ + /* the TxPacketXmittedQ. Packets that are sent use the */ + /* descriptors that are between SwConIdx and HwConIdx. */ + while(SwConIdx != HwConIdx) + { + /* Get the packet that was sent from the TxPacketActiveQ. */ + pPacket = (PLM_PACKET) QQ_PopHead( + &pDevice->TxPacketActiveQ.Container); + + /* Set the return status. */ + pPacket->PacketStatus = LM_STATUS_SUCCESS; + + /* Complete the transmit with a call to MM_CompleteTxDma. */ +// MM_CompleteTxDma(pDevice, pPacket); + + /* Put the packet in the TxPacketXmittedQ for indication later. */ + QQ_PushTail(&pDevice->TxPacketXmittedQ.Container, pPacket); + + /* Move to the next packet's BD. */ + SwConIdx = (SwConIdx + pPacket->u.Tx.FragCount) & + T3_SEND_RCB_ENTRY_COUNT_MASK; + + /* Update the number of unused BDs. */ + atomic_add(pPacket->u.Tx.FragCount, &pDevice->SendBdLeft); + + /* Get the new updated HwConIdx. */ + HwConIdx = pDevice->pStatusBlkVirt->Idx[0].SendConIdx; + } /* while */ + + /* Save the new SwConIdx. */ + pDevice->SendConIdx = SwConIdx; + +} /* LM_ServiceTxInterrupt */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static void +LM_ServiceRxInterrupt( +PLM_DEVICE_BLOCK pDevice) { + PLM_PACKET pPacket; + PT3_RCV_BD pRcvBd; + LM_UINT32 HwRcvRetProdIdx; + LM_UINT32 SwRcvRetConIdx; + + /* Loop thru the receive return rings for received packets. */ + HwRcvRetProdIdx = pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx; + + SwRcvRetConIdx = pDevice->RcvRetConIdx; + while(SwRcvRetConIdx != HwRcvRetProdIdx) + { + pRcvBd = &pDevice->pRcvRetBdVirt[SwRcvRetConIdx]; + + /* Get the received packet descriptor. */ + pPacket = (PLM_PACKET) (MM_UINT_PTR(pDevice->pPacketDescBase) + + MM_UINT_PTR(pRcvBd->Opaque)); + + /* Check the error flag. */ + if(pRcvBd->ErrorFlag && + pRcvBd->ErrorFlag != RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) + { + pPacket->PacketStatus = LM_STATUS_FAILURE; + + pDevice->RxCounters.RxPacketErrCnt++; + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_BAD_CRC) + { + pDevice->RxCounters.RxErrCrcCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_COLL_DETECT) + { + pDevice->RxCounters.RxErrCollCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_LINK_LOST_DURING_PKT) + { + pDevice->RxCounters.RxErrLinkLostCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_PHY_DECODE_ERR) + { + pDevice->RxCounters.RxErrPhyDecodeCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) + { + pDevice->RxCounters.RxErrOddNibbleCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_MAC_ABORT) + { + pDevice->RxCounters.RxErrMacAbortCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_LEN_LT_64) + { + pDevice->RxCounters.RxErrShortPacketCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_TRUNC_NO_RESOURCES) + { + pDevice->RxCounters.RxErrNoResourceCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_GIANT_FRAME_RCVD) + { + pDevice->RxCounters.RxErrLargePacketCnt++; + } + } + else + { + pPacket->PacketStatus = LM_STATUS_SUCCESS; + pPacket->PacketSize = pRcvBd->Len - 4; + + pPacket->Flags = pRcvBd->Flags; + if(pRcvBd->Flags & RCV_BD_FLAG_VLAN_TAG) + { + pPacket->VlanTag = pRcvBd->VlanTag; + } + + pPacket->u.Rx.TcpUdpChecksum = pRcvBd->TcpUdpCksum; + } + + /* Put the packet descriptor containing the received packet */ + /* buffer in the RxPacketReceivedQ for indication later. */ + QQ_PushTail(&pDevice->RxPacketReceivedQ.Container, pPacket); + + /* Go to the next buffer descriptor. */ + SwRcvRetConIdx = (SwRcvRetConIdx + 1) & + T3_RCV_RETURN_RCB_ENTRY_COUNT_MASK; + + /* Get the updated HwRcvRetProdIdx. */ + HwRcvRetProdIdx = pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx; + } /* while */ + + pDevice->RcvRetConIdx = SwRcvRetConIdx; + + /* Update the receive return ring consumer index. */ + MB_REG_WR(pDevice, Mailbox.RcvRetConIdx[0].Low, SwRcvRetConIdx); +} /* LM_ServiceRxInterrupt */ + + + +/******************************************************************************/ +/* Description: */ +/* This is the interrupt event handler routine. It acknowledges all */ +/* pending interrupts and process all pending events. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_ServiceInterrupts( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + int ServicePhyInt = FALSE; + + /* Setup the phy chip whenever the link status changes. */ + if(pDevice->LinkChngMode == T3_LINK_CHNG_MODE_USE_STATUS_REG) + { + Value32 = REG_RD(pDevice, MacCtrl.Status); + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) + { + if (Value32 & MAC_STATUS_MI_INTERRUPT) + { + ServicePhyInt = TRUE; + } + } + else if(Value32 & MAC_STATUS_LINK_STATE_CHANGED) + { + ServicePhyInt = TRUE; + } + } + else + { + if(pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_LINK_CHANGED_STATUS) + { + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED | + (pDevice->pStatusBlkVirt->Status & ~STATUS_BLOCK_LINK_CHANGED_STATUS); + ServicePhyInt = TRUE; + } + } +#if INCLUDE_TBI_SUPPORT + if (pDevice->IgnoreTbiLinkChange == TRUE) + { + ServicePhyInt = FALSE; + } +#endif + if (ServicePhyInt == TRUE) + { + MM_ACQUIRE_PHY_LOCK_IN_IRQ(pDevice); + LM_SetupPhy(pDevice); + MM_RELEASE_PHY_LOCK_IN_IRQ(pDevice); + } + + /* Service receive and transmit interrupts. */ + LM_ServiceRxInterrupt(pDevice); + LM_ServiceTxInterrupt(pDevice); + + /* No spinlock for this queue since this routine is serialized. */ + if(!QQ_Empty(&pDevice->RxPacketReceivedQ.Container)) + { + /* Indicate receive packets. */ + MM_IndicateRxPackets(pDevice); +// LM_QueueRxPackets(pDevice); + } + + /* No spinlock for this queue since this routine is serialized. */ + if(!QQ_Empty(&pDevice->TxPacketXmittedQ.Container)) + { + MM_IndicateTxPackets(pDevice); + } + + return LM_STATUS_SUCCESS; +} /* LM_ServiceInterrupts */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_MulticastAdd( +PLM_DEVICE_BLOCK pDevice, +PLM_UINT8 pMcAddress) { + PLM_UINT8 pEntry; + LM_UINT32 j; + + pEntry = pDevice->McTable[0]; + for(j = 0; j < pDevice->McEntryCount; j++) + { + if(IS_ETH_ADDRESS_EQUAL(pEntry, pMcAddress)) + { + /* Found a match, increment the instance count. */ + pEntry[LM_MC_INSTANCE_COUNT_INDEX] += 1; + + return LM_STATUS_SUCCESS; + } + + pEntry += LM_MC_ENTRY_SIZE; + } + + if(pDevice->McEntryCount >= LM_MAX_MC_TABLE_SIZE) + { + return LM_STATUS_FAILURE; + } + + pEntry = pDevice->McTable[pDevice->McEntryCount]; + + COPY_ETH_ADDRESS(pMcAddress, pEntry); + pEntry[LM_MC_INSTANCE_COUNT_INDEX] = 1; + + pDevice->McEntryCount++; + + LM_SetReceiveMask(pDevice, pDevice->ReceiveMask | LM_ACCEPT_MULTICAST); + + return LM_STATUS_SUCCESS; +} /* LM_MulticastAdd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_MulticastDel( +PLM_DEVICE_BLOCK pDevice, +PLM_UINT8 pMcAddress) { + PLM_UINT8 pEntry; + LM_UINT32 j; + + pEntry = pDevice->McTable[0]; + for(j = 0; j < pDevice->McEntryCount; j++) + { + if(IS_ETH_ADDRESS_EQUAL(pEntry, pMcAddress)) + { + /* Found a match, decrement the instance count. */ + pEntry[LM_MC_INSTANCE_COUNT_INDEX] -= 1; + + /* No more instance left, remove the address from the table. */ + /* Move the last entry in the table to the delete slot. */ + if(pEntry[LM_MC_INSTANCE_COUNT_INDEX] == 0 && + pDevice->McEntryCount > 1) + { + + COPY_ETH_ADDRESS( + pDevice->McTable[pDevice->McEntryCount-1], pEntry); + pEntry[LM_MC_INSTANCE_COUNT_INDEX] = + pDevice->McTable[pDevice->McEntryCount-1] + [LM_MC_INSTANCE_COUNT_INDEX]; + } + pDevice->McEntryCount--; + + /* Update the receive mask if the table is empty. */ + if(pDevice->McEntryCount == 0) + { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask & ~LM_ACCEPT_MULTICAST); + } + + return LM_STATUS_SUCCESS; + } + + pEntry += LM_MC_ENTRY_SIZE; + } + + return LM_STATUS_FAILURE; +} /* LM_MulticastDel */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_MulticastClear( +PLM_DEVICE_BLOCK pDevice) { + pDevice->McEntryCount = 0; + + LM_SetReceiveMask(pDevice, pDevice->ReceiveMask & ~LM_ACCEPT_MULTICAST); + + return LM_STATUS_SUCCESS; +} /* LM_MulticastClear */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetMacAddress( + PLM_DEVICE_BLOCK pDevice, + PLM_UINT8 pMacAddress) +{ + LM_UINT32 j; + + for(j = 0; j < 4; j++) + { + REG_WR(pDevice, MacCtrl.MacAddr[j].High, + (pMacAddress[0] << 8) | pMacAddress[1]); + REG_WR(pDevice, MacCtrl.MacAddr[j].Low, + (pMacAddress[2] << 24) | (pMacAddress[3] << 16) | + (pMacAddress[4] << 8) | pMacAddress[5]); + } + + return LM_STATUS_SUCCESS; +} + + +/******************************************************************************/ +/* Description: */ +/* Sets up the default line speed, and duplex modes based on the requested */ +/* media type. */ +/* */ +/* Return: */ +/* None. */ +/******************************************************************************/ +static LM_STATUS +LM_TranslateRequestedMediaType( +LM_REQUESTED_MEDIA_TYPE RequestedMediaType, +PLM_MEDIA_TYPE pMediaType, +PLM_LINE_SPEED pLineSpeed, +PLM_DUPLEX_MODE pDuplexMode) { + *pMediaType = LM_MEDIA_TYPE_AUTO; + *pLineSpeed = LM_LINE_SPEED_UNKNOWN; + *pDuplexMode = LM_DUPLEX_MODE_UNKNOWN; + + /* determine media type */ + switch(RequestedMediaType) { + case LM_REQUESTED_MEDIA_TYPE_BNC: + *pMediaType = LM_MEDIA_TYPE_BNC; + *pLineSpeed = LM_LINE_SPEED_10MBPS; + *pDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case LM_REQUESTED_MEDIA_TYPE_UTP_AUTO: + *pMediaType = LM_MEDIA_TYPE_UTP; + break; + + case LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS: + *pMediaType = LM_MEDIA_TYPE_UTP; + *pLineSpeed = LM_LINE_SPEED_10MBPS; + *pDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX: + *pMediaType = LM_MEDIA_TYPE_UTP; + *pLineSpeed = LM_LINE_SPEED_10MBPS; + *pDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS: + *pMediaType = LM_MEDIA_TYPE_UTP; + *pLineSpeed = LM_LINE_SPEED_100MBPS; + *pDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX: + *pMediaType = LM_MEDIA_TYPE_UTP; + *pLineSpeed = LM_LINE_SPEED_100MBPS; + *pDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS: + *pMediaType = LM_MEDIA_TYPE_UTP; + *pLineSpeed = LM_LINE_SPEED_1000MBPS; + *pDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX: + *pMediaType = LM_MEDIA_TYPE_UTP; + *pLineSpeed = LM_LINE_SPEED_1000MBPS; + *pDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS: + *pMediaType = LM_MEDIA_TYPE_FIBER; + *pLineSpeed = LM_LINE_SPEED_100MBPS; + *pDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case LM_REQUESTED_MEDIA_TYPE_FIBER_100MBPS_FULL_DUPLEX: + *pMediaType = LM_MEDIA_TYPE_FIBER; + *pLineSpeed = LM_LINE_SPEED_100MBPS; + *pDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS: + *pMediaType = LM_MEDIA_TYPE_FIBER; + *pLineSpeed = LM_LINE_SPEED_1000MBPS; + *pDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX: + *pMediaType = LM_MEDIA_TYPE_FIBER; + *pLineSpeed = LM_LINE_SPEED_1000MBPS; + *pDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + default: + break; + } /* switch */ + + return LM_STATUS_SUCCESS; +} /* LM_TranslateRequestedMediaType */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* LM_STATUS_LINK_ACTIVE */ +/* LM_STATUS_LINK_DOWN */ +/******************************************************************************/ +static LM_STATUS +LM_InitBcm540xPhy( +PLM_DEVICE_BLOCK pDevice) +{ + LM_LINE_SPEED CurrentLineSpeed; + LM_DUPLEX_MODE CurrentDuplexMode; + LM_STATUS CurrentLinkStatus; + LM_UINT32 Value32; + LM_UINT32 j; + + if((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + { + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + if(!pDevice->InitDone) + { + Value32 = 0; + } + + if(!(Value32 & PHY_STATUS_LINK_PASS)) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x0c20); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0012); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1804); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0013); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1204); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0132); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0232); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x201f); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0a20); + + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + for(j = 0; j < 1000; j++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + if(Value32 & PHY_STATUS_LINK_PASS) + { + MM_Wait(40); + break; + } + } + + if((pDevice->PhyId & PHY_ID_REV_MASK) == PHY_BCM5401_B0_REV) + { + if(!(Value32 & PHY_STATUS_LINK_PASS) && + (pDevice->OldLineSpeed == LM_LINE_SPEED_1000MBPS)) + { + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_PHY_RESET); + for(j = 0; j < 100; j++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if(!(Value32 & PHY_CTRL_PHY_RESET)) + { + MM_Wait(40); + break; + } + } + + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x0c20); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0012); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1804); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0013); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1204); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0132); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0232); + + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x201f); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0a20); + } + } + } + } + else if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0) + { + /* Bug: 5701 A0, B0 TX CRC workaround. */ + LM_WritePhy(pDevice, 0x15, 0x0a75); + LM_WritePhy(pDevice, 0x1c, 0x8c68); + LM_WritePhy(pDevice, 0x1c, 0x8d68); + LM_WritePhy(pDevice, 0x1c, 0x8c68); + } + + /* Acknowledge interrupts. */ + LM_ReadPhy(pDevice, BCM540X_INT_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, BCM540X_INT_STATUS_REG, &Value32); + + /* Configure the interrupt mask. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) + { + LM_WritePhy(pDevice, BCM540X_INT_MASK_REG, ~BCM540X_INT_LINK_CHANGE); + } + + /* Configure PHY led mode. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701 || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700)) + { + if(pDevice->LedMode == LED_MODE_THREE_LINK) + { + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, + BCM540X_EXT_CTRL_LINK3_LED_MODE); + } + else + { + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, 0); + } + } + + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + + /* Get current link and duplex mode. */ + for(j = 0; j < 100; j++) + { + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + if(Value32 & PHY_STATUS_LINK_PASS) + { + break; + } + MM_Wait(40); + } + + if(Value32 & PHY_STATUS_LINK_PASS) + { + + /* Determine the current line and duplex settings. */ + LM_ReadPhy(pDevice, BCM540X_AUX_STATUS_REG, &Value32); + for(j = 0; j < 2000; j++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, BCM540X_AUX_STATUS_REG, &Value32); + if(Value32) + { + break; + } + } + + switch(Value32 & BCM540X_AUX_SPEED_MASK) + { + case BCM540X_AUX_10BASET_HD: + CurrentLineSpeed = LM_LINE_SPEED_10MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_10BASET_FD: + CurrentLineSpeed = LM_LINE_SPEED_10MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case BCM540X_AUX_100BASETX_HD: + CurrentLineSpeed = LM_LINE_SPEED_100MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_100BASETX_FD: + CurrentLineSpeed = LM_LINE_SPEED_100MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case BCM540X_AUX_100BASET_HD: + CurrentLineSpeed = LM_LINE_SPEED_1000MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_100BASET_FD: + CurrentLineSpeed = LM_LINE_SPEED_1000MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + default: + + CurrentLineSpeed = LM_LINE_SPEED_UNKNOWN; + CurrentDuplexMode = LM_DUPLEX_MODE_UNKNOWN; + break; + } + + /* Make sure we are in auto-neg mode. */ + for (j = 0; j < 200; j++) + { + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if(Value32 && Value32 != 0x7fff) + { + break; + } + + if(Value32 == 0 && pDevice->RequestedMediaType == + LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS) + { + break; + } + + MM_Wait(10); + } + + /* Use the current line settings for "auto" mode. */ + if(pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_AUTO || + pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_UTP_AUTO) + { + if(Value32 & PHY_CTRL_AUTO_NEG_ENABLE) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + + /* We may be exiting low power mode and the link is in */ + /* 10mb. In this case, we need to restart autoneg. */ + LM_ReadPhy(pDevice, BCM540X_1000BASET_CTRL_REG, &Value32); + pDevice->advertising1000 = Value32; + /* 5702FE supports 10/100Mb only. */ + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5703 || + pDevice->BondId != GRC_MISC_BD_ID_5702FE) + { + if(!(Value32 & (BCM540X_AN_AD_1000BASET_HALF | + BCM540X_AN_AD_1000BASET_FULL))) + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + } + else + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + else + { + /* Force line settings. */ + /* Use the current setting if it matches the user's requested */ + /* setting. */ + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if((pDevice->LineSpeed == CurrentLineSpeed) && + (pDevice->DuplexMode == CurrentDuplexMode)) + { + if ((pDevice->DisableAutoNeg && + !(Value32 & PHY_CTRL_AUTO_NEG_ENABLE)) || + (!pDevice->DisableAutoNeg && + (Value32 & PHY_CTRL_AUTO_NEG_ENABLE))) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + else + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + else + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + + /* Save line settings. */ + pDevice->LineSpeed = CurrentLineSpeed; + pDevice->DuplexMode = CurrentDuplexMode; + pDevice->MediaType = LM_MEDIA_TYPE_UTP; + } + + return CurrentLinkStatus; +} /* LM_InitBcm540xPhy */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetFlowControl( + PLM_DEVICE_BLOCK pDevice, + LM_UINT32 LocalPhyAd, + LM_UINT32 RemotePhyAd) +{ + LM_FLOW_CONTROL FlowCap; + + /* Resolve flow control. */ + FlowCap = LM_FLOW_CONTROL_NONE; + + /* See Table 28B-3 of 802.3ab-1999 spec. */ + if(pDevice->FlowControlCap & LM_FLOW_CONTROL_AUTO_PAUSE) + { + if(LocalPhyAd & PHY_AN_AD_PAUSE_CAPABLE) + { + if(LocalPhyAd & PHY_AN_AD_ASYM_PAUSE) + { + if(RemotePhyAd & PHY_LINK_PARTNER_PAUSE_CAPABLE) + { + FlowCap = LM_FLOW_CONTROL_TRANSMIT_PAUSE | + LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + else if(RemotePhyAd & PHY_LINK_PARTNER_ASYM_PAUSE) + { + FlowCap = LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + } + else + { + if(RemotePhyAd & PHY_LINK_PARTNER_PAUSE_CAPABLE) + { + FlowCap = LM_FLOW_CONTROL_TRANSMIT_PAUSE | + LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + } + } + else if(LocalPhyAd & PHY_AN_AD_ASYM_PAUSE) + { + if((RemotePhyAd & PHY_LINK_PARTNER_PAUSE_CAPABLE) && + (RemotePhyAd & PHY_LINK_PARTNER_ASYM_PAUSE)) + { + FlowCap = LM_FLOW_CONTROL_TRANSMIT_PAUSE; + } + } + } + else + { + FlowCap = pDevice->FlowControlCap; + } + + /* Enable/disable rx PAUSE. */ + pDevice->RxMode &= ~RX_MODE_ENABLE_FLOW_CONTROL; + if(FlowCap & LM_FLOW_CONTROL_RECEIVE_PAUSE && + (pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE || + pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE)) + { + pDevice->FlowControl |= LM_FLOW_CONTROL_RECEIVE_PAUSE; + pDevice->RxMode |= RX_MODE_ENABLE_FLOW_CONTROL; + + } + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + + /* Enable/disable tx PAUSE. */ + pDevice->TxMode &= ~TX_MODE_ENABLE_FLOW_CONTROL; + if(FlowCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE && + (pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE || + pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE)) + { + pDevice->FlowControl |= LM_FLOW_CONTROL_TRANSMIT_PAUSE; + pDevice->TxMode |= TX_MODE_ENABLE_FLOW_CONTROL; + + } + REG_WR(pDevice, MacCtrl.TxMode, pDevice->TxMode); + + return LM_STATUS_SUCCESS; +} + + +#if INCLUDE_TBI_SUPPORT +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_InitBcm800xPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + LM_UINT32 j; + + Value32 = REG_RD(pDevice, MacCtrl.Status); + + /* Reset the SERDES during init and when we have link. */ + if(!pDevice->InitDone || Value32 & MAC_STATUS_PCS_SYNCED) + { + /* Set PLL lock range. */ + LM_WritePhy(pDevice, 0x16, 0x8007); + + /* Software reset. */ + LM_WritePhy(pDevice, 0x00, 0x8000); + + /* Wait for reset to complete. */ + for(j = 0; j < 500; j++) + { + MM_Wait(10); + } + +#if DBG + /* Verify lock (if cable attached). Should be 0x8001. */ + LM_ReadPhy(pDevice, 0x10, &Value32); + DbgMessage(INFORM, ("FiberPhy 0x10 = 0x%x\n", Value32)); +#endif + + /* Config mode; seletct PMA/Ch 1 regs. */ + LM_WritePhy(pDevice, 0x10, 0x8411); + + /* Enable auto-lock and comdet, select txclk for tx. */ + LM_WritePhy(pDevice, 0x11, 0x0a10); + + LM_WritePhy(pDevice, 0x18, 0x00a0); + LM_WritePhy(pDevice, 0x16, 0x41ff); + + /* Assert and deassert POR. */ + LM_WritePhy(pDevice, 0x13, 0x0400); + MM_Wait(40); + LM_WritePhy(pDevice, 0x13, 0x0000); + + LM_WritePhy(pDevice, 0x11, 0x0a50); + MM_Wait(40); + LM_WritePhy(pDevice, 0x11, 0x0a10); + + /* Delay for signal to stabilize. */ + for(j = 0; j < 15000; j++) + { + MM_Wait(10); + } + + /* Deselect the channel register so we can read the PHY id later. */ + LM_WritePhy(pDevice, 0x10, 0x8011); + } + + return LM_STATUS_SUCCESS; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_SetupFiberPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_STATUS CurrentLinkStatus; + AUTONEG_STATUS AnStatus = 0; + LM_UINT32 Value32; + LM_UINT32 Cnt; + LM_UINT32 j, k; + + pDevice->MacMode &= ~(MAC_MODE_HALF_DUPLEX | MAC_MODE_PORT_MODE_MASK); + + /* Initialize the send_config register. */ + REG_WR(pDevice, MacCtrl.TxAutoNeg, 0); + + /* Enable TBI and full duplex mode. */ + pDevice->MacMode |= MAC_MODE_PORT_MODE_TBI; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + + /* Initialize the BCM8002 SERDES PHY. */ + switch(pDevice->PhyId & PHY_ID_MASK) + { + case PHY_BCM8002_PHY_ID: + LM_InitBcm800xPhy(pDevice); + break; + + default: + break; + } + + /* Enable link change interrupt. */ + REG_WR(pDevice, MacCtrl.MacEvent, MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN); + + /* Default to link down. */ + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + + /* Get the link status. */ + Value32 = REG_RD(pDevice, MacCtrl.Status); + if(Value32 & MAC_STATUS_PCS_SYNCED) + { + if((pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_AUTO) || + (pDevice->DisableAutoNeg == FALSE)) + { + /* auto-negotiation mode. */ + /* Initialize the autoneg default capaiblities. */ + AutonegInit(&pDevice->AnInfo); + + /* Set the context pointer to point to the main device structure. */ + pDevice->AnInfo.pContext = pDevice; + + /* Setup flow control advertisement register. */ + Value32 = GetPhyAdFlowCntrlSettings(pDevice); + if(Value32 & PHY_AN_AD_PAUSE_CAPABLE) + { + pDevice->AnInfo.mr_adv_sym_pause = 1; + } + else + { + pDevice->AnInfo.mr_adv_sym_pause = 0; + } + + if(Value32 & PHY_AN_AD_ASYM_PAUSE) + { + pDevice->AnInfo.mr_adv_asym_pause = 1; + } + else + { + pDevice->AnInfo.mr_adv_asym_pause = 0; + } + + /* Try to autoneg up to six times. */ + if (pDevice->IgnoreTbiLinkChange) + { + Cnt = 1; + } + else + { + Cnt = 6; + } + for (j = 0; j < Cnt; j++) + { + REG_WR(pDevice, MacCtrl.TxAutoNeg, 0); + + Value32 = pDevice->MacMode & ~MAC_MODE_PORT_MODE_MASK; + REG_WR(pDevice, MacCtrl.Mode, Value32); + MM_Wait(20); + + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_SEND_CONFIGS); + + MM_Wait(20); + + pDevice->AnInfo.State = AN_STATE_UNKNOWN; + pDevice->AnInfo.CurrentTime_us = 0; + + REG_WR(pDevice, Grc.Timer, 0); + for(k = 0; (pDevice->AnInfo.CurrentTime_us < 75000) && + (k < 75000); k++) + { + AnStatus = Autoneg8023z(&pDevice->AnInfo); + + if((AnStatus == AUTONEG_STATUS_DONE) || + (AnStatus == AUTONEG_STATUS_FAILED)) + { + break; + } + + pDevice->AnInfo.CurrentTime_us = REG_RD(pDevice, Grc.Timer); + + } + if((AnStatus == AUTONEG_STATUS_DONE) || + (AnStatus == AUTONEG_STATUS_FAILED)) + { + break; + } + if (j >= 1) + { + if (!(REG_RD(pDevice, MacCtrl.Status) & + MAC_STATUS_PCS_SYNCED)) { + break; + } + } + } + + /* Stop sending configs. */ + MM_AnTxIdle(&pDevice->AnInfo); + + /* Resolve flow control settings. */ + if((AnStatus == AUTONEG_STATUS_DONE) && + pDevice->AnInfo.mr_an_complete && pDevice->AnInfo.mr_link_ok && + pDevice->AnInfo.mr_lp_adv_full_duplex) + { + LM_UINT32 RemotePhyAd; + LM_UINT32 LocalPhyAd; + + LocalPhyAd = 0; + if(pDevice->AnInfo.mr_adv_sym_pause) + { + LocalPhyAd |= PHY_AN_AD_PAUSE_CAPABLE; + } + + if(pDevice->AnInfo.mr_adv_asym_pause) + { + LocalPhyAd |= PHY_AN_AD_ASYM_PAUSE; + } + + RemotePhyAd = 0; + if(pDevice->AnInfo.mr_lp_adv_sym_pause) + { + RemotePhyAd |= PHY_LINK_PARTNER_PAUSE_CAPABLE; + } + + if(pDevice->AnInfo.mr_lp_adv_asym_pause) + { + RemotePhyAd |= PHY_LINK_PARTNER_ASYM_PAUSE; + } + + LM_SetFlowControl(pDevice, LocalPhyAd, RemotePhyAd); + + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + for (j = 0; j < 30; j++) + { + MM_Wait(20); + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + MM_Wait(20); + if ((REG_RD(pDevice, MacCtrl.Status) & + (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + if (pDevice->PollTbiLink) + { + Value32 = REG_RD(pDevice, MacCtrl.Status); + if (Value32 & MAC_STATUS_RECEIVING_CFG) + { + pDevice->IgnoreTbiLinkChange = TRUE; + } + else + { + pDevice->IgnoreTbiLinkChange = FALSE; + } + } + Value32 = REG_RD(pDevice, MacCtrl.Status); + if (CurrentLinkStatus == LM_STATUS_LINK_DOWN && + (Value32 & MAC_STATUS_PCS_SYNCED) && + ((Value32 & MAC_STATUS_RECEIVING_CFG) == 0)) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + } + else + { + /* We are forcing line speed. */ + pDevice->FlowControlCap &= ~LM_FLOW_CONTROL_AUTO_PAUSE; + LM_SetFlowControl(pDevice, 0, 0); + + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_SEND_CONFIGS); + } + } + /* Set the link polarity bit. */ + pDevice->MacMode &= ~MAC_MODE_LINK_POLARITY; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED | + (pDevice->pStatusBlkVirt->Status & ~STATUS_BLOCK_LINK_CHANGED_STATUS); + + for (j = 0; j < 100; j++) + { + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + MM_Wait(5); + if ((REG_RD(pDevice, MacCtrl.Status) & + (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + + Value32 = REG_RD(pDevice, MacCtrl.Status); + if((Value32 & MAC_STATUS_PCS_SYNCED) == 0) + { + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + if (pDevice->DisableAutoNeg == FALSE) + { + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_SEND_CONFIGS); + MM_Wait(1); + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + } + } + + /* Initialize the current link status. */ + if(CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + pDevice->LineSpeed = LM_LINE_SPEED_1000MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_FULL; + REG_WR(pDevice, MacCtrl.LedCtrl, LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_1000MBPS_LED_ON); + } + else + { + pDevice->LineSpeed = LM_LINE_SPEED_UNKNOWN; + pDevice->DuplexMode = LM_DUPLEX_MODE_UNKNOWN; + REG_WR(pDevice, MacCtrl.LedCtrl, LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_OVERRIDE_TRAFFIC_LED); + } + + /* Indicate link status. */ + if (pDevice->LinkStatus != CurrentLinkStatus) { + pDevice->LinkStatus = CurrentLinkStatus; + MM_IndicateStatus(pDevice, CurrentLinkStatus); + } + + return LM_STATUS_SUCCESS; +} +#endif /* INCLUDE_TBI_SUPPORT */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetupCopperPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_STATUS CurrentLinkStatus; + LM_UINT32 Value32; + + /* Assume there is not link first. */ + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + + /* Disable phy link change attention. */ + REG_WR(pDevice, MacCtrl.MacEvent, 0); + + /* Clear link change attention. */ + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + + /* Disable auto-polling for the moment. */ + pDevice->MiMode = 0xc0000; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + MM_Wait(40); + + /* Determine the requested line speed and duplex. */ + pDevice->OldLineSpeed = pDevice->LineSpeed; + LM_TranslateRequestedMediaType(pDevice->RequestedMediaType, + &pDevice->MediaType, &pDevice->LineSpeed, &pDevice->DuplexMode); + + /* Initialize the phy chip. */ + switch(pDevice->PhyId & PHY_ID_MASK) + { + case PHY_BCM5400_PHY_ID: + case PHY_BCM5401_PHY_ID: + case PHY_BCM5411_PHY_ID: + case PHY_BCM5701_PHY_ID: + case PHY_BCM5703_PHY_ID: + CurrentLinkStatus = LM_InitBcm540xPhy(pDevice); + break; + + default: + break; + } + + if(CurrentLinkStatus == LM_STATUS_LINK_SETTING_MISMATCH) + { + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + } + + /* Setup flow control. */ + pDevice->FlowControl = LM_FLOW_CONTROL_NONE; + if(CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + LM_FLOW_CONTROL FlowCap; /* Flow control capability. */ + + FlowCap = LM_FLOW_CONTROL_NONE; + + if(pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) + { + if(pDevice->DisableAutoNeg == FALSE || + pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_AUTO || + pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_UTP_AUTO) + { + LM_UINT32 ExpectedPhyAd; + LM_UINT32 LocalPhyAd; + LM_UINT32 RemotePhyAd; + + LM_ReadPhy(pDevice, PHY_AN_AD_REG, &LocalPhyAd); + pDevice->advertising = LocalPhyAd; + LocalPhyAd &= (PHY_AN_AD_ASYM_PAUSE | PHY_AN_AD_PAUSE_CAPABLE); + + ExpectedPhyAd = GetPhyAdFlowCntrlSettings(pDevice); + + if(LocalPhyAd != ExpectedPhyAd) + { + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + } + else + { + LM_ReadPhy(pDevice, PHY_LINK_PARTNER_ABILITY_REG, + &RemotePhyAd); + + LM_SetFlowControl(pDevice, LocalPhyAd, RemotePhyAd); + } + } + else + { + pDevice->FlowControlCap &= ~LM_FLOW_CONTROL_AUTO_PAUSE; + LM_SetFlowControl(pDevice, 0, 0); + } + } + } + + if(CurrentLinkStatus == LM_STATUS_LINK_DOWN) + { + LM_ForceAutoNeg(pDevice, pDevice->RequestedMediaType, FALSE); + + /* If we force line speed, we make get link right away. */ + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + if(Value32 & PHY_STATUS_LINK_PASS) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + } + + /* GMII interface. */ + pDevice->MacMode &= ~MAC_MODE_PORT_MODE_MASK; + if(CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + if(pDevice->LineSpeed == LM_LINE_SPEED_100MBPS || + pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) + { + pDevice->MacMode |= MAC_MODE_PORT_MODE_MII; + } + else + { + pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII; + } + } + else { + pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII; + } + + /* Set the MAC to operate in the appropriate duplex mode. */ + pDevice->MacMode &= ~MAC_MODE_HALF_DUPLEX; + if(pDevice->DuplexMode == LM_DUPLEX_MODE_HALF) + { + pDevice->MacMode |= MAC_MODE_HALF_DUPLEX; + } + + /* Set the link polarity bit. */ + pDevice->MacMode &= ~MAC_MODE_LINK_POLARITY; + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + if((pDevice->LedMode == LED_MODE_LINK10) || + (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE && + pDevice->LineSpeed == LM_LINE_SPEED_10MBPS)) + { + pDevice->MacMode |= MAC_MODE_LINK_POLARITY; + } + } + else + { + if (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + pDevice->MacMode |= MAC_MODE_LINK_POLARITY; + } + + /* Set LED mode. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = LED_CTRL_PHY_MODE_1; + } + else + { + if(pDevice->LedMode == LED_MODE_OUTPUT) + { + Value32 = LED_CTRL_PHY_MODE_2; + } + else + { + Value32 = LED_CTRL_PHY_MODE_1; + } + } + REG_WR(pDevice, MacCtrl.LedCtrl, Value32); + } + + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + + /* Enable auto polling. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + pDevice->MiMode |= MI_MODE_AUTO_POLLING_ENABLE; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + } + + /* Enable phy link change attention. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) + { + REG_WR(pDevice, MacCtrl.MacEvent, MAC_EVENT_ENABLE_MI_INTERRUPT); + } + else + { + REG_WR(pDevice, MacCtrl.MacEvent, + MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN); + } + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) && + (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) && + (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) && + (((pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) && + (pDevice->PciState & T3_PCI_STATE_BUS_SPEED_HIGH)) || + !(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE))) + { + MM_Wait(120); + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + MEM_WR_OFFSET(pDevice, T3_FIRMWARE_MAILBOX, + T3_MAGIC_NUM_DISABLE_DMAW_ON_LINK_CHANGE); + } + + /* Indicate link status. */ + if (pDevice->LinkStatus != CurrentLinkStatus) { + pDevice->LinkStatus = CurrentLinkStatus; + MM_IndicateStatus(pDevice, CurrentLinkStatus); + } + + return LM_STATUS_SUCCESS; +} /* LM_SetupCopperPhy */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetupPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_STATUS LmStatus; + +#if INCLUDE_TBI_SUPPORT + if(pDevice->EnableTbi) + { + LmStatus = LM_SetupFiberPhy(pDevice); + } + else +#endif /* INCLUDE_TBI_SUPPORT */ + { + LmStatus = LM_SetupCopperPhy(pDevice); + } + if ((pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) && + (pDevice->DuplexMode == LM_DUPLEX_MODE_HALF)) + { + REG_WR(pDevice, MacCtrl.TxLengths, 0x26ff); + } + else + { + REG_WR(pDevice, MacCtrl.TxLengths, 0x2620); + } + + return LmStatus; +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_ReadPhy( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 PhyReg, +PLM_UINT32 pData32) { + LM_UINT32 Value32; + LM_UINT32 j; + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode & + ~MI_MODE_AUTO_POLLING_ENABLE); + MM_Wait(40); + } + + Value32 = (pDevice->PhyAddr << MI_COM_FIRST_PHY_ADDR_BIT) | + ((PhyReg & MI_COM_PHY_REG_ADDR_MASK) << MI_COM_FIRST_PHY_REG_ADDR_BIT) | + MI_COM_CMD_READ | MI_COM_START; + + REG_WR(pDevice, MacCtrl.MiCom, Value32); + + for(j = 0; j < 20; j++) + { + MM_Wait(25); + + Value32 = REG_RD(pDevice, MacCtrl.MiCom); + + if(!(Value32 & MI_COM_BUSY)) + { + MM_Wait(5); + Value32 = REG_RD(pDevice, MacCtrl.MiCom); + Value32 &= MI_COM_PHY_DATA_MASK; + break; + } + } + + if(Value32 & MI_COM_BUSY) + { + Value32 = 0; + } + + *pData32 = Value32; + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + MM_Wait(40); + } +} /* LM_ReadPhy */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_WritePhy( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 PhyReg, +LM_UINT32 Data32) { + LM_UINT32 Value32; + LM_UINT32 j; + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode & + ~MI_MODE_AUTO_POLLING_ENABLE); + MM_Wait(40); + } + + Value32 = (pDevice->PhyAddr << MI_COM_FIRST_PHY_ADDR_BIT) | + ((PhyReg & MI_COM_PHY_REG_ADDR_MASK) << MI_COM_FIRST_PHY_REG_ADDR_BIT) | + (Data32 & MI_COM_PHY_DATA_MASK) | MI_COM_CMD_WRITE | MI_COM_START; + + REG_WR(pDevice, MacCtrl.MiCom, Value32); + + for(j = 0; j < 20; j++) + { + MM_Wait(25); + + Value32 = REG_RD(pDevice, MacCtrl.MiCom); + + if(!(Value32 & MI_COM_BUSY)) + { + MM_Wait(5); + break; + } + } + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + MM_Wait(40); + } +} /* LM_WritePhy */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetPowerState( +PLM_DEVICE_BLOCK pDevice, +LM_POWER_STATE PowerLevel) { + LM_UINT32 PmeSupport; + LM_UINT32 Value32; + LM_UINT32 PmCtrl; + + /* make sureindirect accesses are enabled*/ + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, pDevice->MiscHostCtrl); + + /* Clear the PME_ASSERT bit and the power state bits. Also enable */ + /* the PME bit. */ + MM_ReadConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, &PmCtrl); + + PmCtrl |= T3_PM_PME_ASSERTED; + PmCtrl &= ~T3_PM_POWER_STATE_MASK; + + /* Set the appropriate power state. */ + if(PowerLevel == LM_POWER_STATE_D0) + { + + /* Bring the card out of low power mode. */ + PmCtrl |= T3_PM_POWER_STATE_D0; + MM_WriteConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, PmCtrl); + + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl); + MM_Wait(40); /* Required delay is about 20us. */ + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x02); + + return LM_STATUS_SUCCESS; + } + else if(PowerLevel == LM_POWER_STATE_D1) + { + PmCtrl |= T3_PM_POWER_STATE_D1; + } + else if(PowerLevel == LM_POWER_STATE_D2) + { + PmCtrl |= T3_PM_POWER_STATE_D2; + } + else if(PowerLevel == LM_POWER_STATE_D3) + { + PmCtrl |= T3_PM_POWER_STATE_D3; + } + else + { + return LM_STATUS_FAILURE; + } + PmCtrl |= T3_PM_PME_ENABLE; + +#if 0 + /* No WOL. */ + if(pDevice->WakeUpModeCap == LM_WAKE_UP_MODE_NONE) + { + DbgMessage(INFORM, ("No power capabilities.\n")); + return LM_STATUS_FAILURE; + } +#endif + + /* Mask out all interrupts so LM_SetupPhy won't be called while we are */ + /* setting new line speed. */ + Value32 = REG_RD(pDevice, PciCfg.MiscHostCtrl); + REG_WR(pDevice, PciCfg.MiscHostCtrl, Value32 | MISC_HOST_CTRL_MASK_PCI_INT); + + if(!pDevice->RestoreOnWakeUp) + { + pDevice->RestoreOnWakeUp = TRUE; + pDevice->WakeUpDisableAutoNeg = pDevice->DisableAutoNeg; + pDevice->WakeUpRequestedMediaType = pDevice->RequestedMediaType; + } + + /* Force auto-negotiation to 10 line speed. */ + pDevice->DisableAutoNeg = FALSE; + pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS; + LM_SetupPhy(pDevice); + + /* Put the driver in the initial state, and go through the power down */ + /* sequence. */ + LM_Halt(pDevice); + + MM_ReadConfig32(pDevice, T3_PCI_PM_CAP_REG, &PmeSupport); + + if (pDevice->WakeUpModeCap != LM_WAKE_UP_MODE_NONE) + { + + /* Enable WOL. */ + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x5a); + MM_Wait(40); + + /* Set LED mode. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = LED_CTRL_PHY_MODE_1; + } + else + { + if(pDevice->LedMode == LED_MODE_OUTPUT) + { + Value32 = LED_CTRL_PHY_MODE_2; + } + else + { + Value32 = LED_CTRL_PHY_MODE_1; + } + } + + Value32 = MAC_MODE_PORT_MODE_MII; + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + if(pDevice->LedMode == LED_MODE_LINK10 || + pDevice->WolSpeed == WOL_SPEED_10MB) + { + Value32 |= MAC_MODE_LINK_POLARITY; + } + } + else + { + Value32 |= MAC_MODE_LINK_POLARITY; + } + + /* Always enable magic packet wake-up if we have vaux. */ + if((PmeSupport & T3_PCI_PM_CAP_PME_D3COLD) && + (pDevice->WakeUpModeCap & LM_WAKE_UP_MODE_MAGIC_PACKET)) + { + Value32 |= MAC_MODE_DETECT_MAGIC_PACKET_ENABLE; + } + + REG_WR(pDevice, MacCtrl.Mode, Value32); + + /* Enable the receiver. */ + REG_WR(pDevice, MacCtrl.RxMode, RX_MODE_ENABLE); + } + + /* Disable tx/rx clocks, and seletect an alternate clock. */ + if(pDevice->WolSpeed == WOL_SPEED_100MB) + { + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_SELECT_ALTERNATE_CLOCK; + } + else + { + Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK; + } + REG_WR(pDevice, PciCfg.ClockCtrl, Value32); + + MM_Wait(40); + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_SELECT_ALTERNATE_CLOCK | T3_PCI_44MHZ_CORE_CLOCK; + } + else + { + Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK | + T3_PCI_44MHZ_CORE_CLOCK; + } + + REG_WR(pDevice, PciCfg.ClockCtrl, Value32); + + MM_Wait(40); + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_44MHZ_CORE_CLOCK; + } + else + { + Value32 = T3_PCI_44MHZ_CORE_CLOCK; + } + + REG_WR(pDevice, PciCfg.ClockCtrl, Value32); + } + else + { + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_SELECT_ALTERNATE_CLOCK | + T3_PCI_POWER_DOWN_PCI_PLL133; + } + else + { + Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK | + T3_PCI_POWER_DOWN_PCI_PLL133; + } + + REG_WR(pDevice, PciCfg.ClockCtrl, Value32); + } + + MM_Wait(40); + + if(!pDevice->EepromWp && (pDevice->WakeUpModeCap != LM_WAKE_UP_MODE_NONE)) + { + /* Switch adapter to auxilliary power. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + /* GPIO0 = 1, GPIO1 = 1, GPIO2 = 0. */ + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + MM_Wait(40); + } + else + { + /* GPIO0 = 0, GPIO1 = 1, GPIO2 = 1. */ + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2); + MM_Wait(40); + + /* GPIO0 = 1, GPIO1 = 1, GPIO2 = 1. */ + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2); + MM_Wait(40); + + /* GPIO0 = 1, GPIO1 = 1, GPIO2 = 0. */ + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + MM_Wait(40); + } + } + + /* Set the phy to low power mode. */ + /* Put the the hardware in low power mode. */ + MM_WriteConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, PmCtrl); + + return LM_STATUS_SUCCESS; +} /* LM_SetPowerState */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +static LM_UINT32 +GetPhyAdFlowCntrlSettings( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + + Value32 = 0; + + /* Auto negotiation flow control only when autonegotiation is enabled. */ + if(pDevice->DisableAutoNeg == FALSE || + pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_AUTO || + pDevice->RequestedMediaType == LM_REQUESTED_MEDIA_TYPE_UTP_AUTO) + { + /* Please refer to Table 28B-3 of the 802.3ab-1999 spec. */ + if((pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE) || + ((pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE) && + (pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE))) + { + Value32 |= PHY_AN_AD_PAUSE_CAPABLE; + } + else if(pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE) + { + Value32 |= PHY_AN_AD_ASYM_PAUSE; + } + else if(pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE) + { + Value32 |= PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE; + } + } + + return Value32; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* LM_STATUS_FAILURE */ +/* LM_STATUS_SUCCESS */ +/* */ +/* If WaitForLink is TRUE, the return code is one of the following. */ +/* LM_STATUS_LINK_DOWN */ +/* LM_STATUS_LINK_ACTIVE */ +/******************************************************************************/ +static LM_STATUS +LM_ForceAutoNegBcm540xPhy( +PLM_DEVICE_BLOCK pDevice, +LM_REQUESTED_MEDIA_TYPE RequestedMediaType, +LM_BOOL WaitForLink) +{ + LM_MEDIA_TYPE MediaType; + LM_LINE_SPEED LineSpeed; + LM_DUPLEX_MODE DuplexMode; + LM_UINT32 NewPhyCtrl; + LM_STATUS LmStatus; + LM_UINT32 Value32; + LM_UINT32 Cnt; + + /* Get the interface type, line speed, and duplex mode. */ + LM_TranslateRequestedMediaType(RequestedMediaType, &MediaType, &LineSpeed, + &DuplexMode); + + if (pDevice->RestoreOnWakeUp) + { + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, 0); + pDevice->advertising1000 = 0; + Value32 = PHY_AN_AD_10BASET_FULL | PHY_AN_AD_10BASET_HALF; + if (pDevice->WolSpeed == WOL_SPEED_100MB) + { + Value32 |= PHY_AN_AD_100BASETX_FULL | PHY_AN_AD_100BASETX_HALF; + } + Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + } + /* Setup the auto-negotiation advertisement register. */ + else if(LineSpeed == LM_LINE_SPEED_UNKNOWN) + { + /* Setup the 10/100 Mbps auto-negotiation advertisement register. */ + Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD | + PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL | + PHY_AN_AD_100BASETX_FULL | PHY_AN_AD_100BASETX_HALF; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + + /* Advertise 1000Mbps */ + Value32 = BCM540X_AN_AD_1000BASET_HALF | BCM540X_AN_AD_1000BASET_FULL; + +#if INCLUDE_5701_AX_FIX + /* Bug: workaround for CRC error in gigabit mode when we are in */ + /* slave mode. This will force the PHY to operate in */ + /* master mode. */ + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0) + { + Value32 |= BCM540X_CONFIG_AS_MASTER | + BCM540X_ENABLE_CONFIG_AS_MASTER; + } +#endif + + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, Value32); + pDevice->advertising1000 = Value32; + } + else + { + if(LineSpeed == LM_LINE_SPEED_1000MBPS) + { + Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + + if(DuplexMode != LM_DUPLEX_MODE_FULL) + { + Value32 = BCM540X_AN_AD_1000BASET_HALF; + } + else + { + Value32 = BCM540X_AN_AD_1000BASET_FULL; + } + + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, Value32); + pDevice->advertising1000 = Value32; + } + else if(LineSpeed == LM_LINE_SPEED_100MBPS) + { + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, 0); + pDevice->advertising1000 = 0; + + if(DuplexMode != LM_DUPLEX_MODE_FULL) + { + Value32 = PHY_AN_AD_100BASETX_HALF; + } + else + { + Value32 = PHY_AN_AD_100BASETX_FULL; + } + + Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + } + else if(LineSpeed == LM_LINE_SPEED_10MBPS) + { + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, 0); + pDevice->advertising1000 = 0; + + if(DuplexMode != LM_DUPLEX_MODE_FULL) + { + Value32 = PHY_AN_AD_10BASET_HALF; + } + else + { + Value32 = PHY_AN_AD_10BASET_FULL; + } + + Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + } + } + + /* Force line speed if auto-negotiation is disabled. */ + if(pDevice->DisableAutoNeg && LineSpeed != LM_LINE_SPEED_UNKNOWN) + { + /* This code path is executed only when there is link. */ + pDevice->MediaType = MediaType; + pDevice->LineSpeed = LineSpeed; + pDevice->DuplexMode = DuplexMode; + + /* Force line seepd. */ + NewPhyCtrl = 0; + switch(LineSpeed) + { + case LM_LINE_SPEED_10MBPS: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_10MBPS; + break; + case LM_LINE_SPEED_100MBPS: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_100MBPS; + break; + case LM_LINE_SPEED_1000MBPS: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_1000MBPS; + break; + default: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_1000MBPS; + break; + } + + if(DuplexMode == LM_DUPLEX_MODE_FULL) + { + NewPhyCtrl |= PHY_CTRL_FULL_DUPLEX_MODE; + } + + /* Don't do anything if the PHY_CTRL is already what we wanted. */ + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if(Value32 != NewPhyCtrl) + { + /* Temporary bring the link down before forcing line speed. */ + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_LOOPBACK_MODE); + + /* Wait for link to go down. */ + for(Cnt = 0; Cnt < 15000; Cnt++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + if(!(Value32 & PHY_STATUS_LINK_PASS)) + { + MM_Wait(40); + break; + } + } + + LM_WritePhy(pDevice, PHY_CTRL_REG, NewPhyCtrl); + MM_Wait(40); + } + } + else + { + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_RESTART_AUTO_NEG); + } + + /* Wait for link. */ + LmStatus = LM_STATUS_SUCCESS; + if(WaitForLink) + { + LmStatus = LM_STATUS_LINK_DOWN; + + /* Wait for link up to 3 seconds. */ + for(Cnt = 0; Cnt < 300000; Cnt++) + { + MM_Wait(10); + + /* Get the current PHY status. */ + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + /* Link ok? */ + if(Value32 & PHY_STATUS_LINK_PASS) + { + LmStatus = LM_STATUS_LINK_ACTIVE; + pDevice->MediaType = LM_MEDIA_TYPE_UTP; + + /* Determine the current line and duplex settings. */ + LM_ReadPhy(pDevice, BCM540X_AUX_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, BCM540X_AUX_STATUS_REG, &Value32); + + switch(Value32 & BCM540X_AUX_SPEED_MASK) + { + case BCM540X_AUX_10BASET_HD: + pDevice->LineSpeed = LM_LINE_SPEED_10MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_10BASET_FD: + pDevice->LineSpeed = LM_LINE_SPEED_10MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case BCM540X_AUX_100BASETX_HD: + pDevice->LineSpeed = LM_LINE_SPEED_100MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_100BASETX_FD: + pDevice->LineSpeed = LM_LINE_SPEED_100MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case BCM540X_AUX_100BASET_HD: + pDevice->LineSpeed = LM_LINE_SPEED_1000MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_100BASET_FD: + pDevice->LineSpeed = LM_LINE_SPEED_1000MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_FULL; + break; + + default: + LmStatus = LM_STATUS_LINK_DOWN; + break; + } + + break; + } + } + + /* Acknowledge interrupts. */ + LM_ReadPhy(pDevice, BCM540X_INT_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, BCM540X_INT_STATUS_REG, &Value32); + } + + return LmStatus; +} /* LM_ForceAutoNegBcm540xPhy */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +static LM_STATUS +LM_ForceAutoNeg( +PLM_DEVICE_BLOCK pDevice, +LM_REQUESTED_MEDIA_TYPE RequestedMediaType, +LM_BOOL WaitForLink) { + LM_STATUS LmStatus; + + /* Initialize the phy chip. */ + switch(pDevice->PhyId & PHY_ID_MASK) + { + case PHY_BCM5400_PHY_ID: + case PHY_BCM5401_PHY_ID: + case PHY_BCM5411_PHY_ID: + case PHY_BCM5701_PHY_ID: + case PHY_BCM5703_PHY_ID: + LmStatus = LM_ForceAutoNegBcm540xPhy(pDevice, RequestedMediaType, + WaitForLink); + break; + + default: + LmStatus = LM_STATUS_FAILURE; + break; + } + + return LmStatus; +} /* LM_ForceAutoNeg */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS LM_LoadFirmware(PLM_DEVICE_BLOCK pDevice, + PT3_FWIMG_INFO pFwImg, + LM_UINT32 LoadCpu, + LM_UINT32 StartCpu) +{ + LM_UINT32 i; + LM_UINT32 address; + + if (LoadCpu & T3_RX_CPU_ID) + { + if (LM_HaltCpu(pDevice,T3_RX_CPU_ID) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + /* First of all clear scrach pad memory */ + for (i = 0; i < T3_RX_CPU_SPAD_SIZE; i+=4) + { + LM_RegWrInd(pDevice,T3_RX_CPU_SPAD_ADDR+i,0); + } + + /* Copy code first */ + address = T3_RX_CPU_SPAD_ADDR + (pFwImg->Text.Offset & 0xffff); + for (i = 0; i <= pFwImg->Text.Length; i+=4) + { + LM_RegWrInd(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Text.Buffer)[i/4]); + } + + address = T3_RX_CPU_SPAD_ADDR + (pFwImg->ROnlyData.Offset & 0xffff); + for (i = 0; i <= pFwImg->ROnlyData.Length; i+=4) + { + LM_RegWrInd(pDevice,address+i, + ((LM_UINT32 *)pFwImg->ROnlyData.Buffer)[i/4]); + } + + address = T3_RX_CPU_SPAD_ADDR + (pFwImg->Data.Offset & 0xffff); + for (i= 0; i <= pFwImg->Data.Length; i+=4) + { + LM_RegWrInd(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Data.Buffer)[i/4]); + } + } + + if (LoadCpu & T3_TX_CPU_ID) + { + if (LM_HaltCpu(pDevice,T3_TX_CPU_ID) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + /* First of all clear scrach pad memory */ + for (i = 0; i < T3_TX_CPU_SPAD_SIZE; i+=4) + { + LM_RegWrInd(pDevice,T3_TX_CPU_SPAD_ADDR+i,0); + } + + /* Copy code first */ + address = T3_TX_CPU_SPAD_ADDR + (pFwImg->Text.Offset & 0xffff); + for (i= 0; i <= pFwImg->Text.Length; i+=4) + { + LM_RegWrInd(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Text.Buffer)[i/4]); + } + + address = T3_TX_CPU_SPAD_ADDR + (pFwImg->ROnlyData.Offset & 0xffff); + for (i= 0; i <= pFwImg->ROnlyData.Length; i+=4) + { + LM_RegWrInd(pDevice,address+i, + ((LM_UINT32 *)pFwImg->ROnlyData.Buffer)[i/4]); + } + + address = T3_TX_CPU_SPAD_ADDR + (pFwImg->Data.Offset & 0xffff); + for (i= 0; i <= pFwImg->Data.Length; i+=4) + { + LM_RegWrInd(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Data.Buffer)[i/4]); + } + } + + if (StartCpu & T3_RX_CPU_ID) + { + /* Start Rx CPU */ + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.PC,pFwImg->StartAddress); + for (i = 0 ; i < 5; i++) + { + if (pFwImg->StartAddress == REG_RD(pDevice,rxCpu.reg.PC)) + break; + + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode,CPU_MODE_HALT); + REG_WR(pDevice,rxCpu.reg.PC,pFwImg->StartAddress); + MM_Wait(1000); + } + + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode, 0); + } + + if (StartCpu & T3_TX_CPU_ID) + { + /* Start Tx CPU */ + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.PC,pFwImg->StartAddress); + for (i = 0 ; i < 5; i++) + { + if (pFwImg->StartAddress == REG_RD(pDevice,txCpu.reg.PC)) + break; + + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.mode,CPU_MODE_HALT); + REG_WR(pDevice,txCpu.reg.PC,pFwImg->StartAddress); + MM_Wait(1000); + } + + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.mode, 0); + } + + return LM_STATUS_SUCCESS; +} + +STATIC LM_STATUS LM_HaltCpu(PLM_DEVICE_BLOCK pDevice,LM_UINT32 cpu_number) +{ + LM_UINT32 i; + + if (cpu_number == T3_RX_CPU_ID) + { + for (i = 0 ; i < 10000; i++) + { + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode,CPU_MODE_HALT); + + if (REG_RD(pDevice,rxCpu.reg.mode) & CPU_MODE_HALT) + break; + } + + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode,CPU_MODE_HALT); + MM_Wait(10); + } + else + { + for (i = 0 ; i < 10000; i++) + { + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.mode,CPU_MODE_HALT); + + if (REG_RD(pDevice,txCpu.reg.mode) & CPU_MODE_HALT) + break; + } + } + + return (( i == 10000) ? LM_STATUS_FAILURE : LM_STATUS_SUCCESS); +} + + +int +LM_BlinkLED(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlinkDurationSec) +{ + LM_UINT32 Oldcfg; + int j; + int ret = 0; + + if(BlinkDurationSec == 0) + { + return 0; + } + if(BlinkDurationSec > 120) + { + BlinkDurationSec = 120; + } + + Oldcfg = REG_RD(pDevice, MacCtrl.LedCtrl); + for(j = 0; j < BlinkDurationSec * 2; j++) + { + if(j % 2) + { + // Turn on the LEDs. + REG_WR(pDevice, MacCtrl.LedCtrl, + LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_1000MBPS_LED_ON | + LED_CTRL_100MBPS_LED_ON | + LED_CTRL_10MBPS_LED_ON | + LED_CTRL_OVERRIDE_TRAFFIC_LED | + LED_CTRL_BLINK_TRAFFIC_LED | + LED_CTRL_TRAFFIC_LED); + } + else + { + // Turn off the LEDs. + REG_WR(pDevice, MacCtrl.LedCtrl, + LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_OVERRIDE_TRAFFIC_LED); + } + current->state = TASK_INTERRUPTIBLE; + if (schedule_timeout(HZ/2) != 0) { + ret = -EINTR; + break; + } + } + REG_WR(pDevice, MacCtrl.LedCtrl, Oldcfg); + return ret; +} + +int t3_do_dma(PLM_DEVICE_BLOCK pDevice, + LM_PHYSICAL_ADDRESS host_addr_phy, int length, + int dma_read) +{ + T3_DMA_DESC dma_desc; + int i; + LM_UINT32 dma_desc_addr; + LM_UINT32 value32; + + REG_WR(pDevice, BufMgr.Mode, 0); + REG_WR(pDevice, Ftq.Reset, 0); + + dma_desc.host_addr.High = host_addr_phy.High; + dma_desc.host_addr.Low = host_addr_phy.Low; + dma_desc.nic_mbuf = 0x2100; + dma_desc.len = length; + dma_desc.flags = 0x00000004; /* Generate Rx-CPU event */ + + if (dma_read) + { + dma_desc.cqid_sqid = (T3_QID_RX_BD_COMP << 8) | + T3_QID_DMA_HIGH_PRI_READ; + REG_WR(pDevice, DmaRead.Mode, DMA_READ_MODE_ENABLE); + } + else + { + dma_desc.cqid_sqid = (T3_QID_RX_DATA_COMP << 8) | + T3_QID_DMA_HIGH_PRI_WRITE; + REG_WR(pDevice, DmaWrite.Mode, DMA_WRITE_MODE_ENABLE); + } + + dma_desc_addr = T3_NIC_DMA_DESC_POOL_ADDR; + + /* Writing this DMA descriptor to DMA memory */ + for (i = 0; i < sizeof(T3_DMA_DESC); i += 4) + { + value32 = *((PLM_UINT32) (((PLM_UINT8) &dma_desc) + i)); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, dma_desc_addr+i); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_DATA_REG, cpu_to_le32(value32)); + } + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, 0); + + if (dma_read) + REG_WR(pDevice, Ftq.DmaHighReadFtqFifoEnqueueDequeue, dma_desc_addr); + else + REG_WR(pDevice, Ftq.DmaHighWriteFtqFifoEnqueueDequeue, dma_desc_addr); + + for (i = 0; i < 40; i++) + { + if (dma_read) + value32 = REG_RD(pDevice, Ftq.RcvBdCompFtqFifoEnqueueDequeue); + else + value32 = REG_RD(pDevice, Ftq.RcvDataCompFtqFifoEnqueueDequeue); + + if ((value32 & 0xffff) == dma_desc_addr) + break; + + MM_Wait(10); + } + + return LM_STATUS_SUCCESS; +} + +STATIC LM_STATUS +LM_DmaTest(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pBufferVirt, + LM_PHYSICAL_ADDRESS BufferPhy, LM_UINT32 BufferSize) +{ + int j; + LM_UINT32 *ptr; + int dma_success = 0; + LM_STATUS ret = LM_STATUS_FAILURE; + + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && + T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701) + { + return LM_STATUS_SUCCESS; + } + while (!dma_success) + { + /* Fill data with incremental patterns */ + ptr = (LM_UINT32 *)pBufferVirt; + for (j = 0; j < BufferSize/4; j++) + *ptr++ = j; + + if (t3_do_dma(pDevice,BufferPhy,BufferSize, 1) == LM_STATUS_FAILURE) + { + goto LM_DmaTestDone; + } + + MM_Wait(40); + ptr = (LM_UINT32 *)pBufferVirt; + /* Fill data with zero */ + for (j = 0; j < BufferSize/4; j++) + *ptr++ = 0; + + if (t3_do_dma(pDevice,BufferPhy,BufferSize, 0) == LM_STATUS_FAILURE) + { + goto LM_DmaTestDone; + } + + MM_Wait(40); + /* Check for data */ + ptr = (LM_UINT32 *)pBufferVirt; + for (j = 0; j < BufferSize/4; j++) + { + if (*ptr++ != j) + { + if ((pDevice->DmaReadWriteCtrl & DMA_CTRL_WRITE_BOUNDARY_MASK) + == DMA_CTRL_WRITE_BOUNDARY_DISABLE) + { + pDevice->DmaReadWriteCtrl = (pDevice->DmaReadWriteCtrl & + ~DMA_CTRL_WRITE_BOUNDARY_MASK) | + DMA_CTRL_WRITE_BOUNDARY_16; + REG_WR(pDevice, PciCfg.DmaReadWriteCtrl, + pDevice->DmaReadWriteCtrl); + break; + } + else + { + goto LM_DmaTestDone; + } + } + } + if (j == (BufferSize/4)) + dma_success = 1; + } + ret = LM_STATUS_SUCCESS; +LM_DmaTestDone: + memset(pBufferVirt, 0, BufferSize); + return ret; +} + diff -Nur linux-2.4.19/drivers/net/bcm/tigon3.h linux-2.4.19-sgi211r3/drivers/net/bcm/tigon3.h --- linux-2.4.19/drivers/net/bcm/tigon3.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/bcm/tigon3.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,3402 @@ + +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* */ +/******************************************************************************/ + +#ifndef TIGON3_H +#define TIGON3_H + +#include "lm.h" +#if INCLUDE_TBI_SUPPORT +#include "autoneg.h" +#endif + + + +/******************************************************************************/ +/* Constants. */ +/******************************************************************************/ + +/* Maxim number of packet descriptors used for sending packets. */ +#define MAX_TX_PACKET_DESC_COUNT 600 +#define DEFAULT_TX_PACKET_DESC_COUNT 100 + +/* Maximum number of packet descriptors used for receiving packets. */ +#if T3_JUMBO_RCB_ENTRY_COUNT +#define MAX_RX_PACKET_DESC_COUNT \ + (T3_STD_RCV_RCB_ENTRY_COUNT + T3_JUMBO_RCV_RCB_ENTRY_COUNT) +#else +#define MAX_RX_PACKET_DESC_COUNT 800 +#endif +#define DEFAULT_RX_PACKET_DESC_COUNT 200 + +/* Threshhold for double copying small tx packets. 0 will disable double */ +/* copying of small Tx packets. */ +#define DEFAULT_TX_COPY_BUFFER_SIZE 0 +#define MIN_TX_COPY_BUFFER_SIZE 64 +#define MAX_TX_COPY_BUFFER_SIZE 512 + +/* Cache line. */ +#define COMMON_CACHE_LINE_SIZE 0x20 +#define COMMON_CACHE_LINE_MASK (COMMON_CACHE_LINE_SIZE-1) + +/* Maximum number of fragment we can handle. */ +#ifndef MAX_FRAGMENT_COUNT +#define MAX_FRAGMENT_COUNT 32 +#endif + +/* B0 bug. */ +#define BCM5700_BX_MIN_FRAG_SIZE 10 +#define BCM5700_BX_MIN_FRAG_BUF_SIZE 16 /* nice aligned size. */ +#define BCM5700_BX_MIN_FRAG_BUF_SIZE_MASK (BCM5700_BX_MIN_FRAG_BUF_SIZE-1) +#define BCM5700_BX_TX_COPY_BUF_SIZE (BCM5700_BX_MIN_FRAG_BUF_SIZE * \ + MAX_FRAGMENT_COUNT) + +/* MAGIC number. */ +//#define T3_MAGIC_NUM 'KevT' +#define T3_FIRMWARE_MAILBOX 0x0b50 +#define T3_MAGIC_NUM 0x4B657654 +#define T3_MAGIC_NUM_DISABLE_DMAW_ON_LINK_CHANGE 0x4861764b + +#define T3_NIC_DATA_SIG_ADDR 0x0b54 +#define T3_NIC_DATA_SIG 0x4b657654 + +#define T3_NIC_DATA_NIC_CFG_ADDR 0x0b58 +#define T3_NIC_CFG_LED_MODE_UNKNOWN BIT_NONE +#define T3_NIC_CFG_LED_MODE_TRIPLE_SPEED BIT_2 +#define T3_NIC_CFG_LED_MODE_LINK_SPEED BIT_3 +#define T3_NIC_CFG_LED_MODE_OPEN_DRAIN BIT_2 +#define T3_NIC_CFG_LED_MODE_OUTPUT BIT_3 +#define T3_NIC_CFG_LED_MODE_MASK (BIT_2 | BIT_3) +#define T3_NIC_CFG_PHY_TYPE_UNKNOWN BIT_NONE +#define T3_NIC_CFG_PHY_TYPE_COPPER BIT_4 +#define T3_NIC_CFG_PHY_TYPE_FIBER BIT_5 +#define T3_NIC_CFG_PHY_TYPE_MASK (BIT_4 | BIT_5) +#define T3_NIC_CFG_ENABLE_WOL BIT_6 +#define T3_NIC_CFG_ENABLE_ASF BIT_7 +#define T3_NIC_EEPROM_WP BIT_8 + +#define T3_NIC_DATA_PHY_ID_ADDR 0x0b74 +#define T3_NIC_PHY_ID1_MASK 0xffff0000 +#define T3_NIC_PHY_ID2_MASK 0x0000ffff + +#define T3_CMD_MAILBOX 0x0b78 +#define T3_CMD_NICDRV_ALIVE 0x01 +#define T3_CMD_NICDRV_PAUSE_FW 0x02 +#define T3_CMD_NICDRV_IPV4ADDR_CHANGE 0x03 +#define T3_CMD_NICDRV_IPV6ADDR_CHANGE 0x04 +#define T3_CMD_5703A0_FIX_DMAFW_DMAR 0x05 +#define T3_CMD_5703A0_FIX_DMAFW_DMAW 0x06 + +#define T3_CMD_LENGTH_MAILBOX 0x0b7c +#define T3_CMD_DATA_MAILBOX 0x0b80 + +#define T3_ASF_FW_STATUS_MAILBOX 0x0c00 + +#define T3_DRV_STATE_MAILBOX 0x0c04 +#define T3_DRV_STATE_START 0x01 +#define T3_DRV_STATE_UNLOAD 0x02 +#define T3_DRV_STATE_WOL 0x03 +#define T3_DRV_STATE_SUSPEND 0x04 + +#define T3_FW_RESET_TYPE_MAILBOX 0x0c08 + +#define T3_MAC_ADDR_HIGH_MAILBOX 0x0c14 +#define T3_MAC_ADDR_LOW_MAILBOX 0x0c18 + +/******************************************************************************/ +/* Hardware constants. */ +/******************************************************************************/ + +/* Number of entries in the send ring: must be 512. */ +#define T3_SEND_RCB_ENTRY_COUNT 512 +#define T3_SEND_RCB_ENTRY_COUNT_MASK (T3_SEND_RCB_ENTRY_COUNT-1) + +/* Number of send RCBs. May be 1-16 but for now, only support one. */ +#define T3_MAX_SEND_RCB_COUNT 16 + +/* Number of entries in the Standard Receive RCB. Must be 512 entries. */ +#define T3_STD_RCV_RCB_ENTRY_COUNT 512 +#define T3_STD_RCV_RCB_ENTRY_COUNT_MASK (T3_STD_RCV_RCB_ENTRY_COUNT-1) +#define DEFAULT_STD_RCV_DESC_COUNT 200 /* Must be < 512. */ +#define MAX_STD_RCV_BUFFER_SIZE 0x600 + +/* Number of entries in the Mini Receive RCB. This value can either be */ +/* 0, 1024. Currently Mini Receive RCB is disabled. */ +#ifndef T3_MINI_RCV_RCB_ENTRY_COUNT +#define T3_MINI_RCV_RCB_ENTRY_COUNT 0 +#endif /* T3_MINI_RCV_RCB_ENTRY_COUNT */ +#define T3_MINI_RCV_RCB_ENTRY_COUNT_MASK (T3_MINI_RCV_RCB_ENTRY_COUNT-1) +#define MAX_MINI_RCV_BUFFER_SIZE 512 +#define DEFAULT_MINI_RCV_BUFFER_SIZE 64 +#define DEFAULT_MINI_RCV_DESC_COUNT 100 /* Must be < 1024. */ + +/* Number of entries in the Jumbo Receive RCB. This value must 256 or 0. */ +/* Currently, Jumbo Receive RCB is disabled. */ +#ifndef T3_JUMBO_RCV_RCB_ENTRY_COUNT +#define T3_JUMBO_RCV_RCB_ENTRY_COUNT 0 +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ +#define T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK (T3_JUMBO_RCV_RCB_ENTRY_COUNT-1) + +#define MAX_JUMBO_RCV_BUFFER_SIZE (10 * 1024) /* > 1514 */ +#define DEFAULT_JUMBO_RCV_BUFFER_SIZE (4 * 1024) /* > 1514 */ +#define DEFAULT_JUMBO_RCV_DESC_COUNT 128 /* Must be < 256. */ + +#define MAX_JUMBO_TX_BUFFER_SIZE (8 * 1024) /* > 1514 */ +#define DEFAULT_JUMBO_TX_BUFFER_SIZE (4 * 1024) /* > 1514 */ + +/* Number of receive return RCBs. Maybe 1-16 but for now, only support one. */ +#define T3_MAX_RCV_RETURN_RCB_COUNT 16 + +/* Number of entries in a Receive Return ring. This value is either 1024 */ +/* or 2048. */ +#ifndef T3_RCV_RETURN_RCB_ENTRY_COUNT +#define T3_RCV_RETURN_RCB_ENTRY_COUNT 1024 +#endif /* T3_RCV_RETURN_RCB_ENTRY_COUNT */ +#define T3_RCV_RETURN_RCB_ENTRY_COUNT_MASK (T3_RCV_RETURN_RCB_ENTRY_COUNT-1) + + +/* Default coalescing parameters. */ +#define DEFAULT_RX_COALESCING_TICKS 100 +#define MAX_RX_COALESCING_TICKS 500 +#define DEFAULT_TX_COALESCING_TICKS 400 +#define MAX_TX_COALESCING_TICKS 500 +#define DEFAULT_RX_MAX_COALESCED_FRAMES 10 +#define MAX_RX_MAX_COALESCED_FRAMES 100 +#define ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES 5 +#define ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES 42 +#define ADAPTIVE_LO_RX_COALESCING_TICKS 50 +#define ADAPTIVE_HI_RX_COALESCING_TICKS 300 +#define ADAPTIVE_LO_PKT_THRESH 30000 +#define ADAPTIVE_HI_PKT_THRESH 74000 +#define DEFAULT_TX_MAX_COALESCED_FRAMES 40 +#define ADAPTIVE_LO_TX_MAX_COALESCED_FRAMES 25 +#define ADAPTIVE_HI_TX_MAX_COALESCED_FRAMES 75 +#define MAX_TX_MAX_COALESCED_FRAMES 100 + +#define DEFAULT_RX_COALESCING_TICKS_DURING_INT 25 +#define DEFAULT_TX_COALESCING_TICKS_DURING_INT 25 +#define DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT 5 +#define DEFAULT_TX_MAX_COALESCED_FRAMES_DURING_INT 5 + +#define BAD_DEFAULT_VALUE 0xffffffff + +#define DEFAULT_STATS_COALESCING_TICKS 1000000 +#define MAX_STATS_COALESCING_TICKS 3600000000U + + +/* Receive BD Replenish thresholds. */ +#define DEFAULT_RCV_STD_BD_REPLENISH_THRESHOLD 4 +#define DEFAULT_RCV_JUMBO_BD_REPLENISH_THRESHOLD 4 + + +/* Maximum physical fragment size. */ +#define MAX_FRAGMENT_SIZE (64 * 1024) + + +/* Standard view. */ +#define T3_STD_VIEW_SIZE (64 * 1024) +#define T3_FLAT_VIEW_SIZE (32 * 1024 * 1024) + + +/* Buffer descriptor base address on the NIC's memory. */ + +#define T3_NIC_SND_BUFFER_DESC_ADDR 0x4000 +#define T3_NIC_STD_RCV_BUFFER_DESC_ADDR 0x6000 +#define T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR 0x7000 + +#define T3_NIC_STD_RCV_BUFFER_DESC_ADDR_EXT_MEM 0xc000 +#define T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR_EXT_MEM 0xd000 +#define T3_NIC_MINI_RCV_BUFFER_DESC_ADDR_EXT_MEM 0xe000 + +#define T3_NIC_SND_BUFFER_DESC_SIZE (T3_SEND_RCB_ENTRY_COUNT * \ + sizeof(T3_SND_BD) / 4) + +#define T3_NIC_STD_RCV_BUFFER_DESC_SIZE (T3_STD_RCV_RCB_ENTRY_COUNT * \ + sizeof(T3_RCV_BD) / 4) + +#define T3_NIC_JUMBO_RCV_BUFFER_DESC_SIZE (T3_JUMBO_RCV_RCB_ENTRY_COUNT * \ + sizeof(T3_EXT_RCV_BD) / 4) + + +/* MBUF pool. */ +#define T3_NIC_MBUF_POOL_ADDR 0x8000 +#define T3_NIC_MBUF_POOL_SIZE 0x18000 + +#define T3_NIC_MBUF_POOL_ADDR_EXT_MEM 0x20000 + +/* DMA descriptor pool */ +#define T3_NIC_DMA_DESC_POOL_ADDR 0x2000 +#define T3_NIC_DMA_DESC_POOL_SIZE 0x2000 /* 8KB. */ + +#define T3_DEF_DMA_MBUF_LOW_WMARK 0x40 +#define T3_DEF_RX_MAC_MBUF_LOW_WMARK 0x20 +#define T3_DEF_MBUF_HIGH_WMARK 0x60 + +#define T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO 304 +#define T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO 152 +#define T3_DEF_MBUF_HIGH_WMARK_JUMBO 380 + +#define T3_DEF_DMA_DESC_LOW_WMARK 5 +#define T3_DEF_DMA_DESC_HIGH_WMARK 10 + +/* Maximum size of giant TCP packet can be sent */ +#define T3_TCP_SEG_MAX_OFFLOAD_SIZE 64*1000 +#define T3_TCP_SEG_MIN_NUM_SEG 20 + +#define T3_RX_CPU_ID 0x1 +#define T3_TX_CPU_ID 0x2 +#define T3_RX_CPU_SPAD_ADDR 0x30000 +#define T3_RX_CPU_SPAD_SIZE 0x4000 +#define T3_TX_CPU_SPAD_ADDR 0x34000 +#define T3_TX_CPU_SPAD_SIZE 0x4000 + +typedef struct T3_DIR_ENTRY +{ + PLM_UINT8 Buffer; + LM_UINT32 Offset; + LM_UINT32 Length; +} T3_DIR_ENTRY,*PT3_DIR_ENTRY; + +typedef struct T3_FWIMG_INFO +{ + LM_UINT32 StartAddress; + T3_DIR_ENTRY Text; + T3_DIR_ENTRY ROnlyData; + T3_DIR_ENTRY Data; + T3_DIR_ENTRY Sbss; + T3_DIR_ENTRY Bss; +} T3_FWIMG_INFO, *PT3_FWIMG_INFO; + + + +/******************************************************************************/ +/* Tigon3 PCI Registers. */ +/******************************************************************************/ +#define T3_PCI_ID_BCM5700 0x164414e4 +#define T3_PCI_ID_BCM5701 0x164514e4 +#define T3_PCI_ID_BCM5702 0x164614e4 +#define T3_PCI_ID_BCM5702x 0x16A614e4 +#define T3_PCI_ID_BCM5703 0x164714e4 +#define T3_PCI_ID_BCM5703x 0x16A714e4 +#define T3_PCI_ID_BCM5702FE 0x164D14e4 + +#define T3_PCI_VENDOR_ID (T3_PCI_ID & 0xffff) +#define T3_PCI_DEVICE_ID (T3_PCI_ID >> 16) + +#define T3_PCI_MISC_HOST_CTRL_REG 0x68 + +/* The most significant 16bit of register 0x68. */ +/* ChipId:4, ChipRev:4, MetalRev:8 */ +#define T3_CHIP_ID_5700_A0 0x7000 +#define T3_CHIP_ID_5700_A1 0x7001 +#define T3_CHIP_ID_5700_B0 0x7100 +#define T3_CHIP_ID_5700_B1 0x7101 +#define T3_CHIP_ID_5700_C0 0x7200 + +#define T3_CHIP_ID_5701_A0 0x0000 +#define T3_CHIP_ID_5701_B0 0x0100 +#define T3_CHIP_ID_5701_B2 0x0102 +#define T3_CHIP_ID_5701_B5 0x0105 + +#define T3_CHIP_ID_5703_A0 0x1000 +#define T3_CHIP_ID_5703_A1 0x1001 +#define T3_CHIP_ID_5703_A2 0x1002 + +/* Chip Id. */ +#define T3_ASIC_REV(_ChipRevId) ((_ChipRevId) >> 12) +#define T3_ASIC_REV_5700 0x07 +#define T3_ASIC_REV_5701 0x00 +#define T3_ASIC_REV_5703 0x01 + +/* Chip id and revision. */ +#define T3_CHIP_REV(_ChipRevId) ((_ChipRevId) >> 8) +#define T3_CHIP_REV_5700_AX 0x70 +#define T3_CHIP_REV_5700_BX 0x71 +#define T3_CHIP_REV_5700_CX 0x72 +#define T3_CHIP_REV_5701_AX 0x00 + +/* Metal revision. */ +#define T3_METAL_REV(_ChipRevId) ((_ChipRevId) & 0xff) +#define T3_METAL_REV_A0 0x00 +#define T3_METAL_REV_A1 0x01 +#define T3_METAL_REV_B0 0x00 +#define T3_METAL_REV_B1 0x01 +#define T3_METAL_REV_B2 0x02 + +#define T3_PCI_REG_CLOCK_CTRL 0x74 + +#define T3_PCI_DISABLE_RX_CLOCK BIT_10 +#define T3_PCI_DISABLE_TX_CLOCK BIT_11 +#define T3_PCI_SELECT_ALTERNATE_CLOCK BIT_12 +#define T3_PCI_POWER_DOWN_PCI_PLL133 BIT_15 +#define T3_PCI_44MHZ_CORE_CLOCK BIT_18 + + +#define T3_PCI_REG_ADDR_REG 0x78 +#define T3_PCI_REG_DATA_REG 0x80 + +#define T3_PCI_MEM_WIN_ADDR_REG 0x7c +#define T3_PCI_MEM_WIN_DATA_REG 0x84 + +#define T3_PCI_PM_CAP_REG 0x48 + +#define T3_PCI_PM_CAP_PME_D3COLD BIT_31 +#define T3_PCI_PM_CAP_PME_D3HOT BIT_30 + +#define T3_PCI_PM_STATUS_CTRL_REG 0x4c + +#define T3_PM_POWER_STATE_MASK (BIT_0 | BIT_1) +#define T3_PM_POWER_STATE_D0 BIT_NONE +#define T3_PM_POWER_STATE_D1 BIT_0 +#define T3_PM_POWER_STATE_D2 BIT_1 +#define T3_PM_POWER_STATE_D3 (BIT_0 | BIT_1) + +#define T3_PM_PME_ENABLE BIT_8 +#define T3_PM_PME_ASSERTED BIT_15 + + +/* PCI state register. */ +#define T3_PCI_STATE_REG 0x70 + +#define T3_PCI_STATE_FORCE_RESET BIT_0 +#define T3_PCI_STATE_INT_NOT_ACTIVE BIT_1 +#define T3_PCI_STATE_CONVENTIONAL_PCI_MODE BIT_2 +#define T3_PCI_STATE_BUS_SPEED_HIGH BIT_3 +#define T3_PCI_STATE_32BIT_PCI_BUS BIT_4 + + +/* Broadcom subsystem/subvendor IDs. */ +#define T3_SVID_BROADCOM 0x14e4 + +#define T3_SSID_BROADCOM_BCM95700A6 0x1644 +#define T3_SSID_BROADCOM_BCM95701A5 0x0001 +#define T3_SSID_BROADCOM_BCM95700T6 0x0002 /* BCM8002 */ +#define T3_SSID_BROADCOM_BCM95700A9 0x0003 /* Agilent */ +#define T3_SSID_BROADCOM_BCM95701T1 0x0005 +#define T3_SSID_BROADCOM_BCM95701T8 0x0006 +#define T3_SSID_BROADCOM_BCM95701A7 0x0007 /* Agilent */ +#define T3_SSID_BROADCOM_BCM95701A10 0x0008 +#define T3_SSID_BROADCOM_BCM95701A12 0x8008 +#define T3_SSID_BROADCOM_BCM95703Ax1 0x0009 +#define T3_SSID_BROADCOM_BCM95703Ax2 0x8009 + +/* 3COM subsystem/subvendor IDs. */ +#define T3_SVID_3COM 0x10b7 + +#define T3_SSID_3COM_3C996T 0x1000 +#define T3_SSID_3COM_3C996BT 0x1006 +#define T3_SSID_3COM_3C996CT 0x1002 +#define T3_SSID_3COM_3C997T 0x1003 +#define T3_SSID_3COM_3C1000T 0x1007 +#define T3_SSID_3COM_3C940BR01 0x1008 + +/* Fiber boards. */ +#define T3_SSID_3COM_3C996SX 0x1004 +#define T3_SSID_3COM_3C997SX 0x1005 + + +/* Dell subsystem/subvendor IDs. */ + +#define T3_SVID_DELL 0x1028 + +#define T3_SSID_DELL_VIPER 0x00d1 +#define T3_SSID_DELL_JAGUAR 0x0106 +#define T3_SSID_DELL_MERLOT 0x0109 +#define T3_SSID_DELL_SLIM_MERLOT 0x010a + +/* Compaq subsystem/subvendor IDs */ + +#define T3_SVID_COMPAQ 0x0e11 + +#define T3_SSID_COMPAQ_BANSHEE 0x007c +#define T3_SSID_COMPAQ_BANSHEE_2 0x009a +#define T3_SSID_COMPAQ_CHANGELING 0x007d +#define T3_SSID_COMPAQ_NC7780 0x0085 +#define T3_SSID_COMPAQ_NC7780_2 0x0099 + + +/******************************************************************************/ +/* MII registers. */ +/******************************************************************************/ + +/* Control register. */ +#define PHY_CTRL_REG 0x00 + +#define PHY_CTRL_SPEED_MASK (BIT_6 | BIT_13) +#define PHY_CTRL_SPEED_SELECT_10MBPS BIT_NONE +#define PHY_CTRL_SPEED_SELECT_100MBPS BIT_13 +#define PHY_CTRL_SPEED_SELECT_1000MBPS BIT_6 +#define PHY_CTRL_COLLISION_TEST_ENABLE BIT_7 +#define PHY_CTRL_FULL_DUPLEX_MODE BIT_8 +#define PHY_CTRL_RESTART_AUTO_NEG BIT_9 +#define PHY_CTRL_ISOLATE_PHY BIT_10 +#define PHY_CTRL_LOWER_POWER_MODE BIT_11 +#define PHY_CTRL_AUTO_NEG_ENABLE BIT_12 +#define PHY_CTRL_LOOPBACK_MODE BIT_14 +#define PHY_CTRL_PHY_RESET BIT_15 + + +/* Status register. */ +#define PHY_STATUS_REG 0x01 + +#define PHY_STATUS_LINK_PASS BIT_2 +#define PHY_STATUS_AUTO_NEG_COMPLETE BIT_5 + + +/* Phy Id registers. */ +#define PHY_ID1_REG 0x02 +#define PHY_ID1_OUI_MASK 0xffff + +#define PHY_ID2_REG 0x03 +#define PHY_ID2_REV_MASK 0x000f +#define PHY_ID2_MODEL_MASK 0x03f0 +#define PHY_ID2_OUI_MASK 0xfc00 + + +/* Auto-negotiation advertisement register. */ +#define PHY_AN_AD_REG 0x04 + +#define PHY_AN_AD_ASYM_PAUSE BIT_11 +#define PHY_AN_AD_PAUSE_CAPABLE BIT_10 +#define PHY_AN_AD_10BASET_HALF BIT_5 +#define PHY_AN_AD_10BASET_FULL BIT_6 +#define PHY_AN_AD_100BASETX_HALF BIT_7 +#define PHY_AN_AD_100BASETX_FULL BIT_8 +#define PHY_AN_AD_PROTOCOL_802_3_CSMA_CD 0x01 + + +/* Auto-negotiation Link Partner Ability register. */ +#define PHY_LINK_PARTNER_ABILITY_REG 0x05 + +#define PHY_LINK_PARTNER_ASYM_PAUSE BIT_11 +#define PHY_LINK_PARTNER_PAUSE_CAPABLE BIT_10 + + +/* Auto-negotiation expansion register. */ +#define PHY_AN_EXPANSION_REG 0x06 + + + +/******************************************************************************/ +/* BCM5400 and BCM5401 phy info. */ +/******************************************************************************/ + +#define PHY_DEVICE_ID 1 + +/* OUI: bit 31-10; Model#: bit 9-4; Rev# bit 3-0. */ +#define PHY_UNKNOWN_PHY 0x00000000 +#define PHY_BCM5400_PHY_ID 0x60008040 +#define PHY_BCM5401_PHY_ID 0x60008050 +#define PHY_BCM5411_PHY_ID 0x60008070 +#define PHY_BCM5701_PHY_ID 0x60008110 +#define PHY_BCM5703_PHY_ID 0x60008160 +#define PHY_BCM8002_PHY_ID 0x60010140 + +#define PHY_BCM5401_B0_REV 0x1 +#define PHY_BCM5401_B2_REV 0x3 +#define PHY_BCM5401_C0_REV 0x6 + +#define PHY_ID_OUI_MASK 0xfffffc00 +#define PHY_ID_MODEL_MASK 0x000003f0 +#define PHY_ID_REV_MASK 0x0000000f +#define PHY_ID_MASK (PHY_ID_OUI_MASK | \ + PHY_ID_MODEL_MASK) + + +#define UNKNOWN_PHY_ID(x) ((((x) & PHY_ID_MASK) != PHY_BCM5400_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5401_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5411_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5701_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5703_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM8002_PHY_ID)) + + + +/* 1000Base-T control register. */ +#define BCM540X_1000BASET_CTRL_REG 0x09 + +#define BCM540X_AN_AD_1000BASET_HALF BIT_8 +#define BCM540X_AN_AD_1000BASET_FULL BIT_9 +#define BCM540X_CONFIG_AS_MASTER BIT_11 +#define BCM540X_ENABLE_CONFIG_AS_MASTER BIT_12 + + +/* Extended control register. */ +#define BCM540X_EXT_CTRL_REG 0x10 + +#define BCM540X_EXT_CTRL_LINK3_LED_MODE BIT_1 +#define BCM540X_EXT_CTRL_TBI BIT_15 + +/* PHY extended status register. */ +#define BCM540X_EXT_STATUS_REG 0x11 + +#define BCM540X_EXT_STATUS_LINK_PASS BIT_8 + + +/* DSP Coefficient Read/Write Port. */ +#define BCM540X_DSP_RW_PORT 0x15 + + +/* DSP Coeficient Address Register. */ +#define BCM540X_DSP_ADDRESS_REG 0x17 + +#define BCM540X_DSP_TAP_NUMBER_MASK 0x00 +#define BCM540X_DSP_AGC_A 0x00 +#define BCM540X_DSP_AGC_B 0x01 +#define BCM540X_DSP_MSE_PAIR_STATUS 0x02 +#define BCM540X_DSP_SOFT_DECISION 0x03 +#define BCM540X_DSP_PHASE_REG 0x04 +#define BCM540X_DSP_SKEW 0x05 +#define BCM540X_DSP_POWER_SAVER_UPPER_BOUND 0x06 +#define BCM540X_DSP_POWER_SAVER_LOWER_BOUND 0x07 +#define BCM540X_DSP_LAST_ECHO 0x08 +#define BCM540X_DSP_FREQUENCY 0x09 +#define BCM540X_DSP_PLL_BANDWIDTH 0x0a +#define BCM540X_DSP_PLL_PHASE_OFFSET 0x0b + +#define BCM540X_DSP_FILTER_DCOFFSET (BIT_10 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT3 (BIT_8 | BIT_9 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT2 (BIT_9 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT1 (BIT_8 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT0 BIT_11 +#define BCM540X_DSP_FILTER_NEXT3 (BIT_8 | BIT_9 | BIT_10) +#define BCM540X_DSP_FILTER_NEXT2 (BIT_9 | BIT_10) +#define BCM540X_DSP_FILTER_NEXT1 (BIT_8 | BIT_10) +#define BCM540X_DSP_FILTER_NEXT0 BIT_10 +#define BCM540X_DSP_FILTER_ECHO (BIT_8 | BIT_9) +#define BCM540X_DSP_FILTER_DFE BIT_9 +#define BCM540X_DSP_FILTER_FFE BIT_8 + +#define BCM540X_DSP_CONTROL_ALL_FILTERS BIT_12 + +#define BCM540X_DSP_SEL_CH_0 BIT_NONE +#define BCM540X_DSP_SEL_CH_1 BIT_13 +#define BCM540X_DSP_SEL_CH_2 BIT_14 +#define BCM540X_DSP_SEL_CH_3 (BIT_13 | BIT_14) + +#define BCM540X_CONTROL_ALL_CHANNELS BIT_15 + + +/* Auxilliary Control Register (Shadow Register) */ +#define BCM5401_AUX_CTRL 0x18 + +#define BCM5401_SHADOW_SEL_MASK 0x7 +#define BCM5401_SHADOW_SEL_NORMAL 0x00 +#define BCM5401_SHADOW_SEL_10BASET 0x01 +#define BCM5401_SHADOW_SEL_POWER_CONTROL 0x02 +#define BCM5401_SHADOW_SEL_IP_PHONE 0x03 +#define BCM5401_SHADOW_SEL_MISC_TEST1 0x04 +#define BCM5401_SHADOW_SEL_MISC_TEST2 0x05 +#define BCM5401_SHADOW_SEL_IP_PHONE_SEED 0x06 + + +/* Shadow register selector == '000' */ +#define BCM5401_SHDW_NORMAL_DIAG_MODE BIT_3 +#define BCM5401_SHDW_NORMAL_DISABLE_MBP BIT_4 +#define BCM5401_SHDW_NORMAL_DISABLE_LOW_PWR BIT_5 +#define BCM5401_SHDW_NORMAL_DISABLE_INV_PRF BIT_6 +#define BCM5401_SHDW_NORMAL_DISABLE_PRF BIT_7 +#define BCM5401_SHDW_NORMAL_RX_SLICING_NORMAL BIT_NONE +#define BCM5401_SHDW_NORMAL_RX_SLICING_4D BIT_8 +#define BCM5401_SHDW_NORMAL_RX_SLICING_3LVL_1D BIT_9 +#define BCM5401_SHDW_NORMAL_RX_SLICING_5LVL_1D (BIT_8 | BIT_9) +#define BCM5401_SHDW_NORMAL_TX_6DB_CODING BIT_10 +#define BCM5401_SHDW_NORMAL_ENABLE_SM_DSP_CLOCK BIT_11 +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_4NS BIT_NONE +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_5NS BIT_12 +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_3NS BIT_13 +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_0NS (BIT_12 | BIT_13) +#define BCM5401_SHDW_NORMAL_EXT_PACKET_LENGTH BIT_14 +#define BCM5401_SHDW_NORMAL_EXTERNAL_LOOPBACK BIT_15 + + +/* Auxilliary status summary. */ +#define BCM540X_AUX_STATUS_REG 0x19 + +#define BCM540X_AUX_LINK_PASS BIT_2 +#define BCM540X_AUX_SPEED_MASK (BIT_8 | BIT_9 | BIT_10) +#define BCM540X_AUX_10BASET_HD BIT_8 +#define BCM540X_AUX_10BASET_FD BIT_9 +#define BCM540X_AUX_100BASETX_HD (BIT_8 | BIT_9) +#define BCM540X_AUX_100BASET4 BIT_10 +#define BCM540X_AUX_100BASETX_FD (BIT_8 | BIT_10) +#define BCM540X_AUX_100BASET_HD (BIT_9 | BIT_10) +#define BCM540X_AUX_100BASET_FD (BIT_8 | BIT_9 | BIT_10) + + +/* Interrupt status. */ +#define BCM540X_INT_STATUS_REG 0x1a + +#define BCM540X_INT_LINK_CHANGE BIT_1 +#define BCM540X_INT_SPEED_CHANGE BIT_2 +#define BCM540X_INT_DUPLEX_CHANGE BIT_3 +#define BCM540X_INT_AUTO_NEG_PAGE_RX BIT_10 + + +/* Interrupt mask register. */ +#define BCM540X_INT_MASK_REG 0x1b + + + +/******************************************************************************/ +/* Register definitions. */ +/******************************************************************************/ + +typedef volatile LM_UINT8 T3_8BIT_REGISTER, *PT3_8BIT_REGISTER; +typedef volatile LM_UINT16 T3_16BIT_REGISTER, *PT3_16BIT_REGISTER; +typedef volatile LM_UINT32 T3_32BIT_REGISTER, *PT3_32BIT_REGISTER; + +typedef struct { + /* Big endian format. */ + T3_32BIT_REGISTER High; + T3_32BIT_REGISTER Low; +} T3_64BIT_REGISTER, *PT3_64BIT_REGISTER; + +typedef T3_64BIT_REGISTER T3_64BIT_HOST_ADDR, *PT3_64BIT_HOST_ADDR; + +#define T3_NUM_OF_DMA_DESC 256 +#define T3_NUM_OF_MBUF 768 + +typedef struct +{ + T3_64BIT_REGISTER host_addr; + T3_32BIT_REGISTER nic_mbuf; + T3_16BIT_REGISTER len; + T3_16BIT_REGISTER cqid_sqid; + T3_32BIT_REGISTER flags; + T3_32BIT_REGISTER opaque1; + T3_32BIT_REGISTER opaque2; + T3_32BIT_REGISTER opaque3; +}T3_DMA_DESC, *PT3_DMA_DESC; + + + +/******************************************************************************/ +/* Ring control block. */ +/******************************************************************************/ + +typedef struct { + T3_64BIT_REGISTER HostRingAddr; + + union { + struct { +#ifdef BIG_ENDIAN_HOST + T3_16BIT_REGISTER MaxLen; + T3_16BIT_REGISTER Flags; +#else /* BIG_ENDIAN_HOST */ + T3_16BIT_REGISTER Flags; + T3_16BIT_REGISTER MaxLen; +#endif + } s; + + T3_32BIT_REGISTER MaxLen_Flags; + } u; + + T3_32BIT_REGISTER NicRingAddr; +} T3_RCB, *PT3_RCB; + +#define T3_RCB_FLAG_USE_EXT_RECV_BD BIT_0 +#define T3_RCB_FLAG_RING_DISABLED BIT_1 + + + +/******************************************************************************/ +/* Status block. */ +/******************************************************************************/ + +/* + * Size of status block is actually 0x50 bytes. Use 0x80 bytes for + * cache line alignment. + */ +#define T3_STATUS_BLOCK_SIZE 0x80 + +typedef struct { + volatile LM_UINT32 Status; + #define STATUS_BLOCK_UPDATED BIT_0 + #define STATUS_BLOCK_LINK_CHANGED_STATUS BIT_1 + #define STATUS_BLOCK_ERROR BIT_2 + + volatile LM_UINT32 StatusTag; + +#ifdef BIG_ENDIAN_HOST + volatile LM_UINT16 RcvStdConIdx; + volatile LM_UINT16 RcvJumboConIdx; + + volatile LM_UINT16 Reserved2; + volatile LM_UINT16 RcvMiniConIdx; + + struct { + volatile LM_UINT16 SendConIdx; /* Send consumer index. */ + volatile LM_UINT16 RcvProdIdx; /* Receive producer index. */ + } Idx[16]; +#else /* BIG_ENDIAN_HOST */ + volatile LM_UINT16 RcvJumboConIdx; + volatile LM_UINT16 RcvStdConIdx; + + volatile LM_UINT16 RcvMiniConIdx; + volatile LM_UINT16 Reserved2; + + struct { + volatile LM_UINT16 RcvProdIdx; /* Receive producer index. */ + volatile LM_UINT16 SendConIdx; /* Send consumer index. */ + } Idx[16]; +#endif +} T3_STATUS_BLOCK, *PT3_STATUS_BLOCK; + + + +/******************************************************************************/ +/* Receive buffer descriptors. */ +/******************************************************************************/ + +typedef struct { + T3_64BIT_HOST_ADDR HostAddr; + +#ifdef BIG_ENDIAN_HOST + volatile LM_UINT16 Index; + volatile LM_UINT16 Len; + + volatile LM_UINT16 Type; + volatile LM_UINT16 Flags; + + volatile LM_UINT16 IpCksum; + volatile LM_UINT16 TcpUdpCksum; + + volatile LM_UINT16 ErrorFlag; + volatile LM_UINT16 VlanTag; +#else /* BIG_ENDIAN_HOST */ + volatile LM_UINT16 Len; + volatile LM_UINT16 Index; + + volatile LM_UINT16 Flags; + volatile LM_UINT16 Type; + + volatile LM_UINT16 TcpUdpCksum; + volatile LM_UINT16 IpCksum; + + volatile LM_UINT16 VlanTag; + volatile LM_UINT16 ErrorFlag; +#endif + + volatile LM_UINT32 Reserved; + volatile LM_UINT32 Opaque; +} T3_RCV_BD, *PT3_RCV_BD; + + +typedef struct { + T3_64BIT_HOST_ADDR HostAddr[3]; + +#ifdef BIG_ENDIAN_HOST + LM_UINT16 Len1; + LM_UINT16 Len2; + + LM_UINT16 Len3; + LM_UINT16 Reserved1; +#else /* BIG_ENDIAN_HOST */ + LM_UINT16 Len2; + LM_UINT16 Len1; + + LM_UINT16 Reserved1; + LM_UINT16 Len3; +#endif + + T3_RCV_BD StdRcvBd; +} T3_EXT_RCV_BD, *PT3_EXT_RCV_BD; + + +/* Error flags. */ +#define RCV_BD_ERR_BAD_CRC 0x0001 +#define RCV_BD_ERR_COLL_DETECT 0x0002 +#define RCV_BD_ERR_LINK_LOST_DURING_PKT 0x0004 +#define RCV_BD_ERR_PHY_DECODE_ERR 0x0008 +#define RCV_BD_ERR_ODD_NIBBLED_RCVD_MII 0x0010 +#define RCV_BD_ERR_MAC_ABORT 0x0020 +#define RCV_BD_ERR_LEN_LT_64 0x0040 +#define RCV_BD_ERR_TRUNC_NO_RESOURCES 0x0080 +#define RCV_BD_ERR_GIANT_FRAME_RCVD 0x0100 + + +/* Buffer descriptor flags. */ +#define RCV_BD_FLAG_END 0x0004 +#define RCV_BD_FLAG_JUMBO_RING 0x0020 +#define RCV_BD_FLAG_VLAN_TAG 0x0040 +#define RCV_BD_FLAG_FRAME_HAS_ERROR 0x0400 +#define RCV_BD_FLAG_MINI_RING 0x0800 +#define RCV_BD_FLAG_IP_CHKSUM_FIELD 0x1000 +#define RCV_BD_FLAG_TCP_UDP_CHKSUM_FIELD 0x2000 +#define RCV_BD_FLAG_TCP_PACKET 0x4000 + + + +/******************************************************************************/ +/* Send buffer descriptor. */ +/******************************************************************************/ + +typedef struct { + T3_64BIT_HOST_ADDR HostAddr; + + union { + struct { +#ifdef BIG_ENDIAN_HOST + LM_UINT16 Len; + LM_UINT16 Flags; +#else /* BIG_ENDIAN_HOST */ + LM_UINT16 Flags; + LM_UINT16 Len; +#endif + } s1; + + LM_UINT32 Len_Flags; + } u1; + + union { + struct { +#ifdef BIG_ENDIAN_HOST + LM_UINT16 Reserved; + LM_UINT16 VlanTag; +#else /* BIG_ENDIAN_HOST */ + LM_UINT16 VlanTag; + LM_UINT16 Reserved; +#endif + } s2; + + LM_UINT32 VlanTag; + } u2; +} T3_SND_BD, *PT3_SND_BD; + + +/* Send buffer descriptor flags. */ +#define SND_BD_FLAG_TCP_UDP_CKSUM 0x0001 +#define SND_BD_FLAG_IP_CKSUM 0x0002 +#define SND_BD_FLAG_END 0x0004 +#define SND_BD_FLAG_IP_FRAG 0x0008 +#define SND_BD_FLAG_IP_FRAG_END 0x0010 +#define SND_BD_FLAG_VLAN_TAG 0x0040 +#define SND_BD_FLAG_COAL_NOW 0x0080 +#define SND_BD_FLAG_CPU_PRE_DMA 0x0100 +#define SND_BD_FLAG_CPU_POST_DMA 0x0200 +#define SND_BD_FLAG_INSERT_SRC_ADDR 0x1000 +#define SND_BD_FLAG_CHOOSE_SRC_ADDR 0x6000 +#define SND_BD_FLAG_DONT_GEN_CRC 0x8000 + +/* MBUFs */ +typedef struct T3_MBUF_FRAME_DESC { +#ifdef BIG_ENDIAN_HOST + LM_UINT32 status_control; + union { + struct { + LM_UINT8 cqid; + LM_UINT8 reserved1; + LM_UINT16 length; + }s1; + LM_UINT32 word; + }u1; + union { + struct + { + LM_UINT16 ip_hdr_start; + LM_UINT16 tcp_udp_hdr_start; + }s2; + + LM_UINT32 word; + }u2; + + union { + struct { + LM_UINT16 data_start; + LM_UINT16 vlan_id; + }s3; + + LM_UINT32 word; + }u3; + + union { + struct { + LM_UINT16 ip_checksum; + LM_UINT16 tcp_udp_checksum; + }s4; + + LM_UINT32 word; + }u4; + + union { + struct { + LM_UINT16 pseudo_checksum; + LM_UINT16 checksum_status; + }s5; + + LM_UINT32 word; + }u5; + + union { + struct { + LM_UINT16 rule_match; + LM_UINT8 class; + LM_UINT8 rupt; + }s6; + + LM_UINT32 word; + }u6; + + union { + struct { + LM_UINT16 reserved2; + LM_UINT16 mbuf_num; + }s7; + + LM_UINT32 word; + }u7; + + LM_UINT32 reserved3; + LM_UINT32 reserved4; +#else + LM_UINT32 status_control; + union { + struct { + LM_UINT16 length; + LM_UINT8 reserved1; + LM_UINT8 cqid; + }s1; + LM_UINT32 word; + }u1; + union { + struct + { + LM_UINT16 tcp_udp_hdr_start; + LM_UINT16 ip_hdr_start; + }s2; + + LM_UINT32 word; + }u2; + + union { + struct { + LM_UINT16 vlan_id; + LM_UINT16 data_start; + }s3; + + LM_UINT32 word; + }u3; + + union { + struct { + LM_UINT16 tcp_udp_checksum; + LM_UINT16 ip_checksum; + }s4; + + LM_UINT32 word; + }u4; + + union { + struct { + LM_UINT16 checksum_status; + LM_UINT16 pseudo_checksum; + }s5; + + LM_UINT32 word; + }u5; + + union { + struct { + LM_UINT8 rupt; + LM_UINT8 class; + LM_UINT16 rule_match; + }s6; + + LM_UINT32 word; + }u6; + + union { + struct { + LM_UINT16 mbuf_num; + LM_UINT16 reserved2; + }s7; + + LM_UINT32 word; + }u7; + + LM_UINT32 reserved3; + LM_UINT32 reserved4; +#endif +}T3_MBUF_FRAME_DESC,*PT3_MBUF_FRAME_DESC; + +typedef struct T3_MBUF_HDR { + union { + struct { + unsigned int C:1; + unsigned int F:1; + unsigned int reserved1:7; + unsigned int next_mbuf:16; + unsigned int length:7; + }s1; + + LM_UINT32 word; + }u1; + + LM_UINT32 next_frame_ptr; +}T3_MBUF_HDR, *PT3_MBUF_HDR; + +typedef struct T3_MBUF +{ + T3_MBUF_HDR hdr; + union + { + struct { + T3_MBUF_FRAME_DESC frame_hdr; + LM_UINT32 data[20]; + }s1; + + struct { + LM_UINT32 data[30]; + }s2; + }body; +}T3_MBUF, *PT3_MBUF; + +#define T3_MBUF_BASE (T3_NIC_MBUF_POOL_ADDR >> 7) +#define T3_MBUF_END ((T3_NIC_MBUF_POOL_ADDR + T3_NIC_MBUF_POOL_SIZE) >> 7) + + + +/******************************************************************************/ +/* Statistics block. */ +/******************************************************************************/ + +typedef struct { + LM_UINT8 Reserved0[0x400-0x300]; + + /* Statistics maintained by Receive MAC. */ + T3_64BIT_REGISTER ifHCInOctets; + T3_64BIT_REGISTER Reserved1; + T3_64BIT_REGISTER etherStatsFragments; + T3_64BIT_REGISTER ifHCInUcastPkts; + T3_64BIT_REGISTER ifHCInMulticastPkts; + T3_64BIT_REGISTER ifHCInBroadcastPkts; + T3_64BIT_REGISTER dot3StatsFCSErrors; + T3_64BIT_REGISTER dot3StatsAlignmentErrors; + T3_64BIT_REGISTER xonPauseFramesReceived; + T3_64BIT_REGISTER xoffPauseFramesReceived; + T3_64BIT_REGISTER macControlFramesReceived; + T3_64BIT_REGISTER xoffStateEntered; + T3_64BIT_REGISTER dot3StatsFramesTooLong; + T3_64BIT_REGISTER etherStatsJabbers; + T3_64BIT_REGISTER etherStatsUndersizePkts; + T3_64BIT_REGISTER inRangeLengthError; + T3_64BIT_REGISTER outRangeLengthError; + T3_64BIT_REGISTER etherStatsPkts64Octets; + T3_64BIT_REGISTER etherStatsPkts65Octetsto127Octets; + T3_64BIT_REGISTER etherStatsPkts128Octetsto255Octets; + T3_64BIT_REGISTER etherStatsPkts256Octetsto511Octets; + T3_64BIT_REGISTER etherStatsPkts512Octetsto1023Octets; + T3_64BIT_REGISTER etherStatsPkts1024Octetsto1522Octets; + T3_64BIT_REGISTER etherStatsPkts1523Octetsto2047Octets; + T3_64BIT_REGISTER etherStatsPkts2048Octetsto4095Octets; + T3_64BIT_REGISTER etherStatsPkts4096Octetsto8191Octets; + T3_64BIT_REGISTER etherStatsPkts8192Octetsto9022Octets; + + T3_64BIT_REGISTER Unused1[37]; + + /* Statistics maintained by Transmit MAC. */ + T3_64BIT_REGISTER ifHCOutOctets; + T3_64BIT_REGISTER Reserved2; + T3_64BIT_REGISTER etherStatsCollisions; + T3_64BIT_REGISTER outXonSent; + T3_64BIT_REGISTER outXoffSent; + T3_64BIT_REGISTER flowControlDone; + T3_64BIT_REGISTER dot3StatsInternalMacTransmitErrors; + T3_64BIT_REGISTER dot3StatsSingleCollisionFrames; + T3_64BIT_REGISTER dot3StatsMultipleCollisionFrames; + T3_64BIT_REGISTER dot3StatsDeferredTransmissions; + T3_64BIT_REGISTER Reserved3; + T3_64BIT_REGISTER dot3StatsExcessiveCollisions; + T3_64BIT_REGISTER dot3StatsLateCollisions; + T3_64BIT_REGISTER dot3Collided2Times; + T3_64BIT_REGISTER dot3Collided3Times; + T3_64BIT_REGISTER dot3Collided4Times; + T3_64BIT_REGISTER dot3Collided5Times; + T3_64BIT_REGISTER dot3Collided6Times; + T3_64BIT_REGISTER dot3Collided7Times; + T3_64BIT_REGISTER dot3Collided8Times; + T3_64BIT_REGISTER dot3Collided9Times; + T3_64BIT_REGISTER dot3Collided10Times; + T3_64BIT_REGISTER dot3Collided11Times; + T3_64BIT_REGISTER dot3Collided12Times; + T3_64BIT_REGISTER dot3Collided13Times; + T3_64BIT_REGISTER dot3Collided14Times; + T3_64BIT_REGISTER dot3Collided15Times; + T3_64BIT_REGISTER ifHCOutUcastPkts; + T3_64BIT_REGISTER ifHCOutMulticastPkts; + T3_64BIT_REGISTER ifHCOutBroadcastPkts; + T3_64BIT_REGISTER dot3StatsCarrierSenseErrors; + T3_64BIT_REGISTER ifOutDiscards; + T3_64BIT_REGISTER ifOutErrors; + + T3_64BIT_REGISTER Unused2[31]; + + /* Statistics maintained by Receive List Placement. */ + T3_64BIT_REGISTER COSIfHCInPkts[16]; + T3_64BIT_REGISTER COSFramesDroppedDueToFilters; + T3_64BIT_REGISTER nicDmaWriteQueueFull; + T3_64BIT_REGISTER nicDmaWriteHighPriQueueFull; + T3_64BIT_REGISTER nicNoMoreRxBDs; + T3_64BIT_REGISTER ifInDiscards; + T3_64BIT_REGISTER ifInErrors; + T3_64BIT_REGISTER nicRecvThresholdHit; + + T3_64BIT_REGISTER Unused3[9]; + + /* Statistics maintained by Send Data Initiator. */ + T3_64BIT_REGISTER COSIfHCOutPkts[16]; + T3_64BIT_REGISTER nicDmaReadQueueFull; + T3_64BIT_REGISTER nicDmaReadHighPriQueueFull; + T3_64BIT_REGISTER nicSendDataCompQueueFull; + + /* Statistics maintained by Host Coalescing. */ + T3_64BIT_REGISTER nicRingSetSendProdIndex; + T3_64BIT_REGISTER nicRingStatusUpdate; + T3_64BIT_REGISTER nicInterrupts; + T3_64BIT_REGISTER nicAvoidedInterrupts; + T3_64BIT_REGISTER nicSendThresholdHit; + + LM_UINT8 Reserved4[0xb00-0x9c0]; +} T3_STATS_BLOCK, *PT3_STATS_BLOCK; + + + +/******************************************************************************/ +/* PCI configuration registers. */ +/******************************************************************************/ + +typedef struct { + T3_16BIT_REGISTER VendorId; + T3_16BIT_REGISTER DeviceId; + + T3_16BIT_REGISTER Command; + T3_16BIT_REGISTER Status; + + T3_32BIT_REGISTER ClassCodeRevId; + + T3_8BIT_REGISTER CacheLineSize; + T3_8BIT_REGISTER LatencyTimer; + T3_8BIT_REGISTER HeaderType; + T3_8BIT_REGISTER Bist; + + T3_32BIT_REGISTER MemBaseAddrLow; + T3_32BIT_REGISTER MemBaseAddrHigh; + + LM_UINT8 Unused1[20]; + + T3_16BIT_REGISTER SubsystemVendorId; + T3_16BIT_REGISTER SubsystemId; + + T3_32BIT_REGISTER RomBaseAddr; + + T3_8BIT_REGISTER PciXCapiblityPtr; + LM_UINT8 Unused2[7]; + + T3_8BIT_REGISTER IntLine; + T3_8BIT_REGISTER IntPin; + T3_8BIT_REGISTER MinGnt; + T3_8BIT_REGISTER MaxLat; + + T3_8BIT_REGISTER PciXCapabilities; + T3_8BIT_REGISTER PmCapabilityPtr; + T3_16BIT_REGISTER PciXCommand; + + T3_32BIT_REGISTER PciXStatus; + + T3_8BIT_REGISTER PmCapabilityId; + T3_8BIT_REGISTER VpdCapabilityPtr; + T3_16BIT_REGISTER PmCapabilities; + + T3_16BIT_REGISTER PmCtrlStatus; + #define PM_CTRL_PME_STATUS BIT_15 + #define PM_CTRL_PME_ENABLE BIT_8 + #define PM_CTRL_PME_POWER_STATE_D0 0 + #define PM_CTRL_PME_POWER_STATE_D1 1 + #define PM_CTRL_PME_POWER_STATE_D2 2 + #define PM_CTRL_PME_POWER_STATE_D3H 3 + + T3_8BIT_REGISTER BridgeSupportExt; + T3_8BIT_REGISTER PmData; + + T3_8BIT_REGISTER VpdCapabilityId; + T3_8BIT_REGISTER MsiCapabilityPtr; + T3_16BIT_REGISTER VpdAddrFlag; + #define VPD_FLAG_WRITE (1 << 15) + #define VPD_FLAG_RW_MASK (1 << 15) + #define VPD_FLAG_READ 0 + + + T3_32BIT_REGISTER VpdData; + + T3_8BIT_REGISTER MsiCapabilityId; + T3_8BIT_REGISTER NextCapabilityPtr; + T3_16BIT_REGISTER MsiCtrl; + #define MSI_CTRL_64BIT_CAP (1 << 7) + #define MSI_CTRL_MSG_ENABLE(x) (x << 4) + #define MSI_CTRL_MSG_CAP(x) (x << 1) + #define MSI_CTRL_ENABLE (1 << 0) + + + T3_32BIT_REGISTER MsiAddrLow; + T3_32BIT_REGISTER MsiAddrHigh; + + T3_16BIT_REGISTER MsiData; + T3_16BIT_REGISTER Unused3; + + T3_32BIT_REGISTER MiscHostCtrl; + #define MISC_HOST_CTRL_CLEAR_INT BIT_0 + #define MISC_HOST_CTRL_MASK_PCI_INT BIT_1 + #define MISC_HOST_CTRL_ENABLE_ENDIAN_BYTE_SWAP BIT_2 + #define MISC_HOST_CTRL_ENABLE_ENDIAN_WORD_SWAP BIT_3 + #define MISC_HOST_CTRL_ENABLE_PCI_STATE_REG_RW BIT_4 + #define MISC_HOST_CTRL_ENABLE_CLK_REG_RW BIT_5 + #define MISC_HOST_CTRL_ENABLE_REG_WORD_SWAP BIT_6 + #define MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS BIT_7 + #define MISC_HOST_CTRL_ENABLE_INT_MASK_MODE BIT_8 + #define MISC_HOST_CTRL_ENABLE_TAGGED_STATUS_MODE BIT_9 + + T3_32BIT_REGISTER DmaReadWriteCtrl; + #define DMA_CTRL_WRITE_BOUNDARY_MASK (BIT_11 | BIT_12 | BIT_13) + #define DMA_CTRL_WRITE_BOUNDARY_DISABLE 0 + #define DMA_CTRL_WRITE_BOUNDARY_16 BIT_11 + #define DMA_CTRL_WRITE_BOUNDARY_32 BIT_12 + #define DMA_CTRL_WRITE_BOUNDARY_64 (BIT_12 | BIT_11) + #define DMA_CTRL_WRITE_BOUNDARY_128 BIT_13 + #define DMA_CTRL_WRITE_BOUNDARY_256 (BIT_13 | BIT_11) + #define DMA_CTRL_WRITE_BOUNDARY_512 (BIT_13 | BIT_12) + #define DMA_CTRL_WRITE_BOUNDARY_1024 (BIT_13 | BIT_12 | BIT_11) + #define DMA_CTRL_WRITE_ONE_DMA_AT_ONCE BIT_14 + + + T3_32BIT_REGISTER PciState; + #define T3_PCI_STATE_FORCE_PCI_RESET BIT_0 + #define T3_PCI_STATE_INTERRUPT_NOT_ACTIVE BIT_1 + #define T3_PCI_STATE_NOT_PCI_X_BUS BIT_2 + #define T3_PCI_STATE_HIGH_BUS_SPEED BIT_3 + #define T3_PCI_STATE_32BIT_PCI_BUS BIT_4 + #define T3_PCI_STATE_PCI_ROM_ENABLE BIT_5 + #define T3_PCI_STATE_PCI_ROM_RETRY_ENABLE BIT_6 + #define T3_PCI_STATE_FLAT_VIEW BIT_8 + + T3_32BIT_REGISTER ClockCtrl; + #define T3_PCI_CLKCTRL_TXCPU_CLK_DISABLE BIT_11 + #define T3_PCI_CLKCTRL_RXCPU_CLK_DISABLE BIT_10 + #define T3_PCI_CLKCTRL_CORE_CLK_DISABLE BIT_9 + + T3_32BIT_REGISTER RegBaseAddr; + + T3_32BIT_REGISTER MemWindowBaseAddr; + +#ifdef NIC_CPU_VIEW + /* These registers are ONLY visible to NIC CPU */ + T3_32BIT_REGISTER PowerConsumed; + T3_32BIT_REGISTER PowerDissipated; +#else /* NIC_CPU_VIEW */ + T3_32BIT_REGISTER RegData; + T3_32BIT_REGISTER MemWindowData; +#endif /* !NIC_CPU_VIEW */ + + T3_32BIT_REGISTER ModeCtrl; + + T3_32BIT_REGISTER MiscCfg; + + T3_32BIT_REGISTER MiscLocalCtrl; + + T3_32BIT_REGISTER Unused4; + + /* NOTE: Big/Little-endian clarification needed. Are these register */ + /* in big or little endian formate. */ + T3_64BIT_REGISTER StdRingProdIdx; + T3_64BIT_REGISTER RcvRetRingConIdx; + T3_64BIT_REGISTER SndProdIdx; + + LM_UINT8 Unused5[80]; +} T3_PCI_CONFIGURATION, *PT3_PCI_CONFIGURATION; + + + +/******************************************************************************/ +/* Mac control registers. */ +/******************************************************************************/ + +typedef struct { + /* MAC mode control. */ + T3_32BIT_REGISTER Mode; + #define MAC_MODE_GLOBAL_RESET BIT_0 + #define MAC_MODE_HALF_DUPLEX BIT_1 + #define MAC_MODE_PORT_MODE_MASK (BIT_2 | BIT_3) + #define MAC_MODE_PORT_MODE_TBI (BIT_2 | BIT_3) + #define MAC_MODE_PORT_MODE_GMII BIT_3 + #define MAC_MODE_PORT_MODE_MII BIT_2 + #define MAC_MODE_PORT_MODE_NONE BIT_NONE + #define MAC_MODE_PORT_INTERNAL_LOOPBACK BIT_4 + #define MAC_MODE_TAGGED_MAC_CONTROL BIT_7 + #define MAC_MODE_TX_BURSTING BIT_8 + #define MAC_MODE_MAX_DEFER BIT_9 + #define MAC_MODE_LINK_POLARITY BIT_10 + #define MAC_MODE_ENABLE_RX_STATISTICS BIT_11 + #define MAC_MODE_CLEAR_RX_STATISTICS BIT_12 + #define MAC_MODE_FLUSH_RX_STATISTICS BIT_13 + #define MAC_MODE_ENABLE_TX_STATISTICS BIT_14 + #define MAC_MODE_CLEAR_TX_STATISTICS BIT_15 + #define MAC_MODE_FLUSH_TX_STATISTICS BIT_16 + #define MAC_MODE_SEND_CONFIGS BIT_17 + #define MAC_MODE_DETECT_MAGIC_PACKET_ENABLE BIT_18 + #define MAC_MODE_ACPI_POWER_ON_ENABLE BIT_19 + #define MAC_MODE_ENABLE_MIP BIT_20 + #define MAC_MODE_ENABLE_TDE BIT_21 + #define MAC_MODE_ENABLE_RDE BIT_22 + #define MAC_MODE_ENABLE_FHDE BIT_23 + + /* MAC status */ + T3_32BIT_REGISTER Status; + #define MAC_STATUS_PCS_SYNCED BIT_0 + #define MAC_STATUS_SIGNAL_DETECTED BIT_1 + #define MAC_STATUS_RECEIVING_CFG BIT_2 + #define MAC_STATUS_CFG_CHANGED BIT_3 + #define MAC_STATUS_SYNC_CHANGED BIT_4 + #define MAC_STATUS_PORT_DECODE_ERROR BIT_10 + #define MAC_STATUS_LINK_STATE_CHANGED BIT_12 + #define MAC_STATUS_MI_COMPLETION BIT_22 + #define MAC_STATUS_MI_INTERRUPT BIT_23 + #define MAC_STATUS_AP_ERROR BIT_24 + #define MAC_STATUS_ODI_ERROR BIT_25 + #define MAC_STATUS_RX_STATS_OVERRUN BIT_26 + #define MAC_STATUS_TX_STATS_OVERRUN BIT_27 + + /* Event Enable */ + T3_32BIT_REGISTER MacEvent; + #define MAC_EVENT_ENABLE_PORT_DECODE_ERR BIT_10 + #define MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN BIT_12 + #define MAC_EVENT_ENABLE_MI_COMPLETION BIT_22 + #define MAC_EVENT_ENABLE_MI_INTERRUPT BIT_23 + #define MAC_EVENT_ENABLE_AP_ERROR BIT_24 + #define MAC_EVENT_ENABLE_ODI_ERROR BIT_25 + #define MAC_EVENT_ENABLE_RX_STATS_OVERRUN BIT_26 + #define MAC_EVENT_ENABLE_TX_STATS_OVERRUN BIT_27 + + /* Led control. */ + T3_32BIT_REGISTER LedCtrl; + #define LED_CTRL_OVERRIDE_LINK_LED BIT_0 + #define LED_CTRL_1000MBPS_LED_ON BIT_1 + #define LED_CTRL_100MBPS_LED_ON BIT_2 + #define LED_CTRL_10MBPS_LED_ON BIT_3 + #define LED_CTRL_OVERRIDE_TRAFFIC_LED BIT_4 + #define LED_CTRL_BLINK_TRAFFIC_LED BIT_5 + #define LED_CTRL_TRAFFIC_LED BIT_6 + #define LED_CTRL_1000MBPS_LED_STATUS BIT_7 + #define LED_CTRL_100MBPS_LED_STATUS BIT_8 + #define LED_CTRL_10MBPS_LED_STATUS BIT_9 + #define LED_CTRL_TRAFFIC_LED_STATUS BIT_10 + #define LED_CTRL_MAC_MODE BIT_NONE + #define LED_CTRL_PHY_MODE_1 BIT_11 + #define LED_CTRL_PHY_MODE_2 BIT_12 + #define LED_CTRL_BLINK_RATE_MASK 0x7ff80000 + #define LED_CTRL_OVERRIDE_BLINK_PERIOD BIT_19 + #define LED_CTRL_OVERRIDE_BLINK_RATE BIT_31 + + /* MAC addresses. */ + struct { + T3_32BIT_REGISTER High; /* Upper 2 bytes. */ + T3_32BIT_REGISTER Low; /* Lower 4 bytes. */ + } MacAddr[4]; + + /* ACPI Mbuf pointer. */ + T3_32BIT_REGISTER AcpiMbufPtr; + + /* ACPI Length and Offset. */ + T3_32BIT_REGISTER AcpiLengthOffset; + #define ACPI_LENGTH_MASK 0xffff + #define ACPI_OFFSET_MASK 0x0fff0000 + #define ACPI_LENGTH(x) x + #define ACPI_OFFSET(x) ((x) << 16) + + /* Transmit random backoff. */ + T3_32BIT_REGISTER TxBackoffSeed; + #define MAC_TX_BACKOFF_SEED_MASK 0x3ff + + /* Receive MTU */ + T3_32BIT_REGISTER MtuSize; + #define MAC_RX_MTU_MASK 0xffff + + /* Gigabit PCS Test. */ + T3_32BIT_REGISTER PcsTest; + #define MAC_PCS_TEST_DATA_PATTERN_MASK 0x0fffff + #define MAC_PCS_TEST_ENABLE BIT_20 + + /* Transmit Gigabit Auto-Negotiation. */ + T3_32BIT_REGISTER TxAutoNeg; + #define MAC_AN_TX_AN_DATA_MASK 0xffff + + /* Receive Gigabit Auto-Negotiation. */ + T3_32BIT_REGISTER RxAutoNeg; + #define MAC_AN_RX_AN_DATA_MASK 0xffff + + /* MI Communication. */ + T3_32BIT_REGISTER MiCom; + #define MI_COM_CMD_MASK (BIT_26 | BIT_27) + #define MI_COM_CMD_WRITE BIT_26 + #define MI_COM_CMD_READ BIT_27 + #define MI_COM_READ_FAILED BIT_28 + #define MI_COM_START BIT_29 + #define MI_COM_BUSY BIT_29 + + #define MI_COM_PHY_ADDR_MASK 0x1f + #define MI_COM_FIRST_PHY_ADDR_BIT 21 + + #define MI_COM_PHY_REG_ADDR_MASK 0x1f + #define MI_COM_FIRST_PHY_REG_ADDR_BIT 16 + + #define MI_COM_PHY_DATA_MASK 0xffff + + /* MI Status. */ + T3_32BIT_REGISTER MiStatus; + #define MI_STATUS_ENABLE_LINK_STATUS_ATTN BIT_0 + + /* MI Mode. */ + T3_32BIT_REGISTER MiMode; + #define MI_MODE_CLOCK_SPEED_10MHZ BIT_0 + #define MI_MODE_USE_SHORT_PREAMBLE BIT_1 + #define MI_MODE_AUTO_POLLING_ENABLE BIT_4 + #define MI_MODE_CORE_CLOCK_SPEED_62MHZ BIT_15 + + /* Auto-polling status. */ + T3_32BIT_REGISTER AutoPollStatus; + #define AUTO_POLL_ERROR BIT_0 + + /* Transmit MAC mode. */ + T3_32BIT_REGISTER TxMode; + #define TX_MODE_RESET BIT_0 + #define TX_MODE_ENABLE BIT_1 + #define TX_MODE_ENABLE_FLOW_CONTROL BIT_4 + #define TX_MODE_ENABLE_BIG_BACKOFF BIT_5 + #define TX_MODE_ENABLE_LONG_PAUSE BIT_6 + + /* Transmit MAC status. */ + T3_32BIT_REGISTER TxStatus; + #define TX_STATUS_RX_CURRENTLY_XOFFED BIT_0 + #define TX_STATUS_SENT_XOFF BIT_1 + #define TX_STATUS_SENT_XON BIT_2 + #define TX_STATUS_LINK_UP BIT_3 + #define TX_STATUS_ODI_UNDERRUN BIT_4 + #define TX_STATUS_ODI_OVERRUN BIT_5 + + /* Transmit MAC length. */ + T3_32BIT_REGISTER TxLengths; + #define TX_LEN_SLOT_TIME_MASK 0xff + #define TX_LEN_IPG_MASK 0x0f00 + #define TX_LEN_IPG_CRS_MASK (BIT_12 | BIT_13) + + /* Receive MAC mode. */ + T3_32BIT_REGISTER RxMode; + #define RX_MODE_RESET BIT_0 + #define RX_MODE_ENABLE BIT_1 + #define RX_MODE_ENABLE_FLOW_CONTROL BIT_2 + #define RX_MODE_KEEP_MAC_CONTROL BIT_3 + #define RX_MODE_KEEP_PAUSE BIT_4 + #define RX_MODE_ACCEPT_OVERSIZED BIT_5 + #define RX_MODE_ACCEPT_RUNTS BIT_6 + #define RX_MODE_LENGTH_CHECK BIT_7 + #define RX_MODE_PROMISCUOUS_MODE BIT_8 + #define RX_MODE_NO_CRC_CHECK BIT_9 + #define RX_MODE_KEEP_VLAN_TAG BIT_10 + + /* Receive MAC status. */ + T3_32BIT_REGISTER RxStatus; + #define RX_STATUS_REMOTE_TRANSMITTER_XOFFED BIT_0 + #define RX_STATUS_XOFF_RECEIVED BIT_1 + #define RX_STATUS_XON_RECEIVED BIT_2 + + /* Hash registers. */ + T3_32BIT_REGISTER HashReg[4]; + + /* Receive placement rules registers. */ + struct { + T3_32BIT_REGISTER Rule; + T3_32BIT_REGISTER Value; + } RcvRules[16]; + + #define RCV_DISABLE_RULE_MASK 0x7fffffff + + #define RCV_RULE1_REJECT_BROADCAST_IDX 0x00 + #define REJECT_BROADCAST_RULE1_RULE 0xc2000000 + #define REJECT_BROADCAST_RULE1_VALUE 0xffffffff + + #define RCV_RULE2_REJECT_BROADCAST_IDX 0x01 + #define REJECT_BROADCAST_RULE2_RULE 0x86000004 + #define REJECT_BROADCAST_RULE2_VALUE 0xffffffff + +#if INCLUDE_5701_AX_FIX + #define RCV_LAST_RULE_IDX 0x04 +#else + #define RCV_LAST_RULE_IDX 0x02 +#endif + + T3_32BIT_REGISTER RcvRuleCfg; + #define RX_RULE_DEFAULT_CLASS (1 << 3) + + LM_UINT8 Reserved1[140]; + + T3_32BIT_REGISTER SerdesCfg; + T3_32BIT_REGISTER SerdesStatus; + + LM_UINT8 Reserved2[104]; + + volatile LM_UINT8 TxMacState[16]; + volatile LM_UINT8 RxMacState[20]; + + LM_UINT8 Reserved3[476]; + + T3_32BIT_REGISTER RxStats[26]; + + LM_UINT8 Reserved4[24]; + + T3_32BIT_REGISTER TxStats[28]; + + LM_UINT8 Reserved5[784]; +} T3_MAC_CONTROL, *PT3_MAC_CONTROL; + + + +/******************************************************************************/ +/* Send data initiator control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define T3_SND_DATA_IN_MODE_RESET BIT_0 + #define T3_SND_DATA_IN_MODE_ENABLE BIT_1 + #define T3_SND_DATA_IN_MODE_STATS_OFLW_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define T3_SND_DATA_IN_STATUS_STATS_OFLW_ATTN BIT_2 + + T3_32BIT_REGISTER StatsCtrl; + #define T3_SND_DATA_IN_STATS_CTRL_ENABLE BIT_0 + #define T3_SND_DATA_IN_STATS_CTRL_FASTER_UPDATE BIT_1 + #define T3_SND_DATA_IN_STATS_CTRL_CLEAR BIT_2 + #define T3_SND_DATA_IN_STATS_CTRL_FLUSH BIT_3 + #define T3_SND_DATA_IN_STATS_CTRL_FORCE_ZERO BIT_4 + + T3_32BIT_REGISTER StatsEnableMask; + T3_32BIT_REGISTER StatsIncMask; + + LM_UINT8 Reserved[108]; + + T3_32BIT_REGISTER ClassOfServCnt[16]; + T3_32BIT_REGISTER DmaReadQFullCnt; + T3_32BIT_REGISTER DmaPriorityReadQFullCnt; + T3_32BIT_REGISTER SdcQFullCnt; + + T3_32BIT_REGISTER NicRingSetSendProdIdxCnt; + T3_32BIT_REGISTER StatusUpdatedCnt; + T3_32BIT_REGISTER InterruptsCnt; + T3_32BIT_REGISTER AvoidInterruptsCnt; + T3_32BIT_REGISTER SendThresholdHitCnt; + + /* Unused space. */ + LM_UINT8 Unused[800]; +} T3_SEND_DATA_INITIATOR, *PT3_SEND_DATA_INITIATOR; + + + +/******************************************************************************/ +/* Send data completion control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_DATA_COMP_MODE_RESET BIT_0 + #define SND_DATA_COMP_MODE_ENABLE BIT_1 + + /* Unused space. */ + LM_UINT8 Unused[1020]; +} T3_SEND_DATA_COMPLETION, *PT3_SEND_DATA_COMPLETION; + + + +/******************************************************************************/ +/* Send BD Ring Selector Control Registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_BD_SEL_MODE_RESET BIT_0 + #define SND_BD_SEL_MODE_ENABLE BIT_1 + #define SND_BD_SEL_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define SND_BD_SEL_STATUS_ERROR_ATTN BIT_2 + + T3_32BIT_REGISTER HwDiag; + + /* Unused space. */ + LM_UINT8 Unused1[52]; + + /* Send BD Ring Selector Local NIC Send BD Consumer Index. */ + T3_32BIT_REGISTER NicSendBdSelConIdx[16]; + + /* Unused space. */ + LM_UINT8 Unused2[896]; +} T3_SEND_BD_SELECTOR, *PT3_SEND_BD_SELECTOR; + + + +/******************************************************************************/ +/* Send BD initiator control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_BD_IN_MODE_RESET BIT_0 + #define SND_BD_IN_MODE_ENABLE BIT_1 + #define SND_BD_IN_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define SND_BD_IN_STATUS_ERROR_ATTN BIT_2 + + /* Send BD initiator local NIC send BD producer index. */ + T3_32BIT_REGISTER NicSendBdInProdIdx[16]; + + /* Unused space. */ + LM_UINT8 Unused2[952]; +} T3_SEND_BD_INITIATOR, *PT3_SEND_BD_INITIATOR; + + + +/******************************************************************************/ +/* Send BD Completion Control. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_BD_COMP_MODE_RESET BIT_0 + #define SND_BD_COMP_MODE_ENABLE BIT_1 + #define SND_BD_COMP_MODE_ATTN_ENABLE BIT_2 + + /* Unused space. */ + LM_UINT8 Unused2[1020]; +} T3_SEND_BD_COMPLETION, *PT3_SEND_BD_COMPLETION; + + + +/******************************************************************************/ +/* Receive list placement control registers. */ +/******************************************************************************/ + +typedef struct { + /* Mode. */ + T3_32BIT_REGISTER Mode; + #define RCV_LIST_PLMT_MODE_RESET BIT_0 + #define RCV_LIST_PLMT_MODE_ENABLE BIT_1 + #define RCV_LIST_PLMT_MODE_CLASS0_ATTN_ENABLE BIT_2 + #define RCV_LIST_PLMT_MODE_MAPPING_OOR_ATTN_ENABLE BIT_3 + #define RCV_LIST_PLMT_MODE_STATS_OFLOW_ATTN_ENABLE BIT_4 + + /* Status. */ + T3_32BIT_REGISTER Status; + #define RCV_LIST_PLMT_STATUS_CLASS0_ATTN BIT_2 + #define RCV_LIST_PLMT_STATUS_MAPPING_ATTN BIT_3 + #define RCV_LIST_PLMT_STATUS_STATS_OFLOW_ATTN BIT_4 + + /* Receive selector list lock register. */ + T3_32BIT_REGISTER Lock; + #define RCV_LIST_SEL_LOCK_REQUEST_MASK 0xffff + #define RCV_LIST_SEL_LOCK_GRANT_MASK 0xffff0000 + + /* Selector non-empty bits. */ + T3_32BIT_REGISTER NonEmptyBits; + #define RCV_LIST_SEL_NON_EMPTY_MASK 0xffff + + /* Receive list placement configuration register. */ + T3_32BIT_REGISTER Config; + + /* Receive List Placement statistics Control. */ + T3_32BIT_REGISTER StatsCtrl; +#define RCV_LIST_STATS_ENABLE BIT_0 +#define RCV_LIST_STATS_FAST_UPDATE BIT_1 + + /* Receive List Placement statistics Enable Mask. */ + T3_32BIT_REGISTER StatsEnableMask; + + /* Receive List Placement statistics Increment Mask. */ + T3_32BIT_REGISTER StatsIncMask; + + /* Unused space. */ + LM_UINT8 Unused1[224]; + + struct { + T3_32BIT_REGISTER Head; + T3_32BIT_REGISTER Tail; + T3_32BIT_REGISTER Count; + + /* Unused space. */ + LM_UINT8 Unused[4]; + } RcvSelectorList[16]; + + /* Local statistics counter. */ + T3_32BIT_REGISTER ClassOfServCnt[16]; + + T3_32BIT_REGISTER DropDueToFilterCnt; + T3_32BIT_REGISTER DmaWriteQFullCnt; + T3_32BIT_REGISTER DmaHighPriorityWriteQFullCnt; + T3_32BIT_REGISTER NoMoreReceiveBdCnt; + T3_32BIT_REGISTER IfInDiscardsCnt; + T3_32BIT_REGISTER IfInErrorsCnt; + T3_32BIT_REGISTER RcvThresholdHitCnt; + + /* Another unused space. */ + LM_UINT8 Unused2[420]; +} T3_RCV_LIST_PLACEMENT, *PT3_RCV_LIST_PLACEMENT; + + + +/******************************************************************************/ +/* Receive Data and Receive BD Initiator Control. */ +/******************************************************************************/ + +typedef struct { + /* Mode. */ + T3_32BIT_REGISTER Mode; + #define RCV_DATA_BD_IN_MODE_RESET BIT_0 + #define RCV_DATA_BD_IN_MODE_ENABLE BIT_1 + #define RCV_DATA_BD_IN_MODE_JUMBO_BD_NEEDED BIT_2 + #define RCV_DATA_BD_IN_MODE_FRAME_TOO_BIG BIT_3 + #define RCV_DATA_BD_IN_MODE_INVALID_RING_SIZE BIT_4 + + /* Status. */ + T3_32BIT_REGISTER Status; + #define RCV_DATA_BD_IN_STATUS_JUMBO_BD_NEEDED BIT_2 + #define RCV_DATA_BD_IN_STATUS_FRAME_TOO_BIG BIT_3 + #define RCV_DATA_BD_IN_STATUS_INVALID_RING_SIZE BIT_4 + + /* Split frame minium size. */ + T3_32BIT_REGISTER SplitFrameMinSize; + + /* Unused space. */ + LM_UINT8 Unused1[0x2440-0x240c]; + + /* Receive RCBs. */ + T3_RCB JumboRcvRcb; + T3_RCB StdRcvRcb; + T3_RCB MiniRcvRcb; + + /* Receive Data and Receive BD Ring Initiator Local NIC Receive */ + /* BD Consumber Index. */ + T3_32BIT_REGISTER NicJumboConIdx; + T3_32BIT_REGISTER NicStdConIdx; + T3_32BIT_REGISTER NicMiniConIdx; + + /* Unused space. */ + LM_UINT8 Unused2[4]; + + /* Receive Data and Receive BD Initiator Local Receive Return ProdIdx. */ + T3_32BIT_REGISTER RcvDataBdProdIdx[16]; + + /* Receive Data and Receive BD Initiator Hardware Diagnostic. */ + T3_32BIT_REGISTER HwDiag; + + /* Unused space. */ + LM_UINT8 Unused3[828]; +} T3_RCV_DATA_BD_INITIATOR, *PT3_RCV_DATA_BD_INITIATOR; + + + +/******************************************************************************/ +/* Receive Data Completion Control Registes. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_DATA_COMP_MODE_RESET BIT_0 + #define RCV_DATA_COMP_MODE_ENABLE BIT_1 + #define RCV_DATA_COMP_MODE_ATTN_ENABLE BIT_2 + + /* Unused spaced. */ + LM_UINT8 Unused[1020]; +} T3_RCV_DATA_COMPLETION, *PT3_RCV_DATA_COMPLETION; + + + +/******************************************************************************/ +/* Receive BD Initiator Control. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_BD_IN_MODE_RESET BIT_0 + #define RCV_BD_IN_MODE_ENABLE BIT_1 + #define RCV_BD_IN_MODE_BD_IN_DIABLED_RCB_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define RCV_BD_IN_STATUS_BD_IN_DIABLED_RCB_ATTN BIT_2 + + T3_32BIT_REGISTER NicJumboRcvProdIdx; + T3_32BIT_REGISTER NicStdRcvProdIdx; + T3_32BIT_REGISTER NicMiniRcvProdIdx; + + T3_32BIT_REGISTER MiniRcvThreshold; + T3_32BIT_REGISTER StdRcvThreshold; + T3_32BIT_REGISTER JumboRcvThreshold; + + /* Unused space. */ + LM_UINT8 Unused[992]; +} T3_RCV_BD_INITIATOR, *PT3_RCV_BD_INITIATOR; + + + +/******************************************************************************/ +/* Receive BD Completion Control Registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_BD_COMP_MODE_RESET BIT_0 + #define RCV_BD_COMP_MODE_ENABLE BIT_1 + #define RCV_BD_COMP_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define RCV_BD_COMP_STATUS_ERROR_ATTN BIT_2 + + T3_32BIT_REGISTER NicJumboRcvBdProdIdx; + T3_32BIT_REGISTER NicStdRcvBdProdIdx; + T3_32BIT_REGISTER NicMiniRcvBdProdIdx; + + /* Unused space. */ + LM_UINT8 Unused[1004]; +} T3_RCV_BD_COMPLETION, *PT3_RCV_BD_COMPLETION; + + + +/******************************************************************************/ +/* Receive list selector control register. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_LIST_SEL_MODE_RESET BIT_0 + #define RCV_LIST_SEL_MODE_ENABLE BIT_1 + #define RCV_LIST_SEL_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define RCV_LIST_SEL_STATUS_ERROR_ATTN BIT_2 + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_RCV_LIST_SELECTOR, *PT3_RCV_LIST_SELECTOR; + + + +/******************************************************************************/ +/* Mbuf cluster free registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; +#define MBUF_CLUSTER_FREE_MODE_RESET BIT_0 +#define MBUF_CLUSTER_FREE_MODE_ENABLE BIT_1 + + T3_32BIT_REGISTER Status; + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_MBUF_CLUSTER_FREE, *PT3_MBUF_CLUSTER_FREE; + + + +/******************************************************************************/ +/* Host coalescing control registers. */ +/******************************************************************************/ + +typedef struct { + /* Mode. */ + T3_32BIT_REGISTER Mode; + #define HOST_COALESCE_RESET BIT_0 + #define HOST_COALESCE_ENABLE BIT_1 + #define HOST_COALESCE_ATTN BIT_2 + #define HOST_COALESCE_NOW BIT_3 + #define HOST_COALESCE_FULL_STATUS_MODE BIT_NONE + #define HOST_COALESCE_64_BYTE_STATUS_MODE BIT_7 + #define HOST_COALESCE_32_BYTE_STATUS_MODE BIT_8 + #define HOST_COALESCE_CLEAR_TICKS_ON_RX_BD_EVENT BIT_9 + #define HOST_COALESCE_CLEAR_TICKS_ON_TX_BD_EVENT BIT_10 + #define HOST_COALESCE_NO_INT_ON_COALESCE_NOW_MODE BIT_11 + #define HOST_COALESCE_NO_INT_ON_FORCE_DMAD_MODE BIT_12 + + /* Status. */ + T3_32BIT_REGISTER Status; + #define HOST_COALESCE_ERROR_ATTN BIT_2 + + /* Receive coalescing ticks. */ + T3_32BIT_REGISTER RxCoalescingTicks; + + /* Send coalescing ticks. */ + T3_32BIT_REGISTER TxCoalescingTicks; + + /* Receive max coalesced frames. */ + T3_32BIT_REGISTER RxMaxCoalescedFrames; + + /* Send max coalesced frames. */ + T3_32BIT_REGISTER TxMaxCoalescedFrames; + + /* Receive coalescing ticks during interrupt. */ + T3_32BIT_REGISTER RxCoalescedTickDuringInt; + + /* Send coalescing ticks during interrupt. */ + T3_32BIT_REGISTER TxCoalescedTickDuringInt; + + /* Receive max coalesced frames during interrupt. */ + T3_32BIT_REGISTER RxMaxCoalescedFramesDuringInt; + + /* Send max coalesced frames during interrupt. */ + T3_32BIT_REGISTER TxMaxCoalescedFramesDuringInt; + + /* Statistics tick. */ + T3_32BIT_REGISTER StatsCoalescingTicks; + + /* Unused space. */ + LM_UINT8 Unused2[4]; + + /* Statistics host address. */ + T3_64BIT_REGISTER StatsBlkHostAddr; + + /* Status block host address.*/ + T3_64BIT_REGISTER StatusBlkHostAddr; + + /* Statistics NIC address. */ + T3_32BIT_REGISTER StatsBlkNicAddr; + + /* Statust block NIC address. */ + T3_32BIT_REGISTER StatusBlkNicAddr; + + /* Flow attention registers. */ + T3_32BIT_REGISTER FlowAttn; + + /* Unused space. */ + LM_UINT8 Unused3[4]; + + T3_32BIT_REGISTER NicJumboRcvBdConIdx; + T3_32BIT_REGISTER NicStdRcvBdConIdx; + T3_32BIT_REGISTER NicMiniRcvBdConIdx; + + /* Unused space. */ + LM_UINT8 Unused4[36]; + + T3_32BIT_REGISTER NicRetProdIdx[16]; + T3_32BIT_REGISTER NicSndBdConIdx[16]; + + /* Unused space. */ + LM_UINT8 Unused5[768]; +} T3_HOST_COALESCING, *PT3_HOST_COALESCING; + + + +/******************************************************************************/ +/* Memory arbiter registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; +#define T3_MEM_ARBITER_MODE_RESET BIT_0 +#define T3_MEM_ARBITER_MODE_ENABLE BIT_1 + + T3_32BIT_REGISTER Status; + + T3_32BIT_REGISTER ArbTrapAddrLow; + T3_32BIT_REGISTER ArbTrapAddrHigh; + + /* Unused space. */ + LM_UINT8 Unused[1008]; +} T3_MEM_ARBITER, *PT3_MEM_ARBITER; + + + +/******************************************************************************/ +/* Buffer manager control register. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define BUFMGR_MODE_RESET BIT_0 + #define BUFMGR_MODE_ENABLE BIT_1 + #define BUFMGR_MODE_ATTN_ENABLE BIT_2 + #define BUFMGR_MODE_BM_TEST BIT_3 + #define BUFMGR_MODE_MBUF_LOW_ATTN_ENABLE BIT_4 + + T3_32BIT_REGISTER Status; + #define BUFMGR_STATUS_ERROR BIT_2 + #define BUFMGR_STATUS_MBUF_LOW BIT_4 + + T3_32BIT_REGISTER MbufPoolAddr; + T3_32BIT_REGISTER MbufPoolSize; + T3_32BIT_REGISTER MbufReadDmaLowWaterMark; + T3_32BIT_REGISTER MbufMacRxLowWaterMark; + T3_32BIT_REGISTER MbufHighWaterMark; + + T3_32BIT_REGISTER RxCpuMbufAllocReq; + #define BUFMGR_MBUF_ALLOC_BIT BIT_31 + T3_32BIT_REGISTER RxCpuMbufAllocResp; + T3_32BIT_REGISTER TxCpuMbufAllocReq; + T3_32BIT_REGISTER TxCpuMbufAllocResp; + + T3_32BIT_REGISTER DmaDescPoolAddr; + T3_32BIT_REGISTER DmaDescPoolSize; + T3_32BIT_REGISTER DmaLowWaterMark; + T3_32BIT_REGISTER DmaHighWaterMark; + + T3_32BIT_REGISTER RxCpuDmaAllocReq; + T3_32BIT_REGISTER RxCpuDmaAllocResp; + T3_32BIT_REGISTER TxCpuDmaAllocReq; + T3_32BIT_REGISTER TxCpuDmaAllocResp; + + T3_32BIT_REGISTER Hwdiag[3]; + + /* Unused space. */ + LM_UINT8 Unused[936]; +} T3_BUFFER_MANAGER, *PT3_BUFFER_MANAGER; + + + +/******************************************************************************/ +/* Read DMA control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define DMA_READ_MODE_RESET BIT_0 + #define DMA_READ_MODE_ENABLE BIT_1 + #define DMA_READ_MODE_TARGET_ABORT_ATTN_ENABLE BIT_2 + #define DMA_READ_MODE_MASTER_ABORT_ATTN_ENABLE BIT_3 + #define DMA_READ_MODE_PARITY_ERROR_ATTN_ENABLE BIT_4 + #define DMA_READ_MODE_ADDR_OVERFLOW_ATTN_ENABLE BIT_5 + #define DMA_READ_MODE_FIFO_OVERRUN_ATTN_ENABLE BIT_6 + #define DMA_READ_MODE_FIFO_UNDERRUN_ATTN_ENABLE BIT_7 + #define DMA_READ_MODE_FIFO_OVERREAD_ATTN_ENABLE BIT_8 + #define DMA_READ_MODE_LONG_READ_ATTN_ENABLE BIT_9 + + T3_32BIT_REGISTER Status; + #define DMA_READ_STATUS_TARGET_ABORT_ATTN BIT_2 + #define DMA_READ_STATUS_MASTER_ABORT_ATTN BIT_3 + #define DMA_READ_STATUS_PARITY_ERROR_ATTN BIT_4 + #define DMA_READ_STATUS_ADDR_OVERFLOW_ATTN BIT_5 + #define DMA_READ_STATUS_FIFO_OVERRUN_ATTN BIT_6 + #define DMA_READ_STATUS_FIFO_UNDERRUN_ATTN BIT_7 + #define DMA_READ_STATUS_FIFO_OVERREAD_ATTN BIT_8 + #define DMA_READ_STATUS_LONG_READ_ATTN BIT_9 + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_DMA_READ, *PT3_DMA_READ; + +typedef union T3_CPU +{ + struct + { + T3_32BIT_REGISTER mode; + #define CPU_MODE_HALT BIT_10 + #define CPU_MODE_RESET BIT_0 + T3_32BIT_REGISTER state; + T3_32BIT_REGISTER EventMask; + T3_32BIT_REGISTER reserved1[4]; + T3_32BIT_REGISTER PC; + T3_32BIT_REGISTER Instruction; + T3_32BIT_REGISTER SpadUnderflow; + T3_32BIT_REGISTER WatchdogClear; + T3_32BIT_REGISTER WatchdogVector; + T3_32BIT_REGISTER WatchdogSavedPC; + T3_32BIT_REGISTER HardwareBp; + T3_32BIT_REGISTER reserved2[3]; + T3_32BIT_REGISTER WatchdogSavedState; + T3_32BIT_REGISTER LastBrchAddr; + T3_32BIT_REGISTER SpadUnderflowSet; + T3_32BIT_REGISTER reserved3[(0x200-0x50)/4]; + T3_32BIT_REGISTER Regs[32]; + T3_32BIT_REGISTER reserved4[(0x400-0x280)/4]; + }reg; +}T3_CPU, *PT3_CPU; + +/******************************************************************************/ +/* Write DMA control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define DMA_WRITE_MODE_RESET BIT_0 + #define DMA_WRITE_MODE_ENABLE BIT_1 + #define DMA_WRITE_MODE_TARGET_ABORT_ATTN_ENABLE BIT_2 + #define DMA_WRITE_MODE_MASTER_ABORT_ATTN_ENABLE BIT_3 + #define DMA_WRITE_MODE_PARITY_ERROR_ATTN_ENABLE BIT_4 + #define DMA_WRITE_MODE_ADDR_OVERFLOW_ATTN_ENABLE BIT_5 + #define DMA_WRITE_MODE_FIFO_OVERRUN_ATTN_ENABLE BIT_6 + #define DMA_WRITE_MODE_FIFO_UNDERRUN_ATTN_ENABLE BIT_7 + #define DMA_WRITE_MODE_FIFO_OVERREAD_ATTN_ENABLE BIT_8 + #define DMA_WRITE_MODE_LONG_READ_ATTN_ENABLE BIT_9 + + T3_32BIT_REGISTER Status; + #define DMA_WRITE_STATUS_TARGET_ABORT_ATTN BIT_2 + #define DMA_WRITE_STATUS_MASTER_ABORT_ATTN BIT_3 + #define DMA_WRITE_STATUS_PARITY_ERROR_ATTN BIT_4 + #define DMA_WRITE_STATUS_ADDR_OVERFLOW_ATTN BIT_5 + #define DMA_WRITE_STATUS_FIFO_OVERRUN_ATTN BIT_6 + #define DMA_WRITE_STATUS_FIFO_UNDERRUN_ATTN BIT_7 + #define DMA_WRITE_STATUS_FIFO_OVERREAD_ATTN BIT_8 + #define DMA_WRITE_STATUS_LONG_READ_ATTN BIT_9 + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_DMA_WRITE, *PT3_DMA_WRITE; + + + +/******************************************************************************/ +/* Mailbox registers. */ +/******************************************************************************/ + +typedef struct { + /* Interrupt mailbox registers. */ + T3_64BIT_REGISTER Interrupt[4]; + + /* General mailbox registers. */ + T3_64BIT_REGISTER General[8]; + + /* Reload statistics mailbox. */ + T3_64BIT_REGISTER ReloadStat; + + /* Receive BD ring producer index registers. */ + T3_64BIT_REGISTER RcvStdProdIdx; + T3_64BIT_REGISTER RcvJumboProdIdx; + T3_64BIT_REGISTER RcvMiniProdIdx; + + /* Receive return ring consumer index registers. */ + T3_64BIT_REGISTER RcvRetConIdx[16]; + + /* Send BD ring host producer index registers. */ + T3_64BIT_REGISTER SendHostProdIdx[16]; + + /* Send BD ring nic producer index registers. */ + T3_64BIT_REGISTER SendNicProdIdx[16]; +}T3_MAILBOX, *PT3_MAILBOX; + +typedef struct { + T3_MAILBOX Mailbox; + + /* Priority mailbox registers. */ + T3_32BIT_REGISTER HighPriorityEventVector; + T3_32BIT_REGISTER HighPriorityEventMask; + T3_32BIT_REGISTER LowPriorityEventVector; + T3_32BIT_REGISTER LowPriorityEventMask; + + /* Unused space. */ + LM_UINT8 Unused[496]; +} T3_GRC_MAILBOX, *PT3_GRC_MAILBOX; + + +/******************************************************************************/ +/* Flow through queues. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Reset; + + LM_UINT8 Unused[12]; + + T3_32BIT_REGISTER DmaNormalReadFtqCtrl; + T3_32BIT_REGISTER DmaNormalReadFtqFullCnt; + T3_32BIT_REGISTER DmaNormalReadFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaNormalReadFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaHighReadFtqCtrl; + T3_32BIT_REGISTER DmaHighReadFtqFullCnt; + T3_32BIT_REGISTER DmaHighReadFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaHighReadFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaCompDiscardFtqCtrl; + T3_32BIT_REGISTER DmaCompDiscardFtqFullCnt; + T3_32BIT_REGISTER DmaCompDiscardFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaCompDiscardFtqFifoWritePeek; + + T3_32BIT_REGISTER SendBdCompFtqCtrl; + T3_32BIT_REGISTER SendBdCompFtqFullCnt; + T3_32BIT_REGISTER SendBdCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SendBdCompFtqFifoWritePeek; + + T3_32BIT_REGISTER SendDataInitiatorFtqCtrl; + T3_32BIT_REGISTER SendDataInitiatorFtqFullCnt; + T3_32BIT_REGISTER SendDataInitiatorFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SendDataInitiatorFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaNormalWriteFtqCtrl; + T3_32BIT_REGISTER DmaNormalWriteFtqFullCnt; + T3_32BIT_REGISTER DmaNormalWriteFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaNormalWriteFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaHighWriteFtqCtrl; + T3_32BIT_REGISTER DmaHighWriteFtqFullCnt; + T3_32BIT_REGISTER DmaHighWriteFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaHighWriteFtqFifoWritePeek; + + T3_32BIT_REGISTER SwType1FtqCtrl; + T3_32BIT_REGISTER SwType1FtqFullCnt; + T3_32BIT_REGISTER SwType1FtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SwType1FtqFifoWritePeek; + + T3_32BIT_REGISTER SendDataCompFtqCtrl; + T3_32BIT_REGISTER SendDataCompFtqFullCnt; + T3_32BIT_REGISTER SendDataCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SendDataCompFtqFifoWritePeek; + + T3_32BIT_REGISTER HostCoalesceFtqCtrl; + T3_32BIT_REGISTER HostCoalesceFtqFullCnt; + T3_32BIT_REGISTER HostCoalesceFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER HostCoalesceFtqFifoWritePeek; + + T3_32BIT_REGISTER MacTxFtqCtrl; + T3_32BIT_REGISTER MacTxFtqFullCnt; + T3_32BIT_REGISTER MacTxFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER MacTxFtqFifoWritePeek; + + T3_32BIT_REGISTER MbufClustFreeFtqCtrl; + T3_32BIT_REGISTER MbufClustFreeFtqFullCnt; + T3_32BIT_REGISTER MbufClustFreeFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER MbufClustFreeFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvBdCompFtqCtrl; + T3_32BIT_REGISTER RcvBdCompFtqFullCnt; + T3_32BIT_REGISTER RcvBdCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvBdCompFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvListPlmtFtqCtrl; + T3_32BIT_REGISTER RcvListPlmtFtqFullCnt; + T3_32BIT_REGISTER RcvListPlmtFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvListPlmtFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvDataBdInitiatorFtqCtrl; + T3_32BIT_REGISTER RcvDataBdInitiatorFtqFullCnt; + T3_32BIT_REGISTER RcvDataBdInitiatorFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvDataBdInitiatorFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvDataCompFtqCtrl; + T3_32BIT_REGISTER RcvDataCompFtqFullCnt; + T3_32BIT_REGISTER RcvDataCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvDataCompFtqFifoWritePeek; + + T3_32BIT_REGISTER SwType2FtqCtrl; + T3_32BIT_REGISTER SwType2FtqFullCnt; + T3_32BIT_REGISTER SwType2FtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SwType2FtqFifoWritePeek; + + /* Unused space. */ + LM_UINT8 Unused2[736]; +} T3_FTQ, *PT3_FTQ; + + + +/******************************************************************************/ +/* Message signaled interrupt registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; +#define MSI_MODE_RESET BIT_0 +#define MSI_MODE_ENABLE BIT_1 + T3_32BIT_REGISTER Status; + + T3_32BIT_REGISTER MsiFifoAccess; + + /* Unused space. */ + LM_UINT8 Unused[1012]; +} T3_MSG_SIGNALED_INT, *PT3_MSG_SIGNALED_INT; + + + +/******************************************************************************/ +/* DMA Completion registes. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define DMA_COMP_MODE_RESET BIT_0 + #define DMA_COMP_MODE_ENABLE BIT_1 + + /* Unused space. */ + LM_UINT8 Unused[1020]; +} T3_DMA_COMPLETION, *PT3_DMA_COMPLETION; + + + +/******************************************************************************/ +/* GRC registers. */ +/******************************************************************************/ + +typedef struct { + /* Mode control register. */ + T3_32BIT_REGISTER Mode; + #define GRC_MODE_UPDATE_ON_COALESCING BIT_0 + #define GRC_MODE_BYTE_SWAP_NON_FRAME_DATA BIT_1 + #define GRC_MODE_WORD_SWAP_NON_FRAME_DATA BIT_2 + #define GRC_MODE_BYTE_SWAP_DATA BIT_4 + #define GRC_MODE_WORD_SWAP_DATA BIT_5 + #define GRC_MODE_SPLIT_HEADER_MODE BIT_8 + #define GRC_MODE_NO_FRAME_CRACKING BIT_9 + #define GRC_MODE_INCLUDE_CRC BIT_10 + #define GRC_MODE_ALLOW_BAD_FRAMES BIT_11 + #define GRC_MODE_NO_INTERRUPT_ON_SENDS BIT_13 + #define GRC_MODE_NO_INTERRUPT_ON_RECEIVE BIT_14 + #define GRC_MODE_FORCE_32BIT_PCI_BUS_MODE BIT_15 + #define GRC_MODE_HOST_STACK_UP BIT_16 + #define GRC_MODE_HOST_SEND_BDS BIT_17 + #define GRC_MODE_TX_NO_PSEUDO_HEADER_CHKSUM BIT_20 + #define GRC_MODE_RX_NO_PSEUDO_HEADER_CHKSUM BIT_23 + #define GRC_MODE_INT_ON_TX_CPU_ATTN BIT_24 + #define GRC_MODE_INT_ON_RX_CPU_ATTN BIT_25 + #define GRC_MODE_INT_ON_MAC_ATTN BIT_26 + #define GRC_MODE_INT_ON_DMA_ATTN BIT_27 + #define GRC_MODE_INT_ON_FLOW_ATTN BIT_28 + #define GRC_MODE_4X_NIC_BASED_SEND_RINGS BIT_29 + #define GRC_MODE_MULTICAST_FRAME_ENABLE BIT_30 + + /* Misc configuration register. */ + T3_32BIT_REGISTER MiscCfg; + #define GRC_MISC_CFG_CORE_CLOCK_RESET BIT_0 + #define GRC_MISC_PRESCALAR_TIMER_MASK 0xfe + #define GRC_MISC_BD_ID_MASK 0x0001e000 + #define GRC_MISC_BD_ID_5700 0x0001e000 + #define GRC_MISC_BD_ID_5701 0x00000000 + #define GRC_MISC_BD_ID_5703 0x00000000 + #define GRC_MISC_BD_ID_5703S 0x00002000 + #define GRC_MISC_BD_ID_5702FE 0x00004000 + + /* Miscellaneous local control register. */ + T3_32BIT_REGISTER LocalCtrl; + #define GRC_MISC_LOCAL_CTRL_INT_ACTIVE BIT_0 + #define GRC_MISC_LOCAL_CTRL_CLEAR_INT BIT_1 + #define GRC_MISC_LOCAL_CTRL_SET_INT BIT_2 + #define GRC_MISC_LOCAL_CTRL_INT_ON_ATTN BIT_3 + #define GRC_MISC_LOCAL_CTRL_GPIO_INPUT0 BIT_8 + #define GRC_MISC_LOCAL_CTRL_GPIO_INPUT1 BIT_9 + #define GRC_MISC_LOCAL_CTRL_GPIO_INPUT2 BIT_10 + #define GRC_MISC_LOCAL_CTRL_GPIO_OE0 BIT_11 + #define GRC_MISC_LOCAL_CTRL_GPIO_OE1 BIT_12 + #define GRC_MISC_LOCAL_CTRL_GPIO_OE2 BIT_13 + #define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 BIT_14 + #define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 BIT_15 + #define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2 BIT_16 + #define GRC_MISC_LOCAL_CTRL_ENABLE_EXT_MEMORY BIT_17 + #define GRC_MISC_LOCAL_CTRL_BANK_SELECT BIT_21 + #define GRC_MISC_LOCAL_CTRL_SSRAM_TYPE BIT_22 + + #define GRC_MISC_MEMSIZE_256K 0 + #define GRC_MISC_MEMSIZE_512K (1 << 18) + #define GRC_MISC_MEMSIZE_1024K (2 << 18) + #define GRC_MISC_MEMSIZE_2048K (3 << 18) + #define GRC_MISC_MEMSIZE_4096K (4 << 18) + #define GRC_MISC_MEMSIZE_8192K (5 << 18) + #define GRC_MISC_MEMSIZE_16M (6 << 18) + #define GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM BIT_24 + + + T3_32BIT_REGISTER Timer; + + T3_32BIT_REGISTER RxCpuEvent; + T3_32BIT_REGISTER RxTimerRef; + T3_32BIT_REGISTER RxCpuSemaphore; + T3_32BIT_REGISTER RemoteRxCpuAttn; + + T3_32BIT_REGISTER TxCpuEvent; + T3_32BIT_REGISTER TxTimerRef; + T3_32BIT_REGISTER TxCpuSemaphore; + T3_32BIT_REGISTER RemoteTxCpuAttn; + + T3_64BIT_REGISTER MemoryPowerUp; + + T3_32BIT_REGISTER EepromAddr; + #define SEEPROM_ADDR_WRITE 0 + #define SEEPROM_ADDR_READ (1 << 31) + #define SEEPROM_ADDR_RW_MASK 0x80000000 + #define SEEPROM_ADDR_COMPLETE (1 << 30) + #define SEEPROM_ADDR_FSM_RESET (1 << 29) + #define SEEPROM_ADDR_DEV_ID(x) (x << 26) + #define SEEPROM_ADDR_DEV_ID_MASK 0x1c000000 + #define SEEPROM_ADDR_START (1 << 25) + #define SEEPROM_ADDR_CLK_PERD(x) (x << 16) + #define SEEPROM_ADDR_ADDRESS(x) (x & 0xfffc) + #define SEEPROM_ADDR_ADDRESS_MASK 0x0000ffff + + #define SEEPROM_CLOCK_PERIOD 60 + #define SEEPROM_CHIP_SIZE (64 * 1024) + + T3_32BIT_REGISTER EepromData; + T3_32BIT_REGISTER EepromCtrl; + + T3_32BIT_REGISTER MdiCtrl; + T3_32BIT_REGISTER SepromDelay; + + /* Unused space. */ + LM_UINT8 Unused[948]; +} T3_GRC, *PT3_GRC; + + +/******************************************************************************/ +/* NVRAM control registers. */ +/******************************************************************************/ + +typedef struct +{ + T3_32BIT_REGISTER Cmd; + #define NVRAM_CMD_RESET BIT_0 + #define NVRAM_CMD_DONE BIT_3 + #define NVRAM_CMD_DO_IT BIT_4 + #define NVRAM_CMD_WR BIT_5 + #define NVRAM_CMD_RD BIT_NONE + #define NVRAM_CMD_ERASE BIT_6 + #define NVRAM_CMD_FIRST BIT_7 + #define NVRAM_CMD_LAST BIT_8 + + T3_32BIT_REGISTER Status; + T3_32BIT_REGISTER WriteData; + + T3_32BIT_REGISTER Addr; + #define NVRAM_ADDRESS_MASK 0xffffff + + T3_32BIT_REGISTER ReadData; + + /* Flash config 1 register. */ + T3_32BIT_REGISTER Config1; + #define FLASH_INTERFACE_ENABLE BIT_0 + #define FLASH_SSRAM_BUFFERRED_MODE BIT_1 + #define FLASH_PASS_THRU_MODE BIT_2 + #define FLASH_BIT_BANG_MODE BIT_3 + #define FLASH_COMPAT_BYPASS BIT_31 + + /* Buffered flash (Atmel: AT45DB011B) specific information */ + #define BUFFERED_FLASH_PAGE_POS 9 + #define BUFFERED_FLASH_BYTE_ADDR_MASK ((1<UndiFix) ? \ + LM_RegWrInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600, \ + Value32) : \ + (void) __raw_writel(Value32, &((pDevice)->pMemView->OffsetName)) + +#define MB_REG_RD(pDevice, OffsetName) \ + (((pDevice)->UndiFix) ? \ + LM_RegRdInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600) : \ + __raw_readl(&((pDevice)->pMemView->OffsetName))) + +#define REG_RD(pDevice, OffsetName) \ + LM_RegRd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)) + +#define REG_WR(pDevice, OffsetName, Value32) \ + LM_RegWr(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName), Value32) + +#define REG_RD_OFFSET(pDevice, Offset) \ + __raw_readl(((LM_UINT8 *) (pDevice)->pMemView + Offset)) + +#define REG_WR_OFFSET(pDevice, Offset, Value32) \ + __raw_writel(Value32, ((LM_UINT8 *) (pDevice)->pMemView + Offset)) + +#define MEM_RD(pDevice, AddrName) \ + LM_MemRdInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName)) +#define MEM_WR(pDevice, AddrName, Value32) \ + LM_MemWrInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName), Value32) + +#define MEM_RD_OFFSET(pDevice, Offset) \ + LM_MemRdInd(pDevice, Offset) +#define MEM_WR_OFFSET(pDevice, Offset, Value32) \ + LM_MemWrInd(pDevice, Offset, Value32) + + +#if 0 +/* MAC register access. */ +LM_UINT32 LM_RegRdInd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register); +LM_VOID LM_RegWrInd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register, + LM_UINT32 Value32); + +/* MAC memory access. */ +LM_UINT32 LM_MemRdInd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr); +LM_VOID LM_MemWrInd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 MemAddr, + LM_UINT32 Value32); + +#define MB_REG_WR(pDevice, OffsetName, Value32) \ + ((pDevice)->UndiFix) ? \ + LM_RegWrInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600, \ + Value32) : \ + (void) __raw_writel(Value32, &((pDevice)->pMemView->OffsetName)) + +#define MB_REG_RD(pDevice, OffsetName) \ + (((pDevice)->UndiFix) ? \ + LM_RegRdInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600) : \ + __raw_readl(&((pDevice)->pMemView->OffsetName))) + +#define REG_RD(pDevice, OffsetName) \ + (((pDevice)->UndiFix) ? \ + LM_RegRdInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)) : \ + __raw_readl(&((pDevice)->pMemView->OffsetName))) + +#if PCIX_TARGET_WORKAROUND + +/* use memor-mapped accesses for mailboxes and reads, UNDI accesses + for writes to all other registers */ +#define REG_WR(pDevice, OffsetName, Value32) \ + ((pDevice)->EnablePciXFix == FALSE) ? \ + (void) __raw_writel(Value32, &((pDevice)->pMemView->OffsetName)) : \ + LM_RegWrInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName), Value32) + + +#define MEM_RD(pDevice, AddrName) \ + LM_MemRdInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName)) +#define MEM_WR(pDevice, AddrName, Value32) \ + LM_MemWrInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName), Value32) + +#define MEM_RD_OFFSET(pDevice, Offset) \ + LM_MemRdInd(pDevice, Offset) +#define MEM_WR_OFFSET(pDevice, Offset, Value32) \ + LM_MemWrInd(pDevice, Offset, Value32) + +#else /* normal target access path below */ + +/* Register access. */ +#define REG_RD(pDevice, OffsetName) \ + __raw_readl(&((pDevice)->pMemView->OffsetName)) +#define REG_WR(pDevice, OffsetName, Value32) \ + __raw_writel(Value32, &((pDevice)->pMemView->OffsetName)) + +/* There could be problem access the memory window directly. For now, */ +/* we have to go through the PCI configuration register. */ +#define MEM_RD(pDevice, AddrName) \ + LM_MemRdInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName)) +#define MEM_WR(pDevice, AddrName, Value32) \ + LM_MemWrInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName), Value32) + +#define MEM_RD_OFFSET(pDevice, Offset) \ + LM_MemRdInd(pDevice, Offset) +#define MEM_WR_OFFSET(pDevice, Offset, Value32) \ + LM_MemWrInd(pDevice, Offset, Value32) + +#endif /* PCIX_TARGET_WORKAROUND */ + +#endif +#endif /* TIGON3_H */ + diff -Nur linux-2.4.19/drivers/net/e1000/Makefile linux-2.4.19-sgi211r3/drivers/net/e1000/Makefile --- linux-2.4.19/drivers/net/e1000/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/Makefile Tue Aug 27 19:53:13 2002 @@ -0,0 +1,92 @@ +################################################################################ +# +# This software program is available to you under a choice of one of two +# licenses. You may choose to be licensed under either the GNU General Public +# License (GPL) Version 2, June 1991, available at +# http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the +# text of which follows: +# +# Recipient has requested a license and Intel Corporation ("Intel") is willing +# to grant a license for the software entitled Linux Base Driver for the +# Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided +# by Intel Corporation. The following definitions apply to this license: +# +# "Licensed Patents" means patent claims licensable by Intel Corporation which +# are necessarily infringed by the use of sale of the Software alone or when +# combined with the operating system referred to below. +# +# "Recipient" means the party to whom Intel delivers this Software. +# +# "Licensee" means Recipient and those third parties that receive a license to +# any operating system available under the GNU Public License version 2.0 or +# later. +# +# Copyright (c) 1999 - 2002 Intel Corporation. +# All rights reserved. +# +# The license is provided to Recipient and Recipient's Licensees under the +# following terms. +# +# Redistribution and use in source and binary forms of the Software, with or +# without modification, are permitted provided that the following conditions +# are met: +# +# Redistributions of source code of the Software may retain the above +# copyright notice, this list of conditions and the following disclaimer. +# +# Redistributions in binary form of the Software may reproduce the above +# copyright notice, this list of conditions and the following disclaimer in +# the documentation and/or materials provided with the distribution. +# +# Neither the name of Intel Corporation nor the names of its contributors +# shall be used to endorse or promote products derived from this Software +# without specific prior written permission. +# +# Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, +# royalty-free patent license under Licensed Patents to make, use, sell, offer +# to sell, import and otherwise transfer the Software, if any, in source code +# and object code form. This license shall include changes to the Software +# that are error corrections or other minor changes to the Software that do +# not add functionality or features when the Software is incorporated in any +# version of an operating system that has been distributed under the GNU +# General Public License 2.0 or later. This patent license shall apply to the +# combination of the Software and any operating system licensed under the GNU +# Public License version 2.0 or later if, at the time Intel provides the +# Software to Recipient, such addition of the Software to the then publicly +# available versions of such operating systems available under the GNU Public +# License version 2.0 or later (whether in gold, beta or alpha form) causes +# such combination to be covered by the Licensed Patents. The patent license +# shall not apply to any other combinations which include the Software. NO +# hardware per se is licensed hereunder. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. +# +################################################################################ + +########################################################################### +# Configuration Section + +# Optional features - set to 'y' for on, anything else for off +# Intel(R) Advanced Network Services +IANS := n +# Intel(R) PRO Diagnostics +IDIAG := n + +########################################################################### +# Driver files + +# core driver files +O_TARGET := e1000.o +obj-y := e1000_main.o e1000_mac.o e1000_phy.o e1000_proc.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/net/e1000/e1000.h linux-2.4.19-sgi211r3/drivers/net/e1000/e1000.h --- linux-2.4.19/drivers/net/e1000/e1000.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,362 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + + +/* Linux PRO/1000 Ethernet Driver main header file */ + +#ifndef _E1000_H_ +#define _E1000_H_ + +#ifndef __E1000_MAIN__ +#define __NO_VERSION__ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ethtool support */ +#ifdef SIOCETHTOOL +#include +#include +#define E1000_ETHTOOL_COPPER_INTERFACE_SUPPORTS (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | \ + SUPPORTED_Autoneg | SUPPORTED_MII) +#define E1000_ETHTOOL_COPPER_INTERFACE_ADVERTISE (ADVERTISED_10baseT_Half | \ + ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | \ + ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full | \ + ADVERTISED_Autoneg | ADVERTISED_MII) +#define E1000_ETHTOOL_FIBER_INTERFACE_SUPPORTS (SUPPORTED_Autoneg | \ + SUPPORTED_FIBRE) +#define E1000_ETHTOOL_FIBER_INTERFACE_ADVERTISE (ADVERTISED_Autoneg | \ + ADVERTISED_FIBRE) +#endif /* SIOCETHTOOL */ + + + +struct e1000_adapter; + +#include "e1000_mac.h" +#include "e1000_phy.h" + +#ifdef IANS +#include "base_comm.h" +#include "ans_driver.h" +#include "ans.h" +#endif + +#ifdef IDIAG +#include "idiag_pro.h" +#include "idiag_e1000.h" +#endif + +#define BAR_0 0 + +/* 8254x can use Dual Address Cycles for 64-bit addressing */ + +/* Advertise that we can DMA from any address location */ +#define E1000_DMA_MASK (~0x0UL) +#define E1000_DBG(args...) +// #define E1000_DBG(args...) printk("e1000: " args) +#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args) +#ifdef CONFIG_PPC +#define E1000_MAX_INTR 1 +#else +#define E1000_MAX_INTR 10 +#endif +#define MAX_NUM_MULTICAST_ADDRESSES 128 + +/* command line options defaults */ +#define DEFAULT_TXD 256 +#define MAX_TXD 256 +#define MIN_TXD 80 +#define MAX_82544_TXD 4096 +#define DEFAULT_RXD 256 +#define MAX_RXD 256 +#define MIN_RXD 80 +#define MAX_82544_RXD 4096 +#define DEFAULT_TIDV 64 +#define MAX_TIDV 0xFFFF +#define MIN_TIDV 0 +#define DEFAULT_RIDV 64 +#define MAX_RIDV 0xFFFF +#define MIN_RIDV 0 +#define DEFAULT_MDIX 0 +#define MAX_MDIX 3 +#define MIN_MDIX 0 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 +#define XSUMRX_DEFAULT OPTION_ENABLED +#define WAITFORLINK_DEFAULT OPTION_ENABLED +#define AUTONEG_ADV_DEFAULT 0x2F +#define AUTONEG_ADV_MASK 0x2F +#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL + +#define E1000_REPORT_TX_EARLY 2 + +/* Supported RX Buffer Sizes */ +#define E1000_RXBUFFER_2048 2048 +#define E1000_RXBUFFER_4096 4096 +#define E1000_RXBUFFER_8192 8192 +#define E1000_RXBUFFER_16384 16384 + +#define E1000_JUMBO_PBA 0x00000028 +#define E1000_DEFAULT_PBA 0x00000030 + +/* Round size up to the next multiple of unit */ +#define E1000_ROUNDUP(size, unit) ((((size) + (unit) - 1) / (unit)) * (unit)) + +/* This is better, but only works for unit sizes that are powers of 2 */ +#define E1000_ROUNDUP2(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) + +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ +struct e1000_buffer { + struct sk_buff *skb; + uint64_t dma; + unsigned long length; +}; + +/* Adapter->flags definitions */ +#define E1000_BOARD_OPEN 0 +#define E1000_RX_REFILL 1 +#define E1000_DIAG_OPEN 2 +#define E1000_LINK_STATUS_CHANGED 3 + +typedef enum _XSUM_CONTEXT_T { + OFFLOAD_NONE, + OFFLOAD_TCP_IP, + OFFLOAD_UDP_IP +} XSUM_CONTEXT_T; + +struct e1000_desc_ring { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical address of the descriptor ring */ + unsigned int size; /* length of descriptor ring in bytes */ + unsigned int count; /* number of descriptors in the ring */ + atomic_t unused; /* number of descriptors with no buffer */ + unsigned int next_to_use; /* next descriptor to associate a buffer with */ + unsigned int next_to_clean; /* next descriptor to check for DD status bit */ + struct e1000_buffer *buffer_info; /* array of buffer information structs */ +}; + +#define E1000_RX_DESC(ring, i) \ + (&(((struct e1000_rx_desc *)(ring.desc))[i])) + +#define E1000_TX_DESC(ring, i) \ + (&(((struct e1000_tx_desc *)(ring.desc))[i])) + +#define E1000_CONTEXT_DESC(ring, i) \ + (&(((struct e1000_context_desc *)(ring.desc))[i])) + +/* board specific private data structure */ + +struct e1000_adapter { + struct e1000_adapter *next; + struct e1000_adapter *prev; + + struct e1000_shared_adapter shared; + +#ifdef IANS + void *iANSReserved; + piANSsupport_t iANSdata; + uint32_t ans_link; + uint32_t ans_speed; + uint32_t ans_duplex; + uint32_t ans_suspend; + IANS_BD_TAGGING_MODE tag_mode; +#endif + + spinlock_t stats_lock; + spinlock_t rx_fill_lock; + + unsigned long flags; + uint32_t bd_number; + struct timer_list timer_id; + + /* Ethernet Node Address */ + uint8_t perm_net_addr[ETH_LENGTH_OF_ADDRESS]; + + /* Status Flags */ + boolean_t link_active; + uint16_t link_speed; + uint16_t link_duplex; + uint32_t rx_buffer_len; + + /* PCI Device Info */ + uint16_t vendor_id; + uint16_t device_id; + uint8_t rev_id; + uint16_t subven_id; + uint16_t subsys_id; + + uint32_t part_num; + + uint32_t int_mask; + + /* driver specific */ + struct tasklet_struct rx_fill_tasklet; + + struct e1000_desc_ring tx_ring; + uint32_t tx_int_delay; + uint32_t TxdCmd; + atomic_t tx_timeout; + + struct e1000_desc_ring rx_ring; + uint32_t rx_int_delay; + + uint64_t XsumRXGood; + uint64_t XsumRXError; + + /* Linux driver specific */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + char *id_string; + boolean_t RxChecksum; + XSUM_CONTEXT_T ActiveChecksumContext; + + struct e1000_phy_info phy_info; + struct e1000_shared_stats stats; + + /* PHY Statistics */ + struct e1000_phy_stats phy_stats; +}; + +/* Prototypes */ + +/* e1000_main.c */ +extern int e1000_init_module(void); +extern int e1000_probe_all(void); +extern void e1000_exit_module(void); +extern int e1000_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +extern void e1000_remove(struct pci_dev *pdev); +extern void e1000_delete(struct e1000_adapter *Adapter); +extern int e1000_open(struct net_device *netdev); +extern int e1000_close(struct net_device *netdev); +extern void e1000_set_multi(struct net_device *netdev); +extern int e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev); +extern struct net_device_stats *e1000_get_stats(struct net_device *netdev); +extern int e1000_change_mtu(struct net_device *netdev, + int new_mtu); +extern int e1000_set_mac(struct net_device *netdev, + void *p); +extern void e1000_intr(int irq, + void *data, + struct pt_regs *regs); +extern int e1000_ioctl(struct net_device *netdev, + struct ifreq *ifr, + int cmd); +extern void e1000_watchdog(unsigned long data); +extern void e1000_diag_ioctl(struct net_device *netdev, + struct ifreq *ifr); + +#ifdef CONFIG_PROC_FS +#include "e1000_proc.h" +#endif +#ifdef IDIAG +#include "e1000_idiag.h" +#endif +#endif /* _E1000_H_ */ diff -Nur linux-2.4.19/drivers/net/e1000/e1000_mac.c linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_mac.c --- linux-2.4.19/drivers/net/e1000/e1000_mac.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_mac.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,2093 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + +/* e1000_mac.c + * Shared functions for accessing and configuring the MAC + */ + +#include "e1000_mac.h" +#include "e1000_phy.h" + +/****************************************************************************** + * Raises the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +e1000_raise_clock(struct e1000_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Raise the clock input to the EEPROM (by setting the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg | E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Lowers the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +e1000_lower_clock(struct e1000_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Lower the clock input to the EEPROM (by clearing the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg & ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Shift data bits out to the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * data - data to send to the EEPROM + * count - number of bits to shift out + *****************************************************************************/ +static void +e1000_shift_out_bits(struct e1000_shared_adapter *shared, + uint16_t data, + uint16_t count) +{ + uint32_t eecd_reg; + uint32_t mask; + + /* We need to shift "count" bits out to the EEPROM. So, value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + */ + mask = 0x01 << (count - 1); + eecd_reg = E1000_READ_REG(shared, EECD); + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + do { + /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", + * and then raising and then lowering the clock (the SK bit controls + * the clock input to the EEPROM). A "0" is shifted out to the EEPROM + * by setting "DI" to "0" and then raising and then lowering the clock. + */ + eecd_reg &= ~E1000_EECD_DI; + + if(data & mask) + eecd_reg |= E1000_EECD_DI; + + E1000_WRITE_REG(shared, EECD, eecd_reg); + + usec_delay(50); + + e1000_raise_clock(shared, &eecd_reg); + e1000_lower_clock(shared, &eecd_reg); + + mask = mask >> 1; + + } while(mask); + + /* We leave the "DI" bit set to "0" when we leave this routine. */ + eecd_reg &= ~E1000_EECD_DI; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} + +/****************************************************************************** + * Shift data bits in from the EEPROM + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static uint16_t +e1000_shift_in_bits(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + uint32_t i; + uint16_t data; + + /* In order to read a register from the EEPROM, we need to shift 16 bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the "DO" + * bit. During this "shifting in" process the "DI" bit should always be + * clear.. + */ + + eecd_reg = E1000_READ_REG(shared, EECD); + + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; + + for(i = 0; i < 16; i++) { + data = data << 1; + e1000_raise_clock(shared, &eecd_reg); + + eecd_reg = E1000_READ_REG(shared, EECD); + + eecd_reg &= ~(E1000_EECD_DI); + if(eecd_reg & E1000_EECD_DO) + data |= 1; + + e1000_lower_clock(shared, &eecd_reg); + } + + return data; +} + +/****************************************************************************** + * Prepares EEPROM for access + * + * shared - Struct containing variables accessed by shared code + * + * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This + * function should be called before issuing a command to the EEPROM. + *****************************************************************************/ +static void +e1000_setup_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Clear SK and DI */ + eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI); + E1000_WRITE_REG(shared, EECD, eecd_reg); + + /* Set CS */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} + +/****************************************************************************** + * Returns EEPROM to a "standby" state + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +e1000_standby_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Deselct EEPROM */ + eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock high */ + eecd_reg |= E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Select EEPROM */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock low */ + eecd_reg &= ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Raises then lowers the EEPROM's clock pin + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +e1000_clock_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Rising edge of clock */ + eecd_reg |= E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Falling edge of clock */ + eecd_reg &= ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Terminates a command by lowering the EEPROM's chip select pin + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +e1000_cleanup_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_DI); + + E1000_WRITE_REG(shared, EECD, eecd_reg); + + e1000_clock_eeprom(shared); + return; +} + +/****************************************************************************** + * Waits for the EEPROM to finish the current command. + * + * shared - Struct containing variables accessed by shared code + * + * The command is done when the EEPROM's data out pin goes high. + *****************************************************************************/ +static uint16_t +e1000_wait_eeprom_command(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + uint32_t i; + + + /* Toggle the CS line. This in effect tells to EEPROM to actually execute + * the command in question. + */ + e1000_standby_eeprom(shared); + + /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will + * signal that the command has been completed by raising the DO signal. + * If DO does not go high in 10 milliseconds, then error out. + */ + for(i = 0; i < 200; i++) { + eecd_reg = E1000_READ_REG(shared, EECD); + + if(eecd_reg & E1000_EECD_DO) + return (TRUE); + + usec_delay(50); + } + ASSERT(0); + return (FALSE); +} + +/****************************************************************************** + * Forces the MAC's flow control settings. + * + * shared - Struct containing variables accessed by shared code + * + * Sets the TFCE and RFCE bits in the device control register to reflect + * the adapter settings. TFCE and RFCE need to be explicitly set by + * software when a Copper PHY is used because autonegotiation is managed + * by the PHY rather than the MAC. Software must also configure these + * bits when link is forced on a fiber connection. + *****************************************************************************/ +static void +e1000_force_mac_fc(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + + DEBUGFUNC("e1000_force_mac_fc"); + + /* Get the current configuration of the Device Control Register */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "shared->fc" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + + switch (shared->fc) { + case e1000_fc_none: + ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + case e1000_fc_rx_pause: + ctrl_reg &= (~E1000_CTRL_TFCE); + ctrl_reg |= E1000_CTRL_RFCE; + break; + case e1000_fc_tx_pause: + ctrl_reg &= (~E1000_CTRL_RFCE); + ctrl_reg |= E1000_CTRL_TFCE; + break; + case e1000_fc_full: + ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Disable TX Flow Control for 82542 (rev 2.0) */ + if(shared->mac_type == e1000_82542_rev2_0) + ctrl_reg &= (~E1000_CTRL_TFCE); + + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; +} + +/****************************************************************************** + * Reset the transmit and receive units; mask and clear all interrupts. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_adapter_stop(struct e1000_shared_adapter *shared) +{ +#if DBG + uint32_t ctrl_reg; +#endif + uint32_t ctrl_ext_reg; + uint32_t icr_reg; + uint16_t pci_cmd_word; + + DEBUGFUNC("e1000_shared_adapter_stop"); + + /* If we are stopped or resetting exit gracefully and wait to be + * started again before accessing the hardware. + */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is already stopped!!!\n"); + return; + } + + /* Set the Adapter Stopped flag so other driver functions stop + * touching the Hardware. + */ + shared->adapter_stopped = TRUE; + + /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; + + e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); + } + } + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Disable the Transmit and Receive units. Then delay to allow + * any pending transactions to complete before we hit the MAC with + * the global reset. + */ + E1000_WRITE_REG(shared, RCTL, 0); + E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP); + + /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */ + shared->tbi_compatibility_on = FALSE; + + msec_delay(10); + + /* Issue a global reset to the MAC. This will reset the chip's + * transmit, receive, DMA, and link units. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + DEBUGOUT("Issuing a global reset to MAC\n"); + E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST); + + /* Delay a few ms just to allow the reset to complete */ + msec_delay(10); + +#if DBG + /* Make sure the self-clearing global reset bit did self clear */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ASSERT(!(ctrl_reg & E1000_CTRL_RST)); +#endif + + /* Force a reload from the EEPROM */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + msec_delay(2); + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Clear any pending interrupt events. */ + icr_reg = E1000_READ_REG(shared, ICR); + + /* If MWI was previously enabled, reenable it. */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + e1000_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); + } + } + return; +} + +/****************************************************************************** + * Performs basic configuration of the adapter. + * + * shared - Struct containing variables accessed by shared code + * + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes the receive address registers, + * multicast table, and VLAN filter table. Calls routines to setup link + * configuration and flow control settings. Clears all on-chip counters. Leaves + * the transmit and receive units disabled and uninitialized. + *****************************************************************************/ +boolean_t +e1000_init_hw(struct e1000_shared_adapter *shared) +{ + uint32_t status_reg; + uint32_t i; + uint16_t pci_cmd_word; + boolean_t status; + + DEBUGFUNC("e1000_init_hw"); + + /* Set the Media Type and exit with error if it is not valid. */ + if(shared->mac_type != e1000_82543) { + /* tbi_compatibility is only valid on 82543 */ + shared->tbi_compatibility_en = FALSE; + } + + if(shared->mac_type >= e1000_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_TBIMODE) { + shared->media_type = e1000_media_type_fiber; + /* tbi_compatibility not valid on fiber */ + shared->tbi_compatibility_en = FALSE; + } else { + shared->media_type = e1000_media_type_copper; + } + } else { + /* This is an 82542 (fiber only) */ + shared->media_type = e1000_media_type_fiber; + } + + /* Disabling VLAN filtering. */ + DEBUGOUT("Initializing the IEEE VLAN\n"); + E1000_WRITE_REG(shared, VET, 0); + + e1000_clear_vfta(shared); + + /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; + e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); + } + E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST); + + msec_delay(5); + } + + /* Setup the receive address. This involves initializing all of the Receive + * Address Registers (RARs 0 - 15). + */ + e1000_init_rx_addrs(shared); + + /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ + if(shared->mac_type == e1000_82542_rev2_0) { + E1000_WRITE_REG(shared, RCTL, 0); + + msec_delay(1); + + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + e1000_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); + } + } + + /* Zero out the Multicast HASH table */ + DEBUGOUT("Zeroing the MTA\n"); + for(i = 0; i < E1000_MC_TBL_SIZE; i++) + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + + /* Call a subroutine to configure the link and setup flow control. */ + status = e1000_setup_fc_and_link(shared); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs(shared); + + shared->low_profile = FALSE; + if(shared->mac_type == e1000_82544) { + if(e1000_read_eeprom(shared, E1000_EEPROM_LED_LOGIC) & + E1000_EEPROM_SWDPIN0) + shared->low_profile = TRUE; + } + + return (status); +} + +/****************************************************************************** + * Initializes receive address filters. + * + * shared - Struct containing variables accessed by shared code + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive addresss registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + *****************************************************************************/ +void +e1000_init_rx_addrs(struct e1000_shared_adapter *shared) +{ + uint32_t i; + uint32_t addr_low; + uint32_t addr_high; + + DEBUGFUNC("e1000_init_rx_addrs"); + + /* Setup the receive address. */ + DEBUGOUT("Programming MAC Address into RAR[0]\n"); + addr_low = (shared->mac_addr[0] | + (shared->mac_addr[1] << 8) | + (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24)); + + addr_high = (shared->mac_addr[4] | + (shared->mac_addr[5] << 8) | E1000_RAH_AV); + + E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low); + E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high); + + /* Zero out the other 15 receive addresses. */ + DEBUGOUT("Clearing RAR[1-15]\n"); + for(i = 1; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + + return; +} + +/****************************************************************************** + * Updates the MAC's list of multicast addresses. + * + * shared - Struct containing variables accessed by shared code + * mc_addr_list - the list of new multicast addresses + * mc_addr_count - number of addresses + * pad - number of bytes between addresses in the list + * + * The given list replaces any existing list. Clears the last 15 receive + * address registers and the multicast table. Uses receive address registers + * for the first 15 multicast addresses, and hashes the rest into the + * multicast table. + *****************************************************************************/ +void +e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, + uint8_t *mc_addr_list, + uint32_t mc_addr_count, + uint32_t pad) +{ + uint32_t hash_value; + uint32_t i; + uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ + + DEBUGFUNC("e1000_mc_addr_list_update"); + + /* Set the new number of MC addresses that we are being requested to use. */ + shared->num_mc_addrs = mc_addr_count; + + /* Clear RAR[1-15] */ + DEBUGOUT(" Clearing RAR[1-15]\n"); + for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + + /* Clear the MTA */ + DEBUGOUT(" Clearing MTA\n"); + for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + } + + /* Add the new addresses */ + for(i = 0; i < mc_addr_count; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i, + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]); + + hash_value = e1000_hash_mc_addr(shared, + mc_addr_list + + (i * (ETH_LENGTH_OF_ADDRESS + pad))); + + DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); + + /* Place this multicast address in the RAR if there is room, * + * else put it in the MTA + */ + if(rar_used_count < E1000_RAR_ENTRIES) { + e1000_rar_set(shared, + mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)), + rar_used_count); + rar_used_count++; + } else { + e1000_mta_set(shared, hash_value); + } + } + + DEBUGOUT("MC Update Complete\n"); + return; +} + +/****************************************************************************** + * Hashes an address to determine its location in the multicast table + * + * shared - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + *****************************************************************************/ +uint32_t +e1000_hash_mc_addr(struct e1000_shared_adapter *shared, + uint8_t *mc_addr) +{ + uint32_t hash_value = 0; + + /* The portion of the address that is used for the hash table is + * determined by the mc_filter_type setting. + */ + switch (shared->mc_filter_type) { + /* [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB - According to H/W docs */ + case 0: + /* [47:36] i.e. 0x563 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + break; + case 1: /* [46:35] i.e. 0xAC6 for above example address */ + hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + break; + case 2: /* [45:34] i.e. 0x5D8 for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + break; + case 3: /* [43:32] i.e. 0x634 for above example address */ + hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + break; + } + + hash_value &= 0xFFF; + return (hash_value); +} + +/****************************************************************************** + * Sets the bit in the multicast table corresponding to the hash value. + * + * shared - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + *****************************************************************************/ +void +e1000_mta_set(struct e1000_shared_adapter *shared, + uint32_t hash_value) +{ + uint32_t hash_bit, hash_reg; + uint32_t mta_reg; + uint32_t temp; + + /* The MTA is a register array of 128 32-bit registers. + * It is treated like an array of 4096 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 5) & 0x7F; + hash_bit = hash_value & 0x1F; + + mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg); + + mta_reg |= (1 << hash_bit); + + /* If we are on an 82544 and we are trying to write an odd offset + * in the MTA, save off the previous entry before writing and + * restore the old value after writing. + */ + if((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1)); + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + } + return; +} + +/****************************************************************************** + * Puts an ethernet address into a receive address register. + * + * shared - Struct containing variables accessed by shared code + * addr - Address to put into receive address register + * index - Receive address register to write + *****************************************************************************/ +void +e1000_rar_set(struct e1000_shared_adapter *shared, + uint8_t *addr, + uint32_t index) +{ + uint32_t rar_low, rar_high; + + /* HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((uint32_t) addr[0] | + ((uint32_t) addr[1] << 8) | + ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24)); + + rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV); + + E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low); + E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high); + return; +} + +/****************************************************************************** + * Writes a value to the specified offset in the VLAN filter table. + * + * shared - Struct containing variables accessed by shared code + * offset - Offset in VLAN filer table to write + * value - Value to write into VLAN filter table + *****************************************************************************/ +void +e1000_write_vfta(struct e1000_shared_adapter *shared, + uint32_t offset, + uint32_t value) +{ + uint32_t temp; + + if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1)); + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + } + return; +} + +/****************************************************************************** + * Clears the VLAN filer table + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_clear_vfta(struct e1000_shared_adapter *shared) +{ + uint32_t offset; + + for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0); + return; +} + +/****************************************************************************** + * Configures flow control and link settings. + * + * shared - Struct containing variables accessed by shared code + * + * Determines which flow control settings to use. Calls the apropriate media- + * specific link configuration function. Configures the flow control settings. + * Assuming the adapter has a valid link partner, a valid link should be + * established. Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + *****************************************************************************/ +boolean_t +e1000_setup_fc_and_link(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t eecd_reg; + uint32_t ctrl_ext_reg; + boolean_t status = TRUE; + + DEBUGFUNC("e1000_setup_fc_and_link"); + + /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the + * EEPROM. Store these bits in a variable that we will later write + * to the Device Control Register (CTRL). + */ + eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG); + + ctrl_reg = + (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) | + ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT)); + + /* Set the PCI priority bit correctly in the CTRL register. This + * determines if the adapter gives priority to receives, or if it + * gives equal priority to transmits and receives. + */ + if(shared->dma_fairness) + ctrl_reg |= E1000_CTRL_PRIOR; + + /* Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable shared->fc will + * be initialized based on a value in the EEPROM. + */ + eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG); + + if(shared->fc > e1000_fc_full) { + if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0) + shared->fc = e1000_fc_none; + else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) + shared->fc = e1000_fc_tx_pause; + else + shared->fc = e1000_fc_full; + } + + /* We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + shared->original_fc = shared->fc; + + if(shared->mac_type == e1000_82542_rev2_0) + shared->fc &= (~e1000_fc_tx_pause); + + if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1)) + shared->fc &= (~e1000_fc_rx_pause); + + DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc); + + /* Take the 4 bits from EEPROM word 0x0F that determine the initial + * polarity value for the SW controlled pins, and setup the + * Extended Device Control reg with that info. + * This is needed because one of the SW controlled pins is used for + * signal detection. So this should be done before e1000_setup_pcs_link() + * or e1000_phy_setup() is called. + */ + if(shared->mac_type == e1000_82543) { + ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT) + << SWDPIO__EXT_SHIFT); + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + } + + /* Call the necessary subroutine to configure the link. */ + if(shared->media_type == e1000_media_type_fiber) + status = e1000_setup_pcs_link(shared, ctrl_reg); + else + status = e1000_phy_setup(shared, ctrl_reg); + + /* Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); + + E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW); + E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time); + + /* Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames in not enabled, then these + * registers will be set to 0. + */ + if(!(shared->fc & e1000_fc_tx_pause)) { + E1000_WRITE_REG(shared, FCRTL, 0); + E1000_WRITE_REG(shared, FCRTH, 0); + } else { + /* We need to set up the Receive Threshold high and low water marks + * as well as (optionally) enabling the transmission of XON frames. + */ + if(shared->fc_send_xon) { + E1000_WRITE_REG(shared, FCRTL, + (shared->fc_low_water | E1000_FCRTL_XONE)); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); + } else { + E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); + } + } + return (status); +} + +/****************************************************************************** + * Sets up link for a fiber based adapter + * + * shared - Struct containing variables accessed by shared code + * ctrl_reg - Current value of the device control register + * + * Manipulates Physical Coding Sublayer functions in order to configure + * link. Assumes the hardware has been previously reset and the transmitter + * and receiver are not enabled. + *****************************************************************************/ +boolean_t +e1000_setup_pcs_link(struct e1000_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint32_t status_reg; + uint32_t tctl_reg; + uint32_t txcw_reg = 0; + uint32_t i; + + DEBUGFUNC("e1000_setup_pcs_link"); + + /* Setup the collsion distance. Since this is configuring the + * TBI it is assumed that we are in Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + i = E1000_FDX_COLLISION_DISTANCE; + i <<= E1000_COLD_SHIFT; + tctl_reg |= i; + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Check for a software override of the flow control settings, and + * setup the device accordingly. If auto-negotiation is enabled, + * then software will have to set the "PAUSE" bits to the correct + * value in the Tranmsit Config Word Register (TXCW) and re-start + * auto-negotiation. However, if auto-negotiation is disabled, + * then software will have to manually configure the two flow + * control enable bits in the CTRL register. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case e1000_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD); + break; + case e1000_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * we will disable the adapter's ability to send PAUSE + * frames. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + case e1000_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + break; + case e1000_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Since auto-negotiation is enabled, take the link out of reset. + * (the link will be in reset, because we previously reset the + * chip). This will restart auto-negotiation. If auto-neogtiation + * is successful then the link-up status bit will be set and the + * flow control enable bits (RFCE and TFCE) will be set according + * to their negotiated value. + */ + DEBUGOUT("Auto-negotiation enabled\n"); + + E1000_WRITE_REG(shared, TXCW, txcw_reg); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + shared->txcw_reg = txcw_reg; + msec_delay(1); + + /* If we have a signal then poll for a "Link-Up" indication in the + * Device Status Register. Time-out if a link isn't seen in 500 + * milliseconds seconds (Auto-negotiation should complete in less + * than 500 milliseconds even if the other end is doing it in SW). + */ + if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) { + + DEBUGOUT("Looking for Link\n"); + for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { + msec_delay(10); + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_LU) + break; + } + + if(i == (LINK_UP_TIMEOUT / 10)) { + /* AutoNeg failed to achieve a link, so we'll call the + * "CheckForLink" routine. This routine will force the link + * up if we have "signal-detect". This will allow us to + * communicate with non-autonegotiating link partners. + */ + DEBUGOUT("Never got a valid link from auto-neg!!!\n"); + + shared->autoneg_failed = 1; + e1000_check_for_link(shared); + shared->autoneg_failed = 0; + } else { + shared->autoneg_failed = 0; + DEBUGOUT("Valid Link Found\n"); + } + } else { + DEBUGOUT("No Signal Detected\n"); + } + + return (TRUE); +} + +/****************************************************************************** + * Configures flow control settings after link is established + * + * shared - Struct containing variables accessed by shared code + * + * Should be called immediately after a valid link has been established. + * Forces MAC flow control settings if link was forced. When in MII/GMII mode + * and autonegotiation is enabled, the MAC flow control settings will be set + * based on the flow control negotiated by the PHY. In TBI mode, the TFCE + * and RFCE bits will be automaticaly set to the negotiated flow control mode. + *****************************************************************************/ +void +e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared) +{ + uint16_t mii_status_reg; + uint16_t mii_nway_adv_reg; + uint16_t mii_nway_lp_ability_reg; + uint16_t speed; + uint16_t duplex; + + DEBUGFUNC("e1000_config_fc_after_link_up"); + + /* Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if(((shared->media_type == e1000_media_type_fiber) + && (shared->autoneg_failed)) + || ((shared->media_type == e1000_media_type_copper) + && (!shared->autoneg))) { + e1000_force_mac_fc(shared); + } + + /* Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if((shared->media_type == e1000_media_type_copper) && shared->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement Register + * (Address 4) and the Auto_Negotiation Base Page Ability + * Register (Address 5) to determine how flow control was + * negotiated. + */ + mii_nway_adv_reg = e1000_read_phy_reg(shared, + PHY_AUTONEG_ADV); + mii_nway_lp_ability_reg = e1000_read_phy_reg(shared, + PHY_LP_ABILITY); + + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + /* Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | e1000_fc_full + * + */ + if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if(shared->original_fc == e1000_fc_full) { + shared->fc = e1000_fc_full; + DEBUGOUT("Flow Control = FULL.\r\n"); + } else { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + } + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * + */ + else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = e1000_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + else if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if(shared->original_fc == e1000_fc_none || + shared->original_fc == e1000_fc_tx_pause) { + shared->fc = e1000_fc_none; + DEBUGOUT("Flow Control = NONE.\r\n"); + } else { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + e1000_get_speed_and_duplex(shared, &speed, &duplex); + + if(duplex == HALF_DUPLEX) + shared->fc = e1000_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + e1000_force_mac_fc(shared); + } else { + DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n"); + } + } + return; +} + +/****************************************************************************** + * Checks to see if the link status of the hardware has changed. + * + * shared - Struct containing variables accessed by shared code + * + * Called by any function that needs to check the link status of the adapter. + *****************************************************************************/ +void +e1000_check_for_link(struct e1000_shared_adapter *shared) +{ + uint32_t rxcw_reg; + uint32_t ctrl_reg; + uint32_t status_reg; + uint32_t rctl_reg; + uint16_t phy_data; + uint16_t lp_capability; + + DEBUGFUNC("e1000_check_for_link"); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + status_reg = E1000_READ_REG(shared, STATUS); + rxcw_reg = E1000_READ_REG(shared, RXCW); + + /* If we have a copper PHY then we only want to go out to the PHY + * registers to see if Auto-Neg has completed and/or if our link + * status has changed. The get_link_status flag will be set if we + * receive a Link Status Change interrupt or we have Rx Sequence + * Errors. + */ + if(shared->media_type == e1000_media_type_copper + && shared->get_link_status) { + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + * Read the register twice since the link bit is sticky. + */ + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + + if(phy_data & MII_SR_LINK_STATUS) { + shared->get_link_status = FALSE; + } else { + DEBUGOUT("**** CFL - No link detected. ****\r\n"); + return; + } + + /* If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if(!shared->autoneg) { + return; + } + + switch (shared->phy_id) { + case M88E1000_12_PHY_ID: + case M88E1000_14_PHY_ID: + case M88E1000_I_PHY_ID: + case M88E1011_I_PHY_ID: + /* We have a M88E1000 PHY and Auto-Neg is enabled. If we + * have Si on board that is 82544 or newer, Auto + * Speed Detection takes care of MAC speed/duplex + * configuration. So we only need to configure Collision + * Distance in the MAC. Otherwise, we need to force + * speed/duplex on the MAC to the current PHY speed/duplex + * settings. + */ + if(shared->mac_type >= e1000_82544) { + DEBUGOUT("CFL - Auto-Neg complete."); + DEBUGOUT("Configuring Collision Distance."); + e1000_config_collision_dist(shared); + } else { + /* Read the Phy Specific Status register to get the + * resolved speed/duplex settings. Then call + * e1000_config_mac_to_phy which will retrieve + * PHY register information and configure the MAC to + * equal the negotiated speed/duplex. + */ + phy_data = e1000_read_phy_reg(shared, + M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("CFL - Auto-Neg complete. phy_data = %x\r\n", + phy_data); + e1000_config_mac_to_phy(shared, phy_data); + } + + /* Configure Flow Control now that Auto-Neg has completed. + * We need to first restore the users desired Flow + * Control setting since we may have had to re-autoneg + * with a different link partner. + */ + e1000_config_fc_after_link_up(shared); + break; + + default: + DEBUGOUT("CFL - Invalid PHY detected.\r\n"); + + } /* end switch statement */ + + /* At this point we know that we are on copper, link is up, + * and we are auto-neg'd. These are pre-conditions for checking + * the link parter capabilities register. We use the link partner + * capabilities to determine if TBI Compatibility needs to be turned on + * or turned off. If the link partner advertises any speed in addition + * to Gigabit, then we assume that they are GMII-based and TBI + * compatibility is not needed. + * If no other speeds are advertised, then we assume the link partner + * is TBI-based and we turn on TBI Compatibility. + */ + if(shared->tbi_compatibility_en) { + lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY); + if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | + NWAY_LPAR_10T_FD_CAPS | + NWAY_LPAR_100TX_HD_CAPS | + NWAY_LPAR_100TX_FD_CAPS | + NWAY_LPAR_100T4_CAPS)) { + /* If our link partner advertises below Gig, then they do not + * need the special Tbi Compatibility mode. + */ + if(shared->tbi_compatibility_on) { + /* If we previously were in the mode, turn it off, now. */ + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg &= ~E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); + shared->tbi_compatibility_on = FALSE; + } + } else { + /* If the mode is was previously off, turn it on. + * For compatibility with a suspected Tbi link partners, + * we will store bad packets. + * (Certain frames have an additional byte on the end and will + * look like CRC errors to to the hardware). + */ + if(!shared->tbi_compatibility_on) { + shared->tbi_compatibility_on = TRUE; + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg |= E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); + } + } + } + } /* end if e1000_media_type_copper statement */ + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate) and the cable is plugged in since we don't + * have Loss-Of-Signal (we HAVE a signal) and our link partner is + * not trying to AutoNeg with us (we are receiving idles/data + * then we need to force our link to connect to a non + * auto-negotiating link partner. We also need to give + * auto-negotiation time to complete in case the cable was just + * plugged in. The autoneg_failed flag does this. + */ + else if((shared->media_type == e1000_media_type_fiber) && /* Fiber PHY */ + (!(status_reg & E1000_STATUS_LU)) && /* no link and */ + (!(ctrl_reg & E1000_CTRL_SWDPIN1)) && /* we have signal */ + (!(rxcw_reg & E1000_RXCW_C))) { /* and rxing idle/data */ + if(shared->autoneg_failed == 0) { /* given AutoNeg time */ + shared->autoneg_failed = 1; + return; + } + + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n"); + + /* Disable auto-negotiation in the TXCW register */ + E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Configure Flow Control after forcing link up. */ + e1000_config_fc_after_link_up(shared); + + } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */ + (ctrl_reg & E1000_CTRL_SLU) && /* we have forced link */ + (rxcw_reg & E1000_RXCW_C)) { /* and Rxing /C/ ordered sets */ + /* If we are forcing link and we are receiving /C/ ordered sets, + * then re-enable auto-negotiation in the RXCW register and + * disable forced link in the Device Control register in an attempt + * to AutoNeg with our link partner. + */ + DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); + + /* Enable auto-negotiation in the TXCW register and stop + * forcing link. + */ + E1000_WRITE_REG(shared, TXCW, shared->txcw_reg); + + E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU)); + } + + return; +} + +/****************************************************************************** + * Clears all hardware statistics counters. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared) +{ + volatile uint32_t temp_reg; + + DEBUGFUNC("e1000_clear_hw_cntrs"); + + /* if we are stopped or resetting exit gracefully */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is stopped!!!\n"); + return; + } + + temp_reg = E1000_READ_REG(shared, CRCERRS); + temp_reg = E1000_READ_REG(shared, SYMERRS); + temp_reg = E1000_READ_REG(shared, MPC); + temp_reg = E1000_READ_REG(shared, SCC); + temp_reg = E1000_READ_REG(shared, ECOL); + temp_reg = E1000_READ_REG(shared, MCC); + temp_reg = E1000_READ_REG(shared, LATECOL); + temp_reg = E1000_READ_REG(shared, COLC); + temp_reg = E1000_READ_REG(shared, DC); + temp_reg = E1000_READ_REG(shared, SEC); + temp_reg = E1000_READ_REG(shared, RLEC); + temp_reg = E1000_READ_REG(shared, XONRXC); + temp_reg = E1000_READ_REG(shared, XONTXC); + temp_reg = E1000_READ_REG(shared, XOFFRXC); + temp_reg = E1000_READ_REG(shared, XOFFTXC); + temp_reg = E1000_READ_REG(shared, FCRUC); + temp_reg = E1000_READ_REG(shared, PRC64); + temp_reg = E1000_READ_REG(shared, PRC127); + temp_reg = E1000_READ_REG(shared, PRC255); + temp_reg = E1000_READ_REG(shared, PRC511); + temp_reg = E1000_READ_REG(shared, PRC1023); + temp_reg = E1000_READ_REG(shared, PRC1522); + temp_reg = E1000_READ_REG(shared, GPRC); + temp_reg = E1000_READ_REG(shared, BPRC); + temp_reg = E1000_READ_REG(shared, MPRC); + temp_reg = E1000_READ_REG(shared, GPTC); + temp_reg = E1000_READ_REG(shared, GORCL); + temp_reg = E1000_READ_REG(shared, GORCH); + temp_reg = E1000_READ_REG(shared, GOTCL); + temp_reg = E1000_READ_REG(shared, GOTCH); + temp_reg = E1000_READ_REG(shared, RNBC); + temp_reg = E1000_READ_REG(shared, RUC); + temp_reg = E1000_READ_REG(shared, RFC); + temp_reg = E1000_READ_REG(shared, ROC); + temp_reg = E1000_READ_REG(shared, RJC); + temp_reg = E1000_READ_REG(shared, TORL); + temp_reg = E1000_READ_REG(shared, TORH); + temp_reg = E1000_READ_REG(shared, TOTL); + temp_reg = E1000_READ_REG(shared, TOTH); + temp_reg = E1000_READ_REG(shared, TPR); + temp_reg = E1000_READ_REG(shared, TPT); + temp_reg = E1000_READ_REG(shared, PTC64); + temp_reg = E1000_READ_REG(shared, PTC127); + temp_reg = E1000_READ_REG(shared, PTC255); + temp_reg = E1000_READ_REG(shared, PTC511); + temp_reg = E1000_READ_REG(shared, PTC1023); + temp_reg = E1000_READ_REG(shared, PTC1522); + temp_reg = E1000_READ_REG(shared, MPTC); + temp_reg = E1000_READ_REG(shared, BPTC); + + if(shared->mac_type < e1000_82543) + return; + + temp_reg = E1000_READ_REG(shared, ALGNERRC); + temp_reg = E1000_READ_REG(shared, RXERRC); + temp_reg = E1000_READ_REG(shared, TNCRS); + temp_reg = E1000_READ_REG(shared, CEXTERR); + temp_reg = E1000_READ_REG(shared, TSCTC); + temp_reg = E1000_READ_REG(shared, TSCTFC); + return; +} + +/****************************************************************************** + * Detects the current speed and duplex settings of the hardware. + * + * shared - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + *****************************************************************************/ +void +e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, + uint16_t *speed, + uint16_t *duplex) +{ + uint32_t status_reg; +#if DBG + uint16_t phy_data; +#endif + + DEBUGFUNC("e1000_get_speed_and_duplex"); + + /* If the adapter is stopped we don't have a speed or duplex */ + if(shared->adapter_stopped) { + *speed = 0; + *duplex = 0; + return; + } + + if(shared->mac_type >= e1000_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + DEBUGOUT("1000 Mbs, "); + } else if(status_reg & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + DEBUGOUT("100 Mbs, "); + } else { + *speed = SPEED_10; + DEBUGOUT("10 Mbs, "); + } + + if(status_reg & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + DEBUGOUT("Full Duplex\r\n"); + } else { + *duplex = HALF_DUPLEX; + DEBUGOUT(" Half Duplex\r\n"); + } + } else { + DEBUGOUT("1000 Mbs, Full Duplex\r\n"); + *speed = SPEED_1000; + *duplex = FULL_DUPLEX; + } + +#if DBG + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID || + shared->phy_id == M88E1011_I_PHY_ID) { + /* read the phy specific status register */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data); + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data); + DEBUGOUT1("Device Status Reg contents = %x\n", + E1000_READ_REG(shared, STATUS)); + } +#endif + return; +} + +/****************************************************************************** + * Reads a 16 bit word from the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * offset - offset of 16 bit word in the EEPROM to read + *****************************************************************************/ +uint16_t +e1000_read_eeprom(struct e1000_shared_adapter *shared, + uint16_t offset) +{ + boolean_t large_eeprom = FALSE; + uint16_t data; + uint32_t eecd_reg; + uint32_t tmp = 0; + + if((shared->mac_type > e1000_82544) && + (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE; + + /* Request EEPROM Access */ + if(shared->mac_type > e1000_82544) { + E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ); + eecd_reg = E1000_READ_REG(shared, EECD); + while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) { + tmp++; + usec_delay(5); + eecd_reg = E1000_READ_REG(shared, EECD); + } + if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE); + } + + /* Prepare the EEPROM for reading */ + e1000_setup_eeprom(shared); + + /* Send the READ command (opcode + addr) */ + e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3); + /* If we have a 256 word EEPROM, there are 8 address bits + * if we have a 64 word EEPROM, there are 6 address bits + */ + if(large_eeprom) + e1000_shift_out_bits(shared, offset, 8); + else + e1000_shift_out_bits(shared, offset, 6); + + /* Read the data */ + data = e1000_shift_in_bits(shared); + + /* End this read operation */ + e1000_standby_eeprom(shared); + + /* Stop requestiong EEPROM access */ + if(shared->mac_type > e1000_82544) + E1000_WRITE_REG(shared, EECD, (uint32_t) 0); + + return (data); +} + +/****************************************************************************** + * Verifies that the EEPROM has a valid checksum + * + * shared - Struct containing variables accessed by shared code + * + * Reads the first 64 16 bit words of the EEPROM and sums the values read. + * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is + * valid. + *****************************************************************************/ +boolean_t +e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared) +{ + uint16_t checksum = 0; + uint16_t i; + + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) + checksum += e1000_read_eeprom(shared, i); + + if(checksum == (uint16_t) EEPROM_SUM) + return (TRUE); + else + return (FALSE); +} + +/****************************************************************************** + * Calculates the EEPROM checksum and writes it to the EEPROM + * + * shared - Struct containing variables accessed by shared code + * + * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA. + * Writes the difference to word offset 63 of the EEPROM. + *****************************************************************************/ +void +e1000_update_eeprom_checksum(struct e1000_shared_adapter *shared) +{ + uint16_t checksum = 0; + uint16_t i; + + for(i = 0; i < EEPROM_CHECKSUM_REG; i++) + checksum += e1000_read_eeprom(shared, i); + + checksum = (uint16_t) EEPROM_SUM - checksum; + + e1000_write_eeprom(shared, EEPROM_CHECKSUM_REG, checksum); + return; +} + +/****************************************************************************** + * Writes a 16 bit word to a given offset in the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * data - 16 bit word to be writen to the EEPROM + * + * If e1000_update_eeprom_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. + *****************************************************************************/ +boolean_t +e1000_write_eeprom(struct e1000_shared_adapter *shared, + uint16_t offset, + uint16_t data) +{ + boolean_t large_eeprom = FALSE; + uint32_t eecd_reg; + uint32_t tmp = 0; + + if((shared->mac_type > e1000_82544) && + (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE; + + /* Request EEPROM Access */ + if(shared->mac_type > e1000_82544) { + E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ); + eecd_reg = E1000_READ_REG(shared, EECD); + while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) { + tmp++; + usec_delay(5); + eecd_reg = E1000_READ_REG(shared, EECD); + } + if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE); + } + + /* Prepare the EEPROM for writing */ + e1000_setup_eeprom(shared); + + /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) + * command to the EEPROM (5-bit opcode plus 4/6-bit dummy). + * This puts the EEPROM into write/erase mode. + */ + e1000_shift_out_bits(shared, EEPROM_EWEN_OPCODE, 5); + if(large_eeprom) + e1000_shift_out_bits(shared, 0, 6); + else + e1000_shift_out_bits(shared, 0, 4); + + /* Prepare the EEPROM */ + e1000_standby_eeprom(shared); + + /* Send the Write command (3-bit opcode + addr) */ + e1000_shift_out_bits(shared, EEPROM_WRITE_OPCODE, 3); + /* If we have a 256 word EEPROM, there are 8 address bits + * if we have a 64 word EEPROM, there are 6 address bits + */ + if(large_eeprom) + e1000_shift_out_bits(shared, offset, 8); + else + e1000_shift_out_bits(shared, offset, 6); + + /* Send the data */ + e1000_shift_out_bits(shared, data, 16); + e1000_wait_eeprom_command(shared); + + /* Recover from write */ + e1000_standby_eeprom(shared); + + /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) + * command to the EEPROM (5-bit opcode plus 4/6-bit dummy). + * This takes the EEPROM out of write/erase mode. + */ + e1000_shift_out_bits(shared, EEPROM_EWDS_OPCODE, 5); + if(large_eeprom) + e1000_shift_out_bits(shared, 0, 6); + else + e1000_shift_out_bits(shared, 0, 4); + + /* Done with writing */ + e1000_cleanup_eeprom(shared); + + /* Stop requestiong EEPROM access */ + if(shared->mac_type > e1000_82544) + E1000_WRITE_REG(shared, EECD, (uint32_t) 0); + + return (TRUE); +} + +/****************************************************************************** + * Reads the adapter's part number from the EEPROM + * + * shared - Struct containing variables accessed by shared code + * part_num - Adapter's part number + *****************************************************************************/ +boolean_t +e1000_read_part_num(struct e1000_shared_adapter *shared, + uint32_t *part_num) +{ + uint16_t eeprom_word; + + DEBUGFUNC("e1000_read_part_num"); + + /* Don't read the EEPROM if we are stopped */ + if(shared->adapter_stopped) { + *part_num = 0; + return (FALSE); + } + + /* Get word 0 from EEPROM */ + eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1)); + + DEBUGOUT("Read first part number word\n"); + + /* Save word 0 in upper half is PartNumber */ + *part_num = (uint32_t) eeprom_word; + *part_num = *part_num << 16; + + /* Get word 1 from EEPROM */ + eeprom_word = + e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1)); + + DEBUGOUT("Read second part number word\n"); + + /* Save word 1 in lower half of PartNumber */ + *part_num |= eeprom_word; + + /* read a valid part number */ + return (TRUE); +} + +/****************************************************************************** + * Turns on the software controllable LED + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_led_on(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + + /* if we're stopped don't touch the hardware */ + if(shared->adapter_stopped) + return; + + /* Read the content of the device control reg */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set the LED control pin to an output */ + ctrl_reg |= E1000_CTRL_SWDPIO0; + + /* Drive it high on normal boards, low on low profile boards */ + if(shared->low_profile) + ctrl_reg &= ~E1000_CTRL_SWDPIN0; + else + ctrl_reg |= E1000_CTRL_SWDPIN0; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; +} + +/****************************************************************************** + * Turns off the software controllable LED + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_led_off(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + + /* if we're stopped don't touch the hardware */ + if(shared->adapter_stopped) + return; + + /* Read the content of the device control reg */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set the LED control pin to an output */ + ctrl_reg |= E1000_CTRL_SWDPIO0; + + /* Drive it low on normal boards, high on low profile boards */ + if(shared->low_profile) + ctrl_reg |= E1000_CTRL_SWDPIN0; + else + ctrl_reg &= ~E1000_CTRL_SWDPIN0; + + /* Write the device control reg. back */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; +} + +/****************************************************************************** + * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT + * + * shared - Struct containing variables accessed by shared code + * frame_len - The length of the frame in question + * mac_addr - The Ethernet destination address of the frame in question + *****************************************************************************/ +uint32_t +e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, + struct e1000_shared_stats *stats, + uint32_t frame_len, + uint8_t *mac_addr) +{ + uint64_t carry_bit; + + /* First adjust the frame length. */ + frame_len--; + /* We need to adjust the statistics counters, since the hardware + * counters overcount this packet as a CRC error and undercount + * the packet as a good packet + */ + /* This packet should not be counted as a CRC error. */ + stats->crcerrs--; + /* This packet does count as a Good Packet Received. */ + stats->gprc++; + + /* Adjust the Good Octets received counters */ + carry_bit = 0x80000000 & stats->gorcl; + stats->gorcl += frame_len; + /* If the high bit of Gorcl (the low 32 bits of the Good Octets + * Received Count) was one before the addition, + * AND it is zero after, then we lost the carry out, + * need to add one to Gorch (Good Octets Received Count High). + * This could be simplified if all environments supported + * 64-bit integers. + */ + if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) + stats->gorch++; + /* Is this a broadcast or multicast? Check broadcast first, + * since the test for a multicast frame will test positive on + * a broadcast frame. + */ + if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) + /* Broadcast packet */ + stats->bprc++; + else if(*mac_addr & 0x01) + /* Multicast packet */ + stats->mprc++; + + if(frame_len == shared->max_frame_size) { + /* In this case, the hardware has overcounted the number of + * oversize frames. + */ + if(stats->roc > 0) + stats->roc--; + } + + /* Adjust the bin counters when the extra byte put the frame in the + * wrong bin. Remember that the frame_len was adjusted above. + */ + if(frame_len == 64) { + stats->prc64++; + stats->prc127--; + } else if(frame_len == 127) { + stats->prc127++; + stats->prc255--; + } else if(frame_len == 255) { + stats->prc255++; + stats->prc511--; + } else if(frame_len == 511) { + stats->prc511++; + stats->prc1023--; + } else if(frame_len == 1023) { + stats->prc1023++; + stats->prc1522--; + } else if(frame_len == 1522) { + stats->prc1522++; + } + return frame_len; +} + +/****************************************************************************** + * Gets the current PCI bus type, speed, and width of the hardware + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_get_bus_info(struct e1000_shared_adapter *shared) +{ + uint32_t status_reg; + + if(shared->mac_type < e1000_82543) { + shared->bus_type = e1000_bus_type_unknown; + shared->bus_speed = e1000_bus_speed_unknown; + shared->bus_width = e1000_bus_width_unknown; + return; + } + + status_reg = E1000_READ_REG(shared, STATUS); + + shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ? + e1000_bus_type_pcix : e1000_bus_type_pci; + + if(shared->bus_type == e1000_bus_type_pci) { + shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ? + e1000_bus_speed_66 : e1000_bus_speed_33; + } else { + switch (status_reg & E1000_STATUS_PCIX_SPEED) { + case E1000_STATUS_PCIX_SPEED_66: + shared->bus_speed = e1000_bus_speed_66; + break; + case E1000_STATUS_PCIX_SPEED_100: + shared->bus_speed = e1000_bus_speed_100; + break; + case E1000_STATUS_PCIX_SPEED_133: + shared->bus_speed = e1000_bus_speed_133; + break; + default: + shared->bus_speed = e1000_bus_speed_reserved; + break; + } + } + + shared->bus_width = (status_reg & E1000_STATUS_BUS64) ? + e1000_bus_width_64 : e1000_bus_width_32; + + return; +} diff -Nur linux-2.4.19/drivers/net/e1000/e1000_mac.h linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_mac.h --- linux-2.4.19/drivers/net/e1000/e1000_mac.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_mac.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,1381 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + +/* e1000_mac.h + * Structures, enums, and macros for the MAC + */ + +#ifndef _E1000_MAC_H_ +#define _E1000_MAC_H_ + +#include "e1000_osdep.h" + +/* Forward declarations of structures used by the shared code */ +struct e1000_shared_adapter; +struct e1000_shared_stats; + +/* Enumerated types specific to the e1000 hardware */ +/* Media Access Controlers */ +typedef enum { + e1000_82542_rev2_0 = 0, + e1000_82542_rev2_1, + e1000_82543, + e1000_82544, + e1000_82540, + e1000_num_macs +} e1000_mac_type; + +/* Media Types */ +typedef enum { + e1000_media_type_copper = 0, + e1000_media_type_fiber = 1, + e1000_num_media_types +} e1000_media_type; + +typedef enum { + e1000_10_half = 0, + e1000_10_full = 1, + e1000_100_half = 2, + e1000_100_full = 3 +} e1000_speed_duplex_type; + +/* Flow Control Settings */ +typedef enum { + e1000_fc_none = 0, + e1000_fc_rx_pause = 1, + e1000_fc_tx_pause = 2, + e1000_fc_full = 3, + e1000_fc_default = 0xFF +} e1000_fc_type; + +/* PCI bus types */ +typedef enum { + e1000_bus_type_unknown = 0, + e1000_bus_type_pci, + e1000_bus_type_pcix +} e1000_bus_type; + +/* PCI bus speeds */ +typedef enum { + e1000_bus_speed_unknown = 0, + e1000_bus_speed_33, + e1000_bus_speed_66, + e1000_bus_speed_100, + e1000_bus_speed_133, + e1000_bus_speed_reserved +} e1000_bus_speed; + +/* PCI bus widths */ +typedef enum { + e1000_bus_width_unknown = 0, + e1000_bus_width_32, + e1000_bus_width_64 +} e1000_bus_width; + + + +/* Function prototypes */ +/* Setup */ +void e1000_adapter_stop(struct e1000_shared_adapter *shared); +boolean_t e1000_init_hw(struct e1000_shared_adapter *shared); +void e1000_init_rx_addrs(struct e1000_shared_adapter *shared); + +/* Filters (multicast, vlan, receive) */ +void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr); +void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value); +void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index); +void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value); +void e1000_clear_vfta(struct e1000_shared_adapter *shared); + +/* Link layer setup functions */ +boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared); +boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg); +void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared); +void e1000_check_for_link(struct e1000_shared_adapter *shared); +void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex); + +/* EEPROM Functions */ +uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg); +boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared); +void e1000_update_eeprom_checksum(struct e1000_shared_adapter *shared); +boolean_t e1000_write_eeprom(struct e1000_shared_adapter *shared, uint16_t reg, uint16_t data); + +/* Everything else */ +void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared); +boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num); +void e1000_led_on(struct e1000_shared_adapter *shared); +void e1000_led_off(struct e1000_shared_adapter *shared); +void e1000_get_bus_info(struct e1000_shared_adapter *shared); +uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr); +void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value); + +/* PCI Device IDs */ +#define E1000_DEV_ID_82542 0x1000 +#define E1000_DEV_ID_82543GC_FIBER 0x1001 +#define E1000_DEV_ID_82543GC_COPPER 0x1004 +#define E1000_DEV_ID_82544EI_COPPER 0x1008 +#define E1000_DEV_ID_82544EI_FIBER 0x1009 +#define E1000_DEV_ID_82544GC_COPPER 0x100C +#define E1000_DEV_ID_82544GC_LOM 0x100D +#define E1000_DEV_ID_82540EM 0x100E +#define NUM_DEV_IDS 8 + +#define NODE_ADDRESS_SIZE 6 +#define ETH_LENGTH_OF_ADDRESS 6 + +/* MAC decode size is 128K - This is the size of BAR0 */ +#define MAC_DECODE_SIZE (128 * 1024) + +#define E1000_82542_2_0_REV_ID 2 +#define E1000_82542_2_1_REV_ID 3 + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +/* The sizes (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */ +#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Without FCS */ +#define CRC_LENGTH 4 +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + + +/* 802.1q VLAN Packet Sizes */ +#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */ + +/* Ethertype field values */ +#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ +#define ETHERNET_IP_TYPE 0x0800 /* IP packets */ +#define ETHERNET_ARP_TYPE 0x0806 /* Address Resolution Protocol (ARP) */ + +/* Packet Header defines */ +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 0x11 + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + */ +#define POLL_IMS_ENABLE_MASK ( \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ) + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* The number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. We + * reserve one of these spots for our directed address, allowing us room for + * E1000_RAR_ENTRIES - 1 multicast addresses. + */ +#define E1000_RAR_ENTRIES 16 + +#define MIN_NUMBER_OF_DESCRIPTORS 8 +#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 + +/* Receive Descriptor */ +struct e1000_rx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + uint16_t length; /* Length of data DMAed into data buffer */ + uint16_t csum; /* Packet checksum */ + uint8_t status; /* Descriptor status */ + uint8_t errors; /* Descriptor Errors */ + uint16_t special; +}; + +/* Receive Decriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define E1000_RXD_SPC_PRI_SHIFT 0x000D /* Priority is in upper 3 of 16 */ +#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define E1000_RXD_SPC_CFI_SHIFT 0x000C /* CFI is bit 12 */ + +/* mask to determine if packets should be dropped due to frame errors */ +#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ + E1000_RXD_ERR_CE | \ + E1000_RXD_ERR_SE | \ + E1000_RXD_ERR_SEQ | \ + E1000_RXD_ERR_CXE | \ + E1000_RXD_ERR_RXE) + +/* Transmit Descriptor */ +struct e1000_tx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t cso; /* Checksum offset */ + uint8_t cmd; /* Descriptor control */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t css; /* Checksum start */ + uint16_t special; + } fields; + } upper; +}; + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + uint32_t ip_config; + struct { + uint8_t ipcss; /* IP checksum start */ + uint8_t ipcso; /* IP checksum offset */ + uint16_t ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + uint32_t tcp_config; + struct { + uint8_t tucss; /* TCP checksum start */ + uint8_t tucso; /* TCP checksum offset */ + uint16_t tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + uint32_t cmd_and_length; /* */ + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t hdr_len; /* Header length */ + uint16_t mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + uint64_t buffer_addr; /* Address of the descriptor's buffer address */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t typ_len_ext; /* */ + uint8_t cmd; /* */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t popts; /* Packet Options */ + uint16_t special; /* */ + } fields; + } upper; +}; + +/* Filters */ +#define E1000_NUM_UNICAST 16 /* Unicast filter entries */ +#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + + +/* Receive Address Register */ +struct e1000_rar { + volatile uint32_t low; /* receive address low */ + volatile uint32_t high; /* receive address high */ +}; + +/* The number of entries in the Multicast Table Array (MTA). */ +#define E1000_NUM_MTA_REGISTERS 128 + +/* IPv4 Address Table Entry */ +struct e1000_ipv4_at_entry { + volatile uint32_t ipv4_addr; /* IP Address (RW) */ + volatile uint32_t reserved; +}; + +/* Four wakeup IP addresses are supported */ +#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4 +#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX +#define E1000_IP6AT_SIZE 1 + +/* IPv6 Address Table Entry */ +struct e1000_ipv6_at_entry { + volatile uint8_t ipv6_addr[16]; +}; + +/* Flexible Filter Length Table Entry */ +struct e1000_fflt_entry { + volatile uint32_t length; /* Flexible Filter Length (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Mask Table Entry */ +struct e1000_ffmt_entry { + volatile uint32_t mask; /* Flexible Filter Mask (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Value Table Entry */ +struct e1000_ffvt_entry { + volatile uint32_t value; /* Flexible Filter Value (RW) */ + volatile uint32_t reserved; +}; + +/* Four Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 + +/* Each Flexible Filter is at most 128 (0x80) bytes in length */ +#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 + +#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX +#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX + +/* Register Set. (82543, 82544) + * + * Registers are defined to be 32 bits and should be accessed as 32 bit values. + * These registers are physically located on the NIC, but are mapped into the + * host memory address space. + * + * RW - register is both readable and writable + * RO - register is read only + * WO - register is write only + * R/clr - register is read only and is cleared when read + * A - register array + */ +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_EERD 0x00014 /* EEPROM Read - RW */ +#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ +#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FCT 0x00030 /* Flow Control Type - RW */ +#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ +#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ +#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ +#define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ +#define E1000_TBT 0x00448 /* TX Burst Timer - RW */ +#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ +#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ +#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ +#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ +#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ +#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ +#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ +#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ +#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ +#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ +#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ +#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ +#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ +#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ +#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ +#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ +#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ +#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ +#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ +#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define E1000_COLC 0x04028 /* Collision Count - R/clr */ +#define E1000_DC 0x04030 /* Defer Count - R/clr */ +#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ +#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ +#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ +#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ +#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ +#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ +#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ +#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ +#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ +#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ +#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ +#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ +#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ +#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ +#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ +#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ +#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ +#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ +#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ +#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ +#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ +#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ +#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ +#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ +#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ +#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */ +#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ +#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */ +#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ +#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ +#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ +#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ +#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ +#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ +#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ +#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ +#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ +#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ +#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ +#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ +#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ +#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ +#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ +#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ +#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ +#define E1000_WUC 0x05800 /* Wakeup Control - RW */ +#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ +#define E1000_WUS 0x05810 /* Wakeup Status - RO */ +#define E1000_MANC 0x05820 /* Management Control - RW */ +#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ +#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ +#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ +#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ +#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ +#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ +#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ +#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ + +/* Register Set (82542) + * + * Some of the 82542 registers are located at different offsets than they are + * in more current versions of the 8254x. Despite the difference in location, + * the registers function in the same manner. + */ +#define E1000_82542_CTRL E1000_CTRL +#define E1000_82542_STATUS E1000_STATUS +#define E1000_82542_EECD E1000_EECD +#define E1000_82542_EERD E1000_EERD +#define E1000_82542_CTRL_EXT E1000_CTRL_EXT +#define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_FCAL E1000_FCAL +#define E1000_82542_FCAH E1000_FCAH +#define E1000_82542_FCT E1000_FCT +#define E1000_82542_VET E1000_VET +#define E1000_82542_RA 0x00040 +#define E1000_82542_ICR E1000_ICR +#define E1000_82542_ITR E1000_ITR +#define E1000_82542_ICS E1000_ICS +#define E1000_82542_IMS E1000_IMS +#define E1000_82542_IMC E1000_IMC +#define E1000_82542_RCTL E1000_RCTL +#define E1000_82542_RDTR 0x00108 +#define E1000_82542_RDBAL 0x00110 +#define E1000_82542_RDBAH 0x00114 +#define E1000_82542_RDLEN 0x00118 +#define E1000_82542_RDH 0x00120 +#define E1000_82542_RDT 0x00128 +#define E1000_82542_FCRTH 0x00160 +#define E1000_82542_FCRTL 0x00168 +#define E1000_82542_FCTTV E1000_FCTTV +#define E1000_82542_TXCW E1000_TXCW +#define E1000_82542_RXCW E1000_RXCW +#define E1000_82542_MTA 0x00200 +#define E1000_82542_TCTL E1000_TCTL +#define E1000_82542_TIPG E1000_TIPG +#define E1000_82542_TDBAL 0x00420 +#define E1000_82542_TDBAH 0x00424 +#define E1000_82542_TDLEN 0x00428 +#define E1000_82542_TDH 0x00430 +#define E1000_82542_TDT 0x00438 +#define E1000_82542_TIDV 0x00440 +#define E1000_82542_TBT E1000_TBT +#define E1000_82542_VFTA 0x00600 +#define E1000_82542_LEDCTL E1000_LEDCTL +#define E1000_82542_PBA E1000_PBA +#define E1000_82542_RXDCTL E1000_RXDCTL +#define E1000_82542_RADV E1000_RADV +#define E1000_82542_RSRPD E1000_RSRPD +#define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_TXDCTL E1000_TXDCTL +#define E1000_82542_TADV E1000_TADV +#define E1000_82542_TSPMT E1000_TSPMT +#define E1000_82542_CRCERRS E1000_CRCERRS +#define E1000_82542_ALGNERRC E1000_ALGNERRC +#define E1000_82542_SYMERRS E1000_SYMERRS +#define E1000_82542_RXERRC E1000_RXERRC +#define E1000_82542_MPC E1000_MPC +#define E1000_82542_SCC E1000_SCC +#define E1000_82542_ECOL E1000_ECOL +#define E1000_82542_MCC E1000_MCC +#define E1000_82542_LATECOL E1000_LATECOL +#define E1000_82542_COLC E1000_COLC +#define E1000_82542_DC E1000_DC +#define E1000_82542_TNCRS E1000_TNCRS +#define E1000_82542_SEC E1000_SEC +#define E1000_82542_CEXTERR E1000_CEXTERR +#define E1000_82542_RLEC E1000_RLEC +#define E1000_82542_XONRXC E1000_XONRXC +#define E1000_82542_XONTXC E1000_XONTXC +#define E1000_82542_XOFFRXC E1000_XOFFRXC +#define E1000_82542_XOFFTXC E1000_XOFFTXC +#define E1000_82542_FCRUC E1000_FCRUC +#define E1000_82542_PRC64 E1000_PRC64 +#define E1000_82542_PRC127 E1000_PRC127 +#define E1000_82542_PRC255 E1000_PRC255 +#define E1000_82542_PRC511 E1000_PRC511 +#define E1000_82542_PRC1023 E1000_PRC1023 +#define E1000_82542_PRC1522 E1000_PRC1522 +#define E1000_82542_GPRC E1000_GPRC +#define E1000_82542_BPRC E1000_BPRC +#define E1000_82542_MPRC E1000_MPRC +#define E1000_82542_GPTC E1000_GPTC +#define E1000_82542_GORCL E1000_GORCL +#define E1000_82542_GORCH E1000_GORCH +#define E1000_82542_GOTCL E1000_GOTCL +#define E1000_82542_GOTCH E1000_GOTCH +#define E1000_82542_RNBC E1000_RNBC +#define E1000_82542_RUC E1000_RUC +#define E1000_82542_RFC E1000_RFC +#define E1000_82542_ROC E1000_ROC +#define E1000_82542_RJC E1000_RJC +#define E1000_82542_MGTPRC E1000_MGTPRC +#define E1000_82542_MGTPDC E1000_MGTPDC +#define E1000_82542_MGTPTC E1000_MGTPTC +#define E1000_82542_TORL E1000_TORL +#define E1000_82542_TORH E1000_TORH +#define E1000_82542_TOTL E1000_TOTL +#define E1000_82542_TOTH E1000_TOTH +#define E1000_82542_TPR E1000_TPR +#define E1000_82542_TPT E1000_TPT +#define E1000_82542_PTC64 E1000_PTC64 +#define E1000_82542_PTC127 E1000_PTC127 +#define E1000_82542_PTC255 E1000_PTC255 +#define E1000_82542_PTC511 E1000_PTC511 +#define E1000_82542_PTC1023 E1000_PTC1023 +#define E1000_82542_PTC1522 E1000_PTC1522 +#define E1000_82542_MPTC E1000_MPTC +#define E1000_82542_BPTC E1000_BPTC +#define E1000_82542_TSCTC E1000_TSCTC +#define E1000_82542_TSCTFC E1000_TSCTFC +#define E1000_82542_RXCSUM E1000_RXCSUM +#define E1000_82542_WUC E1000_WUC +#define E1000_82542_WUFC E1000_WUFC +#define E1000_82542_WUS E1000_WUS +#define E1000_82542_MANC E1000_MANC +#define E1000_82542_IPAV E1000_IPAV +#define E1000_82542_IP4AT E1000_IP4AT +#define E1000_82542_IP6AT E1000_IP6AT +#define E1000_82542_WUPL E1000_WUPL +#define E1000_82542_WUPM E1000_WUPM +#define E1000_82542_FFLT E1000_FFLT +#define E1000_82542_FFMT E1000_FFMT +#define E1000_82542_FFVT E1000_FFVT + +/* Statistics counters collected by the MAC */ +struct e1000_shared_stats { + uint64_t crcerrs; + uint64_t algnerrc; + uint64_t symerrs; + uint64_t rxerrc; + uint64_t mpc; + uint64_t scc; + uint64_t ecol; + uint64_t mcc; + uint64_t latecol; + uint64_t colc; + uint64_t dc; + uint64_t tncrs; + uint64_t sec; + uint64_t cexterr; + uint64_t rlec; + uint64_t xonrxc; + uint64_t xontxc; + uint64_t xoffrxc; + uint64_t xofftxc; + uint64_t fcruc; + uint64_t prc64; + uint64_t prc127; + uint64_t prc255; + uint64_t prc511; + uint64_t prc1023; + uint64_t prc1522; + uint64_t gprc; + uint64_t bprc; + uint64_t mprc; + uint64_t gptc; + uint64_t gorcl; + uint64_t gorch; + uint64_t gotcl; + uint64_t gotch; + uint64_t rnbc; + uint64_t ruc; + uint64_t rfc; + uint64_t roc; + uint64_t rjc; + uint64_t mgprc; + uint64_t mgpdc; + uint64_t mgptc; + uint64_t torl; + uint64_t torh; + uint64_t totl; + uint64_t toth; + uint64_t tpr; + uint64_t tpt; + uint64_t ptc64; + uint64_t ptc127; + uint64_t ptc255; + uint64_t ptc511; + uint64_t ptc1023; + uint64_t ptc1522; + uint64_t mptc; + uint64_t bptc; + uint64_t tsctc; + uint64_t tsctfc; +}; + +/* Structure containing variables used by the shared code (e1000_mac.c and + * e1000_phy.c) + */ +struct e1000_shared_adapter { + uint8_t *hw_addr; + e1000_mac_type mac_type; + e1000_media_type media_type; + void *back; + e1000_fc_type fc; + e1000_bus_speed bus_speed; + e1000_bus_width bus_width; + e1000_bus_type bus_type; + uint32_t phy_id; + uint32_t phy_addr; + uint32_t original_fc; + uint32_t txcw_reg; + uint32_t autoneg_failed; + uint32_t max_frame_size; + uint32_t min_frame_size; + uint32_t mc_filter_type; + uint32_t num_mc_addrs; + uint16_t autoneg_advertised; + uint16_t pci_cmd_word; + uint16_t fc_high_water; + uint16_t fc_low_water; + uint16_t fc_pause_time; + uint16_t device_id; + uint16_t vendor_id; + uint16_t subsystem_id; + uint16_t subsystem_vendor_id; + uint8_t revision_id; + boolean_t disable_polarity_correction; + boolean_t get_link_status; + boolean_t tbi_compatibility_en; + boolean_t tbi_compatibility_on; + boolean_t adapter_stopped; + boolean_t fc_send_xon; + boolean_t report_tx_early; + boolean_t low_profile; + uint8_t autoneg; + uint8_t mdix; + uint8_t forced_speed_duplex; + uint8_t wait_autoneg_complete; + uint8_t dma_fairness; + uint8_t mac_addr[NODE_ADDRESS_SIZE]; +}; + + +#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ +#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ + +/* Register Bit Masks */ +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ +#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ +#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ +#define E1000_STATUS_SPEED_MASK 0x000000C0 +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ +#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ +#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ +#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ +#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ + +/* Constants used to intrepret the masked PCI-X bus speed. */ +#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ +#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ +#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */ + +/* EEPROM/Flash Control */ +#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ +#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ +#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ +#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define E1000_EECD_FWE_SHIFT 4 +#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ +#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ +#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ + +/* EEPROM Read */ +#define E1000_EERD_START 0x00000001 /* Start Read */ +#define E1000_EERD_DONE 0x00000010 /* Read Done */ +#define E1000_EERD_ADDR_SHIFT 8 +#define E1000_EERD_ADDR_MASK 0x0000FF00 /* Read Address */ +#define E1000_EERD_DATA_SHIFT 16 +#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */ + +/* Extended Device Control */ +#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ +#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ +#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN +#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ +#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ +#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */ +#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */ +#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA +#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ +#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ +#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ +#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ +#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ +#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 +#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 +#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 +#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 +#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 +#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 +#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 + +/* MDI Control */ +#define E1000_MDIC_DATA_MASK 0x0000FFFF +#define E1000_MDIC_REG_MASK 0x001F0000 +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_MASK 0x03E00000 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_INT_EN 0x20000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* LED Control */ +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 +#define E1000_LEDCTL_LED1_MODE_SHIFT 8 +#define E1000_LEDCTL_LED1_IVRT 0x00004000 +#define E1000_LEDCTL_LED1_BLINK 0x00008000 +#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 +#define E1000_LEDCTL_LED2_MODE_SHIFT 16 +#define E1000_LEDCTL_LED2_IVRT 0x00400000 +#define E1000_LEDCTL_LED2_BLINK 0x00800000 +#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 +#define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_IVRT 0x40000000 +#define E1000_LEDCTL_LED3_BLINK 0x80000000 + +#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 +#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 +#define E1000_LEDCTL_MODE_LINK_UP 0x2 +#define E1000_LEDCTL_MODE_ACTIVITY 0x3 +#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 +#define E1000_LEDCTL_MODE_LINK_10 0x5 +#define E1000_LEDCTL_MODE_LINK_100 0x6 +#define E1000_LEDCTL_MODE_LINK_1000 0x7 +#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 +#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 +#define E1000_LEDCTL_MODE_COLLISION 0xA +#define E1000_LEDCTL_MODE_BUS_SPEED 0xB +#define E1000_LEDCTL_MODE_BUS_SIZE 0xC +#define E1000_LEDCTL_MODE_PAUSED 0xD +#define E1000_LEDCTL_MODE_LED_ON 0xE +#define E1000_LEDCTL_MODE_LED_OFF 0xF + +/* Receive Address */ +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 + +/* Interrupt Cause Set */ +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_ICS_SRPD E1000_ICR_SRPD + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMS_SRPD E1000_ICR_SRPD + +/* Interrupt Mask Clear */ +#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMC_SRPD E1000_ICR_SRPD + +/* Receive Control */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ + +/* Receive Descriptor */ +#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ +#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */ +#define E1000_RDLEN_LEN 0x0007ff80 /* descriptor length */ +#define E1000_RDH_RDH 0x0000ffff /* receive descriptor head */ +#define E1000_RDT_RDT 0x0000ffff /* receive descriptor tail */ + +/* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Receive Descriptor Control */ +#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */ +#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */ +#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */ +#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */ + +/* Transmit Descriptor Control */ +#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */ +#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ +#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ +#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ +#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ +#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ +#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ +#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ +#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ +#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ +#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ +#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ +#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ +#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ +#define E1000_RXCW_CC 0x10000000 /* Receive config change */ +#define E1000_RXCW_C 0x20000000 /* Receive config */ +#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ +#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ + +/* Transmit Control */ +#define E1000_TCTL_RST 0x00000001 /* software reset */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ +#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ + +/* Receive Checksum Control */ +#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ +#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ +#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ +#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ +#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ +#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ +#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ +#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ +#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ +#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ +#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Wake Up Status */ +#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */ +#define E1000_WUS_MAG 0x00000002 /* Magic Packet Received */ +#define E1000_WUS_EX 0x00000004 /* Directed Exact Received */ +#define E1000_WUS_MC 0x00000008 /* Directed Multicast Received */ +#define E1000_WUS_BC 0x00000010 /* Broadcast Received */ +#define E1000_WUS_ARP 0x00000020 /* ARP Request Packet Received */ +#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */ +#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */ +#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */ +#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */ +#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */ +#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */ +#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ +#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ +#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ +#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ +#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ +#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery + * Filtering */ +#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ +#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ +#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ +#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ +#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ +#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ + +#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ +#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ + +/* Wake Up Packet Length */ +#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ + +#define E1000_MDALIGN 4096 + +/* EEPROM Commands */ +#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ +#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ +#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ +#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ +#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ + +/* EEPROM Word Offsets */ +#define EEPROM_INIT_CONTROL1_REG 0x000A +#define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_FLASH_VERSION 0x0032 +#define EEPROM_CHECKSUM_REG 0x003F + +/* Mask bits for fields in Word 0x0a of the EEPROM */ +#define EEPROM_WORD0A_ILOS 0x0010 +#define EEPROM_WORD0A_SWDPIO 0x01E0 +#define EEPROM_WORD0A_LRST 0x0200 +#define EEPROM_WORD0A_FD 0x0400 +#define EEPROM_WORD0A_66MHZ 0x0800 + +/* Mask bits for fields in Word 0x0f of the EEPROM */ +#define EEPROM_WORD0F_PAUSE_MASK 0x3000 +#define EEPROM_WORD0F_PAUSE 0x1000 +#define EEPROM_WORD0F_ASM_DIR 0x2000 +#define EEPROM_WORD0F_ANE 0x0800 +#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0 + +/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ +#define EEPROM_SUM 0xBABA + +/* EEPROM Map defines (WORD OFFSETS)*/ +#define EEPROM_NODE_ADDRESS_BYTE_0 0 +#define EEPROM_PBA_BYTE_1 8 + +/* EEPROM Map Sizes (Byte Counts) */ +#define PBA_SIZE 4 + +/* Collision related configuration parameters */ +#define E1000_COLLISION_THRESHOLD 16 +#define E1000_CT_SHIFT 4 +#define E1000_FDX_COLLISION_DISTANCE 64 +#define E1000_HDX_COLLISION_DISTANCE 64 +#define E1000_GB_HDX_COLLISION_DISTANCE 512 +#define E1000_COLD_SHIFT 12 + +/* The number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Default values for the transmit IPG register */ +#define DEFAULT_82542_TIPG_IPGT 10 +#define DEFAULT_82543_TIPG_IPGT_FIBER 9 +#define DEFAULT_82543_TIPG_IPGT_COPPER 8 + +#define E1000_TIPG_IPGT_MASK 0x000003FF +#define E1000_TIPG_IPGR1_MASK 0x000FFC00 +#define E1000_TIPG_IPGR2_MASK 0x3FF00000 + +#define DEFAULT_82542_TIPG_IPGR1 2 +#define DEFAULT_82543_TIPG_IPGR1 8 +#define E1000_TIPG_IPGR1_SHIFT 10 + +#define DEFAULT_82542_TIPG_IPGR2 10 +#define DEFAULT_82543_TIPG_IPGR2 6 +#define E1000_TIPG_IPGR2_SHIFT 20 + +#define E1000_TXDMAC_DPP 0x00000001 + +/* PBA constants */ +#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_24K 0x0018 +#define E1000_PBA_40K 0x0028 +#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ + +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 + +/* The historical defaults for the flow control values are given below. */ +#define FC_DEFAULT_HI_THRESH (0x8000) /* 32KB */ +#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */ +#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */ + + +/* The number of bits that we need to shift right to move the "pause" + * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field + * in the TXCW register + */ +#define PAUSE_SHIFT 5 + +/* The number of bits that we need to shift left to move the "SWDPIO" + * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field + * in the CTRL register + */ +#define SWDPIO_SHIFT 17 + +/* The number of bits that we need to shift left to move the "SWDPIO_EXT" + * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The + * Extended CTRL register. + * in the CTRL register + */ +#define SWDPIO__EXT_SHIFT 4 + +/* The number of bits that we need to shift left to move the "ILOS" + * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field + * in the CTRL register + */ +#define ILOS_SHIFT 3 + + +#define RECEIVE_BUFFER_ALIGN_SIZE (256) + +/* The number of milliseconds we wait for auto-negotiation to complete */ +#define LINK_UP_TIMEOUT 500 + +#define E1000_TX_BUFFER_SIZE ((uint32_t)1514) + +/* The carrier extension symbol, as received by the NIC. */ +#define CARRIER_EXTENSION 0x0F + +/* TBI_ACCEPT macro definition: + * + * This macro requires: + * adapter = a pointer to struct e1000_shared_adapter + * status = the 8 bit status field of the RX descriptor with EOP set + * error = the 8 bit error field of the RX descriptor with EOP set + * length = the sum of all the length fields of the RX descriptors that + * make up the current frame + * last_byte = the last byte of the frame DMAed by the hardware + * max_frame_length = the maximum frame length we want to accept. + * min_frame_length = the minimum frame length we want to accept. + * + * This macro is a conditional that should be used in the interrupt + * handler's Rx processing routine when RxErrors have been detected. + * + * Typical use: + * ... + * if (TBI_ACCEPT) { + * accept_frame = TRUE; + * e1000_tbi_adjust_stats(adapter, MacAddress); + * frame_length--; + * } else { + * accept_frame = FALSE; + * } + * ... + */ + +#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \ + ((adapter)->tbi_compatibility_on && \ + (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \ + ((last_byte) == CARRIER_EXTENSION) && \ + (((status) & E1000_RXD_STAT_VP) ? \ + (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \ + ((length) <= ((adapter)->max_frame_size + 1))) : \ + (((length) > (adapter)->min_frame_size) && \ + ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1))))) + + +#endif /* _E1000_MAC_H_ */ diff -Nur linux-2.4.19/drivers/net/e1000/e1000_main.c linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_main.c --- linux-2.4.19/drivers/net/e1000/e1000_main.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_main.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,3780 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + + +#define __E1000_MAIN__ +#ifdef IANS +#define _IANS_MAIN_MODULE_C_ +#endif +#include "e1000.h" + +/* Driver name string */ +char e1000_driver_name[] = "e1000"; + +/* Driver ID string, displayed when loading */ +char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; + +/* Driver version */ +char e1000_driver_version[] = "4.1.7"; + +/* Copyright string, displayed when loading */ +char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation."; + +/* Linked list of board private structures for all NICs found */ +struct e1000_adapter *e1000_adapter_list = NULL; + +/* e1000_strings - PCI Device ID Table + * + * for selecting devices to load on + * private driver_data field (last one) stores an index + * into e1000_strings + * Wildcard entries (PCI_ANY_ID) should come last + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, + * Class, Class Mask, String Index } + */ +static struct pci_device_id e1000_pci_table[] = { + /* Intel(R) PRO/1000 Network Connection */ + {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0}, + {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0}, + {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0}, + {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0}, + {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0}, + {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0}, + {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0}, + /* Compaq Gigabit Ethernet Server Adapter */ + {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + /* IBM Mobile, Desktop & Server Adapters */ + {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2}, + {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2}, + {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2}, + /* Generic */ + {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, e1000_pci_table); + +/* e1000_pci_table - Table of branding strings for all supported NICs. */ + +static char *e1000_strings[] = { + "Intel(R) PRO/1000 Network Connection", + "Compaq Gigabit Ethernet Server Adapter", + "IBM Mobile, Desktop & Server Adapters" +}; + +/* PCI driver information (Linux 2.4 driver API) */ +static struct pci_driver e1000_driver = { + name: e1000_driver_name, + id_table: e1000_pci_table, + probe: e1000_probe, + remove: e1000_remove, + /* Power Managment Hooks */ + suspend: NULL, + resume: NULL +}; + +/* Module Parameters are always initialized to -1, so that the driver + * can tell the difference between no user specified value or the + * user asking for the default value. + * The true default values are loaded in when e1000_check_options is called. + */ + +/* This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ + +#define E1000_MAX_NIC 8 + +/* This is a GCC extension to ANSI C. + * See the item "Labeled Elements in Initializers" in the section + * "Extensions to the C Language Family" of the GCC documentation. + */ + +#define E1000_OPTION_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } + +/* Transmit Descriptor Count + * + * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers + * Valid Range: 80-4096 for 82544 + * + * Default Value: 256 + */ + +static int TxDescriptors[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* Receive Descriptor Count + * + * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers + * Valid Range: 80-4096 for 82544 + * + * Default Value: 256 + */ + +static int RxDescriptors[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* User Specified Speed Override + * + * Valid Range: 0, 10, 100, 1000 + * - 0 - auto-negotiate at all supported speeds + * - 10 - only link at 10 Mbps + * - 100 - only link at 100 Mbps + * - 1000 - only link at 1000 Mbps + * + * Default Value: 0 + */ + +static int Speed[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* User Specified Duplex Override + * + * Valid Range: 0-2 + * - 0 - auto-negotiate for duplex + * - 1 - only link at half duplex + * - 2 - only link at full duplex + * + * Default Value: 0 + */ + +static int Duplex[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* Auto-negotiation Advertisement Override + * + * Valid Range: 0x00-0x0F, 0x20-0x2F + * + * The AutoNeg value is a bit mask describing which speed and duplex + * combinations should be advertised during auto-negotiation. + * The supported speed and duplex modes are listed below + * + * Bit 7 6 5 4 3 2 1 0 + * Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10 + * Duplex Full Full Half Full Half + * + * Default Value: 0x2F + */ + +static int AutoNeg[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* User Specified Flow Control Override + * + * Valid Range: 0-3 + * - 0 - No Flow Control + * - 1 - Rx only, respond to PAUSE frames but do not generate them + * - 2 - Tx only, generate PAUSE frames but ignore them on receive + * - 3 - Full Flow Control Support + * + * Default Value: Read flow control settings from the EEPROM + */ + +static int FlowControl[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* XsumRX - Receive Checksum Offload Enable/Disable + * + * Valid Range: 0, 1 + * - 0 - disables all checksum offload + * - 1 - enables receive IP/TCP/UDP checksum offload + * on 82543 based NICs + * + * Default Value: 1 + */ + +static int XsumRX[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* Transmit Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 64 + */ + +static int TxIntDelay[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* Receive Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 64 + */ + +static int RxIntDelay[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* MDI-X Support Enable/Disable - Applies only to Copper PHY + * + * Valid Range: 0, 3 + * - 0 - Auto in all modes + * - 1 - MDI + * - 2 - MDI-X + * - 3 - Auto in 1000 Base-T mode (MDI in 10 Base-T and 100 Base-T) + * + * Default Value: 0 (Auto) + */ + +static int MdiX[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +/* Automatic Correction of Reversed Cable Polarity Enable/Disable + * This setting applies only to Copper PHY + * + * Valid Range: 0, 1 + * - 0 - Disabled + * - 1 - Enabled + * + * Default Value: 1 (Enabled) + */ + +static int DisablePolarityCorrection[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; + +#ifdef MODULE + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); + +#if defined(MODULE_LICENSE) +MODULE_LICENSE("BSD with patent grant"); +#endif + +MODULE_PARM(TxDescriptors, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(RxDescriptors, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(Speed, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(Duplex, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(AutoNeg, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(XsumRX, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(FlowControl, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(TxIntDelay, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(RxIntDelay, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(MdiX, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); +MODULE_PARM(DisablePolarityCorrection, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); + +MODULE_PARM_DESC(TxDescriptors, "Number of transmit descriptors"); +MODULE_PARM_DESC(RxDescriptors, "Number of receive descriptors"); +MODULE_PARM_DESC(Speed, "Speed setting"); +MODULE_PARM_DESC(Duplex, "Duplex setting"); +MODULE_PARM_DESC(AutoNeg, "Advertised auto-negotiation setting"); +MODULE_PARM_DESC(XsumRX, "Disable or enable Receive Checksum offload"); +MODULE_PARM_DESC(FlowControl, "Flow Control setting"); +MODULE_PARM_DESC(TxIntDelay, "Transmit Interrupt Delay"); +MODULE_PARM_DESC(RxIntDelay, "Receive Interrupt Delay"); +MODULE_PARM_DESC(MdiX, "Set MDI/MDI-X Mode"); +MODULE_PARM_DESC(DisablePolarityCorrection, + "Disable or enable Automatic Correction for Reversed Cable Polarity"); + +#ifdef EXPORT_SYMTAB +/*EXPORT_SYMBOL(e1000_init_module); +EXPORT_SYMBOL(e1000_exit_module); +EXPORT_SYMBOL(e1000_probe); +EXPORT_SYMBOL(e1000_remove); +EXPORT_SYMBOL(e1000_open); +EXPORT_SYMBOL(e1000_close); +EXPORT_SYMBOL(e1000_xmit_frame); +EXPORT_SYMBOL(e1000_intr); +EXPORT_SYMBOL(e1000_set_multi); +EXPORT_SYMBOL(e1000_change_mtu); +EXPORT_SYMBOL(e1000_set_mac); +EXPORT_SYMBOL(e1000_get_stats); +EXPORT_SYMBOL(e1000_watchdog); +EXPORT_SYMBOL(e1000_ioctl); +EXPORT_SYMBOL(e1000_adapter_list);*/ +#endif + +#endif + +/* Local Function Prototypes */ + +static void e1000_check_options(struct e1000_adapter *adapter); +static void e1000_check_fiber_options(struct e1000_adapter *adapter); +static void e1000_check_copper_options(struct e1000_adapter *adapter); +static int e1000_sw_init(struct e1000_adapter *adapter); +static int e1000_hw_init(struct e1000_adapter *adapter); +static void e1000_read_address(struct e1000_adapter *adapter, + uint8_t *addr); +static int e1000_setup_tx_resources(struct e1000_adapter *adapter); +static int e1000_setup_rx_resources(struct e1000_adapter *adapter); +static void e1000_setup_rctl(struct e1000_adapter *adapter); +static void e1000_configure_rx(struct e1000_adapter *adapter); +static void e1000_configure_tx(struct e1000_adapter *adapter); +static void e1000_free_tx_resources(struct e1000_adapter *adapter); +static void e1000_free_rx_resources(struct e1000_adapter *adapter); +static void e1000_update_stats(struct e1000_adapter *adapter); +static inline void e1000_irq_disable(struct e1000_adapter *adapter); +static inline void e1000_irq_enable(struct e1000_adapter *adapter); +static void e1000_clean_tx_irq(struct e1000_adapter *adapter); +static void e1000_clean_rx_irq(struct e1000_adapter *adapter); +static inline void e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb); +static void e1000_alloc_rx_buffers(unsigned long data); +static void e1000_clean_tx_ring(struct e1000_adapter *adapter); +static void e1000_clean_rx_ring(struct e1000_adapter *adapter); +void e1000_hibernate_adapter(struct net_device *netdev); +void e1000_wakeup_adapter(struct net_device *netdev); +static void e1000_enable_WOL(struct e1000_adapter *adapter); + +#ifdef SIOCETHTOOL +static int e1000_ethtool_ioctl(struct net_device *netdev, + struct ifreq *ifr); +#endif +#ifdef IDIAG +static int e1000_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size); +#endif + +/** + * e1000_init_module - Driver Registration Routine + * + * e1000_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ + +int +e1000_init_module() +{ + E1000_DBG("e1000_init_module\n"); + + /* Print the driver ID string and copyright notice */ + + printk("%s - version %s\n%s\n", e1000_driver_string, e1000_driver_version, + e1000_copyright); + + /* register the driver with the PCI subsystem */ + + return pci_module_init(&e1000_driver); +} + +/* this macro creates a special symbol in the object file that + * identifies the driver initialization routine + */ +module_init(e1000_init_module); + +/** + * e1000_exit_module - Driver Exit Cleanup Routine + * + * e1000_exit_module is called just before the driver is removed + * from memory. + **/ + +void +e1000_exit_module() +{ +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *de; +#endif + + E1000_DBG("e1000_exit_module\n"); + + pci_unregister_driver(&e1000_driver); + +#ifdef CONFIG_PROC_FS + /* if there is no e1000_proc_dir (proc creation failure on load) + * then we're done + */ + if(e1000_proc_dir == NULL) + return; + + /* If ADAPTERS_PROC_DIR (/proc/net/PRO_LAN_Adapters) is empty + * it can be removed now (might still be in use by e100) + */ + for(de = e1000_proc_dir->subdir; de; de = de->next) { + + /* ignore . and .. */ + + if(*(de->name) == '.') + continue; + break; + } + if(de) + return; + remove_proc_entry(ADAPTERS_PROC_DIR, proc_net); +#endif + + return; +} + +/* this macro creates a special symbol in the object file that + * identifies the driver cleanup routine + */ +module_exit(e1000_exit_module); + +/** + * e1000_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in e1000_pci_table + * + * Returns 0 on success, negative on failure + * + * e1000_probe initializes an adapter identified by a pci_dev + * structure. The OS initialization is handled here, and + * e1000_sw_init and e1000_hw_init are called to handle the driver + * specific software structures and hardware initialization + * respectively. + **/ + +int +e1000_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev = NULL; + struct e1000_adapter *adapter; + static int cards_found = 0; + +#ifdef CONFIG_PROC_FS + int len; +#endif + + E1000_DBG("e1000_probe\n"); + + /* Make sure the PCI device has the proper resources available */ + + if(pci_enable_device(pdev) != 0) { + E1000_ERR("pci_enable_device failed\n"); + return -ENODEV; + } + + /* Make sure we are enabled as a bus mastering device */ + + pci_set_master(pdev); + + /* Check to see if our PCI addressing needs are supported */ + if(pci_set_dma_mask(pdev, E1000_DMA_MASK) < 0) { + E1000_ERR("PCI DMA not supported by the system\n"); + return -ENODEV; + } + + /* Allocate private data structure (struct e1000_adapter) + */ + netdev = alloc_etherdev(sizeof(struct e1000_adapter)); + + if(netdev == NULL) { + E1000_ERR("Unable to allocate net_device struct\n"); + return -ENOMEM; + } + + /* Calling alloc_etherdev with sizeof(struct e1000_adapter) allocates + * a single buffer of size net_device + struct e1000_adapter + + * alignment. If this is not done then the struct e1000_adapter needs + * to be allocated and freed separately. + */ + adapter = (struct e1000_adapter *) netdev->priv; + memset(adapter, 0, sizeof(struct e1000_adapter)); + adapter->netdev = netdev; + adapter->pdev = pdev; + + /* link the struct e1000_adapter into the list */ + + if(e1000_adapter_list != NULL) + e1000_adapter_list->prev = adapter; + adapter->next = e1000_adapter_list; + e1000_adapter_list = adapter; + adapter->shared.back = (void *) adapter; + + /* reserve the MMIO region as ours */ + + if(!request_mem_region + (pci_resource_start(pdev, BAR_0), pci_resource_len(pdev, BAR_0), + e1000_driver_name)) { + E1000_ERR("request_mem_region failed\n"); + e1000_remove(pdev); + return -ENODEV; + } + + /* map the MMIO region into the kernel virtual address space */ + + adapter->shared.hw_addr = + ioremap(pci_resource_start(pdev, BAR_0), pci_resource_len(pdev, BAR_0)); + + if(adapter->shared.hw_addr == NULL) { + E1000_ERR("ioremap failed\n"); + release_mem_region(pci_resource_start(pdev, BAR_0), + pci_resource_len(pdev, BAR_0)); + e1000_remove(pdev); + return -ENOMEM; + } + + /* don't actually register the interrupt handler until e1000_open */ + + netdev->irq = pdev->irq; + + /* Set the MMIO base address for the NIC */ + +#ifdef IANS + netdev->base_addr = pci_resource_start(pdev, BAR_0); +#endif + netdev->mem_start = pci_resource_start(pdev, BAR_0); + netdev->mem_end = netdev->mem_start + pci_resource_len(pdev, BAR_0); + + /* set up function pointers to driver entry points */ + + netdev->open = &e1000_open; + netdev->stop = &e1000_close; + netdev->hard_start_xmit = &e1000_xmit_frame; + netdev->get_stats = &e1000_get_stats; + netdev->set_multicast_list = &e1000_set_multi; + netdev->set_mac_address = &e1000_set_mac; + netdev->change_mtu = &e1000_change_mtu; + netdev->do_ioctl = &e1000_ioctl; + + /* set up the struct e1000_adapter */ + + adapter->bd_number = cards_found; + adapter->id_string = e1000_strings[ent->driver_data]; + printk("\n%s\n", adapter->id_string); + + /* Order is important here. e1000_sw_init also identifies the + * hardware, so that e1000_check_options can treat command line parameters + * differently depending on the hardware. + */ + e1000_sw_init(adapter); + e1000_check_options(adapter); + +#ifdef MAX_SKB_FRAGS + if(adapter->shared.mac_type >= e1000_82543) { + netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + } else { + netdev->features = NETIF_F_SG | NETIF_F_HIGHDMA; + } +#endif + +#ifdef IANS + adapter->iANSdata = kmalloc(sizeof(iANSsupport_t), GFP_KERNEL); + if(adapter->iANSdata == NULL) { + e1000_remove(pdev); + return -ENOMEM; + } + memset(adapter->iANSdata, 0, sizeof(iANSsupport_t)); + bd_ans_drv_InitANS(adapter, adapter->iANSdata); +#endif + + /* finally, we get around to setting up the hardware */ + + if(e1000_hw_init(adapter) < 0) { + e1000_remove(pdev); + return -ENODEV; + } + cards_found++; + + /* reset stats */ + + e1000_clear_hw_cntrs(&adapter->shared); + e1000_phy_get_info(&adapter->shared, &adapter->phy_info); + + /* Then register the net device once everything initializes + */ + register_netdev(netdev); + +#ifdef CONFIG_PROC_FS + /* set up the proc fs entry */ + + len = strlen(ADAPTERS_PROC_DIR); + + for(e1000_proc_dir = proc_net->subdir; e1000_proc_dir; + e1000_proc_dir = e1000_proc_dir->next) { + if((e1000_proc_dir->namelen == len) && + (memcmp(e1000_proc_dir->name, ADAPTERS_PROC_DIR, len) == 0)) + break; + } + + if(e1000_proc_dir == NULL) + e1000_proc_dir = + create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net); + + if(e1000_proc_dir != NULL) + if(e1000_create_proc_dev(adapter) < 0) { + e1000_remove_proc_dev(adapter->netdev); + } +#endif + + /* print the link status */ + + if(adapter->link_active == 1) + printk("%s: Mem:0x%p IRQ:%d Speed:%d Mbps Duplex:%s\n", + netdev->name, (void *) netdev->mem_start, netdev->irq, + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half"); + else + printk("%s: Mem:0x%p IRQ:%d Speed:N/A Duplex:N/A\n", netdev->name, + (void *) netdev->mem_start, netdev->irq); + + return 0; +} + +/** + * e1000_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * e1000_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + * + * This routine is also called to clean up from a failure in + * e1000_probe. The Adapter struct and netdev will always exist, + * all other pointers must be checked for NULL before freeing. + **/ + +void +e1000_remove(struct pci_dev *pdev) +{ + struct net_device *netdev; + struct e1000_adapter *adapter; + + /* find the Adapter struct that matches this PCI device */ + + for(adapter = e1000_adapter_list; adapter != NULL; adapter = adapter->next) { + if(adapter->pdev == pdev) + break; + } + if(adapter == NULL) + return; + + netdev = adapter->netdev; + + /* this must be called before freeing anything, + * otherwise there is a case where the open entry point can be + * running at the same time as remove. Calling unregister_netdev on an + * open interface results in a call to dev_close, which locks + * properly against the other netdev entry points, so this takes + * care of the hotplug issue of removing an active interface as well. + */ + unregister_netdev(netdev); + + e1000_phy_hw_reset(&adapter->shared); + +#ifdef CONFIG_PROC_FS + /* remove the proc nodes */ + + if(e1000_proc_dir != NULL) + e1000_remove_proc_dev(adapter->netdev); +#endif + + /* remove from the adapter list */ + + if(e1000_adapter_list == adapter) + e1000_adapter_list = adapter->next; + if(adapter->next != NULL) + adapter->next->prev = adapter->prev; + if(adapter->prev != NULL) + adapter->prev->next = adapter->next; + + /* free system resources */ + +#ifdef IANS + if(adapter->iANSdata != NULL) + kfree(adapter->iANSdata); +#endif + + if(adapter->shared.hw_addr != NULL) { + iounmap((void *) adapter->shared.hw_addr); + release_mem_region(pci_resource_start(pdev, BAR_0), + pci_resource_len(pdev, BAR_0)); + } + + /* free the net_device _and_ struct e1000_adapter memory */ + + kfree(netdev); + + return; +} + +/** + * e1000_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line paramters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the Adapter structure. + **/ + +static void +e1000_check_options(struct e1000_adapter *adapter) +{ + int board = adapter->bd_number; + + if(board >= E1000_MAX_NIC) { + printk("Warning: no configuration for board #%i\n", board); + printk("Using defaults for all values\n"); + board = E1000_MAX_NIC; + } + + E1000_DBG("e1000_check_options\n"); + + /* Transmit Descriptor Count */ + + if(TxDescriptors[board] == OPTION_UNSET) { + adapter->tx_ring.count = DEFAULT_TXD; + TxDescriptors[board] = DEFAULT_TXD; + } else + if(((TxDescriptors[board] > MAX_TXD) || + (TxDescriptors[board] < MIN_TXD)) && + (adapter->shared.mac_type <= e1000_82543)) { + printk("Invalid TxDescriptors specified (%i), using default %i\n", + TxDescriptors[board], DEFAULT_TXD); + adapter->tx_ring.count = DEFAULT_TXD; + } else + if(((TxDescriptors[board] > MAX_82544_TXD) || + (TxDescriptors[board] < MIN_TXD)) && + (adapter->shared.mac_type > e1000_82543)) { + printk("Invalid TxDescriptors specified (%i), using default %i\n", + TxDescriptors[board], DEFAULT_TXD); + adapter->tx_ring.count = DEFAULT_TXD; + } else { + printk("Using specified value of %i TxDescriptors\n", + TxDescriptors[board]); + adapter->tx_ring.count = TxDescriptors[board]; + } + + /* tx_ring.count must be a multiple of 8 */ + + adapter->tx_ring.count = E1000_ROUNDUP2(adapter->tx_ring.count, + REQ_TX_DESCRIPTOR_MULTIPLE); + + /* Receive Descriptor Count */ + + if(RxDescriptors[board] == OPTION_UNSET) { + adapter->rx_ring.count = DEFAULT_RXD; + RxDescriptors[board] = DEFAULT_RXD; + } else + if(((RxDescriptors[board] > MAX_RXD) || + (RxDescriptors[board] < MIN_RXD)) && + (adapter->shared.mac_type <= e1000_82543)) { + printk("Invalid RxDescriptors specified (%i), using default %i\n", + RxDescriptors[board], DEFAULT_RXD); + adapter->rx_ring.count = DEFAULT_RXD; + } else + if(((RxDescriptors[board] > MAX_82544_RXD) || + (RxDescriptors[board] < MIN_RXD)) && + (adapter->shared.mac_type > e1000_82543)) { + printk("Invalid RxDescriptors specified (%i), using default %i\n", + RxDescriptors[board], DEFAULT_RXD); + adapter->rx_ring.count = DEFAULT_RXD; + } else { + printk("Using specified value of %i RxDescriptors\n", + RxDescriptors[board]); + adapter->rx_ring.count = RxDescriptors[board]; + } + + /* rx_ring.count must be a multiple of 8 */ + + adapter->rx_ring.count = + E1000_ROUNDUP2(adapter->rx_ring.count, REQ_RX_DESCRIPTOR_MULTIPLE); + + /* Receive Checksum Offload Enable */ + + if(XsumRX[board] == OPTION_UNSET) { + adapter->RxChecksum = XSUMRX_DEFAULT; + XsumRX[board] = XSUMRX_DEFAULT; + } else if((XsumRX[board] != OPTION_ENABLED) && + (XsumRX[board] != OPTION_DISABLED)) { + printk("Invalid XsumRX specified (%i), using default of %i\n", + XsumRX[board], XSUMRX_DEFAULT); + adapter->RxChecksum = XSUMRX_DEFAULT; + } else { + printk("Receive Checksum Offload %s\n", + XsumRX[board] == OPTION_ENABLED ? "Enabled" : "Disabled"); + adapter->RxChecksum = XsumRX[board]; + } + + /* Flow Control */ + + if(FlowControl[board] == OPTION_UNSET) { + adapter->shared.fc = e1000_fc_default; + FlowControl[board] = e1000_fc_default; + } else if((FlowControl[board] > e1000_fc_full) || + (FlowControl[board] < e1000_fc_none)) { + printk("Invalid FlowControl specified (%i), " + "reading default settings from the EEPROM\n", + FlowControl[board]); + adapter->shared.fc = e1000_fc_default; + } else { + adapter->shared.fc = FlowControl[board]; + switch (adapter->shared.fc) { + case e1000_fc_none: + printk("Flow Control Disabled\n"); + break; + case e1000_fc_rx_pause: + printk("Flow Control Receive Only\n"); + break; + case e1000_fc_tx_pause: + printk("Flow Control Transmit Only\n"); + break; + case e1000_fc_full: + printk("Flow Control Enabled\n"); + case e1000_fc_default: + printk("Flow Control Hardware Default\n"); + } + } + + /* Transmit Interrupt Delay */ + + if(TxIntDelay[board] == OPTION_UNSET) { + adapter->tx_int_delay = DEFAULT_TIDV; + TxIntDelay[board] = DEFAULT_TIDV; + } else if((TxIntDelay[board] > MAX_TIDV) || (TxIntDelay[board] < MIN_TIDV)) { + printk("Invalid TxIntDelay specified (%i), using default %i\n", + TxIntDelay[board], DEFAULT_TIDV); + adapter->tx_int_delay = DEFAULT_TIDV; + } else { + printk("Using specified TxIntDelay of %i\n", TxIntDelay[board]); + adapter->tx_int_delay = TxIntDelay[board]; + } + + /* Receive Interrupt Delay */ + + if(RxIntDelay[board] == OPTION_UNSET) { + adapter->rx_int_delay = DEFAULT_RIDV; + RxIntDelay[board] = DEFAULT_RIDV; + } else if((RxIntDelay[board] > MAX_RIDV) || (RxIntDelay[board] < MIN_RIDV)) { + printk("Invalid RxIntDelay specified (%i), using default %i\n", + RxIntDelay[board], DEFAULT_RIDV); + adapter->rx_int_delay = DEFAULT_RIDV; + } else { + printk("Using specified RxIntDelay of %i\n", RxIntDelay[board]); + adapter->rx_int_delay = RxIntDelay[board]; + } + + if(adapter->shared.media_type == e1000_media_type_copper) { + /* MDI/MDI-X Support */ + + if(MdiX[board] == OPTION_UNSET) { + adapter->shared.mdix = DEFAULT_MDIX; + MdiX[board] = DEFAULT_MDIX; + } else if((MdiX[board] > MAX_MDIX) || (MdiX[board] < MIN_MDIX)) { + printk("Invalid MDI/MDI-X specified (%i), using default %i\n", + MdiX[board], DEFAULT_MDIX); + adapter->shared.mdix = DEFAULT_MDIX; + } else { + printk("Using specified MDI/MDI-X of %i\n", MdiX[board]); + adapter->shared.mdix = MdiX[board]; + } + + /* Automatic Correction for Reverse Cable Polarity */ + + if(DisablePolarityCorrection[board] == OPTION_UNSET) { + adapter->shared.disable_polarity_correction = OPTION_DISABLED; + DisablePolarityCorrection[board] = OPTION_DISABLED; + } else if((DisablePolarityCorrection[board] != OPTION_ENABLED) && + (DisablePolarityCorrection[board] != OPTION_DISABLED)) { + printk("Invalid polarity correction specified (%i)," + " using default %i\n", DisablePolarityCorrection[board], + OPTION_DISABLED); + adapter->shared.disable_polarity_correction = OPTION_DISABLED; + } else { + printk("Using specified polarity correction of %i\n", + DisablePolarityCorrection[board]); + adapter->shared.disable_polarity_correction = + DisablePolarityCorrection[board]; + } + } + + /* Speed, Duplex, and AutoNeg */ + + switch (adapter->shared.media_type) { + + case e1000_media_type_fiber: + e1000_check_fiber_options(adapter); + break; + + case e1000_media_type_copper: + e1000_check_copper_options(adapter); + break; + + default: + printk("Unknown Media Type\n"); + break; + } + + return; +} + +/** + * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version + * @adapter: board private structure + * + * Handles speed and duplex options on fiber based adapters + **/ + +static void +e1000_check_fiber_options(struct e1000_adapter *adapter) +{ + int board = + adapter->bd_number > E1000_MAX_NIC ? E1000_MAX_NIC : adapter->bd_number; + + E1000_DBG("CheckSpeedDuplexFiber\n"); + + /* Speed, Duplex, and AutoNeg are not valid on fiber NICs */ + + if((Speed[board] != OPTION_UNSET)) { + Speed[board] = 0; + printk("Warning: Speed not valid for fiber adapters\n"); + printk("Speed Parameter Ignored\n"); + } + if((Duplex[board] != OPTION_UNSET)) { + Duplex[board] = 0; + printk("Warning: Duplex not valid for fiber adapters\n"); + printk("Duplex Parameter Ignored\n"); + } + if((AutoNeg[board] != OPTION_UNSET)) { + AutoNeg[board] = AUTONEG_ADV_DEFAULT; + printk("Warning: AutoNeg not valid for fiber adapters\n"); + printk("AutoNeg Parameter Ignored\n"); + } + + return; +} + +/** + * e1000_check_copper_options - Range Checking for Link Options, Copper Version + * @adapter: board private structure + * + * Handles speed and duplex options on copper based adapters + **/ + +static void +e1000_check_copper_options(struct e1000_adapter *adapter) +{ + int board = + adapter->bd_number > E1000_MAX_NIC ? E1000_MAX_NIC : adapter->bd_number; + int speed, duplex; + boolean_t all_default = TRUE; + + E1000_DBG("CheckSpeedDuplexCopper\n"); + + /* User Specified Auto-negotiation Settings */ + + if(AutoNeg[board] == OPTION_UNSET) { + + adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + AutoNeg[board] = AUTONEG_ADV_DEFAULT; + + } else if((Speed[board] != 0 && Speed[board] != OPTION_UNSET) || + (Duplex[board] != 0 && Duplex[board] != OPTION_UNSET)) { + + printk("Warning: AutoNeg specified along with Speed or Duplex\n"); + printk("AutoNeg Parameter Ignored\n"); + + adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + + } else { + + if(AutoNeg[board] & ~AUTONEG_ADV_MASK) { + + printk("Invalid AutoNeg Specified (0x%X), Parameter Ignored\n", + AutoNeg[board]); + + adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + + } else { + + adapter->shared.autoneg_advertised = AutoNeg[board]; + } + + printk("AutoNeg Advertising "); + if(adapter->shared.autoneg_advertised & ADVERTISE_1000_FULL) { + printk("1000/FD"); + if(adapter->shared.autoneg_advertised & (ADVERTISE_1000_FULL - 1)) + printk(", "); + } + if(adapter->shared.autoneg_advertised & ADVERTISE_1000_HALF) { + printk("1000/HD"); + if(adapter->shared.autoneg_advertised & (ADVERTISE_1000_HALF - 1)) + printk(", "); + } + if(adapter->shared.autoneg_advertised & ADVERTISE_100_FULL) { + printk("100/FD"); + if(adapter->shared.autoneg_advertised & (ADVERTISE_100_FULL - 1)) + printk(", "); + } + if(adapter->shared.autoneg_advertised & ADVERTISE_100_HALF) { + printk("100/HD"); + if(adapter->shared.autoneg_advertised & (ADVERTISE_100_HALF - 1)) + printk(", "); + } + if(adapter->shared.autoneg_advertised & ADVERTISE_10_FULL) { + printk("10/FD"); + if(adapter->shared.autoneg_advertised & (ADVERTISE_10_FULL - 1)) + printk(", "); + } + if(adapter->shared.autoneg_advertised & ADVERTISE_10_HALF) + printk("10/HD"); + printk("\n"); + } + + /* Forced Speed and Duplex */ + + switch (Speed[board]) { + default: + printk("Invalid Speed Specified (%i), Parameter Ignored\n", + Speed[board]); + all_default = FALSE; + case OPTION_UNSET: + speed = 0; + Speed[board] = 0; + break; + case 0: + case 10: + case 100: + case 1000: + speed = Speed[board]; + all_default = FALSE; + break; + } + + switch (Duplex[board]) { + default: + printk("Invalid Duplex Specified (%i), Parameter Ignored\n", + Duplex[board]); + all_default = FALSE; + case OPTION_UNSET: + duplex = 0; + Duplex[board] = 0; + break; + case 0: + case 1: + case 2: + duplex = Duplex[board]; + all_default = FALSE; + break; + } + + switch (speed + duplex) { + case 0: + if(all_default == FALSE) + printk("Speed and Duplex Auto-negotiation Enabled\n"); + adapter->shared.autoneg = 1; + break; + case 1: + printk("Warning: Half Duplex specified without Speed\n"); + printk("Using Auto-negotiation at Half Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = + ADVERTISE_10_HALF | ADVERTISE_100_HALF; + break; + case 2: + printk("Warning: Full Duplex specified without Speed\n"); + printk("Using Auto-negotiation at Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = + ADVERTISE_10_FULL | ADVERTISE_100_FULL | ADVERTISE_1000_FULL; + break; + case 10: + printk("Warning: 10 Mbps Speed specified without Duplex\n"); + printk("Using Auto-negotiation at 10 Mbps only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = + ADVERTISE_10_HALF | ADVERTISE_10_FULL; + break; + case 11: + printk("Forcing to 10 Mbps Half Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_10_half; + adapter->shared.autoneg_advertised = 0; + break; + case 12: + printk("Forcing to 10 Mbps Full Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_10_full; + adapter->shared.autoneg_advertised = 0; + break; + case 100: + printk("Warning: 100 Mbps Speed specified without Duplex\n"); + printk("Using Auto-negotiation at 100 Mbps only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = + ADVERTISE_100_HALF | ADVERTISE_100_FULL; + break; + case 101: + printk("Forcing to 100 Mbps Half Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_100_half; + adapter->shared.autoneg_advertised = 0; + break; + case 102: + printk("Forcing to 100 Mbps Full Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_100_full; + adapter->shared.autoneg_advertised = 0; + break; + case 1000: + printk("Warning: 1000 Mbps Speed specified without Duplex\n"); + printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case 1001: + printk("Warning: Half Duplex is not supported at 1000 Mbps\n"); + printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case 1002: + printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + default: + panic("something is wrong in e1000_check_copper_options"); + } + + /* Speed, AutoNeg and MDI/MDI-X */ + if (!e1000_validate_mdi_setting(&(adapter->shared))) { + printk ("Speed, AutoNeg and MDI-X specifications are incompatible." + " Setting MDI-X to a compatible value.\n"); + } + + return; +} + +/** + * e1000_sw_init - Initialize general software structures (struct e1000_adapter) + * @adapter: board private structure to initialize + * + * Returns 0 on success, negative on failure + * + * e1000_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ + +static int +e1000_sw_init(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + uint32_t status; + + E1000_DBG("e1000_sw_init\n"); + + /* PCI config space info */ + + pci_read_config_word(pdev, PCI_VENDOR_ID, &adapter->vendor_id); + pci_read_config_word(pdev, PCI_DEVICE_ID, &adapter->device_id); + pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->rev_id); + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &adapter->subven_id); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &adapter->subsys_id); + pci_read_config_word(pdev, PCI_COMMAND, &adapter->shared.pci_cmd_word); + adapter->shared.vendor_id = adapter->vendor_id; + adapter->shared.device_id = adapter->device_id; + adapter->shared.revision_id = adapter->rev_id; + adapter->shared.subsystem_vendor_id = adapter->subven_id; + adapter->shared.subsystem_id = adapter->subsys_id; + + /* Initial Receive Buffer Length */ + + if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_2048) + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_4096) + adapter->rx_buffer_len = E1000_RXBUFFER_4096; + else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_8192) + adapter->rx_buffer_len = E1000_RXBUFFER_8192; + else + adapter->rx_buffer_len = E1000_RXBUFFER_16384; + + adapter->shared.max_frame_size = + netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH; + adapter->shared.min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH; + + /* MAC and Phy settings */ + + switch (adapter->device_id) { + case E1000_DEV_ID_82542: + switch (adapter->rev_id) { + case E1000_82542_2_0_REV_ID: + adapter->shared.mac_type = e1000_82542_rev2_0; + break; + case E1000_82542_2_1_REV_ID: + adapter->shared.mac_type = e1000_82542_rev2_1; + break; + default: + adapter->shared.mac_type = e1000_82542_rev2_0; + E1000_ERR("Could not identify 82542 revision\n"); + } + break; + case E1000_DEV_ID_82543GC_FIBER: + case E1000_DEV_ID_82543GC_COPPER: + adapter->shared.mac_type = e1000_82543; + break; + case E1000_DEV_ID_82544EI_COPPER: + case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82544GC_COPPER: + case E1000_DEV_ID_82544GC_LOM: + adapter->shared.mac_type = e1000_82544; + break; + case E1000_DEV_ID_82540EM: + adapter->shared.mac_type = e1000_82540; + break; + default: + E1000_ERR("Could not identify hardware\n"); + return -ENODEV; + } + + adapter->shared.fc_high_water = FC_DEFAULT_HI_THRESH; + adapter->shared.fc_low_water = FC_DEFAULT_LO_THRESH; + adapter->shared.fc_pause_time = FC_DEFAULT_TX_TIMER; + adapter->shared.fc_send_xon = 1; + + /* Identify the Hardware - this is done by the gigabit shared code + * in e1000_init_hw, but it would help to identify the NIC + * before bringing the hardware online for use in e1000_check_options. + */ + if(adapter->shared.mac_type >= e1000_82543) { + status = E1000_READ_REG(&adapter->shared, STATUS); + if(status & E1000_STATUS_TBIMODE) { + adapter->shared.media_type = e1000_media_type_fiber; + } else { + adapter->shared.media_type = e1000_media_type_copper; + } + } else { + adapter->shared.media_type = e1000_media_type_fiber; + } + + if((E1000_REPORT_TX_EARLY == 0) || (E1000_REPORT_TX_EARLY == 1)) { + adapter->shared.report_tx_early = E1000_REPORT_TX_EARLY; + } else { + if(adapter->shared.mac_type < e1000_82543) { + + adapter->shared.report_tx_early = 0; + } else { + adapter->shared.report_tx_early = 1; + } + } + + adapter->shared.wait_autoneg_complete = WAITFORLINK_DEFAULT; + + adapter->shared.tbi_compatibility_en = 1; + + atomic_set(&adapter->tx_timeout, 0); + + spin_lock_init(&adapter->stats_lock); + spin_lock_init(&adapter->rx_fill_lock); + + return 0; +} + +/** + * e1000_hw_init - prepare the hardware + * @adapter: board private struct containing configuration + * + * Returns 0 on success, negative on failure + * + * Initialize the hardware to a configuration as specified by the + * Adapter structure. The controler is reset, the EEPROM is + * verified, the MAC address is set, then the shared initilization + * routines are called. + **/ + +static int +e1000_hw_init(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + E1000_DBG("e1000_hw_init\n"); + + /* Repartition Pba for greater than 9k mtu + * To take effect Ctrl_Rst is required. + */ + if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) + E1000_WRITE_REG(&adapter->shared, PBA, E1000_JUMBO_PBA); + else + E1000_WRITE_REG(&adapter->shared, PBA, E1000_DEFAULT_PBA); + + /* Issue a global reset */ + + adapter->shared.adapter_stopped = 0; + e1000_adapter_stop(&adapter->shared); + adapter->shared.adapter_stopped = 0; + + /* make sure the EEPROM is good */ + + if(!e1000_validate_eeprom_checksum(&adapter->shared)) { + E1000_ERR("The EEPROM Checksum Is Not Valid\n"); + return -1; + } + + /* copy the MAC address out of the EEPROM */ + + e1000_read_address(adapter, adapter->perm_net_addr); + memcpy(netdev->dev_addr, adapter->perm_net_addr, netdev->addr_len); + memcpy(adapter->shared.mac_addr, netdev->dev_addr, netdev->addr_len); + + e1000_read_part_num(&adapter->shared, &(adapter->part_num)); + + if(!e1000_init_hw(&adapter->shared)) { + E1000_ERR("Hardware Initialization Failed\n"); + return -1; + } + + e1000_enable_WOL(adapter); + + adapter->shared.get_link_status = 1; + e1000_check_for_link(&adapter->shared); + + if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) + adapter->link_active = TRUE; + else + adapter->link_active = FALSE; + + if(adapter->link_active == TRUE) { + e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, + &adapter->link_duplex); + } else { + adapter->link_speed = 0; + adapter->link_duplex = 0; + } + + e1000_get_bus_info(&adapter->shared); + + return 0; +} + +/** + * e1000_read_address - Reads the MAC address from the EEPROM + * @adapter: board private structure + * @addr: pointer to an array of bytes + **/ + +static void +e1000_read_address(struct e1000_adapter *adapter, + uint8_t *addr) +{ + uint16_t eeprom_word; + int i; + + E1000_DBG("e1000_read_address\n"); + + for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) { + eeprom_word = + e1000_read_eeprom(&adapter->shared, + EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); + addr[i] = (uint8_t) (eeprom_word & 0x00FF); + addr[i + 1] = (uint8_t) (eeprom_word >> 8); + } + + return; +} + +/** + * e1000_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ + +int +e1000_open(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + E1000_DBG("e1000_open\n"); + + /* prevent multiple opens when dealing with iANS */ + + if(test_and_set_bit(E1000_BOARD_OPEN, &adapter->flags)) { + return -EBUSY; + } + + adapter->shared.fc = adapter->shared.original_fc; + + /* e1000_close issues a global reset (e1000_adapter_stop) + * so e1000_hw_init must be called again or the hardware + * will resume in it's default state + */ + if(e1000_hw_init(adapter) < 0) { + clear_bit(E1000_BOARD_OPEN, &adapter->flags); + return -EBUSY; + } +#ifdef IANS + /* restore VLAN settings */ + if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode) != + IANS_BD_TAGGING_NONE) + bd_ans_hw_EnableVLAN(adapter); +#endif + + adapter->shared.adapter_stopped = 0; + + /* allocate transmit descriptors */ + + if(e1000_setup_tx_resources(adapter) != 0) { + e1000_adapter_stop(&adapter->shared); + clear_bit(E1000_BOARD_OPEN, &adapter->flags); + return -ENOMEM; + } + e1000_configure_tx(adapter); + + /* allocate receive descriptors and buffers */ + + if(e1000_setup_rx_resources(adapter) != 0) { + e1000_adapter_stop(&adapter->shared); + e1000_free_tx_resources(adapter); + clear_bit(E1000_BOARD_OPEN, &adapter->flags); + return -ENOMEM; + } + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + + /* hook the interrupt */ + + if(request_irq(netdev->irq, &e1000_intr, + SA_SHIRQ, e1000_driver_name, netdev) != 0) { + clear_bit(E1000_BOARD_OPEN, &adapter->flags); + e1000_adapter_stop(&adapter->shared); + e1000_free_tx_resources(adapter); + e1000_free_rx_resources(adapter); + clear_bit(E1000_BOARD_OPEN, &adapter->flags); + return -EBUSY; + } + + /* fill Rx ring with sk_buffs */ + + tasklet_init(&adapter->rx_fill_tasklet, e1000_alloc_rx_buffers, + (unsigned long) adapter); + + tasklet_schedule(&adapter->rx_fill_tasklet); + + /* Set the watchdog timer for 2 seconds */ + + init_timer(&adapter->timer_id); + adapter->timer_id.function = &e1000_watchdog; + adapter->timer_id.data = (unsigned long) netdev; + mod_timer(&adapter->timer_id, (jiffies + 2 * HZ)); + + /* stats accumulated while down are dropped + * this does not clear the running total + */ + + e1000_clear_hw_cntrs(&adapter->shared); + + adapter->int_mask = IMS_ENABLE_MASK; + e1000_irq_enable(adapter); + netif_start_queue(netdev); + +#ifdef MODULE + + /* Incrementing the module use count prevents a driver from being + * unloaded while an active network interface is using it. + */ + MOD_INC_USE_COUNT; + +#endif + + return 0; +} + +/** + * e1000_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ + +int +e1000_close(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + E1000_DBG("e1000_close\n"); + + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + return 0; + + /* Issue a global reset */ + + e1000_adapter_stop((&adapter->shared)); + + /* Enable receiver unit after Global reset + * for WOL, so that receiver can still recive + * wake up packet and will not drop it. + */ + if(adapter->shared.mac_type > e1000_82543) + E1000_WRITE_REG(&adapter->shared, RCTL, E1000_RCTL_EN); + + /* free OS resources */ + + netif_stop_queue(netdev); + free_irq(netdev->irq, netdev); + del_timer_sync(&adapter->timer_id); + + /* Make sure the tasklet won't be left after ifconfig down */ + + /* + * Assumption: tasklet is ALREADY enabled, ie, t->count == 0. + * Otherwise, tasklet is still left in the tasklet list, and, + * tasklet_kill will not be able to return (hang). + */ + tasklet_kill(&adapter->rx_fill_tasklet); + + /* free software resources */ + + e1000_free_tx_resources(adapter); + e1000_free_rx_resources(adapter); + +#ifdef MODULE + + /* decrement the module usage count + * so that the driver can be unloaded + */ + MOD_DEC_USE_COUNT; + +#endif + + clear_bit(E1000_BOARD_OPEN, &adapter->flags); + return 0; +} + +/** + * e1000_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * + * Return 0 on success, negative on failure + * + * e1000_setup_tx_resources allocates all software transmit resources + * and enabled the Tx unit of the MAC. + **/ + +static int +e1000_setup_tx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + + E1000_DBG("e1000_setup_tx_resources\n"); + + size = sizeof(struct e1000_buffer) * adapter->tx_ring.count; + adapter->tx_ring.buffer_info = kmalloc(size, GFP_KERNEL); + if(adapter->tx_ring.buffer_info == NULL) { + return -ENOMEM; + } + memset(adapter->tx_ring.buffer_info, 0, size); + + /* round up to nearest 4K */ + + adapter->tx_ring.size = E1000_ROUNDUP2(adapter->tx_ring.count * + sizeof(struct e1000_tx_desc), + 4096); + + adapter->tx_ring.desc = pci_alloc_consistent(pdev, adapter->tx_ring.size, + &adapter->tx_ring.dma); + if(adapter->tx_ring.desc == NULL) { + kfree(adapter->tx_ring.buffer_info); + return -ENOMEM; + } + memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size); + + atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count); + adapter->tx_ring.next_to_use = 0; + adapter->tx_ring.next_to_clean = 0; + + return 0; +} + +/** + * e1000_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ + +static void +e1000_configure_tx(struct e1000_adapter *adapter) +{ + uint32_t tctl, tipg; + + /* Setup the Base and Length of the Rx Descriptor Ring */ + /* tx_ring.dma can be either a 32 or 64 bit value */ + +#if (BITS_PER_LONG == 32) + E1000_WRITE_REG(&adapter->shared, TDBAL, adapter->tx_ring.dma); + E1000_WRITE_REG(&adapter->shared, TDBAH, 0); +#elif ( BITS_PER_LONG == 64) + E1000_WRITE_REG(&adapter->shared, TDBAL, + (uint32_t) (adapter->tx_ring.dma & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->shared, TDBAH, + (uint32_t) (adapter->tx_ring.dma >> 32)); +#else +#error "Unsupported System - does not use 32 or 64 bit pointers!" +#endif + + E1000_WRITE_REG(&adapter->shared, TDLEN, + adapter->tx_ring.count * sizeof(struct e1000_tx_desc)); + + /* Setup the HW Tx Head and Tail descriptor pointers */ + + E1000_WRITE_REG(&adapter->shared, TDH, 0); + E1000_WRITE_REG(&adapter->shared, TDT, 0); + + /* Set the default values for the Tx Inter Packet Gap timer */ + + switch (adapter->shared.mac_type) { + case e1000_82543: + case e1000_82544: + case e1000_82540: + if(adapter->shared.media_type == e1000_media_type_fiber) + tipg = DEFAULT_82543_TIPG_IPGT_FIBER; + else + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; + tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + break; + case e1000_82542_rev2_0: + case e1000_82542_rev2_1: + default: + tipg = DEFAULT_82542_TIPG_IPGT; + tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + break; + } + E1000_WRITE_REG(&adapter->shared, TIPG, tipg); + + /* Set the Tx Interrupt Delay register */ + + E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay); + + /* Program the Transmit Control Register */ + + tctl = + E1000_TCTL_PSP | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD << + E1000_CT_SHIFT); + if(adapter->link_duplex == FULL_DUPLEX) { + tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } else { + tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } + E1000_WRITE_REG(&adapter->shared, TCTL, tctl); + +#ifdef CONFIG_PPC + if(adapter->shared.mac_type >= e1000_82543) { + E1000_WRITE_REG(&adapter->shared, TXDCTL, 0x00020000); + } +#endif + + /* Setup Transmit Descriptor Settings for this adapter */ + adapter->TxdCmd = E1000_TXD_CMD_IFCS; + + if(adapter->tx_int_delay > 0) + adapter->TxdCmd |= E1000_TXD_CMD_IDE; + if(adapter->shared.report_tx_early == 1) + adapter->TxdCmd |= E1000_TXD_CMD_RS; + else + adapter->TxdCmd |= E1000_TXD_CMD_RPS; + + adapter->ActiveChecksumContext = OFFLOAD_NONE; + + return; +} + +/** + * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs) + * @adapter: board private structure + * + * Returns 0 on success, negative on failure + * + * e1000_setup_rx_resources allocates all software receive resources + * and network buffers, and enables the Rx unit of the MAC. + **/ + +static int +e1000_setup_rx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + + E1000_DBG("e1000_setup_rx_resources\n"); + + size = sizeof(struct e1000_buffer) * adapter->rx_ring.count; + adapter->rx_ring.buffer_info = kmalloc(size, GFP_KERNEL); + if(adapter->rx_ring.buffer_info == NULL) { + return -ENOMEM; + } + memset(adapter->rx_ring.buffer_info, 0, size); + + /* Round up to nearest 4K */ + + adapter->rx_ring.size = E1000_ROUNDUP2(adapter->rx_ring.count * + sizeof(struct e1000_rx_desc), + 4096); + + adapter->rx_ring.desc = pci_alloc_consistent(pdev, adapter->rx_ring.size, + &adapter->rx_ring.dma); + + if(adapter->rx_ring.desc == NULL) { + kfree(adapter->rx_ring.buffer_info); + return -ENOMEM; + } + memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size); + + adapter->rx_ring.next_to_clean = 0; + atomic_set(&adapter->rx_ring.unused, adapter->rx_ring.count); + + adapter->rx_ring.next_to_use = 0; + + return 0; +} + +/** + * e1000_setup_rctl - configure the receive control register + * @adapter: Board private structure + **/ + +static void +e1000_setup_rctl(struct e1000_adapter *adapter) +{ + uint32_t rctl; + + /* Setup the Receive Control Register */ + rctl = + E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | + E1000_RCTL_RDMTS_HALF | (adapter->shared. + mc_filter_type << E1000_RCTL_MO_SHIFT); + + if(adapter->shared.tbi_compatibility_on == 1) + rctl |= E1000_RCTL_SBP; + + switch (adapter->rx_buffer_len) { + case E1000_RXBUFFER_2048: + default: + rctl |= E1000_RCTL_SZ_2048; + break; + case E1000_RXBUFFER_4096: + rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case E1000_RXBUFFER_8192: + rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case E1000_RXBUFFER_16384: + rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + } + + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); +} + +/** + * e1000_configure_rx - Configure 8254x Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ + +static void +e1000_configure_rx(struct e1000_adapter *adapter) +{ + uint32_t rctl; + uint32_t rxcsum; + + /* make sure receives are disabled while setting up the descriptor ring */ + rctl = E1000_READ_REG(&adapter->shared, RCTL); + E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN); + + /* set the Receive Delay Timer Register */ + E1000_WRITE_REG(&adapter->shared, RDTR, + adapter->rx_int_delay | E1000_RDT_FPDB); + + /* Setup the Base and Length of the Rx Descriptor Ring */ + /* rx_ring.dma can be either a 32 or 64 bit value */ + +#if (BITS_PER_LONG == 32) + E1000_WRITE_REG(&adapter->shared, RDBAL, adapter->rx_ring.dma); + E1000_WRITE_REG(&adapter->shared, RDBAH, 0); +#elif ( BITS_PER_LONG == 64) + E1000_WRITE_REG(&adapter->shared, RDBAL, + (uint32_t) (adapter->rx_ring.dma & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->shared, RDBAH, + (uint32_t) (adapter->rx_ring.dma >> 32)); +#else +#error "Unsupported System - does not use 32 or 64 bit pointers!" +#endif + + E1000_WRITE_REG(&adapter->shared, RDLEN, + adapter->rx_ring.count * sizeof(struct e1000_rx_desc)); + + /* Setup the HW Rx Head and Tail Descriptor Pointers */ + E1000_WRITE_REG(&adapter->shared, RDH, 0); + E1000_WRITE_REG(&adapter->shared, RDT, 0); + + /* Enable 82543 Receive Checksum Offload for TCP and UDP */ + if((adapter->shared.mac_type >= e1000_82543) && + (adapter->RxChecksum == TRUE)) { + rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM); + rxcsum |= E1000_RXCSUM_TUOFL; + E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum); + } +#ifdef CONFIG_PPC + if(adapter->shared.mac_type >= e1000_82543) { + E1000_WRITE_REG(&adapter->shared, RXDCTL, 0x00020000); + } +#endif + + /* Enable Receives */ + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + + return; +} + +/** + * e1000_free_tx_resources - Free Tx Resources + * @adapter: board private structure + * + * Free all transmit software resources + **/ + +static void +e1000_free_tx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + E1000_DBG("e1000_free_tx_resources\n"); + + e1000_clean_tx_ring(adapter); + + kfree(adapter->tx_ring.buffer_info); + adapter->tx_ring.buffer_info = NULL; + + pci_free_consistent(pdev, adapter->tx_ring.size, adapter->tx_ring.desc, + adapter->tx_ring.dma); + + adapter->tx_ring.desc = NULL; + + return; +} + +/** + * e1000_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + **/ + +static void +e1000_clean_tx_ring(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + int i; + + /* Free all the Tx ring sk_buffs */ + + for(i = 0; i < adapter->tx_ring.count; i++) { + if(adapter->tx_ring.buffer_info[i].skb != NULL) { + + pci_unmap_page(pdev, adapter->tx_ring.buffer_info[i].dma, + adapter->tx_ring.buffer_info[i].length, + PCI_DMA_TODEVICE); + + dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb); + + adapter->tx_ring.buffer_info[i].skb = NULL; + } + } + + size = sizeof(struct e1000_buffer) * adapter->tx_ring.count; + memset(adapter->tx_ring.buffer_info, 0, size); + + /* Zero out the descriptor ring */ + + memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size); + + atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count); + adapter->tx_ring.next_to_use = 0; + adapter->tx_ring.next_to_clean = 0; + + return; +} + +/** + * e1000_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * + * Free all receive software resources + **/ + +static void +e1000_free_rx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + E1000_DBG("e1000_free_rx_resources\n"); + + tasklet_disable(&adapter->rx_fill_tasklet); + + e1000_clean_rx_ring(adapter); + + kfree(adapter->rx_ring.buffer_info); + adapter->rx_ring.buffer_info = NULL; + + pci_free_consistent(pdev, adapter->rx_ring.size, adapter->rx_ring.desc, + adapter->rx_ring.dma); + + adapter->rx_ring.desc = NULL; + + return; +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers + * @adapter: board private structure + **/ + +static void +e1000_clean_rx_ring(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + int i; + + /* Free all the Rx ring sk_buffs */ + + for(i = 0; i < adapter->rx_ring.count; i++) { + if(adapter->rx_ring.buffer_info[i].skb != NULL) { + + pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma, + adapter->rx_ring.buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb); + + adapter->rx_ring.buffer_info[i].skb = NULL; + } + } + + size = sizeof(struct e1000_buffer) * adapter->rx_ring.count; + memset(adapter->rx_ring.buffer_info, 0, size); + + /* Zero out the descriptor ring */ + + memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size); + + atomic_set(&adapter->rx_ring.unused, adapter->rx_ring.count); + adapter->rx_ring.next_to_clean = 0; + adapter->rx_ring.next_to_use = 0; + + return; +} + +/** + * e1000_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * resposible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ + +void +e1000_set_multi(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + struct pci_dev *pdev = adapter->pdev; + uint32_t rctl; + uint8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; + uint16_t pci_command_word; + struct dev_mc_list *mc_ptr; + int i; + + E1000_DBG("e1000_set_multi\n"); + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + + if(adapter->shared.mac_type == e1000_82542_rev2_0) { + if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { + pci_command_word = + adapter->shared.pci_cmd_word & ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command_word); + } + rctl |= E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + mdelay(5); + if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + tasklet_disable(&adapter->rx_fill_tasklet); + e1000_clean_rx_ring(adapter); + } + } + + /* Check for Promiscuous and All Multicast modes */ + + if(netdev->flags & IFF_PROMISC) { + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + } else if(netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else { + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + } + + if(netdev->mc_count > MAX_NUM_MULTICAST_ADDRESSES) { + rctl |= E1000_RCTL_MPE; + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + } else { + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + for(i = 0, mc_ptr = netdev->mc_list; mc_ptr; i++, mc_ptr = mc_ptr->next) + memcpy(&mta[i * ETH_LENGTH_OF_ADDRESS], mc_ptr->dmi_addr, + ETH_LENGTH_OF_ADDRESS); + e1000_mc_addr_list_update(&adapter->shared, mta, netdev->mc_count, 0); + } + + if(adapter->shared.mac_type == e1000_82542_rev2_0) { + rctl = E1000_READ_REG(&adapter->shared, RCTL); + rctl &= ~E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + mdelay(5); + if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { + pci_write_config_word(pdev, PCI_COMMAND, + adapter->shared.pci_cmd_word); + } + if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + e1000_configure_rx(adapter); + tasklet_enable(&adapter->rx_fill_tasklet); + } + } + + return; +} + +#ifdef IANS + +/* flush Tx queue without link */ +static void +e1000_tx_flush(struct e1000_adapter *adapter) +{ + uint32_t ctrl, txcw, icr; + + adapter->int_mask = 0; + e1000_irq_disable(adapter); + synchronize_irq(); + + if(adapter->shared.mac_type < e1000_82543) { + /* Transmit Unit Reset */ + E1000_WRITE_REG(&adapter->shared, TCTL, E1000_TCTL_RST); + E1000_WRITE_REG(&adapter->shared, TCTL, 0); + e1000_clean_tx_ring(adapter); + e1000_configure_tx(adapter); + } else { + /* turn off autoneg, set link up, and invert loss of signal */ + txcw = E1000_READ_REG(&adapter->shared, TXCW); + ctrl = E1000_READ_REG(&adapter->shared, CTRL); + E1000_WRITE_REG(&adapter->shared, TXCW, txcw & ~E1000_TXCW_ANE); + E1000_WRITE_REG(&adapter->shared, CTRL, + (ctrl | E1000_CTRL_SLU | E1000_CTRL_ILOS)); + /* delay to flush queue, then clean up */ + mdelay(20); + e1000_clean_tx_irq(adapter); + E1000_WRITE_REG(&adapter->shared, CTRL, ctrl); + E1000_WRITE_REG(&adapter->shared, TXCW, txcw); + /* clear the link status change interrupts this caused */ + icr = E1000_READ_REG(&adapter->shared, ICR); + } + + adapter->int_mask = IMS_ENABLE_MASK; + e1000_irq_enable(adapter); + return; +} +#endif + +/** + * e1000_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + **/ + +void +e1000_watchdog(unsigned long data) +{ + struct net_device *netdev = (struct net_device *) data; + struct e1000_adapter *adapter = netdev->priv; + +#ifdef IANS +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + int flags; +#endif +#endif + + e1000_check_for_link(&adapter->shared); + + if (test_and_clear_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags)) + e1000_phy_get_info(&adapter->shared, &adapter->phy_info); + + if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) { + if(adapter->link_active != TRUE) { + +#ifdef IANS + if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && + (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) + if(ans_notify) + ans_notify(netdev, IANS_IND_XMIT_QUEUE_READY); +#endif + netif_wake_queue(netdev); + + e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, + &adapter->link_duplex); + printk(KERN_ERR "e1000: %s NIC Link is Up %d Mbps %s\n", + netdev->name, adapter->link_speed, + adapter->link_duplex == + FULL_DUPLEX ? "Full Duplex" : "Half Duplex"); + + adapter->link_active = TRUE; + set_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags); + } + } else { + if(adapter->link_active != FALSE) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + printk(KERN_ERR "e1000: %s NIC Link is Down\n", netdev->name); + adapter->link_active = FALSE; + atomic_set(&adapter->tx_timeout, 0); + } + } + + e1000_update_stats(adapter); + + if(atomic_read(&adapter->tx_timeout) > 1) + atomic_dec(&adapter->tx_timeout); + + if((adapter->link_active == TRUE) && + (atomic_read(&adapter->tx_timeout) == 1)) { + + if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF) { + atomic_set(&adapter->tx_timeout, 3); + } else { + + e1000_hibernate_adapter(netdev); + +#ifdef IANS + if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && + (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) { + adapter->link_active = FALSE; + bd_ans_os_Watchdog(netdev, adapter); + adapter->link_active = TRUE; + } +#endif + atomic_set(&adapter->tx_timeout, 0); + e1000_wakeup_adapter(netdev); + } + } +#ifdef IANS + if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) { + + if(adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON) + bd_ans_os_Watchdog(netdev, adapter); + + if(adapter->link_active == FALSE) { + /* don't sit on SKBs while link is down */ + + if(atomic_read(&adapter->tx_ring.unused) < adapter->tx_ring.count) { + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + spin_lock_irqsave(&netdev->xmit_lock, flags); + e1000_tx_flush(adapter); + spin_unlock_irqrestore(&netdev->xmit_lock, flags); +#else + e1000_tx_flush(adapter); +#endif + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + spin_lock_irqsave(&netdev->queue_lock, flags); + qdisc_reset(netdev->qdisc); + spin_unlock_irqrestore(&netdev->queue_lock, flags); +#else + qdisc_reset(netdev->qdisc); +#endif + } + } +#endif + + if(test_bit(E1000_RX_REFILL, &adapter->flags)) { + tasklet_schedule(&adapter->rx_fill_tasklet); + } + + /* Reset the timer */ + mod_timer(&adapter->timer_id, jiffies + 2 * HZ); + + return; +} + +/** + * e1000_tx_checksum_setup + * @adapter: + * @skb: + * @txd_upper: + * @txd_lower: + **/ + +static inline void +e1000_tx_checksum_setup(struct e1000_adapter *adapter, + struct sk_buff *skb, + uint32_t *txd_upper, + uint32_t *txd_lower) +{ + + struct e1000_context_desc *desc; + int i; + + if(skb->protocol != __constant_htons(ETH_P_IP)) { + *txd_upper = 0; + *txd_lower = adapter->TxdCmd; + return; + } + + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + /* Offload TCP checksum */ + *txd_upper = E1000_TXD_POPTS_TXSM << 8; + *txd_lower = adapter->TxdCmd | E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + if(adapter->ActiveChecksumContext == OFFLOAD_TCP_IP) + return; + else + adapter->ActiveChecksumContext = OFFLOAD_TCP_IP; + break; + case IPPROTO_UDP: + /* Offload UDP checksum */ + *txd_upper = E1000_TXD_POPTS_TXSM << 8; + *txd_lower = adapter->TxdCmd | E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + if(adapter->ActiveChecksumContext == OFFLOAD_UDP_IP) + return; + else + adapter->ActiveChecksumContext = OFFLOAD_UDP_IP; + break; + default: + /* no checksum to offload */ + *txd_upper = 0; + *txd_lower = adapter->TxdCmd; + return; + } + + /* If we reach this point, the checksum offload context + * needs to be reset + */ + + i = adapter->tx_ring.next_to_use; + desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + + desc->lower_setup.ip_fields.ipcss = skb->nh.raw - skb->data; + desc->lower_setup.ip_fields.ipcso = + ((skb->nh.raw + offsetof(struct iphdr, check)) - skb->data); + desc->lower_setup.ip_fields.ipcse = cpu_to_le16(skb->h.raw - skb->data - 1); + + desc->upper_setup.tcp_fields.tucss = (skb->h.raw - skb->data); + desc->upper_setup.tcp_fields.tucso = ((skb->h.raw + skb->csum) - skb->data); + desc->upper_setup.tcp_fields.tucse = 0; + + desc->tcp_seg_setup.data = 0; + desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT) | adapter->TxdCmd; + + i = (i + 1) % adapter->tx_ring.count; + atomic_dec(&adapter->tx_ring.unused); + adapter->tx_ring.next_to_use = i; + E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use); + return; +} + +/** + * e1000_xmit_frame - Transmit entry point + * @skb: buffer with frame data to transmit + * @netdev: network interface device structure + * + * Returns 0 on success, negative on error + * + * e1000_xmit_frame is called by the stack to initiate a transmit. + * The out of resource condition is checked after each successful Tx + * so that the stack can be notified, preventing the driver from + * ever needing to drop a frame. The atomic operations on + * tx_ring.unused are used to syncronize with the transmit + * interrupt processing code without the need for a spinlock. + **/ + +int +e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + struct pci_dev *pdev = adapter->pdev; + struct e1000_tx_desc *tx_desc; + int i, len, offset, txd_needed; + uint32_t txd_upper, txd_lower; + +#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0)) + +#ifdef MAX_SKB_FRAGS + int f; + skb_frag_t *frag; +#endif + + E1000_DBG("e1000_xmit_frame\n"); + + if(adapter->link_active == FALSE) { +#ifdef IANS + if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && + (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) + if(ans_notify) + ans_notify(netdev, IANS_IND_XMIT_QUEUE_FULL); +#endif + netif_stop_queue(netdev); + return 1; + } + +#ifdef MAX_SKB_FRAGS + txd_needed = TXD_USE_COUNT(skb->len - skb->data_len); + for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + frag = &skb_shinfo(skb)->frags[f]; + txd_needed += TXD_USE_COUNT(frag->size); + } +#else + txd_needed = TXD_USE_COUNT(skb->len); +#endif + + /* make sure there are enough Tx descriptors available in the ring */ + if(atomic_read(&adapter->tx_ring.unused) <= (txd_needed + 1)) { + adapter->net_stats.tx_dropped++; +#ifdef IANS + if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && + (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) + if(ans_notify) + ans_notify(netdev, IANS_IND_XMIT_QUEUE_FULL); +#endif + netif_stop_queue(netdev); + + return 1; + } + + if(skb->ip_summed == CHECKSUM_HW) { + e1000_tx_checksum_setup(adapter, skb, &txd_upper, &txd_lower); + } else { + txd_upper = 0; + txd_lower = adapter->TxdCmd; + } + + i = adapter->tx_ring.next_to_use; + tx_desc = E1000_TX_DESC(adapter->tx_ring, i); + +#ifdef IANS + if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) { + tx_desc->lower.data = cpu_to_le32(txd_lower); + tx_desc->upper.data = cpu_to_le32(txd_upper); + if(bd_ans_os_Transmit(adapter, tx_desc, &skb) == BD_ANS_FAILURE) { + return 1; + } + txd_lower = le32_to_cpu(tx_desc->lower.data); + txd_upper = le32_to_cpu(tx_desc->upper.data); + } +#endif + +#ifdef MAX_SKB_FRAGS + len = skb->len - skb->data_len; +#else + len = skb->len; +#endif + offset = 0; + + while(len > 4096) { + adapter->tx_ring.buffer_info[i].length = 4096; + adapter->tx_ring.buffer_info[i].dma = + pci_map_page(pdev, virt_to_page(skb->data + offset), + (unsigned long) (skb->data + offset) & ~PAGE_MASK, + 4096, PCI_DMA_TODEVICE); + + tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(txd_lower | 4096); + tx_desc->upper.data = cpu_to_le32(txd_upper); + + len -= 4096; + offset += 4096; + i = (i + 1) % adapter->tx_ring.count; + atomic_dec(&adapter->tx_ring.unused); + tx_desc = E1000_TX_DESC(adapter->tx_ring, i); + } + adapter->tx_ring.buffer_info[i].length = len; + adapter->tx_ring.buffer_info[i].dma = + pci_map_page(pdev, virt_to_page(skb->data + offset), + (unsigned long) (skb->data + offset) & ~PAGE_MASK, len, + PCI_DMA_TODEVICE); + + tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(txd_lower | len); + tx_desc->upper.data = cpu_to_le32(txd_upper); + +#ifdef MAX_SKB_FRAGS + for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + frag = &skb_shinfo(skb)->frags[f]; + i = (i + 1) % adapter->tx_ring.count; + atomic_dec(&adapter->tx_ring.unused); + tx_desc = E1000_TX_DESC(adapter->tx_ring, i); + + len = frag->size; + offset = 0; + + while(len > 4096) { + adapter->tx_ring.buffer_info[i].length = 4096; + adapter->tx_ring.buffer_info[i].dma = + pci_map_page(pdev, frag->page, frag->page_offset + offset, + 4096, PCI_DMA_TODEVICE); + + tx_desc->buffer_addr = + cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(txd_lower | 4096); + tx_desc->upper.data = cpu_to_le32(txd_upper); + + len -= 4096; + offset += 4096; + i = (i + 1) % adapter->tx_ring.count; + atomic_dec(&adapter->tx_ring.unused); + tx_desc = E1000_TX_DESC(adapter->tx_ring, i); + } + adapter->tx_ring.buffer_info[i].length = len; + adapter->tx_ring.buffer_info[i].dma = + pci_map_page(pdev, frag->page, frag->page_offset + offset, len, + PCI_DMA_TODEVICE); + tx_desc->buffer_addr = + cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); + + tx_desc->lower.data = cpu_to_le32(txd_lower | len); + tx_desc->upper.data = cpu_to_le32(txd_upper); + } +#endif + + /* EOP and SKB pointer go with the last fragment */ + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); + adapter->tx_ring.buffer_info[i].skb = skb; + + i = (i + 1) % adapter->tx_ring.count; + atomic_dec(&adapter->tx_ring.unused); + + /* Move the HW Tx Tail Pointer */ + adapter->tx_ring.next_to_use = i; + + E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use); + + if(atomic_read(&adapter->tx_timeout) == 0) + atomic_set(&adapter->tx_timeout, 3); + + netdev->trans_start = jiffies; + + return 0; +} + +/** + * e1000_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ + +struct net_device_stats * +e1000_get_stats(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + E1000_DBG("e1000_get_stats\n"); + + return &adapter->net_stats; +} + +/** + * e1000_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ + +int +e1000_change_mtu(struct net_device *netdev, + int new_mtu) +{ + struct e1000_adapter *adapter = netdev->priv; + uint32_t old_mtu = adapter->rx_buffer_len; + + E1000_DBG("e1000_change_mtu\n"); + if((new_mtu < MINIMUM_ETHERNET_PACKET_SIZE - ENET_HEADER_SIZE) || + (new_mtu > MAX_JUMBO_FRAME_SIZE - ENET_HEADER_SIZE)) { + E1000_ERR("Invalid MTU setting\n"); + return -EINVAL; + } + + if(new_mtu <= MAXIMUM_ETHERNET_PACKET_SIZE - ENET_HEADER_SIZE) { + /* 2k buffers */ + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + + } else if(adapter->shared.mac_type < e1000_82543) { + E1000_ERR("Jumbo Frames not supported on 82542\n"); + return -EINVAL; + + } else if(new_mtu <= E1000_RXBUFFER_4096 - ENET_HEADER_SIZE - CRC_LENGTH) { + /* 4k buffers */ + adapter->rx_buffer_len = E1000_RXBUFFER_4096; + + } else if(new_mtu <= E1000_RXBUFFER_8192 - ENET_HEADER_SIZE - CRC_LENGTH) { + /* 8k buffers */ + adapter->rx_buffer_len = E1000_RXBUFFER_8192; + + } else { + /* 16k buffers */ + adapter->rx_buffer_len = E1000_RXBUFFER_16384; + } + + if(old_mtu != adapter->rx_buffer_len && + test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + + /* stop */ + tasklet_disable(&adapter->rx_fill_tasklet); + netif_stop_queue(netdev); + adapter->shared.adapter_stopped = 0; + e1000_adapter_stop(&adapter->shared); + + /* clean out old buffers */ + e1000_clean_rx_ring(adapter); + e1000_clean_tx_ring(adapter); + + /* reset hardware */ + adapter->shared.adapter_stopped = 0; + e1000_hw_init(adapter); + + /* go */ + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + e1000_configure_tx(adapter); +#ifdef IANS + /* restore VLAN settings */ + if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode) + != IANS_BD_TAGGING_NONE) + bd_ans_hw_EnableVLAN(adapter); +#endif + tasklet_enable(&adapter->rx_fill_tasklet); + tasklet_schedule(&adapter->rx_fill_tasklet); + e1000_irq_enable(adapter); + netif_start_queue(netdev); + } + + netdev->mtu = new_mtu; + adapter->shared.max_frame_size = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH; + + return 0; +} + +/** + * e1000_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ + +int +e1000_set_mac(struct net_device *netdev, + void *p) +{ + struct e1000_adapter *adapter = netdev->priv; + struct pci_dev *pdev = adapter->pdev; + struct sockaddr *addr = (struct sockaddr *) p; + uint32_t pci_command; + uint32_t rctl; + + E1000_DBG("e1000_set_mac\n"); + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + + if(adapter->shared.mac_type == e1000_82542_rev2_0) { + if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { + pci_command = + adapter->shared.pci_cmd_word & ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + E1000_WRITE_REG(&adapter->shared, RCTL, rctl | E1000_RCTL_RST); + mdelay(5); + if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + tasklet_disable(&adapter->rx_fill_tasklet); + e1000_clean_rx_ring(adapter); + } + } + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len); + + e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0); + + if(adapter->shared.mac_type == e1000_82542_rev2_0) { + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + mdelay(5); + if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { + pci_write_config_word(pdev, PCI_COMMAND, + adapter->shared.pci_cmd_word); + } + if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + e1000_configure_rx(adapter); + tasklet_enable(&adapter->rx_fill_tasklet); + } + } + + return 0; +} + +/** + * e1000_update_stats - Update the board statistics counters + * @adapter: board private structure + **/ + +static void +e1000_update_stats(struct e1000_adapter *adapter) +{ + unsigned long flags; + +#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + + spin_lock_irqsave(&adapter->stats_lock, flags); + + adapter->stats.crcerrs += E1000_READ_REG(&adapter->shared, CRCERRS); + adapter->stats.symerrs += E1000_READ_REG(&adapter->shared, SYMERRS); + adapter->stats.mpc += E1000_READ_REG(&adapter->shared, MPC); + adapter->stats.scc += E1000_READ_REG(&adapter->shared, SCC); + adapter->stats.ecol += E1000_READ_REG(&adapter->shared, ECOL); + adapter->stats.mcc += E1000_READ_REG(&adapter->shared, MCC); + adapter->stats.latecol += E1000_READ_REG(&adapter->shared, LATECOL); + adapter->stats.colc += E1000_READ_REG(&adapter->shared, COLC); + adapter->stats.dc += E1000_READ_REG(&adapter->shared, DC); + adapter->stats.sec += E1000_READ_REG(&adapter->shared, SEC); + adapter->stats.rlec += E1000_READ_REG(&adapter->shared, RLEC); + adapter->stats.xonrxc += E1000_READ_REG(&adapter->shared, XONRXC); + adapter->stats.xontxc += E1000_READ_REG(&adapter->shared, XONTXC); + adapter->stats.xoffrxc += E1000_READ_REG(&adapter->shared, XOFFRXC); + adapter->stats.xofftxc += E1000_READ_REG(&adapter->shared, XOFFTXC); + adapter->stats.fcruc += E1000_READ_REG(&adapter->shared, FCRUC); + adapter->stats.prc64 += E1000_READ_REG(&adapter->shared, PRC64); + adapter->stats.prc127 += E1000_READ_REG(&adapter->shared, PRC127); + adapter->stats.prc255 += E1000_READ_REG(&adapter->shared, PRC255); + adapter->stats.prc511 += E1000_READ_REG(&adapter->shared, PRC511); + adapter->stats.prc1023 += E1000_READ_REG(&adapter->shared, PRC1023); + adapter->stats.prc1522 += E1000_READ_REG(&adapter->shared, PRC1522); + adapter->stats.gprc += E1000_READ_REG(&adapter->shared, GPRC); + adapter->stats.bprc += E1000_READ_REG(&adapter->shared, BPRC); + adapter->stats.mprc += E1000_READ_REG(&adapter->shared, MPRC); + adapter->stats.gptc += E1000_READ_REG(&adapter->shared, GPTC); + + /* for the 64-bit byte counters the low dword must be read first */ + /* both registers clear on the read of the high dword */ + + adapter->stats.gorcl += E1000_READ_REG(&adapter->shared, GORCL); + adapter->stats.gorch += E1000_READ_REG(&adapter->shared, GORCH); + adapter->stats.gotcl += E1000_READ_REG(&adapter->shared, GOTCL); + adapter->stats.gotch += E1000_READ_REG(&adapter->shared, GOTCH); + + adapter->stats.rnbc += E1000_READ_REG(&adapter->shared, RNBC); + adapter->stats.ruc += E1000_READ_REG(&adapter->shared, RUC); + adapter->stats.rfc += E1000_READ_REG(&adapter->shared, RFC); + adapter->stats.roc += E1000_READ_REG(&adapter->shared, ROC); + adapter->stats.rjc += E1000_READ_REG(&adapter->shared, RJC); + + adapter->stats.torl += E1000_READ_REG(&adapter->shared, TORL); + adapter->stats.torh += E1000_READ_REG(&adapter->shared, TORH); + adapter->stats.totl += E1000_READ_REG(&adapter->shared, TOTL); + adapter->stats.toth += E1000_READ_REG(&adapter->shared, TOTH); + + adapter->stats.tpr += E1000_READ_REG(&adapter->shared, TPR); + adapter->stats.tpt += E1000_READ_REG(&adapter->shared, TPT); + adapter->stats.ptc64 += E1000_READ_REG(&adapter->shared, PTC64); + adapter->stats.ptc127 += E1000_READ_REG(&adapter->shared, PTC127); + adapter->stats.ptc255 += E1000_READ_REG(&adapter->shared, PTC255); + adapter->stats.ptc511 += E1000_READ_REG(&adapter->shared, PTC511); + adapter->stats.ptc1023 += E1000_READ_REG(&adapter->shared, PTC1023); + adapter->stats.ptc1522 += E1000_READ_REG(&adapter->shared, PTC1522); + adapter->stats.mptc += E1000_READ_REG(&adapter->shared, MPTC); + adapter->stats.bptc += E1000_READ_REG(&adapter->shared, BPTC); + + if(adapter->shared.mac_type >= e1000_82543) { + adapter->stats.algnerrc += E1000_READ_REG(&adapter->shared, ALGNERRC); + adapter->stats.rxerrc += E1000_READ_REG(&adapter->shared, RXERRC); + adapter->stats.tncrs += E1000_READ_REG(&adapter->shared, TNCRS); + adapter->stats.cexterr += E1000_READ_REG(&adapter->shared, CEXTERR); + adapter->stats.tsctc += E1000_READ_REG(&adapter->shared, TSCTC); + adapter->stats.tsctfc += E1000_READ_REG(&adapter->shared, TSCTFC); + } + + /* Fill out the OS statistics structure */ + + adapter->net_stats.rx_packets = adapter->stats.gprc; + adapter->net_stats.tx_packets = adapter->stats.gptc; + adapter->net_stats.rx_bytes = adapter->stats.gorcl; + adapter->net_stats.tx_bytes = adapter->stats.gotcl; + adapter->net_stats.multicast = adapter->stats.mprc; + adapter->net_stats.collisions = adapter->stats.colc; + + /* Rx Errors */ + + adapter->net_stats.rx_errors = + adapter->stats.rxerrc + adapter->stats.crcerrs + + adapter->stats.algnerrc + adapter->stats.rlec + adapter->stats.rnbc + + adapter->stats.mpc + adapter->stats.cexterr; + adapter->net_stats.rx_dropped = adapter->stats.rnbc; + adapter->net_stats.rx_length_errors = adapter->stats.rlec; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; + adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + + adapter->net_stats.tx_errors = adapter->stats.ecol + adapter->stats.latecol; + adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; + adapter->net_stats.tx_window_errors = adapter->stats.latecol; + + /* Tx Dropped needs to be maintained elsewhere */ + + if(adapter->shared.media_type == e1000_media_type_copper) { + adapter->phy_stats.idle_errors += + (e1000_read_phy_reg(&adapter->shared, PHY_1000T_STATUS) + & PHY_IDLE_ERROR_COUNT_MASK); + adapter->phy_stats.receive_errors += + e1000_read_phy_reg(&adapter->shared, M88E1000_RX_ERR_CNTR); + } + + spin_unlock_irqrestore(&adapter->stats_lock, flags); + return; +} + +/** + * e1000_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ + +static inline void +e1000_irq_disable(struct e1000_adapter *adapter) +{ + E1000_DBG("e1000_irq_disable\n"); + + /* Mask off all interrupts */ + + E1000_WRITE_REG(&adapter->shared, IMC, ~0); + return; +} + +/** + * e1000_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ + +static inline void +e1000_irq_enable(struct e1000_adapter *adapter) +{ + E1000_DBG("e1000_irq_enable\n"); + + E1000_WRITE_REG(&adapter->shared, IMS, adapter->int_mask); + return; +} + +/** + * e1000_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + **/ + +void +e1000_intr(int irq, + void *data, + struct pt_regs *regs) +{ + struct net_device *netdev = (struct net_device *) data; + struct e1000_adapter *adapter = netdev->priv; + uint32_t icr; + uint loop_count = E1000_MAX_INTR; + + E1000_DBG("e1000_intr\n"); + + e1000_irq_disable(adapter); + + while(loop_count > 0 && (icr = E1000_READ_REG(&adapter->shared, ICR)) != 0) { + + if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + adapter->shared.get_link_status = 1; + set_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags); + /* run the watchdog ASAP */ + mod_timer(&adapter->timer_id, jiffies); + } + + e1000_clean_rx_irq(adapter); + e1000_clean_tx_irq(adapter); + loop_count--; + } + + e1000_irq_enable(adapter); + + return; +} + +/** + * e1000_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + **/ + +static void +e1000_clean_tx_irq(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int i; + + struct e1000_tx_desc *tx_desc; + struct net_device *netdev = adapter->netdev; + + E1000_DBG("e1000_clean_tx_irq\n"); + + i = adapter->tx_ring.next_to_clean; + tx_desc = E1000_TX_DESC(adapter->tx_ring, i); + + while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + + if(adapter->tx_ring.buffer_info[i].dma != 0) { + pci_unmap_page(pdev, adapter->tx_ring.buffer_info[i].dma, + adapter->tx_ring.buffer_info[i].length, + PCI_DMA_TODEVICE); + adapter->tx_ring.buffer_info[i].dma = 0; + } + + if(adapter->tx_ring.buffer_info[i].skb != NULL) { + dev_kfree_skb_irq(adapter->tx_ring.buffer_info[i].skb); + adapter->tx_ring.buffer_info[i].skb = NULL; + } + + atomic_inc(&adapter->tx_ring.unused); + i = (i + 1) % adapter->tx_ring.count; + + tx_desc->upper.data = 0; + tx_desc = E1000_TX_DESC(adapter->tx_ring, i); + } + + adapter->tx_ring.next_to_clean = i; + + if(adapter->tx_ring.next_to_clean == adapter->tx_ring.next_to_use) + atomic_set(&adapter->tx_timeout, 0); + else + atomic_set(&adapter->tx_timeout, 3); + + if(netif_queue_stopped(netdev) && + (atomic_read(&adapter->tx_ring.unused) > + (adapter->tx_ring.count * 3 / 4))) { + +#ifdef IANS + if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && + (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) + if(ans_notify) + ans_notify(netdev, IANS_IND_XMIT_QUEUE_READY); +#endif + netif_wake_queue(netdev); + } + + return; +} + +/** + * e1000_clean_rx_irq - Send received data up the network stack, + * @adapter: board private structure + **/ + +static void +e1000_clean_rx_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + int i; + uint32_t length; + struct sk_buff *skb; + uint8_t last_byte; + unsigned long flags; + + E1000_DBG("e1000_clean_rx_irq\n"); + + i = adapter->rx_ring.next_to_clean; + rx_desc = E1000_RX_DESC(adapter->rx_ring, i); + + while(rx_desc->status & E1000_RXD_STAT_DD) { + pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma, + adapter->rx_ring.buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + skb = adapter->rx_ring.buffer_info[i].skb; + length = le16_to_cpu(rx_desc->length); + + if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { + + /* All receives must fit into a single buffer */ + + E1000_DBG("Receive packet consumed multiple buffers\n"); + + dev_kfree_skb_irq(skb); + memset(rx_desc, 0, 16); + mb(); + adapter->rx_ring.buffer_info[i].skb = NULL; + + atomic_inc(&adapter->rx_ring.unused); + + i = (i + 1) % adapter->rx_ring.count; + + rx_desc = E1000_RX_DESC(adapter->rx_ring, i); + continue; + } + + if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + + last_byte = *(skb->data + length - 1); + + if(TBI_ACCEPT + (&adapter->shared, rx_desc->status, rx_desc->errors, length, + last_byte)) { + spin_lock_irqsave(&adapter->stats_lock, flags); + e1000_tbi_adjust_stats(&adapter->shared, &adapter->stats, + length, skb->data); + spin_unlock_irqrestore(&adapter->stats_lock, flags); + length--; + } else { + + E1000_DBG("Receive Errors Reported by Hardware\n"); + + dev_kfree_skb_irq(skb); + memset(rx_desc, 0, 16); + mb(); + adapter->rx_ring.buffer_info[i].skb = NULL; + + atomic_inc(&adapter->rx_ring.unused); + i = (i + 1) % adapter->rx_ring.count; + + rx_desc = E1000_RX_DESC(adapter->rx_ring, i); + continue; + } + } + + /* Good Receive */ + skb_put(skb, length - CRC_LENGTH); + + /* Adjust socket buffer accounting to only cover the ethernet frame + * Not what the stack intends, but there exist TCP problems that + * break NFS for network interfaces that need 2k receive buffers + */ + skb->truesize = skb->len; + + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, rx_desc, skb); + +#ifdef IANS + if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) { + if(bd_ans_os_Receive(adapter, rx_desc, skb) == BD_ANS_FAILURE) + dev_kfree_skb_irq(skb); + else + netif_rx(skb); + } else { + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); + } +#else + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); +#endif + memset(rx_desc, 0, 16); + mb(); + adapter->rx_ring.buffer_info[i].skb = NULL; + + atomic_inc(&adapter->rx_ring.unused); + + i = (i + 1) % adapter->rx_ring.count; + + rx_desc = E1000_RX_DESC(adapter->rx_ring, i); + } + + /* if the Rx ring is less than 3/4 full, allocate more sk_buffs */ + + if(atomic_read(&adapter->rx_ring.unused) > (adapter->rx_ring.count / 4)) { + tasklet_schedule(&adapter->rx_fill_tasklet); + } + adapter->rx_ring.next_to_clean = i; + + return; +} + +/** + * e1000_alloc_rx_buffers - Replace used receive buffers + * @data: address of board private structure + **/ + +static void +e1000_alloc_rx_buffers(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct sk_buff *skb; + int i; + int reserve_len; + + E1000_DBG("e1000_alloc_rx_buffers\n"); + + /* kernel 2.4.7 seems to be broken with respect to tasklet locking */ + if(!spin_trylock(&adapter->rx_fill_lock)) + return; + + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + spin_unlock(&adapter->rx_fill_lock); + return; + } + +#ifdef IANS + reserve_len = E1000_ROUNDUP2(BD_ANS_INFO_SIZE, 16) + 2; +#else + reserve_len = 2; +#endif + + i = adapter->rx_ring.next_to_use; + + while(adapter->rx_ring.buffer_info[i].skb == NULL) { + rx_desc = E1000_RX_DESC(adapter->rx_ring, i); + + skb = alloc_skb(adapter->rx_buffer_len + reserve_len, GFP_ATOMIC); + + if(skb == NULL) { + /* Alloc Failed; If we could not allocate a + * skb during this schedule. Wait for a while before + * tasklet to allocate skb is called again. + */ + set_bit(E1000_RX_REFILL, &adapter->flags); + break; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, reserve_len); + + skb->dev = netdev; + + adapter->rx_ring.buffer_info[i].skb = skb; + adapter->rx_ring.buffer_info[i].length = adapter->rx_buffer_len; + adapter->rx_ring.buffer_info[i].dma = + pci_map_single(pdev, skb->data, adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + + rx_desc->buffer_addr = cpu_to_le64(adapter->rx_ring.buffer_info[i].dma); + + /* move tail */ + E1000_WRITE_REG(&adapter->shared, RDT, i); + + atomic_dec(&adapter->rx_ring.unused); + + i = (i + 1) % adapter->rx_ring.count; + + if(test_and_clear_bit(E1000_RX_REFILL, &adapter->flags)) { + /* Trigger Soft Interrupt */ + E1000_WRITE_REG(&adapter->shared, ICS, E1000_ICS_RXT0); + } + } + + adapter->rx_ring.next_to_use = i; + + spin_unlock(&adapter->rx_fill_lock); + return; +} + +/** + * e1000_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ + +int +e1000_ioctl(struct net_device *netdev, + struct ifreq *ifr, + int cmd) +{ +#ifdef IANS + IANS_BD_PARAM_HEADER *header; +#endif + + E1000_DBG("e1000_do_ioctl\n"); + + switch (cmd) { + +#ifdef IANS + case IANS_BASE_SIOC: + header = (IANS_BD_PARAM_HEADER *) ifr->ifr_data; + if((header->Opcode != IANS_OP_EXT_GET_STATUS) && + (!capable(CAP_NET_ADMIN))) + return -EPERM; + return bd_ans_os_Ioctl(netdev, ifr, cmd); + break; +#endif + +#ifdef IDIAG + case IDIAG_PRO_BASE_SIOC: + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + +#ifdef DIAG_DEBUG + printk("Entering diagnostics\n"); +#endif + e1000_diag_ioctl(netdev, ifr); + break; +#endif /* IDIAG */ + +#ifdef SIOCETHTOOL + case SIOCETHTOOL: + + return e1000_ethtool_ioctl(netdev, ifr); + + break; +#endif + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * e1000_rx_checksum - Receive Checksum Offload for 82543 + * @adapter: board private structure + * @rx_desc: receive descriptor + * @sk_buff: socket buffer with received data + **/ + +static inline void +e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb) +{ + /* 82543 or newer only */ + if((adapter->shared.mac_type < e1000_82543) || + /* Ignore Checksum bit is set */ + (rx_desc->status & E1000_RXD_STAT_IXSM) || + /* TCP Checksum has not been calculated */ + (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { + + skb->ip_summed = CHECKSUM_NONE; + return; + } + + /* At this point we know the hardware did the TCP checksum */ + /* now look at the TCP checksum error bit */ + if(rx_desc->errors & E1000_RXD_ERR_TCPE) { + /* let the stack verify checksum errors */ + skb->ip_summed = CHECKSUM_NONE; + adapter->XsumRXError++; + } else { + /* TCP checksum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->XsumRXGood++; + } + + return; +} + +void +e1000_hibernate_adapter(struct net_device *netdev) +{ + uint32_t icr; + struct e1000_adapter *adapter = netdev->priv; + + e1000_irq_disable(adapter); + netif_stop_queue(netdev); + adapter->shared.adapter_stopped = 0; + e1000_adapter_stop(&adapter->shared); + + if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + + /* Disable tasklet only when interface is opened. */ + tasklet_disable(&adapter->rx_fill_tasklet); + + /* clean out old buffers */ + e1000_clean_rx_ring(adapter); + e1000_clean_tx_ring(adapter); + + /* Delete watchdog timer */ + del_timer(&adapter->timer_id); + + /* Unhook irq */ + e1000_irq_disable(adapter); + icr = E1000_READ_REG(&adapter->shared, ICR); + free_irq(netdev->irq, netdev); + } +} + +void +e1000_wakeup_adapter(struct net_device *netdev) +{ + uint32_t icr; + struct e1000_adapter *adapter = netdev->priv; + + adapter->shared.adapter_stopped = 0; + e1000_adapter_stop(&adapter->shared); + adapter->shared.adapter_stopped = 0; + adapter->shared.fc = adapter->shared.original_fc; + + if(!e1000_init_hw(&adapter->shared)) + printk("Hardware Init Failed at wakeup\n"); + + if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + + /* Setup Rctl */ + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + e1000_alloc_rx_buffers((unsigned long) adapter); + e1000_set_multi(netdev); + e1000_configure_tx(adapter); + +#ifdef IANS + if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode) + != IANS_BD_TAGGING_NONE) + bd_ans_hw_EnableVLAN(adapter); +#endif + + /* Set the watchdog timer for 2 seconds */ + init_timer(&adapter->timer_id); + adapter->timer_id.function = &e1000_watchdog; + adapter->timer_id.data = (unsigned long) netdev; + mod_timer(&adapter->timer_id, (jiffies + 2 * HZ)); + + tasklet_enable(&adapter->rx_fill_tasklet); + + /* Hook irq */ + e1000_irq_disable(adapter); + icr = E1000_READ_REG(&adapter->shared, ICR); + if(request_irq + (netdev->irq, &e1000_intr, SA_SHIRQ, e1000_driver_name, netdev) != 0) + printk(KERN_ERR "e1000: Unable to hook irq.\n"); + + e1000_irq_enable(adapter); + netif_start_queue(netdev); + } +} + +#ifdef IDIAG +int +e1000_xmit_lbtest_frame(struct sk_buff *skb, + struct e1000_adapter *adapter) +{ + /*struct e1000_adapter *adapter = netdev->priv; */ + struct pci_dev *pdev = adapter->pdev; + struct e1000_tx_desc *tx_desc; + int i; + + i = adapter->tx_ring.next_to_use; + tx_desc = E1000_TX_DESC(adapter->tx_ring, i); + + adapter->tx_ring.buffer_info[i].skb = skb; + adapter->tx_ring.buffer_info[i].length = skb->len; + adapter->tx_ring.buffer_info[i].dma = + pci_map_page(pdev, virt_to_page(skb->data), + (unsigned long) skb->data & ~PAGE_MASK, skb->len, + PCI_DMA_TODEVICE); + + tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(skb->len); + + /* zero out the status field in the descriptor */ + + tx_desc->upper.data = 0; + + tx_desc->lower.data |= E1000_TXD_CMD_EOP; + tx_desc->lower.data |= E1000_TXD_CMD_IFCS; + tx_desc->lower.data |= E1000_TXD_CMD_IDE; + + if(adapter->shared.report_tx_early == 1) + tx_desc->lower.data |= E1000_TXD_CMD_RS; + else + tx_desc->lower.data |= E1000_TXD_CMD_RPS; + + /* Move the HW Tx Tail Pointer */ + + adapter->tx_ring.next_to_use++; + adapter->tx_ring.next_to_use %= adapter->tx_ring.count; + + E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use); + mdelay(10); + + atomic_dec(&adapter->tx_ring.unused); + + if(atomic_read(&adapter->tx_ring.unused) <= 1) { + + /* this driver never actually drops transmits, + * so use tx_dropped count to indicate the number of times + * netif_stop_queue is called due to no available descriptors + */ + + adapter->net_stats.tx_dropped++; + return (0); + } + return (1); +} + +int +e1000_rcv_lbtest_frame(struct e1000_adapter *adapter, + unsigned int frame_size) +{ + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + int i, j = 0, rcved_pkt = 0; + uint32_t Length; + struct sk_buff *skb; + + mdelay(500); + i = adapter->rx_ring.next_to_clean; + rx_desc = E1000_RX_DESC(adapter->rx_ring, i); + + while(rx_desc->status & E1000_RXD_STAT_DD) { + Length = le16_to_cpu(rx_desc->length) - CRC_LENGTH; + skb = adapter->rx_ring.buffer_info[i].skb; + + /* Snoop the packet for pattern */ + rcved_pkt = e1000_check_lbtest_frame(skb, frame_size); + + pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma, + adapter->rx_ring.buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + dev_kfree_skb_irq(skb); + adapter->rx_ring.buffer_info[i].skb = NULL; + + rx_desc->status = 0; + atomic_inc(&adapter->rx_ring.unused); + + i++; + i %= adapter->rx_ring.count; + rx_desc = E1000_RX_DESC(adapter->rx_ring, i); + + if(rcved_pkt) + break; + + /* waited enough */ + if(j++ >= adapter->rx_ring.count) + return 0; + + mdelay(5); + + } + + adapter->rx_ring.next_to_clean = i; + + return (rcved_pkt); + +} + +void +e1000_selective_wakeup_adapter(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + uint32_t ctrl, txcw; + + e1000_init_hw(&adapter->shared); + + if((adapter->link_active == FALSE) && + (adapter->shared.mac_type == e1000_82543)) { + + txcw = E1000_READ_REG(&adapter->shared, TXCW); + ctrl = E1000_READ_REG(&adapter->shared, CTRL); + E1000_WRITE_REG(&adapter->shared, TXCW, txcw & ~E1000_TXCW_ANE); + E1000_WRITE_REG(&adapter->shared, CTRL, + (ctrl | E1000_CTRL_SLU | E1000_CTRL_ILOS | + E1000_CTRL_FD)); + mdelay(20); + } + + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) { + set_bit(E1000_BOARD_OPEN, &adapter->flags); + set_bit(E1000_DIAG_OPEN, &adapter->flags); + e1000_setup_tx_resources(adapter); + e1000_setup_rx_resources(adapter); + } + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + e1000_alloc_rx_buffers((unsigned long) adapter); + e1000_configure_tx(adapter); +} + +void +e1000_selective_hibernate_adapter(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + uint32_t ctrl, txcw; + + if((adapter->link_active == FALSE) && + (adapter->shared.mac_type == e1000_82543)) { + + txcw = E1000_READ_REG(&adapter->shared, TXCW); + ctrl = E1000_READ_REG(&adapter->shared, CTRL); + ctrl &= ~E1000_CTRL_SLU & ~E1000_CTRL_ILOS; + E1000_WRITE_REG(&adapter->shared, TXCW, txcw | E1000_TXCW_ANE); + E1000_WRITE_REG(&adapter->shared, CTRL, ctrl); + mdelay(20); + } + /* clean out old buffers */ + e1000_clean_rx_ring(adapter); + e1000_clean_tx_ring(adapter); + if(test_and_clear_bit(E1000_DIAG_OPEN, &adapter->flags)) { + e1000_free_tx_resources(adapter); + e1000_free_rx_resources(adapter); + clear_bit(E1000_BOARD_OPEN, &adapter->flags); + } +} + +static int +e1000_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; + if(*(skb->data + 3) == 0xFF) { + if((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) { + return 1; + } + } + return 0; +} +#endif /* IDIAG */ + +#ifdef SIOCETHTOOL +/** + * e1000_ethtool_ioctl - Ethtool Ioctl Support + * @netdev: net device structure + * @ifr: interface request structure + **/ + +static int +e1000_ethtool_ioctl(struct net_device *netdev, + struct ifreq *ifr) +{ + struct ethtool_cmd eth_cmd; + struct e1000_adapter *adapter = netdev->priv; + boolean_t re_initiate = FALSE; + +#ifdef ETHTOOL_GLINK + struct ethtool_value eth_e1000_linkinfo; +#endif +#ifdef ETHTOOL_GDRVINFO + struct ethtool_drvinfo eth_e1000_info; +#endif +#ifdef ETHTOOL_GWOL + struct ethtool_wolinfo eth_e1000_wolinfo; +#endif + + /* Get the data structure */ + if(copy_from_user(ð_cmd, ifr->ifr_data, sizeof(eth_cmd))) + return -EFAULT; + + switch (eth_cmd.cmd) { + /* Get the information */ + case ETHTOOL_GSET: + if(adapter->shared.media_type == e1000_media_type_copper) { + eth_cmd.supported = E1000_ETHTOOL_COPPER_INTERFACE_SUPPORTS; + eth_cmd.advertising = E1000_ETHTOOL_COPPER_INTERFACE_ADVERTISE; + eth_cmd.port = PORT_MII; + eth_cmd.phy_address = adapter->shared.phy_addr; + eth_cmd.transceiver = + (adapter->shared.mac_type > + e1000_82543) ? XCVR_INTERNAL : XCVR_EXTERNAL; + } else { + eth_cmd.supported = E1000_ETHTOOL_FIBER_INTERFACE_SUPPORTS; + eth_cmd.advertising = E1000_ETHTOOL_FIBER_INTERFACE_ADVERTISE; + eth_cmd.port = PORT_FIBRE; + } + + if(adapter->link_active == TRUE) { + e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, + &adapter->link_duplex); + eth_cmd.speed = adapter->link_speed; + eth_cmd.duplex = + (adapter->link_duplex == + FULL_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + } else { + eth_cmd.speed = 0; + eth_cmd.duplex = 0; + } + + if(adapter->shared.autoneg) + eth_cmd.autoneg = AUTONEG_ENABLE; + else + eth_cmd.autoneg = AUTONEG_DISABLE; + + if(copy_to_user(ifr->ifr_data, ð_cmd, sizeof(eth_cmd))) + return -EFAULT; + + break; + + /* set information */ + case ETHTOOL_SSET: + /* need proper permission to do set */ + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Cannot Force speed/duplex and at the same time autoneg. + * Autoneg will override forcing. + * For example to force speed/duplex pass in + * 'speed 100 duplex half autoneg off' + * pass in 'autoneg on' to start autoneg. + */ + printk("e1000: Requested link to be forced to %d Speed, %s Duplex " + "%s\n", eth_cmd.speed, (eth_cmd.duplex ? "Full" : "Half"), + (eth_cmd.autoneg ? "and Autonegotiate" : ".")); + + if(eth_cmd.autoneg && eth_cmd.speed) + printk("e1000: Autoneg request will over-ride speed forcing\n"); + + /* if not in autoneg mode and have been asked to enable autoneg */ + if(eth_cmd.autoneg) { + if(adapter->shared.autoneg && + adapter->shared.autoneg_advertised == AUTONEG_ADV_DEFAULT) + /* If already in Autoneg */ + return 0; + else { + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + re_initiate = TRUE; + } + } + /* Force link to whatever speed and duplex */ + /* Also turning off Autoneg in case of non-gig speeds */ + else if(eth_cmd.speed) { + /* Check for invalid request */ + if(((eth_cmd.speed != SPEED_10) && (eth_cmd.speed != SPEED_100) && + (eth_cmd.speed != SPEED_1000)) || + ((eth_cmd.duplex != DUPLEX_HALF) && + (eth_cmd.duplex != DUPLEX_FULL)) || + (adapter->shared.media_type == e1000_media_type_fiber)) + return -EINVAL; + + e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, + &adapter->link_duplex); + /* If we are already forced to requested speed and duplex + * Donot do anything, just return + */ + if(!adapter->shared.autoneg && + (adapter->link_speed == eth_cmd.speed) && + (adapter->link_duplex == (eth_cmd.duplex + 1))) + + return 0; + + adapter->shared.autoneg = 0; + adapter->shared.autoneg_advertised = 0; + re_initiate = TRUE; + switch (eth_cmd.speed + eth_cmd.duplex) { + case (SPEED_10 + DUPLEX_HALF): + adapter->shared.forced_speed_duplex = e1000_10_half; + break; + case (SPEED_100 + DUPLEX_HALF): + adapter->shared.forced_speed_duplex = e1000_100_half; + break; + case (SPEED_10 + DUPLEX_FULL): + adapter->shared.forced_speed_duplex = e1000_10_full; + break; + case (SPEED_100 + DUPLEX_FULL): + adapter->shared.forced_speed_duplex = e1000_100_full; + break; + case (SPEED_1000 + DUPLEX_HALF): + printk("Half Duplex is not supported at 1000 Mbps\n"); + case (SPEED_1000 + DUPLEX_FULL): + printk("Using Auto-neg at 1000 Mbps Full Duplex\n"); + default: + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + } + } + + /* End of force */ + /* Put the adapter to new settings */ + if(re_initiate == TRUE) { + e1000_hibernate_adapter(netdev); + e1000_wakeup_adapter(netdev); + } else if(!eth_cmd.autoneg && !eth_cmd.speed) { + printk("Cannot turn off autoneg without " + "knowing what speed to force the link\n"); + printk("Speed specified was %dMbps\n", eth_cmd.speed); + return -EINVAL; + } + /* We donot support setting of + * whatever else that was requested */ + else + return -EOPNOTSUPP; + + break; + +#ifdef ETHTOOL_NWAY_RST + case ETHTOOL_NWAY_RST: + /* need proper permission to restart auto-negotiation */ + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + e1000_hibernate_adapter(netdev); + e1000_wakeup_adapter(netdev); + + break; +#endif + +#ifdef ETHTOOL_GLINK + case ETHTOOL_GLINK: + eth_e1000_linkinfo.data = adapter->link_active; + if(copy_to_user(ifr->ifr_data, ð_e1000_linkinfo, sizeof(eth_e1000_linkinfo))) + return -EFAULT; + break; +#endif + +#ifdef ETHTOOL_GDRVINFO + case ETHTOOL_GDRVINFO: + strcpy(eth_e1000_info.driver, e1000_driver_name); + strcpy(eth_e1000_info.version, e1000_driver_version); + strcpy(eth_e1000_info.fw_version, "None"); + strcpy(eth_e1000_info.bus_info, adapter->pdev->slot_name); + if(copy_to_user(ifr->ifr_data, ð_e1000_info, sizeof(eth_e1000_info))) + return -EFAULT; + break; +#endif + +#ifdef ETHTOOL_GWOL + case ETHTOOL_GWOL: + eth_e1000_wolinfo.supported = eth_e1000_wolinfo.wolopts = WAKE_MAGIC; + if(copy_to_user + (ifr->ifr_data, ð_e1000_wolinfo, sizeof(eth_e1000_wolinfo))) + return -EFAULT; + break; +#endif + + default: + return -EOPNOTSUPP; + } + + return 0; + +} +#endif /* SIOCETHTOOL */ + +/** + * e1000_enable_WOL - Wake On Lan Support (Magic Pkt) + * @adapter: Adapter structure + **/ + +static void +e1000_enable_WOL(struct e1000_adapter *adapter) +{ + uint32_t wuc_val; + + if(adapter->shared.mac_type <= e1000_82543) + return; + + /* Set up Wake-Up Ctrl reg */ + wuc_val = E1000_READ_REG(&adapter->shared, WUC); + wuc_val &= ~(E1000_WUC_APME | E1000_WUC_APMPME); + wuc_val |= (E1000_WUC_PME_STATUS | E1000_WUC_PME_EN); + + E1000_WRITE_REG(&adapter->shared, WUC, wuc_val); + + /* Set up Wake-up Filter */ + E1000_WRITE_REG(&adapter->shared, WUFC, E1000_WUFC_MAG); + + return; +} + +/** + * e1000_write_pci_cg - + * @shared: + * @reg: + * @value: + **/ + +void +e1000_write_pci_cfg(struct e1000_shared_adapter *shared, + uint32_t reg, + uint16_t *value) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) shared->back; + + pci_write_config_word(adapter->pdev, reg, *value); + return; +} + +/* e1000_main.c */ diff -Nur linux-2.4.19/drivers/net/e1000/e1000_osdep.h linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_osdep.h --- linux-2.4.19/drivers/net/e1000/e1000_osdep.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_osdep.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,138 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + + +/* glue for the OS independant part of e1000 + * includes register access macros + */ + +#ifndef _E1000_OSDEP_H_ +#define _E1000_OSDEP_H_ + +#include +#include +#include +#include + +#define usec_delay(x) udelay(x) +#define msec_delay(x) mdelay(x) + +#define PCI_COMMAND_REGISTER PCI_COMMAND +#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE + +typedef enum { + FALSE = 0, + TRUE = 1 +} boolean_t; + +#if DBG +#define ASSERT(x) if(!(x)) panic("E1000: x") +#define DEBUGOUT(S) printk(S "\n") +#define DEBUGOUT1(S,A) printk(S "\n",A) +#define DEBUGOUT2(S,A,B) printk(S "\n",A,B) +#define DEBUGOUT3(S,A,B,C) printk(S "\n",A,B,C) +#define DEBUGOUT7(S,A,B,C,D,E,F,G) printk(S "\n",A,B,C,D,E,F,G) +#else +#define ASSERT(x) +#define DEBUGOUT(S) +#define DEBUGOUT1(S,A) +#define DEBUGOUT2(S,A,B) +#define DEBUGOUT3(S,A,B,C) +#define DEBUGOUT7(S,A,B,C,D,E,F,G) +#endif + +#define MSGOUT(S, A, B) printk(S "\n", A, B) +#define DEBUGFUNC(F) DEBUGOUT(F) + +#define E1000_WRITE_REG(a, reg, value) ( \ + ((a)->mac_type >= e1000_82543) ? \ + (writel((value), ((a)->hw_addr + E1000_##reg))) : \ + (writel((value), ((a)->hw_addr + E1000_82542_##reg)))) + +#define E1000_READ_REG(a, reg) ( \ + ((a)->mac_type >= e1000_82543) ? \ + readl((a)->hw_addr + E1000_##reg) : \ + readl((a)->hw_addr + E1000_82542_##reg)) + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ + ((a)->mac_type >= e1000_82543) ? \ + writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \ + writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))) + +#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ + ((a)->mac_type >= e1000_82543) ? \ + readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \ + readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))) + +#endif /* _E1000_OSDEP_H_ */ diff -Nur linux-2.4.19/drivers/net/e1000/e1000_phy.c linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_phy.c --- linux-2.4.19/drivers/net/e1000/e1000_phy.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_phy.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,1576 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + +/* e1000_phy.c + * Shared functions for accessing and configuring the PHY + */ + +#include "e1000_mac.h" +#include "e1000_phy.h" + +/****************************************************************************** +* Raises the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +e1000_raise_mdc(struct e1000_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Raise the clock input to the Management Data Clock (by setting + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC)); + usec_delay(2); + return; +} + +/****************************************************************************** +* Lowers the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +e1000_lower_mdc(struct e1000_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Lower the clock input to the Management Data Clock (by clearing + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC)); + usec_delay(2); + return; +} + +/****************************************************************************** +* Shifts data bits out to the PHY +* +* shared - Struct containing variables accessed by shared code +* data - Data to send out to the PHY +* count - Number of bits to shift out +* +* Bits are shifted out in MSB to LSB order. +******************************************************************************/ +static void +e1000_phy_shift_out(struct e1000_shared_adapter *shared, + uint32_t data, + uint16_t count) +{ + uint32_t ctrl_reg; + uint32_t mask; + + ASSERT(count <= 32); + + /* We need to shift "count" number of bits out to the PHY. So, the + * value in the "Data" parameter will be shifted out to the PHY + * one bit at a time. In order to do this, "Data" must be broken + * down into bits, which is what the "while" logic does below. + */ + mask = 0x01; + mask <<= (count - 1); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to + * be used as output pins. + */ + ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); + + while(mask) { + /* A "1" is shifted out to the PHY by setting the MDIO bit to + * "1" and then raising and lowering the Management Data Clock + * (MDC). A "0" is shifted out to the PHY by setting the MDIO + * bit to "0" and then raising and lowering the clock. + */ + if(data & mask) + ctrl_reg |= E1000_CTRL_MDIO; + else + ctrl_reg &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + usec_delay(2); + + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + mask = mask >> 1; + } + + /* Clear the data bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + return; +} + +/****************************************************************************** +* Shifts data bits in from the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Bits are shifted in in MSB to LSB order. +******************************************************************************/ +static uint16_t +e1000_phy_shift_in(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint16_t data = 0; + uint8_t i; + + /* In order to read a register from the PHY, we need to shift in a + * total of 18 bits from the PHY. The first two bit (TurnAround) + * times are used to avoid contention on the MDIO pin when a read + * operation is performed. These two bits are ignored by us and + * thrown away. Bits are "shifted in" by raising the clock input + * to the Management Data Clock (setting the MDC bit), and then + * reading the value of the MDIO bit. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as + * input. + */ + ctrl_reg &= ~E1000_CTRL_MDIO_DIR; + ctrl_reg &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Raise and Lower the clock before reading in the data. This + * accounts for the TurnAround bits. The first clock occurred + * when we clocked out the last bit of the Register Address. + */ + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + for(data = 0, i = 0; i < 16; i++) { + data = data << 1; + e1000_raise_mdc(shared, &ctrl_reg); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Check to see if we shifted in a "1". */ + if(ctrl_reg & E1000_CTRL_MDIO) + data |= 1; + + e1000_lower_mdc(shared, &ctrl_reg); + } + + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + /* Clear the MDIO bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + + return (data); +} + +/****************************************************************************** +* Force PHY speed and duplex settings to shared->forced_speed_duplex +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +static void +e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint32_t ctrl_reg; + uint32_t shift; + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_data; + uint16_t i; + + DEBUGFUNC("e1000_phy_force_speed_duplex"); + + /* Turn off Flow control if we are forcing speed and duplex. */ + shared->fc = e1000_fc_none; + + DEBUGOUT1("shared->fc = %d\n", shared->fc); + + /* Read the Device Control Register. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */ + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); + + /* Clear the Auto Speed Detect Enable bit. */ + ctrl_reg &= ~E1000_CTRL_ASDE; + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + /* We need to disable autoneg in order to force link and duplex. */ + + mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN; + + /* Are we forcing Full or Half Duplex? */ + if(shared->forced_speed_duplex == e1000_100_full || + shared->forced_speed_duplex == e1000_10_full) { + + /* We want to force full duplex so we SET the full duplex bits + * in the Device and MII Control Registers. + */ + ctrl_reg |= E1000_CTRL_FD; + mii_ctrl_reg |= MII_CR_FULL_DUPLEX; + + DEBUGOUT("Full Duplex\n"); + } else { + + /* We want to force half duplex so we CLEAR the full duplex + * bits in the Device and MII Control Registers. + */ + ctrl_reg &= ~E1000_CTRL_FD; + mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; /* Do this implies HALF */ + + DEBUGOUT("Half Duplex\n"); + } + + /* Are we forcing 100Mbps??? */ + if(shared->forced_speed_duplex == e1000_100_full || + shared->forced_speed_duplex == e1000_100_half) { + + /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */ + ctrl_reg |= E1000_CTRL_SPD_100; + mii_ctrl_reg |= MII_CR_SPEED_100; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + + DEBUGOUT("Forcing 100mb "); + } else { /* Force 10MB Full or Half */ + + /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */ + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + mii_ctrl_reg |= MII_CR_SPEED_10; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + + DEBUGOUT("Forcing 10mb "); + } + + /* Now we need to configure the Collision Distance. We need to read + * the Transmit Control Register to do this. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) { + + /* We are in Half Duplex mode so we need to set up our collision + * distance for 10/100. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Write the MII Control Register with the new PHY configuration. */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Clear Auto-Crossover to force MDI manually. + * M88E1000 requires MDI forced whenever speed/duplex is forced + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + + DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); + + /* Need to reset the PHY or these bits will get ignored. */ + mii_ctrl_reg |= MII_CR_RESET; + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* The wait_autoneg_complete flag may be a little misleading here. + * Since we are forcing speed and duplex, Auto-Neg is not enabled. + * But we do want to delay for a period while forcing only so we + * don't generate false No Link messages. So we will wait here + * only if the user has set wait_autoneg_complete to 1, which is + * the default. + */ + if(shared->wait_autoneg_complete) { + /* We will wait for autoneg to complete. */ + DEBUGOUT("Waiting for forced speed/duplex link.\n"); + mii_status_reg = 0; + + /* We will wait for autoneg to complete or 4.5 seconds to expire. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + + msec_delay(100); + } /* end for loop */ + + if(i == 0) { /* We didn't get link */ + + /* Reset the DSP and wait again for link. */ + e1000_phy_reset_dsp(shared); + } + + /* This loop will early-out if the link condition has been met. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + + msec_delay(100); + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + } /* end for loop */ + } /* end if wait_autoneg_complete */ + /* + * Because we reset the PHY above, we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock. This + * value defaults back to a 2.5MHz clock when the PHY is reset. + */ + phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + + /* In addition, because of the s/w reset above, we need to enable + * CRS on TX. This must be set for both full and half duplex + * operation. + */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data); + + return; +} + +/***************************************************************************** +* Reads the value from a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to read +******************************************************************************/ +uint16_t +e1000_read_phy_reg(struct e1000_shared_adapter *shared, + uint32_t reg_addr) +{ + uint32_t i; + uint32_t data = 0; + uint32_t command = 0; + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > e1000_82543) { + /* Set up Op-code, Phy Address, and + * register address in the MDI Control register. The MAC will + * take care of interfacing with the PHY to retrieve the + * desired data. + */ + command = ((reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 64; i++) { + usec_delay(10); + + data = E1000_READ_REG(shared, MDIC); + + if(data & E1000_MDIC_READY) + break; + } + } else { + /* We must first send a preamble through the MDIO pin to signal the + * beginning of an MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the next few fields that are required for a read + * operation. We use this method instead of calling the + * e1000_phy_shift_out routine five different times. The format of + * a MII read instruction consists of a shift out of 14 bits and is + * defined as follows: + * + * followed by a shift in of 18 bits. This first two bits shifted + * in are TurnAround bits used to avoid contention on the MDIO pin + * when a READ operation is performed. These two bits are thrown + * away followed by a shift in of 16 bits which contains the + * desired data. + */ + command = ((reg_addr) | + (shared->phy_addr << 5) | + (PHY_OP_READ << 10) | (PHY_SOF << 12)); + + e1000_phy_shift_out(shared, command, 14); + + /* Now that we've shifted out the read command to the MII, we need + * to "shift in" the 16-bit value (18 total bits) of the requested + * PHY register address. + */ + data = (uint32_t) e1000_phy_shift_in(shared); + } + + ASSERT(!(data & E1000_MDIC_ERROR)); + + return ((uint16_t) data); +} + +/****************************************************************************** +* Writes a value to a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to write +* data - data to write to the PHY +******************************************************************************/ +void +e1000_write_phy_reg(struct e1000_shared_adapter *shared, + uint32_t reg_addr, + uint16_t data) +{ + uint32_t i; + uint32_t command = 0; + uint32_t mdic_reg; + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > e1000_82543) { + /* Set up Op-code, Phy Address, register + * address, and data intended for the PHY register in the MDI + * Control register. The MAC will take care of interfacing + * with the PHY to send the desired data. + */ + command = (((uint32_t) data) | + (reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 10; i++) { + usec_delay(10); + + mdic_reg = E1000_READ_REG(shared, MDIC); + + if(mdic_reg & E1000_MDIC_READY) + break; + } + } else { + /* We'll need to use the SW defined pins to shift the write command + * out to the PHY. We first send a preamble to the PHY to signal the + * beginning of the MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the remaining required fields that will indicate + * a write operation. We use this method instead of calling the + * e1000_phy_shift_out routine for each field in the command. The + * format of a MII write instruction is as follows: + * . + */ + command = ((PHY_TURNAROUND) | + (reg_addr << 2) | + (shared->phy_addr << 7) | + (PHY_OP_WRITE << 12) | (PHY_SOF << 14)); + command <<= 16; + command |= ((uint32_t) data); + + e1000_phy_shift_out(shared, command, 32); + } + return; +} + +/****************************************************************************** +* Returns the PHY to the power-on reset state +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +e1000_phy_hw_reset(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t ctrl_ext_reg; + + DEBUGFUNC("e1000_phy_hw_reset"); + + DEBUGOUT("Resetting Phy...\n"); + + if(shared->mac_type > e1000_82543) { + /* Read the device control register and assert the + * E1000_CTRL_PHY_RST bit. Hold for 20ms and then take it out + * of reset. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ctrl_reg |= E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + msec_delay(20); + + ctrl_reg &= ~E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + msec_delay(20); + } else { + /* Read the Extended Device Control Register, assert the + * PHY_RESET_DIR bit. Then clock it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + + /* Set the reset bit in the device control register and clock + * it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg |= E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + } + return; +} + +/****************************************************************************** +* Resets the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Sets bit 15 of the MII Control regiser +******************************************************************************/ +boolean_t +e1000_phy_reset(struct e1000_shared_adapter *shared) +{ + uint16_t reg_data; + uint16_t i; + + DEBUGFUNC("e1000_phy_reset"); + + /* Read the MII control register, set the reset bit and write the + * value back by clocking it out to the PHY. + */ + reg_data = e1000_read_phy_reg(shared, PHY_CTRL); + + reg_data |= MII_CR_RESET; + + e1000_write_phy_reg(shared, PHY_CTRL, reg_data); + + /* Wait for bit 15 of the MII Control Register to be cleared + * indicating the PHY has been reset. + */ + i = 0; + while((reg_data & MII_CR_RESET) && i++ < 500) { + reg_data = e1000_read_phy_reg(shared, PHY_CTRL); + usec_delay(1); + } + + if(i >= 500) { + DEBUGOUT("Timeout waiting for PHY to reset.\n"); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** +* Detects which PHY is present and the speed and duplex +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - current value of the device control register +******************************************************************************/ +boolean_t +e1000_phy_setup(struct e1000_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + uint16_t i; + uint16_t data; + uint16_t autoneg_hw_setting; + uint16_t autoneg_fc_setting; + boolean_t restart_autoneg = FALSE; + boolean_t force_autoneg_restart = FALSE; + + DEBUGFUNC("e1000_phy_setup"); + + /* We want to enable the Auto-Speed Detection bit in the Device + * Control Register. When set to 1, the MAC automatically detects + * the resolved speed of the link and self-configures appropriately. + * The Set Link Up bit must also be set for this behavior work + * properly. + */ + /* Nothing but 82543 and newer */ + ASSERT(shared->mac_type >= e1000_82543); + + /* With 82543, we need to force speed/duplex + * on the MAC equal to what the PHY speed/duplex configuration is. + * In addition, on 82543, we need to perform a hardware reset + * on the PHY to take it out of reset. + */ + if(shared->mac_type >= e1000_82544) { + ctrl_reg |= E1000_CTRL_SLU; + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + } else { + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + if(shared->mac_type == e1000_82543) + e1000_phy_hw_reset(shared); + } + + if(!e1000_detect_gig_phy(shared)) { + /* No PHY detected, return FALSE */ + DEBUGOUT("PhySetup failure, did not detect valid phy.\n"); + return (FALSE); + } + + DEBUGOUT1("Phy ID = %x \n", shared->phy_id); + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg); + + /* Check to see if the Auto Neg Enable bit is set in the MII Control + * Register. If not, we could be in a situation where a driver was + * loaded previously and was forcing speed and duplex. Then the + * driver was unloaded but a e1000_phy_hw_reset was not performed, so + * link was still being forced and link was still achieved. Then + * the driver was reloaded with the intention to auto-negotiate, but + * since link is already established we end up not restarting + * auto-neg. So if the auto-neg bit is not enabled and the driver + * is being loaded with the desire to auto-neg, we set this flag to + * to ensure the restart of the auto-neg engine later in the logic. + */ + if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN)) + force_autoneg_restart = TRUE; + + /* Clear the isolate bit for normal operation and write it back to + * the MII Control Reg. Although the spec says this doesn't need + * to be done when the PHY address is not equal to zero, we do it + * anyway just to be safe. + */ + mii_ctrl_reg &= ~(MII_CR_ISOLATE); + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + DEBUGOUT1("M88E1000 PSCR: %x \n", data); + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data); + + data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + data |= M88E1000_EPSCR_TX_CLK_25; + + e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data); + + /* Certain PHYs will set the default of MII register 4 differently. + * We need to check this against our fc value. If it is + * different, we need to setup up register 4 correctly and restart + * autonegotiation. + */ + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Shift right to put 10T-Half bit in bit 0 + * Isolate the four bits for 100/10 Full/Half. + */ + autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF; + + /* Get the 1000T settings. */ + mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Isolate and OR in the 1000T settings. */ + autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4); + + /* mask all bits in the MII Auto-Neg Advertisement Register + * except for ASM_DIR and PAUSE and shift. This value + * will be used later to see if we need to restart Auto-Negotiation. + */ + autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10); + + /* Perform some bounds checking on the shared->autoneg_advertised + * parameter. If this variable is zero, then set it to the default. + */ + shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if(shared->autoneg_advertised == 0) + shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* We could be in the situation where Auto-Neg has already completed + * and the user has not indicated any overrides. In this case we + * simply need to call e1000_get_speed_and_duplex to obtain the Auto- + * Negotiated speed and duplex, then return. + */ + if(!force_autoneg_restart && shared->autoneg && + (shared->autoneg_advertised == autoneg_hw_setting) && + (shared->fc == autoneg_fc_setting)) { + + DEBUGOUT("No overrides - Reading MII Status Reg..\n"); + + /* Read the MII Status Register. We read this twice because + * certain bits are "sticky" and need to be read twice. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg); + + /* Do we have link now? (if so, auto-neg has completed) */ + if(mii_status_reg & MII_SR_LINK_STATUS) { + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established + * with the link partner. + */ + if(shared->mac_type >= e1000_82544) + e1000_config_collision_dist(shared); + else + e1000_config_mac_to_phy(shared, data); + + e1000_config_fc_after_link_up(shared); + + return (TRUE); + } + } + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (shared->mdix) { + case 1: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL; + + if(shared->disable_polarity_correction == 1) + phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * autoneg = 1 (default) + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * autoneg = 0 + * PHY will be set to 10H, 10F, 100H, or 100F + * depending on value parsed from forced_speed_duplex. + */ + + /* Is autoneg enabled? This is enabled by default or by software override. + * If so, call e1000_phy_setup_autoneg routine to parse the + * autoneg_advertised and fc options. If autoneg is NOT enabled, then the + * user should have provided a speed/duplex override. If so, then call + * e1000_phy_force_speed_duplex to parse and set this up. Otherwise, + * we are in an error situation and need to bail. + */ + if(shared->autoneg) { + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + restart_autoneg = e1000_phy_setup_autoneg(shared); + } else { + DEBUGOUT("Forcing speed and duplex\n"); + e1000_phy_force_speed_duplex(shared); + } + + /* Based on information parsed above, check the flag to indicate + * whether we need to restart Auto-Neg. + */ + if(restart_autoneg) { + DEBUGOUT("Restarting Auto-Neg\n"); + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit. + */ + mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if(shared->wait_autoneg_complete) + e1000_wait_autoneg(shared); + } /* end if restart_autoneg */ + + /* Read the MII Status Register. */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n", + mii_status_reg); + + /* Check link status. Wait up to 100 microseconds for link to + * become valid. + */ + for(i = 0; i < 10; i++) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + usec_delay(10); + DEBUGOUT(". "); + + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + } + + if(mii_status_reg & MII_SR_LINK_STATUS) { + /* Yes, so configure MAC to PHY settings as well as flow control + * registers. + */ + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established with + * the link partner. + */ + if(shared->mac_type >= e1000_82544) + e1000_config_collision_dist(shared); + else + e1000_config_mac_to_phy(shared, data); + + e1000_config_fc_after_link_up(shared); + + DEBUGOUT("Valid link established!!!\n"); + } else { + DEBUGOUT("Unable to establish link!!!\n"); + } + + return (TRUE); +} + +/****************************************************************************** +* Configures PHY autoneg and flow control advertisement settings +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared) +{ + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + + DEBUGFUNC("e1000_phy_setup_autoneg"); + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~REG4_SPEED_MASK; + mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK; + + DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_HALF) { + DEBUGOUT("Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_FULL) { + DEBUGOUT("Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_HALF) { + DEBUGOUT("Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_FULL) { + DEBUGOUT("Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if(shared->autoneg_advertised & ADVERTISE_1000_HALF) { + DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n"); + } + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_1000_FULL) { + DEBUGOUT("Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case e1000_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * (in e1000_config_fc_after_link_up) we will disable the + *shared's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Write the MII Auto-Neg Advertisement Register (Address 4). */ + e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + + DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + /* Write the MII 1000Base-T Control Register (Address 9). */ + e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + return (TRUE); +} + +/****************************************************************************** +* Sets MAC speed and duplex settings to reflect the those in the PHY +* +* shared - Struct containing variables accessed by shared code +* mii_reg - data to write to the MII control register +* +* The contents of the PHY register containing the needed information need to +* be passed in. +******************************************************************************/ +void +e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, + uint16_t mii_reg) +{ + uint32_t ctrl_reg; + uint32_t tctl_reg; + uint32_t shift; + + DEBUGFUNC("e1000_config_mac_to_phy"); + + /* We need to read the Transmit Control register to configure the + * collision distance. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* Read the Device Control Register and set the bits to Force Speed + * and Duplex. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); + + DEBUGOUT1("MII Register Data = %x\r\n", mii_reg); + + /* Clear the ILOS bit. */ + ctrl_reg &= ~E1000_CTRL_ILOS; + + /* Set up duplex in the Device Control and Transmit Control + * registers depending on negotiated values. + */ + if(mii_reg & M88E1000_PSSR_DPLX) { + ctrl_reg |= E1000_CTRL_FD; + + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + ctrl_reg &= ~E1000_CTRL_FD; + + /* We are in Half Duplex mode. Our Half Duplex collision + * distance is different for Gigabit than for 10/100 so we will + * set accordingly. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + /* 1000Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ + } else { + /* 10/100Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + } + + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + ctrl_reg |= E1000_CTRL_SPD_1000; + else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + ctrl_reg |= E1000_CTRL_SPD_100; + else + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + return; +} + +/****************************************************************************** +* Sets the collision distance in the Transmit Control register +* +* shared - Struct containing variables accessed by shared code +* +* Link should have been established previously. Reads the speed and duplex +* information from the Device Status register. +******************************************************************************/ +void +e1000_config_collision_dist(struct e1000_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint16_t speed; + uint16_t duplex; + uint32_t shift; + + DEBUGFUNC("e1000_config_collision_dist"); + + /* Get our current speed and duplex from the Device Status Register. */ + e1000_get_speed_and_duplex(shared, &speed, &duplex); + + /* We need to configure the Collision Distance for both Full or + * Half Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* mask the Collision Distance bits in the Transmit Control Reg. */ + tctl_reg &= ~E1000_TCTL_COLD; + + if(duplex == FULL_DUPLEX) { + /* We are in Full Duplex mode. Therefore, the collision distance + * is the same regardless of speed. + */ + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Half Duplex mode. Half Duplex collision distance is + * different for Gigabit vs. 10/100, so we will set accordingly. + */ + if(speed == SPEED_1000) { /* 1000Mbs HDX */ + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ + } else { /* 10/100Mbs HDX */ + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + } + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + return; +} + +#if DBG +/****************************************************************************** +* Displays the contents of all of the MII registers +* +* shared - Struct containing variables accessed by shared code +* +* For debugging. +******************************************************************************/ +void +e1000_display_mii(struct e1000_shared_adapter *shared) +{ + uint16_t data; + uint16_t phy_id_high; + uint16_t phy_id_low; + uint32_t phy_id; + + DEBUGFUNC("e1000_display_mii"); + + DEBUGOUT1("adapter Base Address = %x\n", shared->hw_addr); + + /* This will read each PHY Reg address and display its contents. */ + + data = e1000_read_phy_reg(shared, PHY_CTRL); + DEBUGOUT1("MII Ctrl Reg contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_STATUS); + data = e1000_read_phy_reg(shared, PHY_STATUS); + DEBUGOUT1("MII Status Reg contents = %x\n", data); + + phy_id_high = e1000_read_phy_reg(shared, PHY_ID1); + usec_delay(2); + phy_id_low = e1000_read_phy_reg(shared, PHY_ID2); + phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK; + DEBUGOUT1("Phy ID = %x \n", phy_id); + + data = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); + DEBUGOUT1("Reg 4 contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_LP_ABILITY); + DEBUGOUT1("Reg 5 contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_AUTONEG_EXP); + DEBUGOUT1("Reg 6 contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_NEXT_PAGE_TX); + DEBUGOUT1("Reg 7 contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_LP_NEXT_PAGE); + DEBUGOUT1("Reg 8 contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_1000T_CTRL); + DEBUGOUT1("Reg 9 contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_1000T_STATUS); + DEBUGOUT1("Reg A contents = %x\n", data); + + data = e1000_read_phy_reg(shared, PHY_EXT_STATUS); + DEBUGOUT1("Reg F contents = %x\n", data); + + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + DEBUGOUT1("M88E1000 Specific Control Reg (0x10) = %x\n", data); + + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Specific Status Reg (0x11) = %x\n", data); + + /* + * data = e1000_read_phy_reg(shared, M88E1000_INT_ENABLE_REG); + * DEBUGOUT1("M88E1000 Interrupt Enable Reg (0x12) = %x\n", data); + */ + + /* + * data = e1000_read_phy_reg(shared, M88E1000_INT_STATUS_REG); + * DEBUGOUT1("M88E1000 Interrupt Status Reg (0x13) = %x\n", data); + */ + + data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + DEBUGOUT1("M88E1000 Ext. Phy Specific Control (0x14) = %x\n", data); + + data = e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR); + DEBUGOUT1("M88E1000 Receive Error Counter (0x15) = %x\n", data); + + /* + * data = e1000_read_phy_reg(shared, M88E1000_LED_CTRL_REG); + * DEBUGOUT1("M88E1000 LED control reg (0x18) = %x\n", data); + */ + + return; +} +#endif // DBG + +/****************************************************************************** +* Probes the expected PHY address for known PHY IDs +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_detect_gig_phy(struct e1000_shared_adapter *shared) +{ + uint32_t phy_id_high; + uint16_t phy_id_low; + + DEBUGFUNC("e1000_detect_gig_phy"); + + /* Read the PHY ID Registers to identify which PHY is onboard. */ + shared->phy_addr = 1; + + phy_id_high = e1000_read_phy_reg(shared, PHY_ID1); + + usec_delay(2); + + phy_id_low = e1000_read_phy_reg(shared, PHY_ID2); + + shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK; + + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID || + shared->phy_id == M88E1011_I_PHY_ID) { + + DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n", + shared->phy_id, shared->phy_addr); + return (TRUE); + } else { + DEBUGOUT("Could not auto-detect Phy!\n"); + return (FALSE); + } +} + +/****************************************************************************** +* Resets the PHY's DSP +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +e1000_phy_reset_dsp(struct e1000_shared_adapter *shared) +{ + e1000_write_phy_reg(shared, 29, 0x1d); + e1000_write_phy_reg(shared, 30, 0xc1); + e1000_write_phy_reg(shared, 30, 0x00); + return; +} + +/****************************************************************************** +* Blocks until autoneg completes or times out (~4.5 seconds) +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_wait_autoneg(struct e1000_shared_adapter *shared) +{ + uint16_t i; + uint16_t mii_status_reg; + boolean_t autoneg_complete = FALSE; + + DEBUGFUNC("e1000_wait_autoneg"); + + /* We will wait for autoneg to complete. */ + DEBUGOUT("Waiting for Auto-Neg to complete.\n"); + mii_status_reg = 0; + + /* We will wait for autoneg to complete or 4.5 seconds to expire. */ + + for(i = PHY_AUTO_NEG_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + autoneg_complete = TRUE; + break; + } + + msec_delay(100); + } + + return (autoneg_complete); +} + +/****************************************************************************** +* Get PHY information from various PHY registers +* +* shared - Struct containing variables accessed by shared code +* phy_status_info - PHY information structure +******************************************************************************/ +boolean_t +e1000_phy_get_info(struct e1000_shared_adapter *shared, + struct e1000_phy_info *phy_status_info) +{ + uint16_t phy_mii_status_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t phy_specific_status_reg; + uint16_t phy_specific_ext_ctrl_reg; + uint16_t phy_1000t_stat_reg; + + phy_status_info->cable_length = e1000_cable_length_undefined; + phy_status_info->extended_10bt_distance = + e1000_10bt_ext_dist_enable_undefined; + phy_status_info->cable_polarity = e1000_rev_polarity_undefined; + phy_status_info->polarity_correction = e1000_polarity_reversal_undefined; + phy_status_info->link_reset = e1000_down_no_idle_undefined; + phy_status_info->mdix_mode = e1000_auto_x_mode_undefined; + phy_status_info->local_rx = e1000_1000t_rx_status_undefined; + phy_status_info->remote_rx = e1000_1000t_rx_status_undefined; + + /* PHY info only valid for copper media. */ + if(shared == NULL || shared->media_type != e1000_media_type_copper) + return FALSE; + + /* PHY info only valid for LINK UP. Read MII status reg + * back-to-back to get link status. + */ + phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) + return FALSE; + + /* Read various PHY registers to get the PHY info. */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + phy_specific_status_reg = + e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + phy_specific_ext_ctrl_reg = + e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS); + + phy_status_info->cable_length = + ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + + phy_status_info->extended_10bt_distance = + (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> + M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + + phy_status_info->cable_polarity = + (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >> + M88E1000_PSSR_REV_POLARITY_SHIFT; + + phy_status_info->polarity_correction = + (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >> + M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + phy_status_info->link_reset = + (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >> + M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT; + + phy_status_info->mdix_mode = + (phy_specific_status_reg & M88E1000_PSSR_MDIX) >> + M88E1000_PSSR_MDIX_SHIFT; + + phy_status_info->local_rx = + (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + phy_status_info->remote_rx = + (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + return TRUE; +} + +boolean_t +e1000_validate_mdi_setting(struct e1000_shared_adapter *shared) +{ + if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) { + shared->mdix = 1; + return FALSE; + } + return TRUE; +} diff -Nur linux-2.4.19/drivers/net/e1000/e1000_phy.h linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_phy.h --- linux-2.4.19/drivers/net/e1000/e1000_phy.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_phy.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,424 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + +/* e1000_phy.h + * Structures, enums, and macros for the PHY + */ + +#ifndef _E1000_PHY_H_ +#define _E1000_PHY_H_ + +#include "e1000_osdep.h" + +/* PHY status info structure and supporting enums */ +typedef enum { + e1000_cable_length_50 = 0, + e1000_cable_length_50_80, + e1000_cable_length_80_110, + e1000_cable_length_110_140, + e1000_cable_length_140, + e1000_cable_length_undefined = 0xFF +} e1000_cable_length; + +typedef enum { + e1000_10bt_ext_dist_enable_normal = 0, + e1000_10bt_ext_dist_enable_lower, + e1000_10bt_ext_dist_enable_undefined = 0xFF +} e1000_10bt_ext_dist_enable; + +typedef enum { + e1000_rev_polarity_normal = 0, + e1000_rev_polarity_reversed, + e1000_rev_polarity_undefined = 0xFF +} e1000_rev_polarity; + +typedef enum { + e1000_polarity_reversal_enabled = 0, + e1000_polarity_reversal_disabled, + e1000_polarity_reversal_undefined = 0xFF +} e1000_polarity_reversal; + +typedef enum { + e1000_down_no_idle_no_detect = 0, + e1000_down_no_idle_detect, + e1000_down_no_idle_undefined = 0xFF +} e1000_down_no_idle; + +typedef enum { + e1000_auto_x_mode_manual_mdi = 0, + e1000_auto_x_mode_manual_mdix, + e1000_auto_x_mode_auto1, + e1000_auto_x_mode_auto2, + e1000_auto_x_mode_undefined = 0xFF +} e1000_auto_x_mode; + +typedef enum { + e1000_1000t_rx_status_not_ok = 0, + e1000_1000t_rx_status_ok, + e1000_1000t_rx_status_undefined = 0xFF +} e1000_1000t_rx_status; + +struct e1000_phy_info { + e1000_cable_length cable_length; + e1000_10bt_ext_dist_enable extended_10bt_distance; + e1000_rev_polarity cable_polarity; + e1000_polarity_reversal polarity_correction; + e1000_down_no_idle link_reset; + e1000_auto_x_mode mdix_mode; + e1000_1000t_rx_status local_rx; + e1000_1000t_rx_status remote_rx; +}; + +struct e1000_phy_stats { + uint32_t idle_errors; + uint32_t receive_errors; +}; + +/* Function Prototypes */ +uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr); +void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data); +void e1000_phy_hw_reset(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg); +boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared); +void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg); +void e1000_config_collision_dist(struct e1000_shared_adapter *shared); +void e1000_display_mii(struct e1000_shared_adapter *shared); +boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared); +void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared); +boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info); +boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared); + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ +#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 +#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 +#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 +#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 +#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 +#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 +#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR +#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CTRL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ +#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ +#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ + +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register */ +#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */ + +/* Next Page TX Register */ +#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* Link Partner Next Page Register */ +#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ +#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */ +#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */ + +#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */ + /* (0=enable, 1=disable) */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, + * 0=CLK125 toggling + */ +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, + * 100BASE-TX/10BASE-T: + * MDI Mode + */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. + */ +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 + /* 1=Enable Extended 10BASE-T distance + * (Lower 10BASE-T RX Threshold) + * 0=Normal 10BASE-T RX Threshold */ +#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 + /* 1=5-Bit interface in 100BASE-TX + * 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5 +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; + * 3=110-140M;4=>140M */ +#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ +#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ +#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_REV_POLARITY_SHIFT 1 +#define M88E1000_PSSR_MDIX_SHIFT 6 +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* M88E1000 Extended PHY Specific Control Register */ +#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ +#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled. + * Will assert lost lock and bring + * link down if idle not seen + * within 1ms in 1000BASE-T + */ +#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + +#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15 + +/* Bit definitions for valid PHY IDs. */ +#define M88E1000_12_PHY_ID 0x01410C50 +#define M88E1000_14_PHY_ID 0x01410C40 +#define M88E1000_I_PHY_ID 0x01410C30 +#define M88E1011_I_PHY_ID 0x01410C20 + +/* Miscellaneous PHY bit definitions. */ +#define PHY_PREAMBLE 0xFFFFFFFF +#define PHY_SOF 0x01 +#define PHY_OP_READ 0x02 +#define PHY_OP_WRITE 0x01 +#define PHY_TURNAROUND 0x02 +#define PHY_PREAMBLE_SIZE 32 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 +#define E1000_PHY_ADDRESS 0x01 +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */ +#define REG4_SPEED_MASK 0x01E0 +#define REG9_SPEED_MASK 0x0300 +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 +#define ADVERTISE_1000_FULL 0x0020 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ + +#endif /* _E1000_PHY_H_ */ diff -Nur linux-2.4.19/drivers/net/e1000/e1000_proc.c linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_proc.c --- linux-2.4.19/drivers/net/e1000/e1000_proc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_proc.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,1437 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + +/***************************************************************************/ +/* /proc File System Interaface Support Functions */ +/***************************************************************************/ + +#include "e1000.h" +extern char e1000_driver_name[]; +extern char e1000_driver_version[]; +#include "e1000_proc.h" +#include + +struct proc_dir_entry *e1000_proc_dir; + +#define CABLE_LENGTH_TO_STRING() \ + msg = \ + (adapter->phy_info.cable_length == e1000_cable_length_50) ? "0-50 Meters (+/- 20 Meters)" : \ + (adapter->phy_info.cable_length == e1000_cable_length_50_80) ? "50-80 Meters (+/- 20 Meters)" : \ + (adapter->phy_info.cable_length == e1000_cable_length_80_110) ? "80-110 Meters (+/- 20 Meters)" : \ + (adapter->phy_info.cable_length == e1000_cable_length_110_140) ? "110-140 Meters (+/- 20 Meters)" : \ + (adapter->phy_info.cable_length == e1000_cable_length_140) ? "> 140 Meters (+/- 20 Meters)" : \ + "Unknown"; + +#define EXTENDED_10BASE_T_DISTANCE_TO_STRING() \ + msg = \ + (adapter->phy_info.extended_10bt_distance == \ + e1000_10bt_ext_dist_enable_normal) ? "Disabled" : \ + (adapter->phy_info.extended_10bt_distance == \ + e1000_10bt_ext_dist_enable_lower) ? "Enabled" : "Unknown"; + +#define CABLE_POLARITY_TO_STRING() \ + msg = \ + (adapter->phy_info.cable_polarity == e1000_rev_polarity_normal) ? "Normal" : \ + (adapter->phy_info.cable_polarity == e1000_rev_polarity_reversed) ? \ + "Reversed" : "Unknown"; + +#define POLARITY_CORRECTION_TO_STRING() \ + msg = \ + (adapter->phy_info.polarity_correction == \ + e1000_polarity_reversal_enabled) ? "Disabled" : \ + (adapter->phy_info.polarity_correction == \ + e1000_polarity_reversal_disabled) ? "Enabled" : "Undefined"; + +#define LINK_RESET_TO_STRING() \ + msg = \ + (adapter->phy_info.link_reset == e1000_down_no_idle_no_detect) ? "Disabled" : \ + (adapter->phy_info.link_reset == e1000_down_no_idle_detect) ? "Enabled" : \ + "Unknown"; + +#define MDI_X_MODE_TO_STRING() \ + msg = (adapter->phy_info.mdix_mode == 0) ? "MDI" : "MDI-X"; + +#define LOCAL_RECEIVER_STATUS_TO_STRING() \ + msg = \ + (adapter->phy_info.local_rx == e1000_1000t_rx_status_not_ok) ? "NOT_OK" : \ + (adapter->phy_info.local_rx == e1000_1000t_rx_status_ok) ? "OK" : \ + "Unknown"; + +#define REMOTE_RECEIVER_STATUS_TO_STRING() \ + msg = \ + (adapter->phy_info.remote_rx == e1000_1000t_rx_status_not_ok) ? "NOT_OK" : \ + (adapter->phy_info.remote_rx == e1000_1000t_rx_status_ok) ? "OK" : \ + "Unknown"; + +static void e1000_link_update(struct e1000_adapter * adapter) { + + e1000_check_for_link(&adapter->shared); + if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) + adapter->link_active = 1; + else + adapter->link_active = 0; + + if (adapter->link_active) { + e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, &adapter->link_duplex); + } else { + adapter->link_speed = 0; + adapter->link_duplex = 0; + } + return; +} + +static int e1000_generic_read(char *page, char **start, off_t off, + int count, int *eof) +{ + int len; + + len = strlen(page); + page[len++] = '\n'; + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +static int e1000_read_ulong(char *page, char **start, off_t off, + int count, int *eof, unsigned long l) +{ + sprintf(page, "%lu", l); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_ulong_hex(char *page, char **start, off_t off, + int count, int *eof, unsigned long l) +{ + sprintf(page, "0x%04lx", l); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_ullong(char *page, char **start, off_t off, + int count, int *eof, unsigned long long l) +{ + sprintf(page, "%Lu", l); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_hwaddr(char *page, char **start, off_t off, + int count, int *eof, unsigned char *hwaddr) +{ + sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X", + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + + return e1000_generic_read(page, start, off, count, eof); +} + +/* need to check page boundaries !!! */ +static int e1000_read_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + struct net_device_stats *stats = &adapter->net_stats; + unsigned char *hwaddr; + char *pagep = page; + char *msg; + + page += sprintf(page, "%-32s %s\n", DESCRIPTION_TAG, adapter->id_string); + page += sprintf(page, "%-32s %06lx-%03x\n", + PART_NUMBER_TAG, + (unsigned long )adapter->part_num >> 8, + adapter->part_num & 0x000000FF); + + page += sprintf(page, "%-32s %s\n", DRVR_NAME_TAG, e1000_driver_name); + + page += sprintf(page, "%-32s %s\n", DRVR_VERSION_TAG, e1000_driver_version); + + page += sprintf(page, "%-32s 0x%04lx\n", + PCI_VENDOR_TAG, (unsigned long) adapter->vendor_id); + page += sprintf(page, "%-32s 0x%04lx\n", + PCI_DEVICE_ID_TAG, (unsigned long) adapter->device_id); + page += sprintf(page, "%-32s 0x%04lx\n", + PCI_SUBSYSTEM_VENDOR_TAG, + (unsigned long) adapter->subven_id); + page += sprintf(page, "%-32s 0x%04lx\n", + PCI_SUBSYSTEM_ID_TAG, + (unsigned long) adapter->subsys_id); + page += sprintf(page, "%-32s 0x%02lx\n", + PCI_REVISION_ID_TAG, + (unsigned long) adapter->rev_id); + + page += sprintf(page, "%-32s %lu\n", + PCI_BUS_TAG, + (unsigned long) (adapter->pdev->bus->number)); + page += sprintf(page, "%-32s %lu\n", + PCI_SLOT_TAG, + (unsigned + long) (PCI_SLOT((adapter->pdev->devfn)))); + + if(adapter->shared.mac_type >= e1000_82543) { + page += sprintf(page, "%-32s %s\n", + PCI_BUS_TYPE_TAG, + (adapter->shared.bus_type == e1000_bus_type_pci) ? "PCI" : + (adapter->shared.bus_type == e1000_bus_type_pcix) ? "PCI-X" : + "UNKNOWN"); + + page += sprintf(page, "%-32s %s\n", + PCI_BUS_SPEED_TAG, + (adapter->shared.bus_speed == e1000_bus_speed_33) ? "33MHz" : + (adapter->shared.bus_speed == e1000_bus_speed_66) ? "66MHz" : + (adapter->shared.bus_speed == e1000_bus_speed_100) ? "100MHz" : + (adapter->shared.bus_speed == e1000_bus_speed_133) ? "133MHz" : + "UNKNOWN"); + + page += sprintf(page, "%-32s %s\n", + PCI_BUS_WIDTH_TAG, + (adapter->shared.bus_width == e1000_bus_width_32) ? "32-bit" : + (adapter->shared.bus_width == e1000_bus_width_64) ? "64-bit" : + "UNKNOWN"); + } + + page += + sprintf(page, "%-32s %lu\n", IRQ_TAG, + (unsigned long) (adapter->pdev->irq)); + page += + sprintf(page, "%-32s %s\n", SYSTEM_DEVICE_NAME_TAG, + adapter->netdev->name); + + hwaddr = adapter->netdev->dev_addr; + page += sprintf(page, "%-32s %02X:%02X:%02X:%02X:%02X:%02X\n", + CURRENT_HWADDR_TAG, + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + + hwaddr = adapter->perm_net_addr; + page += sprintf(page, "%-32s %02X:%02X:%02X:%02X:%02X:%02X\n", + PERMANENT_HWADDR_TAG, + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + + page += sprintf(page, "\n"); + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + if (adapter->link_active == 1) + msg = "up"; + else + msg = "down"; + page += sprintf(page, "%-32s %s\n", LINK_TAG, msg); + + if (adapter->link_speed) + page += sprintf(page, "%-32s %lu\n", + SPEED_TAG, + (unsigned long) (adapter->link_speed)); + else + page += sprintf(page, "%-32s %s\n", SPEED_TAG, "N/A"); + + msg = adapter->link_duplex == FULL_DUPLEX ? "full" : + ((adapter->link_duplex == 0) ? "N/A" : "half"); + page += sprintf(page, "%-32s %s\n", DUPLEX_TAG, msg); + + if (adapter->netdev->flags & IFF_UP) + msg = "up"; + else + msg = "down"; + page += sprintf(page, "%-32s %s\n", STATE_TAG, msg); + + page += sprintf(page, "\n"); + + page += sprintf(page, "%-32s %lu\n", + RX_PACKETS_TAG, (unsigned long) stats->rx_packets); + page += sprintf(page, "%-32s %lu\n", + TX_PACKETS_TAG, (unsigned long) stats->tx_packets); + page += sprintf(page, "%-32s %lu\n", + RX_BYTES_TAG, (unsigned long) stats->rx_bytes); + page += sprintf(page, "%-32s %lu\n", + TX_BYTES_TAG, (unsigned long) stats->tx_bytes); + page += sprintf(page, "%-32s %lu\n", + RX_ERRORS_TAG, (unsigned long) stats->rx_errors); + page += sprintf(page, "%-32s %lu\n", + TX_ERRORS_TAG, (unsigned long) stats->tx_errors); + page += sprintf(page, "%-32s %lu\n", + RX_DROPPED_TAG, (unsigned long) stats->rx_dropped); + page += sprintf(page, "%-32s %lu\n", + TX_DROPPED_TAG, (unsigned long) stats->tx_dropped); + page += sprintf(page, "%-32s %lu\n", + MULTICAST_TAG, (unsigned long) stats->multicast); + page += sprintf(page, "%-32s %lu\n", + COLLISIONS_TAG, (unsigned long) stats->collisions); + page += sprintf(page, "%-32s %lu\n", + RX_LENGTH_ERRORS_TAG, + (unsigned long) stats->rx_length_errors); + page += sprintf(page, "%-32s %lu\n", + RX_OVER_ERRORS_TAG, + (unsigned long) stats->rx_over_errors); + page += sprintf(page, "%-32s %lu\n", + RX_CRC_ERRORS_TAG, + (unsigned long) stats->rx_crc_errors); + page += sprintf(page, "%-32s %lu\n", + RX_FRAME_ERRORS_TAG, + (unsigned long) stats->rx_frame_errors); + page += sprintf(page, "%-32s %lu\n", + RX_FIFO_ERRORS_TAG, + (unsigned long) stats->rx_fifo_errors); + page += sprintf(page, "%-32s %lu\n", + RX_MISSED_ERRORS_TAG, + (unsigned long) stats->rx_missed_errors); + page += sprintf(page, "%-32s %lu\n", + TX_ABORTED_ERRORS_TAG, + (unsigned long) stats->tx_aborted_errors); + page += sprintf(page, "%-32s %lu\n", + TX_CARRIER_ERRORS_TAG, + (unsigned long) stats->tx_carrier_errors); + page += sprintf(page, "%-32s %lu\n", + TX_FIFO_ERRORS_TAG, + (unsigned long) stats->tx_fifo_errors); + page += sprintf(page, "%-32s %lu\n", + TX_HEARTBEAT_ERRORS_TAG, + (unsigned long) stats->tx_heartbeat_errors); + page += sprintf(page, "%-32s %lu\n", + TX_WINDOW_ERRORS_TAG, + (unsigned long) stats->tx_window_errors); + + page += sprintf(page, "\n"); + + /* 8254x specific stats */ + page += sprintf(page, "%-32s %Lu\n", + TX_LATE_COLL_TAG, + (unsigned long long)adapter->stats.latecol); + page += sprintf(page, "%-32s %Lu\n", + TX_DEFERRED_TAG, + (unsigned long long)adapter->stats.dc); + page += sprintf(page, "%-32s %Lu\n", + TX_SINGLE_COLL_TAG, + (unsigned long long)adapter->stats.scc); + page += sprintf(page, "%-32s %Lu\n", + TX_MULTI_COLL_TAG, + (unsigned long long)adapter->stats.mcc); + page += sprintf(page, "%-32s %Lu\n", + RX_LONG_ERRORS_TAG, + (unsigned long long)adapter->stats.roc); + page += sprintf(page, "%-32s %Lu\n", + RX_SHORT_ERRORS_TAG, + (unsigned long long)adapter->stats.ruc); + /* The 82542 does not have an alignment error count register */ + /* ALGNERRC is only valid in MII mode at 10 or 100 Mbps */ + if(adapter->shared.mac_type >= e1000_82543) + page += sprintf(page, "%-32s %Lu\n", + RX_ALIGN_ERRORS_TAG, + (unsigned long long)adapter->stats.algnerrc); + page += sprintf(page, "%-32s %Lu\n", + RX_XON_TAG, + (unsigned long long)adapter->stats.xonrxc); + page += sprintf(page, "%-32s %Lu\n", + RX_XOFF_TAG, + (unsigned long long)adapter->stats.xoffrxc); + page += sprintf(page, "%-32s %Lu\n", + TX_XON_TAG, + (unsigned long long)adapter->stats.xontxc); + page += sprintf(page, "%-32s %Lu\n", + TX_XOFF_TAG, + (unsigned long long)adapter->stats.xofftxc); + page += sprintf(page, "%-32s %Lu\n", + RX_CSUM_GOOD_TAG, + (unsigned long long)adapter->XsumRXGood); + page += sprintf(page, "%-32s %Lu\n", + RX_CSUM_ERROR_TAG, + (unsigned long long)adapter->XsumRXError); + + if (adapter->shared.media_type == e1000_media_type_copper) + msg = "Copper"; + else + msg = "Fiber"; + page += sprintf(page, "\n%-32s %s\n", MEDIA_TYPE_TAG, msg); + + if (adapter->shared.media_type == e1000_media_type_copper) { + CABLE_LENGTH_TO_STRING(); + page += sprintf(page, "%-32s %s\n", CABLE_LENGTH_TAG, msg); + + EXTENDED_10BASE_T_DISTANCE_TO_STRING(); + page += sprintf(page, "%-32s %s\n", EXTENDED_10BASE_T_DISTANCE_TAG, msg); + + CABLE_POLARITY_TO_STRING(); + page += sprintf(page, "%-32s %s\n", CABLE_POLARITY_TAG, msg); + + POLARITY_CORRECTION_TO_STRING(); + page += sprintf(page, "%-32s %s\n", CABLE_POLARITY_CORRECTION_TAG, msg); + + page += sprintf(page, "%-32s %lu\n", IDLE_ERRORS_TAG, (unsigned long)adapter->phy_stats.idle_errors ); + + LINK_RESET_TO_STRING(); + page += sprintf(page, "%-32s %s\n", LINK_RESET_ENABLED_TAG, msg); + + page += sprintf(page, "%-32s %lu\n", RECEIVE_ERRORS_TAG, (unsigned long)adapter->phy_stats.receive_errors); + + MDI_X_MODE_TO_STRING(); + page += sprintf(page, "%-32s %s\n", MDI_X_ENABLED_TAG, msg); + + LOCAL_RECEIVER_STATUS_TO_STRING(); + page += sprintf(page, "%-32s %s\n", LOCAL_RECEIVER_STATUS_TAG, msg); + + REMOTE_RECEIVER_STATUS_TO_STRING(); + page += sprintf(page, "%-32s %s\n", REMOTE_RECEIVER_STATUS_TAG, msg); + } + + *page = 0; + return e1000_generic_read(pagep, start, off, count, eof); +} + +static int e1000_read_descr(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + strncpy(page, adapter->id_string, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_partnum(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + sprintf(page, "%06lx-%03x", + (unsigned long)adapter->part_num >> 8, + adapter->part_num & 0x000000FF); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_drvr_name(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + strncpy(page, e1000_driver_name, PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_drvr_ver(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + strncpy(page, e1000_driver_version, PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_pci_vendor(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong_hex(page, start, off, count, eof, + (unsigned long) adapter->vendor_id); +} + +static int e1000_read_pci_device(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong_hex(page, start, off, count, eof, + (unsigned long) adapter->device_id); +} + +static int e1000_read_pci_sub_vendor(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong_hex(page, start, off, count, eof, + (unsigned long) adapter->subven_id); +} + +static int e1000_read_pci_sub_device(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong_hex(page, start, off, count, eof, + (unsigned long) adapter->subsys_id); +} + +static int e1000_read_pci_revision(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong_hex(page, start, off, count, eof, + (unsigned long) adapter->rev_id); +} + +static int e1000_read_dev_name(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + strncpy(page, adapter->netdev->name, PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_pci_bus(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) (adapter->pdev->bus->number)); +} + +static int e1000_read_pci_slot(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned + long) (PCI_SLOT((adapter->pdev->devfn)))); +} + +static int e1000_read_pci_bus_type(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + strncpy(page, + (adapter->shared.bus_type == e1000_bus_type_pci) ? "PCI" : + (adapter->shared.bus_type == e1000_bus_type_pcix) ? "PCI-X" : + "UNKNOWN", PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_pci_bus_speed(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + strncpy(page, + (adapter->shared.bus_speed == e1000_bus_speed_33) ? "33MHz" : + (adapter->shared.bus_speed == e1000_bus_speed_66) ? "66MHz" : + (adapter->shared.bus_speed == e1000_bus_speed_100) ? "100MHz" : + (adapter->shared.bus_speed == e1000_bus_speed_133) ? "133MHz" : + "UNKNOWN", PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_pci_bus_width(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + strncpy(page, + (adapter->shared.bus_width == e1000_bus_width_32) ? "32-bit" : + (adapter->shared.bus_width == e1000_bus_width_64) ? "64-bit" : + "UNKNOWN", PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_irq(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) (adapter->pdev->irq)); +} + +static int e1000_read_current_hwaddr(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + unsigned char *hwaddr = adapter->netdev->dev_addr; + + return e1000_read_hwaddr(page, start, off, count, eof, hwaddr); +} + +static int e1000_read_permanent_hwaddr(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + unsigned char *hwaddr = adapter->perm_net_addr; + + return e1000_read_hwaddr(page, start, off, count, eof, hwaddr); +} + +static int e1000_read_link_status(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + if (adapter->link_active == 1) + strncpy(page, "up", PAGE_SIZE); + else + strncpy(page, "down", PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_speed(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + if (adapter->link_speed) + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) (adapter->link_speed)); + strncpy(page, "N/A", PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_dplx_mode(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + char *dplx_mode; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + dplx_mode = adapter->link_duplex == FULL_DUPLEX ? "full" : + ((adapter->link_duplex == 0) ? "N/A" : "half"); + strncpy(page, dplx_mode, PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_state(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + if (adapter->netdev->flags & IFF_UP) + strncpy(page, "up", PAGE_SIZE); + else + strncpy(page, "down", PAGE_SIZE); + + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_rx_packets(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_packets); +} + +static int e1000_read_tx_packets(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_packets); +} + +static int e1000_read_rx_bytes(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_bytes); +} + +static int e1000_read_tx_bytes(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_bytes); +} + +static int e1000_read_rx_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_errors); +} + +static int e1000_read_tx_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_errors); +} + +static int e1000_read_rx_dropped(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_dropped); +} + +static int e1000_read_tx_dropped(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_dropped); +} + +static int e1000_read_rx_multicast_packets(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.multicast); +} + +static int e1000_read_collisions(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.collisions); +} + +static int e1000_read_rx_length_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_length_errors); +} + +static int e1000_read_rx_over_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_over_errors); +} + +static int e1000_read_rx_crc_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_crc_errors); +} + +static int e1000_read_rx_frame_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_frame_errors); +} + +static int e1000_read_rx_fifo_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_fifo_errors); +} + +static int e1000_read_rx_missed_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.rx_missed_errors); +} + +static int e1000_read_tx_aborted_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_aborted_errors); +} + +static int e1000_read_tx_carrier_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_carrier_errors); +} + +static int e1000_read_tx_fifo_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_fifo_errors); +} + +static int e1000_read_tx_heartbeat_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_heartbeat_errors); +} + +static int e1000_read_tx_window_errors(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + return e1000_read_ulong(page, start, off, count, eof, + (unsigned long) adapter->net_stats.tx_window_errors); +} + +/* 8254x specific stats */ +static int e1000_read_tx_late_coll(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.latecol); +} + +static int e1000_read_tx_defer_events(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.dc); +} +static int e1000_read_tx_single_coll(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.scc); +} +static int e1000_read_tx_multi_coll(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.mcc); +} +static int e1000_read_rx_oversize(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.roc); +} +static int e1000_read_rx_undersize(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.ruc); +} +static int e1000_read_rx_align_err(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.algnerrc); +} +static int e1000_read_rx_xon(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xonrxc); +} +static int e1000_read_rx_xoff(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xoffrxc); +} +static int e1000_read_tx_xon(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xontxc); +} +static int e1000_read_tx_xoff(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xofftxc); +} + +static struct proc_dir_entry *e1000_create_proc_read(char *name, + struct e1000_adapter * adapter, + struct proc_dir_entry *parent, + read_proc_t * read_proc) +{ + struct proc_dir_entry *pdep; + + if (!(pdep = create_proc_entry(name, S_IFREG, parent))) + return NULL; + pdep->read_proc = read_proc; + pdep->data = adapter; + return pdep; +} + +static int e1000_read_cable_length (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + CABLE_LENGTH_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_media_type (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + switch (adapter->shared.media_type) { + case e1000_media_type_copper: strncpy(page,"Copper", PAGE_SIZE); break; + case e1000_media_type_fiber: strncpy(page, "Fiber", PAGE_SIZE); break; + default: strncpy(page, "Unknown", PAGE_SIZE); + } + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_extended_10base_t_distance (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + EXTENDED_10BASE_T_DISTANCE_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_cable_polarity (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + CABLE_POLARITY_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_cable_polarity_correction (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + POLARITY_CORRECTION_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_idle_errors (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + return e1000_read_ulong(page, start, off, count, eof, adapter->phy_stats.idle_errors); +} + +static int e1000_read_link_reset_enabled (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + LINK_RESET_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_receive_errors (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + return e1000_read_ulong(page, start, off, count, eof, adapter->phy_stats.receive_errors); +} + +static int e1000_read_mdi_x_enabled (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + MDI_X_MODE_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_local_receiver_status (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + LOCAL_RECEIVER_STATUS_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +static int e1000_read_remote_receiver_status (char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + char *msg; + struct e1000_adapter * adapter = (struct e1000_adapter *) data; + + /* If board is not open yet, */ + if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) + e1000_link_update(adapter); + + REMOTE_RECEIVER_STATUS_TO_STRING(); + strncpy (page, msg, PAGE_SIZE); + return e1000_generic_read(page, start, off, count, eof); +} + +int e1000_create_proc_dev(struct e1000_adapter * adapter) +{ + struct proc_dir_entry *dev_dir; + char info[256]; + int len; + + dev_dir = create_proc_entry(adapter->netdev->name, S_IFDIR, e1000_proc_dir); + + strncpy(info, adapter->netdev->name, sizeof(info)); + len = strlen(info); + strncat(info + len, ".info", sizeof(info) - len); + + /* info */ + if (!(e1000_create_proc_read(info, adapter, e1000_proc_dir, e1000_read_info))) + return -1; + + /* description */ + if (!(e1000_create_proc_read(DESCRIPTION_TAG, adapter, dev_dir, e1000_read_descr))) + return -1; + /* part number */ + if (!(e1000_create_proc_read(PART_NUMBER_TAG, adapter, dev_dir, e1000_read_partnum))) + return -1; + /* driver name */ + if (!(e1000_create_proc_read(DRVR_NAME_TAG, adapter, dev_dir, e1000_read_drvr_name))) + return -1; + /* driver version */ + if (!(e1000_create_proc_read(DRVR_VERSION_TAG, adapter, dev_dir, e1000_read_drvr_ver))) + return -1; + /* pci vendor */ + if (!(e1000_create_proc_read(PCI_VENDOR_TAG, adapter, dev_dir, e1000_read_pci_vendor))) + return -1; + /* pci device id */ + if (!(e1000_create_proc_read(PCI_DEVICE_ID_TAG, adapter, dev_dir, + e1000_read_pci_device))) return -1; + /* pci sub vendor */ + if (!(e1000_create_proc_read(PCI_SUBSYSTEM_VENDOR_TAG, adapter, dev_dir, + e1000_read_pci_sub_vendor))) return -1; + /* pci sub device id */ + if (!(e1000_create_proc_read(PCI_SUBSYSTEM_ID_TAG, adapter, dev_dir, + e1000_read_pci_sub_device))) return -1; + /* pci revision id */ + if (!(e1000_create_proc_read(PCI_REVISION_ID_TAG, adapter, dev_dir, + e1000_read_pci_revision))) return -1; + /* device name */ + if (!(e1000_create_proc_read(SYSTEM_DEVICE_NAME_TAG, adapter, dev_dir, + e1000_read_dev_name))) return -1; + /* pci bus */ + if (!(e1000_create_proc_read(PCI_BUS_TAG, adapter, dev_dir, e1000_read_pci_bus))) + return -1; + /* pci slot */ + if (!(e1000_create_proc_read(PCI_SLOT_TAG, adapter, dev_dir, e1000_read_pci_slot))) + return -1; + /* pci bus type */ + if (!(e1000_create_proc_read(PCI_BUS_TYPE_TAG, adapter, dev_dir, + e1000_read_pci_bus_type))) return -1; + /* pci bus speed */ + if (!(e1000_create_proc_read(PCI_BUS_SPEED_TAG, adapter, dev_dir, + e1000_read_pci_bus_speed))) return -1; + /* pci bus width */ + if (!(e1000_create_proc_read(PCI_BUS_WIDTH_TAG, adapter, dev_dir, + e1000_read_pci_bus_width))) return -1; + /* irq */ + if (!(e1000_create_proc_read(IRQ_TAG, adapter, dev_dir, e1000_read_irq))) + return -1; + /* current hwaddr */ + if (!(e1000_create_proc_read(CURRENT_HWADDR_TAG, adapter, dev_dir, + e1000_read_current_hwaddr))) return -1; + /* permanent hwaddr */ + if (!(e1000_create_proc_read(PERMANENT_HWADDR_TAG, adapter, dev_dir, + e1000_read_permanent_hwaddr))) return -1; + + /* link status */ + if (!(e1000_create_proc_read(LINK_TAG, adapter, dev_dir, e1000_read_link_status))) + return -1; + /* speed */ + if (!(e1000_create_proc_read(SPEED_TAG, adapter, dev_dir, e1000_read_speed))) + return -1; + /* duplex mode */ + if (!(e1000_create_proc_read(DUPLEX_TAG, adapter, dev_dir, e1000_read_dplx_mode))) + return -1; + /* state */ + if (!(e1000_create_proc_read(STATE_TAG, adapter, dev_dir, e1000_read_state))) + return -1; + /* rx packets */ + if (!(e1000_create_proc_read(RX_PACKETS_TAG, adapter, dev_dir, e1000_read_rx_packets))) + return -1; + /* tx packets */ + if (!(e1000_create_proc_read(TX_PACKETS_TAG, adapter, dev_dir, e1000_read_tx_packets))) + return -1; + /* rx bytes */ + if (!(e1000_create_proc_read(RX_BYTES_TAG, adapter, dev_dir, e1000_read_rx_bytes))) + return -1; + /* tx bytes */ + if (!(e1000_create_proc_read(TX_BYTES_TAG, adapter, dev_dir, e1000_read_tx_bytes))) + return -1; + /* rx errors */ + if (!(e1000_create_proc_read(RX_ERRORS_TAG, adapter, dev_dir, e1000_read_rx_errors))) + return -1; + /* tx errors */ + if (!(e1000_create_proc_read(TX_ERRORS_TAG, adapter, dev_dir, e1000_read_tx_errors))) + return -1; + /* rx dropped */ + if (!(e1000_create_proc_read(RX_DROPPED_TAG, adapter, dev_dir, e1000_read_rx_dropped))) + return -1; + /* tx dropped */ + if (!(e1000_create_proc_read(TX_DROPPED_TAG, adapter, dev_dir, e1000_read_tx_dropped))) + return -1; + /* multicast packets */ + if (!(e1000_create_proc_read(MULTICAST_TAG, adapter, dev_dir, + e1000_read_rx_multicast_packets))) + return -1; + + /* collisions */ + if (!(e1000_create_proc_read (COLLISIONS_TAG, adapter, dev_dir, e1000_read_collisions))) + return -1; + + /* rx length errors */ + if (!(e1000_create_proc_read(RX_LENGTH_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_length_errors))) return -1; + /* rx over errors */ + if (!(e1000_create_proc_read(RX_OVER_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_over_errors))) return -1; + /* rx crc errors */ + if (!(e1000_create_proc_read(RX_CRC_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_crc_errors))) return -1; + /* rx frame errors */ + if (!(e1000_create_proc_read(RX_FRAME_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_frame_errors))) return -1; + /* rx fifo errors */ + if (!(e1000_create_proc_read(RX_FIFO_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_fifo_errors))) return -1; + /* rx missed errors */ + if (!(e1000_create_proc_read(RX_MISSED_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_missed_errors))) return -1; + /* tx aborted errors */ + if (!(e1000_create_proc_read(TX_ABORTED_ERRORS_TAG, adapter, dev_dir, + e1000_read_tx_aborted_errors))) return -1; + /* tx carrier errors */ + if (!(e1000_create_proc_read(TX_CARRIER_ERRORS_TAG, adapter, dev_dir, + e1000_read_tx_carrier_errors))) return -1; + /* tx fifo errors */ + if (!(e1000_create_proc_read(TX_FIFO_ERRORS_TAG, adapter, dev_dir, + e1000_read_tx_fifo_errors))) return -1; + /* tx heartbeat errors */ + if (!(e1000_create_proc_read(TX_HEARTBEAT_ERRORS_TAG, adapter, dev_dir, + e1000_read_tx_heartbeat_errors))) return -1; + /* tx window errors */ + if (!(e1000_create_proc_read(TX_WINDOW_ERRORS_TAG, adapter, dev_dir, + e1000_read_tx_window_errors))) return -1; + + if (!(e1000_create_proc_read(TX_LATE_COLL_TAG, adapter, dev_dir, + e1000_read_tx_late_coll))) return -1; + if (!(e1000_create_proc_read(TX_DEFERRED_TAG, adapter, dev_dir, + e1000_read_tx_defer_events))) return -1; + if (!(e1000_create_proc_read(TX_SINGLE_COLL_TAG, adapter, dev_dir, + e1000_read_tx_single_coll))) return -1; + if (!(e1000_create_proc_read(TX_MULTI_COLL_TAG, adapter, dev_dir, + e1000_read_tx_multi_coll))) return -1; + if (!(e1000_create_proc_read(RX_LONG_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_oversize))) return -1; + if (!(e1000_create_proc_read(RX_SHORT_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_undersize))) return -1; + if(adapter->shared.mac_type >= e1000_82543) + if (!(e1000_create_proc_read(RX_ALIGN_ERRORS_TAG, adapter, dev_dir, + e1000_read_rx_align_err))) return -1; + if (!(e1000_create_proc_read(RX_XON_TAG, adapter, dev_dir, + e1000_read_rx_xon))) return -1; + if (!(e1000_create_proc_read(RX_XOFF_TAG, adapter, dev_dir, + e1000_read_rx_xoff))) return -1; + if (!(e1000_create_proc_read(TX_XON_TAG, adapter, dev_dir, + e1000_read_tx_xon))) return -1; + if (!(e1000_create_proc_read(TX_XOFF_TAG, adapter, dev_dir, + e1000_read_tx_xoff))) return -1; + + if (!(e1000_create_proc_read(MEDIA_TYPE_TAG, adapter, dev_dir, + e1000_read_media_type))) return -1; + + if (adapter->shared.media_type == e1000_media_type_copper) { + if (!(e1000_create_proc_read(CABLE_LENGTH_TAG, adapter, dev_dir, + e1000_read_cable_length))) return -1; + + if (!(e1000_create_proc_read(EXTENDED_10BASE_T_DISTANCE_TAG, + adapter, dev_dir, + e1000_read_extended_10base_t_distance))) return -1; + + if (!(e1000_create_proc_read(CABLE_POLARITY_TAG, adapter, dev_dir, + e1000_read_cable_polarity))) return -1; + + if (!(e1000_create_proc_read(CABLE_POLARITY_CORRECTION_TAG, adapter, dev_dir, + e1000_read_cable_polarity_correction))) return -1; + + if (!(e1000_create_proc_read(IDLE_ERRORS_TAG, adapter, dev_dir, + e1000_read_idle_errors))) return -1; + + if (!(e1000_create_proc_read(LINK_RESET_ENABLED_TAG, adapter, dev_dir, + e1000_read_link_reset_enabled))) return -1; + + if (!(e1000_create_proc_read(RECEIVE_ERRORS_TAG, adapter, dev_dir, + e1000_read_receive_errors))) return -1; + + if (!(e1000_create_proc_read(MDI_X_ENABLED_TAG, adapter, dev_dir, + e1000_read_mdi_x_enabled))) return -1; + + if (!(e1000_create_proc_read(LOCAL_RECEIVER_STATUS_TAG, adapter, dev_dir, + e1000_read_local_receiver_status))) return -1; + + if (!(e1000_create_proc_read(REMOTE_RECEIVER_STATUS_TAG, adapter, dev_dir, + e1000_read_remote_receiver_status))) return -1; + } + + return 0; +} + +void e1000_remove_proc_dev(struct net_device *dev) +{ + struct proc_dir_entry *de; + struct e1000_adapter * adapter = dev->priv; + char info[256]; + int len; + + len = strlen(dev->name); + strncpy(info, dev->name, sizeof(info)); + strncat(info + len, ".info", sizeof(info) - len); + + for (de = e1000_proc_dir->subdir; de; de = de->next) { + if ((de->namelen == len) && (!memcmp(de->name, dev->name, len))) + break; + } + if (de) { + remove_proc_entry(DESCRIPTION_TAG, de); + remove_proc_entry(PART_NUMBER_TAG, de); + remove_proc_entry(DRVR_NAME_TAG, de); + remove_proc_entry(DRVR_VERSION_TAG, de); + remove_proc_entry(PCI_VENDOR_TAG, de); + remove_proc_entry(PCI_DEVICE_ID_TAG, de); + remove_proc_entry(PCI_SUBSYSTEM_VENDOR_TAG, de); + remove_proc_entry(PCI_SUBSYSTEM_ID_TAG, de); + remove_proc_entry(PCI_REVISION_ID_TAG, de); + remove_proc_entry(SYSTEM_DEVICE_NAME_TAG, de); + remove_proc_entry(PCI_BUS_TAG, de); + remove_proc_entry(PCI_SLOT_TAG, de); + remove_proc_entry(PCI_BUS_TYPE_TAG, de); + remove_proc_entry(PCI_BUS_SPEED_TAG, de); + remove_proc_entry(PCI_BUS_WIDTH_TAG, de); + remove_proc_entry(IRQ_TAG, de); + remove_proc_entry(CURRENT_HWADDR_TAG, de); + remove_proc_entry(PERMANENT_HWADDR_TAG, de); + + remove_proc_entry(LINK_TAG, de); + remove_proc_entry(SPEED_TAG, de); + remove_proc_entry(DUPLEX_TAG, de); + remove_proc_entry(STATE_TAG, de); + + remove_proc_entry(RX_PACKETS_TAG, de); + remove_proc_entry(TX_PACKETS_TAG, de); + remove_proc_entry(RX_BYTES_TAG, de); + remove_proc_entry(TX_BYTES_TAG, de); + remove_proc_entry(RX_ERRORS_TAG, de); + remove_proc_entry(TX_ERRORS_TAG, de); + remove_proc_entry(RX_DROPPED_TAG, de); + remove_proc_entry(TX_DROPPED_TAG, de); + remove_proc_entry(MULTICAST_TAG, de); + remove_proc_entry(COLLISIONS_TAG, de); + remove_proc_entry(RX_LENGTH_ERRORS_TAG, de); + remove_proc_entry(RX_OVER_ERRORS_TAG, de); + remove_proc_entry(RX_CRC_ERRORS_TAG, de); + remove_proc_entry(RX_FRAME_ERRORS_TAG, de); + remove_proc_entry(RX_FIFO_ERRORS_TAG, de); + remove_proc_entry(RX_MISSED_ERRORS_TAG, de); + remove_proc_entry(TX_ABORTED_ERRORS_TAG, de); + remove_proc_entry(TX_CARRIER_ERRORS_TAG, de); + remove_proc_entry(TX_FIFO_ERRORS_TAG, de); + remove_proc_entry(TX_HEARTBEAT_ERRORS_TAG, de); + remove_proc_entry(TX_WINDOW_ERRORS_TAG, de); + remove_proc_entry(TX_LATE_COLL_TAG, de); + remove_proc_entry(TX_DEFERRED_TAG, de); + remove_proc_entry(TX_SINGLE_COLL_TAG, de); + remove_proc_entry(TX_MULTI_COLL_TAG, de); + remove_proc_entry(RX_LONG_ERRORS_TAG, de); + remove_proc_entry(RX_SHORT_ERRORS_TAG, de); + remove_proc_entry(RX_XON_TAG, de); + remove_proc_entry(RX_XOFF_TAG, de); + remove_proc_entry(TX_XON_TAG, de); + remove_proc_entry(TX_XOFF_TAG, de); + + remove_proc_entry(MEDIA_TYPE_TAG, de); + if (adapter->shared.media_type == e1000_media_type_copper) { + remove_proc_entry(CABLE_LENGTH_TAG, de); + remove_proc_entry(EXTENDED_10BASE_T_DISTANCE_TAG, de); + remove_proc_entry(CABLE_POLARITY_TAG, de); + remove_proc_entry(CABLE_POLARITY_CORRECTION_TAG, de); + remove_proc_entry(IDLE_ERRORS_TAG, de); + remove_proc_entry(LINK_RESET_ENABLED_TAG, de); + remove_proc_entry(RECEIVE_ERRORS_TAG, de); + remove_proc_entry(MDI_X_ENABLED_TAG, de); + remove_proc_entry(LOCAL_RECEIVER_STATUS_TAG, de); + remove_proc_entry(REMOTE_RECEIVER_STATUS_TAG, de); + } + } + + remove_proc_entry(info, e1000_proc_dir); + remove_proc_entry(dev->name, e1000_proc_dir); +} diff -Nur linux-2.4.19/drivers/net/e1000/e1000_proc.h linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_proc.h --- linux-2.4.19/drivers/net/e1000/e1000_proc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/e1000/e1000_proc.h Tue Aug 27 19:53:13 2002 @@ -0,0 +1,181 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) 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. + +*******************************************************************************/ + +/* /proc definitions */ +#include + +#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters" + +#define DESCRIPTION_TAG "Description" +#define PART_NUMBER_TAG "Part_Number" +#define DRVR_NAME_TAG "Driver_Name" +#define DRVR_VERSION_TAG "Driver_Version" +#define PCI_VENDOR_TAG "PCI_Vendor" +#define PCI_DEVICE_ID_TAG "PCI_Device_ID" +#define PCI_SUBSYSTEM_VENDOR_TAG "PCI_Subsystem_Vendor" +#define PCI_SUBSYSTEM_ID_TAG "PCI_Subsystem_ID" +#define PCI_REVISION_ID_TAG "PCI_Revision_ID" +#define PCI_BUS_TAG "PCI_Bus" +#define PCI_SLOT_TAG "PCI_Slot" +#define PCI_BUS_TYPE_TAG "PCI_Bus_Type" +#define PCI_BUS_SPEED_TAG "PCI_Bus_Speed" +#define PCI_BUS_WIDTH_TAG "PCI_Bus_Width" +#define IRQ_TAG "IRQ" +#define SYSTEM_DEVICE_NAME_TAG "System_Device_Name" +#define CURRENT_HWADDR_TAG "Current_HWaddr" +#define PERMANENT_HWADDR_TAG "Permanent_HWaddr" + +#define LINK_TAG "Link" +#define SPEED_TAG "Speed" +#define DUPLEX_TAG "Duplex" +#define STATE_TAG "State" + +#define RX_PACKETS_TAG "Rx_Packets" +#define TX_PACKETS_TAG "Tx_Packets" +#define RX_BYTES_TAG "Rx_Bytes" +#define TX_BYTES_TAG "Tx_Bytes" +#define RX_ERRORS_TAG "Rx_Errors" +#define TX_ERRORS_TAG "Tx_Errors" +#define RX_DROPPED_TAG "Rx_Dropped" +#define TX_DROPPED_TAG "Tx_Dropped" +#define MULTICAST_TAG "Multicast" +#define COLLISIONS_TAG "Collisions" +#define RX_LENGTH_ERRORS_TAG "Rx_Length_Errors" +#define RX_OVER_ERRORS_TAG "Rx_Over_Errors" +#define RX_CRC_ERRORS_TAG "Rx_CRC_Errors" +#define RX_FRAME_ERRORS_TAG "Rx_Frame_Errors" +#define RX_FIFO_ERRORS_TAG "Rx_FIFO_Errors" +#define RX_MISSED_ERRORS_TAG "Rx_Missed_Errors" +#define TX_ABORTED_ERRORS_TAG "Tx_Aborted_Errors" +#define TX_CARRIER_ERRORS_TAG "Tx_Carrier_Errors" +#define TX_FIFO_ERRORS_TAG "Tx_FIFO_Errors" +#define TX_HEARTBEAT_ERRORS_TAG "Tx_Heartbeat_Errors" +#define TX_WINDOW_ERRORS_TAG "Tx_Window_Errors" + +#define RX_TCP_CHECKSUM_GOOD_TAG "Rx_TCP_Checksum_Good" +#define RX_TCP_CHECKSUM_BAD_TAG "Rx_TCP_Checksum_Bad" +#define TX_TCP_CHECKSUM_GOOD_TAG "Tx_TCP_Checksum_Good" +#define TX_TCP_CHECKSUM_BAD_TAG "Tx_TCP_Checksum_Bad" + +#define TX_LATE_COLL_TAG "Tx_Abort_Late_Coll" +#define TX_DEFERRED_TAG "Tx_Deferred_Ok" +#define TX_SINGLE_COLL_TAG "Tx_Single_Coll_Ok" +#define TX_MULTI_COLL_TAG "Tx_Multi_Coll_Ok" +#define RX_LONG_ERRORS_TAG "Rx_Long_Length_Errors" +#define RX_SHORT_ERRORS_TAG "Rx_Short_Length_Errors" +#define RX_ALIGN_ERRORS_TAG "Rx_Align_Errors" +#define RX_XON_TAG "Rx_Flow_Control_XON" +#define RX_XOFF_TAG "Rx_Flow_Control_XOFF" +#define TX_XON_TAG "Tx_Flow_Control_XON" +#define TX_XOFF_TAG "Tx_Flow_Control_XOFF" +#define RX_CSUM_GOOD_TAG "Rx_Csum_Offload_Good" +#define RX_CSUM_ERROR_TAG "Rx_Csum_Offload_Errors" + +/* what is the cable length (only for 100/1000 modes)? - 50, 50-80, 80-110, 110-140 and > 140 meters */ +#define CABLE_LENGTH_TAG "PHY_Cable_Length" + +/* Media Type Copper/Fiber */ +#define MEDIA_TYPE_TAG "PHY_Media_Type" + +/* Is extended 10 Base-T distance feature enabled? This is done by lowering the receive threshold - enabled/disabled */ +#define EXTENDED_10BASE_T_DISTANCE_TAG "PHY_Extended_10Base_T_Distance" + +/* Cable polarity Normal/Reversed */ +#define CABLE_POLARITY_TAG "PHY_Cable_Polarity" + +/* Is Polarity reversal enabled? Enabled/Disabled */ +#define CABLE_POLARITY_CORRECTION_TAG "PHY_Disable_Polarity_Correction" + +/* Number of IDLE Errors */ +#define IDLE_ERRORS_TAG "PHY_Idle_Errors" + +/* Should the link be brought down if an IDLE is not seen within 1 msec while in 1000mbps mode? Enabled/Disabled */ +#define LINK_RESET_ENABLED_TAG "PHY_Link_Reset_Enabled" + +/* Number of receive errors */ +#define RECEIVE_ERRORS_TAG "PHY_Receive_Errors" + +/* MDI-X Support Enabled? Auto, Manual(MDI) or Manual(MDI-X) */ +#define MDI_X_ENABLED_TAG "PHY_MDI_X_Enabled" + +/* Local Receiver OK? OK/NOT_OK */ +#define LOCAL_RECEIVER_STATUS_TAG "PHY_Local_Receiver_Status" + +/* Remote Receiver OK? OK/NOT_OK */ +#define REMOTE_RECEIVER_STATUS_TAG "PHY_Remote_Receiver_Status" + +/* symbols exported to e1000_main */ +extern struct proc_dir_entry *e1000_proc_dir; +extern int e1000_create_proc_dev(struct e1000_adapter * Adapter); +extern void e1000_remove_proc_dev(struct net_device *dev); diff -Nur linux-2.4.19/drivers/net/eepro100.c linux-2.4.19-sgi211r3/drivers/net/eepro100.c --- linux-2.4.19/drivers/net/eepro100.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/eepro100.c Wed Oct 16 14:02:58 2002 @@ -25,6 +25,10 @@ Disabled FC and ER, to avoid lockups when when we get FCP interrupts. 2000 Jul 17 Goutham Rao PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary + + 2000 Aug 31 David Mosberger + RX_ALIGN support: enables rx DMA without causing unaligned accesses. + */ static const char *version = @@ -41,14 +45,18 @@ static int txdmacount = 128; static int rxdmacount /* = 0 */; +#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || \ + defined(__mips__) || defined(__arm__) + /* align rx buffers to 2 bytes so that IP header is aligned */ +# define RX_ALIGN +# define RxFD_ALIGNMENT __attribute__ ((aligned (2), packed)) +#else +# define RxFD_ALIGNMENT +#endif + /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. Lower values use more memory, but are faster. */ -#if defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \ - defined(__arm__) -static int rx_copybreak = 1518; -#else static int rx_copybreak = 200; -#endif /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -377,18 +385,18 @@ /* The Speedo3 Rx and Tx frame/buffer descriptors. */ struct descriptor { /* A generic descriptor. */ - s32 cmd_status; /* All command and status fields. */ + volatile s32 cmd_status; /* All command and status fields. */ u32 link; /* struct descriptor * */ unsigned char params[0]; }; /* The Speedo3 Rx and Tx buffer descriptors. */ struct RxFD { /* Receive frame descriptor. */ - s32 status; + volatile s32 status; u32 link; /* struct RxFD * */ u32 rx_buf_addr; /* void * */ u32 count; -}; +} RxFD_ALIGNMENT; /* Selected elements of the Tx/RxFD.status word. */ enum RxFD_bits { @@ -1231,6 +1239,9 @@ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); +#ifdef RX_ALIGN + skb_reserve(skb, 2); /* Align IP on 16 byte boundary */ +#endif sp->rx_skbuff[i] = skb; if (skb == NULL) break; /* OK. Just initially short of Rx bufs. */ @@ -1622,6 +1633,9 @@ struct sk_buff *skb; /* Get a fresh skbuff to replace the consumed one. */ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); +#ifdef RX_ALIGN + skb_reserve(skb, 2); /* Align IP on 16 byte boundary */ +#endif sp->rx_skbuff[entry] = skb; if (skb == NULL) { sp->rx_ringp[entry] = NULL; @@ -1712,6 +1726,7 @@ int entry = sp->cur_rx % RX_RING_SIZE; int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; int alloc_ok = 1; + int npkts = 0; if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); @@ -1778,6 +1793,7 @@ memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail, pkt_len); #endif + npkts++; } else { /* Pass up the already-filled skbuff. */ skb = sp->rx_skbuff[entry]; @@ -1788,6 +1804,7 @@ } sp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); + npkts++; sp->rx_ringp[entry] = NULL; pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry], PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); @@ -1808,7 +1825,8 @@ /* Try hard to refill the recently taken buffers. */ speedo_refill_rx_buffers(dev, 1); - sp->last_rx_time = jiffies; + if (npkts) + sp->last_rx_time = jiffies; return 0; } diff -Nur linux-2.4.19/drivers/net/ioc3-eth.c linux-2.4.19-sgi211r3/drivers/net/ioc3-eth.c --- linux-2.4.19/drivers/net/ioc3-eth.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/ioc3-eth.c Thu Jan 2 15:16:59 2003 @@ -6,7 +6,7 @@ * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. * * Copyright (C) 1999, 2000, 2001 Ralf Baechle - * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. + * Copyright (C) 1995, 1999-2003 Silicon Graphics, Inc. All Rights Reserved. * * References: * o IOC3 ASIC specification 4.51, 1996-04-18 @@ -26,7 +26,7 @@ * which workarounds are required for them? Do we ever have Lucent's? * o For the 2.5 branch kill the mii-tool ioctls. */ -#include +#include #include #include #include @@ -36,13 +36,6 @@ #include #include -#ifdef CONFIG_SERIAL -#include -#include -#define IOC3_BAUD (22000000 / (3*16)) -#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -#endif - #include #include #include @@ -54,13 +47,27 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* direct mapped dma's go to widget b in sn1, widget a in sn0 + * both have Precise and Barrier flags set, sn1 also needs Swap + */ +/* #define DMA_WIDGET 0xb50UL */ /* * 64 RX buffers. This is tunable in the range of 16 <= x < 512. The @@ -79,6 +86,8 @@ /* Private per NIC data of the driver. */ struct ioc3_private { struct ioc3 *regs; + struct pci_dev *pdev; + unsigned long dma_attributes; int phy; unsigned long *rxr; /* pointer to receiver ring */ struct ioc3_etxd *txr; @@ -138,9 +147,13 @@ #define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET + 128) /* DMA barrier to separate cached and uncached accesses. */ +#if defined(__ia64__) +#include +#define BARRIER() ia64_sync_i(); ia64_srlz_i(); ia64_srlz_d() +#else #define BARRIER() \ __asm__("sync" ::: "memory") - +#endif /* __ia64__ */ #define IOC3_SIZE 0x100000 @@ -162,233 +175,17 @@ return (pulse << 10) | (sample << 2); } -static int -nic_wait(struct ioc3 *ioc3) -{ - u32 mcr; - - do { - mcr = ioc3_r(mcr); - } while (!(mcr & 2)); - - return mcr & 1; -} - -static int -nic_reset(struct ioc3 *ioc3) -{ - int presence; - - ioc3_w(mcr, mcr_pack(500, 65)); - presence = nic_wait(ioc3); - - ioc3_w(mcr, mcr_pack(0, 500)); - nic_wait(ioc3); - - return presence; -} - -static inline int -nic_read_bit(struct ioc3 *ioc3) -{ - int result; - - ioc3_w(mcr, mcr_pack(6, 13)); - result = nic_wait(ioc3); - ioc3_w(mcr, mcr_pack(0, 100)); - nic_wait(ioc3); - - return result; -} - -static inline void -nic_write_bit(struct ioc3 *ioc3, int bit) -{ - if (bit) - ioc3_w(mcr, mcr_pack(6, 110)); - else - ioc3_w(mcr, mcr_pack(80, 30)); - - nic_wait(ioc3); -} - /* - * Read a byte from an iButton device + * Get the ether-address */ -static u32 -nic_read_byte(struct ioc3 *ioc3) -{ - u32 result = 0; - int i; - - for (i = 0; i < 8; i++) - result = (result >> 1) | (nic_read_bit(ioc3) << 7); - - return result; -} - -/* - * Write a byte to an iButton device - */ -static void -nic_write_byte(struct ioc3 *ioc3, int byte) -{ - int i, bit; - - for (i = 8; i; i--) { - bit = byte & 1; - byte >>= 1; - - nic_write_bit(ioc3, bit); - } -} - -static u64 -nic_find(struct ioc3 *ioc3, int *last) -{ - int a, b, index, disc; - u64 address = 0; - - nic_reset(ioc3); - /* Search ROM. */ - nic_write_byte(ioc3, 0xf0); - - /* Algorithm from ``Book of iButton Standards''. */ - for (index = 0, disc = 0; index < 64; index++) { - a = nic_read_bit(ioc3); - b = nic_read_bit(ioc3); - - if (a && b) { - printk("NIC search failed (not fatal).\n"); - *last = 0; - return 0; - } - - if (!a && !b) { - if (index == *last) { - address |= 1UL << index; - } else if (index > *last) { - address &= ~(1UL << index); - disc = index; - } else if ((address & (1UL << index)) == 0) - disc = index; - nic_write_bit(ioc3, address & (1UL << index)); - continue; - } else { - if (a) - address |= 1UL << index; - else - address &= ~(1UL << index); - nic_write_bit(ioc3, a); - continue; - } - } - - *last = disc; - - return address; -} - -static int nic_init(struct ioc3 *ioc3) -{ - const char *type; - u8 crc; - u8 serial[6]; - int save = 0, i; - - type = "unknown"; - - while (1) { - u64 reg; - reg = nic_find(ioc3, &save); - - switch (reg & 0xff) { - case 0x91: - type = "DS1981U"; - break; - default: - if (save == 0) { - /* Let the caller try again. */ - return -1; - } - continue; - } - - nic_reset(ioc3); - - /* Match ROM. */ - nic_write_byte(ioc3, 0x55); - for (i = 0; i < 8; i++) - nic_write_byte(ioc3, (reg >> (i << 3)) & 0xff); - - reg >>= 8; /* Shift out type. */ - for (i = 0; i < 6; i++) { - serial[i] = reg & 0xff; - reg >>= 8; - } - crc = reg & 0xff; - break; - } - - printk("Found %s NIC", type); - if (type != "unknown") { - printk (" registration number %02x:%02x:%02x:%02x:%02x:%02x," - " CRC %02x", serial[0], serial[1], serial[2], - serial[3], serial[4], serial[5], crc); - } - printk(".\n"); - - return 0; -} - -/* - * Read the NIC (Number-In-a-Can) device used to store the MAC address on - * SN0 / SN00 nodeboards and PCI cards. - */ -static void ioc3_get_eaddr_nic(struct ioc3_private *ip) -{ - struct ioc3 *ioc3 = ip->regs; - u8 nic[14]; - int tries = 2; /* There may be some problem with the battery? */ - int i; - - ioc3_w(gpcr_s, (1 << 21)); - - while (tries--) { - if (!nic_init(ioc3)) - break; - udelay(500); - } - - if (tries < 0) { - printk("Failed to read MAC address\n"); - return; - } - - /* Read Memory. */ - nic_write_byte(ioc3, 0xf0); - nic_write_byte(ioc3, 0x00); - nic_write_byte(ioc3, 0x00); - - for (i = 13; i >= 0; i--) - nic[i] = nic_read_byte(ioc3); - - for (i = 2; i < 8; i++) - ip->dev->dev_addr[i - 2] = nic[i]; -} - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2) -/* - * Get the ether-address on SN1 nodes - */ -static void ioc3_get_eaddr_sn(struct ioc3_private *ip) +static void ioc3_get_eaddr(struct ioc3_private *ip) { int ibrick_mac_addr_get(nasid_t, char *); struct ioc3 *ioc3 = ip->regs; nasid_t nasid_of_ioc3; char io7eaddr[20]; long mac; - int err_val; + int err_val, i; /* * err_val = ibrick_mac_addr_get(get_nasid(), io7eaddr ); @@ -450,40 +247,10 @@ ip->dev->dev_addr[4] = (mac >> 8) & 0xff; ip->dev->dev_addr[5] = mac & 0xff; } -} -#endif - -/* - * Ok, this is hosed by design. It's necessary to know what machine the - * NIC is in in order to know how to read the NIC address. We also have - * to know if it's a PCI card or a NIC in on the node board ... - */ -static void ioc3_get_eaddr(struct ioc3_private *ip) -{ - void (*do_get_eaddr)(struct ioc3_private *ip) = NULL; - int i; - - /* - * We should also use this code for PCI cards, no matter what host - * machine but how to know that we're a PCI card? - */ -#ifdef CONFIG_SGI_IP27 - do_get_eaddr = ioc3_get_eaddr_nic; -#endif -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2) - do_get_eaddr = ioc3_get_eaddr_sn; -#endif - - if (!do_get_eaddr) { - printk(KERN_ERR "Don't know how to read MAC address of this " - "IOC3 NIC\n"); - return; - } - printk("Ethernet address is "); for (i = 0; i < 6; i++) { printk("%02x", ip->dev->dev_addr[i]); - if (i < 7) + if (i < 5) printk(":"); } printk(".\n"); @@ -521,7 +288,7 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev) { - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = (struct ioc3_private *) dev->priv; struct ioc3 *ioc3 = ip->regs; ip->stats.collisions += (ioc3->etcdc & ETCDC_COLLCNT_MASK); @@ -588,8 +355,8 @@ ip->stats.rx_frame_errors++; next: ip->rx_skbs[n_entry] = new_skb; - rxr[n_entry] = cpu_to_be32((0xa5UL << 56) | - ((unsigned long) rxb & TO_PHYS_MASK)); + rxr[n_entry] = cpu_to_be64((ip->dma_attributes) | + ((unsigned long) rxb & TO_PHYS_MASK)); rxb->w0 = 0; /* Clear valid flag */ n_entry = (n_entry + 1) & 511; /* Update erpir */ @@ -1278,8 +1045,6 @@ /* Allocate and initialize rx ring. 4kb = 512 entries */ ip->rxr = (unsigned long *) get_free_page(GFP_ATOMIC); rxr = (unsigned long *) ip->rxr; - if (!rxr) - printk("ioc3_alloc_rings(): get_free_page() failed!\n"); /* Now the rx buffers. The RX ring may be larger but we only allocate 16 buffers for now. Need to tune @@ -1299,7 +1064,7 @@ /* Because we reserve afterwards. */ skb_put(skb, (1664 + RX_OFFSET)); rxb = (struct ioc3_erxbuf *) skb->data; - rxr[i] = cpu_to_be64((0xa5UL << 56) | + rxr[i] = cpu_to_be64((ip->dma_attributes) | ((unsigned long) rxb & TO_PHYS_MASK)); skb_reserve(skb, RX_OFFSET); } @@ -1309,9 +1074,7 @@ if (ip->txr == NULL) { /* Allocate and initialize tx rings. 16kb = 128 bufs. */ - ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2); - if (!ip->txr) - printk("ioc3_alloc_rings(): get_free_page() failed!\n"); + ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_ATOMIC, 2); ip->tx_pi = 0; ip->tx_ci = 0; } @@ -1330,13 +1093,13 @@ ioc3_clean_tx_ring(ip); /* Now the rx ring base, consume & produce registers. */ - ring = (0xa5UL << 56) | ((unsigned long)ip->rxr & TO_PHYS_MASK); + ring = (ip->dma_attributes) | ((unsigned long)ip->rxr & TO_PHYS_MASK); ioc3->erbr_h = ring >> 32; ioc3->erbr_l = ring & 0xffffffff; ioc3->ercir = (ip->rx_ci << 3); ioc3->erpir = (ip->rx_pi << 3) | ERPIR_ARM; - ring = (0xa5UL << 56) | ((unsigned long)ip->txr & TO_PHYS_MASK); + ring = (ip->dma_attributes) | ((unsigned long)ip->txr & TO_PHYS_MASK); ip->txqlen = 0; /* nothing queued */ @@ -1372,6 +1135,38 @@ } } +static void ioc3_phyreset(struct net_device *dev) +{ + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; + + /* + * phyunreset() + */ + ioc3->gpcr_s = GPCR_PHY_RESET; + ioc3->gpcr_s; + ioc3->gppr_5 = 1; + ioc3->gppr_5; + + /* + * phyreset() + */ + ioc3->gppr_5 = 0; + ioc3->gppr_5; + ioc3->gppr_5 = 1; + ioc3->gppr_5; + + /* #ifdef Colin */ + { + int rval, wval; + rval = mii_read(ip, MII_DCOUNTER); + wval = (rval & ~(1<<5)) | (1<<5); + mii_write(ip, MII_DCOUNTER, (u16) wval); + } + /* #endif */ + +} + static void ioc3_init(struct ioc3_private *ip) { struct net_device *dev = ip->dev; @@ -1381,16 +1176,40 @@ ioc3->emcr = EMCR_RST; /* Reset */ ioc3->emcr; /* Flush WB */ - udelay(4); /* Give it time ... */ + while ( ((ioc3->emcr) & EMCR_ARB_DIAG_IDLE) == 0) { + printk("Waiting for EMCR_ARB_DIAG_IDLE ..\n"); + udelay(4); + } + ioc3->emcr = 0; ioc3->emcr; + /* + * Errata from IOC3 4.4 spec, + * must explicitly clear tx/rx consume and produce pointers. + */ + ioc3->etcir = 0; + ioc3->ercir = 0; + ioc3->etpir = 0; + ioc3->erpir = 0; + /* Misc registers */ ioc3->erbar = 0; + /* irix (sn) sets it this way..we don't really have to + * while we do all dma's with barrier set (i.e. bit 56 in + * dma address) + */ + ioc3->erbar = (int)(PCI64_ATTR_BAR >> 32); ioc3->etcsr = (17<etcdc; /* Clear on read */ ioc3->ercsr = 15; /* RX low watermark */ ioc3->ertr = 0; /* Interrupt immediately */ +/* + * This is a tradeoff between altency and bandwidth; we mostly + * choose bandwidth for now. This should be figured out dynamically as + * on IRIX; at this time no Linux driver does it however. + */ +ioc3->ertr = 100; ioc3->emar_h = (dev->dev_addr[5] << 8) | dev->dev_addr[4]; ioc3->emar_l = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | dev->dev_addr[0]; @@ -1414,6 +1233,7 @@ struct ioc3 *ioc3 = ip->regs; ioc3->emcr = 0; /* Shutup */ + ioc3->emcr; ioc3->eier = 0; /* Disable interrupts */ ioc3->eier; /* Flush */ } @@ -1421,7 +1241,7 @@ static int ioc3_open(struct net_device *dev) { - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip; if (request_irq(dev->irq, ioc3_interrupt, SA_SHIRQ, ioc3_str, dev)) { printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq); @@ -1429,6 +1249,8 @@ return -EAGAIN; } + ip = (struct ioc3_private *) dev->priv; + ip->ehar_h = 0; ip->ehar_l = 0; ioc3_init(ip); @@ -1453,67 +1275,8 @@ return 0; } -/* - * MENET cards have four IOC3 chips, which are attached to two sets of - * PCI slot resources each: the primary connections are on slots - * 0..3 and the secondaries are on 4..7 - * - * All four ethernets are brought out to connectors; six serial ports - * (a pair from each of the first three IOC3s) are brought out to - * MiniDINs; all other subdevices are left swinging in the wind, leave - * them disabled. - */ -static inline int ioc3_is_menet(struct pci_dev *pdev) -{ - struct pci_dev *dev; - - return pdev->bus->parent == NULL - && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(0, 0))) - && dev->vendor == PCI_VENDOR_ID_SGI - && dev->device == PCI_DEVICE_ID_SGI_IOC3 - && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(1, 0))) - && dev->vendor == PCI_VENDOR_ID_SGI - && dev->device == PCI_DEVICE_ID_SGI_IOC3 - && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(2, 0))) - && dev->vendor == PCI_VENDOR_ID_SGI - && dev->device == PCI_DEVICE_ID_SGI_IOC3; -} - -static void inline ioc3_serial_probe(struct pci_dev *pdev, - struct ioc3 *ioc3) -{ - struct serial_struct req; - - /* - * We need to recognice and treat the fourth MENET serial as it - * does not have an SuperIO chip attached to it, therefore attempting - * to access it will result in bus errors. We call something an - * MENET if PCI slot 0, 1, 2 and 3 of a master PCI bus all have an IOC3 - * in it. This is paranoid but we want to avoid blowing up on a - * showhorn PCI box that happens to have 4 IOC3 cards in it so it's - * not paranoid enough ... - */ - if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3) - return; - - /* Register to interrupt zero because we share the interrupt with - the serial driver which we don't properly support yet. */ - memset(&req, 0, sizeof(req)); - req.irq = 0; - req.flags = IOC3_COM_FLAGS; - req.io_type = SERIAL_IO_MEM; - req.iomem_reg_shift = 0; - req.baud_base = IOC3_BAUD; - - req.iomem_base = (unsigned char *) &ioc3->sregs.uarta; - register_serial(&req); - - req.iomem_base = (unsigned char *) &ioc3->sregs.uartb; - register_serial(&req); -} - static int __devinit ioc3_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { struct net_device *dev = NULL; struct ioc3_private *ip; @@ -1532,12 +1295,50 @@ SET_MODULE_OWNER(dev); ip = dev->priv; + + memset(ip, 0, sizeof(*ip)); ip->dev = dev; + ip->pdev = pdev; + +{ + void *tempvirtaddr = NULL; + dma_addr_t tempdmaaddr = (dma_addr_t) NULL; + struct sn_device_sysdata *device_sysdata = pdev->sysdata; + + /* + * IOC3 ethernet driver has been coded to do DMA in Big + * Endian. The current DMA interfaces for SN1 assumes that + * all DMA are targeted to Little Endian(Swap attribute on). + * + * The other problem is that we need to make sure that the + * IOC3 Ethernet driver is functional irrespective of whether + * the IO device is connected via Port A or Port B. + * + * I am reluctant to do the "RIGHT" thing here for now because + * it would mean a much greater effort in a driver that I do not + * have much knowlwdge - Colin Ngam. + */ + tempvirtaddr = kmalloc(1, GFP_KERNEL); + if (!tempvirtaddr) { + printk("ioc3_pci_init: Failed to get DMA address attributes\n"); + return -1; + } + tempdmaaddr = pciio_dmatrans_addr(device_sysdata->vhdl, NULL, __pa(tempvirtaddr), 1, PCIIO_BYTE_STREAM | PCIBR_BARRIER | PCIIO_DMA_CMD | PCIIO_DMA_A64); + ip->dma_attributes = 0xff00000000000000 & (unsigned long) tempdmaaddr; + kfree(tempvirtaddr); +} + + /* + * This probably needs to be register_netdevice, or call + * init_etherdev so that it calls register_netdevice. Quick + * hack for now. + */ + netif_device_attach(dev); dev->irq = pdev->irq; - ioc3_base = pci_resource_start(pdev, 0); - ioc3_size = pci_resource_len(pdev, 0); + ioc3_base = pdev->resource[0].start; + ioc3_size = pdev->resource[0].end - ioc3_base; ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size); if (!ioc3) { printk(KERN_CRIT "ioc3eth(%s): ioremap failed, goodbye.\n", @@ -1547,13 +1348,11 @@ } ip->regs = ioc3; -#ifdef CONFIG_SERIAL - ioc3_serial_probe(pdev, ioc3); -#endif - spin_lock_init(&ip->ioc3_lock); ioc3_stop(ip); + ip->emcr = 0; + ioc3_phyreset(dev); ioc3_init(ip); init_timer(&ip->ioc3_timer); @@ -1561,7 +1360,7 @@ if (ip->phy == -1) { printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n", - pdev->slot_name); + dev->name); err = -ENODEV; goto out_stop; } @@ -1677,15 +1476,15 @@ ETXD_B1V | ETXD_B2V); desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) | (s2 << ETXD_B2CNT_SHIFT)); - desc->p1 = cpu_to_be64((0xa5UL << 56) | + desc->p1 = cpu_to_be64((ip->dma_attributes) | (data & TO_PHYS_MASK)); - desc->p2 = cpu_to_be64((0xa5UL << 56) | + desc->p2 = cpu_to_be64((ip->dma_attributes) | (data & TO_PHYS_MASK)); } else { /* Normal sized packet that doesn't cross a page boundary. */ desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V); desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT); - desc->p1 = cpu_to_be64((0xa5UL << 56) | + desc->p1 = cpu_to_be64((ip->dma_attributes) | (data & TO_PHYS_MASK)); } @@ -1750,7 +1549,7 @@ /* We provide both the mii-tools and the ethtool ioctls. */ static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct ioc3_private *ip = dev->priv; + struct ioc3_private *ip = (struct ioc3_private *) dev->priv; struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data; u16 *data = (u16 *)&rq->ifr_data; struct ioc3 *ioc3 = ip->regs; diff -Nur linux-2.4.19/drivers/net/simeth.c linux-2.4.19-sgi211r3/drivers/net/simeth.c --- linux-2.4.19/drivers/net/simeth.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/net/simeth.c Tue Jan 8 17:05:38 2002 @@ -0,0 +1,533 @@ +/* + * Simulated Ethernet Driver + * + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 Stephane Eranain + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIMETH_RECV_MAX 10 + +/* + * Maximum possible received frame for Ethernet. + * We preallocate an sk_buff of that size to avoid costly + * memcpy for temporary buffer into sk_buff. We do basically + * what's done in other drivers, like eepro with a ring. + * The difference is, of course, that we don't have real DMA !!! + */ +#define SIMETH_FRAME_SIZE ETH_FRAME_LEN + + +#define SSC_NETDEV_PROBE 100 +#define SSC_NETDEV_SEND 101 +#define SSC_NETDEV_RECV 102 +#define SSC_NETDEV_ATTACH 103 +#define SSC_NETDEV_DETACH 104 + +#define NETWORK_INTR 8 + +struct simeth_local { + struct net_device_stats stats; + int simfd; /* descriptor in the simulator */ +}; + +static int simeth_probe1(void); +static int simeth_open(struct net_device *dev); +static int simeth_close(struct net_device *dev); +static int simeth_tx(struct sk_buff *skb, struct net_device *dev); +static int simeth_rx(struct net_device *dev); +static struct net_device_stats *simeth_get_stats(struct net_device *dev); +static void simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static void set_multicast_list(struct net_device *dev); +static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr); + +static char *simeth_version="0.3"; + +/* + * This variable is used to establish a mapping between the Linux/ia64 kernel + * and the host linux kernel. + * + * As of today, we support only one card, even though most of the code + * is ready for many more. The mapping is then: + * linux/ia64 -> linux/x86 + * eth0 -> eth1 + * + * In the future, we some string operations, we could easily support up + * to 10 cards (0-9). + * + * The default mapping can be changed on the kernel command line by + * specifying simeth=ethX (or whatever string you want). + */ +static char *simeth_device="eth0"; /* default host interface to use */ + + + +static volatile unsigned int card_count; /* how many cards "found" so far */ +static int simeth_debug; /* set to 1 to get debug information */ + +/* + * Used to catch IFF_UP & IFF_DOWN events + */ +static struct notifier_block simeth_dev_notifier = { + simeth_device_event, + 0 +}; + + +/* + * Function used when using a kernel command line option. + * + * Format: simeth=interface_name (like eth0) + */ +static int __init +simeth_setup(char *str) +{ + simeth_device = str; + return 1; +} + +__setup("simeth=", simeth_setup); + +/* + * Function used to probe for simeth devices when not installed + * as a loadable module + */ + +int __init +simeth_probe (void) +{ + int r; + + printk("simeth: v%s\n", simeth_version); + + r = simeth_probe1(); + + if (r == 0) register_netdevice_notifier(&simeth_dev_notifier); + + return r; +} + +extern long ia64_ssc (long, long, long, long, int); +extern void ia64_ssc_connect_irq (long intr, long irq); + +static inline int +netdev_probe(char *name, unsigned char *ether) +{ + return ia64_ssc(__pa(name), __pa(ether), 0,0, SSC_NETDEV_PROBE); +} + + +static inline int +netdev_connect(int irq) +{ + /* XXX Fix me + * this does not support multiple cards + * also no return value + */ + ia64_ssc_connect_irq(NETWORK_INTR, irq); + return 0; +} + +static inline int +netdev_attach(int fd, int irq, unsigned int ipaddr) +{ + /* this puts the host interface in the right mode (start interupting) */ + return ia64_ssc(fd, ipaddr, 0,0, SSC_NETDEV_ATTACH); +} + + +static inline int +netdev_detach(int fd) +{ + /* + * inactivate the host interface (don't interrupt anymore) */ + return ia64_ssc(fd, 0,0,0, SSC_NETDEV_DETACH); +} + +static inline int +netdev_send(int fd, unsigned char *buf, unsigned int len) +{ + return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_SEND); +} + +static inline int +netdev_read(int fd, unsigned char *buf, unsigned int len) +{ + return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV); +} + +/* + * Function shared with module code, so cannot be in init section + * + * So far this function "detects" only one card (test_&_set) but could + * be extended easily. + * + * Return: + * - -ENODEV is no device found + * - -ENOMEM is no more memory + * - 0 otherwise + */ +static int +simeth_probe1(void) +{ + unsigned char mac_addr[ETH_ALEN]; + struct simeth_local *local; + struct net_device *dev; + int fd, i; + + /* + * XXX Fix me + * let's support just one card for now + */ + if (test_and_set_bit(0, &card_count)) + return -ENODEV; + + /* + * check with the simulator for the device + */ + fd = netdev_probe(simeth_device, mac_addr); + if (fd == -1) + return -ENODEV; + + dev = init_etherdev(NULL, sizeof(struct simeth_local)); + if (!dev) + return -ENOMEM; + + memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); + + dev->irq = ia64_alloc_irq(); + + /* + * attach the interrupt in the simulator, this does enable interrupts + * until a netdev_attach() is called + */ + netdev_connect(dev->irq); + + memset(dev->priv, 0, sizeof(struct simeth_local)); + + local = dev->priv; + local->simfd = fd; /* keep track of underlying file descriptor */ + + dev->open = simeth_open; + dev->stop = simeth_close; + dev->hard_start_xmit = simeth_tx; + dev->get_stats = simeth_get_stats; + dev->set_multicast_list = set_multicast_list; /* no yet used */ + + /* Fill in the fields of the device structure with ethernet-generic values. */ + ether_setup(dev); + + printk("%s: hosteth=%s simfd=%d, HwAddr", dev->name, simeth_device, local->simfd); + for(i = 0; i < ETH_ALEN; i++) { + printk(" %2.2x", dev->dev_addr[i]); + } + printk(", IRQ %d\n", dev->irq); + + return 0; +} + +/* + * actually binds the device to an interrupt vector + */ +static int +simeth_open(struct net_device *dev) +{ + if (request_irq(dev->irq, simeth_interrupt, 0, "simeth", dev)) { + printk ("simeth: unable to get IRQ %d.\n", dev->irq); + return -EAGAIN; + } + + netif_start_queue(dev); + + return 0; +} + +/* copied from lapbether.c */ +static __inline__ int dev_is_ethdev(struct net_device *dev) +{ + return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5)); +} + + +/* + * Handler for IFF_UP or IFF_DOWN + * + * The reason for that is that we don't want to be interrupted when the + * interface is down. There is no way to unconnect in the simualtor. Instead + * we use this function to shutdown packet processing in the frame filter + * in the simulator. Thus no interrupts are generated + * + * + * That's also the place where we pass the IP address of this device to the + * simulator so that that we can start filtering packets for it + * + * There may be a better way of doing this, but I don't know which yet. + */ +static int +simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) +{ + struct net_device *dev = (struct net_device *)ptr; + struct simeth_local *local; + struct in_device *in_dev; + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + int r; + + + if ( ! dev ) { + printk(KERN_WARNING "simeth_device_event dev=0\n"); + return NOTIFY_DONE; + } + + if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; + + /* + * Check whether or not it's for an ethernet device + * + * XXX Fixme: This works only as long as we support one + * type of ethernet device. + */ + if ( !dev_is_ethdev(dev) ) return NOTIFY_DONE; + + if ((in_dev=dev->ip_ptr) != NULL) { + for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) + if (strcmp(dev->name, ifa->ifa_label) == 0) break; + } + if ( ifa == NULL ) { + printk("simeth_open: can't find device %s's ifa\n", dev->name); + return NOTIFY_DONE; + } + + printk("simeth_device_event: %s ipaddr=0x%x\n", dev->name, htonl(ifa->ifa_local)); + + /* + * XXX Fix me + * if the device was up, and we're simply reconfiguring it, not sure + * we get DOWN then UP. + */ + + local = dev->priv; + /* now do it for real */ + r = event == NETDEV_UP ? + netdev_attach(local->simfd, dev->irq, htonl(ifa->ifa_local)): + netdev_detach(local->simfd); + + printk("simeth: netdev_attach/detach: event=%s ->%d\n", event == NETDEV_UP ? "attach":"detach", r); + + return NOTIFY_DONE; +} + +static int +simeth_close(struct net_device *dev) +{ + netif_stop_queue(dev); + + free_irq(dev->irq, dev); + + return 0; +} + +/* + * Only used for debug + */ +static void +frame_print(unsigned char *from, unsigned char *frame, int len) +{ + int i; + + printk("%s: (%d) %02x", from, len, frame[0] & 0xff); + for(i=1; i < 6; i++ ) { + printk(":%02x", frame[i] &0xff); + } + printk(" %2x", frame[6] &0xff); + for(i=7; i < 12; i++ ) { + printk(":%02x", frame[i] &0xff); + } + printk(" [%02x%02x]\n", frame[12], frame[13]); + + for(i=14; i < len; i++ ) { + printk("%02x ", frame[i] &0xff); + if ( (i%10)==0) printk("\n"); + } + printk("\n"); +} + + +/* + * Function used to transmit of frame, very last one on the path before + * going to the simulator. + */ +static int +simeth_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct simeth_local *local = (struct simeth_local *)dev->priv; + +#if 0 + /* ensure we have at least ETH_ZLEN bytes (min frame size) */ + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + /* Where do the extra padding bytes comes from inthe skbuff ? */ +#else + /* the real driver in the host system is going to take care of that + * or maybe it's the NIC itself. + */ + unsigned int length = skb->len; +#endif + + local->stats.tx_bytes += skb->len; + local->stats.tx_packets++; + + + if (simeth_debug > 5) frame_print("simeth_tx", skb->data, length); + + netdev_send(local->simfd, skb->data, length); + + /* + * we are synchronous on write, so we don't simulate a + * trasnmit complete interrupt, thus we don't need to arm a tx + */ + + dev_kfree_skb(skb); + return 0; +} + +static inline struct sk_buff * +make_new_skb(struct net_device *dev) +{ + struct sk_buff *nskb; + + /* + * The +2 is used to make sure that the IP header is nicely + * aligned (on 4byte boundary I assume 14+2=16) + */ + nskb = dev_alloc_skb(SIMETH_FRAME_SIZE + 2); + if ( nskb == NULL ) { + printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); + return NULL; + } + nskb->dev = dev; + + skb_reserve(nskb, 2); /* Align IP on 16 byte boundaries */ + + skb_put(nskb,SIMETH_FRAME_SIZE); + + return nskb; +} + +/* + * called from interrupt handler to process a received frame + */ +static int +simeth_rx(struct net_device *dev) +{ + struct simeth_local *local; + struct sk_buff *skb; + int len; + int rcv_count = SIMETH_RECV_MAX; + + local = (struct simeth_local *)dev->priv; + /* + * the loop concept has been borrowed from other drivers + * looks to me like it's a throttling thing to avoid pushing to many + * packets at one time into the stack. Making sure we can process them + * upstream and make forward progress overall + */ + do { + if ( (skb=make_new_skb(dev)) == NULL ) { + printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); + local->stats.rx_dropped++; + return 0; + } + /* + * Read only one frame at a time + */ + len = netdev_read(local->simfd, skb->data, SIMETH_FRAME_SIZE); + if ( len == 0 ) { + if ( simeth_debug > 0 ) printk(KERN_WARNING "%s: count=%d netdev_read=0\n", dev->name, SIMETH_RECV_MAX-rcv_count); + break; + } +#if 0 + /* + * XXX Fix me + * Should really do a csum+copy here + */ + memcpy(skb->data, frame, len); +#endif + skb->protocol = eth_type_trans(skb, dev); + + if ( simeth_debug > 6 ) frame_print("simeth_rx", skb->data, len); + + /* + * push the packet up & trigger software interrupt + */ + netif_rx(skb); + + local->stats.rx_packets++; + local->stats.rx_bytes += len; + + } while ( --rcv_count ); + + return len; /* 0 = nothing left to read, otherwise, we can try again */ +} + +/* + * Interrupt handler (Yes, we can do it too !!!) + */ +static void +simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + + if ( dev == NULL ) { + printk(KERN_WARNING "simeth: irq %d for unknown device\n", irq); + return; + } + + /* + * very simple loop because we get interrupts only when receving + */ + while (simeth_rx(dev)); +} + +static struct net_device_stats * +simeth_get_stats(struct net_device *dev) +{ + struct simeth_local *local = (struct simeth_local *) dev->priv; + + return &local->stats; +} + +/* fake multicast ability */ +static void +set_multicast_list(struct net_device *dev) +{ + printk(KERN_WARNING "%s: set_multicast_list called\n", dev->name); +} + +#ifdef CONFIG_NET_FASTROUTE +static int +simeth_accept_fastpath(struct net_device *dev, struct dst_entry *dst) +{ + printk(KERN_WARNING "%s: simeth_accept_fastpath called\n", dev->name); + return -1; +} +#endif + +__initcall(simeth_probe); diff -Nur linux-2.4.19/drivers/net/slip.c linux-2.4.19-sgi211r3/drivers/net/slip.c --- linux-2.4.19/drivers/net/slip.c Mon Feb 25 11:37:59 2002 +++ linux-2.4.19-sgi211r3/drivers/net/slip.c Mon Oct 28 20:43:23 2002 @@ -1393,10 +1393,8 @@ /* First of all: check for active disciplines and hangup them. */ do { - if (busy) { - current->counter = 0; - schedule(); - } + if (busy) + sys_sched_yield(); busy = 0; local_bh_disable(); diff -Nur linux-2.4.19/drivers/net/tg3.c linux-2.4.19-sgi211r3/drivers/net/tg3.c --- linux-2.4.19/drivers/net/tg3.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/tg3.c Fri Jan 10 09:02:35 2003 @@ -33,6 +33,16 @@ #define PCI_DMA_BUS_IS_PHYS 1 #endif +#ifdef CONFIG_IA64_SGI_SN +unsigned long flush_base = 0; +#ifdef BUS_INT_WAR +static struct net_device *root_dev; +void sn_add_polled_interrupt(int irq, int interval); +void sn_delete_polled_interrupt(int irq); +#endif /* BUS_INT_WAR */ +#endif /* CONFIG_IA64_SGI_SN */ + + /* Either I can't figure out how they secretly implemented it (ie. RXD flags * for mini ring, where it should go in NIC sram, and how many entries the NIC * firmware expects) or it isn't really fully implemented. Perhaps Broadcom @@ -133,7 +143,14 @@ static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ +/* SGI - Added SGI Device ID data - No #ifdef CONFIG_IA64_SGI_SN required here */ static struct pci_device_id tg3_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IO9_ETH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_570XC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_570XF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701, @@ -154,6 +171,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { 0, } }; @@ -173,10 +192,20 @@ } } +#ifdef CONFIG_IA64_SGI_SN +#define twf32_mailbox(reg, val) writel(((val) & 0xffffffff), tp->regs + (reg)); \ + barrier(); \ + readl(flush_base); \ + mb(); +#define twf32(reg,val) tg3_write_indirect_reg32(tp,(reg),(val)); \ + barrier(); \ + readl(flush_base); \ + mb(); +#endif /* CONFIG_IA64_SGI_SN */ #define tw32(reg,val) tg3_write_indirect_reg32(tp,(reg),(val)) -#define tw32_mailbox(reg, val) writel(((val) & 0xffffffff), tp->regs + (reg)) -#define tw16(reg,val) writew(((val) & 0xffff), tp->regs + (reg)) -#define tw8(reg,val) writeb(((val) & 0xff), tp->regs + (reg)) +#define tw32_mailbox(reg, val) writel(((val) & 0xffffffff), tp->regs + (reg)) +#define tw16(reg,val) writew(((val) & 0xffff), tp->regs + (reg)) +#define tw8(reg,val) writeb(((val) & 0xff), tp->regs + (reg)) #define tr32(reg) readl(tp->regs + (reg)) #define tr16(reg) readw(tp->regs + (reg)) #define tr8(reg) readb(tp->regs + (reg)) @@ -1554,7 +1583,11 @@ int i; if (unlikely(skb == NULL)) +#ifdef CONFIG_IA64_SGI_SN + return; +#else BUG(); +#endif pci_unmap_single(tp->pdev, pci_unmap_addr(ri, mapping), @@ -2037,17 +2070,31 @@ spin_lock(&tp->lock); +#ifdef CONFIG_IA64_SGI_SN + tp->in_isr = 1; +#endif + while (sblk->status & SD_STATUS_UPDATED) { +#ifdef CONFIG_IA64_SGI_SN + twf32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000001); +#else tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); +#endif sblk->status &= ~SD_STATUS_UPDATED; tg3_interrupt_main_work(tp); + } +#ifdef CONFIG_IA64_SGI_SN + twf32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); + tp->in_isr = 0; +#else tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - 0x00000000); - tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); - } + 0x00000000); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); +#endif /* CONFIG_IA64_SGI_SN */ spin_unlock(&tp->lock); } @@ -2060,6 +2107,26 @@ spin_lock(&tp->lock); +#ifdef CONFIG_IA64_SGI_SN + tp->in_isr = 1; +#endif + + if(!( sblk->status & SD_STATUS_UPDATED)) { + u32 oldtag; + + oldtag = sblk->status_tag; +#ifdef CONFIG_IA64_SGI_SN + twf32_mailbox(MAILBOX_INTERRUPT_0 + + TG3_64BIT_REG_LOW, + oldtag << 24); +#else + tw32_mailbox(MAILBOX_INTERRUPT_0 + + TG3_64BIT_REG_LOW, + oldtag << 24); +#endif + goto tg3idone; + } + if (sblk->status & SD_STATUS_UPDATED) { u32 oldtag; @@ -2077,15 +2144,26 @@ newtag = sblk->status_tag; if (newtag == oldtag) { +#ifdef CONFIG_IA64_SGI_SN + twf32_mailbox(MAILBOX_INTERRUPT_0 + + TG3_64BIT_REG_LOW, + newtag << 24); +#else tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, newtag << 24); +#endif break; } oldtag = newtag; } } +tg3idone: +#ifdef CONFIG_IA64_SGI_SN + tp->in_isr = 0; +#endif + spin_unlock(&tp->lock); } @@ -2267,7 +2345,13 @@ #if TG3_VLAN_TAG_USED writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG); #endif +#ifdef CONFIG_IA64_SGI_SN + barrier(); + readl(flush_base); + mb(); +#endif /* CONFIG_IA64_SGI_SN */ } + } static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) @@ -2537,7 +2621,7 @@ tg3_init_rings(tp); tg3_init_hw(tp); - + spin_unlock_irq(&tp->lock); return 0; @@ -2988,6 +3072,7 @@ } tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET); + udelay(40); udelay(40); udelay(40); @@ -3620,6 +3705,19 @@ /* Receive rules. */ tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS); + +#ifdef CONFIG_IA64_SGI_SN + + /* Reg offset 0x504 + * Set the low water mark maximum receive frames register + * to prevent flow control from dropping packets on the wire + * or that have not yet been sent yet from the other side. + */ + + tw32(MAX_RCV_LOW_WATER_FRAMES, MAX_RCV_WATER_FRAMES_DEFAULT); + +#endif /* CONFIG_IA64_SGI_SN */ + tw32(RCVLPC_CONFIG, 0x0181); /* Receive/send statistics. */ @@ -3812,11 +3910,21 @@ * the cpu is race prone. */ if (tp->hw_status->status & SD_STATUS_UPDATED) { +#ifdef CONFIG_IA64_SGI_SN + twf32(GRC_LOCAL_CTRL, + tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); +#else tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); +#endif } else { +#ifdef CONFIG_IA64_SGI_SN + twf32(HOSTCC_MODE, + (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); +#else tw32(HOSTCC_MODE, (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); +#endif } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { @@ -3864,7 +3972,13 @@ tg3_setup_phy(tp); } } - +#ifdef CONFIG_IA64_SGI_SN + /* Catch missed interrupts */ + if (!(tp->in_isr)) { + tg3_interrupt_main_work(tp); + twf32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); + } +#endif tp->timer_counter = tp->timer_multiplier; } @@ -3951,6 +4065,14 @@ spin_unlock_irq(&tp->lock); +#ifdef CONFIG_IA64_SGI_SN +#ifdef BUS_INT_WAR + root_dev = dev; + sn_add_polled_interrupt(root_dev->irq, 1); +#endif /* BUS_INT_WAR */ +#endif /* CONFIG_IA64_SGI_SN */ + + return 0; } @@ -4225,6 +4347,11 @@ spin_unlock_irq(&tp->lock); +#ifdef BUS_INT_WAR + if (root_dev) + sn_delete_polled_interrupt(root_dev->irq); + udelay(5000); +#endif free_irq(dev->irq, dev); memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev), @@ -4419,6 +4546,7 @@ spin_unlock_irq(&tp->lock); } +//#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,18)) #define TG3_REGDUMP_LEN (32 * 1024) static u8 *tg3_get_regs(struct tg3 *tp) @@ -5067,6 +5195,8 @@ return -EOPNOTSUPP; } +//#endif /* KERNEL_VERSION > 2.4.18 */ + static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -5075,8 +5205,10 @@ int err; switch(cmd) { +//#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,18)) case SIOCETHTOOL: return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data); +//#endif case SIOCGMIIPHY: data->phy_id = PHY_ADDR; @@ -5641,6 +5773,7 @@ tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB; } +#ifndef CONFIG_IA64_SGI_SN /* Only 5701 and later support tagged irq status mode. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) { tp->tg3_flags |= TG3_FLAG_TAGGED_IRQ_STATUS; @@ -5667,6 +5800,10 @@ tp->coalesce_mode = (HOSTCC_MODE_CLRTICK_RXBD | HOSTCC_MODE_CLRTICK_TXBD); } else { +#else + tp->tg3_flags &= ~(TG3_FLAG_TAGGED_IRQ_STATUS); +#endif + tp->coalesce_mode = 0; /* If not using tagged status, set the *_during_int @@ -5676,7 +5813,9 @@ tp->coalesce_config.rx_max_coalesced_frames_during_int_def = 0; tp->coalesce_config.tx_coalesce_ticks_during_int_def = 0; tp->coalesce_config.tx_max_coalesced_frames_during_int_def = 0; +#ifndef CONFIG_IA64_SGI_SN } +#endif if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) @@ -5731,8 +5870,12 @@ /* Determine if TX descriptors will reside in * main memory or in the chip SRAM. */ +#ifndef CONFIG_IA64_SGI_SN if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) tp->tg3_flags |= TG3_FLAG_HOST_TXDS; +#else + tp->tg3_flags |= TG3_FLAG_HOST_TXDS; +#endif /* Quick sanity check. Make sure we see an expected * value here. @@ -5947,6 +6090,7 @@ { dma_addr_t buf_dma; u32 *buf; + u32 lowm_rxfrm; int ret; buf = pci_alloc_consistent(tp->pdev, TEST_BUFFER_SIZE, &buf_dma); @@ -5957,6 +6101,8 @@ tw32(TG3PCI_CLOCK_CTRL, 0); +#ifndef CONFIG_IA64_SGI_SN + { if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) { tp->dma_rwctrl = (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | @@ -5981,7 +6127,7 @@ /* We don't do this on x86 because it seems to hurt performace. * It does help things on other platforms though. */ -#ifndef CONFIG_X86 +#ifndef CONFIG_X86 { u8 byte; int cacheline_size; @@ -6039,7 +6185,28 @@ break; }; } -#endif +#endif /* CONFIG_X86 */ + } +#else /* IS SGI CONFIG_IA64_SGI_SN */ + /* SGI PCIIO DMA preferred settings */ + tp->dma_rwctrl = (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | + (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) | + DMA_RWCTRL_ONE_DMA | + (DMA_RWCTRL_READ_BNDRY_128 | + (0xf << DMA_RWCTRL_MIN_DMA_SHIFT) | + DMA_RWCTRL_WRITE_BNDRY_128); + + /* SGI Conventional PCI Bus */ + if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) { + tp->dma_rwctrl |= (0x3 << DMA_RWCTRL_READ_WATER_SHIFT) | + (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT); + } else { + /* SGI PCI-X Bus */ + tp->dma_rwctrl |= (0x1 << DMA_RWCTRL_READ_WATER_SHIFT) | + (0x1 << DMA_RWCTRL_WRITE_WATER_SHIFT); + } + +#endif /* CONFIG_IA64_SGI_SN */ /* Remove this if it causes problems for some boards. */ tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT; @@ -6324,6 +6491,7 @@ spin_lock_init(&tp->indirect_lock); tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len); + if (tp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -6331,6 +6499,10 @@ goto err_out_free_dev; } +#ifdef CONFIG_IA64_SGI_SN + flush_base = tp->regs; +#endif /* CONFIG_IA64_SGI_SN */ + tg3_init_link_config(tp); tg3_init_coalesce_config(tp); @@ -6370,10 +6542,12 @@ } err = tg3_test_dma(tp); +#ifndef CONFIG_IA64_SGI_SN if (err) { printk(KERN_ERR PFX "DMA engine test failed, aborting.\n"); goto err_out_iounmap; } +#endif /* Tigon3 can do ipv4 only... and some chips have buggy * checksumming. @@ -6399,7 +6573,7 @@ */ pci_save_state(tp->pdev, tp->pci_cfg_state); - printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ", + printk(KERN_INFO "%s: SGI Gigabit Ethernet [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ", dev->name, tp->board_part_number, tp->pci_chip_rev_id, @@ -6414,6 +6588,20 @@ for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + +#ifdef CONFIG_IA64_SGI_SN +#ifdef SGIDEBUG + printk(KERN_INFO "%s: Tigon3 DEBUG-INFO \n%s: Tigon3 DEBUG-INFO \n%s: Tigon3 DEBUG-INFO ", + dev->name, + tg3reg_base, + dev->name, + tp, + dev->name, + dev); + + printk(KERN_ERR "\n%s: Tigon3 DEBUG-INFO \n", dev->name, tp->dma_rwctrl); +#endif /* SGIDEBUG */ +#endif /* CONFIG_IA64_SGI_SN */ return 0; diff -Nur linux-2.4.19/drivers/net/tg3.h linux-2.4.19-sgi211r3/drivers/net/tg3.h --- linux-2.4.19/drivers/net/tg3.h Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/tg3.h Fri Jan 10 09:02:35 2003 @@ -8,6 +8,16 @@ #ifndef _T3_H #define _T3_H +#if (LINUX_VERSION_CODE < 0x020412) +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME; +#define pci_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME) +#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL)) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL)) +#endif + + #define TG3_64BIT_REG_HIGH 0x00UL #define TG3_64BIT_REG_LOW 0x04UL @@ -449,6 +459,10 @@ #define MAC_RCV_RULE_CFG 0x00000500 #define RCV_RULE_CFG_DEFAULT_CLASS 0x00000008 /* 0x504 --> 0x590 unused */ +#ifdef CONFIG_IA64_SGI_SN +#define MAX_RCV_LOW_WATER_FRAMES 0x00000504 +#define MAX_RCV_WATER_FRAMES_DEFAULT 0x00000004 +#endif #define MAC_SERDES_CFG 0x00000590 #define MAC_SERDES_STAT 0x00000594 /* 0x598 --> 0x600 unused */ @@ -1895,6 +1909,9 @@ struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; +#ifdef CONFIG_IA64_SGI_SN + unsigned int in_isr; +#endif }; #endif /* !(_T3_H) */ diff -Nur linux-2.4.19/drivers/net/tulip/media.c linux-2.4.19-sgi211r3/drivers/net/tulip/media.c --- linux-2.4.19/drivers/net/tulip/media.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/net/tulip/media.c Wed Oct 16 14:02:58 2002 @@ -284,6 +284,10 @@ for (i = 0; i < init_length; i++) outl(init_sequence[i], ioaddr + CSR12); } + + (void) inl(ioaddr + CSR6); /* flush CSR12 writes */ + udelay(500); /* Give MII time to recover */ + tmp_info = get_u16(&misc_info[1]); if (tmp_info) tp->advertising[phy_num] = tmp_info | 1; diff -Nur linux-2.4.19/drivers/pci/pci.c linux-2.4.19-sgi211r3/drivers/pci/pci.c --- linux-2.4.19/drivers/pci/pci.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/pci/pci.c Wed Oct 16 14:02:58 2002 @@ -992,8 +992,14 @@ { unsigned int pos, reg, next; u32 l, sz; + u16 cmd; struct resource *res; + /* Disable I/O & memory decoding while we size the BARs. */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + for(pos=0; posresource[pos]; @@ -1059,6 +1065,8 @@ } res->name = dev->name; } + + pci_write_config_word(dev, PCI_COMMAND, cmd); } void __devinit pci_read_bridge_bases(struct pci_bus *child) @@ -1662,10 +1670,10 @@ switch (rqst) { case PM_SAVE_STATE: - error = pci_pm_save_state((u32)data); + error = pci_pm_save_state((unsigned long)data); break; case PM_SUSPEND: - error = pci_pm_suspend((u32)data); + error = pci_pm_suspend((unsigned long)data); break; case PM_RESUME: error = pci_pm_resume(); @@ -1983,16 +1991,16 @@ int map, block; if ((page = pool_find_page (pool, dma)) == 0) { - printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n", + printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (int) (dma & 0xffffffff)); + pool->name, vaddr, (unsigned long) dma); return; } #ifdef CONFIG_PCIPOOL_DEBUG if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (int) (dma & 0xffffffff)); + pool->name, vaddr, dma); return; } #endif diff -Nur linux-2.4.19/drivers/pci/pci.ids linux-2.4.19-sgi211r3/drivers/pci/pci.ids --- linux-2.4.19/drivers/pci/pci.ids Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/pci/pci.ids Thu Nov 7 08:44:57 2002 @@ -1530,6 +1530,7 @@ 2100 QLA2100 64-bit Fibre Channel Adapter 1077 0001 QLA2100 64-bit Fibre Channel Adapter 2200 QLA2200 + 1077 0002 QLA2200 2300 QLA2300 64-bit FC-AL Adapter 2312 QLA2312 Fibre Channel Adapter 1078 Cyrix Corporation @@ -1818,12 +1819,14 @@ 0001 Crosstalk to PCI Bridge 0002 Linc I/O controller 0003 IOC3 I/O controller + ff00 0000 SGI IOC3 I/O controller 0004 O2 MACE 0005 RAD Audio 0006 HPCEX 0007 RPCEX 0008 DiVO VIP 0009 Alteon Gigabit Ethernet + 10a9 8002 SGI Acenic Gigabit Ethernet 0010 AMP Video I/O 0011 GRIP 0012 SGH PSHAC GSN @@ -3882,6 +3885,7 @@ 1410 0104 Gigabit Ethernet-SX PCI Adapter 0002 AceNIC Gigabit Ethernet (Copper) 12ae 0002 Gigabit Ethernet-T (3C986-T) + 10a9 8002 SGI Acenic Gigabit Ethernet 12af TDK USA Corp 12b0 Jorge Scientific Corp 12b1 GammaLink @@ -4757,6 +4761,9 @@ 14e4 0007 NetXtreme BCM5701 1000BaseSX 14e4 0008 NetXtreme BCM5701 1000BaseTX 14e4 8008 NetXtreme BCM5701 1000BaseTX + 10a9 8010 SGI IO9 Gigabit Ethernet (Copper) + 10a9 8011 SGI Gigabit Ethernet (Copper) + 10a9 8012 SGI Gigabit Ethernet (Fiber) 1646 NetXtreme BCM5702 Gigabit Ethernet 0e11 00bb NC7760 1000BaseTX 1028 0126 NetXtreme BCM5702 1000BaseTX @@ -4769,6 +4776,7 @@ 14e4 000b NetXtreme BCM5703 1000BaseTX 14e4 8009 NetXtreme BCM5703 1000BaseTX 14e4 800a NetXtreme BCM5703 1000BaseTX + 10a9 8010 SGI IO9 Gigabit Ethernet (Copper) 164d NetXtreme BCM5702FE Gigabit Ethernet 16a6 NetXtreme BCM5702X Gigabit Ethernet 16a7 NetXtreme BCM5703X Gigabit Ethernet diff -Nur linux-2.4.19/drivers/pci/proc.c linux-2.4.19-sgi211r3/drivers/pci/proc.c --- linux-2.4.19/drivers/pci/proc.c Fri Nov 16 18:38:39 2001 +++ linux-2.4.19-sgi211r3/drivers/pci/proc.c Mon Oct 28 20:43:23 2002 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -21,8 +22,9 @@ static loff_t proc_bus_pci_lseek(struct file *file, loff_t off, int whence) { - loff_t new; + loff_t new = -1; + lock_kernel(); switch (whence) { case 0: new = off; @@ -33,9 +35,8 @@ case 2: new = PCI_CFG_SPACE_SIZE + off; break; - default: - return -EINVAL; } + unlock_kernel(); if (new < 0 || new > PCI_CFG_SPACE_SIZE) return -EINVAL; return (file->f_pos = new); diff -Nur linux-2.4.19/drivers/pnp/isapnp_proc.c linux-2.4.19-sgi211r3/drivers/pnp/isapnp_proc.c --- linux-2.4.19/drivers/pnp/isapnp_proc.c Wed Jan 17 13:29:14 2001 +++ linux-2.4.19-sgi211r3/drivers/pnp/isapnp_proc.c Mon Oct 28 20:43:23 2002 @@ -84,18 +84,26 @@ static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig) { + loff_t ret; + + lock_kernel(); + switch (orig) { case 0: /* SEEK_SET */ file->f_pos = offset; - return file->f_pos; + ret = file->f_pos; + break; case 1: /* SEEK_CUR */ file->f_pos += offset; - return file->f_pos; + ret = file->f_pos; + break; case 2: /* SEEK_END */ default: - return -EINVAL; + ret = -EINVAL; } - return -ENXIO; + + unlock_kernel(); + return ret; } static ssize_t isapnp_info_entry_read(struct file *file, char *buffer, @@ -215,8 +223,9 @@ static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) { - loff_t new; - + loff_t new = -1; + + lock_kernel(); switch (whence) { case 0: new = off; @@ -227,11 +236,12 @@ case 2: new = 256 + off; break; - default: - return -EINVAL; } - if (new < 0 || new > 256) + if (new < 0 || new > 256) { + unlock_kernel(); return -EINVAL; + } + unlock_kernel(); return (file->f_pos = new); } diff -Nur linux-2.4.19/drivers/sbus/char/flash.c linux-2.4.19-sgi211r3/drivers/sbus/char/flash.c --- linux-2.4.19/drivers/sbus/char/flash.c Wed Oct 10 23:42:47 2001 +++ linux-2.4.19-sgi211r3/drivers/sbus/char/flash.c Mon Oct 28 20:43:23 2002 @@ -83,6 +83,7 @@ static long long flash_llseek(struct file *file, long long offset, int origin) { + lock_kernel(); switch (origin) { case 0: file->f_pos = offset; @@ -96,8 +97,10 @@ file->f_pos = flash.read_size; break; default: + unlock_kernel(); return -EINVAL; } + unlock_kernel(); return file->f_pos; } diff -Nur linux-2.4.19/drivers/sbus/char/jsflash.c linux-2.4.19-sgi211r3/drivers/sbus/char/jsflash.c --- linux-2.4.19/drivers/sbus/char/jsflash.c Thu Oct 25 13:58:35 2001 +++ linux-2.4.19-sgi211r3/drivers/sbus/char/jsflash.c Mon Oct 28 20:43:23 2002 @@ -259,16 +259,23 @@ */ static loff_t jsf_lseek(struct file * file, loff_t offset, int orig) { + loff_t ret; + + lock_kernel(); switch (orig) { case 0: file->f_pos = offset; - return file->f_pos; + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return file->f_pos; + ret = file->f_pos; + break; default: - return -EINVAL; + ret = -EINVAL; } + unlock_kernel(); + return ret; } /* diff -Nur linux-2.4.19/drivers/scsi/Config.in linux-2.4.19-sgi211r3/drivers/scsi/Config.in --- linux-2.4.19/drivers/scsi/Config.in Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/scsi/Config.in Wed Oct 16 14:02:58 2002 @@ -182,6 +182,7 @@ bool ' Include loadable firmware in driver' CONFIG_SCSI_QLOGIC_FC_FIRMWARE fi dep_tristate 'Qlogic QLA 1280 SCSI support' CONFIG_SCSI_QLOGIC_1280 $CONFIG_SCSI + dep_tristate 'Qlogic QLA 2100 driver support' CONFIG_SCSI_QLOGIC_QLA2100 $CONFIG_SCSI fi if [ "$CONFIG_X86" = "y" ]; then dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI diff -Nur linux-2.4.19/drivers/scsi/Makefile linux-2.4.19-sgi211r3/drivers/scsi/Makefile --- linux-2.4.19/drivers/scsi/Makefile Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/scsi/Makefile Wed Oct 16 14:02:58 2002 @@ -53,6 +53,7 @@ obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o +obj-$(CONFIG_SCSI_SIM) += simscsi.o obj-$(CONFIG_SCSI_SIM710) += sim710.o obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o obj-$(CONFIG_SCSI_PCI2000) += pci2000.o @@ -84,6 +85,7 @@ obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o +obj-$(CONFIG_SCSI_QLOGIC_QLA2100) += qla2x00.o obj-$(CONFIG_SCSI_PAS16) += pas16.o obj-$(CONFIG_SCSI_SEAGATE) += seagate.o obj-$(CONFIG_SCSI_FD_8xx) += seagate.o diff -Nur linux-2.4.19/drivers/scsi/megaraid.c linux-2.4.19-sgi211r3/drivers/scsi/megaraid.c --- linux-2.4.19/drivers/scsi/megaraid.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/scsi/megaraid.c Wed Oct 16 14:02:58 2002 @@ -2032,9 +2032,6 @@ #if DEBUG -static unsigned int cum_time = 0; -static unsigned int cum_time_cnt = 0; - static void showMbox (mega_scb * pScb) { mega_mailbox *mbox; @@ -2043,7 +2040,7 @@ return; mbox = (mega_mailbox *) pScb->mboxData; - printk ("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", + printk ("%lu cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", pScb->SCpnt->pid, mbox->cmd, mbox->cmdid, mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements); @@ -2288,10 +2285,6 @@ phys_mbox = virt_to_bus (megaCfg->mbox); #endif -#if DEBUG - ShowMbox (pScb); -#endif - /* Wait until mailbox is free */ if (mega_busyWaitMbox (megaCfg)) { printk ("Blocked mailbox......!!\n"); @@ -3031,9 +3024,7 @@ sizeof (mega_mailbox64), &(megaCfg->dma_handle64)); - mega_register_mailbox (megaCfg, - virt_to_bus ((void *) megaCfg-> - mailbox64ptr)); + mega_register_mailbox (megaCfg, megaCfg->dma_handle64); #else mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg-> @@ -3356,9 +3347,13 @@ mbox[0] = IS_BIOS_ENABLED; mbox[2] = GET_BIOS; - mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer); + mboxpnt->xferaddr = pci_map_single(megacfg->dev, + (void *) megacfg->mega_buffer, (2 * 1024L), + PCI_DMA_FROMDEVICE); ret = megaIssueCmd (megacfg, mbox, NULL, 0); + + pci_unmap_single(megacfg->dev, mboxpnt->xferaddr, 2 * 1024L, PCI_DMA_FROMDEVICE); return (*(char *) megacfg->mega_buffer); } diff -Nur linux-2.4.19/drivers/scsi/ql12160_fw.h linux-2.4.19-sgi211r3/drivers/scsi/ql12160_fw.h --- linux-2.4.19/drivers/scsi/ql12160_fw.h Mon Feb 7 19:45:28 2000 +++ linux-2.4.19-sgi211r3/drivers/scsi/ql12160_fw.h Tue Jan 8 17:05:38 2002 @@ -1,56 +1,93 @@ /* + ************************************************************************ + * * + * --- ISP12160 Initiator Firmware --- * + * 32 LUN Support * + * * + ************************************************************************ + * * + * Copyright (C) 1999,2000 Qlogic, Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted provided + * that the following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. - * 2. The name of the author may not be used to endorse or promote products + + * 2. Redistribution 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. 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 ``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 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. + * * + ************************************************************************ + */ + /* - * Firmware Version 10.01.19 (12:38 Oct 12, 1999) + * Firmware Version 10.04.08 (11:30 May 31, 2000) */ #ifdef UNIQUE_FW_NAME -unsigned short fw12160i_version = 10*1024+1; +unsigned short fw12160i_version = 10*1024+4; #else -unsigned short risc_code_version = 10*1024+1; +unsigned short risc_code_version = 10*1024+4; #endif #ifdef UNIQUE_FW_NAME -unsigned char fw12160i_version_str[] = {10,1,19}; +unsigned char fw12160i_version_str[] = {10,4,8}; #else -unsigned char firmware_version[] = {10,1,19}; +unsigned char firmware_version[] = {10,4,8}; #endif #ifdef UNIQUE_FW_NAME -#define fw12160i_VERSION_STRING "10.1.19" +#define fw12160i_VERSION_STRING "10.04.08" #else -#define FW_VERSION_STRING "10.1.19" +#define FW_VERSION_STRING "10.04.08" #endif #ifdef UNIQUE_FW_NAME @@ -64,1326 +101,1383 @@ #else unsigned short risc_code01[] = { #endif - 0x0804, 0x1041, 0x0000, 0x32f8, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x0804, 0x1041, 0x0000, 0x34e5, 0x0000, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, 0x3132, 0x3136, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, - 0x6572, 0x7369, 0x6f6e, 0x2031, 0x302e, 0x3031, 0x2020, 0x2043, + 0x6572, 0x7369, 0x6f6e, 0x2031, 0x302e, 0x3034, 0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, - 0x2400, 0x20c9, 0x8cff, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2001, + 0x2400, 0x20c9, 0x8eff, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1120, 0x2071, 0x0100, 0x70a0, 0x70a2, - 0x20c1, 0x0020, 0x2089, 0x1223, 0x2071, 0x0010, 0x70c3, 0x0004, + 0x20c1, 0x0020, 0x2089, 0x1221, 0x2071, 0x0010, 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x000a, 0x2001, 0x04fd, 0x2004, 0x70d6, 0x2009, 0xfeff, 0x2130, 0x2128, - 0xa1a2, 0x4300, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, - 0xa192, 0x8d00, 0x2009, 0x0000, 0x2001, 0x0032, 0x080c, 0x1d83, - 0x2218, 0x2079, 0x4300, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, + 0xa1a2, 0x4500, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0xa192, 0x8f00, 0x2009, 0x0000, 0x2001, 0x0032, 0x080c, 0x1dcf, + 0x2218, 0x2079, 0x4500, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, 0x1dd8, 0x2009, 0xff00, 0x3400, 0xa102, 0x0218, 0x0110, 0x20a8, 0x42a4, 0x781b, 0x0064, 0x7814, 0xc0cd, - 0xc0d5, 0x7816, 0x2071, 0x0200, 0x00d6, 0x2069, 0x4340, 0x080c, - 0x42d8, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1130, 0x2069, 0x4380, - 0x2071, 0x0100, 0x080c, 0x42d8, 0x7814, 0xc0d4, 0x7816, 0x00de, + 0xc0d5, 0x7816, 0x2071, 0x0200, 0x00d6, 0x2069, 0x4540, 0x080c, + 0x44bd, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1130, 0x2069, 0x4580, + 0x2071, 0x0100, 0x080c, 0x44bd, 0x7814, 0xc0d4, 0x7816, 0x00de, 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802, 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002, - 0x2009, 0x0002, 0x2069, 0x4340, 0x681b, 0x0003, 0x6823, 0x0007, - 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0000, - 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, 0x8109, 0x0500, - 0x68d3, 0x000a, 0x68c3, 0x43c0, 0x2079, 0x4300, 0x68d7, 0x762d, - 0x68c7, 0x48c0, 0x68cb, 0x47c0, 0x68cf, 0x88c0, 0x68ab, 0x8b44, - 0x68af, 0x8b49, 0x68b3, 0x8b44, 0x68b7, 0x8b44, 0x68a7, 0x0001, - 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x11c8, 0x2069, 0x4380, 0x0860, - 0x68d3, 0x000a, 0x68c3, 0x45c0, 0x68d7, 0x7839, 0x68c7, 0x68c0, - 0x68cb, 0x4840, 0x68cf, 0x89d0, 0x68ab, 0x8b49, 0x68af, 0x8b4e, - 0x68b3, 0x8b49, 0x68b7, 0x8b49, 0x68a7, 0x0001, 0x00e6, 0x2069, - 0x47c0, 0x2071, 0x0200, 0x70ec, 0xd0e4, 0x2019, 0x1c09, 0x2021, - 0x0009, 0x1120, 0x2019, 0x1c0c, 0x2021, 0x000c, 0x080c, 0x1cf3, - 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1188, 0x2069, 0x4840, 0x2071, - 0x0100, 0x70ec, 0xd0e4, 0x2019, 0x1c09, 0x2021, 0x0009, 0x1120, - 0x2019, 0x1c0c, 0x2021, 0x000c, 0x080c, 0x1cf3, 0x00ee, 0x2011, - 0x0002, 0x2069, 0x48c0, 0x2009, 0x0002, 0x20a9, 0x0100, 0x6837, - 0x0000, 0x680b, 0x0040, 0x7bc8, 0xa386, 0xfeff, 0x1128, 0x6817, - 0x0100, 0x681f, 0x0064, 0x0020, 0x6817, 0x0064, 0x681f, 0x0002, - 0xade8, 0x0010, 0x1f04, 0x1137, 0x8109, 0x1d38, 0x2001, 0x01ff, - 0x2004, 0xd0fc, 0x1128, 0x8211, 0x0118, 0x2069, 0x68c0, 0x08d8, - 0x080c, 0x2254, 0x080c, 0x3e39, 0x080c, 0x1b0f, 0x080c, 0x42a0, - 0x2091, 0x2200, 0x2079, 0x4300, 0x2071, 0x0050, 0x2091, 0x2400, - 0x2079, 0x4300, 0x2071, 0x0020, 0x2091, 0x2600, 0x2079, 0x0200, - 0x2071, 0x4340, 0x2091, 0x2800, 0x2079, 0x0100, 0x2071, 0x4380, - 0x2091, 0x2000, 0x2079, 0x4300, 0x2071, 0x0010, 0x3200, 0xa085, - 0x303d, 0x2090, 0x2071, 0x0010, 0x70c3, 0x0000, 0x1004, 0x118e, - 0x70c0, 0xa086, 0x0002, 0x1110, 0x080c, 0x13a3, 0x2039, 0x0000, - 0x080c, 0x129c, 0x78ac, 0xa005, 0x1180, 0x0e04, 0x119c, 0x786c, - 0xa065, 0x0110, 0x080c, 0x1ffe, 0x080c, 0x1da4, 0x0e04, 0x11b1, - 0x786c, 0xa065, 0x0110, 0x080c, 0x1ffe, 0x0e04, 0x11b1, 0x2009, - 0x4347, 0x2011, 0x4387, 0x2104, 0x220c, 0xa105, 0x0110, 0x080c, - 0x1c21, 0x2071, 0x4340, 0x70a4, 0xa005, 0x01e8, 0x7450, 0xa485, - 0x0000, 0x01c8, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, 0xa28c, - 0x303d, 0x2190, 0x080c, 0x260d, 0x2091, 0x8000, 0x2091, 0x303d, - 0x0e04, 0x11d3, 0x2079, 0x4300, 0x786c, 0xa065, 0x0120, 0x2071, - 0x0010, 0x080c, 0x1ffe, 0x1d04, 0x11db, 0x2079, 0x4300, 0x2071, - 0x0010, 0x080c, 0x40ed, 0x2071, 0x4380, 0x70a4, 0xa005, 0x0188, - 0x7050, 0xa025, 0x0170, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d4, - 0xa28c, 0x303d, 0x2190, 0x080c, 0x260d, 0x2091, 0x8000, 0x2091, - 0x303d, 0x2079, 0x4300, 0x2071, 0x0010, 0x0e04, 0x11fc, 0x786c, - 0xa065, 0x0110, 0x080c, 0x1ffe, 0x1d04, 0x1190, 0x080c, 0x40ed, - 0x0804, 0x1190, 0x3c00, 0xa084, 0x0007, 0x0002, 0x120e, 0x120e, - 0x1210, 0x1210, 0x1215, 0x1215, 0x121a, 0x121a, 0x080c, 0x243b, - 0x2091, 0x2400, 0x080c, 0x3e9c, 0x0005, 0x2091, 0x2200, 0x080c, - 0x3e9c, 0x0005, 0x2091, 0x2200, 0x080c, 0x3e9c, 0x2091, 0x2400, - 0x080c, 0x3e9c, 0x0005, 0x1243, 0x1243, 0x1244, 0x1244, 0x124f, - 0x124f, 0x124f, 0x124f, 0x1258, 0x1258, 0x1263, 0x1263, 0x124f, - 0x124f, 0x124f, 0x124f, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, - 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, - 0x1272, 0x1272, 0x1272, 0x0cf8, 0x0006, 0x0106, 0x0126, 0x2091, - 0x2800, 0x080c, 0x2458, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, - 0x0106, 0x0126, 0x080c, 0x1202, 0x012e, 0x010e, 0x000e, 0x000d, - 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, 0x080c, 0x2458, 0x012e, - 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, - 0x080c, 0x2458, 0x2091, 0x2800, 0x080c, 0x2458, 0x012e, 0x010e, - 0x000e, 0x000d, 0x0006, 0x0106, 0x0126, 0x00e6, 0x00f6, 0x2079, - 0x4300, 0x2071, 0x0200, 0x2069, 0x4340, 0x3d00, 0xd08c, 0x1120, - 0x2069, 0x4380, 0x2071, 0x0100, 0x080c, 0x42d8, 0x00fe, 0x00ee, - 0x012e, 0x010e, 0x000e, 0x000d, 0x7008, 0x800b, 0x1240, 0x7007, - 0x0002, 0xa08c, 0x01e0, 0x1120, 0xd09c, 0x0108, 0x0887, 0x0897, - 0x70c3, 0x4002, 0x0804, 0x13a6, 0x0e04, 0x1308, 0x2061, 0x0000, - 0x6018, 0xd084, 0x1904, 0x1308, 0x7828, 0xa005, 0x1120, 0x0004, - 0x1309, 0x0804, 0x1308, 0xd0fc, 0x0148, 0x0006, 0x080c, 0x1aa9, - 0x000e, 0x0168, 0x2001, 0x4007, 0x0804, 0x13a5, 0x0006, 0x080c, - 0x1a9b, 0x000e, 0x0120, 0x2001, 0x4007, 0x0804, 0x13a5, 0x7910, - 0xd0fc, 0x1128, 0x2061, 0x4340, 0xc19c, 0xc7fc, 0x0020, 0x2061, - 0x4380, 0xc19d, 0xc7fd, 0x6064, 0xa005, 0x15d0, 0x7912, 0x6083, - 0x0000, 0x7828, 0xc0fc, 0xa086, 0x0018, 0x1120, 0x00c6, 0x080c, - 0x18c9, 0x00ce, 0x782b, 0x0000, 0x607c, 0xa065, 0x0190, 0x00c6, - 0x609c, 0x080c, 0x1b76, 0x00ce, 0x609f, 0x0000, 0x080c, 0x19db, - 0x2009, 0x0018, 0x6087, 0x0103, 0x080c, 0x1ab7, 0x1198, 0x080c, - 0x1b02, 0x7810, 0xd09c, 0x1118, 0x2061, 0x4340, 0x0020, 0x2061, - 0x4380, 0xc09c, 0x7812, 0x607f, 0x0000, 0x60d4, 0xd0c4, 0x0130, - 0xc0c4, 0x60d6, 0x2001, 0x4005, 0x0804, 0x13a5, 0x0804, 0x13a3, - 0x0005, 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, - 0xa08a, 0x0040, 0x1a04, 0x1355, 0x0002, 0x13a3, 0x13f1, 0x13bf, - 0x1425, 0x1459, 0x1459, 0x13b7, 0x19f3, 0x1463, 0x13b1, 0x13c3, - 0x13c4, 0x13c5, 0x13c6, 0x19f7, 0x13b1, 0x1470, 0x14c5, 0x18e4, - 0x19ed, 0x13c7, 0x1795, 0x17cb, 0x17fa, 0x183d, 0x1752, 0x175f, - 0x1772, 0x1784, 0x159a, 0x13b1, 0x14f7, 0x1502, 0x1510, 0x151e, - 0x1535, 0x1543, 0x1546, 0x1554, 0x1562, 0x156c, 0x1580, 0x158c, - 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x15a7, 0x15b8, 0x15d2, 0x1606, - 0x162f, 0x1641, 0x1644, 0x1677, 0x16aa, 0x16bc, 0x1720, 0x1730, - 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x1742, 0x2100, 0xa08a, 0x0040, - 0x1a04, 0x13b1, 0x0002, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, - 0x1a19, 0x1a1f, 0x13b1, 0x13b1, 0x13b1, 0x1a23, 0x1a63, 0x13b1, - 0x13b1, 0x13b1, 0x13b1, 0x13ec, 0x1454, 0x146b, 0x14c0, 0x18df, - 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x1a67, 0x1a0b, 0x1a15, 0x13b1, - 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, - 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, - 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, - 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, - 0x13b1, 0x13b1, 0x13b1, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0028, - 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0e04, 0x13a6, + 0x2009, 0x0002, 0x2069, 0x4540, 0x681b, 0x0003, 0x6823, 0x0007, + 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0006, + 0x6833, 0x0008, 0x683b, 0x0000, 0x8109, 0x0500, 0x68cf, 0x000a, + 0x68bf, 0x45c0, 0x2079, 0x4500, 0x68d3, 0x762d, 0x68c3, 0x4ac0, + 0x68c7, 0x49c0, 0x68cb, 0x8ac0, 0x68a7, 0x8d44, 0x68ab, 0x8d49, + 0x68af, 0x8d44, 0x68b3, 0x8d44, 0x68a3, 0x0001, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x11c8, 0x2069, 0x4580, 0x0870, 0x68cf, 0x000a, + 0x68bf, 0x47c0, 0x68d3, 0x7839, 0x68c3, 0x6ac0, 0x68c7, 0x4a40, + 0x68cb, 0x8bd0, 0x68a7, 0x8d49, 0x68ab, 0x8d4e, 0x68af, 0x8d49, + 0x68b3, 0x8d49, 0x68a3, 0x0001, 0x00e6, 0x2069, 0x49c0, 0x2071, + 0x0200, 0x70ec, 0xd0e4, 0x2019, 0x1c09, 0x2021, 0x0009, 0x1120, + 0x2019, 0x1c0c, 0x2021, 0x000c, 0x080c, 0x1d3f, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x1188, 0x2069, 0x4a40, 0x2071, 0x0100, 0x70ec, + 0xd0e4, 0x2019, 0x1c09, 0x2021, 0x0009, 0x1120, 0x2019, 0x1c0c, + 0x2021, 0x000c, 0x080c, 0x1d3f, 0x00ee, 0x2011, 0x0002, 0x2069, + 0x4ac0, 0x2009, 0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b, + 0x0040, 0x7bc8, 0xa386, 0xfeff, 0x1128, 0x6817, 0x0100, 0x681f, + 0x0064, 0x0020, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, + 0x1f04, 0x1135, 0x8109, 0x1d38, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x1128, 0x8211, 0x0118, 0x2069, 0x6ac0, 0x08d8, 0x080c, 0x22b7, + 0x080c, 0x3fba, 0x080c, 0x1b51, 0x080c, 0x4489, 0x2091, 0x2200, + 0x2079, 0x4500, 0x2071, 0x0050, 0x2091, 0x2400, 0x2079, 0x4500, + 0x2071, 0x0020, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x4540, + 0x2091, 0x2800, 0x2079, 0x0100, 0x2071, 0x4580, 0x2091, 0x2000, + 0x2079, 0x4500, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, + 0x2071, 0x0010, 0x70c3, 0x0000, 0x1004, 0x118c, 0x70c0, 0xa086, + 0x0002, 0x1110, 0x080c, 0x13b3, 0x2039, 0x0000, 0x080c, 0x12ab, + 0x78ac, 0xa005, 0x1180, 0x0e04, 0x119a, 0x786c, 0xa065, 0x0110, + 0x080c, 0x2061, 0x080c, 0x1df0, 0x0e04, 0x11af, 0x786c, 0xa065, + 0x0110, 0x080c, 0x2061, 0x0e04, 0x11af, 0x2009, 0x4547, 0x2011, + 0x4587, 0x2104, 0x220c, 0xa105, 0x0110, 0x080c, 0x1c63, 0x2071, + 0x4540, 0x70a0, 0xa005, 0x01e8, 0x744c, 0xa485, 0x0000, 0x01c8, + 0x2079, 0x0200, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d, 0x2190, + 0x080c, 0x26ff, 0x2091, 0x8000, 0x2091, 0x303d, 0x0e04, 0x11d1, + 0x2079, 0x4500, 0x786c, 0xa065, 0x0120, 0x2071, 0x0010, 0x080c, + 0x2061, 0x1d04, 0x11d9, 0x2079, 0x4500, 0x2071, 0x0010, 0x080c, + 0x42c7, 0x2071, 0x4580, 0x70a0, 0xa005, 0x0188, 0x704c, 0xa025, + 0x0170, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d, + 0x2190, 0x080c, 0x26ff, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079, + 0x4500, 0x2071, 0x0010, 0x0e04, 0x11fa, 0x786c, 0xa065, 0x0110, + 0x080c, 0x2061, 0x1d04, 0x118e, 0x080c, 0x42c7, 0x0804, 0x118e, + 0x3c00, 0xa084, 0x0007, 0x0002, 0x120c, 0x120c, 0x120e, 0x120e, + 0x1213, 0x1213, 0x1218, 0x1218, 0x080c, 0x252b, 0x2091, 0x2400, + 0x080c, 0x4052, 0x0005, 0x2091, 0x2200, 0x080c, 0x4052, 0x0005, + 0x2091, 0x2200, 0x080c, 0x4052, 0x2091, 0x2400, 0x080c, 0x4052, + 0x0005, 0x1241, 0x1241, 0x1242, 0x1242, 0x124d, 0x124d, 0x124d, + 0x124d, 0x1256, 0x1256, 0x1261, 0x1261, 0x124d, 0x124d, 0x124d, + 0x124d, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, + 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, + 0x1270, 0x0cf8, 0x0006, 0x0106, 0x0126, 0x2091, 0x2800, 0x080c, + 0x2548, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, 0x0126, + 0x080c, 0x1200, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, + 0x0126, 0x2091, 0x2600, 0x080c, 0x2548, 0x012e, 0x010e, 0x000e, + 0x000d, 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, 0x080c, 0x2548, + 0x2091, 0x2800, 0x080c, 0x2548, 0x012e, 0x010e, 0x000e, 0x000d, + 0x0006, 0x0106, 0x0126, 0x00d6, 0x00e6, 0x00f6, 0x2079, 0x4500, + 0x2071, 0x0200, 0x2069, 0x4540, 0x3d00, 0xd08c, 0x0130, 0x70ec, + 0xa084, 0x1c00, 0x78e2, 0x080c, 0x44bd, 0x3d00, 0xd084, 0x0150, + 0x2069, 0x4580, 0x2071, 0x0100, 0x70ec, 0xa084, 0x1c00, 0x78e6, + 0x080c, 0x44bd, 0x080c, 0x24dc, 0x00fe, 0x00ee, 0x00de, 0x012e, + 0x010e, 0x000e, 0x000d, 0x7008, 0x800b, 0x1240, 0x7007, 0x0002, + 0xa08c, 0x01e0, 0x1120, 0xd09c, 0x0108, 0x0887, 0x0897, 0x70c3, + 0x4002, 0x0804, 0x13b6, 0x0e04, 0x1317, 0x2061, 0x0000, 0x6018, + 0xd084, 0x1904, 0x1317, 0x7828, 0xa005, 0x1120, 0x0004, 0x1318, + 0x0804, 0x1317, 0xd0fc, 0x0148, 0x0006, 0x080c, 0x1aeb, 0x000e, + 0x0168, 0x2001, 0x4007, 0x0804, 0x13b5, 0x0006, 0x080c, 0x1add, + 0x000e, 0x0120, 0x2001, 0x4007, 0x0804, 0x13b5, 0x7910, 0xd0fc, + 0x1128, 0x2061, 0x4540, 0xc19c, 0xc7fc, 0x0020, 0x2061, 0x4580, + 0xc19d, 0xc7fd, 0x6060, 0xa005, 0x15d0, 0x7912, 0x607f, 0x0000, + 0x7828, 0xc0fc, 0xa086, 0x0018, 0x1120, 0x00c6, 0x080c, 0x190a, + 0x00ce, 0x782b, 0x0000, 0x6078, 0xa065, 0x0190, 0x00c6, 0x609c, + 0x080c, 0x1bb8, 0x00ce, 0x609f, 0x0000, 0x080c, 0x1a1b, 0x2009, + 0x0018, 0x6087, 0x0103, 0x080c, 0x1af9, 0x1198, 0x080c, 0x1b44, + 0x7810, 0xd09c, 0x1118, 0x2061, 0x4540, 0x0020, 0x2061, 0x4580, + 0xc09c, 0x7812, 0x607b, 0x0000, 0x60d0, 0xd0c4, 0x0130, 0xc0c4, + 0x60d2, 0x2001, 0x4005, 0x0804, 0x13b5, 0x0804, 0x13b3, 0x0005, + 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, 0xa03d, + 0xa08a, 0x0040, 0x1a04, 0x1365, 0x0002, 0x13b3, 0x1401, 0x13cf, + 0x1435, 0x1469, 0x1469, 0x13c7, 0x1a33, 0x1473, 0x13c1, 0x13d3, + 0x13d4, 0x13d5, 0x13d6, 0x1a37, 0x13c1, 0x1480, 0x14d5, 0x1925, + 0x1a2d, 0x13d7, 0x17b4, 0x17ea, 0x1819, 0x185c, 0x1771, 0x177e, + 0x1791, 0x17a3, 0x15aa, 0x13c1, 0x1507, 0x1512, 0x1520, 0x152e, + 0x1545, 0x1553, 0x1556, 0x1564, 0x1572, 0x157c, 0x1590, 0x159c, + 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x15b7, 0x15c8, 0x15e2, 0x1616, + 0x163f, 0x1651, 0x1654, 0x167f, 0x16b8, 0x16ca, 0x173f, 0x174f, + 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x1761, 0x2100, 0xa08a, 0x0040, + 0x1a04, 0x13c1, 0x0002, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, + 0x1a59, 0x1a5f, 0x13c1, 0x13c1, 0x13c1, 0x1a63, 0x1aa3, 0x13c1, + 0x13c1, 0x13c1, 0x13c1, 0x13fc, 0x1464, 0x147b, 0x14d0, 0x1920, + 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x1aa7, 0x1a4b, 0x1a55, 0x18ef, + 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, + 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, + 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, + 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, 0x13c1, + 0x13c1, 0x13c1, 0x13c1, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0028, + 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0e04, 0x13b6, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x0005, 0x70c3, 0x4001, 0x0c90, 0x70c3, 0x4006, 0x0c78, 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0c20, 0x70c4, 0x70c3, 0x0004, 0x0807, 0x08f8, 0x08f0, 0x08e8, 0x08e0, 0x2091, 0x8000, 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, - 0x2020, 0x70d3, 0x000a, 0x2001, 0x0001, 0x70d6, 0x2079, 0x0000, + 0x2020, 0x70d3, 0x000a, 0x2001, 0x0004, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051, 0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091, 0x4080, 0x0804, 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0018, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, - 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0904, 0x13a3, + 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0904, 0x13b3, 0xa182, 0x0040, 0x1210, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x7007, 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0de8, 0x7007, - 0x0002, 0xa084, 0x01e0, 0x0120, 0x70c3, 0x4002, 0x0804, 0x13a6, - 0x24a8, 0x53a5, 0x0c10, 0x0804, 0x13a3, 0x2029, 0x0000, 0x2520, + 0x0002, 0xa084, 0x01e0, 0x0120, 0x70c3, 0x4002, 0x0804, 0x13b6, + 0x24a8, 0x53a5, 0x0c10, 0x0804, 0x13b3, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, - 0x0040, 0x7007, 0x0006, 0x81ff, 0x0904, 0x13a3, 0xa182, 0x0040, + 0x0040, 0x7007, 0x0006, 0x81ff, 0x0904, 0x13b3, 0xa182, 0x0040, 0x1210, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0de8, 0xa084, 0x01e0, 0x0d48, - 0x70c3, 0x4002, 0x0804, 0x13a6, 0x75d8, 0x74dc, 0x75da, 0x74de, + 0x70c3, 0x4002, 0x0804, 0x13b6, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0878, 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x1108, 0x200a, - 0x72ca, 0x0804, 0x13a2, 0x70c7, 0x000a, 0x70cb, 0x0001, 0x70cf, - 0x0013, 0x0804, 0x13a3, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, + 0x72ca, 0x0804, 0x13b2, 0x70c7, 0x000a, 0x70cb, 0x0004, 0x70cf, + 0x0008, 0x0804, 0x13b3, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x05f0, 0xa40a, 0x0110, 0x1a04, - 0x13a5, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc085, - 0x78ae, 0x2001, 0x4005, 0x0804, 0x13a5, 0x7b7e, 0x7a7a, 0x7e86, + 0x13b5, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc085, + 0x78ae, 0x2001, 0x4005, 0x0804, 0x13b5, 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00, 0x0170, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f, 0xa118, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0050, 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, 0x0118, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, - 0xfffc, 0x78ae, 0x0018, 0x78ac, 0xc085, 0x78ae, 0x0804, 0x13a3, + 0xfffc, 0x78ae, 0x0018, 0x78ac, 0xc085, 0x78ae, 0x0804, 0x13b3, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, - 0xa005, 0x0500, 0xa40a, 0x0110, 0x1a04, 0x13a5, 0x8001, 0x7892, + 0xa005, 0x0500, 0xa40a, 0x0110, 0x1a04, 0x13b5, 0x8001, 0x7892, 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, - 0x0804, 0x13a5, 0x7a9a, 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, + 0x0804, 0x13b5, 0x7a9a, 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0118, 0x7a10, 0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, - 0x78ae, 0x0018, 0x78ac, 0xc0c5, 0x78ae, 0x0804, 0x13a3, 0x2009, + 0x78ae, 0x0018, 0x78ac, 0xc0c5, 0x78ae, 0x0804, 0x13b3, 0x2009, 0x0000, 0x786c, 0xa065, 0x0118, 0x8108, 0x6000, 0x0cd8, 0x7ac4, - 0x0804, 0x13a1, 0x2009, 0x4348, 0x210c, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x1904, 0x13a2, 0x2011, 0x4388, 0x2214, 0x0804, 0x13a1, - 0x2009, 0x4349, 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, - 0x13a2, 0x2011, 0x4389, 0x2214, 0x0804, 0x13a1, 0x2061, 0x4340, + 0x0804, 0x13b1, 0x2009, 0x4548, 0x210c, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1904, 0x13b2, 0x2011, 0x4588, 0x2214, 0x0804, 0x13b1, + 0x2009, 0x4549, 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, + 0x13b2, 0x2011, 0x4589, 0x2214, 0x0804, 0x13b1, 0x2061, 0x4540, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x1148, 0x2061, 0x4380, 0x6328, 0x73da, 0x632c, 0x831c, - 0x831c, 0x831c, 0x73de, 0x0804, 0x13a1, 0x2009, 0x434c, 0x210c, - 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2011, 0x438c, - 0x2214, 0x0804, 0x13a1, 0x7918, 0x0804, 0x13a2, 0x2009, 0x434d, - 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2011, - 0x438d, 0x2214, 0x0804, 0x13a1, 0x2009, 0x434e, 0x210c, 0x2001, - 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2011, 0x438e, 0x2214, - 0x0804, 0x13a1, 0x7920, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, - 0x13a2, 0x7a24, 0x0804, 0x13a1, 0x2011, 0x4840, 0x71c4, 0xd1fc, - 0x1110, 0x2011, 0x47c0, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, - 0x8003, 0xa268, 0x6a00, 0x6b08, 0x6c1c, 0x74da, 0x0804, 0x13a0, - 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, - 0x8001, 0x2708, 0x0804, 0x13a0, 0x2061, 0x4340, 0x6118, 0x2001, - 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2061, 0x4380, 0x6218, - 0x0804, 0x13a1, 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6908, - 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0804, 0x13a0, 0x71c4, - 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x1a04, 0x139c, 0x080c, - 0x230e, 0xa384, 0x4000, 0x0110, 0xa295, 0x0020, 0x0804, 0x13a0, - 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, 0x1a04, 0x139c, 0xd1bc, - 0x1120, 0x2011, 0x4348, 0x2204, 0x0020, 0x2011, 0x4388, 0x2204, - 0xc0bd, 0x0006, 0x2100, 0xc0bc, 0x2012, 0x080c, 0x22b4, 0x001e, - 0x0804, 0x13a2, 0x71c4, 0x2021, 0x4349, 0x2404, 0x70c6, 0x2019, - 0x0000, 0x0030, 0x71c8, 0x2021, 0x4389, 0x2404, 0x70ca, 0xc3fd, - 0x2011, 0x15fe, 0x20a9, 0x0008, 0x2204, 0xa106, 0x0138, 0x8210, - 0x1f04, 0x15e4, 0x71c4, 0x72c8, 0x0804, 0x139b, 0xa292, 0x15fe, - 0x0026, 0x2122, 0x001e, 0x080c, 0x22c6, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x1110, 0xd3fc, 0x09f0, 0x0804, 0x13a3, 0x03e8, 0x00fa, - 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x4340, + 0xd0fc, 0x1148, 0x2061, 0x4580, 0x6328, 0x73da, 0x632c, 0x831c, + 0x831c, 0x831c, 0x73de, 0x0804, 0x13b1, 0x2009, 0x454c, 0x210c, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b2, 0x2011, 0x458c, + 0x2214, 0x0804, 0x13b1, 0x7918, 0x0804, 0x13b2, 0x2009, 0x0202, + 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b2, 0x2011, + 0x0102, 0x2214, 0x0804, 0x13b1, 0x2009, 0x454d, 0x210c, 0x2001, + 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b2, 0x2011, 0x458d, 0x2214, + 0x0804, 0x13b1, 0x7920, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, + 0x13b2, 0x7a24, 0x0804, 0x13b1, 0x2011, 0x4a40, 0x71c4, 0xd1fc, + 0x1110, 0x2011, 0x49c0, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa268, 0x6a00, 0x6b08, 0x6c1c, 0x74da, 0x0804, 0x13b0, + 0x77c4, 0x080c, 0x1b5f, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, + 0x8001, 0x2708, 0x0804, 0x13b0, 0x2061, 0x4540, 0x6118, 0x2001, + 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b2, 0x2061, 0x4580, 0x6218, + 0x0804, 0x13b1, 0x77c4, 0x080c, 0x1b5f, 0x2091, 0x8000, 0x6908, + 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0804, 0x13b0, 0x71c4, + 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x1a04, 0x13ac, 0x080c, + 0x2373, 0xa384, 0x4000, 0x0110, 0xa295, 0x0020, 0x0804, 0x13b0, + 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, 0x1a04, 0x13ac, 0xd1bc, + 0x1120, 0x2011, 0x4548, 0x2204, 0x0020, 0x2011, 0x4588, 0x2204, + 0xc0bd, 0x0006, 0x2100, 0xc0bc, 0x2012, 0x080c, 0x2319, 0x001e, + 0x0804, 0x13b2, 0x71c4, 0x2021, 0x4549, 0x2404, 0x70c6, 0x2019, + 0x0000, 0x0030, 0x71c8, 0x2021, 0x4589, 0x2404, 0x70ca, 0xc3fd, + 0x2011, 0x160e, 0x20a9, 0x0008, 0x2204, 0xa106, 0x0138, 0x8210, + 0x1f04, 0x15f4, 0x71c4, 0x72c8, 0x0804, 0x13ab, 0xa292, 0x160e, + 0x0026, 0x2122, 0x001e, 0x080c, 0x232b, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1110, 0xd3fc, 0x09f0, 0x0804, 0x13b3, 0x03e8, 0x00fa, + 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x4540, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003, 0x8003, 0x602e, 0x2001, 0x01ff, 0x2004, 0xd0fc, - 0x11a0, 0x0026, 0x0016, 0x2061, 0x4380, 0x6128, 0x622c, 0x8214, + 0x11a0, 0x0026, 0x0016, 0x2061, 0x4580, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70d8, 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, - 0x602e, 0x71da, 0x72de, 0x001e, 0x002e, 0x0804, 0x13a1, 0x2061, - 0x4340, 0x6130, 0x70c4, 0x6032, 0x2001, 0x01ff, 0x2004, 0xd0fc, - 0x1904, 0x13a2, 0x2061, 0x4380, 0x6230, 0x70c8, 0x6032, 0x0804, - 0x13a1, 0x7918, 0x0804, 0x13a2, 0x71c4, 0xa184, 0xffcf, 0x0148, - 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x139c, 0x72c8, 0x0804, - 0x139b, 0x2011, 0x434d, 0x2204, 0x2112, 0x0006, 0x2019, 0x0000, - 0x080c, 0x2302, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, 0x001e, - 0x0804, 0x13a2, 0x71c8, 0xa184, 0xffcf, 0x0128, 0x0006, 0x2110, - 0x71c4, 0x0804, 0x139b, 0x2011, 0x438d, 0x2204, 0x2112, 0x0006, - 0xc3fd, 0x080c, 0x2302, 0x002e, 0x001e, 0x0804, 0x13a1, 0x71c4, + 0x602e, 0x71da, 0x72de, 0x001e, 0x002e, 0x0804, 0x13b1, 0x2061, + 0x4540, 0x6130, 0x70c4, 0x6032, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x1904, 0x13b2, 0x2061, 0x4580, 0x6230, 0x70c8, 0x6032, 0x0804, + 0x13b1, 0x7918, 0x0804, 0x13b2, 0x71c4, 0xa184, 0xf0cf, 0x0148, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13ac, 0x72c8, 0x0804, + 0x13ab, 0x0006, 0x2019, 0x0000, 0x080c, 0x2367, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x0118, 0x001e, 0x0804, 0x13b2, 0x71c8, 0xa184, + 0xf0cf, 0x0128, 0x0006, 0x2110, 0x71c4, 0x0804, 0x13ab, 0x0006, + 0xc3fd, 0x080c, 0x2367, 0x002e, 0x001e, 0x0804, 0x13b1, 0x71c4, 0xa182, 0x0010, 0x0248, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, - 0x139c, 0x72c8, 0x0804, 0x139b, 0x2011, 0x434e, 0x2204, 0x0006, - 0x2112, 0x2019, 0x0000, 0x080c, 0x22ef, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x0118, 0x001e, 0x0804, 0x13a2, 0x71c8, 0xa182, 0x0010, - 0x0228, 0x0006, 0x2110, 0x71c4, 0x0804, 0x139b, 0x2011, 0x438e, - 0x2204, 0x0006, 0x2112, 0xc3fd, 0x080c, 0x22ef, 0x002e, 0x001e, - 0x0804, 0x13a1, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x1904, 0x139b, - 0xa284, 0xfffd, 0x1904, 0x139b, 0x2100, 0x7920, 0x7822, 0x2200, - 0x7a24, 0x7826, 0x0804, 0x13a1, 0x2011, 0x4840, 0x71c4, 0xd1fc, - 0x1110, 0x2011, 0x47c0, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, - 0x8003, 0xa268, 0x72c8, 0x73cc, 0x74d8, 0x71c6, 0x6800, 0x70ca, - 0x73ce, 0x74da, 0x2091, 0x8000, 0x6a02, 0xd2ac, 0x1118, 0x2021, - 0x0000, 0x0078, 0xa484, 0x00ff, 0xa082, 0x0002, 0x16e8, 0x843f, - 0xa7bc, 0x00ff, 0x0130, 0xa786, 0x0002, 0x15b0, 0xa484, 0x00ff, - 0x0598, 0x2061, 0x0200, 0xd1fc, 0x0110, 0x2061, 0x0100, 0x2029, - 0x0009, 0x2031, 0x0062, 0x843f, 0xa7bc, 0x00ff, 0x0130, 0x8307, - 0xa084, 0x00ff, 0x1110, 0xa73d, 0x11f8, 0x2041, 0x001d, 0x8307, - 0xa084, 0x00ff, 0x0150, 0xa842, 0x02b8, 0xa3bc, 0x00ff, 0x2500, - 0xa702, 0x0290, 0x2600, 0xa702, 0x1278, 0x2039, 0x003a, 0x6804, - 0xa705, 0x6806, 0x6b0a, 0x6b0c, 0x73ce, 0x681c, 0x70da, 0x6c1e, - 0x2091, 0x8001, 0x0804, 0x13a3, 0x2091, 0x8001, 0x0804, 0x139d, - 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, - 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0804, 0x13a0, - 0x70c4, 0x2061, 0x4340, 0x6118, 0x601a, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x1904, 0x13a2, 0x70c8, 0x2061, 0x4380, 0x6218, 0x601a, - 0x0804, 0x13a1, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x1a04, - 0x139c, 0x080c, 0x2332, 0xa384, 0x4000, 0x0110, 0xa295, 0x0020, - 0x0804, 0x13a0, 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a08, - 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0804, 0x13a1, 0x77c4, - 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, - 0x6804, 0xa005, 0x0110, 0x080c, 0x2233, 0x2091, 0x8001, 0x2708, - 0x0804, 0x13a1, 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a08, - 0xc295, 0x6a0a, 0x6804, 0xa005, 0x0110, 0x080c, 0x2233, 0x2091, - 0x8001, 0x2708, 0x0804, 0x13a1, 0x77c4, 0x2041, 0x0001, 0x2049, - 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x080c, 0x1b35, 0x2091, - 0x8001, 0x2708, 0x6a08, 0x0804, 0x13a1, 0x77c4, 0xd7fc, 0x0128, - 0x080c, 0x1aa9, 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, - 0x0804, 0x13a5, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x080c, - 0x1bad, 0x11e8, 0x6818, 0xa005, 0x01a0, 0x2708, 0x0076, 0x080c, - 0x2351, 0x007e, 0x1170, 0x2001, 0x0015, 0xd7fc, 0x1118, 0x2061, - 0x4340, 0x0018, 0xc0fd, 0x2061, 0x4380, 0x782a, 0x2091, 0x8001, - 0x0005, 0x2091, 0x8001, 0x2001, 0x4005, 0x0804, 0x13a5, 0x2091, - 0x8001, 0x0804, 0x13a3, 0x77c4, 0xd7fc, 0x0128, 0x080c, 0x1aa9, - 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, 0x0804, 0x13a5, - 0x77c6, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, - 0x8000, 0x080c, 0x1b35, 0x2009, 0x0016, 0xd7fc, 0x1118, 0x2061, - 0x4340, 0x0018, 0x2061, 0x4380, 0xc1fd, 0x6067, 0x0003, 0x607f, - 0x0000, 0x6776, 0x6083, 0x000f, 0x792a, 0x080c, 0x2233, 0x2091, - 0x8001, 0x0005, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xd7fc, 0x0128, - 0x080c, 0x1aa9, 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, - 0x0804, 0x13a5, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2009, 0x0017, - 0xd7fc, 0x1118, 0x2061, 0x4340, 0x0018, 0x2061, 0x4380, 0xc1fd, - 0x607f, 0x0000, 0x6067, 0x0002, 0x6776, 0x6083, 0x000f, 0x792a, - 0x080c, 0x2233, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, 0x0005, - 0x2051, 0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, 0x0118, 0x60d4, - 0xc0fd, 0x60d6, 0x080c, 0x1b35, 0x70c8, 0x6836, 0x8738, 0xa784, - 0x001f, 0x1dc0, 0x2091, 0x8001, 0x0005, 0x72c8, 0xd284, 0x0128, - 0x080c, 0x1aa9, 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, - 0x0804, 0x13a5, 0x72c8, 0x72ca, 0x78ac, 0xa084, 0x0003, 0x1508, - 0x2039, 0x0000, 0xd284, 0x0108, 0xc7fd, 0x2041, 0x0021, 0x2049, - 0x0004, 0x2051, 0x0008, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6808, - 0xc0d4, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, - 0x1d90, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, - 0x1d50, 0x2091, 0x8000, 0x72c8, 0x2069, 0x0100, 0xd284, 0x1110, - 0x2069, 0x0200, 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, - 0x01b0, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, - 0x1f04, 0x1885, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, - 0x0110, 0x1f04, 0x188e, 0x20a9, 0x00fa, 0x1f04, 0x1895, 0x2079, - 0x4300, 0x2009, 0x0018, 0x72c8, 0xd284, 0x1118, 0x2061, 0x4340, - 0x0018, 0x2061, 0x4380, 0xc1fd, 0x792a, 0x6067, 0x0001, 0x6083, - 0x000f, 0x60a7, 0x0000, 0x60a8, 0x60b2, 0x60b6, 0x60d4, 0xd0b4, - 0x0160, 0xc0b4, 0x60d6, 0x00c6, 0x60b8, 0xa065, 0x6008, 0xc0d4, - 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x60d4, 0xa084, 0x7eff, - 0x60d6, 0x78ac, 0xc08d, 0x78ae, 0x681b, 0x0054, 0x2091, 0x8001, - 0x0005, 0xd7fc, 0x1118, 0x2069, 0x4340, 0x0010, 0x2069, 0x4380, - 0x71c4, 0x71c6, 0x6916, 0x81ff, 0x1110, 0x68a7, 0x0001, 0x78ac, - 0xc08c, 0x78ae, 0xd084, 0x1110, 0x080c, 0x1c00, 0x0005, 0x75d8, - 0x74dc, 0x75da, 0x74de, 0x0018, 0x2029, 0x0000, 0x2520, 0x71c4, - 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4300, 0x7dde, - 0x7cda, 0x7bd6, 0x7ad2, 0x080c, 0x1afa, 0x0904, 0x19d7, 0x20a9, - 0x0005, 0x20a1, 0x4314, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, - 0x2009, 0x0040, 0x080c, 0x1cbf, 0x0120, 0x080c, 0x1b02, 0x0804, - 0x19d7, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, 0x1120, 0x0006, - 0x080c, 0x1fe3, 0x000e, 0xa084, 0xff00, 0x8007, 0x8009, 0x0904, - 0x1981, 0x00c6, 0x2c68, 0x080c, 0x1afa, 0x05a8, 0x2c00, 0x689e, - 0x8109, 0x1dc0, 0x609f, 0x0000, 0x00ce, 0x00c6, 0x7ddc, 0x7cd8, - 0x7bd4, 0x7ad0, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, - 0xa5a9, 0x0000, 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x2c68, 0x689c, - 0xa065, 0x0904, 0x1980, 0x2009, 0x0040, 0x080c, 0x1cbf, 0x1550, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x1168, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x000a, 0x1120, 0x0016, 0x080c, 0x1fe0, 0x001e, - 0x2d00, 0x6002, 0x0898, 0x00ce, 0x00c6, 0x609c, 0x080c, 0x1b76, - 0x00ce, 0x609f, 0x0000, 0x080c, 0x19db, 0x2009, 0x0018, 0x6008, - 0xc0cd, 0x600a, 0x6004, 0x6086, 0x080c, 0x1ab7, 0x080c, 0x1b02, - 0x0804, 0x19d7, 0x00ce, 0x00c6, 0x609c, 0x080c, 0x1b76, 0x00ce, - 0x609f, 0x0000, 0x080c, 0x19db, 0x2009, 0x0018, 0x6087, 0x0103, - 0x601b, 0x0003, 0x080c, 0x1ab7, 0x080c, 0x1b02, 0x0804, 0x19d7, - 0x00ce, 0x6114, 0xd1fc, 0x0120, 0x080c, 0x1aa9, 0x01b8, 0x0018, - 0x080c, 0x1a9b, 0x0198, 0x2029, 0x0000, 0x2520, 0x2009, 0x0018, - 0x73c8, 0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x080c, 0x1ab7, - 0x080c, 0x1b02, 0x2001, 0x4007, 0x0804, 0x13a5, 0x74c4, 0x73c8, - 0x72cc, 0x6014, 0x2091, 0x8000, 0x00e6, 0x2009, 0x0012, 0xd0fc, - 0x1118, 0x2071, 0x4340, 0x0018, 0x2071, 0x4380, 0xc1fd, 0x792a, - 0x7067, 0x0005, 0x71d4, 0xa18c, 0xfe7f, 0x71d6, 0x736a, 0x726e, - 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, 0x707e, 0xa02e, 0x2530, - 0x611c, 0xa184, 0x0060, 0x0110, 0x080c, 0x3de5, 0x00ee, 0x6596, + 0x13ac, 0x72c8, 0x0804, 0x13ab, 0x2011, 0x454d, 0x2204, 0x0006, + 0x8104, 0x1208, 0x8108, 0x2112, 0x2019, 0x0000, 0x080c, 0x2354, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, 0x001e, 0x0804, 0x13b2, + 0x71c8, 0xa182, 0x0010, 0x0228, 0x0006, 0x2110, 0x71c4, 0x0804, + 0x13ab, 0x2011, 0x458d, 0x2204, 0x0006, 0x8104, 0x1208, 0x8108, + 0x2112, 0xc3fd, 0x080c, 0x2354, 0x002e, 0x001e, 0x0804, 0x13b1, + 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x1904, 0x13ab, 0xa284, 0xfffd, + 0x1904, 0x13ab, 0x2100, 0x7920, 0x7822, 0x2200, 0x7a24, 0x7826, + 0x0804, 0x13b1, 0x2011, 0x4a40, 0x71c4, 0xd1fc, 0x1110, 0x2011, + 0x49c0, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, + 0x72c8, 0x73cc, 0x74d8, 0x71c6, 0x6800, 0x70ca, 0x73ce, 0x74da, + 0x2091, 0x8000, 0x6a02, 0xd2ac, 0x1118, 0x2021, 0x0000, 0x0090, + 0xa484, 0x00ff, 0xa082, 0x0002, 0x1a04, 0x173b, 0x843f, 0xa7bc, + 0x00ff, 0x0140, 0xa786, 0x0002, 0x1904, 0x173b, 0xa484, 0x00ff, + 0x0904, 0x173b, 0x2061, 0x0200, 0xd1fc, 0x0110, 0x2061, 0x0100, + 0x2029, 0x0009, 0x2031, 0x0062, 0x843f, 0xa7bc, 0x00ff, 0x0130, + 0x8307, 0xa084, 0x00ff, 0x1110, 0xa73d, 0x1138, 0x2041, 0x001d, + 0xa384, 0x00ff, 0xa082, 0x001a, 0x0210, 0xa4a4, 0x00ff, 0x8307, + 0xa084, 0x00ff, 0x0188, 0xa842, 0x02f0, 0xa086, 0x0010, 0x1120, + 0xa39c, 0x00ff, 0xa39d, 0x0f00, 0xa3bc, 0x00ff, 0x2500, 0xa702, + 0x0290, 0x2600, 0xa702, 0x1278, 0x2039, 0x003a, 0x6804, 0xa705, + 0x6806, 0x6b0a, 0x6b0c, 0x73ce, 0x681c, 0x70da, 0x6c1e, 0x2091, + 0x8001, 0x0804, 0x13b3, 0x2091, 0x8001, 0x0804, 0x13ad, 0x77c4, + 0x080c, 0x1b5f, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, + 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0804, 0x13b0, 0x70c4, + 0x2061, 0x4540, 0x6118, 0x601a, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x1904, 0x13b2, 0x70c8, 0x2061, 0x4580, 0x6218, 0x601a, 0x0804, + 0x13b1, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x1a04, 0x13ac, + 0x080c, 0x2397, 0xa384, 0x4000, 0x0110, 0xa295, 0x0020, 0x0804, + 0x13b0, 0x77c4, 0x080c, 0x1b5f, 0x2091, 0x8000, 0x6a08, 0xc28d, + 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0804, 0x13b1, 0x77c4, 0x080c, + 0x1b5f, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, + 0xa005, 0x0110, 0x080c, 0x2296, 0x2091, 0x8001, 0x2708, 0x0804, + 0x13b1, 0x77c4, 0x080c, 0x1b5f, 0x2091, 0x8000, 0x6a08, 0xc295, + 0x6a0a, 0x6804, 0xa005, 0x0110, 0x080c, 0x2296, 0x2091, 0x8001, + 0x2708, 0x0804, 0x13b1, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, + 0x2051, 0x0020, 0x2091, 0x8000, 0x080c, 0x1b77, 0x2091, 0x8001, + 0x2708, 0x6a08, 0x0804, 0x13b1, 0x77c4, 0xd7fc, 0x0128, 0x080c, + 0x1aeb, 0x0138, 0x0804, 0x13b5, 0x080c, 0x1add, 0x0110, 0x0804, + 0x13b5, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x080c, 0x1bef, + 0x11e8, 0x6818, 0xa005, 0x01a0, 0x2708, 0x0076, 0x080c, 0x23b6, + 0x007e, 0x1170, 0x2001, 0x0015, 0xd7fc, 0x1118, 0x2061, 0x4540, + 0x0018, 0xc0fd, 0x2061, 0x4580, 0x782a, 0x2091, 0x8001, 0x0005, + 0x2091, 0x8001, 0x2001, 0x4005, 0x0804, 0x13b5, 0x2091, 0x8001, + 0x0804, 0x13b3, 0x77c4, 0xd7fc, 0x0128, 0x080c, 0x1aeb, 0x0138, + 0x0804, 0x13b5, 0x080c, 0x1add, 0x0110, 0x0804, 0x13b5, 0x77c6, + 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, + 0x080c, 0x1b77, 0x2009, 0x0016, 0xd7fc, 0x1118, 0x2061, 0x4540, + 0x0018, 0x2061, 0x4580, 0xc1fd, 0x6063, 0x0003, 0x607b, 0x0000, + 0x6772, 0x607f, 0x000f, 0x792a, 0x080c, 0x2296, 0x2091, 0x8001, + 0x0005, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xd7fc, 0x0128, 0x080c, + 0x1aeb, 0x0138, 0x0804, 0x13b5, 0x080c, 0x1add, 0x0110, 0x0804, + 0x13b5, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, + 0x1118, 0x2061, 0x4540, 0x0018, 0x2061, 0x4580, 0xc1fd, 0x607b, + 0x0000, 0x6063, 0x0002, 0x6772, 0x607f, 0x000f, 0x792a, 0x080c, + 0x2296, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, + 0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, 0x0118, 0x60d0, 0xc0fd, + 0x60d2, 0x080c, 0x1b77, 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, + 0x1dc0, 0x2091, 0x8001, 0x0005, 0x2019, 0x0000, 0x72c8, 0xd284, + 0x0128, 0x080c, 0x1aeb, 0x0138, 0x0804, 0x13b5, 0x080c, 0x1add, + 0x0110, 0x0804, 0x13b5, 0x72c8, 0x72ca, 0x78ac, 0xa084, 0x0003, + 0x1508, 0x2039, 0x0000, 0xd284, 0x0108, 0xc7fd, 0x2041, 0x0021, + 0x2049, 0x0004, 0x2051, 0x0008, 0x080c, 0x1b5f, 0x2091, 0x8000, + 0x6808, 0xc0d4, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, + 0x001f, 0x1d90, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, + 0x0f00, 0x1d50, 0x2091, 0x8000, 0x72c8, 0x2069, 0x0100, 0xd284, + 0x1110, 0x2069, 0x0200, 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, + 0xd0b4, 0x01b0, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, + 0x0110, 0x1f04, 0x18a6, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, + 0xd084, 0x0110, 0x1f04, 0x18af, 0x20a9, 0x00fa, 0x1f04, 0x18b6, + 0x2079, 0x4500, 0x2009, 0x0018, 0x72c8, 0xd284, 0x1118, 0x2061, + 0x4540, 0x0018, 0x2061, 0x4580, 0xc1fd, 0x607b, 0x0000, 0x792a, + 0x6063, 0x0001, 0x607f, 0x000f, 0x60a3, 0x0000, 0x60a4, 0x60ae, + 0x60b2, 0x60d0, 0xd0b4, 0x0160, 0xc0b4, 0x60d2, 0x00c6, 0x60b4, + 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, + 0x60d0, 0xa084, 0x7eff, 0x60d2, 0x78ac, 0xc08d, 0x78ae, 0x83ff, + 0x0108, 0x0005, 0x681b, 0x0054, 0x2091, 0x8001, 0x0005, 0x73cc, + 0x080c, 0x185e, 0x69ec, 0x6a48, 0xa185, 0x1800, 0x684a, 0xa185, + 0x0040, 0x68ee, 0x73cc, 0x2021, 0x0004, 0x20a9, 0x09ff, 0x1f04, + 0x18ff, 0x8421, 0x1dd0, 0x8319, 0x1db0, 0x69ee, 0x6a4a, 0x2091, + 0x8001, 0x0005, 0xd7fc, 0x1118, 0x2069, 0x4540, 0x0010, 0x2069, + 0x4580, 0x71c4, 0x71c6, 0x6916, 0x81ff, 0x1110, 0x68a3, 0x0001, + 0x78ac, 0xc08c, 0x78ae, 0xd084, 0x1110, 0x080c, 0x1c42, 0x0005, + 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0018, 0x2029, 0x0000, 0x2520, + 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4500, + 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x080c, 0x1b3c, 0x0904, 0x1a17, + 0x20a9, 0x0005, 0x20a1, 0x4514, 0x2091, 0x8000, 0x41a1, 0x2091, + 0x8001, 0x2009, 0x0040, 0x080c, 0x1d0b, 0x0120, 0x080c, 0x1b44, + 0x0804, 0x1a17, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, 0x1120, + 0x0006, 0x080c, 0x2046, 0x000e, 0xa084, 0xff00, 0x8007, 0x8009, + 0x0904, 0x19c2, 0x00c6, 0x2c68, 0x080c, 0x1b3c, 0x05a8, 0x2c00, + 0x689e, 0x8109, 0x1dc0, 0x609f, 0x0000, 0x00ce, 0x00c6, 0x7ddc, + 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, + 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x2c68, + 0x689c, 0xa065, 0x0904, 0x19c1, 0x2009, 0x0040, 0x080c, 0x1d0b, + 0x1550, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x1168, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x000a, 0x1120, 0x0016, 0x080c, 0x2043, + 0x001e, 0x2d00, 0x6002, 0x0898, 0x00ce, 0x00c6, 0x609c, 0x080c, + 0x1bb8, 0x00ce, 0x609f, 0x0000, 0x080c, 0x1a1b, 0x2009, 0x0018, + 0x6008, 0xc0cd, 0x600a, 0x6004, 0x6086, 0x080c, 0x1af9, 0x080c, + 0x1b44, 0x0804, 0x1a17, 0x00ce, 0x00c6, 0x609c, 0x080c, 0x1bb8, + 0x00ce, 0x609f, 0x0000, 0x080c, 0x1a1b, 0x2009, 0x0018, 0x6087, + 0x0103, 0x601b, 0x0003, 0x080c, 0x1af9, 0x080c, 0x1b44, 0x0804, + 0x1a17, 0x00ce, 0x6114, 0xd1fc, 0x0120, 0x080c, 0x1aeb, 0x01b8, + 0x0018, 0x080c, 0x1add, 0x0198, 0x2029, 0x0000, 0x2520, 0x2009, + 0x0018, 0x73c8, 0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x080c, + 0x1af9, 0x080c, 0x1b44, 0x2001, 0x4007, 0x0804, 0x13b5, 0x74c4, + 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x00e6, 0x2009, 0x0012, + 0xd0fc, 0x1118, 0x2071, 0x4540, 0x0018, 0x2071, 0x4580, 0xc1fd, + 0x792a, 0x7063, 0x0005, 0x71d0, 0xc1c4, 0x71d2, 0x7366, 0x726a, + 0x746e, 0x7072, 0x7077, 0x0000, 0x2c00, 0x707a, 0xa02e, 0x2530, + 0x611c, 0xa184, 0x0060, 0x0110, 0x080c, 0x3f66, 0x00ee, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x6714, - 0x6023, 0x0000, 0x080c, 0x2233, 0x2091, 0x8001, 0x0005, 0x70c3, - 0x4005, 0x0804, 0x13a6, 0x20a9, 0x0005, 0x2099, 0x4314, 0x2091, + 0x6023, 0x0000, 0x080c, 0x2296, 0x2091, 0x8001, 0x0005, 0x70c3, + 0x4005, 0x0804, 0x13b6, 0x20a9, 0x0005, 0x2099, 0x4514, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0005, 0x71c4, 0x70c7, 0x0000, - 0x791e, 0x0804, 0x13a3, 0x71c4, 0x71c6, 0x2168, 0x0010, 0x2069, + 0x791e, 0x0804, 0x13b3, 0x71c4, 0x71c6, 0x2168, 0x0010, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x1dd8, 0xa285, 0x0000, 0x1118, 0x70c3, 0x4000, 0x0010, 0x70c3, 0x4003, - 0x70ca, 0x0804, 0x13a6, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, - 0x1a04, 0x139c, 0x7966, 0x0804, 0x13a3, 0x7964, 0x71c6, 0x0804, - 0x13a3, 0x7900, 0x71c6, 0x71c4, 0x7902, 0x0804, 0x13a3, 0x7900, - 0x71c6, 0x0804, 0x13a3, 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, + 0x70ca, 0x0804, 0x13b6, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, + 0x1a04, 0x13ac, 0x7966, 0x0804, 0x13b3, 0x7964, 0x71c6, 0x0804, + 0x13b3, 0x7900, 0x71c6, 0x71c4, 0x7902, 0x0804, 0x13b3, 0x7900, + 0x71c6, 0x0804, 0x13b3, 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0160, 0x810c, 0x0230, 0x8210, 0x810c, 0x810c, 0x0210, 0x8210, - 0x810c, 0x81ff, 0x1904, 0x139d, 0x8210, 0x7a0e, 0xd28c, 0x0538, + 0x810c, 0x81ff, 0x1904, 0x13ad, 0x8210, 0x7a0e, 0xd28c, 0x0538, 0x7910, 0xc1cd, 0x7912, 0x2009, 0x0021, 0x2019, 0x0003, 0xd284, - 0x01c0, 0x8108, 0x2019, 0x0041, 0x2011, 0x8b4e, 0x2312, 0x2019, + 0x01c0, 0x8108, 0x2019, 0x0041, 0x2011, 0x8d4e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, - 0x0006, 0x2011, 0x8b53, 0x2112, 0x2011, 0x8b73, 0x2312, 0x7904, - 0x7806, 0x0804, 0x13a2, 0x7804, 0x70c6, 0x0804, 0x13a3, 0x71c4, - 0xd1fc, 0x1118, 0x2011, 0x47c0, 0x0010, 0x2011, 0x4840, 0x8107, + 0x0006, 0x2011, 0x8d53, 0x2112, 0x2011, 0x8d73, 0x2312, 0x7904, + 0x7806, 0x0804, 0x13b2, 0x7804, 0x70c6, 0x0804, 0x13b3, 0x71c4, + 0xd1fc, 0x1118, 0x2011, 0x49c0, 0x0010, 0x2011, 0x4a40, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x2011, 0x0000, 0x6814, 0xd0fc, 0x0110, 0xa295, 0x0200, 0xd0b4, 0x0110, 0xa295, - 0x0001, 0x6b0c, 0x0804, 0x13a0, 0x0016, 0x7814, 0xd0f4, 0x0138, - 0x2001, 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0050, 0xd0fc, - 0x0138, 0x2001, 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0008, - 0xa006, 0x001e, 0x0005, 0x0016, 0x7814, 0xd0f4, 0x0138, 0x2001, - 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0008, 0xa006, 0x001e, - 0x0005, 0x0016, 0x7814, 0xd0fc, 0x0138, 0x2001, 0x4007, 0x70db, - 0x0001, 0xa18d, 0x0001, 0x0008, 0xa006, 0x001e, 0x0005, 0x7112, - 0x721a, 0x731e, 0x7810, 0xd0c4, 0x0110, 0x7422, 0x7526, 0xac80, - 0x0001, 0x8108, 0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, - 0x0000, 0x6084, 0x20a2, 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, - 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, - 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, - 0xa006, 0xa211, 0x7d10, 0xd5c4, 0x0120, 0x7b84, 0xa319, 0x7c80, - 0xa421, 0x7008, 0xd0fc, 0x0de8, 0x7003, 0x0001, 0x7007, 0x0006, - 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0110, 0x7322, 0x7426, 0xa084, - 0x01e0, 0x0005, 0x7848, 0xa065, 0x0120, 0x2c04, 0x784a, 0x2063, - 0x0000, 0x0005, 0x00f6, 0x2079, 0x4300, 0x7848, 0x2062, 0x2c00, - 0xa005, 0x1110, 0x080c, 0x243b, 0x784a, 0x00fe, 0x0005, 0x2011, - 0x8d00, 0x7a4a, 0x7bc4, 0x8319, 0x0128, 0xa280, 0x0032, 0x2012, - 0x2010, 0x0cc8, 0x2013, 0x0000, 0x0005, 0x0016, 0x0026, 0xd7fc, - 0x1118, 0x2011, 0x48c0, 0x0010, 0x2011, 0x68c0, 0xa784, 0x0f00, - 0x800b, 0xa784, 0x001f, 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, - 0xa105, 0xa268, 0x002e, 0x001e, 0x0005, 0x0c39, 0x2900, 0x682a, - 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, 0x690a, 0x00e6, - 0xd7fc, 0x1128, 0x2009, 0x4353, 0x2071, 0x4340, 0x0020, 0x2009, - 0x4393, 0x2071, 0x4380, 0x210c, 0x6804, 0xa005, 0x0148, 0xa116, - 0x1138, 0x2060, 0x6000, 0x6806, 0x0016, 0x200b, 0x0000, 0x0018, - 0x2009, 0x0000, 0x0016, 0x6804, 0xa065, 0x0178, 0x6000, 0x6806, - 0x0421, 0x080c, 0x1d30, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, - 0x6812, 0x1d88, 0x7910, 0xc1a5, 0x7912, 0x001e, 0x6902, 0x6906, - 0x2d00, 0x2060, 0x080c, 0x2580, 0x00ee, 0x0005, 0xa065, 0x0160, - 0x2008, 0x609c, 0xa005, 0x0128, 0x2062, 0x609f, 0x0000, 0xa065, - 0x0cc0, 0x7848, 0x794a, 0x2062, 0x0005, 0x6007, 0x0103, 0x608f, - 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, - 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022, 0x0005, 0x00e6, 0xd7fc, - 0x1128, 0x2071, 0x4340, 0x2031, 0x43c0, 0x0020, 0x2071, 0x4380, - 0x2031, 0x45c0, 0x7050, 0xa08c, 0x0200, 0x1128, 0xa608, 0x2d0a, - 0x8000, 0x7052, 0xa006, 0x00ee, 0x0005, 0x00f6, 0xd7fc, 0x1118, - 0x2079, 0x4340, 0x0010, 0x2079, 0x4380, 0x080c, 0x1b1d, 0x2091, - 0x8000, 0x6804, 0x780a, 0xa065, 0x0904, 0x1bfe, 0x0030, 0x2c00, - 0x780a, 0x2060, 0x6000, 0xa065, 0x05c8, 0x6010, 0xa306, 0x1db8, - 0x600c, 0xa206, 0x1da0, 0x2c28, 0x784c, 0xac06, 0x1108, 0x0458, - 0x6804, 0xac06, 0x1140, 0x6000, 0x2060, 0x6806, 0xa005, 0x1118, - 0x6803, 0x0000, 0x0048, 0x6400, 0x7808, 0x2060, 0x6402, 0xa486, - 0x0000, 0x1110, 0x2c00, 0x6802, 0x2560, 0x00fe, 0x080c, 0x1b85, - 0x00f6, 0x601b, 0x0005, 0x6023, 0x0020, 0x00fe, 0x080c, 0x1d30, - 0x00f6, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, 0x6812, 0x1118, - 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, 0x00fe, 0x0005, - 0x0076, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0108, 0xc7fd, 0x2041, - 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x080c, - 0x1b35, 0x8738, 0xa784, 0x001f, 0x1dd0, 0xa7bc, 0xff00, 0x873f, - 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d90, 0x2091, 0x8001, 0x007e, - 0x0005, 0x786c, 0x2009, 0x8b74, 0x210c, 0xa10d, 0x0118, 0xa065, - 0x0804, 0x1ffe, 0x2061, 0x0000, 0x6018, 0xd084, 0x11b8, 0x7810, - 0xd08c, 0x0130, 0xc08c, 0x7812, 0xc7fc, 0x2069, 0x4340, 0x0028, - 0xc08d, 0x7812, 0x2069, 0x4380, 0xc7fd, 0x2091, 0x8000, 0x681c, - 0x681f, 0x0000, 0x2091, 0x8001, 0xa005, 0x1108, 0x0005, 0xa08c, - 0xfff0, 0x0110, 0x080c, 0x243b, 0x0002, 0x1c5d, 0x1c60, 0x1c66, - 0x1c6a, 0x1c5e, 0x1c6e, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c73, 0x1c9f, - 0x1ca2, 0x1ca7, 0x1c5e, 0x1c5e, 0x1c5e, 0x0005, 0x080c, 0x243b, - 0x080c, 0x1c00, 0x2001, 0x8001, 0x0804, 0x1cb0, 0x2001, 0x8003, - 0x0804, 0x1cb0, 0x2001, 0x8004, 0x0804, 0x1cb0, 0x080c, 0x1c00, - 0x2001, 0x8006, 0x04e8, 0x2091, 0x8000, 0x0076, 0xd7fc, 0x1128, - 0x2069, 0x4340, 0x2039, 0x0009, 0x0020, 0x2069, 0x4380, 0x2039, - 0x0009, 0x6800, 0xa086, 0x0000, 0x0128, 0x000e, 0x6f1e, 0x2091, - 0x8001, 0x0005, 0x6874, 0x007e, 0xa0bc, 0xff00, 0x2041, 0x0021, - 0x2049, 0x0004, 0x2051, 0x0010, 0x080c, 0x1b35, 0x8738, 0xa784, - 0x001f, 0x1dd0, 0x2091, 0x8001, 0x2001, 0x800a, 0x0088, 0x2001, - 0x800c, 0x0070, 0x080c, 0x1c00, 0x2001, 0x800d, 0x0048, 0xd7fc, - 0x0110, 0x78ec, 0x0008, 0x78e4, 0x70c6, 0x2001, 0x800e, 0x0000, - 0x70c2, 0xd7fc, 0x1118, 0x70db, 0x0000, 0x0010, 0x70db, 0x0001, - 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x0005, 0xac80, - 0x0001, 0x81ff, 0x0518, 0x2099, 0x0030, 0x20a0, 0x700c, 0xa084, - 0x07ff, 0x0100, 0x7018, 0x0006, 0x701c, 0x0006, 0x7020, 0x0006, - 0x7024, 0x0006, 0x7112, 0x81ac, 0x721a, 0x731e, 0x7422, 0x7526, - 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, 0x800b, 0x1ee8, 0x7007, - 0x0002, 0xa08c, 0x01e0, 0x1110, 0x53a5, 0xa006, 0x7003, 0x0000, - 0x7007, 0x0004, 0x000e, 0x7026, 0x000e, 0x7022, 0x000e, 0x701e, - 0x000e, 0x701a, 0x0005, 0x2011, 0x0020, 0x2009, 0x0010, 0x6b0a, - 0x6c0e, 0x681f, 0x0201, 0x6803, 0xfd20, 0x6807, 0x0038, 0x6a1a, - 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, 0x1d80, 0x0005, - 0x70ec, 0xd0dc, 0x1520, 0x2029, 0x0001, 0x7814, 0xd0cc, 0x1160, - 0x70ec, 0xd0e4, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1120, 0x2019, - 0x0c0c, 0x2021, 0x000c, 0x0070, 0x70ec, 0xd0e4, 0x1128, 0x2019, - 0x1c0c, 0x2021, 0x000c, 0x0030, 0x2019, 0x1c09, 0x2021, 0x0009, - 0xa5ad, 0x0200, 0x6b0a, 0x6c0e, 0x6d1e, 0x6807, 0x0038, 0x0005, - 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, 0x7868, 0xa005, 0x796a, - 0x0110, 0x2c02, 0x0008, 0x796e, 0x0005, 0x00c6, 0x2061, 0x4300, - 0x6887, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, - 0x0110, 0x2d02, 0x0008, 0x616e, 0x00ce, 0x0005, 0x2091, 0x8000, - 0x2c04, 0x786e, 0xa005, 0x1108, 0x786a, 0x2091, 0x8001, 0x609c, - 0xa005, 0x0188, 0x00c6, 0x2060, 0x2008, 0x609c, 0xa005, 0x0138, - 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, 0xa005, 0x1dc8, 0x7848, - 0x794a, 0x2062, 0x00ce, 0x7848, 0x2062, 0x609f, 0x0000, 0xac85, - 0x0000, 0x1110, 0x080c, 0x243b, 0x784a, 0x0005, 0x20a9, 0x0010, - 0xa006, 0x8004, 0x8086, 0x818e, 0x1208, 0xa200, 0x1f04, 0x1d7a, - 0x8086, 0x818e, 0x0005, 0x0156, 0x20a9, 0x0010, 0xa005, 0x01b8, - 0xa11a, 0x12a8, 0x8213, 0x818d, 0x0228, 0xa11a, 0x1220, 0x1f04, - 0x1d8a, 0x0028, 0xa11a, 0x2308, 0x8210, 0x1f04, 0x1d8a, 0x0006, - 0x3200, 0xa084, 0xefff, 0x2080, 0x000e, 0x015e, 0x0005, 0x0006, - 0x3200, 0xa085, 0x1000, 0x0cb8, 0x7d74, 0x70d0, 0xa506, 0x0904, - 0x1e5b, 0x7810, 0x2050, 0x7800, 0xd08c, 0x0100, 0x080c, 0x1afa, - 0x0904, 0x1e5b, 0xa046, 0x7970, 0x2500, 0x8000, 0xa112, 0x2009, - 0x0040, 0x1208, 0x0030, 0x72d0, 0xa206, 0x0118, 0x8840, 0x2009, - 0x0080, 0x00c6, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, - 0x0020, 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0110, - 0x080c, 0x1afa, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002, 0x2091, - 0x8001, 0xa08c, 0x01e0, 0x1538, 0x53a5, 0x8cff, 0x1120, 0x88ff, - 0x0904, 0x1e48, 0x0050, 0x2c00, 0x788e, 0x20a9, 0x0020, 0xac80, - 0x0001, 0x20a0, 0x53a5, 0x0804, 0x1e48, 0xa046, 0x7218, 0x731c, - 0xdac4, 0x0110, 0x7420, 0x7524, 0xa292, 0x0040, 0xa39b, 0x0000, - 0xa4a3, 0x0000, 0xa5ab, 0x0000, 0x721a, 0x731e, 0xdac4, 0x0118, - 0x7422, 0x7526, 0xa006, 0x7007, 0x0004, 0x0904, 0x1e48, 0x8cff, - 0x0110, 0x080c, 0x1b02, 0x00ce, 0x080c, 0x1b02, 0xa046, 0x7888, - 0x8000, 0x788a, 0xa086, 0x0002, 0x01c0, 0x7a7c, 0x7b78, 0xdac4, - 0x0110, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, 0xa210, - 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, 0x731e, - 0xdac4, 0x0588, 0x7422, 0x7526, 0x0470, 0x6014, 0xd0fc, 0x1118, - 0x2069, 0x4340, 0x0010, 0x2069, 0x4380, 0x2091, 0x8000, 0x681f, - 0x0002, 0x88ff, 0x0120, 0xa046, 0x788c, 0x2060, 0x0c70, 0x788b, - 0x0000, 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0098, - 0x00ce, 0x788b, 0x0000, 0x080c, 0x1fb9, 0x6004, 0xa084, 0x000f, - 0x0059, 0x88ff, 0x0130, 0x788c, 0x2060, 0x6004, 0xa084, 0x000f, - 0x0019, 0x0804, 0x1da4, 0x0005, 0x0002, 0x1e6d, 0x1e88, 0x1ea1, - 0x1e6d, 0x1eae, 0x1e7e, 0x1e6d, 0x1e6d, 0x1e6d, 0x1e86, 0x1e9f, - 0x1e6d, 0x1e6d, 0x1e6d, 0x1e6d, 0x1e6d, 0x2039, 0x0400, 0x78bc, - 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, 0x080c, 0x1eea, 0x609c, - 0x78ba, 0x609f, 0x0000, 0x080c, 0x1fa5, 0x0005, 0x78bc, 0xd0c4, - 0x0108, 0x0c58, 0x601c, 0xc0bd, 0x601e, 0x0030, 0x080c, 0x1fe3, - 0x78bc, 0xd0c4, 0x0108, 0x0c08, 0x78bf, 0x0000, 0x6004, 0x8007, - 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0138, 0x080c, 0x1eea, 0x0120, - 0x78bc, 0xc0c5, 0x78be, 0x0010, 0x0804, 0x1f05, 0x0005, 0x080c, - 0x1fe0, 0x78bc, 0xa08c, 0x0e00, 0x1110, 0xd0c4, 0x1108, 0x0828, - 0x080c, 0x1eea, 0x1110, 0x0804, 0x1f05, 0x0005, 0x78bc, 0xd0c4, - 0x0110, 0x0804, 0x1e6d, 0x78bf, 0x0000, 0x6714, 0x2011, 0x0001, - 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0188, 0xa7bc, 0xff00, - 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0150, 0xa7bc, 0x8000, 0x2011, - 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0108, 0x00c0, 0x080c, - 0x1b1d, 0x2d00, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, - 0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, - 0x1f04, 0x1ed2, 0x8211, 0x0118, 0x20a9, 0x0100, 0x0c58, 0x080c, - 0x1b02, 0x0005, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, - 0x1110, 0x78ba, 0x0038, 0x689e, 0x2d00, 0x6002, 0x78b8, 0xad06, - 0x1108, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x1130, 0x78bc, 0xc0c4, - 0x78be, 0x78b8, 0x2060, 0xa006, 0x0005, 0x00e6, 0xa02e, 0x2530, - 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, 0x2048, 0xa984, - 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0110, 0x080c, 0x3de5, 0x6596, - 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, 0x4380, 0xd7fc, 0x1110, - 0x2071, 0x4340, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x0120, - 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, - 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, - 0x60c2, 0x2091, 0x8000, 0x6e08, 0xd684, 0x0170, 0xd9fc, 0x1160, - 0x2091, 0x8001, 0x080c, 0x1b85, 0x2091, 0x8000, 0x080c, 0x1d30, - 0x2091, 0x8001, 0x0804, 0x1fa3, 0x6024, 0xa096, 0x0001, 0x1110, - 0x8000, 0x6026, 0x6a10, 0x6814, 0xa202, 0x0268, 0x0160, 0x2091, - 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x080c, - 0x1fa5, 0x0804, 0x1fa3, 0x2c08, 0xd9fc, 0x01f0, 0x6800, 0xa065, - 0x01d8, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0168, 0x704c, 0xa206, - 0x1150, 0x6b04, 0x2160, 0x2304, 0x6002, 0xa005, 0x1108, 0x6902, - 0x2260, 0x6102, 0x0098, 0x2d00, 0x2060, 0x080c, 0x2580, 0x6e08, - 0x2160, 0x6202, 0x6906, 0x0050, 0x6800, 0x6902, 0xa065, 0x0110, - 0x6102, 0x0008, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160, 0xd9fc, - 0x0118, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, 0x7d08, 0x8528, 0x7d0a, - 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, 0x0128, 0xa6b6, 0x0040, - 0x6e0a, 0x080c, 0x1b96, 0x00ee, 0x0005, 0x6008, 0xa705, 0x600a, - 0x2091, 0x8000, 0x080c, 0x1d30, 0x2091, 0x8001, 0x78b8, 0xa065, - 0x0128, 0x609c, 0x78ba, 0x609f, 0x0000, 0x0c78, 0x78b6, 0x78ba, - 0x0005, 0x7970, 0x7874, 0x2818, 0xd384, 0x0118, 0x8000, 0xa112, - 0x0220, 0x8000, 0xa112, 0x1278, 0xc384, 0x7a7c, 0x721a, 0x7a78, - 0x721e, 0xdac4, 0x0120, 0x7a84, 0x7222, 0x7a80, 0x7226, 0xa006, - 0xd384, 0x0108, 0x8000, 0x7876, 0x70d2, 0x781c, 0xa005, 0x0138, - 0x8001, 0x781e, 0x1120, 0x0e04, 0x1fdf, 0x2091, 0x4080, 0x0005, - 0x2039, 0x1ff5, 0x0010, 0x2039, 0x1ffb, 0x2704, 0xa005, 0x0160, - 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, 0x680a, 0x690c, 0x6814, - 0x6916, 0x680e, 0x8738, 0x0c88, 0x0005, 0x0003, 0x0009, 0x000f, - 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x2041, 0x0000, - 0x780c, 0x0002, 0x21a7, 0x2182, 0x2006, 0x2076, 0x2039, 0x8b74, - 0x2734, 0x7d10, 0x00c0, 0x6084, 0xa086, 0x0103, 0x1904, 0x2060, - 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, 0x11d8, 0x0804, 0x2060, - 0x8603, 0xa080, 0x8b55, 0x620c, 0x2202, 0x8000, 0x6210, 0x2202, - 0x080c, 0x1d4e, 0x8630, 0xa68e, 0x000f, 0x0904, 0x20e1, 0x786c, - 0xa065, 0x1d08, 0x7808, 0xa602, 0x1220, 0xd5ac, 0x1110, 0x263a, - 0x0005, 0xa682, 0x0003, 0x1a04, 0x20e1, 0x2091, 0x8000, 0x2069, - 0x0000, 0x6818, 0xd084, 0x11f8, 0x2011, 0x8b55, 0x2204, 0x70c6, - 0x8210, 0x2204, 0x70ca, 0xd684, 0x1130, 0x8210, 0x2204, 0x70da, - 0x8210, 0x2204, 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001, - 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, - 0x203b, 0x0000, 0x0005, 0x7810, 0xc0ad, 0x7812, 0x0804, 0x20e1, - 0x263a, 0x080c, 0x21ad, 0x1904, 0x21c9, 0x786c, 0xa065, 0x1904, - 0x200b, 0x2091, 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0108, - 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0804, 0x21c9, 0x2039, 0x8b74, - 0x2734, 0x7d10, 0x00a0, 0x6084, 0xa086, 0x0103, 0x1904, 0x20cb, - 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, 0x11b8, 0x0804, 0x20cb, - 0xa680, 0x8b55, 0x620c, 0x2202, 0x080c, 0x1d4e, 0x8630, 0xa68e, - 0x001e, 0x0904, 0x20e1, 0x786c, 0xa065, 0x1d28, 0x7808, 0xa602, - 0x1220, 0xd5ac, 0x1110, 0x263a, 0x0005, 0xa682, 0x0006, 0x1a04, - 0x20e1, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x11f8, - 0x2011, 0x8b55, 0x2009, 0x8b4e, 0x26a8, 0x211c, 0x2204, 0x201a, - 0x8108, 0x8210, 0x1f04, 0x20ad, 0xa685, 0x8030, 0x70c2, 0x681b, - 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, - 0x8001, 0xa006, 0x2009, 0x8b75, 0x200a, 0x203a, 0x0005, 0x7810, - 0xc0ad, 0x7812, 0x00b0, 0x263a, 0x080c, 0x21ad, 0x1904, 0x21c9, - 0x786c, 0xa065, 0x1904, 0x207b, 0x2091, 0x8000, 0x7810, 0xa084, - 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0804, - 0x21c9, 0x2091, 0x8000, 0x7007, 0x0004, 0x7994, 0x70d4, 0xa102, - 0x0228, 0x0168, 0x7b90, 0xa302, 0x1150, 0x0010, 0x8002, 0x1138, - 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0005, 0xa184, - 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, - 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, 0x7a9c, 0xa210, 0x721a, - 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0130, 0x7aa4, 0xa211, - 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, 0x0030, 0x7003, 0x0000, - 0x2009, 0x8b54, 0x260a, 0x8109, 0x2198, 0x2104, 0xd084, 0x0108, - 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, 0x8603, 0x7012, 0x7007, - 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a, 0x1208, 0xa006, 0x2028, + 0x0001, 0x6b0c, 0x6800, 0x70da, 0x0804, 0x13b0, 0x0016, 0x7814, + 0xd0f4, 0x0138, 0x2001, 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, + 0x0050, 0xd0fc, 0x0138, 0x2001, 0x4007, 0x70db, 0x0001, 0xa18d, + 0x0001, 0x0008, 0xa006, 0x001e, 0x0005, 0x0016, 0x7814, 0xd0f4, + 0x0138, 0x2001, 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0008, + 0xa006, 0x001e, 0x0005, 0x0016, 0x7814, 0xd0fc, 0x0138, 0x2001, + 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0008, 0xa006, 0x001e, + 0x0005, 0x7112, 0x721a, 0x731e, 0x7810, 0xd0c4, 0x0110, 0x7422, + 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, 0x8098, 0x20a1, + 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, 0x797c, - 0xa108, 0x7a78, 0xa006, 0xa211, 0xd4c4, 0x0120, 0x7b84, 0xa319, - 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0de8, 0xa084, 0x01e0, 0x01d0, - 0x7d10, 0x2031, 0x8b54, 0x2634, 0x78a8, 0x8000, 0x78aa, 0xd08c, - 0x1138, 0x7007, 0x0006, 0x7004, 0xd094, 0x1de8, 0x0804, 0x20e3, - 0x2069, 0x4347, 0x206b, 0x0003, 0x78ac, 0xa085, 0x0300, 0x78ae, - 0xa006, 0x0048, 0x2030, 0x75d6, 0x2091, 0x4080, 0x7d96, 0x7d10, - 0xa5ac, 0xffcf, 0x7d12, 0x2091, 0x8001, 0x78aa, 0x7007, 0x0006, - 0x263a, 0x7003, 0x0001, 0x711a, 0x721e, 0xd5c4, 0x0110, 0x7322, - 0x7426, 0x0005, 0x6084, 0xa086, 0x0103, 0x11d8, 0x6114, 0x6018, - 0xa105, 0x11b8, 0x2069, 0x0000, 0x6818, 0xd084, 0x1190, 0x600c, - 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, 0x2091, - 0x4080, 0x080c, 0x1d4e, 0x0e04, 0x21a0, 0x786c, 0xa065, 0x1d10, - 0x0005, 0x0059, 0x1530, 0x786c, 0xa065, 0x19e0, 0x0410, 0x0029, - 0x1500, 0x786c, 0xa065, 0x1dd8, 0x00e0, 0x6084, 0xa086, 0x0103, - 0x1168, 0x6018, 0xc0fc, 0x601a, 0xa086, 0x0004, 0x1138, 0x7804, - 0xd0a4, 0x0120, 0x080c, 0x1d4e, 0xa006, 0x0005, 0x0079, 0x1118, - 0xa085, 0x0001, 0x0005, 0x00b9, 0x1110, 0x2041, 0x0001, 0x7d10, - 0x0005, 0x88ff, 0x0110, 0x2091, 0x4080, 0x0005, 0x7b90, 0x7994, - 0x70d4, 0xa102, 0x1118, 0xa385, 0x0000, 0x0005, 0x0210, 0xa302, - 0x0005, 0x8002, 0x0005, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c, - 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004, - 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa210, 0xa006, 0xa319, - 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, 0xa005, 0x0110, 0x2009, - 0x0040, 0x080c, 0x1ab7, 0x01d0, 0x78a8, 0x8000, 0x78aa, 0xd08c, - 0x1510, 0x6014, 0xd0fc, 0x1118, 0x2069, 0x4340, 0x0010, 0x2069, - 0x4380, 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab, 0x0000, 0x78ac, - 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, 0x0068, 0x78ab, 0x0000, - 0x080c, 0x1d4e, 0x7990, 0x7894, 0x8000, 0xa10a, 0x1208, 0xa006, - 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, 0x0005, - 0x2138, 0xd7fc, 0x1118, 0x2009, 0x4359, 0x0010, 0x2009, 0x4399, - 0x2091, 0x8000, 0x200a, 0x00f6, 0x2009, 0x4380, 0x2079, 0x0100, - 0xd7fc, 0x1120, 0x2009, 0x4340, 0x2079, 0x0200, 0x2104, 0xa086, - 0x0000, 0x1180, 0xd7fc, 0x1118, 0x2009, 0x4345, 0x0010, 0x2009, - 0x4385, 0x2104, 0xa005, 0x1130, 0x7830, 0xa084, 0x00c0, 0x1110, - 0x781b, 0x0052, 0x00fe, 0x0005, 0x2009, 0x0002, 0x2069, 0x4300, - 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x22a9, 0x2071, 0x4380, - 0x2079, 0x0100, 0x2021, 0x45bf, 0x784b, 0x000f, 0x2001, 0x01ff, - 0x2004, 0xd0fc, 0x0118, 0x2019, 0x3c3b, 0x0030, 0x20a1, 0x012b, - 0x2019, 0x3c3b, 0xd184, 0x0110, 0x20a1, 0x022b, 0x2304, 0xa005, - 0x0140, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, - 0x0ca8, 0x789b, 0x0000, 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, - 0x0000, 0x78af, 0x2020, 0x1f04, 0x2287, 0x7003, 0x0000, 0x0016, - 0xd18c, 0x2009, 0x0000, 0x0108, 0xc1bd, 0x080c, 0x23bd, 0x001e, - 0x7020, 0xa084, 0x000f, 0xa085, 0x6300, 0x7806, 0x780f, 0x9000, - 0x7843, 0x00d8, 0x7853, 0x0090, 0x780b, 0x0308, 0x7456, 0x7053, - 0x0000, 0x8109, 0x0140, 0x2071, 0x4340, 0x2079, 0x0200, 0x2021, - 0x43bf, 0x0804, 0x2264, 0x0005, 0x0016, 0x2011, 0x0101, 0xd1bc, - 0x1110, 0x2011, 0x0201, 0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, - 0xa105, 0x2012, 0x001e, 0x080c, 0x23bd, 0x0005, 0x2011, 0x0101, - 0xd3fc, 0x1110, 0x2011, 0x0201, 0x20a9, 0x0009, 0x810b, 0x1f04, - 0x22ce, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, - 0x0005, 0x2019, 0x0002, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, - 0x1f04, 0x22df, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, - 0x200a, 0x8319, 0x0118, 0x2009, 0x0201, 0x0c78, 0x0005, 0x2011, - 0x0101, 0xd3fc, 0x1110, 0x2011, 0x0201, 0x20a9, 0x000c, 0x810b, - 0x1f04, 0x22f7, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, - 0x2012, 0x0005, 0x2011, 0x0102, 0xd3fc, 0x1110, 0x2011, 0x0202, - 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x0005, 0x00c6, 0x2061, - 0x0100, 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, - 0xa080, 0x0020, 0x609a, 0x62ac, 0x63ac, 0x00ce, 0x0005, 0x00c6, + 0xa108, 0x7a78, 0xa006, 0xa211, 0x7d10, 0xd5c4, 0x0120, 0x7b84, + 0xa319, 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0de8, 0x7003, 0x0001, + 0x7007, 0x0006, 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0110, 0x7322, + 0x7426, 0xa084, 0x01e0, 0x0005, 0x7848, 0xa065, 0x0120, 0x2c04, + 0x784a, 0x2063, 0x0000, 0x0005, 0x00f6, 0x2079, 0x4500, 0x7848, + 0x2062, 0x2c00, 0xa005, 0x1110, 0x080c, 0x252b, 0x784a, 0x00fe, + 0x0005, 0x2011, 0x8f00, 0x7a4a, 0x7bc4, 0x8319, 0x0128, 0xa280, + 0x0032, 0x2012, 0x2010, 0x0cc8, 0x2013, 0x0000, 0x0005, 0x0016, + 0x0026, 0xd7fc, 0x1118, 0x2011, 0x4ac0, 0x0010, 0x2011, 0x6ac0, + 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x0120, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0xa268, 0x002e, 0x001e, 0x0005, 0x0c39, + 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, + 0x690a, 0x00e6, 0xd7fc, 0x1128, 0x2009, 0x4552, 0x2071, 0x4540, + 0x0020, 0x2009, 0x4592, 0x2071, 0x4580, 0x210c, 0x6804, 0xa005, + 0x0148, 0xa116, 0x1138, 0x2060, 0x6000, 0x6806, 0x0016, 0x200b, + 0x0000, 0x0018, 0x2009, 0x0000, 0x0016, 0x6804, 0xa065, 0x0178, + 0x6000, 0x6806, 0x0421, 0x080c, 0x1d7c, 0x6810, 0x7908, 0x8109, + 0x790a, 0x8001, 0x6812, 0x1d88, 0x7910, 0xc1a5, 0x7912, 0x001e, + 0x6902, 0x6906, 0x2d00, 0x2060, 0x080c, 0x2672, 0x00ee, 0x0005, + 0xa065, 0x0160, 0x2008, 0x609c, 0xa005, 0x0128, 0x2062, 0x609f, + 0x0000, 0xa065, 0x0cc0, 0x7848, 0x794a, 0x2062, 0x0005, 0x6007, + 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005, 0x20a0, + 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022, 0x0005, + 0x00e6, 0xd7fc, 0x1128, 0x2071, 0x4540, 0x2031, 0x45c0, 0x0020, + 0x2071, 0x4580, 0x2031, 0x47c0, 0x704c, 0xa08c, 0x0200, 0x1128, + 0xa608, 0x2d0a, 0x8000, 0x704e, 0xa006, 0x00ee, 0x0005, 0x00f6, + 0xd7fc, 0x1118, 0x2079, 0x4540, 0x0010, 0x2079, 0x4580, 0x080c, + 0x1b5f, 0x2091, 0x8000, 0x6804, 0x780a, 0xa065, 0x0904, 0x1c40, + 0x0030, 0x2c00, 0x780a, 0x2060, 0x6000, 0xa065, 0x05c8, 0x6010, + 0xa306, 0x1db8, 0x600c, 0xa206, 0x1da0, 0x2c28, 0x7848, 0xac06, + 0x1108, 0x0458, 0x6804, 0xac06, 0x1140, 0x6000, 0x2060, 0x6806, + 0xa005, 0x1118, 0x6803, 0x0000, 0x0048, 0x6400, 0x7808, 0x2060, + 0x6402, 0xa486, 0x0000, 0x1110, 0x2c00, 0x6802, 0x2560, 0x00fe, + 0x080c, 0x1bc7, 0x00f6, 0x601b, 0x0005, 0x6023, 0x0020, 0x00fe, + 0x080c, 0x1d7c, 0x00f6, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, + 0x6812, 0x1118, 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, + 0x00fe, 0x0005, 0x0076, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0108, + 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, + 0x8000, 0x080c, 0x1b77, 0x8738, 0xa784, 0x001f, 0x1dd0, 0xa7bc, + 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d90, 0x2091, + 0x8001, 0x007e, 0x0005, 0x786c, 0x2009, 0x8d74, 0x210c, 0xa10d, + 0x0118, 0xa065, 0x0804, 0x2061, 0x2061, 0x0000, 0x6018, 0xd084, + 0x11b8, 0x7810, 0xd08c, 0x0130, 0xc08c, 0x7812, 0xc7fc, 0x2069, + 0x4540, 0x0028, 0xc08d, 0x7812, 0x2069, 0x4580, 0xc7fd, 0x2091, + 0x8000, 0x681c, 0x681f, 0x0000, 0x2091, 0x8001, 0xa005, 0x1108, + 0x0005, 0xa08c, 0xfff0, 0x0110, 0x080c, 0x252b, 0x0002, 0x1c9f, + 0x1ca2, 0x1ca8, 0x1cac, 0x1ca0, 0x1cb0, 0x1ca0, 0x1ca0, 0x1ca0, + 0x1cb6, 0x1ce2, 0x1ce5, 0x1cea, 0x1cf3, 0x1ca0, 0x1ca0, 0x0005, + 0x080c, 0x252b, 0x080c, 0x1c42, 0x2001, 0x8001, 0x0804, 0x1cfc, + 0x2001, 0x8003, 0x0804, 0x1cfc, 0x2001, 0x8004, 0x0804, 0x1cfc, + 0x080c, 0x1c42, 0x2001, 0x8006, 0x0804, 0x1cfc, 0x2091, 0x8000, + 0x0076, 0xd7fc, 0x1128, 0x2069, 0x4540, 0x2039, 0x0009, 0x0020, + 0x2069, 0x4580, 0x2039, 0x0009, 0x6800, 0xa086, 0x0000, 0x0128, + 0x000e, 0x6f1e, 0x2091, 0x8001, 0x0005, 0x6870, 0x007e, 0xa0bc, + 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x080c, + 0x1b77, 0x8738, 0xa784, 0x001f, 0x1dd0, 0x2091, 0x8001, 0x2001, + 0x800a, 0x00d0, 0x2001, 0x800c, 0x00b8, 0x080c, 0x1c42, 0x2001, + 0x800d, 0x0090, 0xd7fc, 0x0110, 0x78e4, 0x0008, 0x78e0, 0x70c6, + 0x2001, 0x800e, 0x0048, 0xd7fc, 0x0110, 0x78ec, 0x0008, 0x78e8, + 0x70c6, 0x2001, 0x000d, 0x0000, 0x70c2, 0xd7fc, 0x1118, 0x70db, + 0x0000, 0x0010, 0x70db, 0x0001, 0x2061, 0x0000, 0x601b, 0x0001, + 0x2091, 0x4080, 0x0005, 0xac80, 0x0001, 0x81ff, 0x0518, 0x2099, + 0x0030, 0x20a0, 0x700c, 0xa084, 0x07ff, 0x0100, 0x7018, 0x0006, + 0x701c, 0x0006, 0x7020, 0x0006, 0x7024, 0x0006, 0x7112, 0x81ac, + 0x721a, 0x731e, 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, + 0x7008, 0x800b, 0x1ee8, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x1110, + 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x000e, 0x7026, + 0x000e, 0x7022, 0x000e, 0x701e, 0x000e, 0x701a, 0x0005, 0x2011, + 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x681f, 0x0201, 0x6803, + 0xfd20, 0x6807, 0x0038, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, + 0x0004, 0x8109, 0x1d80, 0x0005, 0x70ec, 0xd0dc, 0x1520, 0x2029, + 0x0001, 0x7814, 0xd0cc, 0x1160, 0x70ec, 0xd0e4, 0x2019, 0x0c0a, + 0x2021, 0x000a, 0x1120, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x0070, + 0x70ec, 0xd0e4, 0x1128, 0x2019, 0x1c0c, 0x2021, 0x000c, 0x0030, + 0x2019, 0x1c09, 0x2021, 0x0009, 0xa5ad, 0x0200, 0x6b0a, 0x6c0e, + 0x6d1e, 0x6807, 0x0038, 0x0005, 0x6004, 0x6086, 0x2c08, 0x2063, + 0x0000, 0x7868, 0xa005, 0x796a, 0x0110, 0x2c02, 0x0008, 0x796e, + 0x0005, 0x00c6, 0x2061, 0x4500, 0x6887, 0x0103, 0x2d08, 0x206b, + 0x0000, 0x6068, 0xa005, 0x616a, 0x0110, 0x2d02, 0x0008, 0x616e, + 0x00ce, 0x0005, 0x2091, 0x8000, 0x2c04, 0x786e, 0xa005, 0x1108, + 0x786a, 0x2091, 0x8001, 0x609c, 0xa005, 0x0188, 0x00c6, 0x2060, + 0x2008, 0x609c, 0xa005, 0x0138, 0x2062, 0x609f, 0x0000, 0xa065, + 0x609c, 0xa005, 0x1dc8, 0x7848, 0x794a, 0x2062, 0x00ce, 0x7848, + 0x2062, 0x609f, 0x0000, 0xac85, 0x0000, 0x1110, 0x080c, 0x252b, + 0x784a, 0x0005, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, + 0x1208, 0xa200, 0x1f04, 0x1dc6, 0x8086, 0x818e, 0x0005, 0x0156, + 0x20a9, 0x0010, 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, 0x818d, + 0x0228, 0xa11a, 0x1220, 0x1f04, 0x1dd6, 0x0028, 0xa11a, 0x2308, + 0x8210, 0x1f04, 0x1dd6, 0x0006, 0x3200, 0xa084, 0xefff, 0x2080, + 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0xa085, 0x1000, 0x0cb8, + 0x7d74, 0x70d0, 0xa506, 0x0904, 0x1ea4, 0x7810, 0x2050, 0x080c, + 0x1b3c, 0x0904, 0x1ea4, 0xa046, 0x7970, 0x2500, 0x8000, 0xa112, + 0x2009, 0x0040, 0x1208, 0x0030, 0x72d0, 0xa206, 0x0118, 0x8840, + 0x2009, 0x0080, 0x00c6, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, + 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, + 0x0110, 0x080c, 0x1b3c, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002, + 0x2091, 0x8001, 0xa08c, 0x01e0, 0x1538, 0x53a5, 0x8cff, 0x1120, + 0x88ff, 0x0904, 0x1e91, 0x0050, 0x2c00, 0x788e, 0x20a9, 0x0020, + 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0804, 0x1e91, 0xa046, 0x7218, + 0x731c, 0xdac4, 0x0110, 0x7420, 0x7524, 0xa292, 0x0040, 0xa39b, + 0x0000, 0xa4a3, 0x0000, 0xa5ab, 0x0000, 0x721a, 0x731e, 0xdac4, + 0x0118, 0x7422, 0x7526, 0xa006, 0x7007, 0x0004, 0x0904, 0x1e91, + 0x8cff, 0x0110, 0x080c, 0x1b44, 0x00ce, 0x080c, 0x1b44, 0xa046, + 0x7888, 0x8000, 0x788a, 0xa086, 0x0002, 0x01c0, 0x7a7c, 0x7b78, + 0xdac4, 0x0110, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, + 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, + 0x731e, 0xdac4, 0x0588, 0x7422, 0x7526, 0x0470, 0x6014, 0xd0fc, + 0x1118, 0x2069, 0x4540, 0x0010, 0x2069, 0x4580, 0x2091, 0x8000, + 0x681f, 0x0002, 0x88ff, 0x0120, 0xa046, 0x788c, 0x2060, 0x0c70, + 0x788b, 0x0000, 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, + 0x0098, 0x00ce, 0x788b, 0x0000, 0x080c, 0x201c, 0x6004, 0xa084, + 0x000f, 0x0059, 0x88ff, 0x0130, 0x788c, 0x2060, 0x6004, 0xa084, + 0x000f, 0x0019, 0x0804, 0x1df0, 0x0005, 0x0002, 0x1eb6, 0x1ed1, + 0x1eea, 0x1eb6, 0x1ef7, 0x1ec7, 0x1eb6, 0x1eb6, 0x1eb6, 0x1ecf, + 0x1ee8, 0x1eb6, 0x1eb6, 0x1eb6, 0x1eb6, 0x1eb6, 0x2039, 0x0400, + 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, 0x080c, 0x1f33, + 0x609c, 0x78ba, 0x609f, 0x0000, 0x080c, 0x2008, 0x0005, 0x78bc, + 0xd0c4, 0x0108, 0x0c58, 0x601c, 0xc0bd, 0x601e, 0x0030, 0x080c, + 0x2046, 0x78bc, 0xd0c4, 0x0108, 0x0c08, 0x78bf, 0x0000, 0x6004, + 0x8007, 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0138, 0x080c, 0x1f33, + 0x0120, 0x78bc, 0xc0c5, 0x78be, 0x0010, 0x0804, 0x1f4e, 0x0005, + 0x080c, 0x2043, 0x78bc, 0xa08c, 0x0e00, 0x1110, 0xd0c4, 0x1108, + 0x0828, 0x080c, 0x1f33, 0x1110, 0x0804, 0x1f4e, 0x0005, 0x78bc, + 0xd0c4, 0x0110, 0x0804, 0x1eb6, 0x78bf, 0x0000, 0x6714, 0x2011, + 0x0001, 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0188, 0xa7bc, + 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0150, 0xa7bc, 0x8000, + 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0108, 0x00c0, + 0x080c, 0x1b5f, 0x2d00, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, + 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, + 0x8001, 0x1f04, 0x1f1b, 0x8211, 0x0118, 0x20a9, 0x0100, 0x0c58, + 0x080c, 0x1b44, 0x0005, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, + 0x78b6, 0x1110, 0x78ba, 0x0038, 0x689e, 0x2d00, 0x6002, 0x78b8, + 0xad06, 0x1108, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x1130, 0x78bc, + 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x0005, 0x00e6, 0xa02e, + 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, 0x2048, + 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0110, 0x080c, 0x3f66, + 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, 0x4580, 0xd7fc, + 0x1110, 0x2071, 0x4540, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, + 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x71c0, 0xa168, + 0x2700, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0x71c4, + 0xa100, 0x60c2, 0x2091, 0x8000, 0x7814, 0xd0c4, 0x0138, 0xd7fc, + 0x1118, 0xd0f4, 0x1140, 0x0010, 0xd0fc, 0x1128, 0x6e08, 0xd684, + 0x01f0, 0xd9fc, 0x11e0, 0x2091, 0x8001, 0x080c, 0x1bc7, 0x2091, + 0x8000, 0x080c, 0x1d7c, 0x2091, 0x8001, 0x7814, 0xd0c4, 0x0904, + 0x2006, 0xd7fc, 0x1120, 0xd0f4, 0x1130, 0x0804, 0x2006, 0xd0fc, + 0x1110, 0x0804, 0x2006, 0x601b, 0x0021, 0x0804, 0x2006, 0x6024, + 0xa096, 0x0001, 0x1110, 0x8000, 0x6026, 0x6a10, 0x6814, 0xa202, + 0x0268, 0x0160, 0x2091, 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, + 0x609f, 0x0000, 0x080c, 0x2008, 0x0804, 0x2006, 0x2c08, 0xd9fc, + 0x01f0, 0x6800, 0xa065, 0x01d8, 0x6a04, 0x7000, 0xa084, 0x0002, + 0x0168, 0x7048, 0xa206, 0x1150, 0x6b04, 0x2160, 0x2304, 0x6002, + 0xa005, 0x1108, 0x6902, 0x2260, 0x6102, 0x0098, 0x2d00, 0x2060, + 0x080c, 0x2672, 0x6e08, 0x2160, 0x6202, 0x6906, 0x0050, 0x6800, + 0x6902, 0xa065, 0x0110, 0x6102, 0x0008, 0x6906, 0x2160, 0x6003, + 0x0000, 0x2160, 0xd9fc, 0x0118, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, + 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, + 0x0128, 0xa6b6, 0x0040, 0x6e0a, 0x080c, 0x1bd8, 0x00ee, 0x0005, + 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x080c, 0x1d7c, 0x2091, + 0x8001, 0x78b8, 0xa065, 0x0128, 0x609c, 0x78ba, 0x609f, 0x0000, + 0x0c78, 0x78b6, 0x78ba, 0x0005, 0x7970, 0x7874, 0x2818, 0xd384, + 0x0118, 0x8000, 0xa112, 0x0220, 0x8000, 0xa112, 0x1278, 0xc384, + 0x7a7c, 0x721a, 0x7a78, 0x721e, 0xdac4, 0x0120, 0x7a84, 0x7222, + 0x7a80, 0x7226, 0xa006, 0xd384, 0x0108, 0x8000, 0x7876, 0x70d2, + 0x781c, 0xa005, 0x0138, 0x8001, 0x781e, 0x1120, 0x0e04, 0x2042, + 0x2091, 0x4080, 0x0005, 0x2039, 0x2058, 0x0010, 0x2039, 0x205e, + 0x2704, 0xa005, 0x0160, 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, + 0x680a, 0x690c, 0x6814, 0x6916, 0x680e, 0x8738, 0x0c88, 0x0005, + 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, + 0x0000, 0x2041, 0x0000, 0x780c, 0x0002, 0x220a, 0x21e5, 0x2069, + 0x20d9, 0x2039, 0x8d74, 0x2734, 0x7d10, 0x00c0, 0x6084, 0xa086, + 0x0103, 0x1904, 0x20c3, 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, + 0x11d8, 0x0804, 0x20c3, 0x8603, 0xa080, 0x8d55, 0x620c, 0x2202, + 0x8000, 0x6210, 0x2202, 0x080c, 0x1d9a, 0x8630, 0xa68e, 0x000f, + 0x0904, 0x2144, 0x786c, 0xa065, 0x1d08, 0x7808, 0xa602, 0x1220, + 0xd5ac, 0x1110, 0x263a, 0x0005, 0xa682, 0x0003, 0x1a04, 0x2144, + 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x11f8, 0x2011, + 0x8d55, 0x2204, 0x70c6, 0x8210, 0x2204, 0x70ca, 0xd684, 0x1130, + 0x8210, 0x2204, 0x70da, 0x8210, 0x2204, 0x70de, 0xa685, 0x8020, + 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, + 0x7812, 0x2091, 0x8001, 0x203b, 0x0000, 0x0005, 0x7810, 0xc0ad, + 0x7812, 0x0804, 0x2144, 0x263a, 0x080c, 0x2210, 0x1904, 0x222c, + 0x786c, 0xa065, 0x1904, 0x206e, 0x2091, 0x8000, 0x7810, 0xa084, + 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0804, + 0x222c, 0x2039, 0x8d74, 0x2734, 0x7d10, 0x00a0, 0x6084, 0xa086, + 0x0103, 0x1904, 0x212e, 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, + 0x11b8, 0x0804, 0x212e, 0xa680, 0x8d55, 0x620c, 0x2202, 0x080c, + 0x1d9a, 0x8630, 0xa68e, 0x001e, 0x0904, 0x2144, 0x786c, 0xa065, + 0x1d28, 0x7808, 0xa602, 0x1220, 0xd5ac, 0x1110, 0x263a, 0x0005, + 0xa682, 0x0006, 0x1a04, 0x2144, 0x2091, 0x8000, 0x2069, 0x0000, + 0x6818, 0xd084, 0x11f8, 0x2011, 0x8d55, 0x2009, 0x8d4e, 0x26a8, + 0x211c, 0x2204, 0x201a, 0x8108, 0x8210, 0x1f04, 0x2110, 0xa685, + 0x8030, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, + 0xffcf, 0x7812, 0x2091, 0x8001, 0xa006, 0x2009, 0x8d75, 0x200a, + 0x203a, 0x0005, 0x7810, 0xc0ad, 0x7812, 0x00b0, 0x263a, 0x080c, + 0x2210, 0x1904, 0x222c, 0x786c, 0xa065, 0x1904, 0x20de, 0x2091, + 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, + 0x2091, 0x8001, 0x0804, 0x222c, 0x2091, 0x8000, 0x7007, 0x0004, + 0x7994, 0x70d4, 0xa102, 0x0228, 0x0168, 0x7b90, 0xa302, 0x1150, + 0x0010, 0x8002, 0x1138, 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, + 0x8001, 0x0005, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, + 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, + 0x7a9c, 0xa210, 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, + 0x0130, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, + 0x0030, 0x7003, 0x0000, 0x2009, 0x8d54, 0x260a, 0x8109, 0x2198, + 0x2104, 0xd084, 0x0108, 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, + 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a, + 0x1208, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, 0x0140, 0x810f, + 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, + 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, 0xd4c4, + 0x0120, 0x7b84, 0xa319, 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0de8, + 0xa084, 0x01e0, 0x01d0, 0x7d10, 0x2031, 0x8d54, 0x2634, 0x78a8, + 0x8000, 0x78aa, 0xd08c, 0x1138, 0x7007, 0x0006, 0x7004, 0xd094, + 0x1de8, 0x0804, 0x2146, 0x2069, 0x4547, 0x206b, 0x0003, 0x78ac, + 0xa085, 0x0300, 0x78ae, 0xa006, 0x0048, 0x2030, 0x75d6, 0x2091, + 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091, 0x8001, + 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, 0x711a, 0x721e, + 0xd5c4, 0x0110, 0x7322, 0x7426, 0x0005, 0x6084, 0xa086, 0x0103, + 0x11d8, 0x6114, 0x6018, 0xa105, 0x11b8, 0x2069, 0x0000, 0x6818, + 0xd084, 0x1190, 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, + 0x681b, 0x0001, 0x2091, 0x4080, 0x080c, 0x1d9a, 0x0e04, 0x2203, + 0x786c, 0xa065, 0x1d10, 0x0005, 0x0059, 0x1530, 0x786c, 0xa065, + 0x19e0, 0x0410, 0x0029, 0x1500, 0x786c, 0xa065, 0x1dd8, 0x00e0, + 0x6084, 0xa086, 0x0103, 0x1168, 0x6018, 0xc0fc, 0x601a, 0xa086, + 0x0004, 0x1138, 0x7804, 0xd0a4, 0x0120, 0x080c, 0x1d9a, 0xa006, + 0x0005, 0x0079, 0x1118, 0xa085, 0x0001, 0x0005, 0x00b9, 0x1110, + 0x2041, 0x0001, 0x7d10, 0x0005, 0x88ff, 0x0110, 0x2091, 0x4080, + 0x0005, 0x7b90, 0x7994, 0x70d4, 0xa102, 0x1118, 0xa385, 0x0000, + 0x0005, 0x0210, 0xa302, 0x0005, 0x8002, 0x0005, 0xa184, 0xff00, + 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, + 0x0018, 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, + 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, + 0xa005, 0x0110, 0x2009, 0x0040, 0x080c, 0x1af9, 0x01d0, 0x78a8, + 0x8000, 0x78aa, 0xd08c, 0x1510, 0x6014, 0xd0fc, 0x1118, 0x2069, + 0x4540, 0x0010, 0x2069, 0x4580, 0x2091, 0x8000, 0x681f, 0x0003, + 0x78ab, 0x0000, 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, + 0x0068, 0x78ab, 0x0000, 0x080c, 0x1d9a, 0x7990, 0x7894, 0x8000, + 0xa10a, 0x1208, 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, + 0x2091, 0x8001, 0x0005, 0x2138, 0xd7fc, 0x1118, 0x2009, 0x4558, + 0x0010, 0x2009, 0x4598, 0x2091, 0x8000, 0x200a, 0x00f6, 0x2009, + 0x4580, 0x2079, 0x0100, 0xd7fc, 0x1120, 0x2009, 0x4540, 0x2079, + 0x0200, 0x2104, 0xa086, 0x0000, 0x1180, 0xd7fc, 0x1118, 0x2009, + 0x4545, 0x0010, 0x2009, 0x4585, 0x2104, 0xa005, 0x1130, 0x7830, + 0xa084, 0x00c0, 0x1110, 0x781b, 0x0052, 0x00fe, 0x0005, 0x2009, + 0x0002, 0x2069, 0x4500, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, + 0x230c, 0x2071, 0x4580, 0x2079, 0x0100, 0x2021, 0x47bf, 0x784b, + 0x000f, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, 0x2019, 0x3dc2, + 0x0030, 0x20a1, 0x012b, 0x2019, 0x3dc2, 0xd184, 0x0110, 0x20a1, + 0x022b, 0x2304, 0xa005, 0x0140, 0x789a, 0x8318, 0x23ac, 0x8318, + 0x2398, 0x53a6, 0x3318, 0x0ca8, 0x789b, 0x0000, 0x789b, 0x0020, + 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, 0x2020, 0x1f04, 0x22ea, + 0x7003, 0x0000, 0x0016, 0xd18c, 0x2009, 0x0000, 0x0108, 0xc1bd, + 0x080c, 0x2422, 0x001e, 0x7020, 0xa084, 0x000f, 0xa085, 0x6300, + 0x7806, 0x780f, 0x9000, 0x7843, 0x00d8, 0x7853, 0x0090, 0x780b, + 0x2f08, 0x7452, 0x704f, 0x0000, 0x8109, 0x0140, 0x2071, 0x4540, + 0x2079, 0x0200, 0x2021, 0x45bf, 0x0804, 0x22c7, 0x080c, 0x24dc, + 0x0005, 0x0016, 0x2011, 0x0101, 0xd1bc, 0x1110, 0x2011, 0x0201, + 0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x001e, + 0x080c, 0x2422, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110, 0x2011, + 0x0201, 0x20a9, 0x0009, 0x810b, 0x1f04, 0x2333, 0xa18c, 0x0e00, + 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x0005, 0x2019, 0x0002, + 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x1f04, 0x2344, 0xa294, + 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x8319, 0x0118, + 0x2009, 0x0201, 0x0c78, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110, + 0x2011, 0x0201, 0x20a9, 0x000c, 0x810b, 0x1f04, 0x235c, 0xa18c, + 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x0005, 0x2011, + 0x0102, 0xd3fc, 0x1110, 0x2011, 0x0202, 0x2204, 0xa084, 0xf0cf, + 0xa105, 0x2012, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, 0x1110, + 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, + 0x62ac, 0x63ac, 0x00ce, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, + 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0022, + 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x00ce, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, - 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, - 0x00ce, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, 0x1110, 0x2061, - 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, - 0xa28c, 0x0020, 0x0118, 0xc2ac, 0xa39d, 0x4000, 0xc3ec, 0xd3b4, - 0x1108, 0xc3ed, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x00ce, - 0x0005, 0x2091, 0x8000, 0x00c6, 0x00e6, 0x6818, 0xa005, 0x0904, - 0x23a1, 0xd1fc, 0x0118, 0x2061, 0x8ad0, 0x0010, 0x2061, 0x89c0, - 0x080c, 0x23a9, 0x0538, 0x20a9, 0x0101, 0xd1fc, 0x0118, 0x2061, - 0x89d0, 0x0010, 0x2061, 0x88c0, 0x00c6, 0x04d9, 0x0128, 0x00ce, - 0x8c60, 0x1f04, 0x236c, 0x0468, 0x000e, 0xd1fc, 0x0128, 0xa082, - 0x89d0, 0x2071, 0x4380, 0x0020, 0xa082, 0x88c0, 0x2071, 0x4340, - 0x707a, 0x7176, 0x2001, 0x0004, 0x7066, 0x7083, 0x000f, 0x080c, - 0x2228, 0x00a0, 0xd1fc, 0x1118, 0x2071, 0x4340, 0x0010, 0x2071, - 0x4380, 0x6020, 0xc0dd, 0x6022, 0x7176, 0x2c00, 0x707e, 0x2001, - 0x0006, 0x7066, 0x7083, 0x000f, 0x080c, 0x2228, 0x2001, 0x0000, - 0x0010, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x00ee, 0x00ce, - 0x0005, 0x2c04, 0xa005, 0x0170, 0x2060, 0x6010, 0xa306, 0x1140, - 0x600c, 0xa206, 0x1128, 0x6014, 0xa106, 0x1110, 0xa006, 0x0020, - 0x6000, 0x0c80, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x0016, - 0x2079, 0x4380, 0x2071, 0x0100, 0xd1bc, 0x1120, 0x2079, 0x4340, - 0x2071, 0x0200, 0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x1110, - 0x001e, 0x0060, 0x810b, 0x810b, 0x810b, 0x810b, 0x000e, 0xa18d, - 0x0800, 0xd0bc, 0x1110, 0xa18d, 0x0f00, 0x2104, 0x00ee, 0x00fe, - 0x0005, 0x00e6, 0x2001, 0x4301, 0x2004, 0xd0ac, 0x1904, 0x2439, - 0x68e4, 0xd0ac, 0x0904, 0x2439, 0xa084, 0x0006, 0x1904, 0x2439, - 0x6014, 0xd0fc, 0x1118, 0x2071, 0x47c0, 0x0010, 0x2071, 0x4840, - 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, - 0xa084, 0x000a, 0x15b0, 0x7108, 0xa194, 0xff00, 0x0590, 0xa18c, - 0x00ff, 0x2001, 0x000a, 0xa106, 0x01a8, 0x2001, 0x000c, 0xa106, - 0x01a0, 0x2001, 0x0012, 0xa106, 0x0198, 0x2001, 0x0014, 0xa106, - 0x0190, 0x2001, 0x0019, 0xa106, 0x0188, 0x2001, 0x0032, 0xa106, - 0x0180, 0x0090, 0x2009, 0x000c, 0x0088, 0x2009, 0x0012, 0x0070, - 0x2009, 0x0014, 0x0058, 0x2009, 0x0019, 0x0040, 0x2009, 0x0020, - 0x0028, 0x2009, 0x003f, 0x0010, 0x2011, 0x0000, 0x2100, 0xa205, - 0x700a, 0x00ee, 0x0005, 0x0e04, 0x243b, 0x2091, 0x8000, 0x2071, + 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, 0xa28c, 0x0020, 0x0118, + 0xc2ac, 0xa39d, 0x4000, 0xc3ec, 0xd3b4, 0x1108, 0xc3ed, 0x62ae, + 0x2010, 0x60a4, 0x63ae, 0x2018, 0x00ce, 0x0005, 0x2091, 0x8000, + 0x00c6, 0x00e6, 0x6818, 0xa005, 0x0904, 0x2406, 0xd1fc, 0x0118, + 0x2061, 0x8cd0, 0x0010, 0x2061, 0x8bc0, 0x080c, 0x240e, 0x0538, + 0x20a9, 0x0101, 0xd1fc, 0x0118, 0x2061, 0x8bd0, 0x0010, 0x2061, + 0x8ac0, 0x00c6, 0x04d9, 0x0128, 0x00ce, 0x8c60, 0x1f04, 0x23d1, + 0x0468, 0x000e, 0xd1fc, 0x0128, 0xa082, 0x8bd0, 0x2071, 0x4580, + 0x0020, 0xa082, 0x8ac0, 0x2071, 0x4540, 0x7076, 0x7172, 0x2001, + 0x0004, 0x7062, 0x707f, 0x000f, 0x080c, 0x228b, 0x00a0, 0xd1fc, + 0x1118, 0x2071, 0x4540, 0x0010, 0x2071, 0x4580, 0x6020, 0xc0dd, + 0x6022, 0x7172, 0x2c00, 0x707a, 0x2001, 0x0006, 0x7062, 0x707f, + 0x000f, 0x080c, 0x228b, 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, + 0x2091, 0x8001, 0xa005, 0x00ee, 0x00ce, 0x0005, 0x2c04, 0xa005, + 0x0170, 0x2060, 0x6010, 0xa306, 0x1140, 0x600c, 0xa206, 0x1128, + 0x6014, 0xa106, 0x1110, 0xa006, 0x0020, 0x6000, 0x0c80, 0xa085, + 0x0001, 0x0005, 0x00f6, 0x00e6, 0x0016, 0x2079, 0x4580, 0x2071, + 0x0100, 0xd1bc, 0x1120, 0x2079, 0x4540, 0x2071, 0x0200, 0x7920, + 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x1110, 0x001e, 0x0060, 0x810b, + 0x810b, 0x810b, 0x810b, 0x000e, 0xa18d, 0x0800, 0xd0bc, 0x1110, + 0xa18d, 0x0f00, 0x2104, 0x00ee, 0x00fe, 0x0005, 0x2001, 0x4501, + 0x2004, 0xd0ac, 0x1138, 0x68e4, 0xd0ac, 0x0120, 0xa084, 0x0006, + 0x1108, 0x0009, 0x0005, 0x6014, 0x00e6, 0x0036, 0x2018, 0x2071, + 0x4a40, 0xd0fc, 0x1110, 0x2071, 0x49c0, 0x8007, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, 0xa084, 0x000a, 0x1904, + 0x24d9, 0x7108, 0xa194, 0xff00, 0x0904, 0x24d9, 0xa18c, 0x00ff, + 0x701c, 0xa084, 0xff00, 0x01c0, 0x7004, 0xa085, 0x003a, 0x7006, + 0x2001, 0x0009, 0xa102, 0x16d8, 0x2001, 0x000a, 0xa102, 0x16d0, + 0x2001, 0x000c, 0xa102, 0x16c8, 0x701c, 0xa084, 0x00ff, 0x701e, + 0x7004, 0xa084, 0xffdf, 0x7006, 0x2001, 0x000a, 0xa106, 0x01a8, + 0x2001, 0x000c, 0xa106, 0x01a0, 0x2001, 0x0012, 0xa106, 0x0198, + 0x2001, 0x0014, 0xa106, 0x0190, 0x2001, 0x0019, 0xa106, 0x0188, + 0x2001, 0x0032, 0xa106, 0x0180, 0x00d8, 0x2009, 0x000c, 0x00d0, + 0x2009, 0x0012, 0x00b8, 0x2009, 0x0014, 0x00a0, 0x2009, 0x0019, + 0x0088, 0x2009, 0x0020, 0x0070, 0x2009, 0x003f, 0x0058, 0x2009, + 0x000a, 0x0040, 0x2009, 0x000c, 0x0028, 0x2009, 0x0019, 0x0010, + 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, 0x7004, 0xa085, 0x000a, + 0x7006, 0x2071, 0x4500, 0x7004, 0xd0bc, 0x0158, 0xd3fc, 0x1120, + 0x73ea, 0x2071, 0x4540, 0x0018, 0x73ee, 0x2071, 0x4580, 0x701f, + 0x800f, 0x003e, 0x00ee, 0x0005, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x11d0, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x12a0, 0x2071, + 0x0200, 0x71ec, 0xa18c, 0x1c00, 0x810f, 0x810c, 0x810c, 0x2079, + 0x0100, 0x78ec, 0xa084, 0x1c00, 0x8007, 0x8004, 0x8004, 0xa105, + 0xa08a, 0x0007, 0x0208, 0x0005, 0x0002, 0x252a, 0x2511, 0x252a, + 0x2511, 0x2504, 0x251e, 0x2504, 0x7008, 0xa084, 0xc3ff, 0xa085, + 0x3000, 0x700a, 0x7808, 0xa084, 0xc3ff, 0xa085, 0x3000, 0x780a, + 0x0005, 0x7008, 0xa084, 0xc3ff, 0xa085, 0x2000, 0x700a, 0x7808, + 0xa084, 0xc3ff, 0xa085, 0x2000, 0x780a, 0x0005, 0x7008, 0xa084, + 0xc3ff, 0xa085, 0x0c00, 0x700a, 0x7808, 0xa084, 0xc3ff, 0xa085, + 0x0c00, 0x780a, 0x0005, 0x0e04, 0x252b, 0x2091, 0x8000, 0x2071, 0x0000, 0x0006, 0x7018, 0xd084, 0x1de8, 0x000e, 0x2071, 0x0010, - 0x70ca, 0x000e, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x0a01, 0x70df, - 0x0013, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0cf8, - 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708e, 0x7592, 0x7496, - 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, 0x0138, 0xd7bc, 0x1128, - 0xa784, 0x007d, 0x1904, 0x3ace, 0x0871, 0xa49c, 0x000f, 0xa382, + 0x70ca, 0x000e, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x0a04, 0x70df, + 0x0008, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0cf8, + 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708a, 0x758e, 0x7492, + 0x7696, 0x779a, 0xa594, 0x003f, 0xd4f4, 0x0138, 0xd7bc, 0x1128, + 0xa784, 0x007d, 0x1904, 0x3c3a, 0x0871, 0xa49c, 0x000f, 0xa382, 0x0004, 0x0320, 0xa3a6, 0x0007, 0x1930, 0x2418, 0x8507, 0xa084, - 0x000f, 0x0002, 0x2a4f, 0x2b10, 0x2b38, 0x2d71, 0x30cc, 0x3112, - 0x31a7, 0x3220, 0x32db, 0x33a6, 0x248d, 0x248a, 0x285b, 0x295c, - 0x30a0, 0x248a, 0x080c, 0x243b, 0x0005, 0xa006, 0x0038, 0x7808, - 0xc08d, 0x780a, 0xa006, 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, - 0xa005, 0x1904, 0x25d9, 0x7064, 0xa084, 0x0007, 0x0002, 0x24a7, - 0x2513, 0x251b, 0x2524, 0x252d, 0x25bf, 0x2536, 0x2513, 0x7830, - 0xd0bc, 0x1d10, 0x71d4, 0xd1b4, 0x1904, 0x24f0, 0x70a4, 0xa086, - 0x0001, 0x09d0, 0x70b4, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, - 0x0080, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, - 0xa05d, 0xa886, 0x0001, 0x0118, 0x69bc, 0x7daa, 0x79aa, 0x68c0, - 0xa04d, 0x6e1c, 0x2001, 0x0010, 0x0804, 0x270a, 0x7060, 0xa005, - 0x1904, 0x248c, 0x00c6, 0x00d6, 0x70b4, 0xa06d, 0x6800, 0xa065, + 0x000f, 0x0002, 0x2b40, 0x2c01, 0x2c29, 0x2e64, 0x31f1, 0x3243, + 0x32e8, 0x3361, 0x341f, 0x34f6, 0x257d, 0x257a, 0x294d, 0x2a4d, + 0x31c5, 0x257a, 0x080c, 0x252b, 0x0005, 0xa006, 0x0038, 0x7808, + 0xc08d, 0x780a, 0xa006, 0x7002, 0x704a, 0x7042, 0x70ce, 0x705c, + 0xa005, 0x1904, 0x26cb, 0x7060, 0xa084, 0x0007, 0x0002, 0x2597, + 0x2605, 0x260d, 0x2616, 0x261f, 0x26b1, 0x2628, 0x2605, 0x7830, + 0xd0bc, 0x1d10, 0x71d0, 0xd1bc, 0x19f8, 0xd1b4, 0x1904, 0x25e2, + 0x70a0, 0xa086, 0x0001, 0x09c0, 0x70b0, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0080, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0118, 0x69bc, 0x7daa, - 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0020, 0x0804, 0x270a, - 0x080c, 0x3a8d, 0x1904, 0x248c, 0x781b, 0x0068, 0x70bc, 0xa06d, + 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0010, 0x0804, 0x27fc, + 0x705c, 0xa005, 0x1904, 0x257c, 0x00c6, 0x00d6, 0x70b0, 0xa06d, + 0x6800, 0xa065, 0xa055, 0x789b, 0x0080, 0x6b0c, 0x7baa, 0x6808, + 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0118, + 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0020, + 0x0804, 0x27fc, 0x080c, 0x3bf9, 0x1904, 0x257c, 0x781b, 0x0068, + 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x68bc, 0x703e, 0xc1b4, + 0x71d2, 0x70b4, 0xa065, 0x68c0, 0x7056, 0x7003, 0x0002, 0x2d00, + 0x704a, 0xad80, 0x0009, 0x7042, 0x0005, 0x080c, 0x3bf9, 0x1120, + 0x781b, 0x0054, 0x7003, 0x0004, 0x0005, 0x080c, 0x3bf9, 0x1128, + 0x2011, 0x000c, 0x0419, 0x7003, 0x0004, 0x0005, 0x080c, 0x3bf9, + 0x1128, 0x2011, 0x0006, 0x00d1, 0x7003, 0x0004, 0x0005, 0x080c, + 0x3bf9, 0x1128, 0x2011, 0x000d, 0x0089, 0x7003, 0x0004, 0x0005, + 0x080c, 0x3bf9, 0x1150, 0x2011, 0x0006, 0x0041, 0x7078, 0x707b, + 0x0000, 0x2068, 0x704a, 0x7003, 0x0001, 0x0005, 0x7170, 0xc1fc, + 0x8107, 0x7882, 0x789b, 0x0080, 0xa286, 0x000c, 0x1120, 0x7aaa, + 0x2001, 0x0001, 0x0098, 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, + 0xa286, 0x000d, 0x0120, 0x7aaa, 0x2001, 0x0002, 0x0038, 0x78ab, + 0x0020, 0x7174, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, + 0x78aa, 0x785b, 0x0004, 0x781b, 0x0113, 0x080c, 0x3c0c, 0x707f, + 0x000f, 0x70d0, 0xd0b4, 0x0168, 0xc0b4, 0x70d2, 0x00c6, 0x70b4, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x00ce, 0x0005, 0x7014, 0xa005, 0x1138, 0x70d0, 0xd0b4, 0x0128, + 0x70b4, 0xac06, 0x1110, 0x0c29, 0x0005, 0x0016, 0x71a0, 0xa186, + 0x0001, 0x0528, 0x00d6, 0x0026, 0x2100, 0x2011, 0x0001, 0xa212, + 0x70b0, 0x2068, 0x6800, 0xac06, 0x0120, 0x8211, 0x01b0, 0x00c9, + 0x0cc8, 0x00c6, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b0, 0x2068, + 0x6800, 0x2060, 0x6008, 0xa084, 0xfbef, 0x600a, 0x8211, 0x0110, + 0x0041, 0x0cb0, 0x70a3, 0x0001, 0x00ce, 0x002e, 0x00de, 0x001e, + 0x0005, 0xade8, 0x0005, 0x70a8, 0xad06, 0x1110, 0x70a4, 0x2068, + 0x0005, 0x080c, 0x3bf9, 0x1904, 0x257c, 0x7078, 0x2068, 0x7770, + 0x080c, 0x3b35, 0x2c50, 0x080c, 0x3c94, 0x789b, 0x0080, 0x6814, + 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, + 0x0004, 0x0804, 0x2801, 0x080c, 0x3bf9, 0x1904, 0x257c, 0x789b, + 0x0080, 0x705c, 0x2068, 0x6f14, 0x70d0, 0xd0b4, 0x0168, 0xc0b4, + 0x70d2, 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x6018, 0x8001, 0x601a, 0x00ce, 0x080c, 0x3b35, 0x2c50, 0x080c, + 0x3c94, 0x6824, 0xa005, 0x0130, 0xa082, 0x0006, 0x0208, 0x0010, + 0x6827, 0x0005, 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x2031, + 0x0020, 0x2041, 0x0001, 0x2001, 0x0003, 0x0804, 0x2801, 0xc28d, + 0x72d2, 0x72bc, 0xa200, 0xa015, 0x7150, 0x8108, 0xa12a, 0x0208, + 0x71bc, 0x2164, 0x6504, 0x85ff, 0x1170, 0x7152, 0x8421, 0x1da8, + 0x70d0, 0xd08c, 0x0128, 0x70cc, 0xa005, 0x1110, 0x70cf, 0x000a, + 0x0005, 0x2200, 0x0c90, 0x70d0, 0xc08c, 0x70d2, 0x70cf, 0x0000, + 0x6034, 0xa005, 0x1db0, 0x6708, 0xa784, 0x073f, 0x01d0, 0xd7d4, + 0x1d80, 0xa784, 0x0021, 0x1d68, 0xa784, 0x0002, 0x0130, 0xa784, + 0x0004, 0x0d38, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, 0x1d08, + 0xa784, 0x0100, 0x0130, 0x6018, 0xa005, 0x19d8, 0xa7bc, 0xfeff, + 0x670a, 0x2568, 0x6823, 0x0000, 0x6e1c, 0xa684, 0x000e, 0x6318, + 0x0128, 0x601c, 0xa302, 0x0220, 0x0118, 0x0858, 0x83ff, 0x1948, + 0x2d58, 0x2c50, 0x7152, 0xd7bc, 0x1110, 0x7028, 0x6022, 0xc7bc, + 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041, 0x0001, + 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0110, 0xd684, + 0x0110, 0xa39c, 0xffbf, 0xd6a4, 0x0110, 0xa39d, 0x0020, 0xa684, + 0x000e, 0x1904, 0x27b3, 0xc7a5, 0x670a, 0x2c00, 0x68c6, 0x77a0, + 0xa786, 0x0001, 0x1178, 0x70d0, 0xd0b4, 0x1160, 0x7000, 0xa082, + 0x0002, 0x1240, 0x7830, 0xd0bc, 0x1128, 0x789b, 0x0080, 0x7baa, + 0x0804, 0x27fa, 0x8739, 0x77a2, 0x2750, 0x77ac, 0xa7b0, 0x0005, + 0x70a8, 0xa606, 0x1108, 0x76a4, 0x76ae, 0x2c3a, 0x8738, 0x2d3a, + 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, 0x7830, 0xd0bc, + 0x0150, 0x2091, 0x8000, 0x2091, 0x303d, 0x70d0, 0xa084, 0x303d, + 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, 0x0120, 0x8421, 0x2200, + 0x1904, 0x2704, 0x0005, 0xd1dc, 0x0904, 0x3796, 0x2029, 0x0020, + 0xd69c, 0x1120, 0x8528, 0xd68c, 0x1108, 0x8528, 0x8840, 0x6f14, + 0x610c, 0x8108, 0xa18c, 0x00ff, 0x70c8, 0xa160, 0x2c64, 0x8cff, + 0x0188, 0x6014, 0xa706, 0x1dd0, 0x60b8, 0x8001, 0x60ba, 0x1d88, + 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x1904, + 0x2704, 0x0005, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840, + 0x6008, 0xc0d5, 0x600a, 0x77a0, 0xa786, 0x0001, 0x1904, 0x278a, + 0x70d0, 0xd0b4, 0x1904, 0x278a, 0x7000, 0xa082, 0x0002, 0x1a04, + 0x278a, 0x7830, 0xd0bc, 0x1904, 0x278a, 0x789b, 0x0080, 0x7baa, + 0x7daa, 0x79aa, 0x2001, 0x0002, 0x0006, 0x6018, 0x8000, 0x601a, + 0x0008, 0x0006, 0x2960, 0x6104, 0x2a60, 0x080c, 0x3ca7, 0x1590, + 0xa184, 0x0018, 0x0180, 0xa184, 0x0010, 0x0118, 0x080c, 0x393d, + 0x1548, 0xa184, 0x0008, 0x0138, 0x69a0, 0xa184, 0x0600, 0x1118, + 0x080c, 0x385d, 0x00f8, 0x69a0, 0xa184, 0x1e00, 0x0528, 0xa184, + 0x0800, 0x0178, 0x00c6, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, + 0x6104, 0xa18d, 0x0010, 0x6106, 0x00ce, 0x080c, 0x393d, 0x1150, + 0x69a0, 0xa184, 0x0200, 0x0118, 0x080c, 0x38a0, 0x0018, 0xa184, + 0x0400, 0x19f0, 0x69a0, 0xa184, 0x1000, 0x0130, 0x6914, 0xa18c, + 0xff00, 0x810f, 0x080c, 0x2384, 0x002e, 0xa68c, 0x00e0, 0xa684, + 0x0060, 0x0128, 0xa086, 0x0060, 0x1110, 0xa18d, 0x4000, 0xa18d, + 0x0104, 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, + 0x681a, 0xd6bc, 0x0168, 0xc0fc, 0x7083, 0x0000, 0xa08a, 0x000d, + 0x0328, 0xa08a, 0x000c, 0x7182, 0x2001, 0x000c, 0x800c, 0x7186, + 0x78aa, 0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, + 0x20a0, 0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, + 0x2898, 0x25a0, 0xa286, 0x0020, 0x1508, 0x70d0, 0xc0b5, 0x70d2, + 0x2c00, 0x70b6, 0x2d00, 0x70ba, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0xa286, 0x0002, 0x0904, 0x28d2, 0x70a0, 0x8000, 0x70a2, 0x74b0, + 0xa498, 0x0005, 0x70a8, 0xa306, 0x1108, 0x73a4, 0x73b2, 0xa286, + 0x0010, 0x0904, 0x257c, 0x00de, 0x00ce, 0x0005, 0x7000, 0xa005, + 0x19e0, 0xa286, 0x0002, 0x1904, 0x28e9, 0x080c, 0x3bf9, 0x19a8, + 0x6814, 0xc0fc, 0x8007, 0x7882, 0x2091, 0x8000, 0x781b, 0x0068, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, - 0x7808, 0xc08d, 0x780a, 0x68bc, 0x7042, 0xc1b4, 0x71d6, 0x70b8, - 0xa065, 0x68c0, 0x705a, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, - 0x0009, 0x7046, 0x0005, 0x080c, 0x3a8d, 0x1120, 0x781b, 0x0054, - 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, 0x1128, 0x2011, 0x000c, - 0x0419, 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, 0x1128, 0x2011, - 0x0006, 0x00d1, 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, 0x1128, - 0x2011, 0x000d, 0x0089, 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, - 0x1150, 0x2011, 0x0006, 0x0041, 0x707c, 0x707f, 0x0000, 0x2068, - 0x704e, 0x7003, 0x0001, 0x0005, 0x7174, 0xc1fc, 0x8107, 0x7882, - 0x789b, 0x0080, 0xa286, 0x000c, 0x1120, 0x7aaa, 0x2001, 0x0001, - 0x0098, 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, 0x000d, - 0x0120, 0x7aaa, 0x2001, 0x0002, 0x0038, 0x78ab, 0x0020, 0x7178, - 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, 0x78aa, 0x785b, - 0x0004, 0x781b, 0x0113, 0x080c, 0x3aa0, 0x7083, 0x000f, 0x70d4, - 0xd0b4, 0x0168, 0xc0b4, 0x70d6, 0x00c6, 0x70b8, 0xa065, 0x6008, - 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x0005, - 0x7014, 0xa005, 0x1138, 0x70d4, 0xd0b4, 0x0128, 0x70b8, 0xac06, - 0x1110, 0x0c29, 0x0005, 0x0016, 0x71a4, 0xa186, 0x0001, 0x0528, - 0x00d6, 0x0026, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b4, 0x2068, - 0x6800, 0xac06, 0x0120, 0x8211, 0x01b0, 0x00c9, 0x0cc8, 0x00c6, - 0x2100, 0x2011, 0x0001, 0xa212, 0x70b4, 0x2068, 0x6800, 0x2060, - 0x6008, 0xa084, 0xfbef, 0x600a, 0x8211, 0x0110, 0x0041, 0x0cb0, - 0x70a7, 0x0001, 0x00ce, 0x002e, 0x00de, 0x001e, 0x0005, 0xade8, - 0x0005, 0x70ac, 0xad06, 0x1110, 0x70a8, 0x2068, 0x0005, 0x080c, - 0x3a8d, 0x1904, 0x248c, 0x707c, 0x2068, 0x7774, 0x080c, 0x396d, - 0x2c50, 0x080c, 0x3b28, 0x789b, 0x0080, 0x6814, 0xa084, 0x001f, - 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, 0x0004, 0x0804, - 0x270f, 0x080c, 0x3a8d, 0x1904, 0x248c, 0x789b, 0x0080, 0x7060, - 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0168, 0xc0b4, 0x70d6, 0x00c6, - 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, - 0x601a, 0x00ce, 0x080c, 0x396d, 0x2c50, 0x080c, 0x3b28, 0x6824, - 0xa005, 0x0130, 0xa082, 0x0006, 0x0208, 0x0010, 0x6827, 0x0005, - 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, - 0x0001, 0x2001, 0x0003, 0x0804, 0x270f, 0xc28d, 0x72d6, 0x72c0, - 0xa200, 0xa015, 0x7154, 0x8108, 0xa12a, 0x0208, 0x71c0, 0x2164, - 0x6504, 0x85ff, 0x1170, 0x7156, 0x8421, 0x1da8, 0x70d4, 0xd08c, - 0x0128, 0x70d0, 0xa005, 0x1110, 0x70d3, 0x000a, 0x0005, 0x2200, - 0x0c90, 0x70d4, 0xc08c, 0x70d6, 0x70d3, 0x0000, 0x6034, 0xa005, - 0x1db0, 0x6708, 0xa784, 0x073f, 0x01d0, 0xd7d4, 0x1d80, 0xa784, - 0x0021, 0x1d68, 0xa784, 0x0002, 0x0130, 0xa784, 0x0004, 0x0d38, - 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, 0x1d08, 0xa784, 0x0100, - 0x0130, 0x6018, 0xa005, 0x19d8, 0xa7bc, 0xfeff, 0x670a, 0x2568, - 0x6823, 0x0000, 0x6e1c, 0xa684, 0x000e, 0x6318, 0x0128, 0x601c, - 0xa302, 0x0220, 0x0118, 0x0858, 0x83ff, 0x1948, 0x2d58, 0x2c50, - 0x7156, 0xd7bc, 0x1110, 0x7028, 0x6022, 0xc7bc, 0x670a, 0x68c0, - 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041, 0x0001, 0x6b14, 0xa39c, - 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0110, 0xd684, 0x0110, 0xa39c, - 0xffbf, 0xd6a4, 0x0110, 0xa39d, 0x0020, 0xa684, 0x000e, 0x1904, - 0x26c1, 0xc7a5, 0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, - 0x1178, 0x70d4, 0xd0b4, 0x1160, 0x7000, 0xa082, 0x0002, 0x1240, - 0x7830, 0xd0bc, 0x1128, 0x789b, 0x0080, 0x7baa, 0x0804, 0x2708, - 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, 0x0005, 0x70ac, 0xa606, - 0x1108, 0x76a8, 0x76b2, 0x2c3a, 0x8738, 0x2d3a, 0x8738, 0x283a, - 0x8738, 0x233a, 0x8738, 0x253a, 0x7830, 0xd0bc, 0x0150, 0x2091, - 0x8000, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, - 0x2090, 0xaad5, 0x0000, 0x0120, 0x8421, 0x2200, 0x1904, 0x2612, - 0x0005, 0xd1dc, 0x0904, 0x35d5, 0x2029, 0x0020, 0xd69c, 0x1120, - 0x8528, 0xd68c, 0x1108, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, - 0xa18c, 0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0188, 0x6014, - 0xa706, 0x1dd0, 0x60b8, 0x8001, 0x60ba, 0x1d88, 0x2a60, 0x6008, - 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x1904, 0x2612, 0x0005, - 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840, 0x6008, 0xc0d5, - 0x600a, 0x77a4, 0xa786, 0x0001, 0x1904, 0x2698, 0x70d4, 0xd0b4, - 0x1904, 0x2698, 0x7000, 0xa082, 0x0002, 0x1a04, 0x2698, 0x7830, - 0xd0bc, 0x1904, 0x2698, 0x789b, 0x0080, 0x7baa, 0x7daa, 0x79aa, - 0x2001, 0x0002, 0x0006, 0x6018, 0x8000, 0x601a, 0x0008, 0x0006, - 0x2960, 0x6104, 0x2a60, 0x080c, 0x3b3b, 0x1590, 0xa184, 0x0018, - 0x0180, 0xa184, 0x0010, 0x0118, 0x080c, 0x3776, 0x1548, 0xa184, - 0x0008, 0x0138, 0x69a0, 0xa184, 0x0600, 0x1118, 0x080c, 0x3696, - 0x00f8, 0x69a0, 0xa184, 0x1e00, 0x0528, 0xa184, 0x0800, 0x0178, - 0x00c6, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, - 0x0010, 0x6106, 0x00ce, 0x080c, 0x3776, 0x1150, 0x69a0, 0xa184, - 0x0200, 0x0118, 0x080c, 0x36d9, 0x0018, 0xa184, 0x0400, 0x19f0, - 0x69a0, 0xa184, 0x1000, 0x0130, 0x6914, 0xa18c, 0xff00, 0x810f, - 0x080c, 0x231f, 0x002e, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0128, - 0xa086, 0x0060, 0x1110, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, - 0x789b, 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, - 0x0168, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0328, 0xa08a, - 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, 0x78aa, 0x3518, - 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0, 0x789b, - 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898, 0x25a0, - 0xa286, 0x0020, 0x1508, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, - 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, 0x7882, 0xa286, 0x0002, - 0x0904, 0x27e0, 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa498, 0x0005, - 0x70ac, 0xa306, 0x1108, 0x73a8, 0x73b6, 0xa286, 0x0010, 0x0904, - 0x248c, 0x00de, 0x00ce, 0x0005, 0x7000, 0xa005, 0x19e0, 0xa286, - 0x0002, 0x1904, 0x27f7, 0x080c, 0x3a8d, 0x19a8, 0x6814, 0xc0fc, - 0x8007, 0x7882, 0x2091, 0x8000, 0x781b, 0x0068, 0x68b4, 0x785a, - 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, - 0x7808, 0xc08d, 0x780a, 0x0126, 0x00d6, 0x00c6, 0x70d4, 0xa084, - 0x2e00, 0x2090, 0x00ce, 0x00de, 0x012e, 0x2900, 0x705a, 0x68bc, - 0x7042, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, - 0x7830, 0xd0bc, 0x0140, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, - 0x2091, 0x8000, 0x2090, 0x70a4, 0xa005, 0x1108, 0x0005, 0x8421, - 0x0de8, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0804, 0x2612, 0xa286, - 0x0010, 0x1560, 0x080c, 0x3a8d, 0x1904, 0x278b, 0x6814, 0xc0fc, - 0x8007, 0x7882, 0x781b, 0x0068, 0x68b4, 0x785a, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x70a4, - 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, 0xa206, 0x1108, - 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, 0x0002, - 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x0005, 0x6bb4, 0xa39d, - 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x6b94, 0x7bd6, - 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x0068, 0x2900, 0x705a, - 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605, 0x0170, 0x70d4, - 0xa084, 0x2e00, 0xa086, 0x2600, 0x1118, 0x2009, 0x0000, 0x0010, - 0x2009, 0x0001, 0xa284, 0x000f, 0x0023, 0xad80, 0x0009, 0x7046, - 0x0005, 0x2859, 0x3fb8, 0x3fb8, 0x3fa6, 0x3fb8, 0x2859, 0x2859, - 0x2859, 0x080c, 0x243b, 0x7808, 0xa084, 0xfffd, 0x780a, 0x00f6, - 0x2079, 0x4300, 0x78ac, 0x00fe, 0xd084, 0x01c0, 0x7064, 0xa086, - 0x0001, 0x1118, 0x7066, 0x0804, 0x293a, 0x7064, 0xa086, 0x0005, - 0x1158, 0x707c, 0x2068, 0x681b, 0x0004, 0x6817, 0x0000, 0x6820, - 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7067, 0x0000, 0x70a7, 0x0000, - 0x70a8, 0x70b2, 0x70b6, 0x080c, 0x256f, 0x0156, 0x2011, 0x0004, - 0x7164, 0xa186, 0x0001, 0x0170, 0xa186, 0x0007, 0x1118, 0x701f, - 0x0005, 0x0040, 0x701f, 0x0001, 0x7067, 0x0000, 0x70d4, 0xc0c5, - 0x70d6, 0x0010, 0x7067, 0x0000, 0x2001, 0x430a, 0x2004, 0xa084, - 0x00ff, 0xa086, 0x0018, 0x0130, 0x7018, 0x7016, 0xa005, 0x1110, - 0x70a7, 0x0001, 0x0066, 0x080c, 0x3d52, 0x20a9, 0x0010, 0x2039, - 0x0000, 0x080c, 0x3861, 0xa7b8, 0x0100, 0x1f04, 0x28b1, 0x006e, - 0x7000, 0x0002, 0x28ee, 0x28cc, 0x28cc, 0x28c4, 0x28ee, 0x28ee, - 0x28ee, 0x28c2, 0x080c, 0x243b, 0x7060, 0xa005, 0x0538, 0xad06, - 0x1118, 0x6800, 0x7062, 0x0080, 0x6820, 0xd084, 0x1148, 0x6f14, - 0x080c, 0x396d, 0x6008, 0xc0d4, 0x600a, 0x080c, 0x35ab, 0x0020, - 0x705c, 0x2060, 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, - 0xd0fc, 0x0108, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820, - 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1d3d, 0xb284, 0x0800, - 0x0118, 0x2021, 0x8ad0, 0x0010, 0x2021, 0x89c0, 0x080c, 0x293f, - 0xb284, 0x0800, 0x0118, 0x2021, 0x4398, 0x0010, 0x2021, 0x4358, - 0x04f1, 0x20a9, 0x0101, 0xb284, 0x0800, 0x0118, 0x2021, 0x89d0, - 0x0010, 0x2021, 0x88c0, 0x0499, 0x8420, 0x1f04, 0x290b, 0xb284, - 0x0600, 0x0118, 0x2061, 0x48c0, 0x0010, 0x2061, 0x68c0, 0x2021, - 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0198, 0x6018, 0x0016, - 0x0006, 0x2011, 0x4302, 0x220c, 0xa102, 0x2012, 0x000e, 0x001e, - 0xa102, 0x0338, 0x6012, 0x1128, 0x2011, 0x4304, 0x2204, 0xc0a5, - 0x2012, 0x601b, 0x0000, 0xace0, 0x0010, 0x1f04, 0x291b, 0x8421, - 0x1d00, 0x015e, 0x7003, 0x0000, 0x704f, 0x0000, 0x0005, 0x0046, - 0x2404, 0xa005, 0x01a8, 0x2068, 0x6800, 0x0006, 0x6a1a, 0x6817, + 0x2091, 0x8001, 0x7808, 0xc08d, 0x780a, 0x0126, 0x00d6, 0x00c6, + 0x70d0, 0xa084, 0x2e00, 0x2090, 0x00ce, 0x00de, 0x012e, 0x2900, + 0x7056, 0x68bc, 0x703e, 0x7003, 0x0002, 0x2d00, 0x704a, 0xad80, + 0x0009, 0x7042, 0x7830, 0xd0bc, 0x0140, 0x2091, 0x303d, 0x70d0, + 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0x70a0, 0xa005, 0x1108, + 0x0005, 0x8421, 0x0de8, 0x724c, 0x70bc, 0xa200, 0xa015, 0x0804, + 0x2704, 0xa286, 0x0010, 0x1560, 0x080c, 0x3bf9, 0x1904, 0x287d, + 0x6814, 0xc0fc, 0x8007, 0x7882, 0x781b, 0x0068, 0x68b4, 0x785a, + 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, + 0x780a, 0x70a0, 0x8000, 0x70a2, 0x74b0, 0xa490, 0x0005, 0x70a8, + 0xa206, 0x1108, 0x72a4, 0x72b2, 0x2900, 0x7056, 0x68bc, 0x703e, + 0x7003, 0x0002, 0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x0005, + 0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x0068, + 0x2900, 0x7056, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605, + 0x0170, 0x70d0, 0xa084, 0x2e00, 0xa086, 0x2600, 0x1118, 0x2009, + 0x0000, 0x0010, 0x2009, 0x0001, 0xa284, 0x000f, 0x0023, 0xad80, + 0x0009, 0x7042, 0x0005, 0x294b, 0x4180, 0x4180, 0x416e, 0x4180, + 0x294b, 0x294b, 0x294b, 0x080c, 0x252b, 0x7808, 0xa084, 0xfffd, + 0x780a, 0x00f6, 0x2079, 0x4500, 0x78ac, 0x00fe, 0xd084, 0x01b0, + 0x7060, 0xa086, 0x0001, 0x0904, 0x2a29, 0x7060, 0xa086, 0x0005, + 0x1158, 0x7078, 0x2068, 0x681b, 0x0004, 0x6817, 0x0000, 0x6820, + 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7063, 0x0000, 0x70a3, 0x0000, + 0x70a4, 0x70ae, 0x70b2, 0x080c, 0x2661, 0x0156, 0x2011, 0x0004, + 0x7160, 0xa186, 0x0001, 0x0160, 0xa186, 0x0007, 0x1118, 0x701f, + 0x0005, 0x0030, 0x701f, 0x0001, 0x70d0, 0xc0c5, 0x70d2, 0x0000, + 0x2001, 0x450a, 0x2004, 0xa084, 0x00ff, 0xa086, 0x0018, 0x0130, + 0x7018, 0x7016, 0xa005, 0x1110, 0x70a3, 0x0001, 0x0066, 0x080c, + 0x3ed9, 0x20a9, 0x0010, 0x2039, 0x0000, 0x080c, 0x3a29, 0xa7b8, + 0x0100, 0x1f04, 0x299d, 0x006e, 0x7000, 0x0002, 0x29da, 0x29b8, + 0x29b8, 0x29b0, 0x29da, 0x29da, 0x29da, 0x29ae, 0x080c, 0x252b, + 0x705c, 0xa005, 0x0538, 0xad06, 0x1118, 0x6800, 0x705e, 0x0080, + 0x6820, 0xd084, 0x1148, 0x6f14, 0x080c, 0x3b35, 0x6008, 0xc0d4, + 0x600a, 0x080c, 0x376c, 0x0020, 0x7058, 0x2060, 0x6800, 0x6002, + 0xa684, 0x5f00, 0x681e, 0x6818, 0xd0fc, 0x0108, 0x6a1a, 0x6817, + 0x0000, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, + 0x080c, 0x1d89, 0x2011, 0x0004, 0xb284, 0x0800, 0x0118, 0x2021, + 0x8cd0, 0x0010, 0x2021, 0x8bc0, 0x080c, 0x2a30, 0xb284, 0x0800, + 0x0118, 0x2021, 0x4597, 0x0010, 0x2021, 0x4557, 0x080c, 0x2a30, + 0x20a9, 0x0101, 0xb284, 0x0800, 0x0118, 0x2021, 0x8bd0, 0x0010, + 0x2021, 0x8ac0, 0x04a9, 0x8420, 0x1f04, 0x29fa, 0xb284, 0x0600, + 0x0118, 0x2061, 0x4ac0, 0x0010, 0x2061, 0x6ac0, 0x2021, 0x0002, + 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0198, 0x6018, 0x0016, 0x0006, + 0x2011, 0x4502, 0x220c, 0xa102, 0x2012, 0x000e, 0x001e, 0xa102, + 0x0338, 0x6012, 0x1128, 0x2011, 0x4504, 0x2204, 0xc0a5, 0x2012, + 0x601b, 0x0000, 0xace0, 0x0010, 0x1f04, 0x2a0a, 0x8421, 0x1d00, + 0x015e, 0x7063, 0x0000, 0x7003, 0x0000, 0x704b, 0x0000, 0x0005, + 0x0046, 0x2404, 0xa005, 0x01a8, 0x2068, 0x6800, 0x0006, 0x6a1a, + 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, + 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1d89, 0x000e, + 0x0c48, 0x004e, 0x2023, 0x0000, 0x0005, 0xa282, 0x0003, 0x0310, + 0x080c, 0x252b, 0x2300, 0x0002, 0x2a57, 0x2ad4, 0x2aee, 0xa282, + 0x0002, 0x0110, 0x080c, 0x252b, 0x7060, 0x7063, 0x0000, 0x707f, + 0x0000, 0x0022, 0x77d0, 0xc7c5, 0x77d2, 0x0002, 0x2a6e, 0x2a6e, + 0x2a70, 0x2aa8, 0x37a0, 0x2a6e, 0x2aa8, 0x2a6e, 0x080c, 0x252b, + 0x7770, 0x080c, 0x3a29, 0x7770, 0xa7bc, 0x8f00, 0x080c, 0x3b35, + 0x6018, 0xa005, 0x0528, 0xd7fc, 0x1118, 0x2021, 0x8bc0, 0x0010, + 0x2021, 0x8cd0, 0x2009, 0x0005, 0x2011, 0x0010, 0x080c, 0x2b08, + 0x01b8, 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, 0x2021, 0x8ac0, + 0x0010, 0x2021, 0x8bd0, 0x0046, 0x2009, 0x0005, 0x2011, 0x0010, + 0x080c, 0x2b08, 0x004e, 0x0118, 0x8420, 0x1f04, 0x2a93, 0x015e, + 0x8738, 0xa784, 0x001f, 0x1990, 0x0804, 0x257f, 0x0804, 0x257f, + 0x7770, 0x080c, 0x3b35, 0x6018, 0xa005, 0x0520, 0xd7fc, 0x1118, + 0x2021, 0x8bc0, 0x0010, 0x2021, 0x8cd0, 0x2009, 0x0005, 0x2011, + 0x0020, 0x080c, 0x2b08, 0x01b0, 0x0156, 0x20a9, 0x0101, 0xd7fc, + 0x1118, 0x2021, 0x8ac0, 0x0010, 0x2021, 0x8bd0, 0x0046, 0x2009, + 0x0005, 0x2011, 0x0020, 0x04e1, 0x004e, 0x0118, 0x8420, 0x1f04, + 0x2ac6, 0x015e, 0x0804, 0x257f, 0x2200, 0x0002, 0x2ad9, 0x2adb, + 0x2adb, 0x080c, 0x252b, 0x2009, 0x0012, 0x7060, 0xa086, 0x0002, + 0x0110, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0108, 0x691a, 0x7063, + 0x0000, 0x70d0, 0xc0c5, 0x70d2, 0x0804, 0x3bab, 0x2200, 0x0002, + 0x2af5, 0x2adb, 0x2af3, 0x080c, 0x252b, 0x080c, 0x3ed9, 0x7000, + 0xa086, 0x0002, 0x1904, 0x3725, 0x080c, 0x3786, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x080c, 0x3717, 0x0904, 0x3725, 0x0804, 0x257f, + 0x2404, 0xa005, 0x0590, 0x2068, 0x2d04, 0x0006, 0x6814, 0xa706, + 0x0118, 0x2d20, 0x000e, 0x0ca8, 0x000e, 0x2022, 0x691a, 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, - 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1d3d, 0x000e, 0x0c48, - 0x004e, 0x2023, 0x0000, 0x0005, 0xa282, 0x0003, 0x0310, 0x080c, - 0x243b, 0x2300, 0x0002, 0x2966, 0x29e3, 0x29fd, 0xa282, 0x0002, - 0x0110, 0x080c, 0x243b, 0x7064, 0x7067, 0x0000, 0x7083, 0x0000, - 0x0022, 0x77d4, 0xc7c5, 0x77d6, 0x0002, 0x297d, 0x297d, 0x297f, - 0x29b7, 0x35df, 0x297d, 0x29b7, 0x297d, 0x080c, 0x243b, 0x7774, - 0x080c, 0x3861, 0x7774, 0xa7bc, 0x8f00, 0x080c, 0x396d, 0x6018, - 0xa005, 0x0528, 0xd7fc, 0x1118, 0x2021, 0x89c0, 0x0010, 0x2021, - 0x8ad0, 0x2009, 0x0005, 0x2011, 0x0010, 0x080c, 0x2a17, 0x01b8, - 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, 0x2021, 0x88c0, 0x0010, - 0x2021, 0x89d0, 0x0046, 0x2009, 0x0005, 0x2011, 0x0010, 0x080c, - 0x2a17, 0x004e, 0x0118, 0x8420, 0x1f04, 0x29a2, 0x015e, 0x8738, - 0xa784, 0x001f, 0x1990, 0x0804, 0x248f, 0x0804, 0x248f, 0x7774, - 0x080c, 0x396d, 0x6018, 0xa005, 0x0520, 0xd7fc, 0x1118, 0x2021, - 0x89c0, 0x0010, 0x2021, 0x8ad0, 0x2009, 0x0005, 0x2011, 0x0020, - 0x080c, 0x2a17, 0x01b0, 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, - 0x2021, 0x88c0, 0x0010, 0x2021, 0x89d0, 0x0046, 0x2009, 0x0005, - 0x2011, 0x0020, 0x04e1, 0x004e, 0x0118, 0x8420, 0x1f04, 0x29d5, - 0x015e, 0x0804, 0x248f, 0x2200, 0x0002, 0x29e8, 0x29ea, 0x29ea, - 0x080c, 0x243b, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002, 0x0110, - 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0108, 0x691a, 0x7067, 0x0000, - 0x70d4, 0xc0c5, 0x70d6, 0x0804, 0x3a3f, 0x2200, 0x0002, 0x2a04, - 0x29ea, 0x2a02, 0x080c, 0x243b, 0x080c, 0x3d52, 0x7000, 0xa086, - 0x0002, 0x1904, 0x356d, 0x080c, 0x35c5, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x080c, 0x355f, 0x0904, 0x356d, 0x0804, 0x248f, 0x2404, - 0xa005, 0x0590, 0x2068, 0x2d04, 0x0006, 0x6814, 0xa706, 0x0118, - 0x2d20, 0x000e, 0x0ca8, 0x000e, 0x2022, 0x691a, 0x6817, 0x0000, - 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, - 0x00ff, 0xa205, 0x6822, 0x080c, 0x1d3d, 0x2021, 0x4302, 0x241c, - 0x8319, 0x2322, 0x6010, 0x8001, 0x6012, 0x1128, 0x2021, 0x4304, - 0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x080c, - 0x258b, 0x080c, 0x35c5, 0x0005, 0xa085, 0x0001, 0x0ce0, 0x2300, - 0x0002, 0x2a56, 0x2a54, 0x2abc, 0x080c, 0x243b, 0x78e4, 0xa005, - 0x1708, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104, 0x248c, 0x0010, - 0x0304, 0x248c, 0x2008, 0xa084, 0x0030, 0x1110, 0x0804, 0x30a0, - 0x78ec, 0xa084, 0x0003, 0x0dd0, 0x2100, 0xa084, 0x0007, 0x0002, - 0x2a9f, 0x2aa8, 0x2a95, 0x2a78, 0x3a83, 0x3a83, 0x2a78, 0x2ab2, - 0x080c, 0x243b, 0x7000, 0xa086, 0x0004, 0x1190, 0x7064, 0xa086, - 0x0002, 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x295c, - 0x7064, 0xa086, 0x0006, 0x0db0, 0x7064, 0xa086, 0x0004, 0x0d90, - 0x79e4, 0x2001, 0x0003, 0x0804, 0x2daa, 0x6818, 0xd0fc, 0x0110, - 0x681b, 0x001d, 0x080c, 0x3837, 0x781b, 0x006e, 0x0005, 0x6818, - 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3837, 0x0804, 0x3a61, - 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3837, 0x781b, - 0x00fa, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, - 0x3837, 0x781b, 0x00cb, 0x0005, 0xa584, 0x000f, 0x11c0, 0x7000, - 0x0002, 0x248f, 0x2ac9, 0x2acb, 0x356d, 0x356d, 0x356d, 0x2ac9, - 0x2ac9, 0x080c, 0x243b, 0x080c, 0x35c5, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x080c, 0x355f, 0x0904, 0x356d, 0x0804, 0x248f, 0x78e4, - 0xa005, 0x1b04, 0x2a7a, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104, - 0x2a7a, 0x0010, 0x0304, 0x2a7a, 0x2008, 0xa084, 0x0030, 0x1118, - 0x781b, 0x0068, 0x0005, 0x78ec, 0xa084, 0x0003, 0x0dc8, 0x2100, - 0xa184, 0x0007, 0x0002, 0x2b02, 0x2b06, 0x2afd, 0x2afb, 0x3a83, - 0x3a83, 0x2afb, 0x3a7d, 0x080c, 0x243b, 0x080c, 0x383d, 0x781b, - 0x006e, 0x0005, 0x080c, 0x383d, 0x0804, 0x3a61, 0x080c, 0x383d, - 0x781b, 0x00fa, 0x0005, 0x080c, 0x383d, 0x781b, 0x00cb, 0x0005, - 0x2300, 0x0002, 0x2b17, 0x2b15, 0x2b19, 0x080c, 0x243b, 0x0804, - 0x3220, 0x681b, 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, - 0x0904, 0x3220, 0x78ec, 0xa084, 0x0003, 0x0904, 0x3220, 0xa184, - 0x0100, 0x0d98, 0xa184, 0x0007, 0x0002, 0x2b35, 0x2b06, 0x2a95, - 0x3a3f, 0x3a83, 0x3a83, 0x3a3f, 0x3a7d, 0x080c, 0x3a4b, 0x0005, - 0xa282, 0x0005, 0x0310, 0x080c, 0x243b, 0x7898, 0x2040, 0x2300, - 0x0002, 0x2b44, 0x2d41, 0x2d4b, 0x2200, 0x0002, 0x2b60, 0x2b4d, - 0x2b60, 0x2b4b, 0x2d25, 0x080c, 0x243b, 0x789b, 0x0018, 0x78a8, - 0x2010, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0a04, 0x3809, 0xa08a, - 0x0004, 0x1a04, 0x3809, 0x0002, 0x3809, 0x3809, 0x3809, 0x37bf, - 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0148, 0x0804, 0x3809, - 0x7000, 0xa005, 0x1dd8, 0x2011, 0x0004, 0x0804, 0x33b2, 0xa184, - 0x00ff, 0xa08a, 0x0010, 0x1a04, 0x3809, 0x0002, 0x2b88, 0x2b86, - 0x2b9a, 0x2b9e, 0x2c3c, 0x3809, 0x3809, 0x2c3e, 0x3809, 0x3809, - 0x2d21, 0x2d21, 0x3809, 0x3809, 0x3809, 0x2d23, 0x080c, 0x243b, - 0xd6e4, 0x0140, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, - 0x00c6, 0x0005, 0x6818, 0xd0fc, 0x0118, 0x681b, 0x001d, 0x0c90, - 0x0804, 0x3a3f, 0x681b, 0x001d, 0x0804, 0x3831, 0x6920, 0x6922, - 0xa684, 0x1800, 0x15e0, 0x6820, 0xd084, 0x1904, 0x2be7, 0x6818, - 0xa086, 0x0008, 0x1110, 0x681b, 0x0000, 0xd6d4, 0x0568, 0xd6bc, - 0x0558, 0x7087, 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, - 0x0718, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, - 0x789b, 0x0061, 0x78aa, 0x0156, 0x0136, 0x0146, 0x0016, 0x3208, - 0xa18c, 0x0600, 0x0118, 0x20a1, 0x022b, 0x0010, 0x20a1, 0x012b, - 0x001e, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, - 0x53a6, 0x014e, 0x013e, 0x015e, 0x781b, 0x0071, 0x0005, 0xd6e4, - 0x0130, 0x781b, 0x0083, 0x0005, 0x781b, 0x0083, 0x0005, 0xa684, - 0x0060, 0x0dd0, 0xd6dc, 0x0dc0, 0xd6fc, 0x01a0, 0xc6fc, 0x7e5a, - 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x8007, 0xa084, 0x007f, 0xa108, - 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, - 0xa303, 0x68ae, 0xd6f4, 0x0118, 0xc6f4, 0x7e5a, 0x6eb6, 0x7000, - 0xa086, 0x0003, 0x1148, 0x0006, 0x080c, 0x3d52, 0x080c, 0x3fb8, - 0x000e, 0x781b, 0x0080, 0x0005, 0xa006, 0x080c, 0x4083, 0x6ab0, - 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0120, 0x2200, 0xa422, - 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde, - 0x2300, 0xa405, 0x1130, 0xc6f5, 0x7e5a, 0x6eb6, 0x781b, 0x0080, - 0x0005, 0x781b, 0x0080, 0x2200, 0xa115, 0x1118, 0x080c, 0x3fb8, - 0x0005, 0x080c, 0x3fe5, 0x0005, 0x080c, 0x243b, 0x0804, 0x2cbd, - 0x00c6, 0x7058, 0x2060, 0x7aa8, 0xa294, 0x00ff, 0xa286, 0x0004, - 0x11d8, 0x6920, 0xd1e4, 0x1170, 0x2039, 0x0000, 0x2041, 0x0000, - 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x36f6, 0x080c, 0x379a, - 0x0804, 0x2cb1, 0xa18c, 0xecff, 0x6922, 0x6104, 0xa18c, 0xffdd, - 0x6106, 0x6000, 0xc0ac, 0x6002, 0xa286, 0x0003, 0x01d0, 0x6104, - 0xa18c, 0x0010, 0x0548, 0x080c, 0x3969, 0x080c, 0x3776, 0x88ff, - 0x0518, 0x00ce, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, - 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, - 0x0005, 0x6920, 0xd1cc, 0x0130, 0xa18c, 0xfdff, 0x6922, 0x6000, - 0xc0ec, 0x6002, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, 0x0000, - 0xa006, 0x2010, 0x080c, 0x379a, 0xa286, 0x0001, 0x0158, 0x6104, - 0xa18c, 0x0008, 0x01b0, 0x080c, 0x3969, 0x080c, 0x3696, 0x88ff, - 0x1980, 0x0078, 0x6920, 0xd1c4, 0x0130, 0xa18c, 0xfeff, 0x6922, - 0x6000, 0xc0e4, 0x6002, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, - 0x36f6, 0x00ce, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, - 0x781b, 0x0083, 0x0005, 0x0804, 0x382d, 0x2808, 0x789b, 0x0080, - 0x2019, 0x0080, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x1188, - 0x7ca8, 0xa4a4, 0x00ff, 0xa480, 0x0002, 0xa300, 0x2018, 0xa102, - 0x0a04, 0x2c40, 0x0904, 0x2c40, 0x24a8, 0x7aa8, 0x1f04, 0x2cd5, - 0x0c48, 0xa284, 0x00f0, 0xa082, 0x0020, 0x06b8, 0x2200, 0xa082, - 0x0021, 0x1698, 0x7aa8, 0x8318, 0x8318, 0x2100, 0xa302, 0x0ad0, - 0xa286, 0x0023, 0x0980, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, - 0xa684, 0xfff1, 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, - 0x78a0, 0x8001, 0x0904, 0x2cb1, 0x20a8, 0x7998, 0x789b, 0x0060, - 0x78aa, 0x2011, 0x0080, 0x799a, 0x78a8, 0x7998, 0x7a9a, 0x78aa, - 0x7a98, 0x1f04, 0x2d03, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, - 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x8318, 0x2100, 0xa302, - 0x0a04, 0x2cc2, 0xa284, 0x0080, 0x1904, 0x3831, 0x78a0, 0xa005, - 0x08c8, 0x0804, 0x3831, 0x0804, 0x3809, 0x7058, 0xa04d, 0x789b, - 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0110, 0x080c, - 0x243b, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, - 0x0005, 0x1a04, 0x3809, 0x0002, 0x3809, 0x3615, 0x3809, 0x3726, - 0x3b83, 0xa282, 0x0000, 0x1110, 0x080c, 0x243b, 0x080c, 0x3837, - 0x781b, 0x0082, 0x0005, 0xa282, 0x0003, 0x1110, 0x080c, 0x243b, - 0xd4fc, 0x11d0, 0x7064, 0xa005, 0x0110, 0x080c, 0x243b, 0x6f14, - 0x7776, 0xa7bc, 0x8f00, 0x080c, 0x396d, 0x6008, 0xa085, 0x0021, - 0x600a, 0x8738, 0xa784, 0x001f, 0x1db0, 0x080c, 0x383a, 0x7067, - 0x0002, 0x701f, 0x0009, 0x0010, 0x080c, 0x3846, 0x781b, 0x0082, - 0x0005, 0xa282, 0x0004, 0x0310, 0x080c, 0x243b, 0x2300, 0x0002, - 0x2d7b, 0x2eff, 0x2f3b, 0xa286, 0x0003, 0x0560, 0x7200, 0x7cd8, - 0x7ddc, 0x7fd0, 0x71d4, 0xd1b4, 0x00f0, 0x7868, 0xa084, 0x00ff, - 0x11d0, 0xa282, 0x0002, 0x12b8, 0x00d6, 0x783b, 0x8300, 0x781b, - 0x0059, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, - 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x00de, - 0x2001, 0x0000, 0x0058, 0x783b, 0x1300, 0x781b, 0x0057, 0x2001, - 0x0000, 0x0020, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x704a, 0x68a0, - 0xd0ec, 0x0118, 0x6008, 0xc08d, 0x600a, 0xa284, 0x000f, 0x0002, - 0x2ee0, 0x2dc5, 0x2dc2, 0x3012, 0x3085, 0x248f, 0x2dc0, 0x2dc0, - 0x080c, 0x243b, 0x6008, 0xc0d4, 0x600a, 0xd6e4, 0x0120, 0x7048, - 0xa086, 0x0014, 0x11e8, 0x080c, 0x3d52, 0x2009, 0x0000, 0x6818, - 0xd0fc, 0x0108, 0x7048, 0xa086, 0x0014, 0x0168, 0x6818, 0xa086, - 0x0008, 0x1904, 0x2ea2, 0x7858, 0xd09c, 0x0904, 0x2ea2, 0x6820, - 0xd0ac, 0x0904, 0x2ea2, 0x681b, 0x0014, 0x2009, 0x0002, 0x04a8, - 0x7868, 0xa08c, 0x00ff, 0x0588, 0xa186, 0x0008, 0x1158, 0x6008, - 0xc0a4, 0x600a, 0x080c, 0x355f, 0x0540, 0x080c, 0x35c5, 0x080c, - 0x3d52, 0x0060, 0xa186, 0x0028, 0x1500, 0x6018, 0xa005, 0x0d78, - 0x8001, 0x0d68, 0x8001, 0x0d58, 0x601e, 0x0c48, 0x6820, 0xd084, - 0x0904, 0x248f, 0xc084, 0x6822, 0x080c, 0x2580, 0x705c, 0x00c6, - 0x2060, 0x6800, 0x6002, 0x00ce, 0x6004, 0x6802, 0xa005, 0x2d00, - 0x1108, 0x6002, 0x6006, 0x0804, 0x248f, 0x0016, 0x81ff, 0x15e0, - 0x7000, 0xa086, 0x0030, 0x05c0, 0x71d4, 0xd1b4, 0x11e8, 0x7060, - 0xa005, 0x1590, 0x70a4, 0xa086, 0x0001, 0x0570, 0x7003, 0x0000, - 0x0046, 0x0056, 0x0076, 0x0066, 0x00c6, 0x00d6, 0x080c, 0x24b2, - 0x00de, 0x00ce, 0x006e, 0x007e, 0x005e, 0x004e, 0x71d4, 0xd1b4, - 0x11d8, 0x7003, 0x0040, 0x00c0, 0x080c, 0x3a8d, 0x11a8, 0x781b, - 0x0068, 0x00d6, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, - 0x7808, 0xc08d, 0x780a, 0x00de, 0x080c, 0x2f63, 0x001e, 0x81ff, - 0x0904, 0x2ea2, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, - 0xa186, 0x0002, 0x15c0, 0x6818, 0xa086, 0x0014, 0x1130, 0x2008, - 0xd6e4, 0x0118, 0x7868, 0xa08c, 0x00ff, 0x080c, 0x3850, 0x080c, - 0x258b, 0x6820, 0xd0dc, 0x1538, 0x8717, 0xa294, 0x000f, 0x8213, - 0x8213, 0x8213, 0xb284, 0x0600, 0x0118, 0xa290, 0x47c0, 0x0010, - 0xa290, 0x4840, 0xa290, 0x0000, 0x221c, 0xd3c4, 0x0130, 0x8210, - 0x2204, 0xa085, 0x0038, 0x2012, 0x8211, 0xd3d4, 0x0138, 0x68a0, - 0xd0c4, 0x1120, 0x080c, 0x2fcb, 0x0804, 0x248f, 0x6008, 0xc08d, - 0x600a, 0x0008, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0110, 0x7048, - 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, 0x0168, 0x2009, - 0x4302, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, - 0x4304, 0x2404, 0xc0a5, 0x2022, 0x6018, 0xa005, 0x0118, 0x8001, - 0x601a, 0x1118, 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084, 0x1130, - 0x6800, 0xa005, 0x1108, 0x6002, 0x6006, 0x0020, 0x705c, 0x2060, - 0x6800, 0x6002, 0x2061, 0x4300, 0x6887, 0x0103, 0x2d08, 0x206b, - 0x0000, 0x6068, 0xa005, 0x616a, 0x0110, 0x2d02, 0x0008, 0x616e, - 0x7200, 0xa286, 0x0030, 0x0158, 0xa286, 0x0040, 0x1904, 0x248f, - 0x7003, 0x0002, 0x704c, 0x2068, 0x68c4, 0x2060, 0x0005, 0x7003, - 0x0002, 0x70bc, 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, 0x68c0, - 0x705a, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x0005, 0xa282, - 0x0004, 0x0210, 0x080c, 0x243b, 0x2200, 0x0002, 0x2f0a, 0x2f19, - 0x2f25, 0x2f19, 0xa586, 0x1300, 0x0160, 0xa586, 0x8300, 0x1d90, - 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x7000, 0xa086, 0x0005, 0x0128, 0x080c, 0x3837, 0x781b, - 0x0082, 0x0005, 0x781b, 0x0083, 0x0005, 0x7890, 0x8007, 0x8001, - 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, - 0xa186, 0x0003, 0x0128, 0xa186, 0x0000, 0x0110, 0x0804, 0x3809, - 0x781b, 0x0083, 0x0005, 0x6820, 0xc095, 0x6822, 0x82ff, 0x1118, - 0x080c, 0x3837, 0x0030, 0x8211, 0x0110, 0x080c, 0x243b, 0x080c, - 0x3846, 0x781b, 0x0082, 0x0005, 0x080c, 0x3aa0, 0x7830, 0xa084, - 0x00c0, 0x1170, 0x0016, 0x3208, 0xa18c, 0x0800, 0x001e, 0x0118, - 0x0104, 0x2f60, 0x0010, 0x0304, 0x2f60, 0x791a, 0xa006, 0x0005, - 0xa085, 0x0001, 0x0005, 0xa684, 0x0060, 0x1130, 0x682f, 0x0000, - 0x6833, 0x0000, 0x0804, 0x2fca, 0xd6dc, 0x1198, 0x68b4, 0xd0dc, - 0x1180, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x1130, - 0x2200, 0xa105, 0x0904, 0x3d52, 0x704b, 0x0015, 0x0804, 0x3d52, - 0x0005, 0xd6ac, 0x01f0, 0xd6f4, 0x0130, 0x682f, 0x0000, 0x6833, - 0x0000, 0x0804, 0x3d52, 0x68b4, 0xa084, 0x4000, 0xa635, 0xd6f4, - 0x1da0, 0x7048, 0xa005, 0x1110, 0x704b, 0x0015, 0xd6dc, 0x1128, - 0x68b4, 0xd0dc, 0x0110, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0804, - 0x3d52, 0xd6f4, 0x0130, 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, - 0x3d52, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x1da0, 0x7048, - 0xa005, 0x1110, 0x704b, 0x0015, 0x2408, 0x2510, 0x2700, 0x8007, - 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, - 0xa205, 0x1110, 0x0804, 0x3d52, 0x7000, 0xa086, 0x0006, 0x0110, - 0x0804, 0x3d52, 0x0005, 0x6946, 0x6008, 0xc0cd, 0xd3cc, 0x0108, - 0xc08d, 0x600a, 0x6818, 0x683a, 0x681b, 0x0006, 0x688f, 0x0000, - 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, - 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, - 0x7000, 0x0002, 0x248f, 0x2ffa, 0x2ff4, 0x2ff2, 0x2ff2, 0x2ff2, - 0x2ff2, 0x2ff2, 0x080c, 0x243b, 0x6820, 0xd084, 0x1118, 0x080c, - 0x35ab, 0x0030, 0x705c, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, - 0x3208, 0xa18c, 0x0600, 0x0118, 0x2021, 0x4358, 0x0010, 0x2021, - 0x4398, 0x2404, 0xa005, 0x0110, 0x2020, 0x0cd8, 0x2d22, 0x206b, - 0x0000, 0x0005, 0x080c, 0x35b1, 0x080c, 0x35c5, 0x6008, 0xc0cc, - 0x600a, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x6938, 0x691a, - 0x6944, 0x6916, 0x3208, 0xa18c, 0x0600, 0x0118, 0x2009, 0x0000, - 0x0010, 0x2009, 0x0001, 0x080c, 0x40b1, 0xd6dc, 0x0118, 0x691c, - 0xc1ed, 0x691e, 0x6818, 0xd0fc, 0x0148, 0x7868, 0xa08c, 0x00ff, - 0x0118, 0x681b, 0x001e, 0x0010, 0x681b, 0x0000, 0xb284, 0x0600, - 0x1118, 0x2021, 0x4398, 0x0010, 0x2021, 0x4358, 0x6800, 0x2022, - 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, 0xd0a4, - 0x0580, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x00d6, - 0x00f6, 0x0156, 0x0146, 0x2079, 0x4300, 0x080c, 0x1b35, 0x014e, - 0x015e, 0x00fe, 0x70cc, 0x2010, 0x2009, 0x0101, 0x0026, 0x2204, - 0xa06d, 0x0140, 0x6814, 0xa706, 0x0110, 0x6800, 0x0cc8, 0x6820, - 0xc0d5, 0x6822, 0x002e, 0x8210, 0x8109, 0x1d80, 0x00de, 0x7067, - 0x0003, 0x707f, 0x0000, 0x7776, 0x7083, 0x000f, 0x71d4, 0xc1c4, - 0x71d6, 0x080c, 0x1d3d, 0x0804, 0x248f, 0x7cd8, 0x7ddc, 0x7fd0, - 0x080c, 0x2f63, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x080c, - 0x3aa4, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xd0fc, 0x0110, 0x7048, - 0x681a, 0xa68c, 0xdf00, 0x691e, 0x7067, 0x0000, 0x0804, 0x248f, - 0x7000, 0xa005, 0x1110, 0x0804, 0x248f, 0xa006, 0x080c, 0x3d52, - 0x6920, 0xd1ac, 0x1110, 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, - 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, 0x6822, 0x7000, 0x0002, - 0x248f, 0x30c2, 0x30c2, 0x30c5, 0x30c5, 0x30c5, 0x30c0, 0x30c0, - 0x080c, 0x243b, 0x6818, 0x0804, 0x2daa, 0x6008, 0xc0a4, 0x600a, - 0x6817, 0x0000, 0x0804, 0x357a, 0x2300, 0x0002, 0x30d1, 0x30d3, - 0x3110, 0x080c, 0x243b, 0xd6fc, 0x1904, 0x2bee, 0x7000, 0xa00d, - 0x0002, 0x248f, 0x30e3, 0x30e3, 0x3104, 0x30e3, 0x310d, 0x30e1, - 0x30e1, 0x080c, 0x243b, 0xa684, 0x0060, 0xa086, 0x0060, 0x11d0, - 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x681c, 0xc0ac, 0x681e, 0xa186, - 0x0002, 0x0110, 0x080c, 0x3d52, 0x080c, 0x3fb8, 0x781b, 0x0083, - 0x71d4, 0xd1b4, 0x1904, 0x248c, 0x70a4, 0xa086, 0x0001, 0x1904, - 0x24ce, 0x0005, 0xd6ec, 0x0d30, 0x6818, 0xd0fc, 0x0130, 0x681b, - 0x0015, 0xd6f4, 0x0110, 0x681b, 0x0007, 0x080c, 0x3a4b, 0x0005, - 0x080c, 0x243b, 0x2300, 0x0002, 0x3119, 0x3134, 0x3182, 0x080c, - 0x243b, 0x7000, 0x0002, 0x3123, 0x3125, 0x3125, 0x3123, 0x3123, - 0x3123, 0x3123, 0x3123, 0x080c, 0x243b, 0x080c, 0x3fb8, 0x681c, - 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x1904, 0x248c, 0x70a4, 0xa086, - 0x0001, 0x1904, 0x24ce, 0x0005, 0xd6fc, 0x15e0, 0x7000, 0xa00d, - 0x0002, 0x248f, 0x3149, 0x3143, 0x316a, 0x3149, 0x316f, 0x3141, - 0x3141, 0x080c, 0x243b, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, - 0x78da, 0xa684, 0x0060, 0xa086, 0x0060, 0x11d0, 0xa6b4, 0xbfbf, - 0xc6ed, 0x7e5a, 0xa186, 0x0002, 0x0110, 0x080c, 0x3d52, 0x080c, - 0x3fb8, 0x781b, 0x0083, 0x681c, 0xc0b4, 0x681e, 0x71d4, 0xd1b4, - 0x1904, 0x248c, 0x70a4, 0xa086, 0x0001, 0x1904, 0x24ce, 0x0005, - 0xd6ec, 0x0d30, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x0007, 0x781b, - 0x00fb, 0x0005, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, - 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, - 0x0083, 0x0005, 0xd6dc, 0x0130, 0x782b, 0x3009, 0x781b, 0x0083, - 0x0804, 0x248c, 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, - 0x1150, 0xa484, 0x0200, 0x0108, 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, - 0x0083, 0x0804, 0x248c, 0x6820, 0xc095, 0x6822, 0x080c, 0x39ca, - 0xc6dd, 0x080c, 0x3837, 0x781b, 0x0082, 0x0804, 0x248c, 0x2300, - 0x0002, 0x31ac, 0x31ae, 0x31b0, 0x080c, 0x243b, 0x0804, 0x3831, - 0x7d98, 0xd6d4, 0x11f8, 0x79e4, 0xd1ac, 0x0130, 0x78ec, 0xa084, - 0x0003, 0x0110, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, - 0xa684, 0xfffb, 0x785a, 0x7d9a, 0x79e4, 0xd1ac, 0x0120, 0x78ec, - 0xa084, 0x0003, 0x1120, 0x2001, 0x0014, 0x0804, 0x2daa, 0xa184, - 0x0007, 0x04c2, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, - 0x81ff, 0x0568, 0x789b, 0x0080, 0x7ba8, 0xa384, 0x0001, 0x11d0, - 0x7ba8, 0x7ba8, 0xa386, 0x0004, 0x1118, 0x2009, 0xffdf, 0x0058, - 0xa386, 0x0001, 0x1118, 0x2009, 0xfff7, 0x0028, 0xa386, 0x0003, - 0x1148, 0x2009, 0xffef, 0x00c6, 0x7058, 0x2060, 0x6004, 0xa104, - 0x6006, 0x00ce, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, - 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xecff, 0x6922, 0x7d9a, - 0x0804, 0x3a3f, 0x2a9f, 0x2aa8, 0x3214, 0x321a, 0x3212, 0x3212, - 0x3a3f, 0x3a3f, 0x080c, 0x243b, 0x6920, 0xa18c, 0xfcff, 0x6922, - 0x0804, 0x3a45, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0804, 0x3a3f, - 0x79e4, 0xa184, 0x0030, 0x0120, 0x78ec, 0xa084, 0x0003, 0x1558, - 0x7000, 0xa086, 0x0004, 0x1190, 0x7064, 0xa086, 0x0002, 0x1130, - 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x295c, 0x7064, 0xa086, - 0x0006, 0x0db0, 0x7064, 0xa086, 0x0004, 0x0d90, 0x7000, 0xa086, - 0x0000, 0x0904, 0x248c, 0x6920, 0xa184, 0x0420, 0x0128, 0xc1d4, - 0x6922, 0x6818, 0x0804, 0x2daa, 0x6818, 0xc0fd, 0x681a, 0x2001, - 0x0014, 0x0804, 0x2daa, 0xa184, 0x0007, 0x0002, 0x3a3f, 0x3a3f, - 0x325e, 0x3a3f, 0x3a83, 0x3a83, 0x3a3f, 0x3a3f, 0xd6bc, 0x0570, - 0x7184, 0x81ff, 0x0558, 0xa182, 0x000d, 0x1318, 0x7087, 0x0000, - 0x0028, 0xa182, 0x000c, 0x7086, 0x2009, 0x000c, 0x789b, 0x0061, - 0x79aa, 0x0156, 0x0136, 0x0146, 0x7088, 0x8114, 0xa210, 0x728a, - 0xa080, 0x000b, 0xad00, 0x2098, 0xb284, 0x0600, 0x0118, 0x20a1, - 0x022b, 0x0010, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, - 0x53a6, 0x014e, 0x013e, 0x015e, 0x0804, 0x3a45, 0xd6d4, 0x1904, - 0x32d1, 0x6820, 0xd084, 0x0904, 0x3a45, 0xa68c, 0x0060, 0xa684, - 0x0060, 0x0120, 0xa086, 0x0060, 0x1108, 0xc1f5, 0xc194, 0x795a, - 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, - 0xc0fd, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0904, 0x35da, 0xa18c, - 0x00f8, 0x1904, 0x35da, 0x0156, 0x0136, 0x0146, 0x0016, 0x20a1, - 0x012b, 0x3208, 0xa18c, 0x0600, 0x0110, 0x20a1, 0x022b, 0x001e, - 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, - 0x014e, 0x013e, 0x015e, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x0804, - 0x3a45, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x0008, 0x080c, 0x3837, - 0x781b, 0x00ed, 0x0005, 0x2300, 0x0002, 0x32e2, 0x3398, 0x32e0, - 0x080c, 0x243b, 0x7cd8, 0x7ddc, 0x7fd0, 0x82ff, 0x11f0, 0x7200, - 0xa286, 0x0003, 0x0904, 0x2d7f, 0x71d4, 0xd1b4, 0x00c0, 0x00d6, - 0x783b, 0x8800, 0x781b, 0x0059, 0x70bc, 0xa06d, 0x68b4, 0xc0a5, - 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, - 0x71d6, 0x7003, 0x0030, 0x00de, 0x0030, 0x7200, 0x0020, 0x783b, - 0x1800, 0x781b, 0x0057, 0xa284, 0x000f, 0x0002, 0x3383, 0x3344, - 0x3318, 0x2da7, 0x3316, 0x3383, 0x3316, 0x3316, 0x080c, 0x243b, - 0x681c, 0xd0ec, 0x0118, 0x6008, 0xc08d, 0x600a, 0x6920, 0xc185, - 0x6922, 0x6800, 0x6006, 0xa005, 0x1108, 0x6002, 0x6008, 0xc0d4, - 0x600a, 0x681c, 0xa084, 0x000e, 0x1148, 0xb284, 0x0600, 0x0118, - 0x2009, 0x89c0, 0x0040, 0x2009, 0x8ad0, 0x0028, 0x7030, 0x68ba, - 0x7140, 0x70cc, 0xa108, 0x2104, 0x6802, 0x2d0a, 0x715e, 0xd6dc, - 0x1118, 0xc6fc, 0x6eb6, 0x04f8, 0x6eb6, 0xa684, 0x0060, 0x05d8, + 0xa084, 0x00ff, 0xa205, 0x6822, 0x080c, 0x1d89, 0x2021, 0x4502, + 0x241c, 0x8319, 0x2322, 0x6010, 0x8001, 0x6012, 0x1128, 0x2021, + 0x4504, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, + 0x080c, 0x267d, 0x080c, 0x3786, 0x0005, 0xa085, 0x0001, 0x0ce0, + 0x2300, 0x0002, 0x2b47, 0x2b45, 0x2bad, 0x080c, 0x252b, 0x78e4, + 0xa005, 0x1708, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104, 0x257c, + 0x0010, 0x0304, 0x257c, 0x2008, 0xa084, 0x0030, 0x1110, 0x0804, + 0x31c5, 0x78ec, 0xa084, 0x0003, 0x0dd0, 0x2100, 0xa084, 0x0007, + 0x0002, 0x2b90, 0x2b99, 0x2b86, 0x2b69, 0x3bef, 0x3bef, 0x2b69, + 0x2ba3, 0x080c, 0x252b, 0x7000, 0xa086, 0x0004, 0x1190, 0x7060, + 0xa086, 0x0002, 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, + 0x2a4d, 0x7060, 0xa086, 0x0006, 0x0db0, 0x7060, 0xa086, 0x0004, + 0x0d90, 0x79e4, 0x2001, 0x0003, 0x0804, 0x2ea4, 0x6818, 0xd0fc, + 0x0110, 0x681b, 0x001d, 0x080c, 0x39ff, 0x781b, 0x006e, 0x0005, + 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x39ff, 0x0804, + 0x3bcd, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x39ff, + 0x781b, 0x00fa, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, + 0x080c, 0x39ff, 0x781b, 0x00cb, 0x0005, 0xa584, 0x000f, 0x11c0, + 0x7000, 0x0002, 0x257f, 0x2bba, 0x2bbc, 0x3725, 0x3725, 0x3725, + 0x2bba, 0x2bba, 0x080c, 0x252b, 0x080c, 0x3786, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x080c, 0x3717, 0x0904, 0x3725, 0x0804, 0x257f, + 0x78e4, 0xa005, 0x1b04, 0x2b6b, 0x3208, 0xa18c, 0x0800, 0x0118, + 0x0104, 0x2b6b, 0x0010, 0x0304, 0x2b6b, 0x2008, 0xa084, 0x0030, + 0x1118, 0x781b, 0x0068, 0x0005, 0x78ec, 0xa084, 0x0003, 0x0dc8, + 0x2100, 0xa184, 0x0007, 0x0002, 0x2bf3, 0x2bf7, 0x2bee, 0x2bec, + 0x3bef, 0x3bef, 0x2bec, 0x3be9, 0x080c, 0x252b, 0x080c, 0x3a05, + 0x781b, 0x006e, 0x0005, 0x080c, 0x3a05, 0x0804, 0x3bcd, 0x080c, + 0x3a05, 0x781b, 0x00fa, 0x0005, 0x080c, 0x3a05, 0x781b, 0x00cb, + 0x0005, 0x2300, 0x0002, 0x2c08, 0x2c06, 0x2c0a, 0x080c, 0x252b, + 0x0804, 0x3361, 0x681b, 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, + 0x0030, 0x0904, 0x3361, 0x78ec, 0xa084, 0x0003, 0x0904, 0x3361, + 0xa184, 0x0100, 0x0d98, 0xa184, 0x0007, 0x0002, 0x2c26, 0x2bf7, + 0x2b86, 0x3bab, 0x3bef, 0x3bef, 0x3bab, 0x3be9, 0x080c, 0x3bb7, + 0x0005, 0xa282, 0x0005, 0x0310, 0x080c, 0x252b, 0x7898, 0x2040, + 0x2300, 0x0002, 0x2c35, 0x2e34, 0x2e3e, 0x2200, 0x0002, 0x2c51, + 0x2c3e, 0x2c51, 0x2c3c, 0x2e16, 0x080c, 0x252b, 0x789b, 0x0018, + 0x78a8, 0x2010, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0a04, 0x39d0, + 0xa08a, 0x0004, 0x1a04, 0x39d0, 0x0002, 0x39d0, 0x39d0, 0x39d0, + 0x3986, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0148, 0x0804, + 0x39d0, 0x7000, 0xa005, 0x1dd8, 0x2011, 0x0004, 0x0804, 0x3502, + 0xa184, 0x00ff, 0xa08a, 0x0010, 0x1a04, 0x39d0, 0x0002, 0x2c79, + 0x2c77, 0x2c8b, 0x2c8f, 0x2d2d, 0x39d0, 0x39d0, 0x2d2f, 0x39d0, + 0x39d0, 0x2e12, 0x2e12, 0x39d0, 0x39d0, 0x39d0, 0x2e14, 0x080c, + 0x252b, 0xd6e4, 0x0140, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, + 0x781b, 0x00c7, 0x0005, 0x6818, 0xd0fc, 0x0118, 0x681b, 0x001d, + 0x0c90, 0x0804, 0x3bab, 0x681b, 0x001d, 0x0804, 0x39f9, 0x6920, + 0x6922, 0xa684, 0x1800, 0x15e0, 0x6820, 0xd084, 0x1904, 0x2cd8, + 0x6818, 0xa086, 0x0008, 0x1110, 0x681b, 0x0000, 0xd6d4, 0x0568, + 0xd6bc, 0x0558, 0x7083, 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, + 0x000d, 0x0718, 0xa08a, 0x000c, 0x7182, 0x2001, 0x000c, 0x800c, + 0x7186, 0x789b, 0x0061, 0x78aa, 0x0156, 0x0136, 0x0146, 0x0016, + 0x3208, 0xa18c, 0x0600, 0x0118, 0x20a1, 0x022b, 0x0010, 0x20a1, + 0x012b, 0x001e, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, + 0x2098, 0x53a6, 0x014e, 0x013e, 0x015e, 0x781b, 0x0071, 0x0005, + 0xd6e4, 0x0130, 0x781b, 0x0083, 0x0005, 0x781b, 0x0083, 0x0005, + 0xa684, 0x0060, 0x0dd0, 0xd6dc, 0x0dc0, 0xd6fc, 0x01a0, 0xc6fc, + 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x8007, 0xa084, 0x007f, + 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, + 0x2200, 0xa303, 0x68ae, 0xd6f4, 0x0118, 0xc6f4, 0x7e5a, 0x6eb6, + 0x7000, 0xa086, 0x0003, 0x1148, 0x0006, 0x080c, 0x3ed9, 0x080c, + 0x4180, 0x000e, 0x781b, 0x0080, 0x0005, 0xa006, 0x080c, 0x425d, + 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0120, 0x2200, + 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, + 0x7bde, 0x2300, 0xa405, 0x1130, 0xc6f5, 0x7e5a, 0x6eb6, 0x781b, + 0x0080, 0x0005, 0x781b, 0x0080, 0x2200, 0xa115, 0x1118, 0x080c, + 0x4180, 0x0005, 0x080c, 0x41ad, 0x0005, 0x080c, 0x252b, 0x0804, + 0x2dae, 0x00c6, 0x7054, 0x2060, 0x7aa8, 0xa294, 0x00ff, 0xa286, + 0x0004, 0x11d8, 0x6920, 0xd1e4, 0x1170, 0x2039, 0x0000, 0x2041, + 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x38bd, 0x080c, + 0x3961, 0x0804, 0x2da2, 0xa18c, 0xecff, 0x6922, 0x6104, 0xa18c, + 0xffdd, 0x6106, 0x6000, 0xc0ac, 0x6002, 0xa286, 0x0003, 0x01d0, + 0x6104, 0xa184, 0x0010, 0x0548, 0x080c, 0x3b31, 0x080c, 0x393d, + 0x88ff, 0x0518, 0x00ce, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, + 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, + 0x0082, 0x0005, 0x6920, 0xd1cc, 0x0130, 0xa18c, 0xfdff, 0x6922, + 0x6000, 0xc0ec, 0x6002, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, + 0x0000, 0xa006, 0x2010, 0x080c, 0x3961, 0xa286, 0x0001, 0x0158, + 0x6104, 0xa184, 0x0008, 0x01b0, 0x080c, 0x3b31, 0x080c, 0x385d, + 0x88ff, 0x1980, 0x0078, 0x6920, 0xd1c4, 0x0130, 0xa18c, 0xfeff, + 0x6922, 0x6000, 0xc0e4, 0x6002, 0x2031, 0x0000, 0xa006, 0x2010, + 0x080c, 0x38bd, 0x00ce, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, + 0x0005, 0x781b, 0x0083, 0x0005, 0x0804, 0x39f5, 0x2808, 0x789b, + 0x0080, 0x2019, 0x0080, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, + 0x1188, 0x7ca8, 0xa4a4, 0x00ff, 0xa480, 0x0002, 0xa300, 0x2018, + 0xa102, 0x0a04, 0x2d31, 0x0904, 0x2d31, 0x24a8, 0x7aa8, 0x1f04, + 0x2dc6, 0x0c48, 0xa284, 0x00f0, 0xa082, 0x0020, 0x06b8, 0x2200, + 0xa082, 0x0021, 0x1698, 0x7aa8, 0x8318, 0x8318, 0x2100, 0xa302, + 0x0ad0, 0xa286, 0x0023, 0x0980, 0x681c, 0xa084, 0xfff1, 0x681e, + 0x7e58, 0xa684, 0xfff1, 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, + 0x600a, 0x78a0, 0x8001, 0x0904, 0x2da2, 0x20a8, 0x7998, 0x789b, + 0x0060, 0x78aa, 0x2011, 0x0080, 0x799a, 0x78a8, 0x7998, 0x7a9a, + 0x78aa, 0x7a98, 0x1f04, 0x2df4, 0xc695, 0x7e5a, 0xd6d4, 0x1118, + 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x8318, 0x2100, + 0xa302, 0x0a04, 0x2db3, 0xa284, 0x0080, 0x1904, 0x39f9, 0x78a0, + 0xa005, 0x08c8, 0x0804, 0x39f9, 0x0804, 0x39d0, 0x7054, 0xa04d, + 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0110, + 0x080c, 0x252b, 0x7aa8, 0xa294, 0x00ff, 0x784b, 0x0008, 0x78a8, + 0xa084, 0x00ff, 0xa08a, 0x0005, 0x1a04, 0x39d0, 0x0002, 0x39d0, + 0x37d4, 0x39d0, 0x38ed, 0x3cef, 0xa282, 0x0000, 0x1110, 0x080c, + 0x252b, 0x080c, 0x39ff, 0x781b, 0x0082, 0x0005, 0xa282, 0x0003, + 0x1110, 0x080c, 0x252b, 0xd4fc, 0x11d0, 0x7060, 0xa005, 0x0110, + 0x080c, 0x252b, 0x6f14, 0x7772, 0xa7bc, 0x8f00, 0x080c, 0x3b35, + 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, 0x1db0, + 0x080c, 0x3a02, 0x7063, 0x0002, 0x701f, 0x0009, 0x0010, 0x080c, + 0x3a0e, 0x781b, 0x0082, 0x0005, 0xa282, 0x0004, 0x0310, 0x080c, + 0x252b, 0x2300, 0x0002, 0x2e6e, 0x3004, 0x3040, 0xa286, 0x0003, + 0x0598, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x71d0, 0xd1bc, 0x1528, + 0xd1b4, 0x0518, 0x2001, 0x4501, 0x2004, 0xd0c4, 0x11f0, 0x7868, + 0xa084, 0x00ff, 0x11d0, 0xa282, 0x0002, 0x12b8, 0x00d6, 0x783b, + 0x8300, 0x781b, 0x0059, 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, + 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, + 0x0030, 0x00de, 0x2001, 0x0000, 0x0058, 0x783b, 0x1300, 0x781b, + 0x0057, 0x2001, 0x0000, 0x0020, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, + 0x7046, 0x68a0, 0xd0ec, 0x0118, 0x6008, 0xc08d, 0x600a, 0xa284, + 0x000f, 0x0002, 0x2fe5, 0x2ebf, 0x2ebc, 0x3117, 0x31aa, 0x257f, + 0x2eba, 0x2eba, 0x080c, 0x252b, 0x6008, 0xc0d4, 0x600a, 0xd6e4, + 0x0120, 0x7044, 0xa086, 0x0014, 0x11e8, 0x080c, 0x3ed9, 0x2009, + 0x0000, 0x6818, 0xd0fc, 0x0108, 0x7044, 0xa086, 0x0014, 0x0168, + 0x6818, 0xa086, 0x0008, 0x1904, 0x2fa7, 0x7858, 0xd09c, 0x0904, + 0x2fa7, 0x6820, 0xd0ac, 0x0904, 0x2fa7, 0x681b, 0x0014, 0x2009, + 0x0002, 0x04a8, 0x7868, 0xa08c, 0x00ff, 0x0588, 0xa186, 0x0008, + 0x1158, 0x6008, 0xc0a4, 0x600a, 0x080c, 0x3717, 0x0540, 0x080c, + 0x3786, 0x080c, 0x3ed9, 0x0060, 0xa186, 0x0028, 0x1500, 0x6018, + 0xa005, 0x0d78, 0x8001, 0x0d68, 0x8001, 0x0d58, 0x601e, 0x0c48, + 0x6820, 0xd084, 0x0904, 0x257f, 0xc084, 0x6822, 0x080c, 0x2672, + 0x7058, 0x00c6, 0x2060, 0x6800, 0x6002, 0x00ce, 0x6004, 0x6802, + 0xa005, 0x2d00, 0x1108, 0x6002, 0x6006, 0x0804, 0x257f, 0x0016, + 0x81ff, 0x15f0, 0x7000, 0xa086, 0x0030, 0x05d0, 0x71d0, 0xd1bc, + 0x15b8, 0xd1b4, 0x11e8, 0x705c, 0xa005, 0x1590, 0x70a0, 0xa086, + 0x0001, 0x0570, 0x7003, 0x0000, 0x0046, 0x0056, 0x0076, 0x0066, + 0x00c6, 0x00d6, 0x080c, 0x25a4, 0x00de, 0x00ce, 0x006e, 0x007e, + 0x005e, 0x004e, 0x71d0, 0xd1b4, 0x11d8, 0x7003, 0x0040, 0x00c0, + 0x080c, 0x3bf9, 0x11a8, 0x781b, 0x0068, 0x00d6, 0x70b8, 0xa06d, + 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, + 0xc1b4, 0x71d2, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, 0x00de, + 0x080c, 0x3068, 0x001e, 0x81ff, 0x0904, 0x2fa7, 0xa684, 0xdf00, + 0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x1904, 0x2fa8, + 0x6818, 0xa086, 0x0014, 0x1130, 0x2008, 0xd6e4, 0x0118, 0x7868, + 0xa08c, 0x00ff, 0x080c, 0x3a18, 0x080c, 0x267d, 0x6820, 0xd0dc, + 0x1578, 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xb284, + 0x0600, 0x0118, 0xa290, 0x49c0, 0x0010, 0xa290, 0x4a40, 0xa290, + 0x0000, 0x221c, 0xd3c4, 0x0170, 0x6820, 0xd0e4, 0x0128, 0xa084, + 0xefff, 0x6822, 0xc3ac, 0x2312, 0x8210, 0x2204, 0xa085, 0x0038, + 0x2012, 0x8211, 0xd3d4, 0x0138, 0x68a0, 0xd0c4, 0x1120, 0x080c, + 0x30d0, 0x0804, 0x257f, 0x6008, 0xc08d, 0x600a, 0x0008, 0x692a, + 0x6916, 0x6818, 0xd0fc, 0x0110, 0x7044, 0x681a, 0xa68c, 0xdf00, + 0x691e, 0x6410, 0x84ff, 0x0168, 0x2009, 0x4502, 0x2104, 0x8001, + 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, 0x4504, 0x2404, 0xc0a5, + 0x2022, 0x6018, 0xa005, 0x0118, 0x8001, 0x601a, 0x1118, 0x6008, + 0xc0a4, 0x600a, 0x6820, 0xd084, 0x1130, 0x6800, 0xa005, 0x1108, + 0x6002, 0x6006, 0x0020, 0x7058, 0x2060, 0x6800, 0x6002, 0x2061, + 0x4500, 0x6887, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, + 0x616a, 0x0110, 0x2d02, 0x0008, 0x616e, 0x7200, 0xa286, 0x0030, + 0x0158, 0xa286, 0x0040, 0x1904, 0x257f, 0x7003, 0x0002, 0x7048, + 0x2068, 0x68c4, 0x2060, 0x0005, 0x7003, 0x0002, 0x70b8, 0xa06d, + 0x68bc, 0x703e, 0x70b4, 0xa065, 0x68c0, 0x7056, 0x2d00, 0x704a, + 0xad80, 0x0009, 0x7042, 0x0005, 0xa282, 0x0004, 0x0210, 0x080c, + 0x252b, 0x2200, 0x0002, 0x300f, 0x301e, 0x302a, 0x301e, 0xa586, + 0x1300, 0x0160, 0xa586, 0x8300, 0x1d90, 0x7003, 0x0000, 0x6018, + 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, 0x7000, 0xa086, + 0x0005, 0x0128, 0x080c, 0x39ff, 0x781b, 0x0082, 0x0005, 0x781b, + 0x0083, 0x0005, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080, + 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0128, + 0xa186, 0x0000, 0x0110, 0x0804, 0x39d0, 0x781b, 0x0083, 0x0005, + 0x6820, 0xc095, 0x6822, 0x82ff, 0x1118, 0x080c, 0x39ff, 0x0030, + 0x8211, 0x0110, 0x080c, 0x252b, 0x080c, 0x3a0e, 0x781b, 0x0082, + 0x0005, 0x080c, 0x3c0c, 0x7830, 0xa084, 0x00c0, 0x1170, 0x0016, + 0x3208, 0xa18c, 0x0800, 0x001e, 0x0118, 0x0104, 0x3065, 0x0010, + 0x0304, 0x3065, 0x791a, 0xa006, 0x0005, 0xa085, 0x0001, 0x0005, + 0xa684, 0x0060, 0x1130, 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, + 0x30cf, 0xd6dc, 0x1198, 0x68b4, 0xd0dc, 0x1180, 0x6998, 0x6a94, + 0x692e, 0x6a32, 0x7044, 0xa005, 0x1130, 0x2200, 0xa105, 0x0904, + 0x3ed9, 0x7047, 0x0015, 0x0804, 0x3ed9, 0x0005, 0xd6ac, 0x01f0, + 0xd6f4, 0x0130, 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, 0x3ed9, + 0x68b4, 0xa084, 0x4000, 0xa635, 0xd6f4, 0x1da0, 0x7044, 0xa005, + 0x1110, 0x7047, 0x0015, 0xd6dc, 0x1128, 0x68b4, 0xd0dc, 0x0110, + 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0804, 0x3ed9, 0xd6f4, 0x0130, + 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, 0x3ed9, 0x68b4, 0xa084, + 0x4800, 0xa635, 0xd6f4, 0x1da0, 0x7044, 0xa005, 0x1110, 0x7047, + 0x0015, 0x2408, 0x2510, 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, + 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x1110, 0x0804, + 0x3ed9, 0x7000, 0xa086, 0x0006, 0x0110, 0x0804, 0x3ed9, 0x0005, + 0x6946, 0x6008, 0xc0cd, 0xd3cc, 0x0108, 0xc08d, 0x600a, 0x6818, + 0x683a, 0x681b, 0x0006, 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, + 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, + 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, 0x0002, 0x257f, + 0x30ff, 0x30f9, 0x30f7, 0x30f7, 0x30f7, 0x30f7, 0x30f7, 0x080c, + 0x252b, 0x6820, 0xd084, 0x1118, 0x080c, 0x376c, 0x0030, 0x7058, + 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, 0x3208, 0xa18c, 0x0600, + 0x0118, 0x2021, 0x4557, 0x0010, 0x2021, 0x4597, 0x2404, 0xa005, + 0x0110, 0x2020, 0x0cd8, 0x2d22, 0x206b, 0x0000, 0x0005, 0x080c, + 0x3772, 0x080c, 0x3786, 0x6008, 0xc0cc, 0x600a, 0x682b, 0x0000, + 0x789b, 0x000e, 0x6f14, 0x6938, 0x691a, 0x6944, 0x6916, 0x3208, + 0xa18c, 0x0600, 0x0118, 0x2009, 0x0000, 0x0010, 0x2009, 0x0001, + 0x080c, 0x428b, 0xd6dc, 0x01c8, 0x691c, 0xc1ed, 0x691e, 0x6828, + 0xa082, 0x000e, 0x0290, 0x6848, 0xa084, 0x000f, 0xa086, 0x000b, + 0x1160, 0x685c, 0xa086, 0x0047, 0x1140, 0x2001, 0x4501, 0x2004, + 0xd0ac, 0x1118, 0x2700, 0x080c, 0x2454, 0x6818, 0xd0fc, 0x0140, + 0x681b, 0x0000, 0x7868, 0xa08c, 0x00ff, 0x0110, 0x681b, 0x001e, + 0xb284, 0x0600, 0x1118, 0x2021, 0x4597, 0x0010, 0x2021, 0x4557, + 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, + 0x6000, 0xd0a4, 0x0580, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, + 0x0020, 0x00d6, 0x00f6, 0x0156, 0x0146, 0x2079, 0x4500, 0x080c, + 0x1b77, 0x014e, 0x015e, 0x00fe, 0x70c8, 0x2010, 0x2009, 0x0101, + 0x0026, 0x2204, 0xa06d, 0x0140, 0x6814, 0xa706, 0x0110, 0x6800, + 0x0cc8, 0x6820, 0xc0d5, 0x6822, 0x002e, 0x8210, 0x8109, 0x1d80, + 0x00de, 0x7063, 0x0003, 0x707b, 0x0000, 0x7772, 0x707f, 0x000f, + 0x71d0, 0xc1c4, 0x71d2, 0x6818, 0xa086, 0x0002, 0x1138, 0x6817, + 0x0000, 0x682b, 0x0000, 0x681c, 0xc0ec, 0x681e, 0x080c, 0x1d89, + 0x0804, 0x257f, 0x7cd8, 0x7ddc, 0x7fd0, 0x080c, 0x3068, 0x682b, + 0x0000, 0x789b, 0x000e, 0x6f14, 0x080c, 0x3c10, 0xa08c, 0x00ff, + 0x6916, 0x6818, 0xd0fc, 0x0110, 0x7044, 0x681a, 0xa68c, 0xdf00, + 0x691e, 0x7063, 0x0000, 0x0804, 0x257f, 0x7000, 0xa005, 0x1110, + 0x0804, 0x257f, 0xa006, 0x080c, 0x3ed9, 0x6920, 0xd1ac, 0x1110, + 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, + 0xa084, 0x00ff, 0x6822, 0x7000, 0x0002, 0x257f, 0x31e7, 0x31e7, + 0x31ea, 0x31ea, 0x31ea, 0x31e5, 0x31e5, 0x080c, 0x252b, 0x6818, + 0x0804, 0x2ea4, 0x6008, 0xc0a4, 0x600a, 0x6817, 0x0000, 0x0804, + 0x373a, 0x2300, 0x0002, 0x31f6, 0x31f8, 0x3241, 0x080c, 0x252b, + 0xd6fc, 0x1904, 0x2cdf, 0x7000, 0xa00d, 0x0002, 0x257f, 0x3208, + 0x3208, 0x3231, 0x3208, 0x323e, 0x3206, 0x3206, 0x080c, 0x252b, + 0xa684, 0x0060, 0x0530, 0xa086, 0x0060, 0x1508, 0xc6ac, 0xc6f4, + 0xc6ed, 0x7e5a, 0x681c, 0xc0ac, 0x681e, 0xa186, 0x0002, 0x0148, + 0x080c, 0x3ed9, 0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, 0x41ad, + 0x0010, 0x080c, 0x4180, 0x781b, 0x0083, 0x71d0, 0xd1b4, 0x1904, + 0x257c, 0x70a0, 0xa086, 0x0001, 0x1904, 0x25c0, 0x0005, 0xd6ec, + 0x09f8, 0x6818, 0xd0fc, 0x0150, 0xd6f4, 0x1130, 0x681b, 0x0015, + 0x781b, 0x0083, 0x0804, 0x257c, 0x681b, 0x0007, 0x080c, 0x3bb7, + 0x0005, 0x080c, 0x252b, 0x2300, 0x0002, 0x324a, 0x326c, 0x32c3, + 0x080c, 0x252b, 0x7000, 0x0002, 0x3254, 0x3256, 0x325d, 0x3254, + 0x3254, 0x3254, 0x3254, 0x3254, 0x080c, 0x252b, 0x69ac, 0x68b0, + 0xa115, 0x0118, 0x080c, 0x41ad, 0x0010, 0x080c, 0x4180, 0x681c, + 0xc0b4, 0x681e, 0x70d0, 0xd0b4, 0x1904, 0x257c, 0x70a0, 0xa086, + 0x0001, 0x1904, 0x25c0, 0x0005, 0xd6fc, 0x1904, 0x32b3, 0x7000, + 0xa00d, 0x0002, 0x257f, 0x3282, 0x327c, 0x32ab, 0x3282, 0x32b0, + 0x327a, 0x327a, 0x080c, 0x252b, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0xa684, 0x0060, 0x0530, 0xa086, 0x0060, 0x1508, + 0xa6b4, 0xbfbf, 0xc6ed, 0x7e5a, 0xa186, 0x0002, 0x0148, 0x080c, + 0x3ed9, 0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, 0x41ad, 0x0010, + 0x080c, 0x4180, 0x781b, 0x0083, 0x681c, 0xc0b4, 0x681e, 0x71d0, + 0xd1b4, 0x1904, 0x257c, 0x70a0, 0xa086, 0x0001, 0x1904, 0x25c0, + 0x0005, 0xd6ec, 0x09f8, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x0007, + 0x781b, 0x00fb, 0x0005, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, + 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, + 0x781b, 0x0083, 0x0005, 0xd6dc, 0x0130, 0x782b, 0x3009, 0x781b, + 0x0083, 0x0804, 0x257c, 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, + 0x0008, 0x1150, 0xa484, 0x0200, 0x0108, 0xc6f5, 0xc6dd, 0x7e5a, + 0x781b, 0x0083, 0x0804, 0x257c, 0x6820, 0xc095, 0x6822, 0x080c, + 0x3ba2, 0xc6dd, 0x080c, 0x39ff, 0x781b, 0x0082, 0x0804, 0x257c, + 0x2300, 0x0002, 0x32ed, 0x32ef, 0x32f1, 0x080c, 0x252b, 0x0804, + 0x39f9, 0x7d98, 0xd6d4, 0x11f8, 0x79e4, 0xd1ac, 0x0130, 0x78ec, + 0xa084, 0x0003, 0x0110, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, + 0x0000, 0xa684, 0xfffb, 0x785a, 0x7d9a, 0x79e4, 0xd1ac, 0x0120, + 0x78ec, 0xa084, 0x0003, 0x1120, 0x2001, 0x0014, 0x0804, 0x2ea4, + 0xa184, 0x0007, 0x04c2, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, + 0x79a8, 0x81ff, 0x0568, 0x789b, 0x0080, 0x7ba8, 0xa384, 0x0001, + 0x11d0, 0x7ba8, 0x7ba8, 0xa386, 0x0004, 0x1118, 0x2009, 0xffdf, + 0x0058, 0xa386, 0x0001, 0x1118, 0x2009, 0xfff7, 0x0028, 0xa386, + 0x0003, 0x1148, 0x2009, 0xffef, 0x00c6, 0x7054, 0x2060, 0x6004, + 0xa104, 0x6006, 0x00ce, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, + 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xecff, 0x6922, + 0x7d9a, 0x0804, 0x3bab, 0x2b90, 0x2b99, 0x3355, 0x335b, 0x3353, + 0x3353, 0x3bab, 0x3bab, 0x080c, 0x252b, 0x6920, 0xa18c, 0xfcff, + 0x6922, 0x0804, 0x3bb1, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0804, + 0x3bab, 0x79e4, 0xa184, 0x0030, 0x0120, 0x78ec, 0xa084, 0x0003, + 0x1570, 0x7000, 0xa086, 0x0004, 0x1190, 0x7060, 0xa086, 0x0002, + 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x2a4d, 0x7060, + 0xa086, 0x0006, 0x0db0, 0x7060, 0xa086, 0x0004, 0x0d90, 0x7000, + 0xa086, 0x0000, 0x0904, 0x257c, 0x6920, 0xa184, 0x0420, 0x0128, + 0xc1d4, 0x6922, 0x6818, 0x0804, 0x2ea4, 0x6818, 0xa08e, 0x0002, + 0x0120, 0xc0fd, 0x681a, 0x2001, 0x0014, 0x0804, 0x2ea4, 0xa184, + 0x0007, 0x0002, 0x3bab, 0x3bab, 0x33a2, 0x3bab, 0x3bef, 0x3bef, + 0x3bab, 0x3bab, 0xd6bc, 0x0570, 0x7180, 0x81ff, 0x0558, 0xa182, + 0x000d, 0x1318, 0x7083, 0x0000, 0x0028, 0xa182, 0x000c, 0x7082, + 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, 0x0156, 0x0136, 0x0146, + 0x7084, 0x8114, 0xa210, 0x7286, 0xa080, 0x000b, 0xad00, 0x2098, + 0xb284, 0x0600, 0x0118, 0x20a1, 0x022b, 0x0010, 0x20a1, 0x012b, + 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x014e, 0x013e, 0x015e, + 0x0804, 0x3bb1, 0xd6d4, 0x1904, 0x3415, 0x6820, 0xd084, 0x0904, + 0x3bb1, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0120, 0xa086, 0x0060, + 0x1108, 0xc1f5, 0xc194, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, + 0x0000, 0x789b, 0x0061, 0x6818, 0xc0fd, 0x681a, 0x78aa, 0x8008, + 0x810c, 0x0904, 0x379b, 0xa18c, 0x00f8, 0x1904, 0x379b, 0x0156, + 0x0136, 0x0146, 0x0016, 0x20a1, 0x012b, 0x3208, 0xa18c, 0x0600, + 0x0110, 0x20a1, 0x022b, 0x001e, 0x789b, 0x0000, 0x8000, 0x80ac, + 0xad80, 0x000b, 0x2098, 0x53a6, 0x014e, 0x013e, 0x015e, 0x6814, + 0xc0fc, 0x8007, 0x7882, 0x0804, 0x3bb1, 0x6818, 0xd0fc, 0x0110, + 0x681b, 0x0008, 0x080c, 0x39ff, 0x781b, 0x00ed, 0x0005, 0x2300, + 0x0002, 0x3426, 0x34e8, 0x3424, 0x080c, 0x252b, 0x7cd8, 0x7ddc, + 0x7fd0, 0x82ff, 0x1528, 0x7200, 0xa286, 0x0003, 0x0904, 0x2e72, + 0x71d0, 0xd1bc, 0x11f8, 0xd1b4, 0x01e8, 0x2001, 0x4501, 0x2004, + 0xd0c4, 0x11c0, 0x00d6, 0x783b, 0x8800, 0x781b, 0x0059, 0x70b8, + 0xa06d, 0x68b4, 0xc0a5, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030, 0x00de, 0x0030, + 0x7200, 0x0020, 0x783b, 0x1800, 0x781b, 0x0057, 0xa284, 0x000f, + 0x0002, 0x34d3, 0x3490, 0x3463, 0x2ea1, 0x3461, 0x34d3, 0x3461, + 0x3461, 0x080c, 0x252b, 0x681c, 0xd0ec, 0x0118, 0x6008, 0xc08d, + 0x600a, 0x6920, 0xc185, 0x6922, 0x6800, 0x6006, 0xa005, 0x1108, + 0x6002, 0x6008, 0xc0d4, 0x600a, 0x681c, 0xa084, 0x000e, 0x1148, + 0xb284, 0x0600, 0x0118, 0x2009, 0x8bc0, 0x0040, 0x2009, 0x8cd0, + 0x0028, 0x7030, 0x68ba, 0x713c, 0x70c8, 0xa108, 0x2104, 0x6802, + 0x2d0a, 0x715a, 0xd6dc, 0x1120, 0xc6fc, 0x6eb6, 0x0804, 0x34d3, + 0x6eb6, 0xa684, 0x0060, 0x1120, 0xa684, 0x7fff, 0x68b6, 0x04d8, 0xd6dc, 0x1150, 0xa684, 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, - 0x68aa, 0x080c, 0x3d52, 0x0478, 0xd6ac, 0x0140, 0xa006, 0x080c, - 0x3d52, 0x2408, 0x2510, 0x69aa, 0x6aa6, 0x0068, 0x2408, 0x2510, + 0x68aa, 0x080c, 0x3ed9, 0x0478, 0xd6ac, 0x0140, 0xa006, 0x080c, + 0x3ed9, 0x2408, 0x2510, 0x69aa, 0x6aa6, 0x0068, 0x2408, 0x2510, 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x69aa, - 0x6aa6, 0x080c, 0x3d52, 0xd6fc, 0x01b0, 0xa684, 0x7fff, 0x68b6, + 0x6aa6, 0x080c, 0x3ed9, 0xd6fc, 0x01b0, 0xa684, 0x7fff, 0x68b6, 0x2510, 0x2408, 0xd6ac, 0x1138, 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, - 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, 0x0030, 0x1904, 0x248f, - 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, - 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x0005, + 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, 0x0030, 0x1904, 0x257f, + 0x7003, 0x0002, 0x70b8, 0xa06d, 0x68bc, 0x703e, 0x70b4, 0xa065, + 0x68c0, 0x7056, 0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x0005, 0xa586, 0x8800, 0x1148, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, - 0x6008, 0xa084, 0xfbef, 0x600a, 0x0804, 0x3831, 0x7047, 0x0000, - 0xa282, 0x0006, 0x0310, 0x080c, 0x243b, 0x2300, 0x0002, 0x33b2, - 0x33e4, 0x340f, 0x2200, 0x0002, 0x33ba, 0x3831, 0x33bc, 0x33ba, - 0x343f, 0x349d, 0x080c, 0x243b, 0x7003, 0x0005, 0xb284, 0x0600, - 0x0118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, 0x2068, 0x704e, - 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x1f04, 0x33cb, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x0804, 0x39f9, 0x7043, 0x0000, + 0xa282, 0x0006, 0x0310, 0x080c, 0x252b, 0x2300, 0x0002, 0x3502, + 0x3534, 0x355f, 0x2200, 0x0002, 0x350a, 0x39f9, 0x350c, 0x350a, + 0x358f, 0x35f9, 0x080c, 0x252b, 0x7003, 0x0005, 0xb284, 0x0600, + 0x0118, 0x2001, 0x8ce0, 0x0010, 0x2001, 0x8d12, 0x2068, 0x704a, + 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x1f04, 0x351b, 0x015e, 0xb284, 0x0600, 0x0118, 0x6817, 0x0000, 0x0010, 0x6817, - 0x8000, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, 0x0800, - 0x6827, 0x0003, 0x0804, 0x3809, 0x7000, 0xa086, 0x0002, 0x1150, - 0x080c, 0x35c5, 0x0010, 0x080c, 0x3d52, 0x6008, 0xa084, 0xfbef, + 0x8000, 0xad80, 0x0009, 0x7042, 0x68b7, 0x0700, 0x6823, 0x0800, + 0x6827, 0x0003, 0x0804, 0x39d0, 0x7000, 0xa086, 0x0002, 0x1150, + 0x080c, 0x3786, 0x0010, 0x080c, 0x3ed9, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0020, 0x7000, 0xa086, 0x0003, 0x0da8, 0x7003, 0x0005, - 0xb284, 0x0600, 0x0118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, - 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, 0x2200, 0x0002, 0x3831, - 0x340d, 0x340d, 0x343f, 0x340d, 0x3831, 0x080c, 0x243b, 0x7000, - 0xa086, 0x0002, 0x1150, 0x080c, 0x35c5, 0x0010, 0x080c, 0x3d52, + 0xb284, 0x0600, 0x0118, 0x2001, 0x8ce0, 0x0010, 0x2001, 0x8d12, + 0x2068, 0x704a, 0xad80, 0x0009, 0x7042, 0x2200, 0x0002, 0x39f9, + 0x355d, 0x355d, 0x358f, 0x355d, 0x39f9, 0x080c, 0x252b, 0x7000, + 0xa086, 0x0002, 0x1150, 0x080c, 0x3786, 0x0010, 0x080c, 0x3ed9, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0020, 0x7000, 0xa086, 0x0003, - 0x0da8, 0x7003, 0x0005, 0xb284, 0x0600, 0x0118, 0x2001, 0x8ae0, - 0x0010, 0x2001, 0x8b12, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, - 0x2200, 0x0002, 0x343a, 0x3438, 0x3438, 0x343a, 0x3438, 0x343a, - 0x080c, 0x243b, 0x080c, 0x3846, 0x781b, 0x0082, 0x0005, 0x7000, - 0xa086, 0x0002, 0x1158, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, - 0x2d00, 0x70be, 0x0038, 0x080c, 0x3d52, 0x0020, 0x7000, 0xa086, + 0x0da8, 0x7003, 0x0005, 0xb284, 0x0600, 0x0118, 0x2001, 0x8ce0, + 0x0010, 0x2001, 0x8d12, 0x2068, 0x704a, 0xad80, 0x0009, 0x7042, + 0x2200, 0x0002, 0x358a, 0x3588, 0x3588, 0x358a, 0x3588, 0x358a, + 0x080c, 0x252b, 0x080c, 0x3a0e, 0x781b, 0x0082, 0x0005, 0x7000, + 0xa086, 0x0002, 0x1158, 0x70d0, 0xc0b5, 0x70d2, 0x2c00, 0x70b6, + 0x2d00, 0x70ba, 0x0038, 0x080c, 0x3ed9, 0x0020, 0x7000, 0xa086, 0x0003, 0x0dc8, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, - 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x89c0, 0xb284, - 0x0600, 0x1118, 0xc2fd, 0x2069, 0x8ad0, 0x2d04, 0x2d08, 0x715e, + 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x8bc0, 0xb284, + 0x0600, 0x1118, 0xc2fd, 0x2069, 0x8cd0, 0x2d04, 0x2d08, 0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, 0x0500, 0x6800, 0x0cb8, 0x7003, - 0x0005, 0xd2fc, 0x1118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, - 0x2068, 0x704e, 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, - 0x1f04, 0x347d, 0x015e, 0xad80, 0x0009, 0x7046, 0x6a16, 0x68b7, + 0x0005, 0xd2fc, 0x1118, 0x2001, 0x8ce0, 0x0010, 0x2001, 0x8d12, + 0x2068, 0x704a, 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, + 0x1f04, 0x35cd, 0x015e, 0xad80, 0x0009, 0x7042, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6920, - 0xa184, 0x0c00, 0x0904, 0x3507, 0x681b, 0x0005, 0xc1ad, 0xc1d4, - 0x6922, 0x080c, 0x383d, 0x0804, 0x3507, 0x7200, 0xa286, 0x0002, - 0x1158, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, - 0x0030, 0x080c, 0x3d52, 0x0018, 0xa286, 0x0003, 0x0dd0, 0x7003, - 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, - 0x001f, 0xa215, 0xb284, 0x0600, 0x1108, 0xc2fd, 0x79a8, 0x79a8, - 0xa18c, 0x00ff, 0x70cc, 0xa168, 0x2d04, 0x2d08, 0x715e, 0xa06d, - 0x0128, 0x6814, 0xa206, 0x0538, 0x6800, 0x0cb8, 0x7003, 0x0005, - 0xb284, 0x0600, 0x0118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, - 0x2068, 0x704e, 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, - 0x1f04, 0x34dd, 0x015e, 0xb284, 0x0600, 0x0110, 0xc2fc, 0x0008, - 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, - 0x0800, 0x6827, 0x0003, 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x0178, - 0xd0dc, 0x0118, 0x080c, 0x3843, 0x0050, 0x681b, 0x0005, 0xc1ad, - 0xc1d4, 0x6922, 0x080c, 0x383d, 0x707f, 0x0000, 0x0000, 0xa6ac, - 0x0060, 0x05c8, 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x11c0, - 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, 0xb7ff, 0xa586, 0x0060, - 0x0550, 0xc6ed, 0x7e5a, 0x2009, 0x0083, 0xd69c, 0x0128, 0x2009, - 0x0082, 0x2019, 0x0000, 0x2320, 0x791a, 0x080c, 0x3fb8, 0x0418, - 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x01a0, 0x7bd2, - 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xc6f4, 0x7e5a, 0x2011, 0x0083, - 0xd69c, 0x0128, 0x2011, 0x0082, 0x2019, 0x0000, 0x2320, 0x7a1a, - 0x080c, 0x3fe5, 0x0040, 0x7e5a, 0x2009, 0x0083, 0xd69c, 0x0110, - 0x2009, 0x0082, 0x791a, 0x68c0, 0x705a, 0x2d00, 0x704e, 0x68c4, - 0x2060, 0x71d4, 0xd1b4, 0x1904, 0x248c, 0x2300, 0xa405, 0x0904, - 0x248c, 0x70a4, 0xa086, 0x0001, 0x1904, 0x24ce, 0x0005, 0x6020, + 0xa184, 0x0c00, 0x0904, 0x3670, 0x7060, 0xa086, 0x0006, 0x1128, + 0x7070, 0xa206, 0x1110, 0x7062, 0x707a, 0x681b, 0x0005, 0xc1ad, + 0x681b, 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x080c, 0x3a05, 0x0804, + 0x3670, 0x7200, 0xa286, 0x0002, 0x1158, 0x70d0, 0xc0b5, 0x70d2, + 0x2c00, 0x70b6, 0x2d00, 0x70ba, 0x0030, 0x080c, 0x3ed9, 0x0018, + 0xa286, 0x0003, 0x0dd0, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, + 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0xb284, 0x0600, + 0x1108, 0xc2fd, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0x2118, 0x70c8, + 0xa168, 0x2d04, 0x2d08, 0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, + 0x0538, 0x6800, 0x0cb8, 0x7003, 0x0005, 0xb284, 0x0600, 0x0118, + 0x2001, 0x8ce0, 0x0010, 0x2001, 0x8d12, 0x2068, 0x704a, 0x0156, + 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x1f04, 0x363a, 0x015e, + 0xb284, 0x0600, 0x0110, 0xc2fc, 0x0008, 0xc2fd, 0x6a16, 0xad80, + 0x0009, 0x7042, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, + 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x01d8, 0xd0dc, 0x0178, 0x7060, + 0xa086, 0x0004, 0x1140, 0x7070, 0xa206, 0x1128, 0x7074, 0xa306, + 0x1110, 0x7062, 0x707a, 0x080c, 0x3a0b, 0x0050, 0x681b, 0x0005, + 0xc1ad, 0xc1d4, 0x6922, 0x080c, 0x3a05, 0x707b, 0x0000, 0x0000, + 0xc6ec, 0xa6ac, 0x0060, 0x0904, 0x36b7, 0x6b98, 0x6c94, 0x69ac, + 0x68b0, 0xa105, 0x11e0, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa586, + 0x0060, 0x05c8, 0xd6f4, 0x1108, 0xc6ed, 0xa6b4, 0xb7ff, 0x7e5a, + 0x2009, 0x0083, 0xd69c, 0x0128, 0x2009, 0x0082, 0x2019, 0x0000, + 0x2320, 0x791a, 0xd6ec, 0x0588, 0x080c, 0x4180, 0x0470, 0x68b0, + 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x01f8, 0x7bd2, 0x7bda, + 0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x1108, 0xc6ed, 0xc6f4, 0x7e5a, + 0x2011, 0x0083, 0xd69c, 0x0128, 0x2011, 0x0082, 0x2019, 0x0000, + 0x2320, 0x7a1a, 0xd6ec, 0x0188, 0x080c, 0x41ad, 0x0070, 0x2019, + 0x0000, 0x2320, 0x0010, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0083, + 0xd69c, 0x0110, 0x2009, 0x0082, 0x791a, 0x68c0, 0x7056, 0x2d00, + 0x704a, 0x68c4, 0x2060, 0x71d0, 0x2001, 0x4501, 0x2004, 0xd0c4, + 0x15c8, 0x70d4, 0xa02d, 0x01b8, 0xd1bc, 0x0548, 0x7a80, 0xa294, + 0x0f00, 0x70d8, 0xa206, 0x0118, 0x78e0, 0xa504, 0x1558, 0x70d6, + 0xc1bc, 0x71d2, 0x0438, 0x2031, 0x0001, 0x852c, 0x0218, 0x8633, + 0x8210, 0x0cd8, 0x0005, 0x7de0, 0xa594, 0xff00, 0x0130, 0x2011, + 0x0008, 0x852f, 0x0c81, 0x8637, 0x0008, 0x0c69, 0x8217, 0x7880, + 0xa084, 0x0f00, 0xa206, 0x0170, 0x72da, 0x76d6, 0x0058, 0x7a80, + 0xa294, 0x0f00, 0x70d8, 0xa236, 0x0dc0, 0x78e0, 0xa534, 0x0da8, + 0xc1bd, 0x71d2, 0xd1b4, 0x1904, 0x257c, 0x2300, 0xa405, 0x0904, + 0x257c, 0x70a0, 0xa086, 0x0001, 0x1904, 0x25c0, 0x0005, 0x6020, 0xa005, 0x0150, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, - 0x700f, 0x0100, 0x702c, 0x6026, 0x0005, 0xa006, 0x080c, 0x3d52, + 0x700f, 0x0100, 0x702c, 0x6026, 0x0005, 0xa006, 0x080c, 0x3ed9, + 0x7000, 0xa086, 0x0002, 0x0120, 0x7060, 0xa086, 0x0005, 0x1150, 0x682b, 0x0000, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, - 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, 0x0002, 0x248f, 0x358b, - 0x3588, 0x35a7, 0x3594, 0x248f, 0x3586, 0x3586, 0x080c, 0x243b, - 0x0441, 0x0409, 0x0028, 0x0429, 0x705c, 0x2060, 0x6800, 0x6002, - 0x080c, 0x1d3d, 0x0804, 0x248f, 0x7064, 0x7067, 0x0000, 0x7083, - 0x0000, 0x0002, 0x35a3, 0x35a3, 0x35a2, 0x35a2, 0x35a2, 0x35a3, - 0x35a2, 0x35a3, 0x2971, 0x7067, 0x0000, 0x0804, 0x248f, 0x681b, - 0x0000, 0x0804, 0x3012, 0x6800, 0xa005, 0x1108, 0x6002, 0x6006, - 0x0005, 0x6410, 0x84ff, 0x0168, 0x2009, 0x4302, 0x2104, 0x8001, - 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, 0x4304, 0x2404, 0xc0a5, - 0x2022, 0x6008, 0xc0a4, 0x600a, 0x0005, 0x6018, 0xa005, 0x0110, - 0x8001, 0x601a, 0x0005, 0x080c, 0x3aa0, 0x681b, 0x0018, 0x04a0, - 0x080c, 0x3aa0, 0x681b, 0x0019, 0x0478, 0x080c, 0x3aa0, 0x681b, - 0x001a, 0x0450, 0x080c, 0x3aa0, 0x681b, 0x0003, 0x0428, 0x7774, - 0x080c, 0x396d, 0x7178, 0xa18c, 0x00ff, 0x3210, 0xa294, 0x0600, - 0x0118, 0xa1e8, 0x88c0, 0x0010, 0xa1e8, 0x89d0, 0x2d04, 0x2d08, - 0x2068, 0xa005, 0x1118, 0x707e, 0x0804, 0x248f, 0x6814, 0xc0fc, - 0x7274, 0xc2fc, 0xa206, 0x0110, 0x6800, 0x0c88, 0x6800, 0x200a, - 0x681b, 0x0005, 0x707f, 0x0000, 0x080c, 0x35b1, 0x6820, 0xd084, - 0x1110, 0x080c, 0x35ab, 0x080c, 0x35c5, 0x681f, 0x0000, 0x6823, - 0x0020, 0x080c, 0x1d3d, 0x0804, 0x248f, 0xa282, 0x0003, 0x1904, - 0x380d, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, - 0xc1bd, 0x6922, 0xd1c4, 0x0590, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, - 0x0510, 0xa682, 0x001c, 0x0218, 0x0110, 0x2031, 0x001c, 0x852b, - 0x852b, 0x2041, 0x0000, 0x080c, 0x38c6, 0x0118, 0x080c, 0x36f6, - 0x00a0, 0x080c, 0x3892, 0x080c, 0x36f3, 0x6920, 0xc1c5, 0x6922, + 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, 0x0002, 0x257f, 0x374b, + 0x3748, 0x3768, 0x3754, 0x257f, 0x3746, 0x3746, 0x080c, 0x252b, + 0x0449, 0x0411, 0x0028, 0x0431, 0x7058, 0x2060, 0x6800, 0x6002, + 0x080c, 0x1d89, 0x0804, 0x257f, 0x7060, 0x7063, 0x0000, 0x707f, + 0x0000, 0x0002, 0x3764, 0x3764, 0x3762, 0x3762, 0x3762, 0x3764, + 0x3762, 0x3764, 0x0804, 0x2a62, 0x7063, 0x0000, 0x0804, 0x257f, + 0x681b, 0x0000, 0x0804, 0x3117, 0x6800, 0xa005, 0x1108, 0x6002, + 0x6006, 0x0005, 0x6410, 0x84ff, 0x0168, 0x2009, 0x4502, 0x2104, + 0x8001, 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, 0x4504, 0x2404, + 0xc0a5, 0x2022, 0x6008, 0xc0a4, 0x600a, 0x0005, 0x6018, 0xa005, + 0x0110, 0x8001, 0x601a, 0x0005, 0x080c, 0x3c0c, 0x681b, 0x0018, + 0x0490, 0x080c, 0x3c0c, 0x681b, 0x0019, 0x0468, 0x080c, 0x3c0c, + 0x681b, 0x001a, 0x0440, 0x080c, 0x3c0c, 0x681b, 0x0003, 0x0418, + 0x7770, 0x080c, 0x3b35, 0x7174, 0xa18c, 0x00ff, 0x3210, 0xa294, + 0x0600, 0x0118, 0xa1e8, 0x8ac0, 0x0010, 0xa1e8, 0x8bd0, 0x2d04, + 0x2d08, 0x2068, 0xa005, 0x1118, 0x707a, 0x0804, 0x257f, 0x6814, + 0x7270, 0xa206, 0x0110, 0x6800, 0x0c98, 0x6800, 0x200a, 0x681b, + 0x0005, 0x707b, 0x0000, 0x080c, 0x3772, 0x6820, 0xd084, 0x1110, + 0x080c, 0x376c, 0x080c, 0x3786, 0x681f, 0x0000, 0x6823, 0x0020, + 0x080c, 0x1d89, 0x0804, 0x257f, 0xa282, 0x0003, 0x1904, 0x39d5, + 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xc1bd, + 0x6922, 0xd1c4, 0x05b0, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, 0x0530, + 0xa682, 0x001c, 0x0218, 0x0110, 0x2031, 0x001c, 0xa686, 0x0010, + 0x1108, 0x8630, 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, 0x3a8e, + 0x0118, 0x080c, 0x38bd, 0x00a0, 0x080c, 0x3a5a, 0x080c, 0x38ba, + 0x6920, 0xc1c5, 0x6922, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, + 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x080c, 0x38ba, + 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, + 0x0005, 0x00c6, 0x7054, 0x2060, 0x6100, 0xd1e4, 0x0598, 0x6208, + 0x8217, 0xa294, 0x00ff, 0xa282, 0x001c, 0x0218, 0x0110, 0x2011, + 0x001c, 0x2600, 0xa202, 0x1208, 0x2230, 0xa686, 0x0010, 0x1108, + 0x8630, 0x6208, 0xa294, 0x00ff, 0x78ec, 0xd0e4, 0x0130, 0xa282, + 0x000a, 0x1240, 0x2011, 0x000a, 0x0028, 0xa282, 0x000c, 0x1210, + 0x2011, 0x000c, 0x2200, 0xa502, 0x1208, 0x2228, 0x080c, 0x3a5e, + 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, 0x3a8e, 0x0118, 0x080c, + 0x38bd, 0x0020, 0x080c, 0x3a5a, 0x080c, 0x38ba, 0x7858, 0xc095, + 0x785a, 0x00ce, 0x781b, 0x0082, 0x0005, 0x00c6, 0x2960, 0x6000, + 0xd0e4, 0x1178, 0x6010, 0xa084, 0x000f, 0x1130, 0x6104, 0xa18c, + 0xfff5, 0x6106, 0x00ce, 0x0005, 0x2011, 0x0032, 0x2019, 0x0000, + 0x00f0, 0x68a0, 0xd0cc, 0x1dc0, 0x6208, 0xa294, 0x00ff, 0x78ec, + 0xd0e4, 0x0130, 0xa282, 0x000b, 0x1218, 0x2011, 0x000a, 0x0028, + 0xa282, 0x000c, 0x1210, 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, + 0x00ff, 0xa382, 0x001c, 0x0218, 0x0110, 0x2019, 0x001c, 0x78ab, + 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, + 0x0005, 0x6820, 0xc0c5, 0x6822, 0x080c, 0x3a18, 0x00ce, 0x0005, + 0x00c6, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, + 0x2019, 0x0000, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, + 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, + 0x00ce, 0x0005, 0xa006, 0x2030, 0x2010, 0x00c6, 0x7154, 0x2160, + 0x2018, 0x2008, 0xa084, 0xffe0, 0xa635, 0x7e86, 0x6018, 0x789a, + 0x7eae, 0x6612, 0x78a4, 0xa084, 0x7770, 0xa18c, 0x000f, 0xa105, + 0x2029, 0x4505, 0x252c, 0xd5cc, 0x0140, 0xd3a4, 0x0110, 0xa085, + 0x0800, 0xd3fc, 0x0110, 0xa085, 0x8080, 0x78a6, 0x6016, 0x788a, + 0xa6b4, 0x001f, 0x8637, 0x8204, 0x8004, 0xa605, 0x600e, 0x6004, + 0xa084, 0xffd5, 0x6006, 0x00ce, 0x0005, 0xa282, 0x0002, 0x1904, + 0x39de, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0568, 0xc1cc, + 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x1a04, 0x39d0, 0x080c, + 0x3963, 0x080c, 0x38ba, 0xa980, 0x0001, 0x200c, 0x080c, 0x3b31, + 0x080c, 0x385d, 0x88ff, 0x0178, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, - 0x781b, 0x0082, 0x0005, 0x080c, 0x36f3, 0x7e58, 0xd6d4, 0x1118, - 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0x00c6, 0x7058, - 0x2060, 0x6100, 0xd1e4, 0x0578, 0x6208, 0x8217, 0xa294, 0x00ff, - 0xa282, 0x001c, 0x0218, 0x0110, 0x2011, 0x001c, 0x2600, 0xa202, - 0x1208, 0x2230, 0x6208, 0xa294, 0x00ff, 0x78ec, 0xd0e4, 0x0130, - 0xa282, 0x000a, 0x1240, 0x2011, 0x000a, 0x0028, 0xa282, 0x000c, - 0x1210, 0x2011, 0x000c, 0x2200, 0xa502, 0x1208, 0x2228, 0x080c, - 0x3896, 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, 0x38c6, 0x0118, - 0x080c, 0x36f6, 0x0020, 0x080c, 0x3892, 0x080c, 0x36f3, 0x7858, - 0xc095, 0x785a, 0x00ce, 0x781b, 0x0082, 0x0005, 0x00c6, 0x2960, - 0x6000, 0xd0e4, 0x1178, 0x6010, 0xa084, 0x000f, 0x1130, 0x6104, - 0xa18c, 0xfff5, 0x6106, 0x00ce, 0x0005, 0x2011, 0x0032, 0x2019, - 0x0000, 0x00f0, 0x68a0, 0xd0cc, 0x1dc0, 0x6208, 0xa294, 0x00ff, - 0x78ec, 0xd0e4, 0x0130, 0xa282, 0x000b, 0x1218, 0x2011, 0x000a, - 0x0028, 0xa282, 0x000c, 0x1210, 0x2011, 0x000c, 0x6308, 0x831f, - 0xa39c, 0x00ff, 0xa382, 0x001c, 0x0218, 0x0110, 0x2019, 0x001c, - 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, - 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x080c, 0x3850, 0x00ce, - 0x0005, 0x00c6, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, - 0x0032, 0x2019, 0x0000, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0003, - 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, - 0x6822, 0x00ce, 0x0005, 0xa006, 0x2030, 0x2010, 0x00c6, 0x7158, - 0x2160, 0x2018, 0x2008, 0xa084, 0xffe0, 0xa635, 0x7e86, 0x6018, - 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, 0x7770, 0xa18c, 0x000f, - 0xa105, 0x2029, 0x4305, 0x252c, 0xd5cc, 0x0140, 0xd3a4, 0x0110, - 0xa085, 0x0800, 0xd3fc, 0x0110, 0xa085, 0x8080, 0x78a6, 0x6016, - 0x788a, 0xa6b4, 0x001f, 0x8637, 0x8204, 0x8004, 0xa605, 0x600e, - 0x6004, 0xa084, 0xffd5, 0x6006, 0x00ce, 0x0005, 0xa282, 0x0002, - 0x1904, 0x3816, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0568, - 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x1a04, 0x3809, - 0x080c, 0x379c, 0x080c, 0x36f3, 0xa980, 0x0001, 0x200c, 0x080c, - 0x3969, 0x080c, 0x3696, 0x88ff, 0x0178, 0x789b, 0x0060, 0x2800, - 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, - 0x0005, 0x781b, 0x0082, 0x0005, 0x7e58, 0xd6d4, 0x1118, 0x781b, - 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0xa282, 0x0002, 0x1218, - 0xa284, 0x0001, 0x0140, 0x7158, 0xa188, 0x0000, 0x210c, 0xd1ec, - 0x1110, 0x2011, 0x0000, 0x080c, 0x3883, 0x0471, 0x080c, 0x36f3, - 0x7858, 0xc095, 0x785a, 0x781b, 0x0082, 0x0005, 0x00c6, 0x0026, - 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x1150, 0x6014, 0xa084, - 0x0040, 0x1120, 0xc1a4, 0x6106, 0xa006, 0x0088, 0x2011, 0x0000, - 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, - 0x0004, 0x080c, 0x3850, 0x6820, 0xa085, 0x0200, 0x6822, 0x002e, - 0x00ce, 0x0005, 0x8807, 0xa715, 0x00c6, 0x2009, 0x0000, 0x7058, - 0x2060, 0x82ff, 0x0110, 0x2009, 0x0040, 0x6018, 0xa080, 0x0002, - 0x789a, 0x78a4, 0xa084, 0xff9f, 0xa105, 0xc0ec, 0xd0b4, 0x1108, - 0xc0ed, 0x6100, 0xd1f4, 0x0110, 0xa085, 0x0020, 0x78a6, 0x6016, - 0x788a, 0x6004, 0xa084, 0xffef, 0x6006, 0x00ce, 0x0005, 0x0006, - 0x7000, 0xa086, 0x0003, 0x0110, 0x000e, 0x0010, 0x000e, 0x0488, - 0xd6ac, 0x0578, 0x7888, 0xa084, 0x0040, 0x0558, 0x7bb8, 0x8307, - 0xa084, 0x007f, 0x1508, 0x8207, 0xa084, 0x00ff, 0xa09e, 0x0001, - 0x1904, 0x382d, 0xd6f4, 0x11d0, 0x79d8, 0x7adc, 0xa108, 0xa291, - 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x080c, 0x4083, 0x781b, - 0x0080, 0xb284, 0x0600, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, - 0x0001, 0x080c, 0x3f50, 0x0005, 0x080c, 0x243b, 0x781b, 0x0080, - 0x0005, 0x781b, 0x0083, 0x0005, 0x2039, 0x0000, 0x2041, 0x0000, - 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x36f6, 0x080c, 0x379a, - 0x7e58, 0x04f9, 0x781b, 0x0082, 0x0005, 0x0cd9, 0x6820, 0xc0c4, - 0x6822, 0x00c6, 0x7058, 0x2060, 0x0804, 0x3720, 0x0c91, 0x6820, - 0xc0cc, 0x6822, 0x00c6, 0x7058, 0x2060, 0x0804, 0x37b9, 0x0c49, - 0x6820, 0xa084, 0xecff, 0x6822, 0x00c6, 0x7058, 0x2060, 0x6004, + 0x781b, 0x0082, 0x0005, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, + 0x0005, 0x781b, 0x0083, 0x0005, 0xa282, 0x0002, 0x1218, 0xa284, + 0x0001, 0x0140, 0x7154, 0xa188, 0x0000, 0x210c, 0xd1ec, 0x1110, + 0x2011, 0x0000, 0x080c, 0x3a4b, 0x0471, 0x080c, 0x38ba, 0x7858, + 0xc095, 0x785a, 0x781b, 0x0082, 0x0005, 0x00c6, 0x0026, 0x2960, + 0x6000, 0x2011, 0x0001, 0xd0ec, 0x1150, 0x6014, 0xa084, 0x0040, + 0x1120, 0xc1a4, 0x6106, 0xa006, 0x0088, 0x2011, 0x0000, 0x78ab, + 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, + 0x080c, 0x3a18, 0x6820, 0xa085, 0x0200, 0x6822, 0x002e, 0x00ce, + 0x0005, 0x8807, 0xa715, 0x00c6, 0x2009, 0x0000, 0x7054, 0x2060, + 0x82ff, 0x0110, 0x2009, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, + 0x78a4, 0xa084, 0xff9f, 0xa105, 0xc0ec, 0xd0b4, 0x1108, 0xc0ed, + 0x6100, 0xd1f4, 0x0110, 0xa085, 0x0020, 0x78a6, 0x6016, 0x788a, + 0x6004, 0xa084, 0xffef, 0x6006, 0x00ce, 0x0005, 0x0006, 0x7000, + 0xa086, 0x0003, 0x0110, 0x000e, 0x0010, 0x000e, 0x0488, 0xd6ac, + 0x0578, 0x7888, 0xa084, 0x0040, 0x0558, 0x7bb8, 0x8307, 0xa084, + 0x007f, 0x1508, 0x8207, 0xa084, 0x00ff, 0xa09e, 0x0001, 0x1904, + 0x39f5, 0xd6f4, 0x11d0, 0x79d8, 0x7adc, 0xa108, 0xa291, 0x0000, + 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x080c, 0x425d, 0x781b, 0x0080, + 0xb284, 0x0600, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, + 0x080c, 0x4118, 0x0005, 0x080c, 0x252b, 0x781b, 0x0080, 0x0005, + 0x781b, 0x0083, 0x0005, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, + 0x0000, 0xa006, 0x2010, 0x080c, 0x38bd, 0x080c, 0x3961, 0x7e58, + 0x080c, 0x3a11, 0x781b, 0x0082, 0x0005, 0x0cd1, 0x6820, 0xc0c4, + 0x6822, 0x00c6, 0x7054, 0x2060, 0x0804, 0x38e7, 0x0c89, 0x6820, + 0xc0cc, 0x6822, 0x00c6, 0x7054, 0x2060, 0x0804, 0x3980, 0x0c41, + 0x6820, 0xa084, 0xecff, 0x6822, 0x00c6, 0x7054, 0x2060, 0x6004, 0xa084, 0xffc5, 0x6006, 0x00ce, 0x0005, 0x0049, 0x781b, 0x0082, 0x0005, 0x6827, 0x0002, 0x0049, 0x781b, 0x0082, 0x0005, 0x2001, 0x0005, 0x0088, 0x2001, 0x000c, 0x0070, 0x6820, 0xc0d5, 0x6822, 0x2001, 0x0006, 0x0040, 0x2001, 0x000d, 0x0028, 0x2001, 0x0009, 0x0010, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, - 0x70d4, 0xd0b4, 0x0168, 0xc0b4, 0x70d6, 0x00c6, 0x70b8, 0xa065, + 0x70d0, 0xd0b4, 0x0168, 0xc0b4, 0x70d2, 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x0005, 0x0076, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, - 0xb28c, 0x0600, 0x0118, 0xa0e0, 0x47c0, 0x0010, 0xa0e0, 0x4840, + 0xb28c, 0x0600, 0x0118, 0xa0e0, 0x49c0, 0x0010, 0xa0e0, 0x4a40, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x7fe0, 0x78ae, 0x6012, 0x79a4, 0xa184, 0x773f, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0038, 0x6006, 0x007e, 0x0005, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, - 0x0804, 0x3850, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0080, + 0x0804, 0x3a18, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, - 0x789b, 0x0060, 0x78ab, 0x0005, 0x0804, 0x3850, 0x0156, 0x8007, + 0x789b, 0x0060, 0x78ab, 0x0005, 0x0804, 0x3a18, 0x0156, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, - 0xa18c, 0xffe0, 0x2021, 0x3952, 0x2019, 0x0011, 0x20a9, 0x000e, + 0xa18c, 0xffe0, 0x2021, 0x3b1a, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, 0xffe0, 0xa106, 0x0128, 0x8420, - 0x2300, 0xa210, 0x1f04, 0x38ba, 0x015e, 0x0005, 0x0156, 0x0804, - 0x3908, 0x2021, 0x3960, 0x20a9, 0x0009, 0x2011, 0x0029, 0xa582, + 0x2300, 0xa210, 0x1f04, 0x3a82, 0x015e, 0x0005, 0x0156, 0x0804, + 0x3ad0, 0x2021, 0x3b28, 0x20a9, 0x0009, 0x2011, 0x0029, 0xa582, 0x0028, 0x0550, 0x8420, 0x95a9, 0x2011, 0x0033, 0xa582, 0x0033, 0x0618, 0x8420, 0x95a9, 0x2019, 0x000a, 0x2011, 0x0065, 0x2200, - 0xa502, 0x02d0, 0x8420, 0x2300, 0xa210, 0x1f04, 0x38df, 0x015e, - 0x0088, 0x2021, 0x3952, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, + 0xa502, 0x02d0, 0x8420, 0x2300, 0xa210, 0x1f04, 0x3aa7, 0x015e, + 0x0088, 0x2021, 0x3b1a, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0033, 0x2200, 0xa502, 0x0240, 0x8420, 0x2300, 0xa210, 0x1f04, - 0x38f1, 0x015e, 0xa006, 0x0005, 0x8211, 0x015e, 0xa582, 0x0064, + 0x3ab9, 0x015e, 0xa006, 0x0005, 0x8211, 0x015e, 0xa582, 0x0064, 0x1220, 0x7808, 0xa085, 0x0070, 0x780a, 0x2404, 0xa005, 0x0005, - 0xa886, 0x0002, 0x01e8, 0x2021, 0x393e, 0x20a9, 0x000d, 0x2011, + 0xa886, 0x0002, 0x01e8, 0x2021, 0x3b06, 0x20a9, 0x000d, 0x2011, 0x0028, 0xa582, 0x0028, 0x0d48, 0x8420, 0x2019, 0x0019, 0x2011, 0x0033, 0x2200, 0xa502, 0x0e00, 0x8420, 0x2300, 0xa210, 0x1f04, - 0x3919, 0x015e, 0x2011, 0x0184, 0xa582, 0x0185, 0x0ab0, 0x0890, - 0x2021, 0x394d, 0x20a9, 0x0003, 0x2011, 0x0024, 0xa586, 0x0024, + 0x3ae1, 0x015e, 0x2011, 0x0184, 0xa582, 0x0185, 0x0ab0, 0x0890, + 0x2021, 0x3b15, 0x20a9, 0x0003, 0x2011, 0x0024, 0xa586, 0x0024, 0x0960, 0x8420, 0x2011, 0x0028, 0xa586, 0x0028, 0x0930, 0x8420, - 0x2019, 0x0019, 0x2011, 0x0033, 0x0804, 0x38f1, 0x1021, 0x2202, + 0x2019, 0x0019, 0x2011, 0x0033, 0x0804, 0x3ab9, 0x1021, 0x2202, 0x3403, 0x4604, 0x5805, 0x6a06, 0x7c07, 0x4610, 0x4612, 0x5812, 0x5a12, 0x6a14, 0x6c14, 0x6e14, 0x7e17, 0x9021, 0xb002, 0xe204, 0xe210, 0xe210, 0x1209, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, @@ -1391,314 +1485,319 @@ 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06, 0x7c07, 0x7e07, 0x0e00, 0x789b, 0x0080, 0xa046, 0x0005, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xd7fc, - 0x0118, 0xa0e0, 0x68c0, 0x0010, 0xa0e0, 0x48c0, 0x0005, 0x00e6, - 0x00f6, 0xd084, 0x0138, 0x2079, 0x0100, 0x2009, 0x4380, 0x2071, - 0x4380, 0x0030, 0x2009, 0x4340, 0x2079, 0x0200, 0x2071, 0x4340, - 0x2091, 0x8000, 0x2104, 0xa084, 0x000f, 0x0002, 0x39c5, 0x39a0, - 0x39a0, 0x39a0, 0x39a0, 0x39a0, 0x399e, 0x399e, 0x080c, 0x243b, - 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, 0x1de0, 0x784b, 0x0008, - 0x7848, 0xa084, 0x0008, 0x1de0, 0x68b4, 0xc0f5, 0x68b6, 0x7858, - 0xc0f5, 0x785a, 0x7830, 0xd0bc, 0x1180, 0xb284, 0x0800, 0x0118, - 0x0104, 0x39c5, 0x0010, 0x0304, 0x39c5, 0x681c, 0xd0ac, 0x1118, - 0x080c, 0x3a4b, 0x0010, 0x781b, 0x00fb, 0x2091, 0x8001, 0x00fe, - 0x00ee, 0x0005, 0x00c6, 0x2001, 0x4301, 0x2004, 0xd0ac, 0x1904, - 0x3a3d, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, - 0xb28c, 0x0600, 0x0118, 0xa0e0, 0x47c0, 0x0010, 0xa0e0, 0x4840, - 0x6004, 0xa084, 0x000a, 0x1904, 0x3a3d, 0x6108, 0xa194, 0xff00, - 0x0904, 0x3a3d, 0xa18c, 0x00ff, 0x601c, 0xa084, 0xff00, 0x0180, - 0x2001, 0x0009, 0xa102, 0x16b8, 0x2001, 0x000a, 0xa102, 0x16b0, - 0x2001, 0x000c, 0xa102, 0x16a8, 0x601c, 0xa084, 0x00ff, 0x601e, - 0x2001, 0x000a, 0xa106, 0x01a8, 0x2001, 0x000c, 0xa106, 0x01a0, - 0x2001, 0x0012, 0xa106, 0x0198, 0x2001, 0x0014, 0xa106, 0x0190, - 0x2001, 0x0019, 0xa106, 0x0188, 0x2001, 0x0032, 0xa106, 0x0180, - 0x00d8, 0x2009, 0x000c, 0x00d0, 0x2009, 0x0012, 0x00b8, 0x2009, - 0x0014, 0x00a0, 0x2009, 0x0019, 0x0088, 0x2009, 0x0020, 0x0070, - 0x2009, 0x003f, 0x0058, 0x2009, 0x000a, 0x0040, 0x2009, 0x000c, - 0x0028, 0x2009, 0x0019, 0x0010, 0x2011, 0x0000, 0x2100, 0xa205, - 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x00ce, 0x0005, 0x781b, - 0x0083, 0x0005, 0x781b, 0x0082, 0x0005, 0x781b, 0x0071, 0x0005, - 0x781b, 0x006e, 0x0005, 0x2009, 0x4319, 0x210c, 0xa186, 0x0000, - 0x0150, 0xa186, 0x0001, 0x0150, 0x701f, 0x000b, 0x7067, 0x0001, - 0x781b, 0x0054, 0x0005, 0x781b, 0x00f3, 0x0005, 0x701f, 0x000a, - 0x0005, 0x2009, 0x4319, 0x210c, 0xa186, 0x0000, 0x0168, 0xa186, - 0x0001, 0x0138, 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0054, - 0x0005, 0x701f, 0x000a, 0x0005, 0x781b, 0x00f2, 0x0005, 0x781b, - 0x00fb, 0x0005, 0x781b, 0x00fa, 0x0005, 0x781b, 0x00cc, 0x0005, - 0x781b, 0x00cb, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, - 0x7067, 0x0001, 0x781b, 0x0054, 0x0005, 0x7830, 0xa084, 0x00c0, - 0x1170, 0x7808, 0xc08c, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000, - 0x78ec, 0xa084, 0x0021, 0x0118, 0x7808, 0xc08d, 0x780a, 0x0005, - 0x7808, 0xc08d, 0x780a, 0x0005, 0x7830, 0xa084, 0x0040, 0x1de0, - 0xb284, 0x0800, 0x0118, 0x1104, 0x3ab2, 0x0010, 0x1304, 0x3ab2, - 0x78ac, 0x0005, 0x7808, 0xa084, 0xfffd, 0x780a, 0xe000, 0xe000, - 0xe000, 0xe000, 0x78ec, 0xa084, 0x0021, 0x0140, 0xb284, 0x0800, - 0x0118, 0x1104, 0x3ac1, 0x0010, 0x1304, 0x3ac4, 0x78ac, 0x0006, - 0x7808, 0xa085, 0x0002, 0x780a, 0x000e, 0x0005, 0xa784, 0x0001, - 0x1904, 0x30a0, 0xa784, 0x0070, 0x0140, 0x00c6, 0x2d60, 0x2f68, - 0x080c, 0x23e1, 0x2d78, 0x2c68, 0x00ce, 0xa784, 0x0008, 0x0148, - 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x248f, 0x0804, - 0x3a3f, 0xa784, 0x0004, 0x01c8, 0x78b8, 0xa084, 0x8000, 0x01a8, - 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x248f, 0x78e4, - 0xa084, 0x0007, 0xa086, 0x0001, 0x1140, 0x78c0, 0xa685, 0x4800, - 0x2030, 0x7e5a, 0x781b, 0x00fb, 0x0005, 0xa784, 0x0080, 0x0140, - 0x7884, 0xd0fc, 0x0128, 0x080c, 0x382d, 0x681b, 0x0022, 0x0005, - 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, - 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, - 0x2a7a, 0xb284, 0x0800, 0x0110, 0x0104, 0x248c, 0x0304, 0x248c, - 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, - 0x0118, 0xa080, 0x4840, 0x0010, 0xa080, 0x47c0, 0x2060, 0x2048, - 0x705a, 0x2a60, 0x0005, 0x00c6, 0x2960, 0x6000, 0xd0ac, 0x0904, - 0x3b81, 0xd1ac, 0x05e0, 0x6108, 0x8117, 0xa18c, 0x00ff, 0x631c, - 0x832f, 0x68a0, 0xd0cc, 0x11c8, 0xa584, 0x00ff, 0x0138, 0x78ec, - 0xd0e4, 0x0110, 0x8213, 0x00b8, 0x2029, 0x0000, 0xa182, 0x000c, - 0x1290, 0x78ec, 0xd0e4, 0x1118, 0x2009, 0x000c, 0x0060, 0xa182, - 0x000b, 0x1248, 0x2009, 0x000a, 0x0030, 0x2009, 0x0032, 0x2011, - 0x0000, 0x2029, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, - 0x0004, 0x79aa, 0x78ab, 0x0000, 0x7aaa, 0x7baa, 0x7daa, 0xa8c0, - 0x0008, 0x6820, 0xa085, 0x1000, 0x6822, 0x080c, 0x3850, 0xa085, - 0x0001, 0x00ce, 0x0005, 0xa282, 0x0006, 0x1904, 0x381f, 0x7da8, - 0x7eac, 0x8637, 0xa5ac, 0x00ff, 0xa6b4, 0x00ff, 0x7fac, 0x8747, - 0xa7bc, 0x00ff, 0xa8c4, 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1e4, - 0x05c8, 0xa18c, 0xecff, 0x6922, 0xa782, 0x0002, 0x1a04, 0x37fc, - 0xa6b4, 0x00ff, 0x0560, 0xa682, 0x0039, 0x1a04, 0x37fc, 0xa582, - 0x0009, 0x0a04, 0x37fc, 0xa882, 0x0003, 0x1a04, 0x37fc, 0xa886, - 0x0002, 0x0128, 0xa886, 0x0000, 0x0138, 0x0804, 0x37fc, 0xa786, - 0x0000, 0x0904, 0x37fc, 0x8634, 0x852b, 0x852b, 0x080c, 0x38c6, - 0x0904, 0x37fc, 0x080c, 0x36f6, 0x080c, 0x379a, 0x7e58, 0xd6d4, - 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0x080c, - 0x36f3, 0x0c90, 0xa886, 0x0002, 0x1108, 0x8634, 0x7158, 0xa188, - 0x0000, 0x210c, 0xd1ac, 0x0904, 0x37fc, 0xd1ec, 0x1120, 0x2039, - 0x0000, 0x2041, 0x0000, 0xd1e4, 0x1120, 0x2031, 0x0000, 0x2041, - 0x0000, 0xa782, 0x0002, 0x12c8, 0x621c, 0xa284, 0x00ff, 0xa706, - 0x0110, 0x2039, 0x0000, 0xa605, 0x0190, 0x6108, 0x811f, 0xa39c, - 0x00ff, 0x0168, 0xa302, 0x1208, 0x2330, 0x8807, 0xa705, 0xa086, - 0x0201, 0x0160, 0xa886, 0x0000, 0x0168, 0x2039, 0x0000, 0x2041, - 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x0070, 0xa284, 0xff00, - 0x1108, 0x2040, 0xa184, 0x00ff, 0xa502, 0x0108, 0x2128, 0x852b, - 0x852b, 0x080c, 0x38c6, 0x0d58, 0x080c, 0x36f6, 0x080c, 0x379a, - 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, 0x0004, - 0x78ab, 0x0000, 0x7daa, 0x7eaa, 0x7faa, 0x2800, 0x78aa, 0x789b, - 0x0060, 0x78ab, 0x0005, 0x080c, 0x3850, 0x7858, 0xc095, 0x785a, - 0x781b, 0x0082, 0x0005, 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, - 0x0014, 0x9855, 0x984d, 0x0014, 0x9911, 0x98ff, 0x0014, 0x0014, - 0x0090, 0x00e7, 0x0100, 0x0402, 0x2008, 0xf880, 0x0018, 0x0017, - 0x840f, 0xd8c1, 0x0014, 0x0016, 0xa20a, 0x0014, 0x300b, 0xa20c, - 0x0014, 0x2500, 0x0013, 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0118, 0xa0e0, 0x6ac0, 0x0010, 0xa0e0, 0x4ac0, 0x0005, 0x00e6, + 0x00f6, 0xd084, 0x0138, 0x2079, 0x0100, 0x2009, 0x4580, 0x2071, + 0x4580, 0x0030, 0x2009, 0x4540, 0x2079, 0x0200, 0x2071, 0x4540, + 0x2091, 0x8000, 0x2104, 0xa084, 0x000f, 0x0002, 0x3b68, 0x3b68, + 0x3b68, 0x3b68, 0x3b68, 0x3b68, 0x3b66, 0x3b66, 0x080c, 0x252b, + 0x69b4, 0xc1f5, 0xa18c, 0xff9f, 0x69b6, 0xa005, 0x0580, 0x7858, + 0xa084, 0xff9f, 0xa085, 0x6000, 0x785a, 0x7828, 0xa086, 0x1814, + 0x1530, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, 0x1de0, 0x784b, + 0x0008, 0x7848, 0xa084, 0x0008, 0x1de0, 0x7830, 0xd0bc, 0x11b8, + 0xb284, 0x0800, 0x0118, 0x0104, 0x3b9f, 0x0010, 0x0304, 0x3b9f, + 0x79e4, 0xa184, 0x0030, 0x0158, 0x78ec, 0xa084, 0x0003, 0x0138, + 0x681c, 0xd0ac, 0x1110, 0x00d9, 0x0010, 0x781b, 0x00fb, 0x00fe, + 0x00ee, 0x0005, 0x2001, 0x4501, 0x2004, 0xd0ac, 0x1118, 0x6814, + 0x080c, 0x2454, 0x0005, 0x781b, 0x0083, 0x0005, 0x781b, 0x0082, + 0x0005, 0x781b, 0x0071, 0x0005, 0x781b, 0x006e, 0x0005, 0x2009, + 0x4519, 0x210c, 0xa186, 0x0000, 0x0150, 0xa186, 0x0001, 0x0150, + 0x701f, 0x000b, 0x7063, 0x0001, 0x781b, 0x0054, 0x0005, 0x781b, + 0x00f3, 0x0005, 0x701f, 0x000a, 0x0005, 0x2009, 0x4519, 0x210c, + 0xa186, 0x0000, 0x0168, 0xa186, 0x0001, 0x0138, 0x701f, 0x000b, + 0x7063, 0x0001, 0x781b, 0x0054, 0x0005, 0x701f, 0x000a, 0x0005, + 0x781b, 0x00f2, 0x0005, 0x781b, 0x00fb, 0x0005, 0x781b, 0x00fa, + 0x0005, 0x781b, 0x00cc, 0x0005, 0x781b, 0x00cb, 0x0005, 0x6818, + 0xd0fc, 0x0110, 0x681b, 0x001d, 0x7063, 0x0001, 0x781b, 0x0054, + 0x0005, 0x7830, 0xa084, 0x00c0, 0x1170, 0x7808, 0xc08c, 0x780a, + 0xe000, 0xe000, 0xe000, 0xe000, 0x78ec, 0xa084, 0x0021, 0x0118, + 0x7808, 0xc08d, 0x780a, 0x0005, 0x7808, 0xc08d, 0x780a, 0x0005, + 0x7830, 0xa084, 0x0040, 0x1de0, 0xb284, 0x0800, 0x0118, 0x1104, + 0x3c1e, 0x0010, 0x1304, 0x3c1e, 0x78ac, 0x0005, 0x7808, 0xa084, + 0xfffd, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000, 0x78ec, 0xa084, + 0x0021, 0x0140, 0xb284, 0x0800, 0x0118, 0x1104, 0x3c2d, 0x0010, + 0x1304, 0x3c30, 0x78ac, 0x0006, 0x7808, 0xa085, 0x0002, 0x780a, + 0x000e, 0x0005, 0xa784, 0x0001, 0x1904, 0x31c5, 0xa784, 0x0070, + 0x0140, 0x00c6, 0x2d60, 0x2f68, 0x080c, 0x2446, 0x2d78, 0x2c68, + 0x00ce, 0xa784, 0x0008, 0x0148, 0x784b, 0x0008, 0x78ec, 0xa084, + 0x0003, 0x0904, 0x31c5, 0x0804, 0x3bab, 0xa784, 0x0004, 0x01c8, + 0x78b8, 0xa084, 0x8000, 0x01a8, 0x784b, 0x0008, 0x78ec, 0xa084, + 0x0003, 0x0904, 0x31c5, 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, + 0x1140, 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00fb, + 0x0005, 0xa784, 0x0080, 0x0140, 0x7884, 0xd0fc, 0x0128, 0x080c, + 0x39f5, 0x681b, 0x0022, 0x0005, 0x681b, 0x0003, 0x7858, 0xa084, + 0x5f00, 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, + 0x78ec, 0xa084, 0x0003, 0x0904, 0x2b6b, 0xb284, 0x0800, 0x0110, + 0x0104, 0x257c, 0x0304, 0x257c, 0x6b14, 0x8307, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0xd3fc, 0x0118, 0xa080, 0x4a40, 0x0010, + 0xa080, 0x49c0, 0x2060, 0x2048, 0x7056, 0x2a60, 0x0005, 0x00c6, + 0x2960, 0x6000, 0xd0ac, 0x0904, 0x3ced, 0xd1ac, 0x05e0, 0x6108, + 0x8117, 0xa18c, 0x00ff, 0x631c, 0x832f, 0x68a0, 0xd0cc, 0x11c8, + 0xa584, 0x00ff, 0x0138, 0x78ec, 0xd0e4, 0x0110, 0x8213, 0x00b8, + 0x2029, 0x0000, 0xa182, 0x000c, 0x1290, 0x78ec, 0xd0e4, 0x1118, + 0x2009, 0x000c, 0x0060, 0xa182, 0x000b, 0x1248, 0x2009, 0x000a, + 0x0030, 0x2009, 0x0032, 0x2011, 0x0000, 0x2029, 0x0000, 0x78ab, + 0x0001, 0x78ab, 0x0006, 0x78ab, 0x0004, 0x79aa, 0x78ab, 0x0000, + 0x7aaa, 0x7baa, 0x7daa, 0xa8c0, 0x0008, 0x6820, 0xa085, 0x1000, + 0x6822, 0x080c, 0x3a18, 0xa085, 0x0001, 0x00ce, 0x0005, 0xa282, + 0x0006, 0x1904, 0x39e7, 0x7da8, 0x7eac, 0x8637, 0xa5ac, 0x00ff, + 0xa6b4, 0x00ff, 0x7fac, 0x8747, 0xa7bc, 0x00ff, 0xa8c4, 0x00ff, + 0x6920, 0xc1bd, 0x6922, 0xd1e4, 0x0904, 0x3d59, 0xa18c, 0xecff, + 0x6922, 0xa782, 0x0002, 0x1a04, 0x39c3, 0xa6b4, 0x00ff, 0x0904, + 0x3d56, 0xa682, 0x0039, 0x1a04, 0x39c3, 0xa582, 0x0009, 0x0a04, + 0x39c3, 0xa882, 0x0003, 0x1a04, 0x39c3, 0xa886, 0x0002, 0x01d0, + 0xa886, 0x0000, 0x1904, 0x39c3, 0x2001, 0x000c, 0x79ec, 0xd1e4, + 0x0110, 0x2001, 0x000a, 0xa502, 0x1290, 0x080c, 0x39c3, 0x00c6, + 0x2960, 0x6004, 0xa085, 0x001a, 0x6006, 0x6000, 0xc0ac, 0x6002, + 0x00ce, 0x0005, 0xa786, 0x0000, 0x0904, 0x39c3, 0x8634, 0xa686, + 0x0010, 0x1108, 0x8630, 0x852b, 0x852b, 0x080c, 0x3a8e, 0x0904, + 0x39c3, 0x080c, 0x38bd, 0x080c, 0x3961, 0x7e58, 0xd6d4, 0x1118, + 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0x080c, 0x38ba, + 0x0c90, 0xa886, 0x0002, 0x1108, 0x8634, 0x7154, 0xa188, 0x0000, + 0x210c, 0xd1ac, 0x0904, 0x39c3, 0xd1ec, 0x1120, 0x2039, 0x0000, + 0x2041, 0x0000, 0xd1e4, 0x1120, 0x2031, 0x0000, 0x2041, 0x0000, + 0xa782, 0x0002, 0x12c8, 0x621c, 0xa284, 0x00ff, 0xa706, 0x0110, + 0x2039, 0x0000, 0xa605, 0x0190, 0x6108, 0x811f, 0xa39c, 0x00ff, + 0x0168, 0xa302, 0x1208, 0x2330, 0x8807, 0xa705, 0xa086, 0x0201, + 0x0160, 0xa886, 0x0000, 0x0168, 0x2039, 0x0000, 0x2041, 0x0000, + 0x2031, 0x0000, 0xa006, 0x2010, 0x0070, 0xa284, 0xff00, 0x1108, + 0x2040, 0xa184, 0x00ff, 0xa502, 0x0108, 0x2128, 0x852b, 0x852b, + 0x080c, 0x3a8e, 0x0d58, 0x080c, 0x38bd, 0x080c, 0x3961, 0x789b, + 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, 0x0004, 0x78ab, + 0x0000, 0x7daa, 0x7eaa, 0x7faa, 0x2800, 0x78aa, 0x789b, 0x0060, + 0x78ab, 0x0005, 0x080c, 0x3a18, 0x7858, 0xc095, 0x785a, 0x781b, + 0x0082, 0x0005, 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, + 0x9855, 0x984d, 0x0014, 0x9911, 0x98ff, 0x0014, 0x0014, 0x0090, + 0x00e7, 0x0100, 0x0402, 0x2008, 0xf880, 0x0018, 0x0017, 0x840f, + 0xd8c1, 0x0014, 0x0016, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, + 0x2500, 0x0013, 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0xa200, 0x3806, 0x8839, 0x20c4, 0x0864, 0xa84f, - 0x3008, 0x28c1, 0x9d18, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, - 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9cce, 0xa8f3, - 0x0864, 0xa83d, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9cce, 0x2021, - 0xa818, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, 0x6fc0, 0x67a4, - 0x6c80, 0x0212, 0xa205, 0x883d, 0x882b, 0x1814, 0x883b, 0x7027, - 0x85f2, 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa814, 0x883e, - 0xa812, 0x280a, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x1814, - 0x883b, 0x7027, 0x8576, 0x8677, 0xa806, 0x796d, 0xa8da, 0x796b, - 0xa8f1, 0x7861, 0x883e, 0x206b, 0x28c1, 0x9d18, 0x2044, 0x2103, - 0x20b4, 0x2095, 0xa8ca, 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, + 0x0010, 0xa200, 0x3806, 0x8839, 0x20c4, 0x0864, 0xa850, 0x3008, + 0x28c1, 0x9d18, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, + 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9cce, 0xa8f3, 0x0864, + 0xa83e, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9cce, 0x28a1, 0x7162, + 0x2021, 0xa818, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, 0x6fc0, + 0x67a4, 0x6c80, 0x0212, 0xa205, 0x883d, 0x882b, 0x1814, 0x883b, + 0x7027, 0x85f2, 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa812, + 0x883e, 0xa810, 0x2881, 0x7161, 0x280a, 0xa204, 0x64c0, 0x6de0, + 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa802, + 0x7861, 0x883e, 0x206c, 0x28c1, 0x9d18, 0x2044, 0x2103, 0x20a2, + 0x2081, 0xa8ca, 0x2902, 0xa20e, 0xa80b, 0xa207, 0x0014, 0xa203, 0x8000, 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, - 0x856e, 0x866f, 0x7121, 0x0014, 0x0704, 0x3008, 0x9cce, 0x0014, - 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, - 0x883f, 0x08e6, 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, 0xf881, - 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, - 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, - 0x8000, 0x2849, 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2081, - 0x2802, 0x1011, 0xa8fc, 0xa889, 0x3008, 0x20a1, 0x283c, 0x1011, - 0xa8fc, 0xa209, 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, - 0x0014, 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, - 0x26e0, 0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, - 0x9d22, 0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, - 0x0016, 0x6042, 0x8008, 0xa8fa, 0x8160, 0x842a, 0x8180, 0xf021, - 0x3008, 0x84a8, 0x11d7, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, - 0x0016, 0x0000, 0x0126, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, - 0x7204, 0x7008, 0xc09c, 0xa205, 0x1178, 0x720c, 0x82ff, 0x0128, - 0x8aff, 0x1150, 0x7200, 0xd284, 0x1138, 0x7007, 0x0004, 0x7003, - 0x0008, 0x012e, 0x2000, 0x0005, 0x7000, 0xa084, 0x0003, 0x7002, - 0xc69c, 0xd084, 0x05b8, 0x2001, 0x4301, 0x2004, 0xd0b4, 0x0904, - 0x3dcf, 0x7108, 0xe000, 0x7008, 0xa106, 0x1dd8, 0xa184, 0x0003, - 0x0904, 0x3dcf, 0xa184, 0x01e0, 0x1904, 0x3dcf, 0xd1f4, 0x1d88, - 0xa184, 0x3000, 0xa086, 0x1000, 0x0d60, 0x2011, 0x0180, 0x710c, - 0x8211, 0x0130, 0x7008, 0xd0f4, 0x1d20, 0x700c, 0xa106, 0x0dc0, - 0x7007, 0x0012, 0x7108, 0xe000, 0x7008, 0xa106, 0x1dd8, 0xa184, - 0x0003, 0x0568, 0xd194, 0x0db0, 0xd1f4, 0x0548, 0x7007, 0x0002, - 0x0880, 0x0428, 0x7108, 0xd1fc, 0x0130, 0x080c, 0x3e9e, 0x8aff, - 0x0904, 0x3d58, 0x0cb8, 0x700c, 0xa08c, 0x07ff, 0x01e8, 0x7004, - 0xd084, 0x0178, 0x7014, 0xa005, 0x1148, 0x7010, 0x7310, 0xa306, - 0x1de0, 0x2300, 0xa005, 0x0128, 0xa102, 0x1e20, 0x7007, 0x0010, - 0x0030, 0x8aff, 0x0148, 0x080c, 0x4046, 0x1de8, 0x09d8, 0x080c, - 0x3e58, 0x012e, 0x2000, 0x0005, 0x7204, 0x7108, 0xc19c, 0x8103, - 0x1218, 0x080c, 0x3e9e, 0x0cc0, 0xa205, 0x1d88, 0x7007, 0x0004, - 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, 0x6428, 0x84ff, 0x0508, - 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x3e19, 0x273c, 0x87fb, - 0x1148, 0x0210, 0x080c, 0x243b, 0x609c, 0xa075, 0x0190, 0x0c88, - 0x2039, 0x3e0e, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, - 0x8421, 0x0138, 0x8738, 0x2704, 0xa005, 0x1da8, 0x709c, 0xa075, - 0x1d00, 0x0005, 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, 0x0015, - 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, - 0x0000, 0x0000, 0x3e0e, 0x3e0b, 0x0000, 0x0000, 0x8000, 0x0000, - 0x3e0e, 0x0000, 0x3e16, 0x3e13, 0x0000, 0x0000, 0x0000, 0x0000, - 0x3e16, 0x0000, 0x3e11, 0x3e11, 0x0000, 0x0000, 0x8000, 0x0000, - 0x3e11, 0x0000, 0x3e17, 0x3e17, 0x0000, 0x0000, 0x0000, 0x0000, - 0x3e17, 0x2079, 0x4300, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, - 0x0002, 0x7003, 0x0001, 0x2009, 0x0002, 0x2071, 0x0050, 0x7007, - 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x1128, 0x8109, 0x0118, 0x2071, 0x0020, 0x0c80, 0x0005, - 0x7004, 0x8004, 0x1690, 0x7007, 0x0012, 0x2019, 0x0000, 0x7108, - 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0110, 0x080c, 0x243b, - 0xa19c, 0x300c, 0xa386, 0x2004, 0x0130, 0xa386, 0x0008, 0x0160, - 0xa386, 0x200c, 0x1d60, 0x7200, 0x8204, 0x0230, 0x730c, 0xa384, - 0x07ff, 0x0110, 0x080c, 0x243b, 0x7007, 0x0012, 0x7000, 0xd084, - 0x1160, 0x7008, 0xa084, 0x01e0, 0x1140, 0x7310, 0x7014, 0xa305, - 0x0120, 0x710c, 0xa184, 0x07ff, 0x1958, 0x7007, 0x0012, 0x7007, - 0x0008, 0x7004, 0xd09c, 0x1de8, 0x7007, 0x0012, 0x7108, 0x8103, - 0x0ed8, 0x7003, 0x0008, 0x0005, 0x7108, 0x0000, 0xa184, 0x01e0, - 0x1550, 0x7108, 0xa184, 0x01e0, 0x1530, 0xa184, 0x0007, 0x0002, - 0x3eb2, 0x3ec0, 0x3eb0, 0x3ec0, 0x3eb0, 0x3f06, 0x3eb0, 0x3f05, - 0x080c, 0x243b, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, - 0x1118, 0x2049, 0x0000, 0x0005, 0x080c, 0x4046, 0x1de8, 0x0005, - 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x0118, 0x080c, - 0x4046, 0x1de8, 0x0005, 0x7007, 0x0012, 0x7108, 0x1d04, 0x3ece, - 0x2091, 0x6000, 0x1d04, 0x3ed2, 0x2091, 0x6000, 0x7007, 0x0012, + 0x856e, 0x7121, 0x0014, 0x0704, 0x3008, 0x9cce, 0x0014, 0xa202, + 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, 0x883f, + 0x08e6, 0xa8f5, 0xf861, 0xa8eb, 0xf801, 0x0014, 0xf881, 0x0016, + 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, + 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, 0x8000, + 0x2849, 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2081, 0x2802, + 0x1011, 0xa8fc, 0xa889, 0x3008, 0x20a1, 0x283c, 0x1011, 0xa8fc, + 0xa209, 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, + 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, + 0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d22, + 0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, + 0x6042, 0x8008, 0xa8fa, 0x8160, 0x842a, 0x8180, 0xf021, 0x3008, + 0x84a8, 0x11d7, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016, + 0x0000, 0x0126, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x7204, + 0x7008, 0xc09c, 0xa205, 0x1178, 0x720c, 0x82ff, 0x0128, 0x8aff, + 0x1150, 0x7200, 0xd284, 0x1138, 0x7007, 0x0004, 0x7003, 0x0008, + 0x012e, 0x2000, 0x0005, 0x7000, 0xa084, 0x0003, 0x7002, 0xc69c, + 0xd084, 0x0588, 0x7108, 0xe000, 0x7008, 0xa106, 0x1dd8, 0xa184, + 0x0003, 0x0904, 0x3f50, 0xa184, 0x01e0, 0x1904, 0x3f50, 0xd1f4, + 0x1d88, 0xa184, 0x3000, 0xa086, 0x1000, 0x0d60, 0x2011, 0x0180, + 0x710c, 0x8211, 0x0130, 0x7008, 0xd0f4, 0x1d20, 0x700c, 0xa106, + 0x0dc0, 0x7007, 0x0012, 0x7108, 0xe000, 0x7008, 0xa106, 0x1dd8, + 0xa184, 0x0003, 0x0568, 0xd194, 0x0db0, 0xd1f4, 0x0548, 0x7007, + 0x0002, 0x0880, 0x0428, 0x7108, 0xd1fc, 0x0130, 0x080c, 0x4053, + 0x8aff, 0x0904, 0x3edf, 0x0cb8, 0x700c, 0xa08c, 0x07ff, 0x01e8, + 0x7004, 0xd084, 0x0178, 0x7014, 0xa005, 0x1148, 0x7010, 0x7310, + 0xa306, 0x1de0, 0x2300, 0xa005, 0x0128, 0xa102, 0x1e20, 0x7007, + 0x0010, 0x0030, 0x8aff, 0x0148, 0x080c, 0x4212, 0x1de8, 0x09d8, + 0x080c, 0x3fd9, 0x012e, 0x2000, 0x0005, 0x7204, 0x7108, 0xc19c, + 0x8103, 0x1218, 0x7007, 0x0002, 0x0cc0, 0xa205, 0x1d88, 0x7007, + 0x0004, 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, 0x6428, 0x84ff, + 0x0508, 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x3f9a, 0x273c, + 0x87fb, 0x1148, 0x0210, 0x080c, 0x252b, 0x609c, 0xa075, 0x0190, + 0x0c88, 0x2039, 0x3f8f, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, + 0xa529, 0x8421, 0x0138, 0x8738, 0x2704, 0xa005, 0x1da8, 0x709c, + 0xa075, 0x1d00, 0x0005, 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, + 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, + 0x001b, 0x0000, 0x0000, 0x3f8f, 0x3f8c, 0x0000, 0x0000, 0x8000, + 0x0000, 0x3f8f, 0x0000, 0x3f97, 0x3f94, 0x0000, 0x0000, 0x0000, + 0x0000, 0x3f97, 0x0000, 0x3f92, 0x3f92, 0x0000, 0x0000, 0x8000, + 0x0000, 0x3f92, 0x0000, 0x3f98, 0x3f98, 0x0000, 0x0000, 0x0000, + 0x0000, 0x3f98, 0x2079, 0x4500, 0x2071, 0x0010, 0x7007, 0x000a, + 0x7007, 0x0002, 0x7003, 0x0001, 0x2009, 0x0002, 0x2071, 0x0050, + 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x1128, 0x8109, 0x0118, 0x2071, 0x0020, 0x0c80, + 0x0005, 0x7004, 0x8004, 0x1a04, 0x402f, 0x7108, 0x7008, 0xa106, + 0x1de0, 0xa184, 0x01e0, 0x0120, 0x080c, 0x408b, 0x0804, 0x404f, + 0x7007, 0x0012, 0x2019, 0x0000, 0x7108, 0x7008, 0xa106, 0x1de0, + 0xa184, 0x01e0, 0x0120, 0x080c, 0x408b, 0x0804, 0x404f, 0xa19c, + 0x300c, 0xa386, 0x2004, 0x0190, 0xa386, 0x0008, 0x01c0, 0x7004, + 0xd084, 0x1148, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x0003, + 0x0110, 0x0804, 0x408b, 0xa386, 0x200c, 0x19f0, 0x7200, 0x8204, + 0x0230, 0x730c, 0xa384, 0x07ff, 0x0110, 0x080c, 0x252b, 0x7108, + 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0118, 0x080c, 0x408b, + 0x0470, 0x7007, 0x0012, 0x7000, 0xd084, 0x1148, 0x7310, 0x7014, + 0xa305, 0x0128, 0x710c, 0xa184, 0x07ff, 0x1904, 0x3fd9, 0x7108, + 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0118, 0x080c, 0x408b, + 0x00b0, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x1de8, + 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0118, 0x080c, + 0x408b, 0x0028, 0x7007, 0x0012, 0x7108, 0x8103, 0x0e88, 0x7003, + 0x0008, 0x0005, 0x7108, 0xa184, 0x01e0, 0x15a8, 0x7108, 0xa184, + 0x01e0, 0x1588, 0xa184, 0x0007, 0x0002, 0x4067, 0x4075, 0x4065, + 0x4075, 0x4065, 0x40c5, 0x4065, 0x40c3, 0x080c, 0x252b, 0x7004, + 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x1118, 0x2049, 0x0000, + 0x0005, 0x080c, 0x4212, 0x1de8, 0x0005, 0x7004, 0xa084, 0x0010, + 0xc08d, 0x7006, 0x7004, 0xd084, 0x1140, 0x7108, 0x7008, 0xa106, + 0x1de0, 0xa184, 0x0003, 0x0108, 0x0030, 0x8aff, 0x0118, 0x080c, + 0x4212, 0x1de8, 0x0005, 0x7007, 0x0012, 0x7108, 0x1d04, 0x408e, + 0x2091, 0x6000, 0x1d04, 0x4092, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x1de8, 0x7007, 0x0012, 0x7108, 0xd1fc, 0x1dd8, 0x7003, 0x0000, 0x7000, 0xa005, 0x1130, 0x7004, 0xa005, 0x1118, 0x700c, 0xa005, 0x0108, 0x0c40, 0x2049, 0x0000, 0xb284, 0x0200, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, - 0x080c, 0x397f, 0x6818, 0xa084, 0x8000, 0x0110, 0x681b, 0x0002, - 0x0005, 0x080c, 0x243b, 0x080c, 0x243b, 0x04b9, 0x7210, 0x7114, - 0x700c, 0xa09c, 0x07ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, - 0x0461, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, - 0x2100, 0xa31b, 0x2400, 0xa305, 0x0140, 0x1238, 0x8412, 0x8210, - 0x830a, 0xa189, 0x0000, 0x2b60, 0x0c58, 0x2b60, 0x8a07, 0x0006, - 0x6004, 0xa084, 0x0008, 0x0118, 0xa7ba, 0x3e13, 0x0010, 0xa7ba, - 0x3e0b, 0x000e, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, - 0x7007, 0x0012, 0x080c, 0x3e58, 0x0005, 0x8a50, 0x8739, 0x2704, + 0x080c, 0x3b47, 0x681b, 0x0002, 0x2051, 0x0000, 0x0005, 0x080c, + 0x252b, 0x080c, 0x252b, 0x080c, 0x4105, 0x7210, 0x7114, 0x700c, + 0xa09c, 0x07ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x04a9, + 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, + 0xa31b, 0x2400, 0xa305, 0x0140, 0x1238, 0x8412, 0x8210, 0x830a, + 0xa189, 0x0000, 0x2b60, 0x0c58, 0x2b60, 0x8a07, 0x0006, 0x6004, + 0xa084, 0x0008, 0x0118, 0xa7ba, 0x3f94, 0x0010, 0xa7ba, 0x3f8c, + 0x000e, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x7108, + 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0110, 0x080c, 0x408b, + 0x7007, 0x0012, 0x080c, 0x3fd9, 0x0005, 0x8a50, 0x8739, 0x2704, 0xa004, 0x1168, 0x6000, 0xa064, 0x1108, 0x2d60, 0x6004, 0xa084, - 0x000f, 0xa080, 0x3e29, 0x203c, 0x87fb, 0x090c, 0x243b, 0x0005, - 0x0126, 0x00d6, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, + 0x000f, 0xa080, 0x3faa, 0x203c, 0x87fb, 0x090c, 0x252b, 0x0005, + 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x0006, 0x6804, 0xa084, 0x0008, 0x000e, 0x0118, - 0xa0b8, 0x3e13, 0x0010, 0xa0b8, 0x3e0b, 0xb284, 0x0200, 0x0110, + 0xa0b8, 0x3f94, 0x0010, 0xa0b8, 0x3f8c, 0xb284, 0x0200, 0x0110, 0x7e20, 0x0008, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0108, 0xc685, 0x2400, 0xa305, 0x0520, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, 0x0008, 0x0140, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, - 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x080c, 0x4067, 0x0010, - 0x080c, 0x4046, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x00d6, - 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x7007, 0x0004, + 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x080c, 0x423a, 0x0010, + 0x080c, 0x4212, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x00d6, + 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x7007, 0x0004, 0x7004, 0xd094, 0x1de8, 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, - 0x0126, 0x00d6, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, + 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x7e20, 0xb284, 0x0200, 0x1108, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0ac, 0x1118, 0xc685, 0x7003, 0x0000, 0x6828, 0x2050, 0x2d60, - 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x3e19, 0x273c, 0x87fb, 0x1138, - 0x0210, 0x080c, 0x243b, 0x689c, 0xa065, 0x0120, 0x0c88, 0x080c, - 0x4046, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x0006, 0x0016, - 0x00d6, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x7e20, 0xb284, + 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x3f9a, 0x273c, 0x87fb, 0x1138, + 0x0210, 0x080c, 0x252b, 0x689c, 0xa065, 0x0120, 0x0c88, 0x080c, + 0x4212, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x0006, 0x0016, + 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x7e20, 0xb284, 0x0200, 0x1108, 0x7e24, 0x00de, 0x003e, 0x004e, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0128, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, - 0x2049, 0x3fe5, 0x6828, 0xa055, 0x05f0, 0x2d70, 0x2e60, 0x7004, - 0xa0bc, 0x000f, 0xa7b8, 0x3e19, 0x273c, 0x87fb, 0x1140, 0x0210, - 0x080c, 0x243b, 0x709c, 0xa075, 0x2060, 0x0568, 0x0c80, 0x2704, - 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0268, 0x8a51, 0x1110, - 0x080c, 0x243b, 0x8738, 0x2704, 0xa005, 0x1d90, 0x709c, 0xa075, - 0x2060, 0x01c8, 0x08e0, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, - 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x1210, 0x080c, - 0x243b, 0xb284, 0x0200, 0x0118, 0x2071, 0x0050, 0x0010, 0x2071, - 0x0020, 0x0804, 0x3f79, 0x012e, 0x2000, 0x0005, 0x7008, 0xa084, - 0x0003, 0xa086, 0x0003, 0x1108, 0x0005, 0x2704, 0xac78, 0x7800, - 0x701a, 0x7804, 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, - 0xa084, 0x0008, 0x0120, 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, - 0x7004, 0xa084, 0x0010, 0xc085, 0x7006, 0x2079, 0x4300, 0x8a51, - 0x01b0, 0x8738, 0x2704, 0xa005, 0x1168, 0x609c, 0xa005, 0x0180, - 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x3e19, 0x203c, 0x87fb, - 0x090c, 0x243b, 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, 0x0005, - 0x2051, 0x0000, 0x0005, 0x0126, 0x0006, 0x00d6, 0x70d4, 0xa084, - 0x4c00, 0x8004, 0x2090, 0x00de, 0x008e, 0x7108, 0xa184, 0x0003, - 0x1128, 0x6828, 0xa005, 0x0178, 0x0804, 0x3d6c, 0x7108, 0xd1fc, - 0x0118, 0x080c, 0x3e9e, 0x0c88, 0x7007, 0x0010, 0x7108, 0xd1fc, - 0x0de8, 0x080c, 0x3e9e, 0x7008, 0xa086, 0x0008, 0x1d30, 0x7000, - 0xa005, 0x1d18, 0x7003, 0x0000, 0x2049, 0x0000, 0x012e, 0x2000, - 0x0005, 0x0126, 0x0146, 0x0136, 0x0156, 0x00c6, 0x00d6, 0x70d4, - 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x2049, 0x40b1, 0xad80, - 0x0011, 0x20a0, 0xb284, 0x0200, 0x0118, 0x2099, 0x0032, 0x0010, - 0x2099, 0x0031, 0x700c, 0xa084, 0x07ff, 0x682a, 0x7007, 0x0008, - 0x7007, 0x0002, 0x7003, 0x0001, 0x0118, 0x8000, 0x80ac, 0x53a5, - 0x700c, 0xa084, 0x07ff, 0x0130, 0x7007, 0x0004, 0x7004, 0xa084, - 0x0004, 0x1de0, 0x00ce, 0x2049, 0x0000, 0x7003, 0x0000, 0x015e, - 0x013e, 0x014e, 0x012e, 0x2000, 0x0005, 0x2091, 0x8000, 0x2091, - 0x6000, 0x78ac, 0xa005, 0x1168, 0x7974, 0x70d0, 0xa106, 0x1148, - 0x781c, 0xa005, 0x0130, 0x781f, 0x0000, 0x0e04, 0x4101, 0x2091, - 0x4080, 0x7830, 0x8001, 0x7832, 0x1904, 0x416b, 0x7834, 0x7832, - 0x2061, 0x68c0, 0x2069, 0x4380, 0xc7fd, 0x68d0, 0xa005, 0x0128, - 0x8001, 0x68d2, 0x1110, 0x080c, 0x42c4, 0x6800, 0xa084, 0x000f, - 0x0168, 0xa086, 0x0001, 0x0150, 0x6844, 0xa00d, 0x0138, 0x2104, - 0xa005, 0x0120, 0x8001, 0x200a, 0x0904, 0x425f, 0x6814, 0xa005, - 0x01a8, 0x8001, 0x6816, 0x1190, 0x68a7, 0x0001, 0x00f6, 0xd7fc, - 0x1118, 0x2079, 0x0200, 0x0010, 0x2079, 0x0100, 0x080c, 0x3aa0, - 0x00fe, 0x6864, 0xa005, 0x0110, 0x080c, 0x2233, 0x6880, 0xa005, - 0x0140, 0x8001, 0x6882, 0x1128, 0x6867, 0x0000, 0x68d4, 0xc0c5, - 0x68d6, 0x68d4, 0xd0fc, 0x01b0, 0xc0fc, 0x68d6, 0x20a9, 0x0200, - 0x6034, 0xa005, 0x0158, 0x8001, 0x6036, 0x68d4, 0xc0fd, 0x68d6, - 0x1128, 0x6010, 0xa005, 0x0110, 0x080c, 0x2233, 0xace0, 0x0010, - 0x1f04, 0x4150, 0xd7fc, 0x0138, 0x2061, 0x48c0, 0x2069, 0x4340, - 0xc7fc, 0x0804, 0x410d, 0x0459, 0x7838, 0x8001, 0x783a, 0x11a0, - 0x783c, 0x783a, 0x2061, 0x48c0, 0x2069, 0x4340, 0xc7fc, 0x680c, - 0xa005, 0x0110, 0x080c, 0x41c9, 0xd7fc, 0x1130, 0x2061, 0x68c0, - 0x2069, 0x4380, 0xc7fd, 0x0c98, 0x7810, 0xd0cc, 0x0168, 0xd0ac, - 0x1120, 0xd0a4, 0x0148, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0e04, - 0x4193, 0x080c, 0x1ffe, 0x0005, 0x2091, 0x8001, 0x0005, 0x7840, - 0x8001, 0x7842, 0x1568, 0x7844, 0x7842, 0x2091, 0x8000, 0x2061, - 0x48c0, 0x2069, 0x4340, 0xc7fc, 0x6810, 0xa005, 0x1110, 0x2001, - 0x0101, 0x8001, 0x6812, 0xd7fc, 0x0118, 0xa080, 0x89d0, 0x0010, - 0xa080, 0x88c0, 0x2040, 0x2004, 0xa065, 0x0150, 0x6024, 0xa005, - 0x0120, 0x8001, 0x6026, 0x0904, 0x4207, 0x6000, 0x2c40, 0x0ca0, - 0xd7fc, 0x1130, 0x2061, 0x68c0, 0x2069, 0x4380, 0xc7fd, 0x08e0, - 0x0005, 0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0540, - 0x6024, 0xa005, 0x0118, 0x8001, 0x6026, 0x0400, 0x6008, 0xc09c, - 0xd084, 0x1110, 0xd0ac, 0x01a8, 0x600a, 0x6004, 0xa06d, 0x01c0, - 0x00c6, 0x0016, 0x6010, 0x8001, 0x6012, 0x080c, 0x35ab, 0x2d00, - 0x2c68, 0x2060, 0x080c, 0x1b85, 0x080c, 0x1d30, 0x001e, 0x00ce, - 0x0038, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0010, 0xa18d, 0x0100, - 0xace0, 0x0010, 0x1f04, 0x41cd, 0xa184, 0x0001, 0x0130, 0xa18c, - 0xfffe, 0x690e, 0x080c, 0x2233, 0x0008, 0x690e, 0x0005, 0x6800, - 0xa005, 0x0120, 0x684c, 0xac06, 0x0904, 0x425f, 0x6864, 0xa005, - 0x0120, 0x6027, 0x0001, 0x0804, 0x425c, 0x2c00, 0x687e, 0x6714, - 0x6f76, 0x6017, 0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x60b4, - 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, - 0x6022, 0x6000, 0x2042, 0x080c, 0x1b1d, 0x6818, 0xa005, 0x0110, - 0x8001, 0x681a, 0x6808, 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, - 0x790a, 0x8001, 0x1310, 0x080c, 0x243b, 0x6812, 0x1118, 0x7910, - 0xc1a5, 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x080c, - 0x1d3d, 0xd7fc, 0x1118, 0x2069, 0x4340, 0x0010, 0x2069, 0x4380, - 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x1118, 0x697a, 0x2001, - 0x0004, 0x2708, 0x080c, 0x2228, 0x2091, 0x8001, 0x0005, 0x00d6, - 0x694c, 0x2160, 0xd7fc, 0x1118, 0x2069, 0x0200, 0x0010, 0x2069, - 0x0100, 0x080c, 0x23e1, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, - 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, - 0x0000, 0x6033, 0x0000, 0x6830, 0xd0b4, 0x01b0, 0x684b, 0x0004, - 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x4282, 0x684b, - 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04, 0x428b, - 0x20a9, 0x00fa, 0x1f04, 0x4292, 0x6808, 0xa084, 0xfffd, 0x680a, - 0x681b, 0x0054, 0x00de, 0x6867, 0x0007, 0x2091, 0x8001, 0x0005, - 0x2079, 0x4300, 0x00e1, 0x0089, 0x00a9, 0x2009, 0x0002, 0x2069, - 0x4380, 0x680f, 0x0000, 0x6813, 0x0000, 0x6817, 0x0000, 0x8109, - 0x0118, 0x2069, 0x4340, 0x0ca8, 0x0005, 0x2019, 0x00a3, 0x7b3a, - 0x7b3e, 0x0005, 0x2019, 0x0033, 0x7b42, 0x7b46, 0x0005, 0x2019, - 0x32dd, 0x7b32, 0x7b36, 0x0005, 0x6950, 0xa185, 0x0000, 0x0178, - 0x00c6, 0x6ac0, 0x2264, 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, - 0xc0b5, 0x600a, 0x8210, 0x8109, 0x1da8, 0x6952, 0x00ce, 0x0005, - 0x70ec, 0xd0dc, 0x1118, 0xd0d4, 0x0180, 0x0088, 0xae8e, 0x0100, - 0x0130, 0x7814, 0xc0f5, 0x7816, 0xd0d4, 0x1170, 0x0050, 0x7814, - 0xc0fd, 0x7816, 0xd0d4, 0x1140, 0x0020, 0xd0e4, 0x0138, 0x70a0, - 0x70a2, 0x7804, 0xd08c, 0x0110, 0x681f, 0x000c, 0x0005, 0xaf67 + 0x2049, 0x41ad, 0x6828, 0xa055, 0x00d6, 0x0904, 0x420e, 0x2d70, + 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x3f9a, 0x273c, 0x87fb, + 0x1140, 0x0210, 0x080c, 0x252b, 0x709c, 0xa075, 0x2060, 0x0570, + 0x0c80, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0268, + 0x8a51, 0x1110, 0x080c, 0x252b, 0x8738, 0x2704, 0xa005, 0x1d90, + 0x709c, 0xa075, 0x2060, 0x01d0, 0x08e0, 0x8422, 0x8420, 0x831a, + 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, + 0x1210, 0x080c, 0x252b, 0xb284, 0x0200, 0x0118, 0x2071, 0x0050, + 0x0010, 0x2071, 0x0020, 0x00de, 0x0804, 0x4141, 0x00de, 0x012e, + 0x2000, 0x0005, 0x7008, 0x0006, 0xa084, 0x01e0, 0x000e, 0x0110, + 0xa006, 0x0005, 0xa084, 0x0003, 0xa086, 0x0003, 0x1108, 0x0005, + 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, 0x701e, 0x7808, 0x7012, + 0x780c, 0x7016, 0x6004, 0xa084, 0x0008, 0x0120, 0x7810, 0x7022, + 0x7814, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, 0xc085, 0x7006, + 0x2079, 0x4500, 0x8a51, 0x01e8, 0x8738, 0x2704, 0xa005, 0x1168, + 0x609c, 0xa005, 0x01b8, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, + 0x3f9a, 0x203c, 0x87fb, 0x090c, 0x252b, 0x7008, 0x0006, 0xa084, + 0x01e0, 0x000e, 0x0110, 0xa006, 0x0028, 0xa084, 0x0003, 0xa086, + 0x0003, 0x0005, 0x2051, 0x0000, 0x0005, 0x0126, 0x0006, 0x00d6, + 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x008e, 0x7108, + 0xa184, 0x0003, 0x1128, 0x6828, 0xa005, 0x0178, 0x0804, 0x3ef3, + 0x7108, 0xd1fc, 0x0118, 0x080c, 0x4053, 0x0c88, 0x7007, 0x0010, + 0x7108, 0xd1fc, 0x0de8, 0x080c, 0x4053, 0x7008, 0xa086, 0x0008, + 0x1d30, 0x7000, 0xa005, 0x1d18, 0x7003, 0x0000, 0x2049, 0x0000, + 0x012e, 0x2000, 0x0005, 0x0126, 0x0146, 0x0136, 0x0156, 0x00c6, + 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x2049, + 0x428b, 0xad80, 0x0011, 0x20a0, 0xb284, 0x0200, 0x0118, 0x2099, + 0x0032, 0x0010, 0x2099, 0x0031, 0x700c, 0xa084, 0x07ff, 0x682a, + 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0118, 0x8000, + 0x80ac, 0x53a5, 0x700c, 0xa084, 0x07ff, 0x0130, 0x7007, 0x0004, + 0x7004, 0xa084, 0x0004, 0x1de0, 0x00ce, 0x2049, 0x0000, 0x7003, + 0x0000, 0x015e, 0x013e, 0x014e, 0x012e, 0x2000, 0x0005, 0x2091, + 0x8000, 0x2091, 0x6000, 0x78ac, 0xa005, 0x1168, 0x7974, 0x70d0, + 0xa106, 0x1148, 0x781c, 0xa005, 0x0130, 0x781f, 0x0000, 0x0e04, + 0x42db, 0x2091, 0x4080, 0x7830, 0x8001, 0x7832, 0x1904, 0x4345, + 0x7834, 0x7832, 0x2061, 0x6ac0, 0x2069, 0x4580, 0xc7fd, 0x68cc, + 0xa005, 0x0128, 0x8001, 0x68ce, 0x1110, 0x080c, 0x44ad, 0x6800, + 0xa084, 0x000f, 0x0168, 0xa086, 0x0001, 0x0150, 0x6840, 0xa00d, + 0x0138, 0x2104, 0xa005, 0x0120, 0x8001, 0x200a, 0x0904, 0x444a, + 0x6814, 0xa005, 0x01a8, 0x8001, 0x6816, 0x1190, 0x68a3, 0x0001, + 0x00f6, 0xd7fc, 0x1118, 0x2079, 0x0200, 0x0010, 0x2079, 0x0100, + 0x080c, 0x3c0c, 0x00fe, 0x6860, 0xa005, 0x0110, 0x080c, 0x2296, + 0x687c, 0xa005, 0x0140, 0x8001, 0x687e, 0x1128, 0x6863, 0x0000, + 0x68d0, 0xc0c5, 0x68d2, 0x68d0, 0xd0fc, 0x01b0, 0xc0fc, 0x68d2, + 0x20a9, 0x0200, 0x6034, 0xa005, 0x0158, 0x8001, 0x6036, 0x68d0, + 0xc0fd, 0x68d2, 0x1128, 0x6010, 0xa005, 0x0110, 0x080c, 0x2296, + 0xace0, 0x0010, 0x1f04, 0x432a, 0xd7fc, 0x0138, 0x2061, 0x4ac0, + 0x2069, 0x4540, 0xc7fc, 0x0804, 0x42e7, 0x0459, 0x7838, 0x8001, + 0x783a, 0x11a0, 0x783c, 0x783a, 0x2061, 0x4ac0, 0x2069, 0x4540, + 0xc7fc, 0x680c, 0xa005, 0x0110, 0x080c, 0x43c1, 0xd7fc, 0x1130, + 0x2061, 0x6ac0, 0x2069, 0x4580, 0xc7fd, 0x0c98, 0x7810, 0xd0cc, + 0x0168, 0xd0ac, 0x1120, 0xd0a4, 0x0148, 0xc0ad, 0x7812, 0x2091, + 0x8001, 0x0e04, 0x436d, 0x080c, 0x2061, 0x0005, 0x2091, 0x8001, + 0x0005, 0x7840, 0x8001, 0x7842, 0x1904, 0x43c0, 0x7844, 0x7842, + 0x2069, 0x4540, 0xc7fc, 0x2079, 0x0200, 0x68d4, 0xa005, 0x0138, + 0x7de0, 0xa504, 0x1120, 0x68d6, 0x68d0, 0xc0bc, 0x68d2, 0x2079, + 0x4500, 0x6810, 0xa005, 0x1110, 0x2001, 0x0101, 0x8001, 0x6812, + 0xd7fc, 0x0118, 0xa080, 0x8bd0, 0x0010, 0xa080, 0x8ac0, 0x2040, + 0x2004, 0xa065, 0x01e0, 0x6024, 0xa005, 0x01b0, 0x8001, 0x6026, + 0x1198, 0x6800, 0xa005, 0x0130, 0x6848, 0xac06, 0x1118, 0x080c, + 0x444a, 0x0068, 0x6860, 0xa005, 0x0118, 0x6027, 0x0001, 0x0020, + 0x080c, 0x4402, 0x2804, 0x0c28, 0x6000, 0x2c40, 0x0c10, 0xd7fc, + 0x1138, 0x2069, 0x4580, 0xc7fd, 0x2079, 0x0100, 0x0804, 0x437d, + 0x0005, 0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0558, + 0x6024, 0xa005, 0x0118, 0x8001, 0x6026, 0x0418, 0x6008, 0xc09c, + 0xd084, 0x1110, 0xd0ac, 0x01c0, 0x600a, 0x6004, 0xa005, 0x01d8, + 0x00d6, 0x00c6, 0x0016, 0x2068, 0x6010, 0x8001, 0x6012, 0x080c, + 0x376c, 0x2d00, 0x2c68, 0x2060, 0x080c, 0x1bc7, 0x080c, 0x1d7c, + 0x001e, 0x00ce, 0x00de, 0x0038, 0xc0bd, 0x600a, 0xa18d, 0x0001, + 0x0010, 0xa18d, 0x0100, 0xace0, 0x0010, 0x1f04, 0x43c5, 0xa184, + 0x0001, 0x0130, 0xa18c, 0xfffe, 0x690e, 0x080c, 0x2296, 0x0008, + 0x690e, 0x0005, 0x2c00, 0x687a, 0x6714, 0x6f72, 0x6017, 0x0000, + 0x602b, 0x0000, 0x601b, 0x0006, 0x60b4, 0xa084, 0x5f00, 0x601e, + 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, + 0x080c, 0x1b5f, 0x6818, 0xa005, 0x0110, 0x8001, 0x681a, 0x6808, + 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x1310, + 0x080c, 0x252b, 0x6812, 0x1118, 0x7910, 0xc1a5, 0x7912, 0x602f, + 0x0000, 0x6033, 0x0000, 0x2c68, 0x080c, 0x1d89, 0xd7fc, 0x1118, + 0x2069, 0x4540, 0x0010, 0x2069, 0x4580, 0x6910, 0xa184, 0x0100, + 0x2001, 0x0006, 0x1118, 0x6976, 0x2001, 0x0004, 0x2708, 0x080c, + 0x228b, 0x0005, 0x00d6, 0x6948, 0x2160, 0xd7fc, 0x1118, 0x2069, + 0x0200, 0x0010, 0x2069, 0x0100, 0x080c, 0x2446, 0x601b, 0x0006, + 0x6858, 0xa084, 0x5f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, + 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6808, 0xa084, + 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x01b0, 0x684b, 0x0004, 0x20a9, + 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x4471, 0x684b, 0x0009, + 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04, 0x447a, 0x20a9, + 0x00fa, 0x1f04, 0x4481, 0x681b, 0x0054, 0x00de, 0x6863, 0x0007, + 0x0005, 0x2079, 0x4500, 0x00e1, 0x0089, 0x00a9, 0x2009, 0x0002, + 0x2069, 0x4580, 0x680f, 0x0000, 0x6813, 0x0000, 0x6817, 0x0000, + 0x8109, 0x0118, 0x2069, 0x4540, 0x0ca8, 0x0005, 0x2019, 0x00a3, + 0x7b3a, 0x7b3e, 0x0005, 0x2019, 0x0033, 0x7b42, 0x7b46, 0x0005, + 0x2019, 0x32dd, 0x7b32, 0x7b36, 0x0005, 0x694c, 0xa185, 0x0000, + 0x0158, 0x00c6, 0x6abc, 0x2264, 0x6008, 0xc0b5, 0x600a, 0x8210, + 0x8109, 0x1dc8, 0x694e, 0x00ce, 0x0005, 0x70ec, 0xd0dc, 0x1118, + 0xd0d4, 0x0190, 0x0098, 0xae8e, 0x0100, 0x0138, 0x7814, 0xc0f5, + 0xc0c5, 0x7816, 0xd0d4, 0x11a8, 0x0088, 0x7814, 0xc0fd, 0xc0c5, + 0x7816, 0xd0d4, 0x1170, 0x0050, 0xd0e4, 0x0168, 0x70e4, 0xa084, + 0x01ff, 0xa086, 0x01ff, 0x0d38, 0x70a0, 0x70a2, 0x7804, 0xd08c, + 0x0110, 0x681f, 0x000c, 0x0005, 0x69ca }; #ifdef UNIQUE_FW_NAME -unsigned short fw12160i_length01 = 0x32f8; +unsigned short fw12160i_length01 = 0x34e5; #else -unsigned short risc_code_length01 = 0x32f8; +unsigned short risc_code_length01 = 0x34e5; #endif diff -Nur linux-2.4.19/drivers/scsi/ql1280_fw.h linux-2.4.19-sgi211r3/drivers/scsi/ql1280_fw.h --- linux-2.4.19/drivers/scsi/ql1280_fw.h Mon Feb 7 19:45:28 2000 +++ linux-2.4.19-sgi211r3/drivers/scsi/ql1280_fw.h Tue Jan 8 17:05:38 2002 @@ -1,59 +1,117 @@ /************************************************************************ + * * + * --- ISP1240/1080/1280 Initiator Firmware --- * + * 32 LUN Support * + * * + ************************************************************************ - * Copyright (C) 1999,2000 Qlogic, Corporation. + + * * + + * Copyright (C) 1999,2000 Qlogic, Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted provided + * that the following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. - * 2. The name of the author may not be used to endorse or promote products + + * 2. Redistribution 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. 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 ``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 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. + * * + ************************************************************************ + */ /* - * Firmware Version 8.09.00 (18:29 Apr 16, 1999) + * Firmware Version 8.13.08 (10:53 Jan 14, 2000) */ -unsigned short fw1280ei_version = 8*1024+9; +#ifdef UNIQUE_FW_NAME +unsigned short fw1280ei_version = 8*1024+13; +#else +unsigned short risc_code_version = 8*1024+13; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw1280ei_version_str[] = {8,13,8}; +#else +unsigned char firmware_version[] = {8,13,8}; +#endif -unsigned char fw1280ei_version_str[] = {8,9,0}; +#ifdef UNIQUE_FW_NAME +#define fw1280ei_VERSION_STRING "8.13.8" +#else +#define FW_VERSION_STRING "8.13.8" +#endif +#ifdef UNIQUE_FW_NAME unsigned short fw1280ei_addr01 = 0x1000 ; +#else +unsigned short risc_code_addr01 = 0x1000 ; +#endif +#ifdef UNIQUE_FW_NAME unsigned short fw1280ei_code01[] = { - 0x0078, 0x1041, 0x0000, 0x39e3, 0x0000, 0x2043, 0x4f50, 0x5952, +#else +unsigned short risc_code01[] = { +#endif + 0x0078, 0x1041, 0x0000, 0x3c71, 0x0000, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, 0x3132, 0x3430, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, - 0x6572, 0x7369, 0x6f6e, 0x2030, 0x382e, 0x3039, 0x2020, 0x2043, + 0x6572, 0x7369, 0x6f6e, 0x2030, 0x382e, 0x3133, 0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, - 0x2400, 0x20c9, 0x93ff, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1080, + 0x2400, 0x20c9, 0x96ff, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1080, 0x00c0, 0x1054, 0x2071, 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, - 0x2089, 0x136a, 0x0078, 0x106d, 0x2001, 0x04fc, 0x2004, 0xa086, + 0x2089, 0x1374, 0x0078, 0x106d, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1280, 0x00c0, 0x1069, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2071, - 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, 0x2089, 0x13ea, 0x0078, - 0x106d, 0x20c1, 0x0020, 0x2089, 0x1312, 0x2071, 0x0010, 0x70c3, + 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, 0x2089, 0x13f8, 0x0078, + 0x106d, 0x20c1, 0x0020, 0x2089, 0x131c, 0x2071, 0x0010, 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0008, 0x2001, 0x04fe, 0x70d6, 0x20c1, 0x0021, 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, @@ -61,1838 +119,1924 @@ 0xa286, 0xa5a5, 0x0040, 0x10a4, 0xa386, 0x000f, 0x0040, 0x10a0, 0x2c6a, 0x2a5a, 0x20c1, 0x0020, 0x2019, 0x000f, 0x0078, 0x1080, 0x2c6a, 0x2a5a, 0x0078, 0x10a2, 0x2c6a, 0x2a5a, 0x2130, 0x2128, - 0xa1a2, 0x4a00, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, - 0xa192, 0x9400, 0x2009, 0x0000, 0x2001, 0x0032, 0x1078, 0x2078, - 0x2218, 0x2079, 0x4a00, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, - 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10bf, 0x2001, 0x04fc, 0x2004, - 0xa086, 0x1080, 0x00c0, 0x10db, 0x2071, 0x0100, 0x0d7e, 0x2069, - 0x4a40, 0x1078, 0x49ae, 0x0d7f, 0x7810, 0xc0ed, 0x7812, 0x781b, - 0x0064, 0x0078, 0x1100, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1280, - 0x00c0, 0x10fb, 0x7814, 0xc0ed, 0xc0d5, 0x7816, 0x781b, 0x0064, - 0x2071, 0x0200, 0x0d7e, 0x2069, 0x4a40, 0x1078, 0x49ae, 0x2069, - 0x4a80, 0x2071, 0x0100, 0x1078, 0x49ae, 0x7814, 0xc0d4, 0x7816, - 0x0d7f, 0x0078, 0x1100, 0x7814, 0xc0e5, 0x7816, 0x781b, 0x003c, - 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802, - 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002, - 0x2009, 0x0002, 0x2069, 0x4a40, 0x681b, 0x0003, 0x6823, 0x0007, - 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0000, - 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, 0x8109, 0x0040, - 0x1154, 0x68d3, 0x000a, 0x68c3, 0x4ac0, 0x2079, 0x4a00, 0x7814, - 0xd0e4, 0x00c0, 0x113a, 0xd0ec, 0x00c0, 0x113e, 0x68d7, 0x7329, - 0x0078, 0x1140, 0x68d7, 0x730d, 0x0078, 0x1140, 0x68d7, 0x7329, - 0x68c7, 0x4fc0, 0x68cb, 0x4ec0, 0x68cf, 0x8fc0, 0x68ab, 0x9244, - 0x68af, 0x9249, 0x68b3, 0x9244, 0x68b7, 0x9244, 0x68a7, 0x0001, - 0x2069, 0x4a80, 0x0078, 0x1114, 0x68d3, 0x000a, 0x68c3, 0x4cc0, - 0x7814, 0xd0e4, 0x00c0, 0x1160, 0x68d7, 0x7439, 0x0078, 0x1162, - 0x68d7, 0x7419, 0x68c7, 0x6fc0, 0x68cb, 0x4f40, 0x68cf, 0x90d0, - 0x68ab, 0x9249, 0x68af, 0x924e, 0x68b3, 0x9249, 0x68b7, 0x9249, - 0x68a7, 0x0001, 0x7810, 0xd0ec, 0x00c0, 0x11b8, 0x7814, 0xd0e4, - 0x00c0, 0x11aa, 0x0e7e, 0x2069, 0x4ec0, 0x2071, 0x0200, 0x70ec, - 0xd0e4, 0x00c0, 0x118b, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, - 0x2007, 0x0078, 0x1191, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, - 0x2007, 0x2069, 0x4f40, 0x2071, 0x0100, 0x70ec, 0xd0e4, 0x00c0, - 0x11a1, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, 0x2007, 0x0078, - 0x11a7, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, 0x2007, 0x0e7f, - 0x0078, 0x11d1, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x2069, 0x4ec0, - 0x1078, 0x2007, 0x2069, 0x4f40, 0x1078, 0x2007, 0x0078, 0x11d1, - 0x2069, 0x4ec0, 0x0e7e, 0x2071, 0x0100, 0x70ec, 0xd0e4, 0x00c0, - 0x11ca, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, 0x2007, 0x0e7f, - 0x0078, 0x11d1, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, 0x2007, - 0x0e7f, 0x2011, 0x0002, 0x2069, 0x4fc0, 0x2009, 0x0002, 0x20a9, - 0x0100, 0x683f, 0x0000, 0x680b, 0x0040, 0x7bc8, 0xa386, 0xfeff, - 0x00c0, 0x11e8, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x11ec, - 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x00f0, 0x11d9, - 0x8109, 0x00c0, 0x11d7, 0x8211, 0x0040, 0x11fa, 0x2069, 0x6fc0, - 0x0078, 0x11d5, 0x1078, 0x2611, 0x1078, 0x441d, 0x1078, 0x1df2, - 0x1078, 0x4957, 0x2091, 0x2100, 0x2079, 0x4a00, 0x7810, 0xd0ec, - 0x0040, 0x120e, 0x2071, 0x0020, 0x0078, 0x1210, 0x2071, 0x0050, - 0x2091, 0x2200, 0x2079, 0x4a00, 0x2071, 0x0020, 0x2091, 0x2300, - 0x2079, 0x4a00, 0x7810, 0xd0ec, 0x0040, 0x1222, 0x2079, 0x0100, - 0x0078, 0x1224, 0x2079, 0x0200, 0x2071, 0x4a40, 0x2091, 0x2400, - 0x2079, 0x0100, 0x2071, 0x4a80, 0x2091, 0x2000, 0x2079, 0x4a00, - 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, 0x2071, 0x0010, - 0x70c3, 0x0000, 0x0090, 0x1243, 0x70c0, 0xa086, 0x0002, 0x00c0, - 0x1243, 0x1078, 0x159d, 0x2039, 0x0000, 0x7810, 0xd0ec, 0x00c0, - 0x12c5, 0x1078, 0x1472, 0x78ac, 0xa005, 0x00c0, 0x1261, 0x0068, - 0x1257, 0x786c, 0xa065, 0x0040, 0x1257, 0x1078, 0x2368, 0x1078, - 0x209f, 0x0068, 0x126e, 0x786c, 0xa065, 0x0040, 0x1261, 0x1078, - 0x2368, 0x0068, 0x126e, 0x2009, 0x4a47, 0x2011, 0x4a87, 0x2104, - 0x220c, 0xa105, 0x0040, 0x126e, 0x1078, 0x1f1e, 0x2071, 0x4a40, - 0x70a4, 0xa005, 0x0040, 0x1293, 0x7450, 0xa485, 0x0000, 0x0040, - 0x1293, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, 0xa28c, 0x303d, - 0x2190, 0x1078, 0x2a9c, 0x2091, 0x8000, 0x2091, 0x303d, 0x0068, - 0x1293, 0x2079, 0x4a00, 0x786c, 0xa065, 0x0040, 0x1293, 0x2071, - 0x0010, 0x1078, 0x2368, 0x00e0, 0x129b, 0x2079, 0x4a00, 0x2071, - 0x0010, 0x1078, 0x4765, 0x2071, 0x4a80, 0x70a4, 0xa005, 0x0040, - 0x12b3, 0x7050, 0xa025, 0x0040, 0x12b3, 0x2079, 0x0100, 0x2091, - 0x8000, 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, 0x2a9c, 0x2091, - 0x8000, 0x2091, 0x303d, 0x2079, 0x4a00, 0x2071, 0x0010, 0x0068, - 0x12bf, 0x786c, 0xa065, 0x0040, 0x12bf, 0x1078, 0x2368, 0x00e0, - 0x1249, 0x1078, 0x4765, 0x0078, 0x1249, 0x1078, 0x1472, 0x78ac, - 0xa005, 0x00c0, 0x12dd, 0x0068, 0x12d3, 0x786c, 0xa065, 0x0040, - 0x12d3, 0x1078, 0x2368, 0x1078, 0x209f, 0x0068, 0x12e7, 0x786c, - 0xa065, 0x0040, 0x12dd, 0x1078, 0x2368, 0x0068, 0x12e7, 0x2009, - 0x4a47, 0x2104, 0xa005, 0x0040, 0x12e7, 0x1078, 0x1f1e, 0x2071, - 0x4a40, 0x70a4, 0xa005, 0x0040, 0x1302, 0x7450, 0xa485, 0x0000, - 0x0040, 0x1302, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d4, 0xa28c, - 0x303d, 0x2190, 0x1078, 0x2a9c, 0x2091, 0x8000, 0x2091, 0x303d, - 0x2079, 0x4a00, 0x2071, 0x0010, 0x0068, 0x130c, 0x786c, 0xa065, - 0x0040, 0x130c, 0x1078, 0x2368, 0x00e0, 0x12c5, 0x1078, 0x4765, - 0x0078, 0x12c5, 0x1332, 0x1332, 0x1334, 0x1334, 0x1341, 0x1341, - 0x1341, 0x1341, 0x134c, 0x134c, 0x1359, 0x1359, 0x1341, 0x1341, - 0x1341, 0x1341, 0x1332, 0x1332, 0x1334, 0x1334, 0x1341, 0x1341, - 0x1341, 0x1341, 0x134c, 0x134c, 0x1359, 0x1359, 0x1341, 0x1341, - 0x1341, 0x1341, 0x0078, 0x1332, 0x007e, 0x107e, 0x127e, 0x2091, - 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, - 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13ba, 0x127f, 0x107f, - 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, - 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, - 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x290b, - 0x2091, 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, - 0x8001, 0x007c, 0x138a, 0x138a, 0x138c, 0x138c, 0x1399, 0x1399, - 0x1399, 0x1399, 0x13a4, 0x13a4, 0x138c, 0x138c, 0x1399, 0x1399, - 0x1399, 0x1399, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, - 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, - 0x13a5, 0x13a5, 0x0078, 0x138a, 0x007e, 0x107e, 0x127e, 0x2091, - 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, - 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13c7, 0x127f, 0x107f, - 0x007f, 0x2091, 0x8001, 0x007c, 0x007c, 0x107e, 0x127e, 0x0d7e, - 0x0e7e, 0x0f7e, 0x007e, 0x2071, 0x0100, 0x2069, 0x4a40, 0x2079, - 0x4a00, 0x1078, 0x49ae, 0x007f, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, - 0x107f, 0x007c, 0x3c00, 0xa084, 0x0007, 0x0079, 0x13bf, 0x13d0, - 0x13d0, 0x13d2, 0x13d2, 0x13d7, 0x13d7, 0x13dc, 0x13dc, 0x3c00, - 0xa084, 0x0003, 0x0079, 0x13cc, 0x13d0, 0x13d0, 0x13e5, 0x13e5, - 0x1078, 0x28ec, 0x2091, 0x2200, 0x1078, 0x44b7, 0x007c, 0x2091, - 0x2100, 0x1078, 0x44b7, 0x007c, 0x2091, 0x2100, 0x1078, 0x44b7, - 0x2091, 0x2200, 0x1078, 0x44b7, 0x007c, 0x2091, 0x2100, 0x1078, - 0x44b7, 0x007c, 0x140a, 0x140a, 0x140c, 0x140c, 0x1419, 0x1419, - 0x1419, 0x1419, 0x1424, 0x1424, 0x1431, 0x1431, 0x1419, 0x1419, - 0x1419, 0x1419, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, - 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, - 0x1442, 0x1442, 0x0078, 0x140a, 0x007e, 0x107e, 0x127e, 0x2091, - 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, - 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13ba, 0x127f, 0x107f, - 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, - 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, - 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x290b, - 0x2091, 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, - 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, - 0x2079, 0x4a00, 0x2071, 0x0200, 0x2069, 0x4a40, 0x3d00, 0xd08c, - 0x00c0, 0x1456, 0x2069, 0x4a80, 0x2071, 0x0100, 0x1078, 0x49ae, - 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, 0x107f, 0x007f, 0x007c, 0x7008, - 0x800b, 0x00c8, 0x146d, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, - 0x146e, 0xd09c, 0x0040, 0x146d, 0x087a, 0x097a, 0x70c3, 0x4002, - 0x0078, 0x15a0, 0x0068, 0x14f7, 0x2061, 0x0000, 0x6018, 0xd084, - 0x00c0, 0x14f7, 0x7828, 0xa005, 0x00c0, 0x1482, 0x0010, 0x14f8, - 0x0078, 0x14f7, 0x7910, 0xd1f4, 0x0040, 0x148a, 0x2001, 0x4007, - 0x0078, 0x159f, 0x7914, 0xd1ec, 0x0040, 0x14a5, 0xd0fc, 0x0040, - 0x149b, 0x007e, 0x1078, 0x1d82, 0x007f, 0x0040, 0x14a5, 0x2001, - 0x4007, 0x0078, 0x159f, 0x007e, 0x1078, 0x1d72, 0x007f, 0x0040, - 0x14a5, 0x2001, 0x4007, 0x0078, 0x159f, 0x7910, 0xd0fc, 0x00c0, - 0x14af, 0x2061, 0x4a40, 0xc19c, 0xc7fc, 0x0078, 0x14b3, 0x2061, - 0x4a80, 0xc19d, 0xc7fd, 0x6064, 0xa005, 0x00c0, 0x14f7, 0x7912, - 0x6083, 0x0000, 0x7828, 0xc0fc, 0xa086, 0x0018, 0x00c0, 0x14c4, - 0x0c7e, 0x1078, 0x1b13, 0x0c7f, 0x782b, 0x0000, 0x607c, 0xa065, - 0x0040, 0x14dd, 0x0c7e, 0x609c, 0x1078, 0x1e5d, 0x0c7f, 0x609f, - 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, 0x6087, 0x0103, 0x1078, - 0x1d92, 0x00c0, 0x14f1, 0x1078, 0x1de4, 0x7810, 0xd09c, 0x00c0, - 0x14e5, 0x2061, 0x4a40, 0x0078, 0x14e9, 0x2061, 0x4a80, 0xc09c, - 0x7812, 0x607f, 0x0000, 0x60d4, 0xd0dc, 0x0040, 0x14f5, 0xc0dc, - 0x60d6, 0x2001, 0x4005, 0x0078, 0x159f, 0x0078, 0x159d, 0x007c, - 0x7810, 0xd0f4, 0x0040, 0x1500, 0x2001, 0x4007, 0x0078, 0x159f, - 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, 0xa08a, - 0x0040, 0x00c8, 0x150d, 0x0079, 0x1514, 0x2100, 0xa08a, 0x0040, - 0x00c8, 0x15ab, 0x0079, 0x1554, 0x159d, 0x15f3, 0x15bc, 0x162b, - 0x1663, 0x1663, 0x15b3, 0x1c57, 0x166e, 0x15ab, 0x15c0, 0x15c2, - 0x15c4, 0x15c6, 0x1c5c, 0x15ab, 0x167c, 0x16d4, 0x1b35, 0x1c51, - 0x15c8, 0x19a7, 0x19e9, 0x1a1f, 0x1a6b, 0x1962, 0x196f, 0x1983, - 0x1996, 0x17a4, 0x1cdc, 0x1706, 0x1713, 0x171f, 0x172b, 0x1741, - 0x174d, 0x1750, 0x175c, 0x1768, 0x1770, 0x178c, 0x1798, 0x15ab, - 0x15ab, 0x15ab, 0x15ab, 0x17b1, 0x17c3, 0x17df, 0x1815, 0x183d, - 0x184d, 0x1850, 0x1881, 0x18b2, 0x18c4, 0x1931, 0x1941, 0x1d32, - 0x15ab, 0x15ab, 0x15ab, 0x1951, 0x15ab, 0x15ab, 0x15ab, 0x15ab, - 0x15ab, 0x1c81, 0x1c87, 0x15ab, 0x15ab, 0x15ab, 0x1c8b, 0x1cd8, - 0x15ab, 0x15ab, 0x1ce8, 0x1cf7, 0x15ed, 0x165d, 0x1676, 0x16ce, - 0x1b2f, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x1d39, 0x1c73, 0x1c7d, - 0x15ab, 0x15ab, 0x1d02, 0x1d1b, 0x15ab, 0x15ab, 0x15ab, 0x15ab, - 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, - 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, - 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, - 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x72ca, 0x71c6, 0x2001, 0x4006, - 0x0078, 0x159f, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, - 0x0068, 0x15a0, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, - 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001, 0x0078, 0x15a0, 0x70c3, - 0x4006, 0x0078, 0x15a0, 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, - 0x0005, 0x53a3, 0x0078, 0x159d, 0x70c4, 0x70c3, 0x0004, 0x007a, - 0x0078, 0x159d, 0x0078, 0x159d, 0x0078, 0x159d, 0x0078, 0x159d, - 0x2091, 0x8000, 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, - 0x70cf, 0x2020, 0x70d3, 0x0008, 0x2001, 0x0009, 0x70d6, 0x2079, - 0x0000, 0x781b, 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, - 0x041a, 0x2051, 0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, - 0x5000, 0x2091, 0x4080, 0x0078, 0x0418, 0x75d8, 0x74dc, 0x75da, - 0x74de, 0x0078, 0x15f6, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, - 0x73cc, 0x70c4, 0x20a0, 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, - 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, - 0x0040, 0x159d, 0xa182, 0x0040, 0x00c8, 0x1610, 0x2120, 0xa006, - 0x2008, 0x8403, 0x7012, 0x7007, 0x0004, 0x7007, 0x0001, 0x7008, - 0xd0fc, 0x0040, 0x1617, 0x7007, 0x0002, 0xa084, 0x01e0, 0x0040, - 0x1625, 0x70c3, 0x4002, 0x0078, 0x15a0, 0x24a8, 0x53a5, 0x0078, - 0x1607, 0x0078, 0x159d, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, - 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x7007, - 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x7007, - 0x0006, 0x81ff, 0x0040, 0x159d, 0xa182, 0x0040, 0x00c8, 0x164a, - 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, - 0x0001, 0x7008, 0xd0fc, 0x0040, 0x1651, 0xa084, 0x01e0, 0x0040, - 0x163f, 0x70c3, 0x4002, 0x0078, 0x15a0, 0x75d8, 0x74dc, 0x75da, - 0x74de, 0x0078, 0x162e, 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, - 0x00c0, 0x166b, 0x200a, 0x72ca, 0x0078, 0x159c, 0x70c7, 0x0008, - 0x70cb, 0x0009, 0x70cf, 0x0000, 0x0078, 0x159d, 0x75d8, 0x76dc, - 0x75da, 0x76de, 0x0078, 0x167f, 0x2029, 0x0000, 0x2530, 0x70c4, - 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, - 0x0040, 0x16c9, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0040, 0x1697, - 0x78ac, 0xc085, 0x78ae, 0x2001, 0x4005, 0x0078, 0x159f, 0x7b7e, - 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00, 0x0040, 0x16af, - 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f, 0xa118, 0xa291, - 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0078, 0x16b9, 0x8407, - 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, - 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, 0x0040, 0x16c3, - 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae, 0x0078, - 0x16cc, 0x78ac, 0xc085, 0x78ae, 0x0078, 0x159d, 0x75d8, 0x76dc, - 0x75da, 0x76de, 0x0078, 0x16d7, 0x2029, 0x0000, 0x2530, 0x70c4, - 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, - 0x0040, 0x1701, 0x8001, 0x7892, 0xa084, 0xfc00, 0x0040, 0x16ef, - 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0078, 0x159f, 0x7a9a, - 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0040, 0x16fa, 0x7a10, - 0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0078, - 0x1704, 0x78ac, 0xc0c5, 0x78ae, 0x0078, 0x159d, 0x2009, 0x0000, - 0x786c, 0xa065, 0x0040, 0x1710, 0x8108, 0x6000, 0x0078, 0x1709, - 0x7ac4, 0x0078, 0x159b, 0x2009, 0x4a48, 0x210c, 0x7810, 0xd0ec, - 0x00c0, 0x159c, 0x2011, 0x4a88, 0x2214, 0x0078, 0x159b, 0x2009, - 0x4a49, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2011, 0x4a89, - 0x2214, 0x0078, 0x159b, 0x2061, 0x4a40, 0x6128, 0x622c, 0x8214, - 0x8214, 0x8214, 0x7810, 0xd0ec, 0x00c0, 0x173f, 0x2061, 0x4a80, - 0x6328, 0x73da, 0x632c, 0x831c, 0x831c, 0x831c, 0x73de, 0x0078, - 0x159b, 0x2009, 0x4a4c, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, - 0x2011, 0x4a8c, 0x2214, 0x0078, 0x159b, 0x7918, 0x0078, 0x159c, - 0x2009, 0x4a4d, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2011, - 0x4a8d, 0x2214, 0x0078, 0x159b, 0x2009, 0x4a4e, 0x210c, 0x7810, - 0xd0ec, 0x00c0, 0x159c, 0x2011, 0x4a8e, 0x2214, 0x0078, 0x159b, - 0x7920, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x7a24, 0x0078, 0x159b, - 0x71c4, 0xd1fc, 0x00c0, 0x1778, 0x2011, 0x4ec0, 0x0078, 0x177a, - 0x2011, 0x4f40, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, - 0xa268, 0x6a00, 0x6804, 0xd09c, 0x0040, 0x1789, 0x6b08, 0x0078, - 0x178a, 0x6b0c, 0x0078, 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, - 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x159a, - 0x2061, 0x4a40, 0x6118, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2061, - 0x4a80, 0x6218, 0x0078, 0x159b, 0x77c4, 0x1078, 0x1e02, 0x2091, - 0x8000, 0x6908, 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0078, - 0x159a, 0x71c4, 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x00c8, - 0x1595, 0x1078, 0x2729, 0xa384, 0x4000, 0x0040, 0x17c1, 0xa295, - 0x0020, 0x0078, 0x159a, 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, - 0x00c8, 0x1595, 0xd1bc, 0x00c0, 0x17d2, 0x2011, 0x4a48, 0x2204, - 0x0078, 0x17d6, 0x2011, 0x4a88, 0x2204, 0xc0bd, 0x007e, 0x2100, - 0xc0bc, 0x2012, 0x1078, 0x2686, 0x017f, 0x0078, 0x159c, 0x71c4, - 0x2021, 0x4a49, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0078, 0x17ee, - 0x71c8, 0x2021, 0x4a89, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x180d, - 0x20a9, 0x0008, 0x2204, 0xa106, 0x0040, 0x17fd, 0x8210, 0x00f0, - 0x17f2, 0x71c4, 0x72c8, 0x0078, 0x1594, 0xa292, 0x180d, 0x027e, - 0x2122, 0x017f, 0x1078, 0x26a7, 0x7810, 0xd0ec, 0x00c0, 0x180b, - 0xd3fc, 0x0040, 0x17e8, 0x0078, 0x159d, 0x03e8, 0x00fa, 0x01f4, - 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x4a40, 0x6128, - 0x622c, 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, - 0x8003, 0x8003, 0x602e, 0x7810, 0xd0ec, 0x00c0, 0x183b, 0x027e, - 0x017e, 0x2061, 0x4a80, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, - 0x70d8, 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, - 0x72de, 0x017f, 0x027f, 0x0078, 0x159b, 0x2061, 0x4a40, 0x6130, - 0x70c4, 0x6032, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2061, 0x4a80, - 0x6230, 0x70c8, 0x6032, 0x0078, 0x159b, 0x7918, 0x0078, 0x159c, - 0x71c4, 0xa184, 0xffcf, 0x0040, 0x185c, 0x7810, 0xd0ec, 0x00c0, - 0x1595, 0x72c8, 0x0078, 0x1594, 0x2011, 0x4a4d, 0x2204, 0x2112, - 0x007e, 0x2019, 0x0000, 0x1078, 0x270e, 0x7810, 0xd0ec, 0x0040, - 0x186c, 0x017f, 0x0078, 0x159c, 0x71c8, 0xa184, 0xffcf, 0x0040, - 0x1875, 0x2110, 0x71c4, 0x0078, 0x1594, 0x2011, 0x4a8d, 0x2204, - 0x2112, 0x007e, 0xc3fd, 0x1078, 0x270e, 0x027f, 0x017f, 0x0078, - 0x159b, 0x71c4, 0xa182, 0x0010, 0x0048, 0x188d, 0x7810, 0xd0ec, - 0x00c0, 0x1595, 0x72c8, 0x0078, 0x1594, 0x2011, 0x4a4e, 0x2204, - 0x007e, 0x2112, 0x2019, 0x0000, 0x1078, 0x26ec, 0x7810, 0xd0ec, - 0x0040, 0x189d, 0x017f, 0x0078, 0x159c, 0x71c8, 0xa182, 0x0010, - 0x0048, 0x18a6, 0x2110, 0x71c4, 0x0078, 0x1594, 0x2011, 0x4a8e, - 0x2204, 0x007e, 0x2112, 0xc3fd, 0x1078, 0x26ec, 0x027f, 0x017f, - 0x0078, 0x159b, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x1594, - 0xa284, 0xfffd, 0x00c0, 0x1594, 0x2100, 0x7920, 0x7822, 0x2200, - 0x7a24, 0x7826, 0x0078, 0x159b, 0x71c4, 0xd1fc, 0x00c0, 0x18cc, - 0x2011, 0x4ec0, 0x0078, 0x18ce, 0x2011, 0x4f40, 0x8107, 0xa084, - 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x2019, 0x0000, 0x72c8, - 0xa284, 0x0080, 0x0040, 0x18e2, 0x6c14, 0x84ff, 0x00c0, 0x18e2, - 0x6817, 0x0040, 0xa284, 0x0040, 0x0040, 0x18ec, 0x6c10, 0x84ff, - 0x00c0, 0x18ec, 0x6813, 0x0001, 0x6800, 0x007e, 0xa226, 0x0040, - 0x1909, 0x6a02, 0xd4ec, 0x0040, 0x18f6, 0xc3a5, 0xd4e4, 0x0040, - 0x18fa, 0xc39d, 0xd4f4, 0x0040, 0x1909, 0x810f, 0xd2f4, 0x0040, - 0x1905, 0x1078, 0x276b, 0x0078, 0x1909, 0x1078, 0x2749, 0x0078, - 0x1909, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1929, 0xa2a4, 0x00ff, - 0x7814, 0xd0e4, 0x00c0, 0x191c, 0xa482, 0x0028, 0x0048, 0x1926, - 0x0040, 0x1926, 0x0078, 0x1920, 0xa482, 0x0043, 0x0048, 0x1926, - 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x1596, 0x6a0a, 0xa39d, - 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, 0x0078, - 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a14, 0x6b1c, - 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, - 0x159a, 0x70c4, 0x2061, 0x4a40, 0x6118, 0x601a, 0x7810, 0xd0ec, - 0x00c0, 0x159c, 0x70c8, 0x2061, 0x4a80, 0x6218, 0x601a, 0x0078, - 0x159b, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x1595, - 0x1078, 0x278d, 0xa384, 0x4000, 0x0040, 0x1960, 0xa295, 0x0020, - 0x0078, 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a08, - 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, - 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, - 0x6804, 0xa005, 0x0040, 0x197e, 0x1078, 0x25de, 0x2091, 0x8001, - 0x2708, 0x0078, 0x159b, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, - 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1991, 0x1078, - 0x25de, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, 0x2041, - 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, - 0x1e1d, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078, 0x159b, 0x77c4, - 0x7814, 0xd0e4, 0x00c0, 0x19bb, 0xd7fc, 0x0040, 0x19b5, 0x1078, - 0x1d82, 0x0040, 0x19bb, 0x0078, 0x159f, 0x1078, 0x1d72, 0x0040, - 0x19bb, 0x0078, 0x159f, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, - 0x1078, 0x1e9a, 0x00c0, 0x19e5, 0x6818, 0xa005, 0x0040, 0x19df, - 0x2708, 0x077e, 0x1078, 0x27bd, 0x077f, 0x00c0, 0x19df, 0x2001, - 0x0015, 0xd7fc, 0x00c0, 0x19d8, 0x2061, 0x4a40, 0x0078, 0x19db, - 0xc0fd, 0x2061, 0x4a80, 0x782a, 0x2091, 0x8001, 0x007c, 0x2091, - 0x8001, 0x2001, 0x4005, 0x0078, 0x159f, 0x2091, 0x8001, 0x0078, - 0x159d, 0x77c4, 0x7814, 0xd0e4, 0x00c0, 0x19fd, 0xd7fc, 0x0040, - 0x19f7, 0x1078, 0x1d82, 0x0040, 0x19fd, 0x0078, 0x159f, 0x1078, - 0x1d72, 0x0040, 0x19fd, 0x0078, 0x159f, 0x77c6, 0x2041, 0x0021, - 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, 0x1e1d, - 0x2009, 0x0016, 0xd7fc, 0x00c0, 0x1a11, 0x2061, 0x4a40, 0x0078, - 0x1a14, 0x2061, 0x4a80, 0xc1fd, 0x6067, 0x0003, 0x6776, 0x6083, - 0x000f, 0x792a, 0x1078, 0x25de, 0x2091, 0x8001, 0x007c, 0x77c8, - 0x77ca, 0x77c4, 0x77c6, 0x7814, 0xd0e4, 0x00c0, 0x1a36, 0xd7fc, - 0x0040, 0x1a30, 0x1078, 0x1d82, 0x0040, 0x1a36, 0x0078, 0x159f, - 0x1078, 0x1d72, 0x0040, 0x1a36, 0x0078, 0x159f, 0xa7bc, 0xff00, - 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, 0x00c0, 0x1a43, 0x2061, - 0x4a40, 0x0078, 0x1a46, 0x2061, 0x4a80, 0xc1fd, 0x6067, 0x0002, - 0x6776, 0x6083, 0x000f, 0x792a, 0x1078, 0x25de, 0x2091, 0x8001, - 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0010, 0x2091, 0x8000, - 0x70c8, 0xa005, 0x0040, 0x1a5f, 0x60d4, 0xc0fd, 0x60d6, 0x1078, - 0x1e1d, 0x70c8, 0x683e, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1a5f, - 0x2091, 0x8001, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x1a7f, 0x72c8, - 0xd284, 0x0040, 0x1a79, 0x1078, 0x1d82, 0x0040, 0x1a7f, 0x0078, - 0x159f, 0x1078, 0x1d72, 0x0040, 0x1a7f, 0x0078, 0x159f, 0x72c8, - 0x72ca, 0x78ac, 0xa084, 0x0003, 0x00c0, 0x1aaa, 0x2039, 0x0000, - 0xd284, 0x0040, 0x1a8c, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, - 0x2051, 0x0008, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6808, 0xc0d4, - 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, - 0x1a92, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, - 0x00c0, 0x1a92, 0x2091, 0x8000, 0x72c8, 0xd284, 0x00c0, 0x1abc, - 0x7810, 0xd0ec, 0x0040, 0x1ab8, 0x2069, 0x0100, 0x0078, 0x1abe, - 0x2069, 0x0200, 0x0078, 0x1abe, 0x2069, 0x0100, 0x6830, 0xd0b4, - 0x0040, 0x1ada, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, - 0x0040, 0x1acc, 0x00f0, 0x1ac6, 0x684b, 0x0009, 0x20a9, 0x0014, - 0x6848, 0xd084, 0x0040, 0x1ad6, 0x00f0, 0x1ad0, 0x20a9, 0x00fa, - 0x00f0, 0x1ad8, 0x2079, 0x4a00, 0x2009, 0x0018, 0x72c8, 0xd284, - 0x00c0, 0x1ae6, 0x2061, 0x4a40, 0x0078, 0x1ae9, 0x2061, 0x4a80, - 0xc1fd, 0x792a, 0x6067, 0x0001, 0x6083, 0x000f, 0x60a7, 0x0000, - 0x60a8, 0x60b2, 0x60b6, 0x60d4, 0xd0b4, 0x0040, 0x1b03, 0xc0b4, - 0x60d6, 0x0c7e, 0x60b8, 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, - 0x8001, 0x601a, 0x0c7f, 0x60d4, 0xa084, 0x77ff, 0x60d6, 0x78ac, - 0xc08d, 0x78ae, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0047, - 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x1b1a, 0x2069, 0x4a40, - 0x0078, 0x1b1c, 0x2069, 0x4a80, 0x78ac, 0xc08c, 0x78ae, 0xd084, - 0x00c0, 0x1b26, 0x0d7e, 0x1078, 0x1efa, 0x0d7f, 0x71c4, 0x71c6, - 0x6916, 0x81ff, 0x00c0, 0x1b2e, 0x68a7, 0x0001, 0x007c, 0x75d8, - 0x74dc, 0x75da, 0x74de, 0x0078, 0x1b38, 0x2029, 0x0000, 0x2520, - 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4a00, - 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x1078, 0x1ddb, 0x0040, 0x1c3b, - 0x20a9, 0x0005, 0x20a1, 0x4a14, 0x2091, 0x8000, 0x41a1, 0x2091, - 0x8001, 0x2009, 0x0040, 0x1078, 0x1fcf, 0x0040, 0x1b5b, 0x1078, - 0x1de4, 0x0078, 0x1c3b, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, - 0x00c0, 0x1b66, 0x007e, 0x1078, 0x234b, 0x007f, 0xa084, 0xff00, - 0x8007, 0x8009, 0x0040, 0x1bda, 0x0c7e, 0x2c68, 0x1078, 0x1ddb, - 0x0040, 0x1bac, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x1b6d, 0x609f, - 0x0000, 0x0c7f, 0x0c7e, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, - 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, - 0x7cda, 0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1bd9, - 0x2009, 0x0040, 0x1078, 0x1fcf, 0x00c0, 0x1bc3, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x0002, 0x00c0, 0x1bac, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x000a, 0x00c0, 0x1ba8, 0x017e, 0x1078, 0x2347, 0x017f, - 0x2d00, 0x6002, 0x0078, 0x1b7b, 0x0c7f, 0x0c7e, 0x609c, 0x1078, - 0x1e5d, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, - 0x6008, 0xc0cd, 0x600a, 0x6004, 0x6086, 0x1078, 0x1d92, 0x1078, - 0x1de4, 0x0078, 0x1c3b, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e5d, - 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, 0x6087, - 0x0103, 0x601b, 0x0003, 0x1078, 0x1d92, 0x1078, 0x1de4, 0x0078, - 0x1c3b, 0x0c7f, 0x7814, 0xd0e4, 0x00c0, 0x1bff, 0x6114, 0xd1fc, - 0x0040, 0x1be8, 0x1078, 0x1d82, 0x0040, 0x1bff, 0x0078, 0x1bec, - 0x1078, 0x1d72, 0x0040, 0x1bff, 0x2029, 0x0000, 0x2520, 0x2009, - 0x0018, 0x73c8, 0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x1078, - 0x1d92, 0x1078, 0x1de4, 0x2001, 0x4007, 0x0078, 0x159f, 0x74c4, - 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x0e7e, 0x2009, 0x0012, - 0xd0fc, 0x00c0, 0x1c0f, 0x2071, 0x4a40, 0x0078, 0x1c12, 0x2071, - 0x4a80, 0xc1fd, 0x792a, 0x7067, 0x0005, 0x71d4, 0xa18c, 0xf77f, - 0x71d6, 0x736a, 0x726e, 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, - 0x707e, 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x1c2a, - 0x1078, 0x43c1, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, - 0x0000, 0x60b3, 0x0000, 0x6714, 0x6023, 0x0000, 0x1078, 0x25de, - 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x15a0, 0x20a9, - 0x0005, 0x2099, 0x4a14, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, - 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, - 0x007c, 0x71c4, 0x70c7, 0x0000, 0x791e, 0x0078, 0x159d, 0x71c4, - 0x71c6, 0x2168, 0x0078, 0x1c5e, 0x2069, 0x1000, 0x690c, 0xa016, - 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1c60, 0xa285, 0x0000, - 0x00c0, 0x1c6e, 0x70c3, 0x4000, 0x0078, 0x1c70, 0x70c3, 0x4003, - 0x70ca, 0x0078, 0x15a0, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, - 0x00c8, 0x1595, 0x7966, 0x0078, 0x159d, 0x7964, 0x71c6, 0x0078, - 0x159d, 0x7900, 0x71c6, 0x71c4, 0x7902, 0x0078, 0x159d, 0x7900, - 0x71c6, 0x0078, 0x159d, 0x70c4, 0xd08c, 0x0040, 0x1c94, 0x7a10, - 0xd2ec, 0x00c0, 0x1c94, 0xc08c, 0x2011, 0x0000, 0xa08c, 0x000d, - 0x0040, 0x1ca8, 0x810c, 0x0048, 0x1ca4, 0x8210, 0x810c, 0x810c, - 0x0048, 0x1ca4, 0x8210, 0x810c, 0x81ff, 0x00c0, 0x1596, 0x8210, - 0x7a0e, 0xd28c, 0x0040, 0x1cd4, 0x7910, 0xc1cd, 0x7912, 0x2009, - 0x0021, 0x2019, 0x0003, 0xd284, 0x0040, 0x1cce, 0x8108, 0x2019, - 0x0041, 0x2011, 0x924e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, - 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, - 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x9253, - 0x2112, 0x2011, 0x9273, 0x2312, 0x7904, 0x7806, 0x0078, 0x159c, - 0x7804, 0x70c6, 0x0078, 0x159d, 0x2091, 0x8000, 0x2019, 0x0000, - 0x2011, 0x0000, 0x2009, 0x0000, 0x2091, 0x8001, 0x0078, 0x159a, - 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6830, 0xa084, 0xff00, - 0x8007, 0x2010, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, - 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a34, 0x2091, 0x8001, 0x2708, - 0x0078, 0x159b, 0x77c4, 0x077e, 0xa7bc, 0xff00, 0x20a9, 0x0008, - 0x72c8, 0x8217, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6c30, 0x6a32, - 0x2091, 0x8001, 0x8738, 0x00f0, 0x1d0a, 0x077f, 0x2708, 0x8427, - 0x2410, 0x0078, 0x159b, 0x77c4, 0x077e, 0xa7bc, 0xff00, 0x20a9, - 0x0008, 0x72c8, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6c34, 0x6a36, - 0x2091, 0x8001, 0x8738, 0x00f0, 0x1d22, 0x077f, 0x2708, 0x2410, - 0x0078, 0x159b, 0x2011, 0x4a3c, 0x220c, 0x70c4, 0x2012, 0x0078, - 0x159c, 0x71c4, 0xd1fc, 0x00c0, 0x1d41, 0x2011, 0x4ec0, 0x0078, - 0x1d43, 0x2011, 0x4f40, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, - 0x8003, 0xa268, 0x6a14, 0xd2b4, 0x0040, 0x1d52, 0x2011, 0x0001, - 0x0078, 0x1d54, 0x2011, 0x0000, 0x6b0c, 0x0078, 0x159a, 0x017e, - 0x7814, 0xd0f4, 0x0040, 0x1d64, 0x2001, 0x4007, 0x70db, 0x0000, - 0xa18d, 0x0001, 0x0078, 0x1d70, 0xd0fc, 0x0040, 0x1d6f, 0x2001, - 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d70, 0xa006, - 0x017f, 0x007c, 0x017e, 0x7814, 0xd0f4, 0x0040, 0x1d7f, 0x2001, - 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0078, 0x1d80, 0xa006, - 0x017f, 0x007c, 0x017e, 0x7814, 0xd0fc, 0x0040, 0x1d8f, 0x2001, - 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d90, 0xa006, - 0x017f, 0x007c, 0x7112, 0x721a, 0x731e, 0x7810, 0xd0c4, 0x0040, - 0x1d9b, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, - 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, 0x53a6, - 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0040, 0x1db8, 0x810f, - 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, 0x1dbb, - 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, - 0x7d10, 0xd5c4, 0x0040, 0x1dc8, 0x7b84, 0xa319, 0x7c80, 0xa421, - 0x7008, 0xd0fc, 0x0040, 0x1dc8, 0x7003, 0x0001, 0x7007, 0x0006, - 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0040, 0x1dd8, 0x7322, 0x7426, - 0xa084, 0x01e0, 0x007c, 0x7848, 0xa065, 0x0040, 0x1de3, 0x2c04, - 0x784a, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x4a00, 0x7848, - 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1def, 0x1078, 0x28ec, 0x784a, - 0x0f7f, 0x007c, 0x2011, 0x9400, 0x7a4a, 0x7bc4, 0x8319, 0x0040, - 0x1dff, 0xa280, 0x0032, 0x2012, 0x2010, 0x0078, 0x1df6, 0x2013, - 0x0000, 0x007c, 0x017e, 0x027e, 0xd7fc, 0x00c0, 0x1e0b, 0x2011, - 0x4fc0, 0x0078, 0x1e0d, 0x2011, 0x6fc0, 0xa784, 0x0f00, 0x800b, - 0xa784, 0x001f, 0x0040, 0x1e18, 0x8003, 0x8003, 0x8003, 0x8003, - 0xa105, 0xa268, 0x027f, 0x017f, 0x007c, 0x1078, 0x1e02, 0x2900, - 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, 0x690a, - 0xd7fc, 0x00c0, 0x1e2f, 0x2009, 0x4a53, 0x0078, 0x1e31, 0x2009, - 0x4a93, 0x210c, 0x6804, 0xa005, 0x0040, 0x1e41, 0xa116, 0x00c0, - 0x1e41, 0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, - 0x1e44, 0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1e59, - 0x6000, 0x6806, 0x1078, 0x1e6f, 0x1078, 0x201b, 0x6810, 0x7908, - 0x8109, 0x790a, 0x8001, 0x6812, 0x00c0, 0x1e44, 0x7910, 0xc1a5, - 0x7912, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x1e6e, - 0x2008, 0x609c, 0xa005, 0x0040, 0x1e6b, 0x2062, 0x609f, 0x0000, - 0xa065, 0x0078, 0x1e61, 0x7848, 0x794a, 0x2062, 0x007c, 0x6007, - 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005, 0x20a0, - 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022, 0x007c, - 0x0e7e, 0xd7fc, 0x00c0, 0x1e8a, 0x2071, 0x4a40, 0x2031, 0x4ac0, - 0x0078, 0x1e8e, 0x2071, 0x4a80, 0x2031, 0x4cc0, 0x7050, 0xa08c, - 0x0200, 0x00c0, 0x1e98, 0xa608, 0x2d0a, 0x8000, 0x7052, 0xa006, - 0x0e7f, 0x007c, 0x0f7e, 0xd7fc, 0x00c0, 0x1ea2, 0x2079, 0x4a40, - 0x0078, 0x1ea4, 0x2079, 0x4a80, 0x1078, 0x1e02, 0x2091, 0x8000, - 0x6804, 0x780a, 0xa065, 0x0040, 0x1ef8, 0x0078, 0x1eb6, 0x2c00, - 0x780a, 0x2060, 0x6000, 0xa065, 0x0040, 0x1ef8, 0x6010, 0xa306, - 0x00c0, 0x1eaf, 0x600c, 0xa206, 0x00c0, 0x1eaf, 0x2c28, 0x784c, - 0xac06, 0x00c0, 0x1ec5, 0x0078, 0x1ef5, 0x6804, 0xac06, 0x00c0, - 0x1ed3, 0x6000, 0x2060, 0x6806, 0xa005, 0x00c0, 0x1ed3, 0x6803, - 0x0000, 0x0078, 0x1edd, 0x6400, 0x7808, 0x2060, 0x6402, 0xa486, - 0x0000, 0x00c0, 0x1edd, 0x2c00, 0x6802, 0x2560, 0x0f7f, 0x1078, - 0x1e6f, 0x0f7e, 0x601b, 0x0005, 0x6023, 0x0020, 0x0f7f, 0x1078, - 0x201b, 0x0f7e, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, 0x6812, - 0x00c0, 0x1ef5, 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, - 0x0f7f, 0x007c, 0x077e, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0040, - 0x1f02, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, - 0x2091, 0x8000, 0x1078, 0x1e1d, 0x8738, 0xa784, 0x001f, 0x00c0, - 0x1f0a, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, - 0x00c0, 0x1f0a, 0x2091, 0x8001, 0x077f, 0x007c, 0x2061, 0x0000, - 0x6018, 0xd084, 0x00c0, 0x1f3e, 0x7810, 0xd08c, 0x0040, 0x1f2f, - 0xc08c, 0x7812, 0xc7fc, 0x2069, 0x4a40, 0x0078, 0x1f34, 0xc08d, - 0x7812, 0x2069, 0x4a80, 0xc7fd, 0x2091, 0x8000, 0x681c, 0x681f, - 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0, 0x1f3f, 0x007c, 0xa08c, - 0xfff0, 0x0040, 0x1f45, 0x1078, 0x28ec, 0x0079, 0x1f47, 0x1f57, - 0x1f5a, 0x1f60, 0x1f64, 0x1f58, 0x1f68, 0x1f58, 0x1f58, 0x1f58, - 0x1f6e, 0x1f9f, 0x1fa3, 0x1fa9, 0x1f58, 0x1f58, 0x1f58, 0x007c, - 0x1078, 0x28ec, 0x1078, 0x1efa, 0x2001, 0x8001, 0x0078, 0x1fbe, - 0x2001, 0x8003, 0x0078, 0x1fbe, 0x2001, 0x8004, 0x0078, 0x1fbe, - 0x1078, 0x1efa, 0x2001, 0x8006, 0x0078, 0x1fbe, 0x2091, 0x8000, - 0x077e, 0xd7fc, 0x00c0, 0x1f7a, 0x2069, 0x4a40, 0x2039, 0x0009, - 0x0078, 0x1f7e, 0x2069, 0x4a80, 0x2039, 0x0009, 0x6800, 0xa086, - 0x0000, 0x0040, 0x1f88, 0x007f, 0x6f1e, 0x2091, 0x8001, 0x007c, - 0x6874, 0x077f, 0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, - 0x2051, 0x0010, 0x1078, 0x1e1d, 0x8738, 0xa784, 0x001f, 0x00c0, - 0x1f92, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, 0x1fbe, 0x2001, - 0x800c, 0x0078, 0x1fbe, 0x1078, 0x1efa, 0x2001, 0x800d, 0x0078, - 0x1fbe, 0x7814, 0xd0e4, 0x00c0, 0x1fbc, 0xd0ec, 0x0040, 0x1fb6, - 0xd7fc, 0x0040, 0x1fb6, 0x78ec, 0x0078, 0x1fb7, 0x78e4, 0x70c6, - 0x2001, 0x800e, 0x0078, 0x1fbe, 0x0078, 0x1f58, 0x70c2, 0xd7fc, - 0x00c0, 0x1fc6, 0x70db, 0x0000, 0x0078, 0x1fc8, 0x70db, 0x0001, - 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, 0xac80, - 0x0001, 0x81ff, 0x0040, 0x1ffa, 0x2099, 0x0030, 0x20a0, 0x700c, - 0xa084, 0x03ff, 0x0040, 0x1fdc, 0x7018, 0x007e, 0x701c, 0x007e, - 0x7020, 0x007e, 0x7024, 0x007e, 0x7112, 0x81ac, 0x721a, 0x731e, - 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, 0x800b, - 0x00c8, 0x1fee, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x1ffa, - 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x007f, 0x7026, - 0x007f, 0x7022, 0x007f, 0x701e, 0x007f, 0x701a, 0x007c, 0x2011, - 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x6803, 0xfd00, 0x6807, - 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, - 0x00c0, 0x200b, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, - 0x7868, 0xa005, 0x796a, 0x0040, 0x2028, 0x2c02, 0x0078, 0x2029, - 0x796e, 0x007c, 0x0c7e, 0x2061, 0x4a00, 0x6887, 0x0103, 0x2d08, - 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x203a, 0x2d02, - 0x0078, 0x203b, 0x616e, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x2c04, - 0x786e, 0xa005, 0x00c0, 0x2045, 0x786a, 0x2091, 0x8001, 0x609c, - 0xa005, 0x0040, 0x205e, 0x0c7e, 0x2060, 0x2008, 0x609c, 0xa005, - 0x0040, 0x205a, 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, 0xa005, - 0x00c0, 0x2052, 0x7848, 0x794a, 0x2062, 0x0c7f, 0x7848, 0x2062, - 0x609f, 0x0000, 0xac85, 0x0000, 0x00c0, 0x2068, 0x1078, 0x28ec, - 0x784a, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, - 0x00c8, 0x2073, 0xa200, 0x00f0, 0x206e, 0x8086, 0x818e, 0x007c, - 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x2099, 0xa11a, 0x00c8, - 0x2099, 0x8213, 0x818d, 0x0048, 0x208c, 0xa11a, 0x00c8, 0x208d, - 0x00f0, 0x2081, 0x0078, 0x2091, 0xa11a, 0x2308, 0x8210, 0x00f0, - 0x2081, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, - 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x2095, 0x7d74, - 0x70d0, 0xa506, 0x0040, 0x2185, 0x7810, 0x2050, 0x7800, 0xd08c, - 0x0040, 0x20c1, 0xdaec, 0x0040, 0x20c1, 0x0e7e, 0x2091, 0x8000, - 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x20be, 0x7008, 0x0e7f, - 0xa086, 0x0008, 0x0040, 0x20c1, 0x0078, 0x2185, 0x0e7f, 0x0078, - 0x2185, 0x1078, 0x1ddb, 0x0040, 0x2185, 0xa046, 0x7970, 0x2500, - 0x8000, 0xa112, 0x2009, 0x0040, 0x00c8, 0x20d0, 0x0078, 0x20d7, - 0x72d0, 0xa206, 0x0040, 0x20d7, 0x8840, 0x2009, 0x0080, 0x0c7e, - 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, 0x0020, 0xac80, - 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0040, 0x20e9, 0x1078, - 0x1ddb, 0x7008, 0xd0fc, 0x0040, 0x20e9, 0x7007, 0x0002, 0x2091, - 0x8001, 0xa08c, 0x01e0, 0x00c0, 0x2120, 0x53a5, 0x8cff, 0x00c0, - 0x20fe, 0x88ff, 0x0040, 0x216f, 0x0078, 0x2108, 0x2c00, 0x788e, - 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0078, 0x216f, - 0xa046, 0x7218, 0x731c, 0xdac4, 0x0040, 0x2110, 0x7420, 0x7524, - 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, 0x0000, 0xa5ab, 0x0000, - 0x721a, 0x731e, 0xdac4, 0x0040, 0x2120, 0x7422, 0x7526, 0xa006, - 0x7007, 0x0004, 0x0040, 0x216f, 0x8cff, 0x0040, 0x2129, 0x1078, - 0x1de4, 0x0c7f, 0x1078, 0x1de4, 0xa046, 0x7888, 0x8000, 0x788a, - 0xa086, 0x0002, 0x0040, 0x214f, 0x7a7c, 0x7b78, 0xdac4, 0x0040, - 0x213b, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, 0xa210, - 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, 0x731e, - 0xdac4, 0x0040, 0x2185, 0x7422, 0x7526, 0x0078, 0x2185, 0x6014, - 0xd0fc, 0x00c0, 0x2157, 0x2069, 0x4a40, 0x0078, 0x2159, 0x2069, - 0x4a80, 0x2091, 0x8000, 0x681f, 0x0002, 0x88ff, 0x0040, 0x2165, - 0xa046, 0x788c, 0x2060, 0x0078, 0x214f, 0x788b, 0x0000, 0x78ac, - 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0078, 0x2185, 0x0c7f, - 0x788b, 0x0000, 0x1078, 0x2319, 0x6004, 0xa084, 0x000f, 0x1078, - 0x2186, 0x88ff, 0x0040, 0x2183, 0x788c, 0x2060, 0x6004, 0xa084, - 0x000f, 0x1078, 0x2186, 0x0078, 0x209f, 0x007c, 0x0079, 0x2188, - 0x2198, 0x21b6, 0x21d4, 0x2198, 0x21e5, 0x21a9, 0x2198, 0x2198, - 0x2198, 0x21b4, 0x21d2, 0x2198, 0x2198, 0x2198, 0x2198, 0x2198, - 0x2039, 0x0400, 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, - 0x1078, 0x2228, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, 0x2303, - 0x007c, 0x78bc, 0xd0c4, 0x0040, 0x21af, 0x0078, 0x2198, 0x601c, - 0xc0bd, 0x601e, 0x0078, 0x21bc, 0x1078, 0x234b, 0x78bc, 0xd0c4, - 0x0040, 0x21bc, 0x0078, 0x2198, 0x78bf, 0x0000, 0x6004, 0x8007, - 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0040, 0x21cf, 0x1078, 0x2228, - 0x0040, 0x21cf, 0x78bc, 0xc0c5, 0x78be, 0x0078, 0x21d1, 0x0078, - 0x2247, 0x007c, 0x1078, 0x2347, 0x78bc, 0xa08c, 0x0e00, 0x00c0, - 0x21dc, 0xd0c4, 0x00c0, 0x21de, 0x0078, 0x2198, 0x1078, 0x2228, - 0x00c0, 0x21e4, 0x0078, 0x2247, 0x007c, 0x78bc, 0xd0c4, 0x0040, - 0x21eb, 0x0078, 0x2198, 0x78bf, 0x0000, 0x6714, 0x2011, 0x0001, - 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, 0x220b, 0xa7bc, - 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040, 0x220b, 0xa7bc, - 0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0040, - 0x220b, 0x0078, 0x2225, 0x1078, 0x1e02, 0x2d00, 0x2091, 0x8000, - 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, - 0xade8, 0x0010, 0x2091, 0x8001, 0x00f0, 0x220e, 0x8211, 0x0040, - 0x2225, 0x20a9, 0x0100, 0x0078, 0x220e, 0x1078, 0x1de4, 0x007c, - 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, 0x00c0, 0x2233, - 0x78ba, 0x0078, 0x223b, 0x689e, 0x2d00, 0x6002, 0x78b8, 0xad06, - 0x00c0, 0x223b, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x00c0, 0x2246, - 0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x007c, 0x0e7e, - 0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, - 0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0040, 0x225a, - 0x1078, 0x43c1, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, - 0x4a80, 0xd7fc, 0x00c0, 0x2266, 0x2071, 0x4a40, 0xa784, 0x0f00, - 0x800b, 0xa784, 0x001f, 0x0040, 0x2271, 0x8003, 0x8003, 0x8003, - 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, 0x8007, 0xa084, 0x000f, - 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, 0x60c2, 0x2091, 0x8000, - 0x7810, 0xd0f4, 0x00c0, 0x228b, 0x6e08, 0xd684, 0x0040, 0x22a1, - 0xd9fc, 0x00c0, 0x22a1, 0x2091, 0x8001, 0x1078, 0x1e6f, 0x2091, - 0x8000, 0x1078, 0x201b, 0x2091, 0x8001, 0x7814, 0xd0e4, 0x00c0, - 0x2301, 0x7810, 0xd0f4, 0x0040, 0x2301, 0x601b, 0x0021, 0x0078, - 0x2301, 0x6024, 0xa096, 0x0001, 0x00c0, 0x22a8, 0x8000, 0x6026, - 0x6a10, 0x6814, 0xa202, 0x0048, 0x22bb, 0x0040, 0x22bb, 0x2091, - 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, - 0x2303, 0x0078, 0x2301, 0x2c08, 0xd9fc, 0x0040, 0x22de, 0x6800, - 0xa065, 0x0040, 0x22de, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0040, - 0x22d9, 0x704c, 0xa206, 0x00c0, 0x22d9, 0x6b04, 0x2160, 0x2304, - 0x6002, 0xa005, 0x00c0, 0x22d5, 0x6902, 0x2260, 0x6102, 0x0078, - 0x22ea, 0x2160, 0x6202, 0x6906, 0x0078, 0x22ea, 0x6800, 0x6902, - 0xa065, 0x0040, 0x22e6, 0x6102, 0x0078, 0x22e7, 0x6906, 0x2160, - 0x6003, 0x0000, 0x2160, 0xd9fc, 0x0040, 0x22f1, 0xa6b4, 0xfffc, - 0x6e0a, 0x6810, 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, - 0x8001, 0xd6b4, 0x0040, 0x2301, 0xa6b6, 0x0040, 0x6e0a, 0x1078, - 0x1e80, 0x0e7f, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, - 0x1078, 0x201b, 0x2091, 0x8001, 0x78b8, 0xa065, 0x0040, 0x2316, - 0x609c, 0x78ba, 0x609f, 0x0000, 0x0078, 0x2303, 0x78b6, 0x78ba, - 0x007c, 0x7970, 0x7874, 0x2818, 0xd384, 0x0040, 0x2323, 0x8000, - 0xa112, 0x0048, 0x2328, 0x8000, 0xa112, 0x00c8, 0x2338, 0xc384, - 0x7a7c, 0x721a, 0x7a78, 0x721e, 0xdac4, 0x0040, 0x2333, 0x7a84, - 0x7222, 0x7a80, 0x7226, 0xa006, 0xd384, 0x0040, 0x2338, 0x8000, - 0x7876, 0x70d2, 0x781c, 0xa005, 0x0040, 0x2346, 0x8001, 0x781e, - 0x00c0, 0x2346, 0x0068, 0x2346, 0x2091, 0x4080, 0x007c, 0x2039, - 0x235f, 0x0078, 0x234d, 0x2039, 0x2365, 0x2704, 0xa005, 0x0040, - 0x235e, 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, 0x680a, 0x690c, - 0x6814, 0x6916, 0x680e, 0x8738, 0x0078, 0x234d, 0x007c, 0x0003, - 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, - 0x2041, 0x0000, 0x780c, 0x0079, 0x236d, 0x2535, 0x2508, 0x2371, - 0x23e5, 0x2039, 0x9274, 0x2734, 0x7d10, 0x0078, 0x238c, 0x6084, - 0xa086, 0x0103, 0x00c0, 0x23ce, 0x6114, 0x6018, 0xa105, 0x00c0, - 0x23ce, 0x8603, 0xa080, 0x9255, 0x620c, 0x2202, 0x8000, 0x6210, - 0x2202, 0x1078, 0x203d, 0x8630, 0xa68e, 0x000f, 0x0040, 0x2454, - 0x786c, 0xa065, 0x00c0, 0x2377, 0x7808, 0xa602, 0x00c8, 0x239d, - 0xd5ac, 0x00c0, 0x239d, 0x263a, 0x007c, 0xa682, 0x0003, 0x00c8, - 0x2454, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, - 0x23c9, 0x2011, 0x9255, 0x2204, 0x70c6, 0x8210, 0x2204, 0x70ca, - 0xd684, 0x00c0, 0x23b9, 0x8210, 0x2204, 0x70da, 0x8210, 0x2204, - 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, - 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, 0x203b, 0x0000, - 0x007c, 0x7810, 0xc0ad, 0x7812, 0x0078, 0x2454, 0x263a, 0x1078, - 0x253f, 0x00c0, 0x254e, 0x786c, 0xa065, 0x00c0, 0x2377, 0x2091, - 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x23e0, 0xc0ad, - 0x7812, 0x2091, 0x8001, 0x0078, 0x254e, 0x2039, 0x9274, 0x2734, - 0x7d10, 0x0078, 0x23fc, 0x6084, 0xa086, 0x0103, 0x00c0, 0x243d, - 0x6114, 0x6018, 0xa105, 0x00c0, 0x243d, 0xa680, 0x9255, 0x620c, - 0x2202, 0x1078, 0x203d, 0x8630, 0xa68e, 0x001e, 0x0040, 0x2454, - 0x786c, 0xa065, 0x00c0, 0x23eb, 0x7808, 0xa602, 0x00c8, 0x240d, - 0xd5ac, 0x00c0, 0x240d, 0x263a, 0x007c, 0xa682, 0x0006, 0x00c8, - 0x2454, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, - 0x2438, 0x2011, 0x9255, 0x2009, 0x924e, 0x26a8, 0x211c, 0x2204, - 0x201a, 0x8108, 0x8210, 0x00f0, 0x241e, 0xa685, 0x8030, 0x70c2, + 0xa1a2, 0x4d00, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0xa192, 0x9700, 0x2009, 0x0000, 0x2001, 0x0032, 0x1078, 0x2061, + 0x2218, 0x2079, 0x4d00, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, + 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10bf, 0x2009, 0xff00, 0x3400, + 0xa102, 0x0048, 0x10cf, 0x0040, 0x10cf, 0x20a8, 0x42a4, 0x2001, + 0x04fc, 0x2004, 0xa086, 0x1080, 0x00c0, 0x10e5, 0x2071, 0x0100, + 0x0d7e, 0x2069, 0x4d40, 0x1078, 0x4c38, 0x0d7f, 0x7810, 0xc0ed, + 0x7812, 0x781b, 0x0064, 0x0078, 0x110a, 0x2001, 0x04fc, 0x2004, + 0xa086, 0x1280, 0x00c0, 0x1105, 0x7814, 0xc0ed, 0xc0d5, 0x7816, + 0x781b, 0x0064, 0x2071, 0x0200, 0x0d7e, 0x2069, 0x4d40, 0x1078, + 0x4c38, 0x2069, 0x4d80, 0x2071, 0x0100, 0x1078, 0x4c38, 0x7814, + 0xc0d4, 0x7816, 0x0d7f, 0x0078, 0x110a, 0x7814, 0xc0e5, 0x7816, + 0x781b, 0x003c, 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, + 0xc08d, 0x7802, 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, + 0x7827, 0x0002, 0x2009, 0x0002, 0x2069, 0x4d40, 0x681b, 0x0003, + 0x6823, 0x0007, 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, + 0x6837, 0x0000, 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, + 0x8109, 0x0040, 0x115e, 0x68d3, 0x000a, 0x68c3, 0x4dc0, 0x2079, + 0x4d00, 0x7814, 0xd0e4, 0x00c0, 0x1144, 0xd0ec, 0x00c0, 0x1148, + 0x68d7, 0x7329, 0x0078, 0x114a, 0x68d7, 0x730d, 0x0078, 0x114a, + 0x68d7, 0x732d, 0x68c7, 0x52c0, 0x68cb, 0x51c0, 0x68cf, 0x92c0, + 0x68ab, 0x9544, 0x68af, 0x9549, 0x68b3, 0x9544, 0x68b7, 0x9544, + 0x68a7, 0x0001, 0x2069, 0x4d80, 0x0078, 0x111e, 0x68d3, 0x000a, + 0x68c3, 0x4fc0, 0x7814, 0xd0e4, 0x00c0, 0x116a, 0x68d7, 0x7439, + 0x0078, 0x116c, 0x68d7, 0x7419, 0x68c7, 0x72c0, 0x68cb, 0x5240, + 0x68cf, 0x93d0, 0x68ab, 0x9549, 0x68af, 0x954e, 0x68b3, 0x9549, + 0x68b7, 0x9549, 0x68a7, 0x0001, 0x7810, 0xd0ec, 0x00c0, 0x11c2, + 0x7814, 0xd0e4, 0x00c0, 0x11b4, 0x0e7e, 0x2069, 0x51c0, 0x2071, + 0x0200, 0x70ec, 0xd0e4, 0x00c0, 0x1195, 0x2019, 0x0c0c, 0x2021, + 0x000c, 0x1078, 0x1ff0, 0x0078, 0x119b, 0x2019, 0x0c0a, 0x2021, + 0x000a, 0x1078, 0x1ff0, 0x2069, 0x5240, 0x2071, 0x0100, 0x70ec, + 0xd0e4, 0x00c0, 0x11ab, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, + 0x1ff0, 0x0078, 0x11b1, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, + 0x1ff0, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0c, 0x2021, 0x000c, + 0x2069, 0x51c0, 0x1078, 0x1ff0, 0x2069, 0x5240, 0x1078, 0x1ff0, + 0x0078, 0x11db, 0x2069, 0x51c0, 0x0e7e, 0x2071, 0x0100, 0x70ec, + 0xd0e4, 0x00c0, 0x11d4, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, + 0x1ff0, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0a, 0x2021, 0x000a, + 0x1078, 0x1ff0, 0x0e7f, 0x2011, 0x0002, 0x2069, 0x52c0, 0x2009, + 0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bc8, + 0xa386, 0xfeff, 0x00c0, 0x11f2, 0x6817, 0x0100, 0x681f, 0x0064, + 0x0078, 0x11f6, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, + 0x00f0, 0x11e3, 0x8109, 0x00c0, 0x11e1, 0x8211, 0x0040, 0x1204, + 0x2069, 0x72c0, 0x0078, 0x11df, 0x1078, 0x261d, 0x1078, 0x4603, + 0x1078, 0x1dbb, 0x1078, 0x4be1, 0x2091, 0x2100, 0x2079, 0x4d00, + 0x7810, 0xd0ec, 0x0040, 0x1218, 0x2071, 0x0020, 0x0078, 0x121a, + 0x2071, 0x0050, 0x2091, 0x2200, 0x2079, 0x4d00, 0x2071, 0x0020, + 0x2091, 0x2300, 0x2079, 0x4d00, 0x7810, 0xd0ec, 0x0040, 0x122c, + 0x2079, 0x0100, 0x0078, 0x122e, 0x2079, 0x0200, 0x2071, 0x4d40, + 0x2091, 0x2400, 0x2079, 0x0100, 0x2071, 0x4d80, 0x2091, 0x2000, + 0x2079, 0x4d00, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, + 0x2071, 0x0010, 0x70c3, 0x0000, 0x0090, 0x124d, 0x70c0, 0xa086, + 0x0002, 0x00c0, 0x124d, 0x1078, 0x15ba, 0x2039, 0x0000, 0x7810, + 0xd0ec, 0x00c0, 0x12cf, 0x1078, 0x148e, 0x78ac, 0xa005, 0x00c0, + 0x126b, 0x0068, 0x1261, 0x786c, 0xa065, 0x0040, 0x1261, 0x1078, + 0x2356, 0x1078, 0x2088, 0x0068, 0x1278, 0x786c, 0xa065, 0x0040, + 0x126b, 0x1078, 0x2356, 0x0068, 0x1278, 0x2009, 0x4d47, 0x2011, + 0x4d87, 0x2104, 0x220c, 0xa105, 0x0040, 0x1278, 0x1078, 0x1ef1, + 0x2071, 0x4d40, 0x70a4, 0xa005, 0x0040, 0x129d, 0x7450, 0xa485, + 0x0000, 0x0040, 0x129d, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, + 0xa28c, 0x303d, 0x2190, 0x1078, 0x2b0b, 0x2091, 0x8000, 0x2091, + 0x303d, 0x0068, 0x129d, 0x2079, 0x4d00, 0x786c, 0xa065, 0x0040, + 0x129d, 0x2071, 0x0010, 0x1078, 0x2356, 0x00e0, 0x12a5, 0x2079, + 0x4d00, 0x2071, 0x0010, 0x1078, 0x49ba, 0x2071, 0x4d80, 0x70a4, + 0xa005, 0x0040, 0x12bd, 0x7050, 0xa025, 0x0040, 0x12bd, 0x2079, + 0x0100, 0x2091, 0x8000, 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, + 0x2b0b, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079, 0x4d00, 0x2071, + 0x0010, 0x0068, 0x12c9, 0x786c, 0xa065, 0x0040, 0x12c9, 0x1078, + 0x2356, 0x00e0, 0x1253, 0x1078, 0x49ba, 0x0078, 0x1253, 0x1078, + 0x148e, 0x78ac, 0xa005, 0x00c0, 0x12e7, 0x0068, 0x12dd, 0x786c, + 0xa065, 0x0040, 0x12dd, 0x1078, 0x2356, 0x1078, 0x2088, 0x0068, + 0x12f1, 0x786c, 0xa065, 0x0040, 0x12e7, 0x1078, 0x2356, 0x0068, + 0x12f1, 0x2009, 0x4d47, 0x2104, 0xa005, 0x0040, 0x12f1, 0x1078, + 0x1ef1, 0x2071, 0x4d40, 0x70a4, 0xa005, 0x0040, 0x130c, 0x7450, + 0xa485, 0x0000, 0x0040, 0x130c, 0x2079, 0x0100, 0x2091, 0x8000, + 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, 0x2b0b, 0x2091, 0x8000, + 0x2091, 0x303d, 0x2079, 0x4d00, 0x2071, 0x0010, 0x0068, 0x1316, + 0x786c, 0xa065, 0x0040, 0x1316, 0x1078, 0x2356, 0x00e0, 0x12cf, + 0x1078, 0x49ba, 0x0078, 0x12cf, 0x133c, 0x133c, 0x133e, 0x133e, + 0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363, + 0x134b, 0x134b, 0x134b, 0x134b, 0x133c, 0x133c, 0x133e, 0x133e, + 0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363, + 0x134b, 0x134b, 0x134b, 0x134b, 0x0078, 0x133c, 0x007e, 0x107e, + 0x127e, 0x2091, 0x2400, 0x1078, 0x292b, 0x127f, 0x107f, 0x007f, + 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13c8, + 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, + 0x127e, 0x2091, 0x2300, 0x1078, 0x292b, 0x127f, 0x107f, 0x007f, + 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, + 0x1078, 0x292b, 0x2091, 0x2400, 0x1078, 0x292b, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x1394, 0x1394, 0x1396, 0x1396, + 0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13ae, 0x13ae, 0x1396, 0x1396, + 0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13af, 0x13af, 0x13af, 0x13af, + 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, + 0x13af, 0x13af, 0x13af, 0x13af, 0x0078, 0x1394, 0x007e, 0x107e, + 0x127e, 0x2091, 0x2300, 0x1078, 0x292b, 0x127f, 0x107f, 0x007f, + 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13d5, + 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007c, 0x107e, + 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x007e, 0x2071, 0x0100, 0x2069, + 0x4d40, 0x2079, 0x4d00, 0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078, + 0x4c38, 0x007f, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, 0x107f, 0x007c, + 0x3c00, 0xa084, 0x0007, 0x0079, 0x13cd, 0x13de, 0x13de, 0x13e0, + 0x13e0, 0x13e5, 0x13e5, 0x13ea, 0x13ea, 0x3c00, 0xa084, 0x0003, + 0x0079, 0x13da, 0x13de, 0x13de, 0x13f3, 0x13f3, 0x1078, 0x290c, + 0x2091, 0x2200, 0x1078, 0x46dd, 0x007c, 0x2091, 0x2100, 0x1078, + 0x46dd, 0x007c, 0x2091, 0x2100, 0x1078, 0x46dd, 0x2091, 0x2200, + 0x1078, 0x46dd, 0x007c, 0x2091, 0x2100, 0x1078, 0x46dd, 0x007c, + 0x1418, 0x1418, 0x141a, 0x141a, 0x1427, 0x1427, 0x1427, 0x1427, + 0x1432, 0x1432, 0x143f, 0x143f, 0x1427, 0x1427, 0x1427, 0x1427, + 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, + 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, + 0x0078, 0x1418, 0x007e, 0x107e, 0x127e, 0x2091, 0x2400, 0x1078, + 0x292b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, + 0x107e, 0x127e, 0x1078, 0x13c8, 0x127f, 0x107f, 0x007f, 0x2091, + 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, + 0x292b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, + 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x292b, 0x2091, 0x2400, + 0x1078, 0x292b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, + 0x007e, 0x107e, 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2079, 0x4d00, + 0x2071, 0x0200, 0x2069, 0x4d40, 0x3d00, 0xd08c, 0x0040, 0x1466, + 0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078, 0x4c38, 0x3d00, 0xd084, + 0x0040, 0x1474, 0x2069, 0x4d80, 0x2071, 0x0100, 0x70ec, 0xa084, + 0x1c00, 0x78e6, 0x1078, 0x4c38, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, + 0x107f, 0x007f, 0x007c, 0x7008, 0x800b, 0x00c8, 0x1489, 0x7007, + 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x148a, 0xd09c, 0x0040, 0x1489, + 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, 0x15bd, 0x0068, 0x1513, + 0x2061, 0x0000, 0x6018, 0xd084, 0x00c0, 0x1513, 0x7828, 0xa005, + 0x00c0, 0x149e, 0x0010, 0x1514, 0x0078, 0x1513, 0x7910, 0xd1f4, + 0x0040, 0x14a6, 0x2001, 0x4007, 0x0078, 0x15bc, 0x7914, 0xd1ec, + 0x0040, 0x14c1, 0xd0fc, 0x0040, 0x14b7, 0x007e, 0x1078, 0x1d4b, + 0x007f, 0x0040, 0x14c1, 0x2001, 0x4007, 0x0078, 0x15bc, 0x007e, + 0x1078, 0x1d3b, 0x007f, 0x0040, 0x14c1, 0x2001, 0x4007, 0x0078, + 0x15bc, 0x7910, 0xd0fc, 0x00c0, 0x14cb, 0x2061, 0x4d40, 0xc19c, + 0xc7fc, 0x0078, 0x14cf, 0x2061, 0x4d80, 0xc19d, 0xc7fd, 0x6064, + 0xa005, 0x00c0, 0x1513, 0x7912, 0x6083, 0x0000, 0x7828, 0xc0fc, + 0xa086, 0x0018, 0x00c0, 0x14e0, 0x0c7e, 0x1078, 0x1b44, 0x0c7f, + 0x782b, 0x0000, 0x607c, 0xa065, 0x0040, 0x14f9, 0x0c7e, 0x609c, + 0x1078, 0x1e30, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c6d, 0x2009, + 0x0018, 0x6087, 0x0103, 0x1078, 0x1d5b, 0x00c0, 0x150d, 0x1078, + 0x1dad, 0x7810, 0xd09c, 0x00c0, 0x1501, 0x2061, 0x4d40, 0x0078, + 0x1505, 0x2061, 0x4d80, 0xc09c, 0x7812, 0x607f, 0x0000, 0x60d4, + 0xd0dc, 0x0040, 0x1511, 0xc0dc, 0x60d6, 0x2001, 0x4005, 0x0078, + 0x15bc, 0x0078, 0x15ba, 0x007c, 0x7810, 0xd0f4, 0x0040, 0x151c, + 0x2001, 0x4007, 0x0078, 0x15bc, 0xa006, 0x70c2, 0x70c6, 0x70ca, + 0x70ce, 0x70da, 0x70c0, 0xa03d, 0xa08a, 0x0040, 0x00c8, 0x152a, + 0x0079, 0x1531, 0x2100, 0xa08a, 0x0040, 0x00c8, 0x15c8, 0x0079, + 0x1571, 0x15ba, 0x1610, 0x15d9, 0x1648, 0x1680, 0x1680, 0x15d0, + 0x1c85, 0x168b, 0x15c8, 0x15dd, 0x15df, 0x15e1, 0x15e3, 0x1c8a, + 0x15c8, 0x1699, 0x16f6, 0x1b64, 0x1c7f, 0x15e5, 0x19d4, 0x1a16, + 0x1a4e, 0x1a9c, 0x198f, 0x199c, 0x19b0, 0x19c3, 0x17cb, 0x15c8, + 0x172d, 0x173a, 0x1746, 0x1752, 0x1768, 0x1774, 0x1777, 0x1783, + 0x178f, 0x1797, 0x17b3, 0x17bf, 0x15c8, 0x15c8, 0x15c8, 0x15c8, + 0x17d8, 0x17ea, 0x1806, 0x183c, 0x1864, 0x1874, 0x1877, 0x18a8, + 0x18d9, 0x18eb, 0x195e, 0x196e, 0x15c8, 0x15c8, 0x15c8, 0x15c8, + 0x197e, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x1caf, 0x1cb5, + 0x15c8, 0x15c8, 0x15c8, 0x1cb9, 0x1cfe, 0x15c8, 0x15c8, 0x15c8, + 0x15c8, 0x160a, 0x167a, 0x1693, 0x16f0, 0x1b5e, 0x15c8, 0x15c8, + 0x15c8, 0x15c8, 0x1d02, 0x1ca1, 0x1cab, 0x15c8, 0x15c8, 0x15c8, + 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, + 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, + 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, + 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, + 0x15c8, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x15bc, 0x73ce, + 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, 0x15bd, 0x2061, + 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, + 0x70c3, 0x4001, 0x0078, 0x15bd, 0x70c3, 0x4006, 0x0078, 0x15bd, + 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, + 0x15ba, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x15ba, 0x0078, + 0x15ba, 0x0078, 0x15ba, 0x0078, 0x15ba, 0x2091, 0x8000, 0x70c3, + 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, + 0x0008, 0x2001, 0x000d, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, + 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051, 0x0445, + 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091, 0x4080, + 0x0078, 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1613, + 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, + 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, 0x721e, + 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0040, 0x15ba, 0xa182, + 0x0040, 0x00c8, 0x162d, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, + 0x7007, 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0040, 0x1634, + 0x7007, 0x0002, 0xa084, 0x01e0, 0x0040, 0x1642, 0x70c3, 0x4002, + 0x0078, 0x15bd, 0x24a8, 0x53a5, 0x0078, 0x1624, 0x0078, 0x15ba, + 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x2098, + 0x20a1, 0x0030, 0x7003, 0x0000, 0x7007, 0x0006, 0x731a, 0x721e, + 0x7422, 0x7526, 0x2021, 0x0040, 0x7007, 0x0006, 0x81ff, 0x0040, + 0x15ba, 0xa182, 0x0040, 0x00c8, 0x1667, 0x2120, 0xa006, 0x2008, + 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, 0x0001, 0x7008, 0xd0fc, + 0x0040, 0x166e, 0xa084, 0x01e0, 0x0040, 0x165c, 0x70c3, 0x4002, + 0x0078, 0x15bd, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x164b, + 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x00c0, 0x1688, 0x200a, + 0x72ca, 0x0078, 0x15b9, 0x70c7, 0x0008, 0x70cb, 0x000d, 0x70cf, + 0x0008, 0x0078, 0x15ba, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, + 0x169c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, + 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x16eb, 0xa40a, + 0x0040, 0x16ac, 0x00c8, 0x15bc, 0x8001, 0x7872, 0xa084, 0xfc00, + 0x0040, 0x16b9, 0x78ac, 0xc085, 0x78ae, 0x2001, 0x4005, 0x0078, + 0x15bc, 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00, + 0x0040, 0x16d1, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f, + 0xa118, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0078, + 0x16db, 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, + 0x0000, 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, + 0x0040, 0x16e5, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, + 0x78ae, 0x0078, 0x16ee, 0x78ac, 0xc085, 0x78ae, 0x0078, 0x15ba, + 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x16f9, 0x2029, 0x0000, + 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, + 0x74d6, 0xa005, 0x0040, 0x1728, 0xa40a, 0x0040, 0x1709, 0x00c8, + 0x15bc, 0x8001, 0x7892, 0xa084, 0xfc00, 0x0040, 0x1716, 0x78ac, + 0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0078, 0x15bc, 0x7a9a, 0x7b9e, + 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0040, 0x1721, 0x7a10, 0xc2c5, + 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0078, 0x172b, + 0x78ac, 0xc0c5, 0x78ae, 0x0078, 0x15ba, 0x2009, 0x0000, 0x786c, + 0xa065, 0x0040, 0x1737, 0x8108, 0x6000, 0x0078, 0x1730, 0x7ac4, + 0x0078, 0x15b8, 0x2009, 0x4d48, 0x210c, 0x7810, 0xd0ec, 0x00c0, + 0x15b9, 0x2011, 0x4d88, 0x2214, 0x0078, 0x15b8, 0x2009, 0x4d49, + 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2011, 0x4d89, 0x2214, + 0x0078, 0x15b8, 0x2061, 0x4d40, 0x6128, 0x622c, 0x8214, 0x8214, + 0x8214, 0x7810, 0xd0ec, 0x00c0, 0x1766, 0x2061, 0x4d80, 0x6328, + 0x73da, 0x632c, 0x831c, 0x831c, 0x831c, 0x73de, 0x0078, 0x15b8, + 0x2009, 0x4d4c, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2011, + 0x4d8c, 0x2214, 0x0078, 0x15b8, 0x7918, 0x0078, 0x15b9, 0x2009, + 0x4d4d, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2011, 0x4d8d, + 0x2214, 0x0078, 0x15b8, 0x2009, 0x4d4e, 0x210c, 0x7810, 0xd0ec, + 0x00c0, 0x15b9, 0x2011, 0x4d8e, 0x2214, 0x0078, 0x15b8, 0x7920, + 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x7a24, 0x0078, 0x15b8, 0x71c4, + 0xd1fc, 0x00c0, 0x179f, 0x2011, 0x51c0, 0x0078, 0x17a1, 0x2011, + 0x5240, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, + 0x6a00, 0x6804, 0xd09c, 0x0040, 0x17b0, 0x6b08, 0x0078, 0x17b1, + 0x6b0c, 0x0078, 0x15b7, 0x77c4, 0x1078, 0x1dcb, 0x2091, 0x8000, + 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x15b7, 0x2061, + 0x4d40, 0x6118, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2061, 0x4d80, + 0x6218, 0x0078, 0x15b8, 0x77c4, 0x1078, 0x1dcb, 0x2091, 0x8000, + 0x6908, 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0078, 0x15b7, + 0x71c4, 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x00c8, 0x15b2, + 0x1078, 0x2735, 0xa384, 0x4000, 0x0040, 0x17e8, 0xa295, 0x0020, + 0x0078, 0x15b7, 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, 0x00c8, + 0x15b2, 0xd1bc, 0x00c0, 0x17f9, 0x2011, 0x4d48, 0x2204, 0x0078, + 0x17fd, 0x2011, 0x4d88, 0x2204, 0xc0bd, 0x007e, 0x2100, 0xc0bc, + 0x2012, 0x1078, 0x2692, 0x017f, 0x0078, 0x15b9, 0x71c4, 0x2021, + 0x4d49, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0078, 0x1815, 0x71c8, + 0x2021, 0x4d89, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x1834, 0x20a9, + 0x0008, 0x2204, 0xa106, 0x0040, 0x1824, 0x8210, 0x00f0, 0x1819, + 0x71c4, 0x72c8, 0x0078, 0x15b1, 0xa292, 0x1834, 0x027e, 0x2122, + 0x017f, 0x1078, 0x26b3, 0x7810, 0xd0ec, 0x00c0, 0x1832, 0xd3fc, + 0x0040, 0x180f, 0x0078, 0x15ba, 0x03e8, 0x00fa, 0x01f4, 0x02ee, + 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x4d40, 0x6128, 0x622c, + 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003, + 0x8003, 0x602e, 0x7810, 0xd0ec, 0x00c0, 0x1862, 0x027e, 0x017e, + 0x2061, 0x4d80, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70d8, + 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, 0x72de, + 0x017f, 0x027f, 0x0078, 0x15b8, 0x2061, 0x4d40, 0x6130, 0x70c4, + 0x6032, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2061, 0x4d80, 0x6230, + 0x70c8, 0x6032, 0x0078, 0x15b8, 0x7918, 0x0078, 0x15b9, 0x71c4, + 0xa184, 0xffcf, 0x0040, 0x1883, 0x7810, 0xd0ec, 0x00c0, 0x15b2, + 0x72c8, 0x0078, 0x15b1, 0x2011, 0x4d4d, 0x2204, 0x2112, 0x007e, + 0x2019, 0x0000, 0x1078, 0x271a, 0x7810, 0xd0ec, 0x0040, 0x1893, + 0x017f, 0x0078, 0x15b9, 0x71c8, 0xa184, 0xffcf, 0x0040, 0x189c, + 0x2110, 0x71c4, 0x0078, 0x15b1, 0x2011, 0x4d8d, 0x2204, 0x2112, + 0x007e, 0xc3fd, 0x1078, 0x271a, 0x027f, 0x017f, 0x0078, 0x15b8, + 0x71c4, 0xa182, 0x0010, 0x0048, 0x18b4, 0x7810, 0xd0ec, 0x00c0, + 0x15b2, 0x72c8, 0x0078, 0x15b1, 0x2011, 0x4d4e, 0x2204, 0x007e, + 0x2112, 0x2019, 0x0000, 0x1078, 0x26f8, 0x7810, 0xd0ec, 0x0040, + 0x18c4, 0x017f, 0x0078, 0x15b9, 0x71c8, 0xa182, 0x0010, 0x0048, + 0x18cd, 0x2110, 0x71c4, 0x0078, 0x15b1, 0x2011, 0x4d8e, 0x2204, + 0x007e, 0x2112, 0xc3fd, 0x1078, 0x26f8, 0x027f, 0x017f, 0x0078, + 0x15b8, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x15b1, 0xa284, + 0xfffd, 0x00c0, 0x15b1, 0x2100, 0x7920, 0x7822, 0x2200, 0x7a24, + 0x7826, 0x0078, 0x15b8, 0x71c4, 0xd1fc, 0x00c0, 0x18f3, 0x2011, + 0x51c0, 0x0078, 0x18f5, 0x2011, 0x5240, 0x8107, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0xa268, 0x2019, 0x0000, 0x72c8, 0x2091, + 0x8000, 0xa284, 0x0080, 0x0040, 0x190b, 0x6c14, 0x84ff, 0x00c0, + 0x190b, 0x6817, 0x0040, 0xa284, 0x0040, 0x0040, 0x1915, 0x6c10, + 0x84ff, 0x00c0, 0x1915, 0x6813, 0x0001, 0x6800, 0x007e, 0xa226, + 0x0040, 0x1932, 0x6a02, 0xd4ec, 0x0040, 0x191f, 0xc3a5, 0xd4e4, + 0x0040, 0x1923, 0xc39d, 0xd4f4, 0x0040, 0x1932, 0x810f, 0xd2f4, + 0x0040, 0x192e, 0x1078, 0x2777, 0x0078, 0x1932, 0x1078, 0x2755, + 0x0078, 0x1932, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1954, 0xa2a4, + 0x00ff, 0x7814, 0xd0e4, 0x00c0, 0x1945, 0xa482, 0x0028, 0x0048, + 0x1951, 0x0040, 0x1951, 0x0078, 0x1949, 0xa482, 0x0043, 0x0048, + 0x1951, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x2091, 0x8001, 0x0078, + 0x15b3, 0x6a0a, 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, + 0x6b0c, 0x71c4, 0x2091, 0x8001, 0x0078, 0x15b7, 0x77c4, 0x1078, + 0x1dcb, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, + 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, 0x15b7, 0x70c4, 0x2061, + 0x4d40, 0x6118, 0x601a, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x70c8, + 0x2061, 0x4d80, 0x6218, 0x601a, 0x0078, 0x15b8, 0x71c4, 0x72c8, + 0x73cc, 0xa182, 0x0010, 0x00c8, 0x15b2, 0x1078, 0x2799, 0xa384, + 0x4000, 0x0040, 0x198d, 0xa295, 0x0020, 0x0078, 0x15b7, 0x77c4, + 0x1078, 0x1dcb, 0x2091, 0x8000, 0x6a08, 0xc28d, 0x6a0a, 0x2091, + 0x8001, 0x2708, 0x0078, 0x15b8, 0x77c4, 0x1078, 0x1dcb, 0x2091, + 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, + 0x19ab, 0x1078, 0x25ea, 0x2091, 0x8001, 0x2708, 0x0078, 0x15b8, + 0x77c4, 0x1078, 0x1dcb, 0x2091, 0x8000, 0x6a08, 0xc295, 0x6a0a, + 0x6804, 0xa005, 0x0040, 0x19be, 0x1078, 0x25ea, 0x2091, 0x8001, + 0x2708, 0x0078, 0x15b8, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, + 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, 0x1de6, 0x2091, 0x8001, + 0x2708, 0x6a08, 0x0078, 0x15b8, 0x77c4, 0x7814, 0xd0e4, 0x00c0, + 0x19e8, 0xd7fc, 0x0040, 0x19e2, 0x1078, 0x1d4b, 0x0040, 0x19e8, + 0x0078, 0x15bc, 0x1078, 0x1d3b, 0x0040, 0x19e8, 0x0078, 0x15bc, + 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x1078, 0x1e6d, 0x00c0, + 0x1a12, 0x6818, 0xa005, 0x0040, 0x1a0c, 0x2708, 0x077e, 0x1078, + 0x27c9, 0x077f, 0x00c0, 0x1a0c, 0x2001, 0x0015, 0xd7fc, 0x00c0, + 0x1a05, 0x2061, 0x4d40, 0x0078, 0x1a08, 0xc0fd, 0x2061, 0x4d80, + 0x782a, 0x2091, 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, + 0x0078, 0x15bc, 0x2091, 0x8001, 0x0078, 0x15ba, 0x77c4, 0x7814, + 0xd0e4, 0x00c0, 0x1a2a, 0xd7fc, 0x0040, 0x1a24, 0x1078, 0x1d4b, + 0x0040, 0x1a2a, 0x0078, 0x15bc, 0x1078, 0x1d3b, 0x0040, 0x1a2a, + 0x0078, 0x15bc, 0x77c6, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, + 0x0020, 0x2091, 0x8000, 0x1078, 0x1de6, 0x2009, 0x0016, 0xd7fc, + 0x00c0, 0x1a3e, 0x2061, 0x4d40, 0x0078, 0x1a41, 0x2061, 0x4d80, + 0xc1fd, 0x6067, 0x0003, 0x607f, 0x0000, 0x6776, 0x6083, 0x000f, + 0x792a, 0x1078, 0x25ea, 0x2091, 0x8001, 0x007c, 0x77c8, 0x77ca, + 0x77c4, 0x77c6, 0x7814, 0xd0e4, 0x00c0, 0x1a65, 0xd7fc, 0x0040, + 0x1a5f, 0x1078, 0x1d4b, 0x0040, 0x1a65, 0x0078, 0x15bc, 0x1078, + 0x1d3b, 0x0040, 0x1a65, 0x0078, 0x15bc, 0xa7bc, 0xff00, 0x2091, + 0x8000, 0x2009, 0x0017, 0xd7fc, 0x00c0, 0x1a72, 0x2061, 0x4d40, + 0x0078, 0x1a75, 0x2061, 0x4d80, 0xc1fd, 0x607f, 0x0000, 0x6067, + 0x0002, 0x6776, 0x6083, 0x000f, 0x792a, 0x1078, 0x25ea, 0x2091, + 0x8001, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0010, 0x2091, + 0x8000, 0x70c8, 0xa005, 0x0040, 0x1a90, 0x60d4, 0xc0fd, 0x60d6, + 0x1078, 0x1de6, 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x1a90, 0x2091, 0x8001, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x1ab0, + 0x72c8, 0xd284, 0x0040, 0x1aaa, 0x1078, 0x1d4b, 0x0040, 0x1ab0, + 0x0078, 0x15bc, 0x1078, 0x1d3b, 0x0040, 0x1ab0, 0x0078, 0x15bc, + 0x72c8, 0x72ca, 0x78ac, 0xa084, 0x0003, 0x00c0, 0x1adb, 0x2039, + 0x0000, 0xd284, 0x0040, 0x1abd, 0xc7fd, 0x2041, 0x0021, 0x2049, + 0x0004, 0x2051, 0x0008, 0x1078, 0x1dcb, 0x2091, 0x8000, 0x6808, + 0xc0d4, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, + 0x00c0, 0x1ac3, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, + 0x0f00, 0x00c0, 0x1ac3, 0x2091, 0x8000, 0x72c8, 0xd284, 0x00c0, + 0x1aed, 0x7810, 0xd0ec, 0x0040, 0x1ae9, 0x2069, 0x0100, 0x0078, + 0x1aef, 0x2069, 0x0200, 0x0078, 0x1aef, 0x2069, 0x0100, 0x6808, + 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x0040, 0x1b0f, 0x684b, + 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, 0x0040, 0x1b01, 0x00f0, + 0x1afb, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0040, + 0x1b0b, 0x00f0, 0x1b05, 0x20a9, 0x00fa, 0x00f0, 0x1b0d, 0x2079, + 0x4d00, 0x2009, 0x0018, 0x72c8, 0xd284, 0x00c0, 0x1b1b, 0x2061, + 0x4d40, 0x0078, 0x1b1e, 0x2061, 0x4d80, 0xc1fd, 0x792a, 0x6067, + 0x0001, 0x6083, 0x000f, 0x60a7, 0x0000, 0x60a8, 0x60b2, 0x60b6, + 0x60d4, 0xd0b4, 0x0040, 0x1b38, 0xc0b4, 0x60d6, 0x0c7e, 0x60b8, + 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, + 0x60d4, 0xa084, 0x77ff, 0x60d6, 0x78ac, 0xc08d, 0x78ae, 0x681b, + 0x0047, 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x1b4b, 0x2069, + 0x4d40, 0x0078, 0x1b4d, 0x2069, 0x4d80, 0x71c4, 0x71c6, 0x6916, + 0x81ff, 0x00c0, 0x1b55, 0x68a7, 0x0001, 0x78ac, 0xc08c, 0x78ae, + 0xd084, 0x00c0, 0x1b5d, 0x1078, 0x1ecd, 0x007c, 0x75d8, 0x74dc, + 0x75da, 0x74de, 0x0078, 0x1b67, 0x2029, 0x0000, 0x2520, 0x71c4, + 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4d00, 0x7dde, + 0x7cda, 0x7bd6, 0x7ad2, 0x1078, 0x1da4, 0x0040, 0x1c69, 0x20a9, + 0x0005, 0x20a1, 0x4d14, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, + 0x2009, 0x0040, 0x1078, 0x1fb8, 0x0040, 0x1b8a, 0x1078, 0x1dad, + 0x0078, 0x1c69, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, 0x00c0, + 0x1b95, 0x007e, 0x1078, 0x2339, 0x007f, 0xa084, 0xff00, 0x8007, + 0x8009, 0x0040, 0x1c09, 0x0c7e, 0x2c68, 0x1078, 0x1da4, 0x0040, + 0x1bdb, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x1b9c, 0x609f, 0x0000, + 0x0c7f, 0x0c7e, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda, + 0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1c08, 0x2009, + 0x0040, 0x1078, 0x1fb8, 0x00c0, 0x1bf2, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x0002, 0x00c0, 0x1bdb, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x000a, 0x00c0, 0x1bd7, 0x017e, 0x1078, 0x2335, 0x017f, 0x2d00, + 0x6002, 0x0078, 0x1baa, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e30, + 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c6d, 0x2009, 0x0018, 0x6008, + 0xc0cd, 0x600a, 0x6004, 0x6086, 0x1078, 0x1d5b, 0x1078, 0x1dad, + 0x0078, 0x1c69, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e30, 0x0c7f, + 0x609f, 0x0000, 0x1078, 0x1c6d, 0x2009, 0x0018, 0x6087, 0x0103, + 0x601b, 0x0003, 0x1078, 0x1d5b, 0x1078, 0x1dad, 0x0078, 0x1c69, + 0x0c7f, 0x7814, 0xd0e4, 0x00c0, 0x1c2e, 0x6114, 0xd1fc, 0x0040, + 0x1c17, 0x1078, 0x1d4b, 0x0040, 0x1c2e, 0x0078, 0x1c1b, 0x1078, + 0x1d3b, 0x0040, 0x1c2e, 0x2029, 0x0000, 0x2520, 0x2009, 0x0018, + 0x73c8, 0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x1078, 0x1d5b, + 0x1078, 0x1dad, 0x2001, 0x4007, 0x0078, 0x15bc, 0x74c4, 0x73c8, + 0x72cc, 0x6014, 0x2091, 0x8000, 0x0e7e, 0x2009, 0x0012, 0xd0fc, + 0x00c0, 0x1c3e, 0x2071, 0x4d40, 0x0078, 0x1c41, 0x2071, 0x4d80, + 0xc1fd, 0x792a, 0x7067, 0x0005, 0x71d4, 0xc1dc, 0x71d6, 0x736a, + 0x726e, 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, 0x707e, 0xa02e, + 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x1c58, 0x1078, 0x45a7, + 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, + 0x0000, 0x6714, 0x6023, 0x0000, 0x1078, 0x25ea, 0x2091, 0x8001, + 0x007c, 0x70c3, 0x4005, 0x0078, 0x15bd, 0x20a9, 0x0005, 0x2099, + 0x4d14, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, 0xa210, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x71c4, + 0x70c7, 0x0000, 0x791e, 0x0078, 0x15ba, 0x71c4, 0x71c6, 0x2168, + 0x0078, 0x1c8c, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210, + 0x8d68, 0x8109, 0x00c0, 0x1c8e, 0xa285, 0x0000, 0x00c0, 0x1c9c, + 0x70c3, 0x4000, 0x0078, 0x1c9e, 0x70c3, 0x4003, 0x70ca, 0x0078, + 0x15bd, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x00c8, 0x15b2, + 0x7966, 0x0078, 0x15ba, 0x7964, 0x71c6, 0x0078, 0x15ba, 0x7900, + 0x71c6, 0x71c4, 0x7902, 0x0078, 0x15ba, 0x7900, 0x71c6, 0x0078, + 0x15ba, 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0040, 0x1cce, + 0x810c, 0x0048, 0x1cca, 0x8210, 0x810c, 0x810c, 0x0048, 0x1cca, + 0x8210, 0x810c, 0x81ff, 0x00c0, 0x15b3, 0x8210, 0x7a0e, 0xd28c, + 0x0040, 0x1cfa, 0x7910, 0xc1cd, 0x7912, 0x2009, 0x0021, 0x2019, + 0x0003, 0xd284, 0x0040, 0x1cf4, 0x8108, 0x2019, 0x0041, 0x2011, + 0x954e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, 0x2019, 0x0043, + 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, 0x2019, 0x0047, + 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x9553, 0x2112, 0x2011, + 0x9573, 0x2312, 0x7904, 0x7806, 0x0078, 0x15b9, 0x7804, 0x70c6, + 0x0078, 0x15ba, 0x71c4, 0xd1fc, 0x00c0, 0x1d0a, 0x2011, 0x51c0, + 0x0078, 0x1d0c, 0x2011, 0x5240, 0x8107, 0xa084, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa268, 0x6a14, 0xd2b4, 0x0040, 0x1d1b, 0x2011, + 0x0001, 0x0078, 0x1d1d, 0x2011, 0x0000, 0x6b0c, 0x0078, 0x15b7, + 0x017e, 0x7814, 0xd0f4, 0x0040, 0x1d2d, 0x2001, 0x4007, 0x70db, + 0x0000, 0xa18d, 0x0001, 0x0078, 0x1d39, 0xd0fc, 0x0040, 0x1d38, + 0x2001, 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d39, + 0xa006, 0x017f, 0x007c, 0x017e, 0x7814, 0xd0f4, 0x0040, 0x1d48, + 0x2001, 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0078, 0x1d49, + 0xa006, 0x017f, 0x007c, 0x017e, 0x7814, 0xd0fc, 0x0040, 0x1d58, + 0x2001, 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d59, + 0xa006, 0x017f, 0x007c, 0x7112, 0x721a, 0x731e, 0x7810, 0xd0c4, + 0x0040, 0x1d64, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, + 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, + 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0040, 0x1d81, + 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, + 0x1d84, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, + 0xa211, 0x7d10, 0xd5c4, 0x0040, 0x1d91, 0x7b84, 0xa319, 0x7c80, + 0xa421, 0x7008, 0xd0fc, 0x0040, 0x1d91, 0x7003, 0x0001, 0x7007, + 0x0006, 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0040, 0x1da1, 0x7322, + 0x7426, 0xa084, 0x01e0, 0x007c, 0x7848, 0xa065, 0x0040, 0x1dac, + 0x2c04, 0x784a, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x4d00, + 0x7848, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1db8, 0x1078, 0x290c, + 0x784a, 0x0f7f, 0x007c, 0x2011, 0x9700, 0x7a4a, 0x7bc4, 0x8319, + 0x0040, 0x1dc8, 0xa280, 0x0032, 0x2012, 0x2010, 0x0078, 0x1dbf, + 0x2013, 0x0000, 0x007c, 0x017e, 0x027e, 0xd7fc, 0x00c0, 0x1dd4, + 0x2011, 0x52c0, 0x0078, 0x1dd6, 0x2011, 0x72c0, 0xa784, 0x0f00, + 0x800b, 0xa784, 0x001f, 0x0040, 0x1de1, 0x8003, 0x8003, 0x8003, + 0x8003, 0xa105, 0xa268, 0x027f, 0x017f, 0x007c, 0x1078, 0x1dcb, + 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, + 0x690a, 0x0e7e, 0xd7fc, 0x00c0, 0x1dfb, 0x2009, 0x4d53, 0x2071, + 0x4d40, 0x0078, 0x1dff, 0x2009, 0x4d93, 0x2071, 0x4d80, 0x210c, + 0x6804, 0xa005, 0x0040, 0x1e0f, 0xa116, 0x00c0, 0x1e0f, 0x2060, + 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x1e12, 0x2009, + 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1e27, 0x6000, 0x6806, + 0x1078, 0x1e42, 0x1078, 0x2004, 0x6810, 0x7908, 0x8109, 0x790a, + 0x8001, 0x6812, 0x00c0, 0x1e12, 0x7910, 0xc1a5, 0x7912, 0x017f, + 0x6902, 0x6906, 0x2d00, 0x2060, 0x1078, 0x2a6d, 0x0e7f, 0x007c, + 0xa065, 0x0040, 0x1e41, 0x2008, 0x609c, 0xa005, 0x0040, 0x1e3e, + 0x2062, 0x609f, 0x0000, 0xa065, 0x0078, 0x1e34, 0x7848, 0x794a, + 0x2062, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, + 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, + 0x682c, 0x6022, 0x007c, 0x0e7e, 0xd7fc, 0x00c0, 0x1e5d, 0x2071, + 0x4d40, 0x2031, 0x4dc0, 0x0078, 0x1e61, 0x2071, 0x4d80, 0x2031, + 0x4fc0, 0x7050, 0xa08c, 0x0200, 0x00c0, 0x1e6b, 0xa608, 0x2d0a, + 0x8000, 0x7052, 0xa006, 0x0e7f, 0x007c, 0x0f7e, 0xd7fc, 0x00c0, + 0x1e75, 0x2079, 0x4d40, 0x0078, 0x1e77, 0x2079, 0x4d80, 0x1078, + 0x1dcb, 0x2091, 0x8000, 0x6804, 0x780a, 0xa065, 0x0040, 0x1ecb, + 0x0078, 0x1e89, 0x2c00, 0x780a, 0x2060, 0x6000, 0xa065, 0x0040, + 0x1ecb, 0x6010, 0xa306, 0x00c0, 0x1e82, 0x600c, 0xa206, 0x00c0, + 0x1e82, 0x2c28, 0x784c, 0xac06, 0x00c0, 0x1e98, 0x0078, 0x1ec8, + 0x6804, 0xac06, 0x00c0, 0x1ea6, 0x6000, 0x2060, 0x6806, 0xa005, + 0x00c0, 0x1ea6, 0x6803, 0x0000, 0x0078, 0x1eb0, 0x6400, 0x7808, + 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1eb0, 0x2c00, 0x6802, + 0x2560, 0x0f7f, 0x1078, 0x1e42, 0x0f7e, 0x601b, 0x0005, 0x6023, + 0x0020, 0x0f7f, 0x1078, 0x2004, 0x0f7e, 0x7908, 0x8109, 0x790a, + 0x6810, 0x8001, 0x6812, 0x00c0, 0x1ec8, 0x7810, 0xc0a5, 0x7812, + 0x2001, 0xffff, 0xa005, 0x0f7f, 0x007c, 0x077e, 0x2700, 0x2039, + 0x0000, 0xd0fc, 0x0040, 0x1ed5, 0xc7fd, 0x2041, 0x0021, 0x2049, + 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x1de6, 0x8738, + 0xa784, 0x001f, 0x00c0, 0x1edd, 0xa7bc, 0xff00, 0x873f, 0x8738, + 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1edd, 0x2091, 0x8001, 0x077f, + 0x007c, 0x786c, 0x2009, 0x9574, 0x210c, 0xa10d, 0x0040, 0x1efb, + 0xa065, 0x0078, 0x2356, 0x2061, 0x0000, 0x6018, 0xd084, 0x00c0, + 0x1f1b, 0x7810, 0xd08c, 0x0040, 0x1f0c, 0xc08c, 0x7812, 0xc7fc, + 0x2069, 0x4d40, 0x0078, 0x1f11, 0xc08d, 0x7812, 0x2069, 0x4d80, + 0xc7fd, 0x2091, 0x8000, 0x681c, 0x681f, 0x0000, 0x2091, 0x8001, + 0xa005, 0x00c0, 0x1f1c, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1f22, + 0x1078, 0x290c, 0x0079, 0x1f24, 0x1f34, 0x1f37, 0x1f3d, 0x1f41, + 0x1f35, 0x1f45, 0x1f35, 0x1f35, 0x1f35, 0x1f4b, 0x1f7c, 0x1f80, + 0x1f86, 0x1f9b, 0x1f35, 0x1f35, 0x007c, 0x1078, 0x290c, 0x1078, + 0x1ecd, 0x2001, 0x8001, 0x0078, 0x1fa7, 0x2001, 0x8003, 0x0078, + 0x1fa7, 0x2001, 0x8004, 0x0078, 0x1fa7, 0x1078, 0x1ecd, 0x2001, + 0x8006, 0x0078, 0x1fa7, 0x2091, 0x8000, 0x077e, 0xd7fc, 0x00c0, + 0x1f57, 0x2069, 0x4d40, 0x2039, 0x0009, 0x0078, 0x1f5b, 0x2069, + 0x4d80, 0x2039, 0x0009, 0x6800, 0xa086, 0x0000, 0x0040, 0x1f65, + 0x007f, 0x6f1e, 0x2091, 0x8001, 0x007c, 0x6874, 0x077f, 0xa0bc, + 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x1078, + 0x1de6, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1f6f, 0x2091, 0x8001, + 0x2001, 0x800a, 0x0078, 0x1fa7, 0x2001, 0x800c, 0x0078, 0x1fa7, + 0x1078, 0x1ecd, 0x2001, 0x800d, 0x0078, 0x1fa7, 0x7814, 0xd0e4, + 0x00c0, 0x1f99, 0xd0ec, 0x0040, 0x1f93, 0xd7fc, 0x0040, 0x1f93, + 0x78e4, 0x0078, 0x1f94, 0x78e0, 0x70c6, 0x2001, 0x800e, 0x0078, + 0x1fa7, 0x0078, 0x1f35, 0xd7fc, 0x0040, 0x1fa1, 0x78ec, 0x0078, + 0x1fa2, 0x78e8, 0x70c6, 0x2001, 0x000d, 0x0078, 0x1fa7, 0x70c2, + 0xd7fc, 0x00c0, 0x1faf, 0x70db, 0x0000, 0x0078, 0x1fb1, 0x70db, + 0x0001, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, + 0xac80, 0x0001, 0x81ff, 0x0040, 0x1fe3, 0x2099, 0x0030, 0x20a0, + 0x700c, 0xa084, 0x03ff, 0x0040, 0x1fc5, 0x7018, 0x007e, 0x701c, + 0x007e, 0x7020, 0x007e, 0x7024, 0x007e, 0x7112, 0x81ac, 0x721a, + 0x731e, 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, + 0x800b, 0x00c8, 0x1fd7, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, + 0x1fe3, 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x007f, + 0x7026, 0x007f, 0x7022, 0x007f, 0x701e, 0x007f, 0x701a, 0x007c, + 0x2011, 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x6803, 0xfd00, + 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, + 0x8109, 0x00c0, 0x1ff4, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, + 0x0000, 0x7868, 0xa005, 0x796a, 0x0040, 0x2011, 0x2c02, 0x0078, + 0x2012, 0x796e, 0x007c, 0x0c7e, 0x2061, 0x4d00, 0x6887, 0x0103, + 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x2023, + 0x2d02, 0x0078, 0x2024, 0x616e, 0x0c7f, 0x007c, 0x2091, 0x8000, + 0x2c04, 0x786e, 0xa005, 0x00c0, 0x202e, 0x786a, 0x2091, 0x8001, + 0x609c, 0xa005, 0x0040, 0x2047, 0x0c7e, 0x2060, 0x2008, 0x609c, + 0xa005, 0x0040, 0x2043, 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, + 0xa005, 0x00c0, 0x203b, 0x7848, 0x794a, 0x2062, 0x0c7f, 0x7848, + 0x2062, 0x609f, 0x0000, 0xac85, 0x0000, 0x00c0, 0x2051, 0x1078, + 0x290c, 0x784a, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, + 0x818e, 0x00c8, 0x205c, 0xa200, 0x00f0, 0x2057, 0x8086, 0x818e, + 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x2082, 0xa11a, + 0x00c8, 0x2082, 0x8213, 0x818d, 0x0048, 0x2075, 0xa11a, 0x00c8, + 0x2076, 0x00f0, 0x206a, 0x0078, 0x207a, 0xa11a, 0x2308, 0x8210, + 0x00f0, 0x206a, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, + 0x157f, 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x207e, + 0x7d74, 0x70d0, 0xa506, 0x0040, 0x216e, 0x7810, 0x2050, 0x7800, + 0xd08c, 0x0040, 0x20aa, 0xdaec, 0x0040, 0x20aa, 0x0e7e, 0x2091, + 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x20a7, 0x7008, + 0x0e7f, 0xa086, 0x0008, 0x0040, 0x20aa, 0x0078, 0x216e, 0x0e7f, + 0x0078, 0x216e, 0x1078, 0x1da4, 0x0040, 0x216e, 0xa046, 0x7970, + 0x2500, 0x8000, 0xa112, 0x2009, 0x0040, 0x00c8, 0x20b9, 0x0078, + 0x20c0, 0x72d0, 0xa206, 0x0040, 0x20c0, 0x8840, 0x2009, 0x0080, + 0x0c7e, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, 0x0020, + 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0040, 0x20d2, + 0x1078, 0x1da4, 0x7008, 0xd0fc, 0x0040, 0x20d2, 0x7007, 0x0002, + 0x2091, 0x8001, 0xa08c, 0x01e0, 0x00c0, 0x2109, 0x53a5, 0x8cff, + 0x00c0, 0x20e7, 0x88ff, 0x0040, 0x2158, 0x0078, 0x20f1, 0x2c00, + 0x788e, 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0078, + 0x2158, 0xa046, 0x7218, 0x731c, 0xdac4, 0x0040, 0x20f9, 0x7420, + 0x7524, 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, 0x0000, 0xa5ab, + 0x0000, 0x721a, 0x731e, 0xdac4, 0x0040, 0x2109, 0x7422, 0x7526, + 0xa006, 0x7007, 0x0004, 0x0040, 0x2158, 0x8cff, 0x0040, 0x2112, + 0x1078, 0x1dad, 0x0c7f, 0x1078, 0x1dad, 0xa046, 0x7888, 0x8000, + 0x788a, 0xa086, 0x0002, 0x0040, 0x2138, 0x7a7c, 0x7b78, 0xdac4, + 0x0040, 0x2124, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, + 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, + 0x731e, 0xdac4, 0x0040, 0x216e, 0x7422, 0x7526, 0x0078, 0x216e, + 0x6014, 0xd0fc, 0x00c0, 0x2140, 0x2069, 0x4d40, 0x0078, 0x2142, + 0x2069, 0x4d80, 0x2091, 0x8000, 0x681f, 0x0002, 0x88ff, 0x0040, + 0x214e, 0xa046, 0x788c, 0x2060, 0x0078, 0x2138, 0x788b, 0x0000, + 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0078, 0x216e, + 0x0c7f, 0x788b, 0x0000, 0x1078, 0x2307, 0x6004, 0xa084, 0x000f, + 0x1078, 0x216f, 0x88ff, 0x0040, 0x216c, 0x788c, 0x2060, 0x6004, + 0xa084, 0x000f, 0x1078, 0x216f, 0x0078, 0x2088, 0x007c, 0x0079, + 0x2171, 0x2181, 0x219f, 0x21bd, 0x2181, 0x21ce, 0x2192, 0x2181, + 0x2181, 0x2181, 0x219d, 0x21bb, 0x2181, 0x2181, 0x2181, 0x2181, + 0x2181, 0x2039, 0x0400, 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, + 0x600a, 0x1078, 0x2211, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, + 0x22f1, 0x007c, 0x78bc, 0xd0c4, 0x0040, 0x2198, 0x0078, 0x2181, + 0x601c, 0xc0bd, 0x601e, 0x0078, 0x21a5, 0x1078, 0x2339, 0x78bc, + 0xd0c4, 0x0040, 0x21a5, 0x0078, 0x2181, 0x78bf, 0x0000, 0x6004, + 0x8007, 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0040, 0x21b8, 0x1078, + 0x2211, 0x0040, 0x21b8, 0x78bc, 0xc0c5, 0x78be, 0x0078, 0x21ba, + 0x0078, 0x2230, 0x007c, 0x1078, 0x2335, 0x78bc, 0xa08c, 0x0e00, + 0x00c0, 0x21c5, 0xd0c4, 0x00c0, 0x21c7, 0x0078, 0x2181, 0x1078, + 0x2211, 0x00c0, 0x21cd, 0x0078, 0x2230, 0x007c, 0x78bc, 0xd0c4, + 0x0040, 0x21d4, 0x0078, 0x2181, 0x78bf, 0x0000, 0x6714, 0x2011, + 0x0001, 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, 0x21f4, + 0xa7bc, 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040, 0x21f4, + 0xa7bc, 0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, + 0x0040, 0x21f4, 0x0078, 0x220e, 0x1078, 0x1dcb, 0x2d00, 0x2091, + 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde, + 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, 0x00f0, 0x21f7, 0x8211, + 0x0040, 0x220e, 0x20a9, 0x0100, 0x0078, 0x21f7, 0x1078, 0x1dad, + 0x007c, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, 0x00c0, + 0x221c, 0x78ba, 0x0078, 0x2224, 0x689e, 0x2d00, 0x6002, 0x78b8, + 0xad06, 0x00c0, 0x2224, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x00c0, + 0x222f, 0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x007c, + 0x0e7e, 0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, + 0x60a2, 0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0040, + 0x2243, 0x1078, 0x45a7, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, + 0x2071, 0x4d80, 0xd7fc, 0x00c0, 0x224f, 0x2071, 0x4d40, 0xa784, + 0x0f00, 0x800b, 0xa784, 0x001f, 0x0040, 0x225a, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, 0x8007, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, 0x60c2, 0x2091, + 0x8000, 0x7810, 0xd0f4, 0x00c0, 0x2274, 0x6e08, 0xd684, 0x0040, + 0x228a, 0xd9fc, 0x00c0, 0x228a, 0x2091, 0x8001, 0x1078, 0x1e42, + 0x2091, 0x8000, 0x1078, 0x2004, 0x2091, 0x8001, 0x7814, 0xd0e4, + 0x00c0, 0x22ef, 0x7810, 0xd0f4, 0x0040, 0x22ef, 0x601b, 0x0021, + 0x0078, 0x22ef, 0x6024, 0xa096, 0x0001, 0x00c0, 0x2291, 0x8000, + 0x6026, 0x6a10, 0x6814, 0xa202, 0x0048, 0x22a4, 0x0040, 0x22a4, + 0x2091, 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, + 0x1078, 0x22f1, 0x0078, 0x22ef, 0x2c08, 0xd9fc, 0x0040, 0x22cc, + 0x6800, 0xa065, 0x0040, 0x22cc, 0x6a04, 0x7000, 0xa084, 0x0002, + 0x0040, 0x22c2, 0x704c, 0xa206, 0x00c0, 0x22c2, 0x6b04, 0x2160, + 0x2304, 0x6002, 0xa005, 0x00c0, 0x22be, 0x6902, 0x2260, 0x6102, + 0x0078, 0x22d8, 0x2d00, 0x2060, 0x1078, 0x2a6d, 0x6e08, 0x2160, + 0x6202, 0x6906, 0x0078, 0x22d8, 0x6800, 0x6902, 0xa065, 0x0040, + 0x22d4, 0x6102, 0x0078, 0x22d5, 0x6906, 0x2160, 0x6003, 0x0000, + 0x2160, 0xd9fc, 0x0040, 0x22df, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, + 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, + 0x0040, 0x22ef, 0xa6b6, 0x0040, 0x6e0a, 0x1078, 0x1e53, 0x0e7f, + 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x1078, 0x2004, + 0x2091, 0x8001, 0x78b8, 0xa065, 0x0040, 0x2304, 0x609c, 0x78ba, + 0x609f, 0x0000, 0x0078, 0x22f1, 0x78b6, 0x78ba, 0x007c, 0x7970, + 0x7874, 0x2818, 0xd384, 0x0040, 0x2311, 0x8000, 0xa112, 0x0048, + 0x2316, 0x8000, 0xa112, 0x00c8, 0x2326, 0xc384, 0x7a7c, 0x721a, + 0x7a78, 0x721e, 0xdac4, 0x0040, 0x2321, 0x7a84, 0x7222, 0x7a80, + 0x7226, 0xa006, 0xd384, 0x0040, 0x2326, 0x8000, 0x7876, 0x70d2, + 0x781c, 0xa005, 0x0040, 0x2334, 0x8001, 0x781e, 0x00c0, 0x2334, + 0x0068, 0x2334, 0x2091, 0x4080, 0x007c, 0x2039, 0x234d, 0x0078, + 0x233b, 0x2039, 0x2353, 0x2704, 0xa005, 0x0040, 0x234c, 0xac00, + 0x2068, 0x6908, 0x6810, 0x6912, 0x680a, 0x690c, 0x6814, 0x6916, + 0x680e, 0x8738, 0x0078, 0x233b, 0x007c, 0x0003, 0x0009, 0x000f, + 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x2041, 0x0000, + 0x780c, 0x0079, 0x235b, 0x252d, 0x2500, 0x235f, 0x23d8, 0x2039, + 0x9574, 0x2734, 0x7d10, 0x0078, 0x237f, 0x6084, 0xa086, 0x0103, + 0x00c0, 0x23c1, 0x6114, 0x6018, 0xa105, 0x0040, 0x2374, 0x86ff, + 0x00c0, 0x2390, 0x0078, 0x23c1, 0x8603, 0xa080, 0x9555, 0x620c, + 0x2202, 0x8000, 0x6210, 0x2202, 0x1078, 0x2026, 0x8630, 0xa68e, + 0x000f, 0x0040, 0x244c, 0x786c, 0xa065, 0x00c0, 0x2365, 0x7808, + 0xa602, 0x00c8, 0x2390, 0xd5ac, 0x00c0, 0x2390, 0x263a, 0x007c, + 0xa682, 0x0003, 0x00c8, 0x244c, 0x2091, 0x8000, 0x2069, 0x0000, + 0x6818, 0xd084, 0x00c0, 0x23bc, 0x2011, 0x9555, 0x2204, 0x70c6, + 0x8210, 0x2204, 0x70ca, 0xd684, 0x00c0, 0x23ac, 0x8210, 0x2204, + 0x70da, 0x8210, 0x2204, 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, + 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, + 0x8001, 0x203b, 0x0000, 0x007c, 0x7810, 0xc0ad, 0x7812, 0x0078, + 0x244c, 0x263a, 0x1078, 0x2537, 0x00c0, 0x255a, 0x786c, 0xa065, + 0x00c0, 0x2365, 0x2091, 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, + 0x0040, 0x23d3, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0078, 0x255a, + 0x2039, 0x9574, 0x2734, 0x7d10, 0x0078, 0x23f4, 0x6084, 0xa086, + 0x0103, 0x00c0, 0x2435, 0x6114, 0x6018, 0xa105, 0x0040, 0x23ed, + 0x86ff, 0x00c0, 0x2405, 0x0078, 0x2435, 0xa680, 0x9555, 0x620c, + 0x2202, 0x1078, 0x2026, 0x8630, 0xa68e, 0x001e, 0x0040, 0x244c, + 0x786c, 0xa065, 0x00c0, 0x23de, 0x7808, 0xa602, 0x00c8, 0x2405, + 0xd5ac, 0x00c0, 0x2405, 0x263a, 0x007c, 0xa682, 0x0006, 0x00c8, + 0x244c, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, + 0x2430, 0x2011, 0x9555, 0x2009, 0x954e, 0x26a8, 0x211c, 0x2204, + 0x201a, 0x8108, 0x8210, 0x00f0, 0x2416, 0xa685, 0x8030, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, - 0x2091, 0x8001, 0xa006, 0x2009, 0x9275, 0x200a, 0x203a, 0x007c, - 0x7810, 0xc0ad, 0x7812, 0x0078, 0x2454, 0x263a, 0x1078, 0x253f, - 0x00c0, 0x254e, 0x786c, 0xa065, 0x00c0, 0x23eb, 0x2091, 0x8000, - 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x244f, 0xc0ad, 0x7812, - 0x2091, 0x8001, 0x0078, 0x254e, 0x2091, 0x8000, 0x7007, 0x0004, - 0x7994, 0x70d4, 0xa102, 0x0048, 0x2465, 0x0040, 0x246f, 0x7b90, - 0xa302, 0x00c0, 0x246f, 0x0078, 0x2468, 0x8002, 0x00c0, 0x246f, + 0x2091, 0x8001, 0xa006, 0x2009, 0x9575, 0x200a, 0x203a, 0x007c, + 0x7810, 0xc0ad, 0x7812, 0x0078, 0x244c, 0x263a, 0x1078, 0x2537, + 0x00c0, 0x255a, 0x786c, 0xa065, 0x00c0, 0x23de, 0x2091, 0x8000, + 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x2447, 0xc0ad, 0x7812, + 0x2091, 0x8001, 0x0078, 0x255a, 0x2091, 0x8000, 0x7007, 0x0004, + 0x7994, 0x70d4, 0xa102, 0x0048, 0x245d, 0x0040, 0x2467, 0x7b90, + 0xa302, 0x00c0, 0x2467, 0x0078, 0x2460, 0x8002, 0x00c0, 0x2467, 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x007c, 0xa184, - 0xff00, 0x0040, 0x247c, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, - 0x8007, 0xa100, 0x0078, 0x247f, 0x8107, 0x8004, 0x8004, 0x7a9c, + 0xff00, 0x0040, 0x2474, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, + 0x8007, 0xa100, 0x0078, 0x2477, 0x8107, 0x8004, 0x8004, 0x7a9c, 0xa210, 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0040, - 0x248f, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, - 0x0030, 0x7003, 0x0000, 0x2009, 0x9254, 0x260a, 0x8109, 0x2198, - 0x2104, 0xd084, 0x0040, 0x249d, 0x8633, 0xa6b0, 0x0002, 0x26a8, + 0x2487, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, + 0x0030, 0x7003, 0x0000, 0x2009, 0x9554, 0x260a, 0x8109, 0x2198, + 0x2104, 0xd084, 0x0040, 0x2495, 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, - 0xa10a, 0x00c8, 0x24ac, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, - 0x0040, 0x24bb, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, - 0xa100, 0x0078, 0x24be, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, - 0x7a78, 0xa006, 0xa211, 0xd4c4, 0x0040, 0x24ca, 0x7b84, 0xa319, - 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0040, 0x24ca, 0xa084, 0x01e0, - 0x0040, 0x24ef, 0x7d10, 0x2031, 0x9254, 0x2634, 0x78a8, 0x8000, - 0x78aa, 0xd08c, 0x00c0, 0x24e4, 0x7007, 0x0006, 0x7004, 0xd094, - 0x00c0, 0x24de, 0x0078, 0x2456, 0x2069, 0x4a47, 0x206b, 0x0003, - 0x78ac, 0xa085, 0x0300, 0x78ae, 0xa006, 0x0078, 0x24f8, 0x2030, + 0xa10a, 0x00c8, 0x24a4, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, + 0x0040, 0x24b3, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, + 0xa100, 0x0078, 0x24b6, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, + 0x7a78, 0xa006, 0xa211, 0xd4c4, 0x0040, 0x24c2, 0x7b84, 0xa319, + 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0040, 0x24c2, 0xa084, 0x01e0, + 0x0040, 0x24e7, 0x7d10, 0x2031, 0x9554, 0x2634, 0x78a8, 0x8000, + 0x78aa, 0xd08c, 0x00c0, 0x24dc, 0x7007, 0x0006, 0x7004, 0xd094, + 0x00c0, 0x24d6, 0x0078, 0x244e, 0x2069, 0x4d47, 0x206b, 0x0003, + 0x78ac, 0xa085, 0x0300, 0x78ae, 0xa006, 0x0078, 0x24f0, 0x2030, 0x75d6, 0x2091, 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091, 0x8001, 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, - 0x711a, 0x721e, 0xd5c4, 0x0040, 0x2507, 0x7322, 0x7426, 0x007c, - 0x6084, 0xa086, 0x0103, 0x00c0, 0x252b, 0x6114, 0x6018, 0xa105, - 0x00c0, 0x252b, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x252b, + 0x711a, 0x721e, 0xd5c4, 0x0040, 0x24ff, 0x7322, 0x7426, 0x007c, + 0x6084, 0xa086, 0x0103, 0x00c0, 0x2523, 0x6114, 0x6018, 0xa105, + 0x00c0, 0x2523, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x2523, 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, - 0x2091, 0x4080, 0x1078, 0x203d, 0x0068, 0x252a, 0x786c, 0xa065, - 0x00c0, 0x2508, 0x007c, 0x1078, 0x253f, 0x00c0, 0x254e, 0x786c, - 0xa065, 0x00c0, 0x2508, 0x0078, 0x254e, 0x1078, 0x253f, 0x00c0, - 0x254e, 0x786c, 0xa065, 0x00c0, 0x2535, 0x0078, 0x254e, 0x1078, - 0x2554, 0x00c0, 0x2546, 0xa085, 0x0001, 0x007c, 0x1078, 0x2563, - 0x00c0, 0x254c, 0x2041, 0x0001, 0x7d10, 0x007c, 0x88ff, 0x0040, - 0x2553, 0x2091, 0x4080, 0x007c, 0x7b90, 0x7994, 0x70d4, 0xa102, - 0x00c0, 0x255d, 0xa385, 0x0000, 0x007c, 0x0048, 0x2561, 0xa302, - 0x007c, 0x8002, 0x007c, 0x7810, 0xd0ec, 0x0040, 0x257b, 0x0e7e, - 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2578, - 0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040, 0x257b, 0x0078, 0x25cc, - 0x0e7f, 0x0078, 0x25cc, 0xa184, 0xff00, 0x0040, 0x2588, 0x810f, - 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, 0x258b, - 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa210, - 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, 0xa005, - 0x0040, 0x259c, 0x2009, 0x0040, 0x1078, 0x1d92, 0x0040, 0x25be, - 0x78a8, 0x8000, 0x78aa, 0xd08c, 0x00c0, 0x25cc, 0x6014, 0xd0fc, - 0x00c0, 0x25ae, 0x2069, 0x4a40, 0x0078, 0x25b0, 0x2069, 0x4a80, - 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab, 0x0000, 0x78ac, 0xa085, - 0x0300, 0x78ae, 0x2091, 0x8001, 0x0078, 0x25cc, 0x78ab, 0x0000, - 0x1078, 0x203d, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8, 0x25c9, - 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, - 0x007c, 0x2138, 0xd7fc, 0x00c0, 0x25d9, 0x2009, 0x4a59, 0x0078, - 0x25db, 0x2009, 0x4a99, 0x2091, 0x8000, 0x200a, 0x0f7e, 0xd7fc, - 0x00c0, 0x25f2, 0x2009, 0x4a40, 0x2001, 0x4a04, 0x2004, 0xd0ec, - 0x0040, 0x25ee, 0x2079, 0x0100, 0x0078, 0x25f6, 0x2079, 0x0200, - 0x0078, 0x25f6, 0x2009, 0x4a80, 0x2079, 0x0100, 0x2104, 0xa086, - 0x0000, 0x00c0, 0x260f, 0xd7fc, 0x00c0, 0x2602, 0x2009, 0x4a45, - 0x0078, 0x2604, 0x2009, 0x4a85, 0x2104, 0xa005, 0x00c0, 0x260f, - 0x7830, 0xa084, 0x00c0, 0x00c0, 0x260f, 0x781b, 0x0045, 0x0f7f, - 0x007c, 0x2009, 0x0002, 0x2069, 0x4a00, 0x6810, 0xd0ec, 0x00c0, - 0x2672, 0x2071, 0x4a80, 0x2079, 0x0100, 0x2021, 0x4cbf, 0x784b, - 0x000f, 0x2019, 0x4205, 0xd184, 0x0040, 0x2632, 0x6810, 0xd0ec, - 0x0040, 0x262e, 0x20a1, 0x012b, 0x0078, 0x2634, 0x20a1, 0x022b, - 0x0078, 0x2634, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, 0x2641, - 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, 0x0078, - 0x2634, 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, - 0x8020, 0x00f0, 0x2645, 0x7003, 0x0000, 0x017e, 0xd18c, 0x2009, - 0x0000, 0x0040, 0x2654, 0xc1bd, 0x1078, 0x283d, 0x017f, 0x7020, - 0xa084, 0x000f, 0x007e, 0x6814, 0xd0e4, 0x007f, 0x00c0, 0x2664, - 0xa085, 0x6340, 0x0078, 0x2666, 0xa085, 0x62c0, 0x7806, 0x780f, - 0x9200, 0x7843, 0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7456, - 0x7053, 0x0000, 0x8109, 0x0040, 0x2685, 0x2071, 0x4a40, 0x6810, - 0xd0ec, 0x0040, 0x267f, 0x2079, 0x0100, 0x0078, 0x2681, 0x2079, - 0x0200, 0x2021, 0x4abf, 0x0078, 0x261f, 0x007c, 0x017e, 0xd1bc, - 0x00c0, 0x269a, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, - 0x0040, 0x2696, 0x2011, 0x0101, 0x0078, 0x269c, 0x2011, 0x0201, - 0x0078, 0x269c, 0x2011, 0x0101, 0xa18c, 0x000f, 0x2204, 0xa084, - 0xfff0, 0xa105, 0x2012, 0x017f, 0x1078, 0x283d, 0x007c, 0xd3fc, - 0x00c0, 0x26ba, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, - 0x0040, 0x26b6, 0x2011, 0x0101, 0x0078, 0x26bc, 0x2011, 0x0201, - 0x0078, 0x26bc, 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x00f0, - 0x26be, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, - 0x007c, 0x2019, 0x0002, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x0040, - 0x26d6, 0x8319, 0x2009, 0x0101, 0x0078, 0x26d8, 0x2009, 0x0101, - 0x20a9, 0x0005, 0x8213, 0x00f0, 0x26da, 0xa294, 0x00e0, 0x2104, - 0xa084, 0xff1f, 0xa205, 0x200a, 0x8319, 0x0040, 0x26eb, 0x2009, - 0x0201, 0x0078, 0x26d8, 0x007c, 0xd3fc, 0x00c0, 0x26ff, 0x007e, - 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x26fb, 0x2011, - 0x0101, 0x0078, 0x2701, 0x2011, 0x0201, 0x0078, 0x2701, 0x2011, - 0x0101, 0x20a9, 0x000c, 0x810b, 0x00f0, 0x2703, 0xa18c, 0xf000, - 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x007c, 0xd3fc, 0x00c0, - 0x2721, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, - 0x271d, 0x2011, 0x0102, 0x0078, 0x2723, 0x2011, 0x0202, 0x0078, - 0x2723, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, - 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x273d, 0x007e, 0x2001, 0x4a04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2739, 0x2061, 0x0100, 0x0078, - 0x273f, 0x2061, 0x0200, 0x0078, 0x273f, 0x2061, 0x0100, 0xc1bc, - 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x62ac, 0x63ac, 0x0c7f, - 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x275d, 0x007e, 0x2001, 0x4a04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2759, 0x2061, 0x0100, 0x0078, - 0x275f, 0x2061, 0x0200, 0x0078, 0x275f, 0x2061, 0x0100, 0xc1bc, - 0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, - 0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x277f, 0x007e, - 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x277b, 0x2061, - 0x0100, 0x0078, 0x2781, 0x2061, 0x0200, 0x0078, 0x2781, 0x2061, - 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, - 0xa085, 0x0020, 0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, - 0x27a1, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, - 0x279d, 0x2061, 0x0100, 0x0078, 0x27a3, 0x2061, 0x0200, 0x0078, - 0x27a3, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, - 0x609a, 0x60a4, 0xa28c, 0x0020, 0x0040, 0x27b1, 0xc2ac, 0xa39d, - 0x4000, 0xc3fc, 0xd3b4, 0x00c0, 0x27b6, 0xc3fd, 0x62ae, 0x2010, - 0x60a4, 0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, - 0x0e7e, 0x6818, 0xa005, 0x0040, 0x281b, 0xd1fc, 0x0040, 0x27cc, - 0x2061, 0x91d0, 0x0078, 0x27ce, 0x2061, 0x90c0, 0x1078, 0x2823, - 0x0040, 0x2801, 0x20a9, 0x0101, 0xd1fc, 0x0040, 0x27db, 0x2061, - 0x90d0, 0x0078, 0x27dd, 0x2061, 0x8fc0, 0x0c7e, 0x1078, 0x2823, - 0x0040, 0x27e8, 0x0c7f, 0x8c60, 0x00f0, 0x27dd, 0x0078, 0x281b, - 0x007f, 0xd1fc, 0x0040, 0x27f2, 0xa082, 0x90d0, 0x2071, 0x4a80, - 0x0078, 0x27f6, 0xa082, 0x8fc0, 0x2071, 0x4a40, 0x707a, 0x7176, - 0x2001, 0x0004, 0x7066, 0x7083, 0x000f, 0x1078, 0x25d1, 0x0078, - 0x2817, 0xd1fc, 0x00c0, 0x2808, 0x2071, 0x4a40, 0x0078, 0x280a, - 0x2071, 0x4a80, 0x6020, 0xc0dd, 0x6022, 0x7176, 0x2c00, 0x707e, - 0x2001, 0x0006, 0x7066, 0x7083, 0x000f, 0x1078, 0x25d1, 0x2001, - 0x0000, 0x0078, 0x281d, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, - 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040, 0x283a, 0x2060, - 0x6010, 0xa306, 0x00c0, 0x2837, 0x600c, 0xa206, 0x00c0, 0x2837, - 0x6014, 0xa106, 0x00c0, 0x2837, 0xa006, 0x0078, 0x283c, 0x6000, - 0x0078, 0x2824, 0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x017e, - 0xd1bc, 0x00c0, 0x2855, 0x2079, 0x4a40, 0x007e, 0x2001, 0x4a04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2851, 0x2071, 0x0100, 0x0078, - 0x2859, 0x2071, 0x0200, 0x0078, 0x2859, 0x2079, 0x4a80, 0x2071, - 0x0100, 0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x00c0, 0x2863, - 0x017f, 0x0078, 0x287e, 0x810b, 0x810b, 0x810b, 0x810b, 0x007f, - 0xd0bc, 0x00c0, 0x287b, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, - 0x007f, 0x0040, 0x2877, 0xa18d, 0x0f00, 0x0078, 0x287d, 0xa18d, - 0x0f00, 0x0078, 0x287d, 0xa18d, 0x0800, 0x2104, 0x0e7f, 0x0f7f, - 0x007c, 0x0e7e, 0x2001, 0x4a01, 0x2004, 0xd0ac, 0x00c0, 0x28ea, - 0x68e4, 0xd0ac, 0x0040, 0x28ea, 0xa084, 0x0006, 0x00c0, 0x28ea, - 0x6014, 0xd0fc, 0x00c0, 0x2898, 0x2071, 0x4ec0, 0x0078, 0x289a, - 0x2071, 0x4f40, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, - 0xae70, 0x7004, 0xa084, 0x000a, 0x00c0, 0x28ea, 0x7108, 0xa194, - 0xff00, 0x0040, 0x28ea, 0xa18c, 0x00ff, 0x2001, 0x000a, 0xa106, - 0x0040, 0x28cd, 0x2001, 0x000c, 0xa106, 0x0040, 0x28d1, 0x2001, - 0x0012, 0xa106, 0x0040, 0x28d5, 0x2001, 0x0014, 0xa106, 0x0040, - 0x28d9, 0x2001, 0x0019, 0xa106, 0x0040, 0x28dd, 0x2001, 0x0032, - 0xa106, 0x0040, 0x28e1, 0x0078, 0x28e5, 0x2009, 0x000c, 0x0078, - 0x28e7, 0x2009, 0x0012, 0x0078, 0x28e7, 0x2009, 0x0014, 0x0078, - 0x28e7, 0x2009, 0x0019, 0x0078, 0x28e7, 0x2009, 0x0020, 0x0078, - 0x28e7, 0x2009, 0x003f, 0x0078, 0x28e7, 0x2011, 0x0000, 0x2100, - 0xa205, 0x700a, 0x0e7f, 0x007c, 0x0068, 0x28ec, 0x2091, 0x8000, - 0x2071, 0x0000, 0x007e, 0x7018, 0xd084, 0x00c0, 0x28f3, 0x007f, + 0x2091, 0x4080, 0x1078, 0x2026, 0x0068, 0x2522, 0x786c, 0xa065, + 0x00c0, 0x2500, 0x007c, 0x1078, 0x2537, 0x00c0, 0x255a, 0x786c, + 0xa065, 0x00c0, 0x2500, 0x0078, 0x255a, 0x1078, 0x2537, 0x00c0, + 0x255a, 0x786c, 0xa065, 0x00c0, 0x252d, 0x0078, 0x255a, 0x6084, + 0xa086, 0x0103, 0x00c0, 0x254b, 0x6018, 0xc0fc, 0x601a, 0xa086, + 0x0004, 0x00c0, 0x254b, 0x7804, 0xd0a4, 0x0040, 0x254b, 0x1078, + 0x2026, 0xa006, 0x007c, 0x1078, 0x2560, 0x00c0, 0x2552, 0xa085, + 0x0001, 0x007c, 0x1078, 0x256f, 0x00c0, 0x2558, 0x2041, 0x0001, + 0x7d10, 0x007c, 0x88ff, 0x0040, 0x255f, 0x2091, 0x4080, 0x007c, + 0x7b90, 0x7994, 0x70d4, 0xa102, 0x00c0, 0x2569, 0xa385, 0x0000, + 0x007c, 0x0048, 0x256d, 0xa302, 0x007c, 0x8002, 0x007c, 0x7810, + 0xd0ec, 0x0040, 0x2587, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x0020, + 0x7004, 0xa005, 0x00c0, 0x2584, 0x7008, 0x0e7f, 0xa086, 0x0008, + 0x0040, 0x2587, 0x0078, 0x25d8, 0x0e7f, 0x0078, 0x25d8, 0xa184, + 0xff00, 0x0040, 0x2594, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, + 0x8007, 0xa100, 0x0078, 0x2597, 0x8107, 0x8004, 0x8004, 0x7a9c, + 0x7b98, 0x7ca4, 0x7da0, 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, + 0x2009, 0x0018, 0x6028, 0xa005, 0x0040, 0x25a8, 0x2009, 0x0040, + 0x1078, 0x1d5b, 0x0040, 0x25ca, 0x78a8, 0x8000, 0x78aa, 0xd08c, + 0x00c0, 0x25d8, 0x6014, 0xd0fc, 0x00c0, 0x25ba, 0x2069, 0x4d40, + 0x0078, 0x25bc, 0x2069, 0x4d80, 0x2091, 0x8000, 0x681f, 0x0003, + 0x78ab, 0x0000, 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, + 0x0078, 0x25d8, 0x78ab, 0x0000, 0x1078, 0x2026, 0x7990, 0x7894, + 0x8000, 0xa10a, 0x00c8, 0x25d5, 0xa006, 0x7896, 0x70d6, 0xa006, + 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x2138, 0xd7fc, 0x00c0, + 0x25e5, 0x2009, 0x4d59, 0x0078, 0x25e7, 0x2009, 0x4d99, 0x2091, + 0x8000, 0x200a, 0x0f7e, 0xd7fc, 0x00c0, 0x25fe, 0x2009, 0x4d40, + 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x0040, 0x25fa, 0x2079, 0x0100, + 0x0078, 0x2602, 0x2079, 0x0200, 0x0078, 0x2602, 0x2009, 0x4d80, + 0x2079, 0x0100, 0x2104, 0xa086, 0x0000, 0x00c0, 0x261b, 0xd7fc, + 0x00c0, 0x260e, 0x2009, 0x4d45, 0x0078, 0x2610, 0x2009, 0x4d85, + 0x2104, 0xa005, 0x00c0, 0x261b, 0x7830, 0xa084, 0x00c0, 0x00c0, + 0x261b, 0x781b, 0x0045, 0x0f7f, 0x007c, 0x2009, 0x0002, 0x2069, + 0x4d00, 0x6810, 0xd0ec, 0x00c0, 0x267e, 0x2071, 0x4d80, 0x2079, + 0x0100, 0x2021, 0x4fbf, 0x784b, 0x000f, 0x2019, 0x43d2, 0xd184, + 0x0040, 0x263e, 0x6810, 0xd0ec, 0x0040, 0x263a, 0x20a1, 0x012b, + 0x0078, 0x2640, 0x20a1, 0x022b, 0x0078, 0x2640, 0x20a1, 0x012b, + 0x2304, 0xa005, 0x0040, 0x264d, 0x789a, 0x8318, 0x23ac, 0x8318, + 0x2398, 0x53a6, 0x3318, 0x0078, 0x2640, 0x789b, 0x0020, 0x20a9, + 0x0010, 0x78af, 0x0000, 0x78af, 0x8020, 0x00f0, 0x2651, 0x7003, + 0x0000, 0x017e, 0xd18c, 0x2009, 0x0000, 0x0040, 0x2660, 0xc1bd, + 0x1078, 0x2849, 0x017f, 0x7020, 0xa084, 0x000f, 0x007e, 0x6814, + 0xd0e4, 0x007f, 0x00c0, 0x2670, 0xa085, 0x6340, 0x0078, 0x2672, + 0xa085, 0x62c0, 0x7806, 0x780f, 0x9200, 0x7843, 0x00d8, 0x7853, + 0x0080, 0x780b, 0x0008, 0x7456, 0x7053, 0x0000, 0x8109, 0x0040, + 0x2691, 0x2071, 0x4d40, 0x6810, 0xd0ec, 0x0040, 0x268b, 0x2079, + 0x0100, 0x0078, 0x268d, 0x2079, 0x0200, 0x2021, 0x4dbf, 0x0078, + 0x262b, 0x007c, 0x017e, 0xd1bc, 0x00c0, 0x26a6, 0x007e, 0x2001, + 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x26a2, 0x2011, 0x0101, + 0x0078, 0x26a8, 0x2011, 0x0201, 0x0078, 0x26a8, 0x2011, 0x0101, + 0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x017f, + 0x1078, 0x2849, 0x007c, 0xd3fc, 0x00c0, 0x26c6, 0x007e, 0x2001, + 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x26c2, 0x2011, 0x0101, + 0x0078, 0x26c8, 0x2011, 0x0201, 0x0078, 0x26c8, 0x2011, 0x0101, + 0x20a9, 0x0009, 0x810b, 0x00f0, 0x26ca, 0xa18c, 0x0e00, 0x2204, + 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2019, 0x0002, 0x2001, + 0x4d04, 0x2004, 0xd0ec, 0x0040, 0x26e2, 0x8319, 0x2009, 0x0101, + 0x0078, 0x26e4, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x00f0, + 0x26e6, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, + 0x8319, 0x0040, 0x26f7, 0x2009, 0x0201, 0x0078, 0x26e4, 0x007c, + 0xd3fc, 0x00c0, 0x270b, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x2707, 0x2011, 0x0101, 0x0078, 0x270d, 0x2011, + 0x0201, 0x0078, 0x270d, 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, + 0x00f0, 0x270f, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, + 0x2012, 0x007c, 0xd3fc, 0x00c0, 0x272d, 0x007e, 0x2001, 0x4d04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2729, 0x2011, 0x0102, 0x0078, + 0x272f, 0x2011, 0x0202, 0x0078, 0x272f, 0x2011, 0x0102, 0x2204, + 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, + 0x2749, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x2745, 0x2061, 0x0100, 0x0078, 0x274b, 0x2061, 0x0200, 0x0078, + 0x274b, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, + 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, + 0x2769, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x2765, 0x2061, 0x0100, 0x0078, 0x276b, 0x2061, 0x0200, 0x0078, + 0x276b, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0022, + 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, 0x007c, 0x0c7e, + 0xd1bc, 0x00c0, 0x278b, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x2787, 0x2061, 0x0100, 0x0078, 0x278d, 0x2061, + 0x0200, 0x0078, 0x278d, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, + 0xa080, 0x0022, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f, + 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x27ad, 0x007e, 0x2001, 0x4d04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x27a9, 0x2061, 0x0100, 0x0078, + 0x27af, 0x2061, 0x0200, 0x0078, 0x27af, 0x2061, 0x0100, 0xc1bc, + 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, 0xa28c, 0x0020, + 0x0040, 0x27bd, 0xc2ac, 0xa39d, 0x4000, 0xc3fc, 0xd3b4, 0x00c0, + 0x27c2, 0xc3fd, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f, + 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, + 0x2827, 0xd1fc, 0x0040, 0x27d8, 0x2061, 0x94d0, 0x0078, 0x27da, + 0x2061, 0x93c0, 0x1078, 0x282f, 0x0040, 0x280d, 0x20a9, 0x0101, + 0xd1fc, 0x0040, 0x27e7, 0x2061, 0x93d0, 0x0078, 0x27e9, 0x2061, + 0x92c0, 0x0c7e, 0x1078, 0x282f, 0x0040, 0x27f4, 0x0c7f, 0x8c60, + 0x00f0, 0x27e9, 0x0078, 0x2827, 0x007f, 0xd1fc, 0x0040, 0x27fe, + 0xa082, 0x93d0, 0x2071, 0x4d80, 0x0078, 0x2802, 0xa082, 0x92c0, + 0x2071, 0x4d40, 0x707a, 0x7176, 0x2001, 0x0004, 0x7066, 0x7083, + 0x000f, 0x1078, 0x25dd, 0x0078, 0x2823, 0xd1fc, 0x00c0, 0x2814, + 0x2071, 0x4d40, 0x0078, 0x2816, 0x2071, 0x4d80, 0x6020, 0xc0dd, + 0x6022, 0x7176, 0x2c00, 0x707e, 0x2001, 0x0006, 0x7066, 0x7083, + 0x000f, 0x1078, 0x25dd, 0x2001, 0x0000, 0x0078, 0x2829, 0x2001, + 0x0001, 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, + 0xa005, 0x0040, 0x2846, 0x2060, 0x6010, 0xa306, 0x00c0, 0x2843, + 0x600c, 0xa206, 0x00c0, 0x2843, 0x6014, 0xa106, 0x00c0, 0x2843, + 0xa006, 0x0078, 0x2848, 0x6000, 0x0078, 0x2830, 0xa085, 0x0001, + 0x007c, 0x0f7e, 0x0e7e, 0x017e, 0xd1bc, 0x00c0, 0x2861, 0x2079, + 0x4d40, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x285d, 0x2071, 0x0100, 0x0078, 0x2865, 0x2071, 0x0200, 0x0078, + 0x2865, 0x2079, 0x4d80, 0x2071, 0x0100, 0x7920, 0xa18c, 0x000f, + 0x70ec, 0xd0c4, 0x00c0, 0x286f, 0x017f, 0x0078, 0x288a, 0x810b, + 0x810b, 0x810b, 0x810b, 0x007f, 0xd0bc, 0x00c0, 0x2887, 0x007e, + 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2883, 0xa18d, + 0x0f00, 0x0078, 0x2889, 0xa18d, 0x0f00, 0x0078, 0x2889, 0xa18d, + 0x0800, 0x2104, 0x0e7f, 0x0f7f, 0x007c, 0x0e7e, 0x2001, 0x4d01, + 0x2004, 0xd0ac, 0x00c0, 0x290a, 0x68e4, 0xd0ac, 0x0040, 0x290a, + 0xa084, 0x0006, 0x00c0, 0x290a, 0x6014, 0xd0fc, 0x00c0, 0x28a4, + 0x2071, 0x51c0, 0x0078, 0x28a6, 0x2071, 0x5240, 0x8007, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, 0xa084, 0x000a, + 0x00c0, 0x290a, 0x7108, 0xa194, 0xff00, 0x0040, 0x290a, 0xa18c, + 0x00ff, 0x2001, 0x000a, 0xa106, 0x0040, 0x28d9, 0x2001, 0x000c, + 0xa106, 0x0040, 0x28dd, 0x2001, 0x0012, 0xa106, 0x0040, 0x28e1, + 0x2001, 0x0014, 0xa106, 0x0040, 0x28e5, 0x2001, 0x0019, 0xa106, + 0x0040, 0x28e9, 0x2001, 0x0032, 0xa106, 0x0040, 0x28ed, 0x0078, + 0x28f1, 0x2009, 0x000c, 0x0078, 0x28f3, 0x2009, 0x0012, 0x0078, + 0x28f3, 0x2009, 0x0014, 0x0078, 0x28f3, 0x2009, 0x0019, 0x0078, + 0x28f3, 0x2009, 0x0020, 0x0078, 0x28f3, 0x2009, 0x003f, 0x0078, + 0x28f3, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, 0x2071, 0x4d00, + 0x7004, 0xd0bc, 0x0040, 0x290a, 0x6014, 0xd0fc, 0x00c0, 0x2905, + 0x70ea, 0x2071, 0x4d40, 0x0078, 0x2908, 0x70ee, 0x2071, 0x4d80, + 0x701f, 0x800f, 0x0e7f, 0x007c, 0x0068, 0x290c, 0x2091, 0x8000, + 0x2071, 0x0000, 0x007e, 0x7018, 0xd084, 0x00c0, 0x2913, 0x007f, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, - 0x0809, 0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, - 0x4080, 0x0078, 0x2909, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, + 0x080d, 0x70df, 0x0008, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, + 0x4080, 0x0078, 0x2929, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708e, 0x7592, 0x7496, 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, - 0x0040, 0x2920, 0xa784, 0x007d, 0x00c0, 0x417b, 0x1078, 0x28ec, - 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x292b, 0xa3a6, 0x0007, - 0x00c0, 0x28ec, 0x2418, 0x8507, 0xa084, 0x000f, 0x0079, 0x2930, - 0x2f45, 0x3035, 0x3060, 0x32c1, 0x363b, 0x36a1, 0x3741, 0x37bd, - 0x38a1, 0x398a, 0x2943, 0x2940, 0x2d2a, 0x2e43, 0x360e, 0x2940, - 0x1078, 0x28ec, 0x007c, 0xa006, 0x0078, 0x294d, 0x7808, 0xc08d, + 0x0040, 0x2940, 0xa784, 0x007d, 0x00c0, 0x4348, 0x1078, 0x290c, + 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x294b, 0xa3a6, 0x0007, + 0x00c0, 0x290c, 0x2418, 0x8507, 0xa084, 0x000f, 0x0079, 0x2950, + 0x2fc6, 0x30b5, 0x30e0, 0x3341, 0x372a, 0x379f, 0x3853, 0x38cf, + 0x39bd, 0x3aac, 0x2963, 0x2960, 0x2d99, 0x2eba, 0x36fb, 0x2960, + 0x1078, 0x290c, 0x007c, 0xa006, 0x0078, 0x296d, 0x7808, 0xc08d, 0x780a, 0xa006, 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, 0xa005, - 0x00c0, 0x2a64, 0x7064, 0xa084, 0x0007, 0x0079, 0x2957, 0x295f, - 0x29cf, 0x29d8, 0x29e3, 0x29ee, 0x2a4a, 0x29f9, 0x29cf, 0x7830, - 0xd0bc, 0x00c0, 0x2942, 0x71d4, 0xd1b4, 0x00c0, 0x29ac, 0x70a4, - 0xa086, 0x0001, 0x0040, 0x2942, 0x70b4, 0xa06d, 0x6800, 0xa065, - 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, - 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0040, 0x2982, 0x69bc, - 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0010, 0x0078, - 0x2bbd, 0x7060, 0xa005, 0x00c0, 0x2942, 0x0c7e, 0x0d7e, 0x70b4, + 0x00c0, 0x2ad3, 0x7064, 0xa084, 0x0007, 0x0079, 0x2977, 0x297f, + 0x29f2, 0x29fb, 0x2a06, 0x2a11, 0x2ab9, 0x2a1c, 0x29f2, 0x7830, + 0xd0bc, 0x00c0, 0x2962, 0x71d4, 0xd1bc, 0x00c0, 0x2962, 0xd1b4, + 0x00c0, 0x29cf, 0x70a4, 0xa086, 0x0001, 0x0040, 0x2962, 0x70b4, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0040, 0x29a5, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, - 0x2001, 0x0020, 0x0078, 0x2bbd, 0x1078, 0x411c, 0x00c0, 0x2942, - 0x781b, 0x005b, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x68bc, - 0x7042, 0xc1b4, 0x71d6, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x7003, - 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0x1078, - 0x411c, 0x00c0, 0x29d7, 0x781b, 0x0047, 0x7003, 0x0004, 0x007c, - 0x1078, 0x411c, 0x00c0, 0x29e2, 0x2011, 0x000c, 0x1078, 0x2a09, - 0x7003, 0x0004, 0x007c, 0x1078, 0x411c, 0x00c0, 0x29ed, 0x2011, - 0x0006, 0x1078, 0x2a09, 0x7003, 0x0004, 0x007c, 0x1078, 0x411c, - 0x00c0, 0x29f8, 0x2011, 0x000d, 0x1078, 0x2a09, 0x7003, 0x0004, - 0x007c, 0x1078, 0x411c, 0x00c0, 0x2a08, 0x2011, 0x0006, 0x1078, - 0x2a09, 0x707c, 0x707f, 0x0000, 0x2068, 0x704e, 0x7003, 0x0001, - 0x007c, 0x7174, 0xc1fc, 0x8107, 0x7882, 0x789b, 0x0010, 0xa286, - 0x000c, 0x00c0, 0x2a18, 0x7aaa, 0x2001, 0x0001, 0x0078, 0x2a2d, - 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, 0x000d, 0x0040, - 0x2a26, 0x7aaa, 0x2001, 0x0002, 0x0078, 0x2a2d, 0x78ab, 0x0020, - 0x7178, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, 0x78aa, - 0x785b, 0x0004, 0x781b, 0x0108, 0x1078, 0x4131, 0x7083, 0x000f, - 0x70d4, 0xd0b4, 0x0040, 0x2a49, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, - 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, - 0x0c7f, 0x007c, 0x1078, 0x411c, 0x00c0, 0x2942, 0x707c, 0x2068, - 0x7774, 0x1078, 0x3fe1, 0x2c50, 0x1078, 0x41f0, 0x789b, 0x0010, - 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, - 0x2001, 0x0004, 0x0078, 0x2bc3, 0x1078, 0x411c, 0x00c0, 0x2942, - 0x789b, 0x0010, 0x7060, 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0040, - 0x2a7e, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, - 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x1078, 0x3fe1, - 0x2c50, 0x1078, 0x41f0, 0x6824, 0xa005, 0x0040, 0x2a8f, 0xa082, - 0x0006, 0x0048, 0x2a8d, 0x0078, 0x2a8f, 0x6827, 0x0005, 0x6814, - 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, - 0x2001, 0x0003, 0x0078, 0x2bc3, 0xc28d, 0x72d6, 0x72c0, 0xa200, - 0xa015, 0x7154, 0x8108, 0xa12a, 0x0048, 0x2aa7, 0x71c0, 0x2164, - 0x6504, 0x85ff, 0x00c0, 0x2abe, 0x7156, 0x8421, 0x00c0, 0x2aa2, - 0x70d4, 0xd08c, 0x0040, 0x2aba, 0x70d0, 0xa005, 0x00c0, 0x2aba, - 0x70d3, 0x000a, 0x007c, 0x2200, 0x0078, 0x2aac, 0x70d4, 0xc08c, - 0x70d6, 0x70d3, 0x0000, 0x603c, 0xa005, 0x00c0, 0x2abb, 0x6708, - 0xa784, 0x073f, 0x0040, 0x2aed, 0xd7d4, 0x00c0, 0x2abb, 0xa784, - 0x0021, 0x00c0, 0x2abb, 0xa784, 0x0002, 0x0040, 0x2ade, 0xa784, - 0x0004, 0x0040, 0x2abb, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, - 0x00c0, 0x2abb, 0xa784, 0x0100, 0x0040, 0x2aed, 0x6018, 0xa005, - 0x00c0, 0x2abb, 0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, - 0x6e1c, 0xa684, 0x000e, 0x6318, 0x0040, 0x2afe, 0x601c, 0xa302, - 0x0048, 0x2b01, 0x0040, 0x2b01, 0x0078, 0x2abb, 0x83ff, 0x00c0, - 0x2abb, 0x2d58, 0x2c50, 0x7156, 0xd7bc, 0x00c0, 0x2b09, 0x7028, - 0x6022, 0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, - 0x2041, 0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, - 0x0040, 0x2b1d, 0xd684, 0x0040, 0x2b1f, 0xa39c, 0xffbf, 0xd6a4, - 0x0040, 0x2b24, 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2b6f, - 0xc7a5, 0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, 0x00c0, - 0x2b43, 0x70d4, 0xd0b4, 0x00c0, 0x2b43, 0x7000, 0xa082, 0x0002, - 0x00c8, 0x2b43, 0x7830, 0xd0bc, 0x00c0, 0x2b43, 0x789b, 0x0010, - 0x7baa, 0x0078, 0x2bbb, 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, - 0x0005, 0x70ac, 0xa606, 0x00c0, 0x2b4e, 0x76a8, 0x76b2, 0x2c3a, - 0x8738, 0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, - 0x7830, 0xd0bc, 0x0040, 0x2b66, 0x2091, 0x8000, 0x2091, 0x303d, - 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, - 0x0040, 0x2b6e, 0x8421, 0x2200, 0x00c0, 0x2aa1, 0x007c, 0xd1dc, - 0x0040, 0x3be5, 0x2029, 0x0020, 0xd69c, 0x00c0, 0x2b7c, 0x8528, - 0xd68c, 0x00c0, 0x2b7c, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, - 0xa18c, 0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0040, 0x2b9b, - 0x6014, 0xa706, 0x00c0, 0x2b84, 0x60b8, 0x8001, 0x60ba, 0x00c0, - 0x2b7f, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, - 0x00c0, 0x2aa1, 0x007c, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, - 0x8840, 0x6008, 0xc0d5, 0x600a, 0x77a4, 0xa786, 0x0001, 0x00c0, - 0x2b43, 0x70d4, 0xd0b4, 0x00c0, 0x2b43, 0x7000, 0xa082, 0x0002, - 0x00c8, 0x2b43, 0x7830, 0xd0bc, 0x00c0, 0x2b43, 0x789b, 0x0010, - 0x7baa, 0x7daa, 0x79aa, 0x2001, 0x0002, 0x007e, 0x6018, 0x8000, - 0x601a, 0x0078, 0x2bc4, 0x007e, 0x2960, 0x6104, 0x2a60, 0xa184, - 0x0018, 0x0040, 0x2be0, 0xa184, 0x0010, 0x0040, 0x2bd3, 0x1078, - 0x3df6, 0x00c0, 0x2c05, 0xa184, 0x0008, 0x0040, 0x2be0, 0x69a0, - 0xa184, 0x0600, 0x00c0, 0x2be0, 0x1078, 0x3cda, 0x0078, 0x2c05, - 0x69a0, 0xa184, 0x1e00, 0x0040, 0x2c10, 0xa184, 0x0800, 0x0040, - 0x2bf9, 0x0c7e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, - 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x1078, 0x3df6, 0x00c0, 0x2c05, - 0x69a0, 0xa184, 0x0200, 0x0040, 0x2c01, 0x1078, 0x3d3a, 0x0078, - 0x2c05, 0xa184, 0x0400, 0x00c0, 0x2bdc, 0x69a0, 0xa184, 0x1000, - 0x0040, 0x2c10, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x2749, - 0x027f, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x2c1d, 0xa086, - 0x0060, 0x00c0, 0x2c1d, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, - 0x789b, 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, - 0x0040, 0x2c38, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0050, - 0x2c36, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, - 0x78aa, 0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, - 0x20a0, 0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, - 0x2898, 0x25a0, 0xa286, 0x0020, 0x00c0, 0x2c70, 0x70d4, 0xc0b5, - 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, - 0x7882, 0xa286, 0x0002, 0x0040, 0x2ca6, 0x70a4, 0x8000, 0x70a6, - 0x74b4, 0xa498, 0x0005, 0x70ac, 0xa306, 0x00c0, 0x2c68, 0x73a8, - 0x73b6, 0xa286, 0x0010, 0x0040, 0x2942, 0x0d7f, 0x0c7f, 0x007c, - 0x7000, 0xa005, 0x00c0, 0x2c4e, 0xa286, 0x0002, 0x00c0, 0x2cc0, - 0x1078, 0x411c, 0x00c0, 0x2c4e, 0x6814, 0xc0fc, 0x8007, 0x7882, - 0x2091, 0x8000, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, - 0x780a, 0x127e, 0x0d7e, 0x0c7e, 0x70d4, 0xa084, 0x2700, 0x2090, - 0x0c7f, 0x0d7f, 0x127f, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, - 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x7830, 0xd0bc, - 0x0040, 0x2cb2, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, - 0x8000, 0x2090, 0x70a4, 0xa005, 0x00c0, 0x2cb7, 0x007c, 0x8421, - 0x0040, 0x2cb6, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0078, 0x2aa1, - 0xa286, 0x0010, 0x00c0, 0x2cf1, 0x1078, 0x411c, 0x00c0, 0x2c4e, - 0x6814, 0xc0fc, 0x8007, 0x7882, 0x781b, 0x005b, 0x68b4, 0x785a, - 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, - 0x780a, 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, - 0xa206, 0x00c0, 0x2ce4, 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, - 0x7042, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, - 0x007c, 0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, - 0x7882, 0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, - 0x005b, 0x2900, 0x705a, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, - 0xa605, 0x0040, 0x2d1c, 0x70d4, 0xa084, 0x2700, 0xa086, 0x2300, - 0x00c0, 0x2d16, 0x2009, 0x0000, 0x0078, 0x2d18, 0x2009, 0x0001, - 0xa284, 0x000f, 0x1079, 0x2d20, 0xad80, 0x0009, 0x7046, 0x007c, - 0x2d28, 0x45f7, 0x45f7, 0x45e4, 0x45f7, 0x2d28, 0x2d28, 0x2d28, - 0x1078, 0x28ec, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, - 0x4a00, 0x78ac, 0x0f7f, 0xd084, 0x0040, 0x2d4e, 0x7064, 0xa086, - 0x0001, 0x00c0, 0x2d3e, 0x7066, 0x0078, 0x2e27, 0x7064, 0xa086, - 0x0005, 0x00c0, 0x2d4c, 0x707c, 0x2068, 0x681b, 0x0004, 0x6817, - 0x0000, 0x6820, 0xc09d, 0x6822, 0x7067, 0x0000, 0x70a7, 0x0000, - 0x70a8, 0x70b2, 0x70b6, 0x70d4, 0xd0b4, 0x0040, 0x2d64, 0xc0b4, + 0x2001, 0x0010, 0x0078, 0x2c2c, 0x7060, 0xa005, 0x00c0, 0x2962, + 0x0c7e, 0x0d7e, 0x70b4, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, + 0x0010, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, + 0xa05d, 0xa886, 0x0001, 0x0040, 0x29c8, 0x69bc, 0x7daa, 0x79aa, + 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0020, 0x0078, 0x2c2c, 0x1078, + 0x42e9, 0x00c0, 0x2962, 0x781b, 0x005b, 0x70bc, 0xa06d, 0x68b4, + 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, + 0xc08d, 0x780a, 0x68bc, 0x7042, 0xc1b4, 0x71d6, 0x70b8, 0xa065, + 0x68c0, 0x705a, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, + 0x7046, 0x007c, 0x1078, 0x42e9, 0x00c0, 0x29fa, 0x781b, 0x0047, + 0x7003, 0x0004, 0x007c, 0x1078, 0x42e9, 0x00c0, 0x2a05, 0x2011, + 0x000c, 0x1078, 0x2a2c, 0x7003, 0x0004, 0x007c, 0x1078, 0x42e9, + 0x00c0, 0x2a10, 0x2011, 0x0006, 0x1078, 0x2a2c, 0x7003, 0x0004, + 0x007c, 0x1078, 0x42e9, 0x00c0, 0x2a1b, 0x2011, 0x000d, 0x1078, + 0x2a2c, 0x7003, 0x0004, 0x007c, 0x1078, 0x42e9, 0x00c0, 0x2a2b, + 0x2011, 0x0006, 0x1078, 0x2a2c, 0x707c, 0x707f, 0x0000, 0x2068, + 0x704e, 0x7003, 0x0001, 0x007c, 0x7174, 0xc1fc, 0x8107, 0x7882, + 0x789b, 0x0010, 0xa286, 0x000c, 0x00c0, 0x2a3b, 0x7aaa, 0x2001, + 0x0001, 0x0078, 0x2a50, 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, + 0xa286, 0x000d, 0x0040, 0x2a49, 0x7aaa, 0x2001, 0x0002, 0x0078, + 0x2a50, 0x78ab, 0x0020, 0x7178, 0x79aa, 0x7aaa, 0x2001, 0x0004, + 0x789b, 0x0060, 0x78aa, 0x785b, 0x0004, 0x781b, 0x0110, 0x1078, + 0x42fe, 0x7083, 0x000f, 0x70d4, 0xd0b4, 0x0040, 0x2a6c, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, - 0x6018, 0x8001, 0x601a, 0x0c7f, 0x157e, 0x2011, 0x0004, 0x7164, - 0xa186, 0x0001, 0x0040, 0x2d7d, 0xa186, 0x0007, 0x00c0, 0x2d74, - 0x701f, 0x0005, 0x0078, 0x2d7d, 0x701f, 0x0001, 0x7067, 0x0000, - 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x2d7f, 0x7067, 0x0000, 0x2001, - 0x4a0a, 0x2004, 0xa084, 0x00ff, 0xa086, 0x0018, 0x0040, 0x2d8f, - 0x7018, 0x7016, 0xa005, 0x00c0, 0x2d8f, 0x70a7, 0x0001, 0x1078, - 0x4326, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078, 0x3edb, 0xa7b8, - 0x0100, 0x00f0, 0x2d95, 0x7000, 0x0079, 0x2d9e, 0x2dcd, 0x2db3, - 0x2db3, 0x2da8, 0x2dcd, 0x2dcd, 0x2dcd, 0x2da6, 0x1078, 0x28ec, - 0x7060, 0xa005, 0x0040, 0x2dcd, 0xad06, 0x00c0, 0x2db3, 0x6800, - 0x7062, 0x0078, 0x2dc5, 0x6820, 0xd084, 0x00c0, 0x2dc1, 0x6f14, - 0x1078, 0x3fe1, 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3bb5, 0x0078, - 0x2dc5, 0x705c, 0x2060, 0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, - 0x6820, 0xc09d, 0x6822, 0x1078, 0x202a, 0xb284, 0x0400, 0x0040, - 0x2dd5, 0x2021, 0x91d0, 0x0078, 0x2dd7, 0x2021, 0x90c0, 0x1078, - 0x2e2c, 0xb284, 0x0400, 0x0040, 0x2de1, 0x2021, 0x4a98, 0x0078, - 0x2de3, 0x2021, 0x4a58, 0x1078, 0x2e2c, 0x20a9, 0x0101, 0xb284, - 0x0400, 0x0040, 0x2def, 0x2021, 0x90d0, 0x0078, 0x2df1, 0x2021, - 0x8fc0, 0x1078, 0x2e2c, 0x8420, 0x00f0, 0x2df1, 0xb284, 0x0300, - 0x0040, 0x2dfe, 0x2061, 0x4fc0, 0x0078, 0x2e00, 0x2061, 0x6fc0, - 0x2021, 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0040, 0x2e1d, - 0x6018, 0x017e, 0x007e, 0x2011, 0x4a02, 0x220c, 0xa102, 0x2012, - 0x007f, 0x017f, 0xa102, 0x0050, 0x2e1d, 0x6012, 0x00c0, 0x2e1d, - 0x2011, 0x4a04, 0x2204, 0xc0a5, 0x2012, 0x601b, 0x0000, 0xace0, - 0x0010, 0x00f0, 0x2e04, 0x8421, 0x00c0, 0x2e02, 0x157f, 0x7003, - 0x0000, 0x704f, 0x0000, 0x007c, 0x047e, 0x2404, 0xa005, 0x0040, - 0x2e3f, 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6817, 0x0000, 0x6820, - 0xc09d, 0x6822, 0x1078, 0x202a, 0x007f, 0x0078, 0x2e2e, 0x047f, - 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, 0x2e49, 0x1078, - 0x28ec, 0x2300, 0x0079, 0x2e4c, 0x2e4f, 0x2eda, 0x2ef7, 0xa282, - 0x0002, 0x0040, 0x2e55, 0x1078, 0x28ec, 0x7064, 0x7067, 0x0000, - 0x7083, 0x0000, 0x0079, 0x2e5c, 0x2e64, 0x2e64, 0x2e66, 0x2ea6, - 0x3bf1, 0x2e64, 0x2ea6, 0x2e64, 0x1078, 0x28ec, 0x7774, 0x1078, - 0x3edb, 0x7774, 0xa7bc, 0x8f00, 0x1078, 0x3fe1, 0x6018, 0xa005, - 0x0040, 0x2e9d, 0xd7fc, 0x00c0, 0x2e79, 0x2021, 0x90c0, 0x0078, - 0x2e7b, 0x2021, 0x91d0, 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, - 0x2f12, 0x0040, 0x2e9d, 0x157e, 0x20a9, 0x0101, 0xd7fc, 0x00c0, - 0x2e8d, 0x2021, 0x8fc0, 0x0078, 0x2e8f, 0x2021, 0x90d0, 0x047e, - 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, 0x2f12, 0x047f, 0x0040, - 0x2e9c, 0x8420, 0x00f0, 0x2e8f, 0x157f, 0x8738, 0xa784, 0x001f, - 0x00c0, 0x2e6c, 0x0078, 0x2946, 0x0078, 0x2946, 0x7774, 0x1078, - 0x3fe1, 0x6018, 0xa005, 0x0040, 0x2ed8, 0xd7fc, 0x00c0, 0x2eb4, - 0x2021, 0x90c0, 0x0078, 0x2eb6, 0x2021, 0x91d0, 0x2009, 0x0005, - 0x2011, 0x0020, 0x1078, 0x2f12, 0x0040, 0x2ed8, 0x157e, 0x20a9, - 0x0101, 0xd7fc, 0x00c0, 0x2ec8, 0x2021, 0x8fc0, 0x0078, 0x2eca, - 0x2021, 0x90d0, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, - 0x2f12, 0x047f, 0x0040, 0x2ed7, 0x8420, 0x00f0, 0x2eca, 0x157f, - 0x0078, 0x2946, 0x2200, 0x0079, 0x2edd, 0x2ee0, 0x2ee2, 0x2ee2, - 0x1078, 0x28ec, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002, 0x0040, - 0x2eeb, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0040, 0x2ef0, 0x691a, - 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x40c9, 0x2200, - 0x0079, 0x2efa, 0x2eff, 0x2ee2, 0x2efd, 0x1078, 0x28ec, 0x1078, - 0x4326, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3b7a, 0x1078, 0x3bd2, - 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3b6b, 0x0040, 0x3b7a, - 0x0078, 0x2946, 0x2404, 0xa005, 0x0040, 0x2f41, 0x2068, 0x2d04, - 0x007e, 0x6814, 0xa706, 0x0040, 0x2f21, 0x2d20, 0x007f, 0x0078, - 0x2f13, 0x007f, 0x2022, 0x691a, 0x6817, 0x0000, 0x6820, 0xa205, - 0x6822, 0x1078, 0x202a, 0x2021, 0x4a02, 0x241c, 0x8319, 0x2322, - 0x6010, 0x8001, 0x6012, 0x00c0, 0x2f3a, 0x2021, 0x4a04, 0x2404, - 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x1078, 0x3bd2, - 0x007c, 0xa085, 0x0001, 0x0078, 0x2f40, 0x2300, 0x0079, 0x2f48, - 0x2f4d, 0x2f4b, 0x2fce, 0x1078, 0x28ec, 0x78e4, 0xa005, 0x00d0, - 0x2f84, 0x3208, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, - 0x0040, 0x2f5e, 0xa18c, 0x0300, 0x0078, 0x2f60, 0xa18c, 0x0400, - 0x0040, 0x2f66, 0x0018, 0x2942, 0x0078, 0x2f68, 0x0028, 0x2942, - 0x2008, 0xa084, 0x0030, 0x00c0, 0x2f70, 0x781b, 0x005b, 0x007c, - 0x78ec, 0xa084, 0x0003, 0x0040, 0x2f6d, 0x2100, 0xa084, 0x0007, - 0x0079, 0x2f7a, 0x2fae, 0x2fb8, 0x2fa3, 0x2f82, 0x4111, 0x4111, - 0x2f82, 0x2fc3, 0x1078, 0x28ec, 0x7000, 0xa086, 0x0004, 0x00c0, - 0x2f9e, 0x7064, 0xa086, 0x0002, 0x00c0, 0x2f94, 0x2011, 0x0002, - 0x2019, 0x0000, 0x0078, 0x2e43, 0x7064, 0xa086, 0x0006, 0x0040, - 0x2f8e, 0x7064, 0xa086, 0x0004, 0x0040, 0x2f8e, 0x79e4, 0x2001, - 0x0003, 0x0078, 0x3304, 0x6818, 0xd0fc, 0x0040, 0x2fa9, 0x681b, - 0x001d, 0x1078, 0x3eae, 0x781b, 0x0061, 0x007c, 0x6818, 0xd0fc, - 0x0040, 0x2fb4, 0x681b, 0x001d, 0x1078, 0x3eae, 0x0078, 0x40ed, - 0x6818, 0xd0fc, 0x0040, 0x2fbe, 0x681b, 0x001d, 0x1078, 0x3eae, - 0x781b, 0x00ef, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x2fc9, 0x681b, - 0x001d, 0x1078, 0x3eae, 0x781b, 0x00bf, 0x007c, 0xa584, 0x000f, - 0x00c0, 0x2feb, 0x7000, 0x0079, 0x2fd5, 0x2946, 0x2fdd, 0x2fdf, - 0x3b7a, 0x3b7a, 0x3b7a, 0x2fdd, 0x2fdd, 0x1078, 0x28ec, 0x1078, - 0x3bd2, 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3b6b, 0x0040, - 0x3b7a, 0x0078, 0x2946, 0x78e4, 0xa005, 0x00d0, 0x2f84, 0x3208, - 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2ffc, - 0xa18c, 0x0300, 0x0078, 0x2ffe, 0xa18c, 0x0400, 0x0040, 0x3004, - 0x0018, 0x2f84, 0x0078, 0x3006, 0x0028, 0x2f84, 0x2008, 0xa084, - 0x0030, 0x00c0, 0x300e, 0x781b, 0x005b, 0x007c, 0x78ec, 0xa084, - 0x0003, 0x0040, 0x300b, 0x2100, 0xa184, 0x0007, 0x0079, 0x3018, - 0x3027, 0x302b, 0x3022, 0x3020, 0x4111, 0x4111, 0x3020, 0x410b, - 0x1078, 0x28ec, 0x1078, 0x3eb6, 0x781b, 0x0061, 0x007c, 0x1078, - 0x3eb6, 0x0078, 0x40ed, 0x1078, 0x3eb6, 0x781b, 0x00ef, 0x007c, - 0x1078, 0x3eb6, 0x781b, 0x00bf, 0x007c, 0x2300, 0x0079, 0x3038, - 0x303d, 0x303b, 0x303f, 0x1078, 0x28ec, 0x0078, 0x37bd, 0x681b, - 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x37bd, - 0x78ec, 0xa084, 0x0003, 0x0040, 0x37bd, 0xa184, 0x0100, 0x0040, - 0x3043, 0xa184, 0x0007, 0x0079, 0x3055, 0x305d, 0x302b, 0x2fa3, - 0x40c9, 0x4111, 0x4111, 0x40c9, 0x410b, 0x1078, 0x40d5, 0x007c, - 0xa282, 0x0005, 0x0050, 0x3066, 0x1078, 0x28ec, 0x2300, 0x0079, - 0x3069, 0x306c, 0x328b, 0x3296, 0x2200, 0x0079, 0x306f, 0x3089, - 0x3076, 0x3089, 0x3074, 0x326e, 0x1078, 0x28ec, 0x789b, 0x0018, - 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048, 0x3e9d, 0xa08a, - 0x0004, 0x00c8, 0x3e9d, 0x0079, 0x3085, 0x3e9d, 0x3e9d, 0x3e9d, - 0x3e47, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x309a, - 0x0078, 0x3e9d, 0x7000, 0xa005, 0x00c0, 0x3090, 0x2011, 0x0004, - 0x0078, 0x3998, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x3e9d, - 0x0079, 0x30a2, 0x30b4, 0x30b2, 0x30c9, 0x30cd, 0x318f, 0x3e9d, - 0x3e9d, 0x3191, 0x3e9d, 0x3e9d, 0x326a, 0x326a, 0x3e9d, 0x3e9d, - 0x3e9d, 0x326c, 0x1078, 0x28ec, 0xd6e4, 0x0040, 0x30bf, 0x2001, - 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x00ba, 0x007c, 0x6818, - 0xd0fc, 0x0040, 0x30c7, 0x681b, 0x001d, 0x0078, 0x30b7, 0x0078, - 0x40c9, 0x681b, 0x001d, 0x0078, 0x3ea7, 0x6920, 0x6922, 0xa684, - 0x1800, 0x00c0, 0x3121, 0x6820, 0xd084, 0x00c0, 0x3127, 0x6818, - 0xa086, 0x0008, 0x00c0, 0x30de, 0x681b, 0x0000, 0xd6d4, 0x0040, - 0x318c, 0xd6bc, 0x0040, 0x311e, 0x7087, 0x0000, 0x6818, 0xa084, - 0x003f, 0xa08a, 0x000d, 0x0050, 0x311e, 0xa08a, 0x000c, 0x7186, + 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x7014, 0xa005, 0x00c0, + 0x2a7b, 0x70d4, 0xd0b4, 0x0040, 0x2a7c, 0x70b8, 0xac06, 0x00c0, + 0x2a7c, 0x1078, 0x2a5b, 0x007c, 0x017e, 0x71a4, 0xa186, 0x0001, + 0x0040, 0x2aae, 0x0d7e, 0x027e, 0x2100, 0x2011, 0x0001, 0xa212, + 0x70b4, 0x2068, 0x6800, 0xac06, 0x0040, 0x2a95, 0x8211, 0x0040, + 0x2aac, 0x1078, 0x2ab0, 0x0078, 0x2a8a, 0x0c7e, 0x2100, 0x2011, + 0x0001, 0xa212, 0x70b4, 0x2068, 0x6800, 0x2060, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x8211, 0x0040, 0x2aa9, 0x1078, 0x2ab0, 0x0078, + 0x2a9c, 0x70a7, 0x0001, 0x0c7f, 0x027f, 0x0d7f, 0x017f, 0x007c, + 0xade8, 0x0005, 0x70ac, 0xad06, 0x00c0, 0x2ab8, 0x70a8, 0x2068, + 0x007c, 0x1078, 0x42e9, 0x00c0, 0x2962, 0x707c, 0x2068, 0x7774, + 0x1078, 0x4187, 0x2c50, 0x1078, 0x43bd, 0x789b, 0x0010, 0x6814, + 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, + 0x0004, 0x0078, 0x2c32, 0x1078, 0x42e9, 0x00c0, 0x2962, 0x789b, + 0x0010, 0x7060, 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0040, 0x2aed, + 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x1078, 0x4187, 0x2c50, + 0x1078, 0x43bd, 0x6824, 0xa005, 0x0040, 0x2afe, 0xa082, 0x0006, + 0x0048, 0x2afc, 0x0078, 0x2afe, 0x6827, 0x0005, 0x6814, 0xa084, + 0x001f, 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, + 0x0003, 0x0078, 0x2c32, 0xc28d, 0x72d6, 0x72c0, 0xa200, 0xa015, + 0x7154, 0x8108, 0xa12a, 0x0048, 0x2b16, 0x71c0, 0x2164, 0x6504, + 0x85ff, 0x00c0, 0x2b2d, 0x7156, 0x8421, 0x00c0, 0x2b11, 0x70d4, + 0xd08c, 0x0040, 0x2b29, 0x70d0, 0xa005, 0x00c0, 0x2b29, 0x70d3, + 0x000a, 0x007c, 0x2200, 0x0078, 0x2b1b, 0x70d4, 0xc08c, 0x70d6, + 0x70d3, 0x0000, 0x6034, 0xa005, 0x00c0, 0x2b2a, 0x6708, 0xa784, + 0x073f, 0x0040, 0x2b5c, 0xd7d4, 0x00c0, 0x2b2a, 0xa784, 0x0021, + 0x00c0, 0x2b2a, 0xa784, 0x0002, 0x0040, 0x2b4d, 0xa784, 0x0004, + 0x0040, 0x2b2a, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, 0x00c0, + 0x2b2a, 0xa784, 0x0100, 0x0040, 0x2b5c, 0x6018, 0xa005, 0x00c0, + 0x2b2a, 0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, 0x6e1c, + 0xa684, 0x000e, 0x6318, 0x0040, 0x2b6d, 0x601c, 0xa302, 0x0048, + 0x2b70, 0x0040, 0x2b70, 0x0078, 0x2b2a, 0x83ff, 0x00c0, 0x2b2a, + 0x2d58, 0x2c50, 0x7156, 0xd7bc, 0x00c0, 0x2b78, 0x7028, 0x6022, + 0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041, + 0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0040, + 0x2b8c, 0xd684, 0x0040, 0x2b8e, 0xa39c, 0xffbf, 0xd6a4, 0x0040, + 0x2b93, 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2bde, 0xc7a5, + 0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2bb2, + 0x70d4, 0xd0b4, 0x00c0, 0x2bb2, 0x7000, 0xa082, 0x0002, 0x00c8, + 0x2bb2, 0x7830, 0xd0bc, 0x00c0, 0x2bb2, 0x789b, 0x0010, 0x7baa, + 0x0078, 0x2c2a, 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, 0x0005, + 0x70ac, 0xa606, 0x00c0, 0x2bbd, 0x76a8, 0x76b2, 0x2c3a, 0x8738, + 0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, 0x7830, + 0xd0bc, 0x0040, 0x2bd5, 0x2091, 0x8000, 0x2091, 0x303d, 0x70d4, + 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, 0x0040, + 0x2bdd, 0x8421, 0x2200, 0x00c0, 0x2b10, 0x007c, 0xd1dc, 0x0040, + 0x3d86, 0x2029, 0x0020, 0xd69c, 0x00c0, 0x2beb, 0x8528, 0xd68c, + 0x00c0, 0x2beb, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, 0xa18c, + 0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0040, 0x2c0a, 0x6014, + 0xa706, 0x00c0, 0x2bf3, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2bee, + 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x00c0, + 0x2b10, 0x007c, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840, + 0x6008, 0xc0d5, 0x600a, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2bb2, + 0x70d4, 0xd0b4, 0x00c0, 0x2bb2, 0x7000, 0xa082, 0x0002, 0x00c8, + 0x2bb2, 0x7830, 0xd0bc, 0x00c0, 0x2bb2, 0x789b, 0x0010, 0x7baa, + 0x7daa, 0x79aa, 0x2001, 0x0002, 0x007e, 0x6018, 0x8000, 0x601a, + 0x0078, 0x2c33, 0x007e, 0x2960, 0x6104, 0x2a60, 0xa184, 0x0018, + 0x0040, 0x2c4f, 0xa184, 0x0010, 0x0040, 0x2c42, 0x1078, 0x3f99, + 0x00c0, 0x2c74, 0xa184, 0x0008, 0x0040, 0x2c4f, 0x69a0, 0xa184, + 0x0600, 0x00c0, 0x2c4f, 0x1078, 0x3e7c, 0x0078, 0x2c74, 0x69a0, + 0xa184, 0x1e00, 0x0040, 0x2c7f, 0xa184, 0x0800, 0x0040, 0x2c68, + 0x0c7e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, + 0x0010, 0x6106, 0x0c7f, 0x1078, 0x3f99, 0x00c0, 0x2c74, 0x69a0, + 0xa184, 0x0200, 0x0040, 0x2c70, 0x1078, 0x3edc, 0x0078, 0x2c74, + 0xa184, 0x0400, 0x00c0, 0x2c4b, 0x69a0, 0xa184, 0x1000, 0x0040, + 0x2c7f, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x2755, 0x027f, + 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x2c8c, 0xa086, 0x0060, + 0x00c0, 0x2c8c, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, 0x0040, + 0x2ca7, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0050, 0x2ca5, + 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, 0x78aa, + 0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0, + 0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898, + 0x25a0, 0xa286, 0x0020, 0x00c0, 0x2cdf, 0x70d4, 0xc0b5, 0x70d6, + 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0xa286, 0x0002, 0x0040, 0x2d15, 0x70a4, 0x8000, 0x70a6, 0x74b4, + 0xa498, 0x0005, 0x70ac, 0xa306, 0x00c0, 0x2cd7, 0x73a8, 0x73b6, + 0xa286, 0x0010, 0x0040, 0x2962, 0x0d7f, 0x0c7f, 0x007c, 0x7000, + 0xa005, 0x00c0, 0x2cbd, 0xa286, 0x0002, 0x00c0, 0x2d2f, 0x1078, + 0x42e9, 0x00c0, 0x2cbd, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x2091, + 0x8000, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, + 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, 0x780a, + 0x127e, 0x0d7e, 0x0c7e, 0x70d4, 0xa084, 0x2700, 0x2090, 0x0c7f, + 0x0d7f, 0x127f, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, 0x0002, + 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x7830, 0xd0bc, 0x0040, + 0x2d21, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, + 0x2090, 0x70a4, 0xa005, 0x00c0, 0x2d26, 0x007c, 0x8421, 0x0040, + 0x2d25, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0078, 0x2b10, 0xa286, + 0x0010, 0x00c0, 0x2d60, 0x1078, 0x42e9, 0x00c0, 0x2cbd, 0x6814, + 0xc0fc, 0x8007, 0x7882, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, + 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, + 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, 0xa206, + 0x00c0, 0x2d53, 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, 0x7042, + 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, + 0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x005b, + 0x2900, 0x705a, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605, + 0x0040, 0x2d8b, 0x70d4, 0xa084, 0x2700, 0xa086, 0x2300, 0x00c0, + 0x2d85, 0x2009, 0x0000, 0x0078, 0x2d87, 0x2009, 0x0001, 0xa284, + 0x000f, 0x1079, 0x2d8f, 0xad80, 0x0009, 0x7046, 0x007c, 0x2d97, + 0x4834, 0x4834, 0x4821, 0x4834, 0x2d97, 0x2d97, 0x2d97, 0x1078, + 0x290c, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, 0x4d00, + 0x78ac, 0x0f7f, 0xd084, 0x0040, 0x2dbf, 0x7064, 0xa086, 0x0001, + 0x00c0, 0x2dad, 0x7066, 0x0078, 0x2e96, 0x7064, 0xa086, 0x0005, + 0x00c0, 0x2dbd, 0x707c, 0x2068, 0x681b, 0x0004, 0x6817, 0x0000, + 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7067, 0x0000, 0x70a7, + 0x0000, 0x70a8, 0x70b2, 0x70b6, 0x1078, 0x2a5b, 0x157e, 0x2011, + 0x0004, 0x7164, 0xa186, 0x0001, 0x0040, 0x2ddf, 0xa186, 0x0007, + 0x00c0, 0x2dd6, 0x701f, 0x0005, 0x0078, 0x2ddf, 0x701f, 0x0001, + 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x2de1, 0x7067, + 0x0000, 0x2001, 0x4d0a, 0x2004, 0xa084, 0x00ff, 0xa086, 0x0018, + 0x0040, 0x2df1, 0x7018, 0x7016, 0xa005, 0x00c0, 0x2df1, 0x70a7, + 0x0001, 0x067e, 0x1078, 0x44fb, 0x20a9, 0x0010, 0x2039, 0x0000, + 0x1078, 0x4081, 0xa7b8, 0x0100, 0x00f0, 0x2df8, 0x067f, 0x7000, + 0x0079, 0x2e02, 0x2e3c, 0x2e17, 0x2e17, 0x2e0c, 0x2e3c, 0x2e3c, + 0x2e3c, 0x2e0a, 0x1078, 0x290c, 0x7060, 0xa005, 0x0040, 0x2e3c, + 0xad06, 0x00c0, 0x2e17, 0x6800, 0x7062, 0x0078, 0x2e29, 0x6820, + 0xd084, 0x00c0, 0x2e25, 0x6f14, 0x1078, 0x4187, 0x6008, 0xc0d4, + 0x600a, 0x1078, 0x3d56, 0x0078, 0x2e29, 0x705c, 0x2060, 0x6800, + 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, 0xd0fc, 0x0040, 0x2e31, + 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, + 0xc09d, 0x6822, 0x1078, 0x2013, 0xb284, 0x0400, 0x0040, 0x2e44, + 0x2021, 0x94d0, 0x0078, 0x2e46, 0x2021, 0x93c0, 0x1078, 0x2e9b, + 0xb284, 0x0400, 0x0040, 0x2e50, 0x2021, 0x4d98, 0x0078, 0x2e52, + 0x2021, 0x4d58, 0x1078, 0x2e9b, 0x20a9, 0x0101, 0xb284, 0x0400, + 0x0040, 0x2e5e, 0x2021, 0x93d0, 0x0078, 0x2e60, 0x2021, 0x92c0, + 0x1078, 0x2e9b, 0x8420, 0x00f0, 0x2e60, 0xb284, 0x0300, 0x0040, + 0x2e6d, 0x2061, 0x52c0, 0x0078, 0x2e6f, 0x2061, 0x72c0, 0x2021, + 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0040, 0x2e8c, 0x6018, + 0x017e, 0x007e, 0x2011, 0x4d02, 0x220c, 0xa102, 0x2012, 0x007f, + 0x017f, 0xa102, 0x0050, 0x2e8c, 0x6012, 0x00c0, 0x2e8c, 0x2011, + 0x4d04, 0x2204, 0xc0a5, 0x2012, 0x601b, 0x0000, 0xace0, 0x0010, + 0x00f0, 0x2e73, 0x8421, 0x00c0, 0x2e71, 0x157f, 0x7003, 0x0000, + 0x704f, 0x0000, 0x007c, 0x047e, 0x2404, 0xa005, 0x0040, 0x2eb6, + 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, + 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, 0x00ff, 0xc09d, + 0x6822, 0x1078, 0x2013, 0x007f, 0x0078, 0x2e9d, 0x047f, 0x2023, + 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, 0x2ec0, 0x1078, 0x290c, + 0x2300, 0x0079, 0x2ec3, 0x2ec6, 0x2f51, 0x2f6e, 0xa282, 0x0002, + 0x0040, 0x2ecc, 0x1078, 0x290c, 0x7064, 0x7067, 0x0000, 0x7083, + 0x0000, 0x0079, 0x2ed3, 0x2edb, 0x2edb, 0x2edd, 0x2f1d, 0x3d92, + 0x2edb, 0x2f1d, 0x2edb, 0x1078, 0x290c, 0x7774, 0x1078, 0x4081, + 0x7774, 0xa7bc, 0x8f00, 0x1078, 0x4187, 0x6018, 0xa005, 0x0040, + 0x2f14, 0xd7fc, 0x00c0, 0x2ef0, 0x2021, 0x93c0, 0x0078, 0x2ef2, + 0x2021, 0x94d0, 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, 0x2f89, + 0x0040, 0x2f14, 0x157e, 0x20a9, 0x0101, 0xd7fc, 0x00c0, 0x2f04, + 0x2021, 0x92c0, 0x0078, 0x2f06, 0x2021, 0x93d0, 0x047e, 0x2009, + 0x0005, 0x2011, 0x0010, 0x1078, 0x2f89, 0x047f, 0x0040, 0x2f13, + 0x8420, 0x00f0, 0x2f06, 0x157f, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x2ee3, 0x0078, 0x2966, 0x0078, 0x2966, 0x7774, 0x1078, 0x4187, + 0x6018, 0xa005, 0x0040, 0x2f4f, 0xd7fc, 0x00c0, 0x2f2b, 0x2021, + 0x93c0, 0x0078, 0x2f2d, 0x2021, 0x94d0, 0x2009, 0x0005, 0x2011, + 0x0020, 0x1078, 0x2f89, 0x0040, 0x2f4f, 0x157e, 0x20a9, 0x0101, + 0xd7fc, 0x00c0, 0x2f3f, 0x2021, 0x92c0, 0x0078, 0x2f41, 0x2021, + 0x93d0, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x2f89, + 0x047f, 0x0040, 0x2f4e, 0x8420, 0x00f0, 0x2f41, 0x157f, 0x0078, + 0x2966, 0x2200, 0x0079, 0x2f54, 0x2f57, 0x2f59, 0x2f59, 0x1078, + 0x290c, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002, 0x0040, 0x2f62, + 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0040, 0x2f67, 0x691a, 0x7067, + 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x4296, 0x2200, 0x0079, + 0x2f71, 0x2f76, 0x2f59, 0x2f74, 0x1078, 0x290c, 0x1078, 0x44fb, + 0x7000, 0xa086, 0x0002, 0x00c0, 0x3d04, 0x1078, 0x3d73, 0x6008, + 0xa084, 0xfbef, 0x600a, 0x1078, 0x3cf5, 0x0040, 0x3d04, 0x0078, + 0x2966, 0x2404, 0xa005, 0x0040, 0x2fc2, 0x2068, 0x2d04, 0x007e, + 0x6814, 0xa706, 0x0040, 0x2f98, 0x2d20, 0x007f, 0x0078, 0x2f8a, + 0x007f, 0x2022, 0x691a, 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, + 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, 0x00ff, 0xa205, 0x6822, + 0x1078, 0x2013, 0x2021, 0x4d02, 0x241c, 0x8319, 0x2322, 0x6010, + 0x8001, 0x6012, 0x00c0, 0x2fb9, 0x2021, 0x4d04, 0x2404, 0xc0a5, + 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x1078, 0x2a7c, 0x1078, + 0x3d73, 0x007c, 0xa085, 0x0001, 0x0078, 0x2fc1, 0x2300, 0x0079, + 0x2fc9, 0x2fce, 0x2fcc, 0x304e, 0x1078, 0x290c, 0x78e4, 0xa005, + 0x00d0, 0x3004, 0x3208, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x2fdf, 0xa18c, 0x0300, 0x0078, 0x2fe1, 0xa18c, + 0x0400, 0x0040, 0x2fe7, 0x0018, 0x2962, 0x0078, 0x2fe9, 0x0028, + 0x2962, 0x2008, 0xa084, 0x0030, 0x00c0, 0x2ff0, 0x0078, 0x36fb, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x2fee, 0x2100, 0xa084, 0x0007, + 0x0079, 0x2ffa, 0x302e, 0x3038, 0x3023, 0x3002, 0x42de, 0x42de, + 0x3002, 0x3043, 0x1078, 0x290c, 0x7000, 0xa086, 0x0004, 0x00c0, + 0x301e, 0x7064, 0xa086, 0x0002, 0x00c0, 0x3014, 0x2011, 0x0002, + 0x2019, 0x0000, 0x0078, 0x2eba, 0x7064, 0xa086, 0x0006, 0x0040, + 0x300e, 0x7064, 0xa086, 0x0004, 0x0040, 0x300e, 0x79e4, 0x2001, + 0x0003, 0x0078, 0x3385, 0x6818, 0xd0fc, 0x0040, 0x3029, 0x681b, + 0x001d, 0x1078, 0x4051, 0x781b, 0x0061, 0x007c, 0x6818, 0xd0fc, + 0x0040, 0x3034, 0x681b, 0x001d, 0x1078, 0x4051, 0x0078, 0x42ba, + 0x6818, 0xd0fc, 0x0040, 0x303e, 0x681b, 0x001d, 0x1078, 0x4051, + 0x781b, 0x00f5, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x3049, 0x681b, + 0x001d, 0x1078, 0x4051, 0x781b, 0x00c5, 0x007c, 0xa584, 0x000f, + 0x00c0, 0x306b, 0x7000, 0x0079, 0x3055, 0x2966, 0x305d, 0x305f, + 0x3d04, 0x3d04, 0x3d04, 0x305d, 0x305d, 0x1078, 0x290c, 0x1078, + 0x3d73, 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3cf5, 0x0040, + 0x3d04, 0x0078, 0x2966, 0x78e4, 0xa005, 0x00d0, 0x3004, 0x3208, + 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x307c, + 0xa18c, 0x0300, 0x0078, 0x307e, 0xa18c, 0x0400, 0x0040, 0x3084, + 0x0018, 0x3004, 0x0078, 0x3086, 0x0028, 0x3004, 0x2008, 0xa084, + 0x0030, 0x00c0, 0x308e, 0x781b, 0x005b, 0x007c, 0x78ec, 0xa084, + 0x0003, 0x0040, 0x308b, 0x2100, 0xa184, 0x0007, 0x0079, 0x3098, + 0x30a7, 0x30ab, 0x30a2, 0x30a0, 0x42de, 0x42de, 0x30a0, 0x42d8, + 0x1078, 0x290c, 0x1078, 0x4059, 0x781b, 0x0061, 0x007c, 0x1078, + 0x4059, 0x0078, 0x42ba, 0x1078, 0x4059, 0x781b, 0x00f5, 0x007c, + 0x1078, 0x4059, 0x781b, 0x00c5, 0x007c, 0x2300, 0x0079, 0x30b8, + 0x30bd, 0x30bb, 0x30bf, 0x1078, 0x290c, 0x0078, 0x38cf, 0x681b, + 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x38cf, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x38cf, 0xa184, 0x0100, 0x0040, + 0x30c3, 0xa184, 0x0007, 0x0079, 0x30d5, 0x30dd, 0x30ab, 0x3023, + 0x4296, 0x42de, 0x42de, 0x4296, 0x42d8, 0x1078, 0x42a2, 0x007c, + 0xa282, 0x0005, 0x0050, 0x30e6, 0x1078, 0x290c, 0x2300, 0x0079, + 0x30e9, 0x30ec, 0x330b, 0x3316, 0x2200, 0x0079, 0x30ef, 0x3109, + 0x30f6, 0x3109, 0x30f4, 0x32ee, 0x1078, 0x290c, 0x789b, 0x0018, + 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048, 0x4040, 0xa08a, + 0x0004, 0x00c8, 0x4040, 0x0079, 0x3105, 0x4040, 0x4040, 0x4040, + 0x3fea, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x311a, + 0x0078, 0x4040, 0x7000, 0xa005, 0x00c0, 0x3110, 0x2011, 0x0004, + 0x0078, 0x3aba, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x4040, + 0x0079, 0x3122, 0x3134, 0x3132, 0x3149, 0x314d, 0x320f, 0x4040, + 0x4040, 0x3211, 0x4040, 0x4040, 0x32ea, 0x32ea, 0x4040, 0x4040, + 0x4040, 0x32ec, 0x1078, 0x290c, 0xd6e4, 0x0040, 0x313f, 0x2001, + 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x00c0, 0x007c, 0x6818, + 0xd0fc, 0x0040, 0x3147, 0x681b, 0x001d, 0x0078, 0x3137, 0x0078, + 0x4296, 0x681b, 0x001d, 0x0078, 0x404a, 0x6920, 0x6922, 0xa684, + 0x1800, 0x00c0, 0x31a1, 0x6820, 0xd084, 0x00c0, 0x31a7, 0x6818, + 0xa086, 0x0008, 0x00c0, 0x315e, 0x681b, 0x0000, 0xd6d4, 0x0040, + 0x320c, 0xd6bc, 0x0040, 0x319e, 0x7087, 0x0000, 0x6818, 0xa084, + 0x003f, 0xa08a, 0x000d, 0x0050, 0x319e, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, 0x789b, 0x0061, 0x78aa, 0x157e, - 0x137e, 0x147e, 0x017e, 0x3208, 0xa18c, 0x0300, 0x0040, 0x3110, - 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x310c, - 0x20a1, 0x012b, 0x0078, 0x3112, 0x20a1, 0x022b, 0x0078, 0x3112, + 0x137e, 0x147e, 0x017e, 0x3208, 0xa18c, 0x0300, 0x0040, 0x3190, + 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x318c, + 0x20a1, 0x012b, 0x0078, 0x3192, 0x20a1, 0x022b, 0x0078, 0x3192, 0x20a1, 0x012b, 0x017f, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b, 0x0064, - 0x007c, 0xd6e4, 0x0040, 0x3127, 0x781b, 0x0076, 0x007c, 0xa684, - 0x0060, 0x0040, 0x3189, 0xd6dc, 0x0040, 0x3189, 0xd6fc, 0x00c0, - 0x3133, 0x0078, 0x314a, 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, - 0x78d0, 0x801b, 0x00c8, 0x313d, 0x8000, 0xa084, 0x003f, 0xa108, + 0x007c, 0xd6e4, 0x0040, 0x31a7, 0x781b, 0x0076, 0x007c, 0xa684, + 0x0060, 0x0040, 0x3209, 0xd6dc, 0x0040, 0x3209, 0xd6fc, 0x00c0, + 0x31b3, 0x0078, 0x31ca, 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, + 0x78d0, 0x801b, 0x00c8, 0x31bd, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, - 0xa303, 0x68ae, 0xd6f4, 0x0040, 0x3150, 0xc6f4, 0x7e5a, 0x6eb6, - 0x7000, 0xa086, 0x0003, 0x00c0, 0x315e, 0x007e, 0x1078, 0x4326, - 0x1078, 0x45f7, 0x007f, 0x781b, 0x0073, 0x007c, 0xa006, 0x1078, - 0x46e5, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, - 0x316d, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, - 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, 0x317d, 0xc6f5, + 0xa303, 0x68ae, 0xd6f4, 0x0040, 0x31d0, 0xc6f4, 0x7e5a, 0x6eb6, + 0x7000, 0xa086, 0x0003, 0x00c0, 0x31de, 0x007e, 0x1078, 0x44fb, + 0x1078, 0x4834, 0x007f, 0x781b, 0x0073, 0x007c, 0xa006, 0x1078, + 0x493a, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, + 0x31ed, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, + 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, 0x31fd, 0xc6f5, 0x7e5a, 0x6eb6, 0x781b, 0x0073, 0x007c, 0x781b, 0x0073, 0x2200, - 0xa115, 0x00c0, 0x3186, 0x1078, 0x45f7, 0x007c, 0x1078, 0x462d, + 0xa115, 0x00c0, 0x3206, 0x1078, 0x4834, 0x007c, 0x1078, 0x486c, 0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0064, 0x007c, 0x1078, - 0x28ec, 0x0078, 0x31dd, 0x6920, 0xd1c4, 0x0040, 0x31a6, 0xc1c4, + 0x290c, 0x0078, 0x325d, 0x6920, 0xd1c4, 0x0040, 0x3226, 0xc1c4, 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0e4, 0x6002, 0x6004, - 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x31d1, 0xd1cc, 0x0040, - 0x31d1, 0xc1cc, 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0ec, + 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x3251, 0xd1cc, 0x0040, + 0x3251, 0xc1cc, 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x6004, 0xc0a4, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xd19c, - 0x0040, 0x31d1, 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, - 0x31d1, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, - 0xd6d4, 0x00c0, 0x31ce, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, - 0x007c, 0x7e58, 0xd6d4, 0x00c0, 0x31d8, 0x781b, 0x0064, 0x007c, - 0x781b, 0x0076, 0x007c, 0x0078, 0x3ea2, 0x2019, 0x0000, 0x7990, - 0xa18c, 0x0007, 0x00c0, 0x31eb, 0x6820, 0xa084, 0x0100, 0x0040, - 0x31db, 0x2009, 0x0008, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, - 0xa286, 0x0001, 0x00c0, 0x3207, 0x2300, 0x7ca8, 0xa400, 0x2018, - 0xa102, 0x0040, 0x31ff, 0x0048, 0x31ff, 0x0078, 0x3201, 0x0078, - 0x3193, 0x24a8, 0x7aa8, 0x00f0, 0x3201, 0x0078, 0x31ed, 0xa284, - 0x00f0, 0xa086, 0x0020, 0x00c0, 0x325b, 0x8318, 0x8318, 0x2300, - 0xa102, 0x0040, 0x3217, 0x0048, 0x3217, 0x0078, 0x3258, 0xa286, - 0x0023, 0x0040, 0x31db, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, + 0x0040, 0x3251, 0x1078, 0x4183, 0x1078, 0x3e7c, 0x88ff, 0x0040, + 0x3251, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, + 0xd6d4, 0x00c0, 0x324e, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, + 0x007c, 0x7e58, 0xd6d4, 0x00c0, 0x3258, 0x781b, 0x0064, 0x007c, + 0x781b, 0x0076, 0x007c, 0x0078, 0x4045, 0x2019, 0x0000, 0x7990, + 0xa18c, 0x0007, 0x00c0, 0x326b, 0x6820, 0xa084, 0x0100, 0x0040, + 0x325b, 0x2009, 0x0008, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, + 0xa286, 0x0001, 0x00c0, 0x3287, 0x2300, 0x7ca8, 0xa400, 0x2018, + 0xa102, 0x0040, 0x327f, 0x0048, 0x327f, 0x0078, 0x3281, 0x0078, + 0x3213, 0x24a8, 0x7aa8, 0x00f0, 0x3281, 0x0078, 0x326d, 0xa284, + 0x00f0, 0xa086, 0x0020, 0x00c0, 0x32db, 0x8318, 0x8318, 0x2300, + 0xa102, 0x0040, 0x3297, 0x0048, 0x3297, 0x0078, 0x32d8, 0xa286, + 0x0023, 0x0040, 0x325b, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, 0x0c7e, 0x7058, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd1a4, - 0x0040, 0x3238, 0x1078, 0x3fdd, 0x1078, 0x3df6, 0x0078, 0x3246, + 0x0040, 0x32b8, 0x1078, 0x4183, 0x1078, 0x3f99, 0x0078, 0x32c6, 0x0c7e, 0x7058, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd19c, - 0x0040, 0x31d1, 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, - 0x31d1, 0x789b, 0x0060, 0x2800, 0x78aa, 0xc695, 0x7e5a, 0xd6d4, - 0x00c0, 0x3255, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, - 0x7aa8, 0x0078, 0x31ed, 0x8318, 0x2300, 0xa102, 0x0040, 0x3264, - 0x0048, 0x3264, 0x0078, 0x31ed, 0xa284, 0x0080, 0x00c0, 0x3ea7, - 0x0078, 0x3ea2, 0x0078, 0x3ea7, 0x0078, 0x3e9d, 0x7058, 0xa04d, + 0x0040, 0x3251, 0x1078, 0x4183, 0x1078, 0x3e7c, 0x88ff, 0x0040, + 0x3251, 0x789b, 0x0060, 0x2800, 0x78aa, 0xc695, 0x7e5a, 0xd6d4, + 0x00c0, 0x32d5, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, + 0x7aa8, 0x0078, 0x326d, 0x8318, 0x2300, 0xa102, 0x0040, 0x32e4, + 0x0048, 0x32e4, 0x0078, 0x326d, 0xa284, 0x0080, 0x00c0, 0x404a, + 0x0078, 0x4045, 0x0078, 0x404a, 0x0078, 0x4040, 0x7058, 0xa04d, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0040, - 0x327b, 0x1078, 0x28ec, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, - 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x3e9d, 0x0079, 0x3287, 0x3e9d, - 0x3c2c, 0x3e9d, 0x3d9e, 0xa282, 0x0000, 0x00c0, 0x3291, 0x1078, - 0x28ec, 0x1078, 0x3eae, 0x781b, 0x0075, 0x007c, 0xa282, 0x0003, - 0x00c0, 0x329c, 0x1078, 0x28ec, 0xd4fc, 0x00c0, 0x32bc, 0x7064, - 0xa005, 0x0040, 0x32a5, 0x1078, 0x28ec, 0x6f14, 0x7776, 0xa7bc, - 0x8f00, 0x1078, 0x3fe1, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, - 0xa784, 0x001f, 0x00c0, 0x32a9, 0x1078, 0x3eb2, 0x7067, 0x0002, - 0x701f, 0x0009, 0x0078, 0x32be, 0x1078, 0x3ebe, 0x781b, 0x0075, - 0x007c, 0xa282, 0x0004, 0x0050, 0x32c7, 0x1078, 0x28ec, 0x2300, - 0x0079, 0x32ca, 0x32cd, 0x346b, 0x34ae, 0xa286, 0x0003, 0x0040, - 0x3304, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x71d4, 0xd1b4, 0x0078, - 0x32fc, 0x0040, 0x32fc, 0x7868, 0xa084, 0x00ff, 0x00c0, 0x32fc, - 0xa282, 0x0002, 0x00c8, 0x32fc, 0x0d7e, 0x783b, 0x8300, 0x781b, - 0x004c, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, - 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, - 0x2001, 0x0000, 0x0078, 0x3308, 0x783b, 0x1300, 0x781b, 0x004a, - 0x2001, 0x0000, 0x0078, 0x3308, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, - 0x704a, 0x68a0, 0xd0ec, 0x0040, 0x3310, 0x6008, 0xc08d, 0x600a, - 0xa284, 0x000f, 0x0079, 0x3314, 0x344b, 0x3321, 0x331e, 0x35ae, - 0x35f2, 0x2946, 0x331c, 0x331c, 0x1078, 0x28ec, 0x6008, 0xc0d4, - 0x600a, 0xd6e4, 0x00c0, 0x3328, 0x1078, 0x4326, 0x0040, 0x3404, - 0x7868, 0xa08c, 0x00ff, 0x0040, 0x3369, 0xa186, 0x0008, 0x00c0, - 0x333e, 0x1078, 0x3bd2, 0x6008, 0xc0a4, 0x600a, 0x1078, 0x3b6b, - 0x0040, 0x3369, 0x1078, 0x4326, 0x0078, 0x3353, 0xa186, 0x0028, - 0x00c0, 0x3369, 0x1078, 0x4326, 0x6008, 0xc0a4, 0x600a, 0x6018, - 0xa005, 0x0040, 0x3353, 0x8001, 0x601a, 0x0040, 0x3353, 0x8001, - 0x0040, 0x3353, 0x601e, 0x6820, 0xd084, 0x0040, 0x2946, 0xc084, - 0x6822, 0x705c, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, - 0x6802, 0xa005, 0x2d00, 0x00c0, 0x3366, 0x6002, 0x6006, 0x0078, - 0x2946, 0x017e, 0x81ff, 0x00c0, 0x33b0, 0x7000, 0xa086, 0x0030, - 0x0040, 0x33b0, 0x71d4, 0xd1b4, 0x00c0, 0x3397, 0x7060, 0xa005, - 0x00c0, 0x33b0, 0x70a4, 0xa086, 0x0001, 0x0040, 0x33b0, 0x7003, - 0x0000, 0x047e, 0x057e, 0x077e, 0x067e, 0x0c7e, 0x0d7e, 0x1078, - 0x296c, 0x0d7f, 0x0c7f, 0x067f, 0x077f, 0x057f, 0x047f, 0x71d4, - 0xd1b4, 0x00c0, 0x33b0, 0x7003, 0x0040, 0x0078, 0x33b0, 0x1078, - 0x411c, 0x00c0, 0x33b0, 0x781b, 0x005b, 0x0d7e, 0x70bc, 0xa06d, - 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, - 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, 0x0d7f, - 0x1078, 0x34e8, 0x017f, 0x81ff, 0x0040, 0x3403, 0xa684, 0xdf00, - 0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x00c0, 0x3404, - 0x70d4, 0xd0b4, 0x0040, 0x33d1, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, - 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, - 0x0c7f, 0x6820, 0xd0dc, 0x00c0, 0x3404, 0x8717, 0xa294, 0x000f, - 0x8213, 0x8213, 0x8213, 0xb284, 0x0300, 0x0040, 0x33e3, 0xa290, - 0x4ec0, 0x0078, 0x33e5, 0xa290, 0x4f40, 0xa290, 0x0000, 0x221c, - 0xd3c4, 0x00c0, 0x33ed, 0x0078, 0x33f3, 0x8210, 0x2204, 0xa085, - 0x0018, 0x2012, 0x8211, 0xd3d4, 0x0040, 0x33fe, 0x68a0, 0xd0c4, - 0x00c0, 0x33fe, 0x1078, 0x3562, 0x0078, 0x2946, 0x6008, 0xc08d, - 0x600a, 0x0078, 0x3404, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0040, - 0x340b, 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, - 0x0040, 0x3420, 0x2009, 0x4a02, 0x2104, 0x8001, 0x200a, 0x8421, - 0x6412, 0x00c0, 0x3420, 0x2021, 0x4a04, 0x2404, 0xc0a5, 0x2022, - 0x6018, 0xa005, 0x0040, 0x3428, 0x8001, 0x601a, 0x00c0, 0x342b, - 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084, 0x00c0, 0x3437, 0x6800, - 0xa005, 0x00c0, 0x3434, 0x6002, 0x6006, 0x0078, 0x343b, 0x705c, - 0x2060, 0x6800, 0x6002, 0x2061, 0x4a00, 0x6887, 0x0103, 0x2d08, - 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x344a, 0x2d02, - 0x0078, 0x344b, 0x616e, 0x7200, 0xa286, 0x0030, 0x0040, 0x345b, - 0xa286, 0x0040, 0x00c0, 0x2946, 0x7003, 0x0002, 0x704c, 0x2068, - 0x68c4, 0x2060, 0x007c, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, - 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, - 0x0009, 0x7046, 0x007c, 0xa282, 0x0004, 0x0048, 0x3471, 0x1078, - 0x28ec, 0x2200, 0x0079, 0x3474, 0x3478, 0x3489, 0x3496, 0x3489, - 0xa586, 0x1300, 0x0040, 0x3489, 0xa586, 0x8300, 0x00c0, 0x346f, - 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x7000, 0xa086, 0x0005, 0x0040, 0x3493, 0x1078, 0x3eae, - 0x781b, 0x0075, 0x007c, 0x781b, 0x0076, 0x007c, 0x7890, 0x8007, - 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, - 0x00ff, 0xa186, 0x0003, 0x0040, 0x34ab, 0xa186, 0x0000, 0x0040, - 0x34ab, 0x0078, 0x3e9d, 0x781b, 0x0076, 0x007c, 0x6820, 0xc095, - 0x6822, 0x82ff, 0x00c0, 0x34b8, 0x1078, 0x3eae, 0x0078, 0x34bf, - 0x8211, 0x0040, 0x34bd, 0x1078, 0x28ec, 0x1078, 0x3ebe, 0x781b, - 0x0075, 0x007c, 0x1078, 0x4131, 0x7830, 0xa084, 0x00c0, 0x00c0, - 0x34e5, 0x017e, 0x3208, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, - 0x007f, 0x0040, 0x34d7, 0xa18c, 0x0300, 0x0078, 0x34d9, 0xa18c, - 0x0400, 0x017f, 0x0040, 0x34e0, 0x0018, 0x34e5, 0x0078, 0x34e2, - 0x0028, 0x34e5, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, - 0xa684, 0x0060, 0x00c0, 0x34f2, 0x682f, 0x0000, 0x6833, 0x0000, - 0x0078, 0x3561, 0xd6dc, 0x00c0, 0x350a, 0x68b4, 0xd0dc, 0x00c0, - 0x350a, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x00c0, - 0x3507, 0x2200, 0xa105, 0x0040, 0x4326, 0x704b, 0x0015, 0x0078, - 0x4326, 0x007c, 0xd6ac, 0x0040, 0x3530, 0xd6f4, 0x0040, 0x3516, - 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x4326, 0x68b4, 0xa084, - 0x4000, 0xa635, 0xd6f4, 0x00c0, 0x3510, 0x7048, 0xa005, 0x00c0, - 0x3523, 0x704b, 0x0015, 0xd6dc, 0x00c0, 0x352c, 0x68b4, 0xd0dc, - 0x0040, 0x352c, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0078, 0x4326, - 0xd6f4, 0x0040, 0x3539, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, - 0x4326, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x00c0, 0x3533, - 0x7048, 0xa005, 0x00c0, 0x3546, 0x704b, 0x0015, 0x2408, 0x2510, - 0x2700, 0x80fb, 0x00c8, 0x354d, 0x8000, 0xa084, 0x003f, 0xa108, - 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x355a, - 0x0078, 0x4326, 0x7000, 0xa086, 0x0006, 0x0040, 0x3561, 0x0078, - 0x4326, 0x007c, 0x6008, 0xc0cd, 0xd3cc, 0x0040, 0x3568, 0xc08d, - 0x600a, 0x681b, 0x0006, 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, - 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, - 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, 0x0079, 0x3580, - 0x2946, 0x3592, 0x358a, 0x3588, 0x3588, 0x3588, 0x3588, 0x3588, - 0x1078, 0x28ec, 0x6820, 0xd084, 0x00c0, 0x3592, 0x1078, 0x3bb5, - 0x0078, 0x3598, 0x705c, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, - 0x3208, 0xa18c, 0x0300, 0x0040, 0x35a1, 0x2021, 0x4a58, 0x0078, - 0x35a3, 0x2021, 0x4a98, 0x2404, 0xa005, 0x0040, 0x35aa, 0x2020, - 0x0078, 0x35a3, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x3bbc, - 0x1078, 0x3bd2, 0x6008, 0xc0cc, 0x600a, 0x682b, 0x0000, 0x789b, - 0x000e, 0x6f14, 0x6817, 0x0002, 0x3208, 0xa18c, 0x0300, 0x0040, - 0x35c5, 0x2009, 0x0000, 0x0078, 0x35c7, 0x2009, 0x0001, 0x1078, - 0x471a, 0xd6dc, 0x0040, 0x35cf, 0x691c, 0xc1ed, 0x691e, 0x6818, - 0xd0fc, 0x0040, 0x35de, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x35dc, - 0x681b, 0x001e, 0x0078, 0x35de, 0x681b, 0x0000, 0xb284, 0x0300, - 0x00c0, 0x35e6, 0x2021, 0x4a98, 0x0078, 0x35e8, 0x2021, 0x4a58, - 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x202a, - 0x0078, 0x2946, 0x7cd8, 0x7ddc, 0x7fd0, 0x1078, 0x34e8, 0x682b, - 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, 0x4135, 0xa08c, 0x00ff, - 0x6916, 0x6818, 0xd0fc, 0x0040, 0x3607, 0x7048, 0x681a, 0xa68c, - 0xdf00, 0x691e, 0x7067, 0x0000, 0x0078, 0x2946, 0x7000, 0xa005, - 0x00c0, 0x3614, 0x0078, 0x2946, 0xa006, 0x1078, 0x4326, 0x6817, - 0x0000, 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, - 0x6820, 0xa084, 0x00ff, 0x6822, 0x7000, 0x0079, 0x3627, 0x2946, - 0x3634, 0x3631, 0x3636, 0x3636, 0x3636, 0x362f, 0x362f, 0x1078, - 0x28ec, 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3bd2, 0x6008, 0xc0a4, - 0x600a, 0x0078, 0x3b85, 0x2300, 0x0079, 0x363e, 0x3641, 0x3643, - 0x369f, 0x1078, 0x28ec, 0xd6fc, 0x00c0, 0x3686, 0x7000, 0xa00d, - 0x0079, 0x364a, 0x2946, 0x3654, 0x3654, 0x3678, 0x3654, 0x3683, - 0x3652, 0x3652, 0x1078, 0x28ec, 0xa684, 0x0060, 0xa086, 0x0060, - 0x00c0, 0x3675, 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x681c, 0xc0ac, - 0x681e, 0xa186, 0x0002, 0x0040, 0x3667, 0x1078, 0x4326, 0x1078, - 0x45f7, 0x781b, 0x0076, 0x71d4, 0xd1b4, 0x00c0, 0x2942, 0x70a4, - 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6ec, 0x0040, 0x365c, - 0x6818, 0xd0fc, 0x0040, 0x3683, 0x681b, 0x0015, 0xd6f4, 0x0040, - 0x3683, 0x681b, 0x0007, 0x1078, 0x40d5, 0x007c, 0xc6fc, 0x7e5a, - 0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8, 0x368f, 0x8000, 0xa084, - 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, - 0x6b94, 0x2200, 0xa303, 0x68ae, 0x781b, 0x0076, 0x007c, 0x1078, - 0x28ec, 0x2300, 0x0079, 0x36a4, 0x36a9, 0x36c5, 0x3719, 0x1078, - 0x28ec, 0x7000, 0x0079, 0x36ac, 0x36b4, 0x36b6, 0x36b6, 0x36b4, - 0x36b4, 0x36b4, 0x36b4, 0x36b4, 0x1078, 0x28ec, 0x1078, 0x45f7, - 0x681c, 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x00c0, 0x2942, 0x70a4, - 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6fc, 0x00c0, 0x3709, - 0x7000, 0xa00d, 0x0079, 0x36cc, 0x2946, 0x36dc, 0x36d6, 0x3700, - 0x36dc, 0x3706, 0x36d4, 0x36d4, 0x1078, 0x28ec, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0xa086, 0x0060, - 0x00c0, 0x36fd, 0xa6b4, 0xbfbf, 0xc6ed, 0x7e5a, 0xa186, 0x0002, - 0x0040, 0x36ec, 0x1078, 0x4326, 0x1078, 0x45f7, 0x781b, 0x0076, - 0x681c, 0xc0b4, 0x681e, 0x71d4, 0xd1b4, 0x00c0, 0x2942, 0x70a4, - 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6ec, 0x0040, 0x36e4, - 0x6818, 0xd0fc, 0x0040, 0x3706, 0x681b, 0x0007, 0x781b, 0x00f0, - 0x007c, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, - 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, 0x0076, - 0x007c, 0xd6dc, 0x0040, 0x3722, 0x782b, 0x3009, 0x781b, 0x0076, - 0x0078, 0x2942, 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, - 0x00c0, 0x3735, 0xa484, 0x0200, 0x0040, 0x372f, 0xc6f5, 0xc6dd, - 0x7e5a, 0x781b, 0x0076, 0x0078, 0x2942, 0x6820, 0xc095, 0x6822, - 0x1078, 0x4062, 0xc6dd, 0x1078, 0x3eae, 0x781b, 0x0075, 0x0078, - 0x2942, 0x2300, 0x0079, 0x3744, 0x3747, 0x3749, 0x374b, 0x1078, - 0x28ec, 0x0078, 0x3ea7, 0xd6d4, 0x00c0, 0x3771, 0x79e4, 0xd1ac, - 0x0040, 0x3759, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3759, 0x782b, - 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, - 0x79e4, 0xd1ac, 0x0040, 0x3769, 0x78ec, 0xa084, 0x0003, 0x00c0, - 0x376d, 0x2001, 0x0014, 0x0078, 0x3304, 0xa184, 0x0007, 0x0079, - 0x37a7, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, - 0x0040, 0x37a5, 0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, - 0x3798, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, 0x378b, 0x2009, - 0xfff7, 0x0078, 0x3791, 0xa386, 0x0003, 0x00c0, 0x3798, 0x2009, - 0xffef, 0x0c7e, 0x7058, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, - 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, - 0x3009, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40c9, 0x2fae, - 0x2fb8, 0x37b1, 0x37b7, 0x37af, 0x37af, 0x40c9, 0x40c9, 0x1078, - 0x28ec, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40cf, 0x6920, - 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40c9, 0x79e4, 0xa184, 0x0030, - 0x0040, 0x37c7, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x37f1, 0x7000, - 0xa086, 0x0004, 0x00c0, 0x37e1, 0x7064, 0xa086, 0x0002, 0x00c0, - 0x37d7, 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, 0x2e43, 0x7064, - 0xa086, 0x0006, 0x0040, 0x37d1, 0x7064, 0xa086, 0x0004, 0x0040, - 0x37d1, 0x7000, 0xa086, 0x0000, 0x0040, 0x2942, 0x6820, 0xd0ac, - 0x00c0, 0x37ed, 0x6818, 0xc0fd, 0x681a, 0x2001, 0x0014, 0x0078, - 0x3304, 0xa184, 0x0007, 0x0079, 0x37f5, 0x40c9, 0x40c9, 0x37fd, - 0x40c9, 0x4111, 0x4111, 0x40c9, 0x40c9, 0xd6bc, 0x0040, 0x383f, - 0x7184, 0x81ff, 0x0040, 0x383f, 0xa182, 0x000d, 0x00d0, 0x380c, - 0x7087, 0x0000, 0x0078, 0x3811, 0xa182, 0x000c, 0x7086, 0x2009, - 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e, 0x147e, 0x7088, - 0x8114, 0xa210, 0x728a, 0xa080, 0x000b, 0xad00, 0x2098, 0xb284, - 0x0300, 0x0040, 0x3833, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, - 0x007f, 0x0040, 0x382f, 0x20a1, 0x012b, 0x0078, 0x3835, 0x20a1, - 0x022b, 0x0078, 0x3835, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, - 0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, 0x40cf, 0xd6d4, - 0x00c0, 0x3893, 0x6820, 0xd084, 0x0040, 0x40cf, 0xa68c, 0x0060, - 0xa684, 0x0060, 0x0040, 0x3851, 0xa086, 0x0060, 0x00c0, 0x3851, - 0xc1f5, 0xc194, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, - 0x789b, 0x0061, 0x6818, 0xc0fd, 0x681a, 0x78aa, 0x8008, 0x810c, - 0x0040, 0x3beb, 0xa18c, 0x00f8, 0x00c0, 0x3beb, 0x157e, 0x137e, - 0x147e, 0x017e, 0x3208, 0xa18c, 0x0300, 0x0040, 0x387f, 0x007e, - 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x387b, 0x20a1, - 0x012b, 0x0078, 0x3881, 0x20a1, 0x022b, 0x0078, 0x3881, 0x20a1, - 0x012b, 0x017f, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, - 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0xc0fc, 0x8007, - 0x7882, 0x0078, 0x40cf, 0x6818, 0xd0fc, 0x0040, 0x3899, 0x681b, - 0x0008, 0x6820, 0xc0ad, 0x6822, 0x1078, 0x3eb6, 0x781b, 0x00e1, - 0x007c, 0x2300, 0x0079, 0x38a4, 0x38a9, 0x397b, 0x38a7, 0x1078, - 0x28ec, 0x7cd8, 0x7ddc, 0x7fd0, 0x82ff, 0x00c0, 0x38d1, 0x7200, - 0xa286, 0x0003, 0x0040, 0x32d2, 0x71d4, 0xd1b4, 0x0078, 0x38d4, - 0x0040, 0x38d4, 0x0d7e, 0x783b, 0x8800, 0x781b, 0x004c, 0x70bc, - 0xa06d, 0x68b4, 0xc0a5, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, - 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x0078, - 0x38d8, 0x7200, 0x0078, 0x38d8, 0x783b, 0x1800, 0x781b, 0x004a, - 0xa284, 0x000f, 0x0079, 0x38dc, 0x3966, 0x391a, 0x38e6, 0x3300, - 0x38e4, 0x3966, 0x38e4, 0x38e4, 0x1078, 0x28ec, 0x681c, 0xd0ec, - 0x0040, 0x38ed, 0x6008, 0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, - 0x6800, 0x6006, 0xa005, 0x00c0, 0x38f6, 0x6002, 0x6008, 0xc0d4, - 0x600a, 0x681c, 0xa084, 0x000e, 0x00c0, 0x390a, 0xb284, 0x0300, - 0x0040, 0x3906, 0x2009, 0x90c0, 0x0078, 0x390f, 0x2009, 0x91d0, - 0x0078, 0x390f, 0x7030, 0x68ba, 0x7140, 0x70cc, 0xa108, 0x2104, - 0x6802, 0x2d0a, 0x715e, 0xd6dc, 0x00c0, 0x391a, 0xc6fc, 0x6eb6, - 0x0078, 0x3966, 0x6eb6, 0xa684, 0x0060, 0x0040, 0x3966, 0xd6dc, - 0x00c0, 0x392d, 0xa684, 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, - 0x68aa, 0x1078, 0x4326, 0x0078, 0x3966, 0xd6ac, 0x0040, 0x3939, - 0xa006, 0x1078, 0x4326, 0x2408, 0x2510, 0x69aa, 0x6aa6, 0x0078, - 0x3949, 0x2408, 0x2510, 0x2700, 0x801b, 0x00c8, 0x3940, 0x8000, - 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x69aa, 0x6aa6, 0x1078, - 0x4326, 0xd6fc, 0x0040, 0x3966, 0xa684, 0x7fff, 0x68b6, 0x2510, - 0x2408, 0xd6ac, 0x00c0, 0x395e, 0x2700, 0x801b, 0x00c8, 0x3959, - 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, - 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, - 0x0030, 0x00c0, 0x2946, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, - 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, - 0x0009, 0x7046, 0x007c, 0xa586, 0x8800, 0x00c0, 0x3988, 0x7003, - 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, - 0x0078, 0x3ea7, 0x7047, 0x0000, 0xa282, 0x0006, 0x0050, 0x3992, - 0x1078, 0x28ec, 0x2300, 0x0079, 0x3995, 0x3998, 0x39cf, 0x3a01, - 0x2200, 0x0079, 0x399b, 0x39a1, 0x3ea7, 0x39a3, 0x39a1, 0x3a38, - 0x3a9b, 0x1078, 0x28ec, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, - 0x39ad, 0x2001, 0x91e0, 0x0078, 0x39af, 0x2001, 0x9212, 0x2068, + 0x32fb, 0x1078, 0x290c, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, + 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x4040, 0x0079, 0x3307, 0x4040, + 0x3dce, 0x4040, 0x3f41, 0xa282, 0x0000, 0x00c0, 0x3311, 0x1078, + 0x290c, 0x1078, 0x4051, 0x781b, 0x0075, 0x007c, 0xa282, 0x0003, + 0x00c0, 0x331c, 0x1078, 0x290c, 0xd4fc, 0x00c0, 0x333c, 0x7064, + 0xa005, 0x0040, 0x3325, 0x1078, 0x290c, 0x6f14, 0x7776, 0xa7bc, + 0x8f00, 0x1078, 0x4187, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, + 0xa784, 0x001f, 0x00c0, 0x3329, 0x1078, 0x4055, 0x7067, 0x0002, + 0x701f, 0x0009, 0x0078, 0x333e, 0x1078, 0x4064, 0x781b, 0x0075, + 0x007c, 0xa282, 0x0004, 0x0050, 0x3347, 0x1078, 0x290c, 0x2300, + 0x0079, 0x334a, 0x334d, 0x350d, 0x3550, 0xa286, 0x0003, 0x0040, + 0x3385, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x71d4, 0xd1bc, 0x00c0, + 0x337d, 0xd1b4, 0x0040, 0x337d, 0x7868, 0xa084, 0x00ff, 0x00c0, + 0x337d, 0xa282, 0x0002, 0x00c8, 0x337d, 0x0d7e, 0x783b, 0x8300, + 0x781b, 0x004c, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, + 0x0d7f, 0x2001, 0x0000, 0x0078, 0x3389, 0x783b, 0x1300, 0x781b, + 0x004a, 0x2001, 0x0000, 0x0078, 0x3389, 0x7200, 0x7cd8, 0x7ddc, + 0x7fd0, 0x704a, 0x68a0, 0xd0ec, 0x0040, 0x3391, 0x6008, 0xc08d, + 0x600a, 0xa284, 0x000f, 0x0079, 0x3395, 0x34ed, 0x33a2, 0x339f, + 0x3653, 0x36df, 0x2966, 0x339d, 0x339d, 0x1078, 0x290c, 0x6008, + 0xc0d4, 0x600a, 0xd6e4, 0x0040, 0x33aa, 0x7048, 0xa086, 0x0014, + 0x00c0, 0x33ca, 0x1078, 0x44fb, 0x2009, 0x0000, 0x6818, 0xd0fc, + 0x0040, 0x33b3, 0x7048, 0xa086, 0x0014, 0x0040, 0x33c4, 0x6818, + 0xa086, 0x0008, 0x00c0, 0x34a5, 0x7858, 0xd09c, 0x0040, 0x34a5, + 0x6820, 0xd0ac, 0x0040, 0x34a5, 0x681b, 0x0014, 0x2009, 0x0002, + 0x0078, 0x3409, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x3409, 0xa186, + 0x0008, 0x00c0, 0x33e0, 0x6008, 0xc0a4, 0x600a, 0x1078, 0x3cf5, + 0x0040, 0x3409, 0x1078, 0x3d73, 0x1078, 0x44fb, 0x0078, 0x33f1, + 0xa186, 0x0028, 0x00c0, 0x3409, 0x6018, 0xa005, 0x0040, 0x33d3, + 0x8001, 0x0040, 0x33d3, 0x8001, 0x0040, 0x33d3, 0x601e, 0x0078, + 0x33d3, 0x6820, 0xd084, 0x0040, 0x2966, 0xc084, 0x6822, 0x1078, + 0x2a6d, 0x705c, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, + 0x6802, 0xa005, 0x2d00, 0x00c0, 0x3406, 0x6002, 0x6006, 0x0078, + 0x2966, 0x017e, 0x81ff, 0x00c0, 0x3453, 0x7000, 0xa086, 0x0030, + 0x0040, 0x3453, 0x71d4, 0xd1bc, 0x00c0, 0x3453, 0xd1b4, 0x00c0, + 0x343a, 0x7060, 0xa005, 0x00c0, 0x3453, 0x70a4, 0xa086, 0x0001, + 0x0040, 0x3453, 0x7003, 0x0000, 0x047e, 0x057e, 0x077e, 0x067e, + 0x0c7e, 0x0d7e, 0x1078, 0x298f, 0x0d7f, 0x0c7f, 0x067f, 0x077f, + 0x057f, 0x047f, 0x71d4, 0xd1b4, 0x00c0, 0x3453, 0x7003, 0x0040, + 0x0078, 0x3453, 0x1078, 0x42e9, 0x00c0, 0x3453, 0x781b, 0x005b, + 0x0d7e, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, + 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x7808, + 0xc08d, 0x780a, 0x0d7f, 0x1078, 0x358a, 0x017f, 0x81ff, 0x0040, + 0x34a5, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, + 0x0002, 0x00c0, 0x34a6, 0x6818, 0xa086, 0x0014, 0x00c0, 0x346f, + 0x2008, 0xd6e4, 0x0040, 0x346f, 0x7868, 0xa08c, 0x00ff, 0x1078, + 0x2a5b, 0x1078, 0x2a7c, 0x6820, 0xd0dc, 0x00c0, 0x34a6, 0x8717, + 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xb284, 0x0300, 0x0040, + 0x3485, 0xa290, 0x51c0, 0x0078, 0x3487, 0xa290, 0x5240, 0xa290, + 0x0000, 0x221c, 0xd3c4, 0x00c0, 0x348f, 0x0078, 0x3495, 0x8210, + 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, 0xd3d4, 0x0040, 0x34a0, + 0x68a0, 0xd0c4, 0x00c0, 0x34a0, 0x1078, 0x3604, 0x0078, 0x2966, + 0x6008, 0xc08d, 0x600a, 0x0078, 0x34a6, 0x692a, 0x6916, 0x6818, + 0xd0fc, 0x0040, 0x34ad, 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, + 0x6410, 0x84ff, 0x0040, 0x34c2, 0x2009, 0x4d02, 0x2104, 0x8001, + 0x200a, 0x8421, 0x6412, 0x00c0, 0x34c2, 0x2021, 0x4d04, 0x2404, + 0xc0a5, 0x2022, 0x6018, 0xa005, 0x0040, 0x34ca, 0x8001, 0x601a, + 0x00c0, 0x34cd, 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084, 0x00c0, + 0x34d9, 0x6800, 0xa005, 0x00c0, 0x34d6, 0x6002, 0x6006, 0x0078, + 0x34dd, 0x705c, 0x2060, 0x6800, 0x6002, 0x2061, 0x4d00, 0x6887, + 0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, + 0x34ec, 0x2d02, 0x0078, 0x34ed, 0x616e, 0x7200, 0xa286, 0x0030, + 0x0040, 0x34fd, 0xa286, 0x0040, 0x00c0, 0x2966, 0x7003, 0x0002, + 0x704c, 0x2068, 0x68c4, 0x2060, 0x007c, 0x7003, 0x0002, 0x70bc, + 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, + 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0xa282, 0x0004, 0x0048, + 0x3513, 0x1078, 0x290c, 0x2200, 0x0079, 0x3516, 0x351a, 0x352b, + 0x3538, 0x352b, 0xa586, 0x1300, 0x0040, 0x352b, 0xa586, 0x8300, + 0x00c0, 0x3511, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, + 0xa084, 0xfbef, 0x600a, 0x7000, 0xa086, 0x0005, 0x0040, 0x3535, + 0x1078, 0x4051, 0x781b, 0x0075, 0x007c, 0x781b, 0x0076, 0x007c, + 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, + 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0040, 0x354d, 0xa186, + 0x0000, 0x0040, 0x354d, 0x0078, 0x4040, 0x781b, 0x0076, 0x007c, + 0x6820, 0xc095, 0x6822, 0x82ff, 0x00c0, 0x355a, 0x1078, 0x4051, + 0x0078, 0x3561, 0x8211, 0x0040, 0x355f, 0x1078, 0x290c, 0x1078, + 0x4064, 0x781b, 0x0075, 0x007c, 0x1078, 0x42fe, 0x7830, 0xa084, + 0x00c0, 0x00c0, 0x3587, 0x017e, 0x3208, 0x007e, 0x2001, 0x4d04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x3579, 0xa18c, 0x0300, 0x0078, + 0x357b, 0xa18c, 0x0400, 0x017f, 0x0040, 0x3582, 0x0018, 0x3587, + 0x0078, 0x3584, 0x0028, 0x3587, 0x791a, 0xa006, 0x007c, 0xa085, + 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, 0x3594, 0x682f, 0x0000, + 0x6833, 0x0000, 0x0078, 0x3603, 0xd6dc, 0x00c0, 0x35ac, 0x68b4, + 0xd0dc, 0x00c0, 0x35ac, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, + 0xa005, 0x00c0, 0x35a9, 0x2200, 0xa105, 0x0040, 0x44fb, 0x704b, + 0x0015, 0x0078, 0x44fb, 0x007c, 0xd6ac, 0x0040, 0x35d2, 0xd6f4, + 0x0040, 0x35b8, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x44fb, + 0x68b4, 0xa084, 0x4000, 0xa635, 0xd6f4, 0x00c0, 0x35b2, 0x7048, + 0xa005, 0x00c0, 0x35c5, 0x704b, 0x0015, 0xd6dc, 0x00c0, 0x35ce, + 0x68b4, 0xd0dc, 0x0040, 0x35ce, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, + 0x0078, 0x44fb, 0xd6f4, 0x0040, 0x35db, 0x682f, 0x0000, 0x6833, + 0x0000, 0x0078, 0x44fb, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, + 0x00c0, 0x35d5, 0x7048, 0xa005, 0x00c0, 0x35e8, 0x704b, 0x0015, + 0x2408, 0x2510, 0x2700, 0x80fb, 0x00c8, 0x35ef, 0x8000, 0xa084, + 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, + 0x00c0, 0x35fc, 0x0078, 0x44fb, 0x7000, 0xa086, 0x0006, 0x0040, + 0x3603, 0x0078, 0x44fb, 0x007c, 0x6946, 0x6008, 0xc0cd, 0xd3cc, + 0x0040, 0x360b, 0xc08d, 0x600a, 0x6818, 0x683a, 0x681b, 0x0006, + 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, + 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, + 0x689b, 0x0020, 0x7000, 0x0079, 0x3625, 0x2966, 0x3637, 0x362f, + 0x362d, 0x362d, 0x362d, 0x362d, 0x362d, 0x1078, 0x290c, 0x6820, + 0xd084, 0x00c0, 0x3637, 0x1078, 0x3d56, 0x0078, 0x363d, 0x705c, + 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, 0x3208, 0xa18c, 0x0300, + 0x0040, 0x3646, 0x2021, 0x4d58, 0x0078, 0x3648, 0x2021, 0x4d98, + 0x2404, 0xa005, 0x0040, 0x364f, 0x2020, 0x0078, 0x3648, 0x2d22, + 0x206b, 0x0000, 0x007c, 0x1078, 0x3d5d, 0x1078, 0x3d73, 0x6008, + 0xc0cc, 0x600a, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x6938, + 0x691a, 0x6944, 0x6916, 0x3208, 0xa18c, 0x0300, 0x0040, 0x366c, + 0x2009, 0x0000, 0x0078, 0x366e, 0x2009, 0x0001, 0x1078, 0x496f, + 0xd6dc, 0x0040, 0x3676, 0x691c, 0xc1ed, 0x691e, 0x6818, 0xd0fc, + 0x0040, 0x3685, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x3683, 0x681b, + 0x001e, 0x0078, 0x3685, 0x681b, 0x0000, 0xb284, 0x0300, 0x00c0, + 0x368d, 0x2021, 0x4d98, 0x0078, 0x368f, 0x2021, 0x4d58, 0x6800, + 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, + 0xd0a4, 0x0040, 0x36cf, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, + 0x0020, 0x0d7e, 0x0f7e, 0x157e, 0x147e, 0x2079, 0x4d00, 0x1078, + 0x1de6, 0x147f, 0x157f, 0x0f7f, 0x70cc, 0x2010, 0x2009, 0x0101, + 0x027e, 0x2204, 0xa06d, 0x0040, 0x36bf, 0x6814, 0xa706, 0x0040, + 0x36bc, 0x6800, 0x0078, 0x36b2, 0x6820, 0xc0d5, 0x6822, 0x027f, + 0x8210, 0x8109, 0x00c0, 0x36b0, 0x0d7f, 0x7067, 0x0003, 0x707f, + 0x0000, 0x7776, 0x7083, 0x000f, 0x71d4, 0xc1dc, 0x71d6, 0x6818, + 0xa086, 0x0002, 0x00c0, 0x36db, 0x6817, 0x0000, 0x682b, 0x0000, + 0x681c, 0xc0ec, 0x681e, 0x1078, 0x2013, 0x0078, 0x2966, 0x7cd8, + 0x7ddc, 0x7fd0, 0x1078, 0x358a, 0x682b, 0x0000, 0x789b, 0x000e, + 0x6f14, 0x1078, 0x4302, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xd0fc, + 0x0040, 0x36f4, 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x7067, + 0x0000, 0x0078, 0x2966, 0x7000, 0xa005, 0x00c0, 0x3701, 0x0078, + 0x2966, 0xa006, 0x1078, 0x44fb, 0x6920, 0xd1ac, 0x00c0, 0x370a, + 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, + 0xa084, 0x00ff, 0x6822, 0x7000, 0x0079, 0x3716, 0x2966, 0x3720, + 0x3720, 0x3723, 0x3723, 0x3723, 0x371e, 0x371e, 0x1078, 0x290c, + 0x6818, 0x0078, 0x3385, 0x6008, 0xc0a4, 0x600a, 0x6817, 0x0000, + 0x0078, 0x3d1b, 0x2300, 0x0079, 0x372d, 0x3730, 0x3732, 0x379d, + 0x1078, 0x290c, 0xd6fc, 0x00c0, 0x3784, 0x7000, 0xa00d, 0x0079, + 0x3739, 0x2966, 0x3743, 0x3743, 0x3772, 0x3743, 0x3781, 0x3741, + 0x3741, 0x1078, 0x290c, 0xa684, 0x0060, 0x0040, 0x3772, 0xa086, + 0x0060, 0x00c0, 0x376f, 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x681c, + 0xc0ac, 0x681e, 0xa186, 0x0002, 0x0040, 0x3761, 0x1078, 0x44fb, + 0x69ac, 0x68b0, 0xa115, 0x0040, 0x3761, 0x1078, 0x486c, 0x0078, + 0x3763, 0x1078, 0x4834, 0x781b, 0x0076, 0x71d4, 0xd1b4, 0x00c0, + 0x2962, 0x70a4, 0xa086, 0x0001, 0x00c0, 0x29ac, 0x007c, 0xd6ec, + 0x0040, 0x374d, 0x6818, 0xd0fc, 0x0040, 0x3781, 0xd6f4, 0x00c0, + 0x377f, 0x681b, 0x0015, 0x781b, 0x0076, 0x0078, 0x2962, 0x681b, + 0x0007, 0x1078, 0x42a2, 0x007c, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, + 0x78d0, 0x801b, 0x00c8, 0x378d, 0x8000, 0xa084, 0x003f, 0xa108, + 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, + 0xa303, 0x68ae, 0x781b, 0x0076, 0x007c, 0x1078, 0x290c, 0x2300, + 0x0079, 0x37a2, 0x37a7, 0x37cc, 0x382b, 0x1078, 0x290c, 0x7000, + 0x0079, 0x37aa, 0x37b2, 0x37b4, 0x37bd, 0x37b2, 0x37b2, 0x37b2, + 0x37b2, 0x37b2, 0x1078, 0x290c, 0x69ac, 0x68b0, 0xa115, 0x0040, + 0x37bd, 0x1078, 0x486c, 0x0078, 0x37bf, 0x1078, 0x4834, 0x681c, + 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x00c0, 0x2962, 0x70a4, 0xa086, + 0x0001, 0x00c0, 0x29ac, 0x007c, 0xd6fc, 0x00c0, 0x381b, 0x7000, + 0xa00d, 0x0079, 0x37d3, 0x2966, 0x37e3, 0x37dd, 0x3812, 0x37e3, + 0x3818, 0x37db, 0x37db, 0x1078, 0x290c, 0x6894, 0x78d6, 0x78de, + 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0x0040, 0x3812, 0xa086, + 0x0060, 0x00c0, 0x380f, 0xa6b4, 0xbfbf, 0xc6ed, 0x7e5a, 0xa186, + 0x0002, 0x0040, 0x37fe, 0x1078, 0x44fb, 0x69ac, 0x68b0, 0xa115, + 0x0040, 0x37fe, 0x1078, 0x486c, 0x0078, 0x3800, 0x1078, 0x4834, + 0x781b, 0x0076, 0x681c, 0xc0b4, 0x681e, 0x71d4, 0xd1b4, 0x00c0, + 0x2962, 0x70a4, 0xa086, 0x0001, 0x00c0, 0x29ac, 0x007c, 0xd6ec, + 0x0040, 0x37ed, 0x6818, 0xd0fc, 0x0040, 0x3818, 0x681b, 0x0007, + 0x781b, 0x00f6, 0x007c, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, + 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, + 0x781b, 0x0076, 0x007c, 0xd6dc, 0x0040, 0x3834, 0x782b, 0x3009, + 0x781b, 0x0076, 0x0078, 0x2962, 0x7884, 0xc0ac, 0x7886, 0x78e4, + 0xa084, 0x0008, 0x00c0, 0x3847, 0xa484, 0x0200, 0x0040, 0x3841, + 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, 0x0076, 0x0078, 0x2962, 0x6820, + 0xc095, 0x6822, 0x1078, 0x421b, 0xc6dd, 0x1078, 0x4051, 0x781b, + 0x0075, 0x0078, 0x2962, 0x2300, 0x0079, 0x3856, 0x3859, 0x385b, + 0x385d, 0x1078, 0x290c, 0x0078, 0x404a, 0xd6d4, 0x00c0, 0x3883, + 0x79e4, 0xd1ac, 0x0040, 0x386b, 0x78ec, 0xa084, 0x0003, 0x0040, + 0x386b, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, + 0xfffb, 0x785a, 0x79e4, 0xd1ac, 0x0040, 0x387b, 0x78ec, 0xa084, + 0x0003, 0x00c0, 0x387f, 0x2001, 0x0014, 0x0078, 0x3385, 0xa184, + 0x0007, 0x0079, 0x38b9, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, + 0x79a8, 0x81ff, 0x0040, 0x38b7, 0x789b, 0x0010, 0x7ba8, 0xa384, + 0x0001, 0x00c0, 0x38aa, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, + 0x389d, 0x2009, 0xfff7, 0x0078, 0x38a3, 0xa386, 0x0003, 0x00c0, + 0x38aa, 0x2009, 0xffef, 0x0c7e, 0x7058, 0x2060, 0x6004, 0xa104, + 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, + 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, + 0x4296, 0x302e, 0x3038, 0x38c3, 0x38c9, 0x38c1, 0x38c1, 0x4296, + 0x4296, 0x1078, 0x290c, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, + 0x429c, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x4296, 0x79e4, + 0xa184, 0x0030, 0x0040, 0x38d9, 0x78ec, 0xa084, 0x0003, 0x00c0, + 0x390d, 0x7000, 0xa086, 0x0004, 0x00c0, 0x38f3, 0x7064, 0xa086, + 0x0002, 0x00c0, 0x38e9, 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, + 0x2eba, 0x7064, 0xa086, 0x0006, 0x0040, 0x38e3, 0x7064, 0xa086, + 0x0004, 0x0040, 0x38e3, 0x7000, 0xa086, 0x0000, 0x0040, 0x2962, + 0x6920, 0xa184, 0x0420, 0x0040, 0x3902, 0xc1d4, 0x6922, 0x6818, + 0x0078, 0x3385, 0x6818, 0xa08e, 0x0002, 0x0040, 0x390b, 0xc0fd, + 0x681a, 0x2001, 0x0014, 0x0078, 0x3385, 0xa184, 0x0007, 0x0079, + 0x3911, 0x4296, 0x4296, 0x3919, 0x4296, 0x42de, 0x42de, 0x4296, + 0x4296, 0xd6bc, 0x0040, 0x395b, 0x7184, 0x81ff, 0x0040, 0x395b, + 0xa182, 0x000d, 0x00d0, 0x3928, 0x7087, 0x0000, 0x0078, 0x392d, + 0xa182, 0x000c, 0x7086, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, + 0x157e, 0x137e, 0x147e, 0x7088, 0x8114, 0xa210, 0x728a, 0xa080, + 0x000b, 0xad00, 0x2098, 0xb284, 0x0300, 0x0040, 0x394f, 0x007e, + 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x394b, 0x20a1, + 0x012b, 0x0078, 0x3951, 0x20a1, 0x022b, 0x0078, 0x3951, 0x20a1, + 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x147f, 0x137f, + 0x157f, 0x0078, 0x429c, 0xd6d4, 0x00c0, 0x39af, 0x6820, 0xd084, + 0x0040, 0x429c, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x396d, + 0xa086, 0x0060, 0x00c0, 0x396d, 0xc1f5, 0xc194, 0x795a, 0x69b6, + 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xc0fd, + 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x3d8c, 0xa18c, 0x00f8, + 0x00c0, 0x3d8c, 0x157e, 0x137e, 0x147e, 0x017e, 0x3208, 0xa18c, + 0x0300, 0x0040, 0x399b, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x3997, 0x20a1, 0x012b, 0x0078, 0x399d, 0x20a1, + 0x022b, 0x0078, 0x399d, 0x20a1, 0x012b, 0x017f, 0x789b, 0x0000, + 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, + 0x157f, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x0078, 0x429c, 0x6818, + 0xd0fc, 0x0040, 0x39b5, 0x681b, 0x0008, 0x6820, 0xc0ad, 0x6822, + 0x1078, 0x4059, 0x781b, 0x00e7, 0x007c, 0x2300, 0x0079, 0x39c0, + 0x39c5, 0x3a9d, 0x39c3, 0x1078, 0x290c, 0x7cd8, 0x7ddc, 0x7fd0, + 0x82ff, 0x00c0, 0x39ee, 0x7200, 0xa286, 0x0003, 0x0040, 0x3352, + 0x71d4, 0xd1bc, 0x00c0, 0x39f1, 0xd1b4, 0x0040, 0x39f1, 0x0d7e, + 0x783b, 0x8800, 0x781b, 0x004c, 0x70bc, 0xa06d, 0x68b4, 0xc0a5, + 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, + 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x0078, 0x39f5, 0x7200, 0x0078, + 0x39f5, 0x783b, 0x1800, 0x781b, 0x004a, 0xa284, 0x000f, 0x0079, + 0x39f9, 0x3a88, 0x3a37, 0x3a03, 0x3381, 0x3a01, 0x3a88, 0x3a01, + 0x3a01, 0x1078, 0x290c, 0x681c, 0xd0ec, 0x0040, 0x3a0a, 0x6008, + 0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, 0x6800, 0x6006, 0xa005, + 0x00c0, 0x3a13, 0x6002, 0x6008, 0xc0d4, 0x600a, 0x681c, 0xa084, + 0x000e, 0x00c0, 0x3a27, 0xb284, 0x0300, 0x0040, 0x3a23, 0x2009, + 0x93c0, 0x0078, 0x3a2c, 0x2009, 0x94d0, 0x0078, 0x3a2c, 0x7030, + 0x68ba, 0x7140, 0x70cc, 0xa108, 0x2104, 0x6802, 0x2d0a, 0x715e, + 0xd6dc, 0x00c0, 0x3a37, 0xc6fc, 0x6eb6, 0x0078, 0x3a88, 0x6eb6, + 0xa684, 0x0060, 0x00c0, 0x3a41, 0xa684, 0x7fff, 0x68b6, 0x0078, + 0x3a88, 0xd6dc, 0x00c0, 0x3a4f, 0xa684, 0x7fff, 0x68b6, 0x6894, + 0x68a6, 0x6898, 0x68aa, 0x1078, 0x44fb, 0x0078, 0x3a88, 0xd6ac, + 0x0040, 0x3a5b, 0xa006, 0x1078, 0x44fb, 0x2408, 0x2510, 0x69aa, + 0x6aa6, 0x0078, 0x3a6b, 0x2408, 0x2510, 0x2700, 0x801b, 0x00c8, + 0x3a62, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x69aa, + 0x6aa6, 0x1078, 0x44fb, 0xd6fc, 0x0040, 0x3a88, 0xa684, 0x7fff, + 0x68b6, 0x2510, 0x2408, 0xd6ac, 0x00c0, 0x3a80, 0x2700, 0x801b, + 0x00c8, 0x3a7b, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, + 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, + 0x7000, 0xa086, 0x0030, 0x00c0, 0x2966, 0x7003, 0x0002, 0x70bc, + 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, + 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0xa586, 0x8800, 0x00c0, + 0x3aaa, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x0078, 0x404a, 0x7047, 0x0000, 0xa282, 0x0006, + 0x0050, 0x3ab4, 0x1078, 0x290c, 0x2300, 0x0079, 0x3ab7, 0x3aba, + 0x3af1, 0x3b23, 0x2200, 0x0079, 0x3abd, 0x3ac3, 0x404a, 0x3ac5, + 0x3ac3, 0x3b5a, 0x3bc2, 0x1078, 0x290c, 0x7003, 0x0005, 0xb284, + 0x0300, 0x0040, 0x3acf, 0x2001, 0x94e0, 0x0078, 0x3ad1, 0x2001, + 0x9512, 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, + 0x8000, 0x00f0, 0x3ad6, 0x157f, 0xb284, 0x0300, 0x0040, 0x3ae4, + 0x6817, 0x0000, 0x0078, 0x3ae6, 0x6817, 0x8000, 0xad80, 0x0009, + 0x7046, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x0078, + 0x4040, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3b02, 0x1078, 0x3d73, + 0x0078, 0x3afc, 0x1078, 0x44fb, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x0078, 0x3b07, 0x7000, 0xa086, 0x0003, 0x0040, 0x3afa, 0x7003, + 0x0005, 0xb284, 0x0300, 0x0040, 0x3b11, 0x2001, 0x94e0, 0x0078, + 0x3b13, 0x2001, 0x9512, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, + 0x2200, 0x0079, 0x3b1b, 0x404a, 0x3b21, 0x3b21, 0x3b5a, 0x3b21, + 0x404a, 0x1078, 0x290c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3b34, + 0x1078, 0x3d73, 0x0078, 0x3b2e, 0x1078, 0x44fb, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x0078, 0x3b39, 0x7000, 0xa086, 0x0003, 0x0040, + 0x3b2c, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3b43, 0x2001, + 0x94e0, 0x0078, 0x3b45, 0x2001, 0x9512, 0x2068, 0x704e, 0xad80, + 0x0009, 0x7046, 0x2200, 0x0079, 0x3b4d, 0x3b55, 0x3b53, 0x3b53, + 0x3b55, 0x3b53, 0x3b55, 0x1078, 0x290c, 0x1078, 0x4064, 0x781b, + 0x0075, 0x007c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3b6c, 0x70d4, + 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3b71, + 0x1078, 0x44fb, 0x0078, 0x3b71, 0x7000, 0xa086, 0x0003, 0x0040, + 0x3b68, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, + 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x93c0, 0xb284, 0x0300, + 0x00c0, 0x3b85, 0xc2fd, 0x2069, 0x94d0, 0x2d04, 0x2d08, 0x715e, + 0xa06d, 0x0040, 0x3b92, 0x6814, 0xa206, 0x0040, 0x3bb2, 0x6800, + 0x0078, 0x3b86, 0x7003, 0x0005, 0xd2fc, 0x00c0, 0x3b9b, 0x2001, + 0x94e0, 0x0078, 0x3b9d, 0x2001, 0x9512, 0x2068, 0x704e, 0x157e, + 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, 0x3ba2, 0x157f, + 0xad80, 0x0009, 0x7046, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, + 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6920, 0xa184, 0x0c00, 0x0040, + 0x3c3c, 0x681b, 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x4059, + 0x0078, 0x3c3c, 0x7200, 0xa286, 0x0002, 0x00c0, 0x3bd4, 0x70d4, + 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3bd8, + 0x1078, 0x44fb, 0x0078, 0x3bd8, 0xa286, 0x0003, 0x0040, 0x3bd0, + 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, + 0xa484, 0x001f, 0xa215, 0xb284, 0x0300, 0x00c0, 0x3be8, 0xc2fd, + 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0x70cc, 0xa168, 0x2d04, 0x2d08, + 0x715e, 0xa06d, 0x0040, 0x3bfb, 0x6814, 0xa206, 0x0040, 0x3c24, + 0x6800, 0x0078, 0x3bef, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, + 0x3c05, 0x2001, 0x94e0, 0x0078, 0x3c07, 0x2001, 0x9512, 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, - 0x39b4, 0x157f, 0xb284, 0x0300, 0x0040, 0x39c2, 0x6817, 0x0000, - 0x0078, 0x39c4, 0x6817, 0x8000, 0xad80, 0x0009, 0x7046, 0x68b7, - 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x0078, 0x3e9d, 0x7000, - 0xa086, 0x0002, 0x00c0, 0x39e0, 0x1078, 0x3bd2, 0x0078, 0x39da, - 0x1078, 0x4326, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0078, 0x39e5, - 0x7000, 0xa086, 0x0003, 0x0040, 0x39d8, 0x7003, 0x0005, 0xb284, - 0x0300, 0x0040, 0x39ef, 0x2001, 0x91e0, 0x0078, 0x39f1, 0x2001, - 0x9212, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, 0x2200, 0x0079, - 0x39f9, 0x3ea7, 0x39ff, 0x39ff, 0x3a38, 0x39ff, 0x3ea7, 0x1078, - 0x28ec, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3a12, 0x1078, 0x3bd2, - 0x0078, 0x3a0c, 0x1078, 0x4326, 0x6008, 0xa084, 0xfbef, 0x600a, - 0x0078, 0x3a17, 0x7000, 0xa086, 0x0003, 0x0040, 0x3a0a, 0x7003, - 0x0005, 0xb284, 0x0300, 0x0040, 0x3a21, 0x2001, 0x91e0, 0x0078, - 0x3a23, 0x2001, 0x9212, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, - 0x2200, 0x0079, 0x3a2b, 0x3a33, 0x3a31, 0x3a31, 0x3a33, 0x3a31, - 0x3a33, 0x1078, 0x28ec, 0x1078, 0x3ebe, 0x781b, 0x0075, 0x007c, - 0x7000, 0xa086, 0x0002, 0x00c0, 0x3a4a, 0x70d4, 0xc0b5, 0x70d6, - 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3a4f, 0x1078, 0x4326, - 0x0078, 0x3a4f, 0x7000, 0xa086, 0x0003, 0x0040, 0x3a46, 0x7003, - 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, - 0x001f, 0xa215, 0x2069, 0x90c0, 0xb284, 0x0300, 0x00c0, 0x3a63, - 0xc2fd, 0x2069, 0x91d0, 0x2d04, 0x2d08, 0x715e, 0xa06d, 0x0040, - 0x3a70, 0x6814, 0xa206, 0x0040, 0x3a90, 0x6800, 0x0078, 0x3a64, - 0x7003, 0x0005, 0xd2fc, 0x00c0, 0x3a79, 0x2001, 0x91e0, 0x0078, - 0x3a7b, 0x2001, 0x9212, 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, - 0x2003, 0x0000, 0x8000, 0x00f0, 0x3a80, 0x157f, 0xad80, 0x0009, - 0x7046, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, - 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x3b10, 0x1078, - 0x3eb6, 0x0078, 0x3b10, 0x7200, 0xa286, 0x0002, 0x00c0, 0x3aad, - 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, - 0x3ab1, 0x1078, 0x4326, 0x0078, 0x3ab1, 0xa286, 0x0003, 0x0040, - 0x3aa9, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, - 0x7ca8, 0xa484, 0x001f, 0xa215, 0xb284, 0x0300, 0x00c0, 0x3ac1, - 0xc2fd, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0x70cc, 0xa168, 0x2d04, - 0x2d08, 0x715e, 0xa06d, 0x0040, 0x3ad4, 0x6814, 0xa206, 0x0040, - 0x3afd, 0x6800, 0x0078, 0x3ac8, 0x7003, 0x0005, 0xb284, 0x0300, - 0x0040, 0x3ade, 0x2001, 0x91e0, 0x0078, 0x3ae0, 0x2001, 0x9212, - 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, - 0x00f0, 0x3ae5, 0x157f, 0xb284, 0x0300, 0x0040, 0x3af2, 0xc2fc, - 0x0078, 0x3af3, 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, - 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x6820, 0xa084, - 0x0c00, 0x0040, 0x3b10, 0xd0dc, 0x0040, 0x3b0a, 0x1078, 0x3eba, - 0x0078, 0x3b10, 0x1078, 0x3eb6, 0x707f, 0x0000, 0x0078, 0x3b10, - 0xa6ac, 0x0060, 0x0040, 0x3b4e, 0x6b98, 0x6c94, 0x69ac, 0x68b0, - 0xa105, 0x00c0, 0x3b33, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, - 0xb7ff, 0xa586, 0x0060, 0x0040, 0x3b4e, 0xc6ed, 0x7e5a, 0x2009, - 0x0076, 0xd69c, 0x0040, 0x3b2e, 0x2009, 0x0075, 0x791a, 0x1078, - 0x45f7, 0x0078, 0x3b57, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, - 0xa305, 0x0040, 0x3b4e, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, - 0xc6f4, 0x7e5a, 0x2011, 0x0076, 0xd69c, 0x0040, 0x3b49, 0x2011, - 0x0075, 0x7a1a, 0x1078, 0x462d, 0x0078, 0x3b57, 0x7e5a, 0x2009, - 0x0076, 0xd69c, 0x0040, 0x3b56, 0x2009, 0x0075, 0x791a, 0x68c0, - 0x705a, 0x2d00, 0x704e, 0x68c4, 0x2060, 0x71d4, 0xd1b4, 0x00c0, - 0x2942, 0x2300, 0xa405, 0x0040, 0x2942, 0x70a4, 0xa086, 0x0001, - 0x00c0, 0x2989, 0x007c, 0x6020, 0xa005, 0x0040, 0x3b79, 0x8001, - 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, 0x700f, 0x0100, 0x702c, - 0x6026, 0x007c, 0xa006, 0x1078, 0x4326, 0x6817, 0x0000, 0x681b, - 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, - 0x0079, 0x3b8a, 0x2946, 0x3b94, 0x3b94, 0x3bb1, 0x3b9c, 0x2946, - 0x3b92, 0x3b92, 0x1078, 0x28ec, 0x1078, 0x3bbc, 0x1078, 0x3bb5, - 0x1078, 0x202a, 0x0078, 0x2946, 0x7064, 0x7067, 0x0000, 0x7083, - 0x0000, 0x0079, 0x3ba3, 0x3bad, 0x3bad, 0x3bab, 0x3bab, 0x3bab, - 0x3bad, 0x3bab, 0x3bad, 0x0079, 0x2e5c, 0x7067, 0x0000, 0x0078, - 0x2946, 0x681b, 0x0000, 0x0078, 0x35ae, 0x6800, 0xa005, 0x00c0, - 0x3bba, 0x6002, 0x6006, 0x007c, 0x6410, 0x84ff, 0x0040, 0x3bce, - 0x2009, 0x4a02, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x00c0, - 0x3bce, 0x2021, 0x4a04, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xc0a4, - 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x3bd8, 0x8001, 0x601a, - 0x007c, 0x1078, 0x4131, 0x681b, 0x0018, 0x0078, 0x3c1a, 0x1078, - 0x4131, 0x681b, 0x0019, 0x0078, 0x3c1a, 0x1078, 0x4131, 0x681b, - 0x001a, 0x0078, 0x3c1a, 0x1078, 0x4131, 0x681b, 0x0003, 0x0078, - 0x3c1a, 0x7774, 0x1078, 0x3fe1, 0x7178, 0xa18c, 0x00ff, 0x3210, - 0xa294, 0x0300, 0x0040, 0x3c00, 0xa1e8, 0x8fc0, 0x0078, 0x3c02, - 0xa1e8, 0x90d0, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, 0x3c0a, - 0x0078, 0x2946, 0x6814, 0xc0fc, 0x7274, 0xc2fc, 0xa206, 0x0040, - 0x3c14, 0x6800, 0x0078, 0x3c03, 0x6800, 0x200a, 0x681b, 0x0005, - 0x707f, 0x0000, 0x1078, 0x3bbc, 0x6820, 0xd084, 0x00c0, 0x3c22, - 0x1078, 0x3bb5, 0x1078, 0x3bd2, 0x681f, 0x0000, 0x6823, 0x0020, - 0x1078, 0x202a, 0x0078, 0x2946, 0xa282, 0x0003, 0x00c0, 0x3e9d, - 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xc1bd, - 0x6922, 0xd1c4, 0x0040, 0x3c86, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, - 0x0040, 0x3c73, 0xa682, 0x000c, 0x0048, 0x3c4a, 0x0040, 0x3c4a, - 0x2031, 0x000c, 0x2500, 0xa086, 0x000a, 0x0040, 0x3c51, 0x852b, - 0x852b, 0x1078, 0x3f73, 0x0040, 0x3c59, 0x1078, 0x3d55, 0x0078, - 0x3c7c, 0x1078, 0x3f2e, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, - 0x6006, 0x1078, 0x3d8a, 0x0c7f, 0x6920, 0xc1c5, 0x6922, 0x7e58, - 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3c70, 0x781b, 0x0061, 0x007c, - 0x781b, 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, - 0x6006, 0x1078, 0x3d8a, 0x0c7f, 0x7e58, 0xd6d4, 0x00c0, 0x3c83, - 0x781b, 0x0064, 0x007c, 0x781b, 0x0076, 0x007c, 0x0c7e, 0x7058, - 0x2060, 0x6100, 0xd1e4, 0x0040, 0x3ccf, 0x6208, 0x8217, 0xa294, - 0x00ff, 0xa282, 0x000c, 0x0048, 0x3c99, 0x0040, 0x3c99, 0x2011, - 0x000c, 0x2600, 0xa202, 0x00c8, 0x3c9e, 0x2230, 0x6208, 0xa294, - 0x00ff, 0x2001, 0x4a05, 0x2004, 0xd0e4, 0x00c0, 0x3cb3, 0x78ec, - 0xd0e4, 0x0040, 0x3cb3, 0xa282, 0x000a, 0x00c8, 0x3cb9, 0x2011, - 0x000a, 0x0078, 0x3cb9, 0xa282, 0x000c, 0x00c8, 0x3cb9, 0x2011, - 0x000c, 0x2200, 0xa502, 0x00c8, 0x3cbe, 0x2228, 0x1078, 0x3f32, - 0x2500, 0xa086, 0x000a, 0x0040, 0x3cc7, 0x852b, 0x852b, 0x1078, - 0x3f73, 0x0040, 0x3ccf, 0x1078, 0x3d55, 0x0078, 0x3cd3, 0x1078, - 0x3f2e, 0x1078, 0x3d8a, 0x7858, 0xc095, 0x785a, 0x0c7f, 0x781b, - 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6000, 0xd0e4, 0x00c0, 0x3cf1, - 0x6010, 0xa084, 0x000f, 0x00c0, 0x3ceb, 0x6104, 0xa18c, 0xfff5, - 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, - 0x3d1c, 0x68a0, 0xd0cc, 0x00c0, 0x3ceb, 0x6208, 0xa294, 0x00ff, - 0x2001, 0x4a05, 0x2004, 0xd0e4, 0x00c0, 0x3d0a, 0x78ec, 0xd0e4, - 0x0040, 0x3d0a, 0xa282, 0x000a, 0x00c0, 0x3d0a, 0x2011, 0x000a, - 0x0078, 0x3d10, 0xa282, 0x000c, 0x00c8, 0x3d10, 0x2011, 0x000c, - 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, 0x0048, 0x3d1c, - 0x0040, 0x3d1c, 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, - 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, - 0x6822, 0x70d4, 0xd0b4, 0x0040, 0x3d38, 0xc0b4, 0x70d6, 0x70b8, - 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, - 0x0c7f, 0x007c, 0x0c7e, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, - 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3d46, 0x78ab, 0x0001, + 0x3c0c, 0x157f, 0xb284, 0x0300, 0x0040, 0x3c19, 0xc2fc, 0x0078, + 0x3c1a, 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, + 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x6920, 0xa184, 0x0c00, + 0x0040, 0x3c3c, 0xd0dc, 0x0040, 0x3c31, 0x1078, 0x4060, 0x0078, + 0x3c3c, 0x681b, 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x4059, + 0x707f, 0x0000, 0x0078, 0x3c3c, 0xc6ec, 0xa6ac, 0x0060, 0x0040, + 0x3c90, 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x00c0, 0x3c69, + 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa586, 0x0060, 0x0040, 0x3c8e, + 0xd6f4, 0x00c0, 0x3c54, 0xc6ed, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, + 0x0076, 0xd69c, 0x0040, 0x3c61, 0x2009, 0x0075, 0x2019, 0x0000, + 0x2320, 0x791a, 0xd6ec, 0x0040, 0x3c99, 0x1078, 0x4834, 0x0078, + 0x3c99, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040, + 0x3c90, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x00c0, + 0x3c7a, 0xc6ed, 0xc6f4, 0x7e5a, 0x2011, 0x0076, 0xd69c, 0x0040, + 0x3c86, 0x2011, 0x0075, 0x2019, 0x0000, 0x2320, 0x7a1a, 0xd6ec, + 0x0040, 0x3c99, 0x1078, 0x486c, 0x0078, 0x3c99, 0xa6b4, 0xb7ff, + 0x7e5a, 0x2009, 0x0076, 0xd69c, 0x0040, 0x3c98, 0x2009, 0x0075, + 0x791a, 0x68c0, 0x705a, 0x2d00, 0x704e, 0x68c4, 0x2060, 0x71d4, + 0x70d8, 0xa02d, 0x0040, 0x3cc1, 0xd1bc, 0x0040, 0x3cdb, 0x7a80, + 0xa294, 0x0f00, 0x70dc, 0xa206, 0x0040, 0x3cb2, 0x78e0, 0xa504, + 0x00c0, 0x3ce8, 0x70da, 0xc1bc, 0x71d6, 0x0078, 0x3ce8, 0x2031, + 0x0001, 0x852c, 0x0048, 0x3cc0, 0x8633, 0x8210, 0x0078, 0x3cb9, + 0x007c, 0x7de0, 0xa594, 0xff00, 0x0040, 0x3cce, 0x2011, 0x0008, + 0x852f, 0x1078, 0x3cb7, 0x8637, 0x0078, 0x3cd0, 0x1078, 0x3cb7, + 0x8217, 0x7880, 0xa084, 0x0f00, 0xa206, 0x0040, 0x3ce8, 0x72de, + 0x76da, 0x0078, 0x3ce8, 0x7a80, 0xa294, 0x0f00, 0x70dc, 0xa236, + 0x0040, 0x3cd8, 0x78e0, 0xa534, 0x0040, 0x3cd8, 0xc1bd, 0x71d6, + 0xd1b4, 0x00c0, 0x2962, 0x2300, 0xa405, 0x0040, 0x2962, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x29ac, 0x007c, 0x6020, 0xa005, 0x0040, + 0x3d03, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, 0x700f, + 0x0100, 0x702c, 0x6026, 0x007c, 0xa006, 0x1078, 0x44fb, 0x7000, + 0xa086, 0x0002, 0x0040, 0x3d11, 0x7064, 0xa086, 0x0005, 0x00c0, + 0x3d1b, 0x682b, 0x0000, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, + 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, 0x0079, 0x3d20, + 0x2966, 0x3d30, 0x3d2a, 0x3d52, 0x3d3a, 0x2966, 0x3d28, 0x3d28, + 0x1078, 0x290c, 0x1078, 0x3d5d, 0x1078, 0x3d56, 0x0078, 0x3d36, + 0x1078, 0x3d5d, 0x705c, 0x2060, 0x6800, 0x6002, 0x1078, 0x2013, + 0x0078, 0x2966, 0x7064, 0x7067, 0x0000, 0x7083, 0x0000, 0x0079, + 0x3d41, 0x3d4e, 0x3d4e, 0x3d49, 0x3d49, 0x3d49, 0x3d4e, 0x3d49, + 0x3d4e, 0x77d4, 0xc7dd, 0x77d6, 0x0079, 0x2ed3, 0x7067, 0x0000, + 0x0078, 0x2966, 0x681b, 0x0000, 0x0078, 0x3653, 0x6800, 0xa005, + 0x00c0, 0x3d5b, 0x6002, 0x6006, 0x007c, 0x6410, 0x84ff, 0x0040, + 0x3d6f, 0x2009, 0x4d02, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, + 0x00c0, 0x3d6f, 0x2021, 0x4d04, 0x2404, 0xc0a5, 0x2022, 0x6008, + 0xc0a4, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x3d79, 0x8001, + 0x601a, 0x007c, 0x1078, 0x42fe, 0x681b, 0x0018, 0x0078, 0x3dbc, + 0x1078, 0x42fe, 0x681b, 0x0019, 0x0078, 0x3dbc, 0x1078, 0x42fe, + 0x681b, 0x001a, 0x0078, 0x3dbc, 0x1078, 0x42fe, 0x681b, 0x0003, + 0x0078, 0x3dbc, 0x7774, 0x1078, 0x4187, 0x7178, 0xa18c, 0x00ff, + 0x3210, 0xa294, 0x0300, 0x0040, 0x3da1, 0xa1e8, 0x92c0, 0x0078, + 0x3da3, 0xa1e8, 0x93d0, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, + 0x3dac, 0x707e, 0x0078, 0x2966, 0x6814, 0xc0fc, 0x7274, 0xc2fc, + 0xa206, 0x0040, 0x3db6, 0x6800, 0x0078, 0x3da4, 0x6800, 0x200a, + 0x681b, 0x0005, 0x707f, 0x0000, 0x1078, 0x3d5d, 0x6820, 0xd084, + 0x00c0, 0x3dc4, 0x1078, 0x3d56, 0x1078, 0x3d73, 0x681f, 0x0000, + 0x6823, 0x0020, 0x1078, 0x2013, 0x0078, 0x2966, 0xa282, 0x0003, + 0x00c0, 0x4040, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, + 0x6920, 0xc1bd, 0x6922, 0xd1c4, 0x0040, 0x3e28, 0xc1c4, 0x6922, + 0xa6b4, 0x00ff, 0x0040, 0x3e15, 0xa682, 0x000c, 0x0048, 0x3dec, + 0x0040, 0x3dec, 0x2031, 0x000c, 0x2500, 0xa086, 0x000a, 0x0040, + 0x3df3, 0x852b, 0x852b, 0x1078, 0x4119, 0x0040, 0x3dfb, 0x1078, + 0x3ef7, 0x0078, 0x3e1e, 0x1078, 0x40d4, 0x0c7e, 0x2960, 0x6004, + 0xa084, 0xfff5, 0x6006, 0x1078, 0x3f2d, 0x0c7f, 0x6920, 0xc1c5, + 0x6922, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3e12, 0x781b, + 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6004, + 0xa084, 0xfff5, 0x6006, 0x1078, 0x3f2d, 0x0c7f, 0x7e58, 0xd6d4, + 0x00c0, 0x3e25, 0x781b, 0x0064, 0x007c, 0x781b, 0x0076, 0x007c, + 0x0c7e, 0x7058, 0x2060, 0x6100, 0xd1e4, 0x0040, 0x3e71, 0x6208, + 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x3e3b, 0x0040, + 0x3e3b, 0x2011, 0x000c, 0x2600, 0xa202, 0x00c8, 0x3e40, 0x2230, + 0x6208, 0xa294, 0x00ff, 0x2001, 0x4d05, 0x2004, 0xd0e4, 0x00c0, + 0x3e55, 0x78ec, 0xd0e4, 0x0040, 0x3e55, 0xa282, 0x000a, 0x00c8, + 0x3e5b, 0x2011, 0x000a, 0x0078, 0x3e5b, 0xa282, 0x000c, 0x00c8, + 0x3e5b, 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8, 0x3e60, 0x2228, + 0x1078, 0x40d8, 0x2500, 0xa086, 0x000a, 0x0040, 0x3e69, 0x852b, + 0x852b, 0x1078, 0x4119, 0x0040, 0x3e71, 0x1078, 0x3ef7, 0x0078, + 0x3e75, 0x1078, 0x40d4, 0x1078, 0x3f2d, 0x7858, 0xc095, 0x785a, + 0x0c7f, 0x781b, 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6000, 0xd0e4, + 0x00c0, 0x3e93, 0x6010, 0xa084, 0x000f, 0x00c0, 0x3e8d, 0x6104, + 0xa18c, 0xfff5, 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, + 0x0000, 0x0078, 0x3ebe, 0x68a0, 0xd0cc, 0x00c0, 0x3e8d, 0x6208, + 0xa294, 0x00ff, 0x2001, 0x4d05, 0x2004, 0xd0e4, 0x00c0, 0x3eac, + 0x78ec, 0xd0e4, 0x0040, 0x3eac, 0xa282, 0x000b, 0x00c8, 0x3eac, + 0x2011, 0x000a, 0x0078, 0x3eb2, 0xa282, 0x000c, 0x00c8, 0x3eb2, + 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, + 0x0048, 0x3ebe, 0x0040, 0x3ebe, 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, - 0x6820, 0xc0c5, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7158, 0x2160, - 0x2018, 0xa08c, 0x0020, 0x0040, 0x3d5e, 0xc0ac, 0x2008, 0xa084, - 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, - 0xa084, 0xfff0, 0xa18c, 0x000f, 0xa105, 0xa39c, 0x0020, 0x0040, - 0x3d73, 0xa085, 0x4000, 0xc0fc, 0xd0b4, 0x00c0, 0x3d78, 0xc0fd, - 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, - 0xa084, 0x00ff, 0xa605, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, - 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x6018, 0x789a, 0x78a4, - 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, - 0x600c, 0xa084, 0x00ff, 0x600e, 0x0c7f, 0x007c, 0xa282, 0x0002, - 0x00c0, 0x3e9d, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0040, - 0x3dd9, 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, - 0x3e9d, 0x1078, 0x3e2a, 0x1078, 0x3d8a, 0xa980, 0x0001, 0x200c, - 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, 0x3dcf, 0x789b, - 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, - 0x3dcc, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, 0x7e58, - 0xd6d4, 0x00c0, 0x3dd6, 0x781b, 0x0064, 0x007c, 0x781b, 0x0076, - 0x007c, 0xa282, 0x0002, 0x00c8, 0x3de1, 0xa284, 0x0001, 0x0040, - 0x3dea, 0x7158, 0xa188, 0x0000, 0x210c, 0xd1ec, 0x00c0, 0x3dea, - 0x2011, 0x0000, 0x1078, 0x3f0f, 0x1078, 0x3e2a, 0x1078, 0x3d8a, - 0x7858, 0xc095, 0x785a, 0x781b, 0x0075, 0x007c, 0x0c7e, 0x027e, - 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x00c0, 0x3e0b, 0x6014, - 0xa084, 0x0040, 0x00c0, 0x3e09, 0xc1a4, 0x6106, 0xa006, 0x0078, - 0x3e27, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, - 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x3e23, - 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, - 0x6018, 0x8001, 0x601a, 0x6820, 0xa085, 0x0200, 0x6822, 0x027f, - 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x82ff, 0x0040, 0x3e32, - 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, - 0xffbf, 0xa205, 0xc0fc, 0xd0b4, 0x00c0, 0x3e3f, 0xc0fd, 0x78a6, - 0x6016, 0x788a, 0x6004, 0xc0a4, 0x6006, 0x0c7f, 0x007c, 0x007e, - 0x7000, 0xa086, 0x0003, 0x0040, 0x3e50, 0x007f, 0x0078, 0x3e53, - 0x007f, 0x0078, 0x3e9a, 0xd6ac, 0x0040, 0x3e9a, 0x7888, 0xa084, - 0x0040, 0x0040, 0x3e9a, 0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, - 0x3e62, 0x8000, 0xa005, 0x0040, 0x3e77, 0x831b, 0x00c8, 0x3e6b, - 0x8001, 0x0040, 0x3e97, 0xd6f4, 0x0040, 0x3e77, 0x78b8, 0x801b, - 0x00c8, 0x3e73, 0x8000, 0xa084, 0x003f, 0x00c0, 0x3e97, 0xc6f4, - 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x3e82, - 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x46e5, - 0x781b, 0x0073, 0xb284, 0x0300, 0x0040, 0x3e92, 0x2001, 0x0000, - 0x0078, 0x3e94, 0x2001, 0x0001, 0x1078, 0x4585, 0x007c, 0x781b, - 0x0073, 0x007c, 0x781b, 0x0076, 0x007c, 0x1078, 0x3ec2, 0x781b, - 0x0075, 0x007c, 0x1078, 0x3eae, 0x781b, 0x0075, 0x007c, 0x6827, - 0x0002, 0x1078, 0x3eb6, 0x781b, 0x0075, 0x007c, 0x2001, 0x0005, - 0x0078, 0x3ec4, 0x2001, 0x000c, 0x0078, 0x3ec4, 0x2001, 0x0006, - 0x0078, 0x3ec4, 0x2001, 0x000d, 0x0078, 0x3ec4, 0x2001, 0x0009, - 0x0078, 0x3ec4, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, - 0x7e5a, 0x70d4, 0xd0b4, 0x0040, 0x3eda, 0xc0b4, 0x70d6, 0x0c7e, - 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, - 0x601a, 0x0c7f, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, - 0x873b, 0x8703, 0x017e, 0xb28c, 0x0300, 0x0040, 0x3eeb, 0xa0e0, - 0x4ec0, 0x0078, 0x3eed, 0xa0e0, 0x4f40, 0x017f, 0xa7b8, 0x0020, - 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040, 0x3efd, 0xa184, 0xfff0, - 0x78a6, 0x6012, 0x6004, 0xc09d, 0x6006, 0x8738, 0x8738, 0x7f9a, - 0x79a4, 0xa184, 0x0040, 0x0040, 0x3f0d, 0xa184, 0xffbf, 0xc0fd, - 0x78a6, 0x6016, 0x6004, 0xc0a5, 0x6006, 0x077f, 0x007c, 0x789b, - 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, - 0x789b, 0x0060, 0x78ab, 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x3f2d, - 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x2031, 0x0000, - 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, - 0x78ab, 0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, - 0x70d4, 0xd0b4, 0x0040, 0x3f51, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, - 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, - 0x0c7f, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, - 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0, 0x2021, 0x3fc6, - 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, - 0xfff0, 0xa106, 0x0040, 0x3f71, 0x8420, 0x2300, 0xa210, 0x00f0, - 0x3f66, 0x157f, 0x007c, 0x157e, 0x2001, 0x4a05, 0x2004, 0xd0e4, - 0x00c0, 0x3fa4, 0x2021, 0x3fd4, 0x20a9, 0x0009, 0x2011, 0x0028, - 0xa582, 0x0019, 0x0040, 0x3fba, 0x0048, 0x3fba, 0x8420, 0x95a9, - 0x2011, 0x0032, 0xa582, 0x0032, 0x0040, 0x3fba, 0x0048, 0x3fba, - 0x8420, 0x95a9, 0x2019, 0x000a, 0x2011, 0x0064, 0x2200, 0xa502, - 0x0040, 0x3fba, 0x0048, 0x3fba, 0x8420, 0x2300, 0xa210, 0x00f0, - 0x3f96, 0x157f, 0x0078, 0x3fb8, 0x2021, 0x3fc6, 0x2019, 0x0011, - 0x20a9, 0x000e, 0x2011, 0x0032, 0x2200, 0xa502, 0x0040, 0x3fba, - 0x0048, 0x3fba, 0x8420, 0x2300, 0xa210, 0x00f0, 0x3fac, 0x157f, - 0xa006, 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8, 0x3fc3, 0x7808, - 0xa085, 0x0070, 0x780a, 0x2404, 0xa005, 0x007c, 0x1209, 0x3002, - 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, - 0x7a06, 0x0c07, 0x0c07, 0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, - 0x6a06, 0x6c06, 0x7c07, 0x7e07, 0x0e00, 0x789b, 0x0010, 0xa046, - 0x007c, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, - 0x8003, 0x8003, 0xa105, 0xd7fc, 0x0040, 0x3ff2, 0xa0e0, 0x6fc0, - 0x0078, 0x3ff4, 0xa0e0, 0x4fc0, 0x007c, 0x0e7e, 0x0f7e, 0xd084, - 0x0040, 0x4002, 0x2079, 0x0100, 0x2009, 0x4a80, 0x2071, 0x4a80, - 0x0078, 0x4014, 0x2009, 0x4a40, 0x007e, 0x2001, 0x4a04, 0x2004, - 0xd0ec, 0x007f, 0x0040, 0x4010, 0x2079, 0x0100, 0x0078, 0x4014, - 0x2079, 0x0200, 0x2071, 0x4a40, 0x2091, 0x8000, 0x2104, 0xa084, - 0x000f, 0x0079, 0x401b, 0x405d, 0x4025, 0x4025, 0x4025, 0x4025, - 0x4025, 0x4023, 0x4023, 0x1078, 0x28ec, 0x784b, 0x0004, 0x7848, - 0xa084, 0x0004, 0x00c0, 0x4027, 0x784b, 0x0008, 0x7848, 0xa084, - 0x0008, 0x00c0, 0x402e, 0x68b4, 0xc0f5, 0x68b6, 0x7858, 0xc0f5, - 0x785a, 0x7830, 0xd0bc, 0x00c0, 0x405d, 0x007e, 0x2001, 0x4a04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x4049, 0xb284, 0x0300, 0x0078, - 0x404b, 0xb284, 0x0400, 0x0040, 0x4051, 0x0018, 0x405d, 0x0078, - 0x4053, 0x0028, 0x405d, 0x681c, 0xd0ac, 0x00c0, 0x405b, 0x1078, - 0x40d5, 0x0078, 0x405d, 0x781b, 0x00f0, 0x2091, 0x8001, 0x0f7f, - 0x0e7f, 0x007c, 0x0c7e, 0x2001, 0x4a01, 0x2004, 0xd0ac, 0x00c0, - 0x40c7, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, - 0xb28c, 0x0300, 0x0040, 0x4078, 0xa0e0, 0x4ec0, 0x0078, 0x407a, - 0xa0e0, 0x4f40, 0x6004, 0xa084, 0x000a, 0x00c0, 0x40c7, 0x6108, - 0xa194, 0xff00, 0x0040, 0x40c7, 0xa18c, 0x00ff, 0x2001, 0x000a, - 0xa106, 0x0040, 0x40a6, 0x2001, 0x000c, 0xa106, 0x0040, 0x40aa, - 0x2001, 0x0012, 0xa106, 0x0040, 0x40ae, 0x2001, 0x0014, 0xa106, - 0x0040, 0x40b2, 0x2001, 0x0019, 0xa106, 0x0040, 0x40b6, 0x2001, - 0x0032, 0xa106, 0x0040, 0x40ba, 0x0078, 0x40be, 0x2009, 0x000c, - 0x0078, 0x40c0, 0x2009, 0x0012, 0x0078, 0x40c0, 0x2009, 0x0014, - 0x0078, 0x40c0, 0x2009, 0x0019, 0x0078, 0x40c0, 0x2009, 0x0020, - 0x0078, 0x40c0, 0x2009, 0x003f, 0x0078, 0x40c0, 0x2011, 0x0000, - 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, - 0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0075, 0x007c, 0x781b, - 0x0064, 0x007c, 0x781b, 0x0061, 0x007c, 0x2009, 0x4a19, 0x210c, - 0xa186, 0x0000, 0x0040, 0x40e7, 0xa186, 0x0001, 0x0040, 0x40ea, - 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, 0x781b, - 0x00e7, 0x007c, 0x701f, 0x000a, 0x007c, 0x2009, 0x4a19, 0x210c, - 0xa186, 0x0000, 0x0040, 0x4102, 0xa186, 0x0001, 0x0040, 0x40ff, - 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, 0x701f, - 0x000a, 0x007c, 0x781b, 0x00e6, 0x007c, 0x781b, 0x00f0, 0x007c, - 0x781b, 0x00ef, 0x007c, 0x781b, 0x00c0, 0x007c, 0x781b, 0x00bf, - 0x007c, 0x6818, 0xd0fc, 0x0040, 0x4117, 0x681b, 0x001d, 0x7067, - 0x0001, 0x781b, 0x0047, 0x007c, 0x7830, 0xa084, 0x00c0, 0x00c0, - 0x4130, 0x7808, 0xc08c, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, - 0x78ec, 0xa084, 0x0021, 0x0040, 0x4130, 0x7808, 0xc08d, 0x780a, - 0x007c, 0x7808, 0xc08d, 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, - 0x00c0, 0x4135, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x0040, 0x4144, - 0xb284, 0x0300, 0x0078, 0x4146, 0xb284, 0x0400, 0x0040, 0x414c, - 0x0098, 0x4150, 0x0078, 0x414e, 0x00a8, 0x4150, 0x78ac, 0x007c, - 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, - 0x78ec, 0xa084, 0x0021, 0x0040, 0x4173, 0x007e, 0x2001, 0x4a04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x4169, 0xb284, 0x0300, 0x0078, - 0x416b, 0xb284, 0x0400, 0x0040, 0x4171, 0x0098, 0x416d, 0x0078, - 0x4173, 0x00a8, 0x4171, 0x78ac, 0x007e, 0x7808, 0xa085, 0x0002, - 0x780a, 0x007f, 0x007c, 0xa784, 0x0001, 0x00c0, 0x360e, 0xa784, - 0x0070, 0x0040, 0x418b, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x2881, - 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x4198, 0x784b, - 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2946, 0x0078, 0x40c9, - 0xa784, 0x0004, 0x0040, 0x41c7, 0x78b8, 0xa084, 0x4001, 0x0040, - 0x41c7, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2946, - 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x41c7, 0x78c0, - 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00f0, 0x007c, 0x784b, - 0x0008, 0x6818, 0xd0fc, 0x0040, 0x41c4, 0x681b, 0x0015, 0xd6f4, - 0x0040, 0x41c4, 0x681b, 0x0007, 0x1078, 0x40d5, 0x007c, 0x681b, - 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833, - 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2f84, - 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x41e4, - 0xb284, 0x0300, 0x0078, 0x41e6, 0xb284, 0x0400, 0x0040, 0x41ec, - 0x0018, 0x2942, 0x0078, 0x41ee, 0x0028, 0x2942, 0x0078, 0x3ea2, - 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, - 0x0040, 0x41fe, 0xa080, 0x4f40, 0x0078, 0x4200, 0xa080, 0x4ec0, - 0x2060, 0x2048, 0x705a, 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, - 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x9906, 0x98f4, - 0x0014, 0x0014, 0x0080, 0x00f1, 0x0100, 0x0402, 0x2008, 0xf880, - 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0x2500, 0x0013, - 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0xa200, - 0x3806, 0x8839, 0x20c4, 0x0864, 0xa850, 0x3008, 0x28c1, 0x9d0d, - 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, - 0x883a, 0xa808, 0x28e2, 0x9cc2, 0xa8f3, 0x0864, 0xa83e, 0x300c, - 0xa801, 0x3008, 0x28e1, 0x9cc2, 0x2021, 0xa81b, 0xa205, 0x870c, - 0xd8de, 0x64a0, 0x6de0, 0x6fc0, 0x63a4, 0x6c80, 0x0212, 0xa205, - 0x883d, 0x9d25, 0x882b, 0x1814, 0x883b, 0x9d2b, 0x883b, 0x7027, - 0x85f2, 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa812, 0x883e, - 0xa810, 0x280c, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x9d25, - 0x1814, 0x9d2b, 0x883b, 0x7023, 0x8576, 0x8677, 0xa802, 0x7861, - 0x883e, 0x206b, 0x28c1, 0x9d0d, 0x2044, 0x2103, 0x20a2, 0x2081, - 0xa8c9, 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, 0x8000, 0x85a4, - 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, - 0x7161, 0x0014, 0x0704, 0x3008, 0x9cc2, 0x0014, 0xa202, 0x8000, - 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, 0x883f, 0x08e6, - 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, - 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, - 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, 0x8000, 0x284a, - 0x1011, 0xa8fc, 0x3008, 0x9d25, 0x8000, 0xa000, 0x2802, 0x1011, - 0xa8fd, 0x9d2b, 0xa887, 0x3008, 0x9d25, 0x283b, 0x1011, 0xa8fd, - 0xa209, 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, - 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, - 0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d17, - 0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, - 0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, - 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, - 0x0016, 0x7944, 0x8421, 0xa020, 0xa532, 0x84a1, 0x0016, 0x7944, - 0x8421, 0xa0df, 0x9532, 0x84a1, 0x0016, 0x0000, 0x127e, 0x70d4, - 0xa084, 0x4600, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205, - 0x00c0, 0x4342, 0x720c, 0x82ff, 0x0040, 0x433d, 0x8aff, 0x00c0, - 0x4342, 0x7200, 0xd284, 0x00c0, 0x4342, 0x7003, 0x0008, 0x127f, - 0x2000, 0x007c, 0x7000, 0xa084, 0x0003, 0x7002, 0xc69c, 0xd084, - 0x0040, 0x4374, 0x2001, 0x4a05, 0x2004, 0xd0ec, 0x00c0, 0x43a5, - 0xd0e4, 0x00c0, 0x435a, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0003, - 0x0040, 0x43a5, 0x0e7e, 0x2071, 0x0010, 0x2009, 0x0007, 0x7008, - 0xa084, 0x3000, 0x00c0, 0x435d, 0x8109, 0x00c0, 0x435f, 0x0e7f, - 0x2009, 0x0007, 0x7008, 0xa084, 0x3000, 0x00c0, 0x435a, 0x8109, - 0x00c0, 0x436a, 0x0078, 0x43a5, 0x7108, 0xd1fc, 0x0040, 0x437f, - 0x1078, 0x44ba, 0x8aff, 0x0040, 0x432c, 0x0078, 0x4374, 0x700c, - 0xa08c, 0x03ff, 0x0040, 0x43aa, 0x7004, 0xd084, 0x0040, 0x439c, - 0x7014, 0xa005, 0x00c0, 0x4398, 0x7010, 0x7310, 0xa306, 0x00c0, - 0x438c, 0x2300, 0xa005, 0x0040, 0x439c, 0xa102, 0x00c8, 0x4374, - 0x7007, 0x0010, 0x0078, 0x43a5, 0x8aff, 0x0040, 0x43aa, 0x1078, - 0x46a3, 0x00c0, 0x439f, 0x0040, 0x4374, 0x1078, 0x4443, 0x127f, - 0x2000, 0x007c, 0x7204, 0x7108, 0xc19c, 0x8103, 0x00c8, 0x43b9, - 0x1078, 0x44ba, 0x0078, 0x43aa, 0x7003, 0x0008, 0x127f, 0x2000, - 0x007c, 0xa205, 0x00c0, 0x43a5, 0x7003, 0x0008, 0x127f, 0x2000, - 0x007c, 0x6428, 0x84ff, 0x0040, 0x43ed, 0x2c70, 0x7004, 0xa0bc, - 0x000f, 0xa7b8, 0x43fd, 0x273c, 0x87fb, 0x00c0, 0x43db, 0x0048, - 0x43d3, 0x1078, 0x28ec, 0x609c, 0xa075, 0x0040, 0x43ed, 0x0078, - 0x43c6, 0x2039, 0x43f2, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, - 0xa529, 0x8421, 0x0040, 0x43ed, 0x8738, 0x2704, 0xa005, 0x00c0, - 0x43dc, 0x709c, 0xa075, 0x00c0, 0x43c6, 0x007c, 0x0000, 0x0005, - 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, - 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x43f2, 0x43ef, - 0x0000, 0x0000, 0x8000, 0x0000, 0x43f2, 0x0000, 0x43fa, 0x43f7, - 0x0000, 0x0000, 0x0000, 0x0000, 0x43fa, 0x0000, 0x43f5, 0x43f5, - 0x0000, 0x0000, 0x8000, 0x0000, 0x43f5, 0x0000, 0x43fb, 0x43fb, - 0x0000, 0x0000, 0x0000, 0x0000, 0x43fb, 0x2079, 0x4a00, 0x2071, - 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0001, 0x7810, - 0xd0ec, 0x0040, 0x4431, 0x2009, 0x0001, 0x2071, 0x0020, 0x0078, - 0x4435, 0x2009, 0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, - 0x0002, 0x7003, 0x0000, 0x8109, 0x0040, 0x4442, 0x2071, 0x0020, - 0x0078, 0x4435, 0x007c, 0x7004, 0x8004, 0x00c8, 0x44a6, 0x7007, - 0x0012, 0x2019, 0x0000, 0x7108, 0x7008, 0xa106, 0x00c0, 0x444b, - 0xa184, 0x01e0, 0x0040, 0x4456, 0x1078, 0x28ec, 0x7810, 0xd0ec, - 0x0040, 0x4470, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0003, 0x00c0, - 0x4474, 0xa184, 0x4000, 0x0040, 0x4478, 0xa382, 0x0003, 0x00c8, - 0x4478, 0xa184, 0x0004, 0x0040, 0x444b, 0x8318, 0x0078, 0x444b, - 0x7814, 0xd0ec, 0x00c0, 0x4478, 0xa184, 0x4000, 0x00c0, 0x444b, - 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x4486, 0xa386, 0x0008, - 0x0040, 0x4491, 0xa386, 0x200c, 0x00c0, 0x444b, 0x7200, 0x8204, - 0x0048, 0x4491, 0x730c, 0xa384, 0x03ff, 0x0040, 0x4491, 0x1078, - 0x28ec, 0x7007, 0x0012, 0x7000, 0xd084, 0x00c0, 0x44a6, 0x7008, - 0xa084, 0x01e0, 0x00c0, 0x44a6, 0x7310, 0x7014, 0xa305, 0x0040, - 0x44a6, 0x710c, 0xa184, 0x03ff, 0x00c0, 0x4443, 0x7007, 0x0012, - 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x44aa, 0x7007, 0x0012, - 0x7108, 0x8103, 0x0048, 0x44ae, 0x7003, 0x0008, 0x007c, 0x7108, - 0x0078, 0x44ba, 0xa184, 0x01e0, 0x00c0, 0x44ee, 0x7108, 0xa184, - 0x01e0, 0x00c0, 0x44ee, 0xa184, 0x0007, 0x0079, 0x44c7, 0x44d1, - 0x44e1, 0x44cf, 0x44e1, 0x44cf, 0x4533, 0x44cf, 0x4531, 0x1078, - 0x28ec, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x00c0, - 0x44dc, 0x2049, 0x0000, 0x007c, 0x1078, 0x46a3, 0x00c0, 0x44dc, - 0x007c, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x0040, - 0x44ed, 0x1078, 0x46a3, 0x00c0, 0x44e9, 0x007c, 0x7007, 0x0012, - 0x7108, 0x00e0, 0x44f1, 0x2091, 0x6000, 0x00e0, 0x44f5, 0x2091, - 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, - 0x44fd, 0x7007, 0x0012, 0x7108, 0xd1fc, 0x00c0, 0x4501, 0x7003, - 0x0000, 0x7000, 0xa005, 0x00c0, 0x4515, 0x7004, 0xa005, 0x00c0, - 0x4515, 0x700c, 0xa005, 0x0040, 0x4517, 0x0078, 0x44f9, 0x2049, - 0x0000, 0xb284, 0x0100, 0x0040, 0x4521, 0x2001, 0x0000, 0x0078, - 0x4523, 0x2001, 0x0001, 0x1078, 0x3ff5, 0x6818, 0xa084, 0x8000, - 0x0040, 0x452c, 0x681b, 0x0002, 0x007c, 0x1078, 0x28ec, 0x1078, - 0x28ec, 0x1078, 0x4570, 0x7210, 0x7114, 0x700c, 0xa09c, 0x03ff, - 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x4570, 0x2704, - 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, - 0x2400, 0xa305, 0x0040, 0x4556, 0x00c8, 0x4556, 0x8412, 0x8210, - 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x453d, 0x2b60, 0x8a07, - 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x4562, 0xa7ba, 0x43f7, - 0x0078, 0x4564, 0xa7ba, 0x43ef, 0x007f, 0xa73d, 0x2c00, 0x6886, - 0x6f8a, 0x6c92, 0x6b8e, 0x7007, 0x0012, 0x1078, 0x4443, 0x007c, - 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x4584, 0x6000, 0xa064, - 0x00c0, 0x457b, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, 0x440d, - 0x203c, 0x87fb, 0x1040, 0x28ec, 0x007c, 0x127e, 0x0d7e, 0x70d4, - 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x6884, 0x2060, 0x6888, - 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, - 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x45a2, 0xa0b8, 0x43f7, - 0x0078, 0x45a4, 0xa0b8, 0x43ef, 0xb284, 0x0100, 0x0040, 0x45ab, - 0x7e20, 0x0078, 0x45ac, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0b4, - 0x0040, 0x45b3, 0xc685, 0x2400, 0xa305, 0x0040, 0x45dd, 0x2c58, - 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, - 0x701e, 0xa184, 0x0008, 0x0040, 0x45cd, 0x6010, 0xa081, 0x0000, - 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, - 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, - 0x2b60, 0x1078, 0x46c6, 0x0078, 0x45df, 0x1078, 0x46a3, 0x00c0, - 0x45dd, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, - 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xd094, - 0x00c0, 0x45ee, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, - 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7e20, - 0xb284, 0x0100, 0x00c0, 0x4605, 0x7e24, 0xa6b5, 0x000c, 0x681c, - 0xd0ac, 0x00c0, 0x4610, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, - 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x43fd, - 0x273c, 0x87fb, 0x00c0, 0x4626, 0x0048, 0x4620, 0x1078, 0x28ec, - 0x689c, 0xa065, 0x0040, 0x462a, 0x0078, 0x4613, 0x1078, 0x46a3, - 0x00c0, 0x4626, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, - 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x7e20, 0xb284, - 0x0100, 0x00c0, 0x463c, 0x7e24, 0x0d7f, 0x037f, 0x047f, 0xa6b5, - 0x000c, 0x681c, 0xd0b4, 0x0040, 0x464a, 0xc685, 0x7003, 0x0000, - 0x7007, 0x0004, 0x2049, 0x462d, 0x6828, 0xa055, 0x0040, 0x46a0, - 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x43fd, 0x273c, - 0x87fb, 0x00c0, 0x4666, 0x0048, 0x465f, 0x1078, 0x28ec, 0x709c, - 0xa075, 0x2060, 0x0040, 0x46a0, 0x0078, 0x4652, 0x2704, 0xae68, - 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, 0x467f, 0x8a51, 0x00c0, - 0x4673, 0x1078, 0x28ec, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4667, - 0x709c, 0xa075, 0x2060, 0x0040, 0x46a0, 0x0078, 0x4652, 0x8422, - 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, - 0x2300, 0xa11b, 0x00c8, 0x468e, 0x1078, 0x28ec, 0xb284, 0x0100, - 0x0040, 0x469c, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x00c0, 0x469c, - 0x2071, 0x0050, 0x0078, 0x469e, 0x2071, 0x0020, 0x0078, 0x45b3, - 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, - 0x00c0, 0x46ab, 0x007c, 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, - 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, 0xa084, 0x0008, - 0x0040, 0x46be, 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, 0x7004, - 0xa084, 0x0010, 0xc085, 0x7006, 0x2079, 0x4a00, 0x8a51, 0x0040, - 0x46e1, 0x8738, 0x2704, 0xa005, 0x00c0, 0x46dc, 0x609c, 0xa005, - 0x0040, 0x46e2, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x43fd, - 0x203c, 0x87fb, 0x1040, 0x28ec, 0x7008, 0xa084, 0x0003, 0xa086, - 0x0003, 0x007c, 0x2051, 0x0000, 0x007c, 0x127e, 0x007e, 0x0d7e, - 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x087f, 0x7108, - 0xa184, 0x0003, 0x00c0, 0x46fa, 0x6828, 0xa005, 0x0040, 0x470a, - 0x0078, 0x4342, 0x7108, 0xd1fc, 0x0040, 0x4702, 0x1078, 0x44ba, - 0x0078, 0x46ef, 0x7007, 0x0010, 0x7108, 0xd1fc, 0x0040, 0x4704, - 0x1078, 0x44ba, 0x7008, 0xa086, 0x0008, 0x00c0, 0x46ef, 0x7000, - 0xa005, 0x00c0, 0x46ef, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, - 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, - 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x2049, 0x471a, - 0xad80, 0x0011, 0x20a0, 0xb284, 0x0100, 0x0040, 0x473d, 0x2001, - 0x4a04, 0x2004, 0xd0ec, 0x0040, 0x4739, 0x2099, 0x0031, 0x0078, - 0x473f, 0x2099, 0x0032, 0x0078, 0x473f, 0x2099, 0x0031, 0x700c, - 0xa084, 0x03ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, - 0x0001, 0x0040, 0x474e, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, - 0x03ff, 0x0040, 0x475a, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, - 0x00c0, 0x4755, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, - 0x137f, 0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x8000, 0x2091, - 0x6000, 0x78ac, 0xa005, 0x00c0, 0x477c, 0x7974, 0x70d0, 0xa106, - 0x00c0, 0x477c, 0x781c, 0xa005, 0x0040, 0x477c, 0x781f, 0x0000, - 0x0068, 0x477c, 0x2091, 0x4080, 0x7830, 0x8001, 0x7832, 0x00c0, - 0x4804, 0x7834, 0x7832, 0x7810, 0xd0ec, 0x00c0, 0x47fd, 0x2061, - 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x68d0, 0xa005, 0x0040, 0x4796, - 0x8001, 0x68d2, 0x00c0, 0x4796, 0x1078, 0x4998, 0x6800, 0xa084, - 0x000f, 0x0040, 0x47ab, 0xa086, 0x0001, 0x0040, 0x47ab, 0x6844, - 0xa00d, 0x0040, 0x47ab, 0x2104, 0xa005, 0x0040, 0x47ab, 0x8001, - 0x200a, 0x0040, 0x4909, 0x6814, 0xa005, 0x0040, 0x47d0, 0x8001, - 0x6816, 0x00c0, 0x47d0, 0x68a7, 0x0001, 0x0f7e, 0xd7fc, 0x00c0, - 0x47c5, 0x7810, 0xd0ec, 0x0040, 0x47c1, 0x2079, 0x0100, 0x0078, - 0x47c7, 0x2079, 0x0200, 0x0078, 0x47c7, 0x2079, 0x0100, 0x1078, - 0x4131, 0x0f7f, 0x6864, 0xa005, 0x0040, 0x47d0, 0x1078, 0x25de, - 0x6880, 0xa005, 0x0040, 0x47dd, 0x8001, 0x6882, 0x00c0, 0x47dd, - 0x6867, 0x0000, 0x68d4, 0xc0dd, 0x68d6, 0x68d4, 0xd0fc, 0x0040, - 0x47fa, 0xc0fc, 0x68d6, 0x20a9, 0x0200, 0x603c, 0xa005, 0x0040, - 0x47f6, 0x8001, 0x603e, 0x68d4, 0xc0fd, 0x68d6, 0x00c0, 0x47f6, - 0x6010, 0xa005, 0x0040, 0x47f6, 0x1078, 0x25de, 0xace0, 0x0010, - 0x00f0, 0x47e5, 0xd7fc, 0x0040, 0x4804, 0x2061, 0x4fc0, 0x2069, - 0x4a40, 0xc7fc, 0x0078, 0x478c, 0x1078, 0x4840, 0x7838, 0x8001, - 0x783a, 0x00c0, 0x4826, 0x783c, 0x783a, 0x2061, 0x4fc0, 0x2069, - 0x4a40, 0xc7fc, 0x680c, 0xa005, 0x0040, 0x4818, 0x1078, 0x487f, - 0xd7fc, 0x00c0, 0x4826, 0x7810, 0xd0ec, 0x00c0, 0x4826, 0x2061, - 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x0078, 0x4812, 0x7814, 0xd0e4, - 0x00c0, 0x482a, 0x7810, 0xd0cc, 0x0040, 0x483d, 0xd0ac, 0x00c0, - 0x4836, 0xd0a4, 0x0040, 0x483d, 0xc0ad, 0x7812, 0x2091, 0x8001, - 0x0068, 0x483c, 0x1078, 0x2368, 0x007c, 0x2091, 0x8001, 0x007c, - 0x7840, 0x8001, 0x7842, 0x00c0, 0x487e, 0x7844, 0x7842, 0x2091, - 0x8000, 0x2061, 0x4fc0, 0x2069, 0x4a40, 0xc7fc, 0x6810, 0xa005, - 0x00c0, 0x4854, 0x2001, 0x0101, 0x8001, 0x6812, 0xd7fc, 0x0040, - 0x485d, 0xa080, 0x90d0, 0x0078, 0x485f, 0xa080, 0x8fc0, 0x2040, - 0x2004, 0xa065, 0x0040, 0x4870, 0x6024, 0xa005, 0x0040, 0x486c, - 0x8001, 0x6026, 0x0040, 0x48ad, 0x6000, 0x2c40, 0x0078, 0x4861, - 0xd7fc, 0x00c0, 0x487e, 0x7810, 0xd0ec, 0x00c0, 0x487e, 0x2061, - 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x0078, 0x484e, 0x007c, 0x2009, - 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0040, 0x4899, 0x6024, - 0xa005, 0x0040, 0x488f, 0x8001, 0x6026, 0x0078, 0x4897, 0x6008, - 0xc09c, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0078, 0x4899, 0xa18d, - 0x0100, 0xace0, 0x0010, 0x00f0, 0x4883, 0xa184, 0x0001, 0x0040, - 0x48a8, 0xa18c, 0xfffe, 0x690e, 0x1078, 0x25de, 0x0078, 0x48a9, - 0x690e, 0x007c, 0x00c0, 0x48a9, 0x786c, 0x6800, 0xa005, 0x0040, - 0x48b5, 0x684c, 0xac06, 0x0040, 0x4909, 0x6864, 0xa005, 0x0040, - 0x48bd, 0x6027, 0x0001, 0x0078, 0x4906, 0x2c00, 0x687e, 0x601b, + 0x6820, 0xc0c5, 0x6822, 0x70d4, 0xd0b4, 0x0040, 0x3eda, 0xc0b4, + 0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, + 0x8001, 0x601a, 0x0c7f, 0x007c, 0x0c7e, 0x2960, 0x6104, 0xa18c, + 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3ee8, + 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, + 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x0c7f, 0x007c, 0x0c7e, + 0x7158, 0x2160, 0x2018, 0xa08c, 0x0020, 0x0040, 0x3f00, 0xc0ac, + 0x2008, 0xa084, 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, + 0x6612, 0x78a4, 0xa084, 0xfff0, 0xa18c, 0x000f, 0xa105, 0xc0f4, + 0xa39c, 0x0020, 0x0040, 0x3f16, 0xa085, 0x4000, 0xc0fc, 0xd0b4, + 0x00c0, 0x3f1b, 0xc0fd, 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x000f, + 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, 0x600e, 0x6004, + 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, + 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, + 0xa084, 0xfff0, 0x7886, 0x600c, 0xa084, 0x00ff, 0x600e, 0x0c7f, + 0x007c, 0xa282, 0x0002, 0x00c0, 0x4040, 0x7aa8, 0x6920, 0xc1bd, + 0x6922, 0xd1cc, 0x0040, 0x3f7c, 0xc1cc, 0x6922, 0xa294, 0x00ff, + 0xa282, 0x0002, 0x00c8, 0x4040, 0x1078, 0x3fcd, 0x1078, 0x3f2d, + 0xa980, 0x0001, 0x200c, 0x1078, 0x4183, 0x1078, 0x3e7c, 0x88ff, + 0x0040, 0x3f72, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, + 0x7e5a, 0xd6d4, 0x00c0, 0x3f6f, 0x781b, 0x0061, 0x007c, 0x781b, + 0x0075, 0x007c, 0x7e58, 0xd6d4, 0x00c0, 0x3f79, 0x781b, 0x0064, + 0x007c, 0x781b, 0x0076, 0x007c, 0xa282, 0x0002, 0x00c8, 0x3f84, + 0xa284, 0x0001, 0x0040, 0x3f8d, 0x7158, 0xa188, 0x0000, 0x210c, + 0xd1ec, 0x00c0, 0x3f8d, 0x2011, 0x0000, 0x1078, 0x40b5, 0x1078, + 0x3fcd, 0x1078, 0x3f2d, 0x7858, 0xc095, 0x785a, 0x781b, 0x0075, + 0x007c, 0x0c7e, 0x027e, 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, + 0x00c0, 0x3fae, 0x6014, 0xa084, 0x0040, 0x00c0, 0x3fac, 0xc1a4, + 0x6106, 0xa006, 0x0078, 0x3fca, 0x2011, 0x0000, 0x78ab, 0x0001, + 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x70d4, + 0xd0b4, 0x0040, 0x3fc6, 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, + 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x6820, 0xa085, + 0x0200, 0x6822, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, + 0x82ff, 0x0040, 0x3fd5, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, + 0x789a, 0x78a4, 0xa084, 0xffbf, 0xa205, 0xc0fc, 0xd0b4, 0x00c0, + 0x3fe2, 0xc0fd, 0x78a6, 0x6016, 0x788a, 0x6004, 0xc0a4, 0x6006, + 0x0c7f, 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x3ff3, + 0x007f, 0x0078, 0x3ff6, 0x007f, 0x0078, 0x403d, 0xd6ac, 0x0040, + 0x403d, 0x7888, 0xa084, 0x0040, 0x0040, 0x403d, 0x7bb8, 0xa384, + 0x003f, 0x831b, 0x00c8, 0x4005, 0x8000, 0xa005, 0x0040, 0x401a, + 0x831b, 0x00c8, 0x400e, 0x8001, 0x0040, 0x403a, 0xd6f4, 0x0040, + 0x401a, 0x78b8, 0x801b, 0x00c8, 0x4016, 0x8000, 0xa084, 0x003f, + 0x00c0, 0x403a, 0xc6f4, 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, + 0xa108, 0x00c8, 0x4025, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, + 0x7ade, 0x1078, 0x493a, 0x781b, 0x0073, 0xb284, 0x0300, 0x0040, + 0x4035, 0x2001, 0x0000, 0x0078, 0x4037, 0x2001, 0x0001, 0x1078, + 0x47c2, 0x007c, 0x781b, 0x0073, 0x007c, 0x781b, 0x0076, 0x007c, + 0x1078, 0x4068, 0x781b, 0x0075, 0x007c, 0x1078, 0x4051, 0x781b, + 0x0075, 0x007c, 0x6827, 0x0002, 0x1078, 0x4059, 0x781b, 0x0075, + 0x007c, 0x2001, 0x0005, 0x0078, 0x406a, 0x2001, 0x000c, 0x0078, + 0x406a, 0x6820, 0xc0d5, 0x6822, 0x2001, 0x0006, 0x0078, 0x406a, + 0x2001, 0x000d, 0x0078, 0x406a, 0x2001, 0x0009, 0x0078, 0x406a, + 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, 0x70d4, + 0xd0b4, 0x0040, 0x4080, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, + 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, + 0x017e, 0xb28c, 0x0300, 0x0040, 0x4091, 0xa0e0, 0x51c0, 0x0078, + 0x4093, 0xa0e0, 0x5240, 0x017f, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, + 0xa184, 0x000f, 0x0040, 0x40a3, 0xa184, 0xfff0, 0x78a6, 0x6012, + 0x6004, 0xc09d, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, + 0x0040, 0x0040, 0x40b3, 0xa184, 0xffbf, 0xc0fd, 0x78a6, 0x6016, + 0x6004, 0xc0a5, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, + 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, + 0x78ab, 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x40d3, 0xc0b4, 0x70d6, + 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, + 0x8001, 0x601a, 0x0c7f, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, + 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, + 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x70d4, 0xd0b4, + 0x0040, 0x40f7, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, + 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, + 0x157e, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, + 0x789a, 0x79a4, 0xa18c, 0xfff0, 0x2021, 0x416c, 0x2019, 0x0011, + 0x20a9, 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, 0xfff0, 0xa106, + 0x0040, 0x4117, 0x8420, 0x2300, 0xa210, 0x00f0, 0x410c, 0x157f, + 0x007c, 0x157e, 0x2001, 0x4d05, 0x2004, 0xd0e4, 0x00c0, 0x414a, + 0x2021, 0x417a, 0x20a9, 0x0009, 0x2011, 0x0028, 0xa582, 0x0019, + 0x0040, 0x4160, 0x0048, 0x4160, 0x8420, 0x95a9, 0x2011, 0x0032, + 0xa582, 0x0032, 0x0040, 0x4160, 0x0048, 0x4160, 0x8420, 0x95a9, + 0x2019, 0x000a, 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x4160, + 0x0048, 0x4160, 0x8420, 0x2300, 0xa210, 0x00f0, 0x413c, 0x157f, + 0x0078, 0x415e, 0x2021, 0x416c, 0x2019, 0x0011, 0x20a9, 0x000e, + 0x2011, 0x0032, 0x2200, 0xa502, 0x0040, 0x4160, 0x0048, 0x4160, + 0x8420, 0x2300, 0xa210, 0x00f0, 0x4152, 0x157f, 0xa006, 0x007c, + 0x157f, 0xa582, 0x0064, 0x00c8, 0x4169, 0x7808, 0xa085, 0x0070, + 0x780a, 0x2404, 0xa005, 0x007c, 0x1209, 0x3002, 0x3202, 0x4203, + 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, + 0x0c07, 0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06, + 0x7c07, 0x7e07, 0x0e00, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, + 0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, + 0xa105, 0xd7fc, 0x0040, 0x4198, 0xa0e0, 0x72c0, 0x0078, 0x419a, + 0xa0e0, 0x52c0, 0x007c, 0x0e7e, 0x0f7e, 0xd084, 0x0040, 0x41a8, + 0x2079, 0x0100, 0x2009, 0x4d80, 0x2071, 0x4d80, 0x0078, 0x41b8, + 0x2009, 0x4d40, 0x2071, 0x4d40, 0x2001, 0x4d04, 0x2004, 0xd0ec, + 0x0040, 0x41b6, 0x2079, 0x0100, 0x0078, 0x41b8, 0x2079, 0x0200, + 0x2091, 0x8000, 0x2104, 0xa084, 0x000f, 0x0079, 0x41bf, 0x41c9, + 0x41c9, 0x41c9, 0x41c9, 0x41c9, 0x41c9, 0x41c7, 0x41c7, 0x1078, + 0x290c, 0x69b4, 0xc1f5, 0xa18c, 0xff9f, 0x69b6, 0xa005, 0x0040, + 0x4218, 0x7858, 0xa084, 0xff9f, 0xa085, 0x6000, 0x785a, 0x7828, + 0xa086, 0x1814, 0x00c0, 0x4218, 0x784b, 0x0004, 0x7848, 0xa084, + 0x0004, 0x00c0, 0x41de, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, + 0x00c0, 0x41e5, 0x7830, 0xd0bc, 0x00c0, 0x4218, 0x007e, 0x2001, + 0x4d04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x41fa, 0xb284, 0x0300, + 0x0078, 0x41fc, 0xb284, 0x0400, 0x0040, 0x4202, 0x0018, 0x4218, + 0x0078, 0x4204, 0x0028, 0x4218, 0x79e4, 0xa184, 0x0030, 0x0040, + 0x4218, 0x78ec, 0xa084, 0x0003, 0x0040, 0x4218, 0x681c, 0xd0ac, + 0x00c0, 0x4216, 0x1078, 0x42a2, 0x0078, 0x4218, 0x781b, 0x00f6, + 0x0f7f, 0x0e7f, 0x007c, 0x0c7e, 0x2001, 0x4d01, 0x2004, 0xd0ac, + 0x00c0, 0x4294, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xb28c, 0x0300, 0x0040, 0x4231, 0xa0e0, 0x51c0, 0x0078, + 0x4233, 0xa0e0, 0x5240, 0x6004, 0xa084, 0x000a, 0x00c0, 0x4294, + 0x6108, 0xa194, 0xff00, 0x0040, 0x4294, 0xa18c, 0x00ff, 0x2001, + 0x000a, 0xa106, 0x0040, 0x425f, 0x2001, 0x000c, 0xa106, 0x0040, + 0x4263, 0x2001, 0x0012, 0xa106, 0x0040, 0x4267, 0x2001, 0x0014, + 0xa106, 0x0040, 0x426b, 0x2001, 0x0019, 0xa106, 0x0040, 0x426f, + 0x2001, 0x0032, 0xa106, 0x0040, 0x4273, 0x0078, 0x4277, 0x2009, + 0x000c, 0x0078, 0x4279, 0x2009, 0x0012, 0x0078, 0x4279, 0x2009, + 0x0014, 0x0078, 0x4279, 0x2009, 0x0019, 0x0078, 0x4279, 0x2009, + 0x0020, 0x0078, 0x4279, 0x2009, 0x003f, 0x0078, 0x4279, 0x2011, + 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, + 0x2061, 0x4d00, 0x6004, 0xd0bc, 0x0040, 0x4294, 0x6814, 0xd0fc, + 0x00c0, 0x428f, 0x60ea, 0x2061, 0x4d40, 0x0078, 0x4292, 0x60ee, + 0x2061, 0x4d80, 0x601f, 0x800f, 0x0c7f, 0x007c, 0x781b, 0x0076, + 0x007c, 0x781b, 0x0075, 0x007c, 0x781b, 0x0064, 0x007c, 0x781b, + 0x0061, 0x007c, 0x2009, 0x4d19, 0x210c, 0xa186, 0x0000, 0x0040, + 0x42b4, 0xa186, 0x0001, 0x0040, 0x42b7, 0x701f, 0x000b, 0x7067, + 0x0001, 0x781b, 0x0047, 0x007c, 0x781b, 0x00ed, 0x007c, 0x701f, + 0x000a, 0x007c, 0x2009, 0x4d19, 0x210c, 0xa186, 0x0000, 0x0040, + 0x42cf, 0xa186, 0x0001, 0x0040, 0x42cc, 0x701f, 0x000b, 0x7067, + 0x0001, 0x781b, 0x0047, 0x007c, 0x701f, 0x000a, 0x007c, 0x781b, + 0x00ec, 0x007c, 0x781b, 0x00f6, 0x007c, 0x781b, 0x00f5, 0x007c, + 0x781b, 0x00c6, 0x007c, 0x781b, 0x00c5, 0x007c, 0x6818, 0xd0fc, + 0x0040, 0x42e4, 0x681b, 0x001d, 0x7067, 0x0001, 0x781b, 0x0047, + 0x007c, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x42fd, 0x7808, 0xc08c, + 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, + 0x0040, 0x42fd, 0x7808, 0xc08d, 0x780a, 0x007c, 0x7808, 0xc08d, + 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, 0x00c0, 0x4302, 0x2001, + 0x4d04, 0x2004, 0xd0ec, 0x0040, 0x4311, 0xb284, 0x0300, 0x0078, + 0x4313, 0xb284, 0x0400, 0x0040, 0x4319, 0x0098, 0x431d, 0x0078, + 0x431b, 0x00a8, 0x431d, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, + 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, + 0x0040, 0x4340, 0x007e, 0x2001, 0x4d04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x4336, 0xb284, 0x0300, 0x0078, 0x4338, 0xb284, 0x0400, + 0x0040, 0x433e, 0x0098, 0x433a, 0x0078, 0x4340, 0x00a8, 0x433e, + 0x78ac, 0x007e, 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, + 0xa784, 0x0001, 0x00c0, 0x36fb, 0xa784, 0x0070, 0x0040, 0x4358, + 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x288d, 0x2d78, 0x2c68, 0x0c7f, + 0xa784, 0x0008, 0x0040, 0x4365, 0x784b, 0x0008, 0x78ec, 0xa084, + 0x0003, 0x0040, 0x2966, 0x0078, 0x4296, 0xa784, 0x0004, 0x0040, + 0x4394, 0x78b8, 0xa084, 0x4001, 0x0040, 0x4394, 0x784b, 0x0008, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x2966, 0x78e4, 0xa084, 0x0007, + 0xa086, 0x0001, 0x00c0, 0x4394, 0x78c0, 0xa685, 0x4800, 0x2030, + 0x7e5a, 0x781b, 0x00f6, 0x007c, 0x784b, 0x0008, 0x6818, 0xd0fc, + 0x0040, 0x4391, 0x681b, 0x0015, 0xd6f4, 0x0040, 0x4391, 0x681b, + 0x0007, 0x1078, 0x42a2, 0x007c, 0x681b, 0x0003, 0x7858, 0xa084, + 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x3004, 0x007e, 0x2001, 0x4d04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x43b1, 0xb284, 0x0300, 0x0078, + 0x43b3, 0xb284, 0x0400, 0x0040, 0x43b9, 0x0018, 0x2962, 0x0078, + 0x43bb, 0x0028, 0x2962, 0x0078, 0x4045, 0x6b14, 0x8307, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, 0x0040, 0x43cb, 0xa080, + 0x5240, 0x0078, 0x43cd, 0xa080, 0x51c0, 0x2060, 0x2048, 0x705a, + 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, + 0x9848, 0x0014, 0x0014, 0x990e, 0x98fa, 0x0014, 0x0014, 0x0080, + 0x00f9, 0x0100, 0x0402, 0x2008, 0xf880, 0x0018, 0xa20a, 0x0014, + 0x300b, 0xa20c, 0x0014, 0x2500, 0x0013, 0x2500, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0xa200, 0x3806, 0x8839, 0x20c4, + 0x0864, 0xa856, 0x3008, 0x28c1, 0x9d15, 0xa201, 0x300c, 0x2847, + 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, + 0x9cc8, 0xa8f3, 0x0864, 0xa844, 0x300c, 0xa801, 0x3008, 0x28e1, + 0x9cc8, 0x2021, 0xa81d, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, + 0x6fc0, 0x63a4, 0x6c80, 0x0212, 0xa205, 0x883d, 0x7942, 0x8020, + 0xa4a1, 0x882b, 0x1814, 0x883b, 0x80df, 0x94a1, 0x7027, 0x85f2, + 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa816, 0x883e, 0xa814, + 0x2001, 0xa812, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x7942, + 0x8020, 0xa4a1, 0x1814, 0x80df, 0x94a1, 0x883b, 0x7023, 0x8576, + 0x8677, 0xa802, 0x7861, 0x883e, 0x206b, 0x28c1, 0x9d15, 0x2044, + 0x2103, 0x20a2, 0x2081, 0xa8c3, 0xa207, 0x2901, 0xa80a, 0x0014, + 0xa203, 0x8000, 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, + 0xa208, 0x856e, 0x866f, 0x7161, 0x0014, 0x0704, 0x3008, 0x9cc8, + 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, + 0x856e, 0x883f, 0x08e6, 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, + 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, + 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, + 0x3008, 0x8000, 0x284a, 0x1011, 0xa8fc, 0x3008, 0x9d2d, 0x8000, + 0xa000, 0x2802, 0x1011, 0xa8fd, 0x9d33, 0xa8bd, 0x3008, 0x9d2d, + 0x283b, 0x1011, 0xa8fd, 0xa209, 0x0017, 0x300c, 0xa209, 0x8000, + 0x85a4, 0x1de2, 0xa209, 0xdac1, 0x0014, 0x0210, 0xa801, 0x0014, + 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, 0x18f2, 0x0014, 0xa20b, + 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d1f, 0x0704, 0xa206, 0x6865, + 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, 0xa8fa, + 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, 0x3008, 0x84a8, 0x11d6, + 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, 0x0016, 0x7944, 0x8421, + 0xa020, 0xa532, 0x84a1, 0x0016, 0x7944, 0x8421, 0xa0df, 0x9532, + 0x84a1, 0x0016, 0x0000, 0x127e, 0x70d4, 0xa084, 0x4600, 0x8004, + 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205, 0x00c0, 0x4517, 0x720c, + 0x82ff, 0x0040, 0x4512, 0x8aff, 0x00c0, 0x4517, 0x7200, 0xd284, + 0x00c0, 0x4517, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x7000, + 0xa084, 0x0003, 0x7002, 0xc69c, 0xd084, 0x0040, 0x455a, 0x7108, + 0x0005, 0x7008, 0xa106, 0x00c0, 0x451f, 0xa184, 0x0003, 0x0040, + 0x458b, 0xa184, 0x01e0, 0x00c0, 0x458b, 0xd1f4, 0x00c0, 0x451f, + 0xa184, 0x3000, 0xa086, 0x1000, 0x0040, 0x451f, 0x2011, 0x0180, + 0x710c, 0x8211, 0x0040, 0x4544, 0x7008, 0xd0f4, 0x00c0, 0x451f, + 0x700c, 0xa106, 0x0040, 0x4539, 0x7007, 0x0012, 0x7108, 0x0005, + 0x7008, 0xa106, 0x00c0, 0x4546, 0xa184, 0x0003, 0x0040, 0x458b, + 0xd194, 0x0040, 0x4546, 0xd1f4, 0x0040, 0x458b, 0x7007, 0x0002, + 0x0078, 0x451f, 0x7108, 0xd1fc, 0x0040, 0x4565, 0x1078, 0x46e0, + 0x8aff, 0x0040, 0x4501, 0x0078, 0x455a, 0x700c, 0xa08c, 0x03ff, + 0x0040, 0x4590, 0x7004, 0xd084, 0x0040, 0x4582, 0x7014, 0xa005, + 0x00c0, 0x457e, 0x7010, 0x7310, 0xa306, 0x00c0, 0x4572, 0x2300, + 0xa005, 0x0040, 0x4582, 0xa102, 0x00c8, 0x455a, 0x7007, 0x0010, + 0x0078, 0x458b, 0x8aff, 0x0040, 0x4590, 0x1078, 0x48e7, 0x00c0, + 0x4585, 0x0040, 0x455a, 0x1078, 0x4629, 0x127f, 0x2000, 0x007c, + 0x7204, 0x7108, 0xc19c, 0x8103, 0x00c8, 0x459f, 0x1078, 0x46e0, + 0x0078, 0x4590, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0xa205, + 0x00c0, 0x458b, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x6428, + 0x84ff, 0x0040, 0x45d3, 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8, + 0x45e3, 0x273c, 0x87fb, 0x00c0, 0x45c1, 0x0048, 0x45b9, 0x1078, + 0x290c, 0x609c, 0xa075, 0x0040, 0x45d3, 0x0078, 0x45ac, 0x2039, + 0x45d8, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, + 0x0040, 0x45d3, 0x8738, 0x2704, 0xa005, 0x00c0, 0x45c2, 0x709c, + 0xa075, 0x00c0, 0x45ac, 0x007c, 0x0000, 0x0005, 0x0009, 0x000d, + 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, + 0x0015, 0x001b, 0x0000, 0x0000, 0x45d8, 0x45d5, 0x0000, 0x0000, + 0x8000, 0x0000, 0x45d8, 0x0000, 0x45e0, 0x45dd, 0x0000, 0x0000, + 0x0000, 0x0000, 0x45e0, 0x0000, 0x45db, 0x45db, 0x0000, 0x0000, + 0x8000, 0x0000, 0x45db, 0x0000, 0x45e1, 0x45e1, 0x0000, 0x0000, + 0x0000, 0x0000, 0x45e1, 0x2079, 0x4d00, 0x2071, 0x0010, 0x7007, + 0x000a, 0x7007, 0x0002, 0x7003, 0x0001, 0x7810, 0xd0ec, 0x0040, + 0x4617, 0x2009, 0x0001, 0x2071, 0x0020, 0x0078, 0x461b, 0x2009, + 0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, + 0x0000, 0x8109, 0x0040, 0x4628, 0x2071, 0x0020, 0x0078, 0x461b, + 0x007c, 0x7004, 0x8004, 0x00c8, 0x46b2, 0x7108, 0x7008, 0xa106, + 0x00c0, 0x462d, 0xa184, 0x01e0, 0x0040, 0x463a, 0x1078, 0x4723, + 0x0078, 0x46da, 0x7007, 0x0012, 0x2019, 0x0000, 0x7108, 0x7008, + 0xa106, 0x00c0, 0x463e, 0xa184, 0x01e0, 0x0040, 0x464b, 0x1078, + 0x4723, 0x0078, 0x46da, 0x7810, 0xd0ec, 0x0040, 0x4665, 0x2001, + 0x04fd, 0x2004, 0xa086, 0x0003, 0x00c0, 0x4669, 0xa184, 0x4000, + 0x0040, 0x466d, 0xa382, 0x0003, 0x00c8, 0x466d, 0xa184, 0x0004, + 0x0040, 0x463e, 0x8318, 0x0078, 0x463e, 0x7814, 0xd0ec, 0x00c0, + 0x466d, 0xa184, 0x4000, 0x00c0, 0x463e, 0xa19c, 0x300c, 0xa386, + 0x2004, 0x0040, 0x468a, 0xa386, 0x0008, 0x0040, 0x4695, 0x7004, + 0xd084, 0x00c0, 0x4686, 0x7108, 0x7008, 0xa106, 0x00c0, 0x467b, + 0xa184, 0x0003, 0x0040, 0x4686, 0x0078, 0x4723, 0xa386, 0x200c, + 0x00c0, 0x463e, 0x7200, 0x8204, 0x0048, 0x4695, 0x730c, 0xa384, + 0x03ff, 0x0040, 0x4695, 0x1078, 0x290c, 0x7108, 0x7008, 0xa106, + 0x00c0, 0x4695, 0xa184, 0x01e0, 0x0040, 0x46a2, 0x1078, 0x4723, + 0x0078, 0x46da, 0x7007, 0x0012, 0x7000, 0xd084, 0x00c0, 0x46b2, + 0x7310, 0x7014, 0xa305, 0x0040, 0x46b2, 0x710c, 0xa184, 0x03ff, + 0x00c0, 0x4629, 0x7108, 0x7008, 0xa106, 0x00c0, 0x46b2, 0xa184, + 0x01e0, 0x0040, 0x46bf, 0x1078, 0x4723, 0x0078, 0x46da, 0x7007, + 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x46c3, 0x7108, + 0x7008, 0xa106, 0x00c0, 0x46c7, 0xa184, 0x01e0, 0x0040, 0x46d4, + 0x1078, 0x4723, 0x0078, 0x46da, 0x7007, 0x0012, 0x7108, 0x8103, + 0x0048, 0x46c7, 0x7003, 0x0008, 0x007c, 0x7108, 0x0078, 0x46e0, + 0xa184, 0x01e0, 0x00c0, 0x4723, 0x7108, 0xa184, 0x01e0, 0x00c0, + 0x4723, 0xa184, 0x0007, 0x0079, 0x46ed, 0x46f7, 0x4707, 0x46f5, + 0x4707, 0x46f5, 0x4765, 0x46f5, 0x4763, 0x1078, 0x290c, 0x7004, + 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x00c0, 0x4702, 0x2049, + 0x0000, 0x007c, 0x1078, 0x48e7, 0x00c0, 0x4702, 0x007c, 0x7004, + 0xa084, 0x0010, 0xc08d, 0x7006, 0x7004, 0xd084, 0x00c0, 0x471b, + 0x7108, 0x7008, 0xa106, 0x00c0, 0x4710, 0xa184, 0x0003, 0x0040, + 0x471b, 0x0078, 0x4723, 0x8aff, 0x0040, 0x4722, 0x1078, 0x48e7, + 0x00c0, 0x471e, 0x007c, 0x7007, 0x0012, 0x7108, 0x00e0, 0x4726, + 0x2091, 0x6000, 0x00e0, 0x472a, 0x2091, 0x6000, 0x7007, 0x0012, + 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x4732, 0x7007, 0x0012, + 0x7108, 0xd1fc, 0x00c0, 0x4736, 0x7003, 0x0000, 0x7000, 0xa005, + 0x00c0, 0x474a, 0x7004, 0xa005, 0x00c0, 0x474a, 0x700c, 0xa005, + 0x0040, 0x474c, 0x0078, 0x472e, 0x2049, 0x0000, 0xb284, 0x0100, + 0x0040, 0x4756, 0x2001, 0x0000, 0x0078, 0x4758, 0x2001, 0x0001, + 0x1078, 0x419b, 0x681b, 0x0002, 0x2051, 0x0000, 0x007c, 0x1078, + 0x290c, 0x1078, 0x290c, 0x1078, 0x47ad, 0x7210, 0x7114, 0x700c, + 0xa09c, 0x03ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, + 0x47ad, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, + 0x2100, 0xa31b, 0x2400, 0xa305, 0x0040, 0x4788, 0x00c8, 0x4788, + 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x476f, + 0x2b60, 0x8a07, 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x4794, + 0xa7ba, 0x45dd, 0x0078, 0x4796, 0xa7ba, 0x45d5, 0x007f, 0xa73d, + 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x7108, 0x7008, 0xa106, + 0x00c0, 0x479d, 0xa184, 0x01e0, 0x0040, 0x47a8, 0x1078, 0x4723, + 0x7007, 0x0012, 0x1078, 0x4629, 0x007c, 0x8a50, 0x8739, 0x2704, + 0xa004, 0x00c0, 0x47c1, 0x6000, 0xa064, 0x00c0, 0x47b8, 0x2d60, + 0x6004, 0xa084, 0x000f, 0xa080, 0x45f3, 0x203c, 0x87fb, 0x1040, + 0x290c, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, + 0x2090, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, + 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804, 0xa084, 0x0008, + 0x007f, 0x0040, 0x47df, 0xa0b8, 0x45dd, 0x0078, 0x47e1, 0xa0b8, + 0x45d5, 0xb284, 0x0100, 0x0040, 0x47e8, 0x7e20, 0x0078, 0x47e9, + 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0040, 0x47f0, 0xc685, + 0x2400, 0xa305, 0x0040, 0x481a, 0x2c58, 0x2704, 0x6104, 0xac60, + 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, 0x0008, + 0x0040, 0x480a, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081, + 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300, + 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, 0x4912, + 0x0078, 0x481c, 0x1078, 0x48e7, 0x00c0, 0x481a, 0x127f, 0x2000, + 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, + 0x0d7f, 0x7007, 0x0004, 0x7004, 0xd094, 0x00c0, 0x482b, 0x7003, + 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, + 0x4600, 0x8004, 0x007e, 0x2090, 0x007f, 0x0d7f, 0x7e20, 0xb284, + 0x0100, 0x00c0, 0x4844, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0ac, + 0x00c0, 0x484f, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, 0x6828, + 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x45e3, 0x273c, + 0x87fb, 0x00c0, 0x4865, 0x0048, 0x485f, 0x1078, 0x290c, 0x689c, + 0xa065, 0x0040, 0x4869, 0x0078, 0x4852, 0x1078, 0x48e7, 0x00c0, + 0x4865, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, + 0x70d4, 0xa084, 0x4600, 0x8004, 0x007e, 0x2090, 0x007f, 0x7e20, + 0xb284, 0x0100, 0x00c0, 0x487d, 0x7e24, 0x0d7f, 0x037f, 0x047f, + 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0040, 0x488b, 0xc685, 0x7003, + 0x0000, 0x7007, 0x0004, 0x2049, 0x486c, 0x6828, 0xa055, 0x0d7e, + 0x0040, 0x48e3, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, + 0x45e3, 0x273c, 0x87fb, 0x00c0, 0x48a8, 0x0048, 0x48a1, 0x1078, + 0x290c, 0x709c, 0xa075, 0x2060, 0x0040, 0x48e3, 0x0078, 0x4894, + 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, 0x48c1, + 0x8a51, 0x00c0, 0x48b5, 0x1078, 0x290c, 0x8738, 0x2704, 0xa005, + 0x00c0, 0x48a9, 0x709c, 0xa075, 0x2060, 0x0040, 0x48e3, 0x0078, + 0x4894, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, + 0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, 0x48d0, 0x1078, 0x290c, + 0xb284, 0x0100, 0x0040, 0x48de, 0x2001, 0x4d04, 0x2004, 0xd0ec, + 0x00c0, 0x48de, 0x2071, 0x0050, 0x0078, 0x48e0, 0x2071, 0x0020, + 0x0d7f, 0x0078, 0x47f0, 0x0d7f, 0x127f, 0x2000, 0x007c, 0x7008, + 0x007e, 0xa084, 0x01e0, 0x007f, 0x0040, 0x48f0, 0xa006, 0x007c, + 0xa084, 0x0003, 0xa086, 0x0003, 0x00c0, 0x48f7, 0x007c, 0x2704, + 0xac78, 0x7800, 0x701a, 0x7804, 0x701e, 0x7808, 0x7012, 0x780c, + 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x490a, 0x7810, 0x7022, + 0x7814, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, 0xc085, 0x7006, + 0x2079, 0x4d00, 0x8a51, 0x0040, 0x4936, 0x8738, 0x2704, 0xa005, + 0x00c0, 0x4928, 0x609c, 0xa005, 0x0040, 0x4937, 0x2060, 0x6004, + 0xa084, 0x000f, 0xa080, 0x45e3, 0x203c, 0x87fb, 0x1040, 0x290c, + 0x7008, 0x007e, 0xa084, 0x01e0, 0x007f, 0x0040, 0x4932, 0xa006, + 0x0078, 0x4937, 0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051, + 0x0000, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x70d4, 0xa084, 0x4600, + 0x8004, 0x2090, 0x0d7f, 0x087f, 0x7108, 0xa184, 0x0003, 0x00c0, + 0x494f, 0x6828, 0xa005, 0x0040, 0x495f, 0x0078, 0x4517, 0x7108, + 0xd1fc, 0x0040, 0x4957, 0x1078, 0x46e0, 0x0078, 0x4944, 0x7007, + 0x0010, 0x7108, 0xd1fc, 0x0040, 0x4959, 0x1078, 0x46e0, 0x7008, + 0xa086, 0x0008, 0x00c0, 0x4944, 0x7000, 0xa005, 0x00c0, 0x4944, + 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, + 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, 0x70d4, 0xa084, 0x4600, + 0x8004, 0x2090, 0x0d7f, 0x2049, 0x496f, 0xad80, 0x0011, 0x20a0, + 0xb284, 0x0100, 0x0040, 0x4992, 0x2001, 0x4d04, 0x2004, 0xd0ec, + 0x0040, 0x498e, 0x2099, 0x0031, 0x0078, 0x4994, 0x2099, 0x0032, + 0x0078, 0x4994, 0x2099, 0x0031, 0x700c, 0xa084, 0x03ff, 0x682a, + 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x49a3, + 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, 0x03ff, 0x0040, 0x49af, + 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x49aa, 0x0c7f, + 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, 0x127f, + 0x2000, 0x007c, 0x2091, 0x8000, 0x2091, 0x6000, 0x78ac, 0xa005, + 0x00c0, 0x49d1, 0x7974, 0x70d0, 0xa106, 0x00c0, 0x49d1, 0x781c, + 0xa005, 0x0040, 0x49d1, 0x781f, 0x0000, 0x0068, 0x49d1, 0x2091, + 0x4080, 0x7830, 0x8001, 0x7832, 0x00c0, 0x4a59, 0x7834, 0x7832, + 0x7810, 0xd0ec, 0x00c0, 0x4a52, 0x2061, 0x72c0, 0x2069, 0x4d80, + 0xc7fd, 0x68d0, 0xa005, 0x0040, 0x49eb, 0x8001, 0x68d2, 0x00c0, + 0x49eb, 0x1078, 0x4c22, 0x6800, 0xa084, 0x000f, 0x0040, 0x4a00, + 0xa086, 0x0001, 0x0040, 0x4a00, 0x6844, 0xa00d, 0x0040, 0x4a00, + 0x2104, 0xa005, 0x0040, 0x4a00, 0x8001, 0x200a, 0x0040, 0x4b95, + 0x6814, 0xa005, 0x0040, 0x4a25, 0x8001, 0x6816, 0x00c0, 0x4a25, + 0x68a7, 0x0001, 0x0f7e, 0xd7fc, 0x00c0, 0x4a1a, 0x7810, 0xd0ec, + 0x0040, 0x4a16, 0x2079, 0x0100, 0x0078, 0x4a1c, 0x2079, 0x0200, + 0x0078, 0x4a1c, 0x2079, 0x0100, 0x1078, 0x42fe, 0x0f7f, 0x6864, + 0xa005, 0x0040, 0x4a25, 0x1078, 0x25ea, 0x6880, 0xa005, 0x0040, + 0x4a32, 0x8001, 0x6882, 0x00c0, 0x4a32, 0x6867, 0x0000, 0x68d4, + 0xc0dd, 0x68d6, 0x68d4, 0xd0fc, 0x0040, 0x4a4f, 0xc0fc, 0x68d6, + 0x20a9, 0x0200, 0x6034, 0xa005, 0x0040, 0x4a4b, 0x8001, 0x6036, + 0x68d4, 0xc0fd, 0x68d6, 0x00c0, 0x4a4b, 0x6010, 0xa005, 0x0040, + 0x4a4b, 0x1078, 0x25ea, 0xace0, 0x0010, 0x00f0, 0x4a3a, 0xd7fc, + 0x0040, 0x4a59, 0x2061, 0x52c0, 0x2069, 0x4d40, 0xc7fc, 0x0078, + 0x49e1, 0x1078, 0x4a95, 0x7838, 0x8001, 0x783a, 0x00c0, 0x4a7b, + 0x783c, 0x783a, 0x2061, 0x52c0, 0x2069, 0x4d40, 0xc7fc, 0x680c, + 0xa005, 0x0040, 0x4a6d, 0x1078, 0x4aec, 0xd7fc, 0x00c0, 0x4a7b, + 0x7810, 0xd0ec, 0x00c0, 0x4a7b, 0x2061, 0x72c0, 0x2069, 0x4d80, + 0xc7fd, 0x0078, 0x4a67, 0x7814, 0xd0e4, 0x00c0, 0x4a7f, 0x7810, + 0xd0cc, 0x0040, 0x4a92, 0xd0ac, 0x00c0, 0x4a8b, 0xd0a4, 0x0040, + 0x4a92, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0068, 0x4a91, 0x1078, + 0x2356, 0x007c, 0x2091, 0x8001, 0x007c, 0x7840, 0x8001, 0x7842, + 0x00c0, 0x4aeb, 0x7844, 0x7842, 0x2091, 0x8000, 0x2061, 0x52c0, + 0x2069, 0x4d40, 0xc7fc, 0x7810, 0x2079, 0x0200, 0xd0ec, 0x0040, + 0x4aab, 0x2079, 0x0100, 0x68d8, 0xa005, 0x0040, 0x4ab7, 0x7de0, + 0xa504, 0x00c0, 0x4ab7, 0x68da, 0x68d4, 0xc0bc, 0x68d6, 0x2079, + 0x4d00, 0x6810, 0xa005, 0x00c0, 0x4abf, 0x2001, 0x0101, 0x8001, + 0x6812, 0xd7fc, 0x0040, 0x4ac8, 0xa080, 0x93d0, 0x0078, 0x4aca, + 0xa080, 0x92c0, 0x2040, 0x2004, 0xa065, 0x0040, 0x4adb, 0x6024, + 0xa005, 0x0040, 0x4ad7, 0x8001, 0x6026, 0x0040, 0x4b37, 0x6000, + 0x2c40, 0x0078, 0x4acc, 0xd7fc, 0x00c0, 0x4aeb, 0x7810, 0xd0ec, + 0x00c0, 0x4aeb, 0x2061, 0x72c0, 0x2069, 0x4d80, 0xc7fd, 0x2079, + 0x0200, 0x0078, 0x4aab, 0x007c, 0x2009, 0x0000, 0x20a9, 0x0200, + 0x6008, 0xd09c, 0x0040, 0x4b23, 0x6024, 0xa005, 0x0040, 0x4afc, + 0x8001, 0x6026, 0x0078, 0x4b21, 0x6008, 0xc09c, 0xd084, 0x00c0, + 0x4b04, 0xd0ac, 0x0040, 0x4b1b, 0x600a, 0x6004, 0xa06d, 0x0040, + 0x4b23, 0x0c7e, 0x017e, 0x6010, 0x8001, 0x6012, 0x1078, 0x3d56, + 0x2d00, 0x2c68, 0x2060, 0x1078, 0x1e42, 0x1078, 0x2004, 0x017f, + 0x0c7f, 0x0078, 0x4b23, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0078, + 0x4b23, 0xa18d, 0x0100, 0xace0, 0x0010, 0x00f0, 0x4af0, 0xa184, + 0x0001, 0x0040, 0x4b32, 0xa18c, 0xfffe, 0x690e, 0x1078, 0x25ea, + 0x0078, 0x4b33, 0x690e, 0x007c, 0x00c0, 0x4b33, 0x786c, 0x6800, + 0xa005, 0x0040, 0x4b3f, 0x684c, 0xac06, 0x0040, 0x4b95, 0x6864, + 0xa005, 0x0040, 0x4b47, 0x6027, 0x0001, 0x0078, 0x4b94, 0x2c00, + 0x687e, 0x6714, 0x6f76, 0x6017, 0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, - 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6f76, 0x1078, - 0x1e02, 0x6818, 0xa005, 0x0040, 0x48d7, 0x8001, 0x681a, 0x6808, - 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x00d0, - 0x48e3, 0x1078, 0x28ec, 0x6812, 0x00c0, 0x48e9, 0x7910, 0xc1a5, - 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x202a, - 0xd7fc, 0x00c0, 0x48f7, 0x2069, 0x4a40, 0x0078, 0x48f9, 0x2069, - 0x4a80, 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x00c0, 0x4903, - 0x697a, 0x2001, 0x0004, 0x2708, 0x1078, 0x25d1, 0x2091, 0x8001, - 0x007c, 0x0d7e, 0x694c, 0x2160, 0xd7fc, 0x00c0, 0x491b, 0x7810, - 0xd0ec, 0x0040, 0x4917, 0x2069, 0x0100, 0x0078, 0x491d, 0x2069, - 0x0200, 0x0078, 0x491d, 0x2069, 0x0100, 0x1078, 0x2881, 0x601b, - 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, - 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6830, - 0xd0b4, 0x0040, 0x494b, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, - 0xd094, 0x0040, 0x493d, 0x00f0, 0x4937, 0x684b, 0x0009, 0x20a9, - 0x0014, 0x6848, 0xd084, 0x0040, 0x4947, 0x00f0, 0x4941, 0x20a9, - 0x00fa, 0x00f0, 0x4949, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, - 0x0047, 0x0d7f, 0x6867, 0x0007, 0x2091, 0x8001, 0x007c, 0x2079, - 0x4a00, 0x1078, 0x498b, 0x1078, 0x4971, 0x1078, 0x497e, 0x2009, - 0x0002, 0x2069, 0x4a80, 0x680f, 0x0000, 0x6813, 0x0000, 0x6817, - 0x0000, 0x8109, 0x0040, 0x4970, 0x2069, 0x4a40, 0x0078, 0x4963, - 0x007c, 0x7810, 0xd0ec, 0x0040, 0x4979, 0x2019, 0x00cc, 0x0078, - 0x497b, 0x2019, 0x007b, 0x7b3a, 0x7b3e, 0x007c, 0x7814, 0xd0e4, - 0x00c0, 0x4986, 0x2019, 0x0040, 0x0078, 0x4988, 0x2019, 0x0026, - 0x7b42, 0x7b46, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x4993, 0x2019, - 0x3f94, 0x0078, 0x4995, 0x2019, 0x2624, 0x7b32, 0x7b36, 0x007c, - 0x6950, 0xa185, 0x0000, 0x0040, 0x49ad, 0x0c7e, 0x6ac0, 0x2264, - 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, 0xc0b5, 0x600a, 0x8210, - 0x8109, 0x00c0, 0x499f, 0x6952, 0x0c7f, 0x007c, 0x70ec, 0xd0dc, - 0x00c0, 0x49b7, 0xd0d4, 0x0040, 0x49d6, 0x0078, 0x49d9, 0x7810, - 0xd0ec, 0x0040, 0x49c2, 0xc0f5, 0x7812, 0xd0ec, 0x0040, 0x49dd, - 0x0078, 0x49d9, 0xae8e, 0x0100, 0x0040, 0x49ce, 0x7814, 0xc0f5, - 0x7816, 0xd0d4, 0x00c0, 0x49dd, 0x0078, 0x49d9, 0x7814, 0xc0fd, - 0x7816, 0xd0d4, 0x00c0, 0x49dd, 0x0078, 0x49d9, 0xd0e4, 0x0040, - 0x49df, 0x7804, 0xd08c, 0x0040, 0x49df, 0x681f, 0x000c, 0x70a0, - 0x70a2, 0x007c, 0x699a + 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x1078, 0x1dcb, 0x6818, + 0xa005, 0x0040, 0x4b65, 0x8001, 0x681a, 0x6808, 0xc0a4, 0x680a, + 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x00d0, 0x4b71, 0x1078, + 0x290c, 0x6812, 0x00c0, 0x4b77, 0x7910, 0xc1a5, 0x7912, 0x602f, + 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x2013, 0xd7fc, 0x00c0, + 0x4b85, 0x2069, 0x4d40, 0x0078, 0x4b87, 0x2069, 0x4d80, 0x6910, + 0xa184, 0x0100, 0x2001, 0x0006, 0x00c0, 0x4b91, 0x697a, 0x2001, + 0x0004, 0x2708, 0x1078, 0x25dd, 0x007c, 0x0d7e, 0x694c, 0x2160, + 0xd7fc, 0x00c0, 0x4ba7, 0x7810, 0xd0ec, 0x0040, 0x4ba3, 0x2069, + 0x0100, 0x0078, 0x4ba9, 0x2069, 0x0200, 0x0078, 0x4ba9, 0x2069, + 0x0100, 0x1078, 0x288d, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, + 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, + 0x0000, 0x6033, 0x0000, 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, + 0xd0b4, 0x0040, 0x4bdb, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, + 0xd094, 0x0040, 0x4bcd, 0x00f0, 0x4bc7, 0x684b, 0x0009, 0x20a9, + 0x0014, 0x6848, 0xd084, 0x0040, 0x4bd7, 0x00f0, 0x4bd1, 0x20a9, + 0x00fa, 0x00f0, 0x4bd9, 0x681b, 0x0047, 0x0d7f, 0x6867, 0x0007, + 0x007c, 0x2079, 0x4d00, 0x1078, 0x4c15, 0x1078, 0x4bfb, 0x1078, + 0x4c08, 0x2009, 0x0002, 0x2069, 0x4d80, 0x680f, 0x0000, 0x6813, + 0x0000, 0x6817, 0x0000, 0x8109, 0x0040, 0x4bfa, 0x2069, 0x4d40, + 0x0078, 0x4bed, 0x007c, 0x7810, 0xd0ec, 0x0040, 0x4c03, 0x2019, + 0x00cc, 0x0078, 0x4c05, 0x2019, 0x007b, 0x7b3a, 0x7b3e, 0x007c, + 0x7814, 0xd0e4, 0x00c0, 0x4c10, 0x2019, 0x0040, 0x0078, 0x4c12, + 0x2019, 0x0026, 0x7b42, 0x7b46, 0x007c, 0x7814, 0xd0e4, 0x00c0, + 0x4c1d, 0x2019, 0x3f94, 0x0078, 0x4c1f, 0x2019, 0x2624, 0x7b32, + 0x7b36, 0x007c, 0x6950, 0xa185, 0x0000, 0x0040, 0x4c37, 0x0c7e, + 0x6ac0, 0x2264, 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, 0xc0b5, + 0x600a, 0x8210, 0x8109, 0x00c0, 0x4c29, 0x6952, 0x0c7f, 0x007c, + 0x70ec, 0xd0dc, 0x00c0, 0x4c41, 0xd0d4, 0x0040, 0x4c64, 0x0078, + 0x4c67, 0x2008, 0x7810, 0xd0ec, 0x0040, 0x4c50, 0xd1c4, 0x00c0, + 0x4c6f, 0xc0f5, 0x7812, 0xd0ec, 0x0040, 0x4c6b, 0x0078, 0x4c67, + 0xae8e, 0x0100, 0x0040, 0x4c5c, 0x7814, 0xc0f5, 0x7816, 0xd0d4, + 0x00c0, 0x4c6b, 0x0078, 0x4c67, 0x7814, 0xc0fd, 0x7816, 0xd0d4, + 0x00c0, 0x4c6b, 0x0078, 0x4c67, 0xd0e4, 0x0040, 0x4c6d, 0x7804, + 0xd08c, 0x0040, 0x4c6d, 0x681f, 0x000c, 0x70a0, 0x70a2, 0x007c, + 0x3782 }; -unsigned short fw1280ei_length01 = 0x39e3; +#ifdef UNIQUE_FW_NAME +unsigned short fw1280ei_length01 = 0x3c71; +#else +unsigned short risc_code_length01 = 0x3c71; +#endif diff -Nur linux-2.4.19/drivers/scsi/ql2100_fw.h linux-2.4.19-sgi211r3/drivers/scsi/ql2100_fw.h --- linux-2.4.19/drivers/scsi/ql2100_fw.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/ql2100_fw.h Tue Jan 8 17:05:38 2002 @@ -0,0 +1,4740 @@ +/************************************************************************ + * * + * --- ISP2100 Fabric Initiator/Target Firmware --- * + * with expanded LUN addressing * + * and FcTape (FCP-2) support * + * * + * * + ************************************************************************ + Copyright (C) 2000 and 2001 Qlogic Corporation + (www.qlogic.com) + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. +************************************************************************/ +/* + * Firmware Version 1.19.16 (10:36 Nov 02, 2000) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_version = 1*1024+19; +#else +unsigned short risc_code_version = 1*1024+19; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw2100tp_version_str[] = {1,19,16}; +#else +unsigned char firmware_version[] = {1,19,16}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw2100tp_VERSION_STRING "1.19.16" +#else +#define FW_VERSION_STRING "1.19.16" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_addr01 = 0x1000 ; +#else +unsigned short risc_code_addr01 = 0x1000 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0078, 0x102d, 0x0000, 0x9260, 0x0000, 0x0001, 0x0013, 0x0010, + 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, + 0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x312e, 0x3139, 0x2020, 0x2020, 0x2400, 0x2091, 0x2000, 0x20c1, + 0x0021, 0x2039, 0xffff, 0x2019, 0xaaaa, 0x2760, 0x2069, 0x7fff, + 0x20c1, 0x0020, 0x2c2c, 0x2d34, 0x2762, 0x236a, 0x2c24, 0x2d04, + 0x266a, 0x2562, 0xa406, 0x00c0, 0x1052, 0x20c1, 0x0021, 0x2c2c, + 0x2362, 0x2c04, 0x2562, 0xa306, 0x0040, 0x1052, 0x20c1, 0x0020, + 0x2039, 0x8fff, 0x20a1, 0xaa00, 0x2708, 0x810d, 0x810d, 0x810d, + 0x810d, 0xa18c, 0x000f, 0x2001, 0x000a, 0xa112, 0xa00e, 0x21a8, + 0x41a4, 0x3400, 0x8211, 0x00c0, 0x105f, 0x2708, 0x3400, 0xa102, + 0x0040, 0x106f, 0x0048, 0x106f, 0x20a8, 0xa00e, 0x41a4, 0x20a1, + 0xa260, 0x2009, 0x0000, 0x20a9, 0x07a0, 0x41a4, 0x3400, 0x20c9, + 0xa7ff, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x255d, + 0x2051, 0xa300, 0x2a70, 0x775e, 0xa786, 0x8fff, 0x0040, 0x1092, + 0x705b, 0xca00, 0x7057, 0xc9f1, 0x7063, 0x0200, 0x7067, 0x0200, + 0x0078, 0x109a, 0x7057, 0xba01, 0x7063, 0x0100, 0x7067, 0x0100, + 0x705b, 0xba00, 0x1078, 0x12df, 0x1078, 0x13c0, 0x1078, 0x1569, + 0x1078, 0x1ca4, 0x1078, 0x4229, 0x1078, 0x74cf, 0x1078, 0x134b, + 0x1078, 0x2a3f, 0x1078, 0x4da2, 0x1078, 0x48b2, 0x1078, 0x57df, + 0x1078, 0x21f7, 0x1078, 0x5abf, 0x1078, 0x5369, 0x1078, 0x210d, + 0x1078, 0x21d4, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x10cf, + 0x7820, 0xa086, 0x0002, 0x00c0, 0x10cf, 0x7823, 0x4000, 0x0068, + 0x10c7, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, + 0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000, + 0xa08e, 0x0003, 0x00c0, 0x10ef, 0x1078, 0x35bc, 0x1078, 0x2a67, + 0x1078, 0x4df2, 0x1078, 0x4a75, 0x2009, 0x0100, 0x2104, 0xa082, + 0x0002, 0x0048, 0x10f3, 0x1078, 0x57fb, 0x0078, 0x10d6, 0x1079, + 0x10f7, 0x0078, 0x10dc, 0x1078, 0x6fa9, 0x0078, 0x10eb, 0x1101, + 0x1102, 0x11be, 0x10ff, 0x1246, 0x12dc, 0x12dd, 0x12de, 0x1078, + 0x1328, 0x007c, 0x127e, 0x0f7e, 0x2091, 0x8000, 0x7000, 0xa086, + 0x0001, 0x00c0, 0x1198, 0x1078, 0x3a43, 0x2079, 0x0100, 0x7844, + 0xa005, 0x00c0, 0x1198, 0x2011, 0x4129, 0x1078, 0x58d4, 0x1078, + 0x1ab1, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, + 0x8010, 0x73c0, 0x1078, 0x3579, 0x2001, 0xffff, 0x1078, 0x5975, + 0x7238, 0xc284, 0x723a, 0x2001, 0xa30c, 0x2014, 0xc2ac, 0x2202, + 0x1078, 0x6db5, 0x2011, 0x0004, 0x1078, 0x8a59, 0x1078, 0x47ce, + 0x1078, 0x4211, 0x0040, 0x1144, 0x7083, 0x0001, 0x70bb, 0x0000, + 0x1078, 0x3bf5, 0x0078, 0x1198, 0x1078, 0x4897, 0x0040, 0x114d, + 0x7a0c, 0xc2b4, 0x7a0e, 0x0078, 0x1159, 0x1078, 0x8ddf, 0x70c8, + 0xd09c, 0x00c0, 0x1159, 0x7094, 0xa005, 0x0040, 0x1159, 0x1078, + 0x41f5, 0x70d3, 0x0000, 0x70cf, 0x0000, 0x72c8, 0x2079, 0xa351, + 0x7804, 0xd0ac, 0x0040, 0x1165, 0xc295, 0x72ca, 0xa296, 0x0004, + 0x0040, 0x1186, 0x2011, 0x0001, 0x1078, 0x8a59, 0x708f, 0x0000, + 0x7093, 0xffff, 0x7003, 0x0002, 0x0f7f, 0x1078, 0x260d, 0x2011, + 0x0005, 0x1078, 0x6ef2, 0x1078, 0x6109, 0x0c7e, 0x2061, 0x0100, + 0x60e3, 0x0008, 0x0c7f, 0x127f, 0x0078, 0x119a, 0x708f, 0x0000, + 0x7093, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, 0x1078, 0x6ef2, + 0x1078, 0x6109, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, + 0x0f7f, 0x127f, 0x007c, 0x0c7e, 0x20a9, 0x0082, 0x2009, 0x007e, + 0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019, 0x0029, 0x1078, + 0x71e0, 0x027f, 0x1078, 0xa190, 0x037f, 0x027f, 0x017f, 0x1078, + 0x2921, 0x8108, 0x00f0, 0x11a0, 0x0c7f, 0x706b, 0x0000, 0x706c, + 0xa084, 0x00ff, 0x706e, 0x7097, 0x0000, 0x007c, 0x127e, 0x2091, + 0x8000, 0x7000, 0xa086, 0x0002, 0x00c0, 0x1244, 0x7090, 0xa086, + 0xffff, 0x0040, 0x11d1, 0x1078, 0x260d, 0x1078, 0x6109, 0x0078, + 0x1244, 0x70c8, 0xd09c, 0x0040, 0x11fd, 0xd084, 0x0040, 0x11fd, + 0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c, + 0x0040, 0x11fd, 0x70cc, 0xa086, 0xffff, 0x0040, 0x11f9, 0x1078, + 0x278a, 0x1078, 0x6109, 0x70c8, 0xd094, 0x00c0, 0x1244, 0x2011, + 0x0001, 0x2019, 0x0000, 0x1078, 0x27c2, 0x1078, 0x6109, 0x0078, + 0x1244, 0x70d0, 0xa005, 0x00c0, 0x1244, 0x708c, 0xa005, 0x00c0, + 0x1244, 0x1078, 0x4897, 0x00c0, 0x1244, 0x2001, 0xa352, 0x2004, + 0xd0ac, 0x0040, 0x1227, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, 0x121a, 0x6000, 0xd0ec, + 0x00c0, 0x1222, 0x017f, 0x8108, 0x00f0, 0x1211, 0x0c7f, 0x157f, + 0x0078, 0x1227, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x1244, 0x7003, + 0x0003, 0x7093, 0xffff, 0x2001, 0x0000, 0x1078, 0x2480, 0x1078, + 0x35f7, 0x2001, 0xa5ac, 0x2004, 0xa086, 0x0005, 0x00c0, 0x123c, + 0x2011, 0x0000, 0x1078, 0x6ef2, 0x2011, 0x0000, 0x1078, 0x6efc, + 0x1078, 0x6109, 0x1078, 0x61d3, 0x127f, 0x007c, 0x017e, 0x0f7e, + 0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, 0x1078, + 0x41de, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0040, + 0x125b, 0x7827, 0x0040, 0xd19c, 0x0040, 0x1260, 0x7827, 0x0008, + 0x007e, 0x037e, 0x157e, 0xa006, 0x1078, 0x5975, 0x7900, 0xa18a, + 0x0003, 0x0050, 0x1289, 0x7954, 0xd1ac, 0x00c0, 0x1289, 0x2009, + 0x00f8, 0x1078, 0x41de, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, + 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x1281, 0x7824, 0xd0ac, 0x00c0, + 0x12ca, 0x00f0, 0x1279, 0x2001, 0x0001, 0x1078, 0x2480, 0x0078, + 0x12d5, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0050, 0x00e0, + 0x128f, 0x2091, 0x6000, 0x00f0, 0x128f, 0x7853, 0x0400, 0x782f, + 0x0000, 0x2009, 0x00f8, 0x1078, 0x41de, 0x20a9, 0x000e, 0x0005, + 0x00f0, 0x129f, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010, + 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, 0x12b4, + 0x7824, 0xd0ac, 0x00c0, 0x12ca, 0x8319, 0x00c0, 0x12aa, 0x2009, + 0xa331, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0040, 0x12c4, + 0x200b, 0x0000, 0x1078, 0x251e, 0x2001, 0x0001, 0x1078, 0x2480, + 0x0078, 0x12d3, 0x2001, 0xa331, 0x2003, 0x0000, 0x7828, 0xc09d, + 0x782a, 0x7827, 0x0048, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f, + 0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70, + 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, 0x12eb, 0x704f, + 0xffff, 0x0078, 0x12ed, 0x704f, 0x0000, 0x7053, 0xffff, 0x706b, + 0x0000, 0x706f, 0x0000, 0x1078, 0x8ddf, 0x2061, 0xa58c, 0x6003, + 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, + 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, + 0xa594, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, + 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, + 0x0000, 0x2061, 0xa5a3, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, + 0x4943, 0x600f, 0x2020, 0x2001, 0xa325, 0x2003, 0x0000, 0x007c, + 0x2091, 0x8000, 0x0068, 0x132a, 0x007e, 0x017e, 0x2079, 0x0000, + 0x7818, 0xd084, 0x00c0, 0x1330, 0x017f, 0x792e, 0x007f, 0x782a, + 0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, + 0x2091, 0x5000, 0x2091, 0x4080, 0x2079, 0xa300, 0x7803, 0x0005, + 0x0078, 0x1348, 0x007c, 0x2071, 0xa300, 0x7158, 0x712e, 0x2021, + 0x0001, 0xa190, 0x002d, 0xa298, 0x002d, 0x0048, 0x1361, 0x705c, + 0xa302, 0x00c8, 0x1361, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, + 0x1353, 0x200b, 0x0000, 0x74a6, 0x74aa, 0x007c, 0x0e7e, 0x127e, + 0x2091, 0x8000, 0x2071, 0xa300, 0x70a8, 0xa0ea, 0x0010, 0x00c8, + 0x1374, 0xa06e, 0x0078, 0x137e, 0x8001, 0x70aa, 0x702c, 0x2068, + 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, + 0x007c, 0x0e7e, 0x2071, 0xa300, 0x127e, 0x2091, 0x8000, 0x70a8, + 0x8001, 0x00c8, 0x138e, 0xa06e, 0x0078, 0x1397, 0x70aa, 0x702c, + 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, + 0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa300, + 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a8, 0x8000, 0x70aa, 0x127f, + 0x0e7f, 0x007c, 0x8dff, 0x0040, 0x13b6, 0x6804, 0x6807, 0x0000, + 0x007e, 0x1078, 0x139a, 0x0d7f, 0x0078, 0x13aa, 0x007c, 0x0e7e, + 0x2071, 0xa300, 0x70a8, 0xa08a, 0x0010, 0xa00d, 0x0e7f, 0x007c, + 0x0e7e, 0x2071, 0xa5d0, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, + 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x0e7f, + 0x007c, 0x0e7e, 0x2270, 0x700b, 0x0000, 0x2071, 0xa5d0, 0x7018, + 0xa088, 0xa5d9, 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, + 0xa005, 0x00c0, 0x13e9, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13fa, + 0x0f7f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa5d0, 0x7004, 0xa005, + 0x00c0, 0x13f8, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13fa, 0x0f7f, + 0x0e7f, 0x007c, 0x7000, 0x0079, 0x13fd, 0x1401, 0x146b, 0x1488, + 0x1488, 0x7018, 0x711c, 0xa106, 0x00c0, 0x1409, 0x7007, 0x0000, + 0x007c, 0x0d7e, 0xa180, 0xa5d9, 0x2004, 0x700a, 0x2068, 0x8108, + 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, + 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, + 0x7016, 0x6804, 0x0d7f, 0xd084, 0x0040, 0x142b, 0x7007, 0x0001, + 0x1078, 0x1430, 0x007c, 0x7007, 0x0002, 0x1078, 0x1446, 0x007c, + 0x017e, 0x027e, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, + 0x143b, 0x2110, 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, + 0x0020, 0x7803, 0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e, + 0x137e, 0x147e, 0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, + 0x0026, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x145a, + 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, + 0x0020, 0x3300, 0x7016, 0x7803, 0x0001, 0x157f, 0x147f, 0x137f, + 0x027f, 0x017f, 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0xa3f9, + 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, + 0x2091, 0x8000, 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, + 0x7002, 0x700b, 0xa3f4, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, + 0x137e, 0x147e, 0x157e, 0x2001, 0xa428, 0x209c, 0x20a1, 0x0014, + 0x7803, 0x0026, 0x2001, 0xa429, 0x20ac, 0x53a6, 0x2099, 0xa42a, + 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, + 0x2091, 0x8000, 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, + 0x7002, 0x700b, 0xa425, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, + 0x017e, 0x0e7e, 0x2071, 0xa5d0, 0x0f7e, 0x2079, 0x0010, 0x7904, + 0x7803, 0x0002, 0xd1fc, 0x0040, 0x14c2, 0xa18c, 0x0700, 0x7004, + 0x1079, 0x14c6, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x13fa, 0x14ce, + 0x14fb, 0x1523, 0x1556, 0x14cc, 0x0078, 0x14cc, 0xa18c, 0x0700, + 0x00c0, 0x14f4, 0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099, + 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, + 0x157f, 0x147f, 0x137f, 0x700c, 0xa005, 0x0040, 0x1510, 0x1078, + 0x1430, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, + 0x0000, 0x1078, 0x13fa, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, + 0x0200, 0x0078, 0x14ef, 0xa18c, 0x0700, 0x00c0, 0x1506, 0x700c, + 0xa005, 0x0040, 0x1510, 0x1078, 0x1446, 0x007c, 0x7008, 0xa080, + 0x0002, 0x2003, 0x0200, 0x7007, 0x0000, 0x1078, 0x13fa, 0x007c, + 0x0d7e, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, + 0x682e, 0x783c, 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, + 0x1078, 0x13fa, 0x007c, 0xa18c, 0x0700, 0x00c0, 0x1550, 0x137e, + 0x147e, 0x157e, 0x2001, 0xa3f7, 0x2004, 0xa080, 0x000d, 0x20a0, + 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001, + 0xa3f9, 0x2004, 0xd0bc, 0x0040, 0x1546, 0x2001, 0xa402, 0x2004, + 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x157f, 0x147f, + 0x137f, 0x7007, 0x0000, 0x1078, 0x4e9b, 0x1078, 0x13fa, 0x007c, + 0x2011, 0x8003, 0x1078, 0x3579, 0x0078, 0x1554, 0xa18c, 0x0700, + 0x00c0, 0x1563, 0x2001, 0xa427, 0x2003, 0x0100, 0x7007, 0x0000, + 0x1078, 0x13fa, 0x007c, 0x2011, 0x8004, 0x1078, 0x3579, 0x0078, + 0x1567, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0xa5e1, + 0x7803, 0x0004, 0x7003, 0x0000, 0x700f, 0xa5e7, 0x7013, 0xa5e7, + 0x780f, 0x0076, 0x7803, 0x0004, 0x127f, 0x007c, 0x6934, 0xa184, + 0x0007, 0x0079, 0x1583, 0x158b, 0x15d1, 0x158b, 0x158b, 0x158b, + 0x15b6, 0x159a, 0x158f, 0xa085, 0x0001, 0x0078, 0x15eb, 0x684c, + 0xd0bc, 0x0040, 0x158b, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, + 0x0078, 0x15d9, 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x158b, + 0x684c, 0xd0bc, 0x0040, 0x158b, 0x6860, 0x682e, 0x685c, 0x682a, + 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, + 0x2015, 0x2004, 0x6832, 0x6858, 0x0078, 0x15e1, 0xa18c, 0x00ff, + 0xa186, 0x0015, 0x00c0, 0x158b, 0x684c, 0xd0ac, 0x0040, 0x158b, + 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, + 0x2015, 0x2004, 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, + 0x15e1, 0x684c, 0xd0ac, 0x0040, 0x158b, 0xa006, 0x682e, 0x682a, + 0x6858, 0xa18c, 0x000f, 0xa188, 0x2015, 0x210c, 0x6932, 0x2d08, + 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, + 0x6912, 0x6980, 0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000, + 0x2001, 0x020a, 0x2004, 0x82ff, 0x0040, 0x160e, 0xa280, 0x0004, + 0x0d7e, 0x206c, 0x684c, 0xd0dc, 0x00c0, 0x160a, 0x1078, 0x157e, + 0x0040, 0x160a, 0x0d7f, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, + 0x0078, 0x160e, 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, + 0x037e, 0x027e, 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, + 0xa005, 0x00c0, 0x1622, 0x7206, 0x2001, 0x1643, 0x007e, 0x2260, + 0x0078, 0x17be, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, + 0x8108, 0xa182, 0xa602, 0x0048, 0x162f, 0x2009, 0xa5e7, 0x710e, + 0x7010, 0xa102, 0xa082, 0x0009, 0x0040, 0x163a, 0xa080, 0x001b, + 0x00c0, 0x163d, 0x2009, 0x0138, 0x200a, 0x7000, 0xa005, 0x00c0, + 0x1643, 0x1078, 0x179f, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e, + 0x0c7e, 0x007e, 0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f, + 0x0d7e, 0x0c7e, 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, 0xa005, + 0x0040, 0x16cf, 0x6808, 0xa005, 0x0040, 0x173c, 0x7000, 0xa005, + 0x00c0, 0x1664, 0x0078, 0x16c4, 0x700c, 0x7110, 0xa106, 0x00c0, + 0x1745, 0x7004, 0xa406, 0x00c0, 0x16c4, 0x2001, 0x0005, 0x2004, + 0xd08c, 0x0040, 0x1681, 0x047e, 0x1078, 0x18e2, 0x047f, 0x2460, + 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x0040, 0x173c, 0x0078, + 0x165e, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x166d, 0x7804, + 0xa084, 0x6000, 0x0040, 0x1692, 0xa086, 0x6000, 0x0040, 0x1692, + 0x0078, 0x166d, 0x7100, 0xa186, 0x0002, 0x00c0, 0x16b2, 0x0e7e, + 0x2b68, 0x6818, 0x2060, 0x1078, 0x1fea, 0x2804, 0xac70, 0x6034, + 0xd09c, 0x00c0, 0x16a7, 0x7108, 0x720c, 0x0078, 0x16a9, 0x7110, + 0x7214, 0x6810, 0xa100, 0x6812, 0x6814, 0xa201, 0x6816, 0x0e7f, + 0x0078, 0x16b6, 0xa186, 0x0001, 0x00c0, 0x16be, 0x7820, 0x6910, + 0xa100, 0x6812, 0x7824, 0x6914, 0xa101, 0x6816, 0x7803, 0x0004, + 0x7003, 0x0000, 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x00c0, + 0x1745, 0x2009, 0x0048, 0x1078, 0x756c, 0x0078, 0x1745, 0x6808, + 0xa005, 0x0040, 0x173c, 0x7000, 0xa005, 0x00c0, 0x16d9, 0x0078, + 0x173c, 0x700c, 0x7110, 0xa106, 0x00c0, 0x16e2, 0x7004, 0xa406, + 0x00c0, 0x173c, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, 0x16f6, + 0x047e, 0x1078, 0x18e2, 0x047f, 0x2460, 0x6010, 0xa080, 0x0002, + 0x2004, 0xa005, 0x0040, 0x173c, 0x0078, 0x16d3, 0x2001, 0x0207, + 0x2004, 0xd09c, 0x00c0, 0x16e2, 0x2001, 0x0005, 0x2004, 0xd08c, + 0x00c0, 0x16e8, 0x7804, 0xa084, 0x6000, 0x0040, 0x170d, 0xa086, + 0x6000, 0x0040, 0x170d, 0x0078, 0x16e2, 0x7007, 0x0000, 0xa016, + 0x2218, 0x7000, 0xa08e, 0x0001, 0x0040, 0x172e, 0xa08e, 0x0002, + 0x00c0, 0x173c, 0x0c7e, 0x0e7e, 0x6818, 0x2060, 0x1078, 0x1fea, + 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, 0x172a, 0x7308, 0x720c, + 0x0078, 0x172c, 0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318, + 0x7824, 0xa211, 0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816, + 0x7803, 0x0004, 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x00c0, + 0x1745, 0x2009, 0x0048, 0x1078, 0x756c, 0x0c7f, 0x0d7f, 0x127f, + 0x007c, 0x0f7e, 0x0e7e, 0x027e, 0x037e, 0x047e, 0x1078, 0x1af7, + 0x027e, 0x2071, 0xa5e1, 0x7000, 0xa086, 0x0000, 0x0040, 0x1790, + 0x7004, 0xac06, 0x00c0, 0x1781, 0x2079, 0x0030, 0x7000, 0xa086, + 0x0003, 0x0040, 0x1781, 0x7804, 0xd0fc, 0x00c0, 0x177d, 0x2001, + 0x0207, 0x2004, 0xd09c, 0x00c0, 0x1763, 0x7803, 0x0004, 0x7804, + 0xd0ac, 0x00c0, 0x176f, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, + 0x0003, 0x7007, 0x0000, 0x0078, 0x1781, 0x1078, 0x18e2, 0x0078, + 0x1753, 0x157e, 0x20a9, 0x0009, 0x2009, 0xa5e7, 0x2104, 0xac06, + 0x00c0, 0x178b, 0x200a, 0xa188, 0x0003, 0x00f0, 0x1786, 0x157f, + 0x027f, 0x2001, 0x015d, 0x201c, 0x831a, 0x2302, 0x2001, 0x0138, + 0x2202, 0x047f, 0x037f, 0x027f, 0x0e7f, 0x0f7f, 0x007c, 0x700c, + 0x7110, 0xa106, 0x00c0, 0x17a7, 0x7003, 0x0000, 0x007c, 0x2104, + 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, 0xa182, + 0xa602, 0x0048, 0x17b5, 0x2009, 0xa5e7, 0x7112, 0x700c, 0xa106, + 0x00c0, 0x17be, 0x2001, 0x0138, 0x2003, 0x0008, 0x8cff, 0x00c0, + 0x17c5, 0x1078, 0x1b22, 0x0078, 0x1823, 0x6010, 0x2068, 0x2d58, + 0x6828, 0xa406, 0x00c0, 0x17d0, 0x682c, 0xa306, 0x0040, 0x17fe, + 0x601c, 0xa086, 0x0008, 0x0040, 0x17fe, 0x6024, 0xd0f4, 0x00c0, + 0x17fa, 0xd0d4, 0x0040, 0x17f6, 0x6038, 0xa402, 0x6034, 0xa303, + 0x0040, 0x17e4, 0x00c8, 0x17f6, 0x643a, 0x6336, 0x6c2a, 0x6b2e, + 0x047e, 0x037e, 0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80, + 0xa303, 0x6816, 0x037f, 0x047f, 0x0078, 0x17fa, 0x1078, 0x8d8e, + 0x0040, 0x17c1, 0x1078, 0x2035, 0x00c0, 0x17c1, 0x0c7e, 0x7004, + 0x2060, 0x6024, 0xc0d4, 0x6026, 0x0c7f, 0x684c, 0xd0f4, 0x0040, + 0x180f, 0x6817, 0xffff, 0x6813, 0xffff, 0x0078, 0x17c1, 0x6824, + 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, + 0x2009, 0x0011, 0x1078, 0x1824, 0x0040, 0x1822, 0x2009, 0x0001, + 0x1078, 0x1824, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x18bb, 0xa03e, + 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1846, 0xd0f4, 0x00c0, 0x1856, + 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1836, 0x189d, 0x185d, + 0x185d, 0x189d, 0x189d, 0x1895, 0x189d, 0x185d, 0x189d, 0x1863, + 0x1863, 0x189d, 0x189d, 0x189d, 0x188c, 0x1863, 0xc0fc, 0x6852, + 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x0d7e, 0xd99c, 0x0040, 0x18a0, + 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x18a0, 0xc0f4, 0x6852, + 0x6b6c, 0x6a70, 0x0d7e, 0x0078, 0x18a7, 0x6b08, 0x6a0c, 0x6d00, + 0x6c04, 0x0078, 0x18a0, 0x7b0c, 0xd3bc, 0x0040, 0x1884, 0x7004, + 0x0e7e, 0x2070, 0x701c, 0x0e7f, 0xa086, 0x0008, 0x00c0, 0x1884, + 0x7b08, 0xa39c, 0x0fff, 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, 0x82ff, + 0x00c0, 0x187f, 0x6810, 0xa302, 0x0048, 0x187f, 0x6b10, 0x2011, + 0x0000, 0x2468, 0x0078, 0x1886, 0x6b10, 0x6a14, 0x6d00, 0x6c04, + 0x6f08, 0x6e0c, 0x0078, 0x18a0, 0x0d7f, 0x0d7e, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x001e, 0x00c0, 0x189d, 0x0d7f, 0x1078, 0x1fd1, + 0x00c0, 0x1824, 0xa00e, 0x0078, 0x18bb, 0x0d7f, 0x1078, 0x1328, + 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, + 0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, + 0x682e, 0x2300, 0x6b10, 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203, + 0x6816, 0x1078, 0x1fd1, 0x007c, 0x1078, 0x1328, 0x1078, 0x1c52, + 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x7003, 0x0000, 0x1078, + 0x1ac6, 0x1078, 0x8a44, 0x0040, 0x18db, 0x6808, 0x8001, 0x680a, + 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f, 0xffff, + 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8758, 0x0078, 0x1aad, + 0x1078, 0x1328, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, + 0x18be, 0xa184, 0x0003, 0xa086, 0x0003, 0x0040, 0x18e0, 0x7000, + 0x0079, 0x18fa, 0x1902, 0x1904, 0x1a06, 0x1a84, 0x1a9b, 0x1902, + 0x1902, 0x1902, 0x1078, 0x1328, 0x8001, 0x7002, 0xa184, 0x0880, + 0x00c0, 0x1919, 0x8aff, 0x0040, 0x199b, 0x2009, 0x0001, 0x1078, + 0x1824, 0x0040, 0x1aad, 0x2009, 0x0001, 0x1078, 0x1824, 0x0078, + 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x00c0, 0x1979, + 0x027e, 0x037e, 0x7808, 0xd0ec, 0x00c0, 0x1930, 0x7c20, 0x7d24, + 0x7e30, 0x7f34, 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1932, + 0x1078, 0x1b9f, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500, + 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x0c7e, 0x7004, 0x2060, 0x6024, + 0xd0f4, 0x00c0, 0x1945, 0x633a, 0x6236, 0x0c7f, 0x2400, 0x6910, + 0xa100, 0x6812, 0x2500, 0x6914, 0xa101, 0x6816, 0x037f, 0x027f, + 0x2600, 0x681e, 0x2700, 0x6822, 0x1078, 0x1fea, 0x2a00, 0x6826, + 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, 0x6808, + 0x8001, 0x680a, 0x00c0, 0x196e, 0x684c, 0xd0e4, 0x0040, 0x196e, + 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x756c, 0x7000, 0xa086, + 0x0004, 0x0040, 0x1aad, 0x7003, 0x0000, 0x1078, 0x179f, 0x0078, + 0x1aad, 0x057e, 0x7d0c, 0xd5bc, 0x00c0, 0x1980, 0x1078, 0xa20c, + 0x057f, 0x1078, 0x1ac6, 0x0f7e, 0x7004, 0x2078, 0x1078, 0x4893, + 0x0040, 0x198d, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, 0xffff, + 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, + 0x6916, 0x0078, 0x1aad, 0x7004, 0x0c7e, 0x2060, 0x6024, 0x0c7f, + 0xd0f4, 0x0040, 0x19a8, 0x6808, 0x8001, 0x680a, 0x0078, 0x1aad, + 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x19c0, 0x7003, + 0x0000, 0x6808, 0x8001, 0x680a, 0x00c0, 0x19bc, 0x7004, 0x2060, + 0x2009, 0x0048, 0x1078, 0x756c, 0x1078, 0x179f, 0x0078, 0x1aad, + 0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000, 0x6816, + 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa188, 0x0007, 0x8114, 0x8214, + 0x8214, 0xa10a, 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, + 0x810b, 0x1078, 0x1b4d, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, + 0x0001, 0x7804, 0xd0fc, 0x0040, 0x19e1, 0x7803, 0x0002, 0x7803, + 0x0004, 0x780f, 0x0076, 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, + 0x0048, 0x1078, 0x756c, 0x1078, 0x1b81, 0x0040, 0x19bc, 0x7908, + 0xd1ec, 0x00c0, 0x19ff, 0x2009, 0x0009, 0x0078, 0x1a01, 0x2009, + 0x0019, 0x7902, 0x7003, 0x0003, 0x0078, 0x1aad, 0x8001, 0x7002, + 0xd194, 0x0040, 0x1a18, 0x7804, 0xd0fc, 0x00c0, 0x18ea, 0x8aff, + 0x0040, 0x1aad, 0x2009, 0x0001, 0x1078, 0x1824, 0x0078, 0x1aad, + 0xa184, 0x0880, 0x00c0, 0x1a25, 0x8aff, 0x0040, 0x1aad, 0x2009, + 0x0001, 0x1078, 0x1824, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, + 0x0000, 0xd1bc, 0x00c0, 0x1a65, 0x027e, 0x037e, 0x7808, 0xd0ec, + 0x00c0, 0x1a38, 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1a3a, + 0x1078, 0x1b9f, 0x6b28, 0x6a2c, 0x1078, 0x1fea, 0x0d7e, 0x0f7e, + 0x2d78, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1a55, 0x6808, + 0x2008, 0xa31a, 0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, + 0x7814, 0xa101, 0x7816, 0x0078, 0x1a61, 0x6810, 0x2008, 0xa31a, + 0x6814, 0xa213, 0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101, + 0x7816, 0x0f7f, 0x0d7f, 0x0078, 0x1934, 0x057e, 0x7d0c, 0x1078, + 0xa20c, 0x057f, 0x1078, 0x1ac6, 0x0f7e, 0x7004, 0x2078, 0x1078, + 0x4893, 0x0040, 0x1a76, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, + 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, + 0x6980, 0x6916, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, + 0x7004, 0xa00d, 0x0040, 0x1a97, 0x6808, 0x8001, 0x680a, 0x00c0, + 0x1a97, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x756c, 0x1078, + 0x179f, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, + 0x2060, 0x6010, 0xa005, 0x0040, 0x1a97, 0x2068, 0x6808, 0x8000, + 0x680a, 0x6c28, 0x6b2c, 0x1078, 0x17be, 0x017f, 0x007f, 0x127f, + 0x007c, 0x127e, 0x2091, 0x2100, 0x7000, 0xa086, 0x0003, 0x00c0, + 0x1ac4, 0x700c, 0x7110, 0xa106, 0x0040, 0x1ac4, 0x20e1, 0x9028, + 0x700f, 0xa5e7, 0x7013, 0xa5e7, 0x127f, 0x007c, 0x0c7e, 0x1078, + 0x1af7, 0x20e1, 0x9028, 0x700c, 0x7110, 0xa106, 0x0040, 0x1aed, + 0x2104, 0xa005, 0x0040, 0x1ada, 0x2060, 0x6010, 0x2060, 0x6008, + 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xa602, 0x0048, 0x1ae2, + 0x2009, 0xa5e7, 0x7112, 0x700c, 0xa106, 0x00c0, 0x1acb, 0x2001, + 0x0138, 0x2003, 0x0008, 0x0078, 0x1acb, 0x2001, 0x015d, 0x200c, + 0x810a, 0x2102, 0x2001, 0x0138, 0x2202, 0x0c7f, 0x007c, 0x2001, + 0x0138, 0x2014, 0x2003, 0x0000, 0x2021, 0xb015, 0x2001, 0x0141, + 0x201c, 0xd3dc, 0x00c0, 0x1b14, 0x2001, 0x0109, 0x201c, 0xa39c, + 0x0048, 0x00c0, 0x1b14, 0x2001, 0x0111, 0x201c, 0x83ff, 0x00c0, + 0x1b14, 0x8421, 0x00c0, 0x1afe, 0x007c, 0x2011, 0x0201, 0x2009, + 0x003c, 0x2204, 0xa005, 0x00c0, 0x1b21, 0x8109, 0x00c0, 0x1b19, + 0x007c, 0x007c, 0x1078, 0x1b15, 0x0040, 0x1b4a, 0x7908, 0xd1ec, + 0x00c0, 0x1b3a, 0x1078, 0x1b81, 0x0040, 0x1b3a, 0x7803, 0x0009, + 0x7904, 0xd1fc, 0x0040, 0x1b30, 0x7803, 0x0006, 0x1078, 0x1b15, + 0x0040, 0x1b4a, 0x780c, 0xd0a4, 0x00c0, 0x1b4a, 0x7007, 0x0000, + 0x1078, 0x1b81, 0x0040, 0x1b4c, 0x7803, 0x0019, 0x7003, 0x0003, + 0x0078, 0x1b4c, 0x1078, 0x1ac6, 0x007c, 0x0e7e, 0x2071, 0x0200, + 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1af7, 0x2019, 0x5000, + 0x8319, 0x0040, 0x1b6b, 0x2001, 0xa602, 0x2004, 0xa086, 0x0000, + 0x0040, 0x1b6b, 0x2001, 0x0021, 0xd0fc, 0x0040, 0x1b58, 0x1078, + 0x1e5d, 0x0078, 0x1b56, 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028, + 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, 0x0100, + 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, 0x0e7f, + 0x007c, 0x7908, 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0048, 0x1b8c, + 0xa085, 0x0001, 0x0078, 0x1b9e, 0x2001, 0x020a, 0x81ff, 0x0040, + 0x1b97, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x20e1, + 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0xa006, 0x007c, 0x7c20, + 0x7d24, 0x7e30, 0x7f34, 0x700c, 0x7110, 0xa106, 0x0040, 0x1c24, + 0x7004, 0x017e, 0x210c, 0xa106, 0x017f, 0x0040, 0x1c24, 0x0d7e, + 0x0c7e, 0x216c, 0x2d00, 0xa005, 0x0040, 0x1c22, 0x6824, 0xd0d4, + 0x00c0, 0x1c22, 0x6810, 0x2068, 0x6850, 0xd0fc, 0x0040, 0x1bec, + 0x8108, 0x2104, 0x6b2c, 0xa306, 0x00c0, 0x1c22, 0x8108, 0x2104, + 0x6a28, 0xa206, 0x00c0, 0x1c22, 0x6850, 0xc0fc, 0xc0f5, 0x6852, + 0x686c, 0x7822, 0x6870, 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, + 0x6818, 0x2060, 0x6034, 0xd09c, 0x0040, 0x1be7, 0x6830, 0x2004, + 0xac68, 0x6808, 0x783a, 0x680c, 0x783e, 0x0078, 0x1c20, 0xa006, + 0x783a, 0x783e, 0x0078, 0x1c20, 0x8108, 0x2104, 0xa005, 0x00c0, + 0x1c22, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c22, 0x6850, 0xc0f5, + 0x6852, 0x6830, 0x2004, 0x6918, 0xa160, 0xa180, 0x000d, 0x2004, + 0xd09c, 0x00c0, 0x1c12, 0x6008, 0x7822, 0x686e, 0x600c, 0x7826, + 0x6872, 0x6000, 0x7832, 0x6004, 0x7836, 0xa006, 0x783a, 0x783e, + 0x0078, 0x1c20, 0x6010, 0x7822, 0x686e, 0x6014, 0x7826, 0x6872, + 0x6000, 0x7832, 0x6004, 0x7836, 0x6008, 0x783a, 0x600c, 0x783e, + 0x7803, 0x0011, 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x017e, + 0x027e, 0x2071, 0xa5e1, 0x2079, 0x0030, 0x2011, 0x0050, 0x7000, + 0xa086, 0x0000, 0x0040, 0x1c4d, 0x8211, 0x0040, 0x1c4b, 0x2001, + 0x0005, 0x2004, 0xd08c, 0x0040, 0x1c34, 0x7904, 0xa18c, 0x0780, + 0x017e, 0x1078, 0x18e2, 0x017f, 0x81ff, 0x00c0, 0x1c4b, 0x2011, + 0x0050, 0x0078, 0x1c2f, 0xa085, 0x0001, 0x027f, 0x017f, 0x0e7f, + 0x0f7f, 0x007c, 0x7803, 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac, + 0x0040, 0x1ca3, 0x8109, 0x00c0, 0x1c56, 0x2009, 0x0100, 0x210c, + 0xa18a, 0x0003, 0x1048, 0x1328, 0x1078, 0x1f75, 0x0e7e, 0x0f7e, + 0x2071, 0xa5d0, 0x2079, 0x0010, 0x7004, 0xa086, 0x0000, 0x0040, + 0x1c9b, 0x7800, 0x007e, 0x7820, 0x007e, 0x7830, 0x007e, 0x7834, + 0x007e, 0x7838, 0x007e, 0x783c, 0x007e, 0x7803, 0x0004, 0x7823, + 0x0000, 0x0005, 0x0005, 0x2079, 0x0030, 0x7804, 0xd0ac, 0x10c0, + 0x1328, 0x2079, 0x0010, 0x007f, 0x783e, 0x007f, 0x783a, 0x007f, + 0x7836, 0x007f, 0x7832, 0x007f, 0x7822, 0x007f, 0x7802, 0x0f7f, + 0x0e7f, 0x0078, 0x1ca1, 0x0f7f, 0x0e7f, 0x7804, 0xd0ac, 0x10c0, + 0x1328, 0x1078, 0x61d3, 0x007c, 0x0e7e, 0x2071, 0xa602, 0x7003, + 0x0000, 0x0e7f, 0x007c, 0x0d7e, 0xa280, 0x0004, 0x206c, 0x694c, + 0xd1dc, 0x00c0, 0x1d26, 0x6934, 0xa184, 0x0007, 0x0079, 0x1cb8, + 0x1cc0, 0x1d11, 0x1cc0, 0x1cc0, 0x1cc0, 0x1cf6, 0x1cd3, 0x1cc2, + 0x1078, 0x1328, 0x684c, 0xd0b4, 0x0040, 0x1e34, 0x6860, 0x682e, + 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, + 0x6958, 0x0078, 0x1d19, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, + 0x00c0, 0x1cc0, 0x684c, 0xd0b4, 0x0040, 0x1e34, 0x6860, 0x682e, + 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, + 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, + 0x2015, 0x2004, 0x6832, 0x6958, 0x0078, 0x1d22, 0xa18c, 0x00ff, + 0xa186, 0x0015, 0x00c0, 0x1d26, 0x684c, 0xd0b4, 0x0040, 0x1e34, + 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, + 0x2015, 0x2004, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0078, + 0x1d22, 0x684c, 0xd0b4, 0x0040, 0x18bc, 0x6958, 0xa006, 0x682e, + 0x682a, 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x2015, + 0x2004, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, + 0x0f7e, 0x2079, 0x0020, 0x7804, 0xd0fc, 0x10c0, 0x1e5d, 0x0e7e, + 0x0d7e, 0x2071, 0xa602, 0x7000, 0xa005, 0x00c0, 0x1dab, 0x0c7e, + 0x7206, 0xa280, 0x0004, 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, + 0x6818, 0x0d7e, 0x2068, 0x686c, 0x7812, 0x6890, 0x0f7e, 0x20e1, + 0x9040, 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, + 0x0f7f, 0x0d7f, 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, + 0x2040, 0x6034, 0xa0cc, 0x000f, 0x6908, 0x2001, 0x04fd, 0x2004, + 0xa086, 0x0007, 0x0040, 0x1d6d, 0xa184, 0x0007, 0x0040, 0x1d6d, + 0x017e, 0x2009, 0x0008, 0xa102, 0x017f, 0xa108, 0x791a, 0x7116, + 0x701e, 0x680c, 0xa081, 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, + 0x7012, 0x7004, 0x692c, 0x6814, 0xa106, 0x00c0, 0x1d84, 0x6928, + 0x6810, 0xa106, 0x0040, 0x1d91, 0x037e, 0x047e, 0x6b14, 0x6c10, + 0x1078, 0x2035, 0x047f, 0x037f, 0x0040, 0x1d91, 0x0c7f, 0x0078, + 0x1dab, 0x8aff, 0x00c0, 0x1d99, 0x0c7f, 0xa085, 0x0001, 0x0078, + 0x1dab, 0x127e, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, + 0x1078, 0x1daf, 0x0040, 0x1da8, 0x2009, 0x0001, 0x1078, 0x1daf, + 0x127f, 0x0c7f, 0xa006, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, + 0x067e, 0x057e, 0x047e, 0x037e, 0x027e, 0x8aff, 0x0040, 0x1e2d, + 0x700c, 0x7214, 0xa23a, 0x7010, 0x7218, 0xa203, 0x0048, 0x1e2c, + 0xa705, 0x0040, 0x1e2c, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, + 0x1ddf, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1dcf, 0x1e0e, + 0x1def, 0x1def, 0x1e0e, 0x1e0e, 0x1e06, 0x1e0e, 0x1def, 0x1e0e, + 0x1df5, 0x1df5, 0x1e0e, 0x1e0e, 0x1e0e, 0x1dfd, 0x1df5, 0xc0fc, + 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1e12, + 0x0d7e, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x1e11, 0x6b08, + 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1e11, 0x6b10, 0x6a14, 0x6d00, + 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x1e11, 0x0d7f, 0x0d7e, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1e0e, 0x0d7f, 0x1078, + 0x1fd1, 0x00c0, 0x1db5, 0xa00e, 0x0078, 0x1e2d, 0x0d7f, 0x1078, + 0x1328, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, + 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a, 0x682c, + 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201, 0x7012, + 0x1078, 0x1fd1, 0x0078, 0x1e2d, 0xa006, 0x027f, 0x037f, 0x047f, + 0x057f, 0x067f, 0x077f, 0x007c, 0x1078, 0x1328, 0x027e, 0x2001, + 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, + 0x0000, 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, + 0x0040, 0x1e4d, 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8758, + 0x20e1, 0x9040, 0x1078, 0x719a, 0x2011, 0x0000, 0x1078, 0x6efc, + 0x1078, 0x61d3, 0x027f, 0x0078, 0x1f29, 0x127e, 0x2091, 0x2200, + 0x007e, 0x017e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, + 0x2071, 0xa602, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, + 0xa184, 0x0700, 0x00c0, 0x1e36, 0x7000, 0x0079, 0x1e77, 0x1f29, + 0x1e7b, 0x1ef6, 0x1f27, 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1e8f, + 0x8aff, 0x0040, 0x1eae, 0x2009, 0x0001, 0x1078, 0x1daf, 0x0040, + 0x1f29, 0x2009, 0x0001, 0x1078, 0x1daf, 0x0078, 0x1f29, 0x7803, + 0x0004, 0xd194, 0x0040, 0x1e9f, 0x6850, 0xc0fc, 0x6852, 0x8aff, + 0x00c0, 0x1ea4, 0x684c, 0xc0f5, 0x684e, 0x0078, 0x1ea4, 0x1078, + 0x1fea, 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, + 0x2800, 0x6832, 0x7003, 0x0000, 0x0078, 0x1f29, 0x711c, 0x81ff, + 0x0040, 0x1ec4, 0x7918, 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, + 0x7000, 0x8000, 0x7002, 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, + 0x0000, 0x7012, 0x0078, 0x1f29, 0x0f7e, 0x027e, 0x781c, 0x007e, + 0x7818, 0x007e, 0x2079, 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, + 0x0012, 0x7816, 0x037e, 0x2019, 0x1000, 0x8319, 0x1040, 0x1328, + 0x7820, 0xd0bc, 0x00c0, 0x1ed5, 0x037f, 0x79c8, 0x007f, 0xa102, + 0x017f, 0x007e, 0x017e, 0x79c4, 0x007f, 0xa103, 0x78c6, 0x007f, + 0x78ca, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, + 0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1f29, 0x8001, 0x7002, + 0xd194, 0x0040, 0x1f0b, 0x7804, 0xd0fc, 0x00c0, 0x1e6d, 0xd19c, + 0x00c0, 0x1f25, 0x8aff, 0x0040, 0x1f29, 0x2009, 0x0001, 0x1078, + 0x1daf, 0x0078, 0x1f29, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, + 0x1fea, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1f1e, + 0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1f22, 0x6810, 0xa31a, + 0x6814, 0xa213, 0x0d7f, 0x0078, 0x1e9f, 0x0078, 0x1e9f, 0x1078, + 0x1328, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, + 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0xa602, 0x7000, 0xa086, 0x0000, + 0x0040, 0x1f72, 0x2079, 0x0020, 0x017e, 0x2009, 0x0207, 0x210c, + 0xd194, 0x0040, 0x1f4f, 0x2009, 0x020c, 0x210c, 0xa184, 0x0003, + 0x0040, 0x1f4f, 0x20e1, 0x9040, 0x2001, 0x020c, 0x2102, 0x2009, + 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0xa106, 0x00c0, 0x1f5a, + 0x20e1, 0x9040, 0x7804, 0xd0fc, 0x0040, 0x1f3d, 0x1078, 0x1e5d, + 0x7000, 0xa086, 0x0000, 0x00c0, 0x1f3d, 0x017f, 0x7803, 0x0004, + 0x7804, 0xd0ac, 0x00c0, 0x1f68, 0x20e1, 0x9040, 0x7803, 0x0002, + 0x7003, 0x0000, 0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x0c7e, 0x0d7e, + 0x0e7e, 0x0f7e, 0x2071, 0xa602, 0x2079, 0x0020, 0x7000, 0xa086, + 0x0000, 0x0040, 0x1fae, 0x7004, 0x2060, 0x6010, 0x2068, 0x1078, + 0x8a44, 0x0040, 0x1f98, 0x6850, 0xc0b5, 0x6852, 0x680c, 0x7a1c, + 0xa206, 0x00c0, 0x1f98, 0x6808, 0x7a18, 0xa206, 0x0040, 0x1fb4, + 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, + 0x7003, 0x0000, 0x7004, 0x2060, 0x1078, 0x8758, 0x20e1, 0x9040, + 0x1078, 0x719a, 0x2011, 0x0000, 0x1078, 0x6efc, 0x0f7f, 0x0e7f, + 0x0d7f, 0x0c7f, 0x027f, 0x007c, 0x6810, 0x6a14, 0xa205, 0x00c0, + 0x1f98, 0x684c, 0xc0dc, 0x684e, 0x2c10, 0x1078, 0x1cab, 0x2001, + 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, + 0x0000, 0x2069, 0xa5ab, 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, + 0x1fae, 0x8840, 0x2804, 0xa005, 0x00c0, 0x1fe5, 0x6004, 0xa005, + 0x0040, 0x1fe7, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, + 0x2015, 0x2044, 0x88ff, 0x1040, 0x1328, 0x8a51, 0x007c, 0x2051, + 0x0000, 0x007c, 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, 0x2004, + 0x2c00, 0xad06, 0x0040, 0x1ff9, 0x6000, 0xa005, 0x00c0, 0x1ff9, + 0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x2025, + 0x2044, 0x88ff, 0x1040, 0x1328, 0x007c, 0x0000, 0x0011, 0x0015, + 0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, + 0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x200a, 0x2006, + 0x0000, 0x0000, 0x2014, 0x0000, 0x200a, 0x0000, 0x2011, 0x200e, + 0x0000, 0x0000, 0x0000, 0x2014, 0x2011, 0x0000, 0x200c, 0x200c, + 0x0000, 0x0000, 0x2014, 0x0000, 0x200c, 0x0000, 0x2012, 0x2012, + 0x0000, 0x0000, 0x0000, 0x2014, 0x2012, 0x0a7e, 0x097e, 0x087e, + 0x6b2e, 0x6c2a, 0x6858, 0xa055, 0x0040, 0x20d8, 0x2d60, 0x6034, + 0xa0cc, 0x000f, 0xa9c0, 0x2015, 0xa986, 0x0007, 0x0040, 0x2050, + 0xa986, 0x000e, 0x0040, 0x2050, 0xa986, 0x000f, 0x00c0, 0x2054, + 0x605c, 0xa422, 0x6060, 0xa31a, 0x2804, 0xa045, 0x00c0, 0x2062, + 0x0050, 0x205c, 0x0078, 0x20d8, 0x6004, 0xa065, 0x0040, 0x20d8, + 0x0078, 0x203f, 0x2804, 0xa005, 0x0040, 0x2080, 0xac68, 0xd99c, + 0x00c0, 0x2070, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0078, 0x2074, + 0x6810, 0xa422, 0x6814, 0xa31b, 0x0048, 0x209f, 0x2300, 0xa405, + 0x0040, 0x2086, 0x8a51, 0x0040, 0x20d8, 0x8840, 0x0078, 0x2062, + 0x6004, 0xa065, 0x0040, 0x20d8, 0x0078, 0x203f, 0x8a51, 0x0040, + 0x20d8, 0x8840, 0x2804, 0xa005, 0x00c0, 0x2099, 0x6004, 0xa065, + 0x0040, 0x20d8, 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x2015, 0x2804, + 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0078, 0x20cc, 0x8422, + 0x8420, 0x831a, 0xa399, 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, + 0x0d7f, 0xd99c, 0x00c0, 0x20ba, 0x6908, 0x2400, 0xa122, 0x690c, + 0x2300, 0xa11b, 0x1048, 0x1328, 0x6800, 0xa420, 0x6804, 0xa319, + 0x0078, 0x20c6, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, + 0x1048, 0x1328, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, + 0x6b22, 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, + 0x2a00, 0x6826, 0x007f, 0x007f, 0x007f, 0xa006, 0x0078, 0x20dd, + 0x087f, 0x097f, 0x0a7f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, + 0x2004, 0xa084, 0x0007, 0x0079, 0x20e5, 0x20ed, 0x20ee, 0x20f1, + 0x20f4, 0x20f9, 0x20fc, 0x2101, 0x2106, 0x007c, 0x1078, 0x1e5d, + 0x007c, 0x1078, 0x18e2, 0x007c, 0x1078, 0x18e2, 0x1078, 0x1e5d, + 0x007c, 0x1078, 0x14b0, 0x007c, 0x1078, 0x1e5d, 0x1078, 0x14b0, + 0x007c, 0x1078, 0x18e2, 0x1078, 0x14b0, 0x007c, 0x1078, 0x18e2, + 0x1078, 0x1e5d, 0x1078, 0x14b0, 0x007c, 0x127e, 0x2091, 0x2300, + 0x2079, 0x0200, 0x2071, 0xa880, 0x2069, 0xa300, 0x2009, 0x0004, + 0x7912, 0x7817, 0x0004, 0x1078, 0x24b5, 0x781b, 0x0002, 0x20e1, + 0x8700, 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, + 0x0007, 0x0079, 0x212b, 0x214f, 0x2133, 0x2137, 0x213b, 0x2141, + 0x2145, 0x2149, 0x214d, 0x1078, 0x5372, 0x0078, 0x214f, 0x1078, + 0x53b3, 0x0078, 0x214f, 0x1078, 0x5372, 0x1078, 0x53b3, 0x0078, + 0x214f, 0x1078, 0x2151, 0x0078, 0x214f, 0x1078, 0x2151, 0x0078, + 0x214f, 0x1078, 0x2151, 0x0078, 0x214f, 0x1078, 0x2151, 0x127f, + 0x007c, 0x007e, 0x017e, 0x027e, 0x7930, 0xa184, 0x0003, 0x0040, + 0x215d, 0x20e1, 0x9040, 0x0078, 0x2186, 0xa184, 0x0030, 0x0040, + 0x216e, 0x6a00, 0xa286, 0x0003, 0x00c0, 0x2168, 0x0078, 0x216a, + 0x1078, 0x4171, 0x20e1, 0x9010, 0x0078, 0x2186, 0xa184, 0x00c0, + 0x0040, 0x2180, 0x0e7e, 0x037e, 0x047e, 0x057e, 0x2071, 0xa5e1, + 0x1078, 0x1ac6, 0x057f, 0x047f, 0x037f, 0x0e7f, 0x0078, 0x2186, + 0xa184, 0x0300, 0x0040, 0x2186, 0x20e1, 0x9020, 0x7932, 0x027f, + 0x017f, 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, 0xa300, + 0x7128, 0x2001, 0xa58f, 0x2102, 0x2001, 0xa597, 0x2102, 0xa182, + 0x0211, 0x00c8, 0x219f, 0x2009, 0x0008, 0x0078, 0x21c9, 0xa182, + 0x0259, 0x00c8, 0x21a7, 0x2009, 0x0007, 0x0078, 0x21c9, 0xa182, + 0x02c1, 0x00c8, 0x21af, 0x2009, 0x0006, 0x0078, 0x21c9, 0xa182, + 0x0349, 0x00c8, 0x21b7, 0x2009, 0x0005, 0x0078, 0x21c9, 0xa182, + 0x0421, 0x00c8, 0x21bf, 0x2009, 0x0004, 0x0078, 0x21c9, 0xa182, + 0x0581, 0x00c8, 0x21c7, 0x2009, 0x0003, 0x0078, 0x21c9, 0x2009, + 0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x1078, 0x24b5, + 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061, + 0x0100, 0x2071, 0xa300, 0x6024, 0x6026, 0x6053, 0x0030, 0x6033, + 0x00ef, 0x60e7, 0x0000, 0x60eb, 0x00ef, 0x60e3, 0x0008, 0x604b, + 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x6007, + 0x0eaf, 0x600f, 0x00ff, 0x602b, 0x002f, 0x127f, 0x007c, 0x2001, + 0xa32f, 0x2003, 0x0000, 0x2001, 0xa32e, 0x2003, 0x0001, 0x007c, + 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x6124, 0xa184, + 0x002c, 0x00c0, 0x220f, 0xa184, 0x0007, 0x0079, 0x2215, 0xa195, + 0x0004, 0xa284, 0x0007, 0x0079, 0x2215, 0x2241, 0x221d, 0x2221, + 0x2225, 0x222b, 0x222f, 0x2235, 0x223b, 0x1078, 0x5ad2, 0x0078, + 0x2241, 0x1078, 0x5bc1, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078, + 0x5ad2, 0x0078, 0x2241, 0x1078, 0x2246, 0x0078, 0x2241, 0x1078, + 0x5ad2, 0x1078, 0x2246, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078, + 0x2246, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078, 0x5ad2, 0x1078, + 0x2246, 0x027f, 0x017f, 0x007f, 0x127f, 0x007c, 0x6124, 0xd1ac, + 0x0040, 0x2342, 0x017e, 0x047e, 0x0c7e, 0x644c, 0xa486, 0xf0f0, + 0x00c0, 0x2259, 0x2061, 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, + 0x0010, 0x74c2, 0xa48c, 0xff00, 0x7034, 0xd084, 0x0040, 0x2271, + 0xa186, 0xf800, 0x00c0, 0x2271, 0x7038, 0xd084, 0x00c0, 0x2271, + 0xc085, 0x703a, 0x037e, 0x2418, 0x2011, 0x8016, 0x1078, 0x3579, + 0x037f, 0xa196, 0xff00, 0x0040, 0x22b3, 0x6030, 0xa084, 0x00ff, + 0x810f, 0xa116, 0x0040, 0x22b3, 0x7130, 0xd184, 0x00c0, 0x22b3, + 0x2011, 0xa352, 0x2214, 0xd2ec, 0x0040, 0x228e, 0xc18d, 0x7132, + 0x2011, 0xa352, 0x2214, 0xd2ac, 0x00c0, 0x22b3, 0x6240, 0xa294, + 0x0010, 0x0040, 0x229a, 0x6248, 0xa294, 0xff00, 0xa296, 0xff00, + 0x0040, 0x22b3, 0x7030, 0xd08c, 0x0040, 0x2305, 0x7034, 0xd08c, + 0x00c0, 0x22aa, 0x2001, 0xa30c, 0x200c, 0xd1ac, 0x00c0, 0x2305, + 0xc1ad, 0x2102, 0x037e, 0x73c0, 0x2011, 0x8013, 0x1078, 0x3579, + 0x037f, 0x0078, 0x2305, 0x7034, 0xd08c, 0x00c0, 0x22bf, 0x2001, + 0xa30c, 0x200c, 0xd1ac, 0x00c0, 0x2305, 0xc1ad, 0x2102, 0x037e, + 0x73c0, 0x2011, 0x8013, 0x1078, 0x3579, 0x037f, 0x7130, 0xc185, + 0x7132, 0x2011, 0xa352, 0x220c, 0xd1a4, 0x0040, 0x22e9, 0x017e, + 0x2009, 0x0001, 0x2011, 0x0100, 0x1078, 0x5a6d, 0x2019, 0x000e, + 0x1078, 0x9e3b, 0xa484, 0x00ff, 0xa080, 0x293f, 0x200c, 0xa18c, + 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x1078, 0x9ec0, + 0x017f, 0xd1ac, 0x00c0, 0x22f6, 0x017e, 0x2009, 0x0000, 0x2019, + 0x0004, 0x1078, 0x27e2, 0x017f, 0x0078, 0x2305, 0x157e, 0x20a9, + 0x007f, 0x2009, 0x0000, 0x1078, 0x4501, 0x00c0, 0x2301, 0x1078, + 0x4235, 0x8108, 0x00f0, 0x22fb, 0x157f, 0x0c7f, 0x047f, 0x0f7e, + 0x2079, 0xa5be, 0x783c, 0xa086, 0x0000, 0x0040, 0x2317, 0x6027, + 0x0004, 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x0000, 0x0f7f, + 0x2011, 0x0003, 0x1078, 0x6ef2, 0x2011, 0x0002, 0x1078, 0x6efc, + 0x1078, 0x6dda, 0x1078, 0x595a, 0x037e, 0x2019, 0x0000, 0x1078, + 0x6e6c, 0x037f, 0x60e3, 0x0000, 0x017f, 0x2001, 0xa300, 0x2014, + 0xa296, 0x0004, 0x00c0, 0x233a, 0xd19c, 0x00c0, 0x233a, 0x6228, + 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xa321, 0x2003, 0x0000, + 0x6027, 0x0020, 0xd194, 0x0040, 0x2426, 0x0f7e, 0x2079, 0xa5be, + 0x783c, 0xa086, 0x0001, 0x00c0, 0x2366, 0x017e, 0x6027, 0x0004, + 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x1000, 0x7803, 0x0000, + 0x2079, 0xa5ab, 0x7807, 0x0000, 0x7833, 0x0000, 0x1078, 0x6109, + 0x1078, 0x61d3, 0x017f, 0x0f7f, 0x0078, 0x2426, 0x0f7f, 0x017e, + 0x3900, 0xa082, 0xa6cd, 0x00c8, 0x2371, 0x017e, 0x1078, 0x728a, + 0x017f, 0x6220, 0xd2b4, 0x0040, 0x23dc, 0x1078, 0x595a, 0x1078, + 0x6c41, 0x6027, 0x0004, 0x0f7e, 0x2019, 0xa5b4, 0x2304, 0xa07d, + 0x0040, 0x23b2, 0x7804, 0xa086, 0x0032, 0x00c0, 0x23b2, 0x0d7e, + 0x0c7e, 0x0e7e, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, + 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x00c0, + 0x2396, 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, + 0x628a, 0x1078, 0x6010, 0x1078, 0x6109, 0x7810, 0x2070, 0x7037, + 0x0103, 0x2f60, 0x1078, 0x753d, 0x0e7f, 0x0c7f, 0x0d7f, 0x0f7f, + 0x017f, 0x007c, 0x0f7f, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, + 0x4000, 0x0040, 0x23bf, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f, + 0x0c7e, 0x2061, 0xa5ab, 0x6028, 0xa09a, 0x00c8, 0x00c8, 0x23cf, + 0x8000, 0x602a, 0x0c7f, 0x1078, 0x6c33, 0x0078, 0x2425, 0x2019, + 0xa5b4, 0x2304, 0xa065, 0x0040, 0x23d9, 0x2009, 0x0027, 0x1078, + 0x756c, 0x0c7f, 0x0078, 0x2425, 0xd2bc, 0x0040, 0x2425, 0x1078, + 0x5967, 0x6017, 0x0010, 0x6027, 0x0004, 0x0d7e, 0x2069, 0x0140, + 0x6804, 0xa084, 0x4000, 0x0040, 0x23f1, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa5ab, 0x6044, 0xa09a, 0x00c8, + 0x00c8, 0x2414, 0x8000, 0x6046, 0x603c, 0x0c7f, 0xa005, 0x0040, + 0x2425, 0x2009, 0x07d0, 0x1078, 0x595f, 0xa080, 0x0007, 0x2004, + 0xa086, 0x0006, 0x00c0, 0x2410, 0x6017, 0x0012, 0x0078, 0x2425, + 0x6017, 0x0016, 0x0078, 0x2425, 0x037e, 0x2019, 0x0001, 0x1078, + 0x6e6c, 0x037f, 0x2019, 0xa5ba, 0x2304, 0xa065, 0x0040, 0x2424, + 0x2009, 0x004f, 0x1078, 0x756c, 0x0c7f, 0x017f, 0xd19c, 0x0040, + 0x247c, 0x7034, 0xd0ac, 0x00c0, 0x2457, 0x017e, 0x157e, 0x6027, + 0x0008, 0x602f, 0x0020, 0x20a9, 0x000a, 0x00f0, 0x2435, 0x602f, + 0x0000, 0x6150, 0xa185, 0x1400, 0x6052, 0x20a9, 0x0320, 0x00e0, + 0x243f, 0x2091, 0x6000, 0x6020, 0xd09c, 0x00c0, 0x244e, 0x157f, + 0x6152, 0x017f, 0x6027, 0x0008, 0x0078, 0x247c, 0x1078, 0x250d, + 0x00f0, 0x243f, 0x157f, 0x6152, 0x017f, 0x6027, 0x0008, 0x017e, + 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x1078, 0x6ef2, 0x2011, + 0x0002, 0x1078, 0x6efc, 0x1078, 0x6dda, 0x1078, 0x595a, 0x037e, + 0x2019, 0x0000, 0x1078, 0x6e6c, 0x037f, 0x60e3, 0x0000, 0x1078, + 0xa22a, 0x1078, 0xa248, 0x2001, 0xa300, 0x2003, 0x0004, 0x6027, + 0x0008, 0x1078, 0x1246, 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c, + 0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000, + 0x2071, 0xa300, 0x71b8, 0x70ba, 0xa116, 0x0040, 0x24ae, 0x81ff, + 0x0040, 0x2498, 0x2011, 0x8011, 0x1078, 0x3579, 0x0078, 0x24ae, + 0x2011, 0x8012, 0x1078, 0x3579, 0x2001, 0xa371, 0x2004, 0xd0fc, + 0x00c0, 0x24ae, 0x037e, 0x0c7e, 0x2061, 0x0100, 0x2019, 0x0028, + 0x2009, 0x0000, 0x1078, 0x27e2, 0x0c7f, 0x037f, 0x127f, 0x0f7f, + 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, 0x0c7e, 0x0f7e, 0x007e, + 0x027e, 0x2061, 0x0100, 0xa190, 0x24d1, 0x2204, 0x60f2, 0x2011, + 0x24de, 0x6000, 0xa082, 0x0003, 0x00c8, 0x24ca, 0x2001, 0x00ff, + 0x0078, 0x24cb, 0x2204, 0x60ee, 0x027f, 0x007f, 0x0f7f, 0x0c7f, + 0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, 0x0348, 0x02c0, + 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, 0x0140, 0x00f8, + 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, 0x2130, 0xa094, + 0xff00, 0x00c0, 0x24ee, 0x81ff, 0x0040, 0x24f2, 0x1078, 0x5623, + 0x0078, 0x24f9, 0xa080, 0x293f, 0x200c, 0xa18c, 0xff00, 0x810f, + 0xa006, 0x007c, 0xa080, 0x293f, 0x200c, 0xa18c, 0x00ff, 0x007c, + 0x0c7e, 0x2061, 0xa300, 0x6030, 0x0040, 0x2509, 0xc09d, 0x0078, + 0x250a, 0xc09c, 0x6032, 0x0c7f, 0x007c, 0x007e, 0x157e, 0x0f7e, + 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c, 0x00c0, 0x251a, + 0x00f0, 0x2514, 0x0f7f, 0x157f, 0x007f, 0x007c, 0x0c7e, 0x007e, + 0x2061, 0x0100, 0x6030, 0x007e, 0x6048, 0x007e, 0x60e4, 0x007e, + 0x60e8, 0x007e, 0x6050, 0x007e, 0x60f0, 0x007e, 0x60ec, 0x007e, + 0x600c, 0x007e, 0x6004, 0x007e, 0x6028, 0x007e, 0x60e0, 0x007e, + 0x602f, 0x0100, 0x602f, 0x0000, 0x0005, 0x0005, 0x0005, 0x0005, + 0x602f, 0x0040, 0x602f, 0x0000, 0x007f, 0x60e2, 0x007f, 0x602a, + 0x007f, 0x6006, 0x007f, 0x600e, 0x007f, 0x60ee, 0x007f, 0x60f2, + 0x007f, 0x6052, 0x007f, 0x60ea, 0x007f, 0x60e6, 0x007f, 0x604a, + 0x007f, 0x6032, 0x007f, 0x0c7f, 0x007c, 0x257d, 0x2581, 0x2585, + 0x258b, 0x2591, 0x2597, 0x259d, 0x25a5, 0x25ad, 0x25b3, 0x25b9, + 0x25c1, 0x25c9, 0x25d1, 0x25d9, 0x25e3, 0x25ed, 0x25ed, 0x25ed, + 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, + 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x107e, 0x007e, 0x0078, + 0x2606, 0x107e, 0x007e, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, + 0x2200, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x0078, + 0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, + 0x007e, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, + 0x2200, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, + 0x2200, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, + 0x2123, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2123, 0x0078, + 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x2123, 0x0078, + 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x2123, 0x0078, + 0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x1078, 0x2123, 0x0078, + 0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x1078, 0x2123, 0x0078, + 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x20de, 0x1078, + 0x2123, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, + 0x20de, 0x1078, 0x2123, 0x0078, 0x2606, 0x0005, 0x0078, 0x25ed, + 0xb084, 0x003c, 0x8004, 0x8004, 0x0079, 0x25f6, 0x2606, 0x2583, + 0x2587, 0x258d, 0x2593, 0x2599, 0x259f, 0x25a7, 0x25af, 0x25b5, + 0x25bb, 0x25c3, 0x25cb, 0x25d3, 0x25db, 0x25e5, 0x0008, 0x25f0, + 0x007f, 0x107f, 0x2091, 0x8001, 0x007c, 0x0c7e, 0x027e, 0x047e, + 0x2021, 0x0000, 0x1078, 0x4897, 0x00c0, 0x2705, 0x70c8, 0xd09c, + 0x0040, 0x2624, 0xd084, 0x00c0, 0x2624, 0xd0bc, 0x00c0, 0x2705, + 0x1078, 0x2709, 0x0078, 0x2705, 0xd094, 0x0040, 0x262b, 0x7093, + 0xffff, 0x0078, 0x2705, 0x2001, 0x010c, 0x203c, 0x7280, 0xd284, + 0x0040, 0x2694, 0xd28c, 0x00c0, 0x2694, 0x037e, 0x7390, 0xa38e, + 0xffff, 0x0040, 0x263e, 0x83ff, 0x00c0, 0x2640, 0x2019, 0x0001, + 0x8314, 0xa2e0, 0xa9c0, 0x2c04, 0xa38c, 0x0001, 0x0040, 0x264d, + 0xa084, 0xff00, 0x8007, 0x0078, 0x264f, 0xa084, 0x00ff, 0xa70e, + 0x0040, 0x2689, 0xa08e, 0x0000, 0x0040, 0x2689, 0xa08e, 0x00ff, + 0x00c0, 0x2666, 0x7230, 0xd284, 0x00c0, 0x268f, 0x7280, 0xc28d, + 0x7282, 0x7093, 0xffff, 0x037f, 0x0078, 0x2694, 0x2009, 0x0000, + 0x1078, 0x24e3, 0x1078, 0x4499, 0x00c0, 0x268c, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2683, 0x7030, 0xd08c, 0x0040, + 0x267d, 0x6000, 0xd0bc, 0x0040, 0x2683, 0x1078, 0x271f, 0x0040, + 0x268c, 0x0078, 0x2689, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040, + 0x268c, 0x8318, 0x0078, 0x2640, 0x7392, 0x0078, 0x2691, 0x7093, + 0xffff, 0x037f, 0x0078, 0x2705, 0xa780, 0x293f, 0x203c, 0xa7bc, + 0xff00, 0x873f, 0x2041, 0x007e, 0x7090, 0xa096, 0xffff, 0x00c0, + 0x26a6, 0x2009, 0x0000, 0x28a8, 0x0078, 0x26b2, 0xa812, 0x0048, + 0x26ae, 0x2008, 0xa802, 0x20a8, 0x0078, 0x26b2, 0x7093, 0xffff, + 0x0078, 0x2705, 0x2700, 0x157e, 0x017e, 0xa106, 0x0040, 0x26f9, + 0xc484, 0x1078, 0x4501, 0x0040, 0x26c3, 0x1078, 0x4499, 0x00c0, + 0x2702, 0x0078, 0x26c4, 0xc485, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x0006, 0x00c0, 0x26d3, 0x7030, 0xd08c, 0x0040, 0x26f1, 0x6000, + 0xd0bc, 0x00c0, 0x26f1, 0x7280, 0xd28c, 0x0040, 0x26e9, 0x6004, + 0xa084, 0x00ff, 0xa082, 0x0006, 0x0048, 0x26f9, 0xd484, 0x00c0, + 0x26e5, 0x1078, 0x44bc, 0x0078, 0x26e7, 0x1078, 0x2921, 0x0078, + 0x26f9, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040, 0x2702, 0x0078, + 0x26f9, 0x1078, 0x28ec, 0x0040, 0x26f9, 0x1078, 0x271f, 0x0040, + 0x2702, 0x017f, 0x8108, 0x157f, 0x00f0, 0x26b2, 0x7093, 0xffff, + 0x0078, 0x2705, 0x017f, 0x157f, 0x7192, 0x047f, 0x027f, 0x0c7f, + 0x007c, 0x0c7e, 0x017e, 0x7093, 0x0000, 0x2009, 0x007e, 0x1078, + 0x4499, 0x00c0, 0x271c, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040, + 0x271c, 0x70c8, 0xc0bd, 0x70ca, 0x017f, 0x0c7f, 0x007c, 0x017e, + 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x2001, 0xa356, 0x2004, 0xa084, + 0x00ff, 0x6842, 0x1078, 0x74d7, 0x0040, 0x2747, 0x2d00, 0x601a, + 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0000, + 0x1078, 0x443f, 0x127e, 0x2091, 0x8000, 0x708c, 0x8000, 0x708e, + 0x127f, 0x2009, 0x0004, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, + 0x0d7f, 0x077f, 0x017f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, + 0x2c68, 0x2001, 0xa356, 0x2004, 0xa084, 0x00ff, 0x6842, 0x1078, + 0x74d7, 0x0040, 0x2785, 0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802, + 0x68a0, 0xa086, 0x007e, 0x0040, 0x276e, 0x6804, 0xa084, 0x00ff, + 0xa086, 0x0006, 0x00c0, 0x276e, 0x1078, 0x2813, 0x601f, 0x0001, + 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f, + 0x127e, 0x2091, 0x8000, 0x708c, 0x8000, 0x708e, 0x127f, 0x2009, + 0x0002, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, + 0x017f, 0x007c, 0x0c7e, 0x027e, 0x2009, 0x0080, 0x1078, 0x4499, + 0x00c0, 0x2798, 0x1078, 0x279b, 0x0040, 0x2798, 0x70cf, 0xffff, + 0x027f, 0x0c7f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, + 0x1078, 0x74d7, 0x0040, 0x27bd, 0x2d00, 0x601a, 0x601f, 0x0001, + 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f, + 0x127e, 0x2091, 0x8000, 0x70d0, 0x8000, 0x70d2, 0x127f, 0x2009, + 0x0002, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, + 0x017f, 0x007c, 0x0c7e, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2009, + 0x007f, 0x1078, 0x4499, 0x00c0, 0x27de, 0x2c68, 0x1078, 0x74d7, + 0x0040, 0x27de, 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a, + 0x2009, 0x0022, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0d7f, + 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078, + 0x5d60, 0x1078, 0x5d02, 0x1078, 0x7ddf, 0x2130, 0x81ff, 0x0040, + 0x27f7, 0x20a9, 0x007e, 0x2009, 0x0000, 0x0078, 0x27fb, 0x20a9, + 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, 0x2804, + 0x1078, 0x471b, 0x1078, 0x4235, 0x017f, 0x8108, 0x00f0, 0x27fb, + 0x86ff, 0x00c0, 0x280d, 0x1078, 0x119b, 0x027f, 0x037f, 0x067f, + 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, + 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x5d53, + 0x077e, 0x2039, 0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, + 0x077f, 0x017f, 0x2e60, 0x1078, 0x471b, 0x6210, 0x6314, 0x1078, + 0x4235, 0x6212, 0x6316, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, + 0x007c, 0x0e7e, 0x007e, 0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc, + 0x00c0, 0x284d, 0x2071, 0xa300, 0x708c, 0xa005, 0x0040, 0x284a, + 0x8001, 0x708e, 0x007f, 0x0e7f, 0x007c, 0x2071, 0xa300, 0x70d0, + 0xa005, 0x0040, 0x284a, 0x8001, 0x70d2, 0x0078, 0x284a, 0x6000, + 0xc08c, 0x6002, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x037e, 0x027e, + 0x017e, 0x157e, 0x2178, 0x81ff, 0x00c0, 0x286a, 0x20a9, 0x0001, + 0x0078, 0x2885, 0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x2881, + 0xd0a4, 0x0040, 0x2881, 0x047e, 0x6018, 0xa080, 0x0028, 0x2024, + 0xa4a4, 0x00ff, 0x8427, 0xa006, 0x2009, 0x002d, 0x1078, 0x9ec0, + 0x047f, 0x20a9, 0x00ff, 0x2011, 0x0000, 0x027e, 0xa28e, 0x007e, + 0x0040, 0x28c9, 0xa28e, 0x007f, 0x0040, 0x28c9, 0xa28e, 0x0080, + 0x0040, 0x28c9, 0xa288, 0xa434, 0x210c, 0x81ff, 0x0040, 0x28c9, + 0x8fff, 0x1040, 0x28d5, 0x0c7e, 0x2160, 0x2001, 0x0001, 0x1078, + 0x48a2, 0x0c7f, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, + 0x0000, 0x1078, 0x5c78, 0x0c7e, 0x027e, 0x2160, 0x6204, 0xa294, + 0x00ff, 0xa286, 0x0006, 0x00c0, 0x28b9, 0x6007, 0x0404, 0x0078, + 0x28be, 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x027f, 0x0c7f, + 0x017e, 0x2c08, 0x1078, 0x9c38, 0x017f, 0x077f, 0x2160, 0x1078, + 0x471b, 0x027f, 0x8210, 0x00f0, 0x2885, 0x157f, 0x017f, 0x027f, + 0x037f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x047e, 0x027e, 0x017e, + 0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x28e8, 0xd0a4, 0x0040, + 0x28e8, 0xa006, 0x2220, 0x8427, 0x2009, 0x0029, 0x1078, 0x9ec0, + 0x017f, 0x027f, 0x047f, 0x007c, 0x017e, 0x027e, 0x037e, 0x0c7e, + 0x7280, 0x82ff, 0x0040, 0x291a, 0xa290, 0xa352, 0x2214, 0xd2ac, + 0x00c0, 0x291a, 0x2100, 0x1078, 0x24fa, 0x81ff, 0x0040, 0x291c, + 0x2019, 0x0001, 0x8314, 0xa2e0, 0xa9c0, 0x2c04, 0xd384, 0x0040, + 0x290e, 0xa084, 0xff00, 0x8007, 0x0078, 0x2910, 0xa084, 0x00ff, + 0xa116, 0x0040, 0x291c, 0xa096, 0x00ff, 0x0040, 0x291a, 0x8318, + 0x0078, 0x2902, 0xa085, 0x0001, 0x0c7f, 0x037f, 0x027f, 0x017f, + 0x007c, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0xa180, 0xa434, + 0x2004, 0xa065, 0x0040, 0x293b, 0x017e, 0x0c7e, 0x1078, 0x8ec0, + 0x017f, 0x1040, 0x1328, 0x611a, 0x1078, 0x2813, 0x1078, 0x753d, + 0x017f, 0x1078, 0x44bc, 0x127f, 0x0c7f, 0x017f, 0x007c, 0x7eef, + 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, + 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, + 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, + 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, + 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, + 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, + 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, + 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, + 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, + 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, + 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, + 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, + 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, + 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, + 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, + 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, + 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, + 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, + 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, + 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, + 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, + 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, + 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, + 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, + 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, + 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, + 0xa381, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, + 0x7033, 0xa391, 0x7037, 0xa391, 0x7007, 0x0001, 0x2061, 0xa3d1, + 0x6003, 0x0002, 0x007c, 0x0090, 0x2a66, 0x0068, 0x2a66, 0x2071, + 0xa381, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2a66, 0x2a60, 0x7820, + 0xa08e, 0x0069, 0x00c0, 0x2b56, 0x0079, 0x2aea, 0x007c, 0x2071, + 0xa381, 0x7004, 0x0079, 0x2a6c, 0x2a70, 0x2a71, 0x2a7b, 0x2a8d, + 0x007c, 0x0090, 0x2a7a, 0x0068, 0x2a7a, 0x2b78, 0x7818, 0xd084, + 0x0040, 0x2a99, 0x007c, 0x2b78, 0x2061, 0xa3d1, 0x6008, 0xa08e, + 0x0100, 0x0040, 0x2a88, 0xa086, 0x0200, 0x0040, 0x2b4e, 0x007c, + 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, 0x2068, 0x6834, + 0xa086, 0x0103, 0x0040, 0x2a95, 0x007c, 0x2a60, 0x2b78, 0x7018, + 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, 0x2aa2, 0x61b8, + 0x0079, 0x2aaa, 0x2100, 0xa08a, 0x003f, 0x00c8, 0x2b4a, 0x61b8, + 0x0079, 0x2aea, 0x2b2c, 0x2b5e, 0x2b66, 0x2b6a, 0x2b72, 0x2b78, + 0x2b7c, 0x2b88, 0x2b8c, 0x2b96, 0x2b9a, 0x2b4a, 0x2b4a, 0x2b4a, + 0x2b9e, 0x2b4a, 0x2bae, 0x2bc5, 0x2bdc, 0x2c58, 0x2c5d, 0x2c8a, + 0x2ce4, 0x2cf5, 0x2d13, 0x2d54, 0x2d5e, 0x2d6b, 0x2d7e, 0x2d9d, + 0x2da6, 0x2de3, 0x2de9, 0x2b4a, 0x2e05, 0x2b4a, 0x2b4a, 0x2b4a, + 0x2b4a, 0x2b4a, 0x2e0c, 0x2e16, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, + 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2e1e, 0x2b4a, 0x2b4a, 0x2b4a, + 0x2b4a, 0x2b4a, 0x2e30, 0x2e47, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, + 0x2b4a, 0x2b4a, 0x2e59, 0x2eb0, 0x2f0e, 0x2f1f, 0x2b4a, 0x2b4a, + 0x2b4a, 0x38f1, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, + 0x2b4a, 0x2b4a, 0x2b96, 0x2b9a, 0x2f36, 0x2b4a, 0x2f43, 0x397d, + 0x39da, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, + 0x2b4a, 0x2b4a, 0x2f90, 0x30c5, 0x30e1, 0x30ed, 0x3150, 0x31a9, + 0x31b4, 0x31f3, 0x3202, 0x3211, 0x3214, 0x2f47, 0x3238, 0x3284, + 0x3291, 0x33a2, 0x34cd, 0x34f7, 0x3604, 0x3614, 0x3621, 0x365b, + 0x372a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x3792, 0x37ae, 0x3828, + 0x38e2, 0x713c, 0x0078, 0x2b2c, 0x2021, 0x4000, 0x1078, 0x3553, + 0x127e, 0x2091, 0x8000, 0x0068, 0x2b39, 0x7818, 0xd084, 0x0040, + 0x2b3c, 0x127f, 0x0078, 0x2b30, 0x7c22, 0x7926, 0x7a2a, 0x7b2e, + 0x781b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000, + 0x127f, 0x007c, 0x2021, 0x4001, 0x0078, 0x2b2e, 0x2021, 0x4002, + 0x0078, 0x2b2e, 0x2021, 0x4003, 0x0078, 0x2b2e, 0x2021, 0x4005, + 0x0078, 0x2b2e, 0x2021, 0x4006, 0x0078, 0x2b2e, 0xa02e, 0x2520, + 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x3562, 0x7823, 0x0004, + 0x7824, 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, + 0x0078, 0x3566, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, 0x2b2c, + 0x7924, 0x2114, 0x0078, 0x2b2c, 0x2099, 0x0009, 0x20a1, 0x0009, + 0x20a9, 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0078, 0x2b2c, + 0x7824, 0x2060, 0x0078, 0x2ba0, 0x2009, 0x0001, 0x2011, 0x0013, + 0x2019, 0x0010, 0x783b, 0x0017, 0x0078, 0x2b2c, 0x7d38, 0x7c3c, + 0x0078, 0x2b60, 0x7d38, 0x7c3c, 0x0078, 0x2b6c, 0x2061, 0x1000, + 0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, 0x00c0, 0x2ba2, + 0x2010, 0xa005, 0x0040, 0x2b2c, 0x0078, 0x2b52, 0x2069, 0xa351, + 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2b5a, 0x8019, 0x0040, 0x2b5a, + 0x684a, 0x6942, 0x782c, 0x6852, 0x7828, 0x6856, 0xa006, 0x685a, + 0x685e, 0x1078, 0x4dbd, 0x0078, 0x2b2c, 0x2069, 0xa351, 0x7824, + 0x7934, 0xa11a, 0x00c8, 0x2b5a, 0x8019, 0x0040, 0x2b5a, 0x684e, + 0x6946, 0x782c, 0x6862, 0x7828, 0x6866, 0xa006, 0x686a, 0x686e, + 0x1078, 0x494d, 0x0078, 0x2b2c, 0xa02e, 0x2520, 0x81ff, 0x00c0, + 0x2b56, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, 0x20a1, 0xa388, + 0x41a1, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, 0x0020, 0x1078, + 0x3562, 0x701b, 0x2bf4, 0x007c, 0x6834, 0x2008, 0xa084, 0x00ff, + 0xa096, 0x0011, 0x0040, 0x2c00, 0xa096, 0x0019, 0x00c0, 0x2b56, + 0x810f, 0xa18c, 0x00ff, 0x0040, 0x2b56, 0x710e, 0x700c, 0x8001, + 0x0040, 0x2c31, 0x700e, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, + 0x0020, 0x2061, 0xa3d1, 0x6224, 0x6328, 0x642c, 0x6530, 0xa290, + 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x1078, + 0x3562, 0x701b, 0x2c24, 0x007c, 0x6834, 0xa084, 0x00ff, 0xa096, + 0x0002, 0x0040, 0x2c2f, 0xa096, 0x000a, 0x00c0, 0x2b56, 0x0078, + 0x2c06, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x436e, + 0x00c0, 0x2c3f, 0x7007, 0x0003, 0x701b, 0x2c41, 0x007c, 0x1078, + 0x4a60, 0x127e, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0xa388, + 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, + 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x127f, 0x0078, 0x3566, + 0x61a0, 0x7824, 0x60a2, 0x0078, 0x2b2c, 0x2091, 0x8000, 0x7823, + 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009, + 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, + 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, + 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, + 0x2071, 0x0010, 0x20c1, 0x00f0, 0xa08a, 0x0003, 0x00c8, 0x0427, + 0x0078, 0x0423, 0x81ff, 0x00c0, 0x2b56, 0x7924, 0x810f, 0xa18c, + 0x00ff, 0x1078, 0x4501, 0x00c0, 0x2b5a, 0x7e38, 0xa684, 0x3fff, + 0xa082, 0x4000, 0x0048, 0x2c9e, 0x0078, 0x2b5a, 0x7c28, 0x7d2c, + 0x1078, 0x46d6, 0xd28c, 0x00c0, 0x2ca9, 0x1078, 0x466a, 0x0078, + 0x2cab, 0x1078, 0x46a4, 0x00c0, 0x2cd5, 0x2061, 0xaa00, 0x127e, + 0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0040, 0x2cc3, 0x6010, + 0xa06d, 0x0040, 0x2cc3, 0x683c, 0xa406, 0x00c0, 0x2cc3, 0x6840, + 0xa506, 0x0040, 0x2cce, 0x127f, 0xace0, 0x0010, 0x2001, 0xa315, + 0x2004, 0xac02, 0x00c8, 0x2b56, 0x0078, 0x2caf, 0x1078, 0x8758, + 0x127f, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0xa00e, 0x2001, 0x0005, + 0x1078, 0x4a60, 0x127e, 0x2091, 0x8000, 0x1078, 0x8cc0, 0x1078, + 0x4982, 0x127f, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, + 0x3530, 0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, + 0x46e4, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, + 0x1078, 0x3542, 0x0040, 0x2b5a, 0x1078, 0x475f, 0x0040, 0x2b56, + 0x2019, 0x0005, 0x1078, 0x4705, 0x0040, 0x2b56, 0x7828, 0xa08a, + 0x1000, 0x00c8, 0x2b5a, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, + 0x58e1, 0x0078, 0x2b2c, 0x127e, 0x2091, 0x8000, 0x81ff, 0x0040, + 0x2d1d, 0x2009, 0x0001, 0x0078, 0x2d4e, 0x2029, 0x00ff, 0x644c, + 0x2400, 0xa506, 0x0040, 0x2d48, 0x2508, 0x1078, 0x4501, 0x00c0, + 0x2d48, 0x1078, 0x475f, 0x00c0, 0x2d33, 0x2009, 0x0002, 0x62a8, + 0x2518, 0x0078, 0x2d4e, 0x2019, 0x0004, 0x1078, 0x4705, 0x00c0, + 0x2d3d, 0x2009, 0x0006, 0x0078, 0x2d4e, 0x7824, 0xa08a, 0x1000, + 0x00c8, 0x2d51, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x58e1, + 0x8529, 0x00c8, 0x2d20, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, + 0x2b56, 0x127f, 0x0078, 0x2b5a, 0x1078, 0x3530, 0x0040, 0x2b5a, + 0x1078, 0x461b, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x81ff, 0x00c0, + 0x2b56, 0x1078, 0x3530, 0x0040, 0x2b5a, 0x1078, 0x460a, 0x1078, + 0x46d6, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, + 0x0040, 0x2b5a, 0x1078, 0x46a7, 0x0040, 0x2b56, 0x1078, 0x43c1, + 0x1078, 0x4663, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x1078, 0x3530, + 0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x62a0, 0x2019, + 0x0005, 0x0c7e, 0x1078, 0x471b, 0x0c7f, 0x1078, 0x5d53, 0x077e, + 0x2039, 0x0000, 0x1078, 0x5c78, 0x2009, 0x0000, 0x1078, 0x9c38, + 0x077f, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x1078, 0x3530, 0x0040, + 0x2b5a, 0x1078, 0x46d6, 0x2208, 0x0078, 0x2b2c, 0x157e, 0x0d7e, + 0x0e7e, 0x2069, 0xa413, 0x6810, 0x6914, 0xa10a, 0x00c8, 0x2db2, + 0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, + 0x00ff, 0x2069, 0xa434, 0x2d04, 0xa075, 0x0040, 0x2dc7, 0x704c, + 0x1078, 0x2dd1, 0xa210, 0x7080, 0x1078, 0x2dd1, 0xa318, 0x8d68, + 0x00f0, 0x2dbb, 0x2300, 0xa218, 0x0e7f, 0x0d7f, 0x157f, 0x0078, + 0x2b2c, 0x0f7e, 0x017e, 0xa07d, 0x0040, 0x2de0, 0x2001, 0x0000, + 0x8000, 0x2f0c, 0x81ff, 0x0040, 0x2de0, 0x2178, 0x0078, 0x2dd8, + 0x017f, 0x0f7f, 0x007c, 0x2069, 0xa413, 0x6910, 0x62a4, 0x0078, + 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x614c, 0xa190, 0x293f, 0x2214, + 0xa294, 0x00ff, 0x606c, 0xa084, 0xff00, 0xa215, 0x6368, 0x67c8, + 0xd79c, 0x0040, 0x2dff, 0x2031, 0x0001, 0x0078, 0x2e01, 0x2031, + 0x0000, 0x7e3a, 0x7f3e, 0x0078, 0x2b2c, 0x613c, 0x6240, 0x2019, + 0xa5a0, 0x231c, 0x0078, 0x2b2c, 0x127e, 0x2091, 0x8000, 0x6134, + 0xa006, 0x2010, 0x2018, 0x127f, 0x0078, 0x2b2c, 0x1078, 0x3542, + 0x0040, 0x2b5a, 0x6244, 0x6338, 0x0078, 0x2b2c, 0x613c, 0x6240, + 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0xa351, 0x831f, 0xa305, + 0x6816, 0x782c, 0x2069, 0xa5a0, 0x2d1c, 0x206a, 0x0078, 0x2b2c, + 0x017e, 0x127e, 0x2091, 0x8000, 0x7824, 0x6036, 0xd094, 0x0040, + 0x2e43, 0x7828, 0xa085, 0x0001, 0x2009, 0xa5a9, 0x200a, 0x2001, + 0xffff, 0x1078, 0x5975, 0x127f, 0x017f, 0x0078, 0x2b2c, 0x1078, + 0x3542, 0x0040, 0x2b5a, 0x7828, 0xa00d, 0x0040, 0x2b5a, 0x782c, + 0xa005, 0x0040, 0x2b5a, 0x6244, 0x6146, 0x6338, 0x603a, 0x0078, + 0x2b2c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, + 0x0c7e, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, + 0x00ff, 0x00c0, 0x2e70, 0x6030, 0xa085, 0xff00, 0x0078, 0x2e7f, + 0xa182, 0x007f, 0x00c8, 0x2ea9, 0xa188, 0x293f, 0x210c, 0xa18c, + 0x00ff, 0x6030, 0xa116, 0x0040, 0x2ea9, 0x810f, 0xa105, 0x127e, + 0x2091, 0x8000, 0x007e, 0x1078, 0x74d7, 0x007f, 0x0040, 0x2ea5, + 0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x1078, 0x3518, 0x0040, + 0x2eac, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x701b, 0x2f07, 0x2d00, 0x6012, 0x2009, 0x0032, + 0x1078, 0x756c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, + 0x2b56, 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x753d, 0x0078, 0x2ea5, + 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x0c7e, + 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, + 0x00c0, 0x2ec7, 0x6030, 0xa085, 0xff00, 0x0078, 0x2ed6, 0xa182, + 0x007f, 0x00c8, 0x2f00, 0xa188, 0x293f, 0x210c, 0xa18c, 0x00ff, + 0x6030, 0xa116, 0x0040, 0x2f00, 0x810f, 0xa105, 0x127e, 0x2091, + 0x8000, 0x007e, 0x1078, 0x74d7, 0x007f, 0x0040, 0x2efc, 0x601a, + 0x600b, 0xbc05, 0x601f, 0x0001, 0x1078, 0x3518, 0x0040, 0x2f03, + 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, + 0x683a, 0x701b, 0x2f07, 0x2d00, 0x6012, 0x2009, 0x0032, 0x1078, + 0x756c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, 0x2b56, + 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x753d, 0x0078, 0x2efc, 0x6830, + 0xa086, 0x0100, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x2061, 0xa62d, + 0x127e, 0x2091, 0x8000, 0x6000, 0xd084, 0x0040, 0x2f1c, 0x6104, + 0x6208, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b5a, 0x81ff, + 0x00c0, 0x2b56, 0x127e, 0x2091, 0x8000, 0x6244, 0x6060, 0xa202, + 0x0048, 0x2f33, 0xa085, 0x0001, 0x1078, 0x2500, 0x1078, 0x3bf5, + 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b5a, 0x127e, 0x2091, + 0x8000, 0x20a9, 0x0011, 0x2001, 0xa340, 0x20a0, 0xa006, 0x40a4, + 0x127f, 0x0078, 0x2b2c, 0x7d38, 0x7c3c, 0x0078, 0x2bde, 0x7824, + 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, 0x2b56, 0x624c, 0xa084, + 0xff00, 0x8007, 0xa206, 0x00c0, 0x2f5f, 0x2001, 0xa340, 0x2009, + 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x3566, 0x81ff, + 0x00c0, 0x2b56, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2b56, 0x0c7e, 0x1078, 0x3518, + 0x0c7f, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x1078, 0x8b85, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x2f81, + 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2b56, 0xad80, 0x000e, + 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x3566, + 0x1078, 0x3518, 0x0040, 0x2b56, 0x1078, 0x421a, 0x2009, 0x001c, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, 0x2fa1, + 0x007c, 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, 0x2b5a, 0x6804, + 0xd0ac, 0x0040, 0x2fae, 0xd0a4, 0x0040, 0x2b5a, 0xd094, 0x0040, + 0x2fb9, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, 0xffdf, 0x6106, + 0x0c7f, 0xd08c, 0x0040, 0x2fc4, 0x0c7e, 0x2061, 0x0100, 0x6104, + 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, 0x210c, 0xa18a, + 0x0002, 0x0048, 0x2fd9, 0xd084, 0x0040, 0x2fd9, 0x6a28, 0xa28a, + 0x007f, 0x00c8, 0x2b5a, 0xa288, 0x293f, 0x210c, 0xa18c, 0x00ff, + 0x6152, 0xd0dc, 0x0040, 0x2fe2, 0x6828, 0xa08a, 0x007f, 0x00c8, + 0x2b5a, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0048, 0x2b5a, 0xa08a, + 0x0841, 0x00c8, 0x2b5a, 0xa084, 0x0007, 0x00c0, 0x2b5a, 0x680c, + 0xa005, 0x0040, 0x2b5a, 0x6810, 0xa005, 0x0040, 0x2b5a, 0x6848, + 0x6940, 0xa10a, 0x00c8, 0x2b5a, 0x8001, 0x0040, 0x2b5a, 0x684c, + 0x6944, 0xa10a, 0x00c8, 0x2b5a, 0x8001, 0x0040, 0x2b5a, 0x6804, + 0xd0fc, 0x0040, 0x3038, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, + 0x0014, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399, + 0x0000, 0x1078, 0x3562, 0x701b, 0x301e, 0x007c, 0xade8, 0x000d, + 0x20a9, 0x0014, 0x2d98, 0x2069, 0xa36d, 0x2da0, 0x53a3, 0x7010, + 0xa0e8, 0x000d, 0x2001, 0xa371, 0x200c, 0xd1e4, 0x0040, 0x3038, + 0x0c7e, 0x2061, 0x0100, 0x6004, 0xa085, 0x0b00, 0x6006, 0x0c7f, + 0x20a9, 0x001c, 0x2d98, 0x2069, 0xa351, 0x2da0, 0x53a3, 0x6814, + 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, 0x6042, 0x1078, + 0x4dbd, 0x1078, 0x48dd, 0x1078, 0x494d, 0x6000, 0xa086, 0x0000, + 0x00c0, 0x30c3, 0x6808, 0x602a, 0x1078, 0x218b, 0x6818, 0x691c, + 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, + 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0040, 0x3070, 0x6830, 0x6934, + 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0078, 0x3072, + 0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x1078, 0x59a8, + 0x6904, 0xd1fc, 0x0040, 0x30a5, 0x0c7e, 0x2009, 0x0000, 0x20a9, + 0x0001, 0x6b70, 0xd384, 0x0040, 0x30a2, 0x0078, 0x308c, 0x839d, + 0x00c8, 0x30a2, 0x3508, 0x8109, 0x1078, 0x5364, 0x6878, 0x6016, + 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a, 0xa184, 0x00ff, + 0x6006, 0x8108, 0x00c0, 0x30a0, 0x6003, 0x0003, 0x0078, 0x30a2, + 0x6003, 0x0001, 0x00f0, 0x3087, 0x0c7f, 0x0c7e, 0x2061, 0x0100, + 0x602f, 0x0040, 0x602f, 0x0000, 0x0c7f, 0x1078, 0x3784, 0x0040, + 0x30b3, 0x1078, 0x2500, 0x60bc, 0xa005, 0x0040, 0x30bf, 0x6003, + 0x0001, 0x2091, 0x301d, 0x1078, 0x4171, 0x0078, 0x30c3, 0x6003, + 0x0004, 0x2091, 0x301d, 0x0078, 0x2b2c, 0x6000, 0xa086, 0x0000, + 0x0040, 0x2b56, 0x2069, 0xa351, 0x7830, 0x6842, 0x7834, 0x6846, + 0x6804, 0xd0fc, 0x0040, 0x30d8, 0x2009, 0x0030, 0x0078, 0x30da, + 0x2009, 0x001c, 0x2d00, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, + 0x3566, 0xa006, 0x1078, 0x2500, 0x81ff, 0x00c0, 0x2b56, 0x1078, + 0x421a, 0x1078, 0x4171, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, + 0x6180, 0x81ff, 0x0040, 0x3107, 0x703f, 0x0000, 0x2001, 0xa9c0, + 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x127e, 0x2091, + 0x8000, 0x1078, 0x3566, 0x701b, 0x2b29, 0x127f, 0x007c, 0x703f, + 0x0001, 0x0d7e, 0x2069, 0xa9c0, 0x20a9, 0x0040, 0x20a1, 0xa9c0, + 0x2019, 0xffff, 0x43a4, 0x654c, 0xa588, 0x293f, 0x210c, 0xa18c, + 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100, 0xa506, 0x0040, + 0x3139, 0x1078, 0x4501, 0x00c0, 0x3139, 0x6014, 0x821c, 0x0048, + 0x3131, 0xa398, 0xa9c0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0078, + 0x3138, 0xa398, 0xa9c0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, + 0x8210, 0x8108, 0xa182, 0x0080, 0x00c8, 0x3140, 0x0078, 0x311d, + 0x8201, 0x8007, 0x2d0c, 0xa105, 0x206a, 0x0d7f, 0x20a9, 0x0040, + 0x20a1, 0xa9c0, 0x2099, 0xa9c0, 0x1078, 0x41be, 0x0078, 0x30f6, + 0x1078, 0x3542, 0x0040, 0x2b5a, 0x0c7e, 0x1078, 0x3518, 0x0c7f, + 0x00c0, 0x315e, 0x2009, 0x0002, 0x0078, 0x2b56, 0x2001, 0xa352, + 0x2004, 0xd0b4, 0x0040, 0x3185, 0x6000, 0xd08c, 0x00c0, 0x3185, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3185, 0x6837, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x8bd9, 0x00c0, 0x317c, + 0x2009, 0x0003, 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3181, + 0x007c, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x20a9, 0x002b, 0x2c98, + 0xade8, 0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, + 0x2098, 0xad80, 0x0006, 0x20a0, 0x1078, 0x41be, 0x20a9, 0x0004, + 0xac80, 0x000a, 0x2098, 0xad80, 0x000a, 0x20a0, 0x1078, 0x41be, + 0x2d00, 0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, + 0x3566, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040, 0x2b5a, + 0x1078, 0x46ef, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x7828, + 0xa08a, 0x1000, 0x00c8, 0x2b5a, 0x1078, 0x3542, 0x0040, 0x2b5a, + 0x1078, 0x475f, 0x0040, 0x2b56, 0x2019, 0x0004, 0x1078, 0x4705, + 0x7924, 0x810f, 0x7a28, 0x1078, 0x31cf, 0x0078, 0x2b2c, 0xa186, + 0x00ff, 0x0040, 0x31d7, 0x1078, 0x31e7, 0x0078, 0x31e6, 0x2029, + 0x007e, 0x2061, 0xa300, 0x644c, 0x2400, 0xa506, 0x0040, 0x31e3, + 0x2508, 0x1078, 0x31e7, 0x8529, 0x00c8, 0x31dc, 0x007c, 0x1078, + 0x4501, 0x00c0, 0x31f2, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, + 0x1078, 0x58e1, 0x007c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, + 0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x46fa, + 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040, + 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x46e4, 0x0078, + 0x2b2c, 0x6100, 0x0078, 0x2b2c, 0x1078, 0x3542, 0x0040, 0x2b5a, + 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x0d7e, + 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x3228, 0xace8, 0x0006, + 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, + 0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200, 0x0078, 0x2b2c, + 0xa006, 0x1078, 0x2500, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, + 0x0040, 0x3245, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x421a, 0x7828, + 0xa08a, 0x1000, 0x00c8, 0x2b5a, 0x7924, 0xa18c, 0xff00, 0x810f, + 0xa186, 0x00ff, 0x0040, 0x325b, 0xa182, 0x007f, 0x00c8, 0x2b5a, + 0x2100, 0x1078, 0x24fa, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000, + 0x2061, 0xa5be, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x0100, + 0x6030, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, + 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4196, 0x1078, 0x596c, + 0x7924, 0xa18c, 0xff00, 0x810f, 0x7a28, 0x1078, 0x31cf, 0x127f, + 0x0c7f, 0x027f, 0x0078, 0x2b2c, 0x7924, 0xa18c, 0xff00, 0x810f, + 0x0c7e, 0x1078, 0x4499, 0x2c08, 0x0c7f, 0x00c0, 0x2b5a, 0x0078, + 0x2b2c, 0x81ff, 0x0040, 0x3298, 0x2009, 0x0001, 0x0078, 0x2b56, + 0x60c8, 0xd09c, 0x00c0, 0x32a0, 0x2009, 0x0005, 0x0078, 0x2b56, + 0x1078, 0x3518, 0x00c0, 0x32a8, 0x2009, 0x0002, 0x0078, 0x2b56, + 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, + 0x32b2, 0x007c, 0x2009, 0x0080, 0x1078, 0x4501, 0x00c0, 0x32bf, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0040, 0x32c3, 0x2021, + 0x400a, 0x0078, 0x2b2e, 0x0d7e, 0xade8, 0x000d, 0x6900, 0x6a08, + 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0040, + 0x3336, 0xa0be, 0x0112, 0x0040, 0x3336, 0xa0be, 0x0113, 0x0040, + 0x3336, 0xa0be, 0x0114, 0x0040, 0x3336, 0xa0be, 0x0117, 0x0040, + 0x3336, 0xa0be, 0x011a, 0x0040, 0x3336, 0xa0be, 0x0121, 0x0040, + 0x332c, 0xa0be, 0x0131, 0x0040, 0x332c, 0xa0be, 0x0171, 0x0040, + 0x3336, 0xa0be, 0x0173, 0x0040, 0x3336, 0xa0be, 0x01a1, 0x00c0, + 0x32fe, 0x6830, 0x8007, 0x6832, 0x0078, 0x333c, 0xa0be, 0x0212, + 0x0040, 0x3332, 0xa0be, 0x0213, 0x0040, 0x3332, 0xa0be, 0x0214, + 0x0040, 0x3324, 0xa0be, 0x0217, 0x0040, 0x331e, 0xa0be, 0x021a, + 0x00c0, 0x3317, 0x6838, 0x8007, 0x683a, 0x0078, 0x3336, 0xa0be, + 0x0300, 0x0040, 0x3336, 0x0d7f, 0x0078, 0x2b5a, 0xad80, 0x0010, + 0x20a9, 0x0007, 0x1078, 0x337e, 0xad80, 0x000e, 0x20a9, 0x0001, + 0x1078, 0x337e, 0x0078, 0x3336, 0xad80, 0x000c, 0x1078, 0x338c, + 0x0078, 0x333c, 0xad80, 0x000e, 0x1078, 0x338c, 0xad80, 0x000c, + 0x20a9, 0x0001, 0x1078, 0x337e, 0x0c7e, 0x1078, 0x3518, 0x0040, + 0x336f, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, 0x6853, 0x0000, + 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, 0x0000, + 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, 0x0c7f, + 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, + 0x6804, 0x2068, 0x1078, 0x8ba1, 0x00c0, 0x336a, 0x2009, 0x0003, + 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3375, 0x007c, 0x0c7f, + 0x0d7f, 0x2009, 0x0002, 0x0078, 0x2b56, 0x6820, 0xa086, 0x8001, + 0x00c0, 0x2b2c, 0x2009, 0x0004, 0x0078, 0x2b56, 0x017e, 0x2008, + 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, + 0x00f0, 0x3380, 0x017f, 0x007c, 0x017e, 0x0a7e, 0x0b7e, 0x2008, + 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, + 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x0b7f, 0x0a7f, + 0x017f, 0x007c, 0x81ff, 0x0040, 0x33a9, 0x2009, 0x0001, 0x0078, + 0x2b56, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, + 0x0048, 0x2b5a, 0xa182, 0x00ff, 0x00c8, 0x2b5a, 0x7a2c, 0x7b28, + 0x6068, 0xa306, 0x00c0, 0x33c4, 0x606c, 0xa24e, 0x0040, 0x2b5a, + 0xa9cc, 0xff00, 0x0040, 0x2b5a, 0x0c7e, 0x1078, 0x346d, 0x2c68, + 0x0c7f, 0x0040, 0x33fc, 0xa0c6, 0x4000, 0x00c0, 0x33e2, 0x0c7e, + 0x007e, 0x2d60, 0x2009, 0x0000, 0x1078, 0x47cb, 0x00c0, 0x33d9, + 0xc185, 0x6000, 0xd0bc, 0x0040, 0x33de, 0xc18d, 0x007f, 0x0c7f, + 0x0078, 0x33f9, 0xa0c6, 0x4007, 0x00c0, 0x33e9, 0x2408, 0x0078, + 0x33f9, 0xa0c6, 0x4008, 0x00c0, 0x33f1, 0x2708, 0x2610, 0x0078, + 0x33f9, 0xa0c6, 0x4009, 0x00c0, 0x33f7, 0x0078, 0x33f9, 0x2001, + 0x4006, 0x2020, 0x0078, 0x2b2e, 0x2d00, 0x7022, 0x017e, 0x0b7e, + 0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x74d7, 0x0040, 0x3442, 0x2d00, + 0x601a, 0x2001, 0xa356, 0x2004, 0xa084, 0x00ff, 0x6842, 0x2e58, + 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x2b70, 0x00c0, + 0x3423, 0x1078, 0x753d, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x2009, + 0x0002, 0x0078, 0x2b56, 0x6837, 0x0000, 0x2d00, 0x6012, 0x6833, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, + 0x2813, 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x442b, + 0x2001, 0x0002, 0x1078, 0x443f, 0x2009, 0x0002, 0x1078, 0x756c, + 0xa085, 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x00c0, 0x344c, + 0x2009, 0x0003, 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3451, + 0x007c, 0x6830, 0xa086, 0x0100, 0x7020, 0x2060, 0x00c0, 0x345f, + 0x2009, 0x0004, 0x6204, 0xa294, 0x00ff, 0x0078, 0x2b56, 0x2009, + 0x0000, 0x1078, 0x47cb, 0x00c0, 0x3466, 0xc185, 0x6000, 0xd0bc, + 0x0040, 0x346b, 0xc18d, 0x0078, 0x2b2c, 0x0e7e, 0x0d7e, 0x2029, + 0x0000, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, 0xa4b4, 0x2e04, + 0xa005, 0x00c0, 0x3482, 0x2100, 0xa406, 0x00c0, 0x34b3, 0x2428, + 0x0078, 0x34b3, 0x2068, 0x6f10, 0x2700, 0xa306, 0x00c0, 0x34a4, + 0x6e14, 0x2600, 0xa206, 0x00c0, 0x34a4, 0x2400, 0xa106, 0x00c0, + 0x34a0, 0x2d60, 0xd884, 0x0040, 0x34c8, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x0006, 0x00c0, 0x34c8, 0x2001, 0x4000, 0x0078, 0x34c9, + 0x2001, 0x4007, 0x0078, 0x34c9, 0x2400, 0xa106, 0x00c0, 0x34b3, + 0x6e14, 0x87ff, 0x00c0, 0x34af, 0x86ff, 0x0040, 0x347f, 0x2001, + 0x4008, 0x0078, 0x34c9, 0x8420, 0x8e70, 0x00f0, 0x3477, 0x85ff, + 0x00c0, 0x34c2, 0x2001, 0x4009, 0x0078, 0x34c9, 0x2001, 0x0001, + 0x0078, 0x34c9, 0x1078, 0x4499, 0x00c0, 0x34be, 0x6312, 0x6216, + 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, 0x00c0, 0x2b56, + 0x1078, 0x3518, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6838, 0xc0fd, + 0x683a, 0x7824, 0xa005, 0x0040, 0x2b5a, 0xa096, 0x00ff, 0x0040, + 0x34e5, 0xa092, 0x0004, 0x00c8, 0x2b5a, 0x2010, 0x2d18, 0x1078, + 0x27c2, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x34f0, 0x007c, + 0x6830, 0xa086, 0x0100, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x7924, + 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, 0x2b5a, 0xa182, + 0x00ff, 0x00c8, 0x2b5a, 0x127e, 0x2091, 0x8000, 0x1078, 0x8a89, + 0x00c0, 0x3515, 0xa190, 0xa434, 0x2204, 0xa065, 0x0040, 0x3515, + 0x1078, 0x4235, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b56, + 0x1078, 0x1381, 0x0040, 0x352f, 0xa006, 0x6802, 0x7010, 0xa005, + 0x00c0, 0x3527, 0x2d00, 0x7012, 0x7016, 0x0078, 0x352d, 0x7014, + 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80, 0x000d, 0x007c, + 0x7924, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x4501, 0x00c0, 0x353f, + 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0048, 0x3540, 0xa066, + 0x8cff, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x1078, 0x4501, + 0x00c0, 0x3550, 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0048, 0x3551, + 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, 0x0040, 0x355e, + 0x2168, 0x6904, 0x1078, 0x139a, 0x0078, 0x3555, 0x7112, 0x7116, + 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x3568, 0x2031, 0x0000, + 0x2061, 0xa3d1, 0x6606, 0x6112, 0x600e, 0x6226, 0x632a, 0x642e, + 0x6532, 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, 0x701b, 0x2b2c, + 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, 0x0000, 0x2001, + 0xa38f, 0x2004, 0xa005, 0x00c0, 0x3594, 0x0068, 0x3594, 0x7818, + 0xd084, 0x00c0, 0x3594, 0x7a22, 0x7b26, 0x7c2a, 0x781b, 0x0001, + 0x2091, 0x4080, 0x0078, 0x35b9, 0x017e, 0x0c7e, 0x0e7e, 0x2071, + 0xa381, 0x7138, 0xa182, 0x0008, 0x0048, 0x35a2, 0x7030, 0x2060, + 0x0078, 0x35b3, 0x7030, 0xa0e0, 0x0008, 0xac82, 0xa3d1, 0x0048, + 0x35ab, 0x2061, 0xa391, 0x2c00, 0x7032, 0x81ff, 0x00c0, 0x35b1, + 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, 0x0e7f, 0x0c7f, + 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, 0xa381, 0x7038, + 0xa005, 0x0040, 0x35f5, 0x127e, 0x2091, 0x8000, 0x0068, 0x35f4, + 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x35f3, 0x0c7e, + 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826, 0x6008, 0x782a, + 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, 0xa005, + 0x00c0, 0x35e9, 0x7033, 0xa391, 0x7037, 0xa391, 0x0c7f, 0x0078, + 0x35f3, 0xac80, 0x0008, 0xa0fa, 0xa3d1, 0x0048, 0x35f1, 0x2001, + 0xa391, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, 0x007c, 0x027e, + 0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x3602, 0x2011, 0x8014, + 0x1078, 0x3579, 0x027f, 0x007c, 0x81ff, 0x00c0, 0x2b56, 0x127e, + 0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x1078, + 0x4171, 0x127f, 0x0078, 0x2b2c, 0x7824, 0x2008, 0xa18c, 0xfffd, + 0x00c0, 0x361f, 0x61d4, 0xa10d, 0x61d6, 0x0078, 0x2b2c, 0x0078, + 0x2b5a, 0x81ff, 0x00c0, 0x2b56, 0x6000, 0xa086, 0x0003, 0x00c0, + 0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x2b56, 0x1078, + 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x00c0, 0x363e, 0x7828, 0xa005, 0x0040, 0x2b2c, 0x0c7e, 0x1078, + 0x3518, 0x0c7f, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6833, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x1078, 0x8c4d, 0x0040, 0x2b56, 0x7007, + 0x0003, 0x701b, 0x3654, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, + 0x2b56, 0x0078, 0x2b2c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, + 0x00c0, 0x2b56, 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, + 0x3518, 0x0040, 0x2b56, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, + 0x0000, 0x702f, 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, + 0x4501, 0x00c0, 0x36d8, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, + 0x0040, 0x3688, 0xa0c4, 0xff00, 0xa8c6, 0x0600, 0x00c0, 0x36d8, + 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x3695, 0x1078, 0x47cb, + 0x00c0, 0x3695, 0xd79c, 0x0040, 0x36d8, 0xd794, 0x00c0, 0x369b, + 0xd784, 0x0040, 0x36a7, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, + 0x0004, 0x53a3, 0x1078, 0x338c, 0xd794, 0x0040, 0x36b0, 0xac80, + 0x000a, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x1078, 0x338c, + 0x21a2, 0xd794, 0x0040, 0x36d0, 0xac80, 0x0000, 0x2098, 0x94a0, + 0x20a9, 0x0002, 0x53a3, 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, + 0x0004, 0x2098, 0x3400, 0x20a9, 0x0002, 0x53a3, 0x1078, 0x337e, + 0xac80, 0x0026, 0x2098, 0x20a9, 0x0002, 0x53a3, 0x0078, 0x36d1, + 0x94a0, 0xd794, 0x0040, 0x36d6, 0xa6b0, 0x000b, 0xa6b0, 0x0005, + 0x8108, 0xd78c, 0x0040, 0x36e2, 0xa186, 0x0100, 0x0040, 0x36f3, + 0x0078, 0x36e6, 0xa186, 0x007e, 0x0040, 0x36f3, 0xd794, 0x0040, + 0x36ed, 0xa686, 0x0020, 0x0078, 0x36ef, 0xa686, 0x0028, 0x0040, + 0x36fc, 0x0078, 0x3677, 0x86ff, 0x00c0, 0x36fa, 0x7120, 0x810b, + 0x0078, 0x2b2c, 0x702f, 0x0001, 0x711e, 0x7020, 0xa600, 0x7022, + 0x772a, 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6612, 0x7024, 0x600e, + 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x13d1, 0x7007, + 0x0002, 0x701b, 0x3714, 0x007c, 0x702c, 0xa005, 0x00c0, 0x3726, + 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, 0xa3d1, + 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x3677, 0x7120, 0x810b, + 0x0078, 0x2b2c, 0x2029, 0x007e, 0x7924, 0x7a28, 0x7b2c, 0x7c38, + 0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, + 0x0048, 0x2b5a, 0xa184, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2b5a, + 0xa502, 0x0048, 0x2b5a, 0xa284, 0xff00, 0x8007, 0xa0e2, 0x0020, + 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0xa284, 0x00ff, 0xa0e2, + 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0xa384, 0xff00, + 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, + 0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, + 0x2b5a, 0xa484, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, + 0xa502, 0x0048, 0x2b5a, 0xa484, 0x00ff, 0xa0e2, 0x0020, 0x0048, + 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0x2061, 0xa5a3, 0x6102, 0x6206, + 0x630a, 0x640e, 0x0078, 0x2b2c, 0x007e, 0x2001, 0xa352, 0x2004, + 0xd0cc, 0x007f, 0x007c, 0x007e, 0x2001, 0xa371, 0x2004, 0xd0bc, + 0x007f, 0x007c, 0x6160, 0x7a24, 0x6300, 0x82ff, 0x00c0, 0x379b, + 0x7926, 0x0078, 0x2b2c, 0x83ff, 0x00c0, 0x2b5a, 0x2001, 0xfff0, + 0xa200, 0x00c8, 0x2b5a, 0x2019, 0xffff, 0x6064, 0xa302, 0xa200, + 0x0048, 0x2b5a, 0x7926, 0x6262, 0x0078, 0x2b2c, 0x2001, 0xa300, + 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x7c28, 0x7d24, 0x7e38, + 0x7f2c, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, 0x0000, 0x2019, + 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, 0x0003, 0x7026, + 0x20a0, 0xa1e0, 0xa434, 0x2c64, 0x8cff, 0x0040, 0x37e8, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x0040, 0x37dd, 0x6004, 0xa084, + 0xff00, 0xa086, 0x0600, 0x00c0, 0x37e8, 0x6014, 0x20a2, 0x94a0, + 0x6010, 0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, + 0x8108, 0xa182, 0x00ff, 0x0040, 0x37f3, 0xa386, 0x002a, 0x0040, + 0x37fc, 0x0078, 0x37c9, 0x83ff, 0x00c0, 0x37fa, 0x7120, 0x810c, + 0x0078, 0x2b2c, 0x702f, 0x0001, 0x711e, 0x7020, 0xa300, 0x7022, + 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6312, 0x7024, 0x600e, 0x6426, + 0x652a, 0x662e, 0x6732, 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, + 0x701b, 0x3813, 0x007c, 0x702c, 0xa005, 0x00c0, 0x3824, 0x711c, + 0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xa3d1, 0x6424, 0x6528, + 0x662c, 0x6730, 0x0078, 0x37c9, 0x7120, 0x810c, 0x0078, 0x2b2c, + 0x81ff, 0x00c0, 0x2b56, 0x60c8, 0xd09c, 0x0040, 0x2b56, 0x1078, + 0x3518, 0x0040, 0x2b56, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x1078, 0x3562, 0x701b, 0x383d, 0x007c, 0x0d7e, 0xade8, 0x000d, + 0x6828, 0xa0be, 0x7000, 0x0040, 0x3850, 0xa0be, 0x7100, 0x0040, + 0x3850, 0xa0be, 0x7200, 0x0040, 0x3850, 0x0d7f, 0x0078, 0x2b5a, + 0x6820, 0x6924, 0x1078, 0x24e3, 0x00c0, 0x387b, 0x1078, 0x4499, + 0x00c0, 0x387b, 0x7122, 0x6612, 0x6516, 0x6e18, 0x0c7e, 0x1078, + 0x3518, 0x0040, 0x387b, 0x1078, 0x3518, 0x0040, 0x387b, 0x0c7f, + 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, + 0x6804, 0x2068, 0x1078, 0x8bbd, 0x0040, 0x2b56, 0x7007, 0x0003, + 0x701b, 0x387e, 0x007c, 0x0d7f, 0x0078, 0x2b56, 0x7120, 0x1078, + 0x2921, 0x6820, 0xa086, 0x8001, 0x0040, 0x2b56, 0x2d00, 0x701e, + 0x6804, 0xa080, 0x0002, 0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0, + 0x1078, 0x41be, 0x007f, 0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, + 0x6d14, 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, + 0x7000, 0x00c0, 0x38a5, 0x0078, 0x38a9, 0xa7c6, 0x7100, 0x00c0, + 0x38b1, 0xa6c2, 0x0004, 0x0048, 0x2b5a, 0x2009, 0x0004, 0x0078, + 0x3566, 0xa7c6, 0x7200, 0x00c0, 0x2b5a, 0xa6c2, 0x0054, 0x0048, + 0x2b5a, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, 0x642e, 0x6532, + 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, 0x701b, 0x38c8, 0x007c, + 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, + 0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x1078, 0x41be, 0x007f, + 0x2009, 0x002a, 0x2061, 0xa3d1, 0x6224, 0x6328, 0x642c, 0x6530, + 0x0078, 0x3566, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040, + 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x4710, 0x0078, + 0x2b2c, 0x7824, 0xd084, 0x0040, 0x3150, 0x1078, 0x3542, 0x0040, + 0x2b5a, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x00c0, 0x3903, 0x2009, + 0x0002, 0x0078, 0x2b56, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0040, 0x3910, 0xa08e, 0x0004, 0x0040, 0x3910, 0xa08e, 0x0005, + 0x00c0, 0x3934, 0x2001, 0xa352, 0x2004, 0xd0b4, 0x0040, 0x3185, + 0x6000, 0xd08c, 0x00c0, 0x3185, 0x6837, 0x0000, 0x6838, 0xc0fd, + 0x683a, 0x1078, 0x8bd9, 0x00c0, 0x3929, 0x2009, 0x0003, 0x0078, + 0x2b56, 0x7007, 0x0003, 0x701b, 0x392e, 0x007c, 0x1078, 0x3542, + 0x0040, 0x2b5a, 0x0078, 0x3185, 0x2009, 0xa32e, 0x210c, 0x81ff, + 0x0040, 0x393e, 0x2009, 0x0001, 0x0078, 0x2b56, 0x2001, 0xa300, + 0x2004, 0xa086, 0x0003, 0x0040, 0x3949, 0x2009, 0x0007, 0x0078, + 0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x0040, 0x3953, 0x2009, + 0x0008, 0x0078, 0x2b56, 0x609c, 0xd0a4, 0x00c0, 0x395a, 0xd0ac, + 0x00c0, 0x3185, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, + 0x683a, 0x1078, 0x8c4d, 0x00c0, 0x3969, 0x2009, 0x0003, 0x0078, + 0x2b56, 0x7007, 0x0003, 0x701b, 0x396e, 0x007c, 0x6830, 0xa086, + 0x0100, 0x00c0, 0x3977, 0x2009, 0x0004, 0x0078, 0x2b56, 0x1078, + 0x3542, 0x0040, 0x2b5a, 0x0078, 0x3912, 0x81ff, 0x2009, 0x0001, + 0x00c0, 0x2b56, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x00c0, + 0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x2009, 0x0008, 0x00c0, + 0x2b56, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x0006, 0x2009, 0x0009, 0x00c0, 0x2b56, 0x0c7e, 0x1078, + 0x3518, 0x0c7f, 0x2009, 0x0002, 0x0040, 0x2b56, 0x6837, 0x0000, + 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00, + 0xa18c, 0x00ff, 0xa006, 0x82ff, 0x00c0, 0x39bc, 0xc0ed, 0x6952, + 0x792c, 0x6956, 0x0078, 0x39c5, 0xa28e, 0x0100, 0x00c0, 0x2b5a, + 0xc0e5, 0x6853, 0x0000, 0x6857, 0x0000, 0x683e, 0x1078, 0x8df6, + 0x2009, 0x0003, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x39d1, + 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040, 0x2b56, + 0x0078, 0x2b2c, 0x81ff, 0x2009, 0x0001, 0x00c0, 0x2b56, 0x6000, + 0xa086, 0x0003, 0x2009, 0x0007, 0x00c0, 0x2b56, 0x1078, 0x3542, + 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x2009, + 0x0009, 0x00c0, 0x2b56, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x2009, + 0x0002, 0x0040, 0x2b56, 0xad80, 0x000f, 0x2009, 0x0008, 0x7a2c, + 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, 0x3a08, 0x007c, + 0x0d7e, 0xade8, 0x000f, 0x6800, 0xa086, 0x0500, 0x00c0, 0x3a1b, + 0x6804, 0xa005, 0x00c0, 0x3a1b, 0x6808, 0xa084, 0xff00, 0x00c0, + 0x3a1b, 0x0078, 0x3a1e, 0x0d7f, 0x00c0, 0x2b5a, 0x0d7f, 0x6837, + 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x0c7e, 0x1078, + 0x3542, 0x00c0, 0x3a2e, 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x8e52, + 0x2009, 0x0003, 0x0c7f, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, + 0x3a3a, 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040, + 0x2b56, 0x0078, 0x2b2c, 0x127e, 0x0c7e, 0x0e7e, 0x2061, 0x0100, + 0x2071, 0xa300, 0x6044, 0xd0a4, 0x00c0, 0x3a6c, 0xd084, 0x0040, + 0x3a55, 0x1078, 0x3bcc, 0x0078, 0x3a68, 0xd08c, 0x0040, 0x3a5c, + 0x1078, 0x3ae3, 0x0078, 0x3a68, 0xd094, 0x0040, 0x3a63, 0x1078, + 0x3ab7, 0x0078, 0x3a68, 0xd09c, 0x0040, 0x3a68, 0x1078, 0x3a76, + 0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, 0x00c0, + 0x3a73, 0xc19d, 0x612a, 0x017f, 0x0078, 0x3a68, 0x624c, 0xa286, + 0xf0f0, 0x00c0, 0x3a87, 0x6048, 0xa086, 0xf0f0, 0x0040, 0x3a87, + 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x3ab6, 0xa294, + 0xff00, 0xa296, 0xf700, 0x0040, 0x3a9c, 0x7134, 0xd1a4, 0x00c0, + 0x3a9c, 0x6240, 0xa294, 0x0010, 0x0040, 0x3a9c, 0x2009, 0x00f7, + 0x1078, 0x41de, 0x0078, 0x3ab6, 0x6043, 0x0040, 0x6043, 0x0000, + 0x7073, 0x0000, 0x708b, 0x0001, 0x70af, 0x0000, 0x70cb, 0x0000, + 0x2009, 0xa9c0, 0x200b, 0x0000, 0x7083, 0x0000, 0x7077, 0x000f, + 0x2009, 0x000f, 0x2011, 0x4122, 0x1078, 0x596c, 0x007c, 0x157e, + 0x7074, 0xa005, 0x00c0, 0x3ae1, 0x2011, 0x4122, 0x1078, 0x58d4, + 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8, + 0x6044, 0xd08c, 0x00c0, 0x3ada, 0x00f0, 0x3ac8, 0x6242, 0x7087, + 0x0000, 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242, + 0x0078, 0x3ae1, 0x6242, 0x7087, 0x0000, 0x707b, 0x0000, 0x0078, + 0x3ae1, 0x157f, 0x007c, 0x7078, 0xa08a, 0x0003, 0x00c8, 0x3aec, + 0x1079, 0x3aef, 0x0078, 0x3aee, 0x1078, 0x1328, 0x007c, 0x3af2, + 0x3b41, 0x3bcb, 0x0f7e, 0x707b, 0x0001, 0x20e1, 0xa000, 0x20e1, + 0x8700, 0x1078, 0x218b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2079, + 0xa800, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, 0x780f, + 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000, 0x781f, + 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000, 0x782f, + 0x0000, 0x2079, 0xa80c, 0x207b, 0x1101, 0x7807, 0x0000, 0x2099, + 0xa305, 0x20a1, 0xa80e, 0x20a9, 0x0004, 0x53a3, 0x2079, 0xa812, + 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xa800, 0x20a1, 0x020b, + 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000, 0x1078, + 0x4158, 0x0f7f, 0x707f, 0x0000, 0x6043, 0x0008, 0x6043, 0x0000, + 0x007c, 0x0d7e, 0x707c, 0x707f, 0x0000, 0xa025, 0x0040, 0x3bb5, + 0x6020, 0xd0b4, 0x00c0, 0x3bb3, 0x7188, 0x81ff, 0x0040, 0x3ba2, + 0xa486, 0x000c, 0x00c0, 0x3bad, 0xa480, 0x0018, 0x8004, 0x20a8, + 0x2011, 0xa880, 0x2019, 0xa800, 0x220c, 0x2304, 0xa106, 0x00c0, + 0x3b79, 0x8210, 0x8318, 0x00f0, 0x3b5c, 0x6043, 0x0004, 0x608b, + 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707b, 0x0002, 0x7087, + 0x0002, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c, 0x0078, + 0x3bb3, 0x2069, 0xa880, 0x6930, 0xa18e, 0x1101, 0x00c0, 0x3bad, + 0x6834, 0xa005, 0x00c0, 0x3bad, 0x6900, 0xa18c, 0x00ff, 0x00c0, + 0x3b8d, 0x6804, 0xa005, 0x0040, 0x3ba2, 0x2011, 0xa88e, 0x2019, + 0xa305, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, 0x0048, 0x3ba0, + 0x00c0, 0x3bad, 0x8210, 0x8318, 0x00f0, 0x3b93, 0x0078, 0x3bad, + 0x708b, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, + 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008, 0x6043, + 0x0000, 0x0078, 0x3bb5, 0x0d7f, 0x007c, 0x6020, 0xd0b4, 0x00c0, + 0x3bb3, 0x60c3, 0x000c, 0x2011, 0xa5b5, 0x2013, 0x0000, 0x707f, + 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, + 0x6c38, 0x0078, 0x3bb3, 0x007c, 0x7084, 0xa08a, 0x001d, 0x00c8, + 0x3bd5, 0x1079, 0x3bd8, 0x0078, 0x3bd7, 0x1078, 0x1328, 0x007c, + 0x3c02, 0x3c11, 0x3c40, 0x3c59, 0x3c85, 0x3cb1, 0x3cdd, 0x3d13, + 0x3d3f, 0x3d67, 0x3daa, 0x3dd4, 0x3df6, 0x3e0c, 0x3e32, 0x3e45, + 0x3e4e, 0x3e7e, 0x3eaa, 0x3ed6, 0x3f02, 0x3f38, 0x3f7d, 0x3fac, + 0x3fce, 0x4010, 0x4036, 0x404f, 0x4050, 0x0c7e, 0x2061, 0xa300, + 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006, + 0x0c7f, 0x007c, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, + 0x7087, 0x0001, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c, + 0x007c, 0x0f7e, 0x707c, 0xa086, 0x0014, 0x00c0, 0x3c3e, 0x6043, + 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x3c3e, 0x2079, 0xa880, 0x7a30, + 0xa296, 0x1102, 0x00c0, 0x3c3c, 0x7834, 0xa005, 0x00c0, 0x3c3c, + 0x7a38, 0xd2fc, 0x0040, 0x3c32, 0x70ac, 0xa005, 0x00c0, 0x3c32, + 0x70af, 0x0001, 0x2011, 0x4129, 0x1078, 0x58d4, 0x7087, 0x0010, + 0x1078, 0x3e4e, 0x0078, 0x3c3e, 0x1078, 0x4171, 0x0f7f, 0x007c, + 0x7087, 0x0003, 0x6043, 0x0004, 0x2011, 0x4129, 0x1078, 0x58d4, + 0x1078, 0x41c6, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, + 0x20a3, 0x0000, 0x00f0, 0x3c50, 0x60c3, 0x0014, 0x1078, 0x4158, + 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3c83, 0x2011, 0x4129, + 0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3c81, 0x2079, 0xa880, + 0x7a30, 0xa296, 0x1102, 0x00c0, 0x3c81, 0x7834, 0xa005, 0x00c0, + 0x3c81, 0x7a38, 0xd2fc, 0x0040, 0x3c7b, 0x70ac, 0xa005, 0x00c0, + 0x3c7b, 0x70af, 0x0001, 0x7087, 0x0004, 0x1078, 0x3c85, 0x0078, + 0x3c83, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0005, 0x1078, + 0x41c6, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, + 0x1078, 0x4211, 0x00c0, 0x3ca3, 0x7070, 0xa005, 0x00c0, 0x3ca3, + 0x714c, 0xa186, 0xffff, 0x0040, 0x3ca3, 0x1078, 0x40ea, 0x0040, + 0x3ca3, 0x1078, 0x41f5, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, + 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3cdb, 0x2011, 0x4129, + 0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3cd9, 0x2079, 0xa880, + 0x7a30, 0xa296, 0x1103, 0x00c0, 0x3cd9, 0x7834, 0xa005, 0x00c0, + 0x3cd9, 0x7a38, 0xd2fc, 0x0040, 0x3cd3, 0x70ac, 0xa005, 0x00c0, + 0x3cd3, 0x70af, 0x0001, 0x7087, 0x0006, 0x1078, 0x3cdd, 0x0078, + 0x3cdb, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0007, 0x1078, + 0x41c6, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, + 0x1078, 0x4211, 0x00c0, 0x3d05, 0x7070, 0xa005, 0x00c0, 0x3d05, + 0x7150, 0xa186, 0xffff, 0x0040, 0x3d05, 0xa180, 0x293f, 0x200c, + 0xa18c, 0xff00, 0x810f, 0x1078, 0x40ea, 0x0040, 0x3d05, 0x1078, + 0x378b, 0x0040, 0x3d05, 0x1078, 0x2500, 0x20a9, 0x0008, 0x2298, + 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3d3d, + 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3d3b, + 0x2079, 0xa880, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3d3b, 0x7834, + 0xa005, 0x00c0, 0x3d3b, 0x7a38, 0xd2fc, 0x0040, 0x3d35, 0x70ac, + 0xa005, 0x00c0, 0x3d35, 0x70af, 0x0001, 0x7087, 0x0008, 0x1078, + 0x3d3f, 0x0078, 0x3d3d, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, + 0x0009, 0x1078, 0x41c6, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, + 0x1078, 0x4211, 0x00c0, 0x3d58, 0x7070, 0xa005, 0x00c0, 0x3d58, + 0x1078, 0x4051, 0x00c0, 0x3d62, 0xa085, 0x0001, 0x1078, 0x2500, + 0x20a9, 0x0008, 0x2099, 0xa88e, 0x26a0, 0x53a6, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, + 0x707c, 0xa005, 0x0040, 0x3da8, 0x2011, 0x4129, 0x1078, 0x58d4, + 0xa086, 0x0014, 0x00c0, 0x3da6, 0x2079, 0xa880, 0x7a30, 0xa296, + 0x1105, 0x00c0, 0x3da6, 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, + 0x3d91, 0x7a38, 0xd2fc, 0x0040, 0x3d8b, 0x70ac, 0xa005, 0x00c0, + 0x3d8b, 0x70af, 0x0001, 0x7087, 0x000a, 0x1078, 0x3daa, 0x0078, + 0x3da8, 0xa005, 0x00c0, 0x3da6, 0x7a38, 0xd2fc, 0x0040, 0x3d9e, + 0x70ac, 0xa005, 0x00c0, 0x3d9e, 0x70af, 0x0001, 0x7083, 0x0000, + 0x7087, 0x000e, 0x1078, 0x3e32, 0x0078, 0x3da8, 0x1078, 0x4171, + 0x0f7f, 0x007c, 0x7087, 0x000b, 0x2011, 0xa80e, 0x22a0, 0x20a9, + 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000, + 0x41a4, 0x1078, 0x41c6, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x1078, + 0x4211, 0x0040, 0x3dc7, 0x2013, 0x0000, 0x0078, 0x3dcb, 0x6030, + 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, 0x60c3, + 0x0084, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, + 0x3df4, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0, + 0x3df2, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x3df2, + 0x7834, 0xa005, 0x00c0, 0x3df2, 0x7087, 0x000c, 0x1078, 0x3df6, + 0x0078, 0x3df4, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x000d, + 0x1078, 0x41c6, 0x20a3, 0x1107, 0x20a3, 0x0000, 0x2099, 0xa88e, + 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0084, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, + 0x3e30, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0, + 0x3e2e, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1107, 0x00c0, 0x3e2e, + 0x7834, 0xa005, 0x00c0, 0x3e2e, 0x7083, 0x0001, 0x1078, 0x41b8, + 0x7087, 0x000e, 0x1078, 0x3e32, 0x0078, 0x3e30, 0x1078, 0x4171, + 0x0f7f, 0x007c, 0x7087, 0x000f, 0x707f, 0x0000, 0x608b, 0xbc85, + 0x608f, 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, + 0x2011, 0x4129, 0x1078, 0x58c7, 0x007c, 0x707c, 0xa005, 0x0040, + 0x3e4d, 0x2011, 0x4129, 0x1078, 0x58d4, 0x007c, 0x7087, 0x0011, + 0x1078, 0x4211, 0x00c0, 0x3e67, 0x7168, 0x81ff, 0x0040, 0x3e67, + 0x2009, 0x0000, 0x706c, 0xa084, 0x00ff, 0x1078, 0x24e3, 0xa186, + 0x0080, 0x0040, 0x3e67, 0x2011, 0xa88e, 0x1078, 0x40ea, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, 0x747c, + 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, + 0x53a6, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, + 0xa005, 0x0040, 0x3ea8, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, + 0x0014, 0x00c0, 0x3ea6, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1103, + 0x00c0, 0x3ea6, 0x7834, 0xa005, 0x00c0, 0x3ea6, 0x7a38, 0xd2fc, + 0x0040, 0x3ea0, 0x70ac, 0xa005, 0x00c0, 0x3ea0, 0x70af, 0x0001, + 0x7087, 0x0012, 0x1078, 0x3eaa, 0x0078, 0x3ea8, 0x1078, 0x4171, + 0x0f7f, 0x007c, 0x7087, 0x0013, 0x1078, 0x41d2, 0x20a3, 0x1103, + 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, 0x1078, 0x4211, 0x00c0, + 0x3ec8, 0x7070, 0xa005, 0x00c0, 0x3ec8, 0x714c, 0xa186, 0xffff, + 0x0040, 0x3ec8, 0x1078, 0x40ea, 0x0040, 0x3ec8, 0x1078, 0x41f5, + 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, + 0xa005, 0x0040, 0x3f00, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, + 0x0014, 0x00c0, 0x3efe, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1104, + 0x00c0, 0x3efe, 0x7834, 0xa005, 0x00c0, 0x3efe, 0x7a38, 0xd2fc, + 0x0040, 0x3ef8, 0x70ac, 0xa005, 0x00c0, 0x3ef8, 0x70af, 0x0001, + 0x7087, 0x0014, 0x1078, 0x3f02, 0x0078, 0x3f00, 0x1078, 0x4171, + 0x0f7f, 0x007c, 0x7087, 0x0015, 0x1078, 0x41d2, 0x20a3, 0x1104, + 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, 0x1078, 0x4211, 0x00c0, + 0x3f2a, 0x7070, 0xa005, 0x00c0, 0x3f2a, 0x7150, 0xa186, 0xffff, + 0x0040, 0x3f2a, 0xa180, 0x293f, 0x200c, 0xa18c, 0xff00, 0x810f, + 0x1078, 0x40ea, 0x0040, 0x3f2a, 0x1078, 0x378b, 0x0040, 0x3f2a, + 0x1078, 0x2500, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, + 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3f7b, 0x2011, 0x4129, 0x1078, + 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3f79, 0x2079, 0xa880, 0x7a30, + 0xa296, 0x1105, 0x00c0, 0x3f79, 0x7834, 0x2011, 0x0100, 0xa21e, + 0x00c0, 0x3f5e, 0x7a38, 0xd2fc, 0x0040, 0x3f5c, 0x70ac, 0xa005, + 0x00c0, 0x3f5c, 0x70af, 0x0001, 0x0078, 0x3f6d, 0xa005, 0x00c0, + 0x3f79, 0x7a38, 0xd2fc, 0x0040, 0x3f6b, 0x70ac, 0xa005, 0x00c0, + 0x3f6b, 0x70af, 0x0001, 0x7083, 0x0000, 0x7a38, 0xd2f4, 0x0040, + 0x3f73, 0x70cb, 0x0008, 0x7087, 0x0016, 0x1078, 0x3f7d, 0x0078, + 0x3f7b, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6, + 0x3430, 0x2011, 0xa88e, 0x7087, 0x0017, 0x1078, 0x4211, 0x00c0, + 0x3f9d, 0x7070, 0xa005, 0x00c0, 0x3f9d, 0x1078, 0x4051, 0x00c0, + 0x3fa7, 0xa085, 0x0001, 0x1078, 0x2500, 0x20a9, 0x0008, 0x2099, + 0xa88e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, + 0x3fcc, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0, + 0x3fca, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x3fca, + 0x7834, 0xa005, 0x00c0, 0x3fca, 0x7087, 0x0018, 0x1078, 0x3fce, + 0x0078, 0x3fcc, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0019, + 0x1078, 0x41d2, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, + 0xa88e, 0x2039, 0xa80e, 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x1078, + 0x4211, 0x00c0, 0x4002, 0x2728, 0x2514, 0x8207, 0xa084, 0x00ff, + 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, 0x6030, + 0x2310, 0x8214, 0xa2a0, 0xa80e, 0x2414, 0xa38c, 0x0001, 0x0040, + 0x3ffd, 0xa294, 0xff00, 0x0078, 0x4000, 0xa294, 0x00ff, 0x8007, + 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x1078, 0x4158, 0x007c, + 0x0f7e, 0x707c, 0xa005, 0x0040, 0x4034, 0x2011, 0x4129, 0x1078, + 0x58d4, 0xa086, 0x0084, 0x00c0, 0x4032, 0x2079, 0xa880, 0x7a30, + 0xa296, 0x1107, 0x00c0, 0x4032, 0x7834, 0xa005, 0x00c0, 0x4032, + 0x7083, 0x0001, 0x1078, 0x41b8, 0x7087, 0x001a, 0x1078, 0x4036, + 0x0078, 0x4034, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x001b, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, + 0x747c, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, + 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x1078, 0x4158, 0x007c, 0x007c, + 0x007c, 0x087e, 0x097e, 0x2029, 0xa352, 0x252c, 0x20a9, 0x0008, + 0x2041, 0xa80e, 0x28a0, 0x2099, 0xa88e, 0x53a3, 0x20a9, 0x0008, + 0x2011, 0x0007, 0xd5d4, 0x0040, 0x4067, 0x2011, 0x0000, 0x2800, + 0xa200, 0x200c, 0xa1a6, 0xffff, 0x00c0, 0x4079, 0xd5d4, 0x0040, + 0x4074, 0x8210, 0x0078, 0x4075, 0x8211, 0x00f0, 0x4067, 0x0078, + 0x40e1, 0x82ff, 0x00c0, 0x408b, 0xd5d4, 0x0040, 0x4085, 0xa1a6, + 0x3fff, 0x0040, 0x4071, 0x0078, 0x4089, 0xa1a6, 0x3fff, 0x0040, + 0x40e1, 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4, + 0x0040, 0x4094, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0040, 0x409b, + 0x8423, 0x0078, 0x409c, 0x8424, 0x00c8, 0x40a9, 0xd5d4, 0x0040, + 0x40a4, 0x8319, 0x0078, 0x40a5, 0x8318, 0x00f0, 0x4095, 0x0078, + 0x40e1, 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x00f0, 0x40ad, + 0x2328, 0x8529, 0xa2be, 0x0007, 0x0040, 0x40c1, 0x007e, 0x2039, + 0x0007, 0x2200, 0xa73a, 0x007f, 0x27a8, 0xa5a8, 0x0010, 0x00f0, + 0x40bd, 0x754e, 0xa5c8, 0x293f, 0x292c, 0xa5ac, 0x00ff, 0x6532, + 0x60e7, 0x0000, 0x65ea, 0x706b, 0x0000, 0x756e, 0x2018, 0x2304, + 0xa405, 0x201a, 0x7073, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008, + 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0xa085, 0x0001, 0x0078, + 0x40e7, 0xa006, 0x0078, 0x40e7, 0xa006, 0x1078, 0x1328, 0x097f, + 0x087f, 0x007c, 0x2118, 0x2021, 0x0000, 0x2001, 0x0007, 0xa39a, + 0x0010, 0x0048, 0x40f7, 0x8420, 0x8001, 0x0078, 0x40ef, 0x2118, + 0x84ff, 0x0040, 0x4100, 0xa39a, 0x0010, 0x8421, 0x00c0, 0x40fb, + 0x2021, 0x0001, 0x83ff, 0x0040, 0x4109, 0x8423, 0x8319, 0x00c0, + 0x4105, 0xa238, 0x2704, 0xa42c, 0x00c0, 0x4121, 0xa405, 0x203a, + 0x714e, 0xa1a0, 0x293f, 0x242c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, + 0x0000, 0x65ea, 0x706b, 0x0000, 0x756e, 0x7073, 0x0001, 0xa084, + 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa300, 0x7077, 0x0000, 0x0e7f, + 0x007c, 0x0e7e, 0x0f7e, 0x2001, 0x0002, 0x1078, 0x5975, 0x2079, + 0x0100, 0x2071, 0x0140, 0x1078, 0x6c41, 0x7004, 0xa084, 0x4000, + 0x0040, 0x413e, 0x7003, 0x1000, 0x7003, 0x0000, 0x127e, 0x2091, + 0x8000, 0x2071, 0xa321, 0x2073, 0x0000, 0x7840, 0x027e, 0x017e, + 0x2009, 0x00f7, 0x1078, 0x41de, 0x017f, 0xa094, 0x0010, 0xa285, + 0x0080, 0x7842, 0x7a42, 0x027f, 0x127f, 0x0f7f, 0x0e7f, 0x007c, + 0x127e, 0x2091, 0x8000, 0x2011, 0xa5b5, 0x2013, 0x0000, 0x707f, + 0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, + 0x1078, 0x6c38, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c, + 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x2009, + 0x00f7, 0x1078, 0x41de, 0x2061, 0xa5be, 0x601b, 0x0000, 0x601f, + 0x0000, 0x2061, 0xa300, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, + 0x0090, 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4196, 0x1078, + 0x58c7, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, 0x0e7e, 0x007e, + 0x127e, 0x2091, 0x8000, 0x2001, 0x0001, 0x1078, 0x5975, 0x2071, + 0x0100, 0x1078, 0x6c41, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, + 0x0040, 0x41ae, 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, + 0x1078, 0x2480, 0x1078, 0x4171, 0x127f, 0x007f, 0x0e7f, 0x007c, + 0x20a9, 0x0040, 0x20a1, 0xa9c0, 0x2099, 0xa88e, 0x3304, 0x8007, + 0x20a2, 0x9398, 0x94a0, 0x00f0, 0x41be, 0x007c, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0xa800, 0x20a1, 0x020b, 0x20a9, 0x000c, + 0x53a6, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, + 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x0c7e, 0x007e, + 0x2061, 0x0100, 0x810f, 0x2001, 0xa32e, 0x2004, 0xa005, 0x00c0, + 0x41ef, 0x6030, 0xa084, 0x00ff, 0xa105, 0x0078, 0x41f1, 0xa185, + 0x00f7, 0x604a, 0x007f, 0x0c7f, 0x007c, 0x017e, 0x047e, 0x2001, + 0xa352, 0x2004, 0xd0a4, 0x0040, 0x4208, 0xa006, 0x2020, 0x2009, + 0x002a, 0x1078, 0x9ec0, 0x2001, 0xa30c, 0x200c, 0xc195, 0x2102, + 0x2019, 0x002a, 0x2009, 0x0000, 0x1078, 0x27e2, 0x047f, 0x017f, + 0x007c, 0x007e, 0x2001, 0xa30c, 0x2004, 0xd09c, 0x0040, 0x4218, + 0x007f, 0x007c, 0x007e, 0x017e, 0x127e, 0x2091, 0x8000, 0x2001, + 0x0101, 0x200c, 0xa18d, 0x0006, 0x2102, 0x127f, 0x017f, 0x007f, + 0x007c, 0x157e, 0x20a9, 0x00ff, 0x2009, 0xa434, 0xa006, 0x200a, + 0x8108, 0x00f0, 0x422f, 0x157f, 0x007c, 0x0d7e, 0x037e, 0x157e, + 0x137e, 0x147e, 0x2069, 0xa351, 0xa006, 0x6002, 0x6007, 0x0707, + 0x600a, 0x600e, 0x6012, 0xa198, 0x293f, 0x231c, 0xa39c, 0x00ff, + 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, + 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, + 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, 0x6066, 0x606a, 0x606e, + 0x6072, 0x6076, 0x607a, 0x607e, 0x6082, 0x6086, 0x608a, 0x608e, + 0x6092, 0x6096, 0x609a, 0x609e, 0x60ae, 0x61a2, 0x0d7e, 0x60a4, + 0xa06d, 0x0040, 0x4275, 0x1078, 0x139a, 0x60a7, 0x0000, 0x60a8, + 0xa06d, 0x0040, 0x427d, 0x1078, 0x139a, 0x60ab, 0x0000, 0x0d7f, + 0xa006, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0x6814, 0xa084, + 0x00ff, 0x6042, 0x147f, 0x137f, 0x157f, 0x037f, 0x0d7f, 0x007c, + 0x127e, 0x2091, 0x8000, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, + 0x4000, 0x00c8, 0x4361, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, + 0x00c8, 0x4367, 0x2001, 0xa30c, 0x2004, 0xa084, 0x0003, 0x0040, + 0x42c2, 0x2001, 0xa30c, 0x2004, 0xd084, 0x00c0, 0x4342, 0xa188, + 0xa434, 0x2104, 0xa065, 0x0040, 0x4342, 0x6004, 0xa084, 0x00ff, + 0xa08e, 0x0006, 0x00c0, 0x4342, 0x6000, 0xd0c4, 0x0040, 0x4342, + 0x0078, 0x42cf, 0xa188, 0xa434, 0x2104, 0xa065, 0x0040, 0x4326, + 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x432c, 0x60a4, + 0xa00d, 0x0040, 0x42d7, 0x1078, 0x4749, 0x0040, 0x4320, 0x60a8, + 0xa00d, 0x0040, 0x42f1, 0x1078, 0x479a, 0x00c0, 0x42f1, 0x694c, + 0xd1fc, 0x00c0, 0x42e7, 0x1078, 0x441c, 0x0078, 0x431b, 0x1078, + 0x43d6, 0x694c, 0xd1ec, 0x00c0, 0x431b, 0x1078, 0x460a, 0x0078, + 0x431b, 0x694c, 0xa184, 0xa000, 0x0040, 0x430b, 0xd1ec, 0x0040, + 0x4304, 0xd1fc, 0x0040, 0x4300, 0x1078, 0x461b, 0x0078, 0x4307, + 0x1078, 0x461b, 0x0078, 0x430b, 0xd1fc, 0x0040, 0x430b, 0x1078, + 0x43d6, 0x0078, 0x431b, 0x6050, 0xa00d, 0x0040, 0x4316, 0x2d00, + 0x200a, 0x6803, 0x0000, 0x6052, 0x0078, 0x431b, 0x2d00, 0x6052, + 0x604e, 0x6803, 0x0000, 0x1078, 0x5c17, 0xa006, 0x127f, 0x007c, + 0x2001, 0x0005, 0x2009, 0x0000, 0x0078, 0x436b, 0x2001, 0x0028, + 0x2009, 0x0000, 0x0078, 0x436b, 0xa082, 0x0006, 0x00c8, 0x4342, + 0x60a0, 0xd0bc, 0x00c0, 0x433e, 0x6100, 0xd1fc, 0x0040, 0x42cf, + 0x2001, 0x0029, 0x2009, 0x1000, 0x0078, 0x436b, 0x2001, 0x0028, + 0x0078, 0x435d, 0x2009, 0xa30c, 0x210c, 0xd18c, 0x0040, 0x434c, + 0x2001, 0x0004, 0x0078, 0x435d, 0xd184, 0x0040, 0x4353, 0x2001, + 0x0004, 0x0078, 0x435d, 0x2001, 0x0029, 0x6100, 0xd1fc, 0x0040, + 0x435d, 0x2009, 0x1000, 0x0078, 0x436b, 0x2009, 0x0000, 0x0078, + 0x436b, 0x2001, 0x0029, 0x2009, 0x0000, 0x0078, 0x436b, 0x2001, + 0x0029, 0x2009, 0x0000, 0xa005, 0x127f, 0x007c, 0x6944, 0x6e48, + 0xa684, 0x3fff, 0xa082, 0x4000, 0x00c8, 0x43bb, 0xa18c, 0xff00, + 0x810f, 0xa182, 0x00ff, 0x00c8, 0x43a1, 0xa188, 0xa434, 0x2104, + 0xa065, 0x0040, 0x43a1, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, + 0x00c0, 0x43a7, 0x684c, 0xd0ec, 0x0040, 0x4394, 0x1078, 0x461b, + 0x1078, 0x43d6, 0x0078, 0x439c, 0x1078, 0x43d6, 0x684c, 0xd0fc, + 0x0040, 0x439c, 0x1078, 0x460a, 0x1078, 0x4663, 0xa006, 0x0078, + 0x43bf, 0x2001, 0x0028, 0x2009, 0x0000, 0x0078, 0x43bf, 0xa082, + 0x0006, 0x00c8, 0x43b5, 0x6100, 0xd1fc, 0x0040, 0x438a, 0x2001, + 0x0029, 0x2009, 0x1000, 0x0078, 0x43bf, 0x2001, 0x0029, 0x2009, + 0x0000, 0x0078, 0x43bf, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, + 0x007c, 0x127e, 0x2091, 0x8000, 0x6050, 0xa00d, 0x0040, 0x43cf, + 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x127f, 0x007c, 0x2d00, + 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x43cd, 0x127e, 0x2091, + 0x8000, 0x604c, 0xa005, 0x0040, 0x43ec, 0x0e7e, 0x2071, 0xa5ab, + 0x7004, 0xa086, 0x0002, 0x0040, 0x43f3, 0x0e7f, 0x604c, 0x6802, + 0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803, + 0x0000, 0x0078, 0x43ea, 0x701c, 0xac06, 0x00c0, 0x43e5, 0x604c, + 0x2070, 0x7000, 0x6802, 0x2d00, 0x7002, 0x0e7f, 0x127f, 0x007c, + 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0040, 0x440e, 0x6800, + 0xa005, 0x00c0, 0x440c, 0x6052, 0x604e, 0xad05, 0x127f, 0x007c, + 0x604c, 0xa06d, 0x0040, 0x441b, 0x6800, 0xa005, 0x00c0, 0x4419, + 0x6052, 0x604e, 0xad05, 0x007c, 0x6803, 0x0000, 0x6084, 0xa00d, + 0x0040, 0x4426, 0x2d00, 0x200a, 0x6086, 0x007c, 0x2d00, 0x6086, + 0x6082, 0x0078, 0x4425, 0x127e, 0x0c7e, 0x027e, 0x2091, 0x8000, + 0x6218, 0x2260, 0x6200, 0xa005, 0x0040, 0x4439, 0xc285, 0x0078, + 0x443a, 0xc284, 0x6202, 0x027f, 0x0c7f, 0x127f, 0x007c, 0x127e, + 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0x007e, 0xa086, + 0x0006, 0x00c0, 0x445e, 0x609c, 0xd0ac, 0x0040, 0x445e, 0x2001, + 0xa352, 0x2004, 0xd0a4, 0x0040, 0x445e, 0xa284, 0xff00, 0x8007, + 0xa086, 0x0007, 0x00c0, 0x445e, 0x2011, 0x0600, 0x007f, 0xa294, + 0xff00, 0xa215, 0x6206, 0x007e, 0xa086, 0x0006, 0x00c0, 0x446e, + 0x6290, 0x82ff, 0x00c0, 0x446e, 0x1078, 0x1328, 0x007f, 0x0c7f, + 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, + 0x6204, 0x007e, 0xa086, 0x0006, 0x00c0, 0x4490, 0x609c, 0xd0a4, + 0x0040, 0x4490, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x4490, + 0xa284, 0x00ff, 0xa086, 0x0007, 0x00c0, 0x4490, 0x2011, 0x0006, + 0x007f, 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x0c7f, 0x127f, + 0x007c, 0x027e, 0xa182, 0x00ff, 0x0048, 0x44a2, 0xa085, 0x0001, + 0x0078, 0x44ba, 0xa190, 0xa434, 0x2204, 0xa065, 0x00c0, 0x44b9, + 0x017e, 0x0d7e, 0x1078, 0x1366, 0x2d60, 0x0d7f, 0x017f, 0x0040, + 0x449e, 0x2c00, 0x2012, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x1078, + 0x4235, 0xa006, 0x027f, 0x007c, 0x127e, 0x2091, 0x8000, 0x027e, + 0xa182, 0x00ff, 0x0048, 0x44c8, 0xa085, 0x0001, 0x0078, 0x44fe, + 0x0d7e, 0xa190, 0xa434, 0x2204, 0xa06d, 0x0040, 0x44fc, 0x2013, + 0x0000, 0x0d7e, 0x0c7e, 0x2d60, 0x60a4, 0xa06d, 0x0040, 0x44da, + 0x1078, 0x139a, 0x60a8, 0xa06d, 0x0040, 0x44e0, 0x1078, 0x139a, + 0x0c7f, 0x0d7f, 0x0d7e, 0x0c7e, 0x68ac, 0x2060, 0x8cff, 0x0040, + 0x44f8, 0x600c, 0x007e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, + 0x44f3, 0x1078, 0x13aa, 0x1078, 0x753d, 0x0c7f, 0x0078, 0x44e6, + 0x0c7f, 0x0d7f, 0x1078, 0x139a, 0x0d7f, 0xa006, 0x027f, 0x127f, + 0x007c, 0x017e, 0xa182, 0x00ff, 0x0048, 0x450a, 0xa085, 0x0001, + 0x0078, 0x4511, 0xa188, 0xa434, 0x2104, 0xa065, 0x0040, 0x4506, + 0xa006, 0x017f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x600b, + 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x2069, 0xa88e, + 0x6808, 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a, 0x0048, 0x4529, + 0x603a, 0x6814, 0x6066, 0x2099, 0xa896, 0xac88, 0x000a, 0x21a0, + 0x20a9, 0x0004, 0x53a3, 0x2099, 0xa89a, 0xac88, 0x0006, 0x21a0, + 0x20a9, 0x0004, 0x53a3, 0x2069, 0xa8ae, 0x6808, 0x606a, 0x690c, + 0x616e, 0x6810, 0x6072, 0x6818, 0x6076, 0xa182, 0x0211, 0x00c8, + 0x454d, 0x2009, 0x0008, 0x0078, 0x4577, 0xa182, 0x0259, 0x00c8, + 0x4555, 0x2009, 0x0007, 0x0078, 0x4577, 0xa182, 0x02c1, 0x00c8, + 0x455d, 0x2009, 0x0006, 0x0078, 0x4577, 0xa182, 0x0349, 0x00c8, + 0x4565, 0x2009, 0x0005, 0x0078, 0x4577, 0xa182, 0x0421, 0x00c8, + 0x456d, 0x2009, 0x0004, 0x0078, 0x4577, 0xa182, 0x0581, 0x00c8, + 0x4575, 0x2009, 0x0003, 0x0078, 0x4577, 0x2009, 0x0002, 0x6192, + 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x017e, 0x027e, 0x0e7e, + 0x2071, 0xa88d, 0x2e04, 0x6896, 0x2071, 0xa88e, 0x7004, 0x689a, + 0x701c, 0x689e, 0x6a00, 0x2009, 0xa371, 0x210c, 0xd0bc, 0x0040, + 0x4597, 0xd1ec, 0x0040, 0x4597, 0xc2ad, 0x0078, 0x4598, 0xc2ac, + 0xd0c4, 0x0040, 0x45a1, 0xd1e4, 0x0040, 0x45a1, 0xc2bd, 0x0078, + 0x45a2, 0xc2bc, 0x6a02, 0x0e7f, 0x027f, 0x017f, 0x007c, 0x0d7e, + 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x0040, 0x45cb, 0x6900, + 0x81ff, 0x00c0, 0x45df, 0x6a04, 0xa282, 0x0010, 0x00c8, 0x45e4, + 0xad88, 0x0004, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0040, + 0x45c6, 0x8108, 0x00f0, 0x45bc, 0x1078, 0x1328, 0x260a, 0x8210, + 0x6a06, 0x0078, 0x45df, 0x1078, 0x1381, 0x0040, 0x45e4, 0x2d00, + 0x60a6, 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, + 0xffff, 0x8108, 0x00f0, 0x45d7, 0x6807, 0x0001, 0x6e12, 0xa085, + 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, 0x0078, 0x45e1, 0x127e, + 0x2091, 0x8000, 0x0d7e, 0x60a4, 0xa00d, 0x0040, 0x4607, 0x2168, + 0x6800, 0xa005, 0x00c0, 0x4603, 0x1078, 0x4749, 0x00c0, 0x4607, + 0x200b, 0xffff, 0x6804, 0xa08a, 0x0002, 0x0048, 0x4603, 0x8001, + 0x6806, 0x0078, 0x4607, 0x1078, 0x139a, 0x60a7, 0x0000, 0x0d7f, + 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x47af, 0x0078, + 0x4613, 0x1078, 0x43c1, 0x1078, 0x46a7, 0x00c0, 0x4611, 0x1078, + 0x4663, 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a8, + 0xa06d, 0x0040, 0x463f, 0x6950, 0x81ff, 0x00c0, 0x4653, 0x6a54, + 0xa282, 0x0010, 0x00c8, 0x4660, 0xad88, 0x0018, 0x20a9, 0x0010, + 0x2104, 0xa086, 0xffff, 0x0040, 0x463a, 0x8108, 0x00f0, 0x4630, + 0x1078, 0x1328, 0x260a, 0x8210, 0x6a56, 0x0078, 0x4653, 0x1078, + 0x1381, 0x0040, 0x4660, 0x2d00, 0x60aa, 0x6853, 0x0000, 0xad88, + 0x0018, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x00f0, 0x464b, + 0x6857, 0x0001, 0x6e62, 0x0078, 0x4657, 0x1078, 0x441c, 0x1078, + 0x466d, 0x00c0, 0x4655, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, + 0xa006, 0x0078, 0x465d, 0x127e, 0x2091, 0x8000, 0x1078, 0x5c17, + 0x127f, 0x007c, 0xa01e, 0x0078, 0x466f, 0x2019, 0x0001, 0xa00e, + 0x127e, 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0, + 0x468d, 0x8dff, 0x0040, 0x46a2, 0x83ff, 0x0040, 0x4685, 0x6848, + 0xa606, 0x0040, 0x4692, 0x0078, 0x468d, 0x683c, 0xa406, 0x00c0, + 0x468d, 0x6840, 0xa506, 0x0040, 0x4692, 0x2d08, 0x6800, 0x2068, + 0x0078, 0x4679, 0x6a00, 0x604c, 0xad06, 0x00c0, 0x469a, 0x624e, + 0x0078, 0x469d, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x46a2, + 0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, 0x46a9, 0x2019, + 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, 0x46d5, 0x83ff, + 0x0040, 0x46b8, 0x6848, 0xa606, 0x0040, 0x46c5, 0x0078, 0x46c0, + 0x683c, 0xa406, 0x00c0, 0x46c0, 0x6840, 0xa506, 0x0040, 0x46c5, + 0x2d08, 0x6800, 0x2068, 0x0078, 0x46ac, 0x6a00, 0x6080, 0xad06, + 0x00c0, 0x46cd, 0x6282, 0x0078, 0x46d0, 0xa180, 0x0000, 0x2202, + 0x82ff, 0x00c0, 0x46d5, 0x6186, 0x8dff, 0x007c, 0xa016, 0x1078, + 0x4742, 0x00c0, 0x46dd, 0x2011, 0x0001, 0x1078, 0x4793, 0x00c0, + 0x46e3, 0xa295, 0x0002, 0x007c, 0x1078, 0x47cb, 0x0040, 0x46ec, + 0x1078, 0x8b12, 0x0078, 0x46ee, 0xa085, 0x0001, 0x007c, 0x1078, + 0x47cb, 0x0040, 0x46f7, 0x1078, 0x8aaa, 0x0078, 0x46f9, 0xa085, + 0x0001, 0x007c, 0x1078, 0x47cb, 0x0040, 0x4702, 0x1078, 0x8af4, + 0x0078, 0x4704, 0xa085, 0x0001, 0x007c, 0x1078, 0x47cb, 0x0040, + 0x470d, 0x1078, 0x8ac6, 0x0078, 0x470f, 0xa085, 0x0001, 0x007c, + 0x1078, 0x47cb, 0x0040, 0x4718, 0x1078, 0x8b30, 0x0078, 0x471a, + 0xa085, 0x0001, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x8000, + 0x6080, 0xa06d, 0x0040, 0x473a, 0x6800, 0x007e, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x007e, 0x6000, 0xd0fc, + 0x0040, 0x4734, 0x1078, 0xa18c, 0x007f, 0x1078, 0x4982, 0x007f, + 0x0078, 0x4721, 0x6083, 0x0000, 0x6087, 0x0000, 0x0d7f, 0x007f, + 0x127f, 0x007c, 0x60a4, 0xa00d, 0x00c0, 0x4749, 0xa085, 0x0001, + 0x007c, 0x0e7e, 0x2170, 0x7000, 0xa005, 0x00c0, 0x475c, 0x20a9, + 0x0010, 0xae88, 0x0004, 0x2104, 0xa606, 0x0040, 0x475c, 0x8108, + 0x00f0, 0x4753, 0xa085, 0x0001, 0xa006, 0x0e7f, 0x007c, 0x0d7e, + 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x00c0, 0x476d, 0x1078, + 0x1381, 0x0040, 0x477f, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807, + 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, + 0x00f0, 0x4775, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, + 0x0078, 0x477c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, + 0x0040, 0x4790, 0x60a7, 0x0000, 0x1078, 0x139a, 0xa085, 0x0001, + 0x127f, 0x0d7f, 0x007c, 0x60a8, 0xa00d, 0x00c0, 0x479a, 0xa085, + 0x0001, 0x007c, 0x0e7e, 0x2170, 0x7050, 0xa005, 0x00c0, 0x47ad, + 0x20a9, 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0040, 0x47ad, + 0x8108, 0x00f0, 0x47a4, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x127e, + 0x2091, 0x8000, 0x1078, 0x4793, 0x00c0, 0x47c9, 0x200b, 0xffff, + 0x0d7e, 0x60a8, 0x2068, 0x6854, 0xa08a, 0x0002, 0x0048, 0x47c4, + 0x8001, 0x6856, 0x0078, 0x47c8, 0x1078, 0x139a, 0x60ab, 0x0000, + 0x0d7f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, 0x0f7e, 0x71ac, + 0x81ff, 0x00c0, 0x47e9, 0x71c8, 0xd19c, 0x0040, 0x47e9, 0x2001, + 0x007e, 0xa080, 0xa434, 0x2004, 0xa07d, 0x0040, 0x47e9, 0x7804, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x47e9, 0x7800, 0xc0ed, + 0x7802, 0x2079, 0xa351, 0x7804, 0xd0a4, 0x0040, 0x480f, 0x157e, + 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, + 0x00c0, 0x4809, 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004, + 0x0040, 0x4806, 0xa086, 0x0006, 0x00c0, 0x4809, 0x6000, 0xc0ed, + 0x6002, 0x017f, 0x8108, 0x00f0, 0x47f5, 0x0c7f, 0x157f, 0x1078, + 0x4897, 0x0040, 0x4818, 0x2001, 0xa59f, 0x200c, 0x0078, 0x4820, + 0x2079, 0xa351, 0x7804, 0xd0a4, 0x0040, 0x4824, 0x2009, 0x07d0, + 0x2011, 0x4826, 0x1078, 0x596c, 0x0f7f, 0x007c, 0x2011, 0x4826, + 0x1078, 0x58d4, 0x1078, 0x4897, 0x0040, 0x484e, 0x2001, 0xa4b2, + 0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xa352, + 0x2004, 0xd0a4, 0x0040, 0x4842, 0x2009, 0x07d0, 0x2011, 0x4826, + 0x1078, 0x596c, 0x0e7e, 0x2071, 0xa300, 0x706b, 0x0000, 0x706f, + 0x0000, 0x1078, 0x260d, 0x0e7f, 0x0078, 0x4886, 0x157e, 0x0c7e, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, + 0x4880, 0x6000, 0xd0ec, 0x0040, 0x4880, 0x047e, 0x62a0, 0xa294, + 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x9ec0, 0x6000, + 0xc0e5, 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700, + 0x6006, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, + 0x1078, 0x5c78, 0x2009, 0x0000, 0x1078, 0x9c38, 0x077f, 0x047f, + 0x017f, 0x8108, 0x00f0, 0x4854, 0x0c7f, 0x157f, 0x007c, 0x0c7e, + 0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x7818, + 0x2004, 0xd0ac, 0x007c, 0x7818, 0x2004, 0xd0bc, 0x007c, 0x0f7e, + 0x2001, 0xa4b2, 0x2004, 0xa07d, 0x0040, 0x48a0, 0x7800, 0xd0ec, + 0x0f7f, 0x007c, 0x127e, 0x027e, 0x2091, 0x8000, 0x6200, 0xa005, + 0x0040, 0x48ad, 0xc2fd, 0x0078, 0x48ae, 0xc2fc, 0x6202, 0x027f, + 0x127f, 0x007c, 0x2071, 0xa413, 0x7003, 0x0001, 0x7007, 0x0000, + 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, + 0x700b, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020, + 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, 0xa57c, 0x7003, 0xa413, + 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, 0xa55c, 0x7013, 0x0020, + 0x7017, 0x0040, 0x7037, 0x0000, 0x007c, 0x017e, 0x0e7e, 0x2071, + 0xa534, 0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001, 0xa352, + 0x2004, 0xd0fc, 0x00c0, 0x48f7, 0x2001, 0xa352, 0x2004, 0xa00e, + 0xd09c, 0x0040, 0x48f4, 0x8108, 0x7102, 0x0078, 0x494a, 0x2001, + 0xa371, 0x200c, 0xa184, 0x000f, 0x2009, 0xa372, 0x210c, 0x0079, + 0x4901, 0x48ec, 0x4922, 0x492a, 0x4935, 0x493b, 0x48ec, 0x48ec, + 0x48ec, 0x4911, 0x48ec, 0x48ec, 0x48ec, 0x48ec, 0x48ec, 0x48ec, + 0x48ec, 0x7003, 0x0004, 0x137e, 0x147e, 0x157e, 0x2099, 0xa375, + 0x20a1, 0xa585, 0x20a9, 0x0004, 0x53a3, 0x157f, 0x147f, 0x137f, + 0x0078, 0x494a, 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, 0x0002, + 0x0078, 0x4930, 0x708f, 0x0002, 0x7007, 0x0121, 0x2001, 0x0003, + 0x7002, 0x7097, 0x0001, 0x0078, 0x4947, 0x7007, 0x0122, 0x2001, + 0x0002, 0x0078, 0x493f, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002, + 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a, 0xa184, + 0x00ff, 0x7092, 0x0e7f, 0x017f, 0x007c, 0x0e7e, 0x2071, 0xa413, + 0x684c, 0xa005, 0x00c0, 0x495b, 0x7028, 0xc085, 0x702a, 0xa085, + 0x0001, 0x0078, 0x4980, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868, + 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844, + 0x7032, 0x2009, 0x000d, 0x200a, 0x700b, 0x0000, 0x8007, 0x8006, + 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, + 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, + 0x0e7f, 0x007c, 0x0e7e, 0x027e, 0x6838, 0xd0fc, 0x00c0, 0x49d8, + 0x6804, 0xa00d, 0x0040, 0x499e, 0x0d7e, 0x2071, 0xa300, 0xa016, + 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x00c0, + 0x4991, 0x702e, 0x70a8, 0xa200, 0x70aa, 0x0d7f, 0x2071, 0xa413, + 0x701c, 0xa005, 0x00c0, 0x49ea, 0x0068, 0x49e8, 0x2071, 0xa534, + 0x7200, 0x82ff, 0x0040, 0x49e8, 0x6934, 0xa186, 0x0103, 0x00c0, + 0x49fb, 0x6948, 0x6844, 0xa105, 0x00c0, 0x49db, 0x2009, 0x8020, + 0x2200, 0x0079, 0x49bb, 0x49e8, 0x49c0, 0x4a18, 0x4a26, 0x49e8, + 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x49e8, 0x7122, 0x683c, + 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x2071, + 0xa300, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a8, 0x8000, 0x70aa, + 0x027f, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, 0x00c0, 0x49e8, + 0x6868, 0xa005, 0x00c0, 0x49e8, 0x2009, 0x8020, 0x0078, 0x49b8, + 0x2071, 0xa413, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012, + 0x7018, 0xa06d, 0x711a, 0x0040, 0x49f8, 0x6902, 0x0078, 0x49f9, + 0x711e, 0x0078, 0x49d8, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0040, + 0x4a09, 0xa186, 0x001e, 0x0040, 0x4a09, 0xa18e, 0x001f, 0x00c0, + 0x49e8, 0x684c, 0xd0cc, 0x0040, 0x49e8, 0x6850, 0xa084, 0x00ff, + 0xa086, 0x0001, 0x00c0, 0x49e8, 0x2009, 0x8021, 0x0078, 0x49b8, + 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x49e8, 0x7186, 0xae90, + 0x0003, 0xa210, 0x683c, 0x2012, 0x0078, 0x4a36, 0x7084, 0x8008, + 0xa092, 0x000f, 0x00c8, 0x49e8, 0x7186, 0xae90, 0x0003, 0x8003, + 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a, + 0x0048, 0x49cf, 0x718c, 0x7084, 0xa10a, 0x0048, 0x49cf, 0x2071, + 0x0000, 0x7018, 0xd084, 0x00c0, 0x49cf, 0x2071, 0xa534, 0x7000, + 0xa086, 0x0002, 0x00c0, 0x4a56, 0x1078, 0x4cd2, 0x2071, 0x0000, + 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x49cf, 0x1078, 0x4cfd, + 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x49cf, + 0x007e, 0x684c, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, + 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x007f, 0xa084, 0x00ff, + 0x684e, 0x007f, 0x684a, 0x6952, 0x007c, 0x2071, 0xa413, 0x7004, + 0x0079, 0x4a7a, 0x4a84, 0x4a95, 0x4ca3, 0x4ca4, 0x4ccb, 0x4cd1, + 0x4a85, 0x4c91, 0x4c32, 0x4cb4, 0x007c, 0x127e, 0x2091, 0x8000, + 0x0068, 0x4a94, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, + 0x7007, 0x0001, 0x700b, 0x0000, 0x127f, 0x2069, 0xa5be, 0x6844, + 0xa005, 0x0050, 0x4abd, 0x00c0, 0x4abd, 0x127e, 0x2091, 0x8000, + 0x2069, 0x0000, 0x6934, 0x2001, 0xa41f, 0x2004, 0xa10a, 0x0040, + 0x4ab8, 0x0068, 0x4abc, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, + 0x4abc, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, + 0x2069, 0xa5be, 0x6847, 0xffff, 0x127f, 0x2069, 0xa300, 0x6844, + 0x6960, 0xa102, 0x2069, 0xa534, 0x688a, 0x6984, 0x701c, 0xa06d, + 0x0040, 0x4acf, 0x81ff, 0x0040, 0x4b17, 0x0078, 0x4ae5, 0x81ff, + 0x0040, 0x4be9, 0x2071, 0xa534, 0x7184, 0x7088, 0xa10a, 0x00c8, + 0x4ae5, 0x7190, 0x2071, 0xa5be, 0x7040, 0xa005, 0x0040, 0x4ae5, + 0x00d0, 0x4be9, 0x7142, 0x0078, 0x4be9, 0x2071, 0xa534, 0x718c, + 0x127e, 0x2091, 0x8000, 0x7084, 0xa10a, 0x0048, 0x4c06, 0x0068, + 0x4b9b, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4b9b, 0x2001, + 0xffff, 0x2071, 0xa5be, 0x7042, 0x2071, 0xa534, 0x7000, 0xa086, + 0x0002, 0x00c0, 0x4b0d, 0x1078, 0x4cd2, 0x2071, 0x0000, 0x701b, + 0x0001, 0x2091, 0x4080, 0x0078, 0x4b9b, 0x1078, 0x4cfd, 0x2071, + 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4b9b, 0x2071, + 0xa534, 0x7000, 0xa005, 0x0040, 0x4bc8, 0x6934, 0xa186, 0x0103, + 0x00c0, 0x4b9e, 0x684c, 0xd0bc, 0x00c0, 0x4bc8, 0x6948, 0x6844, + 0xa105, 0x00c0, 0x4bbb, 0x2009, 0x8020, 0x2071, 0xa534, 0x7000, + 0x0079, 0x4b32, 0x4bc8, 0x4b80, 0x4b58, 0x4b6a, 0x4b37, 0x137e, + 0x147e, 0x157e, 0x2099, 0xa375, 0x20a1, 0xa585, 0x20a9, 0x0004, + 0x53a3, 0x157f, 0x147f, 0x137f, 0x2071, 0xa57c, 0xad80, 0x000f, + 0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, 0x2e10, + 0x1078, 0x13d1, 0x2071, 0xa413, 0x7007, 0x0009, 0x0078, 0x4be9, + 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x4be9, 0xae90, 0x0003, + 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xa413, 0x1078, 0x4d5b, + 0x0078, 0x4be9, 0x7084, 0x8008, 0xa092, 0x000f, 0x00c8, 0x4be9, + 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, + 0x2012, 0x7186, 0x2071, 0xa413, 0x1078, 0x4d5b, 0x0078, 0x4be9, + 0x127e, 0x2091, 0x8000, 0x0068, 0x4b9b, 0x2071, 0x0000, 0x7018, + 0xd084, 0x00c0, 0x4b9b, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, + 0x701b, 0x0001, 0x2091, 0x4080, 0x127f, 0x2071, 0xa413, 0x1078, + 0x4d5b, 0x0078, 0x4be9, 0x127f, 0x0078, 0x4be9, 0xa18c, 0x00ff, + 0xa186, 0x0017, 0x0040, 0x4bac, 0xa186, 0x001e, 0x0040, 0x4bac, + 0xa18e, 0x001f, 0x00c0, 0x4bc8, 0x684c, 0xd0cc, 0x0040, 0x4bc8, + 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x4bc8, 0x2009, + 0x8021, 0x0078, 0x4b2d, 0x6844, 0xa086, 0x0100, 0x00c0, 0x4bc8, + 0x6868, 0xa005, 0x00c0, 0x4bc8, 0x2009, 0x8020, 0x0078, 0x4b2d, + 0x2071, 0xa413, 0x1078, 0x4d6f, 0x0040, 0x4be9, 0x2071, 0xa413, + 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x00c0, + 0x4be0, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x4be0, 0x710e, + 0x7007, 0x0003, 0x1078, 0x4d8f, 0x7050, 0xa086, 0x0100, 0x0040, + 0x4ca4, 0x127e, 0x2091, 0x8000, 0x2071, 0xa413, 0x7008, 0xa086, + 0x0001, 0x00c0, 0x4c04, 0x0068, 0x4c04, 0x2009, 0x000d, 0x7030, + 0x200a, 0x2091, 0x4080, 0x700b, 0x0000, 0x7004, 0xa086, 0x0006, + 0x00c0, 0x4c04, 0x7007, 0x0001, 0x127f, 0x007c, 0x2071, 0xa413, + 0x1078, 0x4d6f, 0x0040, 0x4c2f, 0x2071, 0xa534, 0x7084, 0x700a, + 0x20a9, 0x0020, 0x2099, 0xa535, 0x20a1, 0xa55c, 0x53a3, 0x7087, + 0x0000, 0x2071, 0xa413, 0x2069, 0xa57c, 0x706c, 0x6826, 0x7070, + 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, 0x1078, 0x13d1, + 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0xa5be, 0x7042, 0x127f, + 0x0078, 0x4be9, 0x2069, 0xa57c, 0x6808, 0xa08e, 0x0000, 0x0040, + 0x4c90, 0xa08e, 0x0200, 0x0040, 0x4c8e, 0xa08e, 0x0100, 0x00c0, + 0x4c90, 0x127e, 0x2091, 0x8000, 0x0068, 0x4c8b, 0x2069, 0x0000, + 0x6818, 0xd084, 0x00c0, 0x4c8b, 0x702c, 0x7130, 0x8108, 0xa102, + 0x0048, 0x4c59, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0078, + 0x4c63, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4c63, 0x7070, + 0xa081, 0x0000, 0x7072, 0x7132, 0x6936, 0x700b, 0x0000, 0x2001, + 0xa559, 0x2004, 0xa005, 0x00c0, 0x4c82, 0x6934, 0x2069, 0xa534, + 0x689c, 0x699e, 0x2069, 0xa5be, 0xa102, 0x00c0, 0x4c7b, 0x6844, + 0xa005, 0x00d0, 0x4c89, 0x2001, 0xa55a, 0x200c, 0x810d, 0x6946, + 0x0078, 0x4c89, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, + 0x4080, 0x7007, 0x0001, 0x127f, 0x0078, 0x4c90, 0x7007, 0x0005, + 0x007c, 0x701c, 0xa06d, 0x0040, 0x4ca2, 0x1078, 0x4d6f, 0x0040, + 0x4ca2, 0x7007, 0x0003, 0x1078, 0x4d8f, 0x7050, 0xa086, 0x0100, + 0x0040, 0x4ca4, 0x007c, 0x007c, 0x7050, 0xa09e, 0x0100, 0x00c0, + 0x4cad, 0x7007, 0x0004, 0x0078, 0x4ccb, 0xa086, 0x0200, 0x00c0, + 0x4cb3, 0x7007, 0x0005, 0x007c, 0x2001, 0xa57e, 0x2004, 0xa08e, + 0x0100, 0x00c0, 0x4cc0, 0x7007, 0x0001, 0x1078, 0x4d5b, 0x007c, + 0xa08e, 0x0000, 0x0040, 0x4cbf, 0xa08e, 0x0200, 0x00c0, 0x4cbf, + 0x7007, 0x0005, 0x007c, 0x1078, 0x4d25, 0x7006, 0x1078, 0x4d5b, + 0x007c, 0x007c, 0x0e7e, 0x157e, 0x2071, 0xa534, 0x7184, 0x81ff, + 0x0040, 0x4cfa, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, + 0x21a8, 0x2014, 0x7226, 0x8000, 0x0070, 0x4cf7, 0x2014, 0x722a, + 0x8000, 0x0070, 0x4cf7, 0x2014, 0x722e, 0x8000, 0x0070, 0x4cf7, + 0x2014, 0x723a, 0x8000, 0x0070, 0x4cf7, 0x2014, 0x723e, 0xa180, + 0x8030, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x0e7e, 0x157e, 0x2071, + 0xa534, 0x7184, 0x81ff, 0x0040, 0x4d22, 0xa006, 0x7086, 0xae80, + 0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014, + 0x722a, 0x8000, 0x0070, 0x4d1b, 0x2014, 0x723a, 0x8000, 0x2014, + 0x723e, 0x0078, 0x4d1f, 0x2001, 0x8020, 0x0078, 0x4d21, 0x2001, + 0x8042, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x702c, 0x7130, 0x8108, + 0xa102, 0x0048, 0x4d32, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, + 0x0078, 0x4d3c, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4d3c, + 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, + 0x00c0, 0x4d52, 0x127e, 0x2091, 0x8000, 0x0068, 0x4d55, 0x2001, + 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b, 0x0000, + 0x127f, 0x007c, 0x2001, 0x0007, 0x007c, 0x2001, 0x0006, 0x700b, + 0x0001, 0x127f, 0x007c, 0x701c, 0xa06d, 0x0040, 0x4d6e, 0x127e, + 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0xa005, + 0x00c0, 0x4d6b, 0x701a, 0x127f, 0x1078, 0x139a, 0x007c, 0x2019, + 0x000d, 0x2304, 0x230c, 0xa10e, 0x0040, 0x4d7e, 0x2304, 0x230c, + 0xa10e, 0x0040, 0x4d7e, 0xa006, 0x0078, 0x4d8e, 0x732c, 0x8319, + 0x7130, 0xa102, 0x00c0, 0x4d88, 0x2300, 0xa005, 0x0078, 0x4d8e, + 0x0048, 0x4d8d, 0xa302, 0x0078, 0x4d8e, 0x8002, 0x007c, 0x2d00, + 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x127e, 0x2091, + 0x8000, 0x2009, 0xa5d0, 0x2104, 0xc08d, 0x200a, 0x127f, 0x1078, + 0x13eb, 0x007c, 0x2071, 0xa3e1, 0x7003, 0x0000, 0x7007, 0x0000, + 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, + 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, + 0x708f, 0x0001, 0x70bf, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa3e1, + 0x6848, 0xa005, 0x00c0, 0x4dcb, 0x7028, 0xc085, 0x702a, 0xa085, + 0x0001, 0x0078, 0x4df0, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, + 0x703e, 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, + 0x7032, 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, + 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, + 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, + 0x0e7f, 0x007c, 0x2b78, 0x2071, 0xa3e1, 0x7004, 0x1079, 0x4e50, + 0x700c, 0x0079, 0x4dfb, 0x4e00, 0x4df5, 0x4df5, 0x4df5, 0x4df5, + 0x007c, 0x700c, 0x0079, 0x4e04, 0x4e09, 0x4e4e, 0x4e4e, 0x4e4f, + 0x4e4f, 0x7830, 0x7930, 0xa106, 0x0040, 0x4e13, 0x7830, 0x7930, + 0xa106, 0x00c0, 0x4e39, 0x7030, 0xa10a, 0x0040, 0x4e39, 0x00c8, + 0x4e1b, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x00c8, 0x4e3a, 0x1078, + 0x1366, 0x0040, 0x4e39, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, + 0x0003, 0x7057, 0x0000, 0x127e, 0x007e, 0x2091, 0x8000, 0x2009, + 0xa5d0, 0x2104, 0xc085, 0x200a, 0x007f, 0x700e, 0x127f, 0x1078, + 0x13eb, 0x007c, 0x1078, 0x1366, 0x0040, 0x4e39, 0x2d00, 0x705a, + 0x1078, 0x1366, 0x00c0, 0x4e46, 0x0078, 0x4e25, 0x2d00, 0x7086, + 0x7063, 0x0080, 0x2001, 0x0004, 0x0078, 0x4e29, 0x007c, 0x007c, + 0x4e61, 0x4e62, 0x4e99, 0x4e9a, 0x4e4e, 0x4ed0, 0x4ed5, 0x4f0c, + 0x4f0d, 0x4f28, 0x4f29, 0x4f2a, 0x4f2b, 0x4f2c, 0x4f2d, 0x4fad, + 0x4fd7, 0x007c, 0x700c, 0x0079, 0x4e65, 0x4e6a, 0x4e6d, 0x4e7d, + 0x4e98, 0x4e98, 0x1078, 0x4e01, 0x007c, 0x127e, 0x8001, 0x700e, + 0x7058, 0x007e, 0x1078, 0x5348, 0x0040, 0x4e7a, 0x2091, 0x8000, + 0x1078, 0x4e01, 0x0d7f, 0x0078, 0x4e86, 0x127e, 0x8001, 0x700e, + 0x1078, 0x5348, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, + 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x0020, 0x00c8, + 0x4e95, 0x1079, 0x4eb0, 0x127f, 0x007c, 0x127f, 0x1078, 0x4f2e, + 0x007c, 0x007c, 0x007c, 0x0e7e, 0x2071, 0xa3e1, 0x700c, 0x0079, + 0x4ea1, 0x4ea6, 0x4ea6, 0x4ea6, 0x4ea8, 0x4eac, 0x0e7f, 0x007c, + 0x700f, 0x0001, 0x0078, 0x4eae, 0x700f, 0x0002, 0x0e7f, 0x007c, + 0x4f2e, 0x4f2e, 0x4f4a, 0x4f2e, 0x5080, 0x4f2e, 0x4f2e, 0x4f2e, + 0x4f2e, 0x4f2e, 0x4f4a, 0x50ca, 0x5117, 0x5170, 0x5186, 0x4f2e, + 0x4f2e, 0x4f66, 0x4f4a, 0x4f2e, 0x4f2e, 0x4f87, 0x5245, 0x5263, + 0x4f2e, 0x4f66, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f7c, 0x5263, + 0x7020, 0x2068, 0x1078, 0x139a, 0x007c, 0x700c, 0x0079, 0x4ed8, + 0x4edd, 0x4ee0, 0x4ef0, 0x4f0b, 0x4f0b, 0x1078, 0x4e01, 0x007c, + 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x5348, 0x0040, + 0x4eed, 0x2091, 0x8000, 0x1078, 0x4e01, 0x0d7f, 0x0078, 0x4ef9, + 0x127e, 0x8001, 0x700e, 0x1078, 0x5348, 0x7058, 0x2068, 0x7084, + 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, + 0xa08a, 0x001a, 0x00c8, 0x4f08, 0x1079, 0x4f0e, 0x127f, 0x007c, + 0x127f, 0x1078, 0x4f2e, 0x007c, 0x007c, 0x007c, 0x4f2e, 0x4f4a, + 0x506a, 0x4f2e, 0x4f4a, 0x4f2e, 0x4f4a, 0x4f4a, 0x4f2e, 0x4f4a, + 0x506a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f2e, 0x4f4a, + 0x506a, 0x4f2e, 0x4f2e, 0x4f4a, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f4a, + 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x7007, 0x0001, + 0x6838, 0xa084, 0x00ff, 0xc0d5, 0x683a, 0x127e, 0x2091, 0x8000, + 0x1078, 0x4982, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, + 0x00ff, 0xc0e5, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982, + 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, + 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982, 0x127f, 0x007c, + 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a, 0x127e, + 0x2091, 0x8000, 0x1078, 0x4982, 0x127f, 0x007c, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x0040, 0x4f3c, 0x8001, 0x00c0, 0x4f73, 0x7007, + 0x0001, 0x0078, 0x5049, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, + 0x701a, 0x704b, 0x5049, 0x007c, 0x684c, 0xa084, 0x00c0, 0xa086, + 0x00c0, 0x00c0, 0x4f87, 0x7007, 0x0001, 0x0078, 0x5280, 0x2d00, + 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, + 0xa40c, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8, 0x4f58, + 0x6884, 0xa08a, 0x0002, 0x00c8, 0x4f58, 0x82ff, 0x00c0, 0x4fa9, + 0x6888, 0x698c, 0xa105, 0x0040, 0x4fa9, 0x2001, 0x5019, 0x0078, + 0x4fac, 0xa280, 0x500f, 0x2004, 0x70c6, 0x7010, 0xa015, 0x0040, + 0x4ff7, 0x1078, 0x1366, 0x00c0, 0x4fb8, 0x7007, 0x000f, 0x007c, + 0x2d00, 0x7022, 0x70c4, 0x2060, 0x6000, 0x6836, 0x6004, 0xad00, + 0x7096, 0x6008, 0xa20a, 0x00c8, 0x4fc7, 0xa00e, 0x2200, 0x7112, + 0x620c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0040, 0x4fd0, 0xa108, + 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x1078, 0x13d1, 0x7090, + 0xa08e, 0x0100, 0x0040, 0x4feb, 0xa086, 0x0200, 0x0040, 0x4fe3, + 0x7007, 0x0010, 0x007c, 0x7020, 0x2068, 0x1078, 0x139a, 0x7014, + 0x2068, 0x0078, 0x4f58, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, + 0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, 0x0078, 0x4fad, 0x7014, + 0x2068, 0x7007, 0x0001, 0x6884, 0xa005, 0x00c0, 0x5006, 0x6888, + 0x698c, 0xa105, 0x0040, 0x5006, 0x1078, 0x501d, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x001e, 0x0040, 0x5280, 0x0078, 0x5049, 0x5011, + 0x5015, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, 0x0005, + 0x0006, 0x000a, 0x0011, 0x0005, 0x0004, 0x0f7e, 0x0e7e, 0x0c7e, + 0x077e, 0x067e, 0x6f88, 0x6e8c, 0x6804, 0x2060, 0xacf0, 0x0021, + 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, 0x7816, 0x7008, 0x7812, + 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a, 0x8109, 0x0040, + 0x503f, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0078, 0x502c, 0x6004, + 0xa065, 0x00c0, 0x5026, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x0f7f, + 0x007c, 0x2009, 0xa32e, 0x210c, 0x81ff, 0x00c0, 0x5064, 0x6838, + 0xa084, 0x00ff, 0x683a, 0x1078, 0x4290, 0x00c0, 0x5058, 0x007c, + 0x1078, 0x4a60, 0x127e, 0x2091, 0x8000, 0x1078, 0x8cb8, 0x1078, + 0x4982, 0x127f, 0x0078, 0x5057, 0x2001, 0x0028, 0x2009, 0x0000, + 0x0078, 0x5058, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a, + 0x7010, 0x8001, 0x7012, 0x0040, 0x5079, 0x7007, 0x0006, 0x0078, + 0x507f, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, 0x007c, + 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, + 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x50a9, 0x2009, + 0x0000, 0x20a9, 0x00ff, 0xa096, 0x0002, 0x0040, 0x50a9, 0xa005, + 0x00c0, 0x50bc, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x4501, + 0x00c0, 0x50bc, 0x067e, 0x6e50, 0x1078, 0x45e7, 0x067f, 0x0078, + 0x50bc, 0x047e, 0x2011, 0xa30c, 0x2224, 0xc484, 0xc48c, 0x2412, + 0x047f, 0x0c7e, 0x1078, 0x4501, 0x00c0, 0x50b8, 0x1078, 0x4782, + 0x8108, 0x00f0, 0x50b2, 0x0c7f, 0x684c, 0xd084, 0x00c0, 0x50c3, + 0x1078, 0x139a, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982, + 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, + 0xa352, 0x2004, 0xd0a4, 0x0040, 0x510e, 0x2061, 0xa62d, 0x6100, + 0xd184, 0x0040, 0x50ee, 0x6858, 0xa084, 0x00ff, 0x00c0, 0x5111, + 0x6000, 0xd084, 0x0040, 0x510e, 0x6004, 0xa005, 0x00c0, 0x5114, + 0x6003, 0x0000, 0x600b, 0x0000, 0x0078, 0x510b, 0x2011, 0x0001, + 0x6860, 0xa005, 0x00c0, 0x50f6, 0x2001, 0x001e, 0x8000, 0x6016, + 0x6858, 0xa084, 0x00ff, 0x0040, 0x510e, 0x6006, 0x6858, 0x8007, + 0xa084, 0x00ff, 0x0040, 0x510e, 0x600a, 0x6858, 0x8000, 0x00c0, + 0x510a, 0xc28d, 0x6202, 0x127f, 0x0078, 0x5337, 0x127f, 0x0078, + 0x532f, 0x127f, 0x0078, 0x5327, 0x127f, 0x0078, 0x532b, 0x127e, + 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xa352, 0x2004, 0xd0a4, + 0x0040, 0x516d, 0x2061, 0xa62d, 0x6000, 0xd084, 0x0040, 0x516d, + 0x6204, 0x6308, 0xd08c, 0x00c0, 0x515f, 0x6c48, 0xa484, 0x0003, + 0x0040, 0x5145, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x513e, + 0x2100, 0xa210, 0x0048, 0x516a, 0x0078, 0x5145, 0x8001, 0x00c0, + 0x516a, 0x2100, 0xa212, 0x0048, 0x516a, 0xa484, 0x000c, 0x0040, + 0x515f, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, + 0x5157, 0x2100, 0xa318, 0x0048, 0x516a, 0x0078, 0x515f, 0xa082, + 0x0004, 0x00c0, 0x516a, 0x2100, 0xa31a, 0x0048, 0x516a, 0x6860, + 0xa005, 0x0040, 0x5165, 0x8000, 0x6016, 0x6206, 0x630a, 0x127f, + 0x0078, 0x5337, 0x127f, 0x0078, 0x5333, 0x127f, 0x0078, 0x532f, + 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0xa62d, 0x6300, + 0xd38c, 0x00c0, 0x5180, 0x6308, 0x8318, 0x0048, 0x5183, 0x630a, + 0x127f, 0x0078, 0x5345, 0x127f, 0x0078, 0x5333, 0x127e, 0x0c7e, + 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0040, 0x519a, + 0x0c7e, 0x2061, 0xa62d, 0x6000, 0xa084, 0xfcff, 0x6002, 0x0c7f, + 0x0078, 0x51c9, 0x6858, 0xa005, 0x0040, 0x51e0, 0x685c, 0xa065, + 0x0040, 0x51dc, 0x2001, 0xa32e, 0x2004, 0xa005, 0x0040, 0x51ac, + 0x1078, 0x8c01, 0x0078, 0x51ba, 0x6013, 0x0400, 0x6037, 0x0000, + 0x694c, 0xd1a4, 0x0040, 0x51b6, 0x6950, 0x6136, 0x2009, 0x0041, + 0x1078, 0x756c, 0x6958, 0xa18c, 0xff00, 0xa186, 0x2000, 0x00c0, + 0x51c9, 0x027e, 0x2009, 0x0000, 0x2011, 0xfdff, 0x1078, 0x5a6d, + 0x027f, 0x684c, 0xd0c4, 0x0040, 0x51d8, 0x2061, 0xa62d, 0x6000, + 0xd08c, 0x00c0, 0x51d8, 0x6008, 0x8000, 0x0048, 0x51dc, 0x600a, + 0x0c7f, 0x127f, 0x0078, 0x5337, 0x0c7f, 0x127f, 0x0078, 0x532f, + 0x6954, 0xa186, 0x0045, 0x0040, 0x5213, 0xa186, 0x002a, 0x00c0, + 0x51f0, 0x2001, 0xa30c, 0x200c, 0xc194, 0x2102, 0x0078, 0x51c9, + 0xa186, 0x0020, 0x0040, 0x5209, 0xa186, 0x0029, 0x0040, 0x51fc, + 0xa186, 0x002d, 0x00c0, 0x51dc, 0x6944, 0xa18c, 0xff00, 0x810f, + 0x1078, 0x4501, 0x00c0, 0x51c9, 0x6000, 0xc0e4, 0x6002, 0x0078, + 0x51c9, 0x685c, 0xa065, 0x0040, 0x51dc, 0x2001, 0xa5a1, 0x2004, + 0x6016, 0x0078, 0x51c9, 0x685c, 0xa065, 0x0040, 0x51dc, 0x0e7e, + 0x6860, 0xa075, 0x2001, 0xa32e, 0x2004, 0xa005, 0x0040, 0x522b, + 0x1078, 0x8c01, 0x8eff, 0x0040, 0x5228, 0x2e60, 0x1078, 0x8c01, + 0x0e7f, 0x0078, 0x51c9, 0x6024, 0xc0dc, 0xc0d5, 0x6026, 0x2e60, + 0x6007, 0x003a, 0x6870, 0xa005, 0x0040, 0x523c, 0x6007, 0x003b, + 0x6874, 0x602a, 0x6878, 0x6012, 0x6003, 0x0001, 0x1078, 0x5bf8, + 0x1078, 0x6109, 0x0e7f, 0x0078, 0x51c9, 0x2061, 0xa62d, 0x6000, + 0xd084, 0x0040, 0x525f, 0xd08c, 0x00c0, 0x5345, 0x2091, 0x8000, + 0x6204, 0x8210, 0x0048, 0x5259, 0x6206, 0x2091, 0x8001, 0x0078, + 0x5345, 0x2091, 0x8001, 0x6853, 0x0016, 0x0078, 0x533e, 0x6853, + 0x0007, 0x0078, 0x533e, 0x6834, 0x8007, 0xa084, 0x00ff, 0x00c0, + 0x526d, 0x1078, 0x4f3c, 0x0078, 0x527f, 0x2030, 0x8001, 0x00c0, + 0x5277, 0x7007, 0x0001, 0x1078, 0x5280, 0x0078, 0x527f, 0x7007, + 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5280, 0x007c, + 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2009, 0xa32e, 0x210c, 0x81ff, + 0x00c0, 0x530b, 0x2009, 0xa30c, 0x210c, 0xd194, 0x00c0, 0x5315, + 0x6848, 0x2070, 0xae82, 0xaa00, 0x0048, 0x52fb, 0x2001, 0xa315, + 0x2004, 0xae02, 0x00c8, 0x52fb, 0x2061, 0xa62d, 0x6100, 0xa184, + 0x0301, 0xa086, 0x0001, 0x00c0, 0x52de, 0x711c, 0xa186, 0x0006, + 0x00c0, 0x52e6, 0x7018, 0xa005, 0x0040, 0x530b, 0x2004, 0xd0e4, + 0x00c0, 0x530f, 0x7024, 0xd0dc, 0x00c0, 0x5319, 0x6853, 0x0000, + 0x6803, 0x0000, 0x2d08, 0x7010, 0xa005, 0x00c0, 0x52ca, 0x7112, + 0x684c, 0xd0f4, 0x00c0, 0x531d, 0x2e60, 0x1078, 0x59b6, 0x127f, + 0x0e7f, 0x007c, 0x2068, 0x6800, 0xa005, 0x00c0, 0x52ca, 0x6902, + 0x2168, 0x684c, 0xd0f4, 0x00c0, 0x531d, 0x127f, 0x0e7f, 0x007c, + 0x127f, 0x0e7f, 0x6853, 0x0006, 0x0078, 0x533e, 0xd184, 0x0040, + 0x52d8, 0xd1c4, 0x00c0, 0x52ff, 0x0078, 0x5303, 0x6944, 0xa18c, + 0xff00, 0x810f, 0x1078, 0x4501, 0x00c0, 0x530f, 0x6000, 0xd0e4, + 0x00c0, 0x530f, 0x711c, 0xa186, 0x0007, 0x00c0, 0x52fb, 0x6853, + 0x0002, 0x0078, 0x5311, 0x6853, 0x0008, 0x0078, 0x5311, 0x6853, + 0x000e, 0x0078, 0x5311, 0x6853, 0x0017, 0x0078, 0x5311, 0x6853, + 0x0035, 0x0078, 0x5311, 0x6853, 0x0028, 0x0078, 0x5311, 0x6853, + 0x0029, 0x127f, 0x0e7f, 0x0078, 0x533e, 0x6853, 0x002a, 0x0078, + 0x5311, 0x6853, 0x0045, 0x0078, 0x5311, 0x2e60, 0x2019, 0x0002, + 0x6017, 0x0014, 0x1078, 0x9a6a, 0x127f, 0x0e7f, 0x007c, 0x2009, + 0x003e, 0x0078, 0x5339, 0x2009, 0x0004, 0x0078, 0x5339, 0x2009, + 0x0006, 0x0078, 0x5339, 0x2009, 0x0016, 0x0078, 0x5339, 0x2009, + 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, 0x2091, 0x8000, + 0x1078, 0x4982, 0x2091, 0x8001, 0x007c, 0x1078, 0x139a, 0x007c, + 0x702c, 0x7130, 0x8108, 0xa102, 0x0048, 0x5355, 0xa00e, 0x7034, + 0x7072, 0x7038, 0x7076, 0x0078, 0x5361, 0x7070, 0xa080, 0x0040, + 0x7072, 0x00c8, 0x5361, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, + 0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, 0x1078, 0x59ad, 0x0d7f, + 0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, 0xa085, 0x8002, 0x2012, + 0x0d7f, 0x007c, 0x20e1, 0x0002, 0x3d08, 0x20e1, 0x2000, 0x3d00, + 0xa084, 0x7000, 0x0040, 0x5380, 0xa086, 0x1000, 0x00c0, 0x53ac, + 0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00, 0x8217, 0xa084, 0xf000, + 0xa086, 0x3000, 0x00c0, 0x5390, 0x1078, 0x5570, 0x0078, 0x53a7, + 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, 0x5397, 0x3e60, 0xac84, + 0x000f, 0x00c0, 0x53ac, 0xac82, 0xaa00, 0x0048, 0x53ac, 0x6854, + 0xac02, 0x00c8, 0x53ac, 0x2009, 0x0047, 0x1078, 0x756c, 0x7a1c, + 0xd284, 0x00c0, 0x5372, 0x007c, 0xa016, 0x1078, 0x15ec, 0x0078, + 0x53a7, 0x0078, 0x53ac, 0x781c, 0xd08c, 0x0040, 0x53db, 0x157e, + 0x137e, 0x147e, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076, + 0x00c0, 0x53f1, 0xa484, 0x7000, 0xa086, 0x1000, 0x00c0, 0x53e0, + 0x1078, 0x540c, 0x0040, 0x53f1, 0x20e1, 0x3000, 0x7828, 0x7828, + 0x1078, 0x542a, 0x147f, 0x137f, 0x157f, 0x2009, 0xa5b3, 0x2104, + 0xa005, 0x00c0, 0x53dc, 0x007c, 0x1078, 0x6109, 0x0078, 0x53db, + 0xa484, 0x7000, 0x00c0, 0x53f1, 0x1078, 0x540c, 0x0040, 0x5403, + 0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x0040, 0x53cc, 0x0078, + 0x5403, 0x1078, 0xa1ee, 0xd5a4, 0x0040, 0x53ff, 0x1078, 0x1af7, + 0x20e1, 0x9010, 0x2001, 0x0138, 0x2202, 0x0078, 0x5407, 0x1078, + 0x540c, 0x687f, 0x0000, 0x20e1, 0x3000, 0x7828, 0x7828, 0x147f, + 0x137f, 0x157f, 0x0078, 0x53db, 0xa484, 0x01ff, 0x687e, 0xa005, + 0x0040, 0x541e, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1, + 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c, 0x20a9, 0x000c, + 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, + 0x0078, 0x541d, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007, + 0xa196, 0x0000, 0x00c0, 0x5437, 0x0078, 0x567c, 0x007c, 0xa196, + 0x2000, 0x00c0, 0x5448, 0x6900, 0xa18e, 0x0001, 0x00c0, 0x5444, + 0x1078, 0x3a43, 0x0078, 0x5436, 0x1078, 0x5450, 0x0078, 0x5436, + 0xa196, 0x8000, 0x00c0, 0x5436, 0x1078, 0x570c, 0x0078, 0x5436, + 0x0c7e, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0040, + 0x545d, 0xa196, 0x0023, 0x00c0, 0x5568, 0xa08e, 0x0023, 0x00c0, + 0x5492, 0x1078, 0x57b2, 0x0040, 0x5568, 0x7124, 0x610a, 0x7030, + 0xa08e, 0x0200, 0x00c0, 0x5476, 0x7034, 0xa005, 0x00c0, 0x5568, + 0x2009, 0x0015, 0x1078, 0x756c, 0x0078, 0x5568, 0xa08e, 0x0214, + 0x0040, 0x547e, 0xa08e, 0x0210, 0x00c0, 0x5484, 0x2009, 0x0015, + 0x1078, 0x756c, 0x0078, 0x5568, 0xa08e, 0x0100, 0x00c0, 0x5568, + 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, 0x0016, 0x1078, 0x756c, + 0x0078, 0x5568, 0xa08e, 0x0022, 0x00c0, 0x5568, 0x7030, 0xa08e, + 0x0300, 0x00c0, 0x54a3, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, + 0x0017, 0x0078, 0x5534, 0xa08e, 0x0500, 0x00c0, 0x54af, 0x7034, + 0xa005, 0x00c0, 0x5568, 0x2009, 0x0018, 0x0078, 0x5534, 0xa08e, + 0x2010, 0x00c0, 0x54b7, 0x2009, 0x0019, 0x0078, 0x5534, 0xa08e, + 0x2110, 0x00c0, 0x54bf, 0x2009, 0x001a, 0x0078, 0x5534, 0xa08e, + 0x5200, 0x00c0, 0x54cb, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, + 0x001b, 0x0078, 0x5534, 0xa08e, 0x5000, 0x00c0, 0x54d7, 0x7034, + 0xa005, 0x00c0, 0x5568, 0x2009, 0x001c, 0x0078, 0x5534, 0xa08e, + 0x1300, 0x00c0, 0x54df, 0x2009, 0x0034, 0x0078, 0x5534, 0xa08e, + 0x1200, 0x00c0, 0x54eb, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, + 0x0024, 0x0078, 0x5534, 0xa08c, 0xff00, 0xa18e, 0x2400, 0x00c0, + 0x54f5, 0x2009, 0x002d, 0x0078, 0x5534, 0xa08c, 0xff00, 0xa18e, + 0x5300, 0x00c0, 0x54ff, 0x2009, 0x002a, 0x0078, 0x5534, 0xa08e, + 0x0f00, 0x00c0, 0x5507, 0x2009, 0x0020, 0x0078, 0x5534, 0xa08e, + 0x5300, 0x00c0, 0x550d, 0x0078, 0x552a, 0xa08e, 0x6104, 0x00c0, + 0x552a, 0x2011, 0xa88d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8, + 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, 0x047e, 0x2124, + 0x1078, 0x3579, 0x047f, 0x8108, 0x00f0, 0x551a, 0x2009, 0x0023, + 0x0078, 0x5534, 0xa08e, 0x6000, 0x00c0, 0x5532, 0x2009, 0x003f, + 0x0078, 0x5534, 0x2009, 0x001d, 0x017e, 0x2011, 0xa883, 0x2204, + 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x556a, 0x1078, 0x4499, + 0x00c0, 0x556a, 0x6612, 0x6516, 0x86ff, 0x0040, 0x555a, 0x017f, + 0x017e, 0xa186, 0x0017, 0x00c0, 0x555a, 0x6868, 0xa606, 0x00c0, + 0x555a, 0x686c, 0xa506, 0xa084, 0xff00, 0x00c0, 0x555a, 0x6000, + 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x74d7, 0x0040, 0x556d, 0x017f, + 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x756c, + 0x0c7f, 0x007c, 0x017f, 0x0078, 0x5568, 0x0c7f, 0x0078, 0x556a, + 0x0c7e, 0x1078, 0x55d4, 0x00c0, 0x55d2, 0xa184, 0xff00, 0x8007, + 0xa086, 0x0008, 0x00c0, 0x55d2, 0xa28e, 0x0033, 0x00c0, 0x55a3, + 0x1078, 0x57b2, 0x0040, 0x55d2, 0x7124, 0x610a, 0x7030, 0xa08e, + 0x0200, 0x00c0, 0x5595, 0x7034, 0xa005, 0x00c0, 0x55d2, 0x2009, + 0x0015, 0x1078, 0x756c, 0x0078, 0x55d2, 0xa08e, 0x0100, 0x00c0, + 0x55d2, 0x7034, 0xa005, 0x00c0, 0x55d2, 0x2009, 0x0016, 0x1078, + 0x756c, 0x0078, 0x55d2, 0xa28e, 0x0032, 0x00c0, 0x55d2, 0x7030, + 0xa08e, 0x1400, 0x00c0, 0x55d2, 0x2009, 0x0038, 0x017e, 0x2011, + 0xa883, 0x2204, 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x55d1, + 0x1078, 0x4499, 0x00c0, 0x55d1, 0x6612, 0x6516, 0x0c7e, 0x1078, + 0x74d7, 0x0040, 0x55d0, 0x017f, 0x611a, 0x601f, 0x0004, 0x7120, + 0x610a, 0x017f, 0x1078, 0x756c, 0x1078, 0x6109, 0x0078, 0x55d2, + 0x0c7f, 0x017f, 0x0c7f, 0x007c, 0x0f7e, 0x0d7e, 0x027e, 0x017e, + 0x137e, 0x147e, 0x157e, 0x3c00, 0x007e, 0x2079, 0x0030, 0x2069, + 0x0200, 0x1078, 0x1c25, 0x00c0, 0x5615, 0x1078, 0x1b15, 0x0040, + 0x561f, 0x7908, 0xa18c, 0x1fff, 0xa182, 0x0011, 0x00c8, 0x561f, + 0x20a9, 0x000c, 0x20e1, 0x0000, 0x2ea0, 0x2099, 0x020a, 0x53a5, + 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x7a0c, 0x7808, 0xa080, + 0x0007, 0xa084, 0x1ff8, 0xa08a, 0x0140, 0x10c8, 0x1328, 0x80ac, + 0x20e1, 0x6000, 0x2099, 0x020a, 0x53a5, 0x20e1, 0x7000, 0x6828, + 0x6828, 0x7803, 0x0004, 0xa294, 0x0070, 0x007f, 0x20e0, 0x157f, + 0x147f, 0x137f, 0x017f, 0x027f, 0x0d7f, 0x0f7f, 0x007c, 0xa085, + 0x0001, 0x0078, 0x5615, 0x047e, 0x0e7e, 0x0d7e, 0x2028, 0x2130, + 0xa696, 0x00ff, 0x00c0, 0x5644, 0xa596, 0xfffd, 0x00c0, 0x5634, + 0x2009, 0x007f, 0x0078, 0x5677, 0xa596, 0xfffe, 0x00c0, 0x563c, + 0x2009, 0x007e, 0x0078, 0x5677, 0xa596, 0xfffc, 0x00c0, 0x5644, + 0x2009, 0x0080, 0x0078, 0x5677, 0x2011, 0x0000, 0x2021, 0x0081, + 0x20a9, 0x007e, 0x2071, 0xa4b5, 0x2e1c, 0x83ff, 0x00c0, 0x5656, + 0x82ff, 0x00c0, 0x566b, 0x2410, 0x0078, 0x566b, 0x2368, 0x6f10, + 0x007e, 0x2100, 0xa706, 0x007f, 0x6b14, 0x00c0, 0x5665, 0xa346, + 0x00c0, 0x5665, 0x2408, 0x0078, 0x5677, 0x87ff, 0x00c0, 0x566b, + 0x83ff, 0x0040, 0x5650, 0x8420, 0x8e70, 0x00f0, 0x564c, 0x82ff, + 0x00c0, 0x5676, 0xa085, 0x0001, 0x0078, 0x5678, 0x2208, 0xa006, + 0x0d7f, 0x0e7f, 0x047f, 0x007c, 0xa084, 0x0007, 0x0079, 0x5681, + 0x007c, 0x5689, 0x5689, 0x5689, 0x57c8, 0x5689, 0x568a, 0x56a3, + 0x56f3, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x56a2, 0x7120, 0x2160, + 0xac8c, 0x000f, 0x00c0, 0x56a2, 0xac8a, 0xaa00, 0x0048, 0x56a2, + 0x6854, 0xac02, 0x00c8, 0x56a2, 0x7124, 0x610a, 0x2009, 0x0046, + 0x1078, 0x756c, 0x007c, 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x56f1, + 0x2011, 0xa883, 0x2204, 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, + 0x56f1, 0x1078, 0x4499, 0x00c0, 0x56f1, 0x6612, 0x6516, 0x6000, + 0xd0ec, 0x00c0, 0x56f1, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, + 0x0006, 0x00c0, 0x56d6, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, + 0x56f1, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6122, + 0x2009, 0x0044, 0x1078, 0x756c, 0x0078, 0x56f1, 0x0c7e, 0x1078, + 0x74d7, 0x017f, 0x0040, 0x56f1, 0x611a, 0x601f, 0x0004, 0x7120, + 0x610a, 0xa286, 0x0004, 0x00c0, 0x56e9, 0x6007, 0x0005, 0x0078, + 0x56eb, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5c45, 0x1078, + 0x6109, 0x0c7f, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x570b, 0x7020, + 0x2060, 0xac84, 0x000f, 0x00c0, 0x570b, 0xac82, 0xaa00, 0x0048, + 0x570b, 0x6854, 0xac02, 0x00c8, 0x570b, 0x7124, 0x610a, 0x2009, + 0x0045, 0x1078, 0x756c, 0x007c, 0x7110, 0xa18c, 0xff00, 0x810f, + 0xa18e, 0x0000, 0x00c0, 0x571c, 0xa084, 0x000f, 0xa08a, 0x0006, + 0x00c8, 0x571c, 0x1079, 0x571d, 0x007c, 0x5723, 0x5724, 0x5723, + 0x5723, 0x5794, 0x57a3, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x572c, + 0x702c, 0xd084, 0x0040, 0x5793, 0x700c, 0x7108, 0x1078, 0x24e3, + 0x00c0, 0x5793, 0x1078, 0x4499, 0x00c0, 0x5793, 0x6612, 0x6516, + 0x6204, 0x7110, 0xd1bc, 0x0040, 0x575e, 0xa28c, 0x00ff, 0xa186, + 0x0004, 0x0040, 0x5747, 0xa186, 0x0006, 0x00c0, 0x5784, 0x0c7e, + 0x1078, 0x57b2, 0x0c7f, 0x0040, 0x5793, 0x0c7e, 0x1078, 0x74d7, + 0x017f, 0x0040, 0x5793, 0x611a, 0x601f, 0x0002, 0x7120, 0x610a, + 0x2009, 0x0088, 0x1078, 0x756c, 0x0078, 0x5793, 0xa28c, 0x00ff, + 0xa186, 0x0006, 0x0040, 0x5773, 0xa186, 0x0004, 0x0040, 0x5773, + 0xa294, 0xff00, 0x8217, 0xa286, 0x0004, 0x0040, 0x5773, 0xa286, + 0x0006, 0x00c0, 0x5784, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, + 0x5793, 0x611a, 0x601f, 0x0005, 0x7120, 0x610a, 0x2009, 0x0088, + 0x1078, 0x756c, 0x0078, 0x5793, 0x0c7e, 0x1078, 0x74d7, 0x017f, + 0x0040, 0x5793, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x2009, + 0x0001, 0x1078, 0x756c, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x57a2, + 0x1078, 0x57b2, 0x0040, 0x57a2, 0x7124, 0x610a, 0x2009, 0x0089, + 0x1078, 0x756c, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x57b1, 0x1078, + 0x57b2, 0x0040, 0x57b1, 0x7124, 0x610a, 0x2009, 0x008a, 0x1078, + 0x756c, 0x007c, 0x7020, 0x2060, 0xac84, 0x000f, 0x00c0, 0x57c5, + 0xac82, 0xaa00, 0x0048, 0x57c5, 0x2001, 0xa315, 0x2004, 0xac02, + 0x00c8, 0x57c5, 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x57c4, + 0x7110, 0xd1bc, 0x00c0, 0x57de, 0x7024, 0x2060, 0xac84, 0x000f, + 0x00c0, 0x57de, 0xac82, 0xaa00, 0x0048, 0x57de, 0x6854, 0xac02, + 0x00c8, 0x57de, 0x2009, 0x0051, 0x1078, 0x756c, 0x007c, 0x2071, + 0xa5be, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7012, + 0x7017, 0xaa00, 0x7007, 0x0000, 0x7026, 0x702b, 0x6c4e, 0x7032, + 0x7037, 0x6ca0, 0x703b, 0x0002, 0x703f, 0x0000, 0x7043, 0xffff, + 0x7047, 0xffff, 0x007c, 0x2071, 0xa5be, 0x00e0, 0x58c1, 0x2091, + 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, 0x5873, 0x700f, 0x0361, + 0x7007, 0x0001, 0x127e, 0x2091, 0x8000, 0x7138, 0x8109, 0x713a, + 0x00c0, 0x5871, 0x703b, 0x0002, 0x2009, 0x0100, 0x2104, 0xa082, + 0x0003, 0x00c8, 0x5871, 0x703c, 0xa086, 0x0001, 0x00c0, 0x584e, + 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x582c, + 0x6803, 0x1000, 0x0078, 0x5833, 0x6804, 0xa084, 0x1000, 0x0040, + 0x5833, 0x6803, 0x0100, 0x6803, 0x0000, 0x703f, 0x0000, 0x2069, + 0xa5ab, 0x6804, 0xa082, 0x0006, 0x00c0, 0x5840, 0x6807, 0x0000, + 0x6830, 0xa082, 0x0003, 0x00c0, 0x5847, 0x6833, 0x0000, 0x1078, + 0x6109, 0x1078, 0x61d3, 0x0d7f, 0x0078, 0x5871, 0x0d7e, 0x2069, + 0xa300, 0x6944, 0x6860, 0xa102, 0x00c8, 0x5870, 0x2069, 0xa5ab, + 0x6804, 0xa086, 0x0000, 0x00c0, 0x5870, 0x6830, 0xa086, 0x0000, + 0x00c0, 0x5870, 0x703f, 0x0001, 0x6807, 0x0006, 0x6833, 0x0003, + 0x2069, 0x0100, 0x6830, 0x689e, 0x2069, 0x0140, 0x6803, 0x0600, + 0x0d7f, 0x0078, 0x5876, 0x127e, 0x2091, 0x8000, 0x7024, 0xa00d, + 0x0040, 0x588e, 0x7020, 0x8001, 0x7022, 0x00c0, 0x588e, 0x7023, + 0x0009, 0x8109, 0x7126, 0xa186, 0x03e8, 0x00c0, 0x5889, 0x7028, + 0x107a, 0x81ff, 0x00c0, 0x588e, 0x7028, 0x107a, 0x7030, 0xa00d, + 0x0040, 0x589f, 0x702c, 0x8001, 0x702e, 0x00c0, 0x589f, 0x702f, + 0x0009, 0x8109, 0x7132, 0x00c0, 0x589f, 0x7034, 0x107a, 0x7040, + 0xa005, 0x0040, 0x58a7, 0x0050, 0x58a7, 0x8001, 0x7042, 0x7044, + 0xa005, 0x0040, 0x58af, 0x0050, 0x58af, 0x8001, 0x7046, 0x7018, + 0xa00d, 0x0040, 0x58c0, 0x7008, 0x8001, 0x700a, 0x00c0, 0x58c0, + 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x58c0, 0x701c, 0x107a, + 0x127f, 0x7004, 0x0079, 0x58c4, 0x58eb, 0x58ec, 0x5908, 0x0e7e, + 0x2071, 0xa5be, 0x7018, 0xa005, 0x00c0, 0x58d2, 0x711a, 0x721e, + 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, 0x2071, 0xa5be, + 0x701c, 0xa206, 0x00c0, 0x58de, 0x701a, 0x701e, 0x007f, 0x0e7f, + 0x007c, 0x0e7e, 0x2071, 0xa5be, 0x6088, 0xa102, 0x0048, 0x58e9, + 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, 0x4501, 0x00c0, + 0x58fe, 0x6088, 0x8001, 0x0048, 0x58fe, 0x608a, 0x00c0, 0x58fe, + 0x127e, 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x8108, 0xa182, + 0x00ff, 0x0048, 0x5906, 0xa00e, 0x7007, 0x0002, 0x7112, 0x007c, + 0x7014, 0x2060, 0x127e, 0x2091, 0x8000, 0x603c, 0xa005, 0x0040, + 0x5917, 0x8001, 0x603e, 0x00c0, 0x5917, 0x1078, 0x8cd7, 0x6014, + 0xa005, 0x0040, 0x5941, 0x8001, 0x6016, 0x00c0, 0x5941, 0x611c, + 0xa186, 0x0003, 0x0040, 0x5928, 0xa186, 0x0006, 0x00c0, 0x593f, + 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x593f, 0xa082, + 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x5938, 0x2001, 0x1999, + 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x5941, 0x1078, + 0x8810, 0x127f, 0xac88, 0x0010, 0x7116, 0x2001, 0xca00, 0xa102, + 0x0048, 0x594e, 0x7017, 0xaa00, 0x7007, 0x0000, 0x007c, 0x0e7e, + 0x2071, 0xa5be, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, 0x0002, + 0x0e7f, 0x007c, 0x2001, 0xa5c7, 0x2003, 0x0000, 0x007c, 0x0e7e, + 0x2071, 0xa5be, 0x7132, 0x702f, 0x0009, 0x0e7f, 0x007c, 0x2011, + 0xa5ca, 0x2013, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa5be, 0x711a, + 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x027e, 0x0e7e, 0x0f7e, + 0x2079, 0xa300, 0x7a34, 0xd294, 0x0040, 0x59a4, 0x2071, 0xa5aa, + 0x2e14, 0xa0fe, 0x0000, 0x0040, 0x5991, 0xa0fe, 0x0001, 0x0040, + 0x5995, 0xa0fe, 0x0002, 0x00c0, 0x59a0, 0xa292, 0x0085, 0x0078, + 0x5997, 0xa292, 0x0005, 0x0078, 0x5997, 0xa292, 0x0002, 0x2272, + 0x0040, 0x599c, 0x00c8, 0x59a4, 0x2011, 0x8037, 0x1078, 0x3579, + 0x2011, 0xa5a9, 0x2204, 0x2072, 0x0f7f, 0x0e7f, 0x027f, 0x007c, + 0x0c7e, 0x2061, 0xa62d, 0x0c7f, 0x007c, 0xa184, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa080, 0xa62d, 0x2060, 0x007c, 0x6854, 0xa08a, + 0x199a, 0x0048, 0x59bd, 0x2001, 0x1999, 0xa005, 0x00c0, 0x59cc, + 0x0c7e, 0x2061, 0xa62d, 0x6014, 0x0c7f, 0xa005, 0x00c0, 0x59d1, + 0x2001, 0x001e, 0x0078, 0x59d1, 0xa08e, 0xffff, 0x00c0, 0x59d1, + 0xa006, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, + 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x5a24, 0xd0b4, 0x00c0, 0x59e8, + 0xd0bc, 0x00c0, 0x5a14, 0x2009, 0x0006, 0x1078, 0x5a43, 0x007c, + 0xd0fc, 0x0040, 0x59f3, 0xa084, 0x0003, 0x0040, 0x59f3, 0xa086, + 0x0003, 0x00c0, 0x5a3c, 0x6024, 0xd0d4, 0x0040, 0x59fd, 0xc0d4, + 0x6026, 0x6860, 0x602a, 0x685c, 0x602e, 0x2009, 0xa373, 0x2104, + 0xd084, 0x0040, 0x5a0f, 0x6118, 0xa188, 0x0027, 0x2104, 0xd08c, + 0x00c0, 0x5a0f, 0x2009, 0x0042, 0x1078, 0x756c, 0x007c, 0x2009, + 0x0043, 0x1078, 0x756c, 0x007c, 0xd0fc, 0x0040, 0x5a1f, 0xa084, + 0x0003, 0x0040, 0x5a1f, 0xa086, 0x0003, 0x00c0, 0x5a3c, 0x2009, + 0x0042, 0x1078, 0x756c, 0x007c, 0xd0fc, 0x0040, 0x5a32, 0xa084, + 0x0003, 0xa08e, 0x0002, 0x0040, 0x5a36, 0x2009, 0x0041, 0x1078, + 0x756c, 0x007c, 0x1078, 0x5a41, 0x0078, 0x5a31, 0x2009, 0x0043, + 0x1078, 0x756c, 0x0078, 0x5a31, 0x2009, 0x0004, 0x1078, 0x5a43, + 0x007c, 0x2009, 0x0001, 0x0d7e, 0x6010, 0xa0ec, 0xf000, 0x0040, + 0x5a6b, 0x2068, 0x6952, 0x6800, 0x6012, 0xa186, 0x0001, 0x00c0, + 0x5a65, 0x694c, 0xa18c, 0x8100, 0xa18e, 0x8100, 0x00c0, 0x5a65, + 0x0c7e, 0x2061, 0xa62d, 0x6200, 0xd28c, 0x00c0, 0x5a64, 0x6204, + 0x8210, 0x0048, 0x5a64, 0x6206, 0x0c7f, 0x1078, 0x4982, 0x6010, + 0xa06d, 0x10c0, 0x59b6, 0x0d7f, 0x007c, 0x157e, 0x0c7e, 0x2061, + 0xa62d, 0x6000, 0x81ff, 0x0040, 0x5a78, 0xa205, 0x0078, 0x5a79, + 0xa204, 0x6002, 0x0c7f, 0x157f, 0x007c, 0x6800, 0xd08c, 0x00c0, + 0x5a89, 0x6808, 0xa005, 0x0040, 0x5a89, 0x8001, 0x680a, 0xa085, + 0x0001, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, + 0x00c8, 0x5a93, 0xa200, 0x00f0, 0x5a8e, 0x8086, 0x818e, 0x007c, + 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x5ab9, 0xa11a, 0x00c8, + 0x5ab9, 0x8213, 0x818d, 0x0048, 0x5aac, 0xa11a, 0x00c8, 0x5aad, + 0x00f0, 0x5aa1, 0x0078, 0x5ab1, 0xa11a, 0x2308, 0x8210, 0x00f0, + 0x5aa1, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, + 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x5ab5, 0x127e, + 0x2091, 0x2200, 0x2079, 0xa5ab, 0x127f, 0x0d7e, 0x2069, 0xa5ab, + 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a, + 0x0d7f, 0x007c, 0x0c7e, 0x6027, 0x0001, 0x7804, 0xa084, 0x0007, + 0x0079, 0x5ada, 0x5ae4, 0x5b09, 0x5b64, 0x5aea, 0x5b09, 0x5ae4, + 0x5ae2, 0x5ae2, 0x1078, 0x1328, 0x1078, 0x595a, 0x1078, 0x6109, + 0x0c7f, 0x007c, 0x62c0, 0x82ff, 0x00c0, 0x5af0, 0x0c7f, 0x007c, + 0x2011, 0x4129, 0x1078, 0x58d4, 0x7828, 0xa092, 0x00c8, 0x00c8, + 0x5aff, 0x8000, 0x782a, 0x1078, 0x4168, 0x0078, 0x5aee, 0x1078, + 0x4129, 0x7807, 0x0003, 0x7827, 0x0000, 0x782b, 0x0000, 0x0078, + 0x5aee, 0x1078, 0x595a, 0x3c00, 0x007e, 0x2011, 0x0209, 0x20e1, + 0x4000, 0x2214, 0x007f, 0x20e0, 0x82ff, 0x0040, 0x5b27, 0x62c0, + 0x82ff, 0x00c0, 0x5b27, 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, + 0x1328, 0x2009, 0x0013, 0x1078, 0x756c, 0x0c7f, 0x007c, 0x3900, + 0xa082, 0xa6cd, 0x00c8, 0x5b2e, 0x1078, 0x728a, 0x0c7e, 0x7824, + 0xa065, 0x1040, 0x1328, 0x7804, 0xa086, 0x0004, 0x0040, 0x5ba9, + 0x7828, 0xa092, 0x2710, 0x00c8, 0x5b44, 0x8000, 0x782a, 0x0c7f, + 0x1078, 0x6c33, 0x0078, 0x5b25, 0x6104, 0xa186, 0x0003, 0x00c0, + 0x5b5b, 0x0e7e, 0x2071, 0xa300, 0x70d4, 0x0e7f, 0xd08c, 0x0040, + 0x5b5b, 0x0c7e, 0x0e7e, 0x2061, 0x0100, 0x2071, 0xa300, 0x1078, + 0x4171, 0x0e7f, 0x0c7f, 0x1078, 0xa241, 0x2009, 0x0014, 0x1078, + 0x756c, 0x0c7f, 0x0078, 0x5b25, 0x2001, 0xa5c7, 0x2003, 0x0000, + 0x62c0, 0x82ff, 0x00c0, 0x5b78, 0x782b, 0x0000, 0x7824, 0xa065, + 0x1040, 0x1328, 0x2009, 0x0013, 0x1078, 0x75c3, 0x0c7f, 0x007c, + 0x0c7e, 0x0d7e, 0x3900, 0xa082, 0xa6cd, 0x00c8, 0x5b81, 0x1078, + 0x728a, 0x7824, 0xa005, 0x1040, 0x1328, 0x781c, 0xa06d, 0x1040, + 0x1328, 0x6800, 0xc0dc, 0x6802, 0x7924, 0x2160, 0x1078, 0x753d, + 0x693c, 0x81ff, 0x1040, 0x1328, 0x8109, 0x693e, 0x6854, 0xa015, + 0x0040, 0x5b9d, 0x7a1e, 0x0078, 0x5b9f, 0x7918, 0x791e, 0x7807, + 0x0000, 0x7827, 0x0000, 0x0d7f, 0x0c7f, 0x1078, 0x6109, 0x0078, + 0x5b76, 0x6104, 0xa186, 0x0002, 0x0040, 0x5bb4, 0xa186, 0x0004, + 0x0040, 0x5bb4, 0x0078, 0x5b38, 0x7808, 0xac06, 0x0040, 0x5b38, + 0x1078, 0x6010, 0x1078, 0x5c45, 0x0c7f, 0x1078, 0x6109, 0x0078, + 0x5b25, 0x0c7e, 0x6027, 0x0002, 0x62c8, 0x82ff, 0x00c0, 0x5bdb, + 0x62c4, 0x82ff, 0x00c0, 0x5bdb, 0x793c, 0xa1e5, 0x0000, 0x0040, + 0x5bd5, 0x2009, 0x0049, 0x1078, 0x756c, 0x2011, 0xa5ca, 0x2013, + 0x0000, 0x0c7f, 0x007c, 0x3908, 0xa192, 0xa6cd, 0x00c8, 0x5be2, + 0x1078, 0x728a, 0x6017, 0x0010, 0x793c, 0x81ff, 0x0040, 0x5bd5, + 0x793c, 0xa188, 0x0007, 0x210c, 0xa18e, 0x0006, 0x00c0, 0x5bf4, + 0x6017, 0x0012, 0x0078, 0x5bd9, 0x6017, 0x0016, 0x0078, 0x5bd9, + 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, + 0x2c08, 0x2061, 0xa5ab, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, + 0x0040, 0x5c13, 0xa080, 0x0003, 0x2102, 0x6112, 0x127f, 0x0c7f, + 0x017f, 0x007f, 0x007c, 0x6116, 0x6112, 0x0078, 0x5c0e, 0x0d7e, + 0x2069, 0xa5ab, 0x6000, 0xd0d4, 0x0040, 0x5c2c, 0x6820, 0x8000, + 0x6822, 0xa086, 0x0001, 0x00c0, 0x5c27, 0x2c00, 0x681e, 0x6804, + 0xa084, 0x0007, 0x0079, 0x6111, 0xc0d5, 0x6002, 0x6818, 0xa005, + 0x0040, 0x5c3e, 0x6056, 0x605b, 0x0000, 0x007e, 0x2c00, 0x681a, + 0x0d7f, 0x685a, 0x2069, 0xa5ab, 0x0078, 0x5c1e, 0x6056, 0x605a, + 0x2c00, 0x681a, 0x681e, 0x0078, 0x5c1e, 0x007e, 0x017e, 0x0c7e, + 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xa5ab, + 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0040, 0x5c60, 0xa080, + 0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, + 0x610e, 0x610a, 0x0078, 0x5c5b, 0x0c7e, 0x600f, 0x0000, 0x2c08, + 0x2061, 0xa5ab, 0x6034, 0xa005, 0x0040, 0x5c74, 0xa080, 0x0003, + 0x2102, 0x6136, 0x0c7f, 0x007c, 0x613a, 0x6136, 0x0078, 0x5c72, + 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x017e, 0x007e, + 0x127e, 0x2071, 0xa5ab, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, + 0x8cff, 0x0040, 0x5ced, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, + 0x00c0, 0x5ce8, 0x87ff, 0x0040, 0x5c99, 0x6020, 0xa106, 0x00c0, + 0x5ce8, 0x703c, 0xac06, 0x00c0, 0x5cab, 0x037e, 0x2019, 0x0001, + 0x1078, 0x6e6c, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, + 0x7047, 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x5cb1, 0x660c, + 0x763a, 0x7034, 0xac36, 0x00c0, 0x5cbf, 0x2c00, 0xaf36, 0x0040, + 0x5cbd, 0x2f00, 0x7036, 0x0078, 0x5cbf, 0x7037, 0x0000, 0x660c, + 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5cc8, 0x7e0e, 0x0078, 0x5cc9, + 0x2678, 0x600f, 0x0000, 0x1078, 0x8a44, 0x0040, 0x5ce3, 0x6010, + 0x2068, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5cf7, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, 0xa181, 0x1078, + 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x5c88, + 0x2c78, 0x600c, 0x2060, 0x0078, 0x5c88, 0x127f, 0x007f, 0x017f, + 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, + 0xa086, 0x0006, 0x00c0, 0x5cd6, 0x1078, 0xa181, 0x1078, 0x9e70, + 0x0078, 0x5ce3, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, + 0x0000, 0x127e, 0x2091, 0x8000, 0x2079, 0xa5ab, 0x7838, 0xa065, + 0x0040, 0x5d41, 0x600c, 0x007e, 0x600f, 0x0000, 0x783c, 0xac06, + 0x00c0, 0x5d28, 0x037e, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x7833, + 0x0000, 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000, 0x037f, + 0x1078, 0x8a44, 0x0040, 0x5d3c, 0x6010, 0x2068, 0x601c, 0xa086, + 0x0003, 0x00c0, 0x5d4a, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x007f, 0x0078, + 0x5d0f, 0x7e3a, 0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, 0x067f, + 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5d33, 0x1078, + 0x9e70, 0x0078, 0x5d3c, 0x017e, 0x027e, 0x087e, 0x2041, 0x0000, + 0x1078, 0x5d6d, 0x1078, 0x5e21, 0x087f, 0x027f, 0x017f, 0x007c, + 0x0f7e, 0x127e, 0x2079, 0xa5ab, 0x2091, 0x8000, 0x1078, 0x5ebc, + 0x1078, 0x5f32, 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, + 0x0c7e, 0x067e, 0x017e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, + 0xa5ab, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5e01, 0x6018, + 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x5dfc, 0x88ff, 0x0040, + 0x5d8d, 0x6020, 0xa106, 0x00c0, 0x5dfc, 0x7024, 0xac06, 0x00c0, + 0x5dbd, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x5db8, 0x1078, + 0x595a, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, + 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, + 0x5dad, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, + 0xd084, 0x0040, 0x5db5, 0x6827, 0x0001, 0x037f, 0x0078, 0x5dbd, + 0x6003, 0x0009, 0x630a, 0x0078, 0x5dfc, 0x7014, 0xac36, 0x00c0, + 0x5dc3, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x5dd1, 0x2c00, + 0xaf36, 0x0040, 0x5dcf, 0x2f00, 0x7012, 0x0078, 0x5dd1, 0x7013, + 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5dda, 0x7e0e, + 0x0078, 0x5ddb, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, + 0x8a44, 0x0040, 0x5df5, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5e0a, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, + 0xa181, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x1078, + 0x7045, 0x0c7f, 0x0078, 0x5d7c, 0x2c78, 0x600c, 0x2060, 0x0078, + 0x5d7c, 0x127f, 0x007f, 0x017f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, + 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5e15, 0x1078, + 0xa181, 0x1078, 0x9e70, 0x0078, 0x5df5, 0x601c, 0xa086, 0x0002, + 0x00c0, 0x5df5, 0x6004, 0xa086, 0x0085, 0x0040, 0x5de8, 0x0078, + 0x5df5, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0xa280, 0xa434, + 0x2004, 0xa065, 0x0040, 0x5eb8, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e, + 0x2071, 0xa5ab, 0x6654, 0x7018, 0xac06, 0x00c0, 0x5e38, 0x761a, + 0x701c, 0xac06, 0x00c0, 0x5e44, 0x86ff, 0x00c0, 0x5e43, 0x7018, + 0x701e, 0x0078, 0x5e44, 0x761e, 0x6058, 0xa07d, 0x0040, 0x5e49, + 0x7e56, 0xa6ed, 0x0000, 0x0040, 0x5e4f, 0x2f00, 0x685a, 0x6057, + 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, + 0x4410, 0x0040, 0x5eb4, 0x7624, 0x86ff, 0x0040, 0x5ea2, 0xa680, + 0x0004, 0x2004, 0xad06, 0x00c0, 0x5ea2, 0x0d7e, 0x2069, 0x0100, + 0x68c0, 0xa005, 0x0040, 0x5e99, 0x1078, 0x595a, 0x1078, 0x6c41, + 0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5e82, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5e8a, + 0x6827, 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, + 0x5e93, 0x8001, 0x603e, 0x2660, 0x1078, 0x8c01, 0x0c7f, 0x0078, + 0x5ea2, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, + 0x0078, 0x5e57, 0x8dff, 0x0040, 0x5eb0, 0x6837, 0x0103, 0x6b4a, + 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, 0xa181, 0x1078, 0x4982, + 0x1078, 0x7045, 0x0078, 0x5e57, 0x067f, 0x0d7f, 0x0e7f, 0x0f7f, + 0x127f, 0x007f, 0x0c7f, 0x007c, 0x007e, 0x067e, 0x0c7e, 0x0d7e, + 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x5f16, 0x600c, 0x007e, + 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x5efb, 0x2069, 0x0100, + 0x68c0, 0xa005, 0x0040, 0x5ef5, 0x1078, 0x595a, 0x1078, 0x6c41, + 0x68c3, 0x0000, 0x1078, 0x7188, 0x7827, 0x0000, 0x037e, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5eea, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5ef2, + 0x6827, 0x0001, 0x037f, 0x0078, 0x5efb, 0x6003, 0x0009, 0x630a, + 0x2c30, 0x0078, 0x5f13, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, + 0x5f0f, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5f1d, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, + 0x8c01, 0x1078, 0x7045, 0x007f, 0x0078, 0x5ec3, 0x7e16, 0x7e12, + 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, + 0x00c0, 0x5f26, 0x1078, 0x9e70, 0x0078, 0x5f0f, 0x601c, 0xa086, + 0x0002, 0x00c0, 0x5f0f, 0x6004, 0xa086, 0x0085, 0x0040, 0x5f06, + 0x0078, 0x5f0f, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x7818, 0xa065, + 0x0040, 0x5fa0, 0x6054, 0x007e, 0x6057, 0x0000, 0x605b, 0x0000, + 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x4410, 0x0040, 0x5f9d, + 0x7e24, 0x86ff, 0x0040, 0x5f8f, 0xa680, 0x0004, 0x2004, 0xad06, + 0x00c0, 0x5f8f, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, + 0x5f86, 0x1078, 0x595a, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, + 0x7188, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, + 0x1000, 0x0040, 0x5f6f, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0040, 0x5f77, 0x6827, 0x0001, 0x037f, + 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x5f80, 0x8001, 0x603e, + 0x2660, 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x5f8f, 0x0d7f, 0x0c7e, + 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x5f44, 0x8dff, + 0x0040, 0x5f99, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, + 0x4982, 0x1078, 0x7045, 0x0078, 0x5f44, 0x007f, 0x0078, 0x5f37, + 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x0e7e, + 0x0d7e, 0x067e, 0x6000, 0xd0dc, 0x0040, 0x5fc4, 0x604c, 0xa06d, + 0x0040, 0x5fc4, 0x6848, 0xa606, 0x00c0, 0x5fc4, 0x2071, 0xa5ab, + 0x7024, 0xa035, 0x0040, 0x5fc4, 0xa080, 0x0004, 0x2004, 0xad06, + 0x00c0, 0x5fc4, 0x1078, 0x5fc8, 0x067f, 0x0d7f, 0x0e7f, 0x007c, + 0x0f7e, 0x2079, 0x0100, 0x78c0, 0xa005, 0x00c0, 0x5fd7, 0x0c7e, + 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x600e, 0x1078, + 0x6c41, 0x78c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, + 0x2079, 0x0140, 0x7b04, 0xa384, 0x1000, 0x0040, 0x5feb, 0x7803, + 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, 0x7824, 0xd084, 0x0040, + 0x5ff3, 0x7827, 0x0001, 0x1078, 0x7188, 0x037f, 0x1078, 0x4410, + 0x0c7e, 0x603c, 0xa005, 0x0040, 0x5fff, 0x8001, 0x603e, 0x2660, + 0x1078, 0x753d, 0x0c7f, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x1078, 0x8cb8, 0x1078, 0x4982, 0x1078, 0x7045, 0x0f7f, 0x007c, + 0x0e7e, 0x0c7e, 0x2071, 0xa5ab, 0x7004, 0xa084, 0x0007, 0x0079, + 0x6019, 0x6023, 0x6026, 0x603f, 0x605b, 0x60a0, 0x6023, 0x6023, + 0x6021, 0x1078, 0x1328, 0x0c7f, 0x0e7f, 0x007c, 0x7024, 0xa065, + 0x0040, 0x6034, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0040, + 0x603b, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, + 0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x6034, 0x6018, + 0x2060, 0x1078, 0x4410, 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, + 0x7022, 0x0040, 0x6050, 0x6054, 0xa015, 0x0040, 0x6057, 0x721e, + 0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7218, + 0x721e, 0x0078, 0x6050, 0x7024, 0xa065, 0x0040, 0x609d, 0x700c, + 0xac06, 0x00c0, 0x6072, 0x1078, 0x7045, 0x600c, 0xa015, 0x0040, + 0x606e, 0x720e, 0x600f, 0x0000, 0x0078, 0x609b, 0x720e, 0x720a, + 0x0078, 0x609b, 0x7014, 0xac06, 0x00c0, 0x6085, 0x1078, 0x7045, + 0x600c, 0xa015, 0x0040, 0x6081, 0x7216, 0x600f, 0x0000, 0x0078, + 0x609b, 0x7216, 0x7212, 0x0078, 0x609b, 0x6018, 0x2060, 0x1078, + 0x4410, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x7045, 0x701c, 0xa065, + 0x0040, 0x609b, 0x6054, 0xa015, 0x0040, 0x6099, 0x721e, 0x0078, + 0x609b, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, + 0x7024, 0xa065, 0x0040, 0x60ad, 0x1078, 0x7045, 0x600c, 0xa015, + 0x0040, 0x60b4, 0x720e, 0x600f, 0x0000, 0x1078, 0x7188, 0x7027, + 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a, 0x0078, 0x60ad, + 0x0d7e, 0x2069, 0xa5ab, 0x6830, 0xa084, 0x0003, 0x0079, 0x60c0, + 0x60c6, 0x60c8, 0x60ee, 0x60c6, 0x1078, 0x1328, 0x0d7f, 0x007c, + 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x60e4, 0x683c, 0xa065, + 0x0040, 0x60d9, 0x600c, 0xa015, 0x0040, 0x60e0, 0x6a3a, 0x600f, + 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c7f, 0x0d7f, 0x007c, + 0x683a, 0x6836, 0x0078, 0x60d9, 0x6843, 0x0000, 0x6838, 0xa065, + 0x0040, 0x60d9, 0x6003, 0x0003, 0x0078, 0x60d9, 0x0c7e, 0x6843, + 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x6106, 0x600c, + 0xa015, 0x0040, 0x6102, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, + 0x0078, 0x6106, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, 0x0d7f, + 0x007c, 0x0d7e, 0x2069, 0xa5ab, 0x6804, 0xa084, 0x0007, 0x0079, + 0x6111, 0x611b, 0x61c2, 0x61c2, 0x61c2, 0x61c2, 0x61c4, 0x61c2, + 0x6119, 0x1078, 0x1328, 0x6820, 0xa005, 0x00c0, 0x6121, 0x0d7f, + 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x6130, 0x6807, 0x0004, + 0x6826, 0x682b, 0x0000, 0x1078, 0x620a, 0x0c7f, 0x0d7f, 0x007c, + 0x6814, 0xa065, 0x0040, 0x613e, 0x6807, 0x0001, 0x6826, 0x682b, + 0x0000, 0x1078, 0x620a, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, 0x037e, + 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x61bd, 0x704c, 0xa00d, 0x0040, + 0x614d, 0x7088, 0xa005, 0x0040, 0x6165, 0x7054, 0xa075, 0x0040, + 0x6156, 0xa20e, 0x0040, 0x61bd, 0x0078, 0x615b, 0x6818, 0xa20e, + 0x0040, 0x61bd, 0x2070, 0x704c, 0xa00d, 0x0040, 0x614d, 0x7088, + 0xa005, 0x00c0, 0x614d, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, + 0x00c8, 0x614d, 0x1078, 0x750c, 0x0040, 0x61bd, 0x8318, 0x733e, + 0x6112, 0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, 0xa084, 0x00ff, + 0x6032, 0xa180, 0x0014, 0x2003, 0x0000, 0xa180, 0x0015, 0x2004, + 0xa08a, 0x199a, 0x0048, 0x6186, 0x2001, 0x1999, 0x8003, 0x801b, + 0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc, + 0x0040, 0x619f, 0x7100, 0xd1f4, 0x0040, 0x619b, 0x7114, 0xa18c, + 0x00ff, 0x0078, 0x61a4, 0x2009, 0x0000, 0x0078, 0x61a4, 0xa1e0, + 0x293f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, + 0x679b, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, + 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, + 0x0f7f, 0x0e7f, 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f, + 0x0078, 0x61bb, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, + 0x61d0, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x620a, + 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0xa5ab, 0x6830, + 0xa086, 0x0000, 0x00c0, 0x61f1, 0x6838, 0xa07d, 0x0040, 0x61f1, + 0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091, + 0x2200, 0x027f, 0x1078, 0x1d28, 0x00c0, 0x61f4, 0x127f, 0x1078, + 0x6ae5, 0x0d7f, 0x0f7f, 0x007c, 0x127f, 0x6843, 0x0000, 0x7803, + 0x0002, 0x780c, 0xa015, 0x0040, 0x6206, 0x6a3a, 0x780f, 0x0000, + 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x61f1, 0x683a, 0x6836, + 0x0078, 0x6200, 0x601c, 0xa084, 0x000f, 0x1079, 0x6210, 0x007c, + 0x6219, 0x621e, 0x663f, 0x6758, 0x621e, 0x663f, 0x6758, 0x6219, + 0x621e, 0x1078, 0x6010, 0x1078, 0x6109, 0x007c, 0x157e, 0x137e, + 0x147e, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0044, 0x10c8, 0x1328, + 0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x623b, 0x7900, 0xd1f4, + 0x0040, 0x6237, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x6240, 0x2009, + 0x0000, 0x0078, 0x6240, 0xa1f8, 0x293f, 0x2f0c, 0xa18c, 0x00ff, + 0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x00c8, 0x6292, + 0x1079, 0x6250, 0x0f7f, 0x0c7f, 0x147f, 0x137f, 0x157f, 0x007c, + 0x62f8, 0x6340, 0x6368, 0x6403, 0x6433, 0x643b, 0x6462, 0x6473, + 0x6484, 0x648c, 0x64a4, 0x648c, 0x650f, 0x6473, 0x6530, 0x6538, + 0x6484, 0x6538, 0x6549, 0x6290, 0x6290, 0x6290, 0x6290, 0x6290, + 0x6290, 0x6290, 0x6290, 0x6290, 0x6290, 0x6290, 0x6d05, 0x6d2a, + 0x6d3f, 0x6d62, 0x6d83, 0x6462, 0x6290, 0x6462, 0x648c, 0x6290, + 0x6368, 0x6403, 0x6290, 0x72ac, 0x648c, 0x6290, 0x72cc, 0x648c, + 0x6290, 0x6290, 0x62f3, 0x62a1, 0x6290, 0x72f1, 0x7368, 0x7450, + 0x6290, 0x7461, 0x645c, 0x747d, 0x6290, 0x6d98, 0x6290, 0x6290, + 0x1078, 0x1328, 0x2100, 0x1079, 0x629b, 0x0f7f, 0x0c7f, 0x147f, + 0x137f, 0x157f, 0x007c, 0x629f, 0x629f, 0x629f, 0x62d5, 0x1078, + 0x1328, 0x0d7e, 0x20a1, 0x020b, 0x1078, 0x6567, 0x7810, 0x2068, + 0x20a3, 0x2414, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x683c, 0x20a2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x6850, 0x20a2, 0x6854, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0018, 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x0d7e, 0x7818, + 0x2068, 0x68a0, 0xa082, 0x007e, 0x0048, 0x62d2, 0xa085, 0x0001, + 0x0d7f, 0x007c, 0xa006, 0x0078, 0x62d0, 0x0d7e, 0x20a1, 0x020b, + 0x1078, 0x6567, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x7810, 0xa0e8, + 0x000f, 0x6808, 0x20a2, 0x680c, 0x20a2, 0x6810, 0x20a2, 0x6814, + 0x20a2, 0x6818, 0x20a2, 0x681c, 0x20a2, 0x60c3, 0x0010, 0x1078, + 0x6c2d, 0x0d7f, 0x007c, 0x6030, 0x609a, 0x1078, 0x6c2d, 0x007c, + 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x5200, 0x20a3, 0x0000, + 0x0d7e, 0x2069, 0xa351, 0x6804, 0xd084, 0x0040, 0x6312, 0x6828, + 0x20a3, 0x0000, 0x017e, 0x1078, 0x24fa, 0x21a2, 0x017f, 0x0d7f, + 0x0078, 0x6317, 0x0d7f, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, + 0x0004, 0x2099, 0xa305, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa301, + 0x53a6, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0048, + 0x6331, 0x2001, 0xa31a, 0x20a6, 0x2001, 0xa31b, 0x20a6, 0x0078, + 0x6337, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, 0x6c2d, 0x007c, + 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x0500, 0x20a3, 0x0000, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0048, 0x6358, + 0x2001, 0xa31a, 0x20a6, 0x2001, 0xa31b, 0x20a6, 0x0078, 0x635e, + 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a9, 0x0004, + 0x2099, 0xa305, 0x53a6, 0x60c3, 0x0010, 0x1078, 0x6c2d, 0x007c, + 0x20a1, 0x020b, 0x1078, 0x6567, 0x0c7e, 0x7818, 0x2060, 0x2001, + 0x0000, 0x1078, 0x48a2, 0x0c7f, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa086, 0x007e, 0x00c0, 0x6383, 0x20a3, 0x0400, 0x620c, 0xc2b4, + 0x620e, 0x0078, 0x6385, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, + 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, 0x63d2, 0x2099, + 0xa58c, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, 0xa084, 0x3fff, + 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0xa305, 0x53a6, + 0x20a9, 0x0004, 0x2099, 0xa301, 0x53a6, 0x20a9, 0x0010, 0x20a3, + 0x0000, 0x00f0, 0x63af, 0x2099, 0xa594, 0x3304, 0xc0dd, 0x20a2, + 0x2001, 0xa371, 0x2004, 0xd0e4, 0x0040, 0x63ca, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x9398, 0x9398, 0x9398, 0x33a6, 0x20a9, 0x0004, + 0x0078, 0x63cc, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x00f0, 0x63cc, + 0x0078, 0x63f2, 0x2099, 0xa58c, 0x20a9, 0x0008, 0x53a6, 0x20a9, + 0x0004, 0x2099, 0xa305, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa301, + 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63e3, 0x20a9, + 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63e9, 0x2099, 0xa594, 0x20a9, + 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63f4, + 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x63fa, 0x60c3, 0x0074, + 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, + 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa351, + 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x641f, 0xa085, 0x0020, 0xd1a4, + 0x0040, 0x6424, 0xa085, 0x0010, 0xa085, 0x0002, 0x0d7e, 0x0078, + 0x64ed, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, + 0x5000, 0x0078, 0x6385, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, + 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65ef, + 0x0078, 0x6466, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, + 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, + 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, + 0x0008, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8, + 0x20a3, 0x0200, 0x0078, 0x6385, 0x20a1, 0x020b, 0x1078, 0x65f8, + 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0xa005, 0x0040, 0x649b, + 0x20a2, 0x0078, 0x649d, 0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3, + 0x0008, 0x1078, 0x6c2d, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, + 0x65f8, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818, + 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x64ca, 0x6998, 0xa184, + 0xc000, 0x00c0, 0x64c6, 0xd1ec, 0x0040, 0x64c2, 0x20a3, 0x2100, + 0x0078, 0x64cc, 0x20a3, 0x0100, 0x0078, 0x64cc, 0x20a3, 0x0400, + 0x0078, 0x64cc, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa351, 0x7904, 0x0f7f, 0xd1ac, + 0x00c0, 0x64dc, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x64e1, 0xa085, + 0x0010, 0x2009, 0xa373, 0x210c, 0xd184, 0x0040, 0x64eb, 0x699c, + 0xd18c, 0x0040, 0x64ed, 0xa085, 0x0002, 0x027e, 0x2009, 0xa371, + 0x210c, 0xd1e4, 0x0040, 0x64fb, 0xc0c5, 0xa094, 0x0030, 0xa296, + 0x0010, 0x0040, 0x6505, 0xd1ec, 0x0040, 0x6505, 0xa094, 0x0030, + 0xa296, 0x0010, 0x0040, 0x6505, 0xc0bd, 0x027f, 0x20a2, 0x20a2, + 0x20a2, 0x60c3, 0x0014, 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x20a1, + 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, + 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x6c2d, 0x007c, + 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, 0x0078, 0x62fe, + 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x1078, 0x6c2d, + 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078, + 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, + 0x0000, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x007c, 0x027e, 0x037e, + 0x047e, 0x2019, 0x3200, 0x2021, 0x0800, 0x0078, 0x656e, 0x027e, + 0x037e, 0x047e, 0x2019, 0x2200, 0x2021, 0x0100, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, + 0x00c0, 0x6581, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffe, 0x0078, + 0x65b6, 0xa286, 0x007f, 0x00c0, 0x658d, 0x0d7e, 0xa385, 0x00ff, + 0x20a2, 0x20a3, 0xfffd, 0x0078, 0x65a4, 0xd2bc, 0x0040, 0x65ac, + 0xa286, 0x0080, 0x0d7e, 0x00c0, 0x659c, 0xa385, 0x00ff, 0x20a2, + 0x20a3, 0xfffc, 0x0078, 0x65a4, 0xa2e8, 0xa434, 0x2d6c, 0x6810, + 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x65ba, 0x0d7e, 0xa2e8, 0xa434, 0x2d6c, + 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0xa485, 0x0029, 0x20a2, 0x047f, 0x037f, 0x20a3, + 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, + 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, 0xfffc, + 0x22a2, 0x0d7e, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, + 0x20a3, 0x2029, 0x20a3, 0x0000, 0x0078, 0x65c1, 0x20a3, 0x0100, + 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x007c, 0x027e, + 0x037e, 0x047e, 0x2019, 0x3300, 0x2021, 0x0800, 0x0078, 0x65ff, + 0x027e, 0x037e, 0x047e, 0x2019, 0x2300, 0x2021, 0x0100, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, + 0x007e, 0x0048, 0x661c, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, + 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x662a, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, + 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3, 0x0000, 0x047f, + 0x037f, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, + 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0c7e, + 0x0f7e, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1328, 0xa08a, 0x008c, + 0x10c8, 0x1328, 0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x665d, + 0x7900, 0xd1f4, 0x0040, 0x6659, 0x7914, 0xa18c, 0x00ff, 0x0078, + 0x6662, 0x2009, 0x0000, 0x0078, 0x6662, 0xa1f8, 0x293f, 0x2f0c, + 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, + 0x1079, 0x666d, 0x0f7f, 0x0c7f, 0x007c, 0x6676, 0x6681, 0x669c, + 0x6674, 0x6674, 0x6674, 0x6676, 0x1078, 0x1328, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x66af, 0x60c3, 0x0000, 0x1078, 0x6c2d, 0x147f, + 0x007c, 0x147e, 0x20a1, 0x020b, 0x1078, 0x66e3, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000, + 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, + 0x1078, 0x6c2d, 0x147f, 0x007c, 0x147e, 0x20a1, 0x020b, 0x1078, + 0x6724, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0004, 0x1078, 0x6c2d, 0x147f, 0x007c, 0x027e, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa092, 0x007e, 0x0048, 0x66ce, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, + 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x66dd, 0x0d7e, 0xa0e8, + 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, + 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3, + 0x0000, 0x0078, 0x65c1, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x6702, + 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, + 0x0078, 0x6711, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, + 0x8400, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, + 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, + 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x7a10, 0x22a2, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, + 0x6743, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8500, + 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, + 0x0d7f, 0x0078, 0x6752, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, + 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x0078, 0x6715, + 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, 0x1048, 0x1328, + 0xa08a, 0x0053, 0x10c8, 0x1328, 0x7918, 0x2160, 0x61a0, 0xd1bc, + 0x0040, 0x6777, 0x6100, 0xd1f4, 0x0040, 0x6773, 0x6114, 0xa18c, + 0x00ff, 0x0078, 0x677c, 0x2009, 0x0000, 0x0078, 0x677c, 0xa1e0, + 0x293f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0xa082, + 0x0040, 0x1079, 0x6786, 0x0f7f, 0x0c7f, 0x007c, 0x679b, 0x68a9, + 0x684a, 0x6a59, 0x6799, 0x6799, 0x6799, 0x6799, 0x6799, 0x6799, + 0x6799, 0x6f5e, 0x6f6f, 0x6f80, 0x6f91, 0x6799, 0x748e, 0x6799, + 0x6f4d, 0x1078, 0x1328, 0x0d7e, 0x157e, 0x147e, 0x780b, 0xffff, + 0x20a1, 0x020b, 0x1078, 0x6806, 0x7910, 0x2168, 0x6948, 0x7922, + 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x000f, + 0x00c0, 0x67b6, 0x2001, 0x0005, 0x0078, 0x67c0, 0xd184, 0x0040, + 0x67bd, 0x2001, 0x0004, 0x0078, 0x67c0, 0xa084, 0x0006, 0x8004, + 0x017e, 0x2008, 0x7830, 0xa084, 0x00ff, 0x8007, 0xa105, 0x017f, + 0x20a2, 0xd1ac, 0x0040, 0x67d0, 0x20a3, 0x0002, 0x0078, 0x67dc, + 0xd1b4, 0x0040, 0x67d7, 0x20a3, 0x0001, 0x0078, 0x67dc, 0x20a3, + 0x0000, 0x2230, 0x0078, 0x67de, 0x6a80, 0x6e7c, 0x20a9, 0x0008, + 0xad80, 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, 0x67e2, + 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084, + 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xa5c7, 0x2003, 0x07d0, + 0x2001, 0xa5c6, 0x2003, 0x0009, 0x2001, 0xa5cc, 0x2003, 0x0002, + 0x1078, 0x157e, 0x147f, 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, + 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, + 0x0040, 0x682c, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, + 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x683b, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, + 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, + 0x0000, 0x6130, 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, 0x22a2, + 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b, + 0x1078, 0x686a, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, + 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x60c3, 0x000c, 0x1078, 0x6c2d, 0x147f, 0x137f, 0x157f, + 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6888, 0x0d7e, 0xa0e8, + 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6897, + 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, + 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, + 0x0889, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, + 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, + 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x7810, 0xa06d, 0x1078, + 0x488f, 0x0040, 0x68bd, 0x684c, 0xa084, 0x2020, 0xa086, 0x2020, + 0x00c0, 0x68bd, 0x7824, 0xc0cd, 0x7826, 0x20a1, 0x020b, 0x1078, + 0x6a12, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, + 0xa084, 0xf000, 0x00c0, 0x68d4, 0x7810, 0xa084, 0x0700, 0x8007, + 0x1079, 0x68dc, 0x0078, 0x68d7, 0xa006, 0x1079, 0x68dc, 0x147f, + 0x137f, 0x157f, 0x0d7f, 0x007c, 0x68e6, 0x697e, 0x6989, 0x69b3, + 0x69c7, 0x69e3, 0x69ee, 0x68e4, 0x1078, 0x1328, 0x017e, 0x037e, + 0x694c, 0xa18c, 0x0003, 0x0040, 0x68f1, 0xa186, 0x0003, 0x00c0, + 0x6900, 0x6b78, 0x7824, 0xd0cc, 0x0040, 0x68f7, 0xc3e5, 0x23a2, + 0x6868, 0x20a2, 0x6864, 0x20a2, 0x037f, 0x017f, 0x0078, 0x69be, + 0xa186, 0x0001, 0x10c0, 0x1328, 0x6b78, 0x7824, 0xd0cc, 0x0040, + 0x690a, 0xc3e5, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, + 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, + 0x0300, 0x0040, 0x6978, 0xd3c4, 0x0040, 0x6920, 0x687c, 0xa108, + 0xd3cc, 0x0040, 0x6925, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, + 0xad80, 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x692a, + 0x157f, 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x6978, + 0x20a1, 0x020b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x007e, 0x7818, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6958, 0x0d7e, 0xa0e8, + 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6967, + 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, + 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x007f, + 0x7b24, 0xd3cc, 0x0040, 0x6970, 0x20a3, 0x0889, 0x0078, 0x6972, + 0x20a3, 0x0898, 0x20a2, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, + 0x61c2, 0x037f, 0x017f, 0x1078, 0x6c2d, 0x007c, 0x2011, 0x0008, + 0x7824, 0xd0cc, 0x0040, 0x6985, 0xc2e5, 0x22a2, 0xa016, 0x0078, + 0x69bc, 0x2011, 0x0302, 0x7824, 0xd0cc, 0x0040, 0x6990, 0xc2e5, + 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, + 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, + 0x20a3, 0x0500, 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, + 0x2500, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, + 0x1078, 0x6c2d, 0x007c, 0x2011, 0x0028, 0x7824, 0xd0cc, 0x0040, + 0x69ba, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x1078, 0x6c2d, 0x007c, 0x2011, + 0x0100, 0x7824, 0xd0cc, 0x0040, 0x69ce, 0xc2e5, 0x22a2, 0xa016, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, 0x22a2, + 0x7834, 0xa084, 0x00ff, 0x20a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, + 0x1078, 0x6c2d, 0x007c, 0x2011, 0x0008, 0x7824, 0xd0cc, 0x0040, + 0x69ea, 0xc2e5, 0x22a2, 0xa016, 0x0078, 0x69bc, 0x037e, 0x7b10, + 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x6a01, + 0x7824, 0xd0cc, 0x0040, 0x69fd, 0xc2e5, 0x22a2, 0x037f, 0x0078, + 0x69bc, 0x047e, 0x2021, 0x0800, 0x007e, 0x7824, 0xd0cc, 0x007f, + 0x0040, 0x6a0b, 0xc4e5, 0x24a2, 0x047f, 0x22a2, 0x20a2, 0x037f, + 0x0078, 0x69be, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6a30, 0x0d7e, 0xa0e8, + 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6a3f, + 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, + 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x7824, + 0xd0cc, 0x0040, 0x6a47, 0x20a3, 0x0889, 0x0078, 0x6a49, 0x20a3, + 0x0898, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, + 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, + 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x017e, 0x037e, 0x7810, + 0xa084, 0x0700, 0x8007, 0x1079, 0x6a6c, 0x037f, 0x017f, 0x147f, + 0x137f, 0x157f, 0x0d7f, 0x007c, 0x6a74, 0x6a74, 0x6a76, 0x6a74, + 0x6a74, 0x6a74, 0x6a9b, 0x6a74, 0x1078, 0x1328, 0x7910, 0xa18c, + 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, + 0x1078, 0x6aa5, 0x0d7e, 0x2069, 0xa351, 0x6804, 0xd0bc, 0x0040, + 0x6a90, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, 0x6a92, + 0x20a3, 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, + 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, + 0x6aa5, 0x20a3, 0x7f00, 0x0078, 0x6a93, 0x027e, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, + 0x6ac3, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0100, + 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, + 0x0d7f, 0x0078, 0x6ad2, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, + 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x1078, + 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, + 0x057e, 0x047e, 0x037e, 0x2061, 0x0100, 0x2071, 0xa300, 0x6130, + 0x7818, 0x2068, 0x68a0, 0x2028, 0xd0bc, 0x00c0, 0x6afc, 0x6910, + 0x6a14, 0x6430, 0x0078, 0x6b00, 0x6910, 0x6a14, 0x7368, 0x746c, + 0x781c, 0xa086, 0x0006, 0x0040, 0x6b5f, 0xd5bc, 0x0040, 0x6b10, + 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, 0x6b17, + 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073, + 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, + 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, + 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, + 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, + 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x6b49, 0x6a00, 0xd2f4, + 0x0040, 0x6b47, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6b49, 0x2011, + 0x0000, 0x629e, 0x6017, 0x0016, 0x2009, 0x07d0, 0x60c4, 0xa084, + 0xfff0, 0xa005, 0x0040, 0x6b56, 0x2009, 0x1b58, 0x1078, 0x595f, + 0x037f, 0x047f, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810, + 0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x6bb7, + 0xd5bc, 0x0040, 0x6b73, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, + 0x646e, 0x0078, 0x6b7a, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, + 0x0000, 0x646e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, + 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, + 0x6086, 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, + 0x60c6, 0x707c, 0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, + 0x7928, 0xa109, 0x792a, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, + 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x6bb2, 0x6a00, + 0xd2f4, 0x0040, 0x6bb0, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6bb2, + 0x2011, 0x0000, 0x629e, 0x6017, 0x0012, 0x0078, 0x6b4c, 0xd5bc, + 0x0040, 0x6bc2, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, + 0x0078, 0x6bc9, 0xa185, 0x0700, 0x6062, 0x6266, 0x606b, 0x0000, + 0x646e, 0x1078, 0x488f, 0x0040, 0x6bdf, 0x0d7e, 0x7810, 0xa06d, + 0x684c, 0x0d7f, 0xa084, 0x2020, 0xa086, 0x2020, 0x00c0, 0x6bdf, + 0x7824, 0xc0cd, 0x7826, 0x6073, 0x0889, 0x0078, 0x6be1, 0x6073, + 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, + 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, + 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, + 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0xa582, 0x0080, 0x0048, 0x6c0f, 0x6a00, 0xd2f4, 0x0040, 0x6c0d, + 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6c0f, 0x2011, 0x0000, 0x629e, + 0x7824, 0xd0cc, 0x0040, 0x6c18, 0x6017, 0x0016, 0x0078, 0x6b4c, + 0x6017, 0x0012, 0x0078, 0x6b4c, 0x7a18, 0xa280, 0x0023, 0x2014, + 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, 0x2069, + 0xa5ab, 0x6843, 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x60a3, + 0x0056, 0x60a7, 0x9575, 0x1078, 0x6c38, 0x1078, 0x594f, 0x007c, + 0x007e, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x007f, + 0x007c, 0x007e, 0x0c7e, 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, + 0xa085, 0x0008, 0x6016, 0x0c7f, 0x007f, 0x007c, 0x0c7e, 0x0d7e, + 0x017e, 0x027e, 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194, + 0x4000, 0x0040, 0x6c89, 0x1078, 0x6c41, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0c7e, 0x2061, 0xa5ab, 0x6128, 0xa192, 0x00c8, 0x00c8, + 0x6c76, 0x8108, 0x612a, 0x6124, 0x0c7f, 0x81ff, 0x0040, 0x6c84, + 0x1078, 0x594f, 0x1078, 0x6c38, 0x0078, 0x6c84, 0x6124, 0xa1e5, + 0x0000, 0x0040, 0x6c81, 0x1078, 0xa241, 0x2009, 0x0014, 0x1078, + 0x756c, 0x0c7f, 0x0078, 0x6c84, 0x027f, 0x017f, 0x0d7f, 0x0c7f, + 0x007c, 0x2001, 0xa5c7, 0x2004, 0xa005, 0x00c0, 0x6c84, 0x0c7e, + 0x2061, 0xa5ab, 0x6128, 0xa192, 0x0003, 0x00c8, 0x6c76, 0x8108, + 0x612a, 0x0c7f, 0x1078, 0x594f, 0x1078, 0x4171, 0x0078, 0x6c84, + 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x5967, 0x2071, + 0xa5ab, 0x713c, 0x81ff, 0x0040, 0x6cca, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x6cd0, 0x6803, 0x1000, + 0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x037f, + 0x713c, 0x2160, 0x1078, 0xa241, 0x2009, 0x004a, 0x1078, 0x756c, + 0x0078, 0x6cca, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, + 0x0078, 0x6cba, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, 0x047e, + 0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, 0x2071, + 0xa5ab, 0x7018, 0x2068, 0x8dff, 0x0040, 0x6cfc, 0x68a0, 0xa406, + 0x0040, 0x6cee, 0x6854, 0x2068, 0x0078, 0x6ce3, 0x6010, 0x2060, + 0x643c, 0x6540, 0x6e48, 0x2d60, 0x1078, 0x466a, 0x0040, 0x6cfc, + 0x1078, 0x7045, 0xa085, 0x0001, 0x127f, 0x007f, 0x047f, 0x057f, + 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x6567, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c, + 0xa086, 0x0004, 0x00c0, 0x6d17, 0x6098, 0x0078, 0x6d18, 0x6030, + 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006, + 0x20a2, 0x00f0, 0x6d20, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x1078, + 0x6c2d, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6567, + 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, + 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x147f, 0x157f, 0x007c, 0x157e, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, 0x20a3, + 0x0000, 0x20a9, 0x0006, 0x2011, 0xa340, 0x2019, 0xa341, 0x23a6, + 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x00f0, 0x6d4f, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, 0x6c2d, 0x147f, + 0x157f, 0x007c, 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, + 0x1078, 0x65cf, 0x1078, 0x65e6, 0x7810, 0xa080, 0x0000, 0x2004, + 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, + 0xa080, 0x0004, 0x8003, 0x60c2, 0x1078, 0x6c2d, 0x027f, 0x017f, + 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, + 0x6567, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, + 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x147f, 0x157f, 0x007c, + 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x6567, + 0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808, + 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x1078, 0x6c2d, + 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x0e7e, 0x0c7e, 0x007e, + 0x127e, 0x2091, 0x8000, 0x2071, 0xa5ab, 0x700c, 0x2060, 0x8cff, + 0x0040, 0x6dd1, 0x1078, 0x8c3b, 0x00c0, 0x6dc8, 0x1078, 0x7a05, + 0x600c, 0x007e, 0x1078, 0x753d, 0x1078, 0x7045, 0x0c7f, 0x0078, + 0x6dbf, 0x700f, 0x0000, 0x700b, 0x0000, 0x127f, 0x007f, 0x0c7f, + 0x0e7f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, + 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, + 0x0140, 0x2071, 0xa5ab, 0x7024, 0x2060, 0x8cff, 0x0040, 0x6e2a, + 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x595a, 0x2009, 0x0013, + 0x1078, 0x756c, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x6e0d, + 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x6e1f, 0x7803, + 0x1000, 0x7803, 0x0000, 0x0078, 0x6e1f, 0xd084, 0x0040, 0x6e14, + 0x6827, 0x0001, 0x0078, 0x6e16, 0x00f0, 0x6dfc, 0x7804, 0xa084, + 0x1000, 0x0040, 0x6e1f, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, + 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, + 0x127f, 0x007c, 0x2001, 0xa300, 0x2004, 0xa096, 0x0001, 0x0040, + 0x6e62, 0xa096, 0x0004, 0x0040, 0x6e62, 0x6817, 0x0008, 0x68c3, + 0x0000, 0x2011, 0x4129, 0x1078, 0x58d4, 0x20a9, 0x01f4, 0x6824, + 0xd094, 0x0040, 0x6e50, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, + 0x0040, 0x6e62, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0x6e62, + 0xd084, 0x0040, 0x6e57, 0x6827, 0x0001, 0x0078, 0x6e59, 0x00f0, + 0x6e3f, 0x7804, 0xa084, 0x1000, 0x0040, 0x6e62, 0x7803, 0x0100, + 0x7803, 0x0000, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, + 0x0f7f, 0x157f, 0x127f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, + 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, + 0x0100, 0x2079, 0x0140, 0x2071, 0xa5ab, 0x703c, 0x2060, 0x8cff, + 0x0040, 0x6ee8, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x00c0, + 0x6e86, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x1078, 0x5967, 0x1078, + 0x1f31, 0x047e, 0x057e, 0x2009, 0x017f, 0x212c, 0x200b, 0x00a5, + 0x2021, 0x0169, 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, + 0x6eb7, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x0e7e, 0x0f7e, 0x2079, + 0x0020, 0x2071, 0xa602, 0x6814, 0xa084, 0x0004, 0xa085, 0x0012, + 0x6816, 0x7803, 0x0008, 0x7003, 0x0000, 0x0f7f, 0x0e7f, 0x250a, + 0x057f, 0x047f, 0xa39d, 0x0000, 0x00c0, 0x6ec2, 0x2009, 0x0049, + 0x1078, 0x756c, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x6ed5, + 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x6ee7, 0x7803, + 0x1000, 0x7803, 0x0000, 0x0078, 0x6ee7, 0xd08c, 0x0040, 0x6edc, + 0x6827, 0x0002, 0x0078, 0x6ede, 0x00f0, 0x6ec4, 0x7804, 0xa084, + 0x1000, 0x0040, 0x6ee7, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, + 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, + 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0xa5ab, + 0x6a06, 0x127f, 0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, + 0x2069, 0xa5ab, 0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, + 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2071, 0xa5ab, 0x7614, 0x2660, + 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x6f46, 0x601c, 0xa206, + 0x00c0, 0x6f41, 0x7014, 0xac36, 0x00c0, 0x6f20, 0x660c, 0x7616, + 0x7010, 0xac36, 0x00c0, 0x6f2e, 0x2c00, 0xaf36, 0x0040, 0x6f2c, + 0x2f00, 0x7012, 0x0078, 0x6f2e, 0x7013, 0x0000, 0x660c, 0x067e, + 0x2c00, 0xaf06, 0x0040, 0x6f37, 0x7e0e, 0x0078, 0x6f38, 0x2678, + 0x600f, 0x0000, 0x1078, 0x8c01, 0x1078, 0x7045, 0x0c7f, 0x0078, + 0x6f13, 0x2c78, 0x600c, 0x2060, 0x0078, 0x6f13, 0x127f, 0x007f, + 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, + 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0078, 0x6fa0, 0x157e, 0x147e, + 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, 0x0078, 0x6fa0, 0x157e, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, 0x0078, 0x6fa0, + 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, + 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, + 0x6fa0, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, + 0x1078, 0x7050, 0x60c3, 0x0020, 0x1078, 0x6c2d, 0x147f, 0x157f, + 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, + 0xd1b4, 0x00c0, 0x6fb8, 0xd1bc, 0x00c0, 0x7002, 0x0078, 0x7042, + 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, + 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, + 0x0040, 0x6ff9, 0x6020, 0xd0b4, 0x0040, 0x6ff9, 0x6024, 0xd094, + 0x00c0, 0x6ff9, 0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, + 0x6ff9, 0x00f0, 0x6fc5, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107, + 0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b, + 0xbc91, 0x6043, 0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, + 0xd094, 0x00c0, 0x6ff8, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x6fef, + 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, + 0x0078, 0x7042, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, + 0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, + 0xa084, 0x4000, 0x0040, 0x703b, 0x6020, 0xd0bc, 0x0040, 0x703b, + 0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x703b, 0x00f0, + 0x700f, 0x027e, 0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, + 0x00ff, 0xa10d, 0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, + 0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, + 0x00c0, 0x7035, 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, + 0x200b, 0x0000, 0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0xa5ab, + 0x7020, 0xa005, 0x0040, 0x704e, 0x8001, 0x7022, 0x0e7f, 0x007c, + 0x20a9, 0x0008, 0x20a2, 0x00f0, 0x7052, 0x20a2, 0x20a2, 0x007c, + 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e, + 0x2091, 0x8000, 0x2071, 0xa5ab, 0x7614, 0x2660, 0x2678, 0x2039, + 0x0001, 0x87ff, 0x0040, 0x70f4, 0x8cff, 0x0040, 0x70f4, 0x601c, + 0xa086, 0x0006, 0x00c0, 0x70ef, 0x88ff, 0x0040, 0x707f, 0x2800, + 0xac06, 0x00c0, 0x70ef, 0x2039, 0x0000, 0x0078, 0x708a, 0x6018, + 0xa206, 0x00c0, 0x70ef, 0x85ff, 0x0040, 0x708a, 0x6020, 0xa106, + 0x00c0, 0x70ef, 0x7024, 0xac06, 0x00c0, 0x70ba, 0x2069, 0x0100, + 0x68c0, 0xa005, 0x0040, 0x70b5, 0x1078, 0x595a, 0x6817, 0x0008, + 0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x70aa, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x70b2, + 0x6827, 0x0001, 0x037f, 0x0078, 0x70ba, 0x6003, 0x0009, 0x630a, + 0x0078, 0x70ef, 0x7014, 0xac36, 0x00c0, 0x70c0, 0x660c, 0x7616, + 0x7010, 0xac36, 0x00c0, 0x70ce, 0x2c00, 0xaf36, 0x0040, 0x70cc, + 0x2f00, 0x7012, 0x0078, 0x70ce, 0x7013, 0x0000, 0x660c, 0x067e, + 0x2c00, 0xaf06, 0x0040, 0x70d7, 0x7e0e, 0x0078, 0x70d8, 0x2678, + 0x89ff, 0x00c0, 0x70e7, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, + 0x8a44, 0x0040, 0x70e5, 0x1078, 0x9e70, 0x1078, 0x8c01, 0x1078, + 0x7045, 0x88ff, 0x00c0, 0x70fe, 0x0c7f, 0x0078, 0x7069, 0x2c78, + 0x600c, 0x2060, 0x0078, 0x7069, 0xa006, 0x127f, 0x007f, 0x067f, + 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, + 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x70f5, 0x0f7e, 0x0e7e, 0x0d7e, + 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, + 0xa5ab, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x7177, 0x601c, + 0xa086, 0x0006, 0x00c0, 0x7172, 0x87ff, 0x0040, 0x7125, 0x2700, + 0xac06, 0x00c0, 0x7172, 0x0078, 0x7130, 0x6018, 0xa206, 0x00c0, + 0x7172, 0x85ff, 0x0040, 0x7130, 0x6020, 0xa106, 0x00c0, 0x7172, + 0x703c, 0xac06, 0x00c0, 0x7142, 0x037e, 0x2019, 0x0001, 0x1078, + 0x6e6c, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, + 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x7148, 0x660c, 0x763a, + 0x7034, 0xac36, 0x00c0, 0x7156, 0x2c00, 0xaf36, 0x0040, 0x7154, + 0x2f00, 0x7036, 0x0078, 0x7156, 0x7037, 0x0000, 0x660c, 0x067e, + 0x2c00, 0xaf06, 0x0040, 0x715f, 0x7e0e, 0x0078, 0x7160, 0x2678, + 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x716a, + 0x1078, 0x9e70, 0x1078, 0x8c01, 0x87ff, 0x00c0, 0x7181, 0x0c7f, + 0x0078, 0x7114, 0x2c78, 0x600c, 0x2060, 0x0078, 0x7114, 0xa006, + 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, + 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa7bd, 0x0001, 0x0078, 0x7178, + 0x0e7e, 0x2071, 0xa5ab, 0x2001, 0xa300, 0x2004, 0xa086, 0x0002, + 0x00c0, 0x7196, 0x7007, 0x0005, 0x0078, 0x7198, 0x7007, 0x0000, + 0x0e7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x027e, 0x007e, + 0x127e, 0x2091, 0x8000, 0x2071, 0xa5ab, 0x2c10, 0x7638, 0x2660, + 0x2678, 0x8cff, 0x0040, 0x71d8, 0x2200, 0xac06, 0x00c0, 0x71d3, + 0x7038, 0xac36, 0x00c0, 0x71b6, 0x660c, 0x763a, 0x7034, 0xac36, + 0x00c0, 0x71c4, 0x2c00, 0xaf36, 0x0040, 0x71c2, 0x2f00, 0x7036, + 0x0078, 0x71c4, 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0040, + 0x71cc, 0x7e0e, 0x0078, 0x71cd, 0x2678, 0x600f, 0x0000, 0xa085, + 0x0001, 0x0078, 0x71d8, 0x2c78, 0x600c, 0x2060, 0x0078, 0x71a9, + 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, + 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, + 0x8000, 0x2071, 0xa5ab, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0040, + 0x7279, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x7274, + 0x7024, 0xac06, 0x00c0, 0x721f, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0040, 0x724d, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x7188, + 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, + 0x0040, 0x7216, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0040, 0x721e, 0x6827, 0x0001, 0x037f, 0x700c, + 0xac36, 0x00c0, 0x7225, 0x660c, 0x760e, 0x7008, 0xac36, 0x00c0, + 0x7233, 0x2c00, 0xaf36, 0x0040, 0x7231, 0x2f00, 0x700a, 0x0078, + 0x7233, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, + 0x723c, 0x7e0e, 0x0078, 0x723d, 0x2678, 0x600f, 0x0000, 0x1078, + 0x8c27, 0x00c0, 0x7251, 0x1078, 0x2839, 0x1078, 0x8c3b, 0x00c0, + 0x726d, 0x1078, 0x7a05, 0x0078, 0x726d, 0x1078, 0x7188, 0x0078, + 0x721f, 0x1078, 0x8c3b, 0x00c0, 0x7259, 0x1078, 0x7a05, 0x0078, + 0x726d, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x726d, 0x601c, + 0xa086, 0x0003, 0x00c0, 0x7281, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x1078, + 0x7045, 0x0c7f, 0x0078, 0x71ee, 0x2c78, 0x600c, 0x2060, 0x0078, + 0x71ee, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, + 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x726d, 0x1078, 0x9e70, + 0x0078, 0x726d, 0x037e, 0x157e, 0x137e, 0x147e, 0x3908, 0xa006, + 0xa190, 0x0020, 0x221c, 0xa39e, 0x260c, 0x00c0, 0x729b, 0x8210, + 0x8000, 0x0078, 0x7292, 0xa005, 0x0040, 0x72a7, 0x20a9, 0x0020, + 0x2198, 0x8211, 0xa282, 0x0020, 0x20c8, 0x20a0, 0x53a3, 0x147f, + 0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, + 0x65f8, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x2099, 0xa5a3, 0x20a9, 0x0004, 0x53a6, + 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8, + 0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084, + 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, 0x20a2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x1078, 0x6c2d, + 0x007c, 0x0d7e, 0x017e, 0x2f68, 0x2009, 0x0035, 0x1078, 0x8ef5, + 0x00c0, 0x7361, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x1300, + 0x20a3, 0x0000, 0x7828, 0x2068, 0x681c, 0xa086, 0x0003, 0x0040, + 0x733d, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0, + 0x7317, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0078, 0x7352, 0xa286, + 0x007f, 0x00c0, 0x7321, 0x20a3, 0x00ff, 0x20a3, 0xfffd, 0x0078, + 0x7352, 0xd2bc, 0x0040, 0x7337, 0xa286, 0x0080, 0x00c0, 0x732e, + 0x20a3, 0x00ff, 0x20a3, 0xfffc, 0x0078, 0x7352, 0xa2e8, 0xa434, + 0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x0078, 0x7352, 0x20a3, + 0x0000, 0x6098, 0x20a2, 0x0078, 0x7352, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa082, 0x007e, 0x0048, 0x734e, 0x0d7e, 0x2069, 0xa31a, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x7352, 0x20a3, 0x0000, + 0x6030, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x6c2d, 0x017f, 0x0d7f, + 0x007c, 0x7817, 0x0001, 0x7803, 0x0006, 0x017f, 0x0d7f, 0x007c, + 0x0d7e, 0x027e, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006, 0x0040, + 0x738a, 0xa186, 0x0003, 0x0040, 0x73e5, 0xa186, 0x0005, 0x0040, + 0x73c8, 0xa186, 0x0004, 0x0040, 0x73b8, 0xa186, 0x0008, 0x0040, + 0x73d2, 0x7807, 0x0037, 0x7813, 0x1700, 0x1078, 0x7450, 0x027f, + 0x0d7f, 0x007c, 0x1078, 0x740d, 0x2009, 0x4000, 0x6800, 0x0079, + 0x7391, 0x73a4, 0x73b2, 0x73a6, 0x73b2, 0x73ad, 0x73a4, 0x73a4, + 0x73b2, 0x73b2, 0x73b2, 0x73b2, 0x73a4, 0x73a4, 0x73a4, 0x73a4, + 0x73a4, 0x73b2, 0x73a4, 0x73b2, 0x1078, 0x1328, 0x6824, 0xd0e4, + 0x0040, 0x73ad, 0xd0cc, 0x0040, 0x73b0, 0xa00e, 0x0078, 0x73b2, + 0x2009, 0x2000, 0x6828, 0x20a2, 0x682c, 0x20a2, 0x0078, 0x7403, + 0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, + 0x6a00, 0xa286, 0x0002, 0x00c0, 0x73c6, 0xa00e, 0x0078, 0x7403, + 0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, + 0x0078, 0x7403, 0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x2009, 0x4000, 0xa286, 0x0005, 0x0040, 0x73e2, 0xa286, 0x0002, + 0x00c0, 0x73e3, 0xa00e, 0x0078, 0x7403, 0x1078, 0x740d, 0x6810, + 0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814, 0xa103, 0x20a2, + 0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e, 0x0002, 0x0040, + 0x7401, 0xa08e, 0x0004, 0x0040, 0x7401, 0x2009, 0x4000, 0x0078, + 0x7403, 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018, + 0x1078, 0x6c2d, 0x027f, 0x0d7f, 0x007c, 0x037e, 0x047e, 0x057e, + 0x067e, 0x20a1, 0x020b, 0x1078, 0x65f8, 0xa006, 0x20a3, 0x0200, + 0x20a2, 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa092, 0x007e, 0x0048, 0x7433, 0x0d7e, 0x2069, 0xa31a, + 0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xa434, 0x2d6c, 0x6b10, 0x6c14, + 0x0d7f, 0x0078, 0x7439, 0x2019, 0x0000, 0x6498, 0x2029, 0x0000, + 0x6630, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086, 0x0003, 0x00c0, + 0x7447, 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0078, 0x744b, 0x23a2, + 0x24a2, 0x25a2, 0x26a2, 0x067f, 0x057f, 0x047f, 0x037f, 0x007c, + 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, + 0x007c, 0x20a1, 0x020b, 0x1078, 0x655e, 0x20a3, 0x1400, 0x20a3, + 0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c, + 0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000, + 0x60c3, 0x0010, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x65ef, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810, + 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x007c, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x7499, 0x60c3, 0x0000, 0x1078, 0x6c2d, 0x147f, + 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0xd0bc, 0x0040, 0x74b6, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, + 0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, + 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x74be, 0x20a3, 0x0300, + 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0819, + 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x2fa2, + 0x7a08, 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x007c, 0x2061, + 0xaa00, 0x2a70, 0x7060, 0x7046, 0x704b, 0xaa00, 0x007c, 0x0e7e, + 0x127e, 0x2071, 0xa300, 0x2091, 0x8000, 0x7544, 0xa582, 0x0010, + 0x0048, 0x7509, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, + 0x74f5, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, 0x74f1, 0x0078, + 0x74e4, 0x2061, 0xaa00, 0x0078, 0x74e4, 0x6003, 0x0008, 0x8529, + 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, 0x7505, 0x754a, + 0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704b, 0xaa00, 0x0078, + 0x7500, 0xa006, 0x0078, 0x7502, 0x0e7e, 0x2071, 0xa300, 0x7544, + 0xa582, 0x0010, 0x0048, 0x753a, 0x7048, 0x2060, 0x6000, 0xa086, + 0x0000, 0x0040, 0x7527, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, + 0x7523, 0x0078, 0x7516, 0x2061, 0xaa00, 0x0078, 0x7516, 0x6003, + 0x0008, 0x8529, 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, + 0x7536, 0x754a, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x704b, 0xaa00, + 0x0078, 0x7532, 0xa006, 0x0078, 0x7534, 0xac82, 0xaa00, 0x1048, + 0x1328, 0x2001, 0xa315, 0x2004, 0xac02, 0x10c8, 0x1328, 0xa006, + 0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, + 0x6003, 0x0000, 0x6022, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036, + 0x603a, 0x603e, 0x2061, 0xa300, 0x6044, 0x8000, 0x6046, 0xa086, + 0x0001, 0x0040, 0x7564, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, + 0x6109, 0x127f, 0x0078, 0x7563, 0x601c, 0xa084, 0x000f, 0x0079, + 0x7571, 0x757a, 0x758b, 0x75a7, 0x75c3, 0x8f2d, 0x8f49, 0x8f65, + 0x757a, 0x758b, 0xa186, 0x0013, 0x00c0, 0x7583, 0x1078, 0x6010, + 0x1078, 0x6109, 0x007c, 0xa18e, 0x0047, 0x00c0, 0x758a, 0xa016, + 0x1078, 0x15ec, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, + 0x1328, 0x1079, 0x7595, 0x067f, 0x007c, 0x75a5, 0x7891, 0x7a34, + 0x75a5, 0x7ab8, 0x75df, 0x75a5, 0x75a5, 0x7823, 0x7e6d, 0x75a5, + 0x75a5, 0x75a5, 0x75a5, 0x75a5, 0x75a5, 0x1078, 0x1328, 0x067e, + 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1328, 0x1079, 0x75b1, 0x067f, + 0x007c, 0x75c1, 0x8522, 0x75c1, 0x75c1, 0x75c1, 0x75c1, 0x75c1, + 0x75c1, 0x84c5, 0x86a8, 0x75c1, 0x8552, 0x85d8, 0x8552, 0x85d8, + 0x75c1, 0x1078, 0x1328, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, + 0x1328, 0x1079, 0x75cd, 0x067f, 0x007c, 0x75dd, 0x7eb4, 0x7f81, + 0x80c6, 0x8242, 0x75dd, 0x75dd, 0x75dd, 0x7e8d, 0x846d, 0x8471, + 0x75dd, 0x75dd, 0x75dd, 0x75dd, 0x84a1, 0x1078, 0x1328, 0xa1b6, + 0x0015, 0x00c0, 0x75e7, 0x1078, 0x753d, 0x0078, 0x75ed, 0xa1b6, + 0x0016, 0x10c0, 0x1328, 0x1078, 0x753d, 0x007c, 0x20a9, 0x000e, + 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, + 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, + 0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x75fc, + 0x0e7e, 0x1078, 0x8a44, 0x0040, 0x7613, 0x6010, 0x2070, 0x7007, + 0x0000, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x753d, 0x007c, 0x0d7e, + 0x037e, 0x7330, 0xa386, 0x0200, 0x00c0, 0x7624, 0x6018, 0x2068, + 0x6813, 0x00ff, 0x6817, 0xfffd, 0x6010, 0xa005, 0x0040, 0x762e, + 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6b32, 0x1078, 0x753d, + 0x037f, 0x0d7f, 0x007c, 0x017e, 0x20a9, 0x002a, 0xae80, 0x000c, + 0x2098, 0x6010, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, + 0x6010, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, + 0x0e7e, 0x6010, 0x2004, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, + 0x753d, 0x017f, 0x007c, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2c68, + 0x017e, 0x2009, 0x0035, 0x1078, 0x8ef5, 0x017f, 0x00c0, 0x766f, + 0x027e, 0x6228, 0x2268, 0x027f, 0x2071, 0xa88c, 0x6b1c, 0xa386, + 0x0003, 0x0040, 0x7673, 0xa386, 0x0006, 0x0040, 0x7677, 0x1078, + 0x753d, 0x0078, 0x7679, 0x1078, 0x767c, 0x0078, 0x7679, 0x1078, + 0x771e, 0x0d7f, 0x0e7f, 0x007c, 0x0f7e, 0x6810, 0x2078, 0xa186, + 0x0015, 0x0040, 0x7705, 0xa18e, 0x0016, 0x00c0, 0x771c, 0x700c, + 0xa084, 0xff00, 0xa086, 0x1700, 0x00c0, 0x76e0, 0x8fff, 0x0040, + 0x771a, 0x6808, 0xa086, 0xffff, 0x00c0, 0x7709, 0x784c, 0xa084, + 0x0060, 0xa086, 0x0020, 0x00c0, 0x76a7, 0x797c, 0x7810, 0xa106, + 0x00c0, 0x7709, 0x7980, 0x7814, 0xa106, 0x00c0, 0x7709, 0x1078, + 0x8bf4, 0x6830, 0x7852, 0x784c, 0xc0dc, 0xc0f4, 0xc0d4, 0x784e, + 0x027e, 0xa00e, 0x6a14, 0x2001, 0x000a, 0x1078, 0x5a98, 0x7854, + 0xa20a, 0x0048, 0x76bc, 0x8011, 0x7a56, 0x82ff, 0x027f, 0x00c0, + 0x76c8, 0x0c7e, 0x2d60, 0x1078, 0x8832, 0x0c7f, 0x0078, 0x771a, + 0x0c7e, 0x0d7e, 0x2f68, 0x6838, 0xd0fc, 0x00c0, 0x76d3, 0x1078, + 0x4290, 0x0078, 0x76d5, 0x1078, 0x436e, 0x0d7f, 0x0c7f, 0x00c0, + 0x7709, 0x0c7e, 0x2d60, 0x1078, 0x753d, 0x0c7f, 0x0078, 0x771a, + 0x7008, 0xa086, 0x000b, 0x00c0, 0x76fa, 0x6018, 0x200c, 0xc1bc, + 0x2102, 0x0c7e, 0x2d60, 0x7853, 0x0003, 0x6007, 0x0085, 0x6003, + 0x000b, 0x601f, 0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, + 0x0078, 0x771a, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x7709, 0x2001, + 0xa5a2, 0x2004, 0x683e, 0x0078, 0x771a, 0x1078, 0x7739, 0x0078, + 0x771c, 0x8fff, 0x1040, 0x1328, 0x0c7e, 0x0d7e, 0x2d60, 0x2f68, + 0x684b, 0x0003, 0x1078, 0x8726, 0x1078, 0x8bf4, 0x1078, 0x8c01, + 0x0d7f, 0x0c7f, 0x1078, 0x753d, 0x0f7f, 0x007c, 0xa186, 0x0015, + 0x00c0, 0x7728, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x0078, 0x7736, + 0xa18e, 0x0016, 0x00c0, 0x7738, 0x0c7e, 0x2d00, 0x2060, 0x1078, + 0xa134, 0x1078, 0x5a41, 0x1078, 0x753d, 0x0c7f, 0x1078, 0x753d, + 0x007c, 0x027e, 0x037e, 0x047e, 0x7228, 0x7c80, 0x7b7c, 0xd2f4, + 0x0040, 0x7748, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x0078, 0x77ac, + 0x0c7e, 0x2d60, 0x1078, 0x874a, 0x0c7f, 0x6804, 0xa086, 0x0050, + 0x00c0, 0x7760, 0x0c7e, 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007, + 0x0050, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, 0x0078, 0x77ac, + 0x6800, 0xa086, 0x000f, 0x0040, 0x7782, 0x8fff, 0x1040, 0x1328, + 0x6824, 0xd0dc, 0x00c0, 0x7782, 0x6800, 0xa086, 0x0004, 0x00c0, + 0x7787, 0x784c, 0xd0ac, 0x0040, 0x7787, 0x784c, 0xc0dc, 0xc0f4, + 0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852, 0x2001, 0x0001, 0x682e, + 0x0078, 0x77a6, 0x2001, 0x0007, 0x682e, 0x0078, 0x77a6, 0x784c, + 0xd0b4, 0x00c0, 0x7794, 0xd0ac, 0x0040, 0x7782, 0x784c, 0xd0f4, + 0x00c0, 0x7782, 0x0078, 0x7775, 0xd2ec, 0x00c0, 0x7782, 0x7024, + 0xa306, 0x00c0, 0x779f, 0x7020, 0xa406, 0x0040, 0x7782, 0x7020, + 0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e, 0x1078, 0x8d2b, + 0x1078, 0x6109, 0x0078, 0x77ae, 0x1078, 0x753d, 0x047f, 0x037f, + 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x027e, 0x6034, 0x2068, 0x6a1c, + 0xa286, 0x0007, 0x0040, 0x7806, 0xa286, 0x0002, 0x0040, 0x7806, + 0xa286, 0x0000, 0x0040, 0x7806, 0x6808, 0x6338, 0xa306, 0x00c0, + 0x7806, 0x2071, 0xa88c, 0xa186, 0x0015, 0x0040, 0x7800, 0xa18e, + 0x0016, 0x00c0, 0x77e8, 0x6030, 0xa084, 0x00ff, 0xa086, 0x0001, + 0x00c0, 0x77e8, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x77e8, 0x6034, + 0xa080, 0x0009, 0x200c, 0xc1dd, 0xc1f5, 0x2102, 0x0078, 0x7800, + 0x0c7e, 0x6034, 0x2060, 0x6010, 0x2068, 0x1078, 0x8a44, 0x1040, + 0x1328, 0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, + 0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, 0x0078, 0x7806, + 0x6034, 0x2068, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x1078, 0x753d, + 0x027f, 0x0d7f, 0x0e7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98, + 0x6010, 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x00c0, 0x7820, 0x6018, + 0x2068, 0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802, + 0x0d7f, 0x0078, 0x7608, 0x2100, 0xa1b2, 0x0044, 0x10c8, 0x1328, + 0xa1b2, 0x0040, 0x00c8, 0x7888, 0x0079, 0x782e, 0x787c, 0x7870, + 0x787c, 0x787c, 0x787c, 0x787c, 0x786e, 0x786e, 0x786e, 0x786e, + 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, + 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, + 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x787c, 0x786e, 0x787c, + 0x787c, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x787c, 0x786e, + 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, + 0x787c, 0x787c, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, + 0x786e, 0x786e, 0x786e, 0x787c, 0x786e, 0x786e, 0x1078, 0x1328, + 0x6003, 0x0001, 0x6106, 0x1078, 0x5c45, 0x127e, 0x2091, 0x8000, + 0x1078, 0x6109, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, + 0x5c45, 0x127e, 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, + 0x2600, 0x0079, 0x788b, 0x788f, 0x788f, 0x788f, 0x787c, 0x1078, + 0x1328, 0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1328, 0xa1b6, 0x0013, + 0x00c0, 0x78a1, 0xa0b2, 0x0040, 0x00c8, 0x79fb, 0x2008, 0x0079, + 0x7941, 0xa1b6, 0x0027, 0x00c0, 0x78fe, 0x1078, 0x6010, 0x6004, + 0x1078, 0x8c27, 0x0040, 0x78be, 0x1078, 0x8c3b, 0x0040, 0x78f6, + 0xa08e, 0x0021, 0x0040, 0x78fa, 0xa08e, 0x0022, 0x0040, 0x78f6, + 0xa08e, 0x003d, 0x0040, 0x78fa, 0x0078, 0x78f1, 0x1078, 0x2839, + 0x2001, 0x0007, 0x1078, 0x443f, 0x6018, 0xa080, 0x0028, 0x200c, + 0x1078, 0x7a05, 0xa186, 0x007e, 0x00c0, 0x78d3, 0x2001, 0xa332, + 0x2014, 0xc285, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, + 0x0028, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, 0x1078, 0x5c78, + 0x0c7e, 0x6018, 0xa065, 0x0040, 0x78e7, 0x1078, 0x471b, 0x0c7f, + 0x2c08, 0x1078, 0x9c38, 0x077f, 0x037f, 0x027f, 0x017f, 0x1078, + 0x44bc, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0x1078, 0x7a05, + 0x0078, 0x78f1, 0x1078, 0x7a28, 0x0078, 0x78f1, 0xa186, 0x0014, + 0x00c0, 0x78f5, 0x1078, 0x6010, 0x1078, 0x2813, 0x1078, 0x8c27, + 0x00c0, 0x791d, 0x1078, 0x2839, 0x6018, 0xa080, 0x0028, 0x200c, + 0x1078, 0x7a05, 0xa186, 0x007e, 0x00c0, 0x791b, 0x2001, 0xa332, + 0x200c, 0xc185, 0x2102, 0x0078, 0x78f1, 0x1078, 0x8c3b, 0x00c0, + 0x7925, 0x1078, 0x7a05, 0x0078, 0x78f1, 0x6004, 0xa08e, 0x0032, + 0x00c0, 0x7936, 0x0e7e, 0x0f7e, 0x2071, 0xa381, 0x2079, 0x0000, + 0x1078, 0x2b56, 0x0f7f, 0x0e7f, 0x0078, 0x78f1, 0x6004, 0xa08e, + 0x0021, 0x0040, 0x7921, 0xa08e, 0x0022, 0x1040, 0x7a05, 0x0078, + 0x78f1, 0x7983, 0x7985, 0x7989, 0x798d, 0x7991, 0x7995, 0x7981, + 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, + 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, + 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7999, + 0x79ab, 0x7981, 0x79ad, 0x79ab, 0x7981, 0x7981, 0x7981, 0x7981, + 0x7981, 0x79ab, 0x79ab, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, + 0x7981, 0x7981, 0x7981, 0x79de, 0x79ab, 0x7981, 0x79a5, 0x7981, + 0x7981, 0x7981, 0x79a7, 0x7981, 0x7981, 0x7981, 0x79ab, 0x7981, + 0x7981, 0x1078, 0x1328, 0x0078, 0x79ab, 0x2001, 0x000b, 0x0078, + 0x79b8, 0x2001, 0x0003, 0x0078, 0x79b8, 0x2001, 0x0005, 0x0078, + 0x79b8, 0x2001, 0x0001, 0x0078, 0x79b8, 0x2001, 0x0009, 0x0078, + 0x79b8, 0x1078, 0x6010, 0x6003, 0x0005, 0x2001, 0xa5a2, 0x2004, + 0x603e, 0x1078, 0x6109, 0x0078, 0x79b7, 0x0078, 0x79ab, 0x0078, + 0x79ab, 0x1078, 0x443f, 0x0078, 0x79f0, 0x1078, 0x6010, 0x6003, + 0x0004, 0x2001, 0xa5a0, 0x2004, 0x6016, 0x1078, 0x6109, 0x007c, + 0x1078, 0x443f, 0x1078, 0x6010, 0x2001, 0xa5a2, 0x2004, 0x603e, + 0x6003, 0x0002, 0x037e, 0x2019, 0xa35c, 0x2304, 0xa084, 0xff00, + 0x00c0, 0x79cf, 0x2019, 0xa5a0, 0x231c, 0x0078, 0x79d8, 0x8007, + 0xa09a, 0x0004, 0x0048, 0x79ca, 0x8003, 0x801b, 0x831b, 0xa318, + 0x6316, 0x037f, 0x1078, 0x6109, 0x0078, 0x79b7, 0x0e7e, 0x0f7e, + 0x2071, 0xa381, 0x2079, 0x0000, 0x1078, 0x2b56, 0x0f7f, 0x0e7f, + 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, 0x0078, 0x79b7, + 0x1078, 0x6010, 0x6003, 0x0002, 0x2001, 0xa5a0, 0x2004, 0x6016, + 0x1078, 0x6109, 0x007c, 0x2600, 0x2008, 0x0079, 0x79ff, 0x7a03, + 0x7a03, 0x7a03, 0x79f0, 0x1078, 0x1328, 0x0e7e, 0x1078, 0x8a44, + 0x0040, 0x7a21, 0x6010, 0x2070, 0x7038, 0xd0fc, 0x0040, 0x7a21, + 0x7007, 0x0000, 0x017e, 0x6004, 0xa08e, 0x0021, 0x0040, 0x7a23, + 0xa08e, 0x003d, 0x0040, 0x7a23, 0x017f, 0x7037, 0x0103, 0x7033, + 0x0100, 0x0e7f, 0x007c, 0x017f, 0x1078, 0x7a28, 0x0078, 0x7a21, + 0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, + 0x7023, 0x8001, 0x0e7f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, + 0xa084, 0x00ff, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1328, 0x6604, + 0xa6b6, 0x0043, 0x00c0, 0x7a48, 0x1078, 0x8e6d, 0x0078, 0x7aa7, + 0x6604, 0xa6b6, 0x0033, 0x00c0, 0x7a51, 0x1078, 0x8e11, 0x0078, + 0x7aa7, 0x6604, 0xa6b6, 0x0028, 0x00c0, 0x7a5a, 0x1078, 0x8c6a, + 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0029, 0x00c0, 0x7a63, 0x1078, + 0x8c84, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x001f, 0x00c0, 0x7a6c, + 0x1078, 0x75ee, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0000, 0x00c0, + 0x7a75, 0x1078, 0x780c, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0022, + 0x00c0, 0x7a7e, 0x1078, 0x7617, 0x0078, 0x7aa7, 0x6604, 0xa6b6, + 0x0035, 0x00c0, 0x7a87, 0x1078, 0x7653, 0x0078, 0x7aa7, 0x6604, + 0xa6b6, 0x0039, 0x00c0, 0x7a90, 0x1078, 0x77b2, 0x0078, 0x7aa7, + 0x6604, 0xa6b6, 0x003d, 0x00c0, 0x7a99, 0x1078, 0x7633, 0x0078, + 0x7aa7, 0xa1b6, 0x0015, 0x00c0, 0x7aa1, 0x1079, 0x7aac, 0x0078, + 0x7aa7, 0xa1b6, 0x0016, 0x00c0, 0x7aa8, 0x1079, 0x7bfd, 0x007c, + 0x1078, 0x7583, 0x0078, 0x7aa7, 0x7ad0, 0x7ad3, 0x7ad0, 0x7b1e, + 0x7ad0, 0x7b91, 0x7c09, 0x7ad0, 0x7ad0, 0x7bd5, 0x7ad0, 0x7beb, + 0xa1b6, 0x0048, 0x0040, 0x7ac4, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x1078, 0x15ec, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, + 0x7000, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x753d, 0x007c, + 0x0005, 0x0005, 0x007c, 0x0e7e, 0x2071, 0xa300, 0x707c, 0xa086, + 0x0074, 0x00c0, 0x7b07, 0x1078, 0x9c0c, 0x00c0, 0x7af9, 0x0d7e, + 0x6018, 0x2068, 0x7030, 0xd08c, 0x0040, 0x7aec, 0x6800, 0xd0bc, + 0x0040, 0x7aec, 0xc0c5, 0x6802, 0x1078, 0x7b0b, 0x0d7f, 0x2001, + 0x0006, 0x1078, 0x443f, 0x1078, 0x2839, 0x1078, 0x753d, 0x0078, + 0x7b09, 0x2001, 0x000a, 0x1078, 0x443f, 0x1078, 0x2839, 0x6003, + 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7b09, 0x1078, + 0x7b81, 0x0e7f, 0x007c, 0x6800, 0xd084, 0x0040, 0x7b1d, 0x2001, + 0x0000, 0x1078, 0x442b, 0x2069, 0xa351, 0x6804, 0xd0a4, 0x0040, + 0x7b1d, 0x2001, 0x0006, 0x1078, 0x4472, 0x007c, 0x0d7e, 0x2011, + 0xa31f, 0x2204, 0xa086, 0x0074, 0x00c0, 0x7b7d, 0x6018, 0x2068, + 0x6aa0, 0xa286, 0x007e, 0x00c0, 0x7b31, 0x1078, 0x7d17, 0x0078, + 0x7b7f, 0x1078, 0x7d0d, 0x6018, 0x2068, 0xa080, 0x0028, 0x2014, + 0xa286, 0x0080, 0x00c0, 0x7b55, 0x6813, 0x00ff, 0x6817, 0xfffc, + 0x6010, 0xa005, 0x0040, 0x7b4b, 0x2068, 0x6807, 0x0000, 0x6837, + 0x0103, 0x6833, 0x0200, 0x2001, 0x0006, 0x1078, 0x443f, 0x1078, + 0x2839, 0x1078, 0x753d, 0x0078, 0x7b7f, 0x0e7e, 0x2071, 0xa332, + 0x2e04, 0xd09c, 0x0040, 0x7b70, 0x2071, 0xa880, 0x7108, 0x720c, + 0xa18c, 0x00ff, 0x00c0, 0x7b68, 0xa284, 0xff00, 0x0040, 0x7b70, + 0x6018, 0x2070, 0x70a0, 0xd0bc, 0x00c0, 0x7b70, 0x7112, 0x7216, + 0x0e7f, 0x2001, 0x0004, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, + 0x0003, 0x1078, 0x5c45, 0x0078, 0x7b7f, 0x1078, 0x7b81, 0x0d7f, + 0x007c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x0040, 0x7b8c, + 0x2001, 0x0007, 0x1078, 0x443f, 0x1078, 0x2839, 0x1078, 0x753d, + 0x007c, 0x0e7e, 0x2071, 0xa300, 0x707c, 0xa086, 0x0014, 0x00c0, + 0x7bcf, 0x7000, 0xa086, 0x0003, 0x00c0, 0x7ba4, 0x6010, 0xa005, + 0x00c0, 0x7ba4, 0x1078, 0x35f7, 0x0d7e, 0x6018, 0x2068, 0x1078, + 0x457d, 0x1078, 0x7b0b, 0x0d7f, 0x1078, 0x7dba, 0x00c0, 0x7bcf, + 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, 0xa005, 0x0040, 0x7bcf, + 0x2001, 0x0006, 0x1078, 0x443f, 0x0e7e, 0x6010, 0xa005, 0x0040, + 0x7bc8, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, 0x7033, 0x0200, + 0x0e7f, 0x1078, 0x2839, 0x1078, 0x753d, 0x0078, 0x7bd3, 0x1078, + 0x7a05, 0x1078, 0x7b81, 0x0e7f, 0x007c, 0x2011, 0xa31f, 0x2204, + 0xa086, 0x0014, 0x00c0, 0x7be8, 0x2001, 0x0002, 0x1078, 0x443f, + 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7bea, + 0x1078, 0x7b81, 0x007c, 0x2011, 0xa31f, 0x2204, 0xa086, 0x0004, + 0x00c0, 0x7bfa, 0x2001, 0x0007, 0x1078, 0x443f, 0x1078, 0x753d, + 0x0078, 0x7bfc, 0x1078, 0x7b81, 0x007c, 0x7ad0, 0x7c11, 0x7ad0, + 0x7c4e, 0x7ad0, 0x7cc0, 0x7c09, 0x7ad0, 0x7ad0, 0x7cd5, 0x7ad0, + 0x7ce8, 0x6604, 0xa6b6, 0x001e, 0x00c0, 0x7c10, 0x1078, 0x753d, + 0x007c, 0x0d7e, 0x0c7e, 0x1078, 0x7cfb, 0x00c0, 0x7c27, 0x2001, + 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f, 0x6003, + 0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, 0x0078, 0x7c4b, 0x2009, + 0xa88e, 0x2104, 0xa086, 0x0009, 0x00c0, 0x7c3c, 0x6018, 0x2068, + 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x7c49, 0x8001, 0x6842, + 0x6017, 0x000a, 0x0078, 0x7c4b, 0x2009, 0xa88f, 0x2104, 0xa084, + 0xff00, 0xa086, 0x1900, 0x00c0, 0x7c49, 0x1078, 0x753d, 0x0078, + 0x7c4b, 0x1078, 0x7b81, 0x0c7f, 0x0d7f, 0x007c, 0x1078, 0x7d0a, + 0x00c0, 0x7c62, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, + 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, + 0x0078, 0x7c8e, 0x1078, 0x7a05, 0x2009, 0xa88e, 0x2134, 0xa6b4, + 0x00ff, 0xa686, 0x0005, 0x0040, 0x7c8f, 0xa686, 0x000b, 0x0040, + 0x7c8c, 0x2009, 0xa88f, 0x2104, 0xa084, 0xff00, 0x00c0, 0x7c7c, + 0xa686, 0x0009, 0x0040, 0x7c8f, 0xa086, 0x1900, 0x00c0, 0x7c8c, + 0xa686, 0x0009, 0x0040, 0x7c8f, 0x2001, 0x0004, 0x1078, 0x443f, + 0x1078, 0x753d, 0x0078, 0x7c8e, 0x1078, 0x7b81, 0x007c, 0x0d7e, + 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x7c9d, 0x6838, 0xd0fc, + 0x0040, 0x7c9d, 0x0d7f, 0x0078, 0x7c8c, 0x6018, 0x2068, 0x6840, + 0xa084, 0x00ff, 0xa005, 0x0040, 0x7cae, 0x8001, 0x6842, 0x6017, + 0x000a, 0x6007, 0x0016, 0x0d7f, 0x0078, 0x7c8e, 0x68a0, 0xa086, + 0x007e, 0x00c0, 0x7cbb, 0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, + 0x0e7f, 0x0078, 0x7cbd, 0x1078, 0x2813, 0x0d7f, 0x0078, 0x7c8c, + 0x1078, 0x7d0a, 0x00c0, 0x7cd0, 0x2001, 0x0004, 0x1078, 0x443f, + 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x5c45, 0x0078, 0x7cd4, + 0x1078, 0x7a05, 0x1078, 0x7b81, 0x007c, 0x1078, 0x7d0a, 0x00c0, + 0x7ce5, 0x2001, 0x0008, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, + 0x0005, 0x1078, 0x5c45, 0x0078, 0x7ce7, 0x1078, 0x7b81, 0x007c, + 0x1078, 0x7d0a, 0x00c0, 0x7cf8, 0x2001, 0x000a, 0x1078, 0x443f, + 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7cfa, + 0x1078, 0x7b81, 0x007c, 0x2009, 0xa88e, 0x2104, 0xa086, 0x0003, + 0x00c0, 0x7d09, 0x2009, 0xa88f, 0x2104, 0xa084, 0xff00, 0xa086, + 0x2a00, 0x007c, 0xa085, 0x0001, 0x007c, 0x0c7e, 0x017e, 0xac88, + 0x0006, 0x2164, 0x1078, 0x4513, 0x017f, 0x0c7f, 0x007c, 0x0f7e, + 0x0e7e, 0x0d7e, 0x037e, 0x017e, 0x6018, 0x2068, 0x2071, 0xa332, + 0x2e04, 0xa085, 0x0003, 0x2072, 0x1078, 0x7d8b, 0x0040, 0x7d50, + 0x2001, 0xa352, 0x2004, 0xd0a4, 0x0040, 0x7d39, 0xa006, 0x2020, + 0x2009, 0x002a, 0x1078, 0x9ec0, 0x2001, 0xa30c, 0x200c, 0xc195, + 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x1078, 0x27e2, 0x2071, + 0xa300, 0x1078, 0x260d, 0x0c7e, 0x157e, 0x20a9, 0x0081, 0x2009, + 0x007f, 0x1078, 0x2921, 0x8108, 0x00f0, 0x7d49, 0x157f, 0x0c7f, + 0x1078, 0x7d0d, 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, 0xa880, + 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0xa31a, 0x206a, + 0x78e6, 0x007e, 0x8e70, 0x2e04, 0x2069, 0xa31b, 0x206a, 0x78ea, + 0xa084, 0xff00, 0x017f, 0xa105, 0x2009, 0xa325, 0x200a, 0x2069, + 0xa88e, 0x2071, 0xa59c, 0x6810, 0x2072, 0x6814, 0x7006, 0x6818, + 0x700a, 0x681c, 0x700e, 0x1078, 0x8da9, 0x2001, 0x0006, 0x1078, + 0x443f, 0x1078, 0x2839, 0x1078, 0x753d, 0x017f, 0x037f, 0x0d7f, + 0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x037e, 0x0e7e, 0x157e, 0x2019, + 0xa325, 0x231c, 0x83ff, 0x0040, 0x7db5, 0x2071, 0xa880, 0x2e14, + 0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306, 0x00c0, + 0x7db5, 0x2011, 0xa896, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, + 0x7e55, 0x00c0, 0x7db5, 0x2011, 0xa89a, 0xad98, 0x0006, 0x20a9, + 0x0004, 0x1078, 0x7e55, 0x00c0, 0x7db5, 0x157f, 0x0e7f, 0x037f, + 0x027f, 0x007c, 0x0e7e, 0x2071, 0xa88c, 0x7004, 0xa086, 0x0014, + 0x00c0, 0x7ddd, 0x7008, 0xa086, 0x0800, 0x00c0, 0x7ddd, 0x700c, + 0xd0ec, 0x0040, 0x7ddb, 0xa084, 0x0f00, 0xa086, 0x0100, 0x00c0, + 0x7ddb, 0x7024, 0xd0a4, 0x00c0, 0x7dd8, 0xd0ac, 0x0040, 0x7ddb, + 0xa006, 0x0078, 0x7ddd, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x0e7e, + 0x0d7e, 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, 0x007e, 0x127e, + 0x2091, 0x8000, 0x2029, 0xa5b4, 0x252c, 0x2021, 0xa5ba, 0x2424, + 0x2061, 0xaa00, 0x2071, 0xa300, 0x7244, 0x7060, 0xa202, 0x00c8, + 0x7e43, 0x1078, 0x9ee5, 0x0040, 0x7e3b, 0x671c, 0xa786, 0x0001, + 0x0040, 0x7e3b, 0xa786, 0x0007, 0x0040, 0x7e3b, 0x2500, 0xac06, + 0x0040, 0x7e3b, 0x2400, 0xac06, 0x0040, 0x7e3b, 0x0c7e, 0x6000, + 0xa086, 0x0004, 0x00c0, 0x7e16, 0x1078, 0x1749, 0xa786, 0x0008, + 0x00c0, 0x7e25, 0x1078, 0x8c3b, 0x00c0, 0x7e25, 0x0c7f, 0x1078, + 0x7a05, 0x1078, 0x8c01, 0x0078, 0x7e3b, 0x6010, 0x2068, 0x1078, + 0x8a44, 0x0040, 0x7e38, 0xa786, 0x0003, 0x00c0, 0x7e4d, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, + 0x1078, 0x8c01, 0x0c7f, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, + 0x7e43, 0x0078, 0x7df4, 0x127f, 0x007f, 0x027f, 0x047f, 0x057f, + 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, + 0x7e2f, 0x1078, 0x9e70, 0x0078, 0x7e38, 0x220c, 0x2304, 0xa106, + 0x00c0, 0x7e60, 0x8210, 0x8318, 0x00f0, 0x7e55, 0xa006, 0x007c, + 0x2304, 0xa102, 0x0048, 0x7e68, 0x2001, 0x0001, 0x0078, 0x7e6a, + 0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, 0x6004, 0xa08a, 0x0044, + 0x10c8, 0x1328, 0x1078, 0x8c27, 0x0040, 0x7e7c, 0x1078, 0x8c3b, + 0x0040, 0x7e89, 0x0078, 0x7e82, 0x1078, 0x2839, 0x1078, 0x8c3b, + 0x0040, 0x7e89, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, + 0x007c, 0x1078, 0x7a05, 0x0078, 0x7e82, 0xa182, 0x0040, 0x0079, + 0x7e91, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, + 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea6, 0x7ea6, 0x7ea6, 0x7ea6, + 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea6, 0x1078, 0x1328, 0x600b, 0xffff, + 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, 0x8000, + 0x1078, 0x6109, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x7ebd, + 0x6004, 0xa082, 0x0040, 0x0079, 0x7f48, 0xa186, 0x0027, 0x00c0, + 0x7edf, 0x1078, 0x6010, 0x1078, 0x2813, 0x0d7e, 0x6110, 0x2168, + 0x1078, 0x8a44, 0x0040, 0x7ed9, 0x6837, 0x0103, 0x684b, 0x0029, + 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x1078, 0x4982, 0x1078, + 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0xa186, + 0x0014, 0x00c0, 0x7ee8, 0x6004, 0xa082, 0x0040, 0x0079, 0x7f10, + 0xa186, 0x0046, 0x0040, 0x7ef4, 0xa186, 0x0045, 0x0040, 0x7ef4, + 0xa186, 0x0047, 0x10c0, 0x1328, 0x2001, 0x0109, 0x2004, 0xd084, + 0x0040, 0x7f0d, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, + 0x1078, 0x5ad2, 0x027f, 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, + 0x0002, 0x00c0, 0x7f0d, 0x0078, 0x7f81, 0x1078, 0x7583, 0x007c, + 0x7f25, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, + 0x7f23, 0x7f23, 0x7f23, 0x7f41, 0x7f41, 0x7f41, 0x7f41, 0x7f23, + 0x7f41, 0x7f23, 0x7f41, 0x1078, 0x1328, 0x1078, 0x6010, 0x0d7e, + 0x6110, 0x2168, 0x1078, 0x8a44, 0x0040, 0x7f3b, 0x6837, 0x0103, + 0x684b, 0x0006, 0x6847, 0x0000, 0x6850, 0xc0ec, 0x6852, 0x1078, + 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, + 0x007c, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, + 0x7f5d, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, + 0x7f5b, 0x7f5b, 0x7f5b, 0x7f6f, 0x7f6f, 0x7f6f, 0x7f6f, 0x7f5b, + 0x7f7a, 0x7f5b, 0x7f6f, 0x1078, 0x1328, 0x1078, 0x6010, 0x2001, + 0xa5a2, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x6109, 0x6010, + 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078, + 0x6010, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x6003, 0x000f, 0x1078, + 0x6109, 0x007c, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, + 0x007c, 0xa182, 0x0040, 0x0079, 0x7f85, 0x7f98, 0x7f98, 0x7f98, + 0x7f98, 0x7f98, 0x7f9a, 0x8095, 0x80b7, 0x7f98, 0x7f98, 0x7f98, + 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, + 0x1078, 0x1328, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2071, 0xa880, + 0x7124, 0x610a, 0x2071, 0xa88c, 0x6110, 0x2168, 0x7614, 0xa6b4, + 0x0fff, 0x86ff, 0x0040, 0x8058, 0xa68c, 0x0c00, 0x0040, 0x7fd1, + 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x7fcd, 0x684c, + 0xd0ac, 0x0040, 0x7fcd, 0x6024, 0xd0dc, 0x00c0, 0x7fcd, 0x6850, + 0xd0bc, 0x00c0, 0x7fcd, 0x7318, 0x6814, 0xa306, 0x00c0, 0x806f, + 0x731c, 0x6810, 0xa306, 0x00c0, 0x806f, 0x7318, 0x6b62, 0x731c, + 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x8004, 0xa186, + 0x0028, 0x00c0, 0x7fe1, 0x1078, 0x8c15, 0x684b, 0x001c, 0x0078, + 0x8006, 0xd6dc, 0x0040, 0x7ffd, 0x684b, 0x0015, 0x684c, 0xd0ac, + 0x0040, 0x7ffb, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040, 0x7ffb, + 0x7018, 0xa106, 0x00c0, 0x7ff8, 0x701c, 0xa206, 0x0040, 0x7ffb, + 0x6962, 0x6a5e, 0xc6dc, 0x0078, 0x8006, 0xd6d4, 0x0040, 0x8004, + 0x684b, 0x0007, 0x0078, 0x8006, 0x684b, 0x0000, 0x6837, 0x0103, + 0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x802f, 0xa686, 0x0100, 0x00c0, + 0x801a, 0x2001, 0xa899, 0x2004, 0xa005, 0x00c0, 0x801a, 0xc6c4, + 0x0078, 0x7fa9, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0040, 0x802f, + 0xa38a, 0x0009, 0x0048, 0x8026, 0x2019, 0x0008, 0x037e, 0x2308, + 0x2019, 0xa898, 0xad90, 0x0019, 0x1078, 0x8739, 0x037f, 0xd6cc, + 0x0040, 0x8085, 0x7124, 0x695a, 0x81ff, 0x0040, 0x8085, 0xa192, + 0x0021, 0x00c8, 0x8046, 0x2071, 0xa898, 0x831c, 0x2300, 0xae18, + 0xad90, 0x001d, 0x1078, 0x8739, 0x0078, 0x8085, 0x6838, 0xd0fc, + 0x0040, 0x804f, 0x2009, 0x0020, 0x695a, 0x0078, 0x803b, 0x0f7e, + 0x2d78, 0x1078, 0x86d1, 0x0f7f, 0x1078, 0x8726, 0x0078, 0x8087, + 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8075, 0x684c, + 0xd0ac, 0x0040, 0x8075, 0x6024, 0xd0dc, 0x00c0, 0x8075, 0x6850, + 0xd0bc, 0x00c0, 0x8075, 0x684c, 0xd0f4, 0x00c0, 0x8075, 0x1078, + 0x8cfa, 0x0d7f, 0x0e7f, 0x0078, 0x8094, 0x684b, 0x0000, 0x6837, + 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0040, 0x8085, 0x6810, 0x6914, + 0xa115, 0x0040, 0x8085, 0x1078, 0x8233, 0x1078, 0x4982, 0x6218, + 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x1078, 0x8cc4, 0x0d7f, 0x0e7f, + 0x00c0, 0x8094, 0x1078, 0x753d, 0x007c, 0x0f7e, 0x6003, 0x0003, + 0x2079, 0xa88c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, + 0x784c, 0xd0ac, 0x0040, 0x80a8, 0x6003, 0x0002, 0x0f7f, 0x007c, + 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x603f, 0x0000, 0x2c10, + 0x1078, 0x1cab, 0x1078, 0x5c64, 0x1078, 0x61d3, 0x007c, 0x2001, + 0xa5a2, 0x2004, 0x603e, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, + 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0xa182, 0x0040, + 0x0079, 0x80ca, 0x80dd, 0x80dd, 0x80dd, 0x80dd, 0x80dd, 0x80df, + 0x8182, 0x80dd, 0x80dd, 0x8198, 0x8209, 0x80dd, 0x80dd, 0x80dd, + 0x80dd, 0x8218, 0x80dd, 0x80dd, 0x80dd, 0x1078, 0x1328, 0x077e, + 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0xa88c, 0x6110, 0x2178, 0x7614, + 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, + 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x817d, 0xa694, 0xff00, + 0xa284, 0x0c00, 0x0040, 0x8100, 0x7018, 0x7862, 0x701c, 0x785e, + 0xa284, 0x0300, 0x0040, 0x817d, 0x1078, 0x1381, 0x1040, 0x1328, + 0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, + 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, + 0x0040, 0x811e, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, + 0xa186, 0x0002, 0x0040, 0x813a, 0xa186, 0x0028, 0x00c0, 0x812c, + 0x684b, 0x001c, 0x0078, 0x813c, 0xd6dc, 0x0040, 0x8133, 0x684b, + 0x0015, 0x0078, 0x813c, 0xd6d4, 0x0040, 0x813a, 0x684b, 0x0007, + 0x0078, 0x813c, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, + 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x815a, 0x7328, 0x732c, 0x6b56, + 0x83ff, 0x0040, 0x815a, 0xa38a, 0x0009, 0x0048, 0x8151, 0x2019, + 0x0008, 0x037e, 0x2308, 0x2019, 0xa898, 0xad90, 0x0019, 0x1078, + 0x8739, 0x037f, 0xd6cc, 0x0040, 0x817d, 0x7124, 0x695a, 0x81ff, + 0x0040, 0x817d, 0xa192, 0x0021, 0x00c8, 0x8171, 0x2071, 0xa898, + 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x8739, 0x0078, + 0x817d, 0x7838, 0xd0fc, 0x0040, 0x817a, 0x2009, 0x0020, 0x695a, + 0x0078, 0x8166, 0x2d78, 0x1078, 0x86d1, 0x0d7f, 0x0e7f, 0x0f7f, + 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, 0xa88c, 0x7c04, + 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a, + 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x1cab, 0x1078, 0x6c26, 0x007c, + 0x0d7e, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x81a4, + 0x2001, 0xa5a2, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x60b8, + 0x1078, 0x61d3, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x8207, + 0xd1cc, 0x0040, 0x81de, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x81d6, + 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, + 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, + 0x8210, 0x00f0, 0x81c5, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, + 0x017f, 0x2168, 0x1078, 0x13aa, 0x0078, 0x8201, 0x017e, 0x1078, + 0x13aa, 0x0d7f, 0x1078, 0x8726, 0x0078, 0x8201, 0x6837, 0x0103, + 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040, 0x81fd, 0xa086, + 0x0028, 0x00c0, 0x81ef, 0x684b, 0x001c, 0x0078, 0x81ff, 0xd1dc, + 0x0040, 0x81f6, 0x684b, 0x0015, 0x0078, 0x81ff, 0xd1d4, 0x0040, + 0x81fd, 0x684b, 0x0007, 0x0078, 0x81ff, 0x684b, 0x0000, 0x1078, + 0x4982, 0x1078, 0x8cc4, 0x00c0, 0x8207, 0x1078, 0x753d, 0x0d7f, + 0x007c, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x6003, 0x0002, 0x2001, + 0xa5a2, 0x2004, 0x603e, 0x1078, 0x60b8, 0x1078, 0x61d3, 0x007c, + 0x1078, 0x60b8, 0x1078, 0x2813, 0x0d7e, 0x6110, 0x2168, 0x1078, + 0x8a44, 0x0040, 0x822d, 0x6837, 0x0103, 0x684b, 0x0029, 0x6847, + 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, + 0x1078, 0x61d3, 0x007c, 0x684b, 0x0015, 0xd1fc, 0x0040, 0x823f, + 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, 0x0000, 0x6962, + 0x685e, 0x007c, 0xa182, 0x0040, 0x0079, 0x8246, 0x8259, 0x8259, + 0x8259, 0x8259, 0x8259, 0x825b, 0x8259, 0x8333, 0x833f, 0x8259, + 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, + 0x8259, 0x1078, 0x1328, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, + 0xa88c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x0f7e, 0x2c78, + 0x1078, 0x4893, 0x0f7f, 0x0040, 0x827e, 0xa684, 0x00ff, 0x00c0, + 0x827e, 0x6024, 0xd0f4, 0x00c0, 0x827a, 0x7808, 0xa086, 0x0000, + 0x00c0, 0x827e, 0x1078, 0x8cfa, 0x0078, 0x832e, 0x7e46, 0x7f4c, + 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, + 0x0040, 0x8323, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, 0x8294, + 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, 0x8320, + 0xa686, 0x0100, 0x00c0, 0x82a6, 0x2001, 0xa899, 0x2004, 0xa005, + 0x00c0, 0x82a6, 0xc6c4, 0x7e46, 0x0078, 0x8287, 0x1078, 0x1381, + 0x1040, 0x1328, 0x2d00, 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, + 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, + 0x6e46, 0xa68c, 0x0c00, 0x0040, 0x82c1, 0x7318, 0x6b62, 0x731c, + 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x82dd, 0xa186, + 0x0028, 0x00c0, 0x82cf, 0x684b, 0x001c, 0x0078, 0x82df, 0xd6dc, + 0x0040, 0x82d6, 0x684b, 0x0015, 0x0078, 0x82df, 0xd6d4, 0x0040, + 0x82dd, 0x684b, 0x0007, 0x0078, 0x82df, 0x684b, 0x0000, 0x6f4e, + 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x82fd, + 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0040, 0x82fd, 0xa38a, 0x0009, + 0x0048, 0x82f4, 0x2019, 0x0008, 0x037e, 0x2308, 0x2019, 0xa898, + 0xad90, 0x0019, 0x1078, 0x8739, 0x037f, 0xd6cc, 0x0040, 0x8320, + 0x7124, 0x695a, 0x81ff, 0x0040, 0x8320, 0xa192, 0x0021, 0x00c8, + 0x8314, 0x2071, 0xa898, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, + 0x1078, 0x8739, 0x0078, 0x8320, 0x7838, 0xd0fc, 0x0040, 0x831d, + 0x2009, 0x0020, 0x695a, 0x0078, 0x8309, 0x2d78, 0x1078, 0x86d1, + 0xd6dc, 0x00c0, 0x8326, 0xa006, 0x0078, 0x832c, 0x2001, 0x0001, + 0x2071, 0xa88c, 0x7218, 0x731c, 0x1078, 0x1645, 0x0d7f, 0x0e7f, + 0x0f7f, 0x077f, 0x007c, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x20e1, + 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0x2001, + 0xa5a2, 0x2004, 0x603e, 0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168, + 0x694c, 0xd1e4, 0x0040, 0x846b, 0x603f, 0x0000, 0x0f7e, 0x2c78, + 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8385, 0x6814, 0x6910, 0xa115, + 0x0040, 0x8385, 0x6a60, 0xa206, 0x00c0, 0x8362, 0x685c, 0xa106, + 0x0040, 0x8385, 0x684c, 0xc0e4, 0x684e, 0x6847, 0x0000, 0x6863, + 0x0000, 0x685f, 0x0000, 0x6024, 0xd0f4, 0x00c0, 0x837a, 0x697c, + 0x6810, 0xa102, 0x603a, 0x6980, 0x6814, 0xa103, 0x6036, 0x6024, + 0xc0f5, 0x6026, 0x0d7e, 0x6018, 0x2068, 0x683c, 0x8000, 0x683e, + 0x0d7f, 0x1078, 0x8cfa, 0x0078, 0x846b, 0x694c, 0xd1cc, 0x0040, + 0x8430, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x83ea, 0x017e, 0x684c, + 0x007e, 0x6850, 0x007e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, + 0xa0b6, 0x0002, 0x0040, 0x83bf, 0xa086, 0x0028, 0x00c0, 0x83a6, + 0x684b, 0x001c, 0x784b, 0x001c, 0x0078, 0x83ca, 0xd1dc, 0x0040, + 0x83b6, 0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x8ea5, 0x0040, + 0x83b4, 0x7944, 0xc1dc, 0x7946, 0x0078, 0x83ca, 0xd1d4, 0x0040, + 0x83bf, 0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x83ca, 0x684c, + 0xd0ac, 0x0040, 0x83ca, 0x6810, 0x6914, 0xa115, 0x0040, 0x83ca, + 0x1078, 0x8233, 0x6848, 0x784a, 0x6860, 0x7862, 0x685c, 0x785e, + 0xad90, 0x000d, 0xaf98, 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, + 0x2304, 0x2012, 0x8318, 0x8210, 0x00f0, 0x83d8, 0x157f, 0x0f7f, + 0x007f, 0x6852, 0x007f, 0x684e, 0x017f, 0x2168, 0x1078, 0x13aa, + 0x0078, 0x8465, 0x017e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, + 0xa0b6, 0x0002, 0x0040, 0x8417, 0xa086, 0x0028, 0x00c0, 0x83fe, + 0x684b, 0x001c, 0x784b, 0x001c, 0x0078, 0x8422, 0xd1dc, 0x0040, + 0x840e, 0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x8ea5, 0x0040, + 0x840c, 0x7944, 0xc1dc, 0x7946, 0x0078, 0x8422, 0xd1d4, 0x0040, + 0x8417, 0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x8422, 0x684c, + 0xd0ac, 0x0040, 0x8422, 0x6810, 0x6914, 0xa115, 0x0040, 0x8422, + 0x1078, 0x8233, 0x6860, 0x7862, 0x685c, 0x785e, 0x684c, 0x784e, + 0x0f7f, 0x1078, 0x13aa, 0x0d7f, 0x1078, 0x8726, 0x0078, 0x8465, + 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040, + 0x8456, 0xa086, 0x0028, 0x00c0, 0x8441, 0x684b, 0x001c, 0x0078, + 0x8463, 0xd1dc, 0x0040, 0x844f, 0x684b, 0x0015, 0x1078, 0x8ea5, + 0x0040, 0x844d, 0x6944, 0xc1dc, 0x6946, 0x0078, 0x8463, 0xd1d4, + 0x0040, 0x8456, 0x684b, 0x0007, 0x0078, 0x8463, 0x684b, 0x0000, + 0x684c, 0xd0ac, 0x0040, 0x8463, 0x6810, 0x6914, 0xa115, 0x0040, + 0x8463, 0x1078, 0x8233, 0x1078, 0x4982, 0x1078, 0x8cc4, 0x00c0, + 0x846b, 0x1078, 0x753d, 0x0d7f, 0x007c, 0x1078, 0x6010, 0x0078, + 0x8473, 0x1078, 0x60b8, 0x1078, 0x8a44, 0x0040, 0x8492, 0x0d7e, + 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0xa30c, 0x210c, 0xd18c, + 0x00c0, 0x849d, 0xd184, 0x00c0, 0x8499, 0x6108, 0x694a, 0xa18e, + 0x0029, 0x00c0, 0x848d, 0x1078, 0xa181, 0x6847, 0x0000, 0x1078, + 0x4982, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, 0x1078, 0x61d3, + 0x007c, 0x684b, 0x0004, 0x0078, 0x848d, 0x684b, 0x0004, 0x0078, + 0x848d, 0xa182, 0x0040, 0x0079, 0x84a5, 0x84b8, 0x84b8, 0x84b8, + 0x84b8, 0x84b8, 0x84ba, 0x84b8, 0x84bd, 0x84b8, 0x84b8, 0x84b8, + 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, + 0x1078, 0x1328, 0x1078, 0x753d, 0x007c, 0x007e, 0x027e, 0xa016, + 0x1078, 0x15ec, 0x027f, 0x007f, 0x007c, 0xa182, 0x0085, 0x0079, + 0x84c9, 0x84d2, 0x84d0, 0x84d0, 0x84de, 0x84d0, 0x84d0, 0x84d0, + 0x1078, 0x1328, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e, + 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x027e, 0x057e, + 0x0d7e, 0x0e7e, 0x2071, 0xa880, 0x7224, 0x6212, 0x7220, 0x1078, + 0x8a30, 0x0040, 0x8503, 0x2268, 0x6800, 0xa086, 0x0000, 0x0040, + 0x8503, 0x6018, 0x6d18, 0xa52e, 0x00c0, 0x8503, 0x0c7e, 0x2d60, + 0x1078, 0x874a, 0x0c7f, 0x0040, 0x8503, 0x6803, 0x0002, 0x6007, + 0x0086, 0x0078, 0x8505, 0x6007, 0x0087, 0x6003, 0x0001, 0x1078, + 0x5bf8, 0x1078, 0x6109, 0x0f7e, 0x2278, 0x1078, 0x4893, 0x0f7f, + 0x0040, 0x851d, 0x6824, 0xd0ec, 0x0040, 0x851d, 0x0c7e, 0x2260, + 0x603f, 0x0000, 0x1078, 0x8cfa, 0x0c7f, 0x0e7f, 0x0d7f, 0x057f, + 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x8533, 0x6004, 0xa08a, + 0x0085, 0x1048, 0x1328, 0xa08a, 0x008c, 0x10c8, 0x1328, 0xa082, + 0x0085, 0x0079, 0x8542, 0xa186, 0x0027, 0x0040, 0x853b, 0xa186, + 0x0014, 0x10c0, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, + 0x6109, 0x007c, 0x8549, 0x854b, 0x854b, 0x8549, 0x8549, 0x8549, + 0x8549, 0x1078, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, + 0x6109, 0x007c, 0xa186, 0x0013, 0x00c0, 0x855c, 0x6004, 0xa082, + 0x0085, 0x2008, 0x0078, 0x8597, 0xa186, 0x0027, 0x00c0, 0x857f, + 0x1078, 0x6010, 0x1078, 0x2813, 0x0d7e, 0x6010, 0x2068, 0x1078, + 0x8a44, 0x0040, 0x8575, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, + 0x0029, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, + 0x1078, 0x6109, 0x007c, 0x1078, 0x7583, 0x0078, 0x857a, 0xa186, + 0x0014, 0x00c0, 0x857b, 0x1078, 0x6010, 0x0d7e, 0x6010, 0x2068, + 0x1078, 0x8a44, 0x0040, 0x8575, 0x6837, 0x0103, 0x6847, 0x0000, + 0x684b, 0x0006, 0x6850, 0xc0ec, 0x6852, 0x0078, 0x8571, 0x0079, + 0x8599, 0x85a2, 0x85a0, 0x85a0, 0x85a0, 0x85a0, 0x85a0, 0x85bd, + 0x1078, 0x1328, 0x1078, 0x6010, 0x6030, 0xa08c, 0xff00, 0x810f, + 0xa186, 0x0039, 0x0040, 0x85b0, 0xa186, 0x0035, 0x00c0, 0x85b4, + 0x2001, 0xa5a0, 0x0078, 0x85b6, 0x2001, 0xa5a1, 0x2004, 0x6016, + 0x6003, 0x000c, 0x1078, 0x6109, 0x007c, 0x1078, 0x6010, 0x6030, + 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x85cb, 0xa186, + 0x0035, 0x00c0, 0x85cf, 0x2001, 0xa5a0, 0x0078, 0x85d1, 0x2001, + 0xa5a1, 0x2004, 0x6016, 0x6003, 0x000e, 0x1078, 0x6109, 0x007c, + 0xa182, 0x008c, 0x00c8, 0x85e2, 0xa182, 0x0085, 0x0048, 0x85e2, + 0x0079, 0x85e5, 0x1078, 0x7583, 0x007c, 0x85ec, 0x85ec, 0x85ec, + 0x85ec, 0x85ee, 0x8643, 0x85ec, 0x1078, 0x1328, 0x0f7e, 0x2c78, + 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8601, 0x6030, 0xa08c, 0xff00, + 0x810f, 0xa186, 0x0039, 0x0040, 0x865a, 0xa186, 0x0035, 0x0040, + 0x865a, 0x0d7e, 0x1078, 0x8bf4, 0x1078, 0x8a44, 0x0040, 0x8625, + 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x8616, + 0x684b, 0x0006, 0xc0ec, 0x6852, 0x0078, 0x8621, 0xd0bc, 0x0040, + 0x861d, 0x684b, 0x0002, 0x0078, 0x8621, 0x684b, 0x0005, 0x1078, + 0x8cc0, 0x6847, 0x0000, 0x1078, 0x4982, 0x2c68, 0x1078, 0x74d7, + 0x0040, 0x863e, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xa88e, + 0x210c, 0x6136, 0x2009, 0xa88f, 0x210c, 0x613a, 0x6918, 0x611a, + 0x6920, 0x6122, 0x601f, 0x0001, 0x1078, 0x5bf8, 0x2d60, 0x1078, + 0x753d, 0x0d7f, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, + 0x0040, 0x8680, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035, + 0x0040, 0x865a, 0xa186, 0x001e, 0x0040, 0x865a, 0xa186, 0x0039, + 0x00c0, 0x8680, 0x0d7e, 0x2c68, 0x1078, 0x8ef5, 0x00c0, 0x86a4, + 0x1078, 0x74d7, 0x0040, 0x867d, 0x6106, 0x6003, 0x0001, 0x601f, + 0x0001, 0x6918, 0x611a, 0x6928, 0x612a, 0x692c, 0x612e, 0x6930, + 0xa18c, 0x00ff, 0x6132, 0x6934, 0x6136, 0x6938, 0x613a, 0x6920, + 0x6122, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x2d60, 0x0078, 0x86a4, + 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x86a4, 0x6837, + 0x0103, 0x6850, 0xd0b4, 0x0040, 0x8693, 0xc0ec, 0x6852, 0x684b, + 0x0006, 0x0078, 0x869e, 0xd0bc, 0x0040, 0x869a, 0x684b, 0x0002, + 0x0078, 0x869e, 0x684b, 0x0005, 0x1078, 0x8cc0, 0x6847, 0x0000, + 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x007c, + 0x017e, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x86b8, + 0x6837, 0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x1078, 0x4982, + 0x0d7f, 0x017f, 0xa186, 0x0013, 0x0040, 0x86ca, 0xa186, 0x0014, + 0x0040, 0x86ca, 0xa186, 0x0027, 0x0040, 0x86ca, 0x1078, 0x7583, + 0x0078, 0x86d0, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, + 0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, 0xa182, + 0x0101, 0x00c8, 0x86dd, 0x0078, 0x86df, 0x2009, 0x0100, 0x2130, + 0x2069, 0xa898, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, + 0x001d, 0x1078, 0x8739, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0040, + 0x86f3, 0x1078, 0x13aa, 0x1078, 0x1381, 0x0040, 0x871d, 0x8528, + 0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, + 0x00c8, 0x8709, 0x2608, 0xad90, 0x000f, 0x1078, 0x8739, 0x0078, + 0x871d, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, 0x000f, + 0x1078, 0x8739, 0x0078, 0x86f3, 0x0f7f, 0x852f, 0xa5ad, 0x0003, + 0x7d36, 0xa5ac, 0x0000, 0x0078, 0x8722, 0x0f7f, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, 0x8dff, + 0x0040, 0x8737, 0x6804, 0xa07d, 0x0040, 0x8735, 0x6807, 0x0000, + 0x1078, 0x4982, 0x2f68, 0x0078, 0x872a, 0x1078, 0x4982, 0x0f7f, + 0x007c, 0x157e, 0xa184, 0x0001, 0x0040, 0x873f, 0x8108, 0x810c, + 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, 0x8741, + 0x157f, 0x007c, 0x067e, 0x127e, 0x2091, 0x8000, 0x2031, 0x0001, + 0x601c, 0xa084, 0x000f, 0x1079, 0x8766, 0x127f, 0x067f, 0x007c, + 0x127e, 0x2091, 0x8000, 0x067e, 0x2031, 0x0000, 0x601c, 0xa084, + 0x000f, 0x1079, 0x8766, 0x067f, 0x127f, 0x007c, 0x8780, 0x876e, + 0x877b, 0x879c, 0x876e, 0x877b, 0x879c, 0x877b, 0x1078, 0x1328, + 0x037e, 0x2019, 0x0010, 0x1078, 0x9a6a, 0x601f, 0x0006, 0x6003, + 0x0007, 0x037f, 0x007c, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, + 0x0d7e, 0x86ff, 0x00c0, 0x8797, 0x6010, 0x2068, 0x1078, 0x8a44, + 0x0040, 0x8799, 0xa00e, 0x2001, 0x0005, 0x1078, 0x4a60, 0x1078, + 0x8cc0, 0x1078, 0x4982, 0x1078, 0x753d, 0xa085, 0x0001, 0x0d7f, + 0x007c, 0xa006, 0x0078, 0x8797, 0x6000, 0xa08a, 0x0010, 0x10c8, + 0x1328, 0x1079, 0x87a4, 0x007c, 0x87b4, 0x87d4, 0x87b6, 0x87f7, + 0x87d0, 0x87b4, 0x877b, 0x8780, 0x8780, 0x877b, 0x877b, 0x877b, + 0x877b, 0x877b, 0x877b, 0x877b, 0x1078, 0x1328, 0x86ff, 0x00c0, + 0x87cd, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x87c2, + 0x1078, 0x8cc0, 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, + 0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0xa085, 0x0001, 0x007c, + 0x1078, 0x1749, 0x0078, 0x87b6, 0x0e7e, 0x2071, 0xa5ab, 0x7024, + 0xac06, 0x00c0, 0x87dd, 0x1078, 0x6dda, 0x601c, 0xa084, 0x000f, + 0xa086, 0x0006, 0x00c0, 0x87ef, 0x087e, 0x097e, 0x2049, 0x0001, + 0x2c40, 0x1078, 0x7058, 0x097f, 0x087f, 0x0078, 0x87f1, 0x1078, + 0x6cd2, 0x0e7f, 0x00c0, 0x87b6, 0x1078, 0x877b, 0x007c, 0x037e, + 0x0e7e, 0x2071, 0xa5ab, 0x703c, 0xac06, 0x00c0, 0x8807, 0x2019, + 0x0000, 0x1078, 0x6e6c, 0x0e7f, 0x037f, 0x0078, 0x87b6, 0x1078, + 0x719a, 0x0e7f, 0x037f, 0x00c0, 0x87b6, 0x1078, 0x877b, 0x007c, + 0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, 0x8818, 0x0c7f, 0x007c, + 0x8827, 0x8895, 0x89cd, 0x8832, 0x8c01, 0x8827, 0x9a5b, 0x753d, + 0x8895, 0x1078, 0x8c3b, 0x00c0, 0x8827, 0x1078, 0x7a05, 0x007c, + 0x1078, 0x6010, 0x1078, 0x6109, 0x1078, 0x753d, 0x007c, 0x6017, + 0x0001, 0x007c, 0x6010, 0xa080, 0x0019, 0x2c02, 0x6000, 0xa08a, + 0x0010, 0x10c8, 0x1328, 0x1079, 0x883e, 0x007c, 0x884e, 0x8850, + 0x8872, 0x8884, 0x8891, 0x884e, 0x8827, 0x8827, 0x8827, 0x8884, + 0x8884, 0x884e, 0x884e, 0x884e, 0x884e, 0x888e, 0x1078, 0x1328, + 0x0e7e, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0xa5ab, + 0x7024, 0xac06, 0x0040, 0x886e, 0x1078, 0x6cd2, 0x6007, 0x0085, + 0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xa5a1, 0x2004, 0x6016, + 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x007c, 0x6017, 0x0001, + 0x0078, 0x886c, 0x0d7e, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, + 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, + 0x5bf8, 0x1078, 0x6109, 0x007c, 0x0d7e, 0x6017, 0x0001, 0x6010, + 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x007c, 0x1078, 0x753d, + 0x007c, 0x1078, 0x1749, 0x0078, 0x8872, 0x6000, 0xa08a, 0x0010, + 0x10c8, 0x1328, 0x1079, 0x889d, 0x007c, 0x88ad, 0x882f, 0x88af, + 0x88ad, 0x88af, 0x88af, 0x8828, 0x88ad, 0x8821, 0x8821, 0x88ad, + 0x88ad, 0x88ad, 0x88ad, 0x88ad, 0x88ad, 0x1078, 0x1328, 0x0d7e, + 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa08a, 0x000c, + 0x10c8, 0x1328, 0x1079, 0x88bd, 0x007c, 0x88c9, 0x8971, 0x88cb, + 0x890b, 0x88cb, 0x890b, 0x88cb, 0x88d8, 0x88c9, 0x890b, 0x88c9, + 0x88f5, 0x1078, 0x1328, 0x6004, 0xa08e, 0x0016, 0x0040, 0x8906, + 0xa08e, 0x0004, 0x0040, 0x8906, 0xa08e, 0x0002, 0x0040, 0x8906, + 0x6004, 0x1078, 0x8c3b, 0x0040, 0x898c, 0xa08e, 0x0021, 0x0040, + 0x8990, 0xa08e, 0x0022, 0x0040, 0x898c, 0xa08e, 0x003d, 0x0040, + 0x8990, 0xa08e, 0x0039, 0x0040, 0x8994, 0xa08e, 0x0035, 0x0040, + 0x8994, 0xa08e, 0x001e, 0x0040, 0x8908, 0xa08e, 0x0001, 0x00c0, + 0x8904, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, + 0xa086, 0x0006, 0x0040, 0x8906, 0x1078, 0x2813, 0x1078, 0x7a05, + 0x1078, 0x8c01, 0x007c, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, + 0x0040, 0x8961, 0xa186, 0x0002, 0x00c0, 0x8934, 0x6018, 0x2068, + 0x68a0, 0xd0bc, 0x00c0, 0x89b8, 0x6840, 0xa084, 0x00ff, 0xa005, + 0x0040, 0x8934, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, + 0x6017, 0x0398, 0x1078, 0x74d7, 0x0040, 0x8934, 0x2d00, 0x601a, + 0x601f, 0x0001, 0x0078, 0x8961, 0x0d7f, 0x0c7f, 0x6004, 0xa08e, + 0x0002, 0x00c0, 0x8952, 0x6018, 0xa080, 0x0028, 0x2004, 0xa086, + 0x007e, 0x00c0, 0x8952, 0x2009, 0xa332, 0x2104, 0xc085, 0x200a, + 0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, 0x0e7f, 0x1078, 0x7a05, + 0x0078, 0x8956, 0x1078, 0x7a05, 0x1078, 0x2813, 0x0e7e, 0x127e, + 0x2091, 0x8000, 0x1078, 0x2839, 0x127f, 0x0e7f, 0x1078, 0x8c01, + 0x007c, 0x2001, 0x0002, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, + 0x0002, 0x1078, 0x5c45, 0x1078, 0x6109, 0x0d7f, 0x0c7f, 0x0078, + 0x8960, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, 0x0040, 0x8961, + 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x8934, + 0x8001, 0x6842, 0x6003, 0x0001, 0x1078, 0x5c45, 0x1078, 0x6109, + 0x0d7f, 0x0c7f, 0x0078, 0x8960, 0x1078, 0x7a05, 0x0078, 0x8908, + 0x1078, 0x7a28, 0x0078, 0x8908, 0x0d7e, 0x2c68, 0x6104, 0x1078, + 0x8ef5, 0x0d7f, 0x0040, 0x89a0, 0x1078, 0x753d, 0x0078, 0x89b7, + 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, 0x6032, 0x6007, + 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038, 0x600a, 0x2001, + 0xa5a1, 0x2004, 0x6016, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x007c, + 0x0d7f, 0x0c7f, 0x1078, 0x7a05, 0x1078, 0x2813, 0x0e7e, 0x127e, + 0x2091, 0x8000, 0x1078, 0x2839, 0x6013, 0x0000, 0x601f, 0x0007, + 0x6017, 0x0398, 0x127f, 0x0e7f, 0x007c, 0x6000, 0xa08a, 0x0010, + 0x10c8, 0x1328, 0x1079, 0x89d5, 0x007c, 0x89e5, 0x89e5, 0x89e5, + 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x8827, 0x89e5, + 0x882f, 0x89e7, 0x882f, 0x89f5, 0x89e5, 0x1078, 0x1328, 0x6004, + 0xa086, 0x008b, 0x0040, 0x89f5, 0x6007, 0x008b, 0x6003, 0x000d, + 0x1078, 0x5bf8, 0x1078, 0x6109, 0x007c, 0x1078, 0x8bf4, 0x1078, + 0x8a44, 0x0040, 0x8a2d, 0x1078, 0x2813, 0x0d7e, 0x1078, 0x8a44, + 0x0040, 0x8a0f, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006, + 0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x1078, 0x4982, 0x2c68, + 0x1078, 0x74d7, 0x0040, 0x8a1d, 0x6818, 0x601a, 0x0c7e, 0x2d60, + 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x8a1e, 0x2d60, 0x0d7f, 0x6013, + 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, + 0x5c45, 0x1078, 0x6109, 0x0078, 0x8a2f, 0x1078, 0x8c01, 0x007c, + 0xa284, 0x000f, 0x00c0, 0x8a41, 0xa282, 0xaa00, 0x0048, 0x8a41, + 0x2001, 0xa315, 0x2004, 0xa202, 0x00c8, 0x8a41, 0xa085, 0x0001, + 0x007c, 0xa006, 0x0078, 0x8a40, 0x027e, 0x0e7e, 0x2071, 0xa300, + 0x6210, 0x7058, 0xa202, 0x0048, 0x8a56, 0x705c, 0xa202, 0x00c8, + 0x8a56, 0xa085, 0x0001, 0x0e7f, 0x027f, 0x007c, 0xa006, 0x0078, + 0x8a53, 0x0e7e, 0x0c7e, 0x037e, 0x007e, 0x127e, 0x2091, 0x8000, + 0x2061, 0xaa00, 0x2071, 0xa300, 0x7344, 0x7060, 0xa302, 0x00c8, + 0x8a83, 0x601c, 0xa206, 0x00c0, 0x8a7b, 0x1078, 0x8d66, 0x0040, + 0x8a7b, 0x1078, 0x8c3b, 0x00c0, 0x8a77, 0x1078, 0x7a05, 0x0c7e, + 0x1078, 0x753d, 0x0c7f, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, + 0x8a83, 0x0078, 0x8a64, 0x127f, 0x007f, 0x037f, 0x0c7f, 0x0e7f, + 0x007c, 0x0e7e, 0x0c7e, 0x017e, 0xa188, 0xa434, 0x210c, 0x81ff, + 0x0040, 0x8aa1, 0x2061, 0xaa00, 0x2071, 0xa300, 0x017e, 0x1078, + 0x74d7, 0x017f, 0x0040, 0x8aa4, 0x611a, 0x1078, 0x2813, 0x1078, + 0x753d, 0xa006, 0x0078, 0x8aa6, 0xa085, 0x0001, 0x017f, 0x0c7f, + 0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e, + 0x1078, 0x74d7, 0x057f, 0x0040, 0x8ac3, 0x6612, 0x651a, 0x601f, + 0x0003, 0x2009, 0x004b, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, + 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8abf, 0x0c7e, 0x057e, + 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x74d7, 0x057f, + 0x0040, 0x8af1, 0x6013, 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e, + 0x2560, 0x1078, 0x471b, 0x0c7f, 0x1078, 0x5d53, 0x077e, 0x2039, + 0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x2009, + 0x004c, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, + 0x007c, 0xa006, 0x0078, 0x8aed, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, + 0x1078, 0x74d7, 0x2c78, 0x0c7f, 0x0040, 0x8b0e, 0x7e12, 0x2c00, + 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x1078, 0x8b4e, 0x2f60, + 0x2009, 0x004d, 0x1078, 0x756c, 0xa085, 0x0001, 0x047f, 0x0c7f, + 0x0f7f, 0x007c, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x74d7, + 0x2c78, 0x0c7f, 0x0040, 0x8b2c, 0x7e12, 0x2c00, 0x781a, 0x781f, + 0x0003, 0x2021, 0x0005, 0x1078, 0x8b4e, 0x2f60, 0x2009, 0x004e, + 0x1078, 0x756c, 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c, + 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x74d7, 0x2c78, 0x0c7f, + 0x0040, 0x8b4a, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, + 0x0004, 0x1078, 0x8b4e, 0x2f60, 0x2009, 0x0052, 0x1078, 0x756c, + 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c, 0x097e, 0x077e, + 0x127e, 0x2091, 0x8000, 0x1078, 0x46a7, 0x0040, 0x8b5b, 0x2001, + 0x8b53, 0x0078, 0x8b61, 0x1078, 0x466d, 0x0040, 0x8b6a, 0x2001, + 0x8b5b, 0x007e, 0xa00e, 0x2400, 0x1078, 0x4a60, 0x1078, 0x4982, + 0x007f, 0x007a, 0x2418, 0x1078, 0x5fa7, 0x62a0, 0x087e, 0x2041, + 0x0001, 0x2039, 0x0001, 0x2608, 0x1078, 0x5d6d, 0x087f, 0x1078, + 0x5c78, 0x2f08, 0x2648, 0x1078, 0x9c38, 0x613c, 0x81ff, 0x1040, + 0x5e21, 0x127f, 0x077f, 0x097f, 0x007c, 0x0c7e, 0x127e, 0x2091, + 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8b9e, 0x660a, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x001f, 0x1078, + 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, + 0x8b9b, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7, + 0x017f, 0x0040, 0x8bba, 0x660a, 0x611a, 0x601f, 0x0008, 0x2d00, + 0x6012, 0x2009, 0x0021, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, + 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8bb7, 0x0c7e, 0x127e, 0x2091, + 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8bd6, 0x660a, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x003d, 0x1078, + 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, + 0x8bd3, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7, + 0x017f, 0x0040, 0x8bf1, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, + 0x2009, 0x0000, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, + 0x007c, 0xa006, 0x0078, 0x8bee, 0x027e, 0x0d7e, 0x6218, 0x2268, + 0x6a3c, 0x82ff, 0x0040, 0x8bfe, 0x8211, 0x6a3e, 0x0d7f, 0x027f, + 0x007c, 0x007e, 0x6000, 0xa086, 0x0000, 0x0040, 0x8c13, 0x6013, + 0x0000, 0x601f, 0x0007, 0x2001, 0xa5a1, 0x2004, 0x6016, 0x1078, + 0xa134, 0x603f, 0x0000, 0x007f, 0x007c, 0x067e, 0x0c7e, 0x0d7e, + 0x2031, 0xa352, 0x2634, 0xd6e4, 0x0040, 0x8c23, 0x6618, 0x2660, + 0x6e48, 0x1078, 0x461b, 0x0d7f, 0x0c7f, 0x067f, 0x007c, 0x007e, + 0x017e, 0x6004, 0xa08e, 0x0002, 0x0040, 0x8c38, 0xa08e, 0x0003, + 0x0040, 0x8c38, 0xa08e, 0x0004, 0x0040, 0x8c38, 0xa085, 0x0001, + 0x017f, 0x007f, 0x007c, 0x007e, 0x0d7e, 0x6010, 0xa06d, 0x0040, + 0x8c48, 0x6838, 0xd0fc, 0x0040, 0x8c48, 0xa006, 0x0078, 0x8c4a, + 0xa085, 0x0001, 0x0d7f, 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091, + 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8c67, 0x611a, + 0x601f, 0x0001, 0x2d00, 0x6012, 0x1078, 0x2813, 0x2009, 0x0028, + 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, + 0x0078, 0x8c64, 0xa186, 0x0015, 0x00c0, 0x8c7f, 0x2011, 0xa31f, + 0x2204, 0xa086, 0x0074, 0x00c0, 0x8c7f, 0x1078, 0x7d0d, 0x6003, + 0x0001, 0x6007, 0x0029, 0x1078, 0x5c45, 0x0078, 0x8c83, 0x1078, + 0x7a05, 0x1078, 0x753d, 0x007c, 0xa186, 0x0016, 0x00c0, 0x8c8e, + 0x2001, 0x0004, 0x1078, 0x443f, 0x0078, 0x8caf, 0xa186, 0x0015, + 0x00c0, 0x8cb3, 0x2011, 0xa31f, 0x2204, 0xa086, 0x0014, 0x00c0, + 0x8cb3, 0x0d7e, 0x6018, 0x2068, 0x1078, 0x457d, 0x0d7f, 0x1078, + 0x7dba, 0x00c0, 0x8cb3, 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, + 0xa005, 0x0040, 0x8cb3, 0x2001, 0x0006, 0x1078, 0x443f, 0x1078, + 0x7608, 0x0078, 0x8cb7, 0x1078, 0x7a05, 0x1078, 0x753d, 0x007c, + 0x6848, 0xa086, 0x0005, 0x00c0, 0x8cbf, 0x1078, 0x8cc0, 0x007c, + 0x6850, 0xc0ad, 0x6852, 0x007c, 0x0e7e, 0x2071, 0xa88c, 0x7014, + 0xd0e4, 0x0040, 0x8cd5, 0x6013, 0x0000, 0x6003, 0x0001, 0x6007, + 0x0050, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x007c, 0x0c7e, + 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8ce4, 0x601c, + 0xa084, 0x000f, 0x1079, 0x8ce6, 0x0c7f, 0x007c, 0x8827, 0x8cf1, + 0x8cf4, 0x8cf7, 0x9f00, 0x9f1c, 0x9f1f, 0x8827, 0x8827, 0x1078, + 0x1328, 0x0005, 0x0005, 0x007c, 0x0005, 0x0005, 0x007c, 0x1078, + 0x8cfa, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0040, 0x8d29, + 0x1078, 0x74d7, 0x00c0, 0x8d0a, 0x2001, 0xa5a2, 0x2004, 0x783e, + 0x0078, 0x8d29, 0x7818, 0x601a, 0x781c, 0xa086, 0x0003, 0x0040, + 0x8d17, 0x7808, 0x6036, 0x2f00, 0x603a, 0x0078, 0x8d1b, 0x7808, + 0x603a, 0x2f00, 0x6036, 0x602a, 0x601f, 0x0001, 0x6007, 0x0035, + 0x6003, 0x0001, 0x7920, 0x6122, 0x1078, 0x5bf8, 0x1078, 0x6109, + 0x2f60, 0x0f7f, 0x007c, 0x017e, 0x0f7e, 0x682c, 0x6032, 0xa08e, + 0x0001, 0x0040, 0x8d3c, 0xa086, 0x0005, 0x0040, 0x8d40, 0xa006, + 0x602a, 0x602e, 0x0078, 0x8d51, 0x6824, 0xc0f4, 0xc0d5, 0x6826, + 0x6810, 0x2078, 0x787c, 0x6938, 0xa102, 0x7880, 0x6934, 0xa103, + 0x00c8, 0x8d37, 0x6834, 0x602a, 0x6838, 0xa084, 0xfffc, 0x683a, + 0x602e, 0x2d00, 0x6036, 0x6808, 0x603a, 0x6918, 0x611a, 0x6920, + 0x6122, 0x601f, 0x0001, 0x6007, 0x0039, 0x6003, 0x0001, 0x1078, + 0x5bf8, 0x6803, 0x0002, 0x0f7f, 0x017f, 0x007c, 0x007e, 0x017e, + 0x6004, 0xa08e, 0x0034, 0x0040, 0x8d8b, 0xa08e, 0x0035, 0x0040, + 0x8d8b, 0xa08e, 0x0036, 0x0040, 0x8d8b, 0xa08e, 0x0037, 0x0040, + 0x8d8b, 0xa08e, 0x0038, 0x0040, 0x8d8b, 0xa08e, 0x0039, 0x0040, + 0x8d8b, 0xa08e, 0x003a, 0x0040, 0x8d8b, 0xa08e, 0x003b, 0x0040, + 0x8d8b, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, 0x0f7e, 0x2c78, + 0x1078, 0x4893, 0x00c0, 0x8d98, 0xa085, 0x0001, 0x0078, 0x8da7, + 0x6024, 0xd0f4, 0x00c0, 0x8da6, 0xc0f5, 0x6026, 0x6010, 0x2078, + 0x7828, 0x603a, 0x782c, 0x6036, 0x1078, 0x1749, 0xa006, 0x0f7f, + 0x007c, 0x007e, 0x017e, 0x027e, 0x037e, 0x0e7e, 0x2001, 0xa59c, + 0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x1078, 0x5a98, 0x2001, + 0xa5a0, 0x82ff, 0x00c0, 0x8dbe, 0x2011, 0x0002, 0x2202, 0x2001, + 0xa59e, 0x200c, 0x8000, 0x2014, 0x2071, 0xa58c, 0x711a, 0x721e, + 0x2001, 0x0064, 0x1078, 0x5a98, 0x2001, 0xa5a1, 0x82ff, 0x00c0, + 0x8dd3, 0x2011, 0x0002, 0x2202, 0x2009, 0xa5a2, 0xa280, 0x000a, + 0x200a, 0x0e7f, 0x037f, 0x027f, 0x017f, 0x007f, 0x007c, 0x007e, + 0x0e7e, 0x2001, 0xa5a0, 0x2003, 0x0028, 0x2001, 0xa5a1, 0x2003, + 0x0014, 0x2071, 0xa58c, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001, + 0xa5a2, 0x2003, 0x001e, 0x0e7f, 0x007f, 0x007c, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8e0e, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033, 0x1078, + 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, + 0x8e0b, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071, 0xa300, 0xa186, 0x0015, + 0x00c0, 0x8e40, 0x707c, 0xa086, 0x0018, 0x00c0, 0x8e40, 0x6010, + 0x2068, 0x6a3c, 0xd2e4, 0x00c0, 0x8e34, 0x2c78, 0x1078, 0x62c6, + 0x0040, 0x8e48, 0x7068, 0x6a50, 0xa206, 0x00c0, 0x8e3c, 0x706c, + 0x6a54, 0xa206, 0x00c0, 0x8e3c, 0x6218, 0xa290, 0x0028, 0x2214, + 0x2009, 0x0000, 0x1078, 0x285b, 0x1078, 0x7608, 0x0078, 0x8e44, + 0x1078, 0x7a05, 0x1078, 0x753d, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, + 0x704c, 0xa080, 0x293f, 0x2004, 0x6a54, 0xa206, 0x0040, 0x8e34, + 0x0078, 0x8e3c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, + 0x74d7, 0x017f, 0x0040, 0x8e6a, 0x611a, 0x601f, 0x0001, 0x2d00, + 0x6012, 0x2009, 0x0043, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, + 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8e67, 0x0d7e, 0x0e7e, 0x0f7e, + 0x2071, 0xa300, 0xa186, 0x0015, 0x00c0, 0x8e93, 0x707c, 0xa086, + 0x0004, 0x00c0, 0x8e93, 0x6010, 0xa0e8, 0x000f, 0x2c78, 0x1078, + 0x62c6, 0x0040, 0x8e9b, 0x7068, 0x6a08, 0xa206, 0x00c0, 0x8e8f, + 0x706c, 0x6a0c, 0xa206, 0x00c0, 0x8e8f, 0x1078, 0x2813, 0x1078, + 0x7608, 0x0078, 0x8e97, 0x1078, 0x7a05, 0x1078, 0x753d, 0x0f7f, + 0x0e7f, 0x0d7f, 0x007c, 0x704c, 0xa080, 0x293f, 0x2004, 0x6a0c, + 0xa206, 0x0040, 0x8e8d, 0x0078, 0x8e8f, 0x017e, 0x027e, 0x684c, + 0xd0ac, 0x0040, 0x8ebd, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040, + 0x8ebd, 0x6860, 0xa106, 0x00c0, 0x8eb9, 0x685c, 0xa206, 0x0040, + 0x8ebd, 0x6962, 0x6a5e, 0xa085, 0x0001, 0x027f, 0x017f, 0x007c, + 0x0e7e, 0x127e, 0x2071, 0xa300, 0x2091, 0x8000, 0x7544, 0xa582, + 0x0001, 0x0048, 0x8ef2, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, + 0x0040, 0x8ede, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, 0x8eda, + 0x0078, 0x8ecd, 0x2061, 0xaa00, 0x0078, 0x8ecd, 0x6003, 0x0008, + 0x8529, 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, 0x8eee, + 0x754a, 0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704b, 0xaa00, + 0x0078, 0x8ee9, 0xa006, 0x0078, 0x8eeb, 0x0c7e, 0x027e, 0x017e, + 0xa186, 0x0035, 0x0040, 0x8eff, 0x6a34, 0x0078, 0x8f00, 0x6a28, + 0x1078, 0x8a30, 0x0040, 0x8f29, 0x2260, 0x611c, 0xa186, 0x0003, + 0x0040, 0x8f0e, 0xa186, 0x0006, 0x00c0, 0x8f25, 0x6834, 0xa206, + 0x0040, 0x8f1d, 0x6838, 0xa206, 0x00c0, 0x8f25, 0x6108, 0x6834, + 0xa106, 0x00c0, 0x8f25, 0x0078, 0x8f22, 0x6008, 0x6938, 0xa106, + 0x00c0, 0x8f25, 0x6018, 0x6918, 0xa106, 0x017f, 0x027f, 0x0c7f, + 0x007c, 0xa085, 0x0001, 0x0078, 0x8f25, 0x067e, 0x6000, 0xa0b2, + 0x0010, 0x10c8, 0x1328, 0x1079, 0x8f37, 0x067f, 0x007c, 0x8f47, + 0x93bb, 0x94d3, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f81, + 0x955e, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x1078, + 0x1328, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1328, 0x1079, + 0x8f53, 0x067f, 0x007c, 0x8f63, 0x99f6, 0x8f63, 0x8f63, 0x8f63, + 0x8f63, 0x8f63, 0x8f63, 0x99b4, 0x9a44, 0x8f63, 0xa053, 0xa087, + 0xa053, 0xa087, 0x8f63, 0x1078, 0x1328, 0x067e, 0x6000, 0xa0b2, + 0x0010, 0x10c8, 0x1328, 0x1079, 0x8f6f, 0x067f, 0x007c, 0x8f7f, + 0x969f, 0x976a, 0x9798, 0x9813, 0x8f7f, 0x9919, 0x98c1, 0x956a, + 0x9988, 0x999e, 0x8f7f, 0x8f7f, 0x8f7f, 0x8f7f, 0x8f7f, 0x1078, + 0x1328, 0xa1b2, 0x0044, 0x10c8, 0x1328, 0x2100, 0x0079, 0x8f88, + 0x8fc8, 0x919a, 0x8fc8, 0x8fc8, 0x8fc8, 0x91a2, 0x8fc8, 0x8fc8, + 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, + 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fca, + 0x902d, 0x9038, 0x9081, 0x909c, 0x911b, 0x918b, 0x8fc8, 0x8fc8, + 0x91a6, 0x8fc8, 0x8fc8, 0x91b5, 0x91bc, 0x8fc8, 0x8fc8, 0x8fc8, + 0x8fc8, 0x8fc8, 0x91ea, 0x8fc8, 0x8fc8, 0x91f5, 0x8fc8, 0x8fc8, + 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x920a, 0x8fc8, 0x8fc8, 0x8fc8, + 0x9291, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x9305, + 0x1078, 0x1328, 0x1078, 0x4897, 0x00c0, 0x8fd7, 0x2001, 0xa332, + 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, 0x8fdf, 0x6007, + 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, 0x9195, 0x1078, + 0x4887, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x6218, 0x2270, + 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, + 0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x017f, + 0x2e60, 0x1078, 0x471b, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, + 0x6618, 0x0c7e, 0x2660, 0x1078, 0x4513, 0x0c7f, 0xa6b0, 0x0001, + 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x901f, 0x1078, + 0x9b6c, 0x00c0, 0x907b, 0x1078, 0x9afd, 0x00c0, 0x901b, 0x6007, + 0x0008, 0x0078, 0x9195, 0x6007, 0x0009, 0x0078, 0x9195, 0x1078, + 0x9d45, 0x0040, 0x9029, 0x1078, 0x9b6c, 0x0040, 0x9013, 0x0078, + 0x907b, 0x6013, 0x1900, 0x0078, 0x901b, 0x6106, 0x1078, 0x9aa8, + 0x6007, 0x0006, 0x0078, 0x9195, 0x6007, 0x0007, 0x0078, 0x9195, + 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x0d7e, 0x6618, 0x2668, 0x6e04, + 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x905d, 0xa686, + 0x0004, 0x0040, 0x905d, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, + 0x0040, 0x905d, 0xa686, 0x0004, 0x0040, 0x905d, 0xa686, 0x0005, + 0x0040, 0x905d, 0x0d7f, 0x0078, 0x907b, 0x1078, 0x9bd2, 0x00c0, + 0x9076, 0xa686, 0x0006, 0x00c0, 0x906f, 0x027e, 0x6218, 0xa290, + 0x0028, 0x2214, 0x2009, 0x0000, 0x1078, 0x285b, 0x027f, 0x1078, + 0x457d, 0x6007, 0x000a, 0x0d7f, 0x0078, 0x9195, 0x6007, 0x000b, + 0x0d7f, 0x0078, 0x9195, 0x1078, 0x2813, 0x6007, 0x0001, 0x0078, + 0x9195, 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x6618, 0x0d7e, 0x2668, + 0x6e04, 0x0d7f, 0xa686, 0x0707, 0x0040, 0x907b, 0x027e, 0x6218, + 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x1078, 0x285b, 0x027f, + 0x6007, 0x000c, 0x0078, 0x9195, 0x1078, 0x4897, 0x00c0, 0x90a9, + 0x2001, 0xa332, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, + 0x90b1, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, + 0x9195, 0x1078, 0x4887, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, + 0x00ff, 0xa082, 0x0006, 0x0048, 0x90f5, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0004, 0x0040, 0x90c8, 0xa686, 0x0006, 0x00c0, 0x907b, + 0x1078, 0x9be1, 0x00c0, 0x90d0, 0x6007, 0x000e, 0x0078, 0x9195, + 0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff, 0x8427, + 0x047e, 0x1078, 0x2813, 0x047f, 0x017e, 0xa006, 0x2009, 0xa352, + 0x210c, 0xd1a4, 0x0040, 0x90ef, 0x2009, 0x0029, 0x1078, 0x9ec0, + 0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x0d7f, 0x017f, + 0x047f, 0x6007, 0x0001, 0x0078, 0x9195, 0x2001, 0x0001, 0x1078, + 0x442b, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019, + 0xa305, 0x2011, 0xa890, 0x1078, 0x7e55, 0x037f, 0x027f, 0x017f, + 0x157f, 0xa005, 0x0040, 0x9115, 0xa6b4, 0xff00, 0x8637, 0xa686, + 0x0006, 0x0040, 0x90c8, 0x0078, 0x907b, 0x6013, 0x1900, 0x6007, + 0x0009, 0x0078, 0x9195, 0x1078, 0x4897, 0x00c0, 0x9128, 0x2001, + 0xa332, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, 0x9130, + 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, 0x9195, + 0x1078, 0x4887, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, + 0xa082, 0x0006, 0x0048, 0x9178, 0xa6b4, 0xff00, 0x8637, 0xa686, + 0x0004, 0x0040, 0x9147, 0xa686, 0x0006, 0x00c0, 0x907b, 0x1078, + 0x9c0c, 0x00c0, 0x9153, 0x1078, 0x9afd, 0x00c0, 0x9153, 0x6007, + 0x0010, 0x0078, 0x9195, 0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424, + 0xa4a4, 0x00ff, 0x8427, 0x047e, 0x1078, 0x2813, 0x047f, 0x017e, + 0xa006, 0x2009, 0xa352, 0x210c, 0xd1a4, 0x0040, 0x9172, 0x2009, + 0x0029, 0x1078, 0x9ec0, 0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5, + 0x6802, 0x0d7f, 0x017f, 0x047f, 0x6007, 0x0001, 0x0078, 0x9195, + 0x1078, 0x9d45, 0x0040, 0x9185, 0xa6b4, 0xff00, 0x8637, 0xa686, + 0x0006, 0x0040, 0x9147, 0x0078, 0x907b, 0x6013, 0x1900, 0x6007, + 0x0009, 0x0078, 0x9195, 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x1078, + 0x9343, 0x00c0, 0x907b, 0x6007, 0x0012, 0x6003, 0x0001, 0x1078, + 0x5c45, 0x007c, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5c45, + 0x0078, 0x9199, 0x6007, 0x0005, 0x0078, 0x919c, 0x1078, 0xa0bf, + 0x00c0, 0x9340, 0x1078, 0x9343, 0x00c0, 0x907b, 0x6007, 0x0020, + 0x6003, 0x0001, 0x1078, 0x5c45, 0x007c, 0x6007, 0x0023, 0x6003, + 0x0001, 0x1078, 0x5c45, 0x007c, 0x1078, 0xa0bf, 0x00c0, 0x9340, + 0x1078, 0x9343, 0x00c0, 0x907b, 0x017e, 0x027e, 0x2011, 0xa890, + 0x2214, 0x2c08, 0x1078, 0x9e8c, 0x00c0, 0x91de, 0x2160, 0x6007, + 0x0026, 0x6013, 0x1700, 0x2011, 0xa889, 0x2214, 0xa296, 0xffff, + 0x00c0, 0x91e3, 0x6007, 0x0025, 0x0078, 0x91e3, 0x1078, 0x753d, + 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x1078, 0x5c45, 0x027f, + 0x017f, 0x007c, 0x6106, 0x1078, 0x9363, 0x6007, 0x002b, 0x0078, + 0x9195, 0x6007, 0x002c, 0x0078, 0x9195, 0x1078, 0xa0bf, 0x00c0, + 0x9340, 0x1078, 0x9343, 0x00c0, 0x907b, 0x6106, 0x1078, 0x9368, + 0x00c0, 0x9206, 0x6007, 0x002e, 0x0078, 0x9195, 0x6007, 0x002f, + 0x0078, 0x9195, 0x0e7e, 0x0d7e, 0x0c7e, 0x6018, 0xa080, 0x0001, + 0x200c, 0xa184, 0x00ff, 0xa086, 0x0006, 0x0040, 0x9223, 0xa184, + 0xff00, 0x8007, 0xa086, 0x0006, 0x0040, 0x9223, 0x0c7f, 0x0d7f, + 0x0e7f, 0x0078, 0x919a, 0x2001, 0xa371, 0x2004, 0xd0e4, 0x0040, + 0x928d, 0x2071, 0xa88c, 0x7010, 0x6036, 0x7014, 0x603a, 0x7108, + 0x720c, 0x2001, 0xa352, 0x2004, 0xd0a4, 0x0040, 0x9241, 0x6018, + 0x2068, 0x6810, 0xa106, 0x00c0, 0x9241, 0x6814, 0xa206, 0x0040, + 0x9265, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x9281, 0x2069, + 0xa300, 0x686c, 0xa206, 0x00c0, 0x9281, 0x6868, 0xa106, 0x00c0, + 0x9281, 0x7210, 0x1078, 0x8a30, 0x0040, 0x9287, 0x1078, 0x9f31, + 0x0040, 0x9287, 0x622a, 0x6007, 0x0036, 0x6003, 0x0001, 0x1078, + 0x5bf8, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7214, 0xa286, 0xffff, + 0x0040, 0x9277, 0x1078, 0x8a30, 0x0040, 0x9287, 0xa280, 0x0002, + 0x2004, 0x7110, 0xa106, 0x00c0, 0x9287, 0x0078, 0x9252, 0x7210, + 0x2c08, 0x1078, 0x9e8c, 0x2c10, 0x2160, 0x0040, 0x9287, 0x0078, + 0x9252, 0x6007, 0x0037, 0x6013, 0x1500, 0x0078, 0x925d, 0x6007, + 0x0037, 0x6013, 0x1700, 0x0078, 0x925d, 0x6007, 0x0012, 0x0078, + 0x925d, 0x6018, 0xa080, 0x0001, 0x2004, 0xa084, 0xff00, 0x8007, + 0xa086, 0x0006, 0x00c0, 0x919a, 0x0e7e, 0x0d7e, 0x0c7e, 0x2001, + 0xa371, 0x2004, 0xd0e4, 0x0040, 0x92fd, 0x2069, 0xa300, 0x2071, + 0xa88c, 0x7008, 0x6036, 0x720c, 0x623a, 0xa286, 0xffff, 0x00c0, + 0x92ba, 0x7208, 0x0c7e, 0x2c08, 0x1078, 0x9e8c, 0x2c10, 0x0c7f, + 0x0040, 0x92f1, 0x1078, 0x8a30, 0x0040, 0x92f1, 0x0c7e, 0x027e, + 0x2260, 0x1078, 0x874a, 0x027f, 0x0c7f, 0x7118, 0xa18c, 0xff00, + 0x810f, 0xa186, 0x0001, 0x0040, 0x92db, 0xa186, 0x0005, 0x0040, + 0x92d5, 0xa186, 0x0007, 0x00c0, 0x92e5, 0xa280, 0x0004, 0x2004, + 0xa005, 0x0040, 0x92e5, 0x057e, 0x7510, 0x7614, 0x1078, 0x9f46, + 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x6007, 0x003b, 0x602b, + 0x0009, 0x6013, 0x2a00, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x0078, + 0x92e1, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x1700, 0x6003, + 0x0001, 0x1078, 0x5bf8, 0x0078, 0x92e1, 0x6007, 0x003b, 0x602b, + 0x000b, 0x6013, 0x0000, 0x0078, 0x925d, 0x0e7e, 0x027e, 0x1078, + 0x4897, 0x0040, 0x933a, 0x1078, 0x4887, 0x1078, 0xa148, 0x00c0, + 0x9338, 0x2071, 0xa300, 0x70c8, 0xc085, 0x70ca, 0x0f7e, 0x2079, + 0x0100, 0x7294, 0xa284, 0x00ff, 0x706a, 0x78e6, 0xa284, 0xff00, + 0x726c, 0xa205, 0x706e, 0x78ea, 0x0f7f, 0x70d3, 0x0000, 0x2001, + 0xa352, 0x2004, 0xd0a4, 0x0040, 0x9331, 0x2011, 0xa5c4, 0x2013, + 0x07d0, 0xd0ac, 0x00c0, 0x933a, 0x1078, 0x260d, 0x0078, 0x933a, + 0x1078, 0xa178, 0x027f, 0x0e7f, 0x1078, 0x753d, 0x0078, 0x9199, + 0x1078, 0x753d, 0x007c, 0x0d7e, 0x067e, 0x6618, 0x2668, 0x6e04, + 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x9360, 0xa686, + 0x0004, 0x0040, 0x9360, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, + 0x0040, 0x9360, 0xa686, 0x0004, 0x0040, 0x9360, 0xa085, 0x0001, + 0x067f, 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x9397, 0x0d7f, 0x007c, + 0x0d7e, 0x1078, 0x93a6, 0x00c0, 0x9390, 0x680c, 0xa08c, 0xff00, + 0x6820, 0xa084, 0x00ff, 0xa115, 0x6212, 0x6824, 0x602a, 0xd1e4, + 0x0040, 0x937e, 0x2009, 0x0001, 0x0078, 0x938c, 0xd1ec, 0x0040, + 0x9390, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x1078, 0x24e3, 0x00c0, + 0x9390, 0x2110, 0x2009, 0x0000, 0x1078, 0x285b, 0x0078, 0x9394, + 0xa085, 0x0001, 0x0078, 0x9395, 0xa006, 0x0d7f, 0x007c, 0x2069, + 0xa88d, 0x6800, 0xa082, 0x0010, 0x00c8, 0x93a4, 0x6013, 0x0000, + 0xa085, 0x0001, 0x0078, 0x93a5, 0xa006, 0x007c, 0x6013, 0x0000, + 0x2069, 0xa88c, 0x6808, 0xa084, 0xff00, 0xa086, 0x0800, 0x00c0, + 0x93ba, 0x6800, 0xa084, 0x00ff, 0xa08e, 0x0014, 0x0040, 0x93ba, + 0xa08e, 0x0010, 0x007c, 0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1328, + 0xa1b6, 0x0013, 0x00c0, 0x93c7, 0x2008, 0x0079, 0x93da, 0xa1b6, + 0x0027, 0x0040, 0x93cf, 0xa1b6, 0x0014, 0x10c0, 0x1328, 0x2001, + 0x0007, 0x1078, 0x4472, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, + 0x6109, 0x007c, 0x941a, 0x941c, 0x941a, 0x941a, 0x941a, 0x941c, + 0x9424, 0x94ae, 0x9471, 0x94ae, 0x9485, 0x94ae, 0x9424, 0x94ae, + 0x94a6, 0x94ae, 0x94a6, 0x94ae, 0x94ae, 0x941a, 0x941a, 0x941a, + 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, + 0x941c, 0x941a, 0x94ae, 0x941a, 0x941a, 0x94ae, 0x941a, 0x94ae, + 0x94ae, 0x941a, 0x941a, 0x941a, 0x941a, 0x94ae, 0x94ae, 0x941a, + 0x94ae, 0x94ae, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941c, + 0x94ae, 0x94ae, 0x941a, 0x941a, 0x94ae, 0x94ae, 0x941a, 0x941a, + 0x941a, 0x941a, 0x1078, 0x1328, 0x1078, 0x6010, 0x6003, 0x0002, + 0x1078, 0x6109, 0x0078, 0x94b4, 0x0f7e, 0x2079, 0xa351, 0x7804, + 0x0f7f, 0xd0ac, 0x00c0, 0x94ae, 0x2001, 0x0000, 0x1078, 0x442b, + 0x6018, 0xa080, 0x0004, 0x2004, 0xa086, 0x00ff, 0x0040, 0x94ae, + 0x0c7e, 0x6018, 0x2060, 0x6000, 0xd0f4, 0x00c0, 0x9448, 0x6010, + 0xa005, 0x0040, 0x9448, 0x0c7f, 0x1078, 0x35f7, 0x0078, 0x94ae, + 0x0c7f, 0x2001, 0xa300, 0x2004, 0xa086, 0x0002, 0x00c0, 0x9457, + 0x0f7e, 0x2079, 0xa300, 0x788c, 0x8000, 0x788e, 0x0f7f, 0x2001, + 0x0002, 0x1078, 0x443f, 0x1078, 0x6010, 0x601f, 0x0001, 0x6003, + 0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, 0x1078, 0x6109, 0x0c7e, + 0x6118, 0x2160, 0x2009, 0x0001, 0x1078, 0x58e1, 0x0c7f, 0x0078, + 0x94b4, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0040, 0x94ae, 0xa686, 0x0004, 0x0040, + 0x94ae, 0x2001, 0x0004, 0x0078, 0x94ac, 0x2001, 0xa300, 0x2004, + 0xa086, 0x0003, 0x00c0, 0x948e, 0x1078, 0x35f7, 0x2001, 0x0006, + 0x1078, 0x94b5, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x94ae, 0x2001, 0x0006, + 0x0078, 0x94ac, 0x2001, 0x0004, 0x0078, 0x94ac, 0x2001, 0x0006, + 0x1078, 0x94b5, 0x0078, 0x94ae, 0x1078, 0x4472, 0x1078, 0x6010, + 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0x017e, 0x0d7e, 0x6118, + 0x2168, 0x6900, 0xd184, 0x0040, 0x94d0, 0x6104, 0xa18e, 0x000a, + 0x00c0, 0x94c8, 0x699c, 0xd1a4, 0x00c0, 0x94c8, 0x2001, 0x0007, + 0x1078, 0x443f, 0x2001, 0x0000, 0x1078, 0x442b, 0x1078, 0x2839, + 0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, + 0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1328, 0xa1b6, + 0x0015, 0x00c0, 0x94e7, 0x1079, 0x94ee, 0x0078, 0x94ed, 0xa1b6, + 0x0016, 0x10c0, 0x1328, 0x1079, 0x94fa, 0x007c, 0x7ad0, 0x7ad0, + 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x9547, 0x9506, 0x7ad0, 0x7ad0, + 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, + 0x9547, 0x954f, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x0f7e, 0x2079, + 0xa351, 0x7804, 0xd0ac, 0x00c0, 0x952d, 0x6018, 0xa07d, 0x0040, + 0x952d, 0x7800, 0xd0f4, 0x00c0, 0x9519, 0x7810, 0xa005, 0x00c0, + 0x952d, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, + 0x443f, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, + 0x5c45, 0x1078, 0x6109, 0x0078, 0x9545, 0x2011, 0xa883, 0x2204, + 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x9545, 0x0c7e, 0x1078, + 0x4501, 0x0040, 0x9540, 0x0c7f, 0x1078, 0x753d, 0x0078, 0x9545, + 0x1078, 0x4235, 0x0c7f, 0x1078, 0x753d, 0x0f7f, 0x007c, 0x6604, + 0xa6b6, 0x001e, 0x00c0, 0x954e, 0x1078, 0x753d, 0x007c, 0x1078, + 0x7d0a, 0x00c0, 0x955b, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, + 0x5c45, 0x0078, 0x955d, 0x1078, 0x753d, 0x007c, 0x6004, 0xa08a, + 0x0044, 0x10c8, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, + 0x6109, 0x007c, 0xa182, 0x0040, 0x0079, 0x956e, 0x9581, 0x9581, + 0x9581, 0x9581, 0x9583, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, + 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, + 0x9581, 0x1078, 0x1328, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e, + 0x027e, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0040, 0x9594, + 0x2021, 0x0000, 0x1078, 0xa111, 0x6106, 0x2071, 0xa880, 0x7444, + 0xa4a4, 0xff00, 0x0040, 0x95eb, 0xa486, 0x2000, 0x00c0, 0x95a6, + 0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x5a6d, 0x1078, 0x1381, + 0x1040, 0x1328, 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, + 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, + 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, 0x017e, 0xa084, + 0xff00, 0x6846, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x4982, + 0x017f, 0xa486, 0x2000, 0x00c0, 0x95d3, 0x2019, 0x0017, 0x1078, + 0x9e3b, 0x0078, 0x9645, 0xa486, 0x0400, 0x00c0, 0x95dd, 0x2019, + 0x0002, 0x1078, 0x9dec, 0x0078, 0x9645, 0xa486, 0x0200, 0x00c0, + 0x95e3, 0x1078, 0x9dd1, 0xa486, 0x1000, 0x00c0, 0x95e9, 0x1078, + 0x9e20, 0x0078, 0x9645, 0x2069, 0xa62d, 0x6a00, 0xd284, 0x0040, + 0x969b, 0xa284, 0x0300, 0x00c0, 0x9693, 0x6804, 0xa005, 0x0040, + 0x9683, 0x2d78, 0x6003, 0x0007, 0x1078, 0x1366, 0x0040, 0x964c, + 0x7800, 0xd08c, 0x00c0, 0x9607, 0x7804, 0x8001, 0x7806, 0x6013, + 0x0000, 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x6008, + 0x68b2, 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, + 0x6986, 0x6846, 0x6853, 0x003d, 0x7244, 0xa294, 0x0003, 0xa286, + 0x0002, 0x00c0, 0x9627, 0x684f, 0x0040, 0x0078, 0x9631, 0xa286, + 0x0001, 0x00c0, 0x962f, 0x684f, 0x0080, 0x0078, 0x9631, 0x684f, + 0x0000, 0x20a9, 0x000a, 0x2001, 0xa890, 0xad90, 0x0015, 0x200c, + 0x810f, 0x2112, 0x8000, 0x8210, 0x00f0, 0x9637, 0x200c, 0x6982, + 0x8000, 0x200c, 0x697e, 0x1078, 0x4982, 0x027f, 0x047f, 0x157f, + 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x6013, 0x0100, 0x6003, 0x0001, + 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9645, + 0x2069, 0xa892, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x00c0, + 0x9677, 0x2069, 0xa880, 0x686c, 0xa084, 0x00ff, 0x017e, 0x6110, + 0xa18c, 0x0700, 0xa10d, 0x6112, 0x017f, 0x6003, 0x0001, 0x6007, + 0x0043, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9645, 0x6013, + 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078, + 0x6109, 0x0078, 0x9645, 0x6013, 0x0300, 0x0078, 0x9689, 0x6013, + 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078, + 0x6109, 0x0078, 0x9645, 0x6013, 0x0500, 0x0078, 0x9689, 0x6013, + 0x0600, 0x0078, 0x9658, 0x6013, 0x0200, 0x0078, 0x9658, 0xa186, + 0x0013, 0x00c0, 0x96b1, 0x6004, 0xa08a, 0x0040, 0x1048, 0x1328, + 0xa08a, 0x0053, 0x10c8, 0x1328, 0xa082, 0x0040, 0x2008, 0x0079, + 0x9725, 0xa186, 0x0051, 0x0040, 0x96be, 0xa186, 0x0047, 0x00c0, + 0x96d7, 0x6004, 0xa086, 0x0041, 0x0040, 0x96e5, 0x2001, 0x0109, + 0x2004, 0xd084, 0x0040, 0x96e5, 0x127e, 0x2091, 0x2200, 0x007e, + 0x017e, 0x027e, 0x1078, 0x5ad2, 0x027f, 0x017f, 0x007f, 0x127f, + 0x6000, 0xa086, 0x0002, 0x00c0, 0x96e5, 0x0078, 0x976a, 0xa186, + 0x0027, 0x0040, 0x96df, 0xa186, 0x0014, 0x10c0, 0x1328, 0x6004, + 0xa082, 0x0040, 0x2008, 0x0079, 0x96e8, 0x1078, 0x7583, 0x007c, + 0x96fb, 0x96fd, 0x96fd, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, + 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, + 0x96fb, 0x96fb, 0x96fb, 0x1078, 0x1328, 0x1078, 0x6010, 0x1078, + 0x6109, 0x037e, 0x0d7e, 0x6010, 0xa06d, 0x0040, 0x9722, 0xad84, + 0xf000, 0x0040, 0x9722, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc, + 0x00c0, 0x9722, 0x2019, 0x0004, 0x1078, 0x9e70, 0x6013, 0x0000, + 0x6014, 0xa005, 0x00c0, 0x9720, 0x2001, 0xa5a1, 0x2004, 0x6016, + 0x6003, 0x0007, 0x0d7f, 0x037f, 0x007c, 0x9738, 0x9757, 0x9741, + 0x9764, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, + 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, + 0x1078, 0x1328, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, + 0x200a, 0x1078, 0x6010, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, + 0x0040, 0x9752, 0x6003, 0x0007, 0x2009, 0x0043, 0x1078, 0x756c, + 0x0078, 0x9754, 0x6003, 0x0002, 0x1078, 0x6109, 0x007c, 0x1078, + 0x6010, 0x1078, 0xa0c6, 0x00c0, 0x9761, 0x1078, 0x5a41, 0x1078, + 0x753d, 0x1078, 0x6109, 0x007c, 0x1078, 0x6010, 0x2009, 0x0041, + 0x0078, 0x98c1, 0xa182, 0x0040, 0x0079, 0x976e, 0x9781, 0x9783, + 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9784, 0x9781, 0x9781, + 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x978f, + 0x9781, 0x1078, 0x1328, 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, + 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0x0d7e, + 0x1078, 0x5a41, 0x0d7f, 0x1078, 0xa134, 0x1078, 0x753d, 0x007c, + 0xa182, 0x0040, 0x0079, 0x979c, 0x97af, 0x97af, 0x97af, 0x97af, + 0x97af, 0x97af, 0x97af, 0x97b1, 0x97af, 0x97b4, 0x97df, 0x97af, + 0x97af, 0x97af, 0x97af, 0x97df, 0x97af, 0x97af, 0x97af, 0x1078, + 0x1328, 0x1078, 0x7583, 0x007c, 0x1078, 0x60b8, 0x1078, 0x61d3, + 0x6010, 0x0d7e, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x97ca, 0xa08c, + 0x0003, 0xa18e, 0x0002, 0x0040, 0x97d2, 0x2009, 0x0041, 0x0d7f, + 0x0078, 0x98c1, 0x6003, 0x0007, 0x6017, 0x0000, 0x1078, 0x5a41, + 0x0d7f, 0x007c, 0x1078, 0xa0c6, 0x0040, 0x97d8, 0x0d7f, 0x007c, + 0x1078, 0x5a41, 0x1078, 0x753d, 0x0d7f, 0x0078, 0x97d1, 0x037e, + 0x1078, 0x60b8, 0x1078, 0x61d3, 0x6010, 0x0d7e, 0x2068, 0x6018, + 0x2004, 0xd0bc, 0x0040, 0x97ff, 0x684c, 0xa084, 0x0003, 0xa086, + 0x0002, 0x0040, 0x97fb, 0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, + 0x6328, 0xa31b, 0x632a, 0x6003, 0x0002, 0x0078, 0x9810, 0x2019, + 0x0004, 0x1078, 0x9e70, 0x6014, 0xa005, 0x00c0, 0x980c, 0x2001, + 0xa5a1, 0x2004, 0x8003, 0x6016, 0x6013, 0x0000, 0x6003, 0x0007, + 0x0d7f, 0x037f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x9821, 0x6004, + 0xa086, 0x0042, 0x10c0, 0x1328, 0x1078, 0x6010, 0x1078, 0x6109, + 0x007c, 0xa186, 0x0027, 0x0040, 0x9829, 0xa186, 0x0014, 0x00c0, + 0x9839, 0x6004, 0xa086, 0x0042, 0x10c0, 0x1328, 0x2001, 0x0007, + 0x1078, 0x4472, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, + 0x007c, 0xa182, 0x0040, 0x0079, 0x983d, 0x9850, 0x9850, 0x9850, + 0x9850, 0x9850, 0x9850, 0x9850, 0x9852, 0x985e, 0x9850, 0x9850, + 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, + 0x1078, 0x1328, 0x037e, 0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x1078, 0x15ec, 0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e, + 0x2068, 0x6810, 0x6a14, 0x6118, 0x210c, 0xd1bc, 0x0040, 0x987d, + 0x6124, 0xd1f4, 0x00c0, 0x987d, 0x007e, 0x047e, 0x057e, 0x6c7c, + 0xa422, 0x6d80, 0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, + 0xa529, 0x652a, 0x057f, 0x047f, 0x007f, 0xa20d, 0x00c0, 0x9891, + 0x684c, 0xd0fc, 0x0040, 0x9889, 0x2009, 0x0041, 0x0d7f, 0x0078, + 0x98c1, 0x6003, 0x0007, 0x6017, 0x0000, 0x1078, 0x5a41, 0x0d7f, + 0x007c, 0x007e, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x007f, + 0x0040, 0x989e, 0x6003, 0x0002, 0x0d7f, 0x007c, 0x2009, 0xa30d, + 0x210c, 0xd19c, 0x0040, 0x98a8, 0x6003, 0x0007, 0x0078, 0x98aa, + 0x6003, 0x0006, 0x1078, 0x98b0, 0x1078, 0x5a43, 0x0d7f, 0x007c, + 0xd2fc, 0x0040, 0x98bc, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, + 0x2009, 0x0009, 0x0078, 0x98be, 0x2009, 0x0015, 0x6a6a, 0x6866, + 0x007c, 0xa182, 0x0040, 0x0048, 0x98c7, 0x0079, 0x98d4, 0xa186, + 0x0013, 0x0040, 0x98cf, 0xa186, 0x0014, 0x10c0, 0x1328, 0x6024, + 0xd0dc, 0x1040, 0x1328, 0x007c, 0x98e7, 0x98ee, 0x98fa, 0x9906, + 0x98e7, 0x98e7, 0x98e7, 0x9915, 0x98e7, 0x98e9, 0x98e9, 0x98e7, + 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x1078, + 0x1328, 0x6024, 0xd0dc, 0x1040, 0x1328, 0x007c, 0x6003, 0x0001, + 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, 0x8000, 0x1078, 0x6109, + 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e, + 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x6003, 0x0003, + 0x6106, 0x2c10, 0x1078, 0x1cab, 0x127e, 0x2091, 0x8000, 0x1078, + 0x5c64, 0x1078, 0x61d3, 0x127f, 0x007c, 0xa016, 0x1078, 0x15ec, + 0x007c, 0x127e, 0x2091, 0x8000, 0x037e, 0x0d7e, 0xa182, 0x0040, + 0x1079, 0x9926, 0x0d7f, 0x037f, 0x127f, 0x007c, 0x9936, 0x9938, + 0x994d, 0x996c, 0x9936, 0x9936, 0x9936, 0x9984, 0x9936, 0x9936, + 0x9936, 0x9936, 0x9936, 0x9936, 0x9936, 0x9936, 0x1078, 0x1328, + 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x9962, 0xa09c, 0x0003, + 0xa39e, 0x0003, 0x0040, 0x9962, 0x6003, 0x0001, 0x6106, 0x1078, + 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9987, 0x6010, 0x2068, 0x684c, + 0xd0fc, 0x0040, 0x9962, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, + 0x9962, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x1078, 0x6109, + 0x0078, 0x9987, 0x6013, 0x0000, 0x6017, 0x0000, 0x2019, 0x0004, + 0x1078, 0x9e70, 0x0078, 0x9987, 0x6010, 0x2068, 0x684c, 0xd0fc, + 0x0040, 0x9962, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, 0x9962, + 0x6003, 0x0003, 0x6106, 0x2c10, 0x1078, 0x1cab, 0x1078, 0x5c64, + 0x1078, 0x61d3, 0x0078, 0x9987, 0xa016, 0x1078, 0x15ec, 0x007c, + 0x1078, 0x6010, 0x6110, 0x81ff, 0x0040, 0x9999, 0x0d7e, 0x2168, + 0x1078, 0xa181, 0x037e, 0x2019, 0x0029, 0x1078, 0x9e70, 0x037f, + 0x0d7f, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0x1078, 0x60b8, + 0x6110, 0x81ff, 0x0040, 0x99af, 0x0d7e, 0x2168, 0x1078, 0xa181, + 0x037e, 0x2019, 0x0029, 0x1078, 0x9e70, 0x037f, 0x0d7f, 0x1078, + 0x8c01, 0x1078, 0x61d3, 0x007c, 0xa182, 0x0085, 0x0079, 0x99b8, + 0x99c1, 0x99bf, 0x99bf, 0x99cd, 0x99bf, 0x99bf, 0x99bf, 0x1078, + 0x1328, 0x6003, 0x000b, 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, + 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x027e, 0x0e7e, 0x1078, + 0xa0bf, 0x0040, 0x99d7, 0x1078, 0x753d, 0x0078, 0x99f3, 0x2071, + 0xa880, 0x7224, 0x6212, 0x7220, 0x1078, 0x9d10, 0x0040, 0x99e4, + 0x6007, 0x0086, 0x0078, 0x99ed, 0x6007, 0x0087, 0x7224, 0xa296, + 0xffff, 0x00c0, 0x99ed, 0x6007, 0x0086, 0x6003, 0x0001, 0x1078, + 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x027f, 0x007c, 0xa186, 0x0013, + 0x00c0, 0x9a07, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1328, 0xa08a, + 0x008c, 0x10c8, 0x1328, 0xa082, 0x0085, 0x0079, 0x9a1e, 0xa186, + 0x0027, 0x0040, 0x9a13, 0xa186, 0x0014, 0x0040, 0x9a13, 0x1078, + 0x7583, 0x0078, 0x9a1d, 0x2001, 0x0007, 0x1078, 0x4472, 0x1078, + 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0x9a25, 0x9a27, + 0x9a27, 0x9a25, 0x9a25, 0x9a25, 0x9a25, 0x1078, 0x1328, 0x1078, + 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0xa182, 0x0085, + 0x1048, 0x1328, 0xa182, 0x008c, 0x10c8, 0x1328, 0xa182, 0x0085, + 0x0079, 0x9a3a, 0x9a41, 0x9a41, 0x9a41, 0x9a43, 0x9a41, 0x9a41, + 0x9a41, 0x1078, 0x1328, 0x007c, 0xa186, 0x0013, 0x0040, 0x9a54, + 0xa186, 0x0014, 0x0040, 0x9a54, 0xa186, 0x0027, 0x0040, 0x9a54, + 0x1078, 0x7583, 0x0078, 0x9a5a, 0x1078, 0x6010, 0x1078, 0x8c01, + 0x1078, 0x6109, 0x007c, 0x037e, 0x1078, 0xa134, 0x603f, 0x0000, + 0x2019, 0x000b, 0x1078, 0x9a6a, 0x601f, 0x0006, 0x6003, 0x0007, + 0x037f, 0x007c, 0x127e, 0x037e, 0x2091, 0x8000, 0x087e, 0x2c40, + 0x097e, 0x2049, 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x00c0, + 0x9aa5, 0x077e, 0x2c38, 0x1078, 0x7105, 0x077f, 0x00c0, 0x9aa5, + 0x6000, 0xa086, 0x0000, 0x0040, 0x9aa5, 0x601c, 0xa086, 0x0007, + 0x0040, 0x9aa5, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x9a96, + 0x1078, 0xa134, 0x601f, 0x0007, 0x1078, 0x1749, 0x6010, 0x2068, + 0x1078, 0x8a44, 0x0040, 0x9a9e, 0x1078, 0x9e70, 0x0d7f, 0x6013, + 0x0000, 0x1078, 0xa134, 0x601f, 0x0007, 0x037f, 0x127f, 0x007c, + 0x0f7e, 0x0c7e, 0x037e, 0x157e, 0x2079, 0xa880, 0x7938, 0x783c, + 0x1078, 0x24e3, 0x00c0, 0x9af6, 0x017e, 0x0c7e, 0x1078, 0x4501, + 0x00c0, 0x9af6, 0x2011, 0xa890, 0xac98, 0x000a, 0x20a9, 0x0004, + 0x1078, 0x7e55, 0x00c0, 0x9af6, 0x017f, 0x027f, 0x027e, 0x017e, + 0x2019, 0x0029, 0x1078, 0x71e0, 0x1078, 0x5d53, 0x077e, 0x2039, + 0x0000, 0x1078, 0x5c78, 0x077f, 0x017f, 0x077e, 0x2039, 0x0000, + 0x1078, 0x9c38, 0x077f, 0x1078, 0x471b, 0x027e, 0x6204, 0xa294, + 0xff00, 0x8217, 0xa286, 0x0006, 0x0040, 0x9aea, 0xa286, 0x0004, + 0x00c0, 0x9aed, 0x62a0, 0x1078, 0x28d5, 0x027f, 0x017f, 0x1078, + 0x4235, 0x6612, 0x6516, 0xa006, 0x0078, 0x9af8, 0x0c7f, 0x017f, + 0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c, 0x0c7e, 0x0d7e, 0x0e7e, + 0x017e, 0x2009, 0xa31f, 0x2104, 0xa086, 0x0074, 0x00c0, 0x9b60, + 0x2069, 0xa88e, 0x690c, 0xa182, 0x0100, 0x0048, 0x9b50, 0x6908, + 0xa184, 0x8000, 0x0040, 0x9b5c, 0x6018, 0x2070, 0x7010, 0xa084, + 0x00ff, 0x0040, 0x9b1f, 0x7000, 0xd0f4, 0x0040, 0x9b23, 0xa184, + 0x0800, 0x0040, 0x9b5c, 0x6910, 0xa18a, 0x0001, 0x0048, 0x9b54, + 0x6914, 0x2069, 0xa8ae, 0x6904, 0x81ff, 0x00c0, 0x9b48, 0x690c, + 0xa182, 0x0100, 0x0048, 0x9b50, 0x6908, 0x81ff, 0x00c0, 0x9b4c, + 0x6910, 0xa18a, 0x0001, 0x0048, 0x9b54, 0x6918, 0xa18a, 0x0001, + 0x0048, 0x9b5c, 0x0078, 0x9b66, 0x6013, 0x0100, 0x0078, 0x9b62, + 0x6013, 0x0300, 0x0078, 0x9b62, 0x6013, 0x0500, 0x0078, 0x9b62, + 0x6013, 0x0700, 0x0078, 0x9b62, 0x6013, 0x0900, 0x0078, 0x9b62, + 0x6013, 0x0b00, 0x0078, 0x9b62, 0x6013, 0x0f00, 0x0078, 0x9b62, + 0x6013, 0x2d00, 0xa085, 0x0001, 0x0078, 0x9b67, 0xa006, 0x017f, + 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x027e, 0x037e, + 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, 0xa286, 0x0006, + 0x0040, 0x9b90, 0xa286, 0x0004, 0x0040, 0x9b90, 0xa394, 0xff00, + 0x8217, 0xa286, 0x0006, 0x0040, 0x9b90, 0xa286, 0x0004, 0x0040, + 0x9b90, 0x0c7e, 0x2d60, 0x1078, 0x4513, 0x0c7f, 0x0078, 0x9bcb, + 0x2011, 0xa896, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, + 0x00c0, 0x9bcc, 0x2011, 0xa89a, 0xad98, 0x0006, 0x20a9, 0x0004, + 0x1078, 0x7e55, 0x00c0, 0x9bcc, 0x047e, 0x017e, 0x6aa0, 0xa294, + 0x00ff, 0x8227, 0xa006, 0x2009, 0xa352, 0x210c, 0xd1a4, 0x0040, + 0x9bb8, 0x2009, 0x0029, 0x1078, 0x9ec0, 0x6800, 0xc0e5, 0x6802, + 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, 0x1078, + 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x2001, 0x0007, 0x1078, + 0x4472, 0x017f, 0x047f, 0xa006, 0x157f, 0x037f, 0x027f, 0x0d7f, + 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0xa88e, 0x6800, 0xa086, 0x0800, + 0x0040, 0x9bde, 0x6013, 0x0000, 0x0078, 0x9bdf, 0xa006, 0x0d7f, + 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2079, + 0xa88c, 0x7930, 0x7834, 0x1078, 0x24e3, 0x00c0, 0x9c05, 0x1078, + 0x4501, 0x00c0, 0x9c05, 0x2011, 0xa890, 0xac98, 0x000a, 0x20a9, + 0x0004, 0x1078, 0x7e55, 0x00c0, 0x9c05, 0x2011, 0xa894, 0xac98, + 0x0006, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x157f, 0x037f, 0x027f, + 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, 0x007e, 0x017e, 0x027e, + 0x037e, 0x157e, 0x2011, 0xa883, 0x2204, 0x8211, 0x220c, 0x1078, + 0x24e3, 0x00c0, 0x9c31, 0x1078, 0x4501, 0x00c0, 0x9c31, 0x2011, + 0xa896, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x00c0, + 0x9c31, 0x2011, 0xa89a, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, + 0x7e55, 0x157f, 0x037f, 0x027f, 0x017f, 0x007f, 0x0c7f, 0x007c, + 0x0e7e, 0x0c7e, 0x087e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, + 0x127e, 0x2091, 0x8000, 0x2740, 0x2029, 0xa5b4, 0x252c, 0x2021, + 0xa5ba, 0x2424, 0x2061, 0xaa00, 0x2071, 0xa300, 0x7644, 0x7060, + 0x81ff, 0x0040, 0x9c59, 0x8001, 0xa602, 0x00c8, 0x9cc3, 0x0078, + 0x9c5c, 0xa606, 0x0040, 0x9cc3, 0x2100, 0xac06, 0x0040, 0x9cb9, + 0x1078, 0x9ee5, 0x0040, 0x9cb9, 0x671c, 0xa786, 0x0001, 0x0040, + 0x9cde, 0xa786, 0x0004, 0x0040, 0x9cde, 0xa786, 0x0007, 0x0040, + 0x9cb9, 0x2500, 0xac06, 0x0040, 0x9cb9, 0x2400, 0xac06, 0x0040, + 0x9cb9, 0x1078, 0x9ef9, 0x00c0, 0x9cb9, 0x88ff, 0x0040, 0x9c84, + 0x6020, 0xa906, 0x00c0, 0x9cb9, 0x0d7e, 0x6000, 0xa086, 0x0004, + 0x00c0, 0x9c8e, 0x017e, 0x1078, 0x1749, 0x017f, 0xa786, 0x0008, + 0x00c0, 0x9c9d, 0x1078, 0x8c3b, 0x00c0, 0x9c9d, 0x1078, 0x7a05, + 0x0d7f, 0x1078, 0x8c01, 0x0078, 0x9cb9, 0x6010, 0x2068, 0x1078, + 0x8a44, 0x0040, 0x9cb6, 0xa786, 0x0003, 0x00c0, 0x9ccd, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0xa181, 0x017e, 0x1078, + 0x8cb8, 0x1078, 0x4982, 0x017f, 0x1078, 0x8bf4, 0x0d7f, 0x1078, + 0x8c01, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, 0x00c8, + 0x9cc3, 0x0078, 0x9c4c, 0x127f, 0x027f, 0x047f, 0x057f, 0x067f, + 0x077f, 0x087f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, + 0x9ca7, 0xa386, 0x0005, 0x0040, 0x9cdb, 0x1078, 0xa181, 0x1078, + 0x9e70, 0x0078, 0x9cb6, 0x0d7f, 0x0078, 0x9cb9, 0x1078, 0x9ef9, + 0x00c0, 0x9cb9, 0x81ff, 0x0040, 0x9cb9, 0xa180, 0x0001, 0x2004, + 0xa086, 0x0018, 0x0040, 0x9cf3, 0xa180, 0x0001, 0x2004, 0xa086, + 0x002d, 0x00c0, 0x9cb9, 0x6000, 0xa086, 0x0002, 0x00c0, 0x9cb9, + 0x1078, 0x8c27, 0x0040, 0x9d04, 0x1078, 0x8c3b, 0x00c0, 0x9cb9, + 0x1078, 0x7a05, 0x0078, 0x9d0c, 0x1078, 0x2839, 0x1078, 0x8c3b, + 0x00c0, 0x9d0c, 0x1078, 0x7a05, 0x1078, 0x8c01, 0x0078, 0x9cb9, + 0x0c7e, 0x0e7e, 0x017e, 0x2c08, 0x2170, 0x1078, 0x9e8c, 0x017f, + 0x0040, 0x9d1f, 0x601c, 0xa084, 0x000f, 0x1079, 0x9d22, 0x0e7f, + 0x0c7f, 0x007c, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, + 0x9d2c, 0x9d2a, 0xa006, 0x007c, 0x047e, 0x017e, 0x7018, 0xa080, + 0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, + 0x1078, 0x9ec0, 0x017f, 0x047f, 0x037e, 0x2019, 0x0002, 0x1078, + 0x9a6a, 0x037f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0001, 0x1078, + 0x442b, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019, + 0xa305, 0x2011, 0xa896, 0x1078, 0x7e55, 0x037f, 0x027f, 0x017f, + 0x157f, 0xa005, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x087e, 0x077e, + 0x067e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2740, 0x2061, 0xaa00, + 0x2079, 0x0001, 0x8fff, 0x0040, 0x9dc3, 0x2071, 0xa300, 0x7644, + 0x7060, 0x8001, 0xa602, 0x00c8, 0x9dc3, 0x88ff, 0x0040, 0x9d7e, + 0x2800, 0xac06, 0x00c0, 0x9db9, 0x2079, 0x0000, 0x1078, 0x9ee5, + 0x0040, 0x9db9, 0x2400, 0xac06, 0x0040, 0x9db9, 0x671c, 0xa786, + 0x0006, 0x00c0, 0x9db9, 0xa786, 0x0007, 0x0040, 0x9db9, 0x88ff, + 0x00c0, 0x9d9d, 0x6018, 0xa206, 0x00c0, 0x9db9, 0x85ff, 0x0040, + 0x9d9d, 0x6020, 0xa106, 0x00c0, 0x9db9, 0x0d7e, 0x6000, 0xa086, + 0x0004, 0x00c0, 0x9da9, 0x1078, 0xa134, 0x601f, 0x0007, 0x1078, + 0x1749, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x9db3, 0x047e, + 0x1078, 0x9e70, 0x047f, 0x0d7f, 0x1078, 0x8c01, 0x88ff, 0x00c0, + 0x9dcd, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, 0x00c8, + 0x9dc3, 0x0078, 0x9d6a, 0xa006, 0x127f, 0x027f, 0x067f, 0x077f, + 0x087f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, 0x0078, + 0x9dc4, 0x077e, 0x057e, 0x087e, 0x2041, 0x0000, 0x2029, 0x0001, + 0x2c20, 0x2019, 0x0002, 0x6218, 0x097e, 0x2049, 0x0000, 0x1078, + 0x7058, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, 0x7105, 0x1078, + 0x9d5b, 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e, 0x077e, + 0x0c7e, 0x157e, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x017e, 0x037e, 0x1078, 0x4501, 0x00c0, 0x9e14, 0x2c10, 0x057e, + 0x087e, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, 0x097e, 0x2049, + 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, + 0x7105, 0x1078, 0x9d5b, 0x057f, 0x037f, 0x017f, 0x8108, 0x00f0, + 0x9df8, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, 0x027f, 0x007c, + 0x077e, 0x057e, 0x6218, 0x087e, 0x2041, 0x0000, 0x2029, 0x0001, + 0x2019, 0x0048, 0x097e, 0x2049, 0x0000, 0x1078, 0x7058, 0x097f, + 0x087f, 0x2039, 0x0000, 0x1078, 0x7105, 0x2c20, 0x1078, 0x9d5b, + 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e, 0x077e, 0x0c7e, + 0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x037e, + 0x1078, 0x4501, 0x00c0, 0x9e64, 0x2c10, 0x087e, 0x2041, 0x0000, + 0x2828, 0x047e, 0x2021, 0x0001, 0x1078, 0xa111, 0x047f, 0x097e, + 0x2049, 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x2039, 0x0000, + 0x1078, 0x7105, 0x1078, 0x9d5b, 0x037f, 0x017f, 0x8108, 0x00f0, + 0x9e46, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, 0x027f, 0x007c, + 0x017e, 0x0f7e, 0xad82, 0xca00, 0x0048, 0x9e89, 0xad82, 0xffff, + 0x00c8, 0x9e89, 0x6800, 0xa07d, 0x0040, 0x9e86, 0x6803, 0x0000, + 0x6b52, 0x1078, 0x4982, 0x2f68, 0x0078, 0x9e7a, 0x6b52, 0x1078, + 0x4982, 0x0f7f, 0x017f, 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061, + 0xaa00, 0x2071, 0xa300, 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, + 0x9ebb, 0x2100, 0xac06, 0x0040, 0x9ead, 0x6000, 0xa086, 0x0000, + 0x0040, 0x9ead, 0x6008, 0xa206, 0x00c0, 0x9ead, 0x6018, 0xa1a0, + 0x0006, 0x2424, 0xa406, 0x0040, 0x9eb7, 0xace0, 0x0010, 0x2001, + 0xa315, 0x2004, 0xac02, 0x00c8, 0x9ebb, 0x0078, 0x9e91, 0xa085, + 0x0001, 0x0078, 0x9ebc, 0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c, + 0x0d7e, 0x007e, 0x1078, 0x1381, 0x007f, 0x1040, 0x1328, 0x6837, + 0x010d, 0x685e, 0x027e, 0x2010, 0x1078, 0x8a30, 0x2001, 0x0000, + 0x0040, 0x9ed6, 0x2200, 0xa080, 0x0008, 0x2004, 0x027f, 0x684a, + 0x6956, 0x6c46, 0x684f, 0x0000, 0xa006, 0x68b2, 0x6802, 0x683a, + 0x685a, 0x1078, 0x4982, 0x0d7f, 0x007c, 0x6700, 0xa786, 0x0000, + 0x0040, 0x9ef8, 0xa786, 0x0001, 0x0040, 0x9ef8, 0xa786, 0x000a, + 0x0040, 0x9ef8, 0xa786, 0x0009, 0x0040, 0x9ef8, 0xa085, 0x0001, + 0x007c, 0x0e7e, 0x6018, 0x2070, 0x70a0, 0xa206, 0x0e7f, 0x007c, + 0x017e, 0x6004, 0xa08e, 0x001e, 0x00c0, 0x9f1a, 0x8007, 0x6130, + 0xa18c, 0x00ff, 0xa105, 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, + 0x601f, 0x0005, 0x2001, 0xa5a1, 0x2004, 0x6016, 0x1078, 0x5bf8, + 0x1078, 0x6109, 0x017f, 0x007c, 0x0005, 0x0005, 0x007c, 0x6024, + 0xd0e4, 0x0040, 0x9f30, 0xd0cc, 0x0040, 0x9f2a, 0x1078, 0x8cfa, + 0x0078, 0x9f30, 0x1078, 0xa134, 0x1078, 0x5a41, 0x1078, 0x753d, + 0x007c, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, 0x0079, 0x9f38, + 0x9f41, 0x9f41, 0x9f41, 0x9f43, 0x9f41, 0x9f43, 0x9f43, 0x9f41, + 0x9f43, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa280, 0x0007, + 0x2004, 0xa084, 0x000f, 0x0079, 0x9f4d, 0x9f56, 0x9f56, 0x9f56, + 0x9f56, 0x9f56, 0x9f56, 0x9f61, 0x9f56, 0x9f56, 0x6007, 0x003b, + 0x602b, 0x0009, 0x6013, 0x2a00, 0x6003, 0x0001, 0x1078, 0x5bf8, + 0x007c, 0x0c7e, 0x2260, 0x1078, 0xa134, 0x603f, 0x0000, 0x6024, + 0xc0f4, 0xc0cc, 0x6026, 0x0c7f, 0x0d7e, 0x2268, 0xa186, 0x0007, + 0x00c0, 0x9fc2, 0x6810, 0xa005, 0x0040, 0x9f7f, 0xa080, 0x0013, + 0x2004, 0xd0fc, 0x00c0, 0x9f7f, 0x0d7f, 0x0078, 0x9f56, 0x6007, + 0x003a, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7e, + 0x2d60, 0x6100, 0xa186, 0x0002, 0x00c0, 0xa050, 0x6010, 0xa005, + 0x00c0, 0x9f99, 0x6000, 0xa086, 0x0007, 0x10c0, 0x1328, 0x0078, + 0xa050, 0xa08c, 0xf000, 0x00c0, 0x9fa5, 0x0078, 0x9fa5, 0x2068, + 0x6800, 0xa005, 0x00c0, 0x9f9f, 0x2d00, 0xa080, 0x0013, 0x2004, + 0xa084, 0x0003, 0xa086, 0x0002, 0x00c0, 0x9fbe, 0x6010, 0x2068, + 0x684c, 0xc0dc, 0xc0f4, 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, + 0x2009, 0x0043, 0x1078, 0x98c1, 0x0078, 0xa050, 0x2009, 0x0041, + 0x0078, 0xa04a, 0xa186, 0x0005, 0x00c0, 0xa009, 0x6810, 0xa080, + 0x0013, 0x2004, 0xd0bc, 0x00c0, 0x9fd0, 0x0d7f, 0x0078, 0x9f56, + 0xd0b4, 0x0040, 0x9fd8, 0xd0fc, 0x1040, 0x1328, 0x0078, 0x9f72, + 0x6007, 0x003a, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x1078, 0x6109, + 0x0c7e, 0x2d60, 0x6100, 0xa186, 0x0002, 0x0040, 0x9feb, 0xa186, + 0x0004, 0x00c0, 0xa050, 0x2071, 0xa5e1, 0x7000, 0xa086, 0x0003, + 0x00c0, 0x9ff8, 0x7004, 0xac06, 0x00c0, 0x9ff8, 0x7003, 0x0000, + 0x6810, 0xa080, 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, + 0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0078, + 0xa04a, 0x037e, 0x0d7e, 0x0d7e, 0x1078, 0x1381, 0x037f, 0x1040, + 0x1328, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, + 0x0000, 0x6b5e, 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872, + 0x2360, 0x6024, 0xc0dd, 0x6026, 0x6018, 0xa080, 0x0028, 0x2004, + 0xa084, 0x00ff, 0x8007, 0x6320, 0x6b4a, 0x6846, 0x684f, 0x0000, + 0x6d6a, 0x6e66, 0x686f, 0x0001, 0x1078, 0x4982, 0x2019, 0x0045, + 0x6008, 0x2068, 0x1078, 0x9a6a, 0x2d00, 0x600a, 0x601f, 0x0006, + 0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000, 0x0d7f, 0x037f, + 0x0078, 0xa051, 0x603f, 0x0000, 0x6003, 0x0007, 0x1078, 0x98c1, + 0x0c7f, 0x0d7f, 0x007c, 0xa186, 0x0013, 0x00c0, 0xa05d, 0x6004, + 0xa082, 0x0085, 0x2008, 0x0079, 0xa077, 0xa186, 0x0027, 0x00c0, + 0xa070, 0x1078, 0x6010, 0x037e, 0x0d7e, 0x6010, 0x2068, 0x2019, + 0x0004, 0x1078, 0x9e70, 0x0d7f, 0x037f, 0x1078, 0x6109, 0x007c, + 0xa186, 0x0014, 0x0040, 0xa061, 0x1078, 0x7583, 0x007c, 0xa080, + 0xa07e, 0xa07e, 0xa07e, 0xa07e, 0xa07e, 0xa080, 0x1078, 0x1328, + 0x1078, 0x6010, 0x6003, 0x000c, 0x1078, 0x6109, 0x007c, 0xa182, + 0x008c, 0x00c8, 0xa091, 0xa182, 0x0085, 0x0048, 0xa091, 0x0079, + 0xa094, 0x1078, 0x7583, 0x007c, 0xa09b, 0xa09b, 0xa09b, 0xa09b, + 0xa09d, 0xa0bc, 0xa09b, 0x1078, 0x1328, 0x0d7e, 0x2c68, 0x1078, + 0x74d7, 0x0040, 0xa0b7, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, + 0xa88e, 0x210c, 0x6136, 0x2009, 0xa88f, 0x210c, 0x613a, 0x600b, + 0xffff, 0x6918, 0x611a, 0x601f, 0x0004, 0x1078, 0x5bf8, 0x2d60, + 0x1078, 0x753d, 0x0d7f, 0x007c, 0x1078, 0x753d, 0x007c, 0x0e7e, + 0x6018, 0x2070, 0x7000, 0xd0ec, 0x0e7f, 0x007c, 0x6010, 0xa080, + 0x0013, 0x200c, 0xd1ec, 0x0040, 0xa110, 0x2001, 0xa371, 0x2004, + 0xd0ec, 0x0040, 0xa110, 0x6003, 0x0002, 0x6024, 0xc0e5, 0x6026, + 0xd1ac, 0x0040, 0xa0ee, 0x0f7e, 0x2c78, 0x1078, 0x488f, 0x0f7f, + 0x0040, 0xa0ee, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x2009, 0xa371, + 0x210c, 0xd1f4, 0x00c0, 0xa10e, 0x0078, 0xa100, 0x2009, 0xa371, + 0x210c, 0xd1f4, 0x0040, 0xa0fa, 0x6024, 0xc0e4, 0x6026, 0xa006, + 0x0078, 0xa110, 0x2001, 0xa5a2, 0x200c, 0x8103, 0xa100, 0x603e, + 0x6018, 0xa088, 0x002b, 0x2104, 0xa005, 0x0040, 0xa10b, 0xa088, + 0x0003, 0x0078, 0xa103, 0x2c0a, 0x600f, 0x0000, 0xa085, 0x0001, + 0x007c, 0x017e, 0x0c7e, 0x0e7e, 0x6120, 0xa2f0, 0x002b, 0x2e04, + 0x2060, 0x8cff, 0x0040, 0xa130, 0x84ff, 0x00c0, 0xa123, 0x6020, + 0xa106, 0x00c0, 0xa12b, 0x600c, 0x2072, 0x1078, 0x5a41, 0x1078, + 0x753d, 0x0078, 0xa12d, 0xacf0, 0x0003, 0x2e64, 0x0078, 0xa119, + 0x0e7f, 0x0c7f, 0x017f, 0x007c, 0x0d7e, 0x6018, 0xa0e8, 0x002b, + 0x2d04, 0xa005, 0x0040, 0xa146, 0xac06, 0x0040, 0xa144, 0x2d04, + 0xa0e8, 0x0003, 0x0078, 0xa138, 0x600c, 0x206a, 0x0d7f, 0x007c, + 0x027e, 0x037e, 0x157e, 0x2011, 0xa325, 0x2204, 0xa084, 0x00ff, + 0x2019, 0xa88e, 0x2334, 0xa636, 0x00c0, 0xa174, 0x8318, 0x2334, + 0x2204, 0xa084, 0xff00, 0xa636, 0x00c0, 0xa174, 0x2011, 0xa890, + 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x00c0, + 0xa174, 0x2011, 0xa894, 0x6018, 0xa098, 0x0006, 0x20a9, 0x0004, + 0x1078, 0x7e55, 0x00c0, 0xa174, 0x157f, 0x037f, 0x027f, 0x007c, + 0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, 0x1078, 0x260d, 0x0e7f, + 0x007c, 0x0e7e, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0040, 0xa18a, + 0x1078, 0xa18c, 0x0e7f, 0x007c, 0x6850, 0xc0e5, 0x6852, 0x007c, + 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, 0x017e, + 0x127e, 0x2091, 0x8000, 0x2029, 0xa5b4, 0x252c, 0x2021, 0xa5ba, + 0x2424, 0x2061, 0xaa00, 0x2071, 0xa300, 0x7644, 0x7060, 0xa606, + 0x0040, 0xa1e4, 0x671c, 0xa786, 0x0001, 0x0040, 0xa1b3, 0xa786, + 0x0008, 0x00c0, 0xa1da, 0x2500, 0xac06, 0x0040, 0xa1da, 0x2400, + 0xac06, 0x0040, 0xa1da, 0x1078, 0x9ee5, 0x0040, 0xa1da, 0x1078, + 0x9ef9, 0x00c0, 0xa1da, 0x6000, 0xa086, 0x0004, 0x00c0, 0xa1cc, + 0x017e, 0x1078, 0x1749, 0x017f, 0x1078, 0x8c27, 0x00c0, 0xa1d2, + 0x1078, 0x2839, 0x1078, 0x8c3b, 0x00c0, 0xa1d8, 0x1078, 0x7a05, + 0x1078, 0x8c01, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, + 0x00c8, 0xa1e4, 0x0078, 0xa1a3, 0x127f, 0x017f, 0x027f, 0x047f, + 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, 0x007e, + 0x0e7e, 0x2091, 0x8000, 0x2071, 0xa340, 0xd5a4, 0x0040, 0xa1fb, + 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0xa201, 0x7030, 0x8000, + 0x7032, 0xd5ac, 0x0040, 0xa208, 0x2071, 0xa34a, 0x1078, 0xa237, + 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, + 0x8000, 0x2071, 0xa340, 0xd5a4, 0x0040, 0xa219, 0x7034, 0x8000, + 0x7036, 0xd5b4, 0x0040, 0xa21f, 0x7030, 0x8000, 0x7032, 0xd5ac, + 0x0040, 0xa226, 0x2071, 0xa34a, 0x1078, 0xa237, 0x0e7f, 0x007f, + 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, + 0xa342, 0x1078, 0xa237, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x2e04, + 0x8000, 0x2072, 0x00c8, 0xa240, 0x8e70, 0x2e04, 0x8000, 0x2072, + 0x007c, 0x0e7e, 0x2071, 0xa340, 0x1078, 0xa237, 0x0e7f, 0x007c, + 0x0e7e, 0x2071, 0xa344, 0x1078, 0xa237, 0x0e7f, 0x007c, 0x0001, + 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, + 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x6286 +}; +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_length01 = 0x9260; +#else +unsigned short risc_code_length01 = 0x9260; +#endif + diff -Nur linux-2.4.19/drivers/scsi/ql2200_fw.h linux-2.4.19-sgi211r3/drivers/scsi/ql2200_fw.h --- linux-2.4.19/drivers/scsi/ql2200_fw.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/ql2200_fw.h Tue Jan 8 17:05:38 2002 @@ -0,0 +1,5179 @@ +/************************************************************************ + * * + * --- ISP2200 Initiator/Target Firmware --- * + * with Fabric (Public Loop), Point-point, and * + * expanded LUN addressing for FCTAPE * + * * + ************************************************************************ + Copyright (C) 2000,2001 Qlogic Corporation + (www.qlogic.com) + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + ************************************************************************/ +/* + * Firmware Version 2.01.34 (18:00 Jun 05, 2001) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_version = 2*1024+1; +#else +unsigned short risc_code_version = 2*1024+1; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw2200tp_version_str[] = {2,1,34}; +#else +unsigned char firmware_version[] = {2,1,34}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw2200tp_VERSION_STRING "2.01.34" +#else +#define FW_VERSION_STRING "2.01.34" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_addr01 = 0x1000 ; +#else +unsigned short risc_code_addr01 = 0x1000 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0470, 0x0000, 0x0000, 0xa019, 0x0000, 0x0002, 0x0001, 0x0022, + 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030, + 0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3232, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x322e, 0x3031, 0x2e33, 0x3420, 0x2020, 0x2020, 0x2400, 0x20c1, + 0x0005, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, 0xb5ff, 0x2091, + 0x2000, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x2843, + 0x2051, 0xb100, 0x2a70, 0x2029, 0xe800, 0x2031, 0xffff, 0x2039, + 0xe7e9, 0x2021, 0x0200, 0x0804, 0x144d, 0x20a1, 0xb019, 0xa00e, + 0x20a9, 0x07e7, 0x41a4, 0x3400, 0x755e, 0x7662, 0x775a, 0x7466, + 0x746a, 0x20a1, 0xb800, 0x7160, 0x810d, 0x810d, 0x810d, 0x810d, + 0xa18c, 0x000f, 0x2001, 0x000b, 0xa112, 0xa00e, 0x21a8, 0x41a4, + 0x3400, 0x8211, 0x1dd8, 0x7160, 0x3400, 0xa102, 0x0120, 0x0218, + 0x20a8, 0xa00e, 0x41a4, 0x3800, 0xd08c, 0x01d8, 0x2009, 0xb100, + 0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0001, + 0xa112, 0x20a1, 0x1000, 0xa00e, 0x21a8, 0x41a4, 0x8211, 0x1de0, + 0x2009, 0xb100, 0x3400, 0xa102, 0x0120, 0x0218, 0x20a8, 0xa00e, + 0x41a4, 0x080c, 0x1400, 0x080c, 0x1617, 0x080c, 0x17b0, 0x080c, + 0x1ebd, 0x080c, 0x4a74, 0x080c, 0x828d, 0x080c, 0x15a0, 0x080c, + 0x2d8c, 0x080c, 0x5b8b, 0x080c, 0x51aa, 0x080c, 0x668a, 0x080c, + 0x23ea, 0x080c, 0x68d4, 0x080c, 0x6194, 0x080c, 0x22de, 0x080c, + 0x23b8, 0x2091, 0x3009, 0x7823, 0x0000, 0x1004, 0x10c5, 0x7820, + 0xa086, 0x0002, 0x1150, 0x7823, 0x4000, 0x0e04, 0x10bd, 0x781b, + 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000, + 0x2a70, 0x7000, 0xa08e, 0x0003, 0x1158, 0x080c, 0x3d97, 0x080c, + 0x2db3, 0x080c, 0x5bd9, 0x080c, 0x5359, 0x080c, 0x66b4, 0x0c80, + 0x000b, 0x0c98, 0x10e4, 0x10e5, 0x1207, 0x10e2, 0x12d0, 0x13fd, + 0x13fe, 0x13ff, 0x080c, 0x14fa, 0x0005, 0x0126, 0x00f6, 0x2091, + 0x8000, 0x7000, 0xa086, 0x0001, 0x1904, 0x11d5, 0x080c, 0x156d, + 0x080c, 0x58d5, 0x0150, 0x080c, 0x58fb, 0x15a0, 0x2079, 0x0100, + 0x7828, 0xa085, 0x1800, 0x782a, 0x0468, 0x080c, 0x5816, 0x7000, + 0xa086, 0x0001, 0x1904, 0x11d5, 0x7088, 0xa086, 0x0028, 0x1904, + 0x11d5, 0x2001, 0x0161, 0x2003, 0x0001, 0x2079, 0x0100, 0x7827, + 0xffff, 0x7a28, 0xa295, 0x1e2f, 0x7a2a, 0x2011, 0x57ea, 0x080c, + 0x6742, 0x2011, 0x57f7, 0x080c, 0x6742, 0x2011, 0x494f, 0x080c, + 0x6742, 0x2011, 0x8030, 0x2019, 0x0000, 0x7087, 0x0000, 0x080c, + 0x1d33, 0x00e8, 0x080c, 0x4305, 0x2079, 0x0100, 0x7844, 0xa005, + 0x1904, 0x11d5, 0x2011, 0x494f, 0x080c, 0x6742, 0x2011, 0x57f7, + 0x080c, 0x6742, 0x080c, 0x1d33, 0x2001, 0xb38d, 0x2004, 0x780e, + 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, 0x8010, 0x73c8, 0x080c, + 0x3d5b, 0x7238, 0xc284, 0x723a, 0x2001, 0xb10c, 0x200c, 0xc1ac, + 0x2102, 0x080c, 0x7c1d, 0x2011, 0x0004, 0x080c, 0x9870, 0x080c, + 0x50bf, 0x080c, 0x58d5, 0x0158, 0x080c, 0x4a5d, 0x0140, 0x7087, + 0x0001, 0x70c3, 0x0000, 0x080c, 0x44a2, 0x0804, 0x11d5, 0x080c, + 0x517b, 0x0120, 0x7a0c, 0xc2b4, 0x7a0e, 0x0050, 0x080c, 0x9c16, + 0x70d0, 0xd09c, 0x1128, 0x709c, 0xa005, 0x0110, 0x080c, 0x4a3b, + 0x70db, 0x0000, 0x70d7, 0x0000, 0x72d0, 0x080c, 0x58d5, 0x1178, + 0x2011, 0x0000, 0x0016, 0x080c, 0x27c4, 0x2019, 0xb38f, 0x211a, + 0x001e, 0x704f, 0xffff, 0x7053, 0x00ef, 0x7073, 0x0000, 0x2079, + 0xb152, 0x7804, 0xd0ac, 0x0108, 0xc295, 0x72d2, 0x080c, 0x58d5, + 0x0118, 0xa296, 0x0004, 0x0508, 0x2011, 0x0001, 0x080c, 0x9870, + 0x7097, 0x0000, 0x709b, 0xffff, 0x7003, 0x0002, 0x00fe, 0x080c, + 0x2991, 0x2011, 0x0005, 0x080c, 0x7d52, 0x080c, 0x6e9e, 0x080c, + 0x58d5, 0x0148, 0x00c6, 0x2061, 0x0100, 0x0016, 0x080c, 0x27c4, + 0x61e2, 0x001e, 0x00ce, 0x012e, 0x00d0, 0x7097, 0x0000, 0x709b, + 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, 0x080c, 0x7d52, 0x080c, + 0x6e9e, 0x080c, 0x58d5, 0x0148, 0x00c6, 0x2061, 0x0100, 0x0016, + 0x080c, 0x27c4, 0x61e2, 0x001e, 0x00ce, 0x00fe, 0x012e, 0x0005, + 0x00c6, 0x080c, 0x58d5, 0x1118, 0x20a9, 0x0100, 0x0010, 0x20a9, + 0x0082, 0x080c, 0x58d5, 0x1118, 0x2009, 0x0000, 0x0010, 0x2009, + 0x007e, 0x0016, 0x0026, 0x0036, 0x2110, 0x0026, 0x2019, 0x0029, + 0x080c, 0x7f67, 0x002e, 0x080c, 0xaf53, 0x003e, 0x002e, 0x001e, + 0x080c, 0x2c6e, 0x8108, 0x1f04, 0x11e9, 0x00ce, 0x706f, 0x0000, + 0x7070, 0xa084, 0x00ff, 0x7072, 0x709f, 0x0000, 0x0005, 0x0126, + 0x2091, 0x8000, 0x7000, 0xa086, 0x0002, 0x1904, 0x12ce, 0x7098, + 0xa086, 0xffff, 0x0130, 0x080c, 0x2991, 0x080c, 0x6e9e, 0x0804, + 0x12ce, 0x70d0, 0xd0ac, 0x1110, 0xd09c, 0x0540, 0xd084, 0x0530, + 0x0006, 0x0016, 0x2001, 0x0103, 0x2009, 0xb38d, 0x210c, 0x2102, + 0x001e, 0x000e, 0xd08c, 0x01d0, 0x70d4, 0xa086, 0xffff, 0x0190, + 0x080c, 0x2af0, 0x080c, 0x6e9e, 0x70d0, 0xd094, 0x1904, 0x12ce, + 0x2011, 0x0001, 0x2019, 0x0000, 0x080c, 0x2b26, 0x080c, 0x6e9e, + 0x0804, 0x12ce, 0x70d8, 0xa005, 0x1904, 0x12ce, 0x7094, 0xa005, + 0x1904, 0x12ce, 0x70d0, 0xd0a4, 0x0118, 0xd0b4, 0x0904, 0x12ce, + 0x080c, 0x517b, 0x1904, 0x12ce, 0x2001, 0xb153, 0x2004, 0xd0ac, + 0x01c8, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, + 0x080c, 0x4e21, 0x1118, 0x6000, 0xd0ec, 0x1138, 0x001e, 0x8108, + 0x1f04, 0x125f, 0x00ce, 0x015e, 0x0028, 0x001e, 0x00ce, 0x015e, + 0x0804, 0x12ce, 0x0006, 0x0016, 0x2001, 0x0103, 0x2009, 0xb38d, + 0x210c, 0x2102, 0x001e, 0x000e, 0xa006, 0x2009, 0x0700, 0x20a9, + 0x0002, 0x20a1, 0xb3c7, 0x40a1, 0x706c, 0x8007, 0x7170, 0x810f, + 0x20a9, 0x0002, 0x40a1, 0x2009, 0x0000, 0x080c, 0x14e0, 0x2001, + 0x0000, 0x810f, 0x20a9, 0x0002, 0x40a1, 0xa006, 0x2009, 0x0200, + 0x20a9, 0x0002, 0x20a1, 0xb3d7, 0x40a1, 0x7030, 0xc08c, 0x7032, + 0x7003, 0x0003, 0x709b, 0xffff, 0x080c, 0x1566, 0xa006, 0x080c, + 0x269e, 0x080c, 0x3dcd, 0x00f6, 0x2079, 0x0100, 0x080c, 0x58fb, + 0x0150, 0x080c, 0x58d5, 0x7828, 0x0118, 0xa084, 0xe1ff, 0x0010, + 0xa084, 0xffdf, 0x782a, 0x00fe, 0x2001, 0xb3da, 0x2004, 0xa086, + 0x0005, 0x1120, 0x2011, 0x0000, 0x080c, 0x7d52, 0x2011, 0x0000, + 0x080c, 0x7d5c, 0x080c, 0x6e9e, 0x080c, 0x6f5b, 0x012e, 0x0005, + 0x0016, 0x0046, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, + 0x2009, 0xb133, 0x2104, 0xa005, 0x1110, 0x080c, 0x27f0, 0x2009, + 0x00f7, 0x080c, 0x4a24, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, + 0xd1b4, 0x0110, 0x7827, 0x0040, 0xd19c, 0x0110, 0x7827, 0x0008, + 0x0006, 0x0036, 0x0156, 0x7954, 0xd1ac, 0x1904, 0x133e, 0x080c, + 0x58e7, 0x0158, 0x080c, 0x58fb, 0x1128, 0x2001, 0xb39e, 0x2003, + 0x0000, 0x0070, 0x080c, 0x58dd, 0x0dc0, 0x2001, 0xb39e, 0x2003, + 0xaaaa, 0x2001, 0xb39f, 0x2003, 0x0001, 0x080c, 0x5816, 0x0058, + 0x080c, 0x58d5, 0x0140, 0x2009, 0x00f8, 0x080c, 0x4a24, 0x7843, + 0x0090, 0x7843, 0x0010, 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, + 0x080c, 0x58d5, 0x0138, 0x7824, 0xd0ac, 0x1904, 0x13e4, 0x1f04, + 0x131d, 0x0070, 0x7824, 0x080c, 0x58f1, 0x0118, 0xd0ac, 0x1904, + 0x13e4, 0xa084, 0x1800, 0x0d98, 0x7003, 0x0001, 0x0804, 0x13e4, + 0x2001, 0x0001, 0x080c, 0x269e, 0x0804, 0x13f3, 0x7850, 0xa084, + 0x0180, 0x7852, 0x782f, 0x0020, 0x20a9, 0x0046, 0x1d04, 0x1346, + 0x2091, 0x6000, 0x1f04, 0x1346, 0x7850, 0xa084, 0x0180, 0xa085, + 0x0400, 0x7852, 0x782f, 0x0000, 0x080c, 0x58e7, 0x0158, 0x080c, + 0x58fb, 0x1128, 0x2001, 0xb39e, 0x2003, 0x0000, 0x0070, 0x080c, + 0x58dd, 0x0dc0, 0x2001, 0xb39e, 0x2003, 0xaaaa, 0x2001, 0xb39f, + 0x2003, 0x0001, 0x080c, 0x5816, 0x0020, 0x2009, 0x00f8, 0x080c, + 0x4a24, 0x20a9, 0x000e, 0xe000, 0x1f04, 0x1373, 0x7850, 0xa084, + 0x0180, 0xa085, 0x1400, 0x7852, 0x080c, 0x58d5, 0x0120, 0x7843, + 0x0090, 0x7843, 0x0010, 0x2021, 0xe678, 0x2019, 0xea60, 0x7820, + 0xd09c, 0x1558, 0x080c, 0x58d5, 0x05b8, 0x7824, 0xd0ac, 0x1904, + 0x13e4, 0x080c, 0x58fb, 0x1508, 0x0046, 0x2021, 0x0190, 0x8421, + 0x1df0, 0x004e, 0x8421, 0x11c8, 0x7827, 0x0048, 0x20a9, 0x01f4, + 0x1d04, 0x13a0, 0x2091, 0x6000, 0x1f04, 0x13a0, 0x7824, 0xa084, + 0x0068, 0x15a8, 0x2001, 0xb39e, 0x2003, 0xaaaa, 0x2001, 0xb39f, + 0x2003, 0x0001, 0x7003, 0x0001, 0x0478, 0x8319, 0x1980, 0x2009, + 0xb133, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0120, 0x200b, + 0x0000, 0x080c, 0x27f0, 0x00d8, 0x080c, 0x58e7, 0x1140, 0xa4a2, + 0x0064, 0x1128, 0x080c, 0x58ac, 0x7003, 0x0001, 0x00a8, 0x7827, + 0x1800, 0xe000, 0xe000, 0x7824, 0x080c, 0x58f1, 0x0110, 0xd0ac, + 0x1158, 0xa084, 0x1800, 0x09c8, 0x7003, 0x0001, 0x0028, 0x2001, + 0x0001, 0x080c, 0x269e, 0x0048, 0x2001, 0xb133, 0x2003, 0x0000, + 0x7827, 0x0048, 0x7828, 0xc09d, 0x782a, 0x7850, 0xa084, 0x0180, + 0xa085, 0x0400, 0x7852, 0x015e, 0x003e, 0x000e, 0x080c, 0x153d, + 0x012e, 0x00fe, 0x004e, 0x001e, 0x0005, 0x0005, 0x0005, 0x0005, + 0x2a70, 0x2001, 0xb39e, 0x2003, 0x0000, 0x7087, 0x0000, 0x2009, + 0x0100, 0x2104, 0xa082, 0x0002, 0x0218, 0x704f, 0xffff, 0x0010, + 0x704f, 0x0000, 0x7057, 0xffff, 0x706f, 0x0000, 0x7073, 0x0000, + 0x080c, 0x9c16, 0x2061, 0xb38e, 0x6003, 0x0909, 0x6007, 0x0000, + 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0003, + 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, 0xb396, 0x6003, 0x8000, + 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, 0x0200, 0x6013, 0x00ff, + 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, 0x0000, 0x2061, 0xb3b8, + 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, 0x4943, 0x600f, 0x2020, + 0x2001, 0xb127, 0x2003, 0x0000, 0x0005, 0x04a0, 0x2011, 0x0000, + 0x81ff, 0x0570, 0xa186, 0x0001, 0x1148, 0x2031, 0x8fff, 0x2039, + 0xd001, 0x2021, 0x0100, 0x2029, 0xd000, 0x00e8, 0xa186, 0x0002, + 0x1118, 0x2011, 0x0000, 0x00b8, 0xa186, 0x0005, 0x1118, 0x2011, + 0x0001, 0x0088, 0xa186, 0x0009, 0x1118, 0x2011, 0x0002, 0x0058, + 0xa186, 0x000a, 0x1118, 0x2011, 0x0002, 0x0028, 0xa186, 0x0055, + 0x1110, 0x2011, 0x0003, 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, + 0x0804, 0x104d, 0xa00e, 0x2011, 0x0003, 0x2019, 0x1489, 0x0804, + 0x14da, 0x2019, 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, 0xe000, + 0xe000, 0x2c04, 0xa306, 0x2262, 0x1110, 0xc1b5, 0xc1a5, 0x2011, + 0x0000, 0x2019, 0x149c, 0x04f0, 0x2019, 0xaaaa, 0x2061, 0xffff, + 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, 0xe000, + 0xe000, 0x2c04, 0x2061, 0xffff, 0x2262, 0xa306, 0x0110, 0xc18d, + 0x0008, 0xc185, 0x2011, 0x0002, 0x2019, 0x14b7, 0x0418, 0x2061, + 0xffff, 0x2019, 0xaaaa, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, + 0x2262, 0xa306, 0x1180, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c1c, + 0x2061, 0x7fff, 0x2c04, 0x2061, 0xffff, 0x2262, 0xa306, 0x1110, + 0xc195, 0x0008, 0xc19d, 0x2011, 0x0001, 0x2019, 0x14d8, 0x0010, + 0x0804, 0x144e, 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x0837, + 0x2011, 0x0000, 0x080c, 0x4e21, 0x1178, 0x6004, 0xa0c4, 0x00ff, + 0xa8c6, 0x0006, 0x0128, 0xa0c4, 0xff00, 0xa8c6, 0x0600, 0x1120, + 0xa186, 0x0080, 0x0108, 0x8210, 0x8108, 0xa186, 0x0100, 0x1d50, + 0x2208, 0x0005, 0x2091, 0x8000, 0x0e04, 0x14fc, 0x0006, 0x0016, + 0x2079, 0x0000, 0x7818, 0xd084, 0x1de8, 0x001e, 0x792e, 0x000e, + 0x782a, 0x000e, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, + 0x0001, 0x2091, 0x5000, 0x0126, 0x0156, 0x0146, 0x20a9, 0x0010, + 0x20a1, 0xb4fc, 0x2091, 0x2000, 0x40a1, 0x20a9, 0x0010, 0x2091, + 0x2200, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2400, 0x40a1, 0x20a9, + 0x0010, 0x2091, 0x2600, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2800, + 0x40a1, 0x014e, 0x015e, 0x012e, 0x2079, 0xb100, 0x7803, 0x0005, + 0x2091, 0x4080, 0x04c9, 0x0cf8, 0x0005, 0x0006, 0x080c, 0x1588, + 0x1518, 0x00f6, 0x2079, 0xb123, 0x2f04, 0x8000, 0x207a, 0xa082, + 0x000f, 0x0258, 0xa006, 0x207a, 0x2079, 0xb125, 0x2f04, 0xa084, + 0x0001, 0xa086, 0x0001, 0x207a, 0x0070, 0x2079, 0xb125, 0x2f7c, + 0x8fff, 0x1128, 0x2001, 0x0c03, 0x2003, 0x0040, 0x0020, 0x2001, + 0x0c03, 0x2003, 0x00c0, 0x00fe, 0x000e, 0x0005, 0x0409, 0x1120, + 0x2001, 0x0c03, 0x2003, 0x0080, 0x0005, 0x00d1, 0x1120, 0x2001, + 0x0c03, 0x2003, 0x0040, 0x0005, 0x0006, 0x0091, 0x1178, 0x2001, + 0x0c03, 0x2003, 0x0040, 0x2009, 0x0fff, 0x00a1, 0x2001, 0x0c03, + 0x2003, 0x0080, 0x2009, 0x0fff, 0x0069, 0x0c88, 0x000e, 0x0005, + 0x00c6, 0x2061, 0x0c00, 0x2c04, 0xa084, 0x00ff, 0xa086, 0x00aa, + 0x00ce, 0x0005, 0x0156, 0x0126, 0xa18c, 0x0fff, 0x21a8, 0x1d04, + 0x1597, 0x2091, 0x6000, 0x1f04, 0x1597, 0x012e, 0x015e, 0x0005, + 0x2071, 0xb100, 0x715c, 0x712e, 0x2021, 0x0001, 0xa190, 0x0030, + 0xa298, 0x0030, 0x0240, 0x7060, 0xa302, 0x1228, 0x220a, 0x2208, + 0x2310, 0x8420, 0x0ca8, 0x3800, 0xd08c, 0x0148, 0x7060, 0xa086, + 0xb100, 0x0128, 0x7063, 0xb100, 0x2011, 0x1000, 0x0c48, 0x200b, + 0x0000, 0x74ae, 0x74b2, 0x0005, 0x00e6, 0x0126, 0x2091, 0x8000, + 0x2071, 0xb100, 0x70b0, 0xa0ea, 0x0010, 0x0268, 0x8001, 0x70b2, + 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, + 0x012e, 0x00ee, 0x0005, 0xa06e, 0x0cd8, 0x00e6, 0x2071, 0xb100, + 0x0126, 0x2091, 0x8000, 0x70b0, 0x8001, 0x0260, 0x70b2, 0x702c, + 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x012e, + 0x00ee, 0x0005, 0xa06e, 0x0cd8, 0x00e6, 0x0126, 0x2091, 0x8000, + 0x2071, 0xb100, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b0, 0x8000, + 0x70b2, 0x012e, 0x00ee, 0x0005, 0x8dff, 0x0138, 0x6804, 0x6807, + 0x0000, 0x0006, 0x0c49, 0x00de, 0x0cb8, 0x0005, 0x00e6, 0x2071, + 0xb100, 0x70b0, 0xa08a, 0x0010, 0xa00d, 0x00ee, 0x0005, 0x00e6, + 0x2071, 0xb408, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, + 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x00ee, 0x0005, + 0x00e6, 0x2270, 0x700b, 0x0000, 0x2071, 0xb408, 0x7018, 0xa088, + 0xb411, 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, + 0x1128, 0x00f6, 0x2079, 0x0010, 0x0081, 0x00fe, 0x00ee, 0x0005, + 0x00e6, 0x2071, 0xb408, 0x7004, 0xa005, 0x1128, 0x00f6, 0x2079, + 0x0010, 0x0019, 0x00fe, 0x00ee, 0x0005, 0x7000, 0x0002, 0x1653, + 0x16b7, 0x16d4, 0x16d4, 0x7018, 0x711c, 0xa106, 0x1118, 0x7007, + 0x0000, 0x0005, 0x00d6, 0xa180, 0xb411, 0x2004, 0x700a, 0x2068, + 0x8108, 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, + 0x6828, 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, + 0x680c, 0x7016, 0x6804, 0x00de, 0xd084, 0x0120, 0x7007, 0x0001, + 0x0029, 0x0005, 0x7007, 0x0002, 0x00b1, 0x0005, 0x0016, 0x0026, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, + 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0041, + 0x002e, 0x001e, 0x0005, 0x0016, 0x0026, 0x0136, 0x0146, 0x0156, + 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, 0x2011, + 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, 0x700e, 0x22a8, + 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x3300, 0x7016, 0x7803, + 0x0001, 0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, 0x0136, + 0x0146, 0x0156, 0x2099, 0xb1fa, 0x20a1, 0x0018, 0x20a9, 0x0008, + 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0041, + 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, 0xb1f5, 0x012e, + 0x015e, 0x014e, 0x013e, 0x0005, 0x0136, 0x0146, 0x0156, 0x2001, + 0xb229, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, 0x2001, 0xb22a, + 0x20ac, 0x53a6, 0x2099, 0xb22b, 0x20a1, 0x0018, 0x20a9, 0x0008, + 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0001, + 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, 0xb226, 0x012e, + 0x015e, 0x014e, 0x013e, 0x0005, 0x0016, 0x00e6, 0x2071, 0xb408, + 0x00f6, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, 0xd1fc, 0x0120, + 0xa18c, 0x0700, 0x7004, 0x0023, 0x00fe, 0x00ee, 0x001e, 0x0005, + 0x164d, 0x1717, 0x1745, 0x176f, 0x179f, 0x1716, 0x0cf8, 0xa18c, + 0x0700, 0x1528, 0x0136, 0x0146, 0x0156, 0x7014, 0x20a0, 0x2099, + 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, + 0x015e, 0x014e, 0x013e, 0x700c, 0xa005, 0x0570, 0x7830, 0x7832, + 0x7834, 0x7836, 0x080c, 0x167e, 0x0005, 0x7008, 0xa080, 0x0002, + 0x2003, 0x0100, 0x7007, 0x0000, 0x080c, 0x164d, 0x0005, 0x7008, + 0xa080, 0x0002, 0x2003, 0x0200, 0x0ca8, 0xa18c, 0x0700, 0x1150, + 0x700c, 0xa005, 0x0188, 0x7830, 0x7832, 0x7834, 0x7836, 0x080c, + 0x1693, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, 0x7007, + 0x0000, 0x080c, 0x164d, 0x0005, 0x00d6, 0x7008, 0x2068, 0x7830, + 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, 0x6832, 0x680b, + 0x0100, 0x00de, 0x7007, 0x0000, 0x080c, 0x164d, 0x0005, 0xa18c, + 0x0700, 0x1540, 0x0136, 0x0146, 0x0156, 0x2001, 0xb1f8, 0x2004, + 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, + 0x0020, 0x53a5, 0x2001, 0xb1fa, 0x2004, 0xd0bc, 0x0148, 0x2001, + 0xb203, 0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, + 0x015e, 0x014e, 0x013e, 0x7007, 0x0000, 0x080c, 0x5c70, 0x080c, + 0x164d, 0x0005, 0x2011, 0x8003, 0x080c, 0x3d5b, 0x0cf8, 0xa18c, + 0x0700, 0x1148, 0x2001, 0xb228, 0x2003, 0x0100, 0x7007, 0x0000, + 0x080c, 0x164d, 0x0005, 0x2011, 0x8004, 0x080c, 0x3d5b, 0x0cf8, + 0x0126, 0x2091, 0x2200, 0x2079, 0x0030, 0x2071, 0xb419, 0x7003, + 0x0000, 0x700f, 0xb41f, 0x7013, 0xb41f, 0x780f, 0x00f6, 0x7803, + 0x0004, 0x012e, 0x0005, 0x6934, 0xa184, 0x0007, 0x0002, 0x17cf, + 0x180d, 0x17cf, 0x17cf, 0x17cf, 0x17f5, 0x17dc, 0x17d3, 0xa085, + 0x0001, 0x0804, 0x1827, 0x684c, 0xd0bc, 0x0dc8, 0x6860, 0x682e, + 0x685c, 0x682a, 0x6858, 0x04c8, 0xa18c, 0x00ff, 0xa186, 0x001e, + 0x1d70, 0x684c, 0xd0bc, 0x0d58, 0x6860, 0x682e, 0x685c, 0x682a, + 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, + 0x21f9, 0x2005, 0x6832, 0x6858, 0x0440, 0xa18c, 0x00ff, 0xa186, + 0x0015, 0x19a8, 0x684c, 0xd0ac, 0x0990, 0x6804, 0x681a, 0xa080, + 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x21f9, 0x2005, 0x6832, + 0xa006, 0x682e, 0x682a, 0x6858, 0x0080, 0x684c, 0xd0ac, 0x0904, + 0x17cf, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, 0x000f, 0xa188, + 0x21f9, 0x210d, 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, + 0x684e, 0xa006, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x0005, + 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x82ff, + 0x01a8, 0xa280, 0x0004, 0x00d6, 0x206c, 0x684c, 0xd0dc, 0x1150, + 0x080c, 0x17c3, 0x0138, 0x00de, 0xa280, 0x0000, 0x2003, 0x0002, + 0xa016, 0x0020, 0x6808, 0x8000, 0x680a, 0x00de, 0x0126, 0x0046, + 0x0036, 0x0026, 0x2091, 0x2200, 0x002e, 0x003e, 0x004e, 0x7000, + 0xa005, 0x01d0, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, + 0x8108, 0xa182, 0xb43a, 0x0210, 0x2009, 0xb41f, 0x710e, 0x7010, + 0xa102, 0xa082, 0x0009, 0x0118, 0xa080, 0x001b, 0x1118, 0x2009, + 0x0138, 0x200a, 0x012e, 0x0005, 0x7206, 0x2001, 0x186a, 0x0006, + 0x2260, 0x0804, 0x1987, 0x0126, 0x0026, 0x0036, 0x00c6, 0x0006, + 0x2091, 0x2200, 0x000e, 0x004e, 0x003e, 0x002e, 0x00d6, 0x00c6, + 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, 0xa005, 0x0904, 0x18cc, + 0x6808, 0xa005, 0x0904, 0x1903, 0x7000, 0xa005, 0x1108, 0x0488, + 0x700c, 0x7110, 0xa106, 0x1904, 0x190b, 0x7004, 0xa406, 0x1548, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x0168, 0x0046, 0x080c, 0x1a86, + 0x004e, 0x2460, 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x0904, + 0x1903, 0x0c10, 0x2001, 0x0207, 0x2004, 0xd09c, 0x1d48, 0x7804, + 0xa084, 0x6000, 0x0120, 0xa086, 0x6000, 0x0108, 0x0c08, 0x7818, + 0x6812, 0x781c, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, + 0x2060, 0x6100, 0xa18e, 0x0004, 0x1904, 0x190b, 0x2009, 0x0048, + 0x080c, 0x831a, 0x0804, 0x190b, 0x6808, 0xa005, 0x05a0, 0x7000, + 0xa005, 0x0588, 0x700c, 0x7110, 0xa106, 0x1118, 0x7004, 0xa406, + 0x1550, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0160, 0x0046, 0x080c, + 0x1a86, 0x004e, 0x2460, 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, + 0x01d0, 0x0c28, 0x2001, 0x0207, 0x2004, 0xd09c, 0x1d50, 0x2001, + 0x0005, 0x2004, 0xd08c, 0x1d50, 0x7804, 0xa084, 0x6000, 0x0118, + 0xa086, 0x6000, 0x19f0, 0x7818, 0x6812, 0x781c, 0x6816, 0x7803, + 0x0004, 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x1120, 0x2009, + 0x0048, 0x080c, 0x831a, 0x00ce, 0x00de, 0x012e, 0x0005, 0x00f6, + 0x00e6, 0x0026, 0x0036, 0x0046, 0x0056, 0x2071, 0xb419, 0x7000, + 0xa086, 0x0000, 0x0904, 0x1965, 0x7004, 0xac06, 0x15c0, 0x2079, + 0x0030, 0x7000, 0xa086, 0x0003, 0x0590, 0x7804, 0xd0fc, 0x1560, + 0x2001, 0x0207, 0x2004, 0xd09c, 0x1dc0, 0x7804, 0xd0fc, 0x1520, + 0x080c, 0x1db4, 0x0026, 0x0056, 0x7803, 0x0004, 0x7804, 0xd0ac, + 0x1de8, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003, 0x7007, + 0x0000, 0x005e, 0x002e, 0x2001, 0x015d, 0x2003, 0x0000, 0x080c, + 0x58d5, 0x1118, 0x080c, 0x5957, 0x0050, 0x2001, 0x0160, 0x2502, + 0x2001, 0x0138, 0x2202, 0x0018, 0x080c, 0x1a86, 0x0800, 0x0156, + 0x20a9, 0x0009, 0x2009, 0xb41f, 0x2104, 0xac06, 0x1108, 0x200a, + 0xa188, 0x0003, 0x1f04, 0x195c, 0x015e, 0x005e, 0x004e, 0x003e, + 0x002e, 0x00ee, 0x00fe, 0x0005, 0x700c, 0x7110, 0xa106, 0x0904, + 0x19f7, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, + 0x8108, 0xa182, 0xb43a, 0x0210, 0x2009, 0xb41f, 0x7112, 0x700c, + 0xa106, 0x1128, 0x080c, 0x27c4, 0x2001, 0x0138, 0x2102, 0x8cff, + 0x0598, 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, 0x1590, 0x682c, + 0xa306, 0x1578, 0x7004, 0x2060, 0x6020, 0xc0d4, 0x6022, 0x684c, + 0xd0f4, 0x0128, 0x6817, 0xffff, 0x6813, 0xffff, 0x00e8, 0x6850, + 0xd0f4, 0x1130, 0x7803, 0x0004, 0x6810, 0x781a, 0x6814, 0x781e, + 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, + 0x000f, 0x2009, 0x0011, 0x080c, 0x19fa, 0x0120, 0x2009, 0x0001, + 0x080c, 0x19fa, 0x2d58, 0x0005, 0x080c, 0x1d11, 0x0904, 0x196c, + 0x0cd0, 0x6020, 0xd0f4, 0x11e0, 0xd0d4, 0x01b8, 0x6038, 0xa402, + 0x6034, 0xa303, 0x0108, 0x1288, 0x643a, 0x6336, 0x6c2a, 0x6b2e, + 0x0046, 0x0036, 0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80, + 0xa303, 0x6816, 0x003e, 0x004e, 0x0018, 0x080c, 0x9ba8, 0x09e0, + 0x601c, 0xa08e, 0x0008, 0x0904, 0x1992, 0xa08e, 0x000a, 0x0904, + 0x1992, 0x2001, 0xb174, 0x2004, 0xd0b4, 0x1120, 0x6817, 0xffff, + 0x6813, 0xffff, 0x080c, 0x2219, 0x1938, 0x0804, 0x1992, 0x7003, + 0x0000, 0x0005, 0x8aff, 0x0904, 0x1a60, 0xa03e, 0x2730, 0x6850, + 0xd0fc, 0x11b8, 0xd0f4, 0x1528, 0x00d6, 0x2805, 0xac68, 0x2900, + 0x0002, 0x1a4a, 0x1a2f, 0x1a2f, 0x1a4a, 0x1a4a, 0x1a43, 0x1a4a, + 0x1a2f, 0x1a4a, 0x1a34, 0x1a34, 0x1a4a, 0x1a4a, 0x1a4a, 0x1a3b, + 0x1a34, 0x7803, 0x0004, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, + 0x6c20, 0x00d6, 0xd99c, 0x0548, 0x2805, 0xac68, 0x6f08, 0x6e0c, + 0x0420, 0xc0f4, 0x6852, 0x6b6c, 0x6a70, 0x00d6, 0x0428, 0x6b08, + 0x6a0c, 0x6d00, 0x6c04, 0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04, + 0x6f08, 0x6e0c, 0x0090, 0x00de, 0x00d6, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x001e, 0x1138, 0x00de, 0x080c, 0x21bb, 0x1904, 0x19fa, + 0xa00e, 0x00b0, 0x00de, 0x080c, 0x14fa, 0x7b22, 0x7a26, 0x7d32, + 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x00de, + 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x080c, 0x21bb, + 0x0005, 0x080c, 0x14fa, 0x080c, 0x1e70, 0x7004, 0x2060, 0x00d6, + 0x6010, 0x2068, 0x7003, 0x0000, 0x080c, 0x1d48, 0x080c, 0x986a, + 0x0170, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, + 0x682b, 0xffff, 0x682f, 0xffff, 0x6850, 0xc0bd, 0x6852, 0x00de, + 0x080c, 0x955c, 0x0804, 0x1c7c, 0x080c, 0x14fa, 0x0126, 0x2091, + 0x2200, 0x0006, 0x0016, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, + 0x0002, 0xa184, 0x0700, 0x1978, 0xa184, 0x0003, 0xa086, 0x0003, + 0x0d58, 0x7000, 0x0002, 0x1aa3, 0x1aa9, 0x1bb0, 0x1c57, 0x1c6b, + 0x1aa3, 0x1aa3, 0x1aa3, 0x7804, 0xd09c, 0x1904, 0x1c7c, 0x080c, + 0x14fa, 0x8001, 0x7002, 0xd1bc, 0x11a0, 0xd19c, 0x1904, 0x1b3b, + 0xd1dc, 0x1178, 0x8aff, 0x0904, 0x1b3b, 0x2009, 0x0001, 0x080c, + 0x19fa, 0x0904, 0x1c7c, 0x2009, 0x0001, 0x080c, 0x19fa, 0x0804, + 0x1c7c, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1b1b, + 0x0026, 0x0036, 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, + 0x781c, 0x6816, 0x2001, 0x0201, 0x2004, 0xa005, 0x0140, 0x7808, + 0xd0ec, 0x1128, 0x7803, 0x0009, 0x7003, 0x0004, 0x0010, 0x080c, + 0x1c80, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500, 0x6872, + 0xa213, 0x6b2a, 0x6a2e, 0x00c6, 0x7004, 0x2060, 0x6020, 0xd0f4, + 0x1110, 0x633a, 0x6236, 0x00ce, 0x003e, 0x002e, 0x6e1e, 0x6f22, + 0x080c, 0x21d1, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, + 0x6850, 0xc0fd, 0x6852, 0x6808, 0x8001, 0x680a, 0x1148, 0x684c, + 0xd0e4, 0x0130, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c, 0x831a, + 0x7000, 0xa086, 0x0004, 0x0904, 0x1c7c, 0x7003, 0x0000, 0x080c, + 0x196c, 0x0804, 0x1c7c, 0x0056, 0x7d0c, 0xd5bc, 0x1110, 0x080c, + 0xafbf, 0x005e, 0x080c, 0x1d48, 0x00f6, 0x7004, 0x2078, 0x080c, + 0x5177, 0x0118, 0x7820, 0xc0f5, 0x7822, 0x00fe, 0x682b, 0xffff, + 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x791a, 0x6980, + 0x791e, 0x0804, 0x1c7c, 0x7004, 0x00c6, 0x2060, 0x6020, 0x00ce, + 0xd0f4, 0x0120, 0x6808, 0x8001, 0x680a, 0x0420, 0x7818, 0x6812, + 0x7a1c, 0x6a16, 0xd19c, 0x0160, 0xa205, 0x0150, 0x7004, 0xa080, + 0x0007, 0x2004, 0xa084, 0xfffd, 0xa086, 0x0008, 0x1904, 0x1ac1, + 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x1180, 0x7003, 0x0000, + 0x6808, 0x8001, 0x680a, 0x1130, 0x7004, 0x2060, 0x2009, 0x0048, + 0x080c, 0x831a, 0x080c, 0x196c, 0x0804, 0x1c7c, 0x7818, 0x6812, + 0x781c, 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa192, 0x0841, + 0x1a04, 0x1a63, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, + 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x080c, + 0x1dd7, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, + 0xd0fc, 0x0de8, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x00f6, + 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, 0x080c, 0x831a, + 0x080c, 0x1e09, 0x0938, 0x7908, 0xd1ec, 0x1118, 0x2009, 0x0009, + 0x0010, 0x2009, 0x0019, 0x7902, 0x7003, 0x0003, 0x0804, 0x1c7c, + 0x8001, 0x7002, 0xd194, 0x01a8, 0x7804, 0xd0fc, 0x1904, 0x1c4a, + 0xd09c, 0x0130, 0x7804, 0xd0fc, 0x1904, 0x1a8e, 0xd09c, 0x11a8, + 0x8aff, 0x0904, 0x1c7c, 0x2009, 0x0001, 0x080c, 0x19fa, 0x0804, + 0x1c7c, 0xa184, 0x0888, 0x1148, 0x8aff, 0x0904, 0x1c7c, 0x2009, + 0x0001, 0x080c, 0x19fa, 0x0804, 0x1c7c, 0x7818, 0x6812, 0x7a1c, + 0x6a16, 0xa205, 0x0904, 0x1b58, 0x7803, 0x0004, 0x7003, 0x0000, + 0xd1bc, 0x1904, 0x1c2d, 0x6834, 0xa084, 0x00ff, 0xa086, 0x0029, + 0x1118, 0xd19c, 0x1904, 0x1b58, 0x0026, 0x0036, 0x7c20, 0x7d24, + 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, 0x6816, 0x2001, 0x0201, + 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, 0x1128, 0x7803, 0x0009, + 0x7003, 0x0004, 0x0020, 0x0016, 0x080c, 0x1c80, 0x001e, 0x6b28, + 0x6a2c, 0x080c, 0x21d1, 0x00d6, 0x2805, 0xac68, 0x6034, 0xd09c, + 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020, 0x6810, 0xa31a, + 0x6814, 0xa213, 0x00de, 0xd194, 0x0904, 0x1ae3, 0x2a00, 0x6826, + 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, 0x8001, 0x680a, 0x6b2a, + 0x6a2e, 0x003e, 0x002e, 0x0804, 0x1b6a, 0x0056, 0x7d0c, 0x080c, + 0xafbf, 0x005e, 0x080c, 0x1d48, 0x00f6, 0x7004, 0x2078, 0x080c, + 0x5177, 0x0118, 0x7820, 0xc0f5, 0x7822, 0x00fe, 0x682b, 0xffff, + 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x791a, 0x6980, + 0x791e, 0x0490, 0x7804, 0xd09c, 0x0904, 0x1a8e, 0x7c20, 0x7824, + 0xa405, 0x1904, 0x1a8e, 0x7803, 0x0002, 0x0804, 0x1bd5, 0x7803, + 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0150, 0x6808, 0x8001, + 0x680a, 0x1130, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c, 0x831a, + 0x080c, 0x196c, 0x0088, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, + 0x2060, 0x6010, 0xa005, 0x0da0, 0x2068, 0x6808, 0x8000, 0x680a, + 0x6c28, 0x6b2c, 0x080c, 0x1987, 0x001e, 0x000e, 0x012e, 0x0005, + 0x700c, 0x7110, 0xa106, 0x0904, 0x1d05, 0x7004, 0x0016, 0x210c, + 0xa106, 0x001e, 0x0904, 0x1d05, 0x00d6, 0x00c6, 0x216c, 0x2d00, + 0xa005, 0x0904, 0x1d03, 0x6820, 0xd0d4, 0x1904, 0x1d03, 0x6810, + 0x2068, 0x6850, 0xd0fc, 0x0558, 0x8108, 0x2104, 0x6b2c, 0xa306, + 0x1904, 0x1d03, 0x8108, 0x2104, 0x6a28, 0xa206, 0x1904, 0x1d03, + 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822, 0x6870, 0x7826, + 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060, 0x6034, 0xd09c, + 0x0150, 0x6830, 0x2005, 0x00d6, 0xac68, 0x6808, 0x783a, 0x680c, + 0x783e, 0x00de, 0x04d0, 0xa006, 0x783a, 0x783e, 0x04b0, 0x8108, + 0x2104, 0xa005, 0x15c0, 0x6b2c, 0xa306, 0x15a8, 0x8108, 0x2104, + 0xa005, 0x1588, 0x6a28, 0xa206, 0x1570, 0x6850, 0xc0f5, 0x6852, + 0x6830, 0x2005, 0x6918, 0xa160, 0xa180, 0x000d, 0x2004, 0xd09c, + 0x1170, 0x6008, 0x7822, 0x686e, 0x600c, 0x7826, 0x6872, 0x6000, + 0x7832, 0x6004, 0x7836, 0xa006, 0x783a, 0x783e, 0x0070, 0x6010, + 0x7822, 0x686e, 0x6014, 0x7826, 0x6872, 0x6000, 0x7832, 0x6004, + 0x7836, 0x6008, 0x783a, 0x600c, 0x783e, 0x6810, 0x781a, 0x6814, + 0x781e, 0x7803, 0x0011, 0x00ce, 0x00de, 0x0005, 0x2011, 0x0201, + 0x2009, 0x003c, 0x2204, 0xa005, 0x1118, 0x8109, 0x1dd8, 0x0005, + 0x0005, 0x0ca1, 0x01e0, 0x7908, 0xd1ec, 0x1160, 0x080c, 0x1e09, + 0x0148, 0x7803, 0x0009, 0x7904, 0xd1fc, 0x0de8, 0x7803, 0x0006, + 0x0c29, 0x0168, 0x780c, 0xd0a4, 0x1150, 0x7007, 0x0000, 0x080c, + 0x1e09, 0x0140, 0x7803, 0x0019, 0x7003, 0x0003, 0x0018, 0x00c1, + 0xa085, 0x0001, 0x0005, 0x0126, 0x2091, 0x2200, 0x7000, 0xa086, + 0x0003, 0x1160, 0x700c, 0x7110, 0xa106, 0x0140, 0x080c, 0x2835, + 0x20e1, 0x9028, 0x700f, 0xb41f, 0x7013, 0xb41f, 0x012e, 0x0005, + 0x00c6, 0x080c, 0x58d5, 0x1570, 0x2001, 0x0160, 0x2003, 0x0000, + 0x2001, 0x0138, 0x2003, 0x0000, 0x2011, 0x00c8, 0xe000, 0xe000, + 0x8211, 0x1de0, 0x080c, 0x1daa, 0x700c, 0x7110, 0xa106, 0x0190, + 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001, + 0x600a, 0xa188, 0x0003, 0xa182, 0xb43a, 0x0210, 0x2009, 0xb41f, + 0x7112, 0x0c50, 0x0066, 0x2031, 0x0000, 0x080c, 0x5957, 0x006e, + 0x00ce, 0x0005, 0x04c9, 0x080c, 0x2835, 0x20e1, 0x9028, 0x700c, + 0x7110, 0xa106, 0x01d0, 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, + 0x2060, 0x6008, 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xb43a, + 0x0210, 0x2009, 0xb41f, 0x7112, 0x700c, 0xa106, 0x1d40, 0x080c, + 0x27c4, 0x2001, 0x0138, 0x2102, 0x0c10, 0x2001, 0x015d, 0x200c, + 0x810a, 0x2102, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, + 0x00ce, 0x0005, 0x080c, 0x2835, 0x20e1, 0x9028, 0x2001, 0x015d, + 0x200c, 0x810a, 0x2102, 0x0005, 0x2001, 0x0138, 0x2014, 0x2003, + 0x0000, 0x2001, 0x0160, 0x202c, 0x2003, 0x0000, 0x080c, 0x58d5, + 0x1108, 0x0005, 0x2021, 0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, + 0x1168, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, 0x1138, 0x2001, + 0x0111, 0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70, 0x0005, 0x00e6, + 0x2071, 0x0200, 0x7808, 0xa084, 0xf000, 0xa10d, 0x08a9, 0x2019, + 0x5000, 0x8319, 0x0168, 0x2001, 0xb43a, 0x2004, 0xa086, 0x0000, + 0x0138, 0x2001, 0x0021, 0xd0fc, 0x0da0, 0x080c, 0x205e, 0x0c78, + 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028, 0x7028, 0x7426, 0x7037, + 0x0001, 0x810f, 0x712e, 0x702f, 0x0100, 0x7037, 0x0008, 0x7326, + 0x7422, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x00ee, + 0x0005, 0x0026, 0x2001, 0x015d, 0x200c, 0x810a, 0x2102, 0x7908, + 0xa18c, 0x0fff, 0xa182, 0x0ffd, 0x0210, 0x2009, 0x0000, 0xa190, + 0x0007, 0xa294, 0x1ff8, 0x8214, 0x8214, 0x8214, 0x2001, 0x020a, + 0x82ff, 0x0140, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, + 0x8211, 0x1dd0, 0x20e1, 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, + 0x20e1, 0x6000, 0x2001, 0x0208, 0x200c, 0x2001, 0x0209, 0x2004, + 0xa106, 0x0158, 0x080c, 0x1d06, 0x0130, 0x7908, 0xd1ec, 0x1128, + 0x790c, 0xd1a4, 0x0960, 0x080c, 0x1d48, 0xa006, 0x002e, 0x0005, + 0x00f6, 0x00e6, 0x0016, 0x0026, 0x2071, 0xb419, 0x2079, 0x0030, + 0x2011, 0x0050, 0x7000, 0xa086, 0x0000, 0x01a8, 0x8211, 0x0188, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x0dc8, 0x7904, 0xa18c, 0x0780, + 0x0016, 0x080c, 0x1a86, 0x001e, 0x81ff, 0x1118, 0x2011, 0x0050, + 0x0c48, 0xa085, 0x0001, 0x002e, 0x001e, 0x00ee, 0x00fe, 0x0005, + 0x7803, 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac, 0x0904, 0x1ebc, + 0x8109, 0x1dd0, 0x2009, 0x0100, 0x210c, 0xa18a, 0x0003, 0x0a0c, + 0x14fa, 0x080c, 0x2165, 0x00e6, 0x00f6, 0x2071, 0xb408, 0x2079, + 0x0010, 0x7004, 0xa086, 0x0000, 0x0538, 0x7800, 0x0006, 0x7820, + 0x0006, 0x7830, 0x0006, 0x7834, 0x0006, 0x7838, 0x0006, 0x783c, + 0x0006, 0x7803, 0x0004, 0xe000, 0xe000, 0x2079, 0x0030, 0x7804, + 0xd0ac, 0x190c, 0x14fa, 0x2079, 0x0010, 0x000e, 0x783e, 0x000e, + 0x783a, 0x000e, 0x7836, 0x000e, 0x7832, 0x000e, 0x7822, 0x000e, + 0x7802, 0x00fe, 0x00ee, 0x0030, 0x00fe, 0x00ee, 0x7804, 0xd0ac, + 0x190c, 0x14fa, 0x080c, 0x6f5b, 0x0005, 0x00e6, 0x2071, 0xb43a, + 0x7003, 0x0000, 0x00ee, 0x0005, 0x00d6, 0xa280, 0x0004, 0x206c, + 0x694c, 0xd1dc, 0x1904, 0x1f3a, 0x6934, 0xa184, 0x0007, 0x0002, + 0x1ed8, 0x1f25, 0x1ed8, 0x1ed8, 0x1ed8, 0x1f0c, 0x1eeb, 0x1eda, + 0x080c, 0x14fa, 0x684c, 0xd0b4, 0x0904, 0x2022, 0x6860, 0x682e, + 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, + 0x6958, 0x0804, 0x1f2d, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, + 0x1d38, 0x684c, 0xd0b4, 0x0904, 0x2022, 0x6860, 0x682e, 0x6816, + 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6804, + 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x21f9, + 0x2005, 0x6832, 0x6958, 0x0450, 0xa18c, 0x00ff, 0xa186, 0x0015, + 0x1548, 0x684c, 0xd0b4, 0x0904, 0x2022, 0x6804, 0x681a, 0xa080, + 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x21f9, 0x2005, 0x6832, + 0x6958, 0xa006, 0x682e, 0x682a, 0x0088, 0x684c, 0xd0b4, 0x0904, + 0x1a61, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a, 0x6834, + 0xa084, 0x000f, 0xa080, 0x21f9, 0x2005, 0x6832, 0x6926, 0x684c, + 0xc0dd, 0x684e, 0x00de, 0x0005, 0x00f6, 0x2079, 0x0020, 0x7804, + 0xd0fc, 0x190c, 0x205e, 0x00e6, 0x00d6, 0x2071, 0xb43a, 0x7000, + 0xa005, 0x1904, 0x1fa2, 0x00c6, 0x7206, 0xa280, 0x0004, 0x205c, + 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x00d6, 0x2068, 0x686c, + 0x7812, 0x6890, 0x00f6, 0x20e1, 0x9040, 0x2079, 0x0200, 0x781a, + 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe, 0x00de, 0x2b68, 0x6824, + 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, + 0x6908, 0x791a, 0x7116, 0x680c, 0x781e, 0x701a, 0xa006, 0x700e, + 0x7012, 0x7004, 0x692c, 0x6814, 0xa106, 0x1120, 0x6928, 0x6810, + 0xa106, 0x0158, 0x0036, 0x0046, 0x6b14, 0x6c10, 0x080c, 0x2219, + 0x004e, 0x003e, 0x0110, 0x00ce, 0x00a8, 0x8aff, 0x1120, 0x00ce, + 0xa085, 0x0001, 0x0078, 0x0126, 0x2091, 0x8000, 0x2079, 0x0020, + 0x2009, 0x0001, 0x0059, 0x0118, 0x2009, 0x0001, 0x0039, 0x012e, + 0x00ce, 0xa006, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0076, 0x0066, + 0x0056, 0x0046, 0x0036, 0x0026, 0x8aff, 0x0904, 0x201b, 0x700c, + 0x7214, 0xa23a, 0x7010, 0x7218, 0xa203, 0x0a04, 0x201a, 0xa705, + 0x0904, 0x201a, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x11a8, 0x00d6, + 0x2805, 0xac68, 0x2900, 0x0002, 0x1ffd, 0x1fe2, 0x1fe2, 0x1ffd, + 0x1ffd, 0x1ff6, 0x1ffd, 0x1fe2, 0x1ffd, 0x1fe7, 0x1fe7, 0x1ffd, + 0x1ffd, 0x1ffd, 0x1fee, 0x1fe7, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, + 0x6d1c, 0x6c20, 0xd99c, 0x0528, 0x00d6, 0x2805, 0xac68, 0x6f08, + 0x6e0c, 0x00f0, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x00c8, 0x6b10, + 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0090, 0x00de, 0x00d6, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1138, 0x00de, 0x080c, + 0x21bb, 0x1904, 0x1fac, 0xa00e, 0x00f0, 0x00de, 0x080c, 0x14fa, + 0x00de, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, + 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, + 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201, 0x7012, 0x080c, + 0x21bb, 0x0008, 0xa006, 0x002e, 0x003e, 0x004e, 0x005e, 0x006e, + 0x007e, 0x0005, 0x080c, 0x14fa, 0x0026, 0x2001, 0x0105, 0x2003, + 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, + 0x2060, 0x00d6, 0x6010, 0x2068, 0x080c, 0x986a, 0x0118, 0x6850, + 0xc0bd, 0x6852, 0x601c, 0xa086, 0x0006, 0x1180, 0x2061, 0x0100, + 0x62c8, 0x2001, 0x00fa, 0x8001, 0x1df0, 0x60c8, 0xa206, 0x1dc0, + 0x60c4, 0x686a, 0x60c8, 0x6866, 0x7004, 0x2060, 0x00de, 0x080c, + 0x955c, 0x20e1, 0x9040, 0x080c, 0x7f2b, 0x2011, 0x0000, 0x080c, + 0x7d5c, 0x080c, 0x6f5b, 0x002e, 0x0804, 0x2118, 0x0126, 0x2091, + 0x2400, 0x0006, 0x0016, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x2079, + 0x0020, 0x2071, 0xb43a, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, + 0x0002, 0xa184, 0x0700, 0x1904, 0x2024, 0x7000, 0x0002, 0x2118, + 0x207b, 0x20eb, 0x2116, 0x8001, 0x7002, 0xd19c, 0x1170, 0x8aff, + 0x05d0, 0x2009, 0x0001, 0x080c, 0x1fa6, 0x0904, 0x2118, 0x2009, + 0x0001, 0x080c, 0x1fa6, 0x0804, 0x2118, 0x7803, 0x0004, 0xd194, + 0x0148, 0x6850, 0xc0fc, 0x6852, 0x8aff, 0x11d8, 0x684c, 0xc0f5, + 0x684e, 0x00b8, 0x0026, 0x0036, 0x6b28, 0x6a2c, 0x7820, 0x686e, + 0xa31a, 0x7824, 0x6872, 0xa213, 0x7830, 0x681e, 0x7834, 0x6822, + 0x6b2a, 0x6a2e, 0x003e, 0x002e, 0x080c, 0x21d1, 0x6850, 0xc0fd, + 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, + 0x0000, 0x0804, 0x2118, 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, + 0x0006, 0x2079, 0x0100, 0x7a14, 0xa284, 0x0184, 0xa085, 0x0012, + 0x7816, 0x0036, 0x2019, 0x1000, 0x8319, 0x090c, 0x14fa, 0x7820, + 0xd0bc, 0x1dd0, 0x003e, 0x79c8, 0x000e, 0xa102, 0x001e, 0x0006, + 0x0016, 0x79c4, 0x000e, 0xa103, 0x78c6, 0x000e, 0x78ca, 0xa284, + 0x0184, 0xa085, 0x0012, 0x7816, 0x002e, 0x00fe, 0x7803, 0x0008, + 0x7003, 0x0000, 0x0468, 0x8001, 0x7002, 0xd194, 0x0168, 0x7804, + 0xd0fc, 0x1904, 0x206e, 0xd19c, 0x11f8, 0x8aff, 0x0508, 0x2009, + 0x0001, 0x080c, 0x1fa6, 0x00e0, 0x0026, 0x0036, 0x6b28, 0x6a2c, + 0x080c, 0x21d1, 0x00d6, 0x2805, 0xac68, 0x6034, 0xd09c, 0x1128, + 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020, 0x6810, 0xa31a, 0x6814, + 0xa213, 0x00de, 0x0804, 0x209e, 0x0804, 0x209a, 0x080c, 0x14fa, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x001e, 0x000e, 0x012e, 0x0005, + 0x00f6, 0x00e6, 0x2071, 0xb43a, 0x7000, 0xa086, 0x0000, 0x05d0, + 0x2079, 0x0020, 0x0016, 0x2009, 0x0207, 0x210c, 0xd194, 0x0198, + 0x2009, 0x020c, 0x210c, 0xa184, 0x0003, 0x0168, 0x080c, 0xaffa, + 0x2001, 0x0133, 0x2004, 0xa005, 0x090c, 0x14fa, 0x20e1, 0x9040, + 0x2001, 0x020c, 0x2102, 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, + 0x210c, 0xa106, 0x1110, 0x20e1, 0x9040, 0x7804, 0xd0fc, 0x09d8, + 0x080c, 0x205e, 0x7000, 0xa086, 0x0000, 0x19a8, 0x001e, 0x7803, + 0x0004, 0x7804, 0xd0ac, 0x1de8, 0x20e1, 0x9040, 0x7803, 0x0002, + 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x0026, 0x00c6, 0x00d6, + 0x00e6, 0x00f6, 0x2071, 0xb43a, 0x2079, 0x0020, 0x7000, 0xa086, + 0x0000, 0x0540, 0x7004, 0x2060, 0x6010, 0x2068, 0x080c, 0x986a, + 0x0158, 0x6850, 0xc0b5, 0x6852, 0x680c, 0x7a1c, 0xa206, 0x1120, + 0x6808, 0x7a18, 0xa206, 0x01e0, 0x2001, 0x0105, 0x2003, 0x0010, + 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, + 0x080c, 0x955c, 0x20e1, 0x9040, 0x080c, 0x7f2b, 0x2011, 0x0000, + 0x080c, 0x7d5c, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x002e, 0x0005, + 0x6810, 0x6a14, 0xa205, 0x1d00, 0x684c, 0xc0dc, 0x684e, 0x2c10, + 0x080c, 0x1ec4, 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, + 0x7803, 0x0004, 0x7003, 0x0000, 0x2069, 0xb3d9, 0x6833, 0x0000, + 0x683f, 0x0000, 0x08f8, 0x8840, 0x2805, 0xa005, 0x1170, 0x6004, + 0xa005, 0x0168, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, + 0x21f9, 0x2045, 0x88ff, 0x090c, 0x14fa, 0x8a51, 0x0005, 0x2050, + 0x0005, 0x8a50, 0x8841, 0x2805, 0xa005, 0x1190, 0x2c00, 0xad06, + 0x0120, 0x6000, 0xa005, 0x1108, 0x2d00, 0x2060, 0x681a, 0x6034, + 0xa084, 0x000f, 0xa080, 0x2209, 0x2045, 0x88ff, 0x090c, 0x14fa, + 0x0005, 0x0000, 0x0011, 0x0015, 0x0019, 0x001d, 0x0021, 0x0025, + 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, 0x0021, 0x0027, 0x0000, + 0x0000, 0x0000, 0x21ee, 0x21ea, 0x0000, 0x0000, 0x21f8, 0x0000, + 0x21ee, 0x0000, 0x21f5, 0x21f2, 0x0000, 0x0000, 0x0000, 0x21f8, + 0x21f5, 0x0000, 0x21f0, 0x21f0, 0x0000, 0x0000, 0x21f8, 0x0000, + 0x21f0, 0x0000, 0x21f6, 0x21f6, 0x0000, 0x0000, 0x0000, 0x21f8, + 0x21f6, 0x00a6, 0x0096, 0x0086, 0x6b2e, 0x6c2a, 0x6858, 0xa055, + 0x0904, 0x22aa, 0x2d60, 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x21f9, + 0xa986, 0x0007, 0x0130, 0xa986, 0x000e, 0x0118, 0xa986, 0x000f, + 0x1120, 0x605c, 0xa422, 0x6060, 0xa31a, 0x2805, 0xa045, 0x1140, + 0x0310, 0x0804, 0x22aa, 0x6004, 0xa065, 0x0904, 0x22aa, 0x0c18, + 0x2805, 0xa005, 0x01a8, 0xac68, 0xd99c, 0x1128, 0x6808, 0xa422, + 0x680c, 0xa31b, 0x0020, 0x6810, 0xa422, 0x6814, 0xa31b, 0x0620, + 0x2300, 0xa405, 0x0150, 0x8a51, 0x0904, 0x22aa, 0x8840, 0x0c40, + 0x6004, 0xa065, 0x0904, 0x22aa, 0x0830, 0x8a51, 0x0904, 0x22aa, + 0x8840, 0x2805, 0xa005, 0x1158, 0x6004, 0xa065, 0x0904, 0x22aa, + 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x21f9, 0x2805, 0x2040, 0x2b68, + 0x6850, 0xc0fc, 0x6852, 0x0458, 0x8422, 0x8420, 0x831a, 0xa399, + 0x0000, 0x00d6, 0x2b68, 0x6c6e, 0x6b72, 0x00de, 0xd99c, 0x1168, + 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x0a0c, 0x14fa, + 0x6800, 0xa420, 0x6804, 0xa319, 0x0060, 0x6910, 0x2400, 0xa122, + 0x6914, 0x2300, 0xa11b, 0x0a0c, 0x14fa, 0x6800, 0xa420, 0x6804, + 0xa319, 0x2b68, 0x6c1e, 0x6b22, 0x6850, 0xc0fd, 0x6852, 0x2c00, + 0x681a, 0x2800, 0x6832, 0x2a00, 0x6826, 0x000e, 0x000e, 0x000e, + 0xa006, 0x0028, 0x008e, 0x009e, 0x00ae, 0xa085, 0x0001, 0x0005, + 0x2001, 0x0005, 0x2004, 0xa084, 0x0007, 0x0002, 0x22be, 0x22bf, + 0x22c2, 0x22c5, 0x22ca, 0x22cd, 0x22d2, 0x22d7, 0x0005, 0x080c, + 0x205e, 0x0005, 0x080c, 0x1a86, 0x0005, 0x080c, 0x1a86, 0x080c, + 0x205e, 0x0005, 0x080c, 0x16fc, 0x0005, 0x080c, 0x205e, 0x080c, + 0x16fc, 0x0005, 0x080c, 0x1a86, 0x080c, 0x16fc, 0x0005, 0x080c, + 0x1a86, 0x080c, 0x205e, 0x080c, 0x16fc, 0x0005, 0x0126, 0x2091, + 0x2600, 0x2079, 0x0200, 0x2071, 0xb680, 0x2069, 0xb100, 0x2009, + 0x0004, 0x7912, 0x7817, 0x0004, 0x080c, 0x26d1, 0x781b, 0x0002, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a9, 0x0080, 0x782f, 0x0000, + 0x1f04, 0x22f6, 0x20e1, 0x9080, 0x783b, 0x001f, 0x20e1, 0x8700, + 0x012e, 0x0005, 0x0126, 0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c, + 0x23b5, 0xa084, 0x0007, 0x0002, 0x2326, 0x2314, 0x2317, 0x231a, + 0x231f, 0x2321, 0x2323, 0x2325, 0x080c, 0x619d, 0x0078, 0x080c, + 0x61dc, 0x0060, 0x080c, 0x619d, 0x080c, 0x61dc, 0x0038, 0x0041, + 0x0028, 0x0031, 0x0018, 0x0021, 0x0008, 0x0011, 0x012e, 0x0005, + 0x0006, 0x0016, 0x0026, 0x080c, 0xaffa, 0x7930, 0xa184, 0x0003, + 0x0170, 0x2001, 0xb3e8, 0x2004, 0xa005, 0x0130, 0x2001, 0x0133, + 0x2004, 0xa005, 0x090c, 0x14fa, 0x20e1, 0x9040, 0x04a0, 0xa184, + 0x0030, 0x01e0, 0x6a00, 0xa286, 0x0003, 0x1108, 0x00a0, 0x080c, + 0x58d5, 0x1178, 0x2001, 0xb39f, 0x2003, 0x0001, 0x2001, 0xb100, + 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5919, 0x080c, 0x5816, + 0x0010, 0x080c, 0x4992, 0x20e1, 0x9010, 0x00a8, 0xa184, 0x00c0, + 0x0168, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xb419, 0x080c, + 0x1d48, 0x005e, 0x004e, 0x003e, 0x00ee, 0x0028, 0xa184, 0x0300, + 0x0110, 0x20e1, 0x9020, 0x7932, 0x002e, 0x001e, 0x000e, 0x0005, + 0x0016, 0x00e6, 0x00f6, 0x2071, 0xb100, 0x7128, 0x2001, 0xb391, + 0x2102, 0x2001, 0xb399, 0x2102, 0xa182, 0x0211, 0x1218, 0x2009, + 0x0008, 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, + 0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, + 0x1218, 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, + 0x0004, 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, + 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x080c, + 0x26d1, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x7938, 0x080c, 0x14fa, + 0x0126, 0x2091, 0x2800, 0x2061, 0x0100, 0x2071, 0xb100, 0x6024, + 0x6026, 0x6053, 0x0030, 0x080c, 0x2710, 0x6050, 0xa084, 0xfe7f, + 0x6052, 0x2009, 0x00ef, 0x6132, 0x6136, 0x080c, 0x2720, 0x60e7, + 0x0000, 0x61ea, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, + 0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x0e9f, 0x601b, 0x001e, + 0x600f, 0x00ff, 0x2001, 0xb38d, 0x2003, 0x00ff, 0x602b, 0x002f, + 0x012e, 0x0005, 0x2001, 0xb131, 0x2003, 0x0000, 0x2001, 0xb130, + 0x2003, 0x0001, 0x0005, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, + 0x0026, 0x6124, 0xa184, 0x1e2c, 0x1118, 0xa184, 0x0007, 0x002a, + 0xa195, 0x0004, 0xa284, 0x0007, 0x0002, 0x2427, 0x240d, 0x2410, + 0x2413, 0x2418, 0x241a, 0x241e, 0x2422, 0x080c, 0x68e7, 0x00b8, + 0x080c, 0x69c2, 0x00a0, 0x080c, 0x69c2, 0x080c, 0x68e7, 0x0078, + 0x0099, 0x0068, 0x080c, 0x68e7, 0x0079, 0x0048, 0x080c, 0x69c2, + 0x0059, 0x0028, 0x080c, 0x69c2, 0x080c, 0x68e7, 0x0029, 0x002e, + 0x001e, 0x000e, 0x012e, 0x0005, 0x6124, 0xd19c, 0x1904, 0x263f, + 0x080c, 0x58d5, 0x0578, 0x7000, 0xa086, 0x0003, 0x0198, 0x6024, + 0xa084, 0x1800, 0x0178, 0x080c, 0x58fb, 0x0118, 0x080c, 0x58e7, + 0x1148, 0x6027, 0x0020, 0x6043, 0x0000, 0x2001, 0xb39e, 0x2003, + 0xaaaa, 0x0458, 0x080c, 0x58fb, 0x15d0, 0x6024, 0xa084, 0x1800, + 0x1108, 0x04a8, 0x2001, 0xb39e, 0x2003, 0xaaaa, 0x2001, 0xb39f, + 0x2003, 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0x080c, 0x5816, + 0x0804, 0x263f, 0xd1ac, 0x1518, 0x6024, 0xd0dc, 0x1170, 0xd0e4, + 0x1188, 0xd0d4, 0x11a0, 0xd0cc, 0x0130, 0x7088, 0xa086, 0x0028, + 0x1110, 0x080c, 0x5a64, 0x0804, 0x263f, 0x2001, 0xb39f, 0x2003, + 0x0000, 0x0048, 0x2001, 0xb39f, 0x2003, 0x0002, 0x0020, 0x080c, + 0x59d7, 0x0804, 0x263f, 0x080c, 0x5b04, 0x0804, 0x263f, 0xd1ac, + 0x0904, 0x2587, 0x080c, 0x58d5, 0x11d8, 0x6027, 0x0020, 0x0006, + 0x0026, 0x0036, 0x080c, 0x58f1, 0x1170, 0x2001, 0xb39f, 0x2003, + 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0x080c, 0x5816, 0x003e, + 0x002e, 0x000e, 0x0005, 0x003e, 0x002e, 0x000e, 0x080c, 0x58ac, + 0x0016, 0x0046, 0x00c6, 0x644c, 0xa486, 0xf0f0, 0x1138, 0x2061, + 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74ca, 0xa48c, + 0xff00, 0x7034, 0xd084, 0x0178, 0xa186, 0xf800, 0x1160, 0x7038, + 0xd084, 0x1148, 0xc085, 0x703a, 0x0036, 0x2418, 0x2011, 0x8016, + 0x080c, 0x3d5b, 0x003e, 0xa196, 0xff00, 0x05b8, 0x7050, 0xa084, + 0x00ff, 0x810f, 0xa116, 0x0588, 0x7130, 0xd184, 0x1570, 0x2011, + 0xb153, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011, 0xb153, + 0x2214, 0xd2ac, 0x1510, 0x6240, 0xa294, 0x0010, 0x0130, 0x6248, + 0xa294, 0xff00, 0xa296, 0xff00, 0x01c0, 0x7030, 0xd08c, 0x0904, + 0x2552, 0x7034, 0xd08c, 0x1140, 0x2001, 0xb10c, 0x200c, 0xd1ac, + 0x1904, 0x2552, 0xc1ad, 0x2102, 0x0036, 0x73c8, 0x2011, 0x8013, + 0x080c, 0x3d5b, 0x003e, 0x0804, 0x2552, 0x7034, 0xd08c, 0x1140, + 0x2001, 0xb10c, 0x200c, 0xd1ac, 0x1904, 0x2552, 0xc1ad, 0x2102, + 0x0036, 0x73c8, 0x2011, 0x8013, 0x080c, 0x3d5b, 0x003e, 0x7130, + 0xc185, 0x7132, 0x2011, 0xb153, 0x220c, 0xd1a4, 0x01d0, 0x0016, + 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x688d, 0x2019, 0x000e, + 0x080c, 0xac2b, 0xa484, 0x00ff, 0xa080, 0x2c8c, 0x200d, 0xa18c, + 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x080c, 0xacae, + 0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009, 0x0000, 0x2019, 0x0004, + 0x080c, 0x2b46, 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x080c, 0x4e21, 0x1110, 0x080c, 0x4a80, 0x8108, 0x1f04, + 0x2549, 0x015e, 0x00ce, 0x004e, 0x2011, 0x0003, 0x080c, 0x7d52, + 0x2011, 0x0002, 0x080c, 0x7d5c, 0x080c, 0x7c41, 0x080c, 0x67b6, + 0x0036, 0x2019, 0x0000, 0x080c, 0x7cc4, 0x003e, 0x60e3, 0x0000, + 0x001e, 0x2001, 0xb100, 0x2014, 0xa296, 0x0004, 0x1128, 0xd19c, + 0x1118, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xb122, + 0x2003, 0x0000, 0x6027, 0x0020, 0x080c, 0x58fb, 0x1140, 0x0016, + 0x2009, 0x07d0, 0x2011, 0x57f7, 0x080c, 0x67c8, 0x001e, 0xd194, + 0x0904, 0x263f, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x25f0, 0x080c, + 0x67b6, 0x080c, 0x7a8c, 0x6027, 0x0004, 0x00f6, 0x2019, 0xb3e2, + 0x2304, 0xa07d, 0x0570, 0x7804, 0xa086, 0x0032, 0x1550, 0x00d6, + 0x00c6, 0x00e6, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, + 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0, + 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, 0x628a, + 0x080c, 0x6dc1, 0x080c, 0x6e9e, 0x7810, 0x2070, 0x7037, 0x0103, + 0x2f60, 0x080c, 0x82eb, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, + 0x0005, 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, + 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, + 0xb3d9, 0x6028, 0xa09a, 0x00c8, 0x1238, 0x8000, 0x602a, 0x00ce, + 0x080c, 0x7a7f, 0x0804, 0x263e, 0x2019, 0xb3e2, 0x2304, 0xa065, + 0x0120, 0x2009, 0x0027, 0x080c, 0x831a, 0x00ce, 0x0804, 0x263e, + 0xd2bc, 0x0904, 0x263e, 0x080c, 0x67c3, 0x6014, 0xa084, 0x0184, + 0xa085, 0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, 0x0140, + 0x6804, 0xa084, 0x4000, 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, + 0x00de, 0x00c6, 0x2061, 0xb3d9, 0x6044, 0xa09a, 0x00c8, 0x12f0, + 0x8000, 0x6046, 0x603c, 0x00ce, 0xa005, 0x0540, 0x2009, 0x07d0, + 0x080c, 0x67bb, 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x1138, + 0x6114, 0xa18c, 0x0184, 0xa18d, 0x0012, 0x6116, 0x00b8, 0x6114, + 0xa18c, 0x0184, 0xa18d, 0x0016, 0x6116, 0x0080, 0x0036, 0x2019, + 0x0001, 0x080c, 0x7cc4, 0x003e, 0x2019, 0xb3e8, 0x2304, 0xa065, + 0x0120, 0x2009, 0x004f, 0x080c, 0x831a, 0x00ce, 0x001e, 0xd19c, + 0x0904, 0x269a, 0x7034, 0xd0ac, 0x1560, 0x0016, 0x0156, 0x6027, + 0x0008, 0x602f, 0x0020, 0x20a9, 0x0006, 0x1d04, 0x264d, 0x2091, + 0x6000, 0x1f04, 0x264d, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400, + 0x6052, 0x20a9, 0x0366, 0x1d04, 0x265b, 0x2091, 0x6000, 0x6020, + 0xd09c, 0x1130, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0490, + 0x080c, 0x27e0, 0x1f04, 0x265b, 0x015e, 0x6152, 0x001e, 0x6027, + 0x0008, 0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, + 0x7d52, 0x2011, 0x0002, 0x080c, 0x7d5c, 0x080c, 0x7c41, 0x080c, + 0x67b6, 0x0036, 0x2019, 0x0000, 0x080c, 0x7cc4, 0x003e, 0x60e3, + 0x0000, 0x080c, 0xafd9, 0x080c, 0xaff4, 0xa085, 0x0001, 0x080c, + 0x5919, 0x2001, 0xb100, 0x2003, 0x0004, 0x6027, 0x0008, 0x080c, + 0x12d0, 0x001e, 0xa18c, 0xffd0, 0x6126, 0x0005, 0x0006, 0x0016, + 0x0026, 0x00e6, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2071, 0xb100, + 0x71c0, 0x70c2, 0xa116, 0x01f0, 0x81ff, 0x0128, 0x2011, 0x8011, + 0x080c, 0x3d5b, 0x00b8, 0x2011, 0x8012, 0x080c, 0x3d5b, 0x2001, + 0xb172, 0x2004, 0xd0fc, 0x1170, 0x0036, 0x00c6, 0x080c, 0x276b, + 0x2061, 0x0100, 0x2019, 0x0028, 0x2009, 0x0000, 0x080c, 0x2b46, + 0x00ce, 0x003e, 0x012e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, + 0x0005, 0x00c6, 0x00f6, 0x0006, 0x0026, 0x2061, 0x0100, 0xa190, + 0x26e4, 0x2205, 0x60f2, 0x2011, 0x26f1, 0x2205, 0x60ee, 0x002e, + 0x000e, 0x00fe, 0x00ce, 0x0005, 0x0840, 0x0840, 0x0840, 0x0580, + 0x0420, 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, + 0x01a8, 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, + 0x00ff, 0x2130, 0xa094, 0xff00, 0x1110, 0x81ff, 0x0118, 0x080c, + 0x646d, 0x0038, 0xa080, 0x2c8c, 0x200d, 0xa18c, 0xff00, 0x810f, + 0xa006, 0x0005, 0xa080, 0x2c8c, 0x200d, 0xa18c, 0x00ff, 0x0005, + 0x00d6, 0x2069, 0x0140, 0x2001, 0xb114, 0x2003, 0x00ef, 0x20a9, + 0x0010, 0xa006, 0x6852, 0x6856, 0x1f04, 0x271b, 0x00de, 0x0005, + 0x0006, 0x00d6, 0x0026, 0x2069, 0x0140, 0x2001, 0xb114, 0x2102, + 0x8114, 0x8214, 0x8214, 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, + 0xa006, 0x82ff, 0x1128, 0xa184, 0x000f, 0xa080, 0xb008, 0x2005, + 0x6856, 0x8211, 0x1f04, 0x2730, 0x002e, 0x00de, 0x000e, 0x0005, + 0x00c6, 0x2061, 0xb100, 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, + 0x6032, 0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, + 0x2069, 0x0140, 0x6980, 0xa116, 0x0180, 0xa112, 0x1230, 0x8212, + 0x8210, 0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, + 0x680e, 0x1f04, 0x2760, 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, + 0x00de, 0x015e, 0x0005, 0x2001, 0xb153, 0x2004, 0xd0c4, 0x0150, + 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, + 0xacae, 0x004e, 0x0005, 0x00f6, 0x0016, 0x0026, 0x2079, 0x0140, + 0x78c4, 0xd0dc, 0x0548, 0xa084, 0x0700, 0xa08e, 0x0300, 0x1520, + 0x2011, 0x0000, 0x2009, 0x0002, 0x2300, 0xa080, 0x0020, 0x2018, + 0x2300, 0x080c, 0x68b3, 0x2011, 0x0030, 0x2200, 0x8007, 0xa085, + 0x004c, 0x78c2, 0x2009, 0x0204, 0x210c, 0x2200, 0xa100, 0x2009, + 0x0138, 0x200a, 0x080c, 0x58d5, 0x1118, 0x2009, 0xb38f, 0x200a, + 0x002e, 0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126, + 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x2001, 0x0170, 0x200c, + 0x8000, 0x2014, 0xa184, 0x0003, 0x0110, 0x0804, 0x1a84, 0x002e, + 0x001e, 0x000e, 0x012e, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004, + 0xa082, 0x0005, 0x000e, 0x0268, 0x2001, 0x0170, 0x200c, 0xa18c, + 0x00ff, 0xa18e, 0x004c, 0x1128, 0x200c, 0xa18c, 0xff00, 0x810f, + 0x0010, 0x2009, 0x0000, 0x2001, 0x0204, 0x2004, 0xa108, 0x0005, + 0x0006, 0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, + 0xd08c, 0x1110, 0x1f04, 0x27e7, 0x00fe, 0x015e, 0x000e, 0x0005, + 0x0016, 0x00c6, 0x0006, 0x2061, 0x0100, 0x6030, 0x0006, 0x6048, + 0x0006, 0x60e4, 0x0006, 0x60e8, 0x0006, 0x6050, 0x0006, 0x60f0, + 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, + 0x0006, 0x60e0, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, 0xe000, + 0xe000, 0xe000, 0xe000, 0x602f, 0x0040, 0x602f, 0x0000, 0x000e, + 0x60e2, 0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, + 0x60ee, 0x000e, 0x60f2, 0x000e, 0x6052, 0x000e, 0x60ea, 0x000e, + 0x60e6, 0x000e, 0x604a, 0x000e, 0x6032, 0x6036, 0x2008, 0x080c, + 0x2720, 0x000e, 0x00ce, 0x001e, 0x0005, 0x2009, 0x0171, 0x2104, + 0xd0dc, 0x0140, 0x2009, 0x0170, 0x2104, 0x200b, 0x0080, 0xe000, + 0xe000, 0x200a, 0x0005, 0x28d3, 0x28d7, 0x28db, 0x28e1, 0x28e7, + 0x28ed, 0x28f3, 0x28fb, 0x2903, 0x2909, 0x290f, 0x2917, 0x291f, + 0x2927, 0x292f, 0x2939, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, + 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, + 0x2943, 0x2943, 0x2943, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2945, 0x2945, 0x294b, 0x294b, 0x2952, + 0x2952, 0x2959, 0x2959, 0x2962, 0x2962, 0x2969, 0x2969, 0x2972, + 0x2972, 0x297b, 0x297b, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, + 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, + 0x2943, 0x2943, 0x2943, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, 0x2986, + 0x2986, 0x2986, 0x2986, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, + 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, 0x2943, + 0x2943, 0x2943, 0x2943, 0x0106, 0x0006, 0x0804, 0x298e, 0x0106, + 0x0006, 0x0804, 0x298e, 0x0106, 0x0006, 0x080c, 0x23f3, 0x0804, + 0x298e, 0x0106, 0x0006, 0x080c, 0x23f3, 0x0804, 0x298e, 0x0106, + 0x0006, 0x080c, 0x22b0, 0x0804, 0x298e, 0x0106, 0x0006, 0x080c, + 0x22b0, 0x0804, 0x298e, 0x0106, 0x0006, 0x080c, 0x23f3, 0x080c, + 0x22b0, 0x0804, 0x298e, 0x0106, 0x0006, 0x080c, 0x23f3, 0x080c, + 0x22b0, 0x0804, 0x298e, 0x0106, 0x0006, 0x080c, 0x2302, 0x0804, + 0x298e, 0x0106, 0x0006, 0x080c, 0x2302, 0x0804, 0x298e, 0x0106, + 0x0006, 0x080c, 0x23f3, 0x080c, 0x2302, 0x0804, 0x298e, 0x0106, + 0x0006, 0x080c, 0x23f3, 0x080c, 0x2302, 0x0804, 0x298e, 0x0106, + 0x0006, 0x080c, 0x22b0, 0x080c, 0x2302, 0x0804, 0x298e, 0x0106, + 0x0006, 0x080c, 0x22b0, 0x080c, 0x2302, 0x0804, 0x298e, 0x0106, + 0x0006, 0x080c, 0x23f3, 0x080c, 0x22b0, 0x080c, 0x2302, 0x0804, + 0x298e, 0x0106, 0x0006, 0x080c, 0x23f3, 0x080c, 0x22b0, 0x080c, + 0x2302, 0x0804, 0x298e, 0xe000, 0x0cf0, 0x0106, 0x0006, 0x080c, + 0x27af, 0x0804, 0x298e, 0x0106, 0x0006, 0x080c, 0x27af, 0x080c, + 0x23f3, 0x04e0, 0x0106, 0x0006, 0x080c, 0x27af, 0x080c, 0x22b0, + 0x04a8, 0x0106, 0x0006, 0x080c, 0x27af, 0x080c, 0x23f3, 0x080c, + 0x22b0, 0x0460, 0x0106, 0x0006, 0x080c, 0x27af, 0x080c, 0x2302, + 0x0428, 0x0106, 0x0006, 0x080c, 0x27af, 0x080c, 0x23f3, 0x080c, + 0x2302, 0x00e0, 0x0106, 0x0006, 0x080c, 0x27af, 0x080c, 0x22b0, + 0x080c, 0x2302, 0x0098, 0x0106, 0x0006, 0x080c, 0x27af, 0x080c, + 0x23f3, 0x080c, 0x22b0, 0x080c, 0x2302, 0x0040, 0x20d1, 0x0000, + 0x20d1, 0x0001, 0x20d1, 0x0000, 0x080c, 0x14fa, 0x000e, 0x010e, + 0x000d, 0x00c6, 0x0026, 0x0046, 0x2021, 0x0000, 0x080c, 0x517b, + 0x1904, 0x2a6e, 0x72d0, 0x2001, 0xb39e, 0x2004, 0xa005, 0x1110, + 0xd29c, 0x0148, 0xd284, 0x1138, 0xd2bc, 0x1904, 0x2a6e, 0x080c, + 0x2a72, 0x0804, 0x2a6e, 0xd2cc, 0x1904, 0x2a6e, 0x080c, 0x58d5, + 0x1120, 0x709b, 0xffff, 0x0804, 0x2a6e, 0xd294, 0x0120, 0x709b, + 0xffff, 0x0804, 0x2a6e, 0x2001, 0xb114, 0x203c, 0x7284, 0xd284, + 0x0904, 0x2a10, 0xd28c, 0x1904, 0x2a10, 0x0036, 0x7398, 0xa38e, + 0xffff, 0x1110, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xb7c0, 0x2c04, + 0xa38c, 0x0001, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, + 0x00ff, 0xa70e, 0x0560, 0xa08e, 0x0000, 0x0548, 0xa08e, 0x00ff, + 0x1150, 0x7230, 0xd284, 0x1538, 0x7284, 0xc28d, 0x7286, 0x709b, + 0xffff, 0x003e, 0x0428, 0x2009, 0x0000, 0x080c, 0x26f6, 0x080c, + 0x4dc5, 0x11b8, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1150, + 0x7030, 0xd08c, 0x0118, 0x6000, 0xd0bc, 0x0120, 0x080c, 0x2a85, + 0x0140, 0x0028, 0x080c, 0x2bb4, 0x080c, 0x2ab3, 0x0110, 0x8318, + 0x0818, 0x739a, 0x0010, 0x709b, 0xffff, 0x003e, 0x0804, 0x2a6e, + 0xa780, 0x2c8c, 0x203d, 0xa7bc, 0xff00, 0x873f, 0x2041, 0x007e, + 0x7098, 0xa096, 0xffff, 0x1120, 0x2009, 0x0000, 0x28a8, 0x0050, + 0xa812, 0x0220, 0x2008, 0xa802, 0x20a8, 0x0020, 0x709b, 0xffff, + 0x0804, 0x2a6e, 0x2700, 0x0156, 0x0016, 0xa106, 0x05a0, 0xc484, + 0x080c, 0x4e21, 0x0120, 0x080c, 0x4dc5, 0x15a8, 0x0008, 0xc485, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1130, 0x7030, 0xd08c, + 0x01e8, 0x6000, 0xd0bc, 0x11d0, 0x7284, 0xd28c, 0x0188, 0x6004, + 0xa084, 0x00ff, 0xa082, 0x0006, 0x02b0, 0xd484, 0x1118, 0x080c, + 0x4de4, 0x0028, 0x080c, 0x2c41, 0x0170, 0x080c, 0x2c6e, 0x0058, + 0x080c, 0x2bb4, 0x080c, 0x2ab3, 0x0170, 0x0028, 0x080c, 0x2c41, + 0x0110, 0x0419, 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x2a2a, + 0x709b, 0xffff, 0x0018, 0x001e, 0x015e, 0x719a, 0x004e, 0x002e, + 0x00ce, 0x0005, 0x00c6, 0x0016, 0x709b, 0x0001, 0x2009, 0x007e, + 0x080c, 0x4dc5, 0x1138, 0x080c, 0x2bb4, 0x04a9, 0x0118, 0x70d0, + 0xc0bd, 0x70d2, 0x001e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, + 0x00c6, 0x2c68, 0x2001, 0xb157, 0x2004, 0xa084, 0x00ff, 0x6842, + 0x080c, 0x9ae4, 0x01d8, 0x2d00, 0x601a, 0x080c, 0x9c35, 0x601f, + 0x0001, 0x2001, 0x0000, 0x080c, 0x4d63, 0x2001, 0x0000, 0x080c, + 0x4d75, 0x0126, 0x2091, 0x8000, 0x7094, 0x8000, 0x7096, 0x012e, + 0x2009, 0x0004, 0x080c, 0x831a, 0xa085, 0x0001, 0x00ce, 0x00de, + 0x007e, 0x001e, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, + 0x2001, 0xb157, 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, 0x9ae4, + 0x0550, 0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802, 0x68a0, 0xa086, + 0x007e, 0x0140, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1110, + 0x080c, 0x2b73, 0x080c, 0x9c35, 0x601f, 0x0001, 0x2001, 0x0000, + 0x080c, 0x4d63, 0x2001, 0x0002, 0x080c, 0x4d75, 0x0126, 0x2091, + 0x8000, 0x7094, 0x8000, 0x7096, 0x012e, 0x2009, 0x0002, 0x080c, + 0x831a, 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, + 0x00c6, 0x0026, 0x2009, 0x0080, 0x080c, 0x4dc5, 0x1120, 0x0031, + 0x0110, 0x70d7, 0xffff, 0x002e, 0x00ce, 0x0005, 0x0016, 0x0076, + 0x00d6, 0x00c6, 0x2c68, 0x080c, 0x8295, 0x01d8, 0x2d00, 0x601a, + 0x080c, 0x9c35, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4d63, + 0x2001, 0x0002, 0x080c, 0x4d75, 0x0126, 0x2091, 0x8000, 0x70d8, + 0x8000, 0x70da, 0x012e, 0x2009, 0x0002, 0x080c, 0x831a, 0xa085, + 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x00d6, + 0x0126, 0x2091, 0x8000, 0x2009, 0x007f, 0x080c, 0x4dc5, 0x1190, + 0x2c68, 0x080c, 0x8295, 0x0170, 0x2d00, 0x601a, 0x6312, 0x601f, + 0x0001, 0x620a, 0x080c, 0x9c35, 0x2009, 0x0022, 0x080c, 0x831a, + 0xa085, 0x0001, 0x012e, 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6, + 0x0066, 0x0036, 0x0026, 0x080c, 0x6b41, 0x080c, 0x6aeb, 0x080c, + 0x8cc4, 0x2130, 0x81ff, 0x0128, 0x20a9, 0x007e, 0x2009, 0x0000, + 0x0020, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4e21, + 0x1120, 0x080c, 0x501c, 0x080c, 0x4a80, 0x001e, 0x8108, 0x1f04, + 0x2b5d, 0x86ff, 0x1110, 0x080c, 0x11d8, 0x002e, 0x003e, 0x006e, + 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, + 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, 0x6b35, + 0x0076, 0x2039, 0x0000, 0x080c, 0x6a6b, 0x2c08, 0x080c, 0xaa51, + 0x007e, 0x001e, 0x2e60, 0x080c, 0x501c, 0x6210, 0x6314, 0x080c, + 0x4a80, 0x6212, 0x6316, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, + 0x0005, 0x00e6, 0x0006, 0x6018, 0xa080, 0x0028, 0x2004, 0xa086, + 0x0080, 0x0150, 0x2071, 0xb100, 0x7094, 0xa005, 0x0110, 0x8001, + 0x7096, 0x000e, 0x00ee, 0x0005, 0x2071, 0xb100, 0x70d8, 0xa005, + 0x0dc0, 0x8001, 0x70da, 0x0ca8, 0x6000, 0xc08c, 0x6002, 0x0005, + 0x00f6, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x0156, 0x2178, + 0x81ff, 0x1118, 0x20a9, 0x0001, 0x0098, 0x2001, 0xb153, 0x2004, + 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, 0x2009, + 0x002d, 0x080c, 0xacae, 0x004e, 0x20a9, 0x00ff, 0x2011, 0x0000, + 0x0026, 0xa28e, 0x007e, 0x0904, 0x2c20, 0xa28e, 0x007f, 0x0904, + 0x2c20, 0xa28e, 0x0080, 0x05e0, 0xa288, 0xb235, 0x210c, 0x81ff, + 0x05b8, 0x8fff, 0x1148, 0x2001, 0xb3bd, 0x0006, 0x2003, 0x0001, + 0x04d9, 0x000e, 0x2003, 0x0000, 0x00c6, 0x2160, 0x2001, 0x0001, + 0x080c, 0x5185, 0x00ce, 0x2019, 0x0029, 0x080c, 0x6b35, 0x0076, + 0x2039, 0x0000, 0x080c, 0x6a6b, 0x00c6, 0x0026, 0x2160, 0x6204, + 0xa294, 0x00ff, 0xa286, 0x0006, 0x1118, 0x6007, 0x0404, 0x0028, + 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x002e, 0x00ce, 0x0016, + 0x2c08, 0x080c, 0xaa51, 0x001e, 0x007e, 0x2160, 0x080c, 0x501c, + 0x002e, 0x8210, 0x1f04, 0x2bd8, 0x015e, 0x001e, 0x002e, 0x003e, + 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016, 0x2001, + 0xb153, 0x2004, 0xd0c4, 0x0148, 0xd0a4, 0x0138, 0xa006, 0x2220, + 0x8427, 0x2009, 0x0029, 0x080c, 0xacae, 0x001e, 0x002e, 0x004e, + 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x7284, 0x82ff, 0x01f8, + 0x2011, 0xb153, 0x2214, 0xd2ac, 0x11d0, 0x2100, 0x080c, 0x270a, + 0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xb7c0, 0x2c04, + 0xd384, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, 0x00ff, + 0xa116, 0x0138, 0xa096, 0x00ff, 0x0110, 0x8318, 0x0c68, 0xa085, + 0x0001, 0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, 0x0016, 0x00c6, + 0x0126, 0x2091, 0x8000, 0xa180, 0xb235, 0x2004, 0xa065, 0x0158, + 0x0016, 0x00c6, 0x2061, 0xb4e4, 0x001e, 0x611a, 0x080c, 0x2b73, + 0x001e, 0x080c, 0x4de4, 0x012e, 0x00ce, 0x001e, 0x0005, 0x2001, + 0xb134, 0x2004, 0xd0cc, 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, + 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, + 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, + 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, + 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, + 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, + 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, + 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, + 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, + 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, + 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, + 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, + 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, + 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, + 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, + 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, + 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, + 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, + 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, + 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, + 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, + 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, + 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, + 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, + 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, + 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, + 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, + 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, 0xb182, 0x7003, 0x0002, + 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, 0x7033, 0xb192, 0x7037, + 0xb192, 0x7007, 0x0001, 0x2061, 0xb1d2, 0x6003, 0x0002, 0x0005, + 0x1004, 0x2db2, 0x0e04, 0x2db2, 0x2071, 0xb182, 0x2b78, 0x7818, + 0xd084, 0x1140, 0x2a60, 0x7820, 0xa08e, 0x0069, 0x1904, 0x2e97, + 0x0804, 0x2e30, 0x0005, 0x2071, 0xb182, 0x7004, 0x0002, 0x2dbb, + 0x2dbc, 0x2dc5, 0x2dd6, 0x0005, 0x1004, 0x2dc4, 0x0e04, 0x2dc4, + 0x2b78, 0x7818, 0xd084, 0x01e8, 0x0005, 0x2b78, 0x2061, 0xb1d2, + 0x6008, 0xa08e, 0x0100, 0x0128, 0xa086, 0x0200, 0x0904, 0x2e91, + 0x0005, 0x7014, 0x2068, 0x2a60, 0x7018, 0x0807, 0x7010, 0x2068, + 0x6834, 0xa086, 0x0103, 0x0108, 0x0005, 0x2a60, 0x2b78, 0x7018, + 0x0807, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x1210, 0x61c0, 0x0042, + 0x2100, 0xa08a, 0x003f, 0x1a04, 0x2e8e, 0x61c0, 0x0804, 0x2e30, + 0x2e72, 0x2e9d, 0x2ea5, 0x2ea9, 0x2eb1, 0x2eb7, 0x2ebb, 0x2ec7, + 0x2eca, 0x2ed4, 0x2ed7, 0x2e8e, 0x2e8e, 0x2e8e, 0x2eda, 0x2e8e, + 0x2ee9, 0x2f00, 0x2f17, 0x2f8e, 0x2f93, 0x2fbc, 0x300d, 0x301e, + 0x303d, 0x3075, 0x307f, 0x308c, 0x309f, 0x30c0, 0x30c9, 0x30ff, + 0x3105, 0x2e8e, 0x312e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, + 0x3135, 0x313f, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, + 0x2e8e, 0x2e8e, 0x3147, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, + 0x3159, 0x3161, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, + 0x0002, 0x318b, 0x31df, 0x323a, 0x324d, 0x2e8e, 0x3267, 0x368e, + 0x40ba, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, + 0x2e8e, 0x2ed4, 0x2ed7, 0x3690, 0x2e8e, 0x369d, 0x414a, 0x41a5, + 0x4209, 0x2e8e, 0x4268, 0x428e, 0x42ad, 0x42df, 0x2e8e, 0x2e8e, + 0x2e8e, 0x36a1, 0x3842, 0x385c, 0x387a, 0x38db, 0x393b, 0x3946, + 0x397e, 0x398d, 0x399c, 0x399f, 0x39c2, 0x3a0c, 0x3a84, 0x3a91, + 0x3b92, 0x3cb2, 0x3cdb, 0x3dd9, 0x3dfb, 0x3e07, 0x3e40, 0x3f04, + 0x2e8e, 0x2e8e, 0x2e8e, 0x2e8e, 0x3f6c, 0x3f87, 0x3ff9, 0x40ab, + 0x713c, 0x0000, 0x2021, 0x4000, 0x080c, 0x3d38, 0x0126, 0x2091, + 0x8000, 0x0e04, 0x2e7e, 0x7818, 0xd084, 0x0110, 0x012e, 0x0cb0, + 0x7c22, 0x7926, 0x7a2a, 0x7b2e, 0x781b, 0x0001, 0x2091, 0x4080, + 0x7007, 0x0001, 0x2091, 0x5000, 0x012e, 0x0005, 0x2021, 0x4001, + 0x0c18, 0x2021, 0x4002, 0x0c00, 0x2021, 0x4003, 0x08e8, 0x2021, + 0x4005, 0x08d0, 0x2021, 0x4006, 0x08b8, 0xa02e, 0x2520, 0x7b28, + 0x7a2c, 0x7824, 0x7930, 0x0804, 0x3d45, 0x7823, 0x0004, 0x7824, + 0x0807, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0804, + 0x3d48, 0x7924, 0x7828, 0x2114, 0x200a, 0x0804, 0x2e72, 0x7924, + 0x2114, 0x0804, 0x2e72, 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9, + 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0804, 0x2e72, 0x7824, + 0x2060, 0x0090, 0x2009, 0x0002, 0x2011, 0x0001, 0x2019, 0x0022, + 0x783b, 0x0017, 0x0804, 0x2e72, 0x7d38, 0x7c3c, 0x0840, 0x7d38, + 0x7c3c, 0x0888, 0x2061, 0x1000, 0xe10c, 0xa006, 0x2c15, 0xa200, + 0x8c60, 0x8109, 0x1dd8, 0x2010, 0xa005, 0x0904, 0x2e72, 0x0804, + 0x2e94, 0x2069, 0xb152, 0x7824, 0x7930, 0xa11a, 0x1a04, 0x2e9a, + 0x8019, 0x0904, 0x2e9a, 0x684a, 0x6942, 0x782c, 0x6852, 0x7828, + 0x6856, 0xa006, 0x685a, 0x685e, 0x080c, 0x5ba6, 0x0804, 0x2e72, + 0x2069, 0xb152, 0x7824, 0x7934, 0xa11a, 0x1a04, 0x2e9a, 0x8019, + 0x0904, 0x2e9a, 0x684e, 0x6946, 0x782c, 0x6862, 0x7828, 0x6866, + 0xa006, 0x686a, 0x686e, 0x080c, 0x523e, 0x0804, 0x2e72, 0xa02e, + 0x2520, 0x81ff, 0x1904, 0x2e97, 0x7924, 0x7b28, 0x7a2c, 0x20a9, + 0x0005, 0x20a1, 0xb189, 0x41a1, 0x080c, 0x3d04, 0x0904, 0x2e97, + 0x2009, 0x0020, 0x080c, 0x3d45, 0x701b, 0x2f2f, 0x0005, 0x6834, + 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0120, 0xa096, 0x0019, + 0x1904, 0x2e97, 0x810f, 0xa18c, 0x00ff, 0x0904, 0x2e97, 0x710e, + 0x700c, 0x8001, 0x0528, 0x700e, 0x080c, 0x3d04, 0x0904, 0x2e97, + 0x2009, 0x0020, 0x2061, 0xb1d2, 0x6224, 0x6328, 0x642c, 0x6530, + 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, + 0x080c, 0x3d45, 0x701b, 0x2f5d, 0x0005, 0x6834, 0xa084, 0x00ff, + 0xa096, 0x0002, 0x0120, 0xa096, 0x000a, 0x1904, 0x2e97, 0x08c0, + 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x4cc1, 0x1128, + 0x7007, 0x0003, 0x701b, 0x2f77, 0x0005, 0x080c, 0x5344, 0x0126, + 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0xb189, 0x530a, 0x2100, + 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0xad80, + 0x000d, 0x2009, 0x0020, 0x012e, 0x0804, 0x3d48, 0x61a8, 0x7824, + 0x60aa, 0x0804, 0x2e72, 0x2091, 0x8000, 0x7823, 0x4000, 0x7827, + 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009, 0x017f, 0x2104, + 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, 0x2061, 0x0200, + 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, 0x2104, 0x783e, + 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2071, 0x0010, + 0x20c1, 0x00f0, 0x0804, 0x0427, 0x81ff, 0x1904, 0x2e97, 0x7924, + 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4e21, 0x1904, 0x2e9a, 0x7e38, + 0xa684, 0x3fff, 0xa082, 0x4000, 0x0210, 0x0804, 0x2e9a, 0x7c28, + 0x7d2c, 0x080c, 0x4fe3, 0xd28c, 0x1118, 0x080c, 0x4f8e, 0x0010, + 0x080c, 0x4fbc, 0x1518, 0x2061, 0xb800, 0x0126, 0x2091, 0x8000, + 0x6000, 0xa086, 0x0000, 0x0148, 0x6010, 0xa06d, 0x0130, 0x683c, + 0xa406, 0x1118, 0x6840, 0xa506, 0x0150, 0x012e, 0xace0, 0x0018, + 0x2001, 0xb116, 0x2004, 0xac02, 0x1a04, 0x2e97, 0x0c30, 0x080c, + 0x955c, 0x012e, 0x0904, 0x2e97, 0x0804, 0x2e72, 0xa00e, 0x2001, + 0x0005, 0x080c, 0x5344, 0x0126, 0x2091, 0x8000, 0x080c, 0x9ae0, + 0x080c, 0x5271, 0x012e, 0x0804, 0x2e72, 0x81ff, 0x1904, 0x2e97, + 0x080c, 0x3d19, 0x0904, 0x2e9a, 0x080c, 0x4ee3, 0x0904, 0x2e97, + 0x080c, 0x4fef, 0x0904, 0x2e97, 0x0804, 0x2e72, 0x81ff, 0x1904, + 0x2e97, 0x080c, 0x3d29, 0x0904, 0x2e9a, 0x080c, 0x505b, 0x0904, + 0x2e97, 0x2019, 0x0005, 0x7924, 0x080c, 0x500a, 0x0904, 0x2e97, + 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2e9a, 0x8003, 0x800b, 0x810b, + 0xa108, 0x080c, 0x674e, 0x0804, 0x2e72, 0x0126, 0x2091, 0x8000, + 0x81ff, 0x0118, 0x2009, 0x0001, 0x0450, 0x2029, 0x00ff, 0x644c, + 0x2400, 0xa506, 0x01f8, 0x2508, 0x080c, 0x4e21, 0x11d8, 0x080c, + 0x505b, 0x1128, 0x2009, 0x0002, 0x62b0, 0x2518, 0x00c0, 0x2019, + 0x0004, 0xa00e, 0x080c, 0x500a, 0x1118, 0x2009, 0x0006, 0x0078, + 0x7824, 0xa08a, 0x1000, 0x1270, 0x8003, 0x800b, 0x810b, 0xa108, + 0x080c, 0x674e, 0x8529, 0x1ae0, 0x012e, 0x0804, 0x2e72, 0x012e, + 0x0804, 0x2e97, 0x012e, 0x0804, 0x2e9a, 0x080c, 0x3d19, 0x0904, + 0x2e9a, 0x080c, 0x4f49, 0x080c, 0x4fe3, 0x0804, 0x2e72, 0x81ff, + 0x1904, 0x2e97, 0x080c, 0x3d19, 0x0904, 0x2e9a, 0x080c, 0x4f3a, + 0x080c, 0x4fe3, 0x0804, 0x2e72, 0x81ff, 0x1904, 0x2e97, 0x080c, + 0x3d19, 0x0904, 0x2e9a, 0x080c, 0x4fbe, 0x0904, 0x2e97, 0x080c, + 0x4d05, 0x080c, 0x4f87, 0x080c, 0x4fe3, 0x0804, 0x2e72, 0x080c, + 0x3d19, 0x0904, 0x2e9a, 0x080c, 0x4ee3, 0x0904, 0x2e97, 0x62a0, + 0x2019, 0x0005, 0x00c6, 0x080c, 0x501c, 0x2061, 0x0000, 0x080c, + 0x6b35, 0x0076, 0x2039, 0x0000, 0x080c, 0x6a6b, 0x2009, 0x0000, + 0x080c, 0xaa51, 0x007e, 0x00ce, 0x080c, 0x4fe3, 0x0804, 0x2e72, + 0x080c, 0x3d19, 0x0904, 0x2e9a, 0x080c, 0x4fe3, 0x2208, 0x0804, + 0x2e72, 0x0156, 0x00d6, 0x00e6, 0x2069, 0xb214, 0x6810, 0x6914, + 0xa10a, 0x1210, 0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019, + 0x0000, 0x20a9, 0x007e, 0x2069, 0xb235, 0x2d04, 0xa075, 0x0130, + 0x704c, 0x0071, 0xa210, 0x7080, 0x0059, 0xa318, 0x8d68, 0x1f04, + 0x30dd, 0x2300, 0xa218, 0x00ee, 0x00de, 0x015e, 0x0804, 0x2e72, + 0x00f6, 0x0016, 0xa07d, 0x0140, 0x2001, 0x0000, 0x8000, 0x2f0c, + 0x81ff, 0x0110, 0x2178, 0x0cd0, 0x001e, 0x00fe, 0x0005, 0x2069, + 0xb214, 0x6910, 0x62ac, 0x0804, 0x2e72, 0x81ff, 0x1904, 0x2e97, + 0x614c, 0xa190, 0x2c8c, 0x2215, 0xa294, 0x00ff, 0x636c, 0x83ff, + 0x0108, 0x6270, 0x67d0, 0xd79c, 0x0118, 0x2031, 0x0001, 0x0090, + 0xd7ac, 0x0118, 0x2031, 0x0003, 0x0068, 0xd7a4, 0x0118, 0x2031, + 0x0002, 0x0040, 0x080c, 0x58d5, 0x1118, 0x2031, 0x0004, 0x0010, + 0x2031, 0x0000, 0x7e3a, 0x7f3e, 0x0804, 0x2e72, 0x613c, 0x6240, + 0x2019, 0xb3b5, 0x231c, 0x0804, 0x2e72, 0x0126, 0x2091, 0x8000, + 0x6134, 0xa006, 0x2010, 0x2018, 0x012e, 0x0804, 0x2e72, 0x080c, + 0x3d29, 0x0904, 0x2e9a, 0x6244, 0x6338, 0x0804, 0x2e72, 0x613c, + 0x6240, 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0xb152, 0x831f, + 0xa305, 0x6816, 0x782c, 0x2069, 0xb3b5, 0x2d1c, 0x206a, 0x0804, + 0x2e72, 0x0126, 0x2091, 0x8000, 0x7824, 0x6036, 0x012e, 0x0804, + 0x2e72, 0x7838, 0xa005, 0x01a8, 0x7828, 0xa025, 0x0904, 0x2e9a, + 0x782c, 0xa02d, 0x0904, 0x2e9a, 0xa00e, 0x080c, 0x4e21, 0x1120, + 0x6244, 0x6338, 0x6446, 0x653a, 0xa186, 0x00ff, 0x0190, 0x8108, + 0x0ca0, 0x080c, 0x3d29, 0x0904, 0x2e9a, 0x7828, 0xa00d, 0x0904, + 0x2e9a, 0x782c, 0xa005, 0x0904, 0x2e9a, 0x6244, 0x6146, 0x6338, + 0x603a, 0x0804, 0x2e72, 0x2001, 0xb100, 0x2004, 0xa086, 0x0003, + 0x1904, 0x2e97, 0x00c6, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, + 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, 0xb114, 0x2004, 0xa085, + 0xff00, 0x0078, 0xa182, 0x007f, 0x16a0, 0xa188, 0x2c8c, 0x210d, + 0xa18c, 0x00ff, 0x2001, 0xb114, 0x2004, 0xa116, 0x0550, 0x810f, + 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x8295, 0x000e, + 0x01e0, 0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x080c, 0x3d04, + 0x01d8, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x701b, 0x3233, 0x2d00, 0x6012, 0x2009, 0x0032, + 0x080c, 0x831a, 0x012e, 0x00ce, 0x0005, 0x012e, 0x00ce, 0x0804, + 0x2e97, 0x00ce, 0x0804, 0x2e9a, 0x080c, 0x82eb, 0x0cb0, 0x2001, + 0xb100, 0x2004, 0xa086, 0x0003, 0x1904, 0x2e97, 0x00c6, 0x2061, + 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x1130, + 0x2001, 0xb114, 0x2004, 0xa085, 0xff00, 0x0078, 0xa182, 0x007f, + 0x16a0, 0xa188, 0x2c8c, 0x210d, 0xa18c, 0x00ff, 0x2001, 0xb114, + 0x2004, 0xa116, 0x0550, 0x810f, 0xa105, 0x0126, 0x2091, 0x8000, + 0x0006, 0x080c, 0x8295, 0x000e, 0x01e0, 0x601a, 0x600b, 0xbc05, + 0x601f, 0x0001, 0x080c, 0x3d04, 0x01d8, 0x6837, 0x0000, 0x7007, + 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x701b, 0x3233, + 0x2d00, 0x6012, 0x2009, 0x0032, 0x080c, 0x831a, 0x012e, 0x00ce, + 0x0005, 0x012e, 0x00ce, 0x0804, 0x2e97, 0x00ce, 0x0804, 0x2e9a, + 0x080c, 0x82eb, 0x0cb0, 0x6830, 0xa086, 0x0100, 0x0904, 0x2e97, + 0x0804, 0x2e72, 0x2061, 0xb464, 0x0126, 0x2091, 0x8000, 0x6000, + 0xd084, 0x0140, 0x6104, 0x6208, 0x2019, 0xb111, 0x231c, 0x012e, + 0x0804, 0x2e72, 0x012e, 0x0804, 0x2e9a, 0x81ff, 0x1904, 0x2e97, + 0x080c, 0x58d5, 0x0904, 0x2e97, 0x0126, 0x2091, 0x8000, 0x6244, + 0x6064, 0xa202, 0x0248, 0xa085, 0x0001, 0x080c, 0x2740, 0x080c, + 0x44a2, 0x012e, 0x0804, 0x2e72, 0x012e, 0x0804, 0x2e9a, 0x0126, + 0x2091, 0x8000, 0x7824, 0xa084, 0x0007, 0x0002, 0x3279, 0x3282, + 0x3289, 0x3276, 0x3276, 0x3276, 0x3276, 0x3276, 0x012e, 0x0804, + 0x2e9a, 0x2009, 0x0114, 0x2104, 0xa085, 0x0800, 0x200a, 0x080c, + 0x33f2, 0x0070, 0x2009, 0x010b, 0x200b, 0x0010, 0x080c, 0x33f2, + 0x0038, 0x81ff, 0x0128, 0x012e, 0x2021, 0x400b, 0x0804, 0x2e74, + 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, + 0x2009, 0x0101, 0x210c, 0x0016, 0x2001, 0x0138, 0x200c, 0x2003, + 0x0001, 0x0016, 0x2001, 0x007a, 0x2034, 0x2001, 0x007b, 0x202c, + 0xa006, 0x2048, 0x2050, 0x2058, 0x080c, 0x3633, 0x080c, 0x359d, + 0xa03e, 0x2720, 0x00f6, 0x00e6, 0x00c6, 0x2d60, 0x2071, 0xb43a, + 0x2079, 0x0020, 0x00d6, 0x2069, 0x0000, 0x6824, 0xd0b4, 0x0140, + 0x2001, 0x007d, 0x2004, 0x783e, 0x2001, 0x007c, 0x2004, 0x783a, + 0x00de, 0x2011, 0x0001, 0x080c, 0x3549, 0x080c, 0x3549, 0x00ce, + 0x00ee, 0x00fe, 0x080c, 0x3498, 0x080c, 0x3571, 0x080c, 0x34ee, + 0x080c, 0x3457, 0x080c, 0x3488, 0x00f6, 0x2079, 0x0100, 0x7824, + 0xd094, 0x0530, 0x7814, 0xa084, 0x0184, 0xa085, 0x0010, 0x7816, + 0x2079, 0x0140, 0x080c, 0x33d0, 0x1110, 0x00fe, 0x0430, 0x7804, + 0xd0dc, 0x0dc0, 0x2079, 0x0100, 0x7827, 0x0086, 0x7814, 0xa084, + 0x0184, 0xa085, 0x0032, 0x7816, 0x080c, 0x33d0, 0x1110, 0x00fe, + 0x00a0, 0x7824, 0xd0bc, 0x0dc0, 0x7827, 0x0080, 0xa026, 0x7c16, + 0x7824, 0xd0ac, 0x0130, 0x8b58, 0x080c, 0x33da, 0x00fe, 0x0804, + 0x339a, 0x00fe, 0x080c, 0x33d0, 0x1150, 0x8948, 0x2001, 0x007a, + 0x2602, 0x2001, 0x007b, 0x2502, 0x080c, 0x33da, 0x0088, 0x87ff, + 0x0140, 0x2001, 0x0201, 0x2004, 0xa005, 0x1904, 0x32d4, 0x8739, + 0x0038, 0x2001, 0xb419, 0x2004, 0xa086, 0x0000, 0x1904, 0x32d4, + 0x2001, 0x0033, 0x2003, 0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, + 0xa605, 0x0904, 0x339a, 0x7824, 0xd0bc, 0x0128, 0x2900, 0xaa05, + 0xab05, 0x1904, 0x339a, 0x6033, 0x000d, 0x2001, 0x0030, 0x2003, + 0x0004, 0x7824, 0xd0ac, 0x1148, 0x2001, 0xb419, 0x2003, 0x0003, + 0x2001, 0x0030, 0x2003, 0x0009, 0x0040, 0x6027, 0x0001, 0x2001, + 0x0075, 0x2004, 0xa005, 0x0108, 0x6026, 0x2c00, 0x601a, 0x20e1, + 0x9040, 0x2d00, 0x681a, 0x6833, 0x000d, 0x7824, 0xd0a4, 0x1180, + 0x6827, 0x0000, 0x00c6, 0x20a9, 0x0004, 0x2061, 0x0020, 0x6003, + 0x0008, 0x2001, 0x0203, 0x2004, 0x1f04, 0x336f, 0x00ce, 0x0040, + 0x6827, 0x0001, 0x2001, 0x0074, 0x2004, 0xa005, 0x0108, 0x6826, + 0x00f6, 0x00c6, 0x2079, 0x0100, 0x2061, 0x0020, 0x7827, 0x0002, + 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8, 0x601a, 0x0006, 0x2001, + 0x0073, 0x2004, 0x601e, 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, + 0x0804, 0x32b2, 0x2061, 0x0100, 0x6027, 0x0002, 0x001e, 0x61e2, + 0x001e, 0x6106, 0x7824, 0xa084, 0x0003, 0xa086, 0x0002, 0x0188, + 0x20e1, 0x9028, 0x6050, 0xa084, 0xf7ef, 0x6052, 0x602f, 0x0000, + 0x602c, 0xc0ac, 0x602e, 0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, + 0x0010, 0x2908, 0x2a10, 0x2b18, 0x2b00, 0xaa05, 0xa905, 0x00fe, + 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, + 0x012e, 0x0804, 0x2e72, 0x012e, 0x2021, 0x400c, 0x0804, 0x2e74, + 0xa085, 0x0001, 0x1d04, 0x33d9, 0x2091, 0x6000, 0x8420, 0xa486, + 0x0064, 0x0005, 0x2001, 0x0105, 0x2003, 0x0010, 0x2001, 0x0030, + 0x2003, 0x0004, 0x2001, 0x0020, 0x2003, 0x0004, 0x2001, 0xb419, + 0x2003, 0x0000, 0x2001, 0xb43a, 0x2003, 0x0000, 0x20e1, 0xf000, + 0xa026, 0x0005, 0x00f6, 0x2079, 0x0100, 0x2001, 0xb114, 0x200c, + 0x7932, 0x7936, 0x080c, 0x2720, 0x7850, 0xa084, 0x0980, 0xa085, + 0x0030, 0x7852, 0x2019, 0x01f4, 0x8319, 0x1df0, 0xa084, 0x0980, + 0x7852, 0x782c, 0xc0ad, 0x782e, 0x20a9, 0x0046, 0x1d04, 0x340e, + 0x2091, 0x6000, 0x1f04, 0x340e, 0x7850, 0xa085, 0x0400, 0x7852, + 0x2001, 0x0009, 0x2004, 0xa084, 0x0003, 0xa086, 0x0001, 0x1118, + 0x782c, 0xc0ac, 0x782e, 0x784b, 0xf7f7, 0x7843, 0x0090, 0x7843, + 0x0010, 0x20a9, 0x000e, 0xe000, 0x1f04, 0x342b, 0x7850, 0xa085, + 0x1400, 0x7852, 0x2019, 0x61a8, 0x7854, 0xe000, 0xe000, 0xd08c, + 0x1110, 0x8319, 0x1dc8, 0x7827, 0x0048, 0x7850, 0xa085, 0x0400, + 0x7852, 0x7843, 0x0040, 0x2019, 0x01f4, 0xe000, 0xe000, 0x8319, + 0x1de0, 0x2001, 0x0140, 0x2003, 0x0100, 0x7827, 0x0020, 0x7843, + 0x0000, 0x2003, 0x0000, 0x7827, 0x0048, 0x00fe, 0x0005, 0x7824, + 0xd0ac, 0x11c8, 0x00f6, 0x00e6, 0x2071, 0xb419, 0x2079, 0x0030, + 0x2001, 0x0201, 0x2004, 0xa005, 0x0160, 0x7000, 0xa086, 0x0000, + 0x1140, 0x0051, 0xd0bc, 0x0108, 0x8738, 0x7003, 0x0003, 0x7803, + 0x0019, 0x00ee, 0x00fe, 0x0005, 0x780c, 0xa08c, 0x0070, 0x0178, + 0x2009, 0x007a, 0x260a, 0x2009, 0x007b, 0x250a, 0xd0b4, 0x0108, + 0x8a50, 0xd0ac, 0x0108, 0x8948, 0xd0a4, 0x0108, 0x8b58, 0x0005, + 0x00f6, 0x2079, 0x0200, 0x781c, 0xd084, 0x0140, 0x20e1, 0x0007, + 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x0ca8, 0x00fe, 0x0005, + 0x00e6, 0x2071, 0x0100, 0x2009, 0xb114, 0x210c, 0x716e, 0x7063, + 0x0100, 0x7166, 0x719e, 0x706b, 0x0000, 0x7073, 0x0809, 0x7077, + 0x0008, 0x7078, 0xa080, 0x0100, 0x707a, 0x7080, 0x8000, 0x7082, + 0x7087, 0xaaaa, 0xa006, 0x708a, 0x708e, 0x707e, 0x70d6, 0x70ab, + 0x0036, 0x70af, 0x95d5, 0x7027, 0x0080, 0x7014, 0xa084, 0x0184, + 0xa085, 0x0032, 0x7016, 0x080c, 0x3571, 0x080c, 0x33d0, 0x1110, + 0x8421, 0x0028, 0x7024, 0xd0bc, 0x0db0, 0x7027, 0x0080, 0x00f6, + 0x00e6, 0x2071, 0xb419, 0x2079, 0x0030, 0x00d6, 0x2069, 0x0000, + 0x6824, 0xd0b4, 0x0120, 0x683c, 0x783e, 0x6838, 0x783a, 0x00de, + 0x2011, 0x0011, 0x080c, 0x3549, 0x2011, 0x0001, 0x080c, 0x3549, + 0x00ee, 0x00fe, 0x7017, 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, + 0x2071, 0xb419, 0x2079, 0x0030, 0x7904, 0xd1fc, 0x0904, 0x3546, + 0x7803, 0x0002, 0xa026, 0xd19c, 0x1904, 0x3542, 0x7000, 0x0002, + 0x3546, 0x3504, 0x3528, 0x3542, 0xd1bc, 0x1150, 0xd1dc, 0x1150, + 0x8001, 0x7002, 0x2011, 0x0001, 0x04e1, 0x05c0, 0x04d1, 0x04b0, + 0x780f, 0x0000, 0x7820, 0x7924, 0x7803, 0x0004, 0x7822, 0x7926, + 0x2001, 0x0201, 0x200c, 0x81ff, 0x0de8, 0x080c, 0x3474, 0x2009, + 0x0001, 0x7808, 0xd0ec, 0x0110, 0x2009, 0x0011, 0x7902, 0x00f0, + 0x8001, 0x7002, 0xa184, 0x0880, 0x1138, 0x7804, 0xd0fc, 0x1940, + 0x2011, 0x0001, 0x00b1, 0x0090, 0x6030, 0xa092, 0x0004, 0xa086, + 0x0009, 0x1120, 0x6000, 0x601a, 0x2011, 0x0025, 0x6232, 0xd1dc, + 0x1988, 0x0870, 0x7803, 0x0004, 0x7003, 0x0000, 0x00ee, 0x00fe, + 0x0005, 0x6024, 0xa005, 0x0520, 0x8001, 0x6026, 0x6018, 0x6130, + 0xa140, 0x2804, 0x7832, 0x8840, 0x2804, 0x7836, 0x8840, 0x2804, + 0x7822, 0x8840, 0x2804, 0x7826, 0x8840, 0x7a02, 0x7000, 0x8000, + 0x7002, 0x6018, 0xa802, 0xa08a, 0x0029, 0x1138, 0x6018, 0xa080, + 0x0001, 0x2004, 0x601a, 0x2001, 0x000d, 0x6032, 0xa085, 0x0001, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2071, 0xb43a, 0x2079, 0x0020, + 0x7904, 0xd1fc, 0x01f0, 0x7803, 0x0002, 0x2d60, 0xa026, 0x7000, + 0x0002, 0x3599, 0x3584, 0x3590, 0x8001, 0x7002, 0xd19c, 0x1188, + 0x2011, 0x0001, 0x080c, 0x3549, 0x0160, 0x080c, 0x3549, 0x0048, + 0x8001, 0x7002, 0x7804, 0xd0fc, 0x1d30, 0x2011, 0x0001, 0x080c, + 0x3549, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00c6, + 0x2061, 0x0200, 0x601b, 0x0004, 0x2061, 0x0100, 0x60cf, 0x0400, + 0x6004, 0xc0ac, 0xa085, 0x0200, 0x6006, 0x2001, 0x0074, 0x2004, + 0xa005, 0x01f8, 0x2038, 0x2001, 0x0076, 0x2024, 0x2001, 0x0077, + 0x201c, 0x080c, 0x3d04, 0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, + 0xa78a, 0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, + 0xa03e, 0x6818, 0xa080, 0x000d, 0x04a1, 0x1d90, 0x2d00, 0x681a, + 0x0088, 0x080c, 0x3d04, 0x6833, 0x000d, 0x2070, 0x6827, 0x0001, + 0x2d00, 0x681a, 0x2001, 0x0076, 0x2004, 0x2072, 0x2001, 0x0077, + 0x2004, 0x7006, 0x2061, 0x0020, 0x2079, 0x0100, 0x6013, 0x0400, + 0x20e1, 0x9040, 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, + 0x601a, 0x0006, 0x2001, 0x0073, 0x2004, 0x700e, 0x601e, 0x78c6, + 0x000e, 0x78ca, 0xa006, 0x603a, 0x603e, 0x00ce, 0x00ee, 0x00fe, + 0x0005, 0x00e6, 0x2071, 0x0010, 0x20a0, 0x2099, 0x0014, 0x7003, + 0x0026, 0x7432, 0x7336, 0xa006, 0x703a, 0x703e, 0x810b, 0x810b, + 0x21a8, 0x810b, 0x7122, 0x7003, 0x0041, 0x7004, 0xd0fc, 0x0de8, + 0x7003, 0x0002, 0x7003, 0x0040, 0x53a5, 0x7430, 0x7334, 0x87ff, + 0x0180, 0x00c6, 0x00d6, 0x2d60, 0x00c6, 0x080c, 0x3d04, 0x00ce, + 0x6018, 0x2070, 0x2d00, 0x7006, 0x601a, 0x00de, 0x00ce, 0xa085, + 0x0001, 0x00ee, 0x0005, 0x00e6, 0x2001, 0x0075, 0x2004, 0xa005, + 0x0508, 0x2038, 0x2001, 0x0078, 0x2024, 0x2001, 0x0079, 0x201c, + 0x080c, 0x3d04, 0x2d60, 0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, + 0xa78a, 0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, + 0xa03e, 0x6818, 0xa080, 0x000d, 0x080c, 0x3601, 0x1d88, 0x2d00, + 0x681a, 0x00e0, 0x080c, 0x3d04, 0x2d60, 0x6033, 0x000d, 0x2070, + 0x6027, 0x0001, 0x2c00, 0x601a, 0x2001, 0x0078, 0x2004, 0x2072, + 0x2001, 0x0079, 0x2004, 0x7006, 0x2001, 0x0072, 0x2004, 0xa084, + 0xfff8, 0x700a, 0x2001, 0x0073, 0x2004, 0x700e, 0x2001, 0x0030, + 0x2003, 0x0004, 0x7824, 0xd0ac, 0x1178, 0x2001, 0x0101, 0x200c, + 0xc1ed, 0x2102, 0x6027, 0x0000, 0x2001, 0xb419, 0x2003, 0x0003, + 0x2001, 0x0030, 0x2003, 0x0009, 0x00ee, 0x0005, 0x0804, 0x2e72, + 0x0126, 0x2091, 0x8000, 0x20a9, 0x0012, 0x2001, 0xb140, 0x20a0, + 0xa006, 0x40a4, 0x012e, 0x0804, 0x2e72, 0x7d38, 0x7c3c, 0x0804, + 0x2f19, 0x080c, 0x3d04, 0x0904, 0x2e97, 0x080c, 0x58d5, 0x0110, + 0x080c, 0x4a65, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x080c, 0x3d45, 0x701b, 0x36b5, 0x0005, 0xade8, 0x000d, 0x6800, + 0xa005, 0x0904, 0x2e9a, 0x6804, 0xd0ac, 0x0118, 0xd0a4, 0x0904, + 0x2e9a, 0xd094, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0138, 0x6200, + 0xa292, 0x0005, 0x0218, 0xa18c, 0xffdf, 0x0010, 0xa18d, 0x0020, + 0x6106, 0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, + 0xa18d, 0x0010, 0x0010, 0xa18c, 0xffef, 0x6106, 0x00ce, 0x2009, + 0x0100, 0x210c, 0xa18a, 0x0002, 0x0268, 0xd084, 0x0158, 0x6a28, + 0xa28a, 0x007f, 0x1a04, 0x2e9a, 0xa288, 0x2c8c, 0x210d, 0xa18c, + 0x00ff, 0x6156, 0xd0dc, 0x0130, 0x6828, 0xa08a, 0x007f, 0x1a04, + 0x2e9a, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0a04, 0x2e9a, 0xa08a, + 0x0841, 0x1a04, 0x2e9a, 0xa084, 0x0007, 0x1904, 0x2e9a, 0x680c, + 0xa005, 0x0904, 0x2e9a, 0x6810, 0xa005, 0x0904, 0x2e9a, 0x6848, + 0x6940, 0xa10a, 0x1a04, 0x2e9a, 0x8001, 0x0904, 0x2e9a, 0x684c, + 0x6944, 0xa10a, 0x1a04, 0x2e9a, 0x8001, 0x0904, 0x2e9a, 0x6804, + 0xd0fc, 0x0560, 0x080c, 0x3d04, 0x0904, 0x2e97, 0x2009, 0x0014, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399, 0x0000, + 0x080c, 0x3d45, 0x701b, 0x3735, 0x0005, 0xade8, 0x000d, 0x20a9, + 0x0014, 0x2d98, 0x2069, 0xb16e, 0x2da0, 0x53a3, 0x7010, 0xa0e8, + 0x000d, 0x2001, 0xb172, 0x200c, 0xd1e4, 0x0140, 0x00c6, 0x2061, + 0x0100, 0x6004, 0xa085, 0x0b00, 0x6006, 0x00ce, 0x2009, 0xb3b0, + 0x200b, 0x0000, 0x2001, 0xb174, 0x2004, 0xd0ac, 0x0158, 0x7824, + 0x200a, 0x2009, 0x017f, 0x200a, 0x3200, 0xa084, 0x003f, 0xa085, + 0x3020, 0x2090, 0x20a9, 0x001c, 0x2d98, 0x2069, 0xb152, 0x2da0, + 0x53a3, 0x6814, 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, + 0x6042, 0x080c, 0x5ba6, 0x080c, 0x51d5, 0x080c, 0x523e, 0x6000, + 0xa086, 0x0000, 0x1904, 0x382c, 0x6808, 0x602a, 0x080c, 0x2378, + 0x0006, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x000e, 0x0268, + 0x2009, 0x0170, 0x200b, 0x0080, 0xe000, 0xe000, 0x200b, 0x0000, + 0x0036, 0x6b08, 0x080c, 0x277b, 0x003e, 0x6818, 0x691c, 0x6a20, + 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, + 0x6322, 0x6c04, 0xd4f4, 0x0148, 0x6830, 0x6934, 0x6a38, 0x6b3c, + 0x8007, 0x810f, 0x8217, 0x831f, 0x0010, 0xa084, 0xf0ff, 0x6006, + 0x610a, 0x620e, 0x6312, 0x8007, 0x810f, 0x8217, 0x831f, 0x20a9, + 0x0004, 0x20a1, 0xb3bf, 0x40a1, 0x080c, 0x67ea, 0x6904, 0xd1fc, + 0x0520, 0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, 0x6b70, 0xd384, + 0x01c8, 0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, 0x080c, 0x6135, + 0x6878, 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a, + 0xa184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, 0x0003, 0x0010, + 0x6003, 0x0001, 0x1f04, 0x37ca, 0x00ce, 0x2069, 0xb152, 0x2001, + 0xb39e, 0x6a80, 0xa294, 0x0030, 0xa28e, 0x0000, 0x0170, 0xa28e, + 0x0010, 0x0118, 0xa28e, 0x0020, 0x0140, 0x2003, 0xaaaa, 0x080c, + 0x27c4, 0x2001, 0xb38f, 0x2102, 0x0008, 0x2102, 0x00c6, 0x2061, + 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x00ce, 0x080c, 0x58d5, + 0x0128, 0x080c, 0x3f5e, 0x0110, 0x080c, 0x2740, 0x60c4, 0xa005, + 0x01b0, 0x6003, 0x0001, 0x2009, 0x3816, 0x00c0, 0x080c, 0x58d5, + 0x1158, 0x2011, 0x57ea, 0x080c, 0x6742, 0x2001, 0xb39f, 0x2003, + 0x0000, 0x080c, 0x5816, 0x0040, 0x080c, 0x4992, 0x0028, 0x6003, + 0x0004, 0x2009, 0x382c, 0x0010, 0x0804, 0x2e72, 0x2001, 0x0100, + 0x2004, 0xa082, 0x0005, 0x0258, 0x2001, 0x0170, 0x2004, 0xa084, + 0x00ff, 0xa086, 0x004c, 0x1118, 0x2091, 0x309d, 0x0817, 0x2091, + 0x301d, 0x0817, 0x6000, 0xa086, 0x0000, 0x0904, 0x2e97, 0x2069, + 0xb152, 0x7830, 0x6842, 0x7834, 0x6846, 0x6804, 0xd0fc, 0x0118, + 0x2009, 0x0030, 0x0010, 0x2009, 0x001c, 0x2d00, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x0804, 0x3d48, 0xa006, 0x080c, 0x2740, 0x81ff, + 0x1904, 0x2e97, 0x080c, 0x58d5, 0x1178, 0x2001, 0xb39f, 0x2003, + 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, + 0x5919, 0x080c, 0x5816, 0x0020, 0x080c, 0x4a65, 0x080c, 0x4992, + 0x0804, 0x2e72, 0x81ff, 0x1904, 0x2e97, 0x080c, 0x58d5, 0x1110, + 0x0804, 0x2e97, 0x6184, 0x81ff, 0x0198, 0x703f, 0x0000, 0x2001, + 0xb7c0, 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0126, + 0x2091, 0x8000, 0x080c, 0x3d48, 0x701b, 0x2e70, 0x012e, 0x0005, + 0x703f, 0x0001, 0x00d6, 0x2069, 0xb7c0, 0x20a9, 0x0040, 0x20a1, + 0xb7c0, 0x2019, 0xffff, 0x43a4, 0x654c, 0xa588, 0x2c8c, 0x210d, + 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100, 0xa506, + 0x01a8, 0x080c, 0x4e21, 0x1190, 0x6014, 0x821c, 0x0238, 0xa398, + 0xb7c0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0038, 0xa398, 0xb7c0, + 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, 0x8210, 0x8108, 0xa182, + 0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, 0x2d0c, 0xa105, 0x206a, + 0x00de, 0x20a9, 0x0040, 0x20a1, 0xb7c0, 0x2099, 0xb7c0, 0x080c, + 0x4a04, 0x0804, 0x3887, 0x080c, 0x3d29, 0x0904, 0x2e9a, 0x00c6, + 0x080c, 0x3d04, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, 0x2e97, + 0x2001, 0xb153, 0x2004, 0xd0b4, 0x0550, 0x7824, 0xa084, 0xff00, + 0xa08e, 0x7e00, 0x0520, 0xa08e, 0x7f00, 0x0508, 0xa08e, 0x8000, + 0x01f0, 0x6000, 0xd08c, 0x11d8, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x0006, 0x11a8, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, + 0x99e8, 0x1120, 0x2009, 0x0003, 0x0804, 0x2e97, 0x7007, 0x0003, + 0x701b, 0x3913, 0x0005, 0x080c, 0x3d29, 0x0904, 0x2e9a, 0x20a9, + 0x002b, 0x2c98, 0xade8, 0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004, + 0xac80, 0x0006, 0x2098, 0xad80, 0x0006, 0x20a0, 0x080c, 0x4a04, + 0x20a9, 0x0004, 0xac80, 0x000a, 0x2098, 0xad80, 0x000a, 0x20a0, + 0x080c, 0x4a04, 0x2d00, 0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0804, 0x3d48, 0x81ff, 0x1904, 0x2e97, 0x080c, 0x3d19, + 0x0904, 0x2e9a, 0x080c, 0x4ff8, 0x0804, 0x2e72, 0x81ff, 0x1904, + 0x2e97, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2e9a, 0x080c, 0x3d29, + 0x0904, 0x2e9a, 0x080c, 0x505b, 0x0904, 0x2e97, 0x2019, 0x0004, + 0xa00e, 0x080c, 0x500a, 0x7924, 0x810f, 0x7a28, 0x0011, 0x0804, + 0x2e72, 0xa186, 0x00ff, 0x0110, 0x0071, 0x0060, 0x2029, 0x007e, + 0x2061, 0xb100, 0x644c, 0x2400, 0xa506, 0x0110, 0x2508, 0x0019, + 0x8529, 0x1ec8, 0x0005, 0x080c, 0x4e21, 0x1138, 0x2200, 0x8003, + 0x800b, 0x810b, 0xa108, 0x080c, 0x674e, 0x0005, 0x81ff, 0x1904, + 0x2e97, 0x080c, 0x3d19, 0x0904, 0x2e9a, 0x080c, 0x4ee3, 0x0904, + 0x2e97, 0x080c, 0x5001, 0x0804, 0x2e72, 0x81ff, 0x1904, 0x2e97, + 0x080c, 0x3d19, 0x0904, 0x2e9a, 0x080c, 0x4ee3, 0x0904, 0x2e97, + 0x080c, 0x4fef, 0x0804, 0x2e72, 0x6100, 0x0804, 0x2e72, 0x080c, + 0x3d29, 0x0904, 0x2e9a, 0x2001, 0xb100, 0x2004, 0xa086, 0x0003, + 0x1904, 0x2e97, 0x00d6, 0xace8, 0x000a, 0x7924, 0xd184, 0x0110, + 0xace8, 0x0006, 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, + 0x6b04, 0x831f, 0x6a00, 0x8217, 0x00de, 0x6100, 0xa18c, 0x0200, + 0x0804, 0x2e72, 0x7824, 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x1a04, + 0x2e97, 0x624c, 0xa294, 0x00ff, 0xa084, 0xff00, 0x8007, 0xa206, + 0x1150, 0x2001, 0xb140, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0804, 0x3d48, 0x81ff, 0x1904, 0x2e97, 0x080c, 0x3d29, + 0x0904, 0x2e9a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1904, + 0x2e97, 0x00c6, 0x080c, 0x3d04, 0x00ce, 0x0904, 0x2e97, 0x6837, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x9994, 0x0904, 0x2e97, + 0x7007, 0x0003, 0x701b, 0x39fd, 0x0005, 0x6830, 0xa086, 0x0100, + 0x0904, 0x2e97, 0xad80, 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x0804, 0x3d48, 0xa006, 0x080c, 0x2740, 0x7824, + 0xa084, 0x00ff, 0xa086, 0x00ff, 0x0118, 0x81ff, 0x1904, 0x2e97, + 0x080c, 0x58d5, 0x0110, 0x080c, 0x4a65, 0x7828, 0xa08a, 0x1000, + 0x1a04, 0x2e9a, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, + 0x0138, 0xa182, 0x007f, 0x1a04, 0x2e9a, 0x2100, 0x080c, 0x270a, + 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2061, 0xb3ec, 0x601b, + 0x0000, 0x601f, 0x0000, 0x080c, 0x58d5, 0x1178, 0x2001, 0xb39f, + 0x2003, 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0xa085, 0x0001, + 0x080c, 0x5919, 0x080c, 0x5816, 0x0430, 0x2011, 0x0003, 0x080c, + 0x7d52, 0x2011, 0x0002, 0x080c, 0x7d5c, 0x080c, 0x7c41, 0x080c, + 0x67b6, 0x0036, 0x2019, 0x0000, 0x080c, 0x7cc4, 0x003e, 0x2061, + 0x0100, 0x2001, 0xb114, 0x2004, 0xa084, 0x00ff, 0x810f, 0xa105, + 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, + 0x49c9, 0x080c, 0x67c8, 0x7924, 0xa18c, 0xff00, 0x810f, 0x080c, + 0x58d5, 0x1110, 0x2009, 0x00ff, 0x7a28, 0x080c, 0x3961, 0x012e, + 0x00ce, 0x002e, 0x0804, 0x2e72, 0x7924, 0xa18c, 0xff00, 0x810f, + 0x00c6, 0x080c, 0x4dc5, 0x2c08, 0x00ce, 0x1904, 0x2e9a, 0x0804, + 0x2e72, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x2e97, 0x60d0, + 0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009, 0x0005, 0x0804, 0x2e97, + 0x080c, 0x3d04, 0x1120, 0x2009, 0x0002, 0x0804, 0x2e97, 0x7924, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3d45, 0x701b, 0x3ab1, + 0x0005, 0x2009, 0x0080, 0x080c, 0x4e21, 0x1130, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x0120, 0x2021, 0x400a, 0x0804, 0x2e74, + 0x00d6, 0xade8, 0x000d, 0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, + 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0904, 0x3b28, 0xa0be, 0x0112, + 0x0904, 0x3b28, 0xa0be, 0x0113, 0x0904, 0x3b28, 0xa0be, 0x0114, + 0x0904, 0x3b28, 0xa0be, 0x0117, 0x0904, 0x3b28, 0xa0be, 0x011a, + 0x0904, 0x3b28, 0xa0be, 0x011c, 0x0904, 0x3b28, 0xa0be, 0x0121, + 0x05b0, 0xa0be, 0x0131, 0x0598, 0xa0be, 0x0171, 0x05c8, 0xa0be, + 0x0173, 0x05b0, 0xa0be, 0x01a1, 0x1120, 0x6830, 0x8007, 0x6832, + 0x04a8, 0xa0be, 0x0212, 0x0540, 0xa0be, 0x0213, 0x0528, 0xa0be, + 0x0214, 0x01b0, 0xa0be, 0x0217, 0x0168, 0xa0be, 0x021a, 0x1120, + 0x6838, 0x8007, 0x683a, 0x00e0, 0xa0be, 0x0300, 0x01c8, 0x00de, + 0x0804, 0x2e9a, 0xad80, 0x0010, 0x20a9, 0x0007, 0x080c, 0x3b6e, + 0xad80, 0x000e, 0x20a9, 0x0001, 0x080c, 0x3b6e, 0x0048, 0xad80, + 0x000c, 0x080c, 0x3b7c, 0x0050, 0xad80, 0x000e, 0x080c, 0x3b7c, + 0xad80, 0x000c, 0x20a9, 0x0001, 0x080c, 0x3b6e, 0x00c6, 0x080c, + 0x3d04, 0x0568, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, 0x6853, + 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, + 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, + 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, + 0x0000, 0x6804, 0x2068, 0x080c, 0x99b0, 0x1120, 0x2009, 0x0003, + 0x0804, 0x2e97, 0x7007, 0x0003, 0x701b, 0x3b65, 0x0005, 0x00ce, + 0x00de, 0x2009, 0x0002, 0x0804, 0x2e97, 0x6820, 0xa086, 0x8001, + 0x1904, 0x2e72, 0x2009, 0x0004, 0x0804, 0x2e97, 0x0016, 0x2008, + 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, + 0x1f04, 0x3b70, 0x001e, 0x0005, 0x0016, 0x00a6, 0x00b6, 0x2008, + 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, + 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x00be, 0x00ae, + 0x001e, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x2e97, + 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, 0x60d0, 0xd0ac, 0x1120, + 0xa182, 0x0080, 0x0a04, 0x2e9a, 0xa182, 0x00ff, 0x1a04, 0x2e9a, + 0x7a2c, 0x7b28, 0x606c, 0xa306, 0x1140, 0x6070, 0xa24e, 0x0904, + 0x2e9a, 0xa9cc, 0xff00, 0x0904, 0x2e9a, 0x00c6, 0x080c, 0x3c52, + 0x2c68, 0x00ce, 0x0538, 0xa0c6, 0x4000, 0x1180, 0x00c6, 0x0006, + 0x2d60, 0x2009, 0x0000, 0x080c, 0x50bc, 0x1108, 0xc185, 0x6000, + 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce, 0x0088, 0xa0c6, 0x4007, + 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, 0x1118, 0x2708, 0x2610, + 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, 0x2001, 0x4006, 0x2020, + 0x0804, 0x2e74, 0x2d00, 0x7022, 0x0016, 0x00b6, 0x00c6, 0x00e6, + 0x2c70, 0x080c, 0x8295, 0x05d8, 0x2d00, 0x601a, 0x080c, 0x9c35, + 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, 0x3d04, 0x00ce, 0x2b70, + 0x1150, 0x080c, 0x82eb, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x2009, + 0x0002, 0x0804, 0x2e97, 0x6837, 0x0000, 0x683b, 0x0000, 0x2d00, + 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, 0xd88c, 0x0108, 0xc0f5, + 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x2b73, 0x012e, 0x601f, + 0x0001, 0x2001, 0x0000, 0x080c, 0x4d63, 0x2001, 0x0002, 0x080c, + 0x4d75, 0x2009, 0x0002, 0x080c, 0x831a, 0xa085, 0x0001, 0x00ee, + 0x00ce, 0x00be, 0x001e, 0x1120, 0x2009, 0x0003, 0x0804, 0x2e97, + 0x7007, 0x0003, 0x701b, 0x3c35, 0x0005, 0x6830, 0xa086, 0x0100, + 0x7020, 0x2060, 0x1138, 0x2009, 0x0004, 0x6204, 0xa294, 0x00ff, + 0x0804, 0x2e97, 0x2009, 0x0000, 0x6838, 0xd0f4, 0x1904, 0x2e72, + 0x080c, 0x50bc, 0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, + 0x0804, 0x2e72, 0x00e6, 0x00d6, 0x2029, 0x0000, 0x2001, 0xb134, + 0x2004, 0xd0ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, + 0xb235, 0x0030, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, 0xb2b5, + 0x2e04, 0xa005, 0x1130, 0x2100, 0xa406, 0x1570, 0x2428, 0xc5fd, + 0x0458, 0x2068, 0x6f10, 0x2700, 0xa306, 0x11b0, 0x6e14, 0x2600, + 0xa206, 0x1190, 0x2400, 0xa106, 0x1160, 0x2d60, 0xd884, 0x0568, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1538, 0x2001, 0x4000, + 0x0428, 0x2001, 0x4007, 0x0410, 0x2400, 0xa106, 0x1168, 0x6e14, + 0x87ff, 0x1138, 0x86ff, 0x09d0, 0x2001, 0xb134, 0x2004, 0xd0ac, + 0x19a8, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04, 0x3c68, + 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001, 0x0030, + 0x080c, 0x4dc5, 0x1dd0, 0x6312, 0x6216, 0xa006, 0xa005, 0x00de, + 0x00ee, 0x0005, 0x81ff, 0x1904, 0x2e97, 0x080c, 0x3d04, 0x0904, + 0x2e97, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7824, 0xa005, + 0x0904, 0x2e9a, 0xa096, 0x00ff, 0x0120, 0xa092, 0x0004, 0x1a04, + 0x2e9a, 0x2010, 0x2d18, 0x080c, 0x2b26, 0x0904, 0x2e97, 0x7007, + 0x0003, 0x701b, 0x3cd4, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, + 0x2e97, 0x0804, 0x2e72, 0x7924, 0xa18c, 0xff00, 0x810f, 0x60d0, + 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2e9a, 0xa182, 0x00ff, + 0x1a04, 0x2e9a, 0x0126, 0x2091, 0x8000, 0x080c, 0x989a, 0x1188, + 0xa190, 0xb235, 0x2204, 0xa065, 0x0160, 0x080c, 0x4a80, 0x2001, + 0xb134, 0x2004, 0xd0ac, 0x0110, 0x6017, 0x0000, 0x012e, 0x0804, + 0x2e72, 0x012e, 0x0804, 0x2e97, 0x080c, 0x15dd, 0x0188, 0xa006, + 0x6802, 0x7010, 0xa005, 0x1120, 0x2d00, 0x7012, 0x7016, 0x0030, + 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80, 0x000d, + 0x0005, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4e21, 0x1130, + 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0208, 0xa066, 0x8cff, + 0x0005, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x080c, 0x4e21, 0x1128, + 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0208, 0xa066, 0x8cff, 0x0005, + 0x0016, 0x7110, 0x81ff, 0x0128, 0x2168, 0x6904, 0x080c, 0x15f4, + 0x0cc8, 0x7112, 0x7116, 0x001e, 0x0005, 0x2031, 0x0001, 0x0010, + 0x2031, 0x0000, 0x2061, 0xb1d2, 0x6606, 0x6112, 0x600e, 0x6226, + 0x632a, 0x642e, 0x6532, 0x2c10, 0x080c, 0x1628, 0x7007, 0x0002, + 0x701b, 0x2e72, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, + 0x0000, 0x2001, 0xb190, 0x2004, 0xa005, 0x1168, 0x0e04, 0x3d73, + 0x7818, 0xd084, 0x1140, 0x7a22, 0x7b26, 0x7c2a, 0x781b, 0x0001, + 0x2091, 0x4080, 0x0408, 0x0016, 0x00c6, 0x00e6, 0x2071, 0xb182, + 0x7138, 0xa182, 0x0010, 0x0218, 0x7030, 0x2060, 0x0078, 0x7030, + 0xa0e0, 0x0004, 0xac82, 0xb1d2, 0x0210, 0x2061, 0xb192, 0x2c00, + 0x7032, 0x81ff, 0x1108, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, + 0x640a, 0x00ee, 0x00ce, 0x001e, 0x012e, 0x00fe, 0x0005, 0x00e6, + 0x2071, 0xb182, 0x7038, 0xa005, 0x0570, 0x0126, 0x2091, 0x8000, + 0x0e04, 0x3dca, 0x00f6, 0x2079, 0x0000, 0x7818, 0xd084, 0x1508, + 0x00c6, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826, 0x6008, + 0x782a, 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, + 0xa005, 0x1130, 0x7033, 0xb192, 0x7037, 0xb192, 0x00ce, 0x0048, + 0xac80, 0x0004, 0xa0fa, 0xb1d2, 0x0210, 0x2001, 0xb192, 0x7036, + 0x00ce, 0x00fe, 0x012e, 0x00ee, 0x0005, 0x0026, 0x2001, 0xb153, + 0x2004, 0xd0c4, 0x0120, 0x2011, 0x8014, 0x080c, 0x3d5b, 0x002e, + 0x0005, 0x81ff, 0x1904, 0x2e97, 0x0126, 0x2091, 0x8000, 0x6030, + 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c, 0x58d5, 0x1178, 0x2001, + 0xb39f, 0x2003, 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0xa085, + 0x0001, 0x080c, 0x5919, 0x080c, 0x5816, 0x0010, 0x080c, 0x4992, + 0x012e, 0x0804, 0x2e72, 0x7824, 0x2008, 0xa18c, 0xfffd, 0x1128, + 0x61dc, 0xa10d, 0x61de, 0x0804, 0x2e72, 0x0804, 0x2e9a, 0x81ff, + 0x1904, 0x2e97, 0x6000, 0xa086, 0x0003, 0x1904, 0x2e97, 0x2001, + 0xb153, 0x2004, 0xd0ac, 0x1904, 0x2e97, 0x080c, 0x3d29, 0x0904, + 0x2e9a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1120, 0x7828, + 0xa005, 0x0904, 0x2e72, 0x00c6, 0x080c, 0x3d04, 0x00ce, 0x0904, + 0x2e97, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x080c, 0x9a79, 0x0904, 0x2e97, 0x7007, 0x0003, 0x701b, 0x3e39, + 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2e97, 0x0804, 0x2e72, + 0x2001, 0xb100, 0x2004, 0xa086, 0x0003, 0x1904, 0x2e97, 0x7f24, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3d04, 0x0904, 0x2e97, + 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, + 0xad80, 0x0005, 0x7026, 0x20a0, 0x080c, 0x4e21, 0x1904, 0x3eb3, + 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0130, 0xa0c4, 0xff00, + 0xa8c6, 0x0600, 0x1904, 0x3eb3, 0x2001, 0xb153, 0x2004, 0xd0ac, + 0x1128, 0x080c, 0x50bc, 0x1110, 0xd79c, 0x05e8, 0xd794, 0x1110, + 0xd784, 0x0158, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, + 0x53a3, 0x080c, 0x3b7c, 0xd794, 0x0148, 0xac80, 0x000a, 0x2098, + 0x3400, 0x20a9, 0x0004, 0x53a3, 0x080c, 0x3b7c, 0x21a2, 0xd794, + 0x01d8, 0xac80, 0x0000, 0x2098, 0x94a0, 0x20a9, 0x0002, 0x53a3, + 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, 0x0004, 0x2098, 0x3400, + 0x20a9, 0x0002, 0x53a3, 0x080c, 0x3b6e, 0xac80, 0x0026, 0x2098, + 0x20a9, 0x0002, 0x53a3, 0x0008, 0x94a0, 0xd794, 0x0110, 0xa6b0, + 0x000b, 0xa6b0, 0x0005, 0x8108, 0x2001, 0xb134, 0x2004, 0xd0ac, + 0x0118, 0xa186, 0x0100, 0x0040, 0xd78c, 0x0120, 0xa186, 0x0100, + 0x0170, 0x0018, 0xa186, 0x007e, 0x0150, 0xd794, 0x0118, 0xa686, + 0x0020, 0x0010, 0xa686, 0x0028, 0x0150, 0x0804, 0x3e5c, 0x86ff, + 0x1120, 0x7120, 0x810b, 0x0804, 0x2e72, 0x702f, 0x0001, 0x711e, + 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0xb1d2, 0x6007, 0x0000, + 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, + 0x080c, 0x1628, 0x7007, 0x0002, 0x701b, 0x3eef, 0x0005, 0x702c, + 0xa005, 0x1170, 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, + 0x2061, 0xb1d2, 0x6224, 0x6328, 0x642c, 0x6530, 0x0804, 0x3e5c, + 0x7120, 0x810b, 0x0804, 0x2e72, 0x2029, 0x007e, 0x7924, 0x7a28, + 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, + 0x2e9a, 0xa502, 0x0a04, 0x2e9a, 0xa184, 0x00ff, 0xa0e2, 0x0020, + 0x0a04, 0x2e9a, 0xa502, 0x0a04, 0x2e9a, 0xa284, 0xff00, 0x8007, + 0xa0e2, 0x0020, 0x0a04, 0x2e9a, 0xa502, 0x0a04, 0x2e9a, 0xa284, + 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2e9a, 0xa502, 0x0a04, 0x2e9a, + 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2e9a, 0xa502, + 0x0a04, 0x2e9a, 0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2e9a, + 0xa502, 0x0a04, 0x2e9a, 0xa484, 0xff00, 0x8007, 0xa0e2, 0x0020, + 0x0a04, 0x2e9a, 0xa502, 0x0a04, 0x2e9a, 0xa484, 0x00ff, 0xa0e2, + 0x0020, 0x0a04, 0x2e9a, 0xa502, 0x0a04, 0x2e9a, 0x2061, 0xb3b8, + 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x2e72, 0x0006, 0x2001, + 0xb153, 0x2004, 0xd0cc, 0x000e, 0x0005, 0x0006, 0x2001, 0xb172, + 0x2004, 0xd0bc, 0x000e, 0x0005, 0x6164, 0x7a24, 0x6300, 0x82ff, + 0x1118, 0x7926, 0x0804, 0x2e72, 0x83ff, 0x1904, 0x2e9a, 0x2001, + 0xfff0, 0xa200, 0x1a04, 0x2e9a, 0x2019, 0xffff, 0x6068, 0xa302, + 0xa200, 0x0a04, 0x2e9a, 0x7926, 0x6266, 0x0804, 0x2e72, 0x2001, + 0xb100, 0x2004, 0xa086, 0x0003, 0x1904, 0x2e97, 0x7c28, 0x7d24, + 0x7e38, 0x7f2c, 0x080c, 0x3d04, 0x0904, 0x2e97, 0x2009, 0x0000, + 0x2019, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, 0x0003, + 0x7026, 0x20a0, 0xa1e0, 0xb235, 0x2c64, 0x8cff, 0x01b8, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x0130, 0x6004, 0xa084, 0xff00, + 0xa086, 0x0600, 0x1158, 0x6014, 0x20a2, 0x94a0, 0x6010, 0x8007, + 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, 0x8108, 0xa182, + 0x00ff, 0x0120, 0xa386, 0x002a, 0x0148, 0x08e0, 0x83ff, 0x1120, + 0x7120, 0x810c, 0x0804, 0x2e72, 0x702f, 0x0001, 0x711e, 0x7020, + 0xa300, 0x7022, 0x2061, 0xb1d2, 0x6007, 0x0000, 0x6312, 0x7024, + 0x600e, 0x6426, 0x652a, 0x662e, 0x6732, 0x2c10, 0x080c, 0x1628, + 0x7007, 0x0002, 0x701b, 0x3fe5, 0x0005, 0x702c, 0xa005, 0x1168, + 0x711c, 0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xb1d2, 0x6424, + 0x6528, 0x662c, 0x6730, 0x0804, 0x3fa2, 0x7120, 0x810c, 0x0804, + 0x2e72, 0x81ff, 0x1904, 0x2e97, 0x60d0, 0xd0ac, 0x1118, 0xd09c, + 0x0904, 0x2e97, 0x080c, 0x3d04, 0x0904, 0x2e97, 0x7924, 0x7a2c, + 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3d45, 0x701b, 0x4010, 0x0005, + 0x00d6, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, 0x0148, 0xa0be, + 0x7100, 0x0130, 0xa0be, 0x7200, 0x0118, 0x00de, 0x0804, 0x2e9a, + 0x6820, 0x6924, 0x080c, 0x26f6, 0x1510, 0x080c, 0x4dc5, 0x11f8, + 0x7122, 0x6612, 0x6516, 0x6e18, 0x00c6, 0x080c, 0x3d04, 0x01b8, + 0x080c, 0x3d04, 0x01a0, 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, 0x99cc, + 0x0904, 0x2e97, 0x7007, 0x0003, 0x701b, 0x404a, 0x0005, 0x00de, + 0x0804, 0x2e97, 0x7120, 0x080c, 0x2c6e, 0x6820, 0xa086, 0x8001, + 0x0904, 0x2e97, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002, 0x0006, + 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4a04, 0x000e, 0xade8, + 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0xb1d2, 0x6007, + 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x1108, 0x0018, 0xa7c6, + 0x7100, 0x1140, 0xa6c2, 0x0004, 0x0a04, 0x2e9a, 0x2009, 0x0004, + 0x0804, 0x3d48, 0xa7c6, 0x7200, 0x1904, 0x2e9a, 0xa6c2, 0x0054, + 0x0a04, 0x2e9a, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, 0x642e, + 0x6532, 0x2c10, 0x080c, 0x1628, 0x7007, 0x0002, 0x701b, 0x4091, + 0x0005, 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, 0xa080, + 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4a04, + 0x000e, 0x2009, 0x002a, 0x2061, 0xb1d2, 0x6224, 0x6328, 0x642c, + 0x6530, 0x0804, 0x3d48, 0x81ff, 0x1904, 0x2e97, 0x080c, 0x3d19, + 0x0904, 0x2e9a, 0x080c, 0x4ee3, 0x0904, 0x2e97, 0x080c, 0x5013, + 0x0804, 0x2e72, 0x7824, 0xd084, 0x0904, 0x38db, 0x080c, 0x3d29, + 0x0904, 0x2e9a, 0x00c6, 0x080c, 0x3d04, 0x00ce, 0x1120, 0x2009, + 0x0002, 0x0804, 0x2e97, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0128, 0xa08e, 0x0004, 0x0110, 0xa08e, 0x0005, 0x1580, 0x2001, + 0xb153, 0x2004, 0xd0b4, 0x0904, 0x3917, 0x7824, 0xa084, 0xff00, + 0xa08e, 0x7e00, 0x0904, 0x3917, 0xa08e, 0x7f00, 0x0904, 0x3917, + 0xa08e, 0x8000, 0x0904, 0x3917, 0x6000, 0xd08c, 0x1904, 0x3917, + 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x99e8, 0x1120, + 0x2009, 0x0003, 0x0804, 0x2e97, 0x7007, 0x0003, 0x701b, 0x4101, + 0x0005, 0x080c, 0x3d29, 0x0904, 0x2e9a, 0x0804, 0x3917, 0x2009, + 0xb130, 0x210c, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x2e97, + 0x2001, 0xb100, 0x2004, 0xa086, 0x0003, 0x0120, 0x2009, 0x0007, + 0x0804, 0x2e97, 0x2001, 0xb153, 0x2004, 0xd0ac, 0x0120, 0x2009, + 0x0008, 0x0804, 0x2e97, 0x609c, 0xd0a4, 0x1118, 0xd0ac, 0x1904, + 0x3917, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x080c, 0x9a79, 0x1120, 0x2009, 0x0003, 0x0804, 0x2e97, 0x7007, + 0x0003, 0x701b, 0x413c, 0x0005, 0x6830, 0xa086, 0x0100, 0x1120, + 0x2009, 0x0004, 0x0804, 0x2e97, 0x080c, 0x3d29, 0x0904, 0x2e9a, + 0x0804, 0x40d7, 0x81ff, 0x2009, 0x0001, 0x1904, 0x2e97, 0x6000, + 0xa086, 0x0003, 0x2009, 0x0007, 0x1904, 0x2e97, 0x2001, 0xb153, + 0x2004, 0xd0ac, 0x2009, 0x0008, 0x1904, 0x2e97, 0x080c, 0x3d29, + 0x0904, 0x2e9a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x2009, + 0x0009, 0x1904, 0x2e97, 0x00c6, 0x080c, 0x3d04, 0x00ce, 0x2009, + 0x0002, 0x0904, 0x2e97, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00, 0xa18c, 0x00ff, 0xa006, + 0x82ff, 0x1128, 0xc0ed, 0x6952, 0x792c, 0x6956, 0x0048, 0xa28e, + 0x0100, 0x1904, 0x2e9a, 0xc0e5, 0x6853, 0x0000, 0x6857, 0x0000, + 0x683e, 0x080c, 0x9c36, 0x2009, 0x0003, 0x0904, 0x2e97, 0x7007, + 0x0003, 0x701b, 0x419c, 0x0005, 0x6830, 0xa086, 0x0100, 0x2009, + 0x0004, 0x0904, 0x2e97, 0x0804, 0x2e72, 0x81ff, 0x2009, 0x0001, + 0x1904, 0x2e97, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x1904, + 0x2e97, 0x080c, 0x3d29, 0x0904, 0x2e9a, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x0006, 0x2009, 0x0009, 0x1904, 0x2e97, 0x00c6, 0x080c, + 0x3d04, 0x00ce, 0x2009, 0x0002, 0x0904, 0x2e97, 0xad80, 0x000f, + 0x2009, 0x0008, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3d45, + 0x701b, 0x41d3, 0x0005, 0x00d6, 0xade8, 0x000f, 0x6800, 0xa086, + 0x0500, 0x1140, 0x6804, 0xa005, 0x1128, 0x6808, 0xa084, 0xff00, + 0x1108, 0x0018, 0x00de, 0x1904, 0x2e9a, 0x00de, 0x6837, 0x0000, + 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x00c6, 0x080c, 0x3d29, + 0x1118, 0x00ce, 0x0804, 0x2e9a, 0x080c, 0x9c85, 0x2009, 0x0003, + 0x00ce, 0x0904, 0x2e97, 0x7007, 0x0003, 0x701b, 0x4200, 0x0005, + 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0904, 0x2e97, 0x0804, + 0x2e72, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x2e97, 0x6000, + 0xa086, 0x0003, 0x0120, 0x2009, 0x0007, 0x0804, 0x2e97, 0x7e24, + 0x860f, 0xa18c, 0x00ff, 0xa6b4, 0x00ff, 0x080c, 0x4e21, 0x1904, + 0x2e9a, 0xa186, 0x007f, 0x0150, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x0006, 0x0120, 0x2009, 0x0009, 0x0804, 0x2e97, 0x00c6, 0x080c, + 0x3d04, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, 0x2e97, 0x6837, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x9a03, 0x1120, 0x2009, + 0x0003, 0x0804, 0x2e97, 0x7007, 0x0003, 0x701b, 0x4248, 0x0005, + 0x6808, 0x8007, 0xa086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, + 0x2e97, 0x68b0, 0x6836, 0x6810, 0x8007, 0xa084, 0x00ff, 0x808e, + 0x6814, 0x8007, 0xa084, 0x00ff, 0x8086, 0xa080, 0x0002, 0xa108, + 0xad80, 0x0004, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3d48, + 0x080c, 0x3d04, 0x1120, 0x2009, 0x0002, 0x0804, 0x2e97, 0x7924, + 0xa194, 0xff00, 0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804, + 0x2e9a, 0x2009, 0x001a, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, + 0x3d45, 0x701b, 0x4284, 0x0005, 0xad80, 0x000d, 0x2098, 0x20a9, + 0x001a, 0x20a1, 0xb3bf, 0x53a3, 0x0804, 0x2e72, 0x080c, 0x3d04, + 0x1120, 0x2009, 0x0002, 0x0804, 0x2e97, 0x7924, 0xa194, 0xff00, + 0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804, 0x2e9a, 0x2099, + 0xb3bf, 0x20a0, 0x20a9, 0x001a, 0x53a3, 0x2009, 0x001a, 0x7a2c, + 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3d48, 0x7824, 0xa08a, 0x1000, + 0x1a04, 0x2e9a, 0x0126, 0x2091, 0x8000, 0x8003, 0x800b, 0x810b, + 0xa108, 0x00c6, 0x2061, 0xb3ec, 0x6142, 0x00ce, 0x012e, 0x0804, + 0x2e72, 0x00c6, 0x080c, 0x58d5, 0x1188, 0x2001, 0xb39f, 0x2003, + 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, + 0x5919, 0x080c, 0x5816, 0x080c, 0x14fa, 0x0038, 0x2061, 0xb100, + 0x6030, 0xc09d, 0x6032, 0x080c, 0x4992, 0x00ce, 0x0005, 0x0126, + 0x2091, 0x8000, 0x00c6, 0x2061, 0xb3ec, 0x7924, 0x6152, 0x614e, + 0x6057, 0x0000, 0x604b, 0x0009, 0x7838, 0x606a, 0x783c, 0x6066, + 0x7828, 0x6062, 0x782c, 0x605e, 0x2061, 0xb3a0, 0x2001, 0xb401, + 0x600e, 0x6013, 0x0001, 0x6017, 0x0002, 0x6007, 0x0000, 0x6037, + 0x0000, 0x00ce, 0x012e, 0x0804, 0x2e72, 0x0126, 0x00c6, 0x00e6, + 0x2061, 0x0100, 0x2071, 0xb100, 0x6044, 0xd0a4, 0x11b0, 0xd084, + 0x0118, 0x080c, 0x447c, 0x0068, 0xd08c, 0x0118, 0x080c, 0x439d, + 0x0040, 0xd094, 0x0118, 0x080c, 0x436e, 0x0018, 0xd09c, 0x0108, + 0x0061, 0x00ee, 0x00ce, 0x012e, 0x0005, 0x0016, 0x6128, 0xd19c, + 0x1110, 0xc19d, 0x612a, 0x001e, 0x0ca0, 0x624c, 0xa286, 0xf0f0, + 0x1150, 0x6048, 0xa086, 0xf0f0, 0x0130, 0x624a, 0x6043, 0x0090, + 0x6043, 0x0010, 0x0490, 0xa294, 0xff00, 0xa296, 0xf700, 0x0178, + 0x7134, 0xd1a4, 0x1160, 0x6240, 0xa295, 0x0100, 0x6242, 0xa294, + 0x0010, 0x0128, 0x2009, 0x00f7, 0x080c, 0x4a24, 0x00f0, 0x6040, + 0xa084, 0x0010, 0xa085, 0x0140, 0x6042, 0x6043, 0x0000, 0x7077, + 0x0000, 0x7093, 0x0001, 0x70b7, 0x0000, 0x70d3, 0x0000, 0x2009, + 0xb7c0, 0x200b, 0x0000, 0x7087, 0x0000, 0x707b, 0x000a, 0x2009, + 0x000a, 0x2011, 0x4948, 0x080c, 0x67c8, 0x0005, 0x0156, 0x2001, + 0xb174, 0x2004, 0xd08c, 0x0110, 0x704f, 0xffff, 0x7078, 0xa005, + 0x1510, 0x2011, 0x4948, 0x080c, 0x6742, 0x6040, 0xa094, 0x0010, + 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8, 0x6044, 0xd08c, 0x1168, + 0x1f04, 0x4385, 0x6242, 0x708b, 0x0000, 0x6040, 0xa094, 0x0010, + 0xa285, 0x0080, 0x6042, 0x6242, 0x0030, 0x6242, 0x708b, 0x0000, + 0x707f, 0x0000, 0x0000, 0x015e, 0x0005, 0x707c, 0xa08a, 0x0003, + 0x1210, 0x0023, 0x0010, 0x080c, 0x14fa, 0x0005, 0x43a9, 0x43f9, + 0x447b, 0x00f6, 0x707f, 0x0001, 0x20e1, 0xa000, 0xe000, 0x20e1, + 0x8700, 0x080c, 0x2378, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2079, + 0xb600, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, 0x780f, + 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000, 0x781f, + 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000, 0x782f, + 0x0000, 0x2079, 0xb60c, 0x207b, 0x1101, 0x7807, 0x0000, 0x2099, + 0xb105, 0x20a1, 0xb60e, 0x20a9, 0x0004, 0x53a3, 0x2079, 0xb612, + 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xb600, 0x20a1, 0x020b, + 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000, 0x080c, + 0x4979, 0x00fe, 0x7083, 0x0000, 0x6043, 0x0008, 0x6043, 0x0000, + 0x0005, 0x00d6, 0x7080, 0x7083, 0x0000, 0xa025, 0x0904, 0x4463, + 0x6020, 0xd0b4, 0x1904, 0x4461, 0x7190, 0x81ff, 0x0904, 0x4451, + 0xa486, 0x000c, 0x1904, 0x445c, 0xa480, 0x0018, 0x8004, 0x20a8, + 0x2011, 0xb680, 0x2019, 0xb600, 0x220c, 0x2304, 0xa106, 0x11b8, + 0x8210, 0x8318, 0x1f04, 0x4414, 0x6043, 0x0004, 0x608b, 0xbc94, + 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707f, 0x0002, 0x708b, 0x0002, + 0x2009, 0x07d0, 0x2011, 0x494f, 0x080c, 0x67c8, 0x0490, 0x2069, + 0xb680, 0x6930, 0xa18e, 0x1101, 0x1538, 0x6834, 0xa005, 0x1520, + 0x6900, 0xa18c, 0x00ff, 0x1118, 0x6804, 0xa005, 0x0190, 0x2011, + 0xb68e, 0x2019, 0xb105, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, + 0x0230, 0x1190, 0x8210, 0x8318, 0x1f04, 0x4445, 0x0068, 0x7093, + 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xb680, 0x20a1, + 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008, 0x6043, 0x0000, + 0x0010, 0x00de, 0x0005, 0x6040, 0xa085, 0x0100, 0x6042, 0x6020, + 0xd0b4, 0x1db8, 0x60c3, 0x000c, 0x2011, 0xb3e3, 0x2013, 0x0000, + 0x7083, 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, + 0x080c, 0x7a83, 0x0c30, 0x0005, 0x7088, 0xa08a, 0x001d, 0x1210, + 0x0023, 0x0010, 0x080c, 0x14fa, 0x0005, 0x44af, 0x44be, 0x44e6, + 0x44ff, 0x4523, 0x454b, 0x456f, 0x45a0, 0x45c4, 0x45ec, 0x4623, + 0x464b, 0x4667, 0x467d, 0x469d, 0x46b0, 0x46b8, 0x46e5, 0x4709, + 0x4731, 0x4755, 0x4786, 0x47c3, 0x47f2, 0x480e, 0x484d, 0x486d, + 0x4886, 0x4887, 0x00c6, 0x2061, 0xb100, 0x6003, 0x0007, 0x2061, + 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006, 0x00ce, 0x0005, 0x608b, + 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, 0x708b, 0x0001, 0x2009, + 0x07d0, 0x2011, 0x494f, 0x080c, 0x67c8, 0x0005, 0x00f6, 0x7080, + 0xa086, 0x0014, 0x1508, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x11e0, + 0x2079, 0xb680, 0x7a30, 0xa296, 0x1102, 0x11a0, 0x7834, 0xa005, + 0x1188, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, + 0x0001, 0x2011, 0x494f, 0x080c, 0x6742, 0x708b, 0x0010, 0x080c, + 0x46b8, 0x0010, 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, 0x0003, + 0x6043, 0x0004, 0x2011, 0x494f, 0x080c, 0x6742, 0x080c, 0x4a0c, + 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, 0x20a3, 0x0000, + 0x1f04, 0x44f6, 0x60c3, 0x0014, 0x080c, 0x4979, 0x0005, 0x00f6, + 0x7080, 0xa005, 0x01f0, 0x2011, 0x494f, 0x080c, 0x6742, 0xa086, + 0x0014, 0x11a8, 0x2079, 0xb680, 0x7a30, 0xa296, 0x1102, 0x1178, + 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, + 0x1110, 0x70b7, 0x0001, 0x708b, 0x0004, 0x0029, 0x0010, 0x080c, + 0x4992, 0x00fe, 0x0005, 0x708b, 0x0005, 0x080c, 0x4a0c, 0x20a3, + 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xb68e, 0x080c, 0x4a5d, + 0x1160, 0x7074, 0xa005, 0x1148, 0x714c, 0xa186, 0xffff, 0x0128, + 0x080c, 0x4913, 0x0110, 0x080c, 0x4a3b, 0x20a9, 0x0008, 0x2298, + 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x080c, 0x4979, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0, 0x2011, + 0x494f, 0x080c, 0x6742, 0xa086, 0x0014, 0x11a8, 0x2079, 0xb680, + 0x7a30, 0xa296, 0x1103, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, + 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, + 0x0006, 0x0029, 0x0010, 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, + 0x0007, 0x080c, 0x4a0c, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, + 0x2011, 0xb68e, 0x080c, 0x4a5d, 0x11a8, 0x7074, 0xa005, 0x1190, + 0x7154, 0xa186, 0xffff, 0x0170, 0xa180, 0x2c8c, 0x200d, 0xa18c, + 0xff00, 0x810f, 0x080c, 0x4913, 0x0128, 0x080c, 0x3f65, 0x0110, + 0x080c, 0x2740, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x4979, 0x0005, + 0x00f6, 0x7080, 0xa005, 0x01f0, 0x2011, 0x494f, 0x080c, 0x6742, + 0xa086, 0x0014, 0x11a8, 0x2079, 0xb680, 0x7a30, 0xa296, 0x1104, + 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, + 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, 0x0008, 0x0029, 0x0010, + 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, 0x0009, 0x080c, 0x4a0c, + 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, 0x080c, 0x4a5d, 0x1150, + 0x7074, 0xa005, 0x1138, 0x080c, 0x4888, 0x1170, 0xa085, 0x0001, + 0x080c, 0x2740, 0x20a9, 0x0008, 0x2099, 0xb68e, 0x26a0, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x4979, + 0x0010, 0x080c, 0x44a2, 0x0005, 0x00f6, 0x7080, 0xa005, 0x0588, + 0x2011, 0x494f, 0x080c, 0x6742, 0xa086, 0x0014, 0x1540, 0x2079, + 0xb680, 0x7a30, 0xa296, 0x1105, 0x1510, 0x7834, 0x2011, 0x0100, + 0xa21e, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, + 0x70b7, 0x0001, 0x708b, 0x000a, 0x00b1, 0x0098, 0xa005, 0x1178, + 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, + 0x7087, 0x0000, 0x708b, 0x000e, 0x080c, 0x469d, 0x0010, 0x080c, + 0x4992, 0x00fe, 0x0005, 0x708b, 0x000b, 0x2011, 0xb60e, 0x22a0, + 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, + 0x0000, 0x41a4, 0x080c, 0x4a0c, 0x20a3, 0x1106, 0x20a3, 0x0000, + 0x080c, 0x4a5d, 0x0118, 0x2013, 0x0000, 0x0020, 0x7050, 0xa085, + 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, 0x60c3, 0x0084, + 0x080c, 0x4979, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01b0, 0x2011, + 0x494f, 0x080c, 0x6742, 0xa086, 0x0084, 0x1168, 0x2079, 0xb680, + 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, 0xa005, 0x1120, 0x708b, + 0x000c, 0x0029, 0x0010, 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, + 0x000d, 0x080c, 0x4a0c, 0x20a3, 0x1107, 0x20a3, 0x0000, 0x2099, + 0xb68e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0084, 0x080c, 0x4979, 0x0005, 0x00f6, 0x7080, 0xa005, + 0x01d0, 0x2011, 0x494f, 0x080c, 0x6742, 0xa086, 0x0084, 0x1188, + 0x2079, 0xb680, 0x7a30, 0xa296, 0x1107, 0x1158, 0x7834, 0xa005, + 0x1140, 0x7087, 0x0001, 0x080c, 0x49fe, 0x708b, 0x000e, 0x0029, + 0x0010, 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, 0x000f, 0x7083, + 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, 0x0005, 0x6043, + 0x0004, 0x2009, 0x07d0, 0x2011, 0x494f, 0x080c, 0x6736, 0x0005, + 0x7080, 0xa005, 0x0120, 0x2011, 0x494f, 0x080c, 0x6742, 0x0005, + 0x708b, 0x0011, 0x080c, 0x4a5d, 0x1188, 0x716c, 0x81ff, 0x0170, + 0x2009, 0x0000, 0x7070, 0xa084, 0x00ff, 0x080c, 0x26f6, 0xa186, + 0x0080, 0x0120, 0x2011, 0xb68e, 0x080c, 0x4913, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0xb680, 0x20a1, 0x020b, 0x7480, 0xa480, + 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, + 0x60c3, 0x0014, 0x080c, 0x4979, 0x0005, 0x00f6, 0x7080, 0xa005, + 0x01f0, 0x2011, 0x494f, 0x080c, 0x6742, 0xa086, 0x0014, 0x11a8, + 0x2079, 0xb680, 0x7a30, 0xa296, 0x1103, 0x1178, 0x7834, 0xa005, + 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, + 0x0001, 0x708b, 0x0012, 0x0029, 0x0010, 0x080c, 0x4992, 0x00fe, + 0x0005, 0x708b, 0x0013, 0x080c, 0x4a18, 0x20a3, 0x1103, 0x20a3, + 0x0000, 0x3430, 0x2011, 0xb68e, 0x080c, 0x4a5d, 0x1160, 0x7074, + 0xa005, 0x1148, 0x714c, 0xa186, 0xffff, 0x0128, 0x080c, 0x4913, + 0x0110, 0x080c, 0x4a3b, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x4979, + 0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0, 0x2011, 0x494f, 0x080c, + 0x6742, 0xa086, 0x0014, 0x11a8, 0x2079, 0xb680, 0x7a30, 0xa296, + 0x1104, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, + 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, 0x0014, 0x0029, + 0x0010, 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, 0x0015, 0x080c, + 0x4a18, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0xb68e, + 0x080c, 0x4a5d, 0x11a8, 0x7074, 0xa005, 0x1190, 0x7154, 0xa186, + 0xffff, 0x0170, 0xa180, 0x2c8c, 0x200d, 0xa18c, 0xff00, 0x810f, + 0x080c, 0x4913, 0x0128, 0x080c, 0x3f65, 0x0110, 0x080c, 0x2740, + 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x080c, 0x4979, 0x0005, 0x00f6, 0x7080, + 0xa005, 0x05b8, 0x2011, 0x494f, 0x080c, 0x6742, 0xa086, 0x0014, + 0x1570, 0x2079, 0xb680, 0x7a30, 0xa296, 0x1105, 0x1540, 0x7834, + 0x2011, 0x0100, 0xa21e, 0x1148, 0x7a38, 0xd2fc, 0x0128, 0x70b4, + 0xa005, 0x1110, 0x70b7, 0x0001, 0x0060, 0xa005, 0x11c0, 0x7a38, + 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x7087, + 0x0000, 0x7a38, 0xd2f4, 0x0138, 0x2001, 0xb174, 0x2004, 0xd0a4, + 0x1110, 0x70d3, 0x0008, 0x708b, 0x0016, 0x0029, 0x0010, 0x080c, + 0x4992, 0x00fe, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, + 0xb680, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6, 0x3430, 0x2011, + 0xb68e, 0x708b, 0x0017, 0x080c, 0x4a5d, 0x1150, 0x7074, 0xa005, + 0x1138, 0x080c, 0x4888, 0x1170, 0xa085, 0x0001, 0x080c, 0x2740, + 0x20a9, 0x0008, 0x2099, 0xb68e, 0x26a0, 0x53a6, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x4979, 0x0010, 0x080c, + 0x44a2, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01b0, 0x2011, 0x494f, + 0x080c, 0x6742, 0xa086, 0x0084, 0x1168, 0x2079, 0xb680, 0x7a30, + 0xa296, 0x1106, 0x1138, 0x7834, 0xa005, 0x1120, 0x708b, 0x0018, + 0x0029, 0x0010, 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, 0x0019, + 0x080c, 0x4a18, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, + 0xb68e, 0x2039, 0xb60e, 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x080c, + 0x4a5d, 0x11e8, 0x2728, 0x2514, 0x8207, 0xa084, 0x00ff, 0x8000, + 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, 0x7050, 0x2310, + 0x8214, 0xa2a0, 0xb60e, 0x2414, 0xa38c, 0x0001, 0x0118, 0xa294, + 0xff00, 0x0018, 0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, + 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0084, 0x080c, 0x4979, 0x0005, 0x00f6, 0x7080, 0xa005, + 0x01d0, 0x2011, 0x494f, 0x080c, 0x6742, 0xa086, 0x0084, 0x1188, + 0x2079, 0xb680, 0x7a30, 0xa296, 0x1107, 0x1158, 0x7834, 0xa005, + 0x1140, 0x7087, 0x0001, 0x080c, 0x49fe, 0x708b, 0x001a, 0x0029, + 0x0010, 0x080c, 0x4992, 0x00fe, 0x0005, 0x708b, 0x001b, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x2099, 0xb680, 0x20a1, 0x020b, 0x7480, + 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, + 0x53a6, 0x60c3, 0x0084, 0x080c, 0x4979, 0x0005, 0x0005, 0x0005, + 0x0086, 0x0096, 0x2029, 0xb153, 0x252c, 0x20a9, 0x0008, 0x2041, + 0xb60e, 0x28a0, 0x2099, 0xb68e, 0x53a3, 0x20a9, 0x0008, 0x2011, + 0x0007, 0xd5d4, 0x0110, 0x2011, 0x0000, 0x2800, 0xa200, 0x200c, + 0xa1a6, 0xffff, 0x1148, 0xd5d4, 0x0110, 0x8210, 0x0008, 0x8211, + 0x1f04, 0x489d, 0x0804, 0x490b, 0x82ff, 0x1160, 0xd5d4, 0x0120, + 0xa1a6, 0x3fff, 0x0d90, 0x0020, 0xa1a6, 0x3fff, 0x0904, 0x490b, + 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4, 0x0110, + 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0110, 0x8423, 0x0008, 0x8424, + 0x1240, 0xd5d4, 0x0110, 0x8319, 0x0008, 0x8318, 0x1f04, 0x48c3, + 0x04d0, 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x1f04, 0x48d5, + 0x2328, 0x8529, 0xa2be, 0x0007, 0x0158, 0x0006, 0x2039, 0x0007, + 0x2200, 0xa73a, 0x000e, 0x27a8, 0xa5a8, 0x0010, 0x1f04, 0x48e4, + 0x754e, 0xa5c8, 0x2c8c, 0x292d, 0xa5ac, 0x00ff, 0x7572, 0x6532, + 0x6536, 0x0016, 0x2508, 0x080c, 0x2720, 0x001e, 0x60e7, 0x0000, + 0x65ea, 0x2018, 0x2304, 0xa405, 0x201a, 0x7077, 0x0001, 0x26a0, + 0x2898, 0x20a9, 0x0008, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0xa085, 0x0001, 0x0028, 0xa006, 0x0018, 0xa006, 0x080c, 0x14fa, + 0x009e, 0x008e, 0x0005, 0x2118, 0x2021, 0x0000, 0x2001, 0x0007, + 0xa39a, 0x0010, 0x0218, 0x8420, 0x8001, 0x0cd0, 0x2118, 0x84ff, + 0x0120, 0xa39a, 0x0010, 0x8421, 0x1de0, 0x2021, 0x0001, 0x83ff, + 0x0118, 0x8423, 0x8319, 0x1de8, 0xa238, 0x2704, 0xa42c, 0x11b8, + 0xa405, 0x203a, 0x714e, 0xa1a0, 0x2c8c, 0x242d, 0xa5ac, 0x00ff, + 0x7572, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x2720, 0x001e, + 0x60e7, 0x0000, 0x65ea, 0x7077, 0x0001, 0xa084, 0x0000, 0x0005, + 0x00e6, 0x2071, 0xb100, 0x707b, 0x0000, 0x00ee, 0x0005, 0x00e6, + 0x00f6, 0x2079, 0x0100, 0x2071, 0x0140, 0x080c, 0x7a8c, 0x7004, + 0xa084, 0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x0126, + 0x2091, 0x8000, 0x2071, 0xb122, 0x2073, 0x0000, 0x7840, 0x0026, + 0x0016, 0x2009, 0x00f7, 0x080c, 0x4a24, 0x001e, 0xa094, 0x0010, + 0xa285, 0x0080, 0x7842, 0x7a42, 0x002e, 0x012e, 0x00fe, 0x00ee, + 0x0005, 0x0126, 0x2091, 0x8000, 0x2011, 0xb3e3, 0x2013, 0x0000, + 0x7083, 0x0000, 0x012e, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, + 0x9575, 0x080c, 0x7a83, 0x2009, 0x07d0, 0x2011, 0x494f, 0x080c, + 0x67c8, 0x0005, 0x0016, 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x2011, 0x0003, 0x080c, 0x7d52, 0x2011, 0x0002, 0x080c, 0x7d5c, + 0x080c, 0x7c41, 0x080c, 0x67b6, 0x0036, 0x2019, 0x0000, 0x080c, + 0x7cc4, 0x003e, 0x2009, 0x00f7, 0x080c, 0x4a24, 0x2061, 0xb3ec, + 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0xb100, 0x6003, 0x0001, + 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x002d, + 0x2011, 0x49c9, 0x080c, 0x6736, 0x012e, 0x00ce, 0x002e, 0x001e, + 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x0100, + 0x080c, 0x7a8c, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, 0x0120, + 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, 0x58dd, 0x01a8, 0x080c, + 0x58fb, 0x1190, 0x2001, 0xb39e, 0x2003, 0xaaaa, 0x0016, 0x080c, + 0x27c4, 0x2001, 0xb38f, 0x2102, 0x001e, 0x2001, 0xb39f, 0x2003, + 0x0000, 0x080c, 0x5816, 0x0030, 0x2001, 0x0001, 0x080c, 0x269e, + 0x080c, 0x4992, 0x012e, 0x000e, 0x00ee, 0x0005, 0x20a9, 0x0040, + 0x20a1, 0xb7c0, 0x2099, 0xb68e, 0x3304, 0x8007, 0x20a2, 0x9398, + 0x94a0, 0x1f04, 0x4a04, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x2099, 0xb600, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x0005, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xb680, 0x20a1, 0x020b, + 0x20a9, 0x000c, 0x53a6, 0x0005, 0x00c6, 0x0006, 0x2061, 0x0100, + 0x810f, 0x2001, 0xb130, 0x2004, 0xa005, 0x1138, 0x2001, 0xb114, + 0x2004, 0xa084, 0x00ff, 0xa105, 0x0010, 0xa185, 0x00f7, 0x604a, + 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x2001, 0xb153, 0x2004, + 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, 0x080c, 0xacae, + 0x2001, 0xb10c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, + 0x0000, 0x080c, 0x2b46, 0x004e, 0x001e, 0x0005, 0x080c, 0x4992, + 0x708b, 0x0000, 0x7083, 0x0000, 0x0005, 0x0006, 0x2001, 0xb10c, + 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006, 0x0016, 0x0126, + 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0xa18d, 0x0006, 0x2102, + 0x012e, 0x001e, 0x000e, 0x0005, 0x0156, 0x20a9, 0x00ff, 0x2009, + 0xb235, 0xa006, 0x200a, 0x8108, 0x1f04, 0x4a7a, 0x015e, 0x0005, + 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146, 0x2069, 0xb152, 0xa006, + 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, 0x2c8c, + 0x231d, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, + 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, + 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, + 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x607e, 0x6082, + 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, 0x60ae, + 0x61a2, 0x00d6, 0x60a4, 0xa06d, 0x0110, 0x080c, 0x15f4, 0x60a7, + 0x0000, 0x60a8, 0xa06d, 0x0110, 0x080c, 0x15f4, 0x60ab, 0x0000, + 0x00de, 0xa006, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0x6814, + 0xa084, 0x00ff, 0x6042, 0x014e, 0x013e, 0x015e, 0x003e, 0x00de, + 0x0005, 0x0126, 0x2091, 0x8000, 0x6944, 0x6e48, 0xa684, 0x3fff, + 0xa082, 0x4000, 0x1a04, 0x4b8f, 0xa18c, 0xff00, 0x810f, 0xa182, + 0x00ff, 0x1a04, 0x4b94, 0x2001, 0xb10c, 0x2004, 0xa084, 0x0003, + 0x01c0, 0x2001, 0xb10c, 0x2004, 0xd084, 0x1904, 0x4b77, 0xa188, + 0xb235, 0x2104, 0xa065, 0x0904, 0x4b77, 0x6004, 0xa084, 0x00ff, + 0xa08e, 0x0006, 0x1904, 0x4b77, 0x6000, 0xd0c4, 0x0904, 0x4b77, + 0x0068, 0xa188, 0xb235, 0x2104, 0xa065, 0x0904, 0x4b5b, 0x6004, + 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, 0x4b60, 0x60a4, 0xa00d, + 0x0118, 0x080c, 0x5046, 0x05d0, 0x60a8, 0xa00d, 0x0188, 0x080c, + 0x5091, 0x1170, 0x694c, 0xd1fc, 0x1118, 0x080c, 0x4d56, 0x0448, + 0x080c, 0x4d18, 0x694c, 0xd1ec, 0x1520, 0x080c, 0x4f3a, 0x0408, + 0x694c, 0xa184, 0xa000, 0x0178, 0xd1ec, 0x0140, 0xd1fc, 0x0118, + 0x080c, 0x4f49, 0x0028, 0x080c, 0x4f49, 0x0028, 0xd1fc, 0x0118, + 0x080c, 0x4d18, 0x0070, 0x6050, 0xa00d, 0x0130, 0x2d00, 0x200a, + 0x6803, 0x0000, 0x6052, 0x0028, 0x2d00, 0x6052, 0x604e, 0x6803, + 0x0000, 0x080c, 0x6a13, 0xa006, 0x012e, 0x0005, 0x2001, 0x0005, + 0x2009, 0x0000, 0x04e8, 0x2001, 0x0028, 0x2009, 0x0000, 0x04c0, + 0xa082, 0x0006, 0x12a0, 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1160, + 0x60a0, 0xd0bc, 0x1148, 0x6100, 0xd1fc, 0x0904, 0x4b16, 0x2001, + 0x0029, 0x2009, 0x1000, 0x0420, 0x2001, 0x0028, 0x00a8, 0x2009, + 0xb10c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0068, 0xd184, + 0x0118, 0x2001, 0x0004, 0x0040, 0x2001, 0x0029, 0x6100, 0xd1fc, + 0x0118, 0x2009, 0x1000, 0x0060, 0x2009, 0x0000, 0x0048, 0x2001, + 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, 0x0000, + 0xa005, 0x012e, 0x0005, 0x00e6, 0x0126, 0x2091, 0x8000, 0x6844, + 0x8007, 0xa084, 0x00ff, 0x2008, 0xa182, 0x00ff, 0x1a04, 0x4bee, + 0xa188, 0xb235, 0x2104, 0xa065, 0x01c0, 0x6004, 0xa084, 0x00ff, + 0xa08e, 0x0006, 0x11a8, 0x2c70, 0x080c, 0x8295, 0x05e8, 0x2e00, + 0x601a, 0x2d00, 0x6012, 0x600b, 0xffff, 0x601f, 0x000a, 0x2009, + 0x0003, 0x080c, 0x831a, 0xa006, 0x0460, 0x2001, 0x0028, 0x0440, + 0xa082, 0x0006, 0x1298, 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1158, + 0x60a0, 0xd0bc, 0x1140, 0x6100, 0xd1fc, 0x09e8, 0x2001, 0x0029, + 0x2009, 0x1000, 0x00a8, 0x2001, 0x0028, 0x0090, 0x2009, 0xb10c, + 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0050, 0xd184, 0x0118, + 0x2001, 0x0004, 0x0028, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, + 0xa005, 0x012e, 0x00ee, 0x0005, 0x2001, 0x002c, 0x0cc8, 0x00f6, + 0x00e6, 0x0126, 0x2091, 0x8000, 0x2011, 0x0000, 0x2079, 0xb100, + 0x6944, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x1a04, 0x4cbc, + 0x2001, 0xb10c, 0x2004, 0xa084, 0x0003, 0x1904, 0x4caa, 0x080c, + 0x4e21, 0x1180, 0x6004, 0xa084, 0x00ff, 0xa082, 0x0006, 0x1250, + 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1904, 0x4ca5, 0x60a0, 0xd0bc, + 0x1904, 0x4ca5, 0x6864, 0xa0c6, 0x006f, 0x0118, 0x2008, 0x0804, + 0x4c6e, 0x6968, 0x2140, 0xa18c, 0xff00, 0x810f, 0x78d0, 0xd0ac, + 0x1118, 0xa182, 0x0080, 0x06d0, 0xa182, 0x00ff, 0x16b8, 0x6a70, + 0x6b6c, 0x786c, 0xa306, 0x1160, 0x7870, 0xa24e, 0x1118, 0x2208, + 0x2310, 0x0460, 0xa9cc, 0xff00, 0x1118, 0x2208, 0x2310, 0x0430, + 0x080c, 0x3c52, 0x2c70, 0x0550, 0x2009, 0x0000, 0x2011, 0x0000, + 0xa0c6, 0x4000, 0x1160, 0x0006, 0x2e60, 0x080c, 0x50bc, 0x1108, + 0xc185, 0x7000, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x0088, 0xa0c6, + 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, 0x1118, 0x2708, + 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, 0x2001, 0x4006, + 0x6866, 0x696a, 0x6a6e, 0x2001, 0x0030, 0x0450, 0x080c, 0x8295, + 0x1138, 0x2001, 0x4005, 0x2009, 0x0003, 0x2011, 0x0000, 0x0c80, + 0x2e00, 0x601a, 0x080c, 0x9c35, 0x2d00, 0x6012, 0x601f, 0x0001, + 0x6838, 0xd88c, 0x0108, 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, + 0x080c, 0x2b73, 0x012e, 0x2001, 0x0000, 0x080c, 0x4d63, 0x2001, + 0x0002, 0x080c, 0x4d75, 0x2009, 0x0002, 0x080c, 0x831a, 0xa006, + 0xa005, 0x012e, 0x00ee, 0x00fe, 0x0005, 0x2001, 0x0028, 0x2009, + 0x0000, 0x0cb0, 0x2009, 0xb10c, 0x210c, 0xd18c, 0x0118, 0x2001, + 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, 0x0004, 0x0010, 0x2001, + 0x0029, 0x2009, 0x0000, 0x0c20, 0x2001, 0x0029, 0x2009, 0x0000, + 0x08f8, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x16b8, + 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x12e0, 0xa188, 0xb235, + 0x2104, 0xa065, 0x01b8, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, + 0x11b0, 0x684c, 0xd0ec, 0x0120, 0x080c, 0x4f49, 0x04c9, 0x0030, + 0x04b9, 0x684c, 0xd0fc, 0x0110, 0x080c, 0x4f3a, 0x080c, 0x4f87, + 0xa006, 0x00c8, 0x2001, 0x0028, 0x2009, 0x0000, 0x00a0, 0xa082, + 0x0006, 0x1240, 0x6100, 0xd1fc, 0x0d20, 0x2001, 0x0029, 0x2009, + 0x1000, 0x0048, 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, + 0x0029, 0x2009, 0x0000, 0xa005, 0x0005, 0x0126, 0x2091, 0x8000, + 0x6050, 0xa00d, 0x0138, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, + 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, + 0x0126, 0x2091, 0x8000, 0x604c, 0xa005, 0x0170, 0x00e6, 0x2071, + 0xb3d9, 0x7004, 0xa086, 0x0002, 0x0168, 0x00ee, 0x604c, 0x6802, + 0x2d00, 0x604e, 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803, + 0x0000, 0x0cc0, 0x701c, 0xac06, 0x1d80, 0x604c, 0x2070, 0x7000, + 0x6802, 0x2d00, 0x7002, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x604c, 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, 0x6052, + 0x604e, 0xad05, 0x012e, 0x0005, 0x604c, 0xa06d, 0x0130, 0x6800, + 0xa005, 0x1108, 0x6052, 0x604e, 0xad05, 0x0005, 0x6803, 0x0000, + 0x6084, 0xa00d, 0x0120, 0x2d00, 0x200a, 0x6086, 0x0005, 0x2d00, + 0x6086, 0x6082, 0x0cd8, 0x0126, 0x00c6, 0x0026, 0x2091, 0x8000, + 0x6218, 0x2260, 0x6200, 0xa005, 0x0110, 0xc285, 0x0008, 0xc284, + 0x6202, 0x002e, 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, + 0x8000, 0x6218, 0x2260, 0x6204, 0x0006, 0xa086, 0x0006, 0x1180, + 0x609c, 0xd0ac, 0x0168, 0x2001, 0xb153, 0x2004, 0xd0a4, 0x0140, + 0xa284, 0xff00, 0x8007, 0xa086, 0x0007, 0x1110, 0x2011, 0x0600, + 0x000e, 0xa294, 0xff00, 0xa215, 0x6206, 0x0006, 0xa086, 0x0006, + 0x1128, 0x6290, 0x82ff, 0x1110, 0x080c, 0x14fa, 0x000e, 0x00ce, + 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, 0x2260, + 0x6204, 0x0006, 0xa086, 0x0006, 0x1178, 0x609c, 0xd0a4, 0x0160, + 0x2001, 0xb153, 0x2004, 0xd0ac, 0x1138, 0xa284, 0x00ff, 0xa086, + 0x0007, 0x1110, 0x2011, 0x0006, 0x000e, 0xa294, 0x00ff, 0x8007, + 0xa215, 0x6206, 0x00ce, 0x012e, 0x0005, 0x0026, 0xa182, 0x00ff, + 0x0218, 0xa085, 0x0001, 0x00b0, 0xa190, 0xb235, 0x2204, 0xa065, + 0x1180, 0x0016, 0x00d6, 0x080c, 0x15c4, 0x2d60, 0x00de, 0x001e, + 0x0d80, 0x2c00, 0x2012, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x080c, + 0x4a80, 0xa006, 0x002e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0026, + 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0480, 0x00d6, 0xa190, + 0xb235, 0x2204, 0xa06d, 0x0540, 0x2013, 0x0000, 0x00d6, 0x00c6, + 0x2d60, 0x60a4, 0xa06d, 0x0110, 0x080c, 0x15f4, 0x60a8, 0xa06d, + 0x0110, 0x080c, 0x15f4, 0x00ce, 0x00de, 0x00d6, 0x00c6, 0x68ac, + 0x2060, 0x8cff, 0x0168, 0x600c, 0x0006, 0x6010, 0x2068, 0x080c, + 0x986a, 0x0110, 0x080c, 0x1604, 0x080c, 0x82eb, 0x00ce, 0x0c88, + 0x00ce, 0x00de, 0x080c, 0x15f4, 0x00de, 0xa006, 0x002e, 0x012e, + 0x0005, 0x0016, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0030, + 0xa188, 0xb235, 0x2104, 0xa065, 0x0dc0, 0xa006, 0x001e, 0x0005, + 0x00d6, 0x0156, 0x0136, 0x0146, 0x600b, 0x0000, 0x600f, 0x0000, + 0x6000, 0xc08c, 0x6002, 0x080c, 0x58d5, 0x1538, 0x60a0, 0xa086, + 0x007e, 0x2069, 0xb690, 0x0130, 0x2001, 0xb134, 0x2004, 0xd0ac, + 0x11e0, 0x0098, 0x2d04, 0xd0e4, 0x01c0, 0x00d6, 0x2069, 0xb68e, + 0x00c6, 0x2061, 0xb3b1, 0x6810, 0x2062, 0x6814, 0x6006, 0x6818, + 0x600a, 0x681c, 0x600e, 0x00ce, 0x00de, 0x8d69, 0x2d04, 0x2069, + 0x0140, 0x6886, 0x2069, 0xb100, 0x68a2, 0x2069, 0xb68e, 0x6808, + 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a, 0x0208, 0x603a, 0x6814, + 0x6066, 0x2099, 0xb696, 0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, + 0x53a3, 0x2099, 0xb69a, 0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, + 0x53a3, 0x2069, 0xb6ae, 0x6808, 0x606a, 0x690c, 0x616e, 0x6810, + 0x6072, 0x6818, 0x6076, 0x60a0, 0xa086, 0x007e, 0x1120, 0x2069, + 0xb68e, 0x690c, 0x616e, 0xa182, 0x0211, 0x1218, 0x2009, 0x0008, + 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, 0xa182, + 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, 0x1218, + 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, 0x0004, + 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, 0x2009, + 0x0002, 0x6192, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x0016, + 0x0026, 0x00e6, 0x2071, 0xb68d, 0x2e04, 0x6896, 0x2071, 0xb68e, + 0x7004, 0x689a, 0x701c, 0x689e, 0x6a00, 0x2009, 0xb172, 0x210c, + 0xd0bc, 0x0120, 0xd1ec, 0x0110, 0xc2ad, 0x0008, 0xc2ac, 0xd0c4, + 0x0120, 0xd1e4, 0x0110, 0xc2bd, 0x0008, 0xc2bc, 0x6a02, 0x00ee, + 0x002e, 0x001e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, + 0xa06d, 0x01c0, 0x6900, 0x81ff, 0x1540, 0x6a04, 0xa282, 0x0010, + 0x1648, 0xad88, 0x0004, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, + 0x0128, 0x8108, 0x1f04, 0x4ef5, 0x080c, 0x14fa, 0x260a, 0x8210, + 0x6a06, 0x0098, 0x080c, 0x15dd, 0x01a8, 0x2d00, 0x60a6, 0x6803, + 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, + 0x1f04, 0x4f0d, 0x6807, 0x0001, 0x6e12, 0xa085, 0x0001, 0x012e, + 0x00de, 0x0005, 0xa006, 0x0cd8, 0x0126, 0x2091, 0x8000, 0x00d6, + 0x60a4, 0xa00d, 0x01a0, 0x2168, 0x6800, 0xa005, 0x1160, 0x080c, + 0x5046, 0x1168, 0x200b, 0xffff, 0x6804, 0xa08a, 0x0002, 0x0218, + 0x8001, 0x6806, 0x0020, 0x080c, 0x15f4, 0x60a7, 0x0000, 0x00de, + 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x50a4, 0x0010, + 0x080c, 0x4d05, 0x080c, 0x4fbe, 0x1dd8, 0x080c, 0x4f87, 0x012e, + 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a8, 0xa06d, 0x01c0, + 0x6950, 0x81ff, 0x1540, 0x6a54, 0xa282, 0x0010, 0x1670, 0xad88, + 0x0018, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0128, 0x8108, + 0x1f04, 0x4f5b, 0x080c, 0x14fa, 0x260a, 0x8210, 0x6a56, 0x0098, + 0x080c, 0x15dd, 0x01d0, 0x2d00, 0x60aa, 0x6853, 0x0000, 0xad88, + 0x0018, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, 0x4f73, + 0x6857, 0x0001, 0x6e62, 0x0010, 0x080c, 0x4d56, 0x0089, 0x1de0, + 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, 0x0126, + 0x2091, 0x8000, 0x080c, 0x6a13, 0x012e, 0x0005, 0xa01e, 0x0010, + 0x2019, 0x0001, 0xa00e, 0x0126, 0x2091, 0x8000, 0x604c, 0x2068, + 0x6000, 0xd0dc, 0x1170, 0x8dff, 0x01e8, 0x83ff, 0x0120, 0x6848, + 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, + 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, 0x6a00, 0x604c, 0xad06, + 0x1110, 0x624e, 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, 0x1110, + 0x6152, 0x8dff, 0x012e, 0x0005, 0xa01e, 0x0010, 0x2019, 0x0001, + 0xa00e, 0x6080, 0x2068, 0x8dff, 0x01e8, 0x83ff, 0x0120, 0x6848, + 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, + 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, 0x6a00, 0x6080, 0xad06, + 0x1110, 0x6282, 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, 0x1110, + 0x6186, 0x8dff, 0x0005, 0xa016, 0x080c, 0x5040, 0x1110, 0x2011, + 0x0001, 0x080c, 0x508b, 0x1110, 0xa295, 0x0002, 0x0005, 0x080c, + 0x50bc, 0x0118, 0x080c, 0x9928, 0x0010, 0xa085, 0x0001, 0x0005, + 0x080c, 0x50bc, 0x0118, 0x080c, 0x98b8, 0x0010, 0xa085, 0x0001, + 0x0005, 0x080c, 0x50bc, 0x0118, 0x080c, 0x990b, 0x0010, 0xa085, + 0x0001, 0x0005, 0x080c, 0x50bc, 0x0118, 0x080c, 0x98d4, 0x0010, + 0xa085, 0x0001, 0x0005, 0x080c, 0x50bc, 0x0118, 0x080c, 0x9944, + 0x0010, 0xa085, 0x0001, 0x0005, 0x0126, 0x0006, 0x00d6, 0x2091, + 0x8000, 0x6080, 0xa06d, 0x01a0, 0x6800, 0x0006, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x080c, 0x9ada, 0x0006, 0x6000, 0xd0fc, + 0x0110, 0x080c, 0xaf4f, 0x000e, 0x080c, 0x5271, 0x000e, 0x0c50, + 0x6083, 0x0000, 0x6087, 0x0000, 0x00de, 0x000e, 0x012e, 0x0005, + 0x60a4, 0xa00d, 0x1118, 0xa085, 0x0001, 0x0005, 0x00e6, 0x2170, + 0x7000, 0xa005, 0x1168, 0x20a9, 0x0010, 0xae88, 0x0004, 0x2104, + 0xa606, 0x0130, 0x8108, 0x1f04, 0x504f, 0xa085, 0x0001, 0x0008, + 0xa006, 0x00ee, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, + 0xa06d, 0x1128, 0x080c, 0x15dd, 0x01a0, 0x2d00, 0x60a6, 0x6803, + 0x0001, 0x6807, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, + 0xffff, 0x8108, 0x1f04, 0x506f, 0xa085, 0x0001, 0x012e, 0x00de, + 0x0005, 0xa006, 0x0cd8, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, + 0xa06d, 0x0130, 0x60a7, 0x0000, 0x080c, 0x15f4, 0xa085, 0x0001, + 0x012e, 0x00de, 0x0005, 0x60a8, 0xa00d, 0x1118, 0xa085, 0x0001, + 0x0005, 0x00e6, 0x2170, 0x7050, 0xa005, 0x1160, 0x20a9, 0x0010, + 0xae88, 0x0018, 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, 0x509a, + 0xa085, 0x0001, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x0c19, + 0x1188, 0x200b, 0xffff, 0x00d6, 0x60a8, 0x2068, 0x6854, 0xa08a, + 0x0002, 0x0218, 0x8001, 0x6856, 0x0020, 0x080c, 0x15f4, 0x60ab, + 0x0000, 0x00de, 0x012e, 0x0005, 0x609c, 0xd0a4, 0x0005, 0x00f6, + 0x080c, 0x58d5, 0x01b0, 0x71b4, 0x81ff, 0x1198, 0x71d0, 0xd19c, + 0x0180, 0x2001, 0x007e, 0xa080, 0xb235, 0x2004, 0xa07d, 0x0148, + 0x7804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1118, 0x7800, 0xc0ed, + 0x7802, 0x2079, 0xb152, 0x7804, 0xd0a4, 0x01e8, 0x0156, 0x00c6, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4e21, 0x1168, + 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004, 0x0118, 0xa086, + 0x0006, 0x1118, 0x6000, 0xc0ed, 0x6002, 0x001e, 0x8108, 0x1f04, + 0x50e4, 0x00ce, 0x015e, 0x080c, 0x517b, 0x0120, 0x2001, 0xb3b4, + 0x200c, 0x0038, 0x2079, 0xb152, 0x7804, 0xd0a4, 0x0130, 0x2009, + 0x07d0, 0x2011, 0x510f, 0x080c, 0x67c8, 0x00fe, 0x0005, 0x2011, + 0x510f, 0x080c, 0x6742, 0x080c, 0x517b, 0x01f0, 0x2001, 0xb2b3, + 0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xb153, + 0x2004, 0xd0a4, 0x0130, 0x2009, 0x07d0, 0x2011, 0x510f, 0x080c, + 0x67c8, 0x00e6, 0x2071, 0xb100, 0x706f, 0x0000, 0x7073, 0x0000, + 0x080c, 0x2991, 0x00ee, 0x04b0, 0x0156, 0x00c6, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x0016, 0x080c, 0x4e21, 0x1530, 0x6000, 0xd0ec, + 0x0518, 0x0046, 0x62a0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, + 0x0029, 0x080c, 0xacae, 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x6004, + 0xa084, 0x00ff, 0xa085, 0x0700, 0x6006, 0x2019, 0x0029, 0x080c, + 0x6b35, 0x0076, 0x2039, 0x0000, 0x080c, 0x6a6b, 0x2009, 0x0000, + 0x080c, 0xaa51, 0x007e, 0x004e, 0x001e, 0x8108, 0x1f04, 0x513a, + 0x00ce, 0x015e, 0x0005, 0x00c6, 0x6018, 0x2060, 0x6000, 0xc0ec, + 0x6002, 0x00ce, 0x0005, 0x7818, 0x2004, 0xd0ac, 0x0005, 0x7818, + 0x2004, 0xd0bc, 0x0005, 0x00f6, 0x2001, 0xb2b3, 0x2004, 0xa07d, + 0x0110, 0x7800, 0xd0ec, 0x00fe, 0x0005, 0x0126, 0x0026, 0x2091, + 0x8000, 0x6200, 0xa005, 0x0110, 0xc2fd, 0x0008, 0xc2fc, 0x6202, + 0x002e, 0x012e, 0x0005, 0x2011, 0xb134, 0x2204, 0xd0cc, 0x0138, + 0x2001, 0xb3b2, 0x200c, 0x2011, 0x51a0, 0x080c, 0x67c8, 0x0005, + 0x2011, 0x51a0, 0x080c, 0x6742, 0x2011, 0xb134, 0x2204, 0xc0cc, + 0x2012, 0x0005, 0x2071, 0xb214, 0x7003, 0x0001, 0x7007, 0x0000, + 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, + 0x700b, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020, + 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, 0xb37d, 0x7003, 0xb214, + 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, 0xb35d, 0x7013, 0x0020, + 0x7017, 0x0040, 0x7037, 0x0000, 0x0005, 0x0016, 0x00e6, 0x2071, + 0xb335, 0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001, 0xb153, + 0x2004, 0xd0fc, 0x1150, 0x2001, 0xb153, 0x2004, 0xa00e, 0xd09c, + 0x0108, 0x8108, 0x7102, 0x0804, 0x523b, 0x2001, 0xb172, 0x200c, + 0xa184, 0x000f, 0x2009, 0xb173, 0x210c, 0x0002, 0x51e3, 0x5216, + 0x521d, 0x5227, 0x522c, 0x51e3, 0x51e3, 0x51e3, 0x5206, 0x51e3, + 0x51e3, 0x51e3, 0x51e3, 0x51e3, 0x51e3, 0x51e3, 0x7003, 0x0004, + 0x0136, 0x0146, 0x0156, 0x2099, 0xb176, 0x20a1, 0xb386, 0x20a9, + 0x0004, 0x53a3, 0x015e, 0x014e, 0x013e, 0x0428, 0x708f, 0x0005, + 0x7007, 0x0122, 0x2001, 0x0002, 0x0030, 0x708f, 0x0002, 0x7007, + 0x0121, 0x2001, 0x0003, 0x7002, 0x7097, 0x0001, 0x0088, 0x7007, + 0x0122, 0x2001, 0x0002, 0x0020, 0x7007, 0x0121, 0x2001, 0x0003, + 0x7002, 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a, + 0xa184, 0x00ff, 0x7092, 0x00ee, 0x001e, 0x0005, 0x00e6, 0x2071, + 0xb214, 0x684c, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, + 0x0001, 0x0428, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868, 0x703e, + 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844, 0x7032, + 0x2009, 0x000d, 0x200a, 0x700b, 0x0000, 0x8007, 0x8006, 0x8006, + 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x726e, + 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, 0x00ee, + 0x0005, 0x0156, 0x00e6, 0x0026, 0x6838, 0xd0fc, 0x1904, 0x52ca, + 0x6804, 0xa00d, 0x0188, 0x00d6, 0x2071, 0xb100, 0xa016, 0x702c, + 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, + 0x70b0, 0xa200, 0x70b2, 0x00de, 0x2071, 0xb214, 0x701c, 0xa005, + 0x1904, 0x52da, 0x20a9, 0x0032, 0x0f04, 0x52d8, 0x0e04, 0x5294, + 0x2071, 0xb335, 0x7200, 0x82ff, 0x05d8, 0x6934, 0xa186, 0x0103, + 0x1904, 0x52e8, 0x6948, 0x6844, 0xa105, 0x1540, 0x2009, 0x8020, + 0x2200, 0x0002, 0x52d8, 0x52af, 0x5300, 0x530c, 0x52d8, 0x2071, + 0x0000, 0x20a9, 0x0032, 0x0f04, 0x52d8, 0x7018, 0xd084, 0x1dd8, + 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, + 0x4080, 0x2071, 0xb100, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b0, + 0x8000, 0x70b2, 0x002e, 0x00ee, 0x015e, 0x0005, 0x6844, 0xa086, + 0x0100, 0x1130, 0x6868, 0xa005, 0x1118, 0x2009, 0x8020, 0x0880, + 0x2071, 0xb214, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012, + 0x7018, 0xa06d, 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, 0x0c10, + 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, + 0xa18e, 0x001f, 0x1d28, 0x684c, 0xd0cc, 0x0d10, 0x6850, 0xa084, + 0x00ff, 0xa086, 0x0001, 0x19e0, 0x2009, 0x8021, 0x0804, 0x52a8, + 0x7084, 0x8008, 0xa092, 0x001e, 0x1a98, 0x7186, 0xae90, 0x0003, + 0xa210, 0x683c, 0x2012, 0x0078, 0x7084, 0x8008, 0xa092, 0x000f, + 0x1a38, 0x7186, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, + 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a, 0x0a04, 0x52c1, 0x718c, + 0x7084, 0xa10a, 0x0a04, 0x52c1, 0x2071, 0x0000, 0x7018, 0xd084, + 0x1904, 0x52c1, 0x2071, 0xb335, 0x7000, 0xa086, 0x0002, 0x1150, + 0x080c, 0x558b, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, + 0x0804, 0x52c1, 0x080c, 0x55b5, 0x2071, 0x0000, 0x701b, 0x0001, + 0x2091, 0x4080, 0x0804, 0x52c1, 0x0006, 0x684c, 0x0006, 0x6837, + 0x0103, 0x20a9, 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, + 0x40a4, 0x000e, 0xa084, 0x00ff, 0x684e, 0x000e, 0x684a, 0x6952, + 0x0005, 0x2071, 0xb214, 0x7004, 0x0002, 0x5367, 0x5378, 0x5576, + 0x5577, 0x5584, 0x558a, 0x5368, 0x5567, 0x54fd, 0x5553, 0x0005, + 0x0126, 0x2091, 0x8000, 0x0e04, 0x5377, 0x2009, 0x000d, 0x7030, + 0x200a, 0x2091, 0x4080, 0x7007, 0x0001, 0x700b, 0x0000, 0x012e, + 0x2069, 0xb3ec, 0x683c, 0xa005, 0x03f8, 0x11f0, 0x0126, 0x2091, + 0x8000, 0x2069, 0x0000, 0x6934, 0x2001, 0xb220, 0x2004, 0xa10a, + 0x0170, 0x0e04, 0x539b, 0x2069, 0x0000, 0x6818, 0xd084, 0x1158, + 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x2069, + 0xb3ec, 0x683f, 0xffff, 0x012e, 0x2069, 0xb100, 0x6844, 0x6964, + 0xa102, 0x2069, 0xb335, 0x688a, 0x6984, 0x701c, 0xa06d, 0x0120, + 0x81ff, 0x0904, 0x53f1, 0x00a0, 0x81ff, 0x0904, 0x54b7, 0x2071, + 0xb335, 0x7184, 0x7088, 0xa10a, 0x1258, 0x7190, 0x2071, 0xb3ec, + 0x7038, 0xa005, 0x0128, 0x1b04, 0x54b7, 0x713a, 0x0804, 0x54b7, + 0x2071, 0xb335, 0x718c, 0x0126, 0x2091, 0x8000, 0x7084, 0xa10a, + 0x0a04, 0x54d2, 0x0e04, 0x5473, 0x2071, 0x0000, 0x7018, 0xd084, + 0x1904, 0x5473, 0x2001, 0xffff, 0x2071, 0xb3ec, 0x703a, 0x2071, + 0xb335, 0x7000, 0xa086, 0x0002, 0x1150, 0x080c, 0x558b, 0x2071, + 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x5473, 0x080c, + 0x55b5, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, + 0x5473, 0x2071, 0xb335, 0x7000, 0xa005, 0x0904, 0x5499, 0x6934, + 0xa186, 0x0103, 0x1904, 0x5476, 0x684c, 0xd0bc, 0x1904, 0x5499, + 0x6948, 0x6844, 0xa105, 0x1904, 0x548e, 0x2009, 0x8020, 0x2071, + 0xb335, 0x7000, 0x0002, 0x5499, 0x5459, 0x5431, 0x5443, 0x5410, + 0x0136, 0x0146, 0x0156, 0x2099, 0xb176, 0x20a1, 0xb386, 0x20a9, + 0x0004, 0x53a3, 0x015e, 0x014e, 0x013e, 0x2071, 0xb37d, 0xad80, + 0x000f, 0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, + 0x2e10, 0x080c, 0x1628, 0x2071, 0xb214, 0x7007, 0x0009, 0x0804, + 0x54b7, 0x7084, 0x8008, 0xa092, 0x001e, 0x1a04, 0x54b7, 0xae90, + 0x0003, 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xb214, 0x080c, + 0x560c, 0x0804, 0x54b7, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a04, + 0x54b7, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, + 0x6840, 0x2012, 0x7186, 0x2071, 0xb214, 0x080c, 0x560c, 0x0804, + 0x54b7, 0x0126, 0x2091, 0x8000, 0x0e04, 0x5473, 0x2071, 0x0000, + 0x7018, 0xd084, 0x1180, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, + 0x701b, 0x0001, 0x2091, 0x4080, 0x012e, 0x2071, 0xb214, 0x080c, + 0x560c, 0x0804, 0x54b7, 0x012e, 0x0804, 0x54b7, 0xa18c, 0x00ff, + 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, 0xa18e, 0x001f, + 0x11c0, 0x684c, 0xd0cc, 0x01a8, 0x6850, 0xa084, 0x00ff, 0xa086, + 0x0001, 0x1178, 0x2009, 0x8021, 0x0804, 0x5407, 0x6844, 0xa086, + 0x0100, 0x1138, 0x6868, 0xa005, 0x1120, 0x2009, 0x8020, 0x0804, + 0x5407, 0x2071, 0xb214, 0x080c, 0x561e, 0x01c8, 0x2071, 0xb214, + 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x1130, + 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x7007, 0x0003, + 0x080c, 0x5637, 0x7050, 0xa086, 0x0100, 0x0904, 0x5577, 0x0126, + 0x2091, 0x8000, 0x2071, 0xb214, 0x7008, 0xa086, 0x0001, 0x1180, + 0x0e04, 0x54d0, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, + 0x700b, 0x0000, 0x7004, 0xa086, 0x0006, 0x1110, 0x7007, 0x0001, + 0x012e, 0x0005, 0x2071, 0xb214, 0x080c, 0x561e, 0x0518, 0x2071, + 0xb335, 0x7084, 0x700a, 0x20a9, 0x0020, 0x2099, 0xb336, 0x20a1, + 0xb35d, 0x53a3, 0x7087, 0x0000, 0x2071, 0xb214, 0x2069, 0xb37d, + 0x706c, 0x6826, 0x7070, 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, + 0x2d10, 0x080c, 0x1628, 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, + 0xb3ec, 0x703a, 0x012e, 0x0804, 0x54b7, 0x2069, 0xb37d, 0x6808, + 0xa08e, 0x0000, 0x0904, 0x5552, 0xa08e, 0x0200, 0x0904, 0x5550, + 0xa08e, 0x0100, 0x1904, 0x5552, 0x0126, 0x2091, 0x8000, 0x0e04, + 0x554e, 0x2069, 0x0000, 0x6818, 0xd084, 0x15c0, 0x702c, 0x7130, + 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, + 0x0048, 0x706c, 0xa080, 0x0040, 0x706e, 0x1220, 0x7070, 0xa081, + 0x0000, 0x7072, 0x7132, 0x6936, 0x700b, 0x0000, 0x2001, 0xb35a, + 0x2004, 0xa005, 0x1190, 0x6934, 0x2069, 0xb335, 0x689c, 0x699e, + 0x2069, 0xb3ec, 0xa102, 0x1118, 0x683c, 0xa005, 0x1368, 0x2001, + 0xb35b, 0x200c, 0x810d, 0x693e, 0x0038, 0x2009, 0x8040, 0x6922, + 0x681b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x012e, 0x0010, + 0x7007, 0x0005, 0x0005, 0x2001, 0xb37f, 0x2004, 0xa08e, 0x0100, + 0x1128, 0x7007, 0x0001, 0x080c, 0x560c, 0x0005, 0xa08e, 0x0000, + 0x0de0, 0xa08e, 0x0200, 0x1dc8, 0x7007, 0x0005, 0x0005, 0x701c, + 0xa06d, 0x0158, 0x080c, 0x561e, 0x0140, 0x7007, 0x0003, 0x080c, + 0x5637, 0x7050, 0xa086, 0x0100, 0x0110, 0x0005, 0x0005, 0x7050, + 0xa09e, 0x0100, 0x1118, 0x7007, 0x0004, 0x0030, 0xa086, 0x0200, + 0x1110, 0x7007, 0x0005, 0x0005, 0x080c, 0x55da, 0x7006, 0x080c, + 0x560c, 0x0005, 0x0005, 0x00e6, 0x0156, 0x2071, 0xb335, 0x7184, + 0x81ff, 0x0500, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, + 0x21a8, 0x2014, 0x7226, 0x8000, 0x0f04, 0x55af, 0x2014, 0x722a, + 0x8000, 0x0f04, 0x55af, 0x2014, 0x722e, 0x8000, 0x0f04, 0x55af, + 0x2014, 0x723a, 0x8000, 0x0f04, 0x55af, 0x2014, 0x723e, 0xa180, + 0x8030, 0x7022, 0x015e, 0x00ee, 0x0005, 0x00e6, 0x0156, 0x2071, + 0xb335, 0x7184, 0x81ff, 0x01d8, 0xa006, 0x7086, 0xae80, 0x0003, + 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014, 0x722a, + 0x8000, 0x0f04, 0x55d1, 0x2014, 0x723a, 0x8000, 0x2014, 0x723e, + 0x0018, 0x2001, 0x8020, 0x0010, 0x2001, 0x8042, 0x7022, 0x015e, + 0x00ee, 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, + 0x7034, 0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, 0x0040, + 0x706e, 0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, + 0x8001, 0x700e, 0x1180, 0x0126, 0x2091, 0x8000, 0x0e04, 0x5606, + 0x2001, 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b, + 0x0000, 0x012e, 0x0005, 0x2001, 0x0007, 0x0005, 0x2001, 0x0006, + 0x700b, 0x0001, 0x012e, 0x0005, 0x701c, 0xa06d, 0x0170, 0x0126, + 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0xa005, + 0x1108, 0x701a, 0x012e, 0x080c, 0x15f4, 0x0005, 0x2019, 0x000d, + 0x2304, 0x230c, 0xa10e, 0x0130, 0x2304, 0x230c, 0xa10e, 0x0110, + 0xa006, 0x0060, 0x732c, 0x8319, 0x7130, 0xa102, 0x1118, 0x2300, + 0xa005, 0x0020, 0x0210, 0xa302, 0x0008, 0x8002, 0x0005, 0x2d00, + 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x0126, 0x2091, + 0x8000, 0x2009, 0xb408, 0x2104, 0xc08d, 0x200a, 0x012e, 0x080c, + 0x1640, 0x0005, 0x7088, 0xa08a, 0x0029, 0x1220, 0xa082, 0x001d, + 0x0033, 0x0010, 0x080c, 0x14fa, 0x6027, 0x1e00, 0x0005, 0x573d, + 0x56c0, 0x56d6, 0x5711, 0x5730, 0x5762, 0x5774, 0x56d6, 0x574e, + 0x5664, 0x5692, 0x5663, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, + 0xa005, 0x1180, 0x6808, 0xa005, 0x1518, 0x708b, 0x0028, 0x2069, + 0xb3be, 0x2d04, 0x7002, 0x080c, 0x59d7, 0x6028, 0xa085, 0x0600, + 0x602a, 0x00b0, 0x708b, 0x0028, 0x2069, 0xb3be, 0x2d04, 0x7002, + 0x6028, 0xa085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, + 0x2071, 0xb419, 0x080c, 0x1d48, 0x005e, 0x004e, 0x003e, 0x00ee, + 0x00de, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0xa005, 0x1180, + 0x6808, 0xa005, 0x1518, 0x708b, 0x0028, 0x2069, 0xb3be, 0x2d04, + 0x7002, 0x080c, 0x5a64, 0x6028, 0xa085, 0x0600, 0x602a, 0x00b0, + 0x708b, 0x0028, 0x2069, 0xb3be, 0x2d04, 0x7002, 0x6028, 0xa085, + 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xb419, + 0x080c, 0x1d48, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de, 0x0005, + 0x6803, 0x0090, 0x6124, 0xd1e4, 0x1180, 0x080c, 0x57df, 0xd1d4, + 0x1150, 0xd1dc, 0x1128, 0xd1cc, 0x0140, 0x708b, 0x0020, 0x0028, + 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x0088, + 0x6124, 0xd1cc, 0x1580, 0xd1dc, 0x1558, 0xd1e4, 0x1530, 0xa184, + 0x1e00, 0x1570, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, + 0x5905, 0x0156, 0x6803, 0x0100, 0x20a9, 0x0014, 0x6804, 0xd0dc, + 0x1118, 0x1f04, 0x56ee, 0x0048, 0x20a9, 0x0014, 0x6803, 0x0080, + 0x6804, 0xd0d4, 0x1130, 0x1f04, 0x56f8, 0x080c, 0x5926, 0x015e, + 0x0078, 0x015e, 0x708b, 0x0028, 0x0058, 0x708b, 0x001e, 0x0040, + 0x708b, 0x001d, 0x0028, 0x708b, 0x0020, 0x0010, 0x708b, 0x001f, + 0x0005, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, 0x5905, + 0x6803, 0x0080, 0x6124, 0xd1d4, 0x1180, 0xd1dc, 0x1158, 0xd1e4, + 0x1130, 0xa184, 0x1e00, 0x1158, 0x708b, 0x0028, 0x0040, 0x708b, + 0x001e, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, + 0x6803, 0x00a0, 0x6124, 0xd1dc, 0x1128, 0xd1e4, 0x0128, 0x708b, + 0x001e, 0x0010, 0x708b, 0x001d, 0x0005, 0x080c, 0x5809, 0x6124, + 0xd1dc, 0x1158, 0x080c, 0x57df, 0xd1d4, 0x1128, 0xd1e4, 0x0128, + 0x708b, 0x001e, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x00a0, + 0x6124, 0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, + 0x0140, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, + 0x0021, 0x0005, 0x080c, 0x5809, 0x6124, 0xd1d4, 0x1150, 0xd1dc, + 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, + 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x0090, 0x6124, 0xd1d4, + 0x1178, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0158, 0x708b, + 0x001e, 0x0040, 0x708b, 0x001d, 0x0028, 0x708b, 0x0020, 0x0010, + 0x708b, 0x001f, 0x0005, 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x0126, + 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb100, 0x2091, 0x8000, + 0x080c, 0x58d5, 0x11e8, 0x2001, 0xb10c, 0x200c, 0xd1b4, 0x01c0, + 0xc1b4, 0x2102, 0x6027, 0x0200, 0xe000, 0xe000, 0x6024, 0xd0cc, + 0x0158, 0x6803, 0x00a0, 0x2001, 0xb39f, 0x2003, 0x0001, 0x2001, + 0xb100, 0x2003, 0x0001, 0x0428, 0x6028, 0xc0cd, 0x602a, 0x0408, + 0x080c, 0x58f1, 0x0150, 0x080c, 0x58e7, 0x1138, 0x2001, 0x0001, + 0x080c, 0x269e, 0x080c, 0x58ac, 0x00a0, 0x080c, 0x5806, 0x0178, + 0x2001, 0x0001, 0x080c, 0x269e, 0x7088, 0xa086, 0x001e, 0x0120, + 0x7088, 0xa086, 0x0022, 0x1118, 0x708b, 0x0025, 0x0010, 0x708b, + 0x0021, 0x012e, 0x00ee, 0x00de, 0x00ce, 0x001e, 0x0005, 0x0016, + 0x0026, 0x2009, 0x0064, 0x2011, 0x57ea, 0x080c, 0x6736, 0x002e, + 0x001e, 0x0005, 0x00e6, 0x00f6, 0x0016, 0x080c, 0x7a8c, 0x2071, + 0xb100, 0x080c, 0x578b, 0x001e, 0x00fe, 0x00ee, 0x0005, 0x2001, + 0xb100, 0x2004, 0xa086, 0x0004, 0x0140, 0x2001, 0xb39e, 0x2003, + 0xaaaa, 0x2001, 0xb39f, 0x2003, 0x0000, 0x0005, 0x6020, 0xd09c, + 0x0005, 0x6803, 0x00c0, 0x0156, 0x20a9, 0x002d, 0x1d04, 0x580e, + 0x2091, 0x6000, 0x1f04, 0x580e, 0x015e, 0x0005, 0x00c6, 0x00d6, + 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb100, 0x2001, + 0xb39f, 0x200c, 0xa186, 0x0000, 0x0158, 0xa186, 0x0001, 0x0158, + 0xa186, 0x0002, 0x0158, 0xa186, 0x0003, 0x0158, 0x0804, 0x589a, + 0x708b, 0x0022, 0x0040, 0x708b, 0x0021, 0x0028, 0x708b, 0x0023, + 0x0020, 0x708b, 0x0024, 0x6043, 0x0000, 0x60e3, 0x0000, 0x6887, + 0x0001, 0x2001, 0x0001, 0x080c, 0x274b, 0x0026, 0x2011, 0x0003, + 0x080c, 0x7d52, 0x2011, 0x0002, 0x080c, 0x7d5c, 0x080c, 0x7c41, + 0x080c, 0x67b6, 0x0036, 0x2019, 0x0000, 0x080c, 0x7cc4, 0x003e, + 0x002e, 0x7000, 0xa08e, 0x0004, 0x0118, 0x602b, 0x0028, 0x0010, + 0x602b, 0x0020, 0x0156, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, + 0x6024, 0xd0ac, 0x0118, 0x012e, 0x015e, 0x04d0, 0x6800, 0xa084, + 0x00a0, 0xc0bd, 0x6802, 0x6904, 0xd1d4, 0x1130, 0x6803, 0x0100, + 0x1f04, 0x5868, 0x080c, 0x5926, 0x012e, 0x015e, 0x080c, 0x58e7, + 0x01a8, 0x6044, 0xa005, 0x0168, 0x6050, 0x0006, 0xa085, 0x0020, + 0x6052, 0x080c, 0x5926, 0xa006, 0x8001, 0x1df0, 0x000e, 0x6052, + 0x0028, 0x6804, 0xd0d4, 0x1110, 0x080c, 0x5926, 0x2001, 0xb39f, + 0x2003, 0x0004, 0x080c, 0x564a, 0x080c, 0x58e7, 0x0148, 0x6804, + 0xd0d4, 0x1130, 0xd0dc, 0x1100, 0x2001, 0xb39f, 0x2003, 0x0000, + 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, + 0x0100, 0x2069, 0x0140, 0x2071, 0xb100, 0x2001, 0xb39e, 0x2003, + 0x0000, 0x2001, 0xb38f, 0x2003, 0x0000, 0x708b, 0x0000, 0x60e3, + 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, 0x274b, 0x6803, + 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027, 0xffff, 0x602b, + 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, 0x2001, 0xb39e, + 0x2004, 0xa086, 0xaaaa, 0x000e, 0x0005, 0x0006, 0x2001, 0xb172, + 0x2004, 0xa084, 0x0030, 0xa086, 0x0000, 0x000e, 0x0005, 0x0006, + 0x2001, 0xb172, 0x2004, 0xa084, 0x0030, 0xa086, 0x0030, 0x000e, + 0x0005, 0x0006, 0x2001, 0xb172, 0x2004, 0xa084, 0x0030, 0xa086, + 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0xb172, 0x2004, 0xa084, + 0x0030, 0xa086, 0x0020, 0x000e, 0x0005, 0x2001, 0xb10c, 0x2004, + 0xd0a4, 0x0170, 0x080c, 0x276b, 0x0036, 0x0016, 0x2009, 0x0000, + 0x2019, 0x0028, 0x080c, 0x2b46, 0x001e, 0x003e, 0xa006, 0x0009, + 0x0005, 0x00e6, 0x2071, 0xb10c, 0x2e04, 0x0118, 0xa085, 0x0010, + 0x0010, 0xa084, 0xffef, 0x2072, 0x00ee, 0x0005, 0x6050, 0x0006, + 0x60f0, 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, + 0x6028, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, 0x602f, 0x0040, + 0x602f, 0x0000, 0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, + 0x000e, 0x60ee, 0x000e, 0x60f2, 0x60e3, 0x0000, 0x6887, 0x0001, + 0x2001, 0x0001, 0x080c, 0x274b, 0x6800, 0xa084, 0x00a0, 0xc0bd, + 0x6802, 0x6803, 0x00a0, 0x000e, 0x6052, 0x6050, 0x0005, 0x0156, + 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, + 0x2069, 0x0140, 0x2071, 0xb100, 0x6020, 0xa084, 0x0080, 0x0138, + 0x2001, 0xb10c, 0x200c, 0xc1bd, 0x2102, 0x0804, 0x59cf, 0x2001, + 0xb10c, 0x200c, 0xc1bc, 0x2102, 0x6028, 0xa084, 0xe1ff, 0x602a, + 0x6027, 0x0200, 0x6803, 0x0090, 0x20a9, 0x0384, 0x6024, 0xd0cc, + 0x1518, 0x1d04, 0x597e, 0x2091, 0x6000, 0x1f04, 0x597e, 0x2011, + 0x0003, 0x080c, 0x7d52, 0x2011, 0x0002, 0x080c, 0x7d5c, 0x080c, + 0x7c41, 0x080c, 0x67b6, 0x2019, 0x0000, 0x080c, 0x7cc4, 0x6803, + 0x00a0, 0x2001, 0xb39f, 0x2003, 0x0001, 0x2001, 0xb100, 0x2003, + 0x0001, 0xa085, 0x0001, 0x0458, 0x86ff, 0x1110, 0x080c, 0x1daa, + 0x60e3, 0x0000, 0x2001, 0xb38f, 0x2004, 0x080c, 0x274b, 0x60e2, + 0x6803, 0x0080, 0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00, + 0xe000, 0x6024, 0xa10c, 0x0138, 0x1d04, 0x59b4, 0x2091, 0x6000, + 0x1f04, 0x59b4, 0x0820, 0x6028, 0xa085, 0x1e00, 0x602a, 0x70a0, + 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0xa006, 0x00ee, + 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, + 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, + 0x2071, 0xb100, 0x2069, 0x0140, 0x6020, 0xa084, 0x00c0, 0x0120, + 0x6884, 0xa005, 0x1904, 0x5a2b, 0x6803, 0x0088, 0x60e3, 0x0000, + 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, 0x274b, 0x2069, 0x0200, + 0x6804, 0xa005, 0x1118, 0x6808, 0xa005, 0x01c0, 0x6028, 0xa084, + 0xfbff, 0x602a, 0x6027, 0x0400, 0x2069, 0xb3be, 0x7000, 0x206a, + 0x708b, 0x0026, 0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04, 0x5a0e, + 0x2091, 0x6000, 0x1f04, 0x5a0e, 0x0804, 0x5a5c, 0x2069, 0x0140, + 0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024, + 0xa10c, 0x0530, 0xa084, 0x1a00, 0x1518, 0x1d04, 0x5a1a, 0x2091, + 0x6000, 0x1f04, 0x5a1a, 0x2011, 0x0003, 0x080c, 0x7d52, 0x2011, + 0x0002, 0x080c, 0x7d5c, 0x080c, 0x7c41, 0x080c, 0x67b6, 0x2019, + 0x0000, 0x080c, 0x7cc4, 0x6803, 0x00a0, 0x2001, 0xb39f, 0x2003, + 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0xa085, 0x0001, 0x00a0, + 0x6803, 0x0080, 0x2069, 0x0140, 0x60e3, 0x0000, 0x70a0, 0xa005, + 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001, 0xb38f, 0x2004, + 0x080c, 0x274b, 0x60e2, 0xa006, 0x00ee, 0x00de, 0x00ce, 0x003e, + 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, + 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xb100, 0x6020, + 0xa084, 0x00c0, 0x01f0, 0x2011, 0x0003, 0x080c, 0x7d52, 0x2011, + 0x0002, 0x080c, 0x7d5c, 0x080c, 0x7c41, 0x080c, 0x67b6, 0x2019, + 0x0000, 0x080c, 0x7cc4, 0x2069, 0x0140, 0x6803, 0x00a0, 0x2001, + 0xb39f, 0x2003, 0x0001, 0x2001, 0xb100, 0x2003, 0x0001, 0x0804, + 0x5afc, 0x2001, 0xb10c, 0x200c, 0xd1b4, 0x1150, 0xc1b5, 0x2102, + 0x080c, 0x57df, 0x2069, 0x0140, 0x6803, 0x0080, 0x60e3, 0x0000, + 0x2069, 0x0200, 0x6804, 0xa005, 0x1118, 0x6808, 0xa005, 0x01b8, + 0x6028, 0xa084, 0xfdff, 0x602a, 0x6027, 0x0200, 0x2069, 0xb3be, + 0x7000, 0x206a, 0x708b, 0x0027, 0x7003, 0x0001, 0x20a9, 0x0002, + 0x1d04, 0x5ab8, 0x2091, 0x6000, 0x1f04, 0x5ab8, 0x04e8, 0x6027, + 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024, 0xa10c, 0x01c8, 0xa084, + 0x1c00, 0x11b0, 0x1d04, 0x5abf, 0x0006, 0x0016, 0x00c6, 0x00d6, + 0x00e6, 0x080c, 0x66b4, 0x00ee, 0x00de, 0x00ce, 0x001e, 0x000e, + 0x00e6, 0x2071, 0xb3ec, 0x7018, 0x00ee, 0xa005, 0x1d00, 0x01e0, + 0x0026, 0x2011, 0x57ea, 0x080c, 0x6742, 0x002e, 0x2069, 0x0140, + 0x60e3, 0x0000, 0x70a0, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, + 0x6886, 0x2001, 0xb38f, 0x2004, 0x080c, 0x274b, 0x60e2, 0x2001, + 0xb10c, 0x200c, 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e, + 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, + 0x0046, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xb100, 0x7130, + 0xd184, 0x1180, 0x2011, 0xb153, 0x2214, 0xd2ec, 0x0138, 0xc18d, + 0x7132, 0x2011, 0xb153, 0x2214, 0xd2ac, 0x1120, 0x7030, 0xd08c, + 0x0904, 0x5b69, 0x7130, 0xc185, 0x7132, 0x2011, 0xb153, 0x220c, + 0xd1a4, 0x0530, 0x0016, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, + 0x688d, 0x2019, 0x000e, 0x080c, 0xac2b, 0x0156, 0x20a9, 0x007f, + 0x2009, 0x0000, 0xa186, 0x007e, 0x0170, 0xa186, 0x0080, 0x0158, + 0x080c, 0x4e21, 0x1140, 0x8127, 0xa006, 0x0016, 0x2009, 0x000e, + 0x080c, 0xacae, 0x001e, 0x8108, 0x1f04, 0x5b3a, 0x015e, 0x001e, + 0xd1ac, 0x1148, 0x0016, 0x2009, 0x0000, 0x2019, 0x0004, 0x080c, + 0x2b46, 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x080c, 0x4e21, 0x1110, 0x080c, 0x4a80, 0x8108, 0x1f04, 0x5b60, + 0x015e, 0x2011, 0x0003, 0x080c, 0x7d52, 0x2011, 0x0002, 0x080c, + 0x7d5c, 0x080c, 0x7c41, 0x080c, 0x67b6, 0x0036, 0x2019, 0x0000, + 0x080c, 0x7cc4, 0x003e, 0x60e3, 0x0000, 0x2001, 0xb100, 0x2003, + 0x0001, 0x080c, 0x5816, 0x00ee, 0x00ce, 0x004e, 0x003e, 0x002e, + 0x001e, 0x015e, 0x0005, 0x2071, 0xb1e2, 0x7003, 0x0000, 0x7007, + 0x0000, 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, + 0x0001, 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, + 0x0000, 0x708f, 0x0001, 0x70bf, 0x0000, 0x0005, 0x00e6, 0x2071, + 0xb1e2, 0x6848, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, + 0x0001, 0x0428, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, + 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, + 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, + 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, + 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, + 0x0005, 0x2b78, 0x2071, 0xb1e2, 0x7004, 0x0043, 0x700c, 0x0002, + 0x5be5, 0x5bdc, 0x5bdc, 0x5bdc, 0x5bdc, 0x0005, 0x5c3b, 0x5c3c, + 0x5c6e, 0x5c6f, 0x5c39, 0x5cbd, 0x5cc2, 0x5cf3, 0x5cf4, 0x5d0f, + 0x5d10, 0x5d11, 0x5d12, 0x5d13, 0x5d14, 0x5dca, 0x5df1, 0x700c, + 0x0002, 0x5bfe, 0x5c39, 0x5c39, 0x5c3a, 0x5c3a, 0x7830, 0x7930, + 0xa106, 0x0120, 0x7830, 0x7930, 0xa106, 0x1510, 0x7030, 0xa10a, + 0x01f8, 0x1210, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x12d0, 0x080c, + 0x15c4, 0x01b0, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, + 0x7057, 0x0000, 0x0126, 0x0006, 0x2091, 0x8000, 0x2009, 0xb408, + 0x2104, 0xc085, 0x200a, 0x000e, 0x700e, 0x012e, 0x080c, 0x1640, + 0x0005, 0x080c, 0x15c4, 0x0de0, 0x2d00, 0x705a, 0x080c, 0x15c4, + 0x1108, 0x0c10, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, + 0x08f8, 0x0005, 0x0005, 0x0005, 0x700c, 0x0002, 0x5c43, 0x5c46, + 0x5c54, 0x5c6d, 0x5c6d, 0x080c, 0x5bf7, 0x0005, 0x0126, 0x8001, + 0x700e, 0x7058, 0x0006, 0x080c, 0x611c, 0x0120, 0x2091, 0x8000, + 0x080c, 0x5bf7, 0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, + 0x611c, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, + 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x003a, 0x1218, 0x00db, + 0x012e, 0x0005, 0x012e, 0x080c, 0x5d15, 0x0005, 0x0005, 0x0005, + 0x00e6, 0x2071, 0xb1e2, 0x700c, 0x0002, 0x5c7a, 0x5c7a, 0x5c7a, + 0x5c7c, 0x5c7f, 0x00ee, 0x0005, 0x700f, 0x0001, 0x0010, 0x700f, + 0x0002, 0x00ee, 0x0005, 0x5d15, 0x5d15, 0x5d31, 0x5d15, 0x5eae, + 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x5d31, 0x5ef0, 0x5f33, + 0x5f7c, 0x5f90, 0x5d15, 0x5d15, 0x5d4d, 0x5d31, 0x5d15, 0x5d15, + 0x5da7, 0x6039, 0x6054, 0x5d15, 0x5d4d, 0x5d15, 0x5d15, 0x5d15, + 0x5d15, 0x5d9d, 0x6054, 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x5d15, + 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x5d61, 0x5d15, 0x5d15, 0x5d15, + 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x613a, 0x5d15, + 0x5d15, 0x5d15, 0x5d15, 0x5d15, 0x5d76, 0x7020, 0x2068, 0x080c, + 0x15f4, 0x0005, 0x700c, 0x0002, 0x5cc9, 0x5ccc, 0x5cda, 0x5cf2, + 0x5cf2, 0x080c, 0x5bf7, 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, + 0x0006, 0x080c, 0x611c, 0x0120, 0x2091, 0x8000, 0x080c, 0x5bf7, + 0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x611c, 0x7058, + 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, + 0xa084, 0x00ff, 0xa08a, 0x001a, 0x1218, 0x003b, 0x012e, 0x0005, + 0x012e, 0x0419, 0x0005, 0x0005, 0x0005, 0x5d15, 0x5d31, 0x5e9a, + 0x5d15, 0x5d31, 0x5d15, 0x5d31, 0x5d31, 0x5d15, 0x5d31, 0x5e9a, + 0x5d31, 0x5d31, 0x5d31, 0x5d31, 0x5d31, 0x5d15, 0x5d31, 0x5e9a, + 0x5d15, 0x5d15, 0x5d31, 0x5d15, 0x5d15, 0x5d15, 0x5d31, 0x0005, + 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x7007, 0x0001, 0x6838, + 0xa084, 0x00ff, 0xc0d5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, + 0x5271, 0x012e, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, + 0xc0e5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x5271, 0x012e, + 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, + 0x0126, 0x2091, 0x8000, 0x080c, 0x5271, 0x012e, 0x0005, 0x7007, + 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a, 0x0126, 0x2091, + 0x8000, 0x080c, 0x5271, 0x012e, 0x0005, 0x6834, 0x8007, 0xa084, + 0x00ff, 0x0988, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x5e5a, + 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5e5a, + 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0904, 0x5d23, 0x8001, + 0x1120, 0x7007, 0x0001, 0x0804, 0x5e77, 0x7007, 0x0006, 0x7012, + 0x2d00, 0x7016, 0x701a, 0x704b, 0x5e77, 0x0005, 0x6834, 0x8007, + 0xa084, 0x00ff, 0xa086, 0x0001, 0x1904, 0x5d23, 0x7007, 0x0001, + 0x2009, 0xb130, 0x210c, 0x81ff, 0x11a8, 0x6838, 0xa084, 0x00ff, + 0x683a, 0x6853, 0x0000, 0x080c, 0x4bf7, 0x1108, 0x0005, 0x0126, + 0x2091, 0x8000, 0x6837, 0x0139, 0x684a, 0x6952, 0x080c, 0x5271, + 0x012e, 0x0ca0, 0x2001, 0x0028, 0x0c90, 0x684c, 0xa084, 0x00c0, + 0xa086, 0x00c0, 0x1120, 0x7007, 0x0001, 0x0804, 0x606c, 0x2d00, + 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, + 0xb20d, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x1a04, 0x5d3f, + 0x6a84, 0xa28a, 0x0002, 0x1a04, 0x5d3f, 0x82ff, 0x1138, 0x6888, + 0x698c, 0xa105, 0x0118, 0x2001, 0x5e2d, 0x0018, 0xa280, 0x5e23, + 0x2005, 0x70c6, 0x7010, 0xa015, 0x0904, 0x5e0f, 0x080c, 0x15c4, + 0x1118, 0x7007, 0x000f, 0x0005, 0x2d00, 0x7022, 0x70c4, 0x2060, + 0x2c05, 0x6836, 0xe004, 0xad00, 0x7096, 0xe008, 0xa20a, 0x1210, + 0xa00e, 0x2200, 0x7112, 0xe20c, 0x8003, 0x800b, 0xa296, 0x0004, + 0x0108, 0xa108, 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x080c, + 0x1628, 0x7090, 0xa08e, 0x0100, 0x0170, 0xa086, 0x0200, 0x0118, + 0x7007, 0x0010, 0x0005, 0x7020, 0x2068, 0x080c, 0x15f4, 0x7014, + 0x2068, 0x0804, 0x5d3f, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, + 0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, 0x0804, 0x5dca, 0x7014, + 0x2068, 0x7007, 0x0001, 0x6884, 0xa005, 0x1128, 0x6888, 0x698c, + 0xa105, 0x0108, 0x00b1, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, + 0x0904, 0x606c, 0x04b8, 0x5e25, 0x5e29, 0x0002, 0x0011, 0x0007, + 0x0004, 0x000a, 0x000f, 0x0005, 0x0006, 0x000a, 0x0011, 0x0005, + 0x0004, 0x00f6, 0x00e6, 0x00c6, 0x0076, 0x0066, 0x6f88, 0x6e8c, + 0x6804, 0x2060, 0xacf0, 0x0021, 0xacf8, 0x0027, 0x2009, 0x0005, + 0x700c, 0x7816, 0x7008, 0x7812, 0x7004, 0x7806, 0x7000, 0x7802, + 0x7e0e, 0x7f0a, 0x8109, 0x0128, 0xaef2, 0x0004, 0xaffa, 0x0006, + 0x0c78, 0x6004, 0xa065, 0x1d30, 0x006e, 0x007e, 0x00ce, 0x00ee, + 0x00fe, 0x0005, 0x2009, 0xb130, 0x210c, 0x81ff, 0x1198, 0x6838, + 0xa084, 0x00ff, 0x683a, 0x080c, 0x4ad9, 0x1108, 0x0005, 0x080c, + 0x5344, 0x0126, 0x2091, 0x8000, 0x080c, 0x9ada, 0x080c, 0x5271, + 0x012e, 0x0ca0, 0x2001, 0x0028, 0x2009, 0x0000, 0x0c80, 0x2009, + 0xb130, 0x210c, 0x81ff, 0x11b0, 0x6858, 0xa005, 0x01c0, 0x6838, + 0xa084, 0x00ff, 0x683a, 0x6853, 0x0000, 0x080c, 0x4b9b, 0x1108, + 0x0005, 0x0126, 0x2091, 0x8000, 0x684a, 0x6952, 0x080c, 0x5271, + 0x012e, 0x0cb0, 0x2001, 0x0028, 0x2009, 0x0000, 0x0c90, 0x2001, + 0x0000, 0x0c78, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a, + 0x7010, 0x8001, 0x7012, 0x0118, 0x7007, 0x0006, 0x0030, 0x7014, + 0x2068, 0x7007, 0x0001, 0x7048, 0x080f, 0x0005, 0x7007, 0x0001, + 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, 0x00ff, 0x20a9, + 0x0001, 0xa096, 0x0001, 0x01b0, 0x2009, 0x0000, 0x20a9, 0x00ff, + 0xa096, 0x0002, 0x0178, 0xa005, 0x11f0, 0x6944, 0x810f, 0xa18c, + 0x00ff, 0x080c, 0x4e21, 0x11b8, 0x0066, 0x6e50, 0x080c, 0x4f1c, + 0x006e, 0x0088, 0x0046, 0x2011, 0xb10c, 0x2224, 0xc484, 0x2412, + 0x004e, 0x00c6, 0x080c, 0x4e21, 0x1110, 0x080c, 0x507b, 0x8108, + 0x1f04, 0x5eda, 0x00ce, 0x684c, 0xd084, 0x1118, 0x080c, 0x15f4, + 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x5271, 0x012e, 0x0005, + 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xb153, 0x2004, + 0xd0a4, 0x0580, 0x2061, 0xb464, 0x6100, 0xd184, 0x0178, 0x6858, + 0xa084, 0x00ff, 0x1550, 0x6000, 0xd084, 0x0520, 0x6004, 0xa005, + 0x1538, 0x6003, 0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, 0x0001, + 0x6860, 0xa005, 0x1110, 0x2001, 0x001e, 0x8000, 0x6016, 0x6858, + 0xa084, 0x00ff, 0x0178, 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, + 0x0148, 0x600a, 0x6858, 0x8000, 0x1108, 0xc28d, 0x6202, 0x012e, + 0x0804, 0x610b, 0x012e, 0x0804, 0x6105, 0x012e, 0x0804, 0x60ff, + 0x012e, 0x0804, 0x6102, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, + 0x2001, 0xb153, 0x2004, 0xd0a4, 0x05e0, 0x2061, 0xb464, 0x6000, + 0xd084, 0x05b8, 0x6204, 0x6308, 0xd08c, 0x1530, 0x6c48, 0xa484, + 0x0003, 0x0170, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x1120, 0x2100, + 0xa210, 0x0620, 0x0028, 0x8001, 0x1508, 0x2100, 0xa212, 0x02f0, + 0xa484, 0x000c, 0x0188, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, + 0x0004, 0x1120, 0x2100, 0xa318, 0x0288, 0x0030, 0xa082, 0x0004, + 0x1168, 0x2100, 0xa31a, 0x0250, 0x6860, 0xa005, 0x0110, 0x8000, + 0x6016, 0x6206, 0x630a, 0x012e, 0x0804, 0x610b, 0x012e, 0x0804, + 0x6108, 0x012e, 0x0804, 0x6105, 0x0126, 0x2091, 0x8000, 0x7007, + 0x0001, 0x2061, 0xb464, 0x6300, 0xd38c, 0x1120, 0x6308, 0x8318, + 0x0220, 0x630a, 0x012e, 0x0804, 0x6119, 0x012e, 0x0804, 0x6108, + 0x0126, 0x00c6, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, + 0x0148, 0x00c6, 0x2061, 0xb464, 0x6000, 0xa084, 0xfcff, 0x6002, + 0x00ce, 0x0448, 0x6858, 0xa005, 0x05d0, 0x685c, 0xa065, 0x0598, + 0x2001, 0xb130, 0x2004, 0xa005, 0x0118, 0x080c, 0x9a2b, 0x0068, + 0x6013, 0x0400, 0x6057, 0x0000, 0x694c, 0xd1a4, 0x0110, 0x6950, + 0x6156, 0x2009, 0x0041, 0x080c, 0x831a, 0x6958, 0xa18c, 0xff00, + 0xa186, 0x2000, 0x1140, 0x0026, 0x2009, 0x0000, 0x2011, 0xfdff, + 0x080c, 0x688d, 0x002e, 0x684c, 0xd0c4, 0x0148, 0x2061, 0xb464, + 0x6000, 0xd08c, 0x1120, 0x6008, 0x8000, 0x0208, 0x600a, 0x00ce, + 0x012e, 0x0804, 0x610b, 0x00ce, 0x012e, 0x0804, 0x6105, 0x6954, + 0xa186, 0x002e, 0x0d40, 0xa186, 0x002d, 0x0d28, 0xa186, 0x0045, + 0x0510, 0xa186, 0x002a, 0x1130, 0x2001, 0xb10c, 0x200c, 0xc194, + 0x2102, 0x08c8, 0xa186, 0x0020, 0x0170, 0xa186, 0x0029, 0x1d18, + 0x6944, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4e21, 0x1960, 0x6000, + 0xc0e4, 0x6002, 0x0840, 0x685c, 0xa065, 0x09a8, 0x2001, 0xb3b5, + 0x2004, 0x6016, 0x0800, 0x685c, 0xa065, 0x0968, 0x00e6, 0x6860, + 0xa075, 0x2001, 0xb130, 0x2004, 0xa005, 0x0150, 0x080c, 0x9a2b, + 0x8eff, 0x0118, 0x2e60, 0x080c, 0x9a2b, 0x00ee, 0x0804, 0x5fcb, + 0x6020, 0xc0dc, 0xc0d5, 0x6022, 0x2e60, 0x6007, 0x003a, 0x6870, + 0xa005, 0x0130, 0x6007, 0x003b, 0x6874, 0x602a, 0x6878, 0x6012, + 0x6003, 0x0001, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x00ee, 0x0804, + 0x5fcb, 0x2061, 0xb464, 0x6000, 0xd084, 0x0190, 0xd08c, 0x1904, + 0x6119, 0x0126, 0x2091, 0x8000, 0x6204, 0x8210, 0x0220, 0x6206, + 0x012e, 0x0804, 0x6119, 0x012e, 0x6853, 0x0016, 0x0804, 0x6112, + 0x6853, 0x0007, 0x0804, 0x6112, 0x6834, 0x8007, 0xa084, 0x00ff, + 0x1118, 0x080c, 0x5d23, 0x0078, 0x2030, 0x8001, 0x1120, 0x7007, + 0x0001, 0x0051, 0x0040, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, + 0x701a, 0x704b, 0x606c, 0x0005, 0x00e6, 0x0126, 0x2091, 0x8000, + 0x2009, 0xb130, 0x210c, 0x81ff, 0x1904, 0x60e7, 0x2009, 0xb10c, + 0x210c, 0xd194, 0x1904, 0x60ef, 0x6848, 0x2070, 0xae82, 0xb800, + 0x0a04, 0x60db, 0x2001, 0xb116, 0x2004, 0xae02, 0x1a04, 0x60db, + 0x2061, 0xb464, 0x6100, 0xa184, 0x0301, 0xa086, 0x0001, 0x15a8, + 0x711c, 0xa186, 0x0006, 0x15b0, 0x7018, 0xa005, 0x0904, 0x60e7, + 0x2004, 0xd0e4, 0x1904, 0x60ea, 0x7020, 0xd0dc, 0x1904, 0x60f2, + 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x7010, 0xa005, 0x1158, + 0x7112, 0x684c, 0xd0f4, 0x1904, 0x60f5, 0x2e60, 0x080c, 0x67f8, + 0x012e, 0x00ee, 0x0005, 0x2068, 0x6800, 0xa005, 0x1de0, 0x6902, + 0x2168, 0x684c, 0xd0f4, 0x15c8, 0x012e, 0x00ee, 0x0005, 0x012e, + 0x00ee, 0x6853, 0x0006, 0x0804, 0x6112, 0xd184, 0x0dc0, 0xd1c4, + 0x11a8, 0x00b8, 0x6944, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4e21, + 0x11c8, 0x6000, 0xd0e4, 0x11b0, 0x711c, 0xa186, 0x0007, 0x1118, + 0x6853, 0x0002, 0x0088, 0x6853, 0x0008, 0x0070, 0x6853, 0x000e, + 0x0058, 0x6853, 0x0017, 0x0040, 0x6853, 0x0035, 0x0028, 0x6853, + 0x0028, 0x0010, 0x6853, 0x0029, 0x012e, 0x00ee, 0x0418, 0x6853, + 0x002a, 0x0cd0, 0x6853, 0x0045, 0x0cb8, 0x2e60, 0x2019, 0x0002, + 0x6017, 0x0014, 0x080c, 0xa8af, 0x012e, 0x00ee, 0x0005, 0x2009, + 0x003e, 0x0058, 0x2009, 0x0004, 0x0040, 0x2009, 0x0006, 0x0028, + 0x2009, 0x0016, 0x0010, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, + 0xa105, 0x6856, 0x0126, 0x2091, 0x8000, 0x080c, 0x5271, 0x012e, + 0x0005, 0x080c, 0x15f4, 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, + 0x0230, 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0058, 0x7070, + 0xa080, 0x0040, 0x7072, 0x1230, 0x7074, 0xa081, 0x0000, 0x7076, + 0xa085, 0x0001, 0x7932, 0x7132, 0x0005, 0x00d6, 0x080c, 0x67ef, + 0x00de, 0x0005, 0x00d6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x7007, + 0x0001, 0x6a44, 0xa282, 0x0004, 0x1a04, 0x6185, 0xd284, 0x0170, + 0x6a4c, 0xa290, 0xb235, 0x2204, 0xa065, 0x6004, 0x05e0, 0x8007, + 0xa084, 0x00ff, 0xa084, 0x0006, 0x1108, 0x04a8, 0x2c10, 0x080c, + 0x8295, 0x1118, 0x080c, 0x9ae4, 0x05a0, 0x621a, 0x6844, 0x0002, + 0x6164, 0x6169, 0x616c, 0x6172, 0x2019, 0x0002, 0x080c, 0xac2b, + 0x0060, 0x080c, 0xabc2, 0x0048, 0x2019, 0x0002, 0x6950, 0x080c, + 0xabdd, 0x0018, 0x6950, 0x080c, 0xabc2, 0x080c, 0x82eb, 0x6857, + 0x0000, 0x0126, 0x2091, 0x8000, 0x080c, 0x5271, 0x012e, 0x001e, + 0x002e, 0x003e, 0x00ce, 0x00de, 0x0005, 0x6857, 0x0006, 0x0c88, + 0x6857, 0x0002, 0x0c70, 0x6857, 0x0005, 0x0c58, 0x6857, 0x0004, + 0x0c40, 0x6857, 0x0007, 0x0c28, 0x00d6, 0x2011, 0x0004, 0x2204, + 0xa085, 0x8002, 0x2012, 0x00de, 0x0005, 0x20e1, 0x0002, 0x3d08, + 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0118, 0xa086, 0x1000, + 0x1570, 0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00, 0x8217, 0xa084, + 0xf000, 0xa086, 0x3000, 0x1160, 0xa184, 0xff00, 0x8007, 0xa086, + 0x0008, 0x11e8, 0x080c, 0x2c87, 0x11d0, 0x080c, 0x63bf, 0x0098, + 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x1108, 0x3e60, 0xac84, 0x0007, + 0x1170, 0xac82, 0xb800, 0x0258, 0x6858, 0xac02, 0x1240, 0x2009, + 0x0047, 0x080c, 0x831a, 0x7a1c, 0xd284, 0x1938, 0x0005, 0xa016, + 0x080c, 0x1828, 0x0cc0, 0x0cd8, 0x781c, 0xd08c, 0x0500, 0x0156, + 0x0136, 0x0146, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076, + 0x1530, 0xa484, 0x7000, 0xa086, 0x1000, 0x11a8, 0x080c, 0x623a, + 0x01f0, 0x20e1, 0x3000, 0x7828, 0x7828, 0x080c, 0x6256, 0x014e, + 0x013e, 0x015e, 0x2009, 0xb3e1, 0x2104, 0xa005, 0x1108, 0x0005, + 0x080c, 0x6e9e, 0x0ce0, 0xa484, 0x7000, 0x1518, 0x0499, 0x01b8, + 0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x0d18, 0x0080, 0xd5a4, + 0x0158, 0x080c, 0x1db4, 0x20e1, 0x9010, 0x2001, 0x0160, 0x2502, + 0x2001, 0x0138, 0x2202, 0x0048, 0x00e9, 0x6883, 0x0000, 0x080c, + 0xafa5, 0x20e1, 0x3000, 0x7828, 0x7828, 0x014e, 0x013e, 0x015e, + 0x08b0, 0x0081, 0x1130, 0x7000, 0xa084, 0xff00, 0xa086, 0x8100, + 0x1d70, 0x080c, 0xafa5, 0x20e1, 0x3000, 0x7828, 0x7828, 0x080c, + 0x6630, 0x0c58, 0xa484, 0x01ff, 0x6882, 0xa005, 0x0160, 0xa080, + 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, + 0x020a, 0x53a5, 0x0005, 0x20a9, 0x000c, 0x20e1, 0x1000, 0x2ea0, + 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, 0x0ca0, 0x7000, 0xa084, + 0xff00, 0xa08c, 0xf000, 0x8007, 0xa196, 0x0000, 0x1118, 0x0804, + 0x64c4, 0x0005, 0xa196, 0x2000, 0x1148, 0x6900, 0xa18e, 0x0001, + 0x1118, 0x080c, 0x4305, 0x0ca8, 0x0039, 0x0c98, 0xa196, 0x8000, + 0x1d80, 0x080c, 0x6570, 0x0c68, 0x00c6, 0x6a80, 0x82ff, 0x0904, + 0x63b9, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0120, + 0xa196, 0x0023, 0x1904, 0x63b9, 0xa08e, 0x0023, 0x1570, 0x080c, + 0x660b, 0x0904, 0x63b9, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, + 0x1150, 0x7034, 0xa005, 0x1904, 0x63b9, 0x2009, 0x0015, 0x080c, + 0x831a, 0x0804, 0x63b9, 0xa08e, 0x0214, 0x0118, 0xa08e, 0x0210, + 0x1130, 0x2009, 0x0015, 0x080c, 0x831a, 0x0804, 0x63b9, 0xa08e, + 0x0100, 0x1904, 0x63b9, 0x7034, 0xa005, 0x1904, 0x63b9, 0x2009, + 0x0016, 0x080c, 0x831a, 0x0804, 0x63b9, 0xa08e, 0x0022, 0x1904, + 0x63b9, 0x7030, 0xa08e, 0x0300, 0x1580, 0x68d0, 0xd0a4, 0x0528, + 0xc0b5, 0x68d2, 0x7100, 0xa18c, 0x00ff, 0x696e, 0x7004, 0x6872, + 0x00f6, 0x2079, 0x0100, 0x79e6, 0x78ea, 0x0006, 0xa084, 0x00ff, + 0x0016, 0x2008, 0x080c, 0x2720, 0x7932, 0x7936, 0x001e, 0x000e, + 0x00fe, 0x080c, 0x26f6, 0x694e, 0x703c, 0x00e6, 0x2071, 0x0140, + 0x7086, 0x2071, 0xb100, 0x70a2, 0x00ee, 0x7034, 0xa005, 0x1904, + 0x63b9, 0x2009, 0x0017, 0x0804, 0x637f, 0xa08e, 0x0400, 0x1158, + 0x7034, 0xa005, 0x1904, 0x63b9, 0x68d0, 0xc0a5, 0x68d2, 0x2009, + 0x0030, 0x0804, 0x637f, 0xa08e, 0x0500, 0x1140, 0x7034, 0xa005, + 0x1904, 0x63b9, 0x2009, 0x0018, 0x0804, 0x637f, 0xa08e, 0x2010, + 0x1120, 0x2009, 0x0019, 0x0804, 0x637f, 0xa08e, 0x2110, 0x1120, + 0x2009, 0x001a, 0x0804, 0x637f, 0xa08e, 0x5200, 0x1140, 0x7034, + 0xa005, 0x1904, 0x63b9, 0x2009, 0x001b, 0x0804, 0x637f, 0xa08e, + 0x5000, 0x1140, 0x7034, 0xa005, 0x1904, 0x63b9, 0x2009, 0x001c, + 0x0804, 0x637f, 0xa08e, 0x1300, 0x1120, 0x2009, 0x0034, 0x0804, + 0x637f, 0xa08e, 0x1200, 0x1140, 0x7034, 0xa005, 0x1904, 0x63b9, + 0x2009, 0x0024, 0x0804, 0x637f, 0xa08c, 0xff00, 0xa18e, 0x2400, + 0x1118, 0x2009, 0x002d, 0x04d8, 0xa08c, 0xff00, 0xa18e, 0x5300, + 0x1118, 0x2009, 0x002a, 0x0498, 0xa08e, 0x0f00, 0x1118, 0x2009, + 0x0020, 0x0468, 0xa08e, 0x5300, 0x1108, 0x00d8, 0xa08e, 0x6104, + 0x11c0, 0x2011, 0xb68d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8, + 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, 0x0046, 0x2124, + 0x080c, 0x3d5b, 0x004e, 0x8108, 0x1f04, 0x6362, 0x2009, 0x0023, + 0x0070, 0xa08e, 0x6000, 0x1118, 0x2009, 0x003f, 0x0040, 0xa08e, + 0x7800, 0x1118, 0x2009, 0x0045, 0x0010, 0x2009, 0x001d, 0x0016, + 0x2011, 0xb683, 0x2204, 0x8211, 0x220c, 0x080c, 0x26f6, 0x1598, + 0x080c, 0x4dc5, 0x1580, 0x6612, 0x6516, 0x86ff, 0x01e8, 0x001e, + 0x0016, 0xa186, 0x0017, 0x1158, 0x686c, 0xa606, 0x11a8, 0x6870, + 0xa506, 0xa084, 0xff00, 0x1180, 0x6000, 0xc0f5, 0x6002, 0xa186, + 0x0046, 0x1150, 0x686c, 0xa606, 0x1138, 0x6870, 0xa506, 0xa084, + 0xff00, 0x1110, 0x001e, 0x0068, 0x00c6, 0x080c, 0x8295, 0x0168, + 0x001e, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, + 0x831a, 0x00ce, 0x0005, 0x001e, 0x0ce0, 0x00ce, 0x0ce0, 0x00c6, + 0x0046, 0x080c, 0x6413, 0x1904, 0x6410, 0xa28e, 0x0033, 0x11e8, + 0x080c, 0x660b, 0x0904, 0x6410, 0x7124, 0x610a, 0x7030, 0xa08e, + 0x0200, 0x1140, 0x7034, 0xa005, 0x15d8, 0x2009, 0x0015, 0x080c, + 0x831a, 0x04b0, 0xa08e, 0x0100, 0x1598, 0x7034, 0xa005, 0x1580, + 0x2009, 0x0016, 0x080c, 0x831a, 0x0458, 0xa28e, 0x0032, 0x1540, + 0x7030, 0xa08e, 0x1400, 0x1520, 0x2009, 0x0038, 0x0016, 0x2011, + 0xb683, 0x2204, 0x8211, 0x220c, 0x080c, 0x26f6, 0x11c0, 0x080c, + 0x4dc5, 0x11a8, 0x6612, 0x6516, 0x00c6, 0x080c, 0x8295, 0x0170, + 0x001e, 0x611a, 0x080c, 0x9c35, 0x601f, 0x0004, 0x7120, 0x610a, + 0x001e, 0x080c, 0x831a, 0x080c, 0x6e9e, 0x0010, 0x00ce, 0x001e, + 0x004e, 0x00ce, 0x0005, 0x00f6, 0x00d6, 0x0026, 0x0016, 0x0136, + 0x0146, 0x0156, 0x3c00, 0x0006, 0x2079, 0x0030, 0x2069, 0x0200, + 0x080c, 0x1e48, 0x1590, 0x080c, 0x1d06, 0x05e0, 0x04f1, 0x1130, + 0x7908, 0xa18c, 0x1fff, 0xa182, 0x0011, 0x1688, 0x20a9, 0x000c, + 0x20e1, 0x0000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x20e1, 0x2000, + 0x2001, 0x020a, 0x2004, 0x7a0c, 0x7808, 0xa080, 0x0007, 0xa084, + 0x1ff8, 0x0419, 0x1120, 0xa08a, 0x0140, 0x1a0c, 0x14fa, 0x80ac, + 0x20e1, 0x6000, 0x2099, 0x020a, 0x53a5, 0x20e1, 0x7000, 0x6828, + 0x6828, 0x7803, 0x0004, 0xa294, 0x0070, 0x000e, 0x20e0, 0x015e, + 0x014e, 0x013e, 0x001e, 0x002e, 0x00de, 0x00fe, 0x0005, 0xa016, + 0x080c, 0x1828, 0xa085, 0x0001, 0x0c80, 0x0006, 0x2001, 0x0111, + 0x2004, 0xa084, 0x0003, 0x000e, 0x0005, 0x0046, 0x00e6, 0x00d6, + 0x2028, 0x2130, 0xa696, 0x00ff, 0x1198, 0xa596, 0xfffd, 0x1120, + 0x2009, 0x007f, 0x0804, 0x64bf, 0xa596, 0xfffe, 0x1118, 0x2009, + 0x007e, 0x04e8, 0xa596, 0xfffc, 0x1118, 0x2009, 0x0080, 0x04b8, + 0x2011, 0x0000, 0x2019, 0xb134, 0x231c, 0xd3ac, 0x0138, 0x2021, + 0x0000, 0x20a9, 0x00ff, 0x2071, 0xb235, 0x0030, 0x2021, 0x0081, + 0x20a9, 0x007e, 0x2071, 0xb2b6, 0x2e1c, 0x83ff, 0x1128, 0x82ff, + 0x1198, 0x2410, 0xc2fd, 0x0080, 0x2368, 0x6f10, 0x0006, 0x2100, + 0xa706, 0x000e, 0x6b14, 0x1120, 0xa346, 0x1110, 0x2408, 0x0078, + 0x87ff, 0x1110, 0x83ff, 0x0d58, 0x8420, 0x8e70, 0x1f04, 0x649c, + 0x82ff, 0x1118, 0xa085, 0x0001, 0x0018, 0xc2fc, 0x2208, 0xa006, + 0x00de, 0x00ee, 0x004e, 0x0005, 0xa084, 0x0007, 0x000a, 0x0005, + 0x64d0, 0x64d0, 0x64d0, 0x661d, 0x64d0, 0x64d1, 0x64e6, 0x655b, + 0x0005, 0x7110, 0xd1bc, 0x0188, 0x7120, 0x2160, 0xac8c, 0x0007, + 0x1160, 0xac8a, 0xb800, 0x0248, 0x6858, 0xac02, 0x1230, 0x7124, + 0x610a, 0x2009, 0x0046, 0x080c, 0x831a, 0x0005, 0x00c6, 0x7110, + 0xd1bc, 0x1904, 0x6539, 0x2011, 0xb683, 0x2204, 0x8211, 0x220c, + 0x080c, 0x26f6, 0x1904, 0x6539, 0x080c, 0x4dc5, 0x1904, 0x6539, + 0x6612, 0x6516, 0x6000, 0xd0ec, 0x15e0, 0x6204, 0xa294, 0xff00, + 0x8217, 0xa286, 0x0006, 0x0160, 0x080c, 0x58d5, 0x11d0, 0x6204, + 0xa294, 0x00ff, 0xa286, 0x0006, 0x11a0, 0xa295, 0x0600, 0x6206, + 0x00c6, 0x080c, 0x8295, 0x001e, 0x0530, 0x611a, 0x601f, 0x0006, + 0x7120, 0x610a, 0x7130, 0x6152, 0x2009, 0x0044, 0x080c, 0x831a, + 0x00c0, 0x00c6, 0x080c, 0x8295, 0x001e, 0x0198, 0x611a, 0x601f, + 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x1118, 0x6007, 0x0005, + 0x0010, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x6a3c, 0x080c, + 0x6e9e, 0x00ce, 0x0005, 0x2001, 0xb10d, 0x2004, 0xd0ec, 0x0120, + 0x2011, 0x8049, 0x080c, 0x3d5b, 0x00c6, 0x080c, 0x9ae4, 0x001e, + 0x0d80, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6152, + 0x6013, 0x0300, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x69f6, + 0x080c, 0x6e9e, 0x08f0, 0x7110, 0xd1bc, 0x0188, 0x7020, 0x2060, + 0xac84, 0x0007, 0x1160, 0xac82, 0xb800, 0x0248, 0x6858, 0xac02, + 0x1230, 0x7124, 0x610a, 0x2009, 0x0045, 0x080c, 0x831a, 0x0005, + 0x0006, 0x080c, 0x2c87, 0x000e, 0x1168, 0x7110, 0xa18c, 0xff00, + 0x810f, 0xa18e, 0x0000, 0x1130, 0xa084, 0x000f, 0xa08a, 0x0006, + 0x1208, 0x000b, 0x0005, 0x6589, 0x658a, 0x6589, 0x6589, 0x65f3, + 0x65ff, 0x0005, 0x7110, 0xd1bc, 0x0120, 0x702c, 0xd084, 0x0904, + 0x65f2, 0x700c, 0x7108, 0x080c, 0x26f6, 0x1904, 0x65f2, 0x080c, + 0x4dc5, 0x1904, 0x65f2, 0x6612, 0x6516, 0x6204, 0x7110, 0xd1bc, + 0x01f8, 0xa28c, 0x00ff, 0xa186, 0x0004, 0x0118, 0xa186, 0x0006, + 0x15c8, 0x00c6, 0x080c, 0x660b, 0x00ce, 0x0904, 0x65f2, 0x00c6, + 0x080c, 0x8295, 0x001e, 0x05f0, 0x611a, 0x080c, 0x9c35, 0x601f, + 0x0002, 0x7120, 0x610a, 0x2009, 0x0088, 0x080c, 0x831a, 0x0490, + 0xa28c, 0x00ff, 0xa186, 0x0006, 0x0160, 0xa186, 0x0004, 0x0148, + 0xa294, 0xff00, 0x8217, 0xa286, 0x0004, 0x0118, 0xa286, 0x0006, + 0x1188, 0x00c6, 0x080c, 0x8295, 0x001e, 0x01e0, 0x611a, 0x080c, + 0x9c35, 0x601f, 0x0005, 0x7120, 0x610a, 0x2009, 0x0088, 0x080c, + 0x831a, 0x0080, 0x00c6, 0x080c, 0x8295, 0x001e, 0x0158, 0x611a, + 0x080c, 0x9c35, 0x601f, 0x0004, 0x7120, 0x610a, 0x2009, 0x0001, + 0x080c, 0x831a, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x00a1, 0x0130, + 0x7124, 0x610a, 0x2009, 0x0089, 0x080c, 0x831a, 0x0005, 0x7110, + 0xd1bc, 0x0140, 0x0041, 0x0130, 0x7124, 0x610a, 0x2009, 0x008a, + 0x080c, 0x831a, 0x0005, 0x7020, 0x2060, 0xac84, 0x0007, 0x1158, + 0xac82, 0xb800, 0x0240, 0x2001, 0xb116, 0x2004, 0xac02, 0x1218, + 0xa085, 0x0001, 0x0005, 0xa006, 0x0ce8, 0x7110, 0xd1bc, 0x1178, + 0x7024, 0x2060, 0xac84, 0x0007, 0x1150, 0xac82, 0xb800, 0x0238, + 0x6858, 0xac02, 0x1220, 0x2009, 0x0051, 0x080c, 0x831a, 0x0005, + 0x2031, 0x0105, 0x0069, 0x0005, 0x2031, 0x0206, 0x0049, 0x0005, + 0x2031, 0x0207, 0x0029, 0x0005, 0x2031, 0x0213, 0x0009, 0x0005, + 0x00c6, 0x00d6, 0x00f6, 0x7000, 0xa084, 0xf000, 0xa086, 0xc000, + 0x05b0, 0x080c, 0x8295, 0x0598, 0x0066, 0x00c6, 0x0046, 0x2011, + 0xb683, 0x2204, 0x8211, 0x220c, 0x080c, 0x26f6, 0x1580, 0x080c, + 0x4dc5, 0x1568, 0x6612, 0x6516, 0x2c00, 0x004e, 0x00ce, 0x601a, + 0x080c, 0x9c35, 0x080c, 0x15dd, 0x01f0, 0x2d00, 0x6056, 0x6803, + 0x0000, 0x6837, 0x0000, 0x6c3a, 0xadf8, 0x000f, 0x20a9, 0x000e, + 0x2fa0, 0x2e98, 0x53a3, 0x006e, 0x6612, 0x6007, 0x003e, 0x601f, + 0x0001, 0x6003, 0x0001, 0x080c, 0x6a3c, 0x080c, 0x6e9e, 0x00fe, + 0x00de, 0x00ce, 0x0005, 0x080c, 0x82eb, 0x006e, 0x0cc0, 0x004e, + 0x00ce, 0x0cc8, 0x2071, 0xb3ec, 0x7003, 0x0003, 0x700f, 0x0361, + 0xa006, 0x701a, 0x7012, 0x7017, 0xb800, 0x7007, 0x0000, 0x7026, + 0x702b, 0x7a99, 0x7032, 0x7037, 0x7af9, 0x703b, 0xffff, 0x703f, + 0xffff, 0x7042, 0x7047, 0x42c1, 0x704a, 0x705b, 0x67d1, 0x2001, + 0xb3a0, 0x2003, 0x0003, 0x2001, 0xb3a2, 0x2003, 0x0100, 0x3a00, + 0xa084, 0x0005, 0x706e, 0x0005, 0x2071, 0xb3ec, 0x1d04, 0x6731, + 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x1518, 0x700f, 0x0361, + 0x7007, 0x0001, 0x0126, 0x2091, 0x8000, 0x7040, 0xa00d, 0x0128, + 0x8109, 0x7142, 0x1110, 0x7044, 0x080f, 0x00c6, 0x2061, 0xb100, + 0x6034, 0x00ce, 0xd0cc, 0x0180, 0x3a00, 0xa084, 0x0005, 0x726c, + 0xa216, 0x0150, 0x706e, 0x2011, 0x8043, 0x2018, 0x080c, 0x3d5b, + 0x0018, 0x0126, 0x2091, 0x8000, 0x7024, 0xa00d, 0x0188, 0x7020, + 0x8001, 0x7022, 0x1168, 0x7023, 0x0009, 0x8109, 0x7126, 0xa186, + 0x03e8, 0x1110, 0x7028, 0x080f, 0x81ff, 0x1110, 0x7028, 0x080f, + 0x7030, 0xa00d, 0x0158, 0x702c, 0x8001, 0x702e, 0x1138, 0x702f, + 0x0009, 0x8109, 0x7132, 0x1110, 0x7034, 0x080f, 0x7038, 0xa005, + 0x0118, 0x0310, 0x8001, 0x703a, 0x703c, 0xa005, 0x0118, 0x0310, + 0x8001, 0x703e, 0x704c, 0xa00d, 0x0168, 0x7048, 0x8001, 0x704a, + 0x1148, 0x704b, 0x0009, 0x8109, 0x714e, 0x1120, 0x7150, 0x714e, + 0x7058, 0x080f, 0x7018, 0xa00d, 0x0158, 0x7008, 0x8001, 0x700a, + 0x1138, 0x700b, 0x0009, 0x8109, 0x711a, 0x1110, 0x701c, 0x080f, + 0x012e, 0x7004, 0x0002, 0x6757, 0x6758, 0x6770, 0x00e6, 0x2071, + 0xb3ec, 0x7018, 0xa005, 0x1120, 0x711a, 0x721e, 0x700b, 0x0009, + 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0xb3ec, 0x701c, 0xa206, + 0x1110, 0x701a, 0x701e, 0x000e, 0x00ee, 0x0005, 0x00e6, 0x2071, + 0xb3ec, 0x6088, 0xa102, 0x0208, 0x618a, 0x00ee, 0x0005, 0x0005, + 0x7110, 0x080c, 0x4e21, 0x1158, 0x6088, 0x8001, 0x0240, 0x608a, + 0x1130, 0x0126, 0x2091, 0x8000, 0x080c, 0x6e9e, 0x012e, 0x8108, + 0xa182, 0x00ff, 0x0218, 0xa00e, 0x7007, 0x0002, 0x7112, 0x0005, + 0x7014, 0x2060, 0x0126, 0x2091, 0x8000, 0x603c, 0xa005, 0x0128, + 0x8001, 0x603e, 0x1110, 0x080c, 0x9b23, 0x6014, 0xa005, 0x0500, + 0x8001, 0x6016, 0x11e8, 0x611c, 0xa186, 0x0003, 0x0118, 0xa186, + 0x0006, 0x11a0, 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0270, + 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, + 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0010, 0x080c, 0x9617, + 0x012e, 0xac88, 0x0018, 0x7116, 0x2001, 0xe800, 0xa102, 0x0220, + 0x7017, 0xb800, 0x7007, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb3ec, + 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, 0x0005, 0x2001, 0xb3f5, + 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb3ec, 0x7132, 0x702f, + 0x0009, 0x00ee, 0x0005, 0x2011, 0xb3f8, 0x2013, 0x0000, 0x0005, + 0x00e6, 0x2071, 0xb3ec, 0x711a, 0x721e, 0x700b, 0x0009, 0x00ee, + 0x0005, 0x00c6, 0x0026, 0x7054, 0x8000, 0x7056, 0x2061, 0xb3a0, + 0x6008, 0xa086, 0x0000, 0x0158, 0x7068, 0x6032, 0x7064, 0x602e, + 0x7060, 0x602a, 0x705c, 0x6026, 0x2c10, 0x080c, 0x1628, 0x002e, + 0x00ce, 0x0005, 0x00c6, 0x2061, 0xb464, 0x00ce, 0x0005, 0xa184, + 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0xb464, 0x2060, 0x0005, + 0x6854, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, 0xa005, 0x1150, + 0x00c6, 0x2061, 0xb464, 0x6014, 0x00ce, 0xa005, 0x1138, 0x2001, + 0x001e, 0x0020, 0xa08e, 0xffff, 0x1108, 0xa006, 0x8003, 0x800b, + 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, 0x00c0, 0xa18e, 0x00c0, + 0x05b0, 0xd0b4, 0x1138, 0xd0bc, 0x1528, 0x2009, 0x0006, 0x080c, + 0x6868, 0x0005, 0xd0fc, 0x0130, 0xa084, 0x0003, 0x0118, 0xa086, + 0x0003, 0x15c0, 0x6020, 0xd0d4, 0x0130, 0xc0d4, 0x6022, 0x6860, + 0x602a, 0x685c, 0x602e, 0x2009, 0xb174, 0x2104, 0xd084, 0x0128, + 0x2009, 0x0042, 0x080c, 0x831a, 0x0005, 0x2009, 0x0043, 0x080c, + 0x831a, 0x0005, 0xd0fc, 0x0130, 0xa084, 0x0003, 0x0118, 0xa086, + 0x0003, 0x11c0, 0x2009, 0x0042, 0x080c, 0x831a, 0x0005, 0xd0fc, + 0x0150, 0xa084, 0x0003, 0xa08e, 0x0002, 0x0138, 0x2009, 0x0041, + 0x080c, 0x831a, 0x0005, 0x0051, 0x0ce8, 0x2009, 0x0043, 0x080c, + 0x831a, 0x0cc0, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009, 0x0001, + 0x00d6, 0x6010, 0xa0ec, 0xf000, 0x01f0, 0x2068, 0x6952, 0x6800, + 0x6012, 0xa186, 0x0001, 0x1188, 0x694c, 0xa18c, 0x8100, 0xa18e, + 0x8100, 0x1158, 0x00c6, 0x2061, 0xb464, 0x6200, 0xd28c, 0x1120, + 0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x5271, 0x6010, + 0xa06d, 0x190c, 0x67f8, 0x00de, 0x0005, 0x0156, 0x00c6, 0x2061, + 0xb464, 0x6000, 0x81ff, 0x0110, 0xa205, 0x0008, 0xa204, 0x6002, + 0x00ce, 0x015e, 0x0005, 0x6800, 0xd08c, 0x1138, 0x6808, 0xa005, + 0x0120, 0x8001, 0x680a, 0xa085, 0x0001, 0x0005, 0x20a9, 0x0010, + 0xa006, 0x8004, 0x8086, 0x818e, 0x1208, 0xa200, 0x1f04, 0x68aa, + 0x8086, 0x818e, 0x0005, 0x0156, 0x20a9, 0x0010, 0xa005, 0x01b8, + 0xa11a, 0x12a8, 0x8213, 0x818d, 0x0228, 0xa11a, 0x1220, 0x1f04, + 0x68ba, 0x0028, 0xa11a, 0x2308, 0x8210, 0x1f04, 0x68ba, 0x0006, + 0x3200, 0xa084, 0xefff, 0x2080, 0x000e, 0x015e, 0x0005, 0x0006, + 0x3200, 0xa085, 0x1000, 0x0cb8, 0x0126, 0x2091, 0x2800, 0x2079, + 0xb3d9, 0x012e, 0x00d6, 0x2069, 0xb3d9, 0x6803, 0x0005, 0x2069, + 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a, 0x00de, 0x0005, 0x00c6, + 0x6027, 0x0001, 0x7804, 0xa084, 0x0007, 0x0002, 0x68f8, 0x6919, + 0x696c, 0x68fe, 0x6919, 0x68f8, 0x68f6, 0x68f6, 0x080c, 0x14fa, + 0x080c, 0x67b6, 0x080c, 0x6e9e, 0x00ce, 0x0005, 0x62c0, 0x82ff, + 0x1110, 0x00ce, 0x0005, 0x2011, 0x494f, 0x080c, 0x6742, 0x7828, + 0xa092, 0x00c8, 0x1228, 0x8000, 0x782a, 0x080c, 0x4989, 0x0c88, + 0x080c, 0x494f, 0x7807, 0x0003, 0x7827, 0x0000, 0x782b, 0x0000, + 0x0c40, 0x080c, 0x67b6, 0x3c00, 0x0006, 0x2011, 0x0209, 0x20e1, + 0x4000, 0x2214, 0x000e, 0x20e0, 0x82ff, 0x0178, 0x62c0, 0x82ff, + 0x1160, 0x782b, 0x0000, 0x7824, 0xa065, 0x090c, 0x14fa, 0x2009, + 0x0013, 0x080c, 0x831a, 0x00ce, 0x0005, 0x3900, 0xa082, 0xb51c, + 0x1210, 0x080c, 0x8000, 0x00c6, 0x7824, 0xa065, 0x090c, 0x14fa, + 0x7804, 0xa086, 0x0004, 0x0904, 0x69ac, 0x7828, 0xa092, 0x2710, + 0x1230, 0x8000, 0x782a, 0x00ce, 0x080c, 0x7a7f, 0x0c20, 0x6104, + 0xa186, 0x0003, 0x1188, 0x00e6, 0x2071, 0xb100, 0x70dc, 0x00ee, + 0xd08c, 0x0150, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xb100, + 0x080c, 0x4992, 0x00ee, 0x00ce, 0x080c, 0xafee, 0x2009, 0x0014, + 0x080c, 0x831a, 0x00ce, 0x0838, 0x2001, 0xb3f5, 0x2003, 0x0000, + 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, 0xa065, 0x090c, + 0x14fa, 0x2009, 0x0013, 0x080c, 0x836e, 0x00ce, 0x0005, 0x00c6, + 0x00d6, 0x3900, 0xa082, 0xb51c, 0x1210, 0x080c, 0x8000, 0x7824, + 0xa005, 0x090c, 0x14fa, 0x781c, 0xa06d, 0x090c, 0x14fa, 0x6800, + 0xc0dc, 0x6802, 0x7924, 0x2160, 0x080c, 0x82eb, 0x693c, 0x81ff, + 0x090c, 0x14fa, 0x8109, 0x693e, 0x6854, 0xa015, 0x0110, 0x7a1e, + 0x0010, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x00de, + 0x00ce, 0x080c, 0x6e9e, 0x0888, 0x6104, 0xa186, 0x0002, 0x0128, + 0xa186, 0x0004, 0x0110, 0x0804, 0x6945, 0x7808, 0xac06, 0x0904, + 0x6945, 0x080c, 0x6dc1, 0x080c, 0x6a3c, 0x00ce, 0x080c, 0x6e9e, + 0x0804, 0x6933, 0x00c6, 0x6027, 0x0002, 0x62c8, 0x60c4, 0xa205, + 0x1178, 0x793c, 0xa1e5, 0x0000, 0x0130, 0x2009, 0x0049, 0x080c, + 0x831a, 0x00ce, 0x0005, 0x2011, 0xb3f8, 0x2013, 0x0000, 0x0cc8, + 0x3908, 0xa192, 0xb51c, 0x1210, 0x080c, 0x8000, 0x793c, 0x81ff, + 0x0d90, 0x793c, 0xa188, 0x0007, 0x210c, 0xa18e, 0x0006, 0x1138, + 0x6014, 0xa084, 0x0184, 0xa085, 0x0012, 0x6016, 0x0c10, 0x6014, + 0xa084, 0x0184, 0xa085, 0x0016, 0x6016, 0x08d8, 0x0006, 0x0016, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, + 0xb3d9, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0148, 0xa080, + 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, + 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069, 0xb3d9, 0x6000, 0xd0d4, + 0x0168, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, 0x1110, 0x2c00, + 0x681e, 0x6804, 0xa084, 0x0007, 0x0804, 0x6ea4, 0xc0d5, 0x6002, + 0x6818, 0xa005, 0x0158, 0x6056, 0x605b, 0x0000, 0x0006, 0x2c00, + 0x681a, 0x00de, 0x685a, 0x2069, 0xb3d9, 0x0c18, 0x6056, 0x605a, + 0x2c00, 0x681a, 0x681e, 0x08e8, 0x0006, 0x0016, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb3d9, 0x6020, + 0x8000, 0x6022, 0x6008, 0xa005, 0x0148, 0xa080, 0x0003, 0x2102, + 0x610a, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, 0x610e, 0x610a, + 0x0cc0, 0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb3d9, 0x6034, + 0xa005, 0x0130, 0xa080, 0x0003, 0x2102, 0x6136, 0x00ce, 0x0005, + 0x613a, 0x6136, 0x0cd8, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, + 0x0066, 0x0026, 0x0016, 0x0006, 0x0126, 0x2071, 0xb3d9, 0x7638, + 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904, 0x6ad7, 0x6018, + 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6ad2, 0x87ff, 0x0120, + 0x6050, 0xa106, 0x1904, 0x6ad2, 0x703c, 0xac06, 0x1170, 0x0036, + 0x2019, 0x0001, 0x080c, 0x7cc4, 0x7033, 0x0000, 0x703f, 0x0000, + 0x7043, 0x0000, 0x7047, 0x0000, 0x003e, 0x7038, 0xac36, 0x1110, + 0x660c, 0x763a, 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, + 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, + 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, + 0x986a, 0x0198, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x1510, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x9ada, 0x080c, + 0xaf46, 0x080c, 0x5271, 0x080c, 0x9a1f, 0x080c, 0x9a2b, 0x00ce, + 0x0804, 0x6a7c, 0x2c78, 0x600c, 0x2060, 0x0804, 0x6a7c, 0x012e, + 0x000e, 0x001e, 0x002e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x19d0, 0x080c, 0xaf46, + 0x080c, 0xac5f, 0x0c10, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x00f6, + 0x2031, 0x0000, 0x0126, 0x2091, 0x8000, 0x2079, 0xb3d9, 0x7838, + 0xa065, 0x0558, 0x600c, 0x0006, 0x600f, 0x0000, 0x783c, 0xac06, + 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7cc4, 0x7833, 0x0000, + 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000, 0x003e, 0x080c, + 0x986a, 0x0178, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x11b0, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x5271, 0x080c, + 0x9a1f, 0x080c, 0x9a2b, 0x000e, 0x0898, 0x7e3a, 0x7e36, 0x012e, + 0x00fe, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c, 0xa086, + 0x0006, 0x1d30, 0x080c, 0xac5f, 0x0c60, 0x0016, 0x0026, 0x0086, + 0x2041, 0x0000, 0x0099, 0x080c, 0x6bf7, 0x008e, 0x002e, 0x001e, + 0x0005, 0x00f6, 0x0126, 0x2079, 0xb3d9, 0x2091, 0x8000, 0x080c, + 0x6c84, 0x080c, 0x6cf6, 0x012e, 0x00fe, 0x0005, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126, 0x2091, 0x8000, + 0x2071, 0xb3d9, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0904, 0x6bd3, + 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6bce, 0x88ff, + 0x0120, 0x6050, 0xa106, 0x1904, 0x6bce, 0x7024, 0xac06, 0x1538, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x67b6, 0x080c, + 0x7a8c, 0x68c3, 0x0000, 0x080c, 0x7f1b, 0x7027, 0x0000, 0x0036, + 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, + 0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, 0x04b8, 0x7014, + 0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, + 0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, + 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, + 0x0000, 0x6010, 0x2068, 0x080c, 0x986a, 0x0188, 0x601c, 0xa086, + 0x0003, 0x1510, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, + 0x9ada, 0x080c, 0xaf46, 0x080c, 0x5271, 0x080c, 0x9a1f, 0x080c, + 0x9a2b, 0x080c, 0x7dfb, 0x00ce, 0x0804, 0x6b5d, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x6b5d, 0x012e, 0x000e, 0x001e, 0x006e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x1128, + 0x080c, 0xaf46, 0x080c, 0xac5f, 0x0c10, 0x601c, 0xa086, 0x0002, + 0x1128, 0x6004, 0xa086, 0x0085, 0x0968, 0x08c8, 0x601c, 0xa086, + 0x0005, 0x19a8, 0x6004, 0xa086, 0x0085, 0x0d50, 0x0880, 0x00c6, + 0x0006, 0x0126, 0x2091, 0x8000, 0xa280, 0xb235, 0x2004, 0xa065, + 0x0904, 0x6c80, 0x00f6, 0x00e6, 0x00d6, 0x0066, 0x2071, 0xb3d9, + 0x6654, 0x7018, 0xac06, 0x1108, 0x761a, 0x701c, 0xac06, 0x1130, + 0x86ff, 0x1118, 0x7018, 0x701e, 0x0008, 0x761e, 0x6058, 0xa07d, + 0x0108, 0x7e56, 0xa6ed, 0x0000, 0x0110, 0x2f00, 0x685a, 0x6057, + 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x080c, + 0x4d4c, 0x0904, 0x6c7c, 0x7624, 0x86ff, 0x05e8, 0xa680, 0x0004, + 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0548, 0x080c, 0x67b6, 0x080c, 0x7a8c, 0x68c3, 0x0000, 0x080c, + 0x7f1b, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, + 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, + 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660, 0x080c, 0x9a2b, + 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, + 0x00ce, 0x0804, 0x6c27, 0x8dff, 0x0158, 0x6837, 0x0103, 0x6b4a, + 0x6847, 0x0000, 0x080c, 0x9ada, 0x080c, 0xaf46, 0x080c, 0x5271, + 0x080c, 0x7dfb, 0x0804, 0x6c27, 0x006e, 0x00de, 0x00ee, 0x00fe, + 0x012e, 0x000e, 0x00ce, 0x0005, 0x0006, 0x0066, 0x00c6, 0x00d6, + 0x2031, 0x0000, 0x7814, 0xa065, 0x0904, 0x6cd6, 0x600c, 0x0006, + 0x600f, 0x0000, 0x7824, 0xac06, 0x1540, 0x2069, 0x0100, 0x68c0, + 0xa005, 0x01f0, 0x080c, 0x67b6, 0x080c, 0x7a8c, 0x68c3, 0x0000, + 0x080c, 0x7f1b, 0x7827, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, + 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0028, + 0x6003, 0x0009, 0x630a, 0x2c30, 0x00b0, 0x6010, 0x2068, 0x080c, + 0x986a, 0x0168, 0x601c, 0xa086, 0x0003, 0x11b8, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x080c, 0x5271, 0x080c, 0x9a1f, 0x080c, + 0x9a2b, 0x080c, 0x7dfb, 0x000e, 0x0804, 0x6c8b, 0x7e16, 0x7e12, + 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c, 0xa086, 0x0006, + 0x1118, 0x080c, 0xac5f, 0x0c58, 0x601c, 0xa086, 0x0002, 0x1128, + 0x6004, 0xa086, 0x0085, 0x09d0, 0x0c10, 0x601c, 0xa086, 0x0005, + 0x19f0, 0x6004, 0xa086, 0x0085, 0x0d60, 0x08c8, 0x0006, 0x0066, + 0x00c6, 0x00d6, 0x7818, 0xa065, 0x0904, 0x6d5c, 0x6054, 0x0006, + 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, + 0x080c, 0x4d4c, 0x0904, 0x6d59, 0x7e24, 0x86ff, 0x05e8, 0xa680, + 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069, 0x0100, 0x68c0, + 0xa005, 0x0548, 0x080c, 0x67b6, 0x080c, 0x7a8c, 0x68c3, 0x0000, + 0x080c, 0x7f1b, 0x7827, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, + 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, + 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660, 0x080c, + 0x9a2b, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003, 0x0009, + 0x630a, 0x00ce, 0x0804, 0x6d08, 0x8dff, 0x0138, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x080c, 0x5271, 0x080c, 0x7dfb, 0x0804, + 0x6d08, 0x000e, 0x0804, 0x6cfb, 0x781e, 0x781a, 0x00de, 0x00ce, + 0x006e, 0x000e, 0x0005, 0x00e6, 0x00d6, 0x0066, 0x6000, 0xd0dc, + 0x0188, 0x604c, 0xa06d, 0x0170, 0x6848, 0xa606, 0x1158, 0x2071, + 0xb3d9, 0x7024, 0xa035, 0x0130, 0xa080, 0x0004, 0x2004, 0xad06, + 0x1108, 0x0021, 0x006e, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x2079, + 0x0100, 0x78c0, 0xa005, 0x1138, 0x00c6, 0x2660, 0x6003, 0x0009, + 0x630a, 0x00ce, 0x04a0, 0x080c, 0x7a8c, 0x78c3, 0x0000, 0x080c, + 0x7f1b, 0x7027, 0x0000, 0x0036, 0x2079, 0x0140, 0x7b04, 0xa384, + 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, + 0x7824, 0xd084, 0x0110, 0x7827, 0x0001, 0x080c, 0x7f1b, 0x003e, + 0x080c, 0x4d4c, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, + 0x2660, 0x080c, 0x82eb, 0x00ce, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x9ada, 0x080c, 0x5271, 0x080c, 0x7dfb, 0x00fe, + 0x0005, 0x00e6, 0x00c6, 0x2071, 0xb3d9, 0x7004, 0xa084, 0x0007, + 0x0002, 0x6dd3, 0x6dd6, 0x6dec, 0x6e05, 0x6e3e, 0x6dd3, 0x6dd1, + 0x6dd1, 0x080c, 0x14fa, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, + 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0150, 0x7216, + 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, + 0x0005, 0x7216, 0x7212, 0x0cb0, 0x6018, 0x2060, 0x080c, 0x4d4c, + 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, 0x0120, 0x6054, + 0xa015, 0x0140, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, + 0x00ee, 0x0005, 0x7218, 0x721e, 0x0cb0, 0x7024, 0xa065, 0x0598, + 0x700c, 0xac06, 0x1160, 0x080c, 0x7dfb, 0x600c, 0xa015, 0x0120, + 0x720e, 0x600f, 0x0000, 0x0428, 0x720e, 0x720a, 0x0410, 0x7014, + 0xac06, 0x1160, 0x080c, 0x7dfb, 0x600c, 0xa015, 0x0120, 0x7216, + 0x600f, 0x0000, 0x00b0, 0x7216, 0x7212, 0x0098, 0x6018, 0x2060, + 0x080c, 0x4d4c, 0x6000, 0xc0dc, 0x6002, 0x080c, 0x7dfb, 0x701c, + 0xa065, 0x0138, 0x6054, 0xa015, 0x0110, 0x721e, 0x0010, 0x7218, + 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, + 0x0140, 0x080c, 0x7dfb, 0x600c, 0xa015, 0x0150, 0x720e, 0x600f, + 0x0000, 0x080c, 0x7f1b, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, + 0x720e, 0x720a, 0x0cb0, 0x00d6, 0x2069, 0xb3d9, 0x6830, 0xa084, + 0x0003, 0x0002, 0x6e60, 0x6e62, 0x6e86, 0x6e5e, 0x080c, 0x14fa, + 0x00de, 0x0005, 0x00c6, 0x6840, 0xa086, 0x0001, 0x01b8, 0x683c, + 0xa065, 0x0130, 0x600c, 0xa015, 0x0170, 0x6a3a, 0x600f, 0x0000, + 0x6833, 0x0000, 0x683f, 0x0000, 0x2011, 0xb3f8, 0x2013, 0x0000, + 0x00ce, 0x00de, 0x0005, 0x683a, 0x6836, 0x0c90, 0x6843, 0x0000, + 0x6838, 0xa065, 0x0d68, 0x6003, 0x0003, 0x0c50, 0x00c6, 0x6843, + 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0168, 0x600c, 0xa015, + 0x0130, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, 0x0020, 0x683f, + 0x0000, 0x683a, 0x6836, 0x00ce, 0x00de, 0x0005, 0x00d6, 0x2069, + 0xb3d9, 0x6804, 0xa084, 0x0007, 0x0002, 0x6eaf, 0x6f4b, 0x6f4b, + 0x6f4b, 0x6f4b, 0x6f4d, 0x6ead, 0x6ead, 0x080c, 0x14fa, 0x6820, + 0xa005, 0x1110, 0x00de, 0x0005, 0x00c6, 0x680c, 0xa065, 0x0150, + 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x080c, 0x6f9b, 0x00ce, + 0x00de, 0x0005, 0x6814, 0xa065, 0x0150, 0x6807, 0x0001, 0x6826, + 0x682b, 0x0000, 0x080c, 0x6f9b, 0x00ce, 0x00de, 0x0005, 0x00e6, + 0x0036, 0x6a1c, 0xa2f5, 0x0000, 0x0904, 0x6f47, 0x704c, 0xa00d, + 0x0118, 0x7088, 0xa005, 0x01a0, 0x7054, 0xa075, 0x0120, 0xa20e, + 0x0904, 0x6f47, 0x0028, 0x6818, 0xa20e, 0x0904, 0x6f47, 0x2070, + 0x704c, 0xa00d, 0x0d88, 0x7088, 0xa005, 0x1d70, 0x2e00, 0x681e, + 0x733c, 0x7038, 0xa302, 0x1e40, 0x080c, 0x82c2, 0x0904, 0x6f47, + 0x8318, 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, + 0xa084, 0x00ff, 0x605a, 0xa180, 0x0014, 0x2003, 0x0000, 0xa180, + 0x0015, 0x2004, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, 0x8003, + 0x801b, 0x831b, 0xa318, 0x6316, 0x003e, 0x00f6, 0x2c78, 0x71a0, + 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1110, 0xd1bc, 0x0150, 0x7100, + 0xd1f4, 0x0120, 0x7114, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, + 0x0028, 0xa1e0, 0x2c8c, 0x2c0d, 0xa18c, 0x00ff, 0x2061, 0x0100, + 0x619a, 0x080c, 0x75c4, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, + 0x2f18, 0x6b26, 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, + 0x7807, 0x0040, 0x00fe, 0x00ee, 0x00ce, 0x00de, 0x0005, 0x003e, + 0x00ee, 0x00ce, 0x0cd0, 0x00de, 0x0005, 0x00c6, 0x680c, 0xa065, + 0x0138, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x080c, 0x6f9b, + 0x00ce, 0x00de, 0x0005, 0x00f6, 0x00d6, 0x2069, 0xb3d9, 0x6830, + 0xa086, 0x0000, 0x11c0, 0x2001, 0xb10c, 0x200c, 0xd1bc, 0x1550, + 0x6838, 0xa07d, 0x0180, 0x6833, 0x0001, 0x683e, 0x6847, 0x0000, + 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, 0x1f3c, 0x1130, + 0x012e, 0x080c, 0x78fd, 0x00de, 0x00fe, 0x0005, 0x012e, 0xe000, + 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, 0xa015, 0x0140, 0x6a3a, + 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c60, 0x683a, + 0x6836, 0x0cc0, 0xc1bc, 0x2102, 0x0066, 0x2031, 0x0001, 0x080c, + 0x5957, 0x006e, 0x0868, 0x601c, 0xa084, 0x000f, 0x000b, 0x0005, + 0x6fa9, 0x6fae, 0x7465, 0x7581, 0x6fae, 0x7465, 0x7581, 0x6fa9, + 0x6fae, 0x080c, 0x6dc1, 0x080c, 0x6e9e, 0x0005, 0x0156, 0x0136, + 0x0146, 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14fa, + 0x6118, 0x2178, 0x79a0, 0x2011, 0xb134, 0x2214, 0xd2ac, 0x1110, + 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, + 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8, 0x2c8c, 0x2f0d, 0xa18c, + 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x1a04, + 0x7022, 0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, + 0x70d1, 0x711c, 0x7149, 0x7216, 0x7244, 0x724c, 0x7272, 0x7283, + 0x7294, 0x729c, 0x72b2, 0x729c, 0x730c, 0x7283, 0x732d, 0x7335, + 0x7294, 0x7335, 0x7346, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, + 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7b6d, 0x7b92, + 0x7ba7, 0x7bca, 0x7beb, 0x7272, 0x7020, 0x7272, 0x729c, 0x7020, + 0x7149, 0x7216, 0x7020, 0x801d, 0x729c, 0x7020, 0x803d, 0x729c, + 0x7020, 0x7294, 0x70ca, 0x7035, 0x7020, 0x8062, 0x80d7, 0x81ae, + 0x7020, 0x81bf, 0x726d, 0x81db, 0x7020, 0x7c00, 0x8236, 0x7020, + 0x080c, 0x14fa, 0x2100, 0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, + 0x015e, 0x0005, 0x7033, 0x7033, 0x7033, 0x7069, 0x7087, 0x709d, + 0x7033, 0x7033, 0x7033, 0x080c, 0x14fa, 0x00d6, 0x20a1, 0x020b, + 0x080c, 0x7363, 0x7810, 0x2068, 0x20a3, 0x2414, 0x20a3, 0x0018, + 0x20a3, 0x0800, 0x683c, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6850, 0x20a2, 0x6854, 0x20a2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, 0x7a79, + 0x00de, 0x0005, 0x00d6, 0x7818, 0x2068, 0x68a0, 0x2069, 0xb100, + 0x6ad0, 0xd2ac, 0x1110, 0xd0bc, 0x0110, 0xa085, 0x0001, 0x00de, + 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x7363, 0x20a3, 0x0500, + 0x20a3, 0x0000, 0x7810, 0xa0e8, 0x000f, 0x6808, 0x20a2, 0x680c, + 0x20a2, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x6818, 0x20a2, 0x681c, + 0x20a2, 0x60c3, 0x0010, 0x080c, 0x7a79, 0x00de, 0x0005, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x7363, 0x20a3, 0x7800, 0x20a3, + 0x0000, 0x7808, 0x8007, 0x20a2, 0x20a3, 0x0000, 0x60c3, 0x0008, + 0x080c, 0x7a79, 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, + 0x020b, 0x080c, 0x73ff, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, + 0xdf10, 0x20a3, 0x0034, 0x2099, 0xb105, 0x20a9, 0x0004, 0x53a6, + 0x2099, 0xb101, 0x20a9, 0x0004, 0x53a6, 0x2099, 0xb3bf, 0x20a9, + 0x001a, 0x3304, 0x8007, 0x20a2, 0x9398, 0x1f04, 0x70b9, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x004c, 0x080c, 0x7a79, 0x014e, + 0x015e, 0x0005, 0x2001, 0xb114, 0x2004, 0x609a, 0x080c, 0x7a79, + 0x0005, 0x20a1, 0x020b, 0x080c, 0x7363, 0x20a3, 0x5200, 0x20a3, + 0x0000, 0x00d6, 0x2069, 0xb152, 0x6804, 0xd084, 0x0150, 0x6828, + 0x20a3, 0x0000, 0x0016, 0x080c, 0x270a, 0x21a2, 0x001e, 0x00de, + 0x0028, 0x00de, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, + 0x2099, 0xb105, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb101, 0x53a6, + 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa082, 0x007f, 0x0238, 0x2001, 0xb11b, 0x20a6, 0x2001, + 0xb11c, 0x20a6, 0x0040, 0x20a3, 0x0000, 0x2001, 0xb114, 0x2004, + 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x001c, 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7363, + 0x20a3, 0x0500, 0x20a3, 0x0000, 0x2001, 0xb134, 0x2004, 0xd0ac, + 0x1138, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0238, + 0x2001, 0xb11b, 0x20a6, 0x2001, 0xb11c, 0x20a6, 0x0040, 0x20a3, + 0x0000, 0x2001, 0xb114, 0x2004, 0xa084, 0x00ff, 0x20a2, 0x20a9, + 0x0004, 0x2099, 0xb105, 0x53a6, 0x60c3, 0x0010, 0x080c, 0x7a79, + 0x0005, 0x20a1, 0x020b, 0x080c, 0x7363, 0x00c6, 0x7818, 0x2060, + 0x2001, 0x0000, 0x080c, 0x5185, 0x00ce, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa086, 0x007e, 0x1130, 0x20a3, 0x0400, 0x620c, 0xc2b4, + 0x620e, 0x0010, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, + 0x0028, 0x2004, 0xa086, 0x007e, 0x1904, 0x71d8, 0x2001, 0xb134, + 0x2004, 0xd0a4, 0x01c8, 0x2099, 0xb38e, 0x33a6, 0x9398, 0x20a3, + 0x0000, 0x9398, 0x3304, 0xa084, 0x2000, 0x20a2, 0x9398, 0x33a6, + 0x9398, 0x20a3, 0x0000, 0x9398, 0x2001, 0x2710, 0x20a2, 0x9398, + 0x33a6, 0x9398, 0x33a6, 0x00d0, 0x2099, 0xb38e, 0x33a6, 0x9398, + 0x33a6, 0x9398, 0x3304, 0x080c, 0x58d5, 0x1118, 0xa084, 0x37ff, + 0x0010, 0xa084, 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, + 0x2099, 0xb105, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb101, 0x53a6, + 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x71b2, 0x20a9, 0x0008, + 0x20a3, 0x0000, 0x1f04, 0x71b8, 0x2099, 0xb396, 0x3304, 0xc0dd, + 0x20a2, 0x2001, 0xb172, 0x2004, 0xd0e4, 0x0158, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x9398, 0x9398, 0x9398, 0x33a6, 0x20a9, 0x0004, + 0x0010, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x1f04, 0x71d3, 0x0468, + 0x2001, 0xb134, 0x2004, 0xd0a4, 0x0140, 0x2001, 0xb38f, 0x2004, + 0x60e3, 0x0000, 0x080c, 0x274b, 0x60e2, 0x2099, 0xb38e, 0x20a9, + 0x0008, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb105, 0x53a6, 0x20a9, + 0x0004, 0x2099, 0xb101, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, + 0x1f04, 0x71f6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x71fc, + 0x2099, 0xb396, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, + 0x0000, 0x1f04, 0x7207, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x1f04, + 0x720d, 0x60c3, 0x0074, 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, + 0x080c, 0x7363, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, + 0x20a3, 0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x00f6, 0x2079, 0xb152, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0xa085, + 0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010, 0xa085, 0x0002, 0x00d6, + 0x0804, 0x72ee, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7363, + 0x20a3, 0x5000, 0x0804, 0x7164, 0x20a1, 0x020b, 0x080c, 0x7363, + 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x73f7, 0x0020, 0x20a1, 0x020b, 0x080c, 0x73ff, 0x20a3, 0x0200, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, + 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, 0x080c, 0x73ff, 0x20a3, + 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, + 0x0008, 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, 0x080c, 0x73ff, + 0x20a3, 0x0200, 0x0804, 0x7164, 0x20a1, 0x020b, 0x080c, 0x73ff, + 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0xa005, 0x0110, 0x20a2, + 0x0010, 0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, + 0x7a79, 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x73ff, 0x20a3, + 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818, 0x2068, 0x6894, + 0xa086, 0x0014, 0x1178, 0x6998, 0xa184, 0xc000, 0x1140, 0xd1ec, + 0x0118, 0x20a3, 0x2100, 0x0040, 0x20a3, 0x0100, 0x0028, 0x20a3, + 0x0400, 0x0010, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a2, 0x00f6, 0x2079, 0xb152, 0x7904, 0x00fe, 0xd1ac, + 0x1110, 0xa085, 0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010, 0x2009, + 0xb174, 0x210c, 0xd184, 0x1110, 0xa085, 0x0002, 0x0026, 0x2009, + 0xb172, 0x210c, 0xd1e4, 0x0130, 0xc0c5, 0xa094, 0x0030, 0xa296, + 0x0010, 0x0140, 0xd1ec, 0x0130, 0xa094, 0x0030, 0xa296, 0x0010, + 0x0108, 0xc0bd, 0x002e, 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x0014, + 0x080c, 0x7a79, 0x00de, 0x0005, 0x20a1, 0x020b, 0x080c, 0x73ff, + 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0100, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x73ff, 0x20a3, 0x0200, 0x0804, 0x70d7, 0x20a1, 0x020b, 0x080c, + 0x73ff, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, + 0x2a00, 0x60c3, 0x0008, 0x080c, 0x7a79, 0x0005, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x20a1, 0x020b, 0x080c, 0x73ff, 0x20a3, 0x0100, + 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, 0x0008, + 0x080c, 0x7a79, 0x0005, 0x0026, 0x0036, 0x0046, 0x2019, 0x3200, + 0x2021, 0x0800, 0x0038, 0x0026, 0x0036, 0x0046, 0x2019, 0x2200, + 0x2021, 0x0100, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, + 0x0028, 0x2014, 0xa286, 0x007e, 0x11a0, 0xa385, 0x00ff, 0x20a2, + 0x20a3, 0xfffe, 0x20a3, 0x0000, 0x2011, 0xb114, 0x2214, 0x2001, + 0xb39e, 0x2004, 0xa005, 0x0118, 0x2011, 0xb11c, 0x2214, 0x22a2, + 0x04d0, 0xa286, 0x007f, 0x1138, 0x00d6, 0xa385, 0x00ff, 0x20a2, + 0x20a3, 0xfffd, 0x00c8, 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1110, + 0xd2bc, 0x01c8, 0xa286, 0x0080, 0x00d6, 0x1130, 0xa385, 0x00ff, + 0x20a2, 0x20a3, 0xfffc, 0x0040, 0xa2e8, 0xb235, 0x2d6c, 0x6810, + 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb11b, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x0080, 0x00d6, 0xa2e8, 0xb235, 0x2d6c, 0x6810, + 0xa305, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, + 0xb114, 0x2214, 0x22a2, 0xa485, 0x0029, 0x20a2, 0x004e, 0x003e, + 0x20a3, 0x0000, 0x080c, 0x7a68, 0x22a2, 0x20a3, 0x0000, 0x2fa2, + 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, + 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, + 0xfffc, 0x22a2, 0x00d6, 0x2069, 0xb11b, 0x2da6, 0x8d68, 0x2da6, + 0x00de, 0x20a3, 0x2029, 0x20a3, 0x0000, 0x08e0, 0x20a3, 0x0100, + 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x0005, 0x0026, + 0x0036, 0x0046, 0x2019, 0x3300, 0x2021, 0x0800, 0x0038, 0x0026, + 0x0036, 0x0046, 0x2019, 0x2300, 0x2021, 0x0100, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb134, + 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x02d8, 0x00d6, 0xa0e8, + 0xb235, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x6810, + 0xa005, 0x1140, 0x6814, 0xa005, 0x1128, 0x20a3, 0x00ff, 0x20a3, + 0xfffe, 0x0028, 0x2069, 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0080, 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa305, 0x20a2, + 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb114, 0x2214, + 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3, 0x0000, 0x004e, 0x003e, + 0x080c, 0x7a68, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x080c, 0x7a68, + 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x7810, 0x20a2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00c6, 0x00f6, 0x6004, + 0xa08a, 0x0085, 0x0a0c, 0x14fa, 0xa08a, 0x008c, 0x1a0c, 0x14fa, + 0x6118, 0x2178, 0x79a0, 0x2011, 0xb134, 0x2214, 0xd2ac, 0x1110, + 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, + 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8, 0x2c8c, 0x2f0d, 0xa18c, + 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, 0x001b, + 0x00fe, 0x00ce, 0x0005, 0x749c, 0x74a6, 0x74c1, 0x749a, 0x749a, + 0x749a, 0x749c, 0x080c, 0x14fa, 0x0146, 0x20a1, 0x020b, 0x04a1, + 0x60c3, 0x0000, 0x080c, 0x7a79, 0x014e, 0x0005, 0x0146, 0x20a1, + 0x020b, 0x080c, 0x750d, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, + 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, 0x080c, 0x7a79, 0x014e, + 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, 0x7547, 0x20a3, 0x0003, + 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, + 0x080c, 0x7a79, 0x014e, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb134, 0x2214, + 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, 0xb235, + 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, + 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, + 0xb235, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, + 0x00de, 0x20a3, 0x0000, 0x2011, 0xb114, 0x2214, 0x22a2, 0x20a3, + 0x0009, 0x20a3, 0x0000, 0x0804, 0x73ca, 0x0026, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb134, + 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, + 0xb235, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, + 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, + 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb114, 0x2214, 0x22a2, + 0x2001, 0x0099, 0x20a2, 0x20a3, 0x0000, 0x0804, 0x7456, 0x0026, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, + 0x2011, 0xb134, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, + 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0088, 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x8500, + 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb114, + 0x2214, 0x22a2, 0x2001, 0x0099, 0x20a2, 0x20a3, 0x0000, 0x0804, + 0x7456, 0x00c6, 0x00f6, 0x2c78, 0x7804, 0xa08a, 0x0040, 0x0a0c, + 0x14fa, 0xa08a, 0x0053, 0x1a0c, 0x14fa, 0x7918, 0x2160, 0x61a0, + 0x2011, 0xb134, 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x6100, + 0xd1f4, 0x0120, 0x6114, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, + 0x0028, 0xa1e0, 0x2c8c, 0x2c0d, 0xa18c, 0x00ff, 0x2061, 0x0100, + 0x619a, 0xa082, 0x0040, 0x001b, 0x00fe, 0x00ce, 0x0005, 0x75c4, + 0x76d0, 0x766d, 0x7872, 0x75c2, 0x75c2, 0x75c2, 0x75c2, 0x75c2, + 0x75c2, 0x75c2, 0x7db4, 0x7dc4, 0x7dd4, 0x7de4, 0x75c2, 0x81ec, + 0x75c2, 0x7da3, 0x080c, 0x14fa, 0x00d6, 0x0156, 0x0146, 0x780b, + 0xffff, 0x20a1, 0x020b, 0x080c, 0x7624, 0x7910, 0x2168, 0x6948, + 0x7952, 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, + 0x000f, 0x1118, 0x2001, 0x0005, 0x0040, 0xd184, 0x0118, 0x2001, + 0x0004, 0x0018, 0xa084, 0x0006, 0x8004, 0x0016, 0x2008, 0x7858, + 0xa084, 0x00ff, 0x8007, 0xa105, 0x001e, 0x20a2, 0xd1ac, 0x0118, + 0x20a3, 0x0002, 0x0048, 0xd1b4, 0x0118, 0x20a3, 0x0001, 0x0020, + 0x20a3, 0x0000, 0x2230, 0x0010, 0x6a80, 0x6e7c, 0x20a9, 0x0008, + 0x0136, 0xad88, 0x0017, 0x2198, 0x20a1, 0x021b, 0x53a6, 0x013e, + 0x20a1, 0x020b, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, + 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xb3f5, + 0x2003, 0x07d0, 0x2001, 0xb3f4, 0x2003, 0x0009, 0x080c, 0x17c3, + 0x014e, 0x015e, 0x00de, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, + 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0x2019, 0xb134, 0x231c, + 0xd3ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xb235, 0x2d6c, + 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb11b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb235, + 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x00de, + 0x20a3, 0x0000, 0x2009, 0xb114, 0x210c, 0x21a2, 0x20a3, 0x0829, + 0x20a3, 0x0000, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005, 0x00d6, 0x0156, 0x0136, + 0x0146, 0x20a1, 0x020b, 0x00c1, 0x7810, 0x2068, 0x6860, 0x20a2, + 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x000c, 0x080c, 0x7a79, 0x014e, + 0x013e, 0x015e, 0x00de, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb134, 0x2214, + 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xb235, 0x2d6c, + 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb11b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb235, + 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, 0x00de, + 0x20a3, 0x0000, 0x2011, 0xb114, 0x2214, 0x22a2, 0x20a3, 0x0889, + 0x20a3, 0x0000, 0x080c, 0x7a68, 0x22a2, 0x20a3, 0x0000, 0x7a08, + 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, + 0x00d6, 0x0156, 0x0136, 0x0146, 0x7810, 0xa0ec, 0xf000, 0x0168, + 0xa06d, 0x080c, 0x5173, 0x0148, 0x684c, 0xa084, 0x2020, 0xa086, + 0x2020, 0x1118, 0x7820, 0xc0cd, 0x7822, 0x20a1, 0x020b, 0x080c, + 0x7828, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, + 0xa084, 0xf000, 0x1130, 0x7810, 0xa084, 0x0700, 0x8007, 0x0043, + 0x0010, 0xa006, 0x002b, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, + 0x770a, 0x779f, 0x77a8, 0x77d1, 0x77e4, 0x77ff, 0x7808, 0x7708, + 0x080c, 0x14fa, 0x0016, 0x0036, 0x694c, 0xa18c, 0x0003, 0x0118, + 0xa186, 0x0003, 0x1170, 0x6b78, 0x7820, 0xd0cc, 0x0108, 0xc3e5, + 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x003e, 0x001e, 0x0804, + 0x77db, 0xa186, 0x0001, 0x190c, 0x14fa, 0x6b78, 0x7820, 0xd0cc, + 0x0108, 0xc3e5, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, + 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, + 0x0300, 0x0904, 0x7799, 0xd3c4, 0x0110, 0x687c, 0xa108, 0xd3cc, + 0x0110, 0x6874, 0xa108, 0x0156, 0x20a9, 0x000d, 0xad80, 0x0020, + 0x201c, 0x831f, 0x23a2, 0x8000, 0x1f04, 0x7748, 0x015e, 0x22a2, + 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0904, 0x7799, 0x20a1, 0x020b, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x0006, 0x7818, 0xa080, 0x0028, + 0x2004, 0x2011, 0xb134, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, + 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0088, 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x0700, + 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb114, + 0x2214, 0x22a2, 0x000e, 0x7b20, 0xd3cc, 0x0118, 0x20a3, 0x0889, + 0x0010, 0x20a3, 0x0898, 0x20a2, 0x080c, 0x7a68, 0x22a2, 0x20a3, + 0x0000, 0x61c2, 0x003e, 0x001e, 0x080c, 0x7a79, 0x0005, 0x2011, + 0x0008, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0488, + 0x2011, 0x0302, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, + 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500, + 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x080c, 0x7a79, + 0x0005, 0x2011, 0x0028, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, + 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, + 0x0018, 0x080c, 0x7a79, 0x0005, 0x2011, 0x0100, 0x7820, 0xd0cc, + 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x7854, 0xa084, 0x00ff, 0x20a2, + 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x080c, 0x7a79, 0x0005, 0x2011, + 0x0008, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0888, + 0x0036, 0x7b10, 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, + 0x1138, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0x003e, 0x0808, + 0x0046, 0x2021, 0x0800, 0x0006, 0x7820, 0xd0cc, 0x000e, 0x0108, + 0xc4e5, 0x24a2, 0x004e, 0x22a2, 0x20a2, 0x003e, 0x0804, 0x77db, + 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0x2011, 0xb134, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, + 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0088, 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x0700, + 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb114, + 0x2214, 0x22a2, 0x7820, 0xd0cc, 0x0118, 0x20a3, 0x0889, 0x0010, + 0x20a3, 0x0898, 0x20a3, 0x0000, 0x080c, 0x7a68, 0x22a2, 0x20a3, + 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x0016, 0x0036, + 0x7810, 0xa084, 0x0700, 0x8007, 0x003b, 0x003e, 0x001e, 0x014e, + 0x013e, 0x015e, 0x00de, 0x0005, 0x788c, 0x788c, 0x788e, 0x788c, + 0x788c, 0x788c, 0x78b0, 0x788c, 0x080c, 0x14fa, 0x7910, 0xa18c, + 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, + 0x00f9, 0x00d6, 0x2069, 0xb152, 0x6804, 0xd0bc, 0x0130, 0x682c, + 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0010, 0x20a3, 0x3f00, 0x00de, + 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, 0x080c, 0x7a79, 0x0005, + 0x20a1, 0x020b, 0x2009, 0x0003, 0x0019, 0x20a3, 0x7f00, 0x0c80, + 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0x2011, 0xb134, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, + 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0088, 0x00d6, 0xa0e8, 0xb235, 0x2d6c, 0x6810, 0xa085, 0x0100, + 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb114, + 0x2214, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x080c, + 0x7a68, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x00c6, + 0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0xb100, 0x7150, + 0x7818, 0x2068, 0x68a0, 0x2028, 0x76d0, 0xd6ac, 0x1130, 0xd0bc, + 0x1120, 0x6910, 0x6a14, 0x7450, 0x0020, 0x6910, 0x6a14, 0x736c, + 0x7470, 0x781c, 0xa0be, 0x0006, 0x0904, 0x79b3, 0xa0be, 0x000a, + 0x15e8, 0xa185, 0x0200, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, + 0x2029, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, + 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, + 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, + 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0x609f, 0x0000, 0x080c, 0x8287, 0x2009, 0x07d0, 0x60c4, 0xa084, + 0xfff0, 0xa005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x67bb, 0x003e, + 0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x70d0, 0xd0ac, + 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, + 0x646e, 0x0038, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, + 0x646e, 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, + 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, + 0x7808, 0x6086, 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, + 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, + 0x60d7, 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, + 0x6a14, 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, + 0x8287, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005, 0x0110, + 0x2009, 0x1b58, 0x080c, 0x67bb, 0x003e, 0x004e, 0x005e, 0x00ce, + 0x00de, 0x00ee, 0x0005, 0x7810, 0x2070, 0x704c, 0xa084, 0x0003, + 0xa086, 0x0002, 0x0904, 0x7a09, 0x2001, 0xb134, 0x2004, 0xd0ac, + 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, + 0x646e, 0x0038, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, + 0x646e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, + 0x00ff, 0x688e, 0x8007, 0x607a, 0x7834, 0x607e, 0x2f00, 0x6086, + 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, + 0x707c, 0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, 0x7928, + 0xa109, 0x792a, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, + 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, 0x8284, 0x0804, + 0x79a1, 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, + 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x0038, 0xa185, + 0x0700, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x080c, 0x5173, + 0x0180, 0x00d6, 0x7810, 0xa06d, 0x684c, 0x00de, 0xa084, 0x2020, + 0xa086, 0x2020, 0x1130, 0x7820, 0xc0cd, 0x7822, 0x6073, 0x0889, + 0x0010, 0x6073, 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, + 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, + 0x7808, 0x6082, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, + 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, + 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x7820, 0xd0cc, 0x0120, + 0x080c, 0x8287, 0x0804, 0x79a1, 0x080c, 0x8284, 0x0804, 0x79a1, + 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, + 0x8217, 0x0005, 0x00d6, 0x2069, 0xb3d9, 0x6843, 0x0001, 0x00de, + 0x0005, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x0019, + 0x080c, 0x67ad, 0x0005, 0x0006, 0x6014, 0xa084, 0x0004, 0xa085, + 0x0009, 0x6016, 0x000e, 0x0005, 0x0006, 0x00c6, 0x2061, 0x0100, + 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, 0x00ce, 0x000e, + 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x2061, 0x0100, 0x2069, + 0x0140, 0x080c, 0x58d5, 0x1198, 0x2001, 0xb3f5, 0x2004, 0xa005, + 0x15b8, 0x0066, 0x2031, 0x0001, 0x080c, 0x5957, 0x006e, 0x1118, + 0x080c, 0x67ad, 0x0468, 0x00c6, 0x2061, 0xb3d9, 0x00d8, 0x6904, + 0xa194, 0x4000, 0x0550, 0x0881, 0x6803, 0x1000, 0x6803, 0x0000, + 0x00c6, 0x2061, 0xb3d9, 0x6128, 0xa192, 0x00c8, 0x1258, 0x8108, + 0x612a, 0x6124, 0x00ce, 0x81ff, 0x0198, 0x080c, 0x67ad, 0x080c, + 0x7a83, 0x0070, 0x6124, 0xa1e5, 0x0000, 0x0140, 0x080c, 0xafee, + 0x2009, 0x0014, 0x080c, 0x831a, 0x080c, 0x67b6, 0x00ce, 0x0000, + 0x002e, 0x001e, 0x00de, 0x00ce, 0x0005, 0x2001, 0xb3f5, 0x2004, + 0xa005, 0x1db0, 0x00c6, 0x2061, 0xb3d9, 0x6128, 0xa192, 0x0003, + 0x1e08, 0x8108, 0x612a, 0x00ce, 0x080c, 0x67ad, 0x080c, 0x4992, + 0x0c38, 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x0026, 0x080c, 0x67c3, + 0x2071, 0xb3d9, 0x713c, 0x81ff, 0x0590, 0x2061, 0x0100, 0x2069, + 0x0140, 0x080c, 0x58d5, 0x11a8, 0x0036, 0x2019, 0x0002, 0x080c, + 0x7cc4, 0x003e, 0x713c, 0x2160, 0x080c, 0xafee, 0x2009, 0x004a, + 0x080c, 0x831a, 0x0066, 0x2031, 0x0001, 0x080c, 0x5957, 0x006e, + 0x00b0, 0x6904, 0xa194, 0x4000, 0x01c0, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0036, 0x2019, 0x0001, 0x080c, 0x7cc4, 0x003e, 0x713c, + 0x2160, 0x080c, 0xafee, 0x2009, 0x004a, 0x080c, 0x831a, 0x002e, + 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0c58, 0x00e6, 0x00d6, + 0x00c6, 0x0066, 0x0056, 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, + 0x6018, 0x2068, 0x6ca0, 0x2071, 0xb3d9, 0x7018, 0x2068, 0x8dff, + 0x0198, 0x68a0, 0xa406, 0x0118, 0x6854, 0x2068, 0x0cc0, 0x6010, + 0x2060, 0x643c, 0x6540, 0x6648, 0x2d60, 0x080c, 0x4f8e, 0x0120, + 0x080c, 0x7dfb, 0xa085, 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, + 0x006e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x7363, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c, + 0xa086, 0x0004, 0x1110, 0x6098, 0x0018, 0x2001, 0xb114, 0x2004, + 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006, + 0x20a2, 0x1f04, 0x7b88, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x080c, + 0x7a79, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x7363, + 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, + 0x60c3, 0x0008, 0x080c, 0x7a79, 0x014e, 0x015e, 0x0005, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x73ff, 0x20a3, 0x0200, 0x20a3, + 0x0000, 0x20a9, 0x0006, 0x2011, 0xb140, 0x2019, 0xb141, 0x23a6, + 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x1f04, 0x7bb7, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x7a79, 0x014e, + 0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, + 0x080c, 0x73d8, 0x080c, 0x73ee, 0x7810, 0xa080, 0x0000, 0x2004, + 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, + 0xa080, 0x0004, 0x8003, 0x60c2, 0x080c, 0x7a79, 0x002e, 0x001e, + 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, + 0x7363, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, + 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7a79, 0x014e, 0x015e, 0x0005, + 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, 0x080c, 0x7363, + 0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808, + 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x080c, 0x7a79, + 0x002e, 0x001e, 0x014e, 0x015e, 0x0005, 0x00e6, 0x00c6, 0x0006, + 0x0126, 0x2091, 0x8000, 0x2071, 0xb3d9, 0x700c, 0x2060, 0x8cff, + 0x0178, 0x080c, 0x9a66, 0x1110, 0x080c, 0x8890, 0x600c, 0x0006, + 0x080c, 0x9c2d, 0x080c, 0x82eb, 0x080c, 0x7dfb, 0x00ce, 0x0c78, + 0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x000e, 0x00ce, 0x00ee, + 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026, + 0x0016, 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, + 0x2071, 0xb3d9, 0x7024, 0x2060, 0x8cff, 0x05a0, 0x080c, 0x7a8c, + 0x68c3, 0x0000, 0x080c, 0x67b6, 0x2009, 0x0013, 0x080c, 0x831a, + 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, + 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, + 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x7c62, 0x7804, + 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, + 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, + 0x012e, 0x0005, 0x2001, 0xb100, 0x2004, 0xa096, 0x0001, 0x0550, + 0xa096, 0x0004, 0x0538, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, + 0x494f, 0x080c, 0x6742, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, + 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, + 0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, + 0x1f04, 0x7c9d, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, + 0x7803, 0x0000, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x015e, 0x012e, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, 0x2069, + 0x0100, 0x2079, 0x0140, 0x2071, 0xb3d9, 0x703c, 0x2060, 0x8cff, + 0x0904, 0x7d48, 0x6814, 0xa084, 0x0002, 0x0904, 0x7d48, 0x68af, + 0x95f5, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x1df0, 0x68c7, + 0x0000, 0x68cb, 0x0008, 0x080c, 0x67c3, 0x080c, 0x2120, 0x0046, + 0x2009, 0x017f, 0x200b, 0x00a5, 0x2021, 0x0169, 0x2404, 0xa084, + 0x000f, 0xa086, 0x0004, 0x1500, 0x68af, 0x95f5, 0x68c7, 0x0000, + 0x68cb, 0x0008, 0x00e6, 0x00f6, 0x2079, 0x0020, 0x2071, 0xb43a, + 0x6814, 0xa084, 0x0184, 0xa085, 0x0012, 0x6816, 0x7803, 0x0008, + 0x7003, 0x0000, 0x00fe, 0x00ee, 0xa386, 0x0002, 0x1128, 0x7884, + 0xa005, 0x1110, 0x7887, 0x0001, 0x2001, 0xb3b0, 0x2004, 0x200a, + 0x004e, 0xa39d, 0x0000, 0x1120, 0x2009, 0x0049, 0x080c, 0x831a, + 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, + 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, + 0xd08c, 0x0118, 0x6827, 0x0002, 0x0010, 0x1f04, 0x7d2a, 0x7804, + 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, + 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, + 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0xb3d9, + 0x6a06, 0x012e, 0x00de, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x2069, 0xb3d9, 0x6a32, 0x012e, 0x00de, 0x0005, 0x00f6, 0x00e6, + 0x00c6, 0x0066, 0x0006, 0x0126, 0x2071, 0xb3d9, 0x7614, 0x2660, + 0x2678, 0x2091, 0x8000, 0x8cff, 0x0538, 0x601c, 0xa206, 0x1500, + 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, + 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, + 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, + 0x600f, 0x0000, 0x080c, 0x9a2b, 0x080c, 0x7dfb, 0x00ce, 0x08d8, + 0x2c78, 0x600c, 0x2060, 0x08b8, 0x012e, 0x000e, 0x006e, 0x00ce, + 0x00ee, 0x00fe, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, + 0x7624, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x20a3, 0x1000, 0x0804, 0x7df3, 0x0156, 0x0146, 0x20a1, 0x020b, + 0x080c, 0x7624, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a3, 0x4000, 0x0478, 0x0156, 0x0146, 0x20a1, 0x020b, + 0x080c, 0x7624, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a3, 0x2000, 0x00f8, 0x0156, 0x0146, 0x20a1, 0x020b, + 0x080c, 0x7624, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a3, 0x0400, 0x0078, 0x0156, 0x0146, 0x20a1, 0x020b, + 0x080c, 0x7624, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a3, 0x0200, 0x0089, 0x60c3, 0x0020, 0x080c, 0x7a79, + 0x014e, 0x015e, 0x0005, 0x00e6, 0x2071, 0xb3d9, 0x7020, 0xa005, + 0x0110, 0x8001, 0x7022, 0x00ee, 0x0005, 0x20a9, 0x0008, 0x20a2, + 0x1f04, 0x7e07, 0x20a2, 0x20a2, 0x0005, 0x00f6, 0x00e6, 0x00d6, + 0x00c6, 0x0076, 0x0066, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, + 0xb3d9, 0x7614, 0x2660, 0x2678, 0x2039, 0x0001, 0x87ff, 0x0904, + 0x7e97, 0x8cff, 0x0904, 0x7e97, 0x601c, 0xa086, 0x0006, 0x1904, + 0x7e92, 0x88ff, 0x0138, 0x2800, 0xac06, 0x1904, 0x7e92, 0x2039, + 0x0000, 0x0050, 0x6018, 0xa206, 0x1904, 0x7e92, 0x85ff, 0x0120, + 0x6050, 0xa106, 0x1904, 0x7e92, 0x7024, 0xac06, 0x1538, 0x2069, + 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x67b6, 0x6817, 0x0008, + 0x68c3, 0x0000, 0x080c, 0x7f1b, 0x7027, 0x0000, 0x0036, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, + 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, + 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, 0x0460, 0x7014, 0xac36, + 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, + 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, + 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x89ff, 0x1158, + 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x986a, 0x0110, 0x080c, + 0xac5f, 0x080c, 0x9a2b, 0x080c, 0x7dfb, 0x88ff, 0x1190, 0x00ce, + 0x0804, 0x7e1e, 0x2c78, 0x600c, 0x2060, 0x0804, 0x7e1e, 0xa006, + 0x012e, 0x000e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, + 0x0005, 0x6017, 0x0000, 0x00ce, 0xa8c5, 0x0001, 0x0c88, 0x00f6, + 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, + 0x8000, 0x2071, 0xb3d9, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0904, + 0x7f0b, 0x601c, 0xa086, 0x0006, 0x1904, 0x7f06, 0x87ff, 0x0128, + 0x2700, 0xac06, 0x1904, 0x7f06, 0x0040, 0x6018, 0xa206, 0x15f0, + 0x85ff, 0x0118, 0x6050, 0xa106, 0x15c8, 0x703c, 0xac06, 0x1170, + 0x0036, 0x2019, 0x0001, 0x080c, 0x7cc4, 0x7033, 0x0000, 0x703f, + 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x003e, 0x7038, 0xac36, + 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, + 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, + 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, + 0x6010, 0x2068, 0x080c, 0x986a, 0x0110, 0x080c, 0xac5f, 0x080c, + 0x9a2b, 0x87ff, 0x1190, 0x00ce, 0x0804, 0x7eb6, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x7eb6, 0xa006, 0x012e, 0x000e, 0x002e, 0x006e, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6017, 0x0000, 0x00ce, + 0xa7bd, 0x0001, 0x0c88, 0x00e6, 0x2071, 0xb3d9, 0x2001, 0xb100, + 0x2004, 0xa086, 0x0002, 0x1118, 0x7007, 0x0005, 0x0010, 0x7007, + 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0026, + 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xb3d9, 0x2c10, 0x7638, + 0x2660, 0x2678, 0x8cff, 0x0518, 0x2200, 0xac06, 0x11e0, 0x7038, + 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, 0x1140, 0x2c00, + 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, + 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, + 0xa085, 0x0001, 0x0020, 0x2c78, 0x600c, 0x2060, 0x08d8, 0x012e, + 0x000e, 0x002e, 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00f6, + 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0006, 0x0126, 0x2091, 0x8000, + 0x2071, 0xb3d9, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0904, 0x7ff1, + 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x7fec, 0x7024, + 0xac06, 0x1508, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0904, 0x7fc8, + 0x080c, 0x7a8c, 0x68c3, 0x0000, 0x080c, 0x7f1b, 0x7027, 0x0000, + 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, + 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, + 0x6827, 0x0001, 0x003e, 0x700c, 0xac36, 0x1110, 0x660c, 0x760e, + 0x7008, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x700a, + 0x0010, 0x700b, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0x9a55, 0x1158, + 0x080c, 0x2b99, 0x080c, 0x9a66, 0x11f0, 0x080c, 0x8890, 0x00d8, + 0x080c, 0x7f1b, 0x08c0, 0x080c, 0x9a66, 0x1118, 0x080c, 0x8890, + 0x0090, 0x6010, 0x2068, 0x080c, 0x986a, 0x0168, 0x601c, 0xa086, + 0x0003, 0x11f8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, + 0x5271, 0x080c, 0x9a1f, 0x080c, 0x9c2d, 0x080c, 0x9a2b, 0x080c, + 0x7dfb, 0x00ce, 0x0804, 0x7f75, 0x2c78, 0x600c, 0x2060, 0x0804, + 0x7f75, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, + 0x0005, 0x601c, 0xa086, 0x0006, 0x1d30, 0x080c, 0xac5f, 0x0c18, + 0x0036, 0x0156, 0x0136, 0x0146, 0x3908, 0xa006, 0xa190, 0x0020, + 0x221c, 0xa39e, 0x2990, 0x1118, 0x8210, 0x8000, 0x0cc8, 0xa005, + 0x0138, 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, 0x22c8, 0x53a3, + 0x014e, 0x013e, 0x015e, 0x003e, 0x0005, 0x00d6, 0x20a1, 0x020b, + 0x080c, 0x73ff, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2099, 0xb3b8, 0x20a9, 0x0004, + 0x53a6, 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x080c, 0x7a79, 0x00de, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x73ff, 0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, + 0xa084, 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, + 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, + 0x7a79, 0x0005, 0x00d6, 0x0016, 0x2f68, 0x2009, 0x0035, 0x080c, + 0x9d16, 0x1904, 0x80d0, 0x20a1, 0x020b, 0x080c, 0x7363, 0x20a3, + 0x1300, 0x20a3, 0x0000, 0x7828, 0x2068, 0x681c, 0xa086, 0x0003, + 0x0580, 0x7818, 0xa080, 0x0028, 0x2014, 0x2001, 0xb134, 0x2004, + 0xd0ac, 0x11d0, 0xa286, 0x007e, 0x1128, 0x20a3, 0x00ff, 0x20a3, + 0xfffe, 0x04b8, 0xa286, 0x007f, 0x1128, 0x20a3, 0x00ff, 0x20a3, + 0xfffd, 0x0478, 0xd2bc, 0x0180, 0xa286, 0x0080, 0x1128, 0x20a3, + 0x00ff, 0x20a3, 0xfffc, 0x0428, 0xa2e8, 0xb235, 0x2d6c, 0x6810, + 0x20a2, 0x6814, 0x20a2, 0x00e8, 0x20a3, 0x0000, 0x6098, 0x20a2, + 0x00c0, 0x2001, 0xb134, 0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, + 0x0028, 0x2004, 0xa082, 0x007e, 0x0240, 0x00d6, 0x2069, 0xb11b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0020, 0x20a3, 0x0000, 0x6034, + 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x000c, 0x080c, 0x7a79, 0x001e, 0x00de, 0x0005, + 0x7817, 0x0001, 0x7803, 0x0006, 0x001e, 0x00de, 0x0005, 0x00d6, + 0x0026, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006, 0x01c0, 0xa186, + 0x0003, 0x0904, 0x8146, 0xa186, 0x0005, 0x0904, 0x812f, 0xa186, + 0x0004, 0x05b8, 0xa186, 0x0008, 0x0904, 0x8137, 0x7807, 0x0037, + 0x7813, 0x1700, 0x080c, 0x81ae, 0x002e, 0x00de, 0x0005, 0x080c, + 0x816a, 0x2009, 0x4000, 0x6800, 0x0002, 0x8110, 0x811b, 0x8112, + 0x811b, 0x8117, 0x8110, 0x8110, 0x811b, 0x811b, 0x811b, 0x811b, + 0x8110, 0x8110, 0x8110, 0x8110, 0x8110, 0x811b, 0x8110, 0x811b, + 0x080c, 0x14fa, 0x6820, 0xd0e4, 0x0110, 0xd0cc, 0x0110, 0xa00e, + 0x0010, 0x2009, 0x2000, 0x6828, 0x20a2, 0x682c, 0x20a2, 0x0804, + 0x8160, 0x080c, 0x816a, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, + 0x4000, 0x6a00, 0xa286, 0x0002, 0x1108, 0xa00e, 0x0488, 0x04d1, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, 0x0448, 0x0491, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, 0xa286, 0x0005, + 0x0118, 0xa286, 0x0002, 0x1108, 0xa00e, 0x00d0, 0x0419, 0x6810, + 0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814, 0xa103, 0x20a2, + 0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e, 0x0002, 0x0130, + 0xa08e, 0x0004, 0x0118, 0x2009, 0x4000, 0x0010, 0x2009, 0x0000, + 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, 0x7a79, 0x002e, + 0x00de, 0x0005, 0x0036, 0x0046, 0x0056, 0x0066, 0x20a1, 0x020b, + 0x080c, 0x73ff, 0xa006, 0x20a3, 0x0200, 0x20a2, 0x7934, 0x21a2, + 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb134, + 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0268, 0x00d6, 0x2069, + 0xb11b, 0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xb235, 0x2d6c, 0x6b10, + 0x6c14, 0x00de, 0x0030, 0x2019, 0x0000, 0x6498, 0x2029, 0x0000, + 0x6634, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086, 0x0003, 0x1128, + 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0020, 0x23a2, 0x24a2, 0x25a2, + 0x26a2, 0x006e, 0x005e, 0x004e, 0x003e, 0x0005, 0x20a1, 0x020b, + 0x080c, 0x73ff, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0009, + 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7a79, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x735b, 0x20a3, 0x1400, 0x20a3, 0x0000, 0x7834, + 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c, 0x20a2, 0x7830, + 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000, 0x60c3, 0x0010, + 0x080c, 0x7a79, 0x0005, 0x20a1, 0x020b, 0x080c, 0x73f7, 0x20a3, + 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810, 0x20a2, 0x60c3, + 0x0008, 0x080c, 0x7a79, 0x0005, 0x0146, 0x20a1, 0x020b, 0x0031, + 0x60c3, 0x0000, 0x080c, 0x7a79, 0x014e, 0x0005, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb134, + 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xb235, + 0x2d6c, 0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, + 0xb11b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0078, 0x00d6, 0xa0e8, + 0xb235, 0x2d6c, 0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, + 0x00de, 0x20a3, 0x0000, 0x6234, 0x22a2, 0x20a3, 0x0819, 0x20a3, + 0x0000, 0x080c, 0x7a68, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x7a08, + 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005, 0x20a1, 0x020b, + 0x0079, 0x7910, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0000, 0x20e1, + 0x9080, 0x60a7, 0x9575, 0x080c, 0x7a83, 0x080c, 0x67ad, 0x0005, + 0x0156, 0x0136, 0x0036, 0x00d6, 0x00e6, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x7854, 0x2068, 0xadf0, 0x000f, 0x7210, 0xa296, 0x00c0, + 0xa294, 0xfffd, 0x7212, 0x7214, 0xa294, 0x0300, 0x7216, 0x7100, + 0xa194, 0x00ff, 0x7308, 0xa384, 0x00ff, 0xa08d, 0xc200, 0x7102, + 0xa384, 0xff00, 0xa215, 0x720a, 0x7004, 0x720c, 0x700e, 0x7206, + 0x20a9, 0x000a, 0x2e98, 0x53a6, 0x60a3, 0x0035, 0x6a38, 0xa294, + 0x7000, 0xa286, 0x3000, 0x0110, 0x60a3, 0x0037, 0x00ee, 0x00de, + 0x003e, 0x013e, 0x015e, 0x0005, 0x2009, 0x0092, 0x0010, 0x2009, + 0x0096, 0x60ab, 0x0036, 0x6116, 0x0005, 0x2061, 0xb800, 0x2a70, + 0x7064, 0x7046, 0x704b, 0xb800, 0x0005, 0x00e6, 0x0126, 0x2071, + 0xb100, 0x2091, 0x8000, 0x7544, 0xa582, 0x0010, 0x0608, 0x7048, + 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x0018, 0x7058, + 0xac02, 0x1208, 0x0cb0, 0x2061, 0xb800, 0x0c98, 0x6003, 0x0008, + 0x8529, 0x7546, 0xaca8, 0x0018, 0x7058, 0xa502, 0x1230, 0x754a, + 0xa085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704b, 0xb800, 0x0cc0, + 0xa006, 0x0cc0, 0x00e6, 0x2071, 0xb100, 0x7544, 0xa582, 0x0010, + 0x0600, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, + 0x0018, 0x7058, 0xac02, 0x1208, 0x0cb0, 0x2061, 0xb800, 0x0c98, + 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0018, 0x7058, 0xa502, + 0x1228, 0x754a, 0xa085, 0x0001, 0x00ee, 0x0005, 0x704b, 0xb800, + 0x0cc8, 0xa006, 0x0cc8, 0xac82, 0xb800, 0x0a0c, 0x14fa, 0x2001, + 0xb116, 0x2004, 0xac02, 0x1a0c, 0x14fa, 0xa006, 0x6006, 0x600a, + 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, 0x6003, 0x0000, + 0x6052, 0x6056, 0x6022, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036, + 0x603a, 0x603e, 0x2061, 0xb100, 0x6044, 0x8000, 0x6046, 0xa086, + 0x0001, 0x0108, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x6e9e, + 0x012e, 0x0cc0, 0x601c, 0xa084, 0x000f, 0x0002, 0x8329, 0x8338, + 0x8353, 0x836e, 0x9d43, 0x9d5e, 0x9d79, 0x8329, 0x8338, 0x8329, + 0x8389, 0xa186, 0x0013, 0x1128, 0x080c, 0x6dc1, 0x080c, 0x6e9e, + 0x0005, 0xa18e, 0x0047, 0x1118, 0xa016, 0x080c, 0x1828, 0x0005, + 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14fa, 0x0013, 0x006e, + 0x0005, 0x8351, 0x8722, 0x88ca, 0x8351, 0x893f, 0x8442, 0x8351, + 0x8351, 0x86b4, 0x8d40, 0x8351, 0x8351, 0x8351, 0x8351, 0x8351, + 0x8351, 0x080c, 0x14fa, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, + 0x14fa, 0x0013, 0x006e, 0x0005, 0x836c, 0x935a, 0x836c, 0x836c, + 0x836c, 0x836c, 0x836c, 0x836c, 0x9305, 0x94c0, 0x836c, 0x9387, + 0x93fe, 0x9387, 0x93fe, 0x836c, 0x080c, 0x14fa, 0x0066, 0x6000, + 0xa0b2, 0x0010, 0x1a0c, 0x14fa, 0x0013, 0x006e, 0x0005, 0x8387, + 0x8d81, 0x8e47, 0x8f75, 0x90cf, 0x8387, 0x8387, 0x8387, 0x8d5b, + 0x92b5, 0x92b8, 0x8387, 0x8387, 0x8387, 0x8387, 0x92e2, 0x080c, + 0x14fa, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14fa, 0x0013, + 0x006e, 0x0005, 0x83a2, 0x83a2, 0x83a2, 0x83c5, 0x8418, 0x83a2, + 0x83a2, 0x83a2, 0x83a4, 0x83a2, 0x83a2, 0x83a2, 0x83a2, 0x83a2, + 0x83a2, 0x83a2, 0x080c, 0x14fa, 0xa186, 0x0003, 0x190c, 0x14fa, + 0x00d6, 0x6003, 0x0003, 0x6106, 0x6010, 0x2068, 0x684f, 0x0040, + 0x687c, 0x680a, 0x6880, 0x680e, 0x6813, 0x0000, 0x6817, 0x0000, + 0x00de, 0x2c10, 0x080c, 0x1ec4, 0x080c, 0x6a59, 0x0126, 0x2091, + 0x8000, 0x080c, 0x6f5b, 0x012e, 0x0005, 0xa182, 0x0047, 0x0002, + 0x83d1, 0x83d1, 0x83d3, 0x83f2, 0x83d1, 0x83d1, 0x83d1, 0x83d1, + 0x8404, 0x080c, 0x14fa, 0x00d6, 0x0016, 0x080c, 0x6e53, 0x080c, + 0x6f5b, 0x6003, 0x0004, 0x6110, 0x2168, 0x6854, 0x8003, 0x800b, + 0x810b, 0xa108, 0x6116, 0x684f, 0x0020, 0x685c, 0x685a, 0x6874, + 0x687e, 0x6878, 0x6882, 0x6897, 0x0000, 0x689b, 0x0000, 0x001e, + 0x00de, 0x0005, 0x080c, 0x6e53, 0x00d6, 0x6110, 0x2168, 0x080c, + 0x986a, 0x0120, 0x684b, 0x0006, 0x080c, 0x5271, 0x00de, 0x080c, + 0x82eb, 0x080c, 0x6f5b, 0x0005, 0x080c, 0x6e53, 0x080c, 0x2b73, + 0x00d6, 0x6110, 0x2168, 0x080c, 0x986a, 0x0120, 0x684b, 0x0029, + 0x080c, 0x5271, 0x00de, 0x080c, 0x82eb, 0x080c, 0x6f5b, 0x0005, + 0xa182, 0x0047, 0x0002, 0x8426, 0x8435, 0x8424, 0x8424, 0x8424, + 0x8424, 0x8424, 0x8424, 0x8424, 0x080c, 0x14fa, 0x00d6, 0x6010, + 0x2068, 0x684c, 0xc0f4, 0x684e, 0x00de, 0x20e1, 0x0005, 0x3d18, + 0x3e20, 0x2c10, 0x080c, 0x1828, 0x0005, 0x00d6, 0x6110, 0x2168, + 0x684b, 0x0000, 0x6853, 0x0000, 0x080c, 0x5271, 0x00de, 0x080c, + 0x82eb, 0x0005, 0xa1b6, 0x0015, 0x1118, 0x080c, 0x82eb, 0x0030, + 0xa1b6, 0x0016, 0x190c, 0x14fa, 0x080c, 0x82eb, 0x0005, 0x20a9, + 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, + 0x3420, 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, + 0x0002, 0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x1f04, + 0x845d, 0x00e6, 0x080c, 0x986a, 0x0130, 0x6010, 0x2070, 0x7007, + 0x0000, 0x7037, 0x0103, 0x00ee, 0x080c, 0x82eb, 0x0005, 0x00d6, + 0x0036, 0x7330, 0xa386, 0x0200, 0x1130, 0x6018, 0x2068, 0x6813, + 0x00ff, 0x6817, 0xfffd, 0x6010, 0xa005, 0x0130, 0x2068, 0x6807, + 0x0000, 0x6837, 0x0103, 0x6b32, 0x080c, 0x82eb, 0x003e, 0x00de, + 0x0005, 0x0016, 0x20a9, 0x002a, 0xae80, 0x000c, 0x2098, 0x6010, + 0xa080, 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, 0x6010, 0xa080, + 0x0001, 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x00e6, 0x6010, + 0x2004, 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x82eb, 0x001e, + 0x0005, 0x0016, 0x2009, 0x0000, 0x7030, 0xa086, 0x0100, 0x0140, + 0x7038, 0xa084, 0x00ff, 0x808e, 0x703c, 0xa084, 0x00ff, 0x8086, + 0xa080, 0x0004, 0xa108, 0x21a8, 0xae80, 0x000c, 0x2098, 0x6010, + 0xa080, 0x0002, 0x20a0, 0x080c, 0x4a04, 0x00e6, 0x080c, 0x986a, + 0x0140, 0x6010, 0x2070, 0x7007, 0x0000, 0x7034, 0x70b2, 0x7037, + 0x0103, 0x00ee, 0x080c, 0x82eb, 0x001e, 0x0005, 0x00e6, 0x00d6, + 0x603f, 0x0000, 0x2c68, 0x0016, 0x2009, 0x0035, 0x080c, 0x9d16, + 0x001e, 0x1168, 0x0026, 0x6228, 0x2268, 0x002e, 0x2071, 0xb68c, + 0x6b1c, 0xa386, 0x0003, 0x0130, 0xa386, 0x0006, 0x0128, 0x080c, + 0x82eb, 0x0020, 0x0031, 0x0010, 0x080c, 0x85ba, 0x00de, 0x00ee, + 0x0005, 0x00f6, 0x6810, 0x2078, 0xa186, 0x0015, 0x0904, 0x85a3, + 0xa18e, 0x0016, 0x1904, 0x85b8, 0x700c, 0xa084, 0xff00, 0xa086, + 0x1700, 0x1904, 0x8582, 0x8fff, 0x1138, 0x6800, 0xa086, 0x000f, + 0x0904, 0x8566, 0x0804, 0x85b6, 0x6808, 0xa086, 0xffff, 0x1904, + 0x85a5, 0x784c, 0xa084, 0x0060, 0xa086, 0x0020, 0x1150, 0x797c, + 0x7810, 0xa106, 0x1904, 0x85a5, 0x7980, 0x7814, 0xa106, 0x1904, + 0x85a5, 0x080c, 0x9a1f, 0x6858, 0x7852, 0x784c, 0xc0dc, 0xc0f4, + 0xc0d4, 0x784e, 0x0026, 0xa00e, 0x6a14, 0x2001, 0x000a, 0x080c, + 0x68b3, 0x7854, 0xa20a, 0x0208, 0x8011, 0x7a56, 0x82ff, 0x002e, + 0x1138, 0x00c6, 0x2d60, 0x080c, 0x963b, 0x00ce, 0x0804, 0x85b6, + 0x00c6, 0x00d6, 0x2f68, 0x6838, 0xd0fc, 0x1118, 0x080c, 0x4ad9, + 0x0010, 0x080c, 0x4cc1, 0x00de, 0x00ce, 0x1904, 0x85a5, 0x00c6, + 0x2d60, 0x080c, 0x82eb, 0x00ce, 0x0804, 0x85b6, 0x00c6, 0x080c, + 0x9ae4, 0x0190, 0x6013, 0x0000, 0x6818, 0x601a, 0x080c, 0x9c35, + 0x601f, 0x0003, 0x6904, 0x00c6, 0x2d60, 0x080c, 0x82eb, 0x00ce, + 0x080c, 0x831a, 0x00ce, 0x04d0, 0x2001, 0xb3b7, 0x2004, 0x683e, + 0x00ce, 0x04a0, 0x7008, 0xa086, 0x000b, 0x11a0, 0x6018, 0x200c, + 0xc1bc, 0x2102, 0x00c6, 0x2d60, 0x7853, 0x0003, 0x6007, 0x0085, + 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x69f6, 0x080c, 0x6e9e, + 0x00ce, 0x00e0, 0x700c, 0xa086, 0x2a00, 0x1138, 0x2001, 0xb3b7, + 0x2004, 0x683e, 0x0098, 0x0471, 0x0098, 0x8fff, 0x090c, 0x14fa, + 0x00c6, 0x00d6, 0x2d60, 0x2f68, 0x684b, 0x0003, 0x080c, 0x952f, + 0x080c, 0x9a1f, 0x080c, 0x9a2b, 0x00de, 0x00ce, 0x080c, 0x82eb, + 0x00fe, 0x0005, 0xa186, 0x0015, 0x1128, 0x2001, 0xb3b7, 0x2004, + 0x683e, 0x0068, 0xa18e, 0x0016, 0x1160, 0x00c6, 0x2d00, 0x2060, + 0x080c, 0xaf00, 0x080c, 0x6866, 0x080c, 0x82eb, 0x00ce, 0x080c, + 0x82eb, 0x0005, 0x0026, 0x0036, 0x0046, 0x7228, 0x7c80, 0x7b7c, + 0xd2f4, 0x0130, 0x2001, 0xb3b7, 0x2004, 0x683e, 0x0804, 0x8634, + 0x00c6, 0x2d60, 0x080c, 0x954f, 0x00ce, 0x6804, 0xa086, 0x0050, + 0x1168, 0x00c6, 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007, 0x0050, + 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x00ce, 0x04f0, 0x6800, 0xa086, + 0x000f, 0x01c8, 0x8fff, 0x090c, 0x14fa, 0x6820, 0xd0dc, 0x1198, + 0x6800, 0xa086, 0x0004, 0x1198, 0x784c, 0xd0ac, 0x0180, 0x784c, + 0xc0dc, 0xc0f4, 0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852, 0x2001, + 0x0001, 0x682e, 0x00e0, 0x2001, 0x0007, 0x682e, 0x00c0, 0x784c, + 0xd0b4, 0x1130, 0xd0ac, 0x0db8, 0x784c, 0xd0f4, 0x1da0, 0x0c38, + 0xd2ec, 0x1d88, 0x7024, 0xa306, 0x1118, 0x7020, 0xa406, 0x0d58, + 0x7020, 0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e, 0x080c, + 0x9b71, 0x080c, 0x6e9e, 0x0010, 0x080c, 0x82eb, 0x004e, 0x003e, + 0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x6034, 0x2068, 0x6a1c, + 0xa286, 0x0007, 0x0904, 0x8698, 0xa286, 0x0002, 0x0904, 0x8698, + 0xa286, 0x0000, 0x0904, 0x8698, 0x6808, 0x6338, 0xa306, 0x1904, + 0x8698, 0x2071, 0xb68c, 0xa186, 0x0015, 0x05e0, 0xa18e, 0x0016, + 0x1190, 0x6030, 0xa084, 0x00ff, 0xa086, 0x0001, 0x1160, 0x700c, + 0xa086, 0x2a00, 0x1140, 0x6034, 0xa080, 0x0008, 0x200c, 0xc1dd, + 0xc1f5, 0x2102, 0x0438, 0x00c6, 0x6034, 0x2060, 0x6104, 0xa186, + 0x004b, 0x01a0, 0xa186, 0x004c, 0x0188, 0xa186, 0x004d, 0x0170, + 0xa186, 0x004e, 0x0158, 0xa186, 0x0052, 0x0140, 0x6010, 0x2068, + 0x080c, 0x986a, 0x090c, 0x14fa, 0x6853, 0x0003, 0x6007, 0x0085, + 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x69f6, 0x080c, 0x6e9e, + 0x00ce, 0x0030, 0x6034, 0x2070, 0x2001, 0xb3b7, 0x2004, 0x703e, + 0x080c, 0x82eb, 0x002e, 0x00de, 0x00ee, 0x0005, 0x00d6, 0x20a9, + 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x1148, + 0x6018, 0x2068, 0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, + 0x6802, 0x00de, 0x0804, 0x8469, 0x2100, 0xa1b2, 0x0080, 0x1a0c, + 0x14fa, 0xa1b2, 0x0040, 0x1a04, 0x8718, 0x0002, 0x870c, 0x8700, + 0x870c, 0x870c, 0x870c, 0x870c, 0x86fe, 0x86fe, 0x86fe, 0x86fe, + 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, + 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, + 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x870c, 0x86fe, 0x870c, + 0x870c, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x870c, 0x86fe, + 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, + 0x870c, 0x870c, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, 0x86fe, + 0x86fe, 0x86fe, 0x86fe, 0x870c, 0x86fe, 0x86fe, 0x080c, 0x14fa, + 0x6003, 0x0001, 0x6106, 0x080c, 0x6a3c, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6e9e, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, + 0x6a3c, 0x0126, 0x2091, 0x8000, 0x080c, 0x6e9e, 0x012e, 0x0005, + 0x2600, 0x0002, 0x870c, 0x870c, 0x8720, 0x870c, 0x870c, 0x8720, + 0x080c, 0x14fa, 0x6004, 0xa0b2, 0x0080, 0x1a0c, 0x14fa, 0xa1b6, + 0x0013, 0x0904, 0x87c2, 0xa1b6, 0x0027, 0x1904, 0x8788, 0x080c, + 0x6dc1, 0x6004, 0x080c, 0x9a55, 0x0188, 0x080c, 0x9a66, 0x0904, + 0x8782, 0xa08e, 0x0021, 0x0904, 0x8785, 0xa08e, 0x0022, 0x0904, + 0x8782, 0xa08e, 0x003d, 0x0904, 0x8785, 0x04a8, 0x080c, 0x2b99, + 0x2001, 0x0007, 0x080c, 0x4d75, 0x6018, 0xa080, 0x0028, 0x200c, + 0x080c, 0x8890, 0xa186, 0x007e, 0x1148, 0x2001, 0xb134, 0x2014, + 0xc285, 0x080c, 0x58d5, 0x1108, 0xc2ad, 0x2202, 0x0016, 0x0026, + 0x0036, 0x2110, 0x2019, 0x0028, 0x080c, 0x6b35, 0x0076, 0x2039, + 0x0000, 0x080c, 0x6a6b, 0x00c6, 0x6018, 0xa065, 0x0110, 0x080c, + 0x501c, 0x00ce, 0x2c08, 0x080c, 0xaa51, 0x007e, 0x003e, 0x002e, + 0x001e, 0x080c, 0x4de4, 0x080c, 0x9c2d, 0x080c, 0x82eb, 0x080c, + 0x6e9e, 0x0005, 0x080c, 0x8890, 0x0cb0, 0x080c, 0x88be, 0x0c98, + 0xa186, 0x0014, 0x1db0, 0x080c, 0x6dc1, 0x080c, 0x2b73, 0x080c, + 0x9a55, 0x1188, 0x080c, 0x2b99, 0x6018, 0xa080, 0x0028, 0x200c, + 0x080c, 0x8890, 0xa186, 0x007e, 0x1128, 0x2001, 0xb134, 0x200c, + 0xc185, 0x2102, 0x08c0, 0x080c, 0x9a66, 0x1118, 0x080c, 0x8890, + 0x0890, 0x6004, 0xa08e, 0x0032, 0x1158, 0x00e6, 0x00f6, 0x2071, + 0xb182, 0x2079, 0x0000, 0x080c, 0x2e97, 0x00fe, 0x00ee, 0x0818, + 0x6004, 0xa08e, 0x0021, 0x0d50, 0xa08e, 0x0022, 0x090c, 0x8890, + 0x0804, 0x877b, 0xa0b2, 0x0040, 0x1a04, 0x8885, 0x2008, 0x0002, + 0x880a, 0x880b, 0x880e, 0x8811, 0x8814, 0x8817, 0x8808, 0x8808, + 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, + 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, + 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x881a, 0x8829, + 0x8808, 0x882b, 0x8829, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, + 0x8829, 0x8829, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, 0x8808, + 0x8808, 0x8808, 0x8865, 0x8829, 0x8808, 0x8825, 0x8808, 0x8808, + 0x8808, 0x8826, 0x8808, 0x8808, 0x8808, 0x8829, 0x885c, 0x8808, + 0x080c, 0x14fa, 0x00f0, 0x2001, 0x000b, 0x0460, 0x2001, 0x0003, + 0x0448, 0x2001, 0x0005, 0x0430, 0x2001, 0x0001, 0x0418, 0x2001, + 0x0009, 0x0400, 0x080c, 0x6dc1, 0x6003, 0x0005, 0x2001, 0xb3b7, + 0x2004, 0x603e, 0x080c, 0x6e9e, 0x00a0, 0x0018, 0x0010, 0x080c, + 0x4d75, 0x0804, 0x8876, 0x080c, 0x6dc1, 0x2001, 0xb3b5, 0x2004, + 0x6016, 0x2001, 0xb3b7, 0x2004, 0x603e, 0x6003, 0x0004, 0x080c, + 0x6e9e, 0x0005, 0x080c, 0x4d75, 0x080c, 0x6dc1, 0x6003, 0x0002, + 0x2001, 0xb3b7, 0x2004, 0x603e, 0x0036, 0x2019, 0xb15d, 0x2304, + 0xa084, 0xff00, 0x1120, 0x2001, 0xb3b5, 0x201c, 0x0040, 0x8007, + 0xa09a, 0x0004, 0x0ec0, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, + 0x003e, 0x080c, 0x6e9e, 0x08e8, 0x080c, 0x6dc1, 0x080c, 0x9c2d, + 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x08a0, 0x00e6, 0x00f6, 0x2071, + 0xb182, 0x2079, 0x0000, 0x080c, 0x2e97, 0x00fe, 0x00ee, 0x080c, + 0x6dc1, 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x0818, 0x080c, 0x6dc1, + 0x2001, 0xb3b7, 0x2004, 0x603e, 0x6003, 0x0002, 0x2001, 0xb3b5, + 0x2004, 0x6016, 0x080c, 0x6e9e, 0x0005, 0x2600, 0x2008, 0x0002, + 0x888e, 0x888e, 0x888e, 0x8876, 0x8876, 0x888e, 0x080c, 0x14fa, + 0x00e6, 0x0026, 0x0016, 0x080c, 0x986a, 0x0508, 0x6010, 0x2070, + 0x7034, 0xa086, 0x0139, 0x1148, 0x2001, 0x0030, 0x2009, 0x0000, + 0x2011, 0x4005, 0x080c, 0x9ce4, 0x0090, 0x7038, 0xd0fc, 0x0178, + 0x7007, 0x0000, 0x0016, 0x6004, 0xa08e, 0x0021, 0x0160, 0xa08e, + 0x003d, 0x0148, 0x001e, 0x7037, 0x0103, 0x7033, 0x0100, 0x001e, + 0x002e, 0x00ee, 0x0005, 0x001e, 0x0009, 0x0cc8, 0x00e6, 0xacf0, + 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, 0x8001, + 0x00ee, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804, 0xa084, 0x00ff, + 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x14fa, 0x6604, 0xa6b6, 0x0043, + 0x1120, 0x080c, 0x9ca0, 0x0804, 0x892f, 0x6604, 0xa6b6, 0x0033, + 0x1120, 0x080c, 0x9c50, 0x0804, 0x892f, 0x6604, 0xa6b6, 0x0028, + 0x1120, 0x080c, 0x9a96, 0x0804, 0x892f, 0x6604, 0xa6b6, 0x0029, + 0x1118, 0x080c, 0x9aad, 0x04d8, 0x6604, 0xa6b6, 0x001f, 0x1118, + 0x080c, 0x844f, 0x04a0, 0x6604, 0xa6b6, 0x0000, 0x1118, 0x080c, + 0x869e, 0x0468, 0x6604, 0xa6b6, 0x0022, 0x1118, 0x080c, 0x8477, + 0x0430, 0x6604, 0xa6b6, 0x0035, 0x1118, 0x080c, 0x84de, 0x00f8, + 0x6604, 0xa6b6, 0x0039, 0x1118, 0x080c, 0x863a, 0x00c0, 0x6604, + 0xa6b6, 0x003d, 0x1118, 0x080c, 0x8491, 0x0088, 0x6604, 0xa6b6, + 0x0044, 0x1118, 0x080c, 0x84b1, 0x0050, 0xa1b6, 0x0015, 0x1110, + 0x0053, 0x0028, 0xa1b6, 0x0016, 0x1118, 0x0804, 0x8aeb, 0x0005, + 0x080c, 0x8331, 0x0ce0, 0x8956, 0x8959, 0x8956, 0x899b, 0x8956, + 0x8a78, 0x8af9, 0x8956, 0x8956, 0x8ac7, 0x8956, 0x8adb, 0xa1b6, + 0x0048, 0x0140, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, + 0x1828, 0x0005, 0x00e6, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, + 0x7037, 0x0103, 0x00ee, 0x080c, 0x82eb, 0x0005, 0xe000, 0xe000, + 0x0005, 0x00e6, 0x2071, 0xb100, 0x7080, 0xa086, 0x0074, 0x1530, + 0x080c, 0xaa28, 0x11b0, 0x00d6, 0x6018, 0x2068, 0x7030, 0xd08c, + 0x0128, 0x6800, 0xd0bc, 0x0110, 0xc0c5, 0x6802, 0x00d9, 0x00de, + 0x2001, 0x0006, 0x080c, 0x4d75, 0x080c, 0x2b99, 0x080c, 0x82eb, + 0x0078, 0x2001, 0x000a, 0x080c, 0x4d75, 0x080c, 0x2b99, 0x6003, + 0x0001, 0x6007, 0x0001, 0x080c, 0x6a3c, 0x0010, 0x080c, 0x8a69, + 0x00ee, 0x0005, 0x6800, 0xd084, 0x0168, 0x2001, 0x0000, 0x080c, + 0x4d63, 0x2069, 0xb152, 0x6804, 0xd0a4, 0x0120, 0x2001, 0x0006, + 0x080c, 0x4da2, 0x0005, 0x00d6, 0x2011, 0xb120, 0x2204, 0xa086, + 0x0074, 0x1904, 0x8a66, 0x6018, 0x2068, 0x6aa0, 0xa286, 0x007e, + 0x1120, 0x080c, 0x8bf7, 0x0804, 0x8a09, 0x080c, 0x8bed, 0x6018, + 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, 0x0080, 0x11c0, 0x6813, + 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, 0x0138, 0x2068, 0x6807, + 0x0000, 0x6837, 0x0103, 0x6833, 0x0200, 0x2001, 0x0006, 0x080c, + 0x4d75, 0x080c, 0x2b99, 0x080c, 0x82eb, 0x0804, 0x8a67, 0x00e6, + 0x2071, 0xb134, 0x2e04, 0xd09c, 0x0188, 0x2071, 0xb680, 0x7108, + 0x720c, 0xa18c, 0x00ff, 0x1118, 0xa284, 0xff00, 0x0138, 0x6018, + 0x2070, 0x70a0, 0xd0bc, 0x1110, 0x7112, 0x7216, 0x00ee, 0x6010, + 0xa005, 0x0198, 0x2068, 0x6838, 0xd0f4, 0x0178, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x0039, 0x1958, 0x2001, 0x0000, 0x2009, 0x0000, + 0x2011, 0x4000, 0x080c, 0x9ce4, 0x0840, 0x2001, 0x0004, 0x080c, + 0x4d75, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x6a3c, 0x0804, + 0x8a67, 0x685c, 0xd0e4, 0x01d8, 0x080c, 0x9be0, 0x080c, 0x58d5, + 0x0118, 0xd0dc, 0x1904, 0x89c5, 0x2011, 0xb134, 0x2204, 0xc0ad, + 0x2012, 0x2001, 0xb38f, 0x2004, 0x00f6, 0x2079, 0x0100, 0x78e3, + 0x0000, 0x080c, 0x274b, 0x78e2, 0x00fe, 0x0804, 0x89c5, 0x080c, + 0x9c16, 0x2011, 0xb134, 0x2204, 0xc0a5, 0x2012, 0x0006, 0x080c, + 0xab41, 0x000e, 0x1904, 0x89c5, 0xc0b5, 0x2012, 0x2001, 0x0000, + 0x080c, 0x4d63, 0x00c6, 0x2009, 0x00ef, 0x00f6, 0x2079, 0x0100, + 0x79ea, 0x7932, 0x7936, 0x00fe, 0x080c, 0x2720, 0x00f6, 0x2079, + 0xb100, 0x7972, 0x2100, 0x2009, 0x0000, 0x080c, 0x26f6, 0x794e, + 0x00fe, 0x8108, 0x080c, 0x4dc5, 0x2c00, 0x00ce, 0x1904, 0x89c5, + 0x601a, 0x2001, 0x0002, 0x080c, 0x4d75, 0x601f, 0x0001, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x6a3c, 0x0008, 0x0011, 0x00de, + 0x0005, 0x2001, 0xb100, 0x2004, 0xa086, 0x0003, 0x0120, 0x2001, + 0x0007, 0x080c, 0x4d75, 0x080c, 0x2b99, 0x080c, 0x82eb, 0x0005, + 0x00e6, 0x0026, 0x0016, 0x2071, 0xb100, 0x7080, 0xa086, 0x0014, + 0x15f0, 0x7000, 0xa086, 0x0003, 0x1128, 0x6010, 0xa005, 0x1110, + 0x080c, 0x3dcd, 0x00d6, 0x6018, 0x2068, 0x080c, 0x4ebf, 0x080c, + 0x898a, 0x00de, 0x080c, 0x8ca6, 0x1550, 0x00d6, 0x6018, 0x2068, + 0x6890, 0x00de, 0xa005, 0x0518, 0x2001, 0x0006, 0x080c, 0x4d75, + 0x00e6, 0x6010, 0xa075, 0x01a8, 0x7034, 0xa084, 0x00ff, 0xa086, + 0x0039, 0x1148, 0x2001, 0x0000, 0x2009, 0x0000, 0x2011, 0x4000, + 0x080c, 0x9ce4, 0x0030, 0x7007, 0x0000, 0x7037, 0x0103, 0x7033, + 0x0200, 0x00ee, 0x080c, 0x2b99, 0x080c, 0x82eb, 0x0020, 0x080c, + 0x8890, 0x080c, 0x8a69, 0x001e, 0x002e, 0x00ee, 0x0005, 0x2011, + 0xb120, 0x2204, 0xa086, 0x0014, 0x1158, 0x2001, 0x0002, 0x080c, + 0x4d75, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x6a3c, 0x0010, + 0x080c, 0x8a69, 0x0005, 0x2011, 0xb120, 0x2204, 0xa086, 0x0004, + 0x1138, 0x2001, 0x0007, 0x080c, 0x4d75, 0x080c, 0x82eb, 0x0010, + 0x080c, 0x8a69, 0x0005, 0x000b, 0x0005, 0x8956, 0x8b00, 0x8956, + 0x8b34, 0x8956, 0x8ba9, 0x8af9, 0x8956, 0x8956, 0x8bbc, 0x8956, + 0x8bcc, 0x6604, 0xa6b6, 0x001e, 0x1110, 0x080c, 0x82eb, 0x0005, + 0x00d6, 0x00c6, 0x080c, 0x8bdc, 0x1178, 0x2001, 0x0000, 0x080c, + 0x4d63, 0x2001, 0x0002, 0x080c, 0x4d75, 0x6003, 0x0001, 0x6007, + 0x0002, 0x080c, 0x6a3c, 0x00e8, 0x2009, 0xb68e, 0x2104, 0xa086, + 0x0009, 0x1160, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, + 0x0170, 0x8001, 0x6842, 0x6017, 0x000a, 0x0058, 0x2009, 0xb68f, + 0x2104, 0xa084, 0xff00, 0xa086, 0x1900, 0x1108, 0x08d0, 0x080c, + 0x8a69, 0x00ce, 0x00de, 0x0005, 0x080c, 0x8bea, 0x00d6, 0x2069, + 0xb39e, 0x2d04, 0xa005, 0x0168, 0x6018, 0x2068, 0x68a0, 0xa086, + 0x007e, 0x1138, 0x2069, 0xb11c, 0x2d04, 0x8000, 0x206a, 0x00de, + 0x0010, 0x00de, 0x0078, 0x2001, 0x0000, 0x080c, 0x4d63, 0x2001, + 0x0002, 0x080c, 0x4d75, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, + 0x6a3c, 0x0428, 0x080c, 0x8890, 0x2009, 0xb68e, 0x2134, 0xa6b4, + 0x00ff, 0xa686, 0x0005, 0x01e0, 0xa686, 0x000b, 0x01b0, 0x2009, + 0xb68f, 0x2104, 0xa084, 0xff00, 0x1118, 0xa686, 0x0009, 0x0180, + 0xa086, 0x1900, 0x1150, 0xa686, 0x0009, 0x0150, 0x2001, 0x0004, + 0x080c, 0x4d75, 0x080c, 0x82eb, 0x0010, 0x080c, 0x8a69, 0x0005, + 0x00d6, 0x6010, 0x2068, 0x080c, 0x986a, 0x0128, 0x6838, 0xd0fc, + 0x0110, 0x00de, 0x0c90, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, + 0xa005, 0x0140, 0x8001, 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, + 0x00de, 0x0c28, 0x68a0, 0xa086, 0x007e, 0x1138, 0x00e6, 0x2071, + 0xb100, 0x080c, 0x4a3b, 0x00ee, 0x0010, 0x080c, 0x2b73, 0x00de, + 0x08a0, 0x080c, 0x8bea, 0x1158, 0x2001, 0x0004, 0x080c, 0x4d75, + 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x6a3c, 0x0020, 0x080c, + 0x8890, 0x080c, 0x8a69, 0x0005, 0x0469, 0x1158, 0x2001, 0x0008, + 0x080c, 0x4d75, 0x6003, 0x0001, 0x6007, 0x0005, 0x080c, 0x6a3c, + 0x0010, 0x080c, 0x8a69, 0x0005, 0x00e9, 0x1158, 0x2001, 0x000a, + 0x080c, 0x4d75, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x6a3c, + 0x0010, 0x080c, 0x8a69, 0x0005, 0x2009, 0xb68e, 0x2104, 0xa086, + 0x0003, 0x1138, 0x2009, 0xb68f, 0x2104, 0xa084, 0xff00, 0xa086, + 0x2a00, 0x0005, 0xa085, 0x0001, 0x0005, 0x00c6, 0x0016, 0xac88, + 0x0006, 0x2164, 0x080c, 0x4e30, 0x001e, 0x00ce, 0x0005, 0x00f6, + 0x00e6, 0x00d6, 0x0036, 0x0016, 0x6018, 0x2068, 0x2071, 0xb134, + 0x2e04, 0xa085, 0x0003, 0x2072, 0x080c, 0x8c7b, 0x0560, 0x2009, + 0xb134, 0x2104, 0xc0cd, 0x200a, 0x2001, 0xb153, 0x2004, 0xd0a4, + 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, 0x080c, 0xacae, 0x2001, + 0xb10c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, + 0x080c, 0x2b46, 0x2071, 0xb100, 0x080c, 0x2991, 0x00c6, 0x0156, + 0x20a9, 0x0081, 0x2009, 0x007f, 0x080c, 0x2c6e, 0x8108, 0x1f04, + 0x8c2c, 0x015e, 0x00ce, 0x080c, 0x8bed, 0x6813, 0x00ff, 0x6817, + 0xfffe, 0x2071, 0xb680, 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, + 0x2069, 0xb11b, 0x206a, 0x78e6, 0x0006, 0x8e70, 0x2e04, 0x2069, + 0xb11c, 0x206a, 0x78ea, 0x7832, 0x7836, 0x2010, 0xa084, 0xff00, + 0x001e, 0xa105, 0x2009, 0xb127, 0x200a, 0x2200, 0xa084, 0x00ff, + 0x2008, 0x080c, 0x2720, 0x080c, 0x58d5, 0x0170, 0x2069, 0xb68e, + 0x2071, 0xb3b1, 0x6810, 0x2072, 0x6814, 0x7006, 0x6818, 0x700a, + 0x681c, 0x700e, 0x080c, 0x9be0, 0x0040, 0x2001, 0x0006, 0x080c, + 0x4d75, 0x080c, 0x2b99, 0x080c, 0x82eb, 0x001e, 0x003e, 0x00de, + 0x00ee, 0x00fe, 0x0005, 0x0026, 0x0036, 0x00e6, 0x0156, 0x2019, + 0xb127, 0x231c, 0x83ff, 0x01e8, 0x2071, 0xb680, 0x2e14, 0xa294, + 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306, 0x1190, 0x2011, + 0xb696, 0xad98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x8d2b, 0x1148, + 0x2011, 0xb69a, 0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, 0x8d2b, + 0x1100, 0x015e, 0x00ee, 0x003e, 0x002e, 0x0005, 0x00e6, 0x2071, + 0xb68c, 0x7004, 0xa086, 0x0014, 0x11a8, 0x7008, 0xa086, 0x0800, + 0x1188, 0x700c, 0xd0ec, 0x0160, 0xa084, 0x0f00, 0xa086, 0x0100, + 0x1138, 0x7024, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0xa006, 0x0010, + 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0076, + 0x0056, 0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2029, + 0xb3e2, 0x252c, 0x2021, 0xb3e8, 0x2424, 0x2061, 0xb800, 0x2071, + 0xb100, 0x7244, 0x7064, 0xa202, 0x16f0, 0x080c, 0xacd6, 0x05a0, + 0x671c, 0xa786, 0x0001, 0x0580, 0xa786, 0x0007, 0x0568, 0x2500, + 0xac06, 0x0550, 0x2400, 0xac06, 0x0538, 0x00c6, 0x6000, 0xa086, + 0x0004, 0x1110, 0x080c, 0x190f, 0xa786, 0x0008, 0x1148, 0x080c, + 0x9a66, 0x1130, 0x00ce, 0x080c, 0x8890, 0x080c, 0x9a2b, 0x00a0, + 0x6010, 0x2068, 0x080c, 0x986a, 0x0160, 0xa786, 0x0003, 0x11e8, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x5271, 0x080c, + 0x9a1f, 0x080c, 0x9a2b, 0x00ce, 0xace0, 0x0018, 0x7058, 0xac02, + 0x1210, 0x0804, 0x8cd9, 0x012e, 0x000e, 0x002e, 0x004e, 0x005e, + 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0xa786, 0x0006, 0x1d00, + 0x080c, 0xac5f, 0x0c30, 0x220c, 0x2304, 0xa106, 0x1130, 0x8210, + 0x8318, 0x1f04, 0x8d2b, 0xa006, 0x0005, 0x2304, 0xa102, 0x0218, + 0x2001, 0x0001, 0x0010, 0x2001, 0x0000, 0xa18d, 0x0001, 0x0005, + 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14fa, 0x080c, 0x9a55, 0x0120, + 0x080c, 0x9a66, 0x0168, 0x0028, 0x080c, 0x2b99, 0x080c, 0x9a66, + 0x0138, 0x080c, 0x6dc1, 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x0005, + 0x080c, 0x8890, 0x0cb0, 0xa182, 0x0040, 0x0002, 0x8d71, 0x8d71, + 0x8d71, 0x8d71, 0x8d71, 0x8d71, 0x8d71, 0x8d71, 0x8d71, 0x8d71, + 0x8d71, 0x8d73, 0x8d73, 0x8d73, 0x8d73, 0x8d71, 0x8d71, 0x8d71, + 0x8d73, 0x080c, 0x14fa, 0x600b, 0xffff, 0x6003, 0x0001, 0x6106, + 0x080c, 0x69f6, 0x0126, 0x2091, 0x8000, 0x080c, 0x6e9e, 0x012e, + 0x0005, 0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0040, 0x0804, + 0x8e0d, 0xa186, 0x0027, 0x11e8, 0x080c, 0x6dc1, 0x080c, 0x2b73, + 0x00d6, 0x6110, 0x2168, 0x080c, 0x986a, 0x0168, 0x6837, 0x0103, + 0x684b, 0x0029, 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x080c, + 0x5271, 0x080c, 0x9a1f, 0x00de, 0x080c, 0x82eb, 0x080c, 0x6e9e, + 0x0005, 0xa186, 0x0014, 0x1120, 0x6004, 0xa082, 0x0040, 0x0428, + 0xa186, 0x0046, 0x0138, 0xa186, 0x0045, 0x0120, 0xa186, 0x0047, + 0x190c, 0x14fa, 0x2001, 0x0109, 0x2004, 0xd084, 0x0198, 0x0126, + 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x68e7, 0x002e, + 0x001e, 0x000e, 0x012e, 0xe000, 0x6000, 0xa086, 0x0002, 0x1110, + 0x0804, 0x8e47, 0x080c, 0x8331, 0x0005, 0x0002, 0x8deb, 0x8de9, + 0x8de9, 0x8de9, 0x8de9, 0x8de9, 0x8de9, 0x8de9, 0x8de9, 0x8de9, + 0x8de9, 0x8e06, 0x8e06, 0x8e06, 0x8e06, 0x8de9, 0x8e06, 0x8de9, + 0x8e06, 0x080c, 0x14fa, 0x080c, 0x6dc1, 0x00d6, 0x6110, 0x2168, + 0x080c, 0x986a, 0x0168, 0x6837, 0x0103, 0x684b, 0x0006, 0x6847, + 0x0000, 0x6850, 0xc0ec, 0x6852, 0x080c, 0x5271, 0x080c, 0x9a1f, + 0x00de, 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x0005, 0x080c, 0x6dc1, + 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x0005, 0x0002, 0x8e23, 0x8e21, + 0x8e21, 0x8e21, 0x8e21, 0x8e21, 0x8e21, 0x8e21, 0x8e21, 0x8e21, + 0x8e21, 0x8e35, 0x8e35, 0x8e35, 0x8e35, 0x8e21, 0x8e40, 0x8e21, + 0x8e35, 0x080c, 0x14fa, 0x080c, 0x6dc1, 0x2001, 0xb3b7, 0x2004, + 0x603e, 0x6003, 0x0002, 0x080c, 0x6e9e, 0x6010, 0xa088, 0x0013, + 0x2104, 0xa085, 0x0400, 0x200a, 0x0005, 0x080c, 0x6dc1, 0x2001, + 0xb3b7, 0x2004, 0x603e, 0x6003, 0x000f, 0x080c, 0x6e9e, 0x0005, + 0x080c, 0x6dc1, 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x0005, 0xa182, + 0x0040, 0x0002, 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5f, + 0x8f37, 0x8f66, 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5d, + 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5d, 0x8e5d, 0x080c, 0x14fa, 0x00e6, + 0x00d6, 0x603f, 0x0000, 0x2071, 0xb680, 0x7124, 0x610a, 0x2071, + 0xb68c, 0x6110, 0x2168, 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0904, + 0x8f03, 0xa68c, 0x0c00, 0x01e8, 0x00f6, 0x2c78, 0x080c, 0x5177, + 0x00fe, 0x0198, 0x684c, 0xd0ac, 0x0180, 0x6020, 0xd0dc, 0x1168, + 0x6850, 0xd0bc, 0x1150, 0x7318, 0x6814, 0xa306, 0x1904, 0x8f15, + 0x731c, 0x6810, 0xa306, 0x1904, 0x8f15, 0x7318, 0x6b62, 0x731c, + 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0518, 0xa186, 0x0028, + 0x1128, 0x080c, 0x9a44, 0x684b, 0x001c, 0x00e8, 0xd6dc, 0x01a0, + 0x684b, 0x0015, 0x684c, 0xd0ac, 0x0170, 0x6914, 0x6a10, 0x2100, + 0xa205, 0x0148, 0x7018, 0xa106, 0x1118, 0x701c, 0xa206, 0x0118, + 0x6962, 0x6a5e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, + 0x0010, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e, 0xd6c4, + 0x01f0, 0xa686, 0x0100, 0x1140, 0x2001, 0xb699, 0x2004, 0xa005, + 0x1118, 0xc6c4, 0x0804, 0x8e6e, 0x7328, 0x732c, 0x6b56, 0x83ff, + 0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, + 0x2019, 0xb698, 0xad90, 0x0019, 0x080c, 0x953f, 0x003e, 0xd6cc, + 0x0904, 0x8f28, 0x7124, 0x695a, 0x81ff, 0x0904, 0x8f28, 0xa192, + 0x0021, 0x1250, 0x2071, 0xb698, 0x831c, 0x2300, 0xae18, 0xad90, + 0x001d, 0x080c, 0x953f, 0x04a0, 0x6838, 0xd0fc, 0x0120, 0x2009, + 0x0020, 0x695a, 0x0c78, 0x00f6, 0x2d78, 0x080c, 0x94e4, 0x00fe, + 0x080c, 0x952f, 0x0438, 0x00f6, 0x2c78, 0x080c, 0x5177, 0x00fe, + 0x0188, 0x684c, 0xd0ac, 0x0170, 0x6020, 0xd0dc, 0x1158, 0x6850, + 0xd0bc, 0x1140, 0x684c, 0xd0f4, 0x1128, 0x080c, 0x9b43, 0x00de, + 0x00ee, 0x00e0, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, + 0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x90c1, + 0x080c, 0x5271, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x080c, + 0x9b11, 0x00de, 0x00ee, 0x1110, 0x080c, 0x82eb, 0x0005, 0x00f6, + 0x6003, 0x0003, 0x2079, 0xb68c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, + 0x6010, 0x2078, 0x784c, 0xd0ac, 0x0138, 0x6003, 0x0002, 0x00fe, + 0x0005, 0x2130, 0x2228, 0x0058, 0x2400, 0x797c, 0xa10a, 0x2300, + 0x7a80, 0xa213, 0x2600, 0xa102, 0x2500, 0xa203, 0x0e90, 0x7c12, + 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x603f, 0x0000, 0x2c10, 0x080c, + 0x1ec4, 0x080c, 0x6a59, 0x080c, 0x6f5b, 0x0005, 0x2001, 0xb3b7, + 0x2004, 0x603e, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, + 0x3e20, 0x2c10, 0x080c, 0x1828, 0x0005, 0xa182, 0x0040, 0x0002, + 0x8f8b, 0x8f8b, 0x8f8b, 0x8f8b, 0x8f8b, 0x8f8d, 0x901e, 0x8f8b, + 0x8f8b, 0x9034, 0x9098, 0x8f8b, 0x8f8b, 0x8f8b, 0x8f8b, 0x90a7, + 0x8f8b, 0x8f8b, 0x8f8b, 0x080c, 0x14fa, 0x0076, 0x00f6, 0x00e6, + 0x00d6, 0x2071, 0xb68c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, + 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, + 0x6a3e, 0x86ff, 0x0904, 0x9019, 0xa694, 0xff00, 0xa284, 0x0c00, + 0x0120, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, + 0x9019, 0x080c, 0x15dd, 0x090c, 0x14fa, 0x2d00, 0x784a, 0x7f4c, + 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, + 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120, 0x7318, 0x6b62, + 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0180, 0xa186, + 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0x684b, + 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, 0x0010, 0x684b, + 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, + 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0170, 0xa38a, 0x0009, + 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0xb698, 0xad90, + 0x0019, 0x080c, 0x953f, 0x003e, 0xd6cc, 0x01d8, 0x7124, 0x695a, + 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, 0x2071, 0xb698, 0x831c, + 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x953f, 0x0050, 0x7838, + 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, 0x2d78, 0x080c, + 0x94e4, 0x00de, 0x00ee, 0x00fe, 0x007e, 0x0005, 0x00f6, 0x6003, + 0x0003, 0x2079, 0xb68c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, + 0x2078, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x2c10, 0x080c, + 0x1ec4, 0x080c, 0x7a72, 0x0005, 0x00d6, 0x00f6, 0x2c78, 0x080c, + 0x5177, 0x00fe, 0x0120, 0x2001, 0xb3b7, 0x2004, 0x603e, 0x6003, + 0x0002, 0x080c, 0x6e53, 0x080c, 0x6f5b, 0x6110, 0x2168, 0x694c, + 0xd1e4, 0x0904, 0x9096, 0xd1cc, 0x0540, 0x6948, 0x6838, 0xd0fc, + 0x01e8, 0x0016, 0x684c, 0x0006, 0x6850, 0x0006, 0xad90, 0x000d, + 0xa198, 0x000d, 0x2009, 0x0020, 0x0156, 0x21a8, 0x2304, 0x2012, + 0x8318, 0x8210, 0x1f04, 0x905e, 0x015e, 0x000e, 0x6852, 0x000e, + 0x684e, 0x001e, 0x2168, 0x080c, 0x1604, 0x0418, 0x0016, 0x080c, + 0x1604, 0x00de, 0x080c, 0x952f, 0x00e0, 0x6837, 0x0103, 0x6944, + 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0180, 0xa086, 0x0028, 0x1118, + 0x684b, 0x001c, 0x0060, 0xd1dc, 0x0118, 0x684b, 0x0015, 0x0038, + 0xd1d4, 0x0118, 0x684b, 0x0007, 0x0010, 0x684b, 0x0000, 0x080c, + 0x5271, 0x080c, 0x9b11, 0x1110, 0x080c, 0x82eb, 0x00de, 0x0005, + 0x2019, 0x0001, 0x080c, 0x7cc4, 0x6003, 0x0002, 0x2001, 0xb3b7, + 0x2004, 0x603e, 0x080c, 0x6e53, 0x080c, 0x6f5b, 0x0005, 0x080c, + 0x6e53, 0x080c, 0x2b73, 0x00d6, 0x6110, 0x2168, 0x080c, 0x986a, + 0x0150, 0x6837, 0x0103, 0x684b, 0x0029, 0x6847, 0x0000, 0x080c, + 0x5271, 0x080c, 0x9a1f, 0x00de, 0x080c, 0x82eb, 0x080c, 0x6f5b, + 0x0005, 0x684b, 0x0015, 0xd1fc, 0x0138, 0x684b, 0x0007, 0x8002, + 0x8000, 0x810a, 0xa189, 0x0000, 0x6962, 0x685e, 0x0005, 0xa182, + 0x0040, 0x0002, 0x90e5, 0x90e5, 0x90e5, 0x90e5, 0x90e5, 0x90e7, + 0x90e5, 0x91a0, 0x91ac, 0x90e5, 0x90e5, 0x90e5, 0x90e5, 0x90e5, + 0x90e5, 0x90e5, 0x90e5, 0x90e5, 0x90e5, 0x080c, 0x14fa, 0x0076, + 0x00f6, 0x00e6, 0x00d6, 0x2071, 0xb68c, 0x6110, 0x2178, 0x7614, + 0xa6b4, 0x0fff, 0x00f6, 0x2c78, 0x080c, 0x5177, 0x00fe, 0x0150, + 0xa684, 0x00ff, 0x1138, 0x6020, 0xd0f4, 0x0120, 0x080c, 0x9b43, + 0x0804, 0x919b, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, + 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0904, 0x9191, 0xa694, 0xff00, + 0xa284, 0x0c00, 0x0120, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, + 0x0300, 0x0904, 0x918f, 0xa686, 0x0100, 0x1140, 0x2001, 0xb699, + 0x2004, 0xa005, 0x1118, 0xc6c4, 0x7e46, 0x0c28, 0x080c, 0x15dd, + 0x090c, 0x14fa, 0x2d00, 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, + 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, + 0x6e46, 0xa68c, 0x0c00, 0x0120, 0x7318, 0x6b62, 0x731c, 0x6b5e, + 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0180, 0xa186, 0x0028, 0x1118, + 0x684b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0x684b, 0x0015, 0x0038, + 0xd6d4, 0x0118, 0x684b, 0x0007, 0x0010, 0x684b, 0x0000, 0x6f4e, + 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0198, 0x7328, + 0x732c, 0x6b56, 0x83ff, 0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, + 0x0008, 0x0036, 0x2308, 0x2019, 0xb698, 0xad90, 0x0019, 0x080c, + 0x953f, 0x003e, 0xd6cc, 0x01d8, 0x7124, 0x695a, 0x81ff, 0x01b8, + 0xa192, 0x0021, 0x1250, 0x2071, 0xb698, 0x831c, 0x2300, 0xae18, + 0xad90, 0x001d, 0x080c, 0x953f, 0x0050, 0x7838, 0xd0fc, 0x0120, + 0x2009, 0x0020, 0x695a, 0x0c78, 0x2d78, 0x080c, 0x94e4, 0xd6dc, + 0x1110, 0xa006, 0x0030, 0x2001, 0x0001, 0x2071, 0xb68c, 0x7218, + 0x731c, 0x080c, 0x1873, 0x00de, 0x00ee, 0x00fe, 0x007e, 0x0005, + 0x2001, 0xb3b7, 0x2004, 0x603e, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x080c, 0x1828, 0x0005, 0x2001, 0xb3b7, 0x2004, 0x603e, + 0x00d6, 0x6003, 0x0002, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0904, + 0x92b3, 0x603f, 0x0000, 0x00f6, 0x2c78, 0x080c, 0x5177, 0x00fe, + 0x0560, 0x6814, 0x6910, 0xa115, 0x0540, 0x6a60, 0xa206, 0x1118, + 0x685c, 0xa106, 0x0510, 0x684c, 0xc0e4, 0x684e, 0x6847, 0x0000, + 0x6863, 0x0000, 0x685f, 0x0000, 0x6020, 0xd0f4, 0x1158, 0x697c, + 0x6810, 0xa102, 0x603a, 0x6980, 0x6814, 0xa103, 0x6036, 0x6020, + 0xc0f5, 0x6022, 0x00d6, 0x6018, 0x2068, 0x683c, 0x8000, 0x683e, + 0x00de, 0x080c, 0x9b43, 0x0804, 0x92b3, 0x694c, 0xd1cc, 0x0904, + 0x9283, 0x6948, 0x6838, 0xd0fc, 0x0904, 0x9248, 0x0016, 0x684c, + 0x0006, 0x6850, 0x0006, 0x00f6, 0x2178, 0x7944, 0xa184, 0x00ff, + 0xa0b6, 0x0002, 0x01e0, 0xa086, 0x0028, 0x1128, 0x684b, 0x001c, + 0x784b, 0x001c, 0x00e8, 0xd1dc, 0x0158, 0x684b, 0x0015, 0x784b, + 0x0015, 0x080c, 0x9ccd, 0x0118, 0x7944, 0xc1dc, 0x7946, 0x0080, + 0xd1d4, 0x0128, 0x684b, 0x0007, 0x784b, 0x0007, 0x0048, 0x684c, + 0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x90c1, + 0x6848, 0x784a, 0x6860, 0x7862, 0x685c, 0x785e, 0xad90, 0x000d, + 0xaf98, 0x000d, 0x2009, 0x0020, 0x0156, 0x21a8, 0x2304, 0x2012, + 0x8318, 0x8210, 0x1f04, 0x9236, 0x015e, 0x00fe, 0x000e, 0x6852, + 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, 0x1604, 0x0804, 0x92ae, + 0x0016, 0x00f6, 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, + 0x01e0, 0xa086, 0x0028, 0x1128, 0x684b, 0x001c, 0x784b, 0x001c, + 0x00e8, 0xd1dc, 0x0158, 0x684b, 0x0015, 0x784b, 0x0015, 0x080c, + 0x9ccd, 0x0118, 0x7944, 0xc1dc, 0x7946, 0x0080, 0xd1d4, 0x0128, + 0x684b, 0x0007, 0x784b, 0x0007, 0x0048, 0x684c, 0xd0ac, 0x0130, + 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x90c1, 0x6860, 0x7862, + 0x685c, 0x785e, 0x684c, 0x784e, 0x00fe, 0x080c, 0x1604, 0x00de, + 0x080c, 0x952f, 0x0458, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, + 0xa0b6, 0x0002, 0x01b0, 0xa086, 0x0028, 0x1118, 0x684b, 0x001c, + 0x00d8, 0xd1dc, 0x0148, 0x684b, 0x0015, 0x080c, 0x9ccd, 0x0118, + 0x6944, 0xc1dc, 0x6946, 0x0080, 0xd1d4, 0x0118, 0x684b, 0x0007, + 0x0058, 0x684b, 0x0000, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, + 0xa115, 0x0110, 0x080c, 0x90c1, 0x080c, 0x5271, 0x080c, 0x9b11, + 0x1110, 0x080c, 0x82eb, 0x00de, 0x0005, 0x080c, 0x6dc1, 0x0010, + 0x080c, 0x6e53, 0x080c, 0x986a, 0x01c0, 0x00d6, 0x6110, 0x2168, + 0x6837, 0x0103, 0x2009, 0xb10c, 0x210c, 0xd18c, 0x11c0, 0xd184, + 0x1198, 0x6108, 0x694a, 0xa18e, 0x0029, 0x1110, 0x080c, 0xaf46, + 0x6847, 0x0000, 0x080c, 0x5271, 0x00de, 0x080c, 0x82eb, 0x080c, + 0x6e9e, 0x080c, 0x6f5b, 0x0005, 0x684b, 0x0004, 0x0c88, 0x684b, + 0x0004, 0x0c70, 0xa182, 0x0040, 0x0002, 0x92f8, 0x92f8, 0x92f8, + 0x92f8, 0x92f8, 0x92fa, 0x92f8, 0x92fd, 0x92f8, 0x92f8, 0x92f8, + 0x92f8, 0x92f8, 0x92f8, 0x92f8, 0x92f8, 0x92f8, 0x92f8, 0x92f8, + 0x080c, 0x14fa, 0x080c, 0x82eb, 0x0005, 0x0006, 0x0026, 0xa016, + 0x080c, 0x1828, 0x002e, 0x000e, 0x0005, 0xa182, 0x0085, 0x0002, + 0x9311, 0x930f, 0x930f, 0x931d, 0x930f, 0x930f, 0x930f, 0x080c, + 0x14fa, 0x6003, 0x0001, 0x6106, 0x080c, 0x69f6, 0x0126, 0x2091, + 0x8000, 0x080c, 0x6e9e, 0x012e, 0x0005, 0x0026, 0x0056, 0x00d6, + 0x00e6, 0x2071, 0xb680, 0x7224, 0x6212, 0x7220, 0x080c, 0x985a, + 0x01a0, 0x2268, 0x6800, 0xa086, 0x0000, 0x0178, 0x6018, 0x6d18, + 0xa52e, 0x1158, 0x00c6, 0x2d60, 0x080c, 0x954f, 0x00ce, 0x0128, + 0x6803, 0x0002, 0x6007, 0x0086, 0x0010, 0x6007, 0x0087, 0x6003, + 0x0001, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x00f6, 0x2278, 0x080c, + 0x5177, 0x00fe, 0x0150, 0x6820, 0xd0ec, 0x0138, 0x00c6, 0x2260, + 0x603f, 0x0000, 0x080c, 0x9b43, 0x00ce, 0x00ee, 0x00de, 0x005e, + 0x002e, 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, + 0x0a0c, 0x14fa, 0xa08a, 0x008c, 0x1a0c, 0x14fa, 0xa082, 0x0085, + 0x0072, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, 0x14fa, + 0x080c, 0x6dc1, 0x080c, 0x9a2b, 0x080c, 0x6e9e, 0x0005, 0x937e, + 0x9380, 0x9380, 0x937e, 0x937e, 0x937e, 0x937e, 0x080c, 0x14fa, + 0x080c, 0x6dc1, 0x080c, 0x9a2b, 0x080c, 0x6e9e, 0x0005, 0xa186, + 0x0013, 0x1128, 0x6004, 0xa082, 0x0085, 0x2008, 0x04a8, 0xa186, + 0x0027, 0x11e8, 0x080c, 0x6dc1, 0x080c, 0x2b73, 0x00d6, 0x6010, + 0x2068, 0x080c, 0x986a, 0x0150, 0x6837, 0x0103, 0x6847, 0x0000, + 0x684b, 0x0029, 0x080c, 0x5271, 0x080c, 0x9a1f, 0x00de, 0x080c, + 0x82eb, 0x080c, 0x6e9e, 0x0005, 0x080c, 0x8331, 0x0ce0, 0xa186, + 0x0014, 0x1dd0, 0x080c, 0x6dc1, 0x00d6, 0x6010, 0x2068, 0x080c, + 0x986a, 0x0d60, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, 0x0006, + 0x6850, 0xc0ec, 0x6852, 0x08f0, 0x0002, 0x93ce, 0x93cc, 0x93cc, + 0x93cc, 0x93cc, 0x93cc, 0x93e6, 0x080c, 0x14fa, 0x080c, 0x6dc1, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, + 0x0035, 0x1118, 0x2001, 0xb3b5, 0x0010, 0x2001, 0xb3b6, 0x2004, + 0x6016, 0x6003, 0x000c, 0x080c, 0x6e9e, 0x0005, 0x080c, 0x6dc1, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, + 0x0035, 0x1118, 0x2001, 0xb3b5, 0x0010, 0x2001, 0xb3b6, 0x2004, + 0x6016, 0x6003, 0x000e, 0x080c, 0x6e9e, 0x0005, 0xa182, 0x008c, + 0x1220, 0xa182, 0x0085, 0x0208, 0x001a, 0x080c, 0x8331, 0x0005, + 0x940f, 0x940f, 0x940f, 0x940f, 0x9411, 0x9464, 0x940f, 0x080c, + 0x14fa, 0x00d6, 0x00f6, 0x2c78, 0x080c, 0x5177, 0x00fe, 0x0168, + 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, + 0x0035, 0x1118, 0x00de, 0x0804, 0x9477, 0x080c, 0x9a1f, 0x080c, + 0x986a, 0x01c8, 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4, + 0x0128, 0x684b, 0x0006, 0xc0ec, 0x6852, 0x0048, 0xd0bc, 0x0118, + 0x684b, 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x9ae0, 0x6847, + 0x0000, 0x080c, 0x5271, 0x2c68, 0x080c, 0x8295, 0x01c0, 0x6003, + 0x0001, 0x6007, 0x001e, 0x600b, 0xffff, 0x2009, 0xb68e, 0x210c, + 0x6136, 0x2009, 0xb68f, 0x210c, 0x613a, 0x6918, 0x611a, 0x080c, + 0x9c35, 0x6950, 0x6152, 0x601f, 0x0001, 0x080c, 0x69f6, 0x2d60, + 0x080c, 0x82eb, 0x00de, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5177, + 0x00fe, 0x0598, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035, + 0x0130, 0xa186, 0x001e, 0x0118, 0xa186, 0x0039, 0x1530, 0x00d6, + 0x2c68, 0x080c, 0x9d16, 0x1904, 0x94bc, 0x080c, 0x8295, 0x01d8, + 0x6106, 0x6003, 0x0001, 0x601f, 0x0001, 0x6918, 0x611a, 0x6928, + 0x612a, 0x692c, 0x612e, 0x6930, 0xa18c, 0x00ff, 0x6132, 0x6934, + 0x6136, 0x6938, 0x613a, 0x6950, 0x6152, 0x080c, 0x9c35, 0x080c, + 0x69f6, 0x080c, 0x6e9e, 0x2d60, 0x00f8, 0x00d6, 0x6010, 0x2068, + 0x080c, 0x986a, 0x01c8, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0128, + 0xc0ec, 0x6852, 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0x684b, + 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x9ae0, 0x6847, 0x0000, + 0x080c, 0x5271, 0x080c, 0x9a1f, 0x00de, 0x080c, 0x82eb, 0x0005, + 0x0016, 0x00d6, 0x6010, 0x2068, 0x080c, 0x986a, 0x0140, 0x6837, + 0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x080c, 0x5271, 0x00de, + 0x001e, 0xa186, 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, + 0x0027, 0x0118, 0x080c, 0x8331, 0x0030, 0x080c, 0x6dc1, 0x080c, + 0x9a2b, 0x080c, 0x6e9e, 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6, + 0x2029, 0x0001, 0xa182, 0x0101, 0x1208, 0x0010, 0x2009, 0x0100, + 0x2130, 0x2069, 0xb698, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, + 0xaf90, 0x001d, 0x080c, 0x953f, 0xa6b2, 0x0020, 0x7804, 0xa06d, + 0x0110, 0x080c, 0x1604, 0x080c, 0x15dd, 0x0500, 0x8528, 0x6837, + 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x1228, + 0x2608, 0xad90, 0x000f, 0x0459, 0x0088, 0xa6b2, 0x003c, 0x2009, + 0x003c, 0x2d78, 0xad90, 0x000f, 0x0411, 0x0c28, 0x00fe, 0x852f, + 0xa5ad, 0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0028, 0x00fe, 0x852f, + 0xa5ad, 0x0003, 0x7d36, 0x00de, 0x006e, 0x005e, 0x0005, 0x00f6, + 0x8dff, 0x0158, 0x6804, 0xa07d, 0x0130, 0x6807, 0x0000, 0x080c, + 0x5271, 0x2f68, 0x0cb8, 0x080c, 0x5271, 0x00fe, 0x0005, 0x0156, + 0xa184, 0x0001, 0x0108, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007, + 0x2012, 0x8318, 0x8210, 0x1f04, 0x9546, 0x015e, 0x0005, 0x0066, + 0x0126, 0x2091, 0x8000, 0x2031, 0x0001, 0x601c, 0xa084, 0x000f, + 0x0083, 0x012e, 0x006e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0066, + 0x2031, 0x0000, 0x601c, 0xa084, 0x000f, 0x001b, 0x006e, 0x012e, + 0x0005, 0x9586, 0x9586, 0x9581, 0x95a8, 0x9574, 0x9581, 0x95a8, + 0x9581, 0x9581, 0x9574, 0x9581, 0x080c, 0x14fa, 0x0036, 0x2019, + 0x0010, 0x080c, 0xa8af, 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, + 0x0005, 0xa006, 0x0005, 0xa085, 0x0001, 0x0005, 0x00d6, 0x86ff, + 0x11d8, 0x6010, 0x2068, 0x080c, 0x986a, 0x01c0, 0x6834, 0xa086, + 0x0139, 0x1128, 0x684b, 0x0005, 0x6853, 0x0000, 0x0028, 0xa00e, + 0x2001, 0x0005, 0x080c, 0x5344, 0x080c, 0x9ae0, 0x080c, 0x5271, + 0x080c, 0x82eb, 0xa085, 0x0001, 0x00de, 0x0005, 0xa006, 0x0ce0, + 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14fa, 0x000b, 0x0005, 0x95bf, + 0x95e0, 0x95c1, 0x95ff, 0x95dd, 0x95bf, 0x9581, 0x9586, 0x9586, + 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x080c, + 0x14fa, 0x86ff, 0x11b8, 0x601c, 0xa086, 0x0006, 0x0198, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x986a, 0x0110, 0x080c, 0x9ae0, 0x00de, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x69f6, + 0x080c, 0x6e9e, 0xa085, 0x0001, 0x0005, 0x080c, 0x190f, 0x0c08, + 0x00e6, 0x2071, 0xb3d9, 0x7024, 0xac06, 0x1110, 0x080c, 0x7c41, + 0x601c, 0xa084, 0x000f, 0xa086, 0x0006, 0x1150, 0x0086, 0x0096, + 0x2049, 0x0001, 0x2c40, 0x080c, 0x7e0d, 0x009e, 0x008e, 0x0010, + 0x080c, 0x7b3e, 0x00ee, 0x1928, 0x080c, 0x9581, 0x0005, 0x0036, + 0x00e6, 0x2071, 0xb3d9, 0x703c, 0xac06, 0x1140, 0x2019, 0x0000, + 0x080c, 0x7cc4, 0x00ee, 0x003e, 0x0804, 0x95c1, 0x080c, 0x7f2b, + 0x00ee, 0x003e, 0x1904, 0x95c1, 0x080c, 0x9581, 0x0005, 0x00c6, + 0x601c, 0xa084, 0x000f, 0x0013, 0x00ce, 0x0005, 0x9630, 0x969a, + 0x97c8, 0x963b, 0x9a2b, 0x9630, 0xa8a1, 0x82eb, 0x969a, 0x9629, + 0x9833, 0x080c, 0x14fa, 0x080c, 0x9a66, 0x1110, 0x080c, 0x8890, + 0x0005, 0x080c, 0x6dc1, 0x080c, 0x6e9e, 0x080c, 0x82eb, 0x0005, + 0x6017, 0x0001, 0x0005, 0x6010, 0xa080, 0x0019, 0x2c02, 0x6000, + 0xa08a, 0x0010, 0x1a0c, 0x14fa, 0x000b, 0x0005, 0x9656, 0x9658, + 0x9678, 0x968a, 0x9697, 0x9656, 0x9630, 0x9630, 0x9630, 0x968a, + 0x968a, 0x9656, 0x9656, 0x9656, 0x9656, 0x9694, 0x080c, 0x14fa, + 0x00e6, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0xb3d9, + 0x7024, 0xac06, 0x0190, 0x080c, 0x7b3e, 0x6007, 0x0085, 0x6003, + 0x000b, 0x601f, 0x0002, 0x2001, 0xb3b6, 0x2004, 0x6016, 0x080c, + 0x69f6, 0x080c, 0x6e9e, 0x00ee, 0x0005, 0x6017, 0x0001, 0x0cd8, + 0x00d6, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x00de, 0x6007, + 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x69f6, 0x080c, + 0x6e9e, 0x0005, 0x00d6, 0x6017, 0x0001, 0x6010, 0x2068, 0x6850, + 0xc0b5, 0x6852, 0x00de, 0x0005, 0x080c, 0x82eb, 0x0005, 0x080c, + 0x190f, 0x08f0, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14fa, 0x000b, + 0x0005, 0x96b1, 0x9638, 0x96b3, 0x96b1, 0x96b3, 0x96b3, 0x9631, + 0x96b1, 0x962b, 0x962b, 0x96b1, 0x96b1, 0x96b1, 0x96b1, 0x96b1, + 0x96b1, 0x080c, 0x14fa, 0x00d6, 0x6018, 0x2068, 0x6804, 0xa084, + 0x00ff, 0x00de, 0xa08a, 0x000c, 0x1a0c, 0x14fa, 0x000b, 0x0005, + 0x96cc, 0x976e, 0x96ce, 0x9708, 0x96ce, 0x9708, 0x96ce, 0x96d8, + 0x96cc, 0x9708, 0x96cc, 0x96f4, 0x080c, 0x14fa, 0x6004, 0xa08e, + 0x0016, 0x0588, 0xa08e, 0x0004, 0x0570, 0xa08e, 0x0002, 0x0558, + 0x6004, 0x080c, 0x9a66, 0x0904, 0x9787, 0xa08e, 0x0021, 0x0904, + 0x978b, 0xa08e, 0x0022, 0x0904, 0x9787, 0xa08e, 0x003d, 0x0904, + 0x978b, 0xa08e, 0x0039, 0x0904, 0x978f, 0xa08e, 0x0035, 0x0904, + 0x978f, 0xa08e, 0x001e, 0x0188, 0xa08e, 0x0001, 0x1150, 0x00d6, + 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x00de, 0xa086, 0x0006, + 0x0110, 0x080c, 0x2b73, 0x080c, 0x8890, 0x080c, 0x9a2b, 0x0005, + 0x00c6, 0x00d6, 0x6104, 0xa186, 0x0016, 0x0904, 0x975f, 0xa186, + 0x0002, 0x1518, 0x6018, 0x2068, 0x2001, 0xb134, 0x2004, 0xd0ac, + 0x1904, 0x97b1, 0x68a0, 0xd0bc, 0x1904, 0x97b1, 0x6840, 0xa084, + 0x00ff, 0xa005, 0x0190, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, + 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x080c, 0x8295, 0x0128, + 0x2d00, 0x601a, 0x601f, 0x0001, 0x0450, 0x00de, 0x00ce, 0x6004, + 0xa08e, 0x0002, 0x11a8, 0x6018, 0xa080, 0x0028, 0x2004, 0xa086, + 0x007e, 0x1170, 0x2009, 0xb134, 0x2104, 0xc085, 0x200a, 0x00e6, + 0x2071, 0xb100, 0x080c, 0x4a3b, 0x00ee, 0x080c, 0x8890, 0x0020, + 0x080c, 0x8890, 0x080c, 0x2b73, 0x00e6, 0x0126, 0x2091, 0x8000, + 0x080c, 0x2b99, 0x012e, 0x00ee, 0x080c, 0x9a2b, 0x0005, 0x2001, + 0x0002, 0x080c, 0x4d75, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, + 0x6a3c, 0x080c, 0x6e9e, 0x00de, 0x00ce, 0x0c80, 0x00c6, 0x00d6, + 0x6104, 0xa186, 0x0016, 0x0d58, 0x6018, 0x2068, 0x6840, 0xa084, + 0x00ff, 0xa005, 0x0904, 0x9735, 0x8001, 0x6842, 0x6003, 0x0001, + 0x080c, 0x6a3c, 0x080c, 0x6e9e, 0x00de, 0x00ce, 0x08b8, 0x080c, + 0x8890, 0x0804, 0x9705, 0x080c, 0x88be, 0x0804, 0x9705, 0x00d6, + 0x2c68, 0x6104, 0x080c, 0x9d16, 0x00de, 0x0118, 0x080c, 0x82eb, + 0x00b8, 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, 0x6032, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038, 0x600a, + 0x2001, 0xb3b6, 0x2004, 0x6016, 0x080c, 0x69f6, 0x080c, 0x6e9e, + 0x0005, 0x00de, 0x00ce, 0x080c, 0x8890, 0x080c, 0x2b73, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x080c, 0x2b99, 0x6013, 0x0000, 0x601f, + 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x012e, 0x00ee, 0x0005, + 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14fa, 0x000b, 0x0005, 0x97df, + 0x97df, 0x97df, 0x97df, 0x97df, 0x97df, 0x97df, 0x97df, 0x97df, + 0x9630, 0x97df, 0x9638, 0x97e1, 0x9638, 0x97ee, 0x97df, 0x080c, + 0x14fa, 0x6004, 0xa086, 0x008b, 0x0148, 0x6007, 0x008b, 0x6003, + 0x000d, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x0005, 0x080c, 0x9a1f, + 0x080c, 0x986a, 0x0580, 0x080c, 0x2b73, 0x00d6, 0x080c, 0x986a, + 0x0168, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006, 0x6847, + 0x0000, 0x6850, 0xc0ed, 0x6852, 0x080c, 0x5271, 0x2c68, 0x080c, + 0x8295, 0x0150, 0x6818, 0x601a, 0x080c, 0x9c35, 0x00c6, 0x2d60, + 0x080c, 0x9a2b, 0x00ce, 0x0008, 0x2d60, 0x00de, 0x6013, 0x0000, + 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x6a3c, + 0x080c, 0x6e9e, 0x0078, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, + 0x0039, 0x0118, 0xa186, 0x0035, 0x1118, 0x080c, 0x2b73, 0x08b0, + 0x080c, 0x9a2b, 0x0005, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14fa, + 0x000b, 0x0005, 0x984a, 0x984a, 0x984a, 0x984c, 0x984d, 0x984a, + 0x984a, 0x984a, 0x984a, 0x984a, 0x984a, 0x984a, 0x984a, 0x984a, + 0x984a, 0x984a, 0x080c, 0x14fa, 0x0005, 0x080c, 0x7f2b, 0x190c, + 0x14fa, 0x6110, 0x2168, 0x684b, 0x0006, 0x080c, 0x5271, 0x080c, + 0x82eb, 0x0005, 0xa284, 0x0007, 0x1158, 0xa282, 0xb800, 0x0240, + 0x2001, 0xb116, 0x2004, 0xa202, 0x1218, 0xa085, 0x0001, 0x0005, + 0xa006, 0x0ce8, 0x0026, 0x6210, 0xa294, 0xf000, 0x002e, 0x0005, + 0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, 0x2091, 0x8000, 0x2061, + 0xb800, 0x2071, 0xb100, 0x7344, 0x7064, 0xa302, 0x12a8, 0x601c, + 0xa206, 0x1160, 0x080c, 0x9bc0, 0x0148, 0x080c, 0x9a66, 0x1110, + 0x080c, 0x8890, 0x00c6, 0x080c, 0x82eb, 0x00ce, 0xace0, 0x0018, + 0x7058, 0xac02, 0x1208, 0x0c38, 0x012e, 0x000e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0xa188, 0xb235, 0x210c, + 0x81ff, 0x0170, 0x2061, 0xb800, 0x2071, 0xb100, 0x0016, 0x080c, + 0x8295, 0x001e, 0x0138, 0x611a, 0x080c, 0x2b73, 0x080c, 0x82eb, + 0xa006, 0x0010, 0xa085, 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005, + 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8295, + 0x005e, 0x0180, 0x6612, 0x651a, 0x080c, 0x9c35, 0x601f, 0x0003, + 0x2009, 0x004b, 0x080c, 0x831a, 0xa085, 0x0001, 0x012e, 0x005e, + 0x00ce, 0x0005, 0xa006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, + 0x8000, 0x62a0, 0x00c6, 0x080c, 0x9ae4, 0x005e, 0x0550, 0x6013, + 0x0000, 0x651a, 0x080c, 0x9c35, 0x601f, 0x0003, 0x0016, 0x00c6, + 0x2560, 0x080c, 0x501c, 0x00ce, 0x080c, 0x6b35, 0x0076, 0x2039, + 0x0000, 0x080c, 0x6a6b, 0x2c08, 0x080c, 0xaa51, 0x007e, 0x001e, + 0xd184, 0x0128, 0x080c, 0x82eb, 0xa085, 0x0001, 0x0030, 0x2009, + 0x004c, 0x080c, 0x831a, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, + 0x0005, 0xa006, 0x0cd0, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, + 0x8295, 0x2c78, 0x00ce, 0x0180, 0x7e12, 0x2c00, 0x781a, 0x781f, + 0x0003, 0x2021, 0x0005, 0x080c, 0x9960, 0x2f60, 0x2009, 0x004d, + 0x080c, 0x831a, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, + 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, 0x8295, 0x2c78, 0x00ce, + 0x0178, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, + 0x0439, 0x2f60, 0x2009, 0x004e, 0x080c, 0x831a, 0xa085, 0x0001, + 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6, 0x0046, 0x00c6, + 0x080c, 0x8295, 0x2c78, 0x00ce, 0x0178, 0x7e12, 0x2c00, 0x781a, + 0x781f, 0x0003, 0x2021, 0x0004, 0x0059, 0x2f60, 0x2009, 0x0052, + 0x080c, 0x831a, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, + 0x0096, 0x0076, 0x0126, 0x2091, 0x8000, 0x080c, 0x4fbe, 0x0118, + 0x2001, 0x9965, 0x0028, 0x080c, 0x4f90, 0x0158, 0x2001, 0x996b, + 0x0006, 0xa00e, 0x2400, 0x080c, 0x5344, 0x080c, 0x5271, 0x000e, + 0x0807, 0x2418, 0x080c, 0x6d63, 0x62a0, 0x0086, 0x2041, 0x0001, + 0x2039, 0x0001, 0x2608, 0x080c, 0x6b4e, 0x008e, 0x080c, 0x6a6b, + 0x2f08, 0x2648, 0x080c, 0xaa51, 0x613c, 0x81ff, 0x090c, 0x6bf7, + 0x012e, 0x007e, 0x009e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x00c6, 0x080c, 0x8295, 0x001e, 0x0188, 0x660a, 0x611a, 0x080c, + 0x9c35, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x001f, 0x080c, + 0x831a, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8295, 0x001e, + 0x0188, 0x660a, 0x611a, 0x080c, 0x9c35, 0x601f, 0x0008, 0x2d00, + 0x6012, 0x2009, 0x0021, 0x080c, 0x831a, 0xa085, 0x0001, 0x012e, + 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x00c6, 0x080c, 0x8295, 0x001e, 0x0188, 0x660a, 0x611a, 0x080c, + 0x9c35, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x003d, 0x080c, + 0x831a, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x9ae4, 0x001e, + 0x0180, 0x611a, 0x080c, 0x9c35, 0x601f, 0x0001, 0x2d00, 0x6012, + 0x2009, 0x0000, 0x080c, 0x831a, 0xa085, 0x0001, 0x012e, 0x00ce, + 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, + 0x080c, 0x8295, 0x001e, 0x0188, 0x660a, 0x611a, 0x080c, 0x9c35, + 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0044, 0x080c, 0x831a, + 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x0026, + 0x00d6, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, + 0x00de, 0x002e, 0x0005, 0x0006, 0x6000, 0xa086, 0x0000, 0x0190, + 0x6013, 0x0000, 0x601f, 0x0007, 0x2001, 0xb3b5, 0x2004, 0x0006, + 0xa082, 0x0051, 0x000e, 0x0208, 0x8004, 0x6016, 0x080c, 0xaf00, + 0x603f, 0x0000, 0x000e, 0x0005, 0x0066, 0x00c6, 0x00d6, 0x2031, + 0xb153, 0x2634, 0xd6e4, 0x0128, 0x6618, 0x2660, 0x6e48, 0x080c, + 0x4f49, 0x00de, 0x00ce, 0x006e, 0x0005, 0x0006, 0x0016, 0x6004, + 0xa08e, 0x0002, 0x0140, 0xa08e, 0x0003, 0x0128, 0xa08e, 0x0004, + 0x0110, 0xa085, 0x0001, 0x001e, 0x000e, 0x0005, 0x0006, 0x00d6, + 0x6010, 0xa06d, 0x0148, 0x6834, 0xa086, 0x0139, 0x0138, 0x6838, + 0xd0fc, 0x0110, 0xa006, 0x0010, 0xa085, 0x0001, 0x00de, 0x000e, + 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8295, + 0x001e, 0x0190, 0x611a, 0x080c, 0x9c35, 0x601f, 0x0001, 0x2d00, + 0x6012, 0x080c, 0x2b73, 0x2009, 0x0028, 0x080c, 0x831a, 0xa085, + 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0xa186, 0x0015, + 0x1178, 0x2011, 0xb120, 0x2204, 0xa086, 0x0074, 0x1148, 0x080c, + 0x8bed, 0x6003, 0x0001, 0x6007, 0x0029, 0x080c, 0x6a3c, 0x0020, + 0x080c, 0x8890, 0x080c, 0x82eb, 0x0005, 0xa186, 0x0016, 0x1128, + 0x2001, 0x0004, 0x080c, 0x4d75, 0x00e8, 0xa186, 0x0015, 0x11e8, + 0x2011, 0xb120, 0x2204, 0xa086, 0x0014, 0x11b8, 0x00d6, 0x6018, + 0x2068, 0x080c, 0x4ebf, 0x00de, 0x080c, 0x8ca6, 0x1170, 0x00d6, + 0x6018, 0x2068, 0x6890, 0x00de, 0xa005, 0x0138, 0x2001, 0x0006, + 0x080c, 0x4d75, 0x080c, 0x8469, 0x0020, 0x080c, 0x8890, 0x080c, + 0x82eb, 0x0005, 0x6848, 0xa086, 0x0005, 0x1108, 0x0009, 0x0005, + 0x6850, 0xc0ad, 0x6852, 0x0005, 0x00e6, 0x0126, 0x2071, 0xb100, + 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0608, 0x7048, 0x2060, + 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x0018, 0x7058, 0xac02, + 0x1208, 0x0cb0, 0x2061, 0xb800, 0x0c98, 0x6003, 0x0008, 0x8529, + 0x7546, 0xaca8, 0x0018, 0x7058, 0xa502, 0x1230, 0x754a, 0xa085, + 0x0001, 0x012e, 0x00ee, 0x0005, 0x704b, 0xb800, 0x0cc0, 0xa006, + 0x0cc0, 0x00e6, 0x2071, 0xb68c, 0x7014, 0xd0e4, 0x0150, 0x6013, + 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c, 0x69f6, 0x080c, + 0x6e9e, 0x00ee, 0x0005, 0x00c6, 0x00f6, 0x2c78, 0x080c, 0x5177, + 0x00fe, 0x0120, 0x601c, 0xa084, 0x000f, 0x0013, 0x00ce, 0x0005, + 0x9630, 0x9b3b, 0x9b3e, 0x9b41, 0xaced, 0xad08, 0xad0b, 0x9630, + 0x9630, 0x080c, 0x14fa, 0xe000, 0xe000, 0x0005, 0xe000, 0xe000, + 0x0005, 0x0009, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5177, 0x0538, + 0x080c, 0x8295, 0x1128, 0x2001, 0xb3b7, 0x2004, 0x783e, 0x00f8, + 0x7818, 0x601a, 0x080c, 0x9c35, 0x781c, 0xa086, 0x0003, 0x0128, + 0x7808, 0x6036, 0x2f00, 0x603a, 0x0020, 0x7808, 0x603a, 0x2f00, + 0x6036, 0x602a, 0x601f, 0x0001, 0x6007, 0x0035, 0x6003, 0x0001, + 0x7950, 0x6152, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x2f60, 0x00fe, + 0x0005, 0x0016, 0x00f6, 0x682c, 0x6032, 0xa08e, 0x0001, 0x0138, + 0xa086, 0x0005, 0x0140, 0xa006, 0x602a, 0x602e, 0x00a0, 0x6820, + 0xc0f4, 0xc0d5, 0x6822, 0x6810, 0x2078, 0x787c, 0x6938, 0xa102, + 0x7880, 0x6934, 0xa103, 0x1e78, 0x6834, 0x602a, 0x6838, 0xa084, + 0xfffc, 0x683a, 0x602e, 0x2d00, 0x6036, 0x6808, 0x603a, 0x6918, + 0x611a, 0x6950, 0x6152, 0x601f, 0x0001, 0x6007, 0x0039, 0x6003, + 0x0001, 0x080c, 0x69f6, 0x6803, 0x0002, 0x00fe, 0x001e, 0x0005, + 0x00f6, 0x2c78, 0x080c, 0x5177, 0x1118, 0xa085, 0x0001, 0x0070, + 0x6020, 0xd0f4, 0x1150, 0xc0f5, 0x6022, 0x6010, 0x2078, 0x7828, + 0x603a, 0x782c, 0x6036, 0x080c, 0x190f, 0xa006, 0x00fe, 0x0005, + 0x0006, 0x0016, 0x6004, 0xa08e, 0x0034, 0x01b8, 0xa08e, 0x0035, + 0x01a0, 0xa08e, 0x0036, 0x0188, 0xa08e, 0x0037, 0x0170, 0xa08e, + 0x0038, 0x0158, 0xa08e, 0x0039, 0x0140, 0xa08e, 0x003a, 0x0128, + 0xa08e, 0x003b, 0x0110, 0xa085, 0x0001, 0x001e, 0x000e, 0x0005, + 0x0006, 0x0016, 0x0026, 0x0036, 0x00e6, 0x2001, 0xb3b1, 0x200c, + 0x8000, 0x2014, 0x2001, 0x0032, 0x080c, 0x68b3, 0x2001, 0xb3b5, + 0x82ff, 0x1110, 0x2011, 0x0002, 0x2202, 0x2001, 0xb3b3, 0x200c, + 0x8000, 0x2014, 0x2071, 0xb38e, 0x711a, 0x721e, 0x2001, 0x0064, + 0x080c, 0x68b3, 0x2001, 0xb3b6, 0x82ff, 0x1110, 0x2011, 0x0002, + 0x2202, 0x2009, 0xb3b7, 0xa280, 0x000a, 0x200a, 0x080c, 0x5193, + 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x0006, 0x00e6, + 0x2001, 0xb3b5, 0x2003, 0x0028, 0x2001, 0xb3b6, 0x2003, 0x0014, + 0x2071, 0xb38e, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001, 0xb3b7, + 0x2003, 0x001e, 0x00ee, 0x000e, 0x0005, 0x00d6, 0x6054, 0xa06d, + 0x0110, 0x080c, 0x15f4, 0x00de, 0x0005, 0x0005, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x00c6, 0x080c, 0x8295, 0x001e, 0x0178, 0x611a, + 0x0ca1, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033, 0x080c, + 0x831a, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, + 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb100, 0xa186, 0x0015, 0x1500, + 0x7080, 0xa086, 0x0018, 0x11e0, 0x6010, 0x2068, 0x6a3c, 0xd2e4, + 0x1160, 0x2c78, 0x080c, 0x705a, 0x01d8, 0x706c, 0x6a50, 0xa206, + 0x1160, 0x7070, 0x6a54, 0xa206, 0x1140, 0x6218, 0xa290, 0x0028, + 0x2214, 0x2009, 0x0000, 0x080c, 0x2bb8, 0x080c, 0x8469, 0x0020, + 0x080c, 0x8890, 0x080c, 0x82eb, 0x00fe, 0x00ee, 0x00de, 0x0005, + 0x7050, 0x6a54, 0xa206, 0x0d48, 0x0c80, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x00c6, 0x080c, 0x8295, 0x001e, 0x0180, 0x611a, 0x080c, + 0x9c35, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0043, 0x080c, + 0x831a, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, + 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb100, 0xa186, 0x0015, 0x11c0, + 0x7080, 0xa086, 0x0004, 0x11a0, 0x6010, 0xa0e8, 0x000f, 0x2c78, + 0x080c, 0x705a, 0x01a8, 0x706c, 0x6a08, 0xa206, 0x1130, 0x7070, + 0x6a0c, 0xa206, 0x1110, 0x080c, 0x2b73, 0x080c, 0x8469, 0x0020, + 0x080c, 0x8890, 0x080c, 0x82eb, 0x00fe, 0x00ee, 0x00de, 0x0005, + 0x7050, 0x6a0c, 0xa206, 0x0d78, 0x0c80, 0x0016, 0x0026, 0x684c, + 0xd0ac, 0x0178, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0150, 0x6860, + 0xa106, 0x1118, 0x685c, 0xa206, 0x0120, 0x6962, 0x6a5e, 0xa085, + 0x0001, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0036, 0x6310, 0x2368, + 0x684a, 0x6952, 0xa29e, 0x4000, 0x11a0, 0x00c6, 0x6318, 0x2360, + 0x2009, 0x0000, 0x6838, 0xd0f4, 0x1140, 0x080c, 0x50bc, 0x1108, + 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x6a66, 0x696a, 0x00ce, + 0x0080, 0x6a66, 0x3918, 0xa398, 0x0006, 0x231c, 0x686b, 0x0004, + 0x6b72, 0x00c6, 0x6318, 0x2360, 0x6004, 0xa084, 0x00ff, 0x686e, + 0x00ce, 0x080c, 0x5271, 0x003e, 0x00de, 0x0005, 0x00c6, 0x0026, + 0x0016, 0xa186, 0x0035, 0x0110, 0x6a34, 0x0008, 0x6a28, 0x080c, + 0x985a, 0x01f0, 0x2260, 0x611c, 0xa186, 0x0003, 0x0118, 0xa186, + 0x0006, 0x1190, 0x6834, 0xa206, 0x0140, 0x6838, 0xa206, 0x1160, + 0x6108, 0x6834, 0xa106, 0x1140, 0x0020, 0x6008, 0x6938, 0xa106, + 0x1118, 0x6018, 0x6918, 0xa106, 0x001e, 0x002e, 0x00ce, 0x0005, + 0xa085, 0x0001, 0x0cc8, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, + 0x14fa, 0x0013, 0x006e, 0x0005, 0x9d5c, 0xa224, 0xa353, 0x9d5c, + 0x9d5c, 0x9d5c, 0x9d5c, 0x9d5c, 0x9d94, 0xa3cf, 0x9d5c, 0x9d5c, + 0x9d5c, 0x9d5c, 0x9d5c, 0x9d5c, 0x080c, 0x14fa, 0x0066, 0x6000, + 0xa0b2, 0x0010, 0x1a0c, 0x14fa, 0x0013, 0x006e, 0x0005, 0x9d77, + 0xa846, 0x9d77, 0x9d77, 0x9d77, 0x9d77, 0x9d77, 0x9d77, 0xa80a, + 0xa88e, 0x9d77, 0xae32, 0xae62, 0xae32, 0xae62, 0x9d77, 0x080c, + 0x14fa, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14fa, 0x0013, + 0x006e, 0x0005, 0x9d92, 0xa511, 0xa5de, 0xa60b, 0xa68f, 0x9d92, + 0xa77c, 0xa727, 0xa3db, 0xa7e0, 0xa7f5, 0x9d92, 0x9d92, 0x9d92, + 0x9d92, 0x9d92, 0x080c, 0x14fa, 0xa1b2, 0x0080, 0x1a0c, 0x14fa, + 0x2100, 0xa1b2, 0x0040, 0x1a04, 0xa198, 0x0002, 0x9dde, 0x9fa9, + 0x9dde, 0x9dde, 0x9dde, 0x9fb0, 0x9dde, 0x9dde, 0x9dde, 0x9dde, + 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9dde, + 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9de0, 0x9e3e, 0x9e4d, + 0x9e9b, 0x9eb9, 0x9f37, 0x9f96, 0x9dde, 0x9dde, 0x9fb3, 0x9dde, + 0x9dde, 0x9fc6, 0x9fd1, 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9dde, + 0xa04d, 0x9dde, 0x9dde, 0xa05c, 0x9dde, 0x9dde, 0xa023, 0x9dde, + 0x9dde, 0x9dde, 0xa074, 0x9dde, 0x9dde, 0x9dde, 0xa0ee, 0x9dde, + 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0x9dde, 0xa15f, 0x080c, 0x14fa, + 0x080c, 0x517b, 0x1150, 0x2001, 0xb134, 0x2004, 0xd0cc, 0x1128, + 0xa084, 0x0009, 0xa086, 0x0008, 0x1140, 0x6007, 0x0009, 0x602b, + 0x0009, 0x6013, 0x0000, 0x0804, 0x9fa4, 0x080c, 0x516b, 0x00e6, + 0x00c6, 0x0036, 0x0026, 0x0016, 0x6218, 0x2270, 0x72a0, 0x0026, + 0x2019, 0x0029, 0x080c, 0x6b35, 0x0076, 0x2039, 0x0000, 0x080c, + 0x6a6b, 0x2c08, 0x080c, 0xaa51, 0x007e, 0x001e, 0x2e60, 0x080c, + 0x501c, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x6618, 0x00c6, + 0x2660, 0x080c, 0x4e30, 0x00ce, 0xa6b0, 0x0001, 0x2634, 0xa684, + 0x00ff, 0xa082, 0x0006, 0x0278, 0x080c, 0xa995, 0x1904, 0x9e95, + 0x080c, 0xa935, 0x1120, 0x6007, 0x0008, 0x0804, 0x9fa4, 0x6007, + 0x0009, 0x0804, 0x9fa4, 0x080c, 0xab41, 0x0128, 0x080c, 0xa995, + 0x0d78, 0x0804, 0x9e95, 0x6013, 0x1900, 0x0c88, 0x080c, 0x2c87, + 0x1904, 0xa195, 0x6106, 0x080c, 0xa8ef, 0x6007, 0x0006, 0x0804, + 0x9fa4, 0x6007, 0x0007, 0x0804, 0x9fa4, 0x080c, 0xae96, 0x1904, + 0xa195, 0x080c, 0x2c87, 0x1904, 0xa195, 0x00d6, 0x6618, 0x2668, + 0x6e04, 0xa684, 0x00ff, 0xa082, 0x0006, 0x1220, 0x2001, 0x0001, + 0x080c, 0x4d63, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0188, + 0xa686, 0x0004, 0x0170, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, + 0x0140, 0xa686, 0x0004, 0x0128, 0xa686, 0x0005, 0x0110, 0x00de, + 0x00e0, 0x080c, 0xa9f3, 0x11a0, 0xa686, 0x0006, 0x1150, 0x0026, + 0x6218, 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x2bb8, + 0x002e, 0x080c, 0x4ebf, 0x6007, 0x000a, 0x00de, 0x0804, 0x9fa4, + 0x6007, 0x000b, 0x00de, 0x0804, 0x9fa4, 0x080c, 0x2b73, 0x6007, + 0x0001, 0x0804, 0x9fa4, 0x080c, 0xae96, 0x1904, 0xa195, 0x080c, + 0x2c87, 0x1904, 0xa195, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, + 0xa686, 0x0707, 0x0d50, 0x0026, 0x6218, 0xa290, 0x0028, 0x2214, + 0x2009, 0x0000, 0x080c, 0x2bb8, 0x002e, 0x6007, 0x000c, 0x0804, + 0x9fa4, 0x080c, 0x517b, 0x1140, 0x2001, 0xb134, 0x2004, 0xa084, + 0x0009, 0xa086, 0x0008, 0x1110, 0x0804, 0x9ded, 0x080c, 0x516b, + 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, + 0x06e8, 0x1138, 0x0026, 0x2001, 0x0006, 0x080c, 0x4da2, 0x002e, + 0x0050, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, + 0x0006, 0x1904, 0x9e95, 0x080c, 0xaa00, 0x1120, 0x6007, 0x000e, + 0x0804, 0x9fa4, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, + 0x00ff, 0x8427, 0x0046, 0x080c, 0x2b73, 0x004e, 0x0016, 0xa006, + 0x2009, 0xb153, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, + 0xacae, 0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, + 0x001e, 0x004e, 0x6007, 0x0001, 0x0804, 0x9fa4, 0x2001, 0x0001, + 0x080c, 0x4d63, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, + 0x2019, 0xb105, 0x2011, 0xb690, 0x080c, 0x8d2b, 0x003e, 0x002e, + 0x001e, 0x015e, 0xa005, 0x0168, 0xa6b4, 0xff00, 0x8637, 0xa682, + 0x0004, 0x0a04, 0x9e95, 0xa682, 0x0007, 0x0a04, 0x9ee3, 0x0804, + 0x9e95, 0x6013, 0x1900, 0x6007, 0x0009, 0x0804, 0x9fa4, 0x080c, + 0x517b, 0x1140, 0x2001, 0xb134, 0x2004, 0xa084, 0x0009, 0xa086, + 0x0008, 0x1110, 0x0804, 0x9ded, 0x080c, 0x516b, 0x6618, 0xa6b0, + 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06b8, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, 0x1904, + 0x9e95, 0x080c, 0xaa28, 0x1138, 0x080c, 0xa935, 0x1120, 0x6007, + 0x0010, 0x0804, 0x9fa4, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, + 0xa4a4, 0x00ff, 0x8427, 0x0046, 0x080c, 0x2b73, 0x004e, 0x0016, + 0xa006, 0x2009, 0xb153, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, + 0x080c, 0xacae, 0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, + 0x00de, 0x001e, 0x004e, 0x6007, 0x0001, 0x00f0, 0x080c, 0xab41, + 0x0140, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0950, 0x0804, + 0x9e95, 0x6013, 0x1900, 0x6007, 0x0009, 0x0070, 0x080c, 0x2c87, + 0x1904, 0xa195, 0x080c, 0xae96, 0x1904, 0xa195, 0x080c, 0xa1bd, + 0x1904, 0x9e95, 0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x6a3c, + 0x0005, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x6a3c, 0x0cc0, + 0x6007, 0x0005, 0x0cc0, 0x080c, 0xae96, 0x1904, 0xa195, 0x080c, + 0x2c87, 0x1904, 0xa195, 0x080c, 0xa1bd, 0x1904, 0x9e95, 0x6007, + 0x0020, 0x6003, 0x0001, 0x080c, 0x6a3c, 0x0005, 0x080c, 0x2c87, + 0x1904, 0xa195, 0x6007, 0x0023, 0x6003, 0x0001, 0x080c, 0x6a3c, + 0x0005, 0x080c, 0xae96, 0x1904, 0xa195, 0x080c, 0x2c87, 0x1904, + 0xa195, 0x080c, 0xa1bd, 0x1904, 0x9e95, 0x0016, 0x0026, 0x2011, + 0xb691, 0x2214, 0xa286, 0xffff, 0x0190, 0x2c08, 0x080c, 0x985a, + 0x01e0, 0x2260, 0x2011, 0xb690, 0x2214, 0x6008, 0xa206, 0x11a8, + 0x6018, 0xa190, 0x0006, 0x2214, 0xa206, 0x01e8, 0x0070, 0x2011, + 0xb690, 0x2214, 0x2c08, 0xa006, 0x080c, 0xac80, 0x11a0, 0x2011, + 0xb691, 0x2214, 0xa286, 0xffff, 0x01a0, 0x2160, 0x6007, 0x0026, + 0x6013, 0x1700, 0x2011, 0xb689, 0x2214, 0xa296, 0xffff, 0x1160, + 0x6007, 0x0025, 0x0048, 0x601c, 0xa086, 0x0007, 0x1d70, 0x080c, + 0x82eb, 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x080c, 0x6a3c, + 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, 0x080c, 0x4d63, 0x0156, + 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0xb105, 0x2011, + 0xb696, 0x080c, 0x8d2b, 0x003e, 0x002e, 0x001e, 0x015e, 0x0120, + 0x6007, 0x0031, 0x0804, 0x9fa4, 0x080c, 0x8a69, 0x080c, 0x58d5, + 0x1158, 0x0006, 0x0026, 0x0036, 0x080c, 0x58f1, 0x0110, 0x080c, + 0x58ac, 0x003e, 0x002e, 0x000e, 0x0005, 0x080c, 0x2c87, 0x1904, + 0xa195, 0x6106, 0x080c, 0xa1d9, 0x6007, 0x002b, 0x0804, 0x9fa4, + 0x6007, 0x002c, 0x0804, 0x9fa4, 0x080c, 0xae96, 0x1904, 0xa195, + 0x080c, 0x2c87, 0x1904, 0xa195, 0x080c, 0xa1bd, 0x1904, 0x9e95, + 0x6106, 0x080c, 0xa1dd, 0x1120, 0x6007, 0x002e, 0x0804, 0x9fa4, + 0x6007, 0x002f, 0x0804, 0x9fa4, 0x080c, 0x2c87, 0x1904, 0xa195, + 0x00e6, 0x00d6, 0x00c6, 0x6018, 0xa080, 0x0001, 0x200c, 0xa184, + 0x00ff, 0xa086, 0x0006, 0x0158, 0xa184, 0xff00, 0x8007, 0xa086, + 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, 0x0804, 0x9fa9, 0x2001, + 0xb172, 0x2004, 0xd0e4, 0x0904, 0xa0eb, 0x2071, 0xb68c, 0x7010, + 0x6036, 0x7014, 0x603a, 0x7108, 0x720c, 0x2001, 0xb153, 0x2004, + 0xd0a4, 0x0140, 0x6018, 0x2068, 0x6810, 0xa106, 0x1118, 0x6814, + 0xa206, 0x01f8, 0x2001, 0xb153, 0x2004, 0xd0ac, 0x1590, 0x2069, + 0xb100, 0x6870, 0xa206, 0x1568, 0x686c, 0xa106, 0x1550, 0x7210, + 0x080c, 0x985a, 0x0558, 0x080c, 0xad1a, 0x0540, 0x622a, 0x6007, + 0x0036, 0x6003, 0x0001, 0x080c, 0x69f6, 0x00ce, 0x00de, 0x00ee, + 0x0005, 0x7214, 0xa286, 0xffff, 0x0150, 0x080c, 0x985a, 0x01b0, + 0xa280, 0x0002, 0x2004, 0x7110, 0xa106, 0x1180, 0x0c08, 0x7210, + 0x2c08, 0xa085, 0x0001, 0x080c, 0xac80, 0x2c10, 0x2160, 0x0130, + 0x08b8, 0x6007, 0x0037, 0x6013, 0x1500, 0x08d8, 0x6007, 0x0037, + 0x6013, 0x1700, 0x08b0, 0x6007, 0x0012, 0x0898, 0x080c, 0x2c87, + 0x1904, 0xa195, 0x6018, 0xa080, 0x0001, 0x2004, 0xa084, 0xff00, + 0x8007, 0xa086, 0x0006, 0x1904, 0x9fa9, 0x00e6, 0x00d6, 0x00c6, + 0x2001, 0xb172, 0x2004, 0xd0e4, 0x0904, 0xa157, 0x2069, 0xb100, + 0x2071, 0xb68c, 0x7008, 0x6036, 0x720c, 0x623a, 0xa286, 0xffff, + 0x1150, 0x7208, 0x00c6, 0x2c08, 0xa085, 0x0001, 0x080c, 0xac80, + 0x2c10, 0x00ce, 0x0588, 0x080c, 0x985a, 0x0570, 0x00c6, 0x0026, + 0x2260, 0x080c, 0x954f, 0x002e, 0x00ce, 0x7118, 0xa18c, 0xff00, + 0x810f, 0xa186, 0x0001, 0x0158, 0xa186, 0x0005, 0x0118, 0xa186, + 0x0007, 0x1178, 0xa280, 0x0004, 0x2004, 0xa005, 0x0150, 0x0056, + 0x7510, 0x7614, 0x080c, 0xad31, 0x005e, 0x00ce, 0x00de, 0x00ee, + 0x0005, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00, 0x6003, + 0x0001, 0x080c, 0x69f6, 0x0c88, 0x6007, 0x003b, 0x602b, 0x0009, + 0x6013, 0x1700, 0x6003, 0x0001, 0x080c, 0x69f6, 0x0c30, 0x6007, + 0x003b, 0x602b, 0x000b, 0x6013, 0x0000, 0x0804, 0xa0c1, 0x00e6, + 0x0026, 0x080c, 0x517b, 0x0558, 0x080c, 0x516b, 0x080c, 0xaf11, + 0x1520, 0x2071, 0xb100, 0x70d0, 0xc085, 0x70d2, 0x00f6, 0x2079, + 0x0100, 0x729c, 0xa284, 0x00ff, 0x706e, 0x78e6, 0xa284, 0xff00, + 0x7270, 0xa205, 0x7072, 0x78ea, 0x00fe, 0x70db, 0x0000, 0x2001, + 0xb153, 0x2004, 0xd0a4, 0x0120, 0x2011, 0xb3f2, 0x2013, 0x07d0, + 0xd0ac, 0x1128, 0x080c, 0x2991, 0x0010, 0x080c, 0xaf3d, 0x002e, + 0x00ee, 0x080c, 0x82eb, 0x0804, 0x9fa8, 0x080c, 0x82eb, 0x0005, + 0x2600, 0x0002, 0xa1a3, 0xa1a3, 0xa1a3, 0xa1a3, 0xa1a3, 0xa1a5, + 0xa1a3, 0xa1a3, 0xa1a3, 0x080c, 0x14fa, 0x080c, 0xae96, 0x1d68, + 0x080c, 0x2c87, 0x1d50, 0x0089, 0x1138, 0x6007, 0x0045, 0x6003, + 0x0001, 0x080c, 0x6a3c, 0x0005, 0x080c, 0x2b73, 0x6007, 0x0001, + 0x6003, 0x0001, 0x080c, 0x6a3c, 0x0005, 0x00d6, 0x0066, 0x6618, + 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0170, + 0xa686, 0x0004, 0x0158, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, + 0x0128, 0xa686, 0x0004, 0x0110, 0xa085, 0x0001, 0x006e, 0x00de, + 0x0005, 0x00d6, 0x0449, 0x00de, 0x0005, 0x00d6, 0x0491, 0x11f0, + 0x680c, 0xa08c, 0xff00, 0x6820, 0xa084, 0x00ff, 0xa115, 0x6212, + 0x6824, 0x602a, 0xd1e4, 0x0118, 0x2009, 0x0001, 0x0060, 0xd1ec, + 0x0168, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x080c, 0x26f6, 0x1130, + 0x2110, 0x2009, 0x0000, 0x080c, 0x2bb8, 0x0018, 0xa085, 0x0001, + 0x0008, 0xa006, 0x00de, 0x0005, 0x2069, 0xb68d, 0x6800, 0xa082, + 0x0010, 0x1228, 0x6013, 0x0000, 0xa085, 0x0001, 0x0008, 0xa006, + 0x0005, 0x6013, 0x0000, 0x2069, 0xb68c, 0x6808, 0xa084, 0xff00, + 0xa086, 0x0800, 0x1140, 0x6800, 0xa084, 0x00ff, 0xa08e, 0x0014, + 0x0110, 0xa08e, 0x0010, 0x0005, 0x6004, 0xa0b2, 0x0080, 0x1a0c, + 0x14fa, 0xa1b6, 0x0013, 0x1130, 0x2008, 0xa1b2, 0x0040, 0x1a04, + 0xa324, 0x0092, 0xa1b6, 0x0027, 0x0120, 0xa1b6, 0x0014, 0x190c, + 0x14fa, 0x2001, 0x0007, 0x080c, 0x4da2, 0x080c, 0x6dc1, 0x080c, + 0x9a2b, 0x080c, 0x6e9e, 0x0005, 0xa284, 0xa286, 0xa284, 0xa284, + 0xa284, 0xa286, 0xa298, 0xa31d, 0xa2e8, 0xa31d, 0xa2f9, 0xa31d, + 0xa298, 0xa31d, 0xa315, 0xa31d, 0xa315, 0xa31d, 0xa31d, 0xa284, + 0xa284, 0xa284, 0xa284, 0xa284, 0xa284, 0xa284, 0xa284, 0xa284, + 0xa284, 0xa284, 0xa286, 0xa284, 0xa31d, 0xa284, 0xa284, 0xa31d, + 0xa284, 0xa31a, 0xa31d, 0xa284, 0xa284, 0xa284, 0xa284, 0xa31d, + 0xa31d, 0xa284, 0xa31d, 0xa31d, 0xa284, 0xa292, 0xa284, 0xa284, + 0xa284, 0xa284, 0xa319, 0xa31d, 0xa284, 0xa284, 0xa31d, 0xa31d, + 0xa284, 0xa284, 0xa284, 0xa284, 0x080c, 0x14fa, 0x080c, 0x6dc1, + 0x2001, 0xb3b5, 0x2004, 0x6016, 0x6003, 0x0002, 0x080c, 0x6e9e, + 0x0804, 0xa323, 0x2001, 0x0000, 0x080c, 0x4d63, 0x0804, 0xa31d, + 0x00f6, 0x2079, 0xb152, 0x7804, 0x00fe, 0xd0ac, 0x1904, 0xa31d, + 0x2001, 0x0000, 0x080c, 0x4d63, 0x6018, 0xa080, 0x0004, 0x2004, + 0xa086, 0x00ff, 0x1140, 0x00f6, 0x2079, 0xb100, 0x7894, 0x8000, + 0x7896, 0x00fe, 0x00e0, 0x00c6, 0x6018, 0x2060, 0x6000, 0xd0f4, + 0x1140, 0x6010, 0xa005, 0x0128, 0x00ce, 0x080c, 0x3dcd, 0x0804, + 0xa31d, 0x00ce, 0x2001, 0xb100, 0x2004, 0xa086, 0x0002, 0x1138, + 0x00f6, 0x2079, 0xb100, 0x7894, 0x8000, 0x7896, 0x00fe, 0x2001, + 0x0002, 0x080c, 0x4d75, 0x080c, 0x6dc1, 0x601f, 0x0001, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x6a3c, 0x080c, 0x6e9e, 0x00c6, + 0x6118, 0x2160, 0x2009, 0x0001, 0x080c, 0x674e, 0x00ce, 0x04d8, + 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0006, 0x0550, 0xa686, 0x0004, 0x0538, 0x2001, 0x0004, + 0x0410, 0x2001, 0xb100, 0x2004, 0xa086, 0x0003, 0x1110, 0x080c, + 0x3dcd, 0x2001, 0x0006, 0x04a1, 0x6618, 0x00d6, 0x2668, 0x6e04, + 0x00de, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0170, 0x2001, + 0x0006, 0x0048, 0x2001, 0x0004, 0x0030, 0x2001, 0x0006, 0x0401, + 0x0020, 0x0018, 0x0010, 0x080c, 0x4da2, 0x080c, 0x6dc1, 0x080c, + 0x82eb, 0x080c, 0x6e9e, 0x0005, 0x2600, 0x0002, 0xa32f, 0xa32f, + 0xa32f, 0xa32f, 0xa32f, 0xa331, 0xa32f, 0xa32f, 0xa32f, 0x080c, + 0x14fa, 0x080c, 0x6dc1, 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x0005, + 0x0016, 0x00d6, 0x6118, 0x2168, 0x6900, 0xd184, 0x0188, 0x6104, + 0xa18e, 0x000a, 0x1128, 0x699c, 0xd1a4, 0x1110, 0x2001, 0x0007, + 0x080c, 0x4d75, 0x2001, 0x0000, 0x080c, 0x4d63, 0x080c, 0x2b99, + 0x00de, 0x001e, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804, 0xa084, + 0xff00, 0x8007, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x14fa, 0xa1b6, + 0x0015, 0x1110, 0x003b, 0x0028, 0xa1b6, 0x0016, 0x190c, 0x14fa, + 0x006b, 0x0005, 0x8956, 0x8956, 0x8956, 0x8956, 0x8956, 0x8956, + 0xa3bb, 0xa382, 0x8956, 0x8956, 0x8956, 0x8956, 0x8956, 0x8956, + 0x8956, 0x8956, 0x8956, 0x8956, 0xa3bb, 0xa3c2, 0x8956, 0x8956, + 0x8956, 0x8956, 0x00f6, 0x2079, 0xb152, 0x7804, 0xd0ac, 0x11e0, + 0x6018, 0xa07d, 0x01c8, 0x7800, 0xd0f4, 0x1118, 0x7810, 0xa005, + 0x1198, 0x2001, 0x0000, 0x080c, 0x4d63, 0x2001, 0x0002, 0x080c, + 0x4d75, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, + 0x6a3c, 0x080c, 0x6e9e, 0x00a8, 0x2011, 0xb683, 0x2204, 0x8211, + 0x220c, 0x080c, 0x26f6, 0x1168, 0x00c6, 0x080c, 0x4e21, 0x0120, + 0x00ce, 0x080c, 0x82eb, 0x0028, 0x080c, 0x4a80, 0x00ce, 0x080c, + 0x82eb, 0x00fe, 0x0005, 0x6604, 0xa6b6, 0x001e, 0x1110, 0x080c, + 0x82eb, 0x0005, 0x080c, 0x8bea, 0x1138, 0x6003, 0x0001, 0x6007, + 0x0001, 0x080c, 0x6a3c, 0x0010, 0x080c, 0x82eb, 0x0005, 0x6004, + 0xa08a, 0x0080, 0x1a0c, 0x14fa, 0x080c, 0x6dc1, 0x080c, 0x9a2b, + 0x080c, 0x6e9e, 0x0005, 0xa182, 0x0040, 0x0002, 0xa3f1, 0xa3f1, + 0xa3f1, 0xa3f1, 0xa3f3, 0xa3f1, 0xa3f1, 0xa3f1, 0xa3f1, 0xa3f1, + 0xa3f1, 0xa3f1, 0xa3f1, 0xa3f1, 0xa3f1, 0xa3f1, 0xa3f1, 0xa3f1, + 0xa3f1, 0x080c, 0x14fa, 0x00d6, 0x00e6, 0x00f6, 0x0156, 0x0046, + 0x0026, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0120, 0x2021, + 0x0000, 0x080c, 0xaee2, 0x6106, 0x2071, 0xb680, 0x7444, 0xa4a4, + 0xff00, 0x0904, 0xa457, 0xa486, 0x2000, 0x1130, 0x2009, 0x0001, + 0x2011, 0x0200, 0x080c, 0x688d, 0x080c, 0x15dd, 0x090c, 0x14fa, + 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, + 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, 0x6018, 0x2078, + 0x78a0, 0x8007, 0x7130, 0x694a, 0x0016, 0xa084, 0xff00, 0x6846, + 0x684f, 0x0000, 0x6853, 0x0000, 0x6857, 0x0036, 0x080c, 0x5271, + 0x001e, 0xa486, 0x2000, 0x1130, 0x2019, 0x0017, 0x080c, 0xac2b, + 0x0804, 0xa4b4, 0xa486, 0x0400, 0x1130, 0x2019, 0x0002, 0x080c, + 0xabdd, 0x0804, 0xa4b4, 0xa486, 0x0200, 0x1110, 0x080c, 0xabc2, + 0xa486, 0x1000, 0x1110, 0x080c, 0xac10, 0x0804, 0xa4b4, 0x2069, + 0xb464, 0x6a00, 0xd284, 0x0904, 0xa50d, 0xa284, 0x0300, 0x1904, + 0xa506, 0x6804, 0xa005, 0x0904, 0xa4ee, 0x2d78, 0x6003, 0x0007, + 0x080c, 0x15c4, 0x0904, 0xa4bb, 0x7800, 0xd08c, 0x1118, 0x7804, + 0x8001, 0x7806, 0x6013, 0x0000, 0x6803, 0x0000, 0x6837, 0x0116, + 0x683b, 0x0000, 0x6008, 0x68b2, 0x2c00, 0x684a, 0x6018, 0x2078, + 0x78a0, 0x8007, 0x7130, 0x6986, 0x6846, 0x7928, 0x698a, 0x792c, + 0x698e, 0x7930, 0x6992, 0x7934, 0x6996, 0x6853, 0x003d, 0x7244, + 0xa294, 0x0003, 0xa286, 0x0002, 0x1118, 0x684f, 0x0040, 0x0040, + 0xa286, 0x0001, 0x1118, 0x684f, 0x0080, 0x0010, 0x684f, 0x0000, + 0x20a9, 0x000a, 0x2001, 0xb690, 0xad90, 0x0015, 0x200c, 0x810f, + 0x2112, 0x8000, 0x8210, 0x1f04, 0xa4a6, 0x200c, 0x6982, 0x8000, + 0x200c, 0x697e, 0x080c, 0x5271, 0x002e, 0x004e, 0x015e, 0x00fe, + 0x00ee, 0x00de, 0x0005, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, + 0x0041, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x0c70, 0x2069, 0xb692, + 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x11a8, 0x2069, 0xb680, + 0x686c, 0xa084, 0x00ff, 0x0016, 0x6110, 0xa18c, 0x0700, 0xa10d, + 0x6112, 0x001e, 0x6003, 0x0001, 0x6007, 0x0043, 0x080c, 0x69f6, + 0x080c, 0x6e9e, 0x0888, 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, + 0x0041, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x0830, 0x2001, 0xb10d, + 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x3d5b, 0x6013, + 0x0300, 0x0010, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, + 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x0804, 0xa4b4, 0x6013, 0x0500, + 0x0c98, 0x6013, 0x0600, 0x0804, 0xa4c6, 0x6013, 0x0200, 0x0804, + 0xa4c6, 0xa186, 0x0013, 0x1170, 0x6004, 0xa08a, 0x0040, 0x0a0c, + 0x14fa, 0xa08a, 0x0053, 0x1a0c, 0x14fa, 0xa082, 0x0040, 0x2008, + 0x0804, 0xa59b, 0xa186, 0x0051, 0x0138, 0xa186, 0x0047, 0x11d8, + 0x6004, 0xa086, 0x0041, 0x0518, 0x2001, 0x0109, 0x2004, 0xd084, + 0x01f0, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, + 0x68e7, 0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0xa086, 0x0002, + 0x1170, 0x0804, 0xa5de, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, + 0x190c, 0x14fa, 0x6004, 0xa082, 0x0040, 0x2008, 0x001a, 0x080c, + 0x8331, 0x0005, 0xa565, 0xa567, 0xa567, 0xa58b, 0xa565, 0xa565, + 0xa565, 0xa565, 0xa565, 0xa565, 0xa565, 0xa565, 0xa565, 0xa565, + 0xa565, 0xa565, 0xa565, 0xa565, 0xa565, 0x080c, 0x14fa, 0x080c, + 0x6dc1, 0x080c, 0x6e9e, 0x0036, 0x00d6, 0x6010, 0xa06d, 0x01c0, + 0xad84, 0xf000, 0x01a8, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc, + 0x1178, 0x2019, 0x0004, 0x080c, 0xac5f, 0x6013, 0x0000, 0x6014, + 0xa005, 0x1120, 0x2001, 0xb3b6, 0x2004, 0x6016, 0x6003, 0x0007, + 0x00de, 0x003e, 0x0005, 0x00d6, 0x080c, 0x6dc1, 0x080c, 0x6e9e, + 0x080c, 0x986a, 0x0120, 0x6010, 0x2068, 0x080c, 0x15f4, 0x080c, + 0x9a2b, 0x00de, 0x0005, 0x0002, 0xa5af, 0xa5cc, 0xa5b8, 0xa5d8, + 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0xa5af, + 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0xa5af, 0x080c, + 0x14fa, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, + 0x080c, 0x6dc1, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, 0x0138, + 0x6003, 0x0007, 0x2009, 0x0043, 0x080c, 0x831a, 0x0010, 0x6003, + 0x0002, 0x080c, 0x6e9e, 0x0005, 0x080c, 0x6dc1, 0x080c, 0xae9d, + 0x1120, 0x080c, 0x6866, 0x080c, 0x82eb, 0x080c, 0x6e9e, 0x0005, + 0x080c, 0x6dc1, 0x2009, 0x0041, 0x0804, 0xa727, 0xa182, 0x0040, + 0x0002, 0xa5f4, 0xa5f6, 0xa5f4, 0xa5f4, 0xa5f4, 0xa5f4, 0xa5f4, + 0xa5f7, 0xa5f4, 0xa5f4, 0xa5f4, 0xa5f4, 0xa5f4, 0xa5f4, 0xa5f4, + 0xa5f4, 0xa5f4, 0xa602, 0xa5f4, 0x080c, 0x14fa, 0x0005, 0x6003, + 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, + 0x1828, 0x0005, 0x00d6, 0x080c, 0x6866, 0x00de, 0x080c, 0xaf00, + 0x080c, 0x82eb, 0x0005, 0xa182, 0x0040, 0x0002, 0xa621, 0xa621, + 0xa621, 0xa621, 0xa621, 0xa621, 0xa621, 0xa623, 0xa621, 0xa626, + 0xa65f, 0xa621, 0xa621, 0xa621, 0xa621, 0xa65f, 0xa621, 0xa621, + 0xa621, 0x080c, 0x14fa, 0x080c, 0x8331, 0x0005, 0x2001, 0xb172, + 0x2004, 0xd0e4, 0x0158, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, + 0x0228, 0x2001, 0x011f, 0x2004, 0x6036, 0x0010, 0x6037, 0x0000, + 0x080c, 0x6e53, 0x080c, 0x6f5b, 0x6010, 0x00d6, 0x2068, 0x684c, + 0xd0fc, 0x0150, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0168, 0x2009, + 0x0041, 0x00de, 0x0804, 0xa727, 0x6003, 0x0007, 0x6017, 0x0000, + 0x080c, 0x6866, 0x00de, 0x0005, 0x080c, 0xae9d, 0x0110, 0x00de, + 0x0005, 0x080c, 0x6866, 0x080c, 0x82eb, 0x00de, 0x0ca0, 0x0036, + 0x080c, 0x6e53, 0x080c, 0x6f5b, 0x6010, 0x00d6, 0x2068, 0x6018, + 0x2004, 0xd0bc, 0x0188, 0x684c, 0xa084, 0x0003, 0xa086, 0x0002, + 0x0140, 0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, 0x6328, 0xa31b, + 0x632a, 0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xac5f, + 0x6014, 0xa005, 0x1128, 0x2001, 0xb3b6, 0x2004, 0x8003, 0x6016, + 0x6013, 0x0000, 0x6003, 0x0007, 0x00de, 0x003e, 0x0005, 0xa186, + 0x0013, 0x1150, 0x6004, 0xa086, 0x0042, 0x190c, 0x14fa, 0x080c, + 0x6dc1, 0x080c, 0x6e9e, 0x0005, 0xa186, 0x0027, 0x0118, 0xa186, + 0x0014, 0x1180, 0x6004, 0xa086, 0x0042, 0x190c, 0x14fa, 0x2001, + 0x0007, 0x080c, 0x4da2, 0x080c, 0x6dc1, 0x080c, 0x9a2b, 0x080c, + 0x6e9e, 0x0005, 0xa182, 0x0040, 0x0002, 0xa6c8, 0xa6c8, 0xa6c8, + 0xa6c8, 0xa6c8, 0xa6c8, 0xa6c8, 0xa6ca, 0xa6d6, 0xa6c8, 0xa6c8, + 0xa6c8, 0xa6c8, 0xa6c8, 0xa6c8, 0xa6c8, 0xa6c8, 0xa6c8, 0xa6c8, + 0x080c, 0x14fa, 0x0036, 0x0046, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x080c, 0x1828, 0x004e, 0x003e, 0x0005, 0x6010, 0x00d6, + 0x2068, 0x6810, 0x6a14, 0x0006, 0x0046, 0x0056, 0x6c7c, 0xa422, + 0x6d80, 0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, 0xa529, + 0x652a, 0x005e, 0x004e, 0x000e, 0xa20d, 0x1178, 0x684c, 0xd0fc, + 0x0120, 0x2009, 0x0041, 0x00de, 0x0490, 0x6003, 0x0007, 0x6017, + 0x0000, 0x080c, 0x6866, 0x00de, 0x0005, 0x0006, 0x00f6, 0x2c78, + 0x080c, 0x5177, 0x00fe, 0x000e, 0x0120, 0x6003, 0x0002, 0x00de, + 0x0005, 0x2009, 0xb10d, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, + 0x0010, 0x6003, 0x0006, 0x0021, 0x080c, 0x6868, 0x00de, 0x0005, + 0xd2fc, 0x0140, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, + 0x0009, 0x0010, 0x2009, 0x0015, 0x6a6a, 0x6866, 0x0005, 0xa182, + 0x0040, 0x0208, 0x0062, 0xa186, 0x0013, 0x0120, 0xa186, 0x0014, + 0x190c, 0x14fa, 0x6020, 0xd0dc, 0x090c, 0x14fa, 0x0005, 0xa74a, + 0xa751, 0xa75d, 0xa769, 0xa74a, 0xa74a, 0xa74a, 0xa778, 0xa74a, + 0xa74c, 0xa74c, 0xa74a, 0xa74a, 0xa74a, 0xa74a, 0xa74c, 0xa74a, + 0xa74c, 0xa74a, 0x080c, 0x14fa, 0x6020, 0xd0dc, 0x090c, 0x14fa, + 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, 0x69f6, 0x0126, 0x2091, + 0x8000, 0x080c, 0x6e9e, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, + 0x080c, 0x69f6, 0x0126, 0x2091, 0x8000, 0x080c, 0x6e9e, 0x012e, + 0x0005, 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1ec4, 0x0126, + 0x2091, 0x8000, 0x080c, 0x6a59, 0x080c, 0x6f5b, 0x012e, 0x0005, + 0xa016, 0x080c, 0x1828, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, + 0x00d6, 0xa182, 0x0040, 0x0023, 0x00de, 0x003e, 0x012e, 0x0005, + 0xa798, 0xa79a, 0xa7ac, 0xa7c7, 0xa798, 0xa798, 0xa798, 0xa7dc, + 0xa798, 0xa798, 0xa798, 0xa798, 0xa798, 0xa798, 0xa798, 0xa798, + 0x080c, 0x14fa, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x01f8, 0xa09c, + 0x0003, 0xa39e, 0x0003, 0x01d0, 0x6003, 0x0001, 0x6106, 0x080c, + 0x69f6, 0x080c, 0x6e9e, 0x0498, 0x6010, 0x2068, 0x684c, 0xd0fc, + 0x0168, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0140, 0x6003, 0x0001, + 0x6106, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x0408, 0x6013, 0x0000, + 0x6017, 0x0000, 0x2019, 0x0004, 0x080c, 0xac5f, 0x00c0, 0x6010, + 0x2068, 0x684c, 0xd0fc, 0x0d90, 0xa09c, 0x0003, 0xa39e, 0x0003, + 0x0d68, 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1ec4, 0x080c, + 0x6a59, 0x080c, 0x6f5b, 0x0018, 0xa016, 0x080c, 0x1828, 0x0005, + 0x080c, 0x6dc1, 0x6110, 0x81ff, 0x0158, 0x00d6, 0x2168, 0x080c, + 0xaf46, 0x0036, 0x2019, 0x0029, 0x080c, 0xac5f, 0x003e, 0x00de, + 0x080c, 0x9a2b, 0x080c, 0x6e9e, 0x0005, 0x080c, 0x6e53, 0x6110, + 0x81ff, 0x0158, 0x00d6, 0x2168, 0x080c, 0xaf46, 0x0036, 0x2019, + 0x0029, 0x080c, 0xac5f, 0x003e, 0x00de, 0x080c, 0x9a2b, 0x080c, + 0x6f5b, 0x0005, 0xa182, 0x0085, 0x0002, 0xa816, 0xa814, 0xa814, + 0xa822, 0xa814, 0xa814, 0xa814, 0x080c, 0x14fa, 0x6003, 0x000b, + 0x6106, 0x080c, 0x69f6, 0x0126, 0x2091, 0x8000, 0x080c, 0x6e9e, + 0x012e, 0x0005, 0x0026, 0x00e6, 0x080c, 0xae96, 0x0118, 0x080c, + 0x82eb, 0x00c8, 0x2071, 0xb680, 0x7224, 0x6212, 0x7220, 0x080c, + 0xab0d, 0x0118, 0x6007, 0x0086, 0x0040, 0x6007, 0x0087, 0x7224, + 0xa296, 0xffff, 0x1110, 0x6007, 0x0086, 0x6003, 0x0001, 0x080c, + 0x69f6, 0x080c, 0x6e9e, 0x00ee, 0x002e, 0x0005, 0xa186, 0x0013, + 0x1160, 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x14fa, 0xa08a, 0x008c, + 0x1a0c, 0x14fa, 0xa082, 0x0085, 0x00a2, 0xa186, 0x0027, 0x0130, + 0xa186, 0x0014, 0x0118, 0x080c, 0x8331, 0x0050, 0x2001, 0x0007, + 0x080c, 0x4da2, 0x080c, 0x6dc1, 0x080c, 0x9a2b, 0x080c, 0x6e9e, + 0x0005, 0xa870, 0xa872, 0xa872, 0xa870, 0xa870, 0xa870, 0xa870, + 0x080c, 0x14fa, 0x080c, 0x6dc1, 0x080c, 0x9a2b, 0x080c, 0x6e9e, + 0x0005, 0xa182, 0x0085, 0x0a0c, 0x14fa, 0xa182, 0x008c, 0x1a0c, + 0x14fa, 0xa182, 0x0085, 0x0002, 0xa88b, 0xa88b, 0xa88b, 0xa88d, + 0xa88b, 0xa88b, 0xa88b, 0x080c, 0x14fa, 0x0005, 0xa186, 0x0013, + 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, 0x0118, 0x080c, + 0x8331, 0x0030, 0x080c, 0x6dc1, 0x080c, 0x9a2b, 0x080c, 0x6e9e, + 0x0005, 0x0036, 0x080c, 0xaf00, 0x603f, 0x0000, 0x2019, 0x000b, + 0x0031, 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x0126, + 0x0036, 0x2091, 0x8000, 0x0086, 0x2c40, 0x0096, 0x2049, 0x0000, + 0x080c, 0x7e0d, 0x009e, 0x008e, 0x1578, 0x0076, 0x2c38, 0x080c, + 0x7ea7, 0x007e, 0x1548, 0x6000, 0xa086, 0x0000, 0x0528, 0x601c, + 0xa086, 0x0007, 0x0508, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1150, + 0x080c, 0xaf00, 0x601f, 0x0007, 0x2001, 0xb3b5, 0x2004, 0x6016, + 0x080c, 0x190f, 0x6010, 0x2068, 0x080c, 0x986a, 0x0110, 0x080c, + 0xac5f, 0x00de, 0x6013, 0x0000, 0x080c, 0xaf00, 0x601f, 0x0007, + 0x2001, 0xb3b5, 0x2004, 0x6016, 0x003e, 0x012e, 0x0005, 0x00f6, + 0x00c6, 0x0036, 0x0156, 0x2079, 0xb680, 0x7938, 0x783c, 0x080c, + 0x26f6, 0x15b0, 0x0016, 0x00c6, 0x080c, 0x4e21, 0x1578, 0x001e, + 0x002e, 0x0026, 0x0016, 0x2019, 0x0029, 0x080c, 0x7f67, 0x080c, + 0x6b35, 0x0076, 0x2039, 0x0000, 0x080c, 0x6a6b, 0x007e, 0x001e, + 0x0076, 0x2039, 0x0000, 0x080c, 0xaa51, 0x007e, 0x080c, 0x501c, + 0x0026, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0118, + 0xa286, 0x0004, 0x1118, 0x62a0, 0x080c, 0x2c2c, 0x002e, 0x001e, + 0x080c, 0x4a80, 0x6612, 0x6516, 0xa006, 0x0010, 0x00ce, 0x001e, + 0x015e, 0x003e, 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6, 0x00e6, + 0x0016, 0x2009, 0xb120, 0x2104, 0xa086, 0x0074, 0x1904, 0xa98a, + 0x2069, 0xb68e, 0x690c, 0xa182, 0x0100, 0x06c0, 0x6908, 0xa184, + 0x8000, 0x05e8, 0x2001, 0xb39e, 0x2004, 0xa005, 0x1160, 0x6018, + 0x2070, 0x7010, 0xa084, 0x00ff, 0x0118, 0x7000, 0xd0f4, 0x0118, + 0xa184, 0x0800, 0x0560, 0x6910, 0xa18a, 0x0001, 0x0610, 0x6914, + 0x2069, 0xb6ae, 0x6904, 0x81ff, 0x1198, 0x690c, 0xa182, 0x0100, + 0x02a8, 0x6908, 0x81ff, 0x1178, 0x6910, 0xa18a, 0x0001, 0x0288, + 0x6918, 0xa18a, 0x0001, 0x0298, 0x00d0, 0x6013, 0x0100, 0x00a0, + 0x6013, 0x0300, 0x0088, 0x6013, 0x0500, 0x0070, 0x6013, 0x0700, + 0x0058, 0x6013, 0x0900, 0x0040, 0x6013, 0x0b00, 0x0028, 0x6013, + 0x0f00, 0x0010, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0008, 0xa006, + 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x0026, + 0x0036, 0x0156, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, 0xa286, + 0x0006, 0x0190, 0xa286, 0x0004, 0x0178, 0xa394, 0xff00, 0x8217, + 0xa286, 0x0006, 0x0148, 0xa286, 0x0004, 0x0130, 0x00c6, 0x2d60, + 0x080c, 0x4e30, 0x00ce, 0x04c0, 0x2011, 0xb696, 0xad98, 0x000a, + 0x20a9, 0x0004, 0x080c, 0x8d2b, 0x1580, 0x2011, 0xb69a, 0xad98, + 0x0006, 0x20a9, 0x0004, 0x080c, 0x8d2b, 0x1538, 0x0046, 0x0016, + 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0xb153, 0x210c, + 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, 0xacae, 0x6800, 0xc0e5, + 0x6802, 0x2019, 0x0029, 0x080c, 0x6b35, 0x0076, 0x2039, 0x0000, + 0x080c, 0x6a6b, 0x2c08, 0x080c, 0xaa51, 0x007e, 0x2001, 0x0007, + 0x080c, 0x4da2, 0x001e, 0x004e, 0xa006, 0x015e, 0x003e, 0x002e, + 0x00de, 0x00ce, 0x0005, 0x00d6, 0x2069, 0xb68e, 0x6800, 0xa086, + 0x0800, 0x0118, 0x6013, 0x0000, 0x0008, 0xa006, 0x00de, 0x0005, + 0x00c6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156, 0x2079, 0xb68c, + 0x7930, 0x7834, 0x080c, 0x26f6, 0x11a0, 0x080c, 0x4e21, 0x1188, + 0x2011, 0xb690, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x8d2b, + 0x1140, 0x2011, 0xb694, 0xac98, 0x0006, 0x20a9, 0x0004, 0x080c, + 0x8d2b, 0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00ce, 0x0005, + 0x00c6, 0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011, 0xb683, + 0x2204, 0x8211, 0x220c, 0x080c, 0x26f6, 0x11a0, 0x080c, 0x4e21, + 0x1188, 0x2011, 0xb696, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c, + 0x8d2b, 0x1140, 0x2011, 0xb69a, 0xac98, 0x0006, 0x20a9, 0x0004, + 0x080c, 0x8d2b, 0x015e, 0x003e, 0x002e, 0x001e, 0x000e, 0x00ce, + 0x0005, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0056, 0x0046, + 0x0026, 0x0126, 0x2091, 0x8000, 0x2740, 0x2029, 0xb3e2, 0x252c, + 0x2021, 0xb3e8, 0x2424, 0x2061, 0xb800, 0x2071, 0xb100, 0x7644, + 0x7064, 0x81ff, 0x0128, 0x8001, 0xa602, 0x1a04, 0xaacd, 0x0018, + 0xa606, 0x0904, 0xaacd, 0x2100, 0xac06, 0x0904, 0xaac4, 0x080c, + 0xacd6, 0x0904, 0xaac4, 0x671c, 0xa786, 0x0001, 0x0904, 0xaae4, + 0xa786, 0x0004, 0x0904, 0xaae4, 0xa786, 0x0007, 0x05e8, 0x2500, + 0xac06, 0x05d0, 0x2400, 0xac06, 0x05b8, 0x080c, 0xace6, 0x15a0, + 0x88ff, 0x0118, 0x6050, 0xa906, 0x1578, 0x00d6, 0x6000, 0xa086, + 0x0004, 0x1120, 0x0016, 0x080c, 0x190f, 0x001e, 0xa786, 0x0008, + 0x1148, 0x080c, 0x9a66, 0x1130, 0x080c, 0x8890, 0x00de, 0x080c, + 0x9a2b, 0x00d0, 0x6010, 0x2068, 0x080c, 0x986a, 0x0190, 0xa786, + 0x0003, 0x1528, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, + 0xaf46, 0x0016, 0x080c, 0x9ada, 0x080c, 0x5271, 0x001e, 0x080c, + 0x9a1f, 0x00de, 0x080c, 0x9a2b, 0xace0, 0x0018, 0x2001, 0xb116, + 0x2004, 0xac02, 0x1210, 0x0804, 0xaa65, 0x012e, 0x002e, 0x004e, + 0x005e, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x0005, 0xa786, + 0x0006, 0x19c0, 0xa386, 0x0005, 0x0128, 0x080c, 0xaf46, 0x080c, + 0xac5f, 0x08f8, 0x00de, 0x0c00, 0x080c, 0xace6, 0x19e8, 0x81ff, + 0x09d8, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, 0x0130, 0xa180, + 0x0001, 0x2004, 0xa086, 0x002d, 0x1978, 0x6000, 0xa086, 0x0002, + 0x1958, 0x080c, 0x9a55, 0x0130, 0x080c, 0x9a66, 0x1928, 0x080c, + 0x8890, 0x0038, 0x080c, 0x2b99, 0x080c, 0x9a66, 0x1110, 0x080c, + 0x8890, 0x080c, 0x9a2b, 0x0804, 0xaac4, 0x00c6, 0x00e6, 0x0016, + 0x2c08, 0x2170, 0xa006, 0x080c, 0xac80, 0x001e, 0x0120, 0x601c, + 0xa084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, 0xab26, 0xab26, + 0xab26, 0xab26, 0xab26, 0xab26, 0xab28, 0xab26, 0xa006, 0x0005, + 0x0046, 0x0016, 0x7018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, + 0x8427, 0x2c00, 0x2009, 0x0020, 0x080c, 0xacae, 0x001e, 0x004e, + 0x0036, 0x2019, 0x0002, 0x080c, 0xa8af, 0x003e, 0xa085, 0x0001, + 0x0005, 0x2001, 0x0001, 0x080c, 0x4d63, 0x0156, 0x0016, 0x0026, + 0x0036, 0x20a9, 0x0004, 0x2019, 0xb105, 0x2011, 0xb696, 0x080c, + 0x8d2b, 0x003e, 0x002e, 0x001e, 0x015e, 0xa005, 0x0005, 0x00f6, + 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0026, 0x0126, 0x2091, + 0x8000, 0x2740, 0x2061, 0xb800, 0x2079, 0x0001, 0x8fff, 0x0904, + 0xabb5, 0x2071, 0xb100, 0x7644, 0x7064, 0x8001, 0xa602, 0x1a04, + 0xabb5, 0x88ff, 0x0128, 0x2800, 0xac06, 0x15b0, 0x2079, 0x0000, + 0x080c, 0xacd6, 0x0588, 0x2400, 0xac06, 0x0570, 0x671c, 0xa786, + 0x0006, 0x1550, 0xa786, 0x0007, 0x0538, 0x88ff, 0x1140, 0x6018, + 0xa206, 0x1510, 0x85ff, 0x0118, 0x6050, 0xa106, 0x11e8, 0x00d6, + 0x6000, 0xa086, 0x0004, 0x1150, 0x080c, 0xaf00, 0x601f, 0x0007, + 0x2001, 0xb3b5, 0x2004, 0x6016, 0x080c, 0x190f, 0x6010, 0x2068, + 0x080c, 0x986a, 0x0120, 0x0046, 0x080c, 0xac5f, 0x004e, 0x00de, + 0x080c, 0x9a2b, 0x88ff, 0x1198, 0xace0, 0x0018, 0x2001, 0xb116, + 0x2004, 0xac02, 0x1210, 0x0804, 0xab66, 0xa006, 0x012e, 0x002e, + 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0xa8c5, + 0x0001, 0x0ca0, 0x0076, 0x0056, 0x0086, 0x2041, 0x0000, 0x2029, + 0x0001, 0x2c20, 0x2019, 0x0002, 0x6218, 0x0096, 0x2049, 0x0000, + 0x080c, 0x7e0d, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, 0x7ea7, + 0x080c, 0xab57, 0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056, + 0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x0016, 0x0036, 0x080c, 0x4e21, 0x11b0, 0x2c10, 0x0056, + 0x0086, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, 0x0096, 0x2049, + 0x0000, 0x080c, 0x7e0d, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, + 0x7ea7, 0x080c, 0xab57, 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04, + 0xabe9, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e, 0x0005, + 0x0076, 0x0056, 0x6218, 0x0086, 0x2041, 0x0000, 0x2029, 0x0001, + 0x2019, 0x0048, 0x0096, 0x2049, 0x0000, 0x080c, 0x7e0d, 0x009e, + 0x008e, 0x2039, 0x0000, 0x080c, 0x7ea7, 0x2c20, 0x080c, 0xab57, + 0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056, 0x0076, 0x00c6, + 0x0156, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x0036, + 0x080c, 0x4e21, 0x11c0, 0x2c10, 0x0086, 0x2041, 0x0000, 0x2828, + 0x0046, 0x2021, 0x0001, 0x080c, 0xaee2, 0x004e, 0x0096, 0x2049, + 0x0000, 0x080c, 0x7e0d, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, + 0x7ea7, 0x080c, 0xab57, 0x003e, 0x001e, 0x8108, 0x1f04, 0xac36, + 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0016, + 0x00f6, 0x3800, 0xd08c, 0x0130, 0xad82, 0x1000, 0x02b0, 0xad82, + 0xb100, 0x0230, 0xad82, 0xe800, 0x0280, 0xad82, 0xffff, 0x1268, + 0x6800, 0xa07d, 0x0138, 0x6803, 0x0000, 0x6b52, 0x080c, 0x5271, + 0x2f68, 0x0cb0, 0x6b52, 0x080c, 0x5271, 0x00fe, 0x001e, 0x0005, + 0x00e6, 0x0046, 0x0036, 0x2061, 0xb800, 0xa005, 0x1138, 0x2071, + 0xb100, 0x7444, 0x7064, 0x8001, 0xa402, 0x12d8, 0x2100, 0xac06, + 0x0168, 0x6000, 0xa086, 0x0000, 0x0148, 0x6008, 0xa206, 0x1130, + 0x6018, 0xa1a0, 0x0006, 0x2424, 0xa406, 0x0140, 0xace0, 0x0018, + 0x2001, 0xb116, 0x2004, 0xac02, 0x1220, 0x0c40, 0xa085, 0x0001, + 0x0008, 0xa006, 0x003e, 0x004e, 0x00ee, 0x0005, 0x00d6, 0x0006, + 0x080c, 0x15dd, 0x000e, 0x090c, 0x14fa, 0x6837, 0x010d, 0x685e, + 0x0026, 0x2010, 0x080c, 0x985a, 0x2001, 0x0000, 0x0120, 0x2200, + 0xa080, 0x0014, 0x2004, 0x002e, 0x684a, 0x6956, 0x6c46, 0x684f, + 0x0000, 0x2001, 0xb3bd, 0x2004, 0x6852, 0xa006, 0x68b2, 0x6802, + 0x683a, 0x685a, 0x080c, 0x5271, 0x00de, 0x0005, 0x6700, 0xa786, + 0x0000, 0x0158, 0xa786, 0x0001, 0x0140, 0xa786, 0x000a, 0x0128, + 0xa786, 0x0009, 0x0110, 0xa085, 0x0001, 0x0005, 0x00e6, 0x6018, + 0x2070, 0x70a0, 0xa206, 0x00ee, 0x0005, 0x0016, 0x6004, 0xa08e, + 0x001e, 0x11a0, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, 0x6032, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0005, 0x2001, 0xb3b6, + 0x2004, 0x6016, 0x080c, 0x69f6, 0x080c, 0x6e9e, 0x001e, 0x0005, + 0xe000, 0xe000, 0x0005, 0x6020, 0xd0e4, 0x0158, 0xd0cc, 0x0118, + 0x080c, 0x9b43, 0x0030, 0x080c, 0xaf00, 0x080c, 0x6866, 0x080c, + 0x82eb, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, 0x0002, + 0xad29, 0xad29, 0xad29, 0xad2e, 0xad29, 0xad2b, 0xad2b, 0xad29, + 0xad2b, 0xa006, 0x0005, 0x00c6, 0x2260, 0x00ce, 0xa085, 0x0001, + 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, 0x0002, 0xad40, + 0xad40, 0xad40, 0xad40, 0xad40, 0xad40, 0xad4b, 0xad40, 0xad40, + 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00, 0x6003, 0x0001, + 0x080c, 0x69f6, 0x0005, 0x00c6, 0x2260, 0x080c, 0xaf00, 0x603f, + 0x0000, 0x6020, 0xc0f4, 0xc0cc, 0x6022, 0x6037, 0x0000, 0x00ce, + 0x00d6, 0x2268, 0xa186, 0x0007, 0x1904, 0xada6, 0x6810, 0xa005, + 0x0138, 0xa080, 0x0013, 0x2004, 0xd0fc, 0x1110, 0x00de, 0x08c0, + 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, 0x69f6, 0x080c, 0x6e9e, + 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, 0x1904, 0xae2f, 0x6010, + 0xa005, 0x1138, 0x6000, 0xa086, 0x0007, 0x190c, 0x14fa, 0x0804, + 0xae2f, 0xa08c, 0xf000, 0x1130, 0x0028, 0x2068, 0x6800, 0xa005, + 0x1de0, 0x2d00, 0xa080, 0x0013, 0x2004, 0xa084, 0x0003, 0xa086, + 0x0002, 0x1180, 0x6010, 0x2068, 0x684c, 0xc0dc, 0xc0f4, 0x684e, + 0x6850, 0xc0f4, 0xc0fc, 0x6852, 0x2009, 0x0043, 0x080c, 0xa727, + 0x0804, 0xae2f, 0x2009, 0x0041, 0x0804, 0xae29, 0xa186, 0x0005, + 0x15f0, 0x6810, 0xa080, 0x0013, 0x2004, 0xd0bc, 0x1118, 0x00de, + 0x0804, 0xad40, 0xd0b4, 0x0128, 0xd0fc, 0x090c, 0x14fa, 0x0804, + 0xad5e, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, 0x69f6, 0x080c, + 0x6e9e, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, 0x0120, 0xa186, + 0x0004, 0x1904, 0xae2f, 0x2071, 0xb419, 0x7000, 0xa086, 0x0003, + 0x1128, 0x7004, 0xac06, 0x1110, 0x7003, 0x0000, 0x6810, 0xa080, + 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, 0x200c, 0xc1f4, + 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0804, 0xae29, 0x0036, + 0x00d6, 0x00d6, 0x080c, 0x15dd, 0x003e, 0x090c, 0x14fa, 0x6837, + 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, 0x6b5e, + 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872, 0x2360, 0x6020, + 0xc0dd, 0x6022, 0x6018, 0xa080, 0x0028, 0x2004, 0xa084, 0x00ff, + 0x8007, 0x6350, 0x6b4a, 0x6846, 0x684f, 0x0000, 0x6853, 0x0000, + 0x6d6a, 0x6e66, 0x686f, 0x0001, 0x080c, 0x5271, 0x2019, 0x0045, + 0x6008, 0x2068, 0x080c, 0xa8af, 0x2d00, 0x600a, 0x601f, 0x0006, + 0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000, 0x00de, 0x003e, + 0x0038, 0x603f, 0x0000, 0x6003, 0x0007, 0x080c, 0xa727, 0x00ce, + 0x00de, 0x0005, 0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0085, + 0x2008, 0x00c2, 0xa186, 0x0027, 0x1178, 0x080c, 0x6dc1, 0x0036, + 0x00d6, 0x6010, 0x2068, 0x2019, 0x0004, 0x080c, 0xac5f, 0x00de, + 0x003e, 0x080c, 0x6e9e, 0x0005, 0xa186, 0x0014, 0x0d70, 0x080c, + 0x8331, 0x0005, 0xae5b, 0xae59, 0xae59, 0xae59, 0xae59, 0xae59, + 0xae5b, 0x080c, 0x14fa, 0x080c, 0x6dc1, 0x6003, 0x000c, 0x080c, + 0x6e9e, 0x0005, 0xa182, 0x008c, 0x1220, 0xa182, 0x0085, 0x0208, + 0x001a, 0x080c, 0x8331, 0x0005, 0xae73, 0xae73, 0xae73, 0xae73, + 0xae75, 0xae93, 0xae73, 0x080c, 0x14fa, 0x00d6, 0x2c68, 0x080c, + 0x8295, 0x01a0, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xb68e, + 0x210c, 0x6136, 0x2009, 0xb68f, 0x210c, 0x613a, 0x600b, 0xffff, + 0x6918, 0x611a, 0x601f, 0x0004, 0x080c, 0x69f6, 0x2d60, 0x080c, + 0x82eb, 0x00de, 0x0005, 0x080c, 0x82eb, 0x0005, 0x00e6, 0x6018, + 0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x6010, 0xa08c, 0xf000, + 0x0904, 0xaee1, 0xa080, 0x0013, 0x200c, 0xd1ec, 0x05d0, 0x2001, + 0xb172, 0x2004, 0xd0ec, 0x05a8, 0x6003, 0x0002, 0x6020, 0xc0e5, + 0x6022, 0xd1ac, 0x0180, 0x00f6, 0x2c78, 0x080c, 0x5173, 0x00fe, + 0x0150, 0x2001, 0xb3b7, 0x2004, 0x603e, 0x2009, 0xb172, 0x210c, + 0xd1f4, 0x11e8, 0x0080, 0x2009, 0xb172, 0x210c, 0xd1f4, 0x0128, + 0x6020, 0xc0e4, 0x6022, 0xa006, 0x00a0, 0x2001, 0xb3b7, 0x200c, + 0x8103, 0xa100, 0x603e, 0x6018, 0xa088, 0x002b, 0x2104, 0xa005, + 0x0118, 0xa088, 0x0003, 0x0cd0, 0x2c0a, 0x600f, 0x0000, 0xa085, + 0x0001, 0x0005, 0x0016, 0x00c6, 0x00e6, 0x6150, 0xa2f0, 0x002b, + 0x2e04, 0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118, 0x6050, 0xa106, + 0x1138, 0x600c, 0x2072, 0x080c, 0x6866, 0x080c, 0x82eb, 0x0010, + 0xacf0, 0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce, 0x001e, 0x0005, + 0x00d6, 0x6018, 0xa0e8, 0x002b, 0x2d04, 0xa005, 0x0140, 0xac06, + 0x0120, 0x2d04, 0xa0e8, 0x0003, 0x0cb8, 0x600c, 0x206a, 0x00de, + 0x0005, 0x0026, 0x0036, 0x0156, 0x2011, 0xb127, 0x2204, 0xa084, + 0x00ff, 0x2019, 0xb68e, 0x2334, 0xa636, 0x11d8, 0x8318, 0x2334, + 0x2204, 0xa084, 0xff00, 0xa636, 0x11a0, 0x2011, 0xb690, 0x6018, + 0xa098, 0x000a, 0x20a9, 0x0004, 0x080c, 0x8d2b, 0x1150, 0x2011, + 0xb694, 0x6018, 0xa098, 0x0006, 0x20a9, 0x0004, 0x080c, 0x8d2b, + 0x1100, 0x015e, 0x003e, 0x002e, 0x0005, 0x00e6, 0x2071, 0xb100, + 0x080c, 0x4a3b, 0x080c, 0x2991, 0x00ee, 0x0005, 0x00e6, 0x6018, + 0x2070, 0x7000, 0xd0fc, 0x0108, 0x0011, 0x00ee, 0x0005, 0x6850, + 0xc0e5, 0x6852, 0x0005, 0x00e6, 0x00c6, 0x0076, 0x0066, 0x0056, + 0x0046, 0x0026, 0x0016, 0x0126, 0x2091, 0x8000, 0x2029, 0xb3e2, + 0x252c, 0x2021, 0xb3e8, 0x2424, 0x2061, 0xb800, 0x2071, 0xb100, + 0x7644, 0x7064, 0xa606, 0x0578, 0x671c, 0xa786, 0x0001, 0x0118, + 0xa786, 0x0008, 0x1500, 0x2500, 0xac06, 0x01e8, 0x2400, 0xac06, + 0x01d0, 0x080c, 0xacd6, 0x01b8, 0x080c, 0xace6, 0x11a0, 0x6000, + 0xa086, 0x0004, 0x1120, 0x0016, 0x080c, 0x190f, 0x001e, 0x080c, + 0x9a55, 0x1110, 0x080c, 0x2b99, 0x080c, 0x9a66, 0x1110, 0x080c, + 0x8890, 0x080c, 0x9a2b, 0xace0, 0x0018, 0x2001, 0xb116, 0x2004, + 0xac02, 0x1208, 0x0858, 0x012e, 0x001e, 0x002e, 0x004e, 0x005e, + 0x006e, 0x007e, 0x00ce, 0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, + 0x2091, 0x8000, 0x2071, 0xb140, 0xd5a4, 0x0118, 0x7034, 0x8000, + 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0118, + 0x2071, 0xb14a, 0x0451, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0126, + 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xb140, 0xd5a4, 0x0118, + 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, 0x7032, + 0xd5ac, 0x0118, 0x2071, 0xb14a, 0x0081, 0x00ee, 0x000e, 0x012e, + 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xb142, + 0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e04, 0x8000, 0x2072, + 0x1220, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x0005, 0x00e6, 0x2071, + 0xb140, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071, 0xb144, 0x0c69, + 0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, + 0xb140, 0x7044, 0x8000, 0x7046, 0x00ee, 0x000e, 0x012e, 0x0005, + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, + 0x5790 +}; +#ifdef UNIQUE_FW_NAME +unsigned short fw2200tp_length01 = 0xa019; +#else +unsigned short risc_code_length01 = 0xa019; +#endif + diff -Nur linux-2.4.19/drivers/scsi/ql2300_fw.h linux-2.4.19-sgi211r3/drivers/scsi/ql2300_fw.h --- linux-2.4.19/drivers/scsi/ql2300_fw.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/ql2300_fw.h Tue Jan 8 17:05:38 2002 @@ -0,0 +1,5486 @@ +/************************************************************************ + * * + * --- ISP2300 Initiator/Target Firmware --- * + * with Fabric (Public Loop), Point-point, and * + * expanded LUN addressing for FCTAPE * + * * + ************************************************************************ + Copyright (C) 2000 and 2001 Qlogic Corporation + (www.qlogic.com) + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + ************************************************************************/ +/* + * Firmware Version 3.00.24 (14:18 Jun 05, 2001) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tp_version = 3*1024+0; +#else +unsigned short risc_code_version = 3*1024+0; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw2300tp_version_str[] = {3, 0,24}; +#else +unsigned char firmware_version[] = {3, 0,24}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw2300tp_VERSION_STRING "3.00.24" +#else +#define FW_VERSION_STRING "3.00.24" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tp_addr01 = 0x0800 ; +#else +unsigned short risc_code_addr01 = 0x0800 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tp_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0470, 0x0000, 0x0000, 0xa9b8, 0x0000, 0x0003, 0x0000, 0x0018, + 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030, + 0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3233, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x332e, 0x3030, 0x2e32, 0x3420, 0x2020, 0x2020, 0x2400, 0x20a9, + 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2200, 0x20a9, 0x000f, + 0x2001, 0x0000, 0x400f, 0x2091, 0x2400, 0x20a9, 0x000f, 0x2001, + 0x0000, 0x400f, 0x2091, 0x2600, 0x20a9, 0x000f, 0x2001, 0x0000, + 0x400f, 0x2091, 0x2800, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, + 0x2091, 0x2a00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, + 0x2c00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2e00, + 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2000, 0x2001, + 0x0000, 0x20c1, 0x0004, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, + 0x14ff, 0x2059, 0x0000, 0x2b78, 0x7883, 0x0004, 0x2089, 0x2102, + 0x2051, 0x1100, 0x2a70, 0x20e1, 0x0001, 0x20e9, 0x0001, 0x2029, + 0x45c0, 0x2031, 0xffff, 0x2039, 0x45a9, 0x2021, 0x0200, 0x20e9, + 0x0001, 0x20a1, 0x1000, 0x900e, 0x20a9, 0x05c0, 0x4104, 0x755e, + 0x7662, 0x775a, 0x7466, 0x746a, 0x20a1, 0x15c0, 0x7160, 0x810d, + 0x810d, 0x810d, 0x810d, 0x918c, 0x000f, 0x2001, 0x0001, 0x9112, + 0x900e, 0x21a8, 0x4104, 0x8211, 0x1de0, 0x7160, 0x3400, 0x8001, + 0x9102, 0x0120, 0x0218, 0x20a8, 0x900e, 0x4104, 0x2009, 0x1100, + 0x810d, 0x810d, 0x810d, 0x810d, 0x810d, 0x918c, 0x001f, 0x2001, + 0x0001, 0x9112, 0x20e9, 0x0001, 0x20a1, 0x0800, 0x900e, 0x20a9, + 0x0800, 0x4104, 0x8211, 0x1dd8, 0x2009, 0x1100, 0x3400, 0x9102, + 0x0120, 0x0218, 0x20a8, 0x900e, 0x4104, 0x080c, 0x0e42, 0x080c, + 0x0f8f, 0x080c, 0x13a2, 0x080c, 0x0c8a, 0x080c, 0x4721, 0x080c, + 0x7ebf, 0x080c, 0x0dae, 0x080c, 0x27c1, 0x080c, 0x5a05, 0x080c, + 0x4e0f, 0x080c, 0x64ba, 0x080c, 0x1956, 0x080c, 0x6721, 0x080c, + 0x5fe8, 0x080c, 0x1768, 0x080c, 0x18cb, 0x080c, 0x194b, 0x2091, + 0x3009, 0x7883, 0x0000, 0x1004, 0x0905, 0x7880, 0x9086, 0x0002, + 0x1160, 0x7883, 0x4000, 0x7837, 0x4000, 0x7833, 0x0010, 0x0e04, + 0x08ff, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000, + 0x2a70, 0x7000, 0x908e, 0x0003, 0x1168, 0x080c, 0x3816, 0x080c, + 0x27e5, 0x080c, 0x5a60, 0x080c, 0x52b6, 0x080c, 0x64e0, 0x080c, + 0x20a5, 0x0c70, 0x000b, 0x0c88, 0x0926, 0x0927, 0x0a62, 0x0924, + 0x0b34, 0x0c87, 0x0c88, 0x0c89, 0x080c, 0x0cf1, 0x0005, 0x0126, + 0x00f6, 0x2091, 0x8000, 0x7000, 0x9086, 0x0001, 0x1904, 0x0a30, + 0x7034, 0xd0b4, 0x1130, 0x0026, 0x2011, 0x0080, 0x080c, 0x0d63, + 0x002e, 0x080c, 0x5745, 0x0150, 0x080c, 0x576b, 0x1570, 0x2079, + 0x0100, 0x7828, 0x9085, 0x1800, 0x782a, 0x0438, 0x080c, 0x5682, + 0x7000, 0x9086, 0x0001, 0x1904, 0x0a30, 0x7088, 0x9086, 0x0028, + 0x1904, 0x0a30, 0x2001, 0x0161, 0x2003, 0x0001, 0x2079, 0x0100, + 0x7827, 0xffff, 0x7a28, 0x9295, 0x1e2f, 0x7a2a, 0x2011, 0x5654, + 0x080c, 0x655b, 0x2011, 0x4586, 0x080c, 0x655b, 0x2011, 0x8030, + 0x2019, 0x0000, 0x7087, 0x0000, 0x00d8, 0x080c, 0x3e5a, 0x2079, + 0x0100, 0x7844, 0x9005, 0x1904, 0x0a30, 0x2011, 0x4586, 0x080c, + 0x655b, 0x2001, 0x0265, 0x2001, 0x0205, 0x2003, 0x0000, 0x780f, + 0x006b, 0x7840, 0x9084, 0xfffb, 0x7842, 0x2011, 0x8010, 0x73c8, + 0x080c, 0x1f80, 0x080c, 0x37dc, 0x7238, 0xc284, 0x723a, 0x2001, + 0x110c, 0x200c, 0xc1ac, 0xc1cc, 0x2102, 0x080c, 0x788f, 0x2011, + 0x0004, 0x080c, 0x95d8, 0x080c, 0x4d24, 0x080c, 0x5745, 0x01e8, + 0x080c, 0x46dd, 0x0140, 0x7087, 0x0001, 0x70c3, 0x0000, 0x080c, + 0x4016, 0x0804, 0x0a30, 0x2001, 0x1153, 0x2004, 0xd094, 0x0168, + 0x2011, 0x110c, 0x2204, 0xc0cd, 0x2012, 0x080c, 0x1fc4, 0x1228, + 0x2011, 0x110c, 0x2204, 0xc0bc, 0x0020, 0x2011, 0x110c, 0x2204, + 0xc0bd, 0x2012, 0x080c, 0x4de0, 0x0120, 0x7a0c, 0xc2b4, 0x7a0e, + 0x0050, 0x080c, 0x99a3, 0x70cc, 0xd09c, 0x1128, 0x709c, 0x9005, + 0x0110, 0x080c, 0x46bb, 0x70d7, 0x0000, 0x70d3, 0x0000, 0x72cc, + 0x080c, 0x5745, 0x1178, 0x2011, 0x0000, 0x0016, 0x080c, 0x1d69, + 0x2019, 0x1280, 0x211a, 0x001e, 0x704f, 0xffff, 0x7053, 0x00ef, + 0x7073, 0x0000, 0x2079, 0x1152, 0x7804, 0xd0ac, 0x0108, 0xc295, + 0x72ce, 0x080c, 0x5745, 0x0118, 0x9296, 0x0004, 0x0508, 0x2011, + 0x0001, 0x080c, 0x95d8, 0x7097, 0x0000, 0x709b, 0xffff, 0x7003, + 0x0002, 0x00fe, 0x080c, 0x23cd, 0x2011, 0x0005, 0x080c, 0x79c2, + 0x080c, 0x6d42, 0x080c, 0x5745, 0x0148, 0x00c6, 0x2061, 0x0100, + 0x0016, 0x080c, 0x1d69, 0x61e2, 0x001e, 0x00ce, 0x012e, 0x00d0, + 0x7097, 0x0000, 0x709b, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, + 0x080c, 0x79c2, 0x080c, 0x6d42, 0x080c, 0x5745, 0x0148, 0x00c6, + 0x2061, 0x0100, 0x0016, 0x080c, 0x1d69, 0x61e2, 0x001e, 0x00ce, + 0x00fe, 0x012e, 0x0005, 0x00c6, 0x080c, 0x5745, 0x1118, 0x20a9, + 0x0100, 0x0010, 0x20a9, 0x0082, 0x080c, 0x5745, 0x1118, 0x2009, + 0x0000, 0x0010, 0x2009, 0x007e, 0x0016, 0x0026, 0x0036, 0x2110, + 0x0026, 0x2019, 0x0029, 0x080c, 0x7ba2, 0x002e, 0x080c, 0xad6c, + 0x003e, 0x002e, 0x001e, 0x080c, 0x26a3, 0x8108, 0x1f04, 0x0a44, + 0x00ce, 0x706f, 0x0000, 0x7070, 0x9084, 0x00ff, 0x7072, 0x709f, + 0x0000, 0x0005, 0x0126, 0x2091, 0x8000, 0x7000, 0x9086, 0x0002, + 0x1904, 0x0b32, 0x7098, 0x9086, 0xffff, 0x0130, 0x080c, 0x23cd, + 0x080c, 0x6d42, 0x0804, 0x0b32, 0x70cc, 0xd0ac, 0x1110, 0xd09c, + 0x0520, 0xd084, 0x0510, 0x0006, 0x2001, 0x0103, 0x2003, 0x002b, + 0x000e, 0xd08c, 0x01d0, 0x70d0, 0x9086, 0xffff, 0x0190, 0x080c, + 0x252c, 0x080c, 0x6d42, 0x70cc, 0xd094, 0x1904, 0x0b32, 0x2011, + 0x0001, 0x2019, 0x0000, 0x080c, 0x2562, 0x080c, 0x6d42, 0x0804, + 0x0b32, 0x70d4, 0x9005, 0x1904, 0x0b32, 0x7094, 0x9005, 0x1904, + 0x0b32, 0x70cc, 0xd0a4, 0x0118, 0xd0b4, 0x0904, 0x0b32, 0x080c, + 0x4de0, 0x1904, 0x0b32, 0x2001, 0x1153, 0x2004, 0xd0ac, 0x01c8, + 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, + 0x4b58, 0x1118, 0x6000, 0xd0ec, 0x1138, 0x001e, 0x8108, 0x1f04, + 0x0ab6, 0x00ce, 0x015e, 0x0028, 0x001e, 0x00ce, 0x015e, 0x0804, + 0x0b32, 0x0006, 0x2001, 0x0103, 0x2003, 0x006b, 0x000e, 0x9006, + 0x2009, 0x0700, 0x20a9, 0x0002, 0x20a1, 0x12ca, 0x20e9, 0x0001, + 0x4001, 0x706c, 0x8007, 0x7170, 0x810f, 0x20a9, 0x0002, 0x4001, + 0x2009, 0x0000, 0x080c, 0x0cd7, 0x2001, 0x0000, 0x810f, 0x20a9, + 0x0002, 0x4001, 0x9006, 0x2009, 0x0200, 0x20a9, 0x0002, 0x20a1, + 0x12da, 0x4001, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003, 0x709b, + 0xffff, 0x7034, 0xd0b4, 0x1130, 0x0026, 0x2011, 0x0040, 0x080c, + 0x0d63, 0x002e, 0x9006, 0x080c, 0x1c36, 0x0036, 0x0046, 0x2019, + 0xffff, 0x2021, 0x0006, 0x080c, 0x384a, 0x004e, 0x003e, 0x00f6, + 0x2079, 0x0100, 0x080c, 0x576b, 0x0150, 0x080c, 0x5745, 0x7828, + 0x0118, 0x9084, 0xe1ff, 0x0010, 0x9084, 0xffdf, 0x782a, 0x00fe, + 0x2001, 0x12dd, 0x2004, 0x9086, 0x0005, 0x1120, 0x2011, 0x0000, + 0x080c, 0x79c2, 0x2011, 0x0000, 0x080c, 0x79cc, 0x080c, 0x6d42, + 0x080c, 0x6e10, 0x012e, 0x0005, 0x0016, 0x0046, 0x00f6, 0x0126, + 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, 0x080c, 0x46a4, + 0x7940, 0x918c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0110, 0x7827, + 0x0040, 0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, 0x0036, 0x0156, + 0x7954, 0xd1ac, 0x1904, 0x0b9b, 0x080c, 0x5757, 0x0158, 0x080c, + 0x576b, 0x1128, 0x2001, 0x128f, 0x2003, 0x0000, 0x0070, 0x080c, + 0x574d, 0x0dc0, 0x2001, 0x128f, 0x2003, 0xaaaa, 0x2001, 0x1290, + 0x2003, 0x0001, 0x080c, 0x5682, 0x0058, 0x080c, 0x5745, 0x0140, + 0x2009, 0x00f8, 0x080c, 0x46a4, 0x7843, 0x0090, 0x7843, 0x0010, + 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, 0x5745, 0x0138, + 0x7824, 0xd0ac, 0x1904, 0x0c6f, 0x1f04, 0x0b7a, 0x0070, 0x7824, + 0x080c, 0x5761, 0x0118, 0xd0ac, 0x1904, 0x0c6f, 0x9084, 0x1800, + 0x0d98, 0x7003, 0x0001, 0x0804, 0x0c6f, 0x2001, 0x0001, 0x080c, + 0x1c36, 0x0804, 0x0c78, 0x080c, 0x203d, 0x1148, 0x2001, 0x0001, + 0x080c, 0x1faf, 0x2001, 0x0001, 0x080c, 0x1f92, 0x00d8, 0x080c, + 0x2045, 0x1138, 0x9006, 0x080c, 0x1faf, 0x9006, 0x080c, 0x1f92, + 0x0088, 0x080c, 0x204d, 0x1d50, 0x2001, 0x12b8, 0x2004, 0xd0fc, + 0x0128, 0x7828, 0x9085, 0x0020, 0x782a, 0x0020, 0x080c, 0x1d96, + 0x0804, 0x0c6a, 0x7850, 0x9085, 0x0040, 0x7852, 0x7938, 0x7850, + 0x9084, 0xfbcf, 0x7852, 0x080c, 0x2055, 0x9085, 0x2000, 0x7852, + 0x793a, 0x20a9, 0x0046, 0x1d04, 0x0bd3, 0x2091, 0x6000, 0x1f04, + 0x0bd3, 0x7850, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x7852, 0x793a, + 0x080c, 0x5757, 0x0158, 0x080c, 0x576b, 0x1128, 0x2001, 0x128f, + 0x2003, 0x0000, 0x0070, 0x080c, 0x574d, 0x0dc0, 0x2001, 0x128f, + 0x2003, 0xaaaa, 0x2001, 0x1290, 0x2003, 0x0001, 0x080c, 0x5682, + 0x0020, 0x2009, 0x00f8, 0x080c, 0x46a4, 0x20a9, 0x0028, 0xa001, + 0x1f04, 0x0bff, 0x7850, 0x9085, 0x1400, 0x7852, 0x080c, 0x5745, + 0x0120, 0x7843, 0x0090, 0x7843, 0x0010, 0x2021, 0xe678, 0x2019, + 0xea60, 0x7820, 0xd09c, 0x1528, 0x080c, 0x5745, 0x05c0, 0x7824, + 0xd0ac, 0x1904, 0x0c6f, 0x080c, 0x576b, 0x11d8, 0x0046, 0x2021, + 0x0320, 0x8421, 0x1df0, 0x004e, 0x7827, 0x1800, 0x080c, 0x2055, + 0x7824, 0x9084, 0x1800, 0x1110, 0x8421, 0x1158, 0x2001, 0x128f, + 0x2003, 0xaaaa, 0x2001, 0x1290, 0x2003, 0x0001, 0x7003, 0x0001, + 0x04b0, 0x8319, 0x19b0, 0x2009, 0x12bb, 0x2104, 0x8001, 0x200a, + 0x1168, 0x7827, 0x0048, 0x20a9, 0x0002, 0x080c, 0x2036, 0x7924, + 0x080c, 0x2055, 0xd19c, 0x0110, 0x080c, 0x1f80, 0x00d8, 0x080c, + 0x5757, 0x1140, 0x94a2, 0x03e8, 0x1128, 0x080c, 0x571c, 0x7003, + 0x0001, 0x00a8, 0x7827, 0x1800, 0x080c, 0x2055, 0x7824, 0x080c, + 0x5761, 0x0110, 0xd0ac, 0x1158, 0x9084, 0x1800, 0x0990, 0x7003, + 0x0001, 0x0028, 0x2001, 0x0001, 0x080c, 0x1c36, 0x0028, 0x7827, + 0x0048, 0x7828, 0xc09d, 0x782a, 0x7850, 0x9085, 0x0400, 0x7852, + 0x9006, 0x78f2, 0x015e, 0x003e, 0x000e, 0x7034, 0xd0b4, 0x1110, + 0x080c, 0x0d29, 0x012e, 0x00fe, 0x004e, 0x001e, 0x0005, 0x0005, + 0x0005, 0x0005, 0x2a70, 0x2001, 0x128f, 0x2003, 0x0000, 0x7087, + 0x0000, 0x2009, 0x0100, 0x2104, 0x9082, 0x0002, 0x0218, 0x704f, + 0xffff, 0x0010, 0x704f, 0x0000, 0x7057, 0xffff, 0x706f, 0x0000, + 0x7073, 0x0000, 0x080c, 0x99a3, 0x2061, 0x127f, 0x6003, 0x0909, + 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, 0x00ff, + 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, 0x1287, + 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, 0x0200, + 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, 0x0000, + 0x2061, 0x12a9, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, 0x4943, + 0x600f, 0x2020, 0x2001, 0x1127, 0x2003, 0x0000, 0x0005, 0x2011, + 0x0000, 0x080c, 0x4b58, 0x1178, 0x6004, 0x90c4, 0x00ff, 0x98c6, + 0x0006, 0x0128, 0x90c4, 0xff00, 0x98c6, 0x0600, 0x1120, 0x9186, + 0x0080, 0x0108, 0x8210, 0x8108, 0x9186, 0x0100, 0x1d50, 0x2208, + 0x0005, 0x2091, 0x8000, 0x0e04, 0x0cf3, 0x0006, 0x0016, 0x2079, + 0x0000, 0x001e, 0x798e, 0x000e, 0x788a, 0x000e, 0x7886, 0x3900, + 0x789a, 0x7883, 0x8002, 0x7837, 0x8002, 0x7833, 0x0012, 0x2091, + 0x5000, 0x0156, 0x00d6, 0x2079, 0x0300, 0x7803, 0x0000, 0x2069, + 0x1331, 0x901e, 0x20a9, 0x0020, 0x7b26, 0x7a28, 0x226a, 0x8d68, + 0x8318, 0x1f04, 0x0d14, 0x00de, 0x015e, 0x2079, 0x1100, 0x7803, + 0x0005, 0x2091, 0x4080, 0x7834, 0xd0b4, 0x1108, 0x0451, 0x0cd8, + 0x0005, 0x00f6, 0x0006, 0x2079, 0x1123, 0x2f04, 0x8000, 0x207a, + 0x9082, 0x000f, 0x0258, 0x9006, 0x207a, 0x2079, 0x1125, 0x2f04, + 0x9084, 0x0001, 0x9086, 0x0001, 0x207a, 0x0080, 0x2079, 0x1125, + 0x2f7c, 0x8fff, 0x1130, 0x0026, 0x2011, 0x0080, 0x00e1, 0x002e, + 0x0028, 0x0026, 0x2011, 0x0000, 0x00b1, 0x002e, 0x000e, 0x00fe, + 0x0005, 0x0026, 0x2011, 0x0080, 0x0071, 0x002e, 0x2009, 0x0fff, + 0x00b9, 0x0026, 0x2011, 0x0040, 0x0031, 0x002e, 0x2009, 0x0fff, + 0x0079, 0x0c78, 0x0005, 0x0016, 0x3b08, 0x3a00, 0x9104, 0x918d, + 0x00c0, 0x21d8, 0x9084, 0xff3f, 0x9205, 0x20d0, 0x001e, 0x0005, + 0x0156, 0x0126, 0x918c, 0x0fff, 0x21a8, 0x1d04, 0x0d75, 0x2091, + 0x6000, 0x1f04, 0x0d75, 0x012e, 0x015e, 0x0005, 0x890b, 0x810b, + 0x810b, 0x810b, 0x810b, 0x810b, 0x9994, 0xfc00, 0x8217, 0x8214, + 0x8214, 0x0005, 0x0006, 0x814c, 0x894c, 0x894c, 0x894c, 0x894c, + 0x894c, 0x9284, 0x003f, 0x8007, 0x8003, 0x8003, 0x994d, 0x000e, + 0x0005, 0x0016, 0x0026, 0x0096, 0x3348, 0x0c01, 0x2100, 0x9300, + 0x2098, 0x22e0, 0x009e, 0x002e, 0x001e, 0x3518, 0x20a9, 0x0001, + 0x4002, 0x8007, 0x4004, 0x8319, 0x1dd8, 0x0005, 0x2071, 0x1100, + 0x715c, 0x712e, 0x2021, 0x0001, 0x9190, 0x0040, 0x9298, 0x0040, + 0x0240, 0x7060, 0x9302, 0x1228, 0x220a, 0x2208, 0x2310, 0x8420, + 0x0ca8, 0x200b, 0x0000, 0x74ae, 0x74b2, 0x0005, 0x00e6, 0x0126, + 0x2091, 0x8000, 0x2071, 0x1100, 0x70b0, 0x90ea, 0x0010, 0x0268, + 0x8001, 0x70b2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, + 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0x906e, 0x0cd8, 0x00e6, + 0x2071, 0x1100, 0x0126, 0x2091, 0x8000, 0x70b0, 0x8001, 0x0260, + 0x70b2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, + 0x0000, 0x012e, 0x00ee, 0x0005, 0x906e, 0x0cd8, 0x00e6, 0x0126, + 0x2091, 0x8000, 0x2071, 0x1100, 0x702c, 0x206a, 0x2d00, 0x702e, + 0x70b0, 0x8000, 0x70b2, 0x012e, 0x00ee, 0x0005, 0x8dff, 0x0138, + 0x6804, 0x6807, 0x0000, 0x0006, 0x0c49, 0x00de, 0x0cb8, 0x0005, + 0x00e6, 0x2071, 0x1100, 0x70b0, 0x908a, 0x0010, 0x900d, 0x00ee, + 0x0005, 0x00d6, 0x0821, 0x0148, 0x0016, 0x0026, 0x2d08, 0x2011, + 0x0001, 0x080c, 0x0d8a, 0x002e, 0x001e, 0x00de, 0x0005, 0x00d6, + 0x080c, 0x0dc6, 0x0148, 0x0016, 0x0026, 0x2d08, 0x2011, 0x0001, + 0x080c, 0x0d8a, 0x002e, 0x001e, 0x00de, 0x0005, 0x00d6, 0x0016, + 0x0026, 0x080c, 0x0d7e, 0x2168, 0x002e, 0x001e, 0x080c, 0x0df6, + 0x00de, 0x0005, 0x00e6, 0x2071, 0x130a, 0x7007, 0x0000, 0x701f, + 0x0000, 0x7023, 0x0000, 0x7003, 0x0000, 0x2071, 0x0000, 0x7010, + 0x9085, 0x8004, 0x7012, 0x00ee, 0x0005, 0x00e6, 0x2270, 0x700b, + 0x0000, 0x2071, 0x130a, 0x701c, 0x9088, 0x1314, 0x220a, 0x8000, + 0x9084, 0x0007, 0x701e, 0x7004, 0x9005, 0x1128, 0x00f6, 0x2079, + 0x0080, 0x0081, 0x00fe, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x130a, + 0x7004, 0x9005, 0x1128, 0x00f6, 0x2079, 0x0080, 0x0019, 0x00fe, + 0x00ee, 0x0005, 0x7000, 0x0002, 0x0e7e, 0x0cf1, 0x701c, 0x7120, + 0x9106, 0x1118, 0x7007, 0x0000, 0x0005, 0x00d6, 0x9180, 0x1314, + 0x2004, 0x700a, 0x2068, 0x8108, 0x918c, 0x0007, 0x7122, 0x782b, + 0x0026, 0x6828, 0x7802, 0x682c, 0x7806, 0x6830, 0x780a, 0x6834, + 0x780e, 0x6814, 0x700e, 0x680c, 0x7016, 0x6810, 0x701a, 0x6804, + 0x00de, 0xd084, 0x0120, 0x7007, 0x0001, 0x0029, 0x0005, 0x7007, + 0x0002, 0x00b1, 0x0005, 0x0016, 0x0026, 0x710c, 0x2011, 0x0040, + 0x9182, 0x0040, 0x1210, 0x2110, 0x9006, 0x700e, 0x7212, 0x8203, + 0x7812, 0x782b, 0x0020, 0x782b, 0x0041, 0x002e, 0x001e, 0x0005, + 0x0016, 0x0026, 0x0136, 0x0146, 0x0156, 0x7014, 0x20e0, 0x7018, + 0x2098, 0x20e9, 0x0000, 0x20a1, 0x0088, 0x782b, 0x0026, 0x710c, + 0x2011, 0x0040, 0x9182, 0x0040, 0x1210, 0x2110, 0x9006, 0x700e, + 0x22a8, 0x4006, 0x8203, 0x7812, 0x782b, 0x0020, 0x3300, 0x701a, + 0x782b, 0x0001, 0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, + 0x0016, 0x00e6, 0x2071, 0x130a, 0x00f6, 0x2079, 0x0080, 0x792c, + 0x782b, 0x0002, 0xd1fc, 0x0120, 0x918c, 0x0700, 0x7004, 0x0023, + 0x00fe, 0x00ee, 0x001e, 0x0005, 0x0e7a, 0x0f01, 0x0f33, 0x0f00, + 0x0cf8, 0x918c, 0x0700, 0x1548, 0x0136, 0x0146, 0x0156, 0x7014, + 0x20e8, 0x7018, 0x20a0, 0x20e1, 0x0000, 0x2099, 0x0088, 0x782b, + 0x0040, 0x7010, 0x20a8, 0x4005, 0x3400, 0x701a, 0x015e, 0x014e, + 0x013e, 0x700c, 0x9005, 0x0560, 0x7800, 0x7802, 0x7804, 0x7806, + 0x080c, 0x0eab, 0x0005, 0x7008, 0x9080, 0x0002, 0x2003, 0x0100, + 0x7007, 0x0000, 0x080c, 0x0e7a, 0x0005, 0x7008, 0x9080, 0x0002, + 0x2003, 0x0200, 0x0ca8, 0x918c, 0x0700, 0x1150, 0x700c, 0x9005, + 0x0178, 0x7800, 0x7802, 0x7804, 0x7806, 0x080c, 0x0ec0, 0x0005, + 0x7008, 0x9080, 0x0002, 0x2003, 0x0200, 0x7007, 0x0000, 0x0080, + 0x00d6, 0x7008, 0x2068, 0x7800, 0x682a, 0x7804, 0x682e, 0x7808, + 0x6832, 0x780c, 0x6836, 0x680b, 0x0100, 0x00de, 0x7007, 0x0000, + 0x00c6, 0x00d6, 0x7008, 0x2060, 0x0081, 0x0150, 0x6038, 0x080f, + 0x603b, 0x0000, 0x603f, 0x0000, 0x2c00, 0x2068, 0x080c, 0x0df6, + 0x00de, 0x00ce, 0x080c, 0x0e7a, 0x0005, 0x00e6, 0x2071, 0x1100, + 0x8cff, 0x0140, 0x705c, 0x9c02, 0x0238, 0x9c82, 0xffff, 0x1220, + 0x9085, 0x0001, 0x00ee, 0x0005, 0x9006, 0x0ce0, 0x603c, 0x906d, + 0x090c, 0x0cf1, 0x6008, 0x908e, 0x0100, 0x0130, 0x687b, 0x0030, + 0x6883, 0x0000, 0x6897, 0x4002, 0x080c, 0x50a5, 0x0005, 0x0126, + 0x2091, 0x2200, 0x2079, 0x0300, 0x2071, 0x131c, 0x7003, 0x0000, + 0x78bf, 0x00f6, 0x00c1, 0x7803, 0x0003, 0x780f, 0x0000, 0x20a9, + 0x01c4, 0x2061, 0xae21, 0x2c0d, 0x7912, 0xe104, 0x9ce0, 0x0002, + 0x7916, 0x1f04, 0x0fa3, 0x7807, 0x0001, 0x7803, 0x0000, 0x7803, + 0x0001, 0x012e, 0x0005, 0x00c6, 0x7803, 0x0000, 0x7827, 0x0030, + 0x782b, 0x0400, 0x7827, 0x0031, 0x782b, 0x1331, 0x781f, 0xff00, + 0x781b, 0xff00, 0x2061, 0x1331, 0x602f, 0x15c0, 0x6033, 0x3000, + 0x603b, 0x168e, 0x00ce, 0x0005, 0x0126, 0x2091, 0x2200, 0x7808, + 0xd09c, 0x0138, 0x7820, 0x908c, 0xf000, 0x1508, 0x0043, 0x012e, + 0x0005, 0x9084, 0x0070, 0x190c, 0x0cf1, 0x012e, 0x0005, 0x0ff5, + 0x0ff7, 0x0ffe, 0x1002, 0x1006, 0x100b, 0x100e, 0x1012, 0x101f, + 0x1024, 0x0ff5, 0x108d, 0x1091, 0x10d3, 0x0ff5, 0x0ff5, 0x0ff5, + 0x0ff5, 0x0ff5, 0x0ff5, 0x0ff5, 0x0ff5, 0x080c, 0x0cf1, 0x2009, + 0x0048, 0x2060, 0x080c, 0x7f4e, 0x012e, 0x0005, 0x7004, 0xc085, + 0x7006, 0x0005, 0x7004, 0xc085, 0x7006, 0x0005, 0x080c, 0x10da, + 0x080c, 0x1161, 0x0005, 0x080c, 0x0cf1, 0x0005, 0x7004, 0xc095, + 0x7006, 0x0005, 0x080c, 0x10da, 0x2060, 0x6014, 0x9080, 0x000e, + 0x2003, 0xffff, 0x2009, 0x0048, 0x080c, 0x7f4e, 0x0005, 0x080c, + 0x10da, 0x080c, 0x0cf1, 0x0005, 0x080c, 0x10da, 0x2001, 0x0016, + 0x080c, 0x113b, 0x7827, 0x0018, 0x79ac, 0xd1dc, 0x01c8, 0x7827, + 0x0015, 0x7828, 0x782b, 0x0000, 0x9065, 0x0138, 0x2001, 0x020d, + 0x2003, 0x0050, 0x2003, 0x0020, 0x0088, 0x7004, 0x9005, 0x090c, + 0x0cf1, 0x78ab, 0x0004, 0x7803, 0x0001, 0x080c, 0x1091, 0x0005, + 0x7828, 0x782b, 0x0000, 0x9065, 0x090c, 0x0cf1, 0x6014, 0x2068, + 0x78ab, 0x0004, 0x918c, 0x0700, 0x01d8, 0x080c, 0x1337, 0x080c, + 0x95d2, 0x0158, 0x69ac, 0x6936, 0x69b0, 0x693a, 0x683f, 0xffff, + 0x6843, 0xffff, 0x6880, 0xc0bd, 0x6882, 0x7827, 0x0015, 0x782b, + 0x0000, 0x781f, 0x0300, 0x7803, 0x0001, 0x080c, 0x92a4, 0x0005, + 0x6010, 0x2004, 0xd0bc, 0x190c, 0x993c, 0x2001, 0x0201, 0x2004, + 0x9005, 0x0dd8, 0x7dbc, 0x080c, 0xadd8, 0xd5a4, 0x1118, 0x080c, + 0x10df, 0x0005, 0x080c, 0x1337, 0x7827, 0x0015, 0x782b, 0x0000, + 0x781f, 0x0300, 0x7803, 0x0001, 0x0005, 0x7004, 0xc09d, 0x7006, + 0x0005, 0x7104, 0x9184, 0x0004, 0x190c, 0x0cf1, 0xd184, 0x1181, + 0xd19c, 0x0150, 0xc19c, 0x7106, 0x2001, 0x020d, 0x2003, 0x0050, + 0x2003, 0x0020, 0x04e1, 0x0005, 0x81ff, 0x190c, 0x0cf1, 0x0005, + 0xc184, 0x7106, 0x0016, 0x00e6, 0x2071, 0x0200, 0x080c, 0x1155, + 0x6014, 0x9005, 0x01c0, 0x9080, 0x0019, 0x2004, 0x9084, 0x00ff, + 0x9086, 0x0029, 0x1180, 0x00f6, 0x2c78, 0x080c, 0x119d, 0x00fe, + 0x2001, 0x020d, 0x2003, 0x0020, 0x080c, 0x0fb3, 0x7803, 0x0001, + 0x00ee, 0x001e, 0x0005, 0x2001, 0x020d, 0x2003, 0x0050, 0x2003, + 0x0020, 0x0069, 0x0ca8, 0x0031, 0x2060, 0x2009, 0x0053, 0x080c, + 0x7f4e, 0x0005, 0x7808, 0xd09c, 0x0de8, 0x7820, 0x0005, 0x00d6, + 0x2069, 0x0200, 0x7908, 0x918c, 0x0007, 0x9186, 0x0003, 0x0120, + 0x2001, 0x0016, 0x080c, 0x113b, 0x6804, 0x9005, 0x0de8, 0x2001, + 0x015d, 0x2003, 0x0000, 0x79bc, 0x0016, 0x001e, 0xd1a4, 0x1518, + 0x79b8, 0x0016, 0x001e, 0x918c, 0x0fff, 0x0178, 0x9182, 0x0841, + 0x1260, 0x9188, 0x0007, 0x918c, 0x0ff8, 0x810c, 0x810c, 0x810c, + 0x0421, 0x6827, 0x0001, 0x8109, 0x1dd8, 0x00f9, 0x6827, 0x0002, + 0x00e1, 0x682c, 0xd0e4, 0x1148, 0x6804, 0x9005, 0x0de8, 0x79b8, + 0xd1ec, 0x1118, 0x08c0, 0x080c, 0x1337, 0x7827, 0x0015, 0x782b, + 0x0000, 0x2001, 0x020d, 0x2003, 0x0020, 0x2001, 0x0307, 0x2003, + 0x0300, 0x7803, 0x0001, 0x00de, 0x0005, 0x6824, 0x9084, 0x0003, + 0x1de0, 0x0005, 0x2001, 0x0030, 0x2c08, 0x621c, 0x0021, 0x7830, + 0x9086, 0x0041, 0x0005, 0x00f6, 0x2079, 0x0300, 0x0006, 0x7808, + 0xd09c, 0x0140, 0x0016, 0x0026, 0x00c6, 0x080c, 0x0fcc, 0x00ce, + 0x002e, 0x001e, 0x000e, 0x7832, 0x7936, 0x7a3a, 0x781b, 0x8080, + 0x7818, 0xd0bc, 0x1de8, 0x00fe, 0x0005, 0x7037, 0x0001, 0x7150, + 0x7037, 0x0002, 0x7050, 0x2060, 0xd1bc, 0x1110, 0x7054, 0x2060, + 0x0005, 0x00e6, 0x0016, 0x2071, 0x0200, 0x0c79, 0x7358, 0x745c, + 0x6014, 0x905d, 0x0530, 0x2b68, 0x6010, 0x2004, 0xd0bc, 0x190c, + 0x9917, 0x6b42, 0x6c3e, 0x2001, 0x1174, 0x2004, 0xd0b4, 0x1120, + 0x683b, 0xffff, 0x6837, 0xffff, 0x080c, 0x16ae, 0x1190, 0x080c, + 0x1255, 0x2a00, 0x6816, 0x0130, 0x2c00, 0x680e, 0x2805, 0x680a, + 0x2800, 0x6812, 0x7037, 0x0020, 0x781f, 0x0300, 0x001e, 0x00ee, + 0x0005, 0x7037, 0x0050, 0x7037, 0x0020, 0x001e, 0x00ee, 0x080c, + 0x10df, 0x0005, 0x080c, 0x0cf1, 0x0005, 0x2ff0, 0x0126, 0x2091, + 0x2200, 0x3e60, 0x6014, 0x2068, 0x2d60, 0x903e, 0x2730, 0x6964, + 0x691a, 0x9184, 0x000f, 0x9088, 0x168e, 0x2145, 0x0002, 0x11bf, + 0x1226, 0x11bf, 0x11bf, 0x11bf, 0x11ff, 0x11bf, 0x11c3, 0x11bf, + 0x1214, 0x11bf, 0x11bf, 0x11bf, 0x11bf, 0x11e9, 0x11d5, 0x9085, + 0x0001, 0x0804, 0x124d, 0x687c, 0xd0bc, 0x0dc8, 0x6890, 0x6842, + 0x688c, 0x683e, 0x6888, 0x00d6, 0x2805, 0x9c68, 0x6b08, 0x6a0c, + 0x6d00, 0x6c04, 0x00de, 0x0804, 0x1235, 0x687c, 0xd0bc, 0x0d38, + 0x6890, 0x6842, 0x688c, 0x683e, 0x6888, 0x00d6, 0x2805, 0x9c68, + 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x00de, 0x0804, + 0x1235, 0x687c, 0xd0bc, 0x0998, 0x6890, 0x6842, 0x688c, 0x683e, + 0x6804, 0x2060, 0x9080, 0x0019, 0x200c, 0x691a, 0x91cc, 0x000f, + 0x9980, 0x168e, 0x2045, 0x6888, 0xd19c, 0x11e8, 0x0470, 0x687c, + 0xd0ac, 0x0904, 0x11bf, 0x6804, 0x2060, 0x9080, 0x0019, 0x200c, + 0x691a, 0x91cc, 0x000f, 0x9980, 0x168e, 0x2045, 0x9006, 0x6842, + 0x683e, 0xd19c, 0x1140, 0x00c8, 0x687c, 0xd0ac, 0x0904, 0x11bf, + 0x9006, 0x6842, 0x683e, 0x00d6, 0x2805, 0x9c68, 0x6b10, 0x6a14, + 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x00de, 0x0078, 0x687c, 0xd0ac, + 0x0904, 0x11bf, 0x9006, 0x6842, 0x683e, 0x00d6, 0x2805, 0x9c68, + 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x00de, 0x6b2e, 0x6a32, 0x6d1e, + 0x6c22, 0x6f26, 0x6e2a, 0x6988, 0x8840, 0x281d, 0x68ac, 0x6ab0, + 0x6836, 0x6a3a, 0x8109, 0x6916, 0x1150, 0x3e60, 0x601c, 0xc085, + 0x601e, 0x687c, 0xc0dd, 0x687e, 0x9006, 0x012e, 0x0005, 0x2c00, + 0x680e, 0x6b0a, 0x2800, 0x6812, 0x0c80, 0x903e, 0x2730, 0x6880, + 0xd0fc, 0x11a8, 0x00d6, 0x2805, 0x9c68, 0x2900, 0x0002, 0x1297, + 0x127d, 0x127d, 0x1297, 0x1297, 0x1291, 0x1297, 0x127d, 0x1297, + 0x1282, 0x1282, 0x1297, 0x1297, 0x1297, 0x1289, 0x1282, 0xc0fc, + 0x6882, 0x6b2c, 0x6a30, 0x6d1c, 0x6c20, 0x00d6, 0xd99c, 0x0510, + 0x2805, 0x9c68, 0x6f08, 0x6e0c, 0x00e8, 0x6b08, 0x6a0c, 0x6d00, + 0x6c04, 0x00c0, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, + 0x0088, 0x00de, 0x00d6, 0x6864, 0x9084, 0x00ff, 0x9086, 0x001e, + 0x1130, 0x00de, 0x080c, 0x164e, 0x1900, 0x900e, 0x0060, 0x00de, + 0x080c, 0x0cf1, 0x00de, 0x6b2e, 0x6a32, 0x6d1e, 0x6c22, 0x6f26, + 0x6e2a, 0x080c, 0x164e, 0x0005, 0x2001, 0x020b, 0x2004, 0xd0e4, + 0x0110, 0xd0d4, 0x1140, 0x6014, 0x9080, 0x0021, 0x6118, 0x2102, + 0x601b, 0x0002, 0x0005, 0x0126, 0x00c6, 0x2091, 0x2200, 0x00ce, + 0x2001, 0x0037, 0x2c08, 0x080c, 0x113b, 0x6000, 0x9086, 0x0004, + 0x1120, 0x2009, 0x0048, 0x080c, 0x7f4e, 0x012e, 0x0005, 0x0126, + 0x00c6, 0x2091, 0x2200, 0x00ce, 0x7908, 0x918c, 0x0007, 0x9186, + 0x0000, 0x0904, 0x132c, 0x9186, 0x0003, 0x0904, 0x132c, 0x6020, + 0x6023, 0x0000, 0x0006, 0x2031, 0x0190, 0x00c6, 0x7808, 0xd09c, + 0x190c, 0x0fcc, 0x00ce, 0x2001, 0x0038, 0x2c08, 0x621c, 0x080c, + 0x113b, 0x7930, 0x9186, 0x0040, 0x05d8, 0x9186, 0x0042, 0x190c, + 0x0cf1, 0x2001, 0x001e, 0x8001, 0x1df0, 0x8631, 0x1d30, 0x080c, + 0x136e, 0x0026, 0x0056, 0x2001, 0x00d2, 0x8001, 0x1df0, 0x2031, + 0x2000, 0x8631, 0x05a1, 0x2001, 0x020b, 0x2004, 0xd0e4, 0x0dc8, + 0x78ab, 0x0004, 0x080c, 0x0fb3, 0x781f, 0x8080, 0x78ab, 0x0009, + 0x601c, 0xc084, 0x601e, 0x080c, 0x5745, 0x1130, 0x0066, 0x2031, + 0x0001, 0x080c, 0x57d6, 0x006e, 0x7803, 0x0000, 0x7803, 0x0001, + 0x005e, 0x002e, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, + 0x000e, 0x6022, 0x012e, 0x0005, 0x601c, 0xc084, 0x601e, 0x7827, + 0x0015, 0x7828, 0x9c06, 0x1db0, 0x782b, 0x0000, 0x0c98, 0x080c, + 0x5745, 0x11b0, 0x2001, 0x0138, 0x2003, 0x0000, 0x2001, 0x0160, + 0x2003, 0x0000, 0x2011, 0x012c, 0xa001, 0xa001, 0x8211, 0x1de0, + 0x0081, 0x0066, 0x2031, 0x0000, 0x080c, 0x57d6, 0x006e, 0x0005, + 0x00e9, 0x0039, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, + 0x0005, 0x00e6, 0x2071, 0x0200, 0x080c, 0x205b, 0x7003, 0x002c, + 0x2001, 0x015d, 0x2003, 0x0000, 0x7000, 0x9084, 0x002c, 0x1de0, + 0x7098, 0x709a, 0x709c, 0x709e, 0x00ee, 0x0005, 0x2001, 0x0138, + 0x2014, 0x2003, 0x0000, 0x2001, 0x0160, 0x202c, 0x2003, 0x0000, + 0x2021, 0x0260, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x1168, 0x2001, + 0x0109, 0x201c, 0x939c, 0x0048, 0x1160, 0x2001, 0x0111, 0x201c, + 0x83ff, 0x1110, 0x8421, 0x1d70, 0x2001, 0x015d, 0x2003, 0x0000, + 0x0005, 0x0046, 0x2021, 0x0019, 0x2003, 0x0048, 0xa001, 0xa001, + 0x201c, 0x939c, 0x0048, 0x0120, 0x8421, 0x1db0, 0x004e, 0x0c60, + 0x004e, 0x0c40, 0x00e6, 0x2071, 0x131f, 0x7003, 0x0000, 0x00ee, + 0x0005, 0x00d6, 0x9280, 0x0005, 0x206c, 0x697c, 0xd1dc, 0x1904, + 0x141f, 0x6964, 0x9184, 0x0007, 0x0002, 0x13bd, 0x140a, 0x13bd, + 0x13bd, 0x13bd, 0x13f1, 0x13d0, 0x13bf, 0x080c, 0x0cf1, 0x687c, + 0xd0b4, 0x0904, 0x1507, 0x6890, 0x6842, 0x683a, 0x688c, 0x683e, + 0x6836, 0x68ac, 0x6846, 0x68b0, 0x684a, 0x6988, 0x0804, 0x1412, + 0x6864, 0x9084, 0x00ff, 0x9086, 0x001e, 0x1d38, 0x687c, 0xd0b4, + 0x0904, 0x1507, 0x6890, 0x6842, 0x683a, 0x688c, 0x683e, 0x6836, + 0x68ac, 0x6846, 0x68b0, 0x684a, 0x6804, 0x685a, 0x9080, 0x0019, + 0x2004, 0x9084, 0x000f, 0x9080, 0x168e, 0x2005, 0x6812, 0x6988, + 0x0450, 0x918c, 0x00ff, 0x9186, 0x0015, 0x1548, 0x687c, 0xd0b4, + 0x0904, 0x1507, 0x6804, 0x685a, 0x9080, 0x0019, 0x2004, 0x9084, + 0x000f, 0x9080, 0x168e, 0x2005, 0x6812, 0x6988, 0x9006, 0x6842, + 0x683e, 0x0088, 0x687c, 0xd0b4, 0x0904, 0x1507, 0x6988, 0x9006, + 0x6842, 0x683e, 0x2d00, 0x685a, 0x6864, 0x9084, 0x000f, 0x9080, + 0x168e, 0x2005, 0x6812, 0x6916, 0x687c, 0xc0dd, 0x687e, 0x00de, + 0x0005, 0x00f6, 0x2079, 0x0090, 0x782c, 0xd0fc, 0x190c, 0x1543, + 0x00e6, 0x00d6, 0x2071, 0x131f, 0x7000, 0x9005, 0x1904, 0x1478, + 0x00c6, 0x7206, 0x9280, 0x0005, 0x205c, 0x7004, 0x2068, 0x782b, + 0x0004, 0x6810, 0x00d6, 0x2068, 0x686c, 0x7836, 0x6890, 0x00f6, + 0x2079, 0x0200, 0x7803, 0x0040, 0x781a, 0x2079, 0x0100, 0x8004, + 0x78d6, 0x00fe, 0x00de, 0x2b68, 0x6814, 0x2050, 0x6858, 0x2060, + 0x6810, 0x2040, 0x6064, 0x90cc, 0x000f, 0x6944, 0x791a, 0x7116, + 0x6848, 0x781e, 0x701a, 0x9006, 0x700e, 0x7012, 0x7004, 0x6940, + 0x6838, 0x9106, 0x11c8, 0x693c, 0x6834, 0x9106, 0x11a8, 0x8aff, + 0x01f0, 0x0126, 0x2091, 0x8000, 0x2079, 0x0090, 0x2009, 0x0001, + 0x00d1, 0x0118, 0x2009, 0x0001, 0x00b1, 0x012e, 0x00ce, 0x9006, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0036, 0x0046, 0x6b38, 0x6c34, + 0x080c, 0x16ae, 0x004e, 0x003e, 0x0d10, 0x00ce, 0x0c88, 0x00ce, + 0x9085, 0x0001, 0x0c68, 0x0076, 0x0066, 0x0056, 0x0046, 0x0036, + 0x0026, 0x8aff, 0x0904, 0x1500, 0x700c, 0x7214, 0x923a, 0x7010, + 0x7218, 0x9203, 0x0a04, 0x14ff, 0x9705, 0x0904, 0x14ff, 0x903e, + 0x2730, 0x6880, 0xd0fc, 0x11a8, 0x00d6, 0x2805, 0x9c68, 0x2900, + 0x0002, 0x14e2, 0x14c7, 0x14c7, 0x14e2, 0x14e2, 0x14db, 0x14e2, + 0x14c7, 0x14e2, 0x14cc, 0x14cc, 0x14e2, 0x14e2, 0x14e2, 0x14d3, + 0x14cc, 0xc0fc, 0x6882, 0x6b2c, 0x6a30, 0x6d1c, 0x6c20, 0xd99c, + 0x0528, 0x00d6, 0x2805, 0x9c68, 0x6f08, 0x6e0c, 0x00f0, 0x6b08, + 0x6a0c, 0x6d00, 0x6c04, 0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04, + 0x6f08, 0x6e0c, 0x0090, 0x00de, 0x00d6, 0x6864, 0x9084, 0x00ff, + 0x9086, 0x001e, 0x1138, 0x00de, 0x080c, 0x164e, 0x1904, 0x1491, + 0x900e, 0x00f0, 0x00de, 0x080c, 0x0cf1, 0x00de, 0x7b12, 0x7a16, + 0x7d02, 0x7c06, 0x7f0a, 0x7e0e, 0x792a, 0x7000, 0x8000, 0x7002, + 0x683c, 0x9300, 0x683e, 0x6840, 0x9201, 0x6842, 0x700c, 0x9300, + 0x700e, 0x7010, 0x9201, 0x7012, 0x080c, 0x164e, 0x0008, 0x9006, + 0x002e, 0x003e, 0x004e, 0x005e, 0x006e, 0x007e, 0x0005, 0x080c, + 0x0cf1, 0x0026, 0x2001, 0x0105, 0x2003, 0x0010, 0x782b, 0x0004, + 0x7003, 0x0000, 0x7004, 0x2060, 0x00d6, 0x6014, 0x2068, 0x080c, + 0x95d2, 0x0118, 0x6880, 0xc0bd, 0x6882, 0x6020, 0x9086, 0x0006, + 0x1180, 0x2061, 0x0100, 0x62c8, 0x2001, 0x00fa, 0x8001, 0x1df0, + 0x60c8, 0x9206, 0x1dc0, 0x60c4, 0x689a, 0x60c8, 0x6896, 0x7004, + 0x2060, 0x00de, 0x080c, 0x92a4, 0x2001, 0x0200, 0x2003, 0x0040, + 0x080c, 0x7b66, 0x2011, 0x0000, 0x080c, 0x79cc, 0x080c, 0x6e10, + 0x002e, 0x0804, 0x15fd, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x2079, 0x0090, 0x2071, 0x131f, + 0x2b68, 0x6858, 0x2060, 0x792c, 0x782b, 0x0002, 0x9184, 0x0700, + 0x1904, 0x1509, 0x7000, 0x0002, 0x15fd, 0x1560, 0x15d0, 0x15fb, + 0x8001, 0x7002, 0xd19c, 0x1170, 0x8aff, 0x05d0, 0x2009, 0x0001, + 0x080c, 0x148b, 0x0904, 0x15fd, 0x2009, 0x0001, 0x080c, 0x148b, + 0x0804, 0x15fd, 0x782b, 0x0004, 0xd194, 0x0148, 0x6880, 0xc0fc, + 0x6882, 0x8aff, 0x11d8, 0x687c, 0xc0f5, 0x687e, 0x00b8, 0x0026, + 0x0036, 0x6b3c, 0x6a40, 0x7810, 0x682e, 0x931a, 0x7814, 0x6832, + 0x9213, 0x7800, 0x681e, 0x7804, 0x6822, 0x6b3e, 0x6a42, 0x003e, + 0x002e, 0x080c, 0x1666, 0x6880, 0xc0fd, 0x6882, 0x2a00, 0x6816, + 0x2c00, 0x685a, 0x2800, 0x6812, 0x7003, 0x0000, 0x0804, 0x15fd, + 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, 0x2079, 0x0100, + 0x7a14, 0x9284, 0x1984, 0x9085, 0x0012, 0x7816, 0x0036, 0x2019, + 0x1000, 0x8319, 0x090c, 0x0cf1, 0x7820, 0xd0bc, 0x1dd0, 0x003e, + 0x79c8, 0x000e, 0x9102, 0x001e, 0x0006, 0x0016, 0x79c4, 0x000e, + 0x9103, 0x78c6, 0x000e, 0x78ca, 0x9284, 0x1984, 0x9085, 0x0012, + 0x7816, 0x002e, 0x00fe, 0x782b, 0x0008, 0x7003, 0x0000, 0x0468, + 0x8001, 0x7002, 0xd194, 0x0168, 0x782c, 0xd0fc, 0x1904, 0x1553, + 0xd19c, 0x11f8, 0x8aff, 0x0508, 0x2009, 0x0001, 0x080c, 0x148b, + 0x00e0, 0x0026, 0x0036, 0x6b3c, 0x6a40, 0x080c, 0x1666, 0x00d6, + 0x2805, 0x9c68, 0x6064, 0xd09c, 0x1128, 0x6808, 0x931a, 0x680c, + 0x9213, 0x0020, 0x6810, 0x931a, 0x6814, 0x9213, 0x00de, 0x0804, + 0x1583, 0x0804, 0x157f, 0x080c, 0x0cf1, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x001e, 0x000e, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x2071, + 0x131f, 0x7000, 0x9086, 0x0000, 0x05f0, 0x2079, 0x0090, 0x2009, + 0x0207, 0x210c, 0xd194, 0x01a8, 0x2009, 0x020c, 0x210c, 0x9184, + 0x0003, 0x0178, 0x080c, 0xae13, 0x2001, 0x0133, 0x2004, 0x9005, + 0x090c, 0x0cf1, 0x2001, 0x0200, 0x2003, 0x0040, 0x2001, 0x020c, + 0x2102, 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0x9106, + 0x1120, 0x2001, 0x0200, 0x2003, 0x0040, 0x782c, 0xd0fc, 0x09b8, + 0x080c, 0x1543, 0x7000, 0x9086, 0x0000, 0x1988, 0x782b, 0x0004, + 0x782c, 0xd0ac, 0x1de8, 0x2001, 0x0200, 0x2003, 0x0040, 0x782b, + 0x0002, 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x8840, 0x2805, + 0x9005, 0x0110, 0x8a51, 0x0005, 0x6004, 0x9005, 0x0168, 0x685a, + 0x2060, 0x6064, 0x9084, 0x000f, 0x9080, 0x168e, 0x2045, 0x88ff, + 0x090c, 0x0cf1, 0x8a51, 0x0005, 0x2050, 0x0005, 0x8a50, 0x8841, + 0x2805, 0x9005, 0x1190, 0x2c00, 0x9d06, 0x0120, 0x6000, 0x9005, + 0x1108, 0x2d00, 0x2060, 0x685a, 0x6064, 0x9084, 0x000f, 0x9080, + 0x169e, 0x2045, 0x88ff, 0x090c, 0x0cf1, 0x0005, 0x0000, 0x001d, + 0x0021, 0x0025, 0x0029, 0x002d, 0x0031, 0x0035, 0x0000, 0x001b, + 0x0021, 0x0027, 0x002d, 0x0033, 0x0000, 0x0000, 0x0000, 0x1683, + 0x167f, 0x0000, 0x0000, 0x168d, 0x0000, 0x1683, 0x0000, 0x168a, + 0x1687, 0x0000, 0x0000, 0x0000, 0x168d, 0x168a, 0x0000, 0x1685, + 0x1685, 0x0000, 0x0000, 0x168d, 0x0000, 0x1685, 0x0000, 0x168b, + 0x168b, 0x0000, 0x0000, 0x0000, 0x168d, 0x168b, 0x00a6, 0x0096, + 0x0086, 0x6b42, 0x6c3e, 0x6888, 0x9055, 0x0904, 0x173f, 0x2d60, + 0x6064, 0x90cc, 0x000f, 0x99c0, 0x168e, 0x9986, 0x0007, 0x0130, + 0x9986, 0x000e, 0x0118, 0x9986, 0x000f, 0x1120, 0x608c, 0x9422, + 0x6090, 0x931a, 0x2805, 0x9045, 0x1140, 0x0310, 0x0804, 0x173f, + 0x6004, 0x9065, 0x0904, 0x173f, 0x0c18, 0x2805, 0x9005, 0x01a8, + 0x9c68, 0xd99c, 0x1128, 0x6808, 0x9422, 0x680c, 0x931b, 0x0020, + 0x6810, 0x9422, 0x6814, 0x931b, 0x0620, 0x2300, 0x9405, 0x0150, + 0x8a51, 0x0904, 0x173f, 0x8840, 0x0c40, 0x6004, 0x9065, 0x0904, + 0x173f, 0x0830, 0x8a51, 0x0904, 0x173f, 0x8840, 0x2805, 0x9005, + 0x1158, 0x6004, 0x9065, 0x0904, 0x173f, 0x6064, 0x90cc, 0x000f, + 0x99c0, 0x168e, 0x2805, 0x2040, 0x2b68, 0x6880, 0xc0fc, 0x6882, + 0x0458, 0x8422, 0x8420, 0x831a, 0x9399, 0x0000, 0x00d6, 0x2b68, + 0x6c2e, 0x6b32, 0x00de, 0xd99c, 0x1168, 0x6908, 0x2400, 0x9122, + 0x690c, 0x2300, 0x911b, 0x0a0c, 0x0cf1, 0x6800, 0x9420, 0x6804, + 0x9319, 0x0060, 0x6910, 0x2400, 0x9122, 0x6914, 0x2300, 0x911b, + 0x0a0c, 0x0cf1, 0x6800, 0x9420, 0x6804, 0x9319, 0x2b68, 0x6c1e, + 0x6b22, 0x6880, 0xc0fd, 0x6882, 0x2c00, 0x685a, 0x2800, 0x6812, + 0x2a00, 0x6816, 0x000e, 0x000e, 0x000e, 0x9006, 0x0028, 0x008e, + 0x009e, 0x00ae, 0x9085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004, + 0x9084, 0x0007, 0x0002, 0x1753, 0x1543, 0x1754, 0x1755, 0x1758, + 0x175b, 0x1760, 0x1763, 0x0005, 0x0005, 0x080c, 0x1543, 0x0005, + 0x080c, 0x0ee8, 0x0005, 0x080c, 0x1543, 0x080c, 0x0ee8, 0x0005, + 0x080c, 0x0ee8, 0x0005, 0x080c, 0x1543, 0x080c, 0x0ee8, 0x0005, + 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x0260, 0x2069, + 0x1100, 0x7817, 0x0000, 0x789b, 0x0814, 0x78a3, 0x0406, 0x789f, + 0x0410, 0x2009, 0x013b, 0x200b, 0x0400, 0x781b, 0x0002, 0x783b, + 0x001f, 0x7837, 0x0020, 0x7803, 0x1600, 0x012e, 0x0005, 0x2091, + 0x2600, 0x781c, 0xd0a4, 0x190c, 0x18c8, 0x9084, 0x0006, 0x0002, + 0x17a3, 0x1798, 0x5fe9, 0x179a, 0x179c, 0x179e, 0x17a0, 0x17a2, + 0x080c, 0x0cf1, 0x080c, 0x0cf1, 0x0039, 0x0028, 0x0029, 0x0018, + 0x0019, 0x0008, 0x0009, 0x0005, 0x0006, 0x0016, 0x0026, 0x080c, + 0xae13, 0x7930, 0x9184, 0x0003, 0x0178, 0x2001, 0x12eb, 0x2004, + 0x9005, 0x0130, 0x2001, 0x0133, 0x2004, 0x9005, 0x090c, 0x0cf1, + 0x7803, 0x0040, 0x0804, 0x17fc, 0x9184, 0x0014, 0x01f0, 0x6a00, + 0x9286, 0x0003, 0x1108, 0x00a0, 0x080c, 0x5745, 0x1178, 0x2001, + 0x1290, 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, 0x9085, + 0x0001, 0x080c, 0x5789, 0x080c, 0x5682, 0x0010, 0x080c, 0x45d6, + 0x7803, 0x0010, 0x78a0, 0x78a2, 0x00f8, 0x9184, 0x1400, 0x0168, + 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0x131c, 0x080c, 0x1337, + 0x005e, 0x004e, 0x003e, 0x00ee, 0x0078, 0x9184, 0x0140, 0x0118, + 0x7803, 0x0020, 0x0048, 0x9184, 0x8000, 0x0130, 0x080c, 0x205b, + 0x7803, 0x0004, 0x7898, 0x789a, 0x002e, 0x001e, 0x000e, 0x0005, + 0x0016, 0x0026, 0x0036, 0x0046, 0x00e6, 0x00f6, 0x2071, 0x1100, + 0x7128, 0x2001, 0x1282, 0x2102, 0x2001, 0x128a, 0x2102, 0x2001, + 0x013b, 0x2102, 0x2079, 0x0200, 0x9198, 0x0007, 0x831c, 0x831c, + 0x831c, 0x2320, 0x9182, 0x0224, 0x1228, 0x2011, 0x0004, 0x8423, + 0x8423, 0x0088, 0x9182, 0x02d4, 0x1228, 0x2011, 0x0003, 0x8403, + 0x9420, 0x0048, 0x9182, 0x0444, 0x1220, 0x2011, 0x0002, 0x8423, + 0x0010, 0x2011, 0x0001, 0x9482, 0x0110, 0x8002, 0x8020, 0x8301, + 0x9402, 0x0110, 0x0208, 0x8321, 0x8217, 0x8203, 0x9405, 0x2001, + 0x0201, 0x789e, 0x9198, 0x0007, 0x831c, 0x831c, 0x831c, 0x9398, + 0x0003, 0x2320, 0x9182, 0x0204, 0x1228, 0x2011, 0x0004, 0x8423, + 0x8423, 0x0088, 0x9182, 0x02b4, 0x1228, 0x2011, 0x0003, 0x8403, + 0x9420, 0x0048, 0x9182, 0x041c, 0x1220, 0x2011, 0x0002, 0x8423, + 0x0010, 0x2011, 0x0001, 0x9482, 0x010c, 0x8002, 0x8020, 0x8301, + 0x9402, 0x0110, 0x0208, 0x8321, 0x8217, 0x8203, 0x9405, 0x2001, + 0x0200, 0x78a2, 0x9198, 0x0007, 0x831c, 0x831c, 0x831c, 0x9398, + 0x0005, 0x2320, 0x9182, 0x0204, 0x1230, 0x2011, 0x0008, 0x8423, + 0x8423, 0x8423, 0x0488, 0x9182, 0x024c, 0x1240, 0x2011, 0x0007, + 0x8403, 0x8003, 0x9400, 0x9400, 0x9420, 0x0430, 0x9182, 0x02bc, + 0x1238, 0x2011, 0x0006, 0x8403, 0x8003, 0x9400, 0x9420, 0x00e0, + 0x9182, 0x034c, 0x1230, 0x2011, 0x0005, 0x8403, 0x8003, 0x9420, + 0x0098, 0x9182, 0x042c, 0x1228, 0x2011, 0x0004, 0x8423, 0x8423, + 0x0058, 0x9182, 0x059c, 0x1228, 0x2011, 0x0003, 0x8403, 0x9420, + 0x0018, 0x2011, 0x0002, 0x8423, 0x9482, 0x0228, 0x8002, 0x8020, + 0x8301, 0x9402, 0x0110, 0x0208, 0x8321, 0x8217, 0x8203, 0x9405, + 0x789a, 0x00fe, 0x00ee, 0x004e, 0x003e, 0x002e, 0x001e, 0x0005, + 0x7938, 0x080c, 0x0cf1, 0x0126, 0x2091, 0x2800, 0x2061, 0x0100, + 0x2071, 0x1100, 0x080c, 0x1f80, 0x6054, 0x8004, 0x8004, 0x8004, + 0x8004, 0x9084, 0x000c, 0x6150, 0x918c, 0xfff3, 0x9105, 0x6052, + 0x6050, 0x9084, 0xfbff, 0x9085, 0x2000, 0x6052, 0x2009, 0x12bd, + 0x2011, 0x12be, 0x6358, 0x939c, 0x38f0, 0x2320, 0x080c, 0x1fc4, + 0x1238, 0x939d, 0x4003, 0x94a5, 0x8603, 0x230a, 0x2412, 0x0030, + 0x939d, 0x0203, 0x94a5, 0x8603, 0x230a, 0x2412, 0x9006, 0x080c, + 0x1faf, 0x9006, 0x080c, 0x1f92, 0x20a9, 0x0012, 0x1d04, 0x1906, + 0x2091, 0x6000, 0x1f04, 0x1906, 0x602f, 0x0100, 0x602f, 0x0000, + 0x6050, 0x9085, 0x0400, 0x9084, 0xdfff, 0x6052, 0x6024, 0x6026, + 0x080c, 0x1c83, 0x2009, 0x00ef, 0x6132, 0x6136, 0x080c, 0x1c93, + 0x60e7, 0x0000, 0x61ea, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, + 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x049f, 0x60bb, + 0x0000, 0x20a9, 0x0018, 0x60bf, 0x0000, 0x1f04, 0x1933, 0x60bb, + 0x0000, 0x60bf, 0x0108, 0x60bf, 0x0012, 0x60bf, 0x0320, 0x60bf, + 0x0018, 0x601b, 0x001e, 0x601f, 0x001e, 0x600f, 0x006b, 0x602b, + 0x402f, 0x012e, 0x0005, 0x00f6, 0x2079, 0x0140, 0x78c3, 0x0080, + 0x78c3, 0x0083, 0x78c3, 0x0000, 0x00fe, 0x0005, 0x2001, 0x1131, + 0x2003, 0x0000, 0x2001, 0x1130, 0x2003, 0x0001, 0x0005, 0x0126, + 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x6124, 0x9184, 0x5e2c, + 0x1118, 0x9184, 0x0007, 0x002a, 0x9195, 0x0004, 0x9284, 0x0007, + 0x0002, 0x1993, 0x1979, 0x197c, 0x197f, 0x1984, 0x1986, 0x198a, + 0x198e, 0x080c, 0x677e, 0x00b8, 0x080c, 0x684f, 0x00a0, 0x080c, + 0x684f, 0x080c, 0x677e, 0x0078, 0x0099, 0x0068, 0x080c, 0x677e, + 0x0079, 0x0048, 0x080c, 0x684f, 0x0059, 0x0028, 0x080c, 0x684f, + 0x080c, 0x677e, 0x0029, 0x002e, 0x001e, 0x000e, 0x012e, 0x0005, + 0x6124, 0xd19c, 0x1904, 0x1bbd, 0xd1f4, 0x0110, 0x080c, 0x0cf1, + 0x080c, 0x5745, 0x0578, 0x7000, 0x9086, 0x0003, 0x0198, 0x6024, + 0x9084, 0x1800, 0x0178, 0x080c, 0x576b, 0x0118, 0x080c, 0x5757, + 0x1148, 0x6027, 0x0020, 0x6043, 0x0000, 0x2001, 0x128f, 0x2003, + 0xaaaa, 0x0458, 0x080c, 0x576b, 0x15d0, 0x6024, 0x9084, 0x1800, + 0x1108, 0x04a8, 0x2001, 0x128f, 0x2003, 0xaaaa, 0x2001, 0x1290, + 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, 0x080c, 0x5682, + 0x0804, 0x1bbd, 0xd1ac, 0x1518, 0x6024, 0xd0dc, 0x1170, 0xd0e4, + 0x1188, 0xd0d4, 0x11a0, 0xd0cc, 0x0130, 0x7088, 0x9086, 0x0028, + 0x1110, 0x080c, 0x58e5, 0x0804, 0x1bbd, 0x2001, 0x1290, 0x2003, + 0x0000, 0x0048, 0x2001, 0x1290, 0x2003, 0x0002, 0x0020, 0x080c, + 0x5857, 0x0804, 0x1bbd, 0x080c, 0x597e, 0x0804, 0x1bbd, 0xd1ac, + 0x0904, 0x1af0, 0x080c, 0x5745, 0x11d8, 0x6027, 0x0020, 0x0006, + 0x0026, 0x0036, 0x080c, 0x5761, 0x1170, 0x2001, 0x1290, 0x2003, + 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, 0x080c, 0x5682, 0x003e, + 0x002e, 0x000e, 0x0005, 0x003e, 0x002e, 0x000e, 0x080c, 0x571c, + 0x0016, 0x0046, 0x00c6, 0x644c, 0x9486, 0xf0f0, 0x1138, 0x2061, + 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74ca, 0x948c, + 0xff00, 0x7034, 0xd084, 0x0178, 0x9186, 0xf800, 0x1160, 0x7038, + 0xd084, 0x1148, 0xc085, 0x703a, 0x0036, 0x2418, 0x2011, 0x8016, + 0x080c, 0x37dc, 0x003e, 0x9196, 0xff00, 0x05b8, 0x7050, 0x9084, + 0x00ff, 0x810f, 0x9116, 0x0588, 0x7130, 0xd184, 0x1570, 0x2011, + 0x1153, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011, 0x1153, + 0x2214, 0xd2ac, 0x1510, 0x6240, 0x9294, 0x0010, 0x0130, 0x6248, + 0x9294, 0xff00, 0x9296, 0xff00, 0x01c0, 0x7030, 0xd08c, 0x0904, + 0x1ac6, 0x7034, 0xd08c, 0x1140, 0x2001, 0x110c, 0x200c, 0xd1ac, + 0x1904, 0x1ac6, 0xc1ad, 0x2102, 0x0036, 0x73c8, 0x2011, 0x8013, + 0x080c, 0x37dc, 0x003e, 0x0804, 0x1ac6, 0x7034, 0xd08c, 0x1140, + 0x2001, 0x110c, 0x200c, 0xd1ac, 0x1904, 0x1ac6, 0xc1ad, 0x2102, + 0x0036, 0x73c8, 0x2011, 0x8013, 0x080c, 0x37dc, 0x003e, 0x7130, + 0xc185, 0x7132, 0x2011, 0x1153, 0x220c, 0xd1a4, 0x01f0, 0x0016, + 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x66d5, 0x2019, 0x000e, + 0x00c6, 0x2061, 0x0000, 0x080c, 0xaa50, 0x00ce, 0x9484, 0x00ff, + 0x9080, 0x26c1, 0x200d, 0x918c, 0xff00, 0x810f, 0x8127, 0x9006, + 0x2009, 0x000e, 0x080c, 0xaaca, 0x001e, 0xd1ac, 0x1148, 0x0016, + 0x2009, 0x0000, 0x2019, 0x0004, 0x080c, 0x2582, 0x001e, 0x0070, + 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000, 0x080c, 0x4b58, 0x1110, + 0x080c, 0x472d, 0x8108, 0x1f04, 0x1abd, 0x015e, 0x00ce, 0x004e, + 0x2011, 0x0003, 0x080c, 0x79c2, 0x2011, 0x0002, 0x080c, 0x79cc, + 0x080c, 0x78b3, 0x080c, 0x65cf, 0x0036, 0x2019, 0x0000, 0x080c, + 0x7936, 0x003e, 0x60e3, 0x0000, 0x001e, 0x2001, 0x1100, 0x2014, + 0x9296, 0x0004, 0x1128, 0xd19c, 0x1118, 0x6228, 0xc29d, 0x622a, + 0x2003, 0x0001, 0x2001, 0x1122, 0x2003, 0x0000, 0x6027, 0x0020, + 0xd194, 0x0904, 0x1bbd, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x1b6e, + 0x080c, 0x65cf, 0x080c, 0x7721, 0x6027, 0x0004, 0x00f6, 0x2019, + 0x12e5, 0x2304, 0x907d, 0x05f0, 0x7804, 0x9086, 0x0032, 0x15d0, + 0x00d6, 0x00c6, 0x00e6, 0x2069, 0x0140, 0x7810, 0x685e, 0x7808, + 0x685a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0, 0x6043, + 0x0000, 0x2001, 0x003c, 0x8001, 0x1df0, 0x6803, 0x1000, 0x6803, + 0x0000, 0x2001, 0x001e, 0x8001, 0x0240, 0x20a9, 0x0009, 0x080c, + 0x2036, 0x6904, 0xd1dc, 0x1128, 0x0cb0, 0x6803, 0x1000, 0x6803, + 0x0000, 0x080c, 0x6c56, 0x080c, 0x6d42, 0x7814, 0x2070, 0x7067, + 0x0103, 0x2f60, 0x080c, 0x7f1e, 0x00ee, 0x00ce, 0x00de, 0x00fe, + 0x001e, 0x0005, 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0x9084, + 0x4000, 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, + 0x2061, 0x12dc, 0x6028, 0x909a, 0x00c8, 0x1238, 0x8000, 0x602a, + 0x00ce, 0x080c, 0x76fd, 0x0804, 0x1bbc, 0x2061, 0x0100, 0x62c0, + 0x080c, 0x7e9f, 0x2019, 0x12e5, 0x2304, 0x9065, 0x0120, 0x2009, + 0x0027, 0x080c, 0x7f4e, 0x00ce, 0x0804, 0x1bbc, 0xd2bc, 0x0904, + 0x1bbc, 0x080c, 0x65dc, 0x6014, 0x9084, 0x1984, 0x9085, 0x0010, + 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, 0x0140, 0x6804, 0x9084, + 0x4000, 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, + 0x2061, 0x12dc, 0x6044, 0x909a, 0x00c8, 0x12f0, 0x8000, 0x6046, + 0x603c, 0x00ce, 0x9005, 0x0540, 0x2009, 0x07d0, 0x080c, 0x65d4, + 0x9080, 0x0008, 0x2004, 0x9086, 0x0006, 0x1138, 0x6114, 0x918c, + 0x1984, 0x918d, 0x0012, 0x6116, 0x00b8, 0x6114, 0x918c, 0x1984, + 0x918d, 0x0016, 0x6116, 0x0080, 0x0036, 0x2019, 0x0001, 0x080c, + 0x7936, 0x003e, 0x2019, 0x12eb, 0x2304, 0x9065, 0x0120, 0x2009, + 0x004f, 0x080c, 0x7f4e, 0x00ce, 0x001e, 0xd19c, 0x0904, 0x1c32, + 0x0016, 0x0156, 0x6027, 0x0008, 0x6050, 0x9085, 0x0040, 0x6052, + 0x6050, 0x9084, 0xfbcf, 0x6052, 0x080c, 0x2055, 0x9085, 0x2000, + 0x6052, 0x20a9, 0x0012, 0x1d04, 0x1bd3, 0x2091, 0x6000, 0x1f04, + 0x1bd3, 0x6050, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x6052, 0x20a9, + 0x0028, 0xa001, 0x1f04, 0x1be1, 0x6150, 0x9185, 0x1400, 0x6052, + 0x20a9, 0x0366, 0x1d04, 0x1bea, 0x2091, 0x6000, 0x6020, 0xd09c, + 0x1130, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x04d8, 0x080c, + 0x201f, 0x1f04, 0x1bea, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, + 0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, 0x79c2, + 0x2011, 0x0002, 0x080c, 0x79cc, 0x080c, 0x78b3, 0x080c, 0x65cf, + 0x0036, 0x2019, 0x0000, 0x080c, 0x7936, 0x003e, 0x60e3, 0x0000, + 0x080c, 0xadf2, 0x080c, 0xae0d, 0x2001, 0x1172, 0x2004, 0xd0fc, + 0x1120, 0x9085, 0x0001, 0x080c, 0x5789, 0x2001, 0x0140, 0x2003, + 0x0000, 0x2001, 0x1100, 0x2003, 0x0004, 0x6027, 0x0008, 0x080c, + 0x0b34, 0x001e, 0x918c, 0xffd0, 0x6126, 0x0005, 0x0006, 0x0016, + 0x0026, 0x0036, 0x00e6, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2071, + 0x1100, 0x71c0, 0x70c2, 0x9116, 0x01e0, 0x81ff, 0x0128, 0x2011, + 0x8011, 0x080c, 0x37dc, 0x00a8, 0x2011, 0x8012, 0x080c, 0x37dc, + 0x2001, 0x1172, 0x2004, 0xd0fc, 0x1160, 0x00c6, 0x080c, 0x1cde, + 0x2061, 0x0100, 0x2019, 0x0028, 0x2009, 0x0000, 0x080c, 0x2582, + 0x00ce, 0x012e, 0x00fe, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, + 0x0005, 0x2028, 0x918c, 0x00ff, 0x2130, 0x9094, 0xff00, 0x1110, + 0x81ff, 0x0118, 0x080c, 0x6215, 0x0038, 0x9080, 0x26c1, 0x200d, + 0x918c, 0xff00, 0x810f, 0x9006, 0x0005, 0x9080, 0x26c1, 0x200d, + 0x918c, 0x00ff, 0x0005, 0x00d6, 0x2069, 0x0140, 0x2001, 0x1114, + 0x2003, 0x00ef, 0x20a9, 0x0010, 0x9006, 0x6852, 0x6856, 0x1f04, + 0x1c8e, 0x00de, 0x0005, 0x0006, 0x00d6, 0x0026, 0x2069, 0x0140, + 0x2001, 0x1114, 0x2102, 0x8114, 0x8214, 0x8214, 0x8214, 0x20a9, + 0x0010, 0x6853, 0x0000, 0x9006, 0x82ff, 0x1128, 0x9184, 0x000f, + 0x9080, 0xb1a7, 0x2005, 0x6856, 0x8211, 0x1f04, 0x1ca3, 0x002e, + 0x00de, 0x000e, 0x0005, 0x00c6, 0x2061, 0x1100, 0x6030, 0x0110, + 0xc09d, 0x0008, 0xc09c, 0x6032, 0x00ce, 0x0005, 0x0156, 0x00d6, + 0x0026, 0x0016, 0x0006, 0x2069, 0x0140, 0x6980, 0x9116, 0x0180, + 0x9112, 0x1230, 0x8212, 0x8210, 0x22a8, 0x2001, 0x0402, 0x0018, + 0x22a8, 0x2001, 0x0404, 0x680e, 0x1f04, 0x1cd3, 0x680f, 0x0000, + 0x000e, 0x001e, 0x002e, 0x00de, 0x015e, 0x0005, 0x2001, 0x1153, + 0x2004, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0x9006, 0x0046, 0x2020, + 0x2009, 0x002e, 0x080c, 0xaaca, 0x004e, 0x0005, 0x00f6, 0x0016, + 0x0026, 0x2079, 0x0140, 0x78c4, 0xd0dc, 0x0904, 0x1d51, 0x2009, + 0x0100, 0x210c, 0x918a, 0x0007, 0x0610, 0x9084, 0x0700, 0x908e, + 0x0600, 0x1128, 0x2011, 0x4000, 0x2009, 0x0000, 0x0400, 0x908e, + 0x0500, 0x1128, 0x2011, 0x8000, 0x2009, 0x0000, 0x00c0, 0x908e, + 0x0400, 0x1128, 0x2011, 0x0000, 0x2009, 0x0001, 0x0080, 0x908e, + 0x0300, 0x15b8, 0x2011, 0x0000, 0x2009, 0x0002, 0x0040, 0x9084, + 0x0700, 0x908e, 0x0300, 0x1568, 0x2011, 0x0030, 0x0038, 0x2300, + 0x9080, 0x0020, 0x2018, 0x2300, 0x080c, 0x66ff, 0x2200, 0x8007, + 0x9085, 0x004c, 0x78c2, 0x2009, 0x0227, 0x210c, 0x810f, 0x918c, + 0x00ff, 0x810c, 0x2200, 0x9100, 0x2009, 0x0226, 0x210c, 0x810f, + 0x918c, 0x00ff, 0x810c, 0x9100, 0x2009, 0x0138, 0x200a, 0x080c, + 0x5745, 0x1118, 0x2009, 0x1280, 0x200a, 0x002e, 0x001e, 0x00fe, + 0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126, 0x2091, 0x2800, 0x0006, + 0x0016, 0x0026, 0x2001, 0x0170, 0x200c, 0x8000, 0x2014, 0x9184, + 0x0003, 0x0110, 0x0804, 0x0cf1, 0x002e, 0x001e, 0x000e, 0x012e, + 0x0005, 0x2001, 0x0171, 0x2004, 0xd0dc, 0x0168, 0x2001, 0x0170, + 0x200c, 0x918c, 0x00ff, 0x918e, 0x004c, 0x1128, 0x200c, 0x918c, + 0xff00, 0x810f, 0x0010, 0x2009, 0x0000, 0x2001, 0x0227, 0x2004, + 0x8007, 0x9084, 0x00ff, 0x8004, 0x9108, 0x2001, 0x0226, 0x2004, + 0x8007, 0x9084, 0x00ff, 0x8004, 0x9108, 0x0005, 0x0018, 0x000c, + 0x0018, 0x0020, 0x1000, 0x0800, 0x1000, 0x1800, 0x0156, 0x0006, + 0x0016, 0x0026, 0x00e6, 0x2001, 0x12b0, 0x2004, 0x908a, 0x0007, + 0x1210, 0x004b, 0x0010, 0x080c, 0x0cf1, 0x00ee, 0x002e, 0x001e, + 0x000e, 0x015e, 0x0005, 0x1db2, 0x1dd1, 0x1df6, 0x1df9, 0x1e23, + 0x1e26, 0x1e29, 0x2001, 0x0001, 0x080c, 0x1c36, 0x080c, 0x201a, + 0x2001, 0x12b2, 0x2003, 0x0000, 0x7828, 0x9084, 0xe1d7, 0x782a, + 0x2001, 0x0000, 0x20a9, 0x0009, 0x080c, 0x1fd8, 0x2001, 0x12b0, + 0x2003, 0x0006, 0x2009, 0x001e, 0x2011, 0x1e2a, 0x080c, 0x65e1, + 0x0005, 0x2009, 0x12b5, 0x200b, 0x0000, 0x2001, 0x12ba, 0x2003, + 0x0036, 0x2001, 0x12b9, 0x2003, 0x002a, 0x2001, 0x12b2, 0x2003, + 0x0001, 0x2001, 0x0000, 0x080c, 0x1f92, 0x2001, 0xffff, 0x20a9, + 0x0009, 0x080c, 0x1fd8, 0x2001, 0x12b0, 0x2003, 0x0006, 0x2009, + 0x001e, 0x2011, 0x1e2a, 0x080c, 0x65e1, 0x0005, 0x080c, 0x0cf1, + 0x0005, 0x2001, 0x12ba, 0x2003, 0x0036, 0x2001, 0x12b2, 0x2003, + 0x0003, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0004, 0x0118, 0x2001, + 0x0000, 0x0010, 0x2001, 0x0001, 0x080c, 0x1f92, 0x2001, 0x12b6, + 0x2003, 0x0000, 0x2001, 0xffff, 0x20a9, 0x0009, 0x080c, 0x1fd8, + 0x2001, 0x12b0, 0x2003, 0x0006, 0x2009, 0x001e, 0x2011, 0x1e2a, + 0x080c, 0x65e1, 0x0005, 0x080c, 0x0cf1, 0x0005, 0x080c, 0x0cf1, + 0x0005, 0x0005, 0x0006, 0x0016, 0x0026, 0x00e6, 0x00f6, 0x0156, + 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x2001, 0x12b2, 0x2004, + 0x908a, 0x0007, 0x1210, 0x005b, 0x0010, 0x080c, 0x0cf1, 0x012e, + 0x015e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, 0x0005, 0x1e4e, + 0x1e6e, 0x1eaf, 0x1edf, 0x1f03, 0x1f13, 0x1f16, 0x080c, 0x1fcc, + 0x11b0, 0x7850, 0x9084, 0xefff, 0x7852, 0x2009, 0x12b8, 0x2104, + 0x7a38, 0x9294, 0x0005, 0x9296, 0x0004, 0x0110, 0xc08d, 0x0008, + 0xc085, 0x200a, 0x2001, 0x12b0, 0x2003, 0x0001, 0x0030, 0x080c, + 0x1f3e, 0x2001, 0xffff, 0x080c, 0x1dc2, 0x0005, 0x080c, 0x1f19, + 0x05e8, 0x2009, 0x12b9, 0x2104, 0x8001, 0x200a, 0x080c, 0x1fcc, + 0x1178, 0x7850, 0x9084, 0xefff, 0x7852, 0x7a38, 0x9294, 0x0005, + 0x9296, 0x0005, 0x0520, 0x2009, 0x12b8, 0x2104, 0xc085, 0x200a, + 0x2009, 0x12b5, 0x2104, 0x8000, 0x200a, 0x9086, 0x0005, 0x0118, + 0x080c, 0x1f22, 0x00c8, 0x200b, 0x0000, 0x7a38, 0x9294, 0x0006, + 0x9296, 0x0004, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, + 0x080c, 0x1faf, 0x2001, 0x12b2, 0x2003, 0x0002, 0x0028, 0x2001, + 0x12b0, 0x2003, 0x0003, 0x0010, 0x080c, 0x1de5, 0x0005, 0x080c, + 0x1f19, 0x0560, 0x2009, 0x12b9, 0x2104, 0x8001, 0x200a, 0x080c, + 0x1fcc, 0x1168, 0x7850, 0x9084, 0xefff, 0x7852, 0x2001, 0x12b0, + 0x2003, 0x0003, 0x2001, 0x12b1, 0x2003, 0x0000, 0x00b8, 0x2009, + 0x12b9, 0x2104, 0x9005, 0x1118, 0x080c, 0x1f63, 0x0010, 0x080c, + 0x1f30, 0x080c, 0x1f22, 0x2009, 0x12b5, 0x200b, 0x0000, 0x2001, + 0x12b2, 0x2003, 0x0001, 0x080c, 0x1de5, 0x0000, 0x0005, 0x04c9, + 0x0508, 0x080c, 0x1fcc, 0x11b8, 0x7850, 0x9084, 0xefff, 0x7852, + 0x2009, 0x12b6, 0x2104, 0x8000, 0x200a, 0x9086, 0x0007, 0x0108, + 0x0078, 0x2001, 0x12bb, 0x2003, 0x000a, 0x2009, 0x12b8, 0x2104, + 0xc0fd, 0x200a, 0x0038, 0x0431, 0x2001, 0x12b2, 0x2003, 0x0004, + 0x080c, 0x1e12, 0x0005, 0x00a9, 0x0168, 0x080c, 0x1fcc, 0x1138, + 0x7850, 0x9084, 0xefff, 0x7852, 0x080c, 0x1dfd, 0x0018, 0x0091, + 0x080c, 0x1e12, 0x0005, 0x080c, 0x0cf1, 0x0005, 0x080c, 0x0cf1, + 0x0005, 0x2009, 0x12ba, 0x2104, 0x8001, 0x200a, 0x1110, 0x080c, + 0x1f80, 0x0005, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0005, 0x0118, + 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, 0x080c, 0x1faf, 0x0005, + 0x7a38, 0x9294, 0x0006, 0x9296, 0x0006, 0x0118, 0x2001, 0x0000, + 0x0010, 0x2001, 0x0001, 0x080c, 0x1f92, 0x0005, 0x2009, 0x12b5, + 0x2104, 0x8000, 0x200a, 0x9086, 0x0005, 0x0108, 0x0070, 0x200b, + 0x0000, 0x7a38, 0x9294, 0x0006, 0x9296, 0x0006, 0x0118, 0x2001, + 0x0000, 0x0010, 0x2001, 0x0001, 0x04e9, 0x7a38, 0x9294, 0x0005, + 0x9296, 0x0005, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, + 0x080c, 0x1faf, 0x0005, 0x0086, 0x2001, 0x12b8, 0x2004, 0x9084, + 0x7fff, 0x090c, 0x0cf1, 0x2009, 0x12b7, 0x2144, 0x8846, 0x280a, + 0x9844, 0x0dd8, 0xd08c, 0x1120, 0xd084, 0x1128, 0x080c, 0x0cf1, + 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, 0x00a1, 0x008e, 0x0005, + 0x0006, 0x0156, 0x2001, 0x12b0, 0x20a9, 0x0009, 0x2003, 0x0000, + 0x8000, 0x1f04, 0x1f86, 0x2001, 0x12b7, 0x2003, 0x8000, 0x015e, + 0x000e, 0x0005, 0x00f6, 0x2079, 0x0100, 0x9085, 0x0000, 0x0158, + 0x7838, 0x9084, 0xfff9, 0x9085, 0x0004, 0x783a, 0x2009, 0x12bd, + 0x210c, 0x795a, 0x0050, 0x7838, 0x9084, 0xfffb, 0x9085, 0x0006, + 0x783a, 0x2009, 0x12be, 0x210c, 0x795a, 0x00fe, 0x0005, 0x00f6, + 0x2079, 0x0100, 0x9085, 0x0000, 0x0138, 0x7838, 0x9084, 0xfffa, + 0x9085, 0x0004, 0x783a, 0x0030, 0x7838, 0x9084, 0xfffb, 0x9085, + 0x0005, 0x783a, 0x00fe, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004, + 0x9082, 0x0007, 0x000e, 0x0005, 0x0156, 0x20a9, 0x0064, 0x7820, + 0x080c, 0x2055, 0xd09c, 0x1110, 0x1f04, 0x1fcf, 0x015e, 0x0005, + 0x0126, 0x0016, 0x0006, 0x2091, 0x8000, 0x7850, 0x9085, 0x0040, + 0x7852, 0x7850, 0x9084, 0xfbcf, 0x7852, 0x080c, 0x2055, 0x9085, + 0x2000, 0x7852, 0x000e, 0x2008, 0x9186, 0x0000, 0x1118, 0x783b, + 0x0007, 0x0090, 0x9186, 0x0001, 0x1118, 0x783b, 0x0006, 0x0060, + 0x9186, 0x0002, 0x1118, 0x783b, 0x0005, 0x0030, 0x9186, 0x0003, + 0x1118, 0x783b, 0x0004, 0x0000, 0x0006, 0x1d04, 0x2005, 0x2091, + 0x6000, 0x1f04, 0x2005, 0x7850, 0x9085, 0x0400, 0x9084, 0xdfbf, + 0x7852, 0x080c, 0x2055, 0x9085, 0x1000, 0x7852, 0x000e, 0x001e, + 0x012e, 0x0005, 0x7850, 0x9084, 0xffcf, 0x7852, 0x0005, 0x0006, + 0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd0ac, + 0x1100, 0x7854, 0xd08c, 0x1110, 0x1f04, 0x2029, 0x00fe, 0x015e, + 0x000e, 0x0005, 0x7820, 0x0409, 0xd09c, 0x0005, 0x1d04, 0x2036, + 0x2091, 0x6000, 0x1f04, 0x2036, 0x0005, 0x0006, 0x2001, 0x12bc, + 0x2004, 0x9086, 0x0000, 0x000e, 0x0005, 0x0006, 0x2001, 0x12bc, + 0x2004, 0x9086, 0x0001, 0x000e, 0x0005, 0x0006, 0x2001, 0x12bc, + 0x2004, 0x9086, 0x0002, 0x000e, 0x0005, 0xa001, 0xa001, 0xa001, + 0xa001, 0xa001, 0x0005, 0x2009, 0x0171, 0x2104, 0xd0dc, 0x0140, + 0x2009, 0x0170, 0x2104, 0x200b, 0x0080, 0xa001, 0xa001, 0x200a, + 0x0005, 0x0036, 0x0046, 0x2001, 0x0141, 0x200c, 0x918c, 0xff00, + 0x9186, 0x2000, 0x0118, 0x9186, 0x0100, 0x1560, 0x2009, 0x017f, + 0x200b, 0x00a2, 0x2009, 0x0169, 0x2019, 0x0160, 0x2324, 0x2011, + 0x0003, 0x2104, 0x9084, 0x0007, 0x9086, 0x0003, 0x11b8, 0x2304, + 0x9402, 0x02a0, 0x1d98, 0x8211, 0x1da0, 0x84ff, 0x0170, 0x2001, + 0x0141, 0x200c, 0x918c, 0xff00, 0x9186, 0x0100, 0x0130, 0x2009, + 0x110c, 0x2104, 0xc0dd, 0x200a, 0x0008, 0x0419, 0x2001, 0x017f, + 0x2003, 0x0000, 0x004e, 0x003e, 0x0005, 0x2001, 0x110c, 0x2004, + 0xd0dc, 0x01b0, 0x2001, 0x0160, 0x2004, 0x9005, 0x0140, 0x2001, + 0x0141, 0x2004, 0x9084, 0xff00, 0x9086, 0x0100, 0x1148, 0x0126, + 0x2091, 0x8000, 0x0016, 0x0026, 0x0021, 0x002e, 0x001e, 0x012e, + 0x0005, 0x00c6, 0x2061, 0x0100, 0x6014, 0x0006, 0x2001, 0x0161, + 0x2003, 0x0000, 0x6017, 0x0018, 0xa001, 0xa001, 0x602f, 0x0008, + 0x6104, 0x918e, 0x0010, 0x6106, 0x918e, 0x0010, 0x6106, 0x6017, + 0x0040, 0x2001, 0x0140, 0x2003, 0x1000, 0x2003, 0x0000, 0x001e, + 0x9184, 0x0003, 0x01c0, 0x0036, 0x2019, 0x0141, 0x2304, 0x9084, + 0xff00, 0x9086, 0x0800, 0x1dd0, 0x919c, 0xffe4, 0x9184, 0x0001, + 0x0118, 0x9385, 0x0009, 0x6016, 0x9184, 0x0002, 0x0118, 0x9385, + 0x0012, 0x6016, 0x003e, 0x2001, 0x110c, 0x200c, 0xc1dc, 0x2102, + 0x00ce, 0x0005, 0x23cc, 0x23cc, 0x2192, 0x219e, 0x21aa, 0x21b6, + 0x21c2, 0x21d0, 0x21de, 0x21ea, 0x21f6, 0x2204, 0x2212, 0x2220, + 0x222e, 0x223e, 0x2250, 0x2250, 0x225c, 0x225c, 0x226a, 0x226a, + 0x2288, 0x2288, 0x22a8, 0x22a8, 0x2278, 0x2278, 0x2298, 0x2298, + 0x22b6, 0x22b6, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x22c8, 0x22c8, 0x22d4, 0x22d4, 0x22e2, 0x22e2, + 0x22f0, 0x22f0, 0x2300, 0x2300, 0x230e, 0x230e, 0x231e, 0x231e, + 0x232e, 0x232e, 0x2340, 0x2340, 0x234e, 0x234e, 0x235e, 0x235e, + 0x2380, 0x2380, 0x23a2, 0x23a2, 0x236e, 0x236e, 0x2391, 0x2391, + 0x23b1, 0x23b1, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, 0x224e, + 0x224e, 0x224e, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x195f, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x195f, + 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x1745, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1745, + 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x195f, 0x080c, 0x1745, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x195f, 0x080c, 0x1745, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1787, + 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x195f, + 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x195f, 0x080c, 0x1787, + 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x1745, 0x080c, 0x1787, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1745, 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x195f, + 0x080c, 0x1745, 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x195f, + 0x080c, 0x1745, 0x080c, 0x1787, 0x0804, 0x23c4, 0xa001, 0x0cf0, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x0fcc, 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x195f, 0x080c, 0x0fcc, + 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x1745, 0x080c, 0x0fcc, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x195f, 0x080c, 0x0fcc, 0x080c, 0x1787, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x195f, 0x080c, 0x1745, 0x080c, 0x0fcc, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1745, 0x080c, 0x0fcc, 0x080c, 0x1787, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x0fcc, 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x195f, + 0x080c, 0x1745, 0x080c, 0x0fcc, 0x080c, 0x1787, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1d54, 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, + 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1d54, 0x080c, 0x195f, + 0x0804, 0x23c4, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x1d54, 0x080c, 0x1745, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1d54, 0x080c, 0x195f, 0x080c, 0x1745, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1d54, 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1d54, + 0x080c, 0x195f, 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1d54, + 0x080c, 0x1745, 0x080c, 0x1787, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1d54, + 0x080c, 0x195f, 0x080c, 0x1745, 0x080c, 0x1787, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1d54, 0x080c, 0x0fcc, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1d54, + 0x080c, 0x195f, 0x080c, 0x0fcc, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1d54, + 0x080c, 0x1745, 0x080c, 0x0fcc, 0x0804, 0x23c4, 0x0106, 0x0006, + 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x1d54, + 0x080c, 0x195f, 0x080c, 0x0fcc, 0x080c, 0x1787, 0x0804, 0x23c4, + 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, + 0x080c, 0x1d54, 0x080c, 0x195f, 0x080c, 0x1745, 0x080c, 0x0fcc, + 0x0498, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, + 0x0156, 0x080c, 0x1d54, 0x080c, 0x1745, 0x080c, 0x0fcc, 0x080c, + 0x1787, 0x0410, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, + 0x0146, 0x0156, 0x080c, 0x1d54, 0x080c, 0x0fcc, 0x080c, 0x1787, + 0x0098, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, + 0x0156, 0x080c, 0x1d54, 0x080c, 0x195f, 0x080c, 0x1745, 0x080c, + 0x0fcc, 0x080c, 0x1787, 0x0000, 0x015e, 0x014e, 0x013e, 0x01de, + 0x01ce, 0x012e, 0x000e, 0x010e, 0x000d, 0x00c6, 0x0026, 0x0046, + 0x2021, 0x0000, 0x080c, 0x4de0, 0x1904, 0x24aa, 0x72cc, 0x2001, + 0x128f, 0x2004, 0x9005, 0x1110, 0xd29c, 0x0148, 0xd284, 0x1138, + 0xd2bc, 0x1904, 0x24aa, 0x080c, 0x24ae, 0x0804, 0x24aa, 0xd2cc, + 0x1904, 0x24aa, 0x080c, 0x5745, 0x1120, 0x709b, 0xffff, 0x0804, + 0x24aa, 0xd294, 0x0120, 0x709b, 0xffff, 0x0804, 0x24aa, 0x2001, + 0x1114, 0x203c, 0x7284, 0xd284, 0x0904, 0x244c, 0xd28c, 0x1904, + 0x244c, 0x0036, 0x7398, 0x938e, 0xffff, 0x1110, 0x2019, 0x0001, + 0x8314, 0x92e0, 0x1580, 0x2c04, 0x938c, 0x0001, 0x0120, 0x9084, + 0xff00, 0x8007, 0x0010, 0x9084, 0x00ff, 0x970e, 0x0560, 0x908e, + 0x0000, 0x0548, 0x908e, 0x00ff, 0x1150, 0x7230, 0xd284, 0x1538, + 0x7284, 0xc28d, 0x7286, 0x709b, 0xffff, 0x003e, 0x0428, 0x2009, + 0x0000, 0x080c, 0x1c69, 0x080c, 0x4b03, 0x11b8, 0x6004, 0x9084, + 0x00ff, 0x9086, 0x0006, 0x1150, 0x7030, 0xd08c, 0x0118, 0x6000, + 0xd0bc, 0x0120, 0x080c, 0x24c1, 0x0140, 0x0028, 0x080c, 0x25ec, + 0x080c, 0x24ef, 0x0110, 0x8318, 0x0818, 0x739a, 0x0010, 0x709b, + 0xffff, 0x003e, 0x0804, 0x24aa, 0x9780, 0x26c1, 0x203d, 0x97bc, + 0xff00, 0x873f, 0x2041, 0x007e, 0x7098, 0x9096, 0xffff, 0x1120, + 0x2009, 0x0000, 0x28a8, 0x0050, 0x9812, 0x0220, 0x2008, 0x9802, + 0x20a8, 0x0020, 0x709b, 0xffff, 0x0804, 0x24aa, 0x2700, 0x0156, + 0x0016, 0x9106, 0x05a0, 0xc484, 0x080c, 0x4b58, 0x0120, 0x080c, + 0x4b03, 0x15a8, 0x0008, 0xc485, 0x6004, 0x9084, 0x00ff, 0x9086, + 0x0006, 0x1130, 0x7030, 0xd08c, 0x01e8, 0x6000, 0xd0bc, 0x11d0, + 0x7284, 0xd28c, 0x0188, 0x6004, 0x9084, 0x00ff, 0x9082, 0x0006, + 0x02b0, 0xd484, 0x1118, 0x080c, 0x4b20, 0x0028, 0x080c, 0x2676, + 0x0170, 0x080c, 0x26a3, 0x0058, 0x080c, 0x25ec, 0x080c, 0x24ef, + 0x0170, 0x0028, 0x080c, 0x2676, 0x0110, 0x0419, 0x0140, 0x001e, + 0x8108, 0x015e, 0x1f04, 0x2466, 0x709b, 0xffff, 0x0018, 0x001e, + 0x015e, 0x719a, 0x004e, 0x002e, 0x00ce, 0x0005, 0x00c6, 0x0016, + 0x709b, 0x0001, 0x2009, 0x007e, 0x080c, 0x4b03, 0x1138, 0x080c, + 0x25ec, 0x04a9, 0x0118, 0x70cc, 0xc0bd, 0x70ce, 0x001e, 0x00ce, + 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x2001, 0x1157, + 0x2004, 0x9084, 0x00ff, 0x6842, 0x080c, 0x984d, 0x01d8, 0x2d00, + 0x6012, 0x080c, 0x99cc, 0x6023, 0x0001, 0x2001, 0x0000, 0x080c, + 0x4aa1, 0x2001, 0x0000, 0x080c, 0x4ab3, 0x0126, 0x2091, 0x8000, + 0x7094, 0x8000, 0x7096, 0x012e, 0x2009, 0x0004, 0x080c, 0x7f4e, + 0x9085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x0016, + 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x2001, 0x1157, 0x2004, 0x9084, + 0x00ff, 0x6842, 0x080c, 0x984d, 0x0550, 0x2d00, 0x6012, 0x6800, + 0xc0c4, 0x6802, 0x68a0, 0x9086, 0x007e, 0x0140, 0x6804, 0x9084, + 0x00ff, 0x9086, 0x0006, 0x1110, 0x080c, 0x25ad, 0x080c, 0x99cc, + 0x6023, 0x0001, 0x2001, 0x0000, 0x080c, 0x4aa1, 0x2001, 0x0002, + 0x080c, 0x4ab3, 0x0126, 0x2091, 0x8000, 0x7094, 0x8000, 0x7096, + 0x012e, 0x2009, 0x0002, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x00ce, + 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x0026, 0x2009, 0x0080, + 0x080c, 0x4b03, 0x1120, 0x0031, 0x0110, 0x70d3, 0xffff, 0x002e, + 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x080c, + 0x7ec8, 0x01d8, 0x2d00, 0x6012, 0x080c, 0x99cc, 0x6023, 0x0001, + 0x2001, 0x0000, 0x080c, 0x4aa1, 0x2001, 0x0002, 0x080c, 0x4ab3, + 0x0126, 0x2091, 0x8000, 0x70d4, 0x8000, 0x70d6, 0x012e, 0x2009, + 0x0002, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x00ce, 0x00de, 0x007e, + 0x001e, 0x0005, 0x00c6, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2009, + 0x007f, 0x080c, 0x4b03, 0x1190, 0x2c68, 0x080c, 0x7ec8, 0x0170, + 0x2d00, 0x6012, 0x6316, 0x6023, 0x0001, 0x620a, 0x080c, 0x99cc, + 0x2009, 0x0022, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x012e, 0x00de, + 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0066, 0x0036, 0x0026, 0x080c, + 0x69d6, 0x080c, 0x697f, 0x080c, 0x89dd, 0x2130, 0x81ff, 0x0128, + 0x20a9, 0x007e, 0x2009, 0x0000, 0x0020, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x0016, 0x080c, 0x4b58, 0x1110, 0x080c, 0x472d, 0x001e, + 0x8108, 0x1f04, 0x2599, 0x86ff, 0x1110, 0x080c, 0x0a33, 0x002e, + 0x003e, 0x006e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0036, + 0x0026, 0x0016, 0x6210, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, + 0x080c, 0x69ca, 0x0076, 0x2039, 0x0000, 0x080c, 0x68fe, 0x2c08, + 0x080c, 0xa85f, 0x007e, 0x001e, 0x2e60, 0x6210, 0x6314, 0x080c, + 0x472d, 0x6212, 0x6316, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, + 0x0005, 0x00e6, 0x0006, 0x6010, 0x9080, 0x0028, 0x2004, 0x9086, + 0x0080, 0x0150, 0x2071, 0x1100, 0x7094, 0x9005, 0x0110, 0x8001, + 0x7096, 0x000e, 0x00ee, 0x0005, 0x2071, 0x1100, 0x70d4, 0x9005, + 0x0dc0, 0x8001, 0x70d6, 0x0ca8, 0x6000, 0xc08c, 0x6002, 0x0005, + 0x00f6, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x0156, 0x2178, + 0x81ff, 0x1118, 0x20a9, 0x0001, 0x0098, 0x2001, 0x1153, 0x2004, + 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0x9006, 0x0046, 0x2020, 0x2009, + 0x002d, 0x080c, 0xaaca, 0x004e, 0x20a9, 0x00ff, 0x2011, 0x0000, + 0x0026, 0x928e, 0x007e, 0x0904, 0x2655, 0x928e, 0x007f, 0x05e8, + 0x928e, 0x0080, 0x05d0, 0x9288, 0x1000, 0x210c, 0x81ff, 0x05a8, + 0x8fff, 0x1148, 0x2001, 0x12ae, 0x0006, 0x2003, 0x0001, 0x04c9, + 0x000e, 0x2003, 0x0000, 0x00c6, 0x2160, 0x2001, 0x0001, 0x080c, + 0x4dea, 0x00ce, 0x2019, 0x0029, 0x080c, 0x69ca, 0x0076, 0x2039, + 0x0000, 0x080c, 0x68fe, 0x00c6, 0x0026, 0x2160, 0x6204, 0x9294, + 0x00ff, 0x9286, 0x0006, 0x1118, 0x6007, 0x0404, 0x0028, 0x2001, + 0x0004, 0x8007, 0x9215, 0x6206, 0x002e, 0x00ce, 0x0016, 0x2c08, + 0x080c, 0xa85f, 0x001e, 0x007e, 0x2160, 0x002e, 0x8210, 0x1f04, + 0x2610, 0x015e, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x00fe, + 0x0005, 0x0046, 0x0026, 0x0016, 0x2001, 0x1153, 0x2004, 0xd0c4, + 0x0148, 0xd0a4, 0x0138, 0x9006, 0x2220, 0x8427, 0x2009, 0x0029, + 0x080c, 0xaaca, 0x001e, 0x002e, 0x004e, 0x0005, 0x0016, 0x0026, + 0x0036, 0x00c6, 0x7284, 0x82ff, 0x01f8, 0x2011, 0x1153, 0x2214, + 0xd2ac, 0x11d0, 0x2100, 0x080c, 0x1c7d, 0x81ff, 0x01b8, 0x2019, + 0x0001, 0x8314, 0x92e0, 0x1580, 0x2c04, 0xd384, 0x0120, 0x9084, + 0xff00, 0x8007, 0x0010, 0x9084, 0x00ff, 0x9116, 0x0138, 0x9096, + 0x00ff, 0x0110, 0x8318, 0x0c68, 0x9085, 0x0001, 0x00ce, 0x003e, + 0x002e, 0x001e, 0x0005, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x9180, 0x1000, 0x2004, 0x9065, 0x0158, 0x0016, 0x00c6, 0x2061, + 0x135e, 0x001e, 0x6112, 0x080c, 0x25ad, 0x001e, 0x080c, 0x4b20, + 0x012e, 0x00ce, 0x001e, 0x0005, 0x2001, 0x1133, 0x2004, 0xd0cc, + 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, + 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, + 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, + 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, + 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, + 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, + 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, + 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, + 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, + 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, + 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, + 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, + 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, + 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, + 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, + 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, + 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, + 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, + 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, + 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, + 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, + 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, + 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, + 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, + 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, + 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, + 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x2071, 0x1193, 0x7003, 0x0002, 0x9006, 0x7012, 0x7016, + 0x703a, 0x703e, 0x7033, 0x11a3, 0x7037, 0x11a3, 0x7007, 0x0001, + 0x2061, 0x11e3, 0x6003, 0x0002, 0x0005, 0x1004, 0x27e4, 0x0e04, + 0x27e4, 0x2071, 0x1193, 0x2b78, 0x2a60, 0x7880, 0x908e, 0x0069, + 0x1904, 0x28cc, 0x0804, 0x2860, 0x0005, 0x2071, 0x1193, 0x7004, + 0x0002, 0x27ed, 0x27ee, 0x27f5, 0x2806, 0x0005, 0x1004, 0x27f4, + 0x0e04, 0x27f4, 0x2b78, 0x00e8, 0x0005, 0x2b78, 0x2061, 0x11e3, + 0x6008, 0x908e, 0x0100, 0x0128, 0x9086, 0x0200, 0x0904, 0x28c6, + 0x0005, 0x7014, 0x2068, 0x2a60, 0x7018, 0x0807, 0x7010, 0x2068, + 0x6864, 0x9086, 0x0103, 0x0108, 0x0005, 0x2a60, 0x2b78, 0x7018, + 0x0807, 0x2a60, 0x7880, 0x908a, 0x0040, 0x1210, 0x61c0, 0x0042, + 0x2100, 0x908a, 0x003f, 0x1a04, 0x28c3, 0x61c0, 0x0804, 0x2860, + 0x28a2, 0x28d2, 0x28dc, 0x28e0, 0x28ea, 0x28f0, 0x28f4, 0x2904, + 0x2907, 0x2911, 0x2916, 0x291b, 0x2926, 0x2931, 0x2940, 0x294f, + 0x295d, 0x2974, 0x298f, 0x2a10, 0x2a15, 0x2a3e, 0x2a8b, 0x2a9c, + 0x2aba, 0x28c3, 0x28c3, 0x28c3, 0x2af1, 0x2b10, 0x2b19, 0x2b4c, + 0x2b52, 0x28c3, 0x2b7b, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, + 0x2b86, 0x2b90, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, + 0x28c3, 0x28c3, 0x2b98, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, + 0x2bb5, 0x2bdb, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, + 0x0002, 0x2c05, 0x2c59, 0x2cb4, 0x2cc7, 0x28c3, 0x2ce1, 0x3102, + 0x3b4e, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x28c3, + 0x28c3, 0x2911, 0x2916, 0x3104, 0x28c3, 0x3116, 0x3bde, 0x3c39, + 0x3c9f, 0x28c3, 0x3d00, 0x3d2a, 0x3d4f, 0x3e32, 0x3d81, 0x3ddc, + 0x28c3, 0x311a, 0x32a9, 0x32bf, 0x32dd, 0x3342, 0x33a8, 0x33b3, + 0x33ea, 0x33f9, 0x3408, 0x340b, 0x3433, 0x3486, 0x3502, 0x350f, + 0x3612, 0x3732, 0x375b, 0x3856, 0x3878, 0x3884, 0x38bd, 0x398a, + 0x28c3, 0x28c3, 0x28c3, 0x28c3, 0x39f2, 0x3a0d, 0x3a85, 0x3b3f, + 0x713c, 0x0000, 0x2021, 0x4000, 0x080c, 0x37b8, 0x0126, 0x2091, + 0x8000, 0x0e04, 0x28ac, 0x0010, 0x012e, 0x0cc0, 0x7c36, 0x9486, + 0x4000, 0x0118, 0x7833, 0x0011, 0x0010, 0x7833, 0x0010, 0x7c82, + 0x7986, 0x7a8a, 0x7b8e, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, + 0x5000, 0x012e, 0x0005, 0x2021, 0x4001, 0x08f0, 0x2021, 0x4002, + 0x08d8, 0x2021, 0x4003, 0x08c0, 0x2021, 0x4005, 0x08a8, 0x2021, + 0x4006, 0x0890, 0x2039, 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c, + 0x7884, 0x7990, 0x0804, 0x37c5, 0x7883, 0x0004, 0x7884, 0x0807, + 0x2039, 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c, 0x7884, 0x7990, + 0x0804, 0x37c8, 0x7984, 0x7888, 0x2114, 0x200a, 0x0804, 0x28a2, + 0x7984, 0x2114, 0x0804, 0x28a2, 0x20e1, 0x0000, 0x2099, 0x0021, + 0x20e9, 0x0000, 0x20a1, 0x0021, 0x20a9, 0x001f, 0x4003, 0x7984, + 0x7a88, 0x7b8c, 0x0804, 0x28a2, 0x7884, 0x2060, 0x04d8, 0x2009, + 0x0003, 0x2011, 0x0000, 0x2019, 0x0018, 0x789b, 0x0017, 0x0804, + 0x28a2, 0x2039, 0x0001, 0x7d98, 0x7c9c, 0x0800, 0x2039, 0x0001, + 0x7d98, 0x7c9c, 0x0848, 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, + 0x28cf, 0x2138, 0x7d98, 0x7c9c, 0x0804, 0x28d6, 0x79a0, 0x9182, + 0x0040, 0x0210, 0x0804, 0x28cf, 0x2138, 0x7d98, 0x7c9c, 0x0804, + 0x28e4, 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x28cf, 0x21e8, + 0x7984, 0x7888, 0x20a9, 0x0001, 0x21a0, 0x4004, 0x0804, 0x28a2, + 0x2061, 0x0800, 0xe10c, 0x9006, 0x2c15, 0x9200, 0x8c60, 0x8109, + 0x1dd8, 0x2010, 0x9005, 0x0904, 0x28a2, 0x0804, 0x28c9, 0x79a0, + 0x9182, 0x0040, 0x0210, 0x0804, 0x28cf, 0x21e0, 0x20a9, 0x0001, + 0x7984, 0x2198, 0x4012, 0x0804, 0x28a2, 0x2069, 0x1152, 0x7884, + 0x7990, 0x911a, 0x1a04, 0x28cf, 0x8019, 0x0904, 0x28cf, 0x684a, + 0x6942, 0x788c, 0x6852, 0x7888, 0x6856, 0x9006, 0x685a, 0x685e, + 0x080c, 0x5a12, 0x0804, 0x28a2, 0x2069, 0x1152, 0x7884, 0x7994, + 0x911a, 0x1a04, 0x28cf, 0x8019, 0x0904, 0x28cf, 0x684e, 0x6946, + 0x788c, 0x6862, 0x7888, 0x6866, 0x9006, 0x686a, 0x686e, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4e87, 0x012e, 0x0804, 0x28a2, 0x902e, + 0x2520, 0x81ff, 0x1904, 0x28cc, 0x7984, 0x7b88, 0x7a8c, 0x20a9, + 0x0005, 0x20e9, 0x0001, 0x20a1, 0x119a, 0x4101, 0x080c, 0x3784, + 0x0904, 0x28cc, 0x2009, 0x0020, 0x2039, 0x0001, 0x080c, 0x37c5, + 0x701b, 0x29ab, 0x0005, 0x6864, 0x2008, 0x9084, 0x00ff, 0x9096, + 0x0011, 0x0120, 0x9096, 0x0019, 0x1904, 0x28cc, 0x810f, 0x918c, + 0x00ff, 0x0904, 0x28cc, 0x710e, 0x700c, 0x8001, 0x0538, 0x700e, + 0x080c, 0x3784, 0x0904, 0x28cc, 0x2009, 0x0020, 0x2061, 0x11e3, + 0x6228, 0x632c, 0x6430, 0x6534, 0x9290, 0x0040, 0x9399, 0x0000, + 0x94a1, 0x0000, 0x95a9, 0x0000, 0x2039, 0x0001, 0x080c, 0x37c5, + 0x701b, 0x29db, 0x0005, 0x6864, 0x9084, 0x00ff, 0x9096, 0x0002, + 0x0120, 0x9096, 0x000a, 0x1904, 0x28cc, 0x08b0, 0x7010, 0x2068, + 0x6868, 0xc0fd, 0x686a, 0x080c, 0x4a18, 0x1128, 0x7007, 0x0003, + 0x701b, 0x29f5, 0x0005, 0x080c, 0x52a0, 0x0126, 0x2091, 0x8000, + 0x20a9, 0x0005, 0x20e1, 0x0001, 0x2099, 0x119a, 0x400a, 0x2100, + 0x9210, 0x9399, 0x0000, 0x94a1, 0x0000, 0x95a9, 0x0000, 0x9d80, + 0x0019, 0x2009, 0x0020, 0x012e, 0x2039, 0x0001, 0x0804, 0x37c8, + 0x61a8, 0x7884, 0x60aa, 0x0804, 0x28a2, 0x2091, 0x8000, 0x7837, + 0x4000, 0x7833, 0x0010, 0x7883, 0x4000, 0x7887, 0x4953, 0x788b, + 0x5020, 0x788f, 0x2020, 0x2009, 0x017f, 0x2104, 0x7892, 0x3f00, + 0x7896, 0x2061, 0x0100, 0x6200, 0x2061, 0x0200, 0x603c, 0x8007, + 0x9205, 0x789a, 0x2009, 0x04fd, 0x2104, 0x789e, 0x2091, 0x5000, + 0x2091, 0x4080, 0x2071, 0x0080, 0x0804, 0x0427, 0x81ff, 0x1904, + 0x28cc, 0x7984, 0x810f, 0x918c, 0x00ff, 0x080c, 0x4b58, 0x1904, + 0x28cf, 0x7e98, 0x9684, 0x3fff, 0x9082, 0x4000, 0x0210, 0x0804, + 0x28cf, 0x7c88, 0x7d8c, 0x080c, 0x4ca3, 0x080c, 0x4c75, 0x0000, + 0x1518, 0x2061, 0x15c0, 0x0126, 0x2091, 0x8000, 0x6000, 0x9086, + 0x0000, 0x0148, 0x6014, 0x906d, 0x0130, 0x686c, 0x9406, 0x1118, + 0x6870, 0x9506, 0x0150, 0x012e, 0x9ce0, 0x0018, 0x2001, 0x1116, + 0x2004, 0x9c02, 0x1a04, 0x28cc, 0x0c30, 0x080c, 0x92a4, 0x012e, + 0x0904, 0x28cc, 0x0804, 0x28a2, 0x900e, 0x2001, 0x0005, 0x080c, + 0x52a0, 0x0126, 0x2091, 0x8000, 0x080c, 0x9849, 0x080c, 0x50a5, + 0x012e, 0x0804, 0x28a2, 0x81ff, 0x1904, 0x28cc, 0x080c, 0x3799, + 0x0904, 0x28cf, 0x080c, 0x4c17, 0x0904, 0x28cc, 0x080c, 0x4ca9, + 0x0904, 0x28cc, 0x0804, 0x28a2, 0x81ff, 0x1904, 0x28cc, 0x080c, + 0x37a9, 0x0904, 0x28cf, 0x080c, 0x4cf1, 0x0904, 0x28cc, 0x2019, + 0x0005, 0x080c, 0x4cc4, 0x0904, 0x28cc, 0x7888, 0x908a, 0x1000, + 0x1a04, 0x28cf, 0x8003, 0x800b, 0x810b, 0x9108, 0x080c, 0x6567, + 0x0804, 0x28a2, 0x0126, 0x2091, 0x8000, 0x81ff, 0x0118, 0x2009, + 0x0001, 0x0448, 0x2029, 0x00ff, 0x644c, 0x2400, 0x9506, 0x01f0, + 0x2508, 0x080c, 0x4b58, 0x11d0, 0x080c, 0x4cf1, 0x1128, 0x2009, + 0x0002, 0x62b0, 0x2518, 0x00b8, 0x2019, 0x0004, 0x080c, 0x4cc4, + 0x1118, 0x2009, 0x0006, 0x0078, 0x7884, 0x908a, 0x1000, 0x1270, + 0x8003, 0x800b, 0x810b, 0x9108, 0x080c, 0x6567, 0x8529, 0x1ae8, + 0x012e, 0x0804, 0x28a2, 0x012e, 0x0804, 0x28cc, 0x012e, 0x0804, + 0x28cf, 0x080c, 0x3799, 0x0904, 0x28cf, 0x080c, 0x4c17, 0x0904, + 0x28cc, 0x62a0, 0x2019, 0x0005, 0x00c6, 0x2061, 0x0000, 0x080c, + 0x69ca, 0x0076, 0x2039, 0x0000, 0x080c, 0x68fe, 0x2009, 0x0000, + 0x080c, 0xa85f, 0x007e, 0x00ce, 0x080c, 0x4ca3, 0x0804, 0x28a2, + 0x080c, 0x3799, 0x0904, 0x28cf, 0x080c, 0x4ca3, 0x2208, 0x0804, + 0x28a2, 0x0156, 0x00d6, 0x00e6, 0x2069, 0x1228, 0x6810, 0x6914, + 0x910a, 0x1210, 0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019, + 0x0000, 0x20a9, 0x007e, 0x2069, 0x1000, 0x2d04, 0x9075, 0x0118, + 0x704c, 0x0059, 0x9210, 0x8d68, 0x1f04, 0x2b2d, 0x2300, 0x9218, + 0x00ee, 0x00de, 0x015e, 0x0804, 0x28a2, 0x00f6, 0x0016, 0x907d, + 0x0140, 0x2001, 0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0110, 0x2178, + 0x0cd0, 0x001e, 0x00fe, 0x0005, 0x2069, 0x1228, 0x6910, 0x62ac, + 0x0804, 0x28a2, 0x81ff, 0x1904, 0x28cc, 0x614c, 0x9190, 0x26c1, + 0x2215, 0x9294, 0x00ff, 0x636c, 0x83ff, 0x0108, 0x6270, 0x67cc, + 0xd79c, 0x0118, 0x2031, 0x0001, 0x0090, 0xd7ac, 0x0118, 0x2031, + 0x0003, 0x0068, 0xd7a4, 0x0118, 0x2031, 0x0002, 0x0040, 0x080c, + 0x5745, 0x1118, 0x2031, 0x0004, 0x0010, 0x2031, 0x0000, 0x7e9a, + 0x7f9e, 0x0804, 0x28a2, 0x613c, 0x6240, 0x2019, 0x12a6, 0x231c, + 0x2001, 0x12a7, 0x2004, 0x789a, 0x0804, 0x28a2, 0x0126, 0x2091, + 0x8000, 0x6134, 0x9006, 0x2010, 0x2018, 0x012e, 0x0804, 0x28a2, + 0x080c, 0x37a9, 0x0904, 0x28cf, 0x6244, 0x6338, 0x0804, 0x28a2, + 0x613c, 0x6240, 0x7884, 0x603e, 0x7b88, 0x6342, 0x2069, 0x1152, + 0x831f, 0x9305, 0x6816, 0x788c, 0x2069, 0x12a6, 0x2d1c, 0x206a, + 0x7e98, 0x9682, 0x0014, 0x1210, 0x2031, 0x07d0, 0x2069, 0x12a7, + 0x2d04, 0x266a, 0x789a, 0x0804, 0x28a2, 0x0126, 0x2091, 0x8000, + 0x7884, 0x6036, 0xd0c4, 0x01a8, 0x00d6, 0x78a8, 0x2009, 0x12bd, + 0x200a, 0x78ac, 0x2011, 0x12be, 0x2012, 0x2069, 0x0100, 0x6838, + 0x9086, 0x0007, 0x1118, 0x2214, 0x6a5a, 0x0010, 0x210c, 0x695a, + 0x00de, 0x7884, 0xd0b4, 0x0120, 0x3b00, 0x9084, 0xff3f, 0x20d8, + 0x012e, 0x0804, 0x28a2, 0x7898, 0x9005, 0x01a8, 0x7888, 0x9025, + 0x0904, 0x28cf, 0x788c, 0x902d, 0x0904, 0x28cf, 0x900e, 0x080c, + 0x4b58, 0x1120, 0x6244, 0x6338, 0x6446, 0x653a, 0x9186, 0x00ff, + 0x0190, 0x8108, 0x0ca0, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x7888, + 0x900d, 0x0904, 0x28cf, 0x788c, 0x9005, 0x0904, 0x28cf, 0x6244, + 0x6146, 0x6338, 0x603a, 0x0804, 0x28a2, 0x2001, 0x1100, 0x2004, + 0x9086, 0x0003, 0x1904, 0x28cc, 0x00c6, 0x2061, 0x0100, 0x7984, + 0x810f, 0x918c, 0x00ff, 0x9196, 0x00ff, 0x1130, 0x2001, 0x1114, + 0x2004, 0x9085, 0xff00, 0x0078, 0x9182, 0x007f, 0x16a0, 0x9188, + 0x26c1, 0x210d, 0x918c, 0x00ff, 0x2001, 0x1114, 0x2004, 0x9116, + 0x0550, 0x810f, 0x9105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, + 0x7ec8, 0x000e, 0x01e0, 0x6012, 0x600b, 0xbc09, 0x6023, 0x0001, + 0x080c, 0x3784, 0x01d8, 0x6867, 0x0000, 0x7007, 0x0003, 0x6833, + 0x0000, 0x6868, 0xc0fd, 0x686a, 0x701b, 0x2cad, 0x2d00, 0x6016, + 0x2009, 0x0032, 0x080c, 0x7f4e, 0x012e, 0x00ce, 0x0005, 0x012e, + 0x00ce, 0x0804, 0x28cc, 0x00ce, 0x0804, 0x28cf, 0x080c, 0x7f1e, + 0x0cb0, 0x2001, 0x1100, 0x2004, 0x9086, 0x0003, 0x1904, 0x28cc, + 0x00c6, 0x2061, 0x0100, 0x7984, 0x810f, 0x918c, 0x00ff, 0x9196, + 0x00ff, 0x1130, 0x2001, 0x1114, 0x2004, 0x9085, 0xff00, 0x0078, + 0x9182, 0x007f, 0x16a0, 0x9188, 0x26c1, 0x210d, 0x918c, 0x00ff, + 0x2001, 0x1114, 0x2004, 0x9116, 0x0550, 0x810f, 0x9105, 0x0126, + 0x2091, 0x8000, 0x0006, 0x080c, 0x7ec8, 0x000e, 0x01e0, 0x6012, + 0x600b, 0xbc05, 0x6023, 0x0001, 0x080c, 0x3784, 0x01d8, 0x6867, + 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6868, 0xc0fd, 0x686a, + 0x701b, 0x2cad, 0x2d00, 0x6016, 0x2009, 0x0032, 0x080c, 0x7f4e, + 0x012e, 0x00ce, 0x0005, 0x012e, 0x00ce, 0x0804, 0x28cc, 0x00ce, + 0x0804, 0x28cf, 0x080c, 0x7f1e, 0x0cb0, 0x6830, 0x9086, 0x0100, + 0x0904, 0x28cc, 0x0804, 0x28a2, 0x2061, 0x1329, 0x0126, 0x2091, + 0x8000, 0x6000, 0xd084, 0x0140, 0x6104, 0x6208, 0x2019, 0x1111, + 0x231c, 0x012e, 0x0804, 0x28a2, 0x012e, 0x0804, 0x28cf, 0x81ff, + 0x1904, 0x28cc, 0x080c, 0x5745, 0x0904, 0x28cc, 0x0126, 0x2091, + 0x8000, 0x6244, 0x6064, 0x9202, 0x0248, 0x9085, 0x0001, 0x080c, + 0x1cb3, 0x080c, 0x4016, 0x012e, 0x0804, 0x28a2, 0x012e, 0x0804, + 0x28cf, 0x0126, 0x2091, 0x8000, 0x81ff, 0x0148, 0x080c, 0x204d, + 0x1130, 0x9006, 0x080c, 0x1faf, 0x9006, 0x080c, 0x1f92, 0x7884, + 0x9084, 0x0007, 0x0002, 0x2cfe, 0x2d07, 0x2d10, 0x2cfb, 0x2cfb, + 0x2cfb, 0x2cfb, 0x2cfb, 0x012e, 0x0804, 0x28cf, 0x2009, 0x0114, + 0x2104, 0x9085, 0x0800, 0x200a, 0x080c, 0x2e61, 0x0080, 0x2009, + 0x0114, 0x2104, 0x9085, 0x4000, 0x200a, 0x080c, 0x2e61, 0x0038, + 0x81ff, 0x0128, 0x012e, 0x2021, 0x400b, 0x0804, 0x28a4, 0x0086, + 0x0096, 0x00a6, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2009, + 0x0101, 0x210c, 0x0016, 0x2001, 0x0032, 0x2034, 0x2001, 0x0033, + 0x202c, 0x9006, 0x2048, 0x2050, 0x2058, 0x080c, 0x3098, 0x080c, + 0x2ffe, 0x903e, 0x2720, 0x00f6, 0x00e6, 0x00c6, 0x2d60, 0x2071, + 0x131f, 0x2079, 0x0090, 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4, + 0x0140, 0x2001, 0x0035, 0x2004, 0x780e, 0x2001, 0x0034, 0x2004, + 0x780a, 0x00de, 0x2011, 0x0001, 0x080c, 0x2faa, 0x080c, 0x2faa, + 0x00ce, 0x00ee, 0x00fe, 0x080c, 0x2f03, 0x080c, 0x2fd2, 0x080c, + 0x2f4f, 0x080c, 0x2ec8, 0x080c, 0x2ef9, 0x00f6, 0x2079, 0x0100, + 0x7824, 0xd0ac, 0x0130, 0x8b58, 0x080c, 0x2e43, 0x00fe, 0x0804, + 0x2df2, 0x00fe, 0x080c, 0x2e39, 0x1150, 0x8948, 0x2001, 0x0032, + 0x2602, 0x2001, 0x0033, 0x2502, 0x080c, 0x2e43, 0x0078, 0x87ff, + 0x0138, 0x2001, 0x0201, 0x2004, 0x9005, 0x19b8, 0x8739, 0x0030, + 0x2001, 0x131c, 0x2004, 0x9086, 0x0000, 0x1978, 0x2001, 0x034f, + 0x2003, 0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, 0x9605, 0x0904, + 0x2df2, 0x7884, 0xd0bc, 0x0128, 0x2900, 0x9a05, 0x9b05, 0x1904, + 0x2df2, 0x6013, 0x0019, 0x2001, 0x032a, 0x2003, 0x0004, 0x7884, + 0xd0ac, 0x1148, 0x2001, 0x131c, 0x2003, 0x0003, 0x2001, 0x032a, + 0x2003, 0x0009, 0x0040, 0x6017, 0x0001, 0x2001, 0x002d, 0x2004, + 0x9005, 0x0108, 0x6016, 0x2c00, 0x605a, 0x2001, 0x0200, 0x2003, + 0x0040, 0x2d00, 0x685a, 0x6813, 0x0019, 0x7884, 0xd0a4, 0x1180, + 0x6817, 0x0000, 0x00c6, 0x20a9, 0x0004, 0x2061, 0x0090, 0x602b, + 0x0008, 0x2001, 0x0203, 0x2004, 0x1f04, 0x2dc7, 0x00ce, 0x0040, + 0x6817, 0x0001, 0x2001, 0x002c, 0x2004, 0x9005, 0x0108, 0x6816, + 0x00f6, 0x00c6, 0x2079, 0x0100, 0x2061, 0x0090, 0x7827, 0x0002, + 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0x601a, 0x0006, 0x2001, + 0x002b, 0x2004, 0x601e, 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, + 0x0804, 0x2d33, 0x2001, 0x032a, 0x2003, 0x0004, 0x2061, 0x0100, + 0x6027, 0x0002, 0x001e, 0x6106, 0x2011, 0x020d, 0x2013, 0x0020, + 0x2001, 0x0004, 0x200c, 0x918c, 0xfffd, 0x2102, 0x080c, 0x0f8f, + 0x7884, 0x9084, 0x0003, 0x9086, 0x0002, 0x01a0, 0x2001, 0x0200, + 0x2003, 0x0028, 0x2001, 0x0227, 0x200c, 0x2102, 0x6050, 0x9084, + 0xb7ef, 0x6052, 0x602f, 0x0000, 0x604b, 0xf7f7, 0x6043, 0x0090, + 0x6043, 0x0010, 0x2908, 0x2a10, 0x2b18, 0x2b00, 0x9a05, 0x9905, + 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, + 0x1118, 0x012e, 0x0804, 0x28a2, 0x012e, 0x2021, 0x400c, 0x0804, + 0x28a4, 0x9085, 0x0001, 0x1d04, 0x2e42, 0x2091, 0x6000, 0x8420, + 0x9486, 0x0064, 0x0005, 0x2001, 0x0105, 0x2003, 0x0010, 0x2001, + 0x032a, 0x2003, 0x0004, 0x2001, 0x009a, 0x2003, 0x0004, 0x2001, + 0x131c, 0x2003, 0x0000, 0x2001, 0x131f, 0x2003, 0x0000, 0x2001, + 0x0200, 0x2003, 0x0048, 0x2001, 0x0227, 0x2024, 0x2402, 0x9026, + 0x0005, 0x00f6, 0x2079, 0x0100, 0x2001, 0x1114, 0x200c, 0x7932, + 0x7936, 0x080c, 0x1c93, 0x7850, 0x9084, 0xfbff, 0x9085, 0x0030, + 0x7852, 0x2019, 0x01f4, 0x8319, 0x1df0, 0x9084, 0xffcf, 0x9085, + 0x2000, 0x7852, 0x20a9, 0x0046, 0x1d04, 0x2e7c, 0x2091, 0x6000, + 0x1f04, 0x2e7c, 0x7850, 0x9085, 0x0400, 0x9084, 0xdfff, 0x7852, + 0x2001, 0x0021, 0x2004, 0x9084, 0x0003, 0x9086, 0x0001, 0x1120, + 0x7850, 0x9084, 0xdfff, 0x7852, 0x784b, 0xf7f7, 0x7843, 0x0090, + 0x7843, 0x0010, 0x20a9, 0x0028, 0xa001, 0x1f04, 0x2e9c, 0x7850, + 0x9085, 0x1400, 0x7852, 0x2019, 0x61a8, 0x7854, 0xa001, 0xa001, + 0xd08c, 0x1110, 0x8319, 0x1dc8, 0x7827, 0x0048, 0x7850, 0x9085, + 0x0400, 0x7852, 0x7843, 0x0040, 0x2019, 0x01f4, 0xa001, 0xa001, + 0x8319, 0x1de0, 0x2001, 0x0140, 0x2003, 0x0100, 0x7827, 0x0020, + 0x7843, 0x0000, 0x2003, 0x0000, 0x7827, 0x0048, 0x00fe, 0x0005, + 0x7884, 0xd0ac, 0x11c8, 0x00f6, 0x00e6, 0x2071, 0x131c, 0x2079, + 0x0320, 0x2001, 0x0201, 0x2004, 0x9005, 0x0160, 0x7000, 0x9086, + 0x0000, 0x1140, 0x0051, 0xd0bc, 0x0108, 0x8738, 0x7003, 0x0003, + 0x782b, 0x0019, 0x00ee, 0x00fe, 0x0005, 0x78bc, 0x908c, 0x0070, + 0x0178, 0x2009, 0x0032, 0x260a, 0x2009, 0x0033, 0x250a, 0xd0b4, + 0x0108, 0x8a50, 0xd0ac, 0x0108, 0x8948, 0xd0a4, 0x0108, 0x8b58, + 0x0005, 0x00f6, 0x2079, 0x0200, 0x781c, 0xd084, 0x0110, 0x7837, + 0x0050, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0100, 0x70e3, 0x0005, + 0x702c, 0x9085, 0x0002, 0x702e, 0x2009, 0x1114, 0x210c, 0x716e, + 0x7063, 0x0100, 0x7166, 0x719e, 0x706b, 0x0000, 0x7073, 0x0809, + 0x7077, 0x0008, 0x7078, 0x9080, 0x0100, 0x707a, 0x7080, 0x8000, + 0x7082, 0x7087, 0xaaaa, 0x9006, 0x708a, 0x708e, 0x707e, 0x70d6, + 0x70ab, 0x0036, 0x70af, 0x95d5, 0x7014, 0x9084, 0x1984, 0x9085, + 0x0012, 0x7016, 0x080c, 0x2fd2, 0x00f6, 0x2071, 0x131c, 0x2079, + 0x0320, 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4, 0x0120, 0x689c, + 0x780e, 0x6898, 0x780a, 0x00de, 0x2011, 0x0011, 0x080c, 0x2faa, + 0x2011, 0x0001, 0x080c, 0x2faa, 0x00fe, 0x00ee, 0x0005, 0x00f6, + 0x00e6, 0x2071, 0x131c, 0x2079, 0x0320, 0x792c, 0xd1fc, 0x0904, + 0x2fa7, 0x782b, 0x0002, 0x9026, 0xd19c, 0x1904, 0x2fa3, 0x7000, + 0x0002, 0x2fa7, 0x2f65, 0x2f89, 0x2fa3, 0xd1bc, 0x1150, 0xd1dc, + 0x1150, 0x8001, 0x7002, 0x2011, 0x0001, 0x04e1, 0x05c0, 0x04d1, + 0x04b0, 0x78bf, 0x0000, 0x7810, 0x7914, 0x782b, 0x0004, 0x7812, + 0x7916, 0x2001, 0x0201, 0x200c, 0x81ff, 0x0de8, 0x080c, 0x2ee5, + 0x2009, 0x0001, 0x78b8, 0xd0ec, 0x0110, 0x2009, 0x0011, 0x792a, + 0x00f0, 0x8001, 0x7002, 0x9184, 0x0880, 0x1138, 0x782c, 0xd0fc, + 0x1940, 0x2011, 0x0001, 0x00b1, 0x0090, 0x6010, 0x9092, 0x0004, + 0x9086, 0x0015, 0x1120, 0x6000, 0x605a, 0x2011, 0x0031, 0x6212, + 0xd1dc, 0x1988, 0x0870, 0x782b, 0x0004, 0x7003, 0x0000, 0x00ee, + 0x00fe, 0x0005, 0x6014, 0x9005, 0x0520, 0x8001, 0x6016, 0x6058, + 0x6110, 0x9140, 0x2804, 0x7802, 0x8840, 0x2804, 0x7806, 0x8840, + 0x2804, 0x7812, 0x8840, 0x2804, 0x7816, 0x8840, 0x7a2a, 0x7000, + 0x8000, 0x7002, 0x6058, 0x9802, 0x908a, 0x0029, 0x1138, 0x6058, + 0x9080, 0x0001, 0x2004, 0x605a, 0x2001, 0x0019, 0x6012, 0x9085, + 0x0001, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2071, 0x131f, 0x2079, + 0x0090, 0x792c, 0xd1fc, 0x01f0, 0x782b, 0x0002, 0x2d60, 0x9026, + 0x7000, 0x0002, 0x2ffa, 0x2fe5, 0x2ff1, 0x8001, 0x7002, 0xd19c, + 0x1188, 0x2011, 0x0001, 0x080c, 0x2faa, 0x0160, 0x080c, 0x2faa, + 0x0048, 0x8001, 0x7002, 0x782c, 0xd0fc, 0x1d30, 0x2011, 0x0001, + 0x080c, 0x2faa, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6, + 0x00c6, 0x2061, 0x0200, 0x601b, 0x0004, 0x2061, 0x0100, 0x60cf, + 0x0400, 0x6104, 0xc1ac, 0x6106, 0x2001, 0x002c, 0x2004, 0x9005, + 0x01f8, 0x2038, 0x2001, 0x002e, 0x2024, 0x2001, 0x002f, 0x201c, + 0x080c, 0x3784, 0x6813, 0x0019, 0x6f16, 0x2d00, 0x685a, 0x978a, + 0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0x903e, + 0x6858, 0x9080, 0x0019, 0x04b1, 0x1d90, 0x2d00, 0x685a, 0x0088, + 0x080c, 0x3784, 0x6813, 0x0019, 0x2070, 0x6817, 0x0001, 0x2d00, + 0x685a, 0x2001, 0x002e, 0x2004, 0x2072, 0x2001, 0x002f, 0x2004, + 0x7006, 0x2061, 0x0090, 0x2079, 0x0100, 0x6037, 0x0400, 0x2001, + 0x0200, 0x2003, 0x0040, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, + 0x700a, 0x601a, 0x0006, 0x2001, 0x002b, 0x2004, 0x700e, 0x601e, + 0x78c6, 0x000e, 0x78ca, 0x9006, 0x600a, 0x600e, 0x00ce, 0x00ee, + 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0080, 0x20e9, 0x0001, 0x20a0, + 0x20e1, 0x0000, 0x2099, 0x0088, 0x702b, 0x0026, 0x7402, 0x7306, + 0x9006, 0x700a, 0x700e, 0x810b, 0x810b, 0x21a8, 0x810b, 0x7112, + 0x702b, 0x0041, 0x702c, 0xd0fc, 0x0de8, 0x702b, 0x0002, 0x702b, + 0x0040, 0x4005, 0x7400, 0x7304, 0x87ff, 0x0180, 0x00c6, 0x00d6, + 0x2d60, 0x00c6, 0x080c, 0x3784, 0x00ce, 0x6058, 0x2070, 0x2d00, + 0x7006, 0x605a, 0x00de, 0x00ce, 0x9085, 0x0001, 0x00ee, 0x0005, + 0x00e6, 0x2001, 0x002d, 0x2004, 0x9005, 0x0508, 0x2038, 0x2001, + 0x0030, 0x2024, 0x2001, 0x0031, 0x201c, 0x080c, 0x3784, 0x2d60, + 0x6813, 0x0019, 0x6f16, 0x2d00, 0x685a, 0x978a, 0x0007, 0x0220, + 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0x903e, 0x6858, 0x9080, + 0x0019, 0x080c, 0x3062, 0x1d88, 0x2d00, 0x685a, 0x00e0, 0x080c, + 0x3784, 0x2d60, 0x6013, 0x0019, 0x2070, 0x6017, 0x0001, 0x2c00, + 0x605a, 0x2001, 0x0030, 0x2004, 0x2072, 0x2001, 0x0031, 0x2004, + 0x7006, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0x700a, 0x2001, + 0x002b, 0x2004, 0x700e, 0x2001, 0x032a, 0x2003, 0x0004, 0x7884, + 0xd0ac, 0x1180, 0x2001, 0x0101, 0x200c, 0x918d, 0x0200, 0x2102, + 0x6017, 0x0000, 0x2001, 0x131c, 0x2003, 0x0003, 0x2001, 0x032a, + 0x2003, 0x0009, 0x2001, 0x0300, 0x2003, 0x0000, 0x2001, 0x020d, + 0x2003, 0x0000, 0x2001, 0x0004, 0x200c, 0x918d, 0x0002, 0x2102, + 0x00ee, 0x0005, 0x0804, 0x28a2, 0x0126, 0x2091, 0x8000, 0x20a9, + 0x0012, 0x2001, 0x1140, 0x20e9, 0x0001, 0x20a0, 0x9006, 0x4004, + 0x2009, 0x013c, 0x200a, 0x012e, 0x0804, 0x28a2, 0x7d98, 0x7c9c, + 0x0804, 0x2991, 0x080c, 0x5745, 0x0110, 0x080c, 0x46e5, 0x2069, + 0x1152, 0x2d00, 0x2009, 0x0030, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, + 0x2039, 0x0001, 0x080c, 0x37c5, 0x701b, 0x312f, 0x0005, 0x2069, + 0x1152, 0x6800, 0x9005, 0x0904, 0x28cf, 0x6804, 0xd0ac, 0x0118, + 0xd0a4, 0x0904, 0x28cf, 0xd094, 0x00c6, 0x2061, 0x0100, 0x6104, + 0x0138, 0x6200, 0x9292, 0x0005, 0x0218, 0x918c, 0xffdf, 0x0010, + 0x918d, 0x0020, 0x6106, 0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100, + 0x6104, 0x0118, 0x918d, 0x0010, 0x0010, 0x918c, 0xffef, 0x6106, + 0x00ce, 0xd084, 0x0158, 0x6a28, 0x928a, 0x007f, 0x1a04, 0x28cf, + 0x9288, 0x26c1, 0x210d, 0x918c, 0x00ff, 0x6156, 0xd0dc, 0x0130, + 0x6828, 0x908a, 0x007f, 0x1a04, 0x28cf, 0x604e, 0x6888, 0x9084, + 0x0030, 0x8004, 0x8004, 0x8004, 0x8004, 0x0006, 0x2009, 0x12c0, + 0x9080, 0x1d8e, 0x2005, 0x200a, 0x000e, 0x2009, 0x12c1, 0x9080, + 0x1d92, 0x2005, 0x200a, 0x6808, 0x908a, 0x0100, 0x0a04, 0x28cf, + 0x908a, 0x0841, 0x1a04, 0x28cf, 0x9084, 0x0007, 0x1904, 0x28cf, + 0x680c, 0x9005, 0x0904, 0x28cf, 0x6810, 0x9005, 0x0904, 0x28cf, + 0x6848, 0x6940, 0x910a, 0x1a04, 0x28cf, 0x8001, 0x0904, 0x28cf, + 0x684c, 0x6944, 0x910a, 0x1a04, 0x28cf, 0x8001, 0x0904, 0x28cf, + 0x6980, 0xd1e4, 0x0140, 0x00c6, 0x2061, 0x0100, 0x6004, 0x9085, + 0x0100, 0x6006, 0x00ce, 0x6814, 0x908c, 0x00ff, 0x613e, 0x8007, + 0x9084, 0x00ff, 0x6042, 0x080c, 0x5a12, 0x080c, 0x4e38, 0x080c, + 0x4e87, 0x6808, 0x602a, 0x080c, 0x1800, 0x2009, 0x0170, 0x200b, + 0x0080, 0xa001, 0xa001, 0x200b, 0x0000, 0x0036, 0x6b08, 0x080c, + 0x1cee, 0x003e, 0x6000, 0x9086, 0x0000, 0x1904, 0x3299, 0x6818, + 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, + 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0148, 0x6830, 0x6934, + 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0010, 0x9084, + 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x8007, 0x810f, 0x8217, + 0x831f, 0x20a9, 0x0004, 0x20a1, 0x12c2, 0x20e9, 0x0001, 0x4001, + 0x080c, 0x6603, 0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, 0x6b70, + 0xd384, 0x01d0, 0x0028, 0x83f5, 0x3e18, 0x12b0, 0x3508, 0x8109, + 0x080c, 0x5f4d, 0x6878, 0x6016, 0x6874, 0x2008, 0x9084, 0xff00, + 0x8007, 0x600a, 0x9184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, + 0x0003, 0x0010, 0x6003, 0x0001, 0x1f04, 0x320b, 0x00ce, 0x00c6, + 0x2061, 0x12bc, 0x6a88, 0x9284, 0xc000, 0x2010, 0x9286, 0x0000, + 0x1118, 0x2063, 0x0000, 0x0058, 0x9286, 0x4000, 0x1118, 0x2063, + 0x0001, 0x0028, 0x9286, 0x8000, 0x1da0, 0x2063, 0x0002, 0x00ce, + 0x6888, 0xd0ec, 0x0130, 0x2011, 0x0114, 0x2204, 0x9085, 0x0100, + 0x2012, 0x6a80, 0x9284, 0x0030, 0x9086, 0x0030, 0x1128, 0x9294, + 0xffcf, 0x9295, 0x0020, 0x6a82, 0x2001, 0x128f, 0x6a80, 0x9294, + 0x0030, 0x928e, 0x0000, 0x0170, 0x928e, 0x0010, 0x0118, 0x928e, + 0x0020, 0x0140, 0x2003, 0xaaaa, 0x080c, 0x1d69, 0x2001, 0x1280, + 0x2102, 0x0008, 0x2102, 0x00c6, 0x2061, 0x0100, 0x602f, 0x0040, + 0x602f, 0x0000, 0x00ce, 0x080c, 0x5745, 0x0128, 0x080c, 0x39e4, + 0x0110, 0x080c, 0x1cb3, 0x60c4, 0x9005, 0x01b0, 0x6003, 0x0001, + 0x2009, 0x3283, 0x00c0, 0x080c, 0x5745, 0x1158, 0x2011, 0x5654, + 0x080c, 0x655b, 0x2001, 0x1290, 0x2003, 0x0000, 0x080c, 0x5682, + 0x0040, 0x080c, 0x45d6, 0x0028, 0x6003, 0x0004, 0x2009, 0x3299, + 0x0010, 0x0804, 0x28a2, 0x2001, 0x0170, 0x2004, 0x9084, 0x00ff, + 0x9086, 0x004c, 0x1118, 0x2091, 0x30bd, 0x0817, 0x2091, 0x303d, + 0x0817, 0x6000, 0x9086, 0x0000, 0x0904, 0x28cc, 0x2069, 0x1152, + 0x7890, 0x6842, 0x7894, 0x6846, 0x2d00, 0x2009, 0x0030, 0x7a8c, + 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804, 0x37c8, 0x9006, + 0x080c, 0x1cb3, 0x81ff, 0x1904, 0x28cc, 0x080c, 0x5745, 0x1178, + 0x2001, 0x1290, 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, + 0x9085, 0x0001, 0x080c, 0x5789, 0x080c, 0x5682, 0x0020, 0x080c, + 0x46e5, 0x080c, 0x45d6, 0x0804, 0x28a2, 0x81ff, 0x1904, 0x28cc, + 0x080c, 0x5745, 0x1110, 0x0804, 0x28cc, 0x6184, 0x81ff, 0x01a8, + 0x703f, 0x0000, 0x2001, 0x1580, 0x2009, 0x0040, 0x7a8c, 0x7b88, + 0x7c9c, 0x7d98, 0x0126, 0x2091, 0x8000, 0x2039, 0x0001, 0x080c, + 0x37c8, 0x701b, 0x28a0, 0x012e, 0x0005, 0x703f, 0x0001, 0x00d6, + 0x2069, 0x1580, 0x20a9, 0x0040, 0x20e9, 0x0001, 0x20a1, 0x1580, + 0x2019, 0xffff, 0x4304, 0x654c, 0x9588, 0x26c1, 0x210d, 0x918c, + 0x00ff, 0x216a, 0x900e, 0x2011, 0x0002, 0x2100, 0x9506, 0x01a8, + 0x080c, 0x4b58, 0x1190, 0x6014, 0x821c, 0x0238, 0x9398, 0x1580, + 0x9085, 0xff00, 0x8007, 0x201a, 0x0038, 0x9398, 0x1580, 0x2324, + 0x94a4, 0xff00, 0x9405, 0x201a, 0x8210, 0x8108, 0x9182, 0x0080, + 0x1208, 0x0c18, 0x8201, 0x8007, 0x2d0c, 0x9105, 0x206a, 0x00de, + 0x20a9, 0x0040, 0x20a1, 0x1580, 0x2099, 0x1580, 0x080c, 0x4678, + 0x0804, 0x32ea, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x00c6, 0x080c, + 0x3784, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, 0x28cc, 0x2001, + 0x1153, 0x2004, 0xd0b4, 0x0550, 0x7884, 0x9084, 0xff00, 0x908e, + 0x7e00, 0x0520, 0x908e, 0x7f00, 0x0508, 0x908e, 0x8000, 0x01f0, + 0x6000, 0xd08c, 0x11d8, 0x6004, 0x9084, 0x00ff, 0x9086, 0x0006, + 0x11a8, 0x6867, 0x0000, 0x6868, 0xc0fd, 0x686a, 0x080c, 0x9744, + 0x1120, 0x2009, 0x0003, 0x0804, 0x28cc, 0x7007, 0x0003, 0x701b, + 0x337a, 0x0005, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x20a9, 0x002b, + 0x20e1, 0x0001, 0x2c98, 0x9de8, 0x0002, 0x20e9, 0x0001, 0x2da0, + 0x4003, 0x20a9, 0x0004, 0x9d80, 0x0006, 0x20a0, 0x9c80, 0x0006, + 0x2098, 0x080c, 0x4678, 0x20a9, 0x0004, 0x9d80, 0x000a, 0x20a0, + 0x9c80, 0x000a, 0x2098, 0x080c, 0x4678, 0x2d00, 0x2009, 0x002b, + 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804, 0x37c8, + 0x81ff, 0x1904, 0x28cc, 0x080c, 0x3799, 0x0904, 0x28cf, 0x080c, + 0x4cb2, 0x0804, 0x28a2, 0x81ff, 0x1904, 0x28cc, 0x7888, 0x908a, + 0x1000, 0x1a04, 0x28cf, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x080c, + 0x4cf1, 0x0904, 0x28cc, 0x2019, 0x0004, 0x080c, 0x4cc4, 0x7984, + 0x810f, 0x7a88, 0x0011, 0x0804, 0x28a2, 0x9186, 0x00ff, 0x0110, + 0x0071, 0x0060, 0x2029, 0x007e, 0x2061, 0x1100, 0x644c, 0x2400, + 0x9506, 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c, + 0x4b58, 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0x9108, 0x080c, + 0x6567, 0x0005, 0x81ff, 0x1904, 0x28cc, 0x080c, 0x3799, 0x0904, + 0x28cf, 0x080c, 0x4c17, 0x0904, 0x28cc, 0x080c, 0x4cbb, 0x0804, + 0x28a2, 0x81ff, 0x1904, 0x28cc, 0x080c, 0x3799, 0x0904, 0x28cf, + 0x080c, 0x4c17, 0x0904, 0x28cc, 0x080c, 0x4ca9, 0x0804, 0x28a2, + 0x6100, 0x0804, 0x28a2, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x6004, + 0x9086, 0x0707, 0x0904, 0x28cf, 0x2001, 0x1100, 0x2004, 0x9086, + 0x0003, 0x1904, 0x28cc, 0x00d6, 0x9ce8, 0x000a, 0x7984, 0xd184, + 0x0110, 0x9ce8, 0x0006, 0x680c, 0x8007, 0x789e, 0x6808, 0x8007, + 0x789a, 0x6b04, 0x831f, 0x6a00, 0x8217, 0x00de, 0x6100, 0x918c, + 0x0200, 0x0804, 0x28a2, 0x7884, 0x909c, 0x00ff, 0x939a, 0x0003, + 0x1a04, 0x28cc, 0x624c, 0x9294, 0x00ff, 0x9084, 0xff00, 0x8007, + 0x9206, 0x1188, 0x2031, 0x1148, 0x2009, 0x013c, 0x2136, 0x2001, + 0x1140, 0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, + 0x0001, 0x0804, 0x37c8, 0x81ff, 0x1904, 0x28cc, 0x080c, 0x37a9, + 0x0904, 0x28cf, 0x6004, 0x9084, 0x00ff, 0x9086, 0x0006, 0x1904, + 0x28cc, 0x00c6, 0x080c, 0x3784, 0x00ce, 0x0904, 0x28cc, 0x6867, + 0x0000, 0x6868, 0xc0fd, 0x686a, 0x080c, 0x96eb, 0x0904, 0x28cc, + 0x7007, 0x0003, 0x701b, 0x3475, 0x0005, 0x6830, 0x9086, 0x0100, + 0x0904, 0x28cc, 0x9d80, 0x001b, 0x2009, 0x000c, 0x7a8c, 0x7b88, + 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804, 0x37c8, 0x9006, 0x080c, + 0x1cb3, 0x7884, 0x9084, 0x00ff, 0x9086, 0x00ff, 0x0118, 0x81ff, + 0x1904, 0x28cc, 0x080c, 0x5745, 0x0110, 0x080c, 0x46e5, 0x7888, + 0x908a, 0x1000, 0x1a04, 0x28cf, 0x7984, 0x918c, 0xff00, 0x810f, + 0x9186, 0x00ff, 0x0138, 0x9182, 0x007f, 0x1a04, 0x28cf, 0x2100, + 0x080c, 0x1c7d, 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2061, + 0x12ef, 0x601b, 0x0000, 0x601f, 0x0000, 0x080c, 0x5745, 0x1178, + 0x2001, 0x1290, 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, + 0x9085, 0x0001, 0x080c, 0x5789, 0x080c, 0x5682, 0x0450, 0x2011, + 0x0003, 0x080c, 0x79c2, 0x2011, 0x0002, 0x080c, 0x79cc, 0x080c, + 0x78b3, 0x080c, 0x65cf, 0x0036, 0x2019, 0x0000, 0x080c, 0x7936, + 0x003e, 0x2061, 0x0100, 0x2001, 0x1114, 0x2004, 0x9084, 0x00ff, + 0x810f, 0x9105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, + 0x12b9, 0x200b, 0x0000, 0x2009, 0x002d, 0x2011, 0x4611, 0x080c, + 0x65e1, 0x7984, 0x918c, 0xff00, 0x810f, 0x080c, 0x5745, 0x1110, + 0x2009, 0x00ff, 0x7a88, 0x080c, 0x33cd, 0x012e, 0x00ce, 0x002e, + 0x0804, 0x28a2, 0x7984, 0x918c, 0xff00, 0x810f, 0x00c6, 0x080c, + 0x4b03, 0x2c08, 0x00ce, 0x1904, 0x28cf, 0x0804, 0x28a2, 0x81ff, + 0x0120, 0x2009, 0x0001, 0x0804, 0x28cc, 0x60cc, 0xd0ac, 0x1130, + 0xd09c, 0x1120, 0x2009, 0x0005, 0x0804, 0x28cc, 0x080c, 0x3784, + 0x1120, 0x2009, 0x0002, 0x0804, 0x28cc, 0x7984, 0x7a8c, 0x7b88, + 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x080c, 0x37c5, 0x701b, 0x3531, + 0x0005, 0x2009, 0x0080, 0x080c, 0x4b58, 0x1130, 0x6004, 0x9084, + 0x00ff, 0x9086, 0x0006, 0x0120, 0x2021, 0x400a, 0x0804, 0x28a4, + 0x00d6, 0x9de8, 0x0019, 0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, + 0x6e18, 0x6820, 0x90be, 0x0100, 0x0904, 0x35a8, 0x90be, 0x0112, + 0x0904, 0x35a8, 0x90be, 0x0113, 0x0904, 0x35a8, 0x90be, 0x0114, + 0x0904, 0x35a8, 0x90be, 0x0117, 0x0904, 0x35a8, 0x90be, 0x011a, + 0x0904, 0x35a8, 0x90be, 0x011c, 0x0904, 0x35a8, 0x90be, 0x0121, + 0x05b0, 0x90be, 0x0131, 0x0598, 0x90be, 0x0171, 0x05c8, 0x90be, + 0x0173, 0x05b0, 0x90be, 0x01a1, 0x1120, 0x6830, 0x8007, 0x6832, + 0x04a8, 0x90be, 0x0212, 0x0540, 0x90be, 0x0213, 0x0528, 0x90be, + 0x0214, 0x01b0, 0x90be, 0x0217, 0x0168, 0x90be, 0x021a, 0x1120, + 0x6838, 0x8007, 0x683a, 0x00e0, 0x90be, 0x0300, 0x01c8, 0x00de, + 0x0804, 0x28cf, 0x9d80, 0x0010, 0x20a9, 0x0007, 0x080c, 0x35ee, + 0x9d80, 0x000e, 0x20a9, 0x0001, 0x080c, 0x35ee, 0x0048, 0x9d80, + 0x000c, 0x080c, 0x35fc, 0x0050, 0x9d80, 0x000e, 0x080c, 0x35fc, + 0x9d80, 0x000c, 0x20a9, 0x0001, 0x080c, 0x35ee, 0x00c6, 0x080c, + 0x3784, 0x0568, 0x6868, 0xc0fd, 0x686a, 0x6867, 0x0119, 0x6883, + 0x0000, 0x687f, 0x0020, 0x688b, 0x0001, 0x810b, 0x69ae, 0x68b3, + 0x0000, 0x6ab6, 0x6bba, 0x6cbe, 0x6dc2, 0x69c6, 0x68cb, 0x0000, + 0x00ce, 0x00de, 0x6867, 0x0000, 0x6868, 0xc0fd, 0x686a, 0x6823, + 0x0000, 0x6804, 0x2068, 0x080c, 0x9707, 0x1120, 0x2009, 0x0003, + 0x0804, 0x28cc, 0x7007, 0x0003, 0x701b, 0x35e5, 0x0005, 0x00ce, + 0x00de, 0x2009, 0x0002, 0x0804, 0x28cc, 0x6820, 0x9086, 0x8001, + 0x1904, 0x28a2, 0x2009, 0x0004, 0x0804, 0x28cc, 0x0016, 0x2008, + 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, + 0x1f04, 0x35f0, 0x001e, 0x0005, 0x0016, 0x00a6, 0x00b6, 0x2008, + 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, + 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x00be, 0x00ae, + 0x001e, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x28cc, + 0x7984, 0x2140, 0x918c, 0xff00, 0x810f, 0x60cc, 0xd0ac, 0x1120, + 0x9182, 0x0080, 0x0a04, 0x28cf, 0x9182, 0x00ff, 0x1a04, 0x28cf, + 0x7a8c, 0x7b88, 0x606c, 0x9306, 0x1140, 0x6070, 0x924e, 0x0904, + 0x28cf, 0x99cc, 0xff00, 0x0904, 0x28cf, 0x00c6, 0x080c, 0x36d2, + 0x2c68, 0x00ce, 0x0538, 0x90c6, 0x4000, 0x1180, 0x00c6, 0x0006, + 0x2d60, 0x2009, 0x0000, 0x080c, 0x4d21, 0x1108, 0xc185, 0x6000, + 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce, 0x0088, 0x90c6, 0x4007, + 0x1110, 0x2408, 0x0060, 0x90c6, 0x4008, 0x1118, 0x2708, 0x2610, + 0x0030, 0x90c6, 0x4009, 0x1108, 0x0010, 0x2001, 0x4006, 0x2020, + 0x0804, 0x28a4, 0x2d00, 0x7022, 0x0016, 0x00b6, 0x00c6, 0x00e6, + 0x2c70, 0x080c, 0x7ec8, 0x05d8, 0x2d00, 0x6012, 0x080c, 0x99cc, + 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, 0x3784, 0x00ce, 0x2b70, + 0x1150, 0x080c, 0x7f1e, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x2009, + 0x0002, 0x0804, 0x28cc, 0x6867, 0x0000, 0x686b, 0x0000, 0x2d00, + 0x6016, 0x6833, 0x0000, 0x6868, 0xc0fd, 0xd88c, 0x0108, 0xc0f5, + 0x686a, 0x0126, 0x2091, 0x8000, 0x080c, 0x25ad, 0x012e, 0x6023, + 0x0001, 0x2001, 0x0000, 0x080c, 0x4aa1, 0x2001, 0x0002, 0x080c, + 0x4ab3, 0x2009, 0x0002, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x00ee, + 0x00ce, 0x00be, 0x001e, 0x1120, 0x2009, 0x0003, 0x0804, 0x28cc, + 0x7007, 0x0003, 0x701b, 0x36b5, 0x0005, 0x6830, 0x9086, 0x0100, + 0x7020, 0x2060, 0x1138, 0x2009, 0x0004, 0x6204, 0x9294, 0x00ff, + 0x0804, 0x28cc, 0x2009, 0x0000, 0x6868, 0xd0f4, 0x1904, 0x28a2, + 0x080c, 0x4d21, 0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, + 0x0804, 0x28a2, 0x00e6, 0x00d6, 0x2029, 0x0000, 0x2001, 0x1133, + 0x2004, 0xd0ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, + 0x1000, 0x0030, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, 0x1080, + 0x2e04, 0x9005, 0x1130, 0x2100, 0x9406, 0x1570, 0x2428, 0xc5fd, + 0x0458, 0x2068, 0x6f10, 0x2700, 0x9306, 0x11b0, 0x6e14, 0x2600, + 0x9206, 0x1190, 0x2400, 0x9106, 0x1160, 0x2d60, 0xd884, 0x0568, + 0x6004, 0x9084, 0x00ff, 0x9086, 0x0006, 0x1538, 0x2001, 0x4000, + 0x0428, 0x2001, 0x4007, 0x0410, 0x2400, 0x9106, 0x1168, 0x6e14, + 0x87ff, 0x1138, 0x86ff, 0x09d0, 0x2001, 0x1133, 0x2004, 0xd0ac, + 0x19a8, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04, 0x36e8, + 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001, 0x0030, + 0x080c, 0x4b03, 0x1dd0, 0x6312, 0x6216, 0x9006, 0x9005, 0x00de, + 0x00ee, 0x0005, 0x81ff, 0x1904, 0x28cc, 0x080c, 0x3784, 0x0904, + 0x28cc, 0x6867, 0x0000, 0x6868, 0xc0fd, 0x686a, 0x7884, 0x9005, + 0x0904, 0x28cf, 0x9096, 0x00ff, 0x0120, 0x9092, 0x0004, 0x1a04, + 0x28cf, 0x2010, 0x2d18, 0x080c, 0x2562, 0x0904, 0x28cc, 0x7007, + 0x0003, 0x701b, 0x3754, 0x0005, 0x6830, 0x9086, 0x0100, 0x0904, + 0x28cc, 0x0804, 0x28a2, 0x7984, 0x918c, 0xff00, 0x810f, 0x60cc, + 0xd0ac, 0x1120, 0x9182, 0x0080, 0x0a04, 0x28cf, 0x9182, 0x00ff, + 0x1a04, 0x28cf, 0x0126, 0x2091, 0x8000, 0x080c, 0x9602, 0x1188, + 0x9190, 0x1000, 0x2204, 0x9065, 0x0160, 0x080c, 0x472d, 0x2001, + 0x1133, 0x2004, 0xd0ac, 0x0110, 0x6017, 0x0000, 0x012e, 0x0804, + 0x28a2, 0x012e, 0x0804, 0x28cc, 0x080c, 0x0ddf, 0x0188, 0x9006, + 0x6802, 0x7010, 0x9005, 0x1120, 0x2d00, 0x7012, 0x7016, 0x0030, + 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0x9d80, 0x0019, + 0x0005, 0x7984, 0x810f, 0x918c, 0x00ff, 0x080c, 0x4b58, 0x1130, + 0x7e88, 0x9684, 0x3fff, 0x9082, 0x4000, 0x0208, 0x9066, 0x8cff, + 0x0005, 0x7e84, 0x860f, 0x918c, 0x00ff, 0x080c, 0x4b58, 0x1128, + 0x96b4, 0x00ff, 0x9682, 0x4000, 0x0208, 0x9066, 0x8cff, 0x0005, + 0x0016, 0x7110, 0x81ff, 0x0128, 0x2168, 0x6904, 0x080c, 0x0df6, + 0x0cc8, 0x7112, 0x7116, 0x001e, 0x0005, 0x2031, 0x0001, 0x0010, + 0x2031, 0x0000, 0x2061, 0x11e3, 0x6606, 0x6116, 0x670e, 0x6012, + 0x622a, 0x632e, 0x6432, 0x6536, 0x2c10, 0x080c, 0x0e55, 0x7007, + 0x0002, 0x701b, 0x28a2, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000, + 0x2079, 0x0000, 0x2001, 0x11a1, 0x2004, 0x9005, 0x1158, 0x0e04, + 0x37f2, 0x7a36, 0x7833, 0x0012, 0x7a82, 0x7b86, 0x7c8a, 0x2091, + 0x4080, 0x0408, 0x0016, 0x00c6, 0x00e6, 0x2071, 0x1193, 0x7138, + 0x9182, 0x0010, 0x0218, 0x7030, 0x2060, 0x0078, 0x7030, 0x90e0, + 0x0004, 0x9c82, 0x11e3, 0x0210, 0x2061, 0x11a3, 0x2c00, 0x7032, + 0x81ff, 0x1108, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, + 0x00ee, 0x00ce, 0x001e, 0x012e, 0x00fe, 0x0005, 0x00e6, 0x2071, + 0x1193, 0x7038, 0x9005, 0x0560, 0x0126, 0x2091, 0x8000, 0x0e04, + 0x3847, 0x00f6, 0x2079, 0x0000, 0x00c6, 0x7034, 0x2060, 0x2c04, + 0x7836, 0x7833, 0x0012, 0x7882, 0x6004, 0x7886, 0x6008, 0x788a, + 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, 0x9005, 0x1130, 0x7033, + 0x11a3, 0x7037, 0x11a3, 0x00ce, 0x0048, 0x9c80, 0x0004, 0x90fa, + 0x11e3, 0x0210, 0x2001, 0x11a3, 0x7036, 0x00ce, 0x00fe, 0x012e, + 0x00ee, 0x0005, 0x0026, 0x2001, 0x1153, 0x2004, 0xd0c4, 0x0120, + 0x2011, 0x8014, 0x080c, 0x37dc, 0x002e, 0x0005, 0x81ff, 0x1904, + 0x28cc, 0x0126, 0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac, + 0x6032, 0x080c, 0x5745, 0x1178, 0x2001, 0x1290, 0x2003, 0x0001, + 0x2001, 0x1100, 0x2003, 0x0001, 0x9085, 0x0001, 0x080c, 0x5789, + 0x080c, 0x5682, 0x0010, 0x080c, 0x45d6, 0x012e, 0x0804, 0x28a2, + 0x7884, 0x2008, 0x918c, 0xfffd, 0x1128, 0x61d8, 0x910d, 0x61da, + 0x0804, 0x28a2, 0x0804, 0x28cf, 0x81ff, 0x1904, 0x28cc, 0x6000, + 0x9086, 0x0003, 0x1904, 0x28cc, 0x2001, 0x1153, 0x2004, 0xd0ac, + 0x1904, 0x28cc, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x6004, 0x9084, + 0x00ff, 0x9086, 0x0006, 0x1120, 0x7888, 0x9005, 0x0904, 0x28a2, + 0x00c6, 0x080c, 0x3784, 0x00ce, 0x0904, 0x28cc, 0x6867, 0x0000, + 0x6833, 0x0000, 0x6868, 0xc0fd, 0x686a, 0x080c, 0x97e0, 0x0904, + 0x28cc, 0x7007, 0x0003, 0x701b, 0x38b6, 0x0005, 0x6830, 0x9086, + 0x0100, 0x0904, 0x28cc, 0x0804, 0x28a2, 0x2001, 0x1100, 0x2004, + 0x9086, 0x0003, 0x1904, 0x28cc, 0x7f84, 0x7a8c, 0x7b88, 0x7c9c, + 0x7d98, 0x080c, 0x3784, 0x0904, 0x28cc, 0x2009, 0x0000, 0x2031, + 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0x9d80, 0x0005, 0x7026, + 0x20a0, 0x20e1, 0x0001, 0x20e9, 0x0001, 0x080c, 0x4b58, 0x1904, + 0x3937, 0x6004, 0x90c4, 0x00ff, 0x98c6, 0x0006, 0x0130, 0x90c4, + 0xff00, 0x98c6, 0x0600, 0x1904, 0x3937, 0x2001, 0x1153, 0x2004, + 0xd0ac, 0x1130, 0x080c, 0x4d21, 0x1118, 0xd79c, 0x0904, 0x3937, + 0xd794, 0x1110, 0xd784, 0x0158, 0x9c80, 0x0006, 0x2098, 0x3400, + 0x20a9, 0x0004, 0x4003, 0x080c, 0x35fc, 0xd794, 0x0148, 0x9c80, + 0x000a, 0x2098, 0x3400, 0x20a9, 0x0004, 0x4003, 0x080c, 0x35fc, + 0x21a2, 0x3400, 0x8000, 0x20a0, 0xd794, 0x01d8, 0x9c80, 0x0000, + 0x2098, 0x20a9, 0x0002, 0x4003, 0x9c80, 0x0003, 0x2098, 0x20a9, + 0x0001, 0x4005, 0x9c80, 0x0004, 0x2098, 0x3400, 0x20a9, 0x0002, + 0x4003, 0x080c, 0x35ee, 0x9c80, 0x0026, 0x2098, 0x20a9, 0x0002, + 0x4003, 0xd794, 0x0110, 0x96b0, 0x000b, 0x96b0, 0x0005, 0x8108, + 0x2001, 0x1133, 0x2004, 0xd0ac, 0x0118, 0x9186, 0x0100, 0x0040, + 0xd78c, 0x0120, 0x9186, 0x0100, 0x0170, 0x0018, 0x9186, 0x007e, + 0x0150, 0xd794, 0x0118, 0x9686, 0x0020, 0x0010, 0x9686, 0x0028, + 0x0150, 0x0804, 0x38d9, 0x86ff, 0x1120, 0x7120, 0x810b, 0x0804, + 0x28a2, 0x702f, 0x0001, 0x711e, 0x7020, 0x9600, 0x7022, 0x772a, + 0x2061, 0x11e3, 0x6007, 0x0000, 0x6616, 0x7024, 0x600f, 0x0001, + 0x6012, 0x622a, 0x632e, 0x6432, 0x6536, 0x2c10, 0x080c, 0x0e55, + 0x7007, 0x0002, 0x701b, 0x3975, 0x0005, 0x702c, 0x9005, 0x1170, + 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, 0x11e3, + 0x6228, 0x632c, 0x6430, 0x6534, 0x0804, 0x38d9, 0x7120, 0x810b, + 0x0804, 0x28a2, 0x2029, 0x007e, 0x7984, 0x7a88, 0x7b8c, 0x7c98, + 0x9184, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x28cf, 0x9502, + 0x0a04, 0x28cf, 0x9184, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x28cf, + 0x9502, 0x0a04, 0x28cf, 0x9284, 0xff00, 0x8007, 0x90e2, 0x0020, + 0x0a04, 0x28cf, 0x9502, 0x0a04, 0x28cf, 0x9284, 0x00ff, 0x90e2, + 0x0020, 0x0a04, 0x28cf, 0x9502, 0x0a04, 0x28cf, 0x9384, 0xff00, + 0x8007, 0x90e2, 0x0020, 0x0a04, 0x28cf, 0x9502, 0x0a04, 0x28cf, + 0x9384, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x28cf, 0x9502, 0x0a04, + 0x28cf, 0x9484, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x28cf, + 0x9502, 0x0a04, 0x28cf, 0x9484, 0x00ff, 0x90e2, 0x0020, 0x0a04, + 0x28cf, 0x9502, 0x0a04, 0x28cf, 0x2061, 0x12a9, 0x6102, 0x6206, + 0x630a, 0x640e, 0x0804, 0x28a2, 0x0006, 0x2001, 0x1153, 0x2004, + 0xd0cc, 0x000e, 0x0005, 0x0006, 0x2001, 0x1172, 0x2004, 0xd0bc, + 0x000e, 0x0005, 0x6164, 0x7a84, 0x6300, 0x82ff, 0x1118, 0x7986, + 0x0804, 0x28a2, 0x83ff, 0x1904, 0x28cf, 0x2001, 0xfff0, 0x9200, + 0x1a04, 0x28cf, 0x2019, 0xffff, 0x6068, 0x9302, 0x9200, 0x0a04, + 0x28cf, 0x7986, 0x6266, 0x0804, 0x28a2, 0x2001, 0x1100, 0x2004, + 0x9086, 0x0003, 0x1904, 0x28cc, 0x7c88, 0x7d84, 0x7e98, 0x7f8c, + 0x080c, 0x3784, 0x0904, 0x28cc, 0x2009, 0x0000, 0x2019, 0x0000, + 0x7023, 0x0000, 0x702f, 0x0000, 0x9d80, 0x0003, 0x7026, 0x20a0, + 0x91e0, 0x1000, 0x2c64, 0x8cff, 0x01d8, 0x6004, 0x9084, 0x00ff, + 0x9086, 0x0006, 0x0130, 0x6004, 0x9084, 0xff00, 0x9086, 0x0600, + 0x1178, 0x00d6, 0x3468, 0x6014, 0x206a, 0x8d68, 0x6010, 0x8007, + 0x9105, 0x8007, 0x206a, 0x8d68, 0x2da0, 0x00de, 0x9398, 0x0002, + 0x8108, 0x9182, 0x00ff, 0x0120, 0x9386, 0x002a, 0x0148, 0x08c0, + 0x83ff, 0x1120, 0x7120, 0x810c, 0x0804, 0x28a2, 0x702f, 0x0001, + 0x711e, 0x7020, 0x9300, 0x7022, 0x2061, 0x11e3, 0x6007, 0x0000, + 0x6316, 0x7024, 0x600f, 0x0001, 0x6012, 0x642a, 0x652e, 0x6632, + 0x6736, 0x2c10, 0x080c, 0x0e55, 0x7007, 0x0002, 0x701b, 0x3a71, + 0x0005, 0x702c, 0x9005, 0x1168, 0x711c, 0x7024, 0x20a0, 0x2019, + 0x0000, 0x2061, 0x11e3, 0x6428, 0x652c, 0x6630, 0x6734, 0x0804, + 0x3a28, 0x7120, 0x810c, 0x0804, 0x28a2, 0x81ff, 0x1904, 0x28cc, + 0x60cc, 0xd0ac, 0x1118, 0xd09c, 0x0904, 0x28cc, 0x080c, 0x3784, + 0x0904, 0x28cc, 0x7984, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, + 0x0001, 0x080c, 0x37c5, 0x701b, 0x3a9e, 0x0005, 0x00d6, 0x9de8, + 0x0019, 0x6828, 0x90be, 0x7000, 0x0148, 0x90be, 0x7100, 0x0130, + 0x90be, 0x7200, 0x0118, 0x00de, 0x0804, 0x28cf, 0x6820, 0x6924, + 0x080c, 0x1c69, 0x1510, 0x080c, 0x4b03, 0x11f8, 0x7122, 0x6612, + 0x6516, 0x6e18, 0x00c6, 0x080c, 0x3784, 0x01b8, 0x080c, 0x3784, + 0x01a0, 0x00ce, 0x00de, 0x6867, 0x0000, 0x6868, 0xc0fd, 0x686a, + 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, 0x9728, 0x0904, 0x28cc, + 0x7007, 0x0003, 0x701b, 0x3ad8, 0x0005, 0x00de, 0x0804, 0x28cc, + 0x7120, 0x080c, 0x26a3, 0x6820, 0x9086, 0x8001, 0x0904, 0x28cc, + 0x2d00, 0x701e, 0x6804, 0x9080, 0x0002, 0x0006, 0x20a9, 0x002a, + 0x2098, 0x20a0, 0x080c, 0x4678, 0x000e, 0x9de8, 0x0019, 0x6a08, + 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0x11e3, 0x6007, 0x0000, 0x6e00, + 0x6f28, 0x97c6, 0x7000, 0x1108, 0x0018, 0x97c6, 0x7100, 0x1150, + 0x96c2, 0x0004, 0x0a04, 0x28cf, 0x2009, 0x0004, 0x2039, 0x0001, + 0x0804, 0x37c8, 0x97c6, 0x7200, 0x1904, 0x28cf, 0x96c2, 0x0054, + 0x0a04, 0x28cf, 0x600f, 0x0001, 0x6012, 0x6017, 0x002a, 0x622a, + 0x632e, 0x6432, 0x6536, 0x2c10, 0x080c, 0x0e55, 0x7007, 0x0002, + 0x701b, 0x3b23, 0x0005, 0x701c, 0x2068, 0x6804, 0x9080, 0x0001, + 0x2004, 0x9080, 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, + 0x080c, 0x4678, 0x000e, 0x2009, 0x002a, 0x2061, 0x11e3, 0x6228, + 0x632c, 0x6430, 0x6534, 0x2039, 0x0001, 0x0804, 0x37c8, 0x81ff, + 0x1904, 0x28cc, 0x080c, 0x3799, 0x0904, 0x28cf, 0x080c, 0x4c17, + 0x0904, 0x28cc, 0x080c, 0x4ccd, 0x0804, 0x28a2, 0x7884, 0xd084, + 0x0904, 0x3342, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x00c6, 0x080c, + 0x3784, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, 0x28cc, 0x6004, + 0x9084, 0x00ff, 0x9086, 0x0006, 0x0128, 0x908e, 0x0004, 0x0110, + 0x908e, 0x0005, 0x1580, 0x2001, 0x1153, 0x2004, 0xd0b4, 0x0904, + 0x337e, 0x7884, 0x9084, 0xff00, 0x908e, 0x7e00, 0x0904, 0x337e, + 0x908e, 0x7f00, 0x0904, 0x337e, 0x908e, 0x8000, 0x0904, 0x337e, + 0x6000, 0xd08c, 0x1904, 0x337e, 0x6867, 0x0000, 0x6868, 0xc0fd, + 0x686a, 0x080c, 0x9744, 0x1120, 0x2009, 0x0003, 0x0804, 0x28cc, + 0x7007, 0x0003, 0x701b, 0x3b95, 0x0005, 0x080c, 0x37a9, 0x0904, + 0x28cf, 0x0804, 0x337e, 0x2009, 0x1130, 0x210c, 0x81ff, 0x0120, + 0x2009, 0x0001, 0x0804, 0x28cc, 0x2001, 0x1100, 0x2004, 0x9086, + 0x0003, 0x0120, 0x2009, 0x0007, 0x0804, 0x28cc, 0x2001, 0x1153, + 0x2004, 0xd0ac, 0x0120, 0x2009, 0x0008, 0x0804, 0x28cc, 0x609c, + 0xd0a4, 0x1118, 0xd0ac, 0x1904, 0x337e, 0x6867, 0x0000, 0x6833, + 0x0000, 0x6868, 0xc0fd, 0x686a, 0x080c, 0x97e0, 0x1120, 0x2009, + 0x0003, 0x0804, 0x28cc, 0x7007, 0x0003, 0x701b, 0x3bd0, 0x0005, + 0x6830, 0x9086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x28cc, + 0x080c, 0x37a9, 0x0904, 0x28cf, 0x0804, 0x3b6b, 0x81ff, 0x2009, + 0x0001, 0x1904, 0x28cc, 0x6000, 0x9086, 0x0003, 0x2009, 0x0007, + 0x1904, 0x28cc, 0x2001, 0x1153, 0x2004, 0xd0ac, 0x2009, 0x0008, + 0x1904, 0x28cc, 0x080c, 0x37a9, 0x0904, 0x28cf, 0x6004, 0x9084, + 0x00ff, 0x9086, 0x0006, 0x2009, 0x0009, 0x1904, 0x28cc, 0x00c6, + 0x080c, 0x3784, 0x00ce, 0x2009, 0x0002, 0x0904, 0x28cc, 0x6867, + 0x0000, 0x6833, 0x0000, 0x6868, 0xc0fd, 0x686a, 0x7988, 0x9194, + 0xff00, 0x918c, 0x00ff, 0x9006, 0x82ff, 0x1128, 0xc0ed, 0x6952, + 0x798c, 0x6956, 0x0048, 0x928e, 0x0100, 0x1904, 0x28cf, 0xc0e5, + 0x6853, 0x0000, 0x6857, 0x0000, 0x683e, 0x080c, 0x99cd, 0x2009, + 0x0003, 0x0904, 0x28cc, 0x7007, 0x0003, 0x701b, 0x3c30, 0x0005, + 0x6830, 0x9086, 0x0100, 0x2009, 0x0004, 0x0904, 0x28cc, 0x0804, + 0x28a2, 0x81ff, 0x2009, 0x0001, 0x1904, 0x28cc, 0x6000, 0x9086, + 0x0003, 0x2009, 0x0007, 0x1904, 0x28cc, 0x080c, 0x37a9, 0x0904, + 0x28cf, 0x6004, 0x9084, 0x00ff, 0x9086, 0x0006, 0x2009, 0x0009, + 0x1904, 0x28cc, 0x00c6, 0x080c, 0x3784, 0x00ce, 0x2009, 0x0002, + 0x0904, 0x28cc, 0x9d80, 0x001b, 0x2009, 0x0008, 0x7a8c, 0x7b88, + 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x080c, 0x37c5, 0x701b, 0x3c69, + 0x0005, 0x00d6, 0x9de8, 0x001b, 0x6800, 0x9086, 0x0500, 0x1140, + 0x6804, 0x9005, 0x1128, 0x6808, 0x9084, 0xff00, 0x1108, 0x0018, + 0x00de, 0x1904, 0x28cf, 0x00de, 0x6867, 0x0000, 0x6833, 0x0000, + 0x6868, 0xc0fd, 0x686a, 0x00c6, 0x080c, 0x37a9, 0x1118, 0x00ce, + 0x0804, 0x28cf, 0x080c, 0x9a1c, 0x2009, 0x0003, 0x00ce, 0x0904, + 0x28cc, 0x7007, 0x0003, 0x701b, 0x3c96, 0x0005, 0x6830, 0x9086, + 0x0100, 0x2009, 0x0004, 0x0904, 0x28cc, 0x0804, 0x28a2, 0x81ff, + 0x0120, 0x2009, 0x0001, 0x0804, 0x28cc, 0x6000, 0x9086, 0x0003, + 0x0120, 0x2009, 0x0007, 0x0804, 0x28cc, 0x7e84, 0x860f, 0x918c, + 0x00ff, 0x96b4, 0x00ff, 0x080c, 0x4b58, 0x1904, 0x28cf, 0x9186, + 0x007f, 0x0150, 0x6004, 0x9084, 0x00ff, 0x9086, 0x0006, 0x0120, + 0x2009, 0x0009, 0x0804, 0x28cc, 0x00c6, 0x080c, 0x3784, 0x00ce, + 0x1120, 0x2009, 0x0002, 0x0804, 0x28cc, 0x6867, 0x0000, 0x6868, + 0xc0fd, 0x686a, 0x080c, 0x975f, 0x1120, 0x2009, 0x0003, 0x0804, + 0x28cc, 0x7007, 0x0003, 0x701b, 0x3cde, 0x0005, 0x6808, 0x8007, + 0x9086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x28cc, 0x68e0, + 0x6866, 0x6810, 0x8007, 0x9084, 0x00ff, 0x800c, 0x6814, 0x8007, + 0x9084, 0x00ff, 0x8004, 0x9080, 0x0002, 0x9108, 0x9d80, 0x0004, + 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804, 0x37c8, + 0x080c, 0x3784, 0x1120, 0x2009, 0x0002, 0x0804, 0x28cc, 0x7984, + 0x9194, 0xff00, 0x918c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804, + 0x28cf, 0x2009, 0x001a, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x080c, + 0x37c5, 0x701b, 0x3d1c, 0x0005, 0x9d80, 0x0019, 0x2098, 0x20a9, + 0x001a, 0x20a1, 0x12c2, 0x20e1, 0x0001, 0x20e9, 0x0001, 0x4003, + 0x0804, 0x28a2, 0x080c, 0x3784, 0x1120, 0x2009, 0x0002, 0x0804, + 0x28cc, 0x7984, 0x9194, 0xff00, 0x918c, 0x00ff, 0x8217, 0x82ff, + 0x0110, 0x0804, 0x28cf, 0x2099, 0x12c2, 0x20a0, 0x20a9, 0x001a, + 0x20e1, 0x0001, 0x20e9, 0x0001, 0x4003, 0x2009, 0x001a, 0x7a8c, + 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804, 0x37c8, 0x7884, + 0x908a, 0x1000, 0x1a04, 0x28cf, 0x0126, 0x2091, 0x8000, 0x8003, + 0x800b, 0x810b, 0x9108, 0x00c6, 0x2061, 0x12ef, 0x6142, 0x00ce, + 0x012e, 0x0804, 0x28a2, 0x00c6, 0x080c, 0x5745, 0x1188, 0x2001, + 0x1290, 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, 0x9085, + 0x0001, 0x080c, 0x5789, 0x080c, 0x5682, 0x080c, 0x0cf1, 0x0038, + 0x2061, 0x1100, 0x6030, 0xc09d, 0x6032, 0x080c, 0x45d6, 0x00ce, + 0x0005, 0x00c6, 0x2001, 0x1100, 0x2004, 0x908e, 0x0000, 0x0904, + 0x28cc, 0x7884, 0x9005, 0x0188, 0x7888, 0x2061, 0x12bc, 0x2c0c, + 0x2062, 0x080c, 0x203d, 0x01a0, 0x080c, 0x2045, 0x0188, 0x080c, + 0x204d, 0x0170, 0x2162, 0x0804, 0x28cf, 0x2061, 0x0100, 0x6038, + 0x9086, 0x0007, 0x1118, 0x2009, 0x0001, 0x0010, 0x2009, 0x0000, + 0x7884, 0x9086, 0x0002, 0x1568, 0x2061, 0x0100, 0x6028, 0xc09c, + 0x602a, 0x0026, 0x2011, 0x0003, 0x080c, 0x79c2, 0x2011, 0x0002, + 0x080c, 0x79cc, 0x002e, 0x080c, 0x78b3, 0x080c, 0x65cf, 0x0036, + 0x2019, 0x0000, 0x080c, 0x7936, 0x003e, 0x60e3, 0x0000, 0x080c, + 0xadf2, 0x080c, 0xae0d, 0x9085, 0x0001, 0x080c, 0x5789, 0x2001, + 0x0140, 0x2003, 0x0000, 0x2001, 0x1100, 0x2003, 0x0004, 0x6027, + 0x0008, 0x00ce, 0x0804, 0x28a2, 0x81ff, 0x0120, 0x2009, 0x0001, + 0x0804, 0x28cc, 0x6000, 0x9086, 0x0003, 0x0120, 0x2009, 0x0007, + 0x0804, 0x28cc, 0x7e84, 0x860f, 0x918c, 0x00ff, 0x96b4, 0x00ff, + 0x080c, 0x4b58, 0x1904, 0x28cf, 0x9186, 0x007f, 0x0150, 0x6004, + 0x9084, 0x00ff, 0x9086, 0x0006, 0x0120, 0x2009, 0x0009, 0x0804, + 0x28cc, 0x00c6, 0x080c, 0x3784, 0x00ce, 0x1120, 0x2009, 0x0002, + 0x0804, 0x28cc, 0x6867, 0x0000, 0x6868, 0xc0fd, 0x686a, 0x080c, + 0x977b, 0x1120, 0x2009, 0x0003, 0x0804, 0x28cc, 0x7007, 0x0003, + 0x701b, 0x3e1b, 0x0005, 0x6830, 0x9086, 0x0100, 0x1120, 0x2009, + 0x0004, 0x0804, 0x28cc, 0x68e0, 0x6866, 0x6834, 0x8007, 0x800c, + 0x9d80, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, + 0x0804, 0x37c8, 0x0126, 0x2091, 0x8000, 0x00c6, 0x2061, 0x12ef, + 0x7984, 0x6152, 0x614e, 0x6057, 0x0000, 0x604b, 0x0009, 0x7898, + 0x606a, 0x789c, 0x6066, 0x7888, 0x6062, 0x788c, 0x605e, 0x2061, + 0x1291, 0x2001, 0x1304, 0x6012, 0x600f, 0x0001, 0x6017, 0x0001, + 0x601b, 0x0002, 0x6007, 0x0000, 0x603b, 0x0000, 0x00ce, 0x012e, + 0x0804, 0x28a2, 0x0126, 0x0156, 0x0136, 0x0146, 0x01c6, 0x01d6, + 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2061, 0x0100, 0x2069, 0x0200, + 0x2071, 0x1100, 0x6044, 0xd0a4, 0x11e8, 0xd084, 0x0118, 0x080c, + 0x3ff0, 0x0068, 0xd08c, 0x0118, 0x080c, 0x3f00, 0x0040, 0xd094, + 0x0118, 0x080c, 0x3ed3, 0x0018, 0xd09c, 0x0108, 0x0099, 0x00fe, + 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e, 0x013e, 0x015e, + 0x012e, 0x0005, 0x0016, 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, + 0x001e, 0x0c68, 0x624c, 0x9286, 0xf0f0, 0x1150, 0x6048, 0x9086, + 0xf0f0, 0x0130, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0490, + 0x9294, 0xff00, 0x9296, 0xf700, 0x0178, 0x7134, 0xd1a4, 0x1160, + 0x6240, 0x9295, 0x0100, 0x6242, 0x9294, 0x0010, 0x0128, 0x2009, + 0x00f7, 0x080c, 0x46a4, 0x00f0, 0x6040, 0x9084, 0x0010, 0x9085, + 0x0140, 0x6042, 0x6043, 0x0000, 0x7077, 0x0000, 0x7093, 0x0001, + 0x70b7, 0x0000, 0x70cf, 0x0000, 0x2009, 0x1580, 0x200b, 0x0000, + 0x7087, 0x0000, 0x707b, 0x000f, 0x2009, 0x000f, 0x2011, 0x457f, + 0x080c, 0x65e1, 0x0005, 0x2001, 0x1174, 0x2004, 0xd08c, 0x0110, + 0x704f, 0xffff, 0x7078, 0x9005, 0x1510, 0x2011, 0x457f, 0x080c, + 0x655b, 0x6040, 0x9094, 0x0010, 0x9285, 0x0020, 0x6042, 0x20a9, + 0x00c8, 0x6044, 0xd08c, 0x1168, 0x1f04, 0x3ee9, 0x6242, 0x708b, + 0x0000, 0x6040, 0x9094, 0x0010, 0x9285, 0x0080, 0x6042, 0x6242, + 0x0030, 0x6242, 0x708b, 0x0000, 0x707f, 0x0000, 0x0000, 0x0005, + 0x707c, 0x908a, 0x0003, 0x1210, 0x0023, 0x0010, 0x080c, 0x0cf1, + 0x0005, 0x3f0c, 0x3f54, 0x3fef, 0x00f6, 0x707f, 0x0001, 0x6803, + 0x00fc, 0x20a9, 0x0004, 0x6800, 0x9084, 0x00fc, 0x0120, 0x1f04, + 0x3f13, 0x080c, 0x0cf1, 0x68a0, 0x68a2, 0x689c, 0x689e, 0x6898, + 0x689a, 0xa001, 0x6803, 0x1600, 0x6837, 0x0020, 0x080c, 0x4702, + 0x2079, 0x1500, 0x7833, 0x1101, 0x7837, 0x0000, 0x20e1, 0x0001, + 0x2099, 0x1105, 0x20e9, 0x0001, 0x20a1, 0x150e, 0x20a9, 0x0004, + 0x4003, 0x080c, 0x7e9b, 0x20e1, 0x0001, 0x2099, 0x1500, 0x20e9, + 0x0000, 0x20a1, 0x0240, 0x20a9, 0x0014, 0x4003, 0x60c3, 0x000c, + 0x600f, 0x0000, 0x080c, 0x45b2, 0x00fe, 0x7083, 0x0000, 0x6043, + 0x0008, 0x6043, 0x0000, 0x0005, 0x00f6, 0x7080, 0x7083, 0x0000, + 0x9025, 0x0904, 0x3fcc, 0x6020, 0xd0b4, 0x1904, 0x3fca, 0x7190, + 0x81ff, 0x0904, 0x3fb8, 0x9486, 0x000c, 0x1904, 0x3fc5, 0x9480, + 0x0018, 0x8004, 0x20a8, 0x080c, 0x46fa, 0x2011, 0x0260, 0x2019, + 0x1500, 0x220c, 0x2304, 0x9106, 0x11e8, 0x8210, 0x8318, 0x1f04, + 0x3f71, 0x6043, 0x0004, 0x2061, 0x0140, 0x605b, 0xbc94, 0x605f, + 0xf0f0, 0x2061, 0x0100, 0x6043, 0x0006, 0x707f, 0x0002, 0x708b, + 0x0002, 0x2009, 0x07d0, 0x2011, 0x4586, 0x080c, 0x65e1, 0x080c, + 0x4702, 0x04c0, 0x080c, 0x46fa, 0x2079, 0x0260, 0x7930, 0x918e, + 0x1101, 0x1558, 0x7834, 0x9005, 0x1540, 0x7900, 0x918c, 0x00ff, + 0x1118, 0x7804, 0x9005, 0x0190, 0x080c, 0x46fa, 0x2011, 0x026e, + 0x2019, 0x1105, 0x20a9, 0x0004, 0x220c, 0x2304, 0x9102, 0x0230, + 0x11a0, 0x8210, 0x8318, 0x1f04, 0x3fac, 0x0078, 0x7093, 0x0000, + 0x080c, 0x46fa, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0001, + 0x20a1, 0x1500, 0x20a9, 0x0014, 0x4003, 0x6043, 0x0008, 0x6043, + 0x0000, 0x0010, 0x00fe, 0x0005, 0x6040, 0x9085, 0x0100, 0x6042, + 0x6020, 0xd0b4, 0x1db8, 0x080c, 0x7e9b, 0x20e1, 0x0001, 0x2099, + 0x1500, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x0014, 0x4003, + 0x60c3, 0x000c, 0x2011, 0x12e6, 0x2013, 0x0000, 0x7083, 0x0000, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x7718, 0x08d8, 0x0005, + 0x7088, 0x908a, 0x001d, 0x1210, 0x0023, 0x0010, 0x080c, 0x0cf1, + 0x0005, 0x4023, 0x4036, 0x4060, 0x4080, 0x40a6, 0x40d5, 0x40fb, + 0x4133, 0x4159, 0x4187, 0x41c0, 0x41f8, 0x4216, 0x4241, 0x4263, + 0x427a, 0x4282, 0x42b4, 0x42da, 0x4309, 0x432f, 0x4367, 0x43a6, + 0x43db, 0x43f9, 0x4452, 0x4474, 0x449e, 0x449f, 0x00c6, 0x2061, + 0x1100, 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0x9084, 0xfff9, + 0x6006, 0x00ce, 0x0005, 0x2061, 0x0140, 0x605b, 0xbc94, 0x605f, + 0xf0f0, 0x2061, 0x0100, 0x6043, 0x0002, 0x708b, 0x0001, 0x2009, + 0x07d0, 0x2011, 0x4586, 0x080c, 0x65e1, 0x0005, 0x00f6, 0x7080, + 0x9086, 0x0014, 0x1518, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x11f0, + 0x080c, 0x46fa, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1102, 0x11a0, + 0x7834, 0x9005, 0x1188, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0x9005, + 0x1110, 0x70b7, 0x0001, 0x2011, 0x4586, 0x080c, 0x655b, 0x708b, + 0x0010, 0x080c, 0x4282, 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, + 0x00f6, 0x708b, 0x0003, 0x6043, 0x0004, 0x2011, 0x4586, 0x080c, + 0x655b, 0x080c, 0x4686, 0x2079, 0x0240, 0x7833, 0x1102, 0x7837, + 0x0000, 0x20a9, 0x0008, 0x9f88, 0x000e, 0x200b, 0x0000, 0x8108, + 0x1f04, 0x4075, 0x60c3, 0x0014, 0x080c, 0x45b2, 0x00fe, 0x0005, + 0x00f6, 0x7080, 0x9005, 0x0500, 0x2011, 0x4586, 0x080c, 0x655b, + 0x9086, 0x0014, 0x11b8, 0x080c, 0x46fa, 0x2079, 0x0260, 0x7a30, + 0x9296, 0x1102, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, + 0x0128, 0x70b4, 0x9005, 0x1110, 0x70b7, 0x0001, 0x708b, 0x0004, + 0x0029, 0x0010, 0x080c, 0x46d6, 0x00fe, 0x0005, 0x00f6, 0x708b, + 0x0005, 0x080c, 0x4686, 0x2079, 0x0240, 0x7833, 0x1103, 0x7837, + 0x0000, 0x080c, 0x46fa, 0x080c, 0x46dd, 0x1170, 0x7074, 0x9005, + 0x1158, 0x714c, 0x9186, 0xffff, 0x0138, 0x2011, 0x0008, 0x080c, + 0x4532, 0x0168, 0x080c, 0x46bb, 0x20a9, 0x0008, 0x20e1, 0x0000, + 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, + 0x0014, 0x080c, 0x45b2, 0x00fe, 0x0005, 0x00f6, 0x7080, 0x9005, + 0x0500, 0x2011, 0x4586, 0x080c, 0x655b, 0x9086, 0x0014, 0x11b8, + 0x080c, 0x46fa, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1103, 0x1178, + 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0x9005, + 0x1110, 0x70b7, 0x0001, 0x708b, 0x0006, 0x0029, 0x0010, 0x080c, + 0x46d6, 0x00fe, 0x0005, 0x00f6, 0x708b, 0x0007, 0x080c, 0x4686, + 0x2079, 0x0240, 0x7833, 0x1104, 0x7837, 0x0000, 0x080c, 0x46fa, + 0x080c, 0x46dd, 0x11b8, 0x7074, 0x9005, 0x11a0, 0x7154, 0x9186, + 0xffff, 0x0180, 0x9180, 0x26c1, 0x200d, 0x918c, 0xff00, 0x810f, + 0x2011, 0x0008, 0x080c, 0x4532, 0x0180, 0x080c, 0x39eb, 0x0110, + 0x080c, 0x1cb3, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, + 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, + 0x45b2, 0x00fe, 0x0005, 0x00f6, 0x7080, 0x9005, 0x0500, 0x2011, + 0x4586, 0x080c, 0x655b, 0x9086, 0x0014, 0x11b8, 0x080c, 0x46fa, + 0x2079, 0x0260, 0x7a30, 0x9296, 0x1104, 0x1178, 0x7834, 0x9005, + 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0x9005, 0x1110, 0x70b7, + 0x0001, 0x708b, 0x0008, 0x0029, 0x0010, 0x080c, 0x46d6, 0x00fe, + 0x0005, 0x00f6, 0x708b, 0x0009, 0x080c, 0x4686, 0x2079, 0x0240, + 0x7833, 0x1105, 0x7837, 0x0100, 0x080c, 0x46dd, 0x1150, 0x7074, + 0x9005, 0x1138, 0x080c, 0x44a0, 0x1188, 0x9085, 0x0001, 0x080c, + 0x1cb3, 0x20a9, 0x0008, 0x080c, 0x46fa, 0x20e1, 0x0000, 0x2099, + 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, + 0x080c, 0x45b2, 0x0010, 0x080c, 0x4016, 0x00fe, 0x0005, 0x00f6, + 0x7080, 0x9005, 0x0598, 0x2011, 0x4586, 0x080c, 0x655b, 0x9086, + 0x0014, 0x1550, 0x080c, 0x46fa, 0x2079, 0x0260, 0x7a30, 0x9296, + 0x1105, 0x1510, 0x7834, 0x2011, 0x0100, 0x921e, 0x1160, 0x7a38, + 0xd2fc, 0x0128, 0x70b4, 0x9005, 0x1110, 0x70b7, 0x0001, 0x708b, + 0x000a, 0x00b1, 0x0098, 0x9005, 0x1178, 0x7a38, 0xd2fc, 0x0128, + 0x70b4, 0x9005, 0x1110, 0x70b7, 0x0001, 0x7087, 0x0000, 0x708b, + 0x000e, 0x080c, 0x4263, 0x0010, 0x080c, 0x46d6, 0x00fe, 0x0005, + 0x00f6, 0x708b, 0x000b, 0x2011, 0x150e, 0x20e9, 0x0001, 0x22a0, + 0x20a9, 0x0040, 0x2019, 0xffff, 0x4304, 0x080c, 0x4686, 0x2079, + 0x0240, 0x7833, 0x1106, 0x7837, 0x0000, 0x080c, 0x46dd, 0x0118, + 0x2013, 0x0000, 0x0020, 0x7050, 0x9085, 0x0100, 0x2012, 0x20a9, + 0x0040, 0x2009, 0x024e, 0x2011, 0x150e, 0x220e, 0x8210, 0x8108, + 0x9186, 0x0260, 0x1128, 0x6810, 0x8000, 0x6812, 0x2009, 0x0240, + 0x1f04, 0x41e5, 0x60c3, 0x0084, 0x080c, 0x45b2, 0x00fe, 0x0005, + 0x00f6, 0x7080, 0x9005, 0x01c0, 0x2011, 0x4586, 0x080c, 0x655b, + 0x9086, 0x0084, 0x1178, 0x080c, 0x46fa, 0x2079, 0x0260, 0x7a30, + 0x9296, 0x1106, 0x1138, 0x7834, 0x9005, 0x1120, 0x708b, 0x000c, + 0x0029, 0x0010, 0x080c, 0x46d6, 0x00fe, 0x0005, 0x00f6, 0x708b, + 0x000d, 0x080c, 0x4686, 0x2079, 0x0240, 0x7833, 0x1107, 0x7837, + 0x0000, 0x080c, 0x46fa, 0x20a9, 0x0040, 0x2011, 0x026e, 0x2009, + 0x024e, 0x220e, 0x8210, 0x8108, 0x9186, 0x0260, 0x1150, 0x6810, + 0x8000, 0x6812, 0x2009, 0x0240, 0x6814, 0x8000, 0x6816, 0x2011, + 0x0260, 0x1f04, 0x4229, 0x60c3, 0x0084, 0x080c, 0x45b2, 0x00fe, + 0x0005, 0x00f6, 0x7080, 0x9005, 0x01e0, 0x2011, 0x4586, 0x080c, + 0x655b, 0x9086, 0x0084, 0x1198, 0x080c, 0x46fa, 0x2079, 0x0260, + 0x7a30, 0x9296, 0x1107, 0x1158, 0x7834, 0x9005, 0x1140, 0x7087, + 0x0001, 0x080c, 0x4658, 0x708b, 0x000e, 0x0029, 0x0010, 0x080c, + 0x46d6, 0x00fe, 0x0005, 0x708b, 0x000f, 0x7083, 0x0000, 0x2061, + 0x0140, 0x605b, 0xbc85, 0x605f, 0xb5b5, 0x2061, 0x0100, 0x6043, + 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x4586, 0x080c, + 0x654f, 0x0005, 0x7080, 0x9005, 0x0120, 0x2011, 0x4586, 0x080c, + 0x655b, 0x0005, 0x708b, 0x0011, 0x080c, 0x7e9b, 0x080c, 0x46fa, + 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000, 0x20a1, 0x0240, + 0x7480, 0x9480, 0x0018, 0x9080, 0x0007, 0x9084, 0x03f8, 0x8004, + 0x20a8, 0x4003, 0x080c, 0x46dd, 0x1190, 0x716c, 0x81ff, 0x0178, + 0x2009, 0x0000, 0x7070, 0x9084, 0x00ff, 0x0148, 0x080c, 0x1c69, + 0x9186, 0x0080, 0x0120, 0x2011, 0x0008, 0x080c, 0x4532, 0x60c3, + 0x0014, 0x080c, 0x45b2, 0x0005, 0x00f6, 0x7080, 0x9005, 0x0500, + 0x2011, 0x4586, 0x080c, 0x655b, 0x9086, 0x0014, 0x11b8, 0x080c, + 0x46fa, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1103, 0x1178, 0x7834, + 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0x9005, 0x1110, + 0x70b7, 0x0001, 0x708b, 0x0012, 0x0029, 0x0010, 0x7083, 0x0000, + 0x00fe, 0x0005, 0x00f6, 0x708b, 0x0013, 0x080c, 0x4694, 0x2079, + 0x0240, 0x7833, 0x1103, 0x7837, 0x0000, 0x080c, 0x46fa, 0x080c, + 0x46dd, 0x1170, 0x7074, 0x9005, 0x1158, 0x714c, 0x9186, 0xffff, + 0x0138, 0x2011, 0x0008, 0x080c, 0x4532, 0x0168, 0x080c, 0x46bb, + 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, + 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x45b2, 0x00fe, + 0x0005, 0x00f6, 0x7080, 0x9005, 0x0500, 0x2011, 0x4586, 0x080c, + 0x655b, 0x9086, 0x0014, 0x11b8, 0x080c, 0x46fa, 0x2079, 0x0260, + 0x7a30, 0x9296, 0x1104, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, + 0xd2fc, 0x0128, 0x70b4, 0x9005, 0x1110, 0x70b7, 0x0001, 0x708b, + 0x0014, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, 0x00f6, + 0x708b, 0x0015, 0x080c, 0x4694, 0x2079, 0x0240, 0x7833, 0x1104, + 0x7837, 0x0000, 0x080c, 0x46fa, 0x080c, 0x46dd, 0x11b8, 0x7074, + 0x9005, 0x11a0, 0x7154, 0x9186, 0xffff, 0x0180, 0x9180, 0x26c1, + 0x200d, 0x918c, 0xff00, 0x810f, 0x2011, 0x0008, 0x080c, 0x4532, + 0x0180, 0x080c, 0x39eb, 0x0110, 0x080c, 0x1cb3, 0x20a9, 0x0008, + 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, + 0x4003, 0x60c3, 0x0014, 0x080c, 0x45b2, 0x00fe, 0x0005, 0x00f6, + 0x7080, 0x9005, 0x05c8, 0x2011, 0x4586, 0x080c, 0x655b, 0x9086, + 0x0014, 0x1580, 0x080c, 0x46fa, 0x2079, 0x0260, 0x7a30, 0x9296, + 0x1105, 0x1540, 0x7834, 0x2011, 0x0100, 0x921e, 0x1148, 0x7a38, + 0xd2fc, 0x0128, 0x70b4, 0x9005, 0x1110, 0x70b7, 0x0001, 0x0060, + 0x9005, 0x11c0, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0x9005, 0x1110, + 0x70b7, 0x0001, 0x7087, 0x0000, 0x7a38, 0xd2f4, 0x0138, 0x2001, + 0x1174, 0x2004, 0xd0a4, 0x1110, 0x70cf, 0x0008, 0x708b, 0x0016, + 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, 0x080c, 0x7e9b, + 0x080c, 0x46fa, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000, + 0x20a1, 0x0240, 0x20a9, 0x000e, 0x4003, 0x2011, 0x026e, 0x708b, + 0x0017, 0x080c, 0x46dd, 0x1150, 0x7074, 0x9005, 0x1138, 0x080c, + 0x44a0, 0x1188, 0x9085, 0x0001, 0x080c, 0x1cb3, 0x20a9, 0x0008, + 0x080c, 0x46fa, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, + 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x45b2, 0x0010, + 0x080c, 0x4016, 0x0005, 0x00f6, 0x7080, 0x9005, 0x01c0, 0x2011, + 0x4586, 0x080c, 0x655b, 0x9086, 0x0084, 0x1178, 0x080c, 0x46fa, + 0x2079, 0x0260, 0x7a30, 0x9296, 0x1106, 0x1138, 0x7834, 0x9005, + 0x1120, 0x708b, 0x0018, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, + 0x0005, 0x00f6, 0x708b, 0x0019, 0x080c, 0x4694, 0x2079, 0x0240, + 0x7833, 0x1106, 0x7837, 0x0000, 0x080c, 0x46fa, 0x2009, 0x026e, + 0x2039, 0x150e, 0x20a9, 0x0040, 0x213e, 0x8738, 0x8108, 0x9186, + 0x0280, 0x1128, 0x6814, 0x8000, 0x6816, 0x2009, 0x0260, 0x1f04, + 0x440c, 0x2039, 0x150e, 0x080c, 0x46dd, 0x11e8, 0x2728, 0x2514, + 0x8207, 0x9084, 0x00ff, 0x8000, 0x2018, 0x9294, 0x00ff, 0x8007, + 0x9205, 0x202a, 0x7050, 0x2310, 0x8214, 0x92a0, 0x150e, 0x2414, + 0x938c, 0x0001, 0x0118, 0x9294, 0xff00, 0x0018, 0x9294, 0x00ff, + 0x8007, 0x9215, 0x2222, 0x20a9, 0x0040, 0x2009, 0x024e, 0x270e, + 0x8738, 0x8108, 0x9186, 0x0260, 0x1128, 0x6810, 0x8000, 0x6812, + 0x2009, 0x0240, 0x1f04, 0x443f, 0x60c3, 0x0084, 0x080c, 0x45b2, + 0x00fe, 0x0005, 0x00f6, 0x7080, 0x9005, 0x01e0, 0x2011, 0x4586, + 0x080c, 0x655b, 0x9086, 0x0084, 0x1198, 0x080c, 0x46fa, 0x2079, + 0x0260, 0x7a30, 0x9296, 0x1107, 0x1158, 0x7834, 0x9005, 0x1140, + 0x7087, 0x0001, 0x080c, 0x4658, 0x708b, 0x001a, 0x0029, 0x0010, + 0x7083, 0x0000, 0x00fe, 0x0005, 0x708b, 0x001b, 0x080c, 0x7e9b, + 0x080c, 0x46fa, 0x2011, 0x0260, 0x2009, 0x0240, 0x7480, 0x9480, + 0x0018, 0x9080, 0x0007, 0x9084, 0x03f8, 0x8004, 0x20a8, 0x220e, + 0x8210, 0x8108, 0x9186, 0x0260, 0x1150, 0x6810, 0x8000, 0x6812, + 0x2009, 0x0240, 0x6814, 0x8000, 0x6816, 0x2011, 0x0260, 0x1f04, + 0x4487, 0x60c3, 0x0084, 0x080c, 0x45b2, 0x0005, 0x0005, 0x0005, + 0x0086, 0x0096, 0x2029, 0x1153, 0x252c, 0x20a9, 0x0008, 0x2041, + 0x150e, 0x20e9, 0x0001, 0x28a0, 0x080c, 0x46fa, 0x20e1, 0x0000, + 0x2099, 0x026e, 0x4003, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, + 0x0110, 0x2011, 0x0000, 0x2800, 0x9200, 0x200c, 0x91a6, 0xffff, + 0x1148, 0xd5d4, 0x0110, 0x8210, 0x0008, 0x8211, 0x1f04, 0x44bb, + 0x0804, 0x452a, 0x82ff, 0x1160, 0xd5d4, 0x0120, 0x91a6, 0x3fff, + 0x0d90, 0x0020, 0x91a6, 0x3fff, 0x0904, 0x452a, 0x918d, 0xc000, + 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4, 0x0110, 0x2019, 0x0010, + 0x2120, 0xd5d4, 0x0110, 0x8423, 0x0008, 0x8424, 0x1240, 0xd5d4, + 0x0110, 0x8319, 0x0008, 0x8318, 0x1f04, 0x44e1, 0x04d8, 0x23a8, + 0x2021, 0x0001, 0x8426, 0x8425, 0x1f04, 0x44f3, 0x2328, 0x8529, + 0x92be, 0x0007, 0x0158, 0x0006, 0x2039, 0x0007, 0x2200, 0x973a, + 0x000e, 0x27a8, 0x95a8, 0x0010, 0x1f04, 0x4502, 0x754e, 0x95c8, + 0x26c1, 0x292d, 0x95ac, 0x00ff, 0x7572, 0x6532, 0x6536, 0x0016, + 0x2508, 0x080c, 0x1c93, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x2018, + 0x2304, 0x9405, 0x201a, 0x7077, 0x0001, 0x20e9, 0x0000, 0x20a1, + 0x024e, 0x20e1, 0x0001, 0x2898, 0x20a9, 0x0008, 0x4003, 0x9085, + 0x0001, 0x0028, 0x9006, 0x0018, 0x9006, 0x080c, 0x0cf1, 0x009e, + 0x008e, 0x0005, 0x0156, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x22a8, + 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x2011, 0x024e, + 0x22a0, 0x4003, 0x014e, 0x013e, 0x01de, 0x01ce, 0x015e, 0x2118, + 0x2021, 0x0000, 0x2001, 0x0007, 0x939a, 0x0010, 0x0218, 0x8420, + 0x8001, 0x0cd0, 0x2118, 0x84ff, 0x0120, 0x939a, 0x0010, 0x8421, + 0x1de0, 0x2021, 0x0001, 0x83ff, 0x0118, 0x8423, 0x8319, 0x1de8, + 0x9238, 0x2029, 0x026e, 0x9528, 0x2504, 0x942c, 0x11b8, 0x9405, + 0x203a, 0x714e, 0x91a0, 0x26c1, 0x242d, 0x95ac, 0x00ff, 0x7572, + 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x1c93, 0x001e, 0x60e7, + 0x0000, 0x65ea, 0x7077, 0x0001, 0x9084, 0x0000, 0x0005, 0x00e6, + 0x2071, 0x1100, 0x707b, 0x0000, 0x00ee, 0x0005, 0x00e6, 0x00f6, + 0x2079, 0x0100, 0x2071, 0x0140, 0x080c, 0x4647, 0x080c, 0x7721, + 0x7004, 0x9084, 0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, + 0x0126, 0x2091, 0x8000, 0x2071, 0x1122, 0x2073, 0x0000, 0x7840, + 0x0026, 0x0016, 0x2009, 0x00f7, 0x080c, 0x46a4, 0x001e, 0x9094, + 0x0010, 0x9285, 0x0080, 0x7842, 0x7a42, 0x002e, 0x012e, 0x00fe, + 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x2011, 0x12e6, 0x2013, + 0x0000, 0x7083, 0x0000, 0x012e, 0x60a3, 0x0056, 0x60a7, 0x9575, + 0x080c, 0x7718, 0x6144, 0xd184, 0x0120, 0x7188, 0x918d, 0x2000, + 0x0018, 0x717c, 0x918d, 0x1000, 0x2011, 0x12b9, 0x2112, 0x2009, + 0x07d0, 0x2011, 0x4586, 0x080c, 0x65e1, 0x0005, 0x0016, 0x0026, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x2011, 0x0003, 0x080c, 0x79c2, + 0x2011, 0x0002, 0x080c, 0x79cc, 0x080c, 0x78b3, 0x080c, 0x65cf, + 0x0036, 0x2019, 0x0000, 0x080c, 0x7936, 0x003e, 0x2009, 0x00f7, + 0x080c, 0x46a4, 0x2061, 0x12ef, 0x601b, 0x0000, 0x601f, 0x0000, + 0x2061, 0x1100, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, + 0x6043, 0x0010, 0x2009, 0x12b9, 0x200b, 0x0000, 0x2009, 0x002d, + 0x2011, 0x4611, 0x080c, 0x654f, 0x012e, 0x00ce, 0x002e, 0x001e, + 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x0481, 0x2071, + 0x0100, 0x080c, 0x7721, 0x2071, 0x0140, 0x7004, 0x9084, 0x4000, + 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, 0x574d, 0x01a8, + 0x080c, 0x576b, 0x1190, 0x2001, 0x128f, 0x2003, 0xaaaa, 0x0016, + 0x080c, 0x1d69, 0x2001, 0x1280, 0x2102, 0x001e, 0x2001, 0x1290, + 0x2003, 0x0000, 0x080c, 0x5682, 0x0030, 0x2001, 0x0001, 0x080c, + 0x1c36, 0x080c, 0x45d6, 0x012e, 0x000e, 0x00ee, 0x0005, 0x2001, + 0x110d, 0x2004, 0xd0bc, 0x0158, 0x0026, 0x0036, 0x2011, 0x8017, + 0x2001, 0x12b9, 0x201c, 0x080c, 0x37dc, 0x003e, 0x002e, 0x0005, + 0x20a9, 0x0012, 0x20e9, 0x0001, 0x20a1, 0x1580, 0x080c, 0x46fa, + 0x20e9, 0x0000, 0x2099, 0x026e, 0x0099, 0x20a9, 0x0020, 0x080c, + 0x46f4, 0x2099, 0x0260, 0x20a1, 0x1592, 0x0051, 0x20a9, 0x000e, + 0x080c, 0x46f7, 0x2099, 0x0260, 0x20a1, 0x15b2, 0x0009, 0x0005, + 0x0016, 0x0026, 0x3410, 0x3308, 0x2104, 0x8007, 0x2012, 0x8108, + 0x8210, 0x1f04, 0x467c, 0x002e, 0x001e, 0x0005, 0x080c, 0x7e9b, + 0x20e1, 0x0001, 0x2099, 0x1500, 0x20e9, 0x0000, 0x20a1, 0x0240, + 0x20a9, 0x000c, 0x4003, 0x0005, 0x080c, 0x7e9b, 0x080c, 0x46fa, + 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000, 0x20a1, 0x0240, + 0x20a9, 0x000c, 0x4003, 0x0005, 0x00c6, 0x0006, 0x2061, 0x0100, + 0x810f, 0x2001, 0x1130, 0x2004, 0x9005, 0x1138, 0x2001, 0x1114, + 0x2004, 0x9084, 0x00ff, 0x9105, 0x0010, 0x9185, 0x00f7, 0x604a, + 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x2001, 0x1153, 0x2004, + 0xd0a4, 0x0158, 0x9006, 0x2020, 0x2009, 0x002a, 0x080c, 0xaaca, + 0x2001, 0x110c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, + 0x0000, 0x080c, 0x2582, 0x004e, 0x001e, 0x0005, 0x080c, 0x45d6, + 0x708b, 0x0000, 0x7083, 0x0000, 0x0005, 0x0006, 0x2001, 0x110c, + 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006, 0x0016, 0x0126, + 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0x918d, 0x0006, 0x2102, + 0x012e, 0x001e, 0x000e, 0x0005, 0x2009, 0x0001, 0x0028, 0x2009, + 0x0002, 0x0010, 0x2009, 0x0000, 0x6814, 0x9084, 0xffc0, 0x910d, + 0x6916, 0x0005, 0x00f6, 0x0156, 0x0146, 0x01d6, 0x9006, 0x20a9, + 0x0080, 0x20e9, 0x0001, 0x20a1, 0x1500, 0x4004, 0x2079, 0x1500, + 0x7803, 0x2200, 0x7807, 0x00ef, 0x780f, 0x00ef, 0x7813, 0x0138, + 0x7823, 0xffff, 0x7827, 0xffff, 0x01de, 0x014e, 0x015e, 0x00fe, + 0x0005, 0x0156, 0x20a9, 0x00ff, 0x2009, 0x1000, 0x9006, 0x200a, + 0x8108, 0x1f04, 0x4727, 0x015e, 0x0005, 0x00d6, 0x0036, 0x0156, + 0x0136, 0x0146, 0x2069, 0x1152, 0x9006, 0x6002, 0x6007, 0x0707, + 0x600a, 0x600e, 0x6012, 0x9198, 0x26c1, 0x231d, 0x939c, 0x00ff, + 0x6316, 0x20a9, 0x0004, 0x9c98, 0x0006, 0x20e9, 0x0001, 0x23a0, + 0x4004, 0x20a9, 0x0004, 0x9c98, 0x000a, 0x23a0, 0x4004, 0x603e, + 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, 0x6066, + 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x608a, 0x608e, 0x6092, + 0x6096, 0x609a, 0x609e, 0x60ae, 0x61a2, 0x00d6, 0x60a4, 0x906d, + 0x0110, 0x080c, 0x0df6, 0x60a7, 0x0000, 0x00de, 0x9006, 0x604a, + 0x6810, 0x603a, 0x680c, 0x6046, 0x6814, 0x9084, 0x00ff, 0x6042, + 0x014e, 0x013e, 0x015e, 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, + 0x8000, 0x6974, 0x6e78, 0x9684, 0x3fff, 0x9082, 0x4000, 0x1a04, + 0x47f0, 0x918c, 0xff00, 0x810f, 0x9182, 0x00ff, 0x1a04, 0x47f5, + 0x2001, 0x110c, 0x2004, 0x9084, 0x0003, 0x1904, 0x47fc, 0x9188, + 0x1000, 0x2104, 0x9065, 0x0508, 0x6004, 0x9084, 0x00ff, 0x908e, + 0x0006, 0x1500, 0x60a4, 0x900d, 0x1904, 0x4811, 0x6050, 0x900d, + 0x1148, 0x6802, 0x2d00, 0x6052, 0x604e, 0x080c, 0x68a3, 0x9006, + 0x012e, 0x0005, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x0ca8, + 0x2001, 0x0005, 0x2009, 0x0000, 0x04e0, 0x2001, 0x0028, 0x2009, + 0x0000, 0x04b8, 0x9082, 0x0006, 0x1298, 0x2001, 0x1133, 0x2004, + 0xd0ac, 0x1158, 0x60a0, 0xd0bc, 0x1140, 0x6100, 0xd1fc, 0x0990, + 0x2001, 0x0029, 0x2009, 0x1000, 0x0420, 0x2001, 0x0028, 0x00a8, + 0x2009, 0x110c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0068, + 0xd184, 0x0118, 0x2001, 0x0004, 0x0040, 0x2001, 0x0029, 0x6100, + 0xd1fc, 0x0118, 0x2009, 0x1000, 0x0060, 0x2009, 0x0000, 0x0048, + 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, + 0x0000, 0x9005, 0x012e, 0x0005, 0x2001, 0x110c, 0x2004, 0xd084, + 0x19b8, 0x9188, 0x1000, 0x2104, 0x9065, 0x0990, 0x6004, 0x9084, + 0x00ff, 0x908e, 0x0006, 0x1960, 0x6000, 0xd0c4, 0x0948, 0x0804, + 0x47a2, 0x080c, 0x4cdc, 0x0904, 0x47b8, 0x0804, 0x47a6, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x6874, 0x8007, 0x9084, 0x00ff, 0x2008, + 0x9182, 0x00ff, 0x1a04, 0x486a, 0x9188, 0x1000, 0x2104, 0x9065, + 0x01c0, 0x6004, 0x9084, 0x00ff, 0x908e, 0x0006, 0x11a8, 0x2c70, + 0x080c, 0x7ec8, 0x05e8, 0x2e00, 0x6012, 0x2d00, 0x6016, 0x600b, + 0xffff, 0x6023, 0x000a, 0x2009, 0x0003, 0x080c, 0x7f4e, 0x9006, + 0x0460, 0x2001, 0x0028, 0x0440, 0x9082, 0x0006, 0x1298, 0x2001, + 0x1133, 0x2004, 0xd0ac, 0x1158, 0x60a0, 0xd0bc, 0x1140, 0x6100, + 0xd1fc, 0x09e8, 0x2001, 0x0029, 0x2009, 0x1000, 0x00a8, 0x2001, + 0x0028, 0x0090, 0x2009, 0x110c, 0x210c, 0xd18c, 0x0118, 0x2001, + 0x0004, 0x0050, 0xd184, 0x0118, 0x2001, 0x0004, 0x0028, 0x2001, + 0x0029, 0x0010, 0x2001, 0x0029, 0x9005, 0x012e, 0x00ee, 0x0005, + 0x2001, 0x002c, 0x0cc8, 0x00f6, 0x00e6, 0x0126, 0x2091, 0x8000, + 0x2011, 0x0000, 0x2079, 0x1100, 0x6974, 0x918c, 0xff00, 0x810f, + 0x9182, 0x00ff, 0x1a04, 0x4a12, 0x2001, 0x110c, 0x2004, 0x9084, + 0x0003, 0x1904, 0x49ff, 0x080c, 0x4b58, 0x1180, 0x6004, 0x9084, + 0x00ff, 0x9082, 0x0006, 0x1250, 0x2001, 0x1133, 0x2004, 0xd0ac, + 0x1904, 0x49f9, 0x60a0, 0xd0bc, 0x1904, 0x49f9, 0x6894, 0x90c6, + 0x006f, 0x0158, 0x90c6, 0x005e, 0x0904, 0x4940, 0x90c6, 0x0064, + 0x0904, 0x4974, 0x2008, 0x0804, 0x4909, 0x6998, 0x2140, 0x918c, + 0xff00, 0x810f, 0x78cc, 0xd0ac, 0x1120, 0x9182, 0x0080, 0x0a04, + 0x4909, 0x9182, 0x00ff, 0x1a04, 0x4909, 0x6aa0, 0x6b9c, 0x786c, + 0x9306, 0x1168, 0x7870, 0x924e, 0x1120, 0x2208, 0x2310, 0x0804, + 0x4909, 0x99cc, 0xff00, 0x1118, 0x2208, 0x2310, 0x04d0, 0x080c, + 0x36d2, 0x2c70, 0x05f0, 0x2009, 0x0000, 0x2011, 0x0000, 0x90c6, + 0x4000, 0x1500, 0x0006, 0x2e60, 0x080c, 0x4d21, 0x1108, 0xc185, + 0x7000, 0xd0bc, 0x0108, 0xc18d, 0x20a9, 0x0004, 0x9d80, 0x0031, + 0x20a0, 0x9e80, 0x0006, 0x2098, 0x080c, 0x4678, 0x20a9, 0x0004, + 0x9d80, 0x0035, 0x20a0, 0x9e80, 0x000a, 0x2098, 0x080c, 0x4678, + 0x000e, 0x0088, 0x90c6, 0x4007, 0x1110, 0x2408, 0x0060, 0x90c6, + 0x4008, 0x1118, 0x2708, 0x2610, 0x0030, 0x90c6, 0x4009, 0x1108, + 0x0010, 0x2001, 0x4006, 0x6896, 0x699a, 0x6a9e, 0x2001, 0x0030, + 0x0450, 0x080c, 0x7ec8, 0x1138, 0x2001, 0x4005, 0x2009, 0x0003, + 0x2011, 0x0000, 0x0c80, 0x2e00, 0x6012, 0x080c, 0x99cc, 0x2d00, + 0x6016, 0x6023, 0x0001, 0x6868, 0xd88c, 0x0108, 0xc0f5, 0x686a, + 0x0126, 0x2091, 0x8000, 0x080c, 0x25ad, 0x012e, 0x2001, 0x0000, + 0x080c, 0x4aa1, 0x2001, 0x0002, 0x080c, 0x4ab3, 0x2009, 0x0002, + 0x080c, 0x7f4e, 0x9006, 0x9005, 0x012e, 0x00ee, 0x00fe, 0x0005, + 0x7800, 0x9086, 0x0003, 0x0118, 0x2009, 0x0007, 0x0448, 0x6e98, + 0x860f, 0x918c, 0x00ff, 0x96b4, 0x00ff, 0x080c, 0x4b58, 0x0120, + 0x2009, 0x000a, 0x0804, 0x4909, 0x9186, 0x007f, 0x0148, 0x6004, + 0x9084, 0x00ff, 0x9086, 0x0006, 0x0118, 0x2009, 0x0009, 0x0080, + 0x00d6, 0x080c, 0x0dc6, 0x1120, 0x00de, 0x2009, 0x0002, 0x0040, + 0x2d00, 0x00de, 0x6806, 0x080c, 0x977b, 0x1960, 0x2009, 0x0003, + 0x2001, 0x4005, 0x0804, 0x490b, 0x6e98, 0x860f, 0x918c, 0x00ff, + 0x96b4, 0x00ff, 0x080c, 0x4b58, 0x0120, 0x2009, 0x000a, 0x0804, + 0x4909, 0x00d6, 0x080c, 0x0dc6, 0x1128, 0x00de, 0x2009, 0x0002, + 0x0804, 0x49dd, 0x2d00, 0x00de, 0x6806, 0x00d6, 0x6804, 0x2068, + 0x20a9, 0x002b, 0x20e1, 0x0001, 0x2c98, 0x9de8, 0x0002, 0x20e9, + 0x0001, 0x2da0, 0x4003, 0x20a9, 0x0004, 0x9d80, 0x0006, 0x20a0, + 0x9c80, 0x0006, 0x2098, 0x080c, 0x4678, 0x20a9, 0x0004, 0x9d80, + 0x000a, 0x20a0, 0x9c80, 0x000a, 0x2098, 0x080c, 0x4678, 0x2d10, + 0x00de, 0x687b, 0x0000, 0x6883, 0x0000, 0x6897, 0x4000, 0xd684, + 0x1170, 0x2001, 0x1153, 0x2004, 0xd0b4, 0x1118, 0x689b, 0x000b, + 0x0400, 0x6000, 0xd08c, 0x0118, 0x689b, 0x000c, 0x00d0, 0x6004, + 0x9084, 0x00ff, 0x9086, 0x0006, 0x0118, 0x689b, 0x0009, 0x0088, + 0x7800, 0x9086, 0x0003, 0x0118, 0x689b, 0x0007, 0x0050, 0x080c, + 0x9744, 0x1904, 0x493a, 0x2009, 0x0003, 0x2001, 0x4005, 0x0804, + 0x490b, 0x687b, 0x0030, 0x6897, 0x4005, 0x2200, 0x2009, 0x002b, + 0x6aa0, 0x6b9c, 0x6ca8, 0x6da4, 0x2031, 0x0000, 0x2039, 0x0001, + 0x2041, 0x0f7e, 0x080c, 0x817f, 0x1904, 0x493a, 0x2009, 0x0002, + 0x0c20, 0x2001, 0x0028, 0x2009, 0x0000, 0x0804, 0x493b, 0x2009, + 0x110c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, + 0x0118, 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x2009, 0x0000, + 0x0804, 0x493b, 0x2001, 0x0029, 0x2009, 0x0000, 0x0804, 0x493b, + 0x6974, 0x6e78, 0x9684, 0x3fff, 0x9082, 0x4000, 0x1658, 0x918c, + 0xff00, 0x810f, 0x9182, 0x00ff, 0x1280, 0x9188, 0x1000, 0x2104, + 0x9065, 0x0158, 0x6004, 0x9084, 0x00ff, 0x908e, 0x0006, 0x1150, + 0x0491, 0x080c, 0x4c6e, 0x9006, 0x00c8, 0x2001, 0x0028, 0x2009, + 0x0000, 0x00a0, 0x9082, 0x0006, 0x1240, 0x6100, 0xd1fc, 0x0d80, + 0x2001, 0x0029, 0x2009, 0x1000, 0x0048, 0x2001, 0x0029, 0x2009, + 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, 0x0000, 0x9005, 0x0005, + 0x0126, 0x2091, 0x8000, 0x6050, 0x900d, 0x0138, 0x2d00, 0x200a, + 0x6803, 0x0000, 0x6052, 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, + 0x6803, 0x0000, 0x0cc0, 0x0126, 0x2091, 0x8000, 0x604c, 0x9005, + 0x0170, 0x00e6, 0x2071, 0x12dc, 0x7004, 0x9086, 0x0002, 0x0168, + 0x00ee, 0x604c, 0x6802, 0x2d00, 0x604e, 0x012e, 0x0005, 0x2d00, + 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, 0x701c, 0x9c06, 0x1d80, + 0x604c, 0x2070, 0x7000, 0x6802, 0x2d00, 0x7002, 0x00ee, 0x012e, + 0x0005, 0x0126, 0x2091, 0x8000, 0x604c, 0x906d, 0x0130, 0x6800, + 0x9005, 0x1108, 0x6052, 0x604e, 0x9d05, 0x012e, 0x0005, 0x604c, + 0x906d, 0x0130, 0x6800, 0x9005, 0x1108, 0x6052, 0x604e, 0x9d05, + 0x0005, 0x0126, 0x00c6, 0x0026, 0x2091, 0x8000, 0x6210, 0x2260, + 0x6200, 0x9005, 0x0110, 0xc285, 0x0008, 0xc284, 0x6202, 0x002e, + 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6210, + 0x2260, 0x6204, 0x0006, 0x9086, 0x0006, 0x1180, 0x609c, 0xd0ac, + 0x0168, 0x2001, 0x1153, 0x2004, 0xd0a4, 0x0140, 0x9284, 0xff00, + 0x8007, 0x9086, 0x0007, 0x1110, 0x2011, 0x0600, 0x000e, 0x9294, + 0xff00, 0x9215, 0x6206, 0x0006, 0x9086, 0x0006, 0x1128, 0x6290, + 0x82ff, 0x1110, 0x080c, 0x0cf1, 0x000e, 0x00ce, 0x012e, 0x0005, + 0x0126, 0x00c6, 0x2091, 0x8000, 0x6210, 0x2260, 0x6204, 0x0006, + 0x9086, 0x0006, 0x1178, 0x609c, 0xd0a4, 0x0160, 0x2001, 0x1153, + 0x2004, 0xd0ac, 0x1138, 0x9284, 0x00ff, 0x9086, 0x0007, 0x1110, + 0x2011, 0x0006, 0x000e, 0x9294, 0x00ff, 0x8007, 0x9215, 0x6206, + 0x00ce, 0x012e, 0x0005, 0x0026, 0x9182, 0x00ff, 0x0218, 0x9085, + 0x0001, 0x00a0, 0x9190, 0x1000, 0x2204, 0x9065, 0x1170, 0x0016, + 0x00d6, 0x080c, 0x0dc6, 0x2d60, 0x00de, 0x001e, 0x0d80, 0x2c00, + 0x2012, 0x60a7, 0x0000, 0x080c, 0x472d, 0x9006, 0x002e, 0x0005, + 0x0126, 0x2091, 0x8000, 0x0026, 0x9182, 0x00ff, 0x0218, 0x9085, + 0x0001, 0x0458, 0x00d6, 0x9190, 0x1000, 0x2204, 0x906d, 0x0518, + 0x2013, 0x0000, 0x00d6, 0x00c6, 0x2d60, 0x60a4, 0x906d, 0x0110, + 0x080c, 0x0df6, 0x00ce, 0x00de, 0x00d6, 0x00c6, 0x68ac, 0x2060, + 0x8cff, 0x0168, 0x600c, 0x0006, 0x6014, 0x2068, 0x080c, 0x95d2, + 0x0110, 0x080c, 0x0e06, 0x080c, 0x7f1e, 0x00ce, 0x0c88, 0x00ce, + 0x00de, 0x080c, 0x0df6, 0x00de, 0x9006, 0x002e, 0x012e, 0x0005, + 0x0016, 0x9182, 0x00ff, 0x0218, 0x9085, 0x0001, 0x0030, 0x9188, + 0x1000, 0x2104, 0x9065, 0x0dc0, 0x9006, 0x001e, 0x0005, 0x00d6, + 0x0156, 0x0136, 0x0146, 0x600b, 0x0000, 0x600f, 0x0000, 0x6000, + 0xc08c, 0x6002, 0x080c, 0x5745, 0x1500, 0x60a0, 0x9086, 0x007e, + 0x0130, 0x2001, 0x1133, 0x2004, 0xd0ac, 0x11b8, 0x0078, 0x7040, + 0xd0e4, 0x0198, 0x00c6, 0x2061, 0x12a2, 0x7048, 0x2062, 0x704c, + 0x6006, 0x7050, 0x600a, 0x7054, 0x600e, 0x00ce, 0x703c, 0x2069, + 0x0140, 0x6886, 0x2069, 0x1100, 0x68a2, 0x7040, 0x605e, 0x7048, + 0x6062, 0x6138, 0x910a, 0x0208, 0x603a, 0x704c, 0x6066, 0x20e1, + 0x0000, 0x2099, 0x0276, 0x9c88, 0x000a, 0x20e9, 0x0001, 0x21a0, + 0x20a9, 0x0004, 0x4003, 0x2099, 0x027a, 0x9c88, 0x0006, 0x21a0, + 0x20a9, 0x0004, 0x4003, 0x2069, 0x0200, 0x6817, 0x0001, 0x7040, + 0x606a, 0x7144, 0x616e, 0x7048, 0x6072, 0x7050, 0x6076, 0x2069, + 0x0200, 0x6817, 0x0000, 0x60a0, 0x9086, 0x007e, 0x1110, 0x7144, + 0x616e, 0x9182, 0x0211, 0x1218, 0x2009, 0x0008, 0x0400, 0x9182, + 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, 0x9182, 0x02c1, 0x1218, + 0x2009, 0x0006, 0x00a0, 0x9182, 0x0349, 0x1218, 0x2009, 0x0005, + 0x0070, 0x9182, 0x0421, 0x1218, 0x2009, 0x0004, 0x0040, 0x9182, + 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, 0x2009, 0x0002, 0x6192, + 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x0016, 0x0026, 0x00e6, + 0x2071, 0x0260, 0x7034, 0x6896, 0x703c, 0x689a, 0x7054, 0x689e, + 0x6a00, 0x2009, 0x1172, 0x210c, 0xd0bc, 0x0120, 0xd1ec, 0x0110, + 0xc2ad, 0x0008, 0xc2ac, 0xd0c4, 0x0120, 0xd1e4, 0x0110, 0xc2bd, + 0x0008, 0xc2bc, 0x6a02, 0x00ee, 0x002e, 0x001e, 0x0005, 0x00d6, + 0x0126, 0x2091, 0x8000, 0x60a4, 0x906d, 0x01c0, 0x6900, 0x81ff, + 0x1540, 0x6a04, 0x9282, 0x0010, 0x1648, 0x9d88, 0x0004, 0x20a9, + 0x0010, 0x2104, 0x9086, 0xffff, 0x0128, 0x8108, 0x1f04, 0x4c29, + 0x080c, 0x0cf1, 0x260a, 0x8210, 0x6a06, 0x0098, 0x080c, 0x0ddf, + 0x01a8, 0x2d00, 0x60a6, 0x6803, 0x0000, 0x9d88, 0x0004, 0x20a9, + 0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, 0x4c41, 0x6807, 0x0001, + 0x6e12, 0x9085, 0x0001, 0x012e, 0x00de, 0x0005, 0x9006, 0x0cd8, + 0x0126, 0x2091, 0x8000, 0x00d6, 0x60a4, 0x900d, 0x01a0, 0x2168, + 0x6800, 0x9005, 0x1160, 0x080c, 0x4cdc, 0x1168, 0x200b, 0xffff, + 0x6804, 0x908a, 0x0002, 0x0218, 0x8001, 0x6806, 0x0020, 0x080c, + 0x0df6, 0x60a7, 0x0000, 0x00de, 0x012e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x080c, 0x68a3, 0x012e, 0x0005, 0x901e, 0x0010, 0x2019, + 0x0001, 0x900e, 0x0126, 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, + 0xd0dc, 0x1170, 0x8dff, 0x01e8, 0x83ff, 0x0120, 0x6878, 0x9606, + 0x0158, 0x0030, 0x686c, 0x9406, 0x1118, 0x6870, 0x9506, 0x0120, + 0x2d08, 0x6800, 0x2068, 0x0c70, 0x6a00, 0x604c, 0x9d06, 0x1110, + 0x624e, 0x0018, 0x9180, 0x0000, 0x2202, 0x82ff, 0x1110, 0x6152, + 0x8dff, 0x012e, 0x0005, 0x9016, 0x0489, 0x1110, 0x2011, 0x0001, + 0x0005, 0x080c, 0x4d21, 0x0118, 0x080c, 0x9685, 0x0010, 0x9085, + 0x0001, 0x0005, 0x080c, 0x4d21, 0x0118, 0x080c, 0x9620, 0x0010, + 0x9085, 0x0001, 0x0005, 0x080c, 0x4d21, 0x0118, 0x080c, 0x9668, + 0x0010, 0x9085, 0x0001, 0x0005, 0x080c, 0x4d21, 0x0118, 0x080c, + 0x963c, 0x0010, 0x9085, 0x0001, 0x0005, 0x080c, 0x4d21, 0x0118, + 0x080c, 0x96a1, 0x0010, 0x9085, 0x0001, 0x0005, 0x60a4, 0x900d, + 0x1118, 0x9085, 0x0001, 0x0005, 0x00e6, 0x2170, 0x7000, 0x9005, + 0x1168, 0x20a9, 0x0010, 0x9e88, 0x0004, 0x2104, 0x9606, 0x0130, + 0x8108, 0x1f04, 0x4ce5, 0x9085, 0x0001, 0x0008, 0x9006, 0x00ee, + 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, 0x906d, 0x1128, + 0x080c, 0x0ddf, 0x01a0, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807, + 0x0000, 0x9d88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, + 0x1f04, 0x4d05, 0x9085, 0x0001, 0x012e, 0x00de, 0x0005, 0x9006, + 0x0cd8, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, 0x906d, 0x0130, + 0x60a7, 0x0000, 0x080c, 0x0df6, 0x9085, 0x0001, 0x012e, 0x00de, + 0x0005, 0x609c, 0xd0a4, 0x0005, 0x00f6, 0x080c, 0x5745, 0x01b0, + 0x71b4, 0x81ff, 0x1198, 0x71cc, 0xd19c, 0x0180, 0x2001, 0x007e, + 0x9080, 0x1000, 0x2004, 0x907d, 0x0148, 0x7804, 0x9084, 0x00ff, + 0x9086, 0x0006, 0x1118, 0x7800, 0xc0ed, 0x7802, 0x2079, 0x1152, + 0x7804, 0xd0a4, 0x01e8, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x0016, 0x080c, 0x4b58, 0x1168, 0x6004, 0x9084, 0xff00, + 0x8007, 0x9096, 0x0004, 0x0118, 0x9086, 0x0006, 0x1118, 0x6000, + 0xc0ed, 0x6002, 0x001e, 0x8108, 0x1f04, 0x4d49, 0x00ce, 0x015e, + 0x080c, 0x4de0, 0x0120, 0x2001, 0x12a5, 0x200c, 0x0038, 0x2079, + 0x1152, 0x7804, 0xd0a4, 0x0130, 0x2009, 0x07d0, 0x2011, 0x4d74, + 0x080c, 0x65e1, 0x00fe, 0x0005, 0x2011, 0x4d74, 0x080c, 0x655b, + 0x080c, 0x4de0, 0x01f0, 0x2001, 0x107e, 0x2004, 0x9080, 0x0000, + 0x200c, 0xc1ec, 0x2102, 0x2001, 0x1153, 0x2004, 0xd0a4, 0x0130, + 0x2009, 0x07d0, 0x2011, 0x4d74, 0x080c, 0x65e1, 0x00e6, 0x2071, + 0x1100, 0x706f, 0x0000, 0x7073, 0x0000, 0x080c, 0x23cd, 0x00ee, + 0x04b0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, + 0x080c, 0x4b58, 0x1530, 0x6000, 0xd0ec, 0x0518, 0x0046, 0x62a0, + 0x9294, 0x00ff, 0x8227, 0x9006, 0x2009, 0x0029, 0x080c, 0xaaca, + 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x6004, 0x9084, 0x00ff, 0x9085, + 0x0700, 0x6006, 0x2019, 0x0029, 0x080c, 0x69ca, 0x0076, 0x2039, + 0x0000, 0x080c, 0x68fe, 0x2009, 0x0000, 0x080c, 0xa85f, 0x007e, + 0x004e, 0x001e, 0x8108, 0x1f04, 0x4d9f, 0x00ce, 0x015e, 0x0005, + 0x00c6, 0x6010, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x00ce, 0x0005, + 0x7810, 0x2004, 0xd0ac, 0x0005, 0x7810, 0x2004, 0xd0bc, 0x0005, + 0x00f6, 0x2001, 0x107e, 0x2004, 0x907d, 0x0110, 0x7800, 0xd0ec, + 0x00fe, 0x0005, 0x0126, 0x0026, 0x2091, 0x8000, 0x6200, 0x9005, + 0x0110, 0xc2fd, 0x0008, 0xc2fc, 0x6202, 0x002e, 0x012e, 0x0005, + 0x2011, 0x1133, 0x2204, 0xd0cc, 0x0138, 0x2001, 0x12a3, 0x200c, + 0x2011, 0x4e05, 0x080c, 0x65e1, 0x0005, 0x2011, 0x4e05, 0x080c, + 0x655b, 0x2011, 0x1133, 0x2204, 0xc0cc, 0x2012, 0x0005, 0x2071, + 0x1228, 0x7003, 0x0001, 0x7007, 0x0000, 0x7013, 0x0000, 0x7017, + 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x700b, 0x0000, 0x7047, + 0x0000, 0x2071, 0x126e, 0x7003, 0x1228, 0x7007, 0x0000, 0x700b, + 0x0000, 0x700f, 0x0001, 0x7013, 0x124e, 0x7017, 0x0020, 0x701b, + 0x0040, 0x703b, 0x0000, 0x2001, 0x124a, 0x2003, 0x0000, 0x0005, + 0x0016, 0x00e6, 0x2071, 0x124b, 0x900e, 0x710a, 0x2001, 0x1153, + 0x2004, 0xd0fc, 0x1148, 0x2001, 0x1153, 0x2004, 0x900e, 0xd09c, + 0x0108, 0x8108, 0x7102, 0x04c0, 0x2001, 0x1172, 0x200c, 0x9184, + 0x000f, 0x0002, 0x4e43, 0x4e43, 0x4e43, 0x4e43, 0x4e43, 0x4e62, + 0x4e43, 0x4e43, 0x4e70, 0x4e43, 0x4e43, 0x4e43, 0x4e43, 0x4e43, + 0x4e43, 0x4e43, 0x7003, 0x0003, 0x2009, 0x1173, 0x210c, 0x9184, + 0xff00, 0x8007, 0x9005, 0x1110, 0x2001, 0x0002, 0x7006, 0x00a0, + 0x7003, 0x0004, 0x0136, 0x0146, 0x0156, 0x20e1, 0x0001, 0x2099, + 0x1176, 0x20e9, 0x0001, 0x20a1, 0x1278, 0x20a9, 0x0004, 0x4003, + 0x015e, 0x014e, 0x013e, 0x0000, 0x00ee, 0x001e, 0x0005, 0x00e6, + 0x2071, 0x0050, 0x684c, 0x9005, 0x1150, 0x00e6, 0x2071, 0x1228, + 0x7028, 0xc085, 0x702a, 0x00ee, 0x9085, 0x0001, 0x04e8, 0x6844, + 0x9005, 0x01a8, 0x2009, 0x0000, 0x0156, 0x20a9, 0x0006, 0x8003, + 0x81f5, 0x3e08, 0x1f04, 0x4e9f, 0x015e, 0x6a60, 0x9200, 0x7002, + 0x6864, 0x9101, 0x7006, 0x7013, 0x0000, 0x7017, 0x0000, 0x6860, + 0x7002, 0x6864, 0x7006, 0x6868, 0x700a, 0x686c, 0x700e, 0x6844, + 0x9005, 0x1120, 0x7013, 0x0000, 0x7017, 0x0000, 0x684c, 0x701a, + 0x701c, 0x9085, 0x0040, 0x701e, 0x7037, 0x0019, 0x702b, 0x0001, + 0x00e6, 0x2071, 0x1228, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, + 0x700b, 0x0000, 0x00ee, 0x9006, 0x00ee, 0x0005, 0x6868, 0xd0fc, + 0x11d0, 0x00e6, 0x0026, 0x2001, 0x124b, 0x2004, 0x9005, 0x0904, + 0x50aa, 0x687c, 0xd0bc, 0x1904, 0x50aa, 0x6978, 0x6874, 0x9105, + 0x1904, 0x50aa, 0x2001, 0x124b, 0x2004, 0x0002, 0x50aa, 0x4f17, + 0x4f4b, 0x4f4b, 0x53ec, 0x0005, 0x6868, 0xd0fc, 0x11f8, 0x00e6, + 0x0026, 0x2009, 0x124b, 0x210c, 0x81ff, 0x0904, 0x50aa, 0x687c, + 0xd0cc, 0x0904, 0x50aa, 0x6880, 0x9084, 0x00ff, 0x9086, 0x0001, + 0x1904, 0x50aa, 0x9186, 0x0003, 0x05f0, 0x9186, 0x0004, 0x0904, + 0x53ec, 0x684f, 0x8021, 0x6853, 0x0017, 0x0028, 0x0005, 0x684f, + 0x8020, 0x6853, 0x0016, 0x2071, 0x1228, 0x701c, 0x9005, 0x1904, + 0x5235, 0x0e04, 0x5278, 0x2071, 0x0000, 0x684c, 0x7082, 0x6850, + 0x7032, 0x686c, 0x7086, 0x7036, 0x6870, 0x708a, 0x2091, 0x4080, + 0x2071, 0x1100, 0x2011, 0x0001, 0x6804, 0x900d, 0x702c, 0x1148, + 0x206a, 0x2d00, 0x702e, 0x70b0, 0x9200, 0x70b2, 0x002e, 0x00ee, + 0x0005, 0x00d6, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, + 0x1dc8, 0x00de, 0x0c68, 0x684f, 0x0000, 0x00f6, 0x2079, 0x0050, + 0x2071, 0x1228, 0x206b, 0x0000, 0x7010, 0x9005, 0x1904, 0x5039, + 0x782c, 0x908c, 0x0780, 0x190c, 0x542a, 0x8004, 0x8004, 0x8004, + 0x9084, 0x0003, 0x0002, 0x4f69, 0x5039, 0x4f8f, 0x4fd2, 0x080c, + 0x0cf1, 0x2071, 0x1100, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x7822, + 0x6804, 0x900d, 0x1170, 0x2071, 0x12ef, 0x703c, 0x9005, 0x1328, + 0x2001, 0x124c, 0x2004, 0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, + 0x0005, 0x9016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, + 0x81ff, 0x1dc8, 0x702e, 0x70b0, 0x9200, 0x70b2, 0x0c20, 0x2071, + 0x1100, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x7822, 0x6804, 0x900d, + 0x1558, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, 0x1118, + 0x7022, 0x00ee, 0x0060, 0x00ee, 0xc0d4, 0x8006, 0x8006, 0x806f, + 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b0, 0x8000, 0x70b2, 0x782c, + 0x9094, 0x0780, 0x190c, 0x542a, 0xd0a4, 0x1d18, 0x2071, 0x12ef, + 0x703c, 0x9005, 0x1328, 0x2001, 0x124c, 0x2004, 0x8005, 0x703e, + 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2168, 0x6904, + 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, 0x70b0, 0x9200, + 0x70b2, 0x0838, 0x00d6, 0x00e6, 0x7824, 0xc0d4, 0x8006, 0x8006, + 0x806f, 0x2071, 0x1100, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b0, + 0x8000, 0x70b2, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, 0xd0a4, + 0x1d58, 0x00ee, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, 0xd09c, + 0x11b8, 0x00de, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x7822, 0x6804, + 0x900d, 0x1560, 0x2071, 0x12ef, 0x703c, 0x9005, 0x1328, 0x2001, + 0x124c, 0x2004, 0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, + 0x00de, 0x2d08, 0x7010, 0x8000, 0x7012, 0x7018, 0x906d, 0x711a, + 0x0110, 0x6902, 0x0008, 0x711e, 0x2168, 0x6804, 0x900d, 0x1170, + 0x2071, 0x12ef, 0x703c, 0x9005, 0x1328, 0x2001, 0x124c, 0x2004, + 0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1100, + 0x9016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, + 0x1dc8, 0x702e, 0x70b0, 0x9200, 0x70b2, 0x00fe, 0x002e, 0x00ee, + 0x0005, 0x2d08, 0x7010, 0x8000, 0x7012, 0x7018, 0x906d, 0x711a, + 0x0110, 0x6902, 0x0008, 0x711e, 0x2168, 0x6804, 0x900d, 0x1904, + 0x5092, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, 0xd09c, 0x11b0, + 0x701c, 0x906d, 0x0198, 0x7010, 0x8001, 0x7012, 0x1108, 0x701a, + 0x2d04, 0x701e, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x7822, 0x782c, + 0x9094, 0x0780, 0x190c, 0x542a, 0xd09c, 0x0d50, 0x782c, 0x9094, + 0x0780, 0x190c, 0x542a, 0xd0a4, 0x01b8, 0x00e6, 0x7824, 0xc0d4, + 0x8006, 0x8006, 0x806f, 0x2071, 0x1100, 0x702c, 0x206a, 0x2d00, + 0x702e, 0x70b0, 0x8000, 0x70b2, 0x782c, 0x9094, 0x0780, 0x190c, + 0x542a, 0xd0a4, 0x1d58, 0x00ee, 0x2071, 0x12ef, 0x703c, 0x9005, + 0x1328, 0x2001, 0x124c, 0x2004, 0x8005, 0x703e, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1100, 0x9016, 0x702c, 0x2168, + 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, 0x70b0, + 0x9200, 0x70b2, 0x00ee, 0x0804, 0x5049, 0x6868, 0xd0fc, 0x1500, + 0x00e6, 0x0026, 0x684f, 0x0000, 0x00f6, 0x2079, 0x0050, 0x2071, + 0x1228, 0x206b, 0x0000, 0x7010, 0x9005, 0x1904, 0x51b5, 0x782c, + 0x908c, 0x0780, 0x190c, 0x542a, 0x8004, 0x8004, 0x8004, 0x9084, + 0x0003, 0x0002, 0x50c9, 0x51b5, 0x50e5, 0x514a, 0x080c, 0x0cf1, + 0x0005, 0x2071, 0x1100, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x7822, + 0x6804, 0x900d, 0x1120, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, + 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, + 0x702e, 0x70b0, 0x9200, 0x70b2, 0x0c70, 0x2071, 0x1100, 0x8d07, + 0x8005, 0x8005, 0xc0d5, 0x7822, 0x6804, 0x900d, 0x1904, 0x513b, + 0x7830, 0x8007, 0x9084, 0x001f, 0x9082, 0x0005, 0x1220, 0x00fe, + 0x002e, 0x00ee, 0x0005, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, + 0xd19c, 0x1118, 0x7022, 0x00ee, 0x0060, 0x00ee, 0xc0d4, 0x8006, + 0x8006, 0x806f, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b0, 0x8000, + 0x70b2, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, 0xd0a4, 0x1d18, + 0x0e04, 0x5132, 0x7838, 0x7938, 0x910e, 0x1de0, 0x2069, 0x0000, + 0x6836, 0x6833, 0x0013, 0x2001, 0x1239, 0x200c, 0xc184, 0x2102, + 0x2091, 0x4080, 0x2009, 0x124a, 0x200b, 0x0000, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x2001, 0x1239, 0x200c, 0xc185, 0x2102, 0x00fe, + 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2168, 0x6904, 0x206a, + 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, 0x70b0, 0x9200, 0x70b2, + 0x0804, 0x50fb, 0x00d6, 0x00e6, 0x7824, 0xc0d4, 0x8006, 0x8006, + 0x806f, 0x2071, 0x1100, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b0, + 0x8000, 0x70b2, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, 0xd0a4, + 0x1d58, 0x00ee, 0x0e04, 0x518a, 0x7838, 0x7938, 0x910e, 0x1de0, + 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x7044, 0xc084, 0x7046, + 0x2091, 0x4080, 0x2009, 0x124a, 0x200b, 0x0000, 0x782c, 0x9094, + 0x0780, 0x190c, 0x542a, 0xd09c, 0x1188, 0x00de, 0x8d07, 0x8005, + 0x8005, 0xc0d5, 0x7822, 0x6804, 0x900d, 0x11e0, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x7044, 0xc085, 0x7046, 0x0c40, 0x00de, 0x2d08, + 0x7010, 0x8000, 0x7012, 0x7018, 0x906d, 0x711a, 0x0110, 0x6902, + 0x0008, 0x711e, 0x2168, 0x6804, 0x900d, 0x1120, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x2071, 0x1100, 0x9016, 0x702c, 0x2168, 0x6904, + 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, 0x70b0, 0x9200, + 0x70b2, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x2d08, 0x7010, 0x8000, + 0x7012, 0x7018, 0x906d, 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, + 0x2168, 0x6804, 0x900d, 0x1904, 0x5222, 0x782c, 0x9094, 0x0780, + 0x190c, 0x542a, 0xd09c, 0x11c8, 0x701c, 0x906d, 0x01b0, 0x684c, + 0x9005, 0x1198, 0x7010, 0x8001, 0x7012, 0x1108, 0x701a, 0x2d04, + 0x701e, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x7822, 0x782c, 0x9094, + 0x0780, 0x190c, 0x542a, 0xd09c, 0x0d38, 0x782c, 0x9094, 0x0780, + 0x190c, 0x542a, 0xd0a4, 0x0590, 0x00e6, 0x7824, 0xc0d4, 0x8006, + 0x8006, 0x806f, 0x2071, 0x1100, 0x702c, 0x206a, 0x2d00, 0x702e, + 0x70b0, 0x8000, 0x70b2, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, + 0xd0a4, 0x1d58, 0x00ee, 0x0e04, 0x521b, 0x7838, 0x7938, 0x910e, + 0x1de0, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x7044, 0xc084, + 0x7046, 0x2091, 0x4080, 0x2009, 0x124a, 0x200b, 0x0000, 0x00fe, + 0x002e, 0x00ee, 0x0005, 0x7044, 0xc085, 0x7046, 0x00fe, 0x002e, + 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1100, 0x9016, 0x702c, 0x2168, + 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, 0x70b0, + 0x9200, 0x70b2, 0x00ee, 0x0804, 0x51c5, 0x2071, 0x1228, 0x206b, + 0x0000, 0x2d08, 0x7010, 0x8000, 0x7012, 0x7018, 0x906d, 0x711a, + 0x0110, 0x6902, 0x0008, 0x711e, 0x2168, 0x6804, 0x900d, 0x1128, + 0x1e04, 0x525e, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1100, 0x9016, + 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, + 0x702e, 0x70b0, 0x9200, 0x70b2, 0x0e04, 0x524a, 0x2071, 0x1228, + 0x701c, 0x2068, 0x684c, 0x900d, 0x0d28, 0x2071, 0x0000, 0x7182, + 0x6850, 0x7032, 0x686c, 0x7086, 0x7036, 0x6870, 0x708a, 0x2091, + 0x4080, 0x2071, 0x1228, 0x080c, 0x5416, 0x002e, 0x00ee, 0x0005, + 0x2071, 0x1228, 0x206b, 0x0000, 0x2d08, 0x7010, 0x8000, 0x7012, + 0x7018, 0x906d, 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, 0x2168, + 0x6804, 0x900d, 0x1118, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1100, + 0x9016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, + 0x1dc8, 0x702e, 0x70b0, 0x9200, 0x70b2, 0x002e, 0x00ee, 0x0005, + 0x0006, 0x687c, 0x0006, 0x6867, 0x0103, 0x20a9, 0x001c, 0x9d80, + 0x001d, 0x20a0, 0x9006, 0x20e9, 0x0001, 0x4004, 0x000e, 0x9084, + 0x00ff, 0x687e, 0x000e, 0x687a, 0x6982, 0x0005, 0x2071, 0x1228, + 0x7004, 0x0002, 0x52c0, 0x52c1, 0x53ea, 0x53d8, 0x0cf1, 0x53eb, + 0x0005, 0x2001, 0x124b, 0x2004, 0x0002, 0x52ca, 0x52ca, 0x531c, + 0x531d, 0x5373, 0x0126, 0x2091, 0x8000, 0x1e0c, 0x542f, 0x701c, + 0x906d, 0x01b0, 0x684c, 0x9005, 0x01a8, 0x0e04, 0x52e8, 0x694c, + 0x2071, 0x0000, 0x7182, 0x6850, 0x7032, 0x686c, 0x7086, 0x7036, + 0x6870, 0x708a, 0x2091, 0x4080, 0x2071, 0x1228, 0x080c, 0x5416, + 0x012e, 0x0488, 0x2001, 0x005b, 0x2004, 0x9094, 0x0780, 0x190c, + 0x542a, 0xd09c, 0x2071, 0x1228, 0x1528, 0x2071, 0x1228, 0x700f, + 0x0001, 0x6964, 0x9184, 0x00ff, 0x9086, 0x0003, 0x1130, 0x810f, + 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x8d07, 0x8005, 0x8005, + 0xc0d5, 0x00d6, 0x2069, 0x0050, 0x6822, 0x00de, 0x2071, 0x1228, + 0x701c, 0x2068, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0x9005, + 0x1108, 0x701a, 0x012e, 0x0005, 0x0005, 0x2069, 0x12ef, 0x683c, + 0x9005, 0x03d8, 0x11d0, 0x0126, 0x2091, 0x8000, 0x2069, 0x0050, + 0x693c, 0x6838, 0x9106, 0x0160, 0x0e04, 0x533c, 0x2069, 0x0000, + 0x6837, 0x8040, 0x6833, 0x0012, 0x6883, 0x8040, 0x2091, 0x4080, + 0x2069, 0x12ef, 0x683f, 0xffff, 0x012e, 0x0126, 0x2091, 0x8000, + 0x1e0c, 0x548e, 0x701c, 0x906d, 0x0560, 0x2001, 0x005b, 0x2004, + 0x9094, 0x0780, 0x190c, 0x542a, 0xd09c, 0x1518, 0x2071, 0x1228, + 0x700f, 0x0001, 0x6964, 0x9184, 0x00ff, 0x9086, 0x0003, 0x1130, + 0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x8d07, 0x8005, + 0x8005, 0xc0d5, 0x00d6, 0x2069, 0x0050, 0x6822, 0x00de, 0x701c, + 0x2068, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0x9005, 0x1108, + 0x701a, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x1e0c, 0x542f, + 0x701c, 0x906d, 0x0548, 0x684c, 0x9086, 0x0004, 0x1538, 0x0136, + 0x0146, 0x0156, 0x2099, 0x1176, 0x20e1, 0x0001, 0x20a1, 0x1278, + 0x20e9, 0x0001, 0x20a9, 0x0004, 0x4003, 0x015e, 0x014e, 0x013e, + 0x2071, 0x126e, 0x9d80, 0x001b, 0x700f, 0x0001, 0x7012, 0x7017, + 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, 0x2e10, 0x080c, 0x0e55, + 0x2071, 0x1228, 0x7007, 0x0003, 0x012e, 0x0005, 0x2001, 0x005b, + 0x2004, 0x9094, 0x0780, 0x190c, 0x542a, 0xd09c, 0x2071, 0x1228, + 0x1d98, 0x2071, 0x1228, 0x700f, 0x0001, 0x6964, 0x9184, 0x00ff, + 0x9086, 0x0003, 0x1130, 0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, + 0x710e, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x00d6, 0x2069, 0x0050, + 0x6822, 0x00de, 0x2071, 0x1228, 0x701c, 0x2068, 0x7010, 0x8001, + 0x7012, 0x2d04, 0x701e, 0x9005, 0x1978, 0x701a, 0x012e, 0x0005, + 0x2001, 0x1270, 0x2004, 0x908e, 0x0100, 0x1120, 0x7007, 0x0001, + 0x04a9, 0x0005, 0x908e, 0x0000, 0x0de0, 0x908e, 0x0200, 0x1dc8, + 0x080c, 0x542a, 0x0005, 0x0005, 0x684f, 0x0004, 0x206b, 0x0000, + 0x2d08, 0x2071, 0x1228, 0x7010, 0x8000, 0x7012, 0x7018, 0x906d, + 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, 0x2168, 0x6804, 0x900d, + 0x1118, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1100, 0x9016, 0x702c, + 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, + 0x70b0, 0x9200, 0x70b2, 0x002e, 0x00ee, 0x0005, 0x0126, 0x2091, + 0x8000, 0x701c, 0x906d, 0x0160, 0x7010, 0x8001, 0x7012, 0x2d04, + 0x701e, 0x9005, 0x1108, 0x701a, 0x012e, 0x080c, 0x0df6, 0x0005, + 0x012e, 0x0005, 0x2011, 0x8004, 0x080c, 0x37dc, 0x0cf8, 0x00f6, + 0x2079, 0x0050, 0x7044, 0xd084, 0x0198, 0xc084, 0x7046, 0x7838, + 0x7938, 0x910e, 0x1de0, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, + 0x2091, 0x4080, 0x2009, 0x124a, 0x200b, 0x0000, 0x00fe, 0x0005, + 0x782c, 0x9094, 0x0780, 0x19f1, 0xd0a4, 0x0dc0, 0x2001, 0x124b, + 0x2004, 0x9086, 0x0004, 0x0140, 0x2009, 0x124a, 0x2104, 0x8000, + 0x200a, 0x9082, 0x000f, 0x0e50, 0x00e6, 0x2071, 0x1100, 0x7824, + 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, 0x1118, 0x7022, 0x00ee, + 0x0060, 0x00ee, 0xc0d4, 0x8006, 0x8006, 0x806f, 0x702c, 0x206a, + 0x2d00, 0x702e, 0x70b0, 0x8000, 0x70b2, 0x782c, 0x9094, 0x0780, + 0x190c, 0x542a, 0xd0a4, 0x1d18, 0x7838, 0x7938, 0x910e, 0x1de0, + 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x2091, 0x4080, 0x2009, + 0x124a, 0x200b, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x2079, + 0x0050, 0x7044, 0xd084, 0x0178, 0xc084, 0x7046, 0x7838, 0x7938, + 0x910e, 0x1de0, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x2091, + 0x4080, 0x00fe, 0x0005, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, + 0xd0a4, 0x0db8, 0x00e6, 0x2071, 0x1100, 0x7824, 0xc0d4, 0x8006, + 0x8006, 0x806f, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b0, 0x8000, + 0x70b2, 0x782c, 0x9094, 0x0780, 0x190c, 0x542a, 0xd0a4, 0x1d68, + 0x2069, 0x0050, 0x693c, 0x2069, 0x124b, 0x6808, 0x690a, 0x2069, + 0x12ef, 0x9102, 0x1118, 0x683c, 0x9005, 0x1328, 0x2001, 0x124c, + 0x200c, 0x810d, 0x693e, 0x00ee, 0x00fe, 0x0005, 0x7088, 0x908a, + 0x0029, 0x1220, 0x9082, 0x001d, 0x0033, 0x0010, 0x080c, 0x0cf1, + 0x6027, 0x1e00, 0x0005, 0x55a7, 0x5541, 0x5557, 0x557b, 0x559a, + 0x55cc, 0x55de, 0x5557, 0x55b8, 0x54f0, 0x552a, 0x54ef, 0x0005, + 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005, 0x1180, 0x6808, 0x9005, + 0x1578, 0x708b, 0x0028, 0x2069, 0x12af, 0x2d04, 0x7002, 0x080c, + 0x5857, 0x6028, 0x9085, 0x0600, 0x602a, 0x0410, 0x708b, 0x0028, + 0x2069, 0x12af, 0x2d04, 0x7002, 0x6028, 0x9085, 0x0600, 0x602a, + 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0x131c, 0x080c, 0x1337, + 0x005e, 0x004e, 0x003e, 0x00ee, 0x0126, 0x2091, 0x2200, 0x080c, + 0x0fb3, 0x78ab, 0x0004, 0x7803, 0x0000, 0x7803, 0x0001, 0x012e, + 0x00de, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005, 0x1178, + 0x6808, 0x9005, 0x1160, 0x708b, 0x0028, 0x2069, 0x12af, 0x2d04, + 0x7002, 0x080c, 0x58e5, 0x6028, 0x9085, 0x0600, 0x602a, 0x00de, + 0x0005, 0x6803, 0x0090, 0x6124, 0xd1e4, 0x1180, 0x080c, 0x5649, + 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1cc, 0x0140, 0x708b, 0x0020, + 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, + 0x0088, 0x6124, 0xd1cc, 0x11c8, 0xd1dc, 0x11a0, 0xd1e4, 0x1178, + 0x9184, 0x1e00, 0x11b8, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, + 0x080c, 0x5775, 0x6803, 0x0080, 0x708b, 0x0028, 0x0058, 0x708b, + 0x001e, 0x0040, 0x708b, 0x001d, 0x0028, 0x708b, 0x0020, 0x0010, + 0x708b, 0x001f, 0x0005, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, + 0x080c, 0x5775, 0x6803, 0x0080, 0x6124, 0xd1d4, 0x1180, 0xd1dc, + 0x1158, 0xd1e4, 0x1130, 0x9184, 0x1e00, 0x1158, 0x708b, 0x0028, + 0x0040, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, + 0x001f, 0x0005, 0x6803, 0x00a0, 0x6124, 0xd1dc, 0x1128, 0xd1e4, + 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001d, 0x0005, 0x080c, + 0x5675, 0x6124, 0xd1dc, 0x1158, 0x080c, 0x5649, 0xd1d4, 0x1128, + 0xd1e4, 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001f, 0x0005, + 0x6803, 0x00a0, 0x6124, 0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, + 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, + 0x0010, 0x708b, 0x0021, 0x0005, 0x080c, 0x5675, 0x6124, 0xd1d4, + 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, + 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x0090, + 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, + 0x0158, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, 0x0028, 0x708b, + 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x0016, 0x00c6, 0x00d6, + 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1100, + 0x2091, 0x8000, 0x080c, 0x5745, 0x11e8, 0x2001, 0x110c, 0x200c, + 0xd1b4, 0x01c0, 0xc1b4, 0x2102, 0x6027, 0x0200, 0x080c, 0x2055, + 0x6024, 0xd0cc, 0x0158, 0x6803, 0x00a0, 0x2001, 0x1290, 0x2003, + 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, 0x0428, 0x6028, 0xc0cd, + 0x602a, 0x0408, 0x080c, 0x5761, 0x0150, 0x080c, 0x5757, 0x1138, + 0x2001, 0x0001, 0x080c, 0x1c36, 0x080c, 0x571c, 0x00a0, 0x080c, + 0x5672, 0x0178, 0x2001, 0x0001, 0x080c, 0x1c36, 0x7088, 0x9086, + 0x001e, 0x0120, 0x7088, 0x9086, 0x0022, 0x1118, 0x708b, 0x0025, + 0x0010, 0x708b, 0x0021, 0x012e, 0x00ee, 0x00de, 0x00ce, 0x001e, + 0x0005, 0x0016, 0x0026, 0x2009, 0x0064, 0x2011, 0x5654, 0x080c, + 0x654f, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00f6, 0x0016, 0x080c, + 0x7721, 0x2071, 0x1100, 0x080c, 0x55f5, 0x001e, 0x00fe, 0x00ee, + 0x0005, 0x0026, 0x00e6, 0x2011, 0x5654, 0x2071, 0x12ef, 0x701c, + 0x9206, 0x1118, 0x7018, 0x9005, 0x0110, 0x9085, 0x0001, 0x00ee, + 0x002e, 0x0005, 0x6020, 0xd09c, 0x0005, 0x6803, 0x00c0, 0x0156, + 0x20a9, 0x002d, 0x1d04, 0x567a, 0x2091, 0x6000, 0x1f04, 0x567a, + 0x015e, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, + 0x0140, 0x2071, 0x1100, 0x2001, 0x1290, 0x200c, 0x9186, 0x0000, + 0x0158, 0x9186, 0x0001, 0x0158, 0x9186, 0x0002, 0x0158, 0x9186, + 0x0003, 0x0158, 0x0804, 0x570a, 0x708b, 0x0022, 0x0040, 0x708b, + 0x0021, 0x0028, 0x708b, 0x0023, 0x0030, 0x708b, 0x0024, 0x9085, + 0x0001, 0x080c, 0x5789, 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, + 0x0001, 0x080c, 0x1cbe, 0x0026, 0x2011, 0x0003, 0x080c, 0x79c2, + 0x2011, 0x0002, 0x080c, 0x79cc, 0x080c, 0x78b3, 0x080c, 0x65cf, + 0x0036, 0x2019, 0x0000, 0x080c, 0x7936, 0x003e, 0x002e, 0x7000, + 0x908e, 0x0004, 0x0118, 0x602b, 0x0028, 0x0010, 0x602b, 0x0020, + 0x0156, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x6024, 0xd0ac, + 0x0118, 0x012e, 0x015e, 0x04e0, 0x6800, 0x9084, 0x00a0, 0xc0bd, + 0x6802, 0x080c, 0x2055, 0x6904, 0xd1d4, 0x1130, 0x6803, 0x0100, + 0x1f04, 0x56d6, 0x080c, 0x5796, 0x012e, 0x015e, 0x080c, 0x5757, + 0x01a8, 0x6044, 0x9005, 0x0168, 0x6050, 0x0006, 0x9085, 0x0020, + 0x6052, 0x080c, 0x5796, 0x9006, 0x8001, 0x1df0, 0x000e, 0x6052, + 0x0028, 0x6804, 0xd0d4, 0x1110, 0x080c, 0x5796, 0x2001, 0x1290, + 0x2003, 0x0004, 0x080c, 0x54d6, 0x080c, 0x5757, 0x0148, 0x6804, + 0xd0d4, 0x1130, 0xd0dc, 0x1100, 0x2001, 0x1290, 0x2003, 0x0000, + 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, + 0x0100, 0x2069, 0x0140, 0x2071, 0x1100, 0x2001, 0x128f, 0x2003, + 0x0000, 0x2001, 0x1280, 0x2003, 0x0000, 0x708b, 0x0000, 0x60e3, + 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, 0x1cbe, 0x6803, + 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027, 0xffff, 0x602b, + 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, 0x2001, 0x128f, + 0x2004, 0x9086, 0xaaaa, 0x000e, 0x0005, 0x0006, 0x2001, 0x1172, + 0x2004, 0x9084, 0x0030, 0x9086, 0x0000, 0x000e, 0x0005, 0x0006, + 0x2001, 0x1172, 0x2004, 0x9084, 0x0030, 0x9086, 0x0030, 0x000e, + 0x0005, 0x0006, 0x2001, 0x1172, 0x2004, 0x9084, 0x0030, 0x9086, + 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0x1172, 0x2004, 0x9084, + 0x0030, 0x9086, 0x0020, 0x000e, 0x0005, 0x2001, 0x110c, 0x2004, + 0xd0a4, 0x0170, 0x080c, 0x1cde, 0x0036, 0x0016, 0x2009, 0x0000, + 0x2019, 0x0028, 0x080c, 0x2582, 0x001e, 0x003e, 0x9006, 0x0009, + 0x0005, 0x00e6, 0x2071, 0x110c, 0x2e04, 0x0118, 0x9085, 0x0010, + 0x0010, 0x9084, 0xffef, 0x2072, 0x00ee, 0x0005, 0x6050, 0x0006, + 0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006, + 0x0016, 0x6138, 0x6050, 0x9084, 0xfbff, 0x9085, 0x2000, 0x6052, + 0x613a, 0x20a9, 0x0012, 0x1d04, 0x57ab, 0x2091, 0x6000, 0x1f04, + 0x57ab, 0x602f, 0x0100, 0x602f, 0x0000, 0x6050, 0x9085, 0x0400, + 0x9084, 0xdfff, 0x6052, 0x613a, 0x001e, 0x602f, 0x0040, 0x602f, + 0x0000, 0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, + 0x60ee, 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, + 0x1cbe, 0x6803, 0x00a0, 0x000e, 0x6052, 0x0005, 0x0156, 0x0016, + 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, + 0x0140, 0x2071, 0x1100, 0x6020, 0x9084, 0x0080, 0x0138, 0x2001, + 0x110c, 0x200c, 0xc1c5, 0x2102, 0x0804, 0x584f, 0x2001, 0x110c, + 0x200c, 0xc1c4, 0x2102, 0x6028, 0x9084, 0xe1ff, 0x602a, 0x6027, + 0x0200, 0x6803, 0x0090, 0x20a9, 0x0366, 0x6024, 0xd0cc, 0x1518, + 0x1d04, 0x57fd, 0x2091, 0x6000, 0x1f04, 0x57fd, 0x2011, 0x0003, + 0x080c, 0x79c2, 0x2011, 0x0002, 0x080c, 0x79cc, 0x080c, 0x78b3, + 0x080c, 0x65cf, 0x2019, 0x0000, 0x080c, 0x7936, 0x6803, 0x00a0, + 0x2001, 0x1290, 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, + 0x9085, 0x0001, 0x0460, 0x86ff, 0x1110, 0x080c, 0x1359, 0x60e3, + 0x0000, 0x2001, 0x1280, 0x2004, 0x080c, 0x1cbe, 0x60e2, 0x6803, + 0x0080, 0x20a9, 0x0366, 0x6027, 0x1e00, 0x2009, 0x1e00, 0x080c, + 0x2055, 0x6024, 0x910c, 0x0138, 0x1d04, 0x5833, 0x2091, 0x6000, + 0x1f04, 0x5833, 0x0818, 0x6028, 0x9085, 0x1e00, 0x602a, 0x70a0, + 0x9005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x9006, 0x00ee, + 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, + 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, + 0x2071, 0x1100, 0x2069, 0x0140, 0x6020, 0x9084, 0x00c0, 0x0120, + 0x6884, 0x9005, 0x1904, 0x58ac, 0x6803, 0x0088, 0x60e3, 0x0000, + 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, 0x1cbe, 0x2069, 0x0200, + 0x6804, 0x9005, 0x1118, 0x6808, 0x9005, 0x01c0, 0x6028, 0x9084, + 0xfbff, 0x602a, 0x6027, 0x0400, 0x2069, 0x12af, 0x7000, 0x206a, + 0x708b, 0x0026, 0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04, 0x588e, + 0x2091, 0x6000, 0x1f04, 0x588e, 0x0804, 0x58dd, 0x2069, 0x0140, + 0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00, 0x080c, 0x2055, + 0x6024, 0x910c, 0x0530, 0x9084, 0x1a00, 0x1518, 0x1d04, 0x589a, + 0x2091, 0x6000, 0x1f04, 0x589a, 0x2011, 0x0003, 0x080c, 0x79c2, + 0x2011, 0x0002, 0x080c, 0x79cc, 0x080c, 0x78b3, 0x080c, 0x65cf, + 0x2019, 0x0000, 0x080c, 0x7936, 0x6803, 0x00a0, 0x2001, 0x1290, + 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, 0x9085, 0x0001, + 0x00a0, 0x6803, 0x0080, 0x2069, 0x0140, 0x60e3, 0x0000, 0x70a0, + 0x9005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001, 0x1280, + 0x2004, 0x080c, 0x1cbe, 0x60e2, 0x9006, 0x00ee, 0x00de, 0x00ce, + 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, + 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071, 0x1100, + 0x6020, 0x9084, 0x00c0, 0x01f0, 0x2011, 0x0003, 0x080c, 0x79c2, + 0x2011, 0x0002, 0x080c, 0x79cc, 0x080c, 0x78b3, 0x080c, 0x65cf, + 0x2019, 0x0000, 0x080c, 0x7936, 0x2069, 0x0140, 0x6803, 0x00a0, + 0x2001, 0x1290, 0x2003, 0x0001, 0x2001, 0x1100, 0x2003, 0x0001, + 0x0804, 0x5976, 0x2001, 0x110c, 0x200c, 0xd1b4, 0x1150, 0xc1b5, + 0x2102, 0x080c, 0x5649, 0x2069, 0x0140, 0x6803, 0x0080, 0x60e3, + 0x0000, 0x2069, 0x0200, 0x6804, 0x9005, 0x1118, 0x6808, 0x9005, + 0x0178, 0x6028, 0x9084, 0xfdff, 0x602a, 0x6027, 0x0200, 0x2069, + 0x12af, 0x7000, 0x206a, 0x708b, 0x0027, 0x7003, 0x0001, 0x04f0, + 0x6027, 0x1e00, 0x2009, 0x1e00, 0x080c, 0x2055, 0x6024, 0x910c, + 0x01c8, 0x9084, 0x1c00, 0x11b0, 0x1d04, 0x5938, 0x0006, 0x0016, + 0x00c6, 0x00d6, 0x00e6, 0x080c, 0x64e0, 0x00ee, 0x00de, 0x00ce, + 0x001e, 0x000e, 0x00e6, 0x2071, 0x12ef, 0x7018, 0x00ee, 0x9005, + 0x19f8, 0x01e0, 0x0026, 0x2011, 0x5654, 0x080c, 0x655b, 0x002e, + 0x2069, 0x0140, 0x60e3, 0x0000, 0x70a0, 0x9005, 0x1118, 0x6887, + 0x0001, 0x0008, 0x6886, 0x2001, 0x1280, 0x2004, 0x080c, 0x1cbe, + 0x60e2, 0x2001, 0x110c, 0x200c, 0xc1b4, 0x2102, 0x00ee, 0x00de, + 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, + 0x0026, 0x0036, 0x0046, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, + 0x1100, 0x7130, 0xd184, 0x1180, 0x2011, 0x1153, 0x2214, 0xd2ec, + 0x0138, 0xc18d, 0x7132, 0x2011, 0x1153, 0x2214, 0xd2ac, 0x1120, + 0x7030, 0xd08c, 0x0904, 0x59e3, 0x7130, 0xc185, 0x7132, 0x2011, + 0x1153, 0x220c, 0xd1a4, 0x0530, 0x0016, 0x2009, 0x0001, 0x2011, + 0x0100, 0x080c, 0x66d5, 0x2019, 0x000e, 0x080c, 0xaa50, 0x0156, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x9186, 0x007e, 0x0170, 0x9186, + 0x0080, 0x0158, 0x080c, 0x4b58, 0x1140, 0x8127, 0x9006, 0x0016, + 0x2009, 0x000e, 0x080c, 0xaaca, 0x001e, 0x8108, 0x1f04, 0x59b4, + 0x015e, 0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009, 0x0000, 0x2019, + 0x0004, 0x080c, 0x2582, 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x080c, 0x4b58, 0x1110, 0x080c, 0x472d, 0x8108, + 0x1f04, 0x59da, 0x015e, 0x2011, 0x0003, 0x080c, 0x79c2, 0x2011, + 0x0002, 0x080c, 0x79cc, 0x080c, 0x78b3, 0x080c, 0x65cf, 0x0036, + 0x2019, 0x0000, 0x080c, 0x7936, 0x003e, 0x60e3, 0x0000, 0x2001, + 0x1100, 0x2003, 0x0001, 0x080c, 0x5682, 0x00ee, 0x00ce, 0x004e, + 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x2071, 0x11f4, 0x7003, + 0x0000, 0x7007, 0x0000, 0x708f, 0x0000, 0x7093, 0x0001, 0x70c7, + 0x0000, 0x0005, 0x00e6, 0x2071, 0x0040, 0x6848, 0x9005, 0x1120, + 0x9085, 0x0001, 0x0804, 0x5a5e, 0x6840, 0x9005, 0x01a0, 0x900e, + 0x0156, 0x20a9, 0x0006, 0x8003, 0x81f5, 0x3e08, 0x1f04, 0x5a23, + 0x015e, 0x6a50, 0x9200, 0x7002, 0x6854, 0x9101, 0x7006, 0x7013, + 0x0000, 0x7017, 0x0000, 0x6850, 0x7002, 0x6854, 0x7006, 0x6858, + 0x700a, 0x685c, 0x700e, 0x6840, 0x9005, 0x1120, 0x7013, 0x0000, + 0x7017, 0x0000, 0x6848, 0x701a, 0x701c, 0x9085, 0x0040, 0x701e, + 0x2001, 0x0019, 0x7036, 0x702b, 0x0001, 0x2001, 0x0004, 0x200c, + 0x918c, 0xfff7, 0x918d, 0x8000, 0x2102, 0x00d6, 0x2069, 0x11f4, + 0x6807, 0x0001, 0x00de, 0x080c, 0x5f52, 0x9006, 0x00ee, 0x0005, + 0x2079, 0x0040, 0x2071, 0x11f4, 0x7004, 0x0002, 0x5a70, 0x5a71, + 0x5aa2, 0x5afd, 0x5bfe, 0x5a6e, 0x5a6e, 0x5c27, 0x080c, 0x0cf1, + 0x0005, 0x2079, 0x0040, 0x782c, 0x908c, 0x0780, 0x1530, 0xd0a4, + 0x01b0, 0x7824, 0xc0d4, 0x8006, 0x8006, 0x806f, 0x6803, 0x0000, + 0x6807, 0x0000, 0x6864, 0x9084, 0x00ff, 0x908a, 0x0040, 0x1260, + 0x04a3, 0x7004, 0x9086, 0x0003, 0x1d30, 0x080c, 0x5afd, 0x782c, + 0xd09c, 0x090c, 0x5f52, 0x0005, 0x9082, 0x005a, 0x1218, 0x2100, + 0x0053, 0x0c78, 0x080c, 0x5b37, 0x0c90, 0x2011, 0x8003, 0x080c, + 0x37dc, 0x0cf8, 0x0005, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, + 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, + 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, + 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b57, + 0x5b37, 0x5cdc, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b57, + 0x5d1e, 0x5d61, 0x5daa, 0x5dbe, 0x5b37, 0x5b37, 0x5b73, 0x5b57, + 0x5b37, 0x5b37, 0x5bd7, 0x5e67, 0x5e82, 0x5b37, 0x5b73, 0x5b37, + 0x5b37, 0x5b37, 0x5b37, 0x5bcd, 0x5e82, 0x5b37, 0x5b37, 0x5b37, + 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b87, 0x5b37, + 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, + 0x5f8e, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b9c, 0x5b37, + 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x5b37, 0x2079, 0x0040, 0x7004, + 0x9086, 0x0003, 0x11b8, 0x782c, 0x080c, 0x5f83, 0xd0a4, 0x0190, + 0x7824, 0xc0d4, 0x8006, 0x8006, 0x806f, 0x6803, 0x0000, 0x6807, + 0x0000, 0x6864, 0x9084, 0x00ff, 0x908a, 0x001a, 0x1210, 0x002b, + 0x0c30, 0x00e9, 0x080c, 0x5f52, 0x0005, 0x5b37, 0x5b57, 0x5cc8, + 0x5b37, 0x5b57, 0x5b37, 0x5b57, 0x5b57, 0x5b37, 0x5b57, 0x5cc8, + 0x5b57, 0x5b57, 0x5b57, 0x5b57, 0x5b57, 0x5b37, 0x5b57, 0x5cc8, + 0x5b37, 0x5b37, 0x5b57, 0x5b37, 0x5b37, 0x5b37, 0x5b57, 0x00e6, + 0x2071, 0x11f4, 0x7007, 0x0001, 0x6868, 0x9084, 0x00ff, 0xc0d5, + 0x686a, 0x0126, 0x2091, 0x8000, 0x080c, 0x50a5, 0x012e, 0x00ee, + 0x0005, 0x7007, 0x0001, 0x6868, 0x9084, 0x00ff, 0xc0e5, 0x686a, + 0x0126, 0x2091, 0x8000, 0x080c, 0x50a5, 0x012e, 0x0005, 0x7007, + 0x0001, 0x6868, 0x9084, 0x00ff, 0xc0ed, 0x686a, 0x0126, 0x2091, + 0x8000, 0x080c, 0x50a5, 0x012e, 0x0005, 0x7007, 0x0001, 0x6868, + 0x9084, 0x00ff, 0xc0dd, 0x686a, 0x0126, 0x2091, 0x8000, 0x080c, + 0x50a5, 0x012e, 0x0005, 0x6864, 0x8007, 0x9084, 0x00ff, 0x0988, + 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x5c90, 0x7007, 0x0003, + 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5c90, 0x0005, 0x6864, + 0x8007, 0x9084, 0x00ff, 0x0904, 0x5b49, 0x8001, 0x1120, 0x7007, + 0x0001, 0x0804, 0x5ca9, 0x7007, 0x0003, 0x7012, 0x2d00, 0x7016, + 0x701a, 0x704b, 0x5ca9, 0x0005, 0x6864, 0x8007, 0x9084, 0x00ff, + 0x9086, 0x0001, 0x1904, 0x5b49, 0x7007, 0x0001, 0x2009, 0x1130, + 0x210c, 0x81ff, 0x11a8, 0x6868, 0x9084, 0x00ff, 0x686a, 0x6883, + 0x0000, 0x080c, 0x4873, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000, + 0x6867, 0x0139, 0x687a, 0x6982, 0x080c, 0x50a5, 0x012e, 0x0ca0, + 0x6994, 0x9186, 0x0071, 0x0d38, 0x6897, 0x4005, 0x689b, 0x0001, + 0x2001, 0x0030, 0x2009, 0x0000, 0x0c40, 0x687c, 0x9084, 0x00c0, + 0x9086, 0x00c0, 0x1120, 0x7007, 0x0001, 0x0804, 0x5e99, 0x2d00, + 0x7016, 0x701a, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x20e9, 0x0001, + 0x9080, 0x0030, 0x2098, 0x20a1, 0x1221, 0x4003, 0x6888, 0x7012, + 0x9082, 0x0401, 0x1a04, 0x5b65, 0x6ab4, 0x928a, 0x0002, 0x1a04, + 0x5b65, 0x82ff, 0x1138, 0x68b8, 0x69bc, 0x9105, 0x0118, 0x2001, + 0x5c63, 0x0018, 0x9280, 0x5c59, 0x2005, 0x70ce, 0x7010, 0x9015, + 0x0904, 0x5c45, 0x080c, 0x0dc6, 0x1118, 0x7007, 0x0004, 0x0005, + 0x2d00, 0x7022, 0x70cc, 0x2060, 0xe000, 0x6866, 0xe004, 0x9d00, + 0x709e, 0x709b, 0x0001, 0xe008, 0x920a, 0x1210, 0x900e, 0x2200, + 0x7112, 0xe20c, 0x8003, 0x800b, 0x9296, 0x0004, 0x0108, 0x9108, + 0x71a2, 0x810b, 0x71a6, 0x9e90, 0x0023, 0x080c, 0x0e55, 0x7094, + 0x908e, 0x0100, 0x0170, 0x9086, 0x0200, 0x0118, 0x7007, 0x0007, + 0x0005, 0x7020, 0x2068, 0x080c, 0x0df6, 0x7014, 0x2068, 0x0804, + 0x5b65, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08, + 0x2068, 0x6906, 0x711a, 0x0804, 0x5bfe, 0x7014, 0x2068, 0x7007, + 0x0001, 0x68b4, 0x9005, 0x1128, 0x68b8, 0x69bc, 0x9105, 0x0108, + 0x00b1, 0x6864, 0x9084, 0x00ff, 0x9086, 0x001e, 0x0904, 0x5e99, + 0x04b8, 0x5c5b, 0x5c5f, 0x0002, 0x001d, 0x0007, 0x0004, 0x000a, + 0x001b, 0x0005, 0x0006, 0x000a, 0x001d, 0x0005, 0x0004, 0x00f6, + 0x00e6, 0x00c6, 0x0076, 0x0066, 0x6fb8, 0x6ebc, 0x6804, 0x2060, + 0x9cf0, 0x002d, 0x9cf8, 0x0033, 0x2009, 0x0005, 0x700c, 0x7816, + 0x7008, 0x7812, 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a, + 0x8109, 0x0128, 0x9ef2, 0x0004, 0x9ffa, 0x0006, 0x0c78, 0x6004, + 0x9065, 0x1d30, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x00fe, 0x0005, + 0x2009, 0x1130, 0x210c, 0x81ff, 0x1178, 0x080c, 0x477e, 0x1108, + 0x0005, 0x080c, 0x52a0, 0x0126, 0x2091, 0x8000, 0x080c, 0x9843, + 0x080c, 0x50a5, 0x012e, 0x0ca0, 0x2001, 0x0028, 0x2009, 0x0000, + 0x0c80, 0x2009, 0x1130, 0x210c, 0x81ff, 0x1190, 0x6888, 0x9005, + 0x01a0, 0x6883, 0x0000, 0x080c, 0x4817, 0x1108, 0x0005, 0x0126, + 0x2091, 0x8000, 0x687a, 0x6982, 0x080c, 0x50a5, 0x012e, 0x0cb0, + 0x2001, 0x0028, 0x2009, 0x0000, 0x0c90, 0x2001, 0x0000, 0x0c78, + 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a, 0x7010, 0x8001, + 0x7012, 0x0118, 0x7007, 0x0003, 0x0030, 0x7014, 0x2068, 0x7007, + 0x0001, 0x7048, 0x080f, 0x0005, 0x7007, 0x0001, 0x6974, 0x810f, + 0x918c, 0x00ff, 0x6878, 0x9084, 0x00ff, 0x20a9, 0x0001, 0x9096, + 0x0001, 0x01b0, 0x2009, 0x0000, 0x20a9, 0x00ff, 0x9096, 0x0002, + 0x0178, 0x9005, 0x11f0, 0x6974, 0x810f, 0x918c, 0x00ff, 0x080c, + 0x4b58, 0x11b8, 0x0066, 0x6e80, 0x080c, 0x4c50, 0x006e, 0x0088, + 0x0046, 0x2011, 0x110c, 0x2224, 0xc484, 0x2412, 0x004e, 0x00c6, + 0x080c, 0x4b58, 0x1110, 0x080c, 0x4d11, 0x8108, 0x1f04, 0x5d08, + 0x00ce, 0x687c, 0xd084, 0x1118, 0x080c, 0x0df6, 0x0005, 0x0126, + 0x2091, 0x8000, 0x080c, 0x50a5, 0x012e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x7007, 0x0001, 0x2001, 0x1153, 0x2004, 0xd0a4, 0x0580, + 0x2061, 0x1329, 0x6100, 0xd184, 0x0178, 0x6888, 0x9084, 0x00ff, + 0x1550, 0x6000, 0xd084, 0x0520, 0x6004, 0x9005, 0x1538, 0x6003, + 0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, 0x0001, 0x6890, 0x9005, + 0x1110, 0x2001, 0x001e, 0x8000, 0x6016, 0x6888, 0x9084, 0x00ff, + 0x0178, 0x6006, 0x6888, 0x8007, 0x9084, 0x00ff, 0x0148, 0x600a, + 0x6888, 0x8000, 0x1108, 0xc28d, 0x6202, 0x012e, 0x0804, 0x5f3c, + 0x012e, 0x0804, 0x5f36, 0x012e, 0x0804, 0x5f30, 0x012e, 0x0804, + 0x5f33, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0x1153, + 0x2004, 0xd0a4, 0x05e0, 0x2061, 0x1329, 0x6000, 0xd084, 0x05b8, + 0x6204, 0x6308, 0xd08c, 0x1530, 0x6c78, 0x9484, 0x0003, 0x0170, + 0x6988, 0x918c, 0x00ff, 0x8001, 0x1120, 0x2100, 0x9210, 0x0620, + 0x0028, 0x8001, 0x1508, 0x2100, 0x9212, 0x02f0, 0x9484, 0x000c, + 0x0188, 0x6988, 0x810f, 0x918c, 0x00ff, 0x9082, 0x0004, 0x1120, + 0x2100, 0x9318, 0x0288, 0x0030, 0x9082, 0x0004, 0x1168, 0x2100, + 0x931a, 0x0250, 0x6890, 0x9005, 0x0110, 0x8000, 0x6016, 0x6206, + 0x630a, 0x012e, 0x0804, 0x5f3c, 0x012e, 0x0804, 0x5f39, 0x012e, + 0x0804, 0x5f36, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, + 0x1329, 0x6300, 0xd38c, 0x1120, 0x6308, 0x8318, 0x0220, 0x630a, + 0x012e, 0x0804, 0x5f4a, 0x012e, 0x0804, 0x5f39, 0x0126, 0x00c6, + 0x2091, 0x8000, 0x7007, 0x0001, 0x687c, 0xd0ac, 0x0148, 0x00c6, + 0x2061, 0x1329, 0x6000, 0x9084, 0xfcff, 0x6002, 0x00ce, 0x0448, + 0x6888, 0x9005, 0x05d0, 0x688c, 0x9065, 0x0598, 0x2001, 0x1130, + 0x2004, 0x9005, 0x0118, 0x080c, 0x97a3, 0x0068, 0x6017, 0x0400, + 0x605b, 0x0000, 0x697c, 0xd1a4, 0x0110, 0x6980, 0x615a, 0x2009, + 0x0041, 0x080c, 0x7f4e, 0x6988, 0x918c, 0xff00, 0x9186, 0x2000, + 0x1140, 0x0026, 0x2009, 0x0000, 0x2011, 0xfdff, 0x080c, 0x66d5, + 0x002e, 0x687c, 0xd0c4, 0x0148, 0x2061, 0x1329, 0x6000, 0xd08c, + 0x1120, 0x6008, 0x8000, 0x0208, 0x600a, 0x00ce, 0x012e, 0x0804, + 0x5f3c, 0x00ce, 0x012e, 0x0804, 0x5f36, 0x6984, 0x9186, 0x002e, + 0x0d40, 0x9186, 0x002d, 0x0d28, 0x9186, 0x0045, 0x0510, 0x9186, + 0x002a, 0x1130, 0x2001, 0x110c, 0x200c, 0xc194, 0x2102, 0x08c8, + 0x9186, 0x0020, 0x0170, 0x9186, 0x0029, 0x1d18, 0x6974, 0x918c, + 0xff00, 0x810f, 0x080c, 0x4b58, 0x1960, 0x6000, 0xc0e4, 0x6002, + 0x0840, 0x688c, 0x9065, 0x09a8, 0x2001, 0x12a6, 0x2004, 0x601a, + 0x0800, 0x688c, 0x9065, 0x0968, 0x00e6, 0x6890, 0x9075, 0x2001, + 0x1130, 0x2004, 0x9005, 0x0150, 0x080c, 0x97a3, 0x8eff, 0x0118, + 0x2e60, 0x080c, 0x97a3, 0x00ee, 0x0804, 0x5df9, 0x6024, 0xc0dc, + 0xc0d5, 0x6026, 0x2e60, 0x6007, 0x003a, 0x68a0, 0x9005, 0x0130, + 0x6007, 0x003b, 0x68a4, 0x602e, 0x68a8, 0x6016, 0x6003, 0x0001, + 0x080c, 0x6886, 0x080c, 0x6d42, 0x00ee, 0x0804, 0x5df9, 0x2061, + 0x1329, 0x6000, 0xd084, 0x0190, 0xd08c, 0x1904, 0x5f4a, 0x0126, + 0x2091, 0x8000, 0x6204, 0x8210, 0x0220, 0x6206, 0x012e, 0x0804, + 0x5f4a, 0x012e, 0x6883, 0x0016, 0x0804, 0x5f43, 0x6883, 0x0007, + 0x0804, 0x5f43, 0x6864, 0x8007, 0x9084, 0x00ff, 0x0130, 0x8001, + 0x1138, 0x7007, 0x0001, 0x0069, 0x0005, 0x080c, 0x5b49, 0x0040, + 0x7007, 0x0003, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5e99, + 0x0005, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2061, 0x1100, 0x61c0, + 0x81ff, 0x1904, 0x5f18, 0x6130, 0xd194, 0x1904, 0x5f20, 0x6878, + 0x2070, 0x9e82, 0x15c0, 0x0a04, 0x5f0c, 0x6058, 0x9e02, 0x1a04, + 0x5f0c, 0x2061, 0x1329, 0x6100, 0x9184, 0x0301, 0x9086, 0x0001, + 0x15e8, 0x7120, 0x9186, 0x0006, 0x15f0, 0x7010, 0x9005, 0x0904, + 0x5f18, 0x2004, 0xd0e4, 0x1904, 0x5f1b, 0x7024, 0xd0dc, 0x1904, + 0x5f23, 0x6883, 0x0000, 0x6803, 0x0000, 0x2d08, 0x7014, 0x9005, + 0x1198, 0x7116, 0x687c, 0xd0f4, 0x1904, 0x5f26, 0x2001, 0x1153, + 0x2004, 0xd09c, 0x1118, 0x687c, 0xc0cc, 0x687e, 0x2e60, 0x080c, + 0x6611, 0x012e, 0x00ee, 0x0005, 0x2068, 0x6800, 0x9005, 0x1de0, + 0x6902, 0x2168, 0x687c, 0xd0f4, 0x15c8, 0x012e, 0x00ee, 0x0005, + 0x012e, 0x00ee, 0x6883, 0x0006, 0x0804, 0x5f43, 0xd184, 0x0dc0, + 0xd1c4, 0x11a8, 0x00b8, 0x6974, 0x918c, 0xff00, 0x810f, 0x080c, + 0x4b58, 0x11c8, 0x6000, 0xd0e4, 0x11b0, 0x7120, 0x9186, 0x0007, + 0x1118, 0x6883, 0x0002, 0x0088, 0x6883, 0x0008, 0x0070, 0x6883, + 0x000e, 0x0058, 0x6883, 0x0017, 0x0040, 0x6883, 0x0035, 0x0028, + 0x6883, 0x0028, 0x0010, 0x6883, 0x0029, 0x012e, 0x00ee, 0x0418, + 0x6883, 0x002a, 0x0cd0, 0x6883, 0x0045, 0x0cb8, 0x2e60, 0x2019, + 0x0002, 0x601b, 0x0014, 0x080c, 0xa6bc, 0x012e, 0x00ee, 0x0005, + 0x2009, 0x003e, 0x0058, 0x2009, 0x0004, 0x0040, 0x2009, 0x0006, + 0x0028, 0x2009, 0x0016, 0x0010, 0x2009, 0x0001, 0x6884, 0x9084, + 0xff00, 0x9105, 0x6886, 0x0126, 0x2091, 0x8000, 0x080c, 0x50a5, + 0x012e, 0x0005, 0x080c, 0x0df6, 0x0005, 0x00d6, 0x080c, 0x6608, + 0x00de, 0x0005, 0x00d6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, + 0x0040, 0x702c, 0xd084, 0x01f0, 0x908c, 0x0780, 0x11f8, 0xd09c, + 0x11c8, 0x2071, 0x1100, 0x70b0, 0x90ea, 0x0010, 0x0298, 0x8001, + 0x70b2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, + 0x0000, 0x2071, 0x0040, 0x8d07, 0x8005, 0x8005, 0xc0d5, 0x7022, + 0x702c, 0x0c10, 0x012e, 0x00ee, 0x00de, 0x0005, 0x2011, 0x8003, + 0x080c, 0x37dc, 0x0cf8, 0x0006, 0x9084, 0x0780, 0x0128, 0x2011, + 0x8003, 0x080c, 0x37dc, 0x0cf8, 0x000e, 0x0005, 0x00d6, 0x00c6, + 0x0036, 0x0026, 0x0016, 0x7007, 0x0001, 0x6a74, 0x9282, 0x0004, + 0x1a04, 0x5fd9, 0xd284, 0x0170, 0x6a7c, 0x9290, 0x1000, 0x2204, + 0x9065, 0x6004, 0x05e0, 0x8007, 0x9084, 0x00ff, 0x9084, 0x0006, + 0x1108, 0x04a8, 0x2c10, 0x080c, 0x7ec8, 0x1118, 0x080c, 0x984d, + 0x05a0, 0x6212, 0x6874, 0x0002, 0x5fb8, 0x5fbd, 0x5fc0, 0x5fc6, + 0x2019, 0x0002, 0x080c, 0xaa50, 0x0060, 0x080c, 0xa9e7, 0x0048, + 0x2019, 0x0002, 0x6980, 0x080c, 0xaa02, 0x0018, 0x6980, 0x080c, + 0xa9e7, 0x080c, 0x7f1e, 0x6887, 0x0000, 0x0126, 0x2091, 0x8000, + 0x080c, 0x50a5, 0x012e, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00de, + 0x0005, 0x6887, 0x0006, 0x0c88, 0x6887, 0x0002, 0x0c70, 0x6887, + 0x0005, 0x0c58, 0x6887, 0x0004, 0x0c40, 0x6887, 0x0007, 0x0c28, + 0x0005, 0x781c, 0xd08c, 0x05f0, 0x7d44, 0x7c40, 0x9584, 0x00f6, + 0x1500, 0x9484, 0x7000, 0x0138, 0x908a, 0x2000, 0x1250, 0x9584, + 0x0700, 0x8007, 0x04b2, 0x7000, 0x9084, 0xff00, 0x9086, 0x8100, + 0x0db0, 0x9484, 0x0fff, 0x1130, 0x7000, 0x9084, 0xff00, 0x9086, + 0x8100, 0x11e0, 0x080c, 0xadbe, 0x080c, 0x6423, 0x7817, 0x0140, + 0x00c8, 0x9584, 0x0076, 0x1118, 0x080c, 0x6481, 0x19d0, 0xd5a4, + 0x0168, 0x080c, 0x136e, 0x7803, 0x0010, 0x78a0, 0x78a2, 0x2001, + 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x0020, 0x080c, 0xadbe, + 0x7817, 0x0140, 0x2001, 0x12e5, 0x2004, 0x9005, 0x090c, 0x6d42, + 0x0005, 0x6042, 0x626b, 0x6039, 0x6039, 0x6039, 0x6039, 0x6039, + 0x6039, 0x7817, 0x0140, 0x2001, 0x12e5, 0x2004, 0x9005, 0x090c, + 0x6d42, 0x0005, 0x7000, 0x908c, 0xff00, 0x9194, 0xf000, 0x810f, + 0x9484, 0x0fff, 0x6882, 0x9286, 0x2000, 0x1148, 0x6800, 0x9086, + 0x0001, 0x1118, 0x080c, 0x3e5a, 0x0068, 0x00a9, 0x0058, 0x9286, + 0x3000, 0x1118, 0x080c, 0x61b5, 0x0028, 0x9286, 0x8000, 0x1110, + 0x080c, 0x635d, 0x7817, 0x0140, 0x2001, 0x12e5, 0x2004, 0x9005, + 0x090c, 0x6d42, 0x0005, 0x00c6, 0x7010, 0x9084, 0xff00, 0x8007, + 0x9096, 0x0001, 0x0120, 0x9096, 0x0023, 0x1904, 0x61af, 0x9186, + 0x0023, 0x1550, 0x080c, 0x63f6, 0x0904, 0x61af, 0x7124, 0x610a, + 0x7030, 0x908e, 0x0200, 0x1130, 0x2009, 0x0015, 0x080c, 0x7f4e, + 0x0804, 0x61af, 0x908e, 0x0214, 0x0118, 0x908e, 0x0210, 0x1130, + 0x2009, 0x0015, 0x080c, 0x7f4e, 0x0804, 0x61af, 0x908e, 0x0100, + 0x1904, 0x61af, 0x7034, 0x9005, 0x1904, 0x61af, 0x2009, 0x0016, + 0x080c, 0x7f4e, 0x0804, 0x61af, 0x9186, 0x0022, 0x1904, 0x61af, + 0x7030, 0x908e, 0x0300, 0x1580, 0x68cc, 0xd0a4, 0x0528, 0xc0b5, + 0x68ce, 0x7100, 0x918c, 0x00ff, 0x696e, 0x7004, 0x6872, 0x00f6, + 0x2079, 0x0100, 0x79e6, 0x78ea, 0x0006, 0x9084, 0x00ff, 0x0016, + 0x2008, 0x080c, 0x1c93, 0x7932, 0x7936, 0x001e, 0x000e, 0x00fe, + 0x080c, 0x1c69, 0x694e, 0x703c, 0x00e6, 0x2071, 0x0140, 0x7086, + 0x2071, 0x1100, 0x70a2, 0x00ee, 0x7034, 0x9005, 0x1904, 0x61af, + 0x2009, 0x0017, 0x0804, 0x6175, 0x908e, 0x0400, 0x1158, 0x7034, + 0x9005, 0x1904, 0x61af, 0x68cc, 0xc0a5, 0x68ce, 0x2009, 0x0030, + 0x0804, 0x6175, 0x908e, 0x0500, 0x1140, 0x7034, 0x9005, 0x1904, + 0x61af, 0x2009, 0x0018, 0x0804, 0x6175, 0x908e, 0x2010, 0x1120, + 0x2009, 0x0019, 0x0804, 0x6175, 0x908e, 0x2110, 0x1120, 0x2009, + 0x001a, 0x0804, 0x6175, 0x908e, 0x5200, 0x1140, 0x7034, 0x9005, + 0x1904, 0x61af, 0x2009, 0x001b, 0x0804, 0x6175, 0x908e, 0x5000, + 0x1140, 0x7034, 0x9005, 0x1904, 0x61af, 0x2009, 0x001c, 0x0804, + 0x6175, 0x908e, 0x1300, 0x1120, 0x2009, 0x0034, 0x0804, 0x6175, + 0x908e, 0x1200, 0x1140, 0x7034, 0x9005, 0x1904, 0x61af, 0x2009, + 0x0024, 0x0804, 0x6175, 0x908c, 0xff00, 0x918e, 0x2400, 0x1120, + 0x2009, 0x002d, 0x0804, 0x6175, 0x908c, 0xff00, 0x918e, 0x5300, + 0x1118, 0x2009, 0x002a, 0x04c8, 0x908e, 0x0f00, 0x1118, 0x2009, + 0x0020, 0x0498, 0x908e, 0x5300, 0x1108, 0x00d8, 0x908e, 0x6104, + 0x11c0, 0x2011, 0x026d, 0x8208, 0x2204, 0x9082, 0x0004, 0x8004, + 0x8004, 0x20a8, 0x2011, 0x8015, 0x211c, 0x8108, 0x0046, 0x2124, + 0x080c, 0x37dc, 0x004e, 0x8108, 0x1f04, 0x6152, 0x2009, 0x0023, + 0x00a0, 0x908e, 0x6000, 0x1118, 0x2009, 0x003f, 0x0070, 0x908e, + 0x7800, 0x1118, 0x2009, 0x0045, 0x0040, 0x908e, 0x6300, 0x1118, + 0x2009, 0x004a, 0x0010, 0x2009, 0x001d, 0x0016, 0x2011, 0x0263, + 0x2204, 0x8211, 0x220c, 0x080c, 0x1c69, 0x1598, 0x080c, 0x4b03, + 0x1580, 0x6612, 0x6516, 0x86ff, 0x01e8, 0x001e, 0x0016, 0x9186, + 0x0017, 0x1158, 0x686c, 0x9606, 0x11a8, 0x6870, 0x9506, 0x9084, + 0xff00, 0x1180, 0x6000, 0xc0f5, 0x6002, 0x9186, 0x0046, 0x1150, + 0x686c, 0x9606, 0x1138, 0x6870, 0x9506, 0x9084, 0xff00, 0x1110, + 0x001e, 0x0068, 0x00c6, 0x080c, 0x7ec8, 0x0168, 0x001e, 0x6112, + 0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0x7f4e, 0x00ce, + 0x0005, 0x001e, 0x0ce0, 0x00ce, 0x0ce0, 0x080c, 0x26bc, 0x1140, + 0x7010, 0x9084, 0xff00, 0x8007, 0x908e, 0x0008, 0x1108, 0x0009, + 0x0005, 0x00c6, 0x0046, 0x7000, 0x908c, 0xff00, 0x810f, 0x9186, + 0x0033, 0x11e8, 0x080c, 0x63f6, 0x0904, 0x6212, 0x7124, 0x610a, + 0x7030, 0x908e, 0x0200, 0x1140, 0x7034, 0x9005, 0x15d8, 0x2009, + 0x0015, 0x080c, 0x7f4e, 0x04b0, 0x908e, 0x0100, 0x1598, 0x7034, + 0x9005, 0x1580, 0x2009, 0x0016, 0x080c, 0x7f4e, 0x0458, 0x9186, + 0x0032, 0x1540, 0x7030, 0x908e, 0x1400, 0x1520, 0x2009, 0x0038, + 0x0016, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x1c69, + 0x11c0, 0x080c, 0x4b03, 0x11a8, 0x6612, 0x6516, 0x00c6, 0x080c, + 0x7ec8, 0x0170, 0x001e, 0x6112, 0x080c, 0x99cc, 0x6023, 0x0004, + 0x7120, 0x610a, 0x001e, 0x080c, 0x7f4e, 0x080c, 0x6d42, 0x0010, + 0x00ce, 0x001e, 0x004e, 0x00ce, 0x0005, 0x0046, 0x00e6, 0x00d6, + 0x2028, 0x2130, 0x9696, 0x00ff, 0x11b0, 0x9592, 0xfffc, 0x0298, + 0x9596, 0xfffd, 0x1120, 0x2009, 0x007f, 0x0804, 0x6266, 0x9596, + 0xfffe, 0x1118, 0x2009, 0x007e, 0x04c8, 0x9596, 0xfffc, 0x1118, + 0x2009, 0x0080, 0x0498, 0x2011, 0x0000, 0x2019, 0x1133, 0x231c, + 0xd3ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, 0x1000, + 0x0030, 0x2021, 0x0081, 0x20a9, 0x007e, 0x2071, 0x1081, 0x2e1c, + 0x93ed, 0x0000, 0x1128, 0x82ff, 0x1170, 0x2410, 0xc2fd, 0x0058, + 0x6f10, 0x2600, 0x9706, 0x6814, 0x1120, 0x9546, 0x1110, 0x2408, + 0x0068, 0x9745, 0x0d80, 0x8420, 0x8e70, 0x1f04, 0x6247, 0x82ff, + 0x1118, 0x9085, 0x0001, 0x0018, 0xc2fc, 0x2208, 0x9006, 0x00de, + 0x00ee, 0x004e, 0x0005, 0x7000, 0x908c, 0xff00, 0x810f, 0x9184, + 0x0007, 0x004a, 0x7817, 0x0140, 0x2001, 0x12e5, 0x2004, 0x9005, + 0x090c, 0x6d42, 0x0005, 0x628b, 0x628b, 0x628b, 0x6408, 0x628b, + 0x6294, 0x62b1, 0x6340, 0x628b, 0x628b, 0x628b, 0x628b, 0x628b, + 0x628b, 0x628b, 0x628b, 0x7817, 0x0140, 0x2001, 0x12e5, 0x2004, + 0x9005, 0x090c, 0x6d42, 0x0005, 0x7110, 0xd1bc, 0x0188, 0x7120, + 0x2160, 0x9c8c, 0x0007, 0x1160, 0x9c8a, 0x15c0, 0x0248, 0x6858, + 0x9c02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0046, 0x080c, 0x7f4e, + 0x7817, 0x0140, 0x2001, 0x12e5, 0x2004, 0x9005, 0x090c, 0x6d42, + 0x0005, 0x00c6, 0x7110, 0xd1bc, 0x1904, 0x6316, 0x7108, 0x700c, + 0x2028, 0x918c, 0x00ff, 0x2130, 0x9094, 0xff00, 0x15d8, 0x81ff, + 0x15c8, 0x9080, 0x26c1, 0x200d, 0x918c, 0xff00, 0x810f, 0x9006, + 0x1904, 0x6316, 0x080c, 0x4b03, 0x1904, 0x6316, 0x6612, 0x6516, + 0x6000, 0xd0ec, 0x1904, 0x6316, 0x6204, 0x9294, 0xff00, 0x8217, + 0x9286, 0x0006, 0x1190, 0x00c6, 0x080c, 0x7ec8, 0x001e, 0x0904, + 0x6320, 0x6112, 0x6023, 0x0006, 0x7120, 0x610a, 0x7130, 0x6156, + 0x2009, 0x0044, 0x080c, 0x7f4e, 0x0448, 0x080c, 0x5745, 0x1170, + 0x6204, 0x9294, 0x00ff, 0x9286, 0x0006, 0x1140, 0x9295, 0x0600, + 0x6206, 0x0c08, 0x190c, 0x6215, 0x11c8, 0x0860, 0x00c6, 0x080c, + 0x7ec8, 0x001e, 0x0198, 0x6112, 0x6023, 0x0004, 0x7120, 0x610a, + 0x9286, 0x0004, 0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, + 0x6003, 0x0001, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x7817, 0x0140, + 0x2001, 0x12e5, 0x2004, 0x9005, 0x090c, 0x6d42, 0x00ce, 0x0005, + 0x2001, 0x110d, 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, + 0x37dc, 0x00c6, 0x080c, 0x984d, 0x001e, 0x0d40, 0x6112, 0x6023, + 0x0006, 0x7120, 0x610a, 0x7130, 0x6156, 0x6017, 0x0300, 0x6003, + 0x0001, 0x6007, 0x0041, 0x080c, 0x6886, 0x080c, 0x6d42, 0x08b0, + 0x7110, 0xd1bc, 0x0188, 0x7020, 0x2060, 0x9c84, 0x0007, 0x1160, + 0x9c82, 0x15c0, 0x0248, 0x6858, 0x9c02, 0x1230, 0x7124, 0x610a, + 0x2009, 0x0045, 0x080c, 0x7f4e, 0x7817, 0x0140, 0x2001, 0x12e5, + 0x2004, 0x9005, 0x090c, 0x6d42, 0x0005, 0x080c, 0x26bc, 0x1168, + 0x7010, 0x9084, 0xff00, 0x8007, 0x9086, 0x0000, 0x1130, 0x9184, + 0x000f, 0x908a, 0x0006, 0x1208, 0x000b, 0x0005, 0x6374, 0x6375, + 0x6374, 0x6374, 0x63de, 0x63ea, 0x0005, 0x7110, 0xd1bc, 0x0120, + 0x702c, 0xd084, 0x0904, 0x63dd, 0x700c, 0x7108, 0x080c, 0x1c69, + 0x1904, 0x63dd, 0x080c, 0x4b03, 0x1904, 0x63dd, 0x6612, 0x6516, + 0x6204, 0x7110, 0xd1bc, 0x01f8, 0x928c, 0x00ff, 0x9186, 0x0004, + 0x0118, 0x9186, 0x0006, 0x15c8, 0x00c6, 0x080c, 0x63f6, 0x00ce, + 0x0904, 0x63dd, 0x00c6, 0x080c, 0x7ec8, 0x001e, 0x05f0, 0x6112, + 0x080c, 0x99cc, 0x6023, 0x0002, 0x7120, 0x610a, 0x2009, 0x0088, + 0x080c, 0x7f4e, 0x0490, 0x928c, 0x00ff, 0x9186, 0x0006, 0x0160, + 0x9186, 0x0004, 0x0148, 0x9294, 0xff00, 0x8217, 0x9286, 0x0004, + 0x0118, 0x9286, 0x0006, 0x1188, 0x00c6, 0x080c, 0x7ec8, 0x001e, + 0x01e0, 0x6112, 0x080c, 0x99cc, 0x6023, 0x0005, 0x7120, 0x610a, + 0x2009, 0x0088, 0x080c, 0x7f4e, 0x0080, 0x00c6, 0x080c, 0x7ec8, + 0x001e, 0x0158, 0x6112, 0x080c, 0x99cc, 0x6023, 0x0004, 0x7120, + 0x610a, 0x2009, 0x0001, 0x080c, 0x7f4e, 0x0005, 0x7110, 0xd1bc, + 0x0140, 0x00a1, 0x0130, 0x7124, 0x610a, 0x2009, 0x0089, 0x080c, + 0x7f4e, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x0041, 0x0130, 0x7124, + 0x610a, 0x2009, 0x008a, 0x080c, 0x7f4e, 0x0005, 0x7020, 0x2060, + 0x9c84, 0x0007, 0x1158, 0x9c82, 0x15c0, 0x0240, 0x2001, 0x1116, + 0x2004, 0x9c02, 0x1218, 0x9085, 0x0001, 0x0005, 0x9006, 0x0ce8, + 0x7110, 0xd1bc, 0x1178, 0x7024, 0x2060, 0x9c84, 0x0007, 0x1150, + 0x9c82, 0x15c0, 0x0238, 0x6858, 0x9c02, 0x1220, 0x2009, 0x0051, + 0x080c, 0x7f4e, 0x7817, 0x0140, 0x2001, 0x12e5, 0x2004, 0x9005, + 0x090c, 0x6d42, 0x0005, 0x2031, 0x0105, 0x0069, 0x0005, 0x2031, + 0x0206, 0x0049, 0x0005, 0x2031, 0x0207, 0x0029, 0x0005, 0x2031, + 0x0213, 0x0009, 0x0005, 0x00c6, 0x00d6, 0x00f6, 0x7000, 0x9084, + 0xf000, 0x9086, 0xc000, 0x05d0, 0x080c, 0x7ec8, 0x05b8, 0x0066, + 0x00c6, 0x0046, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, + 0x1c69, 0x15a0, 0x080c, 0x4b03, 0x1588, 0x6612, 0x6516, 0x2c00, + 0x004e, 0x00ce, 0x6012, 0x080c, 0x99cc, 0x080c, 0x0ddf, 0x0510, + 0x2d00, 0x605a, 0x6803, 0x0000, 0x6867, 0x0000, 0x6c6a, 0x9df8, + 0x001b, 0x20a9, 0x000e, 0x20e9, 0x0001, 0x20e1, 0x0000, 0x2fa0, + 0x2e98, 0x4003, 0x006e, 0x6616, 0x6007, 0x003e, 0x6023, 0x0001, + 0x6003, 0x0001, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x00fe, 0x00de, + 0x00ce, 0x0005, 0x080c, 0x7f1e, 0x006e, 0x0cc0, 0x004e, 0x00ce, + 0x0cc8, 0x00c6, 0x7000, 0x908c, 0xff00, 0x9184, 0xf000, 0x810f, + 0x9086, 0x2000, 0x1548, 0x9186, 0x0022, 0x11d8, 0x2001, 0x0111, + 0x2004, 0x9005, 0x1518, 0x7030, 0x908e, 0x0400, 0x01f8, 0x908e, + 0x6000, 0x01e0, 0x908e, 0x5400, 0x01c8, 0x908e, 0x0300, 0x1140, + 0x2009, 0x1133, 0x210c, 0xd184, 0x0118, 0x080c, 0x5745, 0x0170, + 0x0058, 0x9186, 0x0023, 0x1140, 0x080c, 0x63f6, 0x0128, 0x6004, + 0x9086, 0x0002, 0x0118, 0x0000, 0x9006, 0x0010, 0x9085, 0x0001, + 0x00ce, 0x0005, 0x2071, 0x12ef, 0x7003, 0x0003, 0x700f, 0x0361, + 0x9006, 0x701a, 0x7012, 0x7017, 0x15c0, 0x7007, 0x0000, 0x7026, + 0x702b, 0x772e, 0x7032, 0x7037, 0x778e, 0x703b, 0xffff, 0x703f, + 0xffff, 0x7042, 0x7047, 0x3d63, 0x704a, 0x705b, 0x65ea, 0x2001, + 0x1291, 0x2003, 0x0003, 0x2001, 0x1293, 0x2003, 0x0100, 0x0005, + 0x2071, 0x12ef, 0x1d04, 0x654a, 0x2091, 0x6000, 0x700c, 0x8001, + 0x700e, 0x1180, 0x700f, 0x0361, 0x7007, 0x0001, 0x0126, 0x2091, + 0x8000, 0x7040, 0x900d, 0x0148, 0x8109, 0x7142, 0x1130, 0x7044, + 0x080f, 0x0018, 0x0126, 0x2091, 0x8000, 0x7024, 0x900d, 0x0188, + 0x7020, 0x8001, 0x7022, 0x1168, 0x7023, 0x0009, 0x8109, 0x7126, + 0x9186, 0x03e8, 0x1110, 0x7028, 0x080f, 0x81ff, 0x1110, 0x7028, + 0x080f, 0x7030, 0x900d, 0x0158, 0x702c, 0x8001, 0x702e, 0x1138, + 0x702f, 0x0009, 0x8109, 0x7132, 0x1110, 0x7034, 0x080f, 0x7038, + 0x9005, 0x0118, 0x0310, 0x8001, 0x703a, 0x703c, 0x9005, 0x0118, + 0x0310, 0x8001, 0x703e, 0x704c, 0x900d, 0x0168, 0x7048, 0x8001, + 0x704a, 0x1148, 0x704b, 0x0009, 0x8109, 0x714e, 0x1120, 0x7150, + 0x714e, 0x7058, 0x080f, 0x7018, 0x900d, 0x0158, 0x7008, 0x8001, + 0x700a, 0x1138, 0x700b, 0x0009, 0x8109, 0x711a, 0x1110, 0x701c, + 0x080f, 0x012e, 0x7004, 0x0002, 0x6570, 0x6571, 0x6589, 0x00e6, + 0x2071, 0x12ef, 0x7018, 0x9005, 0x1120, 0x711a, 0x721e, 0x700b, + 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0x12ef, 0x701c, + 0x9206, 0x1110, 0x701a, 0x701e, 0x000e, 0x00ee, 0x0005, 0x00e6, + 0x2071, 0x12ef, 0x6088, 0x9102, 0x0208, 0x618a, 0x00ee, 0x0005, + 0x0005, 0x7110, 0x080c, 0x4b58, 0x1158, 0x6088, 0x8001, 0x0240, + 0x608a, 0x1130, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d42, 0x012e, + 0x8108, 0x9182, 0x00ff, 0x0218, 0x900e, 0x7007, 0x0002, 0x7112, + 0x0005, 0x7014, 0x2060, 0x0126, 0x2091, 0x8000, 0x6040, 0x9005, + 0x0128, 0x8001, 0x6042, 0x1110, 0x080c, 0x9887, 0x6018, 0x9005, + 0x0500, 0x8001, 0x601a, 0x11e8, 0x6120, 0x9186, 0x0003, 0x0118, + 0x9186, 0x0006, 0x11a0, 0x6014, 0x2068, 0x6884, 0x908a, 0x199a, + 0x0270, 0x9082, 0x1999, 0x6886, 0x908a, 0x199a, 0x0210, 0x2001, + 0x1999, 0x8003, 0x800b, 0x810b, 0x9108, 0x611a, 0x0010, 0x080c, + 0x9362, 0x012e, 0x9c88, 0x0018, 0x7116, 0x2001, 0x45c0, 0x9102, + 0x0220, 0x7017, 0x15c0, 0x7007, 0x0000, 0x0005, 0x00e6, 0x2071, + 0x12ef, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, 0x0005, 0x2001, + 0x12f8, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, 0x12ef, 0x7132, + 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0x12fb, 0x2013, 0x0000, + 0x0005, 0x00e6, 0x2071, 0x12ef, 0x711a, 0x721e, 0x700b, 0x0009, + 0x00ee, 0x0005, 0x00c6, 0x0026, 0x7054, 0x8000, 0x7056, 0x2061, + 0x1291, 0x6008, 0x9086, 0x0000, 0x0158, 0x7068, 0x6036, 0x7064, + 0x6032, 0x7060, 0x602e, 0x705c, 0x602a, 0x2c10, 0x080c, 0x0e55, + 0x002e, 0x00ce, 0x0005, 0x00c6, 0x2061, 0x1329, 0x00ce, 0x0005, + 0x9184, 0x000f, 0x8003, 0x8003, 0x8003, 0x9080, 0x1329, 0x2060, + 0x0005, 0x6884, 0x908a, 0x199a, 0x1630, 0x9005, 0x1150, 0x00c6, + 0x2061, 0x1329, 0x6014, 0x00ce, 0x9005, 0x1130, 0x2001, 0x001e, + 0x0018, 0x908e, 0xffff, 0x01a8, 0x8003, 0x800b, 0x810b, 0x9108, + 0x611a, 0x687c, 0x908c, 0x00c0, 0x918e, 0x00c0, 0x0904, 0x668a, + 0xd0b4, 0x1160, 0xd0bc, 0x15b8, 0x2009, 0x0006, 0x080c, 0x66b0, + 0x0005, 0x900e, 0x0c68, 0x2001, 0x1999, 0x08b8, 0xd0fc, 0x0160, + 0x908c, 0x0003, 0x0120, 0x918e, 0x0003, 0x1904, 0x66aa, 0x908c, + 0x2020, 0x918e, 0x2020, 0x0180, 0x6024, 0xd0d4, 0x11a8, 0x2009, + 0x1174, 0x2104, 0xd084, 0x1120, 0x2009, 0x0043, 0x0804, 0x7f4e, + 0x2009, 0x0042, 0x0804, 0x7f4e, 0x6110, 0x210c, 0xd1ac, 0x0d60, + 0x6024, 0xc0cd, 0x6026, 0x0c40, 0xc0d4, 0x6026, 0x6890, 0x602e, + 0x688c, 0x6032, 0x0c20, 0xd0fc, 0x0158, 0x908c, 0x0003, 0x0118, + 0x908e, 0x0003, 0x15b8, 0x908c, 0x2020, 0x918e, 0x2020, 0x0150, + 0x00f6, 0x2c78, 0x080c, 0x119d, 0x00fe, 0x2009, 0x0042, 0x080c, + 0x7f4e, 0x0005, 0x6110, 0x210c, 0xd1ac, 0x0d90, 0x6124, 0xc1cd, + 0x6126, 0x0c70, 0xd0fc, 0x0178, 0x908c, 0x2020, 0x918e, 0x2020, + 0x0188, 0x9084, 0x0003, 0x908e, 0x0002, 0x0138, 0x2009, 0x0041, + 0x080c, 0x7f4e, 0x0005, 0x0091, 0x0ce8, 0x2009, 0x0043, 0x080c, + 0x7f4e, 0x0cc0, 0x6110, 0x210c, 0xd1ac, 0x0d58, 0x6124, 0xc1cd, + 0x6126, 0x0c38, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009, 0x0001, + 0x00d6, 0x6014, 0x90ec, 0xf000, 0x01f0, 0x2068, 0x6982, 0x6800, + 0x6016, 0x9186, 0x0001, 0x1188, 0x697c, 0x918c, 0x8100, 0x918e, + 0x8100, 0x1158, 0x00c6, 0x2061, 0x1329, 0x6200, 0xd28c, 0x1120, + 0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x4ef4, 0x6014, + 0x906d, 0x190c, 0x6611, 0x00de, 0x0005, 0x0156, 0x00c6, 0x2061, + 0x1329, 0x6000, 0x81ff, 0x0110, 0x9205, 0x0008, 0x9204, 0x6002, + 0x00ce, 0x015e, 0x0005, 0x6800, 0xd08c, 0x1138, 0x6808, 0x9005, + 0x0120, 0x8001, 0x680a, 0x9085, 0x0001, 0x0005, 0x20a9, 0x0010, + 0x9006, 0x8004, 0x80f6, 0x3e00, 0x81f6, 0x3e08, 0x1208, 0x9200, + 0x1f04, 0x66f2, 0x80f6, 0x3e00, 0x81f6, 0x3e08, 0x0005, 0x0156, + 0x20a9, 0x0010, 0x9005, 0x01c0, 0x911a, 0x12b0, 0x8213, 0x81f5, + 0x3e08, 0x0228, 0x911a, 0x1220, 0x1f04, 0x6706, 0x0028, 0x911a, + 0x2308, 0x8210, 0x1f04, 0x6706, 0x0006, 0x3200, 0x9084, 0xefff, + 0x2080, 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0x9085, 0x1000, + 0x0cb8, 0x0126, 0x2091, 0x2800, 0x2079, 0x12dc, 0x012e, 0x00d6, + 0x2069, 0x12dc, 0x6803, 0x0005, 0x0156, 0x0146, 0x01d6, 0x20e9, + 0x0000, 0x2069, 0x0200, 0x080c, 0x7e9b, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x080c, 0x7e86, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x080c, 0x7e89, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x080c, 0x7e8c, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x080c, 0x7e8f, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x080c, 0x7e92, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x080c, 0x7e95, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x080c, 0x7e98, 0x20a9, 0x0020, 0x20a1, + 0x0240, 0x9006, 0x4004, 0x01de, 0x014e, 0x015e, 0x2069, 0x0004, + 0x2d04, 0x9085, 0x8001, 0x206a, 0x00de, 0x0005, 0x00c6, 0x6027, + 0x0001, 0x7804, 0x9084, 0x0007, 0x0002, 0x678f, 0x67b3, 0x67fd, + 0x6795, 0x67b3, 0x678f, 0x678d, 0x678d, 0x080c, 0x0cf1, 0x080c, + 0x65cf, 0x080c, 0x6d42, 0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, + 0x00ce, 0x0005, 0x2011, 0x4586, 0x080c, 0x655b, 0x7828, 0x9092, + 0x00c8, 0x1228, 0x8000, 0x782a, 0x080c, 0x45c0, 0x0c88, 0x62c0, + 0x080c, 0x7e9f, 0x080c, 0x4586, 0x7807, 0x0003, 0x7827, 0x0000, + 0x782b, 0x0000, 0x0c28, 0x080c, 0x65cf, 0x6220, 0xd2a4, 0x0178, + 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, 0x9065, 0x090c, + 0x0cf1, 0x2009, 0x0013, 0x080c, 0x7f4e, 0x00ce, 0x0005, 0x00c6, + 0x7824, 0x9065, 0x090c, 0x0cf1, 0x7804, 0x9086, 0x0004, 0x0904, + 0x6839, 0x7828, 0x9092, 0x2710, 0x1230, 0x8000, 0x782a, 0x00ce, + 0x080c, 0x76fd, 0x0c50, 0x2011, 0x0130, 0x2214, 0x080c, 0x7e9f, + 0x6104, 0x9186, 0x0003, 0x1188, 0x00e6, 0x2071, 0x1100, 0x70d8, + 0x00ee, 0xd08c, 0x0150, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, + 0x1100, 0x080c, 0x45d6, 0x00ee, 0x00ce, 0x080c, 0xae07, 0x2009, + 0x0014, 0x080c, 0x7f4e, 0x00ce, 0x0840, 0x2001, 0x12f8, 0x2003, + 0x0000, 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, 0x9065, + 0x090c, 0x0cf1, 0x2009, 0x0013, 0x080c, 0x7fa6, 0x00ce, 0x0005, + 0x00c6, 0x00d6, 0x7824, 0x9005, 0x090c, 0x0cf1, 0x781c, 0x906d, + 0x090c, 0x0cf1, 0x080c, 0x7e9f, 0x6800, 0xc0dc, 0x6802, 0x7924, + 0x2160, 0x080c, 0x7f1e, 0x693c, 0x81ff, 0x090c, 0x0cf1, 0x8109, + 0x693e, 0x6854, 0x9015, 0x0110, 0x7a1e, 0x0010, 0x7918, 0x791e, + 0x7807, 0x0000, 0x7827, 0x0000, 0x00de, 0x00ce, 0x080c, 0x6d42, + 0x08a8, 0x6104, 0x9186, 0x0002, 0x0128, 0x9186, 0x0004, 0x0110, + 0x0804, 0x67d1, 0x7808, 0x9c06, 0x0904, 0x67d1, 0x080c, 0x6c56, + 0x080c, 0x68ce, 0x00ce, 0x080c, 0x6d42, 0x0804, 0x67c5, 0x00c6, + 0x6024, 0x6027, 0x0002, 0xd0f4, 0x1550, 0x62c8, 0x60c4, 0x9205, + 0x1170, 0x783c, 0x9065, 0x0130, 0x2009, 0x0049, 0x080c, 0x7f4e, + 0x00ce, 0x0005, 0x2011, 0x12fb, 0x2013, 0x0000, 0x0cc8, 0x793c, + 0x81ff, 0x0dc0, 0x793c, 0x9188, 0x0008, 0x210c, 0x918e, 0x0006, + 0x1138, 0x6014, 0x9084, 0x1984, 0x9085, 0x0012, 0x6016, 0x0c40, + 0x6014, 0x9084, 0x1984, 0x9085, 0x0016, 0x6016, 0x0c08, 0x793c, + 0x2160, 0x2009, 0x004a, 0x080c, 0x7f4e, 0x08d0, 0x0006, 0x0016, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, + 0x12dc, 0x6020, 0x8000, 0x6022, 0x6010, 0x9005, 0x0148, 0x9080, + 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, + 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069, 0x12dc, 0x6000, 0xd0d4, + 0x0178, 0x6820, 0x8000, 0x6822, 0x9086, 0x0001, 0x1110, 0x2c00, + 0x681e, 0x6804, 0x9084, 0x0007, 0x0804, 0x6d59, 0x00de, 0x0005, + 0xc0d5, 0x6002, 0x6818, 0x9005, 0x0158, 0x6056, 0x605b, 0x0000, + 0x0006, 0x2c00, 0x681a, 0x00de, 0x685a, 0x2069, 0x12dc, 0x0c08, + 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, 0x08d8, 0x0006, 0x0016, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, + 0x12dc, 0x6020, 0x8000, 0x6022, 0x6008, 0x9005, 0x0148, 0x9080, + 0x0003, 0x2102, 0x610a, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, + 0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061, + 0x12dc, 0x6034, 0x9005, 0x0130, 0x9080, 0x0003, 0x2102, 0x6136, + 0x00ce, 0x0005, 0x613a, 0x6136, 0x00ce, 0x0005, 0x00f6, 0x00e6, + 0x00d6, 0x00c6, 0x0076, 0x0066, 0x0026, 0x0016, 0x0006, 0x0126, + 0x2071, 0x12dc, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, + 0x0904, 0x696a, 0x6010, 0x9080, 0x0028, 0x2004, 0x9206, 0x1904, + 0x6965, 0x87ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x6965, 0x703c, + 0x9c06, 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7936, 0x7033, + 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x003e, + 0x7038, 0x9c36, 0x1110, 0x660c, 0x763a, 0x7034, 0x9c36, 0x1140, + 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, + 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, + 0x600f, 0x0000, 0x080c, 0x95d2, 0x0198, 0x6014, 0x2068, 0x6020, + 0x9086, 0x0003, 0x1510, 0x6867, 0x0103, 0x6b7a, 0x6877, 0x0000, + 0x080c, 0x9843, 0x080c, 0xad5f, 0x080c, 0x50a5, 0x080c, 0x9797, + 0x080c, 0x97a3, 0x00ce, 0x0804, 0x690f, 0x2c78, 0x600c, 0x2060, + 0x0804, 0x690f, 0x012e, 0x000e, 0x001e, 0x002e, 0x006e, 0x007e, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, + 0x1128, 0x080c, 0xad5f, 0x080c, 0xaa84, 0x0c10, 0x08a0, 0x0006, + 0x0066, 0x00c6, 0x00d6, 0x00f6, 0x2031, 0x0000, 0x0126, 0x2091, + 0x8000, 0x2079, 0x12dc, 0x7838, 0x9065, 0x0558, 0x600c, 0x0006, + 0x600f, 0x0000, 0x783c, 0x9c06, 0x1170, 0x0036, 0x2019, 0x0001, + 0x080c, 0x7936, 0x7833, 0x0000, 0x783f, 0x0000, 0x7843, 0x0000, + 0x7847, 0x0000, 0x003e, 0x080c, 0x95d2, 0x0178, 0x6014, 0x2068, + 0x6020, 0x9086, 0x0003, 0x11b0, 0x6867, 0x0103, 0x6b7a, 0x6877, + 0x0000, 0x080c, 0x50a5, 0x080c, 0x9797, 0x080c, 0x97a3, 0x000e, + 0x0898, 0x7e3a, 0x7e36, 0x012e, 0x00fe, 0x00de, 0x00ce, 0x006e, + 0x000e, 0x0005, 0x6020, 0x9086, 0x0006, 0x1118, 0x080c, 0xaa84, + 0x0c60, 0x0c10, 0x0016, 0x0026, 0x0086, 0x2041, 0x0000, 0x0099, + 0x080c, 0x6a8c, 0x008e, 0x002e, 0x001e, 0x0005, 0x00f6, 0x0126, + 0x2079, 0x12dc, 0x2091, 0x8000, 0x080c, 0x6b19, 0x080c, 0x6b8b, + 0x012e, 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, + 0x0016, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x12dc, 0x7614, + 0x2660, 0x2678, 0x8cff, 0x0904, 0x6a68, 0x6010, 0x9080, 0x0028, + 0x2004, 0x9206, 0x1904, 0x6a63, 0x88ff, 0x0120, 0x6054, 0x9106, + 0x1904, 0x6a63, 0x7024, 0x9c06, 0x1538, 0x2069, 0x0100, 0x68c0, + 0x9005, 0x01f0, 0x080c, 0x65cf, 0x080c, 0x7721, 0x68c3, 0x0000, + 0x080c, 0x7b56, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, + 0x9384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, + 0x6003, 0x0009, 0x630a, 0x04b8, 0x7014, 0x9c36, 0x1110, 0x660c, + 0x7616, 0x7010, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, + 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, + 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6014, 0x2068, + 0x080c, 0x95d2, 0x0188, 0x6020, 0x9086, 0x0003, 0x1510, 0x6867, + 0x0103, 0x6b7a, 0x6877, 0x0000, 0x080c, 0x9843, 0x080c, 0xad5f, + 0x080c, 0x50a5, 0x080c, 0x9797, 0x080c, 0x97a3, 0x080c, 0x7a3e, + 0x00ce, 0x0804, 0x69f2, 0x2c78, 0x600c, 0x2060, 0x0804, 0x69f2, + 0x012e, 0x000e, 0x001e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, + 0x0005, 0x6020, 0x9086, 0x0006, 0x1128, 0x080c, 0xad5f, 0x080c, + 0xaa84, 0x0c10, 0x6020, 0x9086, 0x0002, 0x1128, 0x6004, 0x9086, + 0x0085, 0x0968, 0x08c8, 0x6020, 0x9086, 0x0005, 0x19a8, 0x6004, + 0x9086, 0x0085, 0x0d50, 0x0880, 0x00c6, 0x0006, 0x0126, 0x2091, + 0x8000, 0x9280, 0x1000, 0x2004, 0x9065, 0x0904, 0x6b15, 0x00f6, + 0x00e6, 0x00d6, 0x0066, 0x2071, 0x12dc, 0x6654, 0x7018, 0x9c06, + 0x1108, 0x761a, 0x701c, 0x9c06, 0x1130, 0x86ff, 0x1118, 0x7018, + 0x701e, 0x0008, 0x761e, 0x6058, 0x907d, 0x0108, 0x7e56, 0x96ed, + 0x0000, 0x0110, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, 0x0000, + 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x4a97, 0x0904, 0x6b11, + 0x7624, 0x86ff, 0x05e8, 0x9680, 0x0005, 0x2004, 0x9d06, 0x15c0, + 0x00d6, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0548, 0x080c, 0x65cf, + 0x080c, 0x7721, 0x68c3, 0x0000, 0x080c, 0x7b56, 0x7027, 0x0000, + 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0120, 0x6803, + 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, + 0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0x9005, 0x0110, + 0x8001, 0x603e, 0x2660, 0x080c, 0x97a3, 0x00ce, 0x0048, 0x00de, + 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6abc, + 0x8dff, 0x0158, 0x6867, 0x0103, 0x6b7a, 0x6877, 0x0000, 0x080c, + 0x9843, 0x080c, 0xad5f, 0x080c, 0x50a5, 0x080c, 0x7a3e, 0x0804, + 0x6abc, 0x006e, 0x00de, 0x00ee, 0x00fe, 0x012e, 0x000e, 0x00ce, + 0x0005, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x2031, 0x0000, 0x7814, + 0x9065, 0x0904, 0x6b6b, 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, + 0x9c06, 0x1540, 0x2069, 0x0100, 0x68c0, 0x9005, 0x01f0, 0x080c, + 0x65cf, 0x080c, 0x7721, 0x68c3, 0x0000, 0x080c, 0x7b56, 0x7827, + 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0120, + 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, + 0x0110, 0x6827, 0x0001, 0x003e, 0x0028, 0x6003, 0x0009, 0x630a, + 0x2c30, 0x00b0, 0x6014, 0x2068, 0x080c, 0x95d2, 0x0168, 0x6020, + 0x9086, 0x0003, 0x11b8, 0x6867, 0x0103, 0x6b7a, 0x6877, 0x0000, + 0x080c, 0x50a5, 0x080c, 0x9797, 0x080c, 0x97a3, 0x080c, 0x7a3e, + 0x000e, 0x0804, 0x6b20, 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, + 0x000e, 0x0005, 0x6020, 0x9086, 0x0006, 0x1118, 0x080c, 0xaa84, + 0x0c58, 0x6020, 0x9086, 0x0002, 0x1128, 0x6004, 0x9086, 0x0085, + 0x09d0, 0x0c10, 0x6020, 0x9086, 0x0005, 0x19f0, 0x6004, 0x9086, + 0x0085, 0x0d60, 0x08c8, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x7818, + 0x9065, 0x0904, 0x6bf1, 0x6054, 0x0006, 0x6057, 0x0000, 0x605b, + 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x4a97, 0x0904, + 0x6bee, 0x7e24, 0x86ff, 0x05e8, 0x9680, 0x0005, 0x2004, 0x9d06, + 0x15c0, 0x00d6, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0548, 0x080c, + 0x65cf, 0x080c, 0x7721, 0x68c3, 0x0000, 0x080c, 0x7b56, 0x7827, + 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0120, + 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, + 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0x9005, + 0x0110, 0x8001, 0x603e, 0x2660, 0x080c, 0x97a3, 0x00ce, 0x0048, + 0x00de, 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, + 0x6b9d, 0x8dff, 0x0138, 0x6867, 0x0103, 0x6b7a, 0x6877, 0x0000, + 0x080c, 0x50a5, 0x080c, 0x7a3e, 0x0804, 0x6b9d, 0x000e, 0x0804, + 0x6b90, 0x781e, 0x781a, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, + 0x00e6, 0x00d6, 0x0066, 0x6000, 0xd0dc, 0x0188, 0x604c, 0x906d, + 0x0170, 0x6878, 0x9606, 0x1158, 0x2071, 0x12dc, 0x7024, 0x9035, + 0x0130, 0x9080, 0x0005, 0x2004, 0x9d06, 0x1108, 0x0021, 0x006e, + 0x00de, 0x00ee, 0x0005, 0x00f6, 0x2079, 0x0100, 0x78c0, 0x9005, + 0x1138, 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x04a0, + 0x080c, 0x7721, 0x78c3, 0x0000, 0x080c, 0x7b56, 0x7027, 0x0000, + 0x0036, 0x2079, 0x0140, 0x7b04, 0x9384, 0x1000, 0x0120, 0x7803, + 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, 0x7824, 0xd084, 0x0110, + 0x7827, 0x0001, 0x080c, 0x7b56, 0x003e, 0x080c, 0x4a97, 0x00c6, + 0x603c, 0x9005, 0x0110, 0x8001, 0x603e, 0x2660, 0x080c, 0x7f1e, + 0x00ce, 0x6867, 0x0103, 0x6b7a, 0x6877, 0x0000, 0x080c, 0x9843, + 0x080c, 0x50a5, 0x080c, 0x7a3e, 0x00fe, 0x0005, 0x00e6, 0x00c6, + 0x2001, 0x110c, 0x2014, 0xc2e4, 0x2202, 0x2071, 0x12dc, 0x7004, + 0x9084, 0x0007, 0x0002, 0x6c6d, 0x6c70, 0x6c86, 0x6ca4, 0x6cdd, + 0x6c6d, 0x6c6b, 0x6c6b, 0x080c, 0x0cf1, 0x00ce, 0x00ee, 0x0005, + 0x7024, 0x9065, 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0x9015, + 0x0150, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, + 0x00ce, 0x00ee, 0x0005, 0x7216, 0x7212, 0x0cb0, 0x6010, 0x2060, + 0x080c, 0x4a97, 0x6000, 0xc0dc, 0x6002, 0x7007, 0x0000, 0x7027, + 0x0000, 0x7020, 0x8001, 0x7022, 0x1118, 0x00ce, 0x00ee, 0x0005, + 0x6054, 0x9015, 0x0120, 0x721e, 0x080c, 0x6d42, 0x0cb0, 0x7218, + 0x721e, 0x080c, 0x6d42, 0x0c88, 0x7024, 0x9065, 0x0598, 0x700c, + 0x9c06, 0x1160, 0x080c, 0x7a3e, 0x600c, 0x9015, 0x0120, 0x720e, + 0x600f, 0x0000, 0x0428, 0x720e, 0x720a, 0x0410, 0x7014, 0x9c06, + 0x1160, 0x080c, 0x7a3e, 0x600c, 0x9015, 0x0120, 0x7216, 0x600f, + 0x0000, 0x00b0, 0x7216, 0x7212, 0x0098, 0x6010, 0x2060, 0x080c, + 0x4a97, 0x6000, 0xc0dc, 0x6002, 0x080c, 0x7a3e, 0x701c, 0x9065, + 0x0138, 0x6054, 0x9015, 0x0110, 0x721e, 0x0010, 0x7218, 0x721e, + 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, 0x7024, 0x9065, 0x0140, + 0x080c, 0x7a3e, 0x600c, 0x9015, 0x0150, 0x720e, 0x600f, 0x0000, + 0x080c, 0x7b56, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, 0x720e, + 0x720a, 0x0cb0, 0x00d6, 0x2069, 0x12dc, 0x6830, 0x9084, 0x0003, + 0x0002, 0x6cff, 0x6d01, 0x6d25, 0x6cfd, 0x080c, 0x0cf1, 0x00de, + 0x0005, 0x00c6, 0x6840, 0x9086, 0x0001, 0x01b8, 0x683c, 0x9065, + 0x0130, 0x600c, 0x9015, 0x0170, 0x6a3a, 0x600f, 0x0000, 0x6833, + 0x0000, 0x683f, 0x0000, 0x2011, 0x12fb, 0x2013, 0x0000, 0x00ce, + 0x00de, 0x0005, 0x683a, 0x6836, 0x0c90, 0x6843, 0x0000, 0x6838, + 0x9065, 0x0d68, 0x6003, 0x0003, 0x0c50, 0x00c6, 0x6843, 0x0000, + 0x6847, 0x0000, 0x683c, 0x9065, 0x0168, 0x600c, 0x9015, 0x0130, + 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, 0x0020, 0x683f, 0x0000, + 0x683a, 0x6836, 0x00ce, 0x00de, 0x0005, 0xc1e5, 0x2001, 0x110c, + 0x2102, 0x0005, 0x2001, 0x110c, 0x200c, 0xd1ec, 0x0138, 0xc1ec, + 0x2102, 0x080c, 0x6e10, 0x2001, 0x110c, 0x200c, 0x9184, 0x0600, + 0x9086, 0x0600, 0x0d50, 0x00d6, 0x2069, 0x12dc, 0x6804, 0x9084, + 0x0007, 0x0002, 0x6d64, 0x6def, 0x6def, 0x6def, 0x6def, 0x6df1, + 0x6d62, 0x6d62, 0x080c, 0x0cf1, 0x6820, 0x9005, 0x1110, 0x00de, + 0x0005, 0x00c6, 0x680c, 0x9065, 0x0150, 0x6807, 0x0004, 0x6826, + 0x682b, 0x0000, 0x080c, 0x6e53, 0x00ce, 0x00de, 0x0005, 0x6814, + 0x9065, 0x0150, 0x6807, 0x0001, 0x6826, 0x682b, 0x0000, 0x080c, + 0x6e53, 0x00ce, 0x00de, 0x0005, 0x00e6, 0x6a1c, 0x92f5, 0x0000, + 0x0904, 0x6dec, 0x704c, 0x900d, 0x0118, 0x7088, 0x9005, 0x01a0, + 0x7054, 0x9075, 0x0120, 0x920e, 0x0904, 0x6dec, 0x0028, 0x6818, + 0x920e, 0x0904, 0x6dec, 0x2070, 0x704c, 0x900d, 0x0d88, 0x7088, + 0x9005, 0x1d70, 0x2e00, 0x681e, 0x733c, 0x7038, 0x9302, 0x1e40, + 0x080c, 0x7ef5, 0x0904, 0x6dec, 0x8318, 0x733e, 0x6116, 0x2e10, + 0x6212, 0x9180, 0x0020, 0x2004, 0x9084, 0x00ff, 0x605e, 0x9180, + 0x0020, 0x2003, 0x0000, 0x9180, 0x0021, 0x2004, 0x908a, 0x199a, + 0x0210, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, 0x9318, 0x631a, + 0x00f6, 0x2c78, 0x2061, 0x0100, 0x609b, 0x0000, 0x00d6, 0x00e6, + 0x2069, 0x0200, 0x2071, 0x0240, 0x080c, 0x738a, 0x00ee, 0x00de, + 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b, + 0x0000, 0x7823, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, 0x00fe, + 0x00ee, 0x00ce, 0x00de, 0x0005, 0x00ee, 0x00ce, 0x0cd8, 0x00de, + 0x0005, 0x00c6, 0x680c, 0x9065, 0x0138, 0x6807, 0x0004, 0x6826, + 0x682b, 0x0000, 0x080c, 0x6e53, 0x00ce, 0x00de, 0x0005, 0x2001, + 0x110c, 0x2014, 0xc2ed, 0x2202, 0x00de, 0x00fe, 0x0005, 0x2001, + 0x110c, 0x2014, 0xd2e4, 0x0120, 0xc2e4, 0x2202, 0x080c, 0x6d53, + 0x00f6, 0x00d6, 0x2069, 0x12dc, 0x6830, 0x9086, 0x0000, 0x11e0, + 0x2001, 0x110c, 0x200c, 0xd1c4, 0x11d0, 0x6838, 0x907d, 0x01a0, + 0x6a04, 0x9296, 0x0000, 0x19d8, 0x6833, 0x0001, 0x683e, 0x6847, + 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, 0x1421, + 0x1178, 0x012e, 0x080c, 0x75b1, 0x00de, 0x00fe, 0x0005, 0xc1c4, + 0x2102, 0x0066, 0x2031, 0x0001, 0x080c, 0x57d6, 0x006e, 0x08e8, + 0x012e, 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, 0x9015, 0x0140, + 0x6a3a, 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c20, + 0x683a, 0x6836, 0x0cc0, 0x6020, 0x9084, 0x000f, 0x000b, 0x0005, + 0x6e66, 0x6e6b, 0x7280, 0x733f, 0x6e6b, 0x7280, 0x733f, 0x6e66, + 0x6e6b, 0x6e66, 0x6e66, 0x6e66, 0x6e66, 0x6e66, 0x080c, 0x6c56, + 0x080c, 0x6d42, 0x0005, 0x0156, 0x0136, 0x0146, 0x01c6, 0x01d6, + 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200, 0x2071, 0x0240, + 0x6004, 0x908a, 0x004c, 0x1a0c, 0x0cf1, 0x6110, 0x2178, 0x79a0, + 0x2011, 0x1133, 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x7900, + 0xd1f4, 0x0120, 0x7914, 0x918c, 0x00ff, 0x0040, 0x2009, 0x0000, + 0x0028, 0x91f8, 0x26c1, 0x2f0d, 0x918c, 0x00ff, 0x2c78, 0x2061, + 0x0100, 0x619a, 0x908a, 0x0040, 0x1a04, 0x6eeb, 0x0053, 0x00fe, + 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e, 0x013e, 0x015e, + 0x0005, 0x6fc3, 0x7004, 0x7033, 0x70d5, 0x70f8, 0x70fe, 0x710c, + 0x7115, 0x7122, 0x7128, 0x713a, 0x7128, 0x718a, 0x7115, 0x7197, + 0x719d, 0x7122, 0x719d, 0x71aa, 0x6ee9, 0x6ee9, 0x6ee9, 0x6ee9, + 0x6ee9, 0x6ee9, 0x6ee9, 0x6ee9, 0x6ee9, 0x6ee9, 0x6ee9, 0x7802, + 0x7819, 0x7824, 0x7845, 0x7867, 0x710c, 0x6ee9, 0x710c, 0x7128, + 0x6ee9, 0x7033, 0x70d5, 0x6ee9, 0x7c3b, 0x7128, 0x6ee9, 0x7c57, + 0x7128, 0x6ee9, 0x7122, 0x6fbc, 0x6f05, 0x6ee9, 0x7c6e, 0x7cdb, + 0x7db2, 0x6ee9, 0x7dbf, 0x7109, 0x7dd5, 0x6ee9, 0x7872, 0x7e0f, + 0x6ee9, 0x080c, 0x0cf1, 0x2100, 0x0053, 0x00fe, 0x00ee, 0x00de, + 0x00ce, 0x01de, 0x01ce, 0x014e, 0x013e, 0x015e, 0x0005, 0x6f03, + 0x6f03, 0x6f03, 0x6f2b, 0x6f45, 0x6f55, 0x6f03, 0x6f03, 0x6f03, + 0x6f8e, 0x6f9d, 0x6f03, 0x080c, 0x0cf1, 0x00d6, 0x080c, 0x71be, + 0x7003, 0x2414, 0x7007, 0x0018, 0x700b, 0x0800, 0x7814, 0x2068, + 0x683c, 0x700e, 0x6850, 0x7022, 0x6854, 0x7026, 0x60c3, 0x0018, + 0x080c, 0x76f5, 0x00de, 0x0005, 0x00d6, 0x7810, 0x2068, 0x68a0, + 0x2069, 0x1100, 0x6acc, 0xd2ac, 0x1110, 0xd0bc, 0x0110, 0x9085, + 0x0001, 0x00de, 0x0005, 0x00d6, 0x080c, 0x71be, 0x7003, 0x0500, + 0x7814, 0x90e8, 0x001b, 0x6808, 0x700a, 0x680c, 0x700e, 0x6810, + 0x7012, 0x6814, 0x7016, 0x6818, 0x701a, 0x681c, 0x701e, 0x60c3, + 0x0010, 0x080c, 0x76f5, 0x00de, 0x0005, 0x080c, 0x71be, 0x7003, + 0x7800, 0x7007, 0x0000, 0x7808, 0x8007, 0x700a, 0x700f, 0x0000, + 0x60c3, 0x0008, 0x080c, 0x76f5, 0x0005, 0x00d6, 0x00e6, 0x080c, + 0x7234, 0x2073, 0x0200, 0x8e70, 0x2073, 0x0000, 0x8e70, 0x2073, + 0xdf10, 0x8e70, 0x2073, 0x0034, 0x8e70, 0x2069, 0x1105, 0x20a9, + 0x0004, 0x2d76, 0x8d68, 0x8e70, 0x1f04, 0x6f69, 0x2069, 0x1101, + 0x20a9, 0x0004, 0x2d76, 0x8d68, 0x8e70, 0x1f04, 0x6f72, 0x2069, + 0x12c2, 0x20a9, 0x001a, 0x2d04, 0x8007, 0x2072, 0x8d68, 0x8e70, + 0x1f04, 0x6f7b, 0x2073, 0x0000, 0x8e70, 0x2073, 0x0000, 0x60c3, + 0x004c, 0x080c, 0x76f5, 0x00ee, 0x00de, 0x0005, 0x080c, 0x71be, + 0x7003, 0x6300, 0x7007, 0x0028, 0x700b, 0x0000, 0x7808, 0x700e, + 0x60c3, 0x0008, 0x080c, 0x76f5, 0x0005, 0x00d6, 0x0026, 0x0016, + 0x080c, 0x7234, 0x7003, 0x0200, 0x7814, 0x700e, 0x00e6, 0x9ef0, + 0x0004, 0x2009, 0x0001, 0x2011, 0x000c, 0x2073, 0x0800, 0x8e70, + 0x2073, 0x0000, 0x00ee, 0x7206, 0x710a, 0x62c2, 0x080c, 0x76f5, + 0x001e, 0x002e, 0x00de, 0x0005, 0x2001, 0x1114, 0x2004, 0x609a, + 0x080c, 0x76f5, 0x0005, 0x080c, 0x71be, 0x7003, 0x5200, 0x2069, + 0x1152, 0x6804, 0xd084, 0x0130, 0x6828, 0x0016, 0x080c, 0x1c7d, + 0x710e, 0x001e, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, 0x1105, + 0x20e9, 0x0000, 0x20a1, 0x0250, 0x4003, 0x20a9, 0x0004, 0x2099, + 0x1101, 0x20a1, 0x0254, 0x4003, 0x2001, 0x1133, 0x2004, 0xd0ac, + 0x1138, 0x7810, 0x9080, 0x0028, 0x2004, 0x9082, 0x007f, 0x0248, + 0x2001, 0x111b, 0x2004, 0x7032, 0x2001, 0x111c, 0x2004, 0x7036, + 0x0030, 0x2001, 0x1114, 0x2004, 0x9084, 0x00ff, 0x7036, 0x60c3, + 0x001c, 0x080c, 0x76f5, 0x0005, 0x080c, 0x71be, 0x7003, 0x0500, + 0x2001, 0x1133, 0x2004, 0xd0ac, 0x1138, 0x7810, 0x9080, 0x0028, + 0x2004, 0x9082, 0x007f, 0x0248, 0x2001, 0x111b, 0x2004, 0x700a, + 0x2001, 0x111c, 0x2004, 0x700e, 0x0030, 0x2001, 0x1114, 0x2004, + 0x9084, 0x00ff, 0x700e, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, + 0x1105, 0x20e9, 0x0000, 0x20a1, 0x0250, 0x4003, 0x60c3, 0x0010, + 0x080c, 0x76f5, 0x0005, 0x080c, 0x71be, 0x00c6, 0x7810, 0x2060, + 0x2001, 0x0000, 0x080c, 0x4dea, 0x00ce, 0x7810, 0x9080, 0x0028, + 0x2004, 0x9086, 0x007e, 0x1130, 0x7003, 0x0400, 0x620c, 0xc2b4, + 0x620e, 0x0010, 0x7003, 0x0300, 0x7810, 0x9080, 0x0028, 0x2004, + 0x9086, 0x007e, 0x1904, 0x70a1, 0x00d6, 0x2069, 0x127f, 0x2001, + 0x1133, 0x2004, 0xd0a4, 0x0178, 0x6800, 0x700a, 0x6808, 0x9084, + 0x2000, 0x7012, 0x680c, 0x7016, 0x701f, 0x2710, 0x6818, 0x7022, + 0x681c, 0x7026, 0x0080, 0x6800, 0x700a, 0x6804, 0x700e, 0x6808, + 0x080c, 0x5745, 0x1118, 0x9084, 0x37ff, 0x0010, 0x9084, 0x3fff, + 0x7012, 0x680c, 0x7016, 0x00de, 0x20a9, 0x0004, 0x20e1, 0x0001, + 0x2099, 0x1105, 0x20e9, 0x0000, 0x20a1, 0x0256, 0x4003, 0x20a9, + 0x0004, 0x2099, 0x1101, 0x20a1, 0x025a, 0x4003, 0x00d6, 0x080c, + 0x7e86, 0x2069, 0x1287, 0x2071, 0x024e, 0x6800, 0xc0dd, 0x7002, + 0x2001, 0x1172, 0x2004, 0xd0e4, 0x0110, 0x680c, 0x700e, 0x00de, + 0x0478, 0x2001, 0x1133, 0x2004, 0xd0a4, 0x0140, 0x2001, 0x1280, + 0x2004, 0x60e3, 0x0000, 0x080c, 0x1cbe, 0x60e2, 0x20e1, 0x0001, + 0x2099, 0x127f, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x20a9, 0x0008, + 0x4003, 0x20a9, 0x0004, 0x2099, 0x1105, 0x20a1, 0x0256, 0x4003, + 0x20a9, 0x0004, 0x2099, 0x1101, 0x20a1, 0x025a, 0x4003, 0x080c, + 0x7e86, 0x20a1, 0x024e, 0x20a9, 0x0008, 0x2099, 0x1287, 0x4003, + 0x60c3, 0x0074, 0x080c, 0x76f5, 0x0005, 0x080c, 0x71be, 0x7003, + 0x2010, 0x7007, 0x0014, 0x700b, 0x0800, 0x700f, 0x2000, 0x9006, + 0x00f6, 0x2079, 0x1152, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0x9085, + 0x0020, 0xd1a4, 0x0110, 0x9085, 0x0010, 0x9085, 0x0002, 0x00d6, + 0x0804, 0x716e, 0x7026, 0x60c3, 0x0014, 0x080c, 0x76f5, 0x0005, + 0x080c, 0x71be, 0x7003, 0x5000, 0x0804, 0x704c, 0x080c, 0x71be, + 0x7003, 0x2110, 0x7007, 0x0014, 0x60c3, 0x0014, 0x080c, 0x76f5, + 0x0005, 0x080c, 0x722b, 0x0010, 0x080c, 0x7234, 0x7003, 0x0200, + 0x60c3, 0x0004, 0x080c, 0x76f5, 0x0005, 0x080c, 0x7234, 0x7003, + 0x0100, 0x700b, 0x0003, 0x700f, 0x2a00, 0x60c3, 0x0008, 0x080c, + 0x76f5, 0x0005, 0x080c, 0x7234, 0x7003, 0x0200, 0x0804, 0x704c, + 0x080c, 0x7234, 0x7003, 0x0100, 0x782c, 0x9005, 0x0110, 0x700a, + 0x0010, 0x700b, 0x0003, 0x7814, 0x700e, 0x60c3, 0x0008, 0x080c, + 0x76f5, 0x0005, 0x00d6, 0x080c, 0x7234, 0x7003, 0x0210, 0x7007, + 0x0014, 0x700b, 0x0800, 0x7810, 0x2068, 0x6894, 0x9086, 0x0014, + 0x1178, 0x6998, 0x9184, 0xc000, 0x1140, 0xd1ec, 0x0118, 0x700f, + 0x2100, 0x0040, 0x700f, 0x0100, 0x0028, 0x700f, 0x0400, 0x0010, + 0x700f, 0x0700, 0x00f6, 0x2079, 0x1152, 0x7904, 0x00fe, 0xd1ac, + 0x1110, 0x9085, 0x0020, 0xd1a4, 0x0110, 0x9085, 0x0010, 0x2009, + 0x1174, 0x210c, 0xd184, 0x1110, 0x9085, 0x0002, 0x0026, 0x2009, + 0x1172, 0x210c, 0xd1e4, 0x0130, 0xc0c5, 0x9094, 0x0030, 0x9296, + 0x0010, 0x0140, 0xd1ec, 0x0130, 0x9094, 0x0030, 0x9296, 0x0010, + 0x0108, 0xc0bd, 0x002e, 0x7026, 0x60c3, 0x0014, 0x00de, 0x080c, + 0x76f5, 0x0005, 0x080c, 0x7234, 0x7003, 0x0210, 0x7007, 0x0014, + 0x700f, 0x0100, 0x60c3, 0x0014, 0x080c, 0x76f5, 0x0005, 0x080c, + 0x7234, 0x7003, 0x0200, 0x0804, 0x6fc7, 0x080c, 0x7234, 0x7003, + 0x0100, 0x700b, 0x0003, 0x700f, 0x2a00, 0x60c3, 0x0008, 0x080c, + 0x76f5, 0x0005, 0x080c, 0x7234, 0x7003, 0x0100, 0x700b, 0x000b, + 0x60c3, 0x0008, 0x080c, 0x76f5, 0x0005, 0x0026, 0x00d6, 0x0036, + 0x0046, 0x2019, 0x3200, 0x2021, 0x0800, 0x0040, 0x0026, 0x00d6, + 0x0036, 0x0046, 0x2019, 0x2200, 0x2021, 0x0100, 0x080c, 0x7e9b, + 0x7810, 0x2068, 0x6810, 0x9305, 0x7002, 0x6814, 0x7006, 0x6aa0, + 0x2069, 0x1100, 0x6850, 0x700e, 0x9286, 0x007e, 0x1168, 0x9385, + 0x00ff, 0x7002, 0x7007, 0xfffe, 0x2001, 0x128f, 0x2004, 0x9005, + 0x01e8, 0x6a70, 0x720e, 0x00d0, 0x9286, 0x007f, 0x1130, 0x9385, + 0x00ff, 0x7002, 0x7007, 0xfffd, 0x0068, 0x68cc, 0xd0ac, 0x1110, + 0xd2bc, 0x0160, 0x9286, 0x0080, 0x1128, 0x9385, 0x00ff, 0x7002, + 0x7007, 0xfffc, 0x686c, 0x700a, 0x6870, 0x700e, 0x9485, 0x0029, + 0x7012, 0x004e, 0x003e, 0x00de, 0x080c, 0x76e4, 0x721a, 0x9f95, + 0x0000, 0x7222, 0x7027, 0xffff, 0x2071, 0x024c, 0x002e, 0x0005, + 0x0026, 0x080c, 0x7e9b, 0x7003, 0x02ff, 0x7007, 0xfffc, 0x00d6, + 0x2069, 0x1100, 0x686c, 0x700a, 0x6870, 0x700e, 0x00de, 0x7013, + 0x2029, 0x0c10, 0x7003, 0x0100, 0x7007, 0x0000, 0x700b, 0xfc02, + 0x700f, 0x0000, 0x0005, 0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, + 0x3300, 0x2021, 0x0800, 0x0040, 0x0026, 0x00d6, 0x0036, 0x0046, + 0x2019, 0x2300, 0x2021, 0x0100, 0x080c, 0x7e9b, 0x7810, 0x2068, + 0x6810, 0x9305, 0x7002, 0x6814, 0x7006, 0x68a0, 0x2069, 0x1100, + 0x6a50, 0x720e, 0x6acc, 0xd2ac, 0x1118, 0x9092, 0x007e, 0x02a0, + 0x7810, 0x00c6, 0x2060, 0x6010, 0x9005, 0x1140, 0x6014, 0x9005, + 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffe, 0x0020, 0x686c, 0x700a, + 0x6870, 0x700e, 0x00ce, 0x0000, 0x9485, 0x0098, 0x7012, 0x004e, + 0x003e, 0x00de, 0x080c, 0x76e4, 0x721a, 0x7a08, 0x7222, 0x2f10, + 0x7226, 0x2071, 0x024c, 0x002e, 0x0005, 0x080c, 0x76e4, 0x721a, + 0x7a08, 0x7222, 0x7814, 0x7026, 0x2071, 0x024c, 0x002e, 0x0005, + 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200, 0x2071, 0x0240, + 0x6004, 0x908a, 0x0085, 0x0a0c, 0x0cf1, 0x908a, 0x0090, 0x1a0c, + 0x0cf1, 0x6110, 0x2178, 0x79a0, 0x2011, 0x1133, 0x2214, 0xd2ac, + 0x1110, 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, 0x7914, 0x918c, + 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0x91f8, 0x26c1, 0x2f0d, + 0x918c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0x9082, 0x0085, + 0x002b, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x72c3, 0x72c9, + 0x72d5, 0x72c1, 0x72c1, 0x72c1, 0x72c3, 0x72c1, 0x72c1, 0x72c1, + 0x72c1, 0x080c, 0x0cf1, 0x00e1, 0x60c3, 0x0000, 0x080c, 0x76f5, + 0x0005, 0x04a9, 0x7808, 0x700a, 0x7814, 0x700e, 0x7017, 0xffff, + 0x60c3, 0x000c, 0x080c, 0x76f5, 0x0005, 0x080c, 0x731f, 0x7003, + 0x0003, 0x7007, 0x0300, 0x60c3, 0x0004, 0x080c, 0x76f5, 0x0005, + 0x0026, 0x080c, 0x7e9b, 0x7810, 0x2068, 0x6810, 0x9085, 0x8100, + 0x7002, 0x6814, 0x7006, 0x68a0, 0x2069, 0x1100, 0x6acc, 0xd2ac, + 0x1118, 0x9092, 0x007e, 0x0240, 0x686c, 0x700a, 0x6870, 0x700e, + 0x7013, 0x0009, 0x0804, 0x7204, 0x6a50, 0x720e, 0x0cc8, 0x0026, + 0x080c, 0x7e9b, 0x7810, 0x2068, 0x6810, 0x9085, 0x8400, 0x7002, + 0x6814, 0x7006, 0x68a0, 0x2069, 0x1100, 0x6acc, 0xd2ac, 0x1118, + 0x9092, 0x007e, 0x0248, 0x686c, 0x700a, 0x6870, 0x700e, 0x2001, + 0x0099, 0x7012, 0x0804, 0x7275, 0x6a50, 0x720e, 0x0cc0, 0x0026, + 0x080c, 0x7e9b, 0x7810, 0x2068, 0x6810, 0x9085, 0x8500, 0x7002, + 0x6814, 0x7006, 0x68a0, 0x2069, 0x1100, 0x6acc, 0xd2ac, 0x1118, + 0x9092, 0x007e, 0x0248, 0x686c, 0x700a, 0x6870, 0x700e, 0x2001, + 0x0099, 0x7012, 0x0804, 0x7275, 0x6a50, 0x720e, 0x0cc0, 0x00c6, + 0x00d6, 0x00e6, 0x00f6, 0x2c78, 0x2069, 0x0200, 0x2071, 0x0240, + 0x7804, 0x908a, 0x0040, 0x0a0c, 0x0cf1, 0x908a, 0x0054, 0x1a0c, + 0x0cf1, 0x7910, 0x2160, 0x61a0, 0x2011, 0x1133, 0x2214, 0xd2ac, + 0x1110, 0xd1bc, 0x0150, 0x6100, 0xd1f4, 0x0120, 0x6114, 0x918c, + 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0x91e0, 0x26c1, 0x2c0d, + 0x918c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x9082, 0x0040, 0x002b, + 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x738a, 0x7448, 0x740f, + 0x7550, 0x7388, 0x7388, 0x7388, 0x7388, 0x7388, 0x7388, 0x7388, + 0x7a1a, 0x7a22, 0x7a2a, 0x7a32, 0x7388, 0x7de2, 0x7388, 0x7a12, + 0x080c, 0x0cf1, 0x780b, 0xffff, 0x080c, 0x73dd, 0x7914, 0x2168, + 0x6978, 0x7956, 0x7132, 0x697c, 0x9184, 0x000f, 0x1118, 0x2001, + 0x0005, 0x0040, 0xd184, 0x0118, 0x2001, 0x0004, 0x0018, 0x9084, + 0x0006, 0x8004, 0x2010, 0x785c, 0x9084, 0x00ff, 0x8007, 0x9205, + 0x7042, 0xd1ac, 0x0128, 0x7047, 0x0002, 0x080c, 0x119d, 0x0050, + 0xd1b4, 0x0118, 0x7047, 0x0001, 0x0028, 0x7047, 0x0000, 0x9016, + 0x2230, 0x0010, 0x6ab0, 0x6eac, 0x726a, 0x766e, 0x20a9, 0x0008, + 0x9d88, 0x0023, 0x20e1, 0x0001, 0x2198, 0x20e9, 0x0000, 0x20a1, + 0x0252, 0x2069, 0x0200, 0x6813, 0x0018, 0x4003, 0x6813, 0x0008, + 0x60c3, 0x0020, 0x6017, 0x0009, 0x2001, 0x12f8, 0x2003, 0x07d0, + 0x2001, 0x12f7, 0x2003, 0x0009, 0x0005, 0x00d6, 0x6813, 0x0008, + 0x7a10, 0x2268, 0x6a8c, 0x8210, 0x9294, 0x00ff, 0x6a8e, 0x8217, + 0x721a, 0x6a10, 0x9295, 0x0600, 0x7202, 0x6a14, 0x7206, 0x68a0, + 0x6900, 0x2069, 0x1100, 0x6bcc, 0xd3ac, 0x1138, 0xd0bc, 0x0188, + 0xd1f4, 0x0118, 0x9294, 0x00ff, 0x629a, 0x6a6c, 0x720a, 0x6a70, + 0x720e, 0x7013, 0x0829, 0x2f10, 0x7222, 0x7027, 0xffff, 0x00de, + 0x0005, 0x9294, 0x00ff, 0x629a, 0x6a50, 0x720e, 0x0c90, 0x00d6, + 0x0081, 0x7814, 0x2068, 0x6890, 0x7002, 0x688c, 0x7006, 0x68b0, + 0x700a, 0x68ac, 0x700e, 0x60c3, 0x000c, 0x00de, 0x080c, 0x76f5, + 0x0005, 0x00d6, 0x6813, 0x0008, 0x7810, 0x2068, 0x6810, 0x9085, + 0x0500, 0x7002, 0x6814, 0x7006, 0x68a0, 0x2069, 0x1100, 0x6acc, + 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x686c, 0x700a, 0x6870, 0x700e, + 0x7013, 0x0889, 0x080c, 0x76e4, 0x721a, 0x7a08, 0x7222, 0x2f10, + 0x7226, 0x2071, 0x024c, 0x00de, 0x0005, 0x6a50, 0x720e, 0x0c80, + 0x00d6, 0x080c, 0x7523, 0x7814, 0x2068, 0x7814, 0x9084, 0xf000, + 0x1130, 0x7814, 0x9084, 0x0700, 0x8007, 0x002b, 0x0010, 0x9006, + 0x0013, 0x00de, 0x0005, 0x7465, 0x74bd, 0x74c6, 0x74de, 0x74eb, + 0x74fd, 0x7505, 0x7463, 0x080c, 0x0cf1, 0x0016, 0x0036, 0x697c, + 0x918c, 0x0003, 0x0118, 0x9186, 0x0003, 0x11a0, 0x6ba8, 0x7824, + 0xd0cc, 0x1170, 0x7316, 0x6898, 0x701a, 0x6894, 0x701e, 0x003e, + 0x001e, 0x2001, 0x12c0, 0x2004, 0x60c2, 0x080c, 0x76f5, 0x0005, + 0xc3e5, 0x0c80, 0x9186, 0x0001, 0x190c, 0x0cf1, 0x6ba8, 0x7824, + 0xd0cc, 0x1588, 0x7316, 0x6898, 0x701a, 0x6894, 0x701e, 0x68a4, + 0x7026, 0x68ac, 0x702e, 0x2009, 0x0018, 0x9384, 0x0300, 0x01e8, + 0xd3c4, 0x0110, 0x68ac, 0x9108, 0xd3cc, 0x0110, 0x68a4, 0x9108, + 0x2011, 0x0258, 0x0156, 0x20a9, 0x000d, 0x9d80, 0x002c, 0x201c, + 0x831f, 0x2312, 0x8000, 0x8210, 0x1f04, 0x74a7, 0x015e, 0x9184, + 0x0003, 0x0118, 0x2019, 0x0245, 0x201a, 0x61c2, 0x003e, 0x001e, + 0x080c, 0x76f5, 0x0005, 0xc3e5, 0x0868, 0x2011, 0x0008, 0x7824, + 0xd0cc, 0x1110, 0x7216, 0x0400, 0x0ce8, 0xc2e5, 0x2011, 0x0302, + 0x7824, 0xd0cc, 0x0108, 0xc2e5, 0x7216, 0x7027, 0x0012, 0x702f, + 0x0008, 0x7043, 0x7000, 0x7047, 0x0500, 0x704f, 0x000a, 0x705b, + 0x2500, 0x60c3, 0x0032, 0x080c, 0x76f5, 0x0005, 0x2011, 0x0028, + 0x7824, 0xd0cc, 0x1130, 0x7216, 0x60c3, 0x0018, 0x080c, 0x76f5, + 0x0005, 0x0cc8, 0xc2e5, 0x2011, 0x0100, 0x7824, 0xd0cc, 0x0108, + 0xc2e5, 0x7216, 0x702f, 0x0008, 0x7858, 0x9084, 0x00ff, 0x7036, + 0x60c3, 0x0020, 0x080c, 0x76f5, 0x0005, 0x2011, 0x0008, 0x7824, + 0xd0cc, 0x0108, 0xc2e5, 0x7216, 0x08f8, 0x0036, 0x7b14, 0x9384, + 0xff00, 0x7816, 0x9384, 0x00ff, 0x8001, 0x1138, 0x7824, 0xd0cc, + 0x0108, 0xc2e5, 0x7216, 0x003e, 0x0878, 0x0046, 0x2021, 0x0800, + 0x0006, 0x7824, 0xd0cc, 0x000e, 0x0108, 0xc4e5, 0x7416, 0x004e, + 0x701e, 0x003e, 0x0808, 0x00d6, 0x6813, 0x0008, 0x7a10, 0x2268, + 0x6810, 0x9085, 0x0700, 0x7002, 0x6814, 0x7006, 0x68a0, 0x2069, + 0x1100, 0x6acc, 0xd2ac, 0x1110, 0xd0bc, 0x01a0, 0x686c, 0x700a, + 0x6870, 0x700e, 0x7824, 0xd0cc, 0x1180, 0x7013, 0x0898, 0x080c, + 0x76e4, 0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226, 0x2071, 0x024c, + 0x00de, 0x0005, 0x6a50, 0x720e, 0x0c68, 0x7013, 0x0889, 0x0c78, + 0x0016, 0x7814, 0x9084, 0x0700, 0x8007, 0x0013, 0x001e, 0x0005, + 0x7560, 0x7560, 0x7562, 0x7560, 0x7560, 0x7560, 0x757f, 0x7560, + 0x080c, 0x0cf1, 0x7914, 0x918c, 0xf8ff, 0x918d, 0x0600, 0x7916, + 0x2009, 0x0003, 0x00d1, 0x00d6, 0x2069, 0x1152, 0x6804, 0xd0bc, + 0x0130, 0x682c, 0x9084, 0x00ff, 0x8007, 0x7032, 0x0010, 0x7033, + 0x3f00, 0x00de, 0x60c3, 0x0001, 0x080c, 0x76f5, 0x0005, 0x2009, + 0x0003, 0x0019, 0x7033, 0x7f00, 0x0ca8, 0x00d6, 0x0016, 0x080c, + 0x7e9b, 0x001e, 0x7810, 0x2068, 0x6810, 0x9085, 0x0100, 0x7002, + 0x6814, 0x7006, 0x68a0, 0x2069, 0x1100, 0x6acc, 0xd2ac, 0x1110, + 0xd0bc, 0x01a0, 0x6a6c, 0x720a, 0x6a70, 0x720e, 0x7013, 0x0888, + 0x918d, 0x0008, 0x7116, 0x080c, 0x76e4, 0x721a, 0x7a08, 0x7222, + 0x2f10, 0x7226, 0x2071, 0x024c, 0x00de, 0x0005, 0x6a50, 0x720e, + 0x0c68, 0x00e6, 0x00d6, 0x00c6, 0x0056, 0x0046, 0x0036, 0x2061, + 0x0100, 0x2071, 0x1100, 0x7150, 0x7810, 0x2068, 0x68a0, 0x2028, + 0x6910, 0x6a14, 0x76cc, 0xd6ac, 0x1130, 0xd0bc, 0x1120, 0x2019, + 0x0000, 0x7450, 0x0010, 0x736c, 0x7470, 0x7820, 0x90be, 0x0006, + 0x0904, 0x765a, 0x90be, 0x000a, 0x15e8, 0x9185, 0x0200, 0x6062, + 0x6266, 0x636a, 0x646e, 0x6073, 0x2029, 0x6077, 0x0000, 0x688c, + 0x8000, 0x9084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, + 0x2f00, 0x6082, 0x7808, 0x6086, 0x7814, 0x2070, 0x7038, 0x608a, + 0x7034, 0x608e, 0x7048, 0x60c6, 0x7044, 0x60ca, 0x686c, 0x60ce, + 0x60af, 0x95d5, 0x60d7, 0x0000, 0x609f, 0x0000, 0x080c, 0x7e80, + 0x2009, 0x07d0, 0x60c4, 0x9084, 0xfff0, 0x9005, 0x0110, 0x2009, + 0x1b58, 0x080c, 0x65d4, 0x003e, 0x004e, 0x005e, 0x00ce, 0x00de, + 0x00ee, 0x0005, 0x9185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, + 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0x9084, 0x00ff, + 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, + 0x6086, 0x7814, 0x2070, 0x7038, 0x608a, 0x7034, 0x608e, 0x7048, + 0x60c6, 0x7044, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, + 0x0000, 0x9582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, + 0x9294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, 0x7e80, + 0x2009, 0x07d0, 0x60c4, 0x9084, 0xfff0, 0x9005, 0x0110, 0x2009, + 0x1b58, 0x080c, 0x65d4, 0x003e, 0x004e, 0x005e, 0x00ce, 0x00de, + 0x00ee, 0x0005, 0x7814, 0x2070, 0x707c, 0x9084, 0x0003, 0x9086, + 0x0002, 0x05f0, 0x9185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, + 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0x9084, 0x00ff, + 0x688e, 0x8007, 0x607a, 0x7838, 0x607e, 0x2f00, 0x6086, 0x7808, + 0x6082, 0x7090, 0x608a, 0x708c, 0x608e, 0x70b0, 0x60c6, 0x70ac, + 0x60ca, 0x70ac, 0x7930, 0x9108, 0x7932, 0x70b0, 0x792c, 0x9109, + 0x792e, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0x9582, + 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0x9294, 0x00ff, + 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, 0x7e5b, 0x0804, 0x7648, + 0x9185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x7824, 0xd0cc, + 0x7826, 0x0118, 0x6073, 0x0889, 0x0010, 0x6073, 0x0898, 0x6077, + 0x0000, 0x688c, 0x8000, 0x9084, 0x00ff, 0x688e, 0x8007, 0x607a, + 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0x7038, 0x608a, + 0x7034, 0x608e, 0x7048, 0x60c6, 0x7044, 0x60ca, 0x686c, 0x60ce, + 0x60af, 0x95d5, 0x60d7, 0x0000, 0x9582, 0x0080, 0x0248, 0x6a00, + 0xd2f4, 0x0120, 0x6a14, 0x9294, 0x00ff, 0x0010, 0x2011, 0x0000, + 0x629e, 0x7824, 0xd0cc, 0x0120, 0x080c, 0x7e80, 0x0804, 0x7648, + 0x080c, 0x7e5b, 0x0804, 0x7648, 0x7a10, 0x9280, 0x0023, 0x2014, + 0x8210, 0x9294, 0x00ff, 0x2202, 0x8217, 0x0005, 0x00d6, 0x2069, + 0x12dc, 0x6843, 0x0001, 0x00de, 0x0005, 0x60a3, 0x0056, 0x60a7, + 0x9575, 0x00f1, 0x080c, 0x65c6, 0x0005, 0x0016, 0x2001, 0x110c, + 0x200c, 0x9184, 0x0600, 0x9086, 0x0600, 0x0128, 0x0089, 0x080c, + 0x65c6, 0x001e, 0x0005, 0xc1e5, 0x2001, 0x110c, 0x2102, 0x2001, + 0x12dd, 0x2003, 0x0000, 0x2001, 0x12e5, 0x2003, 0x0000, 0x0c88, + 0x0006, 0x6014, 0x9084, 0x1804, 0x9085, 0x0009, 0x6016, 0x000e, + 0x0005, 0x0006, 0x00c6, 0x2061, 0x0100, 0x6014, 0x9084, 0x1804, + 0x9085, 0x0008, 0x6016, 0x00ce, 0x000e, 0x0005, 0x00c6, 0x00d6, + 0x0016, 0x0026, 0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x5745, + 0x1198, 0x2001, 0x12f8, 0x2004, 0x9005, 0x15b8, 0x0066, 0x2031, + 0x0001, 0x080c, 0x57d6, 0x006e, 0x1118, 0x080c, 0x65c6, 0x0468, + 0x00c6, 0x2061, 0x12dc, 0x00d8, 0x6904, 0x9194, 0x4000, 0x0550, + 0x0881, 0x6803, 0x1000, 0x6803, 0x0000, 0x00c6, 0x2061, 0x12dc, + 0x6128, 0x9192, 0x00c8, 0x1258, 0x8108, 0x612a, 0x6124, 0x00ce, + 0x81ff, 0x0198, 0x080c, 0x65c6, 0x080c, 0x7718, 0x0070, 0x6124, + 0x91e5, 0x0000, 0x0140, 0x080c, 0xae07, 0x2009, 0x0014, 0x080c, + 0x7f4e, 0x080c, 0x65cf, 0x00ce, 0x0000, 0x002e, 0x001e, 0x00de, + 0x00ce, 0x0005, 0x2001, 0x12f8, 0x2004, 0x9005, 0x1db0, 0x00c6, + 0x2061, 0x12dc, 0x6128, 0x9192, 0x0003, 0x1e08, 0x8108, 0x612a, + 0x00ce, 0x080c, 0x65c6, 0x080c, 0x45d6, 0x0c38, 0x00c6, 0x00d6, + 0x00e6, 0x0016, 0x0026, 0x080c, 0x65dc, 0x2071, 0x12dc, 0x713c, + 0x81ff, 0x0590, 0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x5745, + 0x11a8, 0x0036, 0x2019, 0x0002, 0x080c, 0x7936, 0x003e, 0x713c, + 0x2160, 0x080c, 0xae07, 0x2009, 0x004a, 0x080c, 0x7f4e, 0x0066, + 0x2031, 0x0001, 0x080c, 0x57d6, 0x006e, 0x00b0, 0x6904, 0x9194, + 0x4000, 0x01c0, 0x6803, 0x1000, 0x6803, 0x0000, 0x0036, 0x2019, + 0x0001, 0x080c, 0x7936, 0x003e, 0x713c, 0x2160, 0x080c, 0xae07, + 0x2009, 0x004a, 0x080c, 0x7f4e, 0x002e, 0x001e, 0x00ee, 0x00de, + 0x00ce, 0x0005, 0x0c58, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056, + 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, 0x6010, 0x2068, 0x6ca0, + 0x2071, 0x12dc, 0x7018, 0x2068, 0x8dff, 0x0198, 0x68a0, 0x9406, + 0x0118, 0x6854, 0x2068, 0x0cc0, 0x6014, 0x2060, 0x646c, 0x6570, + 0x6678, 0x2d60, 0x080c, 0x4c75, 0x0120, 0x080c, 0x7a3e, 0x9085, + 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, 0x006e, 0x00ce, 0x00de, + 0x00ee, 0x0005, 0x080c, 0x71be, 0x7003, 0x1200, 0x7820, 0x9086, + 0x0004, 0x1110, 0x6098, 0x0018, 0x2001, 0x1114, 0x2004, 0x700e, + 0x7838, 0x7012, 0x783c, 0x7016, 0x60c3, 0x002c, 0x080c, 0x76f5, + 0x0005, 0x080c, 0x71be, 0x7003, 0x0f00, 0x7808, 0x700e, 0x60c3, + 0x0008, 0x080c, 0x76f5, 0x0005, 0x0156, 0x080c, 0x7234, 0x7003, + 0x0200, 0x2011, 0x1148, 0x63f0, 0x2312, 0x20a9, 0x0006, 0x2011, + 0x1140, 0x2019, 0x1141, 0x9ef0, 0x0002, 0x2376, 0x8e70, 0x2276, + 0x8e70, 0x9398, 0x0002, 0x9290, 0x0002, 0x1f04, 0x7835, 0x60c3, + 0x001c, 0x080c, 0x76f5, 0x015e, 0x0005, 0x0016, 0x0026, 0x080c, + 0x7210, 0x080c, 0x7222, 0x9e80, 0x0004, 0x20e9, 0x0000, 0x20a0, + 0x7814, 0x9080, 0x0000, 0x2004, 0x9080, 0x0021, 0x20e1, 0x0001, + 0x2098, 0x7808, 0x9088, 0x0002, 0x21a8, 0x4003, 0x9080, 0x0004, + 0x8003, 0x60c2, 0x080c, 0x76f5, 0x002e, 0x001e, 0x0005, 0x080c, + 0x71be, 0x7003, 0x6200, 0x7808, 0x700e, 0x60c3, 0x0008, 0x080c, + 0x76f5, 0x0005, 0x0016, 0x0026, 0x080c, 0x71be, 0x20e9, 0x0000, + 0x20a1, 0x024c, 0x7814, 0x9080, 0x0000, 0x2004, 0x9080, 0x0023, + 0x20e1, 0x0001, 0x2098, 0x7808, 0x9088, 0x0002, 0x21a8, 0x4003, + 0x8003, 0x60c2, 0x080c, 0x76f5, 0x002e, 0x001e, 0x0005, 0x00e6, + 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x12dc, 0x700c, + 0x2060, 0x8cff, 0x0178, 0x080c, 0x97cd, 0x1110, 0x080c, 0x8576, + 0x600c, 0x0006, 0x080c, 0x99c4, 0x080c, 0x7f1e, 0x080c, 0x7a3e, + 0x00ce, 0x0c78, 0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x000e, + 0x00ce, 0x00ee, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, + 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, + 0x2079, 0x0140, 0x2071, 0x12dc, 0x7024, 0x2060, 0x8cff, 0x05a0, + 0x080c, 0x7721, 0x68c3, 0x0000, 0x080c, 0x65cf, 0x2009, 0x0013, + 0x080c, 0x7f4e, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, + 0x0004, 0x7804, 0x9084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, + 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, + 0x78d4, 0x7804, 0x9084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, + 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x015e, 0x012e, 0x0005, 0x2001, 0x1100, 0x2004, 0x9096, + 0x0001, 0x0550, 0x9096, 0x0004, 0x0538, 0x6817, 0x0008, 0x68c3, + 0x0000, 0x2011, 0x4586, 0x080c, 0x655b, 0x20a9, 0x01f4, 0x6824, + 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, 0x9084, 0x4000, 0x01a0, + 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, + 0x0001, 0x0010, 0x1f04, 0x790f, 0x7804, 0x9084, 0x1000, 0x0120, + 0x7803, 0x0100, 0x7803, 0x0000, 0x000e, 0x001e, 0x002e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x0126, 0x0156, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, + 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x12dc, 0x703c, + 0x2060, 0x8cff, 0x0904, 0x79b8, 0x6814, 0x9084, 0x0002, 0x0904, + 0x79b8, 0x68af, 0x95f5, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, + 0x1df0, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x080c, 0x65dc, 0x080c, + 0x1605, 0x0046, 0x2009, 0x017f, 0x200b, 0x00a5, 0x2021, 0x0169, + 0x2404, 0x9084, 0x000f, 0x9086, 0x0004, 0x1500, 0x68af, 0x95f5, + 0x68c7, 0x0000, 0x68cb, 0x0008, 0x00e6, 0x00f6, 0x2079, 0x0090, + 0x2071, 0x131f, 0x6814, 0x9084, 0x1984, 0x9085, 0x0012, 0x6816, + 0x782b, 0x0008, 0x7003, 0x0000, 0x00fe, 0x00ee, 0x9386, 0x0002, + 0x1128, 0x7884, 0x9005, 0x1110, 0x7887, 0x0001, 0x200b, 0x0000, + 0x004e, 0x939d, 0x0000, 0x1120, 0x2009, 0x0049, 0x080c, 0x7f4e, + 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, + 0x9084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, + 0xd08c, 0x0118, 0x6827, 0x0002, 0x0010, 0x1f04, 0x799a, 0x7804, + 0x9084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, + 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, + 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0x12dc, + 0x6a06, 0x012e, 0x00de, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x2069, 0x12dc, 0x6a32, 0x012e, 0x00de, 0x0005, 0x00f6, 0x00e6, + 0x00c6, 0x0066, 0x0006, 0x0126, 0x2071, 0x12dc, 0x7614, 0x2660, + 0x2678, 0x2091, 0x8000, 0x8cff, 0x0530, 0x6020, 0x9206, 0x11f8, + 0x7014, 0x9c36, 0x1110, 0x660c, 0x7616, 0x7010, 0x9c36, 0x1140, + 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, + 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, + 0x600f, 0x0000, 0x080c, 0x97a3, 0x04c9, 0x00ce, 0x08e0, 0x2c78, + 0x600c, 0x2060, 0x08c0, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00ee, + 0x00fe, 0x0005, 0x080c, 0x73dd, 0x7814, 0x7032, 0x7042, 0x7047, + 0x1000, 0x00f8, 0x080c, 0x73dd, 0x7814, 0x7032, 0x7042, 0x7047, + 0x4000, 0x00b8, 0x080c, 0x73dd, 0x7814, 0x7032, 0x7042, 0x7047, + 0x2000, 0x0078, 0x080c, 0x73dd, 0x7814, 0x7032, 0x7042, 0x7047, + 0x0400, 0x0038, 0x080c, 0x73dd, 0x7814, 0x7032, 0x7042, 0x7047, + 0x0200, 0x60c3, 0x0020, 0x080c, 0x76f5, 0x0005, 0x00e6, 0x2071, + 0x12dc, 0x7020, 0x9005, 0x0110, 0x8001, 0x7022, 0x00ee, 0x0005, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2071, 0x12dc, 0x7614, 0x2660, 0x2678, 0x2039, + 0x0001, 0x87ff, 0x0904, 0x7ad2, 0x8cff, 0x0904, 0x7ad2, 0x6020, + 0x9086, 0x0006, 0x1904, 0x7acd, 0x88ff, 0x0138, 0x2800, 0x9c06, + 0x1904, 0x7acd, 0x2039, 0x0000, 0x0050, 0x6010, 0x9206, 0x1904, + 0x7acd, 0x85ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x7acd, 0x7024, + 0x9c06, 0x1538, 0x2069, 0x0100, 0x68c0, 0x9005, 0x01f0, 0x080c, + 0x65cf, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, 0x7b56, 0x7027, + 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0120, + 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, + 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, + 0x0460, 0x7014, 0x9c36, 0x1110, 0x660c, 0x7616, 0x7010, 0x9c36, + 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, + 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x89ff, 0x1158, 0x600f, 0x0000, 0x6014, 0x2068, 0x080c, + 0x95d2, 0x0110, 0x080c, 0xaa84, 0x080c, 0x97a3, 0x080c, 0x7a3e, + 0x88ff, 0x1190, 0x00ce, 0x0804, 0x7a59, 0x2c78, 0x600c, 0x2060, + 0x0804, 0x7a59, 0x9006, 0x012e, 0x000e, 0x006e, 0x007e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601b, 0x0000, 0x00ce, 0x98c5, + 0x0001, 0x0c88, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, + 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x12dc, 0x7638, 0x2660, + 0x2678, 0x8cff, 0x0904, 0x7b46, 0x6020, 0x9086, 0x0006, 0x1904, + 0x7b41, 0x87ff, 0x0128, 0x2700, 0x9c06, 0x1904, 0x7b41, 0x0040, + 0x6010, 0x9206, 0x15f0, 0x85ff, 0x0118, 0x6054, 0x9106, 0x15c8, + 0x703c, 0x9c06, 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7936, + 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, + 0x003e, 0x7038, 0x9c36, 0x1110, 0x660c, 0x763a, 0x7034, 0x9c36, + 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, + 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0x6014, 0x2068, 0x080c, 0x95d2, 0x0110, + 0x080c, 0xaa84, 0x080c, 0x97a3, 0x87ff, 0x1190, 0x00ce, 0x0804, + 0x7af1, 0x2c78, 0x600c, 0x2060, 0x0804, 0x7af1, 0x9006, 0x012e, + 0x000e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, + 0x601b, 0x0000, 0x00ce, 0x97bd, 0x0001, 0x0c88, 0x00e6, 0x2071, + 0x12dc, 0x2001, 0x1100, 0x2004, 0x9086, 0x0002, 0x1118, 0x7007, + 0x0005, 0x0010, 0x7007, 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, + 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, + 0x12dc, 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0518, 0x2200, + 0x9c06, 0x11e0, 0x7038, 0x9c36, 0x1110, 0x660c, 0x763a, 0x7034, + 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010, + 0x7037, 0x0000, 0x660c, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0x9085, 0x0001, 0x0020, 0x2c78, 0x600c, + 0x2060, 0x08d8, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00ee, + 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0006, + 0x0126, 0x2091, 0x8000, 0x2071, 0x12dc, 0x760c, 0x2660, 0x2678, + 0x8cff, 0x0904, 0x7c2c, 0x6010, 0x9080, 0x0028, 0x2004, 0x9206, + 0x1904, 0x7c27, 0x7024, 0x9c06, 0x1508, 0x2069, 0x0100, 0x68c0, + 0x9005, 0x0904, 0x7c03, 0x080c, 0x7721, 0x68c3, 0x0000, 0x080c, + 0x7b56, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, + 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c, 0x9c36, + 0x1110, 0x660c, 0x760e, 0x7008, 0x9c36, 0x1140, 0x2c00, 0x9f36, + 0x0118, 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c, 0x0066, + 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, + 0x080c, 0x97bc, 0x1158, 0x080c, 0x25d1, 0x080c, 0x97cd, 0x11f0, + 0x080c, 0x8576, 0x00d8, 0x080c, 0x7b56, 0x08c0, 0x080c, 0x97cd, + 0x1118, 0x080c, 0x8576, 0x0090, 0x6014, 0x2068, 0x080c, 0x95d2, + 0x0168, 0x6020, 0x9086, 0x0003, 0x11f8, 0x6867, 0x0103, 0x6b7a, + 0x6877, 0x0000, 0x080c, 0x50a5, 0x080c, 0x9797, 0x080c, 0x99c4, + 0x080c, 0x97a3, 0x080c, 0x7a3e, 0x00ce, 0x0804, 0x7bb0, 0x2c78, + 0x600c, 0x2060, 0x0804, 0x7bb0, 0x012e, 0x000e, 0x006e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, 0x1d30, + 0x080c, 0xaa84, 0x0c18, 0x00d6, 0x080c, 0x7234, 0x7003, 0x0200, + 0x7007, 0x0014, 0x60c3, 0x0014, 0x20e1, 0x0001, 0x2099, 0x12a9, + 0x20e9, 0x0000, 0x20a1, 0x0250, 0x20a9, 0x0004, 0x4003, 0x7023, + 0x0004, 0x7027, 0x7878, 0x080c, 0x76f5, 0x00de, 0x0005, 0x080c, + 0x7234, 0x7003, 0x0214, 0x7007, 0x0018, 0x700b, 0x0800, 0x7814, + 0x9084, 0xff00, 0x700e, 0x7814, 0x9084, 0x00ff, 0x7022, 0x782c, + 0x7026, 0x60c3, 0x0018, 0x080c, 0x76f5, 0x0005, 0x00d6, 0x0016, + 0x00d6, 0x2f68, 0x2009, 0x0035, 0x080c, 0x9ac5, 0x00de, 0x1904, + 0x7cd4, 0x080c, 0x71be, 0x7003, 0x1300, 0x782c, 0x2068, 0x6820, + 0x9086, 0x0003, 0x0570, 0x7810, 0x9080, 0x0028, 0x2014, 0x2001, + 0x1133, 0x2004, 0xd0ac, 0x11d0, 0x9286, 0x007e, 0x1128, 0x700b, + 0x00ff, 0x700f, 0xfffe, 0x04a8, 0x9286, 0x007f, 0x1128, 0x700b, + 0x00ff, 0x700f, 0xfffd, 0x0468, 0xd2bc, 0x0180, 0x9286, 0x0080, + 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffc, 0x0418, 0x92e8, 0x1000, + 0x2d6c, 0x6810, 0x700a, 0x6814, 0x700e, 0x00d8, 0x6098, 0x700e, + 0x00c0, 0x2001, 0x1133, 0x2004, 0xd0ac, 0x1138, 0x7810, 0x9080, + 0x0028, 0x2004, 0x9082, 0x007e, 0x0250, 0x00d6, 0x2069, 0x111b, + 0x2d04, 0x700a, 0x8d68, 0x2d04, 0x700e, 0x00de, 0x0010, 0x6034, + 0x700e, 0x7838, 0x7012, 0x783c, 0x7016, 0x60c3, 0x000c, 0x001e, + 0x00de, 0x080c, 0x76f5, 0x0005, 0x781b, 0x0001, 0x7803, 0x0006, + 0x001e, 0x00de, 0x0005, 0x792c, 0x9180, 0x0008, 0x200c, 0x9186, + 0x0006, 0x01b0, 0x9186, 0x0003, 0x0904, 0x7d4b, 0x9186, 0x0005, + 0x0904, 0x7d34, 0x9186, 0x0004, 0x05c8, 0x9186, 0x0008, 0x0904, + 0x7d3c, 0x7807, 0x0037, 0x7817, 0x1700, 0x080c, 0x7db2, 0x0005, + 0x080c, 0x7d71, 0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, + 0x6800, 0x0002, 0x7d15, 0x7d20, 0x7d17, 0x7d20, 0x7d1c, 0x7d15, + 0x7d15, 0x7d20, 0x7d20, 0x7d20, 0x7d20, 0x7d15, 0x7d15, 0x7d15, + 0x7d15, 0x7d15, 0x7d20, 0x7d15, 0x7d20, 0x080c, 0x0cf1, 0x6824, + 0xd0e4, 0x0110, 0xd0cc, 0x0110, 0x900e, 0x0010, 0x2009, 0x2000, + 0x682c, 0x7022, 0x6830, 0x7026, 0x0804, 0x7d69, 0x080c, 0x7d71, + 0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x6a00, 0x9286, + 0x0002, 0x1108, 0x900e, 0x04a8, 0x04e1, 0x00d6, 0x0026, 0x792c, + 0x2168, 0x2009, 0x4000, 0x0468, 0x04a1, 0x00d6, 0x0026, 0x792c, + 0x2168, 0x2009, 0x4000, 0x9286, 0x0005, 0x0118, 0x9286, 0x0002, + 0x1108, 0x900e, 0x00f0, 0x0429, 0x00d6, 0x0026, 0x792c, 0x2168, + 0x6814, 0x2068, 0x69ac, 0x6834, 0x9112, 0x69b0, 0x6838, 0x9103, + 0x7022, 0x7226, 0x792c, 0x9180, 0x0000, 0x2004, 0x908e, 0x0002, + 0x0130, 0x908e, 0x0004, 0x0118, 0x2009, 0x4000, 0x0010, 0x2009, + 0x0000, 0x712a, 0x60c3, 0x0018, 0x002e, 0x00de, 0x080c, 0x76f5, + 0x0005, 0x0036, 0x0046, 0x0056, 0x0066, 0x080c, 0x7234, 0x9006, + 0x7003, 0x0200, 0x7938, 0x710a, 0x793c, 0x710e, 0x7810, 0x9080, + 0x0028, 0x2004, 0x2011, 0x1133, 0x2214, 0xd2ac, 0x1118, 0x9092, + 0x007e, 0x0268, 0x00d6, 0x2069, 0x111b, 0x2d2c, 0x8d68, 0x2d34, + 0x90e8, 0x1000, 0x2d6c, 0x6b10, 0x6c14, 0x00de, 0x0030, 0x2019, + 0x0000, 0x6498, 0x2029, 0x0000, 0x6634, 0x782c, 0x9080, 0x0008, + 0x2004, 0x9086, 0x0003, 0x1128, 0x7512, 0x7616, 0x731a, 0x741e, + 0x0020, 0x7312, 0x7416, 0x751a, 0x761e, 0x006e, 0x005e, 0x004e, + 0x003e, 0x0005, 0x080c, 0x7234, 0x7003, 0x0100, 0x700b, 0x0009, + 0x7814, 0x700e, 0x60c3, 0x0008, 0x080c, 0x76f5, 0x0005, 0x080c, + 0x71b5, 0x7003, 0x1400, 0x7838, 0x700a, 0x783c, 0x700e, 0x782c, + 0x7012, 0x7830, 0x7016, 0x7834, 0x9084, 0x00ff, 0x8007, 0x701a, + 0x60c3, 0x0010, 0x080c, 0x76f5, 0x0005, 0x080c, 0x722b, 0x7003, + 0x0100, 0x782c, 0x700a, 0x7814, 0x700e, 0x60c3, 0x0008, 0x080c, + 0x76f5, 0x0005, 0x0029, 0x60c3, 0x0000, 0x080c, 0x76f5, 0x0005, + 0x00d6, 0x080c, 0x7e9b, 0x7810, 0x2068, 0x6810, 0x9085, 0x0300, + 0x7002, 0x6814, 0x7006, 0x68a0, 0x2069, 0x1100, 0x6acc, 0xd2ac, + 0x1110, 0xd0bc, 0x0188, 0x686c, 0x700a, 0x6870, 0x700e, 0x7013, + 0x0819, 0x080c, 0x76e4, 0x721a, 0x2f10, 0x7222, 0x7a08, 0x7226, + 0x2071, 0x024c, 0x00de, 0x0005, 0x6234, 0x720e, 0x0c80, 0x0059, + 0x7914, 0x712a, 0x60c3, 0x0000, 0x60a7, 0x9575, 0x080c, 0x7718, + 0x080c, 0x65c6, 0x0005, 0x0036, 0x00d6, 0x00e6, 0x7858, 0x2068, + 0x9df0, 0x001b, 0x7210, 0x9296, 0x00c0, 0x9294, 0xfffd, 0x7212, + 0x7214, 0x9294, 0x0300, 0x7216, 0x7100, 0x9194, 0x00ff, 0x7308, + 0x9384, 0x00ff, 0x908d, 0xc200, 0x7102, 0x9384, 0xff00, 0x9215, + 0x720a, 0x7004, 0x720c, 0x700e, 0x7206, 0x00d6, 0x2069, 0x0200, + 0x080c, 0x7e9b, 0x00de, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, + 0x000a, 0x20e1, 0x0001, 0x2e98, 0x4003, 0x60a3, 0x0035, 0x6a68, + 0x9294, 0x7000, 0x9286, 0x3000, 0x0110, 0x60a3, 0x0037, 0x00ee, + 0x00de, 0x003e, 0x0005, 0x900e, 0x7814, 0x9080, 0x001f, 0x2004, + 0xd0fc, 0x01d8, 0x9084, 0x0003, 0x11c0, 0x2001, 0x110c, 0x2004, + 0xd0bc, 0x0198, 0x7824, 0xd0cc, 0x1180, 0xd0c4, 0x1170, 0x7814, + 0x9080, 0x002a, 0x2004, 0x9005, 0x1140, 0x2001, 0x110c, 0x200c, + 0xc1d5, 0x2102, 0x2009, 0x12c1, 0x210c, 0x918d, 0x0092, 0x0010, + 0x2009, 0x0096, 0x60ab, 0x0036, 0x6116, 0x0005, 0x2009, 0x0009, + 0x00a0, 0x2009, 0x000a, 0x0088, 0x2009, 0x000b, 0x0070, 0x2009, + 0x000c, 0x0058, 0x2009, 0x000d, 0x0040, 0x2009, 0x000e, 0x0028, + 0x2009, 0x000f, 0x0010, 0x2009, 0x0008, 0x6912, 0x0005, 0x00d6, + 0x9290, 0x0018, 0x8214, 0x20e9, 0x0000, 0x2069, 0x0200, 0x6813, + 0x0000, 0x22a8, 0x9284, 0x00e0, 0x0128, 0x20a9, 0x0020, 0x9292, + 0x0020, 0x0008, 0x9016, 0x20a1, 0x0240, 0x9006, 0x4004, 0x82ff, + 0x0120, 0x6810, 0x8000, 0x6812, 0x0c60, 0x00de, 0x0005, 0x2061, + 0x15c0, 0x2071, 0x1100, 0x7064, 0x7046, 0x704b, 0x15c0, 0x0005, + 0x00e6, 0x0126, 0x2071, 0x1100, 0x2091, 0x8000, 0x7544, 0x9582, + 0x0010, 0x0608, 0x7048, 0x2060, 0x6000, 0x9086, 0x0000, 0x0148, + 0x9ce0, 0x0018, 0x7058, 0x9c02, 0x1208, 0x0cb0, 0x2061, 0x15c0, + 0x0c98, 0x6003, 0x0008, 0x8529, 0x7546, 0x9ca8, 0x0018, 0x7058, + 0x9502, 0x1230, 0x754a, 0x9085, 0x0001, 0x012e, 0x00ee, 0x0005, + 0x704b, 0x15c0, 0x0cc0, 0x9006, 0x0cc0, 0x00e6, 0x2071, 0x1100, + 0x7544, 0x9582, 0x0010, 0x0600, 0x7048, 0x2060, 0x6000, 0x9086, + 0x0000, 0x0148, 0x9ce0, 0x0018, 0x7058, 0x9c02, 0x1208, 0x0cb0, + 0x2061, 0x15c0, 0x0c98, 0x6003, 0x0008, 0x8529, 0x7546, 0x9ca8, + 0x0018, 0x7058, 0x9502, 0x1228, 0x754a, 0x9085, 0x0001, 0x00ee, + 0x0005, 0x704b, 0x15c0, 0x0cc8, 0x9006, 0x0cc8, 0x9c82, 0x15c0, + 0x0a0c, 0x0cf1, 0x2001, 0x1116, 0x2004, 0x9c02, 0x1a0c, 0x0cf1, + 0x9006, 0x6006, 0x600a, 0x600e, 0x6016, 0x601a, 0x6012, 0x6023, + 0x0000, 0x6003, 0x0000, 0x601e, 0x6056, 0x605a, 0x6026, 0x602a, + 0x602e, 0x6032, 0x6036, 0x603a, 0x603e, 0x6042, 0x2061, 0x1100, + 0x6044, 0x8000, 0x6046, 0x9086, 0x0001, 0x0108, 0x0005, 0x0126, + 0x2091, 0x8000, 0x080c, 0x6d42, 0x012e, 0x0cc0, 0x6020, 0x9084, + 0x000f, 0x0002, 0x7f60, 0x7f70, 0x7f8b, 0x7fa6, 0x9af2, 0x9b0d, + 0x9b28, 0x7f60, 0x7f70, 0x7f60, 0x7fc2, 0x7f60, 0x7f60, 0x7f60, + 0x9186, 0x0013, 0x1128, 0x080c, 0x6c56, 0x080c, 0x6d42, 0x0005, + 0x9186, 0x0047, 0x1120, 0x9016, 0x080c, 0x119a, 0x0000, 0x0005, + 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0cf1, 0x0013, 0x006e, + 0x0005, 0x7f89, 0x8406, 0x85b0, 0x7f89, 0x862d, 0x8072, 0x7f89, + 0x7f89, 0x8392, 0x8a82, 0x7f89, 0x7f89, 0x7f89, 0x7f89, 0x7f89, + 0x7f89, 0x080c, 0x0cf1, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, + 0x0cf1, 0x0013, 0x006e, 0x0005, 0x7fa4, 0x9085, 0x7fa4, 0x7fa4, + 0x7fa4, 0x7fa4, 0x7fa4, 0x7fa4, 0x902d, 0x91f5, 0x7fa4, 0x90b6, + 0x9131, 0x90b6, 0x9131, 0x7fa4, 0x080c, 0x0cf1, 0x6000, 0x9082, + 0x0016, 0x1a0c, 0x0cf1, 0x6000, 0x0002, 0x7fc0, 0x8ac3, 0x8b8c, + 0x8caa, 0x8e09, 0x7fc0, 0x7fc0, 0x7fc0, 0x8a9d, 0x8fdd, 0x8fe0, + 0x7fc0, 0x7fc0, 0x7fc0, 0x7fc0, 0x900a, 0x7fc0, 0x7fc0, 0x7fc0, + 0x080c, 0x0cf1, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0cf1, + 0x0013, 0x006e, 0x0005, 0x7fdb, 0x7fdb, 0x7fdb, 0x7ffe, 0x8051, + 0x7fdb, 0x7fdb, 0x7fdb, 0x7fdd, 0x7fdb, 0x7fdb, 0x7fdb, 0x7fdb, + 0x7fdb, 0x7fdb, 0x7fdb, 0x080c, 0x0cf1, 0x9186, 0x0003, 0x190c, + 0x0cf1, 0x00d6, 0x6003, 0x0003, 0x6106, 0x6014, 0x2068, 0x687f, + 0x0040, 0x68ac, 0x6846, 0x68b0, 0x684a, 0x6837, 0x0000, 0x683b, + 0x0000, 0x00de, 0x2c10, 0x080c, 0x13a9, 0x080c, 0x68eb, 0x0126, + 0x2091, 0x8000, 0x080c, 0x6e10, 0x012e, 0x0005, 0x9182, 0x0047, + 0x0002, 0x800a, 0x800a, 0x800c, 0x802b, 0x800a, 0x800a, 0x800a, + 0x800a, 0x803d, 0x080c, 0x0cf1, 0x00d6, 0x0016, 0x080c, 0x6cf2, + 0x080c, 0x6e10, 0x6003, 0x0004, 0x6114, 0x2168, 0x6884, 0x8003, + 0x800b, 0x810b, 0x9108, 0x611a, 0x687f, 0x0020, 0x688c, 0x688a, + 0x68a4, 0x68ae, 0x68a8, 0x68b2, 0x68c7, 0x0000, 0x68cb, 0x0000, + 0x001e, 0x00de, 0x0005, 0x080c, 0x6cf2, 0x00d6, 0x6114, 0x2168, + 0x080c, 0x95d2, 0x0120, 0x687b, 0x0006, 0x080c, 0x50a5, 0x00de, + 0x080c, 0x7f1e, 0x080c, 0x6e10, 0x0005, 0x080c, 0x6cf2, 0x080c, + 0x25ad, 0x00d6, 0x6114, 0x2168, 0x080c, 0x95d2, 0x0120, 0x687b, + 0x0029, 0x080c, 0x50a5, 0x00de, 0x080c, 0x7f1e, 0x080c, 0x6e10, + 0x0005, 0x9182, 0x0047, 0x0002, 0x8061, 0x8063, 0x8061, 0x8061, + 0x8061, 0x8061, 0x8061, 0x8061, 0x8061, 0x8061, 0x8061, 0x8061, + 0x8063, 0x080c, 0x0cf1, 0x00d6, 0x080c, 0x1132, 0x6114, 0x2168, + 0x687b, 0x0000, 0x6883, 0x0000, 0x080c, 0x50a5, 0x00de, 0x080c, + 0x7f1e, 0x0005, 0x91b6, 0x0015, 0x1118, 0x080c, 0x7f1e, 0x0030, + 0x91b6, 0x0016, 0x190c, 0x0cf1, 0x080c, 0x7f1e, 0x0005, 0x20a9, + 0x000e, 0x20e1, 0x0000, 0x2e98, 0x6014, 0x20e9, 0x0001, 0x20a0, + 0x4003, 0x9080, 0x001b, 0x20a0, 0x20a9, 0x0006, 0x3310, 0x3420, + 0x9298, 0x0001, 0x94a8, 0x0001, 0x222e, 0x2326, 0x9290, 0x0002, + 0x95a8, 0x0002, 0x9398, 0x0002, 0x94a0, 0x0002, 0x1f04, 0x8094, + 0x00e6, 0x080c, 0x95d2, 0x0130, 0x6014, 0x2070, 0x7007, 0x0000, + 0x7067, 0x0103, 0x00ee, 0x080c, 0x7f1e, 0x0005, 0x00d6, 0x0036, + 0x7330, 0x9386, 0x0200, 0x1130, 0x6010, 0x2068, 0x6813, 0x00ff, + 0x6817, 0xfffd, 0x6014, 0x9005, 0x0130, 0x2068, 0x6807, 0x0000, + 0x6867, 0x0103, 0x6b32, 0x080c, 0x7f1e, 0x003e, 0x00de, 0x0005, + 0x0016, 0x20a9, 0x002a, 0x9e80, 0x000c, 0x20e1, 0x0000, 0x2098, + 0x6014, 0x9080, 0x0002, 0x20e9, 0x0001, 0x20a0, 0x4003, 0x20a9, + 0x002a, 0x6014, 0x9080, 0x0001, 0x2004, 0x9080, 0x0002, 0x20a0, + 0x4003, 0x00e6, 0x6014, 0x2004, 0x2070, 0x7067, 0x0103, 0x00ee, + 0x080c, 0x7f1e, 0x001e, 0x0005, 0x0016, 0x2009, 0x0000, 0x7030, + 0x9086, 0x0100, 0x0140, 0x7038, 0x9084, 0x00ff, 0x800c, 0x703c, + 0x9084, 0x00ff, 0x8004, 0x9080, 0x0004, 0x9108, 0x9192, 0x0014, + 0x1218, 0x2011, 0x0000, 0x0010, 0x2009, 0x0014, 0x21a8, 0x9e80, + 0x000c, 0x2098, 0x6014, 0x9080, 0x0002, 0x20a0, 0x080c, 0x4678, + 0x82ff, 0x0170, 0x2009, 0x0205, 0x2104, 0x8000, 0x200a, 0x2e00, + 0x2098, 0x3400, 0x9080, 0x0014, 0x20a0, 0x22a8, 0x080c, 0x4678, + 0x00e6, 0x080c, 0x95d2, 0x0140, 0x6014, 0x2070, 0x7007, 0x0000, + 0x7064, 0x70e2, 0x7067, 0x0103, 0x00ee, 0x080c, 0x7f1e, 0x001e, + 0x0005, 0x0016, 0x00d6, 0x7030, 0x9086, 0x0100, 0x1118, 0x2009, + 0x0004, 0x0010, 0x7034, 0x800c, 0x21a8, 0x9e80, 0x000c, 0x2098, + 0x6014, 0x2068, 0x6804, 0x9005, 0x1108, 0x2d00, 0x9080, 0x000c, + 0x20a0, 0x080c, 0x4678, 0x080c, 0x95d2, 0x0148, 0x6804, 0x9005, + 0x1158, 0x6807, 0x0000, 0x6864, 0x68e2, 0x6867, 0x0103, 0x080c, + 0x7f1e, 0x00de, 0x001e, 0x0005, 0x00e6, 0x2070, 0x7030, 0x8007, + 0x9086, 0x0100, 0x1118, 0x080c, 0x8576, 0x00b8, 0x7034, 0x8007, + 0x800c, 0x9e80, 0x000c, 0x687b, 0x0000, 0x6883, 0x0000, 0x6897, + 0x4000, 0x6aa0, 0x6b9c, 0x6ca8, 0x6da4, 0x2031, 0x0000, 0x2039, + 0x0001, 0x2041, 0x0f7e, 0x0019, 0x0d30, 0x00ee, 0x08c0, 0x00d6, + 0x0006, 0x080c, 0x0dc6, 0x000e, 0x0190, 0x6812, 0x000e, 0x683e, + 0x0006, 0x6e06, 0x2800, 0x683a, 0x6916, 0x6f0e, 0x6a2a, 0x6b2e, + 0x6c32, 0x6d36, 0x2d10, 0x080c, 0x0e55, 0x9085, 0x0001, 0x00de, + 0x0005, 0x00e6, 0x00d6, 0x6043, 0x0000, 0x2c68, 0x0016, 0x2009, + 0x0035, 0x080c, 0x9ac5, 0x001e, 0x1168, 0x0026, 0x622c, 0x2268, + 0x002e, 0x2071, 0x026c, 0x6b20, 0x9386, 0x0003, 0x0130, 0x9386, + 0x0006, 0x0128, 0x080c, 0x7f1e, 0x0020, 0x0031, 0x0010, 0x080c, + 0x8270, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x6814, 0x2078, 0x9186, + 0x0015, 0x0904, 0x8259, 0x918e, 0x0016, 0x1904, 0x826e, 0x700c, + 0x9084, 0xff00, 0x9086, 0x1700, 0x1904, 0x8238, 0x8fff, 0x1138, + 0x6800, 0x9086, 0x000f, 0x0904, 0x821c, 0x0804, 0x826c, 0x6808, + 0x9086, 0xffff, 0x1904, 0x825b, 0x787c, 0x9084, 0x0060, 0x9086, + 0x0020, 0x1128, 0x783c, 0x7940, 0x9105, 0x1904, 0x825b, 0x080c, + 0x9797, 0x685c, 0x7882, 0x787c, 0xc0dc, 0xc0f4, 0xc0d4, 0x787e, + 0x0026, 0x900e, 0x6a18, 0x2001, 0x000a, 0x080c, 0x66ff, 0x7884, + 0x920a, 0x0208, 0x8011, 0x7a86, 0x82ff, 0x002e, 0x1138, 0x00c6, + 0x2d60, 0x080c, 0x9389, 0x00ce, 0x0804, 0x826c, 0x00c6, 0x00d6, + 0x2f68, 0x6868, 0xd0fc, 0x1118, 0x080c, 0x477e, 0x0010, 0x080c, + 0x4a18, 0x00de, 0x00ce, 0x1904, 0x825b, 0x00c6, 0x2d60, 0x080c, + 0x7f1e, 0x00ce, 0x0804, 0x826c, 0x00c6, 0x080c, 0x984d, 0x0190, + 0x6017, 0x0000, 0x6810, 0x6012, 0x080c, 0x99cc, 0x6023, 0x0003, + 0x6904, 0x00c6, 0x2d60, 0x080c, 0x7f1e, 0x00ce, 0x080c, 0x7f4e, + 0x00ce, 0x04d0, 0x2001, 0x12a8, 0x2004, 0x6842, 0x00ce, 0x04a0, + 0x7008, 0x9086, 0x000b, 0x11a0, 0x6010, 0x200c, 0xc1bc, 0x2102, + 0x00c6, 0x2d60, 0x7883, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, + 0x6023, 0x0002, 0x080c, 0x6886, 0x080c, 0x6d42, 0x00ce, 0x00e0, + 0x700c, 0x9086, 0x2a00, 0x1138, 0x2001, 0x12a8, 0x2004, 0x6842, + 0x0098, 0x0471, 0x0098, 0x8fff, 0x090c, 0x0cf1, 0x00c6, 0x00d6, + 0x2d60, 0x2f68, 0x687b, 0x0003, 0x080c, 0x926a, 0x080c, 0x9797, + 0x080c, 0x97a3, 0x00de, 0x00ce, 0x080c, 0x7f1e, 0x00fe, 0x0005, + 0x9186, 0x0015, 0x1128, 0x2001, 0x12a8, 0x2004, 0x6842, 0x0068, + 0x918e, 0x0016, 0x1160, 0x00c6, 0x2d00, 0x2060, 0x080c, 0xad19, + 0x080c, 0x66ae, 0x080c, 0x7f1e, 0x00ce, 0x080c, 0x7f1e, 0x0005, + 0x0026, 0x0036, 0x0046, 0x7228, 0x7cb0, 0x7bac, 0xd2f4, 0x0130, + 0x2001, 0x12a8, 0x2004, 0x6842, 0x0804, 0x82ec, 0x00c6, 0x2d60, + 0x080c, 0x9297, 0x00ce, 0x6804, 0x9086, 0x0050, 0x1170, 0x00c6, + 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c, 0x6886, + 0x080c, 0x6d42, 0x00ce, 0x0804, 0x82ec, 0x6800, 0x9086, 0x000f, + 0x01c8, 0x8fff, 0x090c, 0x0cf1, 0x6824, 0xd0dc, 0x1198, 0x6800, + 0x9086, 0x0004, 0x1198, 0x787c, 0xd0ac, 0x0180, 0x7843, 0x0fff, + 0x783f, 0x0fff, 0x7880, 0xc0f4, 0xc0fc, 0x7882, 0x2001, 0x0001, + 0x6832, 0x00e8, 0x2001, 0x0007, 0x6832, 0x00c8, 0x787c, 0xd0b4, + 0x1138, 0xd0ac, 0x0db8, 0x7838, 0x7934, 0x9105, 0x0d98, 0x0c30, + 0xd2ec, 0x1d80, 0x7024, 0x9306, 0x1118, 0x7020, 0x9406, 0x0d50, + 0x7020, 0x683e, 0x7024, 0x683a, 0x2001, 0x0005, 0x6832, 0x080c, + 0x98d9, 0x080c, 0x6d42, 0x0010, 0x080c, 0x7f1e, 0x004e, 0x003e, + 0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x6038, 0x2068, 0x6a20, + 0x9286, 0x0007, 0x0904, 0x8350, 0x9286, 0x0002, 0x0904, 0x8350, + 0x9286, 0x0000, 0x0904, 0x8350, 0x6808, 0x633c, 0x9306, 0x1904, + 0x8350, 0x2071, 0x026c, 0x9186, 0x0015, 0x05e0, 0x918e, 0x0016, + 0x1190, 0x6034, 0x9084, 0x00ff, 0x9086, 0x0001, 0x1160, 0x700c, + 0x9086, 0x2a00, 0x1140, 0x6038, 0x9080, 0x0009, 0x200c, 0xc1dd, + 0xc1f5, 0x2102, 0x0438, 0x00c6, 0x6038, 0x2060, 0x6104, 0x9186, + 0x004b, 0x01a0, 0x9186, 0x004c, 0x0188, 0x9186, 0x004d, 0x0170, + 0x9186, 0x004e, 0x0158, 0x9186, 0x0052, 0x0140, 0x6014, 0x2068, + 0x080c, 0x95d2, 0x090c, 0x0cf1, 0x6883, 0x0003, 0x6007, 0x0085, + 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x6886, 0x080c, 0x6d42, + 0x00ce, 0x0030, 0x6038, 0x2070, 0x2001, 0x12a8, 0x2004, 0x7042, + 0x080c, 0x7f1e, 0x002e, 0x00de, 0x00ee, 0x0005, 0x00d6, 0x00f6, + 0x6014, 0x2068, 0x6010, 0x2078, 0x91b6, 0x0015, 0x0130, 0x7a08, + 0x7b0c, 0x7c00, 0xc48c, 0x7c02, 0x0038, 0x7238, 0x7a0a, 0x733c, + 0x7b0e, 0x7c00, 0xc48d, 0x7c02, 0x6804, 0x9005, 0x1120, 0x00fe, + 0x00de, 0x0804, 0x80a0, 0x9080, 0x0002, 0x00d6, 0x2068, 0x6a0a, + 0x6b0e, 0x6c02, 0x00de, 0x2009, 0x002b, 0x6aa0, 0x6b9c, 0x6ca8, + 0x6da4, 0x2031, 0x0000, 0x2039, 0x0001, 0x2041, 0x0f7e, 0x080c, + 0x817f, 0x0128, 0x00fe, 0x00de, 0x080c, 0x7f1e, 0x0005, 0x080c, + 0x8576, 0x0cc0, 0x2100, 0x91b2, 0x004c, 0x1a0c, 0x0cf1, 0x91b2, + 0x0040, 0x1a04, 0x83f6, 0x0002, 0x83ea, 0x83de, 0x83ea, 0x83ea, + 0x83ea, 0x83ea, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, + 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, + 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, + 0x83dc, 0x83dc, 0x83dc, 0x83ea, 0x83dc, 0x83ea, 0x83ea, 0x83dc, + 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83ea, 0x83dc, 0x83dc, 0x83dc, + 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83ea, 0x83ea, + 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, 0x83dc, + 0x83dc, 0x83ea, 0x83dc, 0x83dc, 0x080c, 0x0cf1, 0x6003, 0x0001, + 0x6106, 0x080c, 0x68ce, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d42, + 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, 0x68ce, 0x0126, + 0x2091, 0x8000, 0x080c, 0x6d42, 0x012e, 0x0005, 0x2600, 0x0002, + 0x8404, 0x8404, 0x8404, 0x83ea, 0x83ea, 0x8404, 0x8404, 0x8404, + 0x8404, 0x83ea, 0x8404, 0x8404, 0x080c, 0x0cf1, 0x6004, 0x90b2, + 0x004c, 0x1a0c, 0x0cf1, 0x91b6, 0x0013, 0x0904, 0x84a2, 0x91b6, + 0x0027, 0x1904, 0x8468, 0x080c, 0x6c56, 0x6004, 0x080c, 0x97bc, + 0x0178, 0x080c, 0x97cd, 0x0904, 0x8462, 0x908e, 0x0021, 0x0904, + 0x8465, 0x908e, 0x0022, 0x05f0, 0x908e, 0x003d, 0x05f0, 0x0498, + 0x080c, 0x25d1, 0x2001, 0x0007, 0x080c, 0x4ab3, 0x6010, 0x9080, + 0x0028, 0x200c, 0x080c, 0x8576, 0x9186, 0x007e, 0x1148, 0x2001, + 0x1133, 0x2014, 0xc285, 0x080c, 0x5745, 0x1108, 0xc2ad, 0x2202, + 0x0016, 0x0026, 0x0036, 0x2110, 0x2019, 0x0028, 0x080c, 0x69ca, + 0x0076, 0x2039, 0x0000, 0x080c, 0x68fe, 0x6010, 0x00c6, 0x9065, + 0x0100, 0x00ce, 0x2c08, 0x080c, 0xa85f, 0x007e, 0x003e, 0x002e, + 0x001e, 0x080c, 0x4b20, 0x080c, 0x99c4, 0x080c, 0x7f1e, 0x080c, + 0x6d42, 0x0005, 0x080c, 0x8576, 0x0cb0, 0x080c, 0x85a4, 0x0c98, + 0x9186, 0x0014, 0x1db0, 0x080c, 0x6c56, 0x080c, 0x25ad, 0x080c, + 0x97bc, 0x1188, 0x080c, 0x25d1, 0x6010, 0x9080, 0x0028, 0x200c, + 0x080c, 0x8576, 0x9186, 0x007e, 0x1128, 0x2001, 0x1133, 0x200c, + 0xc185, 0x2102, 0x08c0, 0x080c, 0x97cd, 0x1118, 0x080c, 0x8576, + 0x0890, 0x6004, 0x908e, 0x0032, 0x1158, 0x00e6, 0x00f6, 0x2071, + 0x1193, 0x2079, 0x0000, 0x080c, 0x28cc, 0x00fe, 0x00ee, 0x0818, + 0x6004, 0x908e, 0x0021, 0x0d50, 0x908e, 0x0022, 0x090c, 0x8576, + 0x0804, 0x845b, 0x90b2, 0x0040, 0x1a04, 0x8565, 0x2008, 0x0002, + 0x84ea, 0x84eb, 0x84ee, 0x84f1, 0x84f4, 0x84f7, 0x84e8, 0x84e8, + 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, + 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, + 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84fa, 0x8509, + 0x84e8, 0x850b, 0x8509, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, + 0x8509, 0x8509, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, 0x84e8, + 0x84e8, 0x84e8, 0x8545, 0x8509, 0x84e8, 0x8505, 0x84e8, 0x84e8, + 0x84e8, 0x8506, 0x84e8, 0x84e8, 0x84e8, 0x8509, 0x853c, 0x84e8, + 0x080c, 0x0cf1, 0x00f0, 0x2001, 0x000b, 0x0460, 0x2001, 0x0003, + 0x0448, 0x2001, 0x0005, 0x0430, 0x2001, 0x0001, 0x0418, 0x2001, + 0x0009, 0x0400, 0x080c, 0x6c56, 0x6003, 0x0005, 0x2001, 0x12a8, + 0x2004, 0x6042, 0x080c, 0x6d42, 0x00a0, 0x0018, 0x0010, 0x080c, + 0x4ab3, 0x0804, 0x8556, 0x080c, 0x6c56, 0x2001, 0x12a6, 0x2004, + 0x601a, 0x2001, 0x12a8, 0x2004, 0x6042, 0x6003, 0x0004, 0x080c, + 0x6d42, 0x0005, 0x080c, 0x4ab3, 0x080c, 0x6c56, 0x6003, 0x0002, + 0x2001, 0x12a8, 0x2004, 0x6042, 0x0036, 0x2019, 0x115d, 0x2304, + 0x9084, 0xff00, 0x1120, 0x2001, 0x12a6, 0x201c, 0x0040, 0x8007, + 0x909a, 0x0004, 0x0ec0, 0x8003, 0x801b, 0x831b, 0x9318, 0x631a, + 0x003e, 0x080c, 0x6d42, 0x08e8, 0x080c, 0x6c56, 0x080c, 0x99c4, + 0x080c, 0x7f1e, 0x080c, 0x6d42, 0x08a0, 0x00e6, 0x00f6, 0x2071, + 0x1193, 0x2079, 0x0000, 0x080c, 0x28cc, 0x00fe, 0x00ee, 0x080c, + 0x6c56, 0x080c, 0x7f1e, 0x080c, 0x6d42, 0x0818, 0x080c, 0x6c56, + 0x2001, 0x12a8, 0x2004, 0x6042, 0x6003, 0x0002, 0x2001, 0x12a6, + 0x2004, 0x601a, 0x080c, 0x6d42, 0x0005, 0x2600, 0x2008, 0x0002, + 0x8574, 0x8574, 0x8574, 0x8556, 0x8556, 0x8574, 0x8574, 0x8574, + 0x8574, 0x8556, 0x8574, 0x8574, 0x080c, 0x0cf1, 0x00e6, 0x0026, + 0x0016, 0x080c, 0x95d2, 0x0508, 0x6014, 0x2070, 0x7064, 0x9086, + 0x0139, 0x1148, 0x2001, 0x0030, 0x2009, 0x0000, 0x2011, 0x4005, + 0x080c, 0x9a7b, 0x0090, 0x7068, 0xd0fc, 0x0178, 0x7007, 0x0000, + 0x0016, 0x6004, 0x908e, 0x0021, 0x0160, 0x908e, 0x003d, 0x0148, + 0x001e, 0x7067, 0x0103, 0x7033, 0x0100, 0x001e, 0x002e, 0x00ee, + 0x0005, 0x001e, 0x0009, 0x0cc8, 0x00e6, 0x9cf0, 0x0005, 0x2e74, + 0x7000, 0x2070, 0x7067, 0x0103, 0x7023, 0x8001, 0x00ee, 0x0005, + 0x00d6, 0x6610, 0x2668, 0x6804, 0x9084, 0x00ff, 0x00de, 0x90b2, + 0x000c, 0x1a0c, 0x0cf1, 0x6604, 0x96b6, 0x0043, 0x1120, 0x080c, + 0x9a37, 0x0804, 0x861d, 0x6604, 0x96b6, 0x0033, 0x1120, 0x080c, + 0x99e7, 0x0804, 0x861d, 0x6604, 0x96b6, 0x0028, 0x1120, 0x080c, + 0x97fd, 0x0804, 0x861d, 0x6604, 0x96b6, 0x0029, 0x1120, 0x080c, + 0x9816, 0x0804, 0x861d, 0x6604, 0x96b6, 0x001f, 0x1118, 0x080c, + 0x807f, 0x04d8, 0x6604, 0x96b6, 0x0000, 0x1118, 0x080c, 0x8356, + 0x04a0, 0x6604, 0x96b6, 0x0022, 0x1118, 0x080c, 0x80ae, 0x0468, + 0x6604, 0x96b6, 0x0035, 0x1118, 0x080c, 0x8199, 0x0430, 0x6604, + 0x96b6, 0x0039, 0x1118, 0x080c, 0x82f2, 0x00f8, 0x6604, 0x96b6, + 0x003d, 0x1118, 0x080c, 0x80c8, 0x00c0, 0x6604, 0x96b6, 0x0044, + 0x1118, 0x080c, 0x80ec, 0x0088, 0x6604, 0x96b6, 0x0049, 0x1118, + 0x080c, 0x8131, 0x0050, 0x91b6, 0x0015, 0x1110, 0x0053, 0x0028, + 0x91b6, 0x0016, 0x1118, 0x0804, 0x87e2, 0x0005, 0x080c, 0x7f68, + 0x0ce0, 0x863b, 0x863e, 0x863b, 0x8682, 0x863b, 0x8762, 0x87f0, + 0x863b, 0x863b, 0x87bc, 0x863b, 0x87d2, 0x00e6, 0x080c, 0x1132, + 0x9cf0, 0x0005, 0x2e74, 0x7000, 0x2070, 0x7067, 0x0103, 0x00ee, + 0x080c, 0x7f1e, 0x0005, 0xa001, 0xa001, 0x0005, 0x00e6, 0x2071, + 0x1100, 0x7080, 0x9086, 0x0074, 0x1540, 0x080c, 0xa836, 0x11b0, + 0x6010, 0x00d6, 0x2068, 0x7030, 0xd08c, 0x0128, 0x6800, 0xd0bc, + 0x0110, 0xc0c5, 0x6802, 0x00e9, 0x00de, 0x2001, 0x0006, 0x080c, + 0x4ab3, 0x080c, 0x25d1, 0x080c, 0x7f1e, 0x0088, 0x2001, 0x000a, + 0x080c, 0x4ab3, 0x080c, 0x25d1, 0x6003, 0x0001, 0x6007, 0x0001, + 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0010, 0x080c, 0x8752, 0x00ee, + 0x0005, 0x6800, 0xd084, 0x0168, 0x2001, 0x0000, 0x080c, 0x4aa1, + 0x2069, 0x1152, 0x6804, 0xd0a4, 0x0120, 0x2001, 0x0006, 0x080c, + 0x4ae0, 0x0005, 0x00d6, 0x2011, 0x1120, 0x2204, 0x9086, 0x0074, + 0x1904, 0x874f, 0x6010, 0x2068, 0x6aa0, 0x9286, 0x007e, 0x1120, + 0x080c, 0x88f8, 0x0804, 0x86f0, 0x080c, 0x88ee, 0x6010, 0x2068, + 0x6aa0, 0x9286, 0x0080, 0x11c0, 0x6813, 0x00ff, 0x6817, 0xfffc, + 0x6014, 0x9005, 0x0138, 0x2068, 0x6807, 0x0000, 0x6867, 0x0103, + 0x6833, 0x0200, 0x2001, 0x0006, 0x080c, 0x4ab3, 0x080c, 0x25d1, + 0x080c, 0x7f1e, 0x0804, 0x8750, 0x00e6, 0x2071, 0x1133, 0x2e04, + 0xd09c, 0x0188, 0x2071, 0x0260, 0x7108, 0x720c, 0x918c, 0x00ff, + 0x1118, 0x9284, 0xff00, 0x0138, 0x6010, 0x2070, 0x70a0, 0xd0bc, + 0x1110, 0x7112, 0x7216, 0x00ee, 0x6014, 0x9005, 0x0198, 0x2068, + 0x6868, 0xd0f4, 0x0178, 0x6864, 0x9084, 0x00ff, 0x9086, 0x0039, + 0x1958, 0x2001, 0x0000, 0x2009, 0x0000, 0x2011, 0x4000, 0x080c, + 0x9a7b, 0x0840, 0x2001, 0x0004, 0x080c, 0x4ab3, 0x6003, 0x0001, + 0x6007, 0x0003, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0804, 0x8750, + 0x685c, 0xd0e4, 0x01d8, 0x080c, 0x9966, 0x080c, 0x5745, 0x0118, + 0xd0dc, 0x1904, 0x86aa, 0x2011, 0x1133, 0x2204, 0xc0ad, 0x2012, + 0x2001, 0x1280, 0x2004, 0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000, + 0x080c, 0x1cbe, 0x78e2, 0x00fe, 0x0804, 0x86aa, 0x080c, 0x99a3, + 0x2011, 0x1133, 0x2204, 0xc0a5, 0x2012, 0x0006, 0x080c, 0xa966, + 0x000e, 0x1904, 0x86aa, 0xc0b5, 0x2012, 0x2001, 0x0000, 0x080c, + 0x4aa1, 0x00c6, 0x2009, 0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, + 0x7932, 0x7936, 0x00fe, 0x080c, 0x1c93, 0x00f6, 0x2079, 0x1100, + 0x7972, 0x2100, 0x2009, 0x0000, 0x080c, 0x1c69, 0x794e, 0x00fe, + 0x8108, 0x080c, 0x4b03, 0x2c00, 0x00ce, 0x1904, 0x86aa, 0x6012, + 0x2001, 0x0002, 0x080c, 0x4ab3, 0x6023, 0x0001, 0x6003, 0x0001, + 0x6007, 0x0002, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0008, 0x0011, + 0x00de, 0x0005, 0x2030, 0x2001, 0x1100, 0x2004, 0x9086, 0x0003, + 0x0120, 0x2001, 0x0007, 0x080c, 0x4ab3, 0x080c, 0x25d1, 0x080c, + 0x7f1e, 0x0005, 0x00e6, 0x0026, 0x0016, 0x2071, 0x1100, 0x7080, + 0x9086, 0x0014, 0x1904, 0x87b4, 0x7000, 0x9086, 0x0003, 0x1178, + 0x6014, 0x9005, 0x1160, 0x0036, 0x0046, 0x6010, 0x9080, 0x0028, + 0x201c, 0x2021, 0x0006, 0x080c, 0x384a, 0x004e, 0x003e, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x4bf5, 0x080c, 0x8671, 0x00de, 0x080c, + 0x89bf, 0x1550, 0x6010, 0x00d6, 0x2068, 0x6890, 0x00de, 0x9005, + 0x0518, 0x2001, 0x0006, 0x080c, 0x4ab3, 0x00e6, 0x6014, 0x9075, + 0x01a8, 0x7064, 0x9084, 0x00ff, 0x9086, 0x0039, 0x1148, 0x2001, + 0x0000, 0x2009, 0x0000, 0x2011, 0x4000, 0x080c, 0x9a7b, 0x0030, + 0x7007, 0x0000, 0x7067, 0x0103, 0x7033, 0x0200, 0x00ee, 0x080c, + 0x25d1, 0x080c, 0x7f1e, 0x0020, 0x080c, 0x8576, 0x080c, 0x8752, + 0x001e, 0x002e, 0x00ee, 0x0005, 0x2011, 0x1120, 0x2204, 0x9086, + 0x0014, 0x1168, 0x2001, 0x0002, 0x080c, 0x4ab3, 0x6003, 0x0001, + 0x6007, 0x0001, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0010, 0x080c, + 0x8752, 0x0005, 0x2011, 0x1120, 0x2204, 0x9086, 0x0004, 0x1138, + 0x2001, 0x0007, 0x080c, 0x4ab3, 0x080c, 0x7f1e, 0x0010, 0x080c, + 0x8752, 0x0005, 0x000b, 0x0005, 0x863b, 0x87f7, 0x863b, 0x882d, + 0x863b, 0x88a4, 0x87f0, 0x863b, 0x863b, 0x88b9, 0x863b, 0x88cb, + 0x6604, 0x96b6, 0x001e, 0x1110, 0x080c, 0x7f1e, 0x0005, 0x00d6, + 0x00c6, 0x080c, 0x88dd, 0x1188, 0x2001, 0x0000, 0x080c, 0x4aa1, + 0x2001, 0x0002, 0x080c, 0x4ab3, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x68ce, 0x080c, 0x6d42, 0x00e8, 0x2009, 0x026e, 0x2104, + 0x9086, 0x0009, 0x1160, 0x6010, 0x2068, 0x6840, 0x9084, 0x00ff, + 0x9005, 0x0170, 0x8001, 0x6842, 0x601b, 0x000a, 0x0058, 0x2009, + 0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x1900, 0x1108, 0x08c0, + 0x080c, 0x8752, 0x00ce, 0x00de, 0x0005, 0x080c, 0x88eb, 0x00d6, + 0x2069, 0x128f, 0x2d04, 0x9005, 0x0168, 0x6010, 0x2068, 0x68a0, + 0x9086, 0x007e, 0x1138, 0x2069, 0x111c, 0x2d04, 0x8000, 0x206a, + 0x00de, 0x0010, 0x00de, 0x0088, 0x2001, 0x0000, 0x080c, 0x4aa1, + 0x2001, 0x0002, 0x080c, 0x4ab3, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0428, 0x080c, 0x8576, 0x2009, + 0x026e, 0x2134, 0x96b4, 0x00ff, 0x9686, 0x0005, 0x01e0, 0x9686, + 0x000b, 0x01b0, 0x2009, 0x026f, 0x2104, 0x9084, 0xff00, 0x1118, + 0x9686, 0x0009, 0x0180, 0x9086, 0x1900, 0x1150, 0x9686, 0x0009, + 0x0150, 0x2001, 0x0004, 0x080c, 0x4ab3, 0x080c, 0x7f1e, 0x0010, + 0x080c, 0x8752, 0x0005, 0x00d6, 0x6014, 0x2068, 0x080c, 0x95d2, + 0x0128, 0x6868, 0xd0fc, 0x0110, 0x00de, 0x0c90, 0x6010, 0x2068, + 0x6840, 0x9084, 0x00ff, 0x9005, 0x0140, 0x8001, 0x6842, 0x601b, + 0x000a, 0x6007, 0x0016, 0x00de, 0x0c28, 0x68a0, 0x9086, 0x007e, + 0x1138, 0x00e6, 0x2071, 0x1100, 0x080c, 0x46bb, 0x00ee, 0x0010, + 0x080c, 0x25ad, 0x00de, 0x08a0, 0x080c, 0x88eb, 0x1168, 0x2001, + 0x0004, 0x080c, 0x4ab3, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, + 0x68ce, 0x080c, 0x6d42, 0x0020, 0x080c, 0x8576, 0x080c, 0x8752, + 0x0005, 0x0489, 0x1168, 0x2001, 0x0008, 0x080c, 0x4ab3, 0x6003, + 0x0001, 0x6007, 0x0005, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0010, + 0x080c, 0x8752, 0x0005, 0x00f9, 0x1168, 0x2001, 0x000a, 0x080c, + 0x4ab3, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x68ce, 0x080c, + 0x6d42, 0x0010, 0x080c, 0x8752, 0x0005, 0x2009, 0x026e, 0x2104, + 0x9086, 0x0003, 0x1138, 0x2009, 0x026f, 0x2104, 0x9084, 0xff00, + 0x9086, 0x2a00, 0x0005, 0x9085, 0x0001, 0x0005, 0x00c6, 0x0016, + 0x9c88, 0x0004, 0x2164, 0x080c, 0x4b67, 0x001e, 0x00ce, 0x0005, + 0x00f6, 0x00e6, 0x00d6, 0x0036, 0x0016, 0x6010, 0x2068, 0x2009, + 0x1133, 0x2104, 0x9085, 0x0003, 0x200a, 0x080c, 0x8994, 0x0570, + 0x2009, 0x1133, 0x2104, 0xc0cd, 0x200a, 0x2001, 0x1153, 0x2004, + 0xd0a4, 0x0158, 0x9006, 0x2020, 0x2009, 0x002a, 0x080c, 0xaaca, + 0x2001, 0x110c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, + 0x0001, 0x080c, 0x2582, 0x00e6, 0x2071, 0x1100, 0x080c, 0x23cd, + 0x00ee, 0x00c6, 0x0156, 0x20a9, 0x0081, 0x2009, 0x007f, 0x080c, + 0x26a3, 0x8108, 0x1f04, 0x892f, 0x015e, 0x00ce, 0x080c, 0x88ee, + 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, 0x0260, 0x2079, 0x0200, + 0x7817, 0x0001, 0x2001, 0x1133, 0x200c, 0xc1c5, 0x7018, 0xd0fc, + 0x0110, 0xd0dc, 0x0118, 0x7038, 0xd0dc, 0x1108, 0xc1c4, 0x7817, + 0x0000, 0x2001, 0x1133, 0x2102, 0x2079, 0x0100, 0x2e04, 0x9084, + 0x00ff, 0x2069, 0x111b, 0x206a, 0x78e6, 0x0006, 0x8e70, 0x2e04, + 0x2069, 0x111c, 0x206a, 0x78ea, 0x7832, 0x7836, 0x2010, 0x9084, + 0xff00, 0x001e, 0x9105, 0x2009, 0x1127, 0x200a, 0x2200, 0x9084, + 0x00ff, 0x2008, 0x080c, 0x1c93, 0x080c, 0x5745, 0x0170, 0x2071, + 0x0260, 0x2069, 0x12a2, 0x7048, 0x206a, 0x704c, 0x6806, 0x7050, + 0x680a, 0x7054, 0x680e, 0x080c, 0x9966, 0x0040, 0x2001, 0x0006, + 0x080c, 0x4ab3, 0x080c, 0x25d1, 0x080c, 0x7f1e, 0x001e, 0x003e, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0026, 0x0036, 0x00e6, 0x0156, + 0x2019, 0x1127, 0x231c, 0x83ff, 0x01e8, 0x2071, 0x0260, 0x7200, + 0x9294, 0x00ff, 0x7004, 0x9084, 0xff00, 0x9205, 0x9306, 0x1190, + 0x2011, 0x0276, 0x20a9, 0x0004, 0x9d98, 0x000a, 0x080c, 0x8a45, + 0x1148, 0x2011, 0x027a, 0x20a9, 0x0004, 0x9d98, 0x0006, 0x080c, + 0x8a45, 0x1100, 0x015e, 0x00ee, 0x003e, 0x002e, 0x0005, 0x00e6, + 0x2071, 0x0260, 0x7034, 0x9086, 0x0014, 0x11a8, 0x7038, 0x9086, + 0x0800, 0x1188, 0x703c, 0xd0ec, 0x0160, 0x9084, 0x0f00, 0x9086, + 0x0100, 0x1138, 0x7054, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0x9006, + 0x0010, 0x9085, 0x0001, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, + 0x0076, 0x0056, 0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, + 0x2029, 0x12e5, 0x252c, 0x2021, 0x12eb, 0x2424, 0x2061, 0x15c0, + 0x2071, 0x1100, 0x7244, 0x7064, 0x9202, 0x16f0, 0x080c, 0xaaf2, + 0x05a0, 0x6720, 0x9786, 0x0001, 0x0580, 0x9786, 0x0007, 0x0568, + 0x2500, 0x9c06, 0x0550, 0x2400, 0x9c06, 0x0538, 0x00c6, 0x6000, + 0x9086, 0x0004, 0x1110, 0x080c, 0x12c7, 0x9786, 0x0008, 0x1148, + 0x080c, 0x97cd, 0x1130, 0x00ce, 0x080c, 0x8576, 0x080c, 0x97a3, + 0x00a0, 0x6014, 0x2068, 0x080c, 0x95d2, 0x0160, 0x9786, 0x0003, + 0x11e8, 0x6867, 0x0103, 0x6b7a, 0x6877, 0x0000, 0x080c, 0x50a5, + 0x080c, 0x9797, 0x080c, 0x97a3, 0x00ce, 0x9ce0, 0x0018, 0x7058, + 0x9c02, 0x1210, 0x0804, 0x89f2, 0x012e, 0x000e, 0x002e, 0x004e, + 0x005e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x9786, 0x0006, + 0x1118, 0x080c, 0xaa84, 0x0c30, 0x08e0, 0x220c, 0x2304, 0x9106, + 0x1130, 0x8210, 0x8318, 0x1f04, 0x8a45, 0x9006, 0x0005, 0x2304, + 0x9102, 0x0218, 0x2001, 0x0001, 0x0010, 0x2001, 0x0000, 0x918d, + 0x0001, 0x0005, 0x0136, 0x01c6, 0x0016, 0x0026, 0x080c, 0x0d7e, + 0x2100, 0x22e0, 0x9300, 0x2098, 0x3518, 0x20a9, 0x0001, 0x002e, + 0x220c, 0x4002, 0x910e, 0x1140, 0x8210, 0x8319, 0x1dc8, 0x9006, + 0x001e, 0x01ce, 0x013e, 0x0005, 0x220c, 0x9102, 0x0218, 0x2001, + 0x0001, 0x0010, 0x2001, 0x0000, 0x918d, 0x0001, 0x001e, 0x01ce, + 0x013e, 0x0005, 0x6004, 0x908a, 0x004c, 0x1a0c, 0x0cf1, 0x080c, + 0x97bc, 0x0120, 0x080c, 0x97cd, 0x0168, 0x0028, 0x080c, 0x25d1, + 0x080c, 0x97cd, 0x0138, 0x080c, 0x6c56, 0x080c, 0x7f1e, 0x080c, + 0x6d42, 0x0005, 0x080c, 0x8576, 0x0cb0, 0x9182, 0x0040, 0x0002, + 0x8ab3, 0x8ab3, 0x8ab3, 0x8ab3, 0x8ab3, 0x8ab3, 0x8ab3, 0x8ab3, + 0x8ab3, 0x8ab3, 0x8ab3, 0x8ab5, 0x8ab5, 0x8ab5, 0x8ab5, 0x8ab3, + 0x8ab3, 0x8ab3, 0x8ab5, 0x080c, 0x0cf1, 0x600b, 0xffff, 0x6003, + 0x0001, 0x6106, 0x080c, 0x6886, 0x0126, 0x2091, 0x8000, 0x080c, + 0x6d42, 0x012e, 0x0005, 0x9186, 0x0013, 0x1128, 0x6004, 0x9082, + 0x0040, 0x0804, 0x8b4d, 0x9186, 0x0027, 0x11e8, 0x080c, 0x6c56, + 0x080c, 0x25ad, 0x00d6, 0x6114, 0x2168, 0x080c, 0x95d2, 0x0168, + 0x6867, 0x0103, 0x687b, 0x0029, 0x6877, 0x0000, 0x697c, 0xc1c5, + 0x697e, 0x080c, 0x50a5, 0x080c, 0x9797, 0x00de, 0x080c, 0x7f1e, + 0x080c, 0x6d42, 0x0005, 0x9186, 0x0014, 0x1120, 0x6004, 0x9082, + 0x0040, 0x0418, 0x9186, 0x0046, 0x0138, 0x9186, 0x0045, 0x0120, + 0x9186, 0x0048, 0x190c, 0x0cf1, 0x2001, 0x0109, 0x2004, 0xd084, + 0x0198, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, + 0x677e, 0x002e, 0x001e, 0x000e, 0x012e, 0xa001, 0x6000, 0x9086, + 0x0002, 0x1110, 0x0804, 0x8b8c, 0x0005, 0x0002, 0x8b2b, 0x8b29, + 0x8b29, 0x8b29, 0x8b29, 0x8b29, 0x8b29, 0x8b29, 0x8b29, 0x8b29, + 0x8b29, 0x8b46, 0x8b46, 0x8b46, 0x8b46, 0x8b29, 0x8b46, 0x8b29, + 0x8b46, 0x080c, 0x0cf1, 0x080c, 0x6c56, 0x00d6, 0x6114, 0x2168, + 0x080c, 0x95d2, 0x0168, 0x6867, 0x0103, 0x687b, 0x0006, 0x6877, + 0x0000, 0x6880, 0xc0ec, 0x6882, 0x080c, 0x50a5, 0x080c, 0x9797, + 0x00de, 0x080c, 0x7f1e, 0x080c, 0x6d42, 0x0005, 0x080c, 0x6c56, + 0x080c, 0x7f1e, 0x080c, 0x6d42, 0x0005, 0x0002, 0x8b63, 0x8b61, + 0x8b61, 0x8b61, 0x8b61, 0x8b61, 0x8b61, 0x8b61, 0x8b61, 0x8b61, + 0x8b61, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b61, 0x8b85, 0x8b61, + 0x8b7a, 0x080c, 0x0cf1, 0x00d6, 0x080c, 0x6c56, 0x6014, 0x2068, + 0x2001, 0x12a8, 0x2004, 0x6042, 0x697c, 0xd1ac, 0x0140, 0x6003, + 0x0004, 0x687c, 0x9085, 0x0400, 0x687e, 0x00de, 0x0005, 0x6003, + 0x0002, 0x0cb8, 0x080c, 0x6c56, 0x2001, 0x12a8, 0x2004, 0x6042, + 0x6003, 0x000f, 0x080c, 0x6d42, 0x0005, 0x080c, 0x6c56, 0x080c, + 0x7f1e, 0x080c, 0x6d42, 0x0005, 0x9182, 0x0040, 0x0002, 0x8ba3, + 0x8ba3, 0x8ba3, 0x8ba3, 0x8ba3, 0x8ba5, 0x8c7a, 0x8ba3, 0x8ba3, + 0x8ba3, 0x8ba3, 0x8ba3, 0x8ba3, 0x8ba3, 0x8ba3, 0x8ba3, 0x8ba3, + 0x8ba3, 0x8ba3, 0x8ca9, 0x080c, 0x0cf1, 0x00d6, 0x6114, 0x2168, + 0x7644, 0x96b4, 0x0fff, 0x86ff, 0x1508, 0x6010, 0x2004, 0xd0bc, + 0x1904, 0x8c65, 0x687b, 0x0000, 0x6867, 0x0103, 0x6e76, 0x687c, + 0xd0ac, 0x0128, 0x6834, 0x6938, 0x9115, 0x190c, 0x8dfb, 0x080c, + 0x4ed6, 0x6210, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x7044, 0xd0e4, + 0x1904, 0x8c4b, 0x080c, 0x7f1e, 0x00de, 0x0005, 0x968c, 0x0c00, + 0x0148, 0x6010, 0x2004, 0xd0bc, 0x1904, 0x8c4f, 0x7348, 0x6b92, + 0x734c, 0x6b8e, 0x968c, 0x00ff, 0x9186, 0x0002, 0x0508, 0x9186, + 0x0028, 0x1118, 0x687b, 0x001c, 0x00e8, 0xd6dc, 0x01a0, 0x687b, + 0x0015, 0x687c, 0xd0ac, 0x0170, 0x6938, 0x6a34, 0x2100, 0x9205, + 0x0148, 0x7048, 0x9106, 0x1118, 0x734c, 0x9206, 0x0118, 0x6992, + 0x6a8e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0x687b, 0x0007, 0x0010, + 0x687b, 0x0000, 0x6867, 0x0103, 0x6e76, 0x901e, 0xd6c4, 0x01d8, + 0x9686, 0x0100, 0x1130, 0x7064, 0x9005, 0x1118, 0xc6c4, 0x0804, + 0x8bab, 0x735c, 0x6b86, 0x83ff, 0x0170, 0x938a, 0x0009, 0x0210, + 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018, 0x9d90, 0x0025, + 0x080c, 0x927a, 0x003e, 0xd6cc, 0x0904, 0x8bbf, 0x7154, 0x698a, + 0x81ff, 0x0904, 0x8bbf, 0x9192, 0x0021, 0x1268, 0x8304, 0x9098, + 0x0018, 0x9d90, 0x0029, 0x080c, 0x927a, 0x2011, 0x0205, 0x2013, + 0x0000, 0x0804, 0x8bbf, 0x6868, 0xd0fc, 0x0120, 0x2009, 0x0020, + 0x698a, 0x0c60, 0x00f6, 0x2d78, 0x080c, 0x9219, 0x00fe, 0x080c, + 0x926a, 0x0804, 0x8bc1, 0x080c, 0x987a, 0x0804, 0x8bcc, 0x687c, + 0xd0ac, 0x0904, 0x8bd6, 0x6024, 0xd0dc, 0x1904, 0x8bd6, 0x6880, + 0xd0bc, 0x1904, 0x8bd6, 0x7348, 0x6838, 0x9306, 0x11b8, 0x734c, + 0x6834, 0x9306, 0x0904, 0x8bd6, 0x0088, 0x687c, 0xd0ac, 0x0904, + 0x8bb2, 0x6838, 0x6934, 0x9105, 0x0904, 0x8bb2, 0x6024, 0xd0dc, + 0x1904, 0x8bb2, 0x6880, 0xd0bc, 0x1904, 0x8bb2, 0x080c, 0x98aa, + 0x0804, 0x8bcc, 0x00f6, 0x6003, 0x0003, 0x2079, 0x026c, 0x7c04, + 0x7b00, 0x7e0c, 0x7d08, 0x6014, 0x2078, 0x787c, 0xd0ac, 0x0138, + 0x6003, 0x0002, 0x00fe, 0x0005, 0x2130, 0x2228, 0x0058, 0x2400, + 0x79ac, 0x910a, 0x2300, 0x7ab0, 0x9213, 0x2600, 0x9102, 0x2500, + 0x9203, 0x0e90, 0x7c36, 0x7b3a, 0x7e46, 0x7d4a, 0x00fe, 0x6043, + 0x0000, 0x2c10, 0x080c, 0x13a9, 0x080c, 0x68eb, 0x080c, 0x6e10, + 0x0005, 0x0005, 0x9182, 0x0040, 0x0002, 0x8cc0, 0x8cc0, 0x8cc0, + 0x8cc0, 0x8cc0, 0x8cc2, 0x8d54, 0x8cc0, 0x8cc0, 0x8d6a, 0x8dd2, + 0x8cc0, 0x8cc0, 0x8cc0, 0x8cc0, 0x8de1, 0x8cc0, 0x8cc0, 0x8cc0, + 0x080c, 0x0cf1, 0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0x0260, + 0x6114, 0x2178, 0x7644, 0x7e76, 0x96b4, 0x0fff, 0x7f7c, 0xc7e5, + 0x7f7e, 0x6210, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0904, + 0x8d4f, 0x9694, 0xff00, 0x9284, 0x0c00, 0x0120, 0x7048, 0x7892, + 0x704c, 0x788e, 0x9284, 0x0300, 0x0904, 0x8d4f, 0x080c, 0x0ddf, + 0x090c, 0x0cf1, 0x2d00, 0x787a, 0x7f7c, 0xc7cd, 0x7f7e, 0x6867, + 0x0103, 0x7868, 0x686a, 0x786c, 0x686e, 0x7870, 0x6872, 0x6e76, + 0x968c, 0x0c00, 0x0120, 0x7348, 0x6b92, 0x734c, 0x6b8e, 0x968c, + 0x00ff, 0x9186, 0x0002, 0x0180, 0x9186, 0x0028, 0x1118, 0x687b, + 0x001c, 0x0060, 0xd6dc, 0x0118, 0x687b, 0x0015, 0x0038, 0xd6d4, + 0x0118, 0x687b, 0x0007, 0x0010, 0x687b, 0x0000, 0x6f7e, 0x7880, + 0x6882, 0x7884, 0x6886, 0x901e, 0xd6c4, 0x0190, 0x735c, 0x6b86, + 0x83ff, 0x0170, 0x938a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, + 0x2308, 0x2019, 0x0018, 0x9d90, 0x0025, 0x080c, 0x927a, 0x003e, + 0xd6cc, 0x01e8, 0x7154, 0x698a, 0x81ff, 0x01c8, 0x9192, 0x0021, + 0x1260, 0x8304, 0x9098, 0x0018, 0x9d90, 0x0029, 0x080c, 0x927a, + 0x2011, 0x0205, 0x2013, 0x0000, 0x0050, 0x7868, 0xd0fc, 0x0120, + 0x2009, 0x0020, 0x698a, 0x0c68, 0x2d78, 0x080c, 0x9219, 0x00de, + 0x00ee, 0x00fe, 0x007e, 0x0005, 0x00f6, 0x6003, 0x0003, 0x2079, + 0x026c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6014, 0x2078, 0x7c36, + 0x7b3a, 0x7e46, 0x7d4a, 0x00fe, 0x2c10, 0x080c, 0x13a9, 0x080c, + 0x76ee, 0x0005, 0x00d6, 0x2001, 0x12a8, 0x2004, 0x6042, 0x6003, + 0x0002, 0x080c, 0x6cf2, 0x080c, 0x6e10, 0x6114, 0x2168, 0x697c, + 0xd1e4, 0x0904, 0x8dcd, 0xd1cc, 0x0570, 0x6978, 0x6868, 0xd0fc, + 0x0500, 0x0016, 0x687c, 0x0006, 0x6880, 0x0006, 0x9d90, 0x0019, + 0x9198, 0x0019, 0x2009, 0x0020, 0x0156, 0x21a8, 0x2304, 0x2012, + 0x8318, 0x8210, 0x1f04, 0x8d8e, 0x015e, 0x000e, 0x6882, 0x000e, + 0x687e, 0x001e, 0x6874, 0x0006, 0x2168, 0x080c, 0x0e06, 0x001e, + 0x0440, 0x0016, 0x080c, 0x0e06, 0x00de, 0x6974, 0x0016, 0x080c, + 0x926a, 0x001e, 0x00f0, 0x6867, 0x0103, 0x6974, 0x9184, 0x00ff, + 0x90b6, 0x0002, 0x0180, 0x9086, 0x0028, 0x1118, 0x687b, 0x001c, + 0x0060, 0xd1dc, 0x0118, 0x687b, 0x0015, 0x0038, 0xd1d4, 0x0118, + 0x687b, 0x0007, 0x0010, 0x687b, 0x0000, 0x0016, 0x080c, 0x4ed6, + 0x001e, 0xd1e4, 0x1120, 0x080c, 0x7f1e, 0x00de, 0x0005, 0x080c, + 0x987a, 0x0cd8, 0x2019, 0x0001, 0x080c, 0x7936, 0x6003, 0x0002, + 0x2001, 0x12a8, 0x2004, 0x6042, 0x080c, 0x6cf2, 0x080c, 0x6e10, + 0x0005, 0x080c, 0x6cf2, 0x080c, 0x25ad, 0x00d6, 0x6114, 0x2168, + 0x080c, 0x95d2, 0x0150, 0x6867, 0x0103, 0x687b, 0x0029, 0x6877, + 0x0000, 0x080c, 0x50a5, 0x080c, 0x9797, 0x00de, 0x080c, 0x7f1e, + 0x080c, 0x6e10, 0x0005, 0x687b, 0x0015, 0xd1fc, 0x0138, 0x687b, + 0x0007, 0x8002, 0x8000, 0x810a, 0x9189, 0x0000, 0x6992, 0x688e, + 0x0005, 0x9182, 0x0040, 0x0002, 0x8e20, 0x8e20, 0x8e20, 0x8e20, + 0x8e20, 0x8e22, 0x8e20, 0x8e20, 0x8ec0, 0x8e20, 0x8e20, 0x8e20, + 0x8e20, 0x8e20, 0x8e20, 0x8e20, 0x8e20, 0x8e20, 0x8e20, 0x8fdc, + 0x080c, 0x0cf1, 0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0x0260, + 0x6114, 0x2178, 0x7644, 0x7e76, 0x96b4, 0x0fff, 0x7f7c, 0xc7e5, + 0x7f7e, 0x6210, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0904, + 0x8eb9, 0x9694, 0xff00, 0x9284, 0x0c00, 0x0120, 0x7048, 0x7892, + 0x704c, 0x788e, 0x9284, 0x0300, 0x0904, 0x8eb9, 0x9686, 0x0100, + 0x1130, 0x7064, 0x9005, 0x1118, 0xc6c4, 0x7e76, 0x0c38, 0x080c, + 0x0ddf, 0x090c, 0x0cf1, 0x2d00, 0x787a, 0x7f7c, 0x97bd, 0x0200, + 0x7f7e, 0x6867, 0x0103, 0x7868, 0x686a, 0x786c, 0x686e, 0x7870, + 0x6872, 0x6e76, 0x968c, 0x0c00, 0x0120, 0x7348, 0x6b92, 0x734c, + 0x6b8e, 0x968c, 0x00ff, 0x9186, 0x0002, 0x0180, 0x9186, 0x0028, + 0x1118, 0x687b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0x687b, 0x0015, + 0x0038, 0xd6d4, 0x0118, 0x687b, 0x0007, 0x0010, 0x687b, 0x0000, + 0x6f7e, 0x7880, 0x6882, 0x7884, 0x6886, 0x901e, 0xd6c4, 0x0190, + 0x735c, 0x6b86, 0x83ff, 0x0170, 0x938a, 0x0009, 0x0210, 0x2019, + 0x0008, 0x0036, 0x2308, 0x2019, 0x0018, 0x9d90, 0x0025, 0x080c, + 0x927a, 0x003e, 0xd6cc, 0x01e8, 0x7154, 0x698a, 0x81ff, 0x01c8, + 0x9192, 0x0021, 0x1260, 0x8304, 0x9098, 0x0018, 0x9d90, 0x0029, + 0x080c, 0x927a, 0x2011, 0x0205, 0x2013, 0x0000, 0x0050, 0x7868, + 0xd0fc, 0x0120, 0x2009, 0x0020, 0x698a, 0x0c68, 0x2d78, 0x080c, + 0x9219, 0x080c, 0x12a4, 0x00de, 0x00ee, 0x00fe, 0x007e, 0x0005, + 0x2001, 0x12a8, 0x2004, 0x6042, 0x00d6, 0x6114, 0x2168, 0x683c, + 0x6940, 0x9105, 0x1118, 0x687c, 0xc0dc, 0x687e, 0x6003, 0x0002, + 0x697c, 0xd1e4, 0x0904, 0x8fd7, 0x6043, 0x0000, 0x6010, 0x2004, + 0xd0bc, 0x11f8, 0xd1cc, 0x0904, 0x8fa6, 0x6978, 0x6868, 0xd0fc, + 0x0904, 0x8f69, 0x0016, 0x687c, 0x0006, 0x6880, 0x0006, 0x00f6, + 0x2178, 0x7974, 0x9184, 0x00ff, 0x90b6, 0x0002, 0x0904, 0x8f3e, + 0x9086, 0x0028, 0x15b8, 0x687b, 0x001c, 0x787b, 0x001c, 0x0804, + 0x8f46, 0x6024, 0xd0f4, 0x11d0, 0x6838, 0x6a34, 0x9205, 0x09d0, + 0x6838, 0x6a90, 0x9206, 0x1120, 0x688c, 0x6a34, 0x9206, 0x0990, + 0x6024, 0xd0d4, 0x1148, 0x69ac, 0x6834, 0x9102, 0x603a, 0x69b0, + 0x6838, 0x9103, 0x603e, 0x6024, 0xc0f5, 0x6026, 0x6010, 0x00d6, + 0x2068, 0x683c, 0x8000, 0x683e, 0x00de, 0x687c, 0xc0e4, 0x687e, + 0x6877, 0x0000, 0x6893, 0x0000, 0x688f, 0x0000, 0x080c, 0x98aa, + 0x0804, 0x8fd7, 0xd1dc, 0x0158, 0x687b, 0x0015, 0x787b, 0x0015, + 0x080c, 0x9a64, 0x0118, 0x7974, 0xc1dc, 0x7976, 0x0078, 0xd1d4, + 0x0128, 0x687b, 0x0007, 0x787b, 0x0007, 0x0040, 0x687c, 0xd0ac, + 0x0128, 0x6834, 0x6938, 0x9115, 0x190c, 0x8dfb, 0x6878, 0x787a, + 0x6890, 0x7892, 0x688c, 0x788e, 0x9d90, 0x0019, 0x9f98, 0x0019, + 0x2009, 0x0020, 0x0156, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, + 0x1f04, 0x8f54, 0x015e, 0x00fe, 0x000e, 0x6882, 0x000e, 0x687e, + 0x001e, 0x6874, 0x0006, 0x2168, 0x080c, 0x0e06, 0x001e, 0x0804, + 0x8fd3, 0x0016, 0x00f6, 0x2178, 0x7974, 0x9184, 0x00ff, 0x90b6, + 0x0002, 0x01e0, 0x9086, 0x0028, 0x1128, 0x687b, 0x001c, 0x787b, + 0x001c, 0x00e0, 0xd1dc, 0x0158, 0x687b, 0x0015, 0x787b, 0x0015, + 0x080c, 0x9a64, 0x0118, 0x7974, 0xc1dc, 0x7976, 0x0078, 0xd1d4, + 0x0128, 0x687b, 0x0007, 0x787b, 0x0007, 0x0040, 0x687c, 0xd0ac, + 0x0128, 0x6834, 0x6938, 0x9115, 0x190c, 0x8dfb, 0x6890, 0x7892, + 0x688c, 0x788e, 0x687c, 0x787e, 0x00fe, 0x080c, 0x0e06, 0x00de, + 0x6974, 0x0016, 0x080c, 0x926a, 0x001e, 0x0468, 0x6867, 0x0103, + 0x6974, 0x9184, 0x00ff, 0x90b6, 0x0002, 0x01b0, 0x9086, 0x0028, + 0x1118, 0x687b, 0x001c, 0x00d0, 0xd1dc, 0x0148, 0x687b, 0x0015, + 0x080c, 0x9a64, 0x0118, 0x6974, 0xc1dc, 0x6976, 0x0078, 0xd1d4, + 0x0118, 0x687b, 0x0007, 0x0050, 0x687b, 0x0000, 0x687c, 0xd0ac, + 0x0128, 0x6834, 0x6938, 0x9115, 0x190c, 0x8dfb, 0x6974, 0x0016, + 0x080c, 0x4ed6, 0x001e, 0xd1e4, 0x1120, 0x080c, 0x7f1e, 0x00de, + 0x0005, 0x080c, 0x987a, 0x0cd8, 0x0005, 0x080c, 0x6c56, 0x0010, + 0x080c, 0x6cf2, 0x080c, 0x95d2, 0x01c0, 0x00d6, 0x6114, 0x2168, + 0x6867, 0x0103, 0x2009, 0x110c, 0x210c, 0xd18c, 0x11c0, 0xd184, + 0x1198, 0x6108, 0x697a, 0x918e, 0x0029, 0x1110, 0x080c, 0xad5f, + 0x6877, 0x0000, 0x080c, 0x50a5, 0x00de, 0x080c, 0x7f1e, 0x080c, + 0x6d42, 0x080c, 0x6e10, 0x0005, 0x687b, 0x0004, 0x0c88, 0x687b, + 0x0004, 0x0c70, 0x9182, 0x0040, 0x0002, 0x9020, 0x9020, 0x9020, + 0x9020, 0x9020, 0x9022, 0x9020, 0x9025, 0x9020, 0x9020, 0x9020, + 0x9020, 0x9020, 0x9020, 0x9020, 0x9020, 0x9020, 0x9020, 0x9020, + 0x080c, 0x0cf1, 0x080c, 0x7f1e, 0x0005, 0x0006, 0x0026, 0x9016, + 0x080c, 0x119a, 0x002e, 0x000e, 0x0005, 0x9182, 0x0085, 0x0002, + 0x903d, 0x903b, 0x903b, 0x9049, 0x903b, 0x903b, 0x903b, 0x903b, + 0x903b, 0x903b, 0x903b, 0x080c, 0x0cf1, 0x6003, 0x0001, 0x6106, + 0x080c, 0x6886, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d42, 0x012e, + 0x0005, 0x0026, 0x0056, 0x00d6, 0x00e6, 0x2071, 0x0260, 0x7224, + 0x6216, 0x7220, 0x080c, 0x95c2, 0x01a0, 0x2268, 0x6800, 0x9086, + 0x0000, 0x0178, 0x6010, 0x6d10, 0x952e, 0x1158, 0x00c6, 0x2d60, + 0x080c, 0x9297, 0x00ce, 0x0128, 0x6803, 0x0002, 0x6007, 0x0086, + 0x0010, 0x6007, 0x0087, 0x6003, 0x0001, 0x080c, 0x6886, 0x080c, + 0x6d42, 0x9280, 0x0004, 0x2004, 0xd0bc, 0x0150, 0x6824, 0xd0ec, + 0x0138, 0x00c6, 0x2260, 0x6043, 0x0000, 0x080c, 0x98aa, 0x00ce, + 0x00ee, 0x00de, 0x005e, 0x002e, 0x0005, 0x9186, 0x0013, 0x1160, + 0x6004, 0x908a, 0x0085, 0x0a0c, 0x0cf1, 0x908a, 0x0090, 0x1a0c, + 0x0cf1, 0x9082, 0x0085, 0x0072, 0x9186, 0x0027, 0x0120, 0x9186, + 0x0014, 0x190c, 0x0cf1, 0x080c, 0x6c56, 0x080c, 0x97a3, 0x080c, + 0x6d42, 0x0005, 0x90ad, 0x90af, 0x90af, 0x90ad, 0x90ad, 0x90ad, + 0x90ad, 0x90ad, 0x90ad, 0x90ad, 0x90ad, 0x080c, 0x0cf1, 0x080c, + 0x6c56, 0x080c, 0x97a3, 0x080c, 0x6d42, 0x0005, 0x9186, 0x0013, + 0x1128, 0x6004, 0x9082, 0x0085, 0x2008, 0x04a8, 0x9186, 0x0027, + 0x11e8, 0x080c, 0x6c56, 0x080c, 0x25ad, 0x00d6, 0x6014, 0x2068, + 0x080c, 0x95d2, 0x0150, 0x6867, 0x0103, 0x6877, 0x0000, 0x687b, + 0x0029, 0x080c, 0x50a5, 0x080c, 0x9797, 0x00de, 0x080c, 0x7f1e, + 0x080c, 0x6d42, 0x0005, 0x080c, 0x7f68, 0x0ce0, 0x9186, 0x0014, + 0x1dd0, 0x080c, 0x6c56, 0x00d6, 0x6014, 0x2068, 0x080c, 0x95d2, + 0x0d60, 0x6867, 0x0103, 0x6877, 0x0000, 0x687b, 0x0006, 0x6880, + 0xc0ec, 0x6882, 0x08f0, 0x0002, 0x9101, 0x90ff, 0x90ff, 0x90ff, + 0x90ff, 0x90ff, 0x9119, 0x90ff, 0x90ff, 0x90ff, 0x90ff, 0x080c, + 0x0cf1, 0x080c, 0x6c56, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, + 0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x12a6, 0x0010, + 0x2001, 0x12a7, 0x2004, 0x601a, 0x6003, 0x000c, 0x080c, 0x6d42, + 0x0005, 0x080c, 0x6c56, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, + 0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x12a6, 0x0010, + 0x2001, 0x12a7, 0x2004, 0x601a, 0x6003, 0x000e, 0x080c, 0x6d42, + 0x0005, 0x9182, 0x0090, 0x1220, 0x9182, 0x0085, 0x0208, 0x001a, + 0x080c, 0x7f68, 0x0005, 0x9146, 0x9146, 0x9146, 0x9146, 0x9148, + 0x919b, 0x9146, 0x9146, 0x9146, 0x9146, 0x9146, 0x080c, 0x0cf1, + 0x00d6, 0x6010, 0x2004, 0xd0bc, 0x0168, 0x6034, 0x908c, 0xff00, + 0x810f, 0x9186, 0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x00de, + 0x0804, 0x91ac, 0x080c, 0x9797, 0x080c, 0x95d2, 0x01c8, 0x6014, + 0x2068, 0x6867, 0x0103, 0x6880, 0xd0b4, 0x0128, 0x687b, 0x0006, + 0xc0ec, 0x6882, 0x0048, 0xd0bc, 0x0118, 0x687b, 0x0002, 0x0020, + 0x687b, 0x0005, 0x080c, 0x9849, 0x6877, 0x0000, 0x080c, 0x50a5, + 0x2c68, 0x080c, 0x7ec8, 0x01d0, 0x6003, 0x0001, 0x6007, 0x001e, + 0x600b, 0xffff, 0x2009, 0x026e, 0x210c, 0x613a, 0x2009, 0x026f, + 0x210c, 0x613e, 0x6910, 0x6112, 0x080c, 0x99cc, 0x6954, 0x6156, + 0x6023, 0x0001, 0x080c, 0x6886, 0x080c, 0x6d42, 0x2d60, 0x080c, + 0x7f1e, 0x00de, 0x0005, 0x6010, 0x2004, 0xd0bc, 0x0598, 0x6034, + 0x908c, 0xff00, 0x810f, 0x9186, 0x0035, 0x0130, 0x9186, 0x001e, + 0x0118, 0x9186, 0x0039, 0x1530, 0x00d6, 0x2c68, 0x080c, 0x9ac5, + 0x1904, 0x91f1, 0x080c, 0x7ec8, 0x01d8, 0x6106, 0x6003, 0x0001, + 0x6023, 0x0001, 0x6910, 0x6112, 0x692c, 0x612e, 0x6930, 0x6132, + 0x6934, 0x918c, 0x00ff, 0x6136, 0x6938, 0x613a, 0x693c, 0x613e, + 0x6954, 0x6156, 0x080c, 0x99cc, 0x080c, 0x6886, 0x080c, 0x6d42, + 0x2d60, 0x00f8, 0x00d6, 0x6014, 0x2068, 0x080c, 0x95d2, 0x01c8, + 0x6867, 0x0103, 0x6880, 0xd0b4, 0x0128, 0xc0ec, 0x6882, 0x687b, + 0x0006, 0x0048, 0xd0bc, 0x0118, 0x687b, 0x0002, 0x0020, 0x687b, + 0x0005, 0x080c, 0x9849, 0x6877, 0x0000, 0x080c, 0x50a5, 0x080c, + 0x9797, 0x00de, 0x080c, 0x7f1e, 0x0005, 0x0016, 0x00d6, 0x6014, + 0x2068, 0x080c, 0x95d2, 0x0140, 0x6867, 0x0103, 0x687b, 0x0028, + 0x6877, 0x0000, 0x080c, 0x50a5, 0x00de, 0x001e, 0x9186, 0x0013, + 0x0148, 0x9186, 0x0014, 0x0130, 0x9186, 0x0027, 0x0118, 0x080c, + 0x7f68, 0x0030, 0x080c, 0x6c56, 0x080c, 0x97a3, 0x080c, 0x6d42, + 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6, 0x2029, 0x0001, 0x9182, + 0x0101, 0x1208, 0x0010, 0x2009, 0x0100, 0x2130, 0x8304, 0x9098, + 0x0018, 0x2009, 0x0020, 0x9f90, 0x0029, 0x080c, 0x927a, 0x96b2, + 0x0020, 0x7804, 0x906d, 0x0110, 0x080c, 0x0e06, 0x080c, 0x0ddf, + 0x0520, 0x8528, 0x6867, 0x0110, 0x686b, 0x0000, 0x2d20, 0x7c06, + 0x968a, 0x003d, 0x1228, 0x2608, 0x9d90, 0x001b, 0x0499, 0x00a8, + 0x96b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0x9d90, 0x001b, 0x0451, + 0x0c28, 0x2079, 0x0200, 0x7817, 0x0000, 0x00fe, 0x852f, 0x95ad, + 0x0003, 0x7d66, 0x95ac, 0x0000, 0x0048, 0x2079, 0x0200, 0x7817, + 0x0000, 0x00fe, 0x852f, 0x95ad, 0x0003, 0x7d66, 0x00de, 0x006e, + 0x005e, 0x0005, 0x00f6, 0x8dff, 0x0158, 0x6804, 0x907d, 0x0130, + 0x6807, 0x0000, 0x080c, 0x50a5, 0x2f68, 0x0cb8, 0x080c, 0x50a5, + 0x00fe, 0x0005, 0x00f6, 0x0156, 0x2079, 0x0200, 0x9184, 0x0001, + 0x0108, 0x8108, 0x810c, 0x21a8, 0x2300, 0x9e00, 0x2004, 0x8007, + 0x2012, 0x8318, 0x9386, 0x0020, 0x1120, 0x2018, 0x7814, 0x8000, + 0x7816, 0x8210, 0x1f04, 0x9284, 0x015e, 0x00fe, 0x0005, 0x0066, + 0x0126, 0x2091, 0x8000, 0x2031, 0x0001, 0x6020, 0x9084, 0x000f, + 0x0083, 0x012e, 0x006e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0066, + 0x2031, 0x0000, 0x6020, 0x9084, 0x000f, 0x001b, 0x006e, 0x012e, + 0x0005, 0x92d1, 0x92d1, 0x92cc, 0x92f3, 0x92bf, 0x92cc, 0x92f3, + 0x92cc, 0x92bf, 0x92bf, 0x92cc, 0x92cc, 0x92cc, 0x92bf, 0x080c, + 0x0cf1, 0x0036, 0x2019, 0x0010, 0x080c, 0xa6bc, 0x6023, 0x0006, + 0x6003, 0x0007, 0x003e, 0x0005, 0x9006, 0x0005, 0x9085, 0x0001, + 0x0005, 0x00d6, 0x86ff, 0x11d8, 0x6014, 0x2068, 0x080c, 0x95d2, + 0x01c0, 0x6864, 0x9086, 0x0139, 0x1128, 0x687b, 0x0005, 0x6883, + 0x0000, 0x0028, 0x900e, 0x2001, 0x0005, 0x080c, 0x52a0, 0x080c, + 0x9849, 0x080c, 0x50a5, 0x080c, 0x7f1e, 0x9085, 0x0001, 0x00de, + 0x0005, 0x9006, 0x0ce0, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0cf1, + 0x000b, 0x0005, 0x930a, 0x932b, 0x930c, 0x934a, 0x9328, 0x930a, + 0x92cc, 0x92d1, 0x92d1, 0x92cc, 0x92cc, 0x92cc, 0x92cc, 0x92cc, + 0x92cc, 0x92cc, 0x080c, 0x0cf1, 0x86ff, 0x11b8, 0x6020, 0x9086, + 0x0006, 0x0198, 0x00d6, 0x6014, 0x2068, 0x080c, 0x95d2, 0x0110, + 0x080c, 0x9849, 0x00de, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, + 0x0002, 0x080c, 0x6886, 0x080c, 0x6d42, 0x9085, 0x0001, 0x0005, + 0x080c, 0x12c7, 0x0c08, 0x00e6, 0x2071, 0x12dc, 0x7024, 0x9c06, + 0x1110, 0x080c, 0x78b3, 0x6020, 0x9084, 0x000f, 0x9086, 0x0006, + 0x1150, 0x0086, 0x0096, 0x2049, 0x0001, 0x2c40, 0x080c, 0x7a48, + 0x009e, 0x008e, 0x0010, 0x080c, 0x77d3, 0x00ee, 0x1928, 0x080c, + 0x92cc, 0x0005, 0x0036, 0x00e6, 0x2071, 0x12dc, 0x703c, 0x9c06, + 0x1140, 0x2019, 0x0000, 0x080c, 0x7936, 0x00ee, 0x003e, 0x0804, + 0x930c, 0x080c, 0x7b66, 0x00ee, 0x003e, 0x1904, 0x930c, 0x080c, + 0x92cc, 0x0005, 0x00c6, 0x6020, 0x9084, 0x000f, 0x0013, 0x00ce, + 0x0005, 0x937e, 0x9402, 0x9530, 0x9389, 0x97a3, 0x937e, 0xa6ae, + 0x7f1e, 0x9402, 0x9377, 0x959b, 0x9377, 0x9377, 0x9377, 0x080c, + 0x0cf1, 0x080c, 0x97cd, 0x1110, 0x080c, 0x8576, 0x0005, 0x080c, + 0x6c56, 0x080c, 0x6d42, 0x080c, 0x7f1e, 0x0005, 0x601b, 0x0001, + 0x0005, 0x6014, 0x9080, 0x0025, 0x2c02, 0x6000, 0x908a, 0x0016, + 0x1a0c, 0x0cf1, 0x000b, 0x0005, 0x93a4, 0x93a6, 0x93c6, 0x93d8, + 0x93e5, 0x93a4, 0x937e, 0x937e, 0x937e, 0x93d8, 0x93d8, 0x93a4, + 0x93a4, 0x93a4, 0x93a4, 0x93e2, 0x080c, 0x0cf1, 0x00e6, 0x6014, + 0x2070, 0x7080, 0xc0b5, 0x7082, 0x2071, 0x12dc, 0x7024, 0x9c06, + 0x0190, 0x080c, 0x77d3, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, + 0x0002, 0x2001, 0x12a7, 0x2004, 0x601a, 0x080c, 0x6886, 0x080c, + 0x6d42, 0x00ee, 0x0005, 0x601b, 0x0001, 0x0cd8, 0x00d6, 0x6014, + 0x2068, 0x6880, 0xc0b5, 0x6882, 0x00de, 0x6007, 0x0085, 0x6003, + 0x000b, 0x6023, 0x0002, 0x080c, 0x6886, 0x080c, 0x6d42, 0x0005, + 0x00d6, 0x601b, 0x0001, 0x6014, 0x2068, 0x6880, 0xc0b5, 0x6882, + 0x00de, 0x0005, 0x080c, 0x7f1e, 0x0005, 0x6014, 0x9005, 0x01b8, + 0x9088, 0x001f, 0x210c, 0xd1e4, 0x0190, 0x9080, 0x0021, 0x2004, + 0x601a, 0x2001, 0x0037, 0x2c08, 0x080c, 0x113b, 0x6000, 0x9086, + 0x0004, 0x1120, 0x2009, 0x0048, 0x080c, 0x7f4e, 0x0005, 0x080c, + 0x12c7, 0x0820, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0cf1, 0x000b, + 0x0005, 0x9419, 0x9386, 0x941b, 0x9419, 0x941b, 0x941b, 0x937f, + 0x9419, 0x9379, 0x9379, 0x9419, 0x9419, 0x9419, 0x9419, 0x9419, + 0x9419, 0x080c, 0x0cf1, 0x6010, 0x00d6, 0x2068, 0x6804, 0x9084, + 0x00ff, 0x00de, 0x908a, 0x000c, 0x1a0c, 0x0cf1, 0x000b, 0x0005, + 0x9434, 0x94d6, 0x9436, 0x9470, 0x9436, 0x9470, 0x9436, 0x9440, + 0x9434, 0x9470, 0x9434, 0x945c, 0x080c, 0x0cf1, 0x6004, 0x908e, + 0x0016, 0x0588, 0x908e, 0x0004, 0x0570, 0x908e, 0x0002, 0x0558, + 0x6004, 0x080c, 0x97cd, 0x0904, 0x94ef, 0x908e, 0x0021, 0x0904, + 0x94f3, 0x908e, 0x0022, 0x0904, 0x94ef, 0x908e, 0x003d, 0x0904, + 0x94f3, 0x908e, 0x0039, 0x0904, 0x94f7, 0x908e, 0x0035, 0x0904, + 0x94f7, 0x908e, 0x001e, 0x0188, 0x908e, 0x0001, 0x1150, 0x6010, + 0x00d6, 0x2068, 0x6804, 0x9084, 0x00ff, 0x00de, 0x9086, 0x0006, + 0x0110, 0x080c, 0x25ad, 0x080c, 0x8576, 0x080c, 0x97a3, 0x0005, + 0x00c6, 0x00d6, 0x6104, 0x9186, 0x0016, 0x0904, 0x94c7, 0x9186, + 0x0002, 0x1518, 0x6010, 0x2068, 0x2001, 0x1133, 0x2004, 0xd0ac, + 0x1904, 0x9519, 0x68a0, 0xd0bc, 0x1904, 0x9519, 0x6840, 0x9084, + 0x00ff, 0x9005, 0x0190, 0x8001, 0x6842, 0x6017, 0x0000, 0x6023, + 0x0007, 0x601b, 0x0398, 0x6043, 0x0000, 0x080c, 0x7ec8, 0x0128, + 0x2d00, 0x6012, 0x6023, 0x0001, 0x0450, 0x00de, 0x00ce, 0x6004, + 0x908e, 0x0002, 0x11a8, 0x6010, 0x9080, 0x0028, 0x2004, 0x9086, + 0x007e, 0x1170, 0x2009, 0x1133, 0x2104, 0xc085, 0x200a, 0x00e6, + 0x2071, 0x1100, 0x080c, 0x46bb, 0x00ee, 0x080c, 0x8576, 0x0020, + 0x080c, 0x8576, 0x080c, 0x25ad, 0x00e6, 0x0126, 0x2091, 0x8000, + 0x080c, 0x25d1, 0x012e, 0x00ee, 0x080c, 0x97a3, 0x0005, 0x2001, + 0x0002, 0x080c, 0x4ab3, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, + 0x68ce, 0x080c, 0x6d42, 0x00de, 0x00ce, 0x0c80, 0x00c6, 0x00d6, + 0x6104, 0x9186, 0x0016, 0x0d58, 0x6010, 0x2068, 0x6840, 0x9084, + 0x00ff, 0x9005, 0x0904, 0x949d, 0x8001, 0x6842, 0x6003, 0x0001, + 0x080c, 0x68ce, 0x080c, 0x6d42, 0x00de, 0x00ce, 0x08b8, 0x080c, + 0x8576, 0x0804, 0x946d, 0x080c, 0x85a4, 0x0804, 0x946d, 0x00d6, + 0x2c68, 0x6104, 0x080c, 0x9ac5, 0x00de, 0x0118, 0x080c, 0x7f1e, + 0x00b8, 0x6004, 0x8007, 0x6134, 0x918c, 0x00ff, 0x9105, 0x6036, + 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x603c, 0x600a, + 0x2001, 0x12a7, 0x2004, 0x601a, 0x080c, 0x6886, 0x080c, 0x6d42, + 0x0005, 0x00de, 0x00ce, 0x080c, 0x8576, 0x080c, 0x25ad, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x080c, 0x25d1, 0x6017, 0x0000, 0x6023, + 0x0007, 0x601b, 0x0398, 0x6043, 0x0000, 0x012e, 0x00ee, 0x0005, + 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0cf1, 0x000b, 0x0005, 0x9547, + 0x9547, 0x9547, 0x9547, 0x9547, 0x9547, 0x9547, 0x9547, 0x9547, + 0x937e, 0x9547, 0x9386, 0x9549, 0x9386, 0x9556, 0x9547, 0x080c, + 0x0cf1, 0x6004, 0x9086, 0x008b, 0x0148, 0x6007, 0x008b, 0x6003, + 0x000d, 0x080c, 0x6886, 0x080c, 0x6d42, 0x0005, 0x080c, 0x9797, + 0x080c, 0x95d2, 0x0580, 0x080c, 0x25ad, 0x00d6, 0x080c, 0x95d2, + 0x0168, 0x6014, 0x2068, 0x6867, 0x0103, 0x687b, 0x0006, 0x6877, + 0x0000, 0x6880, 0xc0ed, 0x6882, 0x080c, 0x50a5, 0x2c68, 0x080c, + 0x7ec8, 0x0150, 0x6810, 0x6012, 0x080c, 0x99cc, 0x00c6, 0x2d60, + 0x080c, 0x97a3, 0x00ce, 0x0008, 0x2d60, 0x00de, 0x6017, 0x0000, + 0x6023, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x68ce, + 0x080c, 0x6d42, 0x0078, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, + 0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x080c, 0x25ad, 0x08b0, + 0x080c, 0x97a3, 0x0005, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0cf1, + 0x000b, 0x0005, 0x95b2, 0x95b2, 0x95b2, 0x95b4, 0x95b5, 0x95b2, + 0x95b2, 0x95b2, 0x95b2, 0x95b2, 0x95b2, 0x95b2, 0x95b2, 0x95b2, + 0x95b2, 0x95b2, 0x080c, 0x0cf1, 0x0005, 0x080c, 0x7b66, 0x190c, + 0x0cf1, 0x6114, 0x2168, 0x687b, 0x0006, 0x080c, 0x50a5, 0x080c, + 0x7f1e, 0x0005, 0x9284, 0x0007, 0x1158, 0x9282, 0x15c0, 0x0240, + 0x2001, 0x1116, 0x2004, 0x9202, 0x1218, 0x9085, 0x0001, 0x0005, + 0x9006, 0x0ce8, 0x0026, 0x6214, 0x9294, 0xf000, 0x002e, 0x0005, + 0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, 0x2091, 0x8000, 0x2061, + 0x15c0, 0x2071, 0x1100, 0x7344, 0x7064, 0x9302, 0x12a8, 0x6020, + 0x9206, 0x1160, 0x080c, 0x9946, 0x0148, 0x080c, 0x97cd, 0x1110, + 0x080c, 0x8576, 0x00c6, 0x080c, 0x7f1e, 0x00ce, 0x9ce0, 0x0018, + 0x7058, 0x9c02, 0x1208, 0x0c38, 0x012e, 0x000e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0x9188, 0x1000, 0x210c, + 0x81ff, 0x0170, 0x2061, 0x15c0, 0x2071, 0x1100, 0x0016, 0x080c, + 0x7ec8, 0x001e, 0x0138, 0x6112, 0x080c, 0x25ad, 0x080c, 0x7f1e, + 0x9006, 0x0010, 0x9085, 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005, + 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x7ec8, + 0x005e, 0x0180, 0x6616, 0x6512, 0x080c, 0x99cc, 0x6023, 0x0003, + 0x2009, 0x004b, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x012e, 0x005e, + 0x00ce, 0x0005, 0x9006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, + 0x8000, 0x62a0, 0x00c6, 0x080c, 0x7ec8, 0x005e, 0x01f8, 0x6017, + 0x0000, 0x6512, 0x080c, 0x99cc, 0x6023, 0x0003, 0x00c6, 0x2560, + 0x00ce, 0x080c, 0x69ca, 0x0076, 0x2039, 0x0000, 0x080c, 0x68fe, + 0x2c08, 0x080c, 0xa85f, 0x007e, 0x2009, 0x004c, 0x080c, 0x7f4e, + 0x9085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, 0x9006, 0x0cd0, + 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, 0x7ec8, 0x2c78, 0x00ce, + 0x0180, 0x7e16, 0x2c00, 0x7812, 0x7823, 0x0003, 0x2021, 0x0005, + 0x080c, 0x96bd, 0x2f60, 0x2009, 0x004d, 0x080c, 0x7f4e, 0x9085, + 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6, 0x0046, + 0x00c6, 0x080c, 0x7ec8, 0x2c78, 0x00ce, 0x0178, 0x7e16, 0x2c00, + 0x7812, 0x7823, 0x0003, 0x2021, 0x0005, 0x0439, 0x2f60, 0x2009, + 0x004e, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x004e, 0x00ce, 0x00fe, + 0x0005, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, 0x7ec8, 0x2c78, + 0x00ce, 0x0178, 0x7e16, 0x2c00, 0x7812, 0x7823, 0x0003, 0x2021, + 0x0004, 0x0059, 0x2f60, 0x2009, 0x0052, 0x080c, 0x7f4e, 0x9085, + 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x0096, 0x0076, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4c77, 0x0158, 0x2001, 0x96c2, 0x0006, + 0x900e, 0x2400, 0x080c, 0x52a0, 0x080c, 0x50a5, 0x000e, 0x0807, + 0x2418, 0x080c, 0x6bf8, 0x62a0, 0x0086, 0x2041, 0x0001, 0x2039, + 0x0001, 0x2608, 0x080c, 0x69e3, 0x008e, 0x080c, 0x68fe, 0x2f08, + 0x2648, 0x080c, 0xa85f, 0x613c, 0x81ff, 0x090c, 0x6a8c, 0x012e, + 0x007e, 0x009e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, + 0x080c, 0x7ec8, 0x001e, 0x0188, 0x660a, 0x6112, 0x080c, 0x99cc, + 0x6023, 0x0001, 0x2d00, 0x6016, 0x2009, 0x001f, 0x080c, 0x7f4e, + 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x7ec8, 0x001e, 0x01b0, + 0x660a, 0x6112, 0x080c, 0x99cc, 0x6023, 0x0008, 0x2d00, 0x6016, + 0x00f6, 0x2c78, 0x080c, 0x119d, 0x00fe, 0x2009, 0x0021, 0x080c, + 0x7f4e, 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x7ec8, 0x001e, + 0x0188, 0x660a, 0x6112, 0x080c, 0x99cc, 0x6023, 0x0001, 0x2d00, + 0x6016, 0x2009, 0x003d, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x012e, + 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x00c6, 0x080c, 0x984d, 0x001e, 0x0180, 0x6112, 0x080c, 0x99cc, + 0x6023, 0x0001, 0x2d00, 0x6016, 0x2009, 0x0000, 0x080c, 0x7f4e, + 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x7ec8, 0x001e, 0x0188, + 0x660a, 0x6112, 0x080c, 0x99cc, 0x6023, 0x0001, 0x2d00, 0x6016, + 0x2009, 0x0044, 0x080c, 0x7f4e, 0x9085, 0x0001, 0x012e, 0x00ce, + 0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, + 0x080c, 0x7ec8, 0x001e, 0x0188, 0x660a, 0x6112, 0x080c, 0x99cc, + 0x6023, 0x0001, 0x2d00, 0x6016, 0x2009, 0x0049, 0x080c, 0x7f4e, + 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x0026, + 0x00d6, 0x6210, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, + 0x00de, 0x002e, 0x0005, 0x0006, 0x6000, 0x9086, 0x0000, 0x0190, + 0x6017, 0x0000, 0x6023, 0x0007, 0x2001, 0x12a6, 0x2004, 0x0006, + 0x9082, 0x0051, 0x000e, 0x0208, 0x8004, 0x601a, 0x080c, 0xad19, + 0x6043, 0x0000, 0x000e, 0x0005, 0x0006, 0x0016, 0x6004, 0x908e, + 0x0002, 0x0140, 0x908e, 0x0003, 0x0128, 0x908e, 0x0004, 0x0110, + 0x9085, 0x0001, 0x001e, 0x000e, 0x0005, 0x0006, 0x00d6, 0x6014, + 0x906d, 0x0148, 0x6864, 0x9086, 0x0139, 0x0138, 0x6868, 0xd0fc, + 0x0110, 0x9006, 0x0010, 0x9085, 0x0001, 0x00de, 0x000e, 0x0005, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x7ec8, 0x001e, + 0x0190, 0x6112, 0x080c, 0x99cc, 0x6023, 0x0001, 0x2d00, 0x6016, + 0x080c, 0x25ad, 0x2009, 0x0028, 0x080c, 0x7f4e, 0x9085, 0x0001, + 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x9186, 0x0015, 0x1188, + 0x2011, 0x1120, 0x2204, 0x9086, 0x0074, 0x1158, 0x080c, 0x88ee, + 0x6003, 0x0001, 0x6007, 0x0029, 0x080c, 0x68ce, 0x080c, 0x6d42, + 0x0020, 0x080c, 0x8576, 0x080c, 0x7f1e, 0x0005, 0x9186, 0x0016, + 0x1128, 0x2001, 0x0004, 0x080c, 0x4ab3, 0x00e8, 0x9186, 0x0015, + 0x11e8, 0x2011, 0x1120, 0x2204, 0x9086, 0x0014, 0x11b8, 0x6010, + 0x00d6, 0x2068, 0x080c, 0x4bf5, 0x00de, 0x080c, 0x89bf, 0x1170, + 0x6010, 0x00d6, 0x2068, 0x6890, 0x00de, 0x9005, 0x0138, 0x2001, + 0x0006, 0x080c, 0x4ab3, 0x080c, 0x80a0, 0x0020, 0x080c, 0x8576, + 0x080c, 0x7f1e, 0x0005, 0x6878, 0x9086, 0x0005, 0x1108, 0x0009, + 0x0005, 0x6880, 0xc0ad, 0x6882, 0x0005, 0x00e6, 0x0126, 0x2071, + 0x1100, 0x2091, 0x8000, 0x7544, 0x9582, 0x0001, 0x0608, 0x7048, + 0x2060, 0x6000, 0x9086, 0x0000, 0x0148, 0x9ce0, 0x0018, 0x7058, + 0x9c02, 0x1208, 0x0cb0, 0x2061, 0x15c0, 0x0c98, 0x6003, 0x0008, + 0x8529, 0x7546, 0x9ca8, 0x0018, 0x7058, 0x9502, 0x1230, 0x754a, + 0x9085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704b, 0x15c0, 0x0cc0, + 0x9006, 0x0cc0, 0x6043, 0x0000, 0x6017, 0x0000, 0x6003, 0x0001, + 0x6007, 0x0050, 0x080c, 0x6886, 0x080c, 0x6d42, 0x0005, 0x00c6, + 0x6010, 0x2004, 0xd0bc, 0x0120, 0x6020, 0x9084, 0x000f, 0x0013, + 0x00ce, 0x0005, 0x937e, 0x98a2, 0x98a5, 0x98a8, 0xab09, 0xab24, + 0xab27, 0x937e, 0x937e, 0x937e, 0x937e, 0x937e, 0x937e, 0x937e, + 0x080c, 0x0cf1, 0xa001, 0xa001, 0x0005, 0xa001, 0xa001, 0x0005, + 0x0009, 0x0005, 0x6010, 0x2004, 0xd0bc, 0x0550, 0x00f6, 0x2c78, + 0x080c, 0x7ec8, 0x1128, 0x2001, 0x12a8, 0x2004, 0x7842, 0x00f8, + 0x7810, 0x6012, 0x080c, 0x99cc, 0x7820, 0x9086, 0x0003, 0x0128, + 0x7808, 0x603a, 0x2f00, 0x603e, 0x0020, 0x7808, 0x603e, 0x2f00, + 0x603a, 0x602e, 0x6023, 0x0001, 0x6007, 0x0035, 0x6003, 0x0001, + 0x7954, 0x6156, 0x080c, 0x6886, 0x080c, 0x6d42, 0x2f60, 0x00fe, + 0x0005, 0x0016, 0x00f6, 0x6830, 0x6036, 0x908e, 0x0001, 0x0148, + 0x6803, 0x0002, 0x9086, 0x0005, 0x0168, 0x9006, 0x602e, 0x6032, + 0x00c8, 0x681c, 0xc085, 0x681e, 0x6803, 0x0004, 0x6824, 0xc0f4, + 0xc0d5, 0x6826, 0x6814, 0x2078, 0x78ac, 0x6938, 0x9102, 0x78b0, + 0x693c, 0x9103, 0x1e50, 0x683c, 0x602e, 0x6838, 0x9084, 0xfffc, + 0x683a, 0x6032, 0x2d00, 0x603a, 0x6808, 0x603e, 0x6910, 0x6112, + 0x6954, 0x6156, 0x6023, 0x0001, 0x6007, 0x0039, 0x6003, 0x0001, + 0x080c, 0x6886, 0x080c, 0x6d42, 0x00fe, 0x001e, 0x0005, 0x6024, + 0xd0d4, 0x0510, 0xd0f4, 0x11f8, 0x6038, 0x940a, 0x603c, 0x9303, + 0x0230, 0x9105, 0x0120, 0x6024, 0xc0d4, 0xc0f5, 0x0098, 0x643a, + 0x633e, 0x6c3e, 0x6b42, 0x0046, 0x0036, 0x2400, 0x6cac, 0x9402, + 0x6836, 0x2300, 0x6bb0, 0x9303, 0x683a, 0x003e, 0x004e, 0x6024, + 0xc0d4, 0x0000, 0x6026, 0x0005, 0xd0f4, 0x1138, 0x683c, 0x603a, + 0x6840, 0x603e, 0x6024, 0xc0f5, 0x6026, 0x0005, 0x0006, 0x0016, + 0x6004, 0x908e, 0x0034, 0x01b8, 0x908e, 0x0035, 0x01a0, 0x908e, + 0x0036, 0x0188, 0x908e, 0x0037, 0x0170, 0x908e, 0x0038, 0x0158, + 0x908e, 0x0039, 0x0140, 0x908e, 0x003a, 0x0128, 0x908e, 0x003b, + 0x0110, 0x9085, 0x0001, 0x001e, 0x000e, 0x0005, 0x0006, 0x0016, + 0x0026, 0x0036, 0x00e6, 0x2001, 0x12a2, 0x200c, 0x8000, 0x2014, + 0x2001, 0x0032, 0x080c, 0x66ff, 0x2001, 0x12a6, 0x82ff, 0x1110, + 0x2011, 0x0002, 0x2202, 0x2001, 0x12a4, 0x200c, 0x8000, 0x2014, + 0x2071, 0x127f, 0x711a, 0x721e, 0x2001, 0x0064, 0x080c, 0x66ff, + 0x2001, 0x12a7, 0x82ff, 0x1110, 0x2011, 0x0002, 0x2202, 0x2001, + 0x12a8, 0x9288, 0x000a, 0x2102, 0x2001, 0x1340, 0x2102, 0x2001, + 0x0032, 0x080c, 0x113b, 0x080c, 0x4df8, 0x00ee, 0x003e, 0x002e, + 0x001e, 0x000e, 0x0005, 0x0006, 0x0016, 0x00e6, 0x2001, 0x12a6, + 0x2003, 0x0028, 0x2001, 0x12a7, 0x2003, 0x0014, 0x2071, 0x127f, + 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001, 0x12a8, 0x2009, 0x001e, + 0x2102, 0x2001, 0x1340, 0x2102, 0x2001, 0x0032, 0x080c, 0x113b, + 0x00ee, 0x001e, 0x000e, 0x0005, 0x00d6, 0x6058, 0x906d, 0x0110, + 0x080c, 0x0df6, 0x00de, 0x0005, 0x0005, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x00c6, 0x080c, 0x7ec8, 0x001e, 0x0178, 0x6112, 0x0ca1, + 0x6023, 0x0001, 0x2d00, 0x6016, 0x2009, 0x0033, 0x080c, 0x7f4e, + 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00d6, + 0x00e6, 0x00f6, 0x2071, 0x1100, 0x9186, 0x0015, 0x1500, 0x7080, + 0x9086, 0x0018, 0x11e0, 0x6014, 0x2068, 0x6a3c, 0xd2e4, 0x1160, + 0x2c78, 0x080c, 0x6f1c, 0x01d8, 0x706c, 0x6a50, 0x9206, 0x1160, + 0x7070, 0x6a54, 0x9206, 0x1140, 0x6210, 0x9290, 0x0028, 0x2214, + 0x2009, 0x0000, 0x080c, 0x25f0, 0x080c, 0x80a0, 0x0020, 0x080c, + 0x8576, 0x080c, 0x7f1e, 0x00fe, 0x00ee, 0x00de, 0x0005, 0x7050, + 0x6a54, 0x9206, 0x0d48, 0x0c80, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x00c6, 0x080c, 0x7ec8, 0x001e, 0x0180, 0x6112, 0x080c, 0x99cc, + 0x6023, 0x0001, 0x2d00, 0x6016, 0x2009, 0x0043, 0x080c, 0x7f4e, + 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00d6, + 0x00e6, 0x00f6, 0x2071, 0x1100, 0x9186, 0x0015, 0x11c0, 0x7080, + 0x9086, 0x0004, 0x11a0, 0x6014, 0x90e8, 0x001b, 0x2c78, 0x080c, + 0x6f1c, 0x01a8, 0x706c, 0x6a08, 0x9206, 0x1130, 0x7070, 0x6a0c, + 0x9206, 0x1110, 0x080c, 0x25ad, 0x080c, 0x80a0, 0x0020, 0x080c, + 0x8576, 0x080c, 0x7f1e, 0x00fe, 0x00ee, 0x00de, 0x0005, 0x7050, + 0x6a0c, 0x9206, 0x0d78, 0x0c80, 0x0016, 0x0026, 0x687c, 0xd0ac, + 0x0178, 0x6938, 0x6a34, 0x2100, 0x9205, 0x0150, 0x6890, 0x9106, + 0x1118, 0x688c, 0x9206, 0x0120, 0x6992, 0x6a8e, 0x9085, 0x0001, + 0x002e, 0x001e, 0x0005, 0x00d6, 0x0036, 0x6314, 0x2368, 0x687a, + 0x6982, 0x929e, 0x4000, 0x1560, 0x6310, 0x00c6, 0x2360, 0x2009, + 0x0000, 0x6868, 0xd0f4, 0x1140, 0x080c, 0x4d21, 0x1108, 0xc185, + 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x6a96, 0x699a, 0x20a9, 0x0004, + 0x20e1, 0x0001, 0x20e9, 0x0001, 0x9d80, 0x0031, 0x20a0, 0x9c80, + 0x0006, 0x2098, 0x080c, 0x4678, 0x20a9, 0x0004, 0x9d80, 0x0035, + 0x20a0, 0x9c80, 0x000a, 0x2098, 0x080c, 0x4678, 0x00ce, 0x0080, + 0x6a96, 0x3918, 0x9398, 0x0006, 0x231c, 0x689b, 0x0004, 0x6ba2, + 0x6310, 0x00c6, 0x2360, 0x6004, 0x00ce, 0x9084, 0x00ff, 0x689e, + 0x080c, 0x50a5, 0x003e, 0x00de, 0x0005, 0x00c6, 0x0026, 0x0016, + 0x9186, 0x0035, 0x0110, 0x6a38, 0x0008, 0x6a2c, 0x080c, 0x95c2, + 0x01f0, 0x2260, 0x6120, 0x9186, 0x0003, 0x0118, 0x9186, 0x0006, + 0x1190, 0x6838, 0x9206, 0x0140, 0x683c, 0x9206, 0x1160, 0x6108, + 0x6838, 0x9106, 0x1140, 0x0020, 0x6008, 0x693c, 0x9106, 0x1118, + 0x6010, 0x6910, 0x9106, 0x001e, 0x002e, 0x00ce, 0x0005, 0x9085, + 0x0001, 0x0cc8, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0cf1, + 0x0013, 0x006e, 0x0005, 0x9b0b, 0x9fed, 0xa14f, 0x9b0b, 0x9b0b, + 0x9b0b, 0x9b0b, 0x9b0b, 0x9b42, 0xa1cd, 0x9b0b, 0x9b0b, 0x9b0b, + 0x9b0b, 0x9b0b, 0x9b0b, 0x080c, 0x0cf1, 0x0066, 0x6000, 0x90b2, + 0x0016, 0x1a0c, 0x0cf1, 0x0013, 0x006e, 0x0005, 0x9b26, 0xa64b, + 0x9b26, 0x9b26, 0x9b26, 0x9b26, 0x9b26, 0x9b26, 0xa60b, 0xa69b, + 0x9b26, 0xac51, 0xac85, 0xac51, 0xac85, 0x9b26, 0x080c, 0x0cf1, + 0x6000, 0x9082, 0x0016, 0x1a0c, 0x0cf1, 0x6000, 0x000a, 0x0005, + 0x9b40, 0xa307, 0xa3dc, 0xa3fe, 0xa4a6, 0x9b40, 0xa57d, 0xa528, + 0xa1d9, 0xa5e1, 0xa5f6, 0x9b40, 0x9b40, 0x9b40, 0x9b40, 0x9b40, + 0x080c, 0x0cf1, 0x91b2, 0x004c, 0x1a0c, 0x0cf1, 0x2100, 0x91b2, + 0x0040, 0x1a04, 0x9f4e, 0x0002, 0x9b8c, 0x9d57, 0x9b8c, 0x9b8c, + 0x9b8c, 0x9d60, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, + 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, + 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8e, 0x9bea, 0x9bf9, 0x9c47, 0x9c65, + 0x9ce3, 0x9d42, 0x9b8c, 0x9b8c, 0x9d63, 0x9b8c, 0x9b8c, 0x9d78, + 0x9d85, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9b8c, 0x9dfd, 0x9b8c, + 0x9b8c, 0x9e0c, 0x9b8c, 0x9b8c, 0x9dd3, 0x9b8c, 0x9b8c, 0x9b8c, + 0x9e24, 0x9b8c, 0x9b8c, 0x9b8c, 0x9ea0, 0x9b8c, 0x9b8c, 0x9b8c, + 0x9b8c, 0x9b8c, 0x9b8c, 0x9f15, 0x080c, 0x0cf1, 0x080c, 0x4de0, + 0x1150, 0x2001, 0x1133, 0x2004, 0xd0cc, 0x1128, 0x9084, 0x0009, + 0x9086, 0x0008, 0x1140, 0x6007, 0x0009, 0x602f, 0x0009, 0x6017, + 0x0000, 0x0804, 0x9d50, 0x080c, 0x4dd0, 0x00e6, 0x00c6, 0x0036, + 0x0026, 0x0016, 0x6210, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, + 0x080c, 0x69ca, 0x0076, 0x2039, 0x0000, 0x080c, 0x68fe, 0x2c08, + 0x080c, 0xa85f, 0x007e, 0x001e, 0x2e60, 0x001e, 0x002e, 0x003e, + 0x00ce, 0x00ee, 0x6610, 0x00c6, 0x2660, 0x080c, 0x4b67, 0x00ce, + 0x96b0, 0x0001, 0x2634, 0x9684, 0x00ff, 0x9082, 0x0006, 0x0278, + 0x080c, 0xa7a3, 0x1904, 0x9c41, 0x080c, 0xa740, 0x1120, 0x6007, + 0x0008, 0x0804, 0x9d50, 0x6007, 0x0009, 0x0804, 0x9d50, 0x080c, + 0xa966, 0x0128, 0x080c, 0xa7a3, 0x0d78, 0x0804, 0x9c41, 0x6017, + 0x1900, 0x0c88, 0x080c, 0x26bc, 0x1904, 0x9f4b, 0x6106, 0x080c, + 0xa6fc, 0x6007, 0x0006, 0x0804, 0x9d50, 0x6007, 0x0007, 0x0804, + 0x9d50, 0x080c, 0xacbf, 0x1904, 0x9f4b, 0x080c, 0x26bc, 0x1904, + 0x9f4b, 0x00d6, 0x6610, 0x2668, 0x6e04, 0x9684, 0x00ff, 0x9082, + 0x0006, 0x1220, 0x2001, 0x0001, 0x080c, 0x4aa1, 0x96b4, 0xff00, + 0x8637, 0x9686, 0x0006, 0x0188, 0x9686, 0x0004, 0x0170, 0x6e04, + 0x96b4, 0x00ff, 0x9686, 0x0006, 0x0140, 0x9686, 0x0004, 0x0128, + 0x9686, 0x0005, 0x0110, 0x00de, 0x00e0, 0x080c, 0xa801, 0x11a0, + 0x9686, 0x0006, 0x1150, 0x0026, 0x6210, 0x9290, 0x0028, 0x2214, + 0x2009, 0x0000, 0x080c, 0x25f0, 0x002e, 0x080c, 0x4bf5, 0x6007, + 0x000a, 0x00de, 0x0804, 0x9d50, 0x6007, 0x000b, 0x00de, 0x0804, + 0x9d50, 0x080c, 0x25ad, 0x6007, 0x0001, 0x0804, 0x9d50, 0x080c, + 0xacbf, 0x1904, 0x9f4b, 0x080c, 0x26bc, 0x1904, 0x9f4b, 0x6610, + 0x00d6, 0x2668, 0x6e04, 0x00de, 0x9686, 0x0707, 0x0d50, 0x0026, + 0x6210, 0x9290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x25f0, + 0x002e, 0x6007, 0x000c, 0x0804, 0x9d50, 0x080c, 0x4de0, 0x1140, + 0x2001, 0x1133, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008, 0x1110, + 0x0804, 0x9b9b, 0x080c, 0x4dd0, 0x6610, 0x96b0, 0x0001, 0x2634, + 0x9684, 0x00ff, 0x9082, 0x0006, 0x06e8, 0x1138, 0x0026, 0x2001, + 0x0006, 0x080c, 0x4ae0, 0x002e, 0x0050, 0x96b4, 0xff00, 0x8637, + 0x9686, 0x0004, 0x0120, 0x9686, 0x0006, 0x1904, 0x9c41, 0x080c, + 0xa80e, 0x1120, 0x6007, 0x000e, 0x0804, 0x9d50, 0x0046, 0x6410, + 0x94a0, 0x0028, 0x2424, 0x94a4, 0x00ff, 0x8427, 0x0046, 0x080c, + 0x25ad, 0x004e, 0x0016, 0x9006, 0x2009, 0x1153, 0x210c, 0xd1a4, + 0x0158, 0x2009, 0x0029, 0x080c, 0xaaca, 0x6010, 0x00d6, 0x2068, + 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e, 0x004e, 0x6007, 0x0001, + 0x0804, 0x9d50, 0x2001, 0x0001, 0x080c, 0x4aa1, 0x0156, 0x0016, + 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0x1105, 0x2011, 0x0270, + 0x080c, 0x8a45, 0x003e, 0x002e, 0x001e, 0x015e, 0x9005, 0x0168, + 0x96b4, 0xff00, 0x8637, 0x9682, 0x0004, 0x0a04, 0x9c41, 0x9682, + 0x0007, 0x0a04, 0x9c8f, 0x0804, 0x9c41, 0x6017, 0x1900, 0x6007, + 0x0009, 0x0804, 0x9d50, 0x080c, 0x4de0, 0x1140, 0x2001, 0x1133, + 0x2004, 0x9084, 0x0009, 0x9086, 0x0008, 0x1110, 0x0804, 0x9b9b, + 0x080c, 0x4dd0, 0x6610, 0x96b0, 0x0001, 0x2634, 0x9684, 0x00ff, + 0x9082, 0x0006, 0x06b8, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0004, + 0x0120, 0x9686, 0x0006, 0x1904, 0x9c41, 0x080c, 0xa836, 0x1138, + 0x080c, 0xa740, 0x1120, 0x6007, 0x0010, 0x0804, 0x9d50, 0x0046, + 0x6410, 0x94a0, 0x0028, 0x2424, 0x94a4, 0x00ff, 0x8427, 0x0046, + 0x080c, 0x25ad, 0x004e, 0x0016, 0x9006, 0x2009, 0x1153, 0x210c, + 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, 0xaaca, 0x6010, 0x00d6, + 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e, 0x004e, 0x6007, + 0x0001, 0x00f0, 0x080c, 0xa966, 0x0140, 0x96b4, 0xff00, 0x8637, + 0x9686, 0x0006, 0x0950, 0x0804, 0x9c41, 0x6017, 0x1900, 0x6007, + 0x0009, 0x0070, 0x080c, 0x26bc, 0x1904, 0x9f4b, 0x080c, 0xacbf, + 0x1904, 0x9f4b, 0x080c, 0x9f86, 0x1904, 0x9c41, 0x6007, 0x0012, + 0x6003, 0x0001, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0005, 0x6007, + 0x0001, 0x6003, 0x0001, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0cb0, + 0x6007, 0x0005, 0x0c68, 0x080c, 0xacbf, 0x1904, 0x9f4b, 0x080c, + 0x26bc, 0x1904, 0x9f4b, 0x080c, 0x9f86, 0x1904, 0x9c41, 0x6007, + 0x0020, 0x6003, 0x0001, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0005, + 0x080c, 0x26bc, 0x1904, 0x9f4b, 0x6007, 0x0023, 0x6003, 0x0001, + 0x080c, 0x68ce, 0x080c, 0x6d42, 0x0005, 0x080c, 0xacbf, 0x1904, + 0x9f4b, 0x080c, 0x26bc, 0x1904, 0x9f4b, 0x080c, 0x9f86, 0x1904, + 0x9c41, 0x0016, 0x0026, 0x00e6, 0x2071, 0x0260, 0x7244, 0x9286, + 0xffff, 0x0180, 0x2c08, 0x080c, 0x95c2, 0x01b0, 0x2260, 0x7240, + 0x6008, 0x9206, 0x1188, 0x6010, 0x9190, 0x0004, 0x2214, 0x9206, + 0x01b8, 0x0050, 0x7240, 0x2c08, 0x9006, 0x080c, 0xaa9c, 0x1180, + 0x7244, 0x9286, 0xffff, 0x0190, 0x2160, 0x6007, 0x0026, 0x6017, + 0x1700, 0x7214, 0x9296, 0xffff, 0x1160, 0x6007, 0x0025, 0x0048, + 0x6020, 0x9086, 0x0007, 0x1d80, 0x080c, 0x7f1e, 0x2160, 0x6007, + 0x0025, 0x6003, 0x0001, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x00ee, + 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, 0x080c, 0x4aa1, 0x0156, + 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0x1105, 0x2011, + 0x0276, 0x080c, 0x8a45, 0x003e, 0x002e, 0x001e, 0x015e, 0x0120, + 0x6007, 0x0031, 0x0804, 0x9d50, 0x080c, 0x8752, 0x080c, 0x5745, + 0x1158, 0x0006, 0x0026, 0x0036, 0x080c, 0x5761, 0x0110, 0x080c, + 0x571c, 0x003e, 0x002e, 0x000e, 0x0005, 0x080c, 0x26bc, 0x1904, + 0x9f4b, 0x6106, 0x080c, 0x9fa2, 0x6007, 0x002b, 0x0804, 0x9d50, + 0x6007, 0x002c, 0x0804, 0x9d50, 0x080c, 0xacbf, 0x1904, 0x9f4b, + 0x080c, 0x26bc, 0x1904, 0x9f4b, 0x080c, 0x9f86, 0x1904, 0x9c41, + 0x6106, 0x080c, 0x9fa6, 0x1120, 0x6007, 0x002e, 0x0804, 0x9d50, + 0x6007, 0x002f, 0x0804, 0x9d50, 0x080c, 0x26bc, 0x1904, 0x9f4b, + 0x00e6, 0x00d6, 0x00c6, 0x6010, 0x9080, 0x0001, 0x200c, 0x9184, + 0x00ff, 0x9086, 0x0006, 0x0158, 0x9184, 0xff00, 0x8007, 0x9086, + 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, 0x0804, 0x9d57, 0x2001, + 0x1172, 0x2004, 0xd0e4, 0x0904, 0x9e9d, 0x2071, 0x026c, 0x7010, + 0x603a, 0x7014, 0x603e, 0x7108, 0x720c, 0x2001, 0x1153, 0x2004, + 0xd0a4, 0x0140, 0x6010, 0x2068, 0x6810, 0x9106, 0x1118, 0x6814, + 0x9206, 0x0508, 0x2001, 0x1153, 0x2004, 0xd0ac, 0x15a0, 0x2069, + 0x1100, 0x6870, 0x9206, 0x1578, 0x686c, 0x9106, 0x1560, 0x7210, + 0x080c, 0x95c2, 0x0568, 0x080c, 0xab36, 0x0550, 0x622e, 0x6007, + 0x0036, 0x6003, 0x0001, 0x080c, 0x6886, 0x080c, 0x6d42, 0x00ce, + 0x00de, 0x00ee, 0x0005, 0x7214, 0x9286, 0xffff, 0x0150, 0x080c, + 0x95c2, 0x01b0, 0x9280, 0x0002, 0x2004, 0x7110, 0x9106, 0x1180, + 0x08f8, 0x7210, 0x2c08, 0x9085, 0x0001, 0x080c, 0xaa9c, 0x2c10, + 0x2160, 0x0130, 0x08a8, 0x6007, 0x0037, 0x6017, 0x1500, 0x08c8, + 0x6007, 0x0037, 0x6017, 0x1700, 0x08a0, 0x6007, 0x0012, 0x0888, + 0x080c, 0x26bc, 0x1904, 0x9f4b, 0x6010, 0x9080, 0x0001, 0x2004, + 0x9084, 0xff00, 0x8007, 0x9086, 0x0006, 0x1904, 0x9d57, 0x00e6, + 0x00d6, 0x00c6, 0x2001, 0x1172, 0x2004, 0xd0e4, 0x0904, 0x9f0d, + 0x2069, 0x1100, 0x2071, 0x026c, 0x7008, 0x603a, 0x720c, 0x623e, + 0x9286, 0xffff, 0x1150, 0x7208, 0x00c6, 0x2c08, 0x9085, 0x0001, + 0x080c, 0xaa9c, 0x2c10, 0x00ce, 0x0598, 0x080c, 0x95c2, 0x0580, + 0x00c6, 0x0026, 0x2260, 0x080c, 0x9297, 0x002e, 0x00ce, 0x7118, + 0x918c, 0xff00, 0x810f, 0x9186, 0x0001, 0x0158, 0x9186, 0x0005, + 0x0118, 0x9186, 0x0007, 0x1178, 0x9280, 0x0005, 0x2004, 0x9005, + 0x0150, 0x0056, 0x7510, 0x7614, 0x080c, 0xab4f, 0x005e, 0x00ce, + 0x00de, 0x00ee, 0x0005, 0x6007, 0x003b, 0x602f, 0x0009, 0x6017, + 0x2a00, 0x6003, 0x0001, 0x080c, 0x6886, 0x080c, 0x6d42, 0x0c78, + 0x6007, 0x003b, 0x602f, 0x0009, 0x6017, 0x1700, 0x6003, 0x0001, + 0x080c, 0x6886, 0x080c, 0x6d42, 0x0c10, 0x6007, 0x003b, 0x602f, + 0x000b, 0x6017, 0x0000, 0x0804, 0x9e71, 0x00e6, 0x0026, 0x080c, + 0x4de0, 0x0558, 0x080c, 0x4dd0, 0x080c, 0xad2a, 0x1520, 0x2071, + 0x1100, 0x70cc, 0xc085, 0x70ce, 0x00f6, 0x2079, 0x0100, 0x729c, + 0x9284, 0x00ff, 0x706e, 0x78e6, 0x9284, 0xff00, 0x7270, 0x9205, + 0x7072, 0x78ea, 0x00fe, 0x70d7, 0x0000, 0x2001, 0x1153, 0x2004, + 0xd0a4, 0x0120, 0x2011, 0x12f5, 0x2013, 0x07d0, 0xd0ac, 0x1128, + 0x080c, 0x23cd, 0x0010, 0x080c, 0xad56, 0x002e, 0x00ee, 0x080c, + 0x7f1e, 0x0804, 0x9d56, 0x080c, 0x7f1e, 0x0005, 0x2600, 0x0002, + 0x9f5b, 0x9f5b, 0x9f5b, 0x9f5b, 0x9f5b, 0x9f5d, 0x9f5b, 0x9f5b, + 0x9f5b, 0x9f5b, 0x9f75, 0x080c, 0x0cf1, 0x080c, 0xacbf, 0x1d58, + 0x080c, 0x26bc, 0x1d40, 0x0411, 0x1138, 0x6007, 0x0045, 0x6003, + 0x0001, 0x080c, 0x68ce, 0x0005, 0x080c, 0x25ad, 0x6007, 0x0001, + 0x6003, 0x0001, 0x080c, 0x68ce, 0x0005, 0x080c, 0xacbf, 0x1998, + 0x080c, 0x26bc, 0x1980, 0x0051, 0x1d78, 0x703c, 0x6016, 0x6007, + 0x004a, 0x6003, 0x0001, 0x080c, 0x68ce, 0x0005, 0x00d6, 0x0066, + 0x6610, 0x2668, 0x6e04, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, + 0x0170, 0x9686, 0x0004, 0x0158, 0x6e04, 0x96b4, 0x00ff, 0x9686, + 0x0006, 0x0128, 0x9686, 0x0004, 0x0110, 0x9085, 0x0001, 0x006e, + 0x00de, 0x0005, 0x00d6, 0x0449, 0x00de, 0x0005, 0x00d6, 0x0491, + 0x11f0, 0x680c, 0x908c, 0xff00, 0x6820, 0x9084, 0x00ff, 0x9115, + 0x6216, 0x6824, 0x602e, 0xd1e4, 0x0118, 0x2009, 0x0001, 0x0060, + 0xd1ec, 0x0168, 0x6920, 0x918c, 0x00ff, 0x6824, 0x080c, 0x1c69, + 0x1130, 0x2110, 0x2009, 0x0000, 0x080c, 0x25f0, 0x0018, 0x9085, + 0x0001, 0x0008, 0x9006, 0x00de, 0x0005, 0x2069, 0x026d, 0x6800, + 0x9082, 0x0010, 0x1228, 0x6017, 0x0000, 0x9085, 0x0001, 0x0008, + 0x9006, 0x0005, 0x6017, 0x0000, 0x2069, 0x026c, 0x6808, 0x9084, + 0xff00, 0x9086, 0x0800, 0x1140, 0x6800, 0x9084, 0x00ff, 0x908e, + 0x0014, 0x0110, 0x908e, 0x0010, 0x0005, 0x6004, 0x90b2, 0x004c, + 0x1a0c, 0x0cf1, 0x91b6, 0x0013, 0x1130, 0x2008, 0x91b2, 0x0040, + 0x1a04, 0xa11e, 0x0092, 0x91b6, 0x0027, 0x0120, 0x91b6, 0x0014, + 0x190c, 0x0cf1, 0x2001, 0x0007, 0x080c, 0x4ae0, 0x080c, 0x6c56, + 0x080c, 0x97a3, 0x080c, 0x6d42, 0x0005, 0xa04d, 0xa04f, 0xa04d, + 0xa04d, 0xa04d, 0xa04f, 0xa061, 0xa117, 0xa0b9, 0xa117, 0xa0cd, + 0xa117, 0xa061, 0xa117, 0xa10f, 0xa117, 0xa10f, 0xa117, 0xa117, + 0xa04d, 0xa04d, 0xa04d, 0xa04d, 0xa04d, 0xa04d, 0xa04d, 0xa04d, + 0xa04d, 0xa04d, 0xa04d, 0xa04f, 0xa04d, 0xa117, 0xa04d, 0xa04d, + 0xa117, 0xa04d, 0xa114, 0xa117, 0xa04d, 0xa04d, 0xa04d, 0xa04d, + 0xa117, 0xa117, 0xa04d, 0xa117, 0xa117, 0xa04d, 0xa05b, 0xa04d, + 0xa04d, 0xa04d, 0xa04d, 0xa113, 0xa117, 0xa04d, 0xa04d, 0xa117, + 0xa117, 0xa04d, 0xa04d, 0xa04d, 0xa04d, 0x080c, 0x0cf1, 0x080c, + 0x6c56, 0x2001, 0x12a6, 0x2004, 0x601a, 0x6003, 0x0002, 0x080c, + 0x6d42, 0x0804, 0xa11d, 0x2001, 0x0000, 0x080c, 0x4aa1, 0x0804, + 0xa117, 0x00f6, 0x2079, 0x1152, 0x7804, 0x00fe, 0xd0ac, 0x1904, + 0xa117, 0x2001, 0x0000, 0x080c, 0x4aa1, 0x6010, 0x9080, 0x0004, + 0x2004, 0x9086, 0x00ff, 0x1140, 0x00f6, 0x2079, 0x1100, 0x7894, + 0x8000, 0x7896, 0x00fe, 0x0418, 0x6010, 0x00c6, 0x2060, 0x6000, + 0xd0f4, 0x1178, 0x6010, 0x9005, 0x0160, 0x0036, 0x0046, 0x63a0, + 0x2021, 0x0007, 0x080c, 0x384a, 0x004e, 0x003e, 0x00ce, 0x0804, + 0xa117, 0x00ce, 0x2001, 0x1100, 0x2004, 0x9086, 0x0002, 0x1138, + 0x00f6, 0x2079, 0x1100, 0x7894, 0x8000, 0x7896, 0x00fe, 0x2001, + 0x0002, 0x080c, 0x4ab3, 0x080c, 0x6c56, 0x6023, 0x0001, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x6110, + 0x00c6, 0x2160, 0x2009, 0x0001, 0x080c, 0x6567, 0x00ce, 0x0804, + 0xa11d, 0x6610, 0x00d6, 0x2668, 0x6e04, 0x00de, 0x96b4, 0xff00, + 0x8637, 0x9686, 0x0006, 0x0904, 0xa117, 0x9686, 0x0004, 0x0904, + 0xa117, 0x2001, 0x0004, 0x0804, 0xa115, 0x2001, 0x1100, 0x2004, + 0x9086, 0x0003, 0x1160, 0x0036, 0x0046, 0x6010, 0x9080, 0x0028, + 0x201c, 0x2021, 0x0006, 0x080c, 0x384a, 0x004e, 0x003e, 0x2001, + 0x0006, 0x080c, 0xa134, 0x6610, 0x00d6, 0x2668, 0x6e04, 0x00de, + 0x0066, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x006e, 0x0120, + 0x2001, 0x0006, 0x080c, 0x4ae0, 0x2001, 0x1153, 0x2004, 0xd0ac, + 0x11f0, 0x2001, 0x1133, 0x2004, 0xd0a4, 0x01c8, 0x96b4, 0x00ff, + 0x9686, 0x0006, 0x01a0, 0x00f6, 0x2079, 0x1100, 0x7894, 0x8000, + 0x7896, 0x00fe, 0x0804, 0xa09f, 0x2001, 0x0004, 0x0030, 0x2001, + 0x0006, 0x0411, 0x0020, 0x0018, 0x0010, 0x080c, 0x4ae0, 0x080c, + 0x6c56, 0x080c, 0x7f1e, 0x080c, 0x6d42, 0x0005, 0x2600, 0x0002, + 0xa12b, 0xa12b, 0xa12b, 0xa12b, 0xa12b, 0xa12d, 0xa12b, 0xa12b, + 0xa12b, 0xa12b, 0xa12d, 0x080c, 0x0cf1, 0x080c, 0x6c56, 0x080c, + 0x7f1e, 0x080c, 0x6d42, 0x0005, 0x0016, 0x00d6, 0x6110, 0x2168, + 0x6900, 0xd184, 0x0188, 0x6104, 0x918e, 0x000a, 0x1128, 0x699c, + 0xd1a4, 0x1110, 0x2001, 0x0007, 0x080c, 0x4ab3, 0x2001, 0x0000, + 0x080c, 0x4aa1, 0x080c, 0x25d1, 0x00de, 0x001e, 0x0005, 0x6610, + 0x00d6, 0x2668, 0x6804, 0x9084, 0xff00, 0x8007, 0x00de, 0x90b2, + 0x000c, 0x1a0c, 0x0cf1, 0x91b6, 0x0015, 0x1110, 0x003b, 0x0028, + 0x91b6, 0x0016, 0x190c, 0x0cf1, 0x006b, 0x0005, 0x863b, 0x863b, + 0x863b, 0x863b, 0x863b, 0x863b, 0xa1b7, 0xa17e, 0x863b, 0x863b, + 0x863b, 0x863b, 0x863b, 0x863b, 0x863b, 0x863b, 0x863b, 0x863b, + 0xa1b7, 0xa1be, 0x863b, 0x863b, 0x863b, 0x863b, 0x00f6, 0x2079, + 0x1152, 0x7804, 0xd0ac, 0x11e0, 0x6010, 0x907d, 0x01c8, 0x7800, + 0xd0f4, 0x1118, 0x7810, 0x9005, 0x1198, 0x2001, 0x0000, 0x080c, + 0x4aa1, 0x2001, 0x0002, 0x080c, 0x4ab3, 0x6023, 0x0001, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x68ce, 0x080c, 0x6d42, 0x00a8, + 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x1c69, 0x1168, + 0x00c6, 0x080c, 0x4b58, 0x0120, 0x00ce, 0x080c, 0x7f1e, 0x0028, + 0x080c, 0x472d, 0x00ce, 0x080c, 0x7f1e, 0x00fe, 0x0005, 0x6604, + 0x96b6, 0x001e, 0x1110, 0x080c, 0x7f1e, 0x0005, 0x080c, 0x88eb, + 0x1148, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x68ce, 0x080c, + 0x6d42, 0x0010, 0x080c, 0x7f1e, 0x0005, 0x6004, 0x908a, 0x004c, + 0x1a0c, 0x0cf1, 0x080c, 0x6c56, 0x080c, 0x97a3, 0x080c, 0x6d42, + 0x0005, 0x9182, 0x0040, 0x0002, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, + 0xa1f1, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, + 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, 0xa1ef, 0x080c, + 0x0cf1, 0x00d6, 0x00e6, 0x00f6, 0x0046, 0x0026, 0x6210, 0x9280, + 0x002b, 0x2004, 0x9005, 0x1190, 0x6106, 0x2071, 0x0260, 0x7444, + 0x94a4, 0xff00, 0x0904, 0xa256, 0x9486, 0x2000, 0x1160, 0x2009, + 0x0001, 0x2011, 0x0200, 0x080c, 0x66d5, 0x0028, 0x2021, 0x0000, + 0x080c, 0xacfb, 0x0c48, 0x080c, 0x0ddf, 0x090c, 0x0cf1, 0x6003, + 0x0007, 0x2d00, 0x6867, 0x010d, 0x6803, 0x0000, 0x686b, 0x0000, + 0x6c8a, 0x2c00, 0x688e, 0x6008, 0x68e2, 0x6010, 0x2078, 0x78a0, + 0x8007, 0x7130, 0x697a, 0x0016, 0x9084, 0xff00, 0x6876, 0x687f, + 0x0000, 0x6883, 0x0000, 0x6887, 0x0036, 0x080c, 0x50a5, 0x001e, + 0x9486, 0x2000, 0x1130, 0x2019, 0x0017, 0x080c, 0xaa50, 0x0804, + 0xa2a9, 0x9486, 0x0400, 0x1130, 0x2019, 0x0002, 0x080c, 0xaa02, + 0x0804, 0xa2a9, 0x9486, 0x0200, 0x1110, 0x080c, 0xa9e7, 0x9486, + 0x1000, 0x1110, 0x080c, 0xaa35, 0x0804, 0xa2a9, 0x2069, 0x1329, + 0x6a00, 0xd284, 0x0904, 0xa303, 0x9284, 0x0300, 0x1904, 0xa2fc, + 0x6804, 0x9005, 0x0904, 0xa2e4, 0x2d78, 0x6003, 0x0007, 0x080c, + 0x0dc6, 0x0904, 0xa2b3, 0x7800, 0xd08c, 0x1118, 0x7804, 0x8001, + 0x7806, 0x6017, 0x0000, 0x6803, 0x0000, 0x6867, 0x0116, 0x686b, + 0x0000, 0x6008, 0x68e2, 0x2c00, 0x687a, 0x6010, 0x2078, 0x78a0, + 0x8007, 0x7130, 0x69b6, 0x6876, 0x6883, 0x003d, 0x7044, 0x9084, + 0x0003, 0x9080, 0xa2af, 0x2005, 0x687e, 0x20a9, 0x000a, 0x2001, + 0x0270, 0x9d90, 0x0021, 0x2009, 0x0205, 0x200b, 0x0080, 0x20e1, + 0x0000, 0x20e9, 0x0001, 0x2098, 0x22a0, 0x4003, 0x200b, 0x0000, + 0x2001, 0x027a, 0x200c, 0x69b2, 0x8000, 0x200c, 0x69ae, 0x080c, + 0x50a5, 0x002e, 0x004e, 0x00fe, 0x00ee, 0x00de, 0x0005, 0x0000, + 0x0080, 0x0040, 0x0000, 0x6017, 0x0100, 0x6003, 0x0001, 0x6007, + 0x0041, 0x080c, 0x6886, 0x080c, 0x6d42, 0x0c58, 0x2069, 0x0260, + 0x6848, 0x9084, 0xff00, 0x9086, 0x1200, 0x1198, 0x686c, 0x9084, + 0x00ff, 0x0016, 0x6114, 0x918c, 0x0700, 0x910d, 0x6116, 0x001e, + 0x6003, 0x0001, 0x6007, 0x0043, 0x080c, 0x6886, 0x080c, 0x6d42, + 0x0880, 0x6017, 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, + 0x6886, 0x080c, 0x6d42, 0x0828, 0x2001, 0x110d, 0x2004, 0xd0ec, + 0x0120, 0x2011, 0x8049, 0x080c, 0x37dc, 0x6017, 0x0300, 0x0010, + 0x6017, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x6886, + 0x080c, 0x6d42, 0x0804, 0xa2a9, 0x6017, 0x0500, 0x0c98, 0x6017, + 0x0600, 0x0804, 0xa2be, 0x6017, 0x0200, 0x0804, 0xa2be, 0x9186, + 0x0013, 0x1160, 0x6004, 0x908a, 0x0054, 0x1a0c, 0x0cf1, 0x9082, + 0x0040, 0x0a0c, 0x0cf1, 0x2008, 0x0804, 0xa38f, 0x9186, 0x0051, + 0x0138, 0x9186, 0x0047, 0x11d8, 0x6004, 0x9086, 0x0041, 0x0518, + 0x2001, 0x0109, 0x2004, 0xd084, 0x01f0, 0x0126, 0x2091, 0x2800, + 0x0006, 0x0016, 0x0026, 0x080c, 0x677e, 0x002e, 0x001e, 0x000e, + 0x012e, 0x6000, 0x9086, 0x0002, 0x1170, 0x0804, 0xa3dc, 0x9186, + 0x0027, 0x0120, 0x9186, 0x0014, 0x190c, 0x0cf1, 0x6004, 0x9082, + 0x0040, 0x2008, 0x001a, 0x080c, 0x7f68, 0x0005, 0xa359, 0xa35b, + 0xa35b, 0xa37f, 0xa359, 0xa359, 0xa359, 0xa359, 0xa359, 0xa359, + 0xa359, 0xa359, 0xa359, 0xa359, 0xa359, 0xa359, 0xa359, 0xa359, + 0xa359, 0x080c, 0x0cf1, 0x080c, 0x6c56, 0x080c, 0x6d42, 0x0036, + 0x00d6, 0x6014, 0x906d, 0x01c0, 0x9d84, 0xf000, 0x01a8, 0x6003, + 0x0002, 0x6010, 0x2004, 0xd0bc, 0x1178, 0x2019, 0x0004, 0x080c, + 0xaa84, 0x6017, 0x0000, 0x6018, 0x9005, 0x1120, 0x2001, 0x12a7, + 0x2004, 0x601a, 0x6003, 0x0007, 0x00de, 0x003e, 0x0005, 0x00d6, + 0x080c, 0x6c56, 0x080c, 0x6d42, 0x080c, 0x95d2, 0x0120, 0x6014, + 0x2068, 0x080c, 0x0df6, 0x080c, 0x97a3, 0x00de, 0x0005, 0x0002, + 0xa3a3, 0xa3c0, 0xa3ac, 0xa3d6, 0xa3a3, 0xa3a3, 0xa3a3, 0xa3a3, + 0xa3a3, 0xa3a3, 0xa3a3, 0xa3a3, 0xa3a3, 0xa3a3, 0xa3a3, 0xa3a3, + 0xa3a3, 0xa3a3, 0xa3a3, 0x080c, 0x0cf1, 0x6014, 0x9088, 0x001f, + 0x2104, 0x9085, 0x0400, 0x200a, 0x080c, 0x6c56, 0x6014, 0x9080, + 0x001f, 0x2004, 0xd0b4, 0x0138, 0x6003, 0x0007, 0x2009, 0x0043, + 0x080c, 0x7f4e, 0x0010, 0x6003, 0x0004, 0x080c, 0x6d42, 0x0005, + 0x080c, 0x6c56, 0x6114, 0x9184, 0xf000, 0x0128, 0x9180, 0x001f, + 0x200c, 0xd1ec, 0x1138, 0x080c, 0x66ae, 0x080c, 0x7f1e, 0x080c, + 0x6d42, 0x0005, 0x080c, 0xacc6, 0x0db0, 0x0cc8, 0x080c, 0x6c56, + 0x2009, 0x0041, 0x0804, 0xa528, 0x9182, 0x0040, 0x0002, 0xa3f2, + 0xa3f4, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, + 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, 0xa3f2, + 0xa3f5, 0xa3f2, 0x080c, 0x0cf1, 0x0005, 0x00d6, 0x080c, 0x66ae, + 0x00de, 0x080c, 0xad19, 0x080c, 0x7f1e, 0x0005, 0x9182, 0x0040, + 0x0002, 0xa414, 0xa414, 0xa414, 0xa414, 0xa414, 0xa414, 0xa414, + 0xa416, 0xa414, 0xa419, 0xa471, 0xa414, 0xa414, 0xa414, 0xa414, + 0xa471, 0xa414, 0xa414, 0xa414, 0x080c, 0x0cf1, 0x080c, 0x7f68, + 0x0005, 0x2001, 0x0105, 0x2004, 0x9084, 0x1800, 0x1904, 0xa471, + 0x2001, 0x1172, 0x2004, 0xd0e4, 0x1528, 0x603b, 0x0000, 0x080c, + 0x6cf2, 0x6014, 0x00d6, 0x2068, 0x687c, 0xd0fc, 0x0188, 0x908c, + 0x0003, 0x918e, 0x0002, 0x0508, 0x2001, 0x110c, 0x2004, 0xd0d4, + 0x11e0, 0x080c, 0x6e07, 0x2009, 0x0041, 0x00de, 0x0804, 0xa528, + 0x080c, 0x6e07, 0x6003, 0x0007, 0x601b, 0x0000, 0x080c, 0x66ae, + 0x00de, 0x0005, 0x2001, 0x0100, 0x2004, 0x9082, 0x0005, 0x0aa8, + 0x2001, 0x011f, 0x2004, 0x603a, 0x0890, 0x2001, 0x110c, 0x200c, + 0xc1d4, 0x2102, 0xd1cc, 0x0110, 0x080c, 0x2069, 0x080c, 0x6e07, + 0x6014, 0x9080, 0x001f, 0x200c, 0xd1ec, 0x1130, 0x080c, 0x66ae, + 0x080c, 0x7f1e, 0x00de, 0x0005, 0x080c, 0xacc6, 0x0db8, 0x00de, + 0x0005, 0x2001, 0x110c, 0x200c, 0xc1d4, 0x2102, 0x0036, 0x080c, + 0x6cf2, 0x080c, 0x6e07, 0x6014, 0x00d6, 0x2068, 0x6010, 0x2004, + 0xd0bc, 0x0188, 0x687c, 0x9084, 0x0003, 0x9086, 0x0002, 0x0140, + 0x68ac, 0x6330, 0x931a, 0x6332, 0x68b0, 0x632c, 0x931b, 0x632e, + 0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xaa84, 0x6018, + 0x9005, 0x1128, 0x2001, 0x12a7, 0x2004, 0x8003, 0x601a, 0x6017, + 0x0000, 0x6003, 0x0007, 0x00de, 0x003e, 0x0005, 0x9182, 0x0040, + 0x0002, 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, + 0xa4bd, 0xa4bf, 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, + 0xa4bd, 0xa4bd, 0xa4bd, 0xa4bd, 0xa504, 0x080c, 0x0cf1, 0x6014, + 0x00d6, 0x2068, 0x6834, 0x6a38, 0x6110, 0x210c, 0xd1bc, 0x1190, + 0x920d, 0x1518, 0x687c, 0xd0fc, 0x0128, 0x2009, 0x0041, 0x00de, + 0x0804, 0xa528, 0x6003, 0x0007, 0x601b, 0x0000, 0x080c, 0x66ae, + 0x00de, 0x0005, 0x6124, 0xd1f4, 0x1d58, 0x0006, 0x0046, 0x6cac, + 0x9422, 0x69b0, 0x2200, 0x910b, 0x6030, 0x9420, 0x6432, 0x602c, + 0x9109, 0x612e, 0x004e, 0x000e, 0x08d8, 0x6110, 0x210c, 0xd1bc, + 0x1178, 0x2009, 0x110d, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, + 0x0010, 0x6003, 0x0006, 0x00e9, 0x080c, 0x66b0, 0x00de, 0x0005, + 0x6003, 0x0002, 0x00de, 0x0005, 0x6024, 0xd0f4, 0x0128, 0x080c, + 0x1132, 0x1904, 0xa4bf, 0x0005, 0x00d6, 0x6014, 0x2068, 0x6834, + 0x6938, 0x00de, 0x9105, 0x1120, 0x080c, 0x1132, 0x1904, 0xa4bf, + 0x0005, 0xd2fc, 0x0140, 0x8002, 0x8000, 0x8212, 0x9291, 0x0000, + 0x2009, 0x0009, 0x0010, 0x2009, 0x0015, 0x6a9a, 0x6896, 0x0005, + 0x9182, 0x0040, 0x0208, 0x0062, 0x9186, 0x0013, 0x0120, 0x9186, + 0x0014, 0x190c, 0x0cf1, 0x6024, 0xd0dc, 0x090c, 0x0cf1, 0x0005, + 0xa54b, 0xa552, 0xa55e, 0xa56a, 0xa54b, 0xa54b, 0xa54b, 0xa579, + 0xa54b, 0xa54d, 0xa54d, 0xa54b, 0xa54b, 0xa54b, 0xa54b, 0xa54d, + 0xa54b, 0xa54d, 0xa54b, 0x080c, 0x0cf1, 0x6024, 0xd0dc, 0x090c, + 0x0cf1, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, 0x6886, 0x0126, + 0x2091, 0x8000, 0x080c, 0x6d42, 0x012e, 0x0005, 0x6003, 0x0001, + 0x6106, 0x080c, 0x6886, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d42, + 0x012e, 0x0005, 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x13a9, + 0x0126, 0x2091, 0x8000, 0x080c, 0x68eb, 0x080c, 0x6e10, 0x012e, + 0x0005, 0x9016, 0x080c, 0x119a, 0x0005, 0x0126, 0x2091, 0x8000, + 0x0036, 0x00d6, 0x9182, 0x0040, 0x0023, 0x00de, 0x003e, 0x012e, + 0x0005, 0xa599, 0xa59b, 0xa5ad, 0xa5c8, 0xa599, 0xa599, 0xa599, + 0xa5dd, 0xa599, 0xa599, 0xa599, 0xa599, 0xa599, 0xa599, 0xa599, + 0xa599, 0x080c, 0x0cf1, 0x6014, 0x2068, 0x687c, 0xd0fc, 0x01f8, + 0x909c, 0x0003, 0x939e, 0x0003, 0x01d0, 0x6003, 0x0001, 0x6106, + 0x080c, 0x6886, 0x080c, 0x6d42, 0x0498, 0x6014, 0x2068, 0x687c, + 0xd0fc, 0x0168, 0x909c, 0x0003, 0x939e, 0x0003, 0x0140, 0x6003, + 0x0001, 0x6106, 0x080c, 0x6886, 0x080c, 0x6d42, 0x0408, 0x6017, + 0x0000, 0x601b, 0x0000, 0x2019, 0x0004, 0x080c, 0xaa84, 0x00c0, + 0x6014, 0x2068, 0x687c, 0xd0fc, 0x0d90, 0x909c, 0x0003, 0x939e, + 0x0003, 0x0d68, 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x13a9, + 0x080c, 0x68eb, 0x080c, 0x6e10, 0x0018, 0x9016, 0x080c, 0x119a, + 0x0005, 0x080c, 0x6c56, 0x6114, 0x81ff, 0x0158, 0x00d6, 0x2168, + 0x080c, 0xad5f, 0x0036, 0x2019, 0x0029, 0x080c, 0xaa84, 0x003e, + 0x00de, 0x080c, 0x97a3, 0x080c, 0x6d42, 0x0005, 0x080c, 0x6cf2, + 0x6114, 0x81ff, 0x0158, 0x00d6, 0x2168, 0x080c, 0xad5f, 0x0036, + 0x2019, 0x0029, 0x080c, 0xaa84, 0x003e, 0x00de, 0x080c, 0x97a3, + 0x080c, 0x6e10, 0x0005, 0x9182, 0x0085, 0x0002, 0xa61b, 0xa619, + 0xa619, 0xa627, 0xa619, 0xa619, 0xa619, 0xa619, 0xa619, 0xa619, + 0xa619, 0x080c, 0x0cf1, 0x6003, 0x000b, 0x6106, 0x080c, 0x6886, + 0x0126, 0x2091, 0x8000, 0x080c, 0x6d42, 0x012e, 0x0005, 0x0026, + 0x00e6, 0x080c, 0xacbf, 0x0118, 0x080c, 0x7f1e, 0x00c8, 0x2071, + 0x0260, 0x7224, 0x6216, 0x7220, 0x080c, 0xa91c, 0x0118, 0x6007, + 0x0086, 0x0040, 0x6007, 0x0087, 0x7224, 0x9296, 0xffff, 0x1110, + 0x6007, 0x0086, 0x6003, 0x0001, 0x080c, 0x6886, 0x080c, 0x6d42, + 0x00ee, 0x002e, 0x0005, 0x9186, 0x0013, 0x1160, 0x6004, 0x908a, + 0x0085, 0x0a0c, 0x0cf1, 0x908a, 0x0090, 0x1a0c, 0x0cf1, 0x9082, + 0x0085, 0x00a2, 0x9186, 0x0027, 0x0130, 0x9186, 0x0014, 0x0118, + 0x080c, 0x7f68, 0x0050, 0x2001, 0x0007, 0x080c, 0x4ae0, 0x080c, + 0x6c56, 0x080c, 0x97a3, 0x080c, 0x6d42, 0x0005, 0xa679, 0xa67b, + 0xa67b, 0xa679, 0xa679, 0xa679, 0xa679, 0xa679, 0xa679, 0xa679, + 0xa679, 0x080c, 0x0cf1, 0x080c, 0x6c56, 0x080c, 0x97a3, 0x080c, + 0x6d42, 0x0005, 0x9182, 0x0085, 0x0a0c, 0x0cf1, 0x9182, 0x0090, + 0x1a0c, 0x0cf1, 0x9182, 0x0085, 0x0002, 0xa698, 0xa698, 0xa698, + 0xa69a, 0xa698, 0xa698, 0xa698, 0xa698, 0xa698, 0xa698, 0xa698, + 0x080c, 0x0cf1, 0x0005, 0x9186, 0x0013, 0x0148, 0x9186, 0x0014, + 0x0130, 0x9186, 0x0027, 0x0118, 0x080c, 0x7f68, 0x0030, 0x080c, + 0x6c56, 0x080c, 0x97a3, 0x080c, 0x6d42, 0x0005, 0x0036, 0x080c, + 0xad19, 0x6043, 0x0000, 0x2019, 0x000b, 0x0031, 0x6023, 0x0006, + 0x6003, 0x0007, 0x003e, 0x0005, 0x0126, 0x0036, 0x2091, 0x8000, + 0x0086, 0x2c40, 0x0096, 0x2049, 0x0000, 0x080c, 0x7a48, 0x009e, + 0x008e, 0x1578, 0x0076, 0x2c38, 0x080c, 0x7ae2, 0x007e, 0x1548, + 0x6000, 0x9086, 0x0000, 0x0528, 0x6020, 0x9086, 0x0007, 0x0508, + 0x00d6, 0x6000, 0x9086, 0x0004, 0x1150, 0x080c, 0xad19, 0x6023, + 0x0007, 0x2001, 0x12a6, 0x2004, 0x601a, 0x080c, 0x12c7, 0x6014, + 0x2068, 0x080c, 0x95d2, 0x0110, 0x080c, 0xaa84, 0x00de, 0x6017, + 0x0000, 0x080c, 0xad19, 0x6023, 0x0007, 0x2001, 0x12a6, 0x2004, + 0x601a, 0x003e, 0x012e, 0x0005, 0x00f6, 0x00c6, 0x0036, 0x0156, + 0x2079, 0x0260, 0x7938, 0x783c, 0x080c, 0x1c69, 0x15a0, 0x0016, + 0x00c6, 0x080c, 0x4b58, 0x1568, 0x001e, 0x002e, 0x0026, 0x0016, + 0x2019, 0x0029, 0x080c, 0x7ba2, 0x080c, 0x69ca, 0x0076, 0x2039, + 0x0000, 0x080c, 0x68fe, 0x007e, 0x001e, 0x0076, 0x2039, 0x0000, + 0x080c, 0xa85f, 0x007e, 0x0026, 0x6204, 0x9294, 0xff00, 0x8217, + 0x9286, 0x0006, 0x0118, 0x9286, 0x0004, 0x1118, 0x62a0, 0x080c, + 0x2661, 0x002e, 0x001e, 0x080c, 0x472d, 0x6612, 0x6516, 0x9006, + 0x0010, 0x00ce, 0x001e, 0x015e, 0x003e, 0x00ce, 0x00fe, 0x0005, + 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x2009, 0x1120, 0x2104, 0x9086, + 0x0074, 0x1904, 0xa798, 0x2069, 0x0260, 0x6944, 0x9182, 0x0100, + 0x06d8, 0x6940, 0x9184, 0x8000, 0x0904, 0xa795, 0x2001, 0x128f, + 0x2004, 0x9005, 0x1160, 0x6010, 0x2070, 0x7010, 0x9084, 0x00ff, + 0x0118, 0x7000, 0xd0f4, 0x0118, 0x9184, 0x0800, 0x0570, 0x6948, + 0x918a, 0x0001, 0x0620, 0x694c, 0x2009, 0x0205, 0x200b, 0x0001, + 0x693c, 0x81ff, 0x1198, 0x6944, 0x9182, 0x0100, 0x02a8, 0x6940, + 0x81ff, 0x1178, 0x6948, 0x918a, 0x0001, 0x0288, 0x6950, 0x918a, + 0x0001, 0x0298, 0x00d0, 0x6017, 0x0100, 0x00a0, 0x6017, 0x0300, + 0x0088, 0x6017, 0x0500, 0x0070, 0x6017, 0x0700, 0x0058, 0x6017, + 0x0900, 0x0040, 0x6017, 0x0b00, 0x0028, 0x6017, 0x0f00, 0x0010, + 0x6017, 0x2d00, 0x9085, 0x0001, 0x0008, 0x9006, 0x001e, 0x00ee, + 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x0026, 0x0036, 0x0156, + 0x6210, 0x2268, 0x6b04, 0x9394, 0x00ff, 0x9286, 0x0006, 0x0190, + 0x9286, 0x0004, 0x0178, 0x9394, 0xff00, 0x8217, 0x9286, 0x0006, + 0x0148, 0x9286, 0x0004, 0x0130, 0x00c6, 0x2d60, 0x080c, 0x4b67, + 0x00ce, 0x04c0, 0x2011, 0x0276, 0x20a9, 0x0004, 0x9d98, 0x000a, + 0x080c, 0x8a45, 0x1580, 0x2011, 0x027a, 0x20a9, 0x0004, 0x9d98, + 0x0006, 0x080c, 0x8a45, 0x1538, 0x0046, 0x0016, 0x6aa0, 0x9294, + 0x00ff, 0x8227, 0x9006, 0x2009, 0x1153, 0x210c, 0xd1a4, 0x0138, + 0x2009, 0x0029, 0x080c, 0xaaca, 0x6800, 0xc0e5, 0x6802, 0x2019, + 0x0029, 0x080c, 0x69ca, 0x0076, 0x2039, 0x0000, 0x080c, 0x68fe, + 0x2c08, 0x080c, 0xa85f, 0x007e, 0x2001, 0x0007, 0x080c, 0x4ae0, + 0x001e, 0x004e, 0x9006, 0x015e, 0x003e, 0x002e, 0x00de, 0x00ce, + 0x0005, 0x00d6, 0x2069, 0x026e, 0x6800, 0x9086, 0x0800, 0x0118, + 0x6017, 0x0000, 0x0008, 0x9006, 0x00de, 0x0005, 0x00c6, 0x00f6, + 0x0016, 0x0026, 0x0036, 0x0156, 0x2079, 0x026c, 0x7930, 0x7834, + 0x080c, 0x1c69, 0x11a0, 0x080c, 0x4b58, 0x1188, 0x2011, 0x0270, + 0x20a9, 0x0004, 0x9c98, 0x000a, 0x080c, 0x8a45, 0x1140, 0x2011, + 0x0274, 0x20a9, 0x0004, 0x9c98, 0x0006, 0x080c, 0x8a45, 0x015e, + 0x003e, 0x002e, 0x001e, 0x00fe, 0x00ce, 0x0005, 0x00c6, 0x0006, + 0x0016, 0x0026, 0x0036, 0x0156, 0x2011, 0x0263, 0x2204, 0x8211, + 0x220c, 0x080c, 0x1c69, 0x11a0, 0x080c, 0x4b58, 0x1188, 0x2011, + 0x0276, 0x20a9, 0x0004, 0x9c98, 0x000a, 0x080c, 0x8a45, 0x1140, + 0x2011, 0x027a, 0x20a9, 0x0004, 0x9c98, 0x0006, 0x080c, 0x8a45, + 0x015e, 0x003e, 0x002e, 0x001e, 0x000e, 0x00ce, 0x0005, 0x00e6, + 0x00c6, 0x0086, 0x0076, 0x0066, 0x0056, 0x0046, 0x0026, 0x0126, + 0x2091, 0x8000, 0x2740, 0x2029, 0x12e5, 0x252c, 0x2021, 0x12eb, + 0x2424, 0x2061, 0x15c0, 0x2071, 0x1100, 0x7644, 0x7064, 0x81ff, + 0x0128, 0x8001, 0x9602, 0x1a04, 0xa8db, 0x0018, 0x9606, 0x0904, + 0xa8db, 0x2100, 0x9c06, 0x0904, 0xa8d2, 0x080c, 0xaaf2, 0x0904, + 0xa8d2, 0x6720, 0x9786, 0x0001, 0x0904, 0xa8f3, 0x9786, 0x0004, + 0x0904, 0xa8f3, 0x9786, 0x0007, 0x05e8, 0x2500, 0x9c06, 0x05d0, + 0x2400, 0x9c06, 0x05b8, 0x080c, 0xab02, 0x15a0, 0x88ff, 0x0118, + 0x6054, 0x9906, 0x1578, 0x00d6, 0x6000, 0x9086, 0x0004, 0x1120, + 0x0016, 0x080c, 0x12c7, 0x001e, 0x9786, 0x0008, 0x1148, 0x080c, + 0x97cd, 0x1130, 0x080c, 0x8576, 0x00de, 0x080c, 0x97a3, 0x00d0, + 0x6014, 0x2068, 0x080c, 0x95d2, 0x0190, 0x9786, 0x0003, 0x1528, + 0x6867, 0x0103, 0x6b7a, 0x6877, 0x0000, 0x080c, 0xad5f, 0x0016, + 0x080c, 0x9843, 0x080c, 0x50a5, 0x001e, 0x080c, 0x9797, 0x00de, + 0x080c, 0x97a3, 0x9ce0, 0x0018, 0x2001, 0x1116, 0x2004, 0x9c02, + 0x1210, 0x0804, 0xa873, 0x012e, 0x002e, 0x004e, 0x005e, 0x006e, + 0x007e, 0x008e, 0x00ce, 0x00ee, 0x0005, 0x9786, 0x0006, 0x19c0, + 0x9386, 0x0005, 0x0128, 0x080c, 0xad5f, 0x080c, 0xaa84, 0x08f8, + 0x00de, 0x0c00, 0x0868, 0x080c, 0xab02, 0x19e0, 0x81ff, 0x09d0, + 0x9180, 0x0001, 0x2004, 0x9086, 0x0018, 0x0130, 0x9180, 0x0001, + 0x2004, 0x9086, 0x002d, 0x1970, 0x6000, 0x9086, 0x0002, 0x1950, + 0x080c, 0x97bc, 0x0130, 0x080c, 0x97cd, 0x1920, 0x080c, 0x8576, + 0x0038, 0x080c, 0x25d1, 0x080c, 0x97cd, 0x1110, 0x080c, 0x8576, + 0x080c, 0x97a3, 0x0804, 0xa8d2, 0x00c6, 0x00e6, 0x0016, 0x2c08, + 0x2170, 0x9006, 0x080c, 0xaa9c, 0x001e, 0x0120, 0x6020, 0x9084, + 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, 0xa93b, 0xa93b, 0xa93b, + 0xa93b, 0xa93b, 0xa93b, 0xa93d, 0xa93b, 0xa93b, 0xa93b, 0xa93b, + 0x97a3, 0x97a3, 0xa93b, 0x9006, 0x0005, 0x0046, 0x0016, 0x7010, + 0x9080, 0x0028, 0x2024, 0x94a4, 0x00ff, 0x8427, 0x2c00, 0x2009, + 0x0020, 0x080c, 0xaaca, 0x001e, 0x004e, 0x0036, 0x2019, 0x0002, + 0x080c, 0xa6bc, 0x003e, 0x9085, 0x0001, 0x0005, 0x00d6, 0x6014, + 0x906d, 0x9084, 0xf000, 0x0130, 0x080c, 0x92a4, 0x687b, 0x0005, + 0x080c, 0x50a5, 0x00de, 0x080c, 0x97a3, 0x0005, 0x2001, 0x0001, + 0x080c, 0x4aa1, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, + 0x2019, 0x1105, 0x2011, 0x0276, 0x080c, 0x8a45, 0x003e, 0x002e, + 0x001e, 0x015e, 0x9005, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0086, + 0x0076, 0x0066, 0x0026, 0x0126, 0x2091, 0x8000, 0x2740, 0x2061, + 0x15c0, 0x2079, 0x0001, 0x8fff, 0x0904, 0xa9da, 0x2071, 0x1100, + 0x7644, 0x7064, 0x8001, 0x9602, 0x1a04, 0xa9da, 0x88ff, 0x0128, + 0x2800, 0x9c06, 0x15b0, 0x2079, 0x0000, 0x080c, 0xaaf2, 0x0588, + 0x2400, 0x9c06, 0x0570, 0x6720, 0x9786, 0x0006, 0x1550, 0x9786, + 0x0007, 0x0538, 0x88ff, 0x1140, 0x6010, 0x9206, 0x1510, 0x85ff, + 0x0118, 0x6054, 0x9106, 0x11e8, 0x00d6, 0x6000, 0x9086, 0x0004, + 0x1150, 0x080c, 0xad19, 0x6023, 0x0007, 0x2001, 0x12a6, 0x2004, + 0x601a, 0x080c, 0x12c7, 0x6014, 0x2068, 0x080c, 0x95d2, 0x0120, + 0x0046, 0x080c, 0xaa84, 0x004e, 0x00de, 0x080c, 0x97a3, 0x88ff, + 0x1198, 0x9ce0, 0x0018, 0x2001, 0x1116, 0x2004, 0x9c02, 0x1210, + 0x0804, 0xa98b, 0x9006, 0x012e, 0x002e, 0x006e, 0x007e, 0x008e, + 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x98c5, 0x0001, 0x0ca0, 0x0076, + 0x0056, 0x0086, 0x2041, 0x0000, 0x2029, 0x0001, 0x2c20, 0x2019, + 0x0002, 0x6210, 0x0096, 0x2049, 0x0000, 0x080c, 0x7a48, 0x009e, + 0x008e, 0x2039, 0x0000, 0x080c, 0x7ae2, 0x080c, 0xa97c, 0x005e, + 0x007e, 0x0005, 0x0026, 0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, + 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x0036, + 0x080c, 0x4b58, 0x11b0, 0x2c10, 0x0056, 0x0086, 0x2041, 0x0000, + 0x2508, 0x2029, 0x0001, 0x0096, 0x2049, 0x0000, 0x080c, 0x7a48, + 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, 0x7ae2, 0x080c, 0xa97c, + 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04, 0xaa0e, 0x015e, 0x00ce, + 0x007e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0076, 0x0056, 0x6210, + 0x0086, 0x2041, 0x0000, 0x2029, 0x0001, 0x2019, 0x0048, 0x0096, + 0x2049, 0x0000, 0x080c, 0x7a48, 0x009e, 0x008e, 0x2039, 0x0000, + 0x080c, 0x7ae2, 0x2c20, 0x080c, 0xa97c, 0x005e, 0x007e, 0x0005, + 0x0026, 0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, 0x20a9, + 0x007f, 0x2009, 0x0000, 0x0016, 0x0036, 0x080c, 0x4b58, 0x11c0, + 0x2c10, 0x0086, 0x2041, 0x0000, 0x2828, 0x0046, 0x2021, 0x0001, + 0x080c, 0xacfb, 0x004e, 0x0096, 0x2049, 0x0000, 0x080c, 0x7a48, + 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, 0x7ae2, 0x080c, 0xa97c, + 0x003e, 0x001e, 0x8108, 0x1f04, 0xaa5b, 0x015e, 0x00ce, 0x007e, + 0x005e, 0x004e, 0x002e, 0x0005, 0x0016, 0x00f6, 0x9d82, 0x45c0, + 0x0280, 0x9d82, 0xffff, 0x1268, 0x6800, 0x907d, 0x0138, 0x6803, + 0x0000, 0x6b82, 0x080c, 0x50a5, 0x2f68, 0x0cb0, 0x6b82, 0x080c, + 0x50a5, 0x00fe, 0x001e, 0x0005, 0x00e6, 0x0046, 0x0036, 0x2061, + 0x15c0, 0x9005, 0x1138, 0x2071, 0x1100, 0x7444, 0x7064, 0x8001, + 0x9402, 0x12d8, 0x2100, 0x9c06, 0x0168, 0x6000, 0x9086, 0x0000, + 0x0148, 0x6008, 0x9206, 0x1130, 0x6010, 0x91a0, 0x0004, 0x2424, + 0x9406, 0x0140, 0x9ce0, 0x0018, 0x2001, 0x1116, 0x2004, 0x9c02, + 0x1220, 0x0c40, 0x9085, 0x0001, 0x0008, 0x9006, 0x003e, 0x004e, + 0x00ee, 0x0005, 0x00d6, 0x0006, 0x080c, 0x0ddf, 0x000e, 0x090c, + 0x0cf1, 0x6867, 0x010d, 0x688e, 0x0026, 0x2010, 0x080c, 0x95c2, + 0x2001, 0x0000, 0x0120, 0x2200, 0x9080, 0x0015, 0x2004, 0x002e, + 0x687a, 0x6986, 0x6c76, 0x687f, 0x0000, 0x2001, 0x12ae, 0x2004, + 0x6882, 0x9006, 0x68e2, 0x6802, 0x686a, 0x688a, 0x080c, 0x50a5, + 0x00de, 0x0005, 0x6700, 0x9786, 0x0000, 0x0158, 0x9786, 0x0001, + 0x0140, 0x9786, 0x000a, 0x0128, 0x9786, 0x0009, 0x0110, 0x9085, + 0x0001, 0x0005, 0x00e6, 0x6010, 0x2070, 0x70a0, 0x9206, 0x00ee, + 0x0005, 0x0016, 0x6004, 0x908e, 0x001e, 0x11a0, 0x8007, 0x6134, + 0x918c, 0x00ff, 0x9105, 0x6036, 0x6007, 0x0085, 0x6003, 0x000b, + 0x6023, 0x0005, 0x2001, 0x12a7, 0x2004, 0x601a, 0x080c, 0x6886, + 0x080c, 0x6d42, 0x001e, 0x0005, 0xa001, 0xa001, 0x0005, 0x6024, + 0xd0e4, 0x0158, 0xd0cc, 0x0118, 0x080c, 0x98aa, 0x0030, 0x080c, + 0xad19, 0x080c, 0x66ae, 0x080c, 0x7f1e, 0x0005, 0x9280, 0x0008, + 0x2004, 0x9084, 0x000f, 0x0002, 0xab4a, 0xab4a, 0xab4a, 0xab4c, + 0xab4a, 0xab4c, 0xab4c, 0xab4a, 0xab4c, 0xab4a, 0xab4a, 0xab4a, + 0xab4a, 0xab4a, 0x9006, 0x0005, 0x9085, 0x0001, 0x0005, 0x9280, + 0x0008, 0x2004, 0x9084, 0x000f, 0x0002, 0xab63, 0xab63, 0xab63, + 0xab63, 0xab63, 0xab63, 0xab70, 0xab63, 0xab63, 0xab63, 0xab63, + 0xab63, 0xab63, 0xab63, 0x6007, 0x003b, 0x602f, 0x0009, 0x6017, + 0x2a00, 0x6003, 0x0001, 0x080c, 0x6886, 0x080c, 0x6d42, 0x0005, + 0x00c6, 0x2260, 0x080c, 0xad19, 0x6043, 0x0000, 0x6024, 0xc0f4, + 0xc0e4, 0x6026, 0x603b, 0x0000, 0x00ce, 0x00d6, 0x2268, 0x9186, + 0x0007, 0x1904, 0xabcb, 0x6814, 0x9005, 0x0138, 0x9080, 0x001f, + 0x2004, 0xd0fc, 0x1110, 0x00de, 0x08b0, 0x6007, 0x003a, 0x6003, + 0x0001, 0x080c, 0x6886, 0x080c, 0x6d42, 0x00c6, 0x2d60, 0x6100, + 0x9186, 0x0002, 0x1904, 0xac4e, 0x6014, 0x9005, 0x1138, 0x6000, + 0x9086, 0x0007, 0x190c, 0x0cf1, 0x0804, 0xac4e, 0x908c, 0xf000, + 0x1130, 0x0028, 0x2068, 0x6800, 0x9005, 0x1de0, 0x2d00, 0x9080, + 0x001f, 0x2004, 0x9084, 0x0003, 0x9086, 0x0002, 0x1180, 0x6014, + 0x2068, 0x687c, 0xc0dc, 0xc0f4, 0x687e, 0x6880, 0xc0f4, 0xc0fc, + 0x6882, 0x2009, 0x0043, 0x080c, 0xa528, 0x0804, 0xac4e, 0x2009, + 0x0041, 0x0804, 0xac48, 0x9186, 0x0005, 0x15c0, 0x6814, 0x9080, + 0x001f, 0x2004, 0xd0bc, 0x1118, 0x00de, 0x0804, 0xab63, 0xd0b4, + 0x0128, 0xd0fc, 0x090c, 0x0cf1, 0x0804, 0xab83, 0x6007, 0x003a, + 0x6003, 0x0001, 0x080c, 0x6886, 0x080c, 0x6d42, 0x00c6, 0x2d60, + 0x6100, 0x9186, 0x0002, 0x0120, 0x9186, 0x0004, 0x1904, 0xac4e, + 0x6814, 0x9080, 0x001f, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, + 0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x00f6, 0x2c78, 0x080c, + 0x119d, 0x00fe, 0x2009, 0x0042, 0x0804, 0xac48, 0x0036, 0x00d6, + 0x00d6, 0x080c, 0x0ddf, 0x003e, 0x090c, 0x0cf1, 0x6867, 0x010d, + 0x6803, 0x0000, 0x686b, 0x0000, 0x688b, 0x0000, 0x6b8e, 0x6887, + 0x0045, 0x2c00, 0x6892, 0x6038, 0x68a2, 0x2360, 0x6024, 0xc0dd, + 0x6026, 0x6010, 0x9080, 0x0028, 0x2004, 0x9084, 0x00ff, 0x8007, + 0x6354, 0x6b7a, 0x6876, 0x687f, 0x0000, 0x6883, 0x0000, 0x6d9a, + 0x6e96, 0x689f, 0x0001, 0x080c, 0x50a5, 0x2019, 0x0045, 0x6008, + 0x2068, 0x080c, 0xa6bc, 0x2d00, 0x600a, 0x6023, 0x0006, 0x6003, + 0x0007, 0x601b, 0x0000, 0x6043, 0x0000, 0x00de, 0x003e, 0x0038, + 0x6043, 0x0000, 0x6003, 0x0007, 0x080c, 0xa528, 0x00ce, 0x00de, + 0x0005, 0x9186, 0x0013, 0x1128, 0x6004, 0x9082, 0x0085, 0x2008, + 0x00c2, 0x9186, 0x0027, 0x1178, 0x080c, 0x6c56, 0x0036, 0x00d6, + 0x6014, 0x2068, 0x2019, 0x0004, 0x080c, 0xaa84, 0x00de, 0x003e, + 0x080c, 0x6d42, 0x0005, 0x9186, 0x0014, 0x0d70, 0x080c, 0x7f68, + 0x0005, 0xac7e, 0xac7c, 0xac7c, 0xac7c, 0xac7c, 0xac7c, 0xac7e, + 0xac7c, 0xac7c, 0xac7c, 0xac7c, 0x080c, 0x0cf1, 0x080c, 0x6c56, + 0x6003, 0x000c, 0x080c, 0x6d42, 0x0005, 0x9182, 0x0090, 0x1220, + 0x9182, 0x0085, 0x0208, 0x001a, 0x080c, 0x7f68, 0x0005, 0xac9a, + 0xac9a, 0xac9a, 0xac9a, 0xac9c, 0xacbc, 0xac9a, 0xac9a, 0xac9a, + 0xac9a, 0xac9a, 0x080c, 0x0cf1, 0x00d6, 0x2c68, 0x080c, 0x7ec8, + 0x01b0, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0x026e, 0x210c, + 0x613a, 0x2009, 0x026f, 0x210c, 0x613e, 0x600b, 0xffff, 0x6910, + 0x6112, 0x6023, 0x0004, 0x080c, 0x6886, 0x080c, 0x6d42, 0x2d60, + 0x080c, 0x7f1e, 0x00de, 0x0005, 0x080c, 0x7f1e, 0x0005, 0x00e6, + 0x6010, 0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x2009, 0x1172, + 0x210c, 0xd1ec, 0x0578, 0x6003, 0x0002, 0x6024, 0xc0e5, 0x6026, + 0xd0cc, 0x0150, 0x2001, 0x12a8, 0x2004, 0x6042, 0x2009, 0x1172, + 0x210c, 0xd1f4, 0x11e8, 0x0080, 0x2009, 0x1172, 0x210c, 0xd1f4, + 0x0128, 0x6024, 0xc0e4, 0x6026, 0x9006, 0x00a0, 0x2001, 0x12a8, + 0x200c, 0x8103, 0x9100, 0x6042, 0x6010, 0x9088, 0x002b, 0x2104, + 0x9005, 0x0118, 0x9088, 0x0003, 0x0cd0, 0x2c0a, 0x600f, 0x0000, + 0x9085, 0x0001, 0x0005, 0x0016, 0x00c6, 0x00e6, 0x6154, 0x92f0, + 0x002b, 0x2e04, 0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118, 0x6054, + 0x9106, 0x1138, 0x600c, 0x2072, 0x080c, 0x66ae, 0x080c, 0x7f1e, + 0x0010, 0x9cf0, 0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce, 0x001e, + 0x0005, 0x00d6, 0x6010, 0x90e8, 0x002b, 0x2d04, 0x9005, 0x0140, + 0x9c06, 0x0120, 0x2d04, 0x90e8, 0x0003, 0x0cb8, 0x600c, 0x206a, + 0x00de, 0x0005, 0x0026, 0x0036, 0x0156, 0x2011, 0x1127, 0x2204, + 0x9084, 0x00ff, 0x2019, 0x026e, 0x2334, 0x9636, 0x11d8, 0x8318, + 0x2334, 0x2204, 0x9084, 0xff00, 0x9636, 0x11a0, 0x2011, 0x0270, + 0x20a9, 0x0004, 0x6010, 0x9098, 0x000a, 0x080c, 0x8a45, 0x1150, + 0x2011, 0x0274, 0x20a9, 0x0004, 0x6010, 0x9098, 0x0006, 0x080c, + 0x8a45, 0x1100, 0x015e, 0x003e, 0x002e, 0x0005, 0x00e6, 0x2071, + 0x1100, 0x080c, 0x46bb, 0x080c, 0x23cd, 0x00ee, 0x0005, 0x00e6, + 0x6010, 0x2070, 0x7000, 0xd0fc, 0x0108, 0x0011, 0x00ee, 0x0005, + 0x6880, 0xc0e5, 0x6882, 0x0005, 0x00e6, 0x00c6, 0x0076, 0x0066, + 0x0056, 0x0046, 0x0026, 0x0016, 0x0126, 0x2091, 0x8000, 0x2029, + 0x12e5, 0x252c, 0x2021, 0x12eb, 0x2424, 0x2061, 0x15c0, 0x2071, + 0x1100, 0x7644, 0x7064, 0x9606, 0x0578, 0x6720, 0x9786, 0x0001, + 0x0118, 0x9786, 0x0008, 0x1500, 0x2500, 0x9c06, 0x01e8, 0x2400, + 0x9c06, 0x01d0, 0x080c, 0xaaf2, 0x01b8, 0x080c, 0xab02, 0x11a0, + 0x6000, 0x9086, 0x0004, 0x1120, 0x0016, 0x080c, 0x12c7, 0x001e, + 0x080c, 0x97bc, 0x1110, 0x080c, 0x25d1, 0x080c, 0x97cd, 0x1110, + 0x080c, 0x8576, 0x080c, 0x97a3, 0x9ce0, 0x0018, 0x2001, 0x1116, + 0x2004, 0x9c02, 0x1208, 0x0858, 0x012e, 0x001e, 0x002e, 0x004e, + 0x005e, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x0005, 0x0126, 0x0006, + 0x00e6, 0x2091, 0x8000, 0x2071, 0x1140, 0xd5a4, 0x0118, 0x7034, + 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, 0x7032, 0xd5ac, + 0x0118, 0x2071, 0x114a, 0x0451, 0x00ee, 0x000e, 0x012e, 0x0005, + 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0x1140, 0xd5a4, + 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, + 0x7032, 0xd5ac, 0x0118, 0x2071, 0x114a, 0x0081, 0x00ee, 0x000e, + 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, + 0x1142, 0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e04, 0x8000, + 0x2072, 0x1220, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x0005, 0x00e6, + 0x2071, 0x1140, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1144, + 0x0c69, 0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, + 0x2071, 0x1140, 0x7044, 0x8000, 0x7046, 0x00ee, 0x000e, 0x012e, + 0x0005, 0x8064, 0x0008, 0x0010, 0x0000, 0x8066, 0x0000, 0x0101, + 0x0008, 0x4404, 0x0003, 0x8060, 0x0000, 0x0400, 0x0000, 0x580a, + 0x0003, 0x791e, 0x0003, 0x507c, 0x0003, 0x4c07, 0x000b, 0xbac0, + 0x0009, 0x0082, 0x0008, 0x0c07, 0x0003, 0x15fe, 0x0008, 0x3407, + 0x000b, 0x808c, 0x0008, 0x0001, 0x0000, 0x0000, 0x0007, 0x4047, + 0x000a, 0x808c, 0x0008, 0x0002, 0x0000, 0x0819, 0x000b, 0x4022, + 0x0000, 0x001a, 0x0003, 0x4122, 0x0008, 0x0bfe, 0x0008, 0x11a0, + 0x0001, 0x11a5, 0x000b, 0x0ca0, 0x0001, 0x11a5, 0x000b, 0x9180, + 0x0001, 0x0005, 0x0008, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0019, + 0x0000, 0x4424, 0x000b, 0x0240, 0x0002, 0x099f, 0x000b, 0x00fe, + 0x0000, 0x31a2, 0x000b, 0x112a, 0x0000, 0x002e, 0x0008, 0x022c, + 0x0008, 0x3a44, 0x0002, 0x0c07, 0x0003, 0x1734, 0x0000, 0x1530, + 0x0000, 0x1632, 0x0008, 0x0d2a, 0x0008, 0x9a80, 0x0009, 0x000f, + 0x0008, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0011, 0x0008, 0x4437, + 0x0003, 0x808c, 0x0008, 0x0002, 0x0000, 0x01fe, 0x0008, 0x42e0, + 0x0009, 0x0d98, 0x000b, 0x00fe, 0x0000, 0x43e0, 0x0001, 0x0d98, + 0x000b, 0x9880, 0x0001, 0x0010, 0x0000, 0x7f62, 0x0008, 0x8066, + 0x0000, 0x1e0a, 0x0008, 0x4445, 0x0003, 0x808a, 0x0008, 0x0003, + 0x0008, 0x9a80, 0x0009, 0x0002, 0x0000, 0x7f62, 0x0008, 0x584b, + 0x0003, 0x8066, 0x0000, 0x3679, 0x0000, 0x444e, 0x000b, 0x584f, + 0x000b, 0x8054, 0x0008, 0x0011, 0x0008, 0x8074, 0x0000, 0x1010, + 0x0008, 0x1efe, 0x0000, 0x3007, 0x0003, 0x0058, 0x000c, 0x0007, + 0x0003, 0x1cfe, 0x0008, 0x1b80, 0x0009, 0x7f62, 0x0008, 0x8066, + 0x0000, 0x0231, 0x0008, 0x445d, 0x0003, 0x585e, 0x000b, 0x0140, + 0x0008, 0x0140, 0x0008, 0x0242, 0x0000, 0x0242, 0x0000, 0x1f43, + 0x0002, 0x0c6e, 0x0003, 0x0d44, 0x0000, 0x0d44, 0x0000, 0x0d46, + 0x0008, 0x0d46, 0x0008, 0x0348, 0x0008, 0x0348, 0x0008, 0x044a, + 0x0008, 0x044a, 0x0008, 0x0076, 0x0003, 0x0344, 0x0008, 0x0344, + 0x0008, 0x0446, 0x0008, 0x0446, 0x0008, 0x0548, 0x0008, 0x0548, + 0x0008, 0x064a, 0x0000, 0x064a, 0x0000, 0x5876, 0x000b, 0x8054, + 0x0008, 0x0001, 0x0000, 0x8074, 0x0000, 0x2020, 0x0008, 0x4000, + 0x000f, 0x3a40, 0x000a, 0x0c0a, 0x000b, 0x2b24, 0x0008, 0x2b24, + 0x0008, 0x5880, 0x000b, 0x8054, 0x0008, 0x0002, 0x0000, 0x1242, + 0x0002, 0x08ca, 0x0003, 0x3a45, 0x000a, 0x08bb, 0x0003, 0x1e10, + 0x000a, 0x7f3c, 0x0000, 0x08b8, 0x0003, 0x1d00, 0x0002, 0x7f3a, + 0x0000, 0x0d60, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, + 0x0008, 0x4490, 0x000b, 0x8060, 0x0000, 0x0400, 0x0000, 0x00fe, + 0x0000, 0x34b5, 0x000b, 0x1cfe, 0x0008, 0xff80, 0x0009, 0x0001, + 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, 0x0008, 0x449b, + 0x0003, 0x00fe, 0x0000, 0x318b, 0x0003, 0x0038, 0x0000, 0x00fe, + 0x0000, 0xff80, 0x0009, 0x0019, 0x0000, 0x7f62, 0x0008, 0x8066, + 0x0000, 0x0009, 0x0008, 0x44a5, 0x000b, 0x80c0, 0x0009, 0x00ff, + 0x0008, 0x7f3e, 0x0008, 0x0d60, 0x0000, 0x0efe, 0x0008, 0x1f80, + 0x0001, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, 0x0008, 0x44af, + 0x000b, 0x8060, 0x0000, 0x0400, 0x0000, 0x003a, 0x0008, 0x1dfe, + 0x0000, 0x008c, 0x0003, 0x0036, 0x0008, 0x0058, 0x000c, 0x00ca, + 0x000b, 0x8074, 0x0000, 0x2000, 0x0000, 0x00ca, 0x000b, 0x3a44, + 0x0002, 0x09a8, 0x0003, 0x8074, 0x0000, 0x1000, 0x0000, 0x2d0e, + 0x0000, 0x2d0e, 0x0000, 0x358b, 0x000b, 0x26fe, 0x0008, 0x26fe, + 0x0008, 0x2700, 0x0008, 0x2700, 0x0008, 0x00d0, 0x0009, 0x0cd8, + 0x000b, 0x8074, 0x0000, 0x4040, 0x0008, 0x58ca, 0x0003, 0x507c, + 0x0003, 0x3a46, 0x000a, 0x0cd8, 0x000b, 0x3a47, 0x0002, 0x08d5, + 0x000b, 0x8054, 0x0008, 0x0004, 0x0000, 0x8074, 0x0000, 0x8000, + 0x0000, 0x0112, 0x0003, 0x92c0, 0x0009, 0x0f88, 0x0008, 0x0807, + 0x000b, 0x9a80, 0x0009, 0x0002, 0x0000, 0x7f62, 0x0008, 0x8066, + 0x0000, 0x362a, 0x0000, 0x44dd, 0x000b, 0x2000, 0x0000, 0x2000, + 0x0000, 0x2102, 0x0000, 0x2102, 0x0000, 0x2204, 0x0000, 0x2204, + 0x0000, 0x2306, 0x0000, 0x2306, 0x0000, 0x2408, 0x0000, 0x2408, + 0x0000, 0x250a, 0x0000, 0x250a, 0x0000, 0x260c, 0x0000, 0x260c, + 0x0000, 0x270e, 0x0000, 0x270e, 0x0000, 0x2810, 0x0000, 0x2810, + 0x0000, 0x2912, 0x0000, 0x2912, 0x0000, 0x9a80, 0x0009, 0x0007, + 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0052, 0x0000, 0x44f7, + 0x0003, 0x92c0, 0x0009, 0x0780, 0x0008, 0x0d92, 0x000b, 0x124b, + 0x0002, 0x0900, 0x000b, 0x2e4d, 0x0002, 0x2e4d, 0x0002, 0x098b, + 0x000b, 0x5900, 0x000b, 0x8054, 0x0008, 0x0004, 0x0000, 0x3a46, + 0x000a, 0x0d0d, 0x000b, 0x1243, 0x000a, 0x0910, 0x0003, 0x8010, + 0x0008, 0x000d, 0x0000, 0x017c, 0x0004, 0x1810, 0x0000, 0x017c, + 0x0004, 0x0110, 0x000b, 0x0173, 0x0004, 0x1810, 0x0000, 0x017c, + 0x0004, 0x8074, 0x0000, 0xf000, 0x0008, 0x3a42, 0x0002, 0x0d18, + 0x0003, 0x15fe, 0x0008, 0x342e, 0x0003, 0x0d30, 0x0000, 0x0007, + 0x0003, 0x8074, 0x0000, 0x0501, 0x0000, 0x8010, 0x0008, 0x000c, + 0x0008, 0x017c, 0x0004, 0x0007, 0x0003, 0xbbe0, 0x0009, 0x0030, + 0x0008, 0x0d2e, 0x0003, 0x18fe, 0x0000, 0x3ce0, 0x0009, 0x092b, + 0x000b, 0x15fe, 0x0008, 0x3ce0, 0x0009, 0x092b, 0x000b, 0x016e, + 0x0004, 0x8076, 0x0008, 0x0040, 0x0000, 0x016b, 0x000b, 0x8076, + 0x0008, 0x0041, 0x0008, 0x016b, 0x000b, 0xbbe0, 0x0009, 0x0032, + 0x0000, 0x0d33, 0x0003, 0x3c1e, 0x0008, 0x016b, 0x000b, 0xbbe0, + 0x0009, 0x0037, 0x0000, 0x0d50, 0x0003, 0x18fe, 0x0000, 0x3ce0, + 0x0009, 0x0d2b, 0x0003, 0x1afe, 0x0008, 0xff80, 0x0009, 0x000d, + 0x0000, 0x7f62, 0x0008, 0x2604, 0x0008, 0x2604, 0x0008, 0x2706, + 0x0008, 0x2706, 0x0008, 0x2808, 0x0000, 0x2808, 0x0000, 0x290a, + 0x0000, 0x290a, 0x0000, 0x8066, 0x0000, 0x0422, 0x0000, 0x4547, + 0x0003, 0x0173, 0x0004, 0x8054, 0x0008, 0x0004, 0x0000, 0x8074, + 0x0000, 0xf000, 0x0008, 0x8072, 0x0000, 0x8000, 0x0000, 0x0112, + 0x0003, 0xbbe0, 0x0009, 0x0038, 0x0000, 0x0d62, 0x000b, 0x18fe, + 0x0000, 0x3ce0, 0x0009, 0x095f, 0x000b, 0x15fe, 0x0008, 0x3ce0, + 0x0009, 0x0d27, 0x0003, 0x016e, 0x0004, 0x8076, 0x0008, 0x0040, + 0x0000, 0x8072, 0x0000, 0x8000, 0x0000, 0x019f, 0x0003, 0x8076, + 0x0008, 0x0042, 0x0008, 0x016b, 0x000b, 0xbbe0, 0x0009, 0x0016, + 0x0000, 0x0d6b, 0x000b, 0x3a44, 0x0002, 0x0c09, 0x000b, 0x8072, + 0x0000, 0x8000, 0x0000, 0x8000, 0x000f, 0x0007, 0x0003, 0x8072, + 0x0000, 0x8000, 0x0000, 0x0007, 0x0003, 0x3d30, 0x000a, 0x7f00, + 0x0000, 0xbc80, 0x0001, 0x0007, 0x0000, 0x0177, 0x0003, 0x1930, + 0x000a, 0x7f00, 0x0000, 0x9880, 0x0001, 0x0007, 0x0000, 0x7f62, + 0x0008, 0x8066, 0x0000, 0x000a, 0x0008, 0x457a, 0x000b, 0x4000, + 0x000f, 0x217c, 0x0003, 0x0870, 0x0008, 0x4000, 0x000f, 0xbac0, + 0x0009, 0x0090, 0x0008, 0x0985, 0x0003, 0x8074, 0x0000, 0x0706, + 0x0000, 0x0187, 0x0003, 0x8074, 0x0000, 0x0703, 0x0000, 0x4000, + 0x000f, 0x8010, 0x0008, 0x0008, 0x0000, 0x01ad, 0x000b, 0x0173, + 0x0004, 0x8010, 0x0008, 0x0007, 0x0000, 0x017c, 0x0004, 0x1810, + 0x0000, 0x017c, 0x0004, 0x01b7, 0x0003, 0x8010, 0x0008, 0x0009, + 0x0008, 0x01ad, 0x000b, 0x8010, 0x0008, 0x0005, 0x0008, 0x01ad, + 0x000b, 0x808c, 0x0008, 0x0001, 0x0000, 0x8010, 0x0008, 0x0004, + 0x0000, 0x4143, 0x000a, 0x0840, 0x000b, 0x01ad, 0x000b, 0x8010, + 0x0008, 0x0003, 0x0008, 0x01af, 0x0003, 0x8010, 0x0008, 0x000b, + 0x0000, 0x01af, 0x0003, 0x8010, 0x0008, 0x0002, 0x0000, 0x01af, + 0x0003, 0x3a47, 0x0002, 0x0cca, 0x000b, 0x8010, 0x0008, 0x0006, + 0x0008, 0x01af, 0x0003, 0x8074, 0x0000, 0xf000, 0x0008, 0x017c, + 0x0004, 0x017f, 0x0004, 0x3a40, 0x000a, 0x0807, 0x000b, 0x8010, + 0x0008, 0x000c, 0x0008, 0x017c, 0x0004, 0x0007, 0x0003, 0x8074, + 0x0000, 0xf080, 0x0000, 0x0d30, 0x0000, 0x2e4d, 0x0002, 0x2e4d, + 0x0002, 0x09c0, 0x000b, 0x8054, 0x0008, 0x0019, 0x0000, 0x0007, + 0x0003, 0x8054, 0x0008, 0x0009, 0x0008, 0x0007, 0x0003, 0x0001, + 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, + 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0xbb4d +}; +#ifdef UNIQUE_FW_NAME +unsigned short fw2300tp_length01 = 0xa9b8; +#else +unsigned short risc_code_length01 = 0xa9b8; +#endif + diff -Nur linux-2.4.19/drivers/scsi/qla1280.c linux-2.4.19-sgi211r3/drivers/scsi/qla1280.c --- linux-2.4.19/drivers/scsi/qla1280.c Sun Sep 30 12:26:07 2001 +++ linux-2.4.19-sgi211r3/drivers/scsi/qla1280.c Tue Jan 8 17:05:38 2002 @@ -1,162 +1,110 @@ /******************************************************************************** - * QLOGIC LINUX SOFTWARE - * - * QLogic ISP1x80/1x160 device driver for Linux 2.3.x (redhat 6.X). - * - * COPYRIGHT (C) 1999-2000 QLOGIC CORPORATION - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the Qlogic's Linux Software License. See below. - * - * This program is WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistribution's or 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. - * - ********************************************************************************/ - -/***************************************************************************************** - QLOGIC CORPORATION SOFTWARE - "GNU" GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION - AND MODIFICATION - -This GNU General Public License ("License") applies solely to QLogic Linux -Software ("Software") and may be distributed under the terms of this License. - -1. You may copy and distribute verbatim copies of the Software's source code as -you receive it, in any medium, provided that you conspicuously and appropriately -publish on each copy an appropriate copyright notice and disclaimer of warranty; -keep intact all the notices that refer to this License and to the absence of any -warranty; and give any other recipients of the Software a copy of this License along -with the Software. - -You may charge a fee for the physical act of transferring a copy, and you may at your -option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Software or any portion of it, thus forming -a work based on the Software, and copy and distribute such modifications or work under -the terms of Section 1 above, provided that you also meet all of these conditions: - -* a) You must cause the modified files to carry prominent notices stating that you -changed the files and the date of any change. - -* b) You must cause any work that you distribute or publish that in whole or in part -contains or is derived from the Software or any part thereof, to be licensed as a -whole at no charge to all third parties under the terms of this License. - -* c) If the modified Software normally reads commands interactively when run, you -must cause it, when started running for such interactive use in the most ordinary way, -to print or display an announcement including an appropriate copyright notice and a -notice that there is no warranty (or else, saying that you provide a warranty) and that -users may redistribute the Software under these conditions, and telling the user how to -view a copy of this License. (Exception:if the Software itself is interactive but does -not normally print such an announcement, your work based on the Software is not required -to print an announcement.) - -These requirements apply to the modified work as a whole. If identifiable sections of -that work are not derived from the Software, and can be reasonably considered independent -and separate works in themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you distribute the same -sections as part of a whole which is a work based on the Software, the distribution of the -whole must be on the terms of this License, whose permissions for other licensees extend -to the entire whole, and thus to each and every part regardless of who wrote it. - -3. You may copy and distribute the Software (or a work based on it, under Section 2) in -object code or executable form under the terms of Sections 1 and 2 above provided that -you also do one of the following: - -* a) Accompany it with the complete corresponding machine-readable source code, which must -be distributed under the terms of Sections 1 and 2 above on a medium customarily used for -software interchange; or, - -* b) Accompany it with a written offer, valid for at least three years, to give any third -party, for a charge no more than your cost of physically performing source distribution, -a complete machine-readable copy of the corresponding source code, to be distributed under -the terms of Sections 1 and 2 above on a medium customarily used for software interchange; -or, - -* c) Accompany it with the information you received as to the offer to distribute -corresponding source code. (This alternative is allowed only for noncommercial distribution -and only if you received the Software in object code or executable form with such an offer, -in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for making modifications -to it. For an executable work, complete source code means all the source code for all -modules it contains, plus any associated interface definition files, plus the scripts used -to control compilation and installation of the executable. - -If distribution of executable or object code is made by offering access to copy from a -designated place, then offering equivalent access to copy the source code from the same -place counts as distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Software except as expressly -provided under this License. Any attempt otherwise to copy, modify, sublicense or -distribute the Software is void, and will automatically terminate your rights under this -License. However, parties who have received copies, or rights, from you under this License -will not have their licenses terminated so long as such parties remain in full compliance. - -5. This license grants you world wide, royalty free non-exclusive rights to modify or -distribute the Software or its derivative works. These actions are prohibited by law -if you do not accept this License. Therefore, by modifying or distributing the Software -(or any work based on the Software), you indicate your acceptance of this License to do -so, and all its terms and conditions for copying, distributing or modifying the Software -or works based on it. - -6. Each time you redistribute the Software (or any work based on the Software), the -recipient automatically receives a license from the original licensor to copy, distribute -or modify the Software subject to these terms and conditions. You may not impose any -further restrictions on the recipients' exercise of the rights granted herein. You are -not responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent infringement or for -any other reason (not limited to patent issues), conditions are imposed on you -(whether by court order, agreement or otherwise) that contradict the conditions of this -License, they do not excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this License -and any other pertinent obligations, then as a consequence you may not distribute the -Software at all. - -If any portion of this section is held invalid or unenforceable under any particular -circumstance, the balance of the section is intended to apply and the section as a whole -is intended to apply in other circumstances. -NO WARRANTY - -11. THE SOFTWARE IS PROVIDED WITHOUT A WARRANTY OF ANY KIND. THERE IS NO -WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. -SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR -DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL -DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING -BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR -LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO -OPERATE WITH ANY OTHER SOFTWARES), EVEN IF SUCH HOLDER OR OTHER PARTY HAS -BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -END OF TERMS AND CONDITIONS - -*******************************************************************************************/ - +* QLOGIC LINUX SOFTWARE +* +* QLogic QLA1280 (Ultra2) and QLA12160 (Ultra3) SCSI driver +* Copyright (C) 2000 Qlogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +** +******************************************************************************/ +#define QLA1280_VERSION "3.23 Beta" /**************************************************************************** Revision History: - Rev. 3.00 Jan 17, 1999 DG Qlogic + Rev 3.23 Beta January 11, 2001 BN Qlogic + - Added check of device_id when handling non + QLA12160s during detect(). + Rev 3.22 Beta January 5, 2001 BN Qlogic + - Changed queue_task() to schedule_task() + for kernels 2.4.0 and higher. + Note: 2.4.0-testxx kernels released prior to + the actual 2.4.0 kernel release on January 2001 + will get compile/link errors with schedule_task(). + Please update your kernel to released 2.4.0 level, + or comment lines in this file flagged with 3.22 + to resolve compile/link error of schedule_task(). + - Added -DCONFIG_SMP in addition to -D__SMP__ + in Makefile for 2.4.0 builds of driver as module. + Rev 3.21 Beta January 4, 2001 BN Qlogic + - Changed criteria of 64/32 Bit mode of HBA + operation according to BITS_PER_LONG rather + than HBA's NVRAM setting of >4Gig memory bit; + so that the HBA auto-configures without the need + to setup each system individually. + Rev 3.20 Beta December 5, 2000 BN Qlogic + - Added priority handling to IA-64 onboard SCSI + ISP12160 chip for kernels greater than 2.3.18. + - Added irqrestore for qla1280_intr_handler. + - Enabled /proc/scsi/qla1280 interface. + - Clear /proc/scsi/qla1280 counters in detect(). + Rev 3.19 Beta October 13, 2000 BN Qlogic + - Declare driver_template for new kernel + (2.4.0 and greater) scsi initialization scheme. + - Update /proc/scsi entry for 2.3.18 kernels and + above as qla1280 + Rev 3.18 Beta October 10, 2000 BN Qlogic + - Changed scan order of adapters to map + the QLA12160 followed by the QLA1280. + Rev 3.17 Beta September 18, 2000 BN Qlogic + - Removed warnings for 32 bit 2.4.x compiles + - Corrected declared size for request and response + DMA addresses that are kept in each ha + Rev. 3.16 Beta August 25, 2000 BN Qlogic + - Corrected 64 bit addressing issue on IA-64 + where the upper 32 bits were not properly + passed to the RISC engine. + Rev. 3.15 Beta August 22, 2000 BN Qlogic + - Modified qla1280_setup_chip to properly load + ISP firmware for greater that 4 Gig memory on IA-64 + Rev. 3.14 Beta August 16, 2000 BN Qlogic + - Added setting of dma_mask to full 64 bit + if flags.enable_64bit_addressing is set in NVRAM + Rev. 3.13 Beta August 16, 2000 BN Qlogic + - Use new PCI DMA mapping APIs for 2.4.x kernel + Rev. 3.12 July 18, 2000 Redhat & BN Qlogic + - Added check of pci_enable_device to detect() for 2.3.x + - Use pci_resource_start() instead of + pdev->resource[0].start in detect() for 2.3.x + - Updated driver version + Rev. 3.11 July 14, 2000 BN Qlogic + - Updated SCSI Firmware to following versions: + qla1x80: 8.13.08 + qla1x160: 10.04.08 + - Updated driver version to 3.11 + Rev. 3.10 June 23, 2000 BN Qlogic + - Added filtering of AMI SubSys Vendor ID devices + Rev. 3.9 + - DEBUG_QLA1280 undefined and new version BN Qlogic + Rev. 3.08b May 9, 2000 MD Dell + - Added logic to check against AMI subsystem vendor ID + Rev. 3.08 May 4, 2000 DG Qlogic + - Added logic to check for PCI subsystem ID. + Rev. 3.07 Apr 24, 2000 DG & BN Qlogic + - Updated SCSI Firmware to following versions: + qla12160: 10.01.19 + qla1280: 8.09.00 + Rev. 3.06 Apr 12, 2000 DG & BN Qlogic + - Internal revision; not released + Rev. 3.05 Mar 28, 2000 DG & BN Qlogic + - Edit correction for virt_to_bus and PROC. + Rev. 3.04 Mar 28, 2000 DG & BN Qlogic + - Merge changes from ia64 port. + Rev. 3.03 Mar 28, 2000 BN Qlogic + - Increase version to reflect new code drop with compile fix + of issue with inclusion of linux/spinlock for 2.3 kernels + Rev. 3.02 Mar 15, 2000 BN Qlogic + - Merge qla1280_proc_info from 2.10 code base + Rev. 3.01 Feb 10, 2000 BN Qlogic + - Corrected code to compile on a 2.2.x kernel. + Rev. 3.00 Jan 17, 2000 DG Qlogic - Added 64-bit support. Rev. 2.07 Nov 9, 1999 DG Qlogic - Added new routine to set target parameters for ISP12160. @@ -183,12 +131,11 @@ *****************************************************************************/ +#include #ifdef MODULE #include #endif -#define QLA1280_VERSION " 3.00-Beta" - #include #include #include @@ -207,8 +154,16 @@ #include #include #include -/* MRS #include */ +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) +#include +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +#include # include #endif #include "sd.h" @@ -216,23 +171,16 @@ #include "hosts.h" #define UNIQUE_FW_NAME #include "qla1280.h" -#include "ql12160_fw.h" /* ISP RISC code */ +#include "ql12160_fw.h" /* ISP RISC codes */ #include "ql1280_fw.h" #include -#include /* for kmalloc() */ - - -#ifndef KERNEL_VERSION -# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) -#endif - +#include /* * Compile time Options: * 0 - Disable and 1 - Enable */ -#define QLA1280_64BIT_SUPPORT 1 /* 64-bit Support */ #define QL1280_TARGET_MODE_SUPPORT 0 /* Target mode support */ #define WATCHDOGTIMER 0 #define MEMORY_MAPPED_IO 0 @@ -244,15 +192,9 @@ #define AUTO_ESCALATE_ABORT 0 /* Automatically escalate aborts */ #define STOP_ON_ERROR 0 /* Stop on aborts and resets */ #define STOP_ON_RESET 0 -#define STOP_ON_ABORT 0 -#undef DYNAMIC_MEM_ALLOC - -#define DEBUG_QLA1280 0 /* Debugging */ -/* #define CHECKSRBSIZE */ - -/* - * These macros to assist programming - */ +#define STOP_ON_ABORT 0 +#define QLA1280_PROFILE 1 /* 3.20 */ +#define DEBUG_QLA1280 0 #define BZERO(ptr, amt) memset(ptr, 0, amt) #define BCOPY(src, dst, amt) memcpy(dst, src, amt) @@ -260,19 +202,28 @@ #define KMFREE(ip,siz) kfree((ip)) #define SYS_DELAY(x) udelay(x);barrier() #define QLA1280_DELAY(sec) mdelay(sec * 1000) -#define VIRT_TO_BUS(a) virt_to_bus((a)) -#if QLA1280_64BIT_SUPPORT + +/* 3.16 */ +#if BITS_PER_LONG > 32 +#define pci_dma_lo32(a) (a & 0xffffffff) +#define pci_dma_hi32(a) ((a >> 32) & 0xffffffff) +#else +#define pci_dma_lo32(a) (a & 0xffffffff) +#define pci_dma_hi32(a) 0 +#endif + +#define VIRT_TO_BUS(a) virt_to_bus(((void *)a)) + #if BITS_PER_LONG <= 32 -#define VIRT_TO_BUS_LOW(a) (uint32_t)virt_to_bus((a)) +#define VIRT_TO_BUS_LOW(a) (uint32_t)virt_to_bus(((void *)a)) #define VIRT_TO_BUS_HIGH(a) (uint32_t)(0x0) #else -#define VIRT_TO_BUS_LOW(a) (uint32_t)(0xffffffff & virt_to_bus((a))) -#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0xffffffff & (virt_to_bus((a))>>32)) +#define VIRT_TO_BUS_LOW(a) (uint32_t)(0xffffffff & virt_to_bus((void *)(a))) +#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0xffffffff & (virt_to_bus((void *)(a))>>32)) #endif -#endif /* QLA1280_64BIT_SUPPORT */ -#define STATIC +#define STATIC #define NVRAM_DELAY() udelay(500) /* 2 microsecond delay */ void qla1280_device_queue_depth(scsi_qla_host_t *, Scsi_Device *); @@ -285,11 +236,11 @@ #define LSB(x) (uint8_t)(x) #if BITS_PER_LONG <= 32 -#define LS_64BITS(x) (uint32_t)(x) -#define MS_64BITS(x) (uint32_t)(0x0) +#define LS_64BITS(x) (uint32_t)((unsigned long) x) +#define MS_64BITS(x) (uint32_t)((unsigned long) 0x0) #else -#define LS_64BITS(x) (uint32_t)(0xffffffff & (x)) -#define MS_64BITS(x) (uint32_t)(0xffffffff & ((x)>>32) ) +#define LS_64BITS(x) (uint32_t)(0xffffffff & ((unsigned long)x)) +#define MS_64BITS(x) (uint32_t)(0xffffffff & (((unsigned long)x)>>32) ) #endif /* @@ -300,9 +251,6 @@ STATIC void qla1280_putq_t(scsi_lu_t *, srb_t *); STATIC void qla1280_done_q_put(srb_t *, srb_t **, srb_t **); STATIC void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *); -#ifdef QLA1280_UNUSED -static void qla1280_dump_regs(struct Scsi_Host *host); -#endif #if STOP_ON_ERROR static void qla1280_panic(char *, struct Scsi_Host *host); #endif @@ -312,10 +260,7 @@ STATIC int qla1280_return_status( sts_entry_t *sts, Scsi_Cmnd *cp); STATIC void qla1280_removeq(scsi_lu_t *q, srb_t *sp); STATIC void qla1280_mem_free(scsi_qla_host_t *ha); -static void qla1280_do_dpc(void *p); -#ifdef QLA1280_UNUSED -static void qla1280_set_flags(char * s); -#endif +void qla1280_do_dpc(void *p); static char *qla1280_get_token(char *, char *); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) STATIC inline void mdelay(int); @@ -339,9 +284,7 @@ STATIC uint8_t qla1280_device_reset(scsi_qla_host_t *, uint8_t, uint32_t); STATIC uint8_t qla1280_abort_device(scsi_qla_host_t *, uint8_t, uint32_t, uint32_t); STATIC uint8_t qla1280_abort_command(scsi_qla_host_t *, srb_t *), -#if QLA1280_64BIT_SUPPORT qla1280_64bit_start_scsi(scsi_qla_host_t *, srb_t *), -#endif qla1280_32bit_start_scsi(scsi_qla_host_t *, srb_t *), qla1280_abort_isp(scsi_qla_host_t *); STATIC void qla1280_nv_write(scsi_qla_host_t *, uint16_t), @@ -374,12 +317,12 @@ qla1280_notify_ack(scsi_qla_host_t *, notify_entry_t *), qla1280_immed_notify(scsi_qla_host_t *, notify_entry_t *), qla1280_accept_io(scsi_qla_host_t *, ctio_ret_entry_t *), -#if QLA1280_64BIT_SUPPORT - qla1280_64bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, - paddr32_t *), -#endif - qla1280_32bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, - paddr32_t *), + qla1280_64bit_continue_io(scsi_qla_host_t *, + atio_entry_t *, uint32_t, + paddr32_t *), + qla1280_32bit_continue_io(scsi_qla_host_t *, + atio_entry_t *, uint32_t, + paddr32_t *), qla1280_atio_entry(scsi_qla_host_t *, atio_entry_t *), qla1280_notify_entry(scsi_qla_host_t *, notify_entry_t *); #endif /* QLA1280_TARGET_MODE_SUPPORT */ @@ -400,7 +343,7 @@ qla1280_dump_buffer(caddr_t, uint32_t); char debug_buff[80]; -#if DEBUG_QLA1280 +#if DEBUG_QLA1280 STATIC uint8_t ql_debug_print = 1; #else STATIC uint8_t ql_debug_print = 0; @@ -426,6 +369,22 @@ #endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) +/* + * Our directory Entry in /proc/scsi for the user to + * access the driver. + */ +/* Need to add in proc_fs.h PROC_SCSI_QL1280 */ +#define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP + +struct proc_dir_entry proc_scsi_qla1280 = { + PROC_SCSI_QL1280, 7, "qla1280", + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +#endif + /* We use the Scsi_Pointer structure that's included with each command * SCSI_Cmnd as a scratchpad for our SRB. * @@ -471,17 +430,17 @@ unsigned char *fwver; /* Ptr to F/W version array */ } qla_boards_t; -struct _qlaboards QLBoardTbl[NUM_OF_ISP_DEVICES] = +struct _qlaboards QL1280BoardTbl[NUM_OF_ISP_DEVICES] = { /* Name , Board PCI Device ID, Number of ports */ + {"QLA12160 ", QLA12160_DEVICE_ID, 2, + &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, {"QLA1080 ", QLA1080_DEVICE_ID, 1, &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, {"QLA1240 ", QLA1240_DEVICE_ID, 2, &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, {"QLA1280 ", QLA1280_DEVICE_ID, 2, &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, - {"QLA12160 ", QLA12160_DEVICE_ID, 2, - &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, {"QLA10160 ", QLA10160_DEVICE_ID, 1, &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, {" ", 0, 0} @@ -489,7 +448,7 @@ static unsigned long qla1280_verbose = 1L; static scsi_qla_host_t *qla1280_hostlist = NULL; -#ifdef QLA1280_PROFILE +#if QLA1280_PROFILE static int qla1280_buffer_size = 0; static char *qla1280_buffer = NULL; #endif @@ -567,152 +526,153 @@ * * Returns: *************************************************************************/ -#ifdef QLA1280_PROFILE -#define PROC_BUF (&qla1280_buffer[size]) -#define LUN_ID (targ_lun>>(MAX_T_BITS+MAX_L_BITS)),((targ_lun>>MAX_L_BITS)&0xf), targ_lun&0x7 -#endif +#define PROC_BUF (&qla1280_buffer[len]) int -qla1280_proc_info ( char *buffer, char **start, off_t offset, int length, - int hostno, int inout) -{ -#ifdef QLA1280_PROFILE +qla1280_proc_info( char *buffer, char **start, off_t offset, int length, + int hostno, int inout) { +#if QLA1280_PROFILE struct Scsi_Host *host; scsi_qla_host_t *ha; int size = 0; - int targ_lun; scsi_lu_t *up; - int no_devices; - - printk("Entering proc_info 0x%p,0x%lx,0x%x,0x%x\n",buffer,offset,length,hostno); + int len = 0; + qla_boards_t *bdp; + uint32_t b, t, l; + uint8_t *temp; host = NULL; - /* find the host they want to look at */ - for(ha=qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno; ha=ha->next) + + /* Find the host that was specified */ + for( ha=qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno; ha=ha->next ) ; - if (!ha) - { - size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); - if (size > length) - { + /* if host wasn't found then exit */ + if( !ha ) { + size = sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if( size > length ) { return (size); - } - else - { - return (length); + } else { + return (0); } } host = ha->host; - if (inout == TRUE) /* Has data been written to the file? */ - { - return (qla1280_set_info(buffer, length, host)); - } - /* compute number of active devices */ - no_devices = 0; - for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++) + if( inout == TRUE ) /* Has data been written to the file? */ { - if( (up = ha->dev[targ_lun]) == NULL ) - continue; - no_devices++; + printk("qla1280_proc: has data been written to the file. \n"); + return (qla1280_set_info(buffer, length, host)); } - /* size = 112 * no_devices; */ - size = 4096; - /* round up to the next page */ /* * if our old buffer is the right size use it otherwise * allocate a new one. */ - if (qla1280_buffer_size != size) - { + size = 4096; /* get a page */ + if( qla1280_buffer_size != size ) { /* deallocate this buffer and get a new one */ - if (qla1280_buffer != NULL) - { + if( qla1280_buffer != NULL ) { kfree(qla1280_buffer); qla1280_buffer_size = 0; } qla1280_buffer = kmalloc(size, GFP_KERNEL); } - if (qla1280_buffer == NULL) - { + if( qla1280_buffer == NULL ) { size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n", __LINE__); return size; } + /* save the size of our buffer */ qla1280_buffer_size = size; - size = 0; - size += sprintf(PROC_BUF, "Qlogic 1280/1080 SCSI driver version: "); /* 43 bytes */ - size += sprintf(PROC_BUF, "%5s, ", QLA1280_VERSION); /* 5 */ - size += sprintf(PROC_BUF, "Qlogic Firmware version: "); /* 25 */ - size += sprintf(PROC_BUF, "%2d.%2d.%2d",_firmware_version[0], /* 8 */ - ql12_firmware_version[1], - ql12_firmware_version[2]); - size += sprintf(PROC_BUF, "\n"); /* 1 */ - - size += sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", QLBoardTbl[ha->devnum].bdName); - size += sprintf(PROC_BUF, "Request Queue = 0x%lx, Response Queue = 0x%lx\n", - ha->request_dma, - ha->response_dma); - size += sprintf(PROC_BUF, "Request Queue count= 0x%x, Response Queue count= 0x%x\n", + /* 3.20 clear the buffer we use for proc display */ + temp = qla1280_buffer; + for (b=0 ; b < size; b++) *(temp+b) = 0; + + /* start building the print buffer */ + bdp = &QL1280BoardTbl[ha->devnum]; + size = sprintf(PROC_BUF, + "QLogic PCI to SCSI Adapter for ISP 1280/12160:\n" + " Firmware version: %2d.%02d.%02d, Driver version %s\n", bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], QLA1280_VERSION); + + len += size; + + size = sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", bdp->bdName); + len += size; + size = sprintf(PROC_BUF, "Request Queue = 0x%lx, Response Queue = 0x%lx\n", + (unsigned long) ha->request_dma, + (unsigned long) ha->response_dma); + len += size; + size = sprintf(PROC_BUF, "Request Queue count= 0x%x, Response Queue count= 0x%x\n", REQUEST_ENTRY_CNT, RESPONSE_ENTRY_CNT); - size += sprintf(PROC_BUF,"Number of pending commands = 0x%lx\n", ha->actthreads); - size += sprintf(PROC_BUF,"Number of queued commands = 0x%lx\n", ha->qthreads); - size += sprintf(PROC_BUF,"Number of free request entries = %d\n",ha->req_q_cnt); - size += sprintf(PROC_BUF, "\n"); /* 1 */ + len += size; + size = sprintf(PROC_BUF, "Number of pending commands = 0x%lx\n", ha->actthreads); + len += size; + size = sprintf(PROC_BUF, "Number of queued commands = 0x%lx\n", ha->qthreads); + len += size; + size = sprintf(PROC_BUF, "Number of free request entries = %d\n",ha->req_q_cnt); + len += size; + size = sprintf(PROC_BUF, "\n"); /* 1 */ + len += size; - size += sprintf(PROC_BUF, "Attached devices:\n"); + size = sprintf(PROC_BUF, "SCSI device Information:\n"); + len += size; /* scan for all equipment stats */ - for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++) - { - if( (up = ha->dev[targ_lun]) == NULL ) + for (b = 0; b < MAX_BUSES; b++) + for (t = 0; t < MAX_TARGETS; t++) { + for( l = 0; l < MAX_LUNS; l++ ) { + up = (scsi_lu_t *) LU_Q(ha, b, t, l); + if( up == NULL ) continue; - if( up->io_cnt == 0 ) - { - size += sprintf(PROC_BUF,"(%2d:%2d:%2d) No stats\n",LUN_ID); + /* unused device/lun */ + if( up->io_cnt == 0 || up->io_cnt < 2 ) continue; - } /* total reads since boot */ /* total writes since boot */ /* total requests since boot */ - size += sprintf(PROC_BUF, "Total requests %ld,",up->io_cnt); + size = sprintf(PROC_BUF, "(%2d:%2d:%2d): Total reqs %ld,",b,t,l,up->io_cnt); + len += size; /* current number of pending requests */ - size += sprintf(PROC_BUF, "(%2d:%2d:%2d) pending requests %d,",LUN_ID,up->q_outcnt); + size = sprintf(PROC_BUF, " Pend reqs %d,",up->q_outcnt); + len += size; +#if 0 /* avg response time */ - size += sprintf(PROC_BUF, "Avg response time %ld%%,",(up->resp_time/up->io_cnt)*100); + size = sprintf(PROC_BUF, " Avg resp time %ld%%,",(up->resp_time/up->io_cnt)*100); + len += size; /* avg active time */ - size += sprintf(PROC_BUF, "Avg active time %ld%%\n",(up->act_time/up->io_cnt)*100); + size = sprintf(PROC_BUF, " Avg active time %ld%%\n",(up->act_time/up->io_cnt)*100); +#else + size = sprintf(PROC_BUF, "\n"); +#endif + len += size; + } + if( len >= qla1280_buffer_size ) + break; } - if (size >= qla1280_buffer_size) - { + if( len >= qla1280_buffer_size ) { printk(KERN_WARNING "qla1280: Overflow buffer in qla1280_proc.c\n"); } - if (offset > size - 1) - { + if( offset > len - 1 ) { kfree(qla1280_buffer); qla1280_buffer = NULL; qla1280_buffer_size = length = 0; *start = NULL; - } - else - { + } else { *start = &qla1280_buffer[offset]; /* Start of wanted data */ - if (size - offset < length) - { - length = size - offset; + if( len - offset < length ) { + length = len - offset; } } + return (length); +#else + return (0); #endif - return (length); } - /************************************************************************** * qla1280_detect * This routine will probe for Qlogic 1280 SCSI host adapters. @@ -734,7 +694,10 @@ struct Scsi_Host *host; scsi_qla_host_t *ha, *cur_ha; struct _qlaboards *bdp; - int i, j; + int i,j; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + unsigned short subsys; +#endif #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,95) unsigned int piobase; unsigned char pci_bus, pci_devfn, pci_irq; @@ -747,13 +710,19 @@ #else int index; #endif +#ifndef PCI_VENDOR_ID_AMI +#define PCI_VENDOR_ID_AMI 0x101e +#endif ENTER("qla1280_detect"); + if (sizeof(srb_t) > sizeof(Scsi_Pointer) ) + printk("qla1280_detect: [WARNING] srb_t Must Be Redefined"); + #ifdef CHECKSRBSIZE if (sizeof(srb_t) > sizeof(Scsi_Pointer) ) { - printk("Redefine SRB - its too big"); + printk("qla1280_detect: srb_t Must Be Redefined - its too big"); return 0; } #endif @@ -784,45 +753,174 @@ "qla1280: insmod or else it might trash certain memory areas.\n"); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) if ((int) !pcibios_present()) +#else + if (!pci_present()) +#endif { - printk("scsi: PCI not present\n"); - return 0; - } /* end of IF */ - bdp = &QLBoardTbl[0]; + printk("scsi: PCI not present\n"); + return 0; + } + + bdp = &QL1280BoardTbl[0]; qla1280_hostlist = NULL; -#if 0 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) template->proc_dir = &proc_scsi_qla1280; #else template->proc_name = "qla1280"; #endif + + /* 3.20 */ + /* First Initialize QLA12160 on PCI Bus 1 Dev 2 */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + while ((pdev = pci_find_subsys(QLA1280_VENDOR_ID, + bdp->device_id, /* QLA12160 first in list */ + PCI_ANY_ID, + PCI_ANY_ID,pdev))) { + + /* find QLA12160 device on PCI bus=1 slot=2 */ + if ((pdev->bus->number != 1) || + (PCI_SLOT(pdev->devfn) != 2)) continue; + + if (pci_enable_device(pdev)) goto find_devices; + printk("qla1x160: Initializing ISP12160 on PCI Bus 1, Dev 2\n"); + host = scsi_register(template, sizeof(scsi_qla_host_t)); + if (!host) { + printk(KERN_WARNING "qla1280: Failed to register host, aborting.\n"); + return 0; + } + scsi_set_pci_device(host, pdev); + ha = (scsi_qla_host_t *) host->hostdata; + /* Clear our data area */ + for( j =0, cp = (char *)ha; j < sizeof(scsi_qla_host_t); j++) + *cp++ = 0; + /* Sanitize the information from PCI BIOS. */ + host->irq = pdev->irq; + host->io_port = pci_resource_start(pdev, 0); + ha->pci_bus = pdev->bus->number; + ha->pci_device_fn = pdev->devfn; + ha->pdev = pdev; + ha->device_id = bdp->device_id; /* QLA12160 first in list */ + ha->devnum = 0; // This priority ISP12160 is always devnum zero + if( qla1280_mem_alloc(ha) ) { + printk(KERN_INFO "qla1x160: Failed to get memory\n"); + } + ha->ports = bdp->numPorts; + /* following needed for all cases of OS versions */ + host->io_port &= PCI_BASE_ADDRESS_IO_MASK; + ha->iobase = (device_reg_t *) host->io_port; + ha->host = host; + ha->host_no = host->host_no; + /* 3.20 zero out /proc/scsi/qla1280 counters */ + ha->actthreads = 0; + ha->qthreads = 0; + ha->isr_count = 0; + + /* load the F/W, read paramaters, and init the H/W */ + ha->instance = num_hosts; + if (qla1280_initialize_adapter(ha)) + { + printk(KERN_INFO "qla1x160: Failed to initialize QLA12160 on PCI Bus 1 Dev 2 \n"); + qla1280_mem_free(ha); + scsi_unregister(host); + goto find_devices; + } + host->max_channel = bdp->numPorts-1; + /* Register our resources with Linux */ + if( qla1280_register_with_Linux(ha, bdp->numPorts-1) ) { + printk(KERN_INFO "qla1x160: Failed to register resources for QLA12160 on PCI Bus 1 Dev 2\n"); + qla1280_mem_free(ha); + scsi_unregister(host); + goto find_devices; + } + reg = ha->iobase; + /* Disable ISP interrupts. */ + qla1280_disable_intrs(ha); + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); + + /* Enable chip interrupts. */ + qla1280_enable_intrs(ha); + /* Insert new entry into the list of adapters */ + ha->next = NULL; + /* this preferred device will always be the first one found */ + cur_ha = qla1280_hostlist = ha; + num_hosts++; + } +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + find_devices: +#endif + + pdev = NULL; /* Try and find each different type of adapter we support */ - for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) { + for(i=0;bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES;i++,bdp++) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + /* PCI_SUBSYSTEM_IDS supported */ + while ((pdev = pci_find_subsys(QLA1280_VENDOR_ID, + bdp->device_id, PCI_ANY_ID, PCI_ANY_ID, pdev) )) { + if (pci_enable_device(pdev)) continue; +#else while ((pdev = pci_find_device(QLA1280_VENDOR_ID, bdp->device_id, pdev ) )) { - if (pci_enable_device(pdev)) continue; -#else +#endif /* 2,3,18 */ +#else /* less than 2,1,95 */ while (!(pcibios_find_device(QLA1280_VENDOR_ID, bdp->device_id, index++, &pci_bus, &pci_devfn)) ) { -#endif +#endif /* 2,1,95 */ /* found a adapter */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + /* If it's an AMI SubSys Vendor ID adapter, skip it. */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_AMI) + { + printk("qla1x160: Skip AMI SubSys Vendor ID Chip\n"); + continue; + } + + /* 3.20 and 3.23 */ + /* skip QLA12160 already initialized on PCI Bus 1 Dev 2 */ + /* since we already initialized and presented it */ + if ((bdp->device_id == QLA12160_DEVICE_ID) && + (pdev->bus->number == 1) && + (PCI_SLOT(pdev->devfn) == 2)) continue; + + printk("qla1x160: Supported Device Found VID=%x DID=%x SSVID=%x SSDID=%x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + printk("qla1x160: Supported Device Found\n"); + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, + &subsys); + /* Bypass all AMI SUBSYS VENDOR IDs */ + if (subsys == PCI_VENDOR_ID_AMI) + { + printk("qla1x160: Skip AMI SubSys Vendor ID Chip\n"); + continue; + } +#endif /* 2,1,95 */ +#endif /* 2,3,18 */ host = scsi_register(template, sizeof(scsi_qla_host_t)); - if (!host) { - printk(KERN_WARNING "qla1280: Failed to register host, aborting.\n"); - return 0; - } - scsi_set_pci_device(host, pdev); ha = (scsi_qla_host_t *) host->hostdata; /* Clear our data area */ for( j =0, cp = (char *)ha; j < sizeof(scsi_qla_host_t); j++) - *cp = 0; + *cp++ = 0; /* Sanitize the information from PCI BIOS. */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) host->irq = pdev->irq; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + host->io_port = (unsigned int) pdev->base_address[0]; +#else host->io_port = pci_resource_start(pdev, 0); +#endif ha->pci_bus = pdev->bus->number; ha->pci_device_fn = pdev->devfn; ha->pdev = pdev; @@ -836,38 +934,38 @@ ha->pci_device_fn = pci_devfn; #endif ha->device_id = bdp->device_id; - - ha->devnum = i; + ha->devnum = i; // specifies microcode load address + if( qla1280_mem_alloc(ha) ) { - printk(KERN_INFO "qla1280: Failed to allocate memory for adapter\n"); + printk(KERN_INFO "qla1x160: Failed to get memory\n"); } ha->ports = bdp->numPorts; + /* following needed for all cases of OS versions */ + host->io_port &= PCI_BASE_ADDRESS_IO_MASK; ha->iobase = (device_reg_t *) host->io_port; ha->host = host; ha->host_no = host->host_no; /* load the F/W, read paramaters, and init the H/W */ + ha->instance = num_hosts; if (qla1280_initialize_adapter(ha)) { - - printk(KERN_INFO "qla1280: Failed to initialized adapter\n"); - qla1280_mem_free(ha); - scsi_unregister(host); - continue; + printk(KERN_INFO "qla1x160:Failed to initialize adapter\n"); + qla1280_mem_free(ha); + scsi_unregister(host); + continue; } host->max_channel = bdp->numPorts-1; - ha->instance = num_hosts; /* Register our resources with Linux */ if( qla1280_register_with_Linux(ha, bdp->numPorts-1) ) { - printk(KERN_INFO "qla1280: Failed to register our resources\n"); - qla1280_mem_free(ha); - scsi_unregister(host); - continue; + printk(KERN_INFO "qla1x160: Failed to register resources\n"); + qla1280_mem_free(ha); + scsi_unregister(host); + continue; } - reg = ha->iobase; /* Disable ISP interrupts. */ qla1280_disable_intrs(ha); @@ -924,8 +1022,11 @@ host->can_queue = 0xfffff; /* unlimited */ host->cmd_per_lun = 1; host->select_queue_depths = qla1280_select_queue_depth; - host->n_io_port = 0xFF; - host->base = (unsigned long) ha->mmpbase; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + host->base = (unsigned char *) ha->mmpbase; +#else + host->base = (u_long) ha->mmpbase; +#endif host->max_channel = maxchannels; host->max_lun = MAX_LUNS-1; host->unique_id = ha->instance; @@ -1016,10 +1117,10 @@ bp = &qla1280_buffer[0]; ha = (scsi_qla_host_t *)host->hostdata; - bdp = &QLBoardTbl[ha->devnum]; + bdp = &QL1280BoardTbl[ha->devnum]; memset(bp, 0, sizeof(qla1280_buffer)); sprintf(bp, - "QLogic %sPCI to SCSI Host Adapter: bus %d device %d irq %d\n" + "QLogic %s PCI to SCSI Host Adapter: bus %d device %d irq %d\n" " Firmware version: %2d.%02d.%02d, Driver version %s", (char *)&bdp->bdName[0], ha->pci_bus, (ha->pci_device_fn & 0xf8) >> 3, host->irq, bdp->fwver[0],bdp->fwver[1],bdp->fwver[2], @@ -1051,8 +1152,8 @@ scsi_lu_t *q; u_long handle; - ENTER("qla1280_queuecommand"); - COMTRACE('C') + /*ENTER("qla1280_queuecommand"); + COMTRACE('C')*/ host = cmd->host; ha = (scsi_qla_host_t *) host->hostdata; @@ -1079,7 +1180,7 @@ { LU_Q(ha, b, t, l) = q; BZERO(q,sizeof(struct scsi_lu)); - DEBUG(sprintf(debug_buff,"Allocate new device queue 0x%x\n",q)); + DEBUG(sprintf(debug_buff,"Allocate new device queue 0x%x\n\r",q)); DEBUG(qla1280_print(debug_buff)); DRIVER_UNLOCK } @@ -1087,8 +1188,12 @@ { CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16); qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); - - schedule_task(&ha->run_qla_bh); +/* 3.22 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 3.22 */ + queue_task(&ha->run_qla_bh,&tq_scheduler); +#else /* 3.22 */ + schedule_task(&ha->run_qla_bh); /* 3.22 */ +#endif /* 3.22 */ ha->flags.dpc_sched = TRUE; DRIVER_UNLOCK return(0); @@ -1099,15 +1204,13 @@ handle = INVALID_HANDLE; CMD_HANDLE(cmd) = (unsigned char *)handle; - /* Bookkeeping information */ - sp->r_start = jiffies; /* time the request was received */ - sp->u_start = 0; - /* add the command to our queue */ ha->qthreads++; qla1280_putq_t(q,sp); - DEBUG(sprintf(debug_buff,"qla1280_queuecmd: queue pid=%d, hndl=0x%x\n\r",cmd->pid,handle)); + DEBUG(sprintf(debug_buff, + "qla1280_QC: t=%x CDB=%x I/OSize=0x%x haQueueCount=0x%x\n\r", + t,cmd->cmnd[0],CMD_XFRLEN(cmd),ha->qthreads)); DEBUG(qla1280_print(debug_buff)); /* send command to adapter */ @@ -1117,7 +1220,7 @@ DRIVER_UNLOCK - LEAVE("qla1280_queuecommand"); + /*LEAVE("qla1280_queuecommand");*/ return (0); } @@ -1556,6 +1659,7 @@ { COMTRACE('X') printk(KERN_INFO "scsi(%d): Already in interrupt - returning \n", (int)ha->host_no); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); return; } set_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags); @@ -1587,7 +1691,7 @@ ha->run_qla_bh.routine = qla1280_do_dpc; COMTRACE('P') - schedule_task(&ha->run_qla_bh); + queue_task_irq(&ha->run_qla_bh,&tq_scheduler); ha->flags.dpc_sched = TRUE; } clear_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags); @@ -1611,7 +1715,7 @@ * "host->can_queue". This can cause a panic if we were in our interrupt * code . **************************************************************************/ -static void qla1280_do_dpc(void *p) +void qla1280_do_dpc(void *p) { scsi_qla_host_t *ha = (scsi_qla_host_t *) p; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) @@ -1729,6 +1833,7 @@ scsi_lu_t *q; uint32_t b, t, l; Scsi_Cmnd *cmd; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned long cpu_flags = 0; #endif @@ -1745,7 +1850,8 @@ *done_q_last = NULL; else (*done_q_first)->s_prev = NULL; - cmd = sp->cmd; + + cmd = sp->cmd; b = SCSI_BUS_32(cmd); t = SCSI_TCN_32(cmd); l = SCSI_LUN_32(cmd); @@ -1759,8 +1865,6 @@ q->q_flag &= ~QLA1280_QBUSY; } - q->resp_time += jiffies - sp->r_start; /* Lun bookkeeping information */ - q->act_time += jiffies - sp->u_start; q->io_cnt++; if( sp->dir & BIT_5 ) q->r_cnt++; @@ -1783,7 +1887,28 @@ default: break; } - + /* 3.13 64 and 32 bit */ + /* Release memory used for this I/O */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + if (cmd->use_sg) { + DEBUG(sprintf(debug_buff, + "S/G unmap_sg cmd=%x\n\r",cmd);) + DEBUG(qla1280_print(debug_buff)); + pci_unmap_sg(ha->pdev, cmd->request_buffer, + cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } + else if (cmd->request_bufflen) { + /*DEBUG(sprintf(debug_buff, + "No S/G unmap_single cmd=%x saved_dma_handle=%lx\n\r", + cmd,sp->saved_dma_handle);) + DEBUG(qla1280_print(debug_buff);)*/ + + pci_unmap_single(ha->pdev,sp->saved_dma_handle, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } +#endif /* Call the mid-level driver interrupt handler */ CMD_HANDLE(sp->cmd) = (unsigned char *) 0; ha->actthreads--; @@ -1797,8 +1922,6 @@ qla1280_next(ha, q, b); } DRIVER_UNLOCK - - COMTRACE('d') LEAVE("qla1280_done"); } @@ -1970,7 +2093,7 @@ if (q->q_outcnt >= ha->bus_settings[b].hiwat) q->q_flag |= QLA1280_QBUSY; -#if QLA1280_64BIT_SUPPORT +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) if (ha->flags.enable_64bit_addressing) status = qla1280_64bit_start_scsi(ha, sp); else @@ -1987,7 +2110,7 @@ /* Wait for 30 sec for command to be accepted. */ for (cnt = 6000000; cnt; cnt--) { -#if QLA1280_64BIT_SUPPORT +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) if (ha->flags.enable_64bit_addressing) status = qla1280_64bit_start_scsi(ha, sp); else @@ -2078,7 +2201,7 @@ ENTER("qla1280_putq_t"); #endif DRIVER_LOCK - DEBUG(sprintf(debug_buff,"Adding to device 0x%p<-(0x%p)\n\r",q,sp)); + DEBUG(sprintf(debug_buff,"Adding to device q=0x%p<-(0x%p)sp\n\r",q,sp)); DEBUG(qla1280_print(debug_buff)); sp->s_next = NULL; if (!q->q_first) /* If queue empty */ @@ -2163,28 +2286,33 @@ { uint8_t status = 1; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + dma_addr_t dma_handle; +#endif #ifdef QL_DEBUG_LEVEL_3 ENTER("qla1280_mem_alloc"); #endif -#ifdef DYNAMIC_MEM_ALLOC - ha->request_ring = qla1280_alloc_phys(REQUEST_ENTRY_SIZE * REQUEST_ENTRY_CNT, - &ha->request_dma); - if(ha->request_ring) { - ha->response_ring = qla1280_alloc_phys(RESPONSE_ENTRY_SIZE * RESPONSE_ENTRY_CNT, - &ha->response_dma); - if(ha->response_ring) { - status = 0; - } - } -#else + /* 3.13 */ + /* get consistent memory allocated for request and response rings */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) ha->request_ring = &ha->req[0]; ha->request_dma = VIRT_TO_BUS(&ha->req[0]); ha->response_ring = &ha->res[0]; ha->response_dma = VIRT_TO_BUS(&ha->res[0]); status = 0; -#endif +#else + ha->request_ring = pci_alloc_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT+1)*(sizeof(request_t))), + &dma_handle); + ha->request_dma = dma_handle; + ha->response_ring = pci_alloc_consistent(ha->pdev, + ((RESPONSE_ENTRY_CNT+1)*(sizeof(response_t))), + &dma_handle); + ha->response_dma = dma_handle; + status = 0; +#endif if(status) { #if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) @@ -2228,6 +2356,16 @@ ha->dev[b] = (scsi_lu_t *)NULL; } + /* 3.13 */ + /* free consistent memory allocated for request and response rings */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + pci_free_consistent(ha->pdev, ((REQUEST_ENTRY_CNT+1)*(sizeof(request_t))), + ha->request_ring, ha->request_dma); + + pci_free_consistent(ha->pdev,((RESPONSE_ENTRY_CNT+1)*(sizeof(response_t))), + ha->response_ring, ha->response_dma); +#endif + LEAVE("qlc1280_mem_free"); } @@ -2488,7 +2626,7 @@ /* Verify checksum of loaded RISC code. */ mb[0] = MBC_VERIFY_CHECKSUM; /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *QLBoardTbl[ha->devnum].fwstart; + mb[1] = *QL1280BoardTbl[ha->devnum].fwstart; if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]))) { @@ -2498,7 +2636,7 @@ #endif mb[0] = MBC_EXECUTE_FIRMWARE; /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *QLBoardTbl[ha->devnum].fwstart; + mb[1] = *QL1280BoardTbl[ha->devnum].fwstart; qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); } else @@ -2533,18 +2671,69 @@ qla1280_pci_config(scsi_qla_host_t *ha) { uint8_t status = 1; - uint32_t command; #if MEMORY_MAPPED_IO uint32_t page_offset, base; uint32_t mmapbase; #endif - config_reg_t *creg = 0; uint16_t buf_wd; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + uint32_t command; + config_reg_t *creg = 0; +#endif + ENTER("qla1280_pci_config"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + /* + * Set Bus Master Enable, Memory Address Space Enable and + * reset any error bits, in the command register. + */ + pci_read_config_word(ha->pdev, PCI_COMMAND, &buf_wd); + buf_wd &= ~0x7; +#if MEMORY_MAPPED_IO + DEBUG(printk("qla1280: MEMORY MAPPED IO is enabled.\n")); + buf_wd |= BIT_2 + BIT_1 + BIT_0; +#else + buf_wd |= BIT_2 + BIT_0; +#endif + pci_write_config_word(ha->pdev, PCI_COMMAND, buf_wd); + /* + * Reset expansion ROM address decode enable. + */ + pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &buf_wd); + buf_wd &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, buf_wd); +#if MEMORY_MAPPED_IO + /* + * Get memory mapped I/O address. + */ + pci_read_config_word(ha->pdev, PCI_BASE_ADDRESS_1, &mmapbase); + mmapbase &= PCI_BASE_ADDRESS_MEM_MASK; + + /* + * Find proper memory chunk for memory map I/O reg. + */ + base = mmapbase & PAGE_MASK; + page_offset = mmapbase - base; + /* + * Get virtual address for I/O registers. + */ + ha->mmpbase = ioremap_nocache(base, page_offset + 256); + if( ha->mmpbase ) + { + ha->mmpbase += page_offset; + /* ha->iobase = ha->mmpbase; */ + status = 0; + } +#else /* MEMORY_MAPPED_IO */ + status = 0; +#endif /* MEMORY_MAPPED_IO */ + +#else /*LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) */ + /* Get command register. */ - if (pci_read_config_word(ha->pdev,OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL) + if (pcibios_read_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL) { command = buf_wd; /* @@ -2558,20 +2747,20 @@ #else buf_wd |= BIT_2 + BIT_0; #endif - if( pci_write_config_word(ha->pdev,OFFSET(creg->command), buf_wd) ) + if( pcibios_write_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->command), buf_wd) ) { printk(KERN_WARNING "qla1280: Could not write config word.\n"); } /* Get expansion ROM address. */ - if (pci_read_config_word(ha->pdev,OFFSET(creg->expansion_rom), &buf_wd) == PCIBIOS_SUCCESSFUL) + if (pcibios_read_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->expansion_rom), &buf_wd) == PCIBIOS_SUCCESSFUL) { /* Reset expansion ROM address decode enable. */ buf_wd &= ~BIT_0; - if (pci_write_config_word(ha->pdev,OFFSET(creg->expansion_rom), buf_wd) == PCIBIOS_SUCCESSFUL) + if (pcibios_write_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->expansion_rom), buf_wd) == PCIBIOS_SUCCESSFUL) { #if MEMORY_MAPPED_IO /* Get memory mapped I/O address. */ - pci_read_config_dword(ha->pdev,OFFSET(cfgp->mem_base_addr), &mmapbase); + pcibios_read_config_dword(ha->pci_bus, ha->pci_device_fn,OFFSET(cfgp->mem_base_addr), &mmapbase); mmapbase &= PCI_BASE_ADDRESS_MEM_MASK; /* Find proper memory chunk for memory map I/O reg. */ @@ -2595,6 +2784,7 @@ } } } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) */ LEAVE("qla1280_pci_config"); return(status); @@ -2725,6 +2915,7 @@ * Returns: * 0 = success. */ +#define DUMP_IT_BACK 0 /* for debug of RISC loading */ STATIC uint8_t qla1280_setup_chip(scsi_qla_host_t *ha) { @@ -2733,37 +2924,52 @@ uint16_t *risc_code_address; long risc_code_size; uint16_t mb[MAILBOX_REGISTER_COUNT]; -#ifdef QLA1280_UNUSED - uint8_t *sp; - int i; -#endif uint16_t cnt; int num; +#if DUMP_IT_BACK + int i; + uint8_t *sp; uint8_t *tbuf; - u_long p_tbuf; +#if BITS_PER_LONG > 32 + dma_addr_t p_tbuf; +#else + uint32_t p_tbuf; +#endif +#endif #ifdef QL_DEBUG_LEVEL_3 ENTER("qla1280_setup_chip"); #endif - if( (tbuf = (uint8_t *)KMALLOC(8000) ) == NULL ) - { - printk("setup_chip: couldn't alloacte memory\n"); - return(1); - } - p_tbuf = VIRT_TO_BUS(tbuf); + /* 3.13 */ +#if DUMP_IT_BACK +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + if( (tbuf = (uint8_t *)KMALLOC(8000) ) == NULL ) + { + printk("setup_chip: couldn't alloacte memory\n"); + return(1); + } + p_tbuf = VIRT_TO_BUS(tbuf); +#else + /* get consistent memory allocated for setup_chip */ + tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); +#endif +#endif + /* Load RISC code. */ /* risc_address = ql12_risc_code_addr01; risc_code_address = &ql12_risc_code01[0]; risc_code_size = ql12_risc_code_length01; */ - risc_address = *QLBoardTbl[ha->devnum].fwstart; - risc_code_address = QLBoardTbl[ha->devnum].fwcode; - risc_code_size = (long)(*QLBoardTbl[ha->devnum].fwlen & 0xffff); - - DEBUG(printk("qla1280: DMAing RISC code (%d) words.\n",(int)risc_code_size)); - DEBUG(sprintf(debug_buff,"qla1280_setup_chip: Loading RISC code size =(%ld).\n\r",risc_code_size);) + risc_address = *QL1280BoardTbl[ha->devnum].fwstart; + risc_code_address = QL1280BoardTbl[ha->devnum].fwcode; + risc_code_size = (long)(*QL1280BoardTbl[ha->devnum].fwlen & 0xffff); + + DEBUG(printk("qla1280_setup_chip: DMA RISC code (%d) words\n", + (int)risc_code_size)); + DEBUG(sprintf(debug_buff, + "qla1280_setup_chip: DMA RISC code (%d) words\n\r",risc_code_size);) DEBUG(qla1280_print(debug_buff)); num =0; while (risc_code_size > 0 && !status) @@ -2773,29 +2979,31 @@ if ( cnt > risc_code_size ) cnt = risc_code_size; - DEBUG(sprintf(debug_buff,"qla1280_setup_chip: loading risc @ =(0x%p),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);) + DEBUG(sprintf(debug_buff, + "qla1280_setup_chip: loading risc @ =(0x%p),%d,%d(0x%x).\n\r", + risc_code_address,cnt,num,risc_address);) DEBUG(qla1280_print(debug_buff)); - DEBUG(printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address)); - BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1)); + BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, + (cnt <<1)); + + flush_cache_all(); + mb[0] = MBC_LOAD_RAM; - /* mb[0] = MBC_LOAD_RAM_A64; */ mb[1] = risc_address; mb[4] = cnt; mb[3] = (uint16_t) ha->request_dma & 0xffff; mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff; mb[7] = (uint16_t) (MS_64BITS(ha->request_dma) & 0xffff); mb[6] = (uint16_t) (MS_64BITS(ha->request_dma) >> 16) & 0xffff; - DEBUG(printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3])); + DEBUG(printk("qla1280_setup_chip: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3])); if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, &mb[0])) ) { printk("Failed to load partial segment of f/w\n"); break; } - /* dump it back */ - -#if 0 - mb[0] = MBC_DUMP_RAM_A64; +#if DUMP_IT_BACK + mb[0] = MBC_READ_RAM_WORD; mb[1] = risc_address; mb[4] = cnt; mb[3] = (uint16_t) p_tbuf & 0xffff; @@ -2803,10 +3011,13 @@ mb[7] = (uint16_t) (p_tbuf >> 32) & 0xffff; mb[6] = (uint16_t) (p_tbuf >> 48) & 0xffff; - if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, - &mb[0])) ) + if( (status = qla1280_mailbox_command(ha, + BIT_4|BIT_3|BIT_2|BIT_1|BIT_0,&mb[0])) ) { printk("Failed to dump partial segment of f/w\n"); + DEBUG(sprintf(debug_buff, + "setup_chip: Failed to dump partial segment of f/w\n\r");) + DEBUG(qla1280_print(debug_buff)); break; } sp = (uint8_t *)ha->request_ring; @@ -2814,51 +3025,20 @@ { if( tbuf[i] != sp[i] ) { - printk("qla1280 : firmware compare error @ byte (0x%x)\n",i); - break; + printk("qla1280_setup_chip: FW compare error @ byte(0x%x) loop#=%x\n",i,num); + printk("setup_chip: FWbyte=%x FWfromChip=%x\n",sp[i],tbuf[i]); + DEBUG(sprintf(debug_buff, + "qla1280_setup_chip: FW compare error @ byte(0x%x) loop#=%x\n\r",i);) + DEBUG(qla1280_print(debug_buff);) + /*break;*/ } } - #endif risc_address += cnt; risc_code_size = risc_code_size - cnt; risc_code_address = risc_code_address + cnt; num++; } -#ifdef QLA1280_UNUSED - DEBUG(ql_debug_print = 0;) - { - for (i = 0; i < ql12_risc_code_length01; i++) - { - mb[0] = 0x4; - mb[1] = ql12_risc_code_addr01 + i; - mb[2] = ql12_risc_code01[i]; - - status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, - &mb[0]); - if (status) - { - printk("qla1280 : firmware load failure\n"); - break; - } - - mb[0] = 0x5; - mb[1] = ql12_risc_code_addr01 + i; - mb[2] = 0; - - status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, - &mb[0]); - if (status) - { - printk("qla1280 : firmware dump failure\n"); - break; - } - if( mb[2] != ql12_risc_code01[i] ) - printk("qla1280 : firmware compare error @ (0x%x)\n",ql12_risc_code_addr01+i); - } - } - DEBUG(ql_debug_print = 1;) -#endif /* Verify checksum of loaded RISC code. */ if (!status) @@ -2866,22 +3046,29 @@ DEBUG(printk("qla1280_setup_chip: Verifying checksum of loaded RISC code.\n");) mb[0] = MBC_VERIFY_CHECKSUM; /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *QLBoardTbl[ha->devnum].fwstart; + mb[1] = *QL1280BoardTbl[ha->devnum].fwstart; if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]))) { /* Start firmware execution. */ DEBUG(qla1280_print("qla1280_setup_chip: start firmware running.\n\r");) mb[0] = MBC_EXECUTE_FIRMWARE; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *QLBoardTbl[ha->devnum].fwstart; + mb[1] = *QL1280BoardTbl[ha->devnum].fwstart; qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); } else printk("qla1280_setup_chip: Failed checksum.\n"); } - KMFREE(tbuf,8000); + /* 3.13 */ +#if DUMP_IT_BACK +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(tbuf,8000); +#else + /* free consistent memory allocated for setup_chip */ + pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); +#endif +#endif #if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) if (status) @@ -3158,9 +3345,29 @@ /* Disable RISC load of firmware. */ ha->flags.disable_risc_code_load = nv->cntr_flags_1.disable_loading_risc_code; - /* Enable 64bit addressing. */ - ha->flags.enable_64bit_addressing = - nv->cntr_flags_1.enable_64bit_addressing; + +#if BITS_PER_LONG > 32 + /* Enable 64bit addressing for OS/System combination supporting it */ + /* actual NVRAM bit is: nv->cntr_flags_1.enable_64bit_addressing */ + /* but we will ignore it and use BITS_PER_LONG macro to setup for */ + /* 64 or 32 bit access of host memory in all x86/ia-64/Alpha systems */ + ha->flags.enable_64bit_addressing = 1; +#else + ha->flags.enable_64bit_addressing = 0; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + if (ha->flags.enable_64bit_addressing) { + printk("[[[ qla1x160: 64 Bit PCI Addressing Enabled ]]]\n"); + +#if BITS_PER_LONG > 32 + /* Update our PCI device dma_mask for full 64 bit mask */ + //ha->pdev->dma_mask = (pci_dma_t) 0xffffffffffffffffull; + ha->pdev->dma_mask = 0xffffffffffffffff; + +#endif + } +#endif /* Set ISP hardware DMA burst */ mb[0] = nv->isp_config.c; @@ -3844,7 +4051,7 @@ #endif } -#if QLA1280_64BIT_SUPPORT +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) /* * qla1280_64bit_start_scsi * The start SCSI is responsible for building request packets on @@ -3869,10 +4076,13 @@ uint16_t seg_cnt; struct scatterlist *sg = (struct scatterlist *) NULL; uint32_t *dword_ptr; + dma_addr_t dma_handle; -#ifdef QL_DEBUG_LEVEL_3 ENTER("qla1280_64bit_start_scsi:"); -#endif + + DEBUG(sprintf(debug_buff, + "64bit_start: cmd=%x sp=%x CDB=%x\n\r",cmd,sp,cmd->cmnd[0]);) + DEBUG(qla1280_print(debug_buff)); if( qla1280_check_for_dead_scsi_bus(ha, sp) ) { @@ -3883,9 +4093,10 @@ seg_cnt = 0; req_cnt = 1; if (cmd->use_sg) - { - seg_cnt = cmd->use_sg; + { /* 3.13 64 bit */ sg = (struct scatterlist *) cmd->request_buffer; + seg_cnt = pci_map_sg(ha->pdev,sg,cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); if (seg_cnt > 2) { @@ -3896,7 +4107,7 @@ } else if (cmd->request_bufflen) /* If data transfer. */ { - DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen)); + /*DEBUG(printk("Single data transfer len=0x%x\n",cmd->request_bufflen));*/ seg_cnt = 1; } @@ -3957,7 +4168,7 @@ /* Load SCSI command packet. */ pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd); BCOPY(&(CMD_CDBP(cmd)), pkt->scsi_cdb, pkt->cdb_len); - DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0])); + //DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0])); /* * Load data segments. @@ -3983,12 +4194,17 @@ /* Load command entry data segments. */ for (cnt = 0; cnt < 2 && seg_cnt; cnt++, seg_cnt--) { - DEBUG(sprintf(debug_buff,"SG Segment ap=0x%p, len=0x%x\n\r",sg->address,sg->length)); - DEBUG(qla1280_print(debug_buff)); - *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(sg->address)); - *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address)); - *dword_ptr++ = sg->length; + /* 3.13 64 bit */ + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); sg++; + DEBUG(sprintf(debug_buff, + "S/G Segment phys_addr=%x %x, len=0x%x\n\r", + cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))), + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) + DEBUG(qla1280_print(debug_buff)); } #ifdef QL_DEBUG_LEVEL_5 qla1280_print( @@ -4005,6 +4221,10 @@ /* * Build continuation packets. */ + DEBUG(sprintf(debug_buff, + "S/G Building Continuation...seg_cnt=0x%x remains\n\r", + seg_cnt);) + DEBUG(qla1280_print(debug_buff)); while (seg_cnt > 0) { /* Adjust ring index. */ @@ -4038,10 +4258,17 @@ /* Load continuation entry data segments. */ for (cnt = 0; cnt < 5 && seg_cnt; cnt++, seg_cnt--) { - *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(sg->address)); - *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address)); - *dword_ptr++ = sg->length; - sg++; + /* 3.13 64 bit */ + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); + DEBUG(sprintf(debug_buff, + "S/G Segment Cont. phys_addr=%x %x, len=0x%x\n\r", + cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))), + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) + DEBUG(qla1280_print(debug_buff)); + sg++; } #ifdef QL_DEBUG_LEVEL_5 qla1280_print( @@ -4058,11 +4285,21 @@ #endif } } - else /* No scatter gather data transfer */ - { - *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(cmd->request_buffer)); - *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(cmd->request_buffer)); - *dword_ptr = (uint32_t) cmd->request_bufflen; + else /* No scatter gather data transfer */ + { /* 3.13 64 bit */ + dma_handle = pci_map_single(ha->pdev, + cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + /* save dma_handle for pci_unmap_single */ + sp->saved_dma_handle = dma_handle; + + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(dma_handle)); + *dword_ptr++ = cpu_to_le32(pci_dma_hi32(dma_handle)); + *dword_ptr = (uint32_t) cmd->request_bufflen; + /*DEBUG(sprintf(debug_buff, + "No S/G map_single saved_dma_handle=%lx\n\r",dma_handle)); + DEBUG(qla1280_print(debug_buff));*/ #ifdef QL_DEBUG_LEVEL_5 qla1280_print( "qla1280_64bit_start_scsi: No scatter/gather command packet data - c"); @@ -4077,12 +4314,12 @@ #endif } } -#ifdef QL_DEBUG_LEVEL_5 - else /* No data transfer */ + else /* No data transfer */ { *dword_ptr++ = (uint32_t) 0; *dword_ptr++ = (uint32_t) 0; *dword_ptr = (uint32_t) 0; +#ifdef QL_DEBUG_LEVEL_5 qla1280_print( "qla1280_64bit_start_scsi: No data, command packet data - c"); qla1280_print(" b "); @@ -4093,8 +4330,8 @@ qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); qla1280_print("\n\r"); qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); - } #endif + } /* Adjust ring index. */ ha->req_ring_index++; if (ha->req_ring_index == REQUEST_ENTRY_CNT) @@ -4106,6 +4343,10 @@ ha->request_ring_ptr++; /* Set chip new ring index. */ + DEBUG(qla1280_print("qla1280_64bit_start_scsi: Wakeup RISC for pending command\n\r")); + ha->qthreads--; + sp->flags |= SRB_SENT; + ha->actthreads++; WRT_REG_WORD(®->mailbox4, ha->req_ring_index); } else @@ -4146,7 +4387,7 @@ #endif return(status); } -#endif /* QLA1280_64BIT_SUPPORT */ +#endif /* * qla1280_32bit_start_scsi @@ -4181,8 +4422,15 @@ uint8_t *data_ptr; uint32_t *dword_ptr; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + dma_addr_t dma_handle; +#endif + ENTER("qla1280_32bit_start_scsi"); + DEBUG(sprintf(debug_buff, + "32bit_start: cmd=%x sp=%x CDB=%x\n\r",cmd,sp,cmd->cmnd[0]);) + DEBUG(qla1280_print(debug_buff)); if( qla1280_check_for_dead_scsi_bus(ha, sp) ) { @@ -4199,8 +4447,15 @@ * differences and the kernel SG list uses virtual addresses where * we need physical addresses. */ - seg_cnt = cmd->use_sg; sg = (struct scatterlist *) cmd->request_buffer; + /* 3.13 32 bit */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + seg_cnt = cmd->use_sg; +#else + seg_cnt = pci_map_sg(ha->pdev,sg,cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); +#endif + /* * if greater than four sg entries then we need to allocate * continuation entries @@ -4211,17 +4466,22 @@ if ((uint16_t)(seg_cnt - 4) % 7) req_cnt++; } - DEBUG(sprintf(debug_buff,"S/G for data transfer -num segs(%d), req blk cnt(%d)\n\r",seg_cnt,req_cnt)); + DEBUG(sprintf(debug_buff, + "S/G Transfer cmd=%x seg_cnt=0x%x, req_cnt=%x\n\r", + cmd,seg_cnt,req_cnt)); DEBUG(qla1280_print(debug_buff)); } else if (cmd->request_bufflen) /* If data transfer. */ { - DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen)); + DEBUG(sprintf(debug_buff, + "No S/G transfer t=%x cmd=%x len=%x CDB=%x\n\r", + SCSI_TCN_32(cmd),cmd,cmd->request_bufflen,cmd->cmnd[0])); + DEBUG(qla1280_print(debug_buff)); seg_cnt = 1; } else { - DEBUG(printk("No data transfer \n")); + //DEBUG(printk("No data transfer \n")); seg_cnt = 0; } @@ -4238,7 +4498,8 @@ ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); } - DEBUG(sprintf(debug_buff,"Number of free entries = (%d)\n\r",ha->req_q_cnt)); + DEBUG(sprintf(debug_buff,"Number of free entries=(%d) seg_cnt=0x%x\n\r", + ha->req_q_cnt,seg_cnt)); DEBUG(qla1280_print(debug_buff)); /* If room for request in request ring. */ if ((uint16_t)(req_cnt + 2) < ha->req_q_cnt) @@ -4286,20 +4547,15 @@ data_ptr = (uint8_t *) &(CMD_CDBP(cmd)); for (cnt = 0; cnt < pkt->cdb_len; cnt++) pkt->scsi_cdb[cnt] = *data_ptr++; - DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0])); + //DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0])); /* * Load data segments. */ if (seg_cnt) { - DEBUG(printk("loading data segments..\n")); /* Set transfer direction (READ and WRITE) */ /* Linux doesn't tell us */ - /* - * 3/10 dg - Normally, we should need this check with our F/W - * but because of a small issue with it we do. - * * For block devices, cmd->request.cmd has the operation * For character devices, this isn't always set properly, so * we need to check data_cmnd[0]. This catches the conditions @@ -4325,15 +4581,32 @@ /* Load command entry data segments. */ for (cnt = 0; cnt < 4 && seg_cnt; cnt++, seg_cnt--) { + /* 3.13 32 bit */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(sg->address)); *dword_ptr++ = sg->length; - DEBUG(sprintf(debug_buff,"SG Segment ap=0x%p, len=0x%x\n\r",sg->address,sg->length)); + DEBUG(sprintf(debug_buff, + "S/G Segment phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(VIRT_TO_BUS(sg->address)),sg->length)); + DEBUG(qla1280_print(debug_buff)); +#else + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); + DEBUG(sprintf(debug_buff, + "S/G Segment phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) DEBUG(qla1280_print(debug_buff)); +#endif sg++; } /* * Build continuation packets. */ + DEBUG(sprintf(debug_buff, + "S/G Building Continuation...seg_cnt=0x%x remains\n\r", + seg_cnt);) + DEBUG(qla1280_print(debug_buff)); while (seg_cnt > 0) { /* Adjust ring index. */ @@ -4368,9 +4641,25 @@ /* Load continuation entry data segments. */ for (cnt = 0; cnt < 7 && seg_cnt; cnt++, seg_cnt--) { - *dword_ptr++ = (u_int) cpu_to_le32(VIRT_TO_BUS(sg->address)); - *dword_ptr++ = sg->length; - sg++; + /* 3.13 32 bit */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + *dword_ptr++ = (u_int) cpu_to_le32(VIRT_TO_BUS(sg->address)); + *dword_ptr++ = sg->length; + DEBUG(sprintf(debug_buff, + "S/G Segment Cont. phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(pci_dma_lo32(VIRT_TO_BUS(sg->address))), + sg->length);) + DEBUG(qla1280_print(debug_buff)); +#else + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); + DEBUG(sprintf(debug_buff, + "S/G Segment Cont. phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) + DEBUG(qla1280_print(debug_buff)); +#endif + sg++; } #ifdef QL_DEBUG_LEVEL_5 qla1280_print( @@ -4385,14 +4674,28 @@ #endif } } - else /* No scatter gather data transfer */ + else /* No S/G data transfer */ { + /* 3.13 32 bit */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer)); *dword_ptr = (uint32_t) cmd->request_bufflen; - DEBUG(printk("Single Segment ap=0x%p, len=0x%x\n",cmd->request_buffer,cmd->request_bufflen)); +#else + dma_handle = pci_map_single(ha->pdev, + cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + sp->saved_dma_handle = dma_handle; + + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(dma_handle)); + *dword_ptr = (uint32_t) cmd->request_bufflen; + /*DEBUG(sprintf(debug_buff, + "No S/G map_single saved_dma_handle=%lx\n\r",dma_handle)); + DEBUG(qla1280_print(debug_buff));*/ +#endif } } - else /* No data transfer */ + else /* No data transfer at all */ { *dword_ptr++ = (uint32_t) 0; *dword_ptr = (uint32_t) 0; @@ -4420,10 +4723,8 @@ /* Set chip new ring index. */ DEBUG(qla1280_print("qla1280_32bit_start_scsi: Wakeup RISC for pending command\n\r")); ha->qthreads--; - sp->u_start = jiffies; sp->flags |= SRB_SENT; ha->actthreads++; - /* qla1280_output_number((uint32_t)ha->actthreads++, 16); */ WRT_REG_WORD(®->mailbox4, ha->req_ring_index); } else @@ -4431,7 +4732,7 @@ status = 1; #ifdef QL_DEBUG_LEVEL_2 qla1280_print( - "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r"); + "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r"); qla1280_print(" req_q_cnt="); qla1280_output_number((uint32_t)ha->req_q_cnt, 16); qla1280_print("\n\r"); @@ -4465,6 +4766,7 @@ return(status); } + /* * qla1280_req_pkt * Function is responsible for locking ring and @@ -4895,7 +5197,7 @@ { device_reg_t *reg = ha->iobase; response_t *pkt; - srb_t *sp; + srb_t *sp = 0; uint16_t mailbox[MAILBOX_REGISTER_COUNT]; uint16_t *wptr; uint32_t index; @@ -4909,9 +5211,11 @@ /* Check for mailbox interrupt. */ mailbox[0] = RD_REG_WORD(®->semaphore); + if (mailbox[0] & BIT_0) { /* Get mailbox data. */ + //DEBUG(qla1280_print("qla1280_isr: In Get mailbox data \n\r");) wptr = &mailbox[0]; *wptr++ = RD_REG_WORD(®->mailbox0); @@ -4944,7 +5248,7 @@ { case MBA_SCSI_COMPLETION: /* Response completion */ #ifdef QL_DEBUG_LEVEL_5 - qla1280_print("qla1280_isr: mailbox response completion\n\r"); + qla1280_print("qla1280_isr: mailbox SCSI response completion\n\r"); #endif if (ha->flags.online) { @@ -4973,9 +5277,11 @@ else (*done_q_last)->s_next = sp; *done_q_last = sp; + } else { + #ifdef QL_DEBUG_LEVEL_2 qla1280_print("qla1280_isr: ISP invalid handle\n\r"); #endif @@ -5047,6 +5353,7 @@ #endif break; default: + //DEBUG(qla1280_print("qla1280_isr: default case of switch MB \n\r");) if (mailbox[0] < MBA_ASYNC_EVENT) { wptr = &mailbox[0]; @@ -5063,9 +5370,9 @@ break; } } - else + else { WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); - + } /* * Response ring */ @@ -5129,6 +5436,7 @@ qla1280_error_entry(ha, pkt, done_q_first, done_q_last); + /* Adjust ring index. */ ha->rsp_ring_index++; if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) @@ -5312,9 +5620,12 @@ } pkt->scsi_status = S_CKCON; pkt->option_flags |= (uint32_t)OF_SSTS | (uint32_t)OF_NO_DATA; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) if (ha->flags.enable_64bit_addressing) qla1280_64bit_continue_io(ha, pkt, 0, 0); else +#endif qla1280_32bit_continue_io(ha, pkt, 0, 0); break; case 0x16: /* Requested Capability Not Available */ @@ -5673,10 +5984,12 @@ (uint32_t)OF_NO_DATA; break; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) if (ha->flags.enable_64bit_addressing) - qla1280_64bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); + qla1280_64bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); else - qla1280_32bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); +#endif + qla1280_32bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); break; default: break; @@ -5750,11 +6063,13 @@ ha->outstanding_cmds[pkt->handle] = 0; cp = sp->cmd; + /* Generate LU queue on cntrl, target, LUN */ b = SCSI_BUS_32(cp); t = SCSI_TCN_32(cp); l = SCSI_LUN_32(cp); q = LU_Q(ha, b, t, l); + if( pkt->comp_status || pkt->scsi_status ) { DEBUG(qla1280_print( "scsi: comp_status = ");) @@ -5885,7 +6200,7 @@ /* Place command on done queue. */ qla1280_done_q_put(sp, done_q_first, done_q_last); } -#if QLA1280_64BIT_SUPPORT +#if BITS_PER_LONG > 32 else if (pkt->entry_type == COMMAND_A64_TYPE) { #ifdef QL_DEBUG_LEVEL_2 @@ -5962,7 +6277,6 @@ sp->timeout += 2; */ /* Place request back on top of device queue. */ - /* sp->flags &= ~(SRB_SENT | SRB_TIMEOUT); */ sp->flags = 0; qla1280_putq_t(q, sp); } @@ -6080,7 +6394,7 @@ } } #ifdef QL_DEBUG_LEVEL_3 - qla1280_print("qla1280_restart_queues: exiting normally\n"); + qla1280_print("qla1280_restart_queues: exiting normally\n\r"); #endif } @@ -6166,13 +6480,15 @@ return(ret); } - -/* - * Declarations for load module - */ -static Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; - +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#ifdef MODULE +Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; #include "scsi_module.c" +#endif +#else /* new kernel scsi initialization scheme */ +static Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; +#include "scsi_module.c" +#endif /************************************************************************ * qla1280_check_for_dead_scsi_bus * @@ -6283,13 +6599,13 @@ #if MEMORY_MAPPED_IO ret = *port; #else - ret = inb((int)port); + ret = inb((long)port); #endif if (ql_debug_print) { qla1280_print("qla1280_getbyte: address = "); - qla1280_output_number((uint32_t)port, 16); + qla1280_output_number((unsigned long)port, 16); qla1280_print(" data = 0x"); qla1280_output_number((uint32_t)ret, 16); qla1280_print("\n\r"); @@ -6309,13 +6625,13 @@ #if MEMORY_MAPPED_IO ret = *port; #else - ret = inw((int)port); + ret = inw((unsigned long)port); #endif if (ql_debug_print) { qla1280_print("qla1280_getword: address = "); - qla1280_output_number((uint32_t)port, 16); + qla1280_output_number((unsigned long)port, 16); qla1280_print(" data = 0x"); qla1280_output_number((uint32_t)ret, 16); qla1280_print("\n\r"); @@ -6335,13 +6651,13 @@ #if MEMORY_MAPPED_IO ret = *port; #else - ret = inl((int)port); + ret = inl((unsigned long)port); #endif if (ql_debug_print) { qla1280_print("qla1280_getdword: address = "); - qla1280_output_number((uint32_t)port, 16); + qla1280_output_number((unsigned long)port, 16); qla1280_print(" data = 0x"); qla1280_output_number((uint32_t)ret, 16); qla1280_print("\n\r"); @@ -6359,13 +6675,13 @@ #if MEMORY_MAPPED_IO *port = data; #else - outb(data, (int)port); + outb(data, (unsigned long)port); #endif if (ql_debug_print) { qla1280_print("qla1280_putbyte: address = "); - qla1280_output_number((uint32_t)port, 16); + qla1280_output_number((unsigned long)port, 16); qla1280_print(" data = 0x"); qla1280_output_number((uint32_t)data, 16); qla1280_print("\n\r"); @@ -6384,14 +6700,14 @@ #ifdef _LINUX_IOPORTS outw(data, (int)port); #else - outw((int)port, data); + outw((unsigned long)port, data); #endif #endif if (ql_debug_print) { qla1280_print("qla1280_putword: address = "); - qla1280_output_number((uint32_t)port, 16); + qla1280_output_number((unsigned long)port, 16); qla1280_print(" data = 0x"); qla1280_output_number((uint32_t)data, 16); qla1280_print("\n\r"); @@ -6410,14 +6726,14 @@ #ifdef _LINUX_IOPORTS outl(data,(int)port); #else - outl((int)port, data); + outl((unsigned long)port, data); #endif #endif if (ql_debug_print) { qla1280_print("qla1280_putdword: address = "); - qla1280_output_number((uint32_t)port, 16); + qla1280_output_number((unsigned long)port, 16); qla1280_print(" data = 0x"); qla1280_output_number((uint32_t)data, 16); qla1280_print("\n\r"); @@ -6441,8 +6757,7 @@ /* * Out character to COM2 port. - * PORT must be at standard address for COM2 = 0x2F8, - * or COM1 = 0x3F8 + * PORT must be at standard address for COM1 = 0x3f8 */ #define OUTB(addr,data) outb((data),(addr)) @@ -6452,7 +6767,7 @@ #ifdef QL_DEBUG_CONSOLE printk("%c", c); #else - int com_addr = 0x2f8; + int com_addr = 0x3f8; int hardware_flow_control = 1; int software_flow_control = 0; uint8_t data; @@ -6464,7 +6779,7 @@ }while (!(data & BIT_6)); /* - * Set BAUD rate for COM2 to 19200 (0x6) + * Set BAUD rate for COM2 to 9600 (0x6) */ /* Select rate divisor. */ @@ -6660,8 +6975,6 @@ qla1280_print(debug_buff); sprintf(debug_buff," Pid=%d, SP=0x%p\n\r", (int)cmd->pid, CMD_SP(cmd)); qla1280_print(debug_buff); - sprintf(debug_buff," r_start=0x%lx, u_start=0x%lx\n\r",sp->r_start,sp->u_start); - qla1280_print(debug_buff); sprintf(debug_buff," underflow size = 0x%x, direction=0x%x, req.cmd=0x%x \n\r", cmd->underflow, sp->dir,cmd->request.cmd); qla1280_print(debug_buff); } @@ -6689,23 +7002,6 @@ } #endif -#ifdef QLA1280_UNUSED -/************************************************************************** - * ql1280_dump_regs - * - **************************************************************************/ -static void qla1280_dump_regs(struct Scsi_Host *host) -{ - printk("Mailbox registers:\n"); - printk("qla1280 : mbox 0 0x%04x \n", inw(host->io_port + 0x70)); - printk("qla1280 : mbox 1 0x%04x \n", inw(host->io_port + 0x72)); - printk("qla1280 : mbox 2 0x%04x \n", inw(host->io_port + 0x74)); - printk("qla1280 : mbox 3 0x%04x \n", inw(host->io_port + 0x76)); - printk("qla1280 : mbox 4 0x%04x \n", inw(host->io_port + 0x78)); - printk("qla1280 : mbox 5 0x%04x \n", inw(host->io_port + 0x7a)); -} -#endif - #if STOP_ON_ERROR @@ -6732,9 +7028,6 @@ printk("HA flags =0x%lx\n", *fp); DEBUG2(ql_debug_print = 1;) /* DEBUG2(ql1280_dump_device((scsi_qla_host_t *) host->hostdata)); */ -#ifdef QLA1280_UNUSED - qla1280_dump_regs(host); -#endif sti(); panic("Ooops"); /* cli(); @@ -6747,11 +7040,6 @@ } #endif -#ifdef QLA1280_UNUSED -static void qla1280_set_flags(char * s) -{ -} -#endif /************************************************************************** * qla1280_setup @@ -6765,24 +7053,6 @@ { char *end, *str, *cp; -#ifdef QLA1280_UNUSED - static struct - { - const char *name; - int siz; - void (*func)(); - int arg; - } options[] = - { - { "dump_regs", 9, &qla1280_dump_regs, 0 - }, - { "verbose", 7, &qla1280_set_flags, 0x1 - }, - { "", 0, NULL, 0 - } - }; -#endif - printk("scsi: Processing Option str = %s\n", s); end = strchr(s, '\0'); /* locate command */ @@ -6832,4 +7102,3 @@ * tab-width: 8 * End: */ - diff -Nur linux-2.4.19/drivers/scsi/qla1280.h linux-2.4.19-sgi211r3/drivers/scsi/qla1280.h --- linux-2.4.19/drivers/scsi/qla1280.h Mon Sep 17 13:16:31 2001 +++ linux-2.4.19-sgi211r3/drivers/scsi/qla1280.h Tue Jan 8 17:05:38 2002 @@ -1,169 +1,35 @@ -/************************************************************************* - * QLOGIC LINUX SOFTWARE - * - * QLogic ISP1x80/1x160 device driver for Linux 2.3.x (redhat 6.x). - * - * COPYRIGHT (C) 1996-2000 QLOGIC CORPORATION - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the Qlogic's Linux Software License. - * - * This program is WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistribution's or 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. - * - *****************************************************************************/ - -/************************************************************************************* - QLOGIC CORPORATION SOFTWARE - "GNU" GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION - AND MODIFICATION - -This GNU General Public License ("License") applies solely to QLogic Linux -Software ("Software") and may be distributed under the terms of this License. - -1. You may copy and distribute verbatim copies of the Software's source code as -you receive it, in any medium, provided that you conspicuously and appropriately -publish on each copy an appropriate copyright notice and disclaimer of warranty; -keep intact all the notices that refer to this License and to the absence of any -warranty; and give any other recipients of the Software a copy of this License along -with the Software. - -You may charge a fee for the physical act of transferring a copy, and you may at your -option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Software or any portion of it, thus forming -a work based on the Software, and copy and distribute such modifications or work under -the terms of Section 1 above, provided that you also meet all of these conditions: - -* a) You must cause the modified files to carry prominent notices stating that you -changed the files and the date of any change. - -* b) You must cause any work that you distribute or publish that in whole or in part -contains or is derived from the Software or any part thereof, to be licensed as a -whole at no charge to all third parties under the terms of this License. - -* c) If the modified Software normally reads commands interactively when run, you -must cause it, when started running for such interactive use in the most ordinary way, -to print or display an announcement including an appropriate copyright notice and a -notice that there is no warranty (or else, saying that you provide a warranty) and that -users may redistribute the Software under these conditions, and telling the user how to -view a copy of this License. (Exception:if the Software itself is interactive but does -not normally print such an announcement, your work based on the Software is not required -to print an announcement.) - -These requirements apply to the modified work as a whole. If identifiable sections of -that work are not derived from the Software, and can be reasonably considered independent -and separate works in themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you distribute the same -sections as part of a whole which is a work based on the Software, the distribution of the -whole must be on the terms of this License, whose permissions for other licensees extend -to the entire whole, and thus to each and every part regardless of who wrote it. - -3. You may copy and distribute the Software (or a work based on it, under Section 2) in -object code or executable form under the terms of Sections 1 and 2 above provided that -you also do one of the following: - -* a) Accompany it with the complete corresponding machine-readable source code, which must -be distributed under the terms of Sections 1 and 2 above on a medium customarily used for -software interchange; or, - -* b) Accompany it with a written offer, valid for at least three years, to give any third -party, for a charge no more than your cost of physically performing source distribution, -a complete machine-readable copy of the corresponding source code, to be distributed under -the terms of Sections 1 and 2 above on a medium customarily used for software interchange; -or, - -* c) Accompany it with the information you received as to the offer to distribute -corresponding source code. (This alternative is allowed only for noncommercial distribution -and only if you received the Software in object code or executable form with such an offer, -in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for making modifications -to it. For an executable work, complete source code means all the source code for all -modules it contains, plus any associated interface definition files, plus the scripts used -to control compilation and installation of the executable. - -If distribution of executable or object code is made by offering access to copy from a -designated place, then offering equivalent access to copy the source code from the same -place counts as distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Software except as expressly -provided under this License. Any attempt otherwise to copy, modify, sublicense or -distribute the Software is void, and will automatically terminate your rights under this -License. However, parties who have received copies, or rights, from you under this License -will not have their licenses terminated so long as such parties remain in full compliance. - -5. This license grants you world wide, royalty free non-exclusive rights to modify or -distribute the Software or its derivative works. These actions are prohibited by law -if you do not accept this License. Therefore, by modifying or distributing the Software -(or any work based on the Software), you indicate your acceptance of this License to do -so, and all its terms and conditions for copying, distributing or modifying the Software -or works based on it. - -6. Each time you redistribute the Software (or any work based on the Software), the -recipient automatically receives a license from the original licensor to copy, distribute -or modify the Software subject to these terms and conditions. You may not impose any -further restrictions on the recipients' exercise of the rights granted herein. You are -not responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent infringement or for -any other reason (not limited to patent issues), conditions are imposed on you -(whether by court order, agreement or otherwise) that contradict the conditions of this -License, they do not excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this License -and any other pertinent obligations, then as a consequence you may not distribute the -Software at all. - -If any portion of this section is held invalid or unenforceable under any particular -circumstance, the balance of the section is intended to apply and the section as a whole -is intended to apply in other circumstances. -NO WARRANTY - -11. THE SOFTWARE IS PROVIDED WITHOUT A WARRANTY OF ANY KIND. THERE IS NO -WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. -SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR -DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL -DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING -BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR -LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO -OPERATE WITH ANY OTHER SOFTWARES), EVEN IF SUCH HOLDER OR OTHER PARTY HAS -BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -END OF TERMS AND CONDITIONS +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP1280 (Ultra2) /12160 (Ultra3) SCSI driver +* Copyright (C) 2000 Qlogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +** +******************************************************************************/ -*************************************************************************************/ - - #ifndef _IO_HBA_QLA1280_H /* wrapper symbol for kernel use */ #define _IO_HBA_QLA1280_H /* subject to change without notice */ + +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE not defined */ + #if defined(__cplusplus) extern "C" { #endif -#include - +#ifndef HOSTS_C /* included in hosts.c */ /* * Enable define statement to ignore Data Underrun Errors, * remove define statement to enable detection. @@ -173,15 +39,18 @@ /* * Driver debug definitions. */ -/* #define QL_DEBUG_LEVEL_1 */ /* Output register accesses to COM2. */ -/* #define QL_DEBUG_LEVEL_2 */ /* Output error msgs to COM2. */ -/* #define QL_DEBUG_LEVEL_3 */ /* Output function trace msgs to COM2. */ -/* #define QL_DEBUG_LEVEL_4 */ /* Output NVRAM trace msgs to COM2. */ -/* #define QL_DEBUG_LEVEL_5 */ /* Output ring trace msgs to COM2. */ -/* #define QL_DEBUG_LEVEL_6 */ /* Output WATCHDOG timer trace to COM2. */ -/* #define QL_DEBUG_LEVEL_7 */ /* Output RISC load trace msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_1 */ /* Output register accesses to COM1 */ +/* #define QL_DEBUG_LEVEL_2 */ /* Output error msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_3 */ /* Output function trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_4 */ /* Output NVRAM trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_5 */ /* Output ring trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_6 */ /* Output WATCHDOG timer trace to COM1 */ +/* #define QL_DEBUG_LEVEL_7 */ /* Output RISC load trace msgs to COM1 */ + +#define QL_DEBUG_CONSOLE /* Output to console instead of COM1 */ + /* comment this #define to get output of qla1280_print to COM1 */ + /* if COM1 is not connected to a host system, the driver hangs system! */ -#define QL_DEBUG_CONSOLE /* Output to console instead of COM2. */ #ifndef TRUE # define TRUE 1 @@ -206,7 +75,11 @@ * Locking */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) -# include +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) +# include +# else +# include +# endif # include # define cpuid smp_processor_id() # if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) @@ -314,12 +187,12 @@ #define WRT_REG_DWORD(addr, data) qla1280_putdword((uint32_t *)addr, data) #else /* QL_DEBUG_LEVEL_1 */ #ifdef MEMORY_MAPPED_IO - #define RD_REG_BYTE(addr) readb((unsigned long) (addr) - #define RD_REG_WORD(addr) readw((unsigned long) (addr) - #define RD_REG_DWORD(addr) readl((unsigned long) (addr) - #define WRT_REG_BYTE(addr, data) writeb((data), (unsigned long) (addr)) - #define WRT_REG_WORD(addr, data) writew((data), (unsigned long) (addr)) - #define WRT_REG_DWORD(addr, data) writel((data), (unsigned long) (addr)) + #define RD_REG_BYTE(addr) (*((volatile uint8_t *)addr)) + #define RD_REG_WORD(addr) (*((volatile uint16_t *)addr)) + #define RD_REG_DWORD(addr) (*((volatile uint32_t *)addr)) + #define WRT_REG_BYTE(addr, data) (*((volatile uint8_t *)addr) = data) + #define WRT_REG_WORD(addr, data) (*((volatile uint16_t *)addr) = data) + #define WRT_REG_DWORD(addr, data) (*((volatile uint32_t *)addr) = data) #else /* MEMORY_MAPPED_IO */ #define RD_REG_BYTE(addr) (inb((unsigned long)addr)) #define RD_REG_WORD(addr) (inw((unsigned long)addr)) @@ -372,7 +245,8 @@ /* - * SCSI Request Block structure + * SCSI Request Block structure (sp) that is placed + * on cmd->SCp location of every I/O */ typedef struct srb { @@ -381,10 +255,11 @@ struct srb *s_prev; /* (4) Previous block on LU queue */ uint8_t flags; /* (1) Status flags. */ uint8_t dir; /* direction of transfer */ - uint8_t unused[2]; - u_long r_start; /* jiffies at start of request */ - u_long u_start; /* jiffies when sent to F/W */ -}srb_t; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + dma_addr_t saved_dma_handle; /* for unmap of single transfers */ +#endif + +} srb_t; /* * SRB flag definitions @@ -1562,22 +1437,35 @@ request_t req[REQUEST_ENTRY_CNT+1]; response_t res[RESPONSE_ENTRY_CNT+1]; - unsigned long request_dma; /* Physical address. */ +#if BITS_PER_LONG > 32 + dma_addr_t request_dma; /* Physical Address */ +#else + uint32_t request_dma; /* Physical address. */ +#endif request_t *request_ring; /* Base virtual address */ request_t *request_ring_ptr; /* Current address. */ uint16_t req_ring_index; /* Current index. */ uint16_t req_q_cnt; /* Number of available entries. */ - unsigned long response_dma; /* Physical address. */ +#if BITS_PER_LONG > 32 + dma_addr_t response_dma; /* Physical address. */ +#else + uint32_t response_dma; /* Physical address. */ +#endif response_t *response_ring; /* Base virtual address */ response_t *response_ring_ptr; /* Current address. */ uint16_t rsp_ring_index; /* Current index. */ #if QL1280_TARGET_MODE_SUPPORT /* Target buffer and sense data. */ +#if BITS_PER_LONG > 32 + dma_addr_t tbuf_dma; /* Physical address. */ + dma_addr_t tsense_dma; /* Physical address. */ +#else uint32_t tbuf_dma; /* Physical address. */ - tgt_t *tbuf; uint32_t tsense_dma; /* Physical address. */ +#endif + tgt_t *tbuf; uint8_t *tsense; #endif @@ -1614,8 +1502,13 @@ uint32_t dpc :1; /* 15 */ uint32_t dpc_sched :1; /* 16 */ uint32_t interrupts_on :1; /* 17 */ + uint32_t bios_enabled :1; /* 18 */ }flags; + /* needed holders for PCI ordered list of hosts */ + unsigned long io_port; + uint32_t irq; + }scsi_qla_host_t; /* @@ -1644,6 +1537,8 @@ #define QLA1280_RING_LOCK(ha) #define QLA1280_RING_UNLOCK(ha) +#endif /* HOSTS_C */ + #if defined(__cplusplus) } #endif @@ -1661,49 +1556,20 @@ int qla1280_biosparam(Disk *, kdev_t, int[]); void qla1280_intr_handler(int, void *, struct pt_regs *); void qla1280_setup(char *s, int *dummy); -#if defined(__386__) + # define QLA1280_BIOSPARAM qla1280_biosparam -#else -# define QLA1280_BIOSPARAM NULL -#endif /* * Scsi_Host_template (see hosts.h) * Device driver Interfaces to mid-level SCSI driver. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) -/* This interface is now obsolete !!! */ -#define QLA1280_LINUX_TEMPLATE { \ - next: NULL, \ - usage_count: NULL, \ - proc_dir: NULL, \ - proc_info: NULL, \ - name: "Qlogic ISP 1280", \ - detect: qla1280_detect, \ - release: qla1280_release, \ - info: qla1280_info, \ - command: NULL, \ - queuecommand: qla1280_queuecommand, \ - abort: qla1280_abort, \ - reset: qla1280_reset, \ - slave_attach: NULL, \ - bios_param: QLA1280_BIOSPARAM, \ - can_queue: 255, /* MAX_OUTSTANDING_COMMANDS */ \ - this_id: -1, /* scsi id of host adapter */ \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: 3, /* max commands per lun */ \ - present: 0, /* number of 1280s present */ \ - unchecked_isa_dma: 0, /* no memeory DMA restrictions */ \ - use_clustering: ENABLE_CLUSTERING \ -} -#else -#define QLA1280_LINUX_TEMPLATE { \ +#define QLA1280_LINUX_TEMPLATE { \ next: NULL, \ module: NULL, \ proc_dir: NULL, \ proc_info: qla1280_proc_info, \ - name: "Qlogic ISP 1280\1080", \ + name: "Qlogic ISP 1280\12160", \ detect: qla1280_detect, \ release: qla1280_release, \ info: qla1280_info, \ @@ -1723,13 +1589,14 @@ this_id: -1, /* scsi id of host adapter */\ sg_tablesize: SG_ALL, /* max scatter-gather cmds */\ cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ - present: 0, /* number of 7xxx's present */\ + present: 0, /* number of 1280's present */\ unchecked_isa_dma: 0, /* no memory DMA restrictions */\ use_clustering: ENABLE_CLUSTERING, \ use_new_eh_code: 0, \ emulated: 0 \ } -#endif + #endif /* _IO_HBA_QLA1280_H */ + diff -Nur linux-2.4.19/drivers/scsi/qla2x00.c linux-2.4.19-sgi211r3/drivers/scsi/qla2x00.c --- linux-2.4.19/drivers/scsi/qla2x00.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/qla2x00.c Tue Jan 8 17:05:38 2002 @@ -0,0 +1,12823 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic QLA2x00 device driver for Linux 2.2.x and 2.4.x +* Copyright (C) 2000 and 2001 Qlogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +** +******************************************************************************/ +#define QLA2100_VERSION "4.31.7b" +/**************************************************************************** +Revision History: + Rev. 4.31.7b June 8, 2001 DG QLogic + - Fixed issue when loop id for target is changed to a different + loop id. + Rev. 4.31.6 June 1, 2001 DG QLogic + - Official 2200 firmware: v2.01.34 + - Official 2300 firmware: v3.00.24 + Rev. 4.31.5b May 30, 2001 DG QLogic + - Reset SRB_SENT flag in all isr routines. + - Fix displaying garbage when using /proc. + Rev. 4.31.3b May 15, 2001 DG QLogic + - Using test 2200 firmware: v204.01.33 + Rev. 4.31.2b May 15, 2001 DG QLogic + - Using test 2200 firmware: v203.01.33 + Rev. 4.31.1b May 15, 2001 DG QLogic + - Upgrade FC firmware to: 2200 v209.01.27 + - Changed logic to handle a topology of 4 after issuing the + "Get Host loop id". + Rev. 4.31b May 15, 2001 RL QLogic + - Added code to export PCI device info via a new ioctl function + in kernel 2.4.4. + - Redirect console messages to the OS messages file only. + - Additional fix in ioctl functions for node/port name endianess + problem. + Rev. 4.30b May 3, 2001 RL QLogic + - Moved the allocation of host database to outside of the adapter + structure allocation to avoid the allocation size limitation in the + scsi_register function. + Rev. 4.29b April 27, 2001 RL QLogic + - Fixed endianess of the node and port names read from the config + file for persistent binding entries. + Rev. 4.28b April 26, 2001 DG QLogic + - Fixed persistent binding of target devices. + Rev. 4.27 April 26, 2001 DG QLogic + - Fixed Mailbox timeout logic + - Fixed to compile on 2.4.x RedHat systems. + Rev. 4.25 March 15, 2001 DG QLogic + - released + Rev. 4.25 Beta March 9, 2001 DG QLogic + - incl new qlavendor.c file. + Rev. 4.24 Beta Test32 February 22, 2001 BN QLogic + - Added code for scanning of missing LUN to let the + SCSI layer skip it. + - Revised init_cb_t structure in qla2x00.h for the new + QLA2300 as well as QLA2200 devices. + - Changed criteria of 64/32 Bit mode of HBA + operation according to BITS_PER_LONG rather + than HBA's NVRAM setting of >4Gig memory bit; + so that the HBA auto-configures without the need + to setup each system individually. + - Merged changes for proper compile and operation in Alpha systems. + - Upgrade FC firmware to: QLA2300 v3.00.18 *new + and enabled FC Loopback test on QLA2300 HBAs. + - Add statistics counters and IOCTL support for + HBA Error Count, LIP Resets, and total ISR count. + - Changed qla2100_reinit on loop down after 4 minutes + specific to QLA2100 HBAs only. + - Added code and Makefile option to handle RISC code + download differently for ia-64 platforms than x86 or alpha. + Rev. 4.23 Beta January 12, 2001 BN QLogic + - Use cmd->sc_data_direction for setting of HBA data transfer + direction for 2.4.0 and higher kernels. + Note: Users must set the reply_len in sg_header. + For Writes and no data transfer; reply_len should + be the lenght of sg_header. + For Reads, reply_len should be the length of sg_header + plus the number of bytes to be read. + - Added check of SCSI_RESET_SUGGEST_BUS_RESET during + qla2100_reset() and perform BUS_RESET. + Also perform DEVICE_RESET on else of flag checking. + - Added new /proc/scsi/qla2x00/HbaApiNode for IOCTL interface + for 2.4.x kernels; so driver can be accessed with out need + to have at least one mapped scsi drive. + - Modified qla2100_mailbox_command's second parameter + to 32 bits for use by Loop-Back Diagnostic function + - Increase MAILBOX_REGISTER_COUNT to 32 + - Added Loop-Back Diagnostic function to qla2x00ioctl.c + for QLA2200 HBAs only. + - Order HBA detection as follows: + QLA2300, QLA2200, QLA2100. + - Changed queue_task() to queue_task_irq() in + qla2100_intr_handler() for proper usage. + - In qla2100_register_with_Linux() put check and getting + device iobase before registering of interrupt with Linux; + to help with driver loading/unloading when ramdisk is also loaded. + - Change IOCTL support to SDM_VERSION 5 in qla2x00ioctl.c + to be support SNIA HBA API 1.0 Library + - Upgrade FC firmware to: QLA2200 v2.01.27 *new + QLA2300 v3.00.17 *new + - Added copy of HBA Serial Number to /proc entry + - Added sigmask(SIGKILL) as second parameter to + siginitsetinv() function called during qla2100_do_dpc(); + so that the driver can be unloaded for 2.4.0 kernels. + Rev. 4.22 Beta November 22, 2000 BN QLogic + - Change IOCTL support to SDM_VERSION 4 in qla2x00_v4_ioctl.c + to be compatible with ln_rel-1.0Beta API library + Rev. 4.21 Beta November 15, 2000 BN QLogic + - Upgrade FC firmware to: 2100 v1.19.16 + 2200 v2.01.24 + 2300 v3.00.12 + - Merge of qla2x00 driver 2.19.16Beta changes. + - Updated qlavendor.c for vendor unique command + decoding. + Rev. 4.20 Beta October 17, 2000 BN QLogic + - QLA2300 Support added. + Rev. 4.14 Beta October 16, 2000 BN QLogic + - Added setting of higher address bits for + MBC_INITIALIZE_FIRMWARE operation. + - Release also contains newer qlavendor.c file + - Move to the new SCSI initialization scheme + and always declare the static driver_template + for kernels 2.4.0 and higher + Rev. 4.13 Beta September 21, 2000 BN QLogic + - Added "quiet" option to keep from printing LIP + occurred messages on systems that specify it. + - Added option to choose tp or ef, FC firmware + Rev. 4.12 Beta September 18, 2000 BN QLogic + - Added pci_set_master() to qla2100_pci_config + function to make sure all systems are supported + Rev. 4.11 Beta September 6, 2000 BN QLogic + - Enabled IOCTLs for external IOCTL and APIs + Rev. 4.10 Beta August 28, 2000 BN Qlogic + - Use new PCI DMA mapping APIs for 2.4.x kernel + - Added driver IOCTL support code; but disabled + it with #if 0 for next release + - Verified correct 64 bit addressing with NVRAM: + enable_64bit_addressing (>4GByte Addressing) + enabled in BIOS advanced settings option. + Rev. 4.0 July 24, 2000 BN Qlogic + - Added FC Tape Support by use of new FC Firmware + ql2100_fw.h must be v1.19.12 or greater + ql2200_fw.h must be v2.01.16 or greater + - Corrected HBA Node Name equal to zero + - Changed QLBoardTbl to QLBoardTbl_fc to avoid + double definition error with regards to qla1280 + on new 2.4.0 kernel build tools + Rev. 3.90 Beta July 21, 2000 BN Qlogic + - Added 64 bit OS and IA-64 hardware support + - Move to new major revision number + Rev. 2.22 July 14, 2000 BN Qlogic + - Updated 2100 FW to 1.19.10 + - Updated 2200 FW to 2.01.14 + - Move version to 2.22 for release to DVT + Rev. 2.19.8 July 11, 2000 DG Qlogic + - Fixed 2100 issue of login retry when no fabric is attached. + Rev. 2.19.7 July 6, 2000 DG + - Set queue depth per lun to 16 instead of throttle which is a + port max queue size and added an option "ql2xmaxqdepth=xx" + to allow user to change queue depth. This prevents us from + exceeding the adapter's throttle size which causes requests + to sit in the input queue for long periods of time. + Rev. 2.19.6 June 28, 2000 DG Qlogic + - GA release + - Fixed panic in putq_t routine when called from abort. + Rev. 2.19.5b7 June 27, 2000 DG + - Add logic to wait reset delay if no fabric devices are found. + Rev. 2.19.5b6 June 26, 2000 DG + - Fixed Fw ready issue. + - Clear sent flag in SRB, so we will abort commands in Lun + queue that were previously sent. + - Flush input queue when an isp_abort occurs. + Rev. 2.19.5b5 June 16, 2000 DG + - Fixed issue of not holding off request if multiple RSCN or + PORT updates occur while process the currect RSCN. + Rev. 2.19.5b4 June 16, 2000 DG + - Added lock for done_q to prevent losing requests in timer. + Rev. 2.19.5b3 June 16, 2000 DG + - Added routine to set the correct direction for vendor specific + commands. Set the new option "QLA_SCSI_VENDOR_DIR". + - Fixed issue of retrying continuously on a Missing SCSI device. + - Fixed multiple adapter issue. Only login into adapter node + once and never again. + - Change code not to use loop id 0 for Fabric nodes. + Rev. 2.19.5b2 June 15, 2000 DG + - Added code to reset port down count on good requests. + Rev. 2.19.5 June 8, 2000 DG + - Added code to display the connection type F, FL, or N. + - Reaarange code in DPC routine to put "retry login" + further down in the routine and skip is loop is down. + - Check the returned status after GAN (qla2100_sns_device) + and retry on ISP TX timeout (0x4005). + Rev. 2.19.4 June 6, 2000 DG + - Fixed for panic that occurs when system is shutdown. + Rev. 2.19.3 June 5, 2000 DG + - Fixed retry logic for user configured targets. + Rev. 2.19.2 May 31, 2000 DG + - Remove spinlock in qla2100_timer. + - Change the jiffies timer to loop timer in fw_ready. + Rev. 2.19.1 May 6, 2000 DG + - Change risc code 2200 from 2.1.12 to 2.1.13 to correct issue + of getting mailbox timeouts. + - Change mailbox timer to get correct timeout. + - Added qla2100_cmd_wait to wait for outstanding commands to + complete before querying the name server after a LIP. + Rev. 2.19 May 6, 2000 DG + - Fixed mailbox timeout recovery logic. + Rev. 2.18 May 1, 2000 DG + - Changes from Fabric testing + Rev. 2.18b4 Apr 21, 2000 DG + - Fixed login retry count to retry count. + - If the loop is down for more than 4 minutes then restart + queues and reset adpater if enabled. + - In qla2100_queuecommand we no longer return new requests + immediately back to kernel when loop is down. This causes + SYSTEM to HANG when a lot of requests are outstanding. We + now put them in the done queue and let the DPC routine + return them to kernel. + - Fixed panic cause by changing the timeout value of new request + when the loop is down. + - Cleanup qla2100_next. + Rev. 2.18b3 Apr 18, 2000 DG + - After the GAN, check returned status in resp buffer. + Rev. 2.18b2 Apr 12, 2000 DG + - Added handling of firmware bug when we use connection mode + 1 (P2P). The firmware tries to change to loop mode after + encountering some IO failures/resets. + - Added logic to reset all modules during a chip reset. + - After the GAN, if we lost devices or have a device that was + configured by the user then retry the login. This is a + work-a-round for Brocade switches. It sometimes does + not return all the devices in the port list. + Rev. 2.18b1 Apr 1, 2000 DG + - Added logic to ignore device types other than FL/F + from gan list. Mcdata switch returns a bogus port of + type 85 in the list. + - Added firmware 2.1.11 to fix issues with reusing loop ids. + Rev. 2.17 Mar 21, 2000 DG + - Fixed mailbox timeout timer. + - Added counters to record timeouts and aborts. + Rev. 2.16 Mar 8, 2000 DG + - Fixed Profiling code to reduced output of inactive devices. + - Fixed driver name in "/proc/scsi/qla2x00" instead of "qla". + - Fixed extended timeout value for loop down retries. + - Fixed code that search for target binding in command line to search + for all occurences instead of the first four. + - Disable the reinit of adapter when the LOOP is DOWN + for more than 4 minutes. It can be enabled with the command + line option "reinit_on_loopdown". + - Fixed issue of not setting HBA instance number before + calling HBA initialized. + Rev. 2.15 Feb 19, 2000 DG + - Fixed 2100 issue of driver not seeing storage when switch is connected + to loop. + Rev. 2.14 Feb 11, 2000 DG + - Added new logic to accept persistent binding information from the command line. + - Modified command parser to handle properties on the command line after + the regular options. + Rev. 2.13 Jan 27, 2000 TT + - Modify to use makefile parameter "IP=1" to enanle IP support. + - Fix SNS mailbox cmd parameter in qla2x00_register_ip_device. + - Reverse byte order on ha->port_id to match NT and fix compare bugs. + Rev. 2.12 Jan 26, 2000 TT+DG + - Updated Qlogic Linux sofware license. + - Added IP support for qla2xip driver. + - Fix host adapter structure initialization in qla2100_detect. + - Fix port name byte order in qla2100_update_fc_db. + - Fix the issue of not returning "NO_CONNECT" back to the user + when the loop is down after the loop down timer has expired. + - Added option QLA2100_EXT_TIMEOUT to extend timeout of each command. + default if OFF. + - Change device high water mark (hiwat) to execution throttle. + Rev. 2.11 Dec 8, 1999 DG + - Added Qlogic Linux sofware license. + Rev. 2.10 Oct 31, 1999 DG + - Fixed issue of not releasing requests if port is down (DPC issue). + - Ignore BIOS setting for MAX number of luns unless USE_BIOS_MAX_LUNS + is set. +*****************************************************************************/ + +/* +* Compile time Options: +* 0 - Disable and 1 - Enable +*/ +#define QL2100_TARGET_MODE_SUPPORT 0 /* Target mode support */ +#define MEMORY_MAPPED_IO 0 +#define DEBUG_QLA2100_INTR 0 +#define USE_NVRAM_DEFAULTS 0 +#define DEBUG_PRINT_NVRAM 0 +#define LOADING_RISC_ACTIVITY 0 +#define AUTO_ESCALATE_RESET 0 /* Automatically escalate resets */ +#define AUTO_ESCALATE_ABORT 0 /* Automatically escalate aborts */ +#define STOP_ON_ERROR 0 /* Stop on aborts and resets */ +#define STOP_ON_RESET 0 +#define STOP_ON_ABORT 0 +#define QLA2100_COMTRACE 0 /* One char tracing */ +#define WATCH_THREADS_SIZ 0 /* watch size of pending queue */ +#define USE_PORTNAME 1 /* option to use port names for targets */ +#define QLA2100_EXT_TIMEOUT 0 /* Extend timeout for commands up to 1 min*/ +#define LUN_MASKING 0 +#define USE_FLASH 0 +#define QLA2100_PROFILE 1 +#define QLA_SCSI_VENDOR_DIR 0 /* Decode vendor specific opcodes for direction */ +#define QLA2100_LIPTEST 0 +#define REQ_TRACE 1 + +#undef TRACECODE /* include tracing code in watchdog routines */ +#define CHECK_BINDING + +#define DEBUG_QLA2100 0 /* For Debug of qla2x00 */ +#define DEBUG_GET_FW_DUMP 0 /* also set DEBUG_QLA2100 and + use COM1 and capture it */ +#define USE_TP_FW 1 /* use tp or ef firmware */ + +/* The following WORD_FW_LOAD is defined in Makefile for ia-64 builds + and can also be decommented here for Word by Word confirmation of + RISC code download operation */ +/* #define WORD_FW_LOAD 0 */ + +/* +* String arrays +*/ +#define LINESIZE 256 +#define MAXARGS 26 + +/* +* Include files +*/ +#include +#ifdef MODULE +#include +#endif + +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE not defined */ + +static int num_hosts; /* ioctl related */ +static int apiHBAInstance = 0; /* ioctl related keeps track of API HBA Instance */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) +#define APIDEV 1 +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +#include +# include +#else +/*#include */ + +#define __KERNEL_SYSCALLS__ + +#include +#include + +#include +#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) +#endif +#include "sd.h" +#include "scsi.h" +#include "hosts.h" + +#ifdef FC_IP_SUPPORT +#include +#include "qlcommon.h" +#endif + +#include "qla2x00.h" +#define UNIQUE_FW_NAME /* unique F/W array names */ +#ifdef UNIQUE_FW_NAME +#include "ql2100_fw.h" /* ISP RISC code */ +#ifdef FC_IP_SUPPORT +#include "ql2200ip_fw.h" /* ISP RISC 2200 code */ +#include "ql2300ip_fw.h" /* ISP RISC 2300 code */ +#else +#include "ql2200_fw.h" /* ISP RISC 2200 code */ +#include "ql2300_fw.h" /* ISP RISC 2300 code */ +#endif +#else +#include "isp_fw.h" /* ISP RISC code */ +#include "isp1_fw.h" /* ISP RISC 2200 code */ +#endif +#include +#include + + +#define BZERO(ptr, amt) memset((void *)(ptr), 0, amt) +#define BCMP(s1, s2, amt) memcmp((void *)(s1), (void *)(s2), amt) +#define BCOPY(src, dst, amt) memcpy((void *)(dst), (void *)(src), amt) +#define KMALLOC(siz) kmalloc((siz), GFP_ATOMIC | GFP_DMA) +#define KMFREE(ip,siz) kfree((ip)) +#define SYS_DELAY(x) udelay(x);barrier() +#define QLA2100_DELAY(sec) mdelay(sec * HZ) + +/* 4.10 */ +#if BITS_PER_LONG > 32 +#define pci_dma_lo32(a) (a & 0xffffffff) +#define pci_dma_hi32(a) ((a >> 32) & 0xffffffff) +#else +#define pci_dma_lo32(a) (a & 0xffffffff) +#define pci_dma_hi32(a) 0 +#endif + +#define VIRT_TO_BUS(a) virt_to_bus((a)) + +#if BITS_PER_LONG <= 32 +#define VIRT_TO_BUS_LOW(a) (uint32_t)virt_to_bus(((void *)a)) +#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0x0) +#else +#define VIRT_TO_BUS_LOW(a) (uint32_t)(0xffffffff & virt_to_bus((void *)(a))) +#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0xffffffff & (virt_to_bus((void *)(a))>>32)) +#endif + +#define CACHE_FLUSH(a) (RD_REG_WORD(a)) +#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS+1) + +#define STATIC + +#if BITS_PER_LONG <= 32 +#define LS_64BITS(x) (uint32_t)((unsigned long)x) +#define MS_64BITS(x) (uint32_t)((unsigned long) 0x0) +#else +#define LS_64BITS(x) (uint32_t)(0xffffffff & ((unsigned long)x)) +#define MS_64BITS(x) (uint32_t)(0xffffffff & (((unsigned long)x)>>32) ) +#endif + +#if BITS_PER_LONG <= 32 +#define MSB(x) (uint8_t)(((uint16_t)(x) >> 8) & 0xff) +#define LSB(x) (uint8_t)(x & 0xff) +#define MSW(x) (uint16_t)(((uint32_t)(x) >> 16) & 0xffff) +#define LSW(x) (uint16_t)(x & 0xffff) +#define QL21_64BITS_3RDWD(x) ((uint16_t) 0) +#define QL21_64BITS_4THWD(x) ((uint16_t) 0) +#else +#define MSB(x) (uint8_t)(((uint16_t)(x) >> 8) & 0xff) +#define LSB(x) (uint8_t)(x & 0xff) +#define MSW(x) (uint16_t)(((uint32_t)(x) >> 16) & 0xffff) +#define LSW(x) (uint16_t)(x & 0xffff) +#define QL21_64BITS_3RDWD(x) ((uint16_t) (x >> 32) & 0xffff) +#define QL21_64BITS_4THWD(x) ((uint16_t) (x >> 48) & 0xffff) +#endif + +#define OFFSET(w) (((u_long) &w) & 0xFFFF) /* 256 byte offsets */ +#define SCSI_BUS_32(scp) ((scp)->channel) +#define SCSI_TCN_32(scp) ((scp)->target) +#define SCSI_LUN_32(scp) ((scp)->lun) + +/* +* TIMER MACROS +*/ +#define QLA2100_TIMER_LOCK(ap) spin_lock_irqsave(&(ap)->retry_lock, cpu_flags); +#define QLA2100_TIMER_UNLOCK(ap) spin_unlock_irqrestore(&(ap)->retry_lock, cpu_flags); + + +#define WATCH_INTERVAL 1 /* number of seconds */ +#define START_TIMER(f, h, w) \ +{ \ +init_timer(&(h)->timer); \ +(h)->timer.expires = jiffies + w * HZ;\ +(h)->timer.data = (unsigned long) h; \ +(h)->timer.function = (void (*)(unsigned long))f; \ +(h)->flags.start_timer = FALSE; \ +add_timer(&(h)->timer); \ +(h)->timer_active = 1;\ +} + +#define RESTART_TIMER(f, h, w) \ +{ \ +(h)->timer.expires = jiffies + w * HZ;\ +(h)->flags.start_timer = FALSE; \ +add_timer(&(h)->timer); \ +} + +#define STOP_TIMER(f, h) \ +{ \ +del_timer(&(h)->timer); \ +(h)->timer_active = 0;\ +} + +#define NVRAM_DELAY() udelay(500) /* 2 microsecond delay */ + +typedef unsigned long paddr32_t; + +/* +* Qlogic Driver support Function Prototypes. +*/ +STATIC uint8_t qla2100_register_with_Linux(scsi_qla_host_t *ha, uint8_t maxchannels); +STATIC void qla2100_done(scsi_qla_host_t *, srb_t **, srb_t **), +qla2100_next(scsi_qla_host_t *, scsi_lu_t *), +qla2100_select_queue_depth(struct Scsi_Host *, Scsi_Device *); + +STATIC void qla2100_done_q_put(scsi_qla_host_t *, srb_t *, srb_t **, srb_t **), +qla2100_putq_b(scsi_lu_t *, srb_t *), +qla2100_putq_t(scsi_lu_t *, srb_t *), +qla2100_removeq(scsi_lu_t *, srb_t *), +qla2100_timer(scsi_qla_host_t *), +qla2100_timeout_insert(scsi_qla_host_t *, srb_t *), +qla2100_timeout_remove(scsi_qla_host_t *, srb_t *); + +STATIC uint8_t qla2100_mem_alloc(scsi_qla_host_t *); + +static void qla2100_dump_regs(struct Scsi_Host *host); +#if STOP_ON_ERROR +static void qla2100_panic(char *, struct Scsi_Host *host); +#endif +void qla2100_print_scsi_cmd(Scsi_Cmnd *cmd); +STATIC void qla2100_abort_queue_single(scsi_qla_host_t *,uint32_t,uint32_t,uint32_t,uint32_t); + +STATIC int qla2100_return_status(scsi_qla_host_t *ha, sts_entry_t *sts, Scsi_Cmnd *cp); +STATIC void qla2100_removeq(scsi_lu_t *q, srb_t *sp); +STATIC void qla2100_mem_free(scsi_qla_host_t *ha); +void qla2100_do_dpc(void *p); + +static inline void qla2100_callback(scsi_qla_host_t *ha, srb_t *sp, uint8_t dec), +qla2100_tgt_dealloc(scsi_qla_host_t *, tgt_t *), +qla2100_lun_dealloc(scsi_lu_t *); +static inline tgt_t *qla2100_tgt_alloc(scsi_qla_host_t *); +static inline scsi_lu_t *qla2100_lun_alloc(void); + +static inline void qla2100_enable_intrs(scsi_qla_host_t *); +static inline void qla2100_disable_intrs(scsi_qla_host_t *); +#if QLA2100_EXT_TIMEOUT +static void qla2100_extend_timeout(Scsi_Cmnd *cmd, int timeout); +#endif +static int qla2100_get_tokens(char *line, char **argv, int maxargs ); + +/* +* QLogic ISP2100 Hardware Support Function Prototypes. +*/ +STATIC uint8_t qla2100_initialize_adapter(scsi_qla_host_t *), +qla2100_isp_firmware(scsi_qla_host_t *), +qla2100_pci_config(scsi_qla_host_t *), +qla2100_set_cache_line(scsi_qla_host_t *), +qla2100_chip_diag(scsi_qla_host_t *), +qla2100_setup_chip(scsi_qla_host_t *), +qla2100_init_rings(scsi_qla_host_t *), +qla2100_fw_ready(scsi_qla_host_t *), +qla2100_nvram_config(scsi_qla_host_t *), +qla2200_nvram_config(scsi_qla_host_t *), +qla2100_mailbox_command(scsi_qla_host_t *, uint32_t, uint16_t *), +qla2100_update_device_data(scsi_qla_host_t *, device_data_t *, u_char), +qla2100_sns_device(scsi_qla_host_t *, u_char), +qla2100_update_fc_db(scsi_qla_host_t *, u_char), +qla2100_map_targets(scsi_qla_host_t *), +#if USE_FLASH +qla2100_get_database(scsi_qla_host_t *), +qla2100_save_database(scsi_qla_host_t *), +qla2100_program_flash_address(scsi_qla_host_t *, uint32_t, u_char), +qla2100_erase_flash_sector(scsi_qla_host_t *, uint32_t), +qla2100_poll_flash(scsi_qla_host_t *, uint32_t, u_char), +#endif +qla2100_loop_reset(scsi_qla_host_t *), +qla2100_device_reset(scsi_qla_host_t *, uint32_t, uint32_t), +qla2100_abort_device(scsi_qla_host_t *, uint32_t, uint32_t, uint32_t), +qla2100_abort_command(scsi_qla_host_t *, srb_t *), +qla2100_64bit_start_scsi(scsi_qla_host_t *, srb_t *), +qla2100_32bit_start_scsi(scsi_qla_host_t *, srb_t *), +qla2100_abort_isp(scsi_qla_host_t *), +qla2100_loop_resync(scsi_qla_host_t *); +STATIC uint8_t qla2100_cmd_wait(scsi_qla_host_t *ha); + +STATIC void qla2100_nv_write(scsi_qla_host_t *, uint16_t), +qla2100_nv_delay(void), +qla2100_poll(scsi_qla_host_t *), +qla2100_init_fc_db(scsi_qla_host_t *), +qla2100_init_tgt_map(scsi_qla_host_t *), +#if USE_FLASH +qla2100_flash_enable(scsi_qla_host_t *), +qla2100_flash_disable(scsi_qla_host_t *), +qla2100_write_flash_byte(scsi_qla_host_t *, uint32_t, u_char), +#endif +qla2100_reset_adapter(scsi_qla_host_t *), +qla2100_marker(scsi_qla_host_t *, uint32_t, uint32_t, uint32_t, +u_char), +qla2100_enable_lun(scsi_qla_host_t *), +qla2100_notify_ack(scsi_qla_host_t *, notify_entry_t *), +qla2100_64bit_continue_io(scsi_qla_host_t *, atio_entry_t *, + uint32_t, u_long *), +qla2100_32bit_continue_io(scsi_qla_host_t *, atio_entry_t *, + uint32_t, u_long *), +qla2100_isp_cmd(scsi_qla_host_t *), +qla2100_isr(scsi_qla_host_t *, srb_t **, srb_t **), +qla2100_rst_aen(scsi_qla_host_t *), +qla2100_atio_entry(scsi_qla_host_t *, atio_entry_t *), +qla2100_status_entry(scsi_qla_host_t *, sts_entry_t *, srb_t **, +srb_t **), +qla2100_error_entry(scsi_qla_host_t *, response_t *, srb_t **, +srb_t **), +qla2100_restart_queues(scsi_qla_host_t *, uint8_t), +qla2100_restart_watchdog_queue(scsi_qla_host_t *), +qla2100_abort_queues(scsi_qla_host_t *, uint8_t); + +STATIC uint16_t qla2100_get_nvram_word(scsi_qla_host_t *, uint32_t), +qla2100_nvram_request(scsi_qla_host_t *, uint32_t), +qla2100_read_flash_byte(scsi_qla_host_t *, uint32_t), +qla2100_debounce_register(volatile uint16_t *); + +STATIC request_t *qla2100_req_pkt(scsi_qla_host_t *); +STATIC request_t *qla2100_ms_req_pkt(scsi_qla_host_t *, srb_t *); +uint8_t qla2100_update_config(scsi_qla_host_t *ha); +STATIC uint8_t qla2100_configure_hba(scsi_qla_host_t *ha); +STATIC uint8_t qla2100_configure_loop(scsi_qla_host_t *ha, uint8_t ); +STATIC void qla2100_reset_chip(scsi_qla_host_t *ha); +#if QL2100_TARGET_MODE_SUPPORT +qla2100_enable_lun(scsi_qla_host_t *, uint8_t, uint32_t), +qla2100_notify_ack(scsi_qla_host_t *, notify_entry_t *), +qla2100_immed_notify(scsi_qla_host_t *, notify_entry_t *), +qla2100_accept_io(scsi_qla_host_t *, ctio_ret_entry_t *), +qla2100_64bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, + u_long *), +qla2100_32bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, + u_long *), +qla2100_atio_entry(scsi_qla_host_t *, atio_entry_t *), +qla2100_notify_entry(scsi_qla_host_t *, notify_entry_t *), + +#endif /* QLA2100_TARGET_MODE_SUPPORT */ +STATIC uint8_t qla2100_sns_get_name( scsi_qla_host_t *ha, device_data_t *device, uint8_t flag ); +STATIC void qla2100_display_fc_names(scsi_qla_host_t *ha); +void ql2100_dump_requests(scsi_qla_host_t *ha); +static void qla2100_get_properties(scsi_qla_host_t *ha, char *string); +STATIC uint8_t qla2100_find_propname(scsi_qla_host_t *ha, char *propname, char *propstr, char *db); +static int qla2100_get_prop_16chars(scsi_qla_host_t *ha, char *propname, char *propval, char *cmdline); +static char *qla2100_get_line(char *str, char *line); +void qla2100_check_fabric_devices(scsi_qla_host_t *ha); + +#ifdef FC_IP_SUPPORT + +/* Entry points for IP network driver */ +int qla2x00_ip_inquiry(uint16_t wAdapterNumber, BD_INQUIRY_DATA *pInquiryData); +int qla2x00_ip_enable(scsi_qla_host_t *ha, BD_ENABLE_DATA *pEnableData); +void qla2x00_ip_disable(scsi_qla_host_t *ha); +void qla2x00_add_buffers(scsi_qla_host_t *ha, uint16_t wBufferCount); +int qla2x00_send_packet(scsi_qla_host_t *ha, SEND_CB *pSendCB); + +static int qla2x00_ip_initialize(scsi_qla_host_t *ha); +static int qla2x00_add_new_ip_device(scsi_qla_host_t *ha, +uint16_t wLoopId, +uint8_t *pPortId, +uint8_t *pPortName, +int bForceAdd); +static int qla2x00_convert_to_arp(scsi_qla_host_t *ha, SEND_CB *pSendCB); +static void qla2x00_free_ip_block(scsi_qla_host_t *ha, +IP_DEVICE_BLOCK *pIpDevice); +static int qla2x00_get_ip_loopid(scsi_qla_host_t *ha, +uint8_t *pNodeName, +uint8_t *pLoopId); +static int qla2x00_send_farp_request(scsi_qla_host_t *ha, +uint8_t *pPortName); +static int qla2x00_register_ip_device(scsi_qla_host_t *ha); +static int qla2x00_reserve_ip_block(scsi_qla_host_t *ha, +PIP_DEVICE_BLOCK *pIpDevBlk); +static int qla2x00_update_ip_device_data(scsi_qla_host_t *ha, +device_data_t *pDeviceData); +static int qla2x00_reserve_loopid(scsi_qla_host_t *ha, uint16_t *pLoopId); +static void qla2x00_free_loopid(scsi_qla_host_t *ha, uint16_t wLoopId); +static int qla2x00_login_public_device(scsi_qla_host_t *ha, +uint16_t *pLoopId, +uint8_t *pPortID, +uint16_t wOptions); +static int qla2x00_logout_public_device(scsi_qla_host_t *ha, +uint16_t wLoopId, +uint16_t wOptions); +#else +/* v2.19.8 */ +static int qla2x00_login_public_device(scsi_qla_host_t *ha, +uint16_t *pLoopId, +uint8_t *pPortID, +uint16_t wOptions); +static int qla2x00_reserve_loopid(scsi_qla_host_t *ha, uint16_t *pLoopId); +static void qla2x00_free_loopid(scsi_qla_host_t *ha, uint16_t wLoopId); +#endif + +#if APIDEV +static int apidev_init(struct Scsi_Host*); +static int apidev_cleanup(void); +#endif + +void qla2100_print_q_info(scsi_lu_t *q); + +#if DEBUG_QLA2100 +#ifndef QL_DEBUG_ROUTINES +#define QL_DEBUG_ROUTINES +#endif +#endif +#ifdef QL_DEBUG_ROUTINES +/* +* Driver Debug Function Prototypes. +*/ +STATIC uint8_t qla2100_getbyte(uint8_t *); +STATIC uint16_t qla2100_getword(uint16_t *); +STATIC uint32_t qla2100_getdword(uint32_t *); +STATIC void qla2100_putbyte(uint8_t *, uint8_t), +qla2100_putword(uint16_t *, uint16_t), +qla2100_putdword(uint32_t *, uint32_t), +qla2100_print(int8_t *), +qla2100_output_number(u_long, uint8_t), +qla2100_putc(int8_t); +#endif +#if DEBUG_GET_FW_DUMP +STATIC void qla2300_dump_isp(scsi_qla_host_t *ha), +qla2100_dump_word(uint8_t *, uint32_t, uint32_t); +#endif + +/* Debug print buffer */ +char debug_buff[LINESIZE]; +#if DEBUG_QLA2100 +STATIC uint8_t ql2x_debug_print = 1; +#else +STATIC uint8_t ql2x_debug_print = 0; +#endif + +/* +* insmod needs to find the variable and make it point to something +*/ +static char *ql2xdevconf = NULL; +static int ql2xretrycount = 8; +#ifdef MODULE +static char *ql2xopts = NULL; +static int ql2xmaxqdepth = 0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18) + +/* insmod qla2100 ql2xopts=verbose" */ +MODULE_PARM(ql2xopts, "s"); +MODULE_PARM(ql2xmaxqdepth, "i"); +#endif +/* +* Just in case someone uses commas to separate items on the insmod +* command line, we define a dummy buffer here to avoid having insmod +* write wild stuff into our code segment +*/ +static char dummy_buffer[60] = "Please don't add commas in your insmod command!!\n"; + +#endif + +/* +* Macros to change names of OS remapping routines. +*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif + + +/* +* This is the pointer to the /proc/scsi/qla2100 code. +* access the driver. +*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) +#if CONFIG_PROC_FS +/* this definition is normally in proc_fs.h PROC_SCSI_QL2100 */ +#define PROC_SCSI_QL2100 PROC_SCSI_QLOGICISP + +struct proc_dir_entry proc_scsi_qla2100 = { +PROC_SCSI_QL2100, 7, "qla2x00", +S_IFDIR | S_IRUGO | S_IXUGO, 2, +0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +#endif +#endif +static int qla2100_lip = 0; + +#include +#include + +/* multi-OS QLOGIC IOCTL definition file */ +#include "qla2x00exioct.h" + + +#if QLA_SCSI_VENDOR_DIR +/* Include routine to set direction for vendor specific commands */ +#include "qlavendor.c" +#endif +/*********************************************************************** +* We use the Scsi_Pointer structure that's included with each command +* SCSI_Cmnd as a scratchpad for our SRB. This allows us to accept +* an unlimited number of commands. +* +* SCp will always point to the SRB structure (defined in qla2100.h). +* It is defined as follows: +* - SCp.ptr -- > pointer back to the cmd +* - SCp.this_residual --> used as forward pointer to next srb +* - SCp.buffer --> used as backward pointer to next srb +* - SCp.buffers_residual --> used as flags field +* - SCp.have_data_in --> not used +* - SCp.sent_command --> not used +* - SCp.phase --> not used +***********************************************************************/ +#define CMD_SP(Cmnd) (&(Cmnd)->SCp) +#define CMD_XFRLEN(Cmnd) (Cmnd)->request_bufflen +#define CMD_CDBLEN(Cmnd) (Cmnd)->cmd_len +#define CMD_CDBP(Cmnd) (Cmnd)->cmnd +#define CMD_SNSP(Cmnd) (Cmnd)->sense_buffer +#define CMD_SNSLEN(Cmnd) (sizeof (Cmnd)->sense_buffer) +#define CMD_RESULT(Cmnd) ((Cmnd)->result) +#define CMD_HANDLE(Cmnd) ((Cmnd)->host_scribble) +#define CMD_TIMEOUT(Cmnd) ((Cmnd)->timeout_per_command) + +#define DID_RETRY DID_ERROR + + +/* +* Macros use for debugging the driver. +*/ +#ifdef QL_DEBUG_LEVEL_3 +#define ENTER(x) sprintf(debug_buff,"qla2100 : Entering %s()\n\r", x); \ +qla2100_print(debug_buff); +#define LEAVE(x) sprintf(debug_buff,"qla2100 : Leaving %s()\n\r", x); \ +qla2100_print(debug_buff); +#define ENTER_INTR(x) sprintf(debug_buff,"qla2100 : Entering %s()\n\r", x); \ +qla2100_print(debug_buff); +#define LEAVE_INTR(x) sprintf(debug_buff,"qla2100 : Leaving %s()\n\r", x); \ +qla2100_print(debug_buff); +#define DEBUG3(x) x +#else +#define ENTER(x) +#define LEAVE(x) +#define ENTER_INTR(x) +#define LEAVE_INTR(x) +#define DEBUG3(x) +#endif + +#if QLA2100_COMTRACE +#define COMTRACE(x) qla2100_putc(x); +#else +#define COMTRACE(x) +#endif + +#if DEBUG_QLA2100 +#define DEBUG(x) x +#define DEBUG4(x) +#else +#define DEBUG(x) +#define DEBUG4(x) +#endif + +#ifdef QL_DEBUG_LEVEL_2 +#define DEBUG2(x) x +#else +#define DEBUG2(x) +#endif +#ifdef QL_DEBUG_LEVEL_5 +#define DEBUG5(x) x +#else +#define DEBUG5(x) +#endif + +uint8_t copyright[48] = "Copyright 1999-2001, Qlogic Corporation"; + +/****************************************************************************/ +/* LINUX - Loadable Module Functions. */ +/****************************************************************************/ + +/*****************************************/ +/* ISP Boards supported by this driver */ +/*****************************************/ +#define QLA2100_VENDOR_ID 0x1077 +#define QLA2100_DEVICE_ID 0x2100 +#define QLA2200_DEVICE_ID 0x2200 +#define QLA2200A_DEVICE_ID 0x2200A +#define QLA2300_DEVICE_ID 0x2300 +#define QLA2200A_RISC_ROM_VER 4 + +#define NUM_OF_ISP_DEVICES 4 + +typedef struct _qlaboards +{ +unsigned char bdName[9]; /* Board ID String */ +unsigned long device_id; /* Device ID */ +int numPorts; /* number of loops on adapter */ +unsigned short *fwcode; /* pointer to FW array */ +unsigned long *fwlen; /* number of words in array */ +unsigned short *fwstart; /* start address for F/W */ +unsigned char *fwver; /* Ptr to F/W version array */ +} qla_boards_t; + + +#if USE_TP_FW +struct _qlaboards QLBoardTbl_fc[NUM_OF_ISP_DEVICES] = +{ +/* Name , Board PCI Device ID, Number of ports */ +{"QLA2300 ", QLA2300_DEVICE_ID, MAX_BUSES, +#ifdef FC_IP_SUPPORT +&fw2300ip_code01[0], (unsigned long *)&fw2300ip_length01, &fw2300ip_addr01, &fw2300ip_version_str[0] }, +#else +&fw2300tp_code01[0], (unsigned long *)&fw2300tp_length01, &fw2300tp_addr01, &fw2300tp_version_str[0] }, +#endif +{"QLA2200 ", QLA2200_DEVICE_ID, MAX_BUSES, +#ifdef FC_IP_SUPPORT +&fw2200ip_code01[0], (unsigned long *)&fw2200ip_length01, &fw2200ip_addr01, &fw2200ip_version_str[0] }, +#else +&fw2200tp_code01[0], (unsigned long *)&fw2200tp_length01, &fw2200tp_addr01, &fw2200tp_version_str[0] }, +#endif +{"QLA2100 ", QLA2100_DEVICE_ID, MAX_BUSES, +&fw2100tp_code01[0], (unsigned long *)&fw2100tp_length01,&fw2100tp_addr01, &fw2100tp_version_str[0] }, +{" ", 0, 0} +}; + +#else /* USE_TP_FW */ + +struct _qlaboards QLBoardTbl_fc[NUM_OF_ISP_DEVICES] = +{ +/* Name , Board PCI Device ID, Number of ports */ +{"QLA2300 ", QLA2300_DEVICE_ID, MAX_BUSES, +#ifdef FC_IP_SUPPORT +&fw2300ip_code01[0], (unsigned long *)&fw2300ip_length01, &fw2300ip_addr01, &fw2300ip_version_str[0] }, +#else +&fw2300ef_code01[0], (unsigned long *)&fw2300ef_length01, &fw2300ef_addr01, &fw2300ef_version_str[0] }, +#endif +{"QLA2200 ", QLA2200_DEVICE_ID, MAX_BUSES, +#ifdef FC_IP_SUPPORT +&fw2200ip_code01[0], (unsigned long *)&fw2200ip_length01, &fw2200ip_addr01, &fw2200ip_version_str[0] }, +#else +&fw2200ef_code01[0], (unsigned long *)&fw2200ef_length01, &fw2200ef_addr01, &fw2200ef_version_str[0] }, +#endif +{"QLA2100 ", QLA2100_DEVICE_ID, MAX_BUSES, +&fw2100ef_code01[0], (unsigned long *)&fw2100ef_length01,&fw2100ef_addr01, &fw2100ef_version_str[0] }, +{" ", 0, 0} +}; +#endif /* USE_TP_FW */ + +/* +* Stat info +*/ +static struct _qla2100stats { +unsigned long mboxtout; /* mailbox timeouts */ +unsigned long mboxerr; /* mailbox errors */ +unsigned long ispAbort; /* ISP aborts */ +unsigned long debugNo; +unsigned long loop_resync; +unsigned long outarray_full; +unsigned long retry_q_cnt; +unsigned long done_q_cnt; +scsi_qla_host_t *irqhba; +} qla2100_stats; + +/* +* Command line options +*/ +static unsigned long qla2100_verbose = 1L; +static unsigned long qla2100_quiet = 0L; +static unsigned long qla2100_reinit = 1L; +static unsigned long qla2100_req_dmp = 0L; +static scsi_qla_host_t *qla2100_hostlist = NULL; + +#ifdef QLA2100_PROFILE +static int qla2100_buffer_size = 0; +static char *qla2100_buffer = NULL; +#endif + +#include +#include +#include + +/************************************************************************* +* qla2100_set_info +* +* Description: +* Set parameters for the driver from the /proc filesystem. +* +* Returns: +*************************************************************************/ +int +qla2100_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) { + return (-ENOSYS); /* Currently this is a no-op */ +} + + +#include "qla2x00ioctl.c" + + +/************************************************************************* +* qla2100_proc_info +* +* Description: +* Return information to handle /proc support for the driver. +* +* inout : decides on the direction of the dataflow and the meaning of the +* variables +* buffer: If inout==FALSE data is being written to it else read from it +* (ptrs to a page buffer) +* *start: If inout==FALSE start of the valid data in the buffer +* offset: If inout==FALSE offset from the beginning of the imaginary file +* from which we start writing into the buffer +* length: If inout==FALSE max number of bytes to be written into the buffer +* else number of bytes in the buffer +* Returns: +*************************************************************************/ +#define PROC_BUF (&qla2100_buffer[len]) +int +qla2100_proc_info( char *buffer, char **start, off_t offset, int length, +int hostno, int inout) { +#if QLA2100_PROFILE + struct Scsi_Host *host; + scsi_qla_host_t *ha; + int size = 0; + scsi_lu_t *up; + int len = 0; + qla_boards_t *bdp; + uint32_t t, l; + +#if REQ_TRACE + Scsi_Cmnd *cp; + srb_t *sp; + int i; +#endif + + DEBUG5(printk("Entering proc_info 0x%x,0x%lx,0x%x,0x%x\n",(int)buffer,offset,length,hostno);) + host = NULL; + + /* Find the host that was specified */ + for( ha=qla2100_hostlist; (ha != NULL) && ha->host->host_no != hostno; ha=ha->next ) + ; + + /* if host wasn't found then exit */ + if( !ha ) { + size = sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if( size > length ) { + return (size); + } else { + return (0); + } + } + + host = ha->host; + + if( inout == TRUE ) /* Has data been written to the file? */ + { + printk(KERN_INFO "qla2100_proc: has data been written to the file. \n"); + return (qla2100_set_info(buffer, length, host)); + } + + + /* + * if our old buffer is the right size use it otherwise + * allocate a new one. + */ + size = 4096; /* get a page */ + if( qla2100_buffer_size != size ) { + /* deallocate this buffer and get a new one */ + if( qla2100_buffer != NULL ) { + kfree(qla2100_buffer); + qla2100_buffer_size = 0; + } + qla2100_buffer = kmalloc(size, GFP_KERNEL); + } + if( qla2100_buffer == NULL ) { + size = sprintf(buffer, "qla2100 - kmalloc error at line %d\n", + __LINE__); + return size; + } + /* save the size of our buffer */ + qla2100_buffer_size = size; + + /* start building the print buffer */ + bdp = &QLBoardTbl_fc[ha->devnum]; + qla2100_lip = 1; + size = sprintf(PROC_BUF, + "QLogic PCI to Fibre Channel Host Adapter for ISP2100/ISP2200/ISP2300:\n" /* 72 */ + " Firmware version: %2d.%02d.%02d, Driver version %s\n", /* 66 */ + bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], QLA2100_VERSION); + len += size; + +#if 0 + size = sprintf(PROC_BUF, + "FC HBA: %s; HBA Serial# %x%x%x\n", + bdp->bdName, + ha->serial0, + ha->serial1, + ha->serial2); + len += size; + + size = sprintf(PROC_BUF, + "[%c%c%c%c%c%c]; Part#%c%c%c%c%c%c%c%c; FRU#%c%c%c%c%c%c%c%c; EC#%c%c%c%c%c%c%c%c\n", + ha->oem_string[0], + ha->oem_string[1], + ha->oem_string[2], + ha->oem_string[3], + ha->oem_string[4], + ha->oem_string[5], + + ha->oem_part[0], + ha->oem_part[1], + ha->oem_part[2], + ha->oem_part[3], + ha->oem_part[4], + ha->oem_part[5], + ha->oem_part[6], + ha->oem_part[7], + + ha->oem_fru[0], + ha->oem_fru[1], + ha->oem_fru[2], + ha->oem_fru[3], + ha->oem_fru[4], + ha->oem_fru[5], + ha->oem_fru[6], + ha->oem_fru[7], + + ha->oem_ec[0], + ha->oem_ec[1], + ha->oem_ec[2], + ha->oem_ec[3], + ha->oem_ec[4], + ha->oem_ec[5], + ha->oem_ec[6], + ha->oem_ec[7]); + len += size; +#endif + + size = sprintf(PROC_BUF, "Request Queue = 0x%lx, Response Queue = 0x%lx\n", + (long unsigned int)ha->request_dma, + (long unsigned int)ha->response_dma); + len += size; + size = sprintf(PROC_BUF, "Request Queue count= %ld, Response Queue count= %ld\n", + (long)REQUEST_ENTRY_CNT, + (long)RESPONSE_ENTRY_CNT); + len += size; + size = sprintf(PROC_BUF, "Number of pending commands = 0x%lx\n", ha->actthreads); + len += size; + size = sprintf(PROC_BUF, "Number of queued commands = 0x%lx\n", ha->qthreads); + len += size; + size = sprintf(PROC_BUF, "Number of free request entries = %d\n",ha->req_q_cnt); + len += size; + size = sprintf(PROC_BUF, "Number of mailbox timeouts = %ld\n",qla2100_stats.mboxtout); + len += size; + size = sprintf(PROC_BUF, "Number of ISP aborts = %ld\n",qla2100_stats.ispAbort); + len += size; + size = sprintf(PROC_BUF, "Number of loop resyncs = %ld\n",qla2100_stats.ispAbort); + len += size; + size = sprintf(PROC_BUF, "Number of retries for empty slots = %ld\n",qla2100_stats.outarray_full); + len += size; + size = sprintf(PROC_BUF, "Number of reqs in retry_q = %ld\n",qla2100_stats.retry_q_cnt); + len += size; + size = sprintf(PROC_BUF, "Number of reqs in done_q = %ld\n",qla2100_stats.done_q_cnt); + len += size; + +#if REQ_TRACE + if ( qla2100_req_dmp ) { + size = sprintf(PROC_BUF,"Outstanding Commands on controller:\n"); + len += size; + for( i=0; i < MAX_OUTSTANDING_COMMANDS; i++ ) { + if( (sp = ha->outstanding_cmds[i]) == NULL ) + continue; + if( (cp = sp->cmd) == NULL ) + continue; + size = sprintf(PROC_BUF, + "(%d): Pid=%ld, sp flags=0x%x, cmd=0x%p, state=%x handle=%x\n\r", + i, (int)sp->cmd->pid, (long)sp->flags, + CMD_SP(sp->cmd),(int)sp->state,CMD_HANDLE(sp->cmd)); + + len += size; + if( len >= qla2100_buffer_size ) + goto profile_stop; + } + } +#endif + + /* 2.25 node/port display to proc */ + /* Display the node name for adapter */ + size = sprintf(PROC_BUF, "\nSCSI Device Information:\n"); + len += size; + size = sprintf(PROC_BUF, + "scsi-qla%d-adapter-node=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, + ha->init_cb->node_name[0], + ha->init_cb->node_name[1], + ha->init_cb->node_name[2], + ha->init_cb->node_name[3], + ha->init_cb->node_name[4], + ha->init_cb->node_name[5], + ha->init_cb->node_name[6], + ha->init_cb->node_name[7]); + len += size; + + /* display the port name for adapter */ + size = sprintf(PROC_BUF, + "scsi-qla%d-adapter-port=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, + ha->init_cb->port_name[0], + ha->init_cb->port_name[1], + ha->init_cb->port_name[2], + ha->init_cb->port_name[3], + ha->init_cb->port_name[4], + ha->init_cb->port_name[5], + ha->init_cb->port_name[6], + ha->init_cb->port_name[7]); + len += size; + + /* Print out device port names */ + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + if (ha->fc_db[i].loop_id == PORT_UNUSED) + continue; + +#if USE_PORTNAME + size = sprintf(PROC_BUF, + "scsi-qla%d-target-%d=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, i, + ha->fc_db[i].wwn[0], + ha->fc_db[i].wwn[1], + ha->fc_db[i].wwn[2], + ha->fc_db[i].wwn[3], + ha->fc_db[i].wwn[4], + ha->fc_db[i].wwn[5], + ha->fc_db[i].wwn[6], + ha->fc_db[i].wwn[7]); +#else + size = sprintf(PROC_BUF, + "scsi-qla%d-target-%d=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, i, + ha->fc_db[i].name[0], + ha->fc_db[i].name[1], + ha->fc_db[i].name[2], + ha->fc_db[i].name[3], + ha->fc_db[i].name[4], + ha->fc_db[i].name[5], + ha->fc_db[i].name[6], + ha->fc_db[i].name[7]); +#endif + len += size; + } /* 2.25 node/port display to proc */ + + size = sprintf(PROC_BUF, "\nSCSI LUN Information:\n"); + len += size; + size = sprintf(PROC_BUF, "(Id:Lun)\n"); + len += size; + /* scan for all equipment stats */ + for (t = 0; t < MAX_FIBRE_DEVICES; t++) { + /* valid target */ + if (ha->fc_db[t].loop_id == PORT_UNUSED) + continue; + /* scan all luns */ + for( l = 0; l < ha->max_luns; l++ ) { + up = (scsi_lu_t *) GET_LU_Q(ha, 0, t, l); + if( up == NULL ) + continue; + if( up->io_cnt == 0 || up->io_cnt < 5) + continue; + /* total reads since boot */ + /* total writes since boot */ + /* total requests since boot */ + size = sprintf(PROC_BUF, "(%2d:%2d): Total reqs %ld,",t,l,up->io_cnt); + len += size; + /* current number of pending requests */ + size = sprintf(PROC_BUF, " Pending reqs %d,",up->q_outcnt); + len += size; + + /* current number of pending requests */ + size = sprintf(PROC_BUF, " Queued reqs %d,",(int)up->q_incnt); + len += size; + size = sprintf(PROC_BUF, "\n"); + len += size; + if( len >= qla2100_buffer_size ) + goto profile_stop; + } + if( len >= qla2100_buffer_size ) + break; + } + + profile_stop: + if( len >= qla2100_buffer_size ) { + printk(KERN_WARNING "qla2100: Overflow buffer in qla2100_proc.c\n"); + } + + if( offset > len - 1 ) { + kfree(qla2100_buffer); + qla2100_buffer = NULL; + qla2100_buffer_size = length = 0; + *start = NULL; + } else { + if( len - offset < length ) { + length = len - offset; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + *start = &qla2100_buffer[offset]; /* Start of wanted data */ +#else + *start = buffer; + memcpy(buffer, &qla2100_buffer[offset], length); +#endif + } + return (length); +#else + return (0); +#endif + +} + +/************************************************************************** +* qla2100_detect +* +* Description: +* This routine will probe for Qlogic FC SCSI host adapters. +* It returns the number of host adapters of a particular +* type that were found. It also initialize all data necessary for +* the driver. It is passed-in the host number, so that it +* knows where its first entry is in the scsi_hosts[] array. +* +* Input: +* template - pointer to SCSI template +* +* Returns: +* num - number of host adapters found. +**************************************************************************/ +int +qla2100_detect(Scsi_Host_Template *template) +{ + struct Scsi_Host *host; + scsi_qla_host_t *ha, *cur_ha; + struct _qlaboards *bdp; + int i, j; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + unsigned short subsys; +#endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,95) + unsigned int piobase; + unsigned char pci_bus, pci_devfn, pci_irq; + config_reg_t *cfgp = 0; +#endif + device_reg_t *reg; + char *cp; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + struct pci_dev *pdev = NULL; +#else + int index; +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + struct semaphore sem = MUTEX_LOCKED; +#else + DECLARE_MUTEX_LOCKED(sem); +#endif + + unsigned long wait_switch = 0; + + ENTER("qla2100_detect"); + + if( sizeof(srb_t) > sizeof(Scsi_Pointer) ) + printk(KERN_WARNING "qla2x00: srb_t must be re-defined " + "- it's too big"); + +#ifdef CODECHECK + if( sizeof(srb_t) > sizeof(Scsi_Pointer) ) { + printk(KERN_WARNING "Redefine srb_t - its too big"); + return 0; + } +#endif + +#ifdef MODULE + DEBUG2(sprintf(debug_buff, + "DEBUG: qla2100_detect starts at address = 0x%8lx\n", + (uint32_t)qla2100_detect);) + DEBUG2(qla2100_print(debug_buff);) + /* + * If we are called as a module, the qla2100 pointer may not be null + * and it would point to our bootup string, just like on the lilo + * command line. IF not NULL, then process this config string with + * qla2100_setup + * + * Boot time Options + * To add options at boot time add a line to your lilo.conf file like: + * append="qla2100=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" + * which will result in the first four devices on the first two + * controllers being set to a tagged queue depth of 32. + */ + if( ql2xopts ) + qla2100_setup(ql2xopts, NULL); + if( dummy_buffer[0] != 'P' ) + printk(KERN_WARNING "qla2100: Please read the file " + "/usr/src/linux/drivers/scsi/README.qla2100\n" + "qla2100: to see the proper way to specify options to " + "the qla2100 module\n" + "qla2100: Specifically, don't use any commas when passing " + "arguments to\n" + "qla2100: insmod or else it might trash certain memory " + "areas.\n"); +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + if( (int) !pcibios_present() ) +#else + if (!pci_present()) +#endif + { + printk(KERN_WARNING "scsi: [ERROR] PCI not present\n"); + return 0; + } /* end of IF */ + + bdp = &QLBoardTbl_fc[0]; + qla2100_hostlist = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + template->proc_dir = &proc_scsi_qla2100; +#else + template->proc_name = "qla2x00"; +#endif + + /* Try and find each different type of adapter we support */ + for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) { + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + /* PCI_SUBSYSTEM_IDS supported */ + while ((pdev = pci_find_subsys(QLA2100_VENDOR_ID, + bdp->device_id, PCI_ANY_ID, PCI_ANY_ID, pdev) )) { + if (pci_enable_device(pdev)) continue; +#else + while ((pdev = pci_find_device(QLA2100_VENDOR_ID, + bdp->device_id, pdev ) )) { +#endif /* 2,3,18 */ + +#else /* less than 2,1,95 */ + while (!(pcibios_find_device(QLA2100_VENDOR_ID, + bdp->device_id, index++, &pci_bus, &pci_devfn)) ) { +#endif /* 2,1,95 */ + + /* found an adapter */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + printk(KERN_INFO "qla2x00: detect() found an HBA\n"); + printk(KERN_INFO + "qla2x00: VID=%x DID=%x SSVID=%x SSDID=%x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, + pdev->subsystem_device); + + /* If it's an XXX SubSys Vendor ID adapter, skip it. */ + /* if (pdev->subsystem_vendor == PCI_VENDOR_ID_XXX) + { + printk(KERN_INFO "qla2x00: Skip XXX SubSys " + "Vendor ID Controller\n"); + continue; + } + */ +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, + &subsys); + + /* Bypass all XXX SUBSYS VENDOR IDs */ + /* if (subsys == PCI_VENDOR_ID_XXX) + { + printk(KERN_INFO "qla2x00:Skip XXX SubSys " + "Vendor ID Controller\n"); + continue; + } + */ +#endif /* 2,1,95 */ +#endif /* 2,3,18 */ + host = scsi_register(template, sizeof(scsi_qla_host_t)); + ha = (scsi_qla_host_t *) host->hostdata; + + /* Clear our data area */ + for( j = 0, cp = (char *)ha; + j < sizeof(scsi_qla_host_t); j++, cp++ ) + *cp = 0; + + /* Sanitize the information from PCI BIOS. */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + host->irq = pdev->irq; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + host->io_port = (unsigned long) pdev->base_address[0]; +#else + host->io_port = pdev->resource[0].start; +#endif + ha->pci_bus = pdev->bus->number; + ha->pci_device_fn = pdev->devfn; + ha->pdev = pdev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) + scsi_set_pci_device(host, pdev); +#endif +#else + pcibios_read_config_byte(pci_bus, pci_devfn, + OFFSET(cfgp->interrupt_line), &pci_irq); + pcibios_read_config_dword(pci_bus, pci_devfn, + OFFSET(cfgp->base_port), &piobase); + host->irq = pci_irq; + host->io_port = (unsigned int) piobase; + ha->pci_bus = pci_bus; + ha->pci_device_fn = pci_devfn; +#endif + ha->device_id = bdp->device_id; + host->io_port &= PCI_BASE_ADDRESS_IO_MASK; + ha->devnum = i; + if( qla2100_verbose ) { + printk(KERN_INFO "(scsi): Found a %s @ bus %d, " + "device 0x%x, irq %d, iobase 0x%lx\n", + bdp->bdName, ha->pci_bus, + (ha->pci_device_fn & 0xf8) >> 3, + host->irq, (unsigned long)host->io_port); + } + + ha->iobase = (device_reg_t *) host->io_port; + ha->iobase2300 = (device2300_reg_t *) host->io_port; + ha->host = host; + + /* 4.23 Initialize /proc/scsi/qla2x00 counters */ + ha->actthreads = 0; + ha->qthreads = 0; + ha->dump_done = 0; + ha->isp_aborts = 0; + ha->lip_count = 0; + + if( qla2100_mem_alloc(ha) ) { + printk(KERN_INFO "qla2100: Failed to allocate " + "memory for adapter\n"); + } + ha->prev_topology = 0; + ha->ports = bdp->numPorts; + ha->host_no = host->host_no; + + /* 4.10 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + ha->ioctl_mem = (void *)KMALLOC(PAGE_SIZE); + ha->ioctl_mem_phys = VIRT_TO_BUS(ha->ioctl_mem); +#else + /* get consistent memory allocated for ioctl I/O + * operations + */ + ha->ioctl_mem = pci_alloc_consistent(ha->pdev, + PAGE_SIZE, &ha->ioctl_mem_phys); +#endif + + if (ha->ioctl_mem == NULL) { + printk(KERN_WARNING "qla2100: ERROR in ioctl " + "physical memory allocation\n"); + return(0); + } + + if( ha->device_id == QLA2100_DEVICE_ID ) + ha->max_targets = MAX_TARGETS_2100; + else + ha->max_targets = MAX_TARGETS_2200; + + /* load the F/W, read paramaters, and init the H/W */ + ha->instance = num_hosts; + + if( qla2100_initialize_adapter(ha) ) { + printk(KERN_WARNING + "qla2100_detect: [ERROR] Failed to " + "initialize adapter\n"); + + qla2100_mem_free(ha); + scsi_unregister(host); + continue; + } + + ha->next = NULL; + /* Mark preallocated Loop IDs in use. */ + ha->fabricid[SNS_FL_PORT].in_use = TRUE; + ha->fabricid[FABRIC_CONTROLLER].in_use = TRUE; + ha->fabricid[SIMPLE_NAME_SERVER].in_use = TRUE; + + /* Register our resources with Linux */ + if( qla2100_register_with_Linux(ha, bdp->numPorts-1) ) { + printk(KERN_WARNING + "qla2100: [ERROR] Failed to register our " + "resources\n"); + qla2100_mem_free(ha); + scsi_unregister(host); + continue; + } + + /* reg uses here in detect() are common: + * 2100/2200/2300 + */ + reg = ha->iobase; + + /* Disable ISP interrupts. */ + qla2100_disable_intrs(ha); + + /* + * Startup the kernel thread for this host adapter + */ + + ha->dpc_notify = &sem; + kernel_thread((int (*)(void *))qla2100_do_dpc, + (void *) ha, 0); + + /* + * Now wait for the kernel dpc thread to initialize + * and go to sleep. + */ + down(&sem); + ha->dpc_notify = NULL; + + /* + * These locks are used to prevent more than one + * CPU from modifying the queue at the same time. + * The higher level "io_request_lock" will reduce + * most contention for these locks. + */ + ha->retry_lock = SPIN_LOCK_UNLOCKED; + + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); + + /* Wait around max 5 secs for the devices to come + * on-line we don't want Linux scanning before we + * are ready. + */ + /* v2.19.5b6 */ + for (wait_switch = jiffies+(ha->loop_reset_delay * HZ); + wait_switch > jiffies && + !(ha->device_flags & DFLG_FABRIC_DEVICES) ; ) { + + qla2100_check_fabric_devices(ha); + } + /* just in case we turned it on */ + ha->dpc_flags &= ~COMMAND_WAIT_NEEDED; + + /* List the target we have found */ + qla2100_display_fc_names(ha); + + /* Enable chip interrupts. */ + qla2100_enable_intrs(ha); + + /* Insert new entry into the list of adapters */ + ha->next = NULL; + if( qla2100_hostlist == NULL ) { + qla2100_hostlist = ha; + } else { + cur_ha = qla2100_hostlist; + + while( cur_ha->next != NULL ) + cur_ha = cur_ha->next; + + cur_ha->next = ha; + } + num_hosts++; + } + } /* end of FOR */ + + LEAVE("qla2100_detect"); + return num_hosts; +} + +/************************************************************************** +* qla2100_register_with_Linux +* +* Description: +* Free the passed in Scsi_Host memory structures prior to unloading the +* module. +* +* Input: +* ha - pointer to host adapter structure +* maxchannels - MAX number of channels. +* +* Returns: +* 0 - Sucessfully reserved resources. +* 1 - Failed to reserved a resource. +**************************************************************************/ +STATIC uint8_t qla2100_register_with_Linux(scsi_qla_host_t *ha, uint8_t maxchannels) { + + struct Scsi_Host *host = ha->host; + char drvname[9]; + + host->can_queue = 0xfffff; /* unlimited */ + host->cmd_per_lun = 1; + host->select_queue_depths = qla2100_select_queue_depth; + host->n_io_port = 0xFF; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + host->base = (unsigned char *) ha->mmpbase; +#else + host->base = (u_long) ha->mmpbase; +#endif + host->max_channel = maxchannels; + /* fix: 07/31 host->max_lun = MAX_LUNS-1; */ + host->max_lun = ha->max_luns; + host->unique_id = ha->instance; + host->max_id = ha->max_targets; + + /* set our host ID (need to do something about our two IDs) */ + host->this_id = 255; + + /* Register the I/O space with Linux */ + if( check_region(host->io_port, 0xff) ) { + printk(KERN_WARNING "qla2100 : [ERROR] Failed to reserved i/o region " + "0x%04lx-0x%04lx already in use\n", + host->io_port, host->io_port + 0xff); + /* 4.31.5 - deleted free_irq(host->irq, NULL); */ + return 1; + } + + /* ER# 4368 */ + sprintf(drvname,"qla2x00#%02d",host->unique_id); + + request_region(host->io_port, 0xff, drvname); + + + /* Register the IRQ with Linux (sharable) */ + if( request_irq(host->irq, qla2100_intr_handler, SA_INTERRUPT| SA_SHIRQ, "qla2x00", ha) ) { + printk(KERN_WARNING "qla2100 : [ERROR] Failed to reserved interrupt %d " + "already in use\n", host->irq); + return 1; + } + + /* Initialized the timer */ + START_TIMER(qla2100_timer,ha,WATCH_INTERVAL); + + return 0; +} + + +/************************************************************************** +* qla2100_release +* +* Description: +* Free the passed in Scsi_Host memory structures prior to unloading the +* module. +* +* Input: +* ha - pointer to host adapter structure +* +* Returns: +* 0 - Always returns good status +**************************************************************************/ +int +qla2100_release(struct Scsi_Host *host) { + scsi_qla_host_t *ha = (scsi_qla_host_t *) host->hostdata; + + ENTER("qla2100_release"); + /* if adpater is running and online */ + if( !ha->flags.online ) + return(0); + + /* turn-off interrupts on the card */ + qla2100_disable_intrs(ha); + + /* Detach interrupts */ + if( host->irq ) + free_irq(host->irq, ha); + + /* release io space registers */ + if( host->io_port ) + release_region(host->io_port, 0xff); + + /* Disable timer */ + if( ha->timer_active ) + STOP_TIMER(qla2100_timer,ha) + + /* Kill the kernel thread for this host */ + if( ha->dpc_handler != NULL ) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + struct semaphore sem = MUTEX_LOCKED; +#else + DECLARE_MUTEX_LOCKED(sem); +#endif + + ha->dpc_notify = &sem; + send_sig(SIGKILL, ha->dpc_handler, 1); + down(&sem); + ha->dpc_notify = NULL; + } +#if USE_FLASH + /* Move driver database to flash, if enabled. */ + if( ha->flags.enable_flash_db_update && ha->flags.updated_fc_db ) { + ha->flags.updated_fc_db = FALSE; + qla2100_save_database(ha); + } +#endif +#if MEMORY_MAPPED_IO + if( ha->mmpbase ) { + iounmap((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK)); + } +#endif /* MEMORY_MAPPED_IO */ + +#if APIDEV + apidev_cleanup(); +#endif + + qla2100_mem_free(ha); + ha->flags.online = FALSE; + + LEAVE("qla2100_release"); + return(0); +} + +/************************************************************************** +* qla2100_info +* +* Description: +* +* Input: +* host - pointer to Scsi host adapter structure +* +* Returns: +* Return a text string describing the driver. +**************************************************************************/ +const char * +qla2100_info(struct Scsi_Host *host) { + static char qla2100_buffer[255]; + char *bp; + scsi_qla_host_t *ha; + qla_boards_t *bdp; + +#if APIDEV +/* We must create the api node here instead of qla2100_detect since we want + the api node to be subdirectory of /proc/scsi/qla2x00 which will not + have been created when qla2100_detect exits, but which will have been + created by this point. */ + + apidev_init(host); +#endif + bp = &qla2100_buffer[0]; + ha = (scsi_qla_host_t *)host->hostdata; + bdp = &QLBoardTbl_fc[ha->devnum]; + memset(bp, 0, sizeof(qla2100_buffer)); + sprintf(bp, + "QLogic %sPCI to Fibre Channel Host Adapter: bus %d device %d irq %d\n" + " Firmware version: %2d.%02d.%02d, Driver version %s", + (char *)&bdp->bdName[0], ha->pci_bus, (ha->pci_device_fn & 0xf8) >> 3, host->irq, + bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], QLA2100_VERSION); + return(bp); +} + +/************************************************************************** +* qla1200_queuecommand +* +* Description: +* Queue a command to the controller. +* +* Input: +* cmd - pointer to Scsi cmd structure +* fn - pointer to Scsi done function +* +* Returns: +* 0 - Always +* +* Note: +* The mid-level driver tries to ensures that queuecommand never gets invoked +* concurrently with itself or the interrupt handler (although the +* interrupt handler may call this routine as part of request-completion +* handling). +**************************************************************************/ +int +qla2100_queuecommand(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) { + scsi_qla_host_t *ha; + srb_t *sp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + struct Scsi_Host *host; + uint32_t b, t, l; + scsi_lu_t *q; + u_long handle; + + ENTER("qla2100_queuecommand"); + COMTRACE('C') + + host = cmd->host; + ha = (scsi_qla_host_t *) host->hostdata; + /* Get our SCSI request pointer + * SCp always point to it - see definition in qla2100.h. + */ + sp = (srb_t *) CMD_SP(cmd); + sp->cmd = cmd; + cmd->scsi_done = fn; + + /* If we not trying to do a recovery procedure of some sort + * then this is probably a new command. + */ + if( cmd->flags == 0 && + cmd->retries == 0 ) + sp->flags = 0; + + /* Generate LU queue on bus, target, LUN */ + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + + DEBUG5(qla2100_print_scsi_cmd(cmd);) + DEBUG5(sprintf(debug_buff,"qla2100_queuecmd: pid=%d, opcode=%d, timeout=%d\n",cmd->pid,cmd->cmnd[0],CMD_TIMEOUT(cmd));) + DEBUG5(qla2100_print(debug_buff);) + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + /*DEBUG(sprintf(debug_buff,"\n\nQC: t=%x CDB=%x Size=%x\n\r", + t,cmd->cmnd[0],CMD_XFRLEN(cmd));) + DEBUG(qla2100_print(debug_buff)); */ +#endif + /* + * We found all the devices at LIP time, and created a device + * table for them, so we only need to check the table to see + * if the device is present. if PORT_AVAILABLE or PORT_UNUSED + * then no target exists. + * + * We return DID_NO_CONNECT if the loop is down after loop down + * timer has expired. + */ + if( TGT_Q(ha,b,t) == NULL || + (TGT_Q(ha,b,t) && TGT_Q(ha,b,t)->loop_id > LAST_SNS_LOOP_ID) ) { + /* DEBUG2(printk("scsi(%2d:%2d:%2d:%2d): port unavailable\n", + (int)ha->host_no,b,t,l);) */ + CMD_RESULT(sp->cmd) = DID_NO_CONNECT << 16; + qla2100_callback(ha,sp,FALSE); + LEAVE("qla2100_queuecommand"); + return(0); + } + /* v218b4 */ + if (ha->loop_down_timer == 0 && + ha->loop_state == LOOP_DOWN ){ /* 01/21/00 DG */ + DEBUG2(printk("scsi(%2d:%2d:%2d:%2d): Loop down - returning pid=%ld \n",(int)ha->host_no,b,t,l,cmd->pid);) + CMD_RESULT(sp->cmd) = DID_NO_CONNECT << 16; + ha->flags.done_requests_needed = TRUE; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + LEAVE("qla2100_queuecommand"); + return(0); + } + + /* + * Allocate a LUN/DEVICE queue from this request if we haven't + * already did it on a previous command. + */ + if( (q = GET_LU_Q(ha, b, t,l)) == NULL ) { + DRIVER_LOCK + if( (q = qla2100_lun_alloc()) == NULL ) { + CMD_RESULT(sp->cmd) = DID_RETRY << 16; + qla2100_callback(ha,sp,FALSE); + return(0); + } + LU_Q(ha, b, t, l) = q; + DEBUG(sprintf(debug_buff,"Allocate new device queue 0x%x\n",q)); + DEBUG(qla2100_print(debug_buff)); + DRIVER_UNLOCK + } + + /* Set an invalid handle until we issue the command to ISP */ + /* then we will set the real handle value. */ + handle = INVALID_HANDLE; + CMD_HANDLE(cmd) = (unsigned char *)handle; + +#if QLA2100_EXT_TIMEOUT + /* Extend timeout for this request */ + qla2100_extend_timeout(cmd,60*HZ); +#endif + + /* + * SCSI Kluge + * ======== + * Whenever, we need to wait for an event such as loop down + * (i.e. loop_down_timer ) or port down (i.e. LUN request qeueue is + * suspended) then we will recycle new commands back to the SCSI layer. + * We do this because this is normally a temporary condition and we don't + * want the mid-level scsi.c driver to get upset and start aborting + * commands. + + * The timeout value is extracted from the command minus 1-second + * and put on a retry queue (watchdog). Once the command timeout it + * is returned to the mid-level with a BUSY status, so the mid-level + * will retry it. This process continues until the LOOP DOWN time + * expires or the condition goes away. + */ + if( ha->loop_down_timer || + ha->loop_state == LOOP_DOWN || + (PORT_DOWN(ha,t) > 0) || + ha->loop_state != LOOP_READY || + (q->q_flag & QLA2100_QSUSP) ) { + /* Insert command into watchdog queue */ + qla2100_timeout_insert(ha, sp); + LEAVE("qla2100_queuecommand"); + return (0); + } + /* Set retry count if this is a new command */ + if( sp->flags == 0 && + !(q->q_flag & QLA2100_QSUSP) ) { + sp->retry_count = ha->retry_count; + if( TGT_Q(ha, b, t)->down_timer == 0 ) + sp->port_down_retry_count = ha->port_down_retry_count; + } + + /* No timeout necessary, because the upper layer is doing it for us */ + sp->wdg_time = 0; + + /* add the command to our queue */ + ha->qthreads++; + qla2100_putq_t(q,sp); + + DEBUG5(sprintf(debug_buff,"\nQC: queue pid=%d, hndl=0x%x\n\r", + cmd->pid,handle)); + DEBUG5(qla2100_print(debug_buff)); + + /* send command to adapter */ + qla2100_restart_queues(ha,FALSE); + + COMTRACE('c') + LEAVE("qla2100_queuecommand"); + return (0); +} + +/************************************************************************** +* qla1200_abort +* +* Description: +* Abort the specified SCSI command. +* +* Input: +* cmd - pointer to Scsi cmd structure +* +* Returns: +**************************************************************************/ +int +qla2100_abort(Scsi_Cmnd *cmd) { + scsi_qla_host_t *ha; + srb_t *sp; + srb_t *rp, *rp_next; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + struct Scsi_Host *host; + uint32_t b, t, l; + scsi_lu_t *q; + int return_status = SCSI_ABORT_SUCCESS; + int found = 0; + int i; + u_long handle; + + uint16_t data; + + ENTER("qla2100_abort"); + COMTRACE('A') + + ha = (scsi_qla_host_t *) cmd->host->hostdata; + host = cmd->host; + +#if DEBUG_GET_FW_DUMP + if (ha->device_id == QLA2300_DEVICE_ID) + { + if (ha->dump_done != 1) { + DEBUG(sprintf(debug_buff,"\nqla2100_abort handle=%x: >>>>>>> DUMP 2300 FW <<<<<<<\n",CMD_HANDLE(cmd));) + DEBUG(qla2100_print(debug_buff);) + qla2300_dump_isp(ha); + ha->dump_done = 1; + } + } +#endif + + DRIVER_LOCK + /* Get the SCSI request ptr */ + sp = (srb_t *) CMD_SP(cmd); + + /* + * if the handle is NULL then we already completed the command. + * We always give the handle a value of "INVALID_HANDLE" when + * we received it. + */ + if( (u_long) CMD_HANDLE(cmd) == 0L ) { + + DRIVER_UNLOCK +#if STOP_ON_ABORT + qla2100_panic("qla2100_abort",ha->host); +#endif + return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */ + } + + /* Check for a pending interrupt. */ + if (ha->device_id == QLA2300_DEVICE_ID) + data = qla2100_debounce_register((uint16_t *)&ha->iobase2300->host_status) & RISC_2300_INT; + else data = qla2100_debounce_register(&ha->iobase->istatus) & + RISC_INT; + + /* Check for pending interrupts. */ + if( !(ha->flags.in_isr) && (data)) { + /* Add any completed commands in the done queue */ + DEBUG(qla2100_print("qla2100_abort: Calling isr\n");) + qla2100_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + + /* + * if no LUN queue then something is very wrong!!! + */ + handle = (u_long) CMD_HANDLE(cmd); + + /* Generate LU queue on bus, target, LUN */ + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + if( (q = GET_LU_Q(ha, b, t, l)) == NULL ) { + COMTRACE('a') + + DRIVER_UNLOCK + printk(KERN_WARNING "qla2100 (%d:%d:%d): No LUN queue for the specified device\n",(int)b,(int)t,(int)l); + return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */ + } + +#if AUTO_ESCALATE_ABORT + if( (sp->flags & SRB_ABORTED) ) { + DRIVER_UNLOCK + DEBUG(qla2100_print("qla2100_abort: Abort escalayted - returning SCSI_ABORT_SNOOZE.\n\r")); + return(SCSI_ABORT_SNOOZE); + } +#endif + /* + * if the command ahs a abort pending then tell the upper layer + */ + if( (sp->flags & SRB_ABORT_PENDING) ) { + COMTRACE('a') + DRIVER_UNLOCK + if( qla2100_verbose ) + printk(KERN_INFO "scsi(): Command has a pending abort " + "message - ABORT_PENDING.\n"); + DEBUG(qla2100_print("qla2100: Command has a pending abort message - ABORT_PENDING.\n\r")); + return(SCSI_ABORT_PENDING); + } + + DEBUG(sprintf(debug_buff,"ABORTing command= 0x%x, sp=%x sp->state=%x\n", + (int)cmd,sp,sp->state);) + DEBUG(qla2100_print(debug_buff);) + DEBUG(qla2100_print_scsi_cmd(cmd)); + + for( rp = ha->retry_q_first; (rp); rp = rp_next ) { + rp_next = rp->s_next; + if( sp != rp ) + continue; + qla2100_timeout_remove(ha, sp); + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + found++; + } + + /* + * Our SP pointer points at the command we want to remove from the + * LUN queue providing we haven't already sent it to the adapter. + */ + if( found ) + return_status = SCSI_ABORT_SUCCESS; + else if( !(sp->flags&SRB_SENT) ) { + found++; + DEBUG(sprintf(debug_buff,"qla2100: Cmd in LUN queue aborted pid %d.\n\r",sp->cmd->pid);) + DEBUG(qla2100_print(debug_buff);) + /* Remove srb from SCSI LU queue. */ + qla2100_removeq(q, sp); + sp->flags |= SRB_ABORTED; + CMD_RESULT(cmd) = DID_ABORT << 16; + qla2100_done_q_put(ha, sp, &ha->done_q_first, &ha->done_q_last); + return_status = SCSI_ABORT_SUCCESS; + found++; + } else { /* find the command in our active list */ + for( i = 1; i < MAX_OUTSTANDING_COMMANDS; i++ ) { + if( sp == ha->outstanding_cmds[i] ) { + found++; + DEBUG(sprintf(debug_buff, + "qla2100: RISC aborting pid %d sp->state=%x\n\r", + sp->cmd->pid,sp->state);) + DEBUG(qla2100_print(debug_buff);) + /* DEBUG(qla2100_print_scsi_cmd(cmd)); */ + DEBUG(qla2100_print_q_info(q);) + /* v2.19.8 Ignore abort request if port is down */ + if ( qla2100_abort_command(ha,sp) ) { + DEBUG(printk("qla2100: Failed to abort pid %ld.\n",sp->cmd->pid);) + return_status = SCSI_ABORT_NOT_RUNNING; /* no action */ + } + else + return_status = SCSI_ABORT_PENDING; + break; + } + } + } + +#if STOP_ON_ABORT + qla2100_panic("qla2100_abort",ha->host); +#endif + if( found == 0 ) + return_status = SCSI_ABORT_NOT_RUNNING; /* no action */ + + DEBUG(sprintf(debug_buff, "qla2100_abort: Aborted status returned = 0x%x.\n\r",return_status)); + DEBUG(qla2100_print(debug_buff)); + /* + * Complete any commands + */ + if( ha->done_q_first ) + qla2100_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + if( found ) { + qla2100_restart_queues(ha,TRUE); + } + DRIVER_UNLOCK + + LEAVE("qla2100_abort"); + COMTRACE('a') + return(return_status); +} + +/************************************************************************** +* qla1200_reset +* +* Description: +* The reset function will reset the SCSI bus and abort any executing +* commands. +* +* Input: +* cmd = Linux SCSI command packet of the command that cause the +* bus reset. +* flags = SCSI bus reset option flags (see scsi.h) +* +* Returns: +* DID_RESET in cmd.host_byte of aborted command(s) +* +* Note: +* Resetting the bus always succeeds - is has to, otherwise the +* kernel will panic! Try a surgical technique - sending a BUS +* DEVICE RESET message - on the offending target before pulling +* the SCSI bus reset line. +**************************************************************************/ +int +qla2100_reset(Scsi_Cmnd *cmd, unsigned int flags) { + scsi_qla_host_t *ha; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + uint32_t b, t, l; + srb_t *sp; + typedef enum { + ABORT_DEVICE = 1, + DEVICE_RESET = 2, + BUS_RESET = 3, + ADAPTER_RESET= 4, + RESET_DELAYED= 5, + FAIL = 6 + } action_t; + action_t action = ADAPTER_RESET; + uint16_t data; + scsi_lu_t *q; + int result; + + + ENTER("qla2100_reset"); + COMTRACE('R') + if( cmd == NULL ) { + printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " + "pointer, failing.\n"); + return(SCSI_RESET_SNOOZE); + } + ha = (scsi_qla_host_t *) cmd->host->hostdata; + sp = (srb_t *) CMD_SP(cmd); + +#if STOP_ON_RESET + sprintf(debug_buff,"ABORTing command= 0x%x\n",(int)cmd); + qla2100_print(debug_buff); + qla2100_print_scsi_cmd(cmd); + qla2100_panic("qla2100_reset",ha->host); +#endif + + + DRIVER_LOCK + if (ha->device_id == QLA2300_DEVICE_ID) + data = qla2100_debounce_register((uint16_t *)&ha->iobase2300->host_status) & + RISC_2300_INT; + else data = qla2100_debounce_register(&ha->iobase->istatus) & + RISC_INT; + + /* Check for pending interrupts. */ + if( !(ha->flags.in_isr) && (data) ) { + DEBUG(qla2100_print("qla2100_reset: Calling isr\n");) + qla2100_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + DRIVER_UNLOCK + + /* + * Determine the suggested action that the mid-level driver wants + * us to perform. + */ + if( CMD_HANDLE(cmd) == (unsigned char *) 0 ) { + /* + * if mid-level driver called reset with a orphan SCSI_Cmnd + * (i.e. a command that's not pending ), so perform the + * function specified. + */ + /* 4.23 */ + if( (flags & SCSI_RESET_SUGGEST_HOST_RESET) ) + action = ADAPTER_RESET; + else if( flags & SCSI_RESET_SUGGEST_BUS_RESET ) + action = BUS_RESET; + else + action = DEVICE_RESET; + } else { /* + * Mid-level driver has called reset with this SCSI_Cmnd and + * its pending. + */ + if( flags & SCSI_RESET_SUGGEST_HOST_RESET ) + action = ADAPTER_RESET; + else if( flags & SCSI_RESET_SUGGEST_BUS_RESET ) + action = BUS_RESET; + else + action = DEVICE_RESET; + } + + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + q = GET_LU_Q(ha, b, t, l); + +#if AUTO_ESCALATE_RESET + if( (action & DEVICE_RESET) && (q->q_flag & QLA2100_QRESET) ) { + printk(KERN_INFO "qla2100(%d): Bus device reset already sent to " "device, escalating.\n", (int)ha->host_no); + action = BUS_RESET; + } + if( (action & DEVICE_RESET) && (sp->flags & SRB_ABORT_PENDING) ) { + printk(KERN_INFO "qla2100(%d):Have already attempted to reach " "device with abort device\n", (int)ha->host_no); + printk(KERN_INFO "qla2100(%d):message, will escalate to BUS " "RESET.\n",(int) ha->host_no); + action = BUS_RESET; + } +#endif + + /* + * By this point, we want to already know what we are going to do, + * so we only need to perform the course of action. + */ + + DRIVER_LOCK + result = SCSI_RESET_ERROR; + switch( action ) { + case FAIL: + break; + + case RESET_DELAYED: + result = SCSI_RESET_PENDING; + break; + + case ABORT_DEVICE: + if( qla2100_verbose ) + printk(KERN_INFO "scsi(%d:%d:%d:%d): ABORT DEVICE ISSUED.\n", (int)ha->host_no,(int)b,(int)t,(int)l); + qla2100_abort_queue_single(ha,b,t,l,DID_ABORT); + if( !ha->loop_down_timer ) + if( qla2100_abort_device(ha, b, t, l) == 0 ) + result = SCSI_RESET_PENDING; + break; + + case DEVICE_RESET: + if( qla2100_verbose ) + printk(KERN_INFO "scsi(%d:%d:%d:%d): DEVICE RESET ISSUED.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + for( l = 0; l < ha->max_luns; l++ ) + qla2100_abort_queue_single(ha,b,t,l,DID_ABORT); + if( !ha->loop_down_timer ) + if( qla2100_device_reset(ha, b, t) == 0 ) + result = SCSI_RESET_PENDING; + q->q_flag |= QLA2100_QRESET; + break; + + case BUS_RESET: + if( qla2100_verbose ) + printk(KERN_INFO "scsi(%d:%d:%d:%d): LOOP RESET ISSUED.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + for( t = 0; t < ha->max_targets; t++ ) + for( l = 0; l < ha->max_luns; l++ ) + qla2100_abort_queue_single(ha,b,t,l,DID_RESET); + if( !ha->loop_down_timer ) + if( qla2100_loop_reset(ha) == 0 ) + result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + /* + * The reset loop routine returns all the outstanding commands back + * with "DID_RESET" in the status field. + */ + if( flags & SCSI_RESET_SYNCHRONOUS ) { + CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16); + (*(cmd)->scsi_done)(cmd); + } + + /* ha->reset_start = jiffies; */ + break; + + case ADAPTER_RESET: + default: + if( qla2100_verbose ) { + printk(KERN_INFO "scsi(%d:%d:%d:%d): ADAPTER RESET ISSUED.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + } + ha->flags.reset_active = TRUE; + /* + * We restarted all of the commands automatically, so the mid-level code can expect + * completions momentitarily. + */ + if( qla2100_abort_isp(ha) == 0 ) + result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; + + ha->flags.reset_active = FALSE; + } + + if( ha->done_q_first ) + qla2100_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + qla2100_restart_queues(ha,TRUE); + DRIVER_UNLOCK + + COMTRACE('r') + LEAVE("qla2100_reset"); + return(result); +} + +/************************************************************************** +* qla1200_biosparam +* +* Description: +* Return the disk geometry for the given SCSI device. +**************************************************************************/ +int +qla2100_biosparam(Disk *disk, kdev_t dev, int geom[]) { + int heads, sectors, cylinders; + + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + if( cylinders > 1024 ) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return (0); +} + +/************************************************************************** +* qla2100_intr_handler +* +* Description: +* Handles the actual interrupt from the adapter. +* +* Context: Interrupt +**************************************************************************/ +void +qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + scsi_qla_host_t *ha; + uint16_t data; + device_reg_t *reg; + device2300_reg_t *reg2300; + + ENTER_INTR("qla2100_intr_handler"); + COMTRACE('I') + ha = (scsi_qla_host_t *) dev_id; + if( !ha ) { + printk(KERN_INFO "qla2100_intr_handler: NULL host ptr\n"); + COMTRACE('X') + return; + } + ha->isr_count++; + qla2100_stats.irqhba = ha; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) + /* Prevent concurrent access to adapters register */ + spin_lock_irqsave(&io_request_lock, cpu_flags); + qla2100_disable_intrs(ha); + + if (ha->device_id == QLA2300_DEVICE_ID) { + reg2300 = ha->iobase2300; + data = qla2100_debounce_register( + (uint16_t *)®2300->host_status) & RISC_2300_INT; + } else { + reg = ha->iobase; + data = qla2100_debounce_register(®->istatus) & + RISC_INT; + } + + /* Check for pending interrupts. */ + if( data ) { + /*DEBUG(qla2100_print("qla2100_intr_handler: Int active, Calling isr\n");)*/ + qla2100_isr(ha, + (srb_t **)&ha->done_q_first, + (srb_t **)&ha->done_q_last); + } + + if( ha->done_q_first ) + qla2100_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + qla2100_enable_intrs(ha); + + /* Wakeup the DPC routine */ + if( (!ha->flags.mbox_busy && (ha->flags.isp_abort_needed || + ha->flags.reset_marker || + ha->flags.update_config_needed || + ( !ha->flags.loop_resync_active && + ha->flags.loop_resync_needed) ) ) + && ha->dpc_wait && !ha->dpc_active ) { /* v2.19.4 */ + up(ha->dpc_wait); + } + +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) */ + + /* Prevent concurrent access to istatus register */ + if( test_bit(QLA2100_IN_ISR_BIT, (int *)&ha->flags) ) { + COMTRACE('X') + DEBUG(printk("scsi%d: Already in interrupt - returning \n", (int)ha->host_no);) + return; + } + set_bit(QLA2100_IN_ISR_BIT, (int *)&ha->flags); + qla2100_disable_intrs(ha); + + if (ha->device_id == QLA2300_DEVICE_ID) { + reg2300 = ha->iobase2300; + data = qla2100_debounce_register( + (uint16_t *)®2300->host_status) & RISC_2300_INT; + } else { + reg = ha->iobase; + data = qla2100_debounce_register(®->istatus) & + RISC_INT; + } + + /* Check for pending interrupts. */ + if( data ) { + DEBUG(qla2100_print("qla2100_intr_handler_2: Int active, Calling isr\n");) + qla2100_isr(ha, + (srb_t **)&ha->done_q_first, + (srb_t **)&ha->done_q_last); + } + + if( ha->done_q_first ) + qla2100_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + + /* Schedule the DPC routine */ + if( (ha->flags.isp_abort_needed || + ha->flags.reset_marker || + ( !ha->flags.loop_resync_active && + ha->flags.loop_resync_needed) || + ha->done_q_first ) && !ha->flags.dpc_sched ) { + + ha->run_qla_bh.data = (void *) ha; + ha->run_qla_bh.routine = qla2100_do_dpc; + + COMTRACE('P') + queue_task_irq(&ha->run_qla_bh,&tq_scheduler); + ha->flags.dpc_sched = TRUE; + } + clear_bit(QLA2100_IN_ISR_BIT, (int *)&ha->flags); + qla2100_enable_intrs(ha); +#endif + + COMTRACE('i') + LEAVE_INTR("qla2100_intr_handler"); +} + +/************************************************************************** +* qla2100_do_dpc +* This kernel thread is a task that is schedule by the interrupt handler +* to perform the background processing for interrupts. +* +* Notes: +* This task always run in the context of a kernel thread. It +* is kick-off by the driver's detect code and starts up +* up one per adapter. It immediately goes to sleep and waits for +* some fibre event. When either the interrupt handler or +* the timer routine detects a event it will one of the task +* bits then wake us up. +**************************************************************************/ +void +qla2100_do_dpc(void *p) { + scsi_qla_host_t *ha = (scsi_qla_host_t *) p; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + struct semaphore sem = MUTEX_LOCKED; +#else + DECLARE_MUTEX_LOCKED(sem); +#endif + unsigned long flags; + srb_t *sp, *sp_next; + uint32_t b, t, l; + scsi_lu_t *q; + int status; + + lock_kernel(); + + /* + * If we were started as result of loading a module, close all of the + * user space pages. We don't need them, and if we didn't close them + * they would be locked into memory. + */ + exit_mm(current); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) + + daemonize(); + +#endif + current->session = 1; + current->pgrp = 1; + /* + * FIXME(dg) this is still a child process of the one that did the insmod. + * This needs to be attached to task[0] instead. + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); +#else + siginitsetinv(¤t->blocked, sigmask(SIGKILL)); +#endif + current->fs->umask = 0; + + /* + * Set the name of this process. + */ + sprintf(current->comm, "qla2100_dpc_%d", (int)ha->host_no); + + ha->dpc_wait = &sem; + ha->dpc_handler = current; + + unlock_kernel(); + + /* + * Wake up the thread that created us. + */ + DEBUG(printk("qla2100_dpc: Wake up parent %d\n", ha->dpc_notify->count.counter)); + + up(ha->dpc_notify); + + while( 1 ) { + /* + * If we get a signal, it means we are supposed to go + * away and die. This typically happens if the user is + * trying to unload a module. + */ + DEBUG(printk("qla2100 %d: DPC handler sleeping\n",(int)ha->host_no)); + down_interruptible(&sem); + + if( signal_pending(current) ) + break; /* get out */ + + DEBUG(printk("qla2100 %d: DPC handler waking up\n",(int)ha->host_no);) + + if (ha->dpc_flags & COMMAND_WAIT_NEEDED) { + /* Release task daemon lock. */ + DEBUG(printk("Waiting on commands to complete\n");) + if( qla2100_cmd_wait(ha) ) + continue; + /* Acquire task daemon lock. */ + } + spin_lock_irqsave(&io_request_lock, flags); + ha->dpc_active = 1; + + /* Determine what action is necessary */ + + /* Flush all commands in watchdog queue */ + if( ha->flags.port_restart_needed ) { + DEBUG(qla2100_print("qla2100: DPC port restarting - flushing all cmds in watchdog queue.\n");) + ha->flags.port_restart_needed = FALSE; + for( sp = ha->retry_q_first; (sp != NULL); sp = sp_next ) { + sp_next = sp->s_next; + b = SCSI_BUS_32(sp->cmd); + t = SCSI_TCN_32(sp->cmd); + l = SCSI_LUN_32(sp->cmd); + if( (q = GET_LU_Q(ha, b, t,l)) == NULL || + !(q->q_flag & QLA2100_QSUSP) ) + continue; + q->q_flag &= ~QLA2100_QSUSP; + qla2100_timeout_remove(ha, sp); + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + + /* v2.19 - We want to wait until the end to + * return all requests back to OS. + */ + /* deleted: qla2100_restart_queues(ha, FALSE); */ + ha->flags.restart_queues_needed = TRUE; + } + + /* Process any pending mailbox commands */ + if( !ha->flags.mbox_busy ) { + if( ha->flags.isp_abort_needed ) { + DEBUG(printk("dpc: qla2100_abort_isp ha = %p\n", ha);) + ha->flags.isp_abort_needed = FALSE; + qla2100_abort_isp(ha); + } + + if( ha->flags.reset_marker ) { + DEBUG(printk("dpc: qla2100_reset_marker \n");) + qla2100_rst_aen(ha); + } + + if( ha->flags.update_config_needed ) { + DEBUG(printk("dpc: qla2100_update_config\n");) + qla2100_update_config(ha); + } + + /* v2.19.8 Retry each device up to login retry count */ + if ( (ha->device_flags & RELOGIN_NEEDED) && + !ha->loop_state != LOOP_DOWN ) { /* v2.19.5 */ + DEBUG(printk("dpc: qla2100_login\n");) + ha->device_flags &= ~RELOGIN_NEEDED; + for (t = 0; t < MAX_FIBRE_DEVICES; t++) { + /* check if fabric logic retry needed */ + if ( (ha->fc_db[t].flag & DEV_PUBLIC) && + (ha->fc_db[t].flag & DEV_RELOGIN) ) { + if ( PORT_DOWN(ha,t) ) { + PORT_DOWN(ha,t)--; + if ( (status = qla2x00_login_public_device(ha, + &ha->fc_db[t].loop_id, + &ha->fc_db[t].port_id[0], + (uint16_t) MBC_NO_PLOGI_IF_LOGGED_IN)) == QL_STATUS_SUCCESS ) { + DEBUG(printk("dpc: logged in ID %x\n",ha->fc_db[t].loop_id);) + /* restart ports */ + ha->fc_db[t].flag &= ~DEV_RELOGIN; + PORT_DOWN(ha,t) = 0; + } else if ( status == QL_STATUS_FATAL_ERROR ) { + ha->flags.isp_abort_needed = TRUE; + ha->fc_db[t].flag &= ~DEV_RELOGIN; + PORT_DOWN(ha,t) = 0; + } else { + /* retry the login again */ + ha->device_flags |= RELOGIN_NEEDED; + DEBUG(printk("dpc: Retry %d logged in ID %x\n",PORT_DOWN(ha,t), + ha->fc_db[t].loop_id);) + } + } + } + } + DEBUG(printk("dpc: qla2100_login_end.\n");) + } + + /* v2.19.5 */ + if ( (ha->device_flags & LOGIN_RETRY_NEEDED) && + !ha->loop_state != LOOP_DOWN ) { /* v2.19.5 */ + ha->device_flags &= ~LOGIN_RETRY_NEEDED; + DEBUG(printk("dpc: qla2100_login_retry\n");) + qla2100_loop_resync(ha); + DEBUG(printk("dpc: qla2100_login_retry end.\n");) + } + + /* v2.19.5b5 */ + if( ha->flags.loop_resync_needed ) { + if( (ha->device_flags & RSCN_UPDATE ) ) { + DEBUG(printk("dpc: qla2100_rscn_update\n");) + ha->device_flags &= ~RSCN_UPDATE; + } + else + DEBUG(printk("dpc: qla2100_loop_resync\n");) + qla2100_loop_resync(ha); + DEBUG(printk("dpc: qla2100_loop_resync/rscn_update done\n");) + } + + if( ha->flags.restart_queues_needed ) { + DEBUG(printk("dpc: calling qla2100_restart_queues\n");) + qla2100_restart_queues(ha,FALSE); + } + + if( ha->flags.abort_queue_needed ) { + DEBUG(printk("dpc: qla2100_abort_queues\n");) + qla2100_abort_queues(ha, FALSE); + } + if( !ha->interrupts_on ) + qla2100_enable_intrs(ha); + } + + if( ha->flags.done_requests_needed ) + ha->flags.done_requests_needed = FALSE; + + if( ha->done_q_first ) { + qla2100_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + + ha->dpc_active = 0; + + /* The spinlock is really needed up to this point. (DB) */ + spin_unlock_irqrestore(&io_request_lock, flags); + } + DEBUG(qla2100_print("dpc: DPC handler exiting\n");) + + /* + * Make sure that nobody tries to wake us up again. + */ + ha->dpc_wait = NULL; + ha->dpc_handler = NULL; + ha->dpc_active = 0; + + /* + * If anyone is waiting for us to exit (i.e. someone trying to unload + * a driver), then wake up that process to let them know we are on + * the way out the door. This may be overkill - I *think* that we + * could probably just unload the driver and send the signal, and when + * the error handling thread wakes up that it would just exit without + * needing to touch any memory associated with the driver itself. + */ + if( ha->dpc_notify != NULL ) + up(ha->dpc_notify); + + +} + +/************************************************************************** +* qla2100_device_queue_depth +* Determines the queue depth for a given device. There are two ways +* a queue depth can be obtained for a tagged queueing device. One +* way is the default queue depth which is determined by whether +* If it is defined, then it is used +* as the default queue depth. Otherwise, we use either 4 or 8 as the +* default queue depth (dependent on the number of hardware SCBs). +**************************************************************************/ +STATIC void qla2100_device_queue_depth(scsi_qla_host_t *p, Scsi_Device *device) { + int default_depth = 16; + + device->queue_depth = default_depth; + if( device->tagged_supported ) { + device->tagged_queue = 1; + device->current_tag = 0; +#ifdef MODULE + if( !(ql2xmaxqdepth == 0 || ql2xmaxqdepth > 256) ) + device->queue_depth = ql2xmaxqdepth; +#endif + + printk(KERN_INFO "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue depth %d.\n", + (int)p->host_no, device->channel, device->id, + device->lun, device->queue_depth); + } else { + printk(KERN_WARNING "scsi(%d:%d:%d:%d):Device does not supoort tags queuing!!!.\n", + (int)p->host_no, device->channel, device->id, + device->lun); + } +} + +/************************************************************************** +* qla2100_select_queue_depth +* +* Description: +* Sets the queue depth for each SCSI device hanging off the input +* host adapter. We use a queue depth of 2 for devices that do not +* support tagged queueing. +**************************************************************************/ +STATIC void +qla2100_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) { + Scsi_Device *device; + scsi_qla_host_t *p = (scsi_qla_host_t *) host->hostdata; + + ENTER("qla2100_select_queue_depth"); + for( device = scsi_devs; device != NULL; device = device->next ) { + if( device->host == host ) + qla2100_device_queue_depth(p, device); + } + LEAVE("qla2100_select_queue_depth"); +} + +/************************************************************************** +* ** Driver Support Routines ** +* +* qla2100_enable_intrs +* qla2100_disable_intrs +**************************************************************************/ +static inline void qla2100_enable_intrs(scsi_qla_host_t *ha) { + device_reg_t *reg; + + reg = ha->iobase; + ha->interrupts_on = 1; + /* enable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, (ISP_EN_INT+ ISP_EN_RISC)); +} + +static inline void qla2100_disable_intrs(scsi_qla_host_t *ha) { + device_reg_t *reg; + + reg = ha->iobase; + ha->interrupts_on = 0; + /* disable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, 0); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +/************************************************************************** +* mdelay +* Delay in milliseconds +* +**************************************************************************/ +STATIC inline void +mdelay(int milliseconds) { + int i; + + for( i=0; is_next) ) + *done_q_last = NULL; + else + (*done_q_first)->s_prev = NULL; + qla2100_stats.done_q_cnt--; + DEBUG(sp->state = 5;) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_UNLOCK +#endif + QLA2100_TIMER_UNLOCK(ha); + cmd = sp->cmd; + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + q = GET_LU_Q(ha, b, t, l); + + /* Decrement outstanding commands on device. */ + if( q->q_outcnt ) + q->q_outcnt--; + if( q->q_outcnt < ha->hiwat ) { + q->q_flag &= ~QLA2100_QBUSY; + } + + q->io_cnt++; + + switch( (CMD_RESULT(cmd)>>16) ) { + case DID_RESET: + q->q_flag &= ~QLA2100_QRESET; + /* Issue marker command. */ + qla2100_marker(ha, b, t, 0, MK_SYNC_ID); + break; + case DID_ABORT: + sp->flags &= ~SRB_ABORT_PENDING; + sp->flags |= SRB_ABORTED; + if( sp->flags & SRB_TIMEOUT ) + CMD_RESULT(sp->cmd)= DID_TIME_OUT << 16; + break; + default: + break; + } + + /* 4.10 64 and 32 bit */ + /* Release memory used for this I/O */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + if (cmd->use_sg) { + /* DEBUG(sprintf(debug_buff, + "S/G unmap_sg cmd=%x\n\r",cmd);) + DEBUG(qla2100_print(debug_buff)); */ + pci_unmap_sg(ha->pdev, cmd->request_buffer, + cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } + else if (cmd->request_bufflen) { + /* DEBUG(sprintf(debug_buff, + "No S/G unmap_single cmd=%x saved_dma_handle=%lx\n\r", + cmd,sp->saved_dma_handle);) + DEBUG(qla2100_print(debug_buff);) */ + pci_unmap_single(ha->pdev,sp->saved_dma_handle, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } +#endif + /* Call the mid-level driver interrupt handler */ + /* DEBUG(sprintf(debug_buff," [%d] ",cmd->pid);) + DEBUG(qla2100_print(debug_buff);) */ + + qla2100_callback(ha,sp,TRUE); + qla2100_next(ha, q); + } + + + COMTRACE('d') + /* LEAVE("qla2100_done"); */ +} + +/************************************************************************** +* qla2100_return_status +* Translates a ISP error to a Linux SCSI error +**************************************************************************/ +STATIC int qla2100_return_status(scsi_qla_host_t *ha, + sts_entry_t *sts, Scsi_Cmnd *cp) { + int host_status = DID_ERROR; + int scsi_status; + int comp_status; + unsigned resid; + srb_t *sp; + uint32_t t; + uint8_t *strp; + scsi_lu_t *up; + +#if DEBUG_QLA2100_INTR + STATIC char *reason[] = { + "DID_OK", + "DID_NO_CONNECT", + "DID_BUS_BUSY", + "DID_TIME_OUT", + "DID_BAD_TARGET", + "DID_ABORT", + "DID_PARITY", + "DID_ERROR", + "DID_RESET", + "DID_BAD_INTR" + }; +#endif /* DEBUG_QLA2100_INTR */ + + ENTER("qla2100_return_status"); + +#if DEBUG_QLA2100_INTR + /* + DEBUG(printk("qla2100: compl status = 0x%04x\n", sts->comp_status)); + */ +#endif + scsi_status = sts->scsi_status; + comp_status = sts->comp_status; + sp = (srb_t *) CMD_SP(cp); + + if( (scsi_status & SS_RESIDUAL_OVER) ) + comp_status = CS_DATA_OVERRUN; + else if( (scsi_status & SS_RESPONSE_INFO_LEN_VALID) && + sts->rsp_info[3] == (uint8_t) 0 ) + comp_status = CS_COMPLETE; + + /* If scanning and missing lun then let the scsi layer skip it */ + /* 4.24 dg 01/18/2001 */ + if( cp->cmnd[0] == 0x12 && + cp->lun == 0 ) { /* inquiry */ + strp = (uint8_t *)cp->request_buffer; + up = (scsi_lu_t *) GET_LU_Q(ha, 0, cp->target, cp->lun); + if( *strp == 0x7f && up->io_cnt < 5) { + /* Make lun unassigned and wrong type */ + *strp = 0x23; + } + } + + switch( comp_status ) { + case CS_COMPLETE: + host_status = DID_OK; + /* v2.19.5b2 Reset port down retry on success. */ + sp->port_down_retry_count = ha->port_down_retry_count; + break; + case CS_PORT_UNAVAILABLE: + /* release target data structure */ + host_status = DID_NO_CONNECT; + DEBUG(sprintf(debug_buff,"scsi: Unavail port detected 0x%x-0x%x.\n", + sts->comp_status, sts->scsi_status); ) + DEBUG(qla2100_print(debug_buff);) + break; + case CS_PORT_LOGGED_OUT: + case CS_PORT_CONFIG_CHG: + case CS_PORT_BUSY: + case CS_INCOMPLETE: + host_status = DID_NO_CONNECT; + DEBUG(sprintf(debug_buff,"scsi: Port Error detected 0x%x-0x%x.\n", + sts->comp_status, sts->scsi_status); ) + DEBUG(qla2100_print(debug_buff);) + break; + case CS_RESET: + host_status = DID_RESET; + break; + case CS_ABORTED: + /* v2.19.12 - DID_ABORT does not retry the request */ + /* if we aborted this request then abort otherwise it must be a reset */ + if ( (sp->flags & SRB_ABORT_PENDING) ) + host_status = DID_ABORT; + else + host_status = DID_RESET; + break; + case CS_TIMEOUT: + host_status = DID_ERROR; + /* v2.19.8 if timeout then check to see if logout occurred*/ + t = SCSI_TCN_32(cp); + if ( (ha->fc_db[t].flag & DEV_PUBLIC) && + (sts->status_flags & IOCBSTAT_SF_LOGO) ) { + ha->fc_db[t].flag |= DEV_RELOGIN; + DEBUG(printk("scsi: Timeout occurred with Logo, status flag (%x) with public device loop id (%x), attempt new recovery\n", + sts->status_flags, ha->fc_db[t].loop_id);) + /* Suspend port */ + PORT_DOWN(ha,t) = ha->port_down_retry_count; + ha->device_flags |= RELOGIN_NEEDED; + } + break; + case CS_DATA_UNDERRUN: + resid = sts->residual_length; + /* if RISC reports underrun and target does not report it + * then we must have a lost frame, so tell upper layer + * to retry it by reporting an error. + */ + if( !(sts->scsi_status & SS_RESIDUAL_UNDER) ) { + resid = (unsigned)(CMD_XFRLEN(cp)); + } + + if( (unsigned)(CMD_XFRLEN(cp) - resid) < cp->underflow ) { + host_status = DID_ERROR; + DEBUG3(sprintf(debug_buff,"scsi: Underflow detected - retrying command.\n");) + DEBUG3(qla2100_print(debug_buff);) + } else { + /* v2.19.5b2 Reset port down retry on success. */ + sp->port_down_retry_count = ha->port_down_retry_count; + host_status = DID_OK; + } + break; + + default: + DEBUG3(printk("scsi: Error detected 0x%x-0x%x.\n", + sts->comp_status, sts->scsi_status);) + host_status = DID_ERROR; + break; + } + +#if DEBUG_QLA2100_INTR + sprintf(debug_buff, "qla2100 ISP status: host status (%s) scsi status %x\n\r", reason[host_status], scsi_status); + DEBUG(qla2100_print(debug_buff);) +#endif + + LEAVE("qla2100_return_status"); + + return ((scsi_status & STATUS_MASK) | (host_status << 16) ); +} + +/* +* qla2100_done_q_put +* Place SRB command on done queue. +* +* Input: +* ha = host pointer +* sp = srb pointer. +* done_q_first = done queue first pointer. +* done_q_last = done queue last pointer. +*/ +STATIC void +qla2100_done_q_put(scsi_qla_host_t *ha, srb_t *sp, srb_t **done_q_first, srb_t **done_q_last) { + + unsigned long cpu_flags = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_put_done_q"); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_LOCK +#else + QLA2100_TIMER_LOCK(ha); +#endif + /* Place block on done queue */ + sp->s_next = NULL; + sp->s_prev = *done_q_last; + if( !*done_q_first ) + *done_q_first = sp; + else + (*done_q_last)->s_next = sp; + *done_q_last = sp; + + qla2100_stats.done_q_cnt++; + DEBUG(sp->state = 3;) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_LOCK +#else + QLA2100_TIMER_UNLOCK(ha); +#endif + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_put_done_q"); +#endif +} + + +/************************************************************************** +* qla2100_timer +* +* Description: +* One second timer +* +* Context: Interrupt +**************************************************************************/ +STATIC void +qla2100_timer(scsi_qla_host_t *ha) { + + srb_t *sp, *sp_next; + int stop_timer, kick_off = 0; + int cnt; + int t; + /* unsigned long cpu_flags = 0; */ + + + /* ENTER("qla2100_timer"); */ + + /* v2.19.02 spin_lock_irqsave(&io_request_lock, cpu_flags); */ + + stop_timer = 0; + + for( t = 0; t < ha->max_targets; t++ ) { + if( TGT_Q(ha, 0, t) == NULL ) + continue; + if( TGT_Q(ha, 0, t)->down_timer > 0 ) + TGT_Q(ha, 0, t)->down_timer--; + } + + /* Port Down Handler. */ + if( ha->queue_restart_timer > 0 ) { + ha->queue_restart_timer--; +#ifdef TRACECODE + sprintf(debug_buff,"timer: Port down time in secs %d\n",ha->queue_restart_timer); + qla2100_print(debug_buff); +#endif + /* + * When a port goes DOWN, we suspend the queue and wait 1 second + * (one timer tick) before trying to kick off the commands again. + * We will do this for "port_down_retry_count" times per + * command before giving up on the command altogether. + */ + if( !ha->queue_restart_timer ) { + ha->flags.port_restart_needed = TRUE; + DEBUG(qla2100_print("qla2100_timer: Port Down complete - restarting commands in the queues\n");) + stop_timer++; + } + } + /* Loop down handler. */ + if( ha->loop_down_timer > 0 && + !ha->flags.abort_isp_active && + ha->flags.online ) { + if( ha->loop_down_timer == LOOP_DOWN_TIME ) { + DEBUG(printk("qla2100_timer: Loop Down time expired - aborting the queues before time expire\n");) +#ifdef TRACECODE + qla2100_print("qla2100_timer: Loop Down - aborting the queues before time expire\n"); +#endif +#if 1 + ha->flags.abort_queue_needed = TRUE; +#else + qla2100_abort_queues(ha, TRUE); +#endif + } + + ha->loop_down_timer--; +#ifdef TRACECODE + sprintf(debug_buff,"qla2100_timer: Loop Down - seconds remainning %d\n",ha->loop_down_timer); + qla2100_print(debug_buff); +#endif + /* if the loop has been down for 4 minutes on QLA2100, + reinit adapter */ + if( !ha->loop_down_timer ) { +#ifdef TRACECODE + qla2100_print("qla2100_timer: Loop down for 4 mins \n"); +#endif + DEBUG(printk("qla2100_timer: Loop down exceed 4 mins -restarting queues and abort ISP.\n");) + ha->flags.restart_queues_needed = TRUE; + if ( (ha->device_id == QLA2100_DEVICE_ID) && + (qla2100_reinit == 1 )) + ha->flags.isp_abort_needed = TRUE; + stop_timer++; + } + } + + /* + * Retry Handler -- This handler will recycle queued requests until the + * temporary loop down condition terminates. + */ + if( !ha->flags.abort_isp_active ) { +#ifdef TRACECODE + if( ha->retry_q_first ) + qla2100_print("qla2100_timer: Scanning for timed out commands\n"); +#endif + for( cnt=0, sp = ha->retry_q_first; (sp); sp = sp_next ) { + if( sp->wdg_time ) + sp->wdg_time--; + sp_next = sp->s_next; + if( sp->wdg_time == 0 ) { + kick_off++; + DEBUG3(sprintf(debug_buff,"timer: CMD timeout %p, pid %d\n",sp, sp->cmd->pid);) + DEBUG3(qla2100_print(debug_buff);) + cnt++; + qla2100_timeout_remove(ha, sp); + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + } + + if( cnt > 0 ) { + DEBUG2(sprintf(debug_buff,"timer: found %d requests\n",cnt);) + DEBUG2(qla2100_print(debug_buff);) + } + } + + if( ha->done_q_first ) + ha->flags.done_requests_needed = TRUE; + + if( ha->dpc_flags & ISP_RESET_NEEDED) { + ha->dpc_flags &= ~ISP_RESET_NEEDED; + ha->flags.isp_abort_needed = TRUE; + } + + +#if QLA2100_LIPTEST + if( (ha->forceLip++) == (60*3) && qla2100_lip) { + /* qla2100_loop_reset(ha); */ + qla2100_abort_isp(ha); + ha->forceLip = 0; + } +#endif + /* v2.19.02 spin_unlock_irqrestore(&io_request_lock, cpu_flags); */ + + /* Schedule the DPC routine if needed */ + if( ( ha->flags.isp_abort_needed || + (!ha->flags.loop_resync_active && ha->flags.loop_resync_needed) || + ha->flags.restart_queues_needed || + ha->flags.port_restart_needed || + ha->flags.done_requests_needed || + (ha->device_flags & RELOGIN_NEEDED) || + (ha->dpc_flags & COMMAND_WAIT_NEEDED) || + (ha->device_flags & LOGIN_RETRY_NEEDED) || + kick_off > 0 || + ha->flags.abort_queue_needed ) && + ha->dpc_wait && !ha->dpc_active ) { /* v2.19.4 */ + up(ha->dpc_wait); + } + + /* IOCTL SCSI Pass Thru Handler. */ + if (ha->IoctlPassThru_InProgress) { + if (ha->ioctl_timer) ha->ioctl_timer--; + } + + /* IOCTL FCCT Pass Thru Handler. */ + if (ha->IoctlPassFCCT_InProgress) { + if (ha->ioctl_timer) ha->ioctl_timer--; + } + + /* ha->flags.watchdog_enabled = FALSE; */ + RESTART_TIMER(qla2100_timer,ha,WATCH_INTERVAL); + + /* LEAVE("qla2100_timer"); */ +} + +/* +* qla2100_timeout_insert +* Function used to insert a command block onto the +* watchdog timer queue. +* +* Note: Must insure that sc_time is not zero +* before calling qla2100_timeout_insert. +* +* Input: +* ha = adapter block pointer. +* sp = srb pointer. +*/ +STATIC void +qla2100_timeout_insert(scsi_qla_host_t *ha, srb_t *sp) { + unsigned long cpu_flags = 0; + uint8_t timeoutcnt; + +#ifdef QL_DEBUG_LEVEL_3 + /* ENTER("qla2100_timeout_insert"); */ +#endif + + /* Compute number of time intervals */ + timeoutcnt = (uint8_t) (CMD_TIMEOUT(sp->cmd)/(WATCH_INTERVAL * HZ)); + if( timeoutcnt >= 3 ) /* 3 or more */ + /* sp->wdg_time = timeoutcnt - 3; */ + sp->wdg_time = 3; + else + sp->wdg_time = 1; + + DEBUG3(sprintf(debug_buff,"Watchdog (insert) - pid=%d, tmo=%d \n",sp->cmd->pid,sp->wdg_time);) + DEBUG3(qla2100_print(debug_buff);) + + /* Acquire watchdoq queue specific lock */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_LOCK +#else + QLA2100_TIMER_LOCK(ha); +#endif + /* Add command to queue */ + if (ha->retry_q_first == NULL) { + ha->retry_q_first = sp; + ha->retry_q_last = sp; + } else { + ha->retry_q_last->s_next = sp; + ha->retry_q_last = sp; + } + sp->s_next = NULL; + qla2100_stats.retry_q_cnt++; + sp->state = 0xd0; + + sp->flags |= SRB_WATCHDOG; + ha->flags.watchdog_enabled = TRUE; + + /* Release watchdog queue specific lock */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_UNLOCK +#else + QLA2100_TIMER_UNLOCK(ha); +#endif + +#ifdef QL_DEBUG_LEVEL_3 + /* LEAVE("qla2100_timeout_insert"); */ +#endif +} + +/* +* qla2100_timeout_remove +* Function used to remove a command block from the +* watchdog timer queue. +* +* Note: Must insure that command is on watchdog +* list before calling qla2100_timeout_remove. +* if (sp->flags & SRB_WATCHDOG) +* +* Input: +* ha = adapter block pointer. +* sp = srb pointer. +*/ +STATIC void +qla2100_timeout_remove(scsi_qla_host_t *ha, srb_t *sp) { + unsigned long cpu_flags = 0; + srb_t *nextsp; + +#ifdef QL_DEBUG_LEVEL_3 + /* ENTER("qla2100_timeout_remove"); */ +#endif + + DEBUG3(sprintf(debug_buff,"Watchdog (remove) pid=%d time%d\n",sp->cmd->pid,sp->wdg_time);) + DEBUG3(qla2100_print(debug_buff);) + + /* Acquire watchdoq queue specific lock */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_LOCK +#else + QLA2100_TIMER_LOCK(ha); +#endif + /* Remove command block from watchdog queue. */ + if (ha->retry_q_first != NULL) { + if (ha->retry_q_first == sp) { + /* Remove from top of queue */ + ha->retry_q_first = sp->s_next; + if (ha->retry_q_first == NULL) { + + ha->retry_q_last = NULL; + ha->flags.watchdog_enabled = FALSE; + } + } else { + /* Remove from middle of queue or bottom of queue */ + for (nextsp = ha->retry_q_first; nextsp->s_next != NULL; + nextsp = nextsp->s_next) { + if (nextsp->s_next == sp) { + nextsp->s_next = sp->s_next; + if (nextsp->s_next == NULL) + ha->retry_q_last = nextsp; + break; + } + } + } + sp->flags &= ~SRB_WATCHDOG; + qla2100_stats.retry_q_cnt--; + } + + /* Release watchdog queue specific lock */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_UNLOCK +#else + QLA2100_TIMER_UNLOCK(ha); +#endif + +#ifdef QL_DEBUG_LEVEL_3 + /* LEAVE("qla2100_timeout_remove"); */ +#endif +} + +/* +* qla2100_next +* Retrieve and process next job in the queue. +* +* Input: +* ha = adapter block pointer. +* q = SCSI LU pointer. +* SCSI_LU_Q lock must be already obtained and no other locks. +* +* Output: +* Releases SCSI_LU_Q upon exit. +*/ +STATIC void +qla2100_next(scsi_qla_host_t *ha, scsi_lu_t *q) { + srb_t *sp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + uint8_t status; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_next"); +#endif + + DRIVER_LOCK + COMTRACE('N') + while( ((sp = q->q_first) != NULL) && /* we have a pending cmds */ + !(q->q_flag & QLA2100_QBUSY) && /* device can accept more cmds */ + !((q->q_flag & QLA2100_QSUSP) && /* device queue not suspended */ + !ha->flags.abort_isp_active && /* adapter abort active */ + !ha->loop_down_timer) ) /* down timer not active */ + { + /* Remove srb from SCSI LU queue. */ + qla2100_removeq(q, sp); + sp->state = 0x32; + /* Set busy flag if reached high water mark. */ + q->q_outcnt++; + if( q->q_outcnt >= ha->hiwat ) { + q->q_flag |= QLA2100_QBUSY; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + if( ha->flags.enable_64bit_addressing ) + status = qla2100_64bit_start_scsi(ha, sp); + else +#endif + status = qla2100_32bit_start_scsi(ha, sp); + + if( status ) { + qla2100_putq_t(q, sp); + + if( q->q_outcnt ) + q->q_outcnt--; + if( q->q_outcnt < ha->hiwat ) + q->q_flag &= ~QLA2100_QBUSY; + break; + } + } + + COMTRACE('n') + DRIVER_UNLOCK + /* Release SCSI LU queue specific lock */ + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_next"); +#endif +} +#if 0 +/******************************************************* +v4.10 +* This function has been de-implemented +* All DMAable memory is allocated on the spot +* according to what kernel version is in effect. +******************************************************** +* qla2100_alloc_phys +* Function used to allocate physical memory +* and zero it. +* +* Input: +* size = size in bytes. +* flag = sleep flag. +* phy_addr = physical address pointer. +* +* Returns: +* not NULL = success +*/ +STATIC void * +qla2100_alloc_phys(int siz, u_long *phy_addr) { + void *mem = NULL; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_alloc_phys"); +#endif + mem = KMALLOC(siz); + if( mem != NULL ) { + *phy_addr = VIRT_TO_BUS(mem); + BZERO((caddr_t)mem, siz); + DEBUG5(sprintf(debug_buff,"qla2100: get phys mem =0x%lx\n\r",(long)*phy_addr)); + DEBUG5(qla2100_print(debug_buff);) + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( mem == NULL ) + qla2100_print("qla2100_alloc_phys: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_alloc_phys"); +#endif + return(mem); +} +#endif + +/* +* qla2100_putq_t +* Add the standard SCB job to the top of standard SCB commands. +* +* Input: +* q = SCSI LU pointer. +* sp = srb pointer. +* SCSI_LU_Q lock must be already obtained. +*/ +STATIC void +qla2100_putq_t(scsi_lu_t *q, srb_t *sp) { + srb_t *srb_p; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + /* ENTER("qla2100_putq_t"); */ +#endif + DRIVER_LOCK + DEBUG5(sprintf(debug_buff,"Adding to queue 0x%x<-(0x%x)\n\r",q,sp)); + DEBUG5(qla2100_print(debug_buff)); + sp->s_next = NULL; + q->q_incnt++; + sp->state = 2; + /* v2.19.6 */ + if( !q->q_first || !q->q_last) /* If queue empty */ + { + sp->s_prev = NULL; + q->q_first = sp; + q->q_last = sp; + } else { + srb_p = q->q_first; + while( srb_p ) + srb_p = srb_p->s_next; + + if( srb_p ) { + sp->s_prev = srb_p->s_prev; + if( srb_p->s_prev ) + srb_p->s_prev->s_next = sp; + else + q->q_first = sp; + srb_p->s_prev = sp; + sp->s_next = srb_p; + } else { + sp->s_prev = q->q_last; + q->q_last->s_next = sp; + q->q_last = sp; + } + } + + DRIVER_UNLOCK +#ifdef QL_DEBUG_LEVEL_3 + /* LEAVE("qla2100_putq_t"); */ +#endif +} + +/* +* qla2100_removeq +* Function used to remove a command block from the +* LU queue. +* +* Input: +* q = SCSI LU pointer. +* sp = srb pointer. +* SCSI_LU_Q lock must be already obtained. +*/ +STATIC void +qla2100_removeq(scsi_lu_t *q, srb_t *sp) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + DEBUG5(sprintf(debug_buff,"Removing from device_q (0x%x)->(0x%x)\n\r",q,sp)); + DEBUG5(qla2100_print(debug_buff)); + DRIVER_LOCK + if( sp->s_prev ) { + if( (sp->s_prev->s_next = sp->s_next) != NULL ) + sp->s_next->s_prev = sp->s_prev; + else + q->q_last = sp->s_prev; + } else if( !(q->q_first = sp->s_next) ) + q->q_last = NULL; + else + q->q_first->s_prev = NULL; + q->q_incnt--; + DRIVER_UNLOCK +} + +/* +* qla2100_callback +* Returns the completed SCSI command to LINUX. +* +* Returns: +* None +*/ +static inline void qla2100_callback(scsi_qla_host_t *ha, srb_t *sp, uint8_t dec) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + sp->flags &= ~SRB_SENT; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_LOCK +#endif +#if 0 + if( dec ) + ha->actthreads--; +#endif + + /* v2.19.14 + * Perform internal retries, if needed. + */ + switch( (CMD_RESULT(sp->cmd)>>16) ) { + case DID_ERROR: + if( sp->retry_count > 0 ) { + sp->retry_count--; + DEBUG3(printk("qla2100: RETRY - os retry %d, drv retry %d, port retry %d\n\r",sp->cmd->retries,sp->retry_count,sp->port_down_retry_count)); + CMD_RESULT(sp->cmd) = (int) DID_BUS_BUSY << 16; + } else { + sp->retry_count = ha->retry_count; + /* all resetted commands must return with RESET */ + if(sp->cmd->flags & IS_RESETTING ) { + CMD_RESULT(sp->cmd) = (int) DID_RESET << 16; + DEBUG3(printk("qla2100: RESET cmd %p\n",sp->cmd)); + } + DEBUG3(printk("qla2100: OSerr = %p\n\r",sp->cmd)); + } + break; + default: + break; + } + + /* Call the mid-level driver interrupt handler */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + sti(); + (*(sp->cmd)->scsi_done)(sp->cmd); + cli(); +#else + (*(sp->cmd)->scsi_done)(sp->cmd); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + DRIVER_UNLOCK +#endif +} + +/* +* qla2100_mem_alloc +* Allocates adapter memory. +* +* Returns: +* 0 = success. +* 1 = failure. +*/ +STATIC uint8_t +qla2100_mem_alloc(scsi_qla_host_t *ha) { + + uint8_t status = 1; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_mem_alloc"); +#endif + + /* 4.10 */ + /* get consistent memory allocated for request/response rings */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + ha->request_ring = &ha->req[0]; + ha->request_dma = VIRT_TO_BUS(&ha->req[0]); + ha->response_ring = &ha->res[0]; + ha->response_dma = VIRT_TO_BUS(&ha->res[0]); +#ifdef FC_IP_SUPPORT + ha->pIpBufferQueue = &ha->asIpBuffers[0]; + ha->ppIpBufferQueueLow = VIRT_TO_BUS_LOW(&ha->asIpBuffers[0]); + ha->ppIpBufferQueueHigh = VIRT_TO_BUS_HIGH(&ha->asIpBuffers[0]); +#endif /* FC_IP_SUPPORT */ +#else /* KERNEL >= 2.3.18 */ + ha->request_ring = pci_alloc_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT+1)*(sizeof(request_t))), + &ha->request_dma); + ha->response_ring = pci_alloc_consistent(ha->pdev, + ((RESPONSE_ENTRY_CNT+1)*(sizeof(response_t))), + &ha->response_dma); +#ifdef FC_IP_SUPPORT + /* not ported yet to new pci_alloc_consistent */ + ha->pIpBufferQueue = &ha->asIpBuffers[0]; + ha->ppIpBufferQueueLow = VIRT_TO_BUS_LOW(&ha->asIpBuffers[0]); + ha->ppIpBufferQueueHigh = VIRT_TO_BUS_HIGH(&ha->asIpBuffers[0]); +#endif +#endif + /* 4.10 */ + /* get consistent memory allocated for init control block */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + ha->init_cb = KMALLOC(sizeof(init_cb_t)); + if( ha->init_cb != NULL ) { + ha->init_cb_dma = VIRT_TO_BUS(ha->init_cb); + BZERO((caddr_t)ha->init_cb, sizeof(init_cb_t)); + } +#else + ha->init_cb = pci_alloc_consistent(ha->pdev, + sizeof(init_cb_t), + &ha->init_cb_dma); + BZERO((caddr_t)ha->init_cb, sizeof(init_cb_t)); +#endif + if( ha->init_cb ) status = 0; + + if( status ) + printk(KERN_WARNING "qla2100_mem_alloc: **** FAILED ****\n"); + +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_mem_alloc"); +#endif + return(status); +} + +/* +* qla2100_mem_free +* Frees all adapter allocated memory. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_mem_free(scsi_qla_host_t *ha) { + tgt_t *tgt; + uint32_t b, t; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_mem_free"); +#endif + if( ha ) { + /* Free the target queues */ + b = 0; + for( t = 0; t < MAX_FIBRE_DEVICES; t++ ) { + tgt = TGT_Q(ha, b, t); + if( tgt ) + qla2100_tgt_dealloc(ha, tgt); + } + + /* Free host database. */ + if (ha->phost_db != NULL) { + KMFREE(ha->phost_db, sizeof(fcdev_t) * MAX_HOST_COUNT); + } + + /* 4.10 */ + /* free consistent memory allocated for request and response rings */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + pci_free_consistent(ha->pdev, + ((REQUEST_ENTRY_CNT+1)*(sizeof(request_t))), + ha->request_ring, ha->request_dma); + + pci_free_consistent(ha->pdev, + ((RESPONSE_ENTRY_CNT+1)*(sizeof(response_t))), + ha->response_ring, ha->response_dma); +#endif + /* free memory allocated for ioctl operations */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(ha->ioctl_mem, PAGE_SIZE); +#else + pci_free_consistent(ha->pdev, PAGE_SIZE, + ha->ioctl_mem, ha->ioctl_mem_phys); +#endif + /* free memory allocated for init_cb */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(ha->init_cb, sizeof(init_cb_t)); +#else + pci_free_consistent(ha->pdev, sizeof(init_cb_t), + ha->init_cb, ha->init_cb_dma); +#endif + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_mem_free"); +#endif +} + +/* +* qla2100_tgt_alloc +* Allocates a target queue structure. +* +* Input: +* ha = adapter block pointer. +* +* Returns +* target queue structure = success: +* NULL = otherwise +*/ +static inline tgt_t * +qla2100_tgt_alloc(scsi_qla_host_t *ha) { + tgt_t *tgt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_tgt_alloc"); +#endif + + tgt = (tgt_t *)KMALLOC(sizeof(tgt_t)); /* Could Sleep here */ + if( tgt != NULL ) { + BZERO(tgt,sizeof(tgt_t)); + DEBUG(sprintf(debug_buff,"Alloc Target @ %08x \n",tgt);) + DEBUG(qla2100_print(debug_buff);) + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_tgt_alloc"); +#endif + return(tgt); +} + +/* +* qla2100_lun_alloc +* Allocates a logical device queue structure and lock +* +* Returns: +* SCSI LU structure pointer +*/ +STATIC inline scsi_lu_t * +qla2100_lun_alloc(void) { + scsi_lu_t *q; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_lun_alloc"); +#endif + + q = (scsi_lu_t *)KMALLOC(sizeof(scsi_lu_t)); /* Sleep */ + BZERO(q,sizeof(struct scsi_lu)); + DEBUG(sprintf(debug_buff,"Alloc Lun @ %08x \n",q);) + DEBUG(qla2100_print(debug_buff);) + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_lun_alloc"); +#endif + return(q); +} + +/* +* qla2100_tgt_dealloc +* Deallocates a target and all logical device queue structures. +* +* Input: +* ha = adapter block pointer. +* tgt = Target queue structure pointer +*/ +static inline void +qla2100_tgt_dealloc(scsi_qla_host_t *ha, tgt_t *tgt) { + uint32_t l; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_tgt_dealloc"); +#endif + + if( tgt != NULL ) { + /* Insure all LUN memory is released. */ + for( l = 0; l < ha->max_luns; l++ ) { + if( tgt->luns[l] ) + qla2100_lun_dealloc(tgt->luns[l]); + } + KMFREE(tgt, sizeof(tgt_t)); + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_tgt_dealloc"); +#endif +} + +/* +* qla2100_lun_dealloc +* Deallocates a logical unit queue structure. +* +* Input: +* q = SCSI LU structure pointer +*/ +static inline void +qla2100_lun_dealloc(scsi_lu_t *q) { +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_lun_dealloc"); +#endif + if( q != NULL ) { + DEBUG(sprintf(debug_buff,"Dealloc Lun @ %08x -- deleted\n",q);) + DEBUG(qla2100_print(debug_buff);) + KMFREE(q, sizeof(scsi_lu_t)); + } +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_lun_dealloc"); +#endif + +} + +/* +* qla2100_abort_queue_single +* Abort all commands on a device queues. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void qla2100_abort_queue_single(scsi_qla_host_t *ha,uint32_t b,uint32_t t,uint32_t l,uint32_t stat) { + scsi_lu_t *q; + srb_t *sp; + + ENTER("qla2100_abort_queue_single"); + /* dg - 08/23/99 + * We don't want to try and abort queues that don't exists + * (i.e. the device is not configure on the loop ) + */ + if( ha->loop_down_timer > 0 ) { + return; + } + DEBUG5(sprintf(debug_buff,"Abort queue single %2d:%2d:%2d:%2d\n", + ha->host_no,b,t,l);) + DEBUG5(qla2100_print(debug_buff);) + q = (scsi_lu_t * )GET_LU_Q(ha, b, t, l); + while( q != NULL && (sp = q->q_first) != NULL ) { + /* Acquire LU queue specific lock */ + + qla2100_removeq(q, sp); + + /* Release LU queue specific lock */ + CMD_RESULT(sp->cmd) = stat; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + LEAVE("qla2100_abort_queue_single"); +} + +/****************************************************************************/ +/* QLogic ISP2100 Hardware Support Functions. */ +/****************************************************************************/ + +/* +* qla2100_initialize_adapter +* Initialize board. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +uint8_t +qla2100_initialize_adapter(scsi_qla_host_t *ha) +{ + uint8_t status = QL_STATUS_SUCCESS; + uint8_t isp_init = 0; + uint8_t restart_risc = 0; + uint8_t retry; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_initialize_adapter"); +#endif + + /* Clear adapter flags. */ + ha->forceLip = 0; + ha->flags.online = FALSE; + ha->flags.isp_abort_needed = FALSE; + ha->flags.disable_host_adapter = FALSE; + ha->flags.loop_resync_active = FALSE; + ha->flags.reset_active = FALSE; + ha->flags.abort_isp_active = FALSE; + ha->flags.watchdog_enabled = FALSE; + ha->loop_down_timer = LOOP_DOWN_TIME; + ha->loop_state = LOOP_DOWN; + ha->flags.start_timer = FALSE; + ha->flags.done_requests_needed = FALSE; + ha->device_flags = 0; + ha->dpc_flags = 0; + ha->sns_retry_cnt = 0; + ha->host_db_ptr = 0; + ha->device_flags = 0; + /* 4.11 */ + ha->flags.managment_server_logged_in = 0; + + /* Allocate host database */ + ha->phost_db = (fcdev_t *)KMALLOC(sizeof(fcdev_t) * MAX_HOST_COUNT); + if (ha->phost_db != NULL) { + BZERO(ha->phost_db, sizeof(fcdev_t) * MAX_HOST_COUNT); + DEBUG(sprintf(debug_buff,"Alloc Host DB success. Max Cnt=%d.", + MAX_HOST_COUNT);) + DEBUG(qla2100_print(debug_buff);) + } else { + status = QL_STATUS_RESOURCE_ERROR; + } + + DEBUG(printk("Configure PCI space for adapter...\n")); + + if ( status == QL_STATUS_SUCCESS && + (status = qla2100_pci_config(ha)) == QL_STATUS_SUCCESS ) { + + qla2100_reset_chip(ha); + + /* Initialize Fibre Channel database. */ + qla2100_init_fc_db(ha); + + /* Initialize target map database. */ + qla2100_init_tgt_map(ha); + if( qla2100_verbose ) + printk(KERN_INFO + "scsi(%d): Configure NVRAM parameters...\n", + (int)ha->host_no); + + if( ha->device_id == QLA2100_DEVICE_ID ) + qla2100_nvram_config(ha); + else + qla2200_nvram_config(ha); + + /* v2.19.12 */ + ha->retry_count = ql2xretrycount; + + if( qla2100_verbose ) + printk(KERN_INFO + "scsi(%d): Verifying loaded RISC code...\n", + (int)ha->host_no); + + qla2100_set_cache_line(ha); + + /* If the user specified a device configuration on + * the command line then use it as the configuration. + * Otherwise, we scan for all devices. + */ + if ( ql2xdevconf ) { + qla2100_get_properties(ha, ql2xdevconf); + } + + retry = 10; + /* + * Try an configure the loop. + */ + do { + DEBUG(qla2100_print("qla2100_initialize_adapter: check " + "if firmware needs to be loaded\n");) + + /* If firmware needs to be loaded */ + if( qla2100_isp_firmware(ha) ) { + if( qla2100_verbose ) + printk(KERN_INFO + "scsi(%d): Verifying chip...\n", + (int)ha->host_no); + + if( (status = qla2100_chip_diag(ha)) == + QL_STATUS_SUCCESS ) + status = qla2100_setup_chip(ha); + + if( status == QL_STATUS_SUCCESS ) + DEBUG(printk("scsi(%d): Chip verified " + "and RISC loaded...\n", + (int)ha->host_no)); + } + + if ( status != QL_STATUS_SUCCESS ) + continue; + + status = qla2100_init_rings(ha); + + if ( status != QL_STATUS_SUCCESS ) + continue; + + /* dg - 7/3/1999 + * Wait for a successful LIP up to a maximum of + * (in seconds): RISC login timeout value, RISC + * retry count value, and port down retry value + * OR a minimum of 4 seconds OR If no cable, + * only 5 seconds. + */ + DEBUG(printk("scsi(%d): qla2100_init_rings OK, " + "call qla2100_fw_ready...\n", + (int)ha->host_no)); + DEBUG(qla2100_print("qla2100_init_rings OK, " + "call qla2100_fw_ready...\n");) + + if ( qla2100_fw_ready(ha) == QL_STATUS_SUCCESS ) { + ha->flags.reset_marker = FALSE; + + /* Go setup flash database devices + * with proper Loop ID's. + */ + do { + ha->flags.loop_resync_needed = FALSE; + status = qla2100_update_fc_db(ha, + FALSE); + } while( !ha->loop_down_timer && + ha->flags.loop_resync_needed ); + + /* If database was full and a device + * was not configured, try and reuse + * the slots. + */ + + if( status == QL_STATUS_FATAL_ERROR ) { + do { + ha->flags.loop_resync_needed = + FALSE; + status = + qla2100_update_fc_db(ha, + TRUE); + } while( !ha->loop_down_timer && + ha->flags.loop_resync_needed ); + } + } + if( ha->flags.update_config_needed ) { + ha->init_cb->additional_firmware_options.connection_options = ha->operating_mode; + restart_risc = 1; + } + isp_init = 1; + + } while( restart_risc && retry-- ); + + if( isp_init ) { + ha->flags.reset_marker = FALSE; + qla2100_marker(ha, 0, 0, 0, MK_SYNC_ALL); + + ha->flags.online = TRUE; + + /* Enable target response to SCSI bus. */ + if( ha->flags.enable_target_mode ) + qla2100_enable_lun(ha); + } + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if ( status != QL_STATUS_SUCCESS ) + qla2100_print("qla2100_initialize_adapter: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_initialize_adapter"); +#endif + + return(status); +} + +/* +* ISP Firmware Test +* Checks if present version of RISC firmware is older than +* driver firmware. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = firmware does not need to be loaded. +*/ +STATIC uint8_t +qla2100_isp_firmware(scsi_qla_host_t *ha) { + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2x00_isp_firmware"); +#endif + + if( ha->flags.disable_risc_code_load ) { + /* Verify checksum of loaded RISC code. */ + mb[0] = MBC_VERIFY_CHECKSUM; + mb[1] = *QLBoardTbl_fc[ha->devnum].fwstart; + if( !(status = qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0])) ) { + /* Start firmware execution. */ + mb[0] = MBC_EXECUTE_FIRMWARE; + mb[1] = *QLBoardTbl_fc[ha->devnum].fwstart; + qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } + } else + status = 1; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print( + "qla2100_isp_firmware: **** Return status=1; RISC Load Needed ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2x00_isp_firmware"); +#endif + return(status); +} + +/* +* (08/05/99) +* +* PCI configuration +* Setup device PCI configuration registers. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) +STATIC uint8_t +qla2100_pci_config(scsi_qla_host_t *ha) { + uint8_t status = 1; + uint32_t command; +#if MEMORY_MAPPED_IO + uint32_t page_offset, base; + uint32_t mmapbase; +#endif + config_reg_t *creg = 0; + uint16_t buf_wd; + + ENTER("qla2100_pci_config"); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) +/* 4.12 */ + /* turn on PCI master; for system BIOSes that don't turn + it on by default */ + pci_set_master(ha->pdev); + + if (ha->device_id == QLA2300_DEVICE_ID) { + pci_read_config_word(ha->pdev,OFFSET(creg->command), &buf_wd); + buf_wd = buf_wd | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE | + PCI_COMMAND_PARITY | + PCI_COMMAND_SERR; + buf_wd = buf_wd & ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(ha->pdev,OFFSET(creg->command), buf_wd); + /* temporary: set upper 32 bits of 64 bit address to 0 */ + buf_wd = 0; + pci_write_config_word(ha->pdev,PCI_BASE_ADDRESS_2, buf_wd); + } +#endif + pci_read_config_word(ha->pdev,OFFSET(creg->revision_id), &buf_wd); + ha->revision = buf_wd; + if( !ha->iobase ) { + /* Get command register. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + if( pci_read_config_word(ha->pdev,OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL ) { +#else + if( pci_read_config_word(ha->pdev,OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL ) { +#endif + command = buf_wd; + /* + * Set Bus Master Enable (bit-2), Memory Address Space Enable and + * reset any error bits. + */ + buf_wd &= ~0x7; +#if MEMORY_MAPPED_IO + DEBUG(printk("qla2100: I/O SPACE and MEMORY MAPPED IO is enabled.\n")); + buf_wd |= BIT_2 + BIT_1 + BIT_0; +#else + DEBUG(printk("qla2100: I/O SPACE Enabled and MEMORY MAPPED IO is disabled.\n")); + buf_wd |= BIT_2 + BIT_0; +#endif + if( pci_write_config_word(ha->pdev,OFFSET(creg->command), buf_wd) ) { + printk(KERN_WARNING "qla2100: Could not write config word.\n"); + } + /* Get expansion ROM address. */ + if( pci_read_config_word(ha->pdev, OFFSET(creg->expansion_rom), &buf_wd) == PCIBIOS_SUCCESSFUL ) { + /* Reset expansion ROM address decode enable. */ + buf_wd &= ~BIT_0; + if( pci_write_config_word(ha->pdev, OFFSET(creg->expansion_rom), buf_wd) == PCIBIOS_SUCCESSFUL ) { +#if MEMORY_MAPPED_IO + /* Get memory mapped I/O address. */ + pcibios_read_config_dword(ha->pci_bus, ha->pci_device_fn,OFFSET(cfgp->mem_base_addr), &mmapbase); + mmapbase &= PCI_BASE_ADDRESS_MEM_MASK; + + /* Find proper memory chunk for memory map I/O reg. */ + base = mmapbase & PAGE_MASK; + page_offset = mmapbase - base; + /* Get virtual address for I/O registers. */ + ha->mmpbase = ioremap(base,page_offset + 256); + if( ha->mmpbase ) { + ha->mmpbase += page_offset; + /* ha->iobase = ha->mmpbase; */ + status = 0; + } +#else /* MEMORY_MAPPED_IO */ + status = 0; +#endif /* MEMORY_MAPPED_IO */ + } + } + } + } else + status = 0; + + + LEAVE("qla2100_pci_config"); + return(status); +} +#else +STATIC uint8_t +qla2100_pci_config(scsi_qla_host_t *ha) { + uint8_t status = 1; + uint32_t command; +#if MEMORY_MAPPED_IO + uint32_t page_offset, base; + uint32_t mmapbase; +#endif + config_reg_t *creg = 0; + uint16_t buf_wd; + + ENTER("qla2100_pci_config"); + + pcibios_read_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->revision_id), &buf_wd); + ha->revision = buf_wd; + if( !ha->iobase ) { + /* Get command register. */ + if( pcibios_read_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL ) { + command = buf_wd; + + /* + * Set Bus Master Enable (bit-2), Memory Address Space Enable and + * reset any error bits. + */ + buf_wd &= ~0x7; +#if MEMORY_MAPPED_IO + DEBUG(printk("qla2100: I/O SPACE and MEMORY MAPPED IO is enabled.\n")); + buf_wd |= BIT_2 + BIT_1 + BIT_0; +#else + DEBUG(printk("qla2100: I/O SPACE Enabled and MEMORY MAPPED IO is disabled.\n")); + buf_wd |= BIT_2 + BIT_0; +#endif + if( pcibios_write_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->command), buf_wd) ) { + printk(KERN_WARNING "qla2100: Could not write config word.\n"); + } + /* Get expansion ROM address. */ + if( pcibios_read_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->expansion_rom), &buf_wd) == PCIBIOS_SUCCESSFUL ) { + /* Reset expansion ROM address decode enable. */ + buf_wd &= ~BIT_0; + if( pcibios_write_config_word(ha->pci_bus,ha->pci_device_fn, OFFSET(creg->expansion_rom), buf_wd) == PCIBIOS_SUCCESSFUL ) { +#if MEMORY_MAPPED_IO + /* Get memory mapped I/O address. */ + pcibios_read_config_dword(ha->pci_bus, ha->pci_device_fn,OFFSET(cfgp->mem_base_addr), &mmapbase); + mmapbase &= PCI_BASE_ADDRESS_MEM_MASK; + + /* Find proper memory chunk for memory map I/O reg. */ + base = mmapbase & PAGE_MASK; + page_offset = mmapbase - base; + /* Get virtual address for I/O registers. */ + ha->mmpbase = ioremap(base,page_offset + 256); + if( ha->mmpbase ) { + ha->mmpbase += page_offset; + /* ha->iobase = ha->mmpbase; */ + status = 0; + } +#else /* MEMORY_MAPPED_IO */ + status = 0; +#endif /* MEMORY_MAPPED_IO */ + } + } + } + } else + status = 0; + + + LEAVE("qla2100_pci_config"); + return(status); +} +#endif + + +/* +* qla2100_set_cache_line +* Sets PCI cache line parameter. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_set_cache_line(scsi_qla_host_t *ha) { + int status = 0; + uint8_t buf; + config_reg_t *creg = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_set_cache_line"); +#endif + /* Set the cache line. */ + if( ha->flags.set_cache_line_size_1 ) { + buf = 1; + if( pcibios_write_config_byte(ha->pci_bus, + ha->pci_device_fn, + (u_long)&creg->cache_line,buf) != PCIBIOS_SUCCESSFUL ) + status = 1; + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_set_cache_line: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_set_cache_line"); +#endif + return(status); +} + +/* +* Chip diagnostics +* Test chip for proper operation. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_chip_diag(scsi_qla_host_t *ha) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + uint8_t status = 0; + uint16_t data; + uint32_t cnt; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + ENTER("qla2100_chip_diag"); +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_chip_diag: testing device at "); + qla2100_output_number((u_long)®->flash_address, 16); + qla2100_print("\n"); +#endif + + /* Reset ISP chip. */ + WRT_REG_WORD(®->ctrl_status, ISP_RESET); + data = qla2100_debounce_register(®->ctrl_status); + for( cnt = 6000000 ; cnt && (data & ISP_RESET); cnt-- ) { + SYS_DELAY(5); + data = RD_REG_WORD(®->ctrl_status); + } + + if( cnt ) { +#if defined(QL_DEBUG_LEVEL_2) + qla2100_print("{{{qla2100_chip_diag: Reset register cleared by chip}}}\n\r"); +#endif + /* Reset RISC processor. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + data = qla2100_debounce_register(®->mailbox0); + for( cnt = 6000000; cnt && (data == MBS_BUSY); cnt-- ) { + SYS_DELAY(5); + data = RD_REG_WORD(®->mailbox0); + } + + if( cnt ) { + /* Check product ID of chip */ +#if defined(QL_DEBUG_LEVEL_2) + qla2100_print("{{{qla2100_chip_diag: Checking product ID of chip}}}\n\r"); +#endif + if (ha->device_id != QLA2300_DEVICE_ID) { + if( RD_REG_WORD(®->mailbox1) != PROD_ID_1 || + (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && + RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || + RD_REG_WORD(®->mailbox3) != PROD_ID_3 || + qla2100_debounce_register(®->mailbox4) != PROD_ID_4 ) { + printk(KERN_WARNING "qla2100: [ERROR] Wrong product ID = 0x%x,0x%x,0x%x,0x%x\n", + RD_REG_WORD(®->mailbox1), + RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3), + RD_REG_WORD(®->mailbox4)); + status = 1; + } else { + /* Now determine if we have a 2200A board */ + if( ( ha->device_id == QLA2200_DEVICE_ID || + ha->device_id == QLA2200A_DEVICE_ID ) && + RD_REG_WORD(®->mailbox7) == + QLA2200A_RISC_ROM_VER ) { + ha->device_id = QLA2200A_DEVICE_ID; +#if defined(QL_DEBUG_LEVEL_2) + qla2100_print("qla2100_chip_diag: Found QLA2200A chip.\n\r"); +#endif + } + } + } else { /* check prod id of 2300 here */ + if( RD_REG_WORD(®2300->mailbox1) != PROD_ID_1 || + (RD_REG_WORD(®2300->mailbox2) != PROD_ID_2 && + RD_REG_WORD(®2300->mailbox2) != PROD_ID_2a) || + RD_REG_WORD(®2300->mailbox3) != PROD_ID_3 || + qla2100_debounce_register(®2300->mailbox4) != PROD_ID_4 ) { + printk(KERN_WARNING "qla2300: [ERROR] Wrong product ID = 0x%x,0x%x,0x%x,0x%x\n", + RD_REG_WORD(®2300->mailbox1), + RD_REG_WORD(®2300->mailbox2), + RD_REG_WORD(®2300->mailbox3), + RD_REG_WORD(®2300->mailbox4)); + status = 1; + } + DEBUG(printk("qla2100_chip_diag: Do MBC_MAILBOX_REGISTER_TEST\n")); +#if defined(QL_DEBUG_LEVEL_2) + qla2100_print("qla2100_chip_diag: Do MBC_MAILBOX_REGISTER_TEST\n\r"); +#endif + /* Wrap Incoming Mailboxes Test. */ + mb[0] = MBC_MAILBOX_REGISTER_TEST; + mb[1] = 0xAAAA; + mb[2] = 0x5555; + mb[3] = 0xAA55; + mb[4] = 0x55AA; + mb[5] = 0xA5A5; + mb[6] = 0x5A5A; + mb[7] = 0x2525; + if( !(status = qla2100_mailbox_command(ha, + BIT_7|BIT_6|BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0])) ) { + if( mb[1] != 0xAAAA || mb[2] != 0x5555 || + mb[3] != 0xAA55 || mb[4] != 0x55AA ) + status = 1; + if( mb[5] != 0xA5A5 || mb[6] != 0x5A5A || + mb[7] != 0x2525 ) + status = 1; + if( status ) { + printk(KERN_WARNING "qla2100_chip_diag: [ERROR] *** Failed mailbox register test ***\n\r"); + DEBUG(qla2100_print("qla2100_chip_diag: *** Failed mailbox register test ***\n\r");) + } + } else { + printk(KERN_WARNING "qla2100_chip_diag: [ERROR] failed mailbox send register test\n"); + DEBUG(qla2100_print("qla2100_chip_diag: Failed mailbox send register test\n\r");) + } + } + } else + status = 1; + } else + status = 1; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_chip_diag: **** FAILED ****\n"); + else qla2100_print("qla2100_chip_diag: Returning Good Status \n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_chip_diag"); +#endif + return(status); +} + +/* +* Setup chip +* Load and start RISC firmware. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_setup_chip(scsi_qla_host_t *ha) { + uint16_t cnt; + uint16_t risc_address; + uint16_t *risc_code_address; + long risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint8_t status = 0; + int num, temp; +#ifdef WORD_FW_LOAD + uint16_t *ql21_risc_code_addr01; + uint16_t ql21_risc_code_length01; + uint8_t dump_status; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_setup_chip"); +#endif + + /* Load RISC code. */ + risc_address = *QLBoardTbl_fc[ha->devnum].fwstart; + risc_code_address = QLBoardTbl_fc[ha->devnum].fwcode; + risc_code_size = (long)(*QLBoardTbl_fc[ha->devnum].fwlen & 0xffff); + + DEBUG(printk("qla2100_setup_chip: Loading RISC code size =(0x%lx)\n",risc_code_size);) + DEBUG(qla2100_print("qla2100_setup_chip: Loading RISC code now in silent mode!\n\r");) + num = 0; + DEBUG(sprintf(debug_buff,"virt=%x phys=%x\n\r",ha->request_ring,ha->request_dma);) + DEBUG(qla2100_print(debug_buff);) + /* go into silent mode */ + temp = ql2x_debug_print; + if( ql2x_debug_print ) ql2x_debug_print = 0; + + while( risc_code_size > 0 && !status ) { + /* for 2200A set transfer size to 128 bytes */ + if( ha->device_id == QLA2200A_DEVICE_ID ) + cnt = 128 >> 1; + else + cnt = REQUEST_ENTRY_SIZE * REQUEST_ENTRY_CNT >> 1; + if( cnt > risc_code_size ) + cnt = risc_code_size; + + DEBUG(sprintf(debug_buff,"qla2100_setup_chip:loading risc segment@ addr 0x%x, number of bytes 0x%x, offset 0x%x.\n\r",risc_code_address,cnt,risc_address);) + DEBUG(qla2100_print(debug_buff);) + + BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1)); + + flush_cache_all(); /* flush written firmware to the + ha->request_ring buffer before DMA */ + + mb[0] = MBC_LOAD_RAM; + mb[1] = risc_address; + mb[3] = (uint16_t)(ha->request_dma & 0xffff); + mb[2] = (uint16_t)((ha->request_dma >> 16) & 0xffff); + mb[4] = cnt; + status = qla2100_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + + if( status ) { + qla2100_dump_regs(ha->host); + printk(KERN_WARNING "qla2x00: [ERROR] Failed to load segment %d of FW\n",num); + DEBUG(qla2100_print("qla2100_setup_chip: Failed to load segment of FW\n");) + break; + } + risc_address += cnt; + risc_code_size -= cnt; + risc_code_address += cnt; + num++; + } + ql2x_debug_print = temp; + +#ifdef WORD_FW_LOAD + { + int i; + uint8_t temp; + + temp = ql2x_debug_print; + if( ql2x_debug_print ) ql2x_debug_print = 0; + risc_address = *QLBoardTbl_fc[ha->devnum].fwstart; + ql21_risc_code_addr01 = QLBoardTbl_fc[ha->devnum].fwcode; + ql21_risc_code_length01= (long)(*QLBoardTbl_fc[ha->devnum].fwlen & 0xffff); + + for( i = 0; i < ql21_risc_code_length01 ; i++ ) { + + mb[0] = MBC_WRITE_RAM_WORD; + mb[1] = risc_address + i; + mb[2] = *(ql21_risc_code_addr01 + i); + + dump_status = qla2100_mailbox_command(ha,BIT_2|BIT_1|BIT_0, + &mb[0]); + if( dump_status ) { + printk(KERN_WARNING "qla2x00 : [ERROR] firmware load failure\n"); + break; + } + + mb[0] = MBC_READ_RAM_WORD; + mb[1] = risc_address + i; + mb[2] = 0; + + dump_status = qla2100_mailbox_command(ha,BIT_2|BIT_1|BIT_0, + &mb[0]); + if( dump_status ) { + printk(KERN_WARNING "qla2x00: [ERROR] RISC FW Read Failure\n"); + break; + } + if( mb[2] != *(ql21_risc_code_addr01 + i) ) + printk(KERN_WARNING "qla2x00: [ERROR] RISC FW Compare ERROR @ (0x%p)\n", + (void *) (ql21_risc_code_addr01+i)); + } + ql2x_debug_print = temp; + printk(KERN_INFO "qla2x00: RISC FW download confirmed... \n"); + } +#endif + /* Verify checksum of loaded RISC code. */ + if( !status ) { + DEBUG(printk("qla2100_setup_chip: Verifying Check Sum of loaded RISC code.\n");) + mb[0] = MBC_VERIFY_CHECKSUM; + mb[1] = *QLBoardTbl_fc[ha->devnum].fwstart; + if( !(status = qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0])) ) { + /* Start firmware execution. */ + DEBUG(qla2100_print("qla2100_setup_chip: CS Ok, Start firmware running\n\r");) + mb[0] = MBC_EXECUTE_FIRMWARE; + mb[1]= *QLBoardTbl_fc[ha->devnum].fwstart; + status = qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } +#if defined(QL_DEBUG_LEVEL_2) + else + qla2100_print("qla2100_setup_chip: ISP FW Failed Check Sum\n"); +#endif + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_setup_chip: **** FAILED ****\n"); + else qla2100_print("qla2100_setup_chip: Returning Good Status\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_setup_chip"); +#endif + return(status); +} + +/* +* qla2100_init_rings +* Initializes firmware. +* +* Beginning of request ring has initialization control block +* already built by nvram config routine. +* +* Input: +* ha = adapter block pointer. +* ha->request_ring = request ring virtual address +* ha->response_ring = response ring virtual address +* ha->request_dma = request ring physical address +* ha->response_dma = response ring physical address +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_init_rings(scsi_qla_host_t *ha) { + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int cnt; + device2300_reg_t *reg2300 = ha->iobase2300; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_init_rings"); +#endif + /* Clear outstanding commands array. */ + for( cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) + ha->outstanding_cmds[cnt] = 0; + +#ifdef RSCN + /* Clear RSCN queue. */ + ha->rscn_in_ptr = 0; + ha->rscn_out_ptr = 0; +#endif + + /* Initialize firmware. */ + ha->request_ring_ptr = ha->request_ring; + ha->req_ring_index = 0; + ha->req_q_cnt = REQUEST_ENTRY_CNT; + ha->response_ring_ptr = ha->response_ring; + ha->rsp_ring_index = 0; + mb[0] = MBC_INITIALIZE_FIRMWARE; + mb[3] = LSW(ha->init_cb_dma); + mb[2] = MSW(ha->init_cb_dma); + mb[4] = 0; /* set request queue in ptr for 2100/2200 */ + mb[5] = 0; /* set response queue out ptr for 2100/2200*/ + mb[7] = QL21_64BITS_3RDWD(ha->init_cb_dma); + mb[6] = QL21_64BITS_4THWD(ha->init_cb_dma); + + if (ha->device_id == QLA2300_DEVICE_ID) { + /* set request queue in ptr , response queue out ptr for 2300 */ + WRT_REG_WORD(®2300->req_q_in, 0); + WRT_REG_WORD(®2300->rsp_q_out, 0); + } + + DEBUG(qla2100_print("qla2100_init_rings: Issue MBC_INIT_FIRMWARE op\n");) + status = qla2100_mailbox_command(ha, + BIT_7|BIT_6|BIT_5|BIT_4|BIT_3|BIT_2|BIT_0, + &mb[0]); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_init_rings: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_init_rings"); +#endif + return(status); +} + +/* +* qla2100_fw_ready +* Waits for firmware ready. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_fw_ready(scsi_qla_host_t *ha) { + uint8_t status = 0; + uint32_t cnt, cnt1; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint16_t timeout; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_fw_ready"); +#endif + timeout = (ha->retry_count * ha->login_timeout) + 5; + cnt1 = 0x350; /* 25 secs */ + /* Wait for ISP to finish LIP */ + if(!qla2100_quiet) printk(KERN_INFO "scsi(%d): Waiting for LIP to complete...\n", (int)ha->host->host_no); + if( timeout ) + cnt = 36 * timeout; + else + cnt = 0x700; + + for( ; cnt; cnt-- ) { + mb[0] = MBC_GET_FIRMWARE_STATE; + if( !(status = qla2100_mailbox_command(ha, BIT_0, &mb[0])) ) { + if( ha->loop_down_timer || mb[1] != FSTATE_READY ) { + status = 1; + /* Exit if no cable connected after 10 seconds. */ + if( !cnt1-- ) + if( mb[1] == FSTATE_CONFIG_WAIT || mb[1] == FSTATE_LOSS_OF_SYNC ) { + + break; + } + } else { + DEBUG(printk("qla2100_fw_ready: F/W Ready - OK \n");) + status = 0; /* dg 09/15/99 */ + break; + } + } + + if( ha->flags.online ) { + status = 0; /* dg 09/15/99 */ + break; + } + + /* Delay for a while */ + udelay(10); + +#ifdef QL_DEBUG_LEVEL_2 +/* qla2100_print("qla2100_fw_ready: mailbox_out[1] = "); + qla2100_output_number((uint32_t)mb[1], 16); + qla2100_print("\n");*/ +#endif + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_fw_ready: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_fw_ready"); +#endif + return(status); +} + +/* +* qla2100_configure_hba +* Setup adapter context. +* +* Input: +* ha = adapter state pointer. +* +* Returns: +* 0 = success +* 1 = failed +* +* Context: +* Kernel context. +*/ +STATIC uint8_t +qla2100_configure_hba(scsi_qla_host_t *ha) { + uint8_t rval; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint8_t connect_type[22]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_configure_hba"); +#endif + + /* Get host addresses. */ + mb[0] = MBC_GET_ADAPTER_LOOP_ID; + rval = qla2100_mailbox_command(ha, BIT_0, &mb[0]); + if( !rval ) { + if( mb[6] == 4 ) { + printk(KERN_INFO "scsi%d: Can't get topology - retrying\n",(int)ha->host_no); + return(1); + } + ha->loop_id = mb[1]; + + /* Get loop topology. */ + if( ha->device_id == QLA2100_DEVICE_ID ) { + mb[6] = 0; + } + ha->min_external_loopid = SNS_FIRST_LOOP_ID; + ha->operating_mode = LOOP; + switch( mb[6] ) { + case 0: + ha->current_topology = ISP_CFG_NL; + strcpy((char *)&connect_type[0],"(Loop)"); + break; + case 1: + ha->current_topology = ISP_CFG_FL; + strcpy((char *)&connect_type[0],"(FL_Port)"); + break; + case 2: + ha->operating_mode = P2P; + ha->current_topology = ISP_CFG_N; + ha->min_external_loopid = 1; /* v2.19.5b3 */ + strcpy((char *)&connect_type[0],"(N_Port-to-N_Port)"); + break; + case 3: + ha->operating_mode = P2P; + ha->current_topology = ISP_CFG_F; + ha->min_external_loopid = 1; /* v2.19.5b3 */ + strcpy((char *)&connect_type[0],"(F_Port)"); + break; + default: + ha->current_topology = ISP_CFG_NL; + strcpy((char *)&connect_type[0],"(Loop)"); + break; + } + + /* Save Host port and loop ID. */ + /* Reverse byte order - TT */ + ha->port_id[2] = LSB(mb[2]); + ha->port_id[1] = MSB(mb[2]); + ha->port_id[0] = LSB(mb[3]); + if (!qla2100_quiet) printk(KERN_INFO "scsi%d: Topology - %s, Host Loop address 0x%x\n",(int)ha->host_no,connect_type, ha->loop_id); + } else + printk(KERN_WARNING "qla2100_configure_hba: [ERROR] Get host loop ID failed\n"); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( rval != 0 ) + qla2100_print("qla2100_configure_hba: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_configure_hba"); +#endif + return(rval); +} + +/* +* NVRAM configuration for 2100. +* +* Input: +* ha = adapter block pointer. +* ha->request_ring = request ring virtual address +* ha->response_ring = response ring virtual address +* ha->request_dma = request ring physical address +* ha->response_dma = response ring physical address +* +* Output: +* initialization control block in response_ring +* host adapters parameters in host adapter block +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_nvram_config(scsi_qla_host_t *ha) { + uint8_t status = 0; + uint16_t cnt; + caddr_t dptr1, dptr2; + init_cb_t *icb = ha->init_cb; + nvram21_t *nv = (nvram21_t *)ha->request_ring; + uint16_t *wptr = (uint16_t *)ha->request_ring; + uint8_t chksum = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_nvram_config"); +#endif + + /* Verify valid NVRAM checksum. */ + for( cnt = 0; cnt < sizeof(nvram21_t)/2; cnt++ ) { + *wptr = qla2100_get_nvram_word(ha, cnt); + chksum += (uint8_t)*wptr; + chksum += (uint8_t)(*wptr >> 8); + wptr++; + } + +#if DEBUG_PRINT_NVRAM + qla2100_print( + "qla2100_nvram_config: Contents of NVRAM "); + qla2100_print("\n\r"); + qla2100_dump_buffer((uint8_t *)ha->request_ring, sizeof(nvram21_t)); +#endif + + /* Bad NVRAM data, set defaults parameters. */ + if( chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' || + nv->id[3] != ' ' || nv->nvram_version < 1 ) { + /* Reset NVRAM data. */ + DEBUG(printk("Using defaults for NVRAM: \n")); + DEBUG(printk("checksum=0x%x, Id=%c, version=0x%x\n",chksum,nv->id[0],nv->nvram_version)); + wptr = (uint16_t *)ha->request_ring; + for( cnt = 0; cnt < sizeof(nvram21_t)/2; cnt++ ) + *wptr++ = 0; + + /* + * Set default initialization control block. + */ + nv->parameter_block_version = ICB_VERSION; + nv->firmware_options.enable_fairness = 1; + nv->firmware_options.enable_fast_posting = 1; + nv->firmware_options.enable_full_login_on_lip = 1; + + nv->frame_payload_size = 1024; + nv->max_iocb_allocation = 256; + nv->execution_throttle = 16; + nv->retry_count = 8; + nv->retry_delay = 1; + nv->node_name[0] = 32; + nv->node_name[3] = 224; + nv->node_name[4] = 139; + nv->login_timeout = 4; + + /* + * Set default host adapter parameters + */ + nv->host_p.enable_lip_full_login = 1; + nv->reset_delay = 5; + nv->port_down_retry_count = 8; + nv->maximum_luns_per_target = 8; + status = 1; + } + + /* + * Copy over NVRAM RISC parameter block + * to initialization control block. + */ + dptr1 = (caddr_t)icb; + dptr2 = (caddr_t)&nv->parameter_block_version; + cnt = (caddr_t)&nv->host_p - (caddr_t)&nv->parameter_block_version; + while( cnt-- ) + *dptr1++ = *dptr2++; + + /* HBA node name 0 correction */ + for (cnt=0 ; cnt<8 ; cnt++) { + if (icb->node_name[cnt] != 0) + break; + } + if (cnt == 8) { + for ( cnt= 0 ; cnt < 8 ; cnt++) + icb->node_name[cnt] = icb->port_name[cnt]; + icb->node_name[0] = icb->node_name[0] & ~BIT_0; + icb->port_name[0] = icb->port_name[0] | BIT_0; + } + + /* + * Setup driver firmware options. + */ +#if QL2100_TARGET_MODE_SUPPORT + icb->firmware_options.enable_target_mode = 1; +#else + icb->firmware_options.enable_target_mode = 0; +#endif + icb->firmware_options.disable_initiator_mode = 0; + icb->firmware_options.enable_port_update_event = 1; + icb->firmware_options.enable_full_login_on_lip = 1; + + /* + * Set host adapter parameters + */ + ha->flags.enable_target_mode = icb->firmware_options.enable_target_mode; + ha->flags.disable_luns = nv->host_p.disable_luns; + ha->flags.disable_risc_code_load = nv->host_p.disable_risc_code_load; + ha->flags.set_cache_line_size_1 = nv->host_p.set_cache_line_size_1; + ha->flags.enable_64bit_addressing = nv->host_p.enable_64bit_addressing; + +#if BITS_PER_LONG > 32 + /* Enable 64bit addressing for OS/System combination supporting it */ + /* actual NVRAM bit is: nv->cntr_flags_1.enable_64bit_addressing */ + /* but we will ignore it and use BITS_PER_LONG macro to setup for */ + /* 64 or 32 bit access of host memory in all x86/ia-64/Alpha systems */ + ha->flags.enable_64bit_addressing = 1; +#else + ha->flags.enable_64bit_addressing = 0; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + if (ha->flags.enable_64bit_addressing) + printk(KERN_INFO "[[[ qla2x00: 64 Bit PCI Addressing Enabled ]]]\n"); + +#if BITS_PER_LONG > 32 + /* Update our PCI device dma_mask for full 64 bit mask */ + /* ha->pdev->dma_mask = (pci_dma_t) 0xffffffffffffffffull; */ + ha->pdev->dma_mask = 0xffffffffffffffff; +#endif +#endif + ha->flags.enable_lip_reset = nv->host_p.enable_lip_reset; + ha->flags.enable_lip_full_login = nv->host_p.enable_lip_full_login; + ha->flags.enable_target_reset = nv->host_p.enable_target_reset; + ha->flags.enable_flash_db_update = nv->host_p.enable_database_storage; + + /* new for IOCTL support of APIs */ + ha->node_name[0] = icb->node_name[0]; + ha->node_name[1] = icb->node_name[1]; + ha->node_name[2] = icb->node_name[2]; + ha->node_name[3] = icb->node_name[3]; + ha->node_name[4] = icb->node_name[4]; + ha->node_name[5] = icb->node_name[5]; + ha->node_name[6] = icb->node_name[6]; + ha->node_name[7] = icb->node_name[7]; + ha->nvram_version = nv->nvram_version; + + /* empty data for QLA2100s OEM stuff */ + ha->oem_id = 0; + ha->oem_spare0 = 0; + for ( cnt= 0 ; cnt < 8 ; cnt++) { + ha->oem_string[cnt] = 0; + ha->oem_part[cnt] = 0; + ha->oem_fru[cnt] = 0; + ha->oem_ec[cnt] = 0; + } + + ha->hiwat = icb->iocb_allocation; + ha->execution_throttle = nv->execution_throttle; + + ha->retry_count = nv->retry_count; + ha->login_timeout = nv->login_timeout; + /* Set minimum login_timeout to 4 seconds. */ + if( ha->login_timeout < 4 ) + ha->login_timeout = 4; + ha->port_down_retry_count = nv->port_down_retry_count; + ha->minimum_timeout = (ha->login_timeout * ha->retry_count) + + ha->port_down_retry_count; + ha->loop_reset_delay = nv->reset_delay; + /* Will get the value from nvram. */ + ha->loop_down_timeout = LOOP_DOWN_TIMEOUT; + ha->loop_down_abort_time = LOOP_DOWN_TIME - ha->loop_down_timeout; + + /* save HBA serial number */ + ha->serial0 = nv->node_name[5]; + ha->serial1 = nv->node_name[6]; + ha->serial2 = nv->node_name[7]; + +#if USE_BIOS_MAX_LUNS + if( !nv->maximum_luns_per_target ) + ha->max_luns = MAX_LUNS-1; + else + ha->max_luns = nv->maximum_luns_per_target; +#else + ha->max_luns = MAX_LUNS-1; +#endif + + /* + * Setup ring parameters in initialization control block + */ + icb->request_q_outpointer = 0; + icb->response_q_inpointer = 0; + icb->request_q_length = REQUEST_ENTRY_CNT; + icb->response_q_length = RESPONSE_ENTRY_CNT; + icb->request_q_address[0] = LS_64BITS(ha->request_dma); + icb->request_q_address[1] = MS_64BITS(ha->request_dma); + icb->response_q_address[0] = LS_64BITS(ha->response_dma); + icb->response_q_address[1] = MS_64BITS(ha->response_dma); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_nvram_config: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_nvram_config"); +#endif + return(status); +} + +/* +* NVRAM configuration for the 2200. +* +* Input: +* ha = adapter block pointer. +* ha->request_ring = request ring virtual address +* ha->response_ring = response ring virtual address +* ha->request_dma = request ring physical address +* ha->response_dma = response ring physical address +* +* Output: +* initialization control block in response_ring +* host adapters parameters in host adapter block +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2200_nvram_config(scsi_qla_host_t *ha) { + uint8_t status = 0; + uint16_t cnt; + caddr_t dptr1, dptr2; + init_cb_t *icb = ha->init_cb; + nvram22_t *nv = (nvram22_t *)ha->request_ring; + uint16_t *wptr = (uint16_t *)ha->request_ring; + uint8_t chksum = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2200/2300_nvram_config"); +#endif + + if( !ha->flags.nvram_config_done ) { + + /* Verify valid NVRAM checksum. */ + for( cnt = 0; cnt < sizeof(nvram22_t)/2; cnt++ ) { + *wptr = qla2100_get_nvram_word(ha, cnt); + chksum += (uint8_t)*wptr; + chksum += (uint8_t)(*wptr >> 8); + wptr++; + } + +#if DEBUG_PRINT_NVRAM + qla2100_print( + "qla2200_nvram_config: Contents of NVRAM "); + qla2100_print("\n\r"); + qla2100_dump_buffer((uint8_t *)ha->request_ring, sizeof(nvram22_t)); +#endif + + /* Bad NVRAM data, set defaults parameters. */ + if( chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' || + nv->id[3] != ' ' || nv->nvram_version < 1 ) { + /* Reset NVRAM data. */ + DEBUG(printk("Using defaults for 2200/2300 NVRAM: \n")); + DEBUG(printk("checksum=0x%x, Id0=%c Id1=%c Id2=%x, version=0x%x\n",chksum,nv->id[0],nv->id[1],nv->id[2],nv->nvram_version)); + wptr = (uint16_t *)nv; + for( cnt = 0; cnt < sizeof(nvram21_t)/2; cnt++ ) + *wptr++ = 0; + + /* + * Set default initialization control block. + */ + nv->parameter_block_version = ICB_VERSION; + nv->firmware_options.enable_fairness = 1; + nv->firmware_options.enable_fast_posting = 1; + nv->firmware_options.enable_full_login_on_lip = 1; + nv->firmware_options.enable_name_change = 1; + nv->firmware_options.expanded_ifwcb = 1; + + nv->frame_payload_size = 1024; + nv->max_iocb_allocation = 256; + nv->execution_throttle = 16; + nv->retry_count = 8; + nv->retry_delay = 1; + nv->port_name[0] = 32; + nv->port_name[3] = 224; + nv->port_name[4] = 139; + nv->login_timeout = 4; + nv->additional_firmware_options.connection_options = P2P_LOOP; + /* + * Set default host adapter parameters + */ + nv->host_p.enable_lip_full_login = 1; + nv->reset_delay = 5; + nv->port_down_retry_count = 8; + nv->maximum_luns_per_target = 8; + status = 1; + } + + /* Reset icb data */ + BZERO((caddr_t)icb, sizeof(init_cb_t)); + /* + * Copy over NVRAM RISC parameter block + * to initialization control block. + */ + dptr1 = (caddr_t)icb; + dptr2 = (caddr_t)&nv->parameter_block_version; + cnt = (caddr_t)&nv->additional_firmware_options - (caddr_t)&nv->parameter_block_version; + while( cnt-- ) + *dptr1++ = *dptr2++; + + dptr1 += (caddr_t)&icb->additional_firmware_options - (caddr_t)&icb->request_q_outpointer; + cnt = (caddr_t)&nv->host_p - (caddr_t)&nv->additional_firmware_options; + while( cnt-- ) + *dptr1++ = *dptr2++; + + /* HBA node name 0 correction */ + for (cnt=0 ; cnt<8 ; cnt++) { + if (icb->node_name[cnt] != 0) + break; + } + if (cnt == 8) { + for ( cnt= 0 ; cnt < 8 ; cnt++) + icb->node_name[cnt] = icb->port_name[cnt]; + icb->node_name[0] = icb->node_name[0] & ~BIT_0; + icb->port_name[0] = icb->port_name[0] | BIT_0; + } + + /* + * Setup driver firmware options. + */ + icb->firmware_options.enable_full_duplex = 0; +#if QL2100_TARGET_MODE_SUPPORT + icb->firmware_options.enable_target_mode = 1; +#else + icb->firmware_options.enable_target_mode = 0; +#endif + icb->firmware_options.disable_initiator_mode = 0; + icb->firmware_options.enable_port_update_event = 1; + icb->firmware_options.enable_full_login_on_lip = 1; +#if USE_TP_FW + icb->firmware_options.enable_name_change = 1; + icb->firmware_options.expanded_ifwcb = 1; +#endif + /* + * Set host adapter parameters + */ + ha->flags.enable_target_mode = icb->firmware_options.enable_target_mode; + ha->flags.disable_luns = nv->host_p.disable_luns; + ha->flags.disable_risc_code_load = nv->host_p.disable_risc_code_load; + ha->flags.set_cache_line_size_1 = nv->host_p.set_cache_line_size_1; + ha->flags.enable_64bit_addressing = nv->host_p.enable_64bit_addressing; + +#if BITS_PER_LONG > 32 + /* Enable 64bit addressing for OS/System combination supporting it */ + /* actual NVRAM bit is: nv->cntr_flags_1.enable_64bit_addressing */ + /* but we will ignore it and use BITS_PER_LONG macro to setup for */ + /* 64 or 32 bit access of host memory in all x86/ia-64/Alpha systems */ + ha->flags.enable_64bit_addressing = 1; +#else + ha->flags.enable_64bit_addressing = 0; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + if (ha->flags.enable_64bit_addressing) + printk(KERN_INFO "[[[ qla2x00: 64 Bit PCI Addressing Enabled ]]]\n"); + +#if BITS_PER_LONG > 32 + /* Update our PCI device dma_mask for full 64 bit mask */ + ha->pdev->dma_mask = 0xffffffffffffffff; +#endif +#endif + ha->flags.enable_lip_reset = nv->host_p.enable_lip_reset; + ha->flags.enable_lip_full_login = nv->host_p.enable_lip_full_login; + ha->flags.enable_target_reset = nv->host_p.enable_target_reset; + ha->flags.enable_flash_db_update = nv->host_p.enable_database_storage; + ha->operating_mode = icb->additional_firmware_options.connection_options; + + /* new for IOCTL support of APIs */ + ha->node_name[0] = icb->node_name[0]; + ha->node_name[1] = icb->node_name[1]; + ha->node_name[2] = icb->node_name[2]; + ha->node_name[3] = icb->node_name[3]; + ha->node_name[4] = icb->node_name[4]; + ha->node_name[5] = icb->node_name[5]; + ha->node_name[6] = icb->node_name[6]; + ha->node_name[7] = icb->node_name[7]; + ha->nvram_version = nv->nvram_version; + + + ha->hiwat = icb->iocb_allocation; + ha->execution_throttle = nv->execution_throttle; + + ha->retry_count = nv->retry_count; + ha->login_timeout = nv->login_timeout; + /* Set minimum login_timeout to 4 seconds. */ + if( ha->login_timeout < 4 ) + ha->login_timeout = 4; + ha->port_down_retry_count = nv->port_down_retry_count; + ha->minimum_timeout = (ha->login_timeout * ha->retry_count) + + ha->port_down_retry_count; + ha->loop_reset_delay = nv->reset_delay; + /* Will get the value from nvram. */ + ha->loop_down_timeout = LOOP_DOWN_TIMEOUT; + ha->loop_down_abort_time = LOOP_DOWN_TIME - ha->loop_down_timeout; + + /* save HBA serial number */ + ha->serial0 = nv->port_name[5]; + ha->serial1 = nv->port_name[6]; + ha->serial2 = nv->port_name[7]; + + /* save OEM related items for QLA2200s and QLA2300s */ + ha->oem_id = nv->oem_id; + ha->oem_spare0 = nv->oem_spare0; + + for ( cnt= 2 ; cnt < 8 ; cnt++ ) + ha->oem_string[cnt] = nv->oem_string[cnt]; + + for ( cnt= 0 ; cnt < 8 ; cnt++ ) { + ha->oem_part[cnt] = nv->oem_part[cnt]; + ha->oem_fru[cnt] = nv->oem_fru[cnt]; + ha->oem_ec[cnt] = nv->oem_ec[cnt]; + } + +#ifdef FC_IP_SUPPORT + for (cnt = 0; cnt < 8; cnt++) + ha->acPortName[cnt] = nv->port_name[cnt]; +#endif + +#if USE_BIOS_MAX_LUNS + if( !nv->maximum_luns_per_target ) + ha->max_luns = MAX_LUNS; + else if( nv->maximum_luns_per_target < MAX_LUNS ) + ha->max_luns = nv->maximum_luns_per_target; + else + ha->max_luns = MAX_LUNS; +#else + ha->max_luns = MAX_LUNS; +#endif + + /* + * Setup ring parameters in initialization control block + */ + icb->request_q_outpointer = 0; + icb->response_q_inpointer = 0; + icb->request_q_length = REQUEST_ENTRY_CNT; + icb->response_q_length = RESPONSE_ENTRY_CNT; + icb->request_q_address[0] = LS_64BITS(ha->request_dma); + icb->request_q_address[1] = MS_64BITS(ha->request_dma); + icb->response_q_address[0] = LS_64BITS(ha->response_dma); + icb->response_q_address[1] = MS_64BITS(ha->response_dma); + + icb->lun_enables = 0; + icb->command_resource_count = 0; + icb->immediate_notify_resource_count = 0; + icb->timeout = 0; + icb->reserved_2 = 0; + + ha->flags.nvram_config_done = 1; + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2200_nvram_config: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2200_nvram_config"); +#endif + return(status); +} + +/* +* Get NVRAM data word +* Calculates word position in NVRAM and calls request routine to +* get the word from NVRAM. +* +* Input: +* ha = adapter block pointer. +* address = NVRAM word address. +* +* Returns: +* data word. +*/ +STATIC uint16_t +qla2100_get_nvram_word(scsi_qla_host_t *ha, uint32_t address) { + uint32_t nv_cmd; + uint16_t data; + +#ifdef QL_DEBUG_ROUTINES + uint8_t saved_print_status = ql2x_debug_print; +#endif +#ifdef QL_DEBUG_LEVEL_4 + qla2100_print("qla2100_get_nvram_word: entered\n"); +#endif + + nv_cmd = address << 16; + nv_cmd |= NV_READ_OP; + +#ifdef QL_DEBUG_ROUTINES + ql2x_debug_print = FALSE; +#endif + data = qla2100_nvram_request(ha, nv_cmd); +#ifdef QL_DEBUG_ROUTINES + ql2x_debug_print = saved_print_status; +#endif + +#ifdef QL_DEBUG_LEVEL_4 + qla2100_print("qla2100_get_nvram_word: exiting normally NVRAM data = "); + qla2100_output_number((u_long)data, 16); + qla2100_print("\n"); +#endif + return(data); +} + +/* +* NVRAM request +* Sends read command to NVRAM and gets data from NVRAM. +* +* Input: +* ha = adapter block pointer. +* nv_cmd = Bit 26 = start bit +* Bit 25, 24 = opcode +* Bit 23-16 = address +* Bit 15-0 = write data +* +* Returns: +* data word. +*/ +STATIC uint16_t +qla2100_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd) { + uint8_t cnt; + device_reg_t *reg = ha->iobase; + uint16_t data = 0; + uint16_t reg_data; + + /* Send command to NVRAM. */ + + nv_cmd <<= 5; + for( cnt = 0; cnt < 11; cnt++ ) { + if( nv_cmd & BIT_31 ) + qla2100_nv_write(ha, NV_DATA_OUT); + else + qla2100_nv_write(ha, 0); + nv_cmd <<= 1; + } + + /* Read data from NVRAM. */ + + for( cnt = 0; cnt < 16; cnt++ ) { + WRT_REG_WORD(®->nvram, NV_SELECT+NV_CLOCK); + /* qla2100_nv_delay(ha); */ + NVRAM_DELAY(); + data <<= 1; + reg_data = RD_REG_WORD(®->nvram); + if( reg_data & NV_DATA_IN ) + data |= BIT_0; + WRT_REG_WORD(®->nvram, NV_SELECT); + /* qla2100_nv_delay(ha); */ + NVRAM_DELAY(); + } + + /* Deselect chip. */ + + WRT_REG_WORD(®->nvram, NV_DESELECT); + /* qla2100_nv_delay(ha); */ + NVRAM_DELAY(); + + return(data); +} + +STATIC void +qla2100_nv_write(scsi_qla_host_t *ha, uint16_t data) { + device_reg_t *reg = ha->iobase; + + WRT_REG_WORD(®->nvram, data | NV_SELECT); + NVRAM_DELAY(); + /* qla2100_nv_delay(ha); */ + WRT_REG_WORD(®->nvram, data | NV_SELECT | NV_CLOCK); + /* qla2100_nv_delay(ha); */ + NVRAM_DELAY(); + WRT_REG_WORD(®->nvram, data | NV_SELECT); + /* qla2100_nv_delay(ha); */ + NVRAM_DELAY(); +} + +STATIC void +qla2100_nv_delay(void) { + SYS_DELAY(NV_DELAY_COUNT); +} + + +/* +* Mailbox Command +* Issue mailbox command and waits for completion. +* +* Input: +* ha = adapter block pointer. +* mr = mailbox registers to load. +* mb = data pointer for mailbox registers. +* +* Output: +* mb[MAILBOX_REGISTER_COUNT] = returned mailbox data. +* +* Returns: +* 0 = success +* 1 = failed (mbox status != 0x4000) +*/ +STATIC uint8_t +qla2100_mailbox_command(scsi_qla_host_t *ha, uint32_t mr, uint16_t *mb) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + uint8_t status = 0; + uint32_t cnt; + uint16_t *optr, *iptr; + uint16_t data, command, intreq; + srb_t *done_q_first = 0; + srb_t *done_q_last = 0; + uint32_t longdata = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_mailbox_command"); +#endif + + /* Acquire interrupt specific lock */ + QLA2100_INTR_LOCK(ha); + + DRIVER_LOCK + ha->flags.mbox_busy = TRUE; + +#ifdef QL_DEBUG_LEVEL_5 + sprintf(debug_buff,"scsi%d ",(int)ha->host_no); + qla2100_print(debug_buff); + qla2100_print("qla2100_mailbox_command: [[Start]] mbox_out[0] = "); + qla2100_output_number((u_long)*mb, 16); + qla2100_print("\n"); +#endif + /* Load mailbox registers. */ + if (ha->device_id != QLA2300_DEVICE_ID) + optr = (uint16_t *)®->mailbox0; + else + optr = (uint16_t *)®2300->mailbox0; + +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2100_mailbox_command: Load MB word registers (displayed in bytes) = \n"); + qla2100_dump_buffer((uint8_t *)mb, 16); + qla2100_print("\n"); + qla2100_dump_buffer(((uint8_t *)mb + 0x10), 16); + qla2100_print("\n"); + qla2100_dump_buffer(((uint8_t *)mb + 0x20), 8); + qla2100_print("\n"); + qla2100_print("qla2100_mailbox_command: I/O address = "); + qla2100_output_number((u_long)optr, 16); + qla2100_print("\n"); +#endif + iptr = mb; + command = *(mb); + for( cnt = 0; cnt < MAILBOX_REGISTER_COUNT; cnt++ ) { + if( mr & BIT_0 ) { + WRT_REG_WORD(optr, (*iptr)); + } + mr >>= 1; + optr++; + iptr++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla2100_dump_regs(ha->host); +#endif + + /* Issue set host interrupt command. */ + ha->flags.mbox_int = FALSE; + WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT); + + /* Wait for 30 seconds for command to finish. */ + if (ha->device_id == QLA2300_DEVICE_ID) + data = qla2100_debounce_register((uint16_t *)®2300->host_status); + else data = qla2100_debounce_register(®->istatus); + + cnt = 0x100000*2; /* 22 secs */ + + for( ; cnt > 0 && !ha->flags.mbox_int; cnt-- ) { + /* Check for pending interrupts. */ + if (ha->device_id == QLA2300_DEVICE_ID) { + switch (*mb) { + case MBC_LOAD_RAM: + case MBC_EXECUTE_FIRMWARE: + case MBC_MAILBOX_REGISTER_TEST: + case MBC_VERIFY_CHECKSUM: + case MBC_ABOUT_FIRMWARE: + /* handle ROM commands the old way */ + data = RD_REG_WORD(®->istatus); + intreq = data & RISC_INT; + break; + default: + /* handle non-ROM commands the new way */ + data = RD_REG_WORD(®->istatus); + longdata = RD_REG_DWORD(®2300->host_status); + intreq = longdata & RISC_2300_INT; + break; + } + } else { + /* QLA2100 or QLA2200 */ + data = RD_REG_WORD(®->istatus); + intreq = data & RISC_INT; + } + if ( intreq != 0 ) { + qla2100_isr(ha, + (srb_t **)&done_q_first, + (srb_t **)&done_q_last); + /* udelay(10); */ + } + udelay(10); /* v4.27 */ + } /* for */ + + /* Check for mailbox command timeout. */ + if( !cnt ) { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_mailbox_command: **** MB Command Timeout for cmd = "); + qla2100_output_number((u_long)mb[0], 16); + qla2100_print(" ****\n"); + qla2100_print( + "qla2100_mailbox_command: **** icontrol = "); + qla2100_output_number(RD_REG_WORD(®->ictrl), 16); + qla2100_print(" ****\n"); + qla2100_print( + "qla2100_mailbox_command: **** istatus = "); + qla2100_output_number((u_long)data, 16); + qla2100_print(" ****\n"); + qla2100_print( + "qla2100_mailbox_command: **** chip mailbox[0] = "); + qla2100_output_number((u_long)RD_REG_WORD(optr), 16); + qla2100_print(" ****\n"); + qla2100_dump_regs(ha->host); +#endif + ha->flags.isp_abort_needed = TRUE; + qla2100_stats.mboxtout++; + status = 1; + } else if( ha->mailbox_out[0] != MBS_CMD_CMP ) { + qla2100_stats.mboxerr++; + status = 1; + } + + /* Load return mailbox registers. */ + optr = mb; + iptr = (uint16_t *)&ha->mailbox_out[0]; + + mr = MAILBOX_REGISTER_COUNT; + while( mr-- ) + *optr++ = *iptr++; + + /* Go check for any response interrupts pending. */ + ha->flags.mbox_busy = FALSE; + + qla2100_isr(ha,(srb_t **)&done_q_first,(srb_t **)&done_q_last); + + /* Release interrupt specific lock */ + QLA2100_INTR_UNLOCK(ha); + DRIVER_UNLOCK + + if( ha->flags.isp_abort_needed ) + qla2100_abort_isp(ha); + + if( ha->flags.reset_marker ) + qla2100_rst_aen(ha); + if( ha->flags.update_config_needed ) + qla2100_update_config(ha); + if( ha->flags.loop_resync_needed ) + qla2100_loop_resync(ha); + + if( done_q_first ) + qla2100_done(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) { + qla2100_print("qla2100_mailbox_command: **** FAILED, mailbox0 = "); + qla2100_output_number((u_long)mb[0], 16); + qla2100_print(" ****\n"); + } else { +/* DEBUG(qla2100_print("qla2100_mbc: Completed OK operation=");) +DEBUG(qla2100_output_number((u_long)command, 16);) +DEBUG(qla2100_print(" \n");) +DEBUG(qla2100_print("qla2100_mbc: mailbox[1]=");) +DEBUG(qla2100_output_number((u_long)mb[1], 16);) +DEBUG(qla2100_print(" \n");) +DEBUG(qla2100_print("mbc: +++ rsp_q_in= ");) +DEBUG(qla2100_output_number(RD_REG_WORD(&ha->iobase2300->rsp_q_in), 16);) +DEBUG(qla2100_print(" +++ \n");) +DEBUG(qla2100_print("mbc: +++ rsp_q_out= ");) +DEBUG(qla2100_output_number(RD_REG_WORD(&ha->iobase2300->rsp_q_out), 16);) +DEBUG(qla2100_print(" +++ \n\n");) +DEBUG(printk("qla2100_mbc: Completed OK operation=%x\n\n",command);) */ + } +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_mailbox_command"); +#endif + return(status); +} + + + /* + * qla2100_poll + * Polls ISP for interrupts. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla2100_poll(scsi_qla_host_t *ha) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + uint16_t data; + srb_t *done_q_first = 0; + srb_t *done_q_last = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_poll"); +#endif + + /* Acquire interrupt specific lock */ + QLA2100_INTR_LOCK(ha); + + /* Check for pending interrupts. */ + if (ha->device_id == QLA2300_DEVICE_ID) + data = qla2100_debounce_register((uint16_t *)®2300->host_status) & + RISC_2300_INT; + else data = qla2100_debounce_register(®->istatus) & + RISC_INT; + + /* Check for pending interrupts. */ + if( data ) { + DEBUG(qla2100_print("qla2100_poll: Calling isr\n");) + qla2100_isr(ha, + (srb_t **)&done_q_first, + (srb_t **)&done_q_last); + } + + /* Release interrupt specific lock */ + QLA2100_INTR_UNLOCK(ha); + + if( !ha->flags.mbox_busy ) { + if( ha->flags.isp_abort_needed ) + qla2100_abort_isp(ha); + if( ha->flags.reset_marker ) + qla2100_rst_aen(ha); + if( ha->flags.update_config_needed ) + qla2100_update_config(ha); + if( ha->flags.loop_resync_needed ) + qla2100_loop_resync(ha); + } + + if( done_q_first ) + qla2100_done(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_poll"); +#endif +} + +/* +* qla2100_find_host +* This routine searches the host adapter database +* and return either TRUE or FALSE. +* +* Input: +* ha = adapter block pointer. +* device = device data pointer. +* +* Returns: +* TRUE - found +*/ +STATIC uint8_t +qla2100_find_host(scsi_qla_host_t *ha, device_data_t *device) { + fcdev_t *pdb; + uint16_t cnt; + + pdb = ha->phost_db; + for (cnt = 0; cnt < ha->host_db_ptr; cnt++) { + /* if nodename/portname in database */ +#if USE_PORTNAME + if (BCMP(device->wwn, pdb[cnt].name, 8) == 0) { +#else + if (BCMP(device->name, pdb[cnt].name, 8) == 0) { +#endif + return TRUE; + } + } + return FALSE; +} + +/* +* qla2100_update_host_data +* This routine updates the host device database +* +* Input: +* ha = adapter block pointer. +* device = device data pointer. +* +* Returns: +* 0 = success, if device found or added to database. +* 1 = error +* 2 = database was full and device was not configured. +*/ +STATIC uint8_t +qla2100_update_host_data(scsi_qla_host_t *ha, device_data_t *device, + uint8_t enable_slot_reuse) +{ + fcdev_t *pdb; + uint8_t status = 0; + uint8_t index; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_update_host"); +#endif + + pdb = ha->phost_db; + index = ha->host_db_ptr; + if (index != MAX_HOST_COUNT) { + index++; +#if USE_PORTNAME + BCOPY(device->wwn, pdb[index].name, 8); +#else + BCOPY(device->name, pdb[index].name, 8); +#endif + } else if ( enable_slot_reuse ) { + index = 0; + printk(KERN_INFO "qla2100_update_host: Host table Full." + " Overwriting slot 0."); +#if USE_PORTNAME + BCOPY(device->wwn, pdb[index].name, 8); +#else + BCOPY(device->name, pdb[index].name, 8); +#endif + } else { + printk(KERN_INFO "qla2100_update_host: Host table Full."); + status = 2; + } + ha->host_db_ptr = index; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_update_host: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_update_host"); +#endif + return(status); + +} + +/* +* qla2100_update_device_data +* This routine updates the device data in the database and logs +* onto the device if necessary. +* +* Input: +* ha = adapter block pointer. +* device = device data pointer. +* +* Returns: +* 0 = success, if device found or added to database. +* 1 = error +* 2 = database was full and device was not configured. +*/ +STATIC uint8_t +qla2100_update_device_data(scsi_qla_host_t *ha, device_data_t *device, uint8_t enable_slot_reuse) { + uint8_t status = 0; + uint8_t hostflag = 0; + uint8_t dev_configured; + uint16_t cnt, i; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_update_device"); +#endif + + dev_configured = FALSE; + if( ha->device_id == QLA2100_DEVICE_ID ) { + ha->min_external_loopid = 1; /* v2.19.5b3 */ + ha->max_public_loop_ids = LAST_SNS_LOOP_ID - SNS_FIRST_LOOP_ID + 1; + } else { + ha->max_public_loop_ids = LAST_SNS_LOOP_ID + 1; + } + + DEBUG(sprintf(debug_buff, + "qla2100: Found device - portname=%02x%02x%02x%02x%02x%02x%02x%02x," + " nodename=%02x%02x%02x%02x%02x%02x%02x%02x," + " port Id=%06lx, loop id=%04x\n", + device->wwn[0], device->wwn[1], + device->wwn[2], device->wwn[3], + device->wwn[4], device->wwn[5], + device->wwn[6], device->wwn[7], + device->name[0], device->name[1], + device->name[2], device->name[3], + device->name[4], device->name[5], + device->name[6], device->name[7], + device->port_id[0] << 16 | device->port_id[1] << 8 | device->port_id[2], device->loop_id);) + DEBUG(qla2100_print(debug_buff);) + + /* if we already login to the host adapter then skip it */ + if ( qla2100_find_host(ha, device) ) { + DEBUG(printk("update_db: Skipping host adapter..\n");) + return( status ); + } + + /* Search to see if node name is already in database. If found then change loop ID in database. */ + for( cnt = 0; cnt < MAX_FIBRE_DEVICES && !dev_configured; cnt++ ) { + /* if nodename/portname in database then replace it */ +#if USE_PORTNAME /* updated for ioctl merge */ + if (BCMP(device->wwn, ha->fc_db[cnt].wwn, 8) == 0) { +#else + if (BCMP(device->name, ha->fc_db[cnt].name, 8) == 0) { +#endif + ha->fc_db[cnt].flag &= ~DEV_MISSING; + /* if device was configured by user then find and assign a loop ID for it */ + if( ha->fc_db[cnt].loop_id == PORT_AVAILABLE ) { + DEBUG(qla2100_print("Port marked as already assigned.\n");) + /* If device found is on the public loop. */ + /* then find the next available fabric loop ID */ + if( device->loop_id == 0xffff ) { + status = 1; + /* Search the public database for first available slot. */ + for( i = ha->min_external_loopid; i < ha->max_public_loop_ids; i++ ) { + if( !ha->fabricid[i].in_use ) { + ha->fabricid[i].in_use = TRUE; + if( ha->device_id == QLA2100_DEVICE_ID ) + device->loop_id = SNS_FIRST_LOOP_ID + i; + else + device->loop_id = i; + ha->fc_db[cnt].loop_id = device->loop_id; + ha->fc_db[cnt].port_id[0] = device->port_id[0]; + ha->fc_db[cnt].port_id[1] = device->port_id[1]; + ha->fc_db[cnt].port_id[2] = device->port_id[2]; + ha->fc_db[cnt].flag |= DEV_PUBLIC; + status = 0; + break; + } + } /* end of for */ + } else { /* change the local loop ID in database */ + ha->fc_db[cnt].loop_id = device->loop_id; + } + } else /* loop id may have been previously used */ + { + /* If device is on public loop. */ + if( device->loop_id == 0xffff ) { + /* It was previously public, so use previously assigned loop id. */ + if( ha->fc_db[cnt].flag & DEV_PUBLIC ) + if( ha->device_id == QLA2100_DEVICE_ID ) + device->loop_id = ha->fc_db[cnt].loop_id; + else { + /* if the same topology and public loop */ + /* search for the next avaiable public loop ID */ + DEBUG(printk("update_db: topology prev %d, curr %d\n", + ha->prev_topology, ha->current_topology );) + if( ha->prev_topology == ha->current_topology ) { + if( (ha->min_external_loopid) && + (ha->fc_db[cnt].loop_id < ha->min_external_loopid) ) { + status = 1; + /* find a loop ID for the Public device */ + for( i = ha->min_external_loopid; i < ha->max_public_loop_ids; i++ ) + if( !ha->fabricid[i].in_use ) { + ha->fabricid[i].in_use = TRUE; + device->loop_id = i; + ha->fc_db[cnt].loop_id = device->loop_id; + status = 0; + break; + } + } else + device->loop_id = ha->fc_db[cnt].loop_id; + } else { + status = 1; + /* Find an unused loop ID */ + for( i = ha->min_external_loopid; i < ha->max_public_loop_ids; i++ ) + if( !ha->fabricid[i].in_use ) { + ha->fabricid[i].in_use = TRUE; + device->loop_id = i; + ha->fc_db[cnt].loop_id = device->loop_id; + status = 0; + break; + } + } + + } else { + /* If it moved from private to public loop, assign new public loop id. */ + status = 1; + /* Find an unused loop ID */ + for( i = ha->min_external_loopid; i < ha->max_public_loop_ids; i++ ) + if( !ha->fabricid[i].in_use ) { + ha->fabricid[i].in_use = TRUE; + if( ha->device_id == QLA2100_DEVICE_ID ) + + device->loop_id = SNS_FIRST_LOOP_ID + i; + else + device->loop_id = i; + ha->fc_db[cnt].loop_id = device->loop_id; + ha->fc_db[cnt].flag |= DEV_PUBLIC; + ha->fc_db[cnt].port_id[0] = device->port_id[0]; + ha->fc_db[cnt].port_id[1] = device->port_id[1]; + ha->fc_db[cnt].port_id[2] = device->port_id[2]; + status = 0; + break; + } + } + } else { + /* The found device is on private loop but was + previously on public loop, so free public loop id. */ + if( ha->fc_db[cnt].flag & DEV_PUBLIC ) { + ha->fc_db[cnt].flag &= ~DEV_PUBLIC; + i = ha->fc_db[cnt].loop_id - SNS_FIRST_LOOP_ID; + ha->fabricid[i].in_use = 0; + } + ha->fc_db[cnt].loop_id = device->loop_id; + } + } + + /* If public device in database */ + if( !status && (ha->fc_db[cnt].flag) & DEV_PUBLIC ) { + + + /* If public loop device, compare port id to see if + device moves to another NL/N port. */ + if( ha->fc_db[cnt].port_id[0] != device->port_id[0] || + ha->fc_db[cnt].port_id[1] != device->port_id[1] || + ha->fc_db[cnt].port_id[2] != device->port_id[2] ) { + if( ha->prev_topology == ha->current_topology ) { + /* Port id changed, log device out then log back + in with new port id but same loop id. */ + mb[0] = MBC_LOGOUT_FABRIC_PORT; + mb[1] = ha->fc_db[cnt].loop_id << 8; + qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + ha->fc_db[cnt].port_id[0] = device->port_id[0]; + ha->fc_db[cnt].port_id[1] = device->port_id[1]; + ha->fc_db[cnt].port_id[2] = device->port_id[2]; + } + } + /* + * Try and find a loop Id for the given + * fabric port. We keep trying Ids until we find + * a good one. + */ + mb[0] = 0x4008; + while( !status && mb[0] == 0x4008 ) { + DEBUG(printk("update_db: Trying Fabric Login @ loop id= %d, port id= %06x\n", device->loop_id,device->port_id);) + mb[0] = MBC_LOGIN_FABRIC_PORT; + mb[1] = device->loop_id << 8 | 0x01; + mb[2] = device->port_id[0]; + mb[3] = device->port_id[1] << 8 | device->port_id[2]; + qla2100_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + /* Command parameter error or all IDS used */ + if ( mb[0] == 0x4006 || mb[0] == 0x4009 ) { + status = 1; + DEBUG(printk("update_db: (1) Failed Fabric login with Loop ID = %d\n", device->loop_id);) + } + /* + * if loop Id is in use then try the next Id . + */ + if( mb[0] == 0x4008 ) { + DEBUG(printk("update_db: Used Loop ID = %04x, port id=%06x - trying next id\n", device->loop_id, + ((mb[1] << 16) | (((mb[2] >>8 ) &0xff) << 8) | (mb[2] & 0xff)));) + if( device->loop_id++ <= LAST_SNS_LOOP_ID ) + ha->fabricid[device->loop_id].in_use = TRUE; + else + status = 1; + } + } + /* Login succuessful */ + if( !status ) { + /* if different host */ + if( (mb[1] & 0x1) ) { /* v2.19.05b3 */ + DEBUG(printk("update_db: Warning -- Adapter found: port id=%06x, tgt=%d\n", + ((mb[1] << 16) | (((mb[2] >>8 ) &0xff) << 8) | (mb[2] & 0xff)),cnt);) + qla2100_update_host_data(ha, device, enable_slot_reuse); + ha->fabricid[device->loop_id].in_use = FALSE; + hostflag++; + } else { + /* 4.31.8 update loop id in database */ + ha->fc_db[cnt].loop_id = device->loop_id; + } + } +#if 0 + /* Command error */ + if( !status && mb[0] != 0x4005 ) { + /* Issue Abort target command to cause RISC to + flush all commands outstanding for this device. + Commands will be returned with "Aborted" status. */ + mb[0] = MBC_ABORT_TARGET; + mb[1] = device->loop_id << 8; + mb[2] = 1; + status = qla2100_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + } +#endif + } + dev_configured = TRUE; + } + } + + /* Device not already in database so find */ + /* an empty slot and loop id for it. */ + if( !dev_configured ) { + DEBUG(printk("qla2100_db_update: New Device - not in database.\n");) + + /* If device is on public loop. */ + /* First find an unused Fabric loop ID */ + /* then find a slot. */ + if( device->loop_id == 0xffff ) { + status = 1; + for( i = ha->min_external_loopid; i < ha->max_public_loop_ids; i++ ) { + if( !ha->fabricid[i].in_use ) { + ha->fabricid[i].in_use = TRUE; + if( ha->device_id == QLA2100_DEVICE_ID ) + device->loop_id = SNS_FIRST_LOOP_ID + i; + else + device->loop_id = i; + status = 0; + break; + } + } + /* Preset status to Loop ID used */ + mb[0] = 0x4008; + /* Check to insure loop ID for fabric device is good */ + while( !status && mb[0] == 0x4008 ) { + DEBUG(printk("update_db: Trying Fabric Login @ loop id %d\n", device->loop_id);) + mb[0] = MBC_LOGIN_FABRIC_PORT; + mb[1] = device->loop_id << 8 | 0x01; + mb[2] = device->port_id[0]; + mb[3] = device->port_id[1] << 8 | device->port_id[2]; + qla2100_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]); + if ( mb[0] == 0x4006 || mb[0] == 0x4009 ) { + status = 1; + DEBUG(printk("update_db: (2) Failed Fabric login with Loop ID = %d\n", device->loop_id);) + } + if( mb[0] == 0x4008 ) { + DEBUG(printk("update_db: (2) Used Fabric Loop ID = %04x, port id=%06x\n", device->loop_id, + ((mb[1] << 16) | (((mb[2] >>8 ) &0xff) << 8) | (mb[2] & 0xff)));) + if( device->loop_id++ <= LAST_SNS_LOOP_ID ) + ha->fabricid[device->loop_id].in_use = TRUE; /* v2.19.05b3 */ + else + status = 1; + } + if( (mb[1] & 0x1) ) { /* v2.19.05b3 */ + qla2100_update_host_data(ha, device, enable_slot_reuse); + DEBUG(printk("update_db: Adapter found: port id=%06x\n", + (device->port_id[0] <<16) | + (device->port_id[1] << 8) | (device->port_id[2])) ); + ha->fabricid[device->loop_id].in_use = FALSE; + hostflag++; + } + } + } + /* Now find an empty slot for the device */ + if( !status && hostflag == 0 ) { + if( ha->device_id == QLA2100_DEVICE_ID ) + ha->min_external_loopid = SNS_FIRST_LOOP_ID; + /* Find a empty slot and add device into database. */ + for( i = 0; i < MAX_FIBRE_DEVICES; i++ ) + if( ha->fc_db[i].loop_id == PORT_UNUSED ) { + ha->fc_db[i].flag &= ~DEV_MISSING; + + /* get and set both wwnn and wwpn */ + BCOPY(device->name, ha->fc_db[i].name, 8); + BCOPY(device->wwn, ha->fc_db[i].wwn, 8); + + ha->fc_db[i].loop_id = device->loop_id; + if( device->loop_id >= ha->min_external_loopid ) { + ha->fc_db[i].flag |= DEV_PUBLIC; + ha->fc_db[i].port_id[0] = device->port_id[0]; + ha->fc_db[i].port_id[1] = device->port_id[1]; + ha->fc_db[i].port_id[2] = device->port_id[2]; + } + ha->flags.updated_fc_db = TRUE; + dev_configured = TRUE; + break; + } + if( !dev_configured ) { + if( enable_slot_reuse ) { + for( i = 0; i < MAX_FIBRE_DEVICES; i++ ) + if( ha->fc_db[i].loop_id == PORT_AVAILABLE ) { + ha->fc_db[i].flag &= ~DEV_MISSING; +#if USE_PORTNAME /* ioctl support change */ + BCOPY(device->wwn, ha->fc_db[i].wwn, 8); +#else + BCOPY(device->name, ha->fc_db[i].name, 8); +#endif + ha->fc_db[i].loop_id = device->loop_id; + if( device->loop_id >= ha->min_external_loopid ) { + ha->fc_db[i].flag |= DEV_PUBLIC; + ha->fc_db[i].port_id[0] = device->port_id[0]; + ha->fc_db[i].port_id[1] = device->port_id[1]; + ha->fc_db[i].port_id[2] = device->port_id[2]; + } + ha->flags.updated_fc_db = TRUE; + break; + } + } else { + ha->fabricid[device->loop_id].in_use = FALSE; + status = 2; + } + + } + + } + } +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_update_device: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_update_device"); +#endif + return(status); + } + +/* +* qla2100_sns_device +* Setup Simple Name Server devices with loop ID's. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +* 1 = error +* 2 = database was full and device was not configured. +*/ +STATIC uint8_t +qla2100_sns_device(scsi_qla_host_t *ha, uint8_t enable_slot_reuse) { + uint8_t status = 1; + uint8_t first_port_id[3]; + uint8_t next_port_id[3]; + uint8_t host_port_id[3]; + sns_data_t *sns; +#if BITS_PER_LONG > 32 + uint64_t phys_address = 0; +#else + uint32_t phys_address = 0; +#endif + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint8_t use_gan = 1; + uint8_t retry_count = 0; + gp_idnn_t *gp_idnn; + uint16_t i; + device_data_t device; + uint8_t db_full = 0; + uint16_t public_count; + uint32_t fabric_devices = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_sns_device"); +#endif + + /* If FL port exists, then SNS is present */ + DEBUG(printk("qla2100_sns_device: Checking for Fabric.\n");) + mb[0] = MBC_GET_PORT_NAME; + mb[1] = SNS_FL_PORT << 8; /* port name */ + if( !qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]) ) { + +#ifdef RCSN + /* Mark devices that need re-synchronization. */ + qla2100_device_resync(ha); +#endif + + /* Fl port is present */ + host_port_id[0] = ha->port_id[0]; + host_port_id[1] = ha->port_id[1]; + host_port_id[2] = ha->port_id[2]; + + /* Calculate the max number of public ports */ + if( ha->device_id == QLA2100_DEVICE_ID ) + public_count = ha->max_public_loop_ids; + else + public_count = ha->max_public_loop_ids - ha->min_external_loopid; + + /* Register with name server as type fc4 device */ + +#ifdef FC_IP_SUPPORT + /* Register with name server as type 5 device */ + if (ha->flags.enable_ip == TRUE) { + qla2x00_register_ip_device(ha); + } + + /* If IP enable, skip GP_IDNN and just use GAN */ + if (ha->flags.enable_ip == TRUE) + goto tryGan; +#endif /* FC_IP_SUPPORT */ + + /* Find out if this is a Brocade switch, if so do GP_IDNN. */ + /* otherwise use the GAN */ + mb[0] = MBC_GET_PORT_NAME; + mb[1] = SNS_FL_PORT << 8 | BIT_0; /* node name */ + qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + if( mb[2] == 0x0010 && mb[3] == 0x6000 && + (mb[6] & 0x00FF) == 0x0069 ) { +/* 4.10 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + gp_idnn = KMALLOC(GP_IDNN_LENGTH); + if ( gp_idnn != NULL ) { + phys_address = VIRT_TO_BUS(gp_idnn); + BZERO((caddr_t)gp_idnn, GP_IDNN_LENGTH); + } +#else + gp_idnn = pci_alloc_consistent(ha->pdev, + GP_IDNN_LENGTH, + &phys_address); + BZERO((caddr_t)gp_idnn, GP_IDNN_LENGTH); +#endif + if ( gp_idnn != NULL ) { + /* Retry GP_IDNN til valid list or retries done */ + while( retry_count++ < 10 ) { + /* + * Issue GP_IDNN to get list of port IDs and + * node names from name server. + */ + gp_idnn->req.buffer_length = GP_IDNN_LENGTH/2; + /* 4.10 */ + gp_idnn->req.buffer_address[0] = + LS_64BITS(phys_address); + gp_idnn->req.buffer_address[1] = + MS_64BITS(phys_address); + gp_idnn->req.subcommand_length = 6; + gp_idnn->req.subcommand = 0x173; + gp_idnn->req.length = GP_IDNN_LENGTH / 4; + gp_idnn->req.protocol = 0x08; + + mb[0] = MBC_SEND_SNS_COMMAND; + mb[1] = 14; + mb[3] = LSW(phys_address); + mb[2] = MSW(phys_address); + mb[7] = QL21_64BITS_3RDWD(phys_address); + mb[6] = QL21_64BITS_4THWD(phys_address); + if( !qla2100_mailbox_command(ha, + BIT_7|BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]) ) { + if( gp_idnn->rsp.response == SNS_ACCEPT ) { + DEBUG3(printk("Sns: Get all Fabric devices:\n");) + /* Go down device list and add devices to database. */ + for( i = 0; i < public_count; i++ ) { + /* if not host port id then add it to the database */ + if( gp_idnn->rsp.port_data[i].port_id[0] != host_port_id[0] || + gp_idnn->rsp.port_data[i].port_id[1] != host_port_id[1] || + gp_idnn->rsp.port_data[i].port_id[2] != host_port_id[2] ) { + BCOPY(gp_idnn->rsp.port_data[i].nodename, device.name, 8); + /* get loop id */ + device.port_id[0] = gp_idnn->rsp.port_data[i].port_id[0]; + device.port_id[1] = gp_idnn->rsp.port_data[i].port_id[1]; + device.port_id[2] = gp_idnn->rsp.port_data[i].port_id[2]; +#if USE_PORTNAME + /* Get portname */ + if( qla2100_sns_get_name(ha, &device, 0) ) { + status = 1; /* v2.19.5b4 */ + break; + } +#endif + device.loop_id = 0xffff; + /* Update device database and login to device. */ + fabric_devices++; + if( (status = qla2100_update_device_data(ha, &device, enable_slot_reuse)) ) { + if( status == 2 ) + db_full = 1; + else + break; + } + } + if( gp_idnn->rsp.port_data[i].controlbyte == 0x80 ) + break; + } + use_gan = 0; + break; + } + } + /* Wait for 100ms before retrying */ + for( i = 0; i <= 10000; i++ ) { + udelay(10); + } + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(gp_idnn, GP_IDNN_LENGTH); +#else + pci_free_consistent(ha->pdev, GP_IDNN_LENGTH, + gp_idnn, phys_address); +#endif + } else { + use_gan = 0; +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_sns_device: Failed to allocate memory, No FL Port\n"); +#endif + } + } + /* Use the GAN (GA_NXT) Name server request to discover the ports */ + + /* + * Go through GAN list to find all fabric devices. Will perform + * necessary logout of previously existed devices that have changed + * and save new devices in a new device list. + * + */ + + if( use_gan ) { +#ifdef FC_IP_SUPPORT + tryGan: +#endif + + /* Find all registered ports in the Fabric */ +/* 4.10 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + sns = KMALLOC(sizeof(sns_data_t)); + if ( sns != NULL ) { + phys_address = VIRT_TO_BUS(sns); + BZERO((caddr_t)sns, sizeof(sns_data_t)); + } +#else + sns = pci_alloc_consistent(ha->pdev, + sizeof(sns_data_t), + &phys_address); + BZERO((caddr_t)sns, sizeof(sns_data_t)); +#endif + if ( sns != NULL ) { + DEBUG(printk("qla2100_sns_device: Performing a GAN (%d)\n",public_count);) + status = 0; + /* start with port ID = 0 */ + first_port_id[0] = first_port_id[1] = first_port_id[2] = 0; + next_port_id[0] = next_port_id[1] = next_port_id[2] = 0; + mb[0] = 0; + for( i = 0; i < public_count && !ha->loop_down_timer && + !ha->flags.loop_resync_needed; i++ ) { + /* GAN Get all next entries for the selected port ID from SNS. */ + BZERO((caddr_t)sns, sizeof(sns_data_t)); + sns->p.req.hdr.buffer_length = 318; /*304*/ + sns->p.req.hdr.buffer_address[0] = + LS_64BITS(phys_address); + sns->p.req.hdr.buffer_address[1] = + MS_64BITS(phys_address); + sns->p.req.hdr.subcommand_length = 6; + sns->p.req.subcommand = 0x100; + sns->p.req.param[6] = next_port_id[2]; + sns->p.req.param[7] = next_port_id[1]; + sns->p.req.param[8] = next_port_id[0]; + + mb[0] = MBC_SEND_SNS_COMMAND; + mb[1] = 14; + mb[3] = LSW(phys_address); + mb[2] = MSW(phys_address); + mb[7] = QL21_64BITS_3RDWD(phys_address); + mb[6] = QL21_64BITS_4THWD(phys_address); + if( !qla2100_mailbox_command(ha, + BIT_7|BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]) ) { + if( sns->p.rsp[8] != 0x80 || /* SNS_ACCEPT */ + sns->p.rsp[9] != 0x02 ) { /* 04/18/00 */ + printk(KERN_INFO "qla2100_sns_device: SEND_SNS_COMMAND Failed - 0x%2x%2x mb_res=%x\n", + sns->p.rsp[8],sns->p.rsp[9],mb[0]); + status = 1; + break; + } + /* save next port ID */ + next_port_id[0] = sns->p.rsp[17]; + next_port_id[1] = sns->p.rsp[18]; + next_port_id[2] = sns->p.rsp[19]; + + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_sns_device: MBC_SEND_SNS_COMMAND Failed, No FL Port\n"); +#endif + /* v2.19.5 */ + DEBUG(printk("qla2100_sns_device: Failed Performing a GAN mb0=0x%x, mb1=0x%x\n", + mb[0],mb[1]);) + status = 1; + break; + } + + /* Assign loop ID for device on SNS. */ + if( (next_port_id[0] != first_port_id[0] || + next_port_id[1] != first_port_id[1] || + next_port_id[2] != first_port_id[2]) + && (sns->p.rsp[284] || sns->p.rsp[285] || + sns->p.rsp[286] || sns->p.rsp[287] || + sns->p.rsp[288] || sns->p.rsp[289] || + sns->p.rsp[290] || sns->p.rsp[291]) ) { + /* if port Id local loop skip this ID */ + if( next_port_id[0] != host_port_id[0] || + next_port_id[1] != host_port_id[1] || + next_port_id[2] != host_port_id[2] ) { +#if USE_PORTNAME + /* Extract portname */ + BCOPY(&sns->p.rsp[20], device.wwn, 8); +#endif + /* Extract nodename */ + BCOPY(&sns->p.rsp[284], device.name, 8); + /* extract port ID */ + device.port_id[0] = next_port_id[0]; + device.port_id[1] = next_port_id[1]; + device.port_id[2] = next_port_id[2]; + device.loop_id = 0xffff; + + /* Update device database and login device in */ + + /* if McData, skip all port types except 1 (N_port) & 2 (NL_port) */ + if ( !( (sns->p.rsp[16] == 0x01) || + (sns->p.rsp[16] == 0x02) ) ) { + DEBUG(printk("qla2100_sns_device: Skipping port type %x\n", sns->p.rsp[16]);) + } + +#ifdef FC_IP_SUPPORT + else if (sns->p.rsp[579] & 0x20) { + fabric_devices++; + /* Update IP device */ + if (qla2x00_update_ip_device_data(ha, &device) == QL_STATUS_FATAL_ERROR) { + status = 1; + break; + } + /* Update SCSI device */ + } +#endif + else { + fabric_devices++; + if( (status = qla2100_update_device_data(ha, &device, enable_slot_reuse)) ) { + if( status == 2 ) + db_full = 1; + break; + } + } +#ifdef FC_IP_SUPPORT + } +#endif + } + + /* + * Save first port if not repeating port + * on another Loop ID. + */ + if( !(first_port_id[0] || first_port_id[1] || + first_port_id[2]) ) { + first_port_id[0] = next_port_id[0]; + first_port_id[1] = next_port_id[1]; + first_port_id[2] = next_port_id[2]; + } + } else + break; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(sns, sizeof(sns_data_t)); +#else + pci_free_consistent(ha->pdev, sizeof(sns_data_t), + sns, phys_address); +#endif + + } +#ifdef QL_DEBUG_LEVEL_2 + else + qla2100_print( + "qla2100_sns_device: Failed to allocate memory, No FL Port\n"); +#endif + } + } else +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_sns_device: MBC_GET_PORT_NAME Failed, No FL Port\n"); +#else + DEBUG(printk("No Fabric found.\n");) +#endif + + if( fabric_devices > 0) + ha->device_flags |= DFLG_FABRIC_DEVICES; + + if( db_full ) + status = 2; + + /* Update iff F/FL found and update O.K. */ + if( !status ) + ha->prev_topology = ha->current_topology; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_sns_device: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_sns_device"); +#endif + return(status); +} + +#if USE_PORTNAME +/* +* qla2100_sns_get_name +* This routine is called tot do the SNS Get Port/Name command +* of the specified port. +* +* Input: +* ha = adapter block pointer. +* flag = 0 - port name , 1 - node name +* +* Output: +* +*/ +STATIC uint8_t qla2100_sns_get_name( scsi_qla_host_t *ha, device_data_t *device, uint8_t flag ) { + uint8_t lStatus = 0; + uint16_t wRetryCount; +#if BITS_PER_LONG > 32 + uint64_t phys_address = 0; +#else + uint32_t phys_address = 0; +#endif + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint16_t subCmd, response; + sns_data_t *sns; + + /* Set retry count */ + if ( flag ) + subCmd = 0x113; + else + subCmd = 0x112; + DEBUG2(printk("qla2100_SnsGetName: Get opcode %x - name for port Id %06x\n", subCmd, + (uint32_t)(device->port_id[0] << 16 | device->port_id[1] << 8 | device->port_id[2]));) + + wRetryCount = 2; + while (wRetryCount--) { + /* Do 'Get Port/Node name' mailbox command for the FL attached device */ +/* 4.10 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + sns = KMALLOC(sizeof(sns_data_t)); + if ( sns != NULL ) { + phys_address = VIRT_TO_BUS(sns); + BZERO((caddr_t)sns, sizeof(sns_data_t)); + } +#else + sns = pci_alloc_consistent(ha->pdev, + sizeof(sns_data_t), + &phys_address); + BZERO((caddr_t)sns, sizeof(sns_data_t)); +#endif + if ( sns != NULL ) { + BZERO((caddr_t)sns, sizeof(sns_data_t)); + sns->p.req.hdr.buffer_length = 12; + /* 4.10 */ + sns->p.req.hdr.buffer_address[0] = + LS_64BITS(phys_address); + sns->p.req.hdr.buffer_address[1] = + MS_64BITS(phys_address); + sns->p.req.hdr.subcommand_length = 6; + sns->p.req.subcommand = subCmd; + sns->p.req.param[6] = device->port_id[2]; + sns->p.req.param[7] = device->port_id[1]; + sns->p.req.param[8] = device->port_id[0]; + sns->p.req.param[9] = 0; + + mb[0] = MBC_SEND_SNS_COMMAND; + mb[1] = 14; + mb[3] = LSW(phys_address); + mb[2] = MSW(phys_address); + mb[7] = QL21_64BITS_3RDWD(phys_address); + mb[6] = QL21_64BITS_4THWD(phys_address); + if( !qla2100_mailbox_command(ha, + BIT_7|BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]) ) { + + response = sns->p.rsp[8] | (sns->p.rsp[9] << 8); + if( response == SNS_ACCEPT ) { + if ( flag ) { + BCOPY(&sns->p.rsp[16], device->name, 8); + } else { + BCOPY(&sns->p.rsp[16], device->wwn, 8); + } + } else { + printk(KERN_WARNING "qla2100_SnsGetName: [ERROR] Get Name mb cmd response is not accept - status %x\n", mb[0]); + } + } else if (mb[0] == MBS_FATAL_ERROR) { + printk(KERN_WARNING "qla2100_SnsGetName: [ERROR] Get Name mb cmd fatal error - status %x\n", mb[0]); + lStatus = 1; + break; + } else { + printk(KERN_WARNING "qla2100_SnsGetName: [ERROR] Get Name mb cmd failed - status %x\n", mb[0]); + } + + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(sns, sizeof(sns_data_t)); +#else + pci_free_consistent(ha->pdev, sizeof(sns_data_t), + sns, phys_address); +#endif + } + return(lStatus); + +} +#endif + +/* +* qla2100_init_fc_db +* Initializes Fibre Channel Device Database. +* +* Input: +* ha = adapter block pointer. +* +* Output: +* ha->fc_db = initialized +*/ +STATIC void +qla2100_init_fc_db(scsi_qla_host_t *ha) { + uint16_t cnt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_init_fc_db"); +#endif + + /* Initialize fc database if it is not initialized. */ + if( !ha->fc_db[0].loop_id && !ha->fc_db[1].loop_id ) { + ha->flags.updated_fc_db = FALSE; + + /* Initialize target database. */ + for( cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++ ) { + ha->fc_db[cnt].name[0] = 0L; + ha->fc_db[cnt].name[1] = 0L; + ha->fc_db[cnt].loop_id = PORT_UNUSED; + ha->fc_db[cnt].port_login_retry_count = 8; + ha->fc_db[cnt].flag = 0; /* v2.19.5b3 */ + ha->fc_db[cnt].port_timer = 0; /* v2.19.8 */ + } + +#if USE_FLASH + /* Move flash database to driver database. */ + qla2100_get_database(ha); +#endif + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_init_fc_db"); +#endif +} + +/* +* qla2100_configure_fabric +* Setup fabric devices with loop ID's. +* +* Input: +* ha = adapter block pointer. +* enable_slot_reuse = allows the use of PORT_AVAILABLE slots. +* +* Returns: +* 0 = success. +* 1 = error. +* 2 = database was full and a device was not configured. +* +* Context: +* Kernel context. +*/ +STATIC uint8_t +qla2100_configure_fabric(scsi_qla_host_t *ha, + uint8_t enable_slot_reuse) +{ + uint8_t status = 0; + uint16_t i; + + /* get public loop devices */ + if( !ha->loop_down_timer && !ha->flags.loop_resync_needed ){ + /* Configure loop */ + if( !qla2100_configure_hba(ha) ) { + if( ha->device_id == QLA2100_DEVICE_ID ) { + ha->max_public_loop_ids = LAST_SNS_LOOP_ID - SNS_FIRST_LOOP_ID + 1; + } else { + ha->max_public_loop_ids = LAST_SNS_LOOP_ID + 1; + /* dg 09/15 */ + /* if the topology have change then make all devices available */ + if( ha->prev_topology != ha->current_topology ) { + /* Mark all fabric devices that where present as AVAILABLE */ + for( i = 0; i < ha->max_public_loop_ids; i++ ) + if( (i != SNS_FL_PORT) && (i != FABRIC_CONTROLLER) + && (i != SIMPLE_NAME_SERVER) ) + ha->fabricid[i].in_use = FALSE; + } + } + status = qla2100_sns_device(ha, enable_slot_reuse); + qla2100_restart_queues(ha,TRUE); + } + status = 1; + } + return( status ); +} + +/* +* qla2100_check_devices +* Check devices with loop ID's. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +* 1 = retry needed +* +* Context: +* Kernel context. +*/ +STATIC uint8_t +qla2100_check_devices(scsi_qla_host_t *ha) { + int cnt; + uint8_t ret = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + /* + * Retry any devices that wasn't found but as a WWN. + */ + /* v2.19.05b6 */ + for( cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++ ) { + if( (ha->fc_db[cnt].flag & DEV_MISSING) && + !(ha->fc_db[cnt].flag & DEV_OFFLINE) ) { + /* + * This dev was not detected but its WWN + * is valid. To handle the case where + * the switch may not be giving us the + * device list correctly, schedule for + * a login retry later if not previously + * done so. + */ + DEBUG(printk("qla2100_sns:Port login retry - target %d, count=%d\n",cnt, + ha->fc_db[cnt].port_login_retry_count); ) + if( ha->fc_db[cnt].port_login_retry_count ) + ha->fc_db[cnt].port_login_retry_count--; + + /* + * If after decrement the retry count + * becomes 0, mark this device OFFLINE so + * no more retries will be done based + * on this device. + */ + if (ha->fc_db[cnt].port_login_retry_count == 0) { + DEBUG(printk("qla2100_sns:Port set to OFFLINE - target %d\n",cnt); ) + ha->fc_db[cnt].flag |= DEV_OFFLINE; + } + ret = 1; + } + } + + /* + * Mark devices as DEV_MISSING if they were present + * before and have a loop ID. + */ + for( cnt = 0; cnt < MAX_FIBRE_DEVICES && + !ha->loop_down_timer && + !ha->flags.loop_resync_needed; cnt++ ) { + /* if this slot is used (i.e. loop ID 0 - 0xfe) */ + if( ha->fc_db[cnt].loop_id <= LAST_SNS_LOOP_ID ) { + /* Get port name */ + mb[0] = MBC_GET_PORT_NAME; + mb[1] = ha->fc_db[cnt].loop_id << 8 | BIT_0; + if( qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]) ) { + /* Flag as missing only once */ + if ( !(ha->fc_db[cnt].flag & DEV_MISSING) ) { + if ( ha->fc_db[cnt].port_login_retry_count ) { /* v2.19.05b3 */ + ha->fc_db[cnt].port_login_retry_count--; + ha->fc_db[cnt].flag |= DEV_MISSING; + DEBUG(printk("qla2100_sns: Missing port %d @ loop ID: %x\n", + cnt, ha->fc_db[cnt].loop_id);) + ret++; + } + } + } else if (ha->fc_db[cnt].flag & DEV_MISSING) { + ha->fc_db[cnt].flag &= ~DEV_MISSING; + ha->fc_db[cnt].flag &= ~DEV_OFFLINE; + ha->fc_db[cnt].flag |= DEV_RETURN; + ha->fc_db[cnt].port_login_retry_count = 8; + DEBUG(printk("qla2100_sns: Device %d returned\n", cnt);) + } + } + } + return( ret ); +} + +/* +* qla2100_update_fc_db +* Updates Fibre Channel Device Database with what is actually on loop. +* +* Input: +* ha = adapter block pointer. +* enable_slot_reuse = allows the use of PORT_AVAILABLE slots. +* +* Output: +* ha->fc_db = updated +* +* Returns: +* 0 = success. +* 1 = error. +* 2 = database was full and device was not configured. +*/ +STATIC uint8_t +qla2100_update_fc_db(scsi_qla_host_t *ha, uint8_t enable_slot_reuse) { + uint8_t status = 0; + uint8_t ret = 0; + uint8_t db_full = 0; + uint16_t cnt; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + port_list_entry_t *gn_list, *port_entry; + device_data_t device; +#if BITS_PER_LONG > 32 + uint64_t phys_address = 0; +#else + uint32_t phys_address = 0; +#endif + uint16_t i, size; + uint16_t localdevices = 0; + int retry_needed = 0; + +#ifdef FC_IP_SUPPORT + PIP_DEVICE_BLOCK pIpDevice; +#endif + + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_update_fc_db"); +#endif + + /* Configure loop */ + if( !qla2100_configure_hba(ha) ) { + if( ha->device_id == QLA2100_DEVICE_ID ) { + ha->max_public_loop_ids = LAST_SNS_LOOP_ID - SNS_FIRST_LOOP_ID + 1; + } else { + ha->max_public_loop_ids = LAST_SNS_LOOP_ID + 1; + /* dg 09/15 */ + /* if the topology have change then make all devices available */ + if( ha->prev_topology != ha->current_topology ) { + /* Mark all fabric devices that where present as AVAILABLE */ + for( i = 0; i < ha->max_public_loop_ids; i++ ) + if( (i != SNS_FL_PORT) && (i != FABRIC_CONTROLLER) + && (i != SIMPLE_NAME_SERVER) ) + ha->fabricid[i].in_use = FALSE; + + /* Mark all local devices that where present as AVAILABLE */ + if( ha->current_topology == ISP_CFG_F ) + for( cnt = 0; cnt < MAX_FIBRE_DEVICES && !ha->loop_down_timer + && !ha->flags.loop_resync_needed; cnt++ ) + if( ha->fc_db[cnt].loop_id < SNS_FIRST_LOOP_ID ) { + ha->fc_db[cnt].loop_id = PORT_AVAILABLE; + ha->fc_db[cnt].flag &= ~DEV_PUBLIC; + } + } + } + /* v2.19.03 - Mark all devices missing if configured */ + for( cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++ ) + if( ha->fc_db[cnt].flag & DEV_CONFIGURED) + ha->fc_db[cnt].flag |= DEV_MISSING; + +#ifdef FC_IP_SUPPORT + /* Disable all IP devices in linked list */ + for (pIpDevice = ha->pIpDeviceTop; pIpDevice != NULL; + pIpDevice = pIpDevice->pNextIpDevice) { + pIpDevice->lDeviceFlags &= ~IP_DEV_FLAG_PRESENT; + } +#endif /* FC_IP_SUPPORT */ + + /* Configure local */ + /* Get the port list of devices on the local loop */ +/* 4.10 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + gn_list = KMALLOC(GN_LIST_LENGTH); + if ( gn_list != NULL ) { + phys_address = VIRT_TO_BUS(gn_list); + BZERO((caddr_t)gn_list, GN_LIST_LENGTH); + } +#else + gn_list = pci_alloc_consistent(ha->pdev, + GN_LIST_LENGTH, + &phys_address); + BZERO((caddr_t)gn_list, GN_LIST_LENGTH); +#endif + if( gn_list != NULL ) { + + if( !ha->loop_down_timer && !ha->flags.loop_resync_needed ) { + /* Get port list.*/ + mb[0] = MBC_GET_PORT_LIST; +#ifdef FC_IP_SUPPORT + if (ha->flags.enable_ip == FALSE) + mb[1] = BIT_0; /* Bit 0 - return node names */ + else + mb[1] = BIT_0|BIT_1;/* Bit 0 - return node names, Bit 1 - loop IDs 0-255 */ +#else + mb[1] = BIT_0; +#endif + mb[3] = LSW(phys_address); + mb[2] = MSW(phys_address); + mb[7] = QL21_64BITS_3RDWD(phys_address); + mb[6] = QL21_64BITS_4THWD(phys_address); + if( !qla2100_mailbox_command(ha, BIT_7|BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]) ) { + if ( mb[0] == MBS_COMMAND_COMPLETE ) { + port_entry = gn_list; + size = mb[1]; + /* dg 10/29/99 - check for empty list */ + if ( size/sizeof(port_list_entry_t) == 0 ) { + /* Local devices were present, but may not be reponding, + so retry them later */ + DEBUG(qla2100_print("qla2100_update_fc_db: local port list - empty\n");) + } else + /* Scan through the port list and add devices to the database */ + for( ; size >= sizeof(port_list_entry_t); + size -= sizeof(port_list_entry_t), port_entry++ ) { + /* Skip the known ports. */ +#ifdef FC_IP_SUPPORT + if( ((port_entry->loop_id & LOOP_ID_MASK) == SNS_FL_PORT) || + ((port_entry->loop_id & LOOP_ID_MASK) == FABRIC_CONTROLLER) || + ((port_entry->loop_id & LOOP_ID_MASK) == SIMPLE_NAME_SERVER) ) +#else + if( (port_entry->loop_id == SNS_FL_PORT) || + (port_entry->loop_id == FABRIC_CONTROLLER) || + (port_entry->loop_id == SIMPLE_NAME_SERVER) ) +#endif + continue; + + /* if we are on a public loop then logout the public devices. */ + if( ((ha->current_topology == ISP_CFG_FL) + || (ha->current_topology == ISP_CFG_F)) +#ifdef FC_IP_SUPPORT + && !(port_entry->loop_id & PLE_NOT_SCSI_DEVICE) + && ((port_entry->loop_id & LOOP_ID_MASK) >= ha->min_external_loopid)) { +#else + && (port_entry->loop_id >= ha->min_external_loopid) ) { +#endif + mb[0] = MBC_LOGOUT_FABRIC_PORT; +#ifdef FC_IP_SUPPORT + mb[1] = (port_entry->loop_id & LOOP_ID_MASK) << 8; +#else + mb[1] = port_entry->loop_id << 8; +#endif + qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } else { + /* We are on a local loop */ + /* update the database with the loop */ + /* ID and login to the device. */ +#ifdef FC_IP_SUPPORT + device.loop_id = port_entry->loop_id & LOOP_ID_MASK; +#else + device.loop_id = port_entry->loop_id; +#endif + +#if USE_PORTNAME + /* Get port name */ + mb[0] = MBC_GET_PORT_NAME; + /* mb[1] = device.loop_id << 8 | BIT_0; */ + mb[1] = device.loop_id << 8; + if( !qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]) ) { + /* dg 09/15/99 */ + if ( mb[0] == MBS_COMMAND_COMPLETE ) { + /* tt 1/18/00 */ + mb[2] = (mb[2] & 0x00FF) << 8 | mb[2] >> 8; + mb[3] = (mb[3] & 0x00FF) << 8 | mb[3] >> 8; + mb[6] = (mb[6] & 0x00FF) << 8 | mb[6] >> 8; + mb[7] = (mb[7] & 0x00FF) << 8 | mb[7] >> 8; + + BCOPY(&mb[7], &device.wwn[0], 2); + BCOPY(&mb[6], &device.wwn[2], 2); + BCOPY(&mb[3], &device.wwn[4], 2); + BCOPY(&mb[2], &device.wwn[6], 2); + } else { + status = 1; + printk(KERN_WARNING "qla2100_update_fc_db: [ERROR] GET PORT NAME - bad status.\n"); + goto qla2100_update_fc_db_exit; + } + + } else { /* dg 10/29/99 */ + if ( mb[0] == MBS_FATAL_ERROR ) { + status = 1; + goto qla2100_update_fc_db_exit; + } + continue; + } +#endif + /* Get the node name */ + BCOPY(port_entry->name, device.name, 8); + + +#ifdef FC_IP_SUPPORT + if (!(port_entry->loop_id & PLE_NOT_SCSI_DEVICE)) { + /* SCSI type device */ + DEBUG(sprintf(debug_buff, "qla2100_update_fc_db: SCSI device at ID %x\n\r", + device.loop_id)); + DEBUG(qla2100_print(debug_buff)); +#endif + if( (status = qla2100_update_device_data(ha, &device, enable_slot_reuse)) ) { + /* if not configured or full */ + if( status == 2 ) + db_full = 1; + else + break; + } else + localdevices++; +#ifdef FC_IP_SUPPORT + } else if (ha->flags.enable_ip == TRUE) { + /* SCSI login failed, assume it is IP device */ + DEBUG(sprintf(debug_buff, "qla2100_update_fc_db: IP device at ID %x\n\r", + device.loop_id)); + DEBUG(qla2100_print(debug_buff)); + + /* Update IP device database */ + if (qla2x00_update_ip_device_data(ha, &device) == QL_STATUS_SUCCESS) { + localdevices++; + } else { + status = 1; + break; + } + } +#endif + } + } /* end of For */ + } + } + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(gn_list, GN_LIST_LENGTH); +#else + pci_free_consistent(ha->pdev, GN_LIST_LENGTH, + gn_list, phys_address); +#endif + /* + * if topology is a direct attached local loop then + * don't serach for public devices, unless its a 2100. + */ + if( ((ha->current_topology == ISP_CFG_N) || + (ha->current_topology == ISP_CFG_NL)) && + ha->device_id != QLA2100_DEVICE_ID ) { /* 2/21/00 - dg */ + ha->prev_topology = ha->current_topology; + } else { + /* dgER - we need to add logic to register + * our adapter with the Name server, so we + * can send Command Transport commands (FC4). + * (target mode) + */ + + /* get public loop devices */ + if( !ha->loop_down_timer && !ha->flags.loop_resync_needed ){ + /* v2.19.5 */ + if( (ret = qla2100_sns_device(ha, enable_slot_reuse)) == 2 ) + db_full = 1; + /* v2.19.5b3 */ + if( ret == 1 ) { + if( ha->device_id != QLA2100_DEVICE_ID ) { + status = ret; + ha->sns_retry_cnt++; + if( ha->sns_retry_cnt > 8 ) { + if( !(ha->dpc_flags & ISP_RESET_ONCE) ) + ha->dpc_flags |= ISP_RESET_NEEDED; + } + else + retry_needed++; + } + } + } + + } + + /* Set local loop devices present flag, clear retry flag */ + if (localdevices > 0 ) { + ha->device_flags |= DFLG_LOCAL_DEVICES; + ha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES; + } + + if( qla2100_check_devices(ha) ){ + DEBUG(printk("qla2100: Devices are missing or configured - retrying\n");) + retry_needed++; + } +#ifdef FC_IP_SUPPORT + /* Clean up active IP device list */ + for (pIpDevice = ha->pIpDeviceBottom; pIpDevice != NULL; + pIpDevice = pIpDevice->pLastIpDevice) { + if (!(pIpDevice->lDeviceFlags & IP_DEV_FLAG_PRESENT)) { + /* Device not present, remove it from list and free resources */ + DEBUG(sprintf(debug_buff, "qla2100_update_fc_db: removing IP device, loop ID: %x, port ID: %x\n\r", + pIpDevice->wLoopId, + pIpDevice->acPortId[0]<<16 | pIpDevice->acPortId[1]<<8 | pIpDevice->acPortId[2])); + DEBUG(qla2100_print(debug_buff)); + + if (pIpDevice->lDeviceFlags & IP_DEV_FLAG_PUBLIC_DEVICE) { + /* Do fabric logout and free loop ID */ + if (qla2x00_logout_public_device(ha, pIpDevice->wLoopId, 0) == QL_STATUS_FATAL_ERROR) { + status = 1; + break; + } + qla2x00_free_loopid(ha, pIpDevice->wLoopId); + } + qla2x00_free_ip_block(ha, pIpDevice); + } + } +#endif /* FC_IP_SUPPORT */ + + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_update_fc_db: Failed to allocate memory, No local loop\n"); +#endif + status = 1; + } + /* Map the devices to target IDs */ + if( !ha->loop_down_timer && !ha->flags.loop_resync_needed ) + qla2100_map_targets(ha); + } else + status = 1; + + if( db_full ) + status = 2; + + if( retry_needed ) { + ha->device_flags |= LOGIN_RETRY_NEEDED; + /* v2.19.5 */ + status = 1; + } + + qla2100_update_fc_db_exit: + + if( status == 0 ) { + ha->loop_state = LOOP_READY; + ha->sns_retry_cnt = 0; + for( cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++ ) + ha->fc_db[cnt].port_login_retry_count = 8; + DEBUG(printk("qla2100_update_fc_db: LOOP READY\n");) + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_update_fc_db: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_update_fc_db"); +#endif + return(status); +} + +/* +* qla2100_init_tgt_map +* Initializes target map. +* +* Input: +* ha = adapter block pointer. +* +* Output: +* TGT_Q initialized +*/ +STATIC void +qla2100_init_tgt_map(scsi_qla_host_t *ha) { + uint32_t b, t; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_init_tgt_map"); +#endif + + for( b = 0; b < MAX_BUSES; b++ ) + for( t = 0; t < MAX_FIBRE_DEVICES; t++ ) + TGT_Q(ha, b, t) = (tgt_t *) NULL; + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_init_tgt_map"); +#endif +} + +/* +* qla2100_map_targets +* Setup target queues. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_map_targets(scsi_qla_host_t *ha) { + tgt_t *tgt; + uint32_t b; + uint32_t t; + uint8_t status = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_map_targets"); +#endif + + b = 0; + for( t = 0; t < MAX_FIBRE_DEVICES; t++ ) { + /* if Port never been used. OR */ + /* Device does not exist on port. */ + if( ha->fc_db[t].loop_id != PORT_UNUSED && + ha->fc_db[t].loop_id != PORT_AVAILABLE ) { /* dg 10/29/99 */ + + if( (tgt = TGT_Q(ha, b, t)) != NULL ) { + DEBUG2(sprintf(debug_buff,"Target %d already allocated\n",t)); + DEBUG2(qla2100_print(debug_buff)); + } else + tgt = qla2100_tgt_alloc(ha); + DEBUG(sprintf(debug_buff,"Assigning target ID %02x:%02x @ (%08x) to loop id: 0x%04x\n",b,t,tgt,ha->fc_db[t].loop_id);) + DEBUG(qla2100_print(debug_buff)); + TGT_Q(ha, b, t) = tgt; + tgt->loop_id = ha->fc_db[t].loop_id; + tgt->down_timer = 0; + } + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_map_targets: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_map_targets"); +#endif + return(status); +} +#if USE_FLASH +/* +* qla2100_get_database +* Copies and converts flash database to driver database. +* (may sleep) +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_get_database(scsi_qla_host_t *ha) { + flash_database_t *fptr; + uint8_t status = 1; + uint32_t addr; + uint16_t cnt; + uint8_t *bptr; + uint8_t checksum; + uint32_t b, t; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_get_database"); +#endif + + /* Default setup. */ + ha->flash_db = FLASH_DATABASE_0; + ha->flash_seq = 0; + + if( (fptr = (flash_database_t *)KMALLOC(sizeof(flash_database_t))) ) { + /* Enable Flash Read/Write. */ + qla2100_flash_enable(ha); + + /* Start with flash database with the highest sequence number. */ + b = qla2100_read_flash_byte(ha, FLASH_DATABASE_0); + b |= qla2100_read_flash_byte(ha, FLASH_DATABASE_0 + 1) << 8; + b |= qla2100_read_flash_byte(ha, FLASH_DATABASE_0 + 1) << 16; + b |= qla2100_read_flash_byte(ha, FLASH_DATABASE_0 + 1) << 24; + t = qla2100_read_flash_byte(ha, FLASH_DATABASE_1); + t |= qla2100_read_flash_byte(ha, FLASH_DATABASE_1 + 1) << 8; + t |= qla2100_read_flash_byte(ha, FLASH_DATABASE_1 + 1) << 16; + t |= qla2100_read_flash_byte(ha, FLASH_DATABASE_1 + 1) << 24; + if( t > b ) { + ha->flash_db = FLASH_DATABASE_1; + } + + /* Select the flash database with the good checksum. */ + for( t = 0; t < 2; t++ ) { + checksum = 0; + addr = ha->flash_db; + bptr = (uint8_t *)fptr; + fptr->hdr.size = sizeof(flash_database_t); + + /* Read flash database to driver. */ + for( cnt = 0; cnt < fptr->hdr.size; cnt++ ) { + *bptr = (uint8_t)qla2100_read_flash_byte(ha, addr++); + checksum += *bptr++; + if( bptr == &fptr->hdr.spares[0] && + (fptr->hdr.size > sizeof(flash_database_t) || + fptr->hdr.size < sizeof(flash_hdr_t) || + !fptr->hdr.version) ) { + checksum = 1; + break; + } + } + + if( !checksum ) { + status = 0; + break; + } + /* trying other database */ + if( ha->flash_db == FLASH_DATABASE_0 ) { + ha->flash_db = FLASH_DATABASE_1; + } else { + ha->flash_db = FLASH_DATABASE_0; + } + } + + if( !status ) { + ha->flash_seq = fptr->hdr.seq; + + /* Convert flash database to driver database format. */ + if( fptr->hdr.size -= sizeof(flash_hdr_t) ) { + for( cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++ ) { + ha->fc_db[cnt].name[0] = fptr->node[cnt].name[0]; + ha->fc_db[cnt].name[1] = fptr->node[cnt].name[1]; + cnt, + ha->fc_db[cnt].name[1], + ha->fc_db[cnt].name[0]); + + ha->fc_db[cnt].loop_id = PORT_AVAILABLE; + ha->fc_db[cnt].flag = 0; /* v2.19.05b3 */ + if( !(fptr->hdr.size -= sizeof(flash_node_t)) ) + break; + } + } + } + + qla2100_flash_disable(ha); + + KMFREE(fptr, sizeof(flash_database_t)); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_get_database: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_get_database"); +#endif + return(status); +} + +/* +* qla2100_save_database +* Copies and converts driver database to flash database. +* (may sleep) +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_save_database(scsi_qla_host_t *ha) { + flash_database_t *fptr; + uint8_t status = 1; + uint32_t addr; + uint16_t cnt; + uint8_t *bptr; + uint8_t checksum; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_save_database"); +#endif + + if( (fptr = (flash_database_t *)KMALLOC(sizeof(flash_database_t)) ) ) { + /* Enable Flash Read/Write. */ + qla2100_flash_enable(ha); + + fptr->hdr.seq = ++ha->flash_seq; + fptr->hdr.version = FLASH_DATABASE_VERSION; + fptr->hdr.size = sizeof(flash_hdr_t); + + /* Copy and convert driver database to flash database. */ + for( cnt = 0; cnt < MAX_FIBRE_DEVICES; cnt++ ) { + if( ha->fc_db[cnt].loop_id == PORT_UNUSED ) + break; + else { + fptr->node[cnt].name[0] = ha->fc_db[cnt].name[0]; + fptr->node[cnt].name[1] = ha->fc_db[cnt].name[1]; + fptr->hdr.size += sizeof(flash_node_t); + } + } + + /* Calculate checksum. */ + checksum = 0; + bptr = (uint8_t *)fptr; + for( cnt = 0; cnt < fptr->hdr.size; cnt++ ) + checksum += *bptr++; + fptr->hdr.checksum = ~checksum + 1; + + /* Setup next sector address for flash */ + if( ha->flash_db == FLASH_DATABASE_0 ) + addr = FLASH_DATABASE_1; + else + addr = FLASH_DATABASE_0; + ha->flash_db = addr; + + /* Erase flash sector prior to write. */ + status = qla2100_erase_flash_sector(ha, addr); + + /* Write database to flash. */ + bptr = (uint8_t *)fptr; + for( cnt = 0; cnt < fptr->hdr.size && !status; cnt++ ) + status = qla2100_program_flash_address(ha, addr++, *bptr++); + + qla2100_flash_disable(ha); + + KMFREE(fptr, sizeof(flash_database_t)); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_save_database: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_save_database"); +#endif + return(status); +} + +/* +* qla2100_program_flash_address +* Program flash address. +* +* Input: +* ha = adapter block pointer. +* addr = flash byte address. +* data = data to be written to flash. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_program_flash_address(scsi_qla_host_t *ha, uint32_t addr, uint8_t data) { + uint8_t status; + + /* Write Program Command Sequence */ + qla2100_write_flash_byte(ha, 0x5555, 0xaa); + qla2100_write_flash_byte(ha, 0x2aaa, 0x55); + qla2100_write_flash_byte(ha, 0x5555, 0xa0); + qla2100_write_flash_byte(ha, addr, data); + + /* Wait for write to complete. */ + status = qla2100_poll_flash(ha, addr, data); + +#ifdef QL_DEBUG_LEVEL_2 + if( status ) + qla2100_print("qla2100_program_flash_address: **** FAILED ****\n"); +#endif + return(status); +} + +/* +* qla2100_erase_flash_sector +* Erases flash sector. +* +* Input: +* ha = adapter block pointer. +* addr = sector address. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_erase_flash_sector(scsi_qla_host_t *ha, uint32_t addr) { + uint8_t status; + + addr &= 0x1c000; + + /* Individual Sector Erase Command Sequence */ + qla2100_write_flash_byte(ha, 0x5555, 0xaa); + qla2100_write_flash_byte(ha, 0x2aaa, 0x55); + qla2100_write_flash_byte(ha, 0x5555, 0x80); + qla2100_write_flash_byte(ha, 0x5555, 0xaa); + qla2100_write_flash_byte(ha, 0x2aaa, 0x55); + qla2100_write_flash_byte(ha, addr, 0x30); + + SYS_DELAY(150); + + /* Wait for erase to complete. */ + status = qla2100_poll_flash(ha, addr, 0x80); + +#ifdef QL_DEBUG_LEVEL_2 + if( status ) + qla2100_print("qla2100_erase_flash_sector: **** FAILED ****\n"); +#endif + return(status); +} + +/* +* qla2100_poll_flash +* Polls flash for completion. +* +* Input: +* ha = adapter block pointer. +* addr = flash byte address. +* data = data to be polled. +* +* Returns: +* 0 = success. +*/ +STATIC uint8_t +qla2100_poll_flash(scsi_qla_host_t *ha, uint32_t addr, uint8_t poll_data) { + uint8_t status = 1; + uint8_t flash_data; + uint32_t cnt; + + poll_data &= BIT_7; + + /* Wait for 30 seconds for command to finish. */ + for( cnt = 3000000; cnt; cnt-- ) { + flash_data = (uint8_t)qla2100_read_flash_byte(ha, addr); + + if( (flash_data & BIT_7) == poll_data ) { + status = 0; + break; + } + if( flash_data & BIT_5 && cnt > 2 ) + cnt = 2; + SYS_DELAY(10); + } + + return(status); +} + +/* +* qla2100_flash_enable +* Setup flash for reading/writing. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_flash_enable(scsi_qla_host_t *ha) { + device_reg_t *reg = ha->iobase; + + /* Setup bit 16 of flash address. */ + WRT_REG_WORD(®->nvram, NV_SELECT); + + /* Enable Flash Read/Write. */ + WRT_REG_WORD(®->ctrl_status, ISP_FLASH_ENABLE); + + /* Read/Reset Command Sequence */ + qla2100_write_flash_byte(ha, 0x5555, 0xaa); + qla2100_write_flash_byte(ha, 0x2aaa, 0x55); + qla2100_write_flash_byte(ha, 0x5555, 0xf0); + qla2100_read_flash_byte(ha, FLASH_DATABASE_0); +} + +/* +* qla2100_flash_disable +* Disable flash and allow RISC to run. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_flash_disable(scsi_qla_host_t *ha) { + device_reg_t *reg = ha->iobase; + + /* Restore chip registers. */ + WRT_REG_WORD(®->ctrl_status, 0); + WRT_REG_WORD(®->nvram, 0); +} + +/* +* qla2100_write_flash_byte +* Write byte to flash. +* +* Input: +* ha = adapter block pointer. +* addr = flash byte address. +* data = data to be written. +*/ +STATIC void +qla2100_write_flash_byte(scsi_qla_host_t *ha, uint32_t addr, uint8_t data) { + device_reg_t *reg = ha->iobase; + + WRT_REG_WORD(®->flash_address, (uint16_t)addr); + WRT_REG_WORD(®->flash_data, (uint16_t)data); +} + +/* +* qla2100_read_flash_byte +* Reads byte from flash, but must read a word from chip. +* +* Input: +* ha = adapter block pointer. +* addr = flash byte address. +* +* Returns: +* byte from flash. +*/ +STATIC uint16_t +qla2100_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr) { + device_reg_t *reg = ha->iobase; + uint16_t data; + + WRT_REG_WORD(®->flash_address, (uint16_t)addr); + data = qla2100_debounce_register(®->flash_data); + + return(data); +} +#endif + +/* +* qla2100_reset_adapter +* Reset adapter. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_reset_adapter(scsi_qla_host_t *ha) { + device_reg_t *reg = ha->iobase; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_reset_adapter"); +#endif + + ha->flags.online = FALSE; + qla2100_disable_intrs(ha); + /* WRT_REG_WORD(®->ictrl, 0); */ + /* Reset RISC processor. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_reset_adapter"); +#endif +} + +/* +* qla2100_loop_reset +* Issue loop reset. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +STATIC uint8_t +qla2100_loop_reset(scsi_qla_host_t *ha) { + uint8_t status = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_loop_reset"); +#endif + + if( ha->flags.enable_lip_reset ) { + mb[0] = MBC_LIP_RESET; + mb[1] = 0xff00; + mb[2] = ha->loop_reset_delay; + status |= qla2100_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + } + if( ha->flags.enable_target_reset ) { + mb[0] = MBC_TARGET_RESET; + mb[1] = ha->loop_reset_delay; + status |= qla2100_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } + if( (!ha->flags.enable_target_reset && !ha->flags.enable_lip_reset ) || + ha->flags.enable_lip_full_login ) { + mb[0] = MBC_LIP_FULL_LOGIN; + status |= qla2100_mailbox_command(ha, BIT_0, &mb[0]); + } + + /* Issue marker command. */ + qla2100_marker(ha, 0, 0, 0, MK_SYNC_ALL); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_loop_reset: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_loop_reset"); +#endif + return(status); +} + +/* +* qla2100_device_reset +* Issue bus device reset message to the target. +* +* Input: +* ha = adapter block pointer. +* b = BUS number. +* t = SCSI ID. +* +* Returns: +* 0 = success +*/ +STATIC uint8_t +qla2100_device_reset(scsi_qla_host_t *ha, uint32_t b, uint32_t t) { + tgt_t *tgt; + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_device_reset"); +#endif + + tgt = TGT_Q(ha, b, t); + + mb[0] = MBC_ABORT_TARGET; + mb[1] = tgt->loop_id << 8; + mb[2] = 1; + status = qla2100_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Issue marker command. */ + qla2100_marker(ha, b, t, 0, MK_SYNC_ID); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_device_reset: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_device_reset"); +#endif + return(status); +} + +/* +* qla2100_abort_device +* Issue an abort message to the device +* +* Input: +* ha = adapter block pointer. +* b = BUS number. +* t = SCSI ID. +* l = SCSI LUN. +* +* Returns: +* 0 = success +*/ +STATIC uint8_t +qla2100_abort_device(scsi_qla_host_t *ha, uint32_t b, uint32_t t, uint32_t l) { + tgt_t *tgt; + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_abort_device"); +#endif + + tgt = TGT_Q(ha, b, t); + + mb[0] = MBC_ABORT_DEVICE; + mb[1] = tgt->loop_id << 8; + mb[2] = l; + status = qla2100_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Issue marker command. */ + qla2100_marker(ha, b, t, l, MK_SYNC_ID_LUN); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_abort_device: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_abort_device"); +#endif + return(status); +} + +/* +* qla2100_abort_command +* Abort command aborts a specified IOCB. +* +* Input: +* ha = adapter block pointer. +* sp = SB structure pointer. +* +* Returns: +* 0 = success +*/ +STATIC uint8_t +qla2100_abort_command(scsi_qla_host_t *ha, srb_t *sp) { + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint32_t b, t, l; + uint32_t handle; + tgt_t *tgt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_abort_command"); +#endif + /* v2.19.8 */ + t = SCSI_TCN_32(sp->cmd); + if( ha->loop_state == LOOP_DOWN || + PORT_DOWN(ha,t) > 0 ) { + return(0); + } + + /* Locate handle number. */ + for( handle = 0; handle < MAX_OUTSTANDING_COMMANDS; handle++ ) + if( ha->outstanding_cmds[handle] == sp ) + break; + + DEBUG(qla2100_print("qla2100_abort_command: Sending Abort Command for Handle = ");) + DEBUG(qla2100_output_number((u_long) handle, 16);) + DEBUG(qla2100_print("\n");) + + /* Get a pointer to the SCSI address */ + b = SCSI_BUS_32(sp->cmd); + l = SCSI_LUN_32(sp->cmd); + + tgt = TGT_Q(ha, b, t); + + mb[0] = MBC_ABORT_COMMAND; + mb[1] = tgt->loop_id << 8; + mb[2] = (uint16_t)handle; + mb[3] = handle >> 16; + mb[6] = l; + if( !(status = qla2100_mailbox_command(ha, BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0])) ) + sp->flags |= SRB_ABORT_PENDING; + + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_abort_command: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_abort_command"); +#endif + return(status); +} + +/* +* Issue marker command. +* Function issues marker IOCB. +* +* Input: +* ha = adapter block pointer. +* b = BUS number. +* t = SCSI ID +* l = SCSI LUN +* type = marker modifier +*/ +STATIC void +qla2100_marker(scsi_qla_host_t *ha, uint32_t b, uint32_t t, uint32_t l, uint8_t type) { + mrk_entry_t *pkt; + tgt_t *tgt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_marker"); +#endif + + tgt = TGT_Q(ha, b, t); + + /* Get request packet. */ + if( (pkt = (mrk_entry_t *)qla2100_req_pkt(ha) ) ) { + pkt->entry_type = MARKER_TYPE; + pkt->modifier = type; + + if( type == MK_SYNC_LIP ) + pkt->sequence_number = ha->lip_seq; + else if( type != MK_SYNC_ALL ) { + pkt->lun = l; + pkt->target = (uint8_t)tgt->loop_id; + } + + /* Issue command to ISP */ + qla2100_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( !pkt ) + qla2100_print("qla2100_marker: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_marker"); +#endif +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) +/* +* qla2100_64bit_start_scsi +* The start SCSI is responsible for building request packets on +* request ring and modifying ISP input pointer. +* +* Input: +* ha = adapter block pointer. +* sp = SB structure pointer. +* +* Returns: +* 0 = success, was able to issue command. +*/ +STATIC uint8_t +qla2100_64bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + uint8_t status = 0; + Scsi_Cmnd *cmd = sp->cmd; + uint32_t cnt; + cmd_a64_entry_t *pkt; + uint16_t req_cnt; + uint16_t seg_cnt; + uint16_t cdb_len,temp; + struct scatterlist *sg = (struct scatterlist *) NULL; + uint32_t timeout; + caddr_t data_ptr; + uint32_t *dword_ptr; + uint64_t dma_handle; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_64bit_start_scsi:"); +#endif + DEBUG(sprintf(debug_buff, + "64bit_start: cmd=%x sp=%x CDB=%x\n\r",cmd,sp,cmd->cmnd[0]);) + DEBUG(qla2100_print(debug_buff)); + + /* Calculate number of entries and segments required. */ + seg_cnt = 0; + req_cnt = 1; + if ( cmd->use_sg ) { + /* 4.10 64 bit S/G Data Transfer */ + sg = (struct scatterlist *) cmd->request_buffer; + seg_cnt = pci_map_sg(ha->pdev, + sg,cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + + if( seg_cnt > 2 ) { + req_cnt += (uint16_t)(seg_cnt - 2) / 5; + if( (uint16_t)(seg_cnt - 2) % 5 ) + req_cnt++; + } + } else if( cmd->request_bufflen ) + { /* no S/G Data Transfer */ + /* DEBUG5(printk("Single data transfer (0x%x)\n", + cmd->request_bufflen)); */ + seg_cnt = 1; + } + + /* Acquire ring specific lock */ + QLA2100_RING_LOCK(ha); + + if( (uint16_t)(req_cnt + 2) >= ha->req_q_cnt ) { + /* Calculate number of free request q out entries. */ + if (ha->device_id == QLA2300_DEVICE_ID) cnt = RD_REG_WORD(®2300->req_q_out); + else cnt = RD_REG_WORD(®->mailbox4); + if( ha->req_ring_index < cnt ) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); + } + + /* If room for request in request ring. */ + if( (uint16_t)(req_cnt + 2) < ha->req_q_cnt ) { + /* Check for room in outstanding command list. */ + for( cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && + ha->outstanding_cmds[cnt] != 0; cnt++ ) + ; + + if( cnt < MAX_OUTSTANDING_COMMANDS ) { + ha->outstanding_cmds[cnt] = sp; + ha->req_q_cnt -= req_cnt; + CMD_HANDLE(sp->cmd) = (unsigned char *) (u_long) cnt; + + /* + * Build command packet. + */ + pkt = ha->request_ring_ptr; + + pkt->entry_type = COMMAND_A64_TYPE; + pkt->entry_count = (uint8_t)req_cnt; + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->control_flags= 0; + pkt->entry_status = 0; + pkt->handle = (uint32_t)cnt; + + /* Zero out remaining portion of packet. */ + dword_ptr = (uint32_t *)pkt + 2; + for( cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++ ) + *dword_ptr++ = 0; + + /* + * We subtract 2 sec. from the timeout value to insure + * the ISP time-out before the mid-level or the driver. + */ + timeout = (uint32_t) CMD_TIMEOUT(cmd)/HZ; + if( timeout > 2 ) + pkt->timeout = (uint16_t) timeout - 2; + else + pkt->timeout = (uint16_t) timeout; + + /* Set device target ID and LUN */ + pkt->target = TGT_Q(ha, SCSI_BUS_32(cmd), + SCSI_TCN_32(cmd))->loop_id; + pkt->lun = SCSI_LUN_32(cmd); + + /* Enable simple tag queuing if device supports it. */ + if ( cmd->device->tagged_queue ) { + switch (cmd->tag) { + case SIMPLE_QUEUE_TAG: + pkt->control_flags = CF_SIMPLE_TAG; + break; + case HEAD_OF_QUEUE_TAG: + pkt->control_flags = CF_HEAD_TAG; + break; + case ORDERED_QUEUE_TAG: + pkt->control_flags = CF_ORDERED_TAG; + break; + default: + pkt->control_flags = CF_SIMPLE_TAG; + } + } else + pkt->control_flags = CF_SIMPLE_TAG; + + if (ha->device_id == QLA2300_DEVICE_ID) + pkt->control_flags |= CF_NO_FAST_POSTING; + + /* Load SCSI command packet. */ + cdb_len = (uint16_t)CMD_CDBLEN(cmd); + if (cdb_len > MAX_CMDSZ) cdb_len = MAX_CMDSZ; + data_ptr = (uint8_t *) &(CMD_CDBP(cmd)); + for( cnt = 0; cnt < cdb_len; cnt++ ) + pkt->scsi_cdb[cnt] = *data_ptr++; + pkt->byte_count = (uint32_t) CMD_XFRLEN(cmd); + + /* + * Load data segments. + */ + if( seg_cnt ) /* If data transfer. */ + { + switch( cmd->data_cmnd[0] ) { + case FORMAT_UNIT: + case WRITE_6: + case MODE_SELECT: + case SEND_DIAGNOSTIC: + case WRITE_10: + case WRITE_BUFFER: + case WRITE_LONG: + case WRITE_SAME: + case MODE_SELECT_10: + case WRITE_12: + case WRITE_VERIFY_12: + case SEND_VOLUME_TAG: + pkt->control_flags |= BIT_6; /* WRITE */ + break; + default: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#if QLA_SCSI_VENDOR_DIR + qla2100_set_vend_direction(ha, cmd, pkt); +#else + pkt->control_flags |= BIT_5; /* READ */ +#endif +#else /* kernel version is 2.4.0 or higher */ + if (cmd->sc_data_direction == SCSI_DATA_WRITE) + pkt->control_flags |= BIT_6;/*WRITE*/ + else + pkt->control_flags |= BIT_5;/*READ*/ +#endif /* kernel version 2.4.0 */ + break; + } + sp->dir = pkt->control_flags & (BIT_5|BIT_6); + + /* Set total data segment count. */ + pkt->dseg_count = seg_cnt; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *)&pkt->dseg_0_address; + + if( cmd->use_sg ) /* If scatter gather */ + { + /* Load command entry data segments. */ + for( cnt = 0; cnt < 2 && seg_cnt; cnt++, seg_cnt-- ) { + /* 4.10 64 bit */ + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); + sg++; + /* DEBUG(sprintf(debug_buff, + "S/G Segment phys_addr=%x %x, len=0x%x\n\r", + cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))), + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) + DEBUG(qla2100_print(debug_buff)); */ + } +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2x00_64bit_start_scsi: Scatter/gather command packet data - "); + qla2100_print("b"); + qla2100_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla2100_print("t"); + qla2100_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla2100_print("d"); + qla2100_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla2100_print("\n\r"); + qla2100_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + /* + * Build continuation packets. + */ + while( seg_cnt > 0 ) { + /* Adjust ring index. */ + ha->req_ring_index++; + if( ha->req_ring_index == REQUEST_ENTRY_CNT ) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + pkt = (cmd_a64_entry_t *)ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for( cnt = 0;cnt < REQUEST_ENTRY_SIZE/4; cnt++ ) + *dword_ptr++ = 0; + + /* Load packet defaults. */ + ((cont_a64_entry_t *)pkt)->entry_type = + CONTINUE_A64_TYPE; + ((cont_a64_entry_t *)pkt)->entry_count = 1; + ((cont_a64_entry_t *)pkt)->sys_define = (uint8_t) + ha->req_ring_index; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *) + &((cont_a64_entry_t *)pkt)->dseg_0_address; + + /* Load continuation entry data segments. */ + for( cnt = 0; cnt < 5 && seg_cnt; cnt++, seg_cnt-- ) { + /* 4.10 64 bit */ + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); + sg++; + /* DEBUG(sprintf(debug_buff, + "S/G Segment Cont. phys_addr=%x %x, len=0x%x\n\r", + cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))), + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) + DEBUG(qla2100_print(debug_buff)); */ + } +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2x00_64bit_start_scsi: continuation packet data - c"); + qla2100_print("b"); + qla2100_output_number((u_long)SCSI_BUS_32(cmd), 10); + + qla2100_print("t"); + qla2100_output_number((u_long)SCSI_TCN_32(cmd), 10); + qla2100_print("d"); + qla2100_output_number((u_long)SCSI_LUN_32(cmd), 10); + qla2100_print("\n\r"); + qla2100_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } else /* No scatter gather data transfer */ + { /* 4.10 64 bit */ + dma_handle = pci_map_single(ha->pdev, + cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + /* save dma_handle for pci_unmap_single */ + sp->saved_dma_handle = dma_handle; + + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(dma_handle)); + *dword_ptr++ = cpu_to_le32(pci_dma_hi32(dma_handle)); + *dword_ptr = (uint32_t) cmd->request_bufflen; + /* DEBUG(sprintf(debug_buff, + "64_bit: No S/G map_single saved_dma_handle=%lx len=%x \n\r",dma_handle, cmd->request_bufflen)); + DEBUG(qla2100_print(debug_buff)); */ +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2x00_64bit_start_scsi: No scatter/gather command packet data - c"); + qla2100_print("b"); + qla2100_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla2100_print("t"); + qla2100_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla2100_print("d"); + qla2100_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla2100_print("\n\r"); + qla2100_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } + else /* No data transfer */ + { + *dword_ptr++ = (uint32_t) 0; + *dword_ptr++ = (uint32_t) 0; + *dword_ptr = (uint32_t) 0; +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2x00_64bit_start_scsi: No data, command packet data - c"); + qla2100_print("b"); + qla2100_output_number((u_long)SCSI_BUS_32(cmd), 10); + qla2100_print("t"); + qla2100_output_number((u_long)SCSI_TCN_32(cmd), 10); + qla2100_print("d"); + qla2100_output_number((u_long)SCSI_LUN_32(cmd), 10); + qla2100_print("\n\r"); + qla2x00_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + DEBUG4(qla2100_print("\nqla2100_64bit_start_scsi: Wakeup RISC for pending command\n\r")); + /* Adjust ring index. */ + ha->req_ring_index++; + if( ha->req_ring_index == REQUEST_ENTRY_CNT ) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + /* Set chip new ring index. */ +#if WATCH_THREADS_SIZE + DEBUG3(qla2100_output_number((uint32_t)ha->actthreads, 16)); +#endif + if (ha->device_id == QLA2300_DEVICE_ID) { + temp = CACHE_FLUSH(®2300->req_q_in); + WRT_REG_WORD(®2300->req_q_in, ha->req_ring_index); + } else { + temp = CACHE_FLUSH(®->mailbox4); + WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + } + } else { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2x00_64bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r"); + qla2100_print(" req_q_cnt="); + qla2100_output_number((u_long)ha->req_q_cnt, 16); +#endif + } + } else { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2x00_64bit_start_scsi: in-ptr="); + qla2100_output_number((u_long)ha->req_ring_index, 16); + qla2100_print(" req_q_cnt="); + qla2100_output_number((u_long)ha->req_q_cnt, 16); + qla2100_print(" req_cnt="); + qla2100_output_number((u_long)req_cnt, 16); + qla2100_print("\n\r"); +#endif + } + + /* Release ring specific lock */ + QLA2100_RING_UNLOCK(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2x00_64bit_start_scsi: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla2100_print("qla2x00_64bit_start_scsi: exiting normally\n\r"); +#endif + return(status); +} +#endif + +/* +* qla2100_32bit_start_scsi +* The start SCSI is responsible for building request packets on +* request ring and modifying ISP input pointer. +* +* The Qlogic firmware interface allows every queue slot to have a SCSI +* command and up to 4 scatter/gather (SG) entries. If we need more +* than 4 SG entries, then continuation entries are used that can +* hold another 7 entries each. The start routine determines if there +* is eought empty slots then build the combination of requests to +* fulfill the OS request. +* +* Input: +* ha = adapter block pointer. +* sp = SCSI Request Block structure pointer. +* +* Returns: +* 0 = success, was able to issue command. +*/ +STATIC uint8_t +qla2100_32bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + uint8_t status = 0; + Scsi_Cmnd *cmd = sp->cmd; + uint16_t cdb_len, temp; + uint32_t cnt; + cmd_entry_t *pkt; + uint16_t req_cnt; + uint16_t seg_cnt; + struct scatterlist *sg = (struct scatterlist *) NULL; + caddr_t data_ptr; + uint32_t *dword_ptr; + uint32_t timeout; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + uint64_t dma_handle; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_32bit_start_scsi"); +#endif + +#if defined(QL_DEBUG_LEVEL_5) || defined(QL_DEBUG_LEVEL_3) + printk( + "32bit_start BEGIN: cmd=%x sp=%x CDB=%x\n\r", + cmd,sp,cmd->cmnd[0]); +#endif +#ifdef NEW + /* + * Send marker if required. + */ + if (ha->marker_needed != 0) { + if (qla2200_marker(ha, 0, 0, MK_SYNC_ALL) != 0) { + RING_UNLOCK(ha); + return (1); + } + } +#endif + COMTRACE('S') + /* Calculate number of entries and segments required. */ + seg_cnt = 0; + req_cnt = 1; + if( cmd->use_sg ) { + sg = (struct scatterlist *) cmd->request_buffer; + /* 4.10 32 bit S/G Data Transfer */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + seg_cnt = cmd->use_sg; +#else + seg_cnt = pci_map_sg(ha->pdev,sg,cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); +#endif + /* + * if greater than four sg entries then we need to allocate + * continuation entries + */ + if( seg_cnt > 2 ) { + req_cnt += (uint16_t)(seg_cnt - 3) / 7; + if( (uint16_t)(seg_cnt - 3) % 7 ) + req_cnt++; + } + DEBUG5(sprintf(debug_buff, + "S/G for data transfer -num segs(%d), req blk cnt(%d)\n\r",seg_cnt,req_cnt)); + DEBUG5(qla2100_print(debug_buff)); + } else if( CMD_XFRLEN(cmd) ) /* If data transfer. */ + { /* no S/G Data Transfer */ + /* DEBUG5(printk("Single data transfer (0x%x)\n", + cmd->request_bufflen));*/ + seg_cnt = 1; + } + + /* Acquire ring specific lock */ + QLA2100_RING_LOCK(ha); + + if( (uint16_t)(req_cnt + 2) >= ha->req_q_cnt ) { + /* Calculate number of free request entries. */ + if (ha->device_id == QLA2300_DEVICE_ID) + cnt = qla2100_debounce_register(®2300->req_q_out); + else + cnt = qla2100_debounce_register(®->mailbox4); + + if( ha->req_ring_index < cnt ) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); + } + + DEBUG5(sprintf(debug_buff, + "Number of free entries = (%d)\n\r",ha->req_q_cnt)); + DEBUG5(qla2100_print(debug_buff)); + /* If room for request in request ring. */ + if( (uint16_t)(req_cnt + 2) < ha->req_q_cnt ) { + /* Check for room in outstanding command list. */ + for( cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && + (ha->outstanding_cmds[cnt] != 0); cnt++ ) + ; + + if( cnt < MAX_OUTSTANDING_COMMANDS ) { + ha->outstanding_cmds[cnt] = sp; + ha->req_q_cnt -= req_cnt; + /* save the handle -- helps if we want to abort it */ + CMD_HANDLE(sp->cmd) = (unsigned char *) (u_long) cnt; + + /* + * Build command packet. + */ + pkt = (cmd_entry_t *)ha->request_ring_ptr; + + pkt->entry_type = COMMAND_TYPE; + pkt->entry_count = (uint8_t)req_cnt; + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->entry_status = 0; + pkt->control_flags= 0; + pkt->handle = (uint32_t)cnt; + + /* Zero out remaining portion of packet. */ + dword_ptr = (uint32_t *)pkt + 2; + for( cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++ ) + *dword_ptr++ = 0; + + /* + * v2.19.8 + * We subtract 5 sec. from the timeout value to insure + * the ISP time-out before the mid-level or the driver. + */ + timeout = (uint32_t) CMD_TIMEOUT(cmd)/HZ; + if( timeout > 5 ) + pkt->timeout = (uint16_t) timeout - 5; + else + pkt->timeout = (uint16_t) timeout; + + /* Set device target ID and LUN */ + pkt->target = TGT_Q(ha, + SCSI_BUS_32(cmd), SCSI_TCN_32(cmd))->loop_id; + pkt->lun = SCSI_LUN_32(cmd); + + /* Enable simple tag queuing if device supports it. */ + if ( cmd->device->tagged_queue ) { + switch (cmd->tag) { + case SIMPLE_QUEUE_TAG: + pkt->control_flags = CF_SIMPLE_TAG; + break; + case HEAD_OF_QUEUE_TAG: + pkt->control_flags = CF_HEAD_TAG; + break; + case ORDERED_QUEUE_TAG: + pkt->control_flags = CF_ORDERED_TAG; + break; + default: + pkt->control_flags = CF_SIMPLE_TAG; + } + } else + pkt->control_flags = CF_SIMPLE_TAG; + + if (ha->device_id == QLA2300_DEVICE_ID) + pkt->control_flags |= CF_NO_FAST_POSTING; + + /* Load SCSI command packet. */ + cdb_len = (uint16_t)CMD_CDBLEN(cmd); + if( cdb_len > MAX_CMDSZ ) + cdb_len = MAX_CMDSZ; + data_ptr = (uint8_t *) &(CMD_CDBP(cmd)); + for( cnt = 0; cnt < cdb_len; cnt++ ) + pkt->scsi_cdb[cnt] = *data_ptr++; + DEBUG3(sprintf(debug_buff, + "qla2100: Packet has command[0]=0x%x, hndl=0x%x\n",pkt->scsi_cdb[0],pkt->handle);) + DEBUG3(qla2100_print(debug_buff);) + pkt->byte_count = (uint32_t) CMD_XFRLEN(cmd); + + /* + * Load data segments. + */ + if( seg_cnt ) { + /* Set transfer direction (READ and WRITE) */ + /* Linux doesn't tell us */ + + switch( cmd->data_cmnd[0] ) { + case FORMAT_UNIT: + case WRITE_6: + case MODE_SELECT: + case SEND_DIAGNOSTIC: + case WRITE_10: + case WRITE_BUFFER: + case WRITE_LONG: + case WRITE_SAME: + case MODE_SELECT_10: + case WRITE_12: + case WRITE_VERIFY_12: + case SEND_VOLUME_TAG: + pkt->control_flags |= BIT_6; /* WRITE */ + break; + default: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#if QLA_SCSI_VENDOR_DIR + qla2100_set_vend_direction(ha, cmd, pkt); +#else + pkt->control_flags |= BIT_5; /* READ */ +#endif +#else /* kernel version is 2.4.0 or higher */ + if (cmd->sc_data_direction == SCSI_DATA_WRITE) + pkt->control_flags |= BIT_6;/*WRITE*/ + else + pkt->control_flags |= BIT_5;/*READ*/ +#endif /* kernel version 2.4.0 */ + break; + } + sp->dir = pkt->control_flags & (BIT_5|BIT_6); + + /* Set total data segment count. */ + pkt->dseg_count = seg_cnt; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *)&pkt->dseg_0_address; + + if( cmd->use_sg ) /* If scatter gather */ + { + DEBUG5(qla2100_print("Building S/G data segments..\n\r")); + DEBUG5(qla2100_dump_buffer((caddr_t)sg, 4*16)); + /* Load command entry data segments. */ + for( cnt = 0; cnt < 3 && seg_cnt; cnt++, seg_cnt-- ) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(sg->address)); + *dword_ptr++ = sg->length; + /* DEBUG(sprintf(debug_buff, + "S/G Segment phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(VIRT_TO_BUS(sg->address)),sg->length)); + DEBUG(qla2100_print(debug_buff)); */ +#else + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); + /* DEBUG(sprintf(debug_buff, + "S/G Segment phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) + DEBUG(qla2100_print(debug_buff)); */ +#endif + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2100_32bit_start_scsi: Scatter/gather command packet data - "); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_BUS_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_TCN_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_LUN_32(cmd), 10); + qla2100_print("\n"); + qla2100_dump_buffer((uint8_t *)pkt, REQUEST_ENTRY_SIZE); +#endif + /* + * Build continuation packets. + */ + while( seg_cnt > 0 ) { + /* Adjust ring index. */ + ha->req_ring_index++; + if( ha->req_ring_index == REQUEST_ENTRY_CNT ) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + pkt = (cmd_entry_t *)ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for( cnt = 0;cnt < REQUEST_ENTRY_SIZE/4; cnt++ ) + *dword_ptr++ = 0; + + /* Load packet defaults. */ + ((cont_entry_t *)pkt)->entry_type = CONTINUE_TYPE; + ((cont_entry_t *)pkt)->entry_count = 1; + ((cont_entry_t *)pkt)->sys_define = (uint8_t) + ha->req_ring_index; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *) + &((cont_entry_t *)pkt)->dseg_0_address; + + /* Load continuation entry data segments. */ + for( cnt = 0; cnt < 7 && seg_cnt; cnt++, seg_cnt-- ) { + /* 4.10 32 bit */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + *dword_ptr++ = (u_int) cpu_to_le32(VIRT_TO_BUS(sg->address)); + *dword_ptr++ = sg->length; + /* DEBUG(sprintf(debug_buff, + "S/G Segment Cont. phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(pci_dma_lo32(VIRT_TO_BUS(sg->address))),sg->length);) + DEBUG(qla2100_print(debug_buff)); */ +#else + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); + /* DEBUG(sprintf(debug_buff, + "S/G Segment Cont. phys_addr=0x%x, len=0x%x\n\r", + cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), + cpu_to_le32(sg_dma_len(sg)));) + DEBUG(qla2100_print(debug_buff)); */ +#endif + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2100_32bit_start_scsi: continuation packet data - "); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_BUS_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_TCN_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_LUN_32(cmd), 10); + qla2100_print("\n"); + qla2100_dump_buffer((uint8_t *)pkt, + REQUEST_ENTRY_SIZE); +#endif + } + } else /* No scatter gather data transfer */ + { + /* 4.10 32 bit */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer)); + *dword_ptr = (uint32_t) cmd->request_bufflen; +#else + dma_handle = pci_map_single(ha->pdev, + cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + sp->saved_dma_handle = dma_handle; + + *dword_ptr++ = cpu_to_le32(pci_dma_lo32(dma_handle)); + *dword_ptr = (uint32_t) cmd->request_bufflen; + /* DEBUG(sprintf(debug_buff, + "32_bit: No S/G map_single dma_handle=%lx len=%x\n\r",dma_handle,cmd->request_bufflen)); + DEBUG(qla2100_print(debug_buff)); */ +#endif + /* DEBUG5(printk("Single Segment ap=0x%x, len=0x%x\n",cmd->request_buffer,cmd->request_bufflen));*/ + +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print("qla2100_32bit_start_scsi: No scatter/gather command packet data - "); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_BUS_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_TCN_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_LUN_32(cmd), 10); + qla2100_print("\n"); + qla2100_dump_buffer((uint8_t *)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } + else /* No data transfer */ + { + *dword_ptr++ = (uint32_t) 0; + *dword_ptr = (uint32_t) 0; +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print( + "qla2100_32bit_start_scsi: No data, command packet data - "); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_BUS_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_TCN_32(cmd), 10); + qla2100_print(":"); + qla2100_output_number((u_long)SCSI_LUN_32(cmd), 10); + qla2100_print("\n"); + qla2100_dump_buffer((uint8_t *)pkt, REQUEST_ENTRY_SIZE); +#endif + } + /* Adjust ring index. */ + ha->req_ring_index++; + if( ha->req_ring_index == REQUEST_ENTRY_CNT ) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + /* Set chip new ring index. */ + DEBUG4(qla2100_print("\nqla2100_32bit_start_scsi: Wakeup RISC for pending command\n\r")); + ha->qthreads--; + sp->flags |= SRB_SENT; + sp->state = 0xde; + ha->actthreads++; + + /* DEBUG(sprintf(debug_buff," Start(pid=%d) ",cmd->pid);) + DEBUG(qla2100_print(debug_buff);) */ + +#if WATCH_THREADS_SIZE + DEBUG3(qla2100_output_number((u_long)ha->actthreads, 16)); +#endif + if (ha->device_id == QLA2300_DEVICE_ID) { + temp = CACHE_FLUSH(®2300->req_q_in); + WRT_REG_WORD(®2300->req_q_in, ha->req_ring_index); + } else { + temp = CACHE_FLUSH(®->mailbox4); + WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + } + } else { + status = 1; + qla2100_stats.outarray_full++; +#ifdef QL_DEBUG_LEVEL_8 + qla2100_print( + "qla2100_32bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n"); +#endif + } + } else { + status = 1; +#ifdef QL_DEBUG_LEVEL_8 + qla2100_print("qla2100_32bit_start_scsi: in-ptr="); + qla2100_output_number((u_long)ha->req_ring_index, 16); + qla2100_print(" req_q_cnt="); + qla2100_output_number((u_long)ha->req_q_cnt, 16); + qla2100_print(" req_cnt="); + qla2100_output_number((u_long)req_cnt, 16); + qla2100_print("\n"); +#endif + } + + /* Release ring specific lock */ + QLA2100_RING_UNLOCK(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_32bit_start_scsi: **** FAILED ****\n"); +#ifdef QL_DEBUG_LEVEL_3 + else qla2100_print("qla2100_32bit_start_scsi: exiting normally\n\n\r"); +#endif +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_32bit_start_scsi"); +#endif + COMTRACE('s') + return(status); +} + +/* +* qla2100_ms_req_pkt +* Function is responsible for locking ring and +* getting a zeroed out Managment Server request packet. +* +* Input: +* ha = adapter block pointer. +* sp = srb_t pointer to handle post function call +* Returns: +* 0 = failed to get slot. +*/ +STATIC request_t * +qla2100_ms_req_pkt(scsi_qla_host_t *ha, srb_t *sp) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + request_t *pkt = 0; + uint16_t cnt,i; + uint32_t *dword_ptr; + uint32_t timer; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_ms_req_pkt"); +#endif + + /* Wait for 30 seconds for slot. */ + for( timer = 3000000; timer; timer-- ) { + /* Acquire ring specific lock */ + QLA2100_RING_LOCK(ha); + + if( !ha->req_q_cnt ) { + /* Calculate number of free request entries. */ + if (ha->device_id == QLA2300_DEVICE_ID) cnt = qla2100_debounce_register(®2300->req_q_out); + else cnt = qla2100_debounce_register(®->mailbox4); + if( ha->req_ring_index < cnt ) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); + } + + /* Check for room in outstanding command list. */ + for( cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && + (ha->outstanding_cmds[cnt] != 0); cnt++ ) + ; + + if( (cnt < MAX_OUTSTANDING_COMMANDS) && + ( ha->req_q_cnt != 0 )) { + + pkt = ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for( i = 0; i < REQUEST_ENTRY_SIZE/4; i++ ) + *dword_ptr++ = 0; + + DEBUG(sprintf(debug_buff, + "qla2100_ms_req: putting sp=%x in outstanding_cmds[%x]\n",sp,cnt)); + DEBUG(qla2100_print(debug_buff)); + + ha->outstanding_cmds[cnt] = sp; + /* save the handle */ + CMD_HANDLE(sp->cmd) = (unsigned char *) (u_long) cnt; + + ha->req_q_cnt--; + pkt->handle = (uint32_t)cnt; + + /* Set system defined field. */ + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->entry_status = 0; + + break; + } + + /* Release ring specific lock */ + QLA2100_RING_UNLOCK(ha); + + SYS_DELAY(2); + + /* Check for pending interrupts. */ + qla2100_poll(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( !pkt ) + qla2100_print("qla2100_ms_req_pkt: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_ms_req_pkt"); +#endif + return(pkt); +} + + +/* +* qla2100_req_pkt +* Function is responsible for locking ring and +* getting a zeroed out request packet. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = failed to get slot. +*/ +STATIC request_t * +qla2100_req_pkt(scsi_qla_host_t *ha) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + request_t *pkt = 0; + uint16_t cnt; + uint32_t *dword_ptr; + uint32_t timer; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_req_pkt"); +#endif + + /* Wait for 30 seconds for slot. */ + for( timer = 3000000; timer; timer-- ) { + /* Acquire ring specific lock */ + QLA2100_RING_LOCK(ha); + + if( !ha->req_q_cnt ) { + /* Calculate number of free request entries. */ + if (ha->device_id == QLA2300_DEVICE_ID) cnt = qla2100_debounce_register(®2300->req_q_out); + else cnt = qla2100_debounce_register(®->mailbox4); + if( ha->req_ring_index < cnt ) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); + } + + /* Found empty request ring slot? */ + if( ha->req_q_cnt ) { + ha->req_q_cnt--; + pkt = ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for( cnt = 0; cnt < REQUEST_ENTRY_SIZE/4; cnt++ ) + *dword_ptr++ = 0; + + /* Set system defined field. */ + pkt->sys_define = (uint8_t)ha->req_ring_index; + + /* Set entry count. */ + pkt->entry_count = 1; + + break; + } + + /* Release ring specific lock */ + QLA2100_RING_UNLOCK(ha); + + SYS_DELAY(2); /* 10 */ + + /* Check for pending interrupts. */ + qla2100_poll(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( !pkt ) + qla2100_print("qla2100_req_pkt: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_req_pkt"); +#endif + return(pkt); +} + +/* +* qla2100_isp_cmd +* Function is responsible for modifying ISP input pointer. +* Releases ring lock. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_isp_cmd(scsi_qla_host_t *ha) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_isp_cmd"); +#endif + +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print("qla2100_isp_cmd: IOCB data:\n"); + qla2100_dump_buffer((uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE); +#endif + + /* Adjust ring index. */ + ha->req_ring_index++; + if( ha->req_ring_index == REQUEST_ENTRY_CNT ) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + /* Set chip new ring index. */ + if (ha->device_id == QLA2300_DEVICE_ID) WRT_REG_WORD(®2300->req_q_in, ha->req_ring_index); + else WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + + /* Release ring specific lock */ + QLA2100_RING_UNLOCK(ha); + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_isp_cmd"); +#endif +} + +/* +* qla2100_enable_lun +* Issue enable LUN entry IOCB. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_enable_lun(scsi_qla_host_t *ha) { + elun_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_enable_lun"); +#endif + + /* Get request packet. */ + if( (pkt = (elun_entry_t *)qla2100_req_pkt(ha)) != NULL ) { + pkt->entry_type = ENABLE_LUN_TYPE; + pkt->command_count = 32; + pkt->immed_notify_count = 1; + pkt->timeout = 0xffff; + + /* Issue command to ISP */ + qla2100_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( !pkt ) + qla2100_print("qla2100_enable_lun: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_enable_lun"); +#endif +} + + + +#if QL2100_TARGET_MODE_SUPPORT +/****************************************************************************/ +/* Target Mode Support Functions. */ +/****************************************************************************/ + + +/* +* qla2100_notify_ack +* Issue notify acknowledge IOCB. +* If sequence ID is zero, acknowledgement of +* SCSI bus reset or bus device reset is assumed. +* +* Input: +* ha = adapter block pointer. +* inotify = immediate notify entry pointer. +*/ +STATIC void +qla2100_notify_ack(scsi_qla_host_t *ha, notify_entry_t *inotify) { + nack_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_notify_ack: entered\n"); +#endif + + /* Get request packet. */ + if( pkt = (nack_entry_t *)qla2100_req_pkt(ha) ) { + pkt->entry_type = NOTIFY_ACK_TYPE; + pkt->initiator_id = inotify->initiator_id; + pkt->target_id = inotify->target_id; + + if( (pkt->status = inotify->status) == 0xe ) + /* Reset LIP occurred. */ + pkt->flags = OF_RESET; + else + /* Increment Immediate Notify Resource Count. */ + pkt->flags = OF_INC_RC; + + pkt->task_flags = inotify->task_flags; + pkt->seq_id = inotify->seq_id; + + /* Issue command to ISP */ + qla2100_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( !pkt ) + qla2100_print("qla2100_notify_ack: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_notify_ack: exiting normally\n"); +#endif +} + +/* +* qla2100_64bit_continue_io +* Issue continue target I/O IOCB. +* +* Input: +* ha = adapter block pointer. +* atio = atio pointer. +* len = total bytecount. +* addr = physical address pointer. +*/ +STATIC void +qla2100_64bit_continue_io(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len, + u_long *addr) { + ctio_a64_entry_t *pkt; + uint32_t *dword_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_64bit_continue_io: entered\n"); +#endif + + /* Get request packet. */ + if( pkt = (ctio_a64_entry_t *)qla2100_req_pkt(ha) ) { + pkt->entry_type = CTIO_A64_TYPE; + pkt->initiator_id = atio->initiator_id; + pkt->exchange_id = atio->exchange_id; + pkt->flags = atio->flags | OF_FAST_POST; + pkt->scsi_status = atio->scsi_status; + + if( len ) { + pkt->dseg_count = 1; + pkt->transfer_length = len; + pkt->dseg_0_length = len; + dword_ptr = (uint32_t *)addr; + pkt->dseg_0_address[0] = *dword_ptr++; + pkt->dseg_0_address[1] = *dword_ptr; + } + + /* Issue command to ISP */ + qla2100_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( !pkt ) + qla2100_print("qla2100_64bit_continue_io: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_64bit_continue_io: exiting normally\n"); +#endif +} + +/* +* qla2100_32bit_continue_io +* Issue continue target I/O IOCB. +* +* Input: +* ha = adapter block pointer. +* atio = atio pointer. +* len = total bytecount. +* addr = physical address pointer. +*/ +STATIC void +qla2100_32bit_continue_io(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len, + u_long *addr) { + ctio_entry_t *pkt; + uint32_t *dword_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_continue_io: entered\n"); +#endif + + /* Get request packet. */ + if( pkt = (ctio_entry_t *)qla2100_req_pkt(ha) ) { + pkt->entry_type = CONTINUE_TGT_IO_TYPE; + pkt->initiator_id = atio->initiator_id; + pkt->exchange_id = atio->exchange_id; + pkt->flags = atio->flags | OF_FAST_POST; + pkt->scsi_status = atio->scsi_status; + + if( len ) { + pkt->dseg_count = 1; + pkt->transfer_length = len; + pkt->dseg_0_length = len; + dword_ptr = (uint32_t *)addr; + pkt->dseg_0_address = *dword_ptr; + } + + /* Issue command to ISP */ + qla2100_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( !pkt ) + qla2100_print("qla2100_32bit_continue_io: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_32bit_continue_io: exiting normally\n"); +#endif +} +#endif /* QL2100_TARGET_MODE_SUPPORT */ + + + +/****************************************************************************/ +/* Interrupt Service Routine. */ +/****************************************************************************/ + +/* +* qla2100_isr +* Calls I/O done on command completion. +* +* Input: +* ha = adapter block pointer. +* done_q_first = done queue first pointer. +* done_q_last = done queue last pointer. +* INTR_LOCK must be already obtained. +*/ +STATIC void +qla2100_isr(scsi_qla_host_t *ha, srb_t **done_q_first, srb_t **done_q_last) { + device_reg_t *reg = ha->iobase; + device2300_reg_t *reg2300 = ha->iobase2300; + response_t *pkt, response_entry; + srb_t *sp; + uint16_t mailbox[MAILBOX_REGISTER_COUNT]; + uint16_t *wptr, status2 = 0; + uint32_t index, longstatus, *dptr1, *dptr2; + unsigned long cpu_flags = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_isr"); +#endif + if (ha->device_id != QLA2300_DEVICE_ID) { + /* Check for 2100/2200 mailbox interrupt (semaphore set) */ + longstatus = RD_REG_WORD(®->semaphore); + if (longstatus & BIT_0) status2 = SEMAPHORE_SET; + } else { + /* Get 2300's Interrupt Status byte */ + longstatus = RD_REG_DWORD(®2300->host_status); +/*#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + DEBUG(qla2100_print("qla2100_isr: +++ 2300 RISC_TO_HOST reg= ");) + DEBUG(qla2100_output_number((u_long)longstatus, 16);) + DEBUG(qla2100_print(" +++ \n");) +#endif */ + switch(longstatus & 0xff) { + case 0x1: + case 0x2: + case 0x10: + case 0x11: + case 0x12: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + status2 = SEMAPHORE_SET; + break; + case 0x13: + default: + status2 = 0; + break; + } + } + + if ( status2 == SEMAPHORE_SET ) { + + /* Get mailbox data. */ + wptr = &mailbox[0]; + if (ha->device_id != QLA2300_DEVICE_ID) { + *wptr++ = qla2100_debounce_register(®->mailbox0); + *wptr++ = RD_REG_WORD(®->mailbox1); + *wptr = RD_REG_WORD(®->mailbox2); + } else { + *wptr++ = qla2100_debounce_register(®2300->mailbox0); + *wptr++ = RD_REG_WORD(®2300->mailbox1); + *wptr = RD_REG_WORD(®2300->mailbox2); + } + + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + +#if defined(QL_DEBUG_LEVEL_4) +DEBUG(qla2100_print("qla2100_isr: SEMAPHORE SET Processing, mailbox[0]=");) +DEBUG(qla2100_output_number((u_long)mailbox[0], 16);) +DEBUG(qla2100_print(" \n");) +DEBUG(qla2100_print("qla2100_isr: mailbox[1]=");) +DEBUG(qla2100_output_number((u_long)mailbox[1], 16);) +DEBUG(qla2100_print(" \n");) +DEBUG(qla2100_print("qla2100_isr: mailbox[2]=");) +DEBUG(qla2100_output_number((u_long)mailbox[2], 16);) +DEBUG(qla2100_print(" \n");) +DEBUG(qla2100_print("qla2100_isr: mailbox[3]=");) +DEBUG(qla2100_output_number((u_long)mailbox[3], 16);) +DEBUG(qla2100_print(" \n");) +#endif + +#ifdef FC_IP_SUPPORT /*******************************************/ + /* Handle IP send fast post */ + if (mailbox[0] == MBA_IP_TRANSMIT_COMPLETE) { + SEND_CB *pSendCB; + + /* Clear the semaphore lock , if it was set */ + if (RD_REG_WORD(®->semaphore) & BIT_0) + WRT_REG_WORD(®->semaphore, 0); + + /* Validate cmd handle and get packet pointer */ + if (mailbox[1] < MAX_SEND_PACKETS) { + if ((pSendCB = (SEND_CB *)ha->apActiveIpQueue[mailbox[1]]) != NULL) { + ha->apActiveIpQueue[mailbox[1]] = NULL; + + /* Complete backdoor command */ + (*ha->pSendCompletionRoutine)(pSendCB); + + return; + } + } + + /* Invalid handle from RISC, reset RISC firmware */ + printk(KERN_WARNING "qla2100_isr: bad IP send fast post handle %x\n", + mailbox[1]); + ha->flags.isp_abort_needed = TRUE; + return; + } + + /* Handle IP receive fast post */ + else if (mailbox[0] == MBA_IP_RECEIVE_COMPLETE || + mailbox[0] == MBA_IP_RECEIVE_COMPLETE_SPLIT) { + PBUFFER_CB pBufferCB, pNextBufferCB; + uint32_t lTagVal; + uint32_t lPacketSize; + uint32_t lReceiveBufferSize; + volatile uint16_t *pNextMailbox; + uint16_t wBufferCount; + + pNextMailbox = ®->mailbox10; + + /* If split buffer, set header size for 1st buffer */ + if (mailbox[0] == MBA_IP_RECEIVE_COMPLETE_SPLIT) + lReceiveBufferSize = ha->wHeaderSize; + else + lReceiveBufferSize = ha->lReceiveBufferSize; + + if ((lTagVal = RD_REG_WORD(pNextMailbox)) >= ha->wReceiveBufferCount) { + goto InvalidIpBufferHandle; + } + + pBufferCB = &ha->pReceiveBufferCBs[lTagVal]; + + if (!(pBufferCB->lFlags & BCB_FLAGS_RISC_OWNS_BUFFER)) { + goto InvalidIpBufferHandle; + } + + /* Set buffer belongs to driver now */ + pBufferCB->lFlags &= ~BCB_FLAGS_RISC_OWNS_BUFFER; + + lPacketSize = RD_REG_WORD(®->mailbox3); + pBufferCB->lPacketSize = lPacketSize; + pNextBufferCB = pBufferCB; + + for (wBufferCount = 1; ; wBufferCount++) { + if (lPacketSize > lReceiveBufferSize) { + pNextBufferCB->lBufferSize = lReceiveBufferSize; + lPacketSize -= lReceiveBufferSize; + + /* If split buffer, only use header size on 1st buffer */ + lReceiveBufferSize = ha->lReceiveBufferSize; + + pNextMailbox++; + if ((lTagVal = RD_REG_WORD(pNextMailbox)) >= + ha->wReceiveBufferCount) { + InvalidIpBufferHandle: + printk(KERN_WARNING "qla2100_isr: bad IP receive fast post handle %x\n", + lTagVal); + ha->flags.isp_abort_needed = TRUE; + return; + } + + pNextBufferCB->pNextBufferCB = &ha->pReceiveBufferCBs[lTagVal]; + pNextBufferCB = pNextBufferCB->pNextBufferCB; + + if (!(pNextBufferCB->lFlags & BCB_FLAGS_RISC_OWNS_BUFFER)) { + goto InvalidIpBufferHandle; + } + + /* Set buffer belongs to driver now */ + pNextBufferCB->lFlags &= ~BCB_FLAGS_RISC_OWNS_BUFFER; + } else { + pNextBufferCB->lBufferSize = lPacketSize; + pNextBufferCB->pNextBufferCB = NULL; + break; + } + } + + /* Clear the semaphore lock , if it was set */ + if (RD_REG_WORD(®->semaphore) & BIT_0) + WRT_REG_WORD(®->semaphore, 0); + + /* Pass received packet to IP driver */ + pBufferCB->wBufferCount = wBufferCount; + + (*ha->pReturnReceivePacketsRoutine) + (ha->pReturnReceivePacketsContext, + pBufferCB); + + /* Keep track of RISC buffer pointer (for IP reinit) */ + ha->wIpBufferOut += wBufferCount; + if (ha->wIpBufferOut >= IP_BUFFER_QUEUE_DEPTH) + ha->wIpBufferOut -= IP_BUFFER_QUEUE_DEPTH; + + return; + } +#endif /* FC_IP_SUPPORT ****************************************8*/ + + if( mailbox[0] != MBA_SCSI_COMPLETION ) { +#ifdef QL_DEBUG_LEVEL_4 + qla2100_print("qla2100_isr: non MBA_SCSI_COMPLETION ; Saving mailbox data\n"); +#endif + wptr++; + if (ha->device_id != QLA2300_DEVICE_ID) { + *wptr++ = RD_REG_WORD(®->mailbox3); + *wptr++ = qla2100_debounce_register(®->mailbox4); + *wptr++ = qla2100_debounce_register(®->mailbox5); + *wptr++ = RD_REG_WORD(®->mailbox6); + *wptr = RD_REG_WORD(®->mailbox7); + } else { + *wptr++ = RD_REG_WORD(®2300->mailbox3); + *wptr++ = qla2100_debounce_register(®2300->mailbox4); + *wptr++ = qla2100_debounce_register(®2300->mailbox5); + *wptr++ = RD_REG_WORD(®2300->mailbox6); + *wptr = RD_REG_WORD(®2300->mailbox7); + } + } + + /* Clear the semaphore lock , if it was set */ + if (RD_REG_WORD(®->semaphore) & BIT_0) + WRT_REG_WORD(®->semaphore, 0); + +#ifdef QL_DEBUG_LEVEL_4 + qla2100_print("qla2100_isr: +++ mailbox interrupt mailbox[0] = "); + qla2100_output_number((u_long)mailbox[0], 16); + qla2100_print("+++ \n"); + #endif + /* Handle asynchronous (0x80xx) and + mailbox command completion (0x400x) events */ + switch( mailbox[0] ) { + case MBA_SCSI_COMPLETION: /* 0x8020 */ + if( ha->flags.online ) { + /* Get outstanding command index. */ + index = (uint32_t)(mailbox[2] << 16 | mailbox[1]); + /* Validate handle. */ + if( index < MAX_OUTSTANDING_COMMANDS ) { + sp = ha->outstanding_cmds[index]; + } else + sp = 0; + + if( sp ) { + /* Free outstanding command slot. */ + ha->outstanding_cmds[index] = 0; + + /* Save ISP completion status */ + CMD_RESULT(sp->cmd) = DID_OK; + sp->flags &= ~SRB_SENT; + /* v2.19.5b2 Reset port down retry on success. */ + sp->port_down_retry_count = ha->port_down_retry_count; + + QLA2100_TIMER_LOCK(ha); + ha->actthreads--; + /* Place block on done queue */ + qla2100_stats.done_q_cnt++; + DEBUG(sp->state = 3;) + + sp->s_next = NULL; + sp->s_prev = *done_q_last; + if( !(*done_q_first) ) + *done_q_first = sp; + else + (*done_q_last)->s_next = sp; + *done_q_last = sp; + QLA2100_TIMER_UNLOCK(ha); + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: ISP invalid handle\n"); +#endif + ha->flags.isp_abort_needed = TRUE; + } + } + break; + case MBA_RESET: /* Reset 0x8001*/ +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: asynchronous RESET\n"); +#endif + ha->flags.reset_marker = TRUE; + break; + case MBA_SYSTEM_ERR: /* System Error 0x8002 */ +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: ISP System Error - mbx1="); + qla2100_output_number((u_long)mailbox[1], 16); + qla2100_print(", mbx2="); + qla2100_output_number((u_long)mailbox[2], 16); + qla2100_print(", mbx3="); + qla2100_output_number((u_long)mailbox[3], 16); + qla2100_print("\n"); +#endif + printk(KERN_WARNING + "!qla2100_isr: ISP System Error - mbx1=%xh, mbx2=%xh, mbx3=%xh", + mailbox[1], mailbox[2], mailbox[3]); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: ISP Request Transfer Error\n"); +#endif + printk(KERN_WARNING "qla2100: ISP Request Transfer Error\n"); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: ISP Response Transfer Error\n"); +#endif + printk(KERN_WARNING "qla2100: ISP Response Transfer Error\n"); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: asynchronous WAKEUP_THRES\n"); +#endif + break; + case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ + if(!qla2100_quiet) printk(KERN_INFO "scsi(%d): LIP occurred.\n",(int)ha->host_no); + DEBUG(sprintf(debug_buff,"\n\nscsi(%d): LIP occurred.\n",(int)ha->host_no);) + DEBUG(qla2100_print(debug_buff)); +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_isr: asynchronous MBA_LIP_OCCURRED\n"); +#endif + ha->dpc_flags = ha->dpc_flags | COMMAND_WAIT_NEEDED; + /* Save LIP sequence. */ + ha->lip_seq = mailbox[1]; + if( ha->loop_state != LOOP_DOWN ) { + ha->loop_state = LOOP_DOWN; + ha->loop_down_timer = LOOP_DOWN_TIME; + } + ha->lip_count++; + break; + case MBA_LOOP_UP: + printk(KERN_INFO "scsi(%d): LOOP UP detected\n",(int)ha->host_no); +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: asynchronous MBA_LOOP_UP\n"); +#endif + ha->loop_state = LOOP_UP; + break; + case MBA_LOOP_DOWN: + printk(KERN_INFO "scsi(%d): LOOP DOWN detected\n",(int)ha->host_no); +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: asynchronous MBA_LOOP_DOWN\n"); +#endif + ha->dpc_flags = ha->dpc_flags | COMMAND_WAIT_NEEDED; + if( ha->loop_state != LOOP_DOWN ) { + ha->loop_state = LOOP_DOWN; + ha->loop_down_timer = LOOP_DOWN_TIME; + } + break; + case MBA_LIP_RESET: /* LIP reset occurred. */ + if(!qla2100_quiet) printk(KERN_INFO "scsi(%d): LIP reset occurred\n",(int)ha->host_no); +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_isr: asynchronous MBA_LIP_RESET\n"); +#endif + ha->dpc_flags = ha->dpc_flags | COMMAND_WAIT_NEEDED; + ha->flags.reset_marker = TRUE; + ha->loop_down_timer = LOOP_DOWN_TIME; + ha->loop_state = LOOP_DOWN; + ha->operating_mode = LOOP; + break; + case MBA_LINK_MODE_UP: /* Link mode up. */ + DEBUG(printk(KERN_INFO "scsi(%d): Link node is up\n",(int)ha->host_no);) +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_isr: asynchronous MBA_LINK_MODE_UP\n"); +#endif + ha->dpc_flags = ha->dpc_flags | COMMAND_WAIT_NEEDED; + break; + case MBA_UPDATE_CONFIG: /* Update Configuration. */ + printk(KERN_INFO "scsi(%d): Configuration change detected: value %d.\n",(int)ha->host_no,mailbox[1]); +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_isr: asynchronous MBA_UPDATE_CONFIG\n"); +#endif + ha->flags.update_config_needed = 1; + ha->loop_state = LOOP_DOWN; /* dg - 03/30 */ + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_PORT_UPDATE: /* Port database update occurred. */ + DEBUG(printk("scsi(%d): Port database changed\n",(int)ha->host_no);) +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_isr: asynchronous MBA_PORT_UPDATE\n"); +#endif + ha->loop_down_timer = 0; + ha->flags.loop_resync_needed = TRUE; + ha->loop_state = LOOP_UPDATE; + break; + case MBA_SCR_UPDATE: /* State Change Registration. */ +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_isr: asynchronous MBA_RSCR_UPDATE\n"); +#endif + mailbox[1] = RD_REG_WORD(®->mailbox1); + mailbox[2] = RD_REG_WORD(®->mailbox2); + + DEBUG(printk("scsi(%d): RSCN database changed - 0x%x,0x%x\n",(int)ha->host_no,mailbox[1],mailbox[2]);) +#ifdef RCSN + index = ha->rscn_in_ptr + 1; + if (index == MAX_RSCN_COUNT) + index = 0; + if (index != ha->rscn_out_ptr) { + ha->rscn_queue[ha->rscn_in_ptr].format = + MSB(mb[1]); + ha->rscn_queue[ha->rscn_in_ptr].d_id.b.domain = + LSB(mb[1]); + ha->rscn_queue[ha->rscn_in_ptr].d_id.b.area = + MSB(mb[2]); + ha->rscn_queue[ha->rscn_in_ptr].d_id.b.al_pa = + LSB(mb[2]); + ha->rscn_in_ptr = (uint8_t)index; + } else { + ha->device_flags |= RSCN_QUEUE_OVERFLOW; + } +#endif + ha->device_flags |= RSCN_UPDATE; + ha->loop_down_timer = 0; + ha->flags.loop_resync_needed = TRUE; + ha->loop_state = LOOP_UPDATE; + /* ha->dpc_flags = ha->dpc_flags | COMMAND_WAIT_NEEDED; */ + break; + case MBA_CTIO_COMPLETION: +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_isr: asynchronous MBA_CTIO_COMPLETION\n"); +#endif + break; + default: + if( mailbox[0] < MBA_ASYNC_EVENT /* 0x8000 */) { + wptr = &mailbox[0]; + ha->mailbox_out[0] = *wptr++; + ha->mailbox_out[1] = *wptr++; + ha->mailbox_out[2] = *wptr++; + ha->mailbox_out[3] = *wptr++; + ha->mailbox_out[4] = *wptr++; + ha->mailbox_out[5] = *wptr++; + ha->mailbox_out[6] = *wptr++; + ha->mailbox_out[7] = *wptr; + ha->flags.mbox_int = TRUE; +#ifdef QL_DEBUG_LEVEL_2 + if (mailbox[0] != 0x4000) { + qla2100_print("qla2100_isr: MBA Switch Default mailbox[0]= "); + qla2100_output_number(mailbox[0] , 16); + qla2100_print("\n"); + } +#endif +#ifdef QL_DEBUG_LEVEL_4 + qla2100_print("qla2100_isr: Setting flags.mbox_int=1 in Default mailbox[0]= "); + qla2100_output_number(mailbox[0] , 16); + qla2100_print("\n"); +#endif + } + break; + } /* switch */ + } else { /* not a SEMAPHORE Set Completion */ + if (ha->device_id != QLA2300_DEVICE_ID) + mailbox[5]=qla2100_debounce_register(®->mailbox5); + else + mailbox[5]=qla2100_debounce_register(®2300->rsp_q_in); + + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + /* + * Response Ring Update + */ + /* Clear mailbox busy flag for 2300s; + so we don't ignore its Respose Ring Updates + during send of mailbox command */ + if (ha->device_id == QLA2300_DEVICE_ID) + ha->flags.mbox_busy = FALSE; + + if( ha->flags.online && !(ha->flags.mbox_busy) ) { + if( mailbox[5] < RESPONSE_ENTRY_CNT ) { + while( ha->rsp_ring_index != mailbox[5] ) { + pkt = ha->response_ring_ptr; + +#ifdef QL_DEBUG_LEVEL_5 + qla2100_print("qla2100_isr: ha->rsp_ring_index = "); + qla2100_output_number((u_long)ha->rsp_ring_index, 16); + qla2100_print(" mailbox[5] = "); + qla2100_output_number((u_long)mailbox[5], 16); + qla2100_print("\n"); + qla2100_print("\nqla2100_isr: response packet data\n"); + qla2100_dump_buffer((uint8_t *)pkt, RESPONSE_ENTRY_SIZE); +#endif + +#ifdef FC_IP_SUPPORT /************************************************/ + /* Handle IP send completion */ + if (pkt->entry_type == ET_IP_COMMAND_64) { + uint32_t lTagVal; + SEND_CB *pSendCB; + + /* Set packet pointer from queue entry handle */ + if ((lTagVal = pkt->handle) < MAX_SEND_PACKETS) { + if ((pSendCB = (SEND_CB *)ha->apActiveIpQueue[lTagVal]) != NULL) { + ha->apActiveIpQueue[lTagVal] = NULL; + + /* Return send packet to IP driver */ + (*ha->pSendCompletionRoutine)(pSendCB); + } else { + /* Invalid handle from RISC, reset RISC firmware */ + printk(KERN_WARNING "qla2100_isr: bad IP send handle %x\n", lTagVal); + ha->flags.isp_abort_needed = TRUE; + } + } else { + /* Invalid handle from RISC, reset RISC firmware */ + printk(KERN_WARNING "qla2100_isr: bad IP send handle %x\n", lTagVal); + ha->flags.isp_abort_needed = TRUE; + } + + /* Adjust ring index. */ + ha->rsp_ring_index++; + if( ha->rsp_ring_index == RESPONSE_ENTRY_CNT ) { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } else + ha->response_ring_ptr++; + if (ha->device_id != QLA2300_DEVICE_ID) + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + else + WRT_REG_WORD(®2300->rsp_q_out, ha->rsp_ring_index); + continue; + } + + /* Handle IP receive packet */ + else if (pkt->entry_type == ET_IP_RECEIVE) { + PIP_RECEIVE_ENTRY pIpReceiveEntry = (PIP_RECEIVE_ENTRY)pkt; + PBUFFER_CB pBufferCB, pNextBufferCB; + uint32_t lTagVal; + uint32_t lPacketSize; + uint16_t wBufferCount; + uint32_t lReceiveBufferSize; + + /* If split buffer, set header size for 1st buffer */ + if (pIpReceiveEntry->wCompletionStatus & IP_REC_STATUS_SPLIT_BUFFER) + lReceiveBufferSize = ha->wHeaderSize; + else + lReceiveBufferSize = ha->lReceiveBufferSize; + + if ((lTagVal = pIpReceiveEntry->waBufferHandle[0]) >= + ha->wReceiveBufferCount) { + /* Invalid handle from RISC, reset RISC firmware */ + printk(KERN_WARNING "qla2100_isr: bad IP buffer handle %x\n", lTagVal); + ha->flags.isp_abort_needed = TRUE; + goto InvalidIpHandle; + } + pBufferCB = &ha->pReceiveBufferCBs[lTagVal]; + + if (!(pBufferCB->lFlags & BCB_FLAGS_RISC_OWNS_BUFFER)) { + /* Invalid handle from RISC, reset RISC firmware */ + printk(KERN_WARNING "qla2100_isr: bad IP buffer handle %x\n", lTagVal); + ha->flags.isp_abort_needed = TRUE; + goto InvalidIpHandle; + } + + /* Set buffer belongs to driver now */ + pBufferCB->lFlags &= ~BCB_FLAGS_RISC_OWNS_BUFFER; + + lPacketSize = pIpReceiveEntry->wSequenseLength; + pBufferCB->lPacketSize = lPacketSize; + pNextBufferCB = pBufferCB; + + for (wBufferCount = 1; ; wBufferCount++) { + if (lPacketSize > lReceiveBufferSize) { + pNextBufferCB->lBufferSize = lReceiveBufferSize; + lPacketSize -= lReceiveBufferSize; + + /* If split buffer, only use header size on 1st buffer */ + lReceiveBufferSize = ha->lReceiveBufferSize; + + if ((lTagVal = pIpReceiveEntry->waBufferHandle[wBufferCount]) >= + ha->wReceiveBufferCount) { + /* Invalid handle from RISC, reset RISC firmware */ + printk(KERN_WARNING "qla2100_isr: bad IP buffer handle %x\n", lTagVal); + ha->flags.isp_abort_needed = TRUE; + goto InvalidIpHandle; + } + pNextBufferCB->pNextBufferCB = &ha->pReceiveBufferCBs[lTagVal];; + pNextBufferCB = pNextBufferCB->pNextBufferCB; + + if (!(pNextBufferCB->lFlags & BCB_FLAGS_RISC_OWNS_BUFFER)) { + /* Invalid handle from RISC, reset RISC firmware */ + printk(KERN_WARNING "qla2100_isr: bad IP buffer handle %x\n", lTagVal); + ha->flags.isp_abort_needed = TRUE; + goto InvalidIpHandle; + } + + /* Set buffer belongs to driver now */ + pNextBufferCB->lFlags &= ~BCB_FLAGS_RISC_OWNS_BUFFER; + } else { + pNextBufferCB->lBufferSize = lPacketSize; + pNextBufferCB->pNextBufferCB = NULL; + break; + } + } + + /* Check for incoming ARP packet with matching IP address */ + if (pIpReceiveEntry->wServiceClass == 0) { + PPACKET_HEADER pPacket = (PPACKET_HEADER)pBufferCB->pBuffer; + PIP_DEVICE_BLOCK pIpDevice; + uint8_t acPortId[3]; + + /* Scan list of IP devices to see if login needed */ + for (pIpDevice = ha->pIpDeviceTop; pIpDevice != NULL; + pIpDevice = pIpDevice->pNextIpDevice) { + if (*(uint16_t *)(&pIpDevice->acWorldWideName[2]) == + pPacket->sNetworkHeader.wSourceAddrHigh && + *(uint32_t *)(&pIpDevice->acWorldWideName[4]) == + pPacket->sNetworkHeader.lSourceAddrLow) { + /* Device already in IP list, skip login */ + goto SkipDeviceLogin; + } + } + + /* Device not in list, need to do login */ + acPortId[0] = pIpReceiveEntry->cS_IDHigh; + acPortId[1] = (uint8_t)(pIpReceiveEntry->wS_IDLow >> 8); + acPortId[2] = (uint8_t)pIpReceiveEntry->wS_IDLow; + + /* Make sure its not a local device */ + if (acPortId[0] == ha->port_id[0] && + acPortId[1] == ha->port_id[1]) { + goto SkipDeviceLogin; + } + + if (qla2x00_add_new_ip_device(ha, PUBLIC_LOOP_DEVICE, + acPortId, + (uint8_t *)&pPacket->sNetworkHeader.wSourceNAA, + TRUE) == QL_STATUS_FATAL_ERROR) { + /* Fatal error, reinitialize */ + ha->flags.isp_abort_needed = TRUE; + } + } + SkipDeviceLogin: + /* Pass received packet to IP driver */ + pBufferCB->wBufferCount = wBufferCount; + + (*ha->pReturnReceivePacketsRoutine) + (ha->pReturnReceivePacketsContext, + pBufferCB); + + /* Keep track of RISC buffer pointer (for IP reinit) */ + ha->wIpBufferOut += wBufferCount; + if (ha->wIpBufferOut >= IP_BUFFER_QUEUE_DEPTH) + ha->wIpBufferOut -= IP_BUFFER_QUEUE_DEPTH; + InvalidIpHandle: + /* Adjust ring index. */ + ha->rsp_ring_index++; + if( ha->rsp_ring_index == RESPONSE_ENTRY_CNT ) { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } else + ha->response_ring_ptr++; + if (ha->device_id != QLA2300_DEVICE_ID) + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + else + WRT_REG_WORD(®2300->rsp_q_out, ha->rsp_ring_index); + continue; + } + + /* Handle IP FARP request */ + else if (pkt->entry_type == ET_IP_FARP_REQUEST) { + PIP_FARP_REQUEST_ENTRY pIpFarpRequestEntry; + uint8_t acPortId[3]; + uint8_t acPortName[8]; + + pIpFarpRequestEntry = (PIP_FARP_REQUEST_ENTRY)pkt; + acPortId[0] = pIpFarpRequestEntry->cRequesterPortIdHigh; + acPortId[1] = (uint8_t)(pIpFarpRequestEntry->wRequesterPortIdLow >> 8); + acPortId[2] = (uint8_t)pIpFarpRequestEntry->wRequesterPortIdLow; + acPortName[0] = pIpFarpRequestEntry->acRequesterPortName[7]; + acPortName[1] = pIpFarpRequestEntry->acRequesterPortName[6]; + acPortName[2] = pIpFarpRequestEntry->acRequesterPortName[5]; + acPortName[3] = pIpFarpRequestEntry->acRequesterPortName[4]; + acPortName[4] = pIpFarpRequestEntry->acRequesterPortName[3]; + acPortName[5] = pIpFarpRequestEntry->acRequesterPortName[2]; + acPortName[6] = pIpFarpRequestEntry->acRequesterPortName[1]; + acPortName[7] = pIpFarpRequestEntry->acRequesterPortName[0]; + + /* Login and add device to IP database */ + if (qla2x00_add_new_ip_device(ha, PUBLIC_LOOP_DEVICE, + acPortId, + acPortName, + TRUE) == QL_STATUS_FATAL_ERROR) { + /* Fatal error, reinitialize */ + ha->flags.isp_abort_needed = TRUE; + } + + /* Adjust ring index. */ + ha->rsp_ring_index++; + if( ha->rsp_ring_index == RESPONSE_ENTRY_CNT ) { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } else + ha->response_ring_ptr++; + if (ha->device_id != QLA2300_DEVICE_ID) + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + else + WRT_REG_WORD(®2300->rsp_q_out, ha->rsp_ring_index); + + continue; + } +#endif /* FC_IP_SUPPORT *******************************************/ + + if( pkt->entry_type == STATUS_TYPE || + pkt->entry_status ) { + ha->actthreads--; + if( pkt->entry_type == STATUS_TYPE ) { + qla2100_status_entry(ha, (sts_entry_t *)pkt, + done_q_first, done_q_last); + /* DEBUG(printk("qla2100_isr: RespRingUpdate STATUS TYPE\n");) */ + } else { + qla2100_error_entry(ha, pkt, + done_q_first, done_q_last); + /* DEBUG(printk("qla2100_isr: RespRingUpdate ERROR TYPE \n");)*/ + } + /* Adjust ring index. */ + ha->rsp_ring_index++; + if( ha->rsp_ring_index == RESPONSE_ENTRY_CNT ) { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } else + ha->response_ring_ptr++; + if (ha->device_id != QLA2300_DEVICE_ID) + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + else + WRT_REG_WORD(®2300->rsp_q_out, ha->rsp_ring_index); + } else { + pkt = &response_entry; + + /* Copy packet. */ + dptr1 = (uint32_t *)ha->response_ring_ptr; + dptr2 = (uint32_t *)pkt; + for( index = 0; index < RESPONSE_ENTRY_SIZE/4; + index++ ) + *dptr2++ = *dptr1++; + + /* Adjust ring index. */ + ha->rsp_ring_index++; + if( ha->rsp_ring_index == RESPONSE_ENTRY_CNT ) { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } else + ha->response_ring_ptr++; + if (ha->device_id != QLA2300_DEVICE_ID) + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + else + WRT_REG_WORD(®2300->rsp_q_out, ha->rsp_ring_index); + + /* Release interrupt specific lock */ + QLA2100_INTR_UNLOCK(ha); + +#if QLA2100_TARGET_MODE_SUPPORT + switch( pkt->entry_type ) { + case ACCEPT_TGT_IO_TYPE: + qla2100_atio_entry(ha, (atio_entry_t *)pkt); + break; + case IMMED_NOTIFY_TYPE: + qla2100_notify_ack(ha, (notify_entry_t *)pkt); + break; + default: + break; + } +#endif /**** FC_TARGET_MODE_SUPPORT */ + + /* Acquire interrupt specific lock */ + QLA2100_INTR_LOCK(ha); + } + } + } else { + ha->flags.isp_abort_needed = TRUE; +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_isr: $$$ Response Pointer Error $$$ mb5=\n"); + qla2100_output_number((u_long)mailbox[5], 16); + qla2100_print(" \n"); + printk(KERN_WARNING "qla2100_isr: [ERROR] Response pointer Error mailbox[5]=%x\n",mailbox[5]); +#endif + } + } + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_isr"); +#endif +} + + + +/* +* qla2100_rst_aen +* Processes asynchronous reset. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_rst_aen(scsi_qla_host_t *ha) { +#if QL2100_TARGET_MODE_SUPPORT + notify_entry_t nentry; +#endif /* QL2100_TARGET_MODE_SUPPORT */ + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_rst_aen"); +#endif + + if( ha->flags.online && !ha->flags.reset_active && + !ha->loop_down_timer && !ha->flags.abort_isp_active ) { + ha->flags.reset_active = TRUE; + do { + ha->flags.reset_marker = FALSE; + + /* Issue marker command. */ + qla2100_marker(ha, 0, 0, 0, MK_SYNC_ALL); + +#if QL2100_TARGET_MODE_SUPPORT + if( !ha->loop_down_timer && !ha->flags.reset_marker ) { + /* Issue notify acknowledgement command. */ + BZERO((caddr_t)&nentry, sizeof(notify_entry_t)); + nentry.initiator_id = ha->id; + /* dg 7/3/99 nentry.target_id = ha->id; */ + nentry.task_flags = BIT_13; + qla2100_notify_ack(ha, &nentry); + } +#endif /* QL2100_TARGET_MODE_SUPPORT */ + }while( !ha->loop_down_timer && ha->flags.reset_marker ); + ha->flags.reset_active = FALSE; + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_rst_aen"); +#endif +} + +#if QLA2100_TARGET_MODE_SUPPORT +/* +* qla2100_atio_entry +* Processes received ISP accept target I/O entry. +* +* Input: +* ha = adapter block pointer. +* pkt = entry pointer. +*/ +STATIC void +qla2100_atio_entry(scsi_qla_host_t *ha, atio_entry_t *pkt) { + uint64_t *a64; + uint64_t *end_a64; + u_long phy_addr[2]; + u_long end_addr[2]; + uint32_t len; + uint32_t offset; + uint8_t t; + uint8_t *sense_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_atio_entry: entered\n"); +#endif + + t = pkt->initiator_id; + sense_ptr = ha->tsense + t * TARGET_SENSE_SIZE; + a64 = (uint64_t *)&phy_addr[0]; + end_a64 = (uint64_t *)&end_addr[0]; + + switch( pkt->status & ~BIT_7 ) { + case 7: /* Path invalid */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla2100_print("qla2100_atio_entry: Path invalid\n"); +#endif + break; + case 0x16: /* Requested Capability Not Available */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla2100_print( + "qla2100_atio_entry: Requested Capability Not Available\n"); +#endif + break; + case 0x17: /* Bus Device Reset Message Received */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla2100_print( + "qla2100_atio_entry: Bus Device Reset Message Received\n"); +#endif + break; + case 0x3D: /* CDB Received */ + + /* Check for invalid LUN */ + if( pkt->lun && pkt->cdb[0] != SS_INQUIR && + pkt->cdb[0] != SS_REQSEN ) + pkt->cdb[0] = SS_TEST; + + switch( pkt->cdb[0] ) { + case SS_TEST: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SS_TEST\n"); +#endif + BZERO(sense_ptr, TARGET_SENSE_SIZE); + len = 0; + if( pkt->lun == 0 ) + pkt->scsi_status = S_GOOD; + else { + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_INVLUN; + pkt->scsi_status = S_CKCON; + } + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | OF_NO_DATA); + break; + case SS_REQSEN: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SS_REQSEN\n"); +#endif + phy_addr[0] = ha->tsense_dma; + phy_addr[1] = 0; + *a64 += t * TARGET_SENSE_SIZE; + if( pkt->cdb[4] > TARGET_SENSE_SIZE ) + len = TARGET_SENSE_SIZE; + else + len = pkt->cdb[4]; + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | OF_DATA_IN); + break; + case SS_INQUIR: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SS_INQUIR\n"); +#endif + BZERO(sense_ptr, TARGET_SENSE_SIZE); + phy_addr[0] = ha->tbuf_dma; + phy_addr[1] = 0; + *a64 += TARGET_INQ_OFFSET; + + if( pkt->lun == 0 ) { + ha->tbuf->inq.id_type = ID_PROCESOR; + ha->tbuf->inq.id_pqual = ID_QOK; + } else { + ha->tbuf->inq.id_type = ID_NODEV; + ha->tbuf->inq.id_pqual = ID_QNOLU; + } + + if( pkt->cdb[4] > sizeof(struct ident) ) + len = sizeof(struct ident); + else + len = pkt->cdb[4]; + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | OF_DATA_IN); + break; + case SM_WRDB: + BZERO(sense_ptr, TARGET_SENSE_SIZE); + offset = pkt->cdb[5]; + offset |= pkt->cdb[4] << 8; + offset |= pkt->cdb[3] << 16; + len = pkt->cdb[8]; + len |= pkt->cdb[7] << 8; + len |= pkt->cdb[6] << 16; + end_addr[0] = phy_addr[0] = ha->tbuf_dma; + end_addr[1] = phy_addr[1] = 0; + *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; + switch( pkt->cdb[1] & 7 ) { + case RW_BUF_HDATA: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SM_WRDB, RW_BUF_HDATA\n"); +#endif + if( len > TARGET_DATA_SIZE + 4 ) { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_WRDB, length > buffer size\n"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + pkt->scsi_status = S_CKCON; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + len = 0; + } else if( len ) { + pkt->scsi_status = S_GOOD; + pkt->flags =(uint16_t)(OF_SSTS | OF_INC_RC | + OF_DATA_OUT); + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_WRDB, zero length\n"); +#endif + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + } + + break; + case RW_BUF_DATA: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SM_WRDB, RW_BUF_DATA\n"); +#endif + *a64 += offset + TARGET_DATA_OFFSET; + if( pkt->cdb[2] != 0 || *a64 >= *end_a64 || + *a64 + len > *end_a64 ) { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_WRDB, RW_BUF_DATA BAD\n"); + qla2100_print("buf_id="); + qla2100_output_number((u_long)pkt->cdb[2], 16); + qla2100_print(", offset="); + qla2100_output_number((u_long)offset, 16); + qla2100_print(", length="); + qla2100_output_number((u_long)len, 16); + qla2100_print("\n"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + } else if( len ) { + pkt->scsi_status = S_GOOD; + pkt->flags =(uint16_t)(OF_SSTS | OF_INC_RC | + OF_DATA_OUT); + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_WRDB, zero length\n"); +#endif + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_WRDB unknown mode\n"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + break; + } + break; + case SM_RDDB: + BZERO(sense_ptr, TARGET_SENSE_SIZE); + offset = pkt->cdb[5]; + offset |= pkt->cdb[4] << 8; + offset |= pkt->cdb[3] << 16; + len = pkt->cdb[8]; + len |= pkt->cdb[7] << 8; + len |= pkt->cdb[6] << 16; + end_addr[0] = phy_addr[0] = ha->tbuf_dma; + end_addr[1] = phy_addr[1] = 0; + *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; + switch( pkt->cdb[1] & 7 ) { + case RW_BUF_HDATA: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SM_RDDB, RW_BUF_HDATA\n"); +#endif + if( len ) { + ha->tbuf->hdr[0] = 0; + ha->tbuf->hdr[1] = + (uint8_t)(TARGET_DATA_SIZE >> 16); + ha->tbuf->hdr[2] = + (uint8_t)(TARGET_DATA_SIZE >> 8); + ha->tbuf->hdr[3] = (uint8_t)TARGET_DATA_SIZE; + if( len > TARGET_DATA_SIZE + 4 ) + len = TARGET_DATA_SIZE + 4; + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_DATA_IN); + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_RDDB, zero length\n"); +#endif + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + } + break; + case RW_BUF_DATA: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SM_RDDB, RW_BUF_DATA\n"); +#endif + *a64 += offset + TARGET_DATA_OFFSET; + if( pkt->cdb[2] != 0 || *a64 >= *end_a64 ) { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_RDDB, RW_BUF_DATA BAD\n"); + qla2100_print("buf_id="); + qla2100_output_number((u_long)pkt->cdb[2], 16); + qla2100_print(", offset="); + qla2100_output_number((u_long)offset, 16); + qla2100_print("\n"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + } else { + if( *a64 + len > *end_a64 ) + len = *end_a64 - *a64; + if( len ) { + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | + OF_INC_RC | OF_DATA_IN); + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_RDDB, zero length\n"); +#endif + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | + OF_INC_RC | OF_NO_DATA); + } + } + break; + case RW_BUF_DESC: +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_atio_entry: SM_RDDB, RW_BUF_DESC\n"); +#endif + if( len ) { + if( len > 4 ) + len = 4; + + ha->tbuf->hdr[0] = 0; + if( pkt->cdb[2] != 0 ) { + ha->tbuf->hdr[1] = 0; + ha->tbuf->hdr[2] = 0; + ha->tbuf->hdr[3] = 0; + } else { + ha->tbuf->hdr[1] = + (uint8_t)(TARGET_DATA_SIZE >> 16); + ha->tbuf->hdr[2] = + (uint8_t)(TARGET_DATA_SIZE >> 8); + ha->tbuf->hdr[3] = + (uint8_t)TARGET_DATA_SIZE; + } + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_DATA_IN); + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_RDDB, zero length\n"); +#endif + pkt->scsi_status = S_GOOD; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: SM_RDDB unknown mode\n"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | + OF_NO_DATA); + break; + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_atio_entry: Unknown SCSI command\n"); + qla2100_dump_buffer((uint8_t *)&pkt->cdb[0], MAX_CMDSZ); +#endif + BZERO(sense_ptr, TARGET_SENSE_SIZE); + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_INVOPCODE; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->flags = (uint16_t)(OF_SSTS | OF_INC_RC | OF_NO_DATA); + break; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + if ( ha->flags.enable_64bit_addressing ) + qla2100_64bit_continue_io(ha, pkt, len, &phy_addr); + else +#endif + qla2100_32bit_continue_io(ha, pkt, len, &phy_addr); + break; + default: + break; + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_atio_entry: exiting normally\n"); +#endif +} +#endif /* QLA2100_TARGET_MODE_SUPPORT */ + +/* +* qla2100_status_entry +* Processes received ISP status entry. +* +* Input: +* ha = adapter block pointer. +* pkt = entry pointer. +* done_q_first = done queue first pointer. +* done_q_last = done queue last pointer. +*/ +STATIC void +qla2100_status_entry(scsi_qla_host_t *ha, sts_entry_t *pkt, srb_t **done_q_first, + srb_t **done_q_last) { + uint32_t b, t, l; + uint8_t sense_sz = 0; + srb_t *sp, *sp2; + scsi_lu_t *q; + Scsi_Cmnd *cp; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_status_entry"); +#endif + /* Validate handle. */ + if( pkt->handle < MAX_OUTSTANDING_COMMANDS ) + sp = ha->outstanding_cmds[pkt->handle]; + else + sp = 0; + + if( sp ) { + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle] = 0; + cp = sp->cmd; + sp->ccode = pkt->comp_status; + sp->scode = pkt->scsi_status; + + sp->flags &= ~SRB_SENT; + /* Generate LU queue on cntrl, target, LUN */ + b = SCSI_BUS_32(cp); + t = SCSI_TCN_32(cp); + l = SCSI_LUN_32(cp); + q = GET_LU_Q(ha, b, t, l); + + /* Target busy */ + if( pkt->scsi_status & SS_BUSY_CONDITION && + (uint8_t)pkt->scsi_status != SS_RESERVE_CONFLICT ) { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_status_entry: SCSI busy status, scsi("); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)b, 10); + qla2100_print(":"); + qla2100_output_number((u_long)t, 10); + qla2100_print(":"); + qla2100_output_number((u_long)l, 10); + qla2100_print(")\n"); +#endif + sp->retry_count--; + CMD_RESULT(cp) = (int) (DID_BUS_BUSY << 16) | + (pkt->scsi_status & 0xff); + + } +#if 0 + /* dg - 03/30 */ + else if( ha->loop_down_timer ) { +#endif + else if( ha->loop_down_timer || + ha->loop_state != LOOP_READY ) { +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("scsi("); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)b, 10); + qla2100_print(":"); + qla2100_output_number((u_long)t, 10); + qla2100_print(":"); + qla2100_output_number((u_long)l, 10); + qla2100_print("): Loop Not ready - pid ="); + qla2100_output_number((u_long)sp->cmd->pid, 16); + qla2100_print("\n"); +#endif + CMD_RESULT(cp) = (int) (DID_BUS_BUSY << 16); + } else if( sp->port_down_retry_count > 1 && + (pkt->comp_status == CS_PORT_UNAVAILABLE || + pkt->comp_status == CS_PORT_LOGGED_OUT || + pkt->comp_status == CS_PORT_CONFIG_CHG || + pkt->comp_status == CS_PORT_BUSY) ) { + /* if the port is unavaliable and we haven't exceeded the port down count */ + /* then send command back to the mid-level. */ +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("scsi("); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)b, 10); + qla2100_print(":"); + qla2100_output_number((u_long)t, 10); + qla2100_print(":"); + qla2100_output_number((u_long)l, 10); + qla2100_print("): Port Down Retry Cnt =("); + qla2100_output_number((u_long)sp->port_down_retry_count, 10); + qla2100_print("): , pid ="); + qla2100_output_number((u_long)sp->cmd->pid, 16); + qla2100_print(", status ="); + qla2100_output_number((u_long)pkt->comp_status, 16); + qla2100_print("\n"); +#endif + sp->port_down_retry_count--; + + /* dg 08/17/99 + * Force the SCSI layer to keep retrying until our + * port_down_retry_count expire. They will normally + * try and reset the bus after half the retries + * have completed, so double the count. + */ + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + + /* Acquire target queue lock */ + if( !(q->q_flag & QLA2100_QSUSP) ) { + q->q_flag |= QLA2100_QSUSP; /* suspend starting new commands */ + + /* Decrement port down count on all pending commands. */ + /* and return them back to OS. */ + for( sp2 = q->q_first; sp2; sp2 = sp2->s_next ) { +#if 0 + if( sp2->port_down_retry_count ) /* dg - v4.31.4 */ + sp2->port_down_retry_count--; +#endif + /* v2.19.14 - unconditionally retry these + * requests. + */ + CMD_RESULT(sp2->cmd) = DID_BUS_BUSY << 16; + qla2100_callback(ha,sp2, TRUE); + } + q->q_first = q->q_last = NULL; + /* if port timer is not active then start it */ + if( !ha->queue_restart_timer ) { + ha->queue_restart_timer = PORT_RETRY_TIME; + } + if( TGT_Q(ha, b, t)->down_timer == 0 ) { + TGT_Q(ha, b, t)->down_timer = + ha->port_down_retry_count * PORT_RETRY_TIME; + } + } + + /* Release LU queue specific lock */ + } else { +#ifdef QL_DEBUG_LEVEL_2 + if( pkt->comp_status ) { + qla2100_print( + "qla2100_status_entry: Compl error = "); + qla2100_output_number((u_long)pkt->comp_status, 16); + qla2100_print(", scsi("); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)b, 10); + qla2100_print(":"); + qla2100_output_number((u_long)t, 10); + qla2100_print(":"); + qla2100_output_number((u_long)l, 10); + qla2100_print("), retry count= "); + qla2100_output_number((u_long)sp->port_down_retry_count, 10); + qla2100_print(", pid = "); + qla2100_output_number((u_long)cp->pid, 16); + qla2100_print("\n"); + } +#endif + /* Set ISP completion status and target status byte. */ + CMD_RESULT(cp) = qla2100_return_status(ha, pkt, cp); + + memset((caddr_t)cp->sense_buffer, 0,sizeof(cp->sense_buffer)); + if( pkt->scsi_status & SS_CHECK_CONDITION ) { + /* Mid-level always zero sense buffer before giving it to us */ + if( pkt->scsi_status & SS_SENSE_LEN_VALID ) { + if( pkt->req_sense_length < CMD_SNSLEN(cp) ) + sense_sz = pkt->req_sense_length; + else + sense_sz = CMD_SNSLEN(cp) - 1; + + BCOPY((caddr_t)&pkt->req_sense_data, cp->sense_buffer, sense_sz); + + } + +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print( + "qla2100_status_entry: Check condition Sense data, scsi("); + qla2100_output_number((u_long)ha->host_no, 10); + qla2100_print(":"); + qla2100_output_number((u_long)b, 10); + qla2100_print(":"); + qla2100_output_number((u_long)t, 10); + qla2100_print(":"); + qla2100_output_number((u_long)l, 10); + qla2100_print(")\n"); + if( sense_sz ) + qla2100_dump_buffer(cp->sense_buffer, sense_sz); +#endif + } + } + /* Place command on done queue. */ + qla2100_done_q_put(ha, sp, done_q_first, done_q_last); + } else { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_status_entry: ISP Invalid handle\n"); +#endif + printk(KERN_WARNING "!qla2100: Status Entry invalid handle"); + ha->flags.isp_abort_needed = TRUE; + } +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_status_entry"); +#endif +} + +/* +* qla2100_error_entry +* Processes error entry. +* +* Input: +* ha = adapter block pointer. +* pkt = entry pointer. +* done_q_first = done queue first pointer. +* done_q_last = done queue last pointer. +*/ +STATIC void +qla2100_error_entry(scsi_qla_host_t *ha, response_t *pkt, srb_t **done_q_first, + srb_t **done_q_last) { + srb_t *sp; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_error_entry"); +#endif + +#ifdef QL_DEBUG_LEVEL_2 + if( pkt->entry_status & BIT_5 ) + qla2100_print("qla2100_error_entry: Invalid Entry Order\n"); + else if( pkt->entry_status & BIT_4 ) + qla2100_print("qla2100_error_entry: Invalid Entry Count\n"); + else if( pkt->entry_status & BIT_3 ) + qla2100_print("qla2100_error_entry: Invalid Entry Parameter\n"); + else if( pkt->entry_status & BIT_2 ) + qla2100_print("qla2100_error_entry: Invalid Entry Type\n"); + else if( pkt->entry_status & BIT_1 ) + qla2100_print("qla2100_error_entry: Busy\n"); + else + qla2100_print("qla2100_error_entry: UNKNOWN flag error\n"); +#endif + + /* Validate handle. */ + if( pkt->handle < MAX_OUTSTANDING_COMMANDS ) + sp = ha->outstanding_cmds[pkt->handle]; + else + sp = 0; + + if( sp ) { + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle] = 0; + + sp->flags &= ~SRB_SENT; + /* Bad payload or header */ + if( pkt->entry_status & (BIT_5 + BIT_4 + BIT_3 + BIT_2) ) { + /* Bad payload or header, set error status. */ + CMD_RESULT(sp->cmd) = (int) DID_ERROR << 16; + + } else if( pkt->entry_status & BIT_1 && sp->retry_count ) /* FULL flag */ + { + sp->retry_count--; + CMD_RESULT(sp->cmd) = (int) DID_BUS_BUSY << 16; + } else { + /* Set error status. */ + CMD_RESULT(sp->cmd) =(int) DID_ERROR << 16; + } + /* Place command on done queue. */ + qla2100_done_q_put(ha, sp, done_q_first, done_q_last); + } else if( pkt->entry_type == COMMAND_A64_TYPE || + pkt->entry_type == COMMAND_TYPE ) { +#ifdef QL_DEBUG_LEVEL_2 + qla2100_print("qla2100_error_entry: ISP Invalid handle\n"); +#endif + printk(KERN_WARNING "!qla2100: Error Entry invalid handle"); + ha->flags.isp_abort_needed = TRUE; + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_error_entry"); +#endif +} + +/* +* qla2100_abort_isp +* Resets ISP and aborts all outstanding commands. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +STATIC uint8_t +qla2100_abort_isp(scsi_qla_host_t *ha) { + uint16_t cnt; + srb_t *sp; + scsi_lu_t *q; + uint32_t b, t, l; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + uint8_t status = 0; + + ENTER("qla2100_abort_isp"); + + DRIVER_LOCK + ha->flags.isp_abort_needed = FALSE; + if( !ha->flags.abort_isp_active && ha->flags.online ) { + ha->flags.abort_isp_active = TRUE; + ha->flags.online = FALSE; + ha->dpc_flags &= ~COMMAND_WAIT_NEEDED; + ha->dpc_flags &= ~COMMAND_WAIT_ACTIVE; + qla2100_stats.ispAbort++; + ha->isp_aborts++; + ha->sns_retry_cnt = 0; + printk(KERN_INFO + "qla2100: Performing ISP error recovery - ha= %p\n", + (void *) ha); + qla2100_reset_chip(ha); + + if( ha->loop_state != LOOP_DOWN ) { + ha->loop_state = LOOP_DOWN; + ha->loop_down_timer = LOOP_DOWN_TIME; + } + +#ifdef FC_IP_SUPPORT + /* Return all IP send packets */ + for (cnt = 0; cnt < MAX_SEND_PACKETS; cnt++) { + if (ha->apActiveIpQueue[cnt] != NULL) { + (*ha->pSendCompletionRoutine)(ha->apActiveIpQueue[cnt]); + + ha->apActiveIpQueue[cnt] = NULL; + } + } +#endif + + /* Requeue all commands in outstanding command list. */ + for( cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) { + sp = ha->outstanding_cmds[cnt]; + if( sp ) { + ha->outstanding_cmds[cnt] = 0; + /* Generate LU queue on controller, target, LUN */ + b = SCSI_BUS_32(sp->cmd); + t = SCSI_TCN_32(sp->cmd); + l = SCSI_LUN_32(sp->cmd); + if ((q = (scsi_lu_t *)GET_LU_Q(ha, b, t, l))) { + /* Reset outstanding command count. */ + q->q_outcnt = 0; + q->q_flag &= ~QLA2100_QBUSY; + } + /* sp->flags &= ~(SRB_SENT | SRB_TIMEOUT); */ + sp->flags = 0; + /* we need to send the command back to OS */ + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + } + + if( ha->device_id == QLA2100_DEVICE_ID ) + qla2100_nvram_config(ha); + else + qla2200_nvram_config(ha); + + /* v2.19.12 */ + ha->retry_count = ql2xretrycount; + if( !qla2100_configure_loop(ha, TRUE) ) { + ha->flags.reset_marker = FALSE; + + if( !ha->loop_down_timer ) + qla2100_marker(ha, 0, 0, 0, MK_SYNC_ALL); + + ha->flags.online = TRUE; + + /* Enable target response to SCSI bus. */ + if( ha->flags.enable_target_mode ) + qla2100_enable_lun(ha); + +#ifdef FC_IP_SUPPORT + /* Reenable IP support */ + if (ha->flags.enable_ip) + qla2x00_ip_initialize(ha); +#endif + /* Enable ISP interrupts. */ + qla2100_enable_intrs(ha); + + /* v2.19.5b6 Return all commands */ + qla2100_abort_queues(ha, TRUE); + + /* Restart queues that may have been stopped. */ + ha->flags.abort_isp_active = FALSE; + /* 6/9 if( !ha->loop_down_timer ) */ + qla2100_restart_queues(ha,TRUE); + } else { + printk(KERN_WARNING + "qla2100: ISP error recovery failed, board disabled"); + qla2100_reset_adapter(ha); + qla2100_abort_queues(ha, FALSE); + } + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_abort_isp: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_abort_isp"); +#endif + return(status); +} +/* +* qla2100_restart_watchdog_queue +* Restart device queues. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_restart_watchdog_queue(scsi_qla_host_t *ha) { + srb_t *sp, *sp_next; + + for( sp = ha->retry_q_first; (sp); sp = sp_next ) { + sp_next = sp->s_next; + /* when time expire return request back to OS as BUSY */ + qla2100_timeout_remove(ha, sp); + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + +} + +/* +* qla2100_restart_queues +* Restart device queues. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_restart_queues(scsi_qla_host_t *ha, uint8_t flush) { + scsi_lu_t *q; + uint32_t b, t, l; + srb_t *sp, *sp_next; + srb_t *done_q_first = (srb_t *) NULL; + srb_t *done_q_last = (srb_t *) NULL; + int cnt; + unsigned long cpu_flags = 0; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_restart_queues"); +#endif + + ha->flags.restart_queues_needed = FALSE; + + /* + * start all queues working again. + */ + for( b = 0; b < MAX_BUSES; b++ ) + for( t = 0; t < ha->max_targets; t++ ) { + if( TGT_Q(ha, b, t) == NULL ) + continue; + for( l = 0; l < ha->max_luns; l++ ) { + q = (scsi_lu_t *) GET_LU_Q(ha, b, t, l); + if( q != NULL ) { + q->q_flag &= ~QLA2100_QSUSP; + if( q->q_first ) + qla2100_next(ha, q); + } + } + } + + /* + * Clear out our retry queue + */ + if( flush ) { + for( sp = ha->retry_q_first; (sp); sp = sp_next ) { + sp_next = sp->s_next; + /* when time expire return request back to OS as BUSY */ + qla2100_timeout_remove(ha, sp); + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + qla2100_done_q_put(ha, sp, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + } + + /* Callback everything in done queue */ + cnt = 0; + while( done_q_first ) { + QLA2100_TIMER_LOCK(ha); + /* remove command from done list */ + sp = done_q_first; + if( !(done_q_first = sp->s_next) ) + done_q_last = NULL; + else + (done_q_first)->s_prev = NULL; + cnt++; + qla2100_stats.done_q_cnt--; + DEBUG(sp->state = 5;) + QLA2100_TIMER_UNLOCK(ha); + /* DEBUG(sprintf(debug_buff, + "qla2100_restart_queues: callback pid %d\n", + sp->cmd->pid);) + DEBUG(qla2100_print(debug_buff);) */ + qla2100_callback(ha,sp,FALSE); + } + DEBUG(sprintf(debug_buff,"qla2100_restart_queues: callback %d commands.\n",cnt);) + DEBUG(qla2100_print(debug_buff);) + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_restart_queues"); +#endif +} + +/* +* qla2100_abort_queues +* Abort all commands on device queues. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_abort_queues(scsi_qla_host_t *ha, uint8_t doneqflg) { + scsi_lu_t *q; + uint32_t b, t, l; + srb_t *sp, *sp_next; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_abort_queues"); +#endif + ha->flags.abort_queue_needed = FALSE; + + for( b = 0; b < MAX_BUSES; b++ ) + for( t = 0; t < ha->max_targets; t++ ) { + if( TGT_Q(ha, b, t) == NULL ) + continue; + for( l = 0; l < MAX_LUNS; l++ ) { + q = GET_LU_Q(ha, b, t, l); + if( q != NULL ) { + /* Try to acquire LU queue specific lock */ + /* if( queue is not busy ) + { */ + sp = q->q_first; + q->q_first = q->q_last = NULL; + + while( sp ) { + q->q_incnt--; + sp_next = sp->s_next; + CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; + if ( doneqflg ) { + CMD_HANDLE(sp->cmd) = (unsigned char *) NULL; + qla2100_done_q_put(ha, sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } else + qla2100_callback(ha,sp,FALSE); + sp = sp_next; + } + /* } + else + ha->flags.abort_queue_needed = TRUE; + */ + } + } + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_abort_queues"); +#endif +} + +/* +* qla2100_update_config +* Restart RISC in order to update the connection mode. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +uint8_t +qla2100_update_config(scsi_qla_host_t *ha) { + uint8_t status = 0; + +#ifdef QL_DEBUG_LEVEL_3 + qla2100_print("qla2100_update_config: entered\n"); +#endif + /* Turn-off flag, so we don't get called again */ + ha->flags.update_config_needed = FALSE; + + /* get the new topology */ + qla2100_configure_hba(ha); + + ha->init_cb->additional_firmware_options.connection_options = ha->operating_mode; + DEBUG(printk("qla2100_update_config: Setting new topology to %d\n" , ha->operating_mode);) + + qla2100_reset_chip(ha); + + if( ha->loop_state != LOOP_DOWN ) { + ha->loop_state = LOOP_DOWN; + ha->loop_down_timer = LOOP_DOWN_TIME; + } + + if( !(status = qla2100_configure_loop(ha, TRUE)) ) { + ha->flags.reset_marker = FALSE; + if( !ha->loop_down_timer ) + qla2100_marker(ha, 0, 0, 0, MK_SYNC_ALL); + + ha->flags.online = TRUE; + + /* Enable target response to SCSI bus. */ + if( ha->flags.enable_target_mode ) + qla2100_enable_lun(ha); + + } + + /* Enable ISP interrupts. */ + qla2100_enable_intrs(ha); + /* WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC); */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_update_config: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla2100_print("qla2100_update_config: exiting normally\n"); +#endif + return(status); +} + +/* +* qla2100_loop_resync +* Resync with fibre channel devices. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ +STATIC uint8_t +qla2100_loop_resync(scsi_qla_host_t *ha) { + uint8_t status; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_loop_resync"); +#endif + + ha->loop_state = LOOP_UPDATE; + if( ha->flags.online && !ha->flags.loop_resync_active && + !ha->flags.abort_isp_active ) { + ha->flags.loop_resync_active = TRUE; + if( !(status = qla2100_fw_ready(ha)) ) { + do { + ha->flags.loop_resync_needed = FALSE; + /* v2.19.05b6 */ + ha->loop_state = LOOP_UPDATE; + + /* Issue marker command. */ + qla2100_marker(ha, 0, 0, 0, MK_SYNC_ALL); + + /* Remap devices on Loop. */ + qla2100_update_fc_db(ha, TRUE); + + }while( !ha->loop_down_timer && ha->flags.loop_resync_needed ); + } + ha->flags.loop_resync_active = FALSE; + /* v2.19 - we don't want to call this if we are already + * in the loop resync code + */ + qla2100_restart_queues(ha,TRUE); + } else + status = 0; + + /* Restart queues that may have been stopped. */ + /* 04/10 if( !ha->loop_down_timer ) { + qla2100_restart_queues(ha,TRUE); + } */ + /* v2.19 */ + /* deleted qla2100_restart_queues(ha,TRUE); */ + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if( status ) + qla2100_print("qla2100_loop_resync: **** FAILED ****\n"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla2100_loop_resync"); +#endif + return(status); +} + +/* +* qla2100_debounce_register +* Debounce register. +* +* Input: +* port = register address. +* +* Returns: +* register value. +*/ +STATIC uint16_t +qla2100_debounce_register(volatile uint16_t *addr) { + volatile uint16_t ret; + volatile uint16_t ret2; + + do { + ret = RD_REG_WORD(addr); + ret2 = RD_REG_WORD(addr); + }while( ret != ret2 ); + + return(ret); +} + +/* qla2100_cmd_wait +* Stall driver until all outstanding commands are returned. +* +* Input: +* ha = adapter state pointer. +* +* Return; +* 0 -- Done +* 1 -- continue; +* +* Context: +* Kernel context. +*/ +STATIC uint8_t +qla2100_cmd_wait(scsi_qla_host_t *ha) { + uint16_t index; + uint8_t stat = 1; + + ENTER("qla2200_cmd_wait: started\n"); + + /* Wait for all outstanding commands to be returned. */ + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + if (ha->outstanding_cmds[index] == NULL) + continue; + + /* if command not completed then wait for it */ + if (ha->flags.isp_abort_needed){ + stat = 0; + break; + } + + if( (ha->dpc_flags & COMMAND_WAIT_ACTIVE) && + ha->cmd_wait_cnt-- == 0 ) { + ha->flags.isp_abort_needed = TRUE; + DEBUG(printk("qla2200_cmd_wait: ISP abort %d\n",index);) + } else { + ha->cmd_wait_cnt = 30; + ha->dpc_flags |= COMMAND_WAIT_ACTIVE; + } + + DEBUG5( if( (ha->dpc_flags & COMMAND_WAIT_ACTIVE) ) ) + DEBUG5(printk("qla2200_cmd_wait: on handle %d - cnt %d\n",index,ha->cmd_wait_cnt);) + + } + + if (index == MAX_OUTSTANDING_COMMANDS || + ha->flags.isp_abort_needed) { + ha->dpc_flags &= ~COMMAND_WAIT_NEEDED; + ha->dpc_flags &= ~COMMAND_WAIT_ACTIVE; + stat = 0; + } + return( stat ); +} + +/* +* qla2100_reset_chip +* Reset ISP chip. +* +* Input: +* ha = adapter block pointer. +*/ +STATIC void +qla2100_reset_chip(scsi_qla_host_t *ha) { + uint32_t cnt; + device_reg_t *reg = ha->iobase; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla2100_reset_chip"); +#endif + + /* Disable ISP interrupts. */ + qla2100_disable_intrs(ha); + /* WRT_REG_WORD(®->ictrl, 0); */ + +#if 1 + /* Pause RISC. */ + WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); + for (cnt = 0; cnt < 30000; cnt++) { + if ((RD_REG_WORD(®->host_cmd) & HC_RISC_PAUSE) != 0) + break; + else + udelay(100); + } + + /* Select FPM registers. */ + WRT_REG_WORD(®->ctrl_status, 0x20); + + /* FPM Soft Reset. */ + WRT_REG_WORD(®->fpm_diag_config, 0x100); + + /* Select frame buffer registers. */ + WRT_REG_WORD(®->ctrl_status, 0x10); + + /* Reset frame buffer FIFOs. */ + WRT_REG_WORD(®->fb_cmd, 0xa000); + + /* Select RISC module registers. */ + WRT_REG_WORD(®->ctrl_status, 0); + + /* Reset RISC module. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + + /* Reset ISP semaphore. */ + WRT_REG_WORD(®->semaphore, 0); + + /* Release RISC module. */ + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + + /* Wait for RISC to recover from reset. */ + for (cnt = 0; cnt < 30000; cnt++) { + if (RD_REG_WORD(®->mailbox0) != MBS_BUSY) + break; + else + udelay(100); + } + + /* Disable RISC pause on FPM parity error. */ + WRT_REG_WORD(®->host_cmd, HC_DISABLE_PARITY_PAUSE); +#else + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); + + /* clear mailbox busy */ + ha->flags.mbox_busy = FALSE; + + /* Reset ISP chip. */ + WRT_REG_WORD(®->ctrl_status, ISP_RESET); + + /* + * Delay after reset, for chip to recover. + * Otherwise causes system PANIC + */ + mdelay(2); + + for( cnt = 30000; cnt; cnt-- ) { + if( !(RD_REG_WORD(®->ctrl_status) & ISP_RESET) ) + break; + udelay(100); + } + + /* Reset RISC processor. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + for( cnt = 30000; cnt; cnt-- ) { + if( RD_REG_WORD(®->mailbox0) != MBS_BUSY ) + break; + udelay(100); + } +#endif + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla2100_reset_chip"); +#endif +} + + +#ifdef RCSN +/* +* qla2100_device_resync +* Marks devices in the database that needs resynchronization. +* +* Input: +* ha = adapter block pointer. +* +* Context: +* Kernel context. +*/ +STATIC void +qla2100_device_resync(scsi_qla_host_t *ha) { + uint16_t index; + uint32_t mask; + rscn_t dev; + port_id_t p; + + ENTERT("qla2100_device_resync:"); + while (ha->rscn_out_ptr != ha->rscn_in_ptr || + ha->device_flags & RSCN_QUEUE_OVERFLOW) { + INTR_LOCK(ha); + BCOPY(&ha->rscn_queue[ha->rscn_out_ptr], + &dev, sizeof (rscn_t)); + + ha->rscn_out_ptr++; + if (ha->rscn_out_ptr == MAX_RSCN_COUNT) + ha->rscn_out_ptr = 0; + + /* Queue overflow, set switch default case. */ + if (ha->device_flags & RSCN_QUEUE_OVERFLOW) { + dev.format = 3; + ha->device_flags = ha->device_flags & ~RSCN_QUEUE_OVERFLOW; + } + + switch (dev.format) { + case 0: + mask = 0xffffff; + break; + case 1: + mask = 0xffff00; + break; + case 2: + mask = 0xff0000; + break; + default: + mask = 0x0; + dev.d_id.b24 = 0; + ha->rscn_out_ptr = ha->rscn_in_ptr; + break; + } + INTR_UNLOCK(ha); + + for (index = 0; index < MAX_FIBRE_DEVICES; index++) { + p.b.b24 = dev.d_id.b24; + if (ha->fc_db[index].flags & DEV_PUBLIC && + ha->fc_db[index].port_id[2] == p.r.port_id[2] && + ha->fc_db[index].port_id[1] == p.r.port_id[1] && + ha->fc_db[index].port_id[0] == p.r.port_id[0] ) + if (ha->fc_db[index].loop_id <= SNS_LAST_LOOP_ID) + printk(KERN_INFO "qla2100_device_resync: %d:%d:%d\n", + ha->fc_db[index].port_id[2] , + ha->fc_db[index].port_id[1] , + ha->fc_db[index].port_id[0] ) + ha->fc_db[index].flags |= DEV_MISSING; + } + } + } + + LEAVE("qla2100_device_resync: exiting normally"); +} +#endif /* RCSN */ + +#ifdef GET_PORT_INFO + +/* +* qla2100_get_port_database +* Issue enhanced get port database mailbox command +* and copy device name as necessary. +* +* Input: +* ha = adapter state pointer. +* dev = structure pointer. +* opt = mailbox 1 option byte. +* +* Returns: +* qla2100 local function return status code. +* +* Context: +* Kernel context. +*/ +STATIC int +qla2100_get_port_database(scsi_qla_host_t *ha, fcdev_t *dev, uint8_t opt) { + int rval = 0; + port_database_t *pd; + u_long phys_address = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + ENTER("qla2200_get_port_database:"); +/* 4.10 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + pd = KMALLOC(PORT_DATABASE_SIZE); + if ( pd != NULL ) { + phys_address = VIRT_TO_BUS(pd); + BZERO((caddr_t)pd, PORT_DATABASE_SIZE); + } +#else + pd = pci_alloc_consistent(ha->pdev, + PORT_DATABASE_SIZE, + &phys_address); + BZERO((caddr_t)pd, PORT_DATABASE_SIZE); +#endif + if( pd == NULL ) { + return 2; + } + BZERO((caddr_t)pd, PORT_DATABASE_SIZE); + + mb[0] = MBC_GET_PORT_DATABASE; + mb[1] = dev->loop_id << 8 | opt; + mb[2] = MSW(phys_address); + mb[3] = LSW(phys_address); + mb[6] = 0; + mb[7] = 0; + if( !qla2100_mailbox_command(ha, + BIT_7|BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]) ) { + /* Get d_id of device. */ + /* + dev->d_id.b.al_pa = pd->port_id[2]; + dev->d_id.b.area = pd->port_id[3]; + dev->d_id.b.domain = pd->port_id[0]; + dev->d_id.b.rsvd_1 = 0; + */ + + /* Get initiator status of device. */ + pd->prli_svc_param_word_3[0] & BIT_5 ? + (dev->flags = dev->flags | DEV_INITIATOR) : + (dev->flags = dev->flags & ~DEV_INITIATOR); + } else { + printk(KERN_WARNING "qla2200_get_port_database: [ERROR] failed"); + rval = 1; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) + KMFREE(pd, PORT_DATABASE_SIZE); +#else + pci_free_consistent(ha->pdev, PORT_DATABASE_SIZE, + pd, phys_address); +#endif + LEAVE("qla2200_get_port_database:"); + + return (rval); +} +#endif + +/* +* qla2100_configure_loop +* Resync with fibre channel devices. +* +* Input: +* ha = adapter block pointer. +* +* Returns: +* 0 = success +*/ + +STATIC uint8_t qla2100_configure_loop(scsi_qla_host_t *ha, uint8_t reuse) { + uint8_t status = 0; + + /* If firmware needs to be loaded */ + if( qla2100_isp_firmware(ha) ) { + ha->flags.online = FALSE; + if( !(status = qla2100_chip_diag(ha)) ) + status = qla2100_setup_chip(ha); + } + + if( !status && !(status = qla2100_init_rings(ha)) ) { + if( !qla2100_fw_ready(ha) ) { + ha->flags.reset_marker = FALSE; + do { + ha->flags.loop_resync_needed = FALSE; + /* remap devices on loop */ + qla2100_update_fc_db(ha, reuse); + }while( !ha->loop_down_timer && ha->flags.loop_resync_needed ); + } + } + return(status); +} + +/* + * This routine will wait for fabric devices for + * the reset delay. + */ +void qla2100_check_fabric_devices(scsi_qla_host_t *ha) { + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + mb[0] = MBC_GET_FIRMWARE_STATE; + qla2100_mailbox_command(ha, BIT_0, &mb[0]); +} + +#if QLA2100_EXT_TIMEOUT +/* +* qla2100_extend_timeout +* This routine will extend the timeout to the specified value. +* +* Input: +* cmd = SCSI command structure +* +* Returns: +* None. +*/ +static void qla2100_extend_timeout(Scsi_Cmnd *cmd, int timeout) { + del_timer(&cmd->eh_timeout); + cmd->eh_timeout.expires = jiffies + timeout; + add_timer(&cmd->eh_timeout); +} +#endif +/* +* qla2100_display_fc_names +* This routine will the node names of the different devices found +* after port inquiry. +* +* Input: +* cmd = SCSI command structure +* +* Returns: +* None. +*/ +STATIC void qla2100_display_fc_names(scsi_qla_host_t *ha) { + uint16_t index; + + /* Display the node name for adapter */ + printk(KERN_INFO + "scsi-qla%d-adapter-node=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, + ha->init_cb->node_name[0], + ha->init_cb->node_name[1], + ha->init_cb->node_name[2], + ha->init_cb->node_name[3], + ha->init_cb->node_name[4], + ha->init_cb->node_name[5], + ha->init_cb->node_name[6], + ha->init_cb->node_name[7]); + + /* display the port name for adapter */ + printk(KERN_INFO + "scsi-qla%d-adapter-port=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, + ha->init_cb->port_name[0], + ha->init_cb->port_name[1], + ha->init_cb->port_name[2], + ha->init_cb->port_name[3], + ha->init_cb->port_name[4], + ha->init_cb->port_name[5], + ha->init_cb->port_name[6], + ha->init_cb->port_name[7]); + + /* Print out device port names */ + for (index = 0; index < MAX_FIBRE_DEVICES; index++) { + if (ha->fc_db[index].loop_id == PORT_UNUSED || + ha->fc_db[index].loop_id == PORT_AVAILABLE ) + continue; + +#if USE_PORTNAME + printk(KERN_INFO + "scsi-qla%d-target-%d=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, index, + ha->fc_db[index].wwn[0], + ha->fc_db[index].wwn[1], + ha->fc_db[index].wwn[2], + ha->fc_db[index].wwn[3], + ha->fc_db[index].wwn[4], + ha->fc_db[index].wwn[5], + ha->fc_db[index].wwn[6], + ha->fc_db[index].wwn[7]); +#else + printk(KERN_INFO + "scsi-qla%d-target-%d=%02x%02x%02x%02x%02x%02x%02x%02x;\n", + (int)ha->instance, index, + ha->fc_db[index].name[0], + ha->fc_db[index].name[1], + ha->fc_db[index].name[2], + ha->fc_db[index].name[3], + ha->fc_db[index].name[4], + ha->fc_db[index].name[5], + ha->fc_db[index].name[6], + ha->fc_db[index].name[7]); +#endif + } +} + +/* +* qla2100_find_propname +* Get property in database. +* +* Input: +* ha = adapter structure pointer. +* db = pointer to database +* propstr = pointer to dest array for string +* propname = name of property to search for. +* +* Returns: +* 0 = no property +* value = index of property value. +* +* Context: +* Kernel context. +*/ +STATIC uint8_t +qla2100_find_propname(scsi_qla_host_t *ha, + char *propname, char *propstr, char *db) { + char *np, *cp; + int i,k,l; + + /* find the specified string */ + for( l=0, cp = db; (*cp) && l < strlen(db) ; cp = np, l++ ) { + np = qla2100_get_line(cp, propstr); + DEBUG5(printk("qla2100_find_propname: %d - Searching for {%s} in cmd substr: {%s}, next line: {%s} \n",l,propname,propstr, np);) + /* find the property name */ + k = strlen(propname); + for ( i = 0; (propstr[i]) && i < strlen(db); i++ ) { + if( BCMP(propname,&propstr[i],k) == 0) { + DEBUG5(printk("qla2100_find_propname: found at index = %d\n",i+k );) + return (i+k); /* match */ + } + } + } + return (0); +} + + + +/* +* qla2100_get_prop_16chars +* Get an 8-byte property value for the specified property name by +* converting from the property string found in the configuration file. +* The resulting converted value is in big endian format (MSB at byte0). +* +* Input: +* ha = adapter state pointer. +* propname = property name pointer. +* propval = pointer to location for the converted property val. +* db = pointer to database +* +* Returns: +* 0 = value returned successfully. +* +* Context: +* Kernel context. +*/ +static int +qla2100_get_prop_16chars(scsi_qla_host_t *ha, char *propname, + char *propval, char *db) { + char *propstr; + int i, k; + int rval; + uint8_t nval; + uint8_t *pchar; + uint8_t *ret_byte; + uint8_t *tmp_byte; + uint8_t *retval = (uint8_t*)propval; + uint8_t tmpval[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint16_t max_byte_cnt = 8; /* 16 chars = 8 bytes */ + uint16_t max_strlen = 16; + char buf[LINESIZE]; + + rval = qla2100_find_propname(ha, propname, buf, db); + if ( rval >= LINESIZE ) + rval = 0; + + propstr = &buf[rval]; + if ( *propstr == '=' ) + propstr++; /* ignore equal sign */ + + if (rval == 0 ) { + return (1); + } + + if (strlen(propstr) != max_strlen) { + printk(KERN_INFO + "qla2x00: Failed to find prop for %s - rval=%d, " + "strlen(propstr)=%d->(16), val=%s.\n", + propname, rval, (int)strlen(propstr),propstr); + return (1); + } + + /* Convert string to numbers. */ + + pchar = (uint8_t *)propstr; + tmp_byte = (uint8_t *)tmpval; + + rval = 0; + for (i = 0; i < max_strlen; i++) { + /* + * Check for invalid character, two at a time, + * then convert them starting with first byte. + */ + + if ((pchar[i] >= '0') && (pchar[i] <= '9')) { + nval = pchar[i] - '0'; + } else if ((pchar[i] >= 'A') && (pchar[i] <= 'F')) { + nval = pchar[i] - 'A' + 10; + } else if ((pchar[i] >= 'a') && (pchar[i] <= 'f')) { + nval = pchar[i] - 'a' + 10; + } else { + /* invalid character */ + rval = 1; + break; + } + + if (i & BIT_0) { + *tmp_byte = *tmp_byte | nval; + tmp_byte++; + } else { + *tmp_byte = *tmp_byte | nval << 4; + } + } + + if (rval != 0) { + /* Encountered invalid character. */ + return (rval); + } + + /* Copy over the converted value. */ + + ret_byte = retval; + tmp_byte = tmpval; + + i = max_byte_cnt; + k = 0; + while (i--) { + *ret_byte++ = *tmp_byte++; + } + + /* big endian retval[0]; */ + return (0); +} + +/* +* qla2100_get_properties +* Find all properties for the specified adapeter in +* command line. +* +* Input: +* ha = adapter block pointer. +* cmdline = pointer to command line string +* +* Context: +* Kernel context. +*/ +static void +qla2100_get_properties(scsi_qla_host_t *ha, char *cmdline) { + char propbuf[LINESIZE]; + int tmp_rval; + uint16_t tgt; + uint8_t tmp_name[8]; + + /* Adapter FC node names. */ + sprintf(propbuf, "scsi-qla%d-adapter-node", (int) ha->instance); + qla2100_get_prop_16chars (ha, propbuf, + (caddr_t)(&ha->init_cb->node_name), cmdline); + + sprintf(propbuf, "scsi-qla%d-adapter-port", (int) ha->instance); + + /* DG 04/07 check portname of adapter */ + qla2100_get_prop_16chars (ha, propbuf, + (caddr_t)(tmp_name), cmdline); + if (BCMP(&ha->init_cb->port_name[0], &tmp_name[0], 8) != 0) { + /* + * Adapter port name is WWN, and cannot be changed. + * Inform users of the mismatch, then just continue driver + * loading using the original adapter port name in NVRAM. + */ + printk(KERN_WARNING + "qla2x00: qla%ld found mismatch in adapter port names.\n", + ha->instance); + printk(KERN_INFO + " qla%ld port name found in NVRAM -> %02x%02x%02x%02x%02x%02x%02x%02x\n", + ha->instance, + ha->init_cb->port_name[0], + ha->init_cb->port_name[1], + ha->init_cb->port_name[2], + ha->init_cb->port_name[3], + ha->init_cb->port_name[4], + ha->init_cb->port_name[5], + ha->init_cb->port_name[6], + ha->init_cb->port_name[7]); + printk(KERN_INFO + " qla%ld port name found on command line -> %02x%02x%02x%02x%02x%02x%02x%02x\n", + ha->instance, + tmp_name[0], + tmp_name[1], + tmp_name[2], + tmp_name[3], + tmp_name[4], + tmp_name[5], + tmp_name[6], + tmp_name[7]); + printk(KERN_INFO + " Using port name from NVRAM.\n"); + } + + /* FC name for devices */ + for (tgt = 0; tgt < MAX_FIBRE_DEVICES; tgt++) { + sprintf(propbuf, "scsi-qla%d-target-%d", + (int) ha->instance, tgt); + + tmp_rval = qla2100_get_prop_16chars (ha, propbuf, + tmp_name, cmdline); + if ( tmp_rval == 0 ) { + /* Got a name for this ID. */ + + /* Save to appropriate fields. */ +#if USE_PORTNAME /* updated for ioctl merge */ + BCOPY(tmp_name, ha->fc_db[tgt].wwn, 8); +#else + BCOPY(tmp_name, ha->fc_db[tgt].name, 8); +#endif + ha->fc_db[tgt].loop_id = PORT_AVAILABLE; + ha->fc_db[tgt].flag = 0; /* v2.19.05b3 */ + ha->fc_db[tgt].flag |= DEV_CONFIGURED; + DEBUG(printk("Target %d - configured by user: ",tgt);) + DEBUG(printk("scsi-target=\"%08x%08x\"\n", + tmp_name[1], + tmp_name[0]);)/*ioctl support change*/ + } + } + +} + +/* +* Declarations for load module +*/ + +/* 2.19.15 */ +#ifndef FC_IP_SUPPORT +/************************************************************************/ +/* qla2x00_reserve_loopid */ +/* This routine reserves an unused public loop ID. */ +/* */ +/* Arguments: */ +/* ha - adapter block pointer */ +/* pLoopID - pointer to word for returning loop ID */ +/* */ +/* Return Value: */ +/* QL_STATUS_SUCCESS if no error */ +/* QL_STATUS_RESOURCE_ERROR if out of loop IDs */ +/************************************************************************/ + +static int qla2x00_reserve_loopid(scsi_qla_host_t *ha, uint16_t *pLoopId) +{ + int i; + + /* Look for unused loop ID */ + for (i = ha->min_external_loopid; i < ha->max_public_loop_ids; i++) + { + if (!ha->fabricid[i].in_use) + { + /* Found free loop ID */ + ha->fabricid[i].in_use = TRUE; + *pLoopId = i; + + DEBUG(sprintf(debug_buff, "qla2x00_reserve_loopid: assigned loop ID %x\n\r", *pLoopId)); + DEBUG(qla2100_print(debug_buff)); + return QL_STATUS_SUCCESS; + } + } + + /* Out of loop IDs */ + *pLoopId = ha->max_public_loop_ids + 1; /* Set out of range */ + DEBUG(qla2100_print("qla2x00_reserve_loopid: out of loop IDs\n\r")); + return QL_STATUS_RESOURCE_ERROR; +} /* qla2x00_reserve_loopid */ + + +/************************************************************************/ +/* qla2x00_free_loopid */ +/* This routine frees a public loop ID. */ +/* */ +/* Arguments: */ +/* ha - adapter block pointer */ +/* wLoopID - loop ID to free */ +/* */ +/* Return Value: */ +/* none */ +/************************************************************************/ + +static void qla2x00_free_loopid(scsi_qla_host_t *ha, uint16_t wLoopId) +{ + if (wLoopId < ha->max_public_loop_ids) + { + ha->fabricid[wLoopId].in_use = FALSE; + DEBUG(sprintf(debug_buff, "qla2x00_free_loopid: free loop ID %x\n\r", wLoopId)); + DEBUG(qla2100_print(debug_buff)); + } + else + { + DEBUG(sprintf(debug_buff, "qla2x00_free_loopid: loop ID %x out of range\n\r", wLoopId)); + DEBUG(qla2100_print(debug_buff)); + } +} /* qla2x00_free_loopid */ + + +/************************************************************************/ +/* qla2x00_login_public_device */ +/* This routine issues mailbox command to login fabric port. */ +/* */ +/* Arguments: */ +/* ha - adapter block pointer */ +/* wLoopID - public loop ID for device */ +/* pPortID - pointer to port ID for fabric login */ +/* wOptions - MBC_NO_PLOGI_IF_LOGGED_IN (bit 0) */ +/* MBC_NO_PROCESS_LOGIN (bit 1) */ +/* */ +/* Return Value: */ +/* QL_STATUS_SUCCESS if no error */ +/* QL_STATUS_ERROR if any other error */ +/* QL_STATUS_RESOURCE_ERROR if out of loop IDs */ +/* QL_STATUS_FATAL_ERROR if fatal error */ +/************************************************************************/ + +static int qla2x00_login_public_device(scsi_qla_host_t *ha, + uint16_t *pLoopId, + uint8_t *pPortID, + uint16_t wOptions) +{ + int status = QL_STATUS_SUCCESS; + int wRetryCount; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + /* Set retry count */ + wRetryCount = 2; + + while (wRetryCount--) + { + DEBUG(sprintf(debug_buff, "qla2x00_login_public_device: login loop ID: %x port ID: %x, option: %x\n\r", + *pLoopId, *pPortID << 16 | *(pPortID+1) << 8 | *(pPortID+2), wOptions )); + DEBUG(qla2100_print(debug_buff)); + + /* Issue fabric login request */ + mb[0] = MBC_LOGIN_FABRIC_PORT; + mb[1] = (uint16_t)(*pLoopId << 8 | (wOptions & 0x00FF)); + mb[2] = (uint16_t)(*pPortID); + mb[3] = (uint16_t)(*(pPortID+1) << 8 | *(pPortID+2)); + if (qla2100_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]) == 0) + { + /* Login successful */ + status = QL_STATUS_SUCCESS; + break; + } + + /* Login failed, check status */ + if (mb[0] == MBS_FATAL_ERROR) + { + DEBUG(qla2100_print("qla2x00_login_public_device: LOGIN_FABRIC_PORT fatal error\n\r")); + status = QL_STATUS_FATAL_ERROR; + break; + } + else if (mb[0] == MBS_LOOP_ID_IN_USE) + { + DEBUG(sprintf(debug_buff, "qla2x00_login_public_device: loop ID %x in use by port ID %x (4008)\n\r", + *pLoopId, mb[1] << 16 | mb[2])); + DEBUG(qla2100_print(debug_buff)); + + /* Allocate another loop ID and retry */ + if ((status = qla2x00_reserve_loopid(ha, pLoopId)) == QL_STATUS_SUCCESS) + { + wRetryCount++; + } + else + { + break; + } + } + else if (mb[0] == MBS_PORT_ID_IN_USE) + { + DEBUG(sprintf(debug_buff, "qla2x00_login_public_device: port ID already assigned to loop ID %x (4007)\n\r", + mb[1])); + DEBUG(qla2100_print(debug_buff)); + + /* Free loop ID and use one assigned by RISC */ + qla2x00_free_loopid(ha, *pLoopId); + *pLoopId = mb[1]; + + /* Must reissue login mailbox command with new loop ID */ + wRetryCount++; + } + else + { + DEBUG(sprintf(debug_buff, "qla2x00_login_public_device: login error status %x, MB1: %x, MB2: %x\n\r", + mb[0], mb[1], mb[2])); + DEBUG(qla2100_print(debug_buff)); + status = QL_STATUS_ERROR; + } + } + return(status); +} /* qla2x00_login_public_device */ + + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#ifdef MODULE +Scsi_Host_Template driver_template = QLA2100_LINUX_TEMPLATE; +#include "scsi_module.c" +#endif +#else /* new kernel scsi initialization scheme */ +static Scsi_Host_Template driver_template = QLA2100_LINUX_TEMPLATE; +#include "scsi_module.c" +#endif + +#ifdef QL_DEBUG_ROUTINES +/****************************************************************************/ +/* Driver Debug Functions. */ +/****************************************************************************/ + + /* + * Get byte from I/O port + */ +STATIC uint8_t +qla2100_getbyte(uint8_t *port) { + uint8_t ret; + +#ifdef MEMORY_MAPPED_IO + ret = *port; +#else + ret = inb((int)port); +#endif + + if( ql2x_debug_print ) { + qla2100_print("qla2100_getbyte: address = "); + qla2100_output_number((u_long)port, 16); + qla2100_print(" data = 0x"); + qla2100_output_number((u_long)ret, 16); + qla2100_print("\n"); + } + + return(ret); +} + + /* + * Get word from I/O port + */ +STATIC uint16_t +qla2100_getword(uint16_t *port) { + uint16_t ret; + +#ifdef MEMORY_MAPPED_IO + ret = *port; +#else + ret = inw((int)port); +#endif + + if( ql2x_debug_print ) { + qla2100_print("qla2100_getword: address = "); + qla2100_output_number((u_long)port, 16); + qla2100_print(" data = 0x"); + qla2100_output_number((u_long)ret, 16); + qla2100_print("\n"); + } + + return(ret); +} + + /* + * Get double word from I/O port + */ +STATIC uint32_t +qla2100_getdword(uint32_t *port) { + uint32_t ret; + +#ifdef MEMORY_MAPPED_IO + ret = *port; +#else + ret = inl((int)port); +#endif + + if( ql2x_debug_print ) { + qla2100_print("qla2100_getdword: address = "); + qla2100_output_number((u_long)port, 16); + qla2100_print(" data = 0x"); + qla2100_output_number((u_long)ret, 16); + qla2100_print("\n"); + } + + return(ret); +} + + /* + * Send byte to I/O port + */ +STATIC void +qla2100_putbyte(uint8_t *port, uint8_t data) { +#ifdef MEMORY_MAPPED_IO + *port = data; +#else + outb(data, (int)port); +#endif + + if( ql2x_debug_print ) { + qla2100_print("qla2100_putbyte: address = "); + qla2100_output_number((u_long)port, 16); + qla2100_print(" data = 0x"); + qla2100_output_number((u_long)data, 16); + qla2100_print("\n"); + } +} + + /* + * Send word to I/O port + */ +STATIC void +qla2100_putword(uint16_t *port, uint16_t data) { +#ifdef MEMORY_MAPPED_IO + *port = data; +#else +#ifdef _LINUX_IOPORTS + outw(data, (int)port); +#else + outw((int)port, data); +#endif +#endif + + if( ql2x_debug_print ) { + qla2100_print("qla2100_putword: address = "); + qla2100_output_number((u_long)port, 16); + qla2100_print(" data = 0x"); + qla2100_output_number((u_long)data, 16); + qla2100_print("\n"); + } +} + + /* + * Send double word to I/O port + */ +STATIC void +qla2100_putdword(uint32_t *port, uint32_t data) { +#ifdef MEMORY_MAPPED_IO + *port = data; +#else +#ifdef _LINUX_IOPORTS + outl(data,(int)port); +#else + outl((int)port, data); +#endif +#endif + + if( ql2x_debug_print ) { + qla2100_print("qla2100_putdword: address = "); + qla2100_output_number((u_long)port, 16); + qla2100_print(" data = 0x"); + qla2100_output_number((u_long)data, 16); + qla2100_print("\n"); + } +} + + /* + * Dummy function to prevent warnings for + * declared and unused debug functions + */ +void +qla2100_debug(void) { + qla2100_getbyte(0); + qla2100_getword(0); + qla2100_getdword(0); + qla2100_putbyte(0, 0); + qla2100_putword(0, 0); + qla2100_putdword(0, 0); +} + + /* + * Out character to COM1 port. + * PORT must be at standard address for COM1 = 0x3F8 + * This port is available on both Lion and ia32 systems + */ +#define OUTB(addr,data) outb((data),(addr)) +STATIC void +qla2100_putc(int8_t c) { +#ifdef QL_DEBUG_CONSOLE + + printk("%c",c); + +#else /* QL_DEBUG_CONSOLE */ + + uint8_t data; + int com_addr = 0x3f8; /* COM1 */ + int hardware_flow_control = 1; + int software_flow_control = 0; + uint8_t loop = TRUE; + + do { + + /* Wait for transmitter holding and shift registers for empty. */ + do { + data = inb(com_addr+5); + }while( !(data & BIT_6) ); + + /* + * Set BAUD rate for COM1 to 9600 + */ + + /* BAUD rate divisor LSB. */ + OUTB(com_addr+3, 0x83); + + /* BAUD rate divisor MSB. */ + OUTB(com_addr, 0xc); /* 0xC = 9600 baud */ + + /* Set No parity, 8 bits, 1 stop bit and + select interrupt enable register. */ + OUTB(com_addr+3, 3); + + /* Disable interrupts. */ + OUTB(com_addr+1, 0); + + /* Set data terminal ready and request to send */ + OUTB(com_addr+1, 0); + + if( hardware_flow_control ) { + /* Wait for clear-to-send and data-set-ready */ + do { + data = inb(com_addr+6) & (BIT_5 + BIT_4); + }while( data != (BIT_5 + BIT_4) ); + } else if( software_flow_control ) { + /* Test for data ready. */ + data = inb(com_addr+5); + if( data & BIT_0 ) { + /* If XOFF */ + data = inb(com_addr); + if( data == '\023' ) { + /* Wait for XON */ + do { + /* Wait for int8_t */ + do { + data = inb(com_addr+5); + }while( !(data & BIT_0) ); + data = inb(com_addr); + }while( data != '\021' ); + } + } + } + + /* Output character. */ + OUTB(com_addr, c); + + /* Add return. */ + if( c == '\n' ) + c = '\r'; + else + loop = FALSE; + + }while( loop ); +#endif /* QL_DEBUG_CONSOLE */ +} + + /* + * Out NULL terminated string to COM port. + */ +STATIC void +qla2100_print(int8_t *s) { + if( ql2x_debug_print ) { +#ifdef QL_DEBUG_CONSOLE + printk("%s",s); +#else + /* Output string. */ + while( *s ) + qla2100_putc(*s++); +#endif + } +} + + /* + * Output long number to COM port. + */ +STATIC void + qla2100_output_number(u_long n, uint8_t base) { + int8_t str[12]; + int8_t *s = &str[11]; + uint8_t output = 0; + uint8_t hex = FALSE; + + if( ql2x_debug_print ) { + if( base == 10 || base == 16 ) { + if( base == 16 && n > 9 ) + hex = TRUE; + + *s = 0; + do { + s--; + *s = n % base; + if( *s > 9 ) + *s += 55; + else + *s += '0'; + n /= base; + }while( n ); + + for( ; *s; s++ ) { + if( *s != '0' ) + output = 1; + if( output ) + qla2100_putc(*s); + } + if( !output ) + qla2100_putc(*--s); + + if( hex ) + qla2100_putc('h'); + } + } +} + +STATIC void +qla2100_dump_buffer(uint8_t *b, uint32_t size) { + uint32_t cnt; + uint8_t c; + + if( ql2x_debug_print ) { + qla2100_print( + " 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh Fh\n"); + qla2100_print( + "---------------------------------------------------------------\n"); + + for( cnt = 0; cnt < size; ) { + c = *b++; + if( c < 16 ) + qla2100_putc(' '); + qla2100_output_number((uint32_t)c, 16); + cnt++; + if( !(cnt % 16) ) + qla2100_print("\n"); + else if( c < 10 ) + qla2100_print(" "); + else + qla2100_putc(' '); + } + if( cnt % 16 ) + qla2100_print("\n"); + } +} + /************************************************************************** + * ql2100_print_scsi_cmd + * + **************************************************************************/ +void qla2100_print_scsi_cmd(Scsi_Cmnd *cmd) { + scsi_qla_host_t *ha; + struct Scsi_Host *host = cmd->host; + srb_t *sp; + + int i; + ha = (scsi_qla_host_t *) host->hostdata; + + ql2x_debug_print = 1; + sp = (srb_t *) CMD_SP(cmd); + sprintf(debug_buff,"SCSI Command=0x%p, Handle=0x%08lx pid=%x\n\r", cmd, (u_long)CMD_HANDLE(cmd),cmd->pid); + qla2100_print(debug_buff); + sprintf(debug_buff," chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n\r", + cmd->channel, cmd->target, cmd->lun, cmd->cmd_len); + qla2100_print(debug_buff); + qla2100_print(" CDB = "); + for( i = 0; i < cmd->cmd_len; i++ ) { + sprintf(debug_buff,"0x%02x ", cmd->cmnd[i]); + qla2100_print(debug_buff); + } + + sprintf(debug_buff,"\n\r seg_cnt =%d, retries=%d, serial_number_at_timeout=0x%lx\n\r",cmd->use_sg,cmd->retries,cmd->serial_number_at_timeout); + qla2100_print(debug_buff); + sprintf(debug_buff," request buffer=0x%p, request buffer len=0x%x\n\r",cmd->request_buffer,cmd->request_bufflen); + qla2100_print(debug_buff); + sprintf(debug_buff," tag=%d, flags=0x%x, transfersize=0x%x \n\r", + cmd->tag, cmd->flags,cmd->transfersize); + qla2100_print(debug_buff); + sprintf(debug_buff," Pid=%d, SP=0x%x\n\r", (int)cmd->pid, CMD_SP(cmd)); + + qla2100_print(debug_buff); + sprintf(debug_buff," sp flags=0x%lx, sp state=%x, wdgtime=%d\n\r",sp->flags,sp->state,sp->wdg_time); + qla2100_print(debug_buff); +} + + +void qla2100_print_q_info(scsi_lu_t *q) { + sprintf(debug_buff,"Queue info: queue in =%d, queue out= %d, flags=0x%lx\n\r", q->q_incnt, q->q_outcnt, q->q_flag); + qla2100_print(debug_buff); +} +#endif + + + + + /************************************************************************** + * ql2100_dump_regs + * + **************************************************************************/ +static void qla2100_dump_regs(struct Scsi_Host *host) { + printk("Mailbox registers:\n"); + printk("qla2100 : mbox 0 0x%04x \n", inw(host->io_port + 0x10)); + printk("qla2100 : mbox 1 0x%04x \n", inw(host->io_port + 0x12)); + printk("qla2100 : mbox 2 0x%04x \n", inw(host->io_port + 0x14)); + printk("qla2100 : mbox 3 0x%04x \n", inw(host->io_port + 0x16)); + printk("qla2100 : mbox 4 0x%04x \n", inw(host->io_port + 0x18)); + printk("qla2100 : mbox 5 0x%04x \n", inw(host->io_port + 0x1a)); +#ifdef TRACECODE + sprintf(debug_buff,"qla2100 : mbox 0 0x%04x \n\r", inw(host->io_port + 0x10)); + qla2100_print(debug_buff); + sprintf(debug_buff,"qla2100 : mbox 1 0x%04x \n\r", inw(host->io_port + 0x12)); + qla2100_print(debug_buff); + sprintf(debug_buff,"qla2100 : mbox 2 0x%04x \n\r", inw(host->io_port + 0x14)); + qla2100_print(debug_buff); + sprintf(debug_buff,"qla2100 : mbox 3 0x%04x \n\r", inw(host->io_port + 0x16)); + qla2100_print(debug_buff); + sprintf(debug_buff,"qla2100 : mbox 4 0x%04x \n\r", inw(host->io_port + 0x18)); + qla2100_print(debug_buff); + sprintf(debug_buff,"qla2100 : mbox 5 0x%04x \n\r", inw(host->io_port + 0x1a)); + qla2100_print(debug_buff); +#endif +} + + +#if STOP_ON_ERROR + /************************************************************************** + * ql2100_panic + * + **************************************************************************/ +static void qla2100_panic(char *cp, struct Scsi_Host *host) { + scsi_qla_host_t *ha; + long *fp; + + ha = (scsi_qla_host_t *) host->hostdata; + DEBUG2(ql2x_debug_print = 1;) + sprintf(debug_buff,"qla2100 - PANIC: %s\n",cp); + qla2100_print(debug_buff); + sprintf(debug_buff,"Current time=0x%lx\n", jiffies); + qla2100_print(debug_buff); + sprintf(debug_buff,"Number of pending commands =0x%lx\n", ha->actthreads); + qla2100_print(debug_buff); + sprintf(debug_buff,"Number of queued commands =0x%lx\n", ha->qthreads); + qla2100_print(debug_buff); + sprintf(debug_buff,"Number of free entries = (%d)\n",ha->req_q_cnt); + qla2100_print(debug_buff); + sprintf(debug_buff,"Request Queue @ 0x%lx, Response Queue @ 0x%lx\n", + ha->request_dma, + ha->response_dma); + qla2100_print(debug_buff); + sprintf(debug_buff,"Request In Ptr %d\n", ha->req_ring_index); + qla2100_print(debug_buff); + fp = (long *) &ha->flags; + sprintf(debug_buff,"HA flags =0x%lx\n", *fp); + qla2100_print(debug_buff); + ql2100_dump_requests(ha); + qla2100_dump_regs(host); + cli(); + for( ;; ) { + QLA2100_DELAY(2); barrier(); + } + sti(); +} +#endif +#if 0 + static void qla2100_set_flags(int flag) { + + switch( flag ) { + case 0x1: + qla2100_verbose = 1L; + + } + + } +#endif + /************************************************************************** + * ql2100_dump_requests + * + **************************************************************************/ +void +ql2100_dump_requests(scsi_qla_host_t *ha) { + + Scsi_Cmnd *cp; + srb_t *sp; + int i; +#ifdef QL_DEBUG_ROUTINES + qla2100_print("Outstanding Commands on controller:\n\r"); +#else + printk(KERN_INFO "Outstanding Commands on controller:\n"); +#endif + for( i=0; i < MAX_OUTSTANDING_COMMANDS; i++ ) { + if( (sp = ha->outstanding_cmds[i]) == NULL ) + continue; + if( (cp = sp->cmd) == NULL ) + continue; + sprintf(debug_buff,"(%d): Pid=%ld, sp flags=0x%x, cmd=0x%p\n\r", i, (int)sp->cmd->pid, (long)sp->flags,CMD_SP(sp->cmd)); + +#ifdef QL_DEBUG_ROUTINES + qla2100_print(debug_buff); +#else + printk(KERN_INFO "%s",debug_buff); +#endif + } + +} + + + /************************************************************************** + * qla2100_setup + * + * Handle Linux boot parameters. This routine allows for assigning a value + * to a parameter with a ';' between the parameter and the value. + * ie. qla2x00=arg0;arg1;...;argN; OR + * via the command line. + * ie. qla2x00 ql2xopts=arg0;arg1;...;argN; + **************************************************************************/ +void qla2100_setup(char *s, int *dummy) { + char *cp, *np; + char *slots[MAXARGS]; + char **argv = &slots[0]; + char buf[LINESIZE]; + int argc, opts; + + /* + * Determine if we have any properties. + */ + cp = s; + opts = 1; + while( *cp && (np = qla2100_get_line(cp, buf)) != NULL ) { + if( BCMP("scsi-qla",buf,8) == 0 ) { + DEBUG(printk("qla2100: devconf=%s\n",cp);) + ql2xdevconf = cp; + (opts > 0)? opts-- : 0; + break; + } + opts++; + cp = np; + } + /* + * Parse the args before the properties + */ + if( opts ) { + opts = (opts > MAXARGS-1)? MAXARGS-1: opts; + argc = qla2100_get_tokens(s, argv, opts); + while (argc > 0 ) { + cp = *argv; + DEBUG(printk("scsi: found cmd arg =[%s]\n", cp);) + if( strcmp(cp, "verbose") == 0 ) { + DEBUG(printk("qla2100: verbose\n");) + qla2100_verbose++; + } else if (strcmp(cp, "quiet") == 0) { + qla2100_quiet = 1; + } else if( strcmp(cp, "reinit_on_loopdown") == 0 ) { + qla2100_reinit++; + DEBUG(printk("qla2100: reinit_on_loopdown\n");) + } + argc--, argv++; + } + } + +} + + /********************** qla2100_get_line ********************* + * qla2100_get_line + * Copy a substring from the specified string. The substring + * consists of any number of chars seperated by white spaces (i.e. spaces) + * and ending with a newline '\n' or a semicolon ';'. + * + * Enter: + * str - orig string + * line - substring + * + * Returns: + * cp - pointer to next string + * or + * null - End of string + *************************************************************/ +static char *qla2100_get_line(char *str, char *line) { + register char *cp = str; + register char *sp = line; + + /* skip preceeding spaces */ + while( *cp && *cp == ' ' ) + ++cp; + while ( (*cp) && *cp != '\n' && *cp != ';' ) /* end of line */ + *sp++ = *cp++; + + *sp = '\0'; + DEBUG5(printk("qla2100_get_line: %s\n",line);) + if( (*cp) ) { + cp++; + return( cp ); + } + return( NULL ); +} + + + /**************************** get_tokens ********************* + * Parse command line into argv1, argv2, ... argvX + * Arguments are seperated by white spaces and colons and end + * with a NULL. + *************************************************************/ +static int qla2100_get_tokens(char *line, char **argv, int maxargs ) { + register char *cp = line; + int count = 0; + + while( *cp && count < maxargs ) { + /* skip preceeding spaces */ + while((*cp) && *cp == ' ') + ++cp; + /* symbol starts here */ + argv[count++] = cp; + /* skip symbols */ + while ( (*cp) && !( *cp == ' ' || *cp == ';' || *cp == ':' ) ) + cp++; + /* replace comma or space with a null */ + if( (*cp) && (*cp ==' ' ) && argv[count-1] != cp ) + *cp++ = '\0'; + } + return( count ); +} + +#ifdef FC_IP_SUPPORT + /* Include routines for supporting IP */ +#include "qla2100ip.c" +#endif /* FC_IP_SUPPORT */ + +#if APIDEV +/****************************************************************************/ +/* Create character driver "HbaApiDev" w dynamically allocated major number */ +/* and create "/proc/scsi/qla2x00/HbaApiNode" as the device node associated */ +/* with the major number. */ +/****************************************************************************/ + +#define APIDEV_NODE "HbaApiNode" +#define APIDEV_NAME "HbaApiDev" + +static int apidev_major = 0; +static struct Scsi_Host *apidev_host = 0; + +static int apidev_open(struct inode *inode, struct file *file) +{ + printk (KERN_INFO "qla2100_apidev: open MAJOR number = %d, MINOR number = %d\n", MAJOR (inode->i_rdev), MINOR (inode->i_rdev)); + return 0; +} +static int apidev_close(struct inode *inode, struct file *file) +{ + printk (KERN_INFO "qla2100_apidev: closed\n"); + return 0; +} + +static int apidev_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg) +{ + Scsi_Device fake_scsi_device; + fake_scsi_device.host = apidev_host; + return(qla2100_ioctl(&fake_scsi_device, (int)cmd, (void*)arg)); +} + +static struct file_operations apidev_fops = { + ioctl: apidev_ioctl, + open: apidev_open, + release: apidev_close +}; + +static int apidev_init(struct Scsi_Host *host) +{ + if(apidev_host) return 0; + if (0 > (apidev_major = register_chrdev(0, APIDEV_NAME, &apidev_fops))) + { + DEBUG(printk("qla2100_apidev: register_chrdev rc=%d\n",apidev_major);) + return apidev_major; + } + apidev_host = host; + DEBUG(printk("qla2x00: Created /proc/scsi/qla2x00/%s major=%d\n",APIDEV_NODE,apidev_major);) + proc_mknod(APIDEV_NODE, 0777+S_IFCHR,host->hostt->proc_dir,(kdev_t)MKDEV(apidev_major,0)); + return 0; +} + +static int apidev_cleanup() +{ + if(!apidev_host) return 0; + unregister_chrdev(apidev_major,APIDEV_NAME); + remove_proc_entry(APIDEV_NODE,apidev_host->hostt->proc_dir); + apidev_host = 0; + return 0; +} +#endif /* APIDEV */ + +#ifdef QL_DEBUG_ROUTINES +#if DEBUG_GET_FW_DUMP +#include "x2300dbg.c" +#endif +#endif + + +/* +* Overrides for Emacs so that we almost follow Linus's tabbing style. +* Emacs will notice this stuff at the end of the file and automatically +* adjust the settings for this buffer only. This must remain at the end +* of the file. +* --------------------------------------------------------------------------- +* Local variables: +* c-indent-level: 2 +* c-brace-imaginary-offset: 0 +* c-brace-offset: -2 +* c-argdecl-indent: 2 +* c-label-offset: -2 +* c-continued-statement-offset: 2 +* c-continued-brace-offset: 0 +* indent-tabs-mode: nil +* tab-width: 8 +* End: +*/ diff -Nur linux-2.4.19/drivers/scsi/qla2x00.h linux-2.4.19-sgi211r3/drivers/scsi/qla2x00.h --- linux-2.4.19/drivers/scsi/qla2x00.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/qla2x00.h Tue Jan 8 17:05:38 2002 @@ -0,0 +1,2492 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.2.x and 2.4.x +* Copyright (C) 2000 and 2001 Qlogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +** +******************************************************************************/ + +#ifndef _IO_HBA_QLA2100_H /* wrapper symbol for kernel use */ +#define _IO_HBA_QLA2100_H /* subject to change without notice */ + +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE not defined */ + +#ifndef HOSTS_C + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef ISP2200 +#define ISP2200 +#endif + + +/* + * Driver debug definitions. + */ +/* #define QL_DEBUG_LEVEL_1 */ /* Output register accesses to COM1 */ +/* #define QL_DEBUG_LEVEL_2 */ /* Output error msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_3 */ /* Output function trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_4 */ /* Output NVRAM trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_5 */ /* Output ring trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_6 */ /* Output WATCHDOG timer trace to COM1 */ +/* #define QL_DEBUG_LEVEL_7 */ /* Output RISC load trace msgs to COM1 */ +/* #define QL_DEBUG_LEVEL_8 */ /* Output ring saturation msgs to COM1 */ + +#define QL_DEBUG_CONSOLE /* Output to console instead of COM1 */ + /* comment this #define to get output of qla2100_print to COM1 */ + /* if COM1 is not connected to a host system, the driver hangs system! */ + +/* + * Data bit definitions. + */ +#define BIT_0 0x1 +#define BIT_1 0x2 +#define BIT_2 0x4 +#define BIT_3 0x8 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x100 +#define BIT_9 0x200 +#define BIT_10 0x400 +#define BIT_11 0x800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x10000 +#define BIT_17 0x20000 +#define BIT_18 0x40000 +#define BIT_19 0x80000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x1000000 +#define BIT_25 0x2000000 +#define BIT_26 0x4000000 +#define BIT_27 0x8000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + +/* + * Common size type definitions + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif + +/* + * Local Macro Definitions. + */ +#if defined(QL_DEBUG_LEVEL_1) || defined(QL_DEBUG_LEVEL_2) || \ + defined(QL_DEBUG_LEVEL_3) || defined(QL_DEBUG_LEVEL_4) || \ + defined(QL_DEBUG_LEVEL_5) || defined(QL_DEBUG_LEVEL_6) || \ + defined(QL_DEBUG_LEVEL_7) || defined(QL_DEBUG_LEVEL_8) + #define QL_DEBUG_ROUTINES +#endif + +#ifndef TRUE + #define TRUE 1 +#endif + +#ifndef FALSE + #define FALSE 0 +#endif +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) +# if defined(__sparc_v9__) || defined(__powerpc__) +# error "PPC and Sparc platforms are only support under 2.1.92 and above" +# endif +#endif + + +/* + * Locking + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) +# include +# else +# include +# endif +# include +# define cpuid smp_processor_id() +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +# define DRIVER_LOCK_INIT \ + spin_lock_init(&ha->spin_lock); +# define DRIVER_LOCK \ + if(!ha->cpu_lock_count[cpuid]) { \ + spin_lock_irqsave(&ha->spin_lock, cpu_flags); \ + ha->cpu_lock_count[cpuid]++; \ + } else { \ + ha->cpu_lock_count[cpuid]++; \ + } +# define DRIVER_UNLOCK \ + if(--ha->cpu_lock_count[cpuid] == 0) \ + spin_unlock_irqrestore(&ha->spin_lock, cpu_flags); +# else +# define DRIVER_LOCK_INIT +# define DRIVER_LOCK +# define DRIVER_UNLOCK +# endif +#else +# define cpuid 0 +# define DRIVER_LOCK_INIT +# define DRIVER_LOCK \ + save_flags(cpu_flags); \ + cli(); +# define DRIVER_UNLOCK \ + restore_flags(cpu_flags); +# define le32_to_cpu(x) (x) +# define cpu_to_le32(x) (x) +#endif + + +/* + * I/O register +*/ +/* #define MEMORY_MAPPED_IO */ /* Enable memory mapped I/O */ +#undef MEMORY_MAPPED_IO /* Disable memory mapped I/O */ +#define LINUX_IOPORTS /* Linux in/out routines are define*/ + /* differently from other OSs */ + +#ifdef QL_DEBUG_LEVEL_1 + #define RD_REG_BYTE(addr) qla2100_getbyte((uint8_t *)addr) + #define RD_REG_WORD(addr) qla2100_getword((uint16_t *)addr) + #define RD_REG_DWORD(addr) qla2100_getdword((uint32_t *)addr) + #define WRT_REG_BYTE(addr, data) qla2100_putbyte((uint8_t *)addr, data) + #define WRT_REG_WORD(addr, data) qla2100_putword((uint16_t *)addr, data) + #define WRT_REG_DWORD(addr, data) qla2100_putdword((uint32_t *)addr, data) +#else /* QL_DEBUG_LEVEL_1 */ +#ifdef MEMORY_MAPPED_IO +#define RD_REG_BYTE(addr) (*((volatile uint8_t *)addr)) +#define RD_REG_WORD(addr) (*((volatile uint16_t *)addr)) +#define RD_REG_DWORD(addr) (*((volatile uint32_t *)addr)) +#define WRT_REG_BYTE(addr, data) (*((volatile uint8_t *)addr) = data) +#define WRT_REG_WORD(addr, data) (*((volatile uint16_t *)addr) = data) +#define WRT_REG_DWORD(addr, data) (*((volatile uint32_t *)addr) = data) +#else /* MEMORY_MAPPED_IO */ +#define RD_REG_BYTE(addr) (inb((unsigned long)addr)) +#define RD_REG_WORD(addr) (inw((unsigned long)addr)) +#define RD_REG_DWORD(addr) (inl((unsigned long)addr)) +#define WRT_REG_BYTE(addr, data) (outb(data,(unsigned long)addr)) +#define WRT_REG_WORD(addr, data) (outw(data,(unsigned long)addr)) +#define WRT_REG_DWORD(addr, data) (outl(data,(unsigned long)addr)) +#endif /* MEMORY_MAPPED_IO */ +#endif /* QL_DEBUG_LEVEL_1 */ + +#define MAX_FIBRE_DEVICES 256 +#define MAX_RSCN_COUNT 10 +#define MAX_HOST_COUNT 16 + +/* + * Host adapter default definitions. + */ +#define MAX_BUSES 1 /* We only have one bus today */ +#define MAX_TARGETS_2100 255 +#define MAX_TARGETS_2200 255 +#define MAX_LUNS 255 + +/* + * Fibre Channel device definitions. + */ +#define LAST_LOCAL_LOOP_ID 0x7d +#define SNS_FL_PORT 0x7e +#define FABRIC_CONTROLLER 0x7f +#define SIMPLE_NAME_SERVER 0x80 +#define SNS_FIRST_LOOP_ID 0x81 +#define LAST_SNS_LOOP_ID 0xfe +#define MANAGEMENT_SERVER 0xfe +#define BROADCAST 0xff +#define SNS_ACCEPT 0x0280 /* 8002 swapped */ +#define SNS_REJECT 0x0180 /* 8001 swapped */ + +/* Loop ID's used as database flags, must be higher than any valid Loop ID */ +#define PORT_UNUSED 0x100 /* Port never been used. */ +#define PORT_AVAILABLE 0x101 /* Device does not exist on port. */ + +/* + * Timeout timer counts in seconds + */ +#define QLA2100_WDG_TIME_QUANTUM 1 /* In seconds */ +#define PORT_RETRY_TIME 2 +#define LOOP_DOWN_TIMEOUT 60 +#define LOOP_DOWN_TIME 240 /* 240 */ + +/* Maximum outstanding commands in ISP queues (1-65535) */ +#define LOOP_DOWN_RESET (LOOP_DOWN_TIME - 30) + +/* Maximum outstanding commands in ISP queues (1-65535) */ +#define MAX_OUTSTANDING_COMMANDS 512*2 + +#define REQUEST_ENTRY_CNT 256 /* # of request entries, was 512 */ +#define RESPONSE_ENTRY_CNT 256 /* # of response entries, was 16 */ + +/* + * UnixWare required definitions. + */ +#define HBA_PREFIX qla2100 + +/* Physical DMA memory requirements */ +#define QLA2100_MEMALIGN 4 +#define QLA2100_BOUNDARY 0x80000000 /* 2GB */ + +/* Number of segments 1 - 65535 */ +#define SG_SEGMENTS 32 /* Cmd entry + 6 continuations */ + +/* + * SCSI Request Block + */ +typedef struct srb +{ + Scsi_Cmnd *cmd; /* (4) SCSI command block */ + struct srb *s_next; /* (4) Next block on LU queue */ + struct srb *s_prev; /* (4) Previous block on LU queue */ + uint8_t flags; /* (1) Status flags. */ + uint8_t dir; /* direction of transfer */ + uint8_t retry_count; /* Retry count. */ + uint8_t port_down_retry_count; /* Port down retry count. */ + uint8_t ccode; /* risc completion code */ + uint8_t scode; /* scsi status code */ + uint8_t wdg_time; /* watchdog time in seconds */ + uint8_t state; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) + uint64_t saved_dma_handle; /* for unmap of single transfers */ +#endif +}srb_t; + +/* + * SRB flag definitions + */ +#define SRB_TIMEOUT BIT_0 /* Command timed out */ +#define SRB_SENT BIT_1 /* Command sent to ISP */ +#define SRB_WATCHDOG BIT_2 /* Command on watchdog list */ +#define SRB_ABORT_PENDING BIT_3 /* Command abort sent to device */ +#define SRB_ABORTED BIT_4 /* Command aborted command already */ +#define SRB_RETRY BIT_5 /* Command aborted command already */ + +/* + * LUN - Logical Unit Queue structure + */ +typedef struct scsi_lu +{ + srb_t *q_first; /* First block on LU queue */ + srb_t *q_last; /* Last block on LU queue */ + u_char q_flag; /* LU queue state flags */ + u_short q_outcnt; /* Pending jobs for this LU */ + u_long q_incnt; /* queued jobs for this LU */ + u_long io_cnt; /* total xfer count */ + u_long resp_time; /* total response time (start - finish) */ + u_long act_time; /* total actived time (minus queuing time) */ + u_long w_cnt; /* total writes */ + u_long r_cnt; /* total reads */ +#if QLA2X00_TARGET_MODE_SUPPORT + void (*q_func)(); /* Target driver event handler */ + long q_param; /* Target driver event param */ +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) + spinlock_t *q_spin_lock; /* Device Queue Lock */ +#endif + volatile unsigned char cpu_lock_count[NR_CPUS]; + u_long q_timeout; /* total command timeouts */ +}scsi_lu_t; + +/* + * Logical Unit q_flag definitions + */ +#define QLA2100_QBUSY BIT_0 +#define QLA2100_QWAIT BIT_1 +#define QLA2100_QSUSP BIT_2 +#define QLA2100_QRESET BIT_4 +#define QLA2100_QHBA BIT_5 +#define QLA2100_BSUSP BIT_6 /* controller is suspended */ +#define QLA2100_BREM BIT_7 /* controller is removed */ + +/* + * ISP PCI Configuration Register Set + */ +typedef volatile struct +{ + uint16_t vendor_id; /* 0x0 */ + uint16_t device_id; /* 0x2 */ + uint16_t command; /* 0x4 */ + uint16_t status; /* 0x6 */ + uint8_t revision_id; /* 0x8 */ + uint8_t programming_interface; /* 0x9 */ + uint8_t sub_class; /* 0xa */ + uint8_t base_class; /* 0xb */ + uint8_t cache_line; /* 0xc */ + uint8_t latency_timer; /* 0xd */ + uint8_t header_type; /* 0xe */ + uint8_t bist; /* 0xf */ + uint32_t base_port; /* 0x10 */ + uint32_t mem_base_addr; /* 0x14 */ + uint32_t base_addr[4]; /* 0x18-0x24 */ + uint32_t reserved_1[2]; /* 0x28-0x2c */ + uint16_t expansion_rom; /* 0x30 */ + uint32_t reserved_2[2]; /* 0x34-0x38 */ + uint8_t interrupt_line; /* 0x3c */ + uint8_t interrupt_pin; /* 0x3d */ + uint8_t min_grant; /* 0x3e */ + uint8_t max_latency; /* 0x3f */ +}config_reg_t; + + +/* + * 2100/2200 ISP I/O Register Set structure definitions. + */ +typedef volatile struct +{ + uint16_t flash_address; /* Flash BIOS address */ + uint16_t flash_data; /* Flash BIOS data */ + uint16_t unused_1[1]; /* Gap */ + uint16_t ctrl_status; /* Control/Status */ + #define ISP_FLASH_ENABLE BIT_1 /* Flash BIOS Read/Write enable */ + #define ISP_RESET BIT_0 /* ISP soft reset */ + uint16_t ictrl; /* Interrupt control */ + #define ISP_EN_INT BIT_15 /* ISP enable interrupts. */ + #define ISP_EN_RISC BIT_3 /* ISP enable RISC interrupts. */ + uint16_t istatus; /* Interrupt status @0xa*/ + #define RISC_INT BIT_3 /* RISC interrupt */ + uint16_t semaphore; /* Semaphore */ + uint16_t nvram; /* NVRAM register. @0xe */ + #define NV_DESELECT 0 + #define NV_CLOCK BIT_0 + #define NV_SELECT BIT_1 + #define NV_DATA_OUT BIT_2 + #define NV_DATA_IN BIT_3 + + /* 2100 and 2200 */ + uint16_t mailbox0; /* Mailbox 0 @0x10 */ + uint16_t mailbox1; /* Mailbox 1 */ + uint16_t mailbox2; /* Mailbox 2 */ + uint16_t mailbox3; /* Mailbox 3 */ + uint16_t mailbox4; /* Mailbox 4 */ + uint16_t mailbox5; /* Mailbox 5 */ + uint16_t mailbox6; /* Mailbox 6 */ + uint16_t mailbox7; /* Mailbox 7 */ + + uint16_t unused_2[0x3b]; /* Gap */ + uint16_t fpm_diag_config; + uint16_t unused_3[0x6]; /* Gap */ + uint16_t pcr; /* Processor Control Register. */ + uint16_t unused_4[0x5]; /* Gap */ + uint16_t mctr; /* Memory Configuration and Timing. */ + uint16_t unused_5[0x3]; /* Gap */ + uint16_t fb_cmd; + uint16_t unused_6[0x3]; /* Gap */ + uint16_t host_cmd; /* Host command and control */ + + #define HOST_INT BIT_7 /* host interrupt bit */ +#ifdef FC_IP_SUPPORT + uint16_t unused_3[0x0F]; /* Gap */ + uint16_t mailbox8; /* Mailbox 8 */ + uint16_t mailbox9; /* Mailbox 9 */ + uint16_t mailbox10; /* Mailbox 10 */ + uint16_t mailbox11; /* Mailbox 11 */ + uint16_t mailbox12; /* Mailbox 12 */ + uint16_t mailbox13; /* Mailbox 13 */ + uint16_t mailbox14; /* Mailbox 14 */ + uint16_t mailbox15; /* Mailbox 15 */ + uint16_t mailbox16; /* Mailbox 16 */ + uint16_t mailbox17; /* Mailbox 17 */ + uint16_t mailbox18; /* Mailbox 18 */ + uint16_t mailbox19; /* Mailbox 19 */ + uint16_t mailbox20; /* Mailbox 20 */ + uint16_t mailbox21; /* Mailbox 21 */ + uint16_t mailbox22; /* Mailbox 22 */ + uint16_t mailbox23; /* Mailbox 23 */ +#endif + +}device_reg_t; + +/* + * 2300 ISP I/O Register Set structure definitions. + */ +typedef volatile struct +{ + uint16_t flash_address; /* Flash BIOS address */ + uint16_t flash_data; /* Flash BIOS data */ + uint16_t unused_1[1]; /* Gap */ + uint16_t ctrl_status; /* Control/Status */ + #define ISP_FLASH_ENABLE BIT_1 /* Flash BIOS Read/Write enable */ + #define ISP_RESET BIT_0 /* ISP soft reset */ + uint16_t ictrl; /* Interrupt control */ + #define ISP_EN_INT BIT_15 /* ISP enable interrupts. */ + #define ISP_EN_RISC BIT_3 /* ISP enable RISC interrupts. */ + uint16_t istatus; /* Interrupt status @0xa*/ + #define RISC_2300_INT BIT_15 /* 2300 RISC int for non-ROM cmds */ + uint16_t semaphore; /* Semaphore */ + uint16_t nvram; /* NVRAM register. @0xf */ + #define NV_DESELECT 0 + #define NV_CLOCK BIT_0 + #define NV_SELECT BIT_1 + #define NV_DATA_OUT BIT_2 + #define NV_DATA_IN BIT_3 + /* 2300 */ + uint16_t req_q_in /* @0x10 */; + uint16_t req_q_out /* @0x12 */; + uint16_t rsp_q_in /* @0x14 */; + uint16_t rsp_q_out /* @0x16 */; + uint32_t host_status /* @0x18 */; + uint16_t unused3[0x12]; + uint16_t mailbox0; /* Mailbox 0 @0x40 */ + uint16_t mailbox1; /* Mailbox 1 */ + uint16_t mailbox2; /* Mailbox 2 */ + uint16_t mailbox3; /* Mailbox 3 */ + uint16_t mailbox4; /* Mailbox 4 */ + uint16_t mailbox5; /* Mailbox 5 */ + uint16_t mailbox6; /* Mailbox 6 */ + uint16_t mailbox7; /* Mailbox 7 @0x4E */ + uint16_t mailbox8; /* Mailbox 8 */ + uint16_t mailbox9; /* Mailbox 9 */ + uint16_t mailbox10; /* Mailbox 10 */ + uint16_t mailbox11; /* Mailbox 11 */ + uint16_t mailbox12; /* Mailbox 12 */ + uint16_t mailbox13; /* Mailbox 13 */ + uint16_t mailbox14; /* Mailbox 14 */ + uint16_t mailbox15; /* Mailbox 15 */ + uint16_t mailbox16; /* Mailbox 16 */ + uint16_t mailbox17; /* Mailbox 17 */ + uint16_t mailbox18; /* Mailbox 18 */ + uint16_t mailbox19; /* Mailbox 19 */ + uint16_t mailbox20; /* Mailbox 20 */ + uint16_t mailbox21; /* Mailbox 21 */ + uint16_t mailbox22; /* Mailbox 22 */ + uint16_t mailbox23; /* Mailbox 23 */ + uint16_t mailbox24; /* Mailbox 24 */ + uint16_t mailbox25; /* Mailbox 25 */ + uint16_t mailbox26; /* Mailbox 26 */ + uint16_t mailbox27; /* Mailbox 27 */ + uint16_t mailbox28; /* Mailbox 28 */ + uint16_t mailbox29; /* Mailbox 29 */ + uint16_t mailbox30; /* Mailbox 30 */ + uint16_t mailbox31; /* Mailbox 31 @0x7E */ + uint16_t unused4[0xb]; /* gap */ + + uint16_t fpm_diag_config; + uint16_t unused_3[0x6]; /* Gap */ + uint16_t pcr; /* Processor Control Register. */ + uint16_t unused_4[0x5]; /* Gap */ + uint16_t mctr; /* Memory Configuration and Timing. */ + uint16_t unused_5[0x3]; /* Gap */ + uint16_t fb_cmd; + uint16_t unused_6[0x3]; /* Gap */ + uint16_t host_cmd; /* Host command and control */ + + #define HOST_INT BIT_7 /* host interrupt bit */ +#ifdef FC_IP_SUPPORT + uint16_t unused_3[0x0F]; /* Gap */ + uint16_t mailbox8; /* Mailbox 8 */ + uint16_t mailbox9; /* Mailbox 9 */ + uint16_t mailbox10; /* Mailbox 10 */ + uint16_t mailbox11; /* Mailbox 11 */ + uint16_t mailbox12; /* Mailbox 12 */ + uint16_t mailbox13; /* Mailbox 13 */ + uint16_t mailbox14; /* Mailbox 14 */ + uint16_t mailbox15; /* Mailbox 15 */ + uint16_t mailbox16; /* Mailbox 16 */ + uint16_t mailbox17; /* Mailbox 17 */ + uint16_t mailbox18; /* Mailbox 18 */ + uint16_t mailbox19; /* Mailbox 19 */ + uint16_t mailbox20; /* Mailbox 20 */ + uint16_t mailbox21; /* Mailbox 21 */ + uint16_t mailbox22; /* Mailbox 22 */ + uint16_t mailbox23; /* Mailbox 23 */ +#endif + +}device2300_reg_t; + + +#define MAILBOX_REGISTER_COUNT 32 + +/* + * ISP product identification definitions in mailboxes after reset. + */ +#define PROD_ID_1 0x4953 +#define PROD_ID_2 0x0000 +#define PROD_ID_2a 0x5020 +#define PROD_ID_3 0x2020 +#define PROD_ID_4 0x1 + +/* + * ISP host command and control register command definitions + */ +#define HC_RESET_RISC 0x1000 /* Reset RISC */ +#define HC_PAUSE_RISC 0x2000 /* Pause RISC */ +#define HC_RELEASE_RISC 0x3000 /* Release RISC from reset. */ +#define HC_SET_HOST_INT 0x5000 /* Set host interrupt */ +#define HC_CLR_HOST_INT 0x6000 /* Clear HOST interrupt */ +#define HC_CLR_RISC_INT 0x7000 /* Clear RISC interrupt */ +#define HC_RISC_PAUSE BIT_5 +#define HC_DISABLE_PARITY_PAUSE 0x4001 /* Disable parity error RISC pause. */ + +#define SEMAPHORE_SET 0x1234 + +/* + * ISP mailbox Self-Test status codes + */ +#define MBS_FRM_ALIVE 0 /* Firmware Alive. */ +#define MBS_CHKSUM_ERR 1 /* Checksum Error. */ +#define MBS_BUSY 4 /* Busy. */ + +/* + * ISP mailbox command complete status codes + */ +#define MBS_CMD_CMP 0x4000 /* Command Complete. */ +#define MBS_INV_CMD 0x4001 /* Invalid Command. */ +#define MBS_HOST_INF_ERR 0x4002 /* Host Interface Error. */ +#define MBS_TEST_FAILED 0x4003 /* Test Failed. */ +#define MBS_CMD_ERR 0x4005 /* Command Error. */ +#define MBS_CMD_PARAM_ERR 0x4006 /* Command Parameter Error. */ +#define MBS_FATAL_ERROR 0xF000 /* Command Fatal Error. */ + +#define MBS_FIRMWARE_ALIVE 0x0000 +#define MBS_COMMAND_COMPLETE 0x4000 +#define MBS_INVALID_COMMAND 0x4001 + +/* QLogic subroutine status definitions */ +#define QL_STATUS_SUCCESS 0 +#define QL_STATUS_ERROR 1 +#define QL_STATUS_FATAL_ERROR 2 +#define QL_STATUS_RESOURCE_ERROR 3 +#define QL_STATUS_LOOP_ID_IN_USE 4 +#define QL_STATUS_NO_DATA 5 + +/* + * ISP mailbox asynchronous event status codes + */ +#define MBA_ASYNC_EVENT 0x8000 /* Asynchronous event. */ +#define MBA_RESET 0x8001 /* Reset Detected. */ +#define MBA_SYSTEM_ERR 0x8002 /* System Error. */ +#define MBA_REQ_TRANSFER_ERR 0x8003 /* Request Transfer Error. */ +#define MBA_RSP_TRANSFER_ERR 0x8004 /* Response Transfer Error. */ +#define MBA_WAKEUP_THRES 0x8005 /* Request Queue Wake-up. */ +#define MBA_LIP_OCCURRED 0x8010 /* Loop Initialization Procedure */ + /* occurred. */ +#define MBA_LOOP_UP 0x8011 /* FC Loop UP. */ +#define MBA_LOOP_DOWN 0x8012 /* FC Loop Down. */ +#define MBA_LIP_RESET 0x8013 /* LIP reset occurred. */ +#define MBA_PORT_UPDATE 0x8014 /* Port Database update. */ +#define MBA_SCR_UPDATE 0x8015 /* State Change Registration. */ +#define MBA_SCSI_COMPLETION 0x8020 /* SCSI Command Complete. */ +#define MBA_CTIO_COMPLETION 0x8021 /* CTIO Complete. */ +#ifdef ISP2200 +#define MBA_LINK_MODE_UP 0x8030 /* FC Link Mode UP. */ +#define MBA_UPDATE_CONFIG 0x8036 /* FC Update Configuration. */ +#endif + +/* + * ISP mailbox commands + */ +#define MBC_LOAD_RAM 1 /* Load RAM. */ +#define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ +#define MBC_WRITE_RAM_WORD 4 /* Write RAM word. */ +#define MBC_READ_RAM_WORD 5 /* Read RAM word. */ +#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ +#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */ +#define MBC_ABOUT_FIRMWARE 8 /* Get firmware revision. */ +#define MBC_DUMP_RAM 0xA /* READ BACK FW */ +#define MBC_DUMP_SRAM 0xC /* Dump SRAM */ +#define MBC_IOCB_EXECUTE 0x12 /* Execute an IOCB command */ +#define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */ +#define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */ +#define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */ +#define MBC_TARGET_RESET 0x18 /* Target reset. */ +#define MBC_GET_ADAPTER_LOOP_ID 0x20 /* Get loop id of ISP2100. */ +#define MBC_SET_TARGET_PARAMATERS 0x38 /* Set target parameters. */ +#define MBC_DIAGNOSTIC_LOOP_BACK 0x45 /* Perform LoopBack diagnostic */ +#define MBC_INITIALIZE_FIRMWARE 0x60 /* Initialize firmware */ +#define MBC_INITIATE_LIP 0x62 /* Initiate Loop Initialization */ + /* Procedure */ +#define MBC_GET_PORT_DATABASE 0x64 /* Get port database. */ +#define MBC_GET_FIRMWARE_STATE 0x69 /* Get firmware state. */ +#define MBC_GET_PORT_NAME 0x6a /* Get port name. */ +#define MBC_LIP_RESET 0x6c /* LIP reset. */ +#define MBC_SEND_SNS_COMMAND 0x6e /* Send Simple Name Server command. */ +#define MBC_LOGIN_FABRIC_PORT 0x6f /* Login fabric port. */ +#define MBC_LOGOUT_FABRIC_PORT 0x71 /* Logout fabric port. */ +#define MBC_LIP_FULL_LOGIN 0x72 /* Full login LIP. */ +#define MBC_GET_PORT_LIST 0x75 /* Get port list. */ + +/* + * Firmware state codes from get firmware state mailbox command + */ +#define FSTATE_CONFIG_WAIT 0 +#define FSTATE_WAIT_AL_PA 1 +#define FSTATE_WAIT_LOGIN 2 +#define FSTATE_READY 3 +#define FSTATE_LOSS_OF_SYNC 4 +#define FSTATE_ERROR 5 +#define FSTATE_REINIT 6 +#define FSTATE_NON_PART 7 + +#define FSTATE_CONFIG_CORRECT 0 +#define FSTATE_P2P_RCV_LIP 1 +#define FSTATE_P2P_CHOOSE_LOOP 2 +#define FSTATE_P2P_RCV_UNIDEN_LIP 3 +#define FSTATE_FATAL_ERROR 4 +#define FSTATE_LOOP_BACK_CONN 5 + +/* + * ISP Initialization Control Block. + */ +typedef struct +{ + uint8_t version; + #define ICB_VERSION 1 + uint8_t reserved_1; + struct + { + uint8_t enable_hard_loop_id :1; /* bit 0 */ + uint8_t enable_fairness :1; + uint8_t enable_full_duplex :1; + uint8_t enable_fast_posting :1; + uint8_t enable_target_mode :1; + uint8_t disable_initiator_mode :1; + uint8_t enable_adisc :1; + uint8_t enable_lun_response :1; /* bit 7 */ + uint8_t enable_port_update_event :1; + uint8_t disable_initial_lip :1; + uint8_t enable_decending_soft_assign :1; + uint8_t previous_assigned_addressing :1; + uint8_t enable_stop_q_on_full :1; + uint8_t enable_full_login_on_lip :1; + uint8_t enable_name_change :1; + uint8_t expanded_ifwcb :1; /* bit 15 */ + }firmware_options; + uint16_t frame_length; + uint16_t iocb_allocation; + uint16_t execution_throttle; + uint8_t retry_count; + uint8_t retry_delay; +#ifdef ISP2200 + uint8_t port_name[8]; +#else + uint8_t node_name[8]; +#endif + uint16_t adapter_hard_loop_id; + uint8_t inquiry_data; + uint8_t login_timeout; +#ifdef ISP2200 + uint8_t node_name[8]; +#else + uint8_t reserved_1[8]; +#endif + uint16_t request_q_outpointer; + uint16_t response_q_inpointer; + uint16_t request_q_length; + uint16_t response_q_length; + uint32_t request_q_address[2]; + uint32_t response_q_address[2]; + uint16_t lun_enables; + uint8_t command_resource_count; + uint8_t immediate_notify_resource_count; + uint16_t timeout; + uint16_t reserved_2; + struct + { + uint8_t operation_mode :4; /* Bits 0 1 2 3 */ + uint8_t connection_options :3; /* Bits 4 5 6 */ + #define LOOP 0 + #define P2P 1 + #define LOOP_P2P 2 + #define P2P_LOOP 3 + uint8_t nonpart_if_hard_addr_failed :1; /* Bit 7 */ + uint8_t enable_class2 :1; /* Bit 8 */ + uint8_t enable_ack0 :1; /* Bit 9 */ + uint8_t unused_10 :1; /* bit 10 */ + uint8_t unused_11 :1; /* bit 11 */ + uint8_t enable_fc_tape :1; /* bit 12 */ + uint8_t enable_fc_confirm :1; /* bit 13 */ + uint8_t enable_cmd_q_target_mode :1; /* bit 14 */ + uint8_t unused_15 :1; /* bit 15 */ + }additional_firmware_options; + uint8_t response_accum_timer; + uint8_t interrupt_delay_timer; + struct + { + uint8_t enable_read_xfr_rdy :1; /* Bit 0 */ + uint8_t soft_id_only :1; /* Bit 1 */ + uint8_t unused_2 :1; /* Bit 2 */ + uint8_t unused_3 :1; /* Bit 3 */ + uint8_t fcp_rsp_payload :2; /* Bits 4 5 */ + #define send_24_bytes_0 0 + #define send_12_bytes_0 1 + #define second_send_24_bytes_0 2 + #define send_32_bytes_0 3 + uint8_t unused_6 :1; /* Bit 6 */ + uint8_t unused_7 :1; /* Bit 7 */ + uint8_t unused_8 :1; /* Bit 8 */ + uint8_t unused_9 :1; /* Bit 9 */ + uint8_t unused_10 :1; /* Bit 10 */ + uint8_t unused_11 :1; /* Bit 11 */ + uint8_t unused_12 :1; /* Bit 12 */ + uint8_t set_50_ohms_term_enable :1; /* Bit 13 */ + uint8_t data_rate :2; /* Bits 14 15 */ + #define set_1_gig_rate 0 + #define set_2_gig_rate 1 + #define auto_negotiate 2 + }special_options; + uint16_t reserved_3[13]; +}init_cb_t; + +/* + * ISP Get/Set Target Parameters mailbox command control flags. + */ + +/* + * NVRAM Command values. + */ +#define NV_START_BIT BIT_2 +#define NV_WRITE_OP (BIT_26+BIT_24) +#define NV_READ_OP (BIT_26+BIT_25) +#define NV_ERASE_OP (BIT_26+BIT_25+BIT_24) +#define NV_MASK_OP (BIT_26+BIT_25+BIT_24) +#define NV_DELAY_COUNT 10 + +/* + * ISP2200 NVRAM structure definitions. + */ +typedef struct +{ + /* + * NVRAM header + */ + + uint8_t id[4]; + uint8_t nvram_version; + uint8_t reserved_0; + + /* + * NVRAM RISC parameter block + */ + + uint8_t parameter_block_version; + uint8_t reserved_1; + + struct + { + uint8_t enable_hard_loop_id :1; + uint8_t enable_fairness :1; + uint8_t enable_full_duplex :1; + uint8_t enable_fast_posting :1; + uint8_t enable_target_mode :1; + uint8_t disable_initiator_mode :1; + uint8_t enable_adisc :1; + uint8_t enable_lun_response :1; + uint8_t enable_port_update_event :1; + uint8_t disable_initial_lip :1; + uint8_t enable_decending_soft_assign :1; + uint8_t previous_assigned_addressing :1; + uint8_t enable_stop_q_on_full :1; + uint8_t enable_full_login_on_lip :1; + uint8_t enable_name_change :1; + uint8_t expanded_ifwcb :1; + }firmware_options; + + uint16_t frame_payload_size; + uint16_t max_iocb_allocation; + uint16_t execution_throttle; + uint8_t retry_count; + uint8_t retry_delay; + uint8_t port_name[8]; + uint16_t adapter_hard_loop_id; + uint8_t inquiry_data; + uint8_t login_timeout; + + uint8_t node_name[8]; + + /* Expanded RISC parameter block */ + struct + { + uint8_t operation_mode :4; + uint8_t connection_options :3; + uint8_t nonpart_if_hard_addr_failed :1; + uint8_t enable_class2 :1; + uint8_t enable_ack0 :1; + uint8_t unused_10 :1; + uint8_t unused_11 :1; + uint8_t enable_fc_tape :1; + uint8_t enable_fc_confirm :1; + uint8_t enable_command_reference_num :1; + }additional_firmware_options; + + uint8_t response_accum_timer; + uint8_t interrupt_delay_timer; + uint16_t reserved_2[14]; + + /* + * NVRAM host parameter block + */ + + struct + { + uint8_t unused_0 :1; + uint8_t disable_bios :1; + uint8_t disable_luns :1; + uint8_t enable_selectable_boot :1; + uint8_t disable_risc_code_load :1; + uint8_t set_cache_line_size_1 :1; + uint8_t pci_parity_disable :1; + uint8_t enable_extended_logging :1; + uint8_t enable_64bit_addressing :1; + uint8_t enable_lip_reset :1; + uint8_t enable_lip_full_login :1; + uint8_t enable_target_reset :1; + uint8_t enable_database_storage :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }host_p; + + uint8_t boot_node_name[8]; + uint8_t boot_lun_number; + uint8_t reset_delay; + uint8_t port_down_retry_count; + uint8_t reserved_3; + + uint16_t maximum_luns_per_target; + + uint16_t reserved_6[7]; + + /* Offset 100 */ + uint16_t reserved_7[25]; + + /* Offset 150 */ + uint16_t reserved_8[25]; + + /* Offset 200 */ + uint8_t oem_id; + + uint8_t oem_spare0; + + uint8_t oem_string[6]; + + uint8_t oem_part[8]; + + uint8_t oem_fru[8]; + + uint8_t oem_ec[8]; + + + /* Offset 232 */ + struct + { + uint8_t external_gbic :1; + uint8_t risc_ram_parity :1; + uint8_t buffer_plus_module :1; + uint8_t multi_chip_hba :1; + uint8_t unused_1 :1; + uint8_t unused_2 :1; + uint8_t unused_3 :1; + uint8_t unused_4 :1; + uint8_t unused_5 :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t unused_8 :1; + uint8_t unused_9 :1; + uint8_t unused_10 :1; + uint8_t unused_11 :1; + uint8_t unused_12 :1; + }hba_features; + + uint16_t reserved_9; + uint16_t reserved_10; + uint16_t reserved_11; + + uint16_t reserved_12; + uint16_t reserved_13; + + /* Subsystem ID must be at offset 244 */ + uint16_t subsystem_vendor_id; + + uint16_t reserved_14; + + /* Subsystem device ID must be at offset 248 */ + uint16_t subsystem_device_id; + + uint16_t reserved_15[2]; + uint8_t reserved_16; + uint8_t checksum; +}nvram22_t; + +typedef struct +{ + /* + * NVRAM header for 2100 board. + */ + + uint8_t id[4]; + uint8_t nvram_version; + uint8_t reserved_0; + + /* + * NVRAM RISC parameter block + */ + + uint8_t parameter_block_version; + uint8_t reserved_1; + + struct + { + uint8_t enable_hard_loop_id :1; + uint8_t enable_fairness :1; + uint8_t enable_full_duplex :1; + uint8_t enable_fast_posting :1; + uint8_t enable_target_mode :1; + uint8_t disable_initiator_mode :1; + uint8_t enable_adisc :1; + uint8_t enable_lun_response :1; + uint8_t enable_port_update_event :1; + uint8_t disable_initial_lip :1; + uint8_t enable_decending_soft_assign :1; + uint8_t previous_assigned_addressing :1; + uint8_t enable_stop_q_on_full :1; + uint8_t enable_full_login_on_lip :1; + uint8_t enable_name_change :1; + uint8_t unused_15 :1; + }firmware_options; + + uint16_t frame_payload_size; + uint16_t max_iocb_allocation; + uint16_t execution_throttle; + uint8_t retry_count; + uint8_t retry_delay; + uint8_t node_name[8]; + uint16_t adapter_hard_loop_id; + uint8_t reserved_2; + uint8_t login_timeout; + uint16_t reserved_3[4]; + + /* Reserved for expanded RISC parameter block */ + uint16_t reserved_4[16]; + + /* + * NVRAM host parameter block + */ + + struct + { + uint8_t unused_0 :1; + uint8_t disable_bios :1; + uint8_t disable_luns :1; + uint8_t enable_selectable_boot :1; + uint8_t disable_risc_code_load :1; + uint8_t set_cache_line_size_1 :1; + uint8_t pci_parity_disable :1; + uint8_t enable_extended_logging :1; + uint8_t enable_64bit_addressing :1; + uint8_t enable_lip_reset :1; + uint8_t enable_lip_full_login :1; + uint8_t enable_target_reset :1; + uint8_t enable_database_storage :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }host_p; + + uint8_t boot_node_name[8]; + uint8_t boot_lun_number; + uint8_t reset_delay; + uint8_t port_down_retry_count; + uint8_t reserved_5; + + uint16_t maximum_luns_per_target; + + uint16_t reserved_6[7]; + + /* Offset 100 */ + uint16_t reserved_7[25]; + + /* Offset 150 */ + uint16_t reserved_8[25]; + + /* Offset 200 */ + uint16_t reserved_9[22]; + + /* Subsystem ID must be at offset 244 */ + uint16_t subsystem_vendor_id; + + uint16_t reserved_10; + + /* Subsystem device ID must be at offset 248 */ + uint16_t subsystem_device_id; + + uint16_t reserved_11[2]; + uint8_t reserved_12; + uint8_t checksum; +}nvram21_t; + +/* + * ISP queue - command entry structure definition. + */ +#define MAX_CMDSZ 16 /* SCSI maximum CDB size. */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define COMMAND_TYPE 0x11 /* Command entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t reserved; + uint8_t target; /* SCSI ID */ + uint16_t lun; /* SCSI LUN */ + uint16_t control_flags; /* Control flags. */ +#define CF_HEAD_TAG BIT_1 +#define CF_ORDERED_TAG BIT_2 +#define CF_SIMPLE_TAG BIT_3 +#define CF_READ BIT_5 +#define CF_WRITE BIT_6 +#define CF_NO_FAST_POSTING BIT_7 + uint16_t reserved_1; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + uint32_t byte_count; /* Total byte count. */ + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ +}cmd_entry_t; + +/* + * ISP queue - 64-Bit addressing, command entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define COMMAND_A64_TYPE 0x19 /* Command A64 entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t reserved; + uint8_t target; /* SCSI ID */ + uint16_t lun; /* SCSI LUN */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved_1; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + uint32_t byte_count; /* Total byte count. */ + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ +}cmd_a64_entry_t, request_t; + +/* + * ISP queue - continuation entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_TYPE 0x02 /* Continuation entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved; + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ + uint32_t dseg_4_address; /* Data segment 4 address. */ + uint32_t dseg_4_length; /* Data segment 4 length. */ + uint32_t dseg_5_address; /* Data segment 5 address. */ + uint32_t dseg_5_length; /* Data segment 5 length. */ + uint32_t dseg_6_address; /* Data segment 6 address. */ + uint32_t dseg_6_length; /* Data segment 6 length. */ +}cont_entry_t; + +/* + * ISP queue - 64-Bit addressing, continuation entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_A64_TYPE 0x0A /* Continuation A64 entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address[2]; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address[2]; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ + uint32_t dseg_4_address[2]; /* Data segment 4 address. */ + uint32_t dseg_4_length; /* Data segment 4 length. */ +}cont_a64_entry_t; + +/* + * ISP queue - status entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define STATUS_TYPE 0x03 /* Status entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + #define RF_INV_E_ORDER BIT_5 /* Invalid entry order. */ + #define RF_INV_E_COUNT BIT_4 /* Invalid entry count. */ + #define RF_INV_E_PARAM BIT_3 /* Invalid entry parameter. */ + #define RF_INV_E_TYPE BIT_2 /* Invalid entry type. */ + #define RF_BUSY BIT_1 /* Busy */ + uint32_t handle; /* System handle. */ + uint16_t scsi_status; /* SCSI status. */ + uint16_t comp_status; /* Completion status. */ + uint16_t state_flags; /* State flags. */ + uint16_t status_flags; /* Status flags. */ + #define IOCBSTAT_SF_LOGO 0x2000 /* logo after 2 abts w/ no response (2 sec) */ + uint16_t rsp_info_len; /* Response Info Length. */ + uint16_t req_sense_length; /* Request sense data length. */ + uint32_t residual_length; /* Residual transfer length. */ + uint8_t rsp_info[8]; /* FCP response information. */ + uint8_t req_sense_data[32]; /* Request sense data. */ +}sts_entry_t, response_t; + +/* + * ISP queue - marker entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define MARKER_TYPE 0x04 /* Marker entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved; + uint8_t target; /* SCSI ID */ + uint8_t modifier; /* Modifier (7-0). */ + #define MK_SYNC_ID_LUN 0 /* Synchronize ID/LUN */ + #define MK_SYNC_ID 1 /* Synchronize ID */ + #define MK_SYNC_ALL 2 /* Synchronize all ID/LUN */ + #define MK_SYNC_LIP 3 /* Synchronize all ID/LUN, */ + /* clear port changed, */ + /* use sequence number. */ + uint8_t reserved_1; + uint16_t sequence_number; /* Sequence number of event */ + uint16_t lun; /* SCSI LUN */ + uint8_t reserved_2[48]; +}mrk_entry_t; + +/* + * ISP queue - enable LUN entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define ENABLE_LUN_TYPE 0x0B /* Enable LUN entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t reserved_1; + uint16_t reserved_2; + uint32_t reserved_3; + uint8_t status; + uint8_t reserved_4; + uint8_t command_count; /* Number of ATIOs allocated. */ + uint8_t immed_notify_count; /* Number of Immediate Notify */ + /* entries allocated. */ + uint16_t reserved_5; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t reserved_6[20]; +}elun_entry_t; + +/* + * ISP queue - modify LUN entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define MODIFY_LUN_TYPE 0x0C /* Modify LUN entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t reserved_1; + uint8_t operators; + uint8_t reserved_2; + uint32_t reserved_3; + uint8_t status; + uint8_t reserved_4; + uint8_t command_count; /* Number of ATIOs allocated. */ + uint8_t immed_notify_count; /* Number of Immediate Notify */ + /* entries allocated. */ + uint16_t reserved_5; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t reserved_7[20]; +}modify_lun_entry_t; + +/* + * ISP queue - immediate notify entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define IMMED_NOTIFY_TYPE 0x0D /* Immediate notify entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t initiator_id; + uint8_t reserved_1; + uint8_t target_id; + uint32_t reserved_2; + uint16_t status; + uint16_t task_flags; + uint16_t seq_id; + uint16_t reserved_5[11]; + uint16_t scsi_status; + uint8_t sense_data[18]; +}notify_entry_t; + +/* + * ISP queue - notify acknowledge entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define NOTIFY_ACK_TYPE 0x0E /* Notify acknowledge entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t initiator_id; + uint8_t reserved_1; + uint8_t target_id; + uint16_t flags; + uint16_t reserved_2; + uint16_t status; + uint16_t task_flags; + uint16_t seq_id; + uint16_t reserved_3[21]; +}nack_entry_t; + +/* + * ISP queue - Accept Target I/O (ATIO) entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define ACCEPT_TGT_IO_TYPE 0x16 /* Accept target I/O entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t initiator_id; + uint16_t exchange_id; + uint16_t flags; + uint16_t status; + uint8_t reserved_1; + uint8_t task_codes; + uint8_t task_flags; + uint8_t execution_codes; + uint8_t cdb[MAX_CMDSZ]; + uint32_t data_length; + uint16_t lun; + uint16_t reserved_2A; + uint16_t scsi_status; + uint8_t sense_data[18]; +}atio_entry_t; + +/* + * ISP queue - Continue Target I/O (CTIO) entry for status mode 0 + * structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_TGT_IO_TYPE 0x17 /* CTIO entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t initiator_id; + uint16_t exchange_id; + uint16_t flags; + uint16_t status; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t relative_offset; + uint32_t residual; + uint16_t reserved_1[3]; + uint16_t scsi_status; + uint32_t transfer_length; + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ +}ctio_entry_t; + +/* + * ISP queue - CTIO returned entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_RET_TYPE 0x17 /* CTIO return entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t initiator_id; + uint16_t exchange_id; + uint16_t flags; + uint16_t status; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t relative_offset; + uint32_t residual; + uint16_t reserved_1[8]; + uint16_t scsi_status; + uint8_t sense_data[18]; +}ctio_ret_entry_t; + +/* + * ISP queue - CTIO A64 entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_A64_TYPE 0x1F /* CTIO A64 entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t initiator_id; + uint16_t exchange_id; + uint16_t flags; + uint16_t status; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t relative_offset; + uint32_t residual; + uint16_t reserved_1[3]; + uint16_t scsi_status; + uint32_t transfer_length; + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ +}ctio_a64_entry_t; + +/* + * ISP queue - CTIO returned entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_A64_RET_TYPE 0x1F /* CTIO A64 returned entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint8_t reserved_8; + uint8_t initiator_id; + uint16_t exchange_id; + uint16_t flags; + uint16_t status; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t relative_offset; + uint32_t residual; + uint16_t reserved_1[8]; + uint16_t scsi_status; + uint8_t sense_data[18]; +}ctio_a64_ret_entry_t; + +/* + * ISP queue - Status Contination entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define STATUS_CONT_TYPE 0x10 /* Status contination entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved; + uint8_t entry_status; /* Entry Status. */ + uint8_t sense_data[60]; +}status_cont_entry_t; + +/* + * ISP queue - Command Set entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CMD_SET_TYPE 0x18 /* Command set entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint16_t reserved; + uint16_t status; + uint16_t control_flags; /* Control flags. */ + uint16_t count; + uint32_t iocb_0_address; + uint32_t iocb_1_address; + uint32_t iocb_2_address; + uint32_t iocb_3_address; + uint32_t iocb_4_address; + uint32_t iocb_5_address; + uint32_t iocb_6_address; + uint32_t iocb_7_address; + uint32_t iocb_8_address; + uint32_t iocb_9_address; + uint32_t iocb_10_address; + uint32_t iocb_11_address; +}cmd_set_entry_t; + +/* + * ISP queue - Command Set A64 entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CMD_SET_TYPE 0x18 /* Command set entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t sys_define_2; /* System defined. */ + uint16_t reserved; + uint16_t status; + uint16_t control_flags; /* Control flags. */ + uint16_t count; + uint32_t iocb_0_address[2]; + uint32_t iocb_1_address[2]; + uint32_t iocb_2_address[2]; + uint32_t iocb_3_address[2]; + uint32_t iocb_4_address[2]; + uint32_t iocb_5_address[2]; +}cmd_set_a64_entry_t; + +/* 4.11 + * ISP queue - Command Set entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define MS_IOCB_TYPE 0x29 /* Management Server IOCB entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t reserved; + uint8_t loop_id; + uint16_t status; + uint16_t control_flags; /* Control flags. */ + uint16_t reserved2; + uint16_t timeout; + uint16_t DSDcount; + uint16_t RespDSDcount; + uint8_t reserved3[10]; + uint32_t Response_bytecount; + uint32_t Request_bytecount; + uint32_t dseg_req_address[2]; /* Data segment 0 address. */ + uint32_t dseg_req_length; /* Data segment 0 length. */ + uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */ + uint32_t dseg_rsp_length; /* Data segment 1 length. */ +}cmd_ms_iocb_entry_t; + + +/* + * ISP request and response queue entry sizes + */ +#define RESPONSE_ENTRY_SIZE (sizeof(response_t)) +#define REQUEST_ENTRY_SIZE (sizeof(request_t)) + +/* + * ISP status entry - completion status definitions. + */ +#define CS_COMPLETE 0x0 /* No errors */ +#define CS_INCOMPLETE 0x1 /* Incomplete transfer of cmd. */ +#define CS_DMA 0x2 /* A DMA direction error. */ +#define CS_TRANSPORT 0x3 /* Transport error. */ +#define CS_RESET 0x4 /* SCSI bus reset occurred */ +#define CS_ABORTED 0x5 /* System aborted command. */ +#define CS_TIMEOUT 0x6 /* Timeout error. */ +#define CS_DATA_OVERRUN 0x7 /* Data overrun. */ +#define CS_DATA_UNDERRUN 0x15 /* Data Underrun. */ +#define CS_ABORT_MSG 0xE /* Target rejected abort msg. */ +#define CS_DEV_RESET_MSG 0x12 /* Target rejected dev rst msg. */ +#define CS_PORT_UNAVAILABLE 0x28 /* Port unavailable (selection timeout) */ +#define CS_PORT_LOGGED_OUT 0x29 /* Port Logged Out */ +#define CS_PORT_CONFIG_CHG 0x2A /* Port Configuration Changed */ +#define CS_PORT_BUSY 0x2B /* Port Busy */ +#define CS_BAD_PAYLOAD 0x80 /* Driver defined */ +#define CS_UNKNOWN 0x81 /* Driver defined */ +#define CS_RETRY 0x82 /* Driver defined */ + +/* + * ISP status entry - SCSI status byte bit definitions. + */ +#define SS_RESIDUAL_UNDER BIT_11 +#define SS_RESIDUAL_OVER BIT_10 +#define SS_SENSE_LEN_VALID BIT_9 +#ifdef ISP2200 +#define SS_RESPONSE_INFO_LEN_VALID BIT_8 +#else +#define SS_RESIDUAL_LEN_VALID BIT_8 +#endif + +#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3) +#define SS_BUSY_CONDITION BIT_3 +#define SS_CONDITION_MET BIT_2 +#define SS_CHECK_CONDITION BIT_1 + +/* + * ISP target entries - Flags bit definitions. + */ +#define OF_RESET BIT_5 /* Reset LIP flag */ +#define OF_DATA_IN BIT_6 /* Data in to initiator */ + /* (data from target to initiator) */ +#define OF_DATA_OUT BIT_7 /* Data out from initiator */ + /* (data from initiator to target) */ +#define OF_NO_DATA (BIT_7 | BIT_6) +#define OF_INC_RC BIT_8 /* Increment command resource count */ +#define OF_FAST_POST BIT_9 /* Enable mailbox fast posting. */ +#define OF_SSTS BIT_15 /* Send SCSI status */ + +/* + * Target Read/Write buffer structure. + */ +#define TARGET_DATA_OFFSET 4 +#define TARGET_DATA_SIZE 0x2000 /* 8K */ +#define TARGET_INQ_OFFSET (TARGET_DATA_OFFSET + TARGET_DATA_SIZE) +#define TARGET_SENSE_SIZE 18 +#define TARGET_BUF_SIZE 36 + +#if QL1280_TARGET_MODE_SUPPORT +typedef struct +{ + uint8_t hdr[4]; + uint8_t data[TARGET_DATA_SIZE]; +}tgt_buf_t; +#endif /* QL1280_TARGET_MODE_SUPPORT */ +typedef struct +{ + uint16_t loop_id; +#ifdef QL_MAPPED_TARGETS + uint16_t lun_offset; +#endif + uint32_t down_timer; + scsi_lu_t *luns[MAX_LUNS]; +}tgt_t; + +/* + * 24 bit port ID type definition. + */ +typedef union { + struct { + uint8_t port_id[3]; + uint8_t rsvd_1; + }r; +#if defined(_BIT_FIELDS_LTOH) + uint32_t b24 : 24, + rsvd : 8; + struct { + uint8_t al_pa; + uint8_t area; + uint8_t domain; + uint8_t rsvd_1; + }b; +#else + uint32_t rsvd : 8, + b24 : 24; + struct { + uint8_t domain; + uint8_t area; + uint8_t al_pa; + uint8_t rsvd_1; + }b; +#endif +} port_id_t; + + +typedef struct +{ + uint8_t name[8]; /* big endian node name */ + uint8_t wwn[8]; /* big endian port name */ + uint16_t loop_id; + uint8_t port_id[3]; /* 24-bit port ID */ + uint8_t rsvd_1; + /* + * This is used to retry login for devices specified for + * persistent binding or lost devices. + */ + uint8_t port_login_retry_count; + uint8_t port_timer; + uint16_t flag; + uint32_t mask[8]; /* LUN Mask for this Device */ + /* flags bits defined as follows */ +#define DEV_PUBLIC BIT_0 +#define DEV_OFFLINE BIT_1 +#define DEV_LUNMASK_SET BIT_2 /* some LUNs masked for this device */ +#define DEV_MP_DISABLED BIT_3 /* device disabled for qlmultipath */ +#define DEV_TAPE_DEVICE BIT_4 +#define DEV_CONFIGURED BIT_5 +#define DEV_MISSING BIT_6 +#define DEV_RETURN BIT_7 +#define DEV_HOST BIT_8 +#define DEV_RELOGIN BIT_9 +#define DEV_PORT_DOWN BIT_10 +}fcdev_t; + + +typedef struct +{ + uint8_t in_use; +}fabricid_t; + +/* + * Flash Database structures. + */ +#define FLASH_DATABASE_0 0x1c000 +#define FLASH_DATABASE_1 0x18000 +#define FLASH_DATABASE_VERSION 1 + +typedef struct +{ + uint32_t seq; + uint8_t version; + uint8_t checksum; + uint16_t size; + uint8_t spares[8]; +}flash_hdr_t; + +typedef struct +{ + uint32_t name[2]; + uint8_t spares[8]; +}flash_node_t; + +typedef struct +{ + flash_hdr_t hdr; + flash_node_t node[MAX_FIBRE_DEVICES]; +}flash_database_t; + +/* + * SNS structures. + */ +#define SNS_DATA_SIZE 608 + +typedef struct +{ + uint16_t buffer_length; + uint16_t reserved; + uint32_t buffer_address[2]; + uint16_t subcommand_length; + uint16_t reserved_1; +}sns_hdr_t; + +typedef struct +{ + union + { + struct + { + sns_hdr_t hdr; + uint16_t subcommand; + uint8_t param[SNS_DATA_SIZE - sizeof(sns_hdr_t) - 2]; + }req; + + uint8_t rsp[SNS_DATA_SIZE]; + }p; +}sns_data_t; + +/* + * SNS request/response structures for GP_IDNN. + */ +typedef struct +{ + uint8_t controlbyte; + uint8_t port_id[3]; + uint32_t reserved; + uint8_t nodename[8]; +}port_data_t; + +#ifdef ISP2200 +#define GP_IDNN_LENGTH (256 * sizeof(port_data_t)) + 16 +#else +#define GP_IDNN_LENGTH (126 * sizeof(port_data_t)) + 16 +#endif + +typedef union +{ + struct + { + uint16_t buffer_length; + uint16_t reserved; + uint32_t buffer_address[2]; + uint16_t subcommand_length; + uint16_t reserved_1; + uint16_t subcommand; + uint16_t length; + uint32_t reserved2; + uint32_t protocol; + uint8_t param[GP_IDNN_LENGTH - 28]; + }req; + + struct + { + uint8_t revision; + uint8_t inid[3]; + uint8_t fcstype; + uint8_t subtype; + uint8_t options; + uint8_t reserved; + uint16_t response; + uint16_t residual; + uint8_t reserved1; + uint8_t reason_code; + uint8_t explanation_code; + uint8_t vendor_unique; +#ifdef ISP2200 + port_data_t port_data[256]; +#else + port_data_t port_data[126]; +#endif + }rsp; + +}gp_idnn_t; + +#ifdef ISP2200 +#define GN_LIST_LENGTH 256 * sizeof(port_list_entry_t) +#else +#define GN_LIST_LENGTH 126 * sizeof(port_list_entry_t) +#endif +/* + * Structure used in Get Port List mailbox command (0x75). + */ +typedef struct +{ + uint8_t name[8]; + uint16_t loop_id; +}port_list_entry_t; + +/* + * Structure used for device info. + */ +typedef struct +{ + uint8_t name[8]; /* big endian node name */ + uint8_t wwn[8]; /* big endian port name */ + uint16_t loop_id; + uint8_t port_id[3]; +}device_data_t; + +/* + * Port Database structure definition + * Little endian except where noted. + */ +#define PORT_DATABASE_SIZE 128 /* bytes */ +typedef struct { + uint8_t options; + uint8_t control; + uint8_t master_state; + uint8_t slave_state; +#define PD_STATE_DISCOVERY 0 +#define PD_STATE_WAIT_DISCOVERY_ACK 1 +#define PD_STATE_PORT_LOGIN 2 +#define PD_STATE_WAIT_PORT_LOGIN_ACK 3 +#define PD_STATE_PROCESS_LOGIN 4 +#define PD_STATE_WAIT_PROCESS_LOGIN_ACK 5 +#define PD_STATE_PORT_LOGGED_IN 6 +#define PD_STATE_PORT_UNAVAILABLE 7 +#define PD_STATE_PROCESS_LOGOUT 8 +#define PD_STATE_WAIT_PROCESS_LOGOUT_ACK 9 +#define PD_STATE_PORT_LOGOUT 10 +#define PD_STATE_WAIT_PORT_LOGOUT_ACK 11 + uint8_t reserved[2]; + uint8_t hard_address; + uint8_t reserved_1; + uint8_t port_id[4]; + uint8_t node_name[8]; /* Big endian. */ + uint8_t port_name[8]; /* Big endian. */ + uint16_t execution_throttle; + uint16_t execution_count; + uint8_t reset_count; + uint8_t reserved_2; + uint16_t resource_allocation; + uint16_t current_allocation; + uint16_t queue_head; + uint16_t queue_tail; + uint16_t transmit_execution_list_next; + uint16_t transmit_execution_list_previous; + uint16_t common_features; + uint16_t total_concurrent_sequences; + uint16_t RO_by_information_category; + uint8_t recipient; + uint8_t initiator; + uint16_t receive_data_size; + uint16_t concurrent_sequences; + uint16_t open_sequences_per_exchange; + uint16_t lun_abort_flags; + uint16_t lun_stop_flags; + uint16_t stop_queue_head; + uint16_t stop_queue_tail; + uint16_t port_retry_timer; + uint16_t next_sequence_id; + uint16_t frame_count; + uint16_t PRLI_payload_length; + uint8_t prli_svc_param_word_0[2]; /* Big endian */ + /* Bits 15-0 of word 0 */ + uint8_t prli_svc_param_word_3[2]; /* Big endian */ + /* Bits 15-0 of word 3 */ + uint16_t loop_id; + uint16_t extended_lun_info_list_pointer; + uint16_t extended_lun_stop_list_pointer; +} port_database_t; + + + +/* + * Registered State Change Notification structures. + */ +typedef struct { + port_id_t d_id; + uint8_t format; +} rscn_t; + + + +#ifdef FC_IP_SUPPORT +/* + * Definitions for IP support + */ +#define LOOP_ID_MASK 0x00FF +#define PLE_NOT_SCSI_DEVICE 0x8000 /* Upper bit of loop ID set if not SCSI */ + +/* Firmware IP initialization control block definitions */ +typedef struct _IPInitBlock +{ + uint8_t cVersion; + uint8_t cReserved1; + uint16_t wIpFirmwareOptions; + uint16_t wIpHeaderSize; + uint16_t wIpMTUSize; + uint16_t wIpBufferSize; + uint16_t wReserved2; + uint16_t wReserved3; + uint16_t wReserved4; + uint16_t wReserved5; + uint16_t wIpQueueSize; + uint16_t wIpLowWaterMark; + uint16_t wIpQueueAddr[4]; + uint16_t wIpQueueInPointer; + uint16_t wIpFastPostCount; + uint16_t wIpBufferContainerCount; + uint16_t wIpIocbResourceAllocation; +} IP_INIT_BLOCK, *PIP_INIT_BLOCK; + +#define IPIB_VERSION 0x01 +#define IPIB_LOW_WATER_MARK 0 +#define IPIB_FAST_POST_COUNT 4 +#define IPIB_BUFFER_CONTAINER_COUNT 64 +#define IPIB_IOCB_RESERVE_COUNT 250 + +/* IP firmware options */ +#define IPIB_OPTION_64BIT_ADDRESSING 0x0001 +#define IPIB_OPTION_NO_BROADCAST_FASTPOST 0x0002 +#define IPIB_OPTION_OUT_OF_BUFFERS_EVENT 0x0004 + +/* IP device data structure */ +typedef struct _IpDeviceBlock +{ + uint32_t lDeviceFlags; + uint16_t wLoopId; + uint16_t wUnused1; + uint8_t acWorldWideName[8]; + uint8_t acPortId[3]; + uint8_t cUnused2; + struct _IpDeviceBlock *pNextIpDevice; + struct _IpDeviceBlock *pLastIpDevice; + uint32_t lUnused3; +} IP_DEVICE_BLOCK, *PIP_DEVICE_BLOCK; + +#define IP_DEV_FLAG_PRESENT 0x00000001 +#define IP_DEV_FLAG_PUBLIC_DEVICE 0x00000002 + +#define PUBLIC_LOOP_DEVICE ((uint16_t)-1) + +/* Maximum number of IP connections */ +#define QLLAN_MAX_IP_DEVICES 64 + +/* IP IOCB types */ +#define ET_IP_COMMAND_32 0x13 +#define ET_IP_COMMAND_64 0x1B +#define ET_IP_RECEIVE 0x23 +#define ET_IP_RECEIVE_CONTINUATION 0x2B +#define ET_IP_FARP_REQUEST 0x30 + +/* Data segment descriptor structures */ +typedef struct +{ + uint32_t lBase; + uint32_t lCount; +} DATA_SEG; + +typedef struct +{ + uint32_t lBase[2]; + uint32_t lCount; +} DATA_SEG_A64; + +/* IP Command IOCB structure */ +typedef struct _IpCommandEntry +{ + uint32_t lHeader; + uint32_t lHandle; + uint8_t cReserved1; + uint8_t cLoopId; + uint16_t wCompletionStatus; + uint16_t wControlFlags; + uint16_t wReserved2; + uint16_t wTimeout; + uint16_t wSegmentCount; + uint16_t wServiceClass; + uint16_t wReserved3[7]; + uint32_t lTotalByteCount; + union + { + DATA_SEG asDataSeg[3]; + DATA_SEG_A64 asDataSeg64[2]; + } ds; +} IP_COMMAND_ENTRY, *PIP_COMMAND_ENTRY; + +/* IP Receive IOCB structure */ +#define IP_RECEIVE_ENTRY_MAX_HANDLES 24 +typedef struct _IpReceiveEntry +{ + uint8_t cEntryType; + uint8_t cEntryCount; + uint8_t cSegmentCount; + uint8_t cEntryStatus; + uint16_t wS_IDLow; + uint8_t cS_IDHigh; + uint8_t cReserved1; + uint8_t cReserved2; + uint8_t cLoopId; + uint16_t wCompletionStatus; + uint16_t wServiceClass; + uint16_t wSequenseLength; + uint16_t waBufferHandle[IP_RECEIVE_ENTRY_MAX_HANDLES]; +} IP_RECEIVE_ENTRY, *PIP_RECEIVE_ENTRY; + +/* IP Receive IOCB completion status bits */ +#define IP_REC_STATUS_SPLIT_BUFFER 0x0001 + +/* IP FARP Request IOCB structure */ +typedef struct _IpFarpRequestEntry +{ + uint8_t cEntryType; + uint8_t cEntryCount; + uint8_t cReserved1; + uint8_t cEntryStatus; + uint16_t wRequesterPortIdLow; + uint8_t cRequesterPortIdHigh; + uint8_t cReserved2; + uint8_t acRequesterPortName[8]; +} IP_FARP_REQUEST_ENTRY, *PIP_FARP_REQUEST_ENTRY; + +/* IP mailbox commands */ +#define MBC_INITIALIZE_IP 0x0077 +#define MBC_SEND_FARP_REQUEST 0x0078 + +/* Fabric login mailbox command option bits */ +#define MBC_NO_PLOGI_IF_LOGGED_IN 0x01 +#define MBC_NO_PROCESS_LOGIN 0x02 + +/* Mailbox command completion status */ +#define MBS_PORT_ID_IN_USE 0x4007 +#define MBS_LOOP_ID_IN_USE 0x4008 +#define MBS_ALL_LOOP_IDS_IN_USE 0x4009 +#define MBS_NAME_SERVER_NOT_LOGGED_IN 0x400A + +/* IP async events */ +#define MBA_IP_TRANSMIT_COMPLETE 0x8022 +#define MBA_IP_RECEIVE_COMPLETE 0x8023 +#define MBA_IP_BROADCAST_RECEIVED 0x8024 +#define MBA_IP_RECEIVE_BUFFERS_LOW 0x8025 +#define MBA_IP_OUT_OF_BUFFERS 0x8026 +#define MBA_IP_RECEIVE_COMPLETE_SPLIT 0x8027 + +/* FARP request payload structure */ +typedef struct _IpSendFarpPayload +{ + uint8_t cMatchAddressCode; + uint8_t acReserved1[3]; + uint8_t cResponderFlags; + uint8_t acReserved2[3]; + uint8_t acRequesterPortName[8]; + uint8_t acRequesterNodeName[8]; + uint8_t acResponderPortName[8]; + uint8_t acResponderNodeName[8]; +} IP_SEND_FARP_PAYLOAD, *PIP_SEND_FARP_PAYLOAD; + +#define IP_FARP_MATCH_PORTNAME 0x01 +#define IP_FARP_REQUEST_LOGIN 0x01 +#else +/* Fabric login mailbox command option bits */ +#define MBC_NO_PLOGI_IF_LOGGED_IN 0x01 +#define MBC_NO_PROCESS_LOGIN 0x02 + +/* Mailbox command completion status */ +#define MBS_PORT_ID_IN_USE 0x4007 +#define MBS_LOOP_ID_IN_USE 0x4008 +#define MBS_ALL_LOOP_IDS_IN_USE 0x4009 +#define MBS_NAME_SERVER_NOT_LOGGED_IN 0x400A + +#endif /* FC_IP_SUPPORT */ + +/* + * Linux Host Adapter structure + */ +typedef struct scsi_qla_host +{ + /* ISP ring lock, rings, and indexes */ + request_t req[REQUEST_ENTRY_CNT+1]; + response_t res[RESPONSE_ENTRY_CNT+1]; + + /* Linux adapter configuration data */ + struct Scsi_Host *host; /* pointer to host data */ + struct scsi_qla_host *next; + device_reg_t *iobase; /* Base Memory-mapped or I/O address */ + device2300_reg_t *iobase2300;/* Base Memory-mapped or I/O address */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + struct pci_dev *pdev; +#endif + uint8_t pci_bus; + uint8_t pci_device_fn; + uint8_t devnum; + volatile unsigned char *mmpbase; /* memory mapped address */ + u_long host_no; + u_long instance; + uint8_t revision; + uint8_t ports; + u_long actthreads; + u_long qthreads; + u_long isr_count; /* Interrupt count */ + u_long isp_aborts; + u_long lip_count; + u_long spurious_int; + uint32_t device_id; + + /* ISP connection configuration data */ + uint16_t max_public_loop_ids; + uint16_t min_external_loopid; /* First external loop Id */ + uint8_t current_topology; /* Current ISP configuration */ + uint8_t prev_topology; /* Previous ISP configuration */ +#define ISP_CFG_NL 1 +#define ISP_CFG_N 2 +#define ISP_CFG_FL 4 +#define ISP_CFG_F 8 + + uint8_t id; /* Host adapter SCSI id */ + uint16_t loop_id; /* Host adapter loop id */ + uint8_t port_id[3]; /* Host adapter port id */ + uint8_t operating_mode; /* current F/W operating connection mode */ + /* 0 - LOOP, 1 - P2P, 2 - LOOP_P2P, + * 3 - P2P_LOOP + */ + + /* NVRAM configuration data */ + uint16_t loop_reset_delay; /* Loop reset delay. */ + uint16_t hiwat; /* High water mark per device. */ + uint16_t execution_throttle; /* queue depth */ + uint16_t minimum_timeout; /* Minimum timeout. */ + uint8_t retry_count; + uint8_t login_timeout; + uint8_t port_down_retry_count; + uint8_t loop_down_timeout; + uint16_t max_luns; + uint16_t max_targets; + + /* Device TGT/LUN queues. */ + tgt_t *tgt[MAX_BUSES][MAX_FIBRE_DEVICES]; /* Logical unit queues */ + + /* Interrupt lock, and data */ + + /* Fibre Channel Device Database and LIP sequence. */ + fcdev_t fc_db[MAX_FIBRE_DEVICES]; /* Driver database. */ + uint32_t flash_db; /* Flash database address in use. */ + fabricid_t fabricid[MAX_FIBRE_DEVICES]; /* Fabric ids table . */ + uint32_t flash_seq; /* Flash database seq # in use. */ + volatile uint16_t lip_seq; /* LIP sequence number. */ + + /* Linux bottom half run queue */ + struct tq_struct run_qla_bh; + + /* Linux kernel thread */ + struct task_struct *dpc_handler; /* kernel thread */ + struct semaphore *dpc_wait; /* DPC waits on this semaphore */ + struct semaphore *dpc_notify; /* requester waits for DPC on this + * semaphore + */ + uint8_t dpc_active; /* DPC routine is active */ + + /* Received ISP mailbox data. */ + volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; + + /* Outstandings ISP commands. */ + srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS]; + +#if BITS_PER_LONG > 32 + uint64_t request_dma; /* Physical address. */ +#else + uint32_t request_dma; /* Physical address. */ +#endif + request_t *request_ring; /* Base virtual address */ + request_t *request_ring_ptr; /* Current address. */ + uint16_t req_ring_index; /* Current index. */ + uint16_t req_q_cnt; /* Number of available entries. */ + +#if BITS_PER_LONG > 32 + uint64_t response_dma; /* Physical address. */ +#else + uint32_t response_dma; /* Physical address. */ +#endif + response_t *response_ring; /* Base virtual address */ + response_t *response_ring_ptr; /* Current address. */ + uint16_t rsp_ring_index; /* Current index. */ + +#if QL2X00_TARGET_MODE_SUPPORT + /* Target buffer and sense data. */ + u_long tbuf_dma; /* Physical address. */ + tgt_buf_t *tbuf; + u_long tsense_dma; /* Physical address. */ + uint8_t *tsense; +#endif + +#ifdef FC_IP_SUPPORT + /* Data for IP support */ + uint8_t acPortName[8]; + IP_BUFFER_ENTRY asIpBuffers[IP_BUFFER_QUEUE_DEPTH]; + uint32_t ppIpBufferQueueLow; + uint32_t ppIpBufferQueueHigh; + IP_BUFFER_ENTRY *pIpBufferQueue; + uint16_t wIpBufferIn; + uint16_t wIpBufferOut; + uint32_t lMaximumTransferSize; + uint32_t lReceiveBufferSize; + uint16_t wReceiveBufferCount; + uint16_t wHeaderSize; + PSEND_COMPLETION_CALLBACK pSendCompletionRoutine; + PRECEIVE_PACKETS_CALLBACK pReturnReceivePacketsRoutine; + void *pReturnReceivePacketsContext; + PNOTIFY_CALLBACK pNotifyRoutine; + void *pNotifyContext; + BUFFER_CB *pReceiveBufferCBs; + IP_DEVICE_BLOCK asIpDeviceDatabase[QLLAN_MAX_IP_DEVICES]; + IP_DEVICE_BLOCK *pIpDeviceFree; + IP_DEVICE_BLOCK *pIpDeviceTop; + IP_DEVICE_BLOCK *pIpDeviceBottom; + uint32_t lCurrentTagIndex; + void *apActiveIpQueue[MAX_SEND_PACKETS]; +#endif + + /* Firmware Initialization Control Block data */ +#if BITS_PER_LONG > 32 + uint64_t init_cb_dma; /* Physical address. */ +#else + uint32_t init_cb_dma; /* Physical address. */ +#endif + init_cb_t *init_cb; + + /* Timeout timers. */ + uint8_t queue_restart_timer; + uint8_t loop_down_timer; /* loop down timer */ + uint8_t loop_down_abort_time; /* port down timer */ + uint32_t timer_active; + uint32_t forceLip; + struct timer_list timer; + + /* Watchdog queue, lock and total timer */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) + spinlock_t retry_lock; /* Watchdog Queue Lock */ +#endif + srb_t *retry_q_first; /* First job on watchdog queue */ + srb_t *retry_q_last; /* Last job on watchdog queue */ + + srb_t *done_q_first; /* First job on done queue */ + srb_t *done_q_last; /* Last job on done queue */ + + /* RSCN queue. */ + rscn_t rscn_queue[MAX_RSCN_COUNT]; + uint8_t rscn_in_ptr; + uint8_t rscn_out_ptr; + + /* Host Adapter database */ + fcdev_t *phost_db; + uint8_t host_db_ptr; + + volatile struct + { + uint32_t online :1; /* 0 */ + uint32_t enable_64bit_addressing :1; /* 1 */ + uint32_t mbox_int :1; /* 2 */ + uint32_t mbox_busy :1; /* 3 */ + uint32_t reset_marker :1; /* 4 */ + uint32_t loop_resync_needed :1; /* 5 */ + uint32_t watchdog_enabled :1; /* 6 */ + uint32_t isp_abort_needed :1; /* 7 */ + uint32_t disable_host_adapter :1; /* 8 */ + uint32_t loop_resync_active :1; /* 9 */ + uint32_t reset_active :1; /* 10 */ + uint32_t abort_isp_active :1; /* 11 */ + uint32_t disable_risc_code_load :1; /* 12 */ + uint32_t set_cache_line_size_1 :1; /* 13 */ + uint32_t enable_target_mode :1; /* 14 */ + uint32_t disable_luns :1; /* 15 */ + uint32_t enable_lip_reset :1; /* 16 */ + uint32_t enable_lip_full_login :1; /* 17 */ + uint32_t enable_target_reset :1; /* 18 */ + uint32_t updated_fc_db :1; /* 19 */ + uint32_t enable_flash_db_update :1; /* 20 */ + uint32_t abort_queue_needed :1; /* 21 */ + +#define QLA2100_IN_ISR_BIT 22 + uint32_t in_isr :1; /* 22 */ + uint32_t dpc_sched :1; /* 23 */ + uint32_t start_timer :1; /* 24 */ + uint32_t nvram_config_done :1; /* 25 */ + uint32_t update_config_needed :1; /* 26 */ + uint32_t done_requests_needed :1; /* 27 */ + uint32_t restart_queues_needed :1; /* 28 */ + uint32_t port_restart_needed :1; /* 29 */ +#ifdef FC_IP_SUPPORT + uint32_t enable_ip :1; /* 30 */ +#endif + /* 4.11 */ + uint32_t managment_server_logged_in:1; /* 31 */ + } flags; + + uint32_t device_flags; +#define DFLG_LOCAL_DEVICES BIT_0 +#define DFLG_RETRY_LOCAL_DEVICES BIT_1 +#define RSCN_UPDATE BIT_2 +#define LOGIN_RETRY_NEEDED BIT_3 +#define RSCN_QUEUE_OVERFLOW BIT_4 +#define DFLG_FABRIC_DEVICES BIT_5 +#define RELOGIN_NEEDED BIT_6 + + uint8_t marker_needed; + uint8_t missing_targets; + uint8_t sns_retry_cnt; + uint8_t cmd_wait_cnt; + uint32_t dpc_flags; +#define MAILBOX_RETRY BIT_0 +#define COMMAND_WAIT_NEEDED BIT_1 +#define COMMAND_WAIT_ACTIVE BIT_2 +#define ISP_RESET_NEEDED BIT_3 +#define LOGOUT_DONE BIT_4 +#define ISP_RESET_ONCE BIT_5 + + uint16_t interrupts_on; + + volatile uint16_t loop_state; +/* These values are NOT used as flags. */ +#define LOOP_TIMEOUT 0x1 +#define LOOP_DOWN 0x2 +#define LOOP_UP 0x4 +#define LOOP_UPDATE 0x8 +#define LOOP_READY 0x10 + + /* following are new and needed for IOCTL support */ + uint8_t node_name[8]; + uint8_t nvram_version; + uint8_t ioctl_timer; + uint8_t IoctlPassThru_InProgress; + uint8_t IoctlPassFCCT_InProgress; + void *ioctl_mem; +#if BITS_PER_LONG > 32 + uint64_t ioctl_mem_phys; +#else + uint32_t ioctl_mem_phys; +#endif + + /* HBA serial number */ + uint8_t serial0; + uint8_t serial1; + uint8_t serial2; + + /* oem related items */ + uint8_t oem_id; + uint8_t oem_spare0; + uint8_t oem_part[6]; + uint8_t oem_fru[8]; + uint8_t oem_ec[8]; + uint8_t oem_string[8]; + + uint32_t dump_done; + +} scsi_qla_host_t; + +/* + * Macros to help code, maintain, etc. + */ +#define TGT_Q(ha, b, t) (ha->tgt[b][t]) +#define GET_LU_Q(ha, b, t, l) ( (TGT_Q(ha,b,t) != NULL)? TGT_Q(ha, b, t)->luns[l] : NULL) +#define LU_Q(ha, b, t, l) (TGT_Q(ha, b, t)->luns[l]) +#define PORT_DOWN(ha, t) ((ha)->fc_db[(t)].port_timer) + +/* + * Locking Macro Definitions + * + * LOCK/UNLOCK definitions are lock/unlock primitives for multi-processor + * or spl/splx for uniprocessor. + */ +#define QLA2100_INTR_LOCK(ha) +#define QLA2100_INTR_UNLOCK(ha) + +#define QLA2100_RING_LOCK(ha) +#define QLA2100_RING_UNLOCK(ha) + +#if defined(__cplusplus) +} +#endif +#endif + +#if defined(__386__) +# define QLA2100_BIOSPARAM qla2100_biosparam +#else +# define QLA2100_BIOSPARAM NULL +#endif + +/* + * Linux - SCSI Driver Interface Function Prototypes. + */ +int qla2100_ioctl(Scsi_Device *, int , void *); +int qla2100_proc_info ( char *, char **, off_t, int, int, int); +const char * qla2100_info(struct Scsi_Host *host); +int qla2100_detect(Scsi_Host_Template *); +int qla2100_release(struct Scsi_Host *); +const char * qla2100_info(struct Scsi_Host *); +int qla2100_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int qla2100_abort(Scsi_Cmnd *); +int qla2100_reset(Scsi_Cmnd *, unsigned int); +int qla2100_biosparam(Disk *, kdev_t, int[]); +void qla2100_intr_handler(int, void *, struct pt_regs *); +//void qla2100_device_queue_depth(scsi_qla_host_t *, Scsi_Device *); +void qla2100_setup(char *s, int *dummy); + +/* Number of segments 1 - 65535 */ +#define SG_SEGMENTS 32 /* Cmd entry + 6 continuations */ + +/* + * Scsi_Host_template (see hosts.h) + * Device driver Interfaces to mid-level SCSI driver. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +/* This interface is now obsolete !!! */ +#define QLA2100_LINUX_TEMPLATE { \ + next: NULL, \ + usage_count: NULL, \ + proc_dir: NULL, \ + proc_info: qla2100_proc_info, \ + name: "Qlogic Fibre Channel 2100", \ + detect: qla2100_detect, \ + release: qla2100_release, \ + info: qla2100_info, \ + command: NULL, \ + queuecommand: qla2100_queuecommand, \ + abort: qla2100_abort, \ + reset: qla2100_reset, \ + slave_attach: NULL, \ + bios_param: QLA2100_BIOSPARAM, \ + can_queue: 1, /* MAX_OUTSTANDING_COMMANDS */ \ + this_id: -1, /* scsi id of host adapter */ \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, /* max commands per lun */ \ + present: 0, /* number of ISP present */ \ + unchecked_isa_dma: 0, /* no memeory DMA restrictions */ \ + use_clustering: ENABLE_CLUSTERING \ +} +#else + +#define QLA2100_LINUX_TEMPLATE { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: qla2100_proc_info, \ + name: "Qlogic Fibre Channel 2100", \ + detect: qla2100_detect, \ + release: qla2100_release, \ + info: qla2100_info, \ + ioctl: qla2100_ioctl, \ + command: NULL, \ + queuecommand: qla2100_queuecommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: qla2100_abort, \ + reset: qla2100_reset, \ + slave_attach: NULL, \ + bios_param: QLA2100_BIOSPARAM, \ + can_queue: 255, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: SG_SEGMENTS, /* max scatter-gather cmds */\ + cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0, \ + emulated: 0 \ +} +#endif +#endif /* _IO_HBA_QLA2100_H */ diff -Nur linux-2.4.19/drivers/scsi/qla2x00exioct.h linux-2.4.19-sgi211r3/drivers/scsi/qla2x00exioct.h --- linux-2.4.19/drivers/scsi/qla2x00exioct.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/qla2x00exioct.h Tue Jan 8 17:05:38 2002 @@ -0,0 +1,823 @@ +/* + * File Name: exioct.h + * + * San/Device Management Ioctl Header + * File is created to adhere to Solaris requirement using 8-space tabs. + * + * !!!!! PLEASE DO NOT REMOVE THE TABS !!!!! + * !!!!! PLEASE NO SINGLE LINE COMMENTS: // !!!!! + * !!!!! PLEASE NO MORE THAN 80 CHARS PER LINE !!!!! + * + * *********************************************************************** + * * ** + * * NOTICE ** + * * COPYRIGHT (C) 2000 QLOGIC CORPORATION ** + * * ALL RIGHTS RESERVED ** + * * ** + * *********************************************************************** + * + * Revision History: + * + * Rev. 0 March 1, 2000 + * YPL - Created. + * + * Rev. 1 March 2, 2000 + * RLU - Updated with latest definitions. Added more comments. + * + * Rev. 2 May 16, 2000 + * SP - Updated definitions and changed structures (March 27, 2000) + * SP - Addded structures + * + * Rev. 3 June 1, 2000 + * THL - Made major changes to include all changes talked in our meeting. + * + * Rev. 4 June 5, 2000 + * RLU - Added new definitions/structures for SDM_GET_AEN and SDM_REG_AEN + * functions. + * - Major definition/structure name changes as discussed in meetings. + * - Deleted duplicated command code and structure definitions. + * + * Rev. 4.1 June 14, 2000 + * WTR - Moved Solaris specific defines to exioctso.h. This makes it + * possible for application developers to include only exioct.h + * in their Solaris application development. + * + * Rev. 4.2 June 15, 2000 + * THL - Changed UINT16 and UINT32 back to WORD and DWORD for NT; otherwise, + * NT will get a compilation error for redefining UINT16 and UINT32. + * Added RISC_CODE/FLASH_RAM macros. + * + * Rev. 4.3 June 22, 2000 + * THL - Changed SDM_FC_ADDR according to External Ioctls document. + * Added SDM_DEF_TYPE macros. + * + * Rev. 4.4 June 22, 2000 + * THL - Moved NT specific defines to exioctnt.h. + * + * Rev. 4.5 August 15, 2000 + * SP - Rolled back some changes made by Todd R. + * Kept new status code SDM_STATUS_NO_MEMORY + * Port types fabric and tape device + * + * Rev. 4.7 Sep 6, 2000 + * YPL - Replace SDM_ with EXT_, _ISP with _CHIP. + * Add vendor specific statuses, device update, config defines. + * + * Rev. 5.0 Sep 13, 2000 + * YPL - Update version to 5, remove max defines, make port type bit. + * Change HBA_PORT_PROPERTY to have bus/target/lun defined as UINT16 + * + * Rev. 5.1 Sep 22, 2000 + * THL - Add destination address for specify scsi address or FC address. + * Remove "not support" comment and add more macros. + * + * Rev. 5.2 Sep 27, 2000 + * THL - Add new macros and structure for add and swap target device. + * Create new data structure for get port database. + * TLE - Merge changes needed for FailOver + * + * Rev. 5.3 Sep 29, 2000 + * THL - Add access mode for NVRAM. + * + * Rev. 5.4 Oct 03, 2000 + * THL - Add EXT_SC_GET_FC_STATISTICS. + * + * Rev. 5.5 Oct 18, 2000 + * THL - Remove duplicated EXT_DEF_ADDR_MODE_32 and EXT_DEF_ADDR_MODE_16. + * Reformat new data structures and defines. + * + * Rev. 5.6 Oct 19, 2000 + * RLU - Changed file name from ExIoct.h to exioct.h. + * - Added definition of EXT_RNID_DATA for API implementation. + * - Reformat some lines to conform to the format agreed + * upon in IOCTL meeting (and mentioned at beginning of + * this file). + * + * Rev. 5.7 Oct 25, 2000 + * BN - Added LUN bitmask structure and macros + * + * Rev. 5.8 Oct 25, 2000 + * BN - Added EXT_CC_DRIVER_PROP define + * + * Rev. 5.9 Oct 26, 2000 + * BN - Sync with UnixApi project + * + * Rev. 5.10 Oct 30, 2000 + * BN - Remove not needed #define for EXT_CC_DRIVER_PROP + * - Add EXT_ to IS_LUN_BIT_SET, SET_LUN_BIT, CLR_LUN_BIT + * + * Rev. 5.11 Nov 1, 2000 + * BN - Increased [1] of EXT_DEVICEDATA to [EXT_MAX_TARGET] + * TLE - Decreased [EXT_MAX_TARGET] of EXT_DEVICEDATA to [1] + * + * Rev. 5.12 Nov 7, 2000 + * RLU - Deleted EXT_DEF_MAX_LUNS define and changed all references + * to it to use EXT_MAX_LUN. + * - Changed the revision numbers for the last 2 revisions down + * to use 5.x. + * + * Rev. 5.13 Nov 28, 2000 + * RLU - Change value defines from EXT_... to EXT_DEF_... + * + * Rev. 5.14 Jan 08, 2001 + * BN - Added #define SDM_CC_LOOPBACK SDM_CC_LOOPBACK_OS + * + */ + +#ifndef _EXIOCT_H +#define _EXIOCT_H + +/* + * NOTE: the following version defines must be updated each time the + * changes made may affect the backward compatibility of the + * input/output relations of the SDM IOCTL functions. + */ +#define EXT_VERSION 5 + + +/* + * OS independent General definitions + */ +#define EXT_DEF_SIGNATURE_SIZE 8 +#define EXT_DEF_WWN_NAME_SIZE 8 +#define EXT_DEF_WWP_NAME_SIZE 8 +#define EXT_DEF_SERIAL_NUM_SIZE 4 +#define EXT_DEF_PORTID_SIZE 4 +#define EXT_DEF_PORTID_SIZE_ACTUAL 3 +#define EXT_DEF_MAX_STR_SIZE 128 +#define EXT_DEF_SCSI_PASSTHRU_CDB_LENGTH 12 + +#define EXT_DEF_ADDR_MODE_32 1 +#define EXT_DEF_ADDR_MODE_64 2 + +/* + * *********************************************************************** + * X OS type definitions + * *********************************************************************** + */ +#ifdef _MSC_VER /* NT */ + +#pragma pack(1) +#include "ExIoctNT.h" + +#elif defined(linux) /* Linux */ + +#include "qla2x00exioctln.h" + +#elif defined(sun) || defined(__sun) /* Solaris */ + +#include "exioctso.h" + +#endif + +/* + * *********************************************************************** + * OS dependent General configuration defines + * *********************************************************************** + */ +#define EXT_DEF_MAX_HBA EXT_DEF_MAX_HBA_OS +#define EXT_DEF_MAX_BUS EXT_DEF_MAX_BUS_OS +#define EXT_DEF_MAX_TARGET EXT_DEF_MAX_TARGET_OS +#define EXT_DEF_MAX_LUN EXT_DEF_MAX_LUN_OS + +/* + * *********************************************************************** + * Common header struct definitions for San/Device Mgmt + * *********************************************************************** + */ +typedef struct { + UINT64 Signature; /* 8 chars string */ + UINT16 AddrMode; /* 2 */ + UINT16 Version; /* 2 */ + UINT16 SubCode; /* 2 */ + UINT16 Instance; /* 2 */ + UINT32 Status; /* 4 */ + UINT32 DetailStatus; /* 4 */ + UINT32 Reserved1; /* 4 */ + UINT32 RequestLen; /* 4 */ + UINT32 ResponseLen; /* 4 */ + UINT64 RequestAdr; /* 8 */ + UINT64 ResponseAdr; /* 8 */ + UINT16 HbaSelect; /* 2 */ + UINT16 VendorSpecificStatus[11]; /* 22 */ + UINT64 VendorSpecificData; /* 8 chars string */ +} EXT_IOCTL, *PEXT_IOCTL; /* 84 / 0x54 */ + +/* + * Addressing mode used by the user application + */ +#define EXT_ADDR_MODE EXT_ADDR_MODE_OS + +/* + * Status. These macros are being used for setting Status field in + * EXT_IOCTL structure. + */ +#define EXT_STATUS_OK 0 +#define EXT_STATUS_ERR 1 +#define EXT_STATUS_BUSY 2 +#define EXT_STATUS_PENDING 3 +#define EXT_STATUS_SUSPENDED 4 +#define EXT_STATUS_RETRY_PENDING 5 +#define EXT_STATUS_INVALID_PARAM 6 +#define EXT_STATUS_DATA_OVERRUN 7 +#define EXT_STATUS_DATA_UNDERRUN 8 +#define EXT_STATUS_DEV_NOT_FOUND 9 +#define EXT_STATUS_COPY_ERR 10 +#define EXT_STATUS_MAILBOX 11 +#define EXT_STATUS_UNSUPPORTED_SUBCODE 12 +#define EXT_STATUS_UNSUPPORTED_VERSION 13 +#define EXT_STATUS_MS_NO_RESPONSE 14 +#define EXT_STATUS_SCSI_STATUS 15 +#define EXT_STATUS_BUFFER_TOO_SMALL 16 +#define EXT_STATUS_NO_MEMORY 17 +#define EXT_STATUS_UNKNOWN 18 +#define EXT_STATUS_UNKNOWN_DSTATUS 19 +#define EXT_STATUS_INVALID_REQUEST 20 + +/* + * Detail Status contains the SCSI bus status codes. + */ + +#define EXT_DSTATUS_GOOD 0x00 +#define EXT_DSTATUS_CHECK_CONDITION 0x02 +#define EXT_DSTATUS_CONDITION_MET 0x04 +#define EXT_DSTATUS_BUSY 0x08 +#define EXT_DSTATUS_INTERMEDIATE 0x10 +#define EXT_DSTATUS_INTERMEDIATE_COND_MET 0x14 +#define EXT_DSTATUS_RESERVATION_CONFLICT 0x18 +#define EXT_DSTATUS_COMMAND_TERMINATED 0x22 +#define EXT_DSTATUS_QUEUE_FULL 0x28 + +/* + * Detail Status contains the needed Response buffer space(bytes) + * when Status = EXT_STATUS_BUFFER_TOO_SMALL + */ + + +/* + * Detail Status contains one of the following codes + * when Status = EXT_STATUS_INVALID_PARAM or + * = EXT_STATUS_DEV_NOT_FOUND + */ +#define EXT_DSTATUS_NOADNL_INFO 0x00 +#define EXT_DSTATUS_HBA_INST 0x01 +#define EXT_DSTATUS_TARGET 0x02 +#define EXT_DSTATUS_LUN 0x03 +#define EXT_DSTATUS_REQUEST_LEN 0x04 +#define EXT_DSTATUS_PATH_INDEX 0x05 + +/* + * Currently supported DeviceControl / ioctl command codes + */ +#define EXT_CC_QUERY EXT_CC_QUERY_OS +#define EXT_CC_SEND_FCCT_PASSTHRU EXT_CC_SEND_FCCT_PASSTHRU_OS +#define EXT_CC_REG_AEN EXT_CC_REG_AEN_OS +#define EXT_CC_GET_AEN EXT_CC_GET_AEN_OS +#define EXT_CC_SEND_ELS_RNID EXT_CC_SEND_ELS_RNID_OS +#define EXT_CC_SEND_SCSI_PASSTHRU EXT_CC_SCSI_PASSTHRU_OS +#define EXT_CC_READ_HOST_PARAMS EXT_CC_READ_HOST_PARAMS_OS +#define EXT_CC_READ_RISC_PARAMS EXT_CC_READ_RISC_PARAMS_OS +#define EXT_CC_UPDATE_HOST_PARAMS EXT_CC_UPDATE_HOST_PARAMS_OS +#define EXT_CC_UPDATE_RISC_PARAMS EXT_CC_UPDATE_RISC_PARAMS_OS +#define EXT_CC_READ_NVRAM EXT_CC_READ_NVRAM_OS +#define EXT_CC_UPDATE_NVRAM EXT_CC_UPDATE_NVRAM_OS + +#define EXT_CC_LOOPBACK EXT_CC_LOOPBACK_OS +/* + * HBA port operations + */ +#define EXT_CC_GET_DATA EXT_CC_GET_DATA_OS +#define EXT_CC_SET_DATA EXT_CC_SET_DATA_OS + +/* + * The following DeviceControl / ioctl command codes currently are not + * supported. + */ +#define EXT_CC_SEND_ELS_RTIN EXT_CC_SEND_ELS_RTIN_OS + + +/* + * *********************************************************************** + * EXT_IOCTL SubCode definition. + * These macros are being used for setting SubCode field in EXT_IOCTL + * structure. + * *********************************************************************** + */ + +/* + * Query. + * Uses with EXT_QUERY as the ioctl code. + */ +#define EXT_SC_QUERY_HBA_NODE 1 +#define EXT_SC_QUERY_HBA_PORT 2 +#define EXT_SC_QUERY_DISC_PORT 3 +#define EXT_SC_QUERY_DISC_TGT 4 +#define EXT_SC_QUERY_DISC_LUN 5 /* Currently Not Supported */ +#define EXT_SC_QUERY_DRIVER 6 +#define EXT_SC_QUERY_FW 7 +#define EXT_SC_QUERY_CHIP 8 + +/* + * Get. + * Uses with EXT_GET_DATA as the ioctl code + */ +/* 1 - 99 Common */ +#define EXT_SC_GET_SCSI_ADDR 1 /* Currently Not Supported */ +#define EXT_SC_GET_ERR_DETECTIONS 2 /* Currently Not Supported */ +#define EXT_SC_GET_STATISTICS 3 +#define EXT_SC_GET_BUS_MODE 4 /* Currently Not Supported */ +#define EXT_SC_GET_DR_DUMP_BUF 5 /* Currently Not Supported */ +#define EXT_SC_GET_RISC_CODE 6 +#define EXT_SC_GET_FLASH_RAM 7 + +/* 100 - 199 FC_INTF_TYPE */ +#define EXT_SC_GET_LINK_STATUS 101 /* Currently Not Supported */ +#define EXT_SC_GET_LOOP_ID 102 /* Currently Not Supported */ +#define EXT_SC_GET_LUN_BITMASK 103 +#define EXT_SC_GET_PORT_DATABASE 104 /* Currently Not Supported */ +#define EXT_SC_GET_PORT_DATABASE_MEM 105 /* Currently Not Supported */ +#define EXT_SC_GET_PORT_SUMMARY 106 +#define EXT_SC_GET_POSITION_MAP 107 +#define EXT_SC_GET_RETRY_CNT 108 /* Currently Not Supported */ +#define EXT_SC_GET_RNID 109 +#define EXT_SC_GET_RTIN 110 /* Currently Not Supported */ +#define EXT_SC_GET_FC_LUN_BITMASK 111 +#define EXT_SC_GET_FC_STATISTICS 112 + +/* 200 - 299 SCSI_INTF_TYPE */ +#define EXT_SC_GET_SEL_TIMEOUT 201 /* Currently Not Supported */ + + +/* + * Set. + * Uses with EXT_SET_DATA as the ioctl code + */ +/* 1 - 99 Common */ +#define EXT_SC_RST_STATISTICS 3 /* Currently Not Supported */ +#define EXT_SC_SET_BUS_MODE 4 /* Currently Not Supported */ +#define EXT_SC_SET_DR_DUMP_BUF 5 /* Currently Not Supported */ +#define EXT_SC_SET_RISC_CODE 6 +#define EXT_SC_SET_FLASH_RAM 7 + +/* 100 - 199 FC_INTF_TYPE */ +#define EXT_SC_SET_LUN_BITMASK 103 +#define EXT_SC_SET_RETRY_CNT 108 /* Currently Not Supported */ +#define EXT_SC_SET_RNID 109 +#define EXT_SC_SET_RTIN 110 /* Currently Not Supported */ +#define EXT_SC_SET_FC_LUN_BITMASK 111 +#define EXT_SC_ADD_TARGET_DEVICE 112 +#define EXT_SC_SWAP_TARGET_DEVICE 113 + +/* 200 - 299 SCSI_INTF_TYPE */ +#define EXT_SC_SET_SEL_TIMEOUT 201 /* Currently Not Supported */ + +/* SCSI passthrough */ +#define EXT_SC_SEND_SCSI_PASSTHRU 0 +#define EXT_SC_SEND_FC_SCSI_PASSTHRU 1 + +/* NVRAM */ +#define EXT_SC_NVRAM_HARDWARE 0 /* Save */ +#define EXT_SC_NVRAM_DRIVER 1 /* Driver (Apply) */ +#define EXT_SC_NVRAM_ALL 2 /* NVRAM/Driver (Save+Apply) */ + +/* Read */ + +/* Write */ + +/* Reset */ + +/* Request struct */ + + +/* + * Response struct + */ +typedef struct _EXT_HBA_NODE { + UINT8 WWNN [EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Manufacturer [EXT_DEF_MAX_STR_SIZE]; /* 128; "QLOGIC" */ + UINT8 Model [EXT_DEF_MAX_STR_SIZE]; /* 128; "QLA2200" */ + UINT8 SerialNum [EXT_DEF_SERIAL_NUM_SIZE];/* 4; 123 */ + UINT8 DriverVersion[EXT_DEF_MAX_STR_SIZE]; /* 128; "7.4.3" */ + UINT8 FWVersion [EXT_DEF_MAX_STR_SIZE]; /* 128; "2.1.6" */ + + /* The following field is currently not supported */ + UINT8 OptRomVersion[EXT_DEF_MAX_STR_SIZE]; /* 128; "1.44" */ + + UINT16 PortCount; /* 2; 1 */ + UINT16 InterfaceType; /* 2; FC/SCSI */ + + /* The following two fields are not yet supported */ + UINT32 DriverAttr; /* 4 */ + UINT32 FWAttr; /* 4 */ + + UINT32 Reserved[8]; /* 32 */ +} EXT_HBA_NODE, *PEXT_HBA_NODE; /* 696 */ + +/* HBA node query interface type */ +#define EXT_DEF_FC_INTF_TYPE 1 +#define EXT_DEF_SCSI_INTF_TYPE 2 + +typedef struct _EXT_HBA_PORT { + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id [EXT_DEF_PORTID_SIZE]; /* 4; 3 bytes valid Port Id. */ + UINT16 Type; /* 2; Port Type */ + UINT16 State; /* 2; Port State */ + UINT16 Mode; /* 2 */ + UINT16 DiscPortCount; /* 2 */ + UINT16 DiscPortNameType; /* 2; USE_NODE_NAME or */ + /* USE_PORT_NAME */ + UINT16 DiscTargetCount; /* 2 */ + UINT16 Bus; /* 1 */ + UINT16 Target; /* 1 */ + UINT16 Lun; /* 1 */ + UINT16 Unused; /* 1 */ + UINT32 Reserved[6]; /* 28 */ +} EXT_HBA_PORT, *PEXT_HBA_PORT; /* 56 */ + +/* port type bit definitions */ +#define EXT_DEF_INITIATOR_DEV 0x1 +#define EXT_DEF_TARGET_DEV 0x2 +#define EXT_DEF_TAPE_DEV 0x4 +#define EXT_DEF_FABRIC_DEV 0x8 + + +/* HBA port state */ +#define EXT_DEF_HBA_OK 0 +#define EXT_DEF_HBA_SUSPENDED 1 +#define EXT_DEF_HBA_LOOP_DOWN 2 + +/* Connection mode */ +#define EXT_DEF_P2P_MODE 1 +#define EXT_DEF_LOOP_MODE 2 + +/* Valid name type for Disc. port/target */ +#define EXT_DEF_USE_NODE_NAME 1 +#define EXT_DEF_USE_PORT_NAME 2 + +typedef struct _EXT_DISC_PORT { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id [EXT_DEF_PORTID_SIZE]; /* 4; 3 bytes used. big endian*/ + + /* The following fields currently are not supported */ + UINT16 Type; /* 2; Port Type */ + UINT16 Status; /* 2; Port Status */ + UINT16 Bus; /* 2; n/a for Solaris */ + + UINT16 TargetId; /* 2 */ + UINT32 Reserved[8]; /* 32 */ +} EXT_DISC_PORT, *PEXT_DISC_PORT; /* 60 */ + +typedef struct _EXT_DISC_TARGET { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id [EXT_DEF_PORTID_SIZE]; /* 4; 3 bytes used. big endian*/ + + /* The following fields currently are not supported */ + UINT16 Type; /* 2; Target Type */ + UINT16 Status; /* 2; Target Status*/ + UINT16 Bus; /* 2; n/a for Solaris */ + + UINT16 TargetId; /* 2 */ + + /* The following field is currently not supported */ + UINT16 LunCount; /* 2; n/a for nt */ + + UINT16 Reserved[15]; /* 30 */ +} EXT_DISC_TARGET, *PEXT_DISC_TARGET; /* 60 */ + +/* The following command is not supported */ +typedef struct _EXT_DISC_LUN { /* n/a for nt */ + UINT16 Id; /* 2 */ + UINT16 State; /* 2 */ + UINT16 IoCount; /* 2 */ + UINT16 Reserved[15]; /* 30 */ +} EXT_DISC_LUN, *PEXT_DISC_LUN; /* 36 */ + + +/* SCSI address */ +typedef struct _EXT_SCSI_ADDR { + UINT16 Bus; /* 2 */ + UINT16 Target; /* 2 */ + UINT16 Lun; /* 2 */ + UINT16 Padding[5]; /* 10 */ +} EXT_SCSI_ADDR, *PEXT_SCSI_ADDR; /* 16 */ + + +/* Fibre Channel address */ +typedef struct _EXT_FC_ADDR { + union { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id[EXT_DEF_PORTID_SIZE]; /* 4 */ + } FcAddr; + UINT16 Type; /* 2 */ + UINT16 Padding[2]; /* 2 */ +} EXT_FC_ADDR, *PEXT_FC_ADDR; /* 24 */ + +#define EXT_DEF_TYPE_WWNN 1 +#define EXT_DEF_TYPE_WWPN 2 +#define EXT_DEF_TYPE_PORTID 3 +#define EXT_DEF_TYPE_FABRIC 4 + + +/* Destination address */ +typedef struct _EXT_DEST_ADDR { + union { + UINT8 WWNN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 WWPN[EXT_DEF_WWN_NAME_SIZE]; /* 8 */ + UINT8 Id[EXT_DEF_PORTID_SIZE]; /* 4 */ + struct { + UINT16 Bus; /* 2 */ + UINT16 Target; /* 2 */ + } ScsiAddr; + } DestAddr; + UINT16 DestType; /* 2 */ + UINT16 Lun; /* 2 */ + UINT16 Padding[2]; /* 4 */ +} EXT_DEST_ADDR, *PEXT_DEST_ADDR; /* 20 */ + + +#define EXT_DEF_DESTTYPE_WWNN 1 +#define EXT_DEF_DESTTYPE_WWPN 2 +#define EXT_DEF_DESTTYPE_PORTID 3 +#define EXT_DEF_DESTTYPE_FABRIC 4 +#define EXT_DEF_DESTTYPE_SCSI 5 + +/* Statistic */ +typedef struct _EXT_HBA_PORT_STAT { + UINT32 ControllerErrorCount; /* 4 */ + UINT32 DeviceErrorCount; /* 4 */ + UINT32 TotalIoCount; /* 4 */ + UINT32 TotalMBytes; /* 4; MB of data processed */ + UINT32 TotalLipResets; /* 4; Total no. of LIP Reset */ + UINT32 TotalInterrupts; /* 4; Total no. of Interrupts */ + UINT32 TotalLinkFailures; /* 4 */ + UINT32 TotalLossOfSync; /* 4 */ + UINT32 TotalLossOfSignals; /* 4 */ + UINT32 PrimitiveSeqProtocolErrorCount;/* 4 */ + UINT32 InvalidTransmissionWordCount; /* 4 */ + UINT32 InvalidCRCCount; /* 4 */ + UINT32 Reserved[16]; /* 64 */ +} EXT_HBA_PORT_STAT, *PEXT_HBA_PORT_STAT; /* 112 */ + + +/* Driver property */ +typedef struct _EXT_DRIVER { + UINT8 Version[EXT_DEF_MAX_STR_SIZE];/* 128 */ + UINT16 NumOfBus; /* 2; Port Type */ + UINT16 TargetsPerBus; /* 2; Port Status */ + UINT16 LunsPerTarget; /* 2 */ + UINT32 MaxTransferLen; /* 4 */ + UINT32 MaxDataSegments; /* 4 */ + UINT16 DmaBitAddresses; /* 2 */ + UINT16 IoMapType; /* 2 */ + UINT32 Attrib; /* 4 */ + UINT32 InternalFlags[4]; /* 16 */ + UINT32 Reserved[8]; /* 32 */ +} EXT_DRIVER, *PEXT_DRIVER; /* 198 */ + + +/* Firmware property */ +typedef struct _EXT_FW { + UINT8 Version[EXT_DEF_MAX_STR_SIZE];/* 128 */ + UINT32 Attrib; /* 4 */ + UINT16 Reserved[33]; /* 66 */ +} EXT_FW, *PEXT_FW; /* 198 */ + + +/* ISP/Chip property */ +typedef struct _EXT_CHIP { + UINT16 VendorId; /* 2 */ + UINT16 DeviceId; /* 2 */ + UINT16 SubVendorId; /* 2 */ + UINT16 SubSystemId; /* 2 */ + UINT16 PciBusNumber; /* 2 */ + UINT16 PciSlotNumber; /* 2 */ + UINT32 IoAddr; /* 4 */ + UINT32 IoAddrLen; /* 4 */ + UINT32 MemAddr; /* 4 */ + UINT32 MemAddrLen; /* 4 */ + UINT16 ChipType; /* 2 */ + UINT16 InterruptLevel; /* 2 */ + UINT16 OutMbx[8]; /* 16 */ + UINT32 Reserved[8]; /* 32 */ +} EXT_CHIP, *PEXT_CHIP; /* 80 */ + + +/* Request Buffer for RNID */ +typedef struct _EXT_RNID_REQ { + EXT_FC_ADDR Addr; + UINT8 DataFormat; + UINT32 Reserved[16]; +} EXT_RNID_REQ, *PEXT_RNID_REQ; + +/* Request Buffer for Set RNID */ +typedef struct _EXT_SET_RNID_REQ { + UINT8 IPVersion[2]; + UINT8 UDPPortNumber[2]; + UINT8 IPAddress[16]; + UINT32 Reserved[16]; +} EXT_SET_RNID_REQ, *PEXT_SET_RNID_REQ; + +/* RNID definition and data struct */ +#define SEND_RNID_RSP_SIZE 72 + +typedef struct _RNID_DATA +{ + UINT8 WWN[16]; /* 16 */ + UINT32 UnitType; /* 4 */ + UINT8 PortId[4]; /* 4 */ + UINT32 NumOfAttachedNodes; /* 4 */ + UINT8 IPVersion[2]; /* 2 */ + UINT8 UDPPortNumber[2]; /* 2 */ + UINT8 IPAddress[16]; /* 16 */ + UINT16 Reserved; /* 2 */ + UINT16 TopoDiscFlags; /* 2 */ +} EXT_RNID_DATA, *PEXT_RNID_DATA; /* 52 */ + + +/* SCSI pass-through */ +typedef struct _EXT_SCSI_PASSTHRU { + EXT_SCSI_ADDR TargetAddr; + UINT8 Direction; + UINT8 CdbLength; + UINT8 Cdb[EXT_DEF_SCSI_PASSTHRU_CDB_LENGTH]; + UINT32 Reserved[16]; + UINT8 SenseData[256]; +} EXT_SCSI_PASSTHRU, *PEXT_SCSI_PASSTHRU; + +/* FC SCSI pass-through */ +typedef struct _EXT_FC_SCSI_PASSTHRU { + EXT_DEST_ADDR FCScsiAddr; + UINT8 Direction; + UINT8 CdbLength; + UINT8 Cdb[EXT_DEF_SCSI_PASSTHRU_CDB_LENGTH]; + UINT32 Reserved[16]; + UINT8 SenseData[256]; +} EXT_FC_SCSI_PASSTHRU, *PEXT_FC_SCSI_PASSTHRU; + +/* SCSI pass-through direction */ +#define EXT_DEF_SCSI_PASSTHRU_DATA_IN 1 +#define EXT_DEF_SCSI_PASSTHRU_DATA_OUT 2 + + +/* EXT_REG_AEN Request struct */ +typedef struct _EXT_REG_AEN { + UINT32 Enable; /* 4; non-0 to enable, 0 to disable. */ + UINT32 Reserved; /* 4 */ +} EXT_REG_AEN, *PEXT_REG_AEN; /* 8 */ + +/* EXT_GET_AEN Response struct */ +typedef struct _EXT_ASYNC_EVENT { + UINT32 AsyncEventCode; /* 4 */ + union { + struct { + UINT8 RSCNInfo[EXT_DEF_PORTID_SIZE_ACTUAL];/* 3, BE */ + UINT8 AddrFormat; /* 1 */ + UINT32 Rsvd_1[2]; /* 8 */ + } RSCN; + + UINT32 Reserved[3]; /* 12 */ + } Payload; +} EXT_ASYNC_EVENT, *PEXT_ASYNC_EVENT; /* 16 */ + +/* Asynchronous Event Codes */ +#define EXT_DEF_LIP_OCCURRED 0x8010 +#define EXT_DEF_LINK_UP 0x8011 +#define EXT_DEF_LINK_DOWN 0x8012 +#define EXT_DEF_LIP_RESET 0x8013 +#define EXT_DEF_RSCN 0x8015 +#define EXT_DEF_DEVICE_UPDATE 0x8014 + +/* Required # of entries in the queue buffer allocated. */ +#define EXT_DEF_MAX_AEN_QUEUE EXT_DEF_MAX_AEN_QUEUE_OS + +/* LUN BitMask structure definition, array of 32bit words, + * 1 bit per lun. When bit == 1, the lun is masked. + * Most significant bit of mask[0] is lun 0, bit 24 is lun 7. + */ +typedef struct _EXT_LUN_BIT_MASK { +#if ((EXT_MAX_LUN & 0x7) == 0) + UINT8 mask[EXT_DEF_MAX_LUN >> 3]; +#else + UINT8 mask[(EXT_DEF_MAX_LUN + 8) >> 3 ]; +#endif +} EXT_LUN_BIT_MASK, *PEXT_LUN_BIT_MASK; + +/* Device type to get for EXT_SC_GET_PORT_SUMMARY */ +#define EXT_DEF_GET_KNOWN_DEVICE 0x1 +#define EXT_DEF_GET_VISIBLE_DEVICE 0x2 +#define EXT_DEF_GET_HIDDEN_DEVICE 0x4 +#define EXT_DEF_GET_FABRIC_DEVICE 0x8 +#define EXT_DEF_GET_LOOP_DEVICE 0x10 + +/* Each entry in device database */ +typedef struct _EXT_DEVICEDATAENTRY +{ + UINT8 NodeWWN[8]; /* Node World Wide Name for device */ + UINT8 PortWWN[8]; /* Port World Wide Name for device */ + UINT8 PortID[3]; /* Current PortId for device */ + UINT8 ControlFlags; /* Control flag */ + EXT_SCSI_ADDR TargetAddress; /* scsi address */ + UINT32 DeviceFlags; /* Flags for device */ + UINT16 LoopID; /* Loop ID */ + UINT16 BaseLunNumber; + UINT32 Reserved[32]; +} EXT_DEVICEDATAENTRY, *PEXT_DEVICEDATAENTRY; + +#define EXT_DEF_EXTERNAL_LUN_COUNT 2048 +#define EXT_DEF_EXTERNAL_LUN_BITMASK_BYTES (EXT_DEF_EXTERNAL_LUN_COUNT / 8) + +/* Structure as used in the IOCTL. */ + +typedef struct _EXT_EXTERNAL_LUN_BITMASK_ENTRY +{ + UINT8 NodeName[EXT_DEF_WWN_NAME_SIZE]; + UINT8 PortName[EXT_DEF_WWN_NAME_SIZE]; + + UINT32 Reserved2; + UINT32 Reserved3; + UINT32 Reserved4; + UINT32 Reserved5; /* Pad to 32-byte header.*/ + + UINT8 Bitmask[EXT_DEF_EXTERNAL_LUN_BITMASK_BYTES]; +} EXT_EXTERNAL_LUN_BITMASK_ENTRY, *PEXT_EXTERNAL_LUN_BITMASK_ENTRY; + + +/* Structure as it is stored in the NT registry.*/ + +typedef struct _LUN_BITMASK_LIST +{ + UINT16 Version; /* Should be LUN_BITMASK_REGISTRY_VERSION */ + UINT16 EntryCount; /* Count of variable entries following.*/ + UINT32 Reserved1; + UINT32 Reserved2; + UINT32 Reserved3; + UINT32 Reserved4; + UINT32 Reserved5; + UINT32 Reserved6; + UINT32 Reserved7; /* Pad to 32-byte header.*/ + + EXT_EXTERNAL_LUN_BITMASK_ENTRY BitmaskEntry[1]; + /* Variable-length data.*/ + +} EXT_LUN_BITMASK_LIST, *PEXT_LUN_BITMASK_LIST; + + +/* Device database information */ +typedef struct _EXT_DEVICEDATA +{ + UINT32 TotalDevices; /* Set to total number of device. */ + UINT32 ReturnListEntryCount; /* Set to number of device entries */ + /* returned in list. */ + + EXT_DEVICEDATAENTRY EntryList[1]; /* Variable length */ +} EXT_DEVICEDATA, *PEXT_DEVICEDATA; + + +/* Swap Target Device Data structure */ +typedef struct _EXT_SWAPTARGETDEVICE +{ + EXT_DEVICEDATAENTRY CurrentExistDevice; + EXT_DEVICEDATAENTRY NewDevice; +} EXT_SWAPTARGETDEVICE, *PEXT_SWAPTARGETDEVICE; + +#define EXT_DEF_LUN_BITMASK_LIST_MIN_ENTRIES 1 +#define EXT_DEF_LUN_BITMASK_LIST_MAX_ENTRIES 256 + +#ifdef _WIN64 +#define EXT_DEF_LUN_BITMASK_LIST_HEADER_SIZE 32 +#else +#define EXT_DEF_LUN_BITMASK_LIST_HEADER_SIZE \ + offsetof(LUN_BITMASK_LIST_BUFFER, asBitmaskEntry) +#endif + +#define EXT_DEF_LUN_BITMASK_LIST_MIN_SIZE \ + (EXT_DEF_LUN_BITMASK_LIST_HEADER_SIZE + \ + (sizeof(EXT_EXTERNAL_LUN_BITMASK_ENTRY) * EXT_DEF_LUN_BITMASK_LIST_MIN_ENTRIES)) +#define EXT_LUN_BITMASK_LIST_MAX_SIZE \ + (EXT_LUN_BITMASK_LIST_HEADER_SIZE + \ + (sizeof(EXT_EXTERNAL_LUN_BITMASK_ENTRY) * EXT_DEF_LUN_BITMASK_LIST_MAX_ENTRIES)) +/* + * LUN mask bit manipulation macros + * + * P = Pointer to an EXT_LUN_BIT_MASK union. + * L = LUN number. + */ +#define EXT_IS_LUN_BIT_SET(P,L) \ + ((P->mask[L/8] & (0x80 >> (L%8)))?1:0) + +#define EXT_SET_LUN_BIT(P,L) \ + (P->mask[L/8] |= (0x80 >> (L%8))) + +#define EXT_CLR_LUN_BIT(P,L) \ + (P->mask[L/8] &= ~(0x80 >> (L%8))) + + + +#ifdef _MSC_VER +#pragma pack() +#endif + +#endif /* _EXIOCT_H */ diff -Nur linux-2.4.19/drivers/scsi/qla2x00exioctln.h linux-2.4.19-sgi211r3/drivers/scsi/qla2x00exioctln.h --- linux-2.4.19/drivers/scsi/qla2x00exioctln.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/qla2x00exioctln.h Tue Jan 8 17:05:38 2002 @@ -0,0 +1,131 @@ +/***************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.2.x and 2.4.x +* Copyright (C) 2000 Qlogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +****************************************************************************/ + +/* + Rev 8 Jan 08, 2001 BN + - Added LOOP_BACK ioctl define + + Rev 7 Nov 06, 2000 BN + - Added EXT_DEF_MAX_AEN_QUEUE_OS define + - Added define for handle_hba_t + + Rev 6 Oct 25, 2000 BN + - Added EXT_CC_DRIVER_PROP_OS define + + Rev 5 Oct 25, 2000 BN + - Redo the copyright header and add AEN details + + Rev 4 Oct 23, 2000 BN + - Added definition for BOOLEAN + + Rev 3 Oct 23, 2000 + BN + - Added definitions for EXT_ADDR_MODE_OS + and also include of + + Rev 2 Oct 18, 2000 + BN + - Enable API Exention support + + Rev 1 Original version Sep 7, 2000 + BN + + + +*/ + +#include + +#if BITS_PER_LONG <= 32 +#define EXT_ADDR_MODE_OS EXT_DEF_ADDR_MODE_32 +#else +#define EXT_ADDR_MODE_OS EXT_DEF_ADDR_MODE_64 +#endif + +#define UINT8 uint8_t +#define UINT16 uint16_t +#define UINT32 uint32_t +#define UINT64 void * +#define BOOLEAN uint8_t + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int + +#if BITS_PER_LONG > 32 +#define uint64_t unsigned long +#else +#define uint64_t unsigned long long +#endif + +typedef struct track_instance +{ + + int handle; + +} track_instance_t; + + +#define EXT_DEF_MAX_HBA_OS 256 /* 0 - 0xFF */ +#define EXT_DEF_MAX_BUS_OS 1 +#define EXT_DEF_MAX_TARGET_OS 256 /* 0 - 0xFF */ +#define EXT_DEF_MAX_LUN_OS 256 /* 0 - 0xFF */ + +#define EXT_DEF_MAX_AEN_QUEUE_OS 64 + +#define QLMULTIPATH_MAGIC 'y' +#define _QLBUILD /* for exioct.h to enable include of qinsdmgt.h */ + +#define EXT_CC_STARTIOCTL _IOWR(QLMULTIPATH_MAGIC, 0 , sizeof(EXT_IOCTL)) +#define EXT_CC_SETINSTANCE _IOWR(QLMULTIPATH_MAGIC, 1 , sizeof(EXT_IOCTL)) + +#define EXT_CC_QUERY_OS _IOWR(QLMULTIPATH_MAGIC, 2 , sizeof(EXT_IOCTL)) +#define EXT_CC_SEND_FCCT_PASSTHRU_OS _IOWR(QLMULTIPATH_MAGIC, 3 , sizeof(EXT_IOCTL)) +#define EXT_CC_READ_NVRAM_OS _IOWR(QLMULTIPATH_MAGIC, 4 , sizeof(EXT_IOCTL)) +#define EXT_CC_SCSI_PASSTHRU_OS _IOWR(QLMULTIPATH_MAGIC, 5 , sizeof(EXT_IOCTL)) +#define EXT_CC_STOP_QCMD _IOWR(QLMULTIPATH_MAGIC, 6 , sizeof(EXT_IOCTL)) +#define EXT_CC_RESUME_QCMD _IOWR(QLMULTIPATH_MAGIC, 7 , sizeof(EXT_IOCTL)) +#define EXT_CC_GET_DATA_OS _IOWR(QLMULTIPATH_MAGIC, 8 , sizeof(EXT_IOCTL)) +#define EXT_CC_WWPN_TO_SCSIADDR _IOWR(QLMULTIPATH_MAGIC, 9 , sizeof(EXT_IOCTL)) +#define EXT_CC_REG_AEN_OS _IOWR(QLMULTIPATH_MAGIC, 10 , sizeof(EXT_IOCTL)) +#define EXT_CC_GET_AEN_OS _IOWR(QLMULTIPATH_MAGIC, 11 , sizeof(EXT_IOCTL)) + +#define EXT_CC_DRIVER_PROP_OS _IOWR(QLMULTIPATH_MAGIC, 12 , sizeof(EXT_IOCTL)) + +#define EXT_CC_LOOPBACK_OS _IOWR(QLMULTIPATH_MAGIC, 20 , sizeof(EXT_IOCTL)) + + + +/* + * Overrides for Emacs so that we almost follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -Nur linux-2.4.19/drivers/scsi/qla2x00ioctl.c linux-2.4.19-sgi211r3/drivers/scsi/qla2x00ioctl.c --- linux-2.4.19/drivers/scsi/qla2x00ioctl.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/qla2x00ioctl.c Tue Jan 8 17:05:38 2002 @@ -0,0 +1,1179 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic QLA2x00 device driver for Linux 2.2.x and 2.4.x +* Copyright (C) 2000 Qlogic Corporation +* (www.qlogic.com) +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2, or (at your option) any +* later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +** +******************************************************************************/ +/**************************************************************************** +Revision History: + Rev. 1.3 Beta February 20, 2001 BN QLogic + - Zero the sp used for IOCTL SCSI Passthru operations + Rev. 1.2 Beta January 31, 2001 BN QLogic + - Added setting of scsi completion to pext->DetailStatus + and set pext->Status to EXT_STATUS_SCSI_STATUS. + - Added details to Statistics IOCTL for ispaborts, + lip_count, isr_count. + + Rev. 1.2 Beta January 8, 2001 BN QLogic + - Added loop-back diagnostic IOCTL support. + + Rev. 1.1 Beta October 27, 2000 BN QLogic + - Updated return status from ioctl function. + + Rev. 1.0 Beta October 20, 2000 BN QLogic + - Initial version check in + + +*/ + +void copy_up_EXT( PEXT_IOCTL pext, void *arg) { +uint32_t i; +uint8_t *usr_temp, *kernel_tmp; + + /* copy up the EXT_IOCTL to application (api library) */ + for (i=0 ; i < sizeof(EXT_IOCTL) ; i++) { + usr_temp = (uint8_t *)arg + i; + kernel_tmp = (uint8_t *)pext + i; + __put_user(*kernel_tmp, usr_temp); + } + + return; +} + + +/************************************************************************* + * ioctl_scsi_pt_done + * + * Description: + * Sets completion flag. + * + * Returns: + *************************************************************************/ +void ioctl_scsi_pt_done(Scsi_Cmnd *pscsi_cmd) { + struct Scsi_Host *host; + scsi_qla_host_t *ha; + + host = pscsi_cmd->host; + ha = (scsi_qla_host_t *) host->hostdata; + + ha->IoctlPassThru_InProgress = 0; + return; +} + + +/************************************************************************* + * ioctl_fcct_done + * + * Description: + * Sets completion flag. + * + * Returns: + *************************************************************************/ +void ioctl_fcct_done(Scsi_Cmnd *pscsi_cmd) { + struct Scsi_Host *host; + scsi_qla_host_t *ha; + + host = pscsi_cmd->host; + ha = (scsi_qla_host_t *) host->hostdata; + /* printk("ioctl_fcct_done post function called OK\n"); */ + DEBUG(sprintf(debug_buff,"ioctl_fcct_done post function called OK\n")); + DEBUG(qla2100_print(debug_buff)); + ha->IoctlPassFCCT_InProgress = 0; + return; +} + + +/************************************************************************* + * qla2100_ioctl + * + * Description: + * Performs ioctl requests not satified by the upper levels. + * + * Returns: + * ret = 0 Success + * ret != 0 Failed; detailed status copied to EXT_IOCTL structure + * if applicable + *************************************************************************/ +int +qla2100_ioctl(Scsi_Device *dev, int cmd, void *arg){ + + static EXT_IOCTL ext; + PEXT_IOCTL pext = &ext; + struct Scsi_Host *host; + scsi_qla_host_t *ha, *search_ha; + scsi_lu_t *q; +#if BITS_PER_LONG <= 32 + uint32_t handle; +#else + uint64_t handle; +#endif + uint32_t cnt, i, b, t, l, port_cnt, status; + uint32_t tgt_cnt, tgt, transfer_size, inst; + uint8_t *extptr, *usrsrc, *usr_temp, *kernel_tmp, *kernel_tmp1; + static Scsi_Cmnd scsi_cmd; + Scsi_Cmnd *pscsi_cmd = &scsi_cmd; + static Scsi_Device scsi_device; + static srb_t ioctl_sp; + srb_t *sp = &ioctl_sp; + static EXT_SCSI_PASSTHRU scsi_pass; + EXT_SCSI_PASSTHRU *pscsi_pass = &scsi_pass; + static EXT_HBA_NODE tmp_hba_node; + static EXT_HBA_PORT tmp_hba_port; + static EXT_DISC_PORT tmp_disc_port; + static EXT_DISC_TARGET tmp_disc_target; + static EXT_CHIP tmp_isp; + static EXT_HBA_PORT_STAT tmp_stat; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + unsigned long cpu_flags = 0; + uint16_t scratch; + uint16_t *wptr = &scratch; + qla_boards_t *bdp; + uint8_t *temp; + uint8_t tempbuf[8]; + cmd_ms_iocb_entry_t *pkt; + + int ret = EINVAL; + + BZERO((caddr_t)sp,sizeof(srb_t)); + + host = dev->host; + ha = (scsi_qla_host_t *) host->hostdata; /* midlayer chosen instance */ + + ret = verify_area(VERIFY_READ, (void *)arg, sizeof(EXT_IOCTL)); + if (ret) { + DEBUG2(printk("[qla2100_ioctl: ERROR in verify_area READ ha=%8x]\n",(uint32_t)ha);) + return(ret); + } + /* copy in application layer EXT_IOCTL */ + for (i=0 ; i < sizeof(EXT_IOCTL) ; i++) { + usrsrc = (uint8_t *)(arg + i); + extptr = (uint8_t *)pext + i; + __get_user(*extptr, usrsrc); + } + + /* printk("[GOT QLA2100 IOCTL sig=%s cmd=%x]\n", + (char *)&pext->Signature,cmd); */ + + /* check signature of this ioctl */ + temp = (uint8_t *) &pext->Signature; +#if BITS_PER_LONG <= 32 +for (i=0 ; i<4 ; i++,temp++) tempbuf[i] = *temp; + if( (tempbuf[0] == 'Q') && (tempbuf[1] == 'L') && + (tempbuf[2] == 'O') && (tempbuf[3] == 'G')) status = 0; + else status = 1; +#else + if( (tempbuf[0] == 'Q') && (tempbuf[1] == 'L') && + (tempbuf[2] == 'O') && (tempbuf[3] == 'G') && + (tempbuf[4] == 'I') && (tempbuf[5] == 'C')) status = 0; + else status = 1; +#endif + if ( status != 0) { + DEBUG2(printk("[GOT QLA2100 IOCTL but signature did not match ha=%8x]\n", + (uint32_t)ha);) + ret = EXT_STATUS_ERR; + return(ret); + } + /* check version of this ioctl */ + if (pext->Version != EXT_VERSION) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_INVALID_PARAM; + copy_up_EXT(pext,arg); + printk(KERN_WARNING "qla2x00: GOT QLA2100 IOCTL but version did not match.\n"); + ret = EXT_STATUS_ERR; + return(ret); + } + /* check for API setting HBA Instance for subsequent operations */ + if (cmd == (int)EXT_CC_SETINSTANCE) { + /* since API opens devices once and uses handle for subsequent calls */ + /* we keep a parameter to designate the "active HBA" for ioctls */ + if (pext->HbaSelect < num_hosts) { + apiHBAInstance = pext->HbaSelect; + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + } else { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_INVALID_PARAM; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR in EXT_SETINSTANCE ha=%8x]\n",(uint32_t)ha);) + ret = EXT_STATUS_ERR; + } + return(ret); /* Instance for subsequent IOCTLs are not set */ + } + + /* check for valid apiHBAInstance (set previously by EXT_SETINSTANCE + or default 0) and set ha context for this IOCTL */ + for (search_ha=qla2100_hostlist; + (search_ha != NULL) && search_ha->instance != apiHBAInstance; + search_ha = search_ha->next) ; + if ( !search_ha ) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_INVALID_PARAM; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR in matching apiHBAInstance to an HBA Instance]\n");) + ret = EXT_STATUS_ERR; + return(ret); + } + /* IOCTL ha context is ready to be set from apiHBAInstance */ + ha = search_ha; + /* set EXT_IOCTL.HbaSelect for reference by IOCTL caller */ + pext->HbaSelect = apiHBAInstance; + + switch (cmd) { /* switch on EXT IOCTL COMMAND CODE */ + case EXT_CC_STARTIOCTL: + pext->Instance = num_hosts; + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + /*printk("[QLA2100 EXT_STARTIOCTL did OK ]\n");*/ + ret = EXT_STATUS_OK; + break; + case EXT_CC_QUERY: + /* All Query type ioctls are done here */ + switch(pext->SubCode) { + case EXT_SC_QUERY_HBA_NODE: + /* fill all available HBA NODE Information */ + bdp = &QLBoardTbl_fc[ha->devnum]; + for (i=0; i < 8 ;i++) tmp_hba_node.WWNN[i] = ha->node_name[i]; + sprintf((char *)(tmp_hba_node.Manufacturer),"Qlogic Corp."); + sprintf((char *)(tmp_hba_node.Model),(char *)&bdp->bdName[0]); + tmp_hba_node.SerialNum[0] = ha->node_name[5]; + tmp_hba_node.SerialNum[1] = ha->node_name[6]; + tmp_hba_node.SerialNum[2] = ha->node_name[7]; + sprintf((char *)(tmp_hba_node.DriverVersion),QLA2100_VERSION); + sprintf((char *)(tmp_hba_node.FWVersion),"%2d.%02d.%02d", + bdp->fwver[0], bdp->fwver[1], bdp->fwver[2]); + /* tmp_hba_node.NvramVersion = ha->nvram_version; */ + sprintf((char *)(tmp_hba_node.OptRomVersion),"0"); + tmp_hba_node.InterfaceType = EXT_DEF_FC_INTF_TYPE; + tmp_hba_node.PortCount = 1; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_HBA_NODE)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE ha=%8x]\n",(uint32_t)ha);) + return(ret); + } + /* now copy up the HBA_NODE to user */ + if (pext->ResponseLen < sizeof(EXT_HBA_NODE)) transfer_size = pext->ResponseLen; + else transfer_size = sizeof(EXT_HBA_NODE); + for (i=0 ; i < transfer_size ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)&tmp_hba_node + i; + __put_user(*kernel_tmp, usr_temp); + } + /*printk("[finished QLA2100 IOCTL QUERY_HBA_NODE ]\n"); */ + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + case EXT_SC_QUERY_HBA_PORT: + /* reflect all HBA PORT related info */ + tmp_hba_port.WWPN[7] = ha->init_cb->port_name[7]; + tmp_hba_port.WWPN[6] = ha->init_cb->port_name[6]; + tmp_hba_port.WWPN[5] = ha->init_cb->port_name[5]; + tmp_hba_port.WWPN[4] = ha->init_cb->port_name[4]; + tmp_hba_port.WWPN[3] = ha->init_cb->port_name[3]; + tmp_hba_port.WWPN[2] = ha->init_cb->port_name[2]; + tmp_hba_port.WWPN[1] = ha->init_cb->port_name[1]; + tmp_hba_port.WWPN[0] = ha->init_cb->port_name[0]; + tmp_hba_port.Id[1] = ha->port_id[0]; + tmp_hba_port.Id[2] = ha->port_id[1]; + tmp_hba_port.Id[3] = ha->port_id[2]; + tmp_hba_port.Type = EXT_DEF_INITIATOR_DEV; + + port_cnt = 0; + tgt_cnt = 0; + for (tgt = 0; tgt < MAX_FIBRE_DEVICES ; tgt++) { + if (ha->fc_db[tgt].loop_id > LAST_SNS_LOOP_ID) + continue; + port_cnt++; + + /* at this point the linux driver does not differentiate */ + /* Initiator devices (ie HBAs) from Targets; so the count */ + /* is same for both */ + /* if (ha->fc_db[tgt] & FC_INITIATOR_DEVICE) + continue; */ + tgt_cnt++; + } + tmp_hba_port.DiscPortCount = port_cnt; + tmp_hba_port.DiscTargetCount = tgt_cnt; + + if ( ha->loop_down_timer == 0 && ha->loop_state == LOOP_DOWN) { + tmp_hba_port.State = EXT_DEF_HBA_LOOP_DOWN; + } else tmp_hba_port.State = EXT_DEF_HBA_OK; + tmp_hba_port.DiscPortNameType = EXT_DEF_USE_PORT_NAME; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + sizeof(EXT_HBA_PORT)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE ha=%8x]\n",(uint32_t)ha);) + return(ret); + } + /* now copy up the HBA_PORT to user */ + if (pext->ResponseLen < sizeof(EXT_HBA_PORT)) transfer_size = pext->ResponseLen; + else transfer_size = sizeof(EXT_HBA_PORT); + for (i=0 ; i < transfer_size ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)&tmp_hba_port + i; + __put_user(*kernel_tmp, usr_temp); + } + /*printk("[finished QLA2100 IOCTL QUERY_HBA_PORT ports=%x tgts=%x]\n",port_cnt,tgt_cnt); */ + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + case EXT_SC_QUERY_DISC_PORT: + for (tgt=0, inst=0; tgt < MAX_FIBRE_DEVICES; tgt++) { + if (ha->fc_db[tgt].loop_id > LAST_SNS_LOOP_ID) + continue; + if( inst != pext->Instance ) { + inst++; + continue; + } + break; + } + if (tgt == MAX_FIBRE_DEVICES) { + pext->Status = ret = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + return(ret); + } + + tmp_disc_port.WWNN[0] = ha->fc_db[tgt].name[0]; + tmp_disc_port.WWNN[1] = ha->fc_db[tgt].name[1]; + tmp_disc_port.WWNN[2] = ha->fc_db[tgt].name[2]; + tmp_disc_port.WWNN[3] = ha->fc_db[tgt].name[3]; + + tmp_disc_port.WWNN[4] = ha->fc_db[tgt].name[4]; + tmp_disc_port.WWNN[5] = ha->fc_db[tgt].name[5]; + tmp_disc_port.WWNN[6] = ha->fc_db[tgt].name[6]; + tmp_disc_port.WWNN[7] = ha->fc_db[tgt].name[7]; + + tmp_disc_port.WWPN[0] = ha->fc_db[tgt].wwn[0]; + tmp_disc_port.WWPN[1] = ha->fc_db[tgt].wwn[1]; + tmp_disc_port.WWPN[2] = ha->fc_db[tgt].wwn[2]; + tmp_disc_port.WWPN[3] = ha->fc_db[tgt].wwn[3]; + + tmp_disc_port.WWPN[4] = ha->fc_db[tgt].wwn[4]; + tmp_disc_port.WWPN[5] = ha->fc_db[tgt].wwn[5]; + tmp_disc_port.WWPN[6] = ha->fc_db[tgt].wwn[6]; + tmp_disc_port.WWPN[7] = ha->fc_db[tgt].wwn[7]; + + tmp_disc_port.Id[1] = ha->fc_db[tgt].port_id[0]; + tmp_disc_port.Id[2] = ha->fc_db[tgt].port_id[1]; + tmp_disc_port.Id[3] = ha->fc_db[tgt].port_id[2]; + tmp_disc_port.Type = EXT_DEF_TARGET_DEV; + + tmp_disc_port.Status = EXT_STATUS_OK; + tmp_disc_port.Bus = 0; + tmp_disc_port.TargetId = tgt; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + sizeof(EXT_DISC_PORT)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE ha=%8x]\n",(uint32_t)ha);) + return(ret); + } + + /* now copy up the DISC_PORT to user */ + if (pext->ResponseLen < sizeof(EXT_DISC_PORT)) transfer_size = pext->ResponseLen; + else transfer_size = sizeof(EXT_DISC_PORT); + for (i=0 ; i < transfer_size ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)&tmp_disc_port + i; + __put_user(*kernel_tmp, usr_temp); + } + /*printk("[finished QLA2100 IOCTL QUERY_DISC_PORT ]\n"); */ + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + case EXT_SC_QUERY_DISC_TGT: + /* (for multipath merge) to do: search the ha->tgt[][] data base + instead of ha->fc_db[] so that we give details on Targets that + are visible to the OS. */ + for (tgt=0, inst=0; tgt < MAX_FIBRE_DEVICES; tgt++) { + if (ha->fc_db[tgt].loop_id > LAST_SNS_LOOP_ID) + continue; + if( inst != pext->Instance ) { + inst++; + continue; + } + break; + } + if (tgt == MAX_FIBRE_DEVICES) { + pext->Status = ret = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + return(ret); + } + tmp_disc_target.WWNN[0]= ha->fc_db[tgt].name[0]; + tmp_disc_target.WWNN[1]= ha->fc_db[tgt].name[1]; + tmp_disc_target.WWNN[2]= ha->fc_db[tgt].name[2]; + tmp_disc_target.WWNN[3]= ha->fc_db[tgt].name[3]; + + tmp_disc_target.WWNN[4]= ha->fc_db[tgt].name[4]; + tmp_disc_target.WWNN[5]= ha->fc_db[tgt].name[5]; + tmp_disc_target.WWNN[6]= ha->fc_db[tgt].name[6]; + tmp_disc_target.WWNN[7]= ha->fc_db[tgt].name[7]; + + + tmp_disc_target.WWPN[0]= ha->fc_db[tgt].wwn[0]; + tmp_disc_target.WWPN[1]= ha->fc_db[tgt].wwn[1]; + tmp_disc_target.WWPN[2]= ha->fc_db[tgt].wwn[2]; + tmp_disc_target.WWPN[3]= ha->fc_db[tgt].wwn[3]; + + tmp_disc_target.WWPN[4]= ha->fc_db[tgt].wwn[4]; + tmp_disc_target.WWPN[5]= ha->fc_db[tgt].wwn[5]; + tmp_disc_target.WWPN[6]= ha->fc_db[tgt].wwn[6]; + tmp_disc_target.WWPN[7]= ha->fc_db[tgt].wwn[7]; + tmp_disc_target.Id[1] = ha->fc_db[tgt].port_id[0]; + tmp_disc_target.Id[2] = ha->fc_db[tgt].port_id[1]; + tmp_disc_target.Id[3] = ha->fc_db[tgt].port_id[2]; + tmp_disc_target.Type = EXT_DEF_TARGET_DEV; + + tmp_disc_target.Status = EXT_STATUS_OK; + tmp_disc_target.Bus = 0; + tmp_disc_target.TargetId = tgt; + + cnt = 0; + for (i=0; i < MAX_LUNS ; i++) { + if ((ha->tgt[0][tgt])->luns[i] !=0) + cnt++; + } + tmp_disc_target.LunCount = cnt; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + sizeof(EXT_DISC_TARGET)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE ha=%8x]\n",(uint32_t)ha);) + return(ret); + } + /* now copy up the DISC_TGT to user */ + if (pext->ResponseLen < sizeof(EXT_DISC_PORT)) transfer_size = pext->ResponseLen; + else transfer_size = sizeof(EXT_DISC_TARGET); + for (i=0 ; i < transfer_size ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)&tmp_disc_target + i; + __put_user(*kernel_tmp, usr_temp); + } + /* printk("[finished QLA2100 IOCTL QUERY_DISC_TGT Luns=%x pid0=%x pid1=%x pid2=%x]\n",cnt,ha->fc_db[tgt].port_id[0],ha->fc_db[tgt].port_id[1],ha->fc_db[tgt].port_id[2]);*/ + + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + case EXT_SC_QUERY_CHIP: + host = ha->host; + tmp_isp.VendorId = QLA2100_VENDOR_ID; + tmp_isp.DeviceId = ha->device_id; + tmp_isp.SubVendorId = QLA2100_VENDOR_ID; + tmp_isp.SubSystemId = 0; + tmp_isp.PciBusNumber = ha->pci_bus; + tmp_isp.PciSlotNumber = (ha->pci_device_fn & 0xf8) >> 3; + tmp_isp.IoAddr = host->io_port; + tmp_isp.IoAddrLen = 512; + tmp_isp.MemAddr = 0; + tmp_isp.MemAddrLen = 0; + tmp_isp.ChipType = 0; + tmp_isp.InterruptLevel = host->irq; + for (i=0;i<8;i++) tmp_isp.OutMbx[i] = 0; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + sizeof(EXT_CHIP)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE ha=%8x]\n",(uint32_t)ha);) + return(ret); + } + /* now copy up the ISP to user */ + if (pext->ResponseLen < sizeof(EXT_CHIP)) transfer_size = pext->ResponseLen; + else transfer_size = sizeof(EXT_CHIP); + for (i=0 ; i < transfer_size ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)&tmp_isp + i; + __put_user(*kernel_tmp, usr_temp); + } + /* printk("[finished QLA2100 IOCTL QUERY_CHIP]\n"); */ + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + + case EXT_SC_QUERY_DISC_LUN: + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + default: + ret = EXT_STATUS_ERR; + break; + } + break; + case EXT_CC_GET_DATA: + switch(pext->SubCode) { + case EXT_SC_GET_STATISTICS: + + tmp_stat.ControllerErrorCount = ha->isp_aborts; + tmp_stat.DeviceErrorCount = 0; + tmp_stat.TotalIoCount = ha->qthreads; + tmp_stat.TotalMBytes = 0; + tmp_stat.TotalLipResets = ha->lip_count; + tmp_stat.TotalInterrupts = ha->isr_count; + + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr, + sizeof(EXT_HBA_PORT_STAT)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE ha=%8x]\n",(uint32_t)ha);) + return(ret); + } + /* now copy up the STATISTICS to user */ + if (pext->ResponseLen < sizeof(EXT_HBA_PORT_STAT)) transfer_size = pext->ResponseLen; + else transfer_size = sizeof(EXT_HBA_PORT_STAT); + for (i=0 ; i < transfer_size ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)&tmp_stat + i; + __put_user(*kernel_tmp, usr_temp); + } + /*printk("[finished QLA2100 IOCTL STATISTICS ]\n");*/ + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + default: + break; + } + break; + case EXT_CC_SEND_FCCT_PASSTHRU: + DEBUG(sprintf(debug_buff,"qla2100_ioctl: start EXT_CC_SEND_FCCT_PASSTHRU\n")); + DEBUG(qla2100_print(debug_buff)); + /* Management Server type (fc switch) pass thru ioctl */ + /* same as EXT_FCSCSI_REQ but it is going to the FC switch */ + /* clear ioctl_sp and scsi_cmd to be used */ + kernel_tmp = (uint8_t *)sp; + for (i=0;iioctl_mem; + for (i=0;iResponseLen > PAGE_SIZE) pext->ResponseLen = PAGE_SIZE; + if (pext->RequestLen > PAGE_SIZE) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_INVALID_PARAM; + copy_up_EXT(pext,arg); + /*printk("[EXT_CC_SEND_FCCT_PASSTHRU too big ResponseLen=%x ReqLen=%x]\n",pext->ResponseLen,pext->RequestLen); */ + DEBUG2(printk("[qla2100_ioctl: ERROR size of requested Resp_len in EXT_CC_SEND_FCCT_PASSTHRU]\n");) + return(ret); + } + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + pext->RequestLen); + if (ret){ + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + /*printk("[EXT_CC_SEND_FCCT_PASSTHRU verify read error]\n");*/ + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area READ of EXT_CC_SEND_FCCT_PASSTHRU]\n");) + return(ret); + } + for (i=0 ; i < pext->RequestLen ; i++) { + /* copy in from user space the fcct command to be sent */ + usr_temp = (uint8_t *)pext->RequestAdr + i; + kernel_tmp = (uint8_t *)ha->ioctl_mem + i; + __get_user(*kernel_tmp, usr_temp); + /* printk("{%x}",*kernel_tmp); */ + } + /* check on current topology or loop down */ + if ((ha->current_topology != ISP_CFG_F) && + (ha->current_topology != ISP_CFG_FL ) ) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + /*printk("[EXT_CC_SEND_FCCT_PASSTHRU wrong topology current=%x]\n", + ha->current_topology); */ + DEBUG2(printk("[qla2100_ioctl: ERROR EXT_CC_SEND_FCCT_PASSTHRU not in F-Port or FL-Port mode]\n");) + return(ret); + } + /* check on loop down */ + if ( ha->loop_down_timer == 0 && ha->loop_state == LOOP_DOWN) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + /* printk("[EXT_CC_SEND_FCCT_PASSTHRU loop down]\n"); */ + DEBUG2(printk("[qla2100_ioctl: ERROR EXT_CC_SEND_FCCT_PASSTHRU not in F-Port mode]\n");) + return(ret); + } + /* login to management server device */ + if (ha->flags.managment_server_logged_in == 0) { + mb[0] = MBC_LOGIN_FABRIC_PORT; + mb[1] = MANAGEMENT_SERVER << 8; + mb[2] = 0xff; + mb[3] = 0xfffa; + + ret = qla2100_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + if ( (ret != 0) || (mb[0] == 0x4006) || + (mb[0] == 0x4009) || (mb[0] != 0x4000) ) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + /* printk("[EXT_CC_SEND_FCCT_PASSTHRU could not login to sns]\n"); */ + DEBUG2(printk("[qla2100_ioctl: ERROR could not login to Management Server]\n");) + DEBUG(sprintf(debug_buff,"FCCT ioctl: call qla2100_ms_req_pkt\n")); + DEBUG(qla2100_print(debug_buff)); + return(ret); + } + ha->flags.managment_server_logged_in = 1; + } + + /* setup sp for this FCCT pass thru */ + pscsi_cmd->host = ha->host; + sp->cmd = pscsi_cmd; + sp->flags = SRB_WATCHDOG; + + /* mark this as a special delivery and collection command */ + scsi_cmd.flags = 0; + scsi_cmd.scsi_done = ioctl_fcct_done; + + DEBUG(sprintf(debug_buff,"FCCT ioctl: FABRIC_LOGIN OK, call qla2100_ms_req_pkt\n")); + DEBUG(qla2100_print(debug_buff)); + + /* get spin lock for this operation */ + spin_lock_irqsave(&io_request_lock, cpu_flags); + + /* Get MS request packet. */ + if( (pkt = (cmd_ms_iocb_entry_t *)qla2100_ms_req_pkt(ha, sp) ) ) { + pkt->entry_type = MS_IOCB_TYPE; + pkt->entry_count = 1; + pkt->loop_id = MANAGEMENT_SERVER; + pkt->timeout = 4; + pkt->DSDcount = 1; + pkt->RespDSDcount = 2; + pkt->Response_bytecount = pext->ResponseLen; + pkt->Request_bytecount = pext->RequestLen; + + /* loading command payload address */ + pkt->dseg_req_address[0] = LS_64BITS(ha->ioctl_mem_phys); + pkt->dseg_req_address[1] = MS_64BITS(ha->ioctl_mem_phys); + pkt->dseg_req_length = pext->RequestLen; + + /* loading command response address */ + pkt->dseg_rsp_address[0] = LS_64BITS(ha->ioctl_mem_phys); + pkt->dseg_rsp_address[1] = MS_64BITS(ha->ioctl_mem_phys); + pkt->dseg_rsp_length = pext->ResponseLen; + + /* set flag to indicate IOCTL FCCT PassThru in progress */ + ha->IoctlPassFCCT_InProgress = 1; + + ha->ioctl_timer = 6; /* 6 ticks of 1 second timer max wait */ + + /* Issue command to ISP */ + qla2100_isp_cmd(ha); + } + /* release spin lock since command is issued */ + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + + DEBUG(sprintf(debug_buff, + "FCCT ioctl: Command issued and released spin lock\n")); + DEBUG(qla2100_print(debug_buff)); + + if (!pkt) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + /* printk("[EXT_CC_SEND_FCCT_PASSTHRU could not get Request Packet]\n"); */ + DEBUG2(printk("[qla2100_ioctl:EXT_CC_SEND_FCCT_PASSTHRU could not get Request Packet]\n");) + return(ret); + } + + /* wait for post function or timer to zero the InProgress flag */ + while (ha->IoctlPassFCCT_InProgress == 1) { + udelay(35); + } + + DEBUG(sprintf(debug_buff, + "FCCT ioctl: finished while(InProgress) wait loop \n")); + DEBUG(qla2100_print(debug_buff)); + /* printk("[FCCT IOCTL finished while(InProgress) wait loop ]\n");*/ + + if (ha->IoctlPassFCCT_InProgress == 1) { + /* We waited and post function did not get called */ + DEBUG(printk("[FCCT IOCTL post function not called]\n");) + DEBUG(sprintf(debug_buff, + "FCCT ioctl: post function not called \n")); + DEBUG(qla2100_print(debug_buff)); + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_ERR; + } else { + /* getting device data and putting in pext->ResponseAdr */ + /* printk("[post function called; start FCCT IOCTL returning up data ]\n");*/ + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE for IOCTL PT ha=%8x]\n", + (uint32_t)ha);) + return(ret); + } + /* sending back data returned from Management Server */ + for (i=0 ; i < pext->ResponseLen ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)ha->ioctl_mem + i; + /*printk("[%x]",*kernel_tmp);*/ + __put_user(*kernel_tmp, usr_temp); + } + /*printk("[finished QLA2100 IOCTL EXT_CC_SEND_FCCT_PASSTHRU]\n");*/ + pext->Status = EXT_STATUS_SCSI_STATUS; + pext->DetailStatus = sp->scode; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + } + break; + + case EXT_CC_SEND_SCSI_PASSTHRU: + /* printk("[start EXT_CC_SEND_SCSI_PASSTHRU]\n"); */ + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + sizeof(EXT_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area READ of EXT_SCSI_PASSTHRU]\n");) + return(ret); + } + for (i=0 ; i < sizeof(EXT_SCSI_PASSTHRU) ; i++) { + usr_temp = (uint8_t *)pext->RequestAdr + i; + kernel_tmp = (uint8_t *)pscsi_pass + i; + __get_user(*kernel_tmp, usr_temp); + } + if (pext->ResponseLen > PAGE_SIZE) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_INVALID_PARAM; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR size of requested EXT_SCSI_PASSTHRU]\n");) + return(ret); + } + /* clear ioctl_sp and scsi_cmd and scsi_device to be used */ + kernel_tmp = (uint8_t *)sp; + for (i=0;iioctl_mem; + for (i=0;ihost = ha->host; + sp->cmd = pscsi_cmd; + sp->flags = SRB_WATCHDOG; + + /* mark this as a special delivery and collection command */ + scsi_cmd.flags = 0; + scsi_cmd.scsi_done = ioctl_scsi_pt_done; + + scsi_cmd.device = &scsi_device; + scsi_cmd.device->tagged_queue = 0; + scsi_cmd.use_sg = 0; /* no ScatterGather */ + scsi_cmd.target = pscsi_pass->TargetAddr.Target; + scsi_cmd.lun = pscsi_pass->TargetAddr.Lun; + scsi_cmd.request_bufflen = pext->ResponseLen; + scsi_cmd.request_buffer = ha->ioctl_mem; + scsi_cmd.timeout_per_command = 0x300; + + // printk("[start FCSCSI IOCTL look at direction t=%x l=%x]\n", + // scsi_cmd.target,scsi_cmd.lun); + if (pscsi_pass->Direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) { + /* sending user data from pext->ResponseAdr to device */ + ret = verify_area(VERIFY_READ, (void *)pext->ResponseAdr, + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area READ EXT_SCSI_PASSTHRU]\n");) + return(ret); + } + for (i=0 ; i < pext->ResponseLen ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)ha->ioctl_mem + i; + __get_user(*kernel_tmp, usr_temp); + } + } + if (pscsi_pass->CdbLength == 6) { + scsi_cmd.cmd_len = 6; + scsi_cmd.data_cmnd[0] = scsi_cmd.cmnd[0] = pscsi_pass->Cdb[0]; + scsi_cmd.data_cmnd[1] = scsi_cmd.cmnd[1] = pscsi_pass->Cdb[1]; + scsi_cmd.data_cmnd[2] = scsi_cmd.cmnd[2] = pscsi_pass->Cdb[2]; + scsi_cmd.data_cmnd[3] = scsi_cmd.cmnd[3] = pscsi_pass->Cdb[3]; + scsi_cmd.data_cmnd[4] = scsi_cmd.cmnd[4] = pscsi_pass->Cdb[4]; + scsi_cmd.data_cmnd[5] = scsi_cmd.cmnd[5] = pscsi_pass->Cdb[5]; + scsi_cmd.data_cmnd[6] = scsi_cmd.cmnd[6] = 0; + scsi_cmd.data_cmnd[7] = scsi_cmd.cmnd[7] = 0; + scsi_cmd.data_cmnd[8] = scsi_cmd.cmnd[8] = 0; + scsi_cmd.data_cmnd[9] = scsi_cmd.cmnd[9] = 0; + } else if (pscsi_pass->CdbLength == 10) { + scsi_cmd.cmd_len = 0x0A; + scsi_cmd.data_cmnd[0] = scsi_cmd.cmnd[0] = pscsi_pass->Cdb[0]; + scsi_cmd.data_cmnd[1] = scsi_cmd.cmnd[1] = pscsi_pass->Cdb[1]; + scsi_cmd.data_cmnd[2] = scsi_cmd.cmnd[2] = pscsi_pass->Cdb[2]; + scsi_cmd.data_cmnd[3] = scsi_cmd.cmnd[3] = pscsi_pass->Cdb[3]; + scsi_cmd.data_cmnd[4] = scsi_cmd.cmnd[4] = pscsi_pass->Cdb[4]; + scsi_cmd.data_cmnd[5] = scsi_cmd.cmnd[5] = pscsi_pass->Cdb[5]; + scsi_cmd.data_cmnd[6] = scsi_cmd.cmnd[6] = pscsi_pass->Cdb[6]; + scsi_cmd.data_cmnd[7] = scsi_cmd.cmnd[7] = pscsi_pass->Cdb[7]; + scsi_cmd.data_cmnd[8] = scsi_cmd.cmnd[8] = pscsi_pass->Cdb[8]; + scsi_cmd.data_cmnd[9] = scsi_cmd.cmnd[9] = pscsi_pass->Cdb[9]; + } else if (pscsi_pass->CdbLength == 12) { + scsi_cmd.cmd_len = 0x0C; + scsi_cmd.data_cmnd[0] = scsi_cmd.cmnd[0] = pscsi_pass->Cdb[0]; + scsi_cmd.data_cmnd[1] = scsi_cmd.cmnd[1] = pscsi_pass->Cdb[1]; + scsi_cmd.data_cmnd[2] = scsi_cmd.cmnd[2] = pscsi_pass->Cdb[2]; + scsi_cmd.data_cmnd[3] = scsi_cmd.cmnd[3] = pscsi_pass->Cdb[3]; + scsi_cmd.data_cmnd[4] = scsi_cmd.cmnd[4] = pscsi_pass->Cdb[4]; + scsi_cmd.data_cmnd[5] = scsi_cmd.cmnd[5] = pscsi_pass->Cdb[5]; + scsi_cmd.data_cmnd[6] = scsi_cmd.cmnd[6] = pscsi_pass->Cdb[6]; + scsi_cmd.data_cmnd[7] = scsi_cmd.cmnd[7] = pscsi_pass->Cdb[7]; + scsi_cmd.data_cmnd[8] = scsi_cmd.cmnd[8] = pscsi_pass->Cdb[8]; + scsi_cmd.data_cmnd[9] = scsi_cmd.cmnd[9] = pscsi_pass->Cdb[9]; + scsi_cmd.data_cmnd[10] = scsi_cmd.cmnd[10] = pscsi_pass->Cdb[10]; + scsi_cmd.data_cmnd[11] = scsi_cmd.cmnd[10] = pscsi_pass->Cdb[11]; + } + /* Generate LU queue on bus, target, LUN */ + b = SCSI_BUS_32(pscsi_cmd); + t = SCSI_TCN_32(pscsi_cmd); + l = SCSI_LUN_32(pscsi_cmd); + + /* set sp->target for 32bit/64bit delivery */ + sp->wdg_time = 0; + + /* check presense of requested target and other conditions */ + if( TGT_Q(ha,b,t) == NULL || + ( TGT_Q(ha,b,t) && TGT_Q(ha,b,t)->loop_id > LAST_SNS_LOOP_ID) || + ( ha->loop_down_timer == 0 && ha->loop_state == LOOP_DOWN)) { + printk(KERN_WARNING "qla2x00: FCSCSI IOCTL Target MISSING.\n"); + DEBUG2(printk("scsi(%2d:%2d:%2d:%2d): SCSI PT port unavailable\n", + (int)ha->host_no,b,t,l);) + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + return(ret); + } + /* get spin lock for this operation */ + spin_lock_irqsave(&io_request_lock, cpu_flags); + + /* Allocate a LUN/DEVICE queue from this request */ + if( (q = GET_LU_Q(ha, b, t,l)) == NULL ) { + DRIVER_LOCK + if( (q = qla2100_lun_alloc()) == NULL ) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR in GET_LU_Q for SCSI_PASSTHRU ha=%8x]\n", + (uint32_t)ha);) + ret = EXT_STATUS_ERR; + return(ret); + } + LU_Q(ha, b, t, l) = q; + DEBUG(sprintf(debug_buff,"Allocate new device queue 0x%x\n",q)); + DEBUG(qla2100_print(debug_buff)); + DRIVER_UNLOCK + } + /* Set an invalid handle until we issue the command to ISP */ + /* then we will set the real handle value. */ + handle = INVALID_HANDLE; + CMD_HANDLE(pscsi_cmd) = (unsigned char *)handle; + + if( sp->flags ) { + sp->port_down_retry_count = ha->port_down_retry_count - 1; + sp->retry_count = ha->retry_count; + DEBUG3(sprintf(debug_buff,"qla2100: PT Set retry counts =0x%x,0x%x\n\r", + sp->port_down_retry_count,sp->retry_count)); + DEBUG3(qla2100_print(debug_buff)); + } + qla2100_putq_t(q,sp); + + /* set flag to indicate IOCTL SCSI PassThru in progress */ + ha->IoctlPassThru_InProgress = 1; + + //printk("[start FCSCSI IOCTL restart queues]\n"); + /* send command to adapter */ + qla2100_restart_queues(ha,FALSE); + + /* release spin lock since command is queued */ + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + + ha->ioctl_timer = 6; /* 6 ticks of 1 second timer max wait */ + + /* wait for post function or timer to zero the InProgress flag */ + while (ha->IoctlPassThru_InProgress == 1) { + udelay(35); + } + + //printk("[start FCSCSI IOCTL finished while]\n"); + if (ha->IoctlPassThru_InProgress == 1) { + /* We waited and post function did not get called */ + DEBUG(printk("[FCSCSI IOCTL post function not called]\n");) + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_ERR; + } else { + if (pscsi_pass->Direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) { + /* getting device data and putting in pext->ResponseAdr */ + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE for IOCTL PT ha=%8x]\n", + (uint32_t)ha);) + return(ret); + } + /* now copy up the READ data to user */ + for (i=0 ; i < pext->ResponseLen ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)ha->ioctl_mem + i; + /*printk("[%x]",*kernel_tmp);*/ + __put_user(*kernel_tmp, usr_temp); + } + } + //printk("[[sense0=%x sense2=%x]]\n", + //pscsi_cmd->sense_buffer[0], + //pscsi_cmd->sense_buffer[2]); + /* copy up structure to make sense data available to user */ + for (i=0;i<16;i++) + pscsi_pass->SenseData[i] = pscsi_cmd->sense_buffer[i]; + ret = verify_area(VERIFY_WRITE, (void *)pext->RequestAdr, + sizeof(EXT_SCSI_PASSTHRU)); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area WRITE of EXT_SCSI_PASSTHRU]\n");) + return(ret); + } + for (i=0 ; i < sizeof(EXT_SCSI_PASSTHRU) ; i++) { + usr_temp = (uint8_t *)pext->RequestAdr + i; + kernel_tmp = (uint8_t *)pscsi_pass + i; + __put_user(*kernel_tmp, usr_temp); + } + /* printk("[finished QLA2100 IOCTL EXT_FCSCSI_REQ]\n"); */ + pext->Status = EXT_STATUS_SCSI_STATUS; + pext->DetailStatus = sp->scode; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + } + break; + + case EXT_CC_READ_NVRAM: + if (pext->ResponseLen < sizeof(nvram21_t)) transfer_size = pext->ResponseLen; + else transfer_size = sizeof(nvram21_t)/2; + for( i = 0, cnt = 0; cnt < transfer_size ; cnt++ , i++ ) { + *wptr = qla2100_get_nvram_word(ha, cnt); + + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp = (uint8_t *)wptr; + + usr_temp += i; /* even byte */ + __put_user(*kernel_tmp, usr_temp); + + i++; + usr_temp = (uint8_t *)pext->ResponseAdr; + kernel_tmp1 = (uint8_t *)wptr + 1; + usr_temp += i; /* odd byte */ + __put_user(*kernel_tmp1, usr_temp); + } + + /* printk("[finished QLA2100 IOCTL EXT_NVR_RD]\n"); */ + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + break; + + case EXT_CC_LOOPBACK: + DEBUG(sprintf(debug_buff,"qla2100_ioctl: start EXT_CC_LOOPBACK\n")); + DEBUG(qla2100_print(debug_buff)); + + /* printk("[start EXT_CC_LOOPBACK]\n"); */ + + if (ha->device_id == QLA2100_DEVICE_ID) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + DEBUG2(printk("[EXT_CC_SEND_LOOP_BACK not supported on QLA2100]\n");) + return(ret); + } + + if (pext->ResponseLen > PAGE_SIZE) pext->ResponseLen = PAGE_SIZE; + if (pext->RequestLen > PAGE_SIZE) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_INVALID_PARAM; + copy_up_EXT(pext,arg); + /*printk("[EXT_CC_LOOPBACK too big ResponseLen=%x ReqLen=%x]\n",pext->ResponseLen,pext->RequestLen); */ + DEBUG2(printk("[qla2100_ioctl: ERROR size of requested Resp_len in EXT_CC_SEND_LOOP_BACK]\n");) + return(ret); + } + ret = verify_area(VERIFY_READ, (void *)pext->RequestAdr, + pext->RequestLen); + if (ret){ + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + /*printk("[EXT_CC_LOOPBACK verify read error]\n");*/ + DEBUG2(printk("[qla2100_ioctl: ERROR verify_area READ of EXT_CC_LOOPBACK]\n");) + return(ret); + } + for (i=0 ; i < pext->ResponseLen ; i++) { + /* copy in from user space the user data pattern to be sent */ + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)ha->ioctl_mem + i; + __get_user(*kernel_tmp, usr_temp); + /* printk("{%x}",*kernel_tmp); */ + } + /* check on loop down */ + if ( ha->loop_down_timer == 0 && ha->loop_state == LOOP_DOWN) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_DEV_NOT_FOUND; + copy_up_EXT(pext,arg); + /* printk("[EXT_CC_LOOPBACK loop down]\n"); */ + return(ret); + } + + /* get spin lock for this operation */ + spin_lock_irqsave(&io_request_lock, cpu_flags); + + mb[0] = MBC_DIAGNOSTIC_LOOP_BACK; + mb[1] = 0x72; /* options: 64 bit, use buffer for snd/rcv on ext. loop */ + mb[2] = mb[3] = mb[4] = mb[5] = mb[6] = mb[7] = mb[8] = mb[9] = 0; + mb[10] = LSW(pext->ResponseLen); + mb[11] = MSW(pext->ResponseLen); + mb[12] = 0; /* transfer segment count */ + mb[13] = 0; /* receive segment count */ + mb[14] = LSW(ha->ioctl_mem_phys); /* send data address */ + mb[15] = MSW(ha->ioctl_mem_phys); + mb[20] = QL21_64BITS_3RDWD(ha->ioctl_mem_phys); + mb[21] = QL21_64BITS_4THWD(ha->ioctl_mem_phys); + mb[16] = LSW(ha->ioctl_mem_phys); /* recv data address */ + mb[17] = MSW(ha->ioctl_mem_phys); + mb[6] = QL21_64BITS_3RDWD(ha->ioctl_mem_phys); + mb[7] = QL21_64BITS_4THWD(ha->ioctl_mem_phys); + mb[18] = 1; /* iteration count lsb */ + mb[19] = 0; /* iteration count msb */ + + DEBUG(sprintf(debug_buff, + "LoopBack ioctl: issue loop back mailbox command\n")); + DEBUG(qla2100_print(debug_buff)); + + // wait for 64 bit loopback ready firmware + status = qla2100_mailbox_command(ha,BIT_21|BIT_20|BIT_19|BIT_18| + BIT_17|BIT_16|BIT_15|BIT_14| + BIT_13|BIT_12|BIT_11| + BIT_10|BIT_7|BIT_6|BIT_1|BIT_0, + &mb[0]); + + /* release spin lock since command is issued */ + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + + if (status) { + DEBUG(sprintf(debug_buff, + "LoopBack ioctl: issue loop back mailbox command FAILED\n")); + DEBUG(qla2100_print(debug_buff)); + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_ERR; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_ERR; + } else { + /* put looped back data in pext->ResponseAdr */ + /* printk("[LoopBack ioctl: LoopBack was OK ]\n");*/ + ret = verify_area(VERIFY_WRITE, (void *)pext->ResponseAdr , + pext->ResponseLen); + if (ret) { + pext->Status = EXT_STATUS_ERR; + pext->DetailStatus = EXT_STATUS_COPY_ERR; + copy_up_EXT(pext,arg); + DEBUG2(printk("[LoopBack ioctl: ERROR verify_area WRITE ha=%x]\n", + (uint32_t)ha);) + return(ret); + } + /* sending back looped back data */ + for (i=0 ; i < pext->ResponseLen ; i++) { + usr_temp = (uint8_t *)pext->ResponseAdr + i; + kernel_tmp = (uint8_t *)ha->ioctl_mem + i; + /*printk("[%x]",*kernel_tmp);*/ + __put_user(*kernel_tmp, usr_temp); + } + /*printk("[finished QLA2100 IOCTL EXT_CC_LOOPBACK]\n");*/ + pext->Status = EXT_STATUS_OK; + pext->DetailStatus = EXT_STATUS_OK; + copy_up_EXT(pext,arg); + ret = EXT_STATUS_OK; + } + break; + +/* case EXT_CC_RSCN_REG: + break; + case EXT_CC_RSCN_GET: + break; + case EXT_CC_ELS_RNID_SEND: + break; + case EXT_CC_ELS_RTIN_SEND: + break; + case EXT_CC_PLATFORM_REG: + break; + +all others go here */ + + default: + break; + } + + return(ret); +} + diff -Nur linux-2.4.19/drivers/scsi/qlavendor.c linux-2.4.19-sgi211r3/drivers/scsi/qlavendor.c --- linux-2.4.19/drivers/scsi/qlavendor.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/qlavendor.c Tue Jan 8 17:05:38 2002 @@ -0,0 +1,325 @@ +/******************************************************************************** +* QLOGIC LINUX SOFTWARE +* +* QLogic ISP2x00 device driver for Linux 2.2.x (redhat 6.X). +* +* COPYRIGHT (C) 2000 QLOGIC CORPORATION +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the Qlogic's Linux Software License. See below. +* +* This program is WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistribution's or 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. +* +********************************************************************************/ + +/***************************************************************************************** + QLOGIC CORPORATION SOFTWARE + "GNU" GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION + AND MODIFICATION + +This GNU General Public License ("License") applies solely to QLogic Linux +Software ("Software") and may be distributed under the terms of this License. + +1. You may copy and distribute verbatim copies of the Software's source code as +you receive it, in any medium, provided that you conspicuously and appropriately +publish on each copy an appropriate copyright notice and disclaimer of warranty; +keep intact all the notices that refer to this License and to the absence of any +warranty; and give any other recipients of the Software a copy of this License along +with the Software. + +You may charge a fee for the physical act of transferring a copy, and you may at your +option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Software or any portion of it, thus forming +a work based on the Software, and copy and distribute such modifications or work under +the terms of Section 1 above, provided that you also meet all of these conditions: + +* a) You must cause the modified files to carry prominent notices stating that you +changed the files and the date of any change. + +* b) You must cause any work that you distribute or publish that in whole or in part +contains or is derived from the Software or any part thereof, to be licensed as a +whole at no charge to all third parties under the terms of this License. + +* c) If the modified Software normally reads commands interactively when run, you +must cause it, when started running for such interactive use in the most ordinary way, +to print or display an announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide a warranty) and that +users may redistribute the Software under these conditions, and telling the user how to +view a copy of this License. (Exception:if the Software itself is interactive but does +not normally print such an announcement, your work based on the Software is not required +to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of +that work are not derived from the Software, and can be reasonably considered independent +and separate works in themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you distribute the same +sections as part of a whole which is a work based on the Software, the distribution of the +whole must be on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote it. + +3. You may copy and distribute the Software (or a work based on it, under Section 2) in +object code or executable form under the terms of Sections 1 and 2 above provided that +you also do one of the following: + +* a) Accompany it with the complete corresponding machine-readable source code, which must +be distributed under the terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, + +* b) Accompany it with a written offer, valid for at least three years, to give any third +party, for a charge no more than your cost of physically performing source distribution, +a complete machine-readable copy of the corresponding source code, to be distributed under +the terms of Sections 1 and 2 above on a medium customarily used for software interchange; +or, + +* c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for noncommercial distribution +and only if you received the Software in object code or executable form with such an offer, +in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications +to it. For an executable work, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus the scripts used +to control compilation and installation of the executable. + +If distribution of executable or object code is made by offering access to copy from a +designated place, then offering equivalent access to copy the source code from the same +place counts as distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Software except as expressly +provided under this License. Any attempt otherwise to copy, modify, sublicense or +distribute the Software is void, and will automatically terminate your rights under this +License. However, parties who have received copies, or rights, from you under this License +will not have their licenses terminated so long as such parties remain in full compliance. + +5. This license grants you world wide, royalty free non-exclusive rights to modify or +distribute the Software or its derivative works. These actions are prohibited by law +if you do not accept this License. Therefore, by modifying or distributing the Software +(or any work based on the Software), you indicate your acceptance of this License to do +so, and all its terms and conditions for copying, distributing or modifying the Software +or works based on it. + +6. Each time you redistribute the Software (or any work based on the Software), the +recipient automatically receives a license from the original licensor to copy, distribute +or modify the Software subject to these terms and conditions. You may not impose any +further restrictions on the recipients' exercise of the rights granted herein. You are +not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for +any other reason (not limited to patent issues), conditions are imposed on you +(whether by court order, agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this License +and any other pertinent obligations, then as a consequence you may not distribute the +Software at all. + +If any portion of this section is held invalid or unenforceable under any particular +circumstance, the balance of the section is intended to apply and the section as a whole +is intended to apply in other circumstances. +NO WARRANTY + +11. THE SOFTWARE IS PROVIDEDWITHOUT A WARRANTY OF ANY KIND. THERE IS NO +WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. +SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING +BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO +OPERATE WITH ANY OTHER SOFTWARES), EVEN IF SUCH HOLDER OR OTHER PARTY HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +******************************************************************************/ +/* + * vendor specific op codes. +*/ + +#define UCSCSI_DCMD 0x20 /* DAC960 direct command */ +#define UCSCSI_DCMD_PASSTHRU 0x21 /* DAC960 pass-through command */ +#define UC_SCSI_DCMD 0x22 /* DAC960 FSI direct command */ +#define DAC_CDB_LEN 12 +#define DAC_SENSE_LEN 64 + +#define SCSI_WRITE10 0x2A /* Required for direct disk writes */ +#define SCSI_WRITE6 0x0A /* Required for direct disk writes */ +#define SCSI_WRITEBUFFER 0x3B /* Required for flashing disk FW */ +#define DACMD_WRITE_CONF_ONDISK 0x4B +#define DACMD_WRITE_CONFIG 0x06 +#define DACMD_WRITE_CONF2 0x3C +#define DACMD_WRITE_CONFLABEL 0x49 /* Write configuration label */ +#define DACMD_WRITE_CONFIG_V3x 0x4F +#define DACMD_ADD_CONFIG_V2x 0x18 +#define DACMD_ADD_CONFIG_V3x 0x4C +#define DACMD_STORE_IMAGE 0x21 +#define DACMD_ADD_CAPACITY 0x2A /* add physical drives to existing array */ +#define DACMD_WRITE_IOPORT 0x3A /* write port B */ +#define DACMD_S2S_WRITEFULLCONF 0x60 /* write full configuration */ +#define DACMD_S2S_ADDFULLCONF 0x62 /* add full configuration */ +#define DACMD_S2S_WRITELUNMAP_OLD 0x58 /* write LUN map information */ +#define DACMD_S2S_WRITELUNMAP 0xD2 /* Write LUN MAP Information */ +#define DACMD_S2S_WRITE_IOPORT 0x66 /* write expanded IO port */ +#define DACMD_WRITE_V3x 0x34 /* write data from plain memory */ +#define DACMD_S2S_WRITESIG 0x4D /* write signature information */ + +#define MDACIOCTL_STOREIMAGE 0x2C /* Store the softeware image on controller */ +#define MDACIOCTL_WRITESIGNATURE 0xA6 /* Write Controller Signature */ +#define MDACIOCTL_SETREALTIMECLOCK 0xAC /* Set real time clock value */ +#define MDACIOCTL_PASS_THRU_CDB 0xAD /* Set up a pass-through command */ +#define MDACIOCTL_PASS_THRU_INITIATE 0xAE /* Initiates a pass-through read/write command (bi-directional) */ +#define MDACIOCTL_CREATENEWCONF 0xC0 /* Create new configruation */ +#define MDACIOCTL_ADDNEWCONF 0xC4 /* Add new logical/physical device to configruation */ +#define MDACIOCTL_MORE 0xC6 /* Do MORE operation */ +#define MDACIOCTL_SETPHYSDEVPARAMETER 0xC8 /* Set physical device parameters */ +#define MDACIOCTL_SETLOGDEVPARAMETER 0xCF /* Set logical device parameters */ +#define MDACIOCTL_SETCONTROLLERPARAMTER 0xD1 /* Set controller parameter */ +#define MDACIOCTL_WRITESANMAP 0xD4 /* Set logical device LUN map */ +#define MDACIOCTL_SETMACADDRESS 0xD5 /* Set controller MAC address */ + + /* + * qla2100_set_scsi_direction + * This routine will set the proper direction for vendor specific + * commands. + * + * Note: Vendors should modify this routine to set the proper + * direction of the transfer if they used vendor specific commands. + * + * Input: + * ha = adapter block pointer. + * sp = SCSI Request Block structure pointer. + * + * Returns: + * 0 = success, was able to issue command. + */ + + void qla2100_set_vend_direction(scsi_qla_host_t *ha, + Scsi_Cmnd *cmd, cmd_entry_t *pkt) { + /* This section added 10-JAN-2001 by Lethe. Required to facilitate SCSI + pass-through for flashing disk firmware, and direct disk writes under + Mylex 6.x and 5.x Firmware */ + if( cmd->data_cmnd[0] == UCSCSI_DCMD_PASSTHRU) { + pkt->control_flags = 0; + switch (cmd->data_cmnd[2]) { + case SCSI_WRITE6: + case SCSI_WRITE10: + case SCSI_WRITEBUFFER: + pkt->control_flags |= BIT_6; + break; + default: + pkt->control_flags |= BIT_5; + } + } + else if( cmd->data_cmnd[0] == UCSCSI_DCMD ) + { + pkt->control_flags = 0; + switch( cmd->data_cmnd[2] ) + { + case DACMD_WRITE_CONF_ONDISK: + case DACMD_WRITE_CONFIG: + case DACMD_WRITE_CONF2: + case DACMD_WRITE_CONFLABEL: + case DACMD_WRITE_CONFIG_V3x: + case DACMD_ADD_CONFIG_V2x: + case DACMD_ADD_CONFIG_V3x: + case DACMD_STORE_IMAGE: + case DACMD_ADD_CAPACITY: + case DACMD_WRITE_IOPORT: + case DACMD_S2S_WRITEFULLCONF: + case DACMD_S2S_ADDFULLCONF: + case DACMD_S2S_WRITELUNMAP_OLD: + case DACMD_S2S_WRITELUNMAP: + case DACMD_S2S_WRITE_IOPORT: + case DACMD_WRITE_V3x: + case DACMD_S2S_WRITESIG: + pkt->control_flags |= BIT_6; + break; + default: + pkt->control_flags |= BIT_5; + } + } + +/******************************************************************************************* +* The below logic is required to operate correctly with Mylex (IBM's) DAC960 family of * +* external RAID controllers. * +* * +* In addition to defining whether below CDBs are Reads or Writes, Mylex, in their infinite * +* wisdom, defined a vendor-specific CDB which can act as a Read OR a write, depending on * +* the parameters sent in a previous MDACIOCTL_PASS_THRU_CDB. Instead of adding a lot of * +* logic to define and maintain a MDACIOCTL_PASS_THRU_CDB queue, and parse each one of them * +* to determine direction, I took easy way out (also the low-overhead method). * +* * +* If the high-order bit of the 32-bit UniqueID, defined in byte 3 of data_cmnd[3] is set * +* then I will mark that as a CDB which is going to be a write, otherwise the pass thru * +* operation will be a read. If somebody wishes to rewrite the driver to maintain a 30-sec * +* command queue, and parse the contents of each data buffer passed in to determine R or W * +* then they are free to do so, and it will not impact future versions of the Distributed * +* Array Manager, which required this fix in the first place. * +* * +* This configurator and patch was written by David A. Lethe of Xyratex david@santools.com. * +* In addition, the logic to check cmd->data_cmnd[0] == UC_SCSI_DCMD, was written by * +* Sammy Wilborn of Silicon Graphics, Inc, and David Lethe * +* They define CDBs used by the DAC960FF family, when running FW 7.x and above. * +* * +*******************************************************************************************/ + + else if ( cmd->data_cmnd[0] == UC_SCSI_DCMD ) /* Mylex DAC960 FW 7.x */ + { + pkt->control_flags = 0; + switch( cmd->data_cmnd[2] ) + { + case MDACIOCTL_STOREIMAGE: + case MDACIOCTL_SETREALTIMECLOCK: + case MDACIOCTL_WRITESIGNATURE: + case MDACIOCTL_CREATENEWCONF: + case MDACIOCTL_ADDNEWCONF: + case MDACIOCTL_MORE: + case MDACIOCTL_SETPHYSDEVPARAMETER: + case MDACIOCTL_SETLOGDEVPARAMETER: + case MDACIOCTL_SETCONTROLLERPARAMTER: + case MDACIOCTL_WRITESANMAP: + case MDACIOCTL_SETMACADDRESS: + case MDACIOCTL_PASS_THRU_CDB: + pkt->control_flags |= BIT_6; + break; + default: + if (cmd->data_cmnd[2] == MDACIOCTL_PASS_THRU_INITIATE) { + /* If the high bit of the UniqueID field of the vendor- + specific field is TRUE, then it is marked as a write. */ + if (cmd->data_cmnd[3] & 0x80) + pkt->control_flags |= BIT_6; + else + pkt->control_flags |= BIT_5; + } + else + pkt->control_flags |= BIT_5; + break; + } + } + else + { + pkt->control_flags |= BIT_5; + } + + } diff -Nur linux-2.4.19/drivers/scsi/qlogicfc.c linux-2.4.19-sgi211r3/drivers/scsi/qlogicfc.c --- linux-2.4.19/drivers/scsi/qlogicfc.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/scsi/qlogicfc.c Wed Oct 16 14:02:58 2002 @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,23 @@ #define pci64_dma_build(hi,lo) \ ((dma_addr_t)(((u64)(lo))|(((u64)(hi))<<32))) +#ifdef BRINGUP + +#ifdef BRINGUP2 +int qdelay=2000; /* Default delay */ +#else +int qdelay=100; /* Default delay */ +#endif +static int __init set_qdelay(char *str) +{ + get_option(&str, &qdelay); + return 1; +} + +__setup("qdelay=", set_qdelay); + +#endif + #include "qlogicfc.h" /* Configuration section **************************************************** */ @@ -679,14 +697,25 @@ static void isp2x00_print_status_entry(struct Status_Entry *); #endif +#ifdef BUS_INT_WAR +void sn_add_polled_interrupt(int irq, int interval); +void sn_delete_polled_interrupt(int irq); +#endif + static inline void isp2x00_enable_irqs(struct Scsi_Host *host) { +#ifdef BUS_INT_WAR + sn_add_polled_interrupt(host->irq, 1); +#endif outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL); } static inline void isp2x00_disable_irqs(struct Scsi_Host *host) { +#ifdef BUS_INT_WAR + sn_delete_polled_interrupt(host->irq); +#endif outw(0x0, host->io_port + PCI_INTER_CTL); } @@ -789,6 +818,7 @@ scsi_unregister(host); continue; } +#ifndef BRINGUP2 if (!request_region(host->io_port, 0xff, "qlogicfc")) { printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " "in use\n", @@ -798,6 +828,7 @@ scsi_unregister(host); continue; } +#endif outw(0x0, host->io_port + PCI_SEMAPHORE); outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); @@ -1560,6 +1591,28 @@ Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); +#ifdef BRINGUP + if ( (le16_to_cpu(sts->completion_status) != CS_COMPLETE) + && (le16_to_cpu(sts->completion_status) != CS_PORT_UNAVAILABLE) ) { + printk("qlogicfc%d : completion status 0x%x; scsi status 0x%x; state flags 0x%x; status flags 0x%x\n", + hostdata->host_id, le16_to_cpu(sts->completion_status), + le16_to_cpu(sts->scsi_status), + le16_to_cpu(sts->state_flags), + le16_to_cpu(sts->status_flags)); + + if ( le16_to_cpu(sts->scsi_status) & 0x0200 ) { + printk(" SCSI Sense Data : 0x%x %x %x %x %x %x %x %x\n", + sts->req_sense_data[0], + sts->req_sense_data[1], + sts->req_sense_data[2], + sts->req_sense_data[3], + sts->req_sense_data[4], + sts->req_sense_data[5], + sts->req_sense_data[6], + sts->req_sense_data[7]); + } + } +#endif /* * if any of the following are true we do not * call scsi_done. if the status is CS_ABORTED @@ -1806,6 +1859,16 @@ return 0; } +#ifdef BRINGUP +static void my_delay(unsigned int cycles) +{ + volatile unsigned long now; + now = jiffies; + while (jiffies < now+cycles) + ; +} +#endif + static int isp2x00_reset_hardware(struct Scsi_Host *host) { u_short param[8]; @@ -1827,7 +1890,13 @@ outw(HCCR_RESET, host->io_port + HOST_HCCR); udelay(100); outw(HCCR_RELEASE, host->io_port + HOST_HCCR); +#ifdef BRINGUP + my_delay(qdelay); +#endif outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); +#ifdef BRINGUP + my_delay(qdelay); +#endif loop_count = DEFAULT_LOOP_COUNT; while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) { diff -Nur linux-2.4.19/drivers/scsi/scsi_dma.c linux-2.4.19-sgi211r3/drivers/scsi/scsi_dma.c --- linux-2.4.19/drivers/scsi/scsi_dma.c Mon Feb 25 11:38:04 2002 +++ linux-2.4.19-sgi211r3/drivers/scsi/scsi_dma.c Tue Aug 27 19:53:13 2002 @@ -23,15 +23,86 @@ * PAGE_SIZE must be a multiple of the sector size (512). True * for all reasonably recent architectures (even the VAX...). */ -#define SECTOR_SIZE 512 +#ifdef CONFIG_IA64_PAGE_SIZE_64KB +#define BIG_SECTORS +#endif + +#ifdef BIG_SECTORS +#define SECTOR_SHIFT 10 +#else +#define SECTOR_SHIFT 9 +#endif + +#define SECTOR_SIZE (1<= 64) { \ + (m).hi = ((u64) 1 << ((nbits) - 64)) - 1; \ + (m).lo = ~(u64) 0; \ + } else { \ + (m).hi = 0; \ + (m).lo = ((u64) 1 << (nbits)) - 1; \ + } \ +} while (0) + +#define MAP_SHIFT_LEFT(m, count) \ +do { \ + if ((count) >= 64) { \ + (m).hi = (m).lo << ((count) - 64); \ + (m).lo = 0; \ + } else { \ + (m).hi = ((m).hi << (count)) | ((m).lo >> (64 - (count))); \ + (m).lo <<= count; \ + } \ +} while (0) + +#define MAP_AND(r, left, right) \ +do { \ + (r).hi = (left).hi & (right).hi; \ + (r).lo = (left).lo & (right).lo; \ +} while (0) + +#define MAP_SET(r, mask) \ +do { \ + (r).hi |= (mask).hi; \ + (r).lo |= (mask).lo; \ +} while (0) + +#define MAP_CLEAR(r, mask) \ +do { \ + (r).hi &= ~(mask).hi; \ + (r).lo &= ~(mask).lo; \ +} while (0) + +#define MAP_EQUAL(left, right) (((left.hi ^ right.hi) | (left.lo ^ right.lo)) == 0) +#define MAP_EMPTY(m) ((m.lo | m.hi) == 0) + +#endif + +#ifndef MAP_MAKE_MASK +# define MAP_MAKE_MASK(m,nbits) ((m) = (((u64) 1 << (nbits)) - 1)) +# define MAP_SHIFT_LEFT(m,nbits) ((m) <<= (nbits)) +# define MAP_AND(res,l,r) ((res) = (l) & (r)) +# define MAP_EQUAL(l,r) ((l) == (r)) +# define MAP_EMPTY(m) ((m) == 0) +# define MAP_CLEAR(m, bits) ((m) &= ~(bits)) +# define MAP_SET(m, bits) ((m) |= (bits)) #endif /* @@ -71,31 +142,42 @@ */ void *scsi_malloc(unsigned int len) { - unsigned int nbits, mask; + FreeSectorBitmap mask, busy_sectors, result; + unsigned int nbits; unsigned long flags; int i, j; +#ifdef BIG_SECTORS + if (len % SECTOR_SIZE) + len += 512; +#endif if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE) return NULL; - nbits = len >> 9; - mask = (1 << nbits) - 1; + nbits = len >> SECTOR_SHIFT; spin_lock_irqsave(&allocator_request_lock, flags); - for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) + for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) { + MAP_MAKE_MASK(mask, nbits); + busy_sectors = dma_malloc_freelist[i]; for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) { - if ((dma_malloc_freelist[i] & (mask << j)) == 0) { - dma_malloc_freelist[i] |= (mask << j); + MAP_AND(result, busy_sectors, mask); + if (MAP_EMPTY(result)) { + MAP_SET(dma_malloc_freelist[i], mask); scsi_dma_free_sectors -= nbits; #ifdef DEBUG - SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9))); - printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9)); + SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p\n", + len, dma_malloc_pages[i] + (j << SECTOR_SHIFT))); + printk("SMalloc: %d %p\n", + len, dma_malloc_pages[i] + (j << SECTOR_SHIFT)); #endif spin_unlock_irqrestore(&allocator_request_lock, flags); return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); } + MAP_SHIFT_LEFT(mask, 1); } + } spin_unlock_irqrestore(&allocator_request_lock, flags); return NULL; /* Nope. No more */ } @@ -121,7 +203,8 @@ */ int scsi_free(void *obj, unsigned int len) { - unsigned int page, sector, nbits, mask; + FreeSectorBitmap mask, result; + unsigned int page, sector, nbits; unsigned long flags; #ifdef DEBUG @@ -136,22 +219,27 @@ SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len)); #endif +#ifdef BIG_SECTORS + if (len % SECTOR_SIZE) + len += 512; +#endif spin_lock_irqsave(&allocator_request_lock, flags); for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) { unsigned long page_addr = (unsigned long) dma_malloc_pages[page]; if ((unsigned long) obj >= page_addr && (unsigned long) obj < page_addr + PAGE_SIZE) { - sector = (((unsigned long) obj) - page_addr) >> 9; + sector = (((unsigned long) obj) - page_addr) >> SECTOR_SHIFT; - nbits = len >> 9; - mask = (1 << nbits) - 1; + nbits = len >> SECTOR_SHIFT; + MAP_MAKE_MASK(mask, nbits); if (sector + nbits > SECTORS_PER_PAGE) panic("scsi_free:Bad memory alignment"); - if ((dma_malloc_freelist[page] & - (mask << sector)) != (mask << sector)) { + MAP_SHIFT_LEFT(mask, sector); + MAP_AND(result, mask, dma_malloc_freelist[page]); + if (!MAP_EQUAL(result, mask)) { #ifdef DEBUG printk("scsi_free(obj=%p, len=%d) called from %08lx\n", obj, len, ret); @@ -159,7 +247,7 @@ panic("scsi_free:Trying to free unused memory"); } scsi_dma_free_sectors += nbits; - dma_malloc_freelist[page] &= ~(mask << sector); + MAP_CLEAR(dma_malloc_freelist[page], mask); spin_unlock_irqrestore(&allocator_request_lock, flags); return 0; } diff -Nur linux-2.4.19/drivers/scsi/scsi_ioctl.c linux-2.4.19-sgi211r3/drivers/scsi/scsi_ioctl.c --- linux-2.4.19/drivers/scsi/scsi_ioctl.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/scsi/scsi_ioctl.c Wed Oct 16 14:02:58 2002 @@ -198,6 +198,9 @@ unsigned int needed, buf_needed; int timeout, retries, result; int data_direction; +#if __GNUC__ < 3 + int foo; +#endif if (!sic) return -EINVAL; @@ -207,12 +210,21 @@ if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) return -EFAULT; - if(__get_user(inlen, &sic->inlen)) +#if __GNUC__ < 3 + foo = __get_user(inlen, &sic->inlen); + if(foo) return -EFAULT; - if(__get_user(outlen, &sic->outlen)) + foo = __get_user(outlen, &sic->outlen); + if(foo) + return -EFAULT; +#else + if(__get_user(inlen, &sic->inlen)) return -EFAULT; + if(__get_user(outlen, &sic->outlen)) + return -EFAULT; +#endif /* * We do not transfer more than MAX_BUF with this interface. * If the user needs to transfer more data than this, they diff -Nur linux-2.4.19/drivers/scsi/sd.c linux-2.4.19-sgi211r3/drivers/scsi/sd.c --- linux-2.4.19/drivers/scsi/sd.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/scsi/sd.c Tue Dec 3 18:34:00 2002 @@ -89,6 +89,8 @@ #define SD_TIMEOUT (30 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) +struct hd_struct *sd; + static Scsi_Disk *rscsi_disks; static struct gendisk *sd_gendisks; static int *sd_sizes; @@ -244,6 +246,8 @@ case BLKROGET: case BLKRASET: case BLKRAGET: + case BLKGETLASTSECT: + case BLKSETLASTSECT: case BLKFLSBUF: case BLKSSZGET: case BLKPG: @@ -1089,6 +1093,7 @@ */ static int sd_registered; +static int order; static int sd_init() { @@ -1157,9 +1162,25 @@ max_sectors[SD_MAJOR(i)] = sd_max_sectors + i * (SCSI_DISKS_PER_MAJOR << 4); } - sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); + /* + * FIXME: should unregister blksize_size, hardsect_size and max_sectors when + * the module is unloaded. + */ + order = get_order((sd_template.dev_max << 4) * sizeof(struct hd_struct)); + sd = (struct hd_struct *)__get_free_pages(GFP_ATOMIC, order); + + if (!sd) { + printk(KERN_ERR "*** SCSI error: failed to allocate device structures\n"); + BUG(); + goto cleanup_sd; + } + memset(sd, 0, (sd_template.dev_max << 4) * sizeof(struct hd_struct)); + + if (N_USED_SD_MAJORS > 1) + sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); if (!sd_gendisks) goto cleanup_sd_gendisks; + for (i = 0; i < N_USED_SD_MAJORS; i++) { sd_gendisks[i] = sd_gendisk; /* memcpy */ sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr, @@ -1204,6 +1225,8 @@ kfree(sd_gendisks); sd_gendisks = NULL; cleanup_sd_gendisks: + free_pages((unsigned long)sd, order); +cleanup_sd: kfree(sd_max_sectors); cleanup_max_sectors: kfree(sd_hardsizes); @@ -1438,6 +1461,7 @@ kfree(sd_sizes); kfree(sd_blocksizes); kfree(sd_hardsizes); + free_pages((unsigned long)sd, order); for (i = 0; i < N_USED_SD_MAJORS; i++) { #if 0 /* XXX aren't we forgetting to deallocate something? */ kfree(sd_gendisks[i].de_arr); diff -Nur linux-2.4.19/drivers/scsi/simscsi.c linux-2.4.19-sgi211r3/drivers/scsi/simscsi.c --- linux-2.4.19/drivers/scsi/simscsi.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/simscsi.c Tue Aug 27 19:53:13 2002 @@ -0,0 +1,384 @@ +/* + * Simulated SCSI driver. + * + * Copyright (C) 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1999, 2001 David Mosberger-Tang + * Copyright (C) 1999 Stephane Eranian + * + * 99/12/18 David Mosberger Added support for READ10/WRITE10 needed by linux v2.3.33 + */ +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "scsi.h" +#include "sd.h" +#include "hosts.h" +#include "simscsi.h" + +#define DEBUG_SIMSCSI 1 + +/* Simulator system calls: */ + +#define SSC_OPEN 50 +#define SSC_CLOSE 51 +#define SSC_READ 52 +#define SSC_WRITE 53 +#define SSC_GET_COMPLETION 54 +#define SSC_WAIT_COMPLETION 55 + +#define SSC_WRITE_ACCESS 2 +#define SSC_READ_ACCESS 1 + +#ifdef DEBUG_SIMSCSI + int simscsi_debug; +# define DBG simscsi_debug +#else +# define DBG 0 +#endif + +#if 0 +struct timer_list disk_timer; +#else +static void simscsi_interrupt (unsigned long val); +DECLARE_TASKLET(simscsi_tasklet, simscsi_interrupt, 0); +#endif + +struct disk_req { + unsigned long addr; + unsigned len; +}; + +struct disk_stat { + int fd; + unsigned count; +}; + +extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr); + +static int desc[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; + +static struct queue_entry { + Scsi_Cmnd *sc; +} queue[SIMSCSI_REQ_QUEUE_LEN]; + +static int rd, wr; +static atomic_t num_reqs = ATOMIC_INIT(0); + +/* base name for default disks */ +static char *simscsi_root = DEFAULT_SIMSCSI_ROOT; + +#define MAX_ROOT_LEN 128 + +/* + * used to setup a new base for disk images + * to use /foo/bar/disk[a-z] as disk images + * you have to specify simscsi=/foo/bar/disk on the command line + */ +static int __init +simscsi_setup (char *s) +{ + /* XXX Fix me we may need to strcpy() ? */ + if (strlen(s) > MAX_ROOT_LEN) { + printk("simscsi_setup: prefix too long---using default %s\n", simscsi_root); + } + simscsi_root = s; + return 1; +} + +__setup("simscsi=", simscsi_setup); + +static void +simscsi_interrupt (unsigned long val) +{ + unsigned long flags; + Scsi_Cmnd *sc; + + spin_lock_irqsave(&io_request_lock, flags); + { + while ((sc = queue[rd].sc) != 0) { + atomic_dec(&num_reqs); + queue[rd].sc = 0; + if (DBG) + printk("simscsi_interrupt: done with %ld\n", sc->serial_number); + (*sc->scsi_done)(sc); + rd = (rd + 1) % SIMSCSI_REQ_QUEUE_LEN; + } + } + spin_unlock_irqrestore(&io_request_lock, flags); +} + +int +simscsi_detect (Scsi_Host_Template *templ) +{ + templ->proc_name = "simscsi"; +#if 0 + init_timer(&disk_timer); + disk_timer.function = simscsi_interrupt; +#endif + return 1; /* fake one SCSI host adapter */ +} + +int +simscsi_release (struct Scsi_Host *host) +{ + return 0; /* this is easy... */ +} + +const char * +simscsi_info (struct Scsi_Host *host) +{ + return "simulated SCSI host adapter"; +} + +int +simscsi_abort (Scsi_Cmnd *cmd) +{ + printk ("simscsi_abort: unimplemented\n"); + return SCSI_ABORT_SUCCESS; +} + +int +simscsi_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) +{ + printk ("simscsi_reset: unimplemented\n"); + return SCSI_RESET_SUCCESS; +} + +int +simscsi_biosparam (Disk *disk, kdev_t n, int ip[]) +{ + int size = disk->capacity; + + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; +} + +static void +simscsi_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset, unsigned long len) +{ + struct disk_stat stat; + struct disk_req req; + + req.addr = __pa(sc->request_buffer); + req.len = len; /* # of bytes to transfer */ + + if (sc->request_bufflen < req.len) + return; + + stat.fd = desc[sc->target]; + if (DBG) + printk("simscsi_%s @ %lx (off %lx, len %lu) ->", + mode == SSC_READ ? "read":"write", req.addr, offset, len); + ia64_ssc(stat.fd, 1, __pa(&req), offset, mode); + ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION); + + if (stat.count == req.len) { + sc->result = GOOD; + } else { + sc->result = DID_ERROR << 16; + } + if (DBG) + printk("%d\n", sc->result); +} + +static void +simscsi_sg_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset) +{ + int list_len = sc->use_sg; + struct scatterlist *sl = (struct scatterlist *)sc->buffer; + struct disk_stat stat; + struct disk_req req; + + stat.fd = desc[sc->target]; + + while (list_len) { + req.addr = __pa(sl->address); + req.len = sl->length; + if (DBG) + printk("simscsi_sg_%s @ %lx (off %lx) use_sg=%d len=%d\n", + mode == SSC_READ ? "read":"write", req.addr, offset, + list_len, sl->length); + ia64_ssc(stat.fd, 1, __pa(&req), offset, mode); + ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION); + + /* should not happen in our case */ + if (stat.count != req.len) { + sc->result = DID_ERROR << 16; + return; + } + offset += sl->length; + sl++; + list_len--; + } + sc->result = GOOD; +} + +/* + * function handling both READ_6/WRITE_6 (non-scatter/gather mode) + * commands. + * Added 02/26/99 S.Eranian + */ +static void +simscsi_readwrite6 (Scsi_Cmnd *sc, int mode) +{ + unsigned long offset; + + offset = (((sc->cmnd[1] & 0x1f) << 16) | (sc->cmnd[2] << 8) | sc->cmnd[3])*512; + if (sc->use_sg > 0) + simscsi_sg_readwrite(sc, mode, offset); + else + simscsi_readwrite(sc, mode, offset, sc->cmnd[4]*512); +} + + +static void +simscsi_readwrite10 (Scsi_Cmnd *sc, int mode) +{ + unsigned long offset; + + offset = ( (sc->cmnd[2] << 24) | (sc->cmnd[3] << 16) + | (sc->cmnd[4] << 8) | (sc->cmnd[5] << 0))*512; + if (sc->use_sg > 0) + simscsi_sg_readwrite(sc, mode, offset); + else + simscsi_readwrite(sc, mode, offset, ((sc->cmnd[7] << 8) | sc->cmnd[8])*512); +} + +int +simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *)) +{ + char fname[MAX_ROOT_LEN+16]; + char *buf; +#if DEBUG_SIMSCSI + register long sp asm ("sp"); + + if (DBG) + printk("simscsi_queuecommand: target=%d,cmnd=%u,sc=%lu,sp=%lx,done=%p\n", + sc->target, sc->cmnd[0], sc->serial_number, sp, done); +#endif + + sc->result = DID_BAD_TARGET << 16; + sc->scsi_done = done; + if (sc->target <= 7 && sc->lun == 0) { + switch (sc->cmnd[0]) { + case INQUIRY: + if (sc->request_bufflen < 35) { + break; + } + sprintf (fname, "%s%c", simscsi_root, 'a' + sc->target); + desc[sc->target] = ia64_ssc (__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS, + 0, 0, SSC_OPEN); + if (desc[sc->target] < 0) { + /* disk doesn't exist... */ + break; + } + buf = sc->request_buffer; + buf[0] = 0; /* magnetic disk */ + buf[1] = 0; /* not a removable medium */ + buf[2] = 2; /* SCSI-2 compliant device */ + buf[3] = 2; /* SCSI-2 response data format */ + buf[4] = 31; /* additional length (bytes) */ + buf[5] = 0; /* reserved */ + buf[6] = 0; /* reserved */ + buf[7] = 0; /* various flags */ + memcpy(buf + 8, "HP SIMULATED DISK 0.00", 28); + sc->result = GOOD; + break; + + case TEST_UNIT_READY: + sc->result = GOOD; + break; + + case READ_6: + if (desc[sc->target] < 0 ) + break; + simscsi_readwrite6(sc, SSC_READ); + break; + + case READ_10: + if (desc[sc->target] < 0 ) + break; + simscsi_readwrite10(sc, SSC_READ); + break; + + case WRITE_6: + if (desc[sc->target] < 0) + break; + simscsi_readwrite6(sc, SSC_WRITE); + break; + + case WRITE_10: + if (desc[sc->target] < 0) + break; + simscsi_readwrite10(sc, SSC_WRITE); + break; + + + case READ_CAPACITY: + if (desc[sc->target] < 0 || sc->request_bufflen < 8) { + break; + } + buf = sc->request_buffer; + + /* pretend to be a 1GB disk (partition table contains real stuff): */ + buf[0] = 0x00; + buf[1] = 0x1f; + buf[2] = 0xff; + buf[3] = 0xff; + /* set block size of 512 bytes: */ + buf[4] = 0; + buf[5] = 0; + buf[6] = 2; + buf[7] = 0; + sc->result = GOOD; + break; + + case MODE_SENSE: + printk("MODE_SENSE\n"); + break; + + case START_STOP: + printk("START_STOP\n"); + break; + + default: + panic("simscsi: unknown SCSI command %u\n", sc->cmnd[0]); + } + } + if (sc->result == DID_BAD_TARGET) { + sc->result |= DRIVER_SENSE << 24; + sc->sense_buffer[0] = 0x70; + sc->sense_buffer[2] = 0x00; + } + if (atomic_read(&num_reqs) >= SIMSCSI_REQ_QUEUE_LEN) { + panic("Attempt to queue command while command is pending!!"); + } + atomic_inc(&num_reqs); + queue[wr].sc = sc; + wr = (wr + 1) % SIMSCSI_REQ_QUEUE_LEN; + +#if 0 + if (!timer_pending(&disk_timer)) { + disk_timer.expires = jiffies; + add_timer(&disk_timer); + } +#else + tasklet_schedule(&simscsi_tasklet); +#endif + return 0; +} + + +static Scsi_Host_Template driver_template = SIMSCSI; + +#include "scsi_module.c" diff -Nur linux-2.4.19/drivers/scsi/simscsi.h linux-2.4.19-sgi211r3/drivers/scsi/simscsi.h --- linux-2.4.19/drivers/scsi/simscsi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/scsi/simscsi.h Tue Jan 8 17:05:38 2002 @@ -0,0 +1,39 @@ +/* + * Simulated SCSI driver. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ +#ifndef SIMSCSI_H +#define SIMSCSI_H + +#define SIMSCSI_REQ_QUEUE_LEN 64 + +#define DEFAULT_SIMSCSI_ROOT "/var/ski-disks/sd" + +extern int simscsi_detect (Scsi_Host_Template *); +extern int simscsi_release (struct Scsi_Host *); +extern const char *simscsi_info (struct Scsi_Host *); +extern int simscsi_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int simscsi_abort (Scsi_Cmnd *); +extern int simscsi_reset (Scsi_Cmnd *, unsigned int); +extern int simscsi_biosparam (Disk *, kdev_t, int[]); + +#define SIMSCSI { \ + detect: simscsi_detect, \ + release: simscsi_release, \ + info: simscsi_info, \ + queuecommand: simscsi_queuecommand, \ + abort: simscsi_abort, \ + reset: simscsi_reset, \ + bios_param: simscsi_biosparam, \ + can_queue: SIMSCSI_REQ_QUEUE_LEN, \ + this_id: -1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: SIMSCSI_REQ_QUEUE_LEN, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING \ +} + +#endif /* SIMSCSI_H */ diff -Nur linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_glue.c linux-2.4.19-sgi211r3/drivers/scsi/sym53c8xx_2/sym_glue.c --- linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_glue.c Fri Dec 21 09:41:55 2001 +++ linux-2.4.19-sgi211r3/drivers/scsi/sym53c8xx_2/sym_glue.c Wed Oct 16 14:02:58 2002 @@ -302,11 +302,7 @@ #ifndef SYM_LINUX_DYNAMIC_DMA_MAPPING typedef u_long bus_addr_t; #else -#if SYM_CONF_DMA_ADDRESSING_MODE > 0 -typedef dma64_addr_t bus_addr_t; -#else typedef dma_addr_t bus_addr_t; -#endif #endif /* diff -Nur linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_malloc.c linux-2.4.19-sgi211r3/drivers/scsi/sym53c8xx_2/sym_malloc.c --- linux-2.4.19/drivers/scsi/sym53c8xx_2/sym_malloc.c Fri Nov 9 15:22:54 2001 +++ linux-2.4.19-sgi211r3/drivers/scsi/sym53c8xx_2/sym_malloc.c Wed Oct 16 14:02:58 2002 @@ -143,12 +143,15 @@ a = (m_addr_t) ptr; while (1) { -#ifdef SYM_MEM_FREE_UNUSED if (s == SYM_MEM_CLUSTER_SIZE) { +#ifdef SYM_MEM_FREE_UNUSED M_FREE_MEM_CLUSTER(a); +#else + ((m_link_p) a)->next = h[i].next; + h[i].next = (m_link_p) a; +#endif break; } -#endif b = a ^ s; q = &h[i]; while (q->next && q->next != (m_link_p) b) { diff -Nur linux-2.4.19/drivers/sgi/sn/Makefile linux-2.4.19-sgi211r3/drivers/sgi/sn/Makefile --- linux-2.4.19/drivers/sgi/sn/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/sgi/sn/Makefile Thu Jan 2 15:16:59 2003 @@ -0,0 +1,50 @@ +# +# Makefile for the linux kernel. +# +# +# Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/NoticeExplan +# + +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +O_TARGET := sn_drivers.a + +obj-y = +obj-$(CONFIG_IA64_SGI_SN) += fetchop.o +obj-$(CONFIG_IA64_SGI_SN) += mmtimer.o +obj-$(CONFIG_IA64_SGI_SN) += l1disp.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/drivers/sgi/sn/fetchop.c linux-2.4.19-sgi211r3/drivers/sgi/sn/fetchop.c --- linux-2.4.19/drivers/sgi/sn/fetchop.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/sgi/sn/fetchop.c Fri Feb 7 08:55:45 2003 @@ -0,0 +1,393 @@ +/* + * SN Platform FetchOp Support + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * SN2 FetchOp Device Driver + * + * This driver exports the SN fetchop facility to user processes. + * Fetchops are atomic memory operations that are implemented in the + * memory controller on SGI SN hardware. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_IA64_SGI_SN2 +#define DRIVER_ID_STR "SGI Fetchop Device Driver" +#define REVISION "1.01" + +static int fetchop_mmap(struct file *file, struct vm_area_struct *vma); +static int fetchop_release(struct inode *inode, struct file *file); + +static struct file_operations fetchop_fops = { + owner: THIS_MODULE, + mmap: fetchop_mmap, + release: fetchop_release, +}; + +/* + * There is one of these structs per node. It is used to manage the fetchop space + * that is available on the node. Current assumption is that there is + * only 1 fetchop block of memory per node. + */ +struct node_fetchops { + long maddr; /* MSPEC address of start of fetchops. */ + int count; /* Total number of fetchop pages. */ + atomic_t free; /* Number of pages currently free. */ + unsigned long bits[1]; /* Bitmap for managing pages. */ +}; + + +/* + * One of these structures is allocated when a fetchop region is mmaped. The structure + * is pointed to by the file->private_data field in the file struct. + * This structure is used to record the addresses of the fetop pages. + */ +struct file_data { + int count; /* Number of pages allocated. */ + unsigned long maddr[1]; /* Array of MSPEC addresses. */ +}; + + +/* + * Fetchop statistics. + */ +struct fetchop_stats { + long map_count; /* Number of active mmap's */ + long pages_in_use; /* Number of fetchop pages in use */ + long pages_total; /* Total number of fetchop pages */ +}; + + +static struct fetchop_stats fetchop_stats; +static struct node_fetchops *node_fetchops[MAX_COMPACT_NODES]; +static spinlock_t fetchop_lock = SPIN_LOCK_UNLOCKED; +static struct proc_dir_entry *proc_fetchop; + + + +/* + * fetchop_initialize_page + * + * Initial a page that is about to be used for fetchops. + * All fetchop variables in the page are set to 0. + * + */ +static void +fetchop_initialize_page(unsigned long maddr) +{ + unsigned long p, pe; + + for (p=FETCHOP_KADDR_TO_MSPEC_ADDR(maddr), pe=p+PAGE_SIZE; p= numnodes) + nid = local_cnodeid(); + for (i=0; ibits, fops->count)) < fops->count) { + if (test_and_set_bit(bit, fops->bits) == 0) { + atomic_dec(&node_fetchops[nid]->free); + maddr = fops->maddr + (bit<maddr) >> PAGE_SHIFT; + clear_bit(bit, node_fetchops[nid]->bits); + atomic_inc(&node_fetchops[nid]->free); +} + +static void +fetchop_free_pages(struct file_data *fdata) +{ + int i; + + for (i=0; icount; i++) + fetchop_free_page(fdata->maddr[i]); +} + + +/* + * fetchop_update_stats + * + * Update ststistics of the number of fetchop mappings & pages. + * If creating a new mapping, ensure that we dont exceed the maximum allowed + * number of fetchop pages. + */ +static int +fetchop_update_stats(int mmap, long count) +{ + int ret=0; + + spin_lock(&fetchop_lock); + if (count > 0 && fetchop_stats.pages_in_use + count > fetchop_stats.pages_total) { + ret = -1; + } else { + fetchop_stats.map_count += mmap; + fetchop_stats.pages_in_use += count; + } + spin_unlock(&fetchop_lock); + + return ret; +} + + +/* + * fetchop_mmap + * + * Called when mmaping /dev/fetchop. Creates fetchop pages and map them to + * user space. + */ +static int +fetchop_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long vm_start; + unsigned long maddr; + int pages; + struct file_data *fdata; + + if (vma->vm_pgoff != 0) + return -EINVAL; + + if ((vma->vm_flags&VM_WRITE) == 0) + return -EPERM; + + pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + if (fetchop_update_stats(1, pages) < 0) + return -ENOSPC; + + if (!(fdata=vmalloc(sizeof(struct file_data)+(pages-1)*sizeof(long)))) + return -ENOMEM; + + fdata->count = 0; + file->private_data = fdata; + + vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED | VM_NONCACHED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vm_start = vma->vm_start; + + while (vm_start < vma->vm_end) { + maddr = fetchop_alloc_page(local_cnodeid()); + if (maddr == 0) + BUG(); + fdata->maddr[fdata->count++] = maddr; + + + if (remap_page_range(vm_start, __pa(maddr), PAGE_SIZE, vma->vm_page_prot)) { + fetchop_free_pages(file->private_data); + return -EAGAIN; + } + vm_start += PAGE_SIZE; + } + + return 0; +} + +/* + * fetchop_release + * + * Called when destroying a /dev/fetchop mapping. Frees all + * fetchop pages belonging to the file. + */ +static int +fetchop_release(struct inode *inode, struct file *file) +{ + struct file_data *fdata; + + fdata = file->private_data; + if (fdata && fdata->count) { + fetchop_free_pages(fdata); + fetchop_update_stats(-1, -fdata->count); + } + + return 0; +} + +/* + * fetchop_read_proc + * + * Implements /proc/fetchop. Return statistics about fetchops. + */ +static int +fetchop_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + struct node_fetchops *fops; + int len = 0, nid; + + len += sprintf(page + len, "mappings : %ld\n", fetchop_stats.map_count); + len += sprintf(page + len, "current fetchop pages : %ld\n", fetchop_stats.pages_in_use); + len += sprintf(page + len, "maximum fetchop pages : %ld\n", fetchop_stats.pages_total); + + len += sprintf(page + len, "%4s %7s %7s\n", "node", "total", "free"); + for(nid = 0; nid < numnodes; nid++) { + fops = node_fetchops[nid]; + len += sprintf(page + len, "%4d %7d %7d\n", nid, fops ? fops->count : 0, fops ? atomic_read(&fops->free) : 0); + } + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int +fetchop_write_proc (struct file *file, const char *userbuf, unsigned long count, void *data) +{ + extern long atoi(char *); + char buf[80]; + + if (copy_from_user(buf, userbuf, count < sizeof(buf) ? count : sizeof(buf))) + return -EFAULT; + + return count; +} + + +/* + * fetchop_build_memmap, + * + * Called at boot time to build a map of pages that can be used for fetchops. + */ +static int __init +fetchop_build_memmap(unsigned long start, unsigned long end, void *arg) +{ + struct node_fetchops *fops; + long count, bytes; + + count = (end - start) >> PAGE_SHIFT; + bytes = sizeof(struct node_fetchops) + count/8; + fops = vmalloc(bytes); + memset(fops, 0, bytes); + fops->maddr = FETCHOP_KADDR_TO_MSPEC_ADDR(start); + fops->count = count; + atomic_add(count, &fops->free); + fetchop_stats.pages_total += count; + node_fetchops[MSPEC_TO_NID(start)] = fops; + + sn_flush_all_caches(__va(start), end - start); + + return 0; +} + + + +/* + * fetchop_init + * + * Called at boot time to initialize the fetchop facility. + */ +int __init +fetchop_init(void) +{ + devfs_handle_t hnd; + + if (!(hnd=devfs_register(NULL, FETCHOP_BASENAME, DEVFS_FL_AUTO_DEVNUM, + 0, 0, S_IFCHR | S_IRUGO | S_IWUGO, &fetchop_fops, NULL))) { + printk("%s: failed to register device\n", DRIVER_ID_STR); + return -1; + } + + if ((proc_fetchop = create_proc_entry(FETCHOP_BASENAME, 0644, NULL)) == NULL) { + printk("%s: unable to create proc entry", DRIVER_ID_STR); + return -1; + } + proc_fetchop->read_proc = fetchop_read_proc; + proc_fetchop->write_proc = fetchop_write_proc; + + efi_memmap_walk_uc(fetchop_build_memmap, 0); + printk("%s: v%s\n", DRIVER_ID_STR, REVISION); + + return 0; +} + + + +/*--------------------------------------------------------------------------------------- + * KERNEL APIs + * Note: right now, this APIs use a full page even though a single variable is allocated. + * If these interfaces are used a lot, they should be changed to suballocate + * out of a single page. + */ + +unsigned long +fetchop_kalloc_one(int nid) +{ + if (fetchop_update_stats(1, 1) < 0) + return 0; + return fetchop_alloc_page(nid); +} + + +void +fetchop_kfree_one(unsigned long maddr) +{ + fetchop_free_page(maddr); + fetchop_update_stats(-1, -1); +} + + +module_init(fetchop_init); + +#endif diff -Nur linux-2.4.19/drivers/sgi/sn/l1disp.c linux-2.4.19-sgi211r3/drivers/sgi/sn/l1disp.c --- linux-2.4.19/drivers/sgi/sn/l1disp.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/sgi/sn/l1disp.c Thu Jan 2 15:16:59 2003 @@ -0,0 +1,147 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * L1 display driver for SGI SN machines. + * + * Each brick in an SN system has a small LCD display connected to its + * L1 controller. This driver exports a file called 'l1' in /proc/sn_modules + * for each brick in the system, that the user to control what's displayed + * on the LCD. + * + * Once the SN2 PROM has a SAL call to set the L1 display string, this + * driver should be changed to use it (droppping SN1 support should be ok). + * + * This driver could also benefit from a proper topology API and system + * topology graph, since /proc/sn_modules isn't a very good place for + * the special files. + */ +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jesse Barnes "); +MODULE_DESCRIPTION("L1 display driver"); +MODULE_LICENSE("GPL"); + +static int l1disp_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data); +static struct proc_dir_entry *moduledir; /* /proc/sn_modules directory */ + +#define MODULES_DIR "sn_modules" +#define PROC_DIR "/proc/sn_modules" + +/** + * l1disp_init - initialize L1 display driver + * + * Sets up data structures and /proc entries for the L1 + * display driver + */ +static int __init +l1disp_init(void) +{ + int i; + + moduledir = proc_mkdir(MODULES_DIR, NULL); + if (!moduledir) { + printk(KERN_ERR "cannot create %s directory\n", PROC_DIR); + return -1; + } + + /* + * Create the /proc entries + */ + for (i = 0; i < nummodules; i++) { + char buffer[MAX_SERIAL_NUM_SIZE]; + struct proc_dir_entry *modentry, *l1entry; + + memset(buffer, 0, MAX_SERIAL_NUM_SIZE); + format_module_id(buffer, modules[i]->id, MODULE_FORMAT_BRIEF); + modentry = proc_mkdir(buffer, moduledir); + if (!modentry) { + printk(KERN_ERR "cannot create %s/%s\n", PROC_DIR, buffer); + return -1; + } + l1entry = create_proc_entry("l1", 0600, modentry); + if (!l1entry) { + printk(KERN_ERR "cannot create %s/%s/l1\n", PROC_DIR, buffer); + return -1; + } + l1entry->nlink = 1; +#ifdef CONFIG_IA64_SGI_SN1 + l1entry->data = (void *)&modules[i]->elsc; +#endif + l1entry->write_proc = l1disp_write_proc; + /* a read function would be nice... */ + } + return 0; +} + +/** + * l1disp_exit - cleanup L1 display driver + * + * Cleans up /proc entries associated with this driver + */ +static void +l1disp_exit(void) +{ + remove_proc_entry(MODULES_DIR, NULL); +} + +/** + * l1disp_write_proc - write a new line to the L1 display + * @file: file pointer the user wrote to + * @buffer: string to be displayed + * @count: string length + * @data: elsc_t * (l1 handle) to write to + * + * Writes the line specified by the user to the module specified by @data + */ +static int +l1disp_write_proc (struct file *file, const char *buffer, unsigned long count, + void *data) +{ + int line = 0; /* display line to write to */ + int result = 0; +#ifdef CONFIG_IA64_SGI_SN1 + elsc_t *l1 = (elsc_t *)data; /* l1 handle */ +#endif + char *msg; /* writable copy of buffer */ + + /* + * allocate some space for the message and null terminate it + * if it's not too big + */ + if (count > L1_DISPLAY_LINE_LENGTH) + return -EINVAL; + msg = kmalloc(count + 1, GFP_KERNEL); + if (!msg) { + printk(KERN_ERR "out of memory in %s\n", __FUNCTION__); + return -EAGAIN; + } + memcpy(msg, buffer, count); + msg[count] = 0; + +#ifdef CONFIG_IA64_SGI_SN1 + if ((result = elsc_display_line(l1, msg, line)) < 0) +#else + if ((result = elsc_display_line(get_nasid(), msg, line)) < 0) +#endif + { + printk(KERN_ERR "%s: elsc_display_line returned %d\n", + __FUNCTION__, result); + return -EIO; + } + kfree(msg); + return count; +} + +module_init(l1disp_init); +module_exit(l1disp_exit); diff -Nur linux-2.4.19/drivers/sgi/sn/mmtimer.c linux-2.4.19-sgi211r3/drivers/sgi/sn/mmtimer.c --- linux-2.4.19/drivers/sgi/sn/mmtimer.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/sgi/sn/mmtimer.c Thu Jan 9 10:30:30 2003 @@ -0,0 +1,307 @@ +/* + * Intel Multimedia Timer device implementation for SGI SN platforms. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. + * + * This driver implements a subset of the interface required by the + * IA-PC Multimedia Timers Draft Specification (rev. 0.97) from Intel. + * + * 11/01/01 - jbarnes - initial revision + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef MMTIMER_INTERRUPT_SUPPORT + +MODULE_AUTHOR("Jesse Barnes "); +MODULE_DESCRIPTION("Multimedia timer support"); +MODULE_LICENSE("GPL"); + +static int mmtimer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma); + +/* + * Period in femtoseconds (10^-15 s) + */ +static unsigned long mmtimer_femtoperiod = 0; + +static struct file_operations mmtimer_fops = { + owner: THIS_MODULE, + mmap: mmtimer_mmap, + ioctl: mmtimer_ioctl, +}; + +/* + * Comparators and their associated info. Bedrock has + * two comparison registers. + */ +#ifdef MMTIMER_INTERRUPT_SUPPORT +static mmtimer_t timers[] = { { SPIN_LOCK_UNLOCKED, 0, 0, + (unsigned long *)RTC_COMPARE_A_ADDR, 0 }, + { SPIN_LOCK_UNLOCKED, 0, 0, + (unsigned long *)RTC_COMPARE_B_ADDR, 0 } }; +#endif + +/** + * mmtimer_ioctl - ioctl interface for /dev/mmtimer + * @inode: inode of the device + * @file: file structure for the device + * @cmd: command to execute + * @arg: optional argument to command + * + * Executes the command specified by @cmd. Returns 0 for success, <0 for failure. + * Valid commands are + * + * %MMTIMER_GETOFFSET - Should return the offset (relative to the start + * of the page where the registers are mapped) for the counter in question. + * + * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15) + * seconds + * + * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address + * specified by @arg + * + * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter + * + * %MMTIMER_GETNUM - Returns the umber of comparators available + * + * %MMTIMER_MMAPAVAIL - Returns 1 if the registers can be mmap'd into userspace + * + * %MMTIMER_SETPERIODIC - Sets the comparator in question to the value specified. + * The interrupt handler will add the value specified to the comparator after a + * match. In this case, @arg is the address of a struct mmtimer_alarm. + * + * %MMTIMER_SETONESHOT - Like the above, but the comparator is not updated + * after the match. @arg is also the same as above. + * + * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it + * in the address specified by @arg. + */ +static int +mmtimer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + mmtimer_alarm_t alm; + unsigned long flags; + + switch (cmd) { + case MMTIMER_GETOFFSET: /* offset of the counter */ + /* + * SN RTC registers are on their own 64k page + */ + if(PAGE_SIZE <= (1 << 16)) + ret = (((long)RTC_COUNTER_ADDR) & (PAGE_SIZE-1)) / 8; + else + ret = -ENOSYS; + break; + + case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */ + if(copy_to_user((unsigned long *)arg, &mmtimer_femtoperiod, sizeof(unsigned long))) + return -EFAULT; + break; + + case MMTIMER_GETFREQ: /* frequency in Hz */ + if(copy_to_user((unsigned long *)arg, &sn_rtc_cycles_per_second, sizeof(unsigned long))) + return -EFAULT; + ret = 0; + break; + + case MMTIMER_GETBITS: /* number of bits in the clock */ + ret = RTC_BITS; + break; + + case MMTIMER_GETNUM: /* number of comparators available */ + ret = 1; + break; + + case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */ + ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0; + break; + + case MMTIMER_SETPERIODIC: /* set a periodically signalling timer */ +#ifdef MMTIMER_INTERRUPT_SUPPORT + if(copy_from_user(&alm, (mmtimer_alarm_t *)arg, sizeof(mmtimer_alarm_t))) + return -EFAULT; + if(alm.id < 0 || alm.id > NUM_COMPARATORS) { + if(timers[alm.id].process) { + ret = -EBUSY; + } + else { + spin_lock_irqsave(&timers[alm.id].timer_lock, flags); + timers[alm.id].periodic = 1; + *(timers[alm.id].compare) = alm.value; + timers[alm.id].process = current; + timers[alm.id].signo = alm.signo; + MMTIMER_ENABLE_INT(alm.id); + spin_unlock_irqrestore(&timers[alm.id].timer_lock, flags); + } + } + else +#endif /* MMTIMER_INTERRUPT_SUPPORT */ + ret = -ENOSYS; + break; + + case MMTIMER_SETONESHOT: /* set a one shot alarm */ +#ifdef MMTIMER_INTERRUPT_SUPPORT + if(copy_from_user(&alm, (mmtimer_alarm_t *)arg, sizeof(mmtimer_alarm_t))) + return -EFAULT; + if(alm.id != 0 || alm.id != 1) { + if(timers[alm.id].process) { + ret = -EBUSY; + } + else { + spin_lock_irqsave(&timers[alm.id].timer_lock, flags); + timers[alm.id].periodic = 0; + *(timers[alm.id].compare) = alm.value; + timers[alm.id].process = current; + timers[alm.id].signo = alm.signo; + MMTIMER_ENABLE_INT(alm.id); + spin_unlock_irqrestore(&timers[alm.id].timer_lock, flags); + } + } + else +#endif /* MMTIMER_INTERRUPT_SUPPORT */ + ret = -ENOSYS; + break; + + case MMTIMER_GETCOUNTER: + if(copy_to_user((unsigned long *)arg, RTC_COUNTER_ADDR, sizeof(unsigned long))) + return -EFAULT; + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} + +/** + * mmtimer_mmap - maps the clock's registers into userspace + * @file: file structure for the device + * @vma: VMA to map the registers into + * + * Calls remap_page_range() to map the clock's registers into + * the calling process' address space. + */ +static int +mmtimer_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long mmtimer_addr; + + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + + if (vma->vm_flags & VM_WRITE) + return -EPERM; + + if (PAGE_SIZE > (1 << 16)) + return -ENOSYS; + + vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED | VM_NONCACHED); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + mmtimer_addr = __pa(RTC_COUNTER_ADDR); + mmtimer_addr &= ~(PAGE_SIZE - 1); + mmtimer_addr &= 0xfffffffffffffffUL; + + if (remap_page_range(vma->vm_start, mmtimer_addr, PAGE_SIZE, vma->vm_page_prot)) { + printk(KERN_ERR "remap_page_range failed in mmtimer.c\n"); + return -EAGAIN; + } + + return 0; +} + +#ifdef MMTIMER_INTERRUPT_SUPPORT +/** + * mmtimer_interrupt - timer interrupt handler + * @irq: irq received + * @dev_id: device the irq came from + * @regs: register state upon receipt of the interrupt + * + * Called when one of the comarators matches the counter, this + * routine will send signals to processes that have requested + * them. + */ +static void +mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + int i; + + /* + * Do this once for each comparison register + */ + for(i = 0; i < NUM_COMPARATORS; i++) { + if(MMTIMER_INT_PENDING(i)) { + spin_lock_irqsave(&timers[i].timer_lock, flags); + force_sig(timers[i].signo, timers[i].process); + if(timers[i].periodic) + *(timers[i].compare) += timers[i].periodic; + else { + timers[i].process = 0; + MMTIMER_DISABLE_INT(i); + } + spin_unlock_irqrestore(&timers[i].timer_lock, flags); + } + } +} +#endif /* MMTIMER_INTERRUPT_SUPPORT */ + +/** + * mmtimer_init - device initialization routine + * + * Does initial setup for the mmtimer device. + */ +static int __init +mmtimer_init(void) +{ + devfs_handle_t hnd; + int irq; + + /* + * Sanity check the cycles/sec variable + */ + if (sn_rtc_cycles_per_second < 100000) { + printk(KERN_ERR "%s: unable to determine clock frequency\n", MMTIMER_NAME); + return -1; + } +#ifdef MMTIMER_INTERRUPT_SUPPORT + irq = 4; /* or whatever the RTC interrupt is */ + if(request_irq(irq, mmtimer_interrupt, SA_INTERRUPT, MMTIMER_NAME, NULL)) + return -1; +#endif /* MMTIMER_INTERRUPT_SUPPORT */ + + mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / 2) / + sn_rtc_cycles_per_second; + + if (!(hnd = devfs_register(NULL, MMTIMER_NAME, DEVFS_FL_AUTO_DEVNUM, + 0, 0, S_IFCHR | S_IRUGO, &mmtimer_fops, NULL))) { + printk(KERN_ERR "%s: failed to register device\n", MMTIMER_NAME); + return -1; + } + + printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION, sn_rtc_cycles_per_second/(unsigned long)1E6); + + return 0; +} + +module_init(mmtimer_init); + diff -Nur linux-2.4.19/drivers/sound/Config.in linux-2.4.19-sgi211r3/drivers/sound/Config.in --- linux-2.4.19/drivers/sound/Config.in Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/sound/Config.in Wed Oct 16 14:02:58 2002 @@ -30,6 +30,7 @@ fi fi fi +dep_tristate ' ForteMedia FM801 driver (EXPERIMENTAL)' CONFIG_SOUND_FORTE $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND $CONFIG_PCI dep_mbool ' Creative SBLive! MIDI' CONFIG_MIDI_EMU10K1 $CONFIG_SOUND_EMU10K1 $CONFIG_EXPERIMENTAL dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND $CONFIG_PCI diff -Nur linux-2.4.19/drivers/sound/Makefile linux-2.4.19-sgi211r3/drivers/sound/Makefile --- linux-2.4.19/drivers/sound/Makefile Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/sound/Makefile Wed Oct 16 14:02:58 2002 @@ -70,6 +70,7 @@ obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o +obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o diff -Nur linux-2.4.19/drivers/sound/forte.c linux-2.4.19-sgi211r3/drivers/sound/forte.c --- linux-2.4.19/drivers/sound/forte.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/sound/forte.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1956 @@ +/* + * forte.c - ForteMedia FM801 OSS Driver + * + * Written by Martin K. Petersen + * Copyright (C) 2002 Hewlett-Packard Company + * + * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers + * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik. Thanks + * guys! + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +/* + * TODO: + * MMIO + * Multichannelize + * Multichipify + * MPU401 + * M^Gameport + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "forte" +#define DRIVER_VERSION "$Id: forte.c,v 1.45 2002/08/01 22:34:09 mkp Exp $" +#define PFX DRIVER_NAME ": " + +#undef M_DEBUG + +#ifdef M_DEBUG +#define DPRINTK(args...) printk(KERN_WARNING args) +#else +#define DPRINTK(args...) +#endif + +/* Card capabilities */ +#define FORTE_CAPS (DSP_CAP_MMAP | DSP_CAP_TRIGGER) + +/* Supported audio formats */ +#define FORTE_FMTS (AFMT_U8 | AFMT_S16_LE) + +/* Buffers */ +#define FORTE_MIN_FRAG_SIZE 256 +#define FORTE_MAX_FRAG_SIZE PAGE_SIZE +#define FORTE_DEF_FRAG_SIZE 256 +#define FORTE_MIN_FRAGMENTS 16 +#define FORTE_MAX_FRAGMENTS 256 +#define FORTE_DEF_FRAGMENTS 16 +#define FORTE_MIN_BUF 16386 + +/* PCI BARs */ +#define FORTE_PCM_VOL 0x00 /* PCM Output Volume */ +#define FORTE_FM_VOL 0x02 /* FM Output Volume */ +#define FORTE_I2S_VOL 0x04 /* I2S Volume */ +#define FORTE_REC_SRC 0x06 /* Record Source */ +#define FORTE_PLY_CTRL 0x08 /* Playback Control */ +#define FORTE_PLY_COUNT 0x0a /* Playback Count */ +#define FORTE_PLY_BUF1 0x0c /* Playback Buffer I */ +#define FORTE_PLY_BUF2 0x10 /* Playback Buffer II */ +#define FORTE_CAP_CTRL 0x14 /* Capture Control */ +#define FORTE_CAP_COUNT 0x16 /* Capture Count */ +#define FORTE_CAP_BUF1 0x18 /* Capture Buffer I */ +#define FORTE_CAP_BUF2 0x1c /* Capture Buffer II */ +#define FORTE_CODEC_CTRL 0x22 /* Codec Control */ +#define FORTE_I2S_MODE 0x24 /* I2S Mode Control */ +#define FORTE_VOLUME 0x26 /* Volume Up/Down/Mute Status */ +#define FORTE_I2C_CTRL 0x29 /* I2C Control */ +#define FORTE_AC97_CMD 0x2a /* AC'97 Command */ +#define FORTE_AC97_DATA 0x2c /* AC'97 Data */ +#define FORTE_MPU401_DATA 0x30 /* MPU401 Data */ +#define FORTE_MPU401_CMD 0x31 /* MPU401 Command */ +#define FORTE_GPIO_CTRL 0x52 /* General Purpose I/O Control */ +#define FORTE_GEN_CTRL 0x54 /* General Control */ +#define FORTE_IRQ_MASK 0x56 /* Interrupt Mask */ +#define FORTE_IRQ_STATUS 0x5a /* Interrupt Status */ +#define FORTE_OPL3_BANK0 0x68 /* OPL3 Status Read / Bank 0 Write */ +#define FORTE_OPL3_DATA0 0x69 /* OPL3 Data 0 Write */ +#define FORTE_OPL3_BANK1 0x6a /* OPL3 Bank 1 Write */ +#define FORTE_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */ +#define FORTE_POWERDOWN 0x70 /* Blocks Power Down Control */ + +#define FORTE_CAP_OFFSET FORTE_CAP_CTRL - FORTE_PLY_CTRL + +#define FORTE_AC97_ADDR_SHIFT 10 + +/* Playback and record control register bits */ +#define FORTE_BUF1_LAST (1<<1) +#define FORTE_BUF2_LAST (1<<2) +#define FORTE_START (1<<5) +#define FORTE_PAUSE (1<<6) +#define FORTE_IMMED_STOP (1<<7) +#define FORTE_RATE_SHIFT 8 +#define FORTE_RATE_MASK (15 << FORTE_RATE_SHIFT) +#define FORTE_CHANNELS_4 (1<<12) /* Playback only */ +#define FORTE_CHANNELS_6 (2<<12) /* Playback only */ +#define FORTE_CHANNELS_6MS (3<<12) /* Playback only */ +#define FORTE_CHANNELS_MASK (3<<12) +#define FORTE_16BIT (1<<14) +#define FORTE_STEREO (1<<15) + +/* IRQ status bits */ +#define FORTE_IRQ_PLAYBACK (1<<8) +#define FORTE_IRQ_CAPTURE (1<<9) +#define FORTE_IRQ_VOLUME (1<<14) +#define FORTE_IRQ_MPU (1<<15) + +/* CODEC control */ +#define FORTE_CC_CODEC_RESET (1<<5) +#define FORTE_CC_AC97_RESET (1<<6) + +/* AC97 cmd */ +#define FORTE_AC97_WRITE (0<<7) +#define FORTE_AC97_READ (1<<7) +#define FORTE_AC97_DP_INVALID (0<<8) +#define FORTE_AC97_DP_VALID (1<<8) +#define FORTE_AC97_PORT_RDY (0<<9) +#define FORTE_AC97_PORT_BSY (1<<9) + + +struct forte_channel { + const char *name; + + unsigned short ctrl; /* Ctrl BAR contents */ + unsigned long iobase; /* Ctrl BAR address */ + + wait_queue_head_t wait; + + void *buf; /* Buffer */ + dma_addr_t buf_handle; /* Buffer handle */ + + unsigned int record; + unsigned int format; + unsigned int rate; + unsigned int stereo; + + unsigned int frag_sz; /* Current fragment size */ + unsigned int frag_num; /* Current # of fragments */ + unsigned int buf_sz; /* Current buffer size */ + + unsigned int hwptr; /* Tail */ + unsigned int swptr; /* Head */ + unsigned int filled_frags; /* Fragments currently full */ + unsigned int next_buf; /* Index of next buffer */ + + unsigned int blocked; /* Blocked on I/O */ + unsigned int drain; /* Drain queued buffers */ + unsigned int active; /* Channel currently in use */ + unsigned int mapped; /* mmap */ + + unsigned int buf_pages; /* Real size of buffer */ + unsigned int nr_irqs; /* Number of interrupts */ + unsigned int bytes; /* Total bytes */ +}; + + +struct forte_chip { + struct pci_dev *pci_dev; + unsigned long iobase; + int irq; + + struct semaphore open_sem; /* Device access */ + spinlock_t lock; /* State */ + + spinlock_t ac97_lock; + struct ac97_codec *ac97; + + int multichannel; + int dsp; /* OSS handle */ + int trigger; /* mmap I/O trigger */ + + struct forte_channel play; + struct forte_channel rec; +}; + + +static struct forte_chip *forte; +static int found; + + +/* AC97 Codec -------------------------------------------------------------- */ + + +/** + * forte_ac97_wait: + * @chip: fm801 instance whose AC97 codec to wait on + * + * FIXME: + * Stop busy-waiting + */ + +static inline int +forte_ac97_wait (struct forte_chip *chip) +{ + int i = 10000; + + while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY) + && i-- ) + ; + + return i == 0; +} + + +/** + * forte_ac97_read: + * @codec: AC97 codec to read from + * @reg: register to read + */ + +u16 +forte_ac97_read (struct ac97_codec *codec, u8 reg) +{ + u16 ret = 0; + struct forte_chip *chip = codec->private_data; + + spin_lock (&chip->ac97_lock); + + /* Knock, knock */ + if (forte_ac97_wait (chip)) { + printk (KERN_ERR PFX "ac97_read: Serial bus busy\n"); + goto out; + } + + /* Send read command */ + outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD); + + if (forte_ac97_wait (chip)) { + printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n", + reg); + goto out; + } + + /* Sanity checking */ + if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) { + printk (KERN_ERR PFX "ac97_read: Invalid data port"); + goto out; + } + + /* Fetch result */ + ret = inw (chip->iobase + FORTE_AC97_DATA); + + out: + spin_unlock (&chip->ac97_lock); + return ret; +} + + +/** + * forte_ac97_write: + * @codec: AC97 codec to send command to + * @reg: register to write + * @val: value to write + */ + +void +forte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val) +{ + struct forte_chip *chip = codec->private_data; + + spin_lock (&chip->ac97_lock); + + /* Knock, knock */ + if (forte_ac97_wait (chip)) { + printk (KERN_ERR PFX "ac97_write: Serial bus busy\n"); + goto out; + } + + outw (val, chip->iobase + FORTE_AC97_DATA); + outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD); + + /* Wait for completion */ + if (forte_ac97_wait (chip)) { + printk (KERN_ERR PFX "ac97_write: Bus busy after write\n"); + goto out; + } + + out: + spin_unlock (&chip->ac97_lock); +} + + +/* Mixer ------------------------------------------------------------------- */ + + +/** + * forte_mixer_open: + * @inode: + * @file: + */ + +static int +forte_mixer_open (struct inode *inode, struct file *file) +{ + struct forte_chip *chip = forte; + + MOD_INC_USE_COUNT; + + file->private_data = chip->ac97; + + return 0; +} + + +/** + * forte_mixer_release: + * @inode: + * @file: + */ + +static int +forte_mixer_release (struct inode *inode, struct file *file) +{ + /* We will welease Wodewick */ + MOD_DEC_USE_COUNT; + + return 0; +} + + +/** + * forte_mixer_ioctl: + * @inode: + * @file: + */ + +static int +forte_mixer_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *) file->private_data; + + return codec->mixer_ioctl (codec, cmd, arg); +} + + +static struct file_operations forte_mixer_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + ioctl: forte_mixer_ioctl, + open: forte_mixer_open, + release: forte_mixer_release, +}; + + +/* Channel ----------------------------------------------------------------- */ + +/** + * forte_channel_reset: + * @channel: Channel to reset + * + * Locking: Must be called with lock held. + */ + +static void +forte_channel_reset (struct forte_channel *channel) +{ + if (!channel || !channel->iobase) + return; + + DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name); + + channel->ctrl &= ~FORTE_START; + outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); + + /* We always play at least two fragments, hence these defaults */ + channel->hwptr = channel->frag_sz; + channel->next_buf = 1; + channel->swptr = 0; + channel->filled_frags = 0; + channel->blocked = 0; + channel->drain = 0; + channel->active = 0; + channel->bytes = 0; + channel->nr_irqs = 0; + channel->mapped = 0; +} + + +/** + * forte_channel_start: + * @channel: Channel to start (record/playback) + * + * Locking: Must be called with lock held. + */ + +static void inline +forte_channel_start (struct forte_channel *channel) +{ + if (!channel || !channel->iobase) + return; + + DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name); + + channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST); + channel->ctrl |= FORTE_START; + channel->active = 1; + outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); +} + + +/** + * forte_channel_stop: + * @channel: Channel to stop + * + * Locking: Must be called with lock held. + */ + +static void inline +forte_channel_stop (struct forte_channel *channel) +{ + if (!channel || !channel->iobase) + return; + + DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name); + + channel->ctrl &= ~FORTE_START; + channel->active = 0; + outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); +} + + +/** + * forte_channel_rate: + * @channel: Channel whose rate to set. Playback and record are + * independent. + * @rate: Channel rate in Hz + * + * Locking: Must be called with lock held. + */ + +static int +forte_channel_rate (struct forte_channel *channel, unsigned int rate) +{ + int new_rate, ret; + + if (!channel || !channel->iobase) + return -EINVAL; + + if (rate == 0 || channel->rate == rate) { + ret = channel->rate; + goto out; + } + + if (rate > 48000) + rate = 48000; + + if (rate < 5500) + rate = 5500; + + switch (rate) { + case 5500: new_rate = 0; break; + case 8000: new_rate = 1; break; + case 9600: new_rate = 2; break; + case 11025: new_rate = 3; break; + case 16000: new_rate = 4; break; + case 19200: new_rate = 5; break; + case 22050: new_rate = 6; break; + case 32000: new_rate = 7; break; + case 38400: new_rate = 8; break; + case 44100: new_rate = 9; break; + case 48000: new_rate = 10; break; + + default: + printk (KERN_ERR PFX "Unsupported rate: %d", rate); + ret = -EINVAL; + goto out; + } + + channel->ctrl &= ~FORTE_RATE_MASK; + channel->ctrl |= new_rate << FORTE_RATE_SHIFT; + channel->rate = ret = rate; + + out: + DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate); + + return ret; +} + + +/** + * forte_channel_format: + * @channel: Channel whose audio format to set + * @format: OSS format ID + * + * Locking: Must be called with lock held. + */ + +static int +forte_channel_format (struct forte_channel *channel, int format) +{ + int ret; + + if (!channel || !channel->iobase) + return -EINVAL; + + DPRINTK ("%s: %s format = %d\n", __FUNCTION__, channel->name, format); + + switch (format) { + + case AFMT_QUERY: + ret = channel->format; + break; + + case AFMT_U8: + channel->ctrl &= ~FORTE_16BIT; + channel->format = format; + ret = format; + break; + + case AFMT_S16_LE: + channel->ctrl |= FORTE_16BIT; + channel->format = format; + ret = format; + break; + + default: + printk (KERN_ERR PFX "Unsupported audio format"); + ret = -EINVAL; + break; + } + + return ret; +} + + +/** + * forte_channel_stereo: + * @channel: Channel to toggle + * @stereo: 0 for Mono, 1 for Stereo + * + * Locking: Must be called with lock held. + */ + +static int +forte_channel_stereo (struct forte_channel *channel, unsigned int stereo) +{ + int ret; + + if (!channel || !channel->iobase) + return -EINVAL; + + DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo); + + switch (stereo) { + + case 0: + channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK); + channel-> stereo = stereo; + ret = stereo; + break; + + case 1: + channel->ctrl &= ~FORTE_CHANNELS_MASK; + channel->ctrl |= FORTE_STEREO; + channel-> stereo = stereo; + ret = stereo; + break; + + default: + printk (KERN_ERR PFX "Unsupported channel format"); + ret = -EINVAL; + break; + } + + return ret; +} + + +/** + * forte_channel_buffer: + * @channel: Channel whose buffer to set up + * + * Locking: Must be called with lock held. + * + * FIXME: Buffer scaling dependent on rate/channels/bits + */ + +static void +forte_channel_buffer (struct forte_channel *channel, int sz, int num) +{ + /* Go away, I'm busy */ + if (channel->filled_frags || channel->bytes) + return; + + channel->frag_sz = sz; + channel->frag_num = num; + + if (channel->frag_sz < FORTE_MIN_FRAG_SIZE) + channel->frag_sz = FORTE_MIN_FRAG_SIZE; + + if (channel->frag_sz > FORTE_MAX_FRAG_SIZE) + channel->frag_sz = FORTE_MAX_FRAG_SIZE; + + if (channel->frag_num < FORTE_MIN_FRAGMENTS) + channel->frag_num = FORTE_MIN_FRAGMENTS; + + if (channel->frag_num > FORTE_MAX_FRAGMENTS) + channel->frag_num = FORTE_MAX_FRAGMENTS; + + if (channel->frag_sz * channel->frag_num < FORTE_MIN_BUF) + channel->frag_num = FORTE_MIN_BUF / channel->frag_sz; + + channel->buf_sz = channel->frag_sz * channel->frag_num; + + DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n", + __FUNCTION__, channel->name, channel->frag_sz, + channel->frag_num, channel->buf_sz); +} + + +/** + * forte_channel_prep: + * @channel: Channel whose buffer to prepare + * + * Locking: Lock held. + */ + +static void +forte_channel_prep (struct forte_channel *channel) +{ + struct page *page; + int i; + + if (channel->buf) + return; + + channel->buf_pages = channel->buf_sz >> PAGE_SHIFT; + + if (channel->buf_sz % PAGE_SIZE) + channel->buf_pages++; + + DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n", + __FUNCTION__, channel->name, channel->frag_sz, + channel->frag_num, channel->buf_sz, channel->buf_pages); + + /* DMA buffer */ + channel->buf = pci_alloc_consistent (forte->pci_dev, + channel->buf_pages * PAGE_SIZE, + &channel->buf_handle); + + page = virt_to_page (channel->buf); + + for (i = 0 ; i < channel->buf_pages ; i++) + mem_map_reserve (page++); + + if (!channel->buf || !channel->buf_handle) + BUG(); + + /* Prep buffer registers */ + outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT); + outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1); + outl (channel->buf_handle + channel->frag_sz, + channel->iobase + FORTE_PLY_BUF2); + + /* Reset hwptr */ + channel->hwptr = channel->frag_sz; + channel->next_buf = 1; + + DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name, + channel->buf, channel->buf_handle); +} + + +/** + * forte_channel_drain: + * @chip: + * @channel: + * + * Locking: Don't hold the lock. + */ + +static inline int +forte_channel_drain (struct forte_channel *channel) +{ + DECLARE_WAITQUEUE (wait, current); + unsigned long flags; + + if (!channel->active) + return 0; + + if (channel->mapped) { + spin_lock_irqsave (&forte->lock, flags); + forte_channel_stop (channel); + spin_unlock_irqrestore (&forte->lock, flags); + return 0; + } + + channel->drain = 1; + add_wait_queue (&channel->wait, &wait); + + for (;;) { + spin_lock_irqsave (&forte->lock, flags); + + if (channel->active == 0 || channel->filled_frags < 1) + break; + + spin_unlock_irqrestore (&forte->lock, flags); + __set_current_state (TASK_INTERRUPTIBLE); + schedule(); + } + + channel->drain = 0; + spin_unlock_irqrestore (&forte->lock, flags); + set_current_state (TASK_RUNNING); + remove_wait_queue (&channel->wait, &wait); + + return 0; +} + + +/** + * forte_channel_init: + * @chip: Forte chip instance the channel hangs off + * @channel: Channel to initialize + * + * Description: + * Initializes a channel, sets defaults, and allocates + * buffers. + * + * Locking: No lock held. + */ + +static int +forte_channel_init (struct forte_chip *chip, struct forte_channel *channel) +{ + DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase); + + spin_lock_irq (&chip->lock); + memset (channel, 0x0, sizeof (*channel)); + + if (channel == &chip->play) { + channel->name = "PCM_OUT"; + channel->iobase = chip->iobase; + DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__, + (void *) channel->iobase); + } + else if (channel == &chip->rec) { + channel->name = "PCM_IN"; + channel->iobase = chip->iobase + FORTE_CAP_OFFSET; + channel->record = 1; + DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__, + (void *) channel->iobase); + } + else + BUG(); + + init_waitqueue_head (&channel->wait); + + /* Defaults: 48kHz, 16-bit, mono */ + forte_channel_reset (channel); + forte_channel_stereo (channel, 0); + forte_channel_format (channel, AFMT_S16_LE); + forte_channel_rate (channel, 48000); + forte_channel_buffer (channel, FORTE_DEF_FRAG_SIZE, + FORTE_DEF_FRAGMENTS); + + chip->trigger = 0; + spin_unlock_irq (&chip->lock); + + return 0; +} + + +/** + * forte_channel_free: + * @chip: Chip this channel hangs off + * @channel: Channel to nuke + * + * Description: + * Resets channel and frees buffers. + * + * Locking: Hold your horses. + */ + +static void +forte_channel_free (struct forte_chip *chip, struct forte_channel *channel) +{ + DPRINTK ("%s: %s\n", __FUNCTION__, channel->name); + + if (!channel->buf_handle) + return; + + pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE, + channel->buf, channel->buf_handle); + + memset (channel, 0x0, sizeof (*channel)); +} + + +/* DSP --------------------------------------------------------------------- */ + + +/** + * forte_dsp_ioctl: + */ + +static int +forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ival, ret, rval, rd, wr, count; + unsigned long flags; + struct forte_chip *chip; + struct audio_buf_info abi; + struct count_info cinfo; + + chip = file->private_data; + + if (file->f_mode & FMODE_WRITE) + wr = 1; + else + wr = 0; + + if (file->f_mode & FMODE_READ) + rd = 1; + else + rd = 0; + + switch (cmd) { + + case OSS_GETVERSION: + return put_user (SOUND_VERSION, (int *) arg); + + case SNDCTL_DSP_GETCAPS: + DPRINTK ("%s: GETCAPS\n", __FUNCTION__); + + ival = FORTE_CAPS; /* DUPLEX */ + return put_user (ival, (int *) arg); + + case SNDCTL_DSP_GETFMTS: + DPRINTK ("%s: GETFMTS\n", __FUNCTION__); + + ival = FORTE_FMTS; /* U8, 16LE */ + return put_user (ival, (int *) arg); + + case SNDCTL_DSP_SETFMT: /* U8, 16LE */ + DPRINTK ("%s: SETFMT\n", __FUNCTION__); + + if (get_user (ival, (int *) arg)) + return -EFAULT; + + spin_lock_irq (&chip->lock); + + if (rd) { + forte_channel_stop (&chip->rec); + rval = forte_channel_format (&chip->rec, ival); + } + + if (wr) { + forte_channel_stop (&chip->rec); + rval = forte_channel_format (&chip->play, ival); + } + + spin_unlock_irq (&chip->lock); + + return put_user (rval, (int *) arg); + + case SNDCTL_DSP_STEREO: /* 0 - mono, 1 - stereo */ + DPRINTK ("%s: STEREO\n", __FUNCTION__); + + if (get_user (ival, (int *) arg)) + return -EFAULT; + + spin_lock_irq (&chip->lock); + + if (rd) { + forte_channel_stop (&chip->rec); + rval = forte_channel_stereo (&chip->rec, ival); + } + + if (wr) { + forte_channel_stop (&chip->rec); + rval = forte_channel_stereo (&chip->play, ival); + } + + spin_unlock_irq (&chip->lock); + + return put_user (rval, (int *) arg); + + case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */ + DPRINTK ("%s: CHANNELS\n", __FUNCTION__); + + if (get_user (ival, (int *) arg)) + return -EFAULT; + + spin_lock_irq (&chip->lock); + + if (rd) { + forte_channel_stop (&chip->rec); + rval = forte_channel_stereo (&chip->rec, ival-1) + 1; + } + + if (wr) { + forte_channel_stop (&chip->play); + rval = forte_channel_stereo (&chip->play, ival-1) + 1; + } + + spin_unlock_irq (&chip->lock); + + return put_user (rval, (int *) arg); + + case SNDCTL_DSP_SPEED: + DPRINTK ("%s: SPEED\n", __FUNCTION__); + + if (get_user (ival, (int *) arg)) + return -EFAULT; + + spin_lock_irq (&chip->lock); + + if (rd) { + forte_channel_stop (&chip->rec); + rval = forte_channel_rate (&chip->rec, ival); + } + + if (wr) { + forte_channel_stop (&chip->play); + rval = forte_channel_rate (&chip->play, ival); + } + + spin_unlock_irq (&chip->lock); + + return put_user(rval, (int*) arg); + + case SNDCTL_DSP_GETBLKSIZE: + DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__); + + spin_lock_irq (&chip->lock); + + if (rd) + ival = chip->rec.frag_sz; + + if (wr) + ival = chip->play.frag_sz; + + spin_unlock_irq (&chip->lock); + + return put_user (ival, (int *) arg); + + case SNDCTL_DSP_RESET: + DPRINTK ("%s: RESET\n", __FUNCTION__); + + spin_lock_irq (&chip->lock); + + if (rd) + forte_channel_reset (&chip->rec); + + if (wr) + forte_channel_reset (&chip->play); + + spin_unlock_irq (&chip->lock); + + return 0; + + case SNDCTL_DSP_SYNC: + DPRINTK ("%s: SYNC\n", __FUNCTION__); + + if (wr) { + ret = forte_channel_drain (&chip->play); + spin_lock_irq (&chip->lock); + forte_channel_reset (&chip->play); + spin_unlock_irq (&chip->lock); + } + + return 0; + + case SNDCTL_DSP_POST: + DPRINTK ("%s: POST\n", __FUNCTION__); + + if (wr) { + spin_lock_irq (&chip->lock); + forte_channel_reset (&chip->play); + spin_unlock_irq (&chip->lock); + } + + return 0; + + case SNDCTL_DSP_SETFRAGMENT: + DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__); + + if (get_user (ival, (int *) arg)) + return -EFAULT; + + spin_lock_irq (&chip->lock); + + if (rd) { + forte_channel_buffer (&chip->rec, ival & 0xffff, + (ival >> 16) & 0xffff); + ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz; + } + + if (wr) { + forte_channel_buffer (&chip->play, ival & 0xffff, + (ival >> 16) & 0xffff); + ival = (chip->play.frag_num << 16) +chip->play.frag_sz; + } + + spin_unlock_irq (&chip->lock); + + return put_user (ival, (int *) arg); + + case SNDCTL_DSP_GETISPACE: + DPRINTK ("%s: GETISPACE\n", __FUNCTION__); + + if (!rd) + return -EINVAL; + + spin_lock_irq (&chip->lock); + + abi.fragstotal = chip->rec.frag_num; + abi.fragsize = chip->rec.frag_sz; + + if (chip->rec.mapped) { + abi.fragments = chip->rec.frag_num - 2; + abi.bytes = abi.fragments * abi.fragsize; + } + else { + abi.fragments = chip->rec.filled_frags; + abi.bytes = abi.fragments * abi.fragsize; + } + + spin_unlock_irq (&chip->lock); + + return copy_to_user ((void *) arg, &abi, sizeof (abi)); + + case SNDCTL_DSP_GETIPTR: + DPRINTK ("%s: GETIPTR\n", __FUNCTION__); + + if (!rd) + return -EINVAL; + + spin_lock_irq (&chip->lock); + + if (chip->rec.active) + cinfo.ptr = chip->rec.hwptr; + else + cinfo.ptr = 0; + + cinfo.bytes = chip->rec.bytes; + cinfo.blocks = chip->rec.nr_irqs; + chip->rec.nr_irqs = 0; + + spin_unlock_irq (&chip->lock); + + return copy_to_user ((void *) arg, &cinfo, sizeof (cinfo)); + + case SNDCTL_DSP_GETOSPACE: + if (!wr) + return -EINVAL; + + spin_lock_irq (&chip->lock); + + abi.fragstotal = chip->play.frag_num; + abi.fragsize = chip->play.frag_sz; + + if (chip->play.mapped) { + abi.fragments = chip->play.frag_num - 2; + abi.bytes = chip->play.buf_sz; + } + else { + abi.fragments = chip->play.frag_num - + chip->play.filled_frags; + abi.bytes = abi.fragments * abi.fragsize; + } + + spin_unlock_irq (&chip->lock); + + return copy_to_user ((void *) arg, &abi, sizeof (abi)); + + case SNDCTL_DSP_GETOPTR: + if (!wr) + return -EINVAL; + + spin_lock_irq (&chip->lock); + + if (chip->play.active) + cinfo.ptr = chip->play.hwptr; + else + cinfo.ptr = 0; + + cinfo.bytes = chip->play.bytes; + cinfo.blocks = chip->play.nr_irqs; + chip->play.nr_irqs = 0; + + spin_unlock_irq (&chip->lock); + + return copy_to_user ((void *) arg, &cinfo, sizeof (cinfo)); + + case SNDCTL_DSP_GETODELAY: + if (!chip->play.active) + return 0; + + if (!wr) + return -EINVAL; + + spin_lock_irq (&chip->lock); + + if (chip->play.mapped) { + count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1; + ival = chip->play.frag_sz - count; + } + else { + ival = chip->play.filled_frags * chip->play.frag_sz; + } + + spin_unlock_irq (&chip->lock); + + return put_user (ival, (int *) arg); + + case SNDCTL_DSP_SETDUPLEX: + DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__); + + return -EINVAL; + + case SNDCTL_DSP_GETTRIGGER: + DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__); + + return put_user (chip->trigger, (int *) arg); + + case SNDCTL_DSP_SETTRIGGER: + + if (get_user (ival, (int *) arg)) + return -EFAULT; + + DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival); + + if (wr) { + spin_lock_irq (&chip->lock); + + if (ival & PCM_ENABLE_OUTPUT) + forte_channel_start (&chip->play); + else { + chip->trigger = 1; + forte_channel_prep (&chip->play); + forte_channel_stop (&chip->play); + } + + spin_unlock_irq (&chip->lock); + } + + return 0; + + default: + printk (KERN_ERR PFX "Unsupported ioctl: %x (%p)\n", cmd, + (void *) arg); + break; + } + + return -EINVAL; +} + + +/** + * forte_dsp_open: + */ + +static int +forte_dsp_open (struct inode *inode, struct file *file) +{ + struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */ + struct forte_channel *channel; + + if (down_interruptible (&chip->open_sem)) { + DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__); + return -ERESTARTSYS; + } + + file->private_data = forte; + + DPRINTK ("%s: chip @ %p\n", __FUNCTION__, file->private_data); + + if (file->f_mode & FMODE_WRITE) + forte_channel_init (forte, &forte->play); + + if (file->f_mode & FMODE_READ) + forte_channel_init (forte, &forte->rec); + + return 0; +} + + +/** + * forte_dsp_release: + */ + +static int +forte_dsp_release (struct inode *inode, struct file *file) +{ + struct forte_chip *chip = file->private_data; + int ret = 0; + + DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip); + + if (file->f_mode & FMODE_WRITE) { + forte_channel_drain (&chip->play); + + spin_lock_irq (&chip->lock); + + forte_channel_stop (&chip->play); + forte_channel_free (chip, &chip->play); + + spin_unlock_irq (&chip->lock); + } + + if (file->f_mode & FMODE_READ) { + while (chip->rec.filled_frags > 0) + interruptible_sleep_on (&chip->rec.wait); + + forte_channel_stop (&chip->rec); + forte_channel_free (chip, &chip->rec); + } + + out: + up (&chip->open_sem); + + return ret; +} + + +/** + * forte_dsp_poll: + * + * FIXME: Racy + */ + +static unsigned int +forte_dsp_poll (struct file *file, struct poll_table_struct *wait) +{ + struct forte_chip *chip; + struct forte_channel *channel; + unsigned int mask = 0; + + chip = file->private_data; + + if (file->f_mode & FMODE_WRITE) { + channel = &chip->play; + + if (channel->active) + poll_wait (file, &channel->wait, wait); + + if (channel->filled_frags) + mask |= POLLOUT | POLLWRNORM; + } + + if (file->f_mode & FMODE_READ) { + channel = &chip->rec; + + if (channel->active) + poll_wait (file, &channel->wait, wait); + + if (channel->filled_frags > 0) + mask |= POLLIN | POLLRDNORM; + } + + return mask; +} + + +/** + * forte_dsp_mmap: + */ + +static int +forte_dsp_mmap (struct file *file, struct vm_area_struct *vma) +{ + struct forte_chip *chip; + struct forte_channel *channel; + unsigned long size; + int ret; + + chip = file->private_data; + + DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__, + vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff); + + spin_lock_irq (&chip->lock); + + if (vma->vm_flags & VM_WRITE && chip->play.active) { + ret = -EBUSY; + goto out; + } + + if (vma->vm_flags & VM_READ && chip->rec.active) { + ret = -EBUSY; + goto out; + } + + if (file->f_mode & FMODE_WRITE) + channel = &chip->play; + else if (file->f_mode & FMODE_READ) + channel = &chip->rec; + else { + ret = -EINVAL; + goto out; + } + + forte_channel_prep (channel); + channel->mapped = 1; + + if (vma->vm_pgoff != 0) { + ret = -EINVAL; + goto out; + } + + size = vma->vm_end - vma->vm_start; + + if (size > channel->buf_pages * PAGE_SIZE) { + DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__, + size, channel->buf_sz); + ret = -EINVAL; + goto out; + } + + if (remap_page_range (vma->vm_start, virt_to_phys (channel->buf), + size, vma->vm_page_prot)) { + DPRINTK ("%s: remap el a no worko\n", __FUNCTION__); + ret = -EAGAIN; + goto out; + } + + ret = 0; + + out: + spin_unlock_irq (&chip->lock); + return ret; +} + + +/** + * forte_dsp_write: + */ + +static ssize_t +forte_dsp_write (struct file *file, const char *buffer, size_t bytes, + loff_t *ppos) +{ + struct forte_chip *chip; + struct forte_channel *channel; + unsigned int i = bytes, ret = 0, sz = 0; + unsigned long flags; + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!access_ok (VERIFY_READ, buffer, bytes)) + return -EFAULT; + + chip = (struct forte_chip *) file->private_data; + + if (!chip) + BUG(); + + channel = &chip->play; + + if (!channel) + BUG(); + + spin_lock_irqsave (&chip->lock, flags); + + /* Set up buffers with the right fragment size */ + forte_channel_prep (channel); + + while (i) { + /* All fragment buffers in use -> wait */ + if (channel->frag_num - channel->filled_frags == 0) { + DECLARE_WAITQUEUE (wait, current); + + /* For trigger mode operation, get out */ + if (chip->trigger) { + ret = -EAGAIN; + goto out; + } + + /* Otherwise wait for buffers */ + channel->blocked = 1; + add_wait_queue (&channel->wait, &wait); + + for (;;) { + if (channel->active == 0) + break; + + if (channel->frag_num - channel->filled_frags) + break; + + spin_unlock_irqrestore (&chip->lock, flags); + + set_current_state (TASK_INTERRUPTIBLE); + schedule(); + + spin_lock_irqsave (&chip->lock, flags); + } + + set_current_state (TASK_RUNNING); + remove_wait_queue (&channel->wait, &wait); + channel->blocked = 0; + } + + if (i > channel->frag_sz) + sz = channel->frag_sz; + else + sz = i; + + /* Clear the fragment so we don't get noise when copying + * smaller buffers + */ + memset ((void *) channel->buf + channel->swptr, 0x0, sz); + + if (copy_from_user ((void *) channel->buf + channel->swptr, + buffer, sz)) { + ret = -EFAULT; + goto out; + } + + /* Advance software pointer */ + buffer += sz; + channel->filled_frags++; + channel->swptr += channel->frag_sz; + channel->swptr %= channel->buf_sz; + i -= sz; + + /* If playback isn't active, start it */ + if (channel->active == 0 && chip->trigger == 0) + forte_channel_start (channel); + } + + ret = bytes - i; + + out: + spin_unlock_irqrestore (&chip->lock, flags); + return ret; +} + + +/** + * forte_dsp_read: + */ + +static ssize_t +forte_dsp_read (struct file *file, char *buffer, size_t bytes, + loff_t *ppos) +{ + struct forte_chip *chip; + struct forte_channel *channel; + unsigned int i = bytes, sz, ret; + unsigned long flags; + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!access_ok (VERIFY_WRITE, buffer, bytes)) + return -EFAULT; + + chip = (struct forte_chip *) file->private_data; + + if (!chip) + BUG(); + + channel = &chip->rec; + + if (!channel) + BUG(); + + spin_lock_irqsave (&chip->lock, flags); + + /* Set up buffers with the right fragment size */ + forte_channel_prep (channel); + + /* Start recording */ + forte_channel_start (channel); + + while (i) { + DPRINTK ("%s: i = %d\n", __FUNCTION__, i); + + /* No fragment buffers in use -> wait */ + if (channel->filled_frags == 0) { + DECLARE_WAITQUEUE (wait, current); + + channel->blocked = 1; + add_wait_queue (&channel->wait, &wait); + + for (;;) { + if (channel->active == 0) + break; + + if (channel->filled_frags) + break; + + spin_unlock_irqrestore (&chip->lock, flags); + + set_current_state (TASK_INTERRUPTIBLE); + schedule(); + + spin_lock_irqsave (&chip->lock, flags); + } + + set_current_state (TASK_RUNNING); + remove_wait_queue (&channel->wait, &wait); + channel->blocked = 0; + } + + if (i > channel->frag_sz) + sz = channel->frag_sz; + else + sz = i; + + if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) { + ret = -EFAULT; + DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__); + goto out; + } + + /* Advance software pointer */ + buffer += sz; + channel->filled_frags--; + channel->swptr += channel->frag_sz; + channel->swptr %= channel->buf_sz; + i -= sz; + + DPRINTK ("%s: filled_frags = %d, swptr = %x\n", __FUNCTION__, + channel->filled_frags, channel->swptr); + } + + ret = bytes - i; + + out: + spin_unlock_irqrestore (&chip->lock, flags); + return ret; +} + + +static struct file_operations forte_dsp_fops = { + owner: THIS_MODULE, + llseek: &no_llseek, +// read: &forte_dsp_read, + write: &forte_dsp_write, + poll: &forte_dsp_poll, + ioctl: &forte_dsp_ioctl, + open: &forte_dsp_open, + release: &forte_dsp_release, + mmap: &forte_dsp_mmap, +}; + + +/* Common ------------------------------------------------------------------ */ + + +/** + * forte_interrupt: + */ + +static void +forte_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + struct forte_chip *chip = dev_id; + struct forte_channel *channel = NULL; + u16 status, count; + + status = inw (chip->iobase + FORTE_IRQ_STATUS); + + /* If this is not for us, get outta here ASAP */ + if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0) + return; + + if (status & FORTE_IRQ_PLAYBACK) { + channel = &chip->play; + spin_lock_irq (&chip->lock); + + /* Declare a fragment done */ + channel->filled_frags--; + + /* Get # of completed bytes */ + count = inw (channel->iobase + FORTE_PLY_COUNT) + 1; + channel->bytes += count; + + if (count == 0) { + DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__, + channel->filled_frags); + channel->filled_frags = 0; + forte_channel_stop (channel); + goto pack; + } + + channel->nr_irqs++; + + /* Flip-flop between buffer I and II */ + channel->next_buf ^= 1; + + /* Advance hardware pointer by fragment size and wrap around */ + channel->hwptr += channel->frag_sz; + channel->hwptr %= channel->buf_sz; + + /* Buffer I or buffer II BAR */ + outl (channel->buf_handle + channel->hwptr, + channel->next_buf == 0 ? + channel->iobase + FORTE_PLY_BUF1 : + channel->iobase + FORTE_PLY_BUF2); + + /* If the currently playing fragment is last, schedule stop */ + if (channel->filled_frags == 1) + forte_channel_stop (channel); + pack: + /* Acknowledge interrupt */ + outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS); + + spin_unlock_irq (&chip->lock); + + if (channel->blocked || channel->drain) + wake_up_interruptible (&channel->wait); + } + + if (status & FORTE_IRQ_CAPTURE) { + channel = &chip->rec; + spin_lock_irq (&chip->lock); + + /* One fragment filled */ + channel->filled_frags++; + + DPRINTK ("%s: filled_frags = %d\n", __FUNCTION__, + channel->filled_frags); + + /* Get # of completed bytes */ + count = inw (channel->iobase + FORTE_PLY_COUNT) + 1; + + if (count == 0) { + DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__, + channel->filled_frags); + channel->filled_frags = 0; + goto rack; + } + + /* Buffer I or buffer II BAR */ + outl (channel->buf_handle + channel->hwptr, + channel->next_buf == 0 ? + channel->iobase + FORTE_PLY_BUF1 : + channel->iobase + FORTE_PLY_BUF2); + + /* Flip-flop between buffer I and II */ + channel->next_buf ^= 1; + + /* Advance hardware pointer by fragment size and wrap around */ + channel->hwptr += channel->frag_sz; + channel->hwptr %= channel->buf_sz; + + DPRINTK ("%s: hwptr = %x\n", __FUNCTION__, channel->hwptr); + + /* Out of buffers */ + if (channel->filled_frags == channel->frag_num - 1) + forte_channel_stop (channel); + rack: + /* Acknowledge interrupt */ + outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS); + + spin_unlock_irq (&chip->lock); + + if (channel->blocked) + wake_up_all (&channel->wait); + } + + return; +} + + +/** + * forte_chip_init: + * @chip: Chip instance to initialize + * + * Description: + * Resets chip, configures codec and registers the driver with + * the sound subsystem. + * + * Press and hold Start for 8 secs, then switch on Run + * and hold for 4 seconds. Let go of Start. Numbers + * assume a properly oiled TWG. + */ + +static int __devinit +forte_chip_init (struct forte_chip *chip) +{ + u8 revision; + u16 cmdw; + struct ac97_codec *codec; + + pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision); + + if (revision >= 0xB1) { + chip->multichannel = 1; + printk (KERN_INFO PFX "Multi-channel device detected.\n"); + } + + /* Reset chip */ + outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET, + chip->iobase + FORTE_CODEC_CTRL); + udelay(100); + outw (0, chip->iobase + FORTE_CODEC_CTRL); + + /* Request read from AC97 */ + outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT), + chip->iobase + FORTE_AC97_CMD); + mdelay(750); + + if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) { + printk (KERN_INFO PFX "AC97 codec not responding"); + return -EIO; + } + + /* Init volume */ + outw (0x0808, chip->iobase + FORTE_PCM_VOL); + outw (0x9f1f, chip->iobase + FORTE_FM_VOL); + outw (0x8808, chip->iobase + FORTE_I2S_VOL); + + /* I2S control - I2S mode */ + outw (0x0003, chip->iobase + FORTE_I2S_MODE); + + /* Interrupt setup - unmask PLAYBACK & CAPTURE */ + cmdw = inw (chip->iobase + FORTE_IRQ_MASK); + cmdw &= ~0x0003; + outw (cmdw, chip->iobase + FORTE_IRQ_MASK); + + /* Interrupt clear */ + outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE, + chip->iobase + FORTE_IRQ_STATUS); + + /* Set up the AC97 codec */ + if ((codec = kmalloc (sizeof (struct ac97_codec), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset (codec, 0, sizeof (struct ac97_codec)); + + codec->private_data = chip; + codec->codec_read = forte_ac97_read; + codec->codec_write = forte_ac97_write; + codec->id = 0; + + if (ac97_probe_codec (codec) == 0) { + printk(KERN_ERR PFX "codec probe failed\n"); + kfree (codec); + return -1; + } + + /* Register mixer */ + if ((codec->dev_mixer = + register_sound_mixer (&forte_mixer_fops, -1)) < 0) { + printk (KERN_ERR PFX "couldn't register mixer!\n"); + kfree (codec); + return -1; + } + + chip->ac97 = codec; + + /* Register DSP */ + if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) { + printk (KERN_ERR PFX "couldn't register dsp!\n"); + return -1; + } + + return 0; +} + + +/** + * forte_probe: + * @pci_dev: PCI struct for probed device + * @pci_id: + * + * Description: + * Allocates chip instance, I/O region, and IRQ + */ +static int __init +forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) +{ + struct forte_chip *chip; + int ret = 0; + + /* FIXME: Support more than one chip */ + if (found++) + return -EIO; + + /* Ignition */ + if (pci_enable_device (pci_dev)) + return -EIO; + + pci_set_master (pci_dev); + + /* Allocate chip instance and configure */ + forte = (struct forte_chip *) + kmalloc (sizeof (struct forte_chip), GFP_KERNEL); + chip = forte; + + if (chip == NULL) { + printk (KERN_WARNING PFX "Out of memory"); + return -ENOMEM; + } + + memset (chip, 0, sizeof (struct forte_chip)); + chip->pci_dev = pci_dev; + + init_MUTEX(&chip->open_sem); + spin_lock_init (&chip->lock); + spin_lock_init (&chip->ac97_lock); + + if (! request_region (pci_resource_start (pci_dev, 0), + pci_resource_len (pci_dev, 0), DRIVER_NAME)) { + printk (KERN_WARNING PFX "Unable to reserve I/O space"); + ret = -ENOMEM; + goto error; + } + + chip->iobase = pci_resource_start (pci_dev, 0); + chip->irq = pci_dev->irq; + + if (request_irq (chip->irq, forte_interrupt, SA_SHIRQ, DRIVER_NAME, + chip)) { + printk (KERN_WARNING PFX "Unable to reserve IRQ"); + ret = -EIO; + goto error; + } + + pci_set_drvdata (pci_dev, chip); + + printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%04lX IRQ %u\n", + chip->iobase, pci_resource_end (pci_dev, 0), chip->irq); + + /* Power it up */ + if ((ret = forte_chip_init (chip)) == 0) + return 0; + + error: + if (chip->irq) + free_irq (chip->irq, chip); + + if (chip->iobase) + release_region (pci_resource_start (pci_dev, 0), + pci_resource_len (pci_dev, 0)); + + kfree (chip); + + return ret; +} + + +/** + * forte_remove: + * @pci_dev: PCI device to unclaim + * + */ + +static void +forte_remove (struct pci_dev *pci_dev) +{ + struct forte_chip *chip = pci_get_drvdata (pci_dev); + + if (chip == NULL) + return; + + /* Turn volume down to avoid popping */ + outw (0x1f1f, chip->iobase + FORTE_PCM_VOL); + outw (0x1f1f, chip->iobase + FORTE_FM_VOL); + outw (0x1f1f, chip->iobase + FORTE_I2S_VOL); + + free_irq (chip->irq, chip); + release_region (chip->iobase, pci_resource_len (pci_dev, 0)); + + unregister_sound_dsp (chip->dsp); + unregister_sound_mixer (chip->ac97->dev_mixer); + + kfree (chip); + + printk (KERN_INFO PFX "driver released\n"); +} + + +static struct pci_device_id forte_pci_ids[] __devinitdata = { + { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, + { 0, } +}; + + +static struct pci_driver forte_pci_driver = { + name: DRIVER_NAME, + id_table: forte_pci_ids, + probe: forte_probe, + remove: forte_remove, + +}; + + +/** + * forte_init_module: + * + */ + +static int __init +forte_init_module (void) +{ + if (!pci_present()) + return -ENODEV; + + printk (KERN_INFO PFX DRIVER_VERSION "\n"); + + if (!pci_register_driver (&forte_pci_driver)) { + pci_unregister_driver (&forte_pci_driver); + return -ENODEV; + } + + return 0; +} + + +/** + * forte_cleanup_module: + * + */ + +static void __exit +forte_cleanup_module (void) +{ + pci_unregister_driver (&forte_pci_driver); +} + + +module_init(forte_init_module); +module_exit(forte_cleanup_module); + +MODULE_AUTHOR("Martin K. Petersen "); +MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE (pci, forte_pci_ids); diff -Nur linux-2.4.19/drivers/tc/lk201.h linux-2.4.19-sgi211r3/drivers/tc/lk201.h --- linux-2.4.19/drivers/tc/lk201.h Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/tc/lk201.h Wed Oct 16 14:02:58 2002 @@ -119,4 +119,4 @@ #define LK_STAT_PWRUP_KDOWN 0x3d /* a key was down during the test */ #define LK_STAT_PWRUP_ERROR 0x3e /* keyboard self test failure */ -extern unsigned char scancodeRemap[256]; +extern unsigned char scancodeRemap[256]; \ No newline at end of file diff -Nur linux-2.4.19/drivers/usb/devices.c linux-2.4.19-sgi211r3/drivers/usb/devices.c --- linux-2.4.19/drivers/usb/devices.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/usb/devices.c Mon Oct 28 20:43:23 2002 @@ -632,21 +632,26 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig) { + loff_t ret; + + lock_kernel(); + switch (orig) { case 0: file->f_pos = offset; - return file->f_pos; - + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return file->f_pos; - + ret = file->f_pos; + break; case 2: - return -EINVAL; - default: - return -EINVAL; + ret = -EINVAL; } + + unlock_kernel(); + return ret; } struct file_operations usbdevfs_devices_fops = { diff -Nur linux-2.4.19/drivers/usb/devio.c linux-2.4.19-sgi211r3/drivers/usb/devio.c --- linux-2.4.19/drivers/usb/devio.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/usb/devio.c Mon Oct 28 20:43:23 2002 @@ -57,21 +57,26 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) { + loff_t ret; + + lock_kernel(); + switch (orig) { case 0: file->f_pos = offset; - return file->f_pos; - + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return file->f_pos; - + ret = file->f_pos; + break; case 2: - return -EINVAL; - default: - return -EINVAL; + ret = -EINVAL; } + + unlock_kernel(); + return ret; } static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t *ppos) diff -Nur linux-2.4.19/drivers/usb/drivers.c linux-2.4.19-sgi211r3/drivers/usb/drivers.c --- linux-2.4.19/drivers/usb/drivers.c Wed Apr 26 15:22:55 2000 +++ linux-2.4.19-sgi211r3/drivers/usb/drivers.c Mon Oct 28 20:43:23 2002 @@ -38,6 +38,7 @@ #include #include #include +#include #include /*****************************************************************/ @@ -96,21 +97,24 @@ static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig) { + loff_t ret; + + lock_kernel(); switch (orig) { case 0: file->f_pos = offset; - return file->f_pos; - + ret = file->f_pos; + break; case 1: file->f_pos += offset; - return file->f_pos; - + ret = file->f_pos; + break; case 2: - return -EINVAL; - default: - return -EINVAL; + ret = -EINVAL; } + unlock_kernel(); + return ret; } struct file_operations usbdevfs_drivers_fops = { diff -Nur linux-2.4.19/drivers/usb/hid-core.c linux-2.4.19-sgi211r3/drivers/usb/hid-core.c --- linux-2.4.19/drivers/usb/hid-core.c Fri Aug 2 17:39:44 2002 +++ linux-2.4.19-sgi211r3/drivers/usb/hid-core.c Wed Oct 16 14:02:58 2002 @@ -57,6 +57,26 @@ #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik " #define DRIVER_DESC "USB HID support drivers" +#if defined(CONFIG_KDB_USB) +#include +extern struct kdb_usb_exchange kdb_usb_infos; +struct hid_device *hid_kbd = NULL; + +/* kdb_usb_hid_reset_timer + * This function reset the timer in the input_dev structure + * If you don't do that you'll be unable to exit KDB in the case + * you've entered by pressing the Pause key + */ +void hid_reset_timer(void) +{ + if(hid_kbd->input.timer.list.next) { + (hid_kbd->input.timer.list.next)->prev = hid_kbd->input.timer.list.prev; + (hid_kbd->input.timer.list.prev)->next = hid_kbd->input.timer.list.next; + hid_kbd->input.timer.list.prev = hid_kbd->input.timer.list.next = NULL; + } +} +#endif /* CONFIG_KDB_USB */ + static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; @@ -1277,7 +1297,16 @@ printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n", hid->version >> 8, hid->version & 0xff, c, hid->name, dev->bus->busnum, dev->devnum, ifnum); - +#if defined(CONFIG_KDB_USB) + /* Initialisation of the KDB structure */ + if (!strcmp(c, "Keyboard")) { + hid_kbd = hid; + kdb_usb_infos.urb = &hid->urb; + kdb_usb_infos.buffer = &hid->buffer[0]; + kdb_usb_infos.reset_timer = hid_reset_timer; + kdb_usb_infos.driver = HID_ACTIVE; + } +#endif return hid; } diff -Nur linux-2.4.19/drivers/usb/uhci-debug.h linux-2.4.19-sgi211r3/drivers/usb/uhci-debug.h --- linux-2.4.19/drivers/usb/uhci-debug.h Thu Nov 22 11:49:54 2001 +++ linux-2.4.19-sgi211r3/drivers/usb/uhci-debug.h Mon Oct 28 20:43:23 2002 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "uhci.h" @@ -507,8 +508,11 @@ static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence) { - struct uhci_proc *up = file->private_data; - loff_t new; + struct uhci_proc *up; + loff_t new = -1; + + lock_kernel(); + up = file->private_data; switch (whence) { case 0: @@ -517,12 +521,12 @@ case 1: new = file->f_pos + off; break; - case 2: - default: - return -EINVAL; } - if (new < 0 || new > up->size) + if (new < 0 || new > up->size) { + unlock_kernel(); return -EINVAL; + } + unlock_kernel(); return (file->f_pos = new); } diff -Nur linux-2.4.19/drivers/usb/usb-ohci.c linux-2.4.19-sgi211r3/drivers/usb/usb-ohci.c --- linux-2.4.19/drivers/usb/usb-ohci.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/drivers/usb/usb-ohci.c Wed Oct 16 14:02:58 2002 @@ -2355,21 +2355,22 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base) { ohci_t * ohci; + dma_addr_t bus_addr; ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL); if (!ohci) return NULL; - + memset (ohci, 0, sizeof (ohci_t)); - ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca, - &ohci->hcca_dma); + ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca, &bus_addr); if (!ohci->hcca) { kfree (ohci); return NULL; } memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + ohci->hcca_dma = bus_addr; ohci->disabled = 1; ohci->sleeping = 0; ohci->irq = -1; diff -Nur linux-2.4.19/drivers/usb/usb-uhci.c linux-2.4.19-sgi211r3/drivers/usb/usb-uhci.c --- linux-2.4.19/drivers/usb/usb-uhci.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/drivers/usb/usb-uhci.c Wed Oct 16 14:02:58 2002 @@ -40,7 +40,10 @@ #include #include #include - +#if defined(CONFIG_KDB_USB) +#include +extern struct kdb_usb_exchange kdb_usb_infos; +#endif /* This enables more detailed sanity checks in submit_iso */ //#define ISO_SANITY_CHECK @@ -132,6 +135,113 @@ /* used by userspace UHCI data structure dumper */ uhci_t **uhci_devices = &devs; +/* ------------------------------------------------------------------ */ +/* KDB part */ + +#if defined(CONFIG_KDB_USB) +/* +* The part of the code of UHCI controller that +* process the interrupt transfer +*/ + +void uhci_process_kdb_interrupt (uhci_t *s, urb_t *urb) +{ + int i, ret = -EINPROGRESS; + urb_priv_t *urb_priv = urb->hcpriv; + struct list_head *p = urb_priv->desc_list.next; + uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list); + + int actual_length; + int status = 0; + + for (i = 0; p != &urb_priv->desc_list; p = p->next, i++) // Maybe we allow more than one TD later ;-) + { + desc = list_entry (p, uhci_desc_t, desc_list); + + if (is_td_active(desc)) { + // do not process active TDs + //dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status)); + break; + } + + if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) { + // do not process one-shot TDs, no recycling + break; + } + // extract transfer parameters from TD + + actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status)); + status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe)); + + // see if EP is stalled + if (status == -EPIPE) { + // set up stalled condition + usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + } + + // if any error occurred: ignore this td, and continue + if (status != 0) { + //uhci_show_td (desc); + urb->error_count++; + goto recycle; + } + else + urb->actual_length = actual_length; + +recycle: + uhci_urb_dma_sync(s, urb, urb->hcpriv); + + if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) && + (urb->status != -ENOENT)) { + + urb->status = -EINPROGRESS; + + // Recycle INT-TD if interval!=0, else mark TD as one-shot + if (urb->interval) { + + desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE)); + if (status==0) { + desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE)); + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + } else { + desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE)); + } + desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | + (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27)); + mb(); + } else { + uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB); + // correct toggle after unlink + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + clr_td_ioc(desc); // inactivate TD + } + } + } +} + +/* uhci_kdb_poll + * This function is a minimalist version of the + * controller interrupt handler + */ +void uhci_kdb_poll (void *__uhci, urb_t *urb) +{ + uhci_t *s = __uhci; + unsigned int io_addr = s->io_addr; + unsigned short status; + + /* Reset input timer to be able to quit KDB */ + (*kdb_usb_infos.reset_timer)(); + + s->unlink_urb_done=0; + uhci_process_kdb_interrupt (s, urb); + + clean_descs(s, CLEAN_NOT_FORCED); + uhci_cleanup_unlink(s, CLEAN_NOT_FORCED); + uhci_switch_timer_int(s); +} +#endif /*-------------------------------------------------------------------*/ // Cleans up collected QHs, but not more than 100 in one go void clean_descs(uhci_t *s, int force) @@ -2933,6 +3043,10 @@ return -1; memset (s, 0, sizeof (uhci_t)); +#if defined(CONFIG_KDB_USB) + kdb_usb_infos.uhci = (void *)s; + kdb_usb_infos.poll_func = uhci_kdb_poll; +#endif INIT_LIST_HEAD (&s->free_desc); INIT_LIST_HEAD (&s->urb_list); INIT_LIST_HEAD (&s->urb_unlinked); diff -Nur linux-2.4.19/drivers/usb/usbkbd.c linux-2.4.19-sgi211r3/drivers/usb/usbkbd.c --- linux-2.4.19/drivers/usb/usbkbd.c Fri Sep 14 14:04:07 2001 +++ linux-2.4.19-sgi211r3/drivers/usb/usbkbd.c Tue Feb 4 15:36:30 2003 @@ -71,12 +71,34 @@ unsigned char new[8]; unsigned char old[8]; struct urb irq, led; - devrequest dr; + struct usb_ctrlrequest dr; unsigned char leds, newleds; char name[128]; int open; }; + +#if defined(CONFIG_KDB_USB) +#include +static struct usb_kbd *usb_kbd_ptr = NULL; +extern struct kdb_usb_exchange kdb_usb_infos; + +/* usb_kbd_reset_timer + * This function reset the timer in the input_dev structure + * If you don't do that you'll be unable to exit KDB in the case + * you've entered by pressing the Pause key + */ + +void usb_kbd_reset_timer(void) +{ + if(usb_kbd_ptr->dev.timer.list.next) { + (usb_kbd_ptr->dev.timer.list.next)->prev = usb_kbd_ptr->dev.timer.list.prev; + (usb_kbd_ptr->dev.timer.list.prev)->next = usb_kbd_ptr->dev.timer.list.next; + usb_kbd_ptr->dev.timer.list.prev = usb_kbd_ptr->dev.timer.list.next = NULL; + } +} +#endif /* CONFIG_KDB_USB */ + static void usb_kbd_irq(struct urb *urb) { struct usb_kbd *kbd = urb->context; @@ -214,7 +236,14 @@ FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, usb_kbd_irq, kbd, endpoint->bInterval); - +#if defined(CONFIG_KDB_USB) + /* Init the KDB structure */ + usb_kbd_ptr = kbd; + kdb_usb_infos.urb = &kbd->irq; + kdb_usb_infos.buffer = &kbd->new[0]; + kdb_usb_infos.reset_timer = usb_kbd_reset_timer; + kdb_usb_infos.driver = USB_KBD_ACTIVE; +#endif /* CONFIG_KDB_USB */ kbd->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; kbd->dr.request = USB_REQ_SET_REPORT; kbd->dr.value = 0x200; diff -Nur linux-2.4.19/drivers/video/radeonfb.c linux-2.4.19-sgi211r3/drivers/video/radeonfb.c --- linux-2.4.19/drivers/video/radeonfb.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/drivers/video/radeonfb.c Wed Oct 16 14:02:58 2002 @@ -258,8 +258,8 @@ u32 mmio_base_phys; u32 fb_base_phys; - u32 mmio_base; - u32 fb_base; + void *mmio_base; + void *fb_base; struct pci_dev *pdev; @@ -800,8 +800,7 @@ } /* map the regions */ - rinfo->mmio_base = (u32) ioremap (rinfo->mmio_base_phys, - RADEON_REGSIZE); + rinfo->mmio_base = ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE); if (!rinfo->mmio_base) { printk ("radeonfb: cannot map MMIO\n"); release_mem_region (rinfo->mmio_base_phys, @@ -947,8 +946,7 @@ } } - rinfo->fb_base = (u32) ioremap (rinfo->fb_base_phys, - rinfo->video_ram); + rinfo->fb_base = ioremap (rinfo->fb_base_phys, rinfo->video_ram); if (!rinfo->fb_base) { printk ("radeonfb: cannot map FB\n"); iounmap ((void*)rinfo->mmio_base); @@ -1692,7 +1690,7 @@ disp->dispsw_data = NULL; - disp->screen_base = (char*)rinfo->fb_base; + disp->screen_base = rinfo->fb_base; disp->type = FB_TYPE_PACKED_PIXELS; disp->type_aux = 0; disp->ypanstep = 1; diff -Nur linux-2.4.19/drivers/video/riva/fbdev.c linux-2.4.19-sgi211r3/drivers/video/riva/fbdev.c --- linux-2.4.19/drivers/video/riva/fbdev.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/drivers/video/riva/fbdev.c Wed Oct 16 14:02:58 2002 @@ -140,7 +140,8 @@ CH_GEFORCE3, CH_GEFORCE3_1, CH_GEFORCE3_2, - CH_QUADRO_DDC + CH_QUADRO_DDC, + CH_QUADRO4 }; /* directly indexed by riva_chips enum, above */ @@ -167,7 +168,10 @@ { "GeForce3", NV_ARCH_20}, { "GeForce3 Ti 200", NV_ARCH_20}, { "GeForce3 Ti 500", NV_ARCH_20}, - { "Quadro DDC", NV_ARCH_20} + { "Quadro DDC", NV_ARCH_20}, +#if 0 + { "Quadro4", NV_ARCH_25}, /* doesn't work properly yet... */ +#endif }; static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { @@ -215,6 +219,10 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC }, +#if 0 + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4, /* doesn't work properly yet... */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4 }, +#endif { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); diff -Nur linux-2.4.19/drivers/xscsi/Config.in linux-2.4.19-sgi211r3/drivers/xscsi/Config.in --- linux-2.4.19/drivers/xscsi/Config.in Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/Config.in Thu Feb 20 19:55:58 2003 @@ -0,0 +1,12 @@ +# +# Alternate SCSI configuration +# +comment 'Alternate SCSI support' +bool 'SCSI disk support' CONFIG_XSCSI_DKSC +bool 'Alternate CDROM support' CONFIG_XSCSI_MMSC +bool ' Alternate Qlogic ISP FC SCSI support' CONFIG_XSCSI_QLFC +dep_tristate ' Qlogic ISP FC KDB functions' CONFIG_XSCSI_QLFC_KDB $CONFIG_XSCSI_QLFC $CONFIG_KDB +tristate ' Alternate Qlogic QLA 1280 SCSI support' CONFIG_XSCSI_QL +dep_tristate ' Qlogic SCSI KDB functions' CONFIG_XSCSI_QL_KDB $CONFIG_XSCSI_QL $CONFIG_KDB +dep_bool 'Alternate IDE CDROM support' CONFIG_XSCSI_IDE $CONFIG_XSCSI_MMSC +dep_bool 'Alternate IDE CDROM Debug support' CONFIG_XSCSI_IDE_KDB $CONFIG_XSCSI_IDE $CONFIG_KDB diff -Nur linux-2.4.19/drivers/xscsi/Makefile linux-2.4.19-sgi211r3/drivers/xscsi/Makefile --- linux-2.4.19/drivers/xscsi/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/Makefile Thu Feb 20 19:55:58 2003 @@ -0,0 +1,126 @@ +# +# Makefile for alternative SCSI. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/NoticeExplan + + +EXTRA_INCLUDE_DIRECTORIES = -I. -I $(TOPDIR)/include/linux/xscsi -I $(TOPDIR)/arch/$(ARCH)/kdb +EXTRA_CFLAGS += $(EXTRA_INCLUDE_DIRECTORIES) + +O_OBJS := +OX_OBJS := +M_OBJS := +MX_OBJS := + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := xscsidrv.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := xscsi_syms.o xfailover.o +ifeq "$(CONFIG_XSCSI_QLFC)" "y" + export-objs += qlfc.o +endif +list-multi := xscsi_mod.o qlfc_mod.o ql_mod.o ide_mod.o + +CFLAGS_qlfc.o += -Wno-unknown-pragmas +CFLAGS_dksc.o += -Wno-uninitialized +CFLAGS_ql.o += -Wno-uninitialized + +obj-$(CONFIG_XSCSI) += xscsi_mod.o xscsi_syms.o + +obj-$(CONFIG_XSCSI_DKSC) += dksc.o xfailover.o +obj-$(CONFIG_XSCSI_MMSC) += mmsc.o +obj-$(CONFIG_XSCSI_QL) += ql_mod.o +obj-$(CONFIG_XSCSI_QL_KDB) += qlidbg.o +obj-$(CONFIG_XSCSI_QLFC) += qlfc_mod.o +obj-$(CONFIG_XSCSI_QLFC_KDB) += qlfc_idbg.o +obj-$(CONFIG_XSCSI_IDE) += ide_mod.o +obj-$(CONFIG_XSCSI_IDE_KDB) += ide_idbg.o + +xscsi_mod-objs := xscsi.o xscsids.o xscsiha.o +qlfc_mod-objs := qlfc.o ql2200_fw.o ql2300_fw.o osdep_linux.o +ql_mod-objs := ql.o osdep_linux.o +ide_mod-objs := ide.o osdep_linux.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(foreach m, $(multi-y), $($(basename $(m))-objs)) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +include $(TOPDIR)/Rules.make + +xscsi_mod.o: $(xscsi_mod-objs) + $(LD) -r -o $@ $(xscsi_mod-objs) + +qlfc_mod.o: $(qlfc_mod-objs) + $(LD) -r -o $@ $(qlfc_mod-objs) + +ql_mod.o: $(ql_mod-objs) + $(LD) -r -o $@ $(ql_mod-objs) + +ide_mod.o: $(ide_mod-objs) + $(LD) -r -o $@ $(ide_mod-objs) + +fastdep: diff -Nur linux-2.4.19/drivers/xscsi/dksc.c linux-2.4.19-sgi211r3/drivers/xscsi/dksc.c --- linux-2.4.19/drivers/xscsi/dksc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/dksc.c Wed Jan 29 23:58:17 2003 @@ -0,0 +1,3792 @@ + +/* + * + * + * Copyright (c) 1986-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +#define DKSC_EVENT_LOG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_DUMP +#include +#endif + +#include +#include + +#include "alenlist.h" +#include "xscsi.h" +#include "dksc.h" +#include "xfailover.h" +#include "dvh.h" + +#define DKSC_SARD 1 +#define DKSC_READV_WRITEV 0 + +/* + * For the allocated requests. + */ + +static kmem_cache_t *dkrequest_cachep; + + +#define DK_SETS 64 + +#define DK_DISK_SHIFT 4 +#define DK_DISK_SIZE (1UL << DK_DISK_SHIFT) +#define DK_DISK_MASK (~(DK_DISK_SIZE - 1)) + +#define DK_SET_SHIFT (DK_DISK_SHIFT + 4) +#define DK_SET_SIZE (1UL << DK_SET_SHIFT) +#define DK_SET_MASK (~(DK_SET_SIZE - 1)) + +#define DK_SET(info) (((struct dk_setinfo **) (info)) - dk_setinfo) +#define DK_MINOR(drive, part) (((drive) << DK_DISK_SHIFT) + (part)) + +static spinlock_t dk_disk_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(dk_disk_list); + +static struct dk_setinfo { + struct gendisk *gdev; + struct hd_struct hd[1 << DK_SET_SHIFT]; + devfs_handle_t disks[1 << (DK_SET_SHIFT - DK_DISK_SHIFT)]; + int blksize[1 << 8]; + int blksize_size[1 << 8]; + int hardsect_size[1 << 8]; + int setnum; + int major; + unsigned short inuse; /* bitfield of used drives */ +} *dk_setinfo[DK_SETS]; + +devfs_handle_t dksc_de[256][1 << (MINORBITS - DK_DISK_SHIFT)]; + +struct dk_partinfo { + struct dk_diskinfo *diskinfo; + devfs_handle_t de; + devfs_handle_t de_compat; + int part; +}; + +struct dk_diskinfo { + struct dksoftc *softc; + struct dk_setinfo *setinfo; + scsi_lun_info_t *luninfo; + struct list_head list; + int pending; /* pending for part check */ + int drive; /* index (0-15) in set */ + struct semaphore sema; + struct dk_partinfo *parts[1 << DK_DISK_SHIFT]; +}; + +static unsigned char dk_read[10] = { [0] = 0x28 }; +static unsigned char dk_write[10] = { [0] = 0x2a }; +static unsigned char dk_readcapacity[10] = { [0] = 0x25 }; +static unsigned char dk_tst_unit_rdy[6]; +static unsigned char dk_mode_sense[6] = { [0] = 0x1a }; +static unsigned char dk_startunit[6] = { [0] = 0x1b, [4] = 1 }; + +#if defined(INDUCE_IO_ERROR) +/* + * To induce I/O error, set insert_error to 1, and error_dev to the dev_t. + * This is mainly used for XFS filesystem error handling testing. + */ +int dksc_insert_error = 0; /* whether to enable fault insertion. */ +dev_t dksc_error_dev = 0; /* device to fail */ +int dksc_error_freq = 20; /* frequency at which errors are induced */ + +int dksc_error_count = 0; /* counter to determine which request to + fail (if xlv_insert_error is 1). */ +#endif + +/* + * The basic timeout for the disk driver. Note that it is long to handle + * many units active at same time, with possible disconnects during commands. + */ +#define DKSC_TIMEOUT (60 * HZ) + +/* Maximum number of retries on a failed request */ +#define DK_MAX_RETRY 15 +/* retry on BUSY long enough to allow up to 4 minutes; same as startunit */ +#define DK_MAX_BUSY 16 +#define DK_MAX_BUSY_INTV 16 + +/* Size of a physical disk block (default, if can't get) */ +#ifndef BBSIZE +#define BBSIZE 512 +#endif +#define DK_BLK_SZ BBSIZE + +/* + * The default max queue per disk + */ +#define DFMAXQ 4 +#define DFMAX_READ_BLOCKS 2048 +#define DFMAX_WRITE_BLOCKS 2048 + +/* + * Number of requests. The number of requests that can be queued at + * the same time. + */ +#define DK_NR_REQUESTS 4 +#define DK_MAX_REQUESTS 1025 +#define DK_MAX_REQISSUE 768 + +static void dk_intr(scsi_request_t *); +static int dk_chkcond(struct dksoftc *, scsi_request_t *, int, int); +static void dk_do_retry(scsi_request_t *); +static unsigned int dk_readcap(struct dksoftc *); +static int dk_cmd(struct dksoftc *dk, u_char *cmd_buffer, int cmd_size, + u_int timeoutval, caddr_t addr, size_t len, int rw); +static void dk_checkqueue(struct dksoftc *); +static int dk_getblksz(struct dksoftc *dk); +static void dksc_start(struct dksoftc *, struct dkrequest *, scsi_request_t *); +static void dk_print_sense(struct dksoftc *dk, struct scsi_request *sp, int part); +static struct dkrequest * dk_get_request(struct dksoftc *, int); +static void dk_unalloc_softc(struct dksoftc *dk); +static void dk_callback_frontend(vertex_hdl_t lun_vhdl, uint8_t *sense); +static int dk_callback_backend(register struct dksoftc *dk, int wait); +static void dk_callback_intr(scsi_request_t *); +#ifndef DEBUG +static int dk_user_printable_sense(struct dksoftc *, register scsi_request_t *, int); +#endif +static int dksc_request(request_queue_t *, int, struct buffer_head *); +static int dksc_strategy(struct dksoftc *, int, int, struct buffer_head *, + struct kiobuf *, unsigned int, unsigned int); +static void dksc_unplug(struct dksoftc *); +static void dk_part_remove(struct dk_diskinfo *diskinfo, int i); + +#if CONFIG_DUMP +static int dksc_dump_notify(struct notifier_block *, unsigned long, void *); + +static struct notifier_block dksc_dump_notifier = { + dksc_dump_notify, + NULL, + 0 +}; +#endif + +#if DKSC_EVENT_LOG +static int dksc_event_level = 4; +void +dksc_event_log(int level, struct dksoftc *dk, char *string, unsigned int value1, unsigned int value2) +{ + int i = dk->dk_event_rotor; + + if (level < dksc_event_level) + return; + if (++dk->dk_event_rotor == DKSC_EVENT_LOG_SIZE) + dk->dk_event_rotor = 0; + dk->dk_event_buffer[i].string = string; + dk->dk_event_buffer[i].aval = value1; + dk->dk_event_buffer[i].bval = value2; +} +#else +#define dksc_event_log(l, d, a, b, c) +#endif + + +#ifdef DEBUG +#define dk_dbg_pmsg(dev, part, fmt...) dk_pmsg(dev, part, ## fmt) +#else +#define dk_dbg_pmsg(dev, part, fmt...) +#endif + +#if BITS_PER_LONG == 64 +#define LLP "%lx" +#else +#define LLP "%Lx" +#endif + + +#ifdef CONFIG_PROC_FS +int +dksc_proc_info(char *buffer, char **start, off_t offset, int length) +{ + struct list_head *entry; + int size, len; + off_t begin = 0; + off_t pos = 0; + + spin_lock(&dk_disk_lock); + + len = 0; + list_for_each(entry, &dk_disk_list) { + struct dk_diskinfo *diskinfo; + scsi_lun_info_t *luninfo; + scsi_targ_info_t *targinfo; + scsi_ctlr_info_t *ctlrinfo; + struct dksoftc *dk; + + diskinfo = list_entry(entry, struct dk_diskinfo, list); + luninfo = diskinfo->luninfo; + targinfo = SLI_TARG_INFO(luninfo); + ctlrinfo = STI_CTLR_INFO(targinfo); + + if (STI_NODE(targinfo) == 0) + size = sprintf(buffer + len, + "%s/target%d/lun%d", + devfs_get_name(ctlrinfo->sci_ctlr_vhdl, NULL), + STI_TARG(targinfo), + SLI_LUN(luninfo)); + else + size = sprintf(buffer + len, + "%s/node"LLP"/port"LLP"/lun%d", + devfs_get_name(ctlrinfo->sci_ctlr_vhdl, NULL), + STI_NODE(targinfo), STI_PORT(targinfo), + SLI_LUN(luninfo)); + len += size; + + size = sprintf(buffer + len, " %s %s", + SLI_VENDOR_ID(luninfo), SLI_PRODUCT_ID(luninfo)); + len += size; + + dk = diskinfo->softc; + if (dk != NULL) + size = sprintf(buffer + len, " %d GB\n", + dk->dk_drivecap / 1953125); + else + size = sprintf(buffer + len, "\n"); + len += size; + + pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + break; + } + spin_unlock(&dk_disk_lock); + + *start = buffer + (offset - begin); + len -= (offset - begin); + if (len > length) + len = length; + return len; +} + + +static void +dksc_proc_init(void) +{ + struct proc_dir_entry *generic; + + generic = create_proc_info_entry("xscsi/dksc", 0, 0, dksc_proc_info); + if (!generic) + printk(KERN_ERR "cannot init /proc/xscsi/dksc\n"); +} +#else +#define dksc_proc_init() +#endif + +static void +dk_pmsg(struct dksoftc *dk, int part, char *fmt, ...) +{ + va_list ap; + char message[256]; + int pos; + devfs_handle_t devhdl; + int drive; + + drive = dk->dk_disk_info->drive; + devhdl = dk->dk_disk_info->setinfo->hd[DK_MINOR(drive, part)].de; + + if (devhdl == NULL) + devhdl = dk->dk_disk_info->parts[0]->de; + pos = devfs_generate_path(devhdl, message, sizeof(message)); + if (pos < 0) + printk("drive %d: ", drive); + else + printk("%s: ", &message[pos]); + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end(ap); + printk("%s", message); +} + +static struct gendisk dk_gendisk[]; +static request_queue_t *dk_get_queue(kdev_t dev); +static struct block_device_operations dksc_blk_ops; + +static struct dk_setinfo * +dk_drivealloc(int *major, int *drive) +{ + static int sets; + int set; + int err; + + for (set = 0; set < sets; set++) { + if (~dk_setinfo[set]->inuse & 0xffff) { + *drive = ffz(dk_setinfo[set]->inuse); + *major = dk_setinfo[set]->major; + set_bit(*drive, &dk_setinfo[set]->inuse); + return dk_setinfo[set]; + } + } + + if (!(sets < DK_SETS)) { + printk("No available majors!\n"); + return NULL; + } + + *major = devfs_alloc_major(DEVFS_SPECIAL_BLK); + *drive = 0; + + dk_setinfo[set] = kmalloc(sizeof(struct dk_setinfo), GFP_KERNEL); + if (!dk_setinfo[set]) + return NULL; + memset(dk_setinfo[set], 0, sizeof(struct dk_setinfo)); + + err = register_blkdev(*major, "dksc", &dksc_blk_ops); + if (err) { + kfree(dk_setinfo[set]); + dk_setinfo[set] = NULL; + return NULL; + } + + set_bit(*drive, &dk_setinfo[set]->inuse); + dk_setinfo[set]->major = *major; + dk_setinfo[set]->setnum = set; + + dk_setinfo[set]->gdev = &dk_gendisk[set]; + dk_gendisk[set].major = *major; + dk_gendisk[set].part = dk_setinfo[set]->hd; + dk_gendisk[set].sizes = dk_setinfo[set]->blksize; + dk_gendisk[set].de_arr = dk_setinfo[set]->disks; + dk_gendisk[set].nr_real = DK_SET_SIZE / DK_DISK_SIZE; + blk_dev[*major].queue = dk_get_queue; + blksize_size[*major] = dk_setinfo[set]->blksize_size; + hardsect_size[*major] = dk_setinfo[set]->hardsect_size; + + sets++; + + return dk_setinfo[set]; +} + +static void +dk_drivefree(struct dk_setinfo *setinfo, int drive) +{ + clear_bit(drive, &setinfo->inuse); +} + +extern struct file_operations dksc_char_ops; + +/* + * Allocate disk info and create disc block and raw vertices. + */ +void * +dksc_disk_add(vertex_hdl_t lun_vhdl) +{ + devfs_handle_t disc; + devfs_handle_t rdisc; + struct dk_diskinfo *diskinfo; + struct dk_partinfo *partinfo; + struct dk_setinfo *setinfo; + int major; + int minor; + int drive; + + disc = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + if (disc) { + partinfo = devfs_get_info(disc); + if (partinfo) + return partinfo->diskinfo; + } + + spin_lock(&dk_disk_lock); + setinfo = dk_drivealloc(&major, &drive); + spin_unlock(&dk_disk_lock); + if (!setinfo) + return NULL; + + minor = DK_MINOR(drive, 0); + + partinfo = kmem_zalloc(sizeof(*partinfo), KM_SLEEP); + if (!partinfo) + goto out1; + diskinfo = kmem_zalloc(sizeof(*diskinfo), KM_SLEEP); + if (!diskinfo) + goto out2; + + diskinfo->luninfo = devfs_get_info(lun_vhdl); + diskinfo->setinfo = setinfo; + diskinfo->drive = drive; + diskinfo->parts[0] = partinfo; + sema_init(&diskinfo->sema, 1); + + partinfo->diskinfo = diskinfo; + partinfo->part = 0; + + disc = devfs_register(lun_vhdl, "disc", DEVFS_FL_DEFAULT, + major, minor, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) get_blkfops(major), partinfo); + if (disc == NULL) + goto out3; + + rdisc = devfs_register(lun_vhdl, "rdisc", DEVFS_FL_DEFAULT, + 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) &dksc_char_ops, partinfo); + if (rdisc == NULL) + goto out4; + +#ifndef CONFIG_BLK_DEV_SD + { + int drivenum; + char drivename[8]; + char fullpath[128]; + char firstletter; + char secondletter; + + drivenum = (setinfo->setnum << DK_DISK_SHIFT) + diskinfo->drive; + + if (drivenum < 128) /* # disks that Redhat supports */ { + secondletter = (char) (drivenum % 26) + 'a'; + if (drivenum >= 26) { + firstletter = (char) (drivenum / 26) + 'a' - 1; + sprintf(drivename, "sd%c%c", firstletter, secondletter); + } + else + sprintf(drivename, "sd%c", secondletter); + drivenum = devfs_generate_path(disc, fullpath, 128); + devfs_mk_symlink(NULL, drivename, DEVFS_FL_DEFAULT, + &fullpath[drivenum], &partinfo->de_compat, NULL); + } + } +#endif + + partinfo->de = disc; + dksc_de[major][drive] = disc; + devfs_auto_unregister(disc, rdisc); + + spin_lock(&dk_disk_lock); + list_add_tail(&diskinfo->list, &dk_disk_list); + diskinfo->pending = 1; + spin_unlock(&dk_disk_lock); + + return diskinfo; +out4: + devfs_unregister(disc); +out3: + kmem_free(diskinfo, sizeof(*diskinfo)); +out2: + kmem_free(partinfo, sizeof(*partinfo)); +out1: + spin_lock(&dk_disk_lock); + dk_drivefree(setinfo, drive); + spin_unlock(&dk_disk_lock); + + return NULL; +} + +void +dksc_disk_remove(vertex_hdl_t lun_vhdl) +{ + devfs_handle_t de; + struct dk_partinfo *partinfo; + struct dk_diskinfo *diskinfo; + struct dksoftc *dk; + int i; + + de = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + if (!de) + return; + + partinfo = devfs_get_info(de); + if (!partinfo) + return; + + diskinfo = partinfo->diskinfo; + + /* + * Free the softc data structure and all attachments. + */ + dk = diskinfo->softc; + if (dk != NULL) + dk_unalloc_softc(dk); + + dksc_de[diskinfo->setinfo->major][diskinfo->drive] = NULL; + for (i = 0; i < DK_DISK_SIZE; i++) { + if (!diskinfo->parts[i]) + continue; + dk_part_remove(diskinfo, i); + } + + spin_lock(&dk_disk_lock); + list_del(&diskinfo->list); + dk_drivefree(diskinfo->setinfo, diskinfo->drive); + spin_unlock(&dk_disk_lock); + + kmem_free(diskinfo, sizeof(*diskinfo)); +} + +static devfs_handle_t +dk_part_add(struct dk_diskinfo *diskinfo, int i) +{ + vertex_hdl_t lun_vhdl; + devfs_handle_t part; + devfs_handle_t rpart; + struct dk_partinfo *partinfo; + char name[sizeof("part") + 3 + 1]; + unsigned int major; + unsigned int minor; + + lun_vhdl = SLI_LUN_VHDL(diskinfo->luninfo); + + if (diskinfo->parts[i]) { + printk("attempted to add existing partition!\n"); + return diskinfo->parts[i]->de; + } + + major = diskinfo->setinfo->major; + minor = DK_MINOR(diskinfo->drive, i); + + partinfo = kmem_zalloc(sizeof(*partinfo), KM_SLEEP); + if (!partinfo) + return NULL; + + diskinfo->parts[i] = partinfo; + partinfo->diskinfo = diskinfo; + partinfo->part = i; + + sprintf(name, "part%d", i); + part = devfs_register(lun_vhdl, name, DEVFS_FL_DEFAULT, major, minor, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) get_blkfops(major), partinfo); + if (part == NULL) + goto out1; + + partinfo->de = part; + + sprintf(name, "rpart%d", i); + rpart = devfs_register(lun_vhdl, name, DEVFS_FL_DEFAULT, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) &dksc_char_ops, partinfo); + if (rpart == NULL) + goto out2; + +#ifndef CONFIG_BLK_DEV_SD + { + int drivenum; + char drivename[8]; + char fullpath[128]; + char firstletter; + char secondletter; + + drivenum = (diskinfo->setinfo->setnum << DK_DISK_SHIFT) + diskinfo->drive; + if (drivenum < 128) /* # devices that Redhat supports */ { + secondletter = (char) (drivenum % 26) + 'a'; + if (drivenum >= 26) { + firstletter = (char) (drivenum / 26) + 'a' - 1; + sprintf(drivename, "sd%c%c%d", firstletter, secondletter, i); + } + else + sprintf(drivename, "sd%c%d", secondletter, i); + drivenum = devfs_generate_path(part, fullpath, 128); + devfs_mk_symlink(NULL, drivename, DEVFS_FL_DEFAULT, + &fullpath[drivenum], &partinfo->de_compat, NULL); + } + } +#endif + + devfs_auto_unregister(part, rpart); + + return part; +out2: + devfs_unregister(part); +out1: + kmem_free(partinfo, sizeof(*partinfo)); + diskinfo->parts[i] = NULL; + + return NULL; +} + +static void +dk_part_remove(struct dk_diskinfo *diskinfo, int i) +{ + struct dk_partinfo *partinfo; + struct hd_struct *hd; + + if (!diskinfo->parts[i]) { + printk("partition %d already removed!\n", i); + return; + } + + partinfo = diskinfo->parts[i]; + devfs_unregister(partinfo->de); + devfs_unregister(partinfo->de_compat); + kmem_free(partinfo, sizeof(*partinfo)); + diskinfo->parts[i] = NULL; + + /* + * Zero out nr_sects field in hd_struct so that get_partition_list() + * won't try to look at partition info. This is already done if the + * partition is removed as a result of a call to grok_partitions, but + * if the partition is removed due to the drive disappearing, this is + * necessary. Also zero out the de, since there is no longer a valid + * devfs_entry. + */ + hd = &diskinfo->setinfo->hd[DK_MINOR(diskinfo->drive, i)]; + hd->nr_sects = 0; + hd->de = NULL; +} + + +static int +dk_readparts(struct dksoftc *dk) +{ + struct dk_diskinfo *diskinfo; + scsi_lun_info_t *luninfo; + unsigned int capacity; + int i; + struct dk_setinfo *set; + struct hd_struct *hd; + vertex_hdl_t lun_vhdl; + int drive; + + diskinfo = dk->dk_disk_info; + luninfo = diskinfo->luninfo; + lun_vhdl = SLI_LUN_VHDL(diskinfo->luninfo); + drive = diskinfo->drive; + set = diskinfo->setinfo; + hd = &set->hd[DK_MINOR(drive, 0)]; + /* + * hd should also equal &gdev->part[]; + */ + + /* + * Check to see if the drive is ready for IO. + */ + if (dk_cmd(dk, dk_tst_unit_rdy, SC_CLASS0_SZ, DKSC_TIMEOUT, + NULL, 0, 0)) + return -EIO; + + /* + * We zero out the hd_structure so that the fields are + * initialized. Start_sect and nr_sects will be set in + * grok_partitions. + */ + memset(hd, 0, sizeof(struct hd_struct) << DK_DISK_SHIFT); + + /* + * Get capacity in 512b blocks. + */ + capacity = dk_readcap(dk) << (log2(dk->dk_blksz) - 9); + if (!capacity) { + dk_pmsg(dk, 0, "unable to determine capacity\n"); + return -EIO; + } + + for (i = 0; i < DK_DISK_SIZE; i++) { + if (dk->dk_blksz > 1024) + set->blksize_size[DK_MINOR(drive, i)] = dk->dk_blksz; + else + set->blksize_size[DK_MINOR(drive, i)] = 1024; + set->hardsect_size[DK_MINOR(drive, i)] = dk->dk_blksz; + } + + set->disks[DK_MINOR(drive, 0) >> DK_DISK_SHIFT] = lun_vhdl; + + if (!(dk->dk_flags & DK_FAILOVER)) { + grok_partitions(set->gdev, DK_MINOR(drive, 0) >> DK_DISK_SHIFT, + DK_DISK_SIZE, (long) capacity); + + for (i = 0; i < DK_DISK_SIZE; i++) { + /* + * Update the devfs entries for this partition. + */ + + if (!diskinfo->parts[i] && hd[i].nr_sects) + dk_part_add(diskinfo, i); + else if (diskinfo->parts[i] && !hd[i].nr_sects) + dk_part_remove(diskinfo, i); + + if (diskinfo->parts[i]) + hd[i].de = diskinfo->parts[i]->de; + } + } + + return 0; +} + +static int +dk_diskcheckinq(struct dksoftc *dk) +{ + scsi_target_info_t *info; + vertex_hdl_t lun_vhdl; + + lun_vhdl = SLI_LUN_VHDL(dk->dk_disk_info->luninfo); + + info = SLI_INQ(dk->dk_disk_info->luninfo)(lun_vhdl); + if (info == SCSIDRIVER_NULL) { + dk_dbg_pmsg(dk, 0, "scsi_info failed, lun=%d \n", lun_vhdl); + return -ENODEV; + } + + DKSCLOCK(dk); + dk->dk_inqtyp = info->si_inq; + dk->dk_flags &= ~DK_WONT_START; + DKSCUNLOCK(dk); + + /* Should be direct access. Removable media OK. Look at all + but the vendor specific bit; clearly if the controller + doesn't support the lun we want, or it isn't attached, then + we want to fail right here. */ + + switch(dk->dk_inqtyp[0] & 0x1f) { + case 0: /* No define for disk... */ + case XSCSI_PT_WORM: + case XSCSI_PT_CDROM: + case XSCSI_PT_OPTICAL: + break; + default: + dk_pmsg(dk, 0, "not a disk drive, inquiry byte 0 == 0x%x\n", + dk->dk_inqtyp[0]); + /* Fall through. */ + case 0x1f: + return -ENODEV; + } + + /* + * Only add a sense callback for CDROM devices. + */ + if (cdrom_inquiry_test(&dk->dk_inqtyp[8])) + dk->dk_cb = dk_callback_frontend; + else + dk->dk_cb = NULL; + + dk->dk_target_info = info; + + return 0; +} + +/* Only to call when the disk isn't open! */ + +static int +dk_diskalloc(struct dksoftc *dk) +{ + int ret = 0; + scsi_lun_info_t *luninfo; + + luninfo = dk->dk_disk_info->luninfo; + + ret = SLI_ALLOC(luninfo)(SLI_LUN_VHDL(luninfo), dk->dk_qdepth, + dk->dk_cb); + if (ret != SCSIALLOCOK) { + dk_dbg_pmsg(dk, 0, "scsi_alloc failed\n"); + return ret ? -ret : -ENODEV; + } + + dk_getblksz(dk); + + return 0; +} + +void +dk_diskunalloc(struct dksoftc *dk) +{ + scsi_lun_info_t *luninfo; + + luninfo = dk->dk_disk_info->luninfo; + + if (dk->dk_opencount == 0) + SLI_FREE(luninfo)(SLI_LUN_VHDL(luninfo), dk->dk_cb); +} + +static inline struct dkrequest * +dk_alloc_dkrequest(int flag) +{ + struct dkrequest *rq; + + rq = kmem_cache_alloc(dkrequest_cachep, flag); + if (rq) { + rq->sr.sr_command = rq->cmddata; + rq->sr.sr_sense = rq->sensedata; + rq->sr.sr_senselen = SCSI_SENSE_LEN; + rq->sr.sr_alenlist = &rq->alenlist; + } + return rq; +} + +/* + * Initialize elements that are initialized on each command. + */ +static inline void +dk_request_init(struct dkrequest *rq, struct dk_diskinfo *disk_info) +{ + rq->disk_info = disk_info; + rq->retry_count = 0; + rq->sr.sr_lun_vhdl = SLI_LUN_VHDL(disk_info->luninfo); + rq->sr.sr_ctlr = SLI_ADAP(disk_info->luninfo); + rq->sr.sr_target = SLI_TARG(disk_info->luninfo); + rq->sr.sr_lun = SLI_LUN(disk_info->luninfo); + rq->sr.sr_flags = SRF_AEN_ACK; + rq->sr.sr_tag = SC_TAG_SIMPLE; + rq->sr.sr_dev = rq; +} + +#define dksc_free_rq(list) list_entry((list)->next, struct dkrequest, free_table) + +/* + * Allocate the various dynamic data, initialize locks and + * semaphores, etc. + */ +static struct dksoftc * +dk_alloc_softc(void) +{ + struct dksoftc *dk; + int i; + request_queue_t *q; + + dk = kmalloc(sizeof(struct dksoftc), GFP_KERNEL); + if (!dk) + return NULL; + memset(dk, 0, sizeof(struct dksoftc)); + + dk->dk_qdepth = DFMAXQ; + dk->dk_request_queue.plug_tq.sync = 0; + dk->dk_request_queue.plug_tq.routine = (void (*)(void *))dksc_unplug; + dk->dk_request_queue.plug_tq.data = dk; + + DKSCINITLOCK(dk); + dk->dk_iobuffree_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&dk->dk_wait); + sema_init(&dk->dk_sema, 1); + sema_init(&dk->dk_done, 0); + sema_init(&dk->dk_hold, 0); + + /* + * Use our own request function. Setup our own list of free + * request structures that we can stuff information for each + * buffer_head into. + */ + q = &dk->dk_request_queue; + blk_queue_make_request(q, &dksc_request); + + INIT_LIST_HEAD(&q->queue_head); + INIT_LIST_HEAD(&q->rq[0].free); + INIT_LIST_HEAD(&q->rq[1].free); + + for (i = 0; i < DK_NR_REQUESTS; i++) { + struct dkrequest *rq; + rq = dk_alloc_dkrequest(SLAB_KERNEL); /* sleep allowed */ + if (!rq) + goto out1; + list_add(&rq->free_table, &q->rq[0].free); + } + q->rq[0].count = DK_NR_REQUESTS; + q->queuedata = dk; + + init_waitqueue_head(&q->wait_for_requests[0]); + + /* + * Reserve one request for the callback. + */ + dk->dk_rq = dk_get_request(dk, 0); + + return(dk); +out1: + while (!list_empty(&q->rq[0].free)) { + struct dkrequest *rq; + rq = dksc_free_rq(&q->rq[0].free); + list_del(&rq->free_table); + kmem_cache_free(dkrequest_cachep, rq); + } + kfree(dk); + return NULL; +} + +static int +dk_diskinit(struct dk_diskinfo *diskinfo) +{ + struct dksoftc *dk; + + dk = dk_alloc_softc(); + if (!dk) + return -ENOMEM; + + dk->dk_disk_info = diskinfo; + diskinfo->softc = dk; + + return 0; +} + +static void +dk_unalloc_softc(struct dksoftc *dk) +{ + struct list_head *list; + + DKSCDELETELOCK(dk); + + list = &dk->dk_request_queue.rq[0].free; + + while (!list_empty(list)) { + struct dkrequest *rq; + rq = list_entry(list->next, struct dkrequest, free_table); + list_del(&rq->free_table); + kmem_cache_free(dkrequest_cachep, rq); + } + + kmem_cache_free(dkrequest_cachep, dk->dk_rq); + + kfree(dk); +} + +/* + * Only called at init time. + */ +static int +dk_diskprobe(struct dk_diskinfo *diskinfo) +{ + struct dksoftc *dk; + int ret = 0; + + if (!diskinfo->softc) { + ret = dk_diskinit(diskinfo); + if (ret) return ret; + } + + dk = diskinfo->softc; + ret = dk_diskcheckinq(dk); + if (ret) + return ret; + + ret = dk_diskalloc(dk); + if (ret) + return ret; + + ret = dk_readparts(dk); + dk_diskunalloc(dk); + return ret; +} + +void +dksc_notify(void) +{ + struct dk_diskinfo *diskinfo; + struct list_head *entry; + + spin_lock(&dk_disk_lock); + list_for_each(entry, &dk_disk_list) { + diskinfo = list_entry(entry, struct dk_diskinfo, list); + if (!diskinfo->pending) + continue; + dk_diskprobe(diskinfo); + diskinfo->pending = 0; + } + spin_unlock(&dk_disk_lock); +} + +/* + * Called by failover fo_mirror_lun(). + */ +void +dksc_reprobe (vertex_hdl_t lun_vhdl) +{ + struct dk_diskinfo *diskinfo; + + diskinfo = dksc_disk_add (lun_vhdl); + + if (diskinfo) { + spin_lock(&dk_disk_lock); + dk_diskprobe (diskinfo); /* don't care if pending bit set */ + diskinfo->pending = 0; + spin_unlock(&dk_disk_lock); + } + + return; +} + +static int +dksc_open(struct inode *dkinode, struct file *dkfile) +{ + struct dksoftc *dk; + int part; + int ret = 0; + struct dk_partinfo *partinfo; + struct dk_diskinfo *diskinfo; + devfs_handle_t de; + int drive; + + SCSI_HWG_ACCESS(); + + de = devfs_get_handle_from_inode(dkinode); + + /* + * If we are called from blkdev_get, it may have faked an + * inode for us, in which case we can't get the handle from + * the inode. + */ + if (de == NULL) + de = devfs_find_handle(NULL, NULL, + MAJOR(dkinode->i_rdev), + MINOR(dkinode->i_rdev), + DEVFS_SPECIAL_BLK, 0); + + /* + * It is possible for the kernel to generate an open request + * to a block device that it has just created, so we have to + * allow for the possibility that the devfs lookups will fail. + */ + if (de == NULL) { + SCSI_HWG_UNACCESS(); + return -ENXIO; + } + + partinfo = devfs_get_info(de); + part = partinfo->part; + diskinfo = partinfo->diskinfo; + drive = diskinfo->drive; + + /* + * Single thread open and close. + */ + down(&diskinfo->sema); + + if (diskinfo->softc == NULL) { + ret = dk_diskinit(diskinfo); + if (ret) { + SCSI_HWG_UNACCESS(); + goto out1; + } + } + + dk = diskinfo->softc; + dk_dbg_pmsg(dk, 0, "dkscopen %d/%d\n", MAJOR(dkinode->i_rdev), + MINOR(dkinode->i_rdev)); + + ret = dk_diskcheckinq(dk); + if (ret) { + SCSI_HWG_UNACCESS(); + goto out1; + } + + if (dk->dk_opencount == 0) { + ret = dk_diskalloc(dk); + + SCSI_HWG_UNACCESS(); + if (ret) + goto out1; + + ret = dk_readparts(dk); + if (ret) + goto out2; + } else { + SCSI_HWG_UNACCESS(); + /* + * Removeable media may have changed since last open. + */ + if ((dk->dk_inqtyp[1] & 0x80)) + dk_getblksz(dk); + } + + /* + * Fail if the partition doesn't exist. + */ + if (!diskinfo->setinfo->hd[DK_MINOR(drive, part)].nr_sects) { + ret = -ENXIO; + goto out2; + } + + dk_checkqueue(dk); + dk->dk_opencount++; + + up(&diskinfo->sema); + return ret; +out2: + if (dk->dk_opencount == 0) + dk_diskunalloc(dk); +out1: + up(&diskinfo->sema); + return ret; +} + +/* + * The close routine + * We don't deallocate the softc structure on dksc close. We could + * keep reference counts and free when necessary, but it seems unnecessary. + * + * no reason to free up anything any more, since multiple upper + * layer devices can all have the same channel open; unfortunately, + * in order for the exclusive open stuff to work right, we still + * have to handle the scsi_free[] stuff. + */ +static int +dksc_close(struct inode *dkinode, struct file *dkfile) +{ + struct dksoftc *dk; + struct dk_diskinfo *diskinfo; + struct dk_partinfo *partinfo; + vertex_hdl_t lun_vhdl; + devfs_handle_t de; + + de = devfs_get_handle_from_inode(dkinode); + + /* + * If we are called from blkdev_put, it may have faked an + * inode for us, in which case we can't get the handle from + * the inode. + */ + if (de == NULL) + de = devfs_find_handle(NULL, NULL, + MAJOR(dkinode->i_rdev), + MINOR(dkinode->i_rdev), + DEVFS_SPECIAL_BLK, 0); + + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + + lun_vhdl = SLI_LUN_VHDL(diskinfo->luninfo); + + down(&diskinfo->sema); + + dk = diskinfo->softc; + dk->dk_opencount--; + if (dk->dk_opencount == 0) + SLI_FREE(diskinfo->luninfo)(lun_vhdl, dk->dk_cb); + + up(&diskinfo->sema); + + dk_dbg_pmsg(dk, 0, "dkscclose %d/%d\n", MAJOR(dkinode->i_rdev), + MINOR(dkinode->i_rdev)); + return 0; +} + +#if NOTYET +/* + * dkscioctl -- io controls. Note that because of the + * ioctl_data stuff, there must be only one return from + * this routine. + */ +static int +dkscioctl(struct inode *dkinode, struct file *dkfile, unsigned int cmd, unsigned long arg) +{ + caddr_t ioctl_data; + int error = 0; + scsi_part_info_t *part_info; + scsi_disk_info_t *disk_info; + struct dksoftc *dk; + vertex_hdl_t lun_vhdl; + vertex_hdl_t dev_vhdl; + + dev_vhdl = devfs_get_handle_from_inode(dkinode); + part_info = scsi_part_info_get(dev_vhdl); + disk_info = SPI_DISK_INFO(part_info); + lun_vhdl = SDI_LUN_VHDL(disk_info); + + dk = SDI_DKSOFTC(disk_info); + + switch (cmd) { + case DIOCFOUPDATE: + /* + * only MGR can modify drive characteristics, + * spare blocks, or format drives + */ + if (!capable(CAP_SYS_ADMIN)) { + return -EPERM; + } + ioctl_data = xscsi_dma_malloc(MAX_IOCTL_DATA); + break; + default: + ioctl_data = NULL; + break; + } + + switch (cmd) { + + case DIOCFOUPDATE: +#if NOTYET + { + user_fo_generic_info_t *fgi = (void *) ioctl_data; + int i; + + if(gencopy((void *) arg, ioctl_data, sizeof(dk->dk_vh), 0)) + goto copyerr; + + /* + ** Confirm that at least one of the lvh in the info + ** corresponds to this lvh. If not, return EINVAL. + */ + for (i = 0; i < MAX_FO_PATHS; i++) { + if (fgi->fgi_lun_vhdl[i] == lun_vhdl) { + /* + ** Call into the failover software. + */ + error = fo_scsi_device_update_generic(fgi); + break; + } + } + if (i == MAX_FO_PATHS) + error = -EINVAL; + break; + } +#endif + + default: + error = -EINVAL; + break; + } + + if(ioctl_data) + xscsi_dma_free(ioctl_data); + return error; +} +#endif + +static int +dksc_ioctl(struct inode *dkinode, struct file *dkfile, + unsigned int cmd, unsigned long arg) +{ + struct dk_partinfo *partinfo; + struct dk_diskinfo *diskinfo; + struct dksoftc *dk; + devfs_handle_t de; + int part; + struct dk_setinfo *set; + struct hd_struct *hd; + int info[4]; + int drive; + int minor; + int status; + + de = devfs_get_handle_from_inode(dkinode); + + if (de == NULL) + de = devfs_find_handle(NULL, NULL, + MAJOR(dkinode->i_rdev), + MINOR(dkinode->i_rdev), + DEVFS_SPECIAL_BLK, 0); + + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + dk = diskinfo->softc; + part = partinfo->part; + drive = diskinfo->drive; + set = diskinfo->setinfo; + hd = &set->hd[DK_MINOR(drive, part)]; + + /* We need the device number of the block device for the + character device. */ + + minor = DK_MINOR(drive, part); + + switch (cmd) { + case HDIO_GETGEO: + { + struct hd_geometry *loc = (struct hd_geometry *) arg; + if(!loc) { + status = -EINVAL; + break; + } + + /* default to most commonly used values */ + + info[0] = 0x40; + info[1] = 0x20; + info[2] = hd->nr_sects >> 11; + + if (put_user(info[0], &loc->heads) || + put_user(info[1], &loc->sectors) || + put_user(info[2], &loc->cylinders) || + put_user(hd->start_sect, &loc->start)) + status = -EFAULT; + else + status = 0; + break; + } + case HDIO_GETGEO_BIG: + { + struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; + + if(!loc) { + status = -EINVAL; + break; + } + + /* default to most commonly used values */ + + info[0] = 0x40; + info[1] = 0x20; + info[2] = hd->nr_sects >> 11; + + if (put_user(info[0], &loc->heads) || + put_user(info[1], &loc->sectors) || + put_user(info[2], (unsigned int *) &loc->cylinders) || + put_user(hd->start_sect, &loc->start)) + status = -EFAULT; + else + status = 0; + break; + } + + case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + down(&diskinfo->sema); + if (dk->dk_opencount == 1) + status = dk_readparts(dk); + else + status = EBUSY; + up(&diskinfo->sema); + break; + + case BLKGETSIZE: + /* Get block size in 512B blocks */ + status = put_user((long) hd->nr_sects, (long *) arg); + break; + + default: + status = blk_ioctl(MKDEV(set->major, minor), cmd, arg); + break; + } + + return status; +} + + +static inline struct kiobuf * +dk_getbuf(struct dksoftc *dk) +{ + struct kiobuf *iobuf; + int err; + + spin_lock(&dk->dk_iobuffree_lock); + if (dk->dk_freeiobuf != NULL) { + iobuf = dk->dk_freeiobuf; + dk->dk_freeiobuf = (struct kiobuf *) iobuf->bh[0]; + spin_unlock(&dk->dk_iobuffree_lock); + iobuf->nr_pages = 0; + } + else { + int nbh = 0; + + dk->dk_iobuf_count++; + spin_unlock(&dk->dk_iobuffree_lock); + err = alloc_kiovec_sz(1, &iobuf, &nbh); + if (err) { + spin_lock(&dk->dk_iobuffree_lock); + dk->dk_iobuf_count--; + spin_unlock(&dk->dk_iobuffree_lock); + return NULL; + } + } + return iobuf; +} + +static inline void +dk_freebuf(struct dksoftc *dk, struct kiobuf *iobuf) +{ + spin_lock(&dk->dk_iobuffree_lock); + if (dk->dk_iobuf_count < 32) { + iobuf->bh[0] = (struct buffer_head *) dk->dk_freeiobuf; + dk->dk_freeiobuf = iobuf; + spin_unlock(&dk->dk_iobuffree_lock); + } + else { + dk->dk_iobuf_count--; + spin_unlock(&dk->dk_iobuffree_lock); + free_kiovec(1, &iobuf); + } +} + +static void +dk_kiobuf_end_io(struct kiobuf *iobuf) +{ + complete((struct completion *) iobuf->blocks); +} + +static void +dk_wait_for_io(struct kiobuf *iobuf) +{ + wait_for_completion((struct completion *) iobuf->blocks); +} + +static ssize_t +dksc_raw(struct file *dkfile, char *addr, size_t size, loff_t *offset, int rw) +{ + struct dksoftc *dk; + int count; + unsigned int sector; + int err; + struct dk_diskinfo *diskinfo; + struct dk_partinfo *partinfo; + int part; + devfs_handle_t de; + struct kiobuf *iobuf; + struct dk_setinfo *set; + struct hd_struct *hd; + struct inode *dkinode; + int drive; + + dkinode = dkfile->f_dentry->d_inode; + de = devfs_get_handle_from_inode(dkinode); + partinfo = devfs_get_info(de); + part = partinfo->part; + diskinfo = partinfo->diskinfo; + dk = diskinfo->softc; + drive = diskinfo->drive; + set = diskinfo->setinfo; + hd = &set->hd[DK_MINOR(drive, part)]; + + if (*offset & (dk->dk_blksz - 1) || size & (dk->dk_blksz - 1)) + return -EINVAL; + + sector = *offset >> log2(dk->dk_blksz); + count = size >> log2(dk->dk_blksz); + + if (sector + count > hd->nr_sects >> (log2(dk->dk_blksz) - 9)) + return -EINVAL; + + if ((iobuf = dk_getbuf(dk)) == NULL) + return -EAGAIN; + + err = map_user_kiobuf(rw, iobuf, (unsigned long) addr, size); + if (err) + goto out; + + iobuf->errno = 0; + iobuf->end_io = dk_kiobuf_end_io; + init_completion((struct completion *) iobuf->blocks); + + err = dksc_strategy(dk, part, rw, NULL, iobuf, sector, count); + if (err) + goto out; + + dk_wait_for_io(iobuf); + + if (iobuf->errno) { + err = iobuf->errno; + goto out; + } + + *offset += size; + err = size; +out: + unmap_kiobuf(iobuf); + dk_freebuf(dk, iobuf); + return err; +} + +static ssize_t +dksc_read(struct file *dkfile, char *addr, size_t size, loff_t *offset) +{ + return dksc_raw(dkfile, addr, size, offset, READ); +} + +static ssize_t +dksc_write(struct file *dkfile, const char *addr, size_t size, loff_t *offset) +{ + return dksc_raw(dkfile, (char *) addr, size, offset, WRITE); +} + +#if DKSC_READV_WRITEV +static ssize_t +dksc_rvwv(struct file *dkfile, const struct iovec *iov, + unsigned long iovcount, loff_t *offset, int rw) +{ + struct dksoftc *dk; + int count; + unsigned int sector; + int err; + struct dk_diskinfo *diskinfo; + devfs_handle_t de; + struct dk_partinfo *partinfo; + struct kiobuf *iobuf; + struct dk_setinfo *set; + struct hd_struct *hd; + struct inode *dkinode; + int size; + int i; + + dkinode = dkfile->f_dentry->d_inode; + de = devfs_get_handle_from_inode(dkinode); + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + dk = diskinfo->softc; + set = diskinfo->setinfo; + hd = &set->hd[DK_MINOR(diskinfo->drive, partinfo->part)]; + + size = 0; + for (i = 0; i < iovcount; i++) + size += iov->iov_len; + + if (*offset & (dk->dk_blksz - 1) || size & (dk->dk_blksz - 1)) + return -EINVAL; + + sector = *offset >> log2(dk->dk_blksz); + count = size >> log2(dk->dk_blksz); + + if (sector + count > hd->nr_sects >> (log2(dk->dk_blksz) - 9)) + return -EINVAL; + + err = alloc_kiovec(1, &iobuf); + if (err) + return err; + + err = expand_kiobuf(iobuf, size >> PAGE_SHIFT); + if (err) + goto out; + + err = map_user_kiobuf(rw, iobuf, (unsigned long) iov[0].iov_base, + iov[0].iov_len); + if (err) + goto out; + + for (i = 1; i < iovcount; i++) { + err = add_user_kiobuf(rw, iobuf, (unsigned long) iov[i].iov_base, + iov[0].iov_len); + if (err) + goto out; + } + + iobuf->errno = 0; + iobuf->end_io = dk_kiobuf_end_io; + atomic_inc(&iobuf->io_count); + + err = dksc_strategy(dk, partinfo->part, rw, NULL, iobuf, sector, count); + if (err) { + atomic_dec(&iobuf->io_count); + goto out; + } + + kiobuf_wait_for_io(iobuf); + + if (iobuf->errno) { + err = iobuf->errno; + goto out; + } + + *offset += size; + err = size; +out: + unmap_kiobuf(iobuf); + free_kiovec(1, &iobuf); + return err; +} + +static ssize_t +dksc_readv(struct file *dkfile, const struct iovec *iov, + unsigned long count, loff_t *offset) +{ + return dksc_rvwv(dkfile, iov, count, offset, READ); +} + +static ssize_t +dksc_writev(struct file *dkfile, const struct iovec *iov, + unsigned long count, loff_t *offset) +{ + return dksc_rvwv(dkfile, iov, count, offset, WRITE); +} +#endif + + + +static request_queue_t * +dk_get_queue(kdev_t dev) +{ + devfs_handle_t de; + struct dk_partinfo *partinfo; + struct dksoftc *dk; + + de = dksc_de[MAJOR(dev)][MINOR(dev) >> DK_DISK_SHIFT]; + if (!de) + return NULL; + partinfo = devfs_get_info(de); + dk = partinfo->diskinfo->softc; + + return &dk->dk_request_queue; +} + + +static struct dkrequest * +dk_get_request(struct dksoftc *dk, int rw) +{ + request_queue_t *q = &dk->dk_request_queue; + struct list_head *list = &q->rq[0].free; + register struct dkrequest *rq = NULL; + DECLARE_WAITQUEUE(wait, current); + + DKSCLOCK(dk); + if (!list_empty(list)) { + rq = dksc_free_rq(list); + list_del(&rq->free_table); + } + if (rq == NULL && q->rq[0].count < DK_MAX_REQUESTS) { + rq = dk_alloc_dkrequest(SLAB_ATOMIC); + if (rq != NULL) + ++q->rq[0].count; + } + DKSCUNLOCK(dk); + if (rq != NULL) { + rq->free_list = list; + rq->q = q; + return rq; + } + + /* + * If we're at the point where we're out of requests, make sure + * that we start issuing those requests to the drive. + */ + dksc_unplug(dk); + + add_wait_queue_exclusive(&q->wait_for_requests[0], &wait); + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + DKSCLOCK(dk); + if (!list_empty(list)) { + rq = dksc_free_rq(list); + list_del(&rq->free_table); + DKSCUNLOCK(dk); + rq->free_list = list; + rq->q = q; + break; + } + DKSCUNLOCK(dk); + schedule(); + } + remove_wait_queue(&q->wait_for_requests[0], &wait); + current->state = TASK_RUNNING; + + return rq; +} + +static inline void +__dk_free_request(struct dksoftc *dk, struct dkrequest *rq) +{ + if (!rq->free_list) + BUG(); + + list_add(&rq->free_table, rq->free_list); + rq->free_list = NULL; + wake_up(&rq->q->wait_for_requests[0]); +} + +static void +dk_free_request(struct dksoftc *dk, struct dkrequest *rq) +{ + DKSCLOCK(dk); + __dk_free_request(dk, rq); + DKSCUNLOCK(dk); +} + +/* + * Slightly different version of disksort for controllers and drives which + * have more than one command active (tagged commands, command queueing, + * MACSI mode, etc.). The main difference is that macsisort puts a command + * into the second sort queue if its logical block number is less than the + * logical block number of the last command sent to the controller (stored + * in av_back by the driver). + * The idea is to have two lists, one following the other. In the first list + * are the bufs whose starting block numbers are greater than the starting + * block number of the command last sent to the controller. In the second list + * are those commands whose starting block numbers are less than the starting + * block number of the last command sent to the controller. The last command + * on the first list points to the first command on the second list. */ +void +macsisort(struct dksoftc *dk, struct diskqueue *utab, struct dkrequest *rq) +{ + register unsigned int bn; + register unsigned int fbn; + struct dkrequest **iohead; + struct dkrequest **iotail; + struct dkrequest *ap; + int max_merge = 1023; + long sort_block; + + /* + * max_merge is a hack put it to workaround problems with the 1394 + * tailgate card that can only handle 32 s/g entries. It can revert + * to a constant when that issue is resolved. + */ + if ((dk->dk_inqtyp[0] & 0x1F) == 5) + max_merge = 31; + + if (rq->cmd == WRITE) { + iohead = &utab->delwri_head; + iotail = &utab->delwri_tail; + sort_block = utab->delwri_prev; + } + else { + iohead = &utab->io_head; + iotail = &utab->io_tail; + sort_block = utab->io_prev; + } + + ap = *iohead; + /* + * empty queue case + */ + if (ap == NULL) + { + *iohead = rq; + *iotail = rq; + rq->av_forw = NULL; + dksc_event_log(1, dk, "sorting into empty list", rq->sector, rq->count); + goto macsi_sort_end; + } + + bn = rq->sector; + /* + * if block number < bn of last command to be submitted, AND + * the first buf has a bn >= bn of last command, + * go forward until we hit buf with bn < bn of first buf + * then insert somewhere in second list + * else if block number <= bn at beginning of list, or + * (block number is >= bn of last command AND bn at beginning + * of list is < bn of last command submitted), + * insert at beginning of first list. + * else + * insert somewhere in first list + */ + if (bn < sort_block && ap->sector >= sort_block) + { + fbn = ap->sector; + while (ap->av_forw != NULL && + ap->av_forw->sector >= fbn) + ap = ap->av_forw; + while (ap->av_forw != NULL && + bn > ap->av_forw->sector) + ap = ap->av_forw; + dksc_event_log(1, dk, "sorting into second list", rq->sector, rq->count); + goto macsi_sort_insert; + } + else if ((bn <= ap->sector) || + (bn >= sort_block && ap->sector < sort_block)) + { + rq->av_forw = ap; + *iohead = rq; + dksc_event_log(1, dk, "sorting at start of first list", rq->sector, rq->count); + goto macsi_sort_merge_forward; + } + else + { + fbn = ap->sector; + while (ap->av_forw != NULL && + fbn <= ap->av_forw->sector && + bn > ap->av_forw->sector) + ap = ap->av_forw; + dksc_event_log(1, dk, "sorting into first list", rq->sector, rq->count); + } + + /* + * Insert in list. + */ +macsi_sort_insert: + /* insert rq after ap */ + /* update io_tail if necessary */ + rq->av_forw = ap->av_forw; + ap->av_forw = rq; + if (rq->av_forw == NULL) + *iotail = rq; + + /* + * Merge dkrequests if possible. + * ap points to request behind rq. + */ + if (ap != NULL && ap->bh && rq->bh && + ap->sector + ap->count == rq->sector && + ap->merges + rq->merges < max_merge) + { + dksc_event_log(2, dk, " merging back", ap->sector, ap->count); + ap->count += rq->count; + ap->bhlast->b_reqnext = rq->bh; + ap->bhlast = rq->bh; + ap->av_forw = rq->av_forw; + ap->merges += rq->merges + 1; + __dk_free_request(dk, rq); + rq = ap; /* set up for forward merge check */ + } + ap = rq->av_forw; +macsi_sort_merge_forward: + if (ap != NULL && ap->bh && rq->bh && + rq->sector + rq->count == ap->sector && + rq->merges + ap->merges < max_merge) + { +#if DKSC_EVENT_LOG + if (rq->merges && ap->merges) + dksc_event_log(5, dk, "--- hole fill merge ---", + rq->sector, ap->sector); +#endif + dksc_event_log(3, dk, " merging forward", ap->sector, ap->count); + rq->count += ap->count; + rq->bhlast->b_reqnext = ap->bh; + rq->bhlast = ap->bhlast; + rq->av_forw = ap->av_forw; + rq->merges += ap->merges + 1; + __dk_free_request(dk, ap); + } + +macsi_sort_end: +} + +#if 0 +/* + * nosort() + * Add request to queue. Queue is manged in first in, first out order. + * + */ +static void +nosort(register struct diskqueue *utab, register struct dkrequest *rq) +{ + if (utab->io_head == NULL) + { + utab->io_head = rq; + utab->io_tail = rq; + } + else + { + utab->io_tail->av_forw = rq; + utab->io_tail = rq; + } + + rq->b_resid = rq->count << 9; +} +#endif + + +static struct dkrequest * +fair_disk_dequeue(struct diskqueue *utab) +{ + struct dkrequest *rq; + + /* + * Take a request from the head of the queue. + */ + if (utab->io_head) { + rq = utab->io_head; + utab->io_head = rq->av_forw; + utab->io_prev = rq->sector; + } + else if (utab->delwri_head) { + rq = utab->delwri_head; + utab->delwri_head = rq->av_forw; + utab->delwri_prev = rq->sector; + } + else + return NULL; + + return rq; +} + + +static inline void +dk_finish(struct kiobuf *iobuf, struct buffer_head *bh, int bytes_xferred, int error) +{ + struct buffer_head *nbh; + + if (iobuf) { + iobuf->errno = error; + iobuf->end_io(iobuf); + } + else while (bh != NULL) { + if (!error) { + if (bytes_xferred < bh->b_size) + error = EIO; + else + bytes_xferred -= bh->b_size; + } + nbh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, !error); + bh = nbh; + } +} + + +static void +dk_purgequeues(register struct dksoftc *dk) +{ + struct dkrequest *rq; + struct dkrequest *rqchain = NULL; + struct kiobuf *iobuf; + struct buffer_head *bh; + + /* + * Clear wait queues + */ + while ((rq = fair_disk_dequeue(&(dk->dk_queue))) != NULL) { + dksc_event_log(1, dk, "----> purging off wait list", rq->sector, rq->count); + rq->av_forw = rqchain; + rqchain = rq; + } + + /* + * Clear the dk_retry queue. + */ + while ((rq = dk->dk_retry)) { + dksc_event_log(4, dk, "----> purging off retry", rq->sector, rq->count); + dk->dk_retry = rq->av_forw; + rq->av_forw = rqchain; + rqchain = rq; + } + + DKSCUNLOCK(dk); + + while ((rq = rqchain) != NULL) { + rqchain = rq->av_forw; + iobuf = rq->iobuf; + bh = rq->bh; + dk_free_request(dk, rq); + dk_finish(iobuf, bh, 0, -EIO); + } + + DKSCLOCK(dk); + return; +} + +static void +dksc_command(register struct dksoftc *dk) +{ + struct scsi_request *sp; + struct dkrequest *rq; +#if DKSC_SARD + int tmp; + struct hd_struct *hd, *hd1; + int sectors; +#endif + + while ((rq = (dk->dk_retry ? dk->dk_retry : + dk->dk_queue.io_head ? dk->dk_queue.io_head : + dk->dk_queue.delwri_head)) != NULL) + { + if (dk->dk_request_queue.plugged && dk->dk_retry == NULL) + return; + + /* + * If in the process of issuing a callback command, + * hold all commands. We will restart the issuing + * of commands when the callback command completes. + */ + if (dk->dk_flags & DK_HOLD) + break; + + /* + * Check whether a callback needs to be issued. + * Since the "wait" argument is 0, DK_HOLD and + * DK_NEED_CB will be set by the callback function + * if appropriate. + */ + if (dk->dk_flags & DK_NEED_CB) { + dk_callback_backend(dk, 0); + break; + } + + /* + * See if the queue needs to be purged. + */ + if (dk->dk_flags & (DK_FAILOVER | DK_WONT_START)) { + dk_purgequeues(dk); + break; + } + + if (dk->dk_curq >= dk->dk_qdepth || dk->dk_rqactive >= DK_MAX_REQISSUE) + break; + else + dk->dk_curq++; + + sp = &rq->sr; + + if (!(dk->dk_flags & DK_QUEUE)) + sp->sr_tag = 0; + + /* + * Check the retry queue first -- it has priority. + */ + if (dk->dk_retry) + dk->dk_retry = rq->av_forw; + else + rq = fair_disk_dequeue(&(dk->dk_queue)); + + /* + * Update active queue and alenlist + */ + dk->dk_rqactive++; + rq->av_forw = dk->dk_active; + if (dk->dk_active != NULL) + dk->dk_active->av_back = rq; + rq->av_back = NULL; + dk->dk_active = rq; + +#if DKSC_SARD + /* + * Linux SARD disk accounting + */ + tmp = dk->dk_disk_info->drive; + hd = &dk->dk_disk_info->setinfo->hd[DK_MINOR(tmp, rq->part)]; + if (rq->part) + hd1 = &dk->dk_disk_info->setinfo->hd[DK_MINOR(tmp, 0)]; + else + hd1 = NULL; + if (dk->dk_iostart == 0) + dk->dk_iostart = jiffies; + sectors = rq->count << (log2(dk->dk_blksz) - 9); + if (rq->cmd == READ) { + hd->rd_sectors += sectors; + hd->rd_merges += rq->merges; + if (hd1) { + hd1->rd_sectors += sectors; + hd1->rd_merges += rq->merges; + } + } + else { + hd->wr_sectors += sectors; + hd->wr_merges += rq->merges; + if (hd1) { + hd1->wr_sectors += sectors; + hd1->wr_merges += rq->merges; + } + } + disk_round_stats(hd); + hd->ios_in_flight++; + if (hd1) { + disk_round_stats(hd1); + hd1->ios_in_flight++; + } +#endif + + dksc_event_log(4, dk, "starting command", rq->sector, rq->count); + DKSCUNLOCK(dk); + if (rq->iobuf) + alenlist_setup(&rq->alenlist, + rq->iobuf->maplist, + rq->iobuf->offset, + rq->iobuf->length); + else + alenlist_setup_bh(&rq->alenlist, rq->bh); + dksc_start(dk, rq, sp); + DKSCLOCK(dk); + } +} + +static int +dksc_request(request_queue_t *q, + int rw, + struct buffer_head *bh) +{ + struct dksoftc *dk; + unsigned int dk_sector; + unsigned int dk_count; + int part; + int errno; + + /* + * Partitions may not be initialized, because grok_partitions calls + * bread, which calls this function. Thus, we have to use the major + * and minor number to find the scsi_disk_info structure, and we + * cannot use the scsi_part_info structure. + */ + part = MINOR(bh->b_rdev) & ~DK_DISK_MASK; + dk = q->queuedata; + + if (dk == NULL) + goto bad; + + dk_sector = bh->b_rsector >> (log2(dk->dk_blksz) - 9); + dk_count = bh->b_size >> (log2(dk->dk_blksz)); + + errno = dksc_strategy(dk, part, rw, bh, NULL, dk_sector, dk_count); + + if (errno == -EINVAL) + goto end_io; + else if (errno == -EIO) + goto bad; + return 0; + +end_io: + bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); + return 0; +bad: + buffer_IO_error(bh); + return 0; +} + +static void +dksc_unplug(struct dksoftc *dk) +{ + DKSCLOCK(dk); + if (dk->dk_request_queue.plugged) { + dk->dk_request_queue.plugged = 0; + dksc_command(dk); + } + DKSCUNLOCK(dk); +} + +/* + * Queue device request. The sector and count are based on dk_blksz. + */ +static int +dksc_strategy(struct dksoftc *dk, + int part, + int rw, + struct buffer_head *bh, + struct kiobuf *kiobuf, + unsigned int sector, + unsigned int count) +{ + struct dkrequest *rq; + struct dk_setinfo *set; + int drive; + struct hd_struct *hd; + +#if defined(INDUCE_IO_ERROR) + if (dksc_insert_error && + bp->b_edev == dksc_error_dev) { + if (++dksc_error_count > dksc_error_freq) { + dksc_error_count = 0; + goto bad; + } + } +#endif + + /* + * Write to readonly device is determined in ll_rw_block(). + * Attempt to access beyond end of device is checked for in + * generic_make_request(). + */ + + /* + * Reject the io if the device has failed over. + */ + if (dk->dk_flags & DK_FAILOVER) + return -EIO; + + switch (rw) { + case READA: + rw = READ; /* drop into READ */ + case READ: + case WRITE: + break; + default: + printk(KERN_INFO "dksc: bad command: %d\n", rw); + return -EINVAL; + } + + rq = dk_get_request(dk, rw); + + rq->av_forw = NULL; + rq->av_back = NULL; + rq->cmd = rw; + set = dk->dk_disk_info->setinfo; + drive = dk->dk_disk_info->drive; + hd = &set->hd[DK_MINOR(drive, part)]; + rq->sector = sector + (hd->start_sect >> (log2(dk->dk_blksz) - 9)); + rq->count = count; + rq->part = part; + rq->bh = bh; + rq->bhlast = bh; + rq->iobuf = kiobuf; + rq->merges = 0; + + dk_request_init(rq, dk->dk_disk_info); + + DKSCLOCK(dk); + /* + * Plug this disk's queue if this request is not a kiobuf + * and there is nothing queued + * and it is not yet plugged. + */ + if (kiobuf == NULL && + dk->dk_queue.io_head == NULL && + dk->dk_queue.delwri_head == NULL) + { + if (!dk->dk_request_queue.plugged) { + dk->dk_request_queue.plugged = 1; + queue_task(&dk->dk_request_queue.plug_tq, &tq_disk); + } + } +#if 1 + macsisort(dk, &dk->dk_queue, rq); +#else + nosort(&dk->dk_queue, rq); +#endif + dksc_command(dk); + DKSCUNLOCK(dk); + return 0; +} + +/* + * setup a device operation for calls from outside the driver; upper + * levels of kernel are assumed to do the dki_dcache_{wb,inval} if needed. + */ +static void +dksc_start(struct dksoftc *dk, struct dkrequest *rq, scsi_request_t *sp) +{ + uint32_t sn; + uint32_t sc; + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + + /* Let the scsi driver do the transfer */ + if( rq->cmd == READ ) + memcpy(sp->sr_command, dk_read, SC_CLASS1_SZ); + else + memcpy(sp->sr_command, dk_write, SC_CLASS1_SZ); + + sc = rq->count; + sn = rq->sector; + rq->b_resid = sc << 9; + + /* + * Stuff in the logical block addr. + * Its spot in the cmd is on a short boundary. + */ + sp->sr_command[2] = (u_char)(sn >> 24); + sp->sr_command[3] = (u_char)(sn >> 16); + sp->sr_command[4] = (u_char)(sn >> 8); + sp->sr_command[5] = (u_char)sn; + sp->sr_command[7] = (u_char)(sc >> 8); + sp->sr_command[8] = (u_char)sc; + + sp->sr_cmdlen = SC_CLASS1_SZ; + + sp->sr_notify = dk_intr; + sp->sr_timeout = DKSC_TIMEOUT; + + if (rq->cmd == READ) + sp->sr_flags |= SRF_DIR_IN; + else + sp->sr_flags &= ~SRF_DIR_IN; + + sp->sr_flags |= SRF_ALENLIST; + sp->sr_buflen = sc << log2(dk->dk_blksz); + + SLI_COMMAND(lun_info)(sp); +} + +static inline void +__dk_queue_release(struct dksoftc *dk) +{ + dk->dk_curq--; + if (dk->dk_curq > 0) + dk->dk_iostart = jiffies; + else + dk->dk_iostart = 0; + if (!list_empty(&dk->dk_wait.task_list)) + wake_up(&dk->dk_wait); + else if ((dk->dk_flags & DK_RECURSE) == 0) { + dk->dk_flags |= DK_RECURSE; + dksc_command(dk); + dk->dk_flags &= ~DK_RECURSE; /* turn off recurse bit */ + } +} + +static inline void +dk_queue_release(struct dksoftc *dk) +{ + DKSCLOCK(dk); + __dk_queue_release(dk); + DKSCUNLOCK(dk); +} + +static void +dk_queue_retry(struct dksoftc *dk, struct dkrequest *rq) +{ + DKSCLOCK(dk); + + /* + * Take command off active queue + */ + if (rq->av_back != NULL) + rq->av_back->av_forw = rq->av_forw; + if (rq->av_forw != NULL) + rq->av_forw->av_back = rq->av_back; + if (dk->dk_active == rq) + dk->dk_active = rq->av_forw; + + dksc_event_log(4, dk, "--------> queueing retry", rq->sector, rq->count); + /* + * .... and add it to the retry queue. + */ + rq->av_forw = dk->dk_retry; + dk->dk_retry = rq; + + dk->dk_rqactive--; + __dk_queue_release(dk); + + DKSCUNLOCK(dk); +} + + +/* + * dksc interrupt routine, called via scsisubrel(). + * + */ +static void +dk_intr(register scsi_request_t *sp) +{ + struct dkrequest *rq; + int bytes_xferred; + struct buffer_head *bh; + struct kiobuf *iobuf; + struct dksoftc *dk; + int error = 0; + struct dk_setinfo *set; + struct hd_struct *hd, *hd1; + int drive; + + rq = (struct dkrequest *) sp->sr_dev; + dk = rq->disk_info->softc; + drive = rq->disk_info->drive; + set = rq->disk_info->setinfo; + hd = &set->hd[DK_MINOR(drive, rq->part)]; + + if (rq->part) + hd1 = &set->hd[DK_MINOR(drive, 0)]; + else + hd1 = NULL; + + /* + * If a callback is in progress, don't retry the command + * now. "Return" it to the retry queue and it will get + * scheduled when the callback is complete. + */ + if (dk->dk_flags & (DK_NEED_CB | DK_HOLD)) { + dk_queue_retry(dk, rq); + return; + } + + if (dk_chkcond(dk, sp, 1, 0) == 1) + return; + + switch(sp->sr_status) { + case SC_GOOD: + if (sp->sr_scsi_status != ST_GOOD) { + if (sp->sr_scsi_status == ST_BUSY) + error = -EBUSY; + else + error = -EIO; + } + break; + + case SC_ALIGN: + error = -EFAULT; + /* deliberate fall thru */ + + default: + { + extern char *scsi_adaperrs_tab[]; + if(sp->sr_status < NUM_ADAP_ERRS) + dk_pmsg(dk, rq->part, "SCSI driver error: %s\n", + scsi_adaperrs_tab[sp->sr_status]); + else + dk_pmsg(dk, rq->part, "Unknown SCSI driver error %d\n", + sp->sr_status); + error = -EIO; + } + } + + DKSCLOCK(dk); + +#if DKSC_SARD + /* + * SARD disk accounting + */ + { + long starttime = dk->dk_iostart; + if (rq->cmd == READ) { + hd->rd_ticks += jiffies - starttime; + hd->rd_ios++; + if (hd1) { + hd1->rd_ticks += jiffies - starttime; + hd1->rd_ios++; + } + } + else { + hd->wr_ticks += jiffies - starttime; + hd->wr_ios++; + if (hd1) { + hd1->wr_ticks += jiffies - starttime; + hd1->wr_ios++; + } + } + } + disk_round_stats(hd); + hd->ios_in_flight--; + if (hd1) { + disk_round_stats(hd1); + hd1->ios_in_flight--; + } +#endif + + /* + * Update active queues. + */ + if (rq->av_back != NULL) + rq->av_back->av_forw = rq->av_forw; + if (rq->av_forw != NULL) + rq->av_forw->av_back = rq->av_back; + if (dk->dk_active == rq) + dk->dk_active = rq->av_forw; + + bytes_xferred = sp->sr_buflen - sp->sr_resid; + iobuf = rq->iobuf; + bh = rq->bh; + dksc_event_log(4, dk, "--------> finishing command", rq->sector, rq->count); + + dk->dk_rqactive--; + __dk_queue_release(dk); + __dk_free_request(dk, rq); + + DKSCUNLOCK(dk); + dk_finish(iobuf, bh, bytes_xferred, error); +} + + +/* + * Retry requests when they get Busy statuses or certain Not Ready + * sense codes. + * Return whether or not the retry should be done now, has been + * scheduled for the future (via timeout), or is not to be done + * (either because retry count was exceeded or because retries are + * not to be done). + * Retval: + * 0 = no retry + * > 0 = retry necessary + * < 0 = retry scheduled + */ +static int +dk_busy_retry(struct dksoftc *dk, struct scsi_request *sp, int async) +{ + int retry_cmd; + struct dkrequest *rq; + + rq = (struct dkrequest *) sp->sr_dev; + + /* + * If async is set, we are called from interrupt, and must use + * a timer rather than delay(). + */ + retry_cmd = rq->retry_count; + if (retry_cmd < DK_MAX_BUSY) + { + int intv = 1 << retry_cmd; + if (intv > DK_MAX_BUSY_INTV) + intv = DK_MAX_BUSY_INTV * HZ; + else + intv *= HZ; + + if (async) + { + rq->retry_count = retry_cmd + 1; + sp->sr_tag = 0; + init_timer(&rq->timer); + rq->timer.expires = jiffies + intv; + rq->timer.data = (unsigned long) sp; + rq->timer.function = (void (*)(unsigned long)) dk_do_retry; + add_timer(&rq->timer); + return -1; + } + else + { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(intv); + return 1; + } + } + return 0; +} + +/* + * Return values: + * 0: command should not be retried. + * 1: command should be/has been retried, depending on value of async + * If async set, command retry is scheduled if not too many retries. + * If not async, return value indicates whether to retry or not. + */ +static int +dk_chkcond(struct dksoftc *dk, register scsi_request_t *sp, int async, int mute) +{ + int part; + int retval = 0; + int retry_cmd = 0; + int serious_err = 1; + char key = SC_NOSENSE; + struct dkrequest *rq; + + rq = (struct dkrequest *) sp->sr_dev; + part = rq->part; + + switch (sp->sr_status) + { + case SC_CMDTIME: + case SC_HARDERR: + case SC_PARITY: + /* + * Retry cmds that fail because of timeouts, hardware errors, + * or parity errors. + */ + retry_cmd = 1; + break; + + case SC_GOOD: + if (sp->sr_sensegotten > 0) + { + if ((sp->sr_sense[0] & 0x70) != 0x70) { + dk_pmsg(dk, part, + "invalid sense data, error cause unknown\n"); + retry_cmd = 1; + } + else if (sp->sr_sensegotten <= 2) { + dk_pmsg(dk, part, + "not enough sense data\n"); + retry_cmd = 1; + } + else { + key = sp->sr_sense[2] & 0xF; + if (key == SC_UNIT_ATTN) + serious_err = 0; +#ifndef DEBUG + else if (dk_user_printable_sense(dk, sp, mute)) +#endif + dk_print_sense(dk, sp, part); + + if (key == SC_NOT_READY) + { + /* + * ASC and ASQ are only valid if we received at + * least 14 bytes of sense data. + * If ASC is SC_NOTREADY (4) and ASQ is 0 or 2, + * then set the Need Start Unit flag, as long + * as the error is not for a Start Unit command. + * If the ASC/ASQ is 4/1, that means that the device + * is spinning up, so we treat the same as a BUSY + * SCSI status. + */ + if (sp->sr_sensegotten > 13 && + sp->sr_sense[12] == SC_NOTREADY) + { + uint8_t asq = sp->sr_sense[13]; + + if ((sp->sr_command[0] != 0x1B) && + (asq == 0 || asq == 2)) + { + DKSCLOCK(dk); + dk->dk_flags |= DK_NEEDSTART; + DKSCUNLOCK(dk); + if (async) { + dk_queue_retry(dk, rq); + } + return 1; + } + else if (asq == 1) + { + /* + * Some drives, the TOSHIBA CDROM + * in particular, will return + * NOT_READY to an I/O command for + * about 4 seconds following CD + * load or bus reset. + */ + retry_cmd = dk_busy_retry(dk, sp, async); + /* report 2nd, then every 4 times */ + if (retry_cmd && (rq->retry_count % 4 == 2)) + dk_pmsg(dk, part, "NOT READY; retrying\n"); + if (retry_cmd > 0) + serious_err = 0; + else if (retry_cmd < 0) + return 1; + else + dk_pmsg(dk, part, "NOT READY; giving up\n"); + } + } + } + + /* + * Retry commands that failed because of a unit + * attention, media error, hardware error, aborted + * command, or deferred errors. + * Retrying on unit attention may cause timeouts, + * but that's better than just letting async writes + * fail completely, which otherwise is quite likely + * to happen. + */ + else if (key == SC_MEDIA_ERR || key == SC_HARDW_ERR || + key == SC_CMD_ABORT || key == SC_UNIT_ATTN || + (sp->sr_sense[0] & 1)) + { + retry_cmd = 1; + } + } + + /* + * To ensure that sense key errors cause an error to + * be returned, we set SCSI status to what it really + * was if sense data indicates a serious problem. + * otherwise, if we recovered, we want to clear the + * scsi status, so we don't consider it an error in + * dk_intr(). + */ + sp->sr_scsi_status = (key==SC_ERR_RECOVERED)?ST_GOOD:ST_CHECK; + } + else if (sp->sr_scsi_status == ST_BUSY) { + /* retry up to 4 minutes, same reason as for startunit */ + retry_cmd = dk_busy_retry(dk, sp, async); + + /* report 2nd, then every 4 times */ + if (retry_cmd && (rq->retry_count % 4 == 2)) + dk_pmsg(dk, part, "BUSY; retrying\n"); + if (retry_cmd > 0) + serious_err = 0; + else if (retry_cmd < 0) + return 1; + else { /* give up, busy too long */ + dk_pmsg(dk, part, "Error: BUSY more than 4 minutes\n"); + } + } + else if (sp->sr_scsi_status == ST_CHECK) { + dk_pmsg(dk, part, "unexpected SCSI check condition status " + "(request sense failed)\n"); + retry_cmd = 1; + } + else if (sp->sr_scsi_status != ST_GOOD) { + dk_pmsg(dk, part, "unexpected SCSI status byte 0x%x\n", + sp->sr_scsi_status); + retry_cmd = 1; + } + break; + + case SC_ATTN: + /* + * We don't want to count the SC_ATTN against the retry limit, + * so retries are handled here. + */ + dk_dbg_pmsg(dk, 0, "SC_ATTN: retrying request %d\n", rq->retry_count); + if(async) { + dksc_start(dk, rq, sp); + } + retval = 1; + break; + } + + if (retry_cmd) { + if (serious_err) + retry_cmd = rq->retry_count + 4; + else + retry_cmd = rq->retry_count + 1; + if (retry_cmd <= DK_MAX_RETRY) { + rq->retry_count = retry_cmd; + sp->sr_tag = 0; +#ifndef DEBUG + if ((sp->sr_status == SC_GOOD) && serious_err) +#endif + dk_pmsg(dk, part, " retrying request\n"); + if(async) { + dksc_start(dk, rq, sp); + } + retval = 1; + } + else if (sp->sr_status == SC_GOOD) { + if (serious_err) + dk_pmsg(dk, part, " retries exhausted\n"); + else + dk_pmsg(dk, part, " failure, retries exhausted - key %d" + " status %d\n", key, sp->sr_scsi_status); + } + } + return retval; +} + +/* + * These functions start and get completion of driver generated commands. + */ +static void +dk_rcvcmd(struct scsi_request *sp) +{ + struct dksoftc *dk; + + dk = ((struct dkrequest *) sp->sr_dev)->disk_info->softc; + up(&dk->dk_done); +} + +static void +dk_sendcmd(register struct dksoftc *dk, struct scsi_request *sp) +{ + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + + down(&dk->dk_sema); + sp->sr_notify = dk_rcvcmd; + SLI_COMMAND(lun_info)(sp); + down(&dk->dk_done); + up(&dk->dk_sema); +} + +/* + * General disk command. + * + * Returns 1 if unsuccessful; + * 0 if successful + */ +static int +dk_cmd(struct dksoftc *dk, u_char *cmd_buffer, int cmd_size, + u_int timeoutval, caddr_t addr, size_t len, int rw) +{ + struct dkrequest *rq; + scsi_request_t *sp; + int stat; + DECLARE_WAITQUEUE(wait, current); + + /* + * Wait if commands are to be held. Check twice, in case + * someone beats us to it. + */ + + again: + if (dk->dk_flags & DK_HOLD) { + DKSCLOCK(dk); + if (dk->dk_flags & DK_HOLD) { + dk->dk_hold_count++; + DKSCUNLOCK(dk); + down(&dk->dk_hold); + } + else + DKSCUNLOCK(dk); + } + /* + * Check if callback is needed. If so, attempt to do + * it unless someone already beat us to it. + */ + if (dk->dk_flags & DK_NEED_CB) { + DKSCLOCK(dk); + if (dk->dk_flags & DK_NEED_CB) { + dk_callback_backend(dk, 1); + /* DKSCUNLOCK done by backend */ + } + else { + DKSCUNLOCK(dk); + goto again; + } + } + if (dk->dk_flags & DK_WONT_START) + return 1; + + rq = dk_get_request(dk, rw); + dk_request_init(rq, dk->dk_disk_info); + rq->part = 0; + + /* + * Add to dk_wait queue. When commands complete, if there is + * something on the wait queue, it will wake us up here, rather + * than issuing a new block/char R/W request. + */ + add_wait_queue_exclusive(&dk->dk_wait, &wait); + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + DKSCLOCK(dk); + if (dk->dk_curq < dk->dk_qdepth) { + dk->dk_curq++; + DKSCUNLOCK(dk); + break; + } + DKSCUNLOCK(dk); + schedule(); + } + remove_wait_queue(&dk->dk_wait, &wait); + current->state = TASK_RUNNING; + + sp = &rq->sr; + + do { + /* + * If a callback is in progress, don't (re)try the + * command now. Try to start the callback or wait for + * it to complete before trying again. + */ + if (dk->dk_flags & (DK_NEED_CB | DK_HOLD)) { + dk_queue_release(dk); + dk_free_request(dk, rq); + goto again; + } + + memcpy(sp->sr_command, cmd_buffer, cmd_size); + sp->sr_cmdlen = cmd_size; + if (rw == READ) + sp->sr_flags |= SRF_DIR_IN; + if (addr != NULL) { + sp->sr_flags |= SRF_MAP; +#ifndef CONFIG_IA64 + if (rw == READ) + dma_cache_inv(addr, len); + else + dma_cache_wback(addr, len); +#endif + } + sp->sr_timeout = timeoutval; + sp->sr_buffer = (u_char *)addr; + sp->sr_buflen = len; + dk_sendcmd(dk, sp); + + } while (dk_chkcond(dk, sp, 0, 0) == 1); + + stat = (sp->sr_status || sp->sr_scsi_status); + + dk_queue_release(dk); + dk_free_request(dk, rq); + + return stat; +} + +/* + * Print interesting sense data. + * Extended sense data is all that is allowed. + */ +static void +dk_print_sense(struct dksoftc *dk, struct scsi_request *sp, int part) +{ + register char *key_msg, *add_msg; + register u_int sense_key, add_sense = 0; + u_int asq = 0; + u_char *sense_data = sp->sr_sense; + u_char sense_length = sp->sr_sensegotten; + u_int sense_lba, lba; + + /* Extended sense format */ + sense_key = sense_data[2] & 0xf; + if (sense_data[2] & 0x20) + dk_pmsg(dk, part, "unsupported block size requested\n"); + + if (sense_length > 12) + add_sense = sense_data[12]; + if (sense_length > 13) + asq = sense_data[13]; + + key_msg = scsi_key_msgtab[sense_key]; + if (add_sense == 0) + add_msg = NULL; + else if (add_sense < SC_NUMADDSENSE) + add_msg = scsi_addit_msgtab[add_sense]; + else { + /* + * 0x89 is vendor specific; + * This is the Toshiba XM3332 meaning. + */ + if(dk->dk_inqtyp[0] == XSCSI_PT_CDROM && add_sense == 0x89) + add_msg = "Tried to read audio track as data"; + else + add_msg = NULL; + } + + if (sense_key != SC_NOSENSE && sense_key != SC_UNIT_ATTN && + sense_key != SC_ERR_RECOVERED && sense_key != SC_NOT_READY) + dk_pmsg(dk, part, "[Alert] %s", key_msg); + else + dk_pmsg(dk, part, "%s", key_msg); + printk( ": %s (asc=0x%x, asq=0x%x)", add_msg ? add_msg : "", + add_sense, asq); + if(sense_data[0] & 1) /* in case buffer writes enabled! */ + printk( " (deferred error)"); + + /* SCSI-2 drives give more info if SKSV bit set */ + if(sense_length > 17 && sense_data[15] & 0x80) { + printk( ", (%s byte %d)", + (sense_data[15] & 0x40) ? "cmd" : "data", + (sense_data[16] << 8) | (sense_data[17])); + if(sense_data[15] & 0x8) + printk( " (bit %d)", + sense_data[15] & 0x7); + } + + /* If the valid bit is set, bytes 3-6 give addition info */ + if((sense_data[0] & 0x80) && (sense_length > 6)) { + struct dk_setinfo *set; + struct hd_struct *hd; + int drive; + + drive = dk->dk_disk_info->drive; + set = dk->dk_disk_info->setinfo; + hd = &set->hd[DK_MINOR(drive, part)]; + + sense_lba = (sense_data[3] << 24) | + (sense_data[4] << 16) | + (sense_data[5] << 8) | + (sense_data[6]); + + lba = (sense_lba - + (hd->start_sect >> (log2(dk->dk_blksz) - 9))); + /* + * Report both the block in the partition, and the + * disk block #, because fx wants to spare by disk + * block #, not relative to partition... + */ + printk( ", Block #%d", lba); + if(lba != sense_lba) + printk( " (%d)", sense_lba); + } +#ifdef SAMMY + if (sense_length > 31) { + printk(" addsense 18-31:"); + for (asq = 18; asq < 32; asq++) + printk(" 0x%x", sense_data[asq]); + } +#endif + + if (sense_key == SC_ILLEGALREQ) { + int i; + printk( " CDB:"); + for (i = 0; i < sp->sr_cmdlen; i++) + printk( " %x", sp->sr_command[i]); + } + printk( "\n"); +} + +/* + * This is used to retry a command when a drive returns busy; called from + * a timer. + */ +static void +dk_do_retry(register scsi_request_t *sp) +{ + struct dksoftc *dk; + struct dkrequest *rq; + + rq = (struct dkrequest *) sp->sr_dev; + dk = rq->disk_info->softc; + dksc_start(dk, rq, sp); +} + + +/* + * Return drive capacity in blocks. + */ +static unsigned int +dk_readcap(struct dksoftc *dk) +{ + unsigned int *drivecap; + unsigned int ret; + + drivecap = kmem_alloc(DK_DRIVECAP_SIZE, KM_SLEEP | KM_CACHEALIGN); + + /* dk_drivecap is dynamically allocated for proper cache-alignment + since it is used as a DMA buffer below */ + + if (dk_cmd(dk, dk_readcapacity, SC_CLASS1_SZ, DKSC_TIMEOUT, + (caddr_t) drivecap, DK_DRIVECAP_SIZE, READ)) { + ret = 0; + goto out; + } + + /* increment by one to get capacity, not last block */ + ret = be32_to_cpu(drivecap[0]) + 1; + dk->dk_drivecap = ret; +out: + kmem_free(drivecap, DK_DRIVECAP_SIZE); + return ret; +} + +/* + * This routine is used at open time if queueing is enabled for this drive. + * We check to make sure that the QERR bit is set. If it isn't, we clear + * the queueing bit. + */ +static void +dk_checkqueue(register struct dksoftc *dk) +{ + struct volume_header *dvh = NULL; + int dvhsize; + struct mode_sense_data *msd = NULL; + u_char scsi_cmd[SC_CLASS1_SZ]; + unsigned char qdepth; + uint qflag; + + dvhsize = max(dk->dk_blksz, (typeof(dk->dk_blksz)) sizeof(*dvh)); + if ((dvh = kmem_alloc(dvhsize, KM_SLEEP | KM_CACHEALIGN)) == NULL) + return; + memcpy(scsi_cmd, dk_read, sizeof(dk_read)); + scsi_cmd[8] = 1; + if (dk_cmd(dk, scsi_cmd, SC_CLASS1_SZ, DKSC_TIMEOUT, (caddr_t) dvh, dvhsize, READ)) + goto out; + if (be32_to_cpu(dvh->vh_magic) != VHMAGIC) + goto out; + + qdepth = dvh->vh_dp.dp_ctq_depth; + if (qdepth == 0) { +qoffout: + DKSCLOCK(dk); + dk->dk_flags &= ~DK_QUEUE; + dk->dk_qdepth = 1; + DKSCUNLOCK(dk); + goto out; + } + + qflag = dk->dk_target_info->si_ha_status; + msd = kmem_alloc(sizeof(*msd), KM_SLEEP | KM_CACHEALIGN); + if (msd == NULL) + goto out; + + memcpy(scsi_cmd, dk_mode_sense, sizeof(dk_mode_sense)); + scsi_cmd[2] = QUEUE_PARAM | CURRENT; + scsi_cmd[4] = sizeof(struct queueparam) + 12; + if (dk_cmd(dk, scsi_cmd, SC_CLASS0_SZ, DKSC_TIMEOUT, (caddr_t)msd, scsi_cmd[4], READ)) + goto qoffout; + + /* + * If the low level driver supports the same queue error setting as + * the device, allow queueing. + * If a driver allows either setting of QERR, tell the driver + * the setting of qerr for the drive so that it handles errors + * correctly. + */ + if (((msd->dk_pages.queueparam.q_err == 0) && + ((qflag & (SRH_TAGQ|SRH_QERR0)) == (SRH_TAGQ|SRH_QERR0))) || + ((msd->dk_pages.queueparam.q_err == 1) && + ((qflag & (SRH_TAGQ|SRH_QERR1)) == (SRH_TAGQ|SRH_QERR1)))) + { + if ((qflag & (SRH_TAGQ|SRH_QERR0|SRH_QERR1)) == (SRH_TAGQ|SRH_QERR0|SRH_QERR1)) + { + scsi_lun_info_t *lun_info; + struct scsi_ha_op *ha_ioctl; + + lun_info = dk->dk_disk_info->luninfo; + + ha_ioctl = kmem_zalloc(sizeof(*ha_ioctl), KM_SLEEP); + ha_ioctl->sb_opt = LUN_QERR; + ha_ioctl->sb_arg = (SLI_TARG(lun_info) << SOP_QERR_TARGET_SHFT) | + (SLI_LUN(lun_info) << SOP_QERR_LUN_SHFT) | + (msd->dk_pages.queueparam.q_err << SOP_QERR_VAL_SHFT); + SLI_IOCTL(lun_info)(SLI_CTLR_VHDL(lun_info), SOP_SET_BEHAVE, ha_ioctl); + kmem_free(ha_ioctl, sizeof(*ha_ioctl)); + } + + DKSCLOCK(dk); + dk->dk_flags |= DK_QUEUE; + dk->dk_qdepth = qdepth; + DKSCUNLOCK(dk); + } + else + { + DKSCLOCK(dk); + dk->dk_flags &= ~DK_QUEUE; + dk->dk_qdepth = 1; + DKSCUNLOCK(dk); + + if (qflag & SRH_TAGQ) + dk_pmsg(dk, 0, + "low level driver does not support QERR=%d\n", + msd->dk_pages.queueparam.q_err); + } + +out: + if (msd) kmem_free(msd, sizeof(*msd)); + if (dvh) kmem_free(dvh, dvhsize); +} + +/* + * This is used at open time to get the blksize, before the vh is read. + * After the vh is read, or when the vh ioctl's are used, the blksz + * from the vh is used. This routine is also called after the blocksize + * is potentially changed via ioctl. + * Since not all devices support the FORMAT page, ask for all pages; + * Uses the value from the block descr if supplied, since that + * location is correct for all drives, not just ccs or scsi2. If not, + * use the value from the format page. + * If modesense is successful, set or clear the WRTPROT bit. This is + * mainly for early detection of devices that are either write protected, + * or don't support the write command (such as CDROM). Otherwise may + * get SCSI errors. + * + * The return value is whether or not the actual blocksize changed from the + * blocksize value kept in the vh, even though at this actual moment it + * is not used. -mac +*/ +static int +dk_getblksz(register struct dksoftc *dk) +{ + struct mode_sense_data *msd; + u_char sense_cmd[SC_CLASS0_SZ]; + int blocksize = 0; + int return_value; + + msd = kmem_alloc(sizeof(*msd), KM_SLEEP | KM_CACHEALIGN); + + memcpy(sense_cmd, dk_mode_sense, sizeof(sense_cmd)); + sense_cmd[2] = msd->dk_pages.common.pg_code = ALL|CURRENT; + sense_cmd[4] = msd->dk_pages.common.pg_len = + sizeof(msd->dk_pages.common.pg_maxlen); + + if(dk_cmd(dk, sense_cmd, SC_CLASS0_SZ, DKSC_TIMEOUT, + (caddr_t)msd, sense_cmd[4], READ)) + goto failure; + + DKSCLOCK(dk); + if(msd->wprot) + dk->dk_flags |= DK_WRTPROT; + else + dk->dk_flags &= ~DK_WRTPROT; + DKSCUNLOCK(dk); + + if(msd->bd_len && (msd->block_descrip[5] || + msd->block_descrip[6] || msd->block_descrip[7])) + blocksize = ((unsigned)msd->block_descrip[5]<<16) + + ((unsigned)msd->block_descrip[6]<<8) + msd->block_descrip[7]; + else { /* see if format page is there */ + u_char *d = (u_char *)msd, *maxd = d + msd->sense_len; + d += msd->bd_len + 4; /* after setting maxd! */ + while(d < maxd) { + int i; + if(((*d) & ALL) == DEV_FORMAT) { + blocksize = + (((uint)((struct dev_format *)d)->f_bytes_sec[0])<<8) + + ((struct dev_format *)d)->f_bytes_sec[1]; + break; + } + i = d[1] + 2; /* skip to next page; +2 for hdr */ + d += i; + } + } + +failure: + if(blocksize == 0) { + if (dk->dk_blksz != 0) + dk_dbg_pmsg(dk, 0, + "blocksize changed from %d to %d\n", + dk->dk_blksz,blocksize); + blocksize = DK_BLK_SZ; /* best guess... */ + } + if ((return_value = (dk->dk_blksz != blocksize)) != 0) { + if (dk->dk_blksz != 0) + dk_dbg_pmsg(dk, 0, + "blocksize changed from %d to %d\n", + dk->dk_blksz,blocksize); + dk->dk_blksz = blocksize; + } + kmem_free(msd, sizeof(*msd)); + + return return_value; +} + + +/* +** dk_clr_flags and dk_set_flags used by failover.c +*/ +int +dk_clr_flags (vertex_hdl_t lun_vhdl, int dk_flags) +{ + int error = -1; + devfs_handle_t de; + struct dk_partinfo *partinfo; + struct dksoftc *dk; + + de = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + if (de) { + partinfo = devfs_get_info(de); + dk = partinfo->diskinfo->softc; + if (dk) { + DKSCLOCK(dk); + dk->dk_flags &= ~dk_flags; + DKSCUNLOCK(dk); + error = 0; + } + } + return error; +} + +int +dk_set_flags (vertex_hdl_t lun_vhdl, int dk_flags) +{ + int error = -1; + devfs_handle_t de; + struct dk_partinfo *partinfo; + struct dksoftc *dk; + + de = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + if (de) { + partinfo = devfs_get_info(de); + dk = partinfo->diskinfo->softc; + if (dk) { + DKSCLOCK(dk); + dk->dk_flags |= dk_flags; + DKSCUNLOCK(dk); + error = 0; + } + } + return error; +} + + +/* + * Receives callback notification. Currently only registered for CDROM + * devices. + */ +static void +dk_callback_frontend(vertex_hdl_t lun_vhdl, uint8_t *sense) +{ + struct dksoftc *dk; + devfs_handle_t de; + struct dk_partinfo *partinfo; + + /* + * We only care about UNIT ATTENTION + */ + if ((sense[2] & 0x0f) == 0x06) + { + de = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + partinfo = devfs_get_info(de); + dk = partinfo->diskinfo->softc; + + /* + * Make sure block size has been determined. If the + * blocksize is unknown at this point, don't do a + * callback !! + */ + if (dk->dk_blksz == 0) + return; + + /* + * Turn on the "need to set blocksize" flag; + * We take the lazy approach in that the command + * will be issued prior to the next regular command + * that would be issued. + */ + DKSCLOCK(dk); + dk->dk_flags |= DK_NEED_BLKSZ; + DKSCUNLOCK(dk); + } +} + +/* + * This routine is the backend of the lazy callback implementation, + * and is used for two purposes: + * 1. to set CD-ROM blocksize back to what it was prior to Unit Attention + * 2. to issue a start unit to a drive that is spun down + * + * Called with the dk_lock held. If wait is set, the lock will be released + * prior to calling drive_acquire, and will return with the lock released. + * + * If wait is set, we sleep until command is complete; otherwise command + * is scheduled and we return. + * Return Value: + * 1 - the command was successfully scheduled/completed + * 0 - the command was not scheduled/completed. + */ +static int +dk_callback_backend(struct dksoftc *dk, int wait) +{ + struct mode_sense_data *msd; + unsigned char *select_cmd; + struct scsi_request *sp; + scsi_lun_info_t *lun_info; + int temp; + int blksz = dk->dk_blksz; + ushort action; + + select_cmd = (unsigned char [SC_CLASS0_SZ]) + { [0] = 0x15, [1] = 0x10, [4] = 12 }; + + if (dk->dk_flags & DK_NEEDSTART) + action = DK_NEEDSTART; + else + action = DK_NEED_BLKSZ; + dk->dk_curq++; + + if (wait) { + dk->dk_flags |= DK_HOLD; + dk->dk_flags &= ~action; + DKSCUNLOCK(dk); + } + + dk_request_init(dk->dk_rq, dk->dk_disk_info); + sp = &dk->dk_rq->sr; + + /* + * There is a 12-byte buffer in the dksoftc structure for this + * mode select. The mode_sense_data structure is bigger, but no + * pages are used in this case, so only 12 bytes are required. + */ + if (action == DK_NEED_BLKSZ) { + msd = (struct mode_sense_data *) dk->msel_bd; /* only 12 bytes used */ + msd->bd_len = sizeof(msd->block_descrip); /* 1 descrip */ + msd->block_descrip[5] = (u_char)(blksz >> 16); + msd->block_descrip[6] = (u_char)(blksz >> 8); + msd->block_descrip[7] = (u_char)blksz; + } + + temp = 0; + do { + sp->sr_cmdlen = SC_CLASS0_SZ; + + if (action == DK_NEED_BLKSZ) { + memcpy(sp->sr_command, select_cmd, sp->sr_cmdlen); + sp->sr_buffer = (u_char *)msd; + sp->sr_buflen = select_cmd[4]; + sp->sr_flags |= SRF_FLUSH; + sp->sr_timeout = DKSC_TIMEOUT; + } + else /* (action == DK_NEEDSTART) */ { + memcpy(sp->sr_command, dk_startunit, SC_CLASS0_SZ); + sp->sr_buflen = 0; + /* + * Allow 240 seconds; based on drives that may have spinup delays + * set based on ID; ID 15 waits 15 * intv, where intv is typically + * 10-15 seconds; also allow a bit of slop. + */ + sp->sr_timeout = 240 * HZ; + if (temp++) + dk_pmsg(dk, 0, "Error on device spin up," + " retrying\n"); + else + dk_pmsg(dk, 0, "Device not ready, " + "spinning up\n"); + } + + if (wait) + dk_sendcmd(dk, sp); + else { + dk->dk_flags |= DK_HOLD; + dk->dk_flags &= ~action; + DKSCUNLOCK(dk); + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + sp->sr_notify = dk_callback_intr; + SLI_COMMAND(lun_info)(sp); + DKSCLOCK(dk); + return 1; + } + } while (dk_chkcond(dk, sp, 0, 0) == 1); + + temp = !(sp->sr_status || sp->sr_scsi_status); + + /* + * Release those waiting for callback to complete + */ + DKSCLOCK(dk); + if (action == DK_NEEDSTART) { + if (temp) { + dk->dk_flags &= ~DK_WONT_START; + dk_pmsg(dk, 0, "Device spun up successfully\n"); + } + else { + dk_pmsg(dk, 0, "Device spin up failed, unable" + " to use device -- corrective action necessary\n"); + dk->dk_flags |= DK_WONT_START; + dk_purgequeues(dk); + } + } + dk->dk_flags &= ~DK_HOLD; + __dk_queue_release(dk); + while (dk->dk_hold_count != 0) { + up(&dk->dk_hold); + dk->dk_hold_count--; + } + DKSCUNLOCK(dk); + + return temp; +} + +static void +dk_callback_intr(scsi_request_t *sp) +{ + register struct dksoftc *dk; + scsi_lun_info_t *lun_info; + ushort action; + + if (sp->sr_command[0] == 0x1B) + action = DK_NEEDSTART; + else + action = DK_NEED_BLKSZ; + + dk = ((struct dkrequest *) sp->sr_dev)->disk_info->softc; + if (dk_chkcond(dk, sp, 0, 0) == 1) { + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + if (action == DK_NEEDSTART) + dk_pmsg(dk, 0, + "Error spinning up device, retrying\n"); + SLI_COMMAND(lun_info)(sp); + return; + } + + DKSCLOCK(dk); + /* + * Check to see if callback is for Start Unit or Mode Select. + */ + if (action == DK_NEEDSTART) { + if (sp->sr_status || sp->sr_scsi_status) { + dk_pmsg(dk, 0, "Unable to spin up device, " + "device unusable -- corrective action necessary\n"); + dk->dk_flags |= DK_WONT_START; + dk_purgequeues(dk); + } + else { + dk->dk_flags &= ~DK_WONT_START; + dk_pmsg(dk, 0, "Device successfully spun up\n"); + } + } + + /* + * Release those waiting for callback to complete + */ + dk->dk_flags &= ~DK_HOLD; + __dk_queue_release(dk); + while (dk->dk_hold_count != 0) { + up(&dk->dk_hold); + dk->dk_hold_count--; + } + DKSCUNLOCK(dk); + return; +} + + +#ifndef DEBUG +/* + * In some cases we don't want the sense to be printed, e.g. a "medium + * not present" when the device is a CDROM. + */ +int +dk_user_printable_sense(struct dksoftc *dk, register scsi_request_t *sp, int mute) +{ + int rc = 1; + u_char key = sp->sr_sense[2] & 0xF; + u_char addsense = sp->sr_sense[12]; + uint slen = sp->sr_sensegotten; + + if (dk->dk_inqtyp[1] & 0x80) { /* is removeable */ + switch (key) { + case SC_NOT_READY: + if (slen > 12 && addsense == SC_MEDIA_ABSENT) { /* Medium not present */ + rc = 0; + } + break; + case SC_BLANKCHK: + /* This is to suppress sense data printout associated + with read command issued internally by dksc from + dkscopen while attempting to read volume header + */ + if (addsense == 0x64 && mute) { + rc = 0; + } + break; + default: + break; + } + } + /* + * Don't report 'recovered' errors on defect list; it means the drive doesn't + * support the requested format, and is responding with it's default format. + * We see this when we ask for logical block format, but drive doesn't support + * it, for example. We don't want to print that; fx will just fall back on + * alternate format. See bug #554444. IBM DDRS-39130W is one of those drives. + */ + else if (key==SC_ERR_RECOVERED && (addsense == 0x1c || addsense == SC_DEFECT_ERR)) + rc = 0; + /* + * Don't report 'drive not ready' if the command issued was + * a 'test unit ready'. + */ + else if (sp->sr_command[0] == 0 && addsense == SC_NOTREADY) + rc = 0; + + return(rc); +} +#endif + +struct file_operations dksc_char_ops = { + read: dksc_read, + write: dksc_write, + ioctl: dksc_ioctl, + open: dksc_open, + release: dksc_close, +#if DKSC_READV_WRITEV + readv: dksc_readv, + writev: dksc_writev +#endif +}; + +static struct block_device_operations dksc_blk_ops = { + open: dksc_open, + release: dksc_close, + ioctl: dksc_ioctl, +#if 0 + check_media_change: dksc_check_media_change, + revalidate: dksc_revalidate, +#endif +}; + +static struct gendisk dk_gendisk[DK_SETS] = +{ + [0 ... DK_SETS - 1] = + { + minor_shift: DK_DISK_SHIFT, + max_p: 1 << DK_DISK_SHIFT, + fops: &dksc_blk_ops + } +}; + +void +dkscinit(void) +{ + int i; + + for (i = 0; i < DK_SETS; i++) + add_gendisk(&dk_gendisk[i]); + + dkrequest_cachep = + kmem_cache_create("dksc_requests", sizeof(struct dkrequest), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + + dksc_proc_init(); + +#ifdef CONFIG_KDB + { static void dksc_kdb_init(void); dksc_kdb_init(); } +#endif + +#ifdef CONFIG_DUMP + register_dump_notifier(&dksc_dump_notifier); +#endif +} + +#ifdef CONFIG_DUMP +/* Callback for the dump stuff to let us know a dump is going to happen. + This is a generic registration and we will be notified for non-xscsi devices. + Blow away locks and clear the normal IO paths on the specified device for the + dump writes coming in via normal IO paths. Dont do any other IO. +*/ +static int +dksc_dump_notify(struct notifier_block *nb, unsigned long event, void *dump_device) +{ + struct dksoftc *dk; + scsi_lun_info_t *luninfo; + scsi_targ_info_t *targinfo; + scsi_ctlr_info_t *ctlrinfo; + struct dk_diskinfo *diskinfo; + struct dk_partinfo *partinfo; + vertex_hdl_t dev_vhdl; + devfs_handle_t de; + + if (!(event == DUMP_BEGIN || event == DUMP_TEST)) + return NOTIFY_DONE; + + /* decide if dump_device (kdev_t) is xscsi and get its vertex */ + de = devfs_find_handle(NULL, NULL, + MAJOR(*(kdev_t *)dump_device), + MINOR(*(kdev_t *)dump_device), + DEVFS_SPECIAL_BLK, 0); + + if (de == NULL) /* if its not devfs, its definitely not XSCSI */ + return NOTIFY_DONE; + + /* + * make sure the vertex belongs to dksc + */ + partinfo = devfs_get_info(de); + if (partinfo == NULL) + return NOTIFY_DONE; + if (partinfo->de != de) + return NOTIFY_DONE; + + /* + * do callbacks to the dump driver to indicate that interrupts + * should be disabled and that non-disruptive dumps wont work. + * These notifications are common for all targets. + */ + dump_nondisruptive_disable(); + dump_interrupts_disable(); + + if (event == DUMP_TEST) + return NOTIFY_DONE; + + dev_vhdl = (vertex_hdl_t) de; + diskinfo = partinfo->diskinfo; + dk = diskinfo->softc; + luninfo = diskinfo->luninfo; + targinfo = SLI_TARG_INFO(luninfo); + ctlrinfo = STI_CTLR_INFO(targinfo); + + /* + * send dump event down to target and give it the opportunity to + * clear locks and io path for the dump device. + */ + if (SCI_DUMP(ctlrinfo)(SCI_CTLR_VHDL(ctlrinfo)) == 0) + return NOTIFY_DONE; + + /* + * clobber the semaphores so we don't get stuck waiting; + * this is a panic situation anyway, so no more disk i/o + * will be done after the dump... Should abort/ignore + * any pending i/o on this device also, so it doesn't + * confuse things. + */ + init_waitqueue_head(&dk->dk_wait); + sema_init(&dk->dk_sema, 1); + sema_init(&dk->dk_done, 0); + sema_init(&dk->dk_hold, 0); + DKSCINITLOCK(dk); + dk->dk_iobuffree_lock = SPIN_LOCK_UNLOCKED; + + return NOTIFY_DONE; +} +#endif + + +#ifdef CONFIG_KDB +#undef printf +#include +#include + +static void +dk_dump_disks(void) +{ + int major, disk; + devfs_handle_t de; + struct dk_partinfo *partinfo; + struct dk_diskinfo *diskinfo; + struct dksoftc *dk; + char buffer[128]; + int index; + + for (major = 0; major < 256; major++) + for (disk = 0; disk < 1 << (MINORBITS - DK_DISK_SHIFT); disk++) { + de = dksc_de[major][disk]; + if (de == NULL) + continue; + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + dk = diskinfo->softc; + index = devfs_generate_path(de, buffer, 128); + if (index >= 0) + kdb_printf("(%d/%d) %s softc is 0x%p\n", + major, disk, &buffer[index], (void *) dk); + else + kdb_printf("(%d/%d) no-name softc is 0x%p\n", + major, disk, (void *) dk); + } +} + + +#if DKSC_EVENT_LOG +static void +dk_event_dump(struct dksoftc *dk) +{ + int i, end; + + i = end = dk->dk_event_rotor; + do { + if (dk->dk_event_buffer[i].string) + kdb_printf(" %s (%u, %u)\n", dk->dk_event_buffer[i].string, + dk->dk_event_buffer[i].aval, dk->dk_event_buffer[i].bval); + if (++i == DKSC_EVENT_LOG_SIZE) + i = 0; + } while (i != end); +} +#else +#define dk_event_dump(x) +#endif + +#define DKRQ_PER_LINE 4 +static void +dk_dump_queue(struct dkrequest *rq) +{ + int tmp; + + tmp = DKRQ_PER_LINE; + while (rq != NULL) { + kdb_printf(" %p(%u/%u/%d)", (void *) rq, rq->sector, rq->count, rq->merges); + rq = rq->av_forw; + if (--tmp == 0) { + kdb_printf("\n"); + tmp = DKRQ_PER_LINE; + } + } + if (tmp != DKRQ_PER_LINE) + kdb_printf("\n"); +} + +static int +dksoftc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct dksoftc *dk; + int tmp; + int nextarg; + long offset = 0; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + tmp = kdbgetaddrarg(argc, argv, &nextarg, (kdb_machreg_t *) &dk, &offset, NULL, regs); + if (tmp) + return tmp; + if (dk == NULL) { + dk_dump_disks(); + return 0; + } + + kdb_printf("dksoftc structure at 0x%p\n", (void *) dk); + + dk_event_dump(dk); + + kdb_printf("dk_iostart %lu dk_blksz %u dk_opencount %d dk_flags 0x%x dk_request_queue.plugged %d\n", + dk->dk_iostart, dk->dk_blksz, dk->dk_opencount, dk->dk_flags, dk->dk_request_queue.plugged); + kdb_printf("dk_inqtyp 0x%p dk_rq 0x%p dk_numrq %d\n", + (void *) dk->dk_inqtyp, (void *) dk->dk_rq, + dk->dk_request_queue.rq[0].count); + kdb_printf("&dk_wait 0x%p &dk_sema 0x%p &dk_done 0x%p\n", + (void *) &dk->dk_wait, (void *) &dk->dk_sema, (void *) &dk->dk_done); + kdb_printf("&dk_hold 0x%p dk_hold_count %d dk_retry 0x%p\n", + (void *) &dk->dk_hold, dk->dk_hold_count, (void *) dk->dk_retry); + kdb_printf("&dk_request_queue 0x%p dk_target_info 0x%p dk_cb 0x%p\n", + (void *) &dk->dk_request_queue, (void *) dk->dk_target_info, (void *) dk->dk_cb); + + kdb_printf("dk_queue at 0x%p seq_next %u seq_count %u\n", + (void *) &dk->dk_queue, dk->dk_queue.seq_next, dk->dk_queue.seq_count); + + kdb_printf("read queue head/tail 0x%p/0x%p\n", + (void *) dk->dk_queue.io_head, (void *) dk->dk_queue.io_tail); + dk_dump_queue(dk->dk_queue.io_head); + + kdb_printf("write queue head/tail 0x%p/0x%p\n", + (void *) dk->dk_queue.delwri_head, (void *) dk->dk_queue.delwri_tail); + dk_dump_queue(dk->dk_queue.delwri_head); + + kdb_printf("active queue: (%d/%d commands - %d requests in flight)\n", + dk->dk_curq, dk->dk_qdepth, dk->dk_rqactive); + dk_dump_queue(dk->dk_active); + + return 0; +} + +static void +dksc_kdb_init(void) +{ + kdb_register("dksoftc", dksoftc, "", "dump dksoftc structure", 0); +} +#endif diff -Nur linux-2.4.19/drivers/xscsi/dksc.h linux-2.4.19-sgi211r3/drivers/xscsi/dksc.h --- linux-2.4.19/drivers/xscsi/dksc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/dksc.h Wed Jan 29 23:54:26 2003 @@ -0,0 +1,442 @@ +/* + * + * + * Copyright (c) 1986-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +#define log2(x) ffz(~(x)) + +/* + * Macros for mutual exclusion lock. + */ +#if 0 +#define DKSCLOCK(dk) down(&dk->dk_lock) +#define DKSCUNLOCK(dk) up(&dk->dk_lock) +#define DKSCINITLOCK(dk) sema_init(&dk->dk_lock, 1) +#define DKSCDELETELOCK(dk) +#define DKSCLOCKDECLARE struct semaphore dk_lock +#else +#if 0 +#define DKSCLOCK(dk) spin_lock_irqsave(&dk->dk_lock, dk->dk_intrflags) +#define DKSCUNLOCK(dk) spin_unlock_irqrestore(&dk->dk_lock, dk->dk_intrflags) +#define DKSCLOCKDECLARE spinlock_t dk_lock; unsigned long dk_intrflags +#else +#define DKSCLOCK(dk) spin_lock(&dk->dk_lock) +#define DKSCUNLOCK(dk) spin_unlock(&dk->dk_lock) +#define DKSCLOCKDECLARE spinlock_t dk_lock +#endif +#define DKSCINITLOCK(dk) dk->dk_lock = SPIN_LOCK_UNLOCKED +#define DKSCDELETELOCK(dk) +#endif + +/* values for dk_flags */ +#define DK_WRTPROT 0x0001 /* drive is write protected */ +#define DK_QUEUE 0x0002 /* queueing allowed to drive */ +#define DK_WONT_START 0x0004 /* device fails attempts to start */ +#define DK_MAPUSER 0x0010 /* can map user addresses */ +#define DK_NEEDSTART 0x0020 /* needs a startunit cmd */ +#define DK_RECURSE 0x0200 /* If set have recursion thru dkrelsubchan */ +#define DK_ALENLIST 0x0400 /* Alenlist can be delivered with scsireq */ +#define DK_NEED_BLKSZ 0x0800 /* Need to set blocksize */ +#define DK_HOLD 0x1000 /* Hold commands to device -- backend callback in progress */ +#define DK_NEED_CB (DK_NEEDSTART | DK_NEED_BLKSZ) +#define DK_FAILOVER 0X2000 /* Path failover -- biodone the dk_queue + Reject incoming requests for this device. + Set/cleared by failover_switch. */ + + +/* + * By powers of 2, allows tracking request sizes up to 256 blocks; + * larger requests are included in last bucket. This is multiples + * of blocks for that drive, it is not in terms of any particular + * block size. Currently implemented only for dksc scsi disk driver. + * Returned per drive, not per partition. Only ifdef DEBUG +*/ +#define NUM_BLK_BUCKETS 9 +struct disk_blkstats { + uint bk_reads[NUM_BLK_BUCKETS]; + uint bk_writes[NUM_BLK_BUCKETS]; +}; + +struct dkrequest +{ + unsigned char sensedata[SCSI_SENSE_LEN]; /* cache aligned */ + unsigned char cmddata[SC_CLASS1_SZ]; + + int retry_count; + + struct dkrequest *av_forw; /* sort queue */ + struct dkrequest *av_back; + + struct list_head free_table; + struct list_head *free_list; + + int cmd; /* command (read/write) */ + unsigned int sector; /* sector number (based on dk_blksz) */ + unsigned int count; /* count (in dk_blksz chunks) */ + int merges; + + int drive; + int part; /* partition number */ + int b_resid; /* amount of data not transferred */ + + struct buffer_head *bh; + struct buffer_head *bhlast; + struct kiobuf *iobuf; + request_queue_t *q; + + struct dk_diskinfo *disk_info; + + scsi_request_t sr; + + struct timer_list timer; + struct alenlist_s alenlist; +}; + +struct diskqueue +{ + struct dkrequest *io_head; /* head of I/O queue */ + struct dkrequest *io_tail; /* tail of I/O queue */ + uint32_t io_prev; /* block # of previous command */ + uint32_t seq_next; /* next sequential request */ + int seq_count; /* count of sequential requests */ + int delwri_holdoff; /* delwri fairness variable */ + struct dkrequest *delwri_head; /* head of delwri queue */ + struct dkrequest *delwri_tail; /* tail of delwri queue */ + uint32_t delwri_prev; /* block # of previous command */ +}; + +/* + * Software state per disk drive. + */ +struct dksoftc { + time_t dk_iostart; /* 'start' time for sar measurements */ + + uint dk_drivecap; + uint dk_blksz; /* logical (from drive) blocksize of device */ + int dk_opencount; /* number of layered opens */ + ushort dk_flags; + u_char dk_qdepth; /* command queue depth */ + u_char dk_curq; /* current number of queued commands */ + u_char *dk_inqtyp; /* devtype from first byte of inquiry data */ + + struct dkrequest *dk_rq; /* for callback backend */ + int dk_rqactive; + + DKSCLOCKDECLARE; /* Lock to protect structure fields */ + wait_queue_head_t dk_wait; /* queue for internal commands */ + struct semaphore dk_sema; /* mutex for use of dk_done sema */ + struct semaphore dk_done; /* for synchronous I/O */ + struct semaphore dk_hold; /* used when DK_HOLD set */ + int dk_hold_count; /* number of holders */ + + struct diskqueue dk_queue; /* wait queue */ + struct dkrequest *dk_active; /* active queue */ + struct dkrequest *dk_retry; /* deferred retry queue */ + request_queue_t dk_request_queue; /* linux request queue */ + + struct dk_diskinfo *dk_disk_info; /* info for disk */ + scsi_target_info_t *dk_target_info; + void (*dk_cb)(vertex_hdl_t, uint8_t *); /* Sense callback function */ + u_char msel_bd[12]; /* placeholder for blocksize modeselect */ + + struct kiobuf *dk_freeiobuf; + spinlock_t dk_iobuffree_lock; + int dk_iobuf_count; +#if DKSC_EVENT_LOG + #define DKSC_EVENT_LOG_SIZE 200 + struct { + char *string; + uint aval; + uint bval; + } dk_event_buffer[DKSC_EVENT_LOG_SIZE]; + uint dk_event_rotor; +#endif +}; + +/* used for dk_inqtype and dk_drivecap, respectively */ +#define DK_INQTYP_SIZE 4 +#define DK_DRIVECAP_SIZE 8 + + +/* + * This structure is used by the mode select/get ioctls to determine + * where the data is to be sent to/recieved from. + */ +struct dk_ioctl_data { + caddr_t i_addr; + u_int i_len; + u_char i_page; /* Page code is used only on mode select */ +}; + +/* Maximum amount of data allowed by an ioctl cmd */ +#define MAX_IOCTL_DATA 4096 + +/* These are the possible page codes used by mode sense/get */ +#define ERR_RECOV 0x1 +#define CONN_PARMS 0x2 +#define DEV_FORMAT 0x3 +#define DEV_GEOMETRY 0x4 +#define DEV_FDGEOMETRY 0x5 /* geometry for SMS flexible disks */ +#define BLOCK_DESCRIP 0x7 /* TOSHIBA MK156FB only */ +#define VERIFY_ERR 0x7 /* SCSI 2 Verify error recovery page */ +#define CACHE_SCSI2 0x8 /* SCSI 2 cache control */ +#define QUEUE_PARAM 0xA /* SCSI 2 queue parameters */ +#define NOTCH_SCSI2 0xC /* SCSI 2 notch page */ +#define CACHE_CONTR 0x38 /* CDC Wren IV/V/VI drives */ +#define ALL 0x3f + +/* These are the page control field values recognized by the mode sense cmd */ +#define CURRENT 0 +#define CHANGEABLE (0x1 << 6) +#define DEFAULT (0x2 << 6) +#define SAVED (0x3 << 6) + +#if defined(__LITTLE_ENDIAN) +#define BITFIELD_DECL2(A0, A1) A1, A0 +#define BITFIELD_DECL3(A0, A1, A2) A2, A1, A0 +#define BITFIELD_DECL4(A0, A1, A2, A3) A3, A2, A1, A0 +#define BITFIELD_DECL5(A0, A1, A2, A3, A4) A4, A3, A2, A1, A0 +#define BITFIELD_DECL6(A0, A1, A2, A3, A4, A5) A5, A4, A3, A2, A1, A0 +#define BITFIELD_DECL7(A0, A1, A2, A3, A4, A5, A6) A6, A5, A4, A3, A2, A1, A0 +#define BITFIELD_DECL8(A0, A1, A2, A3, A4, A5, A6, A7) A7, A6, A5, A4, A3, A2, A1, A0 +#endif + +/* + * These are the pages of the drive parameter set/get commands. + * Note that all of the struct should be allocated to the full + * size of the union, since we determine their sizes at run time, + * due to the possiblity of different page sizes on different + * mfg drives. This is normally done by using ptrs to the structs, + * and setting them to point to the dk_pages member of a struct mode_sense_data. + * Any 'extra' bytes won't be changed by programs like fx, but most + * drives require that the pages being set by a mode select be + * the correct size and have valid data for bytes that aren't + * changed (usually retrieved via a mode sense into the same buffer). + */ +union dk_pages { + struct common { + u_char pg_code; + u_char pg_len; + u_char pg_maxlen[0x100-2]; /* make room for max possible page len */ + } common; + struct err_recov { + u_char e_pgcode; + u_char e_pglen; + u_char e_err_bits; + u_char e_retry_count; + /* rest are spec'ed in scsi2, not supported by most drives yet */ + u_char e_rdretry; + u_char e_corrspan; + u_char e_headoffset; + u_char e_strobeoffset; + u_char e_rsv0; + u_char e_wrretry; + u_char e_rsv1; + u_char e_recovtime[2]; + } err_recov; + struct connparms { + u_char c_pgcode; + u_char c_pglen; + u_char c_bfull; + u_char c_bempty; + u_char c_binacthi; + u_char c_binactlo; + u_char c_disconhi; + u_char c_disconlo; + u_char c_reserv[2]; + } cparms; + struct dev_format { + u_char f_pgcode; + u_char f_pglen; + u_char f_trk_zone[2]; + u_char f_altsec[2]; + u_char f_alttrk_zone[2]; + u_char f_alttrk_vol[2]; + u_char f_sec_trac[2]; + u_char f_bytes_sec[2]; + u_char f_interleave[2]; + u_char f_trkskew[2]; + u_char f_cylskew[2]; + u_char f_form_bits; + u_char f_reserved4[3]; + } dev_format; + struct dev_geometry { /* page 4 for winchesters */ + u_char g_pgcode; + u_char g_pglen; + u_char g_ncyl[3]; + u_char g_nhead; + u_char g_wrprecomp[3]; + u_char g_reducewrcur[3]; + u_char g_steprate[2]; + u_char g_landing[3]; + u_char BITFIELD_DECL2(g_reserved1:7, g_spindlesync:1); + u_char g_rotatoff; + u_char g_reserved2; + u_char g_rotatrate[2]; + u_char g_reserved3[2]; + } dev_geometry; + struct dev_fdgeometry { /* page 5 for floppies */ + u_char g_pgcode; + u_char g_pglen; + u_char g_trate[2]; + u_char g_nhead; + u_char g_spt; + u_char g_bytes_sec[2]; + u_char g_ncyl[2]; + u_char g_wprcomp[2]; + u_char g_wrcurr[2]; + u_char g_steprate[2]; + u_char g_steppulsewidth; + u_char g_headset[2]; + u_char g_moton; + u_char g_motoff; + u_char BITFIELD_DECL4(g_trdy:1, g_ssn:1, g_mo:1, g_reserv0:5); + u_char BITFIELD_DECL2(g_reserv1:4, g_stpcyl:4); + u_char g_wrprecomp; + u_char g_headld; + u_char g_headunld; + u_char BITFIELD_DECL2(g_pin34:4, g_pin2:4); + u_char BITFIELD_DECL2(g_pin4:4, g_pin1:4); /* pin 1 TEAC, reserved on NCR */ + u_char g_reserv2[4]; + } dev_fdgeometry; + struct block_descrip { /* Toshiba 156 FB only */ + u_char b_pgcode; + u_char b_pglen; + u_char b_reserved0; + u_char b_bdlen; + u_char b_density; + u_char b_reserved1[3]; + u_int b_blen; /* This is actually a 3 byte val; high + byte reserved */ + } block_descrip; + struct verify_err { /* scsi 2 error recovery params */ + u_char v_pgcode; + u_char v_pglen; + u_char BITFIELD_DECL5(rsv0:4, eer:1, per:1, dte:1, dcr:1); + u_char v_retry; + u_char v_corrspan; + u_char v_rsv1[5]; + u_char v_recovtime[2]; + } verify_err; + struct cachescsi2 { /* scsi 2 cache ctrl page */ + u_char c_pgcode; + u_char c_pglen; + u_char BITFIELD_DECL4(c_rsrv:5, c_wce:1, c_mf:1, c_rcd:1); + u_char BITFIELD_DECL2(c_rdpri:4, c_wrpri:4); + u_char c_predislen[2]; + u_char c_minpre[2]; + u_char c_maxpre[2]; + u_char c_maxpreceil[2]; + u_char BITFIELD_DECL4(c_fsw:1, /* force seq write */ + c_rsrv2:1, /* not yet in rev 10H */ + c_dra:1, /* disable readahead; not yet in rev 10H */ + c_rsrv3:5); /* not yet in rev 10H */ + u_char c_numseg; + u_char c_cachsize[2]; /* cache seg size; not yet in rev 10H */ + u_char c_rsv5; /* not yet in rev 10H */ + u_char c_ncachsize[3]; /* non-cache seg size; not yet in rev 10H */ + } cachescsi2; + struct queueparam { /* scsi 2 queue parameter page */ + u_char q_pgcode; + u_char q_pglen; + u_char BITFIELD_DECL2(q_rsrv1:7, q_rlec:1); + u_char BITFIELD_DECL4(q_algorthm_mod:4, q_rsrv2:2, q_err:1, q_disable:1); + u_char BITFIELD_DECL5(q_eeca:1, q_rsrv3:4, q_raenp:1, q_uaaenp:1, q_eaenp:1); + u_char q_rsrv4; + u_char q_ready_aen_holdoff[2]; + } queueparam; + struct notch { /* info for 'zone bit recorded' devices */ + u_char n_pgcode; + u_char n_pglen; + u_char BITFIELD_DECL3(n_nd:1, n_lpn:1, n_rsv0:6); + u_char n_rsv1; + u_char n_maxnotch[2]; + u_char n_actnotch[2]; + u_char n_startbound[2]; + u_char n_endbound[2]; + u_char n_pagesnotched[2]; + } notch; + struct cachectrl { /* CDC Wren IV/V/VI cache control */ + u_char c_pgcode; + u_char c_pglen; + u_char BITFIELD_DECL5(c_ccen:1, c_wie:1, c_ssm:1, c_ce:1, c_ctsize:4); + u_char c_prefetch; + u_char c_maxpre; + u_char c_maxpremult; + u_char c_minpre; + u_char c_minpremult; + u_char c_reserv[8]; + } cachctrl; +}; + +/* Error recovery flag byte bits for e_err_bits */ +#define E_DCR 0x1 +#define E_DTE 0x2 +#define E_PER 0x4 +#define E_RC 0x10 +#define E_TB 0x20 +#define E_ARRE 0x40 +#define E_AWRE 0x80 + +/* The data structure of the mode sense command */ +struct mode_sense_data { + u_char sense_len; + u_char mediatype; + u_char BITFIELD_DECL4(wprot:1, reserv0:2, dpofua:1, reserv1:4); + u_char bd_len; + u_char block_descrip[8]; /* note that this field will NOT be supplied + by some drives, so that dk_pages data may actually start at this + offset; check the bd_len value! */ + union dk_pages dk_pages; +}; + +/* The structure of the mode select command */ +struct mode_select_data { + u_char reserv0; + u_char mediatype; + u_char BITFIELD_DECL2(wprot:1, reserv1:7); + u_char blk_len; /* This will normally be set to 0 */ + union dk_pages dk_pages; +}; + +struct defect_header { + u_char reserved0; + u_char format_bits; + u_char defect_listlen[2]; +}; + +struct defect_entry { + u_char def_cyl[3]; + u_char def_head; + u_char def_sector[4]; /* bytes from index, or sector */ +}; diff -Nur linux-2.4.19/drivers/xscsi/dvh.h linux-2.4.19-sgi211r3/drivers/xscsi/dvh.h --- linux-2.4.19/drivers/xscsi/dvh.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/dvh.h Fri Jan 3 08:28:29 2003 @@ -0,0 +1,189 @@ +#ident "$Revision: 3.26 $" + +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* + * Copyright 1985 by MIPS Computer Systems, Inc. + */ + +/* + * dvh.h -- disk volume header + */ + +/* + * Format for volume header information + * + * The volume header is a block located at the beginning of all disk + * media (sector 0). It contains information pertaining to physical + * device parameters and logical partition information. + * + * The volume header is manipulated by disk formatters/verifiers, + * partition builders (e.g. fx, dvhtool, and mkfs), and disk drivers. + * + * Previous versions of IRIX wrote a copy of the volume header is + * located at sector 0 of each track of cylinder 0. These copies were + * never used, and reduced the capacity of the volume header to hold large + * files, so this practice was discontinued. + * The volume header is constrained to be less than or equal to 512 + * bytes long. A particular copy is assumed valid if no drive errors + * are detected, the magic number is correct, and the 32 bit 2's complement + * of the volume header is correct. The checksum is calculated by initially + * zeroing vh_csum, summing the entire structure and then storing the + * 2's complement of the sum. Thus a checksum to verify the volume header + * should be 0. + * + * The error summary table, bad sector replacement table, and boot blocks are + * located by searching the volume directory within the volume header. + * + * Tables are sized simply by the integral number of table records that + * will fit in the space indicated by the directory entry. + * + * The amount of space allocated to the volume header, replacement blocks, + * and other tables is user defined when the device is formatted. + */ + +/* + * device parameters are in the volume header to determine mapping + * from logical block numbers to physical device addresses + * alignment of fields has to remain as it used to be, so old drive + * headers still match. + */ +struct device_parameters { + unsigned char dp_unused1[4]; + unsigned short _dp_cylinders; /* backwards compat only, so older + prtvtoc, fx, etc. don't have problems when drives moved around. + Don't count it being filled in in the future. It and _heads, and + _sect are deliberately named differently than the old fields in + their positions */ + unsigned short dp_unused2; + unsigned short _dp_heads; /* backwards compat only */ + unsigned char dp_ctq_depth; /* Depth of CTQ queue */ + unsigned char dp_unused3[3]; + unsigned short _dp_sect; /* backwards compat only */ + unsigned short dp_secbytes; /* length of sector in bytes */ + unsigned char dp_unused4[2]; + int dp_flags; /* flags used by disk driver */ + unsigned char dp_unused5[20]; + unsigned int dp_drivecap; /* drive capacity in blocks; + this is in a field that was never used for scsi drives, + prior to irix 6.3, so it will often be zero. + When found to be zero, or whenever drive capacity changes, + this is reset by fx; programs should not rely on this being + non-zero, since older drives might well never have had this + newer fx fx run on them. */ +}; + +/* + * Device characterization flags + * (dp_flags) + */ +#define DP_CTQ_EN 0x00000040 /* enable command tag queueing */ + +/* + * Boot blocks, bad sector tables, and the error summary table, are located + * via the volume_directory. + */ +#define VDNAMESIZE 8 + +struct volume_directory { + char vd_name[VDNAMESIZE]; /* name */ + int vd_lbn; /* logical block number */ + int vd_nbytes; /* file length in bytes */ +}; + +/* + * partition table describes logical device partitions + * (device drivers examine this to determine mapping from logical units + * to cylinder groups, device formatters/verifiers examine this to determine + * location of replacement tracks/sectors, etc) + * + * NOTE: pt_firstlbn SHOULD BE CYLINDER ALIGNED + */ +struct partition_table { /* one per logical partition */ + unsigned int pt_nblks; /* # of logical blks in partition */ + unsigned int pt_firstlbn; /* first lbn of partition */ + int pt_type; /* use of partition */ +}; + +#define PTYPE_VOLHDR_DFLTSZ 4096 /* default volhdr size is this many + blocks. Used by sash "disksetup=true" and fx "standard" setup. + Defined here to be sure it remains the same in both places (issue + with fx -s mode in miniroot, primarily). */ + +#define PTYPE_VOLHDR 0 /* partition is volume header */ +/* 1 and 2 were used for drive types no longer supported */ +#define PTYPE_RAW 3 /* partition is used for data */ +/* 4 and 5 were for filesystem types we haven't ever supported on MIPS cpus */ +#define PTYPE_VOLUME 6 /* partition is entire volume */ +#define PTYPE_EFS 7 /* partition is sgi EFS */ +#define PTYPE_LVOL 8 /* partition is part of a logical vol */ +#define PTYPE_RLVOL 9 /* part of a "raw" logical vol */ +#define PTYPE_XFS 10 /* partition is sgi XFS */ +#define PTYPE_XFSLOG 11 /* partition is sgi XFS log */ +#define PTYPE_XLV 12 /* partition is part of an XLV vol*/ +#define NPTYPES 16 + +#define VHMAGIC 0xbe5a941 /* randomly chosen value */ +#define NPARTAB 16 /* 16 unix partitions */ +#define NVDIR 15 /* max of 15 directory entries */ +#define BFNAMESIZE 16 /* max 16 chars in boot file name */ + +/* Partition types for ARCS */ +#define NOT_USED 0 /* Not used */ +#define FAT_SHORT 1 /* FAT filesystem, 12-bit FAT entries */ +#define FAT_LONG 4 /* FAT filesystem, 16-bit FAT entries */ +#define EXTENDED 5 /* extended partition */ +#define HUGE 6 /* huge partition- MS/DOS 4.0 and later */ + +/* Active flags for ARCS */ +#define BOOTABLE 0x00; +#define NOT_BOOTABLE 0x80; + +struct volume_header { + int vh_magic; /* identifies volume header */ + short vh_rootpt; /* root partition number */ + short vh_swappt; /* swap partition number */ + char vh_bootfile[BFNAMESIZE]; /* name of file to boot */ + struct device_parameters vh_dp; /* device parameters */ + struct volume_directory vh_vd[NVDIR]; /* other vol hdr contents */ + struct partition_table vh_pt[NPARTAB]; /* device partition layout */ + int vh_csum; /* volume header checksum */ + int vh_fill; /* fill out to 512 bytes */ +}; + +#if _KERNEL +extern int is_vh(register struct volume_header *); +extern int vh_checksum(struct volume_header *); +#endif /* _KERNEL */ diff -Nur linux-2.4.19/drivers/xscsi/ide.c linux-2.4.19-sgi211r3/drivers/xscsi/ide.c --- linux-2.4.19/drivers/xscsi/ide.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/ide.c Fri Jan 31 14:53:10 2003 @@ -0,0 +1,6344 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +//#define IOC4_DMA_BUG 1 + +#define IDE_PCIIO_DMA_A64 0 + +#ifndef IDE_CMD_DEBUG +#define IDE_CMD_DEBUG 1 +#endif + +#define IDE_PCIIO_BYTE_STREAM PCIIO_BYTE_STREAM +#define IDE_PCIIO_WORD_VALUES PCIIO_WORD_VALUES +#define IDE_CACHELINE_SIZE 128 + +#ifdef linux +#define XSCSI +#include "ide.h" +#else +#include "sys/ide.h" +#endif + +#ifdef XSCSI +#if BITS_PER_LONG == 64 +#define LLX "%lx" +#define IDE_PTR "%p" +#define VERT "%p" +#else +#define LLX "%Lx" +#define IDE_PTR "%p" +#define VERT "%p" +#endif + +alenaddr_t xide_mapped[258]; +int xide_map_in=0; +int xide_map_out=0; +int xide_unload_cmd_pending=0; + + +#else // Irix + +#define LLX "%llx" +#define IDE_PTR "%x" +#define VERT "%x" + +int xide_devflag = D_MP | D_ASYNC_ATTACH; + +#endif + +#ifdef IDE_CMD_DEBUG +xide_cmd_dbg_t xide_cmd_list[IDE_CMD_IDX_SZ]; +int xide_cmd_wrap = 0; +int xide_cmd_index = 0; +#endif +int xidedebug = 0; +int xide_error = 5; +int xide_ioc4_rev = 46; + +xide_ProtoInfo_t *xide_proto_list=NULL; +int xide_proto_num = 0; +mutex_t xide_connect_sema; + +static void ata_fake_scsi_cmd(scsi_request_t *req); +int scsi_to_ata(scsi_request_t *req, command_regs_t *cmdblk); +static int xide_poll_ioc4(xide_ProtoInfo_t *pi); +static void xide_co_free_dmamap(xide_CmdObj_t *co); +static void IDE_DBG(int debuglevel, char *format, ...); +static void xide_done(struct scsi_request *req); +static vertex_hdl_t xide_proto_add(xide_ProtoInfo_t *pi); +static int xide_probe(xide_ProtoInfo_t *pi); +static int xide_xidentifyDev(xide_LunInfo_t *li); +static void xide_unalloc_lun(xide_LunInfo_t *li, void *lock_to_unlock); +static int xide_bus_reset(xide_ProtoInfo_t *pi); +static void xide_queue_scsireq(xide_LunInfo_t *li, scsi_request_t *req); +static int xide_piocommand(xide_LunInfo_t *pi, command_regs_t *cmdSent, int bytes, uint16_t *buffer, int cmd_type,xide_CmdObj_t *co); +static void xide_requestsense_done(scsi_request_t *req); +static xide_TargInfo_t *xide_target_add(xide_ProtoInfo_t *pi, uint8_t number); +static void xide_finish_scsireq(xide_LunInfo_t *li, scsi_request_t *req); +static xide_LunInfo_t *xide_add_lun(struct xide_TargInfo_s *ti, int lun_Num); +static int xide_alloc_cmd_object(xide_ProtoInfo_t *pi); +static void xide_test_co_for_free(xide_CmdObj_t *co); +static void xide_remove_co(xide_CmdObj_t *co); +static scsi_request_t *xide_get_requestsense(xide_CmdObj_t *co); +static xide_CmdObj_t *xide_get_co_from_tag(uint8_t tag,xide_LunInfo_t *li); +static xide_ProtoInfo_t *xide_proto_info_proto_get(vertex_hdl_t proto_vhdl); +static int xide_setMode(xide_LunInfo_t *li); +static void xide_queue_scsireq_top(xide_LunInfo_t *li, scsi_request_t *req); +static scsi_request_t *xide_fix_mode_cmd_xmt(scsi_request_t *req); +static void xide_capacity_done(scsi_request_t *req); +static scsi_request_t *xide_get_capacity(xide_LunInfo_t *li, scsi_request_t *orig_req, u_char *cap_data); +static int xide_fix_mode_cmd_rcv(scsi_request_t *req, xide_CmdObj_t *co, int scsi_status); +static int xide_start1(xide_ProtoInfo_t *pi); +static int xide_pktDMA_start(xide_CmdObj_t *co, uint8_t command); +static int xide_scsi_resp_back( xide_CmdObj_t *co); +static void xide_return_lun_cmds(xide_LunInfo_t *li, int rtn_status); +static int xide_pktDMA_complete(xide_ProtoInfo_t *pi); +static int xide_send_co (xide_CmdObj_t *co); +static int xide_dma_init(xide_LunInfo_t *li); +static int xide_get_co_tag(xide_LunInfo_t *li); +static void xide_return_free_co(xide_ProtoInfo_t *pi, xide_CmdObj_t *co); +static void xide_return_co_resources(xide_CmdObj_t *co); +static int xide_maplist(xide_ProtoInfo_t *pi, xide_CmdObj_t *co, void *sgmap, int npgs); +static int xide_getmap(xide_ProtoInfo_t *pi, scsi_request_t *req); +static int xide_getmapsize(scsi_request_t *req); +static xide_CmdObj_t *xide_get_cmd_obj(xide_ProtoInfo_t *pi); +static scsi_request_t *xide_dequeue_scsireq(xide_LunInfo_t *li); +static void xide_done(struct scsi_request *req); +static xide_LunInfo_t *xide_get_intr_lun(xide_ProtoInfo_t *pi); +static void xide_return_finished_req(xide_ProtoInfo_t *pi); +static void xide_complete_a_req(xide_LunInfo_t *li, scsi_request_t *req); +static uint32_t xide_byte_swap(uint32_t value); +static uint64_t xide_byte_swap64(uint64_t value); +static int xide_get_status(xide_ProtoInfo_t *pi, uint8_t *status, int timeout_secs); +struct scsi_target_info *xide_info(vertex_hdl_t lun_vhdl); +static inline void xide_delay(long ticks); + +#if 0 // NOT YET USED +static int xide_remove_lun(xide_LunInfo_t *li, void *lock_to_unlock); +static int xide_autopoll(xide_LunInfo_t *li); +static int xide_pktPIO_data(xide_CmdObj_t *co); +static void xide_remove_target(xide_TargInfo_t *ti); +static void xide_swap(uint16_t *buffer, int length); +#endif + +#ifdef XSCSI +static atomic_t xide_intrthreadcount; +static atomic_t xide_intr_watch_threadcount; +int xide_intr_thread(void *ptr); +int xide_intr_watch_thread(void *ptr); +void xide_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused); +#else +static void print_xide_pciconfig(xide_pciconfig_t *pci_conf); +#endif + +#if 0 +static void xide_swap(uint16_t *buffer, int length) +{ + int i; + uint16_t temp1,temp2; + + for (i=0;i>8); + } + return; +} +#endif + +static uint32_t xide_byte_swap(uint32_t value) +{ +#ifndef XSCSI + return (((value & 0x000000FF)<<24)|((value & 0x0000FF00)<<8)|((value & 0x00FF0000)>>8)|((value & 0xFF000000)>>24)); +#else + return value; +#endif +} + +static uint64_t xide_byte_swap64(uint64_t value) +{ + return value; +#if 0 +#ifndef XSCSI + return value; + +#else + + uint64_t temp1=0,temp2=0,temp=0; + uint32_t tmp1=0, tmp2=0; + + tmp1 = (uint32_t)(value >> 32); + tmp2 = (uint32_t)(value); + + IDE_DBG(11,"byteswap64() :value_orig 0x%x | tmp1 0x%x | tmp2 0x%x ",value,(uint64_t)tmp1,(uint64_t)tmp2); + + temp1 = (uint64_t)xide_byte_swap(tmp1); + temp2 = (uint64_t)xide_byte_swap(tmp2); + IDE_DBG(11," temp1 0x%x | temp2 0x%x \n",temp1,temp2); + + temp = (temp2<<32) | temp1; + + IDE_DBG(11,"byteswap64 : FINAL temp 0x%x ",temp); + // debug("singer"); + return temp; +#endif +#endif +} + +static inline void xide_delay(long ticks) +{ +#ifdef XSCSI + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(ticks); +#else + delay(ticks); +#endif +} + + +#ifndef XSCSI +static void print_xide_pciconfig(xide_pciconfig_t *pci_conf) +{ + IDE_DBG(13,"Printing ATA/ATAPI Card PCI Config Structure\n"); + IDE_DBG(13,"PCI_devID : 0x%x | PCI_vendID : 0x%x\n",pci_conf->PCI_devID,pci_conf->PCI_vendID); + IDE_DBG(13,"PCI_status : 0x%x | PCI_command : 0x%x \n",pci_conf->PCI_status,pci_conf->PCI_command); + IDE_DBG(13,"PCI_classcode[0] : 0x%x | PCI_classcode[1] : 0x%x \n",pci_conf->PCI_class_code[0],pci_conf->PCI_class_code[1]); + IDE_DBG(13,"PCI_classcode[2] : 0x%x \n",pci_conf->PCI_class_code[2]); + IDE_DBG(13,"PCI_revID : 0x%x ",pci_conf->PCI_revID); + IDE_DBG(13,"PCI_latency timer : 0x%x | PCI_cache_line 0x%x \n",pci_conf->PCI_latency_timer, pci_conf->PCI_cache_line); + IDE_DBG(13,"rsvd1 : 0x%x | PCI_header_type : 0x%x\n",pci_conf->rsvd1,pci_conf->PCI_header_type); + IDE_DBG(13,"PCI_base0 : 0x %x | PCI_base1 : 0x %x | PCI_base2 : 0x%x \n", pci_conf->PCI_base0, pci_conf->PCI_base1,pci_conf->PCI_base2); + IDE_DBG(13,"PCI_base3 : 0x %x | PCI_base4 : 0x %x | PCI_base5 : 0x%x \n", pci_conf->PCI_base3, pci_conf->PCI_base4,pci_conf->PCI_base5); + IDE_DBG(13,"PCI_rombase : 0x%x \n",pci_conf->PCI_rombase); + IDE_DBG(13,"PCI_max_latency : 0x%x | PCI_min_grant : 0x%x \n",pci_conf->PCI_max_latency,pci_conf->PCI_min_grant); + IDE_DBG(13,"PCI_intr_pin : 0x%x | PCI_intr_line : 0x%x \n",pci_conf->PCI_intr_pin,pci_conf->PCI_intr_line); + IDE_DBG(13,"PCI_errorgen : 0x%x | PCI_intlinsel1 : 0x %x \n", pci_conf->PCI_errorgen,pci_conf->PCI_intlinsel1); + IDE_DBG(13,"PCI_devstatus0 : 0x%x | PCI_devconfig : 0x%x \n", pci_conf->PCI_devstatus0, pci_conf->PCI_devconfig); +} +#endif + +/* + * Debugging print facility + */ +static void IDE_DBG(int debuglevel, char *format, ...) +{ + va_list ap; + char tempstr[256]; + + if (xidedebug >= debuglevel) + { + va_start(ap, format); + vsprintf(tempstr, format, ap); +#ifdef XSCSI + printk(tempstr); +#else + printf(tempstr); +#endif + va_end(ap); + } +} + +static void IDE_PRINTERR(int debuglevel, char *format, ...) +{ + va_list ap; + char tempstr[256]; + + if (xide_error >= debuglevel) + { + va_start(ap, format); + vsprintf(tempstr, format, ap); +#ifdef XSCSI + printk(KERN_WARNING "xscsi/xide: %s",tempstr); +#else + printf(tempstr); +#endif + va_end(ap); + } +} + +#ifndef XSCSI +void xide_init(void) +{ + int ret; + + IDE_DBG(1,"IDE (ATAPI) Working driver ver 0.9\n"); + ret = pciio_driver_register (CMD_VENDOR_ID, CMD_DEV_ID, "xide_", 0); + ret = pciio_driver_register (PCI_VENDOR_SGI, IOC4_PCI_ID, "xide_",0); +// ret = pciio_driver_register (PCI_VENDOR_ID_PROMISE,PCI_DEVICE_ID_PROMISE_20262 , "xide_", 0); + IDE_ASSERT(ret==0); + INITLOCK(&xide_connect_sema, "xideconnect", 0); + IDE_DBG(1,"xide_init()ret %d \n",ret); +} +#endif + +#ifdef XSCSI +int __devinit xide_attach(struct pci_dev *vhdl, const struct pci_device_id *pci_id) +#else +int xide_attach(vertex_hdl_t vhdl) +#endif +{ + xide_ProtoInfo_t *pi; + int pi_size; + +#ifndef XSCSI + device_desc_t xide_desc=NULL; + pciio_intr_t pciintr; + pciio_piomap_t rmap0=0,rmap1=0,rmap2=0,rmap3=0; +#endif + xide_pciconfig_t *pciconfig=NULL; + + IOLOCK(xide_connect_sema, xide_connect_sema_spl); + +#ifdef XSCSI + if (pci_enable_device(vhdl)) { + IDE_DBG(0,"xscsi/ide:: xide_attach: Failed to enable device with pci_dev 0x"IDE_PTR"... returning\n",vhdl); + IOUNLOCK(xide_connect_sema, xide_connect_sema_spl); + return -1; + }; + pci_set_master(vhdl); +#ifdef CONFIG_IA64_SGI_SN2 // SN2 is Little-Endian + pciio_endian_set(vhdl,PCIDMA_ENDIAN_LITTLE,PCIDMA_ENDIAN_BIG); +#else +#ifdef CONFIG_IA64_SGI_SN1 // SN1 is Big Endian + pciio_endian_set(vhdl,PCIDMA_ENDIAN_BIG,PCIDMA_ENDIAN_LITTLE); +#endif +#endif + +#endif + + /* make sizeof pi double word aligned */ + pi_size = (sizeof(xide_ProtoInfo_t) + (8-1)) & ~(8-1); + IDE_KMEM_ZALLOC(pi, pi_size, VM_CACHEALIGN); + if (pi == NULL) { + IDE_DBG(0,"xscsi/ide:xide_attach: Cannot allocate memory for pi...Returning \n"); + IOUNLOCK(xide_connect_sema, xide_connect_sema_spl); + return(0); + } + + pi->FreeCmdObjTail = pi->FreeCmdObjHead = NULL; + pi->LastTargServed = 0; + pi->Flags = 0; + pi->PtrToTarg[0] = pi->PtrToTarg[1] = NULL; + pi->PciVhdl = vhdl; + pi->device_conf[0] = pi->device_conf[1] = 0; + pi->FinishedQHead = pi->FinishedQTail = NULL; + pi->State = HHR; + pi->BigMapMaxCount=0; + pi->prevent_intr=0; + pi->intr_set=0; + pi->intr_seen=0; + +// Getting the PCI address space info. + +#ifndef XSCSI + pciconfig = (struct xide_pciconfig_s *)pciio_piotrans_addr(vhdl, xide_desc,PCIIO_SPACE_CFG,0,sizeof(xide_pciconfig_t),0); + IDE_ASSERT(pciconfig != NULL); + print_xide_pciconfig(pciconfig); + + pi->devid = pciconfig->PCI_devID; + pi->vendorid = pciconfig->PCI_vendID; +#else + pi->vendorid = vhdl->vendor; + pi->devid = vhdl->device; +#endif + + pi->ProtoVhdl = xide_proto_add(pi); + + INITLOCK(&pi->ResourceLock, "xide_pi_resources", pi->ProtoVhdl); + INITLOCK(&pi->CommandLock, "xide_start1", pi->ProtoVhdl); + INITLOCK(&pi->FinishedQLock, "xide_finish", pi->ProtoVhdl); + INITLOCK(&pi->IntrLock, "xide_intr_lock", pi->ProtoVhdl); + + /* Set WatchDog Timer */ + itimeout(xide_WatchdogTimer, pi, WATCHDOG_TIME, TIMEOUT_SPL); + + pi->revID = pciio_config_get(vhdl,0x08,1); + if ((pi->vendorid == PCI_VENDOR_SGI)&&(pi->devid == IOC4_PCI_ID)) { + IDE_DBG(0,"xscsi/ide:SGI IOC4 BaseIO Card Detected : Firmware Rev %d \n",pi->revID); + if (pi->revID < xide_ioc4_rev) { + IDE_DBG(0,"xscsi/ide:Firmware Rev not supported...Please upgrade to IOC4 Firmware rev %d (or higher) \n",xide_ioc4_rev); + IOUNLOCK(xide_connect_sema, xide_connect_sema_spl); + return(0); + } + } else { + IDE_DBG(0,"xscsi/ide:: PCI IDE Device with Device ID 0x%x | Vendor 0x%x found : Firmware Rev %d \n",pi->devid,pi->vendorid,pi->revID); + } + + IDE_DBG(11,"xide_attach pi 0x"IDE_PTR" \n",pi); +/* +#ifndef XSCSI + pciconfig = (struct xide_pciconfig_s *)pciio_piotrans_addr(vhdl, xide_desc,PCIIO_SPACE_CFG,0,sizeof(xide_pciconfig_t),0); + IDE_ASSERT(pciconfig != NULL); + print_xide_pciconfig(pciconfig); +#endif +*/ + if ((pi->vendorid == CMD_DEV_ID) || (pi->vendorid == PCI_VENDOR_ID_PROMISE)) + { + if (!(pciconfig->PCI_command & PCI_CMD_IO_SPACE)) { + pciio_config_set ( + vhdl, + PCI_CFG_COMMAND, + sizeof(uint16_t), + (uint16_t)(pciconfig->PCI_command|PCI_CMD_IO_SPACE)); + IDE_DBG(11,"Setting PCI-command reg using PCI_CMD_IO_SPACE"); + } + + if (!(pciconfig->PCI_command & PCI_CMD_MEM_SPACE)) { + pciio_config_set ( + vhdl, + PCI_CFG_COMMAND, + sizeof(uint16_t), + (uint16_t)(pciconfig->PCI_command|PCI_CMD_MEM_SPACE)); + IDE_DBG(11,"Setting PCI-command reg using PCI_CMD_MEM_SPACE"); + } + + pciio_config_set ( + vhdl, + PCI_CFG_COMMAND, + sizeof(uint16_t), + (uint16_t)(pciconfig->PCI_command|0x47)); + + pciio_config_set ( + vhdl, + PCI_CFG_STATUS, + sizeof(uint16_t), + (uint16_t)(pciconfig->PCI_status|0x1A90)); + +#ifndef XSCSI + pciconfig = (struct xide_pciconfig_s *)pciio_piotrans_addr(vhdl, xide_desc,PCIIO_SPACE_CFG,0,sizeof(xide_pciconfig_t),0); + IDE_ASSERT(pciconfig != NULL); + print_xide_pciconfig(pciconfig); +#endif + } + + if (pi->vendorid == PCI_VENDOR_SGI) { +#ifdef XSCSI + pi->cmdblk = (caddr_t) pci_resource_start(vhdl,0); + IDE_ASSERT(pi->cmdblk != NULL); + if (!request_region((unsigned long)pi->cmdblk + IOC4_CMD_OFFSET,4*sizeof(command_regs_t),"xide_cmdblk")) { + IDE_DBG(1,"xide_attach(cmd) : Card with vhdl 0x%x in use by another driver \n",vhdl); + // return -1; + } + pi->cmdblk += IOC4_CMD_OFFSET; + IDE_DBG(1,"pi->cmdblk 0x"IDE_PTR"\n",pi->cmdblk); + + // COULD CAUSE ERROR ON LINUX _ CHECK!!!! + pi->ctrlblk = (caddr_t) pci_resource_start(vhdl,0); + IDE_ASSERT(pi->ctrlblk != NULL); + if (!request_region((unsigned long)pi->ctrlblk + IOC4_CTRL_OFFSET ,4,"xide_ctrlblk")) { + IDE_DBG(1,"xide_attach(ctrl) : Card with vhdl 0x%x in use by another driver \n",vhdl); + // return -1; + } + pi->ctrlblk += IOC4_CTRL_OFFSET; + IDE_DBG(1,"pi->ctrlblk 0x"IDE_PTR"\n",pi->ctrlblk); + + pi->dmablk = (caddr_t) pci_resource_start(vhdl,0); + IDE_ASSERT(pi->dmablk != NULL); + if (!request_region((unsigned long)pi->dmablk + IOC4_DMA_OFFSET ,sizeof(ioc4_dma_regs_t),"xide_dmablk")) { + IDE_DBG(1,"xide_attach(dma) : Card with vhdl 0x%x in use by another driver \n",vhdl); + // return -1; + } + pi->dmablk += IOC4_DMA_OFFSET; + IDE_DBG(1,"pi->dmablk 0x"IDE_PTR"\n",pi->dmablk); + + pi->intrblk = (caddr_t) pci_resource_start(vhdl,0); + IDE_ASSERT(pi->intrblk != NULL); + if (!request_region((unsigned long)pi->intrblk + IOC4_INTR_OFFSET,sizeof(ioc4_intr_regs_t),"xide_intrblk")) { + IDE_DBG(1,"xide_attach(intr) : Card with vhdl 0x%x in use by another driver \n",vhdl); + // return -1; + } + pi->intrblk += IOC4_INTR_OFFSET; + IDE_DBG(1,"pi->intrblk 0x"IDE_PTR"\n",pi->intrblk); + +#ifdef CONFIG_IA64_SGI_SN2 + pi->pciio_byte_stream = IDE_PCIIO_WORD_VALUES; // Little Endian Machine +#else +#ifdef CONFIG_IA64_SGI_SN1 + pi->pciio_byte_stream = IDE_PCIIO_BYTE_STREAM; // Big Endian Machine +#endif +#endif + +#else + pi->intrblk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(0), + IOC4_INTR_OFFSET, + sizeof(ioc4_intr_regs_t), + &rmap0, + 0); + IDE_ASSERT(pi->intrblk != NULL); + + + pi->cmdblk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(0), + IOC4_CMD_OFFSET, + 4*sizeof(command_regs_t), + &rmap1, + 0); + IDE_ASSERT(pi->cmdblk != NULL); + + pi->ctrlblk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(0), + IOC4_CTRL_OFFSET, +// 4*sizeof(ctrl_regs_t), + 4, + &rmap2, + 0); + IDE_ASSERT(pi->ctrlblk != NULL); + + pi->dmablk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(0), + IOC4_DMA_OFFSET, + sizeof(ioc4_dma_regs_t), + &rmap3, + 0); + IDE_ASSERT(pi->dmablk != NULL); + + pi->pciio_byte_stream = 0; +#endif + + { // Enabling interrupts on the IOC4 + uint8_t set_reg; + IOLOCK(pi->CommandLock, pi->CommandLockSpl); +// set_reg = IDE_INB(pi,pi->intrblk,IOC4_INTR_SET); +// IDE_DBG(1,"intr regs BEFOR: 0x%x - set \n",set_reg); + IDE_OUTB(pi,pi->intrblk,IOC4_INTR_SET,0x03); + set_reg = IDE_INB(pi,pi->intrblk,IOC4_INTR_SET); + IDE_DBG(1,"intr regs AFTER: 0x%x - set \n",set_reg); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + } + pi->xide_alt_status=0; // Offset to Alternate Status Reg. + + } + else // Standard IDE Card + { +#ifdef XSCSI + + pi->cmdblk = (caddr_t) pci_resource_start(vhdl,0); + IDE_ASSERT(pi->cmdblk != NULL); + if (!request_region((unsigned long)pi->cmdblk,sizeof(command_regs_t),"xide_cmdblk")) { + IDE_DBG(0,"xscsi/ide:xide_attach : Card with vhdl 0x%x in use by another driver \n",vhdl); + // return -1; + } + else { + IDE_DBG(11,"xide_attach pi->cmdblk 0x%x \n",pi->cmdblk); + } + + pi->ctrlblk = (caddr_t) pci_resource_start(vhdl,1); + IDE_ASSERT(pi->ctrlblk != NULL); + if (!request_region((unsigned long)pi->ctrlblk,sizeof(ctrl_regs_t),"xide_ctrlblk")) { + IDE_DBG(0,"xscsi/ide:xide_attach : Card with vhdl 0x%x in use by another driver \n",vhdl); + // return -1; + } + else { + IDE_DBG(11,"xide_attach pi->ctrlblk 0x%x \n",pi->ctrlblk); + } + + pi->dmablk = (caddr_t) pci_resource_start(vhdl,4); + IDE_ASSERT(pi->dmablk != NULL); + if (!request_region((unsigned long)pi->dmablk,sizeof(cmd649_dma_regs_t),"xide_dmablk")) { + IDE_DBG(0,"xscsi/ide:xide_attach : Card with vhdl 0x%x in use by another driver \n",vhdl); + // return -1; + } + else { + IDE_DBG(11,"xide_attach pi->dmablk 0x%x \n",pi->dmablk); + } +#else + pi->cmdblk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(0), + 0, + sizeof(command_regs_t), + &rmap1, + 0); + IDE_ASSERT(pi->cmdblk != NULL); + + pi->ctrlblk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(1), + 0, + sizeof(ctrl_regs_t), + &rmap2, + 0); + IDE_ASSERT(pi->ctrlblk != NULL); + + if (pi->vendorid == PCI_VENDOR_ID_PROMISE) { + pciio_config_set ( + vhdl, + PCI_CFG_CACHE_LINE, + sizeof(uint8_t), + 128); + + pi->dmablk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(4), + 0, + sizeof(pdc20262_dma_regs_t), + &rmap3, + 0); + } + else if (pi->vendorid == CMD_VENDOR_ID) { + pi->dmablk = pciio_pio_addr( + vhdl, + xide_desc, + PCIIO_SPACE_WIN(4), + 0, + sizeof(cmd649_dma_regs_t), + &rmap3, + 0); + } + IDE_ASSERT(pi->dmablk != NULL); + pi->pciio_byte_stream = IDE_PCIIO_BYTE_STREAM; +#endif + pi->xide_alt_status=2; // Offset to Alternate Status Reg. + } + +#ifdef XSCSI + sema_init(&pi->intr_q,0); + IDE_DBG(3,"kernel_thread 0x"IDE_PTR" | pi : 0x"IDE_PTR"\n | vhdl->irq 0x%x", xide_intr_thread, pi,vhdl->irq); + (void) kernel_thread(xide_intr_thread,(void *)pi,0); + +// while ((int)xide_intrthreadcount==0) {}; + if (!request_irq(vhdl->irq,xide_irq_handler, SA_INTERRUPT|SA_SHIRQ, "sgi-xide",pi)) { + IDE_DBG(11,"request_irq returns 0 : good\n"); + } else { + IDE_DBG(1,"xide_attach: request_irq returns non-zero : No Interrupts Possible\n"); +// IOUNLOCK(xide_connect_sema, xide_connect_sema_spl); +// return -EIO; + } + + sema_init(&pi->intr_watch_q,0); + IDE_DBG(3,"kernel_thread: intr_watch_q 0x"IDE_PTR" \n", xide_intr_watch_thread); + (void) kernel_thread(xide_intr_watch_thread,(void *)pi,0); +#else + pciintr = pciio_intr_alloc(pi->PciVhdl, xide_desc, PCIIO_INTR_LINE_A,pi->ProtoVhdl); + pciio_intr_connect(pciintr, (intr_func_t) xide_intr, pi, NULL); +#endif + + xide_probe(pi); + IOUNLOCK(xide_connect_sema, xide_connect_sema_spl); + return 0; +} + +/* Step 1 : Add Channel to hwgraph */ +static vertex_hdl_t xide_proto_add(xide_ProtoInfo_t *pi) +{ + vertex_hdl_t proto_vhdl; +#ifndef XSCSI + int inventory_type=INV_IDE; + graph_error_t rv; + vertex_hdl_t bus_vhdl; +#endif + scsi_ctlr_info_t *proto_info=NULL; + + pi->Next = xide_proto_list; + xide_proto_list = pi; + pi->Number = xide_proto_num++; + +#ifdef XSCSI + proto_vhdl = scsi_ctlr_vertex_add(pi->PciVhdl,0); + sprintf(pi->HwgName, "IDE_%d_%d",pi->PciVhdl->bus->number,pi->Number); + proto_info = scsi_ctlr_info_get(proto_vhdl); +#else + rv = hwgraph_path_add(pi->PciVhdl,EDGE_LBL_SCSI_CTLR "/0",&proto_vhdl); + IDE_ASSERT((rv == GRAPH_SUCCESS) && (proto_vhdl != GRAPH_VERTEX_NONE)); + sprintf(pi->HwgName,"%v",proto_vhdl); +#endif + + pi->ProtoVhdl = proto_vhdl; + +#ifndef XSCSI + proto_info = (scsi_ctlr_info_t *) hwgraph_fastinfo_get(pi->ProtoVhdl); + if (!proto_info) { + proto_info = scsi_ctlr_info_init(); +#endif + SCI_CTLR_VHDL(proto_info) = proto_vhdl; + SCI_ADAP(proto_info) = pi->Number; + SCI_INFO(proto_info) = pi; + + SCI_ALLOC(proto_info) = xide_alloc; + SCI_COMMAND(proto_info) = xide_command; + SCI_FREE(proto_info) = xide_free; +// SCI_DUMP(proto_info) = xide_dump; + SCI_INQ(proto_info) = xide_info; + SCI_IOCTL(proto_info) = xide_ioctl; +// SCI_ABORT(proto_info) = xide_abort; + + SCI_SCSI_TYPE(proto_info) = SCI_SCSI_TYPE_IDE; + scsi_ctlr_info_put(proto_vhdl,proto_info); + scsi_bus_create(proto_vhdl); /* creates "/bus" vertex for channel */ + +#ifndef XSCSI + rv = hwgraph_traverse(pi->ProtoVhdl,EDGE_LBL_BUS, &bus_vhdl); + IDE_ASSERT(rv == GRAPH_SUCCESS); + hwgraph_vertex_unref(bus_vhdl); + } + hwgraph_vertex_unref(proto_vhdl); + + if ((pi->vendorid == PCI_VENDOR_SGI)&&(pi->devid == IOC4_PCI_ID)) { + inventory_type = INV_IDE_IOC4; + } + + device_inventory_add(pi->ProtoVhdl, + INV_DISK, + INV_SCSICONTROL, + -1,0,inventory_type); +#endif + return (proto_vhdl); +} + +static int xide_chip_init(xide_ProtoInfo_t *pi) +{ + if ((pi->vendorid == PCI_VENDOR_SGI)&&(pi->devid == IOC4_PCI_ID)) { + // Enabling interrupts on the IOC4 + uint8_t set_reg; + IOLOCK(pi->CommandLock, pi->CommandLockSpl); + IDE_OUTB(pi,pi->intrblk,IOC4_INTR_SET,0x03); + set_reg = IDE_INB(pi,pi->intrblk,IOC4_INTR_SET); + IDE_DBG(1,"intr regs AFTER: 0x%x - set \n",set_reg); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + } + return 0; +} + +static int xide_probe(xide_ProtoInfo_t *pi) +{ + int i; + int ret=0; + xide_TargInfo_t *ti=NULL; + xide_LunInfo_t *li=NULL; + + + + for (i=0;i<2;i++) { + if (pi->PtrToTarg[i]) { + IDE_DBG(3,"Checking Targ %d\n",i); + ti = pi->PtrToTarg[i]; + if (ti->PtrToLun[0] > 0 ) { + li = ti->PtrToLun[0]; + IDE_DBG(3,"Checking Lun 0x"IDE_PTR"\n",li); + IOLOCK(li->LunLock,li->LunSpl); + if ((li->CmdObjHead)||(li->CmdObjTail)) { + IDE_DBG(1,"Calling xide_return_lun_cmds() from xide_probe\n"); + xide_return_lun_cmds(li,SC_ATTN); + IDE_DBG(1,"xide_return_lun_cmds() from xide_probe DONE\n"); + } + else { + IDE_DBG(1,"li->CmdObjHead)||(li->CmdObjTail =0\n"); + } + IOUNLOCK(li->LunLock,li->LunSpl); + + IOLOCK(pi->CommandLock, pi->CommandLockSpl); + xide_pktDMA_complete(pi); + pi->State = HHR; + ret = xide_bus_reset(pi); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + } + else { + IDE_DBG(11,"No LUN ?? ti 0x"IDE_PTR" \n",ti); + } + xide_return_finished_req(pi); + } + else { + IDE_DBG(21," TARGET[%d] not present for pi 0x%"IDE_PTR" \n",i,(void *)pi); + } + } + + if (!li) { + IOLOCK(pi->CommandLock, pi->CommandLockSpl); + pi->State = HHR; + ret = xide_bus_reset(pi); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + } + + if (ret == -ENODEV) { + IDE_DBG(0,"xscsi/ide:: xide_probe: No ATA/ATAPI devices found.. returning \n"); + return -ENODEV; + } + IDE_DBG(13,"device_conf[0] 0x%x | [1] 0x%x\n",pi->device_conf[0],pi->device_conf[1]); + xide_chip_init(pi); + + for (i=0;i<2;i++) { + if (pi->device_conf[i] & DEV_PRESENT) { + if (pi->device_conf[i] & (ATAPI_DEV_PRESENT|ATA_DEV_PRESENT)) { +// if (pi->device_conf[i] & (ATAPI_DEV_PRESENT)) { + if ((pi->device_conf[i] & DEV_IN_GRAPH)==0) { + IDE_DBG(3,"Adding Target %d \n",i); + xide_target_add(pi,i); + IDE_DBG(3,"Device_conf[%d] 0x%x\n",i,pi->device_conf[i]); + } + } + } + } + + pi->State = DEVICE_PROBE_OVER; + IDE_DBG(13,"Finished ata_probe\n"); +#ifdef XSCSI + xscsi_notify(); +#endif + return 0; + +} + +void xide_execute_device_diagnostic(xide_ProtoInfo_t *pi) +{ + uint8_t status; + + IDE_OUTB(pi,pi->ctrlblk,pi->xide_alt_status,IDE_NIEN); + IDE_OUTB(pi,pi->cmdblk,IDE_COMMAND,0x90); + if (xide_get_status(pi,&status,1)) { + IDE_DBG(1,"xide_execute_device_diagnostic : status remained 0x%x after execute_dev_diagnostic \n",status); +// IDE_ASSERT(0); + } + IDE_DBG(11,"execute_dev : status 0x%x \n",status); +} + +/* Performs a Soft Reset on each individual IDE Device on the bus */ +void xide_device_reset(xide_ProtoInfo_t *pi) +{ + uint8_t status=0; +// IMP : ONLY WORKS FOR ATAPI DEVICES - NOT ATA + + if (pi->device_conf[0] & ATAPI_DEV_PRESENT) { + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x0); + IDE_OUTB(pi,pi->cmdblk,IDE_ERR_FEATURE,0); + IDE_OUTB(pi,pi->cmdblk,IDE_COUNT,0); + IDE_OUTB(pi,pi->cmdblk,IDE_SECTOR,0); + IDE_OUTB(pi,pi->cmdblk,IDE_CYL_LSB,0); + IDE_OUTB(pi,pi->cmdblk,IDE_CYL_MSB,0); + IDE_OUTB(pi,pi->cmdblk,IDE_COMMAND,0x08); + if (xide_get_status(pi,&status,1)) { + IDE_DBG(1,"xscsi/xide: xide_device_reset : status remains 0x%x\n",status); + } +// do { +// xide_delay(HZ/100); +// status=IDE_INB(pi,pi->cmdblk,IDE_COMMAND); +// } while (status & IDE_S_BUSY); + IDE_DBG(11,"dev_reset[0] : status 0x%x \n",status); + } + + if (pi->device_conf[1] & ATAPI_DEV_PRESENT) { + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x10); + IDE_OUTB(pi,pi->cmdblk,IDE_ERR_FEATURE,0); + IDE_OUTB(pi,pi->cmdblk,IDE_COUNT,0); + IDE_OUTB(pi,pi->cmdblk,IDE_SECTOR,0); + IDE_OUTB(pi,pi->cmdblk,IDE_CYL_LSB,0); + IDE_OUTB(pi,pi->cmdblk,IDE_CYL_MSB,0); + IDE_OUTB(pi,pi->cmdblk,IDE_COMMAND,0x08); + if (xide_get_status(pi,&status,1)) { + IDE_DBG(1,"xscsi/xide: xide_device_reset : status remains 0x%x\n",status); + } +// do { +// xide_delay(HZ/100); +// status=IDE_INB(pi,pi->cmdblk,IDE_COMMAND); +// } while (status & IDE_S_BUSY); + IDE_DBG(11,"dev_reset[1] : status 0x%x \n",status); + } +} + + + +/* Performs a Soft reset on the IDE bus and puts the devices/types found in device_conf[] */ + +static int xide_bus_reset(xide_ProtoInfo_t *pi) +{ + int timeout=0; + uint8_t error0=0,error1=0,cyl_lsb,cyl_msb,sector,count; + uint8_t alt_status0,alt_status1; + int absent=0; + + IDE_DBG(21,"xide_bus_reset() \n"); + + if (pi->State == HHR) { + IDE_DBG(5,"Reset on BUS : Initialization\n"); + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x0); + + do { +// IDE_DELAY(10); + xide_delay(HZ/100); + timeout += 10; + alt_status0=IDE_INB(pi,pi->cmdblk,IDE_COMMAND); + IDE_DBG(5,"alt_status0 0x%x | ",alt_status0); + error0=IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + IDE_DBG(5,"error0 0x%x\n",error0); + } + while ((alt_status0 & IDE_S_BUSY) &&(timeout < 100)); + + timeout=0; + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x10); + do { +// IDE_DELAY(10); + xide_delay(HZ/100); + timeout += 10; + alt_status1=IDE_INB(pi,pi->ctrlblk,pi->xide_alt_status); + IDE_DBG(5,"alt_status1 0x%x | ",alt_status1); + error1=IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + IDE_DBG(5,"error1 0x%x\n",error1); + } + while ((alt_status1 & IDE_S_BUSY) && (timeout < 100)); + + IDE_DBG(5,"err0 0x%x | err1 0x%x | alt_1 0x%x | alt_2 0x%x \n",error0,error1,alt_status0,alt_status1); + absent=0; + if (error0 & IDE_E_ABORT) { + absent |= 0x01; + IDE_DBG(2,"Dev 0 Absent\n"); + } + + if (error1 & IDE_E_ABORT) { + IDE_DBG(2,"Dev 1 Absent \n"); + absent |= 0x02; + } + + if (absent == 0x03) return -ENODEV; + // No devices present + + if (!(absent & 0x02)) { + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x10); + pi->device_conf[1] |= DEV_PRESENT; + } + if (!(absent & 0x01)) { + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x00); + pi->device_conf[0] |= DEV_PRESENT; + } + IDE_DBG(6,"absent 0x%x\n",absent); + } + else if (pi->State == DEVICE_PROBE_OVER) { + if (!(pi->device_conf[0] & DEV_PRESENT)) { + absent |= 0x01; + IDE_DBG(1,"Dev 0 Absent\n"); + } + if (!(pi->device_conf[1] & DEV_PRESENT)) { + absent |= 0x02; + IDE_DBG(1,"Dev 1 Absent\n"); + } + } + + + /* Implies none of the devices are busy doing anything else.. so we can reset */ +// IDE_OUTB(pi,pi->ctrlblk,pi->xide_alt_status,0x02); +// IDE_OUTB(pi,pi->ctrlblk,pi->xide_alt_status,0x02|0x04); + IDE_OUTB(pi,pi->ctrlblk,pi->xide_alt_status,0x04); + xide_delay(2*HZ); + IDE_OUTB(pi,pi->ctrlblk,pi->xide_alt_status,0x0); +// IDE_OUTB(pi,pi->ctrlblk,pi->xide_alt_status,0x02); + +/* timeout=0; + do { + IDE_DELAY(10000); + timeout += 10000; + alt_status0=IDE_INB(pi,pi->cmdblk,IDE_COMMAND); + } while ((alt_status0 & IDE_S_BUSY) && (timeout < 310000)); +*/ + + if (xide_get_status(pi,&alt_status0,31)) { + IDE_DBG(0,"xscsi/ide:: xide_bus_reset : status remained 0x%x after reset \n",alt_status0); +// IDE_ASSERT(0); + } + IDE_DBG(11,"xide_bus_reset : alt_status0 : 0x%x \n",alt_status0); + xide_execute_device_diagnostic(pi); +// if (!(absent & 0x01)) + { + uint8_t status0; + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x0); + error0 = IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + cyl_lsb = IDE_INB(pi,pi->cmdblk,IDE_CYL_LSB); + cyl_msb = IDE_INB(pi,pi->cmdblk,IDE_CYL_MSB); + sector = IDE_INB(pi,pi->cmdblk,IDE_SECTOR); + count = IDE_INB(pi,pi->cmdblk,IDE_COUNT); + status0 = IDE_INB(pi,pi->cmdblk,IDE_COMMAND); + + IDE_DBG(5,"status0 0x%x | err0 0x%x | lsb 0x%x | msb 0x%x | sector 0x%x | cnt 0x%x \n", + status0, error0, cyl_lsb, cyl_msb, sector, count); + if ((cyl_lsb == ATAPI_MAGIC_LSB) && + (cyl_msb == ATAPI_MAGIC_MSB)&&(sector ==1)&&(count ==1)) { + IDE_DBG(5,"ATAPI SIGNATURE FOR DEV 0 verified\n"); + if (error0 == 0x01) { + IDE_DBG(1,"xscsi/xide: ATAPI MASTER DEV FOUND\n"); + pi->device_conf[0] |= ATAPI_DEV_PRESENT; + } + + if ((error0 == 0x0) || ((error0 >= 0x02) && ( error0 <= 0x7f))) { + IDE_DBG(3,"ATAPI DEV 0 FAILED\n"); + pi->device_conf[0] = 0; + } + + if (error0 == 0x81) { + IDE_DBG(13,"ATAPI DEV 0 PASSED | DEV 1 FAILED\n"); + pi->device_conf[1] = 0; + } + + if ((error0 == 0x80) || ((error0 >= 0x82) && ( error0 <= 0xff))) { + IDE_DBG(13,"ATAPI DEV 0 & 1 FAILED\n"); + pi->device_conf[0] = 0; + pi->device_conf[0] = 0; + } + } + else if ((cyl_lsb == 0) && (cyl_msb == 0)&&(sector ==1)&&(count ==1)) { + IDE_DBG(5,"ATA SIGNATURE verified : dev 0\n"); + if ((error0 == 0x01)&&(status0==0x50)) { + IDE_DBG(0,"xscsi/ide:: ATA MASTER DEV FOUND\n"); + pi->device_conf[0] |= ATA_DEV_PRESENT; + } + + if ((error0 == 0x0) || ((error0 >= 0x02) && ( error0 <= 0x7f))) { + IDE_DBG(3,"ATA DEV 0 FAILED\n"); + pi->device_conf[0] = 0; + } + + if (error0 == 0x81) { + IDE_DBG(3,"ATA DEV 0 PASSED | DEV 1 FAILED\n"); + pi->device_conf[1] = 0; + } + + if ((error0 == 0x80) || ((error0 >= 0x82) && ( error0 <= 0xff))) { + IDE_DBG(3,"ATA DEV 0 & 1 FAILED\n"); + pi->device_conf[0] = 0; + pi->device_conf[1] = 0; + } + } + else { + IDE_DBG(5,"xide_bus_reset() : Unable to xidentify Dev 0 as ATAPI or ATA .. Please check if the device is powered ON\n"); + pi->device_conf[0] = 0; + } + } +// if (!(absent & 0x02)) + { + uint8_t status1; + + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,0x10); + status1 = IDE_INB(pi,pi->cmdblk,IDE_COMMAND); + error1 = IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + cyl_lsb = IDE_INB(pi,pi->cmdblk,IDE_CYL_LSB); + cyl_msb = IDE_INB(pi,pi->cmdblk,IDE_CYL_MSB); + sector = IDE_INB(pi,pi->cmdblk,IDE_SECTOR); + count = IDE_INB(pi,pi->cmdblk,IDE_COUNT); + + IDE_DBG(5,"status1 0x%x | err0 0x%x | lsb 0x%x | msb 0x%x | sector 0x%x | cnt 0x%x \n", + status1, error0, cyl_lsb, cyl_msb, sector, count); + if ((cyl_lsb == ATAPI_MAGIC_LSB) && + (cyl_msb == ATAPI_MAGIC_MSB)&&(sector ==1)&&(count ==1)) { + IDE_DBG(5,"ATAPI SIGNATURE FOR DEV 1 verified : dev 1\n"); + if (error1 == 0x01) { + pi->device_conf[1] |= ATAPI_DEV_PRESENT; + IDE_DBG(0,"xscsi/ide:: ATAPI SLAVE DEV FOUND\n"); + } + + if ((error1 == 0x0) || ((error1 >= 0x02) && ( error1 <= 0x7f))) { + IDE_DBG(3,"ATAPI DEV 1 FAILED\n"); + pi->device_conf[1] = 0; + } + } + else if ((cyl_lsb == 0) && (cyl_msb == 0)&&(sector ==1)&&(count ==1)) { + IDE_DBG(5,"ATA SIGNATURE verified : dev 1 \n"); + if ((error1 == 0x01)&&(status1==0x50)) { + pi->device_conf[1] |= ATA_DEV_PRESENT; + IDE_DBG(0,"xscsi/ide:: ATA SLAVE DEV FOUND\n"); + } + else { +// if ((error1 == 0x0) || ((error1 >= 0x02) && ( error1 <= 0x7f))) { + IDE_DBG(3,"ATA SLAVE DEV FAILED\n"); + pi->device_conf[1] = 0; + } + } + else { + IDE_DBG(5,"xide_bus_reset() : Unable to xidentify Dev 1 as ATAPI or ATA .. Please check if the device is powered ON\n"); + pi->device_conf[1] = 0; + } + } + return 0; +} + +int xide_intr_clear(xide_ProtoInfo_t *pi) +{ + uint32_t interrupt_reg; + uint8_t intr_reg; + + if (pi->vendorid == CMD_VENDOR_ID) { + interrupt_reg = pciio_config_get(pi->PciVhdl,0x50,1); + IDE_DBG(11,"xide_intr : cmd649 BEFORE intr. reg 0x%x\n",interrupt_reg); + pciio_config_set(pi->PciVhdl,0x50,1,interrupt_reg&0xFF); + interrupt_reg = pciio_config_get(pi->PciVhdl,0x50,1); + IDE_DBG(11,"xide_intr : cmd649 AFTER intr. reg 0x%x\n",interrupt_reg); + return 0; + } + + if (pi->vendorid == PCI_VENDOR_SGI) { + intr_reg = IDE_INB(pi,pi->intrblk,IOC4_INTR_REG); + IDE_DBG(11,"xide_intr_clear: intr_reg 0x%x \n",intr_reg); + if (intr_reg & 0x3) { + IDE_DBG(2,"interrupt from IDE device\n"); + if (intr_reg & 0x02) { //DMA PCI ERROR!!! + uint32_t pci_err_addr_low; + uint32_t pci_err_addr_high; + uint32_t pci_stat_cmd_reg; + pi->pci_dma_error=1; + IDE_DBG(0,"xscsi/ide:xide_intr_clear: Other IR Reg 0x%x gives ATA_MEMERR\n",intr_reg); + pci_err_addr_low = IDE_INDW(pi,pi->intrblk,0); + pci_err_addr_high = IDE_INDW(pi,pi->intrblk,4); + pci_stat_cmd_reg = (uint32_t)pciio_config_get(pi->PciVhdl,4,4); + IDE_DBG(0,"xscsi/ide:xide_intr_clear: err_addr_low 0x%x | err_addr_high 0x%x | status_cmd_reg 0x%x \n", + pci_err_addr_low,pci_err_addr_high,pci_stat_cmd_reg); + if ((pci_err_addr_low & 0x1E)== 0x08) { + IDE_DBG(0,"xscsi/ide:xide_intr_clear: ATA Error (from PCI Regs) \n"); + } +// IDE_ASSERT(0); + pciio_config_set(pi->PciVhdl,4,4,0x00000146); + IDE_OUTB(pi,pi->intrblk,0,1); // Reset the Error bit + } + else { + pi->pci_dma_error=0; + } + IDE_OUTB(pi,pi->intrblk,IOC4_INTR_REG,0x3); + intr_reg = IDE_INB(pi,pi->intrblk,IOC4_INTR_REG); + IDE_DBG(11,"xide_intr_clear(2): intr_reg 0x%x \n",intr_reg); + return IOC4_ATA_MEMERR; + } + else { + IDE_DBG(11,"interrupt NOT from IDE device...returning\n"); + return 1; + } + } + return 0; +} + +int xide_interrupt_check(xide_ProtoInfo_t *pi) +{ + if (pi->vendorid == CMD_VENDOR_ID) { + return 0; // Interrupt from IDE device only + } + else + if (pi->vendorid == PCI_VENDOR_SGI) { + uint8_t intr_reg=0; + intr_reg = IDE_INB(pi,pi->intrblk,IOC4_INTR_REG); + IDE_DBG(1,"intr_reg 0x%x \n",intr_reg); + if (intr_reg & 0x3) { + return 0; + } + else { + return 1; + } + } + return 0; +} + + +void xide_intr(xide_ProtoInfo_t *pi) +{ + xide_LunInfo_t *li=NULL; + xide_CmdObj_t *co=NULL; + int tag = -1; + int ata_memerr=0; + + uint8_t status,count=0; + uint8_t err_feature=0; + uint8_t drq,rel,serv; + + + IDE_DBG(12,"xide_intr 0x"IDE_PTR"\n",pi); + + IOLOCK(pi->CommandLock, pi->CommandLockSpl); + if (xide_interrupt_check(pi)) { + IDE_DBG(1,"xscsi/xide: xide_intr() : interrupt NOT from IDE device...returning\n"); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + return; + } + +// if (xide_get_status(pi,&status,0)){ +// IDE_DBG(0,"xscsi/ide:xide_intr : status remained 0x%x after intr \n",status); +// IDE_ASSERT(0); +// }; + do { // Clear Interrupt from Device + xide_delay(count); + status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND); + } while ((status & IDE_S_BUSY)&&(count++<1000)); + + if (status & IDE_E_ERR) { + err_feature = IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + } + + ata_memerr=xide_intr_clear(pi); // Clear Interrupt from Card +// IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + count=0; + + IOLOCK(pi->IntrLock, pi->IntrLockSpl); + if (pi->intr_set == 0) { + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); +// IOLOCK(pi->CommandLock, pi->CommandLockSpl); + xide_pktDMA_complete(pi); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + IDE_DBG(0,"xscsi/ide:xide_intr(0x"IDE_PTR"):Cleared Unexpected Interrupt: status 0x%x | error 0x%x : Stopped DMA : Did Nothing Else\n",pi,status,err_feature); + return; +// goto start_cmd; + } + else { + int num,valid,count_time; + + count_time=0; +CHECK: + valid=0; + + if ((pi->devid==IOC4_PCI_ID)&& + (pi->vendorid==PCI_VENDOR_SGI)&& + (pi->revID >= 45)) + { + // if (!((status & IDE_E_ERR)||(ata_memerr == IOC4_ATA_MEMERR))) { + if (!(status & IDE_E_ERR)) { + for (num=0;numDmaEndPtr[num]&0xFF) >0) { + valid = 1; + IDE_DBG(1,"num %d | pi->DmaEndPtr[num] %x \n",num,pi->DmaEndPtr[num]); + break; + } + } + if (valid > 0) { + IDE_DBG(1,"Got ATA Interrupt with valid data | EndPtr 0x%x | data 0x%x \n", + pi->DmaEndPtr,*(pi->DmaEndPtr)); + bzero(pi->DmaEndPtr,IDE_CACHELINE_SIZE); + } + else { + IDE_DBG(0,"xscsi/ide:: Got ATA Interrupt with invalid data | EndPtr 0x%x\n", + pi->DmaEndPtr); + xide_delay(HZ/30); + count_time++; + if (count_time < 30) { + goto CHECK; + } + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + return; + } + } + } + pi->intr_set=0; + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); + IDE_DBG(11,"xide_intr(): Got an expected interrupt\n"); + } + +// IOLOCK(pi->CommandLock, pi->CommandLockSpl); + if (xide_pktDMA_complete(pi)) { // DMA-PCI Error + li = xide_get_intr_lun(pi); + xide_device_reset(pi); // Put the IDE Device in a good state + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + IOLOCK(li->LunLock,li->LunSpl); + xide_return_lun_cmds(li,SC_CMDTIME); + IOUNLOCK(li->LunLock,li->LunSpl); + xide_return_finished_req(pi); + goto start_cmd; + } + li = xide_get_intr_lun(pi); + if (li == NULL) { + IDE_DBG(0,"xscsi/ide:: xide_intr(): Got li 0x"IDE_PTR"... returning\n",li); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + return; + } + + IDE_DBG(4,"xide_intr() : status 0x%x \n",status); + if (status & IDE_E_ERR) { + err_feature = IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + } + +// count = IDE_INB(pi,pi->cmdblk,IDE_COUNT); + + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + +// tag = (count & 0xF8)>>3; + tag=0; // 'cause tagged cmds disallowed + IDE_DBG(2,"xide_intr() : tag 0x%x\n",tag); + + IDE_DBG(11,"Before xide_intr's lunlock 0x%x\n",li->LunLock); + IOLOCK(li->LunLock, li->LunSpl); + IDE_DBG(11,"insxide xide_intr's lunlock 0x%x\n",li->LunLock); + co = xide_get_co_from_tag(tag,li); + + if (co==NULL) { + IDE_DBG(0,"xscsi/ide:Bus Reset ? hence co==NULL : li 0x"IDE_PTR"\n",li); + IOUNLOCK(li->LunLock, li->LunSpl); + IDE_ASSERT(0); + return; + } + IDE_DBG(2,"xide_intr() : co 0x"IDE_PTR"\n",co); + + co->SentReq->sr_scsi_status = status & 0x01; + co->request_stage = PKT_DMA_COMPLETE; + if (co->SentReq->sr_scsi_status) { + err_feature = IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + } + else { + err_feature =0; + } + co->SentReq->sr_status = (err_feature & 0xf0) >> 4; + + /* Adding in call to xide_send_co for special ATA Cmds to break the 128KB barrier */ + if (pi->device_conf[li->TargInfo->Number] & ATA_DEV_PRESENT) { + if ((co->SentReq->sr_status == SC_GOOD) || (co->SentReq->sr_scsi_status == ST_GOOD)) { + if (co->Offset_Flag & (IDE_START_TRANSFER|IDE_MIDDLE_TRANSFER)) { + IDE_DBG(1,"In xide_intr before xide_send_co : Flag 0x%x | res 0x%x \n",co->Offset_Flag, + co->Offset_Flag & (IDE_START_TRANSFER|IDE_MIDDLE_TRANSFER)); + if (co->Offset_Flag & IDE_START_TRANSFER) { + IDE_DBG(1,"intr(Before) : Flag 0x%x \n",co->Offset_Flag); + co->Offset_Flag &= (~IDE_START_TRANSFER|IDE_MIDDLE_TRANSFER); + IDE_DBG(1,"intr() : Flag 0x%x \n",co->Offset_Flag); + } + xide_send_co(co); + if ((co->saved_Pte>0) && (!(co->Offset_Flag & IDE_SPLIT_TRANSFER))) { + xide_std_PageTblEntry_t *sgmap_temp; + sgmap_temp = &(co->saved_Pte->xide_32b); + sgmap_temp->EOT_Resv_Len = 0; + sgmap_temp->Adr =0; +// IDE_KMEM_FREE(co->saved_Pte,sizeof(xide_std_PageTblEntry_t)); + } + IDE_DBG(1,"Back to xide_intr after xide_send_co \n"); + IOUNLOCK(li->LunLock, li->LunSpl); + return ; + } + } + } + + +// IDE_DBG(2,"xide_intr(): err_feature 0x%x | count 0x%x | status 0x%x\n",err_feature,count,status); + drq = status & IDE_S_DRQ; +// rel = count & IDE_C_REL; + rel = 0 & IDE_C_REL; + serv = status & IDE_S_SERV; + +// if ((drq==0) && (rel==0) && (serv==0)) { + if (drq==0) { + co->request_stage = CMD_COMPLETE; + xide_scsi_resp_back(co); + IOUNLOCK(li->LunLock, li->LunSpl); + xide_return_finished_req(pi); + goto start_cmd; + } + + if ((drq==0) && (rel==1) && (serv==0)) { + co->request_stage = BUS_RELEASE; + IDE_DBG(3,"!!!xide_intr() : Bus Release UNIMPLEMENTED\n"); +// xide_bus_release(co); // Unimplemented + goto cmd1; + } + + if ((drq==0) && (serv==1)) { + co->request_stage = BUS_RELEASE; + IDE_DBG(3,"!!!xide_intr() : Bus Release & SERVICE Request : UNIMPLEMENTED\n"); +// xide_write_service(co); // Unimplemented + goto cmd1; + } + +cmd1: + IOUNLOCK(li->LunLock, li->LunSpl); + IDE_DBG(0,"xscsi/ide:Reason for Interrupt Not found!! co 0x"IDE_PTR" \n",co); +// IDE_ASSERT(0); +start_cmd: +// Needed because though xide_command() is called by xide_return_finished_req(), we don't return a 2 part request before the 2nd part is complete. + { + int try=2; + while ((xide_start1(pi)&(try--))) ; + } + return; + +} + +static int xide_scsi_resp_back(xide_CmdObj_t *co) +{ + xide_LunInfo_t *li; + xide_ProtoInfo_t *pi; + scsi_request_t *req_sense; + int status=0; + + li = co->li; + pi = li->ProtoInfo; + + if ((li==NULL)||(pi==NULL)) return IDE_E_ERR; + + IDE_ASSERT(mutex_mine(&li->LunLock)); + + if ((!((co->SentReq->sr_status == SC_GOOD) && (co->SentReq->sr_scsi_status == ST_GOOD))) && (pi->device_conf[li->TargInfo->Number] & ATAPI_DEV_PRESENT)){ + IDE_DBG(1,"Sending Request Sense Cmd for req 0x"IDE_PTR"\n",co->SentReq); + xide_co_free_dmamap(co); + req_sense = xide_get_requestsense(co); + co->ReqSense = req_sense; +#ifdef XSCSI + req_sense->sr_spare = (uint64_t)&(co->Tag); +#else + req_sense->sr_spare = (void *)&(co->Tag); +#endif + xide_queue_scsireq_top(li,req_sense); + return IDE_HOLD; + } + else + if (co->ReqSense) { + if (co->ReqSense != co->SentReq) { + IDE_DBG(1,"co->ReqSense != co->SentReq | co 0x"IDE_PTR"\n",co); + IDE_ASSERT(0); + } + else if (co->ReqSense->sr_command[0] == 0x03) { + // Gives error if SentReq is set to NULL as earlier + int i=0; + /* Current co has parent_co waiting on it */ + bcopy(co->ReqSense->sr_buffer, co->OrigReq->sr_sense,SCSI_SENSE_LEN); + co->OrigReq->sr_sensegotten = SCSI_SENSE_LEN; + co->OrigReq->sr_scsi_status = co->ReqSense->sr_scsi_status; + co->OrigReq->sr_status = co->ReqSense->sr_status; + for (i=0;iOrigReq->sr_sensegotten;i++) { + IDE_DBG(15,"Obuf[%d] : 0x%x ",i,co->OrigReq->sr_sense[i]); + } + // Assumes that internal req. will never get an error : dangerous assumption : stupid Aniket +#if IDE_CMD_DEBUG + bcopy(co->ReqSense->sr_command, xide_cmd_list[xide_cmd_index].command, co->ReqSense->sr_cmdlen); + xide_cmd_list[xide_cmd_index].request = co->ReqSense; + if (co->ReqSense->sr_status==0) { + xide_cmd_list[xide_cmd_index].action = IDE_CMD_SUCCESS; + } else { + xide_cmd_list[xide_cmd_index].action = IDE_CMD_ERROR; + } + + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif + (*(co->ReqSense->sr_notify))(co->ReqSense); + IDE_DBG(11,"After sr_notify for request_sense\n"); + co->SentReq = NULL; + co->ReqSense = NULL; + } + } + else { + + if (co->SentReq->sr_command[0] == READ_CAPACITY_CMD) { + if (co->SentReq->sr_buffer) { + int i; + int tmp_blk_num=0, tmp_blk_size=0; + + tmp_blk_num = ((uint32_t)co->SentReq->sr_buffer[0]<<24)| + ((uint32_t)co->SentReq->sr_buffer[1]<<16)| + ((uint32_t)co->SentReq->sr_buffer[2]<<8)| + ((uint32_t)co->SentReq->sr_buffer[3]); + + tmp_blk_size = ((uint32_t)co->SentReq->sr_buffer[4]<<24)| + ((uint32_t)co->SentReq->sr_buffer[5]<<16)| + ((uint32_t)co->SentReq->sr_buffer[6]<<8)| + ((uint32_t)co->SentReq->sr_buffer[7]); + + IDE_DBG(1,"tmp_blk_size 0x%x | tmp_blk_num 0x%x \n",tmp_blk_size,tmp_blk_num); + // bcopy(co->SentReq->sr_buffer,&li->CapNumOfBlocks, 8); + for (i=0;i<8;i++) { + IDE_DBG(11,"buf[%d] : 0x%x\t",i,co->SentReq->sr_buffer[i]); + } + IDE_DBG(11,"\n"); + li->CapNumOfBlocks = tmp_blk_num; + li->CapBlockSize = tmp_blk_size; + IDE_DBG(1,"li->CapNumOfBlocks 0x%x | li->CapBlockSize 0x%x\n", + li->CapNumOfBlocks,li->CapBlockSize); + + li->CapNumOfBlocks += 1; // Expects Total Num. of Blocks IMP CHECK!!!!! + li->CapDataValid = 1; + if (li->BlockSizeValid == 0) { + li->BlockSize = li->CapBlockSize; + IDE_DBG(13,"Setting li->BlockSize to 0x%x\n",li->BlockSize); + li->BlockSizeValid = 1; + } + } + } + + if ((co->OrigReq->sr_buffer != 0) &&(co->OrigReq->sr_command[0] == READ_CAPACITY_CMD)&&(li->BlockSize < li->CapBlockSize)) { + uint fixed_cap,i; + uint fix_multiple; + + fix_multiple = li->CapBlockSize / li->BlockSize; + fixed_cap = ((li->CapNumOfBlocks + 1)* fix_multiple) - 1; + + IDE_DBG(11,"resp_back() : Changing buffer in get_capacity() command req 0x"IDE_PTR" | fixed_cap %d\n",co->SentReq,fixed_cap); + co->OrigReq->sr_buffer[0] = fixed_cap >> 24; + co->OrigReq->sr_buffer[1] = fixed_cap >> 16; + co->OrigReq->sr_buffer[2] = fixed_cap >> 8; + co->OrigReq->sr_buffer[3] = fixed_cap; + co->OrigReq->sr_buffer[4] = li->BlockSize >> 24; + co->OrigReq->sr_buffer[5] = li->BlockSize >> 16; + co->OrigReq->sr_buffer[6] = li->BlockSize >> 8; + co->OrigReq->sr_buffer[7] = li->BlockSize; + + for (i=0; iOrigReq->sr_buflen;i++) { + IDE_DBG(11,"GCap[%d] : 0x%x ",i,co->OrigReq->sr_buffer[i]); + } + } + + if (co->TempReqForFix != NULL) { + IDE_DBG(15,"resp_back() : co->TempReqForFix != NULL | SentReq 0x"IDE_PTR"\n",co->SentReq); + if ( +#ifndef XSCSI + (co->OrigReq->sr_command[0] == MODE_SENSE10_CMD)|| +#endif + (co->OrigReq->sr_command[0] == MODE_SENSE6_CMD)|| + (co->OrigReq->sr_command[0] == READ_CAPACITY_CMD)) { + if (co->OrigReq->sr_buffer!=0) { + status = xide_fix_mode_cmd_rcv(co->OrigReq,co,co->SentReq->sr_status); + { int modelen; + for (modelen=0; modelenOrigReq->sr_buflen; modelen++) { + IDE_DBG(31,"Mss[%d] 0x%x | ",modelen,co->OrigReq->sr_buffer[modelen]); + if (!((modelen+1)%16)) IDE_DBG(31,"\n"); + } + } + } else { + IDE_DBG(11,"rcv like cmd but alenlist passed in : co 0x"IDE_PTR"\n",co); + } + } + if (status==IDE_HOLD) { + IDE_DBG(15,"Probably asking for block_descriptor co 0x"IDE_PTR"\n",co); + return IDE_HOLD; + } + if (co->HoldReq == co->SentReq) { + IDE_DBG(11,"scsi_resp_back() : before calling sr_notify for 0x"IDE_PTR" \n", co->SentReq); + +#if IDE_CMD_DEBUG + bcopy(co->SentReq->sr_command, xide_cmd_list[xide_cmd_index].command, co->SentReq->sr_cmdlen); + xide_cmd_list[xide_cmd_index].request = co->SentReq; + if (co->SentReq->sr_status==0) { + xide_cmd_list[xide_cmd_index].action = IDE_CMD_SUCCESS; + } else { + xide_cmd_list[xide_cmd_index].action = IDE_CMD_ERROR; + } + + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif + + (*(co->SentReq->sr_notify))(co->SentReq); + IDE_DBG(11,"After sr_notify for Msense's temp_req \n"); + co->HoldReq=NULL; + co->SentReq = NULL; + } + } + else { + dki_dcache_inval(co->SentReq->sr_buffer,co->SentReq->sr_buflen); + IDE_DBG(11,"after dki_dcache_invalidate \n"); + } + + co->OrigReq->sr_resid =0; + } + + + if (co->OrigReq->sr_resid !=0 ) { + IDE_DBG(11,"co->OrigReq->sr_resid !=0 | co 0x"IDE_PTR"\n",co); + } + + xide_finish_scsireq(li,co->OrigReq); + + if (li->ContAlleg == 1) { + xide_return_lun_cmds(li,SC_ATTN); + } + xide_remove_co(co); + xide_return_co_resources(co); + xide_test_co_for_free(co); + + return 0; +} + +static void xide_return_lun_cmds(xide_LunInfo_t *li, int rtn_status) +{ + xide_CmdObj_t *co=NULL; + xide_CmdObj_t *next_co=NULL; + scsi_request_t *req; + + IDE_ASSERT(mutex_mine (&li->LunLock)); + + co = li->CmdObjTail; + if (co == NULL) { + IDE_DBG(11,"xide_return_lun_cmds() : li->CmdObjTail 0x"IDE_PTR"\n",li->CmdObjTail); + return; + } + + while (co != NULL) { + next_co = co->Next; + req = co->OrigReq; + req->sr_status = rtn_status; + dki_dcache_inval(req->sr_buffer, req->sr_buflen); + req->sr_resid = req->sr_buflen; + IDE_DBG(11,"xide_return_lun_cmds() : co "IDE_PTR" \n",co); + co->request_stage = CMD_COMPLETE; + xide_complete_a_req(li,req); + xide_remove_co(co); + xide_return_co_resources(co); +// xide_return_free_co(li->ProtoInfo,co); + xide_test_co_for_free(co); + co = next_co; + } + + IDE_ASSERT(li->CmdObjHead == NULL); + IDE_ASSERT(li->CmdObjTail == NULL); + return; + +} + +static void xide_return_finished_req(xide_ProtoInfo_t *pi) +{ + scsi_request_t *req; + scsi_request_t *next_req; + + IOLOCK(pi->FinishedQLock,pi->FinishedQSpl); + + req = pi->FinishedQHead; + pi->FinishedQHead = NULL; + pi->FinishedQTail = NULL; + IOUNLOCK(pi->FinishedQLock, pi->FinishedQSpl); + + while (req != NULL) { + next_req = req->sr_ha; + if (req->sr_notify) { + IDE_DBG(11,"xide_return_finished_req() : before sr_notify \n"); +#if IDE_CMD_DEBUG + bcopy(req->sr_command, xide_cmd_list[xide_cmd_index].command, req->sr_cmdlen); + xide_cmd_list[xide_cmd_index].request = req; + if (req->sr_scsi_status==0) { + xide_cmd_list[xide_cmd_index].action = IDE_CMD_SUCCESS; + } else { + xide_cmd_list[xide_cmd_index].action = IDE_CMD_ERROR; + } + + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif + IDE_ASSERT((uintptr_t)req->sr_notify > 0x80000000); + (*req->sr_notify)(req); + + } + req = next_req; + } +} + +static void xide_finish_scsireq(xide_LunInfo_t *li, scsi_request_t *req) +{ + xide_CmdObj_t *co; + + co = (xide_CmdObj_t *)req->sr_spare; + IDE_DBG(12,"finish_scsireq() : co 0x"IDE_PTR"\n",co); + IDE_ASSERT(co!=NULL); + + dki_dcache_inval(req->sr_buffer, req->sr_buflen); + xide_complete_a_req(li,req); +} + +static void xide_complete_a_req(xide_LunInfo_t *li, scsi_request_t *req) +{ + scsi_request_t *tail; + xide_ProtoInfo_t *pi; + + pi = li->ProtoInfo; + + IOLOCK(pi->FinishedQLock, pi->FinishedQSpl); + + tail = pi->FinishedQTail; + if (tail == 0) { + req->sr_ha = NULL; + pi->FinishedQHead = pi->FinishedQTail = req; + IDE_DBG(3,"xide_complete_a_req: tail 0x"IDE_PTR"; req 0x"IDE_PTR"\n",tail,req); + } + else { + req->sr_ha = 0; + tail->sr_ha = req; + pi->FinishedQTail = req; + IDE_DBG(3,"xide_complete_a_req: tail 0x"IDE_PTR"; req 0x"IDE_PTR"\n",tail,req); + } + + IDE_ASSERT((uintptr_t)req->sr_notify > 0x80000000); + IOUNLOCK(pi->FinishedQLock, pi->FinishedQSpl); + +} + +static void xide_test_co_for_free(xide_CmdObj_t *co) +{ + xide_ProtoInfo_t *pi; + + pi = co->li->ProtoInfo; + + IDE_DBG(13,"xide_test_co_for_free(co = 0x"IDE_PTR") | Got pi 0x"IDE_PTR"\n",co,pi); + xide_return_free_co(pi,co); + return; +} + + + +static int xide_return_co_tag(xide_CmdObj_t *co) +{ + xide_LunInfo_t *li; + + li = co->li; + IDE_DBG(12,"return_co_tag(0x"IDE_PTR") : tag %d\n",co,co->Tag); + IDE_DBG(12,"return_co_tag() : Tag before return 0x%x\n",li->Tag_Used); + li->Tag_Used = li->Tag_Used & ~(1<<(co->Tag)); + IDE_DBG(12,"return_co_tag() : Tag After return 0x%x\n",li->Tag_Used); + return li->Tag_Used; +} + +static void xide_return_co_resources( xide_CmdObj_t *co) +{ + xide_ProtoInfo_t *pi; + + pi= co->li->ProtoInfo; + IOLOCK(pi->ResourceLock, pi->ResourceLockSpl); + + if (co->UseBigmap == 1) { + co->li->ProtoInfo->BigmapInUse = 0; + co->UseBigmap = 0; + } + +#ifdef USE_MAPPED_PCI_TRANSLATION + if (co->PteDMAMap != NULL) { /* space allocated for PTE */ + IDE_DBG(13,"xide_return_co_resources() : PteDMAMap existed\n"); + pciio_dmamap_free(co->PteDMAMap); + co->PteDMAMap = NULL; + } +#endif + + if (co->AllocMapSize > 0) { + IDE_DBG(1,"xide_return_co_resources() : AllocMapSize existed\n"); + IDE_KMEM_FREE((caddr_t)co->Pte, co->AllocMapSize); + co->AllocMapSize = 0; + } + +#ifdef USE_MAPPED_PCI_TRANSLATION +#ifndef CONFIG_IA64_SGI_SN + if (co->DataDMAMap != NULL) { /* data space map exists */ + IDE_DBG(13,"xide_return_co_resources() : DataDMAMap existed\n"); + pciio_dmamap_free(co->DataDMAMap); + co->DataDMAMap = NULL; + } +#endif +#endif + + if (co->NumPtes > 0) { + IDE_ASSERT(co->PciAlenList != NULL); + } + + xide_co_free_dmamap(co); +/* +#ifdef XSCSI + if (co->PciAlenList != NULL) { +#ifdef CONFIG_IA64_SGI_SN + { + int i; + int npgs; + xide_std_PageTblEntry_t *sgmap32=NULL; + xide_ioc4_PageTblEntry_t *sgmap64=NULL; + +// sbp_PageTblEntry_t *sgmap; + + npgs = co->NumPtes; + +// if (co->MapEndLen > 0) npgs--; + + if (pi->vendorid == CMD_VENDOR_ID) { + sgmap32 = (xide_std_PageTblEntry_t *)co->Pte; +// if (co->MapStartLen > 0) { +// npgs--; +// sgmap32++; +// } + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + sgmap64 = (xide_ioc4_PageTblEntry_t *)co->Pte; +// if (co->MapStartLen > 0) { +// npgs--; +// sgmap64++; +// } + } + + IDE_DBG(11,"xide_return_co_resources(): npgs %d | alenlist_size(co->PciAlenList) %d\n",npgs,alenlist_size(co->PciAlenList)); + IDE_ASSERT(npgs == alenlist_size(co->PciAlenList)); + + for (i = 0; i < npgs; i++) { + if (pi->vendorid == CMD_VENDOR_ID) { +// swab32_region((uint32_t *)sgmap32, sizeof(*sgmap32)); + swab64_32((uint64_t *)sgmap32); + if ((xide_mapped[xide_map_out] != (alenaddr_t)sgmap32->Adr)) { + int xide_tmp; + + IDE_DBG(0,"xscsi/ide:xide_return_co_resources() : xide_mapped : [out %d] 0x%x | [in %d] 0x%x | sgmap32->Adr 0x%x \n", + xide_map_out,xide_mapped[xide_map_out],xide_map_in,xide_mapped[xide_map_in],sgmap32->Adr); + for (xide_tmp=xide_map_out-10;(xide_tmp <= xide_map_out) & (xide_tmp >= 0); xide_tmp++) { + IDE_DBG(0,"xscsi/ide:xide_return_co_resources() : xide_mapped[%d] 0x%x \n",xide_tmp,xide_mapped[xide_tmp]); + } + IDE_DBG(0,"xscsi/ide:xide_return_co_resources() : defxide_map_in %d | xide_map_out %d \n",xide_map_in,xide_map_out); + } + IDE_ASSERT(xide_mapped[xide_map_out] == (alenaddr_t)sgmap32->Adr); + pci_unmap_single(pi->PciVhdl, sgmap32->Adr, sgmap32->EOT_Resv_Len, PCI_DMA_BIDIRECTIONAL); + xide_map_out++; + if (xide_map_out > 255) xide_map_out = 0; + sgmap32++; + } else if (pi->vendorid == PCI_VENDOR_SGI ) { +// PUT IN something when U get the IOC4 - 6/20/2002 +// swab32_region((uint32_t *)sgmap64, sizeof(*sgmap32)); +// swab64_32((uint64_t *)sgmap64); + pci_unmap_single(pi->PciVhdl, sgmap64->Adr, sgmap64->EOT_Resv_Len, PCI_DMA_BIDIRECTIONAL); +// IDE_ASSERT(xide_mapped[xide_map_out] == (alenaddr_t)sgmap64->Adr); + xide_map_out++; + if (xide_map_out > 255) xide_map_out = 0; + sgmap64++; + } + } + } +#endif + if (co->PciAlenList != co->AlenList) alenlist_done(co->PciAlenList); + } +#endif +*/ + if (co->AlenList != NULL) { +#ifndef XSCSI + alenlist_done(co->AlenList); +#endif + co->AlenList = NULL; + } + + co->PciAlenList = NULL; + + if ((uintptr_t)co->TempReqForFix > 1) { + scsi_request_t *temp_req; + + temp_req = co->TempReqForFix; +// if (temp_req->sr_buflen > 0) { + if (temp_req->sr_buffer > 0 ) { + IDE_KMEM_FREE(temp_req->sr_buffer, temp_req->sr_buflen); + } + IDE_KMEM_FREE(temp_req, sizeof(scsi_request_t)); + } + + co->TempReqForFix = NULL; + co->FixMap4BlkSz = 0; + co->HoldReq = NULL; + co->OrigReq = NULL; + co->SentReq = NULL; + co->MapEndLen = 0; + co->MapStartLen = 0; + co->NumPtes = 0; + +// co->State = co->State & ~IDE_CO_ACTIVE; + co->State = IDE_CO_FREE; + + co->Offset_Flag=0; + co->offset=0; +// co->saved_Pte=NULL; + co->start_Pte=NULL; + co->start_PtePciAddr=0; + co->Prev_Num_Blocks=0; + + IOUNLOCK(pi->ResourceLock, pi->ResourceLockSpl); + + return; +} + +/* Removes co from the li->CmdObjHead/Tail Queue */ +static void xide_remove_co(xide_CmdObj_t *co) +{ + xide_LunInfo_t *li; + xide_CmdObj_t *prev_co=NULL; + xide_CmdObj_t *chk_co=NULL; + int i=0; + + + li = co->li; + + IDE_ASSERT(mutex_mine(&li->LunLock)); + + chk_co = li->CmdObjTail; + while ((chk_co != co) && (chk_co != NULL)) { + prev_co = chk_co; + chk_co = chk_co->Next; + i++; + } + IDE_DBG(12,"remove_co(): Found co 0x"IDE_PTR" at position %d in CmdObjHead/Tail Queue\n",chk_co,i); + IDE_ASSERT(chk_co == co); + if (co == li->CmdObjHead) { // Head of Queue + IDE_DBG(12,"remove_co(): Found co 0x"IDE_PTR" at Head\n",chk_co,i); + li->CmdObjHead = prev_co; + } + if (prev_co == NULL) { + IDE_DBG(12,"remove_co(): Found co 0x"IDE_PTR" at Tail\n",chk_co,i); + li->CmdObjTail = co->Next; // Tail of Queue + if (co->Next) { + co->Next->Prev = NULL; + } + } + else { + prev_co->Next = co->Next; + co->Next->Prev = prev_co; + } + + co->Next = NULL; + co->Prev = NULL; + xide_return_co_tag(co); + + return; +} + +static scsi_request_t *xide_get_requestsense(xide_CmdObj_t *co) +{ + scsi_request_t *req; + u_char *cap_space; + u_char *cmd,*sense_buf; + int space_to_alloc; + + space_to_alloc = sizeof(scsi_request_t) + 12 + SCSI_SENSE_LEN; + /* request + cmd + sense */ + + IDE_KMEM_ZALLOC(cap_space,space_to_alloc,KM_NOSLEEP); + req = (scsi_request_t *)cap_space; + sense_buf = cap_space + sizeof(scsi_request_t); + cmd = sense_buf + SCSI_SENSE_LEN; + + cmd[0] = 0x03; // Request Sense Command + cmd[4] = SCSI_SENSE_LEN; + + req->sr_ctlr = co->li->ProtoInfo->Number; + req->sr_target = co->li->TargInfo->Number; + req->sr_lun = co->li->Number; + req->sr_command = cmd; + req->sr_cmdlen = 12; + req->sr_buffer = (u_char *)sense_buf; + req->sr_buflen = SCSI_SENSE_LEN; + req->sr_flags = SRF_DIR_IN | SRF_FLUSH | SRF_AEN_ACK; + req->sr_timeout = 10 * HZ; + req->sr_notify = xide_requestsense_done; + req->sr_lun_vhdl =co->li->LunVhdl; + + { int i; + for (i=0; isr_buflen; i++) { + req->sr_buffer[i] = i; + } + } + + IDE_DBG(11,"xide_get_requestsense() : req 0x"IDE_PTR" \n",req); + return(req); +} + +static void xide_requestsense_done(scsi_request_t *req) +{ + int allocated_space; + + allocated_space = sizeof(scsi_request_t) + 12 + SCSI_SENSE_LEN; + IDE_KMEM_FREE(req, allocated_space); +} + +static int xide_pktDMA_start(xide_CmdObj_t *co, uint8_t command) +{ + xide_ProtoInfo_t *pi; + xide_LunInfo_t *li; + ushort dma_direction=0; + + + li = co->li; + pi = li->ProtoInfo; + + if (pi->vendorid == CMD_VENDOR_ID) { + uint8_t bmxidesr0,udxidetcr0; +// uint8_t status=0; + uint8_t write_bmxidesr0=0; + + bmxidesr0 = IDE_INB(pi,pi->dmablk,IDE_BMIDESR0); + udxidetcr0 = IDE_INB(pi,pi->dmablk,IDE_UDIDETCR0); + IDE_DBG(12,"DMA_start(): bmxidesr0 0x%x | udxidetcr0 0x%x\n",bmxidesr0,udxidetcr0); + + if ((co->SentReq->sr_flags & SRF_DIR_IN)!=0) { + dma_direction = IDE_DMA_WRITE; // DMA READ from device + } + else { + dma_direction = IDE_DMA_READ; // DMA Write to device + } + + if (bmxidesr0 & DMA_S_ACTIVE) { + IDE_DBG(1,"Warning!! DMA was active in previous transfer\n"); + IDE_OUTB(pi,pi->dmablk,IDE_BMIDECR0, IDE_DMA_STOP); +// debug("zing"); + } + + if (bmxidesr0 & DMA_S_ERROR) { + write_bmxidesr0 |= DMA_S_INTR|DMA_S_ERROR; + } + + if (pi->LastTargServed == 0) { + write_bmxidesr0 |= DMA_S_MASTER; + } + + if (pi->LastTargServed == 1) { + write_bmxidesr0 |= DMA_S_SLAVE; + } + + IDE_DBG(12,"write_bmxidesr0 : 0x%x\n",write_bmxidesr0); + IDE_OUTB(pi,pi->dmablk,IDE_BMIDESR0,write_bmxidesr0); + + /* Putting Starting address of PRD table + in the Descriptor Table Ptr reg. */ + IDE_OUTDW(pi,pi->dmablk,IDE_DTPR0,co->PtePciAddr); + IDE_DBG(13,"DMA_start() : Writing 0x%x in dtpr0\n",co->PtePciAddr); + + co->request_stage = PKT_DMA_START; + + IDE_OUTB(pi,pi->dmablk,IDE_BMIDECR0,IDE_DMA_START|dma_direction); + IDE_DBG(12,"DMA_start() : DMA Start signal to CMD649 given\n"); + } + + if (pi->vendorid == PCI_VENDOR_SGI) { + uint8_t ata_dma; + uint32_t ptepciaddr_l=0; + uint32_t ptepciaddr_h=0; + uint8_t status=0,count=0; + + + ata_dma = IDE_INB(pi,pi->dmablk,IOC4_DMA_CTRL); + if (ata_dma & IOC4_S_DMA_ACTIVE) { + IDE_DBG(0,"xscsi/ide:Warning!! IOC4 DMA was active in previous transfer\n"); +// IDE_ASSERT(0); + IDE_OUTB(pi,pi->dmablk,IOC4_DMA_CTRL,IOC4_S_DMA_STOP); + count=0; + do { + xide_delay(count); + ata_dma = IDE_INB(pi,pi->dmablk,IOC4_DMA_CTRL); + count ++; + } while ((ata_dma & IOC4_S_DMA_STOP)&& (count <100)); + if (ata_dma & IOC4_S_DMA_STOP) { + IDE_DBG(0,"xscsi/ide:xide_pktDMA_start(): IOC4 DMA STOP bit is still 1\n"); + IDE_ASSERT(0); + } + } + + status = IDE_INB(pi,pi->dmablk,IOC4_DMA_CTRL); + if (status & IOC4_S_DMA_ERROR) { + IDE_DBG(0,"xscsi/ide:Warning!! - DMA Error during Previous transfer | co 0x"IDE_PTR" | status 0x%x"IDE_PTR"\n",co,status); + IDE_OUTB(pi,pi->dmablk,IOC4_DMA_CTRL,IOC4_S_DMA_STOP); + count=0; + do { + ata_dma = IDE_INB(pi,pi->dmablk,IOC4_DMA_CTRL); +// xide_delay(1); + count ++; + } while ((ata_dma & IOC4_S_DMA_STOP)&& (count <100)); + if (ata_dma & IOC4_S_DMA_STOP) { + IDE_DBG(0,"xscsi/ide:xide_pktDMA_start(): IOC4 DMA STOP bit is still 1\n"); + IDE_ASSERT(0); + } + } + + ptepciaddr_l = (uint32_t)co->PtePciAddr; + ptepciaddr_h = (uint32_t)((co->PtePciAddr)>>32); + IDE_DBG(2,"ptepciaddr_h 0x%x | ptepciaddr_l 0x%x \n",(uint64_t)ptepciaddr_h,(uint64_t)ptepciaddr_l); + IDE_OUTDW(pi,pi->dmablk,IOC4_DMA_PTR_L,ptepciaddr_l); + IDE_OUTDW(pi,pi->dmablk,IOC4_DMA_PTR_H,ptepciaddr_h); + + bzero(pi->DmaEndPtr,IDE_CACHELINE_SIZE); + IDE_DBG(1,"pi->DmaEndPtr 0x"IDE_PTR" | data 0x%x \n",pi->DmaEndPtr,*(pi->DmaEndPtr)); + IDE_OUTDW(pi,pi->dmablk,IOC4_DMA_END_ADDR,pi->DmaEndAddr); + + co->request_stage = PKT_DMA_START; + + if ((co->SentReq->sr_flags & SRF_DIR_IN)!=0) { + dma_direction = IOC4_DMA_WRITE; // DMA READ from device + } + else { + dma_direction = IOC4_DMA_READ; // DMA Write to device + } + + IDE_DBG(1,"DMA_start() : DMA Start signal to SGI-IOC4 given\n"); + IDE_OUTB(pi,pi->dmablk,IOC4_DMA_CTRL,IOC4_S_DMA_START|dma_direction); + } +/* + if (pi->vendorid == PCI_VENDOR_ID_PROMISE) { + if (pi->devid == PCI_DEVICE_ID_PROMISE_20262){ + // DoesNOT work as yet: 12/19/2001 + uint32_t atapi_Ch1; + atapi_Ch1 = (0x01)<<24|co->OrigReq->sr_buflen; + IDE_DBG(3,"DMAstart() atapi_ch1 0x%x\n",atapi_Ch1); + IDE_OUTDW(pi,pi->dmablk,IDE_ATAPI_CH1,atapi_Ch1); + } + IDE_OUTB(pi,pi->dmablk,IDE_BMIDECR0,IDE_DMA_START|IDE_DMA_WRITE); + IDE_OUTDW(pi,pi->dmablk,IDE_ATAPI_CH1,0x0|co->OrigReq->sr_buflen); + } +*/ + return 0; + +} + +static int xide_pktDMA_complete(xide_ProtoInfo_t *pi) +{ + uint8_t bmxidesr0; + + if (pi->vendorid == CMD_VENDOR_ID) { + bmxidesr0 = IDE_INB(pi,pi->dmablk,IDE_BMIDESR0); + IDE_OUTB(pi,pi->dmablk,IDE_BMIDECR0, IDE_DMA_STOP); + IDE_OUTB(pi,pi->dmablk,IDE_BMIDESR0,0x06); + IDE_DBG(13,"DMA_complete() : bmxidesr0 0x%x\n",bmxidesr0); + + if (bmxidesr0 & DMA_S_INTR) { + /* Means that DMA transfer completed */ + if (!(bmxidesr0 & DMA_S_ACTIVE)) { + IDE_DBG(15,"DMA_complete() : Normal Completion\n"); + } + else { + IDE_DBG(1,"DMA_complete() : Completion : size(phy. mem)> IDE dev xfer size\n"); + } + } + if (bmxidesr0 & DMA_S_ERROR) { + IDE_DBG(0,"xscsi/ide:DMA_complete() : Controller Error during DMA Transfer!!\n"); + IDE_ASSERT(0); + return DMA_S_ERROR; + } + } + + if (pi->vendorid == PCI_VENDOR_SGI) { + uint bc_dev=-1, bc_mem=-1; + uint8_t dma_err=0,count=0; + + IDE_DBG(2,"complete() : Sending DMA stop \n"); + IDE_OUTB(pi,pi->dmablk,IOC4_DMA_CTRL,IOC4_S_DMA_STOP); + do { + dma_err = IDE_INB(pi,pi->dmablk,IOC4_DMA_CTRL); +// xide_delay(1); + count ++; + } while ((dma_err & IOC4_S_DMA_STOP)&& (count <100)); + if (dma_err & IOC4_S_DMA_STOP) { + IDE_DBG(0,"xscsi/ide:xide_pktDMA_complete(): IOC4 DMA STOP bit is still 1\n"); + IDE_ASSERT(0); + } + + dma_err = IDE_INB(pi,pi->dmablk,IOC4_DMA_CTRL); + bc_dev = IDE_INW(pi,pi->dmablk,IOC4_BC_DEV); + bc_mem = IDE_INW(pi,pi->dmablk,IOC4_BC_MEM); + + IDE_DBG(3,"dma_err = 0x%x | bc_dev = 0x%x | bc_mem = 0x%x", + dma_err,bc_dev,bc_mem); + IDE_DBG(3,"bc_dev 0x%x | byte count at device %d \n",bc_dev,(bc_dev&0x1e)>>1); + IDE_DBG(3,"bc_mem 0x%x | byte count in memory %d \n",bc_mem,(bc_mem&0x1e)>>1); + + + if ((dma_err & IOC4_S_DMA_ERROR )|| (pi->pci_dma_error)) { +// uint32_t pci_status_cmd_reg; + IDE_DBG(1,"DMA engine stop (due to PCI error)...cleared\n"); +// IDE_ASSERT(0); + return IOC4_S_DMA_ERROR; + + } + + if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) { + if (bc_dev > bc_mem+8) { + IDE_DBG(0,"xscsi/ide:: WARNING!!! bc_dev %d != bc_mem %d\n",bc_dev,bc_mem); + IDE_ASSERT(0); + } + } + + } + + return 0; +} + +static xide_LunInfo_t *xide_get_intr_lun(xide_ProtoInfo_t *pi) +{ + uint8_t drive=0; + uint8_t drive_targ=0; + drive = IDE_INB(pi,pi->cmdblk,IDE_DRIVE); + drive_targ = (drive&0x10)>>4; + IDE_DBG(11,"get_intr_lun() drive 0x%x | targ 0x%x \n",drive,drive_targ); + IDE_ASSERT((drive_targ==0) || (drive_targ==1)); + if (pi) { +// IOLOCK(pi->GraphLock, pi->GraphLockSpl); + if (pi->PtrToTarg[drive_targ]) { + if (pi->PtrToTarg[drive_targ]->PtrToLun[0]) { + return(pi->PtrToTarg[drive_targ]->PtrToLun[0]); + } + } +// IOUNLOCK(pi->GraphLock, pi->GraphLockSpl); + } + return NULL; +} + + +static xide_CmdObj_t *xide_get_co_from_tag(uint8_t tag,xide_LunInfo_t *li) +{ + xide_CmdObj_t *co; + + IDE_ASSERT(mutex_mine(&li->LunLock)); + + co = li->CmdObjTail; + + IDE_DBG(13,"xide_get_co_from_tag() | Tail 0x"IDE_PTR"\n",co); + while (co != NULL) { + if (co->Tag == tag) { + IDE_DBG(13,"Matching co 0x"IDE_PTR" with tag %d found\n",co,tag); + return co; + } + else { + co = co->Next; + } + } + + IDE_DBG(0,"xscsi/ide:xide_get_co_from_tag() : co with matching Tag NOT found!! \n"); + IDE_ASSERT(0); + return NULL; +} + +static int xide_send_pktbytes(xide_CmdObj_t *co) +{ + xide_ProtoInfo_t *pi; + xide_LunInfo_t *li; + int i=0; + uint16_t CmdBlk[6]={0,0,0,0,0,0}; + + li = co->li; + pi = li->ProtoInfo; + + IDE_DBG(1,"Targ : %d | req 0x"IDE_PTR" | co->CmdBlk ",pi->LastTargServed,co->SentReq); + for (i=0;i<6;i++) { + CmdBlk[i] = (co->CmdBlk[2*i+1]<<8)|(co->CmdBlk[2*i]); + IDE_DBG(1,"[%d] 0x%x ",i,CmdBlk[i]); + } + IDE_DBG(1,"\n"); + + i=0; + for (;i<6;i++) { +// IDE_PCI_OUTW(&(pi->cmdblk->data),CmdBlk[i]); + IDE_OUTW(pi,pi->cmdblk,IDE_DATA,CmdBlk[i]); + } + + return i*2; +} + +#if 0 +static int xide_pktPIO_data(xide_CmdObj_t *co) +{ + xide_ProtoInfo_t *pi; + xide_LunInfo_t *li; + int i=0; + uint8_t cyl_lsb,cyl_msb,count; + uint8_t alt_status,err_feature; + scsi_request_t *req; + uint16_t *buffer=NULL; + + li = co->li; + pi = li->ProtoInfo; + req = co->SentReq; + + if (req->sr_buflen) { + IDE_KMEM_ZALLOC(buffer,req->sr_buflen,VM_DIRECT); + IDE_ASSERT(buffer!=NULL); + } + + cyl_lsb = IDE_INB(pi,pi->cmdblk,IDE_CYL_LSB); + cyl_msb = IDE_INB(pi,pi->cmdblk,IDE_CYL_MSB); + count = IDE_INB(pi,pi->cmdblk,IDE_COUNT); + + IDE_DBG(11,"xide_pktPIO_data() : cyl_lsb 0x%x, cyl_msb 0x%x , count 0x%x \n",cyl_lsb,cyl_msb,count); + if ((count & 0x03) == 0x02) { /* Transfer from dev to host */ + do { /* Get Data */ + buffer[i] = IDE_INW(pi,pi->cmdblk,IDE_DATA); + alt_status = IDE_INB(pi,pi->ctrlblk,pi->xide_alt_status); + i++; + } while ((alt_status & IDE_S_DRQ)&& (i<256)); + IDE_DBG(1,"xide_pktPIO_data() : %d half-words GOT \n",i); + + xide_swap(buffer,i); + bcopy(buffer,req->sr_buffer,req->sr_buflen); + } + else if ((count & 0x03) == 0x0) { /* Transfer from host to dev */ + bcopy(req->sr_buffer,buffer,req->sr_buflen); + xide_swap(buffer,req->sr_buflen); + do { /* Put Data */ + IDE_OUTW(pi,pi->cmdblk,IDE_DATA,buffer[i]); + alt_status = IDE_INB(pi,pi->ctrlblk,pi->xide_alt_status); + i++; + IDE_ASSERT(isr_buflen); + } while (alt_status & IDE_S_DRQ); + IDE_DBG(14,"xide_pktPIO_data() : %d half-words PUT \n",i); + } + + alt_status = IDE_INB(pi,pi->ctrlblk,pi->xide_alt_status); + count = IDE_INB(pi,pi->cmdblk,IDE_COUNT); + err_feature = IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + + req->sr_scsi_status = alt_status & 0x01; + req->sr_status = (err_feature & 0xf0) >> 4; + IDE_DBG(14,"xide_pktPIO_data(): sr_status 0x%x | sr_scsi_status 0x%x\n",req->sr_status,req->sr_scsi_status); + IDE_DBG(14,"xide_pktPIO_data(): count 0x%x | err_feature 0x%x \n",count,err_feature); + return alt_status; +} +#endif + +/* Adds target : Should be called by probe routine with appropriate number */ +static struct xide_TargInfo_s *xide_target_add(xide_ProtoInfo_t *pi, uint8_t number) +{ + struct xide_TargInfo_s *ti=NULL; + scsi_targ_info_t *targ_info=NULL; + scsi_ctlr_info_t *proto_info=NULL; + xide_LunInfo_t *li=NULL; + + IDE_DBG(11,"xide_target_add() : pi 0x"IDE_PTR" \n",pi); + IDE_KMEM_ZALLOC(ti,sizeof(*ti),VM_CACHEALIGN); + if (ti == NULL) return NULL; + + IDE_DBG(11,"xide_target_add : ti 0x"IDE_PTR"\n",ti); + + INITLOCK(&pi->GraphLock, "Hwg Graph Lock", number); + + IOLOCK(pi->GraphLock, pi->GraphLockSpl); + IDE_DBG(14,"Insxide Lock\n"); + pi->PtrToTarg[number] = ti; + ti->ProtoInfo = pi; + ti->ProtoVhdl = pi->ProtoVhdl; + ti->Number = number; + ti->TargetVhdl = scsi_targ_vertex_add(ti->ProtoVhdl,ti->Number); +// targ_info = (scsi_targ_info_t *)hwgraph_fastinfo_get(ti->TargetVhdl); + targ_info = (scsi_targ_info_t *)scsi_targ_info_get(ti->TargetVhdl); + +// proto_info = (scsi_ctlr_info_t *)hwgraph_fastinfo_get(pi->ProtoVhdl); + proto_info = (scsi_ctlr_info_t *)scsi_ctlr_info_get(pi->ProtoVhdl); + IDE_ASSERT(proto_info!=NULL); + + STI_TARG_VHDL(targ_info) = ti->TargetVhdl; + STI_CTLR_INFO(targ_info) = proto_info; + STI_TARG(targ_info)= ti->Number; + STI_INFO(targ_info) = ti; + STI_PORT(targ_info) = STI_NODE(targ_info) = 0; +#ifndef XSCSI + sprintf(ti->HwgName, "%v", ti->TargetVhdl); +#else + sprintf(ti->HwgName,"IDE_%d_%d_%d",pi->PciVhdl->bus->number, pi->Number, ti->Number); +#endif + pi->device_conf[number] = pi->device_conf[number] | TARGET_IN_GRAPH; + + IOUNLOCK(pi->GraphLock, pi->GraphLockSpl); + li = xide_add_lun(ti,0); + if (li != NULL) { + pi->device_conf[number] = pi->device_conf[number] | DEV_IN_GRAPH; + IDE_DBG(5,"lun 0x"IDE_PTR" attached to target 0x"IDE_PTR" has been probed \n",li,ti); + } + return ti; +} + +static struct xide_LunInfo_s *xide_add_lun(struct xide_TargInfo_s *ti, int lun_Num) +{ + struct xide_LunInfo_s *li; + scsi_targ_info_t *targ_info; + scsi_lun_info_t *lun_info; + struct xide_ProtoInfo_s *pi; + int cmds_alloc; + uint8_t mode; + + pi = ti->ProtoInfo; + + IDE_KMEM_ZALLOC(li, sizeof(*li), VM_CACHEALIGN); + if (li== NULL) return NULL; + + IDE_KMEM_ZALLOC(li->tinfo.si_inq, SCSI_INQUIRY_LEN, KM_CACHEALIGN); + if (li->tinfo.si_inq == NULL) return NULL; + + IDE_KMEM_ZALLOC(li->tinfo.si_sense, SCSI_SENSE_LEN, KM_CACHEALIGN); + if (li->tinfo.si_sense == NULL) { + IDE_KMEM_FREE(li->tinfo.si_inq, SCSI_INQUIRY_LEN); + return(NULL); + } + + IDE_KMEM_ZALLOC(li->xidentifyDev,sizeof(xide_dev_t),KM_CACHEALIGN); + if (li->xidentifyDev == NULL) { + IDE_KMEM_FREE(li->tinfo.si_inq, SCSI_INQUIRY_LEN); + IDE_KMEM_FREE(li->tinfo.si_sense, SCSI_SENSE_LEN); + return(NULL); + } + + INITLOCK(&li->LunLock, "LunLock", lun_Num); + IOLOCK(pi->GraphLock, pi->GraphLockSpl); + li->Number= lun_Num; + ti->PtrToLun[lun_Num]=li; + + cmds_alloc = xide_alloc_cmd_object(pi); + if (cmds_alloc < 0) { + xide_unalloc_lun(li, NULL); + IOUNLOCK(pi->GraphLock, pi->GraphLockSpl); + return(NULL); + } + + li->LunVhdl = scsi_lun_vertex_add(ti->TargetVhdl, li->Number); + targ_info = (scsi_targ_info_t *)scsi_targ_info_get(ti->TargetVhdl); + lun_info = (scsi_lun_info_t *)scsi_lun_info_get(li->LunVhdl); + + if (lun_info == NULL) { + xide_unalloc_lun(li, NULL); + IOUNLOCK(pi->GraphLock, pi->GraphLockSpl); + return(NULL); + } + + SLI_LUN_VHDL(lun_info) = li->LunVhdl; + SLI_TARG_INFO(lun_info) = targ_info; + SLI_LUN(lun_info) = li->Number; + SLI_INFO(lun_info) = li; + + IOUNLOCK(pi->GraphLock, pi->GraphLockSpl); + + IOLOCK(li->LunLock, li->LunSpl); + li->ProtoVhdl = ti->ProtoVhdl; + li->TargetVhdl = ti->TargetVhdl; + li->TargInfo = ti; + li->ProtoInfo = ti->ProtoInfo; + + li->CmdObjHead = NULL; + li->CmdObjTail = NULL; + li->ScsiReqQHead = NULL; + li->ScsiReqQTail = NULL; + + li->WeAreCD = 0; + li->AddSenseBD = 0; + li->FixSenseBD = 0; + li->NoMode6Cmd = 0; + li->BlockSizeValid = 0; + li->CapBlockSize =0; + li->BlockSize =0; +// li->CapNumOfBlocks = NULL; + li->CapNumOfBlocks = 0; + li->ContAlleg = 0; + li->Tag_Used = 0; + li->CapDataValid=0; + +// xide_xidentifyDev(li); + mode = xide_setMode(li); + IDE_DBG(15,"Mode from xide_setMode() = 0x%x\n",mode); + xide_xidentifyDev(li); + xide_dma_init(li); + + IOUNLOCK(li->LunLock, li->LunSpl); + INITLOCK(&li->OpenLock,"Lun Open Lock",li->Number); + xide_info(li->LunVhdl); + return(li); +} + + +static int xide_piocommand(xide_LunInfo_t *li, command_regs_t *cmdSent, int bytes, uint16_t *buffer, int cmd_type, xide_CmdObj_t *co) +{ + xide_ProtoInfo_t *pi; + int i; + uint8_t status,count=-1,cyl_lsb,cyl_msb; + uint16_t word_count; + uint8_t intr_status=0; +// uint32_t no_interrupt=0; + + pi = li->ProtoInfo; + + if (cmd_type & NON_OVERLAP) { + if ((li->CmdObjHead != NULL) || (li->CmdObjTail != NULL)) { + IOLOCK(li->LunLock,li->LunSpl); + xide_return_lun_cmds(li,SC_ATTN); + IOUNLOCK(li->LunLock,li->LunSpl); + xide_return_finished_req(pi); + } + } + /* Disable interrupt */ + + IDE_DBG(13,"xide_piocmd () : Before lock to write cmds\n"); +// IOLOCK(pi->CommandLock, pi->CommandLockSpl); +// IDE_DBG(3,"xide_piocmd () : Waiting to write cmds\n"); +// do { +// status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND); +// } while (status & IDE_S_BUSY); +// IDE_DBG(113,"xide_piocmd () : Ready to write cmds | status is 0x%x \n",status); +// IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + + + IOLOCK(pi->IntrLock, pi->IntrLockSpl); + if (!(cmd_type & CMD_PACKET)) { + IDE_DBG(13,"xide_piocmmand() :Not a Packet cmd\n"); + pi->intr_set = 0; + intr_status = IDE_NIEN; + if (pi->prevent_intr != 1) { + pi->prevent_intr = 1; // No Interrupts + } + } + else { + pi->intr_set = 1; +#ifdef XSCSI + up(&pi->intr_watch_q); +#endif + if (pi->prevent_intr >0) { + pi->prevent_intr=0; // Interrupts Needed + IDE_DBG(11,"xide_piocmmand() :Interrupts Enabled\n"); + intr_status = 0; + } + } + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); + + IDE_DBG(2,"xide_piocommand() drive 0x%x | ef 0x%x | count 0x%x | sector 0x%x | lsb 0x%x msb 0x%x | cmd 0x%x \n",cmdSent->drive,cmdSent->err_feature, + cmdSent->count,cmdSent->sector,cmdSent->cyl_lsb,cmdSent->cyl_msb, + cmdSent->command); + + IOLOCK(pi->CommandLock, pi->CommandLockSpl); + IDE_OUTB(pi,pi->ctrlblk,pi->xide_alt_status,intr_status); + IDE_OUTB(pi,pi->cmdblk,IDE_DRIVE,cmdSent->drive); + IDE_OUTB(pi,pi->cmdblk,IDE_ERR_FEATURE,cmdSent->err_feature); + IDE_OUTB(pi,pi->cmdblk,IDE_COUNT,cmdSent->count); + IDE_OUTB(pi,pi->cmdblk,IDE_SECTOR,cmdSent->sector); + IDE_OUTB(pi,pi->cmdblk,IDE_CYL_LSB,cmdSent->cyl_lsb); + IDE_OUTB(pi,pi->cmdblk,IDE_CYL_MSB,cmdSent->cyl_msb); + IDE_OUTB(pi,pi->cmdblk,IDE_COMMAND,cmdSent->command); + + + if (cmd_type & CMD_ATA_DMA) { + if (co->SentReq->sr_buflen != 0) { + co->request_stage = PKT_DATA_TRANSFER; +// xide_dma_init(li); + xide_pktDMA_start(co, cmdSent->command); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + return 0; + } + } + +// if (xide_get_status(pi,&status,0)) { +// IDE_DBG(0,"xscsi/ide:xide_piocommand: status remained 0x%x after writing regs \n",status); +// IDE_ASSERT(0); +// } + + do { + status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND) ; + }while (status & IDE_S_BUSY); + IDE_DBG(2,"xide_piocommand(after) Got 0x%x status after writing regs\n",status); + + if (cmd_type & CMD_PACKET) { + if (status & IDE_S_DRQ) { + int temp=-1; + co->request_stage = PKT_BYTES_SENT; + pi->DmaEndPtr[0] = 13; // to avoid stale data check + temp = xide_send_pktbytes(co); + IDE_DBG(3,"xide_piocommand() %d PKT bytes sent \n",temp); + co->request_stage = PKT_DATA_TRANSFER; + if (co->SentReq->sr_buflen != 0) { + uint ret=0; + ret = xide_pktDMA_start(co,cmdSent->command); + IDE_DBG(11,"xide_picommand: After pktDMA_start ret %d \n",ret); + } + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + return 0; + } + } + + if (cmd_type & PIO_NONDATA) { + IDE_DBG(13,"xide_piocommand() : Non Data PIO cmd \n"); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + return status; + } + + count = IDE_INB(pi,pi->cmdblk,IDE_COUNT) ; + cyl_lsb = IDE_INB(pi,pi->cmdblk,IDE_CYL_LSB) ; + cyl_msb = IDE_INB(pi,pi->cmdblk,IDE_CYL_MSB) ; + + word_count = cyl_msb<<8 | cyl_lsb; + IDE_DBG(13,"piocommand() : count 0x%x\n | cyl_msb 0x%x | cyl_lsb 0x%x | word_count %d",count,cyl_msb,cyl_lsb,word_count); + + i=0; +// if ((count & 0x03) == 0x02) { /* Read Command : PIO Data IN */ + if (cmd_type & PIO_DATA_IN) { /* Read Command : PIO Data IN */ + status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND) ; + + if (status & IDE_S_DRQ) { +// while (i*2cmdblk,IDE_DATA); + i++; + } + } + + IDE_DBG(15,"xide_piocommand() Got 0x%x status after reading %d words of data\n",status,i); + status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND) ; + + if (status & IDE_S_BUSY) { + do { + status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND) ; + }while (status & IDE_S_BUSY); + IDE_DBG(15,"xide_piocommand() Got 0x%x status 'cause BSY was 1\n",status); + } + + if (i*2 != bytes) { + IDE_DBG(2,"xide_piocommand() CHECK!!! Read %d bytes | %d bytes requested\n",i*2,bytes); + } + } + +// if ((count & 0x03) == 0x0) { + if (cmd_type & PIO_DATA_OUT) { + do { + status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND) ; + if (status & IDE_S_DRQ) { + IDE_OUTW(pi,pi->cmdblk,IDE_DATA,buffer[i]); + i++; + } + } while (status & IDE_S_DRQ); + + IDE_DBG(15,"xide_piocommand() Got 0x%x status after reading data\n",status); + + if (status & IDE_S_BUSY) { + do { + status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND) ; + }while (status & IDE_S_BUSY); + IDE_DBG(15,"xide_piocommand() Got 0x%x status 'cause BSY was 1\n",status); + } + + if (i*2 != bytes) { + IDE_DBG(2,"xide_piocommand() CHECK!!! Wrote %d bytes | %d bytes requested\n",i*2,bytes); + } + } + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + return status; +} + + +static void +xide_unalloc_lun(xide_LunInfo_t *li, void *lock_to_unlock) +{ + + if (lock_to_unlock != NULL) + mutex_unlock(lock_to_unlock); + + FREELOCK(&li->LunLock); + FREELOCK(&li->OpenLock); + + IDE_KMEM_FREE(li->xidentifyDev, sizeof(xide_dev_t)); + IDE_KMEM_FREE(li->tinfo.si_inq, SCSI_INQUIRY_LEN); + IDE_KMEM_FREE(li->tinfo.si_sense, SCSI_SENSE_LEN); + IDE_KMEM_FREE(li, sizeof(*li)); + +} + +static int xide_xidentifyDev(xide_LunInfo_t *li) +{ + uint16_t buffer[256]; + uint8_t status; + xide_ProtoInfo_t *pi; + xide_TargInfo_t *ti; + command_regs_t *cmdSent; + + IDE_KMEM_ZALLOC(cmdSent,sizeof(cmdSent),VM_DIRECT); + IDE_ASSERT(cmdSent!=NULL); + + pi = li->ProtoInfo; + ti = li->TargInfo; + + if (pi->device_conf[ti->Number] & ATAPI_DEV_PRESENT) { + /* Send Identify Packet Device Command */ + cmdSent->command = 0xA1; + IDE_DBG(13,"\nSending 'Identify Packet Device' Command\n"); + } + else if (pi->device_conf[ti->Number] & ATA_DEV_PRESENT) { + /* Send Identify Device Command */ + cmdSent->command = 0xEC; + IDE_DBG(2,"\nSending 'Identify Device' Command\n"); + } + cmdSent->drive=(ti->Number)<<4; + cmdSent->data=0; + cmdSent->err_feature=0; + cmdSent->count=0; + cmdSent->sector=0; + cmdSent->cyl_lsb=0; + cmdSent->cyl_msb=0; + + status = xide_piocommand(li,cmdSent,sizeof(buffer),buffer,NON_OVERLAP|PIO_DATA_IN,NULL); + + + IDE_KMEM_FREE((void *)cmdSent,sizeof(*cmdSent)); + bcopy(buffer,li->xidentifyDev,sizeof(xide_dev_t)); + IDE_DBG(11,"Target %d | Queue_Depth %d \n",ti->Number, li->xidentifyDev->queue_depth); + return status; +} + +#if 0 +static int xide_autopoll(xide_LunInfo_t *li) +{ + uint8_t status,err_feature; + command_regs_t *cmdSent=NULL; + xide_ProtoInfo_t *pi=NULL; + xide_TargInfo_t *ti=NULL; + + IDE_KMEM_ZALLOC(cmdSent,sizeof(cmdSent),VM_DIRECT); + IDE_ASSERT(cmdSent!=NULL); + + pi = li->ProtoInfo; + ti = li->TargInfo; + + cmdSent->command = 0x0; /* NOP Command */ + cmdSent->err_feature = 0x01; /* Auto Poll Mode */ + cmdSent->drive=(ti->Number)<<4; + cmdSent->sector=0; + cmdSent->cyl_lsb=0; + cmdSent->cyl_msb=0; + cmdSent->data =0; + + status = xide_piocommand(li,cmdSent,0,NULL,NON_OVERLAP|PIO_NONDATA,NULL); + IDE_KMEM_FREE((void *)cmdSent,sizeof(*cmdSent)); + err_feature = IDE_INB(pi,pi->cmdblk,IDE_ERR_FEATURE); + IDE_DBG(2,"xide_autopoll() : Status 0x%x\n | Err 0x%x",status,err_feature); + return (status); +} +#endif + + +static int xide_setMode(xide_LunInfo_t *li) +{ + command_regs_t *cmdSent; + xide_TargInfo_t *ti; + + IDE_KMEM_ZALLOC(cmdSent,sizeof(cmdSent),VM_DIRECT); + IDE_ASSERT(cmdSent!=NULL); + + ti = li->TargInfo; + + cmdSent->command = 0xEF; /* Set Feature Command */ + cmdSent->err_feature = 0x03; /* Set Tranfer Mode */ + cmdSent->drive=(ti->Number)<<4; + cmdSent->sector=0; + cmdSent->cyl_lsb=0; + cmdSent->cyl_msb=0; + cmdSent->data =0; + + /* Go from Fastest to Slowest supported modes */ + if (!(li->xidentifyDev->udma5_sel & li->xidentifyDev->udma5_sup)) { + cmdSent->count = 0x45; + } + else + if (!(li->xidentifyDev->udma4_sel & li->xidentifyDev->udma4_sup)) { + cmdSent->count = 0x44; + } + else + if (!(li->xidentifyDev->udma3_sel & li->xidentifyDev->udma3_sup)) { + cmdSent->count = 0x43; + } + else + if (!(li->xidentifyDev->udma2_sel & li->xidentifyDev->udma2_sup)) { + cmdSent->count = 0x42; + } + else + if (!(li->xidentifyDev->udma1_sel & li->xidentifyDev->udma1_sup)) { + cmdSent->count = 0x41; + } + else + if (!(li->xidentifyDev->udma0_sel & li->xidentifyDev->udma0_sup)) { + cmdSent->count = 0x40; + } + else + if (!(li->xidentifyDev->multidma_2supp & li->xidentifyDev->multidma_2)) { + cmdSent->count = 0x22; + } + else + if (!(li->xidentifyDev->multidma_1supp & li->xidentifyDev->multidma_1)) { + cmdSent->count = 0x21; + } + else + if (!(li->xidentifyDev->multidma_0supp & li->xidentifyDev->multidma_0)) { + cmdSent->count = 0x20; + } + else + if (li->xidentifyDev->pio_modes) { + cmdSent->count = 0x08 | li->xidentifyDev->pio_modes; + } + else + if (li->xidentifyDev->iordy_no) { + cmdSent->count = 0x01; + } + else { + cmdSent->count = 0x0; + } + + if (li->ProtoInfo->device_conf[ti->Number] & ATAPI_DEV_PRESENT) { + cmdSent->count = 0x22; + } + else + if (li->ProtoInfo->device_conf[ti->Number] & ATA_DEV_PRESENT) { + cmdSent->count = 0x45; + } + + xide_piocommand(li,cmdSent,0,NULL,NON_OVERLAP|PIO_NONDATA,NULL); + + IDE_KMEM_FREE((void *)cmdSent,sizeof(*cmdSent)); + return (0x22); +} + +/* Allocates Space for CmdObjs, PTEs (of CmdObjs) + BigMap + Transfer_Scratch */ +static int xide_alloc_cmd_object(xide_ProtoInfo_t *pi) +{ + int i; + int space_for_big_map; + int space_for_1_xaction; /* Space for 1 CmdObj */ + int space_for_pte; + int space_for_xaction_o; /* Space for 1 PTE */ + int space_for_xactions_t; /* Total CmdObj Space */ + int space_for_bm; /* Total Space = pte + bm + scratch */ + int space_for_xferscratch; /* Scratch Space */ + + caddr_t mem_for_t_p; /* Total CmdObj Space allocated in Memory */ + caddr_t mem_for_o_p; /* Total Space allocated for pte + bm + scratch */ + paddr_t mem_for_o_p_pa; /* Physical Memory allocated to pte + bm + scratch */ + caddr_t mem_for_dmaendmap; + paddr_t mem_for_dmaendmap_pa; + + xide_CmdObj_t *curr_cmd_obj; + xide_CmdObj_t *next_cmd_obj; + xide_CmdObj_t *prev_cmd_obj; + xide_PageTblEntry_t *curr_pte; + xide_PageTblEntry_t *next_pte; + +#ifdef USE_MAPPED_PCI_TRANSLATION + pciio_dmamap_t pte_map=NULL; /* DMA Map in PCI Space */ + pciio_dmamap_t dmaend_map=NULL; /* DMA Map in PCI Space */ +#endif + iopaddr_t pte_map_baseaddr=0; + iopaddr_t curr_pte_pci_addr; + int alloc_err; + unsigned flags=0; + + space_for_1_xaction = (sizeof(xide_CmdObj_t) + (8-1)) & ~(8-1); +/* + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + space_for_pte = ((sizeof(xide_std_PageTblEntry_t) * IDE_MAPSIZE) + (8-1)) & ~(8-1); + space_for_big_map = pi->BigMapMaxCount * sizeof(xide_std_PageTblEntry_t); + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + space_for_pte = ((sizeof(xide_ioc4_PageTblEntry_t) * IDE_MAPSIZE) + (8-1)) & ~(8-1); + space_for_big_map = pi->BigMapMaxCount * sizeof(xide_ioc4_PageTblEntry_t); + flags = PCIIO_DMA_A64; + } +*/ + if (pi->vendorid == PCI_VENDOR_SGI) { + flags = IDE_PCIIO_DMA_A64; + } + +#ifdef XSCSI + space_for_big_map = btoc(MAXDMASIZE) * sizeof(xide_PageTblEntry_t); + IDE_DBG(1,"\n space_for_big_map %d bytes | btoc(MAXDMASIZE) %d | DMASIZE 0x%x| sizeof(xide_PageTblEntry_t) %d \n",space_for_big_map,btoc(MAXDMASIZE),MAXDMASIZE,sizeof(xide_PageTblEntry_t)); +#else + space_for_big_map = v.v_maxdmasz * sizeof(xide_PageTblEntry_t); +#endif + space_for_pte = ((sizeof(xide_PageTblEntry_t) * IDE_MAPSIZE) + (8-1)) & ~(8-1); + IDE_DBG(11,"xide_alloc_cmd_object: space for pte %d | sizeof PgTblEntry %d bytes\n",space_for_pte,sizeof(xide_PageTblEntry_t)); + space_for_xferscratch = 2048; + + space_for_xactions_t = space_for_1_xaction * IDE_CMD_OBJS; + + /* space used by proto and core drivers only */ + IDE_KMEM_ALLOC(mem_for_t_p, space_for_xactions_t,VM_CACHEALIGN); + + /* space used by driver and hardware, ie needs pci translations */ + space_for_xaction_o = space_for_pte; + space_for_bm = space_for_big_map + (space_for_xaction_o * IDE_CMD_OBJS) + + space_for_xferscratch; + IDE_KMEM_ALLOC(mem_for_o_p, space_for_bm, VM_CACHEALIGN); + + alloc_err = 0; + mem_for_o_p_pa = kvtophys(mem_for_o_p); + + IDE_KMEM_ZALLOC(mem_for_dmaendmap,IDE_CACHELINE_SIZE*2,KM_CACHEALIGN); + if ((uint64_t)mem_for_dmaendmap & (IDE_CACHELINE_SIZE-1)) { // Not Cache aligned + pi->DmaEndPtr = (caddr_t)(((uint64_t)mem_for_dmaendmap + (IDE_CACHELINE_SIZE -1)) & ~(IDE_CACHELINE_SIZE-1)); + } else { + pi->DmaEndPtr = mem_for_dmaendmap; + } + mem_for_dmaendmap_pa = kvtophys(pi->DmaEndPtr); + IDE_DBG(1,"pi->DmaEndPtr 0x"IDE_PTR" | mem 0x"IDE_PTR" | mem_pa 0x"IDE_PTR" \n",pi->DmaEndPtr,mem_for_dmaendmap,mem_for_dmaendmap_pa); + +#ifdef USE_MAPPED_PCI_TRANSLATION + pte_map = pciio_dmamap_alloc(pi->PciVhdl, NULL, space_for_bm, pi->pciio_byte_stream|PCIIO_WRITE_GATHER|flags); + if (pte_map == NULL) { + IDE_DBG(0,"xscsi/ide:: xide_alloc_cmd_object() : Could NOT allocate pte_map\n"); + alloc_err = 1; + } + else { + pi->PteMap = pte_map; + pte_map_baseaddr = pciio_dmamap_addr(pte_map, mem_for_o_p_pa, space_for_bm); + } + IDE_DBG(11,"Using pciio_dmamap_alloc : pte_map_baseaddr 0x%x \n",pte_map_baseaddr); + + dmaend_map = pciio_dmamap_alloc(pi->PciVhdl, NULL,IDE_CACHELINE_SIZE,pi->pciio_byte_stream|flags|PCIIO_DMA_CMD); + if (dmaend_map == NULL) { + IDE_DBG(0,"xscsi/ide:: xide_alloc_cmd_object() : Cannot allocate dmaend_map\n"); + alloc_err=2; + } + else { + pi->DmaEndMap = dmaend_map; + pi->DmaEndAddr = pciio_dmamap_addr(dmaend_map,mem_for_dmaendmap_pa,IDE_CACHELINE_SIZE); + } + IDE_DBG(1,"xide_alloc_cmd_object: DmaEndMap 0x"IDE_PTR" | DmaEndAddr 0x"IDE_PTR" | DMAEndPtr 0x"IDE_PTR" \n",pi->DmaEndMap,pi->DmaEndAddr, pi->DmaEndPtr); + +#else /* USE_DIRECT_PCI_TRANSLATION */ + pte_map_baseaddr = pciio_dmatrans_addr(pi->PciVhdl, NULL, + mem_for_o_p_pa, + space_for_bm, pi->pciio_byte_stream|PCIIO_WRITE_GATHER|flags); + IDE_DBG(11,"Using pciio_dmatrans_addr : pte_map_baseaddr 0x%x \n",pte_map_baseaddr); + + pi->DmaEndAddr = pciio_dmatrans_addr(pi->PciVhdl, NULL, + mem_for_dmaendmap_pa, + IDE_CACHELINE_SIZE, pi->pciio_byte_stream|PCIIO_WRITE_GATHER|flags|PCIIO_DMA_CMD); + + debug("singer"); +#endif + if ((alloc_err > 0) || (pte_map_baseaddr == 0)) { + IDE_DBG(1, "xide_alloc_cmd_object(): ERROR!!! Can't get dmamap for xide cmd space\n"); + IDE_KMEM_FREE(mem_for_o_p, space_for_bm); + if (alloc_err > 1) { + IDE_KMEM_FREE(mem_for_dmaendmap, IDE_CACHELINE_SIZE*2); + } + return(-1); + } + + pi->FreeCmdObjHead = (xide_CmdObj_t *)mem_for_t_p; + curr_cmd_obj = pi->FreeCmdObjHead; +/* + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + curr_pte = (xide_std_PageTblEntry_t *)mem_for_o_p; + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + curr_pte = (xide_ioc4_PageTblEntry_t *)mem_for_o_p; + } +*/ + curr_pte = (xide_PageTblEntry_t *)mem_for_o_p; + prev_cmd_obj = NULL; + curr_pte_pci_addr = pte_map_baseaddr; + + for (i = 0; i < IDE_CMD_OBJS; i++) { +/* + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + curr_cmd_obj->ReservedPte = (xide_std_PageTblEntry_t *)((uintptr_t)curr_pte); + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + curr_cmd_obj->ReservedPte = (xide_ioc4_PageTblEntry_t *)((uintptr_t)curr_pte); + } +*/ + curr_cmd_obj->ReservedPte = (xide_PageTblEntry_t *)((uintptr_t)curr_pte); + curr_cmd_obj->Prev = prev_cmd_obj; + + curr_cmd_obj->ReservedPtePciAddr = curr_pte_pci_addr; + + curr_cmd_obj->UseBigmap = 0; + curr_cmd_obj->State = IDE_CO_FREE; + curr_cmd_obj->NoPte = 0; + curr_cmd_obj->AllocMapSize = 0; +//#ifdef USE_MAPPED_PCI_TRANSLATION + curr_cmd_obj->PteDMAMap = NULL; + curr_cmd_obj->DataDMAMap = NULL; +//#endif + curr_cmd_obj->TempReqForFix = NULL; + curr_cmd_obj->PteDMAMapBaseaddr = 0; + curr_cmd_obj->FixMap4BlkSz = 0; + curr_cmd_obj->HoldReq = NULL; + curr_cmd_obj->SentReq = NULL; + curr_cmd_obj->OrigReq = NULL; + curr_cmd_obj->ReqSense = NULL; + curr_cmd_obj->offset = 0; + curr_cmd_obj->Offset_Flag = 0; + curr_cmd_obj->start_Pte = NULL; + IDE_KMEM_ALLOC(curr_cmd_obj->saved_Pte,sizeof(xide_PageTblEntry_t),KM_CACHEALIGN); + curr_cmd_obj->start_PtePciAddr = 0; + curr_cmd_obj->Prev_Num_Blocks = 0; + curr_cmd_obj->AlenList = NULL; + curr_cmd_obj->PciAlenList = NULL; + curr_cmd_obj->MapStartLen = 0; + curr_cmd_obj->MapEndLen = 0; + + next_cmd_obj = (xide_CmdObj_t *)((uintptr_t)curr_cmd_obj + space_for_1_xaction); + next_pte = (xide_PageTblEntry_t *)((uintptr_t)curr_pte + space_for_xaction_o); +/* + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + next_pte = (xide_std_PageTblEntry_t *)((uintptr_t)curr_pte + space_for_xaction_o); + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + next_pte = (xide_ioc4_PageTblEntry_t *)((uintptr_t)curr_pte + space_for_xaction_o); + } +*/ + + curr_pte_pci_addr = curr_pte_pci_addr + space_for_xaction_o; + + curr_cmd_obj->Next = next_cmd_obj; + + prev_cmd_obj = curr_cmd_obj; + curr_cmd_obj = next_cmd_obj; + curr_pte = next_pte; + } + prev_cmd_obj->Next = NULL; + pi->FreeCmdObjTail = prev_cmd_obj; + pi->Bigmap = (xide_PageTblEntry_t *)curr_pte; +/* + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + pi->Bigmap = (xide_std_PageTblEntry_t *)curr_pte; + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + pi->Bigmap = (xide_ioc4_PageTblEntry_t *)curr_pte; + } +*/ + pi->BigMapPciAddr = curr_pte_pci_addr; + pi->BigmapInUse = 0; + + pi->XferScratch = (caddr_t)pi->Bigmap + space_for_big_map; + pi->XferScratchPci = pi->BigMapPciAddr + space_for_big_map; + + return(0); +} + +struct scsi_target_info *xide_info(vertex_hdl_t lun_vhdl) +{ + xide_ProtoInfo_t *pi; + xide_TargInfo_t *ti; + xide_LunInfo_t *li; + struct scsi_request *req; + struct scsi_target_info *retval = NULL; + scsi_lun_info_t *lun_info; + int retry = 0; + static u_char scsi[6]; + sema_t *sema; + int i; + + lun_info = scsi_lun_info_get(lun_vhdl); + li = (xide_LunInfo_t *)SLI_INFO(lun_info); + + pi = li->ProtoInfo; + ti = li->TargInfo; + +// mutex_lock(&li->OpenLock, PRIBIO); + MUTEX_LOCK(&li->OpenLock, PRIBIO); + + /* + * Issue Inquiry. + */ + + sema = kern_calloc(1, sizeof(sema_t)); + init_sema(sema, 0, "xide",(pi->Number << 7)| ti->Number); + IDE_KMEM_ZALLOC(req, sizeof(*req), VM_CACHEALIGN); + + do { + scsi[0] = 0x12; /* Inquiry command */ + scsi[1] = scsi[2] = scsi[3] = scsi[5] = 0; + scsi[4] = SCSI_INQUIRY_LEN; + + req->sr_ctlr = pi->Number; + req->sr_target = ti->Number; + req->sr_lun = li->Number; + req->sr_command = scsi; /* allocate space for cmd */ + req->sr_cmdlen = 6; /* Inquiry command length */ + req->sr_flags = SRF_DIR_IN | SRF_FLUSH | SRF_AEN_ACK; + req->sr_timeout = 10 * HZ; + req->sr_buffer = li->tinfo.si_inq; + req->sr_buflen = SCSI_INQUIRY_LEN; + req->sr_sense = li->tinfo.si_sense; + req->sr_senselen = SCSI_SENSE_LEN; + req->sr_notify = xide_done; + req->sr_dev = sema; + req->sr_lun_vhdl = lun_vhdl; + req->sr_spare = 0; + + {// Poisoning the buffer - Temp Hack 12/02/02 + req->sr_buffer[0] = 0xFF; + } + + xide_command(req); + IDE_DBG(11,"info(): Sending request : lun_vhdl 0x"IDE_PTR"\n",lun_vhdl); + psema(sema, PRIBIO); + + IDE_DBG(11,"info(): req->sr_status 0x%x | req->sr_scsi_status 0x%x \n",req->sr_status,req->sr_scsi_status); + if ((req->sr_status == SC_GOOD) && (req->sr_scsi_status == ST_GOOD)) { + /* + * If the LUN is not supported and is not a candidate + * for failover, then return NULL. + */ + + if ((li->tinfo.si_inq[0] & 0xC0) == 0x40 && + !fo_is_failover_candidate(li->tinfo.si_inq, lun_vhdl)) { + IDE_DBG(0, + "xscsi/ide: Notice: lun not valid, peripheral qualifier 0x%x\n", + (li->tinfo.si_inq[0] & 0xE0) >> 5); + } + else { + dki_dcache_inval(li->tinfo.si_inq, SCSI_INQUIRY_LEN); + for (i=0;isr_buflen;i++) { + IDE_DBG(21,"b_info[%d] : 0x%x ",i,li->tinfo.si_inq[i]); + } + if (req->sr_buffer > 0) { +// IDE_DBG(0,"xscsi/ide:buf 0x"IDE_PTR", vhdl ox"IDE_PTR" \n",req->sr_buffer,lun_vhdl); +// scsi_device_update(req->sr_buffer, lun_vhdl); + scsi_device_update(li->tinfo.si_inq, lun_vhdl); + } else { + IDE_DBG(0,"xscsi/ide:xide_info...req 0x"IDE_PTR"\n",req); + IDE_ASSERT(0); + } + IDE_DBG(13,"xide_info: after scsi_dev_update | req->sr_buflen %d\n",req->sr_buflen); + li->tinfo.si_maxq = IDE_CMD_OBJS; + li->tinfo.si_qdepth = li->xidentifyDev->queue_depth; + IDE_DBG(1,"xide_info(): Max queue Depth %d\n",li->xidentifyDev->queue_depth); + li->tinfo.si_ha_status = SRH_QERR0 | SRH_MAPUSER | SRH_ALENLIST | SRH_ATAPI; +// SRH_MAPUSER | SRH_ALENLIST; +// li->tinfo.si_ha_status |= SRH_ATAPI | SRH_MULTCMDS; + /* SRH_TAGQ | SRH_QERR1*/ + retval = &li->tinfo; + } + + if ((li->tinfo.si_inq[0] & 0x1f) == 0x05) { // INV_CDROM + li->WeAreCD = 1; +// li->AddSenseBD = 1; + li->FixSenseBD = 1; + li->NoMode6Cmd = 1; + li->NoMode10Cmd = 0; + IDE_DBG(1,"xide_info() Dev detected as CD\n"); + } + else { + li->WeAreCD = 0; +// li->AddSenseBD = 1; + li->FixSenseBD = 1; + li->NoMode6Cmd = 1; + li->NoMode10Cmd = 0; + IDE_DBG(2,"xide_info(lun_vhdl 0x"IDE_PTR") Dev NOT detected as CD\n",lun_vhdl); + } + } + } while (retry++ < 5 && (req->sr_status == SC_ATTN || + req->sr_status == SC_CMDTIME ||req->sr_status == SC_HARDERR)); + + IDE_KMEM_FREE(req, sizeof(*req)); + freesema(sema); // Defined as NULL in linux-xfs + kern_free(sema); +// mutex_unlock(&li->OpenLock); + MUTEX_UNLOCK(&li->OpenLock); + IDE_DBG(16,"xide_info() complete\n"); + return retval; +} + +static void xide_done(struct scsi_request *req) +{ + vsema(req->sr_dev); +} + +void xide_command(scsi_request_t *req) +{ + xide_ProtoInfo_t *pi; + xide_LunInfo_t *li; + scsi_lun_info_t *lun_info; + +#if IDE_CMD_DEBUG + bcopy(req->sr_command, xide_cmd_list[xide_cmd_index].command, req->sr_cmdlen); + xide_cmd_list[xide_cmd_index].datalength = req->sr_buflen; + xide_cmd_list[xide_cmd_index].request = req; + xide_cmd_list[xide_cmd_index].action = IDE_CDBG_RCVD; + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif + IDE_DBG(21,"xide_command(req 0x"IDE_PTR")\n",req); + req->sr_status = req->sr_scsi_status = req->sr_sensegotten = + req->sr_ha_flags = 0; + req->sr_spare = 0; + req->sr_ha = NULL; + req->sr_resid = req->sr_buflen; + + lun_info = scsi_lun_info_get(req->sr_lun_vhdl); + li = SLI_INFO(lun_info); + if (li == NULL) { + req->sr_status = SC_REQUEST; + goto _Err1; + } + IOLOCK(li->LunLock, li->LunSpl); + pi = li->ProtoInfo; + + /* If the buffer passed is not an ALENLIST, but a virtual address or a buf_t */ + if (req->sr_buflen != 0 && !(req->sr_flags & SRF_ALENLIST)) { + int offset; + + if (req->sr_flags & SRF_MAPBP) + offset = 0; + else { + offset = poff(req->sr_buffer); +#ifdef XSCSI + if (btoc(req->sr_buflen + offset) > btoc(MAXDMASIZE)) { +#else + if (btoc(req->sr_buflen + offset) > v.v_maxdmasz) { +#endif + req->sr_status = SC_REQUEST; + IDE_PRINTERR(0,"Request Buffer size too large...returning \n"); + goto _Err; + } + } + } + + /* + * If CONTINGENT ALLEGIANCE in effect and requestor hasn't set + * the AEN_ACK flag, then bail out. + */ + if (li->ContAlleg == 1) { + if (req->sr_flags & SRF_AEN_ACK) { + li->ContAlleg = 0; + IDE_DBG(1,"xide_command() li->ContAlleg Condition seen by dksc\n"); + } + else { + req->sr_status = SC_ATTN; + IDE_DBG(1,"xide_command() req->sr_status = SC_ATTN\n"); + goto _Err; + } + } + + xide_queue_scsireq(li, req); + IOUNLOCK(li->LunLock, li->LunSpl); + + { + int try=4; + while ((xide_start1(pi) & (try--))); + } + return; + +_Err: + IOUNLOCK(li->LunLock, li->LunSpl); + IDE_DBG(3,"xide_command() : _Err\n"); +_Err1: + (*req->sr_notify)(req); + IDE_DBG(3,"xide_command() : _Err1\n"); +} + +/* Add a new request to the tail of the lun's ScsiReqQ. */ + +static void xide_queue_scsireq(xide_LunInfo_t *li, scsi_request_t *req) +{ + IDE_ASSERT(mutex_mine(&li->LunLock)); + + if (li->ScsiReqQHead == NULL) { + li->ScsiReqQHead = req; + req->sr_ha = NULL; + IDE_DBG(13,"xide_queue_scsireq() : 1st req in queue 0x"IDE_PTR"\n",li->ScsiReqQHead); + } + else { + req->sr_ha = li->ScsiReqQTail; + IDE_DBG(13,"xide_queue_scsireq() : Request 0x"IDE_PTR" added to TailEnd\n",req); + } + li->ScsiReqQTail = req; + + return; +} + +static scsi_request_t *xide_dequeue_scsireq(xide_LunInfo_t *li) +{ + scsi_request_t *req=NULL; + scsi_request_t *ret_req=NULL; + scsi_request_t *prev_req=NULL; + + IDE_ASSERT(mutex_mine(&li->LunLock)); + req = li->ScsiReqQTail; + ret_req = li->ScsiReqQHead; + + IDE_DBG(11,"dequeue_scsireq() : li 0x"IDE_PTR" , ret (ScsiReqQTail) 0x"IDE_PTR" | ret_req (ScsiReqQHead) 0x"IDE_PTR" \n",li,li->ScsiReqQTail,li->ScsiReqQHead); + if (req == ret_req) { + li->ScsiReqQTail = li->ScsiReqQHead = NULL; + IDE_DBG(13,"dequeue_scsireq(): Only request 0x"IDE_PTR" in Queue\n",ret_req); + IDE_DBG(11,"dequeue_scsireq() : li 0x"IDE_PTR" , ret 0x"IDE_PTR" | ret_req 0x"IDE_PTR" \n",li,req,ret_req); + } + + while (req != ret_req) { + IDE_DBG(3,"!!! dequeue_scsireq() : Entered while() loop : li 0x"IDE_PTR"\n",li); + prev_req = req; + req = req->sr_ha; + } + + li->ScsiReqQHead= prev_req; + if (li->ScsiReqQHead) { + IDE_DBG(13,"dequeue_scsireq() : Setting Head's sr_ha to NULL\n"); + li->ScsiReqQHead->sr_ha = NULL; + } + + return (ret_req); +} + +/* In gwh's notation for CO, head->next exists and tail->next doesnt.. kinda +opposite to how I use the head/tail notations */ + +static xide_CmdObj_t *xide_get_cmd_obj(xide_ProtoInfo_t *pi) +{ + xide_CmdObj_t *co; + + IOLOCK(pi->ResourceLock, pi->ResourceLockSpl); + if (pi->FreeCmdObjHead == NULL) { + IDE_DBG(33,"COULDNOT find free co() : pi 0x"IDE_PTR" : pi->FreeCmdObjHead 0x"IDE_PTR" \n",pi,pi->FreeCmdObjHead); +// debug("xide_get_cmd_obj"); + IOUNLOCK(pi->ResourceLock, pi->ResourceLockSpl); + return(NULL); + } + + co = pi->FreeCmdObjHead; + IDE_ASSERT(co->State == IDE_CO_FREE); + + pi->FreeCmdObjHead = co->Next; + if (co->Next == NULL) { + IDE_DBG(3,"xide_get_cmd_obj() : getting co 0x"IDE_PTR" from Extreme\n",co); + pi->FreeCmdObjTail = NULL; + } + else { + IDE_DBG(11,"xide_get_cmd_obj() : getting co 0x"IDE_PTR" from Middle\n",co); + co->Next->Prev = NULL; + } + co->Next = NULL; + co->Prev = NULL; + co->Tag = -1; + IOUNLOCK(pi->ResourceLock, pi->ResourceLockSpl); + IDE_ASSERT(co!=NULL); + return(co); +} + +/* + * Examine the type of map and return its length in bytes. Also + * set the map_type to the type of map it is + */ +static int +xide_getmapsize(scsi_request_t *req) +{ + int mapsize; + xide_CmdObj_t *co; + xide_ProtoInfo_t *pi; + int flags=AL_NOCOMPACT; + + +// co = (xide_CmdObj_t *)req->sr_spare; + co = (xide_CmdObj_t *)(uintptr_t)req->sr_spare; + pi = co->li->ProtoInfo; + + if (pi->vendorid == PCI_VENDOR_SGI) { + flags |= IDE_PCIIO_DMA_A64; + } + + if (co->PciAlenList != NULL) { + xide_co_free_dmamap(co); + IDE_DBG(1,"xide_getmaplist(): co->pciAlenlist != NULL \n"); + IDE_ASSERT(0); + } + + if (req->sr_flags & SRF_ALENLIST) { + /* clone sense getmap will call translation with INPLACE flag and we can't + * destroy b_private alenlist. Can get rid of this if INPLACE bug is fixed + * in pciio_dmamap_list + */ + IDE_DBG(11,"!!!getmapsize() : Was passed a alenlist\n"); +#ifdef XSCSI + co->AlenList = (alenlist_t)req->sr_alenlist; + co->PciAlenList = co->AlenList; +#else + co->AlenList = alenlist_clone((alenlist_t) ((buf_t *)(req->sr_bp))->b_private, flags); + co->PciAlenList = co->AlenList; +#endif + } + else { + mapsize = 0; + if (req->sr_buflen == 0) { + return mapsize; + } +#ifdef XSCSI + co->PciAlenList = alenlist_create(flags); + alenlist_grow(co->PciAlenList, 1); + IDE_DBG(11,"xide_getmapsize() : co->PciAlenlist : 0x"IDE_PTR" \n",co->PciAlenList); +#else + co->PciAlenList = NULL; + co->AlenList = NULL; +#endif + if (req->sr_flags & SRF_MAPBP) { +#ifdef XSCSI + co->PciAlenList = buf_to_alenlist(co->AlenList, req->sr_alenlist, flags); // NULL CALL -> 6/10/02 +#else + co->AlenList = buf_to_alenlist(co->AlenList, req->sr_bp, flags); + co->PciAlenList = co->AlenList; +#endif + } + else { + IDE_DBG(13,"req->sr_buffer 0x"IDE_PTR" | buflen %d \n",req->sr_buffer,req->sr_buflen); + co->PciAlenList = kvaddr_to_alenlist(co->PciAlenList, (caddr_t)req->sr_buffer, req->sr_buflen, flags); + co->AlenList = co->PciAlenList; + IDE_DBG(11,"Did the kv_addr->alenlist conversion\n"); + IDE_DBG(11,"PciAlenList 0x"IDE_PTR" | Alenlist 0x"IDE_PTR" \n",co->PciAlenList,co->AlenList); + } + } + + mapsize = -1; + if (co->PciAlenList == NULL) { + return mapsize; + } + + mapsize = alenlist_size(co->PciAlenList); + IDE_DBG(14,"xide_getmapsize() : mapsizeE 0x%x \n",mapsize); + + if (co->FixMap4BlkSz == 1) { + if (co->MapStartLen > 0) { + mapsize++; + } + if (co->MapEndLen > 0) { + mapsize++; + } + } + IDE_DBG(4,"xide_getmapsize() : mapsize 0x%x \n",mapsize); + return mapsize; +} + + + +/* + * Get a DMA map for the command and fill in the page table entry list. + * Return 0 for good map, 1 for error. + */ +static int +xide_getmap(xide_ProtoInfo_t *pi, scsi_request_t *req) +{ + xide_CmdObj_t *co; + int npgs; + uint ptes_to_fill; +// void *sgmap; +// void *last_sgmap; +// void *map = NULL; + xide_PageTblEntry_t *map = NULL; + xide_std_PageTblEntry_t *sgmap32=NULL; + xide_std_PageTblEntry_t *last_sgmap32=NULL; + xide_ioc4_PageTblEntry_t *sgmap64=NULL; + xide_ioc4_PageTblEntry_t *last_sgmap64=NULL; + paddr_t map_pa; + int map_size; + unsigned int flags=0; +#ifdef USE_MAPPED_PCI_TRANSLATION + pciio_dmamap_t pte_data_map; +#endif + alenlist_t pci_alenlist; + + IDE_DBG(13, "Starting xide_getmap\n"); + if (req->sr_buflen == 0) + return(IDE_OK); + + co = (xide_CmdObj_t *)req->sr_spare; +// co->PteDMAMap = NULL; +#ifdef USE_MAPPED_PCI_TRANSLATION + if (co->PteDMAMap != NULL) { /* space allocated for PTE */ + IDE_DBG(11,"xide_getmap() : PteDMAMap being freed %x\n",co->PteDMAMap); + pciio_dmamap_free(co->PteDMAMap); + co->PteDMAMap = NULL; + } +#endif + + npgs = xide_getmapsize(req); + if (npgs < 0) { + return(IDE_FAIL); + } + + co->NumPtes = npgs; + if (co->NumPtes ==0) { + IDE_DBG(0,"xscsi/ide:: co->NumPtes 0x%x \n",co->NumPtes); + IDE_ASSERT(0); + } + +// if (co->NumPtes > 1) { +// IDE_DBG(0,"xscsi/ide:Special Interruption for Teruo : 10/28/02 \n"); +// IDE_ASSERT(0); +// } + + if (npgs <= IDE_MAPSIZE) { + IDE_DBG(15,"xide_getmap(): Using the reserved PTE places\n"); + co->Pte = co->ReservedPte; +// co->PtePciAddr = (uint32_t)co->ReservedPtePciAddr; + co->PtePciAddr = (uint64_t)co->ReservedPtePciAddr; + } + else { + IOLOCK(pi->ResourceLock, pi->ResourceLockSpl); + pi->BigmapInUse =1; + co->UseBigmap = 1; + if (!pi->BigmapInUse) { +#ifdef XSCSI + IDE_DBG(4,"btoc(MAXDMASIZE) %d > npgs %d\n",btoc(MAXDMASIZE),npgs); + IDE_ASSERT(btoc(MAXDMASIZE) >= npgs); +#else + IDE_DBG(4,"v.v_maxdmasz %d > npgs %d\n",v.v_maxdmasz,npgs); + IDE_ASSERT(v.v_maxdmasz >= npgs); +#endif + co->Pte = pi->Bigmap; +// co->PtePciAddr = (uint32_t)pi->BigMapPciAddr; + co->PtePciAddr = (uint64_t)pi->BigMapPciAddr; + pi->BigmapInUse = 1; + co->UseBigmap = 1; + IDE_DBG(2,"xide_getmap(): Using BigMap\n"); + IOUNLOCK(pi->ResourceLock, pi->ResourceLockSpl); + } + else { + IDE_DBG(1,"xide_getmap(): Allocating a new PTE place\n"); + IOUNLOCK(pi->ResourceLock, pi->ResourceLockSpl); +/* if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + map_size = npgs * sizeof(xide_std_PageTblEntry_t); + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + map_size = npgs * sizeof(xide_ioc4_PageTblEntry_t); + flags = PCIIO_DMA_A64; + } +*/ + if (pi->vendorid == PCI_VENDOR_SGI) { + flags = IDE_PCIIO_DMA_A64; + } + + map_size = (npgs * sizeof(xide_PageTblEntry_t) + (8-1)) & ~(8-1); + IDE_DBG(11,"xide_getmap(): mapsize %d bytes | npgs %d \n",map_size,npgs); + IDE_KMEM_ALLOC(map, map_size, VM_CACHEALIGN | VM_PHYSCONTIG); + if (map == NULL) { + IDE_DBG(0,"xscsi/ide:: Cannot allocate %d PTEs \n",npgs); + IDE_ASSERT(0); + return(IDE_FAIL); + } + co->AllocMapSize = map_size; + co->Pte = map; + map_pa = kvtophys(map); +#ifdef USE_MAPPED_PCI_TRANSLATION + pte_data_map = pciio_dmamap_alloc(pi->PciVhdl, NULL, map_size, pi->pciio_byte_stream|PCIIO_WRITE_GATHER|flags); + if (pte_data_map == NULL) { + IDE_DBG(1,"xide_getmap() : Could NOT allocate pte_map\n"); + IDE_ASSERT(0); + return(IDE_FAIL); + } + else { + if (co->PteDMAMap != NULL) { /* space allocated for PTE */ + IDE_DBG(1,"xide_getmap() : PteDMAMap existed\n"); + pciio_dmamap_free(co->PteDMAMap); + co->PteDMAMap = NULL; + } + co->PteDMAMap = pte_data_map; + co->PteDMAMapBaseaddr = pciio_dmamap_addr(pte_data_map, map_pa, map_size); + } + +#else /* USE_DIRECT_PCI_TRANSLATION */ + co->PteDMAMapBaseaddr = pciio_dmatrans_addr(pi->PciVhdl, NULL, + map_pa, map_size,pi->pciio_byte_stream|PCIIO_WRITE_GATHER|flags); +#endif + co->PtePciAddr = (uint64_t)co->PteDMAMapBaseaddr; + } + } /* end else */ + +#ifdef USE_MAPPED_PCI_TRANSLATION +// co->DataDMAMap = pciio_dmamap_alloc(pi->PciVhdl, device_desc_default_get(pi->PciVhdl), req->sr_buflen, PCIIO_DMA_DATA|pi->pciio_byte_stream); + IDE_DBG(13,"xide_getmap() : DataDMAMap being allocated\n"); + if (co->DataDMAMap != NULL) { /* space allocated for PTE */ + IDE_DBG(2,"xide_getmap() : DataDMAMap existed\n"); + pciio_dmamap_free(co->DataDMAMap); + co->PteDMAMap = NULL; + } +#ifndef CONFIG_IA64_SGI_SN // Gary's Code has this ...why? 6/10/02 + co->DataDMAMap = pciio_dmamap_alloc(pi->PciVhdl, NULL, req->sr_buflen,PCIIO_DMA_DATA|pi->pciio_byte_stream|flags); + if (co->DataDMAMap == NULL) { + return(IDE_FAIL); + } +#endif +#endif + alenlist_cursor_init(co->PciAlenList, 0, NULL); + +#ifdef USE_MAPPED_PCI_TRANSLATION +#ifdef CONFIG_IA64_SGI_SN + pci_alenlist = co->PciAlenList; +#else + pci_alenlist = pciio_dmamap_list(co->DataDMAMap, co->PciAlenList, PCIIO_INPLACE|pi->pciio_byte_stream|flags); + IDE_DBG(11,"Using MAPPED pci translation of pci_alenlist 0x"IDE_PTR"\n",pci_alenlist); +#endif +#else /* USE_DIRECT_PCI_TRANSLATION */ + pci_alenlist = pciio_dmatrans_list(pi->PciVhdl, NULL, co->PciAlenList, PCIIO_INPLACE|pi->pciio_byte_stream|flags); + IDE_DBG(11,"Using direct pci translation of pci_alenlist 0x"IDE_PTR"\n",pci_alenlist); +#endif + + IDE_ASSERT(pci_alenlist == co->PciAlenList); + + if (pci_alenlist == NULL) + return(IDE_FAIL); + + ptes_to_fill = npgs; +// sgmap = co->Pte; + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + sgmap32 = &(co->Pte->xide_32b); + last_sgmap32 = (xide_std_PageTblEntry_t *)((uintptr_t)sgmap32 + + ((npgs-1)*sizeof(xide_std_PageTblEntry_t))); + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + sgmap64 = &(co->Pte->sgi_ioc4); + last_sgmap64 = (xide_ioc4_PageTblEntry_t *)((uint64_t)sgmap64 + + ((npgs-1)*sizeof(xide_ioc4_PageTblEntry_t))); + } + + if (co->FixMap4BlkSz == 1) { + if (co->MapEndLen > 0) { + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + last_sgmap32->Adr = xide_byte_swap(co->li->ProtoInfo->XferScratchPci); + last_sgmap32->EOT_Resv_Len = xide_byte_swap(co->MapEndLen); +#ifdef XSCSI +// last_sgmap32->Adr = co->li->ProtoInfo->XferScratchPci; +// last_sgmap32->EOT_Resv_Len = co->MapEndLen; + swab64_32((uint64_t *)last_sgmap32); +//#else +// last_sgmap32->Adr = xide_byte_swap(co->li->ProtoInfo->XferScratchPci); +// last_sgmap32->EOT_Resv_Len = xide_byte_swap(co->MapEndLen); +#endif + IDE_CLR_CACHE(req, co->li->ProtoInfo->XferScratch, last_sgmap32->EOT_Resv_Len); + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + last_sgmap64->Adr = xide_byte_swap64(co->li->ProtoInfo->XferScratchPci); + last_sgmap64->EOT_Resv_Len = xide_byte_swap64(co->MapEndLen); +// IDE_CLR_CACHE(req, co->li->ProtoInfo->XferScratch, last_sgmap64->EOT_Resv_Len); + IDE_CLR_CACHE(req, co->li->ProtoInfo->XferScratch, last_sgmap64->Adr); + } + ptes_to_fill--; + IDE_DBG(1,"getmap()+if() : ptes : %d \n",ptes_to_fill); + } + if (co->MapStartLen > 0) { +// sgmap->Adr = xide_byte_swap(co->li->ProtoInfo->XferScratchPci); +// sgmap->EOT_Resv_Len = xide_byte_swap(co->MapStartLen); + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + sgmap32->Adr = xide_byte_swap(co->li->ProtoInfo->XferScratchPci); + sgmap32->EOT_Resv_Len = xide_byte_swap(co->MapStartLen); +#ifdef XSCSI + swab64_32((uint64_t *)sgmap32); +#endif + sgmap32++; + IDE_CLR_CACHE(req, co->li->ProtoInfo->XferScratch, sgmap32->EOT_Resv_Len); + + } else if (pi->vendorid == PCI_VENDOR_SGI) { + sgmap64->Adr = xide_byte_swap64(co->li->ProtoInfo->XferScratchPci); + sgmap64->EOT_Resv_Len = xide_byte_swap64(co->MapStartLen); +#ifdef XSCSI +// swab64_32((uint64_t *)sgmap64->Adr); +// swab64_32((uint64_t *)sgmap64->EOT_Resv_Len); +#endif + sgmap64++; + IDE_CLR_CACHE(req, co->li->ProtoInfo->XferScratch, sgmap64->EOT_Resv_Len); + } + +// sgmap++; +// IDE_CLR_CACHE(req, co->li->ProtoInfo->XferScratch, sgmap->EOT_Resv_Len); + ptes_to_fill--; + } + } + IDE_DBG(2,"getmap() : ptes : %d \n",ptes_to_fill); + /* Now fill in the page table */ +// if (xide_maplist(pi, co, sgmap) != IDE_OK) { +// return(IDE_FAIL); +// } + if (pi->vendorid == PCI_VENDOR_SGI) { + if (xide_maplist(pi, co, sgmap64,ptes_to_fill) != IDE_OK) { + IDE_DBG(1,"xide_maplist FAILED\n"); + return(IDE_FAIL); + } + } else if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + if (xide_maplist(pi, co, sgmap32,ptes_to_fill) != IDE_OK) { + return(IDE_FAIL); + } + } + +// last_sgmap->EOT_Resv_Len |= 0x00000080; // Setting the End Bit + if (pi->vendorid == PCI_VENDOR_SGI) { + /* PUT CODE HERE FOR LINUX -IOC4 */ +// last_sgmap64->EOT_Resv_Len |= 0x00000080; // Setting the End Bit + last_sgmap64->EOT_Resv_Len |= xide_byte_swap64(0x80000000); // Setting the End Bit + IDE_DBG(1,"xide_getmap() : Addr : 0x%x | Len 0x%x\n",last_sgmap64->Adr,last_sgmap64->EOT_Resv_Len); + } else if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { +#ifdef XSCSI + last_sgmap32->Adr |= 0x80000000; // Setting the End Bit +#else + last_sgmap32->EOT_Resv_Len |= 0x00000080; // Setting the End Bit +#endif + IDE_DBG(3,"xide_getmap() : Addr : 0x%x | Len 0x%x\n",last_sgmap32->Adr,last_sgmap32->EOT_Resv_Len); + } + + return(IDE_OK); +} + + +static int +xide_ata_remap_sg(xide_CmdObj_t *co) +{ + xide_std_PageTblEntry_t *sgmap32=NULL; + int i; + int max_size=ATA_MAX_BLOCKS*ATA_BLOCK_SIZE; + int size=0,new_count=0,extra_bytes=0; + int count=0,addr=0,new_lba,start_lba,num_blocks; + uint64_t sgmap_pciaddr=0; + + +// sgmap32 = &(co->start_Pte->xide_32b) + (co->offset)*sizeof(sgmap32); +// sgmap32 = &(co->start_Pte->xide_32b) ; + + sgmap32 = (xide_std_PageTblEntry_t *) co->start_Pte ; + sgmap_pciaddr = co->start_PtePciAddr + (co->offset)*sizeof(sgmap32); + IDE_DBG(2,"remap() : base : 0x"IDE_PTR" | sgmap32 0x"IDE_PTR" | sgmap_pciaddr 0x%x \n",&(co->start_Pte->xide_32b),sgmap32,sgmap_pciaddr); + + if (co->Offset_Flag & IDE_SPLIT_TRANSFER) { + xide_std_PageTblEntry_t *sgmap_temp=NULL; + + sgmap_temp = (xide_std_PageTblEntry_t *) co->saved_Pte; + sgmap32->EOT_Resv_Len = sgmap_temp->EOT_Resv_Len; + sgmap32->Adr = sgmap_temp->Adr; + } + co->Pte = (xide_PageTblEntry_t *) sgmap32; + co->PtePciAddr = sgmap_pciaddr; + + IDE_DBG(2,"xide_ata_remap_sg() co->Pte 0x"IDE_PTR"| PtePciAddr 0x"IDE_PTR" | max_size 0x%x \n",co->Pte,co->PtePciAddr,max_size); + + //Traverse thro. list until sgmap pts to the last entry in the current transfer + for (i=co->offset;(i< co->NumPtes);i++,sgmap32++) { +#ifdef XSCSI + swab64_32((uint64_t *)sgmap32); +#endif + count = (xide_byte_swap(sgmap32->EOT_Resv_Len) & 0x1FFFF); + addr = xide_byte_swap(sgmap32->Adr); + size += count; + IDE_DBG(1,"xide_ata_remap_sg(%d): count 0x%x | addr 0x%x | size 0x%x \n",i,count,addr,size); + if (size >= max_size) { + sgmap32->EOT_Resv_Len |= xide_byte_swap(0x80000000); + IDE_DBG(1,"xide_ata_remap_sg: Last_sgmap32 0x"IDE_PTR" count 0x%x | addr 0x%x \n ",sgmap32,sgmap32->EOT_Resv_Len,sgmap32->Adr); + co->start_Pte = (xide_PageTblEntry_t *)sgmap32; + break; + } +#ifdef XSCSI + swab64_32((uint64_t *)sgmap32); +#endif + } + + if ((co->offset == 0) && (i >= co->NumPtes-1) && (size <= max_size)) { + return -1; // Normal request + } + + if ((co->offset == 0) && (i < co->NumPtes-1) && (size >= max_size)) { + co->Offset_Flag |= IDE_START_TRANSFER; + IDE_DBG(2,"remap(1) flag 0x%x \n",co->Offset_Flag); + } + + if ((co->offset > 0) && (i < co->NumPtes-1) && (size >= max_size)) { + co->Offset_Flag &= ~IDE_START_TRANSFER; + IDE_DBG(2,"remap(2) flag 0x%x \n",co->Offset_Flag); + co->Offset_Flag |= IDE_MIDDLE_TRANSFER; + IDE_DBG(2,"remap(3) flag 0x%x \n",co->Offset_Flag); + } + + if ((co->offset > 0) && (i >= co->NumPtes-1) && (size <= max_size)) { + co->Offset_Flag &= ~IDE_MIDDLE_TRANSFER; + IDE_DBG(2,"remap(4.1) flag 0x%x \n",co->Offset_Flag); + co->Offset_Flag &= ~IDE_START_TRANSFER; + IDE_DBG(2,"remap(4.2) flag 0x%x \n",co->Offset_Flag); + co->Offset_Flag |= IDE_END_TRANSFER; + IDE_DBG(2,"remap(5) flag 0x%x \n",co->Offset_Flag); + } + + if (size == 0) { + IDE_DBG(2,"remap(): Last transfer in sequence done : Should never get here\n"); + co->Offset_Flag=0; + co->offset=0; + return 0; + } + + + if (size > max_size) { + xide_std_PageTblEntry_t *sgmap_temp=NULL; +#ifdef XSCSI + swab64_32((uint64_t *)sgmap32); +#endif + count = (xide_byte_swap(sgmap32->EOT_Resv_Len) & 0x1FFFF); + addr = xide_byte_swap(sgmap32->Adr); + new_count = count - (size - max_size); + extra_bytes = size-max_size; + IDE_DBG(1,"xide_ata_remap_sg: count %x | new_count %x | size %x | extra_bytes %x\n",count,new_count,size,extra_bytes); + + sgmap32->EOT_Resv_Len = xide_byte_swap(new_count); + sgmap32->EOT_Resv_Len |= xide_byte_swap(0x80000000); +#ifdef XSCSI + swab64_32((uint64_t *)sgmap32); +#endif + IDE_DBG(2,"remap(6) flag 0x%x \n",co->Offset_Flag); + co->Offset_Flag |= IDE_SPLIT_TRANSFER; + IDE_DBG(2,"remap(7) flag 0x%x \n",co->Offset_Flag); +// IDE_KMEM_ALLOC(sgmap_temp,sizeof(sgmap_temp),KM_CACHEALIGN); +// co->saved_Pte = sgmap_temp; + sgmap_temp = (xide_std_PageTblEntry_t *)co->saved_Pte; + sgmap_temp->EOT_Resv_Len = xide_byte_swap(extra_bytes); + sgmap_temp->Adr = xide_byte_swap(addr + new_count); +#ifdef XSCSI + swab64_32((uint64_t *)sgmap_temp); +#endif + + IDE_DBG(2,"xide_ata_remap_sg: savedPte 0x"IDE_PTR", Len 0x%x , Adr 0x%x\n", + co->saved_Pte,sgmap_temp->EOT_Resv_Len,sgmap_temp->Adr); + + size = size - count + new_count; + } else if (size <= max_size) { + sgmap32->EOT_Resv_Len |= xide_byte_swap(0x80000000); +#ifdef XSCSI + swab64_32((uint64_t *)sgmap32); +#endif + sgmap32++; + i++; + co->start_Pte = (xide_PageTblEntry_t *) sgmap32; + co->Offset_Flag &= ~IDE_SPLIT_TRANSFER; + IDE_DBG(2,"remap(8) flag 0x%x \n",co->Offset_Flag); + IDE_DBG(2,"remap() : start_Pte 0x"IDE_PTR"\n",co->start_Pte); + } + co->offset = i; + IDE_DBG(2,"xide_ata_remap_sg: size %d \n",size); + IDE_ASSERT(size <= max_size); + + num_blocks = size/ATA_BLOCK_SIZE; + IDE_DBG(2,"xide_ata_remap_sg() : Offset %d | num_blocks %d | size %d\n",co->offset, num_blocks, size), + + start_lba = (uint32_t)((co->CmdBlk[2]<<24)| + (co->CmdBlk[3]<<16)| + (co->CmdBlk[4]<<8)| + (co->CmdBlk[5])); + + new_lba = start_lba + co->Prev_Num_Blocks; + co->Prev_Num_Blocks = num_blocks; + + IDE_DBG(2,"xide_ata_remap_sg : new_lba : 0x%x | start_lba 0x%x | co->Prev_Num_Blocks 0x%x\n",new_lba,start_lba,co->Prev_Num_Blocks); + + IDE_DBG(2,"remap(Before) : Cmdblk[2] : 0x%x | [3] 0x%x | [4] 0x%x | [5] 0x%x | [7] 0x%x | [8] 0x%x \n", + co->CmdBlk[2],co->CmdBlk[3],co->CmdBlk[4],co->CmdBlk[5],co->CmdBlk[7],co->CmdBlk[8]); + + co->CmdBlk[2] = (uint8_t)(new_lba >>24); + co->CmdBlk[3] = (uint8_t)(new_lba >>16); + co->CmdBlk[4] = (uint8_t)(new_lba >>8); + co->CmdBlk[5] = (uint8_t)new_lba ; + + co->CmdBlk[7] = 0; + co->CmdBlk[8] = num_blocks; + + IDE_DBG(2,"remap(After) : Cmdblk[2] : 0x%x | [3] 0x%x | [4] 0x%x | [5] 0x%x | [7] 0x%x | [8] 0x%x \n", + co->CmdBlk[2],co->CmdBlk[3],co->CmdBlk[4],co->CmdBlk[5],co->CmdBlk[7],co->CmdBlk[8]); + + return num_blocks; +} + + + + +static int +//xide_maplist(xide_ProtoInfo_t *pi, xide_CmdObj_t *co, xide_PageTblEntry_t *sgmap) +xide_maplist(xide_ProtoInfo_t *pi, xide_CmdObj_t *co, void *sgmap, int npgs) +{ + alenaddr_t addr; + size_t count; + alenlist_t pci_alenlist; + int i; + int alensize; + int flags=0; + + xide_std_PageTblEntry_t *sgmap32=NULL; + xide_ioc4_PageTblEntry_t *sgmap64=NULL; + + pci_alenlist = co->PciAlenList; + alensize = alenlist_size(pci_alenlist); + + IDE_ASSERT(alensize == npgs); + + if (pci_alenlist == NULL) { + return(IDE_FAIL); + } + + if (pi->vendorid == PCI_VENDOR_SGI) { + sgmap64 = (xide_ioc4_PageTblEntry_t *)sgmap; + flags = IDE_PCIIO_DMA_A64; + } + else if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + sgmap32 = (xide_std_PageTblEntry_t *)sgmap; + } + + alenlist_cursor_init(pci_alenlist, 0, NULL); + for (i = 0; i < alensize; i++) { + if (alenlist_get(pci_alenlist, NULL, 0, &addr, &count, 0)!=ALENLIST_SUCCESS) { + goto alen_failure; + } + +#ifdef CONFIG_IA64_SGI_SN + { + void *vaddr; +/* pciio_dmamap_t dma_map=NULL; + dma_addr_t dma_addr=0; + unsigned long phys_addr; + struct sn_dma_maps_s *sn_dma_map; +*/ + vaddr = phys_to_virt((uintptr_t)addr); + addr = (alenaddr_t)pci_map_single(pi->PciVhdl, vaddr, count, PCI_DMA_BIDIRECTIONAL); + IDE_DBG(1,"pci_map_single: vhdl 0x"IDE_PTR" | vaddr 0x"IDE_PTR" |count 0x%x | flags 0x%x | addr 0x%x \n",pi->PciVhdl, vaddr, count, PCI_DMA_BIDIRECTIONAL,addr); + if (!(addr)) { + IDE_DBG(0,"xscsi/ide:: pci_map_single(vhdl 0x"IDE_PTR", vaddr 0x"IDE_PTR", count 0x%x, flags 0x%x, addr 0x%x) failed to find any 32-bit dma maps\n",pi->PciVhdl, vaddr, count, PCI_DMA_BIDIRECTIONAL,addr); + goto FAIL; + } + +/* phys_addr = __pa(vaddr); + + dma_map = pciio_dmamap_alloc(pi->PciVhdl,NULL,count,PCIIO_BYTE_STREAM); +// dma_map = pciio_dmamap_alloc(pi->PciVhdl,NULL,count,PCIIO_DMA_DATA|PCIIO_BYTE_STREAM); + if (!dma_map) { + printk(KERN_ERR "xide_maplist : Unable to allocate anymore 32 bit page map entries.\n"); + BUG(); + } + dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, phys_addr,count); + sn_dma_map = (struct sn_dma_maps_s *)dma_map; +// sn_dma_map->dma_addr = (dma_addr_t) dma_addr; + + addr = (dma_addr_t)dma_addr; +*/ + xide_mapped[xide_map_in] = addr; + // checks PCI map allocation-deallocation routine + xide_map_in++; + IDE_DBG(11,"Filling in : xide_mapped[%d] 0x%x | addr 0x%x \n",xide_map_in,xide_mapped[xide_map_in],addr); + if (xide_map_in > 255) { + xide_map_in =0; + } + } +#endif + +/* +#ifdef USE_DIRECT_PCI_TRANSLATION + { + uint64_t addr_tmp; + + addr_tmp = (uint64_t) pciio_dmatrans_addr(pi->PciVhdl,NULL,addr,count,PCIIO_DMA_A64); + IDE_DBG(11,"addr : 0x%x | addr_tmp 0x%x \n",addr,addr_tmp); + addr = addr_tmp; + } +#endif +*/ + + IDE_DBG(3,"xide_maplist() : Adr 0x"IDE_PTR" | count 0x%x \n",(uint64_t)addr,count); + if ((pi->vendorid == CMD_VENDOR_ID)||(pi->vendorid == PCI_VENDOR_ID_PROMISE)) { + sgmap32->Adr = xide_byte_swap(addr); + sgmap32->EOT_Resv_Len = xide_byte_swap(count); +#ifdef XSCSI + swab64_32((uint64_t *)sgmap32); +#endif + IDE_DBG(3,"sgmap32->Adr 0x%x | count 0x%x | i %d\n",sgmap32->Adr,sgmap32->EOT_Resv_Len,i); + sgmap32++; + } else if (pi->vendorid == PCI_VENDOR_SGI) { + /* PUT CODE HERE FOR LINUX _ IOC4 */ + sgmap64->Adr = xide_byte_swap64(addr); + sgmap64->EOT_Resv_Len = xide_byte_swap64(count); + IDE_DBG(2,"sgmap64->Adr 0x%x | count 0x%x | i %d\n",sgmap64->Adr,sgmap64->EOT_Resv_Len,i); + sgmap64++; + } + + } + + return IDE_OK; + +alen_failure: + IDE_DBG(0,"xscsi/ide:xide_maplist(): Alenlist failure\n"); +#ifdef XSCSI + BUG(); +#else + panic("xide_maplist(): ALEN failure\n"); +#endif +FAIL: return IDE_FAIL; +} + +/* Return a CmdObj back to the pi's free list. If it was using + * the bigmap then return that also. If there was a DataDMAMap + * allocated then return the map, freeing up the translation + * entries. + */ +static void +xide_return_free_co(xide_ProtoInfo_t *pi, xide_CmdObj_t *co) +{ + IOLOCK(pi->ResourceLock, pi->ResourceLockSpl); + co->State = IDE_CO_FREE; + + IDE_DBG(13,"xide_return_free_co( pi 0x"IDE_PTR" | co 0x"IDE_PTR")\n",pi,co); + + if (co->UseBigmap == 1) { + pi->BigmapInUse = 0; + co->UseBigmap = 0; + } + +#ifdef USE_MAPPED_PCI_TRANSLATION + if (co->DataDMAMap != NULL) { + IDE_DBG(3,"!!xide_return_free_co() : Freeing DataDMAMap\n"); + pciio_dmamap_free(co->DataDMAMap); + co->DataDMAMap = NULL; + } +#endif + co->Next = NULL; + + co->Prev = pi->FreeCmdObjHead; + if (pi->FreeCmdObjHead != NULL) { /* list > 0 */ + IDE_DBG(13,"!! Co() List was NOT-ZERO (STRANGE)\n"); + pi->FreeCmdObjHead->Next = co; + } + else { /* list = 0 */ + IDE_DBG(13,"!! Co() List was ZERO (GOOD)\n"); + pi->FreeCmdObjTail = co; + } + pi->FreeCmdObjHead = co; + IDE_DBG(13,"Put co(0x "IDE_PTR") back in pi's queue\n",co); + IOUNLOCK(pi->ResourceLock, pi->ResourceLockSpl); + IDE_DBG(11,"After Unlocking pi->resourceLock\n"); +} + +static int xide_get_co_tag(xide_LunInfo_t *li) +{ + int i=-1; + int check_tag=1; + int max_tag; + + IDE_ASSERT (mutex_mine(&li->LunLock)); + max_tag = li->xidentifyDev->queue_depth; + + IDE_DBG(12,"xide_get_co_tag(): Max Tag %d\n",max_tag); + + for (i=0;i<=max_tag;) { + if (li->Tag_Used & (check_tag<Tag_Used = li->Tag_Used | (check_tag<Tag_Used 0x%x\n",li->Tag_Used); + break; + } + } + if (i>max_tag) { + i = -1; + IDE_DBG(12,"get_co_tag(): i > max_tag returning -1\n"); + } + + return i; +} + +static int xide_dma_init(xide_LunInfo_t *li) +{ + xide_ProtoInfo_t *pi; + uint8_t mode=0; + uint8_t udxidetcr0=0; + + pi = li->ProtoInfo; + + if (li->xidentifyDev->valid_w88) { + if (li->xidentifyDev->udma5_sel) { + mode = UDMA_5; + } + else + if (li->xidentifyDev->udma4_sel) { + mode = UDMA_4; + } + else + if (li->xidentifyDev->udma3_sel) { + mode = UDMA_3; + } + else + if (li->xidentifyDev->udma2_sel) { + mode = UDMA_2; + } + else + if (li->xidentifyDev->udma1_sel) { + mode = UDMA_1; + } + else + if (li->xidentifyDev->udma0_sel) { + mode = UDMA_0; + } + } + + if (li->xidentifyDev->valid_w64_70) { + if (li->xidentifyDev->multidma_2) { + IDE_DBG(14,"Mode = MULTIDMA_2\n"); + mode = MULTIDMA_2; + } + else + if (li->xidentifyDev->multidma_1) { + IDE_DBG(14,"Mode = MULTIDMA_1\n"); + mode = MULTIDMA_1; + } + else + if (li->xidentifyDev->multidma_0) { + IDE_DBG(14,"Mode = MULTIDMA_0\n"); + mode = MULTIDMA_0; + } + else + if (li->xidentifyDev->pio_modes) { + mode = PIO | li->xidentifyDev->pio_modes; + } + } + +// mode = MULTIDMA_0; + + if (mode & UDMA) { + if (mode & UDMA_5) { + udxidetcr0 = 0x05; + } + else + if (mode & UDMA_4) { + udxidetcr0 = 0x15; + } + else + if (mode & UDMA_3) { + udxidetcr0 = 0x25; + } + else + if (mode & UDMA_2) { + udxidetcr0 = 0x11; + } + else + if (mode & UDMA_1) { + udxidetcr0 = 0x21; + } + else + if (mode & UDMA_0) { + udxidetcr0 = 0x31; + } + } + +// udxidetcr0=0; +/* + if (pi->vendorid == PCI_VENDOR_ID_PROMISE) { + if (pi->devid == PCI_DEVICE_ID_PROMISE_20262){ + uint32_t sys_ctl; + + IDE_OUTB(pi,pi->dmablk,IDE_MASTER_CTL0,0x01); + IDE_OUTDW(pi,pi->dmablk,IDE_ATAPI_CH1,(0x01)<<24); + sys_ctl = IDE_INDW(pi,pi->dmablk,IDE_SYS_CTL); + IDE_DBG(3,"dma_init() : Promise : sys_ctl 0x%x\n",sys_ctl); + } + } +*/ + if (pi->vendorid == CMD_VENDOR_ID) { + if (pi->devid == CMD_DEV_ID) { + uint8_t time_reg; + time_reg = pciio_config_get(pi->PciVhdl,0x51,1); + IDE_DBG(12,"init(1) : time_reg 0x%x \n",time_reg); + pciio_config_set(pi->PciVhdl,0x51,1,time_reg&0x0C); + pciio_config_set(pi->PciVhdl,0x53,1,0x01); + pciio_config_set(pi->PciVhdl,0x54,1,0x21); + pciio_config_set(pi->PciVhdl,0x55,1,0x01); + pciio_config_set(pi->PciVhdl,0x56,1,0x21); +// time_reg = pciio_config_get(pi->PciVhdl,0x51,1); +// IDE_DBG(2,"init(2) : time_reg 0x%x \n",time_reg); + } + + if (pi->device_conf[li->TargInfo->Number] & ATAPI_DEV_PRESENT) { + mode = MULTIDMA_2; +// if (mode & MDMA) + IDE_DBG(13,"xide_dma_init() : mode 0x%x \n"); + + IDE_OUTB(pi,pi->dmablk,IDE_MRDMODE,0x0D); + IDE_OUTB(pi,pi->dmablk,IDE_BMIDESR0,0x26); + IDE_OUTB(pi,pi->dmablk,IDE_UDIDETCR0,0x0); + IDE_DBG(12,"xide_dma_init() : MDMA: mode being set to 0x%x \n",mode); + } + + if (pi->device_conf[li->TargInfo->Number] & ATA_DEV_PRESENT) { + mode = UDMA_5; + if (li->TargInfo->Number == 0) { + udxidetcr0 |= 0x31; + } + if (li->TargInfo->Number == 1) { + udxidetcr0 |= 0xC2; + } + IDE_DBG(12,"xide_dma_init() UDMA : udxidetcr0 0x%x | mode 0x%x\n",udxidetcr0,mode); + + IDE_OUTB(pi,pi->dmablk,IDE_MRDMODE,0x0D); + IDE_OUTB(pi,pi->dmablk,IDE_BMIDESR0,0x26); + IDE_OUTB(pi,pi->dmablk,IDE_UDIDETCR0,0x05); + } + } + +/* + if (pi->vendorid == PCI_VENDOR_SGI) { + IDE_OUTW(pi,pi->dmablk,IOC4_TIMING,0x041A); + } + Not needed according to Teruo +*/ + + + + return 0; +} + + +/* Just write the PACKET Cmd to the register */ +static int xide_send_co (xide_CmdObj_t *co) +{ + xide_LunInfo_t *li; + xide_TargInfo_t *ti; + xide_ProtoInfo_t *pi; + command_regs_t *cmdSent; + uint8_t status=0; + + li = co->li; + ti = li->TargInfo; + pi = ti->ProtoInfo; + + IDE_KMEM_ZALLOC(cmdSent,sizeof(*cmdSent),VM_DIRECT); + IDE_ASSERT(cmdSent!=NULL); + + cmdSent->command = 0xA0; /* Packet Command */ + cmdSent->drive = (ti->Number)<<4; /* Dev 0 or 1 */ + + cmdSent->err_feature = CMD_NON_OVERLAP; /* Overlap */ + if (co->SentReq->sr_buflen > 0) { + cmdSent->err_feature |= CMD_DMA;/* DMA */ + } + + cmdSent->sector = (co->Tag) << 3; /* Cmd Tag Queuing */ + + cmdSent->cyl_lsb = 0x0; + cmdSent->cyl_msb = 0x0; + cmdSent->data =0; + + co->request_stage = PKT_CMD_IN; +// status = xide_piocommand(li,cmdSent,0,NULL,CMD_NON_OVERLAP|CMD_PACKET,co); + + if (pi->device_conf[ti->Number] & ATA_DEV_PRESENT) { + int ret; + ret = scsi_to_ata(co->SentReq,cmdSent); + + if ((ret == ATA_CMD_FAKE)||(ret == ATA_CMD_UNSUPPORTED)) { + if (ret == ATA_CMD_UNSUPPORTED) { + IDE_DBG(3,"Unsupported Command in req 0x"IDE_PTR"\n",co->OrigReq); + co->OrigReq->sr_status = SC_REQUEST; + } else { + IDE_DBG(3,"Faked Command in req 0x"IDE_PTR"\n",co->OrigReq); + } + xide_finish_scsireq(li,co->OrigReq); + if (li->ContAlleg == 1) { + xide_return_lun_cmds(li,SC_ATTN); + } + xide_remove_co(co); + xide_return_finished_req(pi); + xide_return_co_resources(co); + xide_test_co_for_free(co); + IDE_DBG(11,"Faked ATA : after xide_test_co_for_free() \n"); +// xide_start1(pi); + } + else if (ret == ATA_CMD_SEND) { + status = xide_piocommand(li,cmdSent,0,NULL,CMD_NON_OVERLAP|CMD_PACKET|CMD_ATA_DMA,co); + } + else if (ret == ATA_SPECIAL_CMD_COMPLETE) { + IDE_DBG(1,"xide_send_co() scsi_to_ata : shouldnt gete here \n"); + return -1; // goes to xide_intr() + } + } + + if (pi->device_conf[ti->Number] & ATAPI_DEV_PRESENT) { + IDE_DBG(11,"since atapi dev present : calling xide_piocommand()\n"); + status = xide_piocommand(li,cmdSent,0,NULL,CMD_NON_OVERLAP|CMD_PACKET,co); + } + + IDE_KMEM_FREE((void *)cmdSent,sizeof(*cmdSent)); + return status; +} + + +static int xide_start1(xide_ProtoInfo_t *pi) +{ + xide_LunInfo_t *li=NULL; + xide_TargInfo_t *ti=NULL; + scsi_request_t *req=NULL; + scsi_request_t *req_to_use=NULL; + xide_CmdObj_t *co=NULL; + int mapres; + int tag = -1; +// int *tag_addr=NULL; + int putco=0; + + + IOLOCK(pi->ResourceLock, pi->ResourceLockSpl); + + pi->LastTargServed ^=1; + if ((pi->device_conf[pi->LastTargServed] & TARGET_IN_GRAPH) == 0) { + pi->LastTargServed ^=1; + } + + ti = pi->PtrToTarg[pi->LastTargServed]; + li = ti->PtrToLun[0]; + if (li == NULL) { + IDE_DBG(0,"xscsi/ide:: xide_start1 : li 0x"IDE_PTR"\n",li); + IDE_ASSERT(li!=NULL); + } + IOUNLOCK(pi->ResourceLock, pi->ResourceLockSpl); + + IDE_DBG(14,"\n\n xide_start1(0x"IDE_PTR")\n",pi); + IDE_DBG(14,"xide_start1() : pi->LastTargServed %d \n",pi->LastTargServed); + IOLOCK(li->LunLock, li->LunSpl); + req = xide_dequeue_scsireq(li); + if (req == NULL) { + IDE_DBG(4,"xide_start1(): No requests to be executed\n"); + IOUNLOCK(li->LunLock, li->LunSpl); + return IDE_QUEUE_EMPTY; + } + else { + IDE_DBG(14,"start1() :Got Req 0x"IDE_PTR" to execute\n",req); + } +#if IDE_CMD_DEBUG + bcopy(req->sr_command, xide_cmd_list[xide_cmd_index].command, req->sr_cmdlen); + xide_cmd_list[xide_cmd_index].datalength = req->sr_buflen; + xide_cmd_list[xide_cmd_index].request = req; + xide_cmd_list[xide_cmd_index].action = IDE_CDBG_RM; + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 2; + xide_cmd_index = 0; + } +#endif + + req->sr_resid = req->sr_buflen; + + if (req->sr_spare != 0) { + uint8_t count; + count= IDE_INB(pi,pi->cmdblk,IDE_COUNT); + tag=(count & 0xF8)>>3; + IDE_DBG(3,"xide_start1() : tag 0x%x\n",tag); + IDE_DBG(11,"Calling xide_get_co_from_tag( %x, "IDE_PTR")\n",tag,li); + co = xide_get_co_from_tag(tag,li); + IDE_DBG(1,"xide_start1() : Internally generated request 0x"IDE_PTR"\n",req); + IDE_ASSERT(co!= NULL); + IDE_ASSERT((co->HoldReq == req)||(co->ReqSense == req)); + } + else { + co = xide_get_cmd_obj(pi); + IDE_DBG(34,"xide_start1() : External request 0x"IDE_PTR"\n",req); + if (co == NULL) { + IDE_DBG(11,"co not got : External request 0x"IDE_PTR" ",req); + IDE_DBG(11,"xide_start1() : Couldnt find spare co !!!\n"); + xide_queue_scsireq_top(li,req); + IOUNLOCK(li->LunLock, li->LunSpl); + return IDE_BUSY; + + } + co->OrigReq = req; + putco=1; + co->Tag = xide_get_co_tag(li); + if (co->Tag == -1 ) { + /* No Tag value free */ +// IOLOCK(li->LunLock, li->LunSpl); + IDE_DBG(1,"xide_start1() : No Tag value free for co 0x"IDE_PTR"\n",co); + xide_queue_scsireq_top(li,req); + xide_return_co_resources(co); + xide_return_free_co(pi,co); + IOUNLOCK(li->LunLock, li->LunSpl); + return (IDE_BUSY); + } + IDE_ASSERT(co->UseBigmap == 0); + } + + IDE_DBG(18,"xide_start1(req 0x"IDE_PTR")\n",req); + + co->li = li; + + if (req->sr_buflen > 0) { + co->transfer_type = DMA; +// { +// strncpy((char *)req->sr_buffer,"Aniket",7); +// IDE_DBG(11,"dma_start(): poisoning sr_buffer 0x"IDE_PTR"\n",req->sr_buffer); +// } + } + +#ifdef XSCSI + req->sr_spare = (uint64_t) co; +#else + req->sr_spare = (void *) co; +#endif + co->State = IDE_CO_ACTIVE; + +/* +#ifdef USE_MAPPED_PCI_TRANSLATION + if (co->PteDMAMap != 0) { + IDE_DBG(0,"xscsi/ide:: co->PteDMAMap != 0 \n"); +// IDE_ASSERT(co->PteDMAMap == 0); + } +#endif + for (i=0;i<12;i++) { + co->CmdBlk[i] = 0; + } +*/ + bzero(&co->CmdBlk[0],12); + bcopy(req->sr_command, &co->CmdBlk[0], req->sr_cmdlen); + +// if ((req->sr_command[0]==0x28)&&(req->sr_command[4]==0xdf)&&(req->sr_command[5]==0xe0)) IDE_ASSERT(0); + + if ((( + (req->sr_command[0] == MODE_SENSE6_CMD) || + (req->sr_command[0] == MODE_SELECT6_CMD) || +#ifndef XSCSI + (req->sr_command[0] == MODE_SENSE10_CMD) || + (req->sr_command[0] == MODE_SELECT10_CMD) || + (req->sr_command[0] == READ_CAPACITY_CMD)) && (req->sr_buffer > 0)) || +#endif + (req->sr_command[0] == WRITE10_CMD) || +#ifdef XSCSI + (req->sr_command[0] == READ10_CMD)) && (req->sr_buffer >0))) +#else + (req->sr_command[0] == READ10_CMD)) +#endif + { + req_to_use = xide_fix_mode_cmd_xmt(req); +#if IDE_CMD_DEBUG + bcopy(req_to_use->sr_command, xide_cmd_list[xide_cmd_index].command, req_to_use->sr_cmdlen); + xide_cmd_list[xide_cmd_index].datalength = req_to_use->sr_buflen; + xide_cmd_list[xide_cmd_index].request = req_to_use; + xide_cmd_list[xide_cmd_index].action = IDE_CMD_BRANCH; + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif + + } + else { + req_to_use = req; + } + + IDE_ASSERT(req_to_use!=NULL); + if (req_to_use == NULL) { + IDE_DBG(1,"xide_start1 : req_to_use was NULL co 0x"IDE_PTR"\n",co); + xide_queue_scsireq_top(li,req); + xide_return_co_resources(co); + xide_return_free_co(pi, co); + IOUNLOCK(li->LunLock, li->LunSpl); + return(IDE_FAIL); + } + + co->SentReq = req_to_use; +#ifdef XSCSI + req_to_use->sr_spare = (uint64_t) co; +#else + req_to_use->sr_spare = (void *) co; +#endif + mapres = xide_getmap(pi, req_to_use); + + /* Put Co in the Queue */ + if (putco) { + if (li->CmdObjHead == NULL) { + IDE_DBG(3,"xide_start1() : 1st co in queue co 0x"IDE_PTR"\n",co); + li->CmdObjHead = co; + co->Next = NULL; + } + else { + IDE_DBG(11,"xide_start1() : Inserting co in queue-tail co 0x"IDE_PTR"\n",co); + co->Next = li->CmdObjTail; + li->CmdObjTail->Prev = co; + } + li->CmdObjTail = co; + co->Prev = NULL; + dki_dcache_wb((caddr_t)co->Pte, co->NumPtes * sizeof(xide_PageTblEntry_t)); + } + else { + IDE_DBG(1," co 0x"IDE_PTR" already present in li 0x"IDE_PTR" queue\n",co,li); + } + co->TimeOut = req->sr_timeout; + co->StartTime = lbolt; + co->TimeOutTime = co->StartTime + req->sr_timeout; + IDE_DBG(23,"co->StartTime 0x%x | TimeoutTime 0x%x | lbolt 0x%x\n",co->StartTime,co->TimeOutTime,lbolt); + +// IOLOCK(pi->CommandLock, pi->CommandLockSpl); + +#if IDE_CMD_DEBUG + bcopy(req_to_use->sr_command, xide_cmd_list[xide_cmd_index].command, req_to_use->sr_cmdlen); + xide_cmd_list[xide_cmd_index].datalength = req_to_use->sr_buflen; + xide_cmd_list[xide_cmd_index].request = req_to_use; + xide_cmd_list[xide_cmd_index].action = IDE_CMD_SENT; + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif + if (mapres == IDE_FAIL) { /* couldn't get map so try again later */ + IDE_DBG(1,"Couldnt allocate DMA maps for co 0x"IDE_PTR"\n",co); + req->sr_status = SC_REQUEST; + req->sr_resid = req->sr_buflen; + co->request_stage = CMD_COMPLETE; + IDE_DBG(1,"Befoe xide_complete_a_req() \n"); + xide_complete_a_req(li,req); + IDE_DBG(1,"Befoe xide_remove_co() \n"); + xide_remove_co(co); + IDE_DBG(1,"Befoe xide_return_co_resources() \n"); + xide_return_co_resources(co); + IDE_DBG(1,"Befoe xide_test_co_for_free() \n"); + xide_test_co_for_free(co); + IOUNLOCK(li->LunLock, li->LunSpl); + xide_return_finished_req(pi); + return(IDE_FAIL); + } + + if (pi->device_conf[ti->Number] & ATA_DEV_PRESENT) { + co->Offset_Flag |= IDE_START_TRANSFER; + } + xide_send_co(co); + +// IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + IOUNLOCK(li->LunLock, li->LunSpl); + + return IDE_OK; + +} + +static int xide_fix_mode_cmd_rcv(scsi_request_t *req, xide_CmdObj_t *co, int scsi_status) +{ +// xide_mode_sense_6_hdr_t *mode_sense_6_hdr_t=NULL; + xide_mode_sense_6_hdr_t *mode_sense_6_hdr_h=NULL; + xide_mode_sense_10_hdr_t *mode_sense_10_hdr_t=NULL; + xide_mode_sense_10_hdr_t *mode_sense_10_hdr_h=NULL; + scsi_request_t *temp_req=NULL; + uint sense_length=0; + uint blk_d_len=0; + u_char *bd_start=NULL; + uint host_data_offset=0; + u_char *host_data_start=NULL; + u_char *host_bd_start=NULL; + uint data_cp_len=0; + u_char dev_specific=0; + u_char media_type=0; + u_char *blk_data=NULL; /* where blk data starts */ + xide_LunInfo_t *li=NULL; + u_char rcv_cmd_byte=0; + + if (scsi_status == 2) { + /* We need to send a Request Sense back...so no buffer modification needed */ + return 0; + } + + IDE_DBG(3,"rcv() : Incoming request 0x"IDE_PTR"\n",req); + li = co->li; + temp_req = co->TempReqForFix; + if (temp_req == NULL) { + IDE_DBG(3,"rcv() : didn't use temp_req \n"); + temp_req = req; + } + + rcv_cmd_byte = (u_char)(req->sr_command[0]); + IDE_DBG(3,"rcv() : rcv_cmd_byte 0x%x\n",rcv_cmd_byte); + + /* if the substitute command that was sent out was a mode_sense(6) or a + * mode_sense(10) command, extract the various data field out of the data + * that was retured. + * If a test_unit_ready was received and the real command was a mode_sense(6) + * or mode_sense(10), then the test_unit_ready was done because all that is + * required is the blocksize. So for test_unit_ready, set all the fields to + * 0. When we get to the next section, where we build up the data for the real + * request, the block descriptor (the blocksize) will be added to the mode sense + * data. + */ + + if ((co->CmdBlk[0] == MODE_SENSE10_CMD)&&(rcv_cmd_byte == MODE_SENSE6_CMD)&&(temp_req->sr_buffer!=0)) { + if (li->NoMode6Cmd == 1) { + /* "mode sense 10" or "test unit ready" received */ + IDE_DBG(3,"xide_fix_mode_cmd_rcv() : MSense 10 buffer -> MSense 6 buffer \n"); + mode_sense_10_hdr_t = (xide_mode_sense_10_hdr_t *)temp_req->sr_buffer; + if (mode_sense_10_hdr_t) { + sense_length = (mode_sense_10_hdr_t->SenseLen[0] << 8) + mode_sense_10_hdr_t->SenseLen[1]; + blk_d_len = (mode_sense_10_hdr_t->BlkDescLen[0] << 8) + mode_sense_10_hdr_t->BlkDescLen[1]; + bd_start = &mode_sense_10_hdr_t->Data.DataNoBD[0]; + data_cp_len = sense_length - 6 - blk_d_len; /* subtract header, BD */ + dev_specific = mode_sense_10_hdr_t->DevSpecific; + media_type = mode_sense_10_hdr_t->MediaType; + if (data_cp_len > temp_req->sr_buflen) { + data_cp_len = temp_req->sr_buflen; + } + IDE_DBG(3,"rcv() : sense_length 0x%x |blk_d_len 0x%x | data_cp_len 0x%x |media_type 0x%x\n", + sense_length,blk_d_len,data_cp_len,media_type); + } + else { + IDE_DBG(0,"xscsi/ide:: Modesense Cmd 10 sent with 0 buffer length\n"); + IDE_ASSERT(0); + } + } + } + else if ((co->CmdBlk[0] == 0x0) && + ((rcv_cmd_byte == MODE_SENSE10_CMD) || (rcv_cmd_byte == MODE_SENSE6_CMD))) { + /* test unit ready, ie only blocksize was being read */ + blk_d_len = 0; + data_cp_len = 0; + dev_specific = 0; + media_type = 0; + } + + /* if the blk_d_len is 0 and we are supposed to add in a + * block descriptor, then ajust the lengths of the block + * and where data starts so that we make room for the + * block descriptor + */ + host_data_offset = 0; + if ((li->AddSenseBD == 1) && (blk_d_len == 0)) { /* add in kludged block descriptor */ + IDE_DBG(3,"rcv() : Need to add Blk Desc\n"); + blk_d_len = 8; + host_data_offset = 8; + } + + /* now build up the data fields for the real request using the + * data that was collected above + */ + IDE_DBG(1,"0:host_bd_start 0x%x \n",host_bd_start); + if ((req->sr_command[0] == MODE_SENSE6_CMD)&&(req->sr_buffer!=0)) { /* host gets 6 byte command */ + IDE_DBG(1,"rcv() : Original req was MSense6\n"); + mode_sense_6_hdr_h = (xide_mode_sense_6_hdr_t *)req->sr_buffer; + if (mode_sense_6_hdr_h) { + sense_length = 3 + blk_d_len + data_cp_len; + mode_sense_6_hdr_h->SenseLen = sense_length; + mode_sense_6_hdr_h->MediaType = media_type; + mode_sense_6_hdr_h->DevSpecific = dev_specific; + mode_sense_6_hdr_h->BlkDescLen = blk_d_len; + host_bd_start = &mode_sense_6_hdr_h->Data.DataNoBD[0]; + IDE_DBG(1,"host_bd_start 0x%x \n",host_bd_start); + host_data_start = (u_char *)((uintptr_t)host_bd_start + host_data_offset); + IDE_ASSERT(data_cp_len < 0x200); + if (data_cp_len > 0) { + bcopy(bd_start, host_data_start, data_cp_len); + } + } else { + IDE_DBG(0,"xscsi/ide:: OrigReq->sr_buffer was NULL\n"); + IDE_ASSERT(0); + } + } + else if ((req->sr_command[0] == MODE_SENSE10_CMD)&&(req->sr_buffer!=0)) { + /* host gets 10 byte command */ + IDE_DBG(3,"xide_fix_mode_cmd_rcv() : MSense 10 cmd was got by host \n"); + mode_sense_10_hdr_h = (xide_mode_sense_10_hdr_t *)req->sr_buffer; + if (mode_sense_10_hdr_h) { + sense_length = 6 + blk_d_len + data_cp_len; + mode_sense_10_hdr_h->SenseLen[0] = sense_length >> 8; + mode_sense_10_hdr_h->SenseLen[1] = sense_length & 0xff; + mode_sense_10_hdr_h->MediaType = media_type; + mode_sense_10_hdr_h->DevSpecific = dev_specific; + mode_sense_10_hdr_h->BlkDescLen[0] = blk_d_len >> 8; + mode_sense_10_hdr_h->BlkDescLen[1] = blk_d_len & 0xff; + host_bd_start = &mode_sense_10_hdr_h->Data.DataNoBD[0]; + host_data_start = (u_char *)((uintptr_t)host_bd_start + host_data_offset); + if (data_cp_len > 0) { + bcopy(bd_start, host_data_start, data_cp_len); + } + } else { + IDE_DBG(0,"xscsi/ide:: OrigReq->sr_buffer was NULL\n"); + IDE_ASSERT(0); + } + } + + /* now copy in the block descriptor. If we have done a read capacity + * then just copy its data into the mode_sense data to be returned. If + * there hasn't been a read_capacity then do on and make the target of + * the capacity data be were the block descriptor data is supposed to + * go for the mode_sense command. + */ + + if (host_data_offset == 8) { /* adding block descriptor */ + if (li->CapDataValid == 1) { + IDE_DBG(1,"We have block descriptor : blk_d_len %d | host_bd_start 0x%x\n",blk_d_len,host_bd_start); +//#ifdef IOC4_DMA_BUG // ONLY FOR IOC4 +// bcopy(host_bd_start,co->SentReq->sr_buffer,8); +//#endif + bcopy(&li->CapNumOfBlocks, host_bd_start, 8); +#ifdef XSCSI + swab32_region((uint32_t *)host_bd_start, 8); +// if (li->CapBlockSize > 0x800) BUG(); /*FIXME: remove me */ +#endif + blk_data = host_bd_start; + } + else { + scsi_request_t *cap_req; + + IDE_DBG(3,"Asking for block descriptor\n"); + xide_co_free_dmamap(co); + cap_req = xide_get_capacity(li, req, host_bd_start); + co->HoldReq = cap_req; /* make mode select wait for capacity to fill in BD */ +#ifdef XSCSI + cap_req->sr_spare = (uint64_t) &(co->Tag);// recording Tag of calling co +#else + cap_req->sr_spare = (void *) &(co->Tag);// recording Tag of calling co +#endif + + IDE_DBG(3,"req 0x"IDE_PTR" | co 0x"IDE_PTR" | Tag %d\n",cap_req,co,co->Tag); + xide_queue_scsireq(li, cap_req); // sos + return IDE_HOLD; + } + } + + /* if we get a read_capacity command, then remember the data + * for use in mode_sense commands where we need to add a + * block descriptor. + */ + if (co->SentReq->sr_command[0] == READ_CAPACITY_CMD) { + blk_data = (u_char *)&li->CapNumOfBlocks; + +#ifdef XSCSI + { + int i; + IDE_DBG(11,"Assigning blk_data to li->CapNumOfBlocks\n"); + for (i=0;i<8;i++) { + IDE_DBG(11,"blk[%d] : 0x%x | ",i,blk_data[i]); + } + IDE_DBG(11,"\n"); + +// swab32_region((uint32_t *)blk_data,8); + + for (i=0;i<8;i++) { + IDE_DBG(11,"blk_data[%d] : 0x%x | ",i,blk_data[i]); + } + } +#endif + + } + + /* if the capacity data from a read_capacity or from a block descriptor + * in a mode sense was written, then we need to fix it if we are simulating + * a block size not supported by the target. + */ + if ((blk_data != NULL) && + (li->FixSenseBD == 1) && + (li->BlockSize < li->CapBlockSize)) { + + uint fixed_cap; + uint fix_multiple; + uint numblk; + + IDE_DBG(1,"li->BlockSize 0x%x < CapBlockSize 0x%x \n",li->BlockSize,li->CapBlockSize); + numblk = (blk_data[0] << 24) | (blk_data[1] << 16) | (blk_data[2] << 8) | blk_data[3]; + fix_multiple = li->CapBlockSize / li->BlockSize; + fixed_cap = ((numblk + 1) * fix_multiple) - 1; + blk_data[0] = fixed_cap >> 24; + blk_data[1] = fixed_cap >> 16; + blk_data[2] = fixed_cap >> 8; + blk_data[3] = fixed_cap; + blk_data[4] = li->BlockSize >> 24; + blk_data[5] = li->BlockSize >> 16; + blk_data[6] = li->BlockSize >> 8; + blk_data[7] = li->BlockSize; + } + + dki_dcache_wbinval(req->sr_buffer, req->sr_buflen); + return 0; +} + + +static scsi_request_t * +xide_get_capacity(xide_LunInfo_t *li, scsi_request_t *orig_req, u_char *cap_data) +{ + scsi_request_t *req; + u_char *cap_space; + u_char *cmd; + u_char *sense; + int space_to_alloc; + + + space_to_alloc = sizeof(scsi_request_t) + 12 + SCSI_SENSE_LEN; /* req + cmd + sense */ + IDE_KMEM_ZALLOC(cap_space, space_to_alloc, KM_NOSLEEP); + req = (scsi_request_t *)cap_space; + sense = cap_space + sizeof(scsi_request_t); + cmd = sense + SCSI_SENSE_LEN; + cmd[0] = READ_CAPACITY_CMD; + req->sr_ctlr = li->ProtoInfo->Number; + req->sr_target = li->TargInfo->Number; + req->sr_lun = li->Number; + req->sr_command = cmd; + req->sr_cmdlen = 12; /* Capacity command length */ + req->sr_buffer = (u_char *)cap_data; +#ifdef IOC4_DMA_BUG + { + uint8_t *buffer; + IDE_KMEM_ZALLOC(buffer,8,KM_NOSLEEP|KM_CACHEALIGN); + req->sr_buffer = buffer; + } +#endif + req->sr_buflen = 8; + req->sr_sense = sense; + req->sr_senselen = SCSI_SENSE_LEN; + req->sr_flags = SRF_DIR_IN | SRF_FLUSH | SRF_AEN_ACK; + req->sr_timeout = 10 * HZ; + req->sr_notify = xide_capacity_done; + req->sr_lun_vhdl = li->LunVhdl; +#ifdef XSCSI + req->sr_spare = (uint64_t) orig_req; +#else + req->sr_spare = (void *) orig_req; +#endif + + return(req); +} + +static void xide_capacity_done(scsi_request_t *req) +{ + int allocated_space; + + allocated_space = sizeof(scsi_request_t) + 12 + SCSI_SENSE_LEN; +#if IOC4_DMA_BUG + IDE_KMEM_FREE(req->sr_buffer, 8); +#endif + IDE_KMEM_FREE(req, allocated_space); +} + +/* we must change the 6 byte mode select and mode sense commands + * to the 10 byte versions. The versions are pretty much the same + * except that the 10 byte version has 4 more bytes of header. + * so the allocation length must be bumped by 4. We allocate a + * new scsi_request_t and make it the same as the original request + * except that we increase the data size by 4 (for the header + * length) and point at the new (bigger) space that we allocated. + * + * For outbound data (mode select) we must insert the extra + * bytes into the header and copy the data to the new space. + * + * For inbound data (mode sense) scsi_resp_back will copy the + * data received into the original sr_buffer, removing the + * extra bytes of header. + * + * For ModeSelect we also need to check to see if there is + * a block descriptor (trying to change blocksize) in the + * mode select data. If so and if the device can't handle it + * (a fixed blocksize device), then we must remove the block + * descriptor so we don't get a check condition. We also + * remember what blocksize is being requested so that we can + * fudge Logical Block Addresses and Block Lengths later. + * + * For read10 and write10, we must adjust the LBA and length + * based on the media blocksize (from the last mode select) + * compared to the blocksize from a capacity command. + */ +static scsi_request_t * +xide_fix_mode_cmd_xmt(scsi_request_t *req) +{ + scsi_request_t *temp_req=NULL; + u_char *temp_space=NULL; + u_int temp_space_length=0; + u_int sense_length=0; + u_int param_length=0; + xide_CmdObj_t *co=NULL; + xide_mode_sense_6_hdr_t *mode_sense_6_hdr_in=NULL; + xide_mode_sense_10_hdr_t *mode_sense_10_hdr_in=NULL; +// xide_mode_sense_6_hdr_t *mode_sense_6_hdr_out=NULL; + xide_mode_sense_10_hdr_t *mode_sense_10_hdr_out=NULL; + int alloc_length; + xide_LunInfo_t *li=NULL; + u_char media_type=0; + u_char dev_specific=0; + u_int blk_d_len=0; + u_char *data_start=NULL; + u_char cmd_is_10=0; + uint buflen=0; + u_char *buffer=NULL; + int i; + + co = (xide_CmdObj_t *)req->sr_spare; + li = co->li; + + /* if this is a mode sense (6) command and the device only supports + * the mode sense (10) command, then change the (6) command to a + * (10) command. This will reposition the args in the command making + * it 4 bytes longer. + */ + if (req->sr_command[0] == MODE_SENSE6_CMD) { + + if (li->NoMode6Cmd == 0) { + IDE_DBG(11,"xide_mode_cmd_xmt(): Mode Sense 6 Cmd supported by this CDROM/DVDROM\n"); + return(req); + } + + alloc_length = req->sr_command[4]; + buflen = req->sr_buflen; + buffer = req->sr_buffer; + + /* if we are supposed to fix the Block Descriptor, then dont + * ask for it from the target. So turn on Disable Block + * Descriptor bit + */ + if ((li->FixSenseBD == 1) && !(co->CmdBlk[1] & (1<<3))) { + co->CmdBlk[1] |= (1 << 3); + li->AddSenseBD = 1; + if (req->sr_buflen >= 4) { + if (co->TempReqForFix == NULL) { + co->TempReqForFix = (scsi_request_t *)((uintptr_t) 1); + } + buffer += 8; + buflen -= 8; + alloc_length -= 8; + } + } else { + li->AddSenseBD = 0; + } + + if (alloc_length <= 4) { + co->TempReqForFix = (scsi_request_t *)((uintptr_t) 1); + + co->CmdBlk[0] = 0; /* ??? make into test unit ready */ + co->CmdBlk[1] = 0; + co->CmdBlk[2] = 0; + co->CmdBlk[3] = 0; + co->CmdBlk[4] = 0; + co->CmdBlk[5] = 0; + co->CmdBlk[6] = 0; + co->CmdBlk[7] = 0; + co->CmdBlk[8] = 0; + co->CmdBlk[9] = 0; + co->CmdBlk[10] = 0; + co->CmdBlk[11] = 0; + return (req); + } + + IDE_KMEM_ALLOC(temp_req, sizeof(scsi_request_t), VM_CACHEALIGN); + bcopy(req, temp_req, sizeof(scsi_request_t)); + co->TempReqForFix = temp_req; + + if (li->NoMode6Cmd == 1) { + buflen += 4; /* parameter header is bigger */ + alloc_length += 4; + } + + IDE_KMEM_ALLOC(temp_space, buflen, VM_CACHEALIGN); + temp_req->sr_buffer = temp_space; + temp_req->sr_buflen = buflen; + + if (li->NoMode6Cmd == 1) { +// mode_sense_6_hdr_in = (xide_mode_sense_6_hdr_t *)req->sr_buffer; + + co->CmdBlk[0] = MODE_SENSE10_CMD; + co->CmdBlk[1] = 0; + co->CmdBlk[2] = req->sr_command[2]; // my addition + co->CmdBlk[3] = 0; + co->CmdBlk[4] = 0; + co->CmdBlk[5] = 0; + co->CmdBlk[6] = 0; + co->CmdBlk[7] = alloc_length >> 8; + co->CmdBlk[8] = alloc_length & 0xff; + co->CmdBlk[9] = 0; + co->CmdBlk[10] = 0; + co->CmdBlk[11] = req->sr_command[5]; + + dki_dcache_wbinval(temp_req->sr_buffer, temp_req->sr_buflen); + } + else { + co->CmdBlk[4] = alloc_length; + } + + IDE_DBG(3,"xmt() : Returning temp_req 0x"IDE_PTR" | Orig Req 0x"IDE_PTR"\n",temp_req,req); + return(temp_req); + } + else if (req->sr_command[0] == MODE_SENSE10_CMD) { + /* If we receive a modesense (10) command, + * we need to check if a block descriptor is requested. + * If so, we should set the DBD bit to 1, and record that + * a block descriptor was requested by setting + * li->AddSenseBD=1 + * In the rcv() function we'll add the stored blk-desc + * to this request's buffer. + */ + if (li->NoMode10Cmd == 0) { + + alloc_length = (req->sr_command[7] << 8) + req->sr_command[8]; + buflen = req->sr_buflen; + buffer = req->sr_buffer; + + /* if we are supposed to fix the Block Descriptor, then dont + * ask for it from the target. So turn on Disable Block + * Descriptor bit + */ + if ((li->FixSenseBD == 1) && !(co->CmdBlk[1] & (1<<3))) { + co->CmdBlk[1] |= (1 << 3); + li->AddSenseBD = 1; + if (buflen >= 8) { + buffer += 8; + buflen -= 8; + alloc_length -= 8; + } + } + else { + li->AddSenseBD = 0; + } + + IDE_KMEM_ALLOC(temp_req, sizeof(scsi_request_t), VM_CACHEALIGN); + bcopy(req, temp_req, sizeof(scsi_request_t)); + co->TempReqForFix = temp_req; + + IDE_KMEM_ALLOC(temp_space, buflen, VM_CACHEALIGN); + temp_req->sr_buffer = temp_space; + temp_req->sr_buflen = buflen; + + co->CmdBlk[7] = alloc_length >> 8; + co->CmdBlk[8] = alloc_length & 0xff; + + return(temp_req); + } + } + else if ((req->sr_command[0] == MODE_SELECT6_CMD) || + (req->sr_command[0] == MODE_SELECT10_CMD)) { + /* if this is a mode select (6) command then we can have two + * possible conditions to fix. First, if the device only supports + * the (10) or the (6) version of the command, then we need to + * make the (6) command into a (10) or the (10) into a (6). This + * will reposition data in the command, making it 4 bytes longer + * or shorter. + * Secondly if the device's blocksize cannot be changed, we need to + * intercept the attempt to change the blocksize using the block + * descriptor and get rid of it. At the same time, we will remember what + * the block size attempted was and adjust all read/write commands after + * this so that it appears to the upper levels like the blocksize did + * get set. This will shorten the data by 8, the length of the block + * descriptor and zero out the descriptor length in the header. */ + + if ((((req->sr_command[0] == MODE_SELECT10_CMD) && (li->NoMode10Cmd == 0)) || + ((req->sr_command[0] == MODE_SELECT6_CMD) && (li->NoMode6Cmd == 0))) && + (li->FixSenseBD != 1)) { + IDE_DBG(11,"Returning req 0x"IDE_PTR" without modification \n",req); + return(req); + + } + IDE_DBG(13,"xmt() : Got MSelect 6/10 cmd \n"); + for (i=0;isr_buflen;i++) { + IDE_DBG(23,"MsLT[%d] : 0x"IDE_PTR" ",i,req->sr_buffer[i]); + } + IDE_DBG(13,"\n"); + + IDE_KMEM_ALLOC(temp_req, sizeof(scsi_request_t), VM_CACHEALIGN); + bcopy(req, temp_req, sizeof(scsi_request_t)); + co->TempReqForFix = temp_req; + + temp_space_length = req->sr_buflen; + + if (req->sr_command[0] == MODE_SELECT6_CMD) { + mode_sense_6_hdr_in = (xide_mode_sense_6_hdr_t *)req->sr_buffer; + param_length = req->sr_command[4]; + if (mode_sense_6_hdr_in) { + sense_length = mode_sense_6_hdr_in->SenseLen; + media_type = mode_sense_6_hdr_in->MediaType; + dev_specific = mode_sense_6_hdr_in->DevSpecific; + blk_d_len = mode_sense_6_hdr_in->BlkDescLen; + data_start = (u_char *)&mode_sense_6_hdr_in->Data.DataNoBD[0]; + IDE_DBG(3,"\nMSlt6 : param_len %d | sense_len %d | media_type %d | \ +dev_spec %d | blk_d_len %d | data_start 0x"IDE_PTR" \n", + param_length,sense_length,media_type,dev_specific, + blk_d_len,data_start); + } + + + if (li->NoMode6Cmd == 1) { /* change into modeselect(10 byte) command */ + IDE_DBG(3,"xmt() : MSelect 6 -> 10 ChANGE \n"); + mode_sense_10_hdr_out = (xide_mode_sense_10_hdr_t *)temp_req->sr_buffer; + temp_space_length += 4; /* diff in headers */ + sense_length += 4; + param_length += 4; + co->CmdBlk[0] = MODE_SELECT10_CMD; + co->CmdBlk[1] = req->sr_command[1] | 0x10; // my addition + co->CmdBlk[2] = 0; + co->CmdBlk[3] = 0; + co->CmdBlk[4] = 0; + co->CmdBlk[5] = 0; + co->CmdBlk[6] = 0; + co->CmdBlk[7] = param_length >> 8; + co->CmdBlk[8] = param_length & 0xff; + co->CmdBlk[9] = 0; + co->CmdBlk[10] = 0; + co->CmdBlk[11] = req->sr_command[5]; + cmd_is_10 = 1; + } + } + else { /* this is a MODE_SELECT_10_CMD */ + IDE_DBG(13,"ModeSelect 10 CMD\n"); + mode_sense_10_hdr_in = (xide_mode_sense_10_hdr_t *)req->sr_buffer; + param_length = (req->sr_command[7] << 8) | req->sr_command[8]; + if (param_length > 0xff) param_length = 0xff; + + if (mode_sense_10_hdr_in) { + sense_length = (mode_sense_10_hdr_in->SenseLen[0] << 8) | + mode_sense_10_hdr_in->SenseLen[1]; + if (sense_length > 0xff) sense_length = 0xff; + + media_type = mode_sense_10_hdr_in->MediaType; + dev_specific = mode_sense_10_hdr_in->DevSpecific; + blk_d_len = (mode_sense_10_hdr_in->BlkDescLen[0] << 8) | + mode_sense_10_hdr_in->BlkDescLen[1]; + data_start = (u_char *)&mode_sense_10_hdr_in->Data.DataNoBD[0]; + } + cmd_is_10 = 1; + IDE_DBG(3,"(Mselect10) : param_len %d | sense_len %d | media_type %d | \ + dev_spec %d | blk_d_len %d | data_start 0x"IDE_PTR"\n", + param_length,sense_length,media_type,dev_specific, + blk_d_len,data_start); + } + + + if (li->FixSenseBD == 1) { + IDE_DBG(1,"xmt() : MSelect 6->10 : Fixing Block Descriptor\n"); + if (blk_d_len == 8) { + blk_d_len = 0; + temp_space_length -= 8; + sense_length -= 8; + param_length -= 8; + li->BlockSize = (data_start[5] << 16) | (data_start[6] << 8) | + data_start[7]; + IDE_DBG(1,"xmt() : li->BlockSize CHANGED to 0x"IDE_PTR" \n",li->BlockSize); + li->BlockSizeValid = 1; + data_start = data_start + 8; + } + } + + if (temp_space_length == 0) { + if (cmd_is_10 == 1) { + IDE_DBG(3,"xmt() : MSelect 6->10 : buffer len = 0 \n"); + co->CmdBlk[7] = 0; + co->CmdBlk[8] = 0; + } + temp_req->sr_buffer = NULL; + temp_req->sr_buflen = 0; + return(temp_req); + } + + IDE_KMEM_ALLOC(temp_space, temp_space_length, VM_CACHEALIGN); + temp_req->sr_buffer = temp_space; + temp_req->sr_buflen = temp_space_length; + + if (cmd_is_10 == 1) { + mode_sense_10_hdr_out = (xide_mode_sense_10_hdr_t *)temp_req->sr_buffer; + + if (param_length > 8) { + /* if desc blk is more than header */ + /* 8 bytes for Mselect 10 , 4 bytes for Mselect 6 */ + co->CmdBlk[7] = param_length >> 8; + co->CmdBlk[8] = param_length & 0xff; + } + else { /* if only header, make length = 0 */ + IDE_DBG(13,"xmt() : MSelect 6->10 : CHanged to 'TEST UNIT READY' \n"); + co->CmdBlk[0] = 0; /* ??? make into test unit ready */ + co->CmdBlk[1] = 0; + co->CmdBlk[2] = 0; + co->CmdBlk[3] = 0; + co->CmdBlk[4] = 0; + co->CmdBlk[5] = 0; + co->CmdBlk[6] = 0; + co->CmdBlk[7] = 0; + co->CmdBlk[8] = 0; + co->CmdBlk[9] = 0; + co->CmdBlk[10] = 0; + co->CmdBlk[11] = 0; + + temp_req->sr_buflen = 0; + temp_req->sr_buffer = NULL; + return(temp_req); + } + + mode_sense_10_hdr_out->SenseLen[0] = 0; /* SenseLen rsvd for mode select */ + mode_sense_10_hdr_out->SenseLen[1] = 0; + mode_sense_10_hdr_out->MediaType = media_type; + mode_sense_10_hdr_out->DevSpecific = dev_specific; + mode_sense_10_hdr_out->Reserved[0] = 0; + mode_sense_10_hdr_out->Reserved[1] = 0; + mode_sense_10_hdr_out->BlkDescLen[0] = blk_d_len >> 8; + mode_sense_10_hdr_out->BlkDescLen[1] = blk_d_len & 0xff; + + if (temp_space_length > 8) /* header, ie 8 bytes, done above */ + bcopy(data_start, &mode_sense_10_hdr_out->Data.DataNoBD[0], temp_space_length-8); + } + + for (i=0;isr_buflen;i++) { + IDE_DBG(3,"MSLT10 [%d] : 0x"IDE_PTR" ",i,temp_req->sr_buffer[i]); + } + IDE_DBG(3,"\n"); + dki_dcache_wbinval(temp_req->sr_buffer, temp_req->sr_buflen); + return(temp_req); + } + /* end of mode select 6 or 10 */ + else if ((req->sr_command[0] == READ10_CMD) || + (req->sr_command[0] == WRITE10_CMD)) { + /* here if the command is a read or write using block addresses + * and lengths. We need to determine if the smaller blocks of + * the media start and end not on the bigger device blocks. If + * so, we set the FixMap4BlkSz flag. The allocation of the + * dmamaps will use this to have the unused portions of the + * first and last device blocks DMAed into a null buffer. + */ + IDE_DBG(13,"READ/WRITE 10 cmd received\n"); + if (li->BlockSize < li->CapBlockSize) { + u_int lba; + u_int xfer_len; + u_int new_lba; + u_int new_xfer_len; + u_int divisor; + u_int lba_begin_offset; + u_int lba_end_offset; + + lba = (req->sr_command[2] << 24) | (req->sr_command[3] << 16) | + (req->sr_command[4] << 8) | req->sr_command[5]; + xfer_len = (req->sr_command[7] << 8) | req->sr_command[8]; + + divisor = li->CapBlockSize / li->BlockSize; + + new_lba = lba / divisor; + lba_begin_offset = lba%divisor; + lba_end_offset = (lba_begin_offset + xfer_len)%divisor; + + new_xfer_len = (lba_begin_offset + xfer_len) / divisor; + if (lba_end_offset != 0) new_xfer_len++; + + IDE_DBG(1,"Block Size change needed : xfer_len 0x%x | new_lba 0x%x | new_xfer_len 0x%x lba_begin_offset 0x%x | lba_end_offset 0x%x\n",xfer_len,new_lba,new_xfer_len,lba_begin_offset,lba_end_offset); + + if ((lba_begin_offset != 0) || (lba_end_offset != 0)) { + co->FixMap4BlkSz = 1; + co->MapStartLen = lba_begin_offset * li->BlockSize; + if (lba_end_offset > 0) { + co->MapEndLen = (divisor - lba_end_offset) * li->BlockSize; + } else { + co->MapEndLen = 0; + } + } else { + co->FixMap4BlkSz = 0; + } + + /* fix up the scsi command that the device will see with + * the block address and length based on the device's block + * size. + */ + co->CmdBlk[2] = new_lba >> 24; + co->CmdBlk[3] = new_lba >> 16; + co->CmdBlk[4] = new_lba >> 8; + co->CmdBlk[5] = new_lba; + + co->CmdBlk[7] = new_xfer_len >> 8; + co->CmdBlk[8] = new_xfer_len; + } + else { + IDE_DBG(3,"Block Size change NOT needed\n"); + co->FixMap4BlkSz = 0; + } + IDE_DBG(13,"returning request(0x"IDE_PTR")\n",req); + return(req); + } + /* end if READ10 or WRITE10 CMD */ + else if (req->sr_command[0] == READ_CAPACITY_CMD) { + IDE_DBG(13,"xmt() : Read Capacity Cmd : Nothing done \n"); + return(req); + } + +// IDE_ASSERT(0); + return(req); +} + + +static void xide_queue_scsireq_top(xide_LunInfo_t *li, scsi_request_t *req) +{ + +#if IDE_CMD_DEBUG + bcopy(req->sr_command, xide_cmd_list[xide_cmd_index].command, req->sr_cmdlen); + xide_cmd_list[xide_cmd_index].datalength = req->sr_buflen; + xide_cmd_list[xide_cmd_index].request = req; + xide_cmd_list[xide_cmd_index].action = IDE_CDBG_ADD; + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif + + IDE_ASSERT(mutex_mine(&li->LunLock)); + + if (li->ScsiReqQHead == NULL) { + li->ScsiReqQHead = req; + IDE_DBG(3,"xide_queue_scsireq() : 1st req in queue\n"); + } + else { + li->ScsiReqQHead->sr_ha = req; + IDE_DBG(3,"xide_queue_scsireq() : Request added to HeadEnd\n"); + li->ScsiReqQHead = req; + } + + if (li->ScsiReqQTail == NULL) { + li->ScsiReqQTail = req; + } + IDE_DBG(3,"top() : Inserted Req 0x"IDE_PTR" at top \n",req); + req->sr_ha = NULL; + + return; +} + +int xide_alloc(vertex_hdl_t lun_vhdl, int opt, void (*cb)(vertex_hdl_t, uint8_t *)) +{ + xide_LunInfo_t *li; + int retval = SCSIALLOCOK; + scsi_lun_info_t *lun_info = NULL; + + IDE_DBG(1, "Starting xide_alloc to lun vhdl 0x"IDE_PTR"\n", lun_vhdl); + lun_info = scsi_lun_info_get(lun_vhdl); + if (lun_info == NULL) { + IDE_DBG(1,"xide_alloc() lun_info == NULL\n"); + return ENODEV; + } + + li = SLI_INFO(lun_info); + if (li == NULL) { + IDE_DBG(1,"xide_alloc() li == NULL\n"); + return ENODEV; + } + /* + * Get controller mutex and allocate target and lun data structures + * if necessary. + */ + + mutex_lock(&li->OpenLock,PRIBIO); + IDE_DBG(1,"xide_alloc() : Got Mutex\n"); + + if (li->Exclusive) { + retval = EBUSY; + IDE_DBG(0,"xscsi/ide:: xide_alloc(): li->Exclusive is true\n"); + goto _allocout; + } + + if (opt & SCSIALLOC_EXCLUSIVE) { + if (li->RefCount != 0) { + retval = EBUSY; + IDE_DBG(1,"li->RefCount != 0\n"); + goto _allocout; + } + } + + if (cb != NULL) { + if (li->SenseCallback != NULL) { + retval = EINVAL; + goto _allocout; + } + else { + li->SenseCallback = cb; + } + IDE_DBG(1,"cb != NULL\n"); +// debug("cb"); + } + + li->RefCount++; + IDE_DBG(1,"alloc() : li->RefCount = %d\n",li->RefCount); +_allocout : + mutex_unlock(&li->OpenLock); + return retval; +} + +void xide_free(vertex_hdl_t lun_vhdl, void (*cb)(vertex_hdl_t, uint8_t *)) +{ + xide_LunInfo_t *li; + scsi_lun_info_t *lun_info; + + IDE_DBG(15,"xide_free()\n"); + lun_info = scsi_lun_info_get(lun_vhdl); + if (lun_info == NULL) { + cmn_err(CE_CONT,"Error : xide_free called when RefCount == 0\n"); + return; + } + + li = SLI_INFO(lun_info); + + mutex_lock(&li->OpenLock, PRIBIO); + + if (li->Exclusive) { + li->Exclusive = 0; + } + + if (cb != NULL) { + if (li->SenseCallback == cb) { + li->SenseCallback = NULL; + } + else { + cmn_err(CE_CONT,"xide_free() : li 0x"IDE_PTR" : Error - Callback 0x%x not active\n",li,cb); + } + } + + if (li->RefCount != 0) { + li->RefCount--; + } + else { + cmn_err(CE_CONT,"xide_free() : li 0x"IDE_PTR" : Error - Refcount == 0\n",li); + } + + mutex_unlock(&li->OpenLock); + + IDE_DBG(13,"Ending xide_free()\n"); + +} +#if 0 +static int xide_remove_lun(xide_LunInfo_t *li, void *lock_to_unlock) +{ + xide_TargInfo_t *ti; + scsi_lun_info_t *lun_info; + + IDE_DBG(5,"xide_remove_lun() started\n"); + + ti = li->TargInfo; + + /* Return all cmds for this lun */ + IOLOCK(li->LunLock,li->LunSpl); + xide_return_lun_cmds(li,SC_TIMEOUT); + IOUNLOCK(li->LunLock,li->LunSpl); + xide_return_finished_req(li->ProtoInfo); + + /* Remove the lun vertex */ + SCSI_HWG_UPDATE(); // Holds the HwGraph Lock + + if (li->RefCount == 0) { + + lun_info = scsi_lun_info_get(li->LunVhdl); + IDE_DBG(3,"xide_remove_lun() : luninfo 0x"IDE_PTR"\n",lun_info); +#ifndef XSCSI + if (scsi_lun_vertex_remove(ti->TargetVhdl, li->Number) == GRAPH_VERTEX_NONE) { + xide_remove_target(ti); + } +#else + scsi_lun_vertex_remove(ti->TargetVhdl, li->Number); + xide_remove_target(ti); +#endif + + SLI_INFO(lun_info) = NULL; + IDE_ASSERT(ti->PtrToLun[li->Number] != NULL); + ti->PtrToLun[li->Number] = NULL; + + /* Deallocate lun memory and locks */ + xide_unalloc_lun(li,lock_to_unlock); + SCSI_HWG_UNLOCK(); + return 1; + } + else { + cmn_err(CE_WARN,"Attempt to remove li 0x"IDE_PTR" with RefCount != 0\n",li); + SCSI_HWG_UNLOCK(); + return 0; + } +} +static void xide_remove_target(xide_TargInfo_t *ti) +{ + xide_ProtoInfo_t *pi; + + pi = ti->ProtoInfo; + +#ifndef XSCSI + if (scsi_targ_vertex_remove(ti->ProtoVhdl,ti->Number) == GRAPH_VERTEX_NONE) { + IDE_DBG(3,"xide_remove_target() :scsi_targ_vertex_remove() returned 'GRAPH_VERTEX_NONE' \n"); + } +#else + scsi_targ_vertex_remove(ti->ProtoVhdl,ti->Number); + IDE_DBG(3,"xide_remove_target() :scsi_targ_vertex_remove() returned 'GRAPH_VERTEX_NONE' \n"); +#endif + + IDE_ASSERT(pi->PtrToTarg[ti->Number] != NULL); + pi->PtrToTarg[ti->Number] = NULL; + pi->device_conf[ti->Number] = 0; + + IDE_KMEM_FREE(ti,sizeof(*ti)); + + return; +} +#endif + +int xide_dump(vertex_hdl_t proto_vhdl) +{ + IDE_DBG(1,"xide_dump (proto__vhdl 0x"IDE_PTR")\n",proto_vhdl); + return 0; +} + + +/* + * get the pointer to host adapter info given the + * vertex handle of the vertex corr. to the + * controller + */ +static xide_ProtoInfo_t * +xide_proto_info_proto_get(vertex_hdl_t proto_vhdl) +{ + scsi_ctlr_info_t *proto_info; + + if (proto_vhdl == GRAPH_VERTEX_NONE) + return NULL; + proto_info = scsi_ctlr_info_get(proto_vhdl); + IDE_ASSERT(proto_info); + return(SCI_INFO(proto_info)); +} + +int xide_ioctl(vertex_hdl_t proto_vhdl, uint cmd, struct scsi_ha_op *op) +{ + int rval; + xide_ProtoInfo_t *pi; + + IDE_DBG(3,"Insxide xide_ioctl() : cmd 0x%x\n",cmd); + + switch(cmd) { + + case SOP_RESET: + pi = xide_proto_info_proto_get(proto_vhdl); + IDE_DBG(1,"SOP_RESET pi 0x"IDE_PTR"\n",pi); + xide_probe(pi); + rval = 0; + break; + + case SOP_SCAN: + rval = 0; + pi = xide_proto_info_proto_get(proto_vhdl); + IDE_DBG(1,"SOP_SCAN pi 0x"IDE_PTR"\n",pi); + xide_probe(pi); + break; + + case SOP_BLKSZ: + { + int read; + scsi_atapi_args_t *atapi_args; + vertex_hdl_t dev_vhdl; + xide_LunInfo_t *li; + scsi_lun_info_t *lun_info; + + IDE_DBG(3,"SOP_BLKSZ\n"); + atapi_args = (scsi_atapi_args_t *)op; + read = atapi_args->read; + dev_vhdl = atapi_args->lun_vhdl; + lun_info = scsi_lun_info_get(dev_vhdl); + if (lun_info == NULL) + return -1; + li = SLI_INFO(lun_info); + if (!li) { + rval = -1; + return rval; + } + rval = 0; + if (read) { + if (li->BlockSizeValid == 0) { + if (li->CapDataValid) { + li->BlockSize = li->CapBlockSize; + li->BlockSizeValid = 1; + atapi_args->blksize = li->BlockSize; + } + else { /* CapDataValid is 0 */ + u_char cap_data[8]; + u_char *cd_p; + sema_t *sema; + scsi_request_t *cap_req; + + + sema = kern_calloc(1, sizeof(sema_t)); + init_sema(sema, 0, "xide_cap", li->Number); + cd_p = &cap_data[0]; + cap_req = xide_get_capacity(li, NULL, cd_p); + cap_req->sr_dev = sema; + cap_req->sr_notify = xide_done; + cap_req->sr_spare = 0; + xide_command(cap_req); + psema(sema, PRIBIO); + + if ((cap_req->sr_status == SC_GOOD) && + (cap_req->sr_scsi_status == ST_GOOD)) { + bcopy(cd_p, &li->CapNumOfBlocks, 8); + li->BlockSize = li->CapBlockSize; + li->BlockSizeValid = 1; + atapi_args->blksize = li->BlockSize; + } + else + rval = -1; + + xide_capacity_done(cap_req); + freesema(sema); + kern_free(sema); + } /* end of capDataValid = 0 */ + } /* end of BlockSizeValid = 0 */ + + else /* BlockSizeValid == 1, so return the value */ + atapi_args->blksize = li->BlockSize; + } + else { /* if write, then just set it */ + li->BlockSize = atapi_args->blksize; + } + break; + } + + default: + IDE_DBG(3,"xide_ioctl() : Unimplemented IOCTL call\n"); + rval = -1; + } + + return rval; +} + + +void xide_WatchdogTimer(xide_ProtoInfo_t *pi) +{ + xide_TargInfo_t *ti=NULL; + xide_LunInfo_t *li=NULL; + xide_CmdObj_t *co=NULL; + xide_CmdObj_t *next_co=NULL; + int i=0; + + if (pi!= NULL) { + for(i=0;i<2;i++) { + ti = pi->PtrToTarg[i]; + if (ti!=NULL) { + li = ti->PtrToLun[0]; + if (li!= NULL) { + IOLOCK(li->LunLock, li->LunSpl); + co = li->CmdObjTail; + while (co!= NULL) { + next_co = co->Next; + if (co->TimeOutTime < lbolt) { + + IDE_DBG(1,"BEFORE xide_intr_clear() from li 0x"IDE_PTR"\n | co 0x"IDE_PTR"",li,co); +#if IDE_CMD_DEBUG + bcopy(co->SentReq->sr_command, xide_cmd_list[xide_cmd_index].command,co->SentReq->sr_cmdlen); + xide_cmd_list[xide_cmd_index].request = co->SentReq; + xide_cmd_list[xide_cmd_index].action = IDE_CMD_WATCH; + nanotime(&(xide_cmd_list[xide_cmd_index].Time)); + xide_cmd_index++; + if (xide_cmd_index > IDE_CMD_IDX_SZ) { + xide_cmd_wrap = 1; + xide_cmd_index = 0; + } +#endif +// IOUNLOCK(li->LunLock, li->LunSpl); + IDE_DBG(0,"xscsi/ide:: Request 0x"IDE_PTR" with Command \n",co->SentReq); + { + int cmdlen=0; + for (cmdlen=0;cmdlen<12;cmdlen++) { + IDE_DBG(0,"xscsi/ide:[%d] 0x%x ",cmdlen,co->CmdBlk[cmdlen]); + } + } + IDE_DBG(0,"xscsi/ide: in ide_Watchdog_timer() : Please check Drive/Card \n"); + // IDE_ASSERT(0); + { + int count=3; + do { + xide_delay(HZ/30); + count--; + } while ((xide_poll_ioc4(pi)&& (count))); + if (count) goto end; + } +// IDE_ASSERT(0); +// if (!xide_poll_ioc4(pi)) { +// IDE_DBG(0,"xscsi/ide:: Watchdog(): xide_poll_ioc4 served the interrupt \n"); +// goto end; +// } + IOLOCK(pi->CommandLock, pi->CommandLockSpl); + xide_intr_clear(pi); + IDE_DBG(1,"After xide_intr_clear \n"); + xide_pktDMA_complete(pi); + IDE_DBG(1,"After xide_pkt_DMA_COmplete\n"); +// pi->State = HHR; + IOLOCK(pi->IntrLock, pi->IntrLockSpl); + pi->intr_set = 0; + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); + xide_device_reset(pi); + xide_bus_reset(pi); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + IDE_DBG(1,"xide_WatchdogTimer() : xide bus reset done\n"); + + if (co->ReqSense) { + if (co->ReqSense == co->SentReq) { + IDE_DBG(1,"Request Sense Cmd in DOG()\n",co->ReqSense); + // IDE_ASSERT(0); + } + (*(co->SentReq->sr_notify))(co->SentReq); + co->SentReq = NULL; + co->ReqSense = NULL; + } + co->OrigReq->sr_status = SC_CMDTIME; + dki_dcache_inval(co->OrigReq->sr_buffer, co->OrigReq->sr_buflen); + co->OrigReq->sr_resid = co->OrigReq->sr_buflen; + xide_return_lun_cmds(li,SC_CMDTIME); +end: IDE_DBG(1,"AFTER xide_return_lun_cmds() from li 0x"IDE_PTR"\n",li); +// co->request_stage = CMD_COMPLETE; +// xide_complete_a_req(li,co->OrigReq); +// xide_remove_co(co); +// xide_return_co_resources(co); +// xide_test_co_for_free(co); + } + co = next_co; + } + IOUNLOCK(li->LunLock, li->LunSpl); + } + } + } + if ((pi->FinishedQHead)||(pi->FinishedQTail)) { + IDE_DBG(1,"DOG() : Calling xide_return_finished_req()\n"); + xide_return_finished_req(pi); + } + } + itimeout(xide_WatchdogTimer, xide_proto_list, WATCHDOG_TIME, TIMEOUT_SPL); +} + + +/*****************************************************************/ +/* Converts SCSI Commands from dksc or ds to their xide form */ +/* Used by IDE-ATA Hard Disks */ +/*****************************************************************/ + +/* Copied from Seagate Manual */ +typedef struct ata_scsi_inquiry_s { + u_int8_t qualifier:2, /* Byte 0 | Bits 7-6 */ + device_type:6; /* Byte 0 | Bits 5-0 */ + uint8_t RMB,ptes_to_fill:1, /* Byte 1 | Bit 7 : Removable Media Bit */ + resv1:7; /* Byte 1 : Bit 6 - 0 : Reserved */ + uint8_t resv2_5:5, /* Byte 2 : Bit 7-3 : Reserved */ + ansi_version:3; /* Byte 2 : Bit 2-0 : ANSI Version */ + uint8_t aenc:1, /* Byte 3 : Bit 7 */ + trmiop:1, + naca:1, + hisupport:1, + inq_data_format:4; + uint8_t additional_len; /* Byte 4 */ + uint8_t resv5; /* Byte 5 */ + uint8_t bque:1, /* Byte 6 : Bit 7 */ + encser:1, + port:1, + dual_p:1, + resv6_4:4; + uint8_t reladr:1, /* Byte 7 */ + resv7_3:3, + linked:1, + trndis:1, + cmd_que:1, + soft_rst:1; + uint8_t vendor_id[8]; /* Bytes 8 - 15 */ + uint8_t product_id[16]; /* Bytes 16 - 31 */ + uint8_t product_rev[4]; /* Bytes 32 - 35 */ + uint8_t serial_no[8]; /* Bytes 36 - 43 */ +} ata_scsi_inquiry_t; + +int scsi_to_ata(scsi_request_t *req, command_regs_t *cmdblk) +{ + xide_LunInfo_t *li=NULL; + xide_ProtoInfo_t *pi=NULL; + xide_TargInfo_t *ti=NULL; + scsi_lun_info_t *lun_info; + xide_CmdObj_t *co=NULL; + int result; + + lun_info = scsi_lun_info_get(req->sr_lun_vhdl); + li = SLI_INFO(lun_info); + IDE_ASSERT (li != NULL); + pi = li->ProtoInfo; + ti = li->TargInfo; + + co = (xide_CmdObj_t *)req->sr_spare; + if (co->Offset_Flag & IDE_START_TRANSFER) { + co->start_Pte = co->Pte; + co->start_PtePciAddr = co->PtePciAddr; + } + + result = xide_ata_remap_sg(co); + if (result == -1) { + IDE_DBG(1,"scsi_to_ata() normal request \n"); + co->Offset_Flag=0; + } + if (result > 0) { + IDE_DBG(1,"scsi_to_ata() Special request \n"); + } + if (result == 0) { + IDE_DBG(1,"scsi_to_ata() Special request Complete\n"); + return ATA_SPECIAL_CMD_COMPLETE; + } + + + if (req->sr_command[0] == READ_6) { + uint32_t lba; + lba = (uint32_t)(((req->sr_command[1]&0x0F)<<16)| + ((req->sr_command[2]&0xFF)<<8)| + (req->sr_command[3])); + IDE_DBG(6,"scsi_to_ata() :READ: lba 0x%x \n",lba); + cmdblk->err_feature=0; + cmdblk->count = req->sr_command[4]; + cmdblk->drive = (ti->Number << 4)|LBA_SET; + cmdblk->cyl_msb = (uint8_t) ((lba & 0x00ff0000) >> 16); + cmdblk->cyl_lsb = (uint8_t) ((lba & 0x0000ff00) >> 8); + cmdblk->sector = (uint8_t) (lba & 0x000000ff) ; + // cmdblk->command = 0xC4; + cmdblk->command = 0xC8; + return ATA_CMD_SEND; + } + + if (req->sr_command[0] == READ_EXTENDED) { + uint32_t lba,transfer_len; + +// lba = (uint32_t)((req->sr_command[2]<<24)| +// (req->sr_command[3]<<16)| +// (req->sr_command[4]<<8)| +// (req->sr_command[5])); + lba = (uint32_t)((co->CmdBlk[2]<<24)| + (co->CmdBlk[3]<<16)| + (co->CmdBlk[4]<<8)| + (co->CmdBlk[5])); + +// transfer_len = (req->sr_command[7]<<8)|(req->sr_command[8]); + transfer_len = (co->CmdBlk[7]<<8)|(co->CmdBlk[8]); + IDE_DBG(6,"scsi_to_ata() :READ_X: lba 0x%x | len 0x%x\n",lba,transfer_len); + + if (transfer_len > 256) { + IDE_DBG(1,"scsi_to_ata(): Read Data Length > 256 Blocks ...Unsupported \n"); + IDE_ASSERT(0); + return ATA_CMD_UNSUPPORTED; + } + + cmdblk->err_feature=0; +// cmdblk->count = req->sr_command[8]; +// cmdblk->sector = req->sr_command[5]; +// cmdblk->cyl_lsb = req->sr_command[4]; +// cmdblk->cyl_msb = req->sr_command[3]; +// cmdblk->drive = (ti->Number << 4) | LBA_SET | req->sr_command[2]; + + cmdblk->count = co->CmdBlk[8]; + cmdblk->sector = co->CmdBlk[5]; + cmdblk->cyl_lsb = co->CmdBlk[4]; + cmdblk->cyl_msb = co->CmdBlk[3]; + cmdblk->drive = (ti->Number << 4) | LBA_SET | co->CmdBlk[2]; + cmdblk->command = 0xC8; + IDE_DBG(15,"scsi_to_ata()RD:drive 0x%x | ef 0x%x | count 0x%x | sector 0x%x \ + | lsb 0x%x msb 0x%x | cmd 0x%x \n",cmdblk->drive,cmdblk->err_feature, + cmdblk->count,cmdblk->sector,cmdblk->cyl_lsb,cmdblk->cyl_msb, + cmdblk->command); + return ATA_CMD_SEND; + } + + if (req->sr_command[0] == WRITE_6) { + uint32_t lba; + lba = (uint32_t)(((req->sr_command[1]&0x0F)<<16)| + ((req->sr_command[2]&0xFF)<<8)| + (req->sr_command[3])); + IDE_DBG(6,"scsi_to_ata() :WRITE: lba 0x%x \n",lba); + cmdblk->err_feature=0; + cmdblk->count = req->sr_command[4]; + cmdblk->drive = (ti->Number << 4)|LBA_SET; + cmdblk->cyl_msb = (uint8_t) ((lba & 0x00ff0000) >> 16); + cmdblk->cyl_lsb = (uint8_t) ((lba & 0x0000ff00) >> 8); + cmdblk->sector = (uint8_t) (lba & 0x000000ff) ; + cmdblk->command = 0xCA; + return ATA_CMD_SEND; + } + + if (req->sr_command[0] == WRITE_EXTENDED) { + uint32_t lba,transfer_len; + +// lba = (uint32_t)((req->sr_command[2]<<24)| +// (req->sr_command[3]<<16)| +// (req->sr_command[4]<<8)| +// (req->sr_command[5])); + lba = (uint32_t)((co->CmdBlk[2]<<24)| + (co->CmdBlk[3]<<16)| + (co->CmdBlk[4]<<8)| + (co->CmdBlk[5])); + +// transfer_len = (req->sr_command[7]<<8)|(req->sr_command[8]); + transfer_len = (co->CmdBlk[7]<<8)|(co->CmdBlk[8]); + IDE_DBG(6,"scsi_to_ata() :WRITE_X: lba 0x%x | len 0x%x\n",lba,transfer_len); + + if (transfer_len > 256) { + IDE_DBG(1,"Write Data Length > 256 Blocks ...Unsupported \n"); + IDE_ASSERT(0); + return ATA_CMD_UNSUPPORTED; + } + + cmdblk->err_feature=0; +// cmdblk->count = req->sr_command[8]; +// cmdblk->sector = req->sr_command[5]; +// cmdblk->cyl_lsb = req->sr_command[4]; +// cmdblk->cyl_msb = req->sr_command[3]; +// cmdblk->drive = (ti->Number << 4) | LBA_SET | req->sr_command[2]; + + cmdblk->count = co->CmdBlk[8]; + cmdblk->sector = co->CmdBlk[5]; + cmdblk->cyl_lsb = co->CmdBlk[4]; + cmdblk->cyl_msb = co->CmdBlk[3]; + cmdblk->drive = (ti->Number << 4) | LBA_SET | co->CmdBlk[2]; + cmdblk->command = 0xCA; + + IDE_DBG(13,"scsi_to_ata()WR:drive 0x%x | ef 0x%x | count 0x%x | sector 0x%x \ + | lsb 0x%x msb 0x%x | cmd 0x%x \n",cmdblk->drive,cmdblk->err_feature, + cmdblk->count,cmdblk->sector,cmdblk->cyl_lsb,cmdblk->cyl_msb, + cmdblk->command); + return ATA_CMD_SEND; + } + + if ((req->sr_command[0] == MODESELECT_6)|| + (req->sr_command[0] == MODESELECT_10) || + (req->sr_command[0] == INQUIRY) || + (req->sr_command[0] == READCAPACITY) || + (req->sr_command[0] == TESTUNITREADY) || +// (req->sr_command[0] == REQUEST_SENSE) || + (req->sr_command[0] == MODESENSE_6) || + (req->sr_command[0] == MODESENSE_10)) { + ata_fake_scsi_cmd(req); + return ATA_CMD_FAKE; + } + + return ATA_CMD_UNSUPPORTED; +} + +static void ata_fake_scsi_cmd(scsi_request_t *req) +{ + xide_LunInfo_t *li=NULL; + xide_ProtoInfo_t *pi=NULL; + xide_TargInfo_t *ti=NULL; + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(req->sr_lun_vhdl); + li = SLI_INFO(lun_info); + IDE_ASSERT (li != NULL); + pi = li->ProtoInfo; + ti = li->TargInfo; + + if (req->sr_command[0] == READCAPACITY) { + uint32_t block_size = 512; + + if (req->sr_buffer > 0) { + req->sr_buffer[0] = (uint8_t)(li->xidentifyDev->usr_sect[1] >>8); + req->sr_buffer[1] = (uint8_t)(li->xidentifyDev->usr_sect[1]); + req->sr_buffer[2] = (uint8_t)(li->xidentifyDev->usr_sect[0] >>8); + req->sr_buffer[3] = (uint8_t)(li->xidentifyDev->usr_sect[0] & 0x00FF) - 1; + req->sr_buffer[4] = (uint8_t)(block_size >>24); + req->sr_buffer[5] = (uint8_t)(block_size >>16); + req->sr_buffer[6] = (uint8_t)(block_size >>8); + req->sr_buffer[7] = (uint8_t)(block_size ); +// { +// int tp; +// IDE_DBG(1,"ata_fake: Read Capacity : "); +// for (tp=0;tp<8;tp++) { +// IDE_DBG(1,"[%d] 0x%x | ",tp,req->sr_buffer[tp]); +// } +// IDE_DBG(1,"\n"); +// } + } + req->sr_status = 0; + req->sr_scsi_status = 0; + req->sr_resid = 0; + } + + if ((req->sr_command[0] == MODESELECT_6)|| + (req->sr_command[0] == MODESELECT_10)) { + /* Watch for Block Size changes */ + req->sr_status = 0; + req->sr_scsi_status = 0; + req->sr_resid = 0; + } + + /* MSense_10 not yet coded 11/19/2001*/ + if (req->sr_command[0] == MODESENSE_6) { + if (req->sr_buflen == 12) { + uint32_t block_size = 512; + + if (req->sr_buffer > 0) { + req->sr_buffer[0] = 11; /* Sense Data Length */ + req->sr_buffer[1] = 0; + req->sr_buffer[2] = 0; + req->sr_buffer[3] = 8; + + req->sr_buffer[4] = (uint8_t)((li->xidentifyDev->usr_sect[1] & 0xFF00)>>8); + req->sr_buffer[5] = (uint8_t)(li->xidentifyDev->usr_sect[1] & 0x00FF); + req->sr_buffer[6] = (uint8_t)((li->xidentifyDev->usr_sect[0] & 0xFF00)>>8); + req->sr_buffer[7] = (uint8_t)(li->xidentifyDev->usr_sect[0] & 0x00FF); + req->sr_buffer[8] = (uint8_t)((block_size & 0xFF000000)>>24); + req->sr_buffer[9] = (uint8_t)((block_size & 0x00FF0000)>>16); + req->sr_buffer[10] = (uint8_t)((block_size & 0x0000FF00)>>8); + req->sr_buffer[11] = (uint8_t)(block_size & 0x000000FF); + } + } + req->sr_status = 0; + req->sr_scsi_status = 0; + req->sr_resid = 0; + } + + if (req->sr_command[0] == INQUIRY) { + /* Put in the Inquiry Faking Stuff from li->xidentifyDev */ + ata_scsi_inquiry_t *ata_inq; + + IDE_KMEM_ZALLOC(ata_inq,sizeof(ata_scsi_inquiry_t),KM_CACHEALIGN); + + ata_inq->qualifier = 0 ; /* Hard Disk */ + ata_inq->device_type = 0 ; /* Magnetic Device */ + ata_inq->RMB = 0; + ata_inq->resv1 = 0; + ata_inq->resv2_5 = 0; + ata_inq->ansi_version = 2; + ata_inq->aenc = 0; + ata_inq->trmiop = 0; + ata_inq->naca = 0; + ata_inq->hisupport = 0; + ata_inq->inq_data_format = 2; + ata_inq->additional_len = 0; + ata_inq->resv5 = 0; + ata_inq->bque=0; + ata_inq->encser = 0; + ata_inq->port = 0; + ata_inq->dual_p = 0; + ata_inq->resv6_4 = 0; + ata_inq->reladr =0; + ata_inq->resv7_3 =0; + ata_inq->linked =0; + ata_inq->trndis = 0; + ata_inq->cmd_que= li->xidentifyDev->cmd_queue; + ata_inq->soft_rst=li->xidentifyDev->softreset; + bcopy(li->xidentifyDev->serial_no,ata_inq->vendor_id,8); + bcopy(li->xidentifyDev->model_no,ata_inq->product_id,16); + bcopy(li->xidentifyDev->firmware_rev,ata_inq->product_rev,4); + bcopy(li->xidentifyDev->serial_no+8,ata_inq->serial_no,8); + if (req->sr_buffer >0) { + bcopy(ata_inq,req->sr_buffer,sizeof(ata_scsi_inquiry_t)); + } + req->sr_buflen=sizeof(ata_scsi_inquiry_t); + req->sr_status = 0; + req->sr_scsi_status = 0; + req->sr_resid = 0; + + IDE_KMEM_FREE(ata_inq,sizeof(ata_scsi_inquiry_t)); + } + +// if ((req->sr_command[0] == REQUEST_SENSE)|| + if (req->sr_command[0] == TESTUNITREADY) { + req->sr_sensegotten = 0; + req->sr_resid = 0; + req->sr_status = 0; + } + + +} + +void xide_putb(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset, uint8_t value) +{ + if (pi->vendorid == PCI_VENDOR_SGI) { + PCI_OUTW((uintptr_t)(addr+(offset<<2)),value); + IDE_DBG(24,"addr 0x"IDE_PTR" , value 0x%x \n",(uintptr_t)(addr+(offset<<2)),value); + } + else { +#ifdef XSCSI + PCI_OUTB(((uintptr_t)(addr+offset)),value); +#else + PCI_OUTB(((uintptr_t)((addr+offset))^3),value); +#endif + } +} + +void xide_putw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset, uint16_t value) +{ + if (pi->vendorid == PCI_VENDOR_SGI) { + PCI_OUTW((uintptr_t)(addr+(offset<<2)),value); + IDE_DBG(24,"addr 0x"IDE_PTR" , value 0x%x \n",(uintptr_t)(addr+(offset<<2)),value); + } + else { +#ifdef XSCSI + PCI_OUTH(((uintptr_t)(addr+offset)),value); +#else + PCI_OUTH(((uintptr_t)((addr+offset))^2),value); +#endif + } +} + +void xide_putdw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset, uint32_t value) +{ + if (pi->vendorid == PCI_VENDOR_SGI) { + PCI_OUTW((uintptr_t)(addr+(offset<<2)),value); + IDE_DBG(12,"xide_putdw : addr 0x"IDE_PTR" val 0x%x \n",(uintptr_t)(addr+(offset<<2)),value); + } + else { + PCI_OUTW((uintptr_t)((addr+offset)),value); + } +} + +uint8_t xide_getb(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset) +{ + if (pi->vendorid == PCI_VENDOR_SGI) { +// IDE_DBG(3,"getb() addr 0x"IDE_PTR" \n",(uintptr_t)(addr+(offset<<2))); + return ((uint8_t)PCI_INW((uintptr_t)(addr+(offset<<2)))); + } + else { +#ifdef XSCSI + return(PCI_INB(((uintptr_t)(addr+offset)))); +#else + return(PCI_INB(((uintptr_t)((addr+offset))^3))); +#endif + } +} + + +uint16_t xide_getw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset) +{ + if (pi->vendorid == PCI_VENDOR_SGI) { + IDE_DBG(113,"getw() addr 0x"IDE_PTR" \n",(uintptr_t)(addr+(offset<<2))); + return ((uint16_t)PCI_INW((uintptr_t)(addr+(offset<<2)))); + } + else { +#ifdef XSCSI + return(PCI_INH(((uintptr_t)(addr+offset)))); +#else + return(PCI_INH(((uintptr_t)((addr+offset))^2))); +#endif + } +} + + +uint32_t xide_getdw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset) +{ + if (pi->vendorid == PCI_VENDOR_SGI) { + IDE_DBG(3,"getdw() addr 0x"IDE_PTR" \n",(uintptr_t)(addr+(offset<<2))); + return ((uint32_t)PCI_INW((uintptr_t)(addr+(offset<<2)))); + } + else { + return(PCI_INW((uintptr_t)(addr+offset))); + } +} + +#ifdef XSCSI + +const struct pci_device_id __devinitdata xide_id_table[] = +{ +// { CMD_VENDOR_ID, CMD_DEV_ID, PCI_ANY_ID, PCI_ANY_ID, 0x010400, 0xFFFFFF, 0 }, + { 0x1095, 0x649, PCI_ANY_ID, PCI_ANY_ID, 0x010400, 0xFFFFFF, 0 }, +// { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0x0, 0xFFFFFF, 0 }, + { PCI_VENDOR_SGI, IOC4_PCI_ID, PCI_ANY_ID, PCI_ANY_ID, 0x0b4000, 0xFFFFFF, 0 }, + { 0, 0, 0, 0, 0, 0, 0 } +}; + +struct pci_driver xide_driver = +{ + name: "IDE", + id_table: xide_id_table, + probe: xide_attach, +}; + +//--------------- For newly added linux functions --------------------------- +int __init xide_detect(void) +{ + int rc = 0; + + INITLOCK(&xide_connect_sema, "xideconnect", 0); +// IDE_ASSERT(0); + rc = pci_register_driver(&xide_driver); + if (rc < 0) { + IDE_DBG(11,"xide_detect(): Error in registering driver : rc = %d\n",rc); + } else { + IDE_DBG(11,"xide_detect() : %d IDE Cards found \n",rc); +// BUG(); +// INITLOCK(&xide_connect_sema, "xideconnect", 0); + } + + return 0; +} +module_init(xide_detect); + +void xide_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused) +{ + xide_ProtoInfo_t *pi = (xide_ProtoInfo_t *)dev_id; + +#ifndef CONFIG_IA64_SGI_SN + disable_irq_nosync(irq); + IDE_DBG(11,"Disabled IRQ in IDE irq handler\n"); +#endif + up(&pi->intr_q); +} + +int xide_intr_thread(void *ptr) +{ + + xide_ProtoInfo_t *pi = (xide_ProtoInfo_t *) ptr; + int num=0; + + atomic_inc(&xide_intrthreadcount); + + siginitsetinv(¤t->blocked, 0); + lock_kernel(); + daemonize(); + sprintf(current->comm,"%s_Intr",pi->HwgName); + unlock_kernel(); + +// intrthread_running = 1; +// Need a variable so that this thread can exit in cleanup_module() + + while(1) { + down_interruptible(&pi->intr_q); + IDE_DBG(4,"xide_intrthread: Interrupt Asserted %d times as yet\n",num); + if (xide_unload_cmd_pending == 1) break; + xide_intr(pi); +#ifndef CONFIG_IA64_SGI_SN + enable_irq(pi->PciVhdl->irq); +#endif + num++; + }; + + atomic_dec(&xide_intrthreadcount); + RETURN_FROM_THREAD(); +} + +int xide_intr_watch_thread(void *ptr) +{ + xide_ProtoInfo_t *pi = (xide_ProtoInfo_t *) ptr; + + atomic_inc(&xide_intr_watch_threadcount); + siginitsetinv(¤t->blocked, 0); + lock_kernel(); + daemonize(); + sprintf(current->comm,"%s_Intr_Wt",pi->HwgName); + unlock_kernel(); + + while (1) { + down_interruptible(&pi->intr_watch_q); +// if (xide_unload_cmd_pending == 1) break; + do { + xide_delay(HZ/30); + } while (xide_poll_ioc4(pi)); +#ifndef CONFIG_IA64_SGI_SN + enable_irq(pi->PciVhdl->irq); +#endif + }; + atomic_dec(&xide_intr_watch_threadcount); + RETURN_FROM_THREAD(); + +} + + +#endif + +static void xide_co_free_dmamap(xide_CmdObj_t *co) +{ + xide_ProtoInfo_t *pi=co->li->ProtoInfo; + if (co->PciAlenList != NULL) { + IDE_DBG(1,"xide_co_free_dmamap(): co->pciAlenlist != NULL \n"); +#ifdef XSCSI +#ifdef CONFIG_IA64_SGI_SN + { + int i; + int npgs; + xide_std_PageTblEntry_t *sgmap32=NULL; + xide_ioc4_PageTblEntry_t *sgmap64=NULL; + + npgs = co->NumPtes; + + if (pi->vendorid == CMD_VENDOR_ID) { + sgmap32 = (xide_std_PageTblEntry_t *)co->Pte; + } + else if (pi->vendorid == PCI_VENDOR_SGI) { + sgmap64 = (xide_ioc4_PageTblEntry_t *)co->Pte; + } + + if (npgs != alenlist_size(co->PciAlenList)) { + IDE_DBG(0,"xscsi/ide:xide_free_dmamap: npgs %d | alenlist_size(co->PciAlenList) %d\n",npgs,alenlist_size(co->PciAlenList)); + IDE_ASSERT(npgs == alenlist_size(co->PciAlenList)); + } + + for (i = 0; i < npgs; i++) { + if (pi->vendorid == CMD_VENDOR_ID) { + IDE_DBG(11,"sgmap32 0x"IDE_PTR" | Addr 0x%x | Len 0x%x \n",sgmap32,sgmap32->Adr,sgmap32->EOT_Resv_Len); + swab64_32((uint64_t *)sgmap32); + IDE_DBG(11,"sgmap32 0x"IDE_PTR" | Addr 0x%x | Len 0x%x \n",sgmap32,sgmap32->Adr,sgmap32->EOT_Resv_Len); + if ((xide_mapped[xide_map_out] != sgmap32->Adr)) { + IDE_DBG(0,"xscsi/ide:xide_free_dmamap(): xide_mapped out [%d] 0x%x [in %d] 0x%x| sgmap32->Adr 0x%x \n",xide_map_out,xide_mapped[xide_map_out],xide_map_in,xide_mapped[xide_map_in],sgmap32->Adr); + } +// IDE_ASSERT(xide_mapped[xide_map_out] == (alenaddr_t)sgmap32->Adr); + pci_unmap_single(pi->PciVhdl, sgmap32->Adr, sgmap32->EOT_Resv_Len, PCI_DMA_BIDIRECTIONAL); + IDE_DBG(1,"pci_unmap_single: vhdl 0x"IDE_PTR" | sgmap32->addr 0x"IDE_PTR" | sgmap32->EOT_Resv_Len 0x%x | flags 0x%x \n",pi->PciVhdl, sgmap32->Adr, sgmap32->EOT_Resv_Len, PCI_DMA_BIDIRECTIONAL); + xide_map_out++; + if (xide_map_out > 255) xide_map_out = 0; + sgmap32++; + } else if (pi->vendorid == PCI_VENDOR_SGI ) { + sgmap64->EOT_Resv_Len = sgmap64->EOT_Resv_Len & 0x1FFFF; + pci_unmap_single(pi->PciVhdl, sgmap64->Adr, sgmap64->EOT_Resv_Len, PCI_DMA_BIDIRECTIONAL); + IDE_DBG(1,"pci_unmap_single: vhdl 0x"IDE_PTR" | sgmap64->addr 0x"IDE_PTR" | sgmap64->EOT_Resv_Len 0x%x | flags 0x%x \n",pi->PciVhdl, sgmap64->Adr, sgmap64->EOT_Resv_Len, PCI_DMA_BIDIRECTIONAL); + if (xide_mapped[xide_map_out] != sgmap64->Adr) { + IDE_DBG(1,"xide_free_dmamap(): xide_mapped out [%d] 0x%x [in %d] 0x%x| sgmap64->Adr 0x%x \n",xide_map_out,xide_mapped[xide_map_out],xide_map_in,xide_mapped[xide_map_in],sgmap64->Adr); + // IDE_ASSERT(xide_mapped[xide_map_out] == (alenaddr_t)sgmap64->Adr); + } + xide_map_out++; + if (xide_map_out > 255) xide_map_out = 0; + sgmap64++; + } + } + } +#endif +#endif + if (co->PciAlenList != co->AlenList) alenlist_done(co->PciAlenList); + } + co->PciAlenList = NULL; + +} + + +static int xide_get_status(xide_ProtoInfo_t *pi,uint8_t *status, int timeout_secs) +{ + int count=0; + long delay_ticks=timeout_secs*HZ/100; + + for (*status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND); ((*status & IDE_S_BUSY) && (count < 100)); count++) + { + IDE_DBG(11,"xide_get_status : status 0x%x \n",*status); + xide_delay(delay_ticks); + *status = IDE_INB(pi,pi->cmdblk,IDE_COMMAND); + } + + if (*status & IDE_S_BUSY) { + return 1; // Means device didnt return status correctly + } + else { + return 0; + } +} + +static int xide_poll_ioc4(xide_ProtoInfo_t *pi) +{ + IOLOCK(pi->IntrLock, pi->IntrLockSpl); + if (pi->intr_set) { + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); + if (pi->vendorid == PCI_VENDOR_SGI) { + uint8_t intr_reg; + IOLOCK(pi->CommandLock, pi->CommandLockSpl); + IDE_DBG(1,"Polling : insxide lock \n"); + intr_reg = IDE_INB(pi,pi->intrblk,IOC4_INTR_REG); + IOUNLOCK(pi->CommandLock, pi->CommandLockSpl); + if (intr_reg & 0x3) { + IDE_DBG(1,"xide_poll_ioc4: interrupt from IDE device\n"); + IOLOCK(pi->IntrLock, pi->IntrLockSpl); + if (pi->intr_seen) { + pi->intr_seen=0; + IDE_DBG(1,"xide_poll_ioc4: intr_seen: %d\n",pi->intr_seen); + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); +#ifdef XSCSI + sn_dma_sync(pi->PciVhdl); + up(&pi->intr_q); +#else + xide_intr(pi); +#endif + return 0; + + } else { + pi->intr_seen=1; + IDE_DBG(1,"xide_poll_ioc4: intr_seen[]: %d\n",pi->intr_seen); + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); + return 1; + } + } + else { + IDE_DBG(111,"xide_poll_ioc4: No IDE interrupt \n"); + return 1; + } + } + } + IOUNLOCK(pi->IntrLock, pi->IntrLockSpl); + return 1; +} +//----------------------End --------------------------------------------------- + + + diff -Nur linux-2.4.19/drivers/xscsi/ide.h linux-2.4.19-sgi211r3/drivers/xscsi/ide.h --- linux-2.4.19/drivers/xscsi/ide.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/ide.h Wed Jan 15 11:27:48 2003 @@ -0,0 +1,1123 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifndef __IDE_H_ +#define __IDE_H_ + +#ifdef XSCSI + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#else +#include "sys/types.h" +#include "sys/ksynch.h" +#include "sys/poll.h" +#include "sys/ddi.h" +#include "sys/param.h" +#include "sys/systm.h" +#include "sys/edt.h" +#include "sys/sysmacros.h" +#include "sys/cmn_err.h" +#include "sys/debug.h" +#include "sys/kmem.h" +#include "sys/mman.h" +#include "ksys/ddmap.h" +#include "sys/errno.h" +#include "sys/immu.h" +#include "sys/invent.h" +#include "sys/kopt.h" +#include "sys/mbuf.h" +#include "sys/sbd.h" +#include "sys/socket.h" +#include "sys/cpu.h" +#include "sys/conf.h" +#include "sys/ddi.h" +#include "sys/mload.h" +#include "sys/cred.h" +#include "sys/pci_intf.h" +#include "sys/PCI/pciio.h" +#include "sys/PCI/PCI_defs.h" +#include "sys/ktime.h" +#include "sys/sema.h" +#include "sys/scsi.h" +#include "sys/iograph.h" +#include "ksys/xthread.h" +#include "sys/pfdat.h" +#include "sys/var.h" +#include "sys/failover.h" +#include "sys/invent.h" +#include "sys/PCI/pcibr.h" +#include "sys/alenlist.h" + +#endif + +// Starting Linux - specific declarations + +#define CMD_DEV_ID 0x649 +#define CMD_VENDOR_ID 0x1095 +#define PCI_VENDOR_ID_PROMISE 0x105a +#define PCI_DEVICE_ID_PROMISE_20265 0x0d30 +#define PCI_DEVICE_ID_PROMISE_20267 0x4d30 +#define PCI_DEVICE_ID_PROMISE_20246 0x4d33 +#define PCI_DEVICE_ID_PROMISE_20262 0x4d38 +#define PCI_DEVICE_ID_PROMISE_20268 0x4d68 +#define PCI_DEVICE_ID_PROMISE_20268R 0x6268 +#define PCI_DEVICE_ID_PROMISE_5300 0x5300 + +#ifdef XSCSI +typedef devfs_handle_t xscsi_vhdl_t; +typedef struct pci_dev *pci_hdl_t; +#define PCIIO_WRITE_GATHER 0x0 + +#define SCSI_HWG_UNLOCK() up_write(&scsi_hwgraph_lock) +typedef enum pciio_endian_e { + PCIDMA_ENDIAN_BIG, + PCIDMA_ENDIAN_LITTLE +} pciio_endian_t; + +#else +typedef vertex_hdl_t xscsi_vhdl_t; +typedef xscsi_vhdl_t pci_hdl_t; +#endif + +#define LABEL_LENGTH_MAX 256 +#define ATA_MAX_BLOCKS 256 +#define ATA_BLOCK_SIZE 512 +#define IDE_64KB_LIMIT 0xFFFF +#define IDE_CMD_DEBUG 1 + + +// Ending linux-specific declarations + +#define READCAPACITY 0x25 +#define WRITE_EXTENDED 0x2A + +#define READ_6 0x08 +#define WRITE_6 0x0A +#define READ_EXTENDED 0x28 +#define MODESELECT_6 0x15 +#define MODESELECT_10 0x55 +#define MODESENSE_6 0x1A +#define MODESENSE_10 0x5A +#define INQUIRY 0x12 +#define TESTUNITREADY 0x00 +#define REQUEST_SENSE 0x03 + +#define ATA_CMD_SEND 0x01 +#define ATA_CMD_FAKE 0x02 +#define ATA_CMD_UNSUPPORTED 0x04 +#define ATA_SPECIAL_CMD 0x10 +#define ATA_SPECIAL_CMD_COMPLETE 0x20 +#define LBA_SET 0x40 + +/* + * Used to keep track of last N commands issued. + */ +#ifdef IDE_CMD_DEBUG +typedef struct xide_cmd_dbg_s { + void *request; + u_char command[12]; + int datalength; + u_short action; + u_short code; + timespec_t Time; +} xide_cmd_dbg_t; + +#define IDE_CDBG_RCVD 0 +#define IDE_CDBG_ADD 1 +#define IDE_CDBG_RM 2 +#define IDE_CDBG_FINISH 3 +#define IDE_CDBG_DONE 4 +#define IDE_CMD_BRANCH 5 +#define IDE_CMD_SUCCESS 6 +#define IDE_CMD_ERROR 7 +#define IDE_CMD_WATCH 8 +#define IDE_CMD_SENT 9 +/* +static char *xide_cdbg_actions[] = +{ + "Received ScsiReq ", // 0 + "Add to ScsiReq ", // 1 + "Remove from ScsiReq", // 2 + "Put in FinishQ ", // 3 + "sr_notify() Called", // 4 + "Branched", // 5 + "ScsiReq successful", // 6 + "ScsiReq ERROR", // 7 + "ScsiReq ret. by Watchdog()", // 8 + "ScsiReq Sent to Device", // 9 +}; +*/ +#define IDE_CMD_IDX_SZ 256 /* 32 Cmd Debug Queue */ +#endif + +#define WATCHDOG_TIME (HZ*20) + +/* return codes */ +#define IDE_FAIL 1 +#define IDE_OK 0 + +#define IDE_ABORT -1 +#define IDE_NO_START 0 +#define IDE_STARTED 1 +#define IDE_NEED_WAIT 2 + +/* fix size of some entries */ +#define IDE_MAPSIZE 128 /* min number of page table entrys for cmd */ +#define IDE_CMD_OBJS 1 /* W75_4-0 : max number of commands outstanding - 1 */ + +/* IOC4 Specific Definitions */ +#define IOC4_CMD_OFFSET 0x100 +//#define IOC4_CTRL_OFFSET 0x118 +#define IOC4_CTRL_OFFSET 0x120 +#define IOC4_DMA_OFFSET 0x140 +#define IOC4_INTR_OFFSET 0x0 + +#define IOC4_TIMING 0x00 +#define IOC4_DMA_PTR_L 0x01 +#define IOC4_DMA_PTR_H 0x02 +#define IOC4_DMA_ADDR_L 0x03 +#define IOC4_DMA_ADDR_H 0x04 +#define IOC4_BC_DEV 0x05 +#define IOC4_BC_MEM 0x06 +#define IOC4_DMA_CTRL 0x07 +#define IOC4_DMA_END_ADDR 0x08 + +// Bits in the IOC4 Control/Status Register +#define IOC4_S_DMA_START 0x01 +#define IOC4_S_DMA_STOP 0x02 +#define IOC4_S_DMA_DIR 0x04 +#define IOC4_S_DMA_ACTIVE 0x08 +#define IOC4_S_DMA_ERROR 0x10 +#define IOC4_ATA_MEMERR 0x02 + +// Read/ Write Directions +#define IOC4_DMA_WRITE 0x04 +#define IOC4_DMA_READ 0x00 + +typedef struct xide_std_PageTblEntry { +#ifdef USE_LE32_ORDERING + uint64_t EOT_Resv_Len:32; + uint64_t Adr:32; +#else + uint64_t Adr:32; + uint64_t EOT_Resv_Len:32; +#endif +} xide_std_PageTblEntry_t; + +typedef struct xide_ioc4_PageTblEntry { + uint64_t Adr; + uint64_t EOT_Resv_Len; +} xide_ioc4_PageTblEntry_t; + + +typedef union xide_PageTblEntry { + xide_std_PageTblEntry_t xide_32b; + xide_ioc4_PageTblEntry_t sgi_ioc4; +} xide_PageTblEntry_t; +/* +typedef struct xide_PageTblEntry { + uint64_t Adr:32; + uint64_t EOT_Resv_Len:32; +} xide_PageTblEntry_t; +*/ +typedef struct xide_LunInfo_s xide_LunInfo_t; +typedef struct xide_CmdObj_s xide_CmdObj_t; + +struct xide_CmdObj_s { + /* For putting In queue */ + xide_CmdObj_t *Next; + xide_CmdObj_t *Prev; + /* DMA Stuff */ + uint8_t NoPte; + uint8_t UseBigmap; + xide_PageTblEntry_t *Pte; +// void *Pte; + uint64_t PtePciAddr; +// uint64_t DataPciAddr; + alenlist_t AlenList; /* phys adr of data */ + alenlist_t PciAlenList; /* pci adr of data */ + + /* pre-allocated map of size = IDE_MAPSIZE */ + xide_PageTblEntry_t *ReservedPte; +// void *ReservedPte; + iopaddr_t ReservedPtePciAddr; + + /* The following PTE map variables are only needed if + * the map is > IDE_MAPSIZE and BigMap is not available + */ + uint32_t AllocMapSize; /* for pte map */ + pciio_dmamap_t PteDMAMap; + iopaddr_t PteDMAMapBaseaddr; + int NumPtes; + + /* only has non NULL value if sr_buflen > 0 */ + pciio_dmamap_t DataDMAMap; + iopaddr_t DataDMAMapBaseaddr; + + /* Scsi requests linked to it */ + scsi_request_t *TempReqForFix; + scsi_request_t *HoldReq; + scsi_request_t *OrigReq; + scsi_request_t *SentReq; + + scsi_request_t *ReqSense; + + /* fix up information for device blksz != media blksize */ + u_char FixMap4BlkSz; + int MapStartLen; + int MapEndLen; + + /* timeout information */ + int TimeOut; + int StartTime; + int TimeOutTime; + + uint8_t State; + u_char CmdBlk[12]; /* Command bytes of PKT Command to be sent */ + int8_t Tag; /* Tag value of the scsi_request */ + + xide_LunInfo_t *li; /* Lun to which command is sent */ + uint8_t request_stage; + uint8_t transfer_type; + +/* New Fields to get over the 128K (256 Block) barrier */ + int offset; + xide_PageTblEntry_t *start_Pte; + xide_PageTblEntry_t *saved_Pte; + uint64_t start_PtePciAddr; + uint8_t Offset_Flag; + uint32_t Prev_Num_Blocks; +}; + +typedef struct xide_mode_sense_6_hdr_s { + u_char SenseLen; + u_char MediaType; + u_char DevSpecific; + u_char BlkDescLen; + union { + struct { + u_char NumOfBlks[4]; + u_char BlkLength[4]; + } Desc; + u_char DataNoBD[8]; + } Data; + u_char DataIfBD; +} xide_mode_sense_6_hdr_t; + +typedef struct xide_mode_sense_10_hdr_s { + u_char SenseLen[2]; + u_char MediaType; + u_char DevSpecific; + u_char Reserved[2]; + u_char BlkDescLen[2]; + union { + struct { + u_char NumOfBlks[4]; + u_char BlkLength[4]; + } Desc; + u_char DataNoBD[8]; + } Data; + u_char DataIfBD; +} xide_mode_sense_10_hdr_t; + +#define IDE_DATA 0 +#define IDE_ERR_FEATURE 1 +#define IDE_COUNT 2 +#define IDE_SECTOR 3 +#define IDE_CYL_LSB 4 +#define IDE_CYL_MSB 5 +#define IDE_DRIVE 6 +#define IDE_COMMAND 7 + +typedef volatile struct { + uint8_t data; /* Data Register : Offset 0 */ + uint8_t err_feature; /* (R) Error/ (W)Features Register : Offset 1 */ + uint8_t count; /* (W) sector count : Offset 2 */ + uint8_t sector; /* sector # : Offset 3 : LBA Low*/ + uint8_t cyl_lsb; /* cylinder# LSB : Offset 4 : LBA Mid */ + uint8_t cyl_msb; /* cylinder# MSB : Offset 5 : LBA High*/ + uint8_t drive; /* Sector/Drive/Head/Device register : Offset 6 */ + uint8_t command; /* Command/status register : Offset 7 */ +} command_regs_t; + +#define IDE_ALT_STATUS 2 +//#define IDE_ALT_STATUS 1 + +typedef volatile struct { + uint8_t resvd0; + uint8_t resvd1; + uint8_t alt_status; /* alternate registers offset */ + uint8_t resvd3; +} ctrl_regs_t; + +#define IDE_BMIDECR0 0 +#define IDE_MRDMODE 1 +#define IDE_BMIDESR0 2 +#define IDE_UDIDETCR0 3 +#define IDE_DTPR0 4 +#define IDE_BMIDECR1 8 +#define IDE_BMIDECSR 9 +#define IDE_BMIDESR1 0x0A +#define IDE_UDIDETCR1 0x0B +#define IDE_DTPR1 0x0C +#define IDE_UDMA3_4_CTRL 0x11 +#define IDE_SUB_SYSID 0x12 +#define IDE_FLASH 0x14 +#define IDE_MASTER_CTL0 0x1A +#define IDE_MASTER_CTL1 0x1B +#define IDE_SYS_CTL 0x1C +#define IDE_ATAPI_CH1 0x20 +#define IDE_ATAPI_CH2 0x24 + +typedef volatile struct { + uint8_t bmxidecr0; /* 0x70 : Bus Master Cmd Reg. for Primary Channel */ + uint8_t mrdmode; /* 0x71 : Intr Enable, Status Reg, + Master Read Select Ctrl Reg. for both channels */ + uint8_t bmxidesr0; /* 0x72 : Bus Master Status Reg. for Primary Chnl */ + uint8_t udxidetcr0;/* 0x73 : Ultra DMA Timing Ctrl Reg. for Prim. Chnl */ + uint32_t dtpr0; /* 0x74-77: Descriptor Table Ptr Reg. for Prim. Chnl */ + uint8_t bmxidecr1; /* 0x78 : Bus Master Cmd Reg. for 2ndry Channel */ + uint8_t bmxidecsr; /* 0x79 : Bus Master Ctrl Status Reg */ + uint8_t bmxidesr1; /* 0x0A : Bus Master IDE/ATA Status Reg. for Ch. 2 */ + uint8_t udxidetcr1;/* 0x0B : Ultra DMA Timing Ctrl Reg. for Ch. 2 */ + uint32_t dtpr1; /* 0x0C-0F : Descriptor Table Ptr Reg. for Ch. 2 */ + uint8_t resv_10; /* Reserved */ + uint8_t udma3_4_ctrl; /* 0x11 : Ultra DMA Mode 3,4 Ctrl : Promise */ + uint8_t sub_sysID;/* 0x12 : Sub System ID modification Ctrl : Promise */ + uint8_t resv_13; /* Reserved */ + uint32_t flash; /* 0x14-17: Flash Memory Write port : Promise */ + uint16_t resv18_19;/* Reserved */ + uint8_t master_ctl0;/* 0x1A : Master Mode Ctrl for Ch. 1 : Promise */ + uint8_t master_ctl1;/* 0x1B : Master Mode Ctrl for Ch. 2 : Promise */ + uint32_t sys_ctl; /* 0x1C-1F : System Ctrl Reg. Promise */ + uint32_t atapi_Ch1;/* 0x20-23 : Ch. 1 ATAPI DMA port */ + uint32_t atapi_Ch2;/* 0x24-27 : Ch. 2 ATAPI DMA port */ +} pdc20262_dma_regs_t; + +typedef volatile struct { + uint8_t bmxidecr0; /* 0x70 : Bus Master Cmd Reg. for Primary Channel */ + uint8_t mrdmode; /* 0x71 : Intr Enable, Status Reg, + Master Read Select Ctrl Reg. for both channels */ + uint8_t bmxidesr0; /* 0x72 : Bus Master Status Reg. for Primary Chnl */ + uint8_t udxidetcr0;/* 0x73 : Ultra DMA Timing Ctrl Reg. for Prim. Chnl */ + uint32_t dtpr0; /* 0x74-77: Descriptor Table Ptr Reg. for Prim. Chnl */ + uint8_t bmxidecr1; /* 0x78 : Bus Master Cmd Reg. for 2ndry Channel */ + uint8_t bmxidecsr; /* 0x79 : Bus Master Ctrl Status Reg */ + uint8_t bmxidesr1; /* 0x0A : Bus Master IDE/ATA Status Reg. for Ch. 2 */ + uint8_t udxidetcr1;/* 0x0B : Ultra DMA Timing Ctrl Reg. for Ch. 2 */ + uint32_t dtpr1; /* 0x0C-0F : Descriptor Table Ptr Reg. for Ch. 2 */ +} cmd649_dma_regs_t; + +typedef volatile struct { + uint32_t timing_reg0; + uint32_t timing_reg1; + uint32_t low_mem_ptr; + uint32_t high_mem_ptr; + uint32_t low_mem_addr; + uint32_t high_mem_addr; + uint32_t dev_byte_count; + uint32_t mem_byte_count; + uint32_t status; +} ioc4_dma_regs_t; + +typedef volatile struct { + uint32_t low_err; + uint32_t high_err; + uint32_t serial_intr; + uint32_t ata_intr; // Other Interrupt Reg. + uint32_t serial_set; + uint32_t ata_intr_set; + uint32_t serial_clear; + uint32_t ata_intr_clear; +} ioc4_intr_regs_t; + +#define IOC4_INTR_REG 0x03 +#define IOC4_INTR_SET 0x05 +#define IOC4_INTR_CLEAR 0x07 + + +typedef struct xide_ProtoInfo_s xide_ProtoInfo_t; +typedef struct xide_TargInfo_s xide_TargInfo_t; +typedef struct xide_dev_s xide_dev_t; + +struct xide_ProtoInfo_s { + vertex_hdl_t ProtoVhdl; +#ifndef XSCSI + vertex_hdl_t PciVhdl; +#else + struct pci_dev *PciVhdl; +#endif + uint Flags; + char HwgName[LABEL_LENGTH_MAX]; +#ifdef XSCSI + sema_t intr_q; + sema_t intr_watch_q; +#endif + uint8_t intr_set; + uint8_t intr_seen; + uint8_t prevent_intr; + uint8_t pci_dma_error; + /* For Multiple IDE Controllers */ + xide_ProtoInfo_t *Next; + int Number; + uint16_t devid; + uint16_t vendorid; + uint16_t revID; + uint32_t pciio_byte_stream; + uint8_t xide_alt_status; + + /* For Fairness in sending commands */ + int LastTargServed; /* 0 or 1 only */ + + /* List of free CmdObjs */ + xide_CmdObj_t *FreeCmdObjTail; + xide_CmdObj_t *FreeCmdObjHead; + + /* DMA Stuff */ + xide_PageTblEntry_t *Bigmap;/* for transaction > IDE_MAPSIZE pages */ + iopaddr_t BigMapPciAddr; + int BigmapInUse; + int BigMapMaxCount; + caddr_t XferScratch; + iopaddr_t XferScratchPci; /* PCI address of above */ + pciio_dmamap_t PteMap; + iopaddr_t PteMapBaseaddr; + pciio_dmamap_t DmaEndMap; + iopaddr_t DmaEndAddr; + caddr_t DmaEndPtr; + /* Locking Stuff */ + #if IDE_SPINLOCKS + lock_t GraphLock; /* add/rm to ti/liList or hwgraph */ + int GraphLockSpl; + lock_t CommandLock; /* Commmand Sent to Device */ + int CommandLockSpl; + lock_t ResourceLock; /* todo lists, maps, objs */ + int ResourceLockSpl; + lock_t FinishedQLock; + int FinishedQSpl; + lock_t IntrLock; + int IntrLockSpl; + #else + mutex_t GraphLock; + mutex_t CommandLock; + mutex_t ResourceLock; + mutex_t FinishedQLock; + mutex_t IntrLock; + #endif + + /* Channel Mapping Regs */ +// command_regs_t *cmdblk; +// ctrl_regs_t *ctrlblk; +// dma_regs_t *dmablk; + + caddr_t cmdblk; + caddr_t ctrlblk; + caddr_t dmablk; + caddr_t intrblk; + // Interrupt register block for IOC4 + + /* Target Info */ + int device_conf[2]; + /* 11-8 : 0 -> not added to hwgraph | 1 -> added */ + /* 7-4 : 0 -> not found | 1 -> ATA | 2 -> ATAPI */ + /* 3-0 : 0 -> not found | 1 -> found */ + + xide_TargInfo_t *PtrToTarg[2]; + uint8_t State; + + /* Finished Q of requests */ + scsi_request_t *FinishedQHead; + scsi_request_t *FinishedQTail; +} ; + +struct xide_TargInfo_s { + vertex_hdl_t TargetVhdl; + vertex_hdl_t ProtoVhdl; + xide_ProtoInfo_t *ProtoInfo; + int Number; + char HwgName[LABEL_LENGTH_MAX]; + xide_LunInfo_t *PtrToLun[2]; +}; + +#ifdef XSCSI +typedef void (*SenseCallback_t)(vertex_hdl_t, uint8_t *); +#endif + +struct xide_LunInfo_s { + vertex_hdl_t LunVhdl; + vertex_hdl_t TargetVhdl; + vertex_hdl_t ProtoVhdl; + xide_TargInfo_t *TargInfo; + xide_ProtoInfo_t *ProtoInfo; + int Number; + + /* HwGraph Stuff */ + scsi_target_info_t tinfo; + + /* Identify (Packet) Device Info */ + xide_dev_t *xidentifyDev; + + /* Get Capacity Command Info */ + uint32_t CapNumOfBlocks; + uint32_t CapBlockSize; + int CapDataValid; + uint32_t NumOfBlocks; /* Set by Mselect 6 */ + uint32_t BlockSize; /* Set by Mselect 6 */ + + + /* Block Size Stuff */ + u_char AddSenseBD;/* add/rm block desc for mode cmds */ + u_char FixSenseBD;/* fix block desc for m-select cmd */ + u_char NoMode6Cmd; /* M-sense/sel. 6 byte cmds (y=1) */ + u_char NoMode10Cmd; /* M-sense/sel. 6 byte cmds (y=1) */ + u_char BlockSizeValid; /* Is current block_size valid? */ + + /* Process accessing LUN stuff */ + int RefCount; + u_char Exclusive; + u_char ContAlleg; /* contingent allegiance */ + + /* Queueing Stuff */ + xide_CmdObj_t *CmdObjHead; /* CmdObjs sent to device : Head */ + xide_CmdObj_t *CmdObjTail; /* CmdObjs sent to device : Tail*/ + scsi_request_t *ScsiReqQHead;/* Scsi Reqs by dksc/ds : Head */ + scsi_request_t *ScsiReqQTail;/* Scsi Reqs by dksc/ds : Tail */ + + /* CallBack Func */ +#ifndef XSCSI + void (*SenseCallback)(); +#else + SenseCallback_t SenseCallback; +#endif + + /* Locking Stuff */ + mutex_t OpenLock; + #ifdef IDE_SPINLOCKS + lock_t LunLock; + int LunSpl; + #else + mutex_t LunLock; + #endif + + uint8_t WeAreCD; + uint32_t Tag_Used; + +}; + + +/* +#define IDE_PCI_OUTB(x,y) PCI_OUTB(((uintptr_t)(x)^3),y) +#define IDE_PCI_INB(x) PCI_INB(((uintptr_t)(x)^3)) +#define IDE_PCI_INW(x) PCI_INH(((uintptr_t)(x)^2)) +#define IDE_PCI_OUTW(x,y) PCI_OUTH(((uintptr_t)(x)^2),y) +#define IDE_PCI_OUTDW(x,y) PCI_OUTW((uintptr_t)(x),y) +#define IDE_PCI_INDW(x) PCI_INW((uintptr_t)(x)) +*/ + +#define PCI_VENDOR_SGI 0x10A9 +#define IOC4_PCI_ID 0x100A +void xide_putb(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset, uint8_t value); +void xide_putw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset, uint16_t value); +void xide_putdw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset, uint32_t value); +uint8_t xide_getb(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset); +uint16_t xide_getw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset); +uint32_t xide_getdw(xide_ProtoInfo_t *pi, caddr_t addr, uint8_t offset); + + +#define IDE_OUTB(pi,addr,offset,value) xide_putb(pi,addr,offset,value) +#define IDE_OUTW(pi,addr,offset,value) xide_putw(pi,addr,offset,value) +#define IDE_OUTDW(pi,addr,offset,value) xide_putdw(pi,addr,offset,value) + +#define IDE_INB(pi,addr,offset) xide_getb(pi,addr,offset) +#define IDE_INW(pi,addr,offset) xide_getw(pi,addr,offset) +#define IDE_INDW(pi,addr,offset) xide_getdw(pi,addr,offset) + +#define IDE_DELAY(x) delay(x) + +#define ATAPI_MAGIC_LSB 0x14 +#define ATAPI_MAGIC_MSB 0xeb +#define INV_IDE_IOC4 29 +#define INV_IDE 30 +#define SCI_SCSI_TYPE_IDE 0x31 + +#define IDE_S_BUSY 0x80 +#define IDE_S_DRQ 0x08 +#define IDE_C_REL 0x04 +#define IDE_S_SERV 0x10 + +#define IDE_E_ERR 0x01 +#define IDE_E_ABORT 0x04 + +#define DEV_PRESENT 0x01 +#define DEV_ABSENT 0x00 +#define ATA_DEV_PRESENT 0x40 +#define ATAPI_DEV_PRESENT 0x20 +#define DEV_IN_GRAPH 0x0100 +#define TARGET_IN_GRAPH 0x0200 + +typedef struct xide_pciconfig_s xide_pciconfig_t; + +struct xide_pciconfig_s +{ + u_int16_t PCI_devID,PCI_vendID; + u_int16_t PCI_status,PCI_command; + u_int8_t PCI_class_code[3], PCI_revID; + u_int8_t rsvd1, PCI_header_type, + PCI_latency_timer, PCI_cache_line; + u_int32_t PCI_base0; + u_int32_t PCI_base1; + u_int32_t PCI_base2; + u_int32_t PCI_base3; + u_int32_t PCI_base4; + u_int32_t PCI_base5; + u_int32_t unused1; + u_int32_t unused2; + u_int32_t PCI_rombase; + u_int32_t unused3; + u_int32_t unused4; + u_int8_t PCI_max_latency, PCI_min_grant, + PCI_intr_pin, PCI_intr_line; + u_int8_t PCI_errorgen, PCI_intlinsel1, + PCI_devstatus0, PCI_devconfig; +}; + +/* CDROM Specific Structure only */ +struct xide_dev_s { + uint16_t atapi_dev:2, /* 0_16-15 => atapi */ +#define IDE_DEVICE 0x2 + resv_1 : 1, + dev_type : 3, +#define IDE_DIRECT 0x0 +#define IDE_TAPE 0x1 +#define IDE_CDROM 0x5 +#define IDE_OPTICAL 0x7 + removable : 1, + drq_time : 2, +#define IDE_DRQ_MPROC 0x0 +#define IDE_DRQ_INTR 0x1 +#define IDE_DRQ_ACCL 0x2 + resv_2 : 2, + incomplete : 1, + pkt_len : 2; +#define IDE_PKT_12 0x0 +#define IDE_PKT_16 0x1 + uint16_t cylinder; /* 1: Unused */ + uint16_t w2_resv; /* Word 2 : reserved */ + uint16_t heads; /* 3: Unused */ + uint16_t unfbytes_track; /* 4: Unused */ + uint16_t unfbytes_sector;/* 5: Unused */ + uint16_t sectors; /* 6: Unused */ + uint16_t w7_9resv[3]; /* 7-9 : resv */ + uint8_t serial_no[20]; /* 10-19 */ + uint16_t w20_21resv[2]; /* 20-21 reserved */ + uint16_t ecc_bytes; /* 22: unused */ + uint8_t firmware_rev[8];/* 23-26 : firmware revision */ + uint8_t model_no[40]; /* 27-46 : Model no. */ + uint16_t nsecperint; /* 47 : Unused */ + uint16_t w48_resv; /* 48 : resv */ + uint16_t dma_interleave : 1,/* 49_15 : Interleaved DMA */ + cmd_queue : 1, /* 49_14 : Command Queueing */ + overlap : 1, /* 49_13 : Overlap operation supported */ + softreset :1, /* 49_12 : Obsolete */ + iordy_yes : 1, /* 49_11 : IORDY supported */ + iordy_no :1, /* 49_10 : IORDY may be disabled */ + lba : 1, /* 49_9 : LBA supported */ + dma : 1, /* 49_8 : DMA supported */ + w49_vendor : 8; /* 49_7-0: Vendor Specific */ + uint16_t capvalidate; /* 50 */ + uint16_t old_pio; /* 51 : PIO modes 0-2 : Obsolete */ + uint16_t old_dma; /* 52 : Old DMA modes,not IDE-3:Obsolete */ + uint16_t w53_resv : 13, /* 53_15-3 : reserved */ + valid_w88 : 1, /* 53_2 : Fields in Word 88 valid */ + valid_w64_70 :1,/* 53_1 : Fields in W 64 - 70 valid */ + valid_w54_58 :1;/* 53_0 : Fields in W 54 - 58 valid */ + uint16_t curr_cyl; /* 54 : Unused */ + uint16_t curr_heads; /* 55 : Unused */ + uint16_t curr_sect; /* 56 : Unused */ + uint16_t curr_cap[2]; /* 57-58 : Unused */ + uint16_t w59_resv; /* 59 : reserved */ + uint16_t usr_sect[2]; /* 60-61 : Unused */ + uint16_t singleword_dma; /* 62 : Single Word DMA modes */ + uint16_t w63_resv : 3, /* 63_15-11 : Reserved */ + multidma_2: 1, /* 63_10 : Multiword DMA mode 2 selected */ + multidma_1: 1, /* 63_9 : Multiword DMA mode 1 selected */ + multidma_0: 1, /* 63_8 : Multiword DMA mode 0 selected */ + w63_resv2 : 3, /* 63_7-3 : Reserved */ + multidma_2supp : 1, /* 63_2 : Multiword DMA modes <= 2 supported */ + multidma_1supp : 1, /* 63_1 : Multiword DMA modes <= 1 supported */ + multidma_0supp : 1; /* 63_0 : Multiword DMA mode 0 supported */ + uint16_t w64_resv :8, /* 64_15-8 : reserved */ + pio_modes : 8; /* 64_7-0 : PIO modes supported */ + uint16_t mwdma_min; /* 65 : Minimum Multiword DMA time (in nanosecs) */ + uint16_t mwdma_rec; /* 66 : Manufac. Multiword DMA time (in nanosecs) */ + uint16_t pio_noflow; /* 67 : Min. PIO time & No flowcontrol (nanosecs) */ + uint16_t pio_iordy; /* 68 : Min. PIO time with IORDY */ + uint16_t w69_70resv[2]; /* 69-70 : reserved */ + uint16_t rls_ovrlap; /* 71 : Time(ns) for bus-release after PACKET cmd */ + uint16_t rls_service; /* 72 : Time(ns) for bus-release after SERVICE cmd*/ + uint16_t w73_74resv[2]; /* 73-74 : Reserved */ + uint16_t w75_resv : 11, /* 75_15-5 : Reserved */ + queue_depth:5; /* 75_4-0 : Max. Queue Depth - 1*/ + uint16_t w76_79resv[4]; /* 76-79 : Reserved */ + uint16_t w80_resv :9, /* 80_15-7 : Reserved for IDE 14-7 */ + ver6_supp :1, /* 80_6 : IDE 6 support */ + ver5_supp :1, /* 80_5 : IDE 5 support */ + ver4_supp :1, /* 80_4 : IDE 4 support */ + ver3_supp :1, /* 80_3 : IDE 3 support */ + w80_resv1 :3; /* 80_2-0 : reserved */ + uint16_t ver_minor; /* 81 : Minor version number */ + uint16_t w82_resv :1; /* 82_15 : reserved */ + uint16_t cmd_nop :1; /* 82_14 : NOP cmd */ + uint16_t cmd_readbuf :1; /* 82_13 : Read Buffer Cmd */ + uint16_t cmd_writebuf :1;/* 82_12 : Write Buf */ + uint16_t w82_resv2 :1 ; /* 82_11 : Obsolete */ + uint16_t cmd_hpaset :1; /* 82_10 : Host Prot. Area feature set */ + uint16_t cmd_devreset :1;/* 82_9 : Device Reset Cmd Support */ + uint16_t cmd_service :1; /* 82_8 : Service Interrupt Support */ + uint16_t cmd_release :1; /* 82_7 : Release Interrupt Support */ + uint16_t cmd_lookahead :1; /* 82_6: Look Ahead Support */ + uint16_t cmd_writecache :1;/* 82_5: Write Cache support */ + uint16_t cmd_packet :1; /* 82_4 : Support for Packet Commands */ + uint16_t cmd_pwrmgmt :1; /* 82_3 : Support for Pwr Mgmt */ + uint16_t cmd_media :1; /* 82_2 : Support for Removable Media */ + uint16_t cmd_security:1; /* 82_1 : Security Mode supported */ + uint16_t cmd_smart:1; /* 82_0 : SMART feature support */ + uint16_t w83_resv :2; /* 83_15-14 : Should be 0x01 */ + uint16_t w83_resv2 :1; /* 83_13 : Reserved */ + uint16_t cmd_flushcache:1;/* 83_12: Flush Cache Cmd */ + uint16_t cmd_devconf:1; /* 83_11 : Dev. Conf Overlay Set */ + uint16_t w83_resv3 : 2; /* 83_10-9 : resv */ + uint16_t cmd_setmax :1; /* 83_8 : SET MAX cmd */ + uint16_t w83_resv4 :1; /* 83_7 : reserved */ + uint16_t cmd_setfeatures:1; /* 83_6 : Set Features Cmd */ + uint16_t cmd_pwrup :1; /* 83_5 : Power Up in Standby feature set */ + uint16_t cmd_notifymedia :1; /* 83_4 : Rem. Media Set Notification supp*/ + uint16_t w83_resv5 :3; /* 83_3-1 : reserved */ + uint16_t cmd_microcode :1; /* 83_0 : Download MicroCode support */ + uint16_t w84_resv :2; /* 84_15-14 : Shallbe set to 0x01 */ + uint16_t w84_resv2:14; /* 84_13-0 : resv */ + uint16_t w85_resv :1; /* 85_15 : reserved */ + uint16_t enb_nop :1; /* 85_14 : NOP cmd Enable */ + uint16_t enb_readbuf :1; /* 85_13 : Read Buffer Cmd Enable*/ + uint16_t enb_writebuf :1;/* 85_12 : Write Buf Enable */ + uint16_t w85_resv2 :1 ; /* 85_11 : Obsolete */ + uint16_t enb_hpaset :1; /* 85_10 : Host Prot. Area feature set */ + uint16_t enb_devreset :1;/* 85_9 : Device Reset Cmd Enable */ + uint16_t enb_service :1; /* 85_8 : Service Interrupt Enable */ + uint16_t enb_release :1; /* 85_7 : Release Interrupt Enable */ + uint16_t enb_lookahead :1; /* 85_6: Look Ahead Enable */ + uint16_t enb_writecache :1;/* 85_5: Write Cache Enable */ + uint16_t enb_packet :1; /* 85_4 : Enable Packet Commands */ + uint16_t enb_pwrmgmt :1; /* 85_3 : Enable Pwr Mgmt */ + uint16_t enb_media :1; /* 85_2 : Enable Removable Media */ + uint16_t enb_security:1; /* 85_1 : Security Mode enabled */ + uint16_t enb_smart:1; /* 85_0 : SMART feature enabled */ + uint16_t w86_resv :2; /* 86_15-14 : Should be 0x01 */ + uint16_t w86_resv2 :1; /* 86_13 : Reserved */ + uint16_t sup_flushcache:1;/* 86_12: Flush Cache Cmd */ + uint16_t sup_devconf:1; /* 86_11 : Dev. Conf Overlay Set */ + uint16_t w86_resv3 : 2; /* 86_10-9 : resv */ + uint16_t enb_setmax :1; /* 86_8 : SET MAX cmd */ + uint16_t w86_resv4 :1; /* 86_7 : reserved */ + uint16_t sup_setfeatures:1; /* 86_6 : Set Features Cmd */ + uint16_t enb_pwrup :1; /* 86_5 : Power Up in Standby feature set */ + uint16_t enb_notifymedia :1; /* 86_4 : Rem. Media Set Notification supp*/ + uint16_t w86_resv5 :3; /* 86_3-1 : reserved */ + uint16_t enb_microcode:1; /* 86_0 : Download MicroCode enabled */ + uint16_t w87_resv :2; /* 87_15-14 : set to 0,1 */ + uint16_t w87_resv2:14; /* resv */ + uint16_t w88_resv:2; /* 88_15-14 : resv */ + uint16_t udma5_sel:1; /* 88_13 : Ultra DMA mode 5 selected */ + uint16_t udma4_sel:1; /* 88_12 : Ultra DMA mode 4 selected */ + uint16_t udma3_sel:1; /* 88_11 : Ultra DMA mode 3 selected */ + uint16_t udma2_sel:1; /* 88_10 : Ultra DMA mode 2 selected */ + uint16_t udma1_sel:1; /* 88_9 : Ultra DMA mode 1 selected */ + uint16_t udma0_sel:1; /* 88_8 : Ultra DMA mode 0 selected */ + uint16_t w88_resv2 :2; /* 88_7-6: resv */ + uint16_t udma5_sup:1; /* 88_5 : Ultra DMA mode<=5 support */ + uint16_t udma4_sup:1; /* 88_4 : Ultra DMA mode<=4 support */ + uint16_t udma3_sup:1; /* 88_3 : Ultra DMA mode<=3 support */ + uint16_t udma2_sup:1; /* 88_2 : Ultra DMA mode<=2 support */ + uint16_t udma1_sup:1; /* 88_1 : Ultra DMA mode<=1 support */ + uint16_t udma0_sup:1; /* 88_0 : Ultra DMA mode<=0 support */ + uint16_t w89_92resv[4]; /* 89-92: reserved */ + uint16_t w93_resv:2; /* 93_15-14 : resv */ + uint16_t cblid:1; /* 93_13: CBLID level */ + uint16_t dev1_reset:5; /* 93_12-8 : Dev 1 Hardware reset result */ + uint16_t dev0_reset:8; /* 93_7-0 : Dev 0 Hardware reset result */ + uint16_t w94_125resv[32];/* 94-125 reserved */ + uint16_t byte_count; /* 126 : Set to 0x0 */ + uint16_t w127_resv:14; /* 127_15-2: Reserved */ + uint16_t rmv_status:2; /* 127_1-0 : Rem. Media Status Notify support */ + uint16_t security_status;/* 128 : Security Status */ + uint16_t w129_159resv[31];/* 129-159 : Vendor specific */ + uint16_t w160_175resv[16];/* 160_175 : CFA reserved */ + uint16_t w176_254resv[79];/* 176_254 : CFA reserved */ + uint16_t checksum :8, /* 255_15-8 : Checksum */ + signature:8; /* 255_7-0 : Signature*/ +}; + +/* + * Spinlocks and mutexes both supported as compile time options + */ +#if IDE_SPINLOCKS +#define INITLOCK(l,n,s) init_spinlock(l, n, s) +#define IOLOCK(l,s) s = io_splock(l) +#define IOUNLOCK(l,s) io_spinlockspl(l, s) +#define IOTRYLOCK(l,s) mutex_spintrylock_spl(l, s) +#define FREELOCK(l) spinlock_destroy(l) +#else +#define INITLOCK(l,n,s) init_mutex(l, MUTEX_DEFAULT, n, s) +#define IOLOCK(l,s) mutex_lock(&(l), PRIBIO) +#define IOUNLOCK(l,s) mutex_unlock(&(l)) +#define IOTRYLOCK(l,s) mutex_trylock(&(l)) +#define FREELOCK(l) mutex_destroy(l) +#endif + +//#if defined(IP35) +#if defined(IP32) +#define USE_DIRECT_PCI_TRANSLATION +#else +#define USE_MAPPED_PCI_TRANSLATION +#endif /* IP32 */ + +#define IDE_CLR_CACHE(req, adr, len) \ + if ((req->sr_flags & SRF_FLUSH) == SRF_FLUSH) { \ + if ((req->sr_flags & SRF_DIR_IN) == SRF_DIR_IN) \ + dki_dcache_inval(adr, len); \ + else \ + dki_dcache_wbinval(adr, len); \ + } + +#if IDE_KMEM_DEBUG +#define IDE_KMEM_ALLOC(k,s,f) \ + k = kmem_alloc(s,f); \ + printf("xide alloc: %x, size: %x\n", k, s); + +#define IDE_KMEM_ZALLOC(k,s,f) \ + k = kmem_zalloc(s, f); \ + printf("xide zalloc: %x, size: %x\n", k, s); + +#define IDE_KMEM_FREE(a,s) \ + kmem_free(a, s); \ + printf("xide free: %x, size: %x\n", a, s); +#else +#define IDE_KMEM_ALLOC(k,s,f) k = kmem_alloc(s,f); +#define IDE_KMEM_ZALLOC(k,s,f) k = kmem_zalloc(s,f); +#define IDE_KMEM_FREE(a,s) kmem_free(a,s); +#endif + +#if IDE_CMD_DEBUG +extern xide_cmd_dbg_t xide_cmd_list[IDE_CMD_IDX_SZ]; +extern int xide_cmd_wrap; +extern int xide_cmd_index; +#endif + +/* + * Allows IDE_ASSERT to put us into the debugger + */ +#ifdef XSCSI +#if defined(CONFIG_XSCSI_IDE_KDB) +#define IDE_ASSERT(EX) if(!(EX)){printk("IDE_ASSERT FAIL "); printk("\n"); KDB_ENTER();} +#else +#define IDE_ASSERT(EX) +#endif +#else +#if defined(DEBUG) +#define IDE_ASSERT(EX) if(!(EX)){printf("IDE_ASSERT FAIL "); printf(#EX"\n"); debug("ring");} +#else +#define IDE_ASSERT(EX) +#endif +#endif + +#ifdef SN +#define TIMEOUT_SPL plbase +#else /* !SN */ +#define TIMEOUT_SPL plhi +#endif /* !SN */ + +#define MODE_SENSE6_CMD 0x1A +#define MODE_SENSE10_CMD 0x5A +#define MODE_SELECT6_CMD 0x15 +#define MODE_SELECT10_CMD 0x55 +#define READ_CAPACITY_CMD 0x25 +#define READ10_CMD 0x28 +#define WRITE10_CMD 0x2A +#define TEST_UNIT_READY 0x00 + +#define UDMA 0x40 +#define UDMA_5 0x45 +#define UDMA_4 0x44 +#define UDMA_3 0x43 +#define UDMA_2 0x42 +#define UDMA_1 0x41 +#define UDMA_0 0x40 +#define PIO 0x08 + +#define MDMA 0x20 +#define MULTIDMA_2 0x22 +#define MULTIDMA_1 0x21 +#define MULTIDMA_0 0x20 + +#define IDE_DMA_START 0x01 +#define IDE_DMA_STOP 0x0 +#define IDE_DMA_READ 0x00 +#define IDE_DMA_WRITE 0x08 + +#define DMA_S_ACTIVE 0x01 +#define DMA_S_ERROR 0x02 +#define DMA_S_INTR 0x04 +#define DMA_S_MASTER 0x20 +#define DMA_S_SLAVE 0x40 + +#define IDE_CO_ACTIVE 0x01 +#define IDE_CO_FREE 0x02 + +#define IDE_START_TRANSFER 0x01 +#define IDE_MIDDLE_TRANSFER 0x02 +#define IDE_END_TRANSFER 0x04 +#define IDE_SPLIT_TRANSFER 0x10 + +#define PIO_NONDATA 0x10 +#define PIO_DATA_IN 0x20 +#define PIO_DATA_OUT 0x20 + +#define CMD_OVERLAP 0x02 +#define CMD_NON_OVERLAP 0x01 +#define CMD_DMA 0x40 +#define CMD_PACKET 0x100 +#define CMD_ATA_DMA 0x011400 + +#define HHR 0x01 /* HardWare reset */ +#define HIO 0x10 + +#define DEVICE_PROBE_OVER 0x08 /* Device Probe Over */ +#define OVERLAP 0x02 /* Overlapped Commands */ +#define NON_OVERLAP 0x04 /* No Overlapping Commands */ +#define PACKET 0xA0 /* PKT Command Passed */ + +#define DMA 0x01 +#define PKT_CMD_IN 0x10 +#define PKT_BYTES_SENT 0x20 +#define PKT_DATA_TRANSFER 0x30 +#define PKT_DMA_START 0x40 +#define PKT_DMA_COMPLETE 0x50 +#define CMD_COMPLETE 0x60 +#define BUS_RELEASE 0x70 + +#define IDE_HOLD 0x03 +#define IDE_NIEN 0x02 +#define IDE_QUEUE_EMPTY 0x0 +#define IDE_BUSY 0x1 + +extern int xide_devflag; +extern int xidedebug; +extern xide_ProtoInfo_t *xide_proto_list; +extern int xide_proto_num; + +extern mutex_t xide_connect_sema; + + +/************************** + external declaration +**************************/ + +/* in irix/kern/mtune/kernel file */ +extern int default_intr_pri; + +/* in master.d file */ +extern int xide_print_sense; +extern int xide_print_cmd; + +/* in scsi.c */ +extern char *scsi_adaperrs_tab[]; + +#ifndef XSCSI +void xide_init(void); +int xide_attach(vertex_hdl_t vhdl); +#else +int __init xide_detect(void); +int __devinit xide_attach(struct pci_dev *vhdl, const struct pci_device_id *pci_id); +#endif +void xide_intr(xide_ProtoInfo_t *pi); +void xide_WatchdogTimer(xide_ProtoInfo_t *pi); +int xide_ioctl(vertex_hdl_t proto_vhdl, uint cmd, struct scsi_ha_op *op); +int xide_dump(vertex_hdl_t proto_vhdl); +//void xide_free(vertex_hdl_t lun_vhdl, void (*cb)()); +void xide_free(vertex_hdl_t lun_vhdl, void (*cb)(vertex_hdl_t, uint8_t *)); +//int xide_alloc(vertex_hdl_t lun_vhdl, int opt, void (*cb)()); +int xide_alloc(vertex_hdl_t lun_vhdl, int opt, void (*cb)(vertex_hdl_t, uint8_t *)) ; +void xide_command(scsi_request_t *req); + +#ifdef XSCSI +#undef PCI_OUTW // Syntax error in osdep_linux.h so this hack -> 6/10/02 +#define PCI_OUTW(port,val) outl(val, (unsigned long) (port)) +struct scsi_atapi_args +{ + vertex_hdl_t lun_vhdl; + uint read; /* if 1 get blksize, if 0, set it to blksize */ + uint blksize; +}; +typedef struct scsi_atapi_args scsi_atapi_args_t; +#endif + +#endif diff -Nur linux-2.4.19/drivers/xscsi/ide_idbg.c linux-2.4.19-sgi211r3/drivers/xscsi/ide_idbg.c --- linux-2.4.19/drivers/xscsi/ide_idbg.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/ide_idbg.c Fri Jan 3 08:28:29 2003 @@ -0,0 +1,820 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifdef linux +#define XSCSI +#include +#include +#include +#include +#include +#include "osdep_linux.h" +#include "xscsi.h" +#include "alenlist.h" +#include "ide.h" + +#define qprintf kdb_printf +#define SMALL_ALLOC +#define LLX "%lx" +#define IDE_PTR "%p" +#define IDBG_END_RTN return 0; +#define IDBG_RTN return 0; + +#else + + +#include "sys/types.h" +#include "sys/ksynch.h" +#include "sys/poll.h" +#include "sys/ddi.h" +#include "sys/param.h" +#include "sys/systm.h" +#include "sys/edt.h" +#include "sys/sysmacros.h" +#include "sys/cmn_err.h" +#include "sys/debug.h" +#include "sys/kmem.h" +#include "sys/mman.h" +#include "ksys/ddmap.h" +#include "sys/errno.h" +#include "sys/immu.h" +#include "sys/invent.h" +#include "sys/kopt.h" +#include "sys/mbuf.h" +#include "sys/sbd.h" +#include "sys/socket.h" +#include "sys/cpu.h" +#include "sys/conf.h" +#include "sys/ddi.h" +#include "sys/mload.h" +#include "sys/cred.h" +#include "sys/pci_intf.h" +#include "sys/PCI/pciio.h" +#include "sys/PCI/PCI_defs.h" +#include "sys/ktime.h" +#include "sys/sema.h" +#include "sys/scsi.h" +#include "sys/iograph.h" +#include "ksys/xthread.h" +#include "sys/pfdat.h" +#include "sys/var.h" +#include "sys/failover.h" +#include "sys/invent.h" +#include +#include +#include "sys/ide.h" +//#include "osdep_irix.h" + +#define LLX "%llx" +#define IDE_PTR "%x" + +#define IDBG_END_RTN return +#define IDBG_RTN return + +#ifndef IDE_CMD_DEBUG +#define IDE_CMD_DEBUG 1 +#endif + +struct xide_idbg_func +{ + char *name; + void (*func)(); + char *descrip; +}; + + +void idbg_xide_print_q_info(uintptr_t arg); +void xide_idbg_init(void); +void idbg_xide_chk_mutex(mutex_t *m, char *name); +void idbg_xide_print_mutex_adr(uintptr_t arg); +void idbg_xide_print_proto_info(uintptr_t arg); +void idbg_xide_print_targ_info(uintptr_t arg); +void idbg_xide_print_lun_info(uintptr_t arg); +void idbg_xide_print_cmd_obj(uintptr_t arg); +void idbg_xide_print_cmd_obj_list(uintptr_t arg); +void idbg_xide_print_cmd_list(int arg); + +struct xide_idbg_func xide_idbg_funcs[] = { + "xide_q", idbg_xide_print_q_info, "Print xide transaction queue info", + "xide_mutex", idbg_xide_print_mutex_adr, "Print xide mutex addresses for ctlr", + "xide_pi", idbg_xide_print_proto_info, "print xide proto info", + "xide_ti", idbg_xide_print_targ_info, "print xide target info", + "xide_li", idbg_xide_print_lun_info, "print xide lun info", + "xide_co", idbg_xide_print_cmd_obj, "print xide CmdObj info", + "xide_co_list", idbg_xide_print_cmd_obj_list, "print all xide CmdObjs addresses ", +#if IDE_CMD_DEBUG + "xide_cmd", idbg_xide_print_cmd_list, "print last x commands", +#endif + 0, 0, 0 +}; + +#endif + +#if IDE_CMD_DEBUG +extern xide_cmd_dbg_t xide_cmd_list[IDE_CMD_IDX_SZ]; +extern int xide_cmd_wrap; +extern int xide_cmd_index; +#endif + +#ifndef XSCSI +extern void idbg_mutexdump(mutex_t *mp); + +void +xide_idbg_init(void) +{ + struct xide_idbg_func *fp; + + for (fp = xide_idbg_funcs; fp->name; fp++) { + idbg_addfunc(fp->name, fp->func); + } +} +#endif + +static char *xide_cdbg_actions[] = +{ + "Received ScsiReq ", // 0 + "Add to ScsiReq ", // 1 + "Remove from ScsiReq", // 2 + "Put in FinishQ ", // 3 + "sr_notify() Called", // 4 + "Branched", // 5 + "ScsiReq successful", // 6 + "ScsiReq ERROR", // 7 + "ScsiReq ret. by Watchdog()", // 8 + "ScsiReq Sent to Device", // 9 +}; +#ifdef XSCSI +static int +idbg_xide_print_q_info(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_q_info(uintptr_t arg) +#endif +{ + xide_ProtoInfo_t *pi; + vertex_hdl_t proto_vhdl; + scsi_ctlr_info_t *pi_info; + int i; + xide_LunInfo_t *li; + +#ifdef XSCSI + uintptr_t arg; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) return KDB_ARGCOUNT; + + nextarg = 1; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) return diag; + + arg = (uintptr_t)addr; +#endif + + + if (arg > 10000) + pi = (xide_ProtoInfo_t *)arg; + else { + proto_vhdl = (vertex_hdl_t)arg; + pi_info = scsi_ctlr_info_get(proto_vhdl); + pi = SCI_INFO(pi_info); + } + + if (pi == NULL) { + qprintf("bad vertex 0x"IDE_PTR" specified\n",(void *)arg); + IDBG_RTN; + } + +// if (pi->TargetListHead != NULL) +// qprintf("TargetListHead: 0x%x\n", pi->TargetListHead); + + qprintf("pi 0x"IDE_PTR" | FreeCmdObjHead : 0x"IDE_PTR" \n",(void *)pi,(void *)pi->FreeCmdObjHead); + qprintf("pi 0x"IDE_PTR" | FreeCmdObjTail : 0x"IDE_PTR" \n",(void *)pi,(void *)pi->FreeCmdObjTail); + qprintf("pi 0x"IDE_PTR" | FinishedQHead : 0x"IDE_PTR" \n",(void *)pi,(void *)pi->FinishedQHead); + qprintf("pi 0x"IDE_PTR" | FinishedQTail : 0x"IDE_PTR" \n",(void *)pi,(void *)pi->FinishedQTail); + + for (i=0;i<2;i++) { + if (pi->device_conf[i] & 0x121) { + if (pi->PtrToTarg[i] != NULL) { + if (pi->PtrToTarg[i]->PtrToLun[0] != NULL) { + li = pi->PtrToTarg[i]->PtrToLun[0]; + qprintf("li 0x"IDE_PTR" | ScsiReqQHead : 0x"IDE_PTR"\n",(void *)li,(void *)li->ScsiReqQHead); + qprintf("li 0x"IDE_PTR" | ScsiReqQTail : 0x"IDE_PTR"\n",(void *)li,(void *)li->ScsiReqQTail); + } + } + } + else { + qprintf("Error in argument passed 0x"IDE_PTR"\n",(void *)arg); + } + } + + +// if (pi->ScsiReqQHead != NULL) +// qprintf("ScsiReqQHead: 0x%x\n", pi->ScsiReqQHead); + +// if (pi->TaskReqQHead != NULL) +// qprintf("TaskReqQHead: 0x%x\n", pi->TaskReqQHead); + +// if (pi->FinishedQHead != NULL) +// qprintf("FinshedQHead: 0x%x\n", pi->FinishedQHead); + IDBG_END_RTN; +} + +void +idbg_xide_chk_mutex(mutex_t *m, char *name) +{ +#ifndef XSCSI + if (mutex_owned(m)) { +#else + if (MUTEX_MINE(m)) { +#endif + qprintf("------ %s ------ 0x"IDE_PTR" \n", name,(void *) m); +#ifndef XSCSI + idbg_mutexdump(m); +#endif + } +} + +#ifdef XSCSI +static int +idbg_xide_print_mutex_adr(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_mutex_adr(uintptr_t arg) +#endif +{ + xide_ProtoInfo_t *pi; + vertex_hdl_t proto_vhdl; + scsi_ctlr_info_t *pi_info; + xide_LunInfo_t *li; + xide_TargInfo_t *ti; + int i=0; + +#ifdef XSCSI + uintptr_t arg; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) return diag; + + arg = (uintptr_t)addr; + +#endif + + if (arg > 10000) + pi = (xide_ProtoInfo_t *)arg; + else { + proto_vhdl = (vertex_hdl_t)arg; + pi_info = scsi_ctlr_info_get(proto_vhdl); + pi = SCI_INFO(pi_info); + } + + if (pi == NULL) { + qprintf("bad vertex 0x"IDE_PTR" specified\n",(void *) arg); +#ifdef XSCSI + return -1; +#else + return; +#endif + } + + idbg_xide_chk_mutex(&pi->GraphLock, "GraphLock"); + idbg_xide_chk_mutex(&pi->CommandLock, "CommandLock"); + idbg_xide_chk_mutex(&pi->ResourceLock, "ResourceReqLock"); + + while ((ti=pi->PtrToTarg[i])!=NULL) { + qprintf("----------------\n"); + qprintf("Target - vertex 0x"IDE_PTR"\n", (void *)ti->TargetVhdl); + li = ti->PtrToLun[0]; + while (li) { + qprintf("------\nlun 0x"IDE_PTR"- vertex 0x"IDE_PTR"\n",(void *)li,(void *)li->LunVhdl); + idbg_xide_chk_mutex(&li->OpenLock, "OpenLock"); + idbg_xide_chk_mutex(&li->LunLock, "LunLock"); + } + i++; + } + IDBG_END_RTN; +} + +#ifdef XSCSI +static int +idbg_xide_print_proto_info(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_proto_info(uintptr_t arg) +#endif +{ + xide_ProtoInfo_t *pi; + vertex_hdl_t proto_vhdl; + scsi_ctlr_info_t *pi_info; + +#ifdef XSCSI + uintptr_t arg; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) return KDB_ARGCOUNT; + + nextarg =1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) return diag; + + arg = (uintptr_t)addr; +#endif + + if (arg > 10000) + pi = (xide_ProtoInfo_t *)arg; + else { + proto_vhdl = (vertex_hdl_t)arg; + pi_info = scsi_ctlr_info_get(proto_vhdl); + pi = SCI_INFO(pi_info); + } + + if (pi == NULL) { + qprintf("bad vertex 0x"IDE_PTR" specified\n",(void *) arg); + IDBG_RTN; + } + + qprintf("*Next = 0x"IDE_PTR" ", (void *)pi->Next); + qprintf("*ProtoInfo = 0x"IDE_PTR" ", (void *)pi); + qprintf(" ProtoVhdl = 0x"IDE_PTR"\n", (void *)pi->ProtoVhdl); + qprintf(" Vendor ID 0x%x | Device ID 0x%x \n",pi->vendorid,pi->devid); + qprintf(" PciVhdl = 0x"IDE_PTR"\n", (void *)pi->PciVhdl); +//#ifdef XSCSI +// qprintf(" intr_q 0x"IDE_PTR" \n",(pi->intr_q)); +//#endif + qprintf(" intr_set 0x%x \n",pi->intr_set); + qprintf("*PtrToTarg[0] = 0x"IDE_PTR"\n", (void *)pi->PtrToTarg[0]); + qprintf("*PtrToTarg[1] = 0x"IDE_PTR"\n", (void *)pi->PtrToTarg[1]); + qprintf(" Flags = 0x%x \n", pi->Flags); + qprintf(" State = 0x%x \n", pi->State); + qprintf("*Bigmap = 0x"IDE_PTR" ", (void *)pi->Bigmap); + qprintf(" BigmapInUse = %d\n", pi->BigmapInUse); + qprintf("*FreeCmdObjHead = 0x"IDE_PTR" ", (void *)pi->FreeCmdObjHead); + qprintf("*FreeCmdObjTail = 0x"IDE_PTR"\n", (void *)pi->FreeCmdObjTail); + qprintf(" HwgName = %s\n", pi->HwgName); + qprintf("*FinishedQHead = 0x"IDE_PTR"\n", (void *)pi->FinishedQHead); + qprintf("*FinishedQTail = 0x"IDE_PTR"\n", (void *)pi->FinishedQTail); + qprintf("*cmdblk = 0x"IDE_PTR"\n",(void *)pi->cmdblk); + qprintf("*ctrlblk = 0x"IDE_PTR"\n",(void *)pi->ctrlblk); + qprintf("*dmablk = 0x"IDE_PTR" \n",(void *)pi->dmablk); + qprintf("*intrblk = 0x"IDE_PTR" \n",(void *)pi->intrblk); + qprintf("*deviceconf[0] = 0x%x | [1] = 0x%x \n",pi->device_conf[0],pi->device_conf[1]); + qprintf("LastTargServed %d | \n",pi->LastTargServed); + qprintf("DmaAddrPtr 0x"IDE_PTR"\n",pi->DmaEndPtr); + + IDBG_END_RTN; +} + +#ifdef XSCSI +static int +idbg_xide_print_targ_info(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_targ_info(uintptr_t arg) +#endif +{ + xide_TargInfo_t *ti; + vertex_hdl_t targ_vhdl; + scsi_targ_info_t *ti_info; + +#ifdef XSCSI + uintptr_t arg; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + arg = (uintptr_t)addr; +#endif + + + if (arg > 10000) + ti = (xide_TargInfo_t *)arg; + else { + targ_vhdl = (vertex_hdl_t)arg; + ti_info = scsi_targ_info_get(targ_vhdl); + ti = STI_INFO(ti_info); + } + + if (ti == NULL) { + qprintf("bad vertex 0x"IDE_PTR" specified\n", (void *)arg); + IDBG_RTN; + } + + qprintf("*TargInfo = 0x"IDE_PTR" \t", (void *)ti); + qprintf(" TargetVhdl = 0x"IDE_PTR" \n", (void *)ti->TargetVhdl); + qprintf(" ProtoVhdl = 0x"IDE_PTR" \t ", (void *)ti->ProtoVhdl); + qprintf("*ProtoInfo = 0x"IDE_PTR" \t ", (void *)ti->ProtoInfo); + qprintf(" Number = %d \n", ti->Number); + qprintf(" HwgName = %s \n",ti->HwgName); + + qprintf("PtrToLun[0] = 0x"IDE_PTR"\n", (void *)ti->PtrToLun[0]); + + IDBG_END_RTN; +} + +#ifdef XSCSI +static int +idbg_xide_print_lun_info(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_lun_info(uintptr_t arg) +#endif +{ + xide_LunInfo_t *li; + vertex_hdl_t lun_vhdl; + scsi_lun_info_t *li_info; + +#ifdef XSCSI + uintptr_t arg; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + arg = (uintptr_t)addr; +#endif + + + if (arg > 10000) + li = (xide_LunInfo_t *)arg; + else { + lun_vhdl = (vertex_hdl_t)arg; + li_info = scsi_lun_info_get(lun_vhdl); + li = SLI_INFO(li_info); + } + + if (li == NULL) { + qprintf("bad vertex 0x"IDE_PTR" specified\n", (void *)arg); + IDBG_RTN; + } + + + qprintf(" ContAlleg = %d\n", li->ContAlleg); + qprintf("*LunInfo = 0x"IDE_PTR" ", (void *)li); + qprintf(" LunVhdl = 0x"IDE_PTR" ", (void *)li->LunVhdl); + qprintf(" Number = %d\n", li->Number); + qprintf(" TargetVhdl = 0x"IDE_PTR" ", (void *)li->TargetVhdl); + qprintf(" ProtoVhdl = 0x"IDE_PTR" ", (void *)li->ProtoVhdl); + qprintf("*TargInfo = 0x"IDE_PTR" ", (void *)li->TargInfo); + qprintf("*ProtoInfo = 0x"IDE_PTR"\n", (void *)li->ProtoInfo); + qprintf(" WeAreCD = %d ", li->WeAreCD); + qprintf(" AddSenseBD = %d ", li->AddSenseBD); + qprintf(" FixSenseBD = %d ", li->FixSenseBD); + qprintf(" NoMode6Cmd = %d\n", li->NoMode6Cmd); + qprintf(" RefCount = %d ", li->RefCount); + qprintf(" BlockSizeValid = 0x%x ", li->BlockSizeValid); + qprintf(" BlockSize = 0x%x\n", li->BlockSize); + qprintf(" CapDataValid = %d ", li->CapDataValid); + qprintf(" CapNumOfBlocks = 0x%x ", li->CapNumOfBlocks); + qprintf(" CapBlockSize = 0x%x\n", li->CapBlockSize); + qprintf("*Inquiry = 0x"IDE_PTR"\n", (void *)li->tinfo.si_inq); + qprintf("*ScsiReqQHead = 0x"IDE_PTR" ", (void *)li->ScsiReqQHead); + qprintf("*ScsiReqQTail = 0x"IDE_PTR"\n", (void *)li->ScsiReqQTail); + qprintf("*CmdObjHead = 0x"IDE_PTR" ", (void *)li->CmdObjHead); + qprintf("*CmdObjTail = 0x"IDE_PTR"\n", (void *)li->CmdObjTail); + qprintf("*xidentifyDev = 0x"IDE_PTR"\n",(void *)li->xidentifyDev); + qprintf("*Exclusive = 0x%x\n",li->Exclusive); + qprintf("Tags Occupied = 0x%x\n",li->Tag_Used); + + IDBG_RTN; +} + +#ifdef XSCSI +static int +idbg_xide_print_cmd_obj(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_cmd_obj(uintptr_t arg) +#endif +{ + xide_CmdObj_t *co; + +#ifdef XSCSI + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + co = (xide_CmdObj_t *)addr; + +#else + co = (xide_CmdObj_t *)arg; +#endif + + qprintf(" NoPte = 0x%x \n", co->NoPte); + qprintf(" UseBigmap = 0x%x \n", co->UseBigmap); + qprintf(" State = 0x%x \n", co->State); + qprintf("*li = 0x"IDE_PTR" \n", (void *)co->li); + qprintf("*Next = 0x"IDE_PTR" \n", (void *)co->Next); + qprintf("*Prev = 0x"IDE_PTR" \n", (void *)co->Prev); + qprintf("*Pte = 0x"IDE_PTR" \n", (void *)co->Pte); + qprintf(" NumPtes = %d \n", co->NumPtes); + qprintf("*ReservedPte = 0x"IDE_PTR" \n", (void *)co->ReservedPte); + qprintf("*AlenList = 0x"IDE_PTR" \n", (void *)co->AlenList); + qprintf("*PciAlenList = 0x"IDE_PTR" \n", (void *)co->PciAlenList); + qprintf(" PtePciAddr = 0x"IDE_PTR" \n", (void *)co->PtePciAddr); + qprintf(" ReservedPciAddr = 0x"IDE_PTR" \n",(void *) co->ReservedPtePciAddr); + qprintf(" AllocMapSize = 0x%x \n", co->AllocMapSize); + qprintf(" PteDMAMap = 0x"IDE_PTR" \n", (void *)co->PteDMAMap); + qprintf(" PteDMAMapBaseaddr = 0x"IDE_PTR" \n",(void *) co->PteDMAMapBaseaddr); + qprintf(" DataDMAMap = 0x"IDE_PTR" \n", (void *)co->DataDMAMap); + qprintf("*TempReqForFix = 0x"IDE_PTR" \n", (void *)co->TempReqForFix); + qprintf("*HoldReq = 0x"IDE_PTR" \n", (void *)co->HoldReq); + qprintf("*SentReq = 0x"IDE_PTR" \n", (void *)co->SentReq); + qprintf("*OrigReq = 0x"IDE_PTR" \n", (void *)co->OrigReq); + qprintf("*ReqSense = 0x"IDE_PTR" \n ", (void *)co->ReqSense); + qprintf(" FixMap4BlkSz = 0x%x \n", co->FixMap4BlkSz); + qprintf(" MapStartLen = 0x%x \n", co->MapStartLen); + qprintf(" MapEndLen = 0x%x \n", co->MapEndLen); + qprintf(" Tag = 0x%x \n", co->Tag); + qprintf(" State = 0x%x \n", co->State); + qprintf(" TimeOut = 0x%x \n", co->TimeOut); + qprintf(" TimeOutTime = 0x%x \n", co->TimeOutTime); + qprintf(" StartTime = 0x%x \n", co->StartTime); + qprintf(" request_stage = 0x%x \n", co->request_stage); + qprintf(" transfer_type = 0x%x \n", co->transfer_type); + qprintf(" Cmdblk = 0x"IDE_PTR" \n", (void *)&(co->CmdBlk[0])); + qprintf(" Offset %d | Flag 0x%x \n",co->offset, co->Offset_Flag); + qprintf(" Prev_Num_Blocks %d \n",co->Prev_Num_Blocks); + qprintf(" Saved_Pte 0x"IDE_PTR" | start_Pte 0x"IDE_PTR" | Start_PtePciAdr 0x"IDE_PTR" \n",(void *)co->saved_Pte, (void *)co->start_Pte,(void *)co->start_PtePciAddr); + IDBG_END_RTN; +} + +#ifdef XSCSI +static int +idbg_xide_print_cmd_obj_list(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_cmd_obj_list(uintptr_t arg) +#endif +{ + xide_ProtoInfo_t *pi; + vertex_hdl_t proto_vhdl; + scsi_ctlr_info_t *pi_info; + int cnt = 0; + xide_CmdObj_t *co=NULL; + xide_CmdObj_t *prev_co=NULL; + +#ifdef XSCSI + uintptr_t arg; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + arg = (uintptr_t)addr; +#endif + + + if (arg > 10000) + pi = (xide_ProtoInfo_t *)arg; + else { + proto_vhdl = (vertex_hdl_t)arg; + pi_info = scsi_ctlr_info_get(proto_vhdl); + pi = SCI_INFO(pi_info); + } + + if (pi == NULL) { + qprintf("bad vertex 0x"IDE_PTR" specified\n", (void *)arg); + IDBG_END_RTN; + } + + co = pi->FreeCmdObjHead; + + while (co != NULL) { + qprintf("0x"IDE_PTR" ", (void *)co); + cnt++; + if (cnt%4 == 0) qprintf("\n"); + prev_co = co; + co = co->Next; + } + + qprintf("\n"); + if (prev_co != pi->FreeCmdObjTail) + qprintf("** error: last CmdObj is not FreeCmdObjTail\n"); + qprintf("number of CmdObj = %d\n", cnt); + + IDBG_END_RTN; +} + +#if IDE_CMD_DEBUG +#ifdef XSCSI +static int +idbg_xide_print_cmd_list(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_xide_print_cmd_list(int arg) +#endif +{ + int i; + int j; + int cmd_to_start; + +#ifdef XSCSI + uintptr_t arg; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + arg = (int)addr; +#endif + + if (arg > IDE_CMD_IDX_SZ) + arg = IDE_CMD_IDX_SZ; + + cmd_to_start = xide_cmd_index - arg; + if (cmd_to_start < 0) { + if (xide_cmd_wrap == 1) + cmd_to_start += IDE_CMD_IDX_SZ; + else + cmd_to_start = 0; + } + + i = cmd_to_start; + while (i != xide_cmd_index) { + + qprintf("0x"IDE_PTR" ", (void *)xide_cmd_list[i].request); + qprintf("%s ", xide_cdbg_actions[xide_cmd_list[i].action]); + qprintf("%d ", xide_cmd_list[i].code); +// qprintf(" %d s | %d ns ", xide_cmd_list[i].Time.tv_sec,xide_cmd_list[i].Time.tv_nsec); +// qprintf("- 0x%x ", xide_cmd_list[i].StartTime); +// qprintf("= %d ||", xide_cmd_list[i].EndTime - xide_cmd_list[i].StartTime); + + for (j = 0; j < 12; j++) { + qprintf(" %x ", xide_cmd_list[i].command[j]); + } + qprintf(" buflen = 0x%x\n", xide_cmd_list[i].datalength); + + i++; + if (i == IDE_CMD_IDX_SZ) + i = 0; + } + IDBG_END_RTN; +} + +#endif + +#ifdef XSCSI + +extern int xide_unload_cmd_pending; + +/* +extern sema_t test_thrd_sema; +static int +idbg_sbp2_stop_threads(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + sbp2_unload_cmd_pending = 1; + +// Kill test thread, timeout thread will die on its own + up(&test_thrd_sema); +IDBG_END_RTN +} +*/ + +static int +xide_idbg_register(void) +{ + +#if 0 +int +init_module(void) +{ +#endif + + kdb_register("xide_q", idbg_xide_print_q_info, "", "Print xide transaction queue info",0); + kdb_register("xide_mutex", idbg_xide_print_mutex_adr, "", "Print xide mutex addresses for ctlr",0); + kdb_register("xide_pi", idbg_xide_print_proto_info, "", "print xide proto info",0); + kdb_register("xide_ti", idbg_xide_print_targ_info, "", "print xide target info",0); + kdb_register("xide_li", idbg_xide_print_lun_info, "", "print xide lun info",0); + kdb_register("xide_co", idbg_xide_print_cmd_obj, "", "print xide CmdObj info",0); + kdb_register("xide_co_list", idbg_xide_print_cmd_obj_list, "", "print all xide CmdObjs addresses ",0); +#if IDE_CMD_DEBUG + kdb_register("xide_cmd", idbg_xide_print_cmd_list, "", "print last x commands",0); +#endif +// kdb_register("xide_stop_threads", idbg_xide_stop_threads, "", "stop timeout and test threads", 0); + return(0); +} + +module_init(xide_idbg_register); + +#if 0 +void +cleanup_module(void) +{ + kdb_unregister("xide_q"); + kdb_unregister("xide_mutex"); + kdb_unregister("xide_pi"); + kdb_unregister("xide_ti"); + kdb_unregister("xide_li"); + kdb_unregister("xide_co"); + kdb_unregister("xide_co_list"); +#if IDE_CMD_DEBUG + kdb_unregister("xide_cmd"); +#endif + kdb_unregister("xscsi"); + kdb_unregister("xide_stop_threads"); + +} +EXPORT_NO_SYMBOLS; +#endif + +#endif diff -Nur linux-2.4.19/drivers/xscsi/mmsc.c linux-2.4.19-sgi211r3/drivers/xscsi/mmsc.c --- linux-2.4.19/drivers/xscsi/mmsc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/mmsc.c Wed Jan 15 10:38:06 2003 @@ -0,0 +1,4046 @@ +/* + * + * + * Copyright (c) 1986-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/****************************************************************************** + * mmsc.c is supposed to be identical to dksc.c...the differences are: + * 1) All variables, function names with DKSC, DK, dksc, dk in their name + * are replaced by MMSC, MM, mmsc, mm + * 2) Extra code to support cdrom devices (CDROMS, DVD ROMs etc) has been added. + * 3) Code in mmsc_disk_add() allows the cdrom devices to register with the + * "cdrom.c" layerin linux. + * 4) This driver was split from dksc.c on 8/15/2002 to isolate cdrom support code + * from the generic disk support code in dksc.c + * + * -Aniket Malatpure (aniket@sgi.com) + *****************************************************************************/ + +#define MMSC_EVENT_LOG 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "alenlist.h" +#include "xscsi.h" +#include "mmsc.h" + +#define MMSC_SARD 1 + +#define MMSC_RAW_DEV 1 +#define MMSC_BLK_DEV 2 + +#ifdef CONFIG_BLK_DEV_SR + #define ALIAS_STR "xsr" +#else + #define ALIAS_STR "sr" +#endif + +/* + * For the allocated requests. + */ +static kmem_cache_t *mmrequest_cachep; + +#define MM_SETS 16 + +#define MM_DISK_SHIFT 4 +#define MM_DISK_SIZE (1UL << MM_DISK_SHIFT) +#define MM_DISK_MASK (~(MM_DISK_SIZE - 1)) + +#define MM_SET_SHIFT (MM_DISK_SHIFT + 4) +#define MM_SET_SIZE (1UL << MM_SET_SHIFT) +#define MM_SET_MASK (~(MM_SET_SIZE - 1)) + +#define MM_SET(info) (((struct mm_setinfo **) (info)) - mm_setinfo) +#define MM_MINOR(drive, part) (((drive) << MM_DISK_SHIFT) + (part)) + +static spinlock_t mm_disk_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(mm_disk_list); + +static struct mm_setinfo { + struct gendisk *gdev; + struct hd_struct hd[1 << MM_SET_SHIFT]; + devfs_handle_t disks[1 << (MM_SET_SHIFT - MM_DISK_SHIFT)]; + int blksize[1 << 8]; + int blksize_size[1 << 8]; + int hardsect_size[1 << 8]; + int setnum; + int major; + unsigned short inuse; /* bitfield of used drives */ +} *mm_setinfo[MM_SETS]; + +devfs_handle_t mmsc_de[256][1 << (MINORBITS - MM_DISK_SHIFT)]; + +struct mm_partinfo { + struct mm_diskinfo *diskinfo; + struct mmsc_cdrom_info *cdrominfo; + devfs_handle_t de; + devfs_handle_t de_compat; + int part; +}; + +struct mm_diskinfo { + struct mmsoftc *softc; + struct mm_setinfo *setinfo; + scsi_lun_info_t *luninfo; + struct list_head list; + int pending; /* pending for part check */ + int drive; /* index (0-15) in set */ + struct semaphore sema; + struct mm_partinfo *parts[1 << MM_DISK_SHIFT]; +}; + +static unsigned char mm_read[10] = { [0] = 0x28 }; +static unsigned char mm_write[10] = { [0] = 0x2a }; +static unsigned char mm_readcapacity[10] = { [0] = 0x25 }; +static unsigned char mm_tst_unit_rdy[6]; +static unsigned char mm_mode_sense[6] = { [0] = 0x1a }; +static unsigned char mm_startunit[6] = { [0] = 0x1b, [4] = 1 }; + +#if defined(INDUCE_IO_ERROR) +/* + * To induce I/O error, set insert_error to 1, and error_dev to the dev_t. + * This is mainly used for XFS filesystem error handling testing. + */ +int mmsc_insert_error = 0; /* whether to enable fault insertion. */ +dev_t mmsc_error_dev = 0; /* device to fail */ +int mmsc_error_freq = 20; /* frequency at which errors are induced */ + +int mmsc_error_count = 0; /* counter to determine which request to + fail (if xlv_insert_error is 1). */ +#endif + +/* + * The basic timeout for the disk driver. Note that it is long to handle + * many units active at same time, with possible disconnects during commands. + */ +#define MMSC_TIMEOUT (60 * HZ) + +/* Maximum number of retries on a failed request */ +#define MM_MAX_RETRY 15 +/* retry on BUSY long enough to allow up to 4 minutes; same as startunit */ +#define MM_MAX_BUSY 16 +#define MM_MAX_BUSY_INTV 16 + +/* Size of a physical disk block (default, if can't get) */ +#ifndef BBSIZE +#define BBSIZE 512 +#endif +#define MM_BLK_SZ BBSIZE + +/* + * The default max queue per disk + */ +#define DFMAXQ 1 +#define DFMAX_READ_BLOCKS 2048 +#define DFMAX_WRITE_BLOCKS 2048 + +/* + * Number of requests. The number of requests that can be queued at + * the same time. + */ +#define MM_NR_REQUESTS 4 +#define MM_MAX_REQUESTS 1025 +#define MM_MAX_REQISSUE 768 + +static void mm_intr(scsi_request_t *); +static int mm_chkcond(struct mmsoftc *, scsi_request_t *, int, int); +static void mm_do_retry(scsi_request_t *); +static unsigned int mm_readcap(struct mmsoftc *); +static int mm_cmd(struct mmsoftc *mm, u_char *cmd_buffer, int cmd_size, + u_int timeoutval, caddr_t addr, size_t len, int rw); +static int mm_getblksz(struct mmsoftc *mm); +static void mmsc_start(struct mmsoftc *, struct mmrequest *, scsi_request_t *); +static void mm_print_sense(struct mmsoftc *mm, struct scsi_request *sp, int part); +static struct mmrequest * mm_get_request(struct mmsoftc *, int); +static void mm_unalloc_softc(struct mmsoftc *mm); +static void mm_callback_frontend(vertex_hdl_t lun_vhdl, uint8_t *sense); +static int mm_callback_backend(register struct mmsoftc *mm, int wait); +static void mm_callback_intr(scsi_request_t *); +#ifndef DEBUG +static int mm_user_printable_sense(struct mmsoftc *, register scsi_request_t *, int); +#endif +static int mmsc_request(request_queue_t *, int, struct buffer_head *); +static int mmsc_strategy(struct mmsoftc *, int, int, struct buffer_head *, + struct kiobuf *, unsigned int, unsigned int); +static void mmsc_unplug(struct mmsoftc *); +static void mm_part_remove(struct mm_diskinfo *diskinfo, int i); +static int mmsc_cdrom_probe_capabilities (struct mmsc_cdrom_info *info); + + +#if MMSC_EVENT_LOG +static int mmsc_event_level = 4; +void +mmsc_event_log(int level, struct mmsoftc *mm, char *string, unsigned int value1, unsigned int value2) +{ + int i = mm->mm_event_rotor; + + if (level < mmsc_event_level) + return; + if (++mm->mm_event_rotor == MMSC_EVENT_LOG_SIZE) + mm->mm_event_rotor = 0; + mm->mm_event_buffer[i].string = string; + mm->mm_event_buffer[i].aval = value1; + mm->mm_event_buffer[i].bval = value2; +} +#else +#define mmsc_event_log(l, d, a, b, c) +#endif + + +#ifdef DEBUG +#define mm_dbg_pmsg(dev, part, fmt...) mm_pmsg(dev, part, ## fmt) +#else +#define mm_dbg_pmsg(dev, part, fmt...) +#endif + +#if BITS_PER_LONG == 64 +#define LLP "%lx" +#else +#define LLP "%Lx" +#endif + +int +mmsc_proc_info(char *buffer, char **start, off_t offset, int length) +{ + struct list_head *entry; + int size, len; + off_t begin = 0; + off_t pos = 0; + + spin_lock(&mm_disk_lock); + size = sprintf(buffer, "Disks: %s\n", + list_empty(&mm_disk_list) ? "none" : ""); + len = size; + + list_for_each(entry, &mm_disk_list) { + struct mm_diskinfo *diskinfo; + scsi_lun_info_t *luninfo; + scsi_targ_info_t *targinfo; + scsi_ctlr_info_t *ctlrinfo; + struct mmsoftc *mm; + + diskinfo = list_entry(entry, struct mm_diskinfo, list); + luninfo = diskinfo->luninfo; + targinfo = SLI_TARG_INFO(luninfo); + ctlrinfo = STI_CTLR_INFO(targinfo); + + if (STI_NODE(targinfo) == 0) + size = sprintf(buffer + len, + " %s/target%d/lun%d", + devfs_get_name(ctlrinfo->sci_ctlr_vhdl, NULL), + STI_TARG(targinfo), + SLI_LUN(luninfo)); + else + size = sprintf(buffer + len, + " %s/node"LLP"/port"LLP"/lun%d", + devfs_get_name(ctlrinfo->sci_ctlr_vhdl, NULL), + STI_NODE(targinfo), STI_PORT(targinfo), + SLI_LUN(luninfo)); + len += size; + + mm = diskinfo->softc; + if (mm != NULL) + size = sprintf(buffer + len, " %d GB\n", + mm->mm_drivecap / 1953125); + else + size = sprintf(buffer + len, "\n"); + len += size; + + pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + break; + } + spin_unlock(&mm_disk_lock); + + *start = buffer + (offset - begin); + len -= (offset - begin); + if (len > length) + len = length; + return len; +} + +static void +mm_pmsg(struct mmsoftc *mm, int part, char *fmt, ...) +{ + va_list ap; + char message[256]; + int pos; + devfs_handle_t devhdl; + int drive; + + drive = mm->mm_disk_info->drive; + devhdl = mm->mm_disk_info->setinfo->hd[MM_MINOR(drive, part)].de; + + if (devhdl == NULL) + devhdl = mm->mm_disk_info->parts[0]->de; + pos = devfs_generate_path(devhdl, message, sizeof(message)); + if (pos < 0) + printk("drive %d: ", drive); + else + printk("%s: ", &message[pos]); + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end(ap); + printk("%s", message); +} + +static struct gendisk mm_gendisk[]; +static request_queue_t *mm_get_queue(kdev_t dev); +static struct block_device_operations mmsc_blk_ops; + +static struct mm_setinfo * +mm_drivealloc(int *major, int *drive) +{ + static int sets; + int set; + int err; + + for (set = 0; set < sets; set++) { + if (~mm_setinfo[set]->inuse & 0xffff) { + *drive = ffz(mm_setinfo[set]->inuse); + *major = mm_setinfo[set]->major; + set_bit(*drive, &mm_setinfo[set]->inuse); + return mm_setinfo[set]; + } + } + + if (!(sets < MM_SETS)) { + printk("No available majors!\n"); + return NULL; + } + + *major = devfs_alloc_major(DEVFS_SPECIAL_BLK); + *drive = 0; + + mm_setinfo[set] = kmalloc(sizeof(struct mm_setinfo), GFP_KERNEL); + if (!mm_setinfo[set]) + return NULL; + memset(mm_setinfo[set], 0, sizeof(struct mm_setinfo)); + + err = register_blkdev(*major, "mmsc", &mmsc_blk_ops); + if (err) { + kfree(mm_setinfo[set]); + mm_setinfo[set] = NULL; + return NULL; + } + + set_bit(*drive, &mm_setinfo[set]->inuse); + mm_setinfo[set]->major = *major; + mm_setinfo[set]->setnum = set; + + mm_setinfo[set]->gdev = &mm_gendisk[set]; + mm_gendisk[set].major = *major; + mm_gendisk[set].part = mm_setinfo[set]->hd; + mm_gendisk[set].sizes = mm_setinfo[set]->blksize; + mm_gendisk[set].de_arr = mm_setinfo[set]->disks; + mm_gendisk[set].nr_real = MM_SET_SIZE / MM_DISK_SIZE; + blk_dev[*major].queue = mm_get_queue; + blksize_size[*major] = mm_setinfo[set]->blksize_size; + hardsect_size[*major] = mm_setinfo[set]->hardsect_size; + + sets++; + + return mm_setinfo[set]; +} + +static void +mm_drivefree(struct mm_setinfo *setinfo, int drive) +{ + clear_bit(drive, &setinfo->inuse); +} + +extern struct file_operations mmsc_char_ops; +extern struct cdrom_device_ops mmsc_cdrom_dops; + +/* + * Allocate disk info and create disc block and raw vertices. + */ +void * +mmsc_disk_add(vertex_hdl_t lun_vhdl) +{ + devfs_handle_t disc; + devfs_handle_t rdisc; + struct mm_diskinfo *diskinfo; + struct mm_partinfo *partinfo; + struct mm_setinfo *setinfo; + int major; + int minor; + int drive; + char drivename[20]=""; + struct cdrom_device_info *devinfo=NULL; + struct mmsc_cdrom_info *cdrominfo=NULL; + + disc = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + if (disc) { + partinfo = devfs_get_info(disc); + if (partinfo) + return partinfo->diskinfo; + } + + spin_lock(&mm_disk_lock); + setinfo = mm_drivealloc(&major, &drive); + spin_unlock(&mm_disk_lock); + if (!setinfo) + return NULL; + + minor = MM_MINOR(drive, 0); + + partinfo = kmem_zalloc(sizeof(*partinfo), KM_SLEEP); + if (!partinfo) + goto out1; + diskinfo = kmem_zalloc(sizeof(*diskinfo), KM_SLEEP); + if (!diskinfo) + goto out2; + + diskinfo->luninfo = devfs_get_info(lun_vhdl); + diskinfo->setinfo = setinfo; + diskinfo->drive = drive; + diskinfo->parts[0] = partinfo; + sema_init(&diskinfo->sema, 1); + + partinfo->diskinfo = diskinfo; + partinfo->part = 0; + + disc = devfs_register(lun_vhdl, "disc", DEVFS_FL_DEFAULT, + major, minor, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) get_blkfops(major), partinfo); + if (disc == NULL) + goto out3; + + rdisc = devfs_register(lun_vhdl, "rdisc", DEVFS_FL_DEFAULT, + 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) &mmsc_char_ops, partinfo); + if (rdisc == NULL) + goto out4; + devfs_auto_unregister(disc, rdisc); + partinfo->de = disc; + mmsc_de[major][drive] = disc; + + { + int drivenum; + char fullpath[128]; + char firstletter; + char secondletter; + + drivenum = (setinfo->setnum << MM_DISK_SHIFT) + diskinfo->drive; + + if (drivenum < 702) /* max devices supportable with srXY# */ { + secondletter = (char) (drivenum % 26) + 'a'; + if (drivenum >= 26) { + firstletter = (char) (drivenum / 26) + 'a' - 1; + sprintf(drivename, ALIAS_STR"%c%c", firstletter, secondletter); + } + else + sprintf(drivename, ALIAS_STR"%c", secondletter); + drivenum = devfs_generate_path(disc, fullpath, 128); + devfs_mk_symlink(NULL, drivename, DEVFS_FL_DEFAULT, + &fullpath[drivenum], &partinfo->de_compat, NULL); + } + } + + // cdrom.c specific code starts... + + cdrominfo = (struct mmsc_cdrom_info *) kmem_zalloc (sizeof (*cdrominfo), KM_SLEEP); + if (!cdrominfo) + goto out4; + + partinfo->cdrominfo = cdrominfo; + + cdrominfo->partinfo = partinfo; + + devinfo = &(cdrominfo->devinfo); + devinfo->dev = MKDEV(major,minor); + devinfo->ops = &mmsc_cdrom_dops; + devinfo->mask= 0; + devinfo->use_count = 0; + devinfo->capacity = 1; + devinfo->handle = (void *)cdrominfo; + strcpy(devinfo->name,drivename); + + MMSC_CDROM_STATE_FLAGS (cdrominfo).media_changed = 1; + MMSC_CDROM_STATE_FLAGS (cdrominfo).toc_valid = 0; + MMSC_CDROM_STATE_FLAGS (cdrominfo).door_locked = 0; + + devinfo->de = devfs_register(lun_vhdl,"cd",DEVFS_FL_DEFAULT, + major, minor, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) get_blkfops(major),partinfo); + + if (devinfo->de == NULL) + goto out5; + + // cdrom.c specific code ends + + spin_lock(&mm_disk_lock); + list_add_tail(&diskinfo->list, &mm_disk_list); + diskinfo->pending = 1; + spin_unlock(&mm_disk_lock); + + return diskinfo; + +out5: + kmem_free(cdrominfo, sizeof(*cdrominfo)); +out4: + devfs_unregister(disc); +out3: + kmem_free(diskinfo, sizeof(*diskinfo)); +out2: + kmem_free(partinfo, sizeof(*partinfo)); +out1: + spin_lock(&mm_disk_lock); + mm_drivefree(setinfo, drive); + spin_unlock(&mm_disk_lock); + + return NULL; +} + +// Function to register the cdrom with "cdrom.c" +void +mmsc_register_cdrom(struct mm_diskinfo *diskinfo) +{ + struct mm_partinfo *partinfo=NULL; + struct mmsc_cdrom_info *cdrominfo=NULL; + struct cdrom_device_info *devinfo=NULL; + + partinfo = diskinfo->parts[0]; + cdrominfo = partinfo->cdrominfo; + devinfo = &(cdrominfo->devinfo); + + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).is_changer = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).cd_r = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).cd_rw = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).test_write = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).dvd = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).dvd_r = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).dvd_ram = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).no_eject = 1; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).supp_disc_present = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).audio_play = 0; + MMSC_CDROM_CONFIG_FLAGS (cdrominfo).close_tray = 1; + + devinfo->capacity = mmsc_cdrom_probe_capabilities(cdrominfo); + // set capability mask to match the probe. + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).cd_r) + devinfo->mask |= CDC_CD_R; + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).cd_rw) + devinfo->mask |= CDC_CD_RW; + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).dvd) + devinfo->mask |= CDC_DVD; + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).dvd_r) + devinfo->mask |= CDC_DVD_R; + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).dvd_ram) + devinfo->mask |= CDC_DVD_RAM; + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).is_changer) + devinfo->mask |= CDC_SELECT_DISC; + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).audio_play) + devinfo->mask |= CDC_PLAY_AUDIO; + if (!MMSC_CDROM_CONFIG_FLAGS (cdrominfo).close_tray) + devinfo->mask |= CDC_CLOSE_TRAY; + + register_cdrom(devinfo); + +} + +void +mmsc_disk_remove(vertex_hdl_t lun_vhdl) +{ + devfs_handle_t de; + struct mm_partinfo *partinfo; + struct mm_diskinfo *diskinfo; + struct mmsc_cdrom_info *cdrominfo; + struct cdrom_device_info *devinfo; + struct mmsoftc *mm; + int i; + + de = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + if (!de) + return; + + partinfo = devfs_get_info(de); + if (!partinfo) + return; + + diskinfo = partinfo->diskinfo; + + /* Unregister cdrom device with the cdrom.c layer */ + cdrominfo = partinfo->cdrominfo; + devinfo = &(cdrominfo->devinfo); + unregister_cdrom(devinfo); + devfs_unregister(devinfo->de); + kmem_free(cdrominfo, sizeof(*cdrominfo)); + + /* + * Free the softc data structure and all attachments. + */ + mm = diskinfo->softc; + if (mm != NULL) + mm_unalloc_softc(mm); + + mmsc_de[diskinfo->setinfo->major][diskinfo->drive] = NULL; + for (i = 0; i < MM_DISK_SIZE; i++) { + if (!diskinfo->parts[i]) + continue; + mm_part_remove(diskinfo, i); + } + + spin_lock(&mm_disk_lock); + list_del(&diskinfo->list); + mm_drivefree(diskinfo->setinfo, diskinfo->drive); + spin_unlock(&mm_disk_lock); + + kmem_free(diskinfo, sizeof(*diskinfo)); +} + +static devfs_handle_t +mm_part_add(struct mm_diskinfo *diskinfo, int i) +{ + vertex_hdl_t lun_vhdl; + devfs_handle_t part; + devfs_handle_t rpart; + struct mm_partinfo *partinfo; + char name[sizeof("part") + 3 + 1]; + unsigned int major; + unsigned int minor; + + lun_vhdl = SLI_LUN_VHDL(diskinfo->luninfo); + + if (diskinfo->parts[i]) { + printk("attempted to add existing partition!\n"); + return diskinfo->parts[i]->de; + } + + major = diskinfo->setinfo->major; + minor = MM_MINOR(diskinfo->drive, i); + + partinfo = kmem_zalloc(sizeof(*partinfo), KM_SLEEP); + if (!partinfo) + return NULL; + + diskinfo->parts[i] = partinfo; + partinfo->diskinfo = diskinfo; + partinfo->part = i; + + sprintf(name, "part%d", i); + part = devfs_register(lun_vhdl, name, DEVFS_FL_DEFAULT, major, minor, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) get_blkfops(major), partinfo); + if (part == NULL) + goto out1; + + partinfo->de = part; + + sprintf(name, "rpart%d", i); + rpart = devfs_register(lun_vhdl, name, DEVFS_FL_DEFAULT, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + (void *) &mmsc_char_ops, partinfo); + if (rpart == NULL) + goto out2; + devfs_auto_unregister(part, rpart); + { + int drivenum; + char drivename[8]; + char fullpath[128]; + char firstletter; + char secondletter; + + drivenum = (diskinfo->setinfo->setnum << MM_DISK_SHIFT) + diskinfo->drive; + if (drivenum < 702) /* max devices supportable with sdXY# */ { + secondletter = (char) (drivenum % 26) + 'a'; + if (drivenum >= 26) { + firstletter = (char) (drivenum / 26) + 'a' - 1; + sprintf(drivename, ALIAS_STR"%c%c%d", firstletter, secondletter, i); + } + else + sprintf(drivename, ALIAS_STR"%c%d", secondletter, i); + drivenum = devfs_generate_path(part, fullpath, 128); + devfs_mk_symlink(NULL, drivename, DEVFS_FL_DEFAULT, + &fullpath[drivenum], &partinfo->de_compat, NULL); + } + } + + return part; +out2: + devfs_unregister(part); +out1: + kmem_free(partinfo, sizeof(*partinfo)); + diskinfo->parts[i] = NULL; + + return NULL; +} + +static void +mm_part_remove(struct mm_diskinfo *diskinfo, int i) +{ + struct mm_partinfo *partinfo; + struct hd_struct *hd; + + if (!diskinfo->parts[i]) { + printk("partition %d already removed!\n", i); + return; + } + + partinfo = diskinfo->parts[i]; + devfs_unregister(partinfo->de); + devfs_unregister(partinfo->de_compat); + kmem_free(partinfo, sizeof(*partinfo)); + diskinfo->parts[i] = NULL; + + /* + * Zero out nr_sects field in hd_struct so that get_partition_list() + * won't try to look at partition info. This is already done if the + * partition is removed as a result of a call to grok_partitions, but + * if the partition is removed due to the drive disappearing, this is + * necessary. Also zero out the de, since there is no longer a valid + * devfs_entry. + */ + hd = &diskinfo->setinfo->hd[MM_MINOR(diskinfo->drive, i)]; + hd->nr_sects = 0; + hd->de = NULL; +} + + +static int +mm_readparts(struct mmsoftc *mm) +{ + struct mm_diskinfo *diskinfo; + scsi_lun_info_t *luninfo; + int capacity; + int i; + struct mm_setinfo *set; + struct hd_struct *hd; + vertex_hdl_t lun_vhdl; + int drive; + + diskinfo = mm->mm_disk_info; + luninfo = diskinfo->luninfo; + lun_vhdl = SLI_LUN_VHDL(diskinfo->luninfo); + drive = diskinfo->drive; + set = diskinfo->setinfo; + hd = &set->hd[MM_MINOR(drive, 0)]; + /* + * hd should also equal &gdev->part[]; + */ + + /* + * Check to see if the drive is ready for IO. + */ + if (mm_cmd(mm, mm_tst_unit_rdy, SC_CLASS0_SZ, MMSC_TIMEOUT, + NULL, 0, 0)) + return -EIO; + + /* + * We zero out the hd_structure so that the fields are + * initialized. Start_sect and nr_sects will be set in + * grok_partitions. + */ + memset(hd, 0, sizeof(struct hd_struct) << MM_DISK_SHIFT); + + /* + * Get capacity in 512b blocks. + */ + capacity = mm_readcap(mm) << (log2(mm->mm_blksz) - 9); + if (!capacity) { + mm_pmsg(mm, 0, "unable to determine capacity\n"); + return -EIO; + } + + for (i = 0; i < MM_DISK_SIZE; i++) { + if (mm->mm_blksz > 1024) + set->blksize_size[MM_MINOR(drive, i)] = mm->mm_blksz; + else + set->blksize_size[MM_MINOR(drive, i)] = 1024; + set->hardsect_size[MM_MINOR(drive, i)] = mm->mm_blksz; + } + + set->disks[MM_MINOR(drive, 0) >> MM_DISK_SHIFT] = lun_vhdl; + grok_partitions(set->gdev, MM_MINOR(drive, 0) >> MM_DISK_SHIFT, + MM_DISK_SIZE, capacity); + + for (i = 0; i < MM_DISK_SIZE; i++) { + /* + * Update the devfs entries for this partition. + */ + + if (!diskinfo->parts[i] && hd[i].nr_sects) + mm_part_add(diskinfo, i); + else if (diskinfo->parts[i] && !hd[i].nr_sects) + mm_part_remove(diskinfo, i); + + if (diskinfo->parts[i]) + hd[i].de = diskinfo->parts[i]->de; + } + + return 0; +} + +static int +mm_diskcheckinq(struct mmsoftc *mm) +{ + scsi_target_info_t *info; + vertex_hdl_t lun_vhdl; + + lun_vhdl = SLI_LUN_VHDL(mm->mm_disk_info->luninfo); + + info = SLI_INQ(mm->mm_disk_info->luninfo)(lun_vhdl); + if (info == SCSIDRIVER_NULL) { + mm_dbg_pmsg(mm, 0, "scsi_info failed, lun=%d \n", lun_vhdl); + return -ENODEV; + } + + MMSCLOCK(mm); + mm->mm_inqtyp = info->si_inq; + mm->mm_flags &= ~MM_WONT_START; + MMSCUNLOCK(mm); + + /* + * Should be Multimedia. Removable media OK. Look at all + * but the vendor specific bit; clearly if the controller + * doesn't support the lun we want, or it isn't attached, then + * we want to fail right here. + */ + if ((mm->mm_inqtyp[0] & 0x7f) != XSCSI_PT_CDROM) { + mm_pmsg(mm, 0, "not a multimedia drive, inquiry byte 0 == 0x%x\n", + mm->mm_inqtyp[0]); + return -ENODEV; + } + + /* + * Only add a sense callback for CDROM devices. + */ + mm->mm_cb = mm_callback_frontend; + + mm->mm_target_info = info; + + return 0; +} + +/* Only to call when the disk isn't open! */ + +static int +mm_diskalloc(struct mmsoftc *mm) +{ + int ret = 0; + scsi_lun_info_t *luninfo; + + luninfo = mm->mm_disk_info->luninfo; + + ret = SLI_ALLOC(luninfo)(SLI_LUN_VHDL(luninfo), mm->mm_qdepth, + mm->mm_cb); + if (ret != SCSIALLOCOK) { + mm_dbg_pmsg(mm, 0, "scsi_alloc failed\n"); + return ret ? -ret : -ENODEV; + } + + mm_getblksz(mm); + + return 0; +} + +void +mm_diskunalloc(struct mmsoftc *mm) +{ + scsi_lun_info_t *luninfo; + + luninfo = mm->mm_disk_info->luninfo; + + if (mm->mm_opencount == 0) + SLI_FREE(luninfo)(SLI_LUN_VHDL(luninfo), mm->mm_cb); +} + +static inline struct mmrequest * +mm_alloc_mmrequest(int flag) +{ + struct mmrequest *rq; + + rq = kmem_cache_alloc(mmrequest_cachep, flag); + if (rq) { + rq->sr.sr_command = rq->cmddata; + rq->sr.sr_sense = rq->sensedata; + rq->sr.sr_senselen = SCSI_SENSE_LEN; + rq->sr.sr_alenlist = &rq->alenlist; + } + return rq; +} + +/* + * Initialize elements that are initialized on each command. + */ +static inline void +mm_request_init(struct mmrequest *rq, struct mm_diskinfo *disk_info) +{ + rq->disk_info = disk_info; + rq->retry_count = 0; + rq->sr.sr_lun_vhdl = SLI_LUN_VHDL(disk_info->luninfo); + rq->sr.sr_ctlr = SLI_ADAP(disk_info->luninfo); + rq->sr.sr_target = SLI_TARG(disk_info->luninfo); + rq->sr.sr_lun = SLI_LUN(disk_info->luninfo); + rq->sr.sr_flags = SRF_AEN_ACK; + rq->sr.sr_tag = 0; + rq->sr.sr_dev = rq; +} + +#define mmsc_free_rq(list) list_entry((list)->next, struct mmrequest, free_table) + +/* + * Allocate the various dynamic data, initialize locks and + * semaphores, etc. + */ +static struct mmsoftc * +mm_alloc_softc(void) +{ + struct mmsoftc *mm; + int i; + request_queue_t *q; + + mm = kmalloc(sizeof(struct mmsoftc), GFP_KERNEL); + if (!mm) + return NULL; + memset(mm, 0, sizeof(struct mmsoftc)); + + mm->mm_qdepth = DFMAXQ; + mm->plug_tq.sync = 0; + mm->plug_tq.routine = (void (*)(void *))mmsc_unplug; + mm->plug_tq.data = mm; + + MMSCINITLOCK(mm); + mm->mm_iobuffree_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&mm->mm_wait); + sema_init(&mm->mm_sema, 1); + sema_init(&mm->mm_done, 0); + sema_init(&mm->mm_hold, 0); + + /* + * Use our own request function. Setup our own list of free + * request structures that we can stuff information for each + * buffer_head into. + */ + q = &mm->mm_request_queue; + blk_queue_make_request(q, &mmsc_request); + + INIT_LIST_HEAD(&q->queue_head); + INIT_LIST_HEAD(&q->rq[0].free); + INIT_LIST_HEAD(&q->rq[1].free); + + for (i = 0; i < MM_NR_REQUESTS; i++) { + struct mmrequest *rq; + rq = mm_alloc_mmrequest(SLAB_KERNEL); /* sleep allowed */ + if (!rq) + goto out1; + list_add(&rq->free_table, &q->rq[0].free); + } + q->rq[0].count = MM_NR_REQUESTS; + + init_waitqueue_head(&q->wait_for_requests[0]); + + /* + * Reserve one request for the callback. + */ + mm->mm_rq = mm_get_request(mm, 0); + + return(mm); +out1: + while (!list_empty(&q->rq[0].free)) { + struct mmrequest *rq; + rq = mmsc_free_rq(&q->rq[0].free); + list_del(&rq->free_table); + kmem_cache_free(mmrequest_cachep, rq); + } + kfree(mm); + return NULL; +} + +static int +mm_diskinit(struct mm_diskinfo *diskinfo) +{ + struct mmsoftc *mm; + + mm = mm_alloc_softc(); + if (!mm) + return -ENOMEM; + + mm->mm_disk_info = diskinfo; + diskinfo->softc = mm; + + return 0; +} + +static void +mm_unalloc_softc(struct mmsoftc *mm) +{ + struct list_head *list; + + MMSCDELETELOCK(mm); + + list = &mm->mm_request_queue.rq[0].free; + + while (!list_empty(list)) { + struct mmrequest *rq; + rq = list_entry(list->next, struct mmrequest, free_table); + list_del(&rq->free_table); + kmem_cache_free(mmrequest_cachep, rq); + } + + kmem_cache_free(mmrequest_cachep, mm->mm_rq); + + kfree(mm); +} + +/* + * Only called at init time. + */ +static int +mm_diskprobe(struct mm_diskinfo *diskinfo) +{ + struct mmsoftc *mm; + int ret = 0; + vertex_hdl_t lun_vhdl; + + lun_vhdl = SLI_LUN_VHDL(diskinfo->luninfo); + + if (diskinfo->softc) + return 0; + + ret = mm_diskinit(diskinfo); + if (ret) + return ret; + + mm = diskinfo->softc; + ret = mm_diskcheckinq(mm); + if (ret) + return ret; + + ret = mm_diskalloc(mm); + if (ret) + return ret; + + ret = mm_readparts(mm); + mm_diskunalloc(mm); + + return ret; +} + +void +mmsc_notify(void) +{ + struct mm_diskinfo *diskinfo; + struct list_head *entry; + + spin_lock(&mm_disk_lock); + list_for_each(entry, &mm_disk_list) { + diskinfo = list_entry(entry, struct mm_diskinfo, list); + if (!diskinfo->pending) + continue; + mm_diskprobe(diskinfo); + diskinfo->pending = 0; + mmsc_register_cdrom(diskinfo); + } + spin_unlock(&mm_disk_lock); +} + +static int +mmsc_open(struct inode *mminode, struct file *mmfile, int raw_or_block) +{ + struct mmsoftc *mm; + int part; + int ret = 0; + struct mm_partinfo *partinfo; + struct mm_diskinfo *diskinfo; + devfs_handle_t de; + int drive; + + SCSI_HWG_ACCESS(); + + de = devfs_get_handle_from_inode(mminode); + + /* + * If we are called from blkdev_get, it may have faked an + * inode for us, in which case we can't get the handle from + * the inode. + */ + if (de == NULL) + de = devfs_find_handle(NULL, NULL, + MAJOR(mminode->i_rdev), + MINOR(mminode->i_rdev), + DEVFS_SPECIAL_BLK, 0); + /* + * It is possible for the kernel to generate an open request + * to a block device that it has just created, so we have to + * allow for the possibility that the devfs lookups will fail. + */ + if (de == NULL) { + SCSI_HWG_UNACCESS(); + return -ENXIO; + } + + partinfo = devfs_get_info(de); + part = partinfo->part; + diskinfo = partinfo->diskinfo; + drive = diskinfo->drive; + + /* + * Single thread open and close. + */ + down(&diskinfo->sema); + + if (diskinfo->softc == NULL) { + ret = mm_diskinit(diskinfo); + if (ret) { + SCSI_HWG_UNACCESS(); + goto out1; + } + } + + mm = diskinfo->softc; + mm_dbg_pmsg(mm, 0, "mmscopen %d/%d\n", MAJOR(mminode->i_rdev), + MINOR(mminode->i_rdev)); + + if (raw_or_block == MMSC_BLK_DEV) { + cdrom_open(mminode,mmfile); + } + + ret = mm_diskcheckinq(mm); + if (ret) { + SCSI_HWG_UNACCESS(); + goto out1; + } + + if (mm->mm_opencount == 0) { + ret = mm_diskalloc(mm); + + SCSI_HWG_UNACCESS(); + if (ret) + goto out1; + + ret = mm_readparts(mm); + if (ret) + goto out2; + } else { + SCSI_HWG_UNACCESS(); + /* + * Removeable media may have changed since last open. + */ + if ((mm->mm_inqtyp[1] & 0x80)) + mm_getblksz(mm); + } + + + /* + * Fail if the partition doesn't exist. + */ + if (!diskinfo->setinfo->hd[MM_MINOR(drive, part)].nr_sects) { + ret = -ENXIO; + goto out2; + } + + mm->mm_opencount++; + + up(&diskinfo->sema); + return ret; +out2: + if (mm->mm_opencount == 0) + mm_diskunalloc(mm); +out1: + up(&diskinfo->sema); + return ret; +} + +static int +mmsc_raw_open(struct inode *mminode, struct file *mmfile) +{ + return (mmsc_open(mminode,mmfile,MMSC_RAW_DEV)); +} + +static int +mmsc_block_open(struct inode *mminode, struct file *mmfile) +{ + return (mmsc_open(mminode,mmfile,MMSC_BLK_DEV)); +} + +/* + * The close routine + * We don't deallocate the softc structure on mmsc close. We could + * keep reference counts and free when necessary, but it seems unnecessary. + * + * no reason to free up anything any more, since multiple upper + * layer devices can all have the same channel open; unfortunately, + * in order for the exclusive open stuff to work right, we still + * have to handle the scsi_free[] stuff. + */ +static int +mmsc_close(struct inode *mminode, struct file *mmfile, int raw_or_block) +{ + struct mmsoftc *mm; + struct mm_diskinfo *diskinfo; + struct mm_partinfo *partinfo; + vertex_hdl_t lun_vhdl; + devfs_handle_t de; + + de = devfs_get_handle_from_inode(mminode); + + /* + * If we are called from blkdev_put, it may have faked an + * inode for us, in which case we can't get the handle from + * the inode. + */ + if (de == NULL) + de = devfs_find_handle(NULL, NULL, + MAJOR(mminode->i_rdev), + MINOR(mminode->i_rdev), + DEVFS_SPECIAL_BLK, 0); + + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + + lun_vhdl = SLI_LUN_VHDL(diskinfo->luninfo); + + down(&diskinfo->sema); + + mm = diskinfo->softc; + + if (raw_or_block == MMSC_BLK_DEV) { + cdrom_release(mminode,mmfile); + } + + mm->mm_opencount--; + if (mm->mm_opencount == 0) + SLI_FREE(diskinfo->luninfo)(lun_vhdl, mm->mm_cb); + + up(&diskinfo->sema); + + mm_dbg_pmsg(mm, 0, "mmscclose %d/%d\n", MAJOR(mminode->i_rdev), + MINOR(mminode->i_rdev)); + return 0; +} + +static int +mmsc_raw_close(struct inode *mminode, struct file *mmfile) +{ + return (mmsc_close(mminode,mmfile,MMSC_RAW_DEV)); +} + +static int +mmsc_block_close(struct inode *mminode, struct file *mmfile) +{ + return (mmsc_close(mminode,mmfile,MMSC_BLK_DEV)); +} + +static int +mmsc_ioctl(struct inode *mminode, struct file *mmfile, + unsigned int cmd, unsigned long arg, int raw_or_block) +{ + struct mm_partinfo *partinfo; + struct mm_diskinfo *diskinfo; + struct mmsoftc *mm; + devfs_handle_t de; + int part; + struct mm_setinfo *set; + struct hd_struct *hd; + int info[4]; + int drive; + int minor; + int status; + + de = devfs_get_handle_from_inode(mminode); + + if (de == NULL) + de = devfs_find_handle(NULL, NULL, + MAJOR(mminode->i_rdev), + MINOR(mminode->i_rdev), + DEVFS_SPECIAL_BLK, 0); + + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + mm = diskinfo->softc; + part = partinfo->part; + drive = diskinfo->drive; + set = diskinfo->setinfo; + hd = &set->hd[MM_MINOR(drive, part)]; + + /* We need the device number of the block device for the + character device. */ + + minor = MM_MINOR(drive, part); + + switch (cmd) { + case HDIO_GETGEO: + { + struct hd_geometry *loc = (struct hd_geometry *) arg; + if(!loc) { + status = -EINVAL; + break; + } + + /* default to most commonly used values */ + + info[0] = 0x40; + info[1] = 0x20; + info[2] = hd->nr_sects >> 11; + + if (put_user(info[0], &loc->heads) || + put_user(info[1], &loc->sectors) || + put_user(info[2], &loc->cylinders) || + put_user(hd->start_sect, &loc->start)) + status = -EFAULT; + else + status = 0; + break; + } + case HDIO_GETGEO_BIG: + { + struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; + + if(!loc) { + status = -EINVAL; + break; + } + + /* default to most commonly used values */ + + info[0] = 0x40; + info[1] = 0x20; + info[2] = hd->nr_sects >> 11; + + if (put_user(info[0], &loc->heads) || + put_user(info[1], &loc->sectors) || + put_user(info[2], (unsigned int *) &loc->cylinders) || + put_user(hd->start_sect, &loc->start)) + status = -EFAULT; + else + status = 0; + break; + } + + case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + down(&diskinfo->sema); + if (mm->mm_opencount == 1) + status = mm_readparts(mm); + else + status = EBUSY; + up(&diskinfo->sema); + break; + + case BLKGETSIZE: + /* Get block size in 512B blocks */ + status = put_user((long) hd->nr_sects, (long *) arg); + break; + + default: + if (raw_or_block == MMSC_BLK_DEV) { + status = cdrom_ioctl(mminode,mmfile, cmd, arg); + if (status == -ENOSYS) + status = blk_ioctl(MKDEV(set->major, minor), cmd, arg); + } + break; + + } + + return status; +} + +static int +mmsc_raw_ioctl(struct inode *mminode, struct file *mmfile, + unsigned int cmd, unsigned long arg) +{ + return (mmsc_ioctl(mminode,mmfile,cmd,arg,MMSC_RAW_DEV)); +} + +static int +mmsc_block_ioctl(struct inode *mminode, struct file *mmfile, + unsigned int cmd, unsigned long arg) +{ + return (mmsc_ioctl(mminode,mmfile,cmd,arg,MMSC_BLK_DEV)); +} + +static inline struct kiobuf * +mm_getbuf(struct mmsoftc *mm) +{ + struct kiobuf *iobuf; + int err; + + spin_lock(&mm->mm_iobuffree_lock); + if (mm->mm_freeiobuf != NULL) { + iobuf = mm->mm_freeiobuf; + mm->mm_freeiobuf = (struct kiobuf *) iobuf->bh[0]; + spin_unlock(&mm->mm_iobuffree_lock); + iobuf->nr_pages = 0; + } + else { + int nbh = 0; + + mm->mm_iobuf_count++; + spin_unlock(&mm->mm_iobuffree_lock); + err = alloc_kiovec_sz(1, &iobuf, &nbh); + if (err) { + spin_lock(&mm->mm_iobuffree_lock); + mm->mm_iobuf_count--; + spin_unlock(&mm->mm_iobuffree_lock); + return NULL; + } + } + return iobuf; +} + +static inline void +mm_freebuf(struct mmsoftc *mm, struct kiobuf *iobuf) +{ + spin_lock(&mm->mm_iobuffree_lock); + if (mm->mm_iobuf_count < 32) { + iobuf->bh[0] = (struct buffer_head *) mm->mm_freeiobuf; + mm->mm_freeiobuf = iobuf; + spin_unlock(&mm->mm_iobuffree_lock); + } + else { + mm->mm_iobuf_count--; + spin_unlock(&mm->mm_iobuffree_lock); + free_kiovec(1, &iobuf); + } +} + +static void +mm_kiobuf_end_io(struct kiobuf *iobuf) +{ + complete((struct completion *) iobuf->blocks); +} + +static void +mm_wait_for_io(struct kiobuf *iobuf) +{ + wait_for_completion((struct completion *) iobuf->blocks); +} + +static ssize_t +mmsc_raw(struct file *mmfile, char *addr, size_t size, loff_t *offset, int rw) +{ + struct mmsoftc *mm; + int count; + unsigned int sector; + int err; + struct mm_diskinfo *diskinfo; + struct mm_partinfo *partinfo; + int part; + devfs_handle_t de; + struct kiobuf *iobuf; + struct mm_setinfo *set; + struct hd_struct *hd; + struct inode *mminode; + int drive; + + mminode = mmfile->f_dentry->d_inode; + de = devfs_get_handle_from_inode(mminode); + partinfo = devfs_get_info(de); + part = partinfo->part; + diskinfo = partinfo->diskinfo; + mm = diskinfo->softc; + drive = diskinfo->drive; + set = diskinfo->setinfo; + hd = &set->hd[MM_MINOR(drive, part)]; + + if (*offset & (mm->mm_blksz - 1) || size & (mm->mm_blksz - 1)) + return -EINVAL; + + sector = *offset >> log2(mm->mm_blksz); + count = size >> log2(mm->mm_blksz); + + if (sector + count > hd->nr_sects >> (log2(mm->mm_blksz) - 9)) + return -EINVAL; + + if ((iobuf = mm_getbuf(mm)) == NULL) + return -EAGAIN; + + err = map_user_kiobuf(rw, iobuf, (unsigned long) addr, size); + if (err) + goto out; + + iobuf->errno = 0; + iobuf->end_io = mm_kiobuf_end_io; + init_completion((struct completion *) iobuf->blocks); + + err = mmsc_strategy(mm, part, rw, NULL, iobuf, sector, count); + if (err) + goto out; + + mm_wait_for_io(iobuf); + + if (iobuf->errno) { + err = iobuf->errno; + goto out; + } + + *offset += size; + err = size; +out: + unmap_kiobuf(iobuf); + mm_freebuf(mm, iobuf); + return err; +} + +static ssize_t +mmsc_read(struct file *mmfile, char *addr, size_t size, loff_t *offset) +{ + return mmsc_raw(mmfile, addr, size, offset, READ); +} + +static ssize_t +mmsc_write(struct file *mmfile, const char *addr, size_t size, loff_t *offset) +{ + return mmsc_raw(mmfile, (char *) addr, size, offset, WRITE); +} + + +static request_queue_t * +mm_get_queue(kdev_t dev) +{ + devfs_handle_t de; + struct mm_partinfo *partinfo; + struct mmsoftc *mm; + + de = mmsc_de[MAJOR(dev)][MINOR(dev) >> MM_DISK_SHIFT]; + if (!de) + return NULL; + partinfo = devfs_get_info(de); + mm = partinfo->diskinfo->softc; + + return &mm->mm_request_queue; +} + + +static struct mmrequest * +mm_get_request(struct mmsoftc *mm, int rw) +{ + request_queue_t *q = &mm->mm_request_queue; + struct list_head *list = &q->rq[0].free; + register struct mmrequest *rq = NULL; + DECLARE_WAITQUEUE(wait, current); + + MMSCLOCK(mm); + if (!list_empty(list)) { + rq = mmsc_free_rq(list); + list_del(&rq->free_table); + } + if (rq == NULL && q->rq[0].count < MM_MAX_REQUESTS) { + rq = mm_alloc_mmrequest(SLAB_ATOMIC); + if (rq != NULL) + ++q->rq[0].count; + } + MMSCUNLOCK(mm); + if (rq != NULL) { + rq->free_list = list; + rq->q = q; + return rq; + } + + /* + * If we're at the point where we're out of requests, make sure + * that we start issuing those requests to the drive. + */ + mmsc_unplug(mm); + + add_wait_queue_exclusive(&q->wait_for_requests[0], &wait); + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + MMSCLOCK(mm); + if (!list_empty(list)) { + rq = mmsc_free_rq(list); + list_del(&rq->free_table); + MMSCUNLOCK(mm); + rq->free_list = list; + rq->q = q; + break; + } + MMSCUNLOCK(mm); + schedule(); + } + remove_wait_queue(&q->wait_for_requests[0], &wait); + current->state = TASK_RUNNING; + + return rq; +} + +static inline void +__mm_free_request(struct mmsoftc *mm, struct mmrequest *rq) +{ + if (!rq->free_list) + BUG(); + + list_add(&rq->free_table, rq->free_list); + rq->free_list = NULL; + wake_up(&rq->q->wait_for_requests[0]); +} + +static void +mm_free_request(struct mmsoftc *mm, struct mmrequest *rq) +{ + MMSCLOCK(mm); + __mm_free_request(mm, rq); + MMSCUNLOCK(mm); +} + +/* + * Slightly different version of disksort for controllers and drives which + * have more than one command active (tagged commands, command queueing, + * MACSI mode, etc.). The main difference is that macsisort puts a command + * into the second sort queue if its logical block number is less than the + * logical block number of the last command sent to the controller (stored + * in av_back by the driver). + * The idea is to have two lists, one following the other. In the first list + * are the bufs whose starting block numbers are greater than the starting + * block number of the command last sent to the controller. In the second list + * are those commands whose starting block numbers are less than the starting + * block number of the last command sent to the controller. The last command + * on the first list points to the first command on the second list. */ +void +mmsc_macsisort(struct mmsoftc *mm, struct diskqueue *utab, struct mmrequest *rq) +{ + register unsigned int bn; + register unsigned int fbn; + struct mmrequest **iohead; + struct mmrequest **iotail; + struct mmrequest *ap; + int max_merge = 1023; + long sort_block; + + /* + * max_merge is a hack put it to workaround problems with the 1394 + * tailgate card that can only handle 32 s/g entries. It can revert + * to a constant when that issue is resolved. + */ + if ((mm->mm_inqtyp[0] & 0x1F) == 5) + max_merge = 31; + + if (rq->cmd == WRITE) { + iohead = &utab->delwri_head; + iotail = &utab->delwri_tail; + sort_block = utab->delwri_prev; + } + else { + iohead = &utab->io_head; + iotail = &utab->io_tail; + sort_block = utab->io_prev; + } + + ap = *iohead; + /* + * empty queue case + */ + if (ap == NULL) + { + *iohead = rq; + *iotail = rq; + rq->av_forw = NULL; + mmsc_event_log(1, mm, "sorting into empty list", rq->sector, rq->count); + goto macsi_sort_end; + } + + bn = rq->sector; + /* + * if block number < bn of last command to be submitted, AND + * the first buf has a bn >= bn of last command, + * go forward until we hit buf with bn < bn of first buf + * then insert somewhere in second list + * else if block number <= bn at beginning of list, or + * (block number is >= bn of last command AND bn at beginning + * of list is < bn of last command submitted), + * insert at beginning of first list. + * else + * insert somewhere in first list + */ + if (bn < sort_block && ap->sector >= sort_block) + { + fbn = ap->sector; + while (ap->av_forw != NULL && + ap->av_forw->sector >= fbn) + ap = ap->av_forw; + while (ap->av_forw != NULL && + bn > ap->av_forw->sector) + ap = ap->av_forw; + mmsc_event_log(1, mm, "sorting into second list", rq->sector, rq->count); + goto macsi_sort_insert; + } + else if ((bn <= ap->sector) || + (bn >= sort_block && ap->sector < sort_block)) + { + rq->av_forw = ap; + *iohead = rq; + mmsc_event_log(1, mm, "sorting at start of first list", rq->sector, rq->count); + goto macsi_sort_merge_forward; + } + else + { + fbn = ap->sector; + while (ap->av_forw != NULL && + fbn <= ap->av_forw->sector && + bn > ap->av_forw->sector) + ap = ap->av_forw; + mmsc_event_log(1, mm, "sorting into first list", rq->sector, rq->count); + } + + /* + * Insert in list. + */ +macsi_sort_insert: + /* insert rq after ap */ + /* update io_tail if necessary */ + rq->av_forw = ap->av_forw; + ap->av_forw = rq; + if (rq->av_forw == NULL) + *iotail = rq; + + /* + * Merge mmrequests if possible. + * ap points to request behind rq. + */ + if (ap != NULL && ap->bh && rq->bh && + ap->sector + ap->count == rq->sector && + ap->merges + rq->merges < max_merge) + { + mmsc_event_log(2, mm, " merging back", ap->sector, ap->count); + ap->count += rq->count; + ap->bhlast->b_reqnext = rq->bh; + ap->bhlast = rq->bh; + ap->av_forw = rq->av_forw; + ap->merges += rq->merges + 1; + __mm_free_request(mm, rq); + rq = ap; /* set up for forward merge check */ + } + ap = rq->av_forw; +macsi_sort_merge_forward: + if (ap != NULL && ap->bh && rq->bh && + rq->sector + rq->count == ap->sector && + rq->merges + ap->merges < max_merge) + { +#if MMSC_EVENT_LOG + if (rq->merges && ap->merges) + mmsc_event_log(5, mm, "--- hole fill merge ---", + rq->sector, ap->sector); +#endif + mmsc_event_log(3, mm, " merging forward", ap->sector, ap->count); + rq->count += ap->count; + rq->bhlast->b_reqnext = ap->bh; + rq->bhlast = ap->bhlast; + rq->av_forw = ap->av_forw; + rq->merges += ap->merges + 1; + __mm_free_request(mm, ap); + } + +macsi_sort_end: +} + +#if 0 +/* + * nosort() + * Add request to queue. Queue is manged in first in, first out order. + * + */ +static void +nosort(register struct diskqueue *utab, register struct mmrequest *rq) +{ + if (utab->io_head == NULL) + { + utab->io_head = rq; + utab->io_tail = rq; + } + else + { + utab->io_tail->av_forw = rq; + utab->io_tail = rq; + } + + rq->b_resid = rq->count << 9; +} +#endif + + +static struct mmrequest * +fair_disk_dequeue(struct diskqueue *utab) +{ + struct mmrequest *rq; + + /* + * Take a request from the head of the queue. + */ + if (utab->io_head) { + rq = utab->io_head; + utab->io_head = rq->av_forw; + utab->io_prev = rq->sector; + } + else if (utab->delwri_head) { + rq = utab->delwri_head; + utab->delwri_head = rq->av_forw; + utab->delwri_prev = rq->sector; + } + else + return NULL; + + return rq; +} + +static void +mmsc_command(register struct mmsoftc *mm) +{ + struct scsi_request *sp; + struct mmrequest *rq; +#if MMSC_SARD + int tmp; + struct hd_struct *hd, *hd1; + int sectors; +#endif + + if (mm->mm_plug) + return; + + while ((rq = (mm->mm_retry ? mm->mm_retry : + mm->mm_queue.io_head ? mm->mm_queue.io_head : + mm->mm_queue.delwri_head)) != NULL) + { + /* + * If in the process of issuing a callback command, + * hold all commands. We will restart the issuing + * of commands when the callback command completes. + */ + if (mm->mm_flags & MM_HOLD) + break; + + /* + * Check whether a callback needs to be issued. + * Since the "wait" argument is 0, MM_HOLD and + * MM_NEED_CB will be set by the callback function + * if appropriate. + */ + if (mm->mm_flags & MM_NEED_CB) { + mm_callback_backend(mm, 0); + break; + } + + if (mm->mm_curq >= mm->mm_qdepth || mm->mm_rqactive >= MM_MAX_REQISSUE) + break; + else + mm->mm_curq++; + + sp = &rq->sr; + + if (!(mm->mm_flags & MM_QUEUE)) + sp->sr_tag = 0; + + /* + * Check the retry queue first -- it has priority. + */ + if (mm->mm_retry) + mm->mm_retry = rq->av_forw; + else + rq = fair_disk_dequeue(&(mm->mm_queue)); + + /* + * Update active queue and alenlist + */ + mm->mm_rqactive++; + rq->av_forw = mm->mm_active; + if (mm->mm_active != NULL) + mm->mm_active->av_back = rq; + rq->av_back = NULL; + mm->mm_active = rq; + +#if MMSC_SARD + /* + * Linux SARD disk accounting + */ + tmp = mm->mm_disk_info->drive; + hd = &mm->mm_disk_info->setinfo->hd[MM_MINOR(tmp, rq->part)]; + if (rq->part) + hd1 = &mm->mm_disk_info->setinfo->hd[MM_MINOR(tmp, 0)]; + else + hd1 = NULL; + if (mm->mm_iostart == 0) + mm->mm_iostart = jiffies; + sectors = rq->count << (log2(mm->mm_blksz) - 9); + if (rq->cmd == READ) { + hd->rd_sectors += sectors; + hd->rd_merges += rq->merges; + if (hd1) { + hd1->rd_sectors += sectors; + hd1->rd_merges += rq->merges; + } + } + else { + hd->wr_sectors += sectors; + hd->wr_merges += rq->merges; + if (hd1) { + hd1->wr_sectors += sectors; + hd1->wr_merges += rq->merges; + } + } + disk_round_stats(hd); + hd->ios_in_flight++; + if (hd1) { + disk_round_stats(hd1); + hd1->ios_in_flight++; + } +#endif + + mmsc_event_log(4, mm, "starting command", rq->sector, rq->count); + MMSCUNLOCK(mm); + if (rq->iobuf) + alenlist_setup(&rq->alenlist, + rq->iobuf->maplist, + rq->iobuf->offset, + rq->iobuf->length); + else + alenlist_setup_bh(&rq->alenlist, rq->bh); + mmsc_start(mm, rq, sp); + MMSCLOCK(mm); + } +} + +static int +mmsc_request(request_queue_t *q, + int rw, + struct buffer_head *bh) +{ + struct mmsoftc *mm; + vertex_hdl_t de; + struct mm_partinfo *partinfo; + unsigned int mm_sector; + unsigned int mm_count; + struct mm_diskinfo *diskinfo; + int part; + int errno; + + /* + * Partitions may not be initialized, because grok_partitions calls + * bread, which calls this function. Thus, we have to use the major + * and minor number to find the scsi_disk_info structure, and we + * cannot use the scsi_part_info structure. + */ + de = mmsc_de[MAJOR(bh->b_rdev)][MINOR(bh->b_rdev) >> MM_DISK_SHIFT]; + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + part = MINOR(bh->b_rdev) & ~MM_DISK_MASK; + mm = diskinfo->softc; + + if (mm == NULL) + goto bad; + + mm_sector = bh->b_rsector >> (log2(mm->mm_blksz) - 9); + mm_count = bh->b_size >> (log2(mm->mm_blksz)); + + errno = mmsc_strategy(mm, part, rw, bh, NULL, mm_sector, mm_count); + + if (errno == -EINVAL) + goto end_io; + else if (errno == -EIO) + goto bad; + return 0; + +end_io: + bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); + return 0; +bad: + buffer_IO_error(bh); + return 0; +} + +static void +mmsc_unplug(struct mmsoftc *mm) +{ + MMSCLOCK(mm); + if (mm->mm_plug) { + mm->mm_plug = 0; + mmsc_command(mm); + } + MMSCUNLOCK(mm); +} + +/* + * Queue device request. The sector and count are based on mm_blksz. + */ +static int +mmsc_strategy(struct mmsoftc *mm, + int part, + int rw, + struct buffer_head *bh, + struct kiobuf *kiobuf, + unsigned int sector, + unsigned int count) +{ + struct mmrequest *rq; + struct mm_setinfo *set; + int drive; + struct hd_struct *hd; + +#if defined(INDUCE_IO_ERROR) + if (mmsc_insert_error && + bp->b_edev == mmsc_error_dev) { + if (++mmsc_error_count > mmsc_error_freq) { + mmsc_error_count = 0; + goto bad; + } + } +#endif + + /* + * Write to readonly device is determined in ll_rw_block(). + * Attempt to access beyond end of device is checked for in + * generic_make_request(). + */ + + switch (rw) { + case READA: + rw = READ; /* drop into READ */ + case READ: + case WRITE: + break; + default: + printk(KERN_INFO "mmsc: bad command: %d\n", rw); + return -EINVAL; + } + + rq = mm_get_request(mm, rw); + + rq->av_forw = NULL; + rq->av_back = NULL; + rq->cmd = rw; + set = mm->mm_disk_info->setinfo; + drive = mm->mm_disk_info->drive; + hd = &set->hd[MM_MINOR(drive, part)]; + rq->sector = sector + (hd->start_sect >> (log2(mm->mm_blksz) - 9)); + rq->count = count; + rq->part = part; + rq->bh = bh; + rq->bhlast = bh; + rq->iobuf = kiobuf; + rq->merges = 0; + + mm_request_init(rq, mm->mm_disk_info); + + MMSCLOCK(mm); + if (bh != NULL && mm->mm_queue.io_head == NULL && mm->mm_queue.delwri_head == NULL) { + mm->mm_plug = 1; + queue_task(&mm->plug_tq, &tq_disk); + } +#if 1 + mmsc_macsisort(mm, &mm->mm_queue, rq); +#else + nosort(&mm->mm_queue, rq); +#endif + mmsc_command(mm); + MMSCUNLOCK(mm); + return 0; +} + +/* + * setup a device operation for calls from outside the driver; upper + * levels of kernel are assumed to do the mmi_dcache_{wb,inval} if needed. + */ +static void +mmsc_start(struct mmsoftc *mm, struct mmrequest *rq, scsi_request_t *sp) +{ + int sn; + int sc; + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + + /* Let the scsi driver do the transfer */ + if( rq->cmd == READ ) + memcpy(sp->sr_command, mm_read, SC_CLASS1_SZ); + else + memcpy(sp->sr_command, mm_write, SC_CLASS1_SZ); + + sc = rq->count; + sn = rq->sector; + rq->b_resid = sc << 9; + + /* + * Stuff in the logical block addr. + * Its spot in the cmd is on a short boundary. + */ + sp->sr_command[2] = (u_char)(sn >> 24); + sp->sr_command[3] = (u_char)(sn >> 16); + sp->sr_command[4] = (u_char)(sn >> 8); + sp->sr_command[5] = (u_char)sn; + sp->sr_command[7] = (u_char)(sc >> 8); + sp->sr_command[8] = (u_char)sc; + + sp->sr_cmdlen = SC_CLASS1_SZ; + + sp->sr_notify = mm_intr; + sp->sr_timeout = MMSC_TIMEOUT; + + if (rq->cmd == READ) + sp->sr_flags |= SRF_DIR_IN; + else + sp->sr_flags &= ~SRF_DIR_IN; + + sp->sr_flags |= SRF_ALENLIST; + sp->sr_buflen = sc << log2(mm->mm_blksz); + + SLI_COMMAND(lun_info)(sp); +} + +static inline void +__mm_queue_release(struct mmsoftc *mm) +{ + mm->mm_curq--; + if (mm->mm_curq > 0) + mm->mm_iostart = jiffies; + else + mm->mm_iostart = 0; + if (!list_empty(&mm->mm_wait.task_list)) + wake_up(&mm->mm_wait); + else if ((mm->mm_flags & MM_RECURSE) == 0) { + mm->mm_flags |= MM_RECURSE; + mmsc_command(mm); + mm->mm_flags &= ~MM_RECURSE; /* turn off recurse bit */ + } +} + +static inline void +mm_queue_release(struct mmsoftc *mm) +{ + MMSCLOCK(mm); + __mm_queue_release(mm); + MMSCUNLOCK(mm); +} + +static void +mm_queue_retry(struct mmsoftc *mm, struct mmrequest *rq) +{ + MMSCLOCK(mm); + + /* + * Take command off active queue + */ + if (rq->av_back != NULL) + rq->av_back->av_forw = rq->av_forw; + if (rq->av_forw != NULL) + rq->av_forw->av_back = rq->av_back; + if (mm->mm_active == rq) + mm->mm_active = rq->av_forw; + + /* + * .... and add it to the retry queue. + */ + if (mm->mm_retry == NULL) { + rq->av_forw = NULL; + mm->mm_retry = rq; + } + else { + rq->av_forw = mm->mm_retry; + mm->mm_retry = rq; + } + + mm->mm_rqactive--; + __mm_queue_release(mm); + + MMSCUNLOCK(mm); +} + + +/* + * mmsc interrupt routine, called via scsisubrel(). + * + */ +static void +mm_intr(register scsi_request_t *sp) +{ + struct mmrequest *rq; + int bytes_xferred; + struct buffer_head *bh; + struct buffer_head *nbh; + struct kiobuf *iobuf; + struct mmsoftc *mm; + int error = 0; + struct mm_setinfo *set; + struct hd_struct *hd, *hd1; + int drive; + + rq = (struct mmrequest *) sp->sr_dev; + mm = rq->disk_info->softc; + drive = rq->disk_info->drive; + set = rq->disk_info->setinfo; + hd = &set->hd[MM_MINOR(drive, rq->part)]; + + if (rq->part) + hd1 = &set->hd[MM_MINOR(drive, 0)]; + else + hd1 = NULL; + + /* + * If a callback is in progress, don't retry the command + * now. "Return" it to the retry queue and it will get + * scheduled when the callback is complete. + */ + if (mm->mm_flags & (MM_NEED_CB | MM_HOLD)) { + mm_queue_retry(mm, rq); + return; + } + + if (mm_chkcond(mm, sp, 1, 0) == 1) + return; + + switch(sp->sr_status) { + case SC_GOOD: + if (sp->sr_scsi_status != ST_GOOD) { + if (sp->sr_scsi_status == ST_BUSY) + error = -EBUSY; + else + error = -EIO; + } + break; + + case SC_ALIGN: + error = -EFAULT; + /* deliberate fall thru */ + + default: + { + extern char *scsi_adaperrs_tab[]; + if(sp->sr_status < NUM_ADAP_ERRS) + mm_pmsg(mm, rq->part, "SCSI driver error: %s\n", + scsi_adaperrs_tab[sp->sr_status]); + else + mm_pmsg(mm, rq->part, "Unknown SCSI driver error %d\n", + sp->sr_status); + error = -EIO; + } + } + + MMSCLOCK(mm); + +#if MMSC_SARD + /* + * SARD disk accounting + */ + { + long starttime = mm->mm_iostart; + if (rq->cmd == READ) { + hd->rd_ticks += jiffies - starttime; + hd->rd_ios++; + if (hd1) { + hd1->rd_ticks += jiffies - starttime; + hd1->rd_ios++; + } + } + else { + hd->wr_ticks += jiffies - starttime; + hd->wr_ios++; + if (hd1) { + hd1->wr_ticks += jiffies - starttime; + hd1->wr_ios++; + } + } + } + disk_round_stats(hd); + hd->ios_in_flight--; + if (hd1) { + disk_round_stats(hd1); + hd1->ios_in_flight--; + } +#endif + + /* + * Update active queues. + */ + if (rq->av_back != NULL) + rq->av_back->av_forw = rq->av_forw; + if (rq->av_forw != NULL) + rq->av_forw->av_back = rq->av_back; + if (mm->mm_active == rq) + mm->mm_active = rq->av_forw; + + bytes_xferred = sp->sr_buflen - sp->sr_resid; + iobuf = rq->iobuf; + bh = rq->bh; + + mm->mm_rqactive--; + __mm_queue_release(mm); + __mm_free_request(mm, rq); + + mmsc_event_log(4, mm, "--------> finishing command", rq->sector, rq->count); + MMSCUNLOCK(mm); + if (iobuf) { + iobuf->errno = error; + iobuf->end_io(iobuf); + } + else while (bh != NULL) { + if (!error) { + if (bytes_xferred < bh->b_size) + error = EIO; + else + bytes_xferred -= bh->b_size; + } + nbh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, !error); + bh = nbh; + } +} + + +/* + * Retry requests when they get Busy statuses or certain Not Ready + * sense codes. + * Return whether or not the retry should be done now, has been + * scheduled for the future (via timeout), or is not to be done + * (either because retry count was exceeded or because retries are + * not to be done). + * Retval: + * 0 = no retry + * > 0 = retry necessary + * < 0 = retry scheduled + */ +static int +mm_busy_retry(struct mmsoftc *mm, struct scsi_request *sp, int async) +{ + int retry_cmd; + struct mmrequest *rq; + + rq = (struct mmrequest *) sp->sr_dev; + + /* + * If async is set, we are called from interrupt, and must use + * a timer rather than delay(). + */ + retry_cmd = rq->retry_count; + if (retry_cmd < MM_MAX_BUSY) + { + int intv = 1 << retry_cmd; + if (intv > MM_MAX_BUSY_INTV) + intv = MM_MAX_BUSY_INTV * HZ; + else + intv *= HZ; + + if (async) + { + rq->retry_count = retry_cmd + 1; + sp->sr_tag = 0; + init_timer(&rq->timer); + rq->timer.expires = jiffies + intv; + rq->timer.data = (unsigned long) sp; + rq->timer.function = (void (*)(unsigned long)) mm_do_retry; + add_timer(&rq->timer); + return -1; + } + else + { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(intv); + return 1; + } + } + return 0; +} + +/* + * Return values: + * 0: command should not be retried. + * 1: command should be/has been retried, depending on value of async + * If async set, command retry is scheduled if not too many retries. + * If not async, return value indicates whether to retry or not. + */ +static int +mm_chkcond(struct mmsoftc *mm, register scsi_request_t *sp, int async, int mute) +{ + int part; + int retval = 0; + int retry_cmd = 0; + int serious_err = 1; + char key = SC_NOSENSE; + struct mmrequest *rq; + + rq = (struct mmrequest *) sp->sr_dev; + part = rq->part; + + switch (sp->sr_status) + { + case SC_CMDTIME: + case SC_HARDERR: + case SC_PARITY: + /* + * Retry cmds that fail because of timeouts, hardware errors, + * or parity errors. + */ + retry_cmd = 1; + break; + + case SC_GOOD: + if (sp->sr_sensegotten > 0) + { + if ((sp->sr_sense[0] & 0x70) != 0x70) { + mm_pmsg(mm, part, + "invalid sense data, error cause unknown\n"); + retry_cmd = 1; + } + else if (sp->sr_sensegotten <= 2) { + mm_pmsg(mm, part, + "not enough sense data\n"); + retry_cmd = 1; + } + else { + key = sp->sr_sense[2] & 0xF; + if (key == SC_UNIT_ATTN) + serious_err = 0; +#ifndef DEBUG + else if (mm_user_printable_sense(mm, sp, mute)) +#endif + mm_print_sense(mm, sp, part); + + if (key == SC_NOT_READY) + { + /* + * ASC and ASQ are only valid if we received at + * least 14 bytes of sense data. + * If ASC is SC_NOTREADY (4) and ASQ is 0 or 2, + * then set the Need Start Unit flag, as long + * as the error is not for a Start Unit command. + * If the ASC/ASQ is 4/1, that means that the device + * is spinning up, so we treat the same as a BUSY + * SCSI status. + */ + if (sp->sr_sensegotten > 13 && + sp->sr_sense[12] == SC_NOTREADY) + { + uint8_t asq = sp->sr_sense[13]; + + if ((sp->sr_command[0] != 0x1B) && + (asq == 0 || asq == 2)) + { + MMSCLOCK(mm); + mm->mm_flags |= MM_NEEDSTART; + MMSCUNLOCK(mm); + if (async) { + mm_queue_retry(mm, rq); + } + return 1; + } + else if (asq == 1) + { + /* + * Some drives, the TOSHIBA CDROM + * in particular, will return + * NOT_READY to an I/O command for + * about 4 seconds following CD + * load or bus reset. + */ + retry_cmd = mm_busy_retry(mm, sp, async); + /* report 2nd, then every 4 times */ + if (retry_cmd && (rq->retry_count % 4 == 2)) + mm_pmsg(mm, part, "NOT READY; retrying\n"); + if (retry_cmd > 0) + serious_err = 0; + else if (retry_cmd < 0) + return 1; + else + mm_pmsg(mm, part, "NOT READY; giving up\n"); + } + } + } + + /* + * Retry commands that failed because of a unit + * attention, media error, hardware error, aborted + * command, or deferred errors. + * Retrying on unit attention may cause timeouts, + * but that's better than just letting async writes + * fail completely, which otherwise is quite likely + * to happen. + */ + else if (key == SC_MEDIA_ERR || key == SC_HARDW_ERR || + key == SC_CMD_ABORT || key == SC_UNIT_ATTN || + (sp->sr_sense[0] & 1)) + { + retry_cmd = 1; + } + } + + /* + * To ensure that sense key errors cause an error to + * be returned, we set SCSI status to what it really + * was if sense data indicates a serious problem. + * otherwise, if we recovered, we want to clear the + * scsi status, so we don't consider it an error in + * mm_intr(). + */ + sp->sr_scsi_status = (key==SC_ERR_RECOVERED)?ST_GOOD:ST_CHECK; + } + else if (sp->sr_scsi_status == ST_BUSY) { + /* retry up to 4 minutes, same reason as for startunit */ + retry_cmd = mm_busy_retry(mm, sp, async); + + /* report 2nd, then every 4 times */ + if (retry_cmd && (rq->retry_count % 4 == 2)) + mm_pmsg(mm, part, "BUSY; retrying\n"); + if (retry_cmd > 0) + serious_err = 0; + else if (retry_cmd < 0) + return 1; + else { /* give up, busy too long */ + mm_pmsg(mm, part, "Error: BUSY more than 4 minutes\n"); + } + } + else if (sp->sr_scsi_status == ST_CHECK) { + mm_pmsg(mm, part, "unexpected SCSI check condition status " + "(request sense failed)\n"); + retry_cmd = 1; + } + else if (sp->sr_scsi_status != ST_GOOD) { + mm_pmsg(mm, part, "unexpected SCSI status byte 0x%x\n", + sp->sr_scsi_status); + retry_cmd = 1; + } + break; + + case SC_ATTN: + /* + * We don't want to count the SC_ATTN against the retry limit, + * so retries are handled here. + */ + mm_dbg_pmsg(mm, 0, "SC_ATTN: retrying request %d\n", rq->retry_count); + if(async) { + mmsc_start(mm, rq, sp); + } + retval = 1; + break; + } + + if (retry_cmd) { + if (serious_err) + retry_cmd = rq->retry_count + 4; + else + retry_cmd = rq->retry_count + 1; + if (retry_cmd <= MM_MAX_RETRY) { + rq->retry_count = retry_cmd; + sp->sr_tag = 0; +#ifndef DEBUG + if ((sp->sr_status == SC_GOOD) && serious_err) +#endif + mm_pmsg(mm, part, " retrying request\n"); + if(async) { + mmsc_start(mm, rq, sp); + } + retval = 1; + } + else if (sp->sr_status == SC_GOOD) { + if (serious_err) + mm_pmsg(mm, part, " retries exhausted\n"); + else + mm_pmsg(mm, part, " failure, retries exhausted - key %d" + " status %d\n", key, sp->sr_scsi_status); + } + } + return retval; +} + +/* + * These functions start and get completion of driver generated commands. + */ +static void +mm_rcvcmd(struct scsi_request *sp) +{ + struct mmsoftc *mm; + + mm = ((struct mmrequest *) sp->sr_dev)->disk_info->softc; + up(&mm->mm_done); +} + +static void +mm_sendcmd(register struct mmsoftc *mm, struct scsi_request *sp) +{ + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + + down(&mm->mm_sema); + sp->sr_notify = mm_rcvcmd; + SLI_COMMAND(lun_info)(sp); + down(&mm->mm_done); + up(&mm->mm_sema); +} + +/* + * General disk command. + * + * Returns 1 if unsuccessful; + * 0 if successful + */ +static int +mm_cmd(struct mmsoftc *mm, u_char *cmd_buffer, int cmd_size, + u_int timeoutval, caddr_t addr, size_t len, int rw) +{ + struct mmrequest *rq; + scsi_request_t *sp; + int stat; + DECLARE_WAITQUEUE(wait, current); + + /* + * Wait if commands are to be held. Check twice, in case + * someone beats us to it. + */ + + again: + if (mm->mm_flags & MM_HOLD) { + MMSCLOCK(mm); + if (mm->mm_flags & MM_HOLD) { + mm->mm_hold_count++; + MMSCUNLOCK(mm); + down(&mm->mm_hold); + } + else + MMSCUNLOCK(mm); + } + /* + * Check if callback is needed. If so, attempt to do + * it unless someone already beat us to it. + */ + if (mm->mm_flags & MM_NEED_CB) { + MMSCLOCK(mm); + if (mm->mm_flags & MM_NEED_CB) { + mm_callback_backend(mm, 1); + /* MMSCUNLOCK done by backend */ + } + else { + MMSCUNLOCK(mm); + goto again; + } + } + if (mm->mm_flags & MM_WONT_START) + return 1; + + rq = mm_get_request(mm, rw); + mm_request_init(rq, mm->mm_disk_info); + rq->part = 0; + + /* + * Add to mm_wait queue. When commands complete, if there is + * something on the wait queue, it will wake us up here, rather + * than issuing a new block/char R/W request. + */ + add_wait_queue_exclusive(&mm->mm_wait, &wait); + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + MMSCLOCK(mm); + if (mm->mm_curq < mm->mm_qdepth) { + mm->mm_curq++; + MMSCUNLOCK(mm); + break; + } + MMSCUNLOCK(mm); + schedule(); + } + remove_wait_queue(&mm->mm_wait, &wait); + current->state = TASK_RUNNING; + + sp = &rq->sr; + + do { + /* + * If a callback is in progress, don't (re)try the + * command now. Try to start the callback or wait for + * it to complete before trying again. + */ + if (mm->mm_flags & (MM_NEED_CB | MM_HOLD)) { + mm_queue_release(mm); + mm_free_request(mm, rq); + goto again; + } + + memcpy(sp->sr_command, cmd_buffer, cmd_size); + sp->sr_cmdlen = cmd_size; + if (rw == READ) + sp->sr_flags |= SRF_DIR_IN; + if (addr != NULL) { + sp->sr_flags |= SRF_MAP; +#ifndef CONFIG_IA64 + if (rw == READ) + dma_cache_inv(addr, len); + else + dma_cache_wback(addr, len); +#endif + } + sp->sr_timeout = timeoutval; + sp->sr_buffer = (u_char *)addr; + sp->sr_buflen = len; + mm_sendcmd(mm, sp); + + } while (mm_chkcond(mm, sp, 0, 0) == 1); + + stat = (sp->sr_status || sp->sr_scsi_status); + + mm_queue_release(mm); + mm_free_request(mm, rq); + + return stat; +} + +/* + * Print interesting sense data. + * Extended sense data is all that is allowed. + */ +static void +mm_print_sense(struct mmsoftc *mm, struct scsi_request *sp, int part) +{ + register char *key_msg, *add_msg; + register u_int sense_key, add_sense = 0; + u_int asq = 0; + u_char *sense_data = sp->sr_sense; + u_char sense_length = sp->sr_sensegotten; + u_int sense_lba, lba; + + /* Extended sense format */ + sense_key = sense_data[2] & 0xf; + if (sense_data[2] & 0x20) + mm_pmsg(mm, part, "unsupported block size requested\n"); + + if (sense_length > 12) + add_sense = sense_data[12]; + if (sense_length > 13) + asq = sense_data[13]; + + key_msg = scsi_key_msgtab[sense_key]; + if (add_sense == 0) + add_msg = NULL; + else if (add_sense < SC_NUMADDSENSE) + add_msg = scsi_addit_msgtab[add_sense]; + else { + /* + * 0x89 is vendor specific; + * This is the Toshiba XM3332 meaning. + */ + if(mm->mm_inqtyp[0] == XSCSI_PT_CDROM && add_sense == 0x89) + add_msg = "Tried to read audio track as data"; + else + add_msg = NULL; + } + + if (sense_key != SC_NOSENSE && sense_key != SC_UNIT_ATTN && + sense_key != SC_ERR_RECOVERED && sense_key != SC_NOT_READY) + mm_pmsg(mm, part, "[Alert] %s", key_msg); + else + mm_pmsg(mm, part, "%s", key_msg); + printk( ": %s (asc=0x%x, asq=0x%x)", add_msg ? add_msg : "", + add_sense, asq); + if(sense_data[0] & 1) /* in case buffer writes enabled! */ + printk( " (deferred error)"); + + /* SCSI-2 drives give more info if SKSV bit set */ + if(sense_length > 17 && sense_data[15] & 0x80) { + printk( ", (%s byte %d)", + (sense_data[15] & 0x40) ? "cmd" : "data", + (sense_data[16] << 8) | (sense_data[17])); + if(sense_data[15] & 0x8) + printk( " (bit %d)", + sense_data[15] & 0x7); + } + + /* If the valid bit is set, bytes 3-6 give addition info */ + if((sense_data[0] & 0x80) && (sense_length > 6)) { + struct mm_setinfo *set; + struct hd_struct *hd; + int drive; + + drive = mm->mm_disk_info->drive; + set = mm->mm_disk_info->setinfo; + hd = &set->hd[MM_MINOR(drive, part)]; + + sense_lba = (sense_data[3] << 24) | + (sense_data[4] << 16) | + (sense_data[5] << 8) | + (sense_data[6]); + + lba = (sense_lba - + (hd->start_sect >> (log2(mm->mm_blksz) - 9))); + /* + * Report both the block in the partition, and the + * disk block #, because fx wants to spare by disk + * block #, not relative to partition... + */ + printk( ", Block #%d", lba); + if(lba != sense_lba) + printk( " (%d)", sense_lba); + } +#ifdef SAMMY + if (sense_length > 31) { + printf(" addsense 18-31:"); + for (asq = 18; asq < 32; asq++) + printf(" 0x%x", sense_data[asq]); + } +#endif + + if (sense_key == SC_ILLEGALREQ) { + int i; + printk( " CDB:"); + for (i = 0; i < sp->sr_cmdlen; i++) + printk( " %x", sp->sr_command[i]); + } + printk( "\n"); +} + +/* + * This is used to retry a command when a drive returns busy; called from + * a timer. + */ +static void +mm_do_retry(register scsi_request_t *sp) +{ + struct mmsoftc *mm; + struct mmrequest *rq; + + rq = (struct mmrequest *) sp->sr_dev; + mm = rq->disk_info->softc; + mmsc_start(mm, rq, sp); +} + + +/* + * Return drive capacity in blocks. + */ +static unsigned int +mm_readcap(struct mmsoftc *mm) +{ + unsigned int *drivecap; + unsigned int ret; + + drivecap = kmem_alloc(MM_DRIVECAP_SIZE, KM_SLEEP | KM_CACHEALIGN); + + /* mm_drivecap is dynamically allocated for proper cache-alignment + since it is used as a DMA buffer below */ + + if (mm_cmd(mm, mm_readcapacity, SC_CLASS1_SZ, MMSC_TIMEOUT, + (caddr_t) drivecap, MM_DRIVECAP_SIZE, READ)) { + ret = 0; + goto out; + } + + /* increment by one to get capacity, not last block */ + ret = be32_to_cpu(drivecap[0]) + 1; + mm->mm_drivecap = ret; +out: + kmem_free(drivecap, MM_DRIVECAP_SIZE); + return ret; +} + + +/* + * This is used at open time to get the blksize, before the vh is read. + * After the vh is read, or when the vh ioctl's are used, the blksz + * from the vh is used. This routine is also called after the blocksize + * is potentially changed via ioctl. + * Since not all devices support the FORMAT page, ask for all pages; + * Uses the value from the block descr if supplied, since that + * location is correct for all drives, not just ccs or scsi2. If not, + * use the value from the format page. + * If modesense is successful, set or clear the WRTPROT bit. This is + * mainly for early detection of devices that are either write protected, + * or don't support the write command (such as CDROM). Otherwise may + * get SCSI errors. + * + * The return value is whether or not the actual blocksize changed from the + * blocksize value kept in the vh, even though at this actual moment it + * is not used. -mac +*/ +static int +mm_getblksz(register struct mmsoftc *mm) +{ + struct mode_sense_data *msd=NULL; + u_char sense_cmd[SC_CLASS0_SZ]; + int blocksize = 0; + int return_value; + + msd = kmem_alloc(sizeof(*msd), KM_SLEEP | KM_CACHEALIGN); + + memcpy(sense_cmd, mm_mode_sense, sizeof(sense_cmd)); + sense_cmd[2] = msd->mm_pages.common.pg_code = ALL|CURRENT; + sense_cmd[4] = msd->mm_pages.common.pg_len = + sizeof(msd->mm_pages.common.pg_maxlen); + + if(mm_cmd(mm, sense_cmd, SC_CLASS0_SZ, MMSC_TIMEOUT, + (caddr_t)msd, sense_cmd[4], READ)) + goto failure; + + MMSCLOCK(mm); + if(msd->wprot) + mm->mm_flags |= MM_WRTPROT; + else + mm->mm_flags &= ~MM_WRTPROT; + MMSCUNLOCK(mm); + + if(msd->bd_len && (msd->block_descrip[5] || + msd->block_descrip[6] || msd->block_descrip[7])) + blocksize = ((unsigned)msd->block_descrip[5]<<16) + + ((unsigned)msd->block_descrip[6]<<8) + msd->block_descrip[7]; + else { /* see if format page is there */ + u_char *d = (u_char *)msd, *maxd = d + msd->sense_len; + d += msd->bd_len + 4; /* after setting maxd! */ + while(d < maxd) { + int i; + if(((*d) & ALL) == DEV_FORMAT) { + blocksize = + (((uint)((struct dev_format *)d)->f_bytes_sec[0])<<8) + + ((struct dev_format *)d)->f_bytes_sec[1]; + break; + } + i = d[1] + 2; /* skip to next page; +2 for hdr */ + d += i; + } + } + +failure: + if(blocksize == 0) { + if (mm->mm_blksz != 0) + mm_dbg_pmsg(mm, 0, + "blocksize changed from %d to %d\n", + mm->mm_blksz,blocksize); + blocksize = MM_BLK_SZ; /* best guess... */ + } + if ((return_value = (mm->mm_blksz != blocksize)) != 0) { + if (mm->mm_blksz != 0) + mm_dbg_pmsg(mm, 0, + "blocksize changed from %d to %d\n", + mm->mm_blksz,blocksize); + mm->mm_blksz = blocksize; + } + kmem_free(msd, sizeof(*msd)); + + return return_value; +} + + +/* + * Receives callback notification. Currently only registered for CDROM + * devices. + */ +static void +mm_callback_frontend(vertex_hdl_t lun_vhdl, uint8_t *sense) +{ + struct mmsoftc *mm; + devfs_handle_t de; + struct mm_partinfo *partinfo; + + /* + * We only care about UNIT ATTENTION + */ + if ((sense[2] & 0x0f) == 0x06) + { + de = devfs_find_handle(lun_vhdl, "disc", 0, 0, 0, 0); + partinfo = devfs_get_info(de); + mm = partinfo->diskinfo->softc; + + /* + * Make sure block size has been determined. If the + * blocksize is unknown at this point, don't do a + * callback !! + */ + if (mm->mm_blksz == 0) + return; + + /* + * Turn on the "need to set blocksize" flag; + * We take the lazy approach in that the command + * will be issued prior to the next regular command + * that would be issued. + */ + MMSCLOCK(mm); + mm->mm_flags |= MM_NEED_BLKSZ; + MMSCUNLOCK(mm); + } +} + +/* + * This routine is the backend of the lazy callback implementation, + * and is used for two purposes: + * 1. to set CD-ROM blocksize back to what it was prior to Unit Attention + * 2. to issue a start unit to a drive that is spun down + * + * Called with the mm_lock held. If wait is set, the lock will be released + * prior to calling drive_acquire, and will return with the lock released. + * + * If wait is set, we sleep until command is complete; otherwise command + * is scheduled and we return. + * Return Value: + * 1 - the command was successfully scheduled/completed + * 0 - the command was not scheduled/completed. + */ +static int +mm_callback_backend(struct mmsoftc *mm, int wait) +{ + struct mode_sense_data *msd=NULL; + unsigned char *select_cmd; + struct scsi_request *sp; + scsi_lun_info_t *lun_info; + int temp; + int blksz = mm->mm_blksz; + ushort action; + + select_cmd = (unsigned char [SC_CLASS0_SZ]) + { [0] = 0x15, [1] = 0x10, [4] = 12 }; + + if (mm->mm_flags & MM_NEEDSTART) + action = MM_NEEDSTART; + else + action = MM_NEED_BLKSZ; + mm->mm_curq++; + + if (wait) { + mm->mm_flags |= MM_HOLD; + mm->mm_flags &= ~action; + MMSCUNLOCK(mm); + } + + mm_request_init(mm->mm_rq, mm->mm_disk_info); + sp = &mm->mm_rq->sr; + + /* + * There is a 12-byte buffer in the mmsoftc structure for this + * mode select. The mode_sense_data structure is bigger, but no + * pages are used in this case, so only 12 bytes are required. + */ + if (action == MM_NEED_BLKSZ) { + msd = (struct mode_sense_data *) mm->msel_bd; /* only 12 bytes used */ + msd->bd_len = sizeof(msd->block_descrip); /* 1 descrip */ + msd->block_descrip[5] = (u_char)(blksz >> 16); + msd->block_descrip[6] = (u_char)(blksz >> 8); + msd->block_descrip[7] = (u_char)blksz; + } + + temp = 0; + do { + sp->sr_cmdlen = SC_CLASS0_SZ; + + if (action == MM_NEED_BLKSZ) { + memcpy(sp->sr_command, select_cmd, sp->sr_cmdlen); + sp->sr_buffer = (u_char *)msd; + sp->sr_buflen = select_cmd[4]; + sp->sr_flags |= SRF_FLUSH; + sp->sr_timeout = MMSC_TIMEOUT; + } + else /* (action == MM_NEEDSTART) */ { + memcpy(sp->sr_command, mm_startunit, SC_CLASS0_SZ); + sp->sr_buflen = 0; + /* + * Allow 240 seconds; based on drives that may have spinup delays + * set based on ID; ID 15 waits 15 * intv, where intv is typically + * 10-15 seconds; also allow a bit of slop. + */ + sp->sr_timeout = 240 * HZ; + if (temp++) + mm_pmsg(mm, 0, "Error on device spin up," + " retrying\n"); + else + mm_pmsg(mm, 0, "Device not ready, " + "spinning up\n"); + } + + if (wait) + mm_sendcmd(mm, sp); + else { + mm->mm_flags |= MM_HOLD; + mm->mm_flags &= ~action; + MMSCUNLOCK(mm); + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + sp->sr_notify = mm_callback_intr; + SLI_COMMAND(lun_info)(sp); + MMSCLOCK(mm); + return 1; + } + } while (mm_chkcond(mm, sp, 0, 0) == 1); + + temp = !(sp->sr_status || sp->sr_scsi_status); + + /* + * Release those waiting for callback to complete + */ + MMSCLOCK(mm); + if (action == MM_NEEDSTART) { + if (temp) { + mm->mm_flags &= ~MM_WONT_START; + mm_pmsg(mm, 0, "Device spun up successfully\n"); + } + else { + mm_pmsg(mm, 0, "Device spin up failed, unable" + " to use device -- corrective action necessary\n"); + mm->mm_flags |= MM_WONT_START; + } + } + mm->mm_flags &= ~MM_HOLD; + __mm_queue_release(mm); + while (mm->mm_hold_count != 0) { + up(&mm->mm_hold); + mm->mm_hold_count--; + } + MMSCUNLOCK(mm); + + return temp; +} + +static void +mm_callback_intr(scsi_request_t *sp) +{ + register struct mmsoftc *mm; + scsi_lun_info_t *lun_info; + ushort action; + + if (sp->sr_command[0] == 0x1B) + action = MM_NEEDSTART; + else + action = MM_NEED_BLKSZ; + + mm = ((struct mmrequest *) sp->sr_dev)->disk_info->softc; + if (mm_chkcond(mm, sp, 0, 0) == 1) { + lun_info = scsi_lun_info_get(sp->sr_lun_vhdl); + if (action == MM_NEEDSTART) + mm_pmsg(mm, 0, + "Error spinning up device, retrying\n"); + SLI_COMMAND(lun_info)(sp); + return; + } + + MMSCLOCK(mm); + /* + * Check to see if callback is for Start Unit or Mode Select. + */ + if (action == MM_NEEDSTART) { + if (sp->sr_status || sp->sr_scsi_status) { + mm_pmsg(mm, 0, "Unable to spin up device, " + "device unusable -- corrective action necessary\n"); + mm->mm_flags |= MM_WONT_START; + } + else { + mm->mm_flags &= ~MM_WONT_START; + mm_pmsg(mm, 0, "Device successfully spun up\n"); + } + } + + /* + * Release those waiting for callback to complete + */ + mm->mm_flags &= ~MM_HOLD; + __mm_queue_release(mm); + while (mm->mm_hold_count != 0) { + up(&mm->mm_hold); + mm->mm_hold_count--; + } + MMSCUNLOCK(mm); + return; +} + + +#ifndef DEBUG +/* + * In some cases we don't want the sense to be printed, e.g. a "medium + * not present" when the device is a CDROM. + */ +int +mm_user_printable_sense(struct mmsoftc *mm, register scsi_request_t *sp, int mute) +{ + int rc = 1; + u_char key = sp->sr_sense[2] & 0xF; + u_char addsense = sp->sr_sense[12]; + uint slen = sp->sr_sensegotten; + + if (mm->mm_inqtyp[1] & 0x80) { /* is removeable */ + switch (key) { + case SC_NOT_READY: + if (slen > 12 && addsense == SC_MEDIA_ABSENT) { /* Medium not present */ + rc = 0; + } + break; + case SC_BLANKCHK: + /* This is to suppress sense data printout associated + with read command issued internally by mmsc from + mmscopen while attempting to read volume header + */ + if (addsense == 0x64 && mute) { + rc = 0; + } + break; + default: + break; + } + } + /* + * Don't report 'recovered' errors on defect list; it means the drive doesn't + * support the requested format, and is responding with it's default format. + * We see this when we ask for logical block format, but drive doesn't support + * it, for example. We don't want to print that; fx will just fall back on + * alternate format. See bug #554444. IBM DDRS-39130W is one of those drives. + */ + else if (key==SC_ERR_RECOVERED && (addsense == 0x1c || addsense == SC_DEFECT_ERR)) + rc = 0; + /* + * Don't report 'drive not ready' if the command issued was + * a 'test unit ready'. + */ + else if (sp->sr_command[0] == 0 && addsense == SC_NOTREADY) + rc = 0; + + return(rc); +} +#endif + +struct file_operations mmsc_char_ops = { + read: mmsc_read, + write: mmsc_write, + ioctl: mmsc_raw_ioctl, + open: mmsc_raw_open, + release: mmsc_raw_close, +}; + +static struct block_device_operations mmsc_blk_ops = { + open: mmsc_block_open, + release: mmsc_block_close, + ioctl: mmsc_block_ioctl, +#if 0 + check_media_change: mmsc_check_media_change, + revalidate: mmsc_revalidate, +#endif +}; + +static struct gendisk mm_gendisk[MM_SETS] = +{ + [0 ... MM_SETS - 1] = + { + minor_shift: MM_DISK_SHIFT, + max_p: 1 << MM_DISK_SHIFT, + fops: &mmsc_blk_ops + } +}; + +void +mmscinit(void) +{ + int i; + + for (i = 0; i < MM_SETS; i++) + add_gendisk(&mm_gendisk[i]); + + mmrequest_cachep = + kmem_cache_create("mmsc_requests", sizeof(struct mmrequest), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + +#ifdef CONFIG_KDB + { static void mmsc_kdb_init(void); mmsc_kdb_init(); } +#endif +} + + +#ifdef CONFIG_KDB +#undef printf +#include +#include + +static void +mm_dump_disks(void) +{ + int major, disk; + devfs_handle_t de; + struct mm_partinfo *partinfo; + struct mm_diskinfo *diskinfo; + struct mmsoftc *mm; + char buffer[128]; + int index; + + for (major = 0; major < 256; major++) + for (disk = 0; disk < 1 << (MINORBITS - MM_DISK_SHIFT); disk++) { + de = mmsc_de[major][disk]; + if (de == NULL) + continue; + partinfo = devfs_get_info(de); + diskinfo = partinfo->diskinfo; + mm = diskinfo->softc; + index = devfs_generate_path(de, buffer, 128); + if (index >= 0) + kdb_printf("(%d/%d) %s softc is 0x%p\n", + major, disk, &buffer[index], (void *) mm); + else + kdb_printf("(%d/%d) no-name softc is 0x%p\n", + major, disk, (void *) mm); + } +} + + +#if MMSC_EVENT_LOG +static void +mm_event_dump(struct mmsoftc *mm) +{ + int i = mm->mm_event_rotor; + int end; + + end = mm->mm_event_rotor - 1; + if (end == -1) + end = MMSC_EVENT_LOG_SIZE - 1; + while (i != end) { + if (mm->mm_event_buffer[i].string) + kdb_printf(" %s (%u, %u)\n", mm->mm_event_buffer[i].string, + mm->mm_event_buffer[i].aval, mm->mm_event_buffer[i].bval); + if (++i == MMSC_EVENT_LOG_SIZE) + i = 0; + } +} +#else +#define mm_event_dump(x) +#endif + +#define MMRQ_PER_LINE 4 +static void +mm_dump_queue(struct mmrequest *rq) +{ + int tmp; + + tmp = MMRQ_PER_LINE; + while (rq != NULL) { + kdb_printf(" %p(%u/%u/%d)", (void *) rq, rq->sector, rq->count, rq->merges); + rq = rq->av_forw; + if (--tmp == 0) { + kdb_printf("\n"); + tmp = MMRQ_PER_LINE; + } + } + if (tmp != MMRQ_PER_LINE) + kdb_printf("\n"); +} + +static int +mmsoftc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct mmsoftc *mm; + int tmp; + int nextarg; + long offset = 0; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + tmp = kdbgetaddrarg(argc, argv, &nextarg, (kdb_machreg_t *) &mm, &offset, NULL, regs); + if (tmp) + return tmp; + if (mm == NULL) { + mm_dump_disks(); + return 0; + } + + kdb_printf("mmsoftc structure at 0x%p\n", (void *) mm); + + mm_event_dump(mm); + + kdb_printf("mm_iostart %lu mm_blksz %u mm_opencount %d mm_flags 0x%x mm_plug %d\n", + mm->mm_iostart, mm->mm_blksz, mm->mm_opencount, mm->mm_flags, mm->mm_plug); + kdb_printf("mm_inqtyp 0x%p mm_rq 0x%p mm_numrq %d\n", + (void *) mm->mm_inqtyp, (void *) mm->mm_rq, + mm->mm_request_queue.rq[0].count); + kdb_printf("&mm_wait 0x%p &mm_sema 0x%p &mm_done 0x%p\n", + (void *) &mm->mm_wait, (void *) &mm->mm_sema, (void *) &mm->mm_done); + kdb_printf("&mm_hold 0x%p mm_hold_count %d mm_retry 0x%p\n", + (void *) &mm->mm_hold, mm->mm_hold_count, (void *) mm->mm_retry); + kdb_printf("&mm_request_queue 0x%p mm_target_info 0x%p mm_cb 0x%p\n", + (void *) &mm->mm_request_queue, (void *) mm->mm_target_info, (void *) mm->mm_cb); + + kdb_printf("mm_queue at 0x%p seq_next %u seq_count %u\n", + (void *) &mm->mm_queue, mm->mm_queue.seq_next, mm->mm_queue.seq_count); + + kdb_printf("read queue head/tail 0x%p/0x%p\n", + (void *) mm->mm_queue.io_head, (void *) mm->mm_queue.io_tail); + mm_dump_queue(mm->mm_queue.io_head); + + kdb_printf("write queue head/tail 0x%p/0x%p\n", + (void *) mm->mm_queue.delwri_head, (void *) mm->mm_queue.delwri_tail); + mm_dump_queue(mm->mm_queue.delwri_head); + + kdb_printf("active queue: (%d/%d commands - %d requests in flight)\n", + mm->mm_curq, mm->mm_qdepth, mm->mm_rqactive); + mm_dump_queue(mm->mm_active); + + return 0; +} + +static void +mmsc_kdb_init(void) +{ + kdb_register("mmsoftc", mmsoftc, "", "dump mmsoftc structure", 0); +} +#endif + +/************************************************************************************/ +/* Additions to mmsc.c for cdrom support + * This code registers the device with cdrom.c and adds functions for ioctls + * in cdrom.c + ************************************************************************************/ + + +static inline +int msf_to_lba (byte m, byte s, byte f) +{ + return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; +} + +static inline +void lba_to_msf (int lba, byte *m, byte *s, byte *f) +{ + lba += CD_MSF_OFFSET; + lba &= 0xffffff; /* negative lbas use only 24 bits */ + *m = lba / (CD_SECS * CD_FRAMES); + lba %= (CD_SECS * CD_FRAMES); + *s = lba / CD_FRAMES; + *f = lba % CD_FRAMES; +} + +static int +mmsc_cdrom_open(struct cdrom_device_info *cdi, int purpose) +{ +// Called from cdrom_open...doesnt do anything + return 0; +} + +static void +mmsc_cdrom_release(struct cdrom_device_info *cdi) +{ +// Called from cdrom_close...doesnt do anything + return; +} + +static int +mmsc_cdrom_drive_status(struct cdrom_device_info *cdi, int slot) +{ +// Send Test Unit Ready +// Check ide_cdrom_drive_status() for various types of return values if SENSE data +// return 0 if successful + struct mmsoftc *mm=NULL; + char cmd_buf[SC_CLASS0_SZ] = {0,0,0,0,0,0}; + + mm =((struct mmsc_cdrom_info *)cdi->handle)->partinfo->diskinfo->softc; + if (mm==NULL) { + printk("mmsc_cdrom_drive_status() : mm = NULL\n"); + return -EINVAL; + } + + if (mm_cmd(mm,cmd_buf,SC_CLASS0_SZ,MMSC_TIMEOUT,NULL,0,0)) { + MMSC_CDROM_STATE_FLAGS((struct mmsc_cdrom_info *)cdi->handle).toc_valid = 0; + return CDS_TRAY_OPEN; + } + return CDS_DISC_OK; +} + +/* + * This function checks to see if the media has been changed in the + * CDROM drive. It is possible that we have already sensed a change, + * or the drive may have sensed one and not yet reported it. We must + * be ready for either case. This function always reports the current + * value of the changed bit. If flag is 0, then the changed bit is reset. + * This function could be done as an ioctl, but we would need to have + * an inode for that to work, and we do not always have one. + */ +static int +mmsc_cdrom_media_changed(struct cdrom_device_info *cdi, int slot) +{ + // Send a Test Unit Ready & Get Capacity command + // return -EINVAL if its not possible to check + // return 1 => Changed + // return 0 => Not Changed + return 1; +} + +static int +mmsc_cdrom_tray_move(struct cdrom_device_info *cdi, int position) +{ + // if position==0: cdrom_close (byte 4 -> 0x03) + // else : cdrom_eject (byte 4 -> 0x02) + // HINT :- Use the START/STOP UNIT Cmd (0x1b) + // return 0 if successful -EIO or -E if failed + + struct mmsoftc *mm=NULL; + uint8_t cmd_buf[SC_CLASS0_SZ]={0x1B,0,0,0,0,0}; + + mm =((struct mmsc_cdrom_info *)cdi->handle)->partinfo->diskinfo->softc; + if (mm==NULL) { + printk("mmsc_cdrom_tray_move() : mm == NULL\n"); + return -EINVAL; + } + + cmd_buf[4] = ( position == 0 ) ? 0x03 /* close */ : 0x02 /* eject */; + + return (mm_cmd(mm,cmd_buf,SC_CLASS0_SZ,MMSC_TIMEOUT,NULL,0,0)); +} + +static int +mmsc_cdrom_lock_door(struct cdrom_device_info *cdi, int lock) +{ + // if (lock) : Lock the door + // else : Unlock the door + // HINT: Use Prevent/Allow Medium Removal (0x1e) + // return 0 if successful + + struct mmsoftc *mm=NULL; + uint8_t cmd_buf[SC_CLASS0_SZ]={0x1E,0,0,0,0,0}; + + mm =((struct mmsc_cdrom_info *)cdi->handle)->partinfo->diskinfo->softc; + if (mm==NULL) { + printk("mmsc_cdrom_lock_door() : mm == NULL\n"); + return -EINVAL; + } + + cmd_buf[4] = (lock) ? 1 /* lock*/ : 0 /* unlock */; + + return (mm_cmd(mm,cmd_buf,SC_CLASS0_SZ,MMSC_TIMEOUT,NULL,0,0)); +} + +static int +mmsc_cdrom_select_speed(struct cdrom_device_info *cdi, int speed) +{ + // if speed==0 speed = 0xffff + // else speed *= 177 + // byte[2] = (speed >> 8) & 0xff; + /* Read Drive speed in kbytes/second LSB */ + // byte[3] = speed & 0xff; + + // IF CD-R or CD-RW or DVD-R then set WRITE Speed TOO + /* Write Drive speed in kbytes/second MSB */ + // pc.c[4] = (speed >> 8) & 0xff; + /* Write Drive speed in kbytes/second LSB */ + // pc.c[5] = speed & 0xff + + // HINT : Use Set CD-ROM Speed cmd (0xBB) + // return 0 if successful + + struct mmsoftc *mm=NULL; + + uint8_t cmd_buf[SC_CLASS0_SZ]={0xBB,0,0,0,0,0}; + + mm =((struct mmsc_cdrom_info *)cdi->handle)->partinfo->diskinfo->softc; + if (mm==NULL) { + printk("mmsc_cdrom_select_speed() : mm == NULL\n"); + return -EINVAL; + } + + cmd_buf[2] = (uint8_t) ((speed >> 8) & 0xFF); + cmd_buf[3] = (uint8_t) (speed & 0xFF); + + return (mm_cmd(mm,cmd_buf,SC_CLASS0_SZ,MMSC_TIMEOUT,NULL,0,0)); +} + +static int mmsc_cdrom_read_tocentry(struct mmsoftc *mm, int trackno, int msf_flag, int format, caddr_t addr, size_t len) +{ + uint8_t cmd_buf[SC_CLASS1_SZ] = {0x43,0,0,0,0,0,0,0,0,0}; + + cmd_buf[6] = trackno; + cmd_buf[7] = (len >> 8); + cmd_buf[8] = (len & 0xFF); + cmd_buf[9] = (format << 6); + + if (msf_flag) + cmd_buf[1] = 2; + + return (mm_cmd(mm,cmd_buf,SC_CLASS1_SZ,MMSC_TIMEOUT,addr,len,READ)); + +} + +/* Try to read the entire TOC for the disk into our internal buffer. */ +static int mmsc_cdrom_read_toc(struct mmsc_cdrom_info *info) +{ + int stat,ntracks,i; + struct atapi_toc *toc=info->toc; + struct mmsoftc *mm=NULL; + struct { + struct atapi_toc_header hdr; + struct atapi_toc_entry ent; + } ms_tmp; + + mm = info->partinfo->diskinfo->softc; + + if (mm==NULL) { + printk("mmsc_cdrom_read_toc() : mm == NULL \n"); + return -EINVAL; + } + + if (toc == NULL) { + /* Try to allocate space. */ + toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), GFP_KERNEL); + info->toc = toc; + if (toc == NULL) { + printk ("%s: No cdrom TOC buffer!\n", (&(info->devinfo))->name); + return -ENOMEM; + } + } + + /* First read just the header, so we know how long the TOC is. */ + stat = mmsc_cdrom_read_tocentry(mm,0,1,0,(caddr_t)&toc->hdr,sizeof(struct atapi_toc_header)); + if (stat) return stat; + + ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; + if (ntracks <= 0) + return -EIO; + + if (ntracks > MAX_TRACKS) + ntracks = MAX_TRACKS; + + stat = mmsc_cdrom_read_tocentry(mm, toc->hdr.first_track, 1, 0, (caddr_t)&toc->hdr, sizeof(struct atapi_toc_header) + (ntracks + 1)*sizeof(struct atapi_toc_entry)); + + + if (stat && toc->hdr.first_track > 1) { + /* Cds with CDI tracks only don't have any TOC entries, + despite of this the returned values are + first_track == last_track = number of CDI tracks + 1, + so that this case is indistinguishable from the same + layout plus an additional audio track. + If we get an error for the regular case, we assume + a CDI without additional audio tracks. In this case + the readable TOC is empty (CDI tracks are not included) + and only holds the Leadout entry. Heiko Eißfeldt + ---- Above text copied from drivers/ide/ide-cd.c : aniket 8/7/2002 ---- + */ + + ntracks = 0; + stat = mmsc_cdrom_read_tocentry(mm, CDROM_LEADOUT, 1, 0, (caddr_t)&toc->hdr, sizeof(struct atapi_toc_header) + (ntracks + 1)*sizeof(struct atapi_toc_entry)); + if (stat) + return stat; + + toc->hdr.first_track = CDROM_LEADOUT; + toc->hdr.last_track = CDROM_LEADOUT; + } + + if (stat) + return stat; + + // Endian issue + toc->hdr.toc_length = ntohs(toc->hdr.toc_length); + + for (i=0;i<=ntracks;i++) { + toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute, + toc->ent[i].addr.msf.second, + toc->ent[i].addr.msf.frame); + } + + /* Read the multisession information. */ + if (toc->hdr.first_track != CDROM_LEADOUT) { + stat = mmsc_cdrom_read_tocentry(mm,0,1,1,(caddr_t)&ms_tmp,sizeof(ms_tmp)); + if (stat) + return stat; + } else { + ms_tmp.ent.addr.msf.minute = 0; + ms_tmp.ent.addr.msf.second = 2; + ms_tmp.ent.addr.msf.frame = 0; + ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT; + } + + toc->last_session_lba = msf_to_lba (ms_tmp.ent.addr.msf.minute, ms_tmp.ent.addr.msf.second, ms_tmp.ent.addr.msf.frame); + + toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); + + MMSC_CDROM_STATE_FLAGS (info).toc_valid = 1; + + return 0; + +} + +static int +mmsc_cdrom_get_last_session(struct cdrom_device_info *cdi, + struct cdrom_multisession *ms_info) +{ + // HINT : Use Read TOC Cmd (0x43) + // Check the "cdrom_read_toc() " func + + // We need to set : + // ms_info->addr.lba = toc->last_session_lba; + // ms_info->xa_flag = toc->xa_flag; + // return 0 on success + + struct mmsc_cdrom_info *info=NULL; + struct atapi_toc *toc=NULL; + int ret=0; + + info =((struct mmsc_cdrom_info *)cdi->handle); + + if ((ret = mmsc_cdrom_read_toc(info))) { + return ret; + } + + toc = info->toc; + ms_info->addr.lba = toc->last_session_lba; + ms_info->xa_flag = toc->xa_flag; + + return 0; +} + +static int +mmsc_cdrom_read_subchannel(struct mmsoftc *mm, int format, caddr_t addr, size_t len) +{ + uint8_t cmd_buf[SC_CLASS1_SZ] = {0x42,0,0,0,0,0,0,0,0,0}; + + cmd_buf[1] = 2; // MSF addressing + cmd_buf[2] = 0x40; // request subQ data + cmd_buf[3] = format; + cmd_buf[7] = (len >> 8); + cmd_buf[8] = (len & 0xFF); + + return (mm_cmd(mm,cmd_buf,SC_CLASS1_SZ,MMSC_TIMEOUT,addr,len,READ)); +} + +static int +mmsc_cdrom_play_audio(struct mmsoftc *mm, int lba_start, int lba_end) +{ + uint8_t cmd_buf[SC_CLASS1_SZ] = {0x47,0,0,0,0,0,0,0,0,0}; + + lba_to_msf(lba_start, &cmd_buf[3], &cmd_buf[4], &cmd_buf[5]); + lba_to_msf(lba_end-1, &cmd_buf[6], &cmd_buf[7], &cmd_buf[8]); + + return (mm_cmd(mm,cmd_buf,SC_CLASS1_SZ,MMSC_TIMEOUT,0,0,0)); +} + +static int +mmsc_cdrom_get_mcn(struct cdrom_device_info *cdi, + struct cdrom_mcn *mcn_info) +{ + struct mmsoftc *mm=NULL; + int stat; + char mcnbuf[24]; + + // HINT: Use the Read Sub-Channel Cmd (0x42) + // We need to set : + // memcpy (mcn_info->medium_catalog_number, mcnbuf+9,sizeof (mcn_info->medium_catalog_number)-1); + // mcn_info->medium_catalog_number[sizeof (mcn_info->medium_catalog_number)-1] = '\0'; + // return 0 on success + + mm = ((struct mmsc_cdrom_info *)cdi->handle)->partinfo->diskinfo->softc; + if (mm==NULL) { + printk("mmsc_cdrom_get_mcn( 0x%p, 0x%p) : mm == NULL\n",(void *)cdi,(void *)mcn_info); + return -EINVAL; + } + + if ((stat = mmsc_cdrom_read_subchannel(mm,2,mcnbuf,sizeof(mcnbuf)))) { + return stat; + } + + memcpy (mcn_info->medium_catalog_number, mcnbuf+9, sizeof (mcn_info->medium_catalog_number)-1); + mcn_info->medium_catalog_number[sizeof (mcn_info->medium_catalog_number)-1] = '\0'; + + return 0; +} + +static int +mmsc_cdrom_reset(struct cdrom_device_info *cdi) +{ + // Send ATAPI SOFT RESET (0x08 in Command reg) + // return 0 on success + return 1; +} + +static int +mmsc_cdrom_get_toc_entry(struct mmsc_cdrom_info *info, int track, struct atapi_toc_entry **ent) +{ + struct atapi_toc *toc = info->toc; + int ntracks; + + if (!(MMSC_CDROM_STATE_FLAGS (info).toc_valid)) return -EINVAL; + + /* Check validity of requested track number. */ + ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; + if (toc->hdr.first_track == CDROM_LEADOUT) + ntracks = 0; + if (track == CDROM_LEADOUT) { + *ent = &toc->ent[ntracks]; + } + else if (track < toc->hdr.first_track || track > toc->hdr.last_track) { + return -EINVAL; + } + else { + *ent = &toc->ent[track - toc->hdr.first_track]; + } + + return 0; +} + +static int +mmsc_cdrom_audio_ioctl(struct cdrom_device_info *cdi, + unsigned int cmd, void *arg) +{ + struct mmsc_cdrom_info *info = (struct mmsc_cdrom_info *) cdi->handle; + struct mmsoftc *mm = info->partinfo->diskinfo->softc; + int stat; + + switch (cmd) { + case CDROMREADTOCHDR: + { + struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *)arg; + struct atapi_toc *toc=NULL; + + /* Make sure our saved TOC is valid. */ + stat = mmsc_cdrom_read_toc(info); + if (stat) + return stat; + toc = info->toc; + tochdr->cdth_trk0 = toc->hdr.first_track; + tochdr->cdth_trk1 = toc->hdr.last_track; + + return 0; + } + break; + case CDROMREADTOCENTRY: + { + struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg; + struct atapi_toc_entry *toce; + + stat = mmsc_cdrom_get_toc_entry (info, tocentry->cdte_track, &toce); + if (stat) return stat; + + tocentry->cdte_ctrl = toce->control; + tocentry->cdte_adr = toce->adr; + if (tocentry->cdte_format == CDROM_MSF) { + lba_to_msf (toce->addr.lba, &tocentry->cdte_addr.msf.minute, &tocentry->cdte_addr.msf.second, &tocentry->cdte_addr.msf.frame); + } else + tocentry->cdte_addr.lba = toce->addr.lba; + + return 0; + } + break; + case CDROMPLAYTRKIND: + { + unsigned long lba_start, lba_end; + struct cdrom_ti *ti = (struct cdrom_ti *)arg; + struct atapi_toc_entry *first_toc, *last_toc; + + stat = mmsc_cdrom_get_toc_entry(info, ti->cdti_trk0, &first_toc); + if (stat) + return stat; + + stat = mmsc_cdrom_get_toc_entry(info, ti->cdti_trk1, &last_toc); + if (stat) + return stat; + + if (ti->cdti_trk1 != CDROM_LEADOUT) { + ++last_toc; + } + lba_start = first_toc->addr.lba; + lba_end = last_toc->addr.lba; + + if (lba_end <= lba_start) + return -EINVAL; + + return mmsc_cdrom_play_audio(mm, lba_start, lba_end); + + } + break; + default: + printk("mmsc_cdrom_audio_ioctl() : cdi 0x%p | cmd 0x%x | arg 0x%p \n",(void *)cdi,cmd,(void *)arg); + break; + } + return -ENOSYS; +} + + + + +static int +mmsc_cdrom_dev_ioctl(struct cdrom_device_info *cdi, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case CDROMSETSPINDOWN: + { + printk("mmsc_cdrom_dev_ioctl : CDROMSETSPINDOWN - To be implemented\n"); + } + break; + case CDROMGETSPINDOWN: + { + printk("mmsc_cdrom_dev_ioctl : CDROMGETSPINDOWN - To be implemented\n"); + } + break; + default: + printk("mmsc_cdrom_dev_ioctl() : cdi 0x%p | cmd 0x%x | arg 0x%p \n",(void *)cdi,cmd,(void *)arg); + break; + } + return -ENOSYS; +} + +int +mmsc_cdrom_mode_sense(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int page_code, int page_control) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + + cgc->cmd[0] = GPCMD_MODE_SENSE_10; + cgc->cmd[1] = 0x08; // To prevent Block Descriptor from being returned. + cgc->cmd[2] = page_code | (page_control << 6); + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_READ; + return cdo->generic_packet(cdi, cgc); +} + +static int +mmsc_cdrom_generic_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + // Send pkt cmd in cgc->cmd to drive + // Call mmsc_ioctl such that pkt is passed "as is" to drive. + // return 0 on success + + struct mmsoftc *mm=NULL; + uint status=0; + int data_direction = 0; + + + mm =((struct mmsc_cdrom_info *)cdi->handle)->partinfo->diskinfo->softc; + if (mm==NULL) { + printk("mmsc_cdrom_generic_packet( 0x%p, 0x%p) : mm == NULL\n",(void *)cdi,(void *)cgc); + return -EINVAL; + } + + if (cgc->data_direction == CGC_DATA_READ) data_direction = READ; + if (cgc->data_direction == CGC_DATA_NONE) data_direction = 0; + if (cgc->data_direction == CGC_DATA_WRITE) data_direction = WRITE; + if (cgc->data_direction == CGC_DATA_UNKNOWN) data_direction = 0; + + status = mm_cmd(mm,cgc->cmd,CDROM_PACKET_SIZE,cgc->timeout,cgc->buffer,cgc->buflen,data_direction); + return status; +} + +static int +mmsc_cdrom_get_capabilities(struct mmsc_cdrom_info *info, struct atapi_capabilities_page *cap) +{ + struct cdrom_device_info *cdi = &info->devinfo; + struct cdrom_generic_command cgc; + int stat, attempts=3, size = sizeof(*cap); + + init_cdrom_command(&cgc,cap,size,CGC_DATA_UNKNOWN); + do { /* Copied from ide-cd.c */ + stat = mmsc_cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (!stat) + break; + } while (--attempts); + return stat; +} + +static int +mmsc_cdrom_probe_capabilities (struct mmsc_cdrom_info *info) +{ + struct atapi_capabilities_page cap; + int nslots=1; + + if (mmsc_cdrom_get_capabilities(info, &cap)) + return 0; + + if (cap.lock == 0) + MMSC_CDROM_CONFIG_FLAGS (info).no_doorlock = 1; + if (cap.eject) + MMSC_CDROM_CONFIG_FLAGS (info).no_eject = 0; + if (cap.cd_r_write) + MMSC_CDROM_CONFIG_FLAGS (info).cd_r = 1; + if (cap.cd_rw_write) + MMSC_CDROM_CONFIG_FLAGS (info).cd_rw = 1; + if (cap.test_write) + MMSC_CDROM_CONFIG_FLAGS (info).test_write = 1; + if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) + MMSC_CDROM_CONFIG_FLAGS (info).dvd = 1; + if (cap.dvd_ram_write) + MMSC_CDROM_CONFIG_FLAGS (info).dvd_ram = 1; + if (cap.dvd_r_write) + MMSC_CDROM_CONFIG_FLAGS (info).dvd_r = 1; + if (cap.audio_play) + MMSC_CDROM_CONFIG_FLAGS (info).audio_play = 1; + if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup) + MMSC_CDROM_CONFIG_FLAGS (info).close_tray = 0; + + MMSC_CDROM_CONFIG_FLAGS(info).max_speed = (((int)cap.maxspeed_msb) << 8)|((int)cap.maxspeed_lsb); + MMSC_CDROM_CONFIG_FLAGS(info).current_speed = (((int)cap.currspeed_msb) << 8)|((int)cap.currspeed_lsb); + + (&(info->devinfo))->speed = MMSC_CDROM_CONFIG_FLAGS(info).current_speed; + + /* Printing out Drive Info */ + printk("/dev/%s:", (&(info->devinfo))->name); + printk(" %s", MMSC_CDROM_CONFIG_FLAGS(info).dvd ? "DVD-ROM" : "CD-ROM"); + if (MMSC_CDROM_CONFIG_FLAGS (info).dvd_r|MMSC_CDROM_CONFIG_FLAGS (info).dvd_ram) + printk (" DVD%s%s", + (MMSC_CDROM_CONFIG_FLAGS (info).dvd_r)? "-R" : "", + (MMSC_CDROM_CONFIG_FLAGS (info).dvd_ram)? "-RAM" : ""); + + if (MMSC_CDROM_CONFIG_FLAGS (info).cd_r|MMSC_CDROM_CONFIG_FLAGS (info).cd_rw) + printk (" CD%s%s", + (MMSC_CDROM_CONFIG_FLAGS (info).cd_r)? "-R" : "", + (MMSC_CDROM_CONFIG_FLAGS (info).cd_rw)? "/RW" : ""); + + printk (" drive, "); + + if (MMSC_CDROM_CONFIG_FLAGS(info).max_speed) + printk("Speed %d kBps", MMSC_CDROM_CONFIG_FLAGS(info).max_speed); + + printk (", %dkB Cache \n", ((int)cap.cache_msb<<8)|(cap.cache_lsb)); + + return nslots; + +} + + +static struct cdrom_device_ops mmsc_cdrom_dops = { + open: mmsc_cdrom_open, + release: mmsc_cdrom_release, + drive_status: mmsc_cdrom_drive_status, + media_changed: mmsc_cdrom_media_changed, + tray_move: mmsc_cdrom_tray_move, + lock_door: mmsc_cdrom_lock_door, + select_speed: mmsc_cdrom_select_speed, + get_last_session: mmsc_cdrom_get_last_session, + get_mcn: mmsc_cdrom_get_mcn, + reset: mmsc_cdrom_reset, + audio_ioctl: mmsc_cdrom_audio_ioctl, + dev_ioctl: mmsc_cdrom_dev_ioctl, + capability: CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | + CDC_SELECT_SPEED | CDC_SELECT_DISC | + CDC_MULTI_SESSION | CDC_MCN | + CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | + CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | + CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM | + CDC_GENERIC_PACKET, + generic_packet: mmsc_cdrom_generic_packet, +}; + diff -Nur linux-2.4.19/drivers/xscsi/mmsc.h linux-2.4.19-sgi211r3/drivers/xscsi/mmsc.h --- linux-2.4.19/drivers/xscsi/mmsc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/mmsc.h Fri Jan 3 08:28:29 2003 @@ -0,0 +1,799 @@ +/* + * + * + * Copyright (c) 1986-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifndef _LINUX_MMSC_H +#define _LINUX_MMSC_H + +#define log2(x) ffz(~(x)) + +/* + * Macros for mutual exclusion lock. + */ +#if 0 +#define MMSCLOCK(mm) down(&mm->mm_lock) +#define MMSCUNLOCK(mm) up(&mm->mm_lock) +#define MMSCINITLOCK(mm) sema_init(&mm->mm_lock, 1) +#define MMSCDELETELOCK(mm) +#define MMSCLOCKDECLARE struct semaphore mm_lock +#else +#if 0 +#define MMSCLOCK(mm) spin_lock_irqsave(&mm->mm_lock, mm->mm_intrflags) +#define MMSCUNLOCK(mm) spin_unlock_irqrestore(&mm->mm_lock, mm->mm_intrflags) +#define MMSCLOCKDECLARE spinlock_t mm_lock; unsigned long mm_intrflags +#else +#define MMSCLOCK(mm) spin_lock(&mm->mm_lock) +#define MMSCUNLOCK(mm) spin_unlock(&mm->mm_lock) +#define MMSCLOCKDECLARE spinlock_t mm_lock +#endif +#define MMSCINITLOCK(mm) mm->mm_lock = SPIN_LOCK_UNLOCKED +#define MMSCDELETELOCK(mm) +#endif + +/* values for mm_flags */ +#define MM_WRTPROT 0x0001 /* drive is write protected */ +#define MM_QUEUE 0x0002 /* queueing allowed to drive */ +#define MM_WONT_START 0x0004 /* device fails attempts to start */ +#define MM_MAPUSER 0x0010 /* can map user addresses */ +#define MM_NEEDSTART 0x0020 /* needs a startunit cmd */ +#define MM_RECURSE 0x0200 /* If set have recursion thru mmrelsubchan */ +#define MM_ALENLIST 0x0400 /* Alenlist can be delivered with scsireq */ +#define MM_NEED_BLKSZ 0x0800 /* Need to set blocksize */ +#define MM_HOLD 0x1000 /* Hold commands to device -- backend callback in progress */ +#define MM_NEED_CB (MM_NEEDSTART | MM_NEED_BLKSZ) +#define MM_FAILOVER 0X2000 /* Path failover -- biodone the mm_queue + Reject incoming requests for this device. + Set/cleared by failover_switch. */ + + +/* + * By powers of 2, allows tracking request sizes up to 256 blocks; + * larger requests are included in last bucket. This is multiples + * of blocks for that drive, it is not in terms of any particular + * block size. Currently implemented only for mmsc scsi disk driver. + * Returned per drive, not per partition. Only ifdef DEBUG +*/ +#define NUM_BLK_BUCKETS 9 +struct disk_blkstats { + uint bk_reads[NUM_BLK_BUCKETS]; + uint bk_writes[NUM_BLK_BUCKETS]; +}; + +struct mmrequest +{ + unsigned char sensedata[SCSI_SENSE_LEN]; /* cache aligned */ + unsigned char cmddata[SC_CLASS1_SZ]; + + int retry_count; + + struct mmrequest *av_forw; /* sort queue */ + struct mmrequest *av_back; + + struct list_head free_table; + struct list_head *free_list; + + int cmd; /* command (read/write) */ + unsigned int sector; /* sector number (based on mm_blksz) */ + unsigned int count; /* count (in mm_blksz chunks) */ + int merges; + + int drive; + int part; /* partition number */ + int b_resid; /* amount of data not transferred */ + + struct buffer_head *bh; + struct buffer_head *bhlast; + struct kiobuf *iobuf; + request_queue_t *q; + + struct mm_diskinfo *disk_info; + + scsi_request_t sr; + + struct timer_list timer; + struct alenlist_s alenlist; +}; + +struct diskqueue +{ + struct mmrequest *io_head; /* head of I/O queue */ + struct mmrequest *io_tail; /* tail of I/O queue */ + daddr_t io_prev; /* block # of previous command */ + daddr_t seq_next; /* next sequential request */ + int seq_count; /* count of sequential requests */ + int delwri_holdoff; /* delwri fairness variable */ + struct mmrequest *delwri_head; /* head of delwri queue */ + struct mmrequest *delwri_tail; /* tail of delwri queue */ + daddr_t delwri_prev; /* block # of previous command */ +}; + +/* + * Software state per disk drive. + */ +struct mmsoftc { + u_char mm_curq; /* current number of queued commands */ + u_char mm_plug; + time_t mm_iostart; /* 'start' time for sar measurements */ + + uint mm_drivecap; + uint mm_blksz; /* logical (from drive) blocksize of device */ + int mm_opencount; /* number of layered opens */ + ushort mm_flags; + u_char mm_qdepth; /* command queue depth */ + u_char *mm_inqtyp; /* devtype from first byte of inquiry data */ + + struct tq_struct plug_tq; + struct mmrequest *mm_rq; /* for callback backend */ + int mm_rqactive; + + MMSCLOCKDECLARE; /* Lock to protect structure fields */ + wait_queue_head_t mm_wait; /* queue for internal commands */ + struct semaphore mm_sema; /* mutex for use of mm_done sema */ + struct semaphore mm_done; /* for synchronous I/O */ + struct semaphore mm_hold; /* used when MM_HOLD set */ + int mm_hold_count; /* number of holders */ + + struct diskqueue mm_queue; /* wait queue */ + struct mmrequest *mm_active; /* active queue */ + struct mmrequest *mm_retry; /* deferred retry queue */ + request_queue_t mm_request_queue; /* linux request queue */ + + struct mm_diskinfo *mm_disk_info; /* info for disk */ + scsi_target_info_t *mm_target_info; + void (*mm_cb)(vertex_hdl_t, uint8_t *); /* Sense callback function */ + u_char msel_bd[12]; /* placeholder for blocksize modeselect */ + + struct kiobuf *mm_freeiobuf; + spinlock_t mm_iobuffree_lock; + int mm_iobuf_count; +#if MMSC_EVENT_LOG + #define MMSC_EVENT_LOG_SIZE 200 + struct { + char *string; + uint aval; + uint bval; + } mm_event_buffer[MMSC_EVENT_LOG_SIZE]; + uint mm_event_rotor; +#endif +}; + +/* used for mm_inqtype and mm_drivecap, respectively */ +#define MM_INQTYP_SIZE 4 +#define MM_DRIVECAP_SIZE 8 + + +/* + * This structure is used by the mode select/get ioctls to determine + * where the data is to be sent to/recieved from. + */ +struct mm_ioctl_data { + caddr_t i_addr; + u_int i_len; + u_char i_page; /* Page code is used only on mode select */ +}; + +/* Maximum amount of data allowed by an ioctl cmd */ +#define MAX_IOCTL_DATA 4096 + +/* These are the possible page codes used by mode sense/get */ +#define ERR_RECOV 0x1 +#define CONN_PARMS 0x2 +#define DEV_FORMAT 0x3 +#define DEV_GEOMETRY 0x4 +#define DEV_FDGEOMETRY 0x5 /* geometry for SMS flexible disks */ +#define BLOCK_DESCRIP 0x7 /* TOSHIBA MK156FB only */ +#define VERIFY_ERR 0x7 /* SCSI 2 Verify error recovery page */ +#define CACHE_SCSI2 0x8 /* SCSI 2 cache control */ +#define QUEUE_PARAM 0xA /* SCSI 2 queue parameters */ +#define NOTCH_SCSI2 0xC /* SCSI 2 notch page */ +#define CACHE_CONTR 0x38 /* CDC Wren IV/V/VI drives */ +#define ALL 0x3f + +/* These are the page control field values recognized by the mode sense cmd */ +#define CURRENT 0 +#define CHANGEABLE (0x1 << 6) +#define DEFAULT (0x2 << 6) +#define SAVED (0x3 << 6) + +#if defined(__LITTLE_ENDIAN) +#define BITFIELD_DECL2(A0, A1) A1, A0 +#define BITFIELD_DECL3(A0, A1, A2) A2, A1, A0 +#define BITFIELD_DECL4(A0, A1, A2, A3) A3, A2, A1, A0 +#define BITFIELD_DECL5(A0, A1, A2, A3, A4) A4, A3, A2, A1, A0 +#define BITFIELD_DECL6(A0, A1, A2, A3, A4, A5) A5, A4, A3, A2, A1, A0 +#define BITFIELD_DECL7(A0, A1, A2, A3, A4, A5, A6) A6, A5, A4, A3, A2, A1, A0 +#define BITFIELD_DECL8(A0, A1, A2, A3, A4, A5, A6, A7) A7, A6, A5, A4, A3, A2, A1, A0 +#endif + +/* + * These are the pages of the drive parameter set/get commands. + * Note that all of the struct should be allocated to the full + * size of the union, since we determine their sizes at run time, + * due to the possiblity of different page sizes on different + * mfg drives. This is normally done by using ptrs to the structs, + * and setting them to point to the mm_pages member of a struct mode_sense_data. + * Any 'extra' bytes won't be changed by programs like fx, but most + * drives require that the pages being set by a mode select be + * the correct size and have valid data for bytes that aren't + * changed (usually retrieved via a mode sense into the same buffer). + */ +union mm_pages { + struct common { + u_char pg_code; + u_char pg_len; + u_char pg_maxlen[0x100-2]; /* make room for max possible page len */ + } common; + struct err_recov { + u_char e_pgcode; + u_char e_pglen; + u_char e_err_bits; + u_char e_retry_count; + /* rest are spec'ed in scsi2, not supported by most drives yet */ + u_char e_rdretry; + u_char e_corrspan; + u_char e_headoffset; + u_char e_strobeoffset; + u_char e_rsv0; + u_char e_wrretry; + u_char e_rsv1; + u_char e_recovtime[2]; + } err_recov; + struct connparms { + u_char c_pgcode; + u_char c_pglen; + u_char c_bfull; + u_char c_bempty; + u_char c_binacthi; + u_char c_binactlo; + u_char c_disconhi; + u_char c_disconlo; + u_char c_reserv[2]; + } cparms; + struct dev_format { + u_char f_pgcode; + u_char f_pglen; + u_char f_trk_zone[2]; + u_char f_altsec[2]; + u_char f_alttrk_zone[2]; + u_char f_alttrk_vol[2]; + u_char f_sec_trac[2]; + u_char f_bytes_sec[2]; + u_char f_interleave[2]; + u_char f_trkskew[2]; + u_char f_cylskew[2]; + u_char f_form_bits; + u_char f_reserved4[3]; + } dev_format; + struct dev_geometry { /* page 4 for winchesters */ + u_char g_pgcode; + u_char g_pglen; + u_char g_ncyl[3]; + u_char g_nhead; + u_char g_wrprecomp[3]; + u_char g_reducewrcur[3]; + u_char g_steprate[2]; + u_char g_landing[3]; + u_char BITFIELD_DECL2(g_reserved1:7, g_spindlesync:1); + u_char g_rotatoff; + u_char g_reserved2; + u_char g_rotatrate[2]; + u_char g_reserved3[2]; + } dev_geometry; + struct dev_fdgeometry { /* page 5 for floppies */ + u_char g_pgcode; + u_char g_pglen; + u_char g_trate[2]; + u_char g_nhead; + u_char g_spt; + u_char g_bytes_sec[2]; + u_char g_ncyl[2]; + u_char g_wprcomp[2]; + u_char g_wrcurr[2]; + u_char g_steprate[2]; + u_char g_steppulsewidth; + u_char g_headset[2]; + u_char g_moton; + u_char g_motoff; + u_char BITFIELD_DECL4(g_trdy:1, g_ssn:1, g_mo:1, g_reserv0:5); + u_char BITFIELD_DECL2(g_reserv1:4, g_stpcyl:4); + u_char g_wrprecomp; + u_char g_headld; + u_char g_headunld; + u_char BITFIELD_DECL2(g_pin34:4, g_pin2:4); + u_char BITFIELD_DECL2(g_pin4:4, g_pin1:4); /* pin 1 TEAC, reserved on NCR */ + u_char g_reserv2[4]; + } dev_fdgeometry; + struct block_descrip { /* Toshiba 156 FB only */ + u_char b_pgcode; + u_char b_pglen; + u_char b_reserved0; + u_char b_bdlen; + u_char b_density; + u_char b_reserved1[3]; + u_int b_blen; /* This is actually a 3 byte val; high + byte reserved */ + } block_descrip; + struct verify_err { /* scsi 2 error recovery params */ + u_char v_pgcode; + u_char v_pglen; + u_char BITFIELD_DECL5(rsv0:4, eer:1, per:1, dte:1, dcr:1); + u_char v_retry; + u_char v_corrspan; + u_char v_rsv1[5]; + u_char v_recovtime[2]; + } verify_err; + struct cachescsi2 { /* scsi 2 cache ctrl page */ + u_char c_pgcode; + u_char c_pglen; + u_char BITFIELD_DECL4(c_rsrv:5, c_wce:1, c_mf:1, c_rcd:1); + u_char BITFIELD_DECL2(c_rdpri:4, c_wrpri:4); + u_char c_predislen[2]; + u_char c_minpre[2]; + u_char c_maxpre[2]; + u_char c_maxpreceil[2]; + u_char BITFIELD_DECL4(c_fsw:1, /* force seq write */ + c_rsrv2:1, /* not yet in rev 10H */ + c_dra:1, /* disable readahead; not yet in rev 10H */ + c_rsrv3:5); /* not yet in rev 10H */ + u_char c_numseg; + u_char c_cachsize[2]; /* cache seg size; not yet in rev 10H */ + u_char c_rsv5; /* not yet in rev 10H */ + u_char c_ncachsize[3]; /* non-cache seg size; not yet in rev 10H */ + } cachescsi2; + struct queueparam { /* scsi 2 queue parameter page */ + u_char q_pgcode; + u_char q_pglen; + u_char BITFIELD_DECL2(q_rsrv1:7, q_rlec:1); + u_char BITFIELD_DECL4(q_algorthm_mod:4, q_rsrv2:2, q_err:1, q_disable:1); + u_char BITFIELD_DECL5(q_eeca:1, q_rsrv3:4, q_raenp:1, q_uaaenp:1, q_eaenp:1); + u_char q_rsrv4; + u_char q_ready_aen_holdoff[2]; + } queueparam; + struct notch { /* info for 'zone bit recorded' devices */ + u_char n_pgcode; + u_char n_pglen; + u_char BITFIELD_DECL3(n_nd:1, n_lpn:1, n_rsv0:6); + u_char n_rsv1; + u_char n_maxnotch[2]; + u_char n_actnotch[2]; + u_char n_startbound[2]; + u_char n_endbound[2]; + u_char n_pagesnotched[2]; + } notch; + struct cachectrl { /* CDC Wren IV/V/VI cache control */ + u_char c_pgcode; + u_char c_pglen; + u_char BITFIELD_DECL5(c_ccen:1, c_wie:1, c_ssm:1, c_ce:1, c_ctsize:4); + u_char c_prefetch; + u_char c_maxpre; + u_char c_maxpremult; + u_char c_minpre; + u_char c_minpremult; + u_char c_reserv[8]; + } cachctrl; +}; + +/* Error recovery flag byte bits for e_err_bits */ +#define E_DCR 0x1 +#define E_DTE 0x2 +#define E_PER 0x4 +#define E_RC 0x10 +#define E_TB 0x20 +#define E_ARRE 0x40 +#define E_AWRE 0x80 + +/* The data structure of the mode sense command */ +struct mode_sense_data { + u_char sense_len; + u_char mediatype; + u_char BITFIELD_DECL4(wprot:1, reserv0:2, dpofua:1, reserv1:4); + u_char bd_len; + u_char block_descrip[8]; /* note that this field will NOT be supplied + by some drives, so that mm_pages data may actually start at this + offset; check the bd_len value! */ + union mm_pages mm_pages; +}; + +/* The structure of the mode select command */ +struct mode_select_data { + u_char reserv0; + u_char mediatype; + u_char BITFIELD_DECL2(wprot:1, reserv1:7); + u_char blk_len; /* This will normally be set to 0 */ + union mm_pages mm_pages; +}; + +struct defect_header { + u_char reserved0; + u_char format_bits; + u_char defect_listlen[2]; +}; + +struct defect_entry { + u_char def_cyl[3]; + u_char def_head; + u_char def_sector[4]; /* bytes from index, or sector */ +}; + + +/***************************************************************************** + * The code below is copied from "drivers/ide/ide-cd.h" + * because we need the same structures when interfacing with cdrom.c + ****************************************************************************/ + +typedef unsigned char byte; + +/************************************************************************/ + +#define SECTOR_BITS 9 +#define SECTOR_SIZE (1 << SECTOR_BITS) +#define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_BITS) +#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) +#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE >> SECTOR_BITS) +#define SECTORS_MAX (131072 >> SECTOR_BITS) + +#define BLOCKS_PER_FRAME (CD_FRAMESIZE / BLOCK_SIZE) + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* Configuration flags. These describe the capabilities of the drive. + They generally do not change after initialization, unless we learn + more about the drive from stuff failing. */ +struct ide_cd_config_flags { + __u8 drq_interrupt : 1; /* Device sends an interrupt when ready + for a packet command. */ + __u8 no_doorlock : 1; /* Drive cannot lock the door. */ + __u8 no_eject : 1; /* Drive cannot eject the disc. */ + __u8 nec260 : 1; /* Drive is a pre-1.2 NEC 260 drive. */ + __u8 playmsf_as_bcd : 1; /* PLAYMSF command takes BCD args. */ + __u8 tocaddr_as_bcd : 1; /* TOC addresses are in BCD. */ + __u8 toctracks_as_bcd : 1; /* TOC track numbers are in BCD. */ + __u8 subchan_as_bcd : 1; /* Subchannel info is in BCD. */ + __u8 is_changer : 1; /* Drive is a changer. */ + __u8 cd_r : 1; /* Drive can write to CD-R media . */ + __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */ + __u8 dvd : 1; /* Drive is a DVD-ROM */ + __u8 dvd_r : 1; /* Drive can write DVD-R */ + __u8 dvd_ram : 1; /* Drive can write DVD-RAM */ + __u8 test_write : 1; /* Drive can fake writes */ + __u8 supp_disc_present : 1; /* Changer can report exact contents + of slots. */ + __u8 limit_nframes : 1; /* Drive does not provide data in + multiples of SECTOR_SIZE when more + than one interrupt is needed. */ + __u8 seeking : 1; /* Seeking in progress */ + __u8 audio_play : 1; /* can do audio related commands */ + __u8 close_tray : 1; /* can close the tray */ + __u8 writing : 1; /* pseudo write in progress */ + __u8 reserved : 3; + int max_speed; /* Max speed of the drive */ + int current_speed; /* Current Speed of drive */; +}; +#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) + + +/* State flags. These give information about the current state of the + drive, and will change during normal operation. */ +struct ide_cd_state_flags { + __u8 media_changed : 1; /* Driver has noticed a media change. */ + __u8 toc_valid : 1; /* Saved TOC information is current. */ + __u8 door_locked : 1; /* We think that the drive door is locked. */ + __u8 writing : 1; /* the drive is currently writing */ + __u8 reserved : 4; + byte current_speed; /* Current speed of the drive */ +}; + +#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) + +/* Structure of a MSF cdrom address. */ +struct atapi_msf { + byte reserved; + byte minute; + byte second; + byte frame; +}; + +/* Space to hold the disk TOC. */ +#define MAX_TRACKS 99 +struct atapi_toc_header { + unsigned short toc_length; + byte first_track; + byte last_track; +}; + +struct atapi_toc_entry { + byte reserved1; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 adr : 4; + __u8 control : 4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 control : 4; + __u8 adr : 4; +#else +#error "Please fix " +#endif + byte track; + byte reserved2; + union { + unsigned lba; + struct atapi_msf msf; + } addr; +}; + +struct atapi_toc { + int last_session_lba; + int xa_flag; + unsigned long capacity; + struct atapi_toc_header hdr; + struct atapi_toc_entry ent[MAX_TRACKS+1]; + /* One extra for the leadout. */ +}; + + +/* + * Copied from drivers/ide/ide-cd.h + */ + +struct atapi_capabilities_page { + struct mode_page_header header; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 parameters_saveable : 1; + __u8 reserved1 : 1; + __u8 page_code : 6; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 page_code : 6; + __u8 reserved1 : 1; + __u8 parameters_saveable : 1; +#else +#error "Please fix " +#endif + + byte page_length; + +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved2 : 2; + /* Drive supports reading of DVD-RAM discs */ + __u8 dvd_ram_read : 1; + /* Drive supports reading of DVD-R discs */ + __u8 dvd_r_read : 1; + /* Drive supports reading of DVD-ROM discs */ + __u8 dvd_rom : 1; + /* Drive supports reading CD-R discs with addressing method 2 */ + __u8 method2 : 1; /* reserved in 1.2 */ + /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */ + __u8 cd_rw_read : 1; /* reserved in 1.2 */ + /* Drive supports read from CD-R discs (orange book, part II) */ + __u8 cd_r_read : 1; /* reserved in 1.2 */ +#elif defined(__LITTLE_ENDIAN_BITFIELD) + /* Drive supports read from CD-R discs (orange book, part II) */ + __u8 cd_r_read : 1; /* reserved in 1.2 */ + /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */ + __u8 cd_rw_read : 1; /* reserved in 1.2 */ + /* Drive supports reading CD-R discs with addressing method 2 */ + __u8 method2 : 1; + /* Drive supports reading of DVD-ROM discs */ + __u8 dvd_rom : 1; + /* Drive supports reading of DVD-R discs */ + __u8 dvd_r_read : 1; + /* Drive supports reading of DVD-RAM discs */ + __u8 dvd_ram_read : 1; + __u8 reserved2 : 2; +#else +#error "Please fix " +#endif + +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved3 : 2; + /* Drive can write DVD-RAM discs */ + __u8 dvd_ram_write : 1; + /* Drive can write DVD-R discs */ + __u8 dvd_r_write : 1; + __u8 reserved3a : 1; + /* Drive can fake writes */ + __u8 test_write : 1; + /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ + __u8 cd_rw_write : 1; /* reserved in 1.2 */ + /* Drive supports write to CD-R discs (orange book, part II) */ + __u8 cd_r_write : 1; /* reserved in 1.2 */ +#elif defined(__LITTLE_ENDIAN_BITFIELD) + /* Drive can write to CD-R discs (orange book, part II) */ + __u8 cd_r_write : 1; /* reserved in 1.2 */ + /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ + __u8 cd_rw_write : 1; /* reserved in 1.2 */ + /* Drive can fake writes */ + __u8 test_write : 1; + __u8 reserved3a : 1; + /* Drive can write DVD-R discs */ + __u8 dvd_r_write : 1; + /* Drive can write DVD-RAM discs */ + __u8 dvd_ram_write : 1; + __u8 reserved3 : 2; +#else +#error "Please fix " +#endif + +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved4 : 1; + /* Drive can read multisession discs. */ + __u8 multisession : 1; + /* Drive can read mode 2, form 2 data. */ + __u8 mode2_form2 : 1; + /* Drive can read mode 2, form 1 (XA) data. */ + __u8 mode2_form1 : 1; + /* Drive supports digital output on port 2. */ + __u8 digport2 : 1; + /* Drive supports digital output on port 1. */ + __u8 digport1 : 1; + /* Drive can deliver a composite audio/video data stream. */ + __u8 composite : 1; + /* Drive supports audio play operations. */ + __u8 audio_play : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + /* Drive supports audio play operations. */ + __u8 audio_play : 1; + /* Drive can deliver a composite audio/video data stream. */ + __u8 composite : 1; + /* Drive supports digital output on port 1. */ + __u8 digport1 : 1; + /* Drive supports digital output on port 2. */ + __u8 digport2 : 1; + /* Drive can read mode 2, form 1 (XA) data. */ + __u8 mode2_form1 : 1; + /* Drive can read mode 2, form 2 data. */ + __u8 mode2_form2 : 1; + /* Drive can read multisession discs. */ + __u8 multisession : 1; + __u8 reserved4 : 1; +#else +#error "Please fix " +#endif + +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved5 : 1; + /* Drive can return Media Catalog Number (UPC) info. */ + __u8 upc : 1; + /* Drive can return International Standard Recording Code info. */ + __u8 isrc : 1; + /* Drive supports C2 error pointers. */ + __u8 c2_pointers : 1; + /* R-W data will be returned deinterleaved and error corrected. */ + __u8 rw_corr : 1; + /* Subchannel reads can return combined R-W information. */ + __u8 rw_supported : 1; + /* Drive can continue a read cdda operation from a loss of streaming.*/ + __u8 cdda_accurate : 1; + /* Drive can read Red Book audio data. */ + __u8 cdda : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + /* Drive can read Red Book audio data. */ + __u8 cdda : 1; + /* Drive can continue a read cdda operation from a loss of streaming.*/ + __u8 cdda_accurate : 1; + /* Subchannel reads can return combined R-W information. */ + __u8 rw_supported : 1; + /* R-W data will be returned deinterleaved and error corrected. */ + __u8 rw_corr : 1; + /* Drive supports C2 error pointers. */ + __u8 c2_pointers : 1; + /* Drive can return International Standard Recording Code info. */ + __u8 isrc : 1; + /* Drive can return Media Catalog Number (UPC) info. */ + __u8 upc : 1; + __u8 reserved5 : 1; +#else +#error "Please fix " +#endif + +#if defined(__BIG_ENDIAN_BITFIELD) + /* Drive mechanism types. */ + mechtype_t mechtype : 3; + __u8 reserved6 : 1; + /* Drive can eject a disc or changer cartridge. */ + __u8 eject : 1; + /* State of prevent/allow jumper. */ + __u8 prevent_jumper : 1; + /* Present state of door lock. */ + __u8 lock_state : 1; + /* Drive can lock the door. */ + __u8 lock : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + + /* Drive can lock the door. */ + __u8 lock : 1; + /* Present state of door lock. */ + __u8 lock_state : 1; + /* State of prevent/allow jumper. */ + __u8 prevent_jumper : 1; + /* Drive can eject a disc or changer cartridge. */ + __u8 eject : 1; + __u8 reserved6 : 1; + /* Drive mechanism types. */ + mechtype_t mechtype : 3; +#else +#error "Please fix " +#endif + +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved7 : 4; + /* Drive supports software slot selection. */ + __u8 sss : 1; /* reserved in 1.2 */ + /* Changer can report exact contents of slots. */ + __u8 disc_present : 1; /* reserved in 1.2 */ + /* Audio for each channel can be muted independently. */ + __u8 separate_mute : 1; + /* Audio level for each channel can be controlled independently. */ + __u8 separate_volume : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + + /* Audio level for each channel can be controlled independently. */ + __u8 separate_volume : 1; + /* Audio for each channel can be muted independently. */ + __u8 separate_mute : 1; + /* Changer can report exact contents of slots. */ + __u8 disc_present : 1; /* reserved in 1.2 */ + /* Drive supports software slot selection. */ + __u8 sss : 1; /* reserved in 1.2 */ + __u8 reserved7 : 4; +#else +#error "Please fix " +#endif + + /* Maximum speed (in kB/s). */ + __u8 maxspeed_msb; + __u8 maxspeed_lsb; + /* Number of discrete volume levels. */ + __u8 vol_msb; + __u8 vol_lsb; + /* Size of cache in drive, in kB. */ + __u8 cache_msb; + __u8 cache_lsb; + /* Current speed (in kB/s). */ + __u8 currspeed_msb; + __u8 currspeed_lsb; + char pad[4]; +}; + +// mmsc cdrom specific code +/* Extra per-device info for cdrom devices */ +struct mmsc_cdrom_info { + struct atapi_toc *toc; + struct ide_cd_config_flags config_flags; + struct ide_cd_state_flags state_flags; + struct cdrom_device_info devinfo; + struct mm_partinfo *partinfo; +}; + +#define MMSC_CDROM_CONFIG_FLAGS(info) ((struct mmsc_cdrom_info *)info)->config_flags +#define MMSC_CDROM_STATE_FLAGS(info) ((struct mmsc_cdrom_info *)info)->state_flags + +#endif diff -Nur linux-2.4.19/drivers/xscsi/osdep_linux.c linux-2.4.19-sgi211r3/drivers/xscsi/osdep_linux.c --- linux-2.4.19/drivers/xscsi/osdep_linux.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/osdep_linux.c Fri Jan 3 08:28:29 2003 @@ -0,0 +1,180 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include + +static spinlock_t timeout_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_MUTEX_LOCKED(timeout_wait); +static LIST_HEAD(timeout_expired); +static LIST_HEAD(timeout_pending); + +struct irix_timer { + struct list_head table; + struct timer_list timer; + void (*function)(void *, void *, void *, void *); + void *arg0, *arg1, *arg2, *arg3; +}; + +#define timeout_expired_next() \ +list_entry(timeout_expired.next, struct irix_timer, table) + +static int +timeout_thread(void *unused) +{ + struct irix_timer *timer; + + xscsi_disable_signals(); + lock_kernel(); + daemonize(); + sprintf(current->comm, "irixtimer"); + unlock_kernel(); + + for (;;) { + down_interruptible(&timeout_wait); + spin_lock_bh(&timeout_lock); + timer = timeout_expired_next(); + list_del(&timer->table); + spin_unlock_bh(&timeout_lock); + + timer->function(timer->arg0, timer->arg1, timer->arg2, + timer->arg3); + kmem_free(timer, sizeof(*timer)); + } + + return 0; +} + +static void +timeout_init(void) +{ + kernel_thread(timeout_thread, NULL, 0); +} + +static void +timeout_expire(unsigned long data) +{ + struct irix_timer *timer = (struct irix_timer *) data; + struct irix_timer *entry = NULL; + struct list_head *table; + + spin_lock(&timeout_lock); + list_for_each(table, &timeout_pending) { + entry = list_entry(table, struct irix_timer, table); + if (entry == timer) + break; + } + if (entry != timer) + goto out; + + list_del(table); + list_add_tail(&timer->table, &timeout_expired); + up(&timeout_wait); +out: + spin_unlock(&timeout_lock); +} + + +/* + * XXX + * This is designed to mimic IRIX semantics. However, it cannot + * be called from bottom half or interrupt context, or it will break. + */ +struct irix_timer * +timeout(void *handler, void *ptr, long delay, ...) +{ + static int init = 1; + va_list ap; + struct irix_timer *timer; + void *arg1, *arg2, *arg3; + + va_start(ap, delay); + arg1 = va_arg(ap, void *); + arg2 = va_arg(ap, void *); + arg3 = va_arg(ap, void *); + va_end(ap); + + timer = kmem_alloc(sizeof(*timer), KM_SLEEP); + if (!timer) + return NULL; + + init_timer(&timer->timer); + timer->timer.expires = jiffies + delay; + timer->timer.data = (unsigned long) timer; + timer->timer.function = timeout_expire; + timer->function = (void (*)(void *, void *, void *, void *)) handler; + timer->arg0 = ptr; + timer->arg1 = arg1; + timer->arg2 = arg2; + timer->arg3 = arg3; + + spin_lock_bh(&timeout_lock); + if (init) { + init = 0; + spin_unlock_bh(&timeout_lock); + timeout_init(); + spin_lock_bh(&timeout_lock); + } + list_add_tail(&timer->table, &timeout_pending); + add_timer(&timer->timer); + spin_unlock_bh(&timeout_lock); + + return timer; +} + +void +untimeout(struct irix_timer *timer) +{ + struct list_head *table; + struct irix_timer *entry; + + if (!timer) + return; + + spin_lock_bh(&timeout_lock); + list_for_each(table, &timeout_pending) { + entry = list_entry(table, struct irix_timer, table); + if (entry == timer) { + list_del(&timer->table); + del_timer(&timer->timer); + kmem_free(timer, sizeof(*timer)); + break; + } + } + spin_unlock_bh(&timeout_lock); +} diff -Nur linux-2.4.19/drivers/xscsi/ql.c linux-2.4.19-sgi211r3/drivers/xscsi/ql.c --- linux-2.4.19/drivers/xscsi/ql.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/ql.c Thu Feb 13 10:38:18 2003 @@ -0,0 +1,6903 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifdef linux +#define XSCSI +#endif + +/****************************************************************/ +/* */ +/* Compile time options */ +/* */ +/****************************************************************/ + +#define LOAD_VIA_DMA /* load firmware with DMA */ +#define PROBE_ALL_LUNS 1 +#define USE_MUTEX + + + +#undef QL_SRAM_PARITY /* disable sram parity check, ok since there wont be any SGI + built 1040's under linux */ +#define BUS_RESET_ON_INIT 1 +#define USE_IOSPACE /* Use IO space for mapping QL registers */ +static int showconfig = 1; + +/****************************************************************/ +/* */ +/* DEBUG Compile time options */ +/* Add the following to DBOPTS in klocaldefs */ +/* -DPIO_TRACE - enable QL PIO tracing */ +/* -DQL_TIMEOUT_DEBUG - enable "forced" timeout debugging */ +/* -DQL_STATS - include statistics gathering code */ +/* */ +/****************************************************************/ + +/********************************************************* +* NOTES ON HOW WE CONFIGURE THE BRIDGE FOR QL +* +* There are two virtual DMA channel +* Virtual channel zero is the Command Channel +* This channel is pmu mapped with one rrb +* 32 bit address are generated on the pci bus +* 64 bit translation is done by the PMU +* +* Virtual channel one is the data channel +* This channel is 64bit direct mapped with prefetching +* and two or three rrbs. +* DAC(64bit) address are generated on the pci bus +* +**********************************************************/ + +/********************************************************** +** +** Include files +*/ +#include +#include +#include +#include +#include +#include +#include + +#include "osdep_linux.h" +#include "alenlist.h" +#include "xscsi.h" +#include "xfailover.h" +#include "ql.h" +#include "ql_firmware.h" + +#ifdef BUS_INT_WAR +void sn_add_polled_interrupt(int irq, int interval); +void sn_delete_polled_interrupt(int irq); +#endif + +#ifdef PIO_TRACE +ushort +get_ql_reg(pHA_INFO ha, volatile u_short *rp) { + uint *logp, log_cnt; + u_short sval; + sval = *rp; + if (ha && (logp = ha->chip_info->ql_log_vals) && ((((__psint_t)rp & 0x7fff) != 0x0008) || (sval != 0))) { + if ((log_cnt = *logp) == 0) + log_cnt = 1; + logp[log_cnt++] = (((__psint_t)rp & 0x7fff) << 16) | sval; + if (log_cnt >= QL_LOG_CNT) + log_cnt = 1; + *logp = log_cnt; + } + return sval; +} + +void +set_ql_reg(pHA_INFO ha, volatile u_short *rp, u_short sval) { + uint *logp, log_cnt; + if (ha && (logp = ha->chip_info->ql_log_vals)) { + if ((log_cnt = *logp) == 0) + log_cnt = 1; + logp[log_cnt++] = (((__psint_t)rp & 0x7fff) << 16) | (1 << 31) | sval; + if (log_cnt >= QL_LOG_CNT) + log_cnt = 1; + *logp = log_cnt; + } + *rp = sval; +} + +#define QL_PCI_INH(x) get_ql_reg(ha, x) +#define QL_PCI_OUTH(x,y) set_ql_reg(ha, x, y) +#else +#define QL_PCI_INH(x) ((uint16_t)PCI_INH(((uintptr_t) (x))^2)) +#define QL_PCI_OUTH(x,y) PCI_OUTH(((uintptr_t) (x))^2, y) +#endif /* PIO_TRACE */ + +#define KILL_WITH_TIMEOUT 1 +#define KILL_WITHOUT_TIMEOUT 0 + + +/****************************************************************/ +/* */ +/* Function Prototypes */ +/* */ +/****************************************************************/ + +/* Primary entry points */ + +int qlalloc(vertex_hdl_t, int, void (*)(vertex_hdl_t, uint8_t *)); +void qlcommand(struct scsi_request *req); +void qlfree(vertex_hdl_t, void (*)(vertex_hdl_t, uint8_t *)); +int qldump(vertex_hdl_t); +struct scsi_target_info *qlinfo(vertex_hdl_t ql_lun_vhdl); +int qlioctl(vertex_hdl_t ql_ctlr_vhdl, uint cmd, scsi_ha_op_t *op); +int qlabort(scsi_request_t *scsi_request); +void qlintr(pCHIP_INFO); +void qlinit(void); +int qlattach(scsi_pci_vhdl_t); +static void ql_intr_thread(pCHIP_INFO); +static void ql_intr_handler(int, void *, struct pt_regs *); +void qlhalt(void); + +/* Locally used routines */ +static scsi_target_info_t * ql_scsi_targ_info_init(void); +static ql_local_info_t * ql_local_info_init(int, vertex_hdl_t); +static vertex_hdl_t ql_device_add(vertex_hdl_t, int, int, int); +static void ql_device_remove(vertex_hdl_t, int, int); +pHA_INFO ql_ha_info_from_ctlr_get(vertex_hdl_t); +static pHA_INFO ql_ha_info_from_lun_get(vertex_hdl_t); +static void ql_ha_info_put(vertex_hdl_t, pHA_INFO); +static vertex_hdl_t ql_init(scsi_pci_vhdl_t, pISP_REGS); +static vertex_hdl_t ql_init_board(scsi_pci_vhdl_t, pISP_REGS); +static int ql_init_isp(pCHIP_INFO); +static void ql_enable_intrs(pCHIP_INFO); +#ifdef QL_SRAM_PARITY +static int ql_enable_sram_parity(pCHIP_INFO, int); +#endif +static int ql_entry(scsi_request_t *); +static void ql_service_interrupt(pCHIP_INFO); +static void ql_notify_responses(pCHIP_INFO, scsi_request_t *); +static void ql_start_scsi(pCHIP_INFO); +static void ql_queue_space(pCHIP_INFO, pISP_REGS); +static int ql_mbox_cmd(pCHIP_INFO, u_short *, u_char, u_char, + u_short, u_short, u_short, u_short, + u_short, u_short, u_short, u_short); +static void qldone(scsi_request_t *); +static int ql_reset(vertex_hdl_t); +static void ql_quiesce_bus(pHA_INFO, long, long); +static vertex_hdl_t ql_ctlr_add(scsi_pci_vhdl_t, int, int); +static iopaddr_t fill_sg_elem(pHA_INFO, alenaddr_t, size_t, int); +static void ql_set_defaults(pHA_INFO); +static void scan_bus(vertex_hdl_t); +static int reqi_get_slot(pHA_INFO, int); +static void kill_quiesce(pHA_INFO, int); +static void undo_quiesce(pHA_INFO, int); +static int ql_download_fw(pCHIP_INFO); +static int ql_reset_interface(pCHIP_INFO, int); +static void ql_flush_queue(pHA_INFO, uint); +static void ql_watchdog_timer(void *data); +static void ql_service_mbox_interrupt(pCHIP_INFO); +void ql_store_bus_mode(pHA_INFO ha); +void ql_find_bus_mode(pHA_INFO ha); +static int ql_diffsense_sp(pHA_INFO); +static int ql_probe_bus(pHA_INFO, int, int); +static void ql_ppmsg(pCHIP_INFO , char *, ...); +static void ql_cpmsg(vertex_hdl_t, char *, ...); +static void ql_tpmsg(vertex_hdl_t, u_char, char *, ...); +static void ql_lpmsg(vertex_hdl_t, u_char, u_char, char *, ...); +static void DBG(int level, char *format, ...); +static char * ql_completion_status_msg(uint completion_status); +static void ql_sensepr(vertex_hdl_t, int, int, u_char *, int); +static int ql_set_bus_reset(pCHIP_INFO, u_short *, u_short); +static int ql_set_scsi_id(pCHIP_INFO, u_short *); +static int ql_set_selection_timeout(pCHIP_INFO, u_short *); +static int ql_set_retry_count(pCHIP_INFO, u_short *); +static int ql_set_tag_age_limit(pCHIP_INFO, u_short *); +static int ql_set_clock_rate(pCHIP_INFO, u_short *); +static int ql_set_negation_state(pCHIP_INFO, u_short *); +static int ql_set_asynchronous_data_setup_time(pCHIP_INFO, u_short *); +static int ql_set_pci_control_parameters(pCHIP_INFO, u_short *); +static int ql_set_scsi_parameters(pCHIP_INFO, u_short *, u_short, u_short); +static int ql_set_device_queue_parameters(pCHIP_INFO, u_short *, u_short, u_short, u_short); +static int ql_set_reset_delay_parameters(pCHIP_INFO, u_short *); +static int ql_set_system_parameters(pCHIP_INFO, u_short *); +static int ql_set_firmware_features(pCHIP_INFO, u_short *); +static int ql_set_data_over_recovery_mode(pCHIP_INFO, u_short *); +static int ql_set_abort_device(pCHIP_INFO, u_short *, u_short, u_short, u_short); +static int ql_get_scsi_parameters(pCHIP_INFO, u_short *, u_short, u_short); + +#ifdef DEBUG +static int ql_get_firmware_status(pCHIP_INFO, u_short *); +static int ql_get_scsi_id(pCHIP_INFO, u_short *); +static int ql_get_selection_timeout(pCHIP_INFO, u_short *); +static int ql_get_retry_count(pCHIP_INFO, u_short *); +static int ql_get_tag_age_limit(pCHIP_INFO, u_short *); +static int ql_get_clock_rate(pCHIP_INFO, u_short *); +static int ql_get_negation_state(pCHIP_INFO, u_short *); +static int ql_get_asynchronous_data_setup_time(pCHIP_INFO, u_short *); +static int ql_get_pci_control_parameters(pCHIP_INFO, u_short *); +static int ql_get_device_queue_parameters(pCHIP_INFO, u_short *, u_short, u_short, u_short); +static int ql_get_reset_delay_parameters(pCHIP_INFO, u_short *); +static int ql_get_system_parameters(pCHIP_INFO, u_short *); +static int ql_get_firmware_features(pCHIP_INFO, u_short *); +static int ql_get_data_over_recovery_mode(pCHIP_INFO, u_short *); +static void dump_registers(pCHIP_INFO, pISP_REGS); +static void dump_parameters(vertex_hdl_t); +static void dump_iocb(command_entry *); +static void dump_iorb(status_entry *); +static void dump_continuation(continuation_entry *); +static void dump_marker(marker_entry *); +static void dump_cmd_dma(pHA_INFO); +#endif + +#ifdef DUMP_12160 +void dump_12160(pCHIP_INFO); +#endif + + +#define QL_PPMSGS if (showconfig) ql_ppmsg +#define QL_CPMSGS if (showconfig) ql_cpmsg +#define QL_TPMSGS if (showconfig) ql_tpmsg + +#define QL_KMEM_ZALLOC(_size, _flags) kmem_zalloc((_size), (_flags)) +#define QL_KVPALLOC(_s, _f, _c) kvpalloc((_s), (_f), (_c)) + +#define TIMEOUT_SPL plhi + +/****************************************************************/ +/* */ +/* Global Kernel Information */ +/* */ +/****************************************************************/ +static int ql_pci_slot_number ; +pHA_INFO ql_ha_list ; +static mutex_t ql_driver_lock; /* guards changes to ql_ha_list */ +static int ql_watchdog_timer_inited; + + +static int ql_bus_reset_on_boot = 1; +static int ql_bus_reset_delay = 1; +static int ql_allow_negotiation_on_cdroms = 0; +static int ql_printsense = 0; +static char arg_qlhostid[1]; + +static int ql_debug = 0; + +#undef QL_TIMEOUT_DEBUG + +#ifdef QL_TIMEOUT_DEBUG +#define QL_TIMEOUT_DEBUG_DEFAULT_FREQ 24000 +static int ql_timeout_debug_lunvhdl = 4; +static int ql_timeout_debug_timer = QL_TIMEOUT_DEBUG_DEFAULT_FREQ; +static int ql_timeout_debug_frequency = QL_TIMEOUT_DEBUG_DEFAULT_FREQ; +#endif + +/****************************************************************/ +/****************************************************************/ +/* + * create the info structure associated with a + * lun vertex + */ +static scsi_target_info_t * +ql_scsi_targ_info_init(void) +{ + scsi_target_info_t *info; + + /* + * allocate memory + */ + info = (scsi_target_info_t *)QL_KMEM_ZALLOC(sizeof(scsi_target_info_t), KM_SLEEP); + ASSERT(info); + return(info); +} + +/* + * allocate and initialize the ql specific part of lun info + */ +static ql_local_info_t * +ql_local_info_init(int rev, vertex_hdl_t lun_vhdl) +{ + ql_local_info_t *info; + + info = (ql_local_info_t *)QL_KMEM_ZALLOC(sizeof(*info), KM_SLEEP); + ASSERT(info); + + /* + * By default assume the QERR bit of a device is set to 0, + * unless told otherwise. It's safer that way since assuming + * the opposite could lead to command timeouts. + * However, the disk driver is setting the QERR bit depends on the + * support of the target. Setting the QERR to 0 is the default + + info->qli_dev_flags = DFLG_BEHAVE_QERR1; + */ + + info->rev=rev; + + QL_INIT_MUTEX(QLI_OPENMUTEX(info), "qli_openmutex", lun_vhdl); + QL_SPINIT_LOCK(info->qli_lock, "qli_lock", lun_vhdl); + + return info; +} + +/* + * add a ql device vertex to the hardware graph + */ +static vertex_hdl_t +ql_device_add(vertex_hdl_t ctlr_vhdl, + int targ, + int lun, + int rev) +{ + vertex_hdl_t lun_vhdl; + vertex_hdl_t targ_vhdl; + scsi_lun_info_t *lun_info; + pHA_INFO ha = ql_ha_info_from_ctlr_get(ctlr_vhdl); + + /* + * add the target vertex + */ + + targ_vhdl = scsi_targ_vertex_add(ctlr_vhdl,targ); + ha->ql_defaults.Id[targ].Force_Sync = 0; + + + /* + * add the lun vertex + */ + + lun_vhdl = scsi_lun_vertex_add(targ_vhdl,lun); + + /* + * get the lun info pointer + */ + + lun_info = scsi_lun_info_get(lun_vhdl); + + /* + * initialize the ql specific lun info + */ + + SLI_INFO(lun_info) = ql_local_info_init(rev, lun_vhdl); + + + /* allocate the request block */ + if (ha->reqi_block[targ]==NULL) + ha->reqi_block[targ]= QL_KMEM_ZALLOC(sizeof(REQ_INFO)*(MAX_REQ_INFO+1), VM_NOSLEEP); + + TINFO(lun_info) = ql_scsi_targ_info_init(); + return lun_vhdl; +} + +/* + * remove the ql device vertex and the path leading to it from + * controller vertex ( target/#/lun/#). + * + * the basic idea is to remove the last vertex in target/#/lun/# subpath. + * if this is the last vertex to be removed we don't need the "lun" part of + * the path and we can remove that. this part of the logic is handled by + * scsi_lun_vertex_remove + * + * if the "lun" vertex of the above path has been removed + * scsi_lun_vertex_remove will return GRAPH_VERTEX_NONE in which case + * we have targ/# subpath left and we can go ahead and remove the last + * vertex corr. to specific target number. + * as before we then check if there are any specific target number vertices. + * if there aren't any we can remove the "target" vertex also. this part of + * the logic is handled by scsi_targ_vertex_remove + * + */ + +static void +ql_device_remove(vertex_hdl_t ctlr_vhdl, + int targ, + int lun) +{ + vertex_hdl_t targ_vhdl, lun_vhdl; + scsi_target_info_t *info; + pHA_INFO ha; + + int remove_targ; + lun_t lu; + scsi_lun_info_t *lun_info; + ql_local_info_t *qli; + + targ_vhdl = scsi_targ_vertex_exist(ctlr_vhdl, targ); + lun_vhdl = scsi_lun_vertex_exist(targ_vhdl, lun); + + lun_info = scsi_lun_info_get(lun_vhdl); + ha = ql_ha_info_from_lun_get(lun_vhdl); + mutex_destroy(&OPEN_MUTEX(lun_info)); + qli = SLI_INFO(lun_info); + QL_SPLOCK_DESTROY(qli->qli_lock); + info = TINFO(lun_info); + if (info->si_inq != NULL) + kmem_free(info->si_inq, SCSI_INQUIRY_LEN); + if (info->si_sense != NULL) + kmem_free(info->si_sense, SCSI_SENSE_LEN); + + kmem_free(TINFO(lun_info), sizeof(scsi_target_info_t)); + kmem_free(SLI_INFO(lun_info), sizeof(ql_local_info_t)); + SLI_INFO(lun_info) = NULL; + + scsi_lun_vertex_remove(targ_vhdl, lun); + remove_targ = 1; + for (lu = 0; lu < QL_MAXLUN; lu ++) + if (scsi_lun_vertex_exist(targ_vhdl, lu) != GRAPH_VERTEX_NONE) { + remove_targ = 0; + break; + } + if (remove_targ) { + scsi_targ_vertex_remove(ctlr_vhdl, targ); + kmem_free(ha->reqi_block[targ], sizeof(REQ_INFO)*(MAX_REQ_INFO+1)); + ha->reqi_block[targ]=NULL; + } +} + + +/* + * get the pointer to host adapter info given the + * vertex handle of the vertex corr. to the + * controller + */ +pHA_INFO +ql_ha_info_from_ctlr_get(vertex_hdl_t ctlr_vhdl) +{ + scsi_ctlr_info_t *ctlr_info; + + if (ctlr_vhdl == GRAPH_VERTEX_NONE) + return NULL; + ctlr_info = scsi_ctlr_info_get(ctlr_vhdl); + ASSERT(ctlr_info); + return(SCI_HA_INFO(ctlr_info)); +} + +/* + * get the pointer to host adapter info given the + * ql device vertex handle + */ +static pHA_INFO +ql_ha_info_from_lun_get(vertex_hdl_t lun_vhdl) +{ + + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(lun_vhdl); + ASSERT(lun_info); + ASSERT(SLI_CTLR_INFO(lun_info)); + + return(SLI_HA_INFO(lun_info)); + +} +/* + * put the pointer to host adapter structure into the info + * associated with the controller vertex + */ +static void +ql_ha_info_put(vertex_hdl_t ctlr_vhdl, + pHA_INFO ha) +{ + scsi_ctlr_info_t *ctlr_info; + + /* + * the info structure associated with the controller + * vertex has been created when the vertex was added + */ + + ctlr_info = scsi_ctlr_info_get(ctlr_vhdl); + ASSERT(ctlr_info); + ASSERT(!SCI_HA_INFO(ctlr_info)); + + + SCI_INFO(ctlr_info) = ha; +} + + +/* +** Function: ql_init +** +** Description: Initialize a particular ISP +*/ +static vertex_hdl_t +ql_init(scsi_pci_vhdl_t ql_pci_vhdl, pISP_REGS mem_map_addr) +{ + + /* due to parallel attach, this needs a lock */ + QL_MUTEX_LOCK(ql_driver_lock); + if (!ql_watchdog_timer_inited) + { + ql_watchdog_timer_inited = 1; + itimeout(ql_watchdog_timer, NULL, WATCHDOG_TIME * HZ, TIMEOUT_SPL); + } + QL_MUTEX_UNLOCK(ql_driver_lock); + + + /* + ** Initialize this board. + ** If this fails, then it won't be marked as valid (ignore). + */ + return ql_init_board(ql_pci_vhdl, mem_map_addr); +} + + +/* Function: ql_init_board +** +** Description: Initialize specific ISP board. +** Returns: 0 = success +** 1 = failure +*/ +static vertex_hdl_t +ql_init_board(scsi_pci_vhdl_t ql_pci_vhdl, pISP_REGS mem_map_addr) +{ + pHA_INFO ha=NULL; + pCHIP_INFO chip_info=NULL; + uint16_t vendor_id=0; + uint16_t dev_id=0; + uint8_t rev_id=0; + u_short clock_rate; + int rc = 0; + int channel_count=0; + int i; + + /* Make sure this is a ISP. */ + vendor_id = pciio_config_get(ql_pci_vhdl, PCI_CFG_VENDOR_ID, 2); + dev_id = pciio_config_get(ql_pci_vhdl, PCI_CFG_DEVICE_ID, 2); + rev_id = pciio_config_get(ql_pci_vhdl, PCI_CFG_REV_ID, 1); + + /* If this device is not ours, just leave. */ + if (vendor_id == QLogic_VENDOR_ID ) + { + if (dev_id == QLogic_1040_DEVICE_ID) { + channel_count = 1; + clock_rate = FAST20_CLOCK_RATE; + } + else + if (dev_id == QLogic_1240_DEVICE_ID) { + channel_count = 2; + clock_rate = FAST20_CLOCK_RATE; + } + else + if (dev_id == QLogic_1080_DEVICE_ID) { + channel_count = 1; + clock_rate = FAST40_CLOCK_RATE; + } + else + if (dev_id == QLogic_1280_DEVICE_ID) { + channel_count = 2; + clock_rate = FAST40_CLOCK_RATE; + } + else + if (dev_id == QLogic_12160_DEVICE_ID) { + channel_count = 2; + clock_rate=FAST80_CLOCK_RATE; + } + else + { + rc = 1; + goto init_failed; + } + + } else { + rc = 1; + goto init_failed; + } + + /* Use the addresses they specified. */ + /* Note: this doesn't care whether this is a memory address */ + /* or an I/O address (its whatever they specified). */ + + + /* Allocate and init memory for the adapter structure. */ + { + u_int id; + int i; + + chip_info = (pCHIP_INFO) QL_KMEM_ZALLOC(sizeof(CHIP_INFO), VM_CACHEALIGN | VM_DIRECT | VM_NOSLEEP); + if (chip_info==NULL) + { rc=4; + goto init_failed; + } + + sprintf(chip_info->chip_name, "ql%s", ql_pci_vhdl->slot_name); + +#ifdef PIO_TRACE + chip_info->ql_log_vals = (uint *)QL_KMEM_ZALLOC(sizeof(uint) * QL_LOG_CNT, + VM_CACHEALIGN | VM_NOSLEEP | VM_DIRECT); + + if (chip_info->ql_log_vals == NULL) + { rc=4; + kmem_free(chip_info, sizeof(CHIP_INFO)); + goto init_failed; + } +#endif + + /* pci revision id */ + chip_info->revision = rev_id; + + /* pci device id */ + chip_info->device_id = dev_id; + + chip_info->ha_base = (caddr_t) mem_map_addr; + chip_info->pci_vhdl = ql_pci_vhdl; + chip_info->channel_count = channel_count; + chip_info->clock_rate = clock_rate; + chip_info->chip_flags = 0; + chip_info->req_rotor = 0; + + /* needs to load seperate microcode for 1040 and (1240, 1080 and 1280) */ + if (dev_id == QLogic_1040_DEVICE_ID) { + chip_info->risc_code = risc_1040_code01; + chip_info->risc_code_length = risc_1040_code_length01; + chip_info->risc_code_addr = risc_1040_code_addr01; + } + else if (dev_id == QLogic_12160_DEVICE_ID) { + chip_info->risc_code = risc_12160_code01; + chip_info->risc_code_length = risc_12160_code_length01; + chip_info->risc_code_addr = risc_12160_code_addr01; + } + else { + chip_info->risc_code = risc_1080_code01; + chip_info->risc_code_length = risc_1080_code_length01; + chip_info->risc_code_addr = risc_1080_code_addr01; + } + + QL_INIT_LOCK(&chip_info->ctlrlock, "ql_ctlr", ql_pci_vhdl); + QL_INIT_MUTEX(chip_info->probemutex, "ql_probemutex", ql_pci_vhdl); + QL_INIT_MUTEX(chip_info->mboxmutex, "ql_mboxmutex", ql_pci_vhdl); + + initnsema(&chip_info->mbox_done_sema, 0, "ql_mboxsema"); + + /* put together the alenlist */ + chip_info->alen_p = alenlist_create(0); + + for (i=0; ichip_info = (pCHIP_INFO)chip_info; + ha->chip_info->revision = + pciio_config_get(ql_pci_vhdl, PCI_CFG_REV_ID, 1); + ha->chip_info->ha_info[i] = ha; + ha->host_flags = 0; + + /* assign the channel id */ + ha->channel_id = i; + + ha->ctlr_vhdl = ql_ctlr_add(ql_pci_vhdl, i, channel_count); + scsi_ctlr_vertex_sprintf(ha->ha_name, ql_pci_vhdl, (channel_count > 1 ? i+1 : i)); + + ql_ha_info_put(ha->ctlr_vhdl, ha); + ha->chip_info->ctlr_vhdl[i] = ha->ctlr_vhdl; + + /* Put this adapter on the ha_list */ + QL_MUTEX_LOCK(ql_driver_lock); + ha->next_ha = (ql_ha_list) ? ql_ha_list : NULL; + ql_ha_list = ha; + QL_MUTEX_UNLOCK(ql_driver_lock); + + /* Init the raw request queue to empty. */ + ha->req_forw = NULL; + ha->req_back = NULL; + + ql_set_defaults(ha); + + for (id = 0; id < QL_MAXTARG; id++) + { + + ha->tcmd[id]=0; + ha->reqi_cntr[id] = 1; + } + ha->ql_ncmd=0; + + } + } + + initnsema(&chip_info->intr_sema, 0, "ql_intr_sema"); + sthread_create ("ql_intr",0,0,0, + -10, /* some priority, TBD later */ + KT_PS, /* priority scheduled */ + (st_func_t *)ql_intr_thread, + (void *)chip_info, (void *)NULL, (void *)NULL, (void *)NULL); + if (request_irq(chip_info->pci_vhdl->irq, ql_intr_handler, + SA_INTERRUPT | SA_SHIRQ, "ql", chip_info)) { + printk("%s: interrupt %d already in use\n", + chip_info->chip_name, chip_info->pci_vhdl->irq); + goto init_failed; + } + + if (ql_init_isp(chip_info)) + { + chip_info->chip_flags = AFLG_CHIP_SHUTDOWN; + rc = 2; + goto init_failed; + } + + /* We added a parameter that can be used to LOGICALLY */ + /* disable the board. If they set this flag, then we shouldn't */ + /* publish this adapter board to the SCSI drivers. However, */ + /* we do need to be able to open the device in order to update */ + /* the parameters to re-enable this board. */ + /* So say we failed the initialization, and check whether the */ + /* actual initialization of the adapter failed (with INITIALIZED */ + /* flag) in open routine. */ + for (i=0; ichannel_count;i++){ + ha = chip_info->ha_info[i]; + if (!ha->ql_defaults.HA_Enable) + { + rc = 3; + goto init_failed; + } + } + + /* Indicate we found the board by returning vertex handle of bus 0 */ + return chip_info->ctlr_vhdl[0]; + +init_failed: + if (ha) + ql_cpmsg(ha->ctlr_vhdl, "ql_init_board failed (%d)\n", rc); + else + cmn_err(CE_CONT, "ql_init_board failed (%d)\n", rc); + return GRAPH_VERTEX_NONE; +} + + + +/* Function: ql_init_isp() +** +** Description: Initialize the ISP chip on a specific board. +** Returns: 0 = success +** 1 = failure +*/ + +static int +ql_init_isp(pCHIP_INFO chip_info) +{ + int rc = 0; + int bus_reset_on_init; + + + + QL_LOCK(chip_info); + + chip_info->response_base = (queue_entry *)QL_KVPALLOC(btoc(sizeof(queue_entry)*chip_info->ql_response_queue_depth), + VM_UNCACHED | VM_DIRECT | VM_NOSLEEP | VM_PHYSCONTIG, + 0); + if (chip_info->response_base == NULL) + { + rc = 1; + goto init_done; + } + + chip_info->request_base = (queue_entry *)QL_KVPALLOC(btoc(sizeof(queue_entry)*chip_info->ql_request_queue_depth), + VM_UNCACHED | VM_DIRECT | VM_NOSLEEP | VM_PHYSCONTIG, + 0); + if(chip_info->request_base == NULL) + { + kvpfree(chip_info->response_base, btoc(sizeof(queue_entry)*chip_info->ql_response_queue_depth)); + chip_info->response_base=NULL; + rc = 2; + goto init_done; + } + + chip_info->request_ptr = chip_info->request_base; + chip_info->response_ptr = chip_info->response_base; + chip_info->response_out = 0; + + /* Initialize request queue indexes. */ + + chip_info->queue_space = 0; + chip_info->request_in = 0; + chip_info->request_out = 0; + if (ql_download_fw(chip_info)) + { + rc = 3; + goto init_done; + } + + /* + * Determine whether a SCSI bus reset is to be done + */ + if (ql_bus_reset_on_boot == -1) + bus_reset_on_init = 0; + else + if (ql_bus_reset_on_boot == +1) + bus_reset_on_init = 1; + else + bus_reset_on_init = BUS_RESET_ON_INIT; + + if (ql_reset_interface(chip_info, bus_reset_on_init)) + { + rc = 4; + goto init_done; + } + + init_done: + QL_UNLOCK(chip_info); + if (rc) { + ql_cpmsg(chip_info->ctlr_vhdl[0], "ql_init_isp failed (%d)\n", rc); + if (chip_info->channel_count > 1 ) + ql_cpmsg(chip_info->ctlr_vhdl[1], "ql_init_isp failed (%d)\n", rc); + } + return(rc); +} + + + +/* Function: ql_enable_intrs() +** +** Description: Enable interrupts for our board. +*/ +static void +ql_enable_intrs(pCHIP_INFO chip_info) +{ + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + +#ifdef BUS_INT_WAR + sn_add_polled_interrupt(chip_info->pci_vhdl->irq, 1); +#endif + + /* We're all initialized, LET's have them interrupts BABY! */ + QL_PCI_OUTH(&isp->bus_icr, (ICR_ENABLE_RISC_INT | ICR_ENABLE_ALL_INTS)); + + + /* Remember that we enabled the interrupts. */ + chip_info->chip_flags |= AFLG_CHIP_INTERRUPTS_ENABLED; +} + + +#ifdef QL_SRAM_PARITY +/* Function: ql_enable_sram_parity() +** +** Description: Enable sram parity checking. +** initialize the sram if requested to +*/ +static int +ql_enable_sram_parity(pCHIP_INFO chip_info,int init_sram) +{ + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + u_short mbox_sts[8]; + u_short mailbox0; + u_short hccr, result; + int i; + int read_fail = 0; + + /* the sram parity test never worked for 12160. And there were problems + with it on 1080 and 1240. Since only SGI built 1040 based hardware + has parity sram, we'll just skip the test for anything else */ + if (chip_info->device_id != QLogic_1040_DEVICE_ID) + return(0); + + if (chip_info->chip_flags & AFLG_CHIP_SRAM_PARITY_ENABLE) { + QL_PCI_OUTH(&isp->hccr, HCCR_SRAM_PARITY_ENABLE | HCCR_SRAM_PARITY_BANK0); + QL_PPMSGS(chip_info,"Enabled SRAM parity checking.\n"); + } + + if(init_sram) { + chip_info->chip_flags |= AFLG_CHIP_INITIAL_SRAM_PARITY; + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); + + QL_PCI_OUTH(&isp->r3,0xbeef); /* data pattern */ + /* no. of words to initialize */ + QL_PCI_OUTH(&isp->r4,0x8000); + QL_PCI_OUTH(&isp->r8,0x0016); /* start addr of routine */ + QL_PCI_OUTH(&isp->r9,0x0449); /* exit point after mailbox */ + QL_PCI_OUTH(&isp->rar1,0x1000); /* first address to clear memory */ + QL_PCI_OUTH(&isp->control_dma_address_counter_0,0x43a4); + /* movb r3,[rar1++] ; clear memory */ + QL_PCI_OUTH(&isp->control_dma_address_counter_1,0x8421); + /* dec r4 ; decrement counter */ + QL_PCI_OUTH(&isp->control_dma_address_counter_2,0x08c2); + /* jnz [r8] ; JIF not done with all addresses */ + QL_PCI_OUTH(&isp->control_dma_address_counter_3,0x097a); + /* jmp [r9] ; goto Exit point when done */ + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + /* + * issue mbox command and poll until the command is done + */ + + /* set the starting address of the program to execute */ + QL_PCI_OUTH(&isp->mailbox1, 0x0016); + + /* set the command to execute the firmware */ + QL_PCI_OUTH(&isp->mailbox0, MBOX_CMD_EXECUTE_FIRMWARE); + + + /* Wake up the isp. */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_SET_HOST_INT); + /* poll for command to be done */ + for (i = 0;i < QL_COMPUTE_PARITY_MEMORY; i++) { + mailbox0 = QL_PCI_INH(&isp->mailbox0); + if (mailbox0 == MBOX_STS_COMMAND_COMPLETE) + break; + DELAY(1000); + } + + + /* reset the semaphore */ + QL_PCI_OUTH(&isp->bus_sema, 0); + + /* reset the interrupt */ + QL_PCI_OUTH(&isp->bus_isr, 0); + + /* reset the risc interrupt */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + + /* release the risc process */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + /* + * check to see if sram parity is supported by reading back the data pattern + * and compare if data pattern is correct and no parity error. + */ + + + /* try to read first 32 words of the data from address 0x1000 */ + for (i=0; i<32; i++) { + + if (ql_mbox_cmd(chip_info, mbox_sts, 2, 3, + MBOX_CMD_READ_RAM_WORD, + (u_short) (0x1000 + i), + 0, 0, 0, 0, 0, 0)) + read_fail =1; + + hccr = QL_PCI_INH(&isp->hccr); + + result = hccr & HCCR_SRAM_PARITY_ERROR_DETECTED_1040; + + if (result || read_fail) { + /* check to make sure the data is corrected */ + /* if data is corrected then the board does support parity */ + + /* controller does not support parity */ + chip_info->chip_flags &= ~(AFLG_CHIP_SRAM_PARITY_ENABLE | AFLG_CHIP_INITIAL_SRAM_PARITY); + + QL_PCI_OUTH(&isp->bus_icr, ICR_ENABLE_RISC_INT | ICR_SOFT_RESET); + flushbus(); + + DELAY(30); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RESET); + + + /* disable the sram parity checking */ + hccr &= ~(HCCR_SRAM_PARITY_ENABLE|HCCR_SRAM_PARITY_BANK0); + QL_PCI_OUTH(&isp->hccr, hccr); + + /* clear the interrupt */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + + /* release the risc process */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + /* return to caller */ + return(0); + } + + + } + + /* done with initializing the sram parity */ + chip_info->chip_flags &= ~AFLG_CHIP_INITIAL_SRAM_PARITY; + } + + /* return to caller */ + return(0); + +} +#endif /* QL_SRAM_PARITY */ + + +/* Entry-Point +** Function: qlioctl +** +** Description: Perform host adapter I/O control operations. +*/ +int +qlioctl(vertex_hdl_t ql_ctlr_vhdl, + uint cmd, + scsi_ha_op_t *op) +{ + pHA_INFO ha = ql_ha_info_from_ctlr_get(ql_ctlr_vhdl); + pCHIP_INFO chip_info = ha->chip_info; + u_short mbox_sts[8]; + int err = 0; /* assume no errors */ + int state = NO_QUIESCE_IN_PROGRESS; + int s; + + /* Now, execute passed command ... */ + switch(cmd) + { + case SOP_RESET: + QL_LOCK(ha->chip_info); + if (ql_reset(ql_ctlr_vhdl)) { + err = EIO; + ql_cpmsg(ql_ctlr_vhdl, "SCSI bus reset failed\n"); + } + /* + * Reset Target parameters to their default + * values. + */ + { + int id; + + for (id = 0; id < QL_MAXTARG; ++id) { + if (id == ha->ql_defaults.Initiator_SCSI_Id) + continue; + if (scsi_lun_vhdl_get(ql_ctlr_vhdl, id, 0) == GRAPH_VERTEX_NONE) + continue; + if (ql_set_scsi_parameters(ha->chip_info, mbox_sts, + ha->channel_id, id) ) { + ql_tpmsg(ql_ctlr_vhdl, id, "MBOX_CMD_SET_TARGET_PARAMETERS failed\n"); + } + + } + } + QL_UNLOCK(ha->chip_info); + break; + + case SOP_SCAN: + scan_bus(ql_ctlr_vhdl); + break; + + case SOP_DEBUGLEVEL: /* set debug print count */ + ql_debug = op->sb_arg; + break; + + case SOP_QUIESCE: + + /* + * set the quiesce in progress flag in the ha structure + * set two timeouts + * 1. timeout to succesfully quiesce bus + * 2. timeout for max time to allow quiesce + * if quiesce in progress replace timeouts with + * new ones + * sb_opt = time for quiesce attempt + * sb_arg = time for quiesce to be active + */ + + if( (op->sb_opt == 0) || (op->sb_arg == 0) ) { + err = EINVAL; + break; + } + QL_LOCK(ha->chip_info); + ql_quiesce_bus(ha, op->sb_opt, op->sb_arg); + QL_UNLOCK(ha->chip_info); + break; + + + case SOP_UN_QUIESCE: + /* + * reset the in progress and complete flags + * reset the timeouts + * reset the controller state and rescan the bus + * attempt to start pending commands + */ + QL_LOCK(ha->chip_info); + if (!(ha->host_flags & AFLG_HA_TIMEOUT)) /* prevent killing a watchdog quiesce */ + undo_quiesce(ha, KILL_WITH_TIMEOUT); + QL_UNLOCK(ha->chip_info); + break; + + case SOP_QUIESCE_STATE: + /* report the queice state */ + if (ha->host_flags & AFLG_HA_QUIESCE_IN_PROGRESS) + state = QUIESCE_IN_PROGRESS; + else + if (ha->host_flags & AFLG_HA_QUIESCE_COMPLETE) + state = QUIESCE_IS_COMPLETE; + + copyout(&state,(void *)op->sb_addr,sizeof(int)); + break; + + case SOP_GET_SCSI_PARMS: + { + struct scsi_parms sp; + int targ; + + bzero(&sp, sizeof(struct scsi_parms)); + + QL_LOCK(ha->chip_info); + + sp.sp_is_diff = ha->bus_mode >> 1; + + if ((sp.sp_selection_timeout = (u_short)ha->ql_defaults.Selection_Timeout) >= 250) + sp.sp_selection_timeout *= 1000; + sp.sp_scsi_host_id = (u_short)ha->ql_defaults.Initiator_SCSI_Id; + + for (targ = 0; targ < QL_MAXTARG; ++targ) + { + if (targ == ha->ql_defaults.Initiator_SCSI_Id) + continue; + if (scsi_lun_vhdl_get(ql_ctlr_vhdl, targ, 0) == GRAPH_VERTEX_NONE) + continue; + sp.sp_target_parms[targ].stp_is_present = 1; + if (ql_get_scsi_parameters(chip_info, mbox_sts, ha->channel_id, + targ)) + { + ql_tpmsg(ha->ctlr_vhdl, targ, "MBOX_CMD_GET_TARGET_PARAMETERS command failed\n"); + err = EIO; + } + else + { + if ((mbox_sts[2] >> 8) & CAP_SYNC_DATA_TRANSFERS) + { + sp.sp_target_parms[targ].stp_is_sync = 1; + sp.sp_target_parms[targ].stp_sync_offset = (mbox_sts[3] & 0xFF00) >> 8; + /* cant just do a multiply by 4 always anymore */ + switch (mbox_sts[3] & 0xff) + { case 9: + sp.sp_target_parms[targ].stp_sync_period=12; + break; + case 10: + sp.sp_target_parms[targ].stp_sync_period=25; + break; + case 12: + sp.sp_target_parms[targ].stp_sync_period=50; + break; + case 16: + sp.sp_target_parms[targ].stp_sync_period=67; + break; + case 18: + sp.sp_target_parms[targ].stp_sync_period=75; + break; + case 20: + sp.sp_target_parms[targ].stp_sync_period=83; + break; + case 29: + sp.sp_target_parms[targ].stp_sync_period=117; + break; + case 31: + sp.sp_target_parms[targ].stp_sync_period=125; + break; + case 33: + sp.sp_target_parms[targ].stp_sync_period=132; + break; + case 37: + sp.sp_target_parms[targ].stp_sync_period=150; + break; + case 41: + sp.sp_target_parms[targ].stp_sync_period=167; + break; + case 43: + sp.sp_target_parms[targ].stp_sync_period=175; + break; + case 45: + sp.sp_target_parms[targ].stp_sync_period=183; + break; + case 54: + sp.sp_target_parms[targ].stp_sync_period=217; + break; + case 56: + sp.sp_target_parms[targ].stp_sync_period=225; + break; + case 58: + sp.sp_target_parms[targ].stp_sync_period=233; + break; + case 62: + sp.sp_target_parms[targ].stp_sync_period=250; + break; + case 66: + sp.sp_target_parms[targ].stp_sync_period=267; + break; + case 68: + sp.sp_target_parms[targ].stp_sync_period=275; + break; + case 81: + sp.sp_target_parms[targ].stp_sync_period=325; + break; + case 87: + sp.sp_target_parms[targ].stp_sync_period=350; + break; + case 96: + sp.sp_target_parms[targ].stp_sync_period=387; + break; + default: /* 25, 27, 30, 32, 35, 37, 40, 50, 75 */ + sp.sp_target_parms[targ].stp_sync_period= + (mbox_sts[3] & 0xff)*4; + break; + } + } + sp.sp_target_parms[targ].stp_is_wide = + (((mbox_sts[2] >> 8) & CAP_WIDE_DATA_TRANSFERS) == CAP_WIDE_DATA_TRANSFERS); + } + } + QL_UNLOCK(ha->chip_info); + copyout(&sp, (void *)op->sb_addr, sizeof(struct scsi_parms)); + break; + } /* SOP_GET_SCSI_PARMS */ + + case SOP_SET_BEHAVE: + { + vertex_hdl_t lun_vhdl; + ql_local_info_t *qli; + + QL_LOCK(ha->chip_info); + switch(op->sb_opt) { + case LUN_QERR: + { + u_char targ = (op->sb_arg >> SOP_QERR_TARGET_SHFT) & 0xFF; + u_char lun = (op->sb_arg >> SOP_QERR_LUN_SHFT) & 0xFF; + u_char qerr = (op->sb_arg >> SOP_QERR_VAL_SHFT) & 0xFF; + + + if ((lun_vhdl = scsi_lun_vhdl_get(ql_ctlr_vhdl, targ, lun)) == GRAPH_VERTEX_NONE) { + ql_cpmsg(ha->ctlr_vhdl, + "SOP_SET_BEHAVE LUN_QERR failed: targ/lun %d/%d not valid\n", targ, lun); + err = EINVAL; + break; + } + qli = SLI_INFO(scsi_lun_info_get(lun_vhdl)); + ASSERT(qli); + QL_SPLOCK(qli->qli_lock, s); + if (qerr) + qli->qli_dev_flags |= DFLG_BEHAVE_QERR1; + else + qli->qli_dev_flags &= ~DFLG_BEHAVE_QERR1; + QL_SPUNLOCK(qli->qli_lock, s); + } + break; + default: + ql_cpmsg(ha->ctlr_vhdl, "Illegal SOP_SET_BEHAVE sub-code 0x%x\n", op->sb_opt); + err = EINVAL; + } + QL_UNLOCK(ha->chip_info); + break; + } /* SOP_SET_BEHAVE */ + + default: + err = EINVAL; + } + return(err); /* nothing to return */ +} + +/* Entry-Point +** Function: ql_entry +** +** Description: Execute a SCSI request. +** +** Returns: 0 = success (i.e. I understood the request) +** -1 = failure (what the heck was that?) +*/ +static int +ql_entry(scsi_request_t* request) +{ + u_short id = request->sr_target; + u_short lun = request->sr_lun; + ql_local_info_t *qli = SLI_INFO(scsi_lun_info_get(request->sr_lun_vhdl)); + pHA_INFO ha = ql_ha_info_from_lun_get(request->sr_lun_vhdl); + pCHIP_INFO chip_info = ha->chip_info; + int s; + + /* Before processing the request, make sure we will return good status. */ + request->sr_status = 0; + request->sr_scsi_status = 0; + request->sr_ha_flags = 0; + request->sr_sensegotten = 0; + request->sr_spare = (sr_spare_t) (uintptr_t) ha; + + /* + * Ensure buffer alignment constraints are enforced. Only need + * to check for the case of KV or UV addresses; PAGEIO is + * guaranteed to be page aligned. + */ + if (request->sr_flags & (SRF_MAPUSER | SRF_MAP) && + request->sr_buflen != 0 && + ((uintptr_t) request->sr_buffer & 3)) + { + request->sr_status = SC_ALIGN; + (*request->sr_notify)(request); + return(0); + } + + + QL_LOCK(ha->chip_info); + + /* Error if the adapter specified is invalid. */ + if ((ha == NULL) || (chip_info->chip_flags & AFLG_CHIP_SHUTDOWN)) { + QL_UNLOCK(ha->chip_info); + request->sr_status = SC_REQUEST; + (*request->sr_notify)(request); + return (0); + } + + QL_SPLOCK(qli->qli_lock, s); + /* + * If CONTINGENT ALLEGIANCE in effect and requestor hasn't set + * the AEN_ACK flag, then bail out. + */ + if (qli->qli_dev_flags & DFLG_CONTINGENT_ALLEGIANCE) { + if (request->sr_flags & SRF_AEN_ACK) { + qli->qli_dev_flags &= ~DFLG_CONTINGENT_ALLEGIANCE; + } + else { + QL_SPUNLOCK(qli->qli_lock, s); + QL_UNLOCK(ha->chip_info); + request->sr_status = SC_ATTN; + (*request->sr_notify)(request); + return(0); + } + } + + + /* + * If the LUN is being aborted, stick the command into the LUN + * abort wait Q. + */ + if (qli->qli_dev_flags & DFLG_ABORT_IN_PROGRESS) + { + if (qli->qli_awaitf) + qli->qli_awaitb->sr_ha = request; + else + qli->qli_awaitf = request; + qli->qli_awaitb = request; + request->sr_ha = NULL; + QL_SPUNLOCK(qli->qli_lock, s); + QL_UNLOCK(ha->chip_info); + return(0); + } + + /* + * If LUN is being initialized, stick the command into the LUN + * init. Q. + */ + if (qli->qli_dev_flags & DFLG_INIT_IN_PROGRESS) + { + if (qli->qli_iwaitf) + qli->qli_iwaitb->sr_ha = request; + else + qli->qli_iwaitf = request; + qli->qli_iwaitb = request; + request->sr_ha = NULL; + QL_SPUNLOCK(qli->qli_lock, s); + QL_UNLOCK(ha->chip_info); + return(0); + } + + /* + * Check that the device has been initialized + */ + if (!(qli->qli_dev_flags & DFLG_INITIALIZED) ) { + u_short mbox_sts[8]; + + /* + * Before we can initialize the device, we must make sure that the + * chip has been initialized. If not, then release the mutex and + * delay a bit before retrying. + */ + while (!(chip_info->chip_flags & AFLG_CHIP_INITIALIZED)) { + QL_SPUNLOCK(qli->qli_lock, s); + QL_UNLOCK(ha->chip_info); + delay(1); + QL_LOCK(ha->chip_info); + QL_SPLOCK(qli->qli_lock, s); + } + + qli->qli_dev_flags |= DFLG_INIT_IN_PROGRESS; + + /* + * Check the flag again, in case someone beat us to it. + */ + if (qli->qli_dev_flags & DFLG_INITIALIZED) { + qli->qli_dev_flags &= ~DFLG_INIT_IN_PROGRESS; + QL_SPUNLOCK(qli->qli_lock, s); + goto lun_init_done; + } + QL_SPUNLOCK(qli->qli_lock, s); + + if (ql_set_device_queue_parameters(chip_info, mbox_sts, + ha->channel_id, id, lun)) { + ql_tpmsg(ha->ctlr_vhdl, id, "MBOX_CMD_SET_TARGET_PARAMETERS command failed\n"); + } + + if (ql_set_scsi_parameters(chip_info, mbox_sts, ha->channel_id, id)) { + ql_tpmsg(ha->ctlr_vhdl, id, "MBOX_CMD_SET_TARGET_PARAMETERS command failed\n"); + } + + /* Device has now been initialized! */ + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags |= DFLG_INITIALIZED; + qli->qli_dev_flags &= ~DFLG_INIT_IN_PROGRESS; + QL_SPUNLOCK(qli->qli_lock, s); + + /* + * Move commands waiting in LUN init. queue into the wait Q + */ + if (qli->qli_iwaitf) + { + if (ha->waitf) + { + ha->waitb->sr_ha = qli->qli_iwaitf; + ha->waitb = qli->qli_iwaitb; + } + else + { + ha->waitf = qli->qli_iwaitf; + ha->waitb = qli->qli_iwaitb; + } + ha->waitb->sr_ha = NULL; + } + qli->qli_iwaitf = qli->qli_iwaitb = NULL; + } + else + QL_SPUNLOCK(qli->qli_lock, s); + lun_init_done: + /* + * Stick the command into the LUN Wait Q + */ + if (ha->waitf) + ha->waitb->sr_ha = request; + else + ha->waitf = request; + ha->waitb = request; + request->sr_ha = NULL; + + /* Start the command (if possible). */ + if (!(ha->host_flags & AFLG_HA_DRAIN_IO)) + ql_start_scsi(chip_info); + + if (chip_info->chip_flags & AFLG_CHIP_DUMPING) { + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + while (!(QL_PCI_INH(&isp->bus_isr) & BUS_ISR_RISC_INT)) { + DELAY(25); + } + QL_UNLOCK(ha->chip_info); + qlintr(chip_info); + QL_LOCK(ha->chip_info); + } + + QL_UNLOCK(ha->chip_info); + /* Return a status to indicate we understood the request. */ + return(0); +} + +#include +static void +ql_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + pCHIP_INFO chip_info = (pCHIP_INFO) dev_id; + +#ifndef CONFIG_IA64_SGI_SN + disable_irq_nosync(irq); +#endif + vsema(&chip_info->intr_sema); +} + +static void +ql_intr_thread(pCHIP_INFO chip_info) +{ + xscsi_disable_signals(); + lock_kernel(); + daemonize(); + sprintf(current->comm, "ql_intr"); + unlock_kernel(); + + while (1) { + /* XXX - add something so that we can shut it down */ + down_interruptible(&chip_info->intr_sema); + qlintr(chip_info); +#ifndef CONFIG_IA64_SGI_SN + enable_irq(chip_info->pci_vhdl->irq); +#endif + } +} + +/* Entry-Point +** Function: qlintr +** +** Description: This is the interrupt service routine. This is called +** by the system to process a hardware interrupt for our +** board, or by one of our internal routines that need to +** check for an interrupt by polling. These routines MUST +** lock out interrupts (splx) before calling here. +*/ + +void +qlintr(pCHIP_INFO chip_info) +{ + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + u_short isr = 0; + + QL_LOCK(chip_info); + if (chip_info->chip_flags & AFLG_CHIP_SHUTDOWN) + goto done; + + ASSERT((chip_info->chip_flags & AFLG_CHIP_IN_INTR) == 0); + + chip_info->chip_flags |= AFLG_CHIP_IN_INTR; + + /* Determine if this board caused the (an) interrupt. */ + isr = QL_PCI_INH(&isp->bus_isr); + + if (isr & BUS_ISR_RISC_INT) { + /* We have the interrupter...try to service the request. */ + + ql_service_interrupt(chip_info); + + } + + ASSERT(chip_info->chip_flags & AFLG_CHIP_IN_INTR); + + done: + chip_info->chip_flags &= ~AFLG_CHIP_IN_INTR; + QL_UNLOCK(chip_info); + +} + + +/* +** Function: ql_service_interrupt +** +** Description: This routine actually services the interrupt. +** There are two kinds of interrupts: 1) Responses available +** and 2) a Mailbox request completed. ALWAYS service the +** Mailbox interrupts first. Then process all responses we +** have (may be more than one). Do this by pulling off all +** the completed responses and putting them in a linked list. +** Then after we have them all, tell the adapter we have them +** and do completion processing on the list. This limits +** the amount of time the adapter has to wait to post new +** responses. +** +** The driver should then read mailbox 0. If Mailbox 0 contains a +** value of 0x8000 or greater then the Interrupt is for an Asynchronous +** Event. If Mailbox 0 contains a value between 0x4000 and 0x7fff +** then the value is reporting the results of a mailbox command. +** +** If the interrupt is for a Mailbox Command completion or an +** Asynchronous Event the driver must write a 0 to the Semaphore +** register when it has finished reading the data from the Mailboxes. +** Clearing the Semaphore informs the ISP that the driver has read +** all the information associated with the Mailbox Command or Asynch. +** Event. When the Semaphore is 0 the ISP is free to update the contents +** of the Mailbox registers. The driver may clear the semaphore before +** or after clearing the interrupt from the ISP. +** +** If the Semaphore register contains a 0 then the interrupt is +** reporting that the ISP has added an entry or entries to the +** response queue and the driver should read mailbox 5 to determine +** how many entries were added. The ISP will not add anymore entries +** to the queue or update mailbox 5 until the driver has cleared the +** interrupt from the ISP. +** +** To clear an interrupt from the ISP the driver must write a value of +** 0x7000 to the Host Command and Control (HCCR) register of the ISP. +** +** If the ISP has reported an interrupt to the host it will not modify +** the contents of the Semaphore register, or Mailbox registers 0-3,5-7. +** Until the driver has cleared the interrupt. However, the ISP will +** continu to remove entries from the Request Queue so it is possible +** that the ISP may modify the contents of Mailbox 4 while an interrupt +** is in progress. +** +*/ +static void +ql_service_interrupt(pCHIP_INFO chip_info) +{ + status_entry *q_ptr; + scsi_request_t *request; + ql_local_info_t *qli; + pREQ_INFO r_ptr; + pHA_INFO ha; + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + + scsi_request_t* cmp_forw = NULL; + scsi_request_t* cmp_back = NULL; + + int port, tgt, idx; + u_short isr=0; + void (*temp_callback)(vertex_hdl_t, uint8_t *); + u_char temp_sense[SCSI_SENSE_LEN]; + int s; + + + /* Process all the mailbox interrupts and all responses. */ + do { /* TAG 1 */ + u_short response_in=0; + u_short bus_sema=0; +#ifdef QL_SRAM_PARITY + u_short hccr=0; + u_short result; + int i; +#endif + /* + * Check for async mailbox events. + */ + bus_sema = QL_PCI_INH(&isp->bus_sema); + if (bus_sema & BUS_SEMA_LOCK) + { + ql_service_mbox_interrupt(chip_info); + } + + /* + * Mailbox command processing may have seem IOCB + * completions. Clear the flag + */ + chip_info->chip_flags &= ~AFLG_CHIP_ASYNC_RESPONSE_IN; + + /* + * If there aren't any completed responses then don't do any + * of the following. i.e. it was just a mailbox interrupt or + * spurious + */ + + response_in = chip_info->response_in = QL_PCI_INH(&isp->mailbox5); + if ((response_in == chip_info->response_out) || !(chip_info->chip_flags & AFLG_CHIP_INITIALIZED)) { + +#ifdef QL_SRAM_PARITY + /* check for an sram parity error condition */ + if (chip_info->device_id == QLogic_1040_DEVICE_ID) { + hccr = QL_PCI_INH(&isp->hccr); + result = hccr & HCCR_SRAM_PARITY_ERROR_DETECTED_1040; + + if(result) { + if (!(chip_info->chip_flags & AFLG_CHIP_DOWNLOAD_FIRMWARE)) { + ql_ppmsg(chip_info,"Q-logic sram parity error detected\n"); + if(hccr & HCCR_SRAM_PARITY_BANK0) + ql_ppmsg(chip_info, + "Q-logic sram parity error on bank 0 hccr=%x\n", + hccr); + if(hccr & HCCR_SRAM_PARITY_BANK1) + ql_ppmsg(chip_info, + "Q-logic sram parity error on bank 1\n"); +#ifdef DEBUG + dump_registers(chip_info,isp); +#endif + ql_reset_interface(chip_info,1); + for(i=0; ichannel_count; i++){ + ha = chip_info->ha_info[i]; + ql_flush_queue(ha, SC_HARDERR); + } + } else { + /* + * Parity error will occurred when downloading + * firmware. Ignore the interrupt with the clear and + * release the risc. + * step 1. disable parity checking + * step 2. clear interrupt + * step 3. reenable parity checking + * step 4. release the risc processor + */ + + /* disable parity checking */ + hccr &= ~(HCCR_SRAM_PARITY_ENABLE|HCCR_SRAM_PARITY_BANK0); + QL_PCI_OUTH(&isp->hccr, hccr); + + /* clear the interrupt */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + + /* enable the parity checking */ + QL_PCI_OUTH(&isp->hccr, HCCR_SRAM_PARITY_ENABLE | HCCR_SRAM_PARITY_BANK0); + /* release the risc processor */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + return; + + } + + } + } +#endif /* QL_SRAM_PARITY */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + return; + } + + /* + * Remove all of the responses from the queue. + */ + while ((chip_info->response_out != response_in)) { + q_ptr = (status_entry *)chip_info->response_ptr; + + +#ifdef DEBUG + if (ql_debug >= 2) + dump_iorb(q_ptr); +#endif + + /* + * Check for DEAD response. If dead response, then exit + * the response processing loop. The LEGO architecure + * guarantees no relative completion order vs. issue order + * of write DMAs and PIOs. Consequently, the PIO to read + * the response head pointer register may actually + * complete before the DMA write to update the + * corresponding response block completes. Imagine the + * following scenario: Command A completes and causes an + * interrupt. While in the ISR command B completes, which + * we know about by reading the response tail pointer + * (mailbox 5), but the DMA write to update the response + * block hasn't yet completed. If at this point we bail + * out and await the next interrupt, we'll pick up the + * response for command B then. An interrupt is a barrier + * operation so we're guaranteed that the DMA write will + * have completed by the time we get the interrupt. + */ + if (((volatile status_entry *)q_ptr)->handle == 0xDEAD) + { +#ifdef DEBUG + cmn_err(CE_WARN, "Premature response seen: handle 0x%x, q_ptr 0x%x.\n", + q_ptr->handle, q_ptr); +#endif + /* Update the ISP's response tail pointer. */ + QL_PCI_OUTH(&isp->mailbox5, chip_info->response_out); + + /* Notify caller of command competions */ + ql_notify_responses(chip_info, cmp_forw); + cmp_forw = cmp_back = NULL; + + goto got_responses; + } + + + /* + * Move the pointers for the next entry. + */ + if (chip_info->response_out == (chip_info->ql_response_queue_depth - 1)) + { + chip_info->response_out = 0; + chip_info->response_ptr = chip_info->response_base; + } + else + { + chip_info->response_out++; + chip_info->response_ptr++; + } + + /* + * Make sure the driver issued the command right. + */ + if (q_ptr->hdr.flags & EF_ERROR_MASK) { + if(q_ptr->hdr.flags & EF_BUSY) + ql_ppmsg(chip_info, "Detected busy condition\n"); + if(q_ptr->hdr.flags & EF_BAD_HEADER) + ql_ppmsg(chip_info, "Detected a bad header\n"); + if(q_ptr->hdr.flags & EF_BAD_PAYLOAD) + ql_ppmsg(chip_info, "Detected a bad payload\n"); + continue; + } + + if (q_ptr->hdr.entry_type != ET_STATUS) + { + ql_ppmsg(chip_info, "Invalid driver command issued: " + "entry_cnt 0x%x, entry_type 0x%x, flags 0x%x, sys_def_1 0x%x, handle 0x%x\n", + q_ptr->hdr.entry_cnt, q_ptr->hdr.entry_type, + q_ptr->hdr.flags, q_ptr->hdr.sys_def_1, + q_ptr->handle); +#ifdef DEBUG + if (ql_debug >= 2) + dump_iorb(q_ptr); +#endif + continue; + } + + ASSERT((q_ptr->handle > 0) && (q_ptr->handle <= MAX_HANDLE_NO)); + port = (q_ptr->handle & 0x00001000) >> 12; + if (port >= chip_info->channel_count) + panic("port is greater or equal channel count"); + tgt = (q_ptr->handle & 0x00000f00) >> 8; + idx = (q_ptr->handle & 0x000000ff); + ha = chip_info->ha_info[port]; + r_ptr = &ha->reqi_block[tgt][idx]; + request = r_ptr->req; + + /* make sure we have a live command. Its possible it got flushed since issue */ + if (request==NULL) + continue; + +#ifdef QL_TIMEOUT_DEBUG + if (/*request->sr_lun_vhdl == ql_timeout_debug_lunvhdl &&*/ + --ql_timeout_debug_timer <= 0) + { + ql_lpmsg(ha->ctlr_vhdl, request->sr_target, request->sr_lun, + "ql_timeout_debug: Dropping request 0x%x\n", request); + ql_timeout_debug_timer = ql_timeout_debug_frequency; + continue; + } +#endif + + ha->tcmd[tgt]--; + ha->ql_ncmd--; + + if ((ha->host_flags & AFLG_HA_DRAIN_IO) && (ha->ql_ncmd == 0)) + ha->host_flags &= ~AFLG_HA_DRAIN_IO; + + q_ptr->handle = 0xDEAD; + + /* + * Update LUN status - if all aborted commands have been + * returned, transfer all commands queued during the abort + * phase into the wait Q. + */ + qli = SLI_INFO(scsi_lun_info_get(request->sr_lun_vhdl)); + qli->qli_cmd_rcnt--; + + QL_SPLOCK(qli->qli_lock, s); + if ((qli->qli_dev_flags & DFLG_ABORT_IN_PROGRESS) && (qli->qli_cmd_rcnt == 0)) + { + qli->qli_dev_flags &= ~DFLG_ABORT_IN_PROGRESS; + qli->qli_dev_flags |= DFLG_SEND_MARKER; + + if (qli->qli_awaitf) + { + if (ha->waitf) + { + ha->waitb->sr_ha = qli->qli_awaitf; + ha->waitb = qli->qli_awaitb; + } + else + { + ha->waitf = qli->qli_awaitf; + ha->waitb = qli->qli_awaitb; + } + ha->waitb->sr_ha = NULL; + } + qli->qli_awaitf = qli->qli_awaitb = NULL; + } + QL_SPUNLOCK(qli->qli_lock, s); + + request->sr_status = SC_GOOD; + request->sr_scsi_status = q_ptr->scsi_status; + request->sr_resid = q_ptr->residual; + + + switch(q_ptr->completion_status) + { + case SCS_COMPLETE: /* OK completion */ + case SCS_DATA_UNDERRUN: /* Underruns are OK if request more data than delivered */ + break; + + case SCS_INCOMPLETE: + if (!(q_ptr->state_flags & SS_GOT_TARGET) && + (q_ptr->status_flags & SST_TIMEOUT)) + { + if (!(ha->host_flags & AFLG_HA_BUS_SCAN_IN_PROGRESS)) + ql_tpmsg(ha->ctlr_vhdl, request->sr_target, "Selection timeout\n"); + request->sr_status = SC_TIMEOUT; + } + else + goto comp_hard_error; + break; + + case SCS_DMA_ERROR: + if (q_ptr->state_flags & SS_TRANSFER_COMPLETE) + { ql_tpmsg(ha->ctlr_vhdl, request->sr_target, + "INVALID DMA ERROR: " + "completion status [0x%x] (%s), " + "scsi status[0x%x], state flags[0x%x], status flags[0x%x]\n", + q_ptr->completion_status, + ql_completion_status_msg(q_ptr->completion_status), + q_ptr->scsi_status, + q_ptr->state_flags, + q_ptr->status_flags); + request->sr_status=SC_HARDERR; + } + else + goto comp_hard_error; + break; + + case SCS_RESET_OCCURRED: + request->sr_status = SC_ATTN; + break; + + case SCS_ABORTED: + { + ql_local_info_t *qli = SLI_INFO(scsi_lun_info_get(request->sr_lun_vhdl)); + + request->sr_status = SC_ATTN; + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags |= DFLG_SEND_MARKER; + QL_SPUNLOCK(qli->qli_lock, s); + break; + } + + case SCS_TIMEOUT: + request->sr_status = SC_CMDTIME; + break; + + comp_hard_error: + case SCS_TRANSPORT_ERROR: + case SCS_DATA_OVERRUN: + case SCS_COMMAND_OVERRUN: + case SCS_ABORT_MSG_FAILED: + case SCS_UNEXPECTED_BUS_FREE: + default: + ql_tpmsg(ha->ctlr_vhdl, request->sr_target, + "HARD ERROR: " + "completion status [0x%x] (%s), " + "scsi status[0x%x], state flags[0x%x], status flags[0x%x]\n", + q_ptr->completion_status, + ql_completion_status_msg(q_ptr->completion_status), + q_ptr->scsi_status, + q_ptr->state_flags, + q_ptr->status_flags); + request->sr_status = SC_HARDERR; + break; + } /* switch (q_ptr->completion_status) */ + + /* + * return this reqblock to free state + */ + r_ptr->req = NULL; + + /* + * does this completeion complete our QUIESCE_IN_PROGRESS + */ + if ((ha->host_flags & AFLG_HA_QUIESCE_IN_PROGRESS) && + (ha->ql_ncmd == 0)) + { + ha->host_flags |= AFLG_HA_QUIESCE_COMPLETE; + ha->host_flags &= ~AFLG_HA_QUIESCE_IN_PROGRESS; + untimeout(ha->quiesce_in_progress_id); + ha->quiesce_id = timeout(kill_quiesce, ha, ha->quiesce_time, KILL_WITHOUT_TIMEOUT); + } + + request->sr_scsi_status = q_ptr->scsi_status; + + /* + * If a SCSI bus reset occurred, then we need to + * issue a marker before issuing any new requests. + */ + if (q_ptr->completion_status == SCS_RESET_OCCURRED) + ha->host_flags |= AFLG_HA_SEND_MARKER; + + /* + * Save any request sense info. + */ + if (q_ptr->state_flags & SS_GOT_SENSE) + { + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags |= DFLG_CONTINGENT_ALLEGIANCE; + + /* + * Go abort all other queued commands if QERR=1 + */ + if ((qli->qli_dev_flags & DFLG_BEHAVE_QERR1) && + ((qli->qli_dev_flags & DFLG_ABORT_IN_PROGRESS) == 0) && + (qli->qli_cmd_rcnt > 0)) { + u_short mbox_sts[8]; + + qli->qli_dev_flags |= DFLG_ABORT_IN_PROGRESS; + QL_SPUNLOCK(qli->qli_lock, s); + + if (ql_set_abort_device(ha->chip_info, mbox_sts, + ha->channel_id, request->sr_target, request->sr_lun)) { + ql_lpmsg(ha->ctlr_vhdl, request->sr_target, request->sr_lun, + "MBOX_CMD_ABORT_DEVICE Command failed\n"); + } + + } + else + QL_SPUNLOCK(qli->qli_lock, s); + + + if (ql_printsense) { + + ql_sensepr(ha->ctlr_vhdl, + request->sr_target, + request->sr_lun, + q_ptr->req_sense_data, + q_ptr->req_sense_length); + + if (ql_printsense > 1) { + int slen = q_ptr->req_sense_length; + u_char *sptr = q_ptr->req_sense_data; + + cmn_err(CE_CONT, "Sense bytes in hex: "); + + while (slen-- > 0) + cmn_err(CE_CONT, "%x ", *sptr++); + + cmn_err(CE_CONT, "\n\n"); + } + } + + if (request->sr_sense == NULL) { + + ql_tpmsg(ha->ctlr_vhdl, + request->sr_target, + "No place for sense data (CDB 0x%x)\n", + request->sr_command[0]); + } + else + { + request->sr_sensegotten = q_ptr->req_sense_length; + + bcopy(q_ptr->req_sense_data, + request->sr_sense, + request->sr_sensegotten); + + bcopy(request->sr_sense, + qli->qli_tinfo->si_sense, + request->sr_sensegotten); + QL_SPLOCK(qli->qli_lock, s); + if (qli->qli_sense_callback) + { temp_callback=qli->qli_sense_callback; + ASSERT(qli->qli_tinfo->si_sense); + bcopy(qli->qli_tinfo->si_sense, temp_sense, SCSI_SENSE_LEN); + QL_SPUNLOCK(qli->qli_lock, s); + QL_UNLOCK(ha->chip_info); + (*temp_callback)(request->sr_lun_vhdl, temp_sense); + QL_LOCK(ha->chip_info); + } + else + QL_SPUNLOCK(qli->qli_lock, s); + } + } /* if (q_ptr->state_flags & SS_GOT_SENSE) */ + + /* + * Link this request and return them later. + */ + if (cmp_forw) { + cmp_back->sr_ha = request; + cmp_back = request; + } + else + { + cmp_forw = request; + cmp_back = request; + } + request->sr_ha = NULL; + } /* while ((chip_info->response_out != response_in)) */ + + /* + * Update the ISP's response tail pointer + */ + QL_PCI_OUTH(&isp->mailbox5, chip_info->response_out); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + + /* Notify caller of command competions */ + ql_notify_responses(chip_info, cmp_forw); + cmp_forw = cmp_back = NULL; + + /* Get a new copy of the ISR. */ + isr = QL_PCI_INH(&isp->bus_isr); + + } while ((isr & BUS_ISR_RISC_INT) || (chip_info->chip_flags & AFLG_CHIP_ASYNC_RESPONSE_IN)); /* TAG 1 */ + + got_responses: + /* + * Some resources may have become available. See if there + * are any requests to send. + */ + { + int i; + int cmds=0; + + for (i=0; i< chip_info->channel_count; i++) { + ha = chip_info->ha_info[i]; + if (!(ha->host_flags & AFLG_HA_DRAIN_IO) && ((ha->waitf) || (ha->req_forw))) + ++cmds; + } + if (cmds) + ql_start_scsi(chip_info); + } +} + +static void +ql_notify_responses(pCHIP_INFO chip_info, + scsi_request_t *forwp) +{ + scsi_request_t *request; + + while ((request = forwp)) + { + forwp = request->sr_ha; + +#ifdef HEART_INVALIDATE_WAR + /* if this IO resulted in a DMA to memory from IO (disk read) */ + /* then invalide cache copies of the data */ + if (request->sr_flags & SRF_DIR_IN) + { + if (request->sr_flags & SRF_MAPBP) + { + bp_heart_invalidate_war(request->sr_bp); + } + else + { + heart_invalidate_war(request->sr_buffer,request->sr_buflen); + } + } +#endif /* HEART_INVALIDATE WAR */ + + /* + * Callback now - As a result of callback processing we + * may have executed a mailbox command, which may have + * seen some IOCB completions. AFLG_ASYNC_RESPONSE_IN will + * be set if so. + */ + QL_UNLOCK(chip_info); + (*request->sr_notify)(request); + QL_LOCK(chip_info); + + } /* while (request = forwp) */ +} + +/* Function: ql_start_scsi +** +** Description: This routine tries to start up any new requests we have +** pending on our internal queue. This may be new commands +** or it may be ones that we couldn't start berfore because +** the adapter queues were full. +*/ +static void +ql_start_scsi(pCHIP_INFO chip_info) +{ + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + int zero_cnt; + iopaddr_t pciaddr; + int s; + + /* + * Some other cpu is running this code so our job will get + * start by that cpu. + */ + if (!(chip_info->chip_flags & AFLG_CHIP_INITIALIZED)) { + return; + } + + /* + * Check the wait queue(s). If there's something in there, + * move it all over to the request queue. Check the request + * queues for any requests. If nothing, then bail out now. + */ + { + int i; + int cmds = 0; + pHA_INFO ha; + + for (i = 0; i < chip_info->channel_count; ++i) { + ha = chip_info->ha_info[i]; + if (ha->waitf) + { + if (ha->req_forw) + ha->req_back->sr_ha = ha->waitf; + else + ha->req_forw = ha->waitf; + ha->req_back = ha->waitb; + ha->waitf = ha->waitb = NULL; + ha->req_back->sr_ha = NULL; + } + if (ha->req_forw && ((ha->host_flags & AFLG_HA_QUEUE_PROGRESS_FLAGS) == 0)) + ++cmds; + } + if (cmds == 0) { + return; + } + } + + + + + /* + ** If we're going to do a scatter/gather operation we may need + ** to use more than one queue entry (one for the request and one + ** or more for the scatter/gather table). So, if we have less than + ** two queue slots available (might need one for a marker too) + ** then zap the number of queue entries so we'll go look again. + ** This is kindof a kludge, but ... we's does whats we needs to do. + */ + if ( chip_info->queue_space <= 2) { + chip_info->queue_space = 0; /* go look for "number queue slots" */ + } + + /* + ** Determine how many entries are available on the request queue. + ** + ** This is kinda neat -- instead of always checking if there are + ** any new slots RIGHT NOW, we keep track of how many slots there + ** were the last time we checked. Since we're the only one filling + ** these, there will always be AT LEAST that many still available. + ** Once we reach that number, theres no sense in issuing any more + ** until he's taken some. So, when we filled up the number of slots + ** available on our last check, THEN we check again (to see if there + ** is anymore slots available). + ** + ** If we filled all the slots on the last pass, then check to see + ** how many slots there are NOW! + */ + if (chip_info->queue_space == 0) { + ql_queue_space(chip_info, isp); + } + + /* + * We now loop thru all available channels, taking one command + * off each channel's requests queue in turn, and sending it + * if there's space in the request queue. We use a "rotor" to + * identify the next channel a command is to be sent to. When + * all channels have no remaining commands, we exit the loop + */ + zero_cnt = 0; + while (chip_info->queue_space && zero_cnt < chip_info->channel_count) + { + int i; + pHA_INFO ha; + scsi_request_t *request; + ql_local_info_t *qli; + command_entry *q_ptr; + pREQ_INFO r_ptr; + alenlist_t alenlist; + alenaddr_t address; + size_t length; + int tgt; + int entries = 0, index, ri_slot; + int allow_prefetch; + + i = chip_info->req_rotor++; + chip_info->req_rotor %= chip_info->channel_count; + + if (i >= chip_info->channel_count) + panic("i is greater than the channel count"); + ha = chip_info->ha_info[i]; + if (((request = ha->req_forw) == NULL) || + (ha->host_flags & AFLG_HA_QUEUE_PROGRESS_FLAGS) || + ((ri_slot = reqi_get_slot(ha, (int)request->sr_target)) < 0)) + { + ++zero_cnt; + continue; + } + zero_cnt = 0; + + + + /* + * If we need to send a global Marker do it now + */ + if (ha->host_flags & AFLG_HA_SEND_MARKER) { + + marker_entry * q_ptr; + + ha->host_flags &= ~AFLG_HA_SEND_MARKER; + q_ptr = (marker_entry * )chip_info->request_ptr; + if (chip_info->request_in == (chip_info->ql_request_queue_depth - 1)) { + chip_info->request_in = 0; + chip_info->request_ptr = chip_info->request_base; + } else { + chip_info->request_in++; + chip_info->request_ptr++; + } + + bzero(q_ptr, sizeof(marker_entry)); + + q_ptr->hdr.entry_type = ET_MARKER; + q_ptr->hdr.entry_cnt = 1; + q_ptr->hdr.sys_def_1 = chip_info->request_in; + + q_ptr->channel_id = ha->channel_id; + q_ptr->modifier = MM_SYNC_ALL; + +#ifdef DEBUG + if (ql_debug >= 2) + dump_marker(q_ptr); +#endif + + + /* flush the entry out of the cache */ + /* Tell isp it's got a new I/O request... */ + QL_PCI_OUTH(&isp->mailbox4, chip_info->request_in); + + /* One less I/O slot. */ + chip_info->queue_space--; + + } /* if (ha->host_flags & AFLG_SEND_MARKER) */ + + /* + ** See if we can start one or more requests. + ** This means there's room in the queue, we have another request + ** to start, and we have a request structure for the request. + */ + + r_ptr = &ha->reqi_block[request->sr_target][ri_slot]; + qli = SLI_INFO(scsi_lun_info_get(request->sr_lun_vhdl)); + + /* + * Send a DEVICE SYNCH marker if we need to + */ + QL_SPLOCK(qli->qli_lock, s); + if ((qli->qli_dev_flags & (DFLG_SEND_MARKER|DFLG_ABORT_IN_PROGRESS)) == DFLG_SEND_MARKER) { + marker_entry *q_ptr; + + qli->qli_dev_flags &= ~DFLG_SEND_MARKER; + QL_SPUNLOCK(qli->qli_lock, s); + + q_ptr = (marker_entry * )chip_info->request_ptr; + if (chip_info->request_in == (chip_info->ql_request_queue_depth - 1)) { + chip_info->request_in = 0; + chip_info->request_ptr = chip_info->request_base; + } else { + chip_info->request_in++; + chip_info->request_ptr++; + } + + bzero(q_ptr, sizeof(marker_entry)); + + q_ptr->hdr.entry_type = ET_MARKER; + q_ptr->hdr.entry_cnt = 1; + q_ptr->hdr.sys_def_1 = chip_info->request_in; + + q_ptr->channel_id = ha->channel_id; + q_ptr->target_id = request->sr_target; + q_ptr->target_lun = request->sr_lun; + q_ptr->modifier = MM_SYNC_DEVICE; + + + + + /* Tell isp it's got a new I/O request... */ + QL_PCI_OUTH(&isp->mailbox4, chip_info->request_in); + + /* One less I/O slot. */ + chip_info->queue_space--; + + } + else + QL_SPUNLOCK(qli->qli_lock, s); + + allow_prefetch = 1; + + if (request->sr_buflen) + { + /* + * If buf describes a user virtual address, + * dksc will have constructed a alenlist, + * stuck it in bp->b_private and set the + * SRF_ALENLIST flag. + */ + if (request->sr_flags & SRF_ALENLIST) + { + alenlist = request->sr_alenlist; + alenlist_cursor_init(alenlist, 0, NULL); + } + else + { + alenlist = chip_info->alen_p; + + kvaddr_to_alenlist(alenlist, + (caddr_t)request->sr_buffer, + request->sr_buflen, AL_NOCOMPACT); + } + entries = alenlist_size(alenlist); + + /* + * Ensure request doesn't span more than 254 + * continuation entries, i.e. length doesn't + * exceed 20.8 MB. If it exceeds the + * max. length, unlink the request and toss it + * now. + */ + if (((entries - IOCB_SEGS) / CONTINUATION_SEGS + 1) > MAX_CONTINUATION_ENTRIES) + { + ql_cpmsg(ha->ctlr_vhdl, "Transfer length (0x%x) too large; " + "spans more than %d continuation entries.\n", + request->sr_buflen, MAX_CONTINUATION_ENTRIES); + ha->req_forw = request->sr_ha; + if (ha->req_forw == NULL) + ha->req_back = NULL; + request->sr_status = SC_REQUEST; + QL_UNLOCK(chip_info); + (*request->sr_notify)(request); + QL_LOCK(chip_info); + continue; + } + + + if ((((entries - IOCB_SEGS) / CONTINUATION_SEGS) + 1) >= chip_info->queue_space) + { + /* better check the real space available before */ + /* giving up */ + ql_queue_space(chip_info, isp); + if ((((entries - IOCB_SEGS) / CONTINUATION_SEGS) + 1) >= chip_info->queue_space) + { + chip_info->queue_space = 0; + break; + } + } + + } + + ASSERT(ha == (pHA_INFO)request->sr_spare); + + /* Unhook the request and the request info structure. */ + ha->req_forw = request->sr_ha; + if (ha->req_forw == NULL) + ha->req_back = NULL; + + /* Initialize the request info structure for this request. */ + r_ptr->req = request; + + r_ptr->timeout = (request->sr_timeout / HZ) + WATCHDOG_TIME; + tgt = request->sr_target; + + ha->ql_ncmd++; + ha->tcmd[tgt]++; + + /* + * Bump the LUN command issued count + */ + qli->qli_cmd_rcnt++; + + /* Get a pointer to the queue entry for the command. */ + q_ptr = (command_entry * )chip_info->request_ptr; + + + /* Move the internal pointers for the request queue. */ + if (chip_info->request_in == (chip_info->ql_request_queue_depth - 1)) { + chip_info->request_in = 0; + chip_info->request_ptr = chip_info->request_base; + + } else { + chip_info->request_in++; + chip_info->request_ptr++; + } + + bzero(q_ptr, sizeof(queue_entry)); + /* Fill in the command header. */ + q_ptr->hdr.entry_type = ET_COMMAND; + q_ptr->hdr.entry_cnt = 1; + q_ptr->hdr.sys_def_1 = chip_info->request_in; + + /* Fill in the rest of the command data. */ + q_ptr->handle = ri_slot | (tgt << 8) | (ha->channel_id << 12); + q_ptr->channel_id = ha->channel_id; + q_ptr->target_id = request->sr_target; + ASSERT(request->sr_target != ha->ql_defaults.Initiator_SCSI_Id); + q_ptr->target_lun = request->sr_lun; + if (!request->sr_timeout) + q_ptr->time_out = DEFAULT_TIMEOUT; /* timeouts not handled in driver */ + + if (request->sr_command[0] == INQUIRY_CMD) + { + if (ha->ql_defaults.Id[request->sr_target].Capability.bits.Sync_Data_Transfers == 1) + q_ptr->control_flags |= CF_FORCE_SYNCHONOUS; + else + if (!ha->ql_defaults.Id[request->sr_target].Is_CDROM || ql_allow_negotiation_on_cdroms) + q_ptr->control_flags |= CF_FORCE_ASYNCHONOUS; + + if (ha->ql_defaults.Id[request->sr_target].Capability.bits.Wide_Data_Transfers == 1) + q_ptr->control_flags |= CF_INITIATE_WIDE; + } + + /* Copy over the requests SCSI cdb. */ + q_ptr->cdb_length = request->sr_cmdlen; + + /* + * If vendor unique command is of say 7 bytes, + * we will copy 3 extra garbage bytes below. The + * assumption is that it is an unusual occurrence. + */ + + if (request->sr_cmdlen > 10) { + q_ptr->cdb11 = request->sr_command[11]; + q_ptr->cdb10 = request->sr_command[10]; + } + + if (request->sr_cmdlen > 6) { + q_ptr->cdb9 = request->sr_command[9]; + q_ptr->cdb8 = request->sr_command[8]; + q_ptr->cdb7 = request->sr_command[7]; + q_ptr->cdb6 = request->sr_command[6]; + } + + q_ptr->cdb5 = request->sr_command[5]; + q_ptr->cdb4 = request->sr_command[4]; + q_ptr->cdb3 = request->sr_command[3]; + q_ptr->cdb2 = request->sr_command[2]; + q_ptr->cdb1 = request->sr_command[1]; + q_ptr->cdb0 = request->sr_command[0]; + + if (request->sr_buflen) { + if (!(request->sr_flags & SRF_DIR_IN)) { + q_ptr->control_flags |= CF_WRITE; + + } else { + q_ptr->control_flags |= CF_READ; + } + } + + if (request->sr_flags & SRF_NEG_SYNC) + { + ha->ql_defaults.Id[request->sr_target].Sync_Allowed = 1; + ha->ql_defaults.Id[request->sr_target].Force_Sync = 1; + if (ha->ql_defaults.Id[request->sr_target].Capability.bits.Sync_Data_Transfers == 0) + { + ha->ql_defaults.Id[request->sr_target].Capability.bits.Sync_Data_Transfers = 1; + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags &= ~DFLG_INITIALIZED; + QL_SPUNLOCK(qli->qli_lock, s); + } + q_ptr->control_flags |= CF_FORCE_SYNCHONOUS; + } + else + if (request->sr_flags & SRF_NEG_ASYNC) { + ha->ql_defaults.Id[request->sr_target].Sync_Allowed = 0; + ha->ql_defaults.Id[request->sr_target].Force_Sync = 0; + if (ha->ql_defaults.Id[request->sr_target].Capability.bits.Sync_Data_Transfers == 1) + { + ha->ql_defaults.Id[request->sr_target].Capability.bits.Sync_Data_Transfers = 0; + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags &= ~DFLG_INITIALIZED; + QL_SPUNLOCK(qli->qli_lock, s); + } + q_ptr->control_flags |= CF_FORCE_ASYNCHONOUS; + } + + /* If we said we support tagged commands */ + /* and the drive is configured for tagged support, */ + /* then they pass us the tag information in the */ + /* hostadapter command parameter. */ + /* Pass it along to the host adapter. */ + if (ha->ql_defaults.Id[request->sr_target].Capability.bits.Tagged_Queuing) { + switch (request->sr_tag) { + case SC_TAG_HEAD: + q_ptr->control_flags |= CF_HEAD_TAG; + break; + case SC_TAG_ORDERED: + q_ptr->control_flags |= CF_ORDERED_TAG; + break; + case SC_TAG_SIMPLE: + q_ptr->control_flags |= CF_SIMPLE_TAG; + break; + } + } + + /* If this is a scatter/gather request, then we need */ + /* to adjust the data address and lengths for the */ + /* scatter entries. */ + + /* If there are more than IOCB_SEGS entries in the scatter*/ + /* gather list, then we're going to be using some */ + /* contiuation queue entries. So, tell the command entry */ + /* how many continuations to expect. Add two to include */ + /* the command.*/ + if (entries > IOCB_SEGS) { + int i = 1; + if ((entries - IOCB_SEGS) % CONTINUATION_SEGS) + i = 2; + q_ptr->hdr.entry_cnt = ((entries - IOCB_SEGS) / CONTINUATION_SEGS) + i; + } + + /* Also, update the segment count with the number of */ + /* entries in the scatter/gather list. */ + + q_ptr->segment_cnt = entries; + + /* The command queue entry has room for four */ + /* scatter/gather entries. Fill them in. */ + for (i = 0; i < IOCB_SEGS && entries; i++, entries--) { + if (alenlist_get(alenlist, NULL, (size_t)(1<<30), + &address, &length, 0) != ALENLIST_SUCCESS) + { + panic("ql - bad alen conversion, alen 0x%lx, sreq 0x%lx, br 0x%lx\n", + (unsigned long) alenlist, + (unsigned long) request, + (unsigned long) alenlist); + } + pciaddr = fill_sg_elem(ha, address, length, allow_prefetch); + q_ptr->dseg[i].base_high_32 = (uint32_t) (pciaddr >> 32); + q_ptr->dseg[i].base_low_32 = (uint32_t) pciaddr; + q_ptr->dseg[i].count = length; + } + /* If there is still more entries in the scatter/gather */ + /* list, then we need to use some continuation queue */ + /* entries. While there are more entries in the */ + /* scatter/gather table, allocate a continuation queue */ + /* entry and fill it in. */ + + index = IOCB_SEGS; /* set the index for the */ + + /* next sg element pair */ + while (entries) { + continuation_entry * c_ptr; + + /* Get a pointer to the next queue entry for the */ + /* continuation of the command. */ + c_ptr = (continuation_entry * )chip_info->request_ptr; + + /* Move the internal pointers for the request queue. */ + if (chip_info->request_in == (chip_info->ql_request_queue_depth - 1)) { + chip_info->request_in = 0; + chip_info->request_ptr = chip_info->request_base; + + } else { + chip_info->request_in++; + chip_info->request_ptr++; + } + + /* Fill in the continuation header. */ + bzero(c_ptr, sizeof(continuation_entry)); + c_ptr->hdr.entry_type = ET_CONTINUATION; + c_ptr->hdr.entry_cnt = 1; + c_ptr->hdr.sys_def_1 = chip_info->request_in; + + /* Fill in the scatter entries for this continuation. */ + for (i = 0; i < CONTINUATION_SEGS && entries; i++, entries--) { + if (alenlist_get(alenlist, NULL, (size_t)(1<<30), + &address, &length, 0) != ALENLIST_SUCCESS) { + printf("ql - bad alen conversion\n"); + } + pciaddr = fill_sg_elem(ha, address, length, allow_prefetch); + c_ptr->dseg[i].base_high_32 = (uint32_t) (pciaddr >> 32); + c_ptr->dseg[i].base_low_32 = (uint32_t) pciaddr; + c_ptr->dseg[i].count = length; + index++; + } +#ifdef DEBUG + if (ql_debug >= 2) { + dump_continuation((continuation_entry * )c_ptr); + } +#endif + + /* One less I/O slot. */ + chip_info->queue_space--; + + /*flush the entry out of the cache */ + + + } /* while entries */ +#ifdef DEBUG + if (ql_debug >= 2) { + dump_iocb((command_entry * )q_ptr); + } +#endif + +#ifdef DEBUG + if (ql_debug >= 2) + dump_iocb(q_ptr); +#endif + + + /*flush the entry out of the cache */ + + /* Tell isp it's got a new I/O request... */ + /* Wake up */ + QL_PCI_OUTH(&isp->mailbox4, chip_info->request_in); + + /* One less I/O slot. */ + chip_info->queue_space--; + + + /* + * Check the waitQ to see if something's been queued + * since the last time we checked the waitQ. + */ + if (ha->req_forw == NULL) { + if (ha->waitf) { + ha->req_forw = ha->waitf; + ha->req_back = ha->waitb; + } + ha->waitf = ha->waitb = NULL; + } + } + +#if CONFIG_IA64_SGI_SN + /* + * The ql_queue_space call forces a PIO Read from the chip. This PIO + * forces the competion of the PIO Write to the request_in pointer. This + * gets around a race condition: + * + * CPU A updates request in via PIO write + * CPU A releases req_lock + * CPU B acquires req_lock + * CPU B updates request in via PIO write + * CPU B's PIO write is reflected in PCI transaction + * CPU A's PIO write is reflected in PCI transaction + * + * An alternate plan was to PIO read from the Bridge target flush register. + * We are guaranteed that all PIOs that hit the Bridge after the PIO read + * will retire after all PIOs that hit the Bridge before. + * + ((bridge_t *) ((uintptr_t) chip_info->ha_base & ~0xFFFFFF))->b_wid_tflush; + * + * However, this seems to be slightly slower than ql_queue_space for an + * unknown reason. It's also violates Good Coding Standards. I'm + * leaving it in for future consideration. + */ + ql_queue_space(chip_info, isp); +#endif +} + +/* Function: ql_queue_space */ +static void +ql_queue_space(pCHIP_INFO chip_info, pISP_REGS isp) +{ + u_short mailbox4 = 0; + + mailbox4 = QL_PCI_INH(&isp->mailbox4); + + chip_info->request_out = mailbox4; + + /* + ** If the pointers are the same, then ALL the slots are available. + ** We have to account for wrap condition, so check both conditions. + */ + if (chip_info->request_in == chip_info->request_out) { + chip_info->queue_space = chip_info->ql_request_queue_depth - 1; + } else if (chip_info->request_in > chip_info->request_out) { + chip_info->queue_space = ((chip_info->ql_request_queue_depth - 1) - + (chip_info->request_in - chip_info->request_out)); + } else { + chip_info->queue_space = (chip_info->request_out - chip_info->request_in) - 1; + } +} + +/* Function: ql_mbox_cmd() +** +** Return: 0 no error +** non-0 error +** +** Description: This routine issues a mailbox command. +** We're passed a list of mailboxes and the number of +** mailboxes to read and the number to write. +** +** Note: I've added a special case (that may not be any problem) +** to skip loading mailbox 4 if the command is INITIALIZE RESPONSE QUEUE. +*/ + +static int +ql_mbox_cmd(pCHIP_INFO chip, + u_short *mbox_sts, + u_char out_cnt, u_char in_cnt, + u_short reg0, u_short reg1, u_short reg2, u_short reg3, + u_short reg4, u_short reg5, u_short reg6, u_short reg7) +{ + pISP_REGS isp = (pISP_REGS)chip->ha_base; + int complete = 0; + int retry_cnt = 0; + int intr_retry_cnt = 0; + u_short isr; + u_short bus_icr; + u_short bus_sema; + u_short hccr; + + + /* we need to be sure that only 1 command can run at a time */ + /* so fetch the mailbox mutex first, then get the ctlrlock back */ + QL_UNLOCK(chip); + QL_MUTEX_LOCK(chip->mboxmutex); + QL_LOCK(chip); + + /* + ** Just for grins, clear out ALL the return status. + ** This might catch a bug later where I try to use a return + ** parameter that I wasn't given (would be left over from previous). + */ + mbox_sts[0] = 0; + mbox_sts[1] = 0; + mbox_sts[2] = 0; + mbox_sts[3] = 0; + mbox_sts[4] = 0; + mbox_sts[5] = 0; + mbox_sts[6] = 0; + mbox_sts[7] = 0; + + switch (out_cnt) { + case 8: + QL_PCI_OUTH(&isp->mailbox7, reg7); + case 7: + QL_PCI_OUTH(&isp->mailbox6, reg6); + case 6: + if ((reg0 != MBOX_CMD_SET_TARGET_PARAMETERS) && + (reg0 != MBOX_CMD_LOAD_RAM_64) ) + QL_PCI_OUTH(&isp->mailbox5, reg5); + case 5: + if ( (reg0 != MBOX_CMD_SET_RETRY_COUNT) && + (reg0 != MBOX_CMD_INIT_RESPONSE_QUEUE_64) && + (reg0 != MBOX_CMD_SET_TARGET_PARAMETERS) ) + QL_PCI_OUTH(&isp->mailbox4, reg4); + case 4: + QL_PCI_OUTH(&isp->mailbox3, reg3); + case 3: + QL_PCI_OUTH(&isp->mailbox2, reg2); + case 2: + QL_PCI_OUTH(&isp->mailbox1, reg1); + case 1: + QL_PCI_OUTH(&isp->mailbox0, reg0); + } + + /* + * If called from ISR, then we'll need to poll for mbox + * completion. Else wait on semaphore. + */ + if (chip->chip_flags & (AFLG_CHIP_IN_INTR | AFLG_CHIP_DUMPING | AFLG_CHIP_WATCHDOG_TIMER | AFLG_CHIP_INITIAL_SRAM_PARITY)) { + chip->chip_flags |= AFLG_CHIP_MAIL_BOX_POLLING; + chip->chip_flags &= ~AFLG_CHIP_MAIL_BOX_WAITING; + } + else { + chip->mbox_timeout_info = 10 + WATCHDOG_TIME; /* mailbox timeout is at least 10 seconds */ + chip->chip_flags |= AFLG_CHIP_MAIL_BOX_WAITING; + chip->chip_flags &= ~AFLG_CHIP_MAIL_BOX_POLLING; + } + chip->chip_flags &= ~AFLG_CHIP_MAIL_BOX_DONE; + + /* Wake up the isp. */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_SET_HOST_INT); + + + + /* + * Wait for mailbox done semaphore ...... + */ + if (chip->chip_flags & AFLG_CHIP_MAIL_BOX_WAITING) { + QL_UNLOCK(chip); + psema(&chip->mbox_done_sema, QL_SEMA_PRI); /* hold the mailbox lock to guarantee single thread */ + QL_LOCK(chip); + chip->chip_flags &= ~AFLG_CHIP_MAIL_BOX_WAITING; + if (!(chip->chip_flags & AFLG_CHIP_MAIL_BOX_DONE)) { + reg0 = QL_PCI_INH(&isp->mailbox0); + isr = QL_PCI_INH(&isp->bus_isr); + bus_sema = QL_PCI_INH(&isp->bus_sema); + hccr = QL_PCI_INH(&isp->hccr); + complete = 1; + ql_ppmsg(chip, + "Mailbox timeout: command 0x%x, isr 0x%x, bus_sema 0x%x, hccr 0x%x\n", + reg0, isr, bus_sema, hccr); + } + goto done; + } + + /* + * .... or poll for completion + */ + again: + retry_cnt = 100000; + intr_retry_cnt = 100; + while( !(chip->chip_flags & AFLG_CHIP_MAIL_BOX_DONE) ) { + DELAY(10); + if ((isr = QL_PCI_INH(&isp->bus_isr)) & BUS_ISR_RISC_INT) { + if (chip->chip_flags & AFLG_CHIP_MAIL_BOX_DONE) { + continue; + } + if ((bus_sema = QL_PCI_INH(&isp->bus_sema)) & BUS_SEMA_LOCK) { + if ((chip->chip_flags & (AFLG_CHIP_IN_INTR | AFLG_CHIP_DUMPING | AFLG_CHIP_WATCHDOG_TIMER | AFLG_CHIP_INITIAL_SRAM_PARITY)) || (--intr_retry_cnt <= 0)) { + ql_service_mbox_interrupt(chip); + if (chip->chip_flags & (AFLG_CHIP_DUMPING | AFLG_CHIP_WATCHDOG_TIMER | AFLG_CHIP_INITIAL_SRAM_PARITY)) + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + } + } + else { + u_short response_in_new; + + response_in_new = QL_PCI_INH(&isp->mailbox5); + + if (chip->response_in != response_in_new) { + chip->response_in = response_in_new; + chip->chip_flags |= AFLG_CHIP_ASYNC_RESPONSE_IN; + } + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + } + } + + /* check for the sram parity condition which the host is in interrupt mode + * and pause mode. + */ + hccr = QL_PCI_INH(&isp->hccr); + if ( (hccr & HCCR_HOST_INT) && (hccr & HCCR_PAUSE) ) { + + QL_PPMSGS(chip, "mailbox with host interrupt hccr 0x%x\n", hccr); + goto done; + } + + + /* check for timeout */ + if ( --retry_cnt <= 0) { + reg0 = QL_PCI_INH(&isp->mailbox0); + isr = QL_PCI_INH(&isp->bus_isr); + bus_sema = QL_PCI_INH(&isp->bus_sema); + bus_icr = QL_PCI_INH(&isp->bus_icr); + if ((hccr & HCCR_HOST_INT) && (isr & BUS_ISR_RISC_INT)) { + ql_ppmsg(chip, "Mailbox timeout " + "(command 0x%x, isr 0x%x, bus_sema 0x%x, hccr 0x%x) " + "resetting ISR and retrying\n", + reg0, isr, bus_sema, hccr); + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_CLEAR_RISC_INT); + goto again; + } + complete = 1; + ql_ppmsg(chip, + "Mailbox timeout: intr_retry_cnt %d, command 0x%x, isr 0x%x, bus_sema 0x%x, hccr 0x%x icr 0x%x\n", + intr_retry_cnt, reg0, isr, bus_sema, hccr, bus_icr); + + goto done; + } + } + done: + switch (in_cnt) { + + case 8: + mbox_sts[7] = chip->mailbox[7]; + + case 7: + mbox_sts[6] = chip->mailbox[6]; + case 6: + if (reg0 != MBOX_CMD_LOAD_RAM_64) + mbox_sts[5] = chip->mailbox[5]; + case 5: + if ( (reg0 != MBOX_CMD_SET_RETRY_COUNT) && + (reg0 != MBOX_CMD_INIT_RESPONSE_QUEUE_64) ) + mbox_sts[4] = chip->mailbox[4]; + case 4: + mbox_sts[3] = chip->mailbox[3]; + case 3: + mbox_sts[2] = chip->mailbox[2]; + case 2: + mbox_sts[1] = chip->mailbox[1]; + case 1: + mbox_sts[0] = chip->mailbox[0]; + } + + QL_MUTEX_UNLOCK(chip->mboxmutex); + return(complete); +} + +void +qlcommand(struct scsi_request *req) +{ + ql_entry(req); +} + +static void +qldone(scsi_request_t *request) +{ + vsema(request->sr_dev); +} + +struct scsi_target_info * +qlinfo(vertex_hdl_t ql_lun_vhdl) +{ + struct scsi_request *req; + static u_char scsi[6]; + sema_t *sema; + struct scsi_target_info *retval; + scsi_target_info_t *info; + scsi_lun_info_t *lun_info; + ql_local_info_t *qli; + pHA_INFO ha; + u_char *sensep; + int retry = 2; + int busy_retry = 8; + int s; + + ha = ql_ha_info_from_lun_get(ql_lun_vhdl); + ASSERT(ha != 0); + lun_info = scsi_lun_info_get(ql_lun_vhdl); + qli = SLI_INFO(lun_info); + + info = TINFO(lun_info); + + QL_MUTEX_LOCK(OPEN_MUTEX(lun_info)); + + if (info->si_inq == NULL) + info->si_inq = (u_char * ) QL_KMEM_ZALLOC(SCSI_INQUIRY_LEN, + VM_CACHEALIGN | VM_NOSLEEP | VM_DIRECT); + if (info->si_sense == NULL) + info->si_sense = (u_char * )QL_KMEM_ZALLOC(SCSI_SENSE_LEN, + VM_CACHEALIGN | VM_NOSLEEP | VM_DIRECT); + + sensep = QL_KMEM_ZALLOC(REQ_SENSE_DATA_LENGTH, VM_NOSLEEP); + sema = QL_KMEM_ZALLOC(sizeof(sema_t), VM_NOSLEEP); + req = QL_KMEM_ZALLOC(sizeof(*req), VM_NOSLEEP); + + if ((sensep==NULL) || (sema==NULL) || (req==NULL) || + (info->si_inq==NULL) || (info->si_sense==NULL)) + { retval=NULL; + goto info_done; + } + + init_sema(sema, 0, "ql", ql_lun_vhdl); + + do { + bzero(req, sizeof(*req)); + bzero(info->si_inq, SCSI_INQUIRY_LEN); + + scsi[0] = INQUIRY_CMD; + if (qli->rev>2) + scsi[1] = 0; + else + scsi[1] = (SLI_LUN(lun_info)) << 5; + scsi[2] = scsi[3] = scsi[5] = 0; + scsi[4] = SCSI_INQUIRY_LEN; + req->sr_lun_vhdl = ql_lun_vhdl; + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + + req->sr_command = scsi; + req->sr_cmdlen = 6; /* Inquiry command length */ + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = 10 * HZ; + req->sr_buffer = info->si_inq; + req->sr_buflen = SCSI_INQUIRY_LEN; + req->sr_sense = sensep; + req->sr_notify = qldone; + req->sr_dev = sema; + + qlcommand(req); + + psema(sema, QL_SEMA_PRI); /* keep holding the locks */ + if (req->sr_scsi_status == ST_BUSY) + delay(HZ/2); + } while (((req->sr_status == SC_ATTN || req->sr_status == SC_CMDTIME) && retry--) || + (req->sr_scsi_status == ST_BUSY && busy_retry--)); + + if (req->sr_status == SC_GOOD && req->sr_scsi_status == ST_GOOD && + (info->si_inq[0] !=0 || info->si_inq[4] !=0)) { + + retval = info; + + + /* + * If the LUN is not supported, then return + * NULL. However, if this LUN is a candidate for + * failover we still may want to treat it as a valid + * device. + */ + if ((info->si_inq[0] & 0xC0) == 0x40 && + !fo_is_failover_candidate(info->si_inq, ql_lun_vhdl)) + { + retval = NULL; + } + else + { + scsi_device_update(info->si_inq,ql_lun_vhdl); + + /* no one looks at most of the SRH_ flags anymore. So we'll only + set the ones folks seem to care about */ + info->si_ha_status = SRH_MAPUSER | SRH_ALENLIST | SRH_QERR0 | SRH_QERR1; + if (info->si_inq[SCSI_INFO_BYTE] & SCSI_CTQ_BIT) + { + info->si_ha_status |= SRH_TAGQ; + info->si_maxq = MAX_QUEUE_DEPTH-1; + } + else + info->si_maxq = 1; + + /* + * Does the device support WIDE? + */ + if (info->si_inq[SCSI_INFO_BYTE] & 0x20) + { + if (ha->ql_defaults.Id[req->sr_target].Wide_Allowed && + ha->ql_defaults.Id[req->sr_target].Capability.bits.Wide_Data_Transfers == 0) + { + ha->ql_defaults.Id[req->sr_target].Capability.bits.Wide_Data_Transfers = 1; + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags &= ~DFLG_INITIALIZED; + QL_SPUNLOCK(qli->qli_lock, s); + } + } + else + { + if (ha->ql_defaults.Id[req->sr_target].Capability.bits.Wide_Data_Transfers == 1) + { + ha->ql_defaults.Id[req->sr_target].Capability.bits.Wide_Data_Transfers = 0; + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags &= ~DFLG_INITIALIZED; + QL_SPUNLOCK(qli->qli_lock, s); + } + } + + /* + * Does the device support SYNC? The logic to + * decide whether to allow sync negotiations + * is a little complicated. We allow sync + * negotiations when: + * sync bit in inquiry string is on + * AND device is NOT a CDROM + * OR Force_Sync bit is set. + * + * A little clarification is required. (a) We + * have seen problems with 12x CDROMs (wrong + * data being returned on block reads) if we + * do too many sync negotiations. (b) Some + * SCSI-1 devices don't set the sync bit in + * the inquiry string even though they are + * capable of doing sync. The + * ql_force_sync_negotiation DEVICE ADMIN + * varible will force sync negotiation in such + * cases. + */ + ha->ql_defaults.Id[req->sr_target].Is_CDROM = cdrom_inquiry_test(&info->si_inq[8]); + if (((info->si_inq[SCSI_INFO_BYTE] & 0x10) && + (!ha->ql_defaults.Id[req->sr_target].Is_CDROM || ql_allow_negotiation_on_cdroms)) || + ha->ql_defaults.Id[req->sr_target].Force_Sync) + { + if (ha->ql_defaults.Id[req->sr_target].Sync_Allowed && + ha->ql_defaults.Id[req->sr_target].Capability.bits.Sync_Data_Transfers == 0) + { + ha->ql_defaults.Id[req->sr_target].Capability.bits.Sync_Data_Transfers = 1; + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags &= ~DFLG_INITIALIZED; + QL_SPUNLOCK(qli->qli_lock, s); + } + } + else + { + if (ha->ql_defaults.Id[req->sr_target].Capability.bits.Sync_Data_Transfers == 1) + { + ha->ql_defaults.Id[req->sr_target].Capability.bits.Sync_Data_Transfers = 0; + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags &= ~DFLG_INITIALIZED; + QL_SPUNLOCK(qli->qli_lock, s); + } + } + + /* does device support DT mode? */ + /* check the clocking bit per spc3 spec */ + if (info->si_inq[56] & 0x4) + ha->ql_defaults.Id[req->sr_target].dt=1; + } + } + else + { + retval = NULL; + } + +info_done: + if (sema) + { freesema(sema); + kmem_free(sema, sizeof(sema_t)); + } + + if (req) + kmem_free(req, sizeof(*req)); + + if (sensep) + kmem_free(sensep, REQ_SENSE_DATA_LENGTH); + + QL_MUTEX_UNLOCK(OPEN_MUTEX(lun_info)); + + return retval; +} + + +void qlfree(vertex_hdl_t ql_lun_vhdl, + void (*cb)(vertex_hdl_t, uint8_t *)) + +{ + int s; + scsi_lun_info_t *lun_info = scsi_lun_info_get(ql_lun_vhdl); + ql_local_info_t *qli = SLI_INFO(lun_info); + pHA_INFO ha = ql_ha_info_from_lun_get(ql_lun_vhdl); + + if (ha == NULL) + return; + + QL_MUTEX_LOCK(OPEN_MUTEX(lun_info)); + + QL_SPLOCK(qli->qli_lock, s); + if (qli->qli_dev_flags & DFLG_EXCLUSIVE) + qli->qli_dev_flags &= ~DFLG_EXCLUSIVE; + if (qli->qli_dev_flags & DFLG_CONTINGENT_ALLEGIANCE) + qli->qli_dev_flags &= ~DFLG_CONTINGENT_ALLEGIANCE; + if (qli->qli_ref_count != 0) + qli->qli_ref_count--; + + if (cb) { + if (qli->qli_sense_callback == cb) + { qli->qli_sense_callback = NULL; + QL_SPUNLOCK(qli->qli_lock, s); + } + else + { QL_SPUNLOCK(qli->qli_lock, s); + ql_lpmsg(ha->ctlr_vhdl, SLI_TARG(lun_info), SLI_LUN(lun_info), + "qlfree: callback 0x%x not active\n", cb); + } + } + else + QL_SPUNLOCK(qli->qli_lock, s); + + QL_MUTEX_UNLOCK(OPEN_MUTEX(lun_info)); +} + +int +qlalloc(vertex_hdl_t ql_lun_vhdl, + int opt, + void (*cb)(vertex_hdl_t, uint8_t *)) +{ + int retval = SCSIALLOCOK; + int s; + scsi_lun_info_t *lun_info = scsi_lun_info_get(ql_lun_vhdl); + ql_local_info_t *qli = SLI_INFO(lun_info); + + if (qlinfo(ql_lun_vhdl) == NULL) { + retval = 0; + goto _allocout2; + } + + QL_MUTEX_LOCK(OPEN_MUTEX(lun_info)); + QL_SPLOCK(qli->qli_lock, s); + + if (qli->qli_dev_flags & DFLG_EXCLUSIVE) { + retval = EBUSY; + goto _allocout1; + } + + if (opt & SCSIALLOC_EXCLUSIVE) { + if (qli->qli_ref_count != 0) { + retval = EBUSY; + goto _allocout1; + } else + qli->qli_dev_flags |= DFLG_EXCLUSIVE; + } + qli->qli_ref_count++; + if (cb) { + if (qli->qli_sense_callback && qli->qli_sense_callback != cb) { + retval = EINVAL; + goto _allocout1; + } else + qli->qli_sense_callback = cb; + } + +_allocout1: + QL_SPUNLOCK(qli->qli_lock, s); + QL_MUTEX_UNLOCK(OPEN_MUTEX(lun_info)); + +_allocout2: + return retval; + +} + +static int +ql_reset(vertex_hdl_t ql_ctlr_vhdl) +{ + pHA_INFO ha = ql_ha_info_from_ctlr_get(ql_ctlr_vhdl); + u_short mbox_sts[8]; + int rc; + + if (ha == NULL) + return(1); /*fail*/ + + rc = ql_set_bus_reset(ha->chip_info, mbox_sts, ha->channel_id); + + return(rc ? 1 : 0); +} + + +/* + * qldump - called prior to doing a panic dump + * + * We do have to reset the locks however, in case the panic + * occured while a qlogic device was active in this driver. + * + * The actual dumping will be done by calls to qlcommand() later. + * called at spl7() + */ +int +qldump(vertex_hdl_t ql_ctlr_vhdl) +{ +#define DUMP_SUCCESS 1 +#define DUMP_FAIL 0 + + int rv; + pHA_INFO ha; + ql_local_info_t *qli; + u_int id, lun, req_cnt; + pREQ_INFO r_ptr; + vertex_hdl_t ql_lun_vhdl; + + /* + * Interrupts are disabled, so set DUMPING flag for all + * adapters. This becomes important when qlhalt is called with + * interrupts disabled. + */ + for (ha = ql_ha_list; ha; ha = ha->next_ha) + ha->chip_info->chip_flags |= AFLG_CHIP_DUMPING; + + ha = ql_ha_info_from_ctlr_get(ql_ctlr_vhdl); + if (ha == NULL) { + ql_cpmsg(ql_ctlr_vhdl, "Dump failed; no host adapter structure\n"); + return(DUMP_FAIL); + } + + QL_INIT_LOCK(&ha->chip_info->ctlrlock, "ql_ctlr", ql_ctlr_vhdl); + QL_INIT_MUTEX(ha->chip_info->probemutex, "ql_probemutex", ql_ctlr_vhdl); + QL_INIT_MUTEX(ha->chip_info->mboxmutex, "ql_mboxmutex", ql_ctlr_vhdl); + + QL_LOCK(ha->chip_info); /* needed for proper lock state in called routines */ + ql_reset_interface(ha->chip_info,1); + + /* Init the raw request queue to empty. */ + ha->req_forw = NULL; + ha->req_back = NULL; + + for (id = 0; id < QL_MAXTARG; id++) + { + /* + * Cleanup the target structures + */ + ha->reqi_cntr[id] = 1; + ha->tcmd[id]=0; + r_ptr = ha->reqi_block[id]; + if (r_ptr) + { + for (req_cnt=0; req_cnt <= (MAX_REQ_INFO); req_cnt++, r_ptr++) + r_ptr->req = NULL; + } + + /* + * Cleanup the LUN structures + */ + for (lun = 0; lun < QL_MAXLUN; ++lun) { + if ((ql_lun_vhdl = scsi_lun_vhdl_get(ha->ctlr_vhdl, id, lun)) == GRAPH_VERTEX_NONE) + continue; + qli = SLI_INFO(scsi_lun_info_get(ql_lun_vhdl)); + QL_SPINIT_LOCK(qli->qli_lock, "qli_lock", ql_lun_vhdl); + qli->qli_dev_flags = DFLG_BEHAVE_QERR1; /* ignore the lock around this */ + qli->qli_awaitf = qli->qli_awaitb = NULL; + qli->qli_iwaitf = qli->qli_iwaitb = NULL; + qli->qli_cmd_rcnt = 0; + } /* for (lun) */ + } /* for (id) */ + ha->ql_ncmd=0; + rv = ql_reset(ql_ctlr_vhdl); + if (rv) { + if ((rv = ql_reset_interface(ha->chip_info,1))) + ha->chip_info->chip_flags |= AFLG_CHIP_SHUTDOWN; + } + QL_UNLOCK(ha->chip_info); + if (rv == 0) { + for (id = 0; id < QL_MAXTARG; id++) { + if (id == ha->ql_defaults.Initiator_SCSI_Id) + continue; + if ((ql_lun_vhdl = scsi_lun_vhdl_get(ql_ctlr_vhdl,id,0)) + != GRAPH_VERTEX_NONE) { + qlinfo(ql_lun_vhdl); + } + } + } + return((rv == 0) ? DUMP_SUCCESS : DUMP_FAIL); +} + +/* + * create a vertex for the ql controller in the + * hardware graph and allocate space for the info + * the vertex passed in is our pci connection point + */ +/*ARGSUSED3*/ +static vertex_hdl_t +ql_ctlr_add(scsi_pci_vhdl_t vhdl, int channel_id, int channel_count) +{ + vertex_hdl_t ctlr_vhdl; + scsi_ctlr_info_t *ctlr_info; + + ctlr_vhdl = scsi_ctlr_vertex_add(vhdl, channel_id + ((channel_count > 1) ? 1 : 0)); + ctlr_info = scsi_ctlr_info_get(ctlr_vhdl); + SCI_ADAP(ctlr_info) = ql_pci_slot_number; + SCI_ALLOC(ctlr_info) = qlalloc; + SCI_COMMAND(ctlr_info) = qlcommand; + SCI_FREE(ctlr_info) = qlfree; + SCI_DUMP(ctlr_info) = qldump; + SCI_INQ(ctlr_info) = qlinfo; + SCI_IOCTL(ctlr_info) = qlioctl; + SCI_ABORT(ctlr_info) = qlabort; + scsi_bus_create(ctlr_vhdl); + return(ctlr_vhdl); +} + +/* + * qlinit: called once during system startup or + * when a loadable driver is loaded. + * + * The driver_register function should normally + * be in _reg, not _init. But the ql driver is + * required by devinit before the _reg routines + * are called, so this is an exception. + */ +void +qlinit(void) +{ + + /* initialize mutex for qldriverlock */ + QL_INIT_MUTEX(ql_driver_lock, "qldriverlock", 0); + + /* initialize default value */ + ql_pci_slot_number = 0; + ql_ha_list = NULL; + ql_watchdog_timer_inited = 0; + +} + +const struct pci_device_id __devinitdata ql_id_table[] = +{ + { QLogic_VENDOR_ID, QLogic_1040_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0x010000, 0xFFFFFF, 0 }, + { QLogic_VENDOR_ID, QLogic_1240_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0x010000, 0xFFFFFF, 0 }, + { QLogic_VENDOR_ID, QLogic_1080_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0x010000, 0xFFFFFF, 0 }, + { QLogic_VENDOR_ID, QLogic_1280_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0x010000, 0xFFFFFF, 0 }, + { QLogic_VENDOR_ID, QLogic_12160_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0x010000, 0xFFFFFF, 0 }, + { 0, 0, 0, 0, 0, 0, 0 } +}; + +struct pci_driver ql_driver = +{ + {0}, + "QL", + ql_id_table, + (int (*)(struct pci_dev *, const struct pci_device_id *)) qlattach, + NULL, + NULL, + NULL +}; + +int __init +ql_detect(void) +{ + static int qlinit_done = 0; + + if (qlinit_done) + return 0; + qlinit_done++; + qlinit(); + pci_register_driver(&ql_driver); + return 0; +} +module_init(ql_detect); + + +int +qlattach(scsi_pci_vhdl_t vhdl) +{ + pISP_REGS mem_addr; + pCHIP_INFO chip_info=NULL; + int count0; + int count1; + vertex_hdl_t ql_ctlr_vhdl; + int disks_found = 0; + pHA_INFO ha_tmp=NULL; + int max_targets= QL_MAXTARG; + int rc; + int i; + + u_short mbox_sts[8]; + u_short old_retry_delay; + u_short old_retry_cnt; + u_short reset_retry_cnt = 0; + pISP_REGS isp; + + u_short device_id; + u_short rev_id; + + /* w hot attach/detach, if we returned a non-zero w qldetach and caused a + detach failure, we can get an attach call for a card thats still + attached. So, check to be sure we dont have this card already attached. + if it is, return a 0 to indicate that it "attached ok" */ + QL_MUTEX_LOCK(ql_driver_lock); + ha_tmp=ql_ha_list; + while (ha_tmp) + { if (ha_tmp->chip_info->pci_vhdl==vhdl) + { QL_MUTEX_UNLOCK(ql_driver_lock); + cmn_err(CE_CONT, "%s is already attached\n", ha_tmp->ha_name); + return(0); + } + + ha_tmp=ha_tmp->next_ha; + } + QL_MUTEX_UNLOCK(ql_driver_lock); + + if ((rc = pci_enable_device(vhdl)) != 0) { + printk("ql: cannot enable device, rc == %d\n", rc); + return 1; + } + pci_set_master(vhdl); + mem_addr = (pISP_REGS) pci_resource_start(vhdl, 0); + if (!request_region((unsigned long) mem_addr, sizeof(*mem_addr), "ql")) + printk("ql: card in use by other driver\n"); + + { + ushort command = pciio_config_get(vhdl, PCI_CFG_COMMAND, 2); +#ifdef USE_IOSPACE + if (!(command & PCI_CMD_IO_SPACE)) { + pciio_config_set(vhdl, PCI_CFG_COMMAND, 2, command | PCI_CMD_IO_SPACE); + } +#else + if (!(command & PCI_CMD_MEM_SPACE)) { + pciio_config_set(vhdl, PCI_CFG_COMMAND, 2, command | PCI_CMD_MEM_SPACE); + } +#endif + } + + device_id = pciio_config_get(vhdl, PCI_CFG_DEVICE_ID, 2); + rev_id = pciio_config_get(vhdl, PCI_CFG_REV_ID, 1); + + if ( (device_id == QLogic_1040_DEVICE_ID) || + (device_id == QLogic_1080_DEVICE_ID)) { + count0 = 0; + count1 = 2; + } else if (device_id == QLogic_12160_DEVICE_ID) { + count0 = 3; + count1 = 3; + } else { + count0 = 2; + count1 = 2; + } + pciio_config_set(vhdl, PCI_CFG_LATENCY_TIMER, 1, 0x40); + pciio_config_set(vhdl, PCI_CFG_CACHE_LINE, 1, 0x80); +#if CONFIG_IA64_SGI_SN + if (pcibr_rrb_alloc(vhdl, &count0, &count1) < 0) + cmn_err(CE_PANIC, "ql: Unable to get Bridge RRB's"); +#endif + + /* initialize the adapter */ + if ((ql_ctlr_vhdl = ql_init(vhdl, mem_addr)) == GRAPH_VERTEX_NONE) { + ql_pci_slot_number++; /* increment slot so the next one is ok */ + return(1); + } + + ha_tmp = ql_ha_info_from_ctlr_get(ql_ctlr_vhdl); + chip_info = ha_tmp->chip_info; + + QL_LOCK(chip_info); + + isp = (pISP_REGS) chip_info->ha_base; + for (i=0;i < chip_info->channel_count; i++) { + + ha_tmp = chip_info->ha_info[i]; + + } + + + /* + * Set the retry count to zero for probing. + * this will make the probing faster. + * No lock is needed because here. + */ + + + + if (ql_set_selection_timeout(chip_info, mbox_sts)) { + rc = 1; + goto attach_failed; + } + + + if (ql_set_retry_count(chip_info, mbox_sts)) { + rc = 2; + goto attach_failed; + } else { + old_retry_cnt = mbox_sts[1]; + old_retry_delay = mbox_sts[2]; + reset_retry_cnt = 1; + } + + + chip_info->chip_flags |= AFLG_CHIP_INITIALIZED; + + + + + for (i=0; i < chip_info->channel_count; i++) { + + + ha_tmp = (pHA_INFO) chip_info->ha_info[i]; + + max_targets = QL_MAXTARG; + + +#define MSCSI_A 1 +#define MSCSI_B 2 +#define MSCSI_BO 3 /* MSCSI/B for Octane */ +#define MSCSIA_PNUM "030-0872-" +#define MSCSIB_PNUM "030-1243-" +#define MSCSIBO_PNUM "030-1281-" /* MSCSI/B for Octane */ + + + + + + QL_CPMSGS(ha_tmp->ctlr_vhdl, "Probing SCSI bus\n"); + QL_UNLOCK(chip_info); + QL_MUTEX_LOCK(chip_info->probemutex); + QL_LOCK(chip_info); + disks_found = ql_probe_bus(ha_tmp, max_targets, PROBE_ALL_LUNS); + QL_MUTEX_UNLOCK(ha_tmp->chip_info->probemutex); + ql_pci_slot_number++; + DBG(1, "= %d (disks)\n", disks_found); + }/* for channel_count loop */ + + + if (ql_set_selection_timeout(chip_info, mbox_sts)) { + rc = 3; + goto attach_failed; + + } + + + /* + * if retry count was set to zero than reset it to its old value. + */ + if (reset_retry_cnt) { + chip_info->Retry_Count = old_retry_cnt; + chip_info->Retry_Delay = old_retry_delay; + if (ql_set_retry_count(chip_info, mbox_sts)) { + rc = 4; + goto attach_failed; + } + + } + + QL_UNLOCK(chip_info); + return(0); + +attach_failed: + QL_UNLOCK(chip_info); + ql_ppmsg(chip_info, "qlattach() failed (%d)\n", rc); + return(rc); +} + + + + +int +qlabort(scsi_request_t *scsi_request) +{ + u_short mbox_sts[8]; + pHA_INFO ha = ql_ha_info_from_lun_get(scsi_request->sr_lun_vhdl); + ql_local_info_t *qli = SLI_INFO(scsi_lun_info_get(scsi_request->sr_lun_vhdl)); + int retval = 0; /* assume failure */ + int s; + + /* + * Only issue the ABORT mailbox command if there are + * outstanding * I/Os, otherwise punt. + */ + QL_LOCK(ha->chip_info); + QL_SPLOCK(qli->qli_lock, s); + if (((qli->qli_dev_flags & DFLG_ABORT_IN_PROGRESS) == 0) && + (qli->qli_cmd_rcnt > 0)) { + qli->qli_dev_flags |= DFLG_ABORT_IN_PROGRESS; + QL_SPUNLOCK(qli->qli_lock, s); + + if (ql_mbox_cmd(ha->chip_info, mbox_sts, 2, 2, + MBOX_CMD_ABORT_DEVICE, + (u_short) (ha->channel_id<<15) | + (u_short) (scsi_request->sr_target << 8) | + (u_short) (scsi_request->sr_lun), + 0, 0, 0, 0, 0, 0)) + { + ql_lpmsg(ha->ctlr_vhdl, scsi_request->sr_target, scsi_request->sr_lun, + "MBOX_CMD_ABORT_DEVICE Command failed\n"); + } + else { + retval = 1; /* success */ + } + } + else + QL_SPUNLOCK(qli->qli_lock, s); + QL_UNLOCK(ha->chip_info); + return(retval); +} + +void +qlhalt(void) +{ + pHA_INFO ha; + +#ifdef IP35 + /* in case this is a crash instead of a "halt", blow away locks + and switch to polled mode (necessary for systems w fc system disks + as we'll get a halt call but not a dump call) */ + for (ha = ql_ha_list; ha; ha = ha->next_ha) + { ha->chip_info->chip_flags |= AFLG_CHIP_DUMPING; + + QL_INIT_LOCK(&ha->chip_info->ctlrlock, "ql_ctlr", ha->ctlr_vhdl); + QL_INIT_MUTEX(ha->chip_info->probemutex, "ql_probemutex", ha->ctlr_vhdl); + QL_INIT_MUTEX(ha->chip_info->mboxmutex, "ql_mboxmutex", ha->ctlr_vhdl); + + ha->req_forw = NULL; + ha->req_back = NULL; + } +#endif + + for (ha = ql_ha_list; ha; ha = ha->next_ha) + { QL_LOCK(ha->chip_info); + ql_reset(ha->ctlr_vhdl); + QL_UNLOCK(ha->chip_info); + } +} + +/*ARGSUSED*/ +static iopaddr_t +fill_sg_elem(pHA_INFO ha, alenaddr_t address, size_t length, int allow_prefetch) +{ +#ifdef CONFIG_IA64_SGI_SN +#define QL_DATA_FLAGS (PCIIO_DMA_DATA | PCIIO_BYTE_STREAM | PCIIO_PREFETCH | PCIIO_DMA_A64) + scsi_pci_vhdl_t dev = ha->chip_info->pci_vhdl; + u_char chan = ha->channel_id; + int flags; + + if (chan == 0x01) + flags = PCIBR_VCHAN0 | QL_DATA_FLAGS; + else + flags = PCIBR_VCHAN1 | QL_DATA_FLAGS; +#endif + + return pciio_dmatrans_addr(dev, NULL, address, length, flags); +} + + + +/* +** Function: ql_set_defaults +** +** Description: Sets the default parameters. +*/ +static void +ql_set_defaults(pHA_INFO ha) +{ + int index; + Default_Parameters *n_ptr = &ha->ql_defaults; + pCHIP_INFO chip_info = ha->chip_info; + int disc_allow = 1; + + if ( (chip_info->device_id == QLogic_1240_DEVICE_ID) || + (chip_info->device_id == QLogic_1080_DEVICE_ID) || + (chip_info->device_id == QLogic_1280_DEVICE_ID) || + (chip_info->device_id == QLogic_12160_DEVICE_ID) ) + { + chip_info->ql_request_queue_depth = REQUEST_QUEUE_1240_DEPTH; + chip_info->ql_response_queue_depth = RESPONSE_QUEUE_1240_DEPTH; + } + else + { + chip_info->ql_request_queue_depth = REQUEST_QUEUE_1040_DEPTH; + chip_info->ql_response_queue_depth = RESPONSE_QUEUE_1040_DEPTH; + } + + + /* need to add code to detect which controller is this and assign accordingly */ + n_ptr->HA_Enable = HA_ENABLE; + + { + n_ptr->Initiator_SCSI_Id = INITIATOR_SCSI_ID; + if (arg_qlhostid[0]) + { + if ((arg_qlhostid[0] >= '0') && (arg_qlhostid[0] <= '9')) + n_ptr->Initiator_SCSI_Id = arg_qlhostid[0] - '0'; + else + if ((arg_qlhostid[0] >= 'a') && (arg_qlhostid[0] <= 'f')) + n_ptr->Initiator_SCSI_Id = arg_qlhostid[0] - 'a' + 10; + else + if ((arg_qlhostid[0] >= 'A') && (arg_qlhostid[0] <= 'F')) + n_ptr->Initiator_SCSI_Id = arg_qlhostid[0] - 'A' + 10; + } + if (n_ptr->Initiator_SCSI_Id > 7) + ql_cpmsg(ha->ctlr_vhdl, "Host SCSI ID set to %d - narrow devices will not be seen.\n", + n_ptr->Initiator_SCSI_Id); + } + + + chip_info->Retry_Count = RETRY_COUNT; + chip_info->Retry_Delay = RETRY_DELAY; + + /* do not allow disconnects on early ql parts. only rev b */ + if ((chip_info->device_id == QLogic_1040_DEVICE_ID) &&(chip_info->revision <= REV_ISP1040A)) + disc_allow = 0; + + { + n_ptr->Selection_Timeout = SELECTION_TIMEOUT; + } + + n_ptr->Bus_Reset_Delay = ql_bus_reset_delay; + + for (index = 0; index < QL_MAXTARG; index++) + { + n_ptr->Id[index].Capability.bits.Renegotiate_on_Error = RENEGOTIATE_ON_ERROR; + n_ptr->Id[index].Capability.bits.Stop_Queue_on_Check = STOP_QUEUE_ON_CHECK; + n_ptr->Id[index].Capability.bits.Auto_Request_Sense = AUTO_REQUEST_SENSE; + if (disc_allow) + { + { + n_ptr->Id[index].Capability.bits.Disconnect_Allowed = DISCONNECT_ALLOWED; + } + + { + n_ptr->Id[index].Capability.bits.Tagged_Queuing = TAGGED_QUEUING; + } + } + + + n_ptr->Id[index].Capability.bits.Sync_Data_Transfers = 0; + n_ptr->Id[index].Sync_Allowed = SYNC_DATA_TRANSFERS; + + + n_ptr->Id[index].Capability.bits.Wide_Data_Transfers = 0; + if (ha->host_flags & AFLG_HA_FAST_NARROW) + { + n_ptr->Id[index].Sync_Period = SYNC_PERIOD; + n_ptr->Id[index].Wide_Allowed = 0; + } + else + { + n_ptr->Id[index].Wide_Allowed = WIDE_DATA_TRANSFERS; + + { + if (ha->chip_info->clock_rate == FAST20_CLOCK_RATE) + n_ptr->Id[index].Sync_Period = SYNC_PERIOD_FAST20; + else if (ha->chip_info->clock_rate == FAST40_CLOCK_RATE) + n_ptr->Id[index].Sync_Period = SYNC_PERIOD_FAST40; + else + n_ptr->Id[index].Sync_Period = SYNC_PERIOD_FAST80; + } + } + n_ptr->Id[index].Capability.bits.Parity_Checking = PARITY_CHECKING; + + n_ptr->Id[index].Throttle = EXECUTION_THROTTLE; + { + if (chip_info->device_id == QLogic_12160_DEVICE_ID) + n_ptr->Id[index].Sync_Offset = SYNC_OFFSET_12160; + else + n_ptr->Id[index].Sync_Offset = SYNC_OFFSET; + } + } +} + +/* +** +** +*/ + +static void +scan_bus(vertex_hdl_t ql_ctlr_vhdl) +{ + int disks_found = 0; + pHA_INFO ha = ql_ha_info_from_ctlr_get(ql_ctlr_vhdl); + + QL_CPMSGS(ql_ctlr_vhdl, "Re-probing SCSI bus\n"); + + QL_MUTEX_LOCK(ha->chip_info->probemutex); + QL_LOCK(ha->chip_info); + + /* set defaults again in case some device got changed up */ + ql_set_defaults(ha); + + disks_found = ql_probe_bus(ha, QL_MAXTARG, 1); + QL_UNLOCK(ha->chip_info); + QL_MUTEX_UNLOCK(ha->chip_info->probemutex); + + DBG(1, "= %d (disks)\n", disks_found); +} + +static int +reqi_get_slot(pHA_INFO ha,int tgt) +{ + int i; + pREQ_INFO r_ptr; + int slot = -1; + + i = ha->reqi_cntr[tgt]; + r_ptr = &ha->reqi_block[tgt][i]; + + do { + i++; + if (i > MAX_REQ_INFO) { + i = 0; + } + r_ptr = &ha->reqi_block[tgt][i]; + if (r_ptr->req == NULL) { + slot = i; + break; + } + } while (i != ha->reqi_cntr[tgt]); + + if (slot >= 0) + ha->reqi_cntr[tgt] = slot; + + return slot; +} + +static void +ql_quiesce_bus(pHA_INFO ha, long quiesce_wait, long quiesce_time) +{ + /* is this to extend the quiesce */ + if(ha->host_flags & AFLG_HA_QUIESCE_COMPLETE) { + untimeout(ha->quiesce_id); + ha->quiesce_id = timeout(kill_quiesce, ha, quiesce_time, KILL_WITHOUT_TIMEOUT); + return; + } + if (ha->ql_ncmd == 0) { + ha->host_flags |= AFLG_HA_QUIESCE_COMPLETE; + ha->host_flags &= ~AFLG_HA_QUIESCE_IN_PROGRESS; + ha->quiesce_id = timeout(kill_quiesce, ha, quiesce_time, KILL_WITHOUT_TIMEOUT); + } else { + ha->host_flags |= AFLG_HA_QUIESCE_IN_PROGRESS; + ha->quiesce_in_progress_id = timeout(kill_quiesce,ha, quiesce_wait, KILL_WITHOUT_TIMEOUT); + ha->quiesce_time = quiesce_time; + } +} + + +static void +kill_quiesce(pHA_INFO ha, int kill_timeout) +{ + QL_LOCK(ha->chip_info); + + undo_quiesce(ha, kill_timeout); + + /* try to startup and pending commands */ + if (!(ha->host_flags & AFLG_HA_DRAIN_IO)) + ql_start_scsi(ha->chip_info); + QL_UNLOCK(ha->chip_info); +} + + +static void +undo_quiesce(pHA_INFO ha, int kill_timeout) +{ + ha->host_flags &= ~(AFLG_HA_QUIESCE_IN_PROGRESS | AFLG_HA_QUIESCE_COMPLETE); + if(ha->quiesce_in_progress_id) { + if (kill_timeout == KILL_WITH_TIMEOUT) + untimeout(ha->quiesce_in_progress_id); + ha->quiesce_in_progress_id = NULL; + } + if(ha->quiesce_id) { + if (kill_timeout == KILL_WITH_TIMEOUT) + untimeout(ha->quiesce_id); + ha->quiesce_id = NULL; + } + ha->quiesce_time = 0; +} + +static int +ql_download_fw(pCHIP_INFO chip_info) +{ + u_short mbox_sts[8]; + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + int count; + int retry_cnt; + u_short* w_ptr; + u_short Config_Reg; + int rc = 0; + ushort *firmware; +#ifdef LOAD_VIA_DMA + paddr_t p_ptr; +#endif + + QL_PCI_OUTH(&isp->bus_icr, ICR_ENABLE_RISC_INT | ICR_SOFT_RESET); + flushbus(); + DELAY(30); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RESET); + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + for (retry_cnt = 10000; ; ) { + DELAY(100); + if (!(QL_PCI_INH(&isp->hccr) & HCCR_RESET)) + break; + if (--retry_cnt <= 0) { + rc = 11; + goto download_failed; + } + } + + chip_info->chip_flags |= AFLG_CHIP_DOWNLOAD_FIRMWARE; + +#ifdef QL_SRAM_PARITY + /* turn on the sram parity support first and let the routine */ + /* to determine if the controller is capable to support sram parity */ + + chip_info->chip_flags |= AFLG_CHIP_SRAM_PARITY_ENABLE; + if (ql_enable_sram_parity(chip_info, 1)) { + rc = 7; + goto download_failed; + } +#endif + + ql_enable_intrs(chip_info); + + /* If we're going to load our own firmware, we need to */ + /* stop any currently running firmware (if any). */ + + if (ql_mbox_cmd(chip_info, mbox_sts, 8, 8, + MBOX_CMD_MAILBOX_REGISTER_TEST, + (ushort)0x1111, + (ushort)0x2222, + (ushort)0x3333, + (ushort)0x4444, + (ushort)0x5555, + (ushort)0x6666, + (ushort)0x7777)) + { + rc = 1; + goto download_failed; + } + + + /* At this point, the RISC is running, but not any loaded firmware.*/ + /* We can now either load new firmware or restart the previously loaded */ + /* firmware. */ + + /* Initialize the Control Parameter configuration. */ + + /* Build the value for the ISP Configuration 1 Register. */ + Config_Reg = BURST_128; + + /* always set burst enable */ + Config_Reg |= CONF_1_BURST_ENABLE; + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); /* do I need to do this? */ + QL_PCI_OUTH(&isp->bus_config1, Config_Reg); + QL_PCI_OUTH(&isp->bus_sema, 0); + DELAY(100); + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); /* and this? */ + flushbus(); + DELAY(30); + + + /* Okay, we're ready to load our own firmware. */ + /* We have two ways of doing this: DMA or word by word. */ + +#ifdef LOAD_VIA_DMA + /* wasnt able to get 1040's to download via dma. So... */ + if (chip_info->device_id != QLogic_1040_DEVICE_ID) + { + /* keep in mind that the mailbox command and risc file are using + length in 16 bit words whereas other things use it in bytes */ + + firmware = (ushort *)QL_KMEM_ZALLOC( + chip_info->risc_code_length*sizeof(uint16_t), + VM_CACHEALIGN | VM_NOSLEEP | VM_DIRECT | VM_PHYSCONTIG); + if (firmware==NULL) + { rc=7; + goto download_failed; + } + + /* copy and byte swap the risc code */ + bcopy(chip_info->risc_code, firmware, + chip_info->risc_code_length*sizeof(uint16_t)); + + + + + p_ptr = pciio_dmatrans_addr(chip_info->pci_vhdl, NULL, + kvtophys(firmware), + chip_info->risc_code_length*sizeof(uint16_t), + PCIBR_VCHAN1 | + PCIIO_DMA_DATA | + PCIIO_BYTE_STREAM | + PCIIO_DMA_A64); + + + /* Load my copy of the executable firmware by DMA. */ + if (ql_mbox_cmd(chip_info, mbox_sts, 8, 8, + MBOX_CMD_LOAD_RAM_64, + (u_short)chip_info->risc_code_addr, + (u_short)(p_ptr >> 16), + (u_short)(p_ptr & 0xFFFF), + (u_short)chip_info->risc_code_length, + 0, + (u_short)(p_ptr >> 48), + (u_short)(p_ptr >> 32))) + { + rc = 2; + } + + if (rc) + { kmem_free(firmware, + chip_info->risc_code_length*sizeof(uint16_t)); + goto download_failed; + } + +#if 0 + /* now compare the fw to see if it loaded correctly */ + { + w_ptr = chip_info->risc_code; + for (count = 0; count < chip_info->risc_code_length; + count++, w_ptr++) { + ql_mbox_cmd (chip_info, mbox_sts, 2,3, + MBOX_CMD_READ_RAM_WORD, + (uint16_t)(chip_info->risc_code_addr + count), + 0,0,0,0,0,0); + if (mbox_sts[0] != 0x4000 || mbox_sts[2] != *w_ptr) { + printf( + ql_cpmsg(chip_info->ctlr_vhdl[0], + "LOAD_FW : firmware miscompare: %d, expected 0x%x, actual 0x%x\n", + count,*w_ptr, mbox_sts[2]); + rc=3; + kmem_free(firmware, + chip_info->risc_code_length*sizeof(uint16_t)); + goto download_failed; + } + } + ql_cpmsg(chip_info->ctlr_vhdl[0], "Firmware load verified.\n"); + } +#endif + + kmem_free(firmware, chip_info->risc_code_length*sizeof(uint16_t)); + } + else + +#endif /* LOAD_VIA_DMA */ + { + /* + * Load executable firmware one word at a time + */ + w_ptr = &chip_info->risc_code[0]; + for (count = 0; count < chip_info->risc_code_length; count++) { + if (ql_mbox_cmd(chip_info, mbox_sts, 3, 3, + MBOX_CMD_WRITE_RAM_WORD, + (u_short)(chip_info->risc_code_addr + count), + *w_ptr, /* risc data */ + 0,0,0,0,0)) + { + rc = 4; + goto download_failed; + } + w_ptr++; + } + } + + /* Start ISP firmware. */ + if (ql_mbox_cmd(chip_info, mbox_sts, 2, 1, + MBOX_CMD_EXECUTE_FIRMWARE, + chip_info->risc_code_addr, + 0,0,0,0,0,0)) + { + rc = 5; + goto download_failed; + } + + if (showconfig) { + if (ql_mbox_cmd(chip_info, mbox_sts, 1, 3, + MBOX_CMD_ABOUT_FIRMWARE, + 0,0,0,0,0,0,0)) + { + rc = 6; + goto download_failed; + } + ql_cpmsg(chip_info->ctlr_vhdl[0], "Firmware version: %d.%d.%d\n", + mbox_sts[1], mbox_sts[2], mbox_sts[3]); + } + + chip_info->chip_flags &= ~AFLG_CHIP_DOWNLOAD_FIRMWARE; + + + return(0); + +download_failed: + ql_ppmsg(chip_info, "ql_download_fw failed (%d)\n", rc); + return(rc); +} + +static int +ql_reset_interface(pCHIP_INFO chip, int reset) +{ + u_short mbox_sts[8]; + pISP_REGS isp = (pISP_REGS)chip->ha_base; + paddr_t p_ptr; + int i; + targ_t targ; + lun_t lun; + ql_local_info_t *qli; + vertex_hdl_t lun_vhdl,targ_vhdl; + u_short mailbox0; + int retry_cnt; + int rc = 0; + pHA_INFO ha=NULL; + int s; + + + /* + * reset AFLG_INITIALIZED for adapter + * set the defaults for the devices (wide might change if hot plugged) + * reset DFLG_INITIALIZED for all attached devices + * reset DFLG_CONTINGENT_ALLEGIANCE for all attached devices + * disable interrupt + * pause RISC + * reset ISP1040 + * clear the CMD & DATA DMA chan + * wait for risc reset + */ + + chip->chip_flags &= ~AFLG_CHIP_INITIALIZED; + + for (i=0; i < chip->channel_count; i++) { + ha = chip->ha_info[i]; + ha->host_flags |= AFLG_HA_SEND_MARKER; + for(targ=0 ; targctlr_vhdl, targ)) != GRAPH_VERTEX_NONE) + { + for(lun=0 ; lunctlr_vhdl,targ,lun))!=GRAPH_VERTEX_NONE) { + qli = SLI_INFO(scsi_lun_info_get(lun_vhdl)); + QL_SPLOCK(qli->qli_lock, s); + qli->qli_dev_flags &= ~(DFLG_INITIALIZED | DFLG_CONTINGENT_ALLEGIANCE); + QL_SPUNLOCK(qli->qli_lock, s); + + } + } + } + } + } + + chip->queue_space = 0; + chip->request_in = 0; + chip->request_out = 0; + chip->response_out = 0; + chip->request_ptr = chip->request_base; + chip->response_ptr = chip->response_base; + + /* + * Mark all responses as dead. + */ + { + int i; + status_entry *p; + + for (p = (status_entry *)chip->response_base, i = 0; i < chip->ql_response_queue_depth; ++i, ++p) + p->handle = 0xDEAD; + } + +#ifdef BUS_INT_WAR + sn_delete_polled_interrupt(chip->pci_vhdl->irq); +#endif + + QL_PCI_OUTH(&isp->bus_icr, 0); /* disable interrupts */ + + /* + * Pause RISC and wait till it's paused. + */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); + flushbus(); + for (retry_cnt = 10000; ; ) { + DELAY(100); + if (QL_PCI_INH(&isp->hccr) & HCCR_PAUSE) + break; + if (--retry_cnt <= 0) { + rc = 1; + goto reset_failed; + } + } + + /* + * Reset ISP and wait till it's reset. + */ + QL_PCI_OUTH(&isp->bus_icr, ICR_SOFT_RESET); + flushbus(); + DELAY(30); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RESET); + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + for (retry_cnt = 10000; ; ) { + DELAY(100); + if (!(QL_PCI_INH(&isp->hccr) & HCCR_RESET)) + break; + if (--retry_cnt <= 0) { + rc = 2; + goto reset_failed; + } + } + + if (chip->device_id == QLogic_1040_DEVICE_ID) { + + /* 1040 only */ + QL_PCI_OUTH(&isp->control_dma_control, DMA_CON_RESET_INT | DMA_CON_CLEAR_FIFO | DMA_CON_CLEAR_CHAN); + QL_PCI_OUTH(&isp->data_dma_control, DMA_CON_RESET_INT | DMA_CON_CLEAR_FIFO | DMA_CON_CLEAR_CHAN); + + } else { + + /* 1080, 1240, 1280, 12160 only and we double the register name with other banks */ + u_short tmp_val, tmp_val1; + + /* switch to DMA bank registers file */ + tmp_val = QL_PCI_INH(&isp->bus_config1); + QL_PCI_OUTH(&isp->bus_config1, tmp_val|CONF_1_1240_DMA_SEL); + flushbus(); + + /* write the pci base + address 0x82 to reset DMA command */ + QL_PCI_OUTH(&isp->r1, DMA_CON_RESET_INT | DMA_CON_CLEAR_FIFO | DMA_CON_CLEAR_CHAN); + + /* write the pci base + address 0xA2 to reset DMA Data 0 channel */ + QL_PCI_OUTH(&isp->ivr, DMA_CON_RESET_INT | DMA_CON_CLEAR_FIFO | DMA_CON_CLEAR_CHAN); + + /* write the pci base + address 0xC2 to reset DMA Data 1 channel */ + QL_PCI_OUTH(&isp->c2, DMA_CON_RESET_INT | DMA_CON_CLEAR_FIFO | DMA_CON_CLEAR_CHAN); + flushbus(); + + tmp_val1 = QL_PCI_INH(&isp->accumulator); + QL_PCI_OUTH(&isp->accumulator, tmp_val1|DCR_DMA_BURST_ENABLE); + flushbus(); + + tmp_val1 = QL_PCI_INH(&isp->hccr); + QL_PCI_OUTH(&isp->hccr, tmp_val1|DCR_DMA_BURST_ENABLE); + flushbus(); + + /* switch back the registers bank */ + QL_PCI_OUTH(&isp->bus_config1, tmp_val); + flushbus(); + } + + + for (i = 0;i < QL_RESET; i++) { + mailbox0 = QL_PCI_INH(&isp->mailbox0); + if (mailbox0 != MBOX_STS_BUSY) + break; + DELAY(1000); + } + +#ifdef QL_SRAM_PARITY + ql_enable_sram_parity(chip,0); +#endif /* QL_SRAM_PARITY */ + + QL_PCI_OUTH(&isp->bus_config1, BURST_128 | CONF_1_BURST_ENABLE); + QL_PCI_OUTH(&isp->bus_sema, 0); + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + /* At this point, the firmware is up and running and we're ready to */ + /* initialze for normal startup. */ + + ql_enable_intrs(chip); + + + /* Start ISP firmware. */ + if (ql_mbox_cmd(chip, mbox_sts, 2, 1, + MBOX_CMD_EXECUTE_FIRMWARE, + chip->risc_code_addr, + 0,0,0,0,0,0)) + { + rc = 3; + goto reset_failed; + } + + /* Set Bus Control Parameters. */ + if (ql_set_pci_control_parameters(chip, mbox_sts)) { + rc = 4; + goto reset_failed; + } + + + /* Set the Clock Rate for the board */ + + if (ql_set_clock_rate(chip, mbox_sts)) { + rc = 5; + goto reset_failed; + } + + /* + * PCIIO_DMA_CMD turns prefetcher off, barrier on. + */ + if (chip->response_dmaptr == 0) { + chip->response_dmaptr = pciio_dmatrans_addr(chip->pci_vhdl, NULL, + kvtophys(chip->response_ptr), + sizeof(queue_entry)*chip->ql_response_queue_depth, + PCIBR_VCHAN1 | + PCIIO_BYTE_STREAM | + PCIIO_DMA_CMD | + PCIIO_DMA_A64); + } + + p_ptr = chip->response_dmaptr; + + bzero(chip->response_base, chip->ql_response_queue_depth*sizeof(queue_entry)); + + /* Initialize response queue. */ + if (ql_mbox_cmd(chip, mbox_sts, 8, 8, + MBOX_CMD_INIT_RESPONSE_QUEUE_64, + chip->ql_response_queue_depth, + (u_short)(p_ptr >> 16), + (u_short)(p_ptr & 0xFFFF), + 0, + chip->response_out, + (u_short) (p_ptr >> 48), + (u_short) (p_ptr >> 32))) + { + rc = 6; + goto reset_failed; + } + + + chip->request_ptr = chip->request_base; + + if (chip->request_dmaptr == 0) { + chip->request_dmaptr = pciio_dmatrans_addr(chip->pci_vhdl, NULL, + kvtophys(chip->request_base), + sizeof(queue_entry)*chip->ql_request_queue_depth, + PCIBR_VCHAN1 | + PCIIO_BYTE_STREAM | + PCIIO_DMA_CMD | + PCIIO_DMA_A64); + } + + p_ptr = chip->request_dmaptr; + bzero(chip->request_base,chip->ql_request_queue_depth*sizeof(queue_entry)); + + /* Initialize request queue. */ + + if (ql_mbox_cmd(chip, mbox_sts, 8, 8, + MBOX_CMD_INIT_REQUEST_QUEUE_64, + chip->ql_request_queue_depth, + (u_short)(p_ptr >> 16), + (u_short)(p_ptr & 0xFFFF), + chip->request_in, + 0, + (u_short) (p_ptr >> 48), + (u_short) (p_ptr >> 32))) + { + rc = 7; + goto reset_failed; + } + + if (reset) { + for (i=0; i < chip->channel_count; ++i) { + ha = chip->ha_info[i]; + + if (ql_set_bus_reset(chip, mbox_sts, ha->channel_id)) { + rc = 8; + goto reset_failed; + } + + } + } + + + /* Set SCSI id */ + if (ql_set_scsi_id(chip, mbox_sts)) { + rc = 9; + goto reset_failed; + } + + + /* Set Selection Timeout */ + if (ql_set_selection_timeout(chip, mbox_sts)) { + rc = 10; + goto reset_failed; + } + + + /* Set RETRY limits. */ + if (ql_set_retry_count(chip, mbox_sts)) { + rc = 11; + goto reset_failed; + } + + /* Set Tag Age Limits. */ + if (ql_set_tag_age_limit(chip, mbox_sts)) { + rc = 12; + goto reset_failed; + } + + /* Set Active Negation. */ + if (ql_set_negation_state(chip, mbox_sts)) { + rc = 13; + goto reset_failed; + } + + /* Set Asynchronous Data Setup Time. */ + if (ql_set_asynchronous_data_setup_time(chip, mbox_sts)) { + rc = 14; + goto reset_failed; + } + + + /* Set Data Overrun Recovery Mode */ + if (ql_set_data_over_recovery_mode(chip, mbox_sts)) { + rc = 15; + goto reset_failed; + } + + /* set scsi bus reset delay paramters */ + if (ql_set_reset_delay_parameters(chip, mbox_sts)) { + rc = 16; + goto reset_failed; + } + + /* set system parameters such as memory timing */ + if (ql_set_system_parameters(chip, mbox_sts)) { + rc = 17; + goto reset_failed; + } + + /* set firmware features such as */ + if (ql_set_firmware_features(chip, mbox_sts)) { + rc = 18; + goto reset_failed; + } + + /* Indicate we successfully initialized this ISP! */ + chip->chip_flags |= AFLG_CHIP_INITIALIZED; + return(0); + +reset_failed: + ql_ppmsg(chip, "ql_reset_interface failed (%d)\n", rc); + return(rc); +} + +static void +ql_flush_queue(pHA_INFO ha, uint sr_status) +{ + int i, id, lun; + pREQ_INFO r_ptr; + scsi_request_t* cmp_forw = NULL; + scsi_request_t* cmp_back = NULL; + scsi_request_t* request = NULL; + vertex_hdl_t lun_vhdl; + ql_local_info_t *qli; + int s; + + for (id = 0; id < QL_MAXTARG; id++) { + if (id == ha->ql_defaults.Initiator_SCSI_Id) + continue; + /* + * Clean up queued target commands + */ + r_ptr=ha->reqi_block[id]; + if (r_ptr) + { + for (i = 0; i <= MAX_REQ_INFO ; i++) { + r_ptr = &ha->reqi_block[id][i]; + if (r_ptr->req != NULL) { + if (cmp_forw) { + cmp_back->sr_ha = r_ptr->req; + cmp_back = r_ptr->req; + } + else + { + cmp_forw = r_ptr->req; + cmp_back = r_ptr->req; + } + r_ptr->req->sr_ha = NULL; + r_ptr->req = NULL; + } + } + } + ha->tcmd[id]=0; + + /* + * Clean up queued LUN commands + */ + for (lun = 0; lun < QL_MAXLUN; ++lun) { + if ((lun_vhdl = scsi_lun_vhdl_get(ha->ctlr_vhdl, id, lun)) == GRAPH_VERTEX_NONE) + continue; + qli = SLI_INFO(scsi_lun_info_get(lun_vhdl)); + QL_SPLOCK(qli->qli_lock, s); + if (qli->qli_dev_flags & DFLG_ABORT_IN_PROGRESS && qli->qli_awaitf) { + if (cmp_forw) { + cmp_back->sr_ha = qli->qli_awaitf; + cmp_back = qli->qli_awaitb; + } + else { + cmp_forw = qli->qli_awaitf; + cmp_back = qli->qli_awaitb; + } + cmp_back->sr_ha = NULL; + qli->qli_awaitf = qli->qli_awaitb = NULL; + } + qli->qli_dev_flags &= ~DFLG_ABORT_IN_PROGRESS; + + if (qli->qli_dev_flags & DFLG_INIT_IN_PROGRESS && qli->qli_iwaitf) { + if (cmp_forw) { + cmp_back->sr_ha = qli->qli_iwaitf; + cmp_back = qli->qli_iwaitb; + } + else { + cmp_forw = qli->qli_iwaitf; + cmp_back = qli->qli_iwaitb; + } + cmp_back->sr_ha = NULL; + qli->qli_iwaitf = qli->qli_iwaitb = NULL; + } + qli->qli_dev_flags &= ~DFLG_INIT_IN_PROGRESS; + QL_SPUNLOCK(qli->qli_lock, s); + + qli->qli_cmd_rcnt = 0; + } /* for (lun) */ + } /* for (id) */ + ha->ql_ncmd = 0; + while ((request = cmp_forw)) { + cmp_forw = request->sr_ha; + + if (request->sr_status == 0) + request->sr_status = sr_status; + + QL_UNLOCK(ha->chip_info); + (*request->sr_notify)(request); + QL_LOCK(ha->chip_info); + } +} + + +/* watchdog is complicated. Basically, to do this (somewhat) correctly, the timer periodically goes through + and decreases every cmd's outstanding timer value. And if one go to zero (or less), then we have a problem + + What is done then is to: + quiesce the all board buses for a huge period (MAXWAIT) so any other outstanding commands will drain + As the watchdog goes off periodically, see if the bus has completed draining, and continue timing cmds + (which can expire more commands; which is ok) + (in a multiport card, the non-expired ports will time in block 1, expired ports in block 2) + When the board drains (all non-expired commands, all ports), reset the board (block 3) and + kill the quiesce, restarting io (all ports) + + This allows any other (potentially lengthy) commands to complete (or expire). + The MAXWAIT length drain is limited by all commands expiring or draining. As the timer continues to run, + and no more commands are being accepted, the period is bounded by the longest timer+WATCHDOG_TIME + and it should not be possible to get stuck. It also should wind up being faster than waiting as long + as the longest timer since outstanding commands will likely finish sooner. Worst case, its as long + as the longest time (if the command fails to complete and winds up expired) + If an additional port expires a command, then its timing moves from block 1 to block 2 and its flags are set. + But it causes no additional problems as eventually one of the boards ports moves to block 3 and + warns about all expired cmds, resets the card, and restarts all the ports +*/ + +static void +ql_watchdog_timer(void *data) +{ + pHA_INFO ha; + pHA_INFO ha_tmp; + pCHIP_INFO chip_info; + int tgt; + int chip_reset_needed; + int i, j; + int done; + int long_to; + pREQ_INFO r_ptr; + int undrained, firstp; + + + QL_MUTEX_LOCK(ql_driver_lock); + for ( ha = ql_ha_list; ha != NULL ; ha = ha->next_ha) { + chip_info = ha->chip_info; + QL_LOCK(chip_info); + + /* + * Check for pending mailbox command + */ + if (chip_info->chip_flags & AFLG_CHIP_MAIL_BOX_WAITING) { + + if (chip_info->mbox_timeout_info > 0) + chip_info->mbox_timeout_info -= WATCHDOG_TIME; + else + vsema(&chip_info->mbox_done_sema); + } + + if (!(ha->host_flags & AFLG_HA_TIMEOUT)) + { /* block 1 */ + /* + * Check for timed out SCSI commands, same port only + */ + chip_reset_needed = 0; + if (ha->ql_ncmd) { + for (tgt = 0; tgt < QL_MAXTARG ; tgt++) + { + if (ha->tcmd[tgt]) /* will also skip initiator ID and missing targets */ + { + r_ptr=ha->reqi_block[tgt]; + /* walk through the reqi block checking for expired timers */ + for (i = 0; i <= MAX_REQ_INFO ; i++) { + r_ptr = &ha->reqi_block[tgt][i]; + if (r_ptr->req != NULL) + { if (r_ptr->timeout>0) /* allows slightly negative t/o */ + r_ptr->timeout -= WATCHDOG_TIME; + else + chip_reset_needed=1; /* expired! */ + } + } + } + } + + if (chip_reset_needed) /* drain IO on all board ports */ + { + long_to=0; + for (i=0; ichannel_count; i++) + { ha_tmp=chip_info->ha_info[i]; + ha_tmp->host_flags |= AFLG_HA_DRAIN_IO; + + /* see if this port is already quiesced. If not, quiesce it */ + if (!(ha_tmp->host_flags & (AFLG_HA_QUIESCE_IN_PROGRESS | AFLG_HA_QUIESCE_COMPLETE))) + ql_quiesce_bus(ha_tmp, MAXWAIT, MAXWAIT); /* as long as it can be */ + else if (!(ha_tmp->host_flags & AFLG_HA_TIMEOUT)) + { /* there's an existing quiesce. kill it and start another */ + undo_quiesce(ha_tmp, KILL_WITH_TIMEOUT); + ql_quiesce_bus(ha_tmp, MAXWAIT, MAXWAIT); /* as long as it can be */ + } + + for (tgt=0; tgttcmd[tgt]==0) + continue; + + r_ptr=ha_tmp->reqi_block[tgt]; + for (j = 0; j <= MAX_REQ_INFO ; j++) { + r_ptr = &ha_tmp->reqi_block[tgt][j]; + if ((r_ptr->req != NULL) && (r_ptr->timeout>long_to)) + long_to=r_ptr->timeout; + } + } + } + + ql_cpmsg(ha->ctlr_vhdl, "Command timeout, draining ctlr IO for as long as %d seconds\n", + long_to+2*WATCHDOG_TIME); + + ha->host_flags |= AFLG_HA_TIMEOUT; /* only timing out current port right now */ + } + } + } + else if ((ha->host_flags & (AFLG_HA_TIMEOUT|AFLG_HA_TODRAINED))==AFLG_HA_TIMEOUT) + { /* see if all board IO drained so the reset can happen */ + /* We need to know if all ports drained. other ports are still being timed by the + block 1 code. If it times out cmds as well, thats fine. */ + /* block 2 */ + done=1; + for (i=0; ichannel_count; i++) + { ha_tmp=chip_info->ha_info[i]; + + /* see if there's any untimed out commands outstanding */ + for (tgt=0; tgttcmd[tgt]==0) + continue; + + r_ptr=ha_tmp->reqi_block[tgt]; + for (j = 0; j <= MAX_REQ_INFO ; j++) { + r_ptr = &ha_tmp->reqi_block[tgt][j]; + if ((r_ptr->req != NULL) && (r_ptr->timeout>0)) + { done=0; /* found unexpired cmd, so keep waiting */ + if (ha_tmp==ha) + r_ptr->timeout -= WATCHDOG_TIME; /* keep clock ticking, T/O port only */ + } + } + } + } + + if (done) + ha->host_flags |= AFLG_HA_TODRAINED; + } + + if ((ha->host_flags & (AFLG_HA_TIMEOUT|AFLG_HA_TODRAINED))==(AFLG_HA_TIMEOUT|AFLG_HA_TODRAINED)) + /* yell and restart, shouldnt be anything left except expired cmds. Wacks all ports of course */ + /* its been pointed out that its possible commands can come down with improperly set timer values. + And that they could therefore drain during the t/o interval and that things are actually running + ok. So this code also deals with that scenerio */ + { /* block 3 */ + undrained=0; + for (i=0; i < chip_info->channel_count; i++){ + ha_tmp = chip_info->ha_info[i]; + for (tgt = 0; tgt < QL_MAXTARG ; tgt++) { + if (ha_tmp->tcmd[tgt]==0) + continue; + + firstp=0; + r_ptr=ha_tmp->reqi_block[tgt]; + for (j = 0; j <= MAX_REQ_INFO ; j++) { + r_ptr = &ha_tmp->reqi_block[tgt][j]; + if (r_ptr->req != NULL) + { undrained=1; + if (!firstp) + { firstp=1; + ql_tpmsg(ha_tmp->ctlr_vhdl, tgt, "SCSI command timeout: %d commands: ",ha_tmp->tcmd[tgt]); + } + cmn_err(CE_CONT, "0x%x ", r_ptr->req->sr_command[0]); + } + + } + cmn_err(CE_CONT, "\n"); + } + } + + chip_info->chip_flags |= AFLG_CHIP_WATCHDOG_TIMER; /* switch to polling in case board wedged */ + if (undrained) /* need to carry out the reset */ + { + ql_cpmsg(ha->ctlr_vhdl, "Resetting SCSI chip.\n"); + ql_reset_interface(chip_info,1); + } + else + ql_cpmsg(ha->ctlr_vhdl, "Controller drained, resuming operation\n"); + + for (i=0; i < chip_info->channel_count; i++){ + ha_tmp = chip_info->ha_info[i]; + ql_flush_queue(ha_tmp, SC_CMDTIME); + undo_quiesce(ha_tmp, KILL_WITH_TIMEOUT); + ha_tmp->host_flags &= ~(AFLG_HA_TIMEOUT| AFLG_HA_TODRAINED | AFLG_HA_DRAIN_IO); + } + chip_info->chip_flags &= ~AFLG_CHIP_WATCHDOG_TIMER; + } + + /* this will restart all board ports */ + if (!(ha->host_flags & AFLG_HA_DRAIN_IO) && ((ha->waitf) || (ha->req_forw))) + ql_start_scsi(chip_info); + + QL_UNLOCK(chip_info); + } + itimeout(ql_watchdog_timer, NULL, WATCHDOG_TIME * HZ, TIMEOUT_SPL); + QL_MUTEX_UNLOCK(ql_driver_lock); +} + +#if 0 + else if (bus_reset_needed) { + ql_cpmsg(ha->ctlr_vhdl, "Resetting SCSI bus.\n"); + chip_info->chip_flags |= AFLG_CHIP_WATCHDOG_TIMER; + if (ql_reset(ha->ctlr_vhdl)) + { + /* if bus reset failed that chip reset must take place */ + chip_info->chip_flags &= ~AFLG_CHIP_WATCHDOG_TIMER; + ql_reset_interface(chip_info,1); + for (i=0; i < chip_info->channel_count; i++){ + ha_tmp = chip_info->ha_info[i]; + ql_flush_queue(ha_tmp, SC_CMDTIME); + ha_tmp->host_flags &= ~AFLG_HA_DRAIN_IO; + } + } + else + /* + * Reset Target parameters to their default + * values. + */ + { + int id; + ushort mbox_sts[8]; + + for (id = 0; id < QL_MAXTARG; ++id) { + if (id == ha->ql_defaults.Initiator_SCSI_Id) + continue; + if (scsi_lun_vhdl_get(ha->ctlr_vhdl, id, 0) == GRAPH_VERTEX_NONE) + continue; + if (ql_set_scsi_parameters(ha->chip_info, mbox_sts, + ha->channel_id, id) ) { + ql_tpmsg(ha->ctlr_vhdl, id, "MBOX_CMD_SET_TARGET_PARAMETERS failed\n"); + } + } + chip_info->chip_flags &= ~AFLG_CHIP_WATCHDOG_TIMER; + ql_flush_queue(ha, SC_CMDTIME); + ha->host_flags &= ~AFLG_HA_DRAIN_IO; + } + } +#endif + + +static void +ql_service_mbox_interrupt(pCHIP_INFO chip) +{ + pISP_REGS isp = (pISP_REGS)chip->ha_base; + pHA_INFO ha = NULL; + u_short channel_id; + u_short mailbox0 = 0; + int i; + + + /* Get a new copy of mailbox 0. */ + mailbox0 = QL_PCI_INH(&isp->mailbox0); + + /* check for mailbox for command completion and asynchronous + event */ + + if ( (mailbox0 >= 0x4000) && (mailbox0 <= 0x7fff)) { + chip->mailbox[7] = QL_PCI_INH(&isp->mailbox7); + chip->mailbox[6] = QL_PCI_INH(&isp->mailbox6); + chip->mailbox[5] = QL_PCI_INH(&isp->mailbox5); + chip->mailbox[4] = QL_PCI_INH(&isp->mailbox4); + chip->mailbox[3] = QL_PCI_INH(&isp->mailbox3); + chip->mailbox[2] = QL_PCI_INH(&isp->mailbox2); + chip->mailbox[1] = QL_PCI_INH(&isp->mailbox1); + chip->mailbox[0] = QL_PCI_INH(&isp->mailbox0); + + if (mailbox0 == 0x4000) + chip->chip_flags |= AFLG_CHIP_MAIL_BOX_DONE; + + if (chip->chip_flags & AFLG_CHIP_MAIL_BOX_WAITING) + vsema(&chip->mbox_done_sema); + + goto intr_done; + } + + + + + /* + * mailbox0 = 0x8000 - 0x8fff down + */ + + if (mailbox0 & 0x8000) { + + if (chip->channel_count > 1) + /* get the channel number from mailbox 6 */ + channel_id =QL_PCI_INH(&isp->mailbox6) & 0x1; + else + channel_id=0; + + /* get the ha */ + ha = (pHA_INFO) chip->ha_info[channel_id]; + } + + /* Get the response to our command. */ + switch (mailbox0) { + + case MBOX_ASTS_SYSTEM_ERROR: + ql_cpmsg(ha->ctlr_vhdl, "Unrecoverable SCSI bus state/condition (mbox1=0x%x mbox2=0x%x)\n", + QL_PCI_INH(&isp->mailbox1), QL_PCI_INH(&isp->mailbox2)); + ql_reset_interface(chip,1); + for (i = 0; ichannel_count; i++) { + ha = chip->ha_info[i]; + ql_flush_queue(ha, SC_CMDTIME); /* We want to retry these commands */ + } + break; + + case MBOX_ASTS_SCSI_BUS_RESET: + ha->host_flags |= AFLG_HA_SEND_MARKER; + ql_cpmsg(ha->ctlr_vhdl, "SCSI bus RESET seen.\n"); + break; + + case MBOX_STS_INVALID_COMMAND: + ql_cpmsg(ha->ctlr_vhdl, "Invalid mailbox command: 0x%x\n", mailbox0); + break; + + case MBOX_ASTS_EXECUTION_TIMEOUT_RESET: + ql_cpmsg(ha->ctlr_vhdl, "Execution timeout and SCSI bus reset is asserted.\n"); + break; + + case MBOX_ASTS_EXTENDED_MESSAGE_UNDERRUN: + ql_cpmsg(ha->ctlr_vhdl, "Extended message underrun and Device Reset is asserted.\n"); + break; + case MBOX_ASTS_SCAM_INTERRUPT: + ql_cpmsg(ha->ctlr_vhdl, "SCAM interrupt with completion.\n"); + break; + + case MBOX_ASTS_SCSI_BUS_HANG: + ql_cpmsg(ha->ctlr_vhdl, "SCSI bus hang due to data overrun -- SCSI bus reset needed or set Data Overrun Recovery Mode to 2.\n"); + break; + + case MBOX_ASTS_SCSI_BUS_RESET_BY_ISP: + ql_cpmsg(ha->ctlr_vhdl, "SCSI bus reset isp due to data overrun.\n"); + break; + + case MBOX_ASTS_SCSI_BUS_MODE_TRANSITION: + chip->mailbox[1] = QL_PCI_INH(&isp->mailbox1); +/* + ql_cpmsg(ha->ctlr_vhdl, "SCSI bus mode switch from :%x to %x\n", ha->bus_mode, chip->mailbox[1]); +*/ + ha->bus_mode = (chip->mailbox[1]>>10) & SCSI_BUS_MODE_MASK; + break; + + case MBOX_ASTS_REQUEST_QUEUE_WAKEUP: + /* fall thru */ + + case MBOX_ASTS_RESPONSE_TRANSFER_ERROR: + /* fall thru */ + + case MBOX_ASTS_REQUEST_TRANSFER_ERROR: + /* fall thru */ + default: + break; + } + +intr_done: + QL_PCI_OUTH(&isp->bus_sema, 0); +} + + +/* update the bus mode in inventory from the bus_mode field in ha. + assumes that ha was recently updated and is current */ +/* notes on the values: (its pretty bizarre) + the diff sense bits returned by the ql card are: + bit 12=lvd, 11=hvd, 10=se (counted from bit 0) + value saved in bus_mode, also the SCSI_BUS_MODE_ flag values + 1=se, 2=hvd, 4=lvd + value returned by ql_diffsense + 0=se (or error), 1=hvd, (2=lvd) + for inventory + 0x80=lvd, 0x40=hvd, anything else is SE +*/ +void +ql_store_bus_mode(pHA_INFO ha) +{ + + if (showconfig) + ql_cpmsg(ha->ctlr_vhdl, "SCSI Adapter %x in bus mode : %d\n", + ha->chip_info->device_id, ha->bus_mode); +} + + +/* The following code only works for single port cards (as dual port cards + overlay the port diffsense pins to the same io address). + Only 1240 and 12160 got the special mailbox command fix to check bus mode. + So 1040 and 1080 have to go check the pins... + returns 0=SE, 1=HVD, 2=lvd +*/ +static int +ql_diffsense_sp(pHA_INFO ha) +{ + pCHIP_INFO chip_info = (pCHIP_INFO)ha->chip_info; + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + int retry_cnt; + ushort tmp1; + /*REFERENCED*/ + ushort tmp2; + ushort tmp3; + int diff_sense=0; /* yes, this means default is SE */ + + + /* + * To determine DF/SE we read the value of the DIFFS bit in the + * SCSI Differential Control Pin. To do so we need to pause the RISC + * and perform a register bank switch first. + */ + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); /* Pause RISC */ + flushbus(); + for (retry_cnt = 10000; ; ) + { + DELAY(100); + if (QL_PCI_INH(&isp->hccr) & HCCR_PAUSE) + break; + if (--retry_cnt <= 0) + return(-1); + } + + tmp1 = QL_PCI_INH(&isp->bus_config1); + QL_PCI_OUTH(&isp->bus_config1, tmp1 | 0x0008); /* Perform register bank switch */ + tmp2 = QL_PCI_INH(&isp->bus_config1); + ASSERT(tmp2 & 0x0008); + + tmp3 = QL_PCI_INH(&isp->f6); + if (chip_info->device_id==QLogic_1040_DEVICE_ID) + diff_sense = ((tmp3 & 0x0200) == 0x0200); + else if (chip_info->device_id==QLogic_1080_DEVICE_ID) + diff_sense = (tmp3 & 0x1c00)>>11; /* yep, shifted the SE bit off */ + + + QL_PCI_OUTH(&isp->bus_config1, tmp1); /* Perform register bank switch */ + tmp2 = QL_PCI_INH(&isp->bus_config1); + ASSERT(tmp2 == tmp1); + + DELAY(100); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); /* Restart RISC */ + flushbus(); + DELAY(30); + + for (retry_cnt = 10000; ; ) + { + DELAY(100); + if ((QL_PCI_INH(&isp->hccr) & HCCR_PAUSE) == 0) + break; + if (--retry_cnt <= 0) + return(-1); + } + return(diff_sense); +} + + +/* this routine will update ha's bus_mode field for the current scsi + bus mode. if the card is a 1040 or 1080, we call ql_diffsense_sp. + If not, we use a mailbox command on controller's target id to decide. */ +void +ql_find_bus_mode(pHA_INFO ha) +{ + pCHIP_INFO chip_info = (pCHIP_INFO)ha->chip_info; + u_short mbox_sts[8]; + u_short bus_mode; + + if ((chip_info->device_id==QLogic_1040_DEVICE_ID) || + (chip_info->device_id==QLogic_1080_DEVICE_ID)) + { switch(ql_diffsense_sp(ha)) { + case 0: + bus_mode=SCSI_BUS_MODE_SINGLE_ENDED; + break; + case 1: + bus_mode=SCSI_BUS_MODE_HVD; + break; + case 2: + bus_mode=SCSI_BUS_MODE_LVD; + break; + default: + bus_mode=0; + break; + } + } + else + { + /* cant use ql_get_scsi_parameters as it needs to + deal with a fw difference for 12160. So directly execute + the mailbox command instead */ + if (ql_mbox_cmd(chip_info, mbox_sts, 2, 8, + MBOX_CMD_GET_TARGET_PARAMETERS, + ha->channel_id<<15|ha->ql_defaults.Initiator_SCSI_Id<<8, /* SCSI id */ + 0, 0, 0, 0, 0, 0)) + { + return; + } + + + bus_mode=(mbox_sts[7]>>10); + } + + ha->bus_mode=bus_mode; +} + +static int +ql_probe_bus(pHA_INFO ha, int max_targets, int probe_all_luns) +{ + int disks_found = 0; + int targ, lu; + vertex_hdl_t lun_vhdl; + ql_local_info_t *qli; + scsi_lun_info_t *lun_info; + scsi_target_info_t *info; + u_char *inq; + int rev; + int s; + struct scsi_target_info *ql_ret; + + ha->host_flags |= AFLG_HA_BUS_SCAN_IN_PROGRESS; + + ql_find_bus_mode(ha); + + for (targ = 0; targ < max_targets; targ++) + { + if (targ == ha->ql_defaults.Initiator_SCSI_Id) + continue; + DBG(1, "%d", targ); + if ((lun_vhdl = scsi_lun_vhdl_get(ha->ctlr_vhdl, targ, 0)) == GRAPH_VERTEX_NONE) + lun_vhdl = ql_device_add(ha->ctlr_vhdl, targ, 0, 0); + QL_UNLOCK(ha->chip_info); + ql_ret=qlinfo(lun_vhdl); + if (!ql_ret) + { + /* + * If target no longer exists, remove all the LUN vertices + * also. Make sure no one has the LUN open before removing it -- + * check ref count. + */ + for (lu = 0; lu < QL_MAXLUN; lu ++) + { + if ((lun_vhdl = scsi_lun_vhdl_get(ha->ctlr_vhdl, targ, lu)) != GRAPH_VERTEX_NONE) + { + qli = SLI_INFO(scsi_lun_info_get(lun_vhdl)); + SCSI_HWG_UPDATE(); /* dont hold chip lock while trying to acquire this */ + QL_SPLOCK(qli->qli_lock, s); + if (qli->qli_ref_count == 0) + { QL_SPUNLOCK(qli->qli_lock, s); + ql_device_remove(ha->ctlr_vhdl, targ, lu); + } + else + QL_SPUNLOCK(qli->qli_lock, s); + SCSI_HWG_UNUPDATE(); + } + } + DBG(1, "- "); + } + else + { + /* the above qlinfo got the target's scsi rev info and put it into + si_inq. we need to dig up the ansi rev field so we know how to + set the lun bits on the next inq's */ + lun_info=scsi_lun_info_get(lun_vhdl); + info=TINFO(lun_info); + inq=info->si_inq; + rev= *(inq+2) & 0x07; /* fetch the scsi rev field from the inq data */ + disks_found++; + DBG(1, "+ "); + if (probe_all_luns) + { + for( lu=1; lu < QL_MAXLUN; lu ++) + { + if ((lun_vhdl = scsi_lun_vhdl_get(ha->ctlr_vhdl, targ, lu)) == GRAPH_VERTEX_NONE) + { + QL_LOCK(ha->chip_info); + lun_vhdl = ql_device_add(ha->ctlr_vhdl, targ, lu, rev); + QL_UNLOCK(ha->chip_info); + } + ql_ret=qlinfo(lun_vhdl); + if (!ql_ret) + { + qli = SLI_INFO(scsi_lun_info_get(lun_vhdl)); + SCSI_HWG_UPDATE(); + QL_SPLOCK(qli->qli_lock, s); + if (qli->qli_ref_count == 0) + { QL_SPUNLOCK(qli->qli_lock, s); + ql_device_remove(ha->ctlr_vhdl, targ, lu); + } + else + QL_SPUNLOCK(qli->qli_lock, s); + SCSI_HWG_UNUPDATE(); + } + } + } + } + QL_LOCK(ha->chip_info); + } + ha->host_flags &= ~AFLG_HA_BUS_SCAN_IN_PROGRESS; + ql_store_bus_mode(ha); + QL_UNLOCK(ha->chip_info); + xscsi_notify(); + QL_LOCK(ha->chip_info); + return(disks_found); +} + +static void +ql_ppmsg(pCHIP_INFO chip_info, char *fmt, ...) +{ + va_list ap; + cmn_err(CE_CONT, "%s: ", chip_info->chip_name); + va_start(ap, fmt); + icmn_err(CE_CONT, fmt, ap); + va_end(ap); +} + +static void +ql_cpmsg(vertex_hdl_t ctlr_vhdl, char *fmt, ...) +{ + va_list ap; + pHA_INFO ha; + + { + ha = ql_ha_info_from_ctlr_get(ctlr_vhdl); + cmn_err(CE_CONT, "%s: ", ha->ha_name); + } + va_start(ap, fmt); + icmn_err(CE_CONT, fmt, ap); + va_end(ap); +} + +static void +ql_tpmsg(vertex_hdl_t ctlr_vhdl, u_char target, char *fmt, ...) +{ + va_list ap; + pHA_INFO ha; + + { + ha = ql_ha_info_from_ctlr_get(ctlr_vhdl); + cmn_err(CE_CONT, "%s/%s%d: ", ha->ha_name, EDGE_LBL_TARGET, target); + } + va_start(ap, fmt); + icmn_err(CE_CONT, fmt, ap); + va_end(ap); +} + +static void +ql_lpmsg(vertex_hdl_t ctlr_vhdl, u_char target, u_char lun, char *fmt, ...) +{ + va_list ap; + pHA_INFO ha; + + { + ha = ql_ha_info_from_ctlr_get(ctlr_vhdl); + cmn_err(CE_CONT, "%s/%s%d/%s%d: ", ha->ha_name, EDGE_LBL_TARGET, target, EDGE_LBL_LUN, lun); + } + va_start(ap, fmt); + icmn_err(CE_CONT, fmt, ap); + va_end(ap); +} + +static void +DBG(int level, char *format, ...) +{ + va_list ap; + char tempstr[200]; + + if (ql_debug >= level) + { + va_start(ap, format); + vsprintf(tempstr, format, ap); + printf(tempstr); + va_end(ap); + } +} + +static char * +ql_completion_status_msg(uint completion_status) +{ + struct { + int code; + char *msg; + } ql_comp_msg[] = { + { SCS_COMPLETE, "SCS_COMPLETE" }, + { SCS_INCOMPLETE, "SCS_INCOMPLETE" }, + { SCS_DMA_ERROR, "SCS_DMA_ERROR" }, + { SCS_TRANSPORT_ERROR, "SCS_TRANSPORT_ERROR" }, + { SCS_RESET_OCCURRED, "SCS_RESET_OCCURRED" }, + { SCS_ABORTED, "SCS_ABORTED" }, + { SCS_TIMEOUT, "SCS_TIMEOUT" }, + { SCS_DATA_OVERRUN, "SCS_DATA_OVERRUN" }, + { SCS_COMMAND_OVERRUN, "SCS_COMMAND_OVERRUN" }, + { SCS_ABORT_MSG_FAILED, "SCS_ABORT_MSG_FAILED" }, + { SCS_DEVICE_RESET_MSG_FAILED, "SCS_DEVICE_RESET_MSG_FAILED" }, + { SCS_UNEXPECTED_BUS_FREE, "SCS_UNEXPECTED_BUS_FREE" }, + { SCS_DATA_UNDERRUN, "SCS_DATA_UNDERRUN" }, + { SCS_CMD_UNDERRUN, "SCS_CMD_UNDERRUN" }, + { SCS_SCSI_PHASE_SKIPPED, "SCS_SCSI_PHASE_SKIPPED" }, + { SCS_AUTO_SENSE_FAILED, "SCS_AUTO_SENSE_FAILED" }, + { SCS_WIDE_DATA_XFER_FAILED, "SCS_WIDE_DATA_XFER_FAILED" }, + { SCS_SYNC_DATA_XFER_FAILED, "SCS_SYNC_DATA_XFER_FAILED" }, + { SCS_LVD_BUS_ERROR, "SCS_LVD_BUS_ERROR" }, + { SCS_DATA_CRC, "SCS_DATA_CRC" }, + { -1, "Unknown" } + }; + int i; + + for (i = 0; ql_comp_msg[i].code != -1; ++i) + if (completion_status == ql_comp_msg[i].code) + return(ql_comp_msg[i].msg); + return(ql_comp_msg[i].msg); +} + +static void +ql_sensepr(vertex_hdl_t ctlr_vhdl, int unit, int lun, u_char *sptr, int length) +{ + int key = *(sptr + 2); + + ql_lpmsg(ctlr_vhdl, unit, lun, "check condition: "); + if (key & 0x80) + cmn_err(CE_CONT, "FMK "); + if (key & 0x40) + cmn_err(CE_CONT, "EOM "); + if (key & 0x20) + cmn_err(CE_CONT, "ILI "); + + cmn_err(CE_CONT, "sense key 0x%x (%s) ", + key & 0xF, scsi_key_msgtab[key & 0xF]); + + if (length > 12) { + int asc = *(sptr + 12); + + cmn_err(CE_CONT, "asc 0x%x", asc); + + if (asc < SC_NUMADDSENSE && scsi_addit_msgtab[asc] != NULL) + cmn_err(CE_CONT, " (%s)", scsi_addit_msgtab[asc]); + } + + if (length > 13) cmn_err(CE_CONT, " asq 0x%x\n", *(sptr+13)); + +} + +#ifdef DEBUG + +/* +** Dump the registers for this ISP. +*/ +/* ARGSUSED */ +/* REFERENCED */ +static void +dump_registers(pCHIP_INFO chip_info, pISP_REGS isp) +{ + u_short bus_id_low, bus_id_high, bus_config0, bus_config1; + u_short bus_icr = 0; + u_short bus_isr = 0; + u_short bus_sema; + u_short hccr = 0; + u_short risc_pc; + u_short mbox0, mbox1, mbox2, mbox3, mbox4, mbox5, mbox6, mbox7; + + u_short accumulator; + u_short r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; + u_short ivr; + u_short psr; + u_short rar0, rar1; + u_short pcr; + u_short lcr; + u_short mtr; + u_short sp; + u_short mctr; + u_short lvdi; + u_short hardware_revision; + + u_short control_dma_control; + u_short control_dma_config; + u_short control_dma_fifo_status; + u_short control_dma_status; + u_short control_dma_counter; + u_short control_dma_address_counter_1; + u_short control_dma_address_counter_0; + u_short control_dma_address_counter_3; + u_short control_dma_address_counter_2; + + + u_short data_dma_control; + u_short data_dma_config; + u_short data_dma_fifo_status; + u_short data_dma_status; + u_short data_dma_xfer_counter_high; + u_short data_dma_xfer_counter_low; + u_short data_dma_address_counter_1; + u_short data_dma_address_counter_0; + u_short data_dma_address_counter_3; + u_short data_dma_address_counter_2; + + + /* Get copies of the registers. */ + mbox0 = QL_PCI_INH(&isp->mailbox0); + mbox1 = QL_PCI_INH(&isp->mailbox1); + mbox2 = QL_PCI_INH(&isp->mailbox2); + mbox3 = QL_PCI_INH(&isp->mailbox3); + mbox4 = QL_PCI_INH(&isp->mailbox4); + mbox5 = QL_PCI_INH(&isp->mailbox5); + mbox6 = QL_PCI_INH(&isp->mailbox6); + mbox7 = QL_PCI_INH(&isp->mailbox7); + + bus_id_low = QL_PCI_INH(&isp->bus_id_low); + bus_id_high = QL_PCI_INH(&isp->bus_id_high); + bus_config0 = QL_PCI_INH(&isp->bus_config0); + bus_config1 = QL_PCI_INH(&isp->bus_config1); + bus_icr = QL_PCI_INH(&isp->bus_icr); + bus_isr = QL_PCI_INH(&isp->bus_isr); + bus_sema = QL_PCI_INH(&isp->bus_sema); + hccr = QL_PCI_INH(&isp->hccr); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); + if (chip_info->device_id==QLogic_1040_DEVICE_ID) { + control_dma_control = QL_PCI_INH(&isp->control_dma_control); + control_dma_config = QL_PCI_INH(&isp->control_dma_config); + control_dma_fifo_status = QL_PCI_INH(&isp->control_dma_fifo_status); + control_dma_status = QL_PCI_INH(&isp->control_dma_status); + control_dma_counter = QL_PCI_INH(&isp->control_dma_counter); + control_dma_address_counter_1 = QL_PCI_INH(&isp->control_dma_address_counter_1); + control_dma_address_counter_0 = QL_PCI_INH(&isp->control_dma_address_counter_0); + control_dma_address_counter_3 = QL_PCI_INH(&isp->control_dma_address_counter_3); + control_dma_address_counter_2 = QL_PCI_INH(&isp->control_dma_address_counter_2); + + + data_dma_config = QL_PCI_INH(&isp->data_dma_config); + data_dma_fifo_status = QL_PCI_INH(&isp->data_dma_fifo_status); + data_dma_status = QL_PCI_INH(&isp->data_dma_status); + data_dma_control = QL_PCI_INH(&isp->data_dma_control); + data_dma_xfer_counter_high = QL_PCI_INH(&isp->data_dma_xfer_counter_high); + data_dma_xfer_counter_low = QL_PCI_INH(&isp->data_dma_xfer_counter_low); + data_dma_address_counter_1 = QL_PCI_INH(&isp->data_dma_address_counter_1); + data_dma_address_counter_0 = QL_PCI_INH(&isp->data_dma_address_counter_0); + data_dma_address_counter_3 = QL_PCI_INH(&isp->data_dma_address_counter_3); + data_dma_address_counter_2 = QL_PCI_INH(&isp->data_dma_address_counter_1); + mtr = QL_PCI_INH(&isp->mtr); + } + else + { mctr = QL_PCI_INH(&isp->mctr); + lvdi = QL_PCI_INH(&isp->lvdi); + } + + + accumulator = QL_PCI_INH(&isp->accumulator); + r1 = QL_PCI_INH(&isp->r1); + r2 = QL_PCI_INH(&isp->r2); + r3 = QL_PCI_INH(&isp->r3); + r4 = QL_PCI_INH(&isp->r4); + r5 = QL_PCI_INH(&isp->r5); + r6 = QL_PCI_INH(&isp->r6); + r7 = QL_PCI_INH(&isp->r7); + r8 = QL_PCI_INH(&isp->r8); + r9 = QL_PCI_INH(&isp->r9); + r10 = QL_PCI_INH(&isp->r10); + r11 = QL_PCI_INH(&isp->r11); + r12 = QL_PCI_INH(&isp->r12); + r13 = QL_PCI_INH(&isp->r13); + r14 = QL_PCI_INH(&isp->r14); + r15 = QL_PCI_INH(&isp->r15); + ivr = QL_PCI_INH(&isp->ivr); + psr = QL_PCI_INH(&isp->psr); + rar0 = QL_PCI_INH(&isp->rar0); + rar1 = QL_PCI_INH(&isp->rar1); + pcr = QL_PCI_INH(&isp->pcr); + lcr = QL_PCI_INH(&isp->lcr); + risc_pc = QL_PCI_INH(&isp->risc_pc); + sp = QL_PCI_INH(&isp->sp); + hardware_revision = QL_PCI_INH(&isp->hardware_revision); + + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + + printf("\ndump_regs: mbox0 = %x, mbox1 = %x\n", mbox0, mbox1); + printf("dump_regs: mbox2 = %x, mbox3 = %x\n", mbox2, mbox3); + printf("dump_regs: mbox4 = %x, mbox5 = %x\n", mbox4, mbox5); + printf("dump_regs: mbox6 = %x, mbox7 = %x\n", mbox6, mbox7); + printf("dump_regs: BUS_ICR=%x, BUS_ISR=%x, BUS_SEMA=%x\n", + bus_icr, bus_isr, bus_sema); + printf("dump_regs: BUS_ID_LOW=%x, BUS_ID_HIGH=%x\n", + bus_id_low, bus_id_high); + printf("dump_regs: BUS_CONFIG0=%x, BUS_CONFIG1=%x\n", + bus_config0, bus_config1); + printf("dump_regs: HCCR=%x: %x \n", &isp->hccr, hccr); + printf("risc PC : %x\n", risc_pc); + + + printf("\n"); + if (chip_info->device_id==QLogic_1040_DEVICE_ID) { + printf("dump_regs: control_dma_control %x: %x\n", + &isp->control_dma_control, control_dma_control); + printf("dump_regs: control_dma_config %x: %x\n", + &isp->control_dma_config, control_dma_config); + printf("dump_regs: control_dma_fifo_status %x: %x\n", + &isp->control_dma_fifo_status, control_dma_fifo_status); + printf("dump_regs: control_dma_status %x: %x\n", + &isp->control_dma_status, control_dma_status); + printf("dump_regs: control_dma_counter %x: %x\n", + &isp->control_dma_counter, control_dma_counter); + printf("dump_regs: control_dma_address_counter_1 %x: %x\n", + &isp->control_dma_address_counter_1, control_dma_address_counter_1); + printf("dump_regs: control_dma_address_counter_0 %x: %x\n", + &isp->control_dma_address_counter_0, control_dma_address_counter_0); + printf("dump_regs: control_dma_address_counter_3 %x: %x\n", + &isp->control_dma_address_counter_3, control_dma_address_counter_3); + printf("dump_regs: control_dma_address_counter_0 %x: %x\n", + &isp->control_dma_address_counter_2, control_dma_address_counter_2); + printf("dump_regs: data_dma_config %x: %x\n", + &isp->data_dma_config, data_dma_config); + + printf("dump_regs: data_dma_status %x: %x\n", + &isp->data_dma_status, data_dma_status); + printf("dump_regs: data_dma_fifo_status %x: %x\n", + &isp->data_dma_fifo_status, data_dma_fifo_status); + printf("dump_regs: data_dma_control %x: %x\n", + &isp->data_dma_control, data_dma_control); + printf("dump_regs: data_dma_xfer_counter_high %x: %x\n", + &isp->data_dma_xfer_counter_high, data_dma_xfer_counter_high); + printf("dump_regs: data_dma_xfer_counter_low %x: %x\n", + &isp->data_dma_xfer_counter_low, data_dma_xfer_counter_low); + printf("dump_regs: data_dma_address_counter_1 %x: %x\n", + &isp->data_dma_address_counter_1, + data_dma_address_counter_1); + printf("dump_regs: data_dma_address_counter_0 %x: %x\n", + &isp->data_dma_address_counter_0, + data_dma_address_counter_0); + printf("dump_regs: data_dma_address_counter_3 %x: %x\n", + &isp->data_dma_address_counter_3, + data_dma_address_counter_3); + printf("dump_regs: data_dma_address_counter_2 %x: %x\n", + &isp->data_dma_address_counter_2, + data_dma_address_counter_2); + printf("\n"); + printf("dump_regs: mtr %x\n", mtr); + printf("dump_regs: emb %x\n", mctr); /* note mctr is emb on 1040 */ + } + else + { printf("dump_regs: mctr %x\n", mctr); + printf("dump_regs: lvdi %x\n", lvdi ); + } + + + printf("dump_regs: accumulator %x\n", accumulator ); + printf("dump_regs: r1 %x\n", r1 ); + printf("dump_regs: r2 %x\n", r2); + printf("dump_regs: r3 %x\n", r3 ); + printf("dump_regs: r4 %x\n", r4); + printf("dump_regs: r5 %x\n", r5 ); + printf("dump_regs: r6 %x\n", r6 ); + printf("dump_regs: r7 %x\n", r7); + printf("dump_regs: r8 %x\n", r8 ); + printf("dump_regs: r9 %x\n", r9 ); + printf("dump_regs: r10 %x\n", r10 ); + printf("dump_regs: r11 %x\n", r11 ); + printf("dump_regs: r12 %x\n", r12); + printf("dump_regs: r13 %x\n", r13 ); + printf("dump_regs: r14 %x\n", r14 ); + printf("dump_regs: r15 %x\n", r15 ); + printf("dump_regs: ivr %x\n", ivr ); + printf("dump_regs: psr %x\n", psr ); + printf("dump_regs: rar0 %x\n", rar0 ); + printf("dump_regs: rar1 %x\n", rar1 ); + printf("dump_regs: pcr %x\n", pcr ); + printf("dump_regs: lcr %x\n", lcr); + printf("dump_regs: sp %x\n", sp ); + printf("dump_regs: hardware_revision %x\n", hardware_revision ); +} + + +/* +** Dump FIRMWARE parameters. +*/ +/* REFERENCED */ +static void +dump_parameters(vertex_hdl_t ql_ctlr_vhdl) +{ + pHA_INFO ha = ql_ha_info_from_ctlr_get(ql_ctlr_vhdl); + u_short mbox_sts[8]; + + + if (ql_get_firmware_status(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_FIRMWARE_STATUS Command Failed"); + } else + { + printf("ql_dump_parameters - GET_FIRMWARE_STATUS\n"); + printf(" %x, %x, %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], mbox_sts[3], + mbox_sts[4], mbox_sts[5], mbox_sts[6], mbox_sts[7]); + } + + if (ql_get_scsi_id(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_INITIATOR_SCSI_ID Command Failed"); + } else + { + printf("ql_dump_parameters - GET_INITIATOR_SCSI_ID\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_selection_timeout(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_SELECTION_TIMEOUT Command Failed"); + } else + { + printf("ql_dump_parameters - GET_SELECTION_TIMEOUT\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_retry_count(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_RETRY_COUNT Command Failed"); + } else + { + printf("ql_dump_parameters - GET_RETRY_COUNT\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_tag_age_limit(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_TAG_AGE_LIMIT Command Failed"); + } else + { + printf("ql_dump_parameters - GET_TAG_AGE_LIMIT\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_clock_rate(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_CLOCK_RATE Command Failed"); + } else + { + printf("ql_dump_parameters - GET_CLOCK_RATE\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_negation_state(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_ACTIVE_NEGATION_STATE Command Failed"); + } else + { + printf("ql_dump_parameters - GET_ACTIVE_NEGATION_STATE\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_asynchronous_data_setup_time(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_ASYNC_DATA_SETUP_TIME Command Failed"); + } else + { + printf("ql_dump_parameters - GET_ASYNC_DATA_SETUP_TIME\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_pci_control_parameters(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_BUS_CONTROL_PARAMETERS Command Failed"); + } else + { + printf("ql_dump_parameters - GET_BUS_CONTROL_PARAMETERS\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_scsi_parameters(ha->chip_info, mbox_sts, (u_short)0, (ushort)0)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_TARGET_PARAMETERS Command Failed"); + } else + { + printf("ql_dump_parameters - GET_TARGET_PARAMETERS\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_device_queue_parameters(ha->chip_info, mbox_sts, (u_short)0, (u_short)0, (u_short)0)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_DEVICE_QUEUE_PARAMETERS Command Failed"); + } else + { + printf("ql_dump_parameters - GET_DEVICE_QUEUE_PARAMETERS\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_reset_delay_parameters(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_RESET_DELAY_PARAMETERS Command Failed"); + } else + { + printf("ql_dump_parameters - GET_RESET_DELAY_PARAMETERS\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_system_parameters(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_SYSTEM_PARAMETERS Command Failed"); + } else + { + printf("ql_dump_parameters - GET_SYSTEM_PARAMETERS\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_firmware_features(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_FIRMWARE_FEATURES Command Failed"); + } else + { + printf("ql_dump_parameters - GET_FIRMWARE_FEATURES\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + + if (ql_get_data_over_recovery_mode(ha->chip_info, mbox_sts)) + { + cmn_err(CE_WARN, + "ql_dump_parameters - GET_DATA_RECOVERY_MODE Command Failed"); + } else + { + printf("ql_dump_parameters - GET_DATA_RECOVERY_MODE\n"); + printf(" %x, %x, %x, %x, %x, %x\n", + mbox_sts[0], mbox_sts[1], mbox_sts[2], + mbox_sts[3], mbox_sts[4], mbox_sts[5]); + } + +} + + +static void +dump_iocb(command_entry *q_ptr) +{ + int i; + char *ptr; + + ptr = (char *) q_ptr; + printf("RAW data: "); + for (i = 0; i <= 64; i++) + printf(" %x", *ptr++); + printf("\n"); + + + printf("------------- IOCB ------------- %x\n", q_ptr); + printf("\n"); + printf("Entry Count\t:\t%x\n", q_ptr->hdr.entry_cnt); + printf("Entry Type\t:\t%x\n", q_ptr->hdr.entry_type); + printf("Flags\t\t: \t%x\n", q_ptr->hdr.flags); + printf("System Defined\t:\t%x\n", q_ptr->hdr.sys_def_1); + printf("Handle\t\t:\t%x\n", q_ptr->handle); + printf("Channel\t\t:\t%x\n", q_ptr->channel_id); + printf("Target ID\t:\t%x\n", q_ptr->target_id); + printf("LUN\t\t:\t%x\n", q_ptr->target_lun); + printf("CDB Length\t:\t%x\n", q_ptr->cdb_length); + printf("Control Flags\t:\t%x\n", q_ptr->control_flags); + printf("Timeout\t\t:\t%x\n", q_ptr->time_out); + printf("Data Seg Count\t:\t%x\n", q_ptr->segment_cnt); + switch (q_ptr->cdb_length) { + case SC_CLASS0_SZ: + printf("CDB\t:\t%x %x %x %x %x %x\n", q_ptr->cdb0, q_ptr->cdb1, q_ptr->cdb2, q_ptr->cdb3, + q_ptr->cdb4, q_ptr->cdb5); + break; + + case SC_CLASS2_SZ: + printf("CDB\t:\t%x %x %x %x %x %x %x %x\n", q_ptr->cdb0, q_ptr->cdb1, q_ptr->cdb2, q_ptr->cdb3, + q_ptr->cdb4, q_ptr->cdb5, q_ptr->cdb6, q_ptr->cdb7); + break; + case SC_CLASS1_SZ: + printf("CDB\t:\t%x %x %x %x %x %x %x %x %x %x %x %x\n", q_ptr->cdb0, q_ptr->cdb1, q_ptr->cdb2, + q_ptr->cdb3, q_ptr->cdb4, q_ptr->cdb5, q_ptr->cdb6, q_ptr->cdb7, q_ptr->cdb8, q_ptr->cdb9, + q_ptr->cdb10, q_ptr->cdb11); + break; + } + + for (i = 0; i < IOCB_SEGS; i++) { + printf("Data Segment %d: Address hi %08x low %08x\tCount %x\n", i+1, + q_ptr->dseg[i].base_high_32, q_ptr->dseg[i].base_low_32, + q_ptr->dseg[i].count); + } +} + + +static void +dump_iorb(status_entry *q_ptr) +{ + int i; + char *ptr; + + ptr = (char *) q_ptr; + printf("RAW data: "); + for (i = 0; i <= 64; i++) + printf(" %x", *ptr++); + printf("\n"); + + printf("------------- IORB ------------- %x\n", q_ptr); + printf("Entry Count\t:\t%x\n", q_ptr->hdr.entry_cnt); + printf("Entry Type\t:\t%x\n", q_ptr->hdr.entry_type); + printf("Flags\t\t:\t%x\n", q_ptr->hdr.flags); + printf("System Defined\t:\t%x\n", q_ptr->hdr.sys_def_1); + printf("Handle\t\t:\t%x\n", q_ptr->handle); + printf("Scsi Status\t:\t%x\n", q_ptr->scsi_status); + printf("Comp. Status\t:\t%x\n", q_ptr->completion_status); + printf("State Flags\t:\t%x\n", q_ptr->state_flags); + printf("Status Flags\t:\t%x\n", q_ptr->status_flags); + printf("Time\t\t:\t%x\n", q_ptr->time); + printf("Sense Length\t:\t%x\n", q_ptr->req_sense_length); + printf("Timeout\t\t:\t%x\n", q_ptr->time); + printf("Residual\t:\t%x\n", q_ptr->residual); + printf("Request Sense : %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", q_ptr->req_sense_data[3], + q_ptr->req_sense_data[2], q_ptr->req_sense_data[1], q_ptr->req_sense_data[0], q_ptr->req_sense_data[7], + q_ptr->req_sense_data[6], q_ptr->req_sense_data[5], q_ptr->req_sense_data[4], q_ptr->req_sense_data[11], + q_ptr->req_sense_data[10], q_ptr->req_sense_data[9], q_ptr->req_sense_data[8], q_ptr->req_sense_data[15], + q_ptr->req_sense_data[14], q_ptr->req_sense_data[13], q_ptr->req_sense_data[12]); + printf("Request Sense : %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", q_ptr->req_sense_data[19], + q_ptr->req_sense_data[18], q_ptr->req_sense_data[17], q_ptr->req_sense_data[16], q_ptr->req_sense_data[23], + q_ptr->req_sense_data[22], q_ptr->req_sense_data[21], q_ptr->req_sense_data[20], q_ptr->req_sense_data[27], + q_ptr->req_sense_data[26], q_ptr->req_sense_data[25], q_ptr->req_sense_data[24], q_ptr->req_sense_data[31], + q_ptr->req_sense_data[30], q_ptr->req_sense_data[29], q_ptr->req_sense_data[28]); +} + + +static void +dump_continuation(continuation_entry *q_ptr) +{ + int i; + char *ptr; + + ptr = (char *) q_ptr; + printf("RAW data: "); + for (i = 0; i <= 64; i++) + printf(" %x", *ptr++); + printf("\n"); + + printf("------------- CONTINUATION ------------- %x\n", q_ptr); + printf("Entry Count\t:\t%x\n", q_ptr->hdr.entry_cnt); + printf("Entry Type\t:\t%x\n", q_ptr->hdr.entry_type); + printf("Flags\t\t:\t%x\n", q_ptr->hdr.flags); + printf("System Defined\t:\t%x\n", q_ptr->hdr.sys_def_1); + + for (i = 0; i < CONTINUATION_SEGS; i++) { + printf("Data Segment %d: Address hi %08x low %08x\tCount %x\n", i+1, + q_ptr->dseg[i].base_high_32, q_ptr->dseg[i].base_low_32, + q_ptr->dseg[i].count); + } +} + + +static void +dump_marker(marker_entry *q_ptr) +{ + printf("\n------------- MARKER ------------- %x\n", q_ptr); + printf("Entry Count\t:\t%x\n", q_ptr->hdr.entry_cnt); + printf("Entry Type\t:\t%x\n", q_ptr->hdr.entry_type); + printf("Flags\t\t:\t%x\n", q_ptr->hdr.flags); + printf("System Defined\t:\t%x\n", q_ptr->hdr.sys_def_1); + printf("reserved0\t:\t%x\n", q_ptr->reserved0); + printf("Channel Id\t:\t%x\n", q_ptr->channel_id); + printf("Target\t\t:\t%x\n", q_ptr->target_id); + printf("Lun\t\t:\t%x\n", q_ptr->target_lun); + printf("Modifier\t:\t%x\n", q_ptr->modifier); +} + + +struct cmd_dma { + u_short cdma_control; + u_short cdma_config; + u_short cdma_fifo_status; + u_short cdma_status; + u_short cdma_reserved; + u_short cdma_counter; + u_short cdma_addr_1; + u_short cdma_addr_0; + u_short cdma_addr_3; + u_short cdma_addr_2; +}; +typedef struct cmd_dma cmd_dma_t; + + +/* REFERENCED */ +static void +dump_cmd_dma(pHA_INFO ha) +{ + pISP_REGS isp = (pISP_REGS)ha->chip_info->ha_base; + cmd_dma_t *cdp = (cmd_dma_t *)((__psint_t)isp + 0x20); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); + printf("cmd dma control %04x, config %04x, status %04x, counter %04x\n", + QL_PCI_INH(&cdp->cdma_control), QL_PCI_INH(&cdp->cdma_config), + QL_PCI_INH(&cdp->cdma_status), QL_PCI_INH(&cdp->cdma_counter)); + printf(" counter 3 %04x, 2 %04x, 1 %04x, 0 %04x\n", + QL_PCI_INH(&cdp->cdma_addr_3), QL_PCI_INH(&cdp->cdma_addr_2), + QL_PCI_INH(&cdp->cdma_addr_2), QL_PCI_INH(&cdp->cdma_addr_0)); + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); +} +#endif /* DEBUG */ + + +#ifdef DUMP_12160 +/* board info dump per qlogic's 12160 debug dump procedure */ +void +dump_12160(pCHIP_INFO chip_info) +{ + pISP_REGS isp = (pISP_REGS)chip_info->ha_base; + int retry_cnt, i; + volatile u_short *addr; + volatile u_short regs; + u_int ram_addr; + u_short mbox_sts[8]; + int port, target; + + + chip_info->chip_flags |= AFLG_CHIP_DUMPING; + QL_MUTEX_ENTER(chip_info); + for (port=0; port<2; port++) + { + for (target=0; target<16; target++) + { + ql_mbox_cmd(chip_info, mbox_sts, 2, 4, + MBOX_CMD_GET_DEVICE_QUEUE_PARAMETERS, + port<<15|target<<8, + 0, 0, 0, 0, 0, 0); + qprintf( + "port %d target %d queue depth 0x%x execution throttle 0x%x\n", + port, target, mbox_sts[2], mbox_sts[3]); + ql_mbox_cmd(chip_info, mbox_sts, 2, 4, + 0x1d, + port<<15|target<<8, + 0, 0, 0, 0, 0, 0); + qprintf(" state %x exec count %x total count %x\n", + mbox_sts[1], mbox_sts[2], mbox_sts[3]); + } + } + QL_MUTEX_EXIT(chip_info); + + chip_info->chip_flags |= AFLG_CHIP_DUMPING; + + qprintf("\nISP Debug Dump\n"); + ram_addr=0x1000; + QL_MUTEX_ENTER(chip_info); + while (ram_addr<=0xffff) + { + if ((ram_addr & 0x7) ==0) + qprintf("%x: ", ram_addr); + ql_mbox_cmd(chip_info, mbox_sts, 2, 3, + MBOX_CMD_READ_RAM_WORD, + ram_addr, + 0, 0, 0, 0, 0, 0); + qprintf("%x ", mbox_sts[2]); + if ((ram_addr & 0x7)==7) + qprintf("\n"); + ram_addr++; + } + QL_MUTEX_EXIT(chip_info); + qprintf("End\n"); + + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); + flushbus(); + for (retry_cnt = 10000; retry_cnt>0; retry_cnt--) { + DELAY(100); + if (QL_PCI_INH(&isp->hccr) & HCCR_PAUSE) + break; + } + + + qprintf("the following register dumps are big endian\n"); + + addr= (u_short *)&isp->bus_id_high; /* pci offset 0 */ + qprintf("\nPBIU registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + addr= (u_short *)&isp->mailbox1; + qprintf("Mailbox registers\n"); + for (i=0; i<8; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->bus_config1, 0x300); + addr= (u_short *)&isp->r1; + qprintf("DMA registers\n"); + for (i=0; i<48; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->bus_config1, 0); + addr= (u_short *)&isp->r1; + qprintf("RISC hardware registers\n"); + for (i=0; i<32; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2000); + addr= (u_short *)&isp->r1; + qprintf("RISC GP0 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2200); + addr= (u_short *)&isp->r1; + qprintf("RISC GP1 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2400); + addr= (u_short *)&isp->r1; + qprintf("RISC GP2 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2600); + addr= (u_short *)&isp->r1; + qprintf("RISC GP3 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2800); + addr= (u_short *)&isp->r1; + qprintf("RISC GP4 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2a00); + addr= (u_short *)&isp->r1; + qprintf("RISC GP5 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2c00); + addr= (u_short *)&isp->r1; + qprintf("RISC GP6 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->pcr, 0x2e00); + addr= (u_short *)&isp->r1; + qprintf("RISC GP7 registers\n"); + for (i=0; i<16; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->bus_config1, 0x200); + addr= (u_short *)&isp->r1; + qprintf("SXP1 registers\n"); + for (i=0; i<64; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->bus_config1, 0x100); + addr= (u_short *)&isp->r1; + qprintf("SXP2 registers\n"); + for (i=0; i<64; i++) + { + regs=QL_PCI_INH(addr); + if ((i & 0x7) ==0) + qprintf("%x: ", addr); + qprintf("%x ", regs); + if ((i & 0x7)==7) + qprintf("\n"); + addr++; + } + qprintf("\n"); + + + QL_PCI_OUTH(&isp->bus_icr, ICR_SOFT_RESET); + flushbus(); + DELAY(30); + + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RESET); + QL_PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + flushbus(); + DELAY(30); + + for (retry_cnt = 10000; retry_cnt>0; retry_cnt--) { + DELAY(100); + if (!(QL_PCI_INH(&isp->hccr) & HCCR_RESET)) + break; + } + + /* executing mailbox cmds here doesnt work since the card isnt running */ +} +#endif + + + + + +/* + * Qlogic mailbox command functions + * ql_set_scsi_id + * ql_set_selection_timeout + * ql_set_retry_count + * ql_set_tag_age_limit + * ql_set_clock_rate + * ql_set_negation_state + * ql_set_asynchronous_data_setup_time + * ql_set_pci_control_parameters + * ql_set_scsi_parameters + * ql_set_device_queue_parameters + * ql_set_reset_delay_parameters + * ql_set_system_parameters + * ql_set_firmware_features + * + */ + + +/* Set Bus Reset */ +static int +ql_set_bus_reset(pCHIP_INFO chip, u_short *mbox_sts, u_short channel_id) +{ + + pHA_INFO ha; + + ha = chip->ha_info[channel_id]; + + if ( ql_mbox_cmd(chip, mbox_sts, 3, 3, + MBOX_CMD_BUS_RESET, + ha->ql_defaults.Bus_Reset_Delay, + channel_id, + 0, 0, 0, 0, 0)) { + return (1); + } + return (0); +} + + +/* Set SCSI Id */ +static int +ql_set_scsi_id(pCHIP_INFO chip, u_short *mbox_sts) +{ + pHA_INFO ha; + int i; + + /* Set Initiator SCSI ID. */ + for (i = 0; i < chip->channel_count; ++i) { + ha = chip->ha_info[i]; + if (ql_mbox_cmd(chip, mbox_sts, 2, 2, + MBOX_CMD_SET_INITIATOR_SCSI_ID, + (ha->channel_id << 7) | ha->ql_defaults.Initiator_SCSI_Id, + 0,0,0,0,0,0)) + return (1); + } + return(0); +} + +/* Set Selection Timeout */ +static int +ql_set_selection_timeout(pCHIP_INFO chip, u_short *mbox_sts) +{ + int i; + pHA_INFO ha; + u_short port[2]; + + + for (i=0; ichannel_count; i++) { + ha = (pHA_INFO)chip->ha_info[i]; + port[i] = ha->ql_defaults.Selection_Timeout; + } + + if (ql_mbox_cmd(chip, mbox_sts, 3, 3, + MBOX_CMD_SET_SELECTION_TIMEOUT, + (u_short)port[0], + (u_short)port[1], + 0,0,0,0,0)) + return(1); + + return(0); + +} + +/* Set Retry Count */ +static int +ql_set_retry_count(pCHIP_INFO chip, u_short *mbox_sts) +{ + u_short mboxin, mboxout; + + if (chip->channel_count > 1) + mboxin = mboxout = 8; + else + mboxin = mboxout = 3; + + if (ql_mbox_cmd(chip, mbox_sts, mboxin, mboxout, + MBOX_CMD_SET_RETRY_COUNT, + chip->Retry_Count, + chip->Retry_Delay, + 0,0,0, + chip->Retry_Count, + chip->Retry_Delay)) + return(1); + + return(0); + +} + +/* Set Tag Age Limit */ +static int +ql_set_tag_age_limit(pCHIP_INFO chip, u_short *mbox_sts) +{ + + /* Set Tag Age Limits. */ + if (ql_mbox_cmd(chip, mbox_sts, 3, 3, + MBOX_CMD_SET_TAG_AGE_LIMIT, + TAG_AGE_LIMIT, + TAG_AGE_LIMIT, + 0,0,0,0,0)) + return (1); + + return (0); +} + +/* Set Clock Rate */ +static int +ql_set_clock_rate(pCHIP_INFO chip, u_short *mbox_sts) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 2, 2, + MBOX_CMD_SET_CLOCK_RATE, + chip->clock_rate, + 0,0,0,0,0,0)) + return(1); + + return (0); +} + +/* Set Negation State */ +static int +ql_set_negation_state(pCHIP_INFO chip, u_short *mbox_sts) +{ + u_short port[2]={0}; + int i; + + for (i = 0; i < chip->channel_count; ++i) { + port[i] = (REQ_ACK_ACTIVE_NEGATION << 5) | (DATA_ACTIVE_NEGATION << 4); + } + if (ql_mbox_cmd(chip, mbox_sts, 3, 3, + MBOX_CMD_SET_ACTIVE_NEGATION_STATE, + port[0], + port[1], + 0,0,0,0,0)) + return(1); + + return(0); +} + +/* Set Asynchronous Data Setup Time */ +static int +ql_set_asynchronous_data_setup_time(pCHIP_INFO chip, u_short *mbox_sts) +{ + u_short port[2]={0}; + int i; + + /* Set Asynchronous Data Setup Time. */ + + for (i = 0; i < chip->channel_count; ++i) { + port[i] = ASYNC_DATA_SETUP_TIME; + } + + if (ql_mbox_cmd(chip, mbox_sts, 3, 3, + MBOX_CMD_SET_ASYNC_DATA_SETUP_TIME, + port[0], + port[1], + 0,0,0,0,0)) + return (1); + + return (0); +} + + +/* Set Bus Control Parameters. */ +static int +ql_set_pci_control_parameters(pCHIP_INFO chip, u_short *mbox_sts) +{ + u_short port[2]={0}; + + if (chip->channel_count == 1) { + port[0] = DATA_DMA_BURST_ENABLE << 1; + port[1] = CMD_DMA_BURST_ENABLE << 1; + } + else { + port[0] = port[1] = CMD_DMA_BURST_ENABLE << 1; + } + if (ql_mbox_cmd(chip, mbox_sts, 3, 3, + MBOX_CMD_SET_BUS_CONTROL_PARAMETERS, + port[0], + port[1], + 0,0,0,0,0)) + return (1); + + return (0); +} + +/* Set SCSI Parameters */ +static int +ql_set_scsi_parameters(pCHIP_INFO chip, u_short *mbox_sts, u_short channel_id, u_short target_id) +{ + pHA_INFO ha; + u_short ppr_parm=0; + u_short ppr_flag=0; + + ha = chip->ha_info[channel_id]; + + if (ha->chip_info->device_id == QLogic_12160_DEVICE_ID) + { if (ha->ql_defaults.Id[target_id].Capability.bits.Wide_Data_Transfers) + { ppr_parm= QL_PPR_WIDE; + + /* if you try PPR mode on narrow SE targets, you get a mailbox + T/O. And Qlogic says all ultra 3 targets are wide... So... */ + if (ha->ql_defaults.Id[target_id].Capability.bits.Sync_Data_Transfers && + ha->ql_defaults.Id[target_id].dt) + { /* see if they tuned an st sync value, if so, dont use DT */ + if ((ha->ql_defaults.Id[target_id].Sync_Period == 9) || + (ha->ql_defaults.Id[target_id].Sync_Period == 10) || + (ha->ql_defaults.Id[target_id].Sync_Period == 12) || + (ha->ql_defaults.Id[target_id].Sync_Period == 16) || + (ha->ql_defaults.Id[target_id].Sync_Period == 25)) + { ppr_parm= ppr_parm | QL_PPR_DUAL; + ppr_flag= QL_PPR_ENABLE; + } + } + } + } + + if (ql_mbox_cmd(chip, mbox_sts, 7, 7, + MBOX_CMD_SET_TARGET_PARAMETERS, + (u_short)((channel_id << 15) | (target_id << 8)), + (u_short)((ha->ql_defaults.Id[target_id].Capability.byte << 8) | + ppr_flag), + (u_short)((ha->ql_defaults.Id[target_id].Sync_Offset << 8) | + (ha->ql_defaults.Id[target_id].Sync_Period)), + 0,0, + ppr_parm, + 0)) + return (1); + else + return (0); +} + +/* Set Device Queue Parameters */ +static int +ql_set_device_queue_parameters(pCHIP_INFO chip, u_short *mbox_sts, u_short channel_id, u_short target_id, u_short lun_id) +{ + pHA_INFO ha; + + + ha = chip->ha_info[channel_id]; + + if (ql_mbox_cmd(chip, mbox_sts, 4, 4, + MBOX_CMD_SET_DEVICE_QUEUE_PARAMETERS, + (channel_id << 15) | (target_id << 8) | lun_id, + MAX_QUEUE_DEPTH, + ha->ql_defaults.Id[target_id].Throttle, + 0,0,0,0)) + return (1); + + return (0); + +} + +/* Set Reset Delay Parameters */ +static int +ql_set_reset_delay_parameters(pCHIP_INFO chip, u_short *mbox_sts) +{ + + pHA_INFO ha; + u_short port[2]={0}; + int i; + + /* Set Reset Delay Time. */ + + for (i = 0; i < chip->channel_count; ++i) { + ha = chip->ha_info[i]; + port[i] = ha->ql_defaults.Bus_Reset_Delay; + } + + if (ql_mbox_cmd(chip, mbox_sts, 3, 3, + MBOX_CMD_SET_RESET_DELAY_PARAMETERS, + port[0], + port[1], + 0,0,0,0,0)) + return (1); + + return (0); + + + +} + +/* Set System Parameters */ +static int +ql_set_system_parameters(pCHIP_INFO chip, u_short *mbox_sts) +{ + + + if (ql_mbox_cmd(chip, mbox_sts, 2, 2, + MBOX_CMD_SET_SYSTEM_PARAMETERS, + 0x0001, /* fast memory enable */ + 0,0,0,0,0,0)) + return (1); + + return (0); + +} + +/* Set Firmware Features */ +static int +ql_set_firmware_features(pCHIP_INFO chip, u_short *mbox_sts) +{ + u_short Firmware_Features; + + if (chip->device_id == QLogic_1040_DEVICE_ID) + Firmware_Features = FIRMWARE_FEATURES; + else + Firmware_Features = FIRMWARE_FEATURES | QL_FIRMWARE_FAIRNESS | QL_FIRMWARE_BACKOFF +#ifdef CONFIG_IA64_DIG /* 750, will be using ID 7 */ + ; +#elif defined(CONFIG_IA64_SGI_SN) + | QL_FIRMWARE_FAIRNESS | QL_FIRMWARE_BACKOFF | QL_FIRMWARE_SGICACHE; +#else + | QL_FIRMWARE_FAIRNESS | QL_FIRMWARE_BACKOFF; +#endif + + if (ql_mbox_cmd(chip, mbox_sts, 2, 2, + MBOX_CMD_SET_FIRMWARE_FEATURES, + Firmware_Features, + 0,0,0,0,0,0)) + return (1); + + return (0); +} + + +/* Set Data Overrun Recovery Mode */ +static int +ql_set_data_over_recovery_mode(pCHIP_INFO chip, u_short *mbox_sts) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 2, 2, + MBOX_CMD_SET_DATA_RECOVERY_MODE, + DATA_OVERRUN_MODE_2, + 0,0,0,0,0,0)) + return (1); + + return (0); +} + +static int +ql_set_abort_device(pCHIP_INFO chip, u_short *mbox_sts, u_short channel_id, u_short target_id, u_short lun_id) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 2, 2, + MBOX_CMD_ABORT_DEVICE, + (u_short)( (channel_id<<15) | (target_id << 8) | (u_short) (lun_id) ), + 0, 0, 0, 0, 0, 0)) + return (1); + return (0); + +} + +/* Get SCSI Parameters */ +static int +ql_get_scsi_parameters(pCHIP_INFO chip, u_short *mbox_sts, u_short channel_id, u_short target_id) +{ + u_short tval; + + /* With 12160, the mailbox command for fetching negotiated target values was + changed. So, when we want that, for 12160, we need a different mailbox command and need to + exchange the resulting mailbox values */ + if (chip->device_id == QLogic_12160_DEVICE_ID) + { + if (ql_mbox_cmd(chip, mbox_sts, 2, 8, + MBOX_CMD_GET_TRANSFER_MODE, + channel_id<<15|target_id<<8, /* SCSI id */ + 0, 0, 0, 0, 0, 0)) + return (1); + + /* now juggle the results for compatibility, exchange 2 and 6 */ + tval=mbox_sts[2]; + mbox_sts[2]=mbox_sts[6]; + mbox_sts[6]=tval; + } + else + { + if (ql_mbox_cmd(chip, mbox_sts, 2, 8, + MBOX_CMD_GET_TARGET_PARAMETERS, + channel_id<<15|target_id<<8, /* SCSI id */ + 0, 0, 0, 0, 0, 0)) + return (1); + } + + return (0); + +} + +#ifdef DEBUG +/* Get Firmware Status */ +static int +ql_get_firmware_status(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_FIRMWARE_STATUS, + 0, 0, 0, 0, 0, 0, 0)) + return(1); + return(0); +} + + +/* Get SCSI ID */ +static int +ql_get_scsi_id(pCHIP_INFO chip, u_short *mbox_sts) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_INITIATOR_SCSI_ID, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); + +} + +/* Get Selection Timeout */ +static int +ql_get_selection_timeout(pCHIP_INFO chip, u_short *mbox_sts) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_SELECTION_TIMEOUT, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); + +} + +/* Get Retry Count */ +static int +ql_get_retry_count(pCHIP_INFO chip, u_short *mbox_sts) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_RETRY_COUNT, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); + +} + +/* Get Tag Age Limit */ +static int +ql_get_tag_age_limit(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_TAG_AGE_LIMIT, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); + + +} + +/* Get Clock Rate */ +static int +ql_get_clock_rate(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 2, + MBOX_CMD_GET_CLOCK_RATE, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + return (0); + +} + +/* Get Negation State */ +static int +ql_get_negation_state(pCHIP_INFO chip, u_short *mbox_sts) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_ACTIVE_NEGATION_STATE, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); + +} + +/* Get Asynchronous Data Setup Time */ +static int +ql_get_asynchronous_data_setup_time(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_ASYNC_DATA_SETUP_TIME, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); +} + +/* Get PCI Control Parameters */ +static int +ql_get_pci_control_parameters(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_BUS_CONTROL_PARAMETERS, + 0, 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); + + +} + + +/* Get Device Queue Parameters */ +static int +ql_get_device_queue_parameters(pCHIP_INFO chip, u_short *mbox_sts, u_short channel_id, u_short target_id, u_short lun_id) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 2, 6, + MBOX_CMD_GET_DEVICE_QUEUE_PARAMETERS, + channel_id<<15|target_id<<8|lun_id, /* PORT id | SCSI id | LUN id*/ + 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); +} + +/* Get Reset Delay Parameters */ +static int +ql_get_reset_delay_parameters(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 3, + MBOX_CMD_GET_RESET_DELAY_PARAMETERS, + 0, + 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); +} + +/* Get System Parameters */ +static int +ql_get_system_parameters(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 2, + MBOX_CMD_GET_SYSTEM_PARAMETERS, + 0, + 0, 0, 0, 0, 0, 0)) + return (1); + return (0); + +} + +/* Get Firmware Features */ +static int +ql_get_firmware_features(pCHIP_INFO chip, u_short *mbox_sts) +{ + if (ql_mbox_cmd(chip, mbox_sts, 1, 2, + MBOX_CMD_GET_FIRMWARE_FEATURES, + 0, + 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); +} + + +/* Get Data Over Recovery Mode */ +static int +ql_get_data_over_recovery_mode(pCHIP_INFO chip, u_short *mbox_sts) +{ + + if (ql_mbox_cmd(chip, mbox_sts, 1, 2, + MBOX_CMD_GET_DATA_RECOVERY_MODE, + 0, + 0, 0, 0, 0, 0, 0)) + return (1); + + return (0); + +} +#endif diff -Nur linux-2.4.19/drivers/xscsi/ql.h linux-2.4.19-sgi211r3/drivers/xscsi/ql.h --- linux-2.4.19/drivers/xscsi/ql.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/ql.h Fri Jan 3 08:28:29 2003 @@ -0,0 +1,1366 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifdef XSCSI +#define _KERNEL +#endif + +#ifdef _KERNEL +#ifndef XSCSI +#include +#include +#endif + +/********************************************************** +** +** Debug definitions +*/ + +#ifdef PIO_TRACE +#define QL_LOG_CNT 512 +#endif + +/********************************************************** +** +** General Information +*/ + +#define IOCB_SEGS 2 +#define CONTINUATION_SEGS 5 + +#define MAX_CONTINUATION_ENTRIES 254 + +#define QL_MAXTARG 16 +#define QL_MAXLUN 8 + +#define REQUEST_QUEUE_1040_DEPTH 256 +#define RESPONSE_QUEUE_1040_DEPTH 256 + +#define REQUEST_QUEUE_1240_DEPTH 256 +#define RESPONSE_QUEUE_1240_DEPTH 256 + +#define MAX_REQ_INFO 255 + +#define DEF_EXECUTION_THROTTLE 255 + + +/********************************************************** +** +** Internal Command Information +*/ + +#define REQ_SENSE_DATA_LENGTH 32 + +/********************************************************* +** +** Host Adapter Information +*/ + +/*** +**** Queue Entry. +**** Used only to allocate space for request and response structures. +***/ +typedef struct +{ + u_char data[64]; +} queue_entry; + + +/*** +**** DATA SEGMENT structures. +***/ +typedef struct +{ + u_int base_low_32; + u_int base_high_32; + u_int count; +} ql_data_seg; + + +typedef struct req_information +{ + int timeout; + scsi_request_t* req; +} REQ_INFO, *pREQ_INFO; + + +typedef struct +{ + /* bits */ + u_char Not_Used0 :3; /* 0,1,2 */ + u_char HA_Enable :1; /* 3 */ + u_char Initiator_SCSI_Id :4; /* 4,5,6,7 */ + + u_char Bus_Reset_Delay; + u_char Tag_Age_Limit; + u_short Selection_Timeout; + + struct + { + union { + u_char byte; /* access by entire byte */ + struct { /*bit*/ +#ifdef __LITTLE_ENDIAN + u_char Renegotiate_on_Error :1; /* 0 */ + u_char Stop_Queue_on_Check :1; /* 1 */ + u_char Auto_Request_Sense :1; /* 2 */ + u_char Tagged_Queuing :1; /* 3 */ + u_char Sync_Data_Transfers :1; /* 4 */ + u_char Wide_Data_Transfers :1; /* 5 */ + u_char Parity_Checking :1; /* 6 */ + u_char Disconnect_Allowed :1; /* 7 */ +#else + u_char Disconnect_Allowed :1; /* 7 */ + u_char Parity_Checking :1; /* 6 */ + u_char Wide_Data_Transfers :1; /* 5 */ + u_char Sync_Data_Transfers :1; /* 4 */ + u_char Tagged_Queuing :1; /* 3 */ + u_char Auto_Request_Sense :1; /* 2 */ + u_char Stop_Queue_on_Check :1; /* 1 */ + u_char Renegotiate_on_Error :1; /* 0 */ +#endif + } bits; + + } Capability; + + u_char Throttle; + u_char Sync_Period; + /* bits */ + u_char Sync_Offset :4; /* 0,1,2,3 */ + u_char Wide_Allowed :1; /* 4 */ + u_char Sync_Allowed :1; /* 5 */ + u_char Force_Sync :1; /* 6 */ + u_char Is_CDROM :1; /* 7 */ + u_char dt :1; /* able to do dual transition */ + /* should probably be a capability bit */ + } Id[QL_MAXTARG]; + +} Default_Parameters; + + +typedef struct chip_information +{ + /* + ** Base I/O Address for this card. + ** Make sure to convert this to a usable virtual address. + */ + caddr_t ha_base; + scsi_pci_vhdl_t pci_vhdl; + struct ha_information *ha_info[2]; /* point back the ha information */ + + /* pci infrastructure vertex info */ + vertex_hdl_t ctlr_vhdl[2]; + + u_int chip_flags; /* general flags for the chip */ + u_short device_id; + u_short revision; /* PCI revision ID number */ + int bridge_revnum; /* bridge revision number */ + u_short clock_rate; + + u_short *risc_code; /* risc code firmware data */ + + u_short risc_code_length; /* risc code data length */ + u_short risc_code_addr; /* risc code starting address */ + + u_short channel_count; + + /* + ** Request and Response pointers + */ + u_short request_in; /* request in pointer */ + u_short request_out; /* request out pointer */ + u_short response_out; /* response out pointer (copy of mailbox 5 OUT) */ + u_short response_in; /* response in pointer (copy of mailbox 5 IN) */ + + int queue_space; + + queue_entry* request_ptr; + queue_entry* request_base; + queue_entry* response_ptr; + queue_entry* response_base; + + int ql_request_queue_depth; + int ql_response_queue_depth; + +#ifndef XSCSI + pciio_dmamap_t request_dmamap; + pciio_dmamap_t response_dmamap; +#endif + paddr_t request_dmaptr; + paddr_t response_dmaptr; + +#ifndef XSCSI + pciio_piomap_t rmap; + pciio_intr_t intr_info; +#endif + + /* scatter gather holding place */ + alenlist_t alen_p; + + + /* locking resources */ + mutex_t probemutex; /* guards addition/removal of devices/luns */ + mutex_t mboxmutex; /* guarantees 1 mbox command at any time */ +#ifdef USE_MUTEX + mutex_t ctlrlock; +#else + lock_t ctlrlock; /* guards controller state and data */ + int ctlrlockspl; +#endif + sema_t mbox_done_sema; +#ifdef XSCSI + sema_t intr_sema; +#endif + int mbox_timeout_info; + u_short mailbox[8]; + +#ifdef PIO_TRACE + uint *ql_log_vals; +#endif + + /* chip default parameters */ + u_char Retry_Count; + u_char Retry_Delay; + + u_short req_rotor; + char chip_name[MAXDEVNAME]; + +} CHIP_INFO, *pCHIP_INFO; + +typedef struct ha_information +{ + + struct chip_information *chip_info; + struct ha_information *next_ha; + + u_int host_flags; /* general flags for this adapter */ + + /* scsi ctlr vertex info */ + vertex_hdl_t ctlr_vhdl; + /* bus quiesce timeout id's */ + toid_t quiesce_in_progress_id; /* how long to wait for quiesce to */ + /* complete */ + toid_t quiesce_id; /* id for quiesce_time */ + int quiesce_time; /* how long to keep the bus quiesced */ + + /* + ** General flags for each device. + ** This is used to determine if the device driver + ** has performed a SCSI_INIT on the device AND whether the + ** device has been enabled in the NVRAM. + */ + + /* + ** Queued requests. + */ + scsi_request_t* req_forw; + scsi_request_t* req_back; + + /* locations to store the outstanding requests and the associated alen_l */ + + int tcmd[QL_MAXTARG]; + int reqi_cntr[QL_MAXTARG]; + pREQ_INFO reqi_block[QL_MAXTARG]; + + Default_Parameters ql_defaults; + + int ql_ncmd; + scsi_request_t* waitf; + scsi_request_t* waitb; + +#ifdef QL_STATS + struct adapter_stats *adp_stats; +#endif + u_short channel_id; /* 1240, 1280, 12160 will have 0 and 1 */ + u_short bus_mode; /* SE, LVD, HVD */ + + char ha_name[MAXDEVNAME]; + +} HA_INFO, *pHA_INFO; + +/* +** DMA Configurations Register definitions +** command channel pci address 0x80 +** data0 channel pci address 0xa0 +** data1 channel pci address 0xc0 +*/ + +#define DCR_DMA_DATA_XFER_DIRECTION 0x0001 +#define DCR_DMA_BURST_ENABLE 0x0002 +#define DCR_DMA_INTERRUPT_ENABLE 0x0004 +#define DCR_DMA_REQUEST_FROM_SCSI 0x0008 + +/* + ** dma control register definitions +*/ + +#define DMA_CON_CLEAR_CHAN 0x8 +#define DMA_CON_CLEAR_FIFO 0x4 +#define DMA_CON_RESET_INT 0x2 + +/* + * chip flags + * + */ +#define AFLG_CHIP_INITIALIZED 0x0001 /* isp initialized */ +#define AFLG_CHIP_INTERRUPTS_ENABLED 0x0002 /* interrupts enabled */ +#define AFLG_CHIP_MAIL_BOX_DONE 0x0004 /* mailbox is done */ +#define AFLG_CHIP_MAIL_BOX_WAITING 0x0008 /* waiting mailbox to finish thru interrupt */ +#define AFLG_CHIP_MAIL_BOX_POLLING 0x0010 /* polling for mailbox to finish */ +#define AFLG_CHIP_SHUTDOWN 0x0020 /* shutdown in progress */ +#define AFLG_CHIP_IN_INTR 0x0040 /* in interrupt mode */ +#define AFLG_CHIP_DUMPING 0x0080 /* in dumping mode */ +#define AFLG_CHIP_ASYNC_RESPONSE_IN 0x0100 /* async response coming in */ +#define AFLG_CHIP_DOWNLOAD_FIRMWARE 0x0200 /* downloading firmware */ +#define AFLG_CHIP_INITIAL_SRAM_PARITY 0x0400 /* initializing sram parity */ +#define AFLG_CHIP_SRAM_PARITY_ENABLE 0x0800 /* enable sram parity memory checking */ +#define AFLG_CHIP_WATCHDOG_TIMER 0x1000 /* in watchdog timeout routine */ + +/* + * host adapter flags + * + */ +#define AFLG_HA_FAST_NARROW 0x00000001 /* marker needs to be send */ +#define AFLG_HA_QUIESCE_IN_PROGRESS 0x00000002 /* quiesce in progress */ +#define AFLG_HA_QUIESCE_COMPLETE 0x00000004 /* quiesce completed */ +#define AFLG_HA_DRAIN_IO 0x00000008 /* drain I/O */ +#define AFLG_HA_SEND_MARKER 0x00000010 /* fast and narrow setup */ +#define AFLG_HA_BUS_SCAN_IN_PROGRESS 0x00000020 /* bus scan in progress */ +#define AFLG_HA_TIMEOUT 0x00000040 /* timeout in process */ +#define AFLG_HA_TODRAINED 0x00000080 /* t/o has completed draining */ + +#define AFLG_HA_QUEUE_PROGRESS_FLAGS (AFLG_HA_QUIESCE_IN_PROGRESS | AFLG_HA_QUIESCE_COMPLETE | AFLG_HA_DRAIN_IO) + +/* +** Device flags. +*/ +#define DFLG_INITIALIZED 0x0001 +#define DFLG_INIT_IN_PROGRESS 0x0002 /* LUN Init in progress -- pause LUN queue */ +#define DFLG_EXCLUSIVE 0x0004 +#define DFLG_CONTINGENT_ALLEGIANCE 0x0008 +#define DFLG_ABORT_IN_PROGRESS 0x0010 /* LUN Abort in progress -- pause LUN queue */ +#define DFLG_SEND_MARKER 0x0020 /* Send LUN marker after LUN abort */ +#define DFLG_BEHAVE_QERR1 0x0100 /* QERR=1 for this device */ + +/* +** Device capability bits. +*/ +#define CAP_RENEGOTIATE_ON_ERROR 0x01 +#define CAP_STOP_QUEUE_ON_CHECK 0x02 +#define CAP_AUTO_REQUEST_SENSE 0x04 +#define CAP_TAGGED_QUEUING 0x08 +#define CAP_SYNC_DATA_TRANSFERS 0x10 +#define CAP_WIDE_DATA_TRANSFERS 0x20 +#define CAP_PARITY_CHECKING 0x40 +#define CAP_DISCONNECT_PRIV 0x80 + + +#define QLOGIC_DEV_DESC_NAME "Qlogic SCSI" + +/**************************************************************** +** +** ISP Firmware Definitions +*/ + +/*** +**** ENTRY HEADER structure. +***/ +typedef struct +{ +#ifdef __LITTLE_ENDIAN + u_char entry_type; + u_char entry_cnt; + u_char sys_def_1; + u_char flags; +#else + u_char flags; + u_char sys_def_1; + u_char entry_cnt; + u_char entry_type; +#endif +} entry_header; + + +/* +** Entry Header Type Defintions. +*/ +#define ET_COMMAND 0x9 +#define ET_CONTINUATION 0xa +#define ET_STATUS 3 +#define ET_MARKER 4 +#define ET_EXTENDED_COMMAND 5 + +/* +** Entry Header Flag Definitions. +*/ +#define EF_CONTINUATION 0x01 +#define EF_BUSY 0x02 +#define EF_BAD_HEADER 0x04 +#define EF_BAD_PAYLOAD 0x08 +#define EF_ERROR_MASK (EF_BUSY | EF_BAD_HEADER | EF_BAD_PAYLOAD) + + +/*** +**** COMMAND ENTRY structure. +***/ +typedef struct +{ + entry_header hdr; + + u_int handle; + +#ifdef __LITTLE_ENDIAN + u_char target_lun; + u_char target_id:7, + channel_id:1; + u_short cdb_length; + + u_short control_flags; + u_short reserved; + + u_short time_out; + u_short segment_cnt; + + u_char cdb0; + u_char cdb1; + u_char cdb2; + u_char cdb3; + u_char cdb4; + u_char cdb5; + u_char cdb6; + u_char cdb7; + u_char cdb8; + u_char cdb9; + u_char cdb10; + u_char cdb11; + +#else + u_short cdb_length; + u_char channel_id:1, + target_id:7; + u_char target_lun; + + u_short reserved; + u_short control_flags; + + u_short segment_cnt; + u_short time_out; + + u_char cdb3; + u_char cdb2; + u_char cdb1; + u_char cdb0; + + u_char cdb7; + u_char cdb6; + u_char cdb5; + u_char cdb4; + + u_char cdb11; + u_char cdb10; + u_char cdb9; + u_char cdb8; +#endif /* __LITTLE_ENDIAN */ + + u_int reserved2; + u_int reserved3; + ql_data_seg dseg[IOCB_SEGS]; +} command_entry; + +/* +** Command Entry Control Flag Definitions. +*/ +#define CF_NO_DISCONNECTS 0x0001 +#define CF_HEAD_TAG 0x0002 +#define CF_ORDERED_TAG 0x0004 +#define CF_SIMPLE_TAG 0x0008 +#define CF_TARGET_ROUTINE 0x0010 +#define CF_READ 0x0020 +#define CF_WRITE 0x0040 +#define CF_AUTO_SENSE_DISABLE 0x0100 +#define CF_FORCE_ASYNCHONOUS 0x0200 +#define CF_FORCE_SYNCHONOUS 0x0400 +#define CF_INITIATE_WIDE 0x0800 +#define CF_DISABLE_DATA_PARITY 0x1000 +#define CF_STOP_QUEUE 0x2000 +#define CF_SUPPORT_EXTENDED_SENSE 0x4000 +#define CF_PRIORITY_FLAG 0x8000 + + +/*** +**** CONTINUATION ENTRY structures. +***/ +typedef struct +{ + entry_header hdr; + ql_data_seg dseg[CONTINUATION_SEGS]; +} continuation_entry; + + +/*** +**** MARKER ENTRY structure. +***/ + +typedef struct +{ + entry_header hdr; + + u_int reserved0; + +#ifdef __LITTLE_ENDIAN + u_char target_lun; + u_char target_id:7, + channel_id:1; + u_char modifier; + u_char reserved1; +#else + u_char reserved1; + u_char modifier; + u_char channel_id:1, + target_id:7; + u_char target_lun; +#endif + + u_char reserved2[52]; +} marker_entry; + + +/* +** Marker Entry Modifier Definitions. +*/ +#define MM_SYNC_DEVICE 0 +#define MM_SYNC_TARGET 1 +#define MM_SYNC_ALL 2 + + +/*** +**** STATUS ENTRY structure. +***/ + +typedef struct +{ + entry_header hdr; + + u_int handle; + +#ifdef __LITTLE_ENDIAN + u_short scsi_status; + u_short completion_status; + + u_short state_flags; + u_short status_flags; + + u_short time; + u_short req_sense_length; +#else + u_short completion_status; + u_short scsi_status; + + u_short status_flags; + u_short state_flags; + + u_short req_sense_length; + u_short time; +#endif + + u_int residual; + + u_char reserved[8]; + + u_char req_sense_data[32]; +} status_entry; + + +/* +** Status Entry Completion Status Defintions. +*/ +#define SCS_COMPLETE 0x0000 +#define SCS_INCOMPLETE 0x0001 +#define SCS_DMA_ERROR 0x0002 +#define SCS_TRANSPORT_ERROR 0x0003 +#define SCS_RESET_OCCURRED 0x0004 +#define SCS_ABORTED 0x0005 +#define SCS_TIMEOUT 0x0006 +#define SCS_DATA_OVERRUN 0x0007 +#define SCS_COMMAND_OVERRUN 0x0008 +#define SCS_ABORT_MSG_FAILED 0x000E +#define SCS_DEVICE_RESET_MSG_FAILED 0x0012 +#define SCS_UNEXPECTED_BUS_FREE 0x0014 +#define SCS_DATA_UNDERRUN 0x0015 +#define SCS_CMD_UNDERRUN 0x0016 +#define SCS_SCSI_PHASE_SKIPPED 0x001D +#define SCS_AUTO_SENSE_FAILED 0x001E +#define SCS_WIDE_DATA_XFER_FAILED 0x001F +#define SCS_SYNC_DATA_XFER_FAILED 0x0020 +#define SCS_LVD_BUS_ERROR 0x0021 +#define SCS_DATA_CRC 0x0022 + +/* +** Status Entry State Flag Definitions. +*/ +#define SS_GOT_BUS 0x0100 +#define SS_GOT_TARGET 0x0200 +#define SS_SENT_CDB 0x0400 +#define SS_TRANSFERRED_DATA 0x0800 +#define SS_GOT_STATUS 0x1000 +#define SS_GOT_SENSE 0x2000 +#define SS_TRANSFER_COMPLETE 0x4000 + +/* +** Status Entry Status Flag Definitions. +*/ +#define SST_DISCONNECT 0x0001 +#define SST_SYNCHRONOUS 0x0002 +#define SST_PARITY_ERROR 0x0004 +#define SST_BUS_RESET 0x0008 +#define SST_DEVICE_RESET 0x0010 +#define SST_ABORTED 0x0020 +#define SST_TIMEOUT 0x0040 +#define SST_NEGOTIATION 0x0080 + +/* +** Mailbox Command Definitions. +*/ +#define MBOX_CMD_EXECUTE_FIRMWARE 0x0002 +#define MBOX_CMD_WRITE_RAM_WORD 0x0004 +#define MBOX_CMD_READ_RAM_WORD 0x0005 +#define MBOX_CMD_MAILBOX_REGISTER_TEST 0x0006 +#define MBOX_CMD_ABOUT_FIRMWARE 0x0008 +#define MBOX_CMD_LOAD_RAM_64 0x0009 + +#define MBOX_CMD_ABORT_DEVICE 0x0016 +#define MBOX_CMD_BUS_RESET 0x0018 + +#define MBOX_CMD_GET_FIRMWARE_STATUS 0x001F +#define MBOX_CMD_GET_INITIATOR_SCSI_ID 0x0020 +#define MBOX_CMD_GET_SELECTION_TIMEOUT 0x0021 +#define MBOX_CMD_GET_RETRY_COUNT 0x0022 +#define MBOX_CMD_GET_TAG_AGE_LIMIT 0x0023 +#define MBOX_CMD_GET_CLOCK_RATE 0x0024 +#define MBOX_CMD_GET_ACTIVE_NEGATION_STATE 0x0025 +#define MBOX_CMD_GET_ASYNC_DATA_SETUP_TIME 0x0026 +#define MBOX_CMD_GET_BUS_CONTROL_PARAMETERS 0x0027 +#define MBOX_CMD_GET_TARGET_PARAMETERS 0x0028 +#define MBOX_CMD_GET_DEVICE_QUEUE_PARAMETERS 0x0029 +#define MBOX_CMD_GET_RESET_DELAY_PARAMETERS 0x002A + +#define MBOX_CMD_SET_INITIATOR_SCSI_ID 0x0030 +#define MBOX_CMD_SET_SELECTION_TIMEOUT 0x0031 +#define MBOX_CMD_SET_RETRY_COUNT 0x0032 +#define MBOX_CMD_SET_TAG_AGE_LIMIT 0x0033 +#define MBOX_CMD_SET_CLOCK_RATE 0x0034 +#define MBOX_CMD_SET_ACTIVE_NEGATION_STATE 0x0035 +#define MBOX_CMD_SET_ASYNC_DATA_SETUP_TIME 0x0036 +#define MBOX_CMD_SET_BUS_CONTROL_PARAMETERS 0x0037 +#define MBOX_CMD_SET_TARGET_PARAMETERS 0x0038 +#define MBOX_CMD_SET_DEVICE_QUEUE_PARAMETERS 0x0039 +#define MBOX_CMD_SET_RESET_DELAY_PARAMETERS 0x003A + +#define MBOX_CMD_SET_SYSTEM_PARAMETERS 0x0045 +#define MBOX_CMD_GET_SYSTEM_PARAMETERS 0x0046 +#define MBOX_CMD_SET_FIRMWARE_FEATURES 0x004A +#define MBOX_CMD_GET_FIRMWARE_FEATURES 0x004B + + +#define MBOX_CMD_GET_TRANSFER_MODE 0x0059 +#define MBOX_CMD_SET_DATA_RECOVERY_MODE 0x005A +#define MBOX_CMD_GET_DATA_RECOVERY_MODE 0x005B + +/* 64 bit operation commands */ +#define MBOX_CMD_DUMP_RAM_64 0x0051 +#define MBOX_CMD_INIT_REQUEST_QUEUE_64 0x0052 +#define MBOX_CMD_INIT_RESPONSE_QUEUE_64 0x0053 +#define MBOX_CMD_EXECUTE_IOCB_64 0x0054 + + +/* +** Mailbox Status Definitions. +*/ +#define MBOX_STS_FIRMWARE_ALIVE 0x0000 +#define MBOX_STS_CHECKSUM_ERROR 0x0001 +#define MBOX_STS_SHADOW_LOAD_ERROR 0x0002 +#define MBOX_STS_BUSY 0x0004 + +#define MBOX_STS_COMMAND_COMPLETE 0x4000 +#define MBOX_STS_INVALID_COMMAND 0x4001 +#define MBOX_STS_HOST_INTERFACE_ERROR 0x4002 +#define MBOX_STS_TEST_FAILED 0x4003 +#define MBOX_STS_COMMAND_ERROR 0x4005 +#define MBOX_STS_COMMAND_PARAMETER_ERROR 0x4006 +#define MBOX_STS_BUS_CONFIG_ERROR 0x4007 + +#define MBOX_ASTS_SCSI_BUS_RESET 0x8001 +#define MBOX_ASTS_SYSTEM_ERROR 0x8002 +#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003 +#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004 +#define MBOX_ASTS_REQUEST_QUEUE_WAKEUP 0x8005 +#define MBOX_ASTS_EXECUTION_TIMEOUT_RESET 0x8006 +#define MBOX_ASTS_EXTENDED_MESSAGE_UNDERRUN 0x800A +#define MBOX_ASTS_SCAM_INTERRUPT 0x800B +#define MBOX_ASTS_SCSI_BUS_HANG 0x800C +#define MBOX_ASTS_SCSI_BUS_RESET_BY_ISP 0x800D +#define MBOX_ASTS_SCSI_BUS_MODE_TRANSITION 0x800E + +#define MBOX_ASTS_FAST_POSTING_EVENT_CODE 0x8020 + + + + + +/**************************************************************** +** +** ISP Register Definitions +** These register definitions assume a 32 bit PCI interface (for PIO) +** on a big endian machine. For 32 bit PCI little endian, macros used +** to access them need to XOR the address with 2. +*/ + +typedef volatile struct +{ + /* + ** Bus interface registers. + */ /* Offsets */ + + + u_short bus_id_high; /* 0002 */ + u_short bus_id_low; /* 0000 */ + + u_short bus_config1; /* 0006 */ + u_short bus_config0; /* 0004 */ + + u_short bus_isr; /* 000A */ + u_short bus_icr; /* 0008 */ + + u_short NvRam_reg; /* 000E */ + u_short bus_sema; /* 000C */ + + + /* + ** Skip over DMA Controller registers: + ** 0020-002F - Command DMA Channel + ** 0040-004F - Data DMA Channel ----- + ** except for the dma config and control reg + ** 0060-0063 - DMA FIFO Access Ports + */ + + u_char not_used[0x0010]; + + /* NOTE: control_dma_* and data_dma_* are 1040 only */ + u_short control_dma_control; /* 0022 */ + u_short control_dma_config; /* 0020 */ + u_short control_dma_fifo_status; /* 0026 */ + u_short control_dma_status; /* 0024 */ + u_short control_dma_reserved; /* 002a */ + u_short control_dma_counter; /* 0028 */ + u_short control_dma_address_counter_1; /* 002e */ + u_short control_dma_address_counter_0; /* 002c */ + u_short control_dma_address_counter_3; /* 0032 */ + u_short control_dma_address_counter_2; /* 0030 */ + + + u_char not_used0[0x000c]; + + + u_short data_dma_control; /* 0042 */ + u_short data_dma_config; /* 0040 */ + u_short data_dma_fifo_status; /* 0046 */ + u_short data_dma_status; /* 0044 */ + u_short data_dma_xfer_counter_high; /* 004a */ + u_short data_dma_xfer_counter_low; /* 0048 */ + u_short data_dma_address_counter_1; /* 004e */ + u_short data_dma_address_counter_0; /* 004c */ + u_short data_dma_address_counter_3; /* 0052 */ + u_short data_dma_address_counter_2; /* 0050 */ + + + u_char not_used1[0x001c]; + + /* + ** Mailbox registers. + */ + u_short mailbox1; /* 0070 */ + u_short mailbox0; /* 0072 */ + u_short mailbox3; /* 0074 */ + u_short mailbox2; /* 0076 */ + u_short mailbox5; /* 0078 */ + u_short mailbox4; /* 007A */ + u_short mailbox7; /* 007C */ + u_short mailbox6; /* 007E */ + + + /* + ** Note: in V3 part, RISC and SXP registers are paged. + ** Since we don't use SXP registers, we won't define them. (only 1040 fw) + ** - 1080/1240/1280 fw will be using this bank of register for DMA, SXP, and RISC. + */ + + /* + ** + ** 0080-00BF - RISC Registers. + */ + + u_short r1; /* 82 */ + u_short accumulator; /* 80 */ + + u_short r3; /* 86 */ + u_short r2; /* 84 */ + + u_short r5; /* 8a */ + u_short r4; /* 88 */ + + u_short r7; /* 8e */ + u_short r6; /* 8c */ + + u_short r9; /* 92 */ + u_short r8; /* 90 */ + + u_short r11; /* 96 */ + u_short r10; /* 94 */ + + u_short r13; /* 9a */ + u_short r12; /* 98 */ + + u_short r15; /* 9e */ + u_short r14; /* 9c */ + + + u_short ivr; /* a2 */ + u_short psr; /* a0 */ + + u_short rar0; /* a6 */ + u_short pcr; /* a4 */ + + u_short lcr; /* aa */ + u_short rar1; /* a8 */ + + u_short mtr; /* ae, mtr on 1040 only */ + u_short risc_pc; /* ac */ + + u_short sp; /* b2 */ + u_short mctr; /* b0, emb on 1040, mctr on everything else */ + + u_short b6; /* b6 */ + u_short b4; /* b4 */ + + u_short lvdi; /* ba, undef on 1040, lvd interrupt status on else */ + u_short b8; /* b8 */ + + u_short hardware_revision; /* be */ + u_short bc; /* bc */ + + /* + ** Host Configuration and Control register. + */ + u_short c2; /* c2 */ + u_short hccr; /* c0 */ + + u_short c6; /* c6 */ + u_short c4; /* c4 */ + + u_short ca; /* ca */ + u_short c8; /* c8 */ + + u_short ce; /* ce */ + u_short cc; /* cc */ + + u_short d2; /* d2 */ + u_short d0; /* d0 */ + + u_short d6; /* d6 */ + u_short d4; /* d4 */ + + u_short da; /* da */ + u_short d8; /* d8 */ + + u_short de; /* de */ + u_short dc; /* dc */ + + u_short e2; /* e2 */ + u_short e0; /* e0 */ + + u_short e6; /* e6 */ + u_short e4; /* e4 */ + + u_short ea; /* ea */ + u_short e8; /* e8 */ + + u_short ee; /* ee */ + u_short ec; /* ec */ + + u_short f2; /* f2 */ + u_short f0; /* f0 */ + + u_short f6; /* f6 */ + u_short f4; /* f4 */ + + u_short fa; /* fa */ + u_short f8; /* f8 */ + + u_short fe; /* fe */ + u_short fc; /* fc */ + + +} ISP_REGS, *pISP_REGS; + + + + +/* +** Bus Configuration Register 1 Definitions. +*/ +#define CONF_1_BURST_ENABLE 0x0004 +#define CONF_1_1240_DMA_SEL 0x0300 /* Select DMA bank */ + + +/* this set the high water mark to 32 bytes (16) observed */ + + +/* +** Bus Control Register Definitions. +*/ +#define ICR_SOFT_RESET 0x0001 +#define ICR_ENABLE_ALL_INTS 0x0002 +#define ICR_ENABLE_RISC_INT 0x0004 + + +/* +** Bus Interrupt Status Register Defintions. +*/ +#define BUS_ISR_RISC_INT 0x0004 + + +/* +** Bus Semaphore Register Definitions. +*/ +#define BUS_SEMA_LOCK 0x0001 + + +/* +** Host Command and Control Register Definitions. +*/ + + /* Command Definitions */ + +#define HCCR_CMD_RESET 0x1000 /* reset RISC */ +#define HCCR_CMD_PAUSE 0x2000 /* pause RISC */ +#define HCCR_CMD_RELEASE 0x3000 /* release paused RISC */ +#define HCCR_CMD_SET_HOST_INT 0x5000 /* set host interrupt */ +#define HCCR_CMD_CLEAR_RISC_INT 0x7000 /* clear RISC interrupt */ +#define HCCR_SRAM_PARITY_ENABLE 0xA000 /* enable sram parity */ +#define HCCR_FORCE_PARITY_ERROR 0xE000 /* force sram parity error*/ + + + + /* Status Defintions */ +#define HCCR_SRAM_PARITY_ERROR_DETECTED_1040 0x0400 /* R: parity error detected */ +#define HCCR_SRAM_PARITY_BANK2 0x0400 /* R: bank two enable */ +#define HCCR_SRAM_PARITY_BANK1 0x0200 /* R: bank one enable */ +#define HCCR_SRAM_PARITY_BANK0 0x0100 /* R: bank zero enable */ +#define HCCR_HOST_INT 0x0080 /* R: host interrupt set */ +#define HCCR_RESET 0x0040 /* R: RISC reset in progress */ +#define HCCR_PAUSE 0x0020 /* R: RISC paused */ + + + + +/**************************************************************** +*/ +#define INQUIRY_CMD 0x12 + + +/******************************************************************** +** +** Constants +*/ + + +/* clock rates for ISP1020 and ISP1040 */ + +#define FAST_CLOCK_RATE 40 +#define FAST20_CLOCK_RATE 60 +#define FAST40_CLOCK_RATE 100 /* 1080 and 1280 only */ +#define FAST80_CLOCK_RATE 80 /* 12160 */ + + +/* + * SCSI Bus operation modes are determined by the DIFFM and DIFFS pins. + */ +#define SCSI_BUS_MODE_SINGLE_ENDED 0x0001 +#define SCSI_BUS_MODE_HVD 0x0002 +#define SCSI_BUS_MODE_LVD 0x0004 + +/* This is for bit mask when 0x800E Asynchronous event code return and the data is mailbox1 */ +#define SCSI_BUS_MODE_MASK 0x0007 + + +/******************************************************************** +** +** Structures +*/ + +/* +** Host Adapter defaults. +*/ + +/* new threshold control in Config Register 1 */ +/* bits name */ +/* 15->8 reserved */ +/* 7->4 Extended FIFO control */ +/* 3 SXP Register Select */ +/* 2 Burst enable */ +/* 1->0 FIFO control */ +/* */ +/* */ +/* the original 1020 only used bits 0 and 1 */ +/* but this could not occomodate 128 the btye option*/ +/* Now only use the Extended FIFO control */ + +/* bits 7->4 bits 1->0 burst size */ +/* */ +/* 6 x 512 */ +/* 5 x 256 */ +/* 4 x 128 */ +/* 3 x 64 */ +/* 2 x 32 */ +/* 1 x 16 */ +/* 0 3 64 */ +/* 0 2 32 */ +/* 0 1 16 */ +/* 0 0 8 */ + +#define BURST_512 0x60 /* for 1240 1080, and 1280 chips only */ +#define BURST_256 0x50 /* for 1240 1080, and 1280 chips only */ +#define BURST_128 0x40 +#define BURST_64 0x30 +#define BURST_32 0x20 +#define BURST_16 0x10 + + + +#define HA_ENABLE 1 /* enabled */ +#if defined(XSCSI) && defined(CONFIG_IA64_DIG) +#define INITIATOR_SCSI_ID 7 /* Need to use a default ID of 7 on the 750, system disk conflict on 0 */ +#else +#define INITIATOR_SCSI_ID 0 +#endif +#define BUS_RESET_DELAY 3 /* 3 seconds */ +#define RETRY_COUNT 0 /* no retries */ +#define RETRY_DELAY 0 /* no time between tries*/ +#define ASYNC_DATA_SETUP_TIME 8 /* was 9 clock periods, but is reserved on 12160 */ +#define REQ_ACK_ACTIVE_NEGATION 0x01 /* enabled */ +#define DATA_ACTIVE_NEGATION 0x01 /* enabled */ +#define DATA_DMA_BURST_ENABLE 0x01 /* enabled */ +#define CMD_DMA_BURST_ENABLE 0x01 /* enabled */ + +#define TAG_AGE_LIMIT 8 + +#define SELECTION_TIMEOUT 250 /* 250 ms */ + +#define MAX_QUEUE_DEPTH 256 /* 256 commands */ + +#define DELAY_AFTER_RESET 1 /*second*/ + +/* special firmware features for 1240/1280/12160 */ +#define QL_FIRMWARE_SGICACHE 0x200 /* enable SGI cache flush */ +#define QL_FIRMWARE_FAIRNESS 0x100 /* disable reselection fairness */ +#define QL_FIRMWARE_BACKOFF 0x20 /* disable synchronous backoff */ + +/* 12160 PPR bits */ +#define QL_PPR_WIDE 0x01 /* select wide transfer */ +#define QL_PPR_DUAL 0x200 /* select dual transition */ +#define QL_PPR_ENABLE 0x20 + +/* +** Drive defaults. +*/ +#define RENEGOTIATE_ON_ERROR 1 /* ON */ +#define STOP_QUEUE_ON_CHECK 0 /* OFF */ +#define AUTO_REQUEST_SENSE 1 /* ON */ +#define TAGGED_QUEUING 1 /* ON */ +#define SYNC_DATA_TRANSFERS 1 /* ON */ +#define WIDE_DATA_TRANSFERS 1 /* ON */ +#define PARITY_CHECKING 1 +#define DISCONNECT_ALLOWED 1 +#define EXECUTION_THROTTLE 255 +#define SYNC_PERIOD 25 /* 100 ns */ +#define SYNC_PERIOD_FAST20 12 /* 50 ns */ +#define SYNC_PERIOD_FAST40 10 /* 25 ns */ +#define SYNC_PERIOD_FAST40SE 12 +#define SYNC_PERIOD_FAST80 9 +#define SYNC_PERIOD_FAST80SE 12 +#define SYNC_OFFSET 8 +#define SYNC_OFFSET_12160 0x0E +#define MAX_SYNC_OFFSET 12 +#define MAX_SYNC_OFFSET_12160 0x1c +#define DEFAULT_TIMEOUT 10 /* default scsi timeout is 10 sec */ +#define FIRMWARE_FEATURES 0x0002 + + +/* + * ISP1020/ISP1040 + * note that this is the same as 1020 + * early part were speed graded only + */ +#define REV_ISP1020 (ISP1040_STARTING_REV_NUM + 1) +/* note that this is the same as 1020 */ +/* early part were speed graded only */ +#define REV_ISP1040 1 +#define REV_ISP1040A 2 +#define REV_ISP1040AV4 3 +#define REV_ISP1040B 4 +#define REV_ISP1040BV2 5 /* qlogic 1040B rev 2 */ + + +/* the following are defines for MBOX_CMD_SET_DATA_RECOVERY_MODE */ +/* we are supporting mode 2 right now */ +#define DATA_OVERRUN_MODE_0 0 /* pad data until the target switches out */ + /* of data phase */ +#define DATA_OVERRUN_MODE_1 1 /* hang the bus interrupt host with */ + /* 0x800c in outgoing mailbox 0 register */ + /* the host must reset the bus with mail */ + /* box command */ + +#define DATA_OVERRUN_MODE_2 2 /* ISP resets the SCSI bus places 0x800D */ + /* in outgoing mailbox 0 and returns all */ + /* outstanding io's */ + +/********************************************************** +** +** our PCI Information +*/ + +#ifndef XSCSI +/* +** PCI Bus configuration space registers. +*/ +typedef struct PCI_Config_Registers +{ + u_short Device_Id; + u_short Vendor_Id; /* 00 */ + + u_short Status; + u_short Command; /* 04 */ + + u_char Class_Code[3]; + u_char Rev_Id; /* 08 */ + + + u_char Bits; + u_char Header_Type; + u_char Latency_Timer; + u_char Cache_Line_Size; /* 0C */ + + + u_int IO_Base_Address; /* 10 */ + + u_int Memory_Base_Address; /* 14 */ + + u_int Not_Used1[6]; /* 18 - 2F */ + + u_int ROM_Base_Address; /* 30 */ + + u_int Not_Used2[2]; /* 34 - 3B */ + + u_char Interrupt_Line; /* 3C */ + u_char Interrupt_Pin; + u_char Minimum_Grant; + u_char Maximum_Latency; + + u_short ISP_Config_1; /* 40 */ + u_short Not_Used3; + +} PCI_REG, *pPCI_REG; +#endif + + +/* +** Configuration space offsets: +*/ + +#define QLogic_VENDOR_ID 0x1077 + +#define QLogic_1040_DEVICE_ID 0x1020 +#define QLogic_1240_DEVICE_ID 0x1240 +#define QLogic_1080_DEVICE_ID 0x1080 +#define QLogic_1280_DEVICE_ID 0x1280 +#define QLogic_12160_DEVICE_ID 0x1216 + + +#ifdef QL_STATS +/* +** Structure to return for IOCSTATS. +*/ +typedef struct stats { +int commands; /* # of commands processed */ +int responses; /* # of responses processed */ +int interrupts; /* # of interrupts processed */ +int intrs_processed; /* # of interrupts ACTUALLY processed */ +int responses_handled; /* # IORB processed */ +int markers; /* # of markers issued */ +dev_stats dev[QL_MAXTARG]; + +} stats, *ha_stats; + +#endif + + +/* + * info specific to the ql lun vertex + */ + +typedef struct ql_local_info { + mutex_t qli_openmutex; + u_int qli_dev_flags; /* lun device flags */ + int qli_ref_count; /* no. of references */ + int qli_cmd_rcnt; /* issued command count to this LUN */ + scsi_request_t* qli_awaitf; /* forward pointer for commands awaiting abort completion */ + scsi_request_t* qli_awaitb; /* backward pointer for commands awaiting abort completion */ + scsi_request_t* qli_iwaitf; /* forward pointer for commands awaiting init. completion */ + scsi_request_t* qli_iwaitb; /* backward pointer for commands awaiting init. completion */ + scsi_target_info_t *qli_tinfo; /* scsi target info */ + void (*qli_sense_callback)(vertex_hdl_t, uint8_t *); /* Sense callback routine */ + int rev; /* scsi rev of target */ + /* belongs in targ info */ +#ifdef XSCSI + spinlock_t qli_lock; /* short term lock for fields not fully guarded by chip_lock */ +#else + lock_t qli_lock; /* short term lock for fields not fully guarded by chip_lock */ +#endif +} ql_local_info_t; + +/* + * macros associated with this structure + */ +#define QLI_OPENMUTEX(p) (p->qli_openmutex) +#define QLI_TINFO(p) (p->qli_tinfo) + +/* + * macros associated with the scsi lun info structure specific + * to ql + */ + +#define QL_OPENMUTEX(p) QLI_OPENMUTEX(((ql_local_info_t *)p)) +#define QL_TINFO(p) QLI_TINFO(((ql_local_info_t *)p)) + +#define OPEN_MUTEX(p) QL_OPENMUTEX(SLI_INFO(p)) +#define TINFO(p) QL_TINFO(SLI_INFO(p)) + +#define SCI_HA_INFO(p) ((pHA_INFO)(SCI_INFO(p))) +#define SLI_HA_INFO(p) ((pHA_INFO)(SCI_INFO(SLI_CTLR_INFO(p)))) + +#endif /* KERNEL */ + +/* +** Some miscellaneous configuration parameters. +*/ + +#define QL_RESET 1000 +#define QL_COMPUTE_PARITY_MEMORY 4000 +#define WATCHDOG_TIME 10 /* for bringup set to 10 */ +#define SCSI_INFO_BYTE 7 +#define SCSI_CTQ_BIT 2 + +/* + * Encoding of GPIO bits on channel 0 - MSCSI/A + * [3](r) [2](r) [1](w) [0](w) + * 0 = in slot XIO1 + * 1 = not in slot XIO1 + * diffsense + * 0 = no internal terminator + * 1 = internal terminator + * 0 = internal bus selected + * 1 = external bus selected + * + * Encoding of GPIO bits on channel 0 - MSCSI/B + * [3](r) [2](r) [1](w) [0](w) + * 0 = in slot XIO1 + * 1 = not in slot XIO1 + * not connected + * 0 0 = Internal SE selected + * 0 1 = External SE selected + * 1 0 = External DF (no termination) + * 1 1 = External DF (termination) + * + */ +#define GPIO0 0x01 +#define GPIO1 0x02 +#define GPIO2 0x04 +#define GPIO3 0x08 +#define ENABLE_WRITE (GPIO0 | GPIO1) +#define ENABLE_WRITE_SN00 0x01 +#define NOT_SLOT_ZERO GPIO3 + +/* + * The IOCB handle is comprised of the following + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + * PP UU UU UU UU TT TT TT TT TT TT TT TT + * where PP = port number; 0-1 + * UU = unit number; 0-15 + * TT = command index; 0-255 + */ +#define MAX_HANDLE_NO (0x1000 | ((QL_MAXTARG - 1) * (MAX_REQ_INFO + 1)) | MAX_REQ_INFO) + +#define QL_MUTEX_PRI PRIBIO +#define QL_SEMA_PRI PRIBIO + +#define QL_INIT_MUTEX(l,n,s) init_mutex(&(l), MUTEX_DEFAULT, n, s) + +#define QL_MUTEX_LOCK(l) mutex_lock(&(l), QL_MUTEX_PRI) +#define QL_MUTEX_UNLOCK(l) mutex_unlock(&(l)) + + +#ifdef USE_MUTEX +#define QL_INIT_LOCK(l,n,s) init_mutex(l, MUTEX_DEFAULT, n, s) +#define QL_LOCK(p) mutex_lock(&(p->ctlrlock), QL_MUTEX_PRI) +#define QL_UNLOCK(p) mutex_unlock(&(p->ctlrlock)) +#else +#define QL_INIT_LOCK(l,n,s) init_spinlock(l, n, s) +#define QL_LOCK(p) p->ctlrlockspl=mutex_spinlock(&p->ctlrlock) +#define QL_UNLOCK(p) mutex_spinunlock(&p->ctlrlock, p->ctlrlockspl) +#endif + +#ifdef XSCSI +#define QL_SPLOCK(l,s) spin_lock(&(l)) +#define QL_SPUNLOCK(l,s) spin_unlock(&(l)) +#define QL_SPINIT_LOCK(l,n,s) spin_lock_init(&l) +#define QL_SPLOCK_DESTROY(l) ; +#else +#define QL_SPLOCK(l,s) s=mutex_spinlock(&l) +#define QL_SPUNLOCK(l,s) mutex_spinunlock(&l,s) +#define QL_SPINIT_LOCK(l,n,s) init_spinlock(&l, n, s) +#define QL_SPLOCK_DESTROY(l) spinlock_destroy(&l) +#endif + +#define MAXWAIT 2147483647 /* 2^31-1 */ diff -Nur linux-2.4.19/drivers/xscsi/ql_firmware.h linux-2.4.19-sgi211r3/drivers/xscsi/ql_firmware.h --- linux-2.4.19/drivers/xscsi/ql_firmware.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/ql_firmware.h Fri Feb 1 11:39:38 2002 @@ -0,0 +1,5239 @@ +#define QLOGIC_1040_FIRMWARE_SUPPORT 1 /* define firmware support needed for 1040 */ +#define QLOGIC_1080_FIRMWARE_SUPPORT 1 /* define firmware support needed for 1240,1080,1280 */ +#define QLOGIC_12160_FIRMWARE_SUPPORT 1 /* define firmware support needed for 12160 */ +#ifdef QLOGIC_1040_FIRMWARE_SUPPORT +/* + * Firmware Version 2.55.07 (17:51 Mar 24, 2000) + */ + +unsigned short risc_1040_code_version = 2*1024+55; + +unsigned short risc_1040_code_addr01 = 0x1000 ; + +unsigned short risc_1040_code01[] = { + 0x0078, 0x1041, 0x0000, 0x2b87, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, + 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, + 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, + 0x3130, 0x3230, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, + 0x6572, 0x7369, 0x6f6e, 0x2030, 0x322e, 0x3535, 0x2020, 0x2043, + 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, + 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, + 0x2400, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048, 0x104c, + 0x0038, 0x1052, 0x0078, 0x104e, 0x0028, 0x1052, 0x20b9, 0x1212, + 0x0078, 0x1054, 0x20b9, 0x1313, 0x2071, 0x0010, 0x70c3, 0x0004, + 0x20c9, 0x47ff, 0x2089, 0x1180, 0x70c7, 0x4953, 0x70cb, 0x5020, + 0x70cf, 0x2020, 0x70d3, 0x0002, 0x3f00, 0x70d6, 0x20c1, 0x0008, + 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, + 0x7fff, 0x2d64, 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, + 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10c4, 0xa386, 0x000f, + 0x0040, 0x108a, 0x2c6a, 0x2a5a, 0x20c1, 0x0000, 0x2019, 0x000f, + 0x0078, 0x106a, 0x2c6a, 0x2a5a, 0x20c1, 0x0008, 0x2009, 0x7fff, + 0x2148, 0x2944, 0x204b, 0x0a0a, 0xa9bc, 0x3fff, 0x2734, 0x203b, + 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040, 0x10ae, 0x284a, 0x263a, + 0x20c1, 0x0004, 0x2009, 0x3fff, 0x2134, 0x200b, 0x5050, 0x2114, + 0xa286, 0x5050, 0x0040, 0x10af, 0x0078, 0x1188, 0x284a, 0x263a, + 0x98c0, 0xa188, 0x1000, 0x212c, 0x200b, 0xa5a5, 0x2114, 0xa286, + 0xa5a5, 0x0040, 0x10c1, 0x250a, 0xa18a, 0x1000, 0x98c1, 0x0078, + 0x10c6, 0x250a, 0x0078, 0x10c6, 0x2c6a, 0x2a5a, 0x2130, 0xa18a, + 0x0040, 0x2128, 0xa1a2, 0x3c00, 0x8424, 0x8424, 0x8424, 0x8424, + 0x8424, 0x8424, 0xa192, 0x4800, 0x2009, 0x0000, 0x2001, 0x002f, + 0x1078, 0x1b6e, 0x2218, 0x2079, 0x3c00, 0x2fa0, 0x2408, 0x2011, + 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10e1, 0x7ee6, + 0x8528, 0x7dda, 0x7cde, 0x7be2, 0x787b, 0x0000, 0x2031, 0x0030, + 0x78c3, 0x0101, 0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0003, + 0x7803, 0x0002, 0x2069, 0x3c40, 0x2001, 0x04fd, 0x2004, 0xa082, + 0x0005, 0x0048, 0x1107, 0x0038, 0x1109, 0x0078, 0x110d, 0x00a8, + 0x110d, 0x681b, 0x003c, 0x0078, 0x110f, 0x681b, 0x0028, 0x6807, + 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008, 0x6813, 0x0005, 0x681f, + 0x0000, 0x6823, 0x0006, 0x6817, 0x0008, 0x6827, 0x0000, 0x2069, + 0x3d00, 0x2011, 0x0020, 0x2009, 0x0010, 0x680b, 0x0c19, 0x680f, + 0x0019, 0x6803, 0xfd00, 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, + 0x0008, 0xa290, 0x0004, 0x8109, 0x00c0, 0x1125, 0x2069, 0x3d80, + 0x20a9, 0x0080, 0x6837, 0x0000, 0x680b, 0x0040, 0x7be4, 0xa386, + 0xfeff, 0x00c0, 0x1149, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, + 0x114d, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x0070, + 0x1153, 0x0078, 0x113a, 0x1078, 0x1eb8, 0x1078, 0x3654, 0x1078, + 0x1985, 0x1078, 0x3b0a, 0x3200, 0xa085, 0x000d, 0x2090, 0x70c3, + 0x0000, 0x0090, 0x116a, 0x70c0, 0xa086, 0x0002, 0x00c0, 0x116a, + 0x1078, 0x129f, 0x1078, 0x11b1, 0x78c0, 0xa005, 0x00c0, 0x1176, + 0x1078, 0x1b97, 0x0068, 0x117a, 0x1078, 0x1ddc, 0x0068, 0x117a, + 0x1078, 0x1a84, 0x00e0, 0x116a, 0x1078, 0x3983, 0x0078, 0x116a, + 0x1188, 0x118d, 0x2027, 0x2027, 0x36ce, 0x36ce, 0x2027, 0x2027, + 0x0088, 0x1188, 0x2091, 0x8001, 0x007c, 0x0088, 0x118d, 0x2091, + 0x8001, 0x007c, 0x0078, 0x1192, 0x0078, 0x1194, 0x2009, 0x0022, + 0x2104, 0xa086, 0x4000, 0x0040, 0x11ac, 0x7008, 0x800b, 0x00c8, + 0x11ac, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x11ad, 0xa084, + 0x0008, 0x0040, 0x11ac, 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, + 0x12a2, 0x0068, 0x121c, 0x2061, 0x0000, 0x6018, 0xa084, 0x0001, + 0x00c0, 0x121c, 0x7814, 0xa005, 0x00c0, 0x11c2, 0x0010, 0x121d, + 0x0078, 0x121c, 0x2009, 0x3c68, 0x2104, 0xa005, 0x00c0, 0x121c, + 0x2009, 0x3c71, 0x200b, 0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, + 0x11e7, 0x7816, 0x2009, 0x3c6f, 0x2164, 0x200b, 0x0000, 0x6018, + 0x70c6, 0x6014, 0x70ca, 0x611c, 0xa18c, 0xff00, 0x6020, 0xa084, + 0x00ff, 0xa105, 0x70ce, 0x1078, 0x1977, 0x0078, 0x121a, 0x7814, + 0xa086, 0x0018, 0x00c0, 0x11ee, 0x1078, 0x169d, 0x7817, 0x0000, + 0x2009, 0x3c6f, 0x2104, 0xa065, 0x0040, 0x120a, 0x0c7e, 0x609c, + 0x2060, 0x1078, 0x19d5, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x176e, + 0x2009, 0x001c, 0x6087, 0x0103, 0x1078, 0x18fe, 0x00c0, 0x1216, + 0x1078, 0x1977, 0x2009, 0x3c6f, 0x200b, 0x0000, 0x2009, 0x3c69, + 0x2104, 0x200b, 0x0000, 0xa005, 0x0040, 0x121a, 0x2001, 0x4005, + 0x0078, 0x12a1, 0x0078, 0x129f, 0x007c, 0x70c3, 0x0000, 0x70c7, + 0x0000, 0x70cb, 0x0000, 0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, + 0x00c0, 0x126d, 0x2038, 0x0079, 0x122d, 0x129f, 0x12fa, 0x12be, + 0x12fa, 0x1363, 0x1363, 0x12b5, 0x1786, 0x136e, 0x12ad, 0x12c2, + 0x12c4, 0x12c6, 0x12c8, 0x178b, 0x12ad, 0x1380, 0x13ab, 0x16b5, + 0x1780, 0x12ca, 0x15ca, 0x15ec, 0x160a, 0x1637, 0x1583, 0x1591, + 0x15a5, 0x15b9, 0x141e, 0x12ad, 0x13cc, 0x13d2, 0x13d7, 0x13dc, + 0x13e2, 0x13e7, 0x13ec, 0x13f1, 0x13f6, 0x13fa, 0x140f, 0x141b, + 0x12ad, 0x12ad, 0x12ad, 0x12ad, 0x142a, 0x1433, 0x1442, 0x1468, + 0x1472, 0x1479, 0x14b9, 0x14c8, 0x14d7, 0x14e9, 0x1563, 0x1573, + 0x12ad, 0x12ad, 0x12ad, 0x12ad, 0x1578, 0xa0bc, 0xffa0, 0x00c0, + 0x12ad, 0x2038, 0xa084, 0x001f, 0x0079, 0x1276, 0x17a2, 0x17a5, + 0x17b5, 0x185a, 0x1893, 0x18cf, 0x18ec, 0x12ad, 0x12ad, 0x12ad, + 0x18f0, 0x18f8, 0x12ad, 0x12ad, 0x12ad, 0x12ad, 0x12f0, 0x1359, + 0x1376, 0x13a1, 0x16ab, 0x12ad, 0x12ad, 0x12ad, 0x12ad, 0x12ad, + 0x18ab, 0x18b5, 0x18b9, 0x18c7, 0x12ad, 0x12ad, 0x72ca, 0x71c6, + 0x2001, 0x4006, 0x0078, 0x12a1, 0x73ce, 0x72ca, 0x71c6, 0x2001, + 0x4000, 0x70c2, 0x0068, 0x12a2, 0x2061, 0x0000, 0x601b, 0x0001, + 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001, 0x0078, + 0x12a2, 0x70c3, 0x4006, 0x0078, 0x12a2, 0x2099, 0x0041, 0x20a1, + 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, 0x129f, 0x70c4, 0x70c3, + 0x0004, 0x007a, 0x0078, 0x129f, 0x0078, 0x129f, 0x0078, 0x129f, + 0x0078, 0x129f, 0x2091, 0x8000, 0x70c3, 0x0000, 0x70c7, 0x4953, + 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0002, 0x3f00, 0x70d6, + 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, + 0x2029, 0x0457, 0x2051, 0x0470, 0x2061, 0x0472, 0x20b9, 0xffff, + 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091, 0x4080, 0x0078, 0x0455, + 0x1078, 0x1af1, 0x00c0, 0x12b1, 0x75d8, 0x74dc, 0x75da, 0x74de, + 0x0078, 0x12fd, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, + 0x70c4, 0x20a0, 0x2098, 0x2031, 0x0030, 0x81ff, 0x0040, 0x129f, + 0x7007, 0x0004, 0x731a, 0x721e, 0x7422, 0x7526, 0x2051, 0x0012, + 0x2049, 0x1338, 0x2041, 0x129f, 0x7003, 0x0002, 0xa786, 0x0001, + 0x0040, 0x1320, 0xa786, 0x0050, 0x0040, 0x1320, 0x0078, 0x1326, + 0x2049, 0x1345, 0x2041, 0x1351, 0x7003, 0x0003, 0x7017, 0x0000, + 0x810b, 0x7112, 0x00c8, 0x132e, 0x7017, 0x0001, 0x7007, 0x0001, + 0xa786, 0x0001, 0x0040, 0x1345, 0xa786, 0x0050, 0x0040, 0x1345, + 0x700c, 0xa084, 0x007f, 0x2009, 0x0040, 0xa102, 0x8004, 0x094a, + 0x20a8, 0x26a0, 0x53a6, 0x0078, 0x1196, 0x700c, 0xa084, 0x007f, + 0x0040, 0x1345, 0x80ac, 0x0048, 0x1345, 0x2698, 0x53a5, 0x0078, + 0x1196, 0x700c, 0xa084, 0x007f, 0x80ac, 0x2698, 0x53a5, 0x0078, + 0x129f, 0x1078, 0x1af1, 0x00c0, 0x12b1, 0x75d8, 0x74dc, 0x75da, + 0x74de, 0x0078, 0x12fd, 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, + 0x00c0, 0x136b, 0x200a, 0x72ca, 0x0078, 0x129e, 0x70c7, 0x0002, + 0x70cb, 0x0037, 0x70cf, 0x0007, 0x0078, 0x129f, 0x1078, 0x1af1, + 0x00c0, 0x12b1, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1383, + 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, + 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x139b, 0x8001, 0x788a, + 0x7a92, 0x7b96, 0x7d9a, 0x7e9e, 0x7c8e, 0x78c0, 0xa084, 0xfffc, + 0x78c2, 0x0078, 0x139f, 0x78c0, 0xa085, 0x0001, 0x78c2, 0x0078, + 0x129f, 0x1078, 0x1af1, 0x00c0, 0x12b1, 0x75d8, 0x76dc, 0x75da, + 0x76de, 0x0078, 0x13ae, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, + 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, + 0x13c6, 0x8001, 0x78a6, 0x7aae, 0x7bb2, 0x7db6, 0x7eba, 0x7caa, + 0x78c0, 0xa084, 0xfcff, 0x78c2, 0x0078, 0x13ca, 0x78c0, 0xa085, + 0x0100, 0x78c2, 0x0078, 0x129f, 0x2009, 0x3c5f, 0x210c, 0x7ae0, + 0x0078, 0x129d, 0x2009, 0x3c41, 0x210c, 0x0078, 0x129e, 0x2009, + 0x3c42, 0x210c, 0x0078, 0x129e, 0x2061, 0x3c40, 0x610c, 0x6210, + 0x0078, 0x129d, 0x2009, 0x3c45, 0x210c, 0x0078, 0x129e, 0x2009, + 0x3c46, 0x210c, 0x0078, 0x129e, 0x2009, 0x3c47, 0x210c, 0x0078, + 0x129e, 0x2009, 0x3c48, 0x210c, 0x0078, 0x129e, 0x7908, 0x7a0c, + 0x0078, 0x129d, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa0e8, 0x3d00, 0x6a00, 0x6804, 0xa084, 0x0008, 0x0040, + 0x140c, 0x6b08, 0x0078, 0x140d, 0x6b0c, 0x0078, 0x129c, 0x77c4, + 0x1078, 0x1995, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, + 0x2708, 0x0078, 0x129c, 0x794c, 0x0078, 0x129e, 0x77c4, 0x1078, + 0x1995, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091, 0x8001, + 0x0078, 0x129c, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x1297, 0x1078, + 0x1f4f, 0x0078, 0x129c, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x1297, + 0x2011, 0x3c41, 0x2204, 0x007e, 0x2112, 0x1078, 0x1f08, 0x017f, + 0x0078, 0x129e, 0x71c4, 0x2011, 0x1460, 0x20a9, 0x0008, 0x2204, + 0xa106, 0x0040, 0x1452, 0x8210, 0x0070, 0x1450, 0x0078, 0x1447, + 0x0078, 0x1297, 0xa292, 0x1460, 0x027e, 0x2011, 0x3c42, 0x2204, + 0x2112, 0x017f, 0x007e, 0x1078, 0x1f14, 0x017f, 0x0078, 0x129e, + 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, + 0x2061, 0x3c40, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8, 0x6012, + 0x0078, 0x129d, 0x2061, 0x3c40, 0x6114, 0x70c4, 0x6016, 0x0078, + 0x129e, 0x71c4, 0x2011, 0x0004, 0x2019, 0x1212, 0xa186, 0x0028, + 0x0040, 0x1492, 0x2011, 0x0005, 0x2019, 0x1212, 0xa186, 0x0032, + 0x0040, 0x1492, 0x2011, 0x0006, 0x2019, 0x1313, 0xa186, 0x003c, + 0x00c0, 0x1297, 0x2061, 0x3c40, 0x6018, 0x007e, 0x611a, 0x7800, + 0xa084, 0x0001, 0x00c0, 0x14af, 0x2001, 0x04fd, 0x2004, 0xa082, + 0x0005, 0x0048, 0x14a7, 0x0038, 0x14ab, 0x0078, 0x14af, 0x0028, + 0x14ab, 0x0078, 0x14af, 0x2019, 0x1313, 0x0078, 0x14b1, 0x2019, + 0x1212, 0x23b8, 0x1078, 0x1f25, 0x1078, 0x3b0a, 0x017f, 0x0078, + 0x129e, 0x71c4, 0xa184, 0xffcf, 0x00c0, 0x1297, 0x2011, 0x3c47, + 0x2204, 0x2112, 0x007e, 0x1078, 0x1f47, 0x017f, 0x0078, 0x129e, + 0x71c4, 0xa182, 0x0010, 0x00c8, 0x1297, 0x2011, 0x3c48, 0x2204, + 0x007e, 0x2112, 0x1078, 0x1f36, 0x017f, 0x0078, 0x129e, 0x71c4, + 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x1296, 0xa284, 0xfffd, 0x00c0, + 0x1296, 0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, + 0x129d, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xa0e8, 0x3d00, 0x2019, 0x0000, 0x72c8, 0xa284, 0x0080, 0x0040, + 0x14ff, 0x6c14, 0x84ff, 0x00c0, 0x14ff, 0x6817, 0x0040, 0xa284, + 0x0040, 0x0040, 0x1509, 0x6c10, 0x84ff, 0x00c0, 0x1509, 0x6813, + 0x0001, 0x6800, 0x007e, 0xa226, 0x0040, 0x152c, 0x6a02, 0xa484, + 0x2000, 0x0040, 0x1515, 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, + 0x151b, 0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x152c, 0x810f, + 0xa284, 0x4000, 0x0040, 0x1528, 0x1078, 0x1f69, 0x0078, 0x152c, + 0x1078, 0x1f5b, 0x0078, 0x152c, 0x72cc, 0x6808, 0xa206, 0x0040, + 0x155b, 0xa2a4, 0x00ff, 0x2061, 0x3c40, 0x6118, 0xa186, 0x0028, + 0x0040, 0x1542, 0xa186, 0x0032, 0x0040, 0x1548, 0xa186, 0x003c, + 0x0040, 0x154e, 0xa482, 0x0064, 0x0048, 0x1558, 0x0078, 0x1552, + 0xa482, 0x0050, 0x0048, 0x1558, 0x0078, 0x1552, 0xa482, 0x0043, + 0x0048, 0x1558, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x1298, + 0x6a0a, 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, + 0x71c4, 0x0078, 0x129c, 0x77c4, 0x1078, 0x1995, 0x2091, 0x8000, + 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, + 0x2708, 0x0078, 0x129c, 0x70c4, 0x794c, 0x784e, 0x0078, 0x129e, + 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x1297, 0x1078, + 0x1f77, 0x0078, 0x129c, 0x77c4, 0x1078, 0x1995, 0x2091, 0x8000, + 0x6a08, 0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, + 0x129d, 0x77c4, 0x1078, 0x1995, 0x2091, 0x8000, 0x6a08, 0xa294, + 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x15a0, 0x1078, 0x1e9d, + 0x2091, 0x8001, 0x2708, 0x0078, 0x129d, 0x77c4, 0x1078, 0x1995, + 0x2091, 0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, + 0x0040, 0x15b4, 0x1078, 0x1e9d, 0x2091, 0x8001, 0x2708, 0x0078, + 0x129d, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, + 0x2091, 0x8000, 0x1078, 0x19a2, 0x2091, 0x8001, 0x2708, 0x6a08, + 0x0078, 0x129d, 0x77c4, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, + 0x1078, 0x1a1d, 0x00c0, 0x15e8, 0x6818, 0xa005, 0x0040, 0x15e2, + 0x2708, 0x1078, 0x1f87, 0x00c0, 0x15e2, 0x7817, 0x0015, 0x2091, + 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, 0x0078, 0x12a1, + 0x2091, 0x8001, 0x0078, 0x129f, 0x77c4, 0x77c6, 0x2041, 0x0021, + 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, 0x19a2, + 0x2061, 0x3c40, 0x60a3, 0x0003, 0x67b6, 0x60c7, 0x000f, 0x60a7, + 0x0000, 0x7817, 0x0016, 0x2091, 0x8000, 0x1078, 0x1e9d, 0x2091, + 0x8001, 0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, + 0x2091, 0x8000, 0x2061, 0x3c40, 0x60a3, 0x0002, 0x60a7, 0x0000, + 0x67b6, 0x60c7, 0x000f, 0x7817, 0x0017, 0x2091, 0x8000, 0x1078, + 0x1e9d, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, + 0x0010, 0x2091, 0x8000, 0x1078, 0x19a2, 0x70c8, 0x6836, 0x8738, + 0xa784, 0x0007, 0x00c0, 0x162b, 0x2091, 0x8001, 0x007c, 0x78c0, + 0xa084, 0x0003, 0x00c0, 0x165b, 0x2039, 0x0000, 0x2041, 0x0021, + 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, 0x1995, 0x2091, 0x8000, + 0x6808, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x0007, + 0x00c0, 0x1644, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, + 0x0f00, 0x00c0, 0x1644, 0x2091, 0x8000, 0x2069, 0x0100, 0x6830, + 0xa084, 0x0040, 0x0040, 0x1684, 0x684b, 0x0004, 0x20a9, 0x0014, + 0x6848, 0xa084, 0x0004, 0x0040, 0x1671, 0x0070, 0x1671, 0x0078, + 0x1668, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, + 0x0040, 0x167e, 0x0070, 0x167e, 0x0078, 0x1675, 0x20a9, 0x00fa, + 0x0070, 0x1684, 0x0078, 0x1680, 0x2079, 0x3c00, 0x7817, 0x0018, + 0x2061, 0x3c40, 0x60a3, 0x0001, 0x60a7, 0x0000, 0x60c7, 0x000f, + 0x78c0, 0xa085, 0x0002, 0x78c2, 0x6808, 0xa084, 0xfffd, 0x680a, + 0x681b, 0x0047, 0x2091, 0x8001, 0x007c, 0x78c0, 0xa084, 0xfffd, + 0x78c2, 0xa084, 0x0001, 0x00c0, 0x16a7, 0x1078, 0x1a67, 0x71c4, + 0x71c6, 0x794a, 0x007c, 0x1078, 0x1af1, 0x00c0, 0x12b1, 0x75d8, + 0x74dc, 0x75da, 0x74de, 0x0078, 0x16b8, 0x2029, 0x0000, 0x2520, + 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x3c00, + 0x1078, 0x196e, 0x0040, 0x176a, 0x20a9, 0x0005, 0x20a1, 0x3c16, + 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0040, 0x1078, + 0x1938, 0x0040, 0x16d7, 0x1078, 0x1977, 0x0078, 0x176a, 0x6004, + 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x1738, 0x0c7e, 0x2c68, + 0x1078, 0x196e, 0x0040, 0x1707, 0x2c00, 0x689e, 0x8109, 0x00c0, + 0x16df, 0x609f, 0x0000, 0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, + 0x7524, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1737, 0x2009, 0x0040, + 0x1078, 0x1938, 0x00c0, 0x1720, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x0002, 0x00c0, 0x1707, 0x2d00, 0x6002, 0x0078, 0x16ed, 0x0c7f, + 0x0c7e, 0x609c, 0x2060, 0x1078, 0x19d5, 0x0c7f, 0x609f, 0x0000, + 0x1078, 0x176e, 0x2009, 0x001c, 0x6008, 0xa085, 0x0200, 0x600a, + 0x6004, 0x6086, 0x1078, 0x18fe, 0x1078, 0x1977, 0x0078, 0x176a, + 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x19d5, 0x0c7f, 0x609f, + 0x0000, 0x1078, 0x176e, 0x2009, 0x001c, 0x6087, 0x0103, 0x601b, + 0x0003, 0x1078, 0x18fe, 0x1078, 0x1977, 0x0078, 0x176a, 0x0c7f, + 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x7817, 0x0012, + 0x0e7e, 0x2071, 0x3c40, 0x70a3, 0x0005, 0x70a7, 0x0000, 0x73aa, + 0x72ae, 0x74b2, 0x70b6, 0x70bb, 0x0000, 0x2c00, 0x70be, 0x70c3, + 0x0000, 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x175a, + 0x1078, 0x35f8, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, + 0x0000, 0x60b3, 0x0000, 0x2091, 0x8000, 0x1078, 0x1e9d, 0x2091, + 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x12a2, 0x20a9, 0x0005, + 0x2099, 0x3c16, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, + 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, + 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x129f, 0x71c4, 0x71c6, + 0x2168, 0x0078, 0x178d, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, + 0xa210, 0x8d68, 0x8109, 0x00c0, 0x178f, 0xa285, 0x0000, 0x00c0, + 0x179d, 0x70c3, 0x4000, 0x0078, 0x179f, 0x70c3, 0x4003, 0x70ca, + 0x0078, 0x12a2, 0x79d8, 0x0078, 0x129e, 0x71c4, 0x71c6, 0x2198, + 0x20a1, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x21a0, 0x2099, 0x0042, + 0x20a9, 0x0004, 0x53a3, 0x0078, 0x129f, 0x70c4, 0x2068, 0x2079, + 0x3c00, 0x1078, 0x196e, 0x00c0, 0x17c1, 0x70c3, 0x4005, 0x0078, + 0x12a2, 0x6007, 0x0001, 0x600b, 0x0000, 0x602b, 0x0000, 0x601b, + 0x0006, 0x6a10, 0xa28c, 0x0007, 0xa284, 0x00f0, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0x6016, 0xa284, 0x0800, 0x0040, 0x17dc, + 0x601b, 0x000a, 0x0078, 0x17e2, 0xa284, 0x1000, 0x0040, 0x17e2, + 0x601b, 0x000c, 0xa284, 0x0300, 0x0040, 0x17eb, 0x602b, 0x0001, + 0x8004, 0x8004, 0x8004, 0xa085, 0x0001, 0x601e, 0x6023, 0x0000, + 0x6027, 0x0000, 0xa284, 0x0400, 0x0040, 0x17f8, 0x602b, 0x0000, + 0x20a9, 0x0006, 0xac80, 0x000b, 0x20a0, 0xad80, 0x0005, 0x2098, + 0x53a3, 0xa284, 0x0300, 0x00c0, 0x180d, 0x6046, 0x604a, 0x604e, + 0x6052, 0x6096, 0x609a, 0x0078, 0x1817, 0x6800, 0x6046, 0x6804, + 0x604a, 0x6e08, 0x664e, 0x6d0c, 0x6552, 0x6596, 0x669a, 0x6014, + 0x2091, 0x8000, 0x7817, 0x0042, 0x2c08, 0x2061, 0x3c40, 0x60a3, + 0x0005, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x60af, 0x0000, 0x60b3, + 0x0000, 0x60b6, 0x61be, 0xa284, 0x0400, 0x60c2, 0x2091, 0x8001, + 0x0e7e, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, + 0x0000, 0x0e7f, 0x2091, 0x8000, 0x1078, 0x1e9d, 0x2091, 0x8001, + 0x007c, 0x70c4, 0x2068, 0x2079, 0x3c00, 0x1078, 0x196e, 0x0040, + 0x1856, 0x6007, 0x0001, 0x600b, 0x0000, 0x602b, 0x0000, 0x601b, + 0x0006, 0x70c8, 0x6016, 0x6a10, 0x0078, 0x17d4, 0x70c3, 0x4005, + 0x0078, 0x12a2, 0x78ec, 0xa005, 0x0040, 0x12ad, 0x2091, 0x8000, + 0x70c4, 0x800a, 0x2011, 0x0010, 0x810c, 0x0048, 0x186c, 0x3a00, + 0xa084, 0xfff7, 0x0078, 0x186f, 0x3a00, 0xa085, 0x0008, 0x20d0, + 0x0005, 0x0005, 0xa084, 0xfffb, 0x20d0, 0x0005, 0x0005, 0x0005, + 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0xa085, 0x0004, 0x20d0, + 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, + 0x8211, 0x00c0, 0x1864, 0x3a00, 0xa085, 0x0008, 0x20d0, 0x2091, + 0x8001, 0x0078, 0x129f, 0x2011, 0x04fd, 0x2204, 0xa082, 0x0004, + 0x0048, 0x18a7, 0x78ef, 0x0001, 0x2009, 0xff01, 0x200a, 0x2001, + 0x000c, 0x20d8, 0x2001, 0x000c, 0x20d0, 0x0078, 0x129f, 0x2001, + 0x4005, 0x0078, 0x12a1, 0x7978, 0x71c6, 0x71c4, 0xa182, 0x0003, + 0x00c8, 0x1297, 0x797a, 0x0078, 0x129f, 0x7978, 0x71c6, 0x0078, + 0x129f, 0x796c, 0x71c6, 0x71c4, 0x796e, 0x7970, 0x71ca, 0x71c8, + 0x7972, 0x7974, 0x71ce, 0x71cc, 0x7976, 0x0078, 0x129f, 0x796c, + 0x71c6, 0x7970, 0x71ca, 0x7974, 0x71ce, 0x0078, 0x129f, 0x7900, + 0x71c6, 0x71c4, 0x7902, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, + 0x0048, 0x18de, 0x0038, 0x18e0, 0x0078, 0x18ea, 0x00a8, 0x18ea, + 0xa18c, 0x0001, 0x00c0, 0x18e8, 0x20b9, 0x1313, 0x0078, 0x18ea, + 0x20b9, 0x1212, 0x0078, 0x129f, 0x7900, 0x71c6, 0x0078, 0x129f, + 0x2009, 0x3c79, 0x2104, 0x70c6, 0x70c4, 0x200a, 0x0078, 0x129f, + 0x2009, 0x3c79, 0x2104, 0x70c6, 0x0078, 0x129f, 0x700c, 0xa084, + 0x00ff, 0x0040, 0x190a, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x1905, 0x7017, 0x0000, 0x7112, 0x721a, 0x731e, 0x7422, + 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, 0x8098, 0x20a1, + 0x0030, 0x6084, 0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, 0x7002, + 0x7007, 0x0001, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, + 0x1922, 0x7108, 0x8103, 0x00c8, 0x1922, 0x7014, 0xa005, 0x0040, + 0x1922, 0x7007, 0x0002, 0xa184, 0x01e0, 0x7003, 0x0000, 0x007c, + 0x700c, 0xa084, 0x00ff, 0x0040, 0x1944, 0x7007, 0x0004, 0x7004, + 0xa084, 0x0004, 0x00c0, 0x193f, 0x7017, 0x0000, 0x7112, 0x721a, + 0x7422, 0x7526, 0x731e, 0x2099, 0x0030, 0x8108, 0x81ac, 0x780c, + 0xa085, 0x0001, 0x7002, 0x7007, 0x0001, 0x2009, 0x0022, 0x2104, + 0xa084, 0x4000, 0x00c0, 0x1955, 0x7008, 0x800b, 0x00c8, 0x1955, + 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x196b, 0xac80, 0x0001, + 0x20a0, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x7850, 0xa065, + 0x0040, 0x1976, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, 0x0f7e, + 0x2079, 0x3c00, 0x7850, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1982, + 0x1078, 0x2007, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x4800, 0x7a52, + 0x7be0, 0x8319, 0x0040, 0x1992, 0xa280, 0x002f, 0x2012, 0x2010, + 0x0078, 0x1989, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800c, + 0xa784, 0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, + 0x3d80, 0x007c, 0x1078, 0x1995, 0x2900, 0x682a, 0x2a00, 0x682e, + 0x6808, 0xa084, 0xffef, 0xa80d, 0x690a, 0x2009, 0x3c4f, 0x210c, + 0x6804, 0xa005, 0x0040, 0x19bf, 0xa116, 0x00c0, 0x19bf, 0x2060, + 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x19c2, 0x2009, + 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x19d1, 0x6000, 0x6806, + 0x1078, 0x19e2, 0x1078, 0x1b12, 0x6810, 0x8001, 0x6812, 0x00c0, + 0x19c2, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x19e1, + 0x609c, 0x609f, 0x0000, 0x2008, 0x1078, 0x1977, 0x2100, 0x0078, + 0x19d5, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, + 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, + 0x682c, 0x6022, 0x007c, 0x0e7e, 0x2071, 0x3c40, 0x7040, 0xa08c, + 0x0080, 0x00c0, 0x1a01, 0xa088, 0x3c80, 0x2d0a, 0x8000, 0x7042, + 0xa006, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x3c40, 0x2009, 0x3c80, + 0x7240, 0x8221, 0x8211, 0x0048, 0x1a1b, 0x2104, 0x8108, 0xad06, + 0x00c0, 0x1a0a, 0x8119, 0x211e, 0x8108, 0x8318, 0x8211, 0x00c8, + 0x1a13, 0x7442, 0xa006, 0x0e7f, 0x007c, 0x1078, 0x1995, 0x2091, + 0x8000, 0x6804, 0x781e, 0xa065, 0x0040, 0x1a66, 0x0078, 0x1a2e, + 0x2c00, 0x781e, 0x6000, 0xa065, 0x0040, 0x1a66, 0x6010, 0xa306, + 0x00c0, 0x1a28, 0x600c, 0xa206, 0x00c0, 0x1a28, 0x2c28, 0x2001, + 0x3c4f, 0x2004, 0xac06, 0x00c0, 0x1a3f, 0x0078, 0x1a63, 0x6804, + 0xac06, 0x00c0, 0x1a4d, 0x6000, 0x2060, 0x6806, 0xa005, 0x00c0, + 0x1a4d, 0x6803, 0x0000, 0x0078, 0x1a57, 0x6400, 0x781c, 0x2060, + 0x6402, 0xa486, 0x0000, 0x00c0, 0x1a57, 0x2c00, 0x6802, 0x2560, + 0x1078, 0x19e2, 0x601b, 0x0005, 0x6023, 0x0020, 0x1078, 0x1b12, + 0x6810, 0x8001, 0x6812, 0x2001, 0xffff, 0xa005, 0x007c, 0x2039, + 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, + 0x8000, 0x1078, 0x19a2, 0x8738, 0xa784, 0x0007, 0x00c0, 0x1a71, + 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, + 0x1a71, 0x2091, 0x8001, 0x007c, 0x2061, 0x0000, 0x6018, 0xa084, + 0x0001, 0x00c0, 0x1a95, 0x2091, 0x8000, 0x78d4, 0x78d7, 0x0000, + 0x2091, 0x8001, 0xa005, 0x00c0, 0x1a96, 0x007c, 0xa08c, 0xfff0, + 0x0040, 0x1a9c, 0x1078, 0x2007, 0x0079, 0x1a9e, 0x1aae, 0x1ab1, + 0x1ab7, 0x1abb, 0x1aaf, 0x1abf, 0x1aaf, 0x1ac5, 0x1ac9, 0x1acd, + 0x1b00, 0x1b04, 0x1aaf, 0x1aaf, 0x1aaf, 0x1aaf, 0x007c, 0x1078, + 0x2007, 0x1078, 0x1a67, 0x2001, 0x8001, 0x0078, 0x1b0a, 0x2001, + 0x8003, 0x0078, 0x1b0a, 0x2001, 0x8004, 0x0078, 0x1b0a, 0x1078, + 0x1a67, 0x2001, 0x8006, 0x0078, 0x1b0a, 0x2001, 0x8008, 0x0078, + 0x1b0a, 0x2001, 0x8009, 0x0078, 0x1b0a, 0x2091, 0x8000, 0x2069, + 0x3c40, 0x6800, 0xa086, 0x0000, 0x0040, 0x1adb, 0x2091, 0x8001, + 0x78d7, 0x0009, 0x007c, 0x68b4, 0xa0bc, 0xff00, 0x2041, 0x0021, + 0x2049, 0x0004, 0x2051, 0x0010, 0x1078, 0x19a2, 0x8738, 0xa784, + 0x0007, 0x00c0, 0x1ae4, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, + 0x1b0a, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0004, 0x00c8, 0x1afa, + 0x0078, 0x1afd, 0xa006, 0x0078, 0x1aff, 0xa085, 0x0001, 0x007c, + 0x2001, 0x800c, 0x0078, 0x1b0a, 0x1078, 0x1a67, 0x2001, 0x800d, + 0x0078, 0x1b0a, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, + 0x4080, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, 0x787c, + 0x8000, 0x787e, 0x7880, 0xa005, 0x7982, 0x0040, 0x1b22, 0x2c02, + 0x0078, 0x1b23, 0x7986, 0x007c, 0x0c7e, 0x2061, 0x3c00, 0x6887, + 0x0103, 0x2d08, 0x206b, 0x0000, 0x607c, 0x8000, 0x607e, 0x6080, + 0xa005, 0x6182, 0x0040, 0x1b37, 0x2d02, 0x0078, 0x1b38, 0x6186, + 0x0c7f, 0x007c, 0x1078, 0x1b4b, 0x0040, 0x1b4a, 0x0c7e, 0x609c, + 0xa065, 0x0040, 0x1b45, 0x1078, 0x19d5, 0x0c7f, 0x609f, 0x0000, + 0x1078, 0x1977, 0x007c, 0x7884, 0xa065, 0x0040, 0x1b5d, 0x2091, + 0x8000, 0x787c, 0x8001, 0x787e, 0x2c04, 0x7886, 0xa005, 0x00c0, + 0x1b5b, 0x7882, 0x8000, 0x2091, 0x8001, 0x007c, 0x20a9, 0x0010, + 0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x1b67, 0xa200, 0x0070, + 0x1b6b, 0x0078, 0x1b62, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, + 0x0010, 0xa005, 0x0040, 0x1b91, 0xa11a, 0x00c8, 0x1b91, 0x8213, + 0x818d, 0x0048, 0x1b82, 0xa11a, 0x00c8, 0x1b83, 0x0070, 0x1b89, + 0x0078, 0x1b77, 0xa11a, 0x2308, 0x8210, 0x0070, 0x1b89, 0x0078, + 0x1b77, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, + 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x1b8d, 0x798c, + 0x70d0, 0x007e, 0x007f, 0xa106, 0x0040, 0x1c13, 0x7800, 0xa084, + 0x0002, 0x0040, 0x1baa, 0x2011, 0x04fd, 0x2204, 0xa082, 0x0005, + 0x00c8, 0x1bbd, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, + 0x00c0, 0x1c13, 0x7008, 0x7208, 0xa206, 0x00c0, 0x1c13, 0xa286, + 0x0008, 0x00c0, 0x1c13, 0x2071, 0x0010, 0x1078, 0x196e, 0x0040, + 0x1c13, 0x7a94, 0x7b90, 0x7c9c, 0x7d98, 0xa184, 0xff00, 0x0040, + 0x1be1, 0x2031, 0x0000, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, + 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x2100, + 0xa210, 0x2600, 0xa319, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, + 0x1beb, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0xa4a1, + 0x0000, 0xa5a9, 0x0000, 0x2009, 0x0040, 0x1078, 0x1938, 0x2091, + 0x8001, 0x0040, 0x1c0a, 0x1078, 0x1977, 0x78a0, 0x8000, 0x78a2, + 0xa086, 0x0002, 0x00c0, 0x1c13, 0x2091, 0x8000, 0x78d7, 0x0002, + 0x78a3, 0x0000, 0x78c0, 0xa085, 0x0003, 0x78c2, 0x2091, 0x8001, + 0x0078, 0x1c13, 0x78a3, 0x0000, 0x1078, 0x1da5, 0x6004, 0xa084, + 0x000f, 0x0079, 0x1c18, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, + 0x1c28, 0x1c4a, 0x1c70, 0x1c28, 0x1c82, 0x1c37, 0x1c28, 0x1c28, + 0x1c28, 0x1c44, 0x1c6a, 0x1c28, 0x1c28, 0x1c28, 0x1c28, 0x1c28, + 0x2039, 0x0400, 0x78d0, 0xa705, 0x78d2, 0x6008, 0xa705, 0x600a, + 0x1078, 0x1cc0, 0x609c, 0x78ce, 0x1078, 0x1d8d, 0x007c, 0x78d0, + 0xa084, 0x0100, 0x0040, 0x1c3e, 0x0078, 0x1c28, 0x601c, 0xa085, + 0x0080, 0x601e, 0x0078, 0x1c51, 0x1078, 0x1af1, 0x00c0, 0x1c28, + 0x1078, 0x1dbf, 0x78d0, 0xa084, 0x0100, 0x0040, 0x1c51, 0x0078, + 0x1c28, 0x78d3, 0x0000, 0x6004, 0x8007, 0xa084, 0x00ff, 0x78c6, + 0x8001, 0x609f, 0x0000, 0x0040, 0x1c67, 0x1078, 0x1cc0, 0x0040, + 0x1c67, 0x78d0, 0xa085, 0x0100, 0x78d2, 0x0078, 0x1c69, 0x1078, + 0x1ce4, 0x007c, 0x1078, 0x1af1, 0x00c0, 0x1c28, 0x1078, 0x1dbb, + 0x78d0, 0xa08c, 0x0e00, 0x00c0, 0x1c79, 0xa084, 0x0100, 0x00c0, + 0x1c7b, 0x0078, 0x1c28, 0x1078, 0x1cc0, 0x00c0, 0x1c81, 0x1078, + 0x1ce4, 0x007c, 0x78d0, 0xa084, 0x0100, 0x0040, 0x1c89, 0x0078, + 0x1c28, 0x78d3, 0x0000, 0x6714, 0x20a9, 0x0001, 0x6018, 0xa084, + 0x00ff, 0xa005, 0x0040, 0x1ca6, 0xa7bc, 0xff00, 0x20a9, 0x0008, + 0xa08e, 0x0001, 0x0040, 0x1ca6, 0x2039, 0x0000, 0x20a9, 0x0080, + 0xa08e, 0x0002, 0x0040, 0x1ca6, 0x0078, 0x1cbd, 0x1078, 0x1995, + 0x2d00, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, + 0xa084, 0xffde, 0x680a, 0x2d00, 0xa080, 0x0010, 0x2068, 0x2091, + 0x8001, 0x0070, 0x1cbd, 0x0078, 0x1ca9, 0x1078, 0x1977, 0x007c, + 0x78c8, 0xa06d, 0x00c0, 0x1ccb, 0x2c00, 0x78ca, 0x78ce, 0x609f, + 0x0000, 0x0078, 0x1cd7, 0x2c00, 0x689e, 0x609f, 0x0000, 0x78ca, + 0x2d00, 0x6002, 0x78cc, 0xad06, 0x00c0, 0x1cd7, 0x6002, 0x78c4, + 0x8001, 0x78c6, 0x00c0, 0x1ce3, 0x78d0, 0xa084, 0x0000, 0x78d2, + 0x78cc, 0x2060, 0xa006, 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, + 0xa184, 0xe1ff, 0x601e, 0xa184, 0x0060, 0x0040, 0x1cf3, 0x0e7e, + 0x1078, 0x35f8, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, + 0x0000, 0x60b3, 0x0000, 0x6714, 0x1078, 0x1995, 0x2091, 0x8000, + 0x60a0, 0xa084, 0x8000, 0x00c0, 0x1d1a, 0x6808, 0xa084, 0x0001, + 0x0040, 0x1d1a, 0x2091, 0x8001, 0x1078, 0x19e2, 0x2091, 0x8000, + 0x1078, 0x1b12, 0x2091, 0x8001, 0x78cb, 0x0000, 0x78cf, 0x0000, + 0x0078, 0x1d8c, 0x6024, 0xa096, 0x0001, 0x00c0, 0x1d21, 0x8000, + 0x6026, 0x6a10, 0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x1d30, + 0x0040, 0x1d30, 0x2039, 0x0200, 0x1078, 0x1d8d, 0x0078, 0x1d8c, + 0x2c08, 0x2091, 0x8000, 0x60a0, 0xa084, 0x8000, 0x0040, 0x1d5d, + 0x6800, 0xa065, 0x0040, 0x1d62, 0x6a04, 0x0e7e, 0x2071, 0x3c40, + 0x7000, 0xa084, 0x0001, 0x0040, 0x1d57, 0x703c, 0xa206, 0x00c0, + 0x1d57, 0x6b04, 0x231c, 0x2160, 0x6302, 0x2300, 0xa005, 0x00c0, + 0x1d52, 0x6902, 0x2260, 0x6102, 0x0e7f, 0x0078, 0x1d69, 0x2160, + 0x6202, 0x6906, 0x0e7f, 0x0078, 0x1d69, 0x6800, 0xa065, 0x0040, + 0x1d62, 0x6102, 0x6902, 0x00c0, 0x1d66, 0x6906, 0x2160, 0x6003, + 0x0000, 0x2160, 0x60a0, 0xa084, 0x8000, 0x0040, 0x1d73, 0x6808, + 0xa084, 0xfffc, 0x680a, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, + 0x6808, 0xa08c, 0x0040, 0x0040, 0x1d82, 0xa086, 0x0040, 0x680a, + 0x1078, 0x19f3, 0x2091, 0x8000, 0x1078, 0x1e9d, 0x2091, 0x8001, + 0x78cf, 0x0000, 0x78cb, 0x0000, 0x007c, 0x6008, 0xa705, 0x600a, + 0x2091, 0x8000, 0x1078, 0x1b12, 0x2091, 0x8001, 0x78cc, 0xa065, + 0x0040, 0x1da0, 0x609c, 0x78ce, 0x609f, 0x0000, 0x0078, 0x1d90, + 0x78cb, 0x0000, 0x78cf, 0x0000, 0x007c, 0x7988, 0x788c, 0x8000, + 0xa10a, 0x00c8, 0x1dac, 0xa006, 0x788e, 0x70d2, 0x7804, 0xa005, + 0x0040, 0x1dba, 0x8001, 0x7806, 0x00c0, 0x1dba, 0x0068, 0x1dba, + 0x2091, 0x4080, 0x007c, 0x2039, 0x1dd3, 0x0078, 0x1dc1, 0x2039, + 0x1dd9, 0x2704, 0xa005, 0x0040, 0x1dd2, 0xac00, 0x2068, 0x6b08, + 0x6c0c, 0x6910, 0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16, 0x8738, + 0x0078, 0x1dc1, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, + 0x0000, 0x0015, 0x001b, 0x0000, 0x0068, 0x1e22, 0x2029, 0x0000, + 0x7884, 0xa065, 0x0040, 0x1e1d, 0x2009, 0x3c79, 0x2104, 0xa084, + 0x0001, 0x0040, 0x1e10, 0x6084, 0xa086, 0x0103, 0x00c0, 0x1e10, + 0x6018, 0xa005, 0x00c0, 0x1e10, 0x6014, 0xa005, 0x00c0, 0x1e10, + 0x0d7e, 0x2069, 0x0000, 0x6818, 0xa084, 0x0001, 0x00c0, 0x1e0f, + 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, + 0x2091, 0x4080, 0x0d7f, 0x1078, 0x1b3a, 0x0078, 0x1e1d, 0x0d7f, + 0x1078, 0x1e23, 0x0040, 0x1e1d, 0x057e, 0x1078, 0x1e34, 0x057f, + 0x00c0, 0x1e1d, 0x8528, 0x0078, 0x1de0, 0x85ff, 0x0040, 0x1e22, + 0x2091, 0x4080, 0x007c, 0x7ba4, 0x79a8, 0x70d4, 0x007e, 0x007f, + 0xa102, 0x00c0, 0x1e2e, 0x2300, 0xa005, 0x007c, 0x0048, 0x1e32, + 0xa302, 0x007c, 0x8002, 0x007c, 0x7800, 0xa084, 0x0002, 0x0040, + 0x1e40, 0x2011, 0x04fd, 0x2204, 0xa082, 0x0005, 0x00c8, 0x1e53, + 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1e84, + 0x7008, 0x7208, 0xa206, 0x00c0, 0x1e84, 0xa286, 0x0008, 0x00c0, + 0x1e84, 0x2071, 0x0010, 0x1078, 0x1e89, 0x2009, 0x001c, 0x6028, + 0xa005, 0x0040, 0x1e5d, 0x2009, 0x0040, 0x1078, 0x18fe, 0x0040, + 0x1e76, 0x78bc, 0x8000, 0x78be, 0xa086, 0x0002, 0x00c0, 0x1e84, + 0x2091, 0x8000, 0x78d7, 0x0003, 0x78bf, 0x0000, 0x78c0, 0xa085, + 0x0300, 0x78c2, 0x2091, 0x8001, 0x0078, 0x1e84, 0x78bf, 0x0000, + 0x1078, 0x1b3a, 0x79a4, 0x78a8, 0x8000, 0xa10a, 0x00c8, 0x1e81, + 0xa006, 0x78aa, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, + 0x007c, 0x8107, 0x8004, 0x8004, 0x7ab0, 0x7bac, 0x7cb8, 0x7db4, + 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, + 0x2009, 0x3c68, 0x2091, 0x8000, 0x200a, 0x0f7e, 0x2079, 0x0100, + 0x2009, 0x3c40, 0x2104, 0xa086, 0x0000, 0x00c0, 0x1eb6, 0x2009, + 0x3c12, 0x2104, 0xa005, 0x00c0, 0x1eb6, 0x7830, 0xa084, 0x00c0, + 0x00c0, 0x1eb6, 0x0018, 0x1eb6, 0x781b, 0x0045, 0x0f7f, 0x007c, + 0x127e, 0x2091, 0x2300, 0x2071, 0x3c40, 0x2079, 0x0100, 0x784b, + 0x000f, 0x2019, 0x34bd, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, + 0x1ed2, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, + 0x0078, 0x1ec5, 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, + 0x78af, 0x0020, 0x0070, 0x1ede, 0x0078, 0x1ed6, 0x7003, 0x0000, + 0x1078, 0x1ff0, 0x7004, 0xa084, 0x000f, 0x017e, 0x2009, 0x04fd, + 0x210c, 0xa18a, 0x0005, 0x0048, 0x1ef5, 0x0038, 0x1ef1, 0x0078, + 0x1ef5, 0xa085, 0x62c0, 0x0078, 0x1ef7, 0xa085, 0x6280, 0x017f, + 0x7806, 0x780f, 0x9200, 0x7843, 0x00d8, 0x7853, 0x0080, 0x780b, + 0x0008, 0x7047, 0x3c7f, 0x7043, 0x0000, 0x127f, 0x2000, 0x007c, + 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084, 0xfff0, 0xa105, + 0x2012, 0x1078, 0x1ff0, 0x007c, 0x2011, 0x0101, 0x20a9, 0x0009, + 0x810b, 0x0070, 0x1f1d, 0x0078, 0x1f18, 0xa18c, 0x0e00, 0x2204, + 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009, 0x0101, 0x20a9, + 0x0005, 0x8213, 0x0070, 0x1f2e, 0x0078, 0x1f29, 0xa294, 0x00e0, + 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c, 0x2011, 0x0101, + 0x20a9, 0x000c, 0x810b, 0x0070, 0x1f3f, 0x0078, 0x1f3a, 0xa18c, + 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x007c, 0x2011, + 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c, 0x8103, + 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x62ac, + 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, + 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, + 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, + 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f, 0x007c, 0x8103, + 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, + 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, + 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, 0x1fce, 0x2061, + 0x4680, 0x1078, 0x1fd6, 0x0040, 0x1fba, 0x20a9, 0x0000, 0x2061, + 0x4580, 0x0c7e, 0x1078, 0x1fd6, 0x0040, 0x1fa6, 0x0c7f, 0x8c60, + 0x0070, 0x1fa4, 0x0078, 0x1f99, 0x0078, 0x1fce, 0x007f, 0xa082, + 0x4580, 0x2071, 0x3c40, 0x70ba, 0x6020, 0xa085, 0x0800, 0x6022, + 0x71b6, 0x2001, 0x0004, 0x70a2, 0x70c7, 0x000f, 0x1078, 0x1e98, + 0x0078, 0x1fca, 0x2071, 0x3c40, 0x6020, 0xa085, 0x0800, 0x6022, + 0x71b6, 0x2c00, 0x70be, 0x2001, 0x0006, 0x70a2, 0x70c7, 0x000f, + 0x1078, 0x1e98, 0x2001, 0x0000, 0x0078, 0x1fd0, 0x2001, 0x0001, + 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, + 0x0040, 0x1fed, 0x2060, 0x6010, 0xa306, 0x00c0, 0x1fea, 0x600c, + 0xa206, 0x00c0, 0x1fea, 0x6014, 0xa106, 0x00c0, 0x1fea, 0xa006, + 0x0078, 0x1fef, 0x6000, 0x0078, 0x1fd7, 0xa085, 0x0001, 0x007c, + 0x2011, 0x3c41, 0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, + 0xa084, 0x0100, 0x0040, 0x2006, 0x2021, 0xff04, 0x2122, 0x810b, + 0x810b, 0x810b, 0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0068, + 0x2007, 0x2091, 0x8000, 0x2071, 0x0000, 0x007e, 0x7018, 0xa084, + 0x0001, 0x00c0, 0x200e, 0x007f, 0x2071, 0x0010, 0x70ca, 0x007f, + 0x70c6, 0x70c3, 0x8002, 0x70db, 0x0237, 0x70df, 0x0007, 0x2071, + 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x2025, 0x107e, + 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, + 0x2009, 0x3c74, 0x78a0, 0x200a, 0x8108, 0x250a, 0x8108, 0x240a, + 0x8108, 0x260a, 0x8108, 0x270a, 0xa594, 0x003f, 0xa484, 0x4000, + 0x0040, 0x2048, 0xa784, 0x007c, 0x00c0, 0x344a, 0x1078, 0x2007, + 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x2050, 0x1078, 0x2007, + 0x8507, 0xa084, 0x000f, 0x0079, 0x2055, 0x24ff, 0x25be, 0x25e4, + 0x2858, 0x2ad4, 0x2b32, 0x2b78, 0x2bfd, 0x2c9f, 0x2d2c, 0x207d, + 0x2065, 0x2358, 0x2421, 0x2aaf, 0x2065, 0x1078, 0x2007, 0x0018, + 0x202c, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7003, + 0x0000, 0x703f, 0x0000, 0x7030, 0xa005, 0x0040, 0x2079, 0x7033, + 0x0000, 0x1078, 0x3425, 0x0018, 0x202c, 0x2009, 0x3c0f, 0x200b, + 0x0000, 0x705c, 0xa005, 0x00c0, 0x2152, 0x70a0, 0xa084, 0x0007, + 0x0079, 0x208a, 0x217e, 0x2092, 0x20a0, 0x20bd, 0x20df, 0x212c, + 0x2105, 0x2092, 0x7808, 0xa084, 0xfffd, 0x780a, 0x2009, 0x0047, + 0x1078, 0x2996, 0x00c0, 0x209e, 0x7003, 0x0004, 0x0078, 0x2067, + 0x1078, 0x340c, 0x00c0, 0x20bb, 0x70b4, 0x8007, 0x7882, 0x789b, + 0x0010, 0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, + 0x0004, 0x2009, 0x00fb, 0x1078, 0x2994, 0x00c0, 0x20bb, 0x7003, + 0x0004, 0x70c7, 0x000f, 0x0078, 0x2067, 0x1078, 0x340c, 0x00c0, + 0x20dd, 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007, + 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, + 0x0002, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, 0x2994, 0x00c0, + 0x20dd, 0x7003, 0x0004, 0x70c7, 0x000f, 0x0078, 0x2067, 0x1078, + 0x340c, 0x00c0, 0x2103, 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, + 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x71b8, + 0x79aa, 0x78ab, 0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, + 0x0004, 0x2009, 0x00fb, 0x1078, 0x2994, 0x00c0, 0x2103, 0x7003, + 0x0004, 0x70c7, 0x000f, 0x0078, 0x2067, 0x1078, 0x340c, 0x00c0, + 0x212a, 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007, + 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, + 0x0002, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, 0x2994, 0x00c0, + 0x212a, 0x70bc, 0x70bf, 0x0000, 0x2068, 0x703e, 0x7003, 0x0002, + 0x70c7, 0x000f, 0x0078, 0x2067, 0x1078, 0x340c, 0x00c0, 0x2067, + 0x70bc, 0x2068, 0x6f14, 0x1078, 0x3348, 0x2c50, 0x1078, 0x34ab, + 0x789b, 0x0010, 0x6814, 0xa084, 0x0007, 0xa085, 0x0080, 0x007e, + 0x007f, 0x78aa, 0x6e1c, 0x067e, 0x067f, 0x2041, 0x0001, 0x70c0, + 0xa084, 0x0400, 0x2001, 0x0004, 0x0040, 0x2150, 0x2001, 0x0006, + 0x0078, 0x2274, 0x1078, 0x340c, 0x00c0, 0x2067, 0x789b, 0x0010, + 0x705c, 0x2068, 0x6f14, 0x1078, 0x3348, 0x2c50, 0x1078, 0x34ab, + 0x6008, 0xa085, 0x0010, 0x600a, 0x6824, 0xa005, 0x0040, 0x2170, + 0xa082, 0x0006, 0x0048, 0x216e, 0x0078, 0x2170, 0x6827, 0x0005, + 0x6814, 0xa084, 0x0007, 0xa085, 0x0080, 0x78aa, 0x2031, 0x0020, + 0x2041, 0x0001, 0x2001, 0x0003, 0x0078, 0x2274, 0x0018, 0x202c, + 0x7440, 0xa485, 0x0000, 0x0040, 0x21a8, 0xa080, 0x3c80, 0x2030, + 0x7144, 0x0018, 0x202c, 0x8108, 0xa12a, 0x0048, 0x2191, 0x2009, + 0x3c80, 0x2164, 0x6504, 0x85ff, 0x00c0, 0x21b5, 0x8421, 0x00c0, + 0x2189, 0x017e, 0x2009, 0x3c0f, 0x2104, 0xa005, 0x00c0, 0x21a6, + 0x017e, 0x2009, 0x3c10, 0x2104, 0x017f, 0x200a, 0x017f, 0x7146, + 0x7003, 0x0000, 0x703f, 0x0000, 0x0078, 0x2067, 0x7640, 0xa6b0, + 0x3c80, 0x7144, 0x2600, 0x0078, 0x2196, 0x7146, 0x2568, 0x2558, + 0x753e, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0, 0x21b2, 0x6708, + 0x7736, 0xa784, 0x013f, 0x0040, 0x21e7, 0xa784, 0x0021, 0x00c0, + 0x21b2, 0xa784, 0x0002, 0x0040, 0x21d4, 0xa784, 0x0004, 0x0040, + 0x21b2, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0, 0x21b2, + 0xa784, 0x0010, 0x00c0, 0x21b2, 0xa784, 0x0100, 0x0040, 0x21e7, + 0x6018, 0xa005, 0x00c0, 0x21b2, 0xa7bc, 0xfeff, 0x670a, 0x6823, + 0x0000, 0x6e1c, 0xa684, 0x000e, 0x6118, 0x0040, 0x21f7, 0x601c, + 0xa102, 0x0048, 0x21fa, 0x0040, 0x21fa, 0x0078, 0x21ae, 0x81ff, + 0x00c0, 0x21ae, 0xa784, 0x0080, 0x00c0, 0x2200, 0x700c, 0x6022, + 0xa7bc, 0xff7f, 0x670a, 0x1078, 0x34ab, 0x0018, 0x202c, 0x789b, + 0x0010, 0xa046, 0x1078, 0x340c, 0x00c0, 0x2067, 0x6b14, 0xa39c, + 0x0007, 0xa39d, 0x00c0, 0x704c, 0xa084, 0x8000, 0x0040, 0x221c, + 0xa684, 0x0001, 0x0040, 0x221e, 0xa39c, 0xffbf, 0xa684, 0x0010, + 0x0040, 0x2224, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, + 0x00c0, 0x222f, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x2270, 0x714c, + 0xa18c, 0x0800, 0x0040, 0x2f47, 0x2011, 0x0021, 0x8004, 0x8004, + 0x0048, 0x2246, 0x2011, 0x0022, 0x8004, 0x0048, 0x2246, 0x2011, + 0x0020, 0x8004, 0x0048, 0x2246, 0x0040, 0x2270, 0x7aaa, 0x8840, + 0x1078, 0x3425, 0x6a14, 0x610c, 0x8108, 0xa18c, 0x00ff, 0xa1e0, + 0x4580, 0x2c64, 0x8cff, 0x0040, 0x2267, 0x6014, 0xa206, 0x00c0, + 0x2251, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x224c, 0x0c7e, 0x2a60, + 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, 0x217e, 0x1078, + 0x340c, 0x00c0, 0x2067, 0x2a60, 0x610e, 0x79aa, 0x8840, 0x712e, + 0x0018, 0x202c, 0x2001, 0x0001, 0x007e, 0x7150, 0xa184, 0x0018, + 0x0040, 0x228f, 0xa184, 0x0010, 0x0040, 0x2282, 0x1078, 0x316c, + 0x00c0, 0x22b2, 0xa184, 0x0008, 0x0040, 0x228f, 0x69a0, 0xa184, + 0x0600, 0x00c0, 0x228f, 0x1078, 0x3068, 0x0078, 0x22b2, 0x69a0, + 0xa184, 0x0800, 0x0040, 0x22a6, 0x0c7e, 0x027e, 0x2960, 0x6000, + 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, 0x027f, + 0x0c7f, 0x1078, 0x316c, 0x00c0, 0x22b2, 0x69a0, 0xa184, 0x0200, + 0x0040, 0x22ae, 0x1078, 0x30b7, 0x0078, 0x22b2, 0xa184, 0x0400, + 0x00c0, 0x228b, 0x69a0, 0xa184, 0x1000, 0x0040, 0x22bd, 0x6914, + 0xa18c, 0xff00, 0x810f, 0x1078, 0x1f5b, 0x007f, 0x0018, 0x202c, + 0x7002, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x22cd, 0xa086, + 0x0060, 0x00c0, 0x22cd, 0xa18d, 0x4000, 0x88ff, 0x0040, 0x22d2, + 0xa18d, 0x0004, 0x795a, 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, + 0x789b, 0x0061, 0x6818, 0xa08d, 0x8000, 0xa084, 0x7fff, 0x691a, + 0xa68c, 0x0080, 0x0040, 0x22f1, 0x70cb, 0x0000, 0xa08a, 0x000d, + 0x0050, 0x22ef, 0xa08a, 0x000c, 0x71ca, 0x2001, 0x000c, 0x800c, + 0x71ce, 0x78aa, 0x8008, 0x810c, 0x0040, 0x2f4d, 0xa18c, 0x00f8, + 0x00c0, 0x2f4d, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, + 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, + 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, 0x6d94, 0x7dd6, 0x7dde, + 0x6e98, 0x7ed2, 0x7eda, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x231a, + 0x0098, 0x2322, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x3425, + 0x0078, 0x206f, 0x7200, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, + 0x232f, 0x781b, 0x004a, 0x1078, 0x3425, 0x0078, 0x2340, 0x6ab4, + 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004a, 0x1078, 0x3425, 0x7200, + 0x2500, 0xa605, 0x0040, 0x2340, 0xa284, 0x0007, 0x1079, 0x234e, + 0xad80, 0x0009, 0x7032, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, + 0x2067, 0x6018, 0x8000, 0x601a, 0x0078, 0x2067, 0x2356, 0x3862, + 0x3862, 0x3851, 0x3862, 0x2356, 0x3851, 0x2356, 0x1078, 0x2007, + 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, 0x3c00, 0x78c0, + 0x0f7f, 0xa084, 0x0001, 0x0040, 0x237e, 0x70a0, 0xa086, 0x0001, + 0x00c0, 0x236d, 0x70a2, 0x0078, 0x2405, 0x70a0, 0xa086, 0x0005, + 0x00c0, 0x237c, 0x70bc, 0x2068, 0x681b, 0x0004, 0x6817, 0x0000, + 0x6820, 0xa085, 0x0008, 0x6822, 0x70a3, 0x0000, 0x157e, 0x2011, + 0x0004, 0x71a0, 0xa186, 0x0001, 0x0040, 0x23a0, 0xa186, 0x0007, + 0x00c0, 0x2390, 0x2009, 0x3c35, 0x200b, 0x0005, 0x0078, 0x23a0, + 0x2009, 0x3c13, 0x2104, 0x2009, 0x3c12, 0x200a, 0x2009, 0x3c35, + 0x200b, 0x0001, 0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x23a2, + 0x70a3, 0x0000, 0x1078, 0x35ae, 0x20a9, 0x0010, 0x2039, 0x0000, + 0x1078, 0x3239, 0xa7b8, 0x0100, 0x0070, 0x23b0, 0x0078, 0x23a8, + 0x7000, 0x0079, 0x23b3, 0x23e1, 0x23ca, 0x23ca, 0x23bd, 0x23e1, + 0x23e1, 0x23e1, 0x23bb, 0x1078, 0x2007, 0x2021, 0x3c57, 0x2404, + 0xa005, 0x0040, 0x23e1, 0xad06, 0x00c0, 0x23ca, 0x6800, 0x2022, + 0x0078, 0x23da, 0x6820, 0xa084, 0x0001, 0x00c0, 0x23d6, 0x6f14, + 0x1078, 0x3348, 0x1078, 0x2f1e, 0x0078, 0x23da, 0x7054, 0x2060, + 0x6800, 0x6002, 0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, + 0x1b24, 0x2021, 0x4680, 0x1078, 0x240b, 0x2021, 0x3c57, 0x1078, + 0x240b, 0x20a9, 0x0000, 0x2021, 0x4580, 0x1078, 0x240b, 0x8420, + 0x0070, 0x23f4, 0x0078, 0x23ed, 0x20a9, 0x0080, 0x2061, 0x3d80, + 0x6018, 0x6110, 0xa102, 0x6012, 0x601b, 0x0000, 0xace0, 0x0010, + 0x0070, 0x2404, 0x0078, 0x23f8, 0x157f, 0x7003, 0x0000, 0x703f, + 0x0000, 0x0078, 0x2067, 0x047e, 0x2404, 0xa005, 0x0040, 0x241d, + 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, + 0x1078, 0x1b24, 0x007f, 0x0078, 0x240d, 0x047f, 0x2023, 0x0000, + 0x007c, 0xa282, 0x0003, 0x0050, 0x2427, 0x1078, 0x2007, 0x2300, + 0x0079, 0x242a, 0x242d, 0x24a0, 0x24bd, 0xa282, 0x0002, 0x0040, + 0x2433, 0x1078, 0x2007, 0x70a0, 0x70a3, 0x0000, 0x70c7, 0x0000, + 0x0079, 0x243a, 0x2442, 0x2442, 0x2444, 0x2478, 0x2f53, 0x2442, + 0x2478, 0x2442, 0x1078, 0x2007, 0x77b4, 0x1078, 0x3239, 0x77b4, + 0xa7bc, 0x0f00, 0x1078, 0x3348, 0x6018, 0xa005, 0x0040, 0x246f, + 0x2021, 0x4680, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x24da, + 0x0040, 0x246f, 0x157e, 0x20a9, 0x0000, 0x2021, 0x4580, 0x047e, + 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x24da, 0x047f, 0x0040, + 0x246e, 0x8420, 0x0070, 0x246e, 0x0078, 0x245f, 0x157f, 0x8738, + 0xa784, 0x0007, 0x00c0, 0x244a, 0x0078, 0x206f, 0x0078, 0x206f, + 0x77b4, 0x1078, 0x3348, 0x6018, 0xa005, 0x0040, 0x249e, 0x2021, + 0x4680, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x24da, 0x0040, + 0x249e, 0x157e, 0x20a9, 0x0000, 0x2021, 0x4580, 0x047e, 0x2009, + 0x0005, 0x2011, 0x0020, 0x1078, 0x24da, 0x047f, 0x0040, 0x249d, + 0x8420, 0x0070, 0x249d, 0x0078, 0x248e, 0x157f, 0x0078, 0x206f, + 0x2200, 0x0079, 0x24a3, 0x24a6, 0x24a8, 0x24a8, 0x1078, 0x2007, + 0x2009, 0x0012, 0x70a0, 0xa086, 0x0002, 0x0040, 0x24b1, 0x2009, + 0x000e, 0x6818, 0xa084, 0x8000, 0x0040, 0x24b7, 0x691a, 0x70a3, + 0x0000, 0x70a7, 0x0001, 0x0078, 0x33d7, 0x2200, 0x0079, 0x24c0, + 0x24c5, 0x24a8, 0x24c3, 0x1078, 0x2007, 0x7000, 0xa086, 0x0001, + 0x00c0, 0x24d6, 0x1078, 0x2f34, 0x6008, 0xa084, 0xffef, 0x600a, + 0x1078, 0x2ed6, 0x0040, 0x24d6, 0x0078, 0x217e, 0x1078, 0x29a3, + 0x0078, 0x2ee3, 0x2404, 0xa005, 0x0040, 0x24fb, 0x2068, 0x2d04, + 0x007e, 0x6814, 0xa706, 0x0040, 0x24e9, 0x2d20, 0x007f, 0x0078, + 0x24db, 0x007f, 0x2022, 0x691a, 0x6820, 0xa205, 0x6822, 0x1078, + 0x1b24, 0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, + 0x1078, 0x2f34, 0x007c, 0xa085, 0x0001, 0x0078, 0x24fa, 0x2300, + 0x0079, 0x2502, 0x2507, 0x2505, 0x2562, 0x1078, 0x2007, 0x78e4, + 0xa005, 0x00d0, 0x252a, 0x0018, 0x252a, 0x2008, 0xa084, 0x0030, + 0x00c0, 0x2516, 0x781b, 0x004a, 0x0078, 0x2067, 0x78ec, 0xa084, + 0x0003, 0x0040, 0x2512, 0x2100, 0xa084, 0x0007, 0x0079, 0x2520, + 0x253b, 0x2548, 0x252e, 0x2528, 0x33ff, 0x33ff, 0x2528, 0x2555, + 0x1078, 0x2007, 0x2001, 0x0003, 0x0078, 0x286c, 0x6818, 0xa084, + 0x8000, 0x0040, 0x2535, 0x681b, 0x001d, 0x1078, 0x321c, 0x781b, + 0x0053, 0x0078, 0x2067, 0x6818, 0xa084, 0x8000, 0x0040, 0x2542, + 0x681b, 0x001d, 0x1078, 0x321c, 0x781b, 0x00de, 0x0078, 0x2067, + 0x6818, 0xa084, 0x8000, 0x0040, 0x254f, 0x681b, 0x001d, 0x1078, + 0x321c, 0x781b, 0x00e5, 0x0078, 0x2067, 0x6818, 0xa084, 0x8000, + 0x0040, 0x255c, 0x681b, 0x001d, 0x1078, 0x321c, 0x781b, 0x009c, + 0x0078, 0x2067, 0xa584, 0x000f, 0x00c0, 0x2583, 0x7000, 0x0079, + 0x2569, 0x2571, 0x2573, 0x2571, 0x257f, 0x257f, 0x257f, 0x257f, + 0x2571, 0x1078, 0x2007, 0x1078, 0x2f34, 0x6008, 0xa084, 0xffef, + 0x600a, 0x1078, 0x2ed6, 0x0040, 0x257f, 0x0078, 0x217e, 0x1078, + 0x29a3, 0x0078, 0x2ee3, 0x78e4, 0xa005, 0x00d0, 0x252a, 0x0018, + 0x252a, 0x2008, 0xa084, 0x0030, 0x00c0, 0x2592, 0x781b, 0x004a, + 0x0078, 0x2067, 0x78ec, 0xa084, 0x0003, 0x0040, 0x258e, 0x2100, + 0xa184, 0x0007, 0x0079, 0x259c, 0x25ac, 0x25b2, 0x25a6, 0x25a4, + 0x33ff, 0x33ff, 0x25a4, 0x33f7, 0x1078, 0x2007, 0x1078, 0x3224, + 0x781b, 0x0053, 0x0078, 0x2067, 0x1078, 0x3224, 0x781b, 0x00de, + 0x0078, 0x2067, 0x1078, 0x3224, 0x781b, 0x00e5, 0x0078, 0x2067, + 0x1078, 0x3224, 0x781b, 0x009c, 0x0078, 0x2067, 0x2300, 0x0079, + 0x25c1, 0x25c6, 0x25c4, 0x25c8, 0x1078, 0x2007, 0x0078, 0x2bfd, + 0x681b, 0x0008, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, + 0x2bfd, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2bfd, 0xa184, 0x0007, + 0x0079, 0x25da, 0x25e2, 0x25b2, 0x252e, 0x33d7, 0x33ff, 0x33ff, + 0x25e2, 0x33f7, 0x1078, 0x2007, 0xa282, 0x0005, 0x0050, 0x25ea, + 0x1078, 0x2007, 0x2300, 0x0079, 0x25ed, 0x25f0, 0x281d, 0x2829, + 0x2200, 0x0079, 0x25f3, 0x260d, 0x25fa, 0x260d, 0x25f8, 0x2802, + 0x1078, 0x2007, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, + 0x0020, 0x0048, 0x31fe, 0xa08a, 0x0004, 0x00c8, 0x31fe, 0x0079, + 0x2609, 0x31fe, 0x31fe, 0x31fe, 0x31ac, 0x789b, 0x0018, 0x79a8, + 0xa184, 0x0080, 0x0040, 0x2622, 0xa184, 0x0018, 0x0040, 0x261e, + 0x0078, 0x31fe, 0x7000, 0xa005, 0x00c0, 0x2618, 0x2011, 0x0004, + 0x0078, 0x2d3a, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x31fe, + 0x0079, 0x262a, 0x263c, 0x263a, 0x2654, 0x2658, 0x2711, 0x31fe, + 0x31fe, 0x2713, 0x31fe, 0x31fe, 0x27fe, 0x27fe, 0x31fe, 0x31fe, + 0x31fe, 0x2800, 0x1078, 0x2007, 0xa684, 0x1000, 0x0040, 0x2649, + 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x0099, 0x0078, + 0x2067, 0x6818, 0xa084, 0x8000, 0x0040, 0x2652, 0x681b, 0x001d, + 0x0078, 0x2640, 0x0078, 0x33d7, 0x681b, 0x001d, 0x0078, 0x320a, + 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0, 0x2699, 0x6820, 0xa084, + 0x0001, 0x00c0, 0x269f, 0x6818, 0xa086, 0x0008, 0x00c0, 0x266a, + 0x681b, 0x0000, 0xa684, 0x0400, 0x0040, 0x270d, 0xa684, 0x0080, + 0x0040, 0x2695, 0x70cb, 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, + 0x000d, 0x0050, 0x2695, 0xa08a, 0x000c, 0x71ca, 0x2001, 0x000c, + 0x800c, 0x71ce, 0x789b, 0x0061, 0x78aa, 0x157e, 0x137e, 0x147e, + 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, + 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b, 0x0056, 0x0078, + 0x2067, 0xa684, 0x1000, 0x0040, 0x269f, 0x0078, 0x2067, 0xa684, + 0x0060, 0x0040, 0x2709, 0xa684, 0x0800, 0x0040, 0x2709, 0xa684, + 0x8000, 0x00c0, 0x26ad, 0x0078, 0x26c7, 0xa6b4, 0x7fff, 0x7e5a, + 0x6eb6, 0x789b, 0x0076, 0x7aac, 0x79ac, 0x78ac, 0x801b, 0x00c8, + 0x26ba, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, + 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0xa684, + 0x4000, 0x0040, 0x26cf, 0xa6b4, 0xbfff, 0x7e5a, 0x6eb6, 0x7000, + 0xa086, 0x0003, 0x00c0, 0x26dc, 0x1078, 0x3654, 0x1078, 0x3851, + 0x781b, 0x0065, 0x0078, 0x2067, 0xa006, 0x1078, 0x3920, 0x6ab0, + 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, 0x26eb, 0x2200, + 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x6ba6, 0x7bd6, 0x2300, + 0xa405, 0x00c0, 0x26fb, 0xa6b5, 0x4000, 0x7e5a, 0x6eb6, 0x781b, + 0x0065, 0x0078, 0x2067, 0x781b, 0x0065, 0x2200, 0xa115, 0x00c0, + 0x2705, 0x1078, 0x3862, 0x0078, 0x2067, 0x1078, 0x3897, 0x0078, + 0x2067, 0x781b, 0x0068, 0x0078, 0x2067, 0x781b, 0x0056, 0x0078, + 0x2067, 0x1078, 0x2007, 0x0078, 0x2770, 0x6920, 0xa184, 0x0100, + 0x0040, 0x272b, 0xa18c, 0xfeff, 0x6922, 0x0c7e, 0x7048, 0x2060, + 0x6000, 0xa084, 0xefff, 0x6002, 0x6004, 0xa084, 0xfff5, 0x6006, + 0x0c7f, 0x0078, 0x275f, 0xa184, 0x0200, 0x0040, 0x275f, 0xa18c, + 0xfdff, 0x6922, 0x0c7e, 0x7048, 0x2060, 0x6000, 0xa084, 0xdfff, + 0x6002, 0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, 0x0c7f, + 0xa184, 0x0008, 0x0040, 0x275f, 0x1078, 0x3344, 0x1078, 0x3068, + 0x88ff, 0x0040, 0x275f, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, + 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x275b, 0x781b, + 0x0053, 0x0078, 0x2067, 0x781b, 0x0067, 0x0078, 0x2067, 0x7e58, + 0xa684, 0x0400, 0x00c0, 0x2768, 0x781b, 0x0056, 0x0078, 0x2067, + 0x781b, 0x0068, 0x0078, 0x2067, 0x0078, 0x3204, 0x0078, 0x3204, + 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x276e, 0x789b, + 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, 0x2793, + 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x278b, 0x0048, + 0x278b, 0x0078, 0x278d, 0x0078, 0x2715, 0x24a8, 0x7aa8, 0x00f0, + 0x278d, 0x0078, 0x2779, 0xa284, 0x00f0, 0xa086, 0x0020, 0x00c0, + 0x27ef, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x27a3, 0x0048, + 0x27a3, 0x0078, 0x27ec, 0xa286, 0x0023, 0x0040, 0x276e, 0x681c, + 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xa085, 0x0010, + 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a, 0x0c7e, 0x7048, + 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0010, 0x0040, + 0x27c7, 0x1078, 0x3344, 0x1078, 0x316c, 0x0078, 0x27d6, 0x0c7e, + 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, + 0x0040, 0x275f, 0x1078, 0x3344, 0x1078, 0x3068, 0x88ff, 0x0040, + 0x275f, 0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5, 0x0004, 0x7e5a, + 0xa684, 0x0400, 0x00c0, 0x27e8, 0x781b, 0x0053, 0x0078, 0x2067, + 0x781b, 0x0067, 0x0078, 0x2067, 0x7aa8, 0x0078, 0x2779, 0x8318, + 0x2300, 0xa102, 0x0040, 0x27f8, 0x0048, 0x27f8, 0x0078, 0x2779, + 0xa284, 0x0080, 0x00c0, 0x320a, 0x0078, 0x3204, 0x0078, 0x320a, + 0x0078, 0x31fe, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, + 0x0001, 0x0040, 0x280d, 0x1078, 0x2007, 0x7aa8, 0xa294, 0x00ff, + 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x31fe, 0x0079, + 0x2819, 0x2f84, 0x2fbb, 0x31fe, 0x3107, 0xa282, 0x0000, 0x00c0, + 0x2823, 0x1078, 0x2007, 0x1078, 0x321c, 0x781b, 0x0067, 0x0078, + 0x2067, 0xa282, 0x0003, 0x00c0, 0x282f, 0x1078, 0x2007, 0xa484, + 0x8000, 0x00c0, 0x2852, 0x70a0, 0xa005, 0x0040, 0x2839, 0x1078, + 0x2007, 0x6f14, 0x77b6, 0xa7bc, 0x0f00, 0x1078, 0x3348, 0x6008, + 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x0007, 0x00c0, 0x283d, + 0x1078, 0x3220, 0x70a3, 0x0002, 0x2009, 0x3c35, 0x200b, 0x0009, + 0x0078, 0x2854, 0x1078, 0x322c, 0x781b, 0x0067, 0x0078, 0x2067, + 0xa282, 0x0004, 0x0050, 0x285e, 0x1078, 0x2007, 0x2300, 0x0079, + 0x2861, 0x2864, 0x294f, 0x297e, 0xa286, 0x0003, 0x0040, 0x286a, + 0x1078, 0x2007, 0x2001, 0x0000, 0x007e, 0x681c, 0xa084, 0x2000, + 0x0040, 0x2876, 0x6008, 0xa085, 0x0002, 0x600a, 0x007f, 0x703a, + 0x7000, 0xa084, 0x0007, 0x0079, 0x287d, 0x2885, 0x2887, 0x2887, + 0x2a64, 0x2a95, 0x206f, 0x2a95, 0x2885, 0x1078, 0x2007, 0xa684, + 0x1000, 0x00c0, 0x288f, 0x1078, 0x35ae, 0x0040, 0x2929, 0x7868, + 0xa08c, 0x00ff, 0x0040, 0x28d5, 0xa186, 0x0008, 0x00c0, 0x28a6, + 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2ed6, 0x0040, 0x28d5, + 0x1078, 0x2f34, 0x1078, 0x35ae, 0x0078, 0x28bc, 0xa186, 0x0028, + 0x00c0, 0x28d5, 0x1078, 0x35ae, 0x6008, 0xa084, 0xffef, 0x600a, + 0x6018, 0xa005, 0x0040, 0x28bc, 0x8001, 0x601a, 0x6008, 0xa085, + 0x0008, 0x600a, 0x7010, 0x6026, 0x6820, 0xa084, 0x0001, 0x0040, + 0x206f, 0x6820, 0xa084, 0xfffe, 0x6822, 0x7054, 0x0c7e, 0x2060, + 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, + 0x28d2, 0x6002, 0x6006, 0x0078, 0x206f, 0x017e, 0x1078, 0x29a3, + 0x017f, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, 0x81ff, + 0x0040, 0x2929, 0xa186, 0x0002, 0x00c0, 0x2921, 0xa684, 0x0800, + 0x00c0, 0x28f2, 0xa684, 0x0060, 0x0040, 0x28f2, 0x78d8, 0x7adc, + 0x682e, 0x6a32, 0x6820, 0xa084, 0x0800, 0x00c0, 0x2929, 0x8717, + 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xa290, 0x3d00, 0xa290, + 0x0000, 0x221c, 0xa384, 0x0100, 0x00c0, 0x2908, 0x0078, 0x290e, + 0x8210, 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, 0xa384, 0x0400, + 0x0040, 0x291b, 0x68a0, 0xa084, 0x0100, 0x00c0, 0x291b, 0x1078, + 0x2a1f, 0x0078, 0x206f, 0x6008, 0xa085, 0x0002, 0x600a, 0x0078, + 0x2929, 0xa186, 0x0018, 0x0040, 0x2929, 0xa186, 0x0014, 0x0040, + 0x206f, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, 0x2931, 0x7038, + 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x2f25, 0x1078, 0x2f34, + 0x00c0, 0x293e, 0x6008, 0xa084, 0xffef, 0x600a, 0x6820, 0xa084, + 0x0001, 0x00c0, 0x2947, 0x1078, 0x2f1e, 0x0078, 0x294b, 0x7054, + 0x2060, 0x6800, 0x6002, 0x1078, 0x1b24, 0x0078, 0x206f, 0xa282, + 0x0004, 0x0048, 0x2955, 0x1078, 0x2007, 0x2200, 0x0079, 0x2958, + 0x2953, 0x295c, 0x2969, 0x295c, 0x7000, 0xa086, 0x0005, 0x0040, + 0x2965, 0x1078, 0x321c, 0x781b, 0x0067, 0x781b, 0x0068, 0x0078, + 0x2067, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, + 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0040, 0x297a, + 0x0078, 0x31fe, 0x781b, 0x0068, 0x0078, 0x2067, 0x6820, 0xa085, + 0x0004, 0x6822, 0x82ff, 0x00c0, 0x2989, 0x1078, 0x321c, 0x0078, + 0x2990, 0x8211, 0x0040, 0x298e, 0x1078, 0x2007, 0x1078, 0x322c, + 0x781b, 0x0067, 0x0078, 0x2067, 0x1078, 0x3425, 0x7830, 0xa084, + 0x00c0, 0x00c0, 0x29a0, 0x0018, 0x29a0, 0x791a, 0xa006, 0x007c, + 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, 0x29ad, 0x682f, + 0x0000, 0x6833, 0x0000, 0x0078, 0x2a1e, 0xa684, 0x0800, 0x00c0, + 0x29c7, 0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, 0x0800, 0x00c0, + 0x29c7, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x703b, 0x0015, 0x7000, + 0xa086, 0x0006, 0x0040, 0x29c6, 0x1078, 0x35ae, 0x007c, 0xa684, + 0x0020, 0x0040, 0x29e9, 0xa684, 0x4000, 0x0040, 0x29d5, 0x682f, + 0x0000, 0x6833, 0x0000, 0x0078, 0x29bf, 0x68b4, 0xa084, 0x4800, + 0xa635, 0xa684, 0x4000, 0x00c0, 0x29cf, 0x7038, 0xa005, 0x00c0, + 0x29e3, 0x703b, 0x0015, 0x79d8, 0x7adc, 0x692e, 0x6a32, 0x0078, + 0x29bf, 0xa684, 0x4000, 0x0040, 0x29f3, 0x682f, 0x0000, 0x6833, + 0x0000, 0x0078, 0x29bf, 0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, + 0x4000, 0x00c0, 0x29ed, 0x7038, 0xa005, 0x00c0, 0x2a01, 0x703b, + 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, 0x2a08, 0x8000, + 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, + 0xa205, 0x00c0, 0x2a15, 0x0078, 0x29bf, 0x7000, 0xa086, 0x0006, + 0x0040, 0x2a1e, 0x1078, 0x3920, 0x0078, 0x29bf, 0x007c, 0xa384, + 0x0200, 0x0040, 0x2a27, 0x6008, 0xa085, 0x0002, 0x600a, 0x681b, + 0x0006, 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, + 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, + 0x0000, 0x689b, 0x0020, 0x7000, 0x0079, 0x2a3e, 0x2a46, 0x2a48, + 0x2a51, 0x2a46, 0x2a46, 0x2a46, 0x2a46, 0x2a46, 0x1078, 0x2007, + 0x6820, 0xa084, 0x0001, 0x00c0, 0x2a51, 0x1078, 0x2f1e, 0x0078, + 0x2a57, 0x7054, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, 0x2021, + 0x3c57, 0x2404, 0xa005, 0x0040, 0x2a60, 0x2020, 0x0078, 0x2a59, + 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x2f25, 0x1078, 0x2f34, + 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, + 0x3952, 0xa684, 0x0800, 0x0040, 0x2a79, 0x691c, 0xa18d, 0x2000, + 0x691e, 0x6818, 0xa084, 0x8000, 0x0040, 0x2a89, 0x7868, 0xa08c, + 0x00ff, 0x0040, 0x2a87, 0x681b, 0x001e, 0x0078, 0x2a89, 0x681b, + 0x0000, 0x2021, 0x3c57, 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, + 0x692e, 0x1078, 0x1b24, 0x0078, 0x206f, 0x1078, 0x29a3, 0x682b, + 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, 0x342a, 0xa08c, 0x00ff, + 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, 0x2aa8, 0x7038, 0x681a, + 0xa68c, 0xdf00, 0x691e, 0x70a3, 0x0000, 0x0078, 0x206f, 0xa006, + 0x1078, 0x35ae, 0x6817, 0x0000, 0x681b, 0x0014, 0xa68c, 0xdf00, + 0x691e, 0x682b, 0x0000, 0x6820, 0xa085, 0x00ff, 0x6822, 0x7000, + 0x0079, 0x2ac2, 0x2aca, 0x2acc, 0x2acc, 0x2ace, 0x2ace, 0x2ace, + 0x2ace, 0x2aca, 0x1078, 0x2007, 0x1078, 0x2f34, 0x6008, 0xa084, + 0xffef, 0x600a, 0x0078, 0x2eee, 0x2300, 0x0079, 0x2ad7, 0x2ada, + 0x2adc, 0x2b30, 0x1078, 0x2007, 0x7000, 0x0079, 0x2adf, 0x2ae7, + 0x2ae9, 0x2ae9, 0x2b04, 0x2ae9, 0x2b11, 0x2b04, 0x2ae7, 0x1078, + 0x2007, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x2b00, 0xa6b4, + 0xffdf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, + 0xffdf, 0x681e, 0x1078, 0x35ae, 0x1078, 0x3862, 0x0078, 0x33d7, + 0xa684, 0x2000, 0x0040, 0x2af3, 0x6818, 0xa084, 0x8000, 0x0040, + 0x2b11, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040, 0x2b11, 0x681b, + 0x0007, 0x2009, 0x3c1e, 0x210c, 0xa186, 0x0000, 0x0040, 0x2b26, + 0xa186, 0x0001, 0x0040, 0x2b2a, 0x2009, 0x3c35, 0x200b, 0x000b, + 0x70a3, 0x0001, 0x781b, 0x0047, 0x0078, 0x2067, 0x781b, 0x00df, + 0x0078, 0x2067, 0x2009, 0x3c35, 0x200b, 0x000a, 0x0078, 0x2067, + 0x1078, 0x2007, 0x2300, 0x0079, 0x2b35, 0x2b38, 0x2b3a, 0x2b6c, + 0x1078, 0x2007, 0x7000, 0x0079, 0x2b3d, 0x2b44, 0x2b46, 0x2b46, + 0x2b61, 0x2b46, 0x2b61, 0x2b44, 0x1078, 0x2007, 0xa684, 0x0060, + 0xa086, 0x0060, 0x00c0, 0x2b5d, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff, + 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf, 0x681e, 0x1078, + 0x35ae, 0x1078, 0x3862, 0x0078, 0x33d7, 0xa684, 0x2000, 0x0040, + 0x2b50, 0x6818, 0xa084, 0x8000, 0x0040, 0x2b68, 0x681b, 0x0007, + 0x781b, 0x00e6, 0x0078, 0x2067, 0x6820, 0xa085, 0x0004, 0x6822, + 0xa6b5, 0x0800, 0x1078, 0x321c, 0x781b, 0x0067, 0x0078, 0x2067, + 0x2300, 0x0079, 0x2b7b, 0x2b7e, 0x2b80, 0x2b82, 0x1078, 0x2007, + 0x1078, 0x2007, 0xa684, 0x0400, 0x00c0, 0x2bab, 0x79e4, 0xa184, + 0x0020, 0x0040, 0x2b92, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2b92, + 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, + 0x785a, 0x79e4, 0xa184, 0x0020, 0x0040, 0x2ba3, 0x78ec, 0xa084, + 0x0003, 0x00c0, 0x2ba7, 0x2001, 0x0014, 0x0078, 0x286c, 0xa184, + 0x0007, 0x0079, 0x2be3, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, + 0x79a8, 0x81ff, 0x0040, 0x2be1, 0x789b, 0x0010, 0x7ba8, 0xa384, + 0x0001, 0x00c0, 0x2bd2, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, + 0x2bc5, 0x2009, 0xfff7, 0x0078, 0x2bcb, 0xa386, 0x0003, 0x00c0, + 0x2bd2, 0x2009, 0xffef, 0x0c7e, 0x7048, 0x2060, 0x6004, 0xa104, + 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, + 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, + 0x6922, 0x0078, 0x33d7, 0x253b, 0x2548, 0x2bed, 0x2bf5, 0x2beb, + 0x2beb, 0x2beb, 0x33d7, 0x1078, 0x2007, 0x6920, 0xa18c, 0xfdff, + 0xa18c, 0xfeff, 0x6922, 0x0078, 0x33df, 0x6920, 0xa18c, 0xfdff, + 0xa18c, 0xfeff, 0x6922, 0x0078, 0x33d7, 0x79e4, 0xa184, 0x0030, + 0x0040, 0x2c07, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x2c18, 0x70a0, + 0xa086, 0x0002, 0x00c0, 0x2c10, 0x2011, 0x0002, 0x0078, 0x2421, + 0x6818, 0xa085, 0x8000, 0x681a, 0x2001, 0x0014, 0x0078, 0x286c, + 0xa184, 0x0007, 0x0079, 0x2c1c, 0x33d7, 0x33d7, 0x2c24, 0x33d7, + 0x33ff, 0x33ff, 0x33d7, 0x33d7, 0xa684, 0x0080, 0x0040, 0x2c53, + 0x71c8, 0x81ff, 0x0040, 0x2c53, 0xa182, 0x000d, 0x00d0, 0x2c34, + 0x70cb, 0x0000, 0x0078, 0x2c39, 0xa182, 0x000c, 0x70ca, 0x2009, + 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e, 0x147e, 0x70cc, + 0x8114, 0xa210, 0x72ce, 0xa080, 0x000b, 0xad00, 0x2098, 0x20a1, + 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x147f, 0x137f, + 0x157f, 0x0078, 0x33df, 0xa684, 0x0400, 0x00c0, 0x2c94, 0x6820, + 0xa084, 0x0001, 0x0040, 0x33df, 0xa68c, 0x0060, 0xa684, 0x0060, + 0x0040, 0x2c68, 0xa086, 0x0060, 0x00c0, 0x2c68, 0xa18d, 0x4000, + 0xa18c, 0xfffb, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, + 0x789b, 0x0061, 0x6818, 0xa085, 0x8000, 0x681a, 0x78aa, 0x8008, + 0x810c, 0x0040, 0x2f4d, 0xa18c, 0x00f8, 0x00c0, 0x2f4d, 0x157e, + 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, + 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, + 0x8007, 0x7882, 0x0078, 0x33df, 0x6818, 0xa084, 0x8000, 0x0040, + 0x2c9b, 0x681b, 0x0008, 0x781b, 0x00da, 0x0078, 0x2067, 0x2300, + 0x0079, 0x2ca2, 0x2ca7, 0x2d2a, 0x2ca5, 0x1078, 0x2007, 0x7000, + 0xa084, 0x0007, 0x0079, 0x2cac, 0x2cb4, 0x2cb6, 0x2cdb, 0x2cb4, + 0x2cb4, 0x206f, 0x2cb4, 0x2cb4, 0x1078, 0x2007, 0x681c, 0xa084, + 0x2000, 0x0040, 0x2cbf, 0x6008, 0xa085, 0x0002, 0x600a, 0x6920, + 0xa18d, 0x0001, 0x6922, 0x6800, 0x6006, 0xa005, 0x00c0, 0x2cc9, + 0x6002, 0x681c, 0xa084, 0x000e, 0x0040, 0x2cd5, 0x7014, 0x68ba, + 0x712c, 0xa188, 0x4580, 0x0078, 0x2cd7, 0x2009, 0x4680, 0x2104, + 0x6802, 0x2d0a, 0x7156, 0x6eb6, 0xa684, 0x0060, 0x0040, 0x2d28, + 0xa684, 0x0800, 0x00c0, 0x2cef, 0xa684, 0x7fff, 0x68b6, 0x6894, + 0x68a6, 0x6898, 0x68aa, 0x1078, 0x35ae, 0x0078, 0x2d28, 0xa684, + 0x0020, 0x0040, 0x2cfc, 0xa006, 0x1078, 0x3920, 0x79d8, 0x7adc, + 0x69aa, 0x6aa6, 0x0078, 0x2d02, 0x1078, 0x3355, 0x69aa, 0x6aa6, + 0x1078, 0x3920, 0xa684, 0x8000, 0x0040, 0x2d28, 0xa684, 0x7fff, + 0x68b6, 0x789b, 0x0076, 0x1078, 0x342a, 0x2010, 0x1078, 0x342a, + 0x2008, 0xa684, 0x0020, 0x00c0, 0x2d20, 0x1078, 0x342a, 0x801b, + 0x00c8, 0x2d1b, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, + 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, + 0x0078, 0x206f, 0x0078, 0x320a, 0x7033, 0x0000, 0xa282, 0x0006, + 0x0050, 0x2d34, 0x1078, 0x2007, 0x2300, 0x0079, 0x2d37, 0x2d3a, + 0x2d63, 0x2d89, 0x2200, 0x0079, 0x2d3d, 0x2d43, 0x320a, 0x2d45, + 0x2d43, 0x2db5, 0x2e08, 0x1078, 0x2007, 0x7003, 0x0005, 0x2001, + 0x4690, 0x2068, 0x703e, 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, + 0x8000, 0x0070, 0x2d55, 0x0078, 0x2d4e, 0x157f, 0xad80, 0x0009, + 0x7032, 0x6817, 0x0000, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, + 0x0003, 0x0078, 0x31fe, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2d70, + 0x1078, 0x2f34, 0x1078, 0x35ae, 0x7034, 0x600a, 0x0078, 0x2d75, + 0x7000, 0xa086, 0x0003, 0x0040, 0x2d6a, 0x7003, 0x0005, 0x2001, + 0x4690, 0x2068, 0x703e, 0xad80, 0x0009, 0x7032, 0x2200, 0x0079, + 0x2d81, 0x320a, 0x2d87, 0x2d87, 0x2db5, 0x2d87, 0x320a, 0x1078, + 0x2007, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2d96, 0x1078, 0x2f34, + 0x1078, 0x35ae, 0x7034, 0x600a, 0x0078, 0x2d9b, 0x7000, 0xa086, + 0x0003, 0x0040, 0x2d90, 0x7003, 0x0005, 0x2001, 0x4690, 0x2068, + 0x703e, 0xad80, 0x0009, 0x7032, 0x2200, 0x0079, 0x2da7, 0x2daf, + 0x2dad, 0x2dad, 0x2daf, 0x2dad, 0x2daf, 0x1078, 0x2007, 0x1078, + 0x322c, 0x781b, 0x0067, 0x0078, 0x2067, 0x7000, 0xa086, 0x0001, + 0x00c0, 0x2dc2, 0x1078, 0x2f34, 0x1078, 0x35ae, 0x7034, 0x600a, + 0x0078, 0x2dc7, 0x7000, 0xa086, 0x0003, 0x0040, 0x2dbc, 0x7003, + 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, + 0x0007, 0xa215, 0x2069, 0x4680, 0x2d04, 0x2d08, 0x7156, 0x2068, + 0xa005, 0x0040, 0x2de2, 0x6814, 0xa206, 0x0040, 0x2dfd, 0x6800, + 0x0078, 0x2dd5, 0x7003, 0x0005, 0x2001, 0x4690, 0x2068, 0x703e, + 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2df2, + 0x0078, 0x2deb, 0x157f, 0xad80, 0x0009, 0x7032, 0x6a16, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, + 0xa084, 0x0c00, 0x0040, 0x2e69, 0x1078, 0x3224, 0x0078, 0x2e69, + 0x7000, 0xa086, 0x0001, 0x00c0, 0x2e15, 0x1078, 0x2f34, 0x1078, + 0x35ae, 0x7034, 0x600a, 0x0078, 0x2e1a, 0x7000, 0xa086, 0x0003, + 0x0040, 0x2e0f, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, + 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, 0x79a8, 0x79a8, 0xa18c, + 0x00ff, 0xa1e8, 0x4580, 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005, + 0x0040, 0x2e39, 0x6814, 0xa206, 0x0040, 0x2e54, 0x6800, 0x0078, + 0x2e2c, 0x7003, 0x0005, 0x2001, 0x4690, 0x2068, 0x703e, 0x157e, + 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2e49, 0x0078, + 0x2e42, 0x157f, 0xad80, 0x0009, 0x7032, 0x6a16, 0x68b7, 0x0700, + 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, + 0x0c00, 0x0040, 0x2e69, 0xa084, 0x0800, 0x0040, 0x2e63, 0x1078, + 0x3228, 0x0078, 0x2e69, 0x1078, 0x3224, 0x70bf, 0x0000, 0x0078, + 0x2e69, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xa080, 0x3d00, 0x2060, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, + 0xa684, 0x0060, 0x0040, 0x2ea9, 0x6b98, 0x6c94, 0x69ac, 0x68b0, + 0xa105, 0x00c0, 0x2e97, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, + 0xb7ff, 0x7e5a, 0xa684, 0x0060, 0xa086, 0x0060, 0x0040, 0x2ea9, + 0x1078, 0x3862, 0xa6b5, 0x2000, 0x7e5a, 0x0078, 0x2ea9, 0x68b0, + 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040, 0x2ea9, 0x7bd2, + 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xa6b4, 0xbfff, 0x7e5a, 0x1078, + 0x3897, 0x077f, 0x1078, 0x3348, 0x2009, 0x0068, 0xa684, 0x0008, + 0x0040, 0x2ec8, 0x78e4, 0xa084, 0x0030, 0x0040, 0x2ec0, 0x78ec, + 0xa084, 0x0003, 0x0040, 0x2ec0, 0x2009, 0x0067, 0x0078, 0x2ec8, + 0x0f7e, 0x2079, 0x3c00, 0x1078, 0x35ae, 0x0f7f, 0x0078, 0x206f, + 0x791a, 0x2d00, 0x703e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa080, 0x3d00, 0x2048, 0x0078, 0x2067, 0x6020, 0xa005, + 0x0040, 0x2ee2, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, + 0x7010, 0x6026, 0x007c, 0xa006, 0x1078, 0x35ae, 0x6817, 0x0000, + 0x681b, 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, + 0x0007, 0x0079, 0x2ef3, 0x2efb, 0x2efd, 0x2efd, 0x2f1a, 0x2f05, + 0x2efb, 0x2f05, 0x2efb, 0x1078, 0x2007, 0x1078, 0x2f25, 0x1078, + 0x2f1e, 0x1078, 0x1b24, 0x0078, 0x206f, 0x70a0, 0x70a3, 0x0000, + 0x70c7, 0x0000, 0x0079, 0x2f0c, 0x2f16, 0x2f16, 0x2f14, 0x2f14, + 0x2f14, 0x2f16, 0x2f14, 0x2f16, 0x0079, 0x243a, 0x70a3, 0x0000, + 0x0078, 0x206f, 0x681b, 0x0000, 0x0078, 0x2a64, 0x6800, 0xa005, + 0x00c0, 0x2f23, 0x6002, 0x6006, 0x007c, 0x6010, 0xa005, 0x0040, + 0x2f2e, 0x8001, 0x00d0, 0x2f2e, 0x1078, 0x2007, 0x6012, 0x6008, + 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x2f3a, + 0x8001, 0x601a, 0x007c, 0x1078, 0x3425, 0x681b, 0x0018, 0x0078, + 0x2f71, 0x1078, 0x3425, 0x681b, 0x0019, 0x0078, 0x2f71, 0x1078, + 0x3425, 0x681b, 0x001a, 0x0078, 0x2f71, 0x1078, 0x3425, 0x681b, + 0x0003, 0x0078, 0x2f71, 0x77b4, 0x1078, 0x3348, 0x71b8, 0xa18c, + 0x00ff, 0xa1e8, 0x4580, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, + 0x2f63, 0x0078, 0x206f, 0x6814, 0x72b4, 0xa206, 0x0040, 0x2f6b, + 0x6800, 0x0078, 0x2f5c, 0x6800, 0x200a, 0x681b, 0x0005, 0x70bf, + 0x0000, 0x1078, 0x2f25, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2f7a, + 0x1078, 0x2f1e, 0x1078, 0x2f34, 0x681f, 0x0000, 0x6823, 0x0020, + 0x1078, 0x1b24, 0x0078, 0x206f, 0xa282, 0x0005, 0x00c0, 0x31fe, + 0x78a8, 0xa084, 0x00ff, 0x802f, 0x78a8, 0xa084, 0x00ff, 0xa52d, + 0x78a8, 0xa084, 0x00ff, 0x8037, 0x78a8, 0xa084, 0x00ff, 0xa635, + 0x7cd8, 0x2600, 0xa420, 0x7bdc, 0x2500, 0xa319, 0x0048, 0x31fe, + 0x7cda, 0x7bde, 0x6caa, 0x7cd2, 0x6ba6, 0x7bd6, 0x1078, 0x3654, + 0x1078, 0x3851, 0x781b, 0x0065, 0x0078, 0x2067, 0xa006, 0x1078, + 0x3920, 0x781b, 0x0065, 0x0078, 0x2067, 0x78d0, 0x79d4, 0x1078, + 0x3897, 0x0078, 0x2067, 0xa282, 0x0003, 0x00c0, 0x31fe, 0x7da8, + 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xa18d, 0x0080, + 0x6922, 0xa184, 0x0100, 0x0040, 0x301b, 0xa18c, 0xfeff, 0x6922, + 0xa6b4, 0x00ff, 0x0040, 0x3005, 0xa682, 0x000c, 0x0048, 0x2fdc, + 0x0040, 0x2fdc, 0x2031, 0x000c, 0x852b, 0x852b, 0x1078, 0x32b7, + 0x0040, 0x2fe6, 0x1078, 0x30d3, 0x0078, 0x300e, 0x1078, 0x3272, + 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x30f7, + 0x0c7f, 0x6920, 0xa18d, 0x0100, 0x6922, 0x7e58, 0xa6b5, 0x0004, + 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x3001, 0x781b, 0x0053, 0x0078, + 0x2067, 0x781b, 0x0067, 0x0078, 0x2067, 0x0c7e, 0x2960, 0x6004, + 0xa084, 0xfff5, 0x6006, 0x1078, 0x30f7, 0x0c7f, 0x7e58, 0xa684, + 0x0400, 0x00c0, 0x3017, 0x781b, 0x0056, 0x0078, 0x2067, 0x781b, + 0x0068, 0x0078, 0x2067, 0x0c7e, 0x7048, 0x2060, 0x6100, 0xa18c, + 0x1000, 0x0040, 0x305b, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, + 0x000c, 0x0048, 0x302f, 0x0040, 0x302f, 0x2011, 0x000c, 0x2600, + 0xa202, 0x00c8, 0x3034, 0x2230, 0x6208, 0xa294, 0x00ff, 0x7018, + 0xa086, 0x0028, 0x00c0, 0x3044, 0xa282, 0x0019, 0x00c8, 0x304a, + 0x2011, 0x0019, 0x0078, 0x304a, 0xa282, 0x000c, 0x00c8, 0x304a, + 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8, 0x304f, 0x2228, 0x1078, + 0x3276, 0x852b, 0x852b, 0x1078, 0x32b7, 0x0040, 0x305b, 0x1078, + 0x30d3, 0x0078, 0x305f, 0x1078, 0x3272, 0x1078, 0x30f7, 0x7858, + 0xa085, 0x0004, 0x785a, 0x0c7f, 0x781b, 0x0067, 0x0078, 0x2067, + 0x0c7e, 0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x3080, 0x6010, + 0xa084, 0x000f, 0x00c0, 0x307a, 0x6104, 0xa18c, 0xfff5, 0x6106, + 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x30a7, + 0x68a0, 0xa084, 0x0200, 0x00c0, 0x307a, 0x6208, 0xa294, 0x00ff, + 0x7018, 0xa086, 0x0028, 0x00c0, 0x3095, 0xa282, 0x0019, 0x00c8, + 0x309b, 0x2011, 0x0019, 0x0078, 0x309b, 0xa282, 0x000c, 0x00c8, + 0x309b, 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, + 0x000c, 0x0048, 0x30a7, 0x0040, 0x30a7, 0x2019, 0x000c, 0x78ab, + 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, + 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, + 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, + 0x0000, 0x0078, 0x30c3, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, + 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, + 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008, 0xa084, + 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, + 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a, + 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, + 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, + 0x7048, 0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, + 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c, 0xa282, + 0x0002, 0x00c0, 0x31fe, 0x7aa8, 0x6920, 0xa18d, 0x0080, 0x6922, + 0xa184, 0x0200, 0x0040, 0x314c, 0xa18c, 0xfdff, 0x6922, 0xa294, + 0x00ff, 0xa282, 0x0002, 0x00c8, 0x31fe, 0x1078, 0x3193, 0x1078, + 0x30f7, 0xa980, 0x0001, 0x200c, 0x1078, 0x3344, 0x1078, 0x3068, + 0x88ff, 0x0040, 0x313f, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, + 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x313b, 0x781b, + 0x0053, 0x0078, 0x2067, 0x781b, 0x0067, 0x0078, 0x2067, 0x7e58, + 0xa684, 0x0400, 0x00c0, 0x3148, 0x781b, 0x0056, 0x0078, 0x2067, + 0x781b, 0x0068, 0x0078, 0x2067, 0xa282, 0x0002, 0x00c8, 0x3154, + 0xa284, 0x0001, 0x0040, 0x315e, 0x7148, 0xa188, 0x0000, 0x210c, + 0xa18c, 0x2000, 0x00c0, 0x315e, 0x2011, 0x0000, 0x1078, 0x3264, + 0x1078, 0x3193, 0x1078, 0x30f7, 0x7858, 0xa085, 0x0004, 0x785a, + 0x781b, 0x0067, 0x0078, 0x2067, 0x0c7e, 0x027e, 0x2960, 0x6000, + 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x3183, 0x6014, 0xa084, + 0x0040, 0x00c0, 0x3181, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078, + 0x3190, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, + 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200, 0x6822, + 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff, 0x0040, + 0x319b, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, + 0xa084, 0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, + 0xffef, 0x6006, 0x0c7f, 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, + 0x0040, 0x31b5, 0x007f, 0x0078, 0x31b8, 0x007f, 0x0078, 0x31fa, + 0xa684, 0x0020, 0x0040, 0x31fa, 0x7888, 0xa084, 0x0040, 0x0040, + 0x31fa, 0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, 0x31c8, 0x8000, + 0xa005, 0x0040, 0x31de, 0x831b, 0x00c8, 0x31d1, 0x8001, 0x0040, + 0x31f6, 0xa684, 0x4000, 0x0040, 0x31de, 0x78b8, 0x801b, 0x00c8, + 0x31da, 0x8000, 0xa084, 0x003f, 0x00c0, 0x31f6, 0xa6b4, 0xbfff, + 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x31ea, + 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x3920, + 0x781b, 0x0065, 0x1078, 0x37f1, 0x0078, 0x2067, 0x781b, 0x0065, + 0x0078, 0x2067, 0x781b, 0x0068, 0x0078, 0x2067, 0x1078, 0x3230, + 0x781b, 0x0067, 0x0078, 0x2067, 0x1078, 0x321c, 0x781b, 0x0067, + 0x0078, 0x2067, 0x6827, 0x0002, 0x1078, 0x3224, 0x78e4, 0xa084, + 0x0030, 0x0040, 0x206f, 0x78ec, 0xa084, 0x0003, 0x0040, 0x206f, + 0x781b, 0x0067, 0x0078, 0x2067, 0x2001, 0x0005, 0x0078, 0x3232, + 0x2001, 0x000c, 0x0078, 0x3232, 0x2001, 0x0006, 0x0078, 0x3232, + 0x2001, 0x000d, 0x0078, 0x3232, 0x2001, 0x0009, 0x0078, 0x3232, + 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xa6b5, 0x0008, 0x7e5a, + 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, + 0xa0e0, 0x3d00, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, + 0x0040, 0x3252, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, + 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, + 0x0040, 0x3262, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, + 0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, + 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, + 0x0004, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, + 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, + 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, 0xa084, + 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, + 0xfff0, 0x2001, 0x3c46, 0x2004, 0xa082, 0x0028, 0x0040, 0x32a0, + 0x2021, 0x332b, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x32a6, + 0x2021, 0x3337, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, + 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x32b5, 0x8420, 0x2300, + 0xa210, 0x0070, 0x32b5, 0x0078, 0x32a8, 0x157f, 0x007c, 0x157e, + 0x2011, 0x3c46, 0x2214, 0xa282, 0x0032, 0x0048, 0x32cb, 0x0040, + 0x32cf, 0x2021, 0x331d, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, + 0x0032, 0x0078, 0x32e1, 0xa282, 0x0028, 0x0040, 0x32d9, 0x2021, + 0x332b, 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064, 0x0078, + 0x32e1, 0x2021, 0x3337, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, + 0x0064, 0x2200, 0xa502, 0x0040, 0x32f1, 0x0048, 0x32f1, 0x8420, + 0x2300, 0xa210, 0x0070, 0x32ee, 0x0078, 0x32e1, 0x157f, 0xa006, + 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8, 0x32fc, 0x7808, 0xa085, + 0x0070, 0x780a, 0x0078, 0x32fc, 0x78ec, 0xa084, 0x0300, 0x0040, + 0x330a, 0x2404, 0xa09e, 0x1102, 0x00c0, 0x330a, 0x2001, 0x2101, + 0x0078, 0x331b, 0x2404, 0xa09e, 0x1102, 0x00c0, 0x331b, 0x2001, + 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048, 0x331a, 0x2001, 0x1201, + 0x0078, 0x331b, 0x2404, 0xa005, 0x007c, 0x1102, 0x3002, 0x3202, + 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, + 0x0c07, 0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202, 0x7202, + 0x6605, 0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, + 0x3202, 0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604, 0x7804, + 0x7a04, 0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, + 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003, 0x8003, + 0x8003, 0xa105, 0xa0e0, 0x3d80, 0x007c, 0x79d8, 0x7adc, 0x78d0, + 0x801b, 0x00c8, 0x335c, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, + 0x0000, 0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3c40, 0x2091, + 0x8000, 0x2104, 0x0079, 0x336c, 0x339e, 0x3376, 0x3376, 0x3376, + 0x3376, 0x3376, 0x3376, 0x3374, 0x1078, 0x2007, 0x784b, 0x0004, + 0x7848, 0xa084, 0x0004, 0x00c0, 0x3378, 0x784b, 0x0008, 0x7848, + 0xa084, 0x0008, 0x00c0, 0x337f, 0x68b4, 0xa085, 0x4000, 0x68b6, + 0x7858, 0xa085, 0x4000, 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, + 0x339e, 0x0018, 0x339e, 0x681c, 0xa084, 0x0020, 0x00c0, 0x339c, + 0x781b, 0x00df, 0x0078, 0x339e, 0x781b, 0x00e6, 0x2091, 0x8001, + 0x0f7f, 0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa0e0, 0x3d00, 0x6004, 0xa084, 0x000a, 0x00c0, + 0x33d5, 0x6108, 0xa194, 0xff00, 0x0040, 0x33d5, 0xa18c, 0x00ff, + 0x2001, 0x0019, 0xa106, 0x0040, 0x33c4, 0x2001, 0x0032, 0xa106, + 0x0040, 0x33c8, 0x0078, 0x33cc, 0x2009, 0x0020, 0x0078, 0x33ce, + 0x2009, 0x003f, 0x0078, 0x33ce, 0x2011, 0x0000, 0x2100, 0xa205, + 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, + 0x0068, 0x0078, 0x2067, 0x781b, 0x0067, 0x0078, 0x2067, 0x781b, + 0x0056, 0x0078, 0x2067, 0x781b, 0x0053, 0x0078, 0x2067, 0x781b, + 0x00df, 0x0078, 0x2067, 0x781b, 0x00de, 0x0078, 0x2067, 0x781b, + 0x00e6, 0x0078, 0x2067, 0x781b, 0x00e5, 0x0078, 0x2067, 0x781b, + 0x009d, 0x0078, 0x2067, 0x781b, 0x009c, 0x0078, 0x2067, 0x6818, + 0xa084, 0x8000, 0x0040, 0x3406, 0x681b, 0x001d, 0x70a3, 0x0001, + 0x781b, 0x0047, 0x0078, 0x2067, 0x007e, 0x7830, 0xa084, 0x00c0, + 0x00c0, 0x3423, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, + 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x3423, 0x7808, + 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0x7808, 0xa085, 0x0002, + 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, 0x00c0, 0x342a, 0x0098, + 0x3433, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, + 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x3442, + 0x0098, 0x3440, 0x78ac, 0x007e, 0x7808, 0xa085, 0x0002, 0x780a, + 0x007f, 0x007c, 0xa784, 0x0070, 0x0040, 0x344e, 0xa784, 0x0008, + 0x0040, 0x345b, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, + 0x206f, 0x0078, 0x33d7, 0xa784, 0x0004, 0x0040, 0x348e, 0x78b8, + 0xa084, 0x4001, 0x0040, 0x348e, 0x784b, 0x0008, 0x78ec, 0xa084, + 0x0003, 0x0040, 0x206f, 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, + 0x00c0, 0x348e, 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, + 0x00e6, 0x0078, 0x2067, 0x784b, 0x0008, 0x6818, 0xa084, 0x8000, + 0x0040, 0x348a, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040, 0x348a, + 0x681b, 0x0007, 0x781b, 0x00df, 0x0078, 0x2067, 0x681b, 0x0003, + 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, + 0x784b, 0x0008, 0x78e4, 0xa005, 0x00d0, 0x252a, 0xa084, 0x0020, + 0x0040, 0x252a, 0x78ec, 0xa084, 0x0003, 0x0040, 0x252a, 0x0018, + 0x252a, 0x0078, 0x3204, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa080, 0x3d00, 0x2060, 0x2048, 0x704a, 0x6000, + 0x704e, 0x6004, 0x7052, 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, + 0x000a, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x98f9, 0x98e9, + 0x0014, 0x0014, 0x0014, 0x0080, 0x00c0, 0x0100, 0x0402, 0x2008, + 0xf880, 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0xa200, + 0x8838, 0x3806, 0x8839, 0x28c2, 0x9cc2, 0xa805, 0x0864, 0xa83d, + 0x3008, 0x28c1, 0x9cc2, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, + 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9c9f, 0xa8f3, + 0x0864, 0xa82b, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9c9f, 0x280d, + 0xa204, 0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, + 0x8677, 0xa80f, 0x786e, 0x883e, 0xa80c, 0x282b, 0xa205, 0x64a0, + 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa801, + 0x883e, 0x206b, 0x28c1, 0x9cc2, 0x2044, 0x2103, 0x20a2, 0x2081, + 0xa8dc, 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, 0x8000, 0x85a4, + 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, + 0x0704, 0x3008, 0x9c9f, 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, + 0x84a8, 0x19e2, 0xf848, 0x8176, 0x86eb, 0x85eb, 0x872e, 0x87a9, + 0x883f, 0x08e6, 0xa8f1, 0xf861, 0xa8e8, 0xf801, 0x0014, 0xf881, + 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, + 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0xa206, + 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, + 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, 0x3008, 0x84a8, + 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, 0x0016, 0x8000, + 0x2848, 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011, + 0xa8fd, 0xa883, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017, + 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0xd301, 0x0014, + 0x26e0, 0x873a, 0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014, + 0xa20d, 0x3806, 0x0210, 0x9ccc, 0x0704, 0x0000, 0x127e, 0x2091, + 0x2200, 0x2049, 0x35ae, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215, + 0x7008, 0xa084, 0xfff7, 0xa205, 0x0040, 0x35c0, 0x0078, 0x35c3, + 0x127f, 0x2000, 0x007c, 0x7000, 0xa084, 0x0001, 0x00c0, 0x35f1, + 0x7108, 0x8103, 0x00c8, 0x35d0, 0x1078, 0x36de, 0x0078, 0x35c8, + 0x700c, 0xa08c, 0x00ff, 0x0040, 0x35f1, 0x7004, 0x8004, 0x00c8, + 0x35e8, 0x7014, 0xa005, 0x00c0, 0x35e4, 0x7010, 0xa005, 0x0040, + 0x35e8, 0xa102, 0x00c8, 0x35c8, 0x7007, 0x0010, 0x0078, 0x35f1, + 0x8aff, 0x0040, 0x35f1, 0x1078, 0x38f7, 0x00c0, 0x35eb, 0x0040, + 0x35c8, 0x1078, 0x366e, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, + 0x6428, 0x84ff, 0x0040, 0x3624, 0x2c70, 0x7004, 0xa0bc, 0x000f, + 0xa7b8, 0x3634, 0x273c, 0x87fb, 0x00c0, 0x3612, 0x0048, 0x360a, + 0x1078, 0x2007, 0x609c, 0xa075, 0x0040, 0x3624, 0x0078, 0x35fd, + 0x2039, 0x3629, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, + 0x8421, 0x0040, 0x3624, 0x8738, 0x2704, 0xa005, 0x00c0, 0x3613, + 0x709c, 0xa075, 0x00c0, 0x35fd, 0x007c, 0x0000, 0x0005, 0x0009, + 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, + 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x3629, 0x3626, 0x0000, + 0x0000, 0x8000, 0x0000, 0x3629, 0x0000, 0x3631, 0x362e, 0x0000, + 0x0000, 0x0000, 0x0000, 0x3631, 0x0000, 0x362c, 0x362c, 0x0000, + 0x0000, 0x8000, 0x0000, 0x362c, 0x0000, 0x3632, 0x3632, 0x0000, + 0x0000, 0x0000, 0x0000, 0x3632, 0x127e, 0x2091, 0x2200, 0x2079, + 0x3c00, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, + 0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, + 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x2049, 0x366e, + 0x2019, 0x0000, 0x7004, 0x8004, 0x00c8, 0x36ba, 0x7007, 0x0012, + 0x7108, 0x7008, 0xa106, 0x00c0, 0x3678, 0xa184, 0x01e0, 0x0040, + 0x3683, 0x1078, 0x2007, 0xa184, 0x4000, 0x00c0, 0x3678, 0xa19c, + 0x300c, 0xa386, 0x2004, 0x0040, 0x3695, 0xa386, 0x0008, 0x0040, + 0x36a0, 0xa386, 0x200c, 0x00c0, 0x3678, 0x7200, 0x8204, 0x0048, + 0x36a0, 0x730c, 0xa384, 0x00ff, 0x0040, 0x36a0, 0x1078, 0x2007, + 0x7007, 0x0012, 0x7000, 0xa084, 0x0001, 0x00c0, 0x36ba, 0x7008, + 0xa084, 0x01e0, 0x00c0, 0x36ba, 0x7310, 0x7014, 0xa305, 0x0040, + 0x36ba, 0x710c, 0xa184, 0x0300, 0x00c0, 0x36ba, 0xa184, 0x00ff, + 0x00c0, 0x366e, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, + 0x0008, 0x00c0, 0x36be, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, + 0x36c3, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, 0x007e, + 0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x36de, 0x157f, + 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, 0x7500, + 0x730c, 0xa384, 0x0300, 0x00c0, 0x3720, 0xa184, 0x01e0, 0x00c0, + 0x3744, 0x7108, 0xa184, 0x01e0, 0x00c0, 0x3744, 0x2001, 0x04fd, + 0x2004, 0xa082, 0x0005, 0x00c8, 0x3714, 0xa184, 0x4000, 0x00c0, + 0x36e9, 0xa986, 0x3920, 0x00c0, 0x3714, 0xa19c, 0x300c, 0xa386, + 0x2004, 0x0040, 0x370b, 0xa386, 0x0008, 0x0040, 0x3714, 0xa386, + 0x200c, 0x00c0, 0x36e9, 0x7200, 0x8204, 0x0048, 0x3714, 0x730c, + 0xa384, 0x00ff, 0x00c0, 0x3720, 0xa184, 0x0007, 0x0079, 0x3718, + 0x3722, 0x3734, 0x3720, 0x3734, 0x3720, 0x3780, 0x3720, 0x377e, + 0x1078, 0x2007, 0x7004, 0xa084, 0x0010, 0xa085, 0x0002, 0x7006, + 0x8aff, 0x00c0, 0x372f, 0x2049, 0x0000, 0x0078, 0x3733, 0x1078, + 0x38f7, 0x00c0, 0x372f, 0x007c, 0x7004, 0xa084, 0x0010, 0xa085, + 0x0002, 0x7006, 0x8aff, 0x00c0, 0x373f, 0x0078, 0x3743, 0x1078, + 0x38f7, 0x00c0, 0x373f, 0x007c, 0x7007, 0x0012, 0x7108, 0x00e0, + 0x3747, 0x2091, 0x6000, 0x00e0, 0x374b, 0x2091, 0x6000, 0x7007, + 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0, 0x3753, + 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, 0x3758, 0x7003, 0x0000, + 0x7000, 0xa005, 0x00c0, 0x376c, 0x7004, 0xa005, 0x00c0, 0x376c, + 0x700c, 0xa005, 0x0040, 0x376e, 0x0078, 0x374f, 0x2049, 0x0000, + 0x1078, 0x3362, 0x6818, 0xa084, 0x8000, 0x0040, 0x3779, 0x681b, + 0x0002, 0x007c, 0x1078, 0x2007, 0x1078, 0x2007, 0x1078, 0x37dc, + 0x7210, 0x7114, 0x700c, 0xa09c, 0x00ff, 0x2800, 0xa300, 0xa211, + 0xa189, 0x0000, 0x1078, 0x37dc, 0x2704, 0x2c58, 0xac60, 0x6308, + 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305, 0x0040, + 0x37a3, 0x00c8, 0x37a3, 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, + 0x2b60, 0x0078, 0x378a, 0x2b60, 0x8a07, 0x007e, 0x6004, 0xa084, + 0x0008, 0x0040, 0x37af, 0xa7ba, 0x362e, 0x0078, 0x37b1, 0xa7ba, + 0x3626, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, + 0x7007, 0x0012, 0x1078, 0x366e, 0x007c, 0x8738, 0x2704, 0xa005, + 0x00c0, 0x37d0, 0x609c, 0xa005, 0x0040, 0x37d9, 0x2060, 0x6004, + 0xa084, 0x000f, 0xa080, 0x3634, 0x203c, 0x87fb, 0x1040, 0x2007, + 0x8a51, 0x0040, 0x37d8, 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, + 0x007c, 0x2051, 0x0000, 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, + 0x00c0, 0x37f0, 0x6000, 0xa064, 0x00c0, 0x37e7, 0x2d60, 0x6004, + 0xa084, 0x000f, 0xa080, 0x3644, 0x203c, 0x87fb, 0x1040, 0x2007, + 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6884, 0x2060, + 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, + 0x007e, 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x380b, 0xa0b8, + 0x362e, 0x0078, 0x380d, 0xa0b8, 0x3626, 0x7e08, 0xa6b5, 0x000c, + 0x681c, 0xa084, 0x0040, 0x0040, 0x3817, 0xa6b5, 0x0001, 0x7007, + 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x3819, 0x2400, 0xa305, + 0x00c0, 0x3824, 0x0078, 0x384a, 0x2c58, 0x2704, 0x6104, 0xac60, + 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, 0x0008, + 0x0040, 0x383a, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081, + 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300, + 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, 0x37bd, + 0x0078, 0x384c, 0x1078, 0x38f7, 0x00c0, 0x384a, 0x127f, 0x2000, + 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004, + 0x7004, 0xa084, 0x0004, 0x00c0, 0x3858, 0x7003, 0x0008, 0x127f, + 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, + 0x3862, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x386b, + 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084, 0x0020, 0x00c0, 0x387a, + 0xa6b5, 0x0001, 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, + 0xa7b8, 0x3634, 0x273c, 0x87fb, 0x00c0, 0x3890, 0x0048, 0x388a, + 0x1078, 0x2007, 0x689c, 0xa065, 0x0040, 0x3894, 0x0078, 0x387d, + 0x1078, 0x38f7, 0x00c0, 0x3890, 0x127f, 0x2000, 0x007c, 0x127e, + 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, 0x047f, + 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084, 0x0040, 0x0040, 0x38aa, + 0xa6b5, 0x0001, 0x2049, 0x3897, 0x6828, 0xa055, 0x0040, 0x38f4, + 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x3634, 0x273c, + 0x87fb, 0x00c0, 0x38c6, 0x0048, 0x38bf, 0x1078, 0x2007, 0x709c, + 0xa075, 0x2060, 0x0040, 0x38f4, 0x0078, 0x38b2, 0x2704, 0xae68, + 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, 0x38e1, 0x8a51, 0x00c0, + 0x38d3, 0x1078, 0x2007, 0x8738, 0x2704, 0xa005, 0x00c0, 0x38c7, + 0x709c, 0xa075, 0x2060, 0x0040, 0x38f4, 0x2039, 0x3626, 0x0078, + 0x38b2, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, + 0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, 0x38f0, 0x1078, 0x2007, + 0x2071, 0x0020, 0x0078, 0x3817, 0x127f, 0x2000, 0x007c, 0x7008, + 0xa084, 0x0003, 0xa086, 0x0003, 0x0040, 0x391f, 0x2704, 0xac08, + 0x2104, 0x701a, 0x8108, 0x2104, 0x701e, 0x8108, 0x2104, 0x7012, + 0x8108, 0x2104, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x3916, + 0x8108, 0x2104, 0x7022, 0x8108, 0x2104, 0x7026, 0x7602, 0x7004, + 0xa084, 0x0010, 0xa085, 0x0001, 0x7006, 0x1078, 0x37bd, 0x007c, + 0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, 0x2049, 0x3920, 0x0d7f, + 0x087f, 0x7108, 0xa184, 0x0003, 0x00c0, 0x3934, 0x6828, 0xa005, + 0x0040, 0x3942, 0x0078, 0x35c3, 0x00a0, 0x393b, 0x7108, 0x1078, + 0x36de, 0x0078, 0x3929, 0x7007, 0x0010, 0x00a0, 0x393d, 0x7108, + 0x1078, 0x36de, 0x7008, 0xa086, 0x0008, 0x00c0, 0x3929, 0x7000, + 0xa005, 0x00c0, 0x3929, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, + 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, + 0x2091, 0x2200, 0x0d7f, 0x2049, 0x3952, 0xad80, 0x0011, 0x20a0, + 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff, 0x682a, 0x7007, 0x0008, + 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x3971, 0x8000, 0x80ac, + 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x3973, + 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, + 0x127f, 0x2000, 0x007c, 0x2091, 0x6000, 0x2091, 0x8000, 0x78c0, + 0xa005, 0x00c0, 0x399a, 0x798c, 0x70d0, 0xa106, 0x00c0, 0x399a, + 0x7804, 0xa005, 0x0040, 0x399a, 0x7807, 0x0000, 0x0068, 0x399a, + 0x2091, 0x4080, 0x7820, 0x8001, 0x7822, 0x00c0, 0x3a1f, 0x7824, + 0x7822, 0x783c, 0xa005, 0x0040, 0x39ab, 0x8001, 0x783e, 0x00c0, + 0x39ab, 0x1078, 0x3b47, 0x78ec, 0xa005, 0x0040, 0x39cf, 0x78d4, + 0xa005, 0x00c0, 0x39cf, 0x3a10, 0xa284, 0x0002, 0x00c0, 0x39bf, + 0x78d7, 0x0007, 0x2009, 0xff01, 0x200a, 0x0078, 0x39cf, 0xa284, + 0x0001, 0x00c0, 0x39c7, 0x78eb, 0x0000, 0x0078, 0x39cf, 0x78e8, + 0xa005, 0x00c0, 0x39cf, 0x78d7, 0x0008, 0x78eb, 0x0001, 0x2069, + 0x3c40, 0x6800, 0xa084, 0x0007, 0x0040, 0x39e6, 0xa086, 0x0002, + 0x0040, 0x39e6, 0x6830, 0xa00d, 0x0040, 0x39e6, 0x2104, 0xa005, + 0x0040, 0x39e6, 0x8001, 0x200a, 0x0040, 0x3ac1, 0x7848, 0xa005, + 0x0040, 0x39f0, 0x8001, 0x784a, 0x00c0, 0x39f0, 0x1078, 0x1e9d, + 0x68c4, 0xa005, 0x0040, 0x39fc, 0x8001, 0x68c6, 0x00c0, 0x39fc, + 0x68a3, 0x0000, 0x68a7, 0x0001, 0x2061, 0x3d80, 0x20a9, 0x0080, + 0x2009, 0x0001, 0x6034, 0xa005, 0x0040, 0x3a12, 0x8001, 0x6036, + 0x00c0, 0x3a12, 0x6010, 0xa005, 0x0040, 0x3a12, 0x017e, 0x1078, + 0x1e9d, 0x017f, 0xace0, 0x0010, 0x0070, 0x3a18, 0x0078, 0x3a02, + 0x8109, 0x0040, 0x3a1f, 0x20a9, 0x0100, 0x0078, 0x3a02, 0x1078, + 0x3a26, 0x1078, 0x3a4b, 0x2091, 0x8001, 0x007c, 0x7834, 0x8001, + 0x7836, 0x00c0, 0x3a4a, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, + 0xa005, 0x00c0, 0x3a35, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, + 0x4580, 0x2040, 0x2004, 0xa065, 0x0040, 0x3a4a, 0x6024, 0xa005, + 0x0040, 0x3a46, 0x8001, 0x6026, 0x0040, 0x3a7a, 0x6000, 0x2c40, + 0x0078, 0x3a3b, 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x3a79, + 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x3a58, 0x2001, 0x0080, + 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x3d80, + 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040, 0x3a79, 0xa290, + 0x0009, 0x2204, 0xa005, 0x0040, 0x3a71, 0x8001, 0x2012, 0x00c0, + 0x3a79, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, + 0x1e9d, 0x007c, 0x2069, 0x3c40, 0x6800, 0xa005, 0x0040, 0x3a84, + 0x683c, 0xac06, 0x0040, 0x3ac1, 0x601b, 0x0006, 0x60b4, 0xa084, + 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, + 0x6000, 0x2042, 0x6714, 0x6fb6, 0x1078, 0x1995, 0x6818, 0xa005, + 0x0040, 0x3a9c, 0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, + 0x6810, 0x8001, 0x00d0, 0x3aa6, 0x1078, 0x2007, 0x6812, 0x602f, + 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x1b24, 0x2069, 0x3c40, + 0x7944, 0xa184, 0x0100, 0x2001, 0x0006, 0x68a2, 0x00c0, 0x3abc, + 0x69ba, 0x2001, 0x0004, 0x68a2, 0x1078, 0x1e98, 0x2091, 0x8001, + 0x007c, 0x2009, 0x3c4f, 0x2164, 0x2069, 0x0100, 0x601b, 0x0006, + 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, + 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6830, 0xa084, + 0x0040, 0x0040, 0x3afb, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, + 0xa084, 0x0004, 0x0040, 0x3ae8, 0x0070, 0x3ae8, 0x0078, 0x3adf, + 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, + 0x3af5, 0x0070, 0x3af5, 0x0078, 0x3aec, 0x20a9, 0x00fa, 0x0070, + 0x3afb, 0x0078, 0x3af7, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, + 0x0047, 0x2009, 0x3c68, 0x200b, 0x0007, 0x784c, 0x784a, 0x2091, + 0x8001, 0x007c, 0x2079, 0x3c00, 0x1078, 0x3b35, 0x1078, 0x3b19, + 0x1078, 0x3b27, 0x7833, 0x0000, 0x7847, 0x0000, 0x784b, 0x0000, + 0x007c, 0x2019, 0x000c, 0x2011, 0x3c46, 0x2204, 0xa086, 0x003c, + 0x0040, 0x3b24, 0x2019, 0x0008, 0x7b2a, 0x7b2e, 0x007c, 0x2019, + 0x0039, 0x2011, 0x3c46, 0x2204, 0xa086, 0x003c, 0x0040, 0x3b32, + 0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, 0x3971, 0x2011, + 0x3c46, 0x2204, 0xa086, 0x003c, 0x0040, 0x3b40, 0x2019, 0x2626, + 0x7b22, 0x7b26, 0x783f, 0x0000, 0x7843, 0x000a, 0x007c, 0x2069, + 0x3c40, 0x6a40, 0xa285, 0x0000, 0x0040, 0x3b61, 0x6944, 0xa080, + 0x3c80, 0x2164, 0x6304, 0x83ff, 0x00c0, 0x3b61, 0x8211, 0x0040, + 0x3b64, 0x8108, 0xa11a, 0x0048, 0x3b51, 0x2009, 0x3c80, 0x0078, + 0x3b51, 0x7940, 0x793e, 0x007c, 0x2039, 0x0000, 0x20a9, 0x0080, + 0x1078, 0x1995, 0x2d00, 0xa088, 0x0002, 0x2168, 0x682b, 0x0000, + 0x682f, 0x0000, 0x2104, 0xa085, 0x0040, 0x200a, 0x2100, 0xa088, + 0x0010, 0x0070, 0x3b7d, 0x0078, 0x3b6d, 0x2009, 0x3c51, 0x200b, + 0x3c7f, 0x2009, 0x3c50, 0x200b, 0x0000, 0x007c, 0xf686 +}; + +unsigned short risc_1040_code_length01 = 0x2b87; + +#else + +unsigned short risc_1040_code_version = 0x0000; +unsigned short risc_1040_code_addr01 = 0x0000 ; +unsigned short risc_1040_code01[] = { 0x0000 }; +unsigned short risc_1040_code_length01 = 0x0000; + +#endif + + +#ifdef QLOGIC_1080_FIRMWARE_SUPPORT + +/************************************************************************ + * * + * --- ISP1240 Initiator RISC Firmware --- * + * 32 LUN Support * + * * + ************************************************************************ + * * + * NOTICE * + * * + * COPYRIGHT 1994-2001 QLOGIC CORPORATION * + * ALL RIGHTS RESERVED * + * * + * This computer program is CONFIDENTIAL and contains TRADE SECRETS of * + * QLOGIC CORPORATION. The receipt or possession of this program does * + * not convey any rights to reproduce or disclose its contents, or to * + * manufacture, use, or sell anything that it may describe, in whole or * + * in part, without the specific written consent of QLOGIC CORPORATION. * + * Any reproduction of this program without the express written consent * + * of QLOGIC CORPORATION is a violation of the copyright laws and may * + * subject you to civil liability and criminal prosecution. * + * * + ************************************************************************ + */ + + +/* + * Firmware Version 8.15.10 (10:30 Jul 09, 2001) + */ + +unsigned short risc_1080_code_version = 8*1024+15; + +unsigned short risc_1080_code_addr01 = 0x1000 ; + +unsigned short risc_1080_code01[] = { + 0x0078, 0x1041, 0x0000, 0x3e1e, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, + 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, + 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, + 0x3132, 0x3430, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, + 0x6572, 0x7369, 0x6f6e, 0x2030, 0x382e, 0x3135, 0x2020, 0x2043, + 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, + 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, + 0x2400, 0x20c9, 0x98ff, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1080, + 0x00c0, 0x1054, 0x2071, 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, + 0x2089, 0x1374, 0x0078, 0x106d, 0x2001, 0x04fc, 0x2004, 0xa086, + 0x1280, 0x00c0, 0x1069, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2071, + 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, 0x2089, 0x13f8, 0x0078, + 0x106d, 0x20c1, 0x0020, 0x2089, 0x131c, 0x2071, 0x0010, 0x70c3, + 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, + 0x0008, 0x2001, 0x04fe, 0x70d6, 0x20c1, 0x0021, 0x2019, 0x0000, + 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, + 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, + 0xa286, 0xa5a5, 0x0040, 0x10a4, 0xa386, 0x000f, 0x0040, 0x10a0, + 0x2c6a, 0x2a5a, 0x20c1, 0x0020, 0x2019, 0x000f, 0x0078, 0x1080, + 0x2c6a, 0x2a5a, 0x0078, 0x10a2, 0x2c6a, 0x2a5a, 0x2130, 0x2128, + 0xa1a2, 0x4f00, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0xa192, 0x9900, 0x2009, 0x0000, 0x2001, 0x0032, 0x1078, 0x20ba, + 0x2218, 0x2079, 0x4f00, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, + 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10bf, 0x2009, 0xff00, 0x3400, + 0xa102, 0x0048, 0x10cf, 0x0040, 0x10cf, 0x20a8, 0x42a4, 0x2001, + 0x04fc, 0x2004, 0xa086, 0x1080, 0x00c0, 0x10e5, 0x2071, 0x0100, + 0x0d7e, 0x2069, 0x4f40, 0x1078, 0x4da0, 0x0d7f, 0x7810, 0xc0ed, + 0x7812, 0x781b, 0x0064, 0x0078, 0x110a, 0x2001, 0x04fc, 0x2004, + 0xa086, 0x1280, 0x00c0, 0x1105, 0x7814, 0xc0ed, 0xc0d5, 0x7816, + 0x781b, 0x0064, 0x2071, 0x0200, 0x0d7e, 0x2069, 0x4f40, 0x1078, + 0x4da0, 0x2069, 0x4f80, 0x2071, 0x0100, 0x1078, 0x4da0, 0x7814, + 0xc0d4, 0x7816, 0x0d7f, 0x0078, 0x110a, 0x7814, 0xc0e5, 0x7816, + 0x781b, 0x003c, 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, + 0xc08d, 0x7802, 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, + 0x7827, 0x0002, 0x2009, 0x0002, 0x2069, 0x4f40, 0x681b, 0x0003, + 0x6823, 0x0007, 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, + 0x6837, 0x0000, 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, + 0x8109, 0x0040, 0x115e, 0x68d3, 0x000a, 0x68c3, 0x4fc0, 0x2079, + 0x4f00, 0x7814, 0xd0e4, 0x00c0, 0x1144, 0xd0ec, 0x00c0, 0x1148, + 0x68d7, 0x7329, 0x0078, 0x114a, 0x68d7, 0x730d, 0x0078, 0x114a, + 0x68d7, 0x732d, 0x68c7, 0x54c0, 0x68cb, 0x53c0, 0x68cf, 0x94c0, + 0x68ab, 0x9744, 0x68af, 0x9749, 0x68b3, 0x9744, 0x68b7, 0x9744, + 0x68a7, 0x0001, 0x2069, 0x4f80, 0x0078, 0x111e, 0x68d3, 0x000a, + 0x68c3, 0x51c0, 0x7814, 0xd0e4, 0x00c0, 0x116a, 0x68d7, 0x7439, + 0x0078, 0x116c, 0x68d7, 0x7419, 0x68c7, 0x74c0, 0x68cb, 0x5440, + 0x68cf, 0x95d0, 0x68ab, 0x9749, 0x68af, 0x974e, 0x68b3, 0x9749, + 0x68b7, 0x9749, 0x68a7, 0x0001, 0x7810, 0xd0ec, 0x00c0, 0x11c2, + 0x7814, 0xd0e4, 0x00c0, 0x11b4, 0x0e7e, 0x2069, 0x53c0, 0x2071, + 0x0200, 0x70ec, 0xd0e4, 0x00c0, 0x1195, 0x2019, 0x0c0c, 0x2021, + 0x000c, 0x1078, 0x2049, 0x0078, 0x119b, 0x2019, 0x0c0a, 0x2021, + 0x000a, 0x1078, 0x2049, 0x2069, 0x5440, 0x2071, 0x0100, 0x70ec, + 0xd0e4, 0x00c0, 0x11ab, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, + 0x2049, 0x0078, 0x11b1, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, + 0x2049, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0c, 0x2021, 0x000c, + 0x2069, 0x53c0, 0x1078, 0x2049, 0x2069, 0x5440, 0x1078, 0x2049, + 0x0078, 0x11db, 0x2069, 0x53c0, 0x0e7e, 0x2071, 0x0100, 0x70ec, + 0xd0e4, 0x00c0, 0x11d4, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, + 0x2049, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0a, 0x2021, 0x000a, + 0x1078, 0x2049, 0x0e7f, 0x2011, 0x0002, 0x2069, 0x54c0, 0x2009, + 0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bc8, + 0xa386, 0xfeff, 0x00c0, 0x11f2, 0x6817, 0x0100, 0x681f, 0x0064, + 0x0078, 0x11f6, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, + 0x00f0, 0x11e3, 0x8109, 0x00c0, 0x11e1, 0x8211, 0x0040, 0x1204, + 0x2069, 0x74c0, 0x0078, 0x11df, 0x1078, 0x269b, 0x1078, 0x4703, + 0x1078, 0x1e14, 0x1078, 0x4d32, 0x2091, 0x2100, 0x2079, 0x4f00, + 0x7810, 0xd0ec, 0x0040, 0x1218, 0x2071, 0x0020, 0x0078, 0x121a, + 0x2071, 0x0050, 0x2091, 0x2200, 0x2079, 0x4f00, 0x2071, 0x0020, + 0x2091, 0x2300, 0x2079, 0x4f00, 0x7810, 0xd0ec, 0x0040, 0x122c, + 0x2079, 0x0100, 0x0078, 0x122e, 0x2079, 0x0200, 0x2071, 0x4f40, + 0x2091, 0x2400, 0x2079, 0x0100, 0x2071, 0x4f80, 0x2091, 0x2000, + 0x2079, 0x4f00, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, + 0x2071, 0x0010, 0x70c3, 0x0000, 0x0090, 0x124d, 0x70c0, 0xa086, + 0x0002, 0x00c0, 0x124d, 0x1078, 0x15c1, 0x2039, 0x0000, 0x7810, + 0xd0ec, 0x00c0, 0x12cf, 0x1078, 0x148e, 0x78ac, 0xa005, 0x00c0, + 0x126b, 0x0068, 0x1261, 0x786c, 0xa065, 0x0040, 0x1261, 0x1078, + 0x23d5, 0x1078, 0x20e1, 0x0068, 0x1278, 0x786c, 0xa065, 0x0040, + 0x126b, 0x1078, 0x23d5, 0x0068, 0x1278, 0x2009, 0x4f47, 0x2011, + 0x4f87, 0x2104, 0x220c, 0xa105, 0x0040, 0x1278, 0x1078, 0x1f4a, + 0x2071, 0x4f40, 0x70a4, 0xa005, 0x0040, 0x129d, 0x7450, 0xa485, + 0x0000, 0x0040, 0x129d, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, + 0xa28c, 0x303d, 0x2190, 0x1078, 0x2baa, 0x2091, 0x8000, 0x2091, + 0x303d, 0x0068, 0x129d, 0x2079, 0x4f00, 0x786c, 0xa065, 0x0040, + 0x129d, 0x2071, 0x0010, 0x1078, 0x23d5, 0x00e0, 0x12a5, 0x2079, + 0x4f00, 0x2071, 0x0010, 0x1078, 0x4b06, 0x2071, 0x4f80, 0x70a4, + 0xa005, 0x0040, 0x12bd, 0x7050, 0xa025, 0x0040, 0x12bd, 0x2079, + 0x0100, 0x2091, 0x8000, 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, + 0x2baa, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079, 0x4f00, 0x2071, + 0x0010, 0x0068, 0x12c9, 0x786c, 0xa065, 0x0040, 0x12c9, 0x1078, + 0x23d5, 0x00e0, 0x1253, 0x1078, 0x4b06, 0x0078, 0x1253, 0x1078, + 0x148e, 0x78ac, 0xa005, 0x00c0, 0x12e7, 0x0068, 0x12dd, 0x786c, + 0xa065, 0x0040, 0x12dd, 0x1078, 0x23d5, 0x1078, 0x20e1, 0x0068, + 0x12f1, 0x786c, 0xa065, 0x0040, 0x12e7, 0x1078, 0x23d5, 0x0068, + 0x12f1, 0x2009, 0x4f47, 0x2104, 0xa005, 0x0040, 0x12f1, 0x1078, + 0x1f4a, 0x2071, 0x4f40, 0x70a4, 0xa005, 0x0040, 0x130c, 0x7450, + 0xa485, 0x0000, 0x0040, 0x130c, 0x2079, 0x0100, 0x2091, 0x8000, + 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, 0x2baa, 0x2091, 0x8000, + 0x2091, 0x303d, 0x2079, 0x4f00, 0x2071, 0x0010, 0x0068, 0x1316, + 0x786c, 0xa065, 0x0040, 0x1316, 0x1078, 0x23d5, 0x00e0, 0x12cf, + 0x1078, 0x4b06, 0x0078, 0x12cf, 0x133c, 0x133c, 0x133e, 0x133e, + 0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363, + 0x134b, 0x134b, 0x134b, 0x134b, 0x133c, 0x133c, 0x133e, 0x133e, + 0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363, + 0x134b, 0x134b, 0x134b, 0x134b, 0x0078, 0x133c, 0x007e, 0x107e, + 0x127e, 0x2091, 0x2400, 0x1078, 0x29ca, 0x127f, 0x107f, 0x007f, + 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13c8, + 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, + 0x127e, 0x2091, 0x2300, 0x1078, 0x29ca, 0x127f, 0x107f, 0x007f, + 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, + 0x1078, 0x29ca, 0x2091, 0x2400, 0x1078, 0x29ca, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x1394, 0x1394, 0x1396, 0x1396, + 0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13ae, 0x13ae, 0x1396, 0x1396, + 0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13af, 0x13af, 0x13af, 0x13af, + 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, + 0x13af, 0x13af, 0x13af, 0x13af, 0x0078, 0x1394, 0x007e, 0x107e, + 0x127e, 0x2091, 0x2300, 0x1078, 0x29ca, 0x127f, 0x107f, 0x007f, + 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13d5, + 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007c, 0x107e, + 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x007e, 0x2071, 0x0100, 0x2069, + 0x4f40, 0x2079, 0x4f00, 0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078, + 0x4da0, 0x007f, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, 0x107f, 0x007c, + 0x3c00, 0xa084, 0x0007, 0x0079, 0x13cd, 0x13de, 0x13de, 0x13e0, + 0x13e0, 0x13e5, 0x13e5, 0x13ea, 0x13ea, 0x3c00, 0xa084, 0x0003, + 0x0079, 0x13da, 0x13de, 0x13de, 0x13f3, 0x13f3, 0x1078, 0x29ab, + 0x2091, 0x2200, 0x1078, 0x47dd, 0x007c, 0x2091, 0x2100, 0x1078, + 0x47dd, 0x007c, 0x2091, 0x2100, 0x1078, 0x47dd, 0x2091, 0x2200, + 0x1078, 0x47dd, 0x007c, 0x2091, 0x2100, 0x1078, 0x47dd, 0x007c, + 0x1418, 0x1418, 0x141a, 0x141a, 0x1427, 0x1427, 0x1427, 0x1427, + 0x1432, 0x1432, 0x143f, 0x143f, 0x1427, 0x1427, 0x1427, 0x1427, + 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, + 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, + 0x0078, 0x1418, 0x007e, 0x107e, 0x127e, 0x2091, 0x2400, 0x1078, + 0x29ca, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, + 0x107e, 0x127e, 0x1078, 0x13c8, 0x127f, 0x107f, 0x007f, 0x2091, + 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, + 0x29ca, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, + 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x29ca, 0x2091, 0x2400, + 0x1078, 0x29ca, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, + 0x007e, 0x107e, 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2079, 0x4f00, + 0x2071, 0x0200, 0x2069, 0x4f40, 0x3d00, 0xd08c, 0x0040, 0x1466, + 0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078, 0x4da0, 0x3d00, 0xd084, + 0x0040, 0x1474, 0x2069, 0x4f80, 0x2071, 0x0100, 0x70ec, 0xa084, + 0x1c00, 0x78e6, 0x1078, 0x4da0, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, + 0x107f, 0x007f, 0x007c, 0x7008, 0x800b, 0x00c8, 0x1489, 0x7007, + 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x148a, 0xd09c, 0x0040, 0x1489, + 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, 0x15c4, 0x0068, 0x151a, + 0x2061, 0x0000, 0x6018, 0xd084, 0x00c0, 0x151a, 0x7828, 0xa005, + 0x00c0, 0x149e, 0x0010, 0x151b, 0x0078, 0x151a, 0x7910, 0xd1f4, + 0x0040, 0x14a4, 0x0078, 0x14b9, 0x7914, 0xd1ec, 0x0040, 0x14bd, + 0xd0fc, 0x0040, 0x14b3, 0x007e, 0x1078, 0x1da7, 0x007f, 0x0040, + 0x14bd, 0x0078, 0x14b9, 0x007e, 0x1078, 0x1d9a, 0x007f, 0x0040, + 0x14bd, 0x2001, 0x4007, 0x0078, 0x15c3, 0x7910, 0xd0fc, 0x00c0, + 0x14c7, 0x2061, 0x4f40, 0xc19c, 0xc7fc, 0x0078, 0x14cb, 0x2061, + 0x4f80, 0xc19d, 0xc7fd, 0x6064, 0xa005, 0x00c0, 0x151a, 0x7912, + 0x6082, 0x7828, 0xc0fc, 0xa086, 0x0018, 0x00c0, 0x14db, 0x0c7e, + 0x1078, 0x1b85, 0x0c7f, 0x782b, 0x0000, 0x607c, 0xa065, 0x0040, + 0x1500, 0x0c7e, 0x609c, 0x1078, 0x1e89, 0x0c7f, 0x609f, 0x0000, + 0x1078, 0x1cce, 0x2009, 0x0018, 0x6087, 0x0103, 0x7810, 0x007e, + 0x84ff, 0x00c0, 0x14f6, 0x85ff, 0x0040, 0x14f8, 0xc0c5, 0x7812, + 0x1078, 0x1db4, 0x007f, 0x7812, 0x00c0, 0x1514, 0x1078, 0x1e06, + 0x7810, 0xd09c, 0x00c0, 0x1508, 0x2061, 0x4f40, 0x0078, 0x150c, + 0x2061, 0x4f80, 0xc09c, 0x7812, 0x607f, 0x0000, 0x60d4, 0xd0dc, + 0x0040, 0x1518, 0xc0dc, 0x60d6, 0x2001, 0x4005, 0x0078, 0x15c3, + 0x0078, 0x15c1, 0x007c, 0x7810, 0xd0f4, 0x0040, 0x1523, 0x2001, + 0x4007, 0x0078, 0x15c3, 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, + 0x70da, 0x70c0, 0xa03d, 0xa08a, 0x0040, 0x00c8, 0x1531, 0x0079, + 0x1538, 0x2100, 0xa08a, 0x0040, 0x00c8, 0x15cf, 0x0079, 0x1578, + 0x15c1, 0x1617, 0x15e0, 0x164f, 0x1687, 0x1687, 0x15d7, 0x1ce6, + 0x1692, 0x15cf, 0x15e4, 0x15e6, 0x15e8, 0x15ea, 0x1ceb, 0x15cf, + 0x16a0, 0x16fd, 0x1ba5, 0x1ce0, 0x15ec, 0x19ea, 0x1a2c, 0x1a67, + 0x1ab8, 0x19a5, 0x19b2, 0x19c6, 0x19d9, 0x17eb, 0x15cf, 0x1734, + 0x1741, 0x174d, 0x1759, 0x176f, 0x177b, 0x177e, 0x178a, 0x1796, + 0x179e, 0x17d3, 0x17df, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x17f8, + 0x180a, 0x1826, 0x185c, 0x1884, 0x1894, 0x1897, 0x18c8, 0x18f9, + 0x190b, 0x1974, 0x1984, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x1994, + 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x1d10, 0x1d16, 0x15cf, + 0x15cf, 0x15cf, 0x1d1a, 0x1d5f, 0x15cf, 0x15cf, 0x15cf, 0x15cf, + 0x1611, 0x1681, 0x169a, 0x16f7, 0x1b9f, 0x15cf, 0x15cf, 0x1b68, + 0x15cf, 0x1d63, 0x1d02, 0x1d0c, 0x15cf, 0x15cf, 0x15cf, 0x15cf, + 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, + 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, + 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, + 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, + 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x15c3, 0x73ce, 0x72ca, + 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, 0x15c4, 0x2061, 0x0000, + 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, 0x70c3, + 0x4001, 0x0078, 0x15c4, 0x70c3, 0x4006, 0x0078, 0x15c4, 0x2099, + 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, 0x15c1, + 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x15c1, 0x0078, 0x15c1, + 0x0078, 0x15c1, 0x0078, 0x15c1, 0x2091, 0x8000, 0x70c3, 0x0004, + 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0008, + 0x2001, 0x000f, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, + 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051, 0x0445, 0x2061, + 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091, 0x4080, 0x0078, + 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x161a, 0x2029, + 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, 0x2099, + 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, + 0x7526, 0x2021, 0x0040, 0x81ff, 0x0040, 0x15c1, 0xa182, 0x0040, + 0x00c8, 0x1634, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x7007, + 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0040, 0x163b, 0x7007, + 0x0002, 0xa084, 0x01e0, 0x0040, 0x1649, 0x70c3, 0x4002, 0x0078, + 0x15c4, 0x24a8, 0x53a5, 0x0078, 0x162b, 0x0078, 0x15c1, 0x2029, + 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x2098, 0x20a1, + 0x0030, 0x7003, 0x0000, 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, + 0x7526, 0x2021, 0x0040, 0x7007, 0x0006, 0x81ff, 0x0040, 0x15c1, + 0xa182, 0x0040, 0x00c8, 0x166e, 0x2120, 0xa006, 0x2008, 0x8403, + 0x7012, 0x24a8, 0x53a6, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0040, + 0x1675, 0xa084, 0x01e0, 0x0040, 0x1663, 0x70c3, 0x4002, 0x0078, + 0x15c4, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1652, 0x71c4, + 0x70c8, 0x2114, 0xa79e, 0x0004, 0x00c0, 0x168f, 0x200a, 0x72ca, + 0x0078, 0x15c0, 0x70c7, 0x0008, 0x70cb, 0x000f, 0x70cf, 0x000a, + 0x0078, 0x15c1, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x16a3, + 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, + 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x16f2, 0xa40a, 0x0040, + 0x16b3, 0x00c8, 0x16bc, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0040, + 0x16c0, 0x78ac, 0xc085, 0x78ae, 0x2001, 0x4005, 0x0078, 0x15c3, + 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00, 0x0040, + 0x16d8, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f, 0xa118, + 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0078, 0x16e2, + 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, 0x0000, + 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, 0x0040, + 0x16ec, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae, + 0x0078, 0x16f5, 0x78ac, 0xc085, 0x78ae, 0x0078, 0x15c1, 0x75d8, + 0x76dc, 0x75da, 0x76de, 0x0078, 0x1700, 0x2029, 0x0000, 0x2530, + 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, + 0xa005, 0x0040, 0x172f, 0xa40a, 0x0040, 0x1710, 0x00c8, 0x1719, + 0x8001, 0x7892, 0xa084, 0xfc00, 0x0040, 0x171d, 0x78ac, 0xc0c5, + 0x78ae, 0x2001, 0x4005, 0x0078, 0x15c3, 0x7a9a, 0x7b9e, 0x7da2, + 0x7ea6, 0x2600, 0xa505, 0x0040, 0x1728, 0x7a10, 0xc2c5, 0x7a12, + 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0078, 0x1732, 0x78ac, + 0xc0c5, 0x78ae, 0x0078, 0x15c1, 0x2009, 0x0000, 0x786c, 0xa065, + 0x0040, 0x173e, 0x8108, 0x6000, 0x0078, 0x1737, 0x7ac4, 0x0078, + 0x15bf, 0x2009, 0x4f48, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15c0, + 0x2011, 0x4f88, 0x2214, 0x0078, 0x15bf, 0x2009, 0x4f49, 0x210c, + 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2011, 0x4f89, 0x2214, 0x0078, + 0x15bf, 0x2061, 0x4f40, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, + 0x7810, 0xd0ec, 0x00c0, 0x176d, 0x2061, 0x4f80, 0x6328, 0x73da, + 0x632c, 0x831c, 0x831c, 0x831c, 0x73de, 0x0078, 0x15bf, 0x2009, + 0x4f4c, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2011, 0x4f8c, + 0x2214, 0x0078, 0x15bf, 0x7918, 0x0078, 0x15c0, 0x2009, 0x4f4d, + 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2011, 0x4f8d, 0x2214, + 0x0078, 0x15bf, 0x2009, 0x4f4e, 0x210c, 0x7810, 0xd0ec, 0x00c0, + 0x15c0, 0x2011, 0x4f8e, 0x2214, 0x0078, 0x15bf, 0x7920, 0x7810, + 0xd0ec, 0x00c0, 0x15c0, 0x7a24, 0x0078, 0x15bf, 0x71c4, 0xd1fc, + 0x00c0, 0x17a6, 0x2011, 0x53c0, 0x0078, 0x17a8, 0x2011, 0x5440, + 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x6a00, + 0x6804, 0xd09c, 0x0040, 0x17b7, 0x6b08, 0x0078, 0x17b8, 0x6b0c, + 0xd1fc, 0x00c0, 0x17bf, 0x2021, 0x023b, 0x0078, 0x17c1, 0x2021, + 0x013b, 0x2424, 0x7914, 0xd1e4, 0x0040, 0x17cd, 0xd4c4, 0x00c0, + 0x17cc, 0xc4d5, 0x0078, 0x17cd, 0xc4dd, 0xa4a4, 0x1c00, 0x74de, + 0x71c4, 0x0078, 0x15be, 0x77c4, 0x1078, 0x1e24, 0x2091, 0x8000, + 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x15be, 0x2061, + 0x4f40, 0x6118, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2061, 0x4f80, + 0x6218, 0x0078, 0x15bf, 0x77c4, 0x1078, 0x1e24, 0x2091, 0x8000, + 0x6908, 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0078, 0x15be, + 0x71c4, 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x00c8, 0x15b9, + 0x1078, 0x27bf, 0xa384, 0x4000, 0x0040, 0x1808, 0xa295, 0x0020, + 0x0078, 0x15be, 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, 0x00c8, + 0x15b9, 0xd1bc, 0x00c0, 0x1819, 0x2011, 0x4f48, 0x2204, 0x0078, + 0x181d, 0x2011, 0x4f88, 0x2204, 0xc0bd, 0x007e, 0x2100, 0xc0bc, + 0x2012, 0x1078, 0x271c, 0x017f, 0x0078, 0x15c0, 0x71c4, 0x2021, + 0x4f49, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0078, 0x1835, 0x71c8, + 0x2021, 0x4f89, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x1854, 0x20a9, + 0x0008, 0x2204, 0xa106, 0x0040, 0x1844, 0x8210, 0x00f0, 0x1839, + 0x71c4, 0x72c8, 0x0078, 0x15b8, 0xa292, 0x1854, 0x027e, 0x2122, + 0x017f, 0x1078, 0x273d, 0x7810, 0xd0ec, 0x00c0, 0x1852, 0xd3fc, + 0x0040, 0x182f, 0x0078, 0x15c1, 0x03e8, 0x00fa, 0x01f4, 0x02ee, + 0x0004, 0x0001, 0x0002, 0x0003, 0x2061, 0x4f40, 0x6128, 0x622c, + 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003, + 0x8003, 0x602e, 0x7810, 0xd0ec, 0x00c0, 0x1882, 0x027e, 0x017e, + 0x2061, 0x4f80, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70d8, + 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, 0x72de, + 0x017f, 0x027f, 0x0078, 0x15bf, 0x2061, 0x4f40, 0x6130, 0x70c4, + 0x6032, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2061, 0x4f80, 0x6230, + 0x70c8, 0x6032, 0x0078, 0x15bf, 0x7918, 0x0078, 0x15c0, 0x71c4, + 0xa184, 0xffcf, 0x0040, 0x18a3, 0x7810, 0xd0ec, 0x00c0, 0x15b9, + 0x72c8, 0x0078, 0x15b8, 0x2011, 0x4f4d, 0x2204, 0x2112, 0x007e, + 0x2019, 0x0000, 0x1078, 0x27a4, 0x7810, 0xd0ec, 0x0040, 0x18b3, + 0x017f, 0x0078, 0x15c0, 0x71c8, 0xa184, 0xffcf, 0x0040, 0x18bc, + 0x2110, 0x71c4, 0x0078, 0x15b8, 0x2011, 0x4f8d, 0x2204, 0x2112, + 0x007e, 0xc3fd, 0x1078, 0x27a4, 0x027f, 0x017f, 0x0078, 0x15bf, + 0x71c4, 0xa182, 0x0010, 0x0048, 0x18d4, 0x7810, 0xd0ec, 0x00c0, + 0x15b9, 0x72c8, 0x0078, 0x15b8, 0x2011, 0x4f4e, 0x2204, 0x007e, + 0x2112, 0x2019, 0x0000, 0x1078, 0x2782, 0x7810, 0xd0ec, 0x0040, + 0x18e4, 0x017f, 0x0078, 0x15c0, 0x71c8, 0xa182, 0x0010, 0x0048, + 0x18ed, 0x2110, 0x71c4, 0x0078, 0x15b8, 0x2011, 0x4f8e, 0x2204, + 0x007e, 0x2112, 0xc3fd, 0x1078, 0x2782, 0x027f, 0x017f, 0x0078, + 0x15bf, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x15b8, 0xa284, + 0xfffd, 0x00c0, 0x15b8, 0x2100, 0x7920, 0x7822, 0x2200, 0x7a24, + 0x7826, 0x0078, 0x15bf, 0x71c4, 0xd1fc, 0x00c0, 0x1913, 0x2011, + 0x53c0, 0x0078, 0x1915, 0x2011, 0x5440, 0x8107, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0xa268, 0x2019, 0x0000, 0x72c8, 0xd2bc, + 0x0040, 0x1924, 0xa39d, 0x0010, 0xd2b4, 0x0040, 0x1929, 0xa39d, + 0x0008, 0x2091, 0x8000, 0x6800, 0x007e, 0xa226, 0x0040, 0x1948, + 0x6a02, 0xd4ec, 0x0040, 0x1935, 0xc3a5, 0xd4e4, 0x0040, 0x1939, + 0xc39d, 0xd4f4, 0x0040, 0x1948, 0x810f, 0xd2f4, 0x0040, 0x1944, + 0x1078, 0x2801, 0x0078, 0x1948, 0x1078, 0x27df, 0x0078, 0x1948, + 0x72cc, 0x6808, 0xa206, 0x0040, 0x196a, 0xa2a4, 0x00ff, 0x7814, + 0xd0e4, 0x00c0, 0x195b, 0xa482, 0x0028, 0x0048, 0x1967, 0x0040, + 0x1967, 0x0078, 0x195f, 0xa482, 0x0043, 0x0048, 0x1967, 0x71c4, + 0x71c6, 0x027f, 0x72ca, 0x2091, 0x8001, 0x0078, 0x15ba, 0x6a0a, + 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, + 0x2091, 0x8001, 0x0078, 0x15be, 0x77c4, 0x1078, 0x1e24, 0x2091, + 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, + 0x681e, 0x2708, 0x0078, 0x15be, 0x70c4, 0x2061, 0x4f40, 0x6118, + 0x601a, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x70c8, 0x2061, 0x4f80, + 0x6218, 0x601a, 0x0078, 0x15bf, 0x71c4, 0x72c8, 0x73cc, 0xa182, + 0x0010, 0x00c8, 0x15b9, 0x1078, 0x2823, 0xa384, 0x4000, 0x0040, + 0x19a3, 0xa295, 0x0020, 0x0078, 0x15be, 0x77c4, 0x1078, 0x1e24, + 0x2091, 0x8000, 0x6a08, 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, + 0x0078, 0x15bf, 0x77c4, 0x1078, 0x1e24, 0x2091, 0x8000, 0x6a08, + 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x19c1, 0x1078, + 0x2668, 0x2091, 0x8001, 0x2708, 0x0078, 0x15bf, 0x77c4, 0x1078, + 0x1e24, 0x2091, 0x8000, 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, + 0x0040, 0x19d4, 0x1078, 0x2668, 0x2091, 0x8001, 0x2708, 0x0078, + 0x15bf, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, + 0x2091, 0x8000, 0x1078, 0x1e3f, 0x2091, 0x8001, 0x2708, 0x6a08, + 0x0078, 0x15bf, 0x77c4, 0x7814, 0xd0e4, 0x00c0, 0x19fe, 0xd7fc, + 0x0040, 0x19f8, 0x1078, 0x1da7, 0x0040, 0x19fe, 0x0078, 0x15c3, + 0x1078, 0x1d9a, 0x0040, 0x19fe, 0x0078, 0x15c3, 0x73c8, 0x72cc, + 0x77c6, 0x73ca, 0x72ce, 0x1078, 0x1ec6, 0x00c0, 0x1a28, 0x6818, + 0xa005, 0x0040, 0x1a22, 0x2708, 0x077e, 0x1078, 0x2853, 0x077f, + 0x00c0, 0x1a22, 0x2001, 0x0015, 0xd7fc, 0x00c0, 0x1a1b, 0x2061, + 0x4f40, 0x0078, 0x1a1e, 0xc0fd, 0x2061, 0x4f80, 0x782a, 0x2091, + 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, 0x0078, 0x15c3, + 0x2091, 0x8001, 0x0078, 0x15c1, 0x77c4, 0x7814, 0xd0e4, 0x00c0, + 0x1a40, 0xd7fc, 0x0040, 0x1a3a, 0x1078, 0x1da7, 0x0040, 0x1a40, + 0x0078, 0x15c3, 0x1078, 0x1d9a, 0x0040, 0x1a40, 0x0078, 0x15c3, + 0x77c6, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, + 0x8000, 0x1078, 0x1e3f, 0x2009, 0x0016, 0xd7fc, 0x00c0, 0x1a54, + 0x2061, 0x4f40, 0x0078, 0x1a57, 0x2061, 0x4f80, 0xc1fd, 0x6067, + 0x0003, 0x607f, 0x0000, 0x6776, 0x6083, 0x000f, 0x792a, 0x61d4, + 0xc1dc, 0x61d6, 0x1078, 0x2668, 0x2091, 0x8001, 0x007c, 0x77c8, + 0x77ca, 0x77c4, 0x77c6, 0x7814, 0xd0e4, 0x00c0, 0x1a7e, 0xd7fc, + 0x0040, 0x1a78, 0x1078, 0x1da7, 0x0040, 0x1a7e, 0x0078, 0x15c3, + 0x1078, 0x1d9a, 0x0040, 0x1a7e, 0x0078, 0x15c3, 0xa7bc, 0xff00, + 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, 0x00c0, 0x1a8b, 0x2061, + 0x4f40, 0x0078, 0x1a8e, 0x2061, 0x4f80, 0xc1fd, 0x607f, 0x0000, + 0x6067, 0x0002, 0x6776, 0x6083, 0x000f, 0x792a, 0x61d4, 0xc1dc, + 0x61d6, 0x1078, 0x2668, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, + 0x0005, 0x2051, 0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, 0x0040, + 0x1aac, 0x60d4, 0xc0fd, 0x60d6, 0x1078, 0x1e3f, 0x70c8, 0x6836, + 0x8738, 0xa784, 0x001f, 0x00c0, 0x1aac, 0x2091, 0x8001, 0x007c, + 0x2019, 0x0000, 0x7814, 0xd0e4, 0x00c0, 0x1ace, 0x72c8, 0xd284, + 0x0040, 0x1ac8, 0x1078, 0x1da7, 0x0040, 0x1ace, 0x0078, 0x15c3, + 0x1078, 0x1d9a, 0x0040, 0x1ace, 0x0078, 0x15c3, 0x72c8, 0x72ca, + 0x78ac, 0xa084, 0x0003, 0x00c0, 0x1af9, 0x2039, 0x0000, 0xd284, + 0x0040, 0x1adb, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, + 0x0008, 0x1078, 0x1e24, 0x2091, 0x8000, 0x6808, 0xc0d4, 0xa80d, + 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1ae1, + 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, + 0x1ae1, 0x2091, 0x8000, 0x72c8, 0xd284, 0x00c0, 0x1b0b, 0x7810, + 0xd0ec, 0x0040, 0x1b07, 0x2069, 0x0100, 0x0078, 0x1b0d, 0x2069, + 0x0200, 0x0078, 0x1b0d, 0x2069, 0x0100, 0x6808, 0xa084, 0xfffd, + 0x680a, 0x6830, 0xd0b4, 0x0040, 0x1b2d, 0x684b, 0x0004, 0x20a9, + 0x0014, 0x6848, 0xd094, 0x0040, 0x1b1f, 0x00f0, 0x1b19, 0x684b, + 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0040, 0x1b29, 0x00f0, + 0x1b23, 0x20a9, 0x00fa, 0x00f0, 0x1b2b, 0x2079, 0x4f00, 0x2009, + 0x0018, 0x72c8, 0xd284, 0x00c0, 0x1b39, 0x2061, 0x4f40, 0x0078, + 0x1b3c, 0x2061, 0x4f80, 0xc1fd, 0x607f, 0x0000, 0x792a, 0x6067, + 0x0001, 0x6083, 0x000f, 0x60a7, 0x0000, 0x60a8, 0x60b2, 0x60b6, + 0x60d4, 0xd0b4, 0x0040, 0x1b58, 0xc0b4, 0x60d6, 0x0c7e, 0x60b8, + 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, + 0x60d4, 0xa084, 0x77ff, 0x60d6, 0x78ac, 0xc08d, 0x78ae, 0x83ff, + 0x0040, 0x1b63, 0x007c, 0x681b, 0x0047, 0x2091, 0x8001, 0x007c, + 0x73cc, 0x1078, 0x1aba, 0x69ec, 0x6a48, 0xa185, 0x1800, 0x684a, + 0xa185, 0x0040, 0x68ee, 0x73cc, 0x2021, 0x0004, 0x20a9, 0x09ff, + 0x00f0, 0x1b78, 0x8421, 0x00c0, 0x1b76, 0x8319, 0x00c0, 0x1b74, + 0x69ee, 0x6a4a, 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x1b8c, + 0x2069, 0x4f40, 0x0078, 0x1b8e, 0x2069, 0x4f80, 0x71c4, 0x71c6, + 0x6916, 0x81ff, 0x00c0, 0x1b96, 0x68a7, 0x0001, 0x78ac, 0xc08c, + 0x78ae, 0xd084, 0x00c0, 0x1b9e, 0x1078, 0x1f26, 0x007c, 0x75d8, + 0x74dc, 0x75da, 0x74de, 0x0078, 0x1ba7, 0xa02e, 0x2520, 0x71c4, + 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4f00, 0x7dde, + 0x7cda, 0x7bd6, 0x7ad2, 0x1078, 0x1dfd, 0x0040, 0x1cca, 0x20a9, + 0x0005, 0x20a1, 0x4f14, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, + 0x2009, 0x0040, 0x1078, 0x2011, 0x0040, 0x1bca, 0x1078, 0x1e06, + 0x0078, 0x1cca, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, 0x00c0, + 0x1bd5, 0x007e, 0x1078, 0x23b8, 0x007f, 0xa084, 0xff00, 0x8007, + 0x8009, 0x0040, 0x1c61, 0x0c7e, 0x2c68, 0x1078, 0x1dfd, 0x0040, + 0x1c1b, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x1bdc, 0x609f, 0x0000, + 0x0c7f, 0x0c7e, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda, + 0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1c60, 0x2009, + 0x0040, 0x1078, 0x2011, 0x00c0, 0x1c3e, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x0002, 0x00c0, 0x1c1b, 0x6004, 0xa084, 0x00ff, 0xa086, + 0x000a, 0x00c0, 0x1c17, 0x017e, 0x1078, 0x23b4, 0x017f, 0x2d00, + 0x6002, 0x0078, 0x1bea, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e89, + 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1cce, 0x2009, 0x0018, 0x6008, + 0xc0cd, 0x600a, 0x6004, 0x6086, 0x7810, 0x007e, 0x84ff, 0x00c0, + 0x1c34, 0x85ff, 0x0040, 0x1c36, 0xc0c5, 0x7812, 0x1078, 0x1db4, + 0x007f, 0x7812, 0x1078, 0x1e06, 0x0078, 0x1cca, 0x0c7f, 0x0c7e, + 0x609c, 0x1078, 0x1e89, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1cce, + 0x2009, 0x0018, 0x6087, 0x0103, 0x601b, 0x0003, 0x7810, 0x007e, + 0x84ff, 0x00c0, 0x1c56, 0x85ff, 0x0040, 0x1c58, 0xc0c5, 0x7812, + 0x1078, 0x1db4, 0x007f, 0x7812, 0x1078, 0x1e06, 0x0078, 0x1cca, + 0x0c7f, 0x7814, 0xd0e4, 0x00c0, 0x1c8f, 0x6114, 0xd1fc, 0x0040, + 0x1c6f, 0x1078, 0x1da7, 0x0040, 0x1c8f, 0x0078, 0x1c73, 0x1078, + 0x1d9a, 0x0040, 0x1c8f, 0x1078, 0x1cce, 0x2009, 0x0018, 0x6087, + 0x0103, 0x601b, 0x0021, 0x7810, 0x007e, 0x84ff, 0x00c0, 0x1c83, + 0x85ff, 0x0040, 0x1c85, 0xc0c5, 0x7812, 0x1078, 0x1db4, 0x007f, + 0x7812, 0x1078, 0x1e06, 0x2001, 0x4007, 0x0078, 0x15c3, 0x74c4, + 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x0e7e, 0x2009, 0x0012, + 0xd0fc, 0x00c0, 0x1c9f, 0x2071, 0x4f40, 0x0078, 0x1ca2, 0x2071, + 0x4f80, 0xc1fd, 0x792a, 0x7067, 0x0005, 0x71d4, 0xc1dc, 0x71d6, + 0x736a, 0x726e, 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, 0x707e, + 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x1cb9, 0x1078, + 0x46a7, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, + 0x60b3, 0x0000, 0x6714, 0x6023, 0x0000, 0x1078, 0x2668, 0x2091, + 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x15c4, 0x20a9, 0x0005, + 0x2099, 0x4f14, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, + 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, + 0x71c4, 0x70c7, 0x0000, 0x791e, 0x0078, 0x15c1, 0x71c4, 0x71c6, + 0x2168, 0x0078, 0x1ced, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, + 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1cef, 0xa285, 0x0000, 0x00c0, + 0x1cfd, 0x70c3, 0x4000, 0x0078, 0x1cff, 0x70c3, 0x4003, 0x70ca, + 0x0078, 0x15c4, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x00c8, + 0x15b9, 0x7966, 0x0078, 0x15c1, 0x7964, 0x71c6, 0x0078, 0x15c1, + 0x7900, 0x71c6, 0x71c4, 0x7902, 0x0078, 0x15c1, 0x7900, 0x71c6, + 0x0078, 0x15c1, 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0040, + 0x1d2f, 0x810c, 0x0048, 0x1d2b, 0x8210, 0x810c, 0x810c, 0x0048, + 0x1d2b, 0x8210, 0x810c, 0x81ff, 0x00c0, 0x15ba, 0x8210, 0x7a0e, + 0xd28c, 0x0040, 0x1d5b, 0x7910, 0xc1cd, 0x7912, 0x2009, 0x0021, + 0x2019, 0x0003, 0xd284, 0x0040, 0x1d55, 0x8108, 0x2019, 0x0041, + 0x2011, 0x974e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, 0x2019, + 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, 0x2019, + 0x0047, 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x9753, 0x2112, + 0x2011, 0x9773, 0x2312, 0x7904, 0x7806, 0x0078, 0x15c0, 0x7804, + 0x70c6, 0x0078, 0x15c1, 0x71c4, 0xd1fc, 0x00c0, 0x1d6b, 0x2011, + 0x53c0, 0x0078, 0x1d6d, 0x2011, 0x5440, 0x8107, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0xa268, 0x6a14, 0xd2b4, 0x0040, 0x1d7c, + 0x2011, 0x0001, 0x0078, 0x1d7e, 0x2011, 0x0000, 0x6b0c, 0x6800, + 0x70da, 0x0078, 0x15be, 0x7814, 0xd0f4, 0x0040, 0x1d8e, 0x2001, + 0x4007, 0x70db, 0x0000, 0xa005, 0x0078, 0x1d99, 0xd0fc, 0x0040, + 0x1d98, 0x2001, 0x4007, 0x70db, 0x0001, 0xa005, 0x0078, 0x1d99, + 0xa006, 0x007c, 0x7814, 0xd0f4, 0x0040, 0x1da5, 0x2001, 0x4007, + 0x70db, 0x0000, 0xa005, 0x0078, 0x1da6, 0xa006, 0x007c, 0x7814, + 0xd0fc, 0x0040, 0x1db2, 0x2001, 0x4007, 0x70db, 0x0001, 0xa005, + 0x0078, 0x1db3, 0xa006, 0x007c, 0x7112, 0x721a, 0x731e, 0x7810, + 0xd0c4, 0x0040, 0x1dbd, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, + 0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, + 0x20a2, 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0040, + 0x1dda, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, + 0x0078, 0x1ddd, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, + 0xa006, 0xa211, 0x7d10, 0xd5c4, 0x0040, 0x1dea, 0x7b84, 0xa319, + 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0040, 0x1dea, 0x7003, 0x0001, + 0x7007, 0x0006, 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0040, 0x1dfa, + 0x7322, 0x7426, 0xa084, 0x01e0, 0x007c, 0x7848, 0xa065, 0x0040, + 0x1e05, 0x2c04, 0x784a, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, + 0x4f00, 0x7848, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1e11, 0x1078, + 0x29ab, 0x784a, 0x0f7f, 0x007c, 0x2011, 0x9900, 0x7a4a, 0x7bc4, + 0x8319, 0x0040, 0x1e21, 0xa280, 0x0032, 0x2012, 0x2010, 0x0078, + 0x1e18, 0x2013, 0x0000, 0x007c, 0x017e, 0x027e, 0xd7fc, 0x00c0, + 0x1e2d, 0x2011, 0x54c0, 0x0078, 0x1e2f, 0x2011, 0x74c0, 0xa784, + 0x0f00, 0x800b, 0xa784, 0x001f, 0x0040, 0x1e3a, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0xa268, 0x027f, 0x017f, 0x007c, 0x1078, + 0x1e24, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, + 0xa80d, 0x690a, 0x0e7e, 0xd7fc, 0x00c0, 0x1e54, 0x2009, 0x4f53, + 0x2071, 0x4f40, 0x0078, 0x1e58, 0x2009, 0x4f93, 0x2071, 0x4f80, + 0x210c, 0x6804, 0xa005, 0x0040, 0x1e68, 0xa116, 0x00c0, 0x1e68, + 0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x1e6b, + 0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1e80, 0x6000, + 0x6806, 0x1078, 0x1e9b, 0x1078, 0x205d, 0x6810, 0x7908, 0x8109, + 0x790a, 0x8001, 0x6812, 0x00c0, 0x1e6b, 0x7910, 0xc1a5, 0x7912, + 0x017f, 0x6902, 0x6906, 0x2d00, 0x2060, 0x1078, 0x2b0c, 0x0e7f, + 0x007c, 0xa065, 0x0040, 0x1e9a, 0x2008, 0x609c, 0xa005, 0x0040, + 0x1e97, 0x2062, 0x609f, 0x0000, 0xa065, 0x0078, 0x1e8d, 0x7848, + 0x794a, 0x2062, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, + 0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, + 0x601a, 0x682c, 0x6022, 0x007c, 0x0e7e, 0xd7fc, 0x00c0, 0x1eb6, + 0x2071, 0x4f40, 0x2031, 0x4fc0, 0x0078, 0x1eba, 0x2071, 0x4f80, + 0x2031, 0x51c0, 0x7050, 0xa08c, 0x0200, 0x00c0, 0x1ec4, 0xa608, + 0x2d0a, 0x8000, 0x7052, 0xa006, 0x0e7f, 0x007c, 0x0f7e, 0xd7fc, + 0x00c0, 0x1ece, 0x2079, 0x4f40, 0x0078, 0x1ed0, 0x2079, 0x4f80, + 0x1078, 0x1e24, 0x2091, 0x8000, 0x6804, 0x780a, 0xa065, 0x0040, + 0x1f24, 0x0078, 0x1ee2, 0x2c00, 0x780a, 0x2060, 0x6000, 0xa065, + 0x0040, 0x1f24, 0x6010, 0xa306, 0x00c0, 0x1edb, 0x600c, 0xa206, + 0x00c0, 0x1edb, 0x2c28, 0x784c, 0xac06, 0x00c0, 0x1ef1, 0x0078, + 0x1f21, 0x6804, 0xac06, 0x00c0, 0x1eff, 0x6000, 0x2060, 0x6806, + 0xa005, 0x00c0, 0x1eff, 0x6803, 0x0000, 0x0078, 0x1f09, 0x6400, + 0x7808, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1f09, 0x2c00, + 0x6802, 0x2560, 0x0f7f, 0x1078, 0x1e9b, 0x0f7e, 0x601b, 0x0005, + 0x6023, 0x0020, 0x0f7f, 0x1078, 0x205d, 0x0f7e, 0x7908, 0x8109, + 0x790a, 0x6810, 0x8001, 0x6812, 0x00c0, 0x1f21, 0x7810, 0xc0a5, + 0x7812, 0x2001, 0xffff, 0xa005, 0x0f7f, 0x007c, 0x077e, 0x2700, + 0x2039, 0x0000, 0xd0fc, 0x0040, 0x1f2e, 0xc7fd, 0x2041, 0x0021, + 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x1e3f, + 0x8738, 0xa784, 0x001f, 0x00c0, 0x1f36, 0xa7bc, 0xff00, 0x873f, + 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1f36, 0x2091, 0x8001, + 0x077f, 0x007c, 0x786c, 0x2009, 0x9774, 0x210c, 0xa10d, 0x0040, + 0x1f54, 0xa065, 0x0078, 0x23d5, 0x2061, 0x0000, 0x6018, 0xd084, + 0x00c0, 0x1f74, 0x7810, 0xd08c, 0x0040, 0x1f65, 0xc08c, 0x7812, + 0xc7fc, 0x2069, 0x4f40, 0x0078, 0x1f6a, 0xc08d, 0x7812, 0x2069, + 0x4f80, 0xc7fd, 0x2091, 0x8000, 0x681c, 0x681f, 0x0000, 0x2091, + 0x8001, 0xa005, 0x00c0, 0x1f75, 0x007c, 0xa08c, 0xfff0, 0x0040, + 0x1f7b, 0x1078, 0x29ab, 0x0079, 0x1f7d, 0x1f8d, 0x1f90, 0x1f96, + 0x1f9a, 0x1f8e, 0x1f9e, 0x1f8e, 0x1f8e, 0x1f8e, 0x1fa4, 0x1fd5, + 0x1fd9, 0x1fdf, 0x1ff4, 0x1f8e, 0x1f8e, 0x007c, 0x1078, 0x29ab, + 0x1078, 0x1f26, 0x2001, 0x8001, 0x0078, 0x2000, 0x2001, 0x8003, + 0x0078, 0x2000, 0x2001, 0x8004, 0x0078, 0x2000, 0x1078, 0x1f26, + 0x2001, 0x8006, 0x0078, 0x2000, 0x2091, 0x8000, 0x077e, 0xd7fc, + 0x00c0, 0x1fb0, 0x2069, 0x4f40, 0x2039, 0x0009, 0x0078, 0x1fb4, + 0x2069, 0x4f80, 0x2039, 0x0009, 0x6800, 0xa086, 0x0000, 0x0040, + 0x1fbe, 0x007f, 0x6f1e, 0x2091, 0x8001, 0x007c, 0x6874, 0x077f, + 0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, + 0x1078, 0x1e3f, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1fc8, 0x2091, + 0x8001, 0x2001, 0x800a, 0x0078, 0x2000, 0x2001, 0x800c, 0x0078, + 0x2000, 0x1078, 0x1f26, 0x2001, 0x800d, 0x0078, 0x2000, 0x7814, + 0xd0e4, 0x00c0, 0x1ff2, 0xd0ec, 0x0040, 0x1fec, 0xd7fc, 0x0040, + 0x1fec, 0x78e4, 0x0078, 0x1fed, 0x78e0, 0x70c6, 0x2001, 0x800e, + 0x0078, 0x2000, 0x0078, 0x1f8e, 0xd7fc, 0x0040, 0x1ffa, 0x78ec, + 0x0078, 0x1ffb, 0x78e8, 0x70c6, 0x2001, 0x800f, 0x0078, 0x2000, + 0x70c2, 0xd7fc, 0x00c0, 0x2008, 0x70db, 0x0000, 0x0078, 0x200a, + 0x70db, 0x0001, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, + 0x007c, 0xac80, 0x0001, 0x81ff, 0x0040, 0x203c, 0x2099, 0x0030, + 0x20a0, 0x700c, 0xa084, 0x03ff, 0x0040, 0x201e, 0x7018, 0x007e, + 0x701c, 0x007e, 0x7020, 0x007e, 0x7024, 0x007e, 0x7112, 0x81ac, + 0x721a, 0x731e, 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, + 0x7008, 0x800b, 0x00c8, 0x2030, 0x7007, 0x0002, 0xa08c, 0x01e0, + 0x00c0, 0x203c, 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, + 0x007f, 0x7026, 0x007f, 0x7022, 0x007f, 0x701e, 0x007f, 0x701a, + 0x007c, 0x2011, 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x6803, + 0xfd00, 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, + 0x0004, 0x8109, 0x00c0, 0x204d, 0x007c, 0x6004, 0x6086, 0x2c08, + 0x2063, 0x0000, 0x7868, 0xa005, 0x796a, 0x0040, 0x206a, 0x2c02, + 0x0078, 0x206b, 0x796e, 0x007c, 0x0c7e, 0x2061, 0x4f00, 0x6887, + 0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, + 0x207c, 0x2d02, 0x0078, 0x207d, 0x616e, 0x0c7f, 0x007c, 0x2091, + 0x8000, 0x2c04, 0x786e, 0xa005, 0x00c0, 0x2087, 0x786a, 0x2091, + 0x8001, 0x609c, 0xa005, 0x0040, 0x20a0, 0x0c7e, 0x2060, 0x2008, + 0x609c, 0xa005, 0x0040, 0x209c, 0x2062, 0x609f, 0x0000, 0xa065, + 0x609c, 0xa005, 0x00c0, 0x2094, 0x7848, 0x794a, 0x2062, 0x0c7f, + 0x7848, 0x2062, 0x609f, 0x0000, 0xac85, 0x0000, 0x00c0, 0x20aa, + 0x1078, 0x29ab, 0x784a, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, + 0x8086, 0x818e, 0x00c8, 0x20b5, 0xa200, 0x00f0, 0x20b0, 0x8086, + 0x818e, 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x20db, + 0xa11a, 0x00c8, 0x20db, 0x8213, 0x818d, 0x0048, 0x20ce, 0xa11a, + 0x00c8, 0x20cf, 0x00f0, 0x20c3, 0x0078, 0x20d3, 0xa11a, 0x2308, + 0x8210, 0x00f0, 0x20c3, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, + 0x007f, 0x157f, 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, + 0x20d7, 0x7d74, 0x70d0, 0xa506, 0x0040, 0x21c7, 0x7810, 0x2050, + 0x7800, 0xd08c, 0x0040, 0x2103, 0xdaec, 0x0040, 0x2103, 0x0e7e, + 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2100, + 0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040, 0x2103, 0x0078, 0x21c7, + 0x0e7f, 0x0078, 0x21c7, 0x1078, 0x1dfd, 0x0040, 0x21c7, 0xa046, + 0x7970, 0x2500, 0x8000, 0xa112, 0x2009, 0x0040, 0x00c8, 0x2112, + 0x0078, 0x2119, 0x72d0, 0xa206, 0x0040, 0x2119, 0x8840, 0x2009, + 0x0080, 0x0c7e, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, + 0x0020, 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0040, + 0x212b, 0x1078, 0x1dfd, 0x7008, 0xd0fc, 0x0040, 0x212b, 0x7007, + 0x0002, 0x2091, 0x8001, 0xa08c, 0x01e0, 0x00c0, 0x2162, 0x53a5, + 0x8cff, 0x00c0, 0x2140, 0x88ff, 0x0040, 0x21b1, 0x0078, 0x214a, + 0x2c00, 0x788e, 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5, + 0x0078, 0x21b1, 0xa046, 0x7218, 0x731c, 0xdac4, 0x0040, 0x2152, + 0x7420, 0x7524, 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, 0x0000, + 0xa5ab, 0x0000, 0x721a, 0x731e, 0xdac4, 0x0040, 0x2162, 0x7422, + 0x7526, 0xa006, 0x7007, 0x0004, 0x0040, 0x21b1, 0x8cff, 0x0040, + 0x216b, 0x1078, 0x1e06, 0x0c7f, 0x1078, 0x1e06, 0xa046, 0x7888, + 0x8000, 0x788a, 0xa086, 0x0002, 0x0040, 0x2191, 0x7a7c, 0x7b78, + 0xdac4, 0x0040, 0x217d, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, + 0x8004, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, + 0x721a, 0x731e, 0xdac4, 0x0040, 0x21c7, 0x7422, 0x7526, 0x0078, + 0x21c7, 0x6014, 0xd0fc, 0x00c0, 0x2199, 0x2069, 0x4f40, 0x0078, + 0x219b, 0x2069, 0x4f80, 0x2091, 0x8000, 0x681f, 0x0002, 0x88ff, + 0x0040, 0x21a7, 0xa046, 0x788c, 0x2060, 0x0078, 0x2191, 0x788b, + 0x0000, 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0078, + 0x21c7, 0x0c7f, 0x788b, 0x0000, 0x1078, 0x2386, 0x6004, 0xa084, + 0x000f, 0x1078, 0x21c8, 0x88ff, 0x0040, 0x21c5, 0x788c, 0x2060, + 0x6004, 0xa084, 0x000f, 0x1078, 0x21c8, 0x0078, 0x20e1, 0x007c, + 0x0079, 0x21ca, 0x21da, 0x21f8, 0x2216, 0x21da, 0x2227, 0x21eb, + 0x21da, 0x21da, 0x21da, 0x21f6, 0x2214, 0x21da, 0x21da, 0x21da, + 0x21da, 0x21da, 0x2039, 0x0400, 0x78bc, 0xa705, 0x78be, 0x6008, + 0xa705, 0x600a, 0x1078, 0x226a, 0x609c, 0x78ba, 0x609f, 0x0000, + 0x1078, 0x2370, 0x007c, 0x78bc, 0xd0c4, 0x0040, 0x21f1, 0x0078, + 0x21da, 0x601c, 0xc0bd, 0x601e, 0x0078, 0x21fe, 0x1078, 0x23b8, + 0x78bc, 0xd0c4, 0x0040, 0x21fe, 0x0078, 0x21da, 0x78bf, 0x0000, + 0x6004, 0x8007, 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0040, 0x2211, + 0x1078, 0x226a, 0x0040, 0x2211, 0x78bc, 0xc0c5, 0x78be, 0x0078, + 0x2213, 0x0078, 0x2289, 0x007c, 0x1078, 0x23b4, 0x78bc, 0xa08c, + 0x0e00, 0x00c0, 0x221e, 0xd0c4, 0x00c0, 0x2220, 0x0078, 0x21da, + 0x1078, 0x226a, 0x00c0, 0x2226, 0x0078, 0x2289, 0x007c, 0x78bc, + 0xd0c4, 0x0040, 0x222d, 0x0078, 0x21da, 0x78bf, 0x0000, 0x6714, + 0x2011, 0x0001, 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, + 0x224d, 0xa7bc, 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040, + 0x224d, 0xa7bc, 0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, + 0x0002, 0x0040, 0x224d, 0x0078, 0x2267, 0x1078, 0x1e24, 0x2d00, + 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, + 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, 0x00f0, 0x2250, + 0x8211, 0x0040, 0x2267, 0x20a9, 0x0100, 0x0078, 0x2250, 0x1078, + 0x1e06, 0x007c, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, + 0x00c0, 0x2275, 0x78ba, 0x0078, 0x227d, 0x689e, 0x2d00, 0x6002, + 0x78b8, 0xad06, 0x00c0, 0x227d, 0x6002, 0x78b0, 0x8001, 0x78b2, + 0x00c0, 0x2288, 0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, + 0x007c, 0x0e7e, 0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, + 0x601c, 0x60a2, 0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, + 0x0040, 0x229c, 0x1078, 0x46a7, 0x6596, 0x65a6, 0x669a, 0x66aa, + 0x6714, 0x2071, 0x4f80, 0xd7fc, 0x00c0, 0x22a8, 0x2071, 0x4f40, + 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x0040, 0x22b3, 0x8003, + 0x8003, 0x8003, 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, 0x8007, + 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, 0x60c2, + 0x2091, 0x8000, 0x7814, 0xd0c4, 0x0040, 0x22d8, 0xd0ec, 0x0040, + 0x22d4, 0xd7fc, 0x00c0, 0x22d1, 0xd0f4, 0x00c0, 0x22df, 0x0078, + 0x22d8, 0xd0fc, 0x00c0, 0x22df, 0x7810, 0xd0f4, 0x00c0, 0x22df, + 0x6e08, 0xd684, 0x0040, 0x2309, 0xd9fc, 0x00c0, 0x2309, 0x2091, + 0x8001, 0x1078, 0x1e9b, 0x2091, 0x8000, 0x1078, 0x205d, 0x2091, + 0x8001, 0x7814, 0xd0e4, 0x00c0, 0x236e, 0x7814, 0xd0c4, 0x0040, + 0x236e, 0xd0ec, 0x0040, 0x2301, 0xd7fc, 0x00c0, 0x22fc, 0xd0f4, + 0x00c0, 0x2305, 0x0078, 0x236e, 0xd0fc, 0x00c0, 0x2305, 0x0078, + 0x236e, 0x7810, 0xd0f4, 0x0040, 0x236e, 0x601b, 0x0021, 0x0078, + 0x236e, 0x6024, 0xa096, 0x0001, 0x00c0, 0x2310, 0x8000, 0x6026, + 0x6a10, 0x6814, 0xa202, 0x0048, 0x2323, 0x0040, 0x2323, 0x2091, + 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, + 0x2370, 0x0078, 0x236e, 0x2c08, 0xd9fc, 0x0040, 0x234b, 0x6800, + 0xa065, 0x0040, 0x234b, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0040, + 0x2341, 0x704c, 0xa206, 0x00c0, 0x2341, 0x6b04, 0x2160, 0x2304, + 0x6002, 0xa005, 0x00c0, 0x233d, 0x6902, 0x2260, 0x6102, 0x0078, + 0x2357, 0x2d00, 0x2060, 0x1078, 0x2b0c, 0x6e08, 0x2160, 0x6202, + 0x6906, 0x0078, 0x2357, 0x6800, 0x6902, 0xa065, 0x0040, 0x2353, + 0x6102, 0x0078, 0x2354, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160, + 0xd9fc, 0x0040, 0x235e, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, 0x7d08, + 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, 0x0040, + 0x236e, 0xa6b6, 0x0040, 0x6e0a, 0x1078, 0x1eac, 0x0e7f, 0x007c, + 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x1078, 0x205d, 0x2091, + 0x8001, 0x78b8, 0xa065, 0x0040, 0x2383, 0x609c, 0x78ba, 0x609f, + 0x0000, 0x0078, 0x2370, 0x78b6, 0x78ba, 0x007c, 0x7970, 0x7874, + 0x2818, 0xd384, 0x0040, 0x2390, 0x8000, 0xa112, 0x0048, 0x2395, + 0x8000, 0xa112, 0x00c8, 0x23a5, 0xc384, 0x7a7c, 0x721a, 0x7a78, + 0x721e, 0xdac4, 0x0040, 0x23a0, 0x7a84, 0x7222, 0x7a80, 0x7226, + 0xa006, 0xd384, 0x0040, 0x23a5, 0x8000, 0x7876, 0x70d2, 0x781c, + 0xa005, 0x0040, 0x23b3, 0x8001, 0x781e, 0x00c0, 0x23b3, 0x0068, + 0x23b3, 0x2091, 0x4080, 0x007c, 0x2039, 0x23cc, 0x0078, 0x23ba, + 0x2039, 0x23d2, 0x2704, 0xa005, 0x0040, 0x23cb, 0xac00, 0x2068, + 0x6908, 0x6810, 0x6912, 0x680a, 0x690c, 0x6814, 0x6916, 0x680e, + 0x8738, 0x0078, 0x23ba, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015, + 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x2041, 0x0000, 0x780c, + 0x0079, 0x23da, 0x25ac, 0x257f, 0x23de, 0x2457, 0x2039, 0x9774, + 0x2734, 0x7d10, 0x0078, 0x23fe, 0x6084, 0xa086, 0x0103, 0x00c0, + 0x2440, 0x6114, 0x6018, 0xa105, 0x0040, 0x23f3, 0x86ff, 0x00c0, + 0x240f, 0x0078, 0x2440, 0x8603, 0xa080, 0x9755, 0x620c, 0x2202, + 0x8000, 0x6210, 0x2202, 0x1078, 0x207f, 0x8630, 0xa68e, 0x000f, + 0x0040, 0x24cb, 0x786c, 0xa065, 0x00c0, 0x23e4, 0x7808, 0xa602, + 0x00c8, 0x240f, 0xd5ac, 0x00c0, 0x240f, 0x263a, 0x007c, 0xa682, + 0x0003, 0x00c8, 0x24cb, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, + 0xd084, 0x00c0, 0x243b, 0x2011, 0x9755, 0x2204, 0x70c6, 0x8210, + 0x2204, 0x70ca, 0xd684, 0x00c0, 0x242b, 0x8210, 0x2204, 0x70da, + 0x8210, 0x2204, 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001, + 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, + 0x203b, 0x0000, 0x007c, 0x7810, 0xc0ad, 0x7812, 0x0078, 0x24cb, + 0x263a, 0x1078, 0x25b6, 0x00c0, 0x25d9, 0x786c, 0xa065, 0x00c0, + 0x23e4, 0x2091, 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, + 0x2452, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0078, 0x25d9, 0x2039, + 0x9774, 0x2734, 0x7d10, 0x0078, 0x2473, 0x6084, 0xa086, 0x0103, + 0x00c0, 0x24b4, 0x6114, 0x6018, 0xa105, 0x0040, 0x246c, 0x86ff, + 0x00c0, 0x2484, 0x0078, 0x24b4, 0xa680, 0x9755, 0x620c, 0x2202, + 0x1078, 0x207f, 0x8630, 0xa68e, 0x001e, 0x0040, 0x24cb, 0x786c, + 0xa065, 0x00c0, 0x245d, 0x7808, 0xa602, 0x00c8, 0x2484, 0xd5ac, + 0x00c0, 0x2484, 0x263a, 0x007c, 0xa682, 0x0006, 0x00c8, 0x24cb, + 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x24af, + 0x2011, 0x9755, 0x2009, 0x974e, 0x26a8, 0x211c, 0x2204, 0x201a, + 0x8108, 0x8210, 0x00f0, 0x2495, 0xa685, 0x8030, 0x70c2, 0x681b, + 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, + 0x8001, 0xa006, 0x2009, 0x9775, 0x200a, 0x203a, 0x007c, 0x7810, + 0xc0ad, 0x7812, 0x0078, 0x24cb, 0x263a, 0x1078, 0x25b6, 0x00c0, + 0x25d9, 0x786c, 0xa065, 0x00c0, 0x245d, 0x2091, 0x8000, 0x7810, + 0xa084, 0xffcf, 0x86ff, 0x0040, 0x24c6, 0xc0ad, 0x7812, 0x2091, + 0x8001, 0x0078, 0x25d9, 0x2091, 0x8000, 0x7007, 0x0004, 0x7994, + 0x70d4, 0xa102, 0x0048, 0x24dc, 0x0040, 0x24e6, 0x7b90, 0xa302, + 0x00c0, 0x24e6, 0x0078, 0x24df, 0x8002, 0x00c0, 0x24e6, 0x263a, + 0x7810, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x007c, 0xa184, 0xff00, + 0x0040, 0x24f3, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, + 0xa100, 0x0078, 0x24f6, 0x8107, 0x8004, 0x8004, 0x7a9c, 0xa210, + 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0040, 0x2506, + 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, 0x0030, + 0x7003, 0x0000, 0x2009, 0x9754, 0x260a, 0x8109, 0x2198, 0x2104, + 0xd084, 0x0040, 0x2514, 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, + 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a, + 0x00c8, 0x2523, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, 0x0040, + 0x2532, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, + 0x0078, 0x2535, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, + 0xa006, 0xa211, 0xd4c4, 0x0040, 0x2541, 0x7b84, 0xa319, 0x7c80, + 0xa421, 0x7008, 0xd0fc, 0x0040, 0x2541, 0xa084, 0x01e0, 0x0040, + 0x2566, 0x7d10, 0x2031, 0x9754, 0x2634, 0x78a8, 0x8000, 0x78aa, + 0xd08c, 0x00c0, 0x255b, 0x7007, 0x0006, 0x7004, 0xd094, 0x00c0, + 0x2555, 0x0078, 0x24cd, 0x2069, 0x4f47, 0x206b, 0x0003, 0x78ac, + 0xa085, 0x0300, 0x78ae, 0xa006, 0x0078, 0x256f, 0x2030, 0x75d6, + 0x2091, 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091, + 0x8001, 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, 0x711a, + 0x721e, 0xd5c4, 0x0040, 0x257e, 0x7322, 0x7426, 0x007c, 0x6084, + 0xa086, 0x0103, 0x00c0, 0x25a2, 0x6114, 0x6018, 0xa105, 0x00c0, + 0x25a2, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x25a2, 0x600c, + 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, 0x2091, + 0x4080, 0x1078, 0x207f, 0x0068, 0x25a1, 0x786c, 0xa065, 0x00c0, + 0x257f, 0x007c, 0x1078, 0x25b6, 0x00c0, 0x25d9, 0x786c, 0xa065, + 0x00c0, 0x257f, 0x0078, 0x25d9, 0x1078, 0x25b6, 0x00c0, 0x25d9, + 0x786c, 0xa065, 0x00c0, 0x25ac, 0x0078, 0x25d9, 0x6084, 0xa086, + 0x0103, 0x00c0, 0x25ca, 0x6018, 0xc0fc, 0x601a, 0xa086, 0x0004, + 0x00c0, 0x25ca, 0x7804, 0xd0a4, 0x0040, 0x25ca, 0x1078, 0x207f, + 0xa006, 0x007c, 0x1078, 0x25df, 0x00c0, 0x25d1, 0xa085, 0x0001, + 0x007c, 0x1078, 0x25ee, 0x00c0, 0x25d7, 0x2041, 0x0001, 0x7d10, + 0x007c, 0x88ff, 0x0040, 0x25de, 0x2091, 0x4080, 0x007c, 0x7b90, + 0x7994, 0x70d4, 0xa102, 0x00c0, 0x25e8, 0xa385, 0x0000, 0x007c, + 0x0048, 0x25ec, 0xa302, 0x007c, 0x8002, 0x007c, 0x7810, 0xd0ec, + 0x0040, 0x2606, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, + 0xa005, 0x00c0, 0x2603, 0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040, + 0x2606, 0x0078, 0x2657, 0x0e7f, 0x0078, 0x2657, 0xa184, 0xff00, + 0x0040, 0x2613, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, + 0xa100, 0x0078, 0x2616, 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, + 0x7ca4, 0x7da0, 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, + 0x0018, 0x6028, 0xa005, 0x0040, 0x2627, 0x2009, 0x0040, 0x1078, + 0x1db4, 0x0040, 0x2649, 0x78a8, 0x8000, 0x78aa, 0xd08c, 0x00c0, + 0x2657, 0x6014, 0xd0fc, 0x00c0, 0x2639, 0x2069, 0x4f40, 0x0078, + 0x263b, 0x2069, 0x4f80, 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab, + 0x0000, 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, 0x0078, + 0x2657, 0x78ab, 0x0000, 0x1078, 0x207f, 0x7990, 0x7894, 0x8000, + 0xa10a, 0x00c8, 0x2654, 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, + 0x0010, 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x2663, 0x2009, + 0x4f59, 0x0078, 0x2665, 0x2009, 0x4f99, 0x2091, 0x8000, 0x200a, + 0x0f7e, 0xd7fc, 0x00c0, 0x267c, 0x2009, 0x4f40, 0x2001, 0x4f04, + 0x2004, 0xd0ec, 0x0040, 0x2678, 0x2079, 0x0100, 0x0078, 0x2680, + 0x2079, 0x0200, 0x0078, 0x2680, 0x2009, 0x4f80, 0x2079, 0x0100, + 0x2104, 0xa086, 0x0000, 0x00c0, 0x2699, 0xd7fc, 0x00c0, 0x268c, + 0x2009, 0x4f45, 0x0078, 0x268e, 0x2009, 0x4f85, 0x2104, 0xa005, + 0x00c0, 0x2699, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2699, 0x781b, + 0x0045, 0x0f7f, 0x007c, 0x2009, 0x0002, 0x2069, 0x4f00, 0x6810, + 0xd0ec, 0x00c0, 0x2708, 0x2071, 0x4f80, 0x2079, 0x0100, 0x2021, + 0x51bf, 0x784b, 0x000f, 0x2019, 0x449e, 0xd184, 0x0040, 0x26bc, + 0x6810, 0xd0ec, 0x0040, 0x26b8, 0x20a1, 0x012b, 0x0078, 0x26be, + 0x20a1, 0x022b, 0x0078, 0x26be, 0x20a1, 0x012b, 0x2304, 0xa005, + 0x0040, 0x26cb, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, + 0x3318, 0x0078, 0x26be, 0x789b, 0x0020, 0x20a9, 0x0010, 0x6814, + 0xd0e4, 0x0040, 0x26db, 0x78af, 0x0000, 0x78af, 0x9020, 0x00f0, + 0x26d3, 0x0078, 0x26e1, 0x78af, 0x0000, 0x78af, 0x8020, 0x00f0, + 0x26db, 0x7003, 0x0000, 0x017e, 0xd18c, 0x2009, 0x0000, 0x0040, + 0x26ea, 0xc1bd, 0x1078, 0x28db, 0x017f, 0x7020, 0xa084, 0x000f, + 0x007e, 0x6814, 0xd0e4, 0x007f, 0x00c0, 0x26fa, 0xa085, 0x6340, + 0x0078, 0x26fc, 0xa085, 0x62c0, 0x7806, 0x780f, 0x9200, 0x7843, + 0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7456, 0x7053, 0x0000, + 0x8109, 0x0040, 0x271b, 0x2071, 0x4f40, 0x6810, 0xd0ec, 0x0040, + 0x2715, 0x2079, 0x0100, 0x0078, 0x2717, 0x2079, 0x0200, 0x2021, + 0x4fbf, 0x0078, 0x26a9, 0x007c, 0x017e, 0xd1bc, 0x00c0, 0x2730, + 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x272c, + 0x2011, 0x0101, 0x0078, 0x2732, 0x2011, 0x0201, 0x0078, 0x2732, + 0x2011, 0x0101, 0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105, + 0x2012, 0x017f, 0x1078, 0x28db, 0x007c, 0xd3fc, 0x00c0, 0x2750, + 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x274c, + 0x2011, 0x0101, 0x0078, 0x2752, 0x2011, 0x0201, 0x0078, 0x2752, + 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x00f0, 0x2754, 0xa18c, + 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2019, + 0x0002, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x0040, 0x276c, 0x8319, + 0x2009, 0x0101, 0x0078, 0x276e, 0x2009, 0x0101, 0x20a9, 0x0005, + 0x8213, 0x00f0, 0x2770, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, + 0xa205, 0x200a, 0x8319, 0x0040, 0x2781, 0x2009, 0x0201, 0x0078, + 0x276e, 0x007c, 0xd3fc, 0x00c0, 0x2795, 0x007e, 0x2001, 0x4f04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2791, 0x2011, 0x0101, 0x0078, + 0x2797, 0x2011, 0x0201, 0x0078, 0x2797, 0x2011, 0x0101, 0x20a9, + 0x000c, 0x810b, 0x00f0, 0x2799, 0xa18c, 0xf000, 0x2204, 0xa084, + 0x0fff, 0xa105, 0x2012, 0x007c, 0xd3fc, 0x00c0, 0x27b7, 0x007e, + 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x27b3, 0x2011, + 0x0102, 0x0078, 0x27b9, 0x2011, 0x0202, 0x0078, 0x27b9, 0x2011, + 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c, 0x0c7e, + 0xd1bc, 0x00c0, 0x27d3, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x27cf, 0x2061, 0x0100, 0x0078, 0x27d5, 0x2061, + 0x0200, 0x0078, 0x27d5, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, + 0xa080, 0x0020, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x0c7e, + 0xd1bc, 0x00c0, 0x27f3, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x27ef, 0x2061, 0x0100, 0x0078, 0x27f5, 0x2061, + 0x0200, 0x0078, 0x27f5, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, + 0xa080, 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, + 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x2815, 0x007e, 0x2001, 0x4f04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2811, 0x2061, 0x0100, 0x0078, + 0x2817, 0x2061, 0x0200, 0x0078, 0x2817, 0x2061, 0x0100, 0xc1bc, + 0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa085, 0x0020, + 0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x2837, 0x007e, + 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2833, 0x2061, + 0x0100, 0x0078, 0x2839, 0x2061, 0x0200, 0x0078, 0x2839, 0x2061, + 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, + 0xa28c, 0x0020, 0x0040, 0x2847, 0xc2ac, 0xa39d, 0x4000, 0xc3fc, + 0xd3b4, 0x00c0, 0x284c, 0xc3fd, 0x62ae, 0x2010, 0x60a4, 0x63ae, + 0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, + 0xa005, 0x0040, 0x28b9, 0xd1fc, 0x0040, 0x2862, 0x2061, 0x96d0, + 0x0078, 0x2864, 0x2061, 0x95c0, 0x1078, 0x28c1, 0x0040, 0x289b, + 0x20a9, 0x0101, 0xd1fc, 0x0040, 0x2871, 0x2061, 0x95d0, 0x0078, + 0x2873, 0x2061, 0x94c0, 0x0c7e, 0x1078, 0x28c1, 0x0040, 0x287e, + 0x0c7f, 0x8c60, 0x00f0, 0x2873, 0x0078, 0x28b9, 0x007f, 0xd1fc, + 0x0040, 0x2888, 0xa082, 0x95d0, 0x2071, 0x4f80, 0x0078, 0x288c, + 0xa082, 0x94c0, 0x2071, 0x4f40, 0x707a, 0x7176, 0x2138, 0x2001, + 0x0004, 0x7066, 0x7083, 0x000f, 0x71d4, 0xc1dc, 0x71d6, 0x1078, + 0x265c, 0x0078, 0x28b5, 0xd1fc, 0x00c0, 0x28a2, 0x2071, 0x4f40, + 0x0078, 0x28a4, 0x2071, 0x4f80, 0x6020, 0xc0dd, 0x6022, 0x7176, + 0x2138, 0x2c00, 0x707e, 0x2001, 0x0006, 0x7066, 0x7083, 0x000f, + 0x71d4, 0xc1dc, 0x71d6, 0x1078, 0x265c, 0x2001, 0x0000, 0x0078, + 0x28bb, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f, + 0x007c, 0x2c04, 0xa005, 0x0040, 0x28d8, 0x2060, 0x6010, 0xa306, + 0x00c0, 0x28d5, 0x600c, 0xa206, 0x00c0, 0x28d5, 0x6014, 0xa106, + 0x00c0, 0x28d5, 0xa006, 0x0078, 0x28da, 0x6000, 0x0078, 0x28c2, + 0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x017e, 0xd1bc, 0x00c0, + 0x28f3, 0x2079, 0x4f40, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x28ef, 0x2071, 0x0100, 0x0078, 0x28f7, 0x2071, + 0x0200, 0x0078, 0x28f7, 0x2079, 0x4f80, 0x2071, 0x0100, 0x7920, + 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x00c0, 0x2901, 0x017f, 0x0078, + 0x291c, 0x810b, 0x810b, 0x810b, 0x810b, 0x007f, 0xd0bc, 0x00c0, + 0x2919, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x2915, 0xa18d, 0x0f00, 0x0078, 0x291b, 0xa18d, 0x0f00, 0x0078, + 0x291b, 0xa18d, 0x0800, 0x2104, 0x0e7f, 0x0f7f, 0x007c, 0x0e7e, + 0x2001, 0x4f01, 0x2004, 0xd0ac, 0x00c0, 0x299c, 0x68e4, 0xd0ac, + 0x0040, 0x299c, 0xa084, 0x0006, 0x00c0, 0x299c, 0x6014, 0xd0fc, + 0x00c0, 0x2936, 0x2071, 0x53c0, 0x0078, 0x2938, 0x2071, 0x5440, + 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, + 0xa084, 0x000a, 0x00c0, 0x299c, 0x7108, 0xa194, 0xff00, 0x0040, + 0x299c, 0xa18c, 0x00ff, 0x2001, 0x000a, 0xa106, 0x0040, 0x296b, + 0x2001, 0x000c, 0xa106, 0x0040, 0x296f, 0x2001, 0x0012, 0xa106, + 0x0040, 0x2973, 0x2001, 0x0014, 0xa106, 0x0040, 0x2977, 0x2001, + 0x0019, 0xa106, 0x0040, 0x297b, 0x2001, 0x0032, 0xa106, 0x0040, + 0x297f, 0x0078, 0x2983, 0x2009, 0x000c, 0x0078, 0x2985, 0x2009, + 0x0012, 0x0078, 0x2985, 0x2009, 0x0014, 0x0078, 0x2985, 0x2009, + 0x0019, 0x0078, 0x2985, 0x2009, 0x0020, 0x0078, 0x2985, 0x2009, + 0x003f, 0x0078, 0x2985, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, + 0x2071, 0x4f00, 0x7004, 0xd0bc, 0x0040, 0x299c, 0x6014, 0xd0fc, + 0x00c0, 0x2997, 0x70ea, 0x2071, 0x4f40, 0x0078, 0x299a, 0x70ee, + 0x2071, 0x4f80, 0x701f, 0x000d, 0x0e7f, 0x007c, 0x2001, 0x4f05, + 0x2004, 0xd0e4, 0x00c0, 0x29aa, 0x7804, 0xa084, 0xff1f, 0xa085, + 0x6340, 0x7806, 0x007c, 0x0068, 0x29ab, 0x2091, 0x8000, 0x2071, + 0x0000, 0x007e, 0x7018, 0xd084, 0x00c0, 0x29b2, 0x007f, 0x2071, + 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x080f, + 0x70df, 0x000a, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, + 0x0078, 0x29c8, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708e, + 0x7592, 0x7496, 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, 0x0040, + 0x29df, 0xa784, 0x007d, 0x00c0, 0x4414, 0x1078, 0x29ab, 0xa49c, + 0x000f, 0xa382, 0x0004, 0x0050, 0x29ea, 0xa3a6, 0x0007, 0x00c0, + 0x29ab, 0x2418, 0x8507, 0xa084, 0x000f, 0x0079, 0x29ef, 0x3068, + 0x3159, 0x3184, 0x33f6, 0x37df, 0x3859, 0x390e, 0x399f, 0x3a8d, + 0x3b7c, 0x2a02, 0x29ff, 0x2e39, 0x2f5c, 0x37b0, 0x29ff, 0x1078, + 0x29ab, 0x007c, 0xa006, 0x0078, 0x2a0c, 0x7808, 0xc08d, 0x780a, + 0xa006, 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, 0xa005, 0x00c0, + 0x2b72, 0x7064, 0xa084, 0x0007, 0x0079, 0x2a16, 0x2a1e, 0x2a91, + 0x2a9a, 0x2aa5, 0x2ab0, 0x2b58, 0x2abb, 0x2a91, 0x7830, 0xd0bc, + 0x00c0, 0x2a01, 0x71d4, 0xd1bc, 0x00c0, 0x2a01, 0xd1b4, 0x00c0, + 0x2a6e, 0x70a4, 0xa086, 0x0001, 0x0040, 0x2a01, 0x70b4, 0xa06d, + 0x6800, 0xa065, 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, 0x6808, + 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0040, + 0x2a44, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, + 0x0010, 0x0078, 0x2ccc, 0x7060, 0xa005, 0x00c0, 0x2a01, 0x0c7e, + 0x0d7e, 0x70b4, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0010, + 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, + 0xa886, 0x0001, 0x0040, 0x2a67, 0x69bc, 0x7daa, 0x79aa, 0x68c0, + 0xa04d, 0x6e1c, 0x2001, 0x0020, 0x0078, 0x2ccc, 0x1078, 0x43a7, + 0x00c0, 0x2a01, 0x781b, 0x005b, 0x70bc, 0xa06d, 0x68b4, 0x785a, + 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, + 0x780a, 0x68bc, 0x7042, 0xc1b4, 0x71d6, 0x70b8, 0xa065, 0x68c0, + 0x705a, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, + 0x007c, 0x1078, 0x43a7, 0x00c0, 0x2a99, 0x781b, 0x0047, 0x7003, + 0x0004, 0x007c, 0x1078, 0x43a7, 0x00c0, 0x2aa4, 0x2011, 0x000c, + 0x1078, 0x2acb, 0x7003, 0x0004, 0x007c, 0x1078, 0x43a7, 0x00c0, + 0x2aaf, 0x2011, 0x0006, 0x1078, 0x2acb, 0x7003, 0x0004, 0x007c, + 0x1078, 0x43a7, 0x00c0, 0x2aba, 0x2011, 0x000d, 0x1078, 0x2acb, + 0x7003, 0x0004, 0x007c, 0x1078, 0x43a7, 0x00c0, 0x2aca, 0x2011, + 0x0006, 0x1078, 0x2acb, 0x707c, 0x707f, 0x0000, 0x2068, 0x704e, + 0x7003, 0x0001, 0x007c, 0x7174, 0xc1fc, 0x8107, 0x7882, 0x789b, + 0x0010, 0xa286, 0x000c, 0x00c0, 0x2ada, 0x7aaa, 0x2001, 0x0001, + 0x0078, 0x2aef, 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, + 0x000d, 0x0040, 0x2ae8, 0x7aaa, 0x2001, 0x0002, 0x0078, 0x2aef, + 0x78ab, 0x0020, 0x7178, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, + 0x0060, 0x78aa, 0x785b, 0x0004, 0x781b, 0x0116, 0x1078, 0x43ca, + 0x7083, 0x000f, 0x70d4, 0xd0b4, 0x0040, 0x2b0b, 0xc0b4, 0x70d6, + 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, + 0x8001, 0x601a, 0x0c7f, 0x007c, 0x7014, 0xa005, 0x00c0, 0x2b1a, + 0x70d4, 0xd0b4, 0x0040, 0x2b1b, 0x70b8, 0xac06, 0x00c0, 0x2b1b, + 0x1078, 0x2afa, 0x007c, 0x017e, 0x71a4, 0xa186, 0x0001, 0x0040, + 0x2b4d, 0x0d7e, 0x027e, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b4, + 0x2068, 0x6800, 0xac06, 0x0040, 0x2b34, 0x8211, 0x0040, 0x2b4b, + 0x1078, 0x2b4f, 0x0078, 0x2b29, 0x0c7e, 0x2100, 0x2011, 0x0001, + 0xa212, 0x70b4, 0x2068, 0x6800, 0x2060, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x8211, 0x0040, 0x2b48, 0x1078, 0x2b4f, 0x0078, 0x2b3b, + 0x70a7, 0x0001, 0x0c7f, 0x027f, 0x0d7f, 0x017f, 0x007c, 0xade8, + 0x0005, 0x70ac, 0xad06, 0x00c0, 0x2b57, 0x70a8, 0x2068, 0x007c, + 0x1078, 0x43a7, 0x00c0, 0x2a01, 0x707c, 0x2068, 0x7774, 0x1078, + 0x4245, 0x2c50, 0x1078, 0x4489, 0x789b, 0x0010, 0x6814, 0xa084, + 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, 0x0004, + 0x0078, 0x2cd2, 0x1078, 0x43a7, 0x00c0, 0x2a01, 0x789b, 0x0010, + 0x7060, 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0040, 0x2b8c, 0xc0b4, + 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x6018, 0x8001, 0x601a, 0x0c7f, 0x1078, 0x4245, 0x2c50, 0x1078, + 0x4489, 0x6824, 0xa005, 0x0040, 0x2b9d, 0xa082, 0x0006, 0x0048, + 0x2b9b, 0x0078, 0x2b9d, 0x6827, 0x0005, 0x6814, 0xa084, 0x001f, + 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, 0x0003, + 0x0078, 0x2cd2, 0xc28d, 0x72d6, 0x72c0, 0xa200, 0xa015, 0x7154, + 0x8108, 0xa12a, 0x0048, 0x2bb5, 0x71c0, 0x2164, 0x6504, 0x85ff, + 0x00c0, 0x2bcc, 0x7156, 0x8421, 0x00c0, 0x2bb0, 0x70d4, 0xd08c, + 0x0040, 0x2bc8, 0x70d0, 0xa005, 0x00c0, 0x2bc8, 0x70d3, 0x000a, + 0x007c, 0x2200, 0x0078, 0x2bba, 0x70d4, 0xc08c, 0x70d6, 0x70d3, + 0x0000, 0x6034, 0xa005, 0x00c0, 0x2bc9, 0x6708, 0xa784, 0x073f, + 0x0040, 0x2bfb, 0xd7d4, 0x00c0, 0x2bc9, 0xa784, 0x0021, 0x00c0, + 0x2bc9, 0xa784, 0x0002, 0x0040, 0x2bec, 0xa784, 0x0004, 0x0040, + 0x2bc9, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, 0x00c0, 0x2bc9, + 0xa784, 0x0100, 0x0040, 0x2bfb, 0x6018, 0xa005, 0x00c0, 0x2bc9, + 0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, 0x6e1c, 0xa684, + 0x000e, 0x6318, 0x0040, 0x2c0c, 0x601c, 0xa302, 0x0048, 0x2c0f, + 0x0040, 0x2c0f, 0x0078, 0x2bc9, 0x83ff, 0x00c0, 0x2bc9, 0x2d58, + 0x2c50, 0x7156, 0xd7bc, 0x00c0, 0x2c18, 0x7028, 0x6022, 0x603a, + 0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041, + 0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0040, + 0x2c2c, 0xd684, 0x0040, 0x2c2e, 0xa39c, 0xffbf, 0xd6a4, 0x0040, + 0x2c33, 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2c7e, 0xc7a5, + 0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2c52, + 0x70d4, 0xd0b4, 0x00c0, 0x2c52, 0x7000, 0xa082, 0x0002, 0x00c8, + 0x2c52, 0x7830, 0xd0bc, 0x00c0, 0x2c52, 0x789b, 0x0010, 0x7baa, + 0x0078, 0x2cca, 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, 0x0005, + 0x70ac, 0xa606, 0x00c0, 0x2c5d, 0x76a8, 0x76b2, 0x2c3a, 0x8738, + 0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, 0x7830, + 0xd0bc, 0x0040, 0x2c75, 0x2091, 0x8000, 0x2091, 0x303d, 0x70d4, + 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, 0x0040, + 0x2c7d, 0x8421, 0x2200, 0x00c0, 0x2baf, 0x007c, 0xd1dc, 0x0040, + 0x3e40, 0x2029, 0x0020, 0xd69c, 0x00c0, 0x2c8b, 0x8528, 0xd68c, + 0x00c0, 0x2c8b, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, 0xa18c, + 0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0040, 0x2caa, 0x6014, + 0xa706, 0x00c0, 0x2c93, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2c8e, + 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x00c0, + 0x2baf, 0x007c, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840, + 0x6008, 0xc0d5, 0x600a, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2c52, + 0x70d4, 0xd0b4, 0x00c0, 0x2c52, 0x7000, 0xa082, 0x0002, 0x00c8, + 0x2c52, 0x7830, 0xd0bc, 0x00c0, 0x2c52, 0x789b, 0x0010, 0x7baa, + 0x7daa, 0x79aa, 0x2001, 0x0002, 0x007e, 0x6018, 0x8000, 0x601a, + 0x0078, 0x2cd3, 0x007e, 0x2960, 0x6104, 0x2a60, 0xa184, 0x0018, + 0x0040, 0x2cef, 0xa184, 0x0010, 0x0040, 0x2ce2, 0x1078, 0x4055, + 0x00c0, 0x2d14, 0xa184, 0x0008, 0x0040, 0x2cef, 0x69a0, 0xa184, + 0x0600, 0x00c0, 0x2cef, 0x1078, 0x3f35, 0x0078, 0x2d14, 0x69a0, + 0xa184, 0x1e00, 0x0040, 0x2d1f, 0xa184, 0x0800, 0x0040, 0x2d08, + 0x0c7e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, + 0x0010, 0x6106, 0x0c7f, 0x1078, 0x4055, 0x00c0, 0x2d14, 0x69a0, + 0xa184, 0x0200, 0x0040, 0x2d10, 0x1078, 0x3f98, 0x0078, 0x2d14, + 0xa184, 0x0400, 0x00c0, 0x2ceb, 0x69a0, 0xa184, 0x1000, 0x0040, + 0x2d1f, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x27df, 0x027f, + 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x2d2c, 0xa086, 0x0060, + 0x00c0, 0x2d2c, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, 0x0040, + 0x2d47, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0050, 0x2d45, + 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, 0x78aa, + 0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0, + 0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898, + 0x25a0, 0xa286, 0x0020, 0x00c0, 0x2d7f, 0x70d4, 0xc0b5, 0x70d6, + 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0xa286, 0x0002, 0x0040, 0x2db5, 0x70a4, 0x8000, 0x70a6, 0x74b4, + 0xa498, 0x0005, 0x70ac, 0xa306, 0x00c0, 0x2d77, 0x73a8, 0x73b6, + 0xa286, 0x0010, 0x0040, 0x2a01, 0x0d7f, 0x0c7f, 0x007c, 0x7000, + 0xa005, 0x00c0, 0x2d5d, 0xa286, 0x0002, 0x00c0, 0x2dcf, 0x1078, + 0x43a7, 0x00c0, 0x2d5d, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x2091, + 0x8000, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, + 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, 0x780a, + 0x127e, 0x0d7e, 0x0c7e, 0x70d4, 0xa084, 0x2700, 0x2090, 0x0c7f, + 0x0d7f, 0x127f, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, 0x0002, + 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x7830, 0xd0bc, 0x0040, + 0x2dc1, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, + 0x2090, 0x70a4, 0xa005, 0x00c0, 0x2dc6, 0x007c, 0x8421, 0x0040, + 0x2dc5, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0078, 0x2baf, 0xa286, + 0x0010, 0x00c0, 0x2e00, 0x1078, 0x43a7, 0x00c0, 0x2d5d, 0x6814, + 0xc0fc, 0x8007, 0x7882, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, + 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, + 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, 0xa206, + 0x00c0, 0x2df3, 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, 0x7042, + 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, + 0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x005b, + 0x2900, 0x705a, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605, + 0x0040, 0x2e2b, 0x70d4, 0xa084, 0x2700, 0xa086, 0x2300, 0x00c0, + 0x2e25, 0x2009, 0x0000, 0x0078, 0x2e27, 0x2009, 0x0001, 0xa284, + 0x000f, 0x1079, 0x2e2f, 0xad80, 0x0009, 0x7046, 0x007c, 0x2e37, + 0x4930, 0x4930, 0x491d, 0x4930, 0x2e37, 0x2e37, 0x2e37, 0x1078, + 0x29ab, 0x7808, 0xa084, 0xfffd, 0x780a, 0x1078, 0x299e, 0x0f7e, + 0x2079, 0x4f00, 0x78ac, 0x0f7f, 0xd084, 0x0040, 0x2e61, 0x7064, + 0xa086, 0x0001, 0x00c0, 0x2e4f, 0x7066, 0x0078, 0x2f38, 0x7064, + 0xa086, 0x0005, 0x00c0, 0x2e5f, 0x707c, 0x2068, 0x681b, 0x0004, + 0x6817, 0x0000, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7067, + 0x0000, 0x70a7, 0x0000, 0x70a8, 0x70b2, 0x70b6, 0x1078, 0x2afa, + 0x157e, 0x2011, 0x0004, 0x7164, 0xa186, 0x0001, 0x0040, 0x2e81, + 0xa186, 0x0007, 0x00c0, 0x2e78, 0x701f, 0x0005, 0x0078, 0x2e81, + 0x701f, 0x0001, 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, + 0x2e83, 0x7067, 0x0000, 0x2001, 0x4f0a, 0x2004, 0xa084, 0x00ff, + 0xa086, 0x0018, 0x0040, 0x2e93, 0x7018, 0x7016, 0xa005, 0x00c0, + 0x2e93, 0x70a7, 0x0001, 0x067e, 0x1078, 0x45cd, 0x20a9, 0x0010, + 0x2039, 0x0000, 0x1078, 0x413f, 0xa7b8, 0x0100, 0x00f0, 0x2e9a, + 0x067f, 0x7000, 0x0079, 0x2ea4, 0x2ede, 0x2eb9, 0x2eb9, 0x2eae, + 0x2ede, 0x2ede, 0x2ede, 0x2eac, 0x1078, 0x29ab, 0x7060, 0xa005, + 0x0040, 0x2ede, 0xad06, 0x00c0, 0x2eb9, 0x6800, 0x7062, 0x0078, + 0x2ecb, 0x6820, 0xd084, 0x00c0, 0x2ec7, 0x6f14, 0x1078, 0x4245, + 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3e10, 0x0078, 0x2ecb, 0x705c, + 0x2060, 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, 0xd0fc, + 0x0040, 0x2ed3, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820, + 0xa084, 0x00ff, 0xc09d, 0x6822, 0x1078, 0x206c, 0xb284, 0x0400, + 0x0040, 0x2ee6, 0x2021, 0x96d0, 0x0078, 0x2ee8, 0x2021, 0x95c0, + 0x1078, 0x2f3d, 0xb284, 0x0400, 0x0040, 0x2ef2, 0x2021, 0x4f98, + 0x0078, 0x2ef4, 0x2021, 0x4f58, 0x1078, 0x2f3d, 0x20a9, 0x0101, + 0xb284, 0x0400, 0x0040, 0x2f00, 0x2021, 0x95d0, 0x0078, 0x2f02, + 0x2021, 0x94c0, 0x1078, 0x2f3d, 0x8420, 0x00f0, 0x2f02, 0xb284, + 0x0300, 0x0040, 0x2f0f, 0x2061, 0x54c0, 0x0078, 0x2f11, 0x2061, + 0x74c0, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0040, + 0x2f2e, 0x6018, 0x017e, 0x007e, 0x2011, 0x4f02, 0x220c, 0xa102, + 0x2012, 0x007f, 0x017f, 0xa102, 0x0050, 0x2f2e, 0x6012, 0x00c0, + 0x2f2e, 0x2011, 0x4f04, 0x2204, 0xc0a5, 0x2012, 0x601b, 0x0000, + 0xace0, 0x0010, 0x00f0, 0x2f15, 0x8421, 0x00c0, 0x2f13, 0x157f, + 0x7003, 0x0000, 0x704f, 0x0000, 0x007c, 0x047e, 0x2404, 0xa005, + 0x0040, 0x2f58, 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6817, 0x0000, + 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, + 0x00ff, 0xc09d, 0x6822, 0x1078, 0x206c, 0x007f, 0x0078, 0x2f3f, + 0x047f, 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, 0x2f62, + 0x1078, 0x29ab, 0x2300, 0x0079, 0x2f65, 0x2f68, 0x2ff3, 0x3010, + 0xa282, 0x0002, 0x0040, 0x2f6e, 0x1078, 0x29ab, 0x7064, 0x7067, + 0x0000, 0x7083, 0x0000, 0x0079, 0x2f75, 0x2f7d, 0x2f7d, 0x2f7f, + 0x2fbf, 0x3e4c, 0x2f7d, 0x2fbf, 0x2f7d, 0x1078, 0x29ab, 0x7774, + 0x1078, 0x413f, 0x7774, 0xa7bc, 0x8f00, 0x1078, 0x4245, 0x6018, + 0xa005, 0x0040, 0x2fb6, 0xd7fc, 0x00c0, 0x2f92, 0x2021, 0x95c0, + 0x0078, 0x2f94, 0x2021, 0x96d0, 0x2009, 0x0005, 0x2011, 0x0010, + 0x1078, 0x302b, 0x0040, 0x2fb6, 0x157e, 0x20a9, 0x0101, 0xd7fc, + 0x00c0, 0x2fa6, 0x2021, 0x94c0, 0x0078, 0x2fa8, 0x2021, 0x95d0, + 0x047e, 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, 0x302b, 0x047f, + 0x0040, 0x2fb5, 0x8420, 0x00f0, 0x2fa8, 0x157f, 0x8738, 0xa784, + 0x001f, 0x00c0, 0x2f85, 0x0078, 0x2a05, 0x0078, 0x2a05, 0x7774, + 0x1078, 0x4245, 0x6018, 0xa005, 0x0040, 0x2ff1, 0xd7fc, 0x00c0, + 0x2fcd, 0x2021, 0x95c0, 0x0078, 0x2fcf, 0x2021, 0x96d0, 0x2009, + 0x0005, 0x2011, 0x0020, 0x1078, 0x302b, 0x0040, 0x2ff1, 0x157e, + 0x20a9, 0x0101, 0xd7fc, 0x00c0, 0x2fe1, 0x2021, 0x94c0, 0x0078, + 0x2fe3, 0x2021, 0x95d0, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020, + 0x1078, 0x302b, 0x047f, 0x0040, 0x2ff0, 0x8420, 0x00f0, 0x2fe3, + 0x157f, 0x0078, 0x2a05, 0x2200, 0x0079, 0x2ff6, 0x2ff9, 0x2ffb, + 0x2ffb, 0x1078, 0x29ab, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002, + 0x0040, 0x3004, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0040, 0x3009, + 0x691a, 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x4354, + 0x2200, 0x0079, 0x3013, 0x3018, 0x2ffb, 0x3016, 0x1078, 0x29ab, + 0x1078, 0x45cd, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3dbe, 0x1078, + 0x3e2d, 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3daf, 0x0040, + 0x3dbe, 0x0078, 0x2a05, 0x2404, 0xa005, 0x0040, 0x3064, 0x2068, + 0x2d04, 0x007e, 0x6814, 0xa706, 0x0040, 0x303a, 0x2d20, 0x007f, + 0x0078, 0x302c, 0x007f, 0x2022, 0x691a, 0x6817, 0x0000, 0x682b, + 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, 0x00ff, + 0xa205, 0x6822, 0x1078, 0x206c, 0x2021, 0x4f02, 0x241c, 0x8319, + 0x2322, 0x6010, 0x8001, 0x6012, 0x00c0, 0x305b, 0x2021, 0x4f04, + 0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x1078, + 0x2b1b, 0x1078, 0x3e2d, 0x007c, 0xa085, 0x0001, 0x0078, 0x3063, + 0x2300, 0x0079, 0x306b, 0x3070, 0x306e, 0x30f0, 0x1078, 0x29ab, + 0x78e4, 0xa005, 0x00d0, 0x30a6, 0x3208, 0x007e, 0x2001, 0x4f04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x3081, 0xa18c, 0x0300, 0x0078, + 0x3083, 0xa18c, 0x0400, 0x0040, 0x3089, 0x0018, 0x2a01, 0x0078, + 0x308b, 0x0028, 0x2a01, 0x2008, 0xa084, 0x0030, 0x00c0, 0x3092, + 0x0078, 0x37b0, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3090, 0x2100, + 0xa084, 0x0007, 0x0079, 0x309c, 0x30d0, 0x30da, 0x30c5, 0x30a4, + 0x439c, 0x439c, 0x30a4, 0x30e5, 0x1078, 0x29ab, 0x7000, 0xa086, + 0x0004, 0x00c0, 0x30c0, 0x7064, 0xa086, 0x0002, 0x00c0, 0x30b6, + 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, 0x2f5c, 0x7064, 0xa086, + 0x0006, 0x0040, 0x30b0, 0x7064, 0xa086, 0x0004, 0x0040, 0x30b0, + 0x79e4, 0x2001, 0x0003, 0x0078, 0x343a, 0x6818, 0xd0fc, 0x0040, + 0x30cb, 0x681b, 0x001d, 0x1078, 0x410f, 0x781b, 0x0064, 0x007c, + 0x6818, 0xd0fc, 0x0040, 0x30d6, 0x681b, 0x001d, 0x1078, 0x410f, + 0x0078, 0x4378, 0x6818, 0xd0fc, 0x0040, 0x30e0, 0x681b, 0x001d, + 0x1078, 0x410f, 0x781b, 0x00f8, 0x007c, 0x6818, 0xd0fc, 0x0040, + 0x30eb, 0x681b, 0x001d, 0x1078, 0x410f, 0x781b, 0x00c8, 0x007c, + 0xa584, 0x000f, 0x00c0, 0x310f, 0x1078, 0x299e, 0x7000, 0x0079, + 0x30f9, 0x2a05, 0x3101, 0x3103, 0x3dbe, 0x3dbe, 0x3dbe, 0x3101, + 0x3101, 0x1078, 0x29ab, 0x1078, 0x3e2d, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x1078, 0x3daf, 0x0040, 0x3dbe, 0x0078, 0x2a05, 0x78e4, + 0xa005, 0x00d0, 0x30a6, 0x3208, 0x007e, 0x2001, 0x4f04, 0x2004, + 0xd0ec, 0x007f, 0x0040, 0x3120, 0xa18c, 0x0300, 0x0078, 0x3122, + 0xa18c, 0x0400, 0x0040, 0x3128, 0x0018, 0x30a6, 0x0078, 0x312a, + 0x0028, 0x30a6, 0x2008, 0xa084, 0x0030, 0x00c0, 0x3132, 0x781b, + 0x005b, 0x007c, 0x78ec, 0xa084, 0x0003, 0x0040, 0x312f, 0x2100, + 0xa184, 0x0007, 0x0079, 0x313c, 0x314b, 0x314f, 0x3146, 0x3144, + 0x439c, 0x439c, 0x3144, 0x4396, 0x1078, 0x29ab, 0x1078, 0x4117, + 0x781b, 0x0064, 0x007c, 0x1078, 0x4117, 0x0078, 0x4378, 0x1078, + 0x4117, 0x781b, 0x00f8, 0x007c, 0x1078, 0x4117, 0x781b, 0x00c8, + 0x007c, 0x2300, 0x0079, 0x315c, 0x3161, 0x315f, 0x3163, 0x1078, + 0x29ab, 0x0078, 0x399f, 0x681b, 0x0016, 0x78a3, 0x0000, 0x79e4, + 0xa184, 0x0030, 0x0040, 0x399f, 0x78ec, 0xa084, 0x0003, 0x0040, + 0x399f, 0xa184, 0x0100, 0x0040, 0x3167, 0xa184, 0x0007, 0x0079, + 0x3179, 0x3181, 0x314f, 0x30c5, 0x4354, 0x439c, 0x439c, 0x4354, + 0x4396, 0x1078, 0x4360, 0x007c, 0xa282, 0x0005, 0x0050, 0x318a, + 0x1078, 0x29ab, 0x2300, 0x0079, 0x318d, 0x3190, 0x33c0, 0x33cb, + 0x2200, 0x0079, 0x3193, 0x31ad, 0x319a, 0x31ad, 0x3198, 0x33a3, + 0x1078, 0x29ab, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, + 0x0020, 0x0048, 0x40fe, 0xa08a, 0x0004, 0x00c8, 0x40fe, 0x0079, + 0x31a9, 0x40fe, 0x40fe, 0x40fe, 0x40a8, 0x789b, 0x0018, 0x79a8, + 0xa184, 0x0080, 0x0040, 0x31be, 0x0078, 0x40fe, 0x7000, 0xa005, + 0x00c0, 0x31b4, 0x2011, 0x0004, 0x0078, 0x3b8a, 0xa184, 0x00ff, + 0xa08a, 0x0010, 0x00c8, 0x40fe, 0x0079, 0x31c6, 0x31d8, 0x31d6, + 0x31ed, 0x31f1, 0x32c4, 0x40fe, 0x40fe, 0x32c6, 0x40fe, 0x40fe, + 0x339f, 0x339f, 0x40fe, 0x40fe, 0x40fe, 0x33a1, 0x1078, 0x29ab, + 0xd6e4, 0x0040, 0x31e3, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, + 0x781b, 0x00c3, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x31eb, 0x681b, + 0x001d, 0x0078, 0x31db, 0x0078, 0x4354, 0x681b, 0x001d, 0x0078, + 0x4108, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0, 0x3256, 0x6820, + 0xd084, 0x00c0, 0x325c, 0x6818, 0xa086, 0x0008, 0x00c0, 0x3202, + 0x681b, 0x0000, 0xd6d4, 0x0040, 0x32c1, 0xd6bc, 0x0040, 0x3242, + 0x7087, 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, 0x0050, + 0x3242, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, + 0x789b, 0x0061, 0x78aa, 0x157e, 0x137e, 0x147e, 0x017e, 0x3208, + 0xa18c, 0x0300, 0x0040, 0x3234, 0x007e, 0x2001, 0x4f04, 0x2004, + 0xd0ec, 0x007f, 0x0040, 0x3230, 0x20a1, 0x012b, 0x0078, 0x3236, + 0x20a1, 0x022b, 0x0078, 0x3236, 0x20a1, 0x012b, 0x017f, 0x789b, + 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, + 0x137f, 0x157f, 0x6038, 0xa005, 0x00c0, 0x3251, 0x681c, 0xa084, + 0x000e, 0x0040, 0x4108, 0x1078, 0x411e, 0x782b, 0x3008, 0x0078, + 0x3253, 0x8001, 0x603a, 0x781b, 0x0067, 0x007c, 0xd6e4, 0x0040, + 0x325c, 0x781b, 0x0079, 0x007c, 0xa684, 0x0060, 0x0040, 0x32be, + 0xd6dc, 0x0040, 0x32be, 0xd6fc, 0x00c0, 0x3268, 0x0078, 0x327f, + 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8, + 0x3272, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, + 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0xd6f4, + 0x0040, 0x3285, 0xc6f4, 0x7e5a, 0x6eb6, 0x7000, 0xa086, 0x0003, + 0x00c0, 0x3293, 0x007e, 0x1078, 0x45cd, 0x1078, 0x4930, 0x007f, + 0x781b, 0x0076, 0x007c, 0xa006, 0x1078, 0x4a35, 0x6ab0, 0x69ac, + 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, 0x32a2, 0x2200, 0xa422, + 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde, + 0x2300, 0xa405, 0x00c0, 0x32b2, 0xc6f5, 0x7e5a, 0x6eb6, 0x781b, + 0x0076, 0x007c, 0x781b, 0x0076, 0x2200, 0xa115, 0x00c0, 0x32bb, + 0x1078, 0x4930, 0x007c, 0x1078, 0x4968, 0x007c, 0x781b, 0x0079, + 0x007c, 0x781b, 0x0067, 0x007c, 0x1078, 0x29ab, 0x0078, 0x3312, + 0x6920, 0xd1c4, 0x0040, 0x32db, 0xc1c4, 0x6922, 0x0c7e, 0x7058, + 0x2060, 0x6000, 0xc0e4, 0x6002, 0x6004, 0xa084, 0xfff5, 0x6006, + 0x0c7f, 0x0078, 0x3306, 0xd1cc, 0x0040, 0x3306, 0xc1cc, 0x6922, + 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x6004, 0xc0a4, + 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xd19c, 0x0040, 0x3306, 0x1078, + 0x4241, 0x1078, 0x3f35, 0x88ff, 0x0040, 0x3306, 0x789b, 0x0060, + 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3303, + 0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7e58, 0xd6d4, + 0x00c0, 0x330d, 0x781b, 0x0067, 0x007c, 0x781b, 0x0079, 0x007c, + 0x0078, 0x4103, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x00c0, + 0x3320, 0x6820, 0xa084, 0x0100, 0x0040, 0x3310, 0x2009, 0x0008, + 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, + 0x333c, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x3334, + 0x0048, 0x3334, 0x0078, 0x3336, 0x0078, 0x32c8, 0x24a8, 0x7aa8, + 0x00f0, 0x3336, 0x0078, 0x3322, 0xa284, 0x00f0, 0xa086, 0x0020, + 0x00c0, 0x3390, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x334c, + 0x0048, 0x334c, 0x0078, 0x338d, 0xa286, 0x0023, 0x0040, 0x3310, + 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xc0a5, + 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, 0x0c7e, 0x7058, 0x2060, + 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd1a4, 0x0040, 0x336d, 0x1078, + 0x4241, 0x1078, 0x4055, 0x0078, 0x337b, 0x0c7e, 0x7058, 0x2060, + 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd19c, 0x0040, 0x3306, 0x1078, + 0x4241, 0x1078, 0x3f35, 0x88ff, 0x0040, 0x3306, 0x789b, 0x0060, + 0x2800, 0x78aa, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x338a, 0x781b, + 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7aa8, 0x0078, 0x3322, + 0x8318, 0x2300, 0xa102, 0x0040, 0x3399, 0x0048, 0x3399, 0x0078, + 0x3322, 0xa284, 0x0080, 0x00c0, 0x4108, 0x0078, 0x4103, 0x0078, + 0x4108, 0x0078, 0x40fe, 0x7058, 0xa04d, 0x789b, 0x0018, 0x78a8, + 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0040, 0x33b0, 0x1078, 0x29ab, + 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, + 0x00c8, 0x40fe, 0x0079, 0x33bc, 0x40fe, 0x3e86, 0x40fe, 0x3ffd, + 0xa282, 0x0000, 0x00c0, 0x33c6, 0x1078, 0x29ab, 0x1078, 0x410f, + 0x781b, 0x0078, 0x007c, 0xa282, 0x0003, 0x00c0, 0x33d1, 0x1078, + 0x29ab, 0xd4fc, 0x00c0, 0x33f1, 0x7064, 0xa005, 0x0040, 0x33da, + 0x1078, 0x29ab, 0x6f14, 0x7776, 0xa7bc, 0x8f00, 0x1078, 0x4245, + 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x33de, 0x1078, 0x4113, 0x7067, 0x0002, 0x701f, 0x0009, 0x0078, + 0x33f3, 0x1078, 0x4122, 0x781b, 0x0078, 0x007c, 0xa282, 0x0004, + 0x0050, 0x33fc, 0x1078, 0x29ab, 0x2300, 0x0079, 0x33ff, 0x3402, + 0x35c2, 0x3605, 0xa286, 0x0003, 0x0040, 0x343a, 0x7200, 0x7cd8, + 0x7ddc, 0x7fd0, 0x71d4, 0xd1bc, 0x00c0, 0x3432, 0xd1b4, 0x0040, + 0x3432, 0x7868, 0xa084, 0x00ff, 0x00c0, 0x3432, 0xa282, 0x0002, + 0x00c8, 0x3432, 0x0d7e, 0x783b, 0x8300, 0x781b, 0x004c, 0x70bc, + 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, + 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x2001, 0x0000, + 0x0078, 0x343e, 0x783b, 0x1300, 0x781b, 0x004a, 0x2001, 0x0000, + 0x0078, 0x343e, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x704a, 0x68a0, + 0xd0ec, 0x0040, 0x3446, 0x6008, 0xc08d, 0x600a, 0xa284, 0x000f, + 0x0079, 0x344a, 0x35a2, 0x3457, 0x3454, 0x3708, 0x3794, 0x2a05, + 0x3452, 0x3452, 0x1078, 0x29ab, 0x6008, 0xc0d4, 0x600a, 0xd6e4, + 0x0040, 0x345f, 0x7048, 0xa086, 0x0014, 0x00c0, 0x347f, 0x1078, + 0x45cd, 0x2009, 0x0000, 0x6818, 0xd0fc, 0x0040, 0x3468, 0x7048, + 0xa086, 0x0014, 0x0040, 0x3479, 0x6818, 0xa086, 0x0008, 0x00c0, + 0x355a, 0x7858, 0xd09c, 0x0040, 0x355a, 0x6820, 0xd0ac, 0x0040, + 0x355a, 0x681b, 0x0014, 0x2009, 0x0002, 0x0078, 0x34be, 0x7868, + 0xa08c, 0x00ff, 0x0040, 0x34be, 0xa186, 0x0008, 0x00c0, 0x3495, + 0x6008, 0xc0a4, 0x600a, 0x1078, 0x3daf, 0x0040, 0x34be, 0x1078, + 0x3e2d, 0x1078, 0x45cd, 0x0078, 0x34a6, 0xa186, 0x0028, 0x00c0, + 0x34be, 0x6018, 0xa005, 0x0040, 0x3488, 0x8001, 0x0040, 0x3488, + 0x8001, 0x0040, 0x3488, 0x601e, 0x0078, 0x3488, 0x6820, 0xd084, + 0x0040, 0x2a05, 0xc084, 0x6822, 0x1078, 0x2b0c, 0x705c, 0x0c7e, + 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00, + 0x00c0, 0x34bb, 0x6002, 0x6006, 0x0078, 0x2a05, 0x017e, 0x81ff, + 0x00c0, 0x3508, 0x7000, 0xa086, 0x0030, 0x0040, 0x3508, 0x71d4, + 0xd1bc, 0x00c0, 0x3508, 0xd1b4, 0x00c0, 0x34ef, 0x7060, 0xa005, + 0x00c0, 0x3508, 0x70a4, 0xa086, 0x0001, 0x0040, 0x3508, 0x7003, + 0x0000, 0x047e, 0x057e, 0x077e, 0x067e, 0x0c7e, 0x0d7e, 0x1078, + 0x2a2e, 0x0d7f, 0x0c7f, 0x067f, 0x077f, 0x057f, 0x047f, 0x71d4, + 0xd1b4, 0x00c0, 0x3508, 0x7003, 0x0040, 0x0078, 0x3508, 0x1078, + 0x43a7, 0x00c0, 0x3508, 0x781b, 0x005b, 0x0d7e, 0x70bc, 0xa06d, + 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, + 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, 0x0d7f, + 0x1078, 0x363f, 0x017f, 0x81ff, 0x0040, 0x355a, 0xa684, 0xdf00, + 0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x00c0, 0x355b, + 0x6818, 0xa086, 0x0014, 0x00c0, 0x3524, 0x2008, 0xd6e4, 0x0040, + 0x3524, 0x7868, 0xa08c, 0x00ff, 0x1078, 0x2afa, 0x1078, 0x2b1b, + 0x6820, 0xd0dc, 0x00c0, 0x355b, 0x8717, 0xa294, 0x000f, 0x8213, + 0x8213, 0x8213, 0xb284, 0x0300, 0x0040, 0x353a, 0xa290, 0x53c0, + 0x0078, 0x353c, 0xa290, 0x5440, 0xa290, 0x0000, 0x221c, 0xd3c4, + 0x00c0, 0x3544, 0x0078, 0x354a, 0x8210, 0x2204, 0xa085, 0x0018, + 0x2012, 0x8211, 0xd3d4, 0x0040, 0x3555, 0x68a0, 0xd0c4, 0x00c0, + 0x3555, 0x1078, 0x36b9, 0x0078, 0x2a05, 0x6008, 0xc08d, 0x600a, + 0x0078, 0x355b, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0040, 0x3562, + 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, 0x0040, + 0x3577, 0x2009, 0x4f02, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, + 0x00c0, 0x3577, 0x2021, 0x4f04, 0x2404, 0xc0a5, 0x2022, 0x6018, + 0xa005, 0x0040, 0x357f, 0x8001, 0x601a, 0x00c0, 0x3582, 0x6008, + 0xc0a4, 0x600a, 0x6820, 0xd084, 0x00c0, 0x358e, 0x6800, 0xa005, + 0x00c0, 0x358b, 0x6002, 0x6006, 0x0078, 0x3592, 0x705c, 0x2060, + 0x6800, 0x6002, 0x2061, 0x4f00, 0x6887, 0x0103, 0x2d08, 0x206b, + 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x35a1, 0x2d02, 0x0078, + 0x35a2, 0x616e, 0x7200, 0xa286, 0x0030, 0x0040, 0x35b2, 0xa286, + 0x0040, 0x00c0, 0x2a05, 0x7003, 0x0002, 0x704c, 0x2068, 0x68c4, + 0x2060, 0x007c, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, 0x7042, + 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, 0x0009, + 0x7046, 0x007c, 0xa282, 0x0004, 0x0048, 0x35c8, 0x1078, 0x29ab, + 0x2200, 0x0079, 0x35cb, 0x35cf, 0x35e0, 0x35ed, 0x35e0, 0xa586, + 0x1300, 0x0040, 0x35e0, 0xa586, 0x8300, 0x00c0, 0x35c6, 0x7003, + 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x7000, 0xa086, 0x0005, 0x0040, 0x35ea, 0x1078, 0x410f, 0x781b, + 0x0078, 0x007c, 0x781b, 0x0079, 0x007c, 0x7890, 0x8007, 0x8001, + 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, + 0xa186, 0x0003, 0x0040, 0x3602, 0xa186, 0x0000, 0x0040, 0x3602, + 0x0078, 0x40fe, 0x781b, 0x0079, 0x007c, 0x6820, 0xc095, 0x6822, + 0x82ff, 0x00c0, 0x360f, 0x1078, 0x410f, 0x0078, 0x3616, 0x8211, + 0x0040, 0x3614, 0x1078, 0x29ab, 0x1078, 0x4122, 0x781b, 0x0078, + 0x007c, 0x1078, 0x43ca, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x363c, + 0x017e, 0x3208, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x362e, 0xa18c, 0x0300, 0x0078, 0x3630, 0xa18c, 0x0400, + 0x017f, 0x0040, 0x3637, 0x0018, 0x363c, 0x0078, 0x3639, 0x0028, + 0x363c, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, + 0x0060, 0x00c0, 0x3649, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, + 0x36b8, 0xd6dc, 0x00c0, 0x3661, 0x68b4, 0xd0dc, 0x00c0, 0x3661, + 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x00c0, 0x365e, + 0x2200, 0xa105, 0x0040, 0x45cd, 0x704b, 0x0015, 0x0078, 0x45cd, + 0x007c, 0xd6ac, 0x0040, 0x3687, 0xd6f4, 0x0040, 0x366d, 0x682f, + 0x0000, 0x6833, 0x0000, 0x0078, 0x45cd, 0x68b4, 0xa084, 0x4000, + 0xa635, 0xd6f4, 0x00c0, 0x3667, 0x7048, 0xa005, 0x00c0, 0x367a, + 0x704b, 0x0015, 0xd6dc, 0x00c0, 0x3683, 0x68b4, 0xd0dc, 0x0040, + 0x3683, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0078, 0x45cd, 0xd6f4, + 0x0040, 0x3690, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x45cd, + 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x00c0, 0x368a, 0x7048, + 0xa005, 0x00c0, 0x369d, 0x704b, 0x0015, 0x2408, 0x2510, 0x2700, + 0x80fb, 0x00c8, 0x36a4, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, + 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x36b1, 0x0078, + 0x45cd, 0x7000, 0xa086, 0x0006, 0x0040, 0x36b8, 0x0078, 0x45cd, + 0x007c, 0x6946, 0x6008, 0xc0cd, 0xd3cc, 0x0040, 0x36c0, 0xc08d, + 0x600a, 0x6818, 0x683a, 0x681b, 0x0006, 0x688f, 0x0000, 0x6893, + 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, + 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, + 0x0079, 0x36da, 0x2a05, 0x36ec, 0x36e4, 0x36e2, 0x36e2, 0x36e2, + 0x36e2, 0x36e2, 0x1078, 0x29ab, 0x6820, 0xd084, 0x00c0, 0x36ec, + 0x1078, 0x3e10, 0x0078, 0x36f2, 0x705c, 0x2c50, 0x2060, 0x6800, + 0x6002, 0x2a60, 0x3208, 0xa18c, 0x0300, 0x0040, 0x36fb, 0x2021, + 0x4f58, 0x0078, 0x36fd, 0x2021, 0x4f98, 0x2404, 0xa005, 0x0040, + 0x3704, 0x2020, 0x0078, 0x36fd, 0x2d22, 0x206b, 0x0000, 0x007c, + 0x1078, 0x3e17, 0x1078, 0x3e2d, 0x6008, 0xc0cc, 0x600a, 0x682b, + 0x0000, 0x789b, 0x000e, 0x6f14, 0x6938, 0x691a, 0x6944, 0x6916, + 0x3208, 0xa18c, 0x0300, 0x0040, 0x3721, 0x2009, 0x0000, 0x0078, + 0x3723, 0x2009, 0x0001, 0x1078, 0x4a72, 0xd6dc, 0x0040, 0x372b, + 0x691c, 0xc1ed, 0x691e, 0x6818, 0xd0fc, 0x0040, 0x373a, 0x7868, + 0xa08c, 0x00ff, 0x0040, 0x3738, 0x681b, 0x001e, 0x0078, 0x373a, + 0x681b, 0x0000, 0xb284, 0x0300, 0x00c0, 0x3742, 0x2021, 0x4f98, + 0x0078, 0x3744, 0x2021, 0x4f58, 0x6800, 0x2022, 0x6a3c, 0x6940, + 0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, 0xd0a4, 0x0040, 0x3784, + 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x0d7e, 0x0f7e, + 0x157e, 0x147e, 0x2079, 0x4f00, 0x1078, 0x1e3f, 0x147f, 0x157f, + 0x0f7f, 0x70cc, 0x2010, 0x2009, 0x0101, 0x027e, 0x2204, 0xa06d, + 0x0040, 0x3774, 0x6814, 0xa706, 0x0040, 0x3771, 0x6800, 0x0078, + 0x3767, 0x6820, 0xc0d5, 0x6822, 0x027f, 0x8210, 0x8109, 0x00c0, + 0x3765, 0x0d7f, 0x7067, 0x0003, 0x707f, 0x0000, 0x7776, 0x7083, + 0x000f, 0x71d4, 0xc1dc, 0x71d6, 0x6818, 0xa086, 0x0002, 0x00c0, + 0x3790, 0x6817, 0x0000, 0x682b, 0x0000, 0x681c, 0xc0ec, 0x681e, + 0x1078, 0x206c, 0x0078, 0x2a05, 0x7cd8, 0x7ddc, 0x7fd0, 0x1078, + 0x363f, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, 0x43ce, + 0xa08c, 0x00ff, 0x6916, 0x6818, 0xd0fc, 0x0040, 0x37a9, 0x7048, + 0x681a, 0xa68c, 0xdf00, 0x691e, 0x7067, 0x0000, 0x0078, 0x2a05, + 0x7000, 0xa005, 0x00c0, 0x37b6, 0x0078, 0x2a05, 0xa006, 0x1078, + 0x45cd, 0x6920, 0xd1ac, 0x00c0, 0x37bf, 0x681b, 0x0014, 0xa68c, + 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, 0x6822, + 0x7000, 0x0079, 0x37cb, 0x2a05, 0x37d5, 0x37d5, 0x37d8, 0x37d8, + 0x37d8, 0x37d3, 0x37d3, 0x1078, 0x29ab, 0x6818, 0x0078, 0x343a, + 0x6008, 0xc0a4, 0x600a, 0x6817, 0x0000, 0x0078, 0x3dd5, 0x2300, + 0x0079, 0x37e2, 0x37e5, 0x37e7, 0x3857, 0x1078, 0x29ab, 0xd6fc, + 0x00c0, 0x383e, 0x7000, 0xa00d, 0x0079, 0x37ee, 0x2a05, 0x37f8, + 0x37f8, 0x3828, 0x37f8, 0x383b, 0x37f6, 0x37f6, 0x1078, 0x29ab, + 0xa684, 0x0060, 0x0040, 0x3828, 0xa086, 0x0060, 0x00c0, 0x3825, + 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x6eb6, 0x681c, 0xc0ac, 0x681e, + 0xa186, 0x0002, 0x0040, 0x3817, 0x1078, 0x45cd, 0x69ac, 0x68b0, + 0xa115, 0x0040, 0x3817, 0x1078, 0x4968, 0x0078, 0x3819, 0x1078, + 0x4930, 0x781b, 0x0079, 0x71d4, 0xd1b4, 0x00c0, 0x2a01, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x2a4b, 0x007c, 0xd6ec, 0x0040, 0x3802, + 0x6818, 0xd0fc, 0x0040, 0x383b, 0xd6f4, 0x00c0, 0x3835, 0x681b, + 0x0015, 0x781b, 0x0079, 0x0078, 0x2a01, 0x681b, 0x0007, 0x682f, + 0x0000, 0x6833, 0x0000, 0x1078, 0x4360, 0x007c, 0xc6fc, 0x7e5a, + 0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8, 0x3847, 0x8000, 0xa084, + 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, + 0x6b94, 0x2200, 0xa303, 0x68ae, 0x781b, 0x0079, 0x007c, 0x1078, + 0x29ab, 0x2300, 0x0079, 0x385c, 0x3861, 0x3886, 0x38e6, 0x1078, + 0x29ab, 0x7000, 0x0079, 0x3864, 0x386c, 0x386e, 0x3877, 0x386c, + 0x386c, 0x386c, 0x386c, 0x386c, 0x1078, 0x29ab, 0x69ac, 0x68b0, + 0xa115, 0x0040, 0x3877, 0x1078, 0x4968, 0x0078, 0x3879, 0x1078, + 0x4930, 0x681c, 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x00c0, 0x2a01, + 0x70a4, 0xa086, 0x0001, 0x00c0, 0x2a4b, 0x007c, 0xd6fc, 0x00c0, + 0x38d6, 0x7000, 0xa00d, 0x0079, 0x388d, 0x2a05, 0x389d, 0x3897, + 0x38cd, 0x389d, 0x38d3, 0x3895, 0x3895, 0x1078, 0x29ab, 0x6894, + 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0x0040, + 0x38cd, 0xa086, 0x0060, 0x00c0, 0x38ca, 0xa6b4, 0xbfbf, 0xc6ed, + 0x7e5a, 0x6eb6, 0xa186, 0x0002, 0x0040, 0x38b9, 0x1078, 0x45cd, + 0x69ac, 0x68b0, 0xa115, 0x0040, 0x38b9, 0x1078, 0x4968, 0x0078, + 0x38bb, 0x1078, 0x4930, 0x781b, 0x0079, 0x681c, 0xc0b4, 0x681e, + 0x71d4, 0xd1b4, 0x00c0, 0x2a01, 0x70a4, 0xa086, 0x0001, 0x00c0, + 0x2a4b, 0x007c, 0xd6ec, 0x0040, 0x38a7, 0x6818, 0xd0fc, 0x0040, + 0x38d3, 0x681b, 0x0007, 0x781b, 0x00f9, 0x007c, 0xc6fc, 0x7e5a, + 0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, + 0xa303, 0x68ae, 0x79d2, 0x781b, 0x0079, 0x007c, 0xd6dc, 0x0040, + 0x38ef, 0x782b, 0x3009, 0x781b, 0x0079, 0x0078, 0x2a01, 0x7884, + 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, 0x00c0, 0x3902, 0xa484, + 0x0200, 0x0040, 0x38fc, 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, 0x0079, + 0x0078, 0x2a01, 0x6820, 0xc095, 0x6822, 0x1078, 0x42d9, 0xc6dd, + 0x1078, 0x410f, 0x781b, 0x0078, 0x0078, 0x2a01, 0x2300, 0x0079, + 0x3911, 0x3914, 0x3916, 0x3918, 0x1078, 0x29ab, 0x0078, 0x4108, + 0xd6d4, 0x00c0, 0x3953, 0x79e4, 0xd1ac, 0x0040, 0x3926, 0x78ec, + 0xa084, 0x0003, 0x0040, 0x3926, 0x782b, 0x3009, 0x789b, 0x0060, + 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xd1ac, 0x0040, + 0x3936, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x394f, 0x2001, 0x4f04, + 0x2004, 0xd0e4, 0x00c0, 0x394b, 0x6820, 0xd0c4, 0x0040, 0x394b, + 0x0c7e, 0x7058, 0x2060, 0x6004, 0xc09d, 0x6006, 0x6008, 0xa084, + 0x00ff, 0x600a, 0x0c7f, 0x2001, 0x0014, 0x0078, 0x343a, 0xa184, + 0x0007, 0x0079, 0x3989, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, + 0x79a8, 0x81ff, 0x0040, 0x3987, 0x789b, 0x0010, 0x7ba8, 0xa384, + 0x0001, 0x00c0, 0x397a, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, + 0x396d, 0x2009, 0xfff7, 0x0078, 0x3973, 0xa386, 0x0003, 0x00c0, + 0x397a, 0x2009, 0xffef, 0x0c7e, 0x7058, 0x2060, 0x6004, 0xa104, + 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, + 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, + 0x4354, 0x30d0, 0x30da, 0x3993, 0x3999, 0x3991, 0x3991, 0x4354, + 0x4354, 0x1078, 0x29ab, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, + 0x435a, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x4354, 0x79e4, + 0xa184, 0x0030, 0x0040, 0x39a9, 0x78ec, 0xa084, 0x0003, 0x00c0, + 0x39dd, 0x7000, 0xa086, 0x0004, 0x00c0, 0x39c3, 0x7064, 0xa086, + 0x0002, 0x00c0, 0x39b9, 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, + 0x2f5c, 0x7064, 0xa086, 0x0006, 0x0040, 0x39b3, 0x7064, 0xa086, + 0x0004, 0x0040, 0x39b3, 0x7000, 0xa086, 0x0000, 0x0040, 0x2a01, + 0x6920, 0xa184, 0x0420, 0x0040, 0x39d2, 0xc1d4, 0x6922, 0x6818, + 0x0078, 0x343a, 0x6818, 0xa08e, 0x0002, 0x0040, 0x39db, 0xc0fd, + 0x681a, 0x2001, 0x0014, 0x0078, 0x343a, 0xa184, 0x0007, 0x0079, + 0x39e1, 0x4354, 0x4354, 0x39e9, 0x4354, 0x439c, 0x439c, 0x4354, + 0x4354, 0xd6bc, 0x0040, 0x3a2b, 0x7184, 0x81ff, 0x0040, 0x3a2b, + 0xa182, 0x000d, 0x00d0, 0x39f8, 0x7087, 0x0000, 0x0078, 0x39fd, + 0xa182, 0x000c, 0x7086, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, + 0x157e, 0x137e, 0x147e, 0x7088, 0x8114, 0xa210, 0x728a, 0xa080, + 0x000b, 0xad00, 0x2098, 0xb284, 0x0300, 0x0040, 0x3a1f, 0x007e, + 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x3a1b, 0x20a1, + 0x012b, 0x0078, 0x3a21, 0x20a1, 0x022b, 0x0078, 0x3a21, 0x20a1, + 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x147f, 0x137f, + 0x157f, 0x0078, 0x435a, 0xd6d4, 0x00c0, 0x3a7f, 0x6820, 0xd084, + 0x0040, 0x435a, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x3a3d, + 0xa086, 0x0060, 0x00c0, 0x3a3d, 0xc1f5, 0xc194, 0x795a, 0x69b6, + 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xc0fd, + 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x3e46, 0xa18c, 0x00f8, + 0x00c0, 0x3e46, 0x157e, 0x137e, 0x147e, 0x017e, 0x3208, 0xa18c, + 0x0300, 0x0040, 0x3a6b, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x3a67, 0x20a1, 0x012b, 0x0078, 0x3a6d, 0x20a1, + 0x022b, 0x0078, 0x3a6d, 0x20a1, 0x012b, 0x017f, 0x789b, 0x0000, + 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, + 0x157f, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x0078, 0x435a, 0x6818, + 0xd0fc, 0x0040, 0x3a85, 0x681b, 0x0008, 0x6820, 0xc0ad, 0x6822, + 0x1078, 0x4117, 0x781b, 0x00ea, 0x007c, 0x2300, 0x0079, 0x3a90, + 0x3a95, 0x3b6d, 0x3a93, 0x1078, 0x29ab, 0x7cd8, 0x7ddc, 0x7fd0, + 0x82ff, 0x00c0, 0x3abe, 0x7200, 0xa286, 0x0003, 0x0040, 0x3407, + 0x71d4, 0xd1bc, 0x00c0, 0x3ac1, 0xd1b4, 0x0040, 0x3ac1, 0x0d7e, + 0x783b, 0x8800, 0x781b, 0x004c, 0x70bc, 0xa06d, 0x68b4, 0xc0a5, + 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, + 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x0078, 0x3ac5, 0x7200, 0x0078, + 0x3ac5, 0x783b, 0x1800, 0x781b, 0x004a, 0xa284, 0x000f, 0x0079, + 0x3ac9, 0x3b58, 0x3b07, 0x3ad3, 0x3436, 0x3ad1, 0x3b58, 0x3ad1, + 0x3ad1, 0x1078, 0x29ab, 0x681c, 0xd0ec, 0x0040, 0x3ada, 0x6008, + 0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, 0x6800, 0x6006, 0xa005, + 0x00c0, 0x3ae3, 0x6002, 0x6008, 0xc0d4, 0x600a, 0x681c, 0xa084, + 0x000e, 0x00c0, 0x3af7, 0xb284, 0x0300, 0x0040, 0x3af3, 0x2009, + 0x95c0, 0x0078, 0x3afc, 0x2009, 0x96d0, 0x0078, 0x3afc, 0x7030, + 0x68ba, 0x7140, 0x70cc, 0xa108, 0x2104, 0x6802, 0x2d0a, 0x715e, + 0xd6dc, 0x00c0, 0x3b07, 0xc6fc, 0x6eb6, 0x0078, 0x3b58, 0x6eb6, + 0xa684, 0x0060, 0x00c0, 0x3b11, 0xa684, 0x7fff, 0x68b6, 0x0078, + 0x3b58, 0xd6dc, 0x00c0, 0x3b1f, 0xa684, 0x7fff, 0x68b6, 0x6894, + 0x68a6, 0x6898, 0x68aa, 0x1078, 0x45cd, 0x0078, 0x3b58, 0xd6ac, + 0x0040, 0x3b2b, 0xa006, 0x1078, 0x45cd, 0x2408, 0x2510, 0x69aa, + 0x6aa6, 0x0078, 0x3b3b, 0x2408, 0x2510, 0x2700, 0x801b, 0x00c8, + 0x3b32, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x69aa, + 0x6aa6, 0x1078, 0x45cd, 0xd6fc, 0x0040, 0x3b58, 0xa684, 0x7fff, + 0x68b6, 0x2510, 0x2408, 0xd6ac, 0x00c0, 0x3b50, 0x2700, 0x801b, + 0x00c8, 0x3b4b, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, + 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, + 0x7000, 0xa086, 0x0030, 0x00c0, 0x2a05, 0x7003, 0x0002, 0x70bc, + 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, + 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0xa586, 0x8800, 0x00c0, + 0x3b7a, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x0078, 0x4108, 0x7047, 0x0000, 0xa282, 0x0006, + 0x0050, 0x3b84, 0x1078, 0x29ab, 0x2300, 0x0079, 0x3b87, 0x3b8a, + 0x3b9c, 0x3ba8, 0x2200, 0x0079, 0x3b8d, 0x3b93, 0x4108, 0x3b95, + 0x3b93, 0x3be2, 0x3c37, 0x1078, 0x29ab, 0x7a80, 0xa294, 0x0f00, + 0x1078, 0x3cc1, 0x0078, 0x40fe, 0x1078, 0x3bb9, 0x0079, 0x3ba0, + 0x4108, 0x3ba6, 0x3ba6, 0x3be2, 0x3ba6, 0x4108, 0x1078, 0x29ab, + 0x1078, 0x3bb9, 0x0079, 0x3bac, 0x3bb4, 0x3bb2, 0x3bb2, 0x3bb4, + 0x3bb2, 0x3bb4, 0x1078, 0x29ab, 0x1078, 0x4122, 0x781b, 0x0078, + 0x007c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3bca, 0x1078, 0x3e2d, + 0x0078, 0x3bc4, 0x1078, 0x45cd, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x0078, 0x3bcf, 0x7000, 0xa086, 0x0003, 0x0040, 0x3bc2, 0x7003, + 0x0005, 0xb284, 0x0300, 0x0040, 0x3bd9, 0x2001, 0x96e0, 0x0078, + 0x3bdb, 0x2001, 0x9712, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, + 0x2200, 0x007c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3bf4, 0x70d4, + 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3bf9, + 0x1078, 0x45cd, 0x0078, 0x3bf9, 0x7000, 0xa086, 0x0003, 0x0040, + 0x3bf0, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, + 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x95c0, 0xb284, 0x0300, + 0x00c0, 0x3c0d, 0xc2fd, 0x2069, 0x96d0, 0x2d04, 0x2d08, 0x715e, + 0xa06d, 0x0040, 0x3c1a, 0x6814, 0xa206, 0x0040, 0x3c1c, 0x6800, + 0x0078, 0x3c0e, 0x1078, 0x3cc1, 0x6eb4, 0x7e5a, 0x6920, 0xa184, + 0x0c00, 0x0040, 0x3ceb, 0x7064, 0xa086, 0x0006, 0x00c0, 0x3c2e, + 0x7074, 0xa206, 0x00c0, 0x3c2e, 0x7066, 0x707e, 0x681b, 0x0005, + 0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x4117, 0x0078, 0x3ceb, 0x7200, + 0xa286, 0x0002, 0x00c0, 0x3c49, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, + 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3c4d, 0x1078, 0x45cd, 0x0078, + 0x3c4d, 0xa286, 0x0003, 0x0040, 0x3c45, 0x7003, 0x0001, 0x7a80, + 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, + 0xb284, 0x0300, 0x00c0, 0x3c5d, 0xc2fd, 0x79a8, 0x79a8, 0xa18c, + 0x00ff, 0x2118, 0x70cc, 0xa168, 0x2d04, 0x2d08, 0x715e, 0xa06d, + 0x0040, 0x3c71, 0x6814, 0xa206, 0x0040, 0x3c9a, 0x6800, 0x0078, + 0x3c65, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3c7b, 0x2001, + 0x96e0, 0x0078, 0x3c7d, 0x2001, 0x9712, 0x2068, 0x704e, 0x157e, + 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, 0x3c82, 0x157f, + 0xb284, 0x0300, 0x0040, 0x3c8f, 0xc2fc, 0x0078, 0x3c90, 0xc2fd, + 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, 0x0800, + 0x6827, 0x0003, 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x0040, 0x3ceb, + 0xd0dc, 0x0040, 0x3cb6, 0x7064, 0xa086, 0x0004, 0x00c0, 0x3cb2, + 0x7074, 0xa206, 0x00c0, 0x3cb2, 0x7078, 0xa306, 0x00c0, 0x3cb2, + 0x7066, 0x707e, 0x1078, 0x411e, 0x0078, 0x3ceb, 0x681b, 0x0005, + 0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x4117, 0x707f, 0x0000, 0x0078, + 0x3ceb, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3ccb, 0x2001, + 0x96e0, 0x0078, 0x3ccd, 0x2001, 0x9712, 0x2068, 0x704e, 0x157e, + 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, 0x3cd2, 0x157f, + 0xb284, 0x0300, 0x0040, 0x3cdf, 0xc2fc, 0x0078, 0x3ce0, 0xc2fd, + 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, 0x0800, + 0x6827, 0x0003, 0x007c, 0xc6ec, 0xa6ac, 0x0060, 0x0040, 0x3d3d, + 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x00c0, 0x3d18, 0x7bd2, + 0x7bda, 0x7cd6, 0x7cde, 0xa586, 0x0060, 0x0040, 0x3d42, 0xd6f4, + 0x00c0, 0x3d03, 0xc6ed, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0079, + 0xd69c, 0x0040, 0x3d10, 0x2009, 0x0078, 0x2019, 0x0000, 0x2320, + 0x791a, 0xd6ec, 0x0040, 0x3d4d, 0x1078, 0x4930, 0x0078, 0x3d4d, + 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040, 0x3d44, + 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x00c0, 0x3d29, + 0xc6ed, 0xc6f4, 0x7e5a, 0x2011, 0x0079, 0xd69c, 0x0040, 0x3d35, + 0x2011, 0x0078, 0x2019, 0x0000, 0x2320, 0x7a1a, 0xd6ec, 0x0040, + 0x3d4d, 0x1078, 0x4968, 0x0078, 0x3d4d, 0x2019, 0x0000, 0x2320, + 0x0078, 0x3d44, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0079, 0xd69c, + 0x0040, 0x3d4c, 0x2009, 0x0078, 0x791a, 0x68c0, 0x705a, 0x2d00, + 0x704e, 0x68c4, 0x2060, 0x71d4, 0x2001, 0x4f01, 0x2004, 0xd0c4, + 0x00c0, 0x3da2, 0x70d8, 0xa02d, 0x0040, 0x3d7b, 0xd1bc, 0x0040, + 0x3d95, 0x7a80, 0xa294, 0x0f00, 0x70dc, 0xa206, 0x0040, 0x3d6c, + 0x78e0, 0xa504, 0x00c0, 0x3da2, 0x70da, 0xc1bc, 0x71d6, 0x0078, + 0x3da2, 0x2031, 0x0001, 0x852c, 0x0048, 0x3d7a, 0x8633, 0x8210, + 0x0078, 0x3d73, 0x007c, 0x7de0, 0xa594, 0xff00, 0x0040, 0x3d88, + 0x2011, 0x0008, 0x852f, 0x1078, 0x3d71, 0x8637, 0x0078, 0x3d8a, + 0x1078, 0x3d71, 0x8217, 0x7880, 0xa084, 0x0f00, 0xa206, 0x0040, + 0x3da2, 0x72de, 0x76da, 0x0078, 0x3da2, 0x7a80, 0xa294, 0x0f00, + 0x70dc, 0xa236, 0x0040, 0x3d92, 0x78e0, 0xa534, 0x0040, 0x3d92, + 0xc1bd, 0x71d6, 0xd1b4, 0x00c0, 0x2a01, 0x2300, 0xa405, 0x0040, + 0x2a01, 0x70a4, 0xa086, 0x0001, 0x00c0, 0x2a4b, 0x007c, 0x6020, + 0xa005, 0x0040, 0x3dbd, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, + 0x600a, 0x700f, 0x0100, 0x702c, 0x6026, 0x007c, 0xa006, 0x1078, + 0x45cd, 0x7000, 0xa086, 0x0002, 0x0040, 0x3dcb, 0x7064, 0xa086, + 0x0005, 0x00c0, 0x3dd5, 0x682b, 0x0000, 0x6817, 0x0000, 0x681b, + 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, + 0x0079, 0x3dda, 0x2a05, 0x3dea, 0x3de4, 0x3e0c, 0x3df4, 0x2a05, + 0x3de2, 0x3de2, 0x1078, 0x29ab, 0x1078, 0x3e17, 0x1078, 0x3e10, + 0x0078, 0x3df0, 0x1078, 0x3e17, 0x705c, 0x2060, 0x6800, 0x6002, + 0x1078, 0x206c, 0x0078, 0x2a05, 0x7064, 0x7067, 0x0000, 0x7083, + 0x0000, 0x0079, 0x3dfb, 0x3e08, 0x3e08, 0x3e03, 0x3e03, 0x3e03, + 0x3e08, 0x3e03, 0x3e08, 0x77d4, 0xc7dd, 0x77d6, 0x0079, 0x2f75, + 0x7067, 0x0000, 0x0078, 0x2a05, 0x681b, 0x0000, 0x0078, 0x3708, + 0x6800, 0xa005, 0x00c0, 0x3e15, 0x6002, 0x6006, 0x007c, 0x6410, + 0x84ff, 0x0040, 0x3e29, 0x2009, 0x4f02, 0x2104, 0x8001, 0x200a, + 0x8421, 0x6412, 0x00c0, 0x3e29, 0x2021, 0x4f04, 0x2404, 0xc0a5, + 0x2022, 0x6008, 0xc0a4, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, + 0x3e33, 0x8001, 0x601a, 0x007c, 0x1078, 0x43ca, 0x681b, 0x0018, + 0x0078, 0x3e74, 0x1078, 0x43ca, 0x681b, 0x0019, 0x0078, 0x3e74, + 0x1078, 0x43ca, 0x681b, 0x001a, 0x0078, 0x3e74, 0x1078, 0x43ca, + 0x681b, 0x0003, 0x0078, 0x3e74, 0x7774, 0x1078, 0x4245, 0x7178, + 0xa18c, 0x00ff, 0x3210, 0xa294, 0x0300, 0x0040, 0x3e5b, 0xa1e8, + 0x94c0, 0x0078, 0x3e5d, 0xa1e8, 0x95d0, 0x2d04, 0x2d08, 0x2068, + 0xa005, 0x00c0, 0x3e66, 0x707e, 0x0078, 0x2a05, 0x6814, 0x7274, + 0xa206, 0x0040, 0x3e6e, 0x6800, 0x0078, 0x3e5e, 0x6800, 0x200a, + 0x681b, 0x0005, 0x707f, 0x0000, 0x1078, 0x3e17, 0x6820, 0xd084, + 0x00c0, 0x3e7c, 0x1078, 0x3e10, 0x1078, 0x3e2d, 0x681f, 0x0000, + 0x6823, 0x0020, 0x1078, 0x206c, 0x0078, 0x2a05, 0xa282, 0x0003, + 0x00c0, 0x40fe, 0x7da8, 0xa5ac, 0x00ff, 0x7e5a, 0x7ea8, 0xa6b4, + 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1c4, 0x0040, 0x3ee1, 0xc1c4, + 0x6922, 0xa6b4, 0x00ff, 0x0040, 0x3ece, 0xa682, 0x000c, 0x0048, + 0x3ea5, 0x0040, 0x3ea5, 0x2031, 0x000c, 0x2500, 0xa086, 0x000a, + 0x0040, 0x3eac, 0x852b, 0x852b, 0x1078, 0x41d7, 0x0040, 0x3eb4, + 0x1078, 0x3fb3, 0x0078, 0x3ed7, 0x1078, 0x4192, 0x0c7e, 0x2960, + 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x3fe9, 0x0c7f, 0x6920, + 0xc1c5, 0x6922, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3ecb, + 0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x0c7e, 0x2960, + 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x3fe9, 0x0c7f, 0x7e58, + 0xd6d4, 0x00c0, 0x3ede, 0x781b, 0x0067, 0x007c, 0x781b, 0x0079, + 0x007c, 0x0c7e, 0x7058, 0x2060, 0x6100, 0xd1e4, 0x0040, 0x3f2a, + 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x3ef4, + 0x0040, 0x3ef4, 0x2011, 0x000c, 0x2600, 0xa202, 0x00c8, 0x3ef9, + 0x2230, 0x6208, 0xa294, 0x00ff, 0x2001, 0x4f05, 0x2004, 0xd0e4, + 0x00c0, 0x3f0e, 0x78ec, 0xd0e4, 0x0040, 0x3f0e, 0xa282, 0x000a, + 0x00c8, 0x3f14, 0x2011, 0x000a, 0x0078, 0x3f14, 0xa282, 0x000c, + 0x00c8, 0x3f14, 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8, 0x3f19, + 0x2228, 0x1078, 0x4196, 0x2500, 0xa086, 0x000a, 0x0040, 0x3f22, + 0x852b, 0x852b, 0x1078, 0x41d7, 0x0040, 0x3f2a, 0x1078, 0x3fb3, + 0x0078, 0x3f2e, 0x1078, 0x4192, 0x1078, 0x3fe9, 0x7858, 0xc095, + 0x785a, 0x0c7f, 0x781b, 0x0078, 0x007c, 0x0c7e, 0x2960, 0x6000, + 0xd0e4, 0x00c0, 0x3f4f, 0xd0b4, 0x00c0, 0x3f49, 0x6010, 0xa084, + 0x000f, 0x00c0, 0x3f49, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f, + 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3f7a, 0x68a0, + 0xd0cc, 0x00c0, 0x3f49, 0x6208, 0xa294, 0x00ff, 0x2001, 0x4f05, + 0x2004, 0xd0e4, 0x00c0, 0x3f68, 0x78ec, 0xd0e4, 0x0040, 0x3f68, + 0xa282, 0x000b, 0x00c8, 0x3f68, 0x2011, 0x000a, 0x0078, 0x3f6e, + 0xa282, 0x000c, 0x00c8, 0x3f6e, 0x2011, 0x000c, 0x6308, 0x831f, + 0xa39c, 0x00ff, 0xa382, 0x000c, 0x0048, 0x3f7a, 0x0040, 0x3f7a, + 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, + 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x70d4, + 0xd0b4, 0x0040, 0x3f96, 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, + 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, + 0x0c7e, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, + 0x2019, 0x0000, 0x0078, 0x3fa4, 0x78ab, 0x0001, 0x78ab, 0x0003, + 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, + 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7158, 0x2160, 0x2018, 0xa08c, + 0x0020, 0x0040, 0x3fbc, 0xc0ac, 0x2008, 0xa084, 0xfff0, 0xa635, + 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, 0xfff0, + 0xa18c, 0x000f, 0xa105, 0xc0f4, 0xa39c, 0x0020, 0x0040, 0x3fd2, + 0xa085, 0x4000, 0xc0fc, 0xd0b4, 0x00c0, 0x3fd7, 0xc0fd, 0x78a6, + 0x6016, 0x788a, 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, 0xa084, + 0x00ff, 0xa605, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, + 0x007c, 0x0c7e, 0x7058, 0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, + 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, 0x600c, + 0xa084, 0x00ff, 0x600e, 0x0c7f, 0x007c, 0xa282, 0x0002, 0x00c0, + 0x40fe, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0040, 0x4038, + 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, 0x40fe, + 0x1078, 0x408b, 0x1078, 0x3fe9, 0xa980, 0x0001, 0x200c, 0x1078, + 0x4241, 0x1078, 0x3f35, 0x88ff, 0x0040, 0x402e, 0x789b, 0x0060, + 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x402b, + 0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7e58, 0xd6d4, + 0x00c0, 0x4035, 0x781b, 0x0067, 0x007c, 0x781b, 0x0079, 0x007c, + 0xa282, 0x0002, 0x00c8, 0x4040, 0xa284, 0x0001, 0x0040, 0x4049, + 0x7158, 0xa188, 0x0000, 0x210c, 0xd1ec, 0x00c0, 0x4049, 0x2011, + 0x0000, 0x1078, 0x4173, 0x1078, 0x408b, 0x1078, 0x3fe9, 0x7858, + 0xc095, 0x785a, 0x781b, 0x0078, 0x007c, 0x0c7e, 0x027e, 0x2960, + 0x6000, 0x2011, 0x0001, 0xd0ec, 0x00c0, 0x406c, 0xd0bc, 0x00c0, + 0x406a, 0x6014, 0xd0b4, 0x00c0, 0x406a, 0xc1a4, 0x6106, 0xa006, + 0x0078, 0x4088, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, + 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x70d4, 0xd0b4, 0x0040, + 0x4084, 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x6018, 0x8001, 0x601a, 0x6820, 0xa085, 0x0200, 0x6822, + 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x82ff, 0x0040, + 0x4093, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, + 0xa084, 0xffbf, 0xa205, 0xc0fc, 0xd0b4, 0x00c0, 0x40a0, 0xc0fd, + 0x78a6, 0x6016, 0x788a, 0x6004, 0xc0a4, 0x6006, 0x0c7f, 0x007c, + 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x40b1, 0x007f, 0x0078, + 0x40b4, 0x007f, 0x0078, 0x40fb, 0xd6ac, 0x0040, 0x40fb, 0x7888, + 0xa084, 0x0040, 0x0040, 0x40fb, 0x7bb8, 0xa384, 0x003f, 0x831b, + 0x00c8, 0x40c3, 0x8000, 0xa005, 0x0040, 0x40d8, 0x831b, 0x00c8, + 0x40cc, 0x8001, 0x0040, 0x40f8, 0xd6f4, 0x0040, 0x40d8, 0x78b8, + 0x801b, 0x00c8, 0x40d4, 0x8000, 0xa084, 0x003f, 0x00c0, 0x40f8, + 0xc6f4, 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, + 0x40e3, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, + 0x4a35, 0x781b, 0x0076, 0xb284, 0x0300, 0x0040, 0x40f3, 0x2001, + 0x0000, 0x0078, 0x40f5, 0x2001, 0x0001, 0x1078, 0x48bf, 0x007c, + 0x781b, 0x0076, 0x007c, 0x781b, 0x0079, 0x007c, 0x1078, 0x4126, + 0x781b, 0x0078, 0x007c, 0x1078, 0x410f, 0x781b, 0x0078, 0x007c, + 0x6827, 0x0002, 0x1078, 0x4117, 0x781b, 0x0078, 0x007c, 0x2001, + 0x0005, 0x0078, 0x4128, 0x2001, 0x000c, 0x0078, 0x4128, 0x6820, + 0xc0d5, 0x6822, 0x2001, 0x0006, 0x0078, 0x4128, 0x2001, 0x000d, + 0x0078, 0x4128, 0x2001, 0x0009, 0x0078, 0x4128, 0x2001, 0x0007, + 0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, 0x70d4, 0xd0b4, 0x0040, + 0x413e, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x077e, + 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0x017e, 0xb28c, + 0x0300, 0x0040, 0x414f, 0xa0e0, 0x53c0, 0x0078, 0x4151, 0xa0e0, + 0x5440, 0x017f, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, + 0x0040, 0x4161, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xc09d, + 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, 0x0040, + 0x4171, 0xa184, 0xffbf, 0xc0fd, 0x78a6, 0x6016, 0x6004, 0xc0a5, + 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, + 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, + 0x70d4, 0xd0b4, 0x0040, 0x4191, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, + 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, + 0x789b, 0x0060, 0x78ab, 0x0005, 0x70d4, 0xd0b4, 0x0040, 0x41b5, + 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x157e, 0x8007, + 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, + 0xa18c, 0xfff0, 0x2021, 0x422a, 0x2019, 0x0011, 0x20a9, 0x000e, + 0x2011, 0x0032, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x41d5, + 0x8420, 0x2300, 0xa210, 0x00f0, 0x41ca, 0x157f, 0x007c, 0x157e, + 0x2001, 0x4f05, 0x2004, 0xd0e4, 0x00c0, 0x4208, 0x2021, 0x4238, + 0x20a9, 0x0009, 0x2011, 0x0028, 0xa582, 0x0019, 0x0040, 0x421e, + 0x0048, 0x421e, 0x8420, 0x95a9, 0x2011, 0x0032, 0xa582, 0x0032, + 0x0040, 0x421e, 0x0048, 0x421e, 0x8420, 0x95a9, 0x2019, 0x000a, + 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x421e, 0x0048, 0x421e, + 0x8420, 0x2300, 0xa210, 0x00f0, 0x41fa, 0x157f, 0x0078, 0x421c, + 0x2021, 0x422a, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, + 0x2200, 0xa502, 0x0040, 0x421e, 0x0048, 0x421e, 0x8420, 0x2300, + 0xa210, 0x00f0, 0x4210, 0x157f, 0xa006, 0x007c, 0x157f, 0xa582, + 0x0064, 0x00c8, 0x4227, 0x7808, 0xa085, 0x0070, 0x780a, 0x2404, + 0xa005, 0x007c, 0x1209, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, + 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, 0x0e07, + 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06, 0x7c07, 0x7e07, + 0x0e00, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800b, + 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xd7fc, + 0x0040, 0x4256, 0xa0e0, 0x74c0, 0x0078, 0x4258, 0xa0e0, 0x54c0, + 0x007c, 0x0e7e, 0x0f7e, 0xd084, 0x0040, 0x4266, 0x2079, 0x0100, + 0x2009, 0x4f80, 0x2071, 0x4f80, 0x0078, 0x4276, 0x2009, 0x4f40, + 0x2071, 0x4f40, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x0040, 0x4274, + 0x2079, 0x0100, 0x0078, 0x4276, 0x2079, 0x0200, 0x2091, 0x8000, + 0x2104, 0xa084, 0x000f, 0x0079, 0x427d, 0x4287, 0x4287, 0x4287, + 0x4287, 0x4287, 0x4287, 0x4285, 0x4285, 0x1078, 0x29ab, 0x69b4, + 0xc1f5, 0xa18c, 0xff9f, 0x69b6, 0xa005, 0x0040, 0x42d6, 0x7858, + 0xa084, 0xff9f, 0xa085, 0x6000, 0x785a, 0x7828, 0xa086, 0x1814, + 0x00c0, 0x42d6, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, 0x00c0, + 0x429c, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0, 0x42a3, + 0x7830, 0xd0bc, 0x00c0, 0x42d6, 0x007e, 0x2001, 0x4f04, 0x2004, + 0xd0ec, 0x007f, 0x0040, 0x42b8, 0xb284, 0x0300, 0x0078, 0x42ba, + 0xb284, 0x0400, 0x0040, 0x42c0, 0x0018, 0x42d6, 0x0078, 0x42c2, + 0x0028, 0x42d6, 0x79e4, 0xa184, 0x0030, 0x0040, 0x42d6, 0x78ec, + 0xa084, 0x0003, 0x0040, 0x42d6, 0x681c, 0xd0ac, 0x00c0, 0x42d4, + 0x1078, 0x4360, 0x0078, 0x42d6, 0x781b, 0x00f9, 0x0f7f, 0x0e7f, + 0x007c, 0x0c7e, 0x2001, 0x4f01, 0x2004, 0xd0ac, 0x00c0, 0x4352, + 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xb28c, + 0x0300, 0x0040, 0x42ef, 0xa0e0, 0x53c0, 0x0078, 0x42f1, 0xa0e0, + 0x5440, 0x6004, 0xa084, 0x000a, 0x00c0, 0x4352, 0x6108, 0xa194, + 0xff00, 0x0040, 0x4352, 0xa18c, 0x00ff, 0x2001, 0x000a, 0xa106, + 0x0040, 0x431d, 0x2001, 0x000c, 0xa106, 0x0040, 0x4321, 0x2001, + 0x0012, 0xa106, 0x0040, 0x4325, 0x2001, 0x0014, 0xa106, 0x0040, + 0x4329, 0x2001, 0x0019, 0xa106, 0x0040, 0x432d, 0x2001, 0x0032, + 0xa106, 0x0040, 0x4331, 0x0078, 0x4335, 0x2009, 0x000c, 0x0078, + 0x4337, 0x2009, 0x0012, 0x0078, 0x4337, 0x2009, 0x0014, 0x0078, + 0x4337, 0x2009, 0x0019, 0x0078, 0x4337, 0x2009, 0x0020, 0x0078, + 0x4337, 0x2009, 0x003f, 0x0078, 0x4337, 0x2011, 0x0000, 0x2100, + 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x2061, 0x4f00, + 0x6004, 0xd0bc, 0x0040, 0x4352, 0x6814, 0xd0fc, 0x00c0, 0x434d, + 0x60ea, 0x2061, 0x4f40, 0x0078, 0x4350, 0x60ee, 0x2061, 0x4f80, + 0x601f, 0x800f, 0x0c7f, 0x007c, 0x781b, 0x0079, 0x007c, 0x781b, + 0x0078, 0x007c, 0x781b, 0x0067, 0x007c, 0x781b, 0x0064, 0x007c, + 0x2009, 0x4f19, 0x210c, 0xa186, 0x0000, 0x0040, 0x4372, 0xa186, + 0x0001, 0x0040, 0x4375, 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, + 0x0047, 0x007c, 0x781b, 0x00f0, 0x007c, 0x701f, 0x000a, 0x007c, + 0x2009, 0x4f19, 0x210c, 0xa186, 0x0000, 0x0040, 0x438d, 0xa186, + 0x0001, 0x0040, 0x438a, 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, + 0x0047, 0x007c, 0x701f, 0x000a, 0x007c, 0x781b, 0x00ef, 0x007c, + 0x781b, 0x00f9, 0x007c, 0x781b, 0x00f8, 0x007c, 0x781b, 0x00c9, + 0x007c, 0x781b, 0x00c8, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x43a2, + 0x681b, 0x001d, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, 0x7830, + 0xa084, 0x00c0, 0x00c0, 0x43c9, 0x7808, 0xc08c, 0x780a, 0x0005, + 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x00c0, 0x43c6, + 0x2001, 0x4f05, 0x2004, 0xd0e4, 0x00c0, 0x43c4, 0x7804, 0xa084, + 0xff1f, 0xa085, 0x00e0, 0x7806, 0xa006, 0x007c, 0x7808, 0xc08d, + 0x780a, 0x007c, 0x7808, 0xc08d, 0x780a, 0x007c, 0x7830, 0xa084, + 0x0040, 0x00c0, 0x43ce, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x0040, + 0x43dd, 0xb284, 0x0300, 0x0078, 0x43df, 0xb284, 0x0400, 0x0040, + 0x43e5, 0x0098, 0x43e9, 0x0078, 0x43e7, 0x00a8, 0x43e9, 0x78ac, + 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, + 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x440c, 0x007e, 0x2001, + 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x4402, 0xb284, 0x0300, + 0x0078, 0x4404, 0xb284, 0x0400, 0x0040, 0x440a, 0x0098, 0x4406, + 0x0078, 0x440c, 0x00a8, 0x440a, 0x78ac, 0x007e, 0x7808, 0xa085, + 0x0002, 0x780a, 0x007f, 0x007c, 0xa784, 0x0001, 0x00c0, 0x37b0, + 0xa784, 0x0070, 0x0040, 0x4424, 0x0c7e, 0x2d60, 0x2f68, 0x1078, + 0x291f, 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x4431, + 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x37b0, 0x0078, + 0x4354, 0xa784, 0x0004, 0x0040, 0x4460, 0x78b8, 0xa084, 0x4001, + 0x0040, 0x4460, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, + 0x37b0, 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x4460, + 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00f9, 0x007c, + 0x784b, 0x0008, 0x6818, 0xd0fc, 0x0040, 0x445d, 0x681b, 0x0015, + 0xd6f4, 0x0040, 0x445d, 0x681b, 0x0007, 0x1078, 0x4360, 0x007c, + 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, + 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, + 0x30a6, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x447d, 0xb284, 0x0300, 0x0078, 0x447f, 0xb284, 0x0400, 0x0040, + 0x4485, 0x0018, 0x2a01, 0x0078, 0x4487, 0x0028, 0x2a01, 0x0078, + 0x4103, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xd3fc, 0x0040, 0x4497, 0xa080, 0x5440, 0x0078, 0x4499, 0xa080, + 0x53c0, 0x2060, 0x2048, 0x705a, 0x2a60, 0x007c, 0x0020, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0062, 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x9914, + 0x98fd, 0x0014, 0x0014, 0x0080, 0x00ff, 0x0100, 0x0402, 0x2008, + 0xf880, 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0x2500, + 0x0013, 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0xa200, 0x3806, 0x7102, 0x805f, 0x9481, 0x8839, 0x20c4, 0x0864, + 0xa856, 0x3008, 0x28c1, 0x9d1b, 0xa201, 0x300c, 0x2847, 0x8161, + 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9ccb, + 0xa8f3, 0x0864, 0xa844, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9ccb, + 0x2021, 0xa81d, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, 0x6fc0, + 0x63a4, 0x6c80, 0x0212, 0xa205, 0x883d, 0x7942, 0x8020, 0xa4a1, + 0x882b, 0x1814, 0x883b, 0x80df, 0x94a1, 0x7027, 0x85f2, 0xa737, + 0xa532, 0xf003, 0x8576, 0x8677, 0xa816, 0x883e, 0xa814, 0x2001, + 0xa812, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x7942, 0x8020, + 0xa4a1, 0x1814, 0x80df, 0x94a1, 0x883b, 0x7023, 0x8576, 0x8677, + 0xa802, 0x7861, 0x883e, 0x206b, 0x28c1, 0x9d1b, 0x2044, 0x2103, + 0x20a2, 0x2081, 0xa8c3, 0xa207, 0x0904, 0xa20e, 0xa809, 0xa203, + 0x8000, 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, + 0x856e, 0x866f, 0x7161, 0x0014, 0x0704, 0x3008, 0x9ccb, 0x0014, + 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, + 0x883f, 0x08e6, 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, 0xf881, + 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, + 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, + 0x8000, 0x284a, 0x1011, 0xa8fc, 0x3008, 0x9d33, 0x8000, 0xa000, + 0x2802, 0x1011, 0xa8fd, 0x9d39, 0xa8bd, 0x3008, 0x9d33, 0x283b, + 0x1011, 0xa8fd, 0xa209, 0x7102, 0x805f, 0x9481, 0x0017, 0x300c, + 0xa209, 0x8000, 0x85a4, 0x1de2, 0xa209, 0xdac1, 0x0014, 0x0210, + 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, 0x18f2, + 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d25, 0x0704, + 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, + 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, 0x3008, + 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, 0x0016, + 0x7944, 0x8421, 0xa020, 0xa532, 0x84a1, 0x0016, 0x7944, 0x8421, + 0xa0df, 0x9532, 0x84a1, 0x0016, 0x0000, 0x127e, 0x70d4, 0xa084, + 0x4600, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205, 0x00c0, + 0x45f3, 0x720c, 0x82ff, 0x0040, 0x45e4, 0x8aff, 0x00c0, 0x45f3, + 0x7200, 0xd284, 0x00c0, 0x45f3, 0x7804, 0xd0cc, 0x0040, 0x45ea, + 0x1078, 0x4abd, 0x7023, 0x0000, 0x7027, 0x0000, 0x7003, 0x0008, + 0x127f, 0x2000, 0x007c, 0x7000, 0xa084, 0x0003, 0x7002, 0xc69c, + 0xd084, 0x0040, 0x464c, 0x7108, 0x0005, 0x7008, 0xa106, 0x00c0, + 0x45fb, 0xa184, 0x0003, 0x0040, 0x467d, 0xa184, 0x01e0, 0x00c0, + 0x467d, 0xd1f4, 0x00c0, 0x45fb, 0xa184, 0x3000, 0xa086, 0x1000, + 0x0040, 0x45fb, 0x2001, 0x4f05, 0x2004, 0xd0e4, 0x0040, 0x4628, + 0x2011, 0x0180, 0x710c, 0x8211, 0x0040, 0x4636, 0x7008, 0xd0f4, + 0x00c0, 0x45fb, 0x700c, 0xa106, 0x0040, 0x461b, 0x0078, 0x4618, + 0x2011, 0x0180, 0x710c, 0x8211, 0x0040, 0x4636, 0x7008, 0xd0f4, + 0x00c0, 0x45fb, 0x700c, 0xa106, 0x0040, 0x462b, 0x7007, 0x0012, + 0x7108, 0x0005, 0x7008, 0xa106, 0x00c0, 0x4638, 0xa184, 0x0003, + 0x0040, 0x467d, 0xd194, 0x0040, 0x4638, 0xd1f4, 0x0040, 0x467d, + 0x7007, 0x0002, 0x0078, 0x45fb, 0x7108, 0xd1fc, 0x0040, 0x4657, + 0x1078, 0x47de, 0x8aff, 0x0040, 0x45d3, 0x0078, 0x464c, 0x700c, + 0xa08c, 0x03ff, 0x0040, 0x4682, 0x7004, 0xd084, 0x0040, 0x4674, + 0x7014, 0xa005, 0x00c0, 0x4670, 0x7010, 0x7310, 0xa306, 0x00c0, + 0x4664, 0x2300, 0xa005, 0x0040, 0x4674, 0xa102, 0x00c8, 0x464c, + 0x7007, 0x0010, 0x0078, 0x467d, 0x8aff, 0x0040, 0x4682, 0x1078, + 0x49e3, 0x00c0, 0x4677, 0x0040, 0x464c, 0x1078, 0x4729, 0x127f, + 0x2000, 0x007c, 0x7204, 0x7108, 0xc19c, 0x8103, 0x00c8, 0x4691, + 0x7007, 0x0002, 0x0078, 0x4682, 0x7003, 0x0008, 0x127f, 0x2000, + 0x007c, 0xa205, 0x00c0, 0x467d, 0x7023, 0x0000, 0x7027, 0x0000, + 0x7003, 0x0008, 0x007e, 0x2001, 0x4f01, 0x2004, 0xd0cc, 0x0040, + 0x46a3, 0x1078, 0x4abd, 0x007f, 0x127f, 0x2000, 0x007c, 0x6428, + 0x84ff, 0x0040, 0x46d3, 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8, + 0x46e3, 0x273c, 0x87fb, 0x00c0, 0x46c1, 0x0048, 0x46b9, 0x1078, + 0x29ab, 0x609c, 0xa075, 0x0040, 0x46d3, 0x0078, 0x46ac, 0x2039, + 0x46d8, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, + 0x0040, 0x46d3, 0x8738, 0x2704, 0xa005, 0x00c0, 0x46c2, 0x709c, + 0xa075, 0x00c0, 0x46ac, 0x007c, 0x0000, 0x0005, 0x0009, 0x000d, + 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, + 0x0015, 0x001b, 0x0000, 0x0000, 0x46d8, 0x46d5, 0x0000, 0x0000, + 0x8000, 0x0000, 0x46d8, 0x0000, 0x46e0, 0x46dd, 0x0000, 0x0000, + 0x0000, 0x0000, 0x46e0, 0x0000, 0x46db, 0x46db, 0x0000, 0x0000, + 0x8000, 0x0000, 0x46db, 0x0000, 0x46e1, 0x46e1, 0x0000, 0x0000, + 0x0000, 0x0000, 0x46e1, 0x2079, 0x4f00, 0x2071, 0x0010, 0x7007, + 0x000a, 0x7007, 0x0002, 0x7003, 0x0001, 0x7810, 0xd0ec, 0x0040, + 0x4717, 0x2009, 0x0001, 0x2071, 0x0020, 0x0078, 0x471b, 0x2009, + 0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, + 0x0000, 0x8109, 0x0040, 0x4728, 0x2071, 0x0020, 0x0078, 0x471b, + 0x007c, 0x7004, 0x8004, 0x00c8, 0x47b2, 0x7108, 0x7008, 0xa106, + 0x00c0, 0x472d, 0xa184, 0x01e0, 0x0040, 0x473a, 0x1078, 0x4821, + 0x0078, 0x47da, 0x7007, 0x0012, 0x2019, 0x0000, 0x7108, 0x7008, + 0xa106, 0x00c0, 0x473e, 0xa184, 0x01e0, 0x0040, 0x474b, 0x1078, + 0x4821, 0x0078, 0x47da, 0x7810, 0xd0ec, 0x0040, 0x4765, 0x2001, + 0x04fd, 0x2004, 0xa086, 0x0003, 0x00c0, 0x4769, 0xa184, 0x4000, + 0x0040, 0x476d, 0xa382, 0x0003, 0x00c8, 0x476d, 0xa184, 0x0004, + 0x0040, 0x473e, 0x8318, 0x0078, 0x473e, 0x7814, 0xd0ec, 0x00c0, + 0x476d, 0xa184, 0x4000, 0x00c0, 0x473e, 0xa19c, 0x300c, 0xa386, + 0x2004, 0x0040, 0x478a, 0xa386, 0x0008, 0x0040, 0x4795, 0x7004, + 0xd084, 0x00c0, 0x4786, 0x7108, 0x7008, 0xa106, 0x00c0, 0x477b, + 0xa184, 0x0003, 0x0040, 0x4786, 0x0078, 0x4821, 0xa386, 0x200c, + 0x00c0, 0x473e, 0x7200, 0x8204, 0x0048, 0x4795, 0x730c, 0xa384, + 0x03ff, 0x0040, 0x4795, 0x1078, 0x29ab, 0x7108, 0x7008, 0xa106, + 0x00c0, 0x4795, 0xa184, 0x01e0, 0x0040, 0x47a2, 0x1078, 0x4821, + 0x0078, 0x47da, 0x7007, 0x0012, 0x7000, 0xd084, 0x00c0, 0x47b2, + 0x7310, 0x7014, 0xa305, 0x0040, 0x47b2, 0x710c, 0xa184, 0x03ff, + 0x00c0, 0x4729, 0x7108, 0x7008, 0xa106, 0x00c0, 0x47b2, 0xa184, + 0x01e0, 0x0040, 0x47bf, 0x1078, 0x4821, 0x0078, 0x47da, 0x7007, + 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x47c3, 0x7108, + 0x7008, 0xa106, 0x00c0, 0x47c7, 0xa184, 0x01e0, 0x0040, 0x47d4, + 0x1078, 0x4821, 0x0078, 0x47da, 0x7007, 0x0012, 0x7108, 0x8103, + 0x0048, 0x47c7, 0x7003, 0x0008, 0x007c, 0x7108, 0xa184, 0x01e0, + 0x00c0, 0x4821, 0x7108, 0xa184, 0x01e0, 0x00c0, 0x4821, 0xa184, + 0x0007, 0x0079, 0x47eb, 0x47f5, 0x4805, 0x47f3, 0x4805, 0x47f3, + 0x4863, 0x47f3, 0x4861, 0x1078, 0x29ab, 0x7004, 0xa084, 0x0010, + 0xc08d, 0x7006, 0x8aff, 0x00c0, 0x4800, 0x2049, 0x0000, 0x007c, + 0x1078, 0x49e3, 0x00c0, 0x4800, 0x007c, 0x7004, 0xa084, 0x0010, + 0xc08d, 0x7006, 0x7004, 0xd084, 0x00c0, 0x4819, 0x7108, 0x7008, + 0xa106, 0x00c0, 0x480e, 0xa184, 0x0003, 0x0040, 0x4819, 0x0078, + 0x4821, 0x8aff, 0x0040, 0x4820, 0x1078, 0x49e3, 0x00c0, 0x481c, + 0x007c, 0x7007, 0x0012, 0x7108, 0x00e0, 0x4824, 0x2091, 0x6000, + 0x00e0, 0x4828, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, + 0x7004, 0xd09c, 0x00c0, 0x4830, 0x7007, 0x0012, 0x7108, 0xd1fc, + 0x00c0, 0x4834, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, 0x4848, + 0x7004, 0xa005, 0x00c0, 0x4848, 0x700c, 0xa005, 0x0040, 0x484a, + 0x0078, 0x482c, 0x2049, 0x0000, 0xb284, 0x0100, 0x0040, 0x4854, + 0x2001, 0x0000, 0x0078, 0x4856, 0x2001, 0x0001, 0x1078, 0x4259, + 0x681b, 0x0002, 0x2051, 0x0000, 0x007c, 0x1078, 0x29ab, 0x1078, + 0x29ab, 0x1078, 0x48aa, 0x7210, 0x7114, 0x700c, 0xa09c, 0x03ff, + 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x48aa, 0x2704, + 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, + 0x2400, 0xa305, 0x0040, 0x4886, 0x00c8, 0x4886, 0x8412, 0x8210, + 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x486d, 0x2b60, 0x8a07, + 0x007e, 0x6004, 0xd09c, 0x0040, 0x4891, 0xa7ba, 0x46dd, 0x0078, + 0x4893, 0xa7ba, 0x46d5, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, + 0x6c92, 0x6b8e, 0x7108, 0x7008, 0xa106, 0x00c0, 0x489a, 0xa184, + 0x01e0, 0x0040, 0x48a5, 0x1078, 0x4821, 0x7007, 0x0012, 0x1078, + 0x4729, 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x48be, + 0x6000, 0xa064, 0x00c0, 0x48b5, 0x2d60, 0x6004, 0xa084, 0x000f, + 0xa080, 0x46f3, 0x203c, 0x87fb, 0x1040, 0x29ab, 0x007c, 0x127e, + 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x6884, + 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, + 0x00ff, 0x007e, 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x48dc, + 0xa0b8, 0x46dd, 0x0078, 0x48de, 0xa0b8, 0x46d5, 0xb284, 0x0100, + 0x0040, 0x48e5, 0x7e20, 0x0078, 0x48e6, 0x7e24, 0xa6b5, 0x000c, + 0x681c, 0xd0b4, 0x0040, 0x48ed, 0xc685, 0x2400, 0xa305, 0x0040, + 0x4916, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, + 0x6004, 0xa301, 0x701e, 0xd19c, 0x0040, 0x4906, 0x6010, 0xa081, + 0x0000, 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, + 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, + 0x0001, 0x2b60, 0x1078, 0x4a0d, 0x0078, 0x4918, 0x1078, 0x49e3, + 0x00c0, 0x4916, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4, + 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7007, 0x0004, 0x7004, + 0xd094, 0x00c0, 0x4927, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, + 0x127e, 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x007e, 0x2090, + 0x007f, 0x0d7f, 0x7e20, 0xb284, 0x0100, 0x00c0, 0x4940, 0x7e24, + 0xa6b5, 0x000c, 0x681c, 0xd0ac, 0x00c0, 0x494b, 0xc685, 0x7003, + 0x0000, 0x7007, 0x0004, 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, + 0x000f, 0xa7b8, 0x46e3, 0x273c, 0x87fb, 0x00c0, 0x4961, 0x0048, + 0x495b, 0x1078, 0x29ab, 0x689c, 0xa065, 0x0040, 0x4965, 0x0078, + 0x494e, 0x1078, 0x49e3, 0x00c0, 0x4961, 0x127f, 0x2000, 0x007c, + 0x127e, 0x007e, 0x017e, 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, + 0x007e, 0x2090, 0x007f, 0x7e20, 0xb284, 0x0100, 0x00c0, 0x4979, + 0x7e24, 0x0d7f, 0x037f, 0x047f, 0xa6b5, 0x000c, 0x681c, 0xd0b4, + 0x0040, 0x4987, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, 0x2049, + 0x4968, 0x6828, 0xa055, 0x0d7e, 0x0040, 0x49df, 0x2d70, 0x2e60, + 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x46e3, 0x273c, 0x87fb, 0x00c0, + 0x49a4, 0x0048, 0x499d, 0x1078, 0x29ab, 0x709c, 0xa075, 0x2060, + 0x0040, 0x49df, 0x0078, 0x4990, 0x2704, 0xae68, 0x6808, 0xa422, + 0x680c, 0xa31b, 0x0048, 0x49bd, 0x8a51, 0x00c0, 0x49b1, 0x1078, + 0x29ab, 0x8738, 0x2704, 0xa005, 0x00c0, 0x49a5, 0x709c, 0xa075, + 0x2060, 0x0040, 0x49df, 0x0078, 0x4990, 0x8422, 0x8420, 0x831a, + 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, + 0x00c8, 0x49cc, 0x1078, 0x29ab, 0xb284, 0x0100, 0x0040, 0x49da, + 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x00c0, 0x49da, 0x2071, 0x0050, + 0x0078, 0x49dc, 0x2071, 0x0020, 0x0d7f, 0x0078, 0x48ed, 0x0d7f, + 0x127f, 0x2000, 0x007c, 0x7008, 0x007e, 0xa084, 0x01e0, 0x007f, + 0x0040, 0x49ec, 0xa006, 0x007c, 0xa084, 0x0003, 0xa086, 0x0003, + 0x00c0, 0x49f3, 0x007c, 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, + 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, 0xd09c, 0x0040, + 0x4a05, 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, 0x7004, 0xa084, + 0x0010, 0xc085, 0x7006, 0x2079, 0x4f00, 0x8a51, 0x0040, 0x4a31, + 0x8738, 0x2704, 0xa005, 0x00c0, 0x4a23, 0x609c, 0xa005, 0x0040, + 0x4a32, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x46e3, 0x203c, + 0x87fb, 0x1040, 0x29ab, 0x7008, 0x007e, 0xa084, 0x01e0, 0x007f, + 0x0040, 0x4a2d, 0xa006, 0x0078, 0x4a32, 0xa084, 0x0003, 0xa086, + 0x0003, 0x007c, 0x2051, 0x0000, 0x007c, 0x127e, 0x007e, 0x0d7e, + 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x087f, 0x7108, + 0xa184, 0x0003, 0x00c0, 0x4a4a, 0x6828, 0xa005, 0x0040, 0x4a5a, + 0x0078, 0x45f3, 0x7108, 0xd1fc, 0x0040, 0x4a52, 0x1078, 0x47de, + 0x0078, 0x4a3f, 0x7007, 0x0010, 0x7108, 0xd1fc, 0x0040, 0x4a54, + 0x1078, 0x47de, 0x7008, 0xa086, 0x0008, 0x00c0, 0x4a3f, 0x7000, + 0xa005, 0x00c0, 0x4a3f, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, + 0x007e, 0x7804, 0xd0cc, 0x0040, 0x4a6f, 0x1078, 0x4abd, 0x007f, + 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, + 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x2049, 0x4a72, + 0xad80, 0x0011, 0x20a0, 0xb284, 0x0100, 0x0040, 0x4a95, 0x2001, + 0x4f04, 0x2004, 0xd0ec, 0x0040, 0x4a91, 0x2099, 0x0031, 0x0078, + 0x4a97, 0x2099, 0x0032, 0x0078, 0x4a97, 0x2099, 0x0031, 0x700c, + 0xa084, 0x03ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, + 0x0001, 0x0040, 0x4aa6, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, + 0x03ff, 0x0040, 0x4ab2, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x4aad, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, + 0x137f, 0x147f, 0x127f, 0x2000, 0x007c, 0x127e, 0x70d4, 0xa084, + 0x4600, 0x8004, 0x2090, 0x6814, 0xd0fc, 0x0040, 0x4aff, 0x7000, + 0xd084, 0x0040, 0x4aff, 0x7e24, 0xa6b5, 0x0004, 0x7007, 0x0004, + 0x7118, 0x017e, 0x711c, 0x017e, 0x7120, 0x017e, 0x7124, 0x017e, + 0xa00e, 0x711a, 0x701f, 0x3fff, 0x7122, 0x7126, 0x7013, 0x0004, + 0x7116, 0x7602, 0x7007, 0x0001, 0x2001, 0xffff, 0x2009, 0x0031, + 0x200a, 0x200a, 0x7108, 0xd1fc, 0x0040, 0x4aea, 0x027f, 0x7226, + 0x027f, 0x7222, 0x027f, 0x721e, 0x027f, 0x721a, 0x7007, 0x0002, + 0x7008, 0xa086, 0x0008, 0x0040, 0x4aff, 0x0078, 0x4821, 0x7007, + 0x0004, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x2091, 0x8000, + 0x2091, 0x6000, 0x78ac, 0xa005, 0x00c0, 0x4b1d, 0x7974, 0x70d0, + 0xa106, 0x00c0, 0x4b1d, 0x781c, 0xa005, 0x0040, 0x4b1d, 0x781f, + 0x0000, 0x0068, 0x4b1d, 0x2091, 0x4080, 0x7830, 0x8001, 0x7832, + 0x00c0, 0x4ba5, 0x7834, 0x7832, 0x7810, 0xd0ec, 0x00c0, 0x4b9e, + 0x2061, 0x74c0, 0x2069, 0x4f80, 0xc7fd, 0x68d0, 0xa005, 0x0040, + 0x4b37, 0x8001, 0x68d2, 0x00c0, 0x4b37, 0x1078, 0x4d73, 0x6800, + 0xa084, 0x000f, 0x0040, 0x4b4c, 0xa086, 0x0001, 0x0040, 0x4b4c, + 0x6844, 0xa00d, 0x0040, 0x4b4c, 0x2104, 0xa005, 0x0040, 0x4b4c, + 0x8001, 0x200a, 0x0040, 0x4ce6, 0x6814, 0xa005, 0x0040, 0x4b71, + 0x8001, 0x6816, 0x00c0, 0x4b71, 0x68a7, 0x0001, 0x0f7e, 0xd7fc, + 0x00c0, 0x4b66, 0x7810, 0xd0ec, 0x0040, 0x4b62, 0x2079, 0x0100, + 0x0078, 0x4b68, 0x2079, 0x0200, 0x0078, 0x4b68, 0x2079, 0x0100, + 0x1078, 0x43ca, 0x0f7f, 0x6864, 0xa005, 0x0040, 0x4b71, 0x1078, + 0x2668, 0x6880, 0xa005, 0x0040, 0x4b7e, 0x8001, 0x6882, 0x00c0, + 0x4b7e, 0x6867, 0x0000, 0x68d4, 0xc0dd, 0x68d6, 0x68d4, 0xd0fc, + 0x0040, 0x4b9b, 0xc0fc, 0x68d6, 0x20a9, 0x0200, 0x6034, 0xa005, + 0x0040, 0x4b97, 0x8001, 0x6036, 0x68d4, 0xc0fd, 0x68d6, 0x00c0, + 0x4b97, 0x6010, 0xa005, 0x0040, 0x4b97, 0x1078, 0x2668, 0xace0, + 0x0010, 0x00f0, 0x4b86, 0xd7fc, 0x0040, 0x4ba5, 0x2061, 0x54c0, + 0x2069, 0x4f40, 0xc7fc, 0x0078, 0x4b2d, 0x1078, 0x4be1, 0x7838, + 0x8001, 0x783a, 0x00c0, 0x4bc7, 0x783c, 0x783a, 0x2061, 0x54c0, + 0x2069, 0x4f40, 0xc7fc, 0x680c, 0xa005, 0x0040, 0x4bb9, 0x1078, + 0x4c4b, 0xd7fc, 0x00c0, 0x4bc7, 0x7810, 0xd0ec, 0x00c0, 0x4bc7, + 0x2061, 0x74c0, 0x2069, 0x4f80, 0xc7fd, 0x0078, 0x4bb3, 0x7814, + 0xd0e4, 0x00c0, 0x4bcb, 0x7810, 0xd0cc, 0x0040, 0x4bde, 0xd0ac, + 0x00c0, 0x4bd7, 0xd0a4, 0x0040, 0x4bde, 0xc0ad, 0x7812, 0x2091, + 0x8001, 0x0068, 0x4bdd, 0x1078, 0x23d5, 0x007c, 0x2091, 0x8001, + 0x007c, 0x7840, 0x8001, 0x7842, 0x00c0, 0x4c4a, 0x7844, 0x7842, + 0x2069, 0x4f40, 0xc7fc, 0x7810, 0x2079, 0x0200, 0xd0ec, 0x0040, + 0x4bf3, 0x2079, 0x0100, 0x68d8, 0xa005, 0x0040, 0x4bff, 0x7de0, + 0xa504, 0x00c0, 0x4bff, 0x68da, 0x68d4, 0xc0bc, 0x68d6, 0x2079, + 0x4f00, 0x6810, 0xa005, 0x00c0, 0x4c07, 0x2001, 0x0101, 0x8001, + 0x6812, 0xd7fc, 0x0040, 0x4c10, 0xa080, 0x95d0, 0x0078, 0x4c12, + 0xa080, 0x94c0, 0x2040, 0x2004, 0xa065, 0x0040, 0x4c3c, 0x6024, + 0xa005, 0x0040, 0x4c38, 0x8001, 0x6026, 0x00c0, 0x4c38, 0x6800, + 0xa005, 0x0040, 0x4c2b, 0x684c, 0xac06, 0x00c0, 0x4c2b, 0x1078, + 0x4ce6, 0x0078, 0x4c3c, 0x6864, 0xa005, 0x0040, 0x4c33, 0x6027, + 0x0001, 0x0078, 0x4c38, 0x1078, 0x4c99, 0x2804, 0x0078, 0x4c14, + 0x6000, 0x2c40, 0x0078, 0x4c14, 0xd7fc, 0x00c0, 0x4c4a, 0x7810, + 0xd0ec, 0x00c0, 0x4c4a, 0x2069, 0x4f80, 0xc7fd, 0x2079, 0x0100, + 0x0078, 0x4bf3, 0x007c, 0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, + 0xd09c, 0x0040, 0x4c85, 0x6024, 0xa005, 0x0040, 0x4c5b, 0x8001, + 0x6026, 0x0078, 0x4c83, 0x6008, 0xc09c, 0xd084, 0x00c0, 0x4c63, + 0xd0ac, 0x0040, 0x4c7d, 0x600a, 0x6004, 0xa005, 0x0040, 0x4c85, + 0x0d7e, 0x0c7e, 0x017e, 0x2068, 0x6010, 0x8001, 0x6012, 0x1078, + 0x3e10, 0x2d00, 0x2c68, 0x2060, 0x1078, 0x1e9b, 0x1078, 0x205d, + 0x017f, 0x0c7f, 0x0d7f, 0x0078, 0x4c85, 0xc0bd, 0x600a, 0xa18d, + 0x0001, 0x0078, 0x4c85, 0xa18d, 0x0100, 0xace0, 0x0010, 0x00f0, + 0x4c4f, 0xa184, 0x0001, 0x0040, 0x4c94, 0xa18c, 0xfffe, 0x690e, + 0x1078, 0x2668, 0x0078, 0x4c95, 0x690e, 0x007c, 0x00c0, 0x4c95, + 0x786c, 0x2c00, 0x687e, 0x6714, 0x6f76, 0x6017, 0x0000, 0x602b, + 0x0000, 0x601b, 0x0006, 0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, + 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x1078, + 0x1e24, 0x6818, 0xa005, 0x0040, 0x4cb7, 0x8001, 0x681a, 0x6808, + 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x00d0, + 0x4cc3, 0x1078, 0x29ab, 0x6812, 0x00c0, 0x4cc9, 0x7910, 0xc1a5, + 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x206c, + 0xd7fc, 0x00c0, 0x4cd7, 0x2069, 0x4f40, 0x0078, 0x4cd9, 0x2069, + 0x4f80, 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x00c0, 0x4ce3, + 0x697a, 0x2001, 0x0004, 0x1078, 0x265c, 0x007c, 0x0d7e, 0x694c, + 0x2160, 0xd7fc, 0x00c0, 0x4cf8, 0x7810, 0xd0ec, 0x0040, 0x4cf4, + 0x2069, 0x0100, 0x0078, 0x4cfa, 0x2069, 0x0200, 0x0078, 0x4cfa, + 0x2069, 0x0100, 0x1078, 0x291f, 0x601b, 0x0006, 0x6858, 0xa084, + 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, + 0x602f, 0x0000, 0x6033, 0x0000, 0x6808, 0xa084, 0xfffd, 0x680a, + 0x6830, 0xd0b4, 0x0040, 0x4d2c, 0x684b, 0x0004, 0x20a9, 0x0014, + 0x6848, 0xd094, 0x0040, 0x4d1e, 0x00f0, 0x4d18, 0x684b, 0x0009, + 0x20a9, 0x0014, 0x6848, 0xd084, 0x0040, 0x4d28, 0x00f0, 0x4d22, + 0x20a9, 0x00fa, 0x00f0, 0x4d2a, 0x681b, 0x0047, 0x0d7f, 0x6867, + 0x0007, 0x007c, 0x2079, 0x4f00, 0x1078, 0x4d66, 0x1078, 0x4d4c, + 0x1078, 0x4d59, 0x2009, 0x0002, 0x2069, 0x4f80, 0x680f, 0x0000, + 0x6813, 0x0000, 0x6817, 0x0000, 0x8109, 0x0040, 0x4d4b, 0x2069, + 0x4f40, 0x0078, 0x4d3e, 0x007c, 0x7810, 0xd0ec, 0x0040, 0x4d54, + 0x2019, 0x00cc, 0x0078, 0x4d56, 0x2019, 0x007b, 0x7b3a, 0x7b3e, + 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x4d61, 0x2019, 0x0040, 0x0078, + 0x4d63, 0x2019, 0x0026, 0x7b42, 0x7b46, 0x007c, 0x7814, 0xd0e4, + 0x00c0, 0x4d6e, 0x2019, 0x3f94, 0x0078, 0x4d70, 0x2019, 0x2624, + 0x7b32, 0x7b36, 0x007c, 0x6a50, 0xa285, 0x0000, 0x0040, 0x4d9f, + 0x6954, 0x6bc0, 0xa300, 0x0c7e, 0x2164, 0x6304, 0x83ff, 0x00c0, + 0x4d8b, 0x8211, 0x0040, 0x4d8f, 0x8108, 0xa11a, 0x0048, 0x4d7c, + 0x69c0, 0x0078, 0x4d7c, 0x68d3, 0x000a, 0x0c7f, 0x007c, 0x6950, + 0x6ac0, 0x2264, 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, 0xc0b5, + 0x600a, 0x8210, 0x8109, 0x00c0, 0x4d91, 0x6952, 0x0c7f, 0x007c, + 0x00e0, 0x4da0, 0x2091, 0x6000, 0x00e0, 0x4da4, 0x2091, 0x6000, + 0x70ec, 0xd0dc, 0x00c0, 0x4db1, 0xd0d4, 0x0040, 0x4dda, 0x0078, + 0x4ddd, 0x2008, 0x7810, 0xd0ec, 0x0040, 0x4dc4, 0xd1c4, 0x00c0, + 0x4dfe, 0x7814, 0xc0c5, 0x7816, 0x7810, 0xc0f5, 0x7812, 0xd0ec, + 0x0040, 0x4dfa, 0x0078, 0x4df6, 0xae8e, 0x0100, 0x0040, 0x4dd1, + 0x7814, 0xc0f5, 0xc0c5, 0x7816, 0xd0d4, 0x00c0, 0x4dfa, 0x0078, + 0x4df6, 0x7814, 0xc0fd, 0xc0c5, 0x7816, 0xd0d4, 0x00c0, 0x4dfa, + 0x0078, 0x4df6, 0xd0e4, 0x0040, 0x4dfc, 0x00e0, 0x4ddd, 0x2091, + 0x6000, 0x2009, 0x000c, 0x00e0, 0x4de3, 0x2091, 0x6000, 0x8109, + 0x00c0, 0x4de3, 0x70e4, 0xa084, 0x01ff, 0xa086, 0x01ff, 0x00c0, + 0x4df4, 0x70ec, 0x0078, 0x4db1, 0x1078, 0x4dff, 0x7804, 0xd08c, + 0x0040, 0x4dfc, 0x681f, 0x000c, 0x70a0, 0x70a2, 0x007c, 0x7910, + 0xd1ec, 0x0040, 0x4e09, 0x7814, 0xc0c4, 0xc1f4, 0x7912, 0x0078, + 0x4e1b, 0xae8e, 0x0100, 0x0040, 0x4e15, 0x7814, 0xc0f4, 0xd0fc, + 0x00c0, 0x4e1b, 0xc0c4, 0x0078, 0x4e1b, 0x7814, 0xc0fc, 0xd0f4, + 0x00c0, 0x4e1b, 0xc0c4, 0x7816, 0x007c, 0x7bd7 +}; + +unsigned short risc_1080_code_length01 = 0x3e1e; + +#else + +unsigned short risc_1080_code_version = 0x0000; +unsigned short risc_1080_code_addr01 = 0x0000 ; +unsigned short risc_1080_code01[] = { 0x0000 }; +unsigned short risc_1080_code_length01 = 0x0000; + +#endif + + +#if QLOGIC_12160_FIRMWARE_SUPPORT +/* + ************************************************************************ + * * + * --- ISP12160A Initiator Firmware --- * + * 32 LUN Support * + * * + ************************************************************************ + * * + * NOTICE * + * * + * COPYRIGHT 1994-2001 QLOGIC CORPORATION * + * ALL RIGHTS RESERVED * + * * + * This computer program is CONFIDENTIAL and contains TRADE SECRETS of * + * QLOGIC CORPORATION. The receipt or possession of this program does * + * not convey any rights to reproduce or disclose its contents, or to * + * manufacture, use, or sell anything that it may describe, in whole or * + * in part, without the specific written consent of QLOGIC CORPORATION. * + * Any reproduction of this program without the express written consent * + * of QLOGIC CORPORATION is a violation of the copyright laws and may * + * subject you to civil liability and criminal prosecution. * + * * + ************************************************************************ + + */ + + +/* + * Firmware Version 10.04.34 (07:48 Jun 25, 2001) + */ + +unsigned short risc_12160_code_version = 10*1024+4; + +unsigned short risc_12160_code_addr01 = 0x1000 ; + +unsigned short risc_12160_code01[] = { + 0x0804, 0x1041, 0x0000, 0x361d, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, + 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, + 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, + 0x3132, 0x3136, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, + 0x6572, 0x7369, 0x6f6e, 0x2031, 0x302e, 0x3034, 0x2020, 0x2043, + 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, + 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, + 0x2400, 0x20c9, 0x90ff, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2001, + 0x01ff, 0x2004, 0xd0fc, 0x1120, 0x2071, 0x0100, 0x70a0, 0x70a2, + 0x20c1, 0x0020, 0x2089, 0x1221, 0x2071, 0x0010, 0x70c3, 0x0004, + 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x000a, + 0x2001, 0x04fd, 0x2004, 0x70d6, 0x2009, 0xfeff, 0x2130, 0x2128, + 0xa1a2, 0x4700, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0xa192, 0x9100, 0x2009, 0x0000, 0x2001, 0x0032, 0x080c, 0x1df7, + 0x2218, 0x2079, 0x4700, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, + 0x0040, 0x42a4, 0x8109, 0x1dd8, 0x2009, 0xff00, 0x3400, 0xa102, + 0x0218, 0x0110, 0x20a8, 0x42a4, 0x781b, 0x0064, 0x7814, 0xc0cd, + 0xc0d5, 0x7816, 0x2071, 0x0200, 0x00d6, 0x2069, 0x4740, 0x080c, + 0x45b2, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1130, 0x2069, 0x4780, + 0x2071, 0x0100, 0x080c, 0x45b2, 0x7814, 0xc0d4, 0x7816, 0x00de, + 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802, + 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002, + 0x2009, 0x0002, 0x2069, 0x4740, 0x681b, 0x0003, 0x6823, 0x0007, + 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0006, + 0x6833, 0x0008, 0x683b, 0x0000, 0x8109, 0x0500, 0x68cf, 0x000a, + 0x68bf, 0x47c0, 0x2079, 0x4700, 0x68d3, 0x762d, 0x68c3, 0x4cc0, + 0x68c7, 0x4bc0, 0x68cb, 0x8cc0, 0x68a7, 0x8f44, 0x68ab, 0x8f49, + 0x68af, 0x8f44, 0x68b3, 0x8f44, 0x68a3, 0x0001, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x11c8, 0x2069, 0x4780, 0x0870, 0x68cf, 0x000a, + 0x68bf, 0x49c0, 0x68d3, 0x7839, 0x68c3, 0x6cc0, 0x68c7, 0x4c40, + 0x68cb, 0x8dd0, 0x68a7, 0x8f49, 0x68ab, 0x8f4e, 0x68af, 0x8f49, + 0x68b3, 0x8f49, 0x68a3, 0x0001, 0x00e6, 0x2069, 0x4bc0, 0x2071, + 0x0200, 0x70ec, 0xd0e4, 0x2019, 0x1809, 0x2021, 0x0009, 0x1120, + 0x2019, 0x180c, 0x2021, 0x000c, 0x080c, 0x1d67, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x1188, 0x2069, 0x4c40, 0x2071, 0x0100, 0x70ec, + 0xd0e4, 0x2019, 0x1809, 0x2021, 0x0009, 0x1120, 0x2019, 0x180c, + 0x2021, 0x000c, 0x080c, 0x1d67, 0x00ee, 0x2011, 0x0002, 0x2069, + 0x4cc0, 0x2009, 0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b, + 0x0040, 0x7bc8, 0xa386, 0xfeff, 0x1128, 0x6817, 0x0100, 0x681f, + 0x0064, 0x0020, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, + 0x1f04, 0x1135, 0x8109, 0x1d38, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x1128, 0x8211, 0x0118, 0x2069, 0x6cc0, 0x08d8, 0x080c, 0x22de, + 0x080c, 0x4027, 0x080c, 0x1b7c, 0x080c, 0x456b, 0x2091, 0x2200, + 0x2079, 0x4700, 0x2071, 0x0050, 0x2091, 0x2400, 0x2079, 0x4700, + 0x2071, 0x0020, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x4740, + 0x2091, 0x2800, 0x2079, 0x0100, 0x2071, 0x4780, 0x2091, 0x2000, + 0x2079, 0x4700, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, + 0x2071, 0x0010, 0x70c3, 0x0000, 0x1004, 0x118c, 0x70c0, 0xa086, + 0x0002, 0x1110, 0x080c, 0x13ba, 0x2039, 0x0000, 0x080c, 0x12ab, + 0x78ac, 0xa005, 0x1180, 0x0e04, 0x119a, 0x786c, 0xa065, 0x0110, + 0x080c, 0x2089, 0x080c, 0x1e18, 0x0e04, 0x11af, 0x786c, 0xa065, + 0x0110, 0x080c, 0x2089, 0x0e04, 0x11af, 0x2009, 0x4747, 0x2011, + 0x4787, 0x2104, 0x220c, 0xa105, 0x0110, 0x080c, 0x1c8b, 0x2071, + 0x4740, 0x70a0, 0xa005, 0x01e8, 0x744c, 0xa485, 0x0000, 0x01c8, + 0x2079, 0x0200, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d, 0x2190, + 0x080c, 0x2731, 0x2091, 0x8000, 0x2091, 0x303d, 0x0e04, 0x11d1, + 0x2079, 0x4700, 0x786c, 0xa065, 0x0120, 0x2071, 0x0010, 0x080c, + 0x2089, 0x1d04, 0x11d9, 0x2079, 0x4700, 0x2071, 0x0010, 0x080c, + 0x4382, 0x2071, 0x4780, 0x70a0, 0xa005, 0x0188, 0x704c, 0xa025, + 0x0170, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d, + 0x2190, 0x080c, 0x2731, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079, + 0x4700, 0x2071, 0x0010, 0x0e04, 0x11fa, 0x786c, 0xa065, 0x0110, + 0x080c, 0x2089, 0x1d04, 0x118e, 0x080c, 0x4382, 0x0804, 0x118e, + 0x3c00, 0xa084, 0x0007, 0x0002, 0x120c, 0x120c, 0x120e, 0x120e, + 0x1213, 0x1213, 0x1218, 0x1218, 0x080c, 0x255d, 0x2091, 0x2400, + 0x080c, 0x40bf, 0x0005, 0x2091, 0x2200, 0x080c, 0x40bf, 0x0005, + 0x2091, 0x2200, 0x080c, 0x40bf, 0x2091, 0x2400, 0x080c, 0x40bf, + 0x0005, 0x1241, 0x1241, 0x1242, 0x1242, 0x124d, 0x124d, 0x124d, + 0x124d, 0x1256, 0x1256, 0x1261, 0x1261, 0x124d, 0x124d, 0x124d, + 0x124d, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, + 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, + 0x1270, 0x0cf8, 0x0006, 0x0106, 0x0126, 0x2091, 0x2800, 0x080c, + 0x257a, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, 0x0126, + 0x080c, 0x1200, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, + 0x0126, 0x2091, 0x2600, 0x080c, 0x257a, 0x012e, 0x010e, 0x000e, + 0x000d, 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, 0x080c, 0x257a, + 0x2091, 0x2800, 0x080c, 0x257a, 0x012e, 0x010e, 0x000e, 0x000d, + 0x0006, 0x0106, 0x0126, 0x00d6, 0x00e6, 0x00f6, 0x2079, 0x4700, + 0x2071, 0x0200, 0x2069, 0x4740, 0x3d00, 0xd08c, 0x0130, 0x70ec, + 0xa084, 0x1c00, 0x78e2, 0x080c, 0x45b2, 0x3d00, 0xd084, 0x0150, + 0x2069, 0x4780, 0x2071, 0x0100, 0x70ec, 0xa084, 0x1c00, 0x78e6, + 0x080c, 0x45b2, 0x080c, 0x250e, 0x00fe, 0x00ee, 0x00de, 0x012e, + 0x010e, 0x000e, 0x000d, 0x7008, 0x800b, 0x1240, 0x7007, 0x0002, + 0xa08c, 0x01e0, 0x1120, 0xd09c, 0x0108, 0x0887, 0x0897, 0x70c3, + 0x4002, 0x0804, 0x13bd, 0x0e04, 0x131e, 0x2061, 0x0000, 0x6018, + 0xd084, 0x1904, 0x131e, 0x7828, 0xa005, 0x1120, 0x0004, 0x131f, + 0x0804, 0x131e, 0xd0fc, 0x0130, 0x0006, 0x080c, 0x1b19, 0x000e, + 0x0150, 0x0028, 0x0006, 0x080c, 0x1b0e, 0x000e, 0x0120, 0x2001, + 0x4007, 0x0804, 0x13bc, 0x7910, 0xd0fc, 0x1128, 0x2061, 0x4740, + 0xc19c, 0xc7fc, 0x0020, 0x2061, 0x4780, 0xc19d, 0xc7fd, 0x6060, + 0xa005, 0x1904, 0x131e, 0x7912, 0x607e, 0x7828, 0xc0fc, 0xa086, + 0x0018, 0x1120, 0x00c6, 0x080c, 0x1925, 0x00ce, 0x782b, 0x0000, + 0x6078, 0xa065, 0x01e0, 0x00c6, 0x609c, 0x080c, 0x1be3, 0x00ce, + 0x609f, 0x0000, 0x080c, 0x1a50, 0x2009, 0x0018, 0x6087, 0x0103, + 0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812, + 0x080c, 0x1b24, 0x000e, 0x7812, 0x1198, 0x080c, 0x1b6f, 0x7810, + 0xd09c, 0x1118, 0x2061, 0x4740, 0x0020, 0x2061, 0x4780, 0xc09c, + 0x7812, 0x607b, 0x0000, 0x60d0, 0xd0c4, 0x0130, 0xc0c4, 0x60d2, + 0x2001, 0x4005, 0x0804, 0x13bc, 0x0804, 0x13ba, 0x0005, 0xa006, + 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, 0xa03d, 0xa08a, + 0x0040, 0x1a04, 0x136c, 0x0002, 0x13ba, 0x1408, 0x13d6, 0x143c, + 0x1470, 0x1470, 0x13ce, 0x1a68, 0x147a, 0x13c8, 0x13da, 0x13db, + 0x13dc, 0x13dd, 0x1a6c, 0x13c8, 0x1487, 0x14db, 0x1940, 0x1a62, + 0x13de, 0x17c9, 0x17ff, 0x1831, 0x1877, 0x1786, 0x1793, 0x17a6, + 0x17b8, 0x15c0, 0x13c8, 0x150d, 0x1518, 0x1526, 0x1534, 0x154b, + 0x1559, 0x155c, 0x156e, 0x157c, 0x1586, 0x15a6, 0x15b2, 0x13c8, + 0x13c8, 0x13c8, 0x13c8, 0x15cd, 0x15de, 0x15f8, 0x162c, 0x1655, + 0x1667, 0x166a, 0x1694, 0x16cd, 0x16df, 0x1754, 0x1764, 0x13c8, + 0x13c8, 0x13c8, 0x13c8, 0x1776, 0x2100, 0xa08a, 0x0040, 0x1a04, + 0x13c8, 0x0002, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x1a8e, + 0x1a94, 0x13c8, 0x13c8, 0x13c8, 0x1a98, 0x1ad8, 0x13c8, 0x13c8, + 0x13c8, 0x13c8, 0x1403, 0x146b, 0x1482, 0x14d6, 0x193b, 0x13c8, + 0x13c8, 0x190a, 0x13c8, 0x1adc, 0x1a80, 0x1a8a, 0x13c8, 0x13c8, + 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, + 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, + 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, + 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, + 0x13c8, 0x13c8, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0028, 0x73ce, + 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0e04, 0x13bd, 0x2061, + 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x0005, + 0x70c3, 0x4001, 0x0c90, 0x70c3, 0x4006, 0x0c78, 0x2099, 0x0041, + 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0c20, 0x70c4, 0x70c3, + 0x0004, 0x0807, 0x08f8, 0x08f0, 0x08e8, 0x08e0, 0x2091, 0x8000, + 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, + 0x70d3, 0x000a, 0x2001, 0x0004, 0x70d6, 0x2079, 0x0000, 0x781b, + 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051, + 0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091, + 0x4080, 0x0804, 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0018, + 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, + 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, 0x721e, + 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0904, 0x13ba, 0xa182, + 0x0040, 0x1210, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x7007, + 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002, + 0xa084, 0x01e0, 0x0120, 0x70c3, 0x4002, 0x0804, 0x13bd, 0x24a8, + 0x53a5, 0x0c10, 0x0804, 0x13ba, 0x2029, 0x0000, 0x2520, 0x71d0, + 0x72c8, 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, 0x0000, + 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, + 0x7007, 0x0006, 0x81ff, 0x0904, 0x13ba, 0xa182, 0x0040, 0x1210, + 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, + 0x0001, 0x7008, 0xd0fc, 0x0de8, 0xa084, 0x01e0, 0x0d48, 0x70c3, + 0x4002, 0x0804, 0x13bd, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0878, + 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x1108, 0x200a, 0x72ca, + 0x0804, 0x13b9, 0x70c7, 0x000a, 0x70cb, 0x0004, 0x70cf, 0x0022, + 0x0804, 0x13ba, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, 0x2029, + 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, + 0x73ce, 0x74d2, 0xa005, 0x05e8, 0xa40a, 0x0108, 0x1240, 0x8001, + 0x7872, 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc085, 0x78ae, 0x2001, + 0x4005, 0x0804, 0x13bc, 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76, + 0xa48c, 0xff00, 0x0170, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, + 0x810f, 0xa118, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, + 0x0050, 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, + 0x0000, 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, + 0x0118, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae, + 0x0018, 0x78ac, 0xc085, 0x78ae, 0x0804, 0x13ba, 0x75d8, 0x76dc, + 0x75da, 0x76de, 0x0018, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, + 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0500, + 0xa40a, 0x0110, 0x1a04, 0x13bc, 0x8001, 0x7892, 0xa084, 0xfc00, + 0x0138, 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0804, 0x13bc, + 0x7a9a, 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0118, 0x7a10, + 0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0018, + 0x78ac, 0xc0c5, 0x78ae, 0x0804, 0x13ba, 0x2009, 0x0000, 0x786c, + 0xa065, 0x0118, 0x8108, 0x6000, 0x0cd8, 0x7ac4, 0x0804, 0x13b8, + 0x2009, 0x4748, 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, + 0x13b9, 0x2011, 0x4788, 0x2214, 0x0804, 0x13b8, 0x2009, 0x4749, + 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, + 0x4789, 0x2214, 0x0804, 0x13b8, 0x2061, 0x4740, 0x6128, 0x622c, + 0x8214, 0x8214, 0x8214, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1148, + 0x2061, 0x4780, 0x6328, 0x73da, 0x632c, 0x831c, 0x831c, 0x831c, + 0x73de, 0x0804, 0x13b8, 0x2009, 0x474c, 0x210c, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, 0x478c, 0x2214, 0x0804, + 0x13b8, 0x7918, 0x0804, 0x13b9, 0x2009, 0x0202, 0x210c, 0xa18c, + 0x0f30, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, + 0x0102, 0x2214, 0xa294, 0x0f30, 0x0804, 0x13b8, 0x2009, 0x474d, + 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, + 0x478d, 0x2214, 0x0804, 0x13b8, 0x7920, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1904, 0x13b9, 0x7a24, 0x0804, 0x13b8, 0x2011, 0x4c40, + 0x71c4, 0xd1fc, 0x1110, 0x2011, 0x4bc0, 0x8107, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0xa268, 0x6a00, 0x6b08, 0x6c1c, 0x74da, + 0x74c4, 0xd4fc, 0x1118, 0x2021, 0x023b, 0x0010, 0x2021, 0x013b, + 0x2424, 0xa4a4, 0x1c00, 0x74de, 0x0804, 0x13b7, 0x77c4, 0x080c, + 0x1b8a, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, + 0x0804, 0x13b7, 0x2061, 0x4740, 0x6118, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1904, 0x13b9, 0x2061, 0x4780, 0x6218, 0x0804, 0x13b8, + 0x77c4, 0x080c, 0x1b8a, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, + 0x77da, 0x2091, 0x8001, 0x0804, 0x13b7, 0x71c4, 0x2110, 0xa294, + 0x000f, 0xa282, 0x0010, 0x1a04, 0x13b3, 0x080c, 0x239c, 0xa384, + 0x4000, 0x0110, 0xa295, 0x0020, 0x0804, 0x13b7, 0x71c4, 0x2100, + 0xc0bc, 0xa082, 0x0010, 0x1a04, 0x13b3, 0xd1bc, 0x1120, 0x2011, + 0x4748, 0x2204, 0x0020, 0x2011, 0x4788, 0x2204, 0xc0bd, 0x0006, + 0x2100, 0xc0bc, 0x2012, 0x080c, 0x2340, 0x001e, 0x0804, 0x13b9, + 0x71c4, 0x2021, 0x4749, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0030, + 0x71c8, 0x2021, 0x4789, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x1624, + 0x20a9, 0x0008, 0x2204, 0xa106, 0x0138, 0x8210, 0x1f04, 0x160a, + 0x71c4, 0x72c8, 0x0804, 0x13b2, 0xa292, 0x1624, 0x0026, 0x2122, + 0x001e, 0x080c, 0x2352, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1110, + 0xd3fc, 0x09f0, 0x0804, 0x13ba, 0x03e8, 0x00fa, 0x01f4, 0x02ee, + 0x0004, 0x0001, 0x0002, 0x0003, 0x2061, 0x4740, 0x6128, 0x622c, + 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003, + 0x8003, 0x602e, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x11a0, 0x0026, + 0x0016, 0x2061, 0x4780, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, + 0x70d8, 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, + 0x72de, 0x001e, 0x002e, 0x0804, 0x13b8, 0x2061, 0x4740, 0x6130, + 0x70c4, 0x6032, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, + 0x2061, 0x4780, 0x6230, 0x70c8, 0x6032, 0x0804, 0x13b8, 0x7918, + 0x0804, 0x13b9, 0x71c4, 0xa184, 0xf0cf, 0x0148, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x1904, 0x13b3, 0x72c8, 0x0804, 0x13b2, 0x2019, + 0x0000, 0x080c, 0x238e, 0x0036, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x0118, 0x001e, 0x0804, 0x13b9, 0x71c8, 0xa184, 0xf0cf, 0x0128, + 0x000e, 0x2110, 0x71c4, 0x0804, 0x13b2, 0xc3fd, 0x080c, 0x238e, + 0x2310, 0x001e, 0x0804, 0x13b8, 0x71c4, 0xa182, 0x0010, 0x0248, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b3, 0x72c8, 0x0804, + 0x13b2, 0x2011, 0x474d, 0x2204, 0x0006, 0x8104, 0x1208, 0x8108, + 0x2112, 0x2019, 0x0000, 0x080c, 0x237b, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x0118, 0x001e, 0x0804, 0x13b9, 0x71c8, 0xa182, 0x0010, + 0x0228, 0x0006, 0x2110, 0x71c4, 0x0804, 0x13b2, 0x2011, 0x478d, + 0x2204, 0x0006, 0x8104, 0x1208, 0x8108, 0x2112, 0xc3fd, 0x080c, + 0x237b, 0x002e, 0x001e, 0x0804, 0x13b8, 0x71c4, 0x72c8, 0xa184, + 0xfffd, 0x1904, 0x13b2, 0xa284, 0xfffd, 0x1904, 0x13b2, 0x2100, + 0x7920, 0x7822, 0x2200, 0x7a24, 0x7826, 0x0804, 0x13b8, 0x2011, + 0x4c40, 0x71c4, 0xd1fc, 0x1110, 0x2011, 0x4bc0, 0x8107, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x72c8, 0x73cc, 0x74d8, + 0x71c6, 0x6800, 0x70ca, 0x73ce, 0x74da, 0x2091, 0x8000, 0x6a02, + 0xd2ac, 0x1118, 0x2021, 0x0000, 0x0090, 0xa484, 0x00ff, 0xa082, + 0x0002, 0x1a04, 0x1750, 0x843f, 0xa7bc, 0x00ff, 0x0140, 0xa786, + 0x0002, 0x1904, 0x1750, 0xa484, 0x00ff, 0x0904, 0x1750, 0x2061, + 0x0200, 0xd1fc, 0x0110, 0x2061, 0x0100, 0x2029, 0x0009, 0x2031, + 0x0062, 0x843f, 0xa7bc, 0x00ff, 0x0130, 0x8307, 0xa084, 0x00ff, + 0x1110, 0xa73d, 0x1138, 0x2041, 0x0019, 0xa384, 0x00ff, 0xa082, + 0x001a, 0x0210, 0xa4a4, 0x00ff, 0x8307, 0xa084, 0x00ff, 0x0188, + 0xa842, 0x02f0, 0xa086, 0x0010, 0x1120, 0xa39c, 0x00ff, 0xa39d, + 0x0f00, 0xa3bc, 0x00ff, 0x2500, 0xa702, 0x0290, 0x2600, 0xa702, + 0x1278, 0x2039, 0x003a, 0x6804, 0xa705, 0x6806, 0x6b0a, 0x6b0c, + 0x73ce, 0x681c, 0x70da, 0x6c1e, 0x2091, 0x8001, 0x0804, 0x13ba, + 0x2091, 0x8001, 0x0804, 0x13b4, 0x77c4, 0x080c, 0x1b8a, 0x2091, + 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, + 0x681e, 0x2708, 0x0804, 0x13b7, 0x70c4, 0x2061, 0x4740, 0x6118, + 0x601a, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x70c8, + 0x2061, 0x4780, 0x6218, 0x601a, 0x0804, 0x13b8, 0x71c4, 0x72c8, + 0x73cc, 0xa182, 0x0010, 0x1a04, 0x13b3, 0x080c, 0x23c0, 0xa384, + 0x4000, 0x0110, 0xa295, 0x0020, 0x0804, 0x13b7, 0x77c4, 0x080c, + 0x1b8a, 0x2091, 0x8000, 0x6a08, 0xc28d, 0x6a0a, 0x2091, 0x8001, + 0x2708, 0x0804, 0x13b8, 0x77c4, 0x080c, 0x1b8a, 0x2091, 0x8000, + 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0110, 0x080c, + 0x22bd, 0x2091, 0x8001, 0x2708, 0x0804, 0x13b8, 0x77c4, 0x080c, + 0x1b8a, 0x2091, 0x8000, 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, + 0x0110, 0x080c, 0x22bd, 0x2091, 0x8001, 0x2708, 0x0804, 0x13b8, + 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, + 0x8000, 0x080c, 0x1ba2, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0804, + 0x13b8, 0x77c4, 0xd7fc, 0x0128, 0x080c, 0x1b19, 0x0138, 0x0804, + 0x13bc, 0x080c, 0x1b0e, 0x0110, 0x0804, 0x13bc, 0x73c8, 0x72cc, + 0x77c6, 0x73ca, 0x72ce, 0x080c, 0x1c1a, 0x11e8, 0x6818, 0xa005, + 0x01a0, 0x2708, 0x0076, 0x080c, 0x23df, 0x007e, 0x1170, 0x2001, + 0x0015, 0xd7fc, 0x1118, 0x2061, 0x4740, 0x0018, 0xc0fd, 0x2061, + 0x4780, 0x782a, 0x2091, 0x8001, 0x0005, 0x2091, 0x8001, 0x2001, + 0x4005, 0x0804, 0x13bc, 0x2091, 0x8001, 0x0804, 0x13ba, 0x77c4, + 0xd7fc, 0x0128, 0x080c, 0x1b19, 0x0138, 0x0804, 0x13bc, 0x080c, + 0x1b0e, 0x0110, 0x0804, 0x13bc, 0x77c6, 0x2041, 0x0021, 0x2049, + 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x080c, 0x1ba2, 0x2009, + 0x0016, 0xd7fc, 0x1118, 0x2061, 0x4740, 0x0018, 0x2061, 0x4780, + 0xc1fd, 0x6063, 0x0003, 0x607b, 0x0000, 0x6772, 0x607f, 0x000f, + 0x792a, 0x61d0, 0xc1c4, 0x61d2, 0x080c, 0x22bd, 0x2091, 0x8001, + 0x0005, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xd7fc, 0x0128, 0x080c, + 0x1b19, 0x0138, 0x0804, 0x13bc, 0x080c, 0x1b0e, 0x0110, 0x0804, + 0x13bc, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, + 0x1118, 0x2061, 0x4740, 0x0018, 0x2061, 0x4780, 0xc1fd, 0x607b, + 0x0000, 0x6063, 0x0002, 0x6772, 0x607f, 0x000f, 0x792a, 0x61d0, + 0xc1c4, 0x61d2, 0x080c, 0x22bd, 0x2091, 0x8001, 0x2041, 0x0021, + 0x2049, 0x0005, 0x2051, 0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, + 0x0118, 0x60d0, 0xc0fd, 0x60d2, 0x080c, 0x1ba2, 0x70c8, 0x6836, + 0x8738, 0xa784, 0x001f, 0x1dc0, 0x2091, 0x8001, 0x0005, 0x2019, + 0x0000, 0x72c8, 0xd284, 0x0128, 0x080c, 0x1b19, 0x0138, 0x0804, + 0x13bc, 0x080c, 0x1b0e, 0x0110, 0x0804, 0x13bc, 0x72c8, 0x72ca, + 0x78ac, 0xa084, 0x0003, 0x1508, 0x2039, 0x0000, 0xd284, 0x0108, + 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x080c, + 0x1b8a, 0x2091, 0x8000, 0x6808, 0xc0d4, 0xa80d, 0x690a, 0x2091, + 0x8001, 0x8738, 0xa784, 0x001f, 0x1d90, 0xa7bc, 0xff00, 0x873f, + 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d50, 0x2091, 0x8000, 0x72c8, + 0x2069, 0x0100, 0xd284, 0x1110, 0x2069, 0x0200, 0x6808, 0xa084, + 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x01b0, 0x684b, 0x0004, 0x20a9, + 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x18c1, 0x684b, 0x0009, + 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04, 0x18ca, 0x20a9, + 0x00fa, 0x1f04, 0x18d1, 0x2079, 0x4700, 0x2009, 0x0018, 0x72c8, + 0xd284, 0x1118, 0x2061, 0x4740, 0x0018, 0x2061, 0x4780, 0xc1fd, + 0x607b, 0x0000, 0x792a, 0x6063, 0x0001, 0x607f, 0x000f, 0x60a3, + 0x0000, 0x60a4, 0x60ae, 0x60b2, 0x60d0, 0xd0b4, 0x0160, 0xc0b4, + 0x60d2, 0x00c6, 0x60b4, 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, + 0x8001, 0x601a, 0x00ce, 0x60d0, 0xa084, 0x7eff, 0x60d2, 0x78ac, + 0xc08d, 0x78ae, 0x83ff, 0x0108, 0x0005, 0x681b, 0x0054, 0x2091, + 0x8001, 0x0005, 0x73cc, 0x080c, 0x1879, 0x69ec, 0x6a48, 0xa185, + 0x1800, 0x684a, 0xa185, 0x0040, 0x68ee, 0x73cc, 0x2021, 0x0004, + 0x20a9, 0x09ff, 0x1f04, 0x191a, 0x8421, 0x1dd0, 0x8319, 0x1db0, + 0x69ee, 0x6a4a, 0x2091, 0x8001, 0x0005, 0xd7fc, 0x1118, 0x2069, + 0x4740, 0x0010, 0x2069, 0x4780, 0x71c4, 0x71c6, 0x6916, 0x81ff, + 0x1110, 0x68a3, 0x0001, 0x78ac, 0xc08c, 0x78ae, 0xd084, 0x1110, + 0x080c, 0x1c6a, 0x0005, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0010, + 0xa02e, 0x2520, 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, + 0x2079, 0x4700, 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x080c, 0x1b67, + 0x0904, 0x1a4c, 0x20a9, 0x0005, 0x20a1, 0x4714, 0x2091, 0x8000, + 0x41a1, 0x2091, 0x8001, 0x2009, 0x0040, 0x080c, 0x1d33, 0x0120, + 0x080c, 0x1b6f, 0x0804, 0x1a4c, 0x6004, 0xa08c, 0x00ff, 0xa18e, + 0x0009, 0x1120, 0x0006, 0x080c, 0x206e, 0x000e, 0xa084, 0xff00, + 0x8007, 0x8009, 0x0904, 0x19f0, 0x00c6, 0x2c68, 0x080c, 0x1b67, + 0x05a8, 0x2c00, 0x689e, 0x8109, 0x1dc0, 0x609f, 0x0000, 0x00ce, + 0x00c6, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040, 0xa399, + 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda, 0x7bd6, + 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0904, 0x19ef, 0x2009, 0x0040, + 0x080c, 0x1d33, 0x15a0, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, + 0x1168, 0x6004, 0xa084, 0x00ff, 0xa086, 0x000a, 0x1120, 0x0016, + 0x080c, 0x206b, 0x001e, 0x2d00, 0x6002, 0x0898, 0x00ce, 0x00c6, + 0x609c, 0x080c, 0x1be3, 0x00ce, 0x609f, 0x0000, 0x080c, 0x1a50, + 0x2009, 0x0018, 0x6008, 0xc0cd, 0x600a, 0x6004, 0x6086, 0x7810, + 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812, 0x080c, + 0x1b24, 0x000e, 0x7812, 0x080c, 0x1b6f, 0x0804, 0x1a4c, 0x00ce, + 0x00c6, 0x609c, 0x080c, 0x1be3, 0x00ce, 0x609f, 0x0000, 0x080c, + 0x1a50, 0x2009, 0x0018, 0x6087, 0x0103, 0x601b, 0x0003, 0x7810, + 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812, 0x080c, + 0x1b24, 0x000e, 0x7812, 0x080c, 0x1b6f, 0x0804, 0x1a4c, 0x00ce, + 0x6114, 0xd1fc, 0x0120, 0x080c, 0x1b19, 0x01f0, 0x0018, 0x080c, + 0x1b0e, 0x01d0, 0x080c, 0x1a50, 0x2009, 0x0018, 0x6087, 0x0103, + 0x601b, 0x0021, 0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, + 0xc0c5, 0x7812, 0x080c, 0x1b24, 0x000e, 0x7812, 0x080c, 0x1b6f, + 0x2001, 0x4007, 0x0804, 0x13bc, 0x74c4, 0x73c8, 0x72cc, 0x6014, + 0x2091, 0x8000, 0x00e6, 0x2009, 0x0012, 0xd0fc, 0x1118, 0x2071, + 0x4740, 0x0018, 0x2071, 0x4780, 0xc1fd, 0x792a, 0x7063, 0x0005, + 0x71d0, 0xc1c4, 0x71d2, 0x7366, 0x726a, 0x746e, 0x7072, 0x7077, + 0x0000, 0x2c00, 0x707a, 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, + 0x0110, 0x080c, 0x3fd3, 0x00ee, 0x6596, 0x65a6, 0x669a, 0x66aa, + 0x60af, 0x0000, 0x60b3, 0x0000, 0x6714, 0x6023, 0x0000, 0x080c, + 0x22bd, 0x2091, 0x8001, 0x0005, 0x70c3, 0x4005, 0x0804, 0x13bd, + 0x20a9, 0x0005, 0x2099, 0x4714, 0x2091, 0x8000, 0x530a, 0x2091, + 0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, + 0x0000, 0x0005, 0x71c4, 0x70c7, 0x0000, 0x791e, 0x0804, 0x13ba, + 0x71c4, 0x71c6, 0x2168, 0x0010, 0x2069, 0x1000, 0x690c, 0xa016, + 0x2d04, 0xa210, 0x8d68, 0x8109, 0x1dd8, 0xa285, 0x0000, 0x1118, + 0x70c3, 0x4000, 0x0010, 0x70c3, 0x4003, 0x70ca, 0x0804, 0x13bd, + 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x1a04, 0x13b3, 0x7966, + 0x0804, 0x13ba, 0x7964, 0x71c6, 0x0804, 0x13ba, 0x7900, 0x71c6, + 0x71c4, 0x7902, 0x0804, 0x13ba, 0x7900, 0x71c6, 0x0804, 0x13ba, + 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0160, 0x810c, 0x0230, + 0x8210, 0x810c, 0x810c, 0x0210, 0x8210, 0x810c, 0x81ff, 0x1904, + 0x13b4, 0x8210, 0x7a0e, 0xd28c, 0x0538, 0x7910, 0xc1cd, 0x7912, + 0x2009, 0x0021, 0x2019, 0x0003, 0xd284, 0x01c0, 0x8108, 0x2019, + 0x0041, 0x2011, 0x8f4e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, + 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, + 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x8f53, + 0x2112, 0x2011, 0x8f73, 0x2312, 0x7904, 0x7806, 0x0804, 0x13b9, + 0x7804, 0x70c6, 0x0804, 0x13ba, 0x71c4, 0xd1fc, 0x1118, 0x2011, + 0x4bc0, 0x0010, 0x2011, 0x4c40, 0x8107, 0xa084, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa268, 0x2011, 0x0000, 0x6814, 0xd0fc, 0x0110, + 0xa295, 0x0200, 0xd0b4, 0x0110, 0xa295, 0x0001, 0x6b0c, 0x6800, + 0x70da, 0x0804, 0x13b7, 0x7814, 0xd0f4, 0x0130, 0x2001, 0x4007, + 0x70db, 0x0000, 0xa005, 0x0048, 0xd0fc, 0x0130, 0x2001, 0x4007, + 0x70db, 0x0001, 0xa005, 0x0008, 0xa006, 0x0005, 0x7814, 0xd0f4, + 0x0130, 0x2001, 0x4007, 0x70db, 0x0000, 0xa005, 0x0008, 0xa006, + 0x0005, 0x7814, 0xd0fc, 0x0130, 0x2001, 0x4007, 0x70db, 0x0001, + 0xa005, 0x0008, 0xa006, 0x0005, 0x7112, 0x721a, 0x731e, 0x7810, + 0xd0c4, 0x0110, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, + 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, + 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0140, 0x810f, + 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, + 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, 0x7d10, + 0xd5c4, 0x0120, 0x7b84, 0xa319, 0x7c80, 0xa421, 0x7008, 0xd0fc, + 0x0de8, 0x7003, 0x0001, 0x7007, 0x0006, 0x711a, 0x721e, 0x7d10, + 0xd5c4, 0x0110, 0x7322, 0x7426, 0xa084, 0x01e0, 0x0005, 0x7848, + 0xa065, 0x0120, 0x2c04, 0x784a, 0x2063, 0x0000, 0x0005, 0x00f6, + 0x2079, 0x4700, 0x7848, 0x2062, 0x2c00, 0xa005, 0x1110, 0x080c, + 0x255d, 0x784a, 0x00fe, 0x0005, 0x2011, 0x9100, 0x7a4a, 0x7bc4, + 0x8319, 0x0128, 0xa280, 0x0032, 0x2012, 0x2010, 0x0cc8, 0x2013, + 0x0000, 0x0005, 0x0016, 0x0026, 0xd7fc, 0x1118, 0x2011, 0x4cc0, + 0x0010, 0x2011, 0x6cc0, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, + 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa268, 0x002e, + 0x001e, 0x0005, 0x0c39, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, + 0xa084, 0xf9ef, 0xa80d, 0x690a, 0x00e6, 0xd7fc, 0x1128, 0x2009, + 0x4752, 0x2071, 0x4740, 0x0020, 0x2009, 0x4792, 0x2071, 0x4780, + 0x210c, 0x6804, 0xa005, 0x0148, 0xa116, 0x1138, 0x2060, 0x6000, + 0x6806, 0x0016, 0x200b, 0x0000, 0x0018, 0x2009, 0x0000, 0x0016, + 0x6804, 0xa065, 0x0178, 0x6000, 0x6806, 0x0421, 0x080c, 0x1da4, + 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x6812, 0x1d88, 0x7910, + 0xc1a5, 0x7912, 0x001e, 0x6902, 0x6906, 0x2d00, 0x2060, 0x080c, + 0x26a4, 0x00ee, 0x0005, 0xa065, 0x0160, 0x2008, 0x609c, 0xa005, + 0x0128, 0x2062, 0x609f, 0x0000, 0xa065, 0x0cc0, 0x7848, 0x794a, + 0x2062, 0x0005, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, + 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, + 0x682c, 0x6022, 0x0005, 0x00e6, 0xd7fc, 0x1128, 0x2071, 0x4740, + 0x2031, 0x47c0, 0x0020, 0x2071, 0x4780, 0x2031, 0x49c0, 0x704c, + 0xa08c, 0x0200, 0x1128, 0xa608, 0x2d0a, 0x8000, 0x704e, 0xa006, + 0x00ee, 0x0005, 0x00f6, 0xd7fc, 0x1118, 0x2079, 0x4740, 0x0010, + 0x2079, 0x4780, 0x080c, 0x1b8a, 0x2091, 0x8000, 0x6804, 0x780a, + 0xa065, 0x05f0, 0x0030, 0x2c00, 0x780a, 0x2060, 0x6000, 0xa065, + 0x05b8, 0x6010, 0xa306, 0x1db8, 0x600c, 0xa206, 0x1da0, 0x2c28, + 0x7848, 0xac06, 0x1108, 0x0448, 0x6804, 0xac06, 0x1140, 0x6000, + 0x2060, 0x6806, 0xa005, 0x1118, 0x6803, 0x0000, 0x0048, 0x6400, + 0x7808, 0x2060, 0x6402, 0xa486, 0x0000, 0x1110, 0x2c00, 0x6802, + 0x2560, 0x080c, 0x1bf2, 0x601b, 0x0005, 0x6023, 0x0020, 0x00fe, + 0x080c, 0x1da4, 0x00f6, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, + 0x6812, 0x1118, 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, + 0x00fe, 0x0005, 0x0076, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0108, + 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, + 0x8000, 0x080c, 0x1ba2, 0x8738, 0xa784, 0x001f, 0x1dd0, 0xa7bc, + 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d90, 0x2091, + 0x8001, 0x007e, 0x0005, 0x786c, 0x2009, 0x8f74, 0x210c, 0xa10d, + 0x0118, 0xa065, 0x0804, 0x2089, 0x2061, 0x0000, 0x6018, 0xd084, + 0x11b8, 0x7810, 0xd08c, 0x0130, 0xc08c, 0x7812, 0xc7fc, 0x2069, + 0x4740, 0x0028, 0xc08d, 0x7812, 0x2069, 0x4780, 0xc7fd, 0x2091, + 0x8000, 0x681c, 0x681f, 0x0000, 0x2091, 0x8001, 0xa005, 0x1108, + 0x0005, 0xa08c, 0xfff0, 0x0110, 0x080c, 0x255d, 0x0002, 0x1cc7, + 0x1cca, 0x1cd0, 0x1cd4, 0x1cc8, 0x1cd8, 0x1cc8, 0x1cc8, 0x1cc8, + 0x1cde, 0x1d0a, 0x1d0d, 0x1d12, 0x1d1b, 0x1cc8, 0x1cc8, 0x0005, + 0x080c, 0x255d, 0x080c, 0x1c6a, 0x2001, 0x8001, 0x0804, 0x1d24, + 0x2001, 0x8003, 0x0804, 0x1d24, 0x2001, 0x8004, 0x0804, 0x1d24, + 0x080c, 0x1c6a, 0x2001, 0x8006, 0x0804, 0x1d24, 0x2091, 0x8000, + 0x0076, 0xd7fc, 0x1128, 0x2069, 0x4740, 0x2039, 0x0009, 0x0020, + 0x2069, 0x4780, 0x2039, 0x0009, 0x6800, 0xa086, 0x0000, 0x0128, + 0x000e, 0x6f1e, 0x2091, 0x8001, 0x0005, 0x6870, 0x007e, 0xa0bc, + 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x080c, + 0x1ba2, 0x8738, 0xa784, 0x001f, 0x1dd0, 0x2091, 0x8001, 0x2001, + 0x800a, 0x00d0, 0x2001, 0x800c, 0x00b8, 0x080c, 0x1c6a, 0x2001, + 0x800d, 0x0090, 0xd7fc, 0x0110, 0x78e4, 0x0008, 0x78e0, 0x70c6, + 0x2001, 0x800e, 0x0048, 0xd7fc, 0x0110, 0x78ec, 0x0008, 0x78e8, + 0x70c6, 0x2001, 0x800f, 0x0000, 0x70c2, 0xd7fc, 0x1118, 0x70db, + 0x0000, 0x0010, 0x70db, 0x0001, 0x2061, 0x0000, 0x601b, 0x0001, + 0x2091, 0x4080, 0x0005, 0xac80, 0x0001, 0x81ff, 0x0518, 0x2099, + 0x0030, 0x20a0, 0x700c, 0xa084, 0x07ff, 0x0100, 0x7018, 0x0006, + 0x701c, 0x0006, 0x7020, 0x0006, 0x7024, 0x0006, 0x7112, 0x81ac, + 0x721a, 0x731e, 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, + 0x7008, 0x800b, 0x1ee8, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x1110, + 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x000e, 0x7026, + 0x000e, 0x7022, 0x000e, 0x701e, 0x000e, 0x701a, 0x0005, 0x2011, + 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x681f, 0x0201, 0x6803, + 0xfd20, 0x6807, 0x0038, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, + 0x0004, 0x8109, 0x1d80, 0x0005, 0x70ec, 0xd0dc, 0x1520, 0x2029, + 0x0001, 0x7814, 0xd0cc, 0x1160, 0x70ec, 0xd0e4, 0x2019, 0x0c0a, + 0x2021, 0x000a, 0x1120, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x0070, + 0x70ec, 0xd0e4, 0x1128, 0x2019, 0x180c, 0x2021, 0x000c, 0x0030, + 0x2019, 0x1809, 0x2021, 0x0009, 0xa5ad, 0x0200, 0x6b0a, 0x6c0e, + 0x6d1e, 0x6807, 0x0038, 0x0005, 0x6004, 0x6086, 0x2c08, 0x2063, + 0x0000, 0x7868, 0xa005, 0x796a, 0x0110, 0x2c02, 0x0008, 0x796e, + 0x0005, 0x00c6, 0x2061, 0x4700, 0x6887, 0x0103, 0x2d08, 0x206b, + 0x0000, 0x6068, 0xa005, 0x616a, 0x0110, 0x2d02, 0x0008, 0x616e, + 0x00ce, 0x0005, 0x2091, 0x8000, 0x2c04, 0x786e, 0xa005, 0x1108, + 0x786a, 0x2091, 0x8001, 0x609c, 0xa005, 0x0188, 0x00c6, 0x2060, + 0x2008, 0x609c, 0xa005, 0x0138, 0x2062, 0x609f, 0x0000, 0xa065, + 0x609c, 0xa005, 0x1dc8, 0x7848, 0x794a, 0x2062, 0x00ce, 0x7848, + 0x2062, 0x609f, 0x0000, 0xac85, 0x0000, 0x1110, 0x080c, 0x255d, + 0x784a, 0x0005, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, + 0x1208, 0xa200, 0x1f04, 0x1dee, 0x8086, 0x818e, 0x0005, 0x0156, + 0x20a9, 0x0010, 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, 0x818d, + 0x0228, 0xa11a, 0x1220, 0x1f04, 0x1dfe, 0x0028, 0xa11a, 0x2308, + 0x8210, 0x1f04, 0x1dfe, 0x0006, 0x3200, 0xa084, 0xefff, 0x2080, + 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0xa085, 0x1000, 0x0cb8, + 0x7d74, 0x70d0, 0xa506, 0x0904, 0x1ecc, 0x7810, 0x2050, 0x080c, + 0x1b67, 0x0904, 0x1ecc, 0xa046, 0x7970, 0x2500, 0x8000, 0xa112, + 0x2009, 0x0040, 0x1208, 0x0030, 0x72d0, 0xa206, 0x0118, 0x8840, + 0x2009, 0x0080, 0x00c6, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, + 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, + 0x0110, 0x080c, 0x1b67, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002, + 0x2091, 0x8001, 0xa08c, 0x01e0, 0x1538, 0x53a5, 0x8cff, 0x1120, + 0x88ff, 0x0904, 0x1eb9, 0x0050, 0x2c00, 0x788e, 0x20a9, 0x0020, + 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0804, 0x1eb9, 0xa046, 0x7218, + 0x731c, 0xdac4, 0x0110, 0x7420, 0x7524, 0xa292, 0x0040, 0xa39b, + 0x0000, 0xa4a3, 0x0000, 0xa5ab, 0x0000, 0x721a, 0x731e, 0xdac4, + 0x0118, 0x7422, 0x7526, 0xa006, 0x7007, 0x0004, 0x0904, 0x1eb9, + 0x8cff, 0x0110, 0x080c, 0x1b6f, 0x00ce, 0x080c, 0x1b6f, 0xa046, + 0x7888, 0x8000, 0x788a, 0xa086, 0x0002, 0x01c0, 0x7a7c, 0x7b78, + 0xdac4, 0x0110, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, + 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, + 0x731e, 0xdac4, 0x0588, 0x7422, 0x7526, 0x0470, 0x6014, 0xd0fc, + 0x1118, 0x2069, 0x4740, 0x0010, 0x2069, 0x4780, 0x2091, 0x8000, + 0x681f, 0x0002, 0x88ff, 0x0120, 0xa046, 0x788c, 0x2060, 0x0c70, + 0x788b, 0x0000, 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, + 0x0098, 0x00ce, 0x788b, 0x0000, 0x080c, 0x2044, 0x6004, 0xa084, + 0x000f, 0x0059, 0x88ff, 0x0130, 0x788c, 0x2060, 0x6004, 0xa084, + 0x000f, 0x0019, 0x0804, 0x1e18, 0x0005, 0x0002, 0x1ede, 0x1ef9, + 0x1f12, 0x1ede, 0x1f1f, 0x1eef, 0x1ede, 0x1ede, 0x1ede, 0x1ef7, + 0x1f10, 0x1ede, 0x1ede, 0x1ede, 0x1ede, 0x1ede, 0x2039, 0x0400, + 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, 0x080c, 0x1f5b, + 0x609c, 0x78ba, 0x609f, 0x0000, 0x080c, 0x2030, 0x0005, 0x78bc, + 0xd0c4, 0x0108, 0x0c58, 0x601c, 0xc0bd, 0x601e, 0x0030, 0x080c, + 0x206e, 0x78bc, 0xd0c4, 0x0108, 0x0c08, 0x78bf, 0x0000, 0x6004, + 0x8007, 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0138, 0x080c, 0x1f5b, + 0x0120, 0x78bc, 0xc0c5, 0x78be, 0x0010, 0x0804, 0x1f76, 0x0005, + 0x080c, 0x206b, 0x78bc, 0xa08c, 0x0e00, 0x1110, 0xd0c4, 0x1108, + 0x0828, 0x080c, 0x1f5b, 0x1110, 0x0804, 0x1f76, 0x0005, 0x78bc, + 0xd0c4, 0x0110, 0x0804, 0x1ede, 0x78bf, 0x0000, 0x6714, 0x2011, + 0x0001, 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0188, 0xa7bc, + 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0150, 0xa7bc, 0x8000, + 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0108, 0x00c0, + 0x080c, 0x1b8a, 0x2d00, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, + 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, + 0x8001, 0x1f04, 0x1f43, 0x8211, 0x0118, 0x20a9, 0x0100, 0x0c58, + 0x080c, 0x1b6f, 0x0005, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, + 0x78b6, 0x1110, 0x78ba, 0x0038, 0x689e, 0x2d00, 0x6002, 0x78b8, + 0xad06, 0x1108, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x1130, 0x78bc, + 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x0005, 0x00e6, 0xa02e, + 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, 0x2048, + 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0110, 0x080c, 0x3fd3, + 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, 0x4780, 0xd7fc, + 0x1110, 0x2071, 0x4740, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, + 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x71c0, 0xa168, + 0x2700, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0x71c4, + 0xa100, 0x60c2, 0x2091, 0x8000, 0x7814, 0xd0c4, 0x0138, 0xd7fc, + 0x1118, 0xd0f4, 0x1140, 0x0010, 0xd0fc, 0x1128, 0x6e08, 0xd684, + 0x01f0, 0xd9fc, 0x11e0, 0x2091, 0x8001, 0x080c, 0x1bf2, 0x2091, + 0x8000, 0x080c, 0x1da4, 0x2091, 0x8001, 0x7814, 0xd0c4, 0x0904, + 0x202e, 0xd7fc, 0x1120, 0xd0f4, 0x1130, 0x0804, 0x202e, 0xd0fc, + 0x1110, 0x0804, 0x202e, 0x601b, 0x0021, 0x0804, 0x202e, 0x6024, + 0xa096, 0x0001, 0x1110, 0x8000, 0x6026, 0x6a10, 0x6814, 0xa202, + 0x0268, 0x0160, 0x2091, 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, + 0x609f, 0x0000, 0x080c, 0x2030, 0x0804, 0x202e, 0x2c08, 0xd9fc, + 0x01f0, 0x6800, 0xa065, 0x01d8, 0x6a04, 0x7000, 0xa084, 0x0002, + 0x0168, 0x7048, 0xa206, 0x1150, 0x6b04, 0x2160, 0x2304, 0x6002, + 0xa005, 0x1108, 0x6902, 0x2260, 0x6102, 0x0098, 0x2d00, 0x2060, + 0x080c, 0x26a4, 0x6e08, 0x2160, 0x6202, 0x6906, 0x0050, 0x6800, + 0x6902, 0xa065, 0x0110, 0x6102, 0x0008, 0x6906, 0x2160, 0x6003, + 0x0000, 0x2160, 0xd9fc, 0x0118, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, + 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, + 0x0128, 0xa6b6, 0x0040, 0x6e0a, 0x080c, 0x1c03, 0x00ee, 0x0005, + 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x080c, 0x1da4, 0x2091, + 0x8001, 0x78b8, 0xa065, 0x0128, 0x609c, 0x78ba, 0x609f, 0x0000, + 0x0c78, 0x78b6, 0x78ba, 0x0005, 0x7970, 0x7874, 0x2818, 0xd384, + 0x0118, 0x8000, 0xa112, 0x0220, 0x8000, 0xa112, 0x1278, 0xc384, + 0x7a7c, 0x721a, 0x7a78, 0x721e, 0xdac4, 0x0120, 0x7a84, 0x7222, + 0x7a80, 0x7226, 0xa006, 0xd384, 0x0108, 0x8000, 0x7876, 0x70d2, + 0x781c, 0xa005, 0x0138, 0x8001, 0x781e, 0x1120, 0x0e04, 0x206a, + 0x2091, 0x4080, 0x0005, 0x2039, 0x2080, 0x0010, 0x2039, 0x2086, + 0x2704, 0xa005, 0x0160, 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, + 0x680a, 0x690c, 0x6814, 0x6916, 0x680e, 0x8738, 0x0c88, 0x0005, + 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, + 0x0000, 0x2041, 0x0000, 0x780c, 0x0002, 0x2232, 0x220d, 0x2091, + 0x2101, 0x2039, 0x8f74, 0x2734, 0x7d10, 0x00c0, 0x6084, 0xa086, + 0x0103, 0x1904, 0x20eb, 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, + 0x11d8, 0x0804, 0x20eb, 0x8603, 0xa080, 0x8f55, 0x620c, 0x2202, + 0x8000, 0x6210, 0x2202, 0x080c, 0x1dc2, 0x8630, 0xa68e, 0x000f, + 0x0904, 0x216c, 0x786c, 0xa065, 0x1d08, 0x7808, 0xa602, 0x1220, + 0xd5ac, 0x1110, 0x263a, 0x0005, 0xa682, 0x0003, 0x1a04, 0x216c, + 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x11f8, 0x2011, + 0x8f55, 0x2204, 0x70c6, 0x8210, 0x2204, 0x70ca, 0xd684, 0x1130, + 0x8210, 0x2204, 0x70da, 0x8210, 0x2204, 0x70de, 0xa685, 0x8020, + 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, + 0x7812, 0x2091, 0x8001, 0x203b, 0x0000, 0x0005, 0x7810, 0xc0ad, + 0x7812, 0x0804, 0x216c, 0x263a, 0x080c, 0x2238, 0x1904, 0x2254, + 0x786c, 0xa065, 0x1904, 0x2096, 0x2091, 0x8000, 0x7810, 0xa084, + 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0804, + 0x2254, 0x2039, 0x8f74, 0x2734, 0x7d10, 0x00a0, 0x6084, 0xa086, + 0x0103, 0x1904, 0x2156, 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, + 0x11b8, 0x0804, 0x2156, 0xa680, 0x8f55, 0x620c, 0x2202, 0x080c, + 0x1dc2, 0x8630, 0xa68e, 0x001e, 0x0904, 0x216c, 0x786c, 0xa065, + 0x1d28, 0x7808, 0xa602, 0x1220, 0xd5ac, 0x1110, 0x263a, 0x0005, + 0xa682, 0x0006, 0x1a04, 0x216c, 0x2091, 0x8000, 0x2069, 0x0000, + 0x6818, 0xd084, 0x11f8, 0x2011, 0x8f55, 0x2009, 0x8f4e, 0x26a8, + 0x211c, 0x2204, 0x201a, 0x8108, 0x8210, 0x1f04, 0x2138, 0xa685, + 0x8030, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, + 0xffcf, 0x7812, 0x2091, 0x8001, 0xa006, 0x2009, 0x8f75, 0x200a, + 0x203a, 0x0005, 0x7810, 0xc0ad, 0x7812, 0x00b0, 0x263a, 0x080c, + 0x2238, 0x1904, 0x2254, 0x786c, 0xa065, 0x1904, 0x2106, 0x2091, + 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, + 0x2091, 0x8001, 0x0804, 0x2254, 0x2091, 0x8000, 0x7007, 0x0004, + 0x7994, 0x70d4, 0xa102, 0x0228, 0x0168, 0x7b90, 0xa302, 0x1150, + 0x0010, 0x8002, 0x1138, 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, + 0x8001, 0x0005, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, + 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, + 0x7a9c, 0xa210, 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, + 0x0130, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, + 0x0030, 0x7003, 0x0000, 0x2009, 0x8f54, 0x260a, 0x8109, 0x2198, + 0x2104, 0xd084, 0x0108, 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, + 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a, + 0x1208, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, 0x0140, 0x810f, + 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, + 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, 0xd4c4, + 0x0120, 0x7b84, 0xa319, 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0de8, + 0xa084, 0x01e0, 0x01d0, 0x7d10, 0x2031, 0x8f54, 0x2634, 0x78a8, + 0x8000, 0x78aa, 0xd08c, 0x1138, 0x7007, 0x0006, 0x7004, 0xd094, + 0x1de8, 0x0804, 0x216e, 0x2069, 0x4747, 0x206b, 0x0003, 0x78ac, + 0xa085, 0x0300, 0x78ae, 0xa006, 0x0048, 0x2030, 0x75d6, 0x2091, + 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091, 0x8001, + 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, 0x711a, 0x721e, + 0xd5c4, 0x0110, 0x7322, 0x7426, 0x0005, 0x6084, 0xa086, 0x0103, + 0x11d8, 0x6114, 0x6018, 0xa105, 0x11b8, 0x2069, 0x0000, 0x6818, + 0xd084, 0x1190, 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, + 0x681b, 0x0001, 0x2091, 0x4080, 0x080c, 0x1dc2, 0x0e04, 0x222b, + 0x786c, 0xa065, 0x1d10, 0x0005, 0x0059, 0x1530, 0x786c, 0xa065, + 0x19e0, 0x0410, 0x0029, 0x1500, 0x786c, 0xa065, 0x1dd8, 0x00e0, + 0x6084, 0xa086, 0x0103, 0x1168, 0x6018, 0xc0fc, 0x601a, 0xa086, + 0x0004, 0x1138, 0x7804, 0xd0a4, 0x0120, 0x080c, 0x1dc2, 0xa006, + 0x0005, 0x0079, 0x1118, 0xa085, 0x0001, 0x0005, 0x00b9, 0x1110, + 0x2041, 0x0001, 0x7d10, 0x0005, 0x88ff, 0x0110, 0x2091, 0x4080, + 0x0005, 0x7b90, 0x7994, 0x70d4, 0xa102, 0x1118, 0xa385, 0x0000, + 0x0005, 0x0210, 0xa302, 0x0005, 0x8002, 0x0005, 0xa184, 0xff00, + 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, + 0x0018, 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, + 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, + 0xa005, 0x0110, 0x2009, 0x0040, 0x080c, 0x1b24, 0x01d0, 0x78a8, + 0x8000, 0x78aa, 0xd08c, 0x1510, 0x6014, 0xd0fc, 0x1118, 0x2069, + 0x4740, 0x0010, 0x2069, 0x4780, 0x2091, 0x8000, 0x681f, 0x0003, + 0x78ab, 0x0000, 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, + 0x0068, 0x78ab, 0x0000, 0x080c, 0x1dc2, 0x7990, 0x7894, 0x8000, + 0xa10a, 0x1208, 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, + 0x2091, 0x8001, 0x0005, 0xd7fc, 0x1118, 0x2009, 0x4758, 0x0010, + 0x2009, 0x4798, 0x2091, 0x8000, 0x200a, 0x00f6, 0x2009, 0x4780, + 0x2079, 0x0100, 0xd7fc, 0x1120, 0x2009, 0x4740, 0x2079, 0x0200, + 0x2104, 0xa086, 0x0000, 0x1180, 0xd7fc, 0x1118, 0x2009, 0x4745, + 0x0010, 0x2009, 0x4785, 0x2104, 0xa005, 0x1130, 0x7830, 0xa084, + 0x00c0, 0x1110, 0x781b, 0x0052, 0x00fe, 0x0005, 0x2009, 0x0002, + 0x2069, 0x4700, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x2333, + 0x2071, 0x4780, 0x2079, 0x0100, 0x2021, 0x49bf, 0x784b, 0x000f, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, 0x2019, 0x3e21, 0x0030, + 0x20a1, 0x012b, 0x2019, 0x3e21, 0xd184, 0x0110, 0x20a1, 0x022b, + 0x2304, 0xa005, 0x0140, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, + 0x53a6, 0x3318, 0x0ca8, 0x789b, 0x0000, 0x789b, 0x0020, 0x20a9, + 0x0010, 0x78af, 0x0000, 0x78af, 0x2020, 0x1f04, 0x2311, 0x7003, + 0x0000, 0x0016, 0xd18c, 0x2009, 0x0000, 0x0108, 0xc1bd, 0x080c, + 0x2454, 0x001e, 0x7020, 0xa084, 0x000f, 0xa085, 0x6300, 0x7806, + 0x780f, 0x9000, 0x7843, 0x00d8, 0x7853, 0x0090, 0x780b, 0x2f08, + 0x7452, 0x704f, 0x0000, 0x8109, 0x0140, 0x2071, 0x4740, 0x2079, + 0x0200, 0x2021, 0x47bf, 0x0804, 0x22ee, 0x080c, 0x250e, 0x0005, + 0x0016, 0x2011, 0x0101, 0xd1bc, 0x1110, 0x2011, 0x0201, 0xa18c, + 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x001e, 0x080c, + 0x2454, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110, 0x2011, 0x0201, + 0x20a9, 0x0009, 0x810b, 0x1f04, 0x235a, 0xa18c, 0x0e00, 0x2204, + 0xa084, 0xf1ff, 0xa105, 0x2012, 0x0005, 0x2019, 0x0002, 0x2009, + 0x0101, 0x20a9, 0x0005, 0x8213, 0x1f04, 0x236b, 0xa294, 0x00e0, + 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x8319, 0x0118, 0x2009, + 0x0201, 0x0c78, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110, 0x2011, + 0x0201, 0x20a9, 0x000c, 0x810b, 0x1f04, 0x2383, 0xa18c, 0xf000, + 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x0005, 0x2011, 0x0102, + 0xd3fc, 0x1110, 0x2011, 0x0202, 0x2204, 0xa09c, 0x0f30, 0xa084, + 0xf0cf, 0xa105, 0x2012, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, + 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, + 0x609a, 0x62ac, 0x63ac, 0x00ce, 0x0005, 0x00c6, 0x2061, 0x0100, + 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, + 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x00ce, 0x0005, + 0x00c6, 0x2061, 0x0100, 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, + 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, 0xa28c, 0x0020, + 0x0118, 0xc2ac, 0xa39d, 0x4000, 0xc3ec, 0xd3b4, 0x1108, 0xc3ed, + 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x00ce, 0x0005, 0x2091, + 0x8000, 0x00c6, 0x00e6, 0x6818, 0xa005, 0x0904, 0x2438, 0xd1fc, + 0x0118, 0x2061, 0x8ed0, 0x0010, 0x2061, 0x8dc0, 0x080c, 0x2440, + 0x0560, 0x20a9, 0x0101, 0xd1fc, 0x0118, 0x2061, 0x8dd0, 0x0010, + 0x2061, 0x8cc0, 0x00c6, 0x080c, 0x2440, 0x0128, 0x00ce, 0x8c60, + 0x1f04, 0x23fa, 0x04a8, 0x000e, 0xd1fc, 0x0128, 0xa082, 0x8dd0, + 0x2071, 0x4780, 0x0020, 0xa082, 0x8cc0, 0x2071, 0x4740, 0x7076, + 0x7172, 0x2138, 0x2001, 0x0004, 0x7062, 0x707f, 0x000f, 0x71d0, + 0xc1c4, 0x71d2, 0x080c, 0x22b3, 0x00c0, 0xd1fc, 0x1118, 0x2071, + 0x4740, 0x0010, 0x2071, 0x4780, 0x6020, 0xc0dd, 0x6022, 0x7172, + 0x2138, 0x2c00, 0x707a, 0x2001, 0x0006, 0x7062, 0x707f, 0x000f, + 0x71d0, 0xc1c4, 0x71d2, 0x080c, 0x22b3, 0x2001, 0x0000, 0x0010, + 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x00ee, 0x00ce, 0x0005, + 0x2c04, 0xa005, 0x0170, 0x2060, 0x6010, 0xa306, 0x1140, 0x600c, + 0xa206, 0x1128, 0x6014, 0xa106, 0x1110, 0xa006, 0x0020, 0x6000, + 0x0c80, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x0016, 0x2079, + 0x4780, 0x2071, 0x0100, 0xd1bc, 0x1120, 0x2079, 0x4740, 0x2071, + 0x0200, 0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x1110, 0x001e, + 0x0060, 0x810b, 0x810b, 0x810b, 0x810b, 0x000e, 0xa18d, 0x0800, + 0xd0bc, 0x1110, 0xa18d, 0x0f00, 0x2104, 0x00ee, 0x00fe, 0x0005, + 0x2001, 0x4701, 0x2004, 0xd0ac, 0x1138, 0x68e4, 0xd0ac, 0x0120, + 0xa084, 0x0006, 0x1108, 0x0009, 0x0005, 0x6014, 0x00e6, 0x0036, + 0x2018, 0x2071, 0x4c40, 0xd0fc, 0x1110, 0x2071, 0x4bc0, 0x8007, + 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, 0xa084, + 0x000a, 0x1904, 0x250b, 0x7108, 0xa194, 0xff00, 0x0904, 0x250b, + 0xa18c, 0x00ff, 0x701c, 0xa084, 0xff00, 0x01c0, 0x7004, 0xa085, + 0x003a, 0x7006, 0x2001, 0x0009, 0xa102, 0x16d8, 0x2001, 0x000a, + 0xa102, 0x16d0, 0x2001, 0x000c, 0xa102, 0x16c8, 0x701c, 0xa084, + 0x00ff, 0x701e, 0x7004, 0xa084, 0xffdf, 0x7006, 0x2001, 0x000a, + 0xa106, 0x01a8, 0x2001, 0x000c, 0xa106, 0x01a0, 0x2001, 0x0012, + 0xa106, 0x0198, 0x2001, 0x0014, 0xa106, 0x0190, 0x2001, 0x0019, + 0xa106, 0x0188, 0x2001, 0x0032, 0xa106, 0x0180, 0x00d8, 0x2009, + 0x000c, 0x00d0, 0x2009, 0x0012, 0x00b8, 0x2009, 0x0014, 0x00a0, + 0x2009, 0x0019, 0x0088, 0x2009, 0x0020, 0x0070, 0x2009, 0x003f, + 0x0058, 0x2009, 0x000a, 0x0040, 0x2009, 0x000c, 0x0028, 0x2009, + 0x0019, 0x0010, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, 0x7004, + 0xa085, 0x000a, 0x7006, 0x2071, 0x4700, 0x7004, 0xd0bc, 0x0158, + 0xd3fc, 0x1120, 0x73ea, 0x2071, 0x4740, 0x0018, 0x73ee, 0x2071, + 0x4780, 0x701f, 0x000d, 0x003e, 0x00ee, 0x0005, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x11d0, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, + 0x12a0, 0x2071, 0x0200, 0x71ec, 0xa18c, 0x1c00, 0x810f, 0x810c, + 0x810c, 0x2079, 0x0100, 0x78ec, 0xa084, 0x1c00, 0x8007, 0x8004, + 0x8004, 0xa105, 0xa08a, 0x0007, 0x0208, 0x0005, 0x0002, 0x255c, + 0x2543, 0x255c, 0x2543, 0x2536, 0x2550, 0x2536, 0x7008, 0xa084, + 0xc3ff, 0xa085, 0x3000, 0x700a, 0x7808, 0xa084, 0xc3ff, 0xa085, + 0x3000, 0x780a, 0x0005, 0x7008, 0xa084, 0xc3ff, 0xa085, 0x2000, + 0x700a, 0x7808, 0xa084, 0xc3ff, 0xa085, 0x2000, 0x780a, 0x0005, + 0x7008, 0xa084, 0xc3ff, 0xa085, 0x0c00, 0x700a, 0x7808, 0xa084, + 0xc3ff, 0xa085, 0x0c00, 0x780a, 0x0005, 0x0e04, 0x255d, 0x2091, + 0x8000, 0x2071, 0x0000, 0x0006, 0x7018, 0xd084, 0x1de8, 0x000e, + 0x2071, 0x0010, 0x70ca, 0x000e, 0x70c6, 0x70c3, 0x8002, 0x70db, + 0x0a04, 0x70df, 0x0022, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, + 0x4080, 0x0cf8, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708a, + 0x758e, 0x7492, 0x7696, 0x779a, 0xa594, 0x003f, 0xd4f4, 0x0138, + 0xd7bc, 0x1128, 0xa784, 0x007d, 0x1904, 0x3c86, 0x0871, 0xa49c, + 0x000f, 0xa382, 0x0004, 0x0320, 0xa3a6, 0x0007, 0x1930, 0x2418, + 0x8507, 0xa084, 0x000f, 0x0002, 0x2b5a, 0x2c45, 0x2c83, 0x2ee9, + 0x3267, 0x32be, 0x3364, 0x33f3, 0x34c7, 0x3599, 0x25af, 0x25ac, + 0x2981, 0x2a67, 0x323b, 0x25ac, 0x080c, 0x255d, 0x0005, 0xa006, + 0x0038, 0x7808, 0xc08d, 0x780a, 0xa006, 0x7002, 0x704a, 0x7042, + 0x70ce, 0x705c, 0xa005, 0x1904, 0x26fd, 0x7060, 0xa084, 0x0007, + 0x0002, 0x25c9, 0x2637, 0x263f, 0x2648, 0x2651, 0x26e3, 0x265a, + 0x2637, 0x7830, 0xd0bc, 0x1d10, 0x71d0, 0xd1bc, 0x19f8, 0xd1b4, + 0x1904, 0x2614, 0x70a0, 0xa086, 0x0001, 0x09c0, 0x70b0, 0xa06d, + 0x6800, 0xa065, 0xa055, 0x789b, 0x0080, 0x6b0c, 0x7baa, 0x6808, + 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0118, + 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0010, + 0x0804, 0x2830, 0x705c, 0xa005, 0x1904, 0x25ae, 0x00c6, 0x00d6, + 0x70b0, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0080, 0x6b0c, + 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, + 0x0001, 0x0118, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, + 0x2001, 0x0020, 0x0804, 0x2830, 0x080c, 0x3c45, 0x1904, 0x25ae, + 0x781b, 0x0068, 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x68bc, + 0x703e, 0xc1b4, 0x71d2, 0x70b4, 0xa065, 0x68c0, 0x7056, 0x7003, + 0x0002, 0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x0005, 0x080c, + 0x3c45, 0x1120, 0x781b, 0x0054, 0x7003, 0x0004, 0x0005, 0x080c, + 0x3c45, 0x1128, 0x2011, 0x000c, 0x0419, 0x7003, 0x0004, 0x0005, + 0x080c, 0x3c45, 0x1128, 0x2011, 0x0006, 0x00d1, 0x7003, 0x0004, + 0x0005, 0x080c, 0x3c45, 0x1128, 0x2011, 0x000d, 0x0089, 0x7003, + 0x0004, 0x0005, 0x080c, 0x3c45, 0x1150, 0x2011, 0x0006, 0x0041, + 0x7078, 0x707b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0004, 0x0005, + 0x7170, 0xc1fc, 0x8107, 0x7882, 0x789b, 0x0080, 0xa286, 0x000c, + 0x1120, 0x7aaa, 0x2001, 0x0001, 0x0098, 0xa18c, 0x001f, 0xa18d, + 0x00c0, 0x79aa, 0xa286, 0x000d, 0x0120, 0x7aaa, 0x2001, 0x0002, + 0x0038, 0x78ab, 0x0020, 0x7174, 0x79aa, 0x7aaa, 0x2001, 0x0004, + 0x789b, 0x0060, 0x78aa, 0x785b, 0x0004, 0x781b, 0x0113, 0x080c, + 0x3c58, 0x707f, 0x000f, 0x70d0, 0xd0b4, 0x0168, 0xc0b4, 0x70d2, + 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, + 0x8001, 0x601a, 0x00ce, 0x0005, 0x7014, 0xa005, 0x1138, 0x70d0, + 0xd0b4, 0x0128, 0x70b4, 0xac06, 0x1110, 0x0c29, 0x0005, 0x0016, + 0x71a0, 0xa186, 0x0001, 0x0528, 0x00d6, 0x0026, 0x2100, 0x2011, + 0x0001, 0xa212, 0x70b0, 0x2068, 0x6800, 0xac06, 0x0120, 0x8211, + 0x01b0, 0x00c9, 0x0cc8, 0x00c6, 0x2100, 0x2011, 0x0001, 0xa212, + 0x70b0, 0x2068, 0x6800, 0x2060, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x8211, 0x0110, 0x0041, 0x0cb0, 0x70a3, 0x0001, 0x00ce, 0x002e, + 0x00de, 0x001e, 0x0005, 0xade8, 0x0005, 0x70a8, 0xad06, 0x1110, + 0x70a4, 0x2068, 0x0005, 0x080c, 0x3c45, 0x1904, 0x25ae, 0x7078, + 0x2068, 0x7770, 0x080c, 0x3b81, 0x2c50, 0x080c, 0x3ce0, 0x789b, + 0x0080, 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, + 0x0001, 0x2001, 0x0004, 0x0804, 0x2835, 0x080c, 0x3c45, 0x1904, + 0x25ae, 0x789b, 0x0080, 0x705c, 0x2068, 0x6f14, 0x70d0, 0xd0b4, + 0x0168, 0xc0b4, 0x70d2, 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x080c, 0x3b81, + 0x2c50, 0x080c, 0x3ce0, 0x6824, 0xa005, 0x0130, 0xa082, 0x0006, + 0x0208, 0x0010, 0x6827, 0x0005, 0x6814, 0xa084, 0x001f, 0xc0bd, + 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, 0x0003, 0x0804, + 0x2835, 0xc28d, 0x72d2, 0x72bc, 0xa200, 0xa015, 0x7150, 0x8108, + 0xa12a, 0x0208, 0x71bc, 0x2164, 0x6504, 0x85ff, 0x1170, 0x7152, + 0x8421, 0x1da8, 0x70d0, 0xd08c, 0x0128, 0x70cc, 0xa005, 0x1110, + 0x70cf, 0x000a, 0x0005, 0x2200, 0x0c90, 0x70d0, 0xc08c, 0x70d2, + 0x70cf, 0x0000, 0x6034, 0xa005, 0x1db0, 0x6708, 0xa784, 0x073f, + 0x01d0, 0xd7d4, 0x1d80, 0xa784, 0x0021, 0x1d68, 0xa784, 0x0002, + 0x0130, 0xa784, 0x0004, 0x0d38, 0xa7bc, 0xfffb, 0x670a, 0xa784, + 0x0218, 0x1d08, 0xa784, 0x0100, 0x0130, 0x6018, 0xa005, 0x19d8, + 0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, 0x6e1c, 0xa684, + 0x000e, 0x6318, 0x0128, 0x601c, 0xa302, 0x0220, 0x0118, 0x0858, + 0x83ff, 0x1948, 0x2d58, 0x2c50, 0x7152, 0xd7bc, 0x1120, 0x7028, + 0x6022, 0x603a, 0x0010, 0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, + 0x6100, 0x2a60, 0x2041, 0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, + 0x00c0, 0xd1fc, 0x0110, 0xd684, 0x0110, 0xa39c, 0xffbf, 0xd6a4, + 0x0110, 0xa39d, 0x0020, 0xa684, 0x000e, 0x1904, 0x27e7, 0xc7a5, + 0x670a, 0x2c00, 0x68c6, 0x77a0, 0xa786, 0x0001, 0x1178, 0x70d0, + 0xd0b4, 0x1160, 0x7000, 0xa082, 0x0002, 0x1240, 0x7830, 0xd0bc, + 0x1128, 0x789b, 0x0080, 0x7baa, 0x0804, 0x282e, 0x8739, 0x77a2, + 0x2750, 0x77ac, 0xa7b0, 0x0005, 0x70a8, 0xa606, 0x1108, 0x76a4, + 0x76ae, 0x2c3a, 0x8738, 0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, + 0x8738, 0x253a, 0x7830, 0xd0bc, 0x0150, 0x2091, 0x8000, 0x2091, + 0x303d, 0x70d0, 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, + 0x0000, 0x0120, 0x8421, 0x2200, 0x1904, 0x2736, 0x0005, 0xd1dc, + 0x0904, 0x37df, 0x2029, 0x0020, 0xd69c, 0x1120, 0x8528, 0xd68c, + 0x1108, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, 0xa18c, 0x00ff, + 0x70c8, 0xa160, 0x2c64, 0x8cff, 0x0188, 0x6014, 0xa706, 0x1dd0, + 0x60b8, 0x8001, 0x60ba, 0x1d88, 0x2a60, 0x6008, 0xa085, 0x0100, + 0x600a, 0x2200, 0x8421, 0x1904, 0x2736, 0x0005, 0x2a60, 0x610e, + 0x69be, 0x2c00, 0x68c6, 0x8840, 0x6008, 0xc0d5, 0x600a, 0x77a0, + 0xa786, 0x0001, 0x1904, 0x27be, 0x70d0, 0xd0b4, 0x1904, 0x27be, + 0x7000, 0xa082, 0x0002, 0x1a04, 0x27be, 0x7830, 0xd0bc, 0x1904, + 0x27be, 0x789b, 0x0080, 0x7baa, 0x7daa, 0x79aa, 0x2001, 0x0002, + 0x0006, 0x6018, 0x8000, 0x601a, 0x0008, 0x0006, 0x2960, 0x6104, + 0x2a60, 0x080c, 0x3cf3, 0x1590, 0xa184, 0x0018, 0x0180, 0xa184, + 0x0010, 0x0118, 0x080c, 0x3988, 0x1548, 0xa184, 0x0008, 0x0138, + 0x69a0, 0xa184, 0x0600, 0x1118, 0x080c, 0x38a6, 0x00f8, 0x69a0, + 0xa184, 0x1e00, 0x0528, 0xa184, 0x0800, 0x0178, 0x00c6, 0x2960, + 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, + 0x00ce, 0x080c, 0x3988, 0x1150, 0x69a0, 0xa184, 0x0200, 0x0118, + 0x080c, 0x38eb, 0x0018, 0xa184, 0x0400, 0x19f0, 0x69a0, 0xa184, + 0x1000, 0x0130, 0x6914, 0xa18c, 0xff00, 0x810f, 0x080c, 0x23ad, + 0x002e, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0128, 0xa086, 0x0060, + 0x1110, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, 0x789b, 0x0060, + 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, 0x0168, 0xc0fc, + 0x7083, 0x0000, 0xa08a, 0x000d, 0x0328, 0xa08a, 0x000c, 0x7182, + 0x2001, 0x000c, 0x800c, 0x7186, 0x78aa, 0x3518, 0x3340, 0x3428, + 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0, 0x789b, 0x0000, 0xad80, + 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898, 0x25a0, 0xa286, 0x0020, + 0x1508, 0x70d0, 0xc0b5, 0x70d2, 0x2c00, 0x70b6, 0x2d00, 0x70ba, + 0x6814, 0xc0fc, 0x8007, 0x7882, 0xa286, 0x0002, 0x0904, 0x2906, + 0x70a0, 0x8000, 0x70a2, 0x74b0, 0xa498, 0x0005, 0x70a8, 0xa306, + 0x1108, 0x73a4, 0x73b2, 0xa286, 0x0010, 0x0904, 0x25ae, 0x00de, + 0x00ce, 0x0005, 0x7000, 0xa005, 0x19e0, 0xa286, 0x0002, 0x1904, + 0x291d, 0x080c, 0x3c45, 0x19a8, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0x2091, 0x8000, 0x781b, 0x0068, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, + 0x780a, 0x0126, 0x00d6, 0x00c6, 0x70d0, 0xa084, 0x2e00, 0x2090, + 0x00ce, 0x00de, 0x012e, 0x2900, 0x7056, 0x68bc, 0x703e, 0x7003, + 0x0002, 0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x7830, 0xd0bc, + 0x0140, 0x2091, 0x303d, 0x70d0, 0xa084, 0x303d, 0x2091, 0x8000, + 0x2090, 0x70a0, 0xa005, 0x1108, 0x0005, 0x8421, 0x0de8, 0x724c, + 0x70bc, 0xa200, 0xa015, 0x0804, 0x2736, 0xa286, 0x0010, 0x1560, + 0x080c, 0x3c45, 0x1904, 0x28b1, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0x781b, 0x0068, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x70a0, 0x8000, 0x70a2, + 0x74b0, 0xa490, 0x0005, 0x70a8, 0xa206, 0x1108, 0x72a4, 0x72b2, + 0x2900, 0x7056, 0x68bc, 0x703e, 0x7003, 0x0002, 0x2d00, 0x704a, + 0xad80, 0x0009, 0x7042, 0x0005, 0x6bb4, 0xa39d, 0x2000, 0x7b5a, + 0x6814, 0xc0fc, 0x8007, 0x7882, 0x6b94, 0x7bd6, 0x7bde, 0x6e98, + 0x7ed2, 0x7eda, 0x781b, 0x0068, 0x2900, 0x7056, 0x7202, 0x7808, + 0xc08d, 0x780a, 0x2300, 0xa605, 0x0170, 0x70d0, 0xa084, 0x2e00, + 0xa086, 0x2600, 0x1118, 0x2009, 0x0000, 0x0010, 0x2009, 0x0001, + 0xa284, 0x000f, 0x0023, 0xad80, 0x0009, 0x7042, 0x0005, 0x297f, + 0x41eb, 0x41eb, 0x41d9, 0x41eb, 0x297f, 0x297f, 0x297f, 0x080c, + 0x255d, 0x7808, 0xa084, 0xfffd, 0x780a, 0x00f6, 0x2079, 0x4700, + 0x78ac, 0x00fe, 0xd084, 0x01b0, 0x7060, 0xa086, 0x0001, 0x0904, + 0x2a43, 0x7060, 0xa086, 0x0005, 0x1158, 0x7078, 0x2068, 0x681b, + 0x0004, 0x6817, 0x0000, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, + 0x7063, 0x0000, 0x70a3, 0x0000, 0x70a4, 0x70ae, 0x70b2, 0x080c, + 0x2693, 0x0156, 0x2011, 0x0004, 0x7160, 0xa186, 0x0001, 0x0160, + 0xa186, 0x0007, 0x1118, 0x701f, 0x0005, 0x0030, 0x701f, 0x0001, + 0x70d0, 0xc0c5, 0x70d2, 0x0000, 0x2001, 0x470a, 0x2004, 0xa084, + 0x00ff, 0xa086, 0x0018, 0x0130, 0x7018, 0x7016, 0xa005, 0x1110, + 0x70a3, 0x0001, 0x0066, 0x080c, 0x3f38, 0x20a9, 0x0010, 0x2039, + 0x0000, 0x080c, 0x3a77, 0xa7b8, 0x0100, 0x1f04, 0x29d1, 0x006e, + 0x7000, 0x0002, 0x2a0e, 0x29ec, 0x29ec, 0x29e4, 0x2a0e, 0x2a0e, + 0x2a0e, 0x29e2, 0x080c, 0x255d, 0x705c, 0xa005, 0x0538, 0xad06, + 0x1118, 0x6800, 0x705e, 0x0080, 0x6820, 0xd084, 0x1148, 0x6f14, + 0x080c, 0x3b81, 0x6008, 0xc0d4, 0x600a, 0x080c, 0x37b5, 0x0020, + 0x7058, 0x2060, 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, + 0xd0fc, 0x0108, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820, + 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1db1, 0x2011, 0x0004, + 0x74c8, 0xa4a0, 0x0100, 0x04b1, 0xaea0, 0x0017, 0x0499, 0x20a9, + 0x0101, 0x74c8, 0x0479, 0x8420, 0x1f04, 0x2a1a, 0x70c0, 0x2060, + 0x2021, 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0198, 0x6018, + 0x0016, 0x0006, 0x2011, 0x4702, 0x220c, 0xa102, 0x2012, 0x000e, + 0x001e, 0xa102, 0x0338, 0x6012, 0x1128, 0x2011, 0x4704, 0x2204, + 0xc0a5, 0x2012, 0x601b, 0x0000, 0xace0, 0x0010, 0x1f04, 0x2a24, + 0x8421, 0x1d00, 0x015e, 0x7063, 0x0000, 0x7003, 0x0000, 0x704b, + 0x0000, 0x0005, 0x0046, 0x2404, 0xa005, 0x01a8, 0x2068, 0x6800, + 0x0006, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, + 0x5f00, 0x681e, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, + 0x1db1, 0x000e, 0x0c48, 0x004e, 0x2023, 0x0000, 0x0005, 0xa282, + 0x0003, 0x0310, 0x080c, 0x255d, 0x2300, 0x0002, 0x2a71, 0x2aee, + 0x2b08, 0xa282, 0x0002, 0x0110, 0x080c, 0x255d, 0x7060, 0x7063, + 0x0000, 0x707f, 0x0000, 0x0022, 0x77d0, 0xc7c5, 0x77d2, 0x0002, + 0x2a88, 0x2a88, 0x2a8a, 0x2ac2, 0x37e9, 0x2a88, 0x2ac2, 0x2a88, + 0x080c, 0x255d, 0x7770, 0x080c, 0x3a77, 0x7770, 0xa7bc, 0x8f00, + 0x080c, 0x3b81, 0x6018, 0xa005, 0x0528, 0xd7fc, 0x1118, 0x2021, + 0x8dc0, 0x0010, 0x2021, 0x8ed0, 0x2009, 0x0005, 0x2011, 0x0010, + 0x080c, 0x2b22, 0x01b8, 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, + 0x2021, 0x8cc0, 0x0010, 0x2021, 0x8dd0, 0x0046, 0x2009, 0x0005, + 0x2011, 0x0010, 0x080c, 0x2b22, 0x004e, 0x0118, 0x8420, 0x1f04, + 0x2aad, 0x015e, 0x8738, 0xa784, 0x001f, 0x1990, 0x0804, 0x25b1, + 0x0804, 0x25b1, 0x7770, 0x080c, 0x3b81, 0x6018, 0xa005, 0x0520, + 0xd7fc, 0x1118, 0x2021, 0x8dc0, 0x0010, 0x2021, 0x8ed0, 0x2009, + 0x0005, 0x2011, 0x0020, 0x080c, 0x2b22, 0x01b0, 0x0156, 0x20a9, + 0x0101, 0xd7fc, 0x1118, 0x2021, 0x8cc0, 0x0010, 0x2021, 0x8dd0, + 0x0046, 0x2009, 0x0005, 0x2011, 0x0020, 0x04e1, 0x004e, 0x0118, + 0x8420, 0x1f04, 0x2ae0, 0x015e, 0x0804, 0x25b1, 0x2200, 0x0002, + 0x2af3, 0x2af5, 0x2af5, 0x080c, 0x255d, 0x2009, 0x0012, 0x7060, + 0xa086, 0x0002, 0x0110, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0108, + 0x691a, 0x7063, 0x0000, 0x70d0, 0xc0c5, 0x70d2, 0x0804, 0x3bf7, + 0x2200, 0x0002, 0x2b0f, 0x2af5, 0x2b0d, 0x080c, 0x255d, 0x080c, + 0x3f38, 0x7000, 0xa086, 0x0002, 0x1904, 0x376e, 0x080c, 0x37cf, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x080c, 0x3760, 0x0904, 0x376e, + 0x0804, 0x25b1, 0x2404, 0xa005, 0x0590, 0x2068, 0x2d04, 0x0006, + 0x6814, 0xa706, 0x0118, 0x2d20, 0x000e, 0x0ca8, 0x000e, 0x2022, + 0x691a, 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, + 0x681e, 0x6820, 0xa084, 0x00ff, 0xa205, 0x6822, 0x080c, 0x1db1, + 0x2021, 0x4702, 0x241c, 0x8319, 0x2322, 0x6010, 0x8001, 0x6012, + 0x1128, 0x2021, 0x4704, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, + 0xf9ef, 0x600a, 0x080c, 0x26af, 0x080c, 0x37cf, 0x0005, 0xa085, + 0x0001, 0x0ce0, 0x2300, 0x0002, 0x2b61, 0x2b5f, 0x2bdc, 0x080c, + 0x255d, 0x78e4, 0xa005, 0x17b0, 0x3208, 0xa18c, 0x0800, 0x0118, + 0x0104, 0x25ae, 0x0010, 0x0304, 0x25ae, 0x2008, 0xa084, 0x0030, + 0x1110, 0x0804, 0x323b, 0x78ec, 0xa084, 0x0003, 0x0dd0, 0x7884, + 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, + 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, + 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001, 0x0002, + 0x2bbf, 0x2bc8, 0x2bb5, 0x2b98, 0x3c3b, 0x3c3b, 0x2b98, 0x2bd2, + 0x080c, 0x255d, 0x7000, 0xa086, 0x0004, 0x1190, 0x7060, 0xa086, + 0x0002, 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x2a67, + 0x7060, 0xa086, 0x0006, 0x0db0, 0x7060, 0xa086, 0x0004, 0x0d90, + 0x79e4, 0x2001, 0x0003, 0x0804, 0x2f29, 0x6818, 0xd0fc, 0x0110, + 0x681b, 0x001d, 0x080c, 0x3a4d, 0x781b, 0x006e, 0x0005, 0x6818, + 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3a4d, 0x0804, 0x3c19, + 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3a4d, 0x781b, + 0x00fa, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, + 0x3a4d, 0x781b, 0x00cb, 0x0005, 0xa584, 0x000f, 0x11c0, 0x7000, + 0x0002, 0x25b1, 0x2be9, 0x2beb, 0x376e, 0x376e, 0x376e, 0x2be9, + 0x2be9, 0x080c, 0x255d, 0x080c, 0x37cf, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x080c, 0x3760, 0x0904, 0x376e, 0x0804, 0x25b1, 0x78e4, + 0xa005, 0x1b04, 0x2b9a, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104, + 0x2b9a, 0x0010, 0x0304, 0x2b9a, 0x2008, 0xa084, 0x0030, 0x1118, + 0x781b, 0x0068, 0x0005, 0x78ec, 0xa084, 0x0003, 0x0dc8, 0x7884, + 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, + 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, + 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001, 0x0002, + 0x2c37, 0x2c3b, 0x2c32, 0x2c30, 0x3c3b, 0x3c3b, 0x2c30, 0x3c35, + 0x080c, 0x255d, 0x080c, 0x3a53, 0x781b, 0x006e, 0x0005, 0x080c, + 0x3a53, 0x0804, 0x3c19, 0x080c, 0x3a53, 0x781b, 0x00fa, 0x0005, + 0x080c, 0x3a53, 0x781b, 0x00cb, 0x0005, 0x2300, 0x0002, 0x2c4c, + 0x2c4a, 0x2c4e, 0x080c, 0x255d, 0x0804, 0x33f3, 0x681b, 0x0016, + 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0904, 0x33f3, 0x78ec, + 0xa084, 0x0003, 0x0904, 0x33f3, 0xa184, 0x0100, 0x0d98, 0x7884, + 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, + 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, + 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001, 0x0002, + 0x2c80, 0x2c3b, 0x2bb5, 0x3bf7, 0x3c3b, 0x3c3b, 0x3bf7, 0x3c35, + 0x080c, 0x3c03, 0x0005, 0xa282, 0x0005, 0x0310, 0x080c, 0x255d, + 0x7898, 0x2040, 0x2300, 0x0002, 0x2c8f, 0x2eb9, 0x2ec3, 0x2200, + 0x0002, 0x2cab, 0x2c98, 0x2cab, 0x2c96, 0x2e9b, 0x080c, 0x255d, + 0x789b, 0x0018, 0x78a8, 0x2010, 0xa084, 0x00ff, 0xa082, 0x0020, + 0x0a04, 0x3a1c, 0xa08a, 0x0004, 0x1a04, 0x3a1c, 0x0002, 0x3a1c, + 0x3a1c, 0x3a1c, 0x39d2, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, + 0x0148, 0x0804, 0x3a1c, 0x7000, 0xa005, 0x1dd8, 0x2011, 0x0004, + 0x0804, 0x35a5, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x1a04, 0x3a1c, + 0x0002, 0x2cd3, 0x2cd1, 0x2ce5, 0x2ce9, 0x2d97, 0x3a1c, 0x3a1c, + 0x2d99, 0x3a1c, 0x3a1c, 0x2e97, 0x2e97, 0x3a1c, 0x3a1c, 0x3a1c, + 0x2e99, 0x080c, 0x255d, 0xd6e4, 0x0140, 0x2001, 0x0300, 0x8000, + 0x8000, 0x783a, 0x781b, 0x00c7, 0x0005, 0x6818, 0xd0fc, 0x0118, + 0x681b, 0x001d, 0x0c90, 0x0804, 0x3bf7, 0x681b, 0x001d, 0x0804, + 0x3a47, 0x6920, 0x6922, 0xa684, 0x1800, 0x1904, 0x2d3a, 0x6820, + 0xd084, 0x1904, 0x2d42, 0x6818, 0xa086, 0x0008, 0x1110, 0x681b, + 0x0000, 0xd6d4, 0x0568, 0xd6bc, 0x0558, 0x7083, 0x0000, 0x6818, + 0xa084, 0x003f, 0xa08a, 0x000d, 0x0718, 0xa08a, 0x000c, 0x7182, + 0x2001, 0x000c, 0x800c, 0x7186, 0x789b, 0x0061, 0x78aa, 0x0156, + 0x0136, 0x0146, 0x0016, 0x3208, 0xa18c, 0x0600, 0x0118, 0x20a1, + 0x022b, 0x0010, 0x20a1, 0x012b, 0x001e, 0x789b, 0x0000, 0x8000, + 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x014e, 0x013e, 0x015e, + 0x6038, 0xa005, 0x1150, 0x681c, 0xa084, 0x000e, 0x0904, 0x3a47, + 0x080c, 0x3a59, 0x782b, 0x3008, 0x0010, 0x8001, 0x603a, 0x781b, + 0x0071, 0x0005, 0xd6e4, 0x0130, 0x781b, 0x0083, 0x0005, 0x781b, + 0x0083, 0x0005, 0xa684, 0x0060, 0x0dd0, 0xd6dc, 0x0dc0, 0xd6fc, + 0x01a0, 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x8007, + 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, + 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0xd6f4, 0x0118, 0xc6f4, + 0x7e5a, 0x6eb6, 0x7000, 0xa086, 0x0003, 0x1148, 0x0006, 0x080c, + 0x3f38, 0x080c, 0x41eb, 0x000e, 0x781b, 0x0080, 0x0005, 0xa006, + 0x080c, 0x42c7, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, + 0x0120, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, + 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x1130, 0xc6f5, 0x7e5a, + 0x6eb6, 0x781b, 0x0080, 0x0005, 0x781b, 0x0080, 0x2200, 0xa115, + 0x1118, 0x080c, 0x41eb, 0x0005, 0x080c, 0x4218, 0x0005, 0x080c, + 0x255d, 0x0804, 0x2e2d, 0x00c6, 0x7054, 0x2060, 0x6920, 0xa18c, + 0xecff, 0x6922, 0x6000, 0xa084, 0xcfdf, 0x6002, 0x080c, 0x3905, + 0xa006, 0x2040, 0x2038, 0x080c, 0x39ad, 0x0804, 0x2e21, 0x00c6, + 0x7054, 0x2060, 0x2c48, 0x7aa8, 0xa294, 0x00ff, 0xa286, 0x0004, + 0x11d8, 0x6920, 0xd1e4, 0x1170, 0x2039, 0x0000, 0x2041, 0x0000, + 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x3908, 0x080c, 0x39ad, + 0x0804, 0x2e21, 0xa18c, 0xecff, 0x6922, 0x6104, 0xa18c, 0xffdd, + 0x6106, 0x6000, 0xc0ac, 0x6002, 0xa286, 0x0003, 0x01d0, 0x6104, + 0xa184, 0x0010, 0x0548, 0x080c, 0x3b7d, 0x080c, 0x3988, 0x88ff, + 0x0518, 0x00ce, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, + 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, + 0x0005, 0x6920, 0xd1cc, 0x0130, 0xa18c, 0xfdff, 0x6922, 0x6000, + 0xc0ec, 0x6002, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, 0x0000, + 0xa006, 0x2010, 0x080c, 0x39ad, 0xa286, 0x0001, 0x0158, 0x6104, + 0xa184, 0x0008, 0x01b0, 0x080c, 0x3b7d, 0x080c, 0x38a6, 0x88ff, + 0x1980, 0x0078, 0x6920, 0xd1c4, 0x0130, 0xa18c, 0xfeff, 0x6922, + 0x6000, 0xc0e4, 0x6002, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, + 0x3908, 0x00ce, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, + 0x781b, 0x0083, 0x0005, 0x0804, 0x3a43, 0x2808, 0x789b, 0x0080, + 0x2019, 0x0080, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x11b8, + 0x2300, 0xa102, 0xa086, 0x0001, 0x0904, 0x2d9b, 0x7ca8, 0xa4a4, + 0x00ff, 0xa480, 0x0002, 0xa300, 0x2018, 0xa102, 0x0a04, 0x2daf, + 0x0904, 0x2daf, 0x24a8, 0x7aa8, 0x1f04, 0x2e4b, 0x0c18, 0xa284, + 0x00f0, 0xa082, 0x0020, 0x06b8, 0x2200, 0xa082, 0x0021, 0x1698, + 0x7aa8, 0x8318, 0x8318, 0x2100, 0xa302, 0x0aa0, 0xa286, 0x0023, + 0x0950, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, + 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, 0x78a0, 0x8001, + 0x0904, 0x2e21, 0x20a8, 0x7998, 0x789b, 0x0060, 0x78aa, 0x2011, + 0x0080, 0x799a, 0x78a8, 0x7998, 0x7a9a, 0x78aa, 0x7a98, 0x1f04, + 0x2e79, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, + 0x781b, 0x0082, 0x0005, 0x8318, 0x2100, 0xa302, 0x0a04, 0x2e32, + 0xa284, 0x0080, 0x1904, 0x3a47, 0x78a0, 0xa005, 0x08c8, 0x0804, + 0x3a47, 0x0804, 0x3a1c, 0x7054, 0xa04d, 0x789b, 0x0018, 0x78a8, + 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0110, 0x080c, 0x255d, 0x7aa8, + 0xa294, 0x00ff, 0x784b, 0x0008, 0x78a8, 0xa084, 0x00ff, 0xa08a, + 0x0005, 0x1a04, 0x3a1c, 0x0002, 0x3a1c, 0x381d, 0x3a1c, 0x3938, + 0x3d43, 0xa282, 0x0000, 0x1110, 0x080c, 0x255d, 0x080c, 0x3a4d, + 0x781b, 0x0082, 0x0005, 0xa282, 0x0003, 0x1110, 0x080c, 0x255d, + 0xd4fc, 0x11d0, 0x7060, 0xa005, 0x0110, 0x080c, 0x255d, 0x6f14, + 0x7772, 0xa7bc, 0x8f00, 0x080c, 0x3b81, 0x6008, 0xa085, 0x0021, + 0x600a, 0x8738, 0xa784, 0x001f, 0x1db0, 0x080c, 0x3a50, 0x7063, + 0x0002, 0x701f, 0x0009, 0x0010, 0x080c, 0x3a5c, 0x781b, 0x0082, + 0x0005, 0xa282, 0x0004, 0x0310, 0x080c, 0x255d, 0x2300, 0x0002, + 0x2ef3, 0x3089, 0x30c5, 0xa286, 0x0003, 0x0598, 0x7200, 0x7cd8, + 0x7ddc, 0x7fd0, 0x71d0, 0xd1b4, 0x0528, 0xd1bc, 0x1518, 0x2001, + 0x4701, 0x2004, 0xd0c4, 0x11f0, 0x7868, 0xa084, 0x00ff, 0x11d0, + 0xa282, 0x0002, 0x12b8, 0x00d6, 0x783b, 0x8300, 0x781b, 0x0059, + 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030, 0x00de, 0x2001, + 0x0000, 0x0058, 0x783b, 0x1300, 0x781b, 0x0057, 0x2001, 0x0000, + 0x0020, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x7046, 0x68a0, 0xd0ec, + 0x0118, 0x6008, 0xc08d, 0x600a, 0xa284, 0x000f, 0x0002, 0x306a, + 0x2f44, 0x2f41, 0x3195, 0x3220, 0x25b1, 0x2f3f, 0x2f3f, 0x080c, + 0x255d, 0x6008, 0xc0d4, 0x600a, 0xd6e4, 0x0120, 0x7044, 0xa086, + 0x0014, 0x11e8, 0x080c, 0x3f38, 0x2009, 0x0000, 0x6818, 0xd0fc, + 0x0108, 0x7044, 0xa086, 0x0014, 0x0168, 0x6818, 0xa086, 0x0008, + 0x1904, 0x302c, 0x7858, 0xd09c, 0x0904, 0x302c, 0x6820, 0xd0ac, + 0x0904, 0x302c, 0x681b, 0x0014, 0x2009, 0x0002, 0x04a8, 0x7868, + 0xa08c, 0x00ff, 0x0588, 0xa186, 0x0008, 0x1158, 0x6008, 0xc0a4, + 0x600a, 0x080c, 0x3760, 0x0540, 0x080c, 0x37cf, 0x080c, 0x3f38, + 0x0060, 0xa186, 0x0028, 0x1500, 0x6018, 0xa005, 0x0d78, 0x8001, + 0x0d68, 0x8001, 0x0d58, 0x601e, 0x0c48, 0x6820, 0xd084, 0x0904, + 0x25b1, 0xc084, 0x6822, 0x080c, 0x26a4, 0x7058, 0x00c6, 0x2060, + 0x6800, 0x6002, 0x00ce, 0x6004, 0x6802, 0xa005, 0x2d00, 0x1108, + 0x6002, 0x6006, 0x0804, 0x25b1, 0x0016, 0x81ff, 0x15f0, 0x7000, + 0xa086, 0x0030, 0x05d0, 0x71d0, 0xd1bc, 0x15b8, 0xd1b4, 0x11e8, + 0x705c, 0xa005, 0x1590, 0x70a0, 0xa086, 0x0001, 0x0570, 0x7003, + 0x0000, 0x0046, 0x0056, 0x0076, 0x0066, 0x00c6, 0x00d6, 0x080c, + 0x25d6, 0x00de, 0x00ce, 0x006e, 0x007e, 0x005e, 0x004e, 0x71d0, + 0xd1b4, 0x11d8, 0x7003, 0x0040, 0x00c0, 0x080c, 0x3c45, 0x11a8, + 0x781b, 0x0068, 0x00d6, 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, + 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, + 0x0030, 0x7808, 0xc08d, 0x780a, 0x00de, 0x080c, 0x30ed, 0x001e, + 0x81ff, 0x0904, 0x302c, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, + 0x6f14, 0xa186, 0x0002, 0x1904, 0x302d, 0x6818, 0xa086, 0x0014, + 0x1130, 0x2008, 0xd6e4, 0x0118, 0x7868, 0xa08c, 0x00ff, 0x080c, + 0x3a66, 0x080c, 0x26af, 0x6820, 0xd0dc, 0x1578, 0x8717, 0xa294, + 0x000f, 0x8213, 0x8213, 0x8213, 0xb284, 0x0600, 0x0118, 0xa290, + 0x4bc0, 0x0010, 0xa290, 0x4c40, 0xa290, 0x0000, 0x221c, 0xd3c4, + 0x0170, 0x6820, 0xd0e4, 0x0128, 0xa084, 0xefff, 0x6822, 0xc3ac, + 0x2312, 0x8210, 0x2204, 0xa085, 0x0038, 0x2012, 0x8211, 0xd3d4, + 0x0138, 0x68a0, 0xd0c4, 0x1120, 0x080c, 0x3155, 0x0804, 0x25b1, + 0x6008, 0xc08d, 0x600a, 0x0008, 0x692a, 0x6916, 0x6818, 0xd0fc, + 0x0110, 0x7044, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, + 0x0168, 0x2009, 0x4702, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, + 0x1128, 0x2021, 0x4704, 0x2404, 0xc0a5, 0x2022, 0x6018, 0xa005, + 0x0118, 0x8001, 0x601a, 0x1118, 0x6008, 0xc0a4, 0x600a, 0x6820, + 0xd084, 0x1130, 0x6800, 0xa005, 0x1108, 0x6002, 0x6006, 0x0020, + 0x7058, 0x2060, 0x6800, 0x6002, 0x2061, 0x4700, 0x6887, 0x0103, + 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0110, 0x2d02, + 0x0008, 0x616e, 0x7200, 0xa286, 0x0030, 0x0158, 0xa286, 0x0040, + 0x1904, 0x25b1, 0x7003, 0x0002, 0x7048, 0x2068, 0x68c4, 0x2060, + 0x0005, 0x7003, 0x0002, 0x70b8, 0xa06d, 0x68bc, 0x703e, 0x70b4, + 0xa065, 0x68c0, 0x7056, 0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, + 0x0005, 0xa282, 0x0004, 0x0210, 0x080c, 0x255d, 0x2200, 0x0002, + 0x3094, 0x30a3, 0x30af, 0x30a3, 0xa586, 0x1300, 0x0160, 0xa586, + 0x8300, 0x1d90, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, + 0xa084, 0xfbef, 0x600a, 0x7000, 0xa086, 0x0005, 0x0128, 0x080c, + 0x3a4d, 0x781b, 0x0082, 0x0005, 0x781b, 0x0083, 0x0005, 0x7890, + 0x8007, 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, + 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0128, 0xa186, 0x0000, 0x0110, + 0x0804, 0x3a1c, 0x781b, 0x0083, 0x0005, 0x6820, 0xc095, 0x6822, + 0x82ff, 0x1118, 0x080c, 0x3a4d, 0x0030, 0x8211, 0x0110, 0x080c, + 0x255d, 0x080c, 0x3a5c, 0x781b, 0x0082, 0x0005, 0x080c, 0x3c58, + 0x7830, 0xa084, 0x00c0, 0x1170, 0x0016, 0x3208, 0xa18c, 0x0800, + 0x001e, 0x0118, 0x0104, 0x30ea, 0x0010, 0x0304, 0x30ea, 0x791a, + 0xa006, 0x0005, 0xa085, 0x0001, 0x0005, 0xa684, 0x0060, 0x1130, + 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, 0x3154, 0xd6dc, 0x1198, + 0x68b4, 0xd0dc, 0x1180, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7044, + 0xa005, 0x1130, 0x2200, 0xa105, 0x0904, 0x3f38, 0x7047, 0x0015, + 0x0804, 0x3f38, 0x0005, 0xd6ac, 0x01f0, 0xd6f4, 0x0130, 0x682f, + 0x0000, 0x6833, 0x0000, 0x0804, 0x3f38, 0x68b4, 0xa084, 0x4000, + 0xa635, 0xd6f4, 0x1da0, 0x7044, 0xa005, 0x1110, 0x7047, 0x0015, + 0xd6dc, 0x1128, 0x68b4, 0xd0dc, 0x0110, 0x6ca8, 0x6da4, 0x6c2e, + 0x6d32, 0x0804, 0x3f38, 0xd6f4, 0x0130, 0x682f, 0x0000, 0x6833, + 0x0000, 0x0804, 0x3f38, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, + 0x1da0, 0x7044, 0xa005, 0x1110, 0x7047, 0x0015, 0x2408, 0x2510, + 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x692e, + 0x6a32, 0x2100, 0xa205, 0x1110, 0x0804, 0x3f38, 0x7000, 0xa086, + 0x0006, 0x0110, 0x0804, 0x3f38, 0x0005, 0x6946, 0x6008, 0xc0cd, + 0xd3cc, 0x0108, 0xc08d, 0x600a, 0x6818, 0x683a, 0x681b, 0x0006, + 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, + 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, + 0x689b, 0x0020, 0x7000, 0x0002, 0x25b1, 0x3184, 0x317e, 0x317c, + 0x317c, 0x317c, 0x317c, 0x317c, 0x080c, 0x255d, 0x6820, 0xd084, + 0x1118, 0x080c, 0x37b5, 0x0030, 0x7058, 0x2c50, 0x2060, 0x6800, + 0x6002, 0x2a60, 0xaea0, 0x0017, 0x2404, 0xa005, 0x0110, 0x2020, + 0x0cd8, 0x2d22, 0x206b, 0x0000, 0x0005, 0x080c, 0x37bb, 0x080c, + 0x37cf, 0x6008, 0xc0cc, 0x600a, 0x682b, 0x0000, 0x789b, 0x000e, + 0x6f14, 0x6938, 0x691a, 0x6944, 0x6916, 0x2009, 0x0000, 0xae86, + 0x4740, 0x0110, 0x2009, 0x0001, 0x080c, 0x42fe, 0xd6dc, 0x01c8, + 0x691c, 0xc1ed, 0x691e, 0x6828, 0xa082, 0x000e, 0x0290, 0x6848, + 0xa084, 0x000f, 0xa086, 0x000b, 0x1160, 0x685c, 0xa086, 0x0047, + 0x1140, 0x2001, 0x4701, 0x2004, 0xd0ac, 0x1118, 0x2700, 0x080c, + 0x2486, 0x6818, 0xd0fc, 0x0140, 0x681b, 0x0000, 0x7868, 0xa08c, + 0x00ff, 0x0110, 0x681b, 0x001e, 0xaea0, 0x0017, 0x6800, 0x2022, + 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, 0xd0a4, + 0x0580, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x00d6, + 0x00f6, 0x0156, 0x0146, 0x2079, 0x4700, 0x080c, 0x1ba2, 0x014e, + 0x015e, 0x00fe, 0x70c8, 0x2010, 0x2009, 0x0101, 0x0026, 0x2204, + 0xa06d, 0x0140, 0x6814, 0xa706, 0x0110, 0x6800, 0x0cc8, 0x6820, + 0xc0d5, 0x6822, 0x002e, 0x8210, 0x8109, 0x1d80, 0x00de, 0x7063, + 0x0003, 0x707b, 0x0000, 0x7772, 0x707f, 0x000f, 0x71d0, 0xc1c4, + 0x71d2, 0x6818, 0xa086, 0x0002, 0x1138, 0x6817, 0x0000, 0x682b, + 0x0000, 0x681c, 0xc0ec, 0x681e, 0x080c, 0x1db1, 0x0804, 0x25b1, + 0x7cd8, 0x7ddc, 0x7fd0, 0x080c, 0x30ed, 0x682b, 0x0000, 0x789b, + 0x000e, 0x6f14, 0x080c, 0x3c5c, 0xa08c, 0x00ff, 0x6916, 0x6818, + 0xd0fc, 0x0110, 0x7044, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x7063, + 0x0000, 0x0804, 0x25b1, 0x7000, 0xa005, 0x1110, 0x0804, 0x25b1, + 0xa006, 0x080c, 0x3f38, 0x6920, 0xd1ac, 0x1110, 0x681b, 0x0014, + 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, + 0x6822, 0x7000, 0x0002, 0x25b1, 0x325d, 0x325d, 0x3260, 0x3260, + 0x3260, 0x325b, 0x325b, 0x080c, 0x255d, 0x6818, 0x0804, 0x2f29, + 0x6008, 0xc0a4, 0x600a, 0x6817, 0x0000, 0x0804, 0x3783, 0x2300, + 0x0002, 0x326c, 0x326e, 0x32bc, 0x080c, 0x255d, 0xd6fc, 0x1904, + 0x2d49, 0x7000, 0xa00d, 0x0002, 0x25b1, 0x327e, 0x327e, 0x32a8, + 0x327e, 0x32b9, 0x327c, 0x327c, 0x080c, 0x255d, 0xa684, 0x0060, + 0x0538, 0xa086, 0x0060, 0x1510, 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, + 0x6eb6, 0x681c, 0xc0ac, 0x681e, 0xa186, 0x0002, 0x0148, 0x080c, + 0x3f38, 0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, 0x4218, 0x0010, + 0x080c, 0x41eb, 0x781b, 0x0083, 0x71d0, 0xd1b4, 0x1904, 0x25ae, + 0x70a0, 0xa086, 0x0001, 0x1904, 0x25f2, 0x0005, 0xd6ec, 0x09f0, + 0x6818, 0xd0fc, 0x0170, 0xd6f4, 0x1130, 0x681b, 0x0015, 0x781b, + 0x0083, 0x0804, 0x25ae, 0x681b, 0x0007, 0x682f, 0x0000, 0x6833, + 0x0000, 0x080c, 0x3c03, 0x0005, 0x080c, 0x255d, 0x2300, 0x0002, + 0x32c5, 0x32e7, 0x333f, 0x080c, 0x255d, 0x7000, 0x0002, 0x32cf, + 0x32d1, 0x32d8, 0x32cf, 0x32cf, 0x32cf, 0x32cf, 0x32cf, 0x080c, + 0x255d, 0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, 0x4218, 0x0010, + 0x080c, 0x41eb, 0x681c, 0xc0b4, 0x681e, 0x70d0, 0xd0b4, 0x1904, + 0x25ae, 0x70a0, 0xa086, 0x0001, 0x1904, 0x25f2, 0x0005, 0xd6fc, + 0x1904, 0x332f, 0x7000, 0xa00d, 0x0002, 0x25b1, 0x32fd, 0x32f7, + 0x3327, 0x32fd, 0x332c, 0x32f5, 0x32f5, 0x080c, 0x255d, 0x6894, + 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0x0538, + 0xa086, 0x0060, 0x1510, 0xa6b4, 0xbfbf, 0xc6ed, 0x7e5a, 0x6eb6, + 0xa186, 0x0002, 0x0148, 0x080c, 0x3f38, 0x69ac, 0x68b0, 0xa115, + 0x0118, 0x080c, 0x4218, 0x0010, 0x080c, 0x41eb, 0x781b, 0x0083, + 0x681c, 0xc0b4, 0x681e, 0x71d0, 0xd1b4, 0x1904, 0x25ae, 0x70a0, + 0xa086, 0x0001, 0x1904, 0x25f2, 0x0005, 0xd6ec, 0x09f0, 0x6818, + 0xd0fc, 0x0110, 0x681b, 0x0007, 0x781b, 0x00fb, 0x0005, 0xc6fc, + 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, + 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, 0x0083, 0x0005, 0xd6dc, + 0x0130, 0x782b, 0x3009, 0x781b, 0x0083, 0x0804, 0x25ae, 0x7884, + 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, 0x1150, 0xa484, 0x0200, + 0x0108, 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, 0x0083, 0x0804, 0x25ae, + 0x6820, 0xc095, 0x6822, 0x080c, 0x3bee, 0xc6dd, 0x080c, 0x3a4d, + 0x781b, 0x0082, 0x0804, 0x25ae, 0x2300, 0x0002, 0x3369, 0x336b, + 0x336d, 0x080c, 0x255d, 0x0804, 0x3a47, 0x7d98, 0xd6d4, 0x15a8, + 0x79e4, 0xd1ac, 0x0130, 0x78ec, 0xa084, 0x0003, 0x0110, 0x782b, + 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, + 0x7d9a, 0x79e4, 0xd1ac, 0x0120, 0x78ec, 0xa084, 0x0003, 0x1120, + 0x2001, 0x0014, 0x0804, 0x2f29, 0x7884, 0xd0fc, 0x1118, 0xa184, + 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, 0x0004, 0x1118, 0x2001, + 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, 0x0005, 0x0118, 0xa184, + 0x0007, 0x0010, 0x2001, 0x0001, 0x04c2, 0x7a90, 0xa294, 0x0007, + 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0568, 0x789b, 0x0080, 0x7ba8, + 0xa384, 0x0001, 0x11d0, 0x7ba8, 0x7ba8, 0xa386, 0x0004, 0x1118, + 0x2009, 0xffdf, 0x0058, 0xa386, 0x0001, 0x1118, 0x2009, 0xfff7, + 0x0028, 0xa386, 0x0003, 0x1148, 0x2009, 0xffef, 0x00c6, 0x7054, + 0x2060, 0x6004, 0xa104, 0x6006, 0x00ce, 0x789b, 0x0060, 0x78ab, + 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, + 0xecff, 0x6922, 0x7d9a, 0x0804, 0x3bf7, 0x2bbf, 0x2bc8, 0x33e7, + 0x33ed, 0x33e5, 0x33e5, 0x3bf7, 0x3bf7, 0x080c, 0x255d, 0x6920, + 0xa18c, 0xfcff, 0x6922, 0x0804, 0x3bfd, 0x6920, 0xa18c, 0xfcff, + 0x6922, 0x0804, 0x3bf7, 0x79e4, 0xa184, 0x0030, 0x0120, 0x78ec, + 0xa084, 0x0003, 0x1570, 0x7000, 0xa086, 0x0004, 0x1190, 0x7060, + 0xa086, 0x0002, 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, + 0x2a67, 0x7060, 0xa086, 0x0006, 0x0db0, 0x7060, 0xa086, 0x0004, + 0x0d90, 0x7000, 0xa086, 0x0000, 0x0904, 0x25ae, 0x6920, 0xa184, + 0x0420, 0x0128, 0xc1d4, 0x6922, 0x6818, 0x0804, 0x2f29, 0x6818, + 0xa08e, 0x0002, 0x0120, 0xc0fd, 0x681a, 0x2001, 0x0014, 0x0804, + 0x2f29, 0x7884, 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, + 0x0007, 0xa086, 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, + 0x0007, 0xa086, 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, + 0x0001, 0x0002, 0x3bf7, 0x3bf7, 0x344a, 0x3bf7, 0x3c3b, 0x3c3b, + 0x3bf7, 0x3bf7, 0xd6bc, 0x0570, 0x7180, 0x81ff, 0x0558, 0xa182, + 0x000d, 0x1318, 0x7083, 0x0000, 0x0028, 0xa182, 0x000c, 0x7082, + 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, 0x0156, 0x0136, 0x0146, + 0x7084, 0x8114, 0xa210, 0x7286, 0xa080, 0x000b, 0xad00, 0x2098, + 0xb284, 0x0600, 0x0118, 0x20a1, 0x022b, 0x0010, 0x20a1, 0x012b, + 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x014e, 0x013e, 0x015e, + 0x0804, 0x3bfd, 0xd6d4, 0x1904, 0x34bd, 0x6820, 0xd084, 0x0904, + 0x3bfd, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0120, 0xa086, 0x0060, + 0x1108, 0xc1f5, 0xc194, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, + 0x0000, 0x789b, 0x0061, 0x6818, 0xc0fd, 0x681a, 0x78aa, 0x8008, + 0x810c, 0x0904, 0x37e4, 0xa18c, 0x00f8, 0x1904, 0x37e4, 0x0156, + 0x0136, 0x0146, 0x0016, 0x20a1, 0x012b, 0x3208, 0xa18c, 0x0600, + 0x0110, 0x20a1, 0x022b, 0x001e, 0x789b, 0x0000, 0x8000, 0x80ac, + 0xad80, 0x000b, 0x2098, 0x53a6, 0x014e, 0x013e, 0x015e, 0x6814, + 0xc0fc, 0x8007, 0x7882, 0x0804, 0x3bfd, 0x6818, 0xd0fc, 0x0110, + 0x681b, 0x0008, 0x080c, 0x3a4d, 0x781b, 0x00ed, 0x0005, 0x2300, + 0x0002, 0x34ce, 0x358b, 0x34cc, 0x080c, 0x255d, 0x7cd8, 0x7ddc, + 0x7fd0, 0x82ff, 0x1528, 0x7200, 0xa286, 0x0003, 0x0904, 0x2ef7, + 0x71d0, 0xd1bc, 0x11f8, 0xd1b4, 0x01e8, 0x2001, 0x4701, 0x2004, + 0xd0c4, 0x11c0, 0x00d6, 0x783b, 0x8800, 0x781b, 0x0059, 0x70b8, + 0xa06d, 0x68b4, 0xc0a5, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030, 0x00de, 0x0030, + 0x7200, 0x0020, 0x783b, 0x1800, 0x781b, 0x0057, 0xa284, 0x000f, + 0x0002, 0x3576, 0x3533, 0x350b, 0x2f26, 0x3509, 0x3576, 0x3509, + 0x3509, 0x080c, 0x255d, 0x681c, 0xd0ec, 0x0118, 0x6008, 0xc08d, + 0x600a, 0x6920, 0xc185, 0x6922, 0x6800, 0x6006, 0xa005, 0x1108, + 0x6002, 0x6008, 0xc0d4, 0x600a, 0x681c, 0xa084, 0x000e, 0x1120, + 0x71c8, 0xa188, 0x0100, 0x0028, 0x7030, 0x68ba, 0x713c, 0x70c8, + 0xa108, 0x2104, 0x6802, 0x2d0a, 0x715a, 0xd6dc, 0x1120, 0xc6fc, + 0x6eb6, 0x0804, 0x3576, 0x6eb6, 0xa684, 0x0060, 0x1120, 0xa684, + 0x7fff, 0x68b6, 0x04d8, 0xd6dc, 0x1150, 0xa684, 0x7fff, 0x68b6, + 0x6894, 0x68a6, 0x6898, 0x68aa, 0x080c, 0x3f38, 0x0478, 0xd6ac, + 0x0140, 0xa006, 0x080c, 0x3f38, 0x2408, 0x2510, 0x69aa, 0x6aa6, + 0x0068, 0x2408, 0x2510, 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, + 0xa291, 0x0000, 0x69aa, 0x6aa6, 0x080c, 0x3f38, 0xd6fc, 0x01b0, + 0xa684, 0x7fff, 0x68b6, 0x2510, 0x2408, 0xd6ac, 0x1138, 0x2700, + 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, + 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, + 0x0030, 0x1904, 0x25b1, 0x7003, 0x0002, 0x70b8, 0xa06d, 0x68bc, + 0x703e, 0x70b4, 0xa065, 0x68c0, 0x7056, 0x2d00, 0x704a, 0xad80, + 0x0009, 0x7042, 0x0005, 0xa586, 0x8800, 0x1148, 0x7003, 0x0000, + 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0804, + 0x3a47, 0x7043, 0x0000, 0xa282, 0x0006, 0x0310, 0x080c, 0x255d, + 0x2300, 0x0002, 0x35a5, 0x35b6, 0x35c0, 0x2200, 0x0002, 0x35ad, + 0x3a47, 0x35af, 0x35ad, 0x35f1, 0x363f, 0x080c, 0x255d, 0x7a80, + 0xa294, 0x0f00, 0x080c, 0x3693, 0x0804, 0x3a1c, 0x00c1, 0x0002, + 0x3a47, 0x35be, 0x35be, 0x35f1, 0x35be, 0x3a47, 0x080c, 0x255d, + 0x0071, 0x0002, 0x35ca, 0x35c8, 0x35c8, 0x35ca, 0x35c8, 0x35ca, + 0x080c, 0x255d, 0x080c, 0x3a5c, 0x781b, 0x0082, 0x0005, 0x7000, + 0xa086, 0x0002, 0x1150, 0x080c, 0x37cf, 0x0010, 0x080c, 0x3f38, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x0020, 0x7000, 0xa086, 0x0003, + 0x0da8, 0x7003, 0x0005, 0x2001, 0x8ee0, 0xae8e, 0x4740, 0x0110, + 0x2001, 0x8f12, 0x2068, 0x704a, 0xad80, 0x0009, 0x7042, 0x2200, + 0x0005, 0x7000, 0xa086, 0x0002, 0x1158, 0x70d0, 0xc0b5, 0x70d2, + 0x2c00, 0x70b6, 0x2d00, 0x70ba, 0x0038, 0x080c, 0x3f38, 0x0020, + 0x7000, 0xa086, 0x0003, 0x0dc8, 0x7003, 0x0001, 0x7a80, 0xa294, + 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, + 0x8dc0, 0xb284, 0x0600, 0x1118, 0xc2fd, 0x2069, 0x8ed0, 0x2d04, + 0x2d08, 0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, 0x0120, 0x6800, + 0x0cb8, 0x080c, 0x3693, 0x6eb4, 0x7e5a, 0x6920, 0xa184, 0x0c00, + 0x0904, 0x36b9, 0x7060, 0xa086, 0x0006, 0x1128, 0x7070, 0xa206, + 0x1110, 0x7062, 0x707a, 0x681b, 0x0005, 0xc1ad, 0x681b, 0x0005, + 0xc1ad, 0xc1d4, 0x6922, 0x080c, 0x3a53, 0x0804, 0x36b9, 0x7200, + 0xa286, 0x0002, 0x1158, 0x70d0, 0xc0b5, 0x70d2, 0x2c00, 0x70b6, + 0x2d00, 0x70ba, 0x0030, 0x080c, 0x3f38, 0x0018, 0xa286, 0x0003, + 0x0dd0, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, + 0x7ca8, 0xa484, 0x001f, 0xa215, 0xae86, 0x4740, 0x0108, 0xc2fd, + 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0x2118, 0x70c8, 0xa168, 0x2d04, + 0x2d08, 0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, 0x0118, 0x6800, + 0x0cb8, 0x0409, 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x0904, 0x36b9, + 0xd0dc, 0x0178, 0x7060, 0xa086, 0x0004, 0x1140, 0x7070, 0xa206, + 0x1128, 0x7074, 0xa306, 0x1110, 0x7062, 0x707a, 0x080c, 0x3a59, + 0x0480, 0x681b, 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x080c, 0x3a53, + 0x707b, 0x0000, 0x0430, 0x7003, 0x0005, 0xb284, 0x0600, 0x0118, + 0x2001, 0x8ee0, 0x0010, 0x2001, 0x8f12, 0x2068, 0x704a, 0x0156, + 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x1f04, 0x36a2, 0x015e, + 0xb284, 0x0600, 0x0110, 0xc2fc, 0x0008, 0xc2fd, 0x6a16, 0xad80, + 0x0009, 0x7042, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, + 0x0005, 0xc6ec, 0xa6ac, 0x0060, 0x0904, 0x3700, 0x6b98, 0x6c94, + 0x69ac, 0x68b0, 0xa105, 0x11e0, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, + 0xa586, 0x0060, 0x05c8, 0xd6f4, 0x1108, 0xc6ed, 0xa6b4, 0xb7ff, + 0x7e5a, 0x2009, 0x0083, 0xd69c, 0x0128, 0x2009, 0x0082, 0x2019, + 0x0000, 0x2320, 0x791a, 0xd6ec, 0x0588, 0x080c, 0x41eb, 0x0470, + 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x01f8, 0x7bd2, + 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x1108, 0xc6ed, 0xc6f4, + 0x7e5a, 0x2011, 0x0083, 0xd69c, 0x0128, 0x2011, 0x0082, 0x2019, + 0x0000, 0x2320, 0x7a1a, 0xd6ec, 0x0188, 0x080c, 0x4218, 0x0070, + 0x2019, 0x0000, 0x2320, 0x0010, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, + 0x0083, 0xd69c, 0x0110, 0x2009, 0x0082, 0x791a, 0x68c0, 0x7056, + 0x2d00, 0x704a, 0x68c4, 0x2060, 0x71d0, 0x2001, 0x4701, 0x2004, + 0xd0c4, 0x15c8, 0x70d4, 0xa02d, 0x01b8, 0xd1bc, 0x0548, 0x7a80, + 0xa294, 0x0f00, 0x70d8, 0xa206, 0x0118, 0x78e0, 0xa504, 0x1558, + 0x70d6, 0xc1bc, 0x71d2, 0x0438, 0x2031, 0x0001, 0x852c, 0x0218, + 0x8633, 0x8210, 0x0cd8, 0x0005, 0x7de0, 0xa594, 0xff00, 0x0130, + 0x2011, 0x0008, 0x852f, 0x0c81, 0x8637, 0x0008, 0x0c69, 0x8217, + 0x7880, 0xa084, 0x0f00, 0xa206, 0x0170, 0x72da, 0x76d6, 0x0058, + 0x7a80, 0xa294, 0x0f00, 0x70d8, 0xa236, 0x0dc0, 0x78e0, 0xa534, + 0x0da8, 0xc1bd, 0x71d2, 0xd1b4, 0x1904, 0x25ae, 0x2300, 0xa405, + 0x0904, 0x25ae, 0x70a0, 0xa086, 0x0001, 0x1904, 0x25f2, 0x0005, + 0x6020, 0xa005, 0x0150, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, + 0x600a, 0x700f, 0x0100, 0x702c, 0x6026, 0x0005, 0xa006, 0x080c, + 0x3f38, 0x7000, 0xa086, 0x0002, 0x0120, 0x7060, 0xa086, 0x0005, + 0x1150, 0x682b, 0x0000, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, + 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, 0x0002, 0x25b1, + 0x3794, 0x3791, 0x37b1, 0x379d, 0x25b1, 0x378f, 0x378f, 0x080c, + 0x255d, 0x0449, 0x0411, 0x0028, 0x0431, 0x7058, 0x2060, 0x6800, + 0x6002, 0x080c, 0x1db1, 0x0804, 0x25b1, 0x7060, 0x7063, 0x0000, + 0x707f, 0x0000, 0x0002, 0x37ad, 0x37ad, 0x37ab, 0x37ab, 0x37ab, + 0x37ad, 0x37ab, 0x37ad, 0x0804, 0x2a7c, 0x7063, 0x0000, 0x0804, + 0x25b1, 0x681b, 0x0000, 0x0804, 0x3195, 0x6800, 0xa005, 0x1108, + 0x6002, 0x6006, 0x0005, 0x6410, 0x84ff, 0x0168, 0x2009, 0x4702, + 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, 0x4704, + 0x2404, 0xc0a5, 0x2022, 0x6008, 0xc0a4, 0x600a, 0x0005, 0x6018, + 0xa005, 0x0110, 0x8001, 0x601a, 0x0005, 0x080c, 0x3c58, 0x681b, + 0x0018, 0x0490, 0x080c, 0x3c58, 0x681b, 0x0019, 0x0468, 0x080c, + 0x3c58, 0x681b, 0x001a, 0x0440, 0x080c, 0x3c58, 0x681b, 0x0003, + 0x0418, 0x7770, 0x080c, 0x3b81, 0x7174, 0xa18c, 0x00ff, 0x3210, + 0xa294, 0x0600, 0x0118, 0xa1e8, 0x8cc0, 0x0010, 0xa1e8, 0x8dd0, + 0x2d04, 0x2d08, 0x2068, 0xa005, 0x1118, 0x707a, 0x0804, 0x25b1, + 0x6814, 0x7270, 0xa206, 0x0110, 0x6800, 0x0c98, 0x6800, 0x200a, + 0x681b, 0x0005, 0x707b, 0x0000, 0x080c, 0x37bb, 0x6820, 0xd084, + 0x1110, 0x080c, 0x37b5, 0x080c, 0x37cf, 0x681f, 0x0000, 0x6823, + 0x0020, 0x080c, 0x1db1, 0x0804, 0x25b1, 0xa282, 0x0003, 0x1904, + 0x3a21, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, + 0xc1bd, 0x6922, 0xd1c4, 0x05b0, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, + 0x0530, 0xa682, 0x0018, 0x0218, 0x0110, 0x2031, 0x0018, 0xa686, + 0x0010, 0x1108, 0x8630, 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, + 0x3ada, 0x0118, 0x080c, 0x3908, 0x00a0, 0x080c, 0x3aa6, 0x080c, + 0x3905, 0x6920, 0xc1c5, 0x6922, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, + 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x080c, + 0x3905, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, + 0x0083, 0x0005, 0x00c6, 0x7054, 0x2060, 0x6100, 0xd1e4, 0x0598, + 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x0018, 0x0218, 0x0110, + 0x2011, 0x0018, 0x2600, 0xa202, 0x1208, 0x2230, 0xa686, 0x0010, + 0x1108, 0x8630, 0x6208, 0xa294, 0x00ff, 0x78ec, 0xd0e4, 0x0130, + 0xa282, 0x000a, 0x1240, 0x2011, 0x000a, 0x0028, 0xa282, 0x000c, + 0x1210, 0x2011, 0x000c, 0x2200, 0xa502, 0x1208, 0x2228, 0x080c, + 0x3aaa, 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, 0x3ada, 0x0118, + 0x080c, 0x3908, 0x0020, 0x080c, 0x3aa6, 0x080c, 0x3905, 0x7858, + 0xc095, 0x785a, 0x00ce, 0x781b, 0x0082, 0x0005, 0x00c6, 0x2960, + 0x6000, 0xd0e4, 0x1188, 0xd0b4, 0x1150, 0x6010, 0xa084, 0x000f, + 0x1130, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x00ce, 0x0005, 0x2011, + 0x0032, 0x2019, 0x0000, 0x00f0, 0x68a0, 0xd0cc, 0x1dc0, 0x6208, + 0xa294, 0x00ff, 0x78ec, 0xd0e4, 0x0130, 0xa282, 0x000b, 0x1218, + 0x2011, 0x000a, 0x0028, 0xa282, 0x000c, 0x1210, 0x2011, 0x000c, + 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x0018, 0x0218, 0x0110, + 0x2019, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, + 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x080c, + 0x3a66, 0x00ce, 0x0005, 0x00c6, 0x2960, 0x6104, 0xa18c, 0xfff5, + 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0000, 0x78ab, 0x0001, + 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, + 0x6820, 0xc0c5, 0x6822, 0x00ce, 0x0005, 0xa006, 0x2030, 0x2010, + 0x00c6, 0x7154, 0x2160, 0x2018, 0x2008, 0xa084, 0xffe0, 0xa635, + 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, 0x7770, + 0xa18c, 0x000f, 0xa105, 0x2029, 0x4705, 0x252c, 0xd5cc, 0x0140, + 0xd3a4, 0x0110, 0xa085, 0x0800, 0xd3fc, 0x0110, 0xa085, 0x8080, + 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x001f, 0x8637, 0x8204, 0x8004, + 0xa605, 0x600e, 0x6004, 0xa084, 0xffd5, 0x6006, 0x00ce, 0x0005, + 0xa282, 0x0002, 0x1904, 0x3a2b, 0x7aa8, 0x6920, 0xc1bd, 0x6922, + 0xd1cc, 0x0568, 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, + 0x1a04, 0x3a1c, 0x080c, 0x39af, 0x080c, 0x3905, 0xa980, 0x0001, + 0x200c, 0x080c, 0x3b7d, 0x080c, 0x38a6, 0x88ff, 0x0178, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, + 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x7e58, 0xd6d4, + 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0xa282, + 0x0002, 0x1218, 0xa284, 0x0001, 0x0140, 0x7154, 0xa188, 0x0000, + 0x210c, 0xd1ec, 0x1110, 0x2011, 0x0000, 0x080c, 0x3a98, 0x0479, + 0x080c, 0x3905, 0x7858, 0xc095, 0x785a, 0x781b, 0x0082, 0x0005, + 0x00c6, 0x0026, 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x1158, + 0xd0bc, 0x1138, 0x6014, 0xd0b4, 0x1120, 0xc1a4, 0x6106, 0xa006, + 0x0088, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, + 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x080c, 0x3a66, 0x6820, 0xa085, + 0x0200, 0x6822, 0x002e, 0x00ce, 0x0005, 0x8807, 0xa715, 0x00c6, + 0x2009, 0x0000, 0x7054, 0x2060, 0x82ff, 0x0110, 0x2009, 0x0040, + 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, 0xff9f, 0xa105, + 0xc0ec, 0xd0b4, 0x1108, 0xc0ed, 0x6100, 0xd1f4, 0x0110, 0xa085, + 0x0020, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, 0xffef, 0x6006, + 0x00ce, 0x0005, 0x0006, 0x7000, 0xa086, 0x0003, 0x0110, 0x000e, + 0x0010, 0x000e, 0x0488, 0xd6ac, 0x0578, 0x7888, 0xa084, 0x0040, + 0x0558, 0x7bb8, 0x8307, 0xa084, 0x007f, 0x1508, 0x8207, 0xa084, + 0x00ff, 0xa09e, 0x0001, 0x1904, 0x3a43, 0xd6f4, 0x11d0, 0x79d8, + 0x7adc, 0xa108, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, + 0x080c, 0x42c7, 0x781b, 0x0080, 0xb284, 0x0600, 0x0118, 0x2001, + 0x0000, 0x0010, 0x2001, 0x0001, 0x080c, 0x4184, 0x0005, 0x080c, + 0x255d, 0x781b, 0x0080, 0x0005, 0x781b, 0x0083, 0x0005, 0x2039, + 0x0000, 0x2041, 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, + 0x3908, 0x080c, 0x39ad, 0x7e58, 0x080c, 0x3a5f, 0x781b, 0x0082, + 0x0005, 0x0cd1, 0x6820, 0xc0c4, 0x6822, 0x00c6, 0x7054, 0x2060, + 0x080c, 0x3932, 0x00b0, 0x0c81, 0x6820, 0xc0cc, 0x6822, 0x00c6, + 0x7054, 0x2060, 0x080c, 0x39cc, 0x0060, 0x0c31, 0x6820, 0xa084, + 0xecff, 0x6822, 0x00c6, 0x7054, 0x2060, 0x6004, 0xa084, 0xffc5, + 0x6006, 0x00ce, 0x0005, 0x0049, 0x781b, 0x0082, 0x0005, 0x6827, + 0x0002, 0x0049, 0x781b, 0x0082, 0x0005, 0x2001, 0x0005, 0x0088, + 0x2001, 0x000c, 0x0070, 0x6820, 0xc0d5, 0x6822, 0x2001, 0x0006, + 0x0040, 0x2001, 0x000d, 0x0028, 0x2001, 0x0009, 0x0010, 0x2001, + 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, 0x70d0, 0xd0b4, + 0x0168, 0xc0b4, 0x70d2, 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x0005, 0x0076, + 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0, 0x4bc0, + 0xae8e, 0x4740, 0x0110, 0xa0e0, 0x4c40, 0xa7b8, 0x0020, 0x7f9a, + 0x79a4, 0xa184, 0x7fe0, 0x78ae, 0x6012, 0x79a4, 0xa184, 0x773f, + 0x78a6, 0x6016, 0x6004, 0xa085, 0x0038, 0x6006, 0x007e, 0x0005, + 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, + 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, 0x0800, 0x2031, 0x0000, + 0x2029, 0x0032, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0003, + 0x78ab, 0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, + 0x0804, 0x3a66, 0x0156, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, + 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xffe0, 0x2021, 0x3b66, + 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, + 0xffe0, 0xa106, 0x0128, 0x8420, 0x2300, 0xa210, 0x1f04, 0x3ace, + 0x015e, 0x0005, 0x0156, 0x0804, 0x3b1c, 0x2021, 0x3b74, 0x20a9, + 0x0009, 0x2011, 0x0029, 0xa582, 0x0028, 0x0550, 0x8420, 0x95a9, + 0x2011, 0x0033, 0xa582, 0x0033, 0x0618, 0x8420, 0x95a9, 0x2019, + 0x000a, 0x2011, 0x0065, 0x2200, 0xa502, 0x02d0, 0x8420, 0x2300, + 0xa210, 0x1f04, 0x3af3, 0x015e, 0x0088, 0x2021, 0x3b66, 0x2019, + 0x0011, 0x20a9, 0x000e, 0x2011, 0x0033, 0x2200, 0xa502, 0x0240, + 0x8420, 0x2300, 0xa210, 0x1f04, 0x3b05, 0x015e, 0xa006, 0x0005, + 0x8211, 0x015e, 0xa582, 0x0064, 0x1220, 0x7808, 0xa085, 0x0070, + 0x780a, 0x2404, 0xa005, 0x0005, 0xa886, 0x0002, 0x01e8, 0x2021, + 0x3b52, 0x20a9, 0x000d, 0x2011, 0x0028, 0xa582, 0x0028, 0x0d48, + 0x8420, 0x2019, 0x0019, 0x2011, 0x0033, 0x2200, 0xa502, 0x0e00, + 0x8420, 0x2300, 0xa210, 0x1f04, 0x3b2d, 0x015e, 0x2011, 0x0184, + 0xa582, 0x0185, 0x0ab0, 0x0890, 0x2021, 0x3b61, 0x20a9, 0x0003, + 0x2011, 0x0024, 0xa586, 0x0024, 0x0960, 0x8420, 0x2011, 0x0028, + 0xa586, 0x0028, 0x0930, 0x8420, 0x2019, 0x0019, 0x2011, 0x0033, + 0x0804, 0x3b05, 0x1021, 0x2202, 0x3403, 0x4604, 0x5805, 0x6a06, + 0x7c07, 0x4610, 0x4612, 0x5812, 0x5a12, 0x6a14, 0x6c14, 0x6e14, + 0x7e17, 0x9021, 0xb002, 0xe204, 0xe210, 0xe210, 0x1209, 0x3002, + 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, + 0x7a06, 0x0c07, 0x0c07, 0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, + 0x6a06, 0x6c06, 0x7c07, 0x7e07, 0x0e00, 0x789b, 0x0080, 0xa046, + 0x0005, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0xd7fc, 0x0118, 0xa0e0, 0x6cc0, 0x0010, + 0xa0e0, 0x4cc0, 0x0005, 0x00e6, 0x00f6, 0xd084, 0x0138, 0x2079, + 0x0100, 0x2009, 0x4780, 0x2071, 0x4780, 0x0030, 0x2009, 0x4740, + 0x2079, 0x0200, 0x2071, 0x4740, 0x2091, 0x8000, 0x2104, 0xa084, + 0x000f, 0x0002, 0x3bb4, 0x3bb4, 0x3bb4, 0x3bb4, 0x3bb4, 0x3bb4, + 0x3bb2, 0x3bb2, 0x080c, 0x255d, 0x69b4, 0xc1f5, 0xa18c, 0xff9f, + 0x69b6, 0xa005, 0x0580, 0x7858, 0xa084, 0xff9f, 0xa085, 0x6000, + 0x785a, 0x7828, 0xa086, 0x1814, 0x1530, 0x784b, 0x0004, 0x7848, + 0xa084, 0x0004, 0x1de0, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, + 0x1de0, 0x7830, 0xd0bc, 0x11b8, 0xb284, 0x0800, 0x0118, 0x0104, + 0x3beb, 0x0010, 0x0304, 0x3beb, 0x79e4, 0xa184, 0x0030, 0x0158, + 0x78ec, 0xa084, 0x0003, 0x0138, 0x681c, 0xd0ac, 0x1110, 0x00d9, + 0x0010, 0x781b, 0x00fb, 0x00fe, 0x00ee, 0x0005, 0x2001, 0x4701, + 0x2004, 0xd0ac, 0x1118, 0x6814, 0x080c, 0x2486, 0x0005, 0x781b, + 0x0083, 0x0005, 0x781b, 0x0082, 0x0005, 0x781b, 0x0071, 0x0005, + 0x781b, 0x006e, 0x0005, 0x2009, 0x4719, 0x210c, 0xa186, 0x0000, + 0x0150, 0xa186, 0x0001, 0x0150, 0x701f, 0x000b, 0x7063, 0x0001, + 0x781b, 0x0054, 0x0005, 0x781b, 0x00f3, 0x0005, 0x701f, 0x000a, + 0x0005, 0x2009, 0x4719, 0x210c, 0xa186, 0x0000, 0x0168, 0xa186, + 0x0001, 0x0138, 0x701f, 0x000b, 0x7063, 0x0001, 0x781b, 0x0054, + 0x0005, 0x701f, 0x000a, 0x0005, 0x781b, 0x00f2, 0x0005, 0x781b, + 0x00fb, 0x0005, 0x781b, 0x00fa, 0x0005, 0x781b, 0x00cc, 0x0005, + 0x781b, 0x00cb, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, + 0x7063, 0x0001, 0x781b, 0x0054, 0x0005, 0x7830, 0xa084, 0x00c0, + 0x1170, 0x7808, 0xc08c, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000, + 0x78ec, 0xa084, 0x0021, 0x0118, 0x7808, 0xc08d, 0x780a, 0x0005, + 0x7808, 0xc08d, 0x780a, 0x0005, 0x7830, 0xa084, 0x0040, 0x1de0, + 0xb284, 0x0800, 0x0118, 0x1104, 0x3c6a, 0x0010, 0x1304, 0x3c6a, + 0x78ac, 0x0005, 0x7808, 0xa084, 0xfffd, 0x780a, 0xe000, 0xe000, + 0xe000, 0xe000, 0x78ec, 0xa084, 0x0021, 0x0140, 0xb284, 0x0800, + 0x0118, 0x1104, 0x3c79, 0x0010, 0x1304, 0x3c7c, 0x78ac, 0x0006, + 0x7808, 0xa085, 0x0002, 0x780a, 0x000e, 0x0005, 0xa784, 0x0001, + 0x1904, 0x323b, 0xa784, 0x0070, 0x0140, 0x00c6, 0x2d60, 0x2f68, + 0x080c, 0x2478, 0x2d78, 0x2c68, 0x00ce, 0xa784, 0x0008, 0x0148, + 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x323b, 0x0804, + 0x3bf7, 0xa784, 0x0004, 0x01c8, 0x78b8, 0xa084, 0x8000, 0x01a8, + 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x323b, 0x78e4, + 0xa084, 0x0007, 0xa086, 0x0001, 0x1140, 0x78c0, 0xa685, 0x4800, + 0x2030, 0x7e5a, 0x781b, 0x00fb, 0x0005, 0xa784, 0x0080, 0x0140, + 0x7884, 0xd0fc, 0x0128, 0x080c, 0x3a43, 0x681b, 0x0022, 0x0005, + 0x681b, 0x0003, 0x7858, 0xa084, 0x5f00, 0x681e, 0x682f, 0x0000, + 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, + 0x2b9a, 0xb284, 0x0800, 0x0110, 0x0104, 0x25ae, 0x0304, 0x25ae, + 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, + 0x0118, 0xa080, 0x4c40, 0x0010, 0xa080, 0x4bc0, 0x2060, 0x2048, + 0x7056, 0x2a60, 0x0005, 0x00c6, 0x2960, 0x6000, 0xd0ac, 0x0904, + 0x3d41, 0x68a0, 0xd1ac, 0x1120, 0xa084, 0x0e00, 0x0904, 0x3d3f, + 0x6108, 0x8117, 0xa18c, 0x00ff, 0x631c, 0x832f, 0xd0dc, 0x0110, + 0xa39d, 0x0001, 0xd0cc, 0x11c8, 0xa584, 0x00ff, 0x0138, 0x78ec, + 0xd0e4, 0x0110, 0x8213, 0x00b8, 0x2029, 0x0000, 0xa182, 0x000c, + 0x1290, 0x78ec, 0xd0e4, 0x1118, 0x2009, 0x000c, 0x0060, 0xa182, + 0x000b, 0x1248, 0x2009, 0x000a, 0x0030, 0x2009, 0x0032, 0x2011, + 0x0000, 0x2029, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, + 0x0004, 0x79aa, 0x78ab, 0x0000, 0x7aaa, 0x7baa, 0x7daa, 0xa8c0, + 0x0008, 0x6820, 0xa085, 0x1000, 0x6822, 0x080c, 0x3a66, 0xa085, + 0x0001, 0x00ce, 0x0005, 0xa282, 0x0006, 0x1904, 0x3a35, 0x7da8, + 0x7eac, 0x8637, 0xa5ac, 0x00ff, 0xa6b4, 0x00ff, 0x7fac, 0x8747, + 0xa7bc, 0x00ff, 0xa8c4, 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1e4, + 0x0904, 0x3db5, 0xa18c, 0xecff, 0x6922, 0xa782, 0x0002, 0x1a04, + 0x3a0f, 0xa6b4, 0x00ff, 0x0904, 0x3db2, 0xa682, 0x0031, 0x1a04, + 0x3a0f, 0xa582, 0x0009, 0x0a04, 0x3a0f, 0xa882, 0x0003, 0x1a04, + 0x3a0f, 0xa886, 0x0002, 0x01d0, 0xa886, 0x0000, 0x1904, 0x3a0f, + 0x2001, 0x000c, 0x79ec, 0xd1e4, 0x0110, 0x2001, 0x000a, 0xa502, + 0x1290, 0x080c, 0x3a0f, 0x00c6, 0x2960, 0x6004, 0xa085, 0x001a, + 0x6006, 0x6000, 0xc0ac, 0x6002, 0x00ce, 0x0005, 0xa786, 0x0000, + 0x0904, 0x3a0f, 0x8634, 0xa682, 0x0018, 0x0228, 0x0120, 0x2031, + 0x0018, 0x0804, 0x3e03, 0xa686, 0x0010, 0x1108, 0x8630, 0x852b, + 0x852b, 0x080c, 0x3ada, 0x0904, 0x3a0f, 0x080c, 0x3908, 0x080c, + 0x39ad, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, + 0x0083, 0x0005, 0x080c, 0x3905, 0x0c90, 0xa886, 0x0002, 0x1108, + 0x8634, 0x7154, 0xa188, 0x0000, 0x210c, 0xd1ac, 0x0904, 0x3a0f, + 0xd1ec, 0x1120, 0x2039, 0x0000, 0x2041, 0x0000, 0xd1e4, 0x1120, + 0x2031, 0x0000, 0x2041, 0x0000, 0xa782, 0x0002, 0x12c8, 0x621c, + 0xa284, 0x00ff, 0xa706, 0x0110, 0x2039, 0x0000, 0xa605, 0x0190, + 0x6108, 0x811f, 0xa39c, 0x00ff, 0x0168, 0xa302, 0x1208, 0x2330, + 0x8807, 0xa705, 0xa086, 0x0201, 0x0160, 0xa886, 0x0000, 0x0168, + 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, + 0x0070, 0xa284, 0xff00, 0x1108, 0x2040, 0xa184, 0x00ff, 0xa502, + 0x0108, 0x2128, 0x852b, 0x852b, 0x080c, 0x3ada, 0x0d58, 0x080c, + 0x3908, 0x080c, 0x39ad, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, + 0x0006, 0x78ab, 0x0004, 0x7daa, 0x78ab, 0x0000, 0x7eaa, 0x7faa, + 0x2800, 0x78aa, 0x789b, 0x0060, 0x78ab, 0x0008, 0x6820, 0xc0e5, + 0x6822, 0x080c, 0x3a66, 0x7858, 0xc095, 0x785a, 0x781b, 0x0082, + 0x0005, 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9855, + 0x984d, 0x0014, 0x9911, 0x98ff, 0x0014, 0x0014, 0x0090, 0x00e7, + 0x0100, 0x0402, 0x2008, 0xf880, 0x0018, 0x0017, 0x840f, 0xd8c1, + 0x0014, 0x0016, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0x2500, + 0x0013, 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0xa200, 0x3806, 0x8839, 0x20c4, 0x0864, 0xa850, 0x3008, 0x28c1, + 0x9d18, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, + 0x1856, 0x883a, 0xa808, 0x28e2, 0x9cce, 0xa8f3, 0x0864, 0xa83e, + 0x300c, 0xa801, 0x3008, 0x28e1, 0x9cce, 0x28a2, 0x7163, 0xa831, + 0x2021, 0xa818, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, 0x6fc0, + 0x67a4, 0x6c80, 0x0212, 0xa205, 0x883d, 0x882b, 0x1814, 0x883b, + 0x7027, 0x85f2, 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa813, + 0x883e, 0xa811, 0x2882, 0x7162, 0xa814, 0x280a, 0xa204, 0x64c0, + 0x6de0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, + 0xa802, 0x7861, 0x883e, 0x206a, 0x28c1, 0x9d18, 0x2042, 0x2101, + 0xa8ca, 0x2902, 0xa20e, 0xa80b, 0xa207, 0x0014, 0xa203, 0x8000, + 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, + 0x7121, 0x0014, 0x0704, 0x3008, 0x9cce, 0x0014, 0xa202, 0x8000, + 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, 0x883f, 0x08e6, + 0xa8f5, 0xf861, 0xa8eb, 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, + 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, + 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, 0x8000, 0x2849, + 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2081, 0x2802, 0x1011, + 0xa8fc, 0xa889, 0x3008, 0x20a1, 0x283c, 0x1011, 0xa8fc, 0xa209, + 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0x0210, + 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, 0x18f2, + 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d22, 0x0704, + 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, + 0x8008, 0xa8fa, 0x8160, 0x842a, 0x8180, 0xf021, 0x3008, 0x84a8, + 0x11d7, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016, 0x0000, + 0x0126, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x7204, 0x7008, + 0xc09c, 0xa205, 0x11a0, 0x720c, 0x82ff, 0x0128, 0x8aff, 0x1178, + 0x7200, 0xd284, 0x1160, 0x7804, 0xd0cc, 0x0110, 0x080c, 0x433a, + 0x7007, 0x0008, 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, 0x7000, + 0xa084, 0x0003, 0x7002, 0xc69c, 0xd084, 0x0588, 0x7108, 0xe000, + 0x7008, 0xa106, 0x1dd8, 0xa184, 0x0003, 0x0904, 0x3fb4, 0xa184, + 0x01e0, 0x1904, 0x3fb4, 0xd1f4, 0x1d88, 0xa184, 0x3000, 0xa086, + 0x1000, 0x0d60, 0x2011, 0x0180, 0x710c, 0x8211, 0x0130, 0x7008, + 0xd0f4, 0x1d20, 0x700c, 0xa106, 0x0dc0, 0x7007, 0x0012, 0x7108, + 0xe000, 0x7008, 0xa106, 0x1dd8, 0xa184, 0x0003, 0x0568, 0xd194, + 0x0db0, 0xd1f4, 0x0548, 0x7007, 0x0002, 0x0880, 0x0428, 0x7108, + 0xd1fc, 0x0130, 0x080c, 0x40c0, 0x8aff, 0x0904, 0x3f3e, 0x0cb8, + 0x700c, 0xa08c, 0x07ff, 0x01e8, 0x7004, 0xd084, 0x0178, 0x7014, + 0xa005, 0x1148, 0x7010, 0x7310, 0xa306, 0x1de0, 0x2300, 0xa005, + 0x0128, 0xa102, 0x1e20, 0x7007, 0x0010, 0x0030, 0x8aff, 0x0148, + 0x080c, 0x427d, 0x1de8, 0x09d8, 0x080c, 0x4046, 0x012e, 0x2000, + 0x0005, 0x7204, 0x7108, 0xc19c, 0x8103, 0x1218, 0x7007, 0x0002, + 0x0cc0, 0xa205, 0x1d88, 0x7007, 0x0008, 0x7003, 0x0008, 0x0006, + 0x2001, 0x4701, 0x2004, 0xd0cc, 0x0110, 0x080c, 0x433a, 0x000e, + 0x012e, 0x2000, 0x0005, 0x6428, 0x84ff, 0x0508, 0x2c70, 0x7004, + 0xa0bc, 0x000f, 0xa7b8, 0x4007, 0x273c, 0x87fb, 0x1148, 0x0210, + 0x080c, 0x255d, 0x609c, 0xa075, 0x0190, 0x0c88, 0x2039, 0x3ffc, + 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, 0x0138, + 0x8738, 0x2704, 0xa005, 0x1da8, 0x709c, 0xa075, 0x1d00, 0x0005, + 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, + 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, + 0x3ffc, 0x3ff9, 0x0000, 0x0000, 0x8000, 0x0000, 0x3ffc, 0x0000, + 0x4004, 0x4001, 0x0000, 0x0000, 0x0000, 0x0000, 0x4004, 0x0000, + 0x3fff, 0x3fff, 0x0000, 0x0000, 0x8000, 0x0000, 0x3fff, 0x0000, + 0x4005, 0x4005, 0x0000, 0x0000, 0x0000, 0x0000, 0x4005, 0x2079, + 0x4700, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, + 0x0001, 0x2009, 0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, + 0x0002, 0x7003, 0x0000, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1128, + 0x8109, 0x0118, 0x2071, 0x0020, 0x0c80, 0x0005, 0x7004, 0x8004, + 0x1a04, 0x409c, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, + 0x0120, 0x080c, 0x40f8, 0x0804, 0x40bc, 0x7007, 0x0012, 0x2019, + 0x0000, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0120, + 0x080c, 0x40f8, 0x0804, 0x40bc, 0xa19c, 0x300c, 0xa386, 0x2004, + 0x0190, 0xa386, 0x0008, 0x01c0, 0x7004, 0xd084, 0x1148, 0x7108, + 0x7008, 0xa106, 0x1de0, 0xa184, 0x0003, 0x0110, 0x0804, 0x40f8, + 0xa386, 0x200c, 0x19f0, 0x7200, 0x8204, 0x0230, 0x730c, 0xa384, + 0x07ff, 0x0110, 0x080c, 0x255d, 0x7108, 0x7008, 0xa106, 0x1de0, + 0xa184, 0x01e0, 0x0118, 0x080c, 0x40f8, 0x0470, 0x7007, 0x0012, + 0x7000, 0xd084, 0x1148, 0x7310, 0x7014, 0xa305, 0x0128, 0x710c, + 0xa184, 0x07ff, 0x1904, 0x4046, 0x7108, 0x7008, 0xa106, 0x1de0, + 0xa184, 0x01e0, 0x0118, 0x080c, 0x40f8, 0x00b0, 0x7007, 0x0012, + 0x7007, 0x0008, 0x7004, 0xd09c, 0x1de8, 0x7108, 0x7008, 0xa106, + 0x1de0, 0xa184, 0x01e0, 0x0118, 0x080c, 0x40f8, 0x0028, 0x7007, + 0x0012, 0x7108, 0x8103, 0x0e88, 0x7003, 0x0008, 0x0005, 0x7108, + 0xa184, 0x01e0, 0x15a8, 0x7108, 0xa184, 0x01e0, 0x1588, 0xa184, + 0x0007, 0x0002, 0x40d4, 0x40e2, 0x40d2, 0x40e2, 0x40d2, 0x4132, + 0x40d2, 0x4130, 0x080c, 0x255d, 0x7004, 0xa084, 0x0010, 0xc08d, + 0x7006, 0x8aff, 0x1118, 0x2049, 0x0000, 0x0005, 0x080c, 0x427d, + 0x1de8, 0x0005, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x7004, + 0xd084, 0x1140, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x0003, + 0x0108, 0x0030, 0x8aff, 0x0118, 0x080c, 0x427d, 0x1de8, 0x0005, + 0x7007, 0x0012, 0x7108, 0x1d04, 0x40fb, 0x2091, 0x6000, 0x1d04, + 0x40ff, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, + 0xd09c, 0x1de8, 0x7007, 0x0012, 0x7108, 0xd1fc, 0x1dd8, 0x7003, + 0x0000, 0x7000, 0xa005, 0x1130, 0x7004, 0xa005, 0x1118, 0x700c, + 0xa005, 0x0108, 0x0c40, 0x2049, 0x0000, 0xb284, 0x0200, 0x0118, + 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, 0x080c, 0x3b93, 0x681b, + 0x0002, 0x2051, 0x0000, 0x0005, 0x080c, 0x255d, 0x080c, 0x255d, + 0x080c, 0x4171, 0x7210, 0x7114, 0x700c, 0xa09c, 0x07ff, 0x2800, + 0xa300, 0xa211, 0xa189, 0x0000, 0x04a1, 0x2704, 0x2c58, 0xac60, + 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305, + 0x0140, 0x1238, 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, + 0x0c58, 0x2b60, 0x8a07, 0x0006, 0x6004, 0xd09c, 0x0118, 0xa7ba, + 0x4001, 0x0010, 0xa7ba, 0x3ff9, 0x000e, 0xa73d, 0x2c00, 0x6886, + 0x6f8a, 0x6c92, 0x6b8e, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, + 0x01e0, 0x0110, 0x080c, 0x40f8, 0x7007, 0x0012, 0x080c, 0x4046, + 0x0005, 0x8a50, 0x8739, 0x2704, 0xa004, 0x1168, 0x6000, 0xa064, + 0x1108, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, 0x4017, 0x203c, + 0x87fb, 0x090c, 0x255d, 0x0005, 0x0126, 0x00d6, 0x70d0, 0xa084, + 0x4c00, 0x8004, 0x2090, 0x00de, 0x6884, 0x2060, 0x6888, 0x6b8c, + 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x0006, 0x6804, + 0xa084, 0x0008, 0x000e, 0x0118, 0xa0b8, 0x4001, 0x0010, 0xa0b8, + 0x3ff9, 0xb284, 0x0200, 0x0110, 0x7e20, 0x0008, 0x7e24, 0xa6b5, + 0x000c, 0x681c, 0xd0b4, 0x0108, 0xc685, 0x2400, 0xa305, 0x0518, + 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, + 0xa301, 0x701e, 0xd19c, 0x0140, 0x6010, 0xa081, 0x0000, 0x7022, + 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, + 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, + 0x080c, 0x42a4, 0x0010, 0x080c, 0x427d, 0x1de8, 0x012e, 0x2000, + 0x0005, 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, + 0x00de, 0x7007, 0x0004, 0x7004, 0xd094, 0x1de8, 0x7003, 0x0008, + 0x012e, 0x2000, 0x0005, 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, + 0x8004, 0x2090, 0x00de, 0x7e20, 0xb284, 0x0200, 0x1108, 0x7e24, + 0xa6b5, 0x000c, 0x681c, 0xd0ac, 0x1118, 0xc685, 0x7003, 0x0000, + 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x4007, + 0x273c, 0x87fb, 0x1138, 0x0210, 0x080c, 0x255d, 0x689c, 0xa065, + 0x0120, 0x0c88, 0x080c, 0x427d, 0x1de8, 0x012e, 0x2000, 0x0005, + 0x0126, 0x0006, 0x0016, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, + 0x2090, 0x7e20, 0xb284, 0x0200, 0x1108, 0x7e24, 0x00de, 0x003e, + 0x004e, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0128, 0xc685, 0x7003, + 0x0000, 0x7007, 0x0004, 0x2049, 0x4218, 0x6828, 0xa055, 0x00d6, + 0x0904, 0x4279, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, + 0x4007, 0x273c, 0x87fb, 0x1140, 0x0210, 0x080c, 0x255d, 0x709c, + 0xa075, 0x2060, 0x0570, 0x0c80, 0x2704, 0xae68, 0x6808, 0xa422, + 0x680c, 0xa31b, 0x0268, 0x8a51, 0x1110, 0x080c, 0x255d, 0x8738, + 0x2704, 0xa005, 0x1d90, 0x709c, 0xa075, 0x2060, 0x01d0, 0x08e0, + 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, + 0x690c, 0x2300, 0xa11b, 0x1210, 0x080c, 0x255d, 0xb284, 0x0200, + 0x0118, 0x2071, 0x0050, 0x0010, 0x2071, 0x0020, 0x00de, 0x0804, + 0x41ad, 0x00de, 0x012e, 0x2000, 0x0005, 0x7008, 0x0006, 0xa084, + 0x01e0, 0x000e, 0x0110, 0xa006, 0x0005, 0xa084, 0x0003, 0xa086, + 0x0003, 0x1108, 0x0005, 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, + 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, 0xd09c, 0x0120, + 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, + 0xc085, 0x7006, 0x2079, 0x4700, 0x8a51, 0x01e8, 0x8738, 0x2704, + 0xa005, 0x1168, 0x609c, 0xa005, 0x01b8, 0x2060, 0x6004, 0xa084, + 0x000f, 0xa080, 0x4007, 0x203c, 0x87fb, 0x090c, 0x255d, 0x7008, + 0x0006, 0xa084, 0x01e0, 0x000e, 0x0110, 0xa006, 0x0028, 0xa084, + 0x0003, 0xa086, 0x0003, 0x0005, 0x2051, 0x0000, 0x0005, 0x0126, + 0x0006, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, + 0x008e, 0x7108, 0xa184, 0x0003, 0x1128, 0x6828, 0xa005, 0x0178, + 0x0804, 0x3f57, 0x7108, 0xd1fc, 0x0118, 0x080c, 0x40c0, 0x0c88, + 0x7007, 0x0010, 0x7108, 0xd1fc, 0x0de8, 0x080c, 0x40c0, 0x7008, + 0xa086, 0x0008, 0x1d30, 0x7000, 0xa005, 0x1d18, 0x7003, 0x0000, + 0x2049, 0x0000, 0x0006, 0x2001, 0x4701, 0x2004, 0xd0cc, 0x0110, + 0x080c, 0x433a, 0x000e, 0x012e, 0x2000, 0x0005, 0x0126, 0x0146, + 0x0136, 0x0156, 0x00c6, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, + 0x2090, 0x00de, 0x2049, 0x42fe, 0xad80, 0x0011, 0x20a0, 0xb284, + 0x0200, 0x0118, 0x2099, 0x0032, 0x0010, 0x2099, 0x0031, 0x700c, + 0xa084, 0x07ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, + 0x0001, 0x0118, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, 0x07ff, + 0x0130, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x1de0, 0x00ce, + 0x2049, 0x0000, 0x7003, 0x0000, 0x015e, 0x013e, 0x014e, 0x012e, + 0x2000, 0x0005, 0x6814, 0xd0fc, 0x0904, 0x437d, 0x7000, 0xd084, + 0x05e0, 0x7e24, 0xa6b5, 0x0004, 0x7007, 0x0004, 0x7004, 0xa084, + 0x0004, 0x1de0, 0x7118, 0x0016, 0x711c, 0x0016, 0x7120, 0x0016, + 0x7124, 0x0016, 0x701b, 0x0000, 0x701f, 0x3fff, 0x7023, 0x0000, + 0x7027, 0x0000, 0x7013, 0x0004, 0x7017, 0x0000, 0x7602, 0x7007, + 0x0001, 0x2001, 0xffff, 0x2009, 0x0031, 0x200a, 0x200a, 0x7108, + 0x7008, 0xa106, 0x1de0, 0xd1fc, 0x0dd0, 0x002e, 0x7226, 0x002e, + 0x7222, 0x002e, 0x721e, 0x002e, 0x721a, 0x7007, 0x0002, 0x7008, + 0xa086, 0x0008, 0x0110, 0x0804, 0x40f8, 0x7007, 0x0004, 0x7003, + 0x0000, 0x0005, 0x2091, 0x8000, 0x2091, 0x6000, 0x78ac, 0xa005, + 0x1168, 0x7974, 0x70d0, 0xa106, 0x1148, 0x781c, 0xa005, 0x0130, + 0x781f, 0x0000, 0x0e04, 0x4396, 0x2091, 0x4080, 0x2069, 0x4780, + 0xd7fc, 0x1110, 0x2069, 0x4740, 0x6800, 0xa084, 0x000f, 0x1198, + 0x68d0, 0xd0b4, 0x0180, 0xd0bc, 0x1170, 0x00f6, 0x2079, 0x0100, + 0xd7fc, 0x1110, 0x2079, 0x0200, 0x7830, 0xa084, 0x00c0, 0x1110, + 0x080c, 0x22bd, 0x00fe, 0x7830, 0x8001, 0x7832, 0x1904, 0x441d, + 0x7834, 0x7832, 0x2061, 0x6cc0, 0x2069, 0x4780, 0xc7fd, 0x68cc, + 0xa005, 0x0128, 0x8001, 0x68ce, 0x1110, 0x080c, 0x458f, 0x6800, + 0xa084, 0x000f, 0x0168, 0xa086, 0x0001, 0x0150, 0x6840, 0xa00d, + 0x0138, 0x2104, 0xa005, 0x0120, 0x8001, 0x200a, 0x0904, 0x452c, + 0x6814, 0xa005, 0x01a8, 0x8001, 0x6816, 0x1190, 0x68a3, 0x0001, + 0x00f6, 0xd7fc, 0x1118, 0x2079, 0x0200, 0x0010, 0x2079, 0x0100, + 0x080c, 0x3c58, 0x00fe, 0x6860, 0xa005, 0x0110, 0x080c, 0x22bd, + 0x687c, 0xa005, 0x0140, 0x8001, 0x687e, 0x1128, 0x6863, 0x0000, + 0x68d0, 0xc0c5, 0x68d2, 0x68d0, 0xd0fc, 0x01b0, 0xc0fc, 0x68d2, + 0x20a9, 0x0200, 0x6034, 0xa005, 0x0158, 0x8001, 0x6036, 0x68d0, + 0xc0fd, 0x68d2, 0x1128, 0x6010, 0xa005, 0x0110, 0x080c, 0x22bd, + 0xace0, 0x0010, 0x1f04, 0x4402, 0xd7fc, 0x0138, 0x2061, 0x4cc0, + 0x2069, 0x4740, 0xc7fc, 0x0804, 0x43bf, 0x0459, 0x7838, 0x8001, + 0x783a, 0x11a0, 0x783c, 0x783a, 0x2061, 0x4cc0, 0x2069, 0x4740, + 0xc7fc, 0x680c, 0xa005, 0x0110, 0x080c, 0x4499, 0xd7fc, 0x1130, + 0x2061, 0x6cc0, 0x2069, 0x4780, 0xc7fd, 0x0c98, 0x7810, 0xd0cc, + 0x0168, 0xd0ac, 0x1120, 0xd0a4, 0x0148, 0xc0ad, 0x7812, 0x2091, + 0x8001, 0x0e04, 0x4445, 0x080c, 0x2089, 0x0005, 0x2091, 0x8001, + 0x0005, 0x7840, 0x8001, 0x7842, 0x1904, 0x4498, 0x7844, 0x7842, + 0x2069, 0x4740, 0xc7fc, 0x2079, 0x0200, 0x68d4, 0xa005, 0x0138, + 0x7de0, 0xa504, 0x1120, 0x68d6, 0x68d0, 0xc0bc, 0x68d2, 0x2079, + 0x4700, 0x6810, 0xa005, 0x1110, 0x2001, 0x0101, 0x8001, 0x6812, + 0xd7fc, 0x0118, 0xa080, 0x8dd0, 0x0010, 0xa080, 0x8cc0, 0x2040, + 0x2004, 0xa065, 0x01e0, 0x6024, 0xa005, 0x01b0, 0x8001, 0x6026, + 0x1198, 0x6800, 0xa005, 0x0130, 0x6848, 0xac06, 0x1118, 0x080c, + 0x452c, 0x0068, 0x6860, 0xa005, 0x0118, 0x6027, 0x0001, 0x0020, + 0x080c, 0x44da, 0x2804, 0x0c28, 0x6000, 0x2c40, 0x0c10, 0xd7fc, + 0x1138, 0x2069, 0x4780, 0xc7fd, 0x2079, 0x0100, 0x0804, 0x4455, + 0x0005, 0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0558, + 0x6024, 0xa005, 0x0118, 0x8001, 0x6026, 0x0418, 0x6008, 0xc09c, + 0xd084, 0x1110, 0xd0ac, 0x01c0, 0x600a, 0x6004, 0xa005, 0x01d8, + 0x00d6, 0x00c6, 0x0016, 0x2068, 0x6010, 0x8001, 0x6012, 0x080c, + 0x37b5, 0x2d00, 0x2c68, 0x2060, 0x080c, 0x1bf2, 0x080c, 0x1da4, + 0x001e, 0x00ce, 0x00de, 0x0038, 0xc0bd, 0x600a, 0xa18d, 0x0001, + 0x0010, 0xa18d, 0x0100, 0xace0, 0x0010, 0x1f04, 0x449d, 0xa184, + 0x0001, 0x0130, 0xa18c, 0xfffe, 0x690e, 0x080c, 0x22bd, 0x0008, + 0x690e, 0x0005, 0x2c00, 0x687a, 0x6714, 0x6f72, 0x6017, 0x0000, + 0x602b, 0x0000, 0x601b, 0x0006, 0x60b4, 0xa084, 0x5f00, 0x601e, + 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, + 0x2069, 0x4780, 0xd7fc, 0x1110, 0x2069, 0x4740, 0x6858, 0xac06, + 0x1110, 0x2800, 0x685a, 0x080c, 0x1b8a, 0x6818, 0xa005, 0x0110, + 0x8001, 0x681a, 0x6808, 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, + 0x790a, 0x8001, 0x1310, 0x080c, 0x255d, 0x6812, 0x1118, 0x7910, + 0xc1a5, 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x080c, + 0x1db1, 0xd7fc, 0x1118, 0x2069, 0x4740, 0x0010, 0x2069, 0x4780, + 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x1118, 0x6976, 0x2001, + 0x0004, 0x080c, 0x22b3, 0x0005, 0x00d6, 0x6948, 0x2160, 0xd7fc, + 0x1118, 0x2069, 0x0200, 0x0010, 0x2069, 0x0100, 0x080c, 0x2478, + 0x601b, 0x0006, 0x6858, 0xa084, 0x5f00, 0x601e, 0x6020, 0xa084, + 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, + 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x01b0, 0x684b, + 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x4553, + 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04, + 0x455c, 0x20a9, 0x00fa, 0x1f04, 0x4563, 0x681b, 0x0054, 0x00de, + 0x6863, 0x0007, 0x0005, 0x2079, 0x4700, 0x00e1, 0x0089, 0x00a9, + 0x2009, 0x0002, 0x2069, 0x4780, 0x680f, 0x0000, 0x6813, 0x0000, + 0x6817, 0x0000, 0x8109, 0x0118, 0x2069, 0x4740, 0x0ca8, 0x0005, + 0x2019, 0x00a3, 0x7b3a, 0x7b3e, 0x0005, 0x2019, 0x0033, 0x7b42, + 0x7b46, 0x0005, 0x2019, 0x32dd, 0x7b32, 0x7b36, 0x0005, 0x6a4c, + 0xa285, 0x0000, 0x01f0, 0x6950, 0x6bbc, 0xa300, 0x00c6, 0x2164, + 0x6304, 0x83ff, 0x1138, 0x8211, 0x0148, 0x8108, 0xa11a, 0x0eb8, + 0x69bc, 0x0ca8, 0x68cf, 0x000a, 0x00ce, 0x0005, 0x694c, 0x6abc, + 0x2264, 0x6008, 0xc0b5, 0x600a, 0x8210, 0x8109, 0x1dc8, 0x694e, + 0x00ce, 0x0005, 0x1d04, 0x45b2, 0x2091, 0x6000, 0x1d04, 0x45b6, + 0x2091, 0x6000, 0x70ec, 0xd0dc, 0x1118, 0xd0d4, 0x0190, 0x00a0, + 0xae8e, 0x0100, 0x0138, 0x7814, 0xc0f5, 0xc0c5, 0x7816, 0xd0d4, + 0x1580, 0x0460, 0x7814, 0xc0fd, 0xc0c5, 0x7816, 0xd0d4, 0x1548, + 0x0428, 0xd0e4, 0x0904, 0x4619, 0x1d04, 0x45d4, 0x2091, 0x6000, + 0x2009, 0x000c, 0x1d04, 0x45da, 0x2091, 0x6000, 0x8109, 0x1dd0, + 0x70e4, 0xa084, 0x01ff, 0xa086, 0x01ff, 0x1110, 0x70ec, 0x08c0, + 0xae8e, 0x0100, 0x0128, 0x7814, 0xc0f4, 0xd0fc, 0x1130, 0x0020, + 0x7814, 0xc0fc, 0xd0f4, 0x1108, 0xc0c4, 0x7816, 0x7804, 0xd08c, + 0x0500, 0x00c6, 0x2061, 0x0000, 0x6018, 0xd084, 0x11b8, 0xae86, + 0x0200, 0x00e6, 0x2071, 0x0010, 0x0120, 0x70db, 0x0001, 0x78e4, + 0x0018, 0x70db, 0x0000, 0x78e0, 0x70c6, 0x70c3, 0x800e, 0x601b, + 0x0001, 0x2091, 0x4080, 0x00ee, 0x00ce, 0x0018, 0x00ce, 0x681f, + 0x000c, 0x70a0, 0x70a2, 0x0005, 0xa3f4 +}; + +unsigned short risc_12160_code_length01 = 0x361d; + +#else + +unsigned short risc_12160_code_version = 0x0000; +unsigned short risc_12160_code_addr01 = 0x0000 ; +unsigned short risc_12160_code01[] = { 0x0000 }; +unsigned short risc_12160_code_length01 = 0x0000; + +#endif diff -Nur linux-2.4.19/drivers/xscsi/qlidbg.c linux-2.4.19-sgi211r3/drivers/xscsi/qlidbg.c --- linux-2.4.19/drivers/xscsi/qlidbg.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/qlidbg.c Mon Feb 3 11:51:35 2003 @@ -0,0 +1,691 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifdef linux +#include +#include +#include +#include +#include +#include + +#define qprintf kdb_printf +#define XSCSI + +#include "osdep_linux.h" +#include "xscsi.h" +#include "alenlist.h" +#include "ql.h" + +#define IDBG_END return 0; + +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void idbg_qlinfo(pHA_INFO); +void idbg_qlregs(pHA_INFO); +#ifdef PIO_TRACE +void idbg_qlpio(pHA_INFO, __psint_t); +#endif +void idbg_qlluninfo(vertex_hdl_t); +void idbg_qlhelp(void); +#ifdef DUMP_12160 +void idbg_qldump12160(pHA_INFO); +#endif + +#define IDBG_END +#define VD (void (*)()) +#endif /* linux */ + +extern pHA_INFO ql_ha_list; +extern pHA_INFO ql_ha_info_from_ctlr_get(vertex_hdl_t); +#ifdef DUMP_12160 +extern void dump_12160(pCHIP_INFO chip_info); +#endif + +struct idbg_if { +#ifndef XSCSI + char *name; + void (*func)(); + char *descrip; +#else + char *name; + char *descrip; +#endif +}; + +struct idbg_if qlidbg_funcs[] = { +#ifndef XSCSI + "qlinfo", VD idbg_qlinfo, "\t\tDump QL host adapter status. Usage: qlinfo []", + "qlregs", VD idbg_qlregs, "\t\tDump QL host adapter registers. Usage: qlregs []", +#ifdef PIO_TRACE + "qlpio", VD idbg_qlpio, "\t\tDump QL host adapter PIO trace. Usage: qlpio [ []]", +#endif + "qlluninfo", VD idbg_qlluninfo, "\t\tDump QL LUN information. Usage: qlluninfo ", + "qlhelp", VD idbg_qlhelp, "\t\tPrint help about QL idbg functions", +#ifdef DUMP_12160 + "qldump12160", VD idbg_qldump12160, "\t\tDebugging card dump of 12160 adapter card. Usage: qldump12160 ", +#endif + 0, 0, 0 +#else + { "qlinfo", "\t\tDump QL host adapter status. Usage: qlinfo []" }, + { "qlregs", "\t\tDump QL host adapter registers. Usage: qlregs []" }, +#ifdef PIO_TRACE + { "qlpio", "\t\tDump QL host adapter PIO trace. Usage: qlpio [ []]" }, +#endif + { "qlluninfo", "\t\tDump QL LUN information. Usage: qlluninfo " }, + { "qlhelp", "\t\tPrint help about QL idbg functions" }, +#ifdef DUMP_12160 + { "qldump12160", "\t\tDebugging card dump of 12160 adapter card. Usage: qldump12160 " }, +#endif + { 0, 0 } +#endif /* XSCSI */ +}; + +int qlpio_count = 10; + + +#ifndef XSCSI +void +qlidbg_init(void) +{ + struct idbg_if *p; + + for (p = qlidbg_funcs; p->name; p++) + idbg_addfunc(p->name, p->func); +} +#endif + +/* + ++ kp qlhelp - print descriptions of QL kp funcions. +*/ +#ifdef XSCSI +static int +idbg_qlhelp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_qlhelp(void) +#endif +{ + struct idbg_if *p; + + for (p = qlidbg_funcs; p->name; p++) { + qprintf("%s:%s\n", p->name, p->descrip); + } + IDBG_END +} + +/* + ++ kp qlinfo - print data structures for QL controller. If no + ++ argument is supplied, print a short list of all controllers. +*/ +#ifdef XSCSI +static int +idbg_qlinfo(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_qlinfo(pHA_INFO ha) +#endif +{ + int i, j; + +#ifdef XSCSI + pHA_INFO ha; + unsigned long number = -1LL; + int diag; + + if (argc >1) + return (KDB_ARGCOUNT); + + if (argc == 1) + { + diag = kdbgetularg(argv[1], &number); + if (diag) + return (diag); + } + + ha=(pHA_INFO)number; +#endif + + if (ha == (pHA_INFO)(-1LL)) { + for (ha = ql_ha_list; ha; ha = ha->next_ha) { + qprintf("0x%p: %s\n", (void *)ha, ha->ha_name); + } + } + else { +#ifdef XSCSI + qprintf("ctlr_vhdl: %p, pci_vhdl: %p, bridge revnum: %d, host_flags: 0x%x chip_flags: 0x%x\n", + (void *)ha->ctlr_vhdl, (void *)ha->chip_info->pci_vhdl, ha->chip_info->bridge_revnum, ha->host_flags, + ha->chip_info->chip_flags); +#else + qprintf("ctlr_vhdl: %d, pci_vhdl: %d, bridge revnum: %d, host_flags: 0x%x chip_flags: 0x%x\n", + ha->ctlr_vhdl, ha->chip_info->pci_vhdl, ha->chip_info->bridge_revnum, ha->host_flags, + ha->chip_info->chip_flags); +#endif + + qprintf("chip_info: 0x%p, device_id: 0x%x, channel_count: %d \n", + (void *)ha->chip_info, ha->chip_info->device_id, ha->chip_info->channel_count); +#ifdef PIO_TRACE + qprintf("ha_base: 0x%p, ql_log_vals: 0x%p\n", + (void *)ha->chip_info->ha_base, (void *)ha->chip_info->ql_log_vals); +#else + qprintf("ha_base: 0x%p\n", (void *)ha->chip_info->ha_base); +#endif + qprintf("request_in: %d, request_out: %d, response_out: %d, queue_space: %d\n", + ha->chip_info->request_in, ha->chip_info->request_out, ha->chip_info->response_out, + ha->chip_info->queue_space); + qprintf("request_ptr: 0x%p, request_base: 0x%p\n", + (void *)ha->chip_info->request_ptr, (void *)ha->chip_info->request_base); + qprintf("response_ptr: 0x%p, response_base: 0x%p\n", + (void *)ha->chip_info->response_ptr, (void *)ha->chip_info->response_base); + qprintf("req_forw: 0x%p, req_back: 0x%p\n", + (void *)ha->req_forw, (void *)ha->req_back); + qprintf("waitf: 0x%p, waitb: 0x%p\n", + (void *)ha->waitf, (void *)ha->waitb); + qprintf("reqi_block: 0x%p\n", (void *)ha->reqi_block); + qprintf("probemutex: 0x%p\n", (void *)&ha->chip_info->probemutex); + qprintf("mboxmutex: 0x%p, ctlrlock: 0x%p\n", (void *)&ha->chip_info->mboxmutex, (void *)&ha->chip_info->ctlrlock); + qprintf("mbox_done_sema 0x%p\n", (void *)&ha->chip_info->mbox_done_sema); + qprintf("Outstanding SCSI commands: ql_ncmd: %d\n", ha->ql_ncmd); + for (i = 0; i < QL_MAXTARG; ++i) { + qprintf("targ: %d: tcmd: %d\n", i, ha->tcmd[i]); + if (ha->reqi_block[i]!=NULL) + { + for (j = 0; j < MAX_REQ_INFO + 1; ++j) { + if (ha->reqi_block[i][j].req) { + qprintf("\t(%d)req: 0x%p, timeout: %d\n", + j, + (void *)ha->reqi_block[i][j].req, + ha->reqi_block[i][j].timeout); + } + } + } + } + } + IDBG_END +} + +/* + ++ kp qlregs - print internal registers for QL controller. If no + ++ argument is supplied, print a short list of all controllers. +*/ +#ifdef XSCSI +static int +idbg_qlregs(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_qlregs(pHA_INFO ha) +#endif +{ + +#ifdef XSCSI + pHA_INFO ha; + unsigned long number = -1LL; + int diag; + + if (argc >1) + return (KDB_ARGCOUNT); + + if (argc == 1) + { + diag = kdbgetularg(argv[1], &number); + if (diag) + return (diag); + } + ha=(pHA_INFO)number; +#endif + + if (ha == (pHA_INFO)(-1LL)) { + for (ha = ql_ha_list; ha; ha = ha->next_ha) { + qprintf("0x%p: %s\n", (void *)ha, ha->ha_name); + } + } + else { + pISP_REGS isp = (pISP_REGS)ha->chip_info->ha_base; + u_short bus_id_low, bus_id_high, bus_config0, bus_config1; + u_short bus_icr = 0; + u_short bus_isr = 0; + u_short bus_sema; + u_short hccr = 0; + u_short risc_pc; + u_short mbox0, mbox1, mbox2, mbox3, mbox4, mbox5, mbox6, mbox7; + + u_short accumulator; + u_short r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; + u_short ivr; + u_short psr; + u_short rar0, rar1; + u_short pcr; + u_short lcr; + u_short mtr=0; + u_short sp; + u_short mctr=0; + u_short lvdi=0; + u_short hardware_revision; + + u_short control_dma_control=0; + u_short control_dma_config=0; + u_short control_dma_fifo_status=0; + u_short control_dma_status=0; + u_short control_dma_counter=0; + u_short control_dma_address_counter_1=0; + u_short control_dma_address_counter_0=0; + u_short control_dma_address_counter_3=0; + u_short control_dma_address_counter_2=0; + + u_short data_dma_control=0; + u_short data_dma_config=0; + u_short data_dma_fifo_status=0; + u_short data_dma_status=0; + u_short data_dma_xfer_counter_high=0; + u_short data_dma_xfer_counter_low=0; + u_short data_dma_address_counter_1=0; + u_short data_dma_address_counter_0=0; + u_short data_dma_address_counter_3=0; + u_short data_dma_address_counter_2=0; + + /* Get copies of the registers. */ + mbox0 = PCI_INH(&isp->mailbox0); + mbox1 = PCI_INH(&isp->mailbox1); + mbox2 = PCI_INH(&isp->mailbox2); + mbox3 = PCI_INH(&isp->mailbox3); + mbox4 = PCI_INH(&isp->mailbox4); + mbox5 = PCI_INH(&isp->mailbox5); + mbox6 = PCI_INH(&isp->mailbox6); + mbox7 = PCI_INH(&isp->mailbox7); + + bus_id_low = PCI_INH(&isp->bus_id_low); + bus_id_high = PCI_INH(&isp->bus_id_high); + bus_config0 = PCI_INH(&isp->bus_config0); + bus_config1 = PCI_INH(&isp->bus_config1); + bus_icr = PCI_INH(&isp->bus_icr); + bus_isr = PCI_INH(&isp->bus_isr); + bus_sema = PCI_INH(&isp->bus_sema); + hccr = PCI_INH(&isp->hccr); + + PCI_OUTH(&isp->hccr, HCCR_CMD_PAUSE); + if (ha->chip_info->device_id==QLogic_1040_DEVICE_ID) { + control_dma_control = PCI_INH(&isp->control_dma_control); + control_dma_config = PCI_INH(&isp->control_dma_config); + control_dma_fifo_status = PCI_INH(&isp->control_dma_fifo_status); + control_dma_status = PCI_INH(&isp->control_dma_status); + control_dma_counter = PCI_INH(&isp->control_dma_counter); + + control_dma_address_counter_1 = PCI_INH(&isp->control_dma_address_counter_1); + control_dma_address_counter_0 = PCI_INH(&isp->control_dma_address_counter_0); + control_dma_address_counter_3 = PCI_INH(&isp->control_dma_address_counter_3); + control_dma_address_counter_2 = PCI_INH(&isp->control_dma_address_counter_2); + + data_dma_config = PCI_INH(&isp->data_dma_config); + data_dma_fifo_status = PCI_INH(&isp->data_dma_fifo_status); + data_dma_status = PCI_INH(&isp->data_dma_status); + data_dma_control = PCI_INH(&isp->data_dma_control); + + data_dma_xfer_counter_high = PCI_INH(&isp->data_dma_xfer_counter_high); + data_dma_xfer_counter_low = PCI_INH(&isp->data_dma_xfer_counter_low); + data_dma_address_counter_1 = PCI_INH(&isp->data_dma_address_counter_1); + data_dma_address_counter_0 = PCI_INH(&isp->data_dma_address_counter_0); + data_dma_address_counter_3 = PCI_INH(&isp->data_dma_address_counter_3); + data_dma_address_counter_2 = PCI_INH(&isp->data_dma_address_counter_2); + mtr = PCI_INH(&isp->mtr); + } + else + { mctr = PCI_INH(&isp->mctr); + lvdi = PCI_INH(&isp->lvdi); + } + + + accumulator = PCI_INH(&isp->accumulator); + r1 = PCI_INH(&isp->r1); + r2 = PCI_INH(&isp->r2); + r3 = PCI_INH(&isp->r3); + r4 = PCI_INH(&isp->r4); + r5 = PCI_INH(&isp->r5); + r6 = PCI_INH(&isp->r6); + r7 = PCI_INH(&isp->r7); + r8 = PCI_INH(&isp->r8); + r9 = PCI_INH(&isp->r9); + r10 = PCI_INH(&isp->r10); + r11 = PCI_INH(&isp->r11); + r12 = PCI_INH(&isp->r12); + r13 = PCI_INH(&isp->r13); + r14 = PCI_INH(&isp->r14); + r15 = PCI_INH(&isp->r15); + ivr = PCI_INH(&isp->ivr); + psr = PCI_INH(&isp->psr); + rar0 = PCI_INH(&isp->rar0); + rar1 = PCI_INH(&isp->rar1); + pcr = PCI_INH(&isp->pcr); + lcr = PCI_INH(&isp->lcr); + risc_pc = PCI_INH(&isp->risc_pc); + sp = PCI_INH(&isp->sp); + hardware_revision = PCI_INH(&isp->hardware_revision); + + + PCI_OUTH(&isp->hccr, HCCR_CMD_RELEASE); + + + qprintf("mbox0 = 0x%x, mbox1 = 0x%x\n", mbox0, mbox1); + qprintf("mbox2 = 0x%x, mbox3 = 0x%x\n", mbox2, mbox3); + qprintf("mbox4 = 0x%x, mbox5 = 0x%x\n", mbox4, mbox5); + qprintf("mbox6 = 0x%x, mbox7 = 0x%x\n", mbox6, mbox7); + qprintf("BUS_ID_LOW=0x%x, BUS_ID_HIGH=0x%x\n", + bus_id_low, bus_id_high); + qprintf("BUS_CONFIG0=0x%x, BUS_CONFIG1=0x%x\n", + bus_config0, bus_config1); + qprintf("BUS_ICR=0x%x, BUS_ISR=0x%x, BUS_SEMA=0x%x\n", + bus_icr, bus_isr, bus_sema); + qprintf("HCCR=0x%p: 0x%x \n", (void *)&isp->hccr, hccr); + qprintf("risc PC : 0x%x\n", risc_pc); + + qprintf("\n"); + if (ha->chip_info->device_id==QLogic_1040_DEVICE_ID) { + qprintf("control_dma_control 0x%p: 0x%x\n", + (void *)&isp->control_dma_control, control_dma_control); + qprintf("control_dma_config 0x%p: 0x%x\n", + (void *)&isp->control_dma_config, control_dma_config); + qprintf("control_dma_fifo_status 0x%p: 0x%x\n", + (void *)&isp->control_dma_fifo_status, control_dma_fifo_status); + qprintf("control_dma_status 0x%p: 0x%x\n", + (void *)&isp->control_dma_status, control_dma_status); + qprintf("control_dma_counter 0x%p: 0x%x\n", + (void *)&isp->control_dma_counter, control_dma_counter); + qprintf("dump_regs: control_dma_address_counter_1 0x%p: 0x%x\n", + (void *)&isp->control_dma_address_counter_1, control_dma_address_counter_1); + qprintf("dump_regs: control_dma_address_counter_0 0x%p: 0x%x\n", + (void *)&isp->control_dma_address_counter_0, control_dma_address_counter_0); + qprintf("dump_regs: control_dma_address_counter_3 0x%p: 0x%x\n", + (void *)&isp->control_dma_address_counter_3, control_dma_address_counter_3); + qprintf("dump_regs: control_dma_address_counter_0 0x%p: 0x%x\n", + (void *)&isp->control_dma_address_counter_2, control_dma_address_counter_2); + qprintf("data_dma_config 0x%p: 0x%x\n", + (void *)&isp->data_dma_config, data_dma_config); + + qprintf("data_dma_status 0x%p: 0x%x\n", + (void *)&isp->data_dma_status, data_dma_status); + qprintf("data_dma_fifo_status 0x%p: 0x%x\n", + (void *)&isp->data_dma_fifo_status, data_dma_fifo_status); + qprintf("data_dma_control 0x%p: 0x%x\n", + (void *)&isp->data_dma_control, data_dma_control); + qprintf("data_dma_xfer_counter_high 0x%p: 0x%x\n", + (void *)&isp->data_dma_xfer_counter_high, data_dma_xfer_counter_high); + qprintf("data_dma_xfer_counter_low 0x%p: 0x%x\n", + (void *)&isp->data_dma_xfer_counter_low, data_dma_xfer_counter_low); + qprintf("dump_regs: data_dma_address_counter_1 0x%p: 0x%x\n", + (void *)&isp->data_dma_address_counter_1, + data_dma_address_counter_1); + qprintf("dump_regs: data_dma_address_counter_0 0x%p: 0x%x\n", + (void *)&isp->data_dma_address_counter_0, + data_dma_address_counter_0); + qprintf("dump_regs: data_dma_address_counter_3 0x%p: 0x%x\n", + (void *)&isp->data_dma_address_counter_3, + data_dma_address_counter_3); + qprintf("dump_regs: data_dma_address_counter_2 0x%p: 0x%x\n", + (void *)&isp->data_dma_address_counter_2, + data_dma_address_counter_2); + qprintf("\n"); + qprintf("dump_regs: mtr 0x%x\n", mtr); + qprintf("dump_regs: emb 0x%x\n", mctr); /* note mctr is emb on 1040 */ + } + else + { qprintf("dump_regs: mctr 0x%x\n", mctr); + qprintf("dump_regs: lvdi 0x%x\n", lvdi ); + } + + qprintf("dump_regs: accumulator 0x%x\n", accumulator ); + qprintf("dump_regs: r1 0x%x\n", r1 ); + qprintf("dump_regs: r2 0x%x\n", r2); + qprintf("dump_regs: r3 0x%x\n", r3 ); + qprintf("dump_regs: r4 0x%x\n", r4); + qprintf("dump_regs: r5 0x%x\n", r5 ); + qprintf("dump_regs: r6 0x%x\n", r6 ); + qprintf("dump_regs: r7 0x%x\n", r7); + qprintf("dump_regs: r8 0x%x\n", r8 ); + qprintf("dump_regs: r9 0x%x\n", r9 ); + qprintf("dump_regs: r10 0x%x\n", r10 ); + qprintf("dump_regs: r11 0x%x\n", r11 ); + qprintf("dump_regs: r12 0x%x\n", r12); + qprintf("dump_regs: r13 0x%x\n", r13 ); + qprintf("dump_regs: r14 0x%x\n", r14 ); + qprintf("dump_regs: r15 0x%x\n", r15 ); + qprintf("dump_regs: ivr 0x%x\n", ivr ); + qprintf("dump_regs: psr 0x%x\n", psr ); + qprintf("dump_regs: rar0 0x%x\n", rar0 ); + qprintf("dump_regs: rar1 0x%x\n", rar1 ); + qprintf("dump_regs: pcr 0x%x\n", pcr ); + qprintf("dump_regs: lcr 0x%x\n", lcr); + qprintf("dump_regs: sp 0x%x\n", sp ); + qprintf("dump_regs: hardware_revision 0x%x\n", hardware_revision ); + } + IDBG_END +} + +#ifdef PIO_TRACE +/* + ++ kp qlpio - dump PIO trace, if it exists + ++ argument is supplied, print a short list of all controllers. +*/ +#ifdef XSCSI +static int +idbg_qlpio(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_qlpio(pHA_INFO ha, __psint_t count) +#endif +{ + int rc; + +#ifdef XSCSI + pHA_INFO ha; + unsigned long number = -1LL; + int diag; + int count; + + if (argc >2) + return (KDB_ARGCOUNT); + + if (argc > 0) + { + diag = kdbgetularg(argv[1], &ha); + if (diag) + return (diag); + + if (argc == 2) + kdbgetularg(argv[2], &count); + } + ha=(pHA_INFO)number; +#endif + + if (ha == (pHA_INFO)(-1LL)) { + for (ha = ql_ha_list; ha; ha = ha->next_ha) { + qprintf("0x%p: %s\n", (void *)ha, ha->ha_name); + } + } + else { + uint last_index = ha->ql_log_vals[0]; + uint i, j = 0; + ushort dir, reg, val; + char regname[10]; + + qprintf("ha = 0x%p, count = 0x%p\n", (void *)ha, count); +#if 1 + count = qlpio_count; +#endif + if ((count > QL_LOG_CNT) || (count == 0)) + count = QL_LOG_CNT; + i = (last_index - 1 - count + QL_LOG_CNT - 1) % (QL_LOG_CNT - 1) + 1; + for (j = 0; j < count; ++j) { + dir = (ha->ql_log_vals[i] & 0x80000000) >> 31; + reg = (ha->ql_log_vals[i] & 0x7FFF0000) >> 16; + val = ha->ql_log_vals[i] & 0x0000FFFF; + switch(reg) { + case 0x0070: sprintf(regname, "MAILBOX1"); break; + case 0x0072: sprintf(regname, "MAILBOX0"); break; + case 0x0074: sprintf(regname, "MAILBOX3"); break; + case 0x0076: sprintf(regname, "MAILBOX2"); break; + case 0x0078: sprintf(regname, "MAILBOX5"); break; + case 0x007A: sprintf(regname, "MAILBOX4"); break; + case 0x007C: sprintf(regname, "MAILBOX7"); break; + case 0x007E: sprintf(regname, "MAILBOX6"); break; + + case 0x0008: sprintf(regname, "ISR"); break; + case 0x000A: sprintf(regname, "ICR"); break; + case 0x000E: sprintf(regname, "BUSSEMA"); break; + case 0x00C2: sprintf(regname, "HCCR"); break; + default: sprintf(regname, "0x%x", reg); + } + qprintf("[%4d] %s 0x%4x (%9s): 0x%4x\n", j - count, (dir ? "W":"R"), reg, regname, val); + if (i++ == QL_LOG_CNT) + i = 1; + } + } + IDBG_END +} +#endif + +/* + ++ kp qlluninfo - print QL lun information. Argument is LUN VHDL. +*/ +#ifdef XSCSI +static int +idbg_qlluninfo(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_qlluninfo(vertex_hdl_t lun_vhdl) +#endif +{ + ql_local_info_t *qli; + pHA_INFO ha; + scsi_request_t *req; + +#ifndef XSCSI + char path_name[MAXDEVNAME]; + int rc; + +#else + vertex_hdl_t lun_vhdl; + unsigned long number; + int diag; + + if (argc != 1) + return (KDB_ARGCOUNT); + + diag = kdbgetularg(argv[1], &number); + if (diag) + return (diag); + lun_vhdl=(vertex_hdl_t)number; +#endif /* xscsi */ + + qli = SLI_INFO(scsi_lun_info_get(lun_vhdl)); + ha = ql_ha_info_from_ctlr_get(SLI_CTLR_VHDL(scsi_lun_info_get(lun_vhdl))); +#ifndef XSCSI + rc = hwgraph_vertex_name_get(lun_vhdl, path_name, MAXDEVNAME); + qprintf("ha 0x%p, lun_vhdl: %d, lun_name %s\n", + (void *)ha, lun_vhdl, (rc == GRAPH_SUCCESS ? path_name : "Invalid vhdl")); +#else + qprintf("ha 0x%p, lun_vhdl: %p\n", + (void *)ha, (void *)lun_vhdl); +#endif + qprintf("openmutex: 0x%p\n", (void *)&qli->qli_openmutex); + qprintf("dev_flags: 0x%x\n", qli->qli_dev_flags); + qprintf("ref_count: %d, cmd_rcnt: %d\n", + qli->qli_ref_count, qli->qli_cmd_rcnt); + qprintf("Abort waiting requests: "); + for (req = qli->qli_awaitf; req; req = req->sr_ha) + qprintf("0x%p ", (void *)req); + qprintf("\n"); + qprintf("Init waiting requests: "); + for (req = qli->qli_iwaitf; req; req = req->sr_ha) + qprintf("0x%p ", (void *)req); + qprintf("\n"); + IDBG_END +} + +#ifdef DUMP_12160 +#ifdef XSCSI +static int +idbg_qldump(int argc, const char **argv, const char **envp, struct pt_regs *regs) +#else +void +idbg_qldump12160(pHA_INFO ha) +#endif +{ +#ifdef XSCSI + pHA_INFO ha = -1LL; + unsigned long number; + int diag; + + if (argc != 1) + return (KDB_ARGCOUNT); + + diag = kdbgetularg(argv[1], &number); + if (diag) + return (diag); + ha=(pHA_INFO)number; +#endif + + qprintf("\n"); + dump_12160(ha->chip_info); + IDBG_END +} +#endif + + +#ifdef XSCSI +static int +qlidbg_register(void) +{ + kdb_register("qlinfo", idbg_qlinfo, "[]", "Dump QL host adapter status", 0); + kdb_register("qlregs", idbg_qlregs, "[]", "Dump QL host adapter registers", 0); +#ifdef PIO_TRACE + kdb_register("qlpio", idbg_qlpio, "[ []]", "Dump QL host adapter PIO trace", 0); +#endif + kdb_register("qlluninfo", idbg_qlluninfo, "", "Dump QL LUN information", 0); + kdb_register("qlhelp", idbg_qlhelp, "", "Print help about QL idbg functions", 0); +#ifdef DUMP_12160 + kdb_register("qldump12160", idbg_qldump12160, "", "Debugging card dump of 12160 adapter card", 0); +#endif + return(0); +} + +module_init(qlidbg_register); +#endif diff -Nur linux-2.4.19/drivers/xscsi/xfailover.c linux-2.4.19-sgi211r3/drivers/xscsi/xfailover.c --- linux-2.4.19/drivers/xscsi/xfailover.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/xfailover.c Fri Jan 3 08:28:29 2003 @@ -0,0 +1,3308 @@ +/* + * + * + * Copyright (c) 1986-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* + * FAILOVER module. + * + * Main functions: + * * Keep track of multipathed devices and paths to each. + * * Perform switch from a failed 'primary' path to one of + * 'secondary' paths, and any device specific failover functions. + * + * Main entry points: + * * fo_scsi_device_update() - called during device discovery to + * update the failover data structures with the device being + * discovered. + * * fo_scsi_device_update_generic() - called by the user land + * program foupdate within in the foupdate init.d script just prior + * to calling xlv_assemble. Initializes the kernel failover + * structures for generic devices. + * * fo_scsi_lun_remove() - called to cleanup failover structures + * following the removal of a LUN. + * * fo_scsi_device_switch() - called to perform switch from + * primary path to secondary path. The secondary path is + * returned. The paths must be vertex handles to scsi, char or + * block devices. + * * fo_scsi_device_pathcount() - called to determine the number of + * paths in a failover group. The path must be a vertex handle to + * scsi, char or block device. + * * fo_is_failover_candidate() - returns non-zero if the device is + * a candidate for * failover, else zero. + * + * Internal structures: + * * SCSI failover candidates list - this is a list of device types + * and pointers to device specific functions for performing generic + * tasks. Fields in each structure are: + * scsi_match_str1, + * scsi_match_str2, + * scsi_match_off1, + * scsi_match_off2 - used for determining whether a device is a + * candidate for failover. + * scsi_validlun_func - device specific function used for + * determining whether a LUN is actually valid. + * scsi_getname_func - device specific function returning a + * unique name across the name space of that device + * type. + * scsi_cmpname_func - device specific unique name comparison function. + * scsi_freename_func - device specific function for freeing + * names returned by scsi_getname_func. + * scsi_sprintf_func - device specific function returning string + * representation of unique name. + * scsi_switch_func - device specific function to perform failover. + * scsi_vh_coherency_policy - policy on maintaining coherency of + * partition vertices between the various paths + * of a failover group. + * scsi_foi; - pointer to instance list for this device type. + * * SCSI failover instances - this is a list of devices found for + * the particular type previously determined to be candidates for + * failover. Fields in each structure are: + * foi_foc - back pointer to candidate structure. + * foi_grp_name - unique name of this failover group. + * foi_primary - current primary path (index) + * foi_path_vhdl - vertex handle of the LUN vertex of a path + * foi_path_status - status of the path (VALID, FAILED, etc.) + * foi_next - pointer to next device of this type. */ + +#ident "io/failover.c: $Revision: 1.37 $" + +#ifndef linux + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#else + #include + #include + #include + #include + #include + #include + #include + + #include "xscsi.h" + #include "alenlist.h" + #include "dksc.h" + #include "osdep_linux.h" +#endif + +#include "xfailover.h" + +int fo_devflag = D_MP; +int fo_max_paths=32; + +extern devfs_handle_t devfs_xscsi; +static devfs_handle_t failover_vhdl; + + +#ifdef DEBUG +#define FO_DEBUG_LEVEL 1 +int fo_debug = FO_DEBUG_LEVEL; +#endif + +/* + * List of free SCSI requests + */ +#define FO_SR_LIST_SIZE 4 +#define FO_SR_CDB_SIZE 16 +#define FO_SR_SENSE_SIZE 16 + +#define FO_SR_BUF_SIZE 256 /* must be LARGER than below page lengths */ + +#define DG_PG25_LEN 20 /* header plus 16 bytes of data */ +#define DG_PG22_LEN 8 /* header plus 4 bytes of data */ +#define LSI_PG2C_LEN 110 +#define LSI_PG8_LEN 16 +#define LSI_PG2E_LEN 68 + +struct fo_request { + struct scsi_request *fr_srreq; + sema_t *fr_sema; + u_char *fr_command; + u_char *fr_sense; + u_char *fr_buffer; + struct fo_request *fr_next; +}; +static struct fo_request *fr_free_list; +static sema_t *fr_sema; +static sema_t *fr_count_sema; + +/* + * Defined in master.d/failover + */ +extern uint fo_auto_failover_on_start; +extern uint fo_auto_failover_on_dev_deletion; + + +#define inventory_t int + +/* + * Forward declarations for other local functions + */ +static struct fo_request *fo_get_fr(void); +static void fo_free_fr(struct fo_request *fr); +static void fo_scsi_done(scsi_request_t *req); +static void fo_mirror_lun(vertex_hdl_t, vertex_hdl_t); +static int fo_path_add (struct scsi_fo_instance *foi, vertex_hdl_t lun_vhdl, int is_viable_primary); +static void fo_remove_instance (struct scsi_candidate *foc, struct scsi_fo_instance *foi); +static int fo_generic_switch_func(vertex_hdl_t, vertex_hdl_t); +static int clariion_k5_primary_func(struct scsi_candidate *, struct user_fo_generic_info *); +static int fo_inquiry_test(vertex_hdl_t); + +/* + * Forward declarations of DG specific functions + */ +struct dg_name { + uint32_t dg_sig1; + uint32_t dg_sig2; + uint16_t dg_lun; +}; +typedef struct dg_name *dg_name_t; +static int dg_sauna_validlun_func(u_char *inq, vertex_hdl_t lun_vhdl); +static int dg_sauna_getname_func(vertex_hdl_t, scsi_name_t *, u_char *); +static int dg_sauna_cmpname_func(scsi_name_t, scsi_name_t); +static int dg_sauna_freename_func(scsi_name_t ret_name); +static char *dg_sauna_sprintf_func(scsi_name_t name); +static int dg_sauna_switch_func(vertex_hdl_t, vertex_hdl_t); + +/* + * Forward declarations for Mylex specific functions + */ +typedef struct mylex_name *mylex_name_t; +static int mylex_validlun_func(u_char *inq, vertex_hdl_t lun_vhdl); +static int mylex_getname_func(vertex_hdl_t, scsi_name_t *, u_char *); +static int mylex_cmpname_func(scsi_name_t, scsi_name_t); +static char *mylex_sprintf_func(scsi_name_t name); +static int mylex_switch_func(vertex_hdl_t, vertex_hdl_t); + +/* + * Forward declarations for generic device id page (0x83) + */ +struct device_id_page { + u_char +#if defined(__LITTLE_ENDIAN) + peripheral_device_type:5, + peripheral_qualifier:3; +#else + peripheral_qualifier:3, + peripheral_device_type:5; +#endif + u_char page_code; + u_char reserved1; + u_char page_length; + struct { + uint8_t +#if defined(__LITTLE_ENDIAN) + code_set:4, + reserved1:4; +#else + reserved1:4, + code_set:4; +#endif + uint8_t +#if defined(__LITTLE_ENDIAN) + identifier_type:4, + reserved2:4; +#else + reserved2:4, + identifier_type:4; +#endif + uint8_t reserved3; + uint8_t identifier_length; + uint8_t identifier[0]; + }idlist[0]; +}; + + +/* + * Forward declarations for LSI specific functions + */ +struct lsi_redundant_controller_page_2c { + u_char header[4]; + u_char page_code; + u_char page_length; + char serial_number[16]; + char alt_serial_number[16]; + u_char rdac_mode[2]; + u_char alt_rdac_mode[2]; + u_char quiescence_timeout; + u_char rdac_options; + u_char lun_table[32]; + u_char lun_table_expansion[32]; /* merge with above when used */ + u_char reserved[2]; +}; + +struct lsi_caching_page_8 { + u_char header[4]; + u_char page_code; /* 0x8 */ + u_char page_length; /* 0xa */ + u_char +#if defined(__LITTLE_ENDIAN) + rcd:1, + mf:1, + wce:1, /* write caching enabled */ + reserved:5; +#else + reserved:5, + wce:1, /* write caching enabled */ + mf:1, + rcd:1; +#endif + u_char +#if defined(__LITTLE_ENDIAN) + wrp:4, /* write retention priority */ + drrp:4; /* demand read retention priority */ +#else + drrp:4, /* demand read retention priority */ + wrp:4; /* write retention priority */ +#endif + u_char dpftl[2]; /* disable pre-fetch transfer length */ + u_char minpf[2]; /* minimum pre-fetch */ + u_char maxpf[2]; /* maximum pre-fetch */ + u_char maxpf_ceil[2]; /* maximum pre-fetch ceiling */ +}; + +struct lsi_cache_page_2e { + u_char header[4]; + u_char page_code; /* 0x2e */ + u_char page_length; /* 0x3e */ + u_char +#if defined(__LITTLE_ENDIAN) + cme:1, + fwt:1, + cwob:1, + ecde:1, + reserved:4; +#else + reserved:4, + ecde:1, + cwob:1, + fwt:1, + cme:1; +#endif + u_char +#if defined(__LITTLE_ENDIAN) + wca:1, + rca:1, + bok:1, + abok:1, + cma:1, + acma:1, + bpr:1, + abpr:1; +#else + abpr:1, + bpr:1, + acma:1, + cma:1, + abok:1, + bok:1, + rca:1, + wca:1; +#endif + u_char reserved1[2]; + u_char read_caching_algorithm; + u_char reserved2; + u_char write_caching_algorithm; + u_char reserved3; + u_char cache_flush_algorithm; + u_char +#if defined(__LITTLE_ENDIAN) + cache_flush_modifier:4, + reserved4:4; +#else + reserved4:4, + cache_flush_modifier:4; +#endif + u_char two_minute_warning_flush_algorithm; + u_char +#if defined(__LITTLE_ENDIAN) + two_minute_warning_flush_modifier:4, + reserved5:4; +#else + reserved5:4, + two_minute_warning_flush_modifier:4; +#endif + u_char +#if defined(__LITTLE_ENDIAN) + cache_battery_age:7, + age_set:1; +#else + age_set:1, + cache_battery_age:7; +#endif + u_char reserved6; + u_char demand_flush_threshold; + u_char demand_flush_amount; + u_char reserved7[4]; + u_char cache_size[2]; + u_char cache_block_size[2]; + u_char large_io_size[2]; + u_char cache_mirror_allocation_size; + u_char reserved8[3]; +}; + + +struct lsi_name { + uint16_t lsi_lun; + uint8_t lsi_name_length; + char lsi_volume_uuid[0]; +}; + +static int lsi_validlun_func(u_char *inq, vertex_hdl_t lun_vhdl); +static int lsi_getname_func(vertex_hdl_t, scsi_name_t *, u_char *); +static int lsi_cmpname_func(scsi_name_t, scsi_name_t); +static char *lsi_sprintf_func(scsi_name_t name); +static int lsi_switch_func(vertex_hdl_t, vertex_hdl_t); +static int lsi_reportwarnings_func(vertex_hdl_t); + + +/* + * CANDIDATES STRUCTURES: Define which type of devices will be candidates for failover + */ +#if 0 /* for reference */ +struct scsi_candidate { + char *scsi_match_str1; /* First string used for matching */ + char *scsi_match_str2; /* Second string used for matching */ + u_char scsi_match_off1; /* Offset of 1st string in inventory */ + u_char scsi_match_off2; /* Offset of 2nd string in inventory */ + int (*scsi_validlun_func)(u_char *, vertex_hdl_t); + int (*scsi_getname_func)(vertex_hdl_t, scsi_name_t *, u_char *); + int (*scsi_cmpname_func)(scsi_name_t, scsi_name_t); + int (*scsi_freename_func)(scsi_name_t); + char *(*scsi_sprintf_func)(scsi_name_t); + int (*scsi_switch_func)(vertex_hdl_t, vertex_hdl_t); + int (*scsi_primary_func)(struct scsi_candidate *, + struct user_fo_generic_info *); + int (*scsi_reportwarnings_func)(vertex_hdl_t); + int scsi_vh_coherency_policy; + sema_t *scsi_foi_sema4; + struct scsi_fo_instance *scsi_foi; +}; +#endif + +#define GENERIC_MATCH_1 "GENERIC" +#define GENERIC_MATCH_2 "DISK" + +struct scsi_candidate fo_candidates[] = { + { + "SGI", "SAUNA", + 8, 36, + dg_sauna_validlun_func, + dg_sauna_getname_func, dg_sauna_cmpname_func, dg_sauna_freename_func, dg_sauna_sprintf_func, + dg_sauna_switch_func, + NULL, + NULL, + FO_VH_COH_POLICY_LAZY, + NULL, + NULL, + }, + { + "SGI", "K5", + 8, 36, + dg_sauna_validlun_func, + dg_sauna_getname_func, dg_sauna_cmpname_func, dg_sauna_freename_func, dg_sauna_sprintf_func, + dg_sauna_switch_func, + clariion_k5_primary_func, + NULL, + FO_VH_COH_POLICY_LAZY, + NULL, + NULL, + }, + { /* 1st generation 9100 */ + "MYLEX", "DACARMRB", + 8, 16, + mylex_validlun_func, + mylex_getname_func, mylex_cmpname_func, + dg_sauna_freename_func, + mylex_sprintf_func, + mylex_switch_func, + clariion_k5_primary_func, + NULL, + FO_VH_COH_POLICY_LAZY, + NULL, + NULL, + }, + { /* 2nd generation 9100 */ + "SGI", "TP9100 FFX2", + 8, 16, + mylex_validlun_func, + mylex_getname_func, mylex_cmpname_func, + dg_sauna_freename_func, + mylex_sprintf_func, + mylex_switch_func, + clariion_k5_primary_func, + NULL, + FO_VH_COH_POLICY_LAZY, + NULL, + NULL, + }, + { + "SGI", "TP9400", + 8, 16, + lsi_validlun_func, + lsi_getname_func, lsi_cmpname_func, + dg_sauna_freename_func, + lsi_sprintf_func, + lsi_switch_func, + clariion_k5_primary_func, + lsi_reportwarnings_func, + FO_VH_COH_POLICY_LAZY, + NULL, + NULL, + }, + { + "SGI", "TP9500", + 8, 16, + lsi_validlun_func, + lsi_getname_func, lsi_cmpname_func, + dg_sauna_freename_func, + lsi_sprintf_func, + lsi_switch_func, + clariion_k5_primary_func, + lsi_reportwarnings_func, + FO_VH_COH_POLICY_LAZY, + NULL, + NULL, + }, + { + GENERIC_MATCH_1, GENERIC_MATCH_2, + 0, 0, + NULL, + lsi_getname_func, lsi_cmpname_func, + dg_sauna_freename_func, lsi_sprintf_func, + fo_generic_switch_func, + NULL, + NULL, + FO_VH_COH_POLICY_LAZY, + NULL, + NULL + }, + { /* terminating entry */ + NULL, NULL, + 0, 0, + NULL, + NULL, NULL, + dg_sauna_freename_func, NULL, + NULL, + NULL, + NULL, + 0, + NULL, + NULL + } +}; + +struct scsi_candidate *fo_candidate_generic=NULL; /* pointer to generic foc */ + +/* + * Local debug print function + */ +#ifdef DEBUG +static char * +sprint_hex(u_char ch) +{ + static char p[8]; + int i; + + i = ((ch >> 4) & 0x0F); + p[0] = (i > 9) ? (i - 10 + 'A') : (i + '0'); + i = (ch & 0x0F); + p[1] = (i > 9) ? (i - 10 + 'A') : (i + '0'); + p[2] = '\0'; + return(p); +} +#endif + +/*ARGSUSED*/ +static void +DBG(int level, char *format, ...) +{ +#ifdef DEBUG + va_list ap; + char out_string[256]; + + if (level <= fo_debug) { + va_start(ap, format); + vsprintf(out_string, format, ap); + printk(out_string); + va_end(ap); + } +#endif +} + +/* + * Local debug print function for SCSI results + */ +/*ARGSUSED*/ +static void +SCSI_DBG(int level, scsi_request_t *req, char *format, ...) +{ +#ifdef DEBUG + va_list ap; + char out_string[256]; + int i; + + if (level <= fo_debug) { + va_start(ap, format); + vsprintf(out_string, format, ap); + cmn_err(CE_DEBUG, out_string); + va_end(ap); + + cmn_err(CE_DEBUG, "\tReturn status: 0x%x\n", req->sr_status); + cmn_err(CE_DEBUG, "\tSCSI status: 0x%x\n", req->sr_scsi_status); + cmn_err(CE_DEBUG, "\tCDB: "); + for (i = 0; i < req->sr_cmdlen; ++i) + cmn_err(CE_DEBUG, "%s ", sprint_hex(req->sr_command[i])); + cmn_err(CE_DEBUG, "\n"); + if (req->sr_sensegotten > 0) { + cmn_err(CE_DEBUG, "\tSCSI sense: "); + for (i = 0; i < req->sr_sensegotten; ++i) { + if ((i > 0) && ((i % 16) == 0)) + cmn_err(CE_DEBUG, "\n\t "); + else + if ((i > 0) && ((i % 4) == 0)) + cmn_err(CE_DEBUG, " "); + cmn_err(CE_DEBUG, "%s ", sprint_hex(req->sr_sense[i])); + } + cmn_err(CE_DEBUG, "\n"); + } + } +#endif +} + + +static int +failover_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int +failover_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static int +failover_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + + int error=0; + unsigned long arg1, arg2; + + struct fo_ioctl_args args; + + if (copy_from_user ((void *)&args, (void *)arg, sizeof(struct fo_ioctl_args))) + return -EFAULT; + + arg1 = args.arg1; + arg2 = args.arg2; + + switch (cmd) { + + case DIOCFOUPDATE: + /* arg1 - pointer to fgi structure */ + /* arg2 - user allocation size */ + { + struct user_fo_generic_info *fgi; + + if (!capable(CAP_SYS_ADMIN)) { + return -EPERM; + } + + fgi = (struct user_fo_generic_info *) kmem_zalloc (arg2, KM_NOSLEEP); + if (!fgi) return -ENOMEM; + + if (copy_from_user ((void *)fgi, (void *) arg1, arg2)) + return -EFAULT; + + /* + ** Call into the failover software. + */ + error = fo_scsi_device_update_generic(fgi); + if (error) error = -error; + kmem_free ((void *)fgi,arg2); + } + break; + + case SGI_FO_GET_VERTEX_NAME: + /* arg1 - vertex */ + /* arg2 - pointer to array */ + { + char path_name [MAXDEVNAME]; + int offset; + if ((offset=devfs_generate_path ((vertex_hdl_t)arg1, path_name, sizeof(path_name))) < 0) + return -EINVAL; + + if (copy_to_user ((void *)arg2, (caddr_t)&path_name[offset], MAXDEVNAME-offset)) + return -EFAULT; + + } + break; + + case SGI_FO_GET_MAX_PATHS: + if (copy_to_user ((void *)arg1, (caddr_t)&fo_max_paths, sizeof(int))) + return -EFAULT; + break; + + case SGI_FO_DUMP: + { + struct user_fo_instance *buf, *u_foi; + int alloc_len, len; + struct scsi_candidate *foc; + struct scsi_fo_instance *foi; + int i; + + if (copy_from_user ((void *)&alloc_len, (void *) arg1, sizeof(int))) + return -EFAULT; + + if (alloc_len < fo_max_paths*sizeof(vertex_hdl_t)+sizeof(struct user_fo_instance)) + return -EINVAL; + + if ((buf = kmem_zalloc(alloc_len, KM_NOSLEEP)) == NULL) + return -ENOMEM; + + u_foi = buf; + len = 0; + for (foc = fo_candidates; foc->scsi_match_str1; ++foc) { + for (foi = foc->scsi_foi; foi; foi = foi->foi_next) { + + len += fo_max_paths*sizeof(vertex_hdl_t)+sizeof(struct user_fo_instance); + if (len > alloc_len) { + error = ENOSPC; + goto fo_dump_done; + } + u_foi->foi_primary = foi->foi_primary; + for (i = 0; i < fo_max_paths; ++i) + u_foi->foi_path_vhdl[i] = foi->foi_path[i].foi_path_vhdl; + + u_foi = (struct user_fo_instance *) + ((char *)u_foi + fo_max_paths*sizeof(vertex_hdl_t) + sizeof(struct user_fo_instance)); + + } + } + + if (copy_to_user((void *)arg2, (void *)buf, len)) { + error = -EFAULT; + goto fo_dump_done; + } + if (copy_to_user((void *)arg1, (void *) &len, sizeof(int))) + { + error = -EFAULT; + goto fo_dump_done; + } + fo_dump_done: + kmem_free(buf, alloc_len); + break; + } + + + case SGI_FO_SWITCH: + case SGI_FO_TRESSPASS: + { + int rc; + unsigned long dev; + unsigned int major, minor; + devfs_handle_t p_vhdl, s_vhdl; + + if (!capable(CAP_SYS_ADMIN)) { + return -EPERM; + } + + dev = (unsigned long) arg1; + major = MAJOR (dev); + minor = MINOR (dev); + + p_vhdl = devfs_get_handle (NULL, NULL, major, minor, DEVFS_SPECIAL_BLK, 0); + + if (cmd == SGI_FO_TRESSPASS) + rc = fo_scsi_device_switch_new(p_vhdl, &s_vhdl, 1); + else + rc = fo_scsi_device_switch_new(p_vhdl, &s_vhdl, 0); + + + if (rc == FO_SWITCH_SUCCESS || rc == FO_SWITCH_ONEPATHONLY) { + /* copyout if s_vhdl returned */ + if (!devfs_get_maj_min(s_vhdl,&major,&minor)) { + dev = MKDEV(major,minor); + if (copy_to_user((void *)arg2, (void *)&dev, sizeof(dev))) + return -EFAULT; + } + else BUG(); + } + + if (rc != FO_SWITCH_SUCCESS) + return -EIO; + + break; + } + } + + + return error; +} + +struct file_operations failover_ops = { + ioctl: failover_ioctl, + open: failover_open, + release: failover_close +}; + +/* + * FAILOVER module INIT function. Allocate needed structures. + */ +void +fo_init(void) +{ + u_char *p; + struct fo_request *fr; + int bufsize; + int i; + struct scsi_candidate *foc; + + /* + * Verify fo_max_paths is SANE! + */ +#ifdef NOTYET + if (fo_maximum_paths > 128) fo_max_paths = 128; + else if (fo_maximum_paths < 4) fo_max_paths = 4; + else fo_max_paths = fo_maximum_paths; +#endif + + /* + ** Create the devfs/xscsi/failover node. + */ + + if (devfs_find_handle(devfs_xscsi, "failover", 0,0,0,0) != NULL) return; + + failover_vhdl = devfs_register (devfs_xscsi, "failover", DEVFS_FL_DEFAULT, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &failover_ops, NULL); + if (failover_vhdl == NULL) { + printk ("failover: unable to create devfs entry.\n"); + return; + } + + /* + * Allocate SR freelist sema4. + */ + fr_sema = kern_calloc(1, sizeof(sema_t)); + init_sema(fr_sema, 1, "fo_sr", 0); + fr_count_sema = kern_calloc(1, sizeof(sema_t)); + init_sema(fr_count_sema, FO_SR_LIST_SIZE, "fo_srcnt", 0); + fr_free_list = NULL; + + /* + * Allocate SRs, sense buffers, CDBs and data buffers + */ + bufsize = FO_SR_LIST_SIZE * (sizeof(struct fo_request) + + sizeof(struct scsi_request) + + sizeof(sema_t) + + FO_SR_CDB_SIZE + + FO_SR_SENSE_SIZE + + FO_SR_BUF_SIZE); + p = kern_calloc(1, bufsize); + for (i = 0; i < FO_SR_LIST_SIZE; ++i) { + fr = (struct fo_request *)p; + p += sizeof(struct fo_request); + + fr->fr_srreq = (struct scsi_request *)p; + p += sizeof(struct scsi_request); + + fr->fr_sema = (sema_t *)p; + p += sizeof(sema_t); + init_sema(fr->fr_sema, 0, "fo_sr", i); + + fr->fr_command = p; + p += FO_SR_CDB_SIZE; + + fr->fr_sense = p; + p += FO_SR_SENSE_SIZE; + + fr->fr_buffer = p; + p += FO_SR_BUF_SIZE; + + if (fr_free_list) + fr->fr_next = fr_free_list; + fr_free_list = fr; + } + + /* + * Create instance list locks and do other initialization. + */ + for (i = 0, foc = fo_candidates; foc->scsi_match_str1; ++i, ++foc) { + foc->scsi_foi_sema4 = kern_calloc(1, sizeof(sema_t)); + init_sema(foc->scsi_foi_sema4, 1, "fo_foi", i); + if (!fo_candidate_generic && + strcmp (foc->scsi_match_str1, GENERIC_MATCH_1) == 0 && + strcmp (foc->scsi_match_str2, GENERIC_MATCH_2) == 0) + { + fo_candidate_generic = foc; + } + } +} + +/* + * FAILOVER module START function. Perform auto-failover on those + * degenerate cases where, e.g. in the case of Clariion, a LUN is + * bound to a failed SP. + */ +#ifdef NOTEVER +void +fo_start(void) +{ + struct scsi_candidate *foc; + struct scsi_fo_instance *foi; + int i; + int rc, retry; + u_char ctlr,targ,lun; + scsi_lun_info_t *lun_info; + scsi_ctlr_info_t *ctlr_info; + struct fo_request *fr; + struct scsi_request *req; + u_char *cdb; + u_char *inq; + + if (!fo_auto_failover_on_start) + return; + + for (foc = fo_candidates; foc->scsi_match_str1; ++foc) { + for (foi = foc->scsi_foi; foi; foi = foi->foi_next) { + psema(foc->scsi_foi_sema4, PRIBIO); + if (foi->foi_primary == FOI_NO_PRIMARY) { + /* + * Found an instance with one or more valid paths but with no + * viable primary paths. Go through all valid paths and attempt + * to make then primaries by performing a failover switch. If + * still unsuccessful, then the first call to + * fo_scsi_device_switch for this instance will fail. + */ + for (i = 0; i < fo_max_paths; ++i) { + if (foi->foi_path[i].foi_path_status == FOI_PATHSTAT_VALID && + foc->scsi_switch_func) { + lun_info = scsi_lun_info_get(foi->foi_path[i].foi_path_vhdl); + ctlr_info = STI_CTLR_INFO(SLI_TARG_INFO(lun_info)); + ctlr = SLI_ADAP(lun_info); + targ = SLI_TARG(lun_info); + lun = SLI_LUN(lun_info); + DBG(2, "fo_start(%d,%d,%d) - initiating auto-failover\n", ctlr, targ, lun); + rc = (*foc->scsi_switch_func)(0, foi->foi_path[i].foi_path_vhdl); + if (rc == 0) { + DBG(2, "fo_start(%d,%d,%d) - auto-failover successfull\n", ctlr, targ, lun); + /* + * Successfully performed failover switch - make this + * path the primary and create appropriate HWG nodes. + */ + + foi->foi_primary = i; + /* + * Get the inquiry string and call scsi_device_update to + * create HWG nodes for this path. + */ + inq = kern_calloc(1, SCSI_INQUIRY_LEN); + fr = fo_get_fr(); + for (retry = 2; ;) { + ASSERT(fr); + req = fr->fr_srreq; + cdb = req->sr_command; + cdb[0] = 0x12; + cdb[1] = cdb[2] = cdb[3] = cdb[5] = 0x0; + cdb[4] = SCSI_INQUIRY_LEN; + req->sr_lun_vhdl = foi->foi_path[i].foi_path_vhdl; + req->sr_ctlr = ctlr; + req->sr_target = targ; + req->sr_lun = lun; + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = 10; + req->sr_buffer = inq; + req->sr_buflen = SCSI_INQUIRY_LEN; + req->sr_notify = fo_scsi_done; + + DBG(10, "fo_start: issuing inquiry command - fr 0x%x, req 0x%x\n", fr, req); + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + DBG(10, "fo_start: command done, req 0x%x\n", req); + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) + break; + SCSI_DBG(1, req, "fo_start: Inquiry command failed: req 0x%x\n", req); + if (retry-- == 0) { + rc = -1; + DBG(1, "fo_start(%d,%d,%d) - auto-failover update failed\n", ctlr, targ, lun); + goto update_done; + } + } + scsi_device_update(inq, foi->foi_path[i].foi_path_vhdl); + update_done: + fo_free_fr(fr); + kern_free(inq); + } + + + else { + DBG(1, "fo_start(%d,%d,%d) - auto-failover failed\n", ctlr, targ, lun); + } + } + } + } + vsema(foc->scsi_foi_sema4); + } + } +} +#endif + +static struct fo_request * +fo_get_fr(void) { + struct fo_request *fr; + + psema(fr_count_sema, PRIBIO); + psema(fr_sema, PRIBIO); + + fr = fr_free_list; + fr_free_list = fr->fr_next; + fr->fr_next = NULL; + + fr->fr_srreq->sr_command = fr->fr_command; + fr->fr_srreq->sr_sense = fr->fr_sense; + fr->fr_srreq->sr_senselen = FO_SR_SENSE_SIZE; + fr->fr_srreq->sr_buffer = fr->fr_buffer; + fr->fr_srreq->sr_dev = fr->fr_sema; + + vsema(fr_sema); + return(fr); +} + +static void +fo_free_fr(struct fo_request *fr) +{ + psema(fr_sema, PRIBIO); + + if (fr_free_list) + fr->fr_next = fr_free_list; + fr_free_list = fr; + + vsema(fr_sema); + vsema(fr_count_sema); +} + + +/* + * Clear the DK_FAILOVER flag in the dksoftc structure for the device, to stop + * incoming requests from being returned with EIO. + * This is necessary should we be returning to a previously failed path. + */ + +static void +fo_enable_access(vertex_hdl_t lun_vhdl, struct scsi_fo_instance *foi, int remove_primary) +{ + if (!foi->foi_restrict) + return; + + if (dk_clr_flags(lun_vhdl,DK_FAILOVER)) + DBG (2, "Unable to clear failover flag for new vhdl %d\n", lun_vhdl); +} + +/* + * Set the DK_FAILOVER flag in the dksoftc structure for the device, to cause + * the queued requests to be dequeued and returned with EIO. This should + * result in a retry of those requests down the new path. + * Also results in new requests to the device being rejected with EIO. + */ +static void +fo_restrict_access(vertex_hdl_t lun_vhdl, struct scsi_fo_instance *foi, int failed) +{ + if (!foi->foi_restrict) + return; + + if (dk_set_flags (lun_vhdl,DK_FAILOVER)) + DBG (2, "Unable to set failover flag for old vhdl %d\n", lun_vhdl); + +} + +vertex_hdl_t +fo_get_lun_vhdl_from_dev (unsigned long dev) +{ + vertex_hdl_t lun_vhdl=NULL; + unsigned int major, minor; + major = MAJOR (dev); + minor = MINOR (dev); + + if (major || minor) { + lun_vhdl = devfs_get_handle (NULL, NULL, major, minor, DEVFS_SPECIAL_BLK, 0); + if (lun_vhdl) lun_vhdl=devfs_get_parent(lun_vhdl); + } + + return lun_vhdl; +} + +/* + * FAILOVER module primary entry point. Called from + * dkscioctl(). Accepts a user_fo_generic_info structure (from user land!) + * and creates an instance structure for each entry within it. + * + * First, verify that lvhs in call not resident in a different group. + * If so, if it's primary, fail the call. + * if it's alternate, remove from group. + * + * Second, see if group membership is changing. + * If removing primary, initiate failover, to new primary if possible, then remove. + * If removing alternate, remove from group. + * + * Third, update group. + * Add new members. + * If changing primary, failover to it. + * + * Exit status: + * 0 - ok + * EINVAL - user_fo_generic_info invalid + * EACCES - specified path part of different group + * EBUSY - tried to remove primary path from group + * ENOMEM - no room in instance table (too many entries), some entries may have been added + * EBADF - group name mismatch or foi points to wrong candidate table + */ + +int +fo_scsi_device_update_generic (struct user_fo_generic_info *fgi) +{ + int error=0; + int i; + int j; + int paths; + int found_match; + int is_viable_primary; + int is_new_instance=0; + u_char *inq; + scsi_name_t foi_name; + vertex_hdl_t lun_vhdl; + scsi_lun_info_t *lun_info; + struct scsi_candidate *foc; + struct scsi_fo_instance *foi; + struct scsi_fo_instance *match; + struct scsi_fo_instance *inst; + + for (foc = fo_candidates; foc->scsi_match_str1; ++foc) + { + if (!strncmp(foc->scsi_match_str1, + (char *) &fgi->fgi_lun_data[0].fgi_inq_data[foc->scsi_match_off1], + strlen(foc->scsi_match_str1)) && + !strncmp(foc->scsi_match_str2, + (char *) &fgi->fgi_lun_data[0].fgi_inq_data[foc->scsi_match_off2], + strlen(foc->scsi_match_str2))) + { + psema(foc->scsi_foi_sema4, PRIBIO); /* lock the list */ + if (foc->scsi_primary_func != NULL) + error = (*foc->scsi_primary_func)(foc, fgi); + else + error = EINVAL; + vsema(foc->scsi_foi_sema4); + goto bail_out; + } + } + + /* + ** Find the generic failover candidate table entry. + */ + for (found_match=0, foc = fo_candidates; + foc->scsi_match_str1; + ++foc) { + if ( strcmp (foc->scsi_match_str1, GENERIC_MATCH_1) == 0 + && strcmp (foc->scsi_match_str2, GENERIC_MATCH_2) == 0) { + + found_match = 1; + break; + } + } + + if (!found_match) { + error = EBADF; + goto bail_out; + } + + /* + ** Extract group name from failover_generic_info + ** and save in buffer. + */ + + foi_name = fgi->fgi_instance_name; + if (strlen(foi_name) == 0) { + error = EINVAL; + goto bail_out; + } + + /* + ** Validate input structure. + ** Have to have at least one set of data. + ** NULL terminates input. + ** Convert major/minor fgi_lun_vhdl to a + ** real vertex_hdl_t. + */ + + for (i=0; ifgi_lun_data[i].fgi_lun_vhdl = fo_get_lun_vhdl_from_dev ((unsigned long)fgi->fgi_lun_data[i].fgi_lun_vhdl); + if (! fgi->fgi_lun_data[i].fgi_lun_vhdl) { + if (i==0) { + error = ENODEV; + goto bail_out; + } + else break; + } + } + + /* + ** Set number of paths encountered within structure. + */ + + paths = i; + + /* + ** Try and get the failover instance by comparing group names. + ** Verify that all incoming lun_vhdls are + ** not part of another instance. + ** + ** Note, raid instances are not checked. + */ + + psema(foc->scsi_foi_sema4, PRIBIO); /* lock the list */ + + inst = foc->scsi_foi; + match = 0; + + while ((foi=inst)) { /* spin down the instances */ + + if (strcmp (inst->foi_grp_name,foi_name) != 0) { /* wrong group */ + + for (i=0; ifgi_lun_data[i].fgi_lun_vhdl; + if (inst->foi_path[j].foi_path_vhdl == lun_vhdl) { + error = EACCES; + goto update_done; + } + } + } + } + else { + match = inst; /* found foi! */ + } + inst = inst->foi_next; + } + + foi = match; + + /* + ** Try and get the failover instance from a lun_info. + */ + + if (!foi) { + for (foi=NULL,j=0; jfgi_lun_data[j].fgi_lun_vhdl; + lun_info = scsi_lun_info_get(lun_vhdl); + foi = SLI_FO_INFO(lun_info); + if (foi) { + break; + } + + } + } + + /* + ** Instance doesn't exist for any paths. + ** + ** If this is the very first instance, allocate and set up. + ** If not, scan the instance chain checking for conflicting + ** group name. Should there be a conflict, return EBUSY. + */ + + + if (!foi) { /* instance doesn't exist, set one up */ + + /* + ** + */ + + if (!foc->scsi_foi) { /* first instance */ + is_new_instance = 1; + foi = kern_calloc(1, sizeof(struct scsi_fo_instance)+(sizeof(struct foi_path_info)*fo_max_paths)); + foc->scsi_foi = foi; + foi->foi_foc = foc; + foi->foi_grp_name = kern_calloc(1,1+sizeof(fgi->fgi_instance_name)); + foi->foi_primary = FOI_NO_PRIMARY; + foi->foi_restrict = 1; + strcpy (foi->foi_grp_name,fgi->fgi_instance_name); + for (i=0; ifoi_path[i].foi_path_vhdl = 0; + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_INVALID; + } + } + + else { /* Check for duplicate group */ + foi = foc->scsi_foi; + while (foi) { + if (strcmp(foi->foi_grp_name,foi_name) == 0) { /* Oops.... */ + error = EBUSY; /* no incoming member same as existing member. */ + goto update_done; + } + foi = foi->foi_next; + } + ASSERT (foi==NULL); + + /* + ** Allocate a new foi and link it into chain. + ** Initialize the foi. + */ + + is_new_instance = 1; + foi = kern_calloc(1, sizeof(struct scsi_fo_instance)+(sizeof(struct foi_path_info)*fo_max_paths)); + foi->foi_next = foc->scsi_foi; + foc->scsi_foi = foi; + foi->foi_foc = foc; + foi->foi_grp_name = kern_calloc(1,1+sizeof(fgi->fgi_instance_name)); + foi->foi_primary = FOI_NO_PRIMARY; + foi->foi_restrict = 1; + strcpy (foi->foi_grp_name,fgi->fgi_instance_name); + + for (i=0; ifoi_path[i].foi_path_vhdl = 0; + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_INVALID; + } + } + } + + else if (foi->foi_foc != foc) { /* from wrong candidate table */ + error = EBADF; + goto update_done; + } + + /* + ** A few sanity checks before going TOO far. + */ + + ASSERT (foi != NULL); + ASSERT (foc->scsi_foi); + + + /* + ** Make certain that the group name is the same and + ** that the instance points to the right candidate table. + */ + + if (foi->foi_foc != foc || strcmp (foi->foi_grp_name,foi_name) != 0) { + error = EBADF; + goto update_done; + } + + /* + ** Check to see if removing path from instance. + */ + for (i=0; ifgi_lun_data[j].fgi_lun_vhdl; + if (foi->foi_path[i].foi_path_vhdl == lun_vhdl) { + found_match=1; + break; + } + } + if (!found_match && foi->foi_path[i].foi_path_status != FOI_PATHSTAT_INVALID) { + if (i == foi->foi_primary) { /* Don't remove primary! */ + DBG(2,"attempt to remove primary!\n"); + error = EBUSY; + goto update_done; + } + + /* + ** Allow access to device and adjust inventory. + */ + fo_enable_access(foi->foi_path[i].foi_path_vhdl, foi, 1); + + /* + ** Mirror (restore) partitions to device. + */ + fo_mirror_lun ( foi->foi_path[foi->foi_primary].foi_path_vhdl, + foi->foi_path[i].foi_path_vhdl); + + /* + ** Remove the path from failover instance. + */ + DBG(2,"marking path %d invalid, clearing path vhdl of %d\n", + i,foi->foi_path[i].foi_path_vhdl); + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_INVALID; + foi->foi_path[i].foi_path_vhdl = 0; + } + } + + /* + ** Check to see if adding path to instance. + */ + for (i=0; ifgi_lun_data[i].fgi_lun_vhdl; + if (foi->foi_path[j].foi_path_vhdl == lun_vhdl) { + found_match=1; + break; + } + } + if (!found_match) { + /* + ** Add the path. + */ + inq = &fgi->fgi_lun_data[i].fgi_inq_data[0]; + is_viable_primary = ((inq[0] & 0x60) == 0); + lun_vhdl = fgi->fgi_lun_data[i].fgi_lun_vhdl; + error = fo_path_add(foi, lun_vhdl, is_viable_primary); + DBG (2,"fo_scsi_device_update_generic: called fo_path_add, " + "foi 0x%x, rc (%d)\n",(void *)foi,error); + if (error) { + break; + } + } + } + + +update_done: + + if (error && is_new_instance) + fo_remove_instance(foc,foi); + + vsema(foc->scsi_foi_sema4); + +bail_out: + + DBG (2,"fo_scsi_device_update_generic: exit. (%d)\n",error); + return error; +} + +static void +fo_remove_instance (struct scsi_candidate *foc, struct scsi_fo_instance *foi) +{ + + /* + ** Unlink and free the specified instance from the + ** candidate table. + */ + + void (*free_func)(scsi_name_t); + struct scsi_fo_instance *prev, *next; + + if (!foc || !foi) return; + + free_func = (void (*)(scsi_name_t))foc->scsi_freename_func; + + ASSERT (free_func); + + prev = foc->scsi_foi; + + if (prev == foi) { /* first one */ + foc->scsi_foi = foi->foi_next; + free_func (foi->foi_grp_name); + kern_free (foi); + } + else { + next = prev->foi_next; + while (next && next != foi) { + prev = next; + next = next->foi_next; + } + if (next == foi) { /* found it */ + prev->foi_next = foi->foi_next; + free_func (foi->foi_grp_name); + kern_free (foi); + } + } +} + +static int +fo_path_add (struct scsi_fo_instance *foi, vertex_hdl_t lun_vhdl, int is_viable_primary) +{ + int i, error; + const char *path_name; + scsi_lun_info_t *lun_info; + + /* + * Find an unused path slot + */ + + error = 0; + + for (i=0; ; ++i) { + + if (i == fo_max_paths) { + + path_name = devfs_get_name (lun_vhdl, NULL); + if (path_name) { + + cmn_err(CE_WARN, "%s: Failover group alternate path count exceeds %d," + " lun not part of failover group.\n", + path_name, fo_max_paths); + } + + error = ENOMEM; + break; + } + + if (foi->foi_path[i].foi_path_status == FOI_PATHSTAT_INVALID) { + + foi->foi_path[i].foi_path_vhdl = lun_vhdl; + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_VALID; + lun_info = scsi_lun_info_get(lun_vhdl); + SLI_FO_INFO(lun_info) = foi; + + if (foi->foi_primary == FOI_NO_PRIMARY) { + if (is_viable_primary) { + DBG (2,"PRIMARY is %d\n",lun_vhdl); + foi->foi_primary = i; + if (foi->foi_foc->scsi_reportwarnings_func) { + (foi->foi_foc->scsi_reportwarnings_func)(lun_vhdl); + } + fo_enable_access(lun_vhdl, foi, 0); + } + } + else if (foi->foi_foc == fo_candidate_generic) + fo_restrict_access(lun_vhdl, foi, 0); + break; + } + } + + return error; +} + +/* + * FAILOVER module primary entry point. Called from + * scsi_device_update(). Determines if a device is a candidate for + * failover and if so creates an instance structure for it. + */ +void +fo_scsi_device_update(u_char *inq, vertex_hdl_t lun_vhdl) +{ + int found_match=0; + struct scsi_candidate *foc; + struct scsi_fo_instance *foi; + int i; + scsi_name_t foi_name; + u_char ctlr,targ,lun; + scsi_lun_info_t *lun_info; + const char *path_name; + int rc; + int is_viable_primary; + + lun_info = scsi_lun_info_get(lun_vhdl); + ctlr = SLI_ADAP(lun_info); + targ = SLI_TARG(lun_info); + lun = SLI_LUN(lun_info); + + /* + * Is this a viable primary path ? + */ + is_viable_primary = ((inq[0] & 0x60) == 0); + + /* + * If current LUN already has a pointer to the failover instance + * struct, then we've previously encountered this device, and it + * should be part of a failover instance. + * If no primary has been found yet, and this lun has become eligible + * to be a primary, make it primary. + * If it is a primary, then enable access, else restrict access. It + * is unnecessary to do this when added to the foi, since this code + * will be executed on the second successful scsi_info. Since the + * first will result in the device being created, ioconfig will force + * at least a second in setting ctlr number. + */ + foi = SLI_FO_INFO(lun_info); + if (foi) { + for (i = 0; i < fo_max_paths; ++i) + if (foi->foi_path[i].foi_path_vhdl == lun_vhdl) + break; + if (i == fo_max_paths) + cmn_err(CE_PANIC, "fo_scsi_device_update: Path not found: foi 0x%x, lun_vhdl %d\n", foi, lun_vhdl); + if (foi->foi_primary == FOI_NO_PRIMARY && is_viable_primary) { + /* + * Make this LUN the primary path + */ + foi->foi_primary = i; + if (foi->foi_foc->scsi_reportwarnings_func) { + (foi->foi_foc->scsi_reportwarnings_func)(lun_vhdl); + } + } + if (foi->foi_primary == i) + fo_enable_access(lun_vhdl, foi, 0); + else + fo_restrict_access(lun_vhdl, foi, 0); + return; + } + + /* + * Walk down candidates list looking for a match + */ + for (foc = fo_candidates; foc->scsi_match_str1; ++foc) { + if (strncmp(foc->scsi_match_str1, + (char *)(inq+foc->scsi_match_off1), + strlen(foc->scsi_match_str1)) == 0 && + strncmp(foc->scsi_match_str2, + (char *)(inq+foc->scsi_match_off2), + strlen(foc->scsi_match_str2)) == 0) { + found_match = 1; + break; + } + } +#define GENERIC 0 +#if !GENERIC + if (!found_match) + return; +#else + if (!found_match) { + foc--; + goto try_generic; + } +#endif + + DBG(10, "fo_scsi_device_update(%d,%d,%d) - found match\n", ctlr, targ, lun); + + /* + * Make sure the current LUN is valid, i.e. is bound, or is not + * bound but does exist. + */ + ASSERT(foc->scsi_validlun_func); + if (!(*foc->scsi_validlun_func)(inq, lun_vhdl)) { + DBG(2, "fo_scsi_device_update(%d,%d,%d) - invalid LUN\n", ctlr, targ, lun); + return; + } + +#if GENERIC +try_generic: +#endif + + ASSERT(foc->scsi_getname_func); + if ((*foc->scsi_getname_func)(lun_vhdl, &foi_name, inq)) { + printk("fo_scsi_device_update(%d,%d,%d) - scsi_getname_func failed\n", ctlr, targ, lun); + return; + } + + /* + * Get pathname for debug + */ + + path_name = devfs_get_name (lun_vhdl, NULL); + ASSERT(path_name); + + /* + * Lock instance list and walk down list of instances looking for a + * match. If we match the name against an existing instance, we add + * to the group, otherwise we create a new instance. + */ + psema(foc->scsi_foi_sema4, PRIBIO); + if (foc->scsi_foi) { + for (foi = foc->scsi_foi; foi; foi = foi->foi_next) { + ASSERT(foc->scsi_cmpname_func); + if ((rc = (*foc->scsi_cmpname_func)(foi->foi_grp_name, foi_name)) != FO_NAMECMP_FAIL) { +#ifdef DEBUG + /* + * Got a match -- make sure it's not a duplicate + */ + for (i = 0; i < fo_max_paths; ++i) { + if (foi->foi_path[i].foi_path_vhdl == lun_vhdl) + ASSERT(foi->foi_path[i].foi_path_vhdl != lun_vhdl); + } +#endif + DBG(10, "fo_scsi_device_update(%d,%d,%d) -- %s %s - %s\n", + ctlr, targ, lun, + path_name, + (*foc->scsi_sprintf_func)(foi_name), + (rc == FO_NAMECMP_SUCCESS) ? "IS MATCH": "IS REPLACE MATCH"); + + /* + * Find an unused path slot + */ + for (i = 0; ; ++i) { + if (i == fo_max_paths) { + /* REFERENCED */ + cmn_err(CE_WARN, "%s: Failover group alternate path count exceeds %d," + " lun not part of failover group.\n", + path_name, fo_max_paths); + goto update_done; + } + if (foi->foi_path[i].foi_path_status == FOI_PATHSTAT_INVALID) { + foi->foi_path[i].foi_path_vhdl = lun_vhdl; + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_VALID; + SLI_FO_INFO(lun_info) = foi; + if (is_viable_primary) { + if (foi->foi_primary == FOI_NO_PRIMARY) { + foi->foi_primary = i; + if (foc->scsi_reportwarnings_func) { + (foc->scsi_reportwarnings_func)(lun_vhdl); + } + } + } + + + /* + * If it's a replace match, replace the old name with the new + */ + if (rc == FO_NAMECMP_SUCCESS) { + (*foc->scsi_freename_func)(foi_name); + } + else { + (*foc->scsi_freename_func)(foi->foi_grp_name); + foi->foi_grp_name = foi_name; + } + goto update_done; + } + } + } + } /* for (foi) */ + } + + /* + * No match found or List is empty + */ + DBG(10, "fo_scsi_device_update(%d,%d,%d) -- %s %s - NEW\n", + ctlr, targ, lun, + path_name, + (*foc->scsi_sprintf_func)(foi_name)); + foi = kern_calloc(1, sizeof(struct scsi_fo_instance)+(sizeof(struct foi_path_info)*fo_max_paths)); + if (foc->scsi_foi) + foi->foi_next = foc->scsi_foi; + foc->scsi_foi = foi; + foi->foi_foc = foc; + foi->foi_grp_name = foi_name; + if (is_viable_primary) { + foi->foi_primary = 0; + if (foc->scsi_reportwarnings_func) { + (foc->scsi_reportwarnings_func)(lun_vhdl); + } + } + else + foi->foi_primary = FOI_NO_PRIMARY; + foi->foi_path[0].foi_path_vhdl = lun_vhdl; + foi->foi_path[0].foi_path_status = FOI_PATHSTAT_VALID; + SLI_FO_INFO(lun_info) = foi; + +update_done: + vsema(foc->scsi_foi_sema4); + return; +} + +/* + * FAILOVER module primary entry point. Called when a LUN vertex is + * about to be removed. + */ +void +fo_scsi_lun_remove(vertex_hdl_t lun_vhdl) +{ + int i, j; + struct scsi_fo_instance *foi; + struct scsi_candidate *foc; + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(lun_vhdl); +/* really lun_info = devfs_get_info(lun_vhdl); */ + + if (!lun_info) return; + foi = SLI_FO_INFO(lun_info); + if (!foi) return; + foc = foi->foi_foc; + + /* + * Find this LUN + */ + psema(foc->scsi_foi_sema4, PRIBIO); + for (i = 0; i < fo_max_paths; ++i) { + if (foi->foi_path[i].foi_path_vhdl == lun_vhdl) { + goto lun_found; + } + } + cmn_err(CE_ALERT, "fo_scsi_lun_remove: LUN not found %v\n", lun_vhdl); + vsema(foc->scsi_foi_sema4); + return; + + lun_found: + for (j = 0; j < fo_max_paths; ++j) { + if (foi->foi_path[j].foi_path_status == FOI_PATHSTAT_INVALID) { + continue; + } + } + + /* + * If we've just removed the primary, but not done a + * failover, then we need to mark this group as "without + * primary". + */ + if (i == foi->foi_primary) + foi->foi_primary = FOI_NO_PRIMARY; + + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_INVALID; + foi->foi_path[i].foi_path_vhdl = 0; + vsema(foc->scsi_foi_sema4); + return; +} + +int +fo_scsi_device_path_state (vertex_hdl_t p_vhdl) +{ + /* + ** Return the state of this vertex, i.e., + ** PRIMARY, ALTERNATE, or uninteresting. + */ + char *pn, path_name[MAXDEVNAME]; + int pno; /* path name offset */ + vertex_hdl_t p_lun_vhdl; + scsi_lun_info_t *lun_info; + struct scsi_fo_instance *foi; + + /* + ** Get the full pathname of this vertex, validate its path includes xscsi. + ** Get the parent of the current vertex. It should be the lunxx vertex. + */ + + if ((pno=devfs_generate_path (p_vhdl, path_name, sizeof(path_name))) < 0) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: unable to generate path_name for vertex %d\n",p_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + pn = &path_name[pno]; + if (strstr(pn,"xscsi") == NULL) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: pathname %s for vertex %d isn't an xscsi path.\n",pn,p_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + if ((p_lun_vhdl=devfs_get_parent(p_vhdl)) == NULL) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: unable to get parent vertex for vertex %d\n",p_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + if (strncmp(devfs_get_name(p_lun_vhdl,NULL),"lun",3) != 0) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: vertex %d is not a lun_vertex.\n",p_lun_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + /* + * Get the failover info for the primary lun_vhdl + */ + lun_info = scsi_lun_info_get(p_lun_vhdl); + if (!lun_info) + { + cmn_err(CE_DEBUG, "fo_scsi_device_switch: %s: no lun info.\n",pn); + return FO_SWITCH_INVALID_PATH; + } +cmn_err(CE_DEBUG, "fo_scsi_device_switch: %s: found lun info.\n",pn); + + foi = SLI_FO_INFO(lun_info); + if (foi == NULL) + { + DBG(10, "fo_scsi_device_switch: No failover info associated with lun vertex %d\n", p_lun_vhdl); + return(FO_UNKNOWN_DEVICE); + } + + if (foi->foi_primary != FOI_NO_PRIMARY && foi->foi_path[foi->foi_primary].foi_path_vhdl == p_lun_vhdl) + return FO_PRIMARY_PATH; + else + return FO_ALTERNATE_PATH; +} + +int +fo_scsi_device_switch(vertex_hdl_t p_vhdl, vertex_hdl_t *s_vhdl) +{ + return fo_scsi_device_switch_new(p_vhdl, s_vhdl, 0); +} + +/* + * FAILOVER module primary entry point. Called with a primary path + * (scsi, char or block HWG vertex), performs failover and returns the + * corresponding secondary path. + * + * DEVICE SEMANTICS: In most cases, the vhdl passed in corresponds to + * that of the current primary path. In those cases where the + * failover group in question does *not* currently have a primary + * path, the next available secondary path is picked instead. + */ +int +fo_scsi_device_switch_new(vertex_hdl_t p_vhdl, vertex_hdl_t *s_vhdl, int tresspass) +{ + int rc = FO_SWITCH_SUCCESS; + char *pn, path_name[MAXDEVNAME]; + int pno; /* path name offset */ + const char *tail_name; + int i, j; + int num_paths; + vertex_hdl_t p_lun_vhdl, s_lun_vhdl; + scsi_lun_info_t *lun_info; + struct scsi_candidate *foc; + struct scsi_fo_instance *foi; + + /* + ** Get the full pathname of this vertex, validate its path includes xscsi. + ** Get the parent of the current vertex. It should be the lunxx vertex. + */ + + if ((pno=devfs_generate_path (p_vhdl, path_name, sizeof(path_name))) < 0) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: unable to generate path_name for vertex %d\n",p_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + pn = &path_name[pno]; + if (strstr(pn,"xscsi") == NULL) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: pathname %s for vertex %d isn't an xscsi path.\n",pn,p_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + if ((tail_name=devfs_get_name(p_vhdl,NULL)) == NULL) { /* needed for locating returned vertex hdl */ + cmn_err (CE_DEBUG, "fo_scsi_device_switch: unable to get tail_name for vertex %d\n",p_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + if ((p_lun_vhdl=devfs_get_parent(p_vhdl)) == NULL) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: unable to get parent vertex for vertex %d\n",p_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + if (strncmp(devfs_get_name(p_lun_vhdl,NULL),"lun",3) != 0) { + cmn_err (CE_DEBUG, "fo_scsi_device_switch: vertex %d is not a lun_vertex.\n",p_lun_vhdl); + return (FO_SWITCH_INVALID_PATH); + } + + /* + * Get the failover info for the primary lun_vhdl + */ + lun_info = scsi_lun_info_get(p_lun_vhdl); + if (!lun_info) + { + cmn_err(CE_DEBUG, "fo_scsi_device_switch: %s: no lun info.\n",pn); + return FO_SWITCH_INVALID_PATH; + } + + foi = SLI_FO_INFO(lun_info); + if (foi == NULL) + { + DBG(10, "fo_scsi_device_switch: No failover info associated with lun vertex %d\n", p_lun_vhdl); + return(FO_SWITCH_FAIL); + } + foc = foi->foi_foc; + + psema(foc->scsi_foi_sema4, PRIBIO); + + /* + * If only one path and it's currently the primary, return + * degenerate case. + */ + for (i = 0, num_paths = 0; i < fo_max_paths; ++i) + { + if (foi->foi_path[i].foi_path_status != FOI_PATHSTAT_INVALID) + ++num_paths; + } + + /* + * Check if failover has already happened. If the current primary + * path is equal to p_lun_vhdl or there currently is no primary, + * then failover has not been performed yet. + */ + if (foi->foi_primary == FOI_NO_PRIMARY || foi->foi_path[foi->foi_primary].foi_path_vhdl == p_lun_vhdl) + { + int unclun_pend = 1; + u_char path_stat; + int original_primary; + + original_primary = foi->foi_primary; + if (foi->foi_primary == FOI_NO_PRIMARY) + i = 0; + else { + i = foi->foi_primary + 1; + if (i == fo_max_paths) + i = 0; + foi->foi_primary = FOI_NO_PRIMARY; + } + j = 0; + + /* + * Find an unfailed secondary path and try to make it primary. If no + * path works return FO_SWITCH_PATHS_EXHAUSTED. + * + * If there is a device specific switch routine for the new path, + * try to do an Inquiry first, to see if the switch can be avoided, + * unless the tresspass variable is set, in which case we want to + * take the first path. + * If Inquiry's have been done to all paths, and only unconnected luns were + * found, then call the device specific switch routine for the new path. + */ + do + { + path_stat = foi->foi_path[i].foi_path_status; + s_lun_vhdl = foi->foi_path[i].foi_path_vhdl; + DBG(3, "fo_scsi_device_switch: trying path %d status %d\n\tpath %v\n", + i, path_stat, s_lun_vhdl); + if (path_stat == FOI_PATHSTAT_VALID) { + if (!foc->scsi_switch_func) + foi->foi_primary = i; + else if (!tresspass) { + int inqtest; + inqtest = fo_inquiry_test(s_lun_vhdl); + if (inqtest == 0) { + /* + * If the original path is the only one that does + * not require tresspass, but there are other paths + * that could be tresspassed, then try the tresspass + * first. + * A side effect of a successful inquiry test is + * that the primary is set (in fo_scsi_device_update), + * so we need not set it, but we need to set it to + * no primary if we don't want an early exit. + */ + if (original_primary == i) { + if (num_paths == 1) + rc = FO_SWITCH_ONEPATHONLY; + if (j < fo_max_paths*(unclun_pend-1)) + foi->foi_primary = FOI_NO_PRIMARY; + } + } + else if (inqtest == 0x20) { + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_UNCLUN; + unclun_pend = 2; + } else + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_FAILED; + } + else + goto try_tresspass; + } + else if (path_stat == FOI_PATHSTAT_UNCLUN) { +try_tresspass: + DBG (1, "trying trespass %d %d\n",p_lun_vhdl, s_lun_vhdl); + if ((*foc->scsi_switch_func)(p_lun_vhdl, s_lun_vhdl) == 0) + foi->foi_primary = i; + } + i++; + if (i == fo_max_paths) + i = 0; + j++; + } + while (foi->foi_primary == FOI_NO_PRIMARY && (j < fo_max_paths*unclun_pend)); + + if (foi->foi_primary == FOI_NO_PRIMARY) { + /* + * No valid paths found or all paths have failed. + * Make all failed paths valid and keep primary set to what it was on entry. + */ + rc = FO_SWITCH_PATHS_EXHAUSTED; + for (i = 0; i < fo_max_paths; ++i) { + if (foi->foi_path[i].foi_path_status != FOI_PATHSTAT_INVALID) + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_VALID; + } + goto switch_done; + } + } + else + { + s_lun_vhdl = foi->foi_path[foi->foi_primary].foi_path_vhdl; + } + + /* reset 'failed' paths to valid after a good switch */ + for (i = 0; i < fo_max_paths; ++i) { + if (foi->foi_path[i].foi_path_status != FOI_PATHSTAT_INVALID) { + foi->foi_path[i].foi_path_status = FOI_PATHSTAT_VALID; + } + } + + /* + * [Possibly] create disk and partition vertices for secondary + * path. Mirror those of the primary path + */ + if (foc->scsi_vh_coherency_policy == FO_VH_COH_POLICY_LAZY) + fo_mirror_lun(p_lun_vhdl, s_lun_vhdl); + + if (p_lun_vhdl != s_lun_vhdl) + { + fo_enable_access(s_lun_vhdl, foi, 0); + fo_restrict_access(p_lun_vhdl, foi, 1); + } + + *s_vhdl = devfs_find_handle(s_lun_vhdl, tail_name, 0, 0, 0, 0); + if (!(*s_vhdl)) { + rc = FO_SWITCH_FAIL; + } + +switch_done: + vsema(foc->scsi_foi_sema4); + return(rc); +} + +/* + * FAILOVER module primary entry point. Called with a path (scsi, char + * or block HWG vertex) and returns the number of paths in that + * failover group. + */ +int +fo_scsi_device_pathcount(vertex_hdl_t vhdl) +{ + char *pn, path_name[MAXDEVNAME]; + int pno; + const char *tail_name; + int i; + vertex_hdl_t lun_vhdl; + scsi_lun_info_t *lun_info; + struct scsi_fo_instance *foi; + int pathcount; + + /* + ** Get the full pathname of this vertex, validate its path includes xscsi. + ** Get the parent of the current vertex. It should be the lunxx vertex. + */ + + if ((pno=devfs_generate_path (vhdl, path_name, sizeof(path_name))) < 0) { + cmn_err (CE_DEBUG, "fo_scsi_device_pathcount: unable to generate path_name for vertex %d\n",vhdl); + return (FO_PATHCOUNT_FAIL); + } + + pn = &path_name[pno]; + if (strstr(&path_name[pno],"xscsi") == NULL) { + cmn_err (CE_DEBUG, "fo_scsi_device_pathcount: pathname %s for vertex %d isn't an xscsi path.\n",&path_name[pno],vhdl); + return (FO_PATHCOUNT_FAIL); + } + + if ((tail_name=devfs_get_name(vhdl,NULL)) == NULL) { /* needed for locating returned vertex hdl */ + cmn_err (CE_DEBUG, "fo_scsi_device_pathcount: unable to get tail_name for vertex %d\n",vhdl); + return (FO_PATHCOUNT_FAIL); + } + + if ((lun_vhdl=devfs_get_parent(vhdl)) == NULL) { + cmn_err (CE_DEBUG, "fo_scsi_device_pathcount: unable to get parent vertex for vertex %d\n",vhdl); + return (FO_PATHCOUNT_FAIL); + } + + if (strncmp(devfs_get_name(lun_vhdl,NULL),"lun",3) != 0) { + cmn_err (CE_DEBUG, "fo_scsi_device_pathcount: vertex %d is not a lun_vertex.\n",lun_vhdl); + return (FO_PATHCOUNT_FAIL); + } + + + /* + * Get the failover info for the lun_vhdl + */ + + lun_info = scsi_lun_info_get(lun_vhdl); + if (!lun_info) { + cmn_err(CE_DEBUG, "fo_scsi_device_pathcount: %s: no lun info.\n",pn); + return FO_PATHCOUNT_FAIL; + } + + foi = SLI_FO_INFO(lun_info); + if (foi == NULL) { + DBG(10, "fo_scsi_device_pathcount: No failover info associated with lun vertex %d\n", lun_vhdl); + return(FO_PATHCOUNT_FAIL); + } + + pathcount = 0; + for (i = 0; i < fo_max_paths; ++i) { + if (foi->foi_path[i].foi_path_status == FOI_PATHSTAT_INVALID) { + continue; + } + ++pathcount; + } + return(pathcount); +} + +/* + * FAILOVER module primary entry point. Returns non-zero if the device is + * a candidate for failover, else zero. + */ +/* ARGSUSED */ +int +fo_is_failover_candidate(u_char *inq, vertex_hdl_t unused_vhdl) +{ + int found_match=0; + struct scsi_candidate *foc; + + /* + * Walk down candidates list looking for a match + */ + for (foc = fo_candidates; foc->scsi_match_str1; ++foc) { + if (strncmp(foc->scsi_match_str1, (char *)(inq+foc->scsi_match_off1), strlen(foc->scsi_match_str1)) == 0 + && strncmp(foc->scsi_match_str2, (char *)(inq+foc->scsi_match_off2), strlen(foc->scsi_match_str2)) == 0) { + found_match = 1; + break; + } + } + return(found_match); +} + + +/* + * Given primary and secondary LUN vertices, mirrors scsi and + * partition vertices hanging off the primary onto the secondary. + */ +static void +fo_mirror_lun(vertex_hdl_t p_lun_vhdl, vertex_hdl_t s_lun_vhdl) +{ + dksc_reprobe (s_lun_vhdl); /* will add "[r]disc" and "[r]partXX" */ +} + +static void +fo_scsi_done(scsi_request_t *req) +{ + vsema(req->sr_dev); +} + +/* +** START OF VENDOR UNIQUE FUNCTIONS +*/ + + +/* ARGSUSED1 */ +static int +dg_sauna_validlun_func(u_char *inq, vertex_hdl_t unused) +{ + /* + * On DG RAID, a LUN can be in one of three states: + * Peripheral Qualifier Device-Type Modifier + * Doesn't Exist 1 0 + * Not Assigned 1 > 0 + * Assigned 0 > 0 + * + * Return: 0, lun invalid + * 1, lun valid + */ + return( ! ( ( (inq[0]&0xE0) == 0x20 ) && ( (inq[1] & 0x7F) == 0) ) ); +/* peripheral_qualifier == 001b (target capabile of supporting device, but not currently connected */ +/* device_type_modifier == 00000b (direct access device) */ +} + + +/* ARGSUSED1 */ +static int +mylex_validlun_func(u_char *inq, vertex_hdl_t unused) +{ + /* + * With Mylex RAID, a LUN is valid if its Peripheral Qualifier is 0. + * + * Return: 0, lun invalid + * 1, lun valid + */ + return((inq[0] & 0xE0) == 0); +} + +static int +lsi_validlun_func(u_char *inq, vertex_hdl_t lun_vhdl) +{ + scsi_lun_info_t *lun_info; + scsi_ctlr_info_t *ctlr_info; + struct fo_request *fr=NULL; + struct scsi_request *req; + u_char *cdb; + u_char *buf; + int lun_valid = 0; + + struct lsi_redundant_controller_page_2c *pg2c; + + /* + ** An unowned lun will return 0x20 in byte 0 of the inquiry data. + ** An unconfigured/unconfigurable lun will return 0x7f. + */ + + if ((inq[0]&0x1f) == 0) { /* so far, so good */ + + /* + ** Read page 2c and check that the RDAC modes are correct. + */ + + lun_info = scsi_lun_info_get(lun_vhdl); + ctlr_info = STI_CTLR_INFO(SLI_TARG_INFO(lun_info)); + + fr = fo_get_fr(); + ASSERT(fr); + + /* + ** Check page 2c for proper rdac modes. + */ + + req = fr->fr_srreq; + cdb = req->sr_command; + buf = req->sr_buffer; + cdb[0] = 0x1A; /* Mode sense of page 0x2C */ + cdb[1] = 0x08; /* Disable return of block descriptor */ + cdb[2] = 0x2c; + cdb[4] = LSI_PG2C_LEN; + req->sr_lun_vhdl = lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = 10*HZ; + req->sr_buflen = LSI_PG2C_LEN; + req->sr_notify = fo_scsi_done; + + DBG(10, "lsi_validlun_func: issuing mode sense command - fr 0x%x, req 0x%x\n", fr, req); + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + DBG(10, "lsi_validlun_func: command done, req 0x%x\n", req); + + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) { /* command okay */ + + pg2c = (struct lsi_redundant_controller_page_2c *)buf; + + /* + ** Check that this is NOT the UTM lun. + ** If the value in the lun table is 3, it's the + ** UTM lun. A one means the lun is owned by this controller. + ** A two means the lun is owned by the alternate controller. + ** A zero means the lun is not configured. + */ + + lun_valid = (pg2c->lun_table[req->sr_lun] == 1 || pg2c->lun_table[req->sr_lun] == 2); + } + fo_free_fr(fr); + } + + return lun_valid; +} + +static int +lsi_reportwarnings_func (vertex_hdl_t lun_vhdl) +{ + scsi_lun_info_t *lun_info; + scsi_ctlr_info_t *ctlr_info; + struct fo_request *fr=NULL; + struct scsi_request *req; + u_char *cdb; + u_char *buf; + char pn[MAXDEVNAME+1]; + int pno; + const char *path_name=NULL; + int alt_controller_present = 0; + + struct lsi_redundant_controller_page_2c *pg2c; + struct lsi_cache_page_2e *pg2e; + + if ((pno=devfs_generate_path (lun_vhdl, pn, sizeof(pn))) >= 0) { + path_name = &pn[pno]; + + lun_info = scsi_lun_info_get(lun_vhdl); + ctlr_info = STI_CTLR_INFO(SLI_TARG_INFO(lun_info)); + + fr = fo_get_fr(); + ASSERT(fr); + + /* + ** Check page 2c for proper rdac modes. + */ + + req = fr->fr_srreq; + cdb = req->sr_command; + buf = req->sr_buffer; + cdb[0] = 0x1A; /* Mode sense of page 0x2C */ + cdb[1] = 0x08; /* Disable return of block descriptor */ + cdb[2] = 0x2c; + cdb[4] = LSI_PG2C_LEN; + req->sr_lun_vhdl = lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = 10*HZ; + req->sr_buflen = LSI_PG2C_LEN; + req->sr_notify = fo_scsi_done; + + DBG(10, "lsi_validlun_func: issuing mode sense command - fr 0x%x, req 0x%x\n", fr, req); + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + DBG(10, "lsi_validlun_func: command done, req 0x%x\n", req); + + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) { /* command okay */ + + pg2c = (struct lsi_redundant_controller_page_2c *)buf; + + alt_controller_present = pg2c->rdac_mode[0]; + } + + /* + ** Get page 2e to report upon current cache settings + */ + + req = fr->fr_srreq; + cdb = req->sr_command; + buf = req->sr_buffer; + cdb[0] = 0x1A; /* Mode sense of page 0x2E */ + cdb[1] = 0x08; /* Disable return of block descriptor */ + cdb[2] = 0x2e; + cdb[4] = LSI_PG2E_LEN; + req->sr_lun_vhdl = lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = 10*HZ; + req->sr_buflen = LSI_PG2E_LEN; + req->sr_notify = fo_scsi_done; + + DBG(10, "lsi_reportwarnings_func: issuing mode sense command - fr 0x%x, req 0x%x\n", fr, req); + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + DBG(10, "lsi_reportwarnings_func: command done, req 0x%x\n", req); + + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) { /* command okay */ + + pg2e = (struct lsi_cache_page_2e *)buf; + + /* + ** Get the cache memory active and write cache active flags. + */ + + if (!alt_controller_present) { + if (pg2e->wca) { + cmn_err (CE_WARN, "%s: write cache active without an alternate controller.\n",path_name); + } + } + else { + if (pg2e->wca && !pg2e->cma) { + cmn_err (CE_WARN, "%s: write cache active without cache mirroring active.\n",path_name); + } + } + } + + fo_free_fr(fr); + } + + return 0; +} + +/* ARGSUSED */ +static int +dg_sauna_getname_func(vertex_hdl_t lun_vhdl, scsi_name_t *ret_name, u_char *inq) +{ + scsi_lun_info_t *lun_info; + scsi_ctlr_info_t *ctlr_info; + struct fo_request *fr; + struct scsi_request *req; + u_char *cdb; + u_char *buf; + uint32_t sig, psig; + struct dg_name *name; + int retry; + int retval = 0; + +#define DG_MODE_SENSE_TO (10*HZ) +#define DG_MAX_RETRIES 5 /* Maximum number of retries */ + + lun_info = scsi_lun_info_get(lun_vhdl); + ctlr_info = STI_CTLR_INFO(SLI_TARG_INFO(lun_info)); + + /* + * Do a MODE SENSE command of page 0x25 to get the signature and + * peer signature. + */ + for (retry = DG_MAX_RETRIES; ;) { + fr = fo_get_fr(); + ASSERT(fr); + req = fr->fr_srreq; + cdb = req->sr_command; + buf = req->sr_buffer; + cdb[0] = 0x1A; /* Mode sense of page 0x25 */ + cdb[1] = 0x08; /* Disable return of block descriptor */ + cdb[2] = 0x25; + cdb[4] = DG_PG25_LEN; + req->sr_lun_vhdl = lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = DG_MODE_SENSE_TO; + req->sr_buflen = DG_PG25_LEN; + req->sr_notify = fo_scsi_done; + + DBG(10, "dg_sauna_getname_func: issuing mode sense command - fr 0x%x, req 0x%x\n", fr, req); + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + DBG(10, "dg_sauna_getname_func: command done, req 0x%x\n", req); + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) + break; + SCSI_DBG(2, req, "dg_sauna_getname_func: Command failed: req 0x%x\n", req); + if (retry-- == 0) { + retval = -1; + goto getname_done; + } + fo_free_fr(fr); + } + + name = kern_calloc(1, sizeof(struct dg_name)); + sig = *(uint32_t *)(buf + 8); + psig = *(uint32_t *)(buf + 12); + ASSERT(sig != psig); + if (sig < psig) { + name->dg_sig1 = sig; + name->dg_sig2 = psig; + } + else { + name->dg_sig1 = psig; + name->dg_sig2 = sig; + } + name->dg_lun = SLI_LUN(lun_info); + *(dg_name_t *)ret_name = name; + + getname_done: + fo_free_fr(fr); + + return(retval); +} + +/* ARGSUSED */ +static int +lsi_getname_func(vertex_hdl_t lun_vhdl, scsi_name_t *ret_name, u_char *inq) +{ + scsi_lun_info_t *lun_info; + scsi_ctlr_info_t *ctlr_info; + struct fo_request *fr; + struct scsi_request *req; + u_char *cdb; + u_char *buf; + struct lsi_name *name=NULL; + int retval = -1; + + + /* + ** Each lun has a uuid associated with it stored in the + ** vital product inquiry page 0x83. Extract it and store + ** in the name for comparison purposes. + */ + + lun_info = scsi_lun_info_get(lun_vhdl); + ctlr_info = STI_CTLR_INFO(SLI_TARG_INFO(lun_info)); + + fr = fo_get_fr(); + ASSERT(fr); + req = fr->fr_srreq; + cdb = req->sr_command; + buf = req->sr_buffer; + cdb[0] = 0x12; /* Inquiry of vital product page 83 */ + cdb[1] = 1; /* enable vital product data */ + cdb[2] = 0x83; + cdb[4] = FO_SR_BUF_SIZE-1; + req->sr_lun_vhdl = lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = 10*HZ; + req->sr_buflen = FO_SR_BUF_SIZE-1; + req->sr_notify = fo_scsi_done; + + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) { + + int i, volume_uuid_ok=0, page_length; + + struct device_id_page *did; + did = (struct device_id_page *)buf; + + page_length = did->page_length; + if (page_length >= 5) { /* implies at least one descriptor */ + + int id; + uint8_t *p; + int remaining_page_length=page_length; + + for (id=0; remaining_page_length>=5; id++) { /* scan ids, look for one usable */ + int code_set, id_type, id_length; + + code_set = did->idlist[id].code_set; + id_type = did->idlist[id].identifier_type; + id_length= did->idlist[id].identifier_length; + remaining_page_length -= (id_length+3+1); + + if ((code_set == 1 || code_set == 2) /* binary or ascii */ + && (id_type >= 1 && id_type <= 3)) { /* assignment authority was used */ + + /* ultimately allocates 1 extra byte */ + name = kern_calloc(1, sizeof(struct lsi_name)+id_length); + + name->lsi_lun = SLI_LUN(lun_info); + name->lsi_name_length = id_length; + + /* + ** copy the uuid to the lsi_name structure, + ** checking that the volume uuid is initialized + ** (lsi uses all blanks as uninitialized uuid) + */ + + for (p=&did->idlist[id].identifier[0],i=0; ilsi_volume_uuid[i] = *p++; + } + if (volume_uuid_ok) { + *(struct lsi_name **)ret_name = name; + retval = 0; + break; + } + } + } + } + } + + fo_free_fr(fr); + + if (retval != 0 && name) kern_free (name); + return(retval); +} + + +#define MYLEX_SIGNATURE_SIZE 20 +#define MYLEX_SIGNATURE_OFFSET 36 + +/* ARGSUSED */ +static int +mylex_getname_func(vertex_hdl_t lun_vhdl, scsi_name_t *ret_name, u_char *inq) +{ + u_char *name; + + name = kern_calloc(1, MYLEX_SIGNATURE_SIZE); + bcopy(&inq[MYLEX_SIGNATURE_OFFSET], name, MYLEX_SIGNATURE_SIZE); + *ret_name = name; + + return 0; +} + + +static int +dg_sauna_cmpname_func(scsi_name_t name1, scsi_name_t name2) +{ + register dg_name_t p1 = name1; + register dg_name_t p2 = name2; + + if (p1->dg_lun == p2->dg_lun) { + if ((p1->dg_sig1 == p2->dg_sig1) && + (p1->dg_sig2 == p2->dg_sig2)) + return(FO_NAMECMP_SUCCESS); + else + if ((p1->dg_sig1 == p2->dg_sig1 && p1->dg_sig1 != 0) || + (p1->dg_sig1 == p2->dg_sig2 && p1->dg_sig1 != 0) || + (p1->dg_sig2 == p2->dg_sig1 && p1->dg_sig2 != 0) || + (p1->dg_sig2 == p2->dg_sig2 && p1->dg_sig2 != 0)) + return(FO_NAMECMP_REPLACE); + else + return(FO_NAMECMP_FAIL); + } + else + return(FO_NAMECMP_FAIL); +} + +static int +lsi_cmpname_func(scsi_name_t name1, scsi_name_t name2) +{ + + struct lsi_name *p1 = name1; + struct lsi_name *p2 = name2; + + int length1 = p1->lsi_name_length; + int length2 = p2->lsi_name_length; + + if (length1 == length2) { + + /* yeah, I know, compares length again.... */ + if (bcmp(p1,p2,sizeof(struct lsi_name)+length1) == 0) { + return(FO_NAMECMP_SUCCESS); + } + else { + return(FO_NAMECMP_FAIL); + } + } + else return FO_NAMECMP_FAIL; +} + +static int +mylex_cmpname_func(scsi_name_t name1, scsi_name_t name2) +{ + if (!bcmp(name1, name2, MYLEX_SIGNATURE_SIZE)) + return FO_NAMECMP_SUCCESS; + else + return FO_NAMECMP_FAIL; +} + +static int +dg_sauna_freename_func(scsi_name_t ret_name) +{ + kern_free(ret_name); + return(0); +} + +static char * +dg_sauna_sprintf_func(scsi_name_t name) +{ + static char ret_str[32]; + dg_name_t p = name; + + sprintf(ret_str, "%x:%x:%d", p->dg_sig1, p->dg_sig2, p->dg_lun); + return(ret_str); +} + +static char * +lsi_sprintf_func(scsi_name_t name) +{ + uint8_t *p = (uint8_t *)name; + struct lsi_name *n = (struct lsi_name *)name; + static char ret_str[FO_SR_BUF_SIZE]; + int i; + + for (i=0; ilsi_name_length+sizeof(struct lsi_name);i++,p++) { + if (*p > 15) sprintf (ret_str+(i*2),"%x", *p); + else sprintf (ret_str+(i*2),"0%x",*p); + } + return ret_str; +} + +static char * +mylex_sprintf_func(scsi_name_t name) +{ + static char ret_str[32]; + sprintf(ret_str, "%d:%Lx", *(uint16_t *)name, + (long long unsigned int)((((uint64_t) ((uint32_t *)name)[1]) << 32) | + (uint64_t) ((uint32_t *)name)[2]) + ); + return ret_str; +} + +/* ARGSUSED2 */ +static int +dg_sauna_switch_func(vertex_hdl_t p_lun_vhdl, vertex_hdl_t s_lun_vhdl) +{ + scsi_lun_info_t *lun_info; + scsi_ctlr_info_t *ctlr_info; + struct fo_request *fr; + struct scsi_request *req; + u_char *cdb; + u_char *buf; + int retry; + int retval = 0; + int err; + +#define DG_INQUIRY_TO (10*HZ) /* Time interval between retries */ +#define DG_MAX_RETRIES 5 /* Maximum number of retries */ +#define DG_TRESPASS_TO (60*HZ) + + lun_info = scsi_lun_info_get(s_lun_vhdl); + ctlr_info = STI_CTLR_INFO(SLI_TARG_INFO(lun_info)); + + for (retry = DG_MAX_RETRIES; ; ) { + if ((err = (SLI_ALLOC(lun_info))(s_lun_vhdl, 0, NULL)) == SCSIALLOCOK) + break; + DBG(1, "dg_sauna_switch_func: scsi_alloc(%d,%d,%d) failed: err = %d\n", + SLI_ADAP(lun_info), SLI_TARG(lun_info), SLI_LUN(lun_info), err); + if (retry-- == 0) + return(-1); + /* + * the delay of 1000 results in a delay of 10 seconds. The original + * comment specified a delay of 1 mSec. That comment was wrong. I'm + * uncertain if the delay value is wrong or not. I'm not going to + * change it at this point in the release. mdr + */ + delay(1000); + } + + /* + * Do the TRESPASS command. + */ + for (retry = DG_MAX_RETRIES; ;) { + fr = fo_get_fr(); + ASSERT(fr); + req = fr->fr_srreq; + cdb = req->sr_command; + buf = req->sr_buffer; + cdb[0] = 0x15; /* Mode select of page 0x22 */ + cdb[4] = DG_PG22_LEN; + req->sr_lun_vhdl = s_lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_AEN_ACK; + req->sr_timeout = 60 * HZ; + req->sr_buflen = DG_PG22_LEN; + req->sr_notify = fo_scsi_done; + bzero(buf, DG_PG22_LEN); + buf[4] = 0x22; /* Trespass page */ + buf[5] = 0x02; /* Length */ + buf[6] = 0x01; /* Trespass only this LUN */ + buf[7] = SLI_LUN(lun_info); /* LUN number */ + + DBG(10, "dg_sauna_switch_func: issuing trespass command - fr 0x%x, req 0x%x\n", fr, req); + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + DBG(10, "dg_sauna_switch_func: command done, req 0x%x\n", req); + psema(req->sr_dev, PRIBIO); + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) + break; + SCSI_DBG(2, req, "dg_sauna_switch_func: Command failed: req 0x%x\n", req); + if (retry-- == 0) { + retval = -1; + goto switch_done; + } + fo_free_fr(fr); + } + + switch_done: + fo_free_fr(fr); + SLI_FREE(lun_info)(s_lun_vhdl, NULL); + + return(retval); +} + +/* ARGSUSED2 */ +static int +lsi_switch_func(vertex_hdl_t p_lun_vhdl, vertex_hdl_t s_lun_vhdl) +{ + scsi_lun_info_t *lun_info; + scsi_ctlr_info_t *ctlr_info; + struct fo_request *fr=NULL; + struct scsi_request *req; + u_char *cdb; + u_char *buf; + int retval=-1; + int retries, forced_retries; + int err; + int parity_scan_required=0; + int command_lock_retries; + int command_lock_delay = 10; + char pn[MAXDEVNAME+1]; + int pno; + char *path_name; + u_char cme=0, wca=0, cma=0; + u_char cache_flags_valid=0; + + struct lsi_redundant_controller_page_2c *pg2c=NULL; + struct lsi_cache_page_2e *pg2e; + +#define LSI_INQUIRY_TO (10) /* Command timeouts */ +#define LSI_TRESPASS_TO (60) +#define LSI_SWITCH_ACTIVE_TO (120) +#define COMMAND_LOCK_RETRIES (10) + + command_lock_retries = COMMAND_LOCK_RETRIES; + + /* + ** A switch of lun ownership involves executing a mode select + ** with the lun's ownership value in the controller lun table + ** set to 0x81. A mode sense is issued prior to the mode select + ** to establish proper defaults for the mode select and to permit + ** verification that the lun in question is currently owned + ** by the current primary controller. + */ + + lun_info = scsi_lun_info_get(s_lun_vhdl); + ctlr_info = STI_CTLR_INFO(SLI_TARG_INFO(lun_info)); + + if ((err = (SLI_ALLOC(lun_info))(s_lun_vhdl, 0, NULL)) != SCSIALLOCOK) { + + DBG(1, "lsi_switch_func: scsi_alloc(%d,%d,%d) failed: err = %d\n", + SLI_ADAP(lun_info), SLI_TARG(lun_info), SLI_LUN(lun_info), err); + return(-1); + } + + fr = fo_get_fr(); + ASSERT(fr); + + if ((pno=devfs_generate_path (s_lun_vhdl, pn, sizeof(pn))) < 0) { + sprintf (pn, "lun vertex %p",(void *)s_lun_vhdl); + pno=0; + } + path_name = &pn[pno]; + + +start_over: + + /* + ** Get page 2e to access current write cache settings. + */ + + retries = 5; + while (retries--) { + req = fr->fr_srreq; + cdb = req->sr_command; + buf = req->sr_buffer; + cdb[0] = 0x1A; /* Mode sense of page 0x2E */ + cdb[1] = 0x08; /* Disable return of block descriptor */ + cdb[2] = 0x2e; + cdb[4] = LSI_PG2E_LEN; + req->sr_lun_vhdl = s_lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = 30*HZ; + req->sr_buflen = LSI_PG2E_LEN; + req->sr_notify = fo_scsi_done; + + DBG(10, "lsi_switch_func: issuing mode sense command - fr 0x%x, req 0x%x\n", fr, req); + ASSERT(req->sr_buffer); + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + DBG(10, "lsi_switch_func: command done, req 0x%x\n", req); + + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) { /* command okay */ + + pg2e = (struct lsi_cache_page_2e *)buf; + + cma = pg2e->cma; + wca = pg2e->wca; + cme = pg2e->cme; + + if (cme && !cma) { + cmn_err (CE_NOTE, "%s: cache mirror enabled but not active.\n",path_name); + } + else if (!cme) { + cmn_err (CE_WARN, "%s: cache mirror not enabled.\n",path_name); + } + cache_flags_valid = 1; + break; + } + } + + /* + ** Do the mode sense to check ownership. + */ + + retries = 5; + while (retries--) { + cdb[0] = 0x1A; /* Mode sense of page 0x2c */ + cdb[1] = 0x08; /* Disable return of block descriptor */ + cdb[2] = 0x2c; + cdb[4] = LSI_PG2C_LEN; + req->sr_lun_vhdl = s_lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = LSI_INQUIRY_TO*HZ; + req->sr_buflen = LSI_PG2C_LEN; + req->sr_notify = fo_scsi_done; + + bzero(buf, LSI_PG2C_LEN); + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 && req->sr_sensegotten == 0) { + pg2c = (struct lsi_redundant_controller_page_2c *)buf; + break; + } + } + + /* + ** If the lun is owned by the current primary controller, first try the + ** "trespass" command. Note: this can fail if the current primary controller + ** is down. The next step is to switch the current primary controller to + ** passive mode, using the "force" bit if necessary. At that point, + ** all luns will be owned by the newly active controller. + */ + + if (pg2c && pg2c->lun_table[req->sr_lun] == 2) { /* owned by current primary controller */ + + int lun_table_value; + retval = -1; + retries = 5; + while (retries-- && retval != 0) { + + /* + ** Do the mode select to take ownership. + */ + + req->sr_flags = SRF_AEN_ACK; + req->sr_timeout = (5+LSI_TRESPASS_TO)*HZ; + cdb[0] = 0x15; /* Mode select of page 0x2c */ + cdb[1] = 0; + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = LSI_PG2C_LEN; + + pg2c->header[0] = pg2c->header[1] = pg2c->header[2] = pg2c->header[3] = 0; + + pg2c->page_code = 0x2c; /* clear ps */ + pg2c->page_length = LSI_PG2C_LEN - 6; + pg2c->quiescence_timeout = LSI_TRESPASS_TO; + lun_table_value = pg2c->lun_table[req->sr_lun]; + pg2c->lun_table[req->sr_lun] = 0x81; /* take ownership */ + pg2c->rdac_options &= ~2; /* clear force bit */ + cmn_err (CE_NOTE, "%s: lun ownership transfer initiated.\n",path_name); + + DBG (2, "lsi_switch: issuing mode select: trespass\n"); + + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + pg2c->lun_table[req->sr_lun] = lun_table_value; /* restore original value */ + + if (req->sr_status == 0 && req->sr_scsi_status == 0 + && req->sr_sensegotten == 0) { /* okay */ + retval = 0; /* exits while, skips next while */ + cmn_err (CE_NOTE, "%s: lun ownership transfer successful.\n",path_name); + } + else if ((req->sr_sensegotten > 14) + && ((req->sr_sense[2]&0xf) == 5) + && (req->sr_sense[12] == 0x91) + && (req->sr_sense[13] == 0x36) + && command_lock_retries) { + cmn_err (CE_NOTE, "%s: command lock: retrying in %d second(s): " + "retries remaining %d.\n", + path_name,command_lock_delay,command_lock_retries); + command_lock_retries--; + delay (command_lock_delay*HZ); + goto start_over; + } + else if (retries) { + if (req->sr_sensegotten) delay (command_lock_delay*HZ); + else delay (HZ*3); /* arbitrary guess at this point */ + cmn_err (CE_NOTE, "%s: lun ownership transfer failed, retrying.\n",path_name); + } + else { + if (cache_flags_valid) { + if (wca && !cma) { + cmn_err (CE_WARN, "%s: write caching active WITHOUT cache mirroring.\n",path_name); + cmn_err (CE_WARN, "%s: lun ownership transfer failed, giving up.\n",path_name); + } + else + cmn_err (CE_NOTE, "%s: lun ownership transfer failed.\n",path_name); + } + else { + cmn_err (CE_WARN, "%s: could not determine state of write caching.\n",path_name); + cmn_err (CE_WARN, "%s: lun ownership transfer failed.\n",path_name); + } + } + } + + /* + ** If the modeselect to take ownership didn't work, the + ** next step is to switch the current primary controller to + ** passive mode and this controller then becomes the + ** active controller in the active/passive pair. + */ + + command_lock_retries = COMMAND_LOCK_RETRIES; + + retries = 5; + forced_retries = 3; + while (cache_flags_valid && (cma||!wca) && (retries || forced_retries) && retval != 0) { + + /* + ** Do the mode select to become active controller and + ** make the current primary controller passive. + ** + ** This takes ownership of all luns from the current primary. + */ + + req->sr_flags = SRF_AEN_ACK; + req->sr_timeout = (5+LSI_SWITCH_ACTIVE_TO)*HZ; + cdb[0] = 0x15; /* Mode select of page 0x2c */ + cdb[1] = 0; + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = LSI_PG2C_LEN; + + pg2c->header[0] = pg2c->header[1] = pg2c->header[2] = pg2c->header[3] = 0; + + pg2c->page_code = 0x2c; /* clear ps */ + pg2c->page_length = LSI_PG2C_LEN - 6; + pg2c->lun_table[req->sr_lun] = 0x2; /* restore original value */ + pg2c->rdac_mode[1] = 1; /* become the active controller */ + pg2c->quiescence_timeout = LSI_SWITCH_ACTIVE_TO; + if (retries) { + pg2c->rdac_options &= ~2; /* disable forced quiescence */ + cmn_err (CE_NOTE, "%s: attempting to set the alternate controller " + "to passive mode.\n",path_name); + retries --; + } + else { + pg2c->rdac_options |= 2; /* enable forced quiescence */ + cmn_err (CE_NOTE, "%s: attempting to force the alternate controller " + "to passive mode.\n",path_name); + forced_retries --; + } + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 + && req->sr_sensegotten == 0) { /* okay */ + retval = 0; /* exits while */ + parity_scan_required = 1; + cmn_err (CE_NOTE, "%s: successfully set controller passive.\n",path_name); + } + else if ((req->sr_sensegotten > 14) + && ((req->sr_sense[2]&0xf) == 5) + && (req->sr_sense[12] == 0x91) + && (req->sr_sense[13] == 0x36) + && command_lock_retries) { + cmn_err (CE_NOTE, "%s: command lock: retrying in %d seconds: " + "retries remaining %d.\n", + path_name,command_lock_delay,command_lock_retries); + command_lock_retries--; + delay (command_lock_delay*HZ); + goto start_over; + } + else if (retries || forced_retries) { + cmn_err (CE_NOTE, "%s: unable to set controller passive, retrying.\n",path_name); + if (req->sr_sensegotten) delay (command_lock_delay*HZ); + else delay (HZ*3); /* arbitrary guess at this point */ + } + else { + cmn_err (CE_WARN, "%s: unable to set controller passive, giving up.\n",path_name); + } + } + + if (parity_scan_required) { + cdb[0] = 0x1A; /* Mode sense of page 0x2c */ + cdb[1] = 0x08; /* Disable return of block descriptor */ + cdb[2] = 0x2c; + cdb[4] = LSI_PG2C_LEN; + req->sr_lun_vhdl = s_lun_vhdl; + req->sr_ctlr = SLI_ADAP(lun_info); + req->sr_target = SLI_TARG(lun_info); + req->sr_lun = SLI_LUN(lun_info); + req->sr_cmdlen = SC_CLASS0_SZ; + req->sr_flags = SRF_DIR_IN | SRF_AEN_ACK; + req->sr_timeout = LSI_INQUIRY_TO*HZ; + req->sr_buflen = LSI_PG2C_LEN; + req->sr_notify = fo_scsi_done; + + bzero(buf, LSI_PG2C_LEN); + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + /* + ** Do the mode select to initiate a parity scan. + */ + + command_lock_retries = COMMAND_LOCK_RETRIES; + +start_over2: + req->sr_flags = SRF_AEN_ACK; + req->sr_timeout = (5+LSI_SWITCH_ACTIVE_TO)*HZ; + cdb[0] = 0x15; /* Mode select of page 0x2c */ + cdb[1] = 0; + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = LSI_PG2C_LEN; + + pg2c->header[0] = pg2c->header[1] = pg2c->header[2] = pg2c->header[3] = 0; + + pg2c->page_code = 0x2c; /* clear ps */ + pg2c->page_length = LSI_PG2C_LEN - 6; + pg2c->quiescence_timeout = LSI_SWITCH_ACTIVE_TO; + + pg2c->rdac_options = 1; + + DBG (2, "lsi_switch: initiating parity scan\n"); + cmn_err (CE_NOTE, "%s: initiating parity scan\n" ,path_name); + + (*ctlr_info->sci_command)(req); + psema(req->sr_dev, PRIBIO); + + if (req->sr_status == 0 && req->sr_scsi_status == 0 + && req->sr_sensegotten == 0) { /* okay */ + retval = 0; /* exits while */ + cmn_err (CE_NOTE, "%s: successfully initiated parity scan.\n",path_name); + } + else if ((req->sr_sensegotten > 14) + && ((req->sr_sense[2]&0xf) == 5) + && (req->sr_sense[12] == 0x91) + && (req->sr_sense[13] == 0x36) + && command_lock_retries) { + cmn_err (CE_NOTE, "%s: command lock: retrying in %d seconds: " + "retries remaining %d.\n", + path_name,command_lock_delay,command_lock_retries); + command_lock_retries--; + delay (command_lock_delay*HZ); + goto start_over2; + } + else { + cmn_err (CE_WARN, "%s: unable to initiate parity scan.\n",path_name); + } + } + } + else if (pg2c && pg2c->lun_table[req->sr_lun] == 1) { /* already owned by this controller */ + cmn_err (CE_NOTE, "%s: lun ownership transfer not required.\n",path_name); + retval = 0; + } + + fo_free_fr (fr); + SLI_FREE(lun_info)(s_lun_vhdl, NULL); + + return retval; +} + +/* ARGSUSED2 */ +int +mylex_switch_func(vertex_hdl_t p_lun_vhdl, vertex_hdl_t s_lun_vhdl) +{ + return 0; +} + +/* + * return: EBADF if the chosen primary lun isn't viable (unconnected lun) + * EINVAL if there is no foi for the chosen lun + */ +static int +clariion_k5_primary_func(struct scsi_candidate *foc, struct user_fo_generic_info *fgi) +{ + struct scsi_fo_instance *foi; + vertex_hdl_t lun_vhdl; + int i, j; + + if (fgi->fgi_lun_data[0].fgi_inq_data[0] & 0x60) + return EBADF; + + /* + * Look through foi's to find one with this lun vhdl + */ + lun_vhdl = fgi->fgi_lun_data[0].fgi_lun_vhdl; + DBG (3, "Attempting to mark %d as primary in its failover group\n", lun_vhdl); + foi = foc->scsi_foi; + while (foi != NULL) + { + for (i = 0; i < fo_max_paths; i++) + { + if (foi->foi_path[i].foi_path_vhdl == lun_vhdl && + foi->foi_path[i].foi_path_status == FOI_PATHSTAT_VALID) + goto found_foi; + } + foi = foi->foi_next; + } + return EINVAL; + +found_foi: + foi->foi_restrict = 1; + DBG(3, "Found %d in foi 0x%x, path %d\n", lun_vhdl, foi, i); + for (j = 0; j < fo_max_paths; j++) + { + if (j == i || foi->foi_path[j].foi_path_status == FOI_PATHSTAT_INVALID) + continue; + fo_restrict_access(foi->foi_path[j].foi_path_vhdl, foi, 0); + } + fo_enable_access(lun_vhdl, foi, 0); + foi->foi_primary = i; + return 0; +} + + +static int +fo_generic_switch_func (vertex_hdl_t p_lun_vhdl, vertex_hdl_t s_lun_vhdl) +{ + scsi_lun_info_t *lun_info; + int retry; + int retval = 0; + int err; + + p_lun_vhdl = p_lun_vhdl; /* remove compiler remark */ + + lun_info = scsi_lun_info_get(s_lun_vhdl); + + for (retry = 5; ; ) { + if ((err = (SLI_ALLOC(lun_info))(s_lun_vhdl, 0, NULL)) == SCSIALLOCOK) + break; + DBG(1, "fo_generic_switch_func: scsi_alloc(%d,%d,%d) failed: err = %d\n", + SLI_ADAP(lun_info), SLI_TARG(lun_info), SLI_LUN(lun_info), err); + if (retry-- == 0) + return(-1); + delay(100); /* Delay 1 sec */ + } + + SLI_FREE(lun_info)(s_lun_vhdl, NULL); + + return(retval); +} + + +static int +fo_inquiry_test(vertex_hdl_t s_lun_vhdl) +{ + struct scsi_target_info *info; + scsi_lun_info_t *lun_info; + + lun_info = scsi_lun_info_get(s_lun_vhdl); + info = SLI_INQ(lun_info)(s_lun_vhdl); + + DBG(1, "fo_inquiry_test: scsi_alloc(%d,%d,%d) returned 0x%x (0x%x)\n", + SLI_ADAP(lun_info), SLI_TARG(lun_info), SLI_LUN(lun_info), info, + info ? info->si_inq[0] : -1); + + if (info != SCSIDRIVER_NULL) + return (int) (uint) info->si_inq[0]; + + return -1; +} + +EXPORT_SYMBOL(fo_scsi_device_path_state); +EXPORT_SYMBOL(fo_scsi_device_switch); +EXPORT_SYMBOL(fo_scsi_device_pathcount); +EXPORT_SYMBOL(fo_is_failover_candidate); diff -Nur linux-2.4.19/drivers/xscsi/xscsi.c linux-2.4.19-sgi211r3/drivers/xscsi/xscsi.c --- linux-2.4.19/drivers/xscsi/xscsi.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/xscsi.c Fri Jan 3 08:28:29 2003 @@ -0,0 +1,1040 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xscsi.h" +#include "xfailover.h" + +#define DK_PART_SHIFT 4 + +devfs_handle_t devfs_xscsi; + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_xscsi; +#endif + +static void scsi_dev_remove(vertex_hdl_t); + +/* + * Linux init functions + */ +static void (*scsidriver_init[])(void) = { +#ifdef CONFIG_XSCSI_DKSC + dkscinit, + fo_init, +#endif +#ifdef CONFIG_XSCSI_MMSC + mmscinit, +#endif +}; + + +#ifdef CONFIG_PROC_FS +static int +xscsi_proc_info(char *buffer, char **start, off_t offset, int length) +{ + return 0; +} +#endif + +static void +xscsi_init_proc(void) +{ +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *generic; + + generic = proc_mkdir("xscsi", NULL); + if (!generic) { + printk(KERN_ERR "cannot init /proc/xscsi\n"); + return; + } + + proc_xscsi = proc_mkdir("xscsi/ctlr", NULL); + if (!proc_xscsi) + printk(KERN_ERR "cannot init /proc/xscsi/ctlr\n"); + + generic = create_proc_info_entry("xscsi/scsi", 0, 0, xscsi_proc_info); + if (!generic) + printk(KERN_ERR "cannit init /proc/xscsi/scsi\n"); +#endif +} + +static kmem_cache_t *scsi_targ_cache; +static kmem_cache_t *scsi_lun_cache; +static kmem_cache_t *scsi_dev_cache; + +static int +xscsi_init(void) +{ + int i; + + xscsi_init_proc(); + + scsi_targ_cache = kmem_cache_create("xscsi_targ_info", sizeof(scsi_targ_info_t), + 0, 0, NULL, NULL); + scsi_lun_cache = kmem_cache_create("xscsi_lun_info", sizeof(scsi_lun_info_t), + 0, 0, NULL, NULL); + scsi_dev_cache = kmem_cache_create("xscsi_dev_info", sizeof(scsi_dev_info_t), + 0, 0, NULL, NULL); + + devfs_xscsi = devfs_mk_dir(NULL, "xscsi", NULL); + if (devfs_xscsi == NULL) { + printk("xscsi: unable to create devfs entry\n"); + return -ENODEV; + } + + init_rwsem(&scsi_hwgraph_lock); + + for (i = 0; i < sizeof(scsidriver_init)/sizeof(scsidriver_init[0]); i++) + (*scsidriver_init[i])(); + +#ifdef CONFIG_KDB + { static void xscsidbg_init(void); xscsidbg_init(); } +#endif + + return 0; +} +module_init(xscsi_init); + + +/* + * Some SCSI devices lie about supporting multiple LUNs. Since the + * infrastructure automatically creates device nodes for all supported + * LUNs, exceptions need to be noted. + */ +single_inq_str_s multilun_exc_inq_strings[] = { + { "TEAC", 8, 0 }, + { "INSITE", 8, 0 }, + { NULL, 0, 0 } +}; + +char *scsi_adaperrs_tab[NUM_ADAP_ERRS] = { + "", + "device does not respond to selection", + "Controller protocol error or SCSI bus reset", + "SCSI bus parity error", + "Parity/ECC error in system memory during DMA", + "Command timed out", + "Buffer not correctly aligned in memory", + "Unit attention received on another command causes retry", + "Driver protocol error" +}; + +/* + * NOTE: these tables are used by the smfd, tpsc, and dksc drivers, + * and will probably be used by other SCSI drivers in the future. + * That is why they are now in scsi.c, even though not referenced here. + */ +char *scsi_key_msgtab[SC_NUMSENSE] = { + "No sense", /* 0x0 */ + "Recovered Error", /* 0x1 */ + "Device not ready", /* 0x2 */ + "Media error", /* 0x3 */ + "Device hardware error", /* 0x4 */ + "Illegal request", /* 0x5 */ + "Unit Attention", /* 0x6 */ + "Data protect error", /* 0x7 */ + "Unexpected blank media", /* 0x8 */ + "Vendor Unique error", /* 0x9 */ + "Copy Aborted", /* 0xa */ + "Aborted command", /* 0xb */ + "Search data successful", /* 0xc */ + "Volume overflow", /* 0xd */ + "Reserved (0xE)", /* 0xe */ + "Reserved (0xF)", /* 0xf */ +}; + +/* + * Additional Sense Qualifier message table. + * There is no table in the PROM. + */ +char *scsi_addit_msgtab[SC_NUMADDSENSE] = { + NULL, /* 0x00 */ + "No index/sector signal", /* 0x01 */ + "No seek complete", /* 0x02 */ + "Write fault", /* 0x03 */ + "Not ready to perform command", /* 0x04 */ + "Unit does not respond to selection", /* 0x05 */ + "No reference position", /* 0x06 */ + "Multiple drives selected", /* 0x07 */ + "LUN communication error", /* 0x08 */ + "Track error", /* 0x09 */ + "Error log overflow", /* 0x0a */ + NULL, /* 0x0b */ + "Write error", /* 0x0c */ + NULL, /* 0x0d */ + NULL, /* 0x0e */ + NULL, /* 0x0f */ + "ID CRC or ECC error", /* 0x10 */ + "Unrecovered data block read error", /* 0x11 */ + "No addr mark found in ID field", /* 0x12 */ + "No addr mark found in Data field", /* 0x13 */ + "No record found", /* 0x14 */ + "Seek position error", /* 0x15 */ + "Data sync mark error", /* 0x16 */ + "Read data recovered with retries", /* 0x17 */ + "Read data recovered with ECC", /* 0x18 */ + "Defect list error", /* 0x19 */ + "Parameter overrun", /* 0x1a */ + "Synchronous transfer error", /* 0x1b */ + "Defect list not found", /* 0x1c */ + "Compare error", /* 0x1d */ + "Recovered ID with ECC", /* 0x1e */ + NULL, /* 0x1f */ + "Invalid command code", /* 0x20 */ + "Illegal logical block address", /* 0x21 */ + "Illegal function", /* 0x22 */ + NULL, /* 0x23 */ + "Illegal field in CDB", /* 0x24 */ + "Invalid LUN", /* 0x25 */ + "Invalid field in parameter list", /* 0x26 */ + "Media write protected", /* 0x27 */ + "Media change", /* 0x28 */ + "Device reset", /* 0x29 */ + "Log parameters changed", /* 0x2a */ + "Copy requires disconnect", /* 0x2b */ + "Command sequence error", /* 0x2c */ + "Update in place error", /* 0x2d */ + NULL, /* 0x2e */ + "Tagged commands cleared", /* 0x2f */ + "Incompatible media", /* 0x30 */ + "Media format corrupted", /* 0x31 */ + "No defect spare location available", /* 0x32 */ + "Media length error", /* 0x33 (spec'ed as tape only) */ + NULL, /* 0x34 */ + NULL, /* 0x35 */ + "Toner/ink error", /* 0x36 */ + "Parameter rounded", /* 0x37 */ + NULL, /* 0x38 */ + "Saved parameters not supported", /* 0x39 */ + "Medium not present", /* 0x3a */ + "Forms error", /* 0x3b */ + NULL, /* 0x3c */ + "Invalid ID msg", /* 0x3d */ + "Self config in progress", /* 0x3e */ + "Device config has changed", /* 0x3f */ + "RAM failure", /* 0x40 */ + "Data path diagnostic failure", /* 0x41 */ + "Power on diagnostic failure", /* 0x42 */ + "Message reject error", /* 0x43 */ + "Internal controller error", /* 0x44 */ + "Select/Reselect failed", /* 0x45 */ + "Soft reset failure", /* 0x46 */ + "SCSI interface parity error", /* 0x47 */ + "Initiator detected error", /* 0x48 */ + "Inappropriate/Illegal message", /* 0x49 */ + "Command phase error", /* 0x4a */ + "Data phase error", /* 0x4b */ + "Failed self configuration", /* 0x4c */ + NULL, /* 0x4d */ + "Overlapped cmds attempted", /* 0x4e */ + NULL, /* 0x4f */ + NULL, /* (tape only) 0x50 */ + NULL, /* (tape only) 0x51 */ + NULL, /* (tape only) 0x52 */ + "Media load/unload failure", /* 0x53 */ + NULL, /* 0x54 */ + NULL, /* 0x55 */ + NULL, /* 0x56 */ + "Unable to read table of contents", /* 0x57 */ + "Generation (optical device) bad", /* 0x58 */ + "Updated block read (optical device)", /* 0x59 */ + "Operator request or state change", /* 0x5a */ + "Logging exception", /* 0x5a */ + "RPL status change", /* 0x5c */ + "Self Diagnostics predict unit will fail soon", /* 0x5d */ + NULL, /* 0x5e */ + NULL, /* 0x5f */ + "Lamp failure", /* 0x60 */ + "Video acquisition error/focus problem", /* 0x61 */ + "Scan head positioning error", /* 0x62 */ + "End of user area on track", /* 0x63 */ + "Illegal mode for this track", /* 0x64 */ + NULL, /* 0x65 */ + NULL, /* 0x66 */ + NULL, /* 0x67 */ + NULL, /* 0x68 */ + NULL, /* 0x69 */ + NULL, /* 0x6a */ + NULL, /* 0x6b */ + NULL, /* 0x6c */ + NULL, /* 0x6d */ + NULL, /* 0x6e */ + NULL, /* 0x6f */ + "Decompression error", /* 0x70 (DAT only; may be in scsi3) */ +}; + +/* + * The scsi_hwgraph_lock is necessary to prevent graph deletes during + * critical portions of code execution. + */ +struct rw_semaphore scsi_hwgraph_lock; + + +/* + * Add a SCSI controller. + */ +vertex_hdl_t +scsi_ctlr_vertex_add(struct pci_dev *pci, int channel) +{ + vertex_hdl_t ctlr_vhdl; + scsi_ctlr_info_t *ctlrinfo; + char slotname[sizeof("pci00.00.0-0")]; + + scsi_ctlr_vertex_sprintf(slotname, pci, channel); + + ctlr_vhdl = devfs_mk_dir(devfs_xscsi, slotname, NULL); + if (ctlr_vhdl == NULL) + return NULL; + + ctlrinfo = kmem_zalloc(sizeof(*ctlrinfo), KM_SLEEP); + SCI_CTLR_VHDL(ctlrinfo) = ctlr_vhdl; + SCI_PCI(ctlrinfo) = pci; + devfs_set_info(ctlr_vhdl, ctlrinfo); + + return ctlr_vhdl; +} + +#ifdef CONFIG_PROC_FS +void +scsi_ctlr_proc_add(struct pci_dev *pci, get_info_t *get_info) +{ + create_proc_info_entry(pci->slot_name, 0, 0, get_info); +} +#endif + +/* + * Check if target vertex already exists. + */ +vertex_hdl_t +scsi_targ_vertex_exist(vertex_hdl_t ctlr_vhdl, + targ_t targ) +{ + char name[sizeof("target") + 3]; + + sprintf(name, "%s%d", "target", (int) targ & 0xff); + + return devfs_find_handle(ctlr_vhdl, name, 0, 0, 0, 0); +} + +vertex_hdl_t +scsi_node_port_vertex_exist(vertex_hdl_t ctlr_vhdl, uint64_t node, uint64_t port) +{ + char nodename[sizeof("node") + 16]; + char portname[sizeof("port") + 16]; + vertex_hdl_t targ_vhdl; + + sprintf(nodename, "%s%Lx", "node", (unsigned long long) node); + sprintf(portname, "%s%Lx", "port", (unsigned long long) port); + + targ_vhdl = devfs_find_handle(ctlr_vhdl, nodename, 0, 0, 0, 0); + if (targ_vhdl == NULL) + return NULL; + + targ_vhdl = devfs_find_handle(targ_vhdl, portname, 0, 0, 0, 0); + + return targ_vhdl; +} + +/* + * Remove the target vertex corresponding to the given unit number. + */ +void +scsi_targ_vertex_remove(vertex_hdl_t ctlr_vhdl, + targ_t targ) +{ + vertex_hdl_t targ_vhdl; + scsi_targ_info_t *targinfo; + + targ_vhdl = scsi_targ_vertex_exist(ctlr_vhdl, targ); + if (targ_vhdl != GRAPH_VERTEX_NONE) { + targinfo = devfs_get_info(targ_vhdl); + if (!targinfo) + return; + devfs_unregister(targ_vhdl); + kmem_cache_free(scsi_targ_cache, targinfo); + } +} + +/* + * Remove node vertex if warranted. + */ +void +scsi_node_vertex_remove(vertex_hdl_t ctlr_vhdl, uint64_t node) +{ + char nodename[sizeof("node") + 16]; + vertex_hdl_t port_vhdl, node_vhdl; + + sprintf(nodename, "node%Lx", (unsigned long long) node); + + node_vhdl = devfs_find_handle(ctlr_vhdl, nodename, 0, 0, 0, 0); + if (node_vhdl == NULL) + return; + + port_vhdl = devfs_get_first_child(node_vhdl); + /* check for port vertex */ + if (port_vhdl == NULL) + devfs_unregister(node_vhdl); + return; +} + +/* + * Remove the port vertex corresponding to the given port number + * Also remove node vertex if warranted. + */ +void +scsi_node_port_vertex_remove(vertex_hdl_t ctlr_vhdl, uint64_t node, uint64_t port) +{ + vertex_hdl_t targ_vhdl; + scsi_targ_info_t *targinfo; + + targ_vhdl = scsi_node_port_vertex_exist(ctlr_vhdl, node, port); + if (targ_vhdl != GRAPH_VERTEX_NONE) { + targinfo = devfs_get_info(targ_vhdl); + if (!targinfo) + return; + devfs_unregister(targ_vhdl); + kmem_cache_free(scsi_targ_cache, targinfo); + } + + scsi_node_vertex_remove(ctlr_vhdl, node); +} + + +/* + * Add a target vertex. + */ +vertex_hdl_t +scsi_targ_vertex_add(vertex_hdl_t ctlr_vhdl, + targ_t targ) +{ + vertex_hdl_t targ_vhdl; + scsi_targ_info_t *targinfo; + char name[sizeof("target") + 3]; + + targ_vhdl = scsi_targ_vertex_exist(ctlr_vhdl, targ); + if (targ_vhdl != GRAPH_VERTEX_NONE) + return targ_vhdl; + + targinfo = kmem_cache_zalloc(scsi_targ_cache, GFP_KERNEL); + if (targinfo == NULL) + return NULL; + + sprintf(name, "%s%d", "target", (int) targ & 0xff); + targ_vhdl = devfs_mk_dir(ctlr_vhdl, name, NULL); + if (targ_vhdl == NULL) { + kmem_cache_free(scsi_targ_cache, targinfo); + return NULL; + } + + STI_TARG_VHDL(targinfo) = targ_vhdl; + STI_CTLR_INFO(targinfo) = devfs_get_info(ctlr_vhdl); + STI_TARG(targinfo) = targ; + devfs_set_info(targ_vhdl, targinfo); + + return targ_vhdl; +} + + +/* + * Add node/port vertices to the graph and put the info + * associated with them. + */ +vertex_hdl_t +scsi_node_port_vertex_add(vertex_hdl_t ctlr_vhdl, uint64_t node, uint64_t port) +{ + scsi_targ_info_t *targinfo; + char nodename[sizeof("node") + 16]; + char portname[sizeof("port") + 16]; + vertex_hdl_t targ_vhdl; + + targ_vhdl = scsi_node_port_vertex_exist(ctlr_vhdl, node, port); + if (targ_vhdl != GRAPH_VERTEX_NONE) + return targ_vhdl; + + sprintf(nodename, "node%Lx", (unsigned long long) node); + sprintf(portname, "port%Lx", (unsigned long long) port); + + targinfo = kmem_cache_zalloc(scsi_targ_cache, GFP_KERNEL); + if (targinfo == NULL) + return NULL; + + targ_vhdl = devfs_get_handle(ctlr_vhdl, nodename, 0, 0, 0, 0); + if (targ_vhdl == NULL) + targ_vhdl = devfs_mk_dir(ctlr_vhdl, nodename, NULL); + if (targ_vhdl == NULL) + goto alloc_failure; + + targ_vhdl = devfs_mk_dir(targ_vhdl, portname, NULL); + if (targ_vhdl == NULL) + goto alloc_failure; + + STI_TARG_VHDL(targinfo) = targ_vhdl; + STI_CTLR_INFO(targinfo) = devfs_get_info(ctlr_vhdl); + STI_NODE(targinfo) = node; + STI_PORT(targinfo) = port; + devfs_set_info(targ_vhdl, targinfo); + return targ_vhdl; + +alloc_failure: + kmem_cache_free(scsi_targ_cache, targinfo); + return NULL; +} + + +/* + * check if lun vertex already exists and return it if so + */ +vertex_hdl_t +scsi_lun_vertex_exist(vertex_hdl_t targ_vhdl, + lun_t lun) +{ + char name[sizeof("lun") + 5]; + + sprintf(name, "%s%d", "lun", (int) lun & 0xffff); + + return devfs_find_handle(targ_vhdl, name, 0, 0, 0, 0); +} + + +void +scsi_lun_vertex_remove(vertex_hdl_t targ_vhdl, + targ_t lun) +{ + vertex_hdl_t lun_vhdl; + scsi_lun_info_t *luninfo; + + lun_vhdl = scsi_lun_vertex_exist(targ_vhdl, lun); + if (lun_vhdl != GRAPH_VERTEX_NONE) { + luninfo = devfs_get_info(lun_vhdl); + scsi_dev_remove(lun_vhdl); + fo_scsi_lun_remove(lun_vhdl); + dksc_disk_remove(lun_vhdl); + devfs_unregister(lun_vhdl); + kmem_cache_free(scsi_lun_cache, luninfo); + } +} + +/* + * add a lun vertex to the graph and put the info + * associated with it + */ +vertex_hdl_t +scsi_lun_vertex_add(vertex_hdl_t targ_vhdl, + lun_t lun) +{ + vertex_hdl_t lun_vhdl; + scsi_lun_info_t *luninfo; + scsi_targ_info_t *targinfo = devfs_get_info(targ_vhdl); + char name[sizeof("lun") + 5]; + + lun_vhdl = scsi_lun_vertex_exist(targ_vhdl, lun); + if (lun_vhdl != GRAPH_VERTEX_NONE) + return lun_vhdl; + + luninfo = kmem_cache_zalloc(scsi_lun_cache, GFP_KERNEL); + if (luninfo == NULL) + return NULL; + + sprintf(name, "%s%d", "lun", (int) lun & 0xffff); + lun_vhdl = devfs_mk_dir(targ_vhdl, name, luninfo); + if (lun_vhdl == NULL) { + kmem_cache_free(scsi_lun_cache, luninfo); + return NULL; + } + + SLI_TARG_INFO(luninfo) = targinfo; + SLI_LUN(luninfo) = lun; + SLI_LUN_VHDL(luninfo) = lun_vhdl; + + return lun_vhdl; +} + + +/* + * Some devices lie about whether they support multi-LUNs. Exception + * those cases + */ +static int +scsi_device_is_multilun(u_char *inv) +{ + single_inq_str_t p; + + if(inv[8] == 0) return 0; /* hack for bug 564484; + insite returns no data on lun1-7, but adapter drivers + forget to check for this */ + for (p = multilun_exc_inq_strings; p->str; ++p) { + if (strncmp((char *)&inv[p->offset], p->str, strlen(p->str)) == 0) + return(0); + } + return(1); +} + + +static void +scsi_disk_update(vertex_hdl_t lun_vhdl) +{ + if (!dksc_disk_add(lun_vhdl)) + printk("failed to add disk!\n"); +} + +static void +scsi_mm_update(vertex_hdl_t lun_vhdl) +{ + if (!mmsc_disk_add(lun_vhdl)) + printk("Failed to add cdrom 0x%p !\n", (void *) lun_vhdl); +} + + +static vertex_hdl_t +scsi_dev_add(vertex_hdl_t lun_vhdl) +{ + vertex_hdl_t scsi_vhdl; + scsi_dev_info_t *devinfo; + scsi_lun_info_t *luninfo; + + scsi_vhdl = devfs_find_handle(lun_vhdl, "ds", 0, 0, 0, 0); + if (scsi_vhdl) + return scsi_vhdl; + + devinfo = kmem_cache_zalloc(scsi_dev_cache, GFP_KERNEL); + if (devinfo == NULL) + return NULL; + + scsi_vhdl = devfs_register(lun_vhdl, "ds", DEVFS_FL_DEFAULT, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &xscsids_ops, devinfo); + if (scsi_vhdl == NULL) + goto out; + + luninfo = devfs_get_info(lun_vhdl); + SDEVI_LUN_INFO(devinfo) = luninfo; + return scsi_vhdl; + +out: + kmem_cache_free(scsi_dev_cache, devinfo); + return NULL; +} + +static void +scsi_dev_remove(vertex_hdl_t lun_vhdl) +{ + vertex_hdl_t scsi_vhdl; + scsi_dev_info_t *devinfo; + + scsi_vhdl = devfs_find_handle(lun_vhdl, "ds", 0, 0, 0, 0); + if (!scsi_vhdl) + return; + + devinfo = devfs_get_info(scsi_vhdl); + devfs_unregister(scsi_vhdl); + kmem_cache_free(scsi_dev_cache, devinfo); +} + + +/* + * creates a new vertex corr. to this scsi device in the + * hardware graph attached to the vertex corr. to the vhdl + * + */ +void +scsi_device_update(u_char *inq, vertex_hdl_t lun_vhdl) +{ + vertex_hdl_t scsi_vhdl; + scsi_lun_info_t *lun_info; + int targ, lun; + uint64_t node, port; + scsi_ctlr_info_t *ctlr_info; + + lun_info = devfs_get_info(lun_vhdl); + lun_info->sli_device_type = inq[0] & 0x1F; + strncpy(lun_info->sli_vendor_id, &inq[8], SLI_VENDOR_ID_LEN); + strncpy(lun_info->sli_product_id, &inq[16], SLI_PRODUCT_ID_LEN); + + targ = SLI_TARG(lun_info); + lun = SLI_LUN(lun_info); + node = SLI_NODE(lun_info); + port = SLI_PORT(lun_info); + ctlr_info = SLI_CTLR_INFO(lun_info); + + /* + * If LUN > 0 and the device is lying about multi-lunned support, bail out. + */ + if (lun > 0 && !scsi_device_is_multilun(inq)) + return; + + scsi_vhdl = scsi_dev_add(lun_vhdl); + + fo_scsi_device_update(inq, lun_vhdl); + + /* + * Check the peripheral qualifier - non-zero means LUN is + * either not supported or is not currently attached. Do + * not attach to the respective driver. + * Following a tresspass, a RAID lun that was formerly + * accessible will be inaccessible, but the device will + * still be attached to dksc; it will just give errors when + * I/O to it is attempted. + */ + if ((inq[0] & 0x60) && !(inq[0] & 0x80)) { + /* Irix code removes from inventory. + * At some future point, we should detach from the drivers + * if already attached. For now, we just don't attach. + */ + return; + } + + switch (inq[0] & 0x1F) + { + case 0: /* disk */ + /* + * attach to disk driver (dksc) + */ + scsi_disk_update(lun_vhdl); + break; + +#if NOTYET + case 1: /* sequential == tape */ + + if ( scsitype = tstapetype( (ts_inquiry_t *)inv, NULL ) ) { + prefix = TS_PREFIX; + } else { + scsitype = tpsctapetype((ct_g0inq_data_t *)inv, 0); + prefix = TPSC_PREFIX; + } + which = "tape"; + sprintf(extra=scsi_dev_loc_str, " type %d", scsitype); + + /* + * Check the type 1 registration to determine whether + * this device needs to be attached to a 3rd party + * driver. If not, then by default we'll attach it + * to the tape driver (tpsc.c). + */ + if (driver_info) { + /* + * Mark this device as a tape + */ + device_driver_admin_info_set(driver_info->sd_driver_prefix, TAPE_IDENT, TAPE_IDENT); + known_vhdl = scsi_device_register(lun_vhdl, inv, driver_info->sd_pathname_prefix); + if (!scsi_device_is_attached(known_vhdl)) + scsi_device_attach(known_vhdl, driver_info->sd_driver_prefix); + } + else { + /* + * add the vertex corresponding to the new + * scsi tape to the hardware graph + */ + known_vhdl = scsi_device_register(lun_vhdl, inv, EDGE_LBL_TAPE); + if (hwgraph_traverse(known_vhdl, + TPSC_DEFAULT"/"EDGE_LBL_CHAR, + &tmp_vhdl) != GRAPH_SUCCESS) { + scsi_device_attach(known_vhdl, prefix); + inv_vhdl = known_vhdl; + inv_class = INV_TAPE; + inv_type = INV_SCSIQIC; + inv_ctlr = eadap; + inv_unit = targ; + inv_state = scsitype; + } else + hwgraph_vertex_unref(tmp_vhdl); + } + break; +#endif + + case 5: /* CDROM */ + /* + * attach to the mm (CDROM type device's) driver (mmsc.c). + */ + scsi_mm_update(lun_vhdl); + break; + + case 7: /* Optical Disk */ + /* + * attach to the disk driver (dksc.c). + */ + scsi_disk_update(lun_vhdl); + break; + + default: + /* + * Currently no drivers for these devices. + */ + break; + } +} + + +void +scsi_bus_create(vertex_hdl_t ctlr_vhdl) +{ + devfs_register(ctlr_vhdl, "bus", DEVFS_FL_DEFAULT, + 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &scsiha_ops, NULL); +} + +/* + * given the controller vertex handle , target & the lun get the + * lun vertex handle + */ +vertex_hdl_t +scsi_lun_vhdl_get(vertex_hdl_t ctlr_vhdl, + targ_t targ, + lun_t lun) +{ + vertex_hdl_t tt, ll; + + tt = scsi_targ_vertex_exist(ctlr_vhdl, targ); + if (tt != GRAPH_VERTEX_NONE) { + ll = scsi_lun_vertex_exist(tt, lun); + if (ll != GRAPH_VERTEX_NONE) + return ll; + } + return GRAPH_VERTEX_NONE; +} + +/* + * given the controller vertex handle, FC node & port, and the lun, + * get the lun vertex handle + */ +vertex_hdl_t +scsi_fabric_lun_vhdl_get(vertex_hdl_t ctlr_vhdl, uint64_t node, uint64_t port, lun_t lun) +{ + vertex_hdl_t tt, ll; + + tt = scsi_node_port_vertex_exist(ctlr_vhdl, node, port); + if (tt != GRAPH_VERTEX_NONE) { + ll = scsi_lun_vertex_exist(tt, lun); + if (ll != GRAPH_VERTEX_NONE) + return ll; + } + return GRAPH_VERTEX_NONE; +} + + +#if 0 +struct double_uint { + uint32_t low; + uint32_t high; +}; +uint64_t +__ucmpdi2 (struct double_uint au, struct double_uint bu) +{ + if (au.high < bu.high) + return 0; + else if (au.high > bu.high) + return 2; + if (au.low < bu.low) + return 0; + else if (au.low > bu.low) + return 2; + return 1; +} +#endif + + +uint64_t +fc_short_portname(uint64_t node, uint64_t port) +{ + /* + * IEEE names look something like this: + * 1000uuuuuuuuuuuu + * 1 is the NAA identifier, i.e., IEEE + * 000 is a reserved "must be zero" field + * uuuuuuuuuuuu is the ULA, or UNIVERSAL LAN ADDRESS + * + * IEEE extended names look something like this: + * 2vvvuuuuuuuuuuuu + * 2 is the NAA identifier, i.e., IEEE extended + * vvv is a vendor specified EXTENSION to the lower 48 bits + * uuuuuuuuuuuu is the ULA, or UNIVERSAL LAN ADDRESS + * + * The ULA has the following format: + * VVVVVVxxxxxx + * VVVVVV is the IEEE company id + * xxxxxx is a unique value assigned by that company + * + * Type 1 names are commonly used as a node name. + * Type 2 names are used as both node and port names. + * + * xxxxxx is frequently used as a port or node serial number + * vvv is frequently used as a port's port number + * + * However, some vendors choose to use the "vvv" for other purposes + * such as relating one node of a raid to another. FC-PH-3 does not + * specify that "vvv" be used as a port number, only that it is + * vendor specified. FC-PH did specify that "vvv" was a port number. + * + * So, what we do for type 1 and 2, IEEE and IEEE extended names to + * determine a short port name is to look for variation in the port + * name from the node name. If the only variation between port and + * node name is within the "vvv" field (ignoring NAA), it is presumed + * that this is the port number and is returned as such, using bits + * 59-56 as the least significant bits of the port number and bits + * 55-48 as the most significant bits. This becomes the short + * portname. This funny munging conforms to the defacto standard + * set by Seagate with their FC disk drives. + * + * If the "vvv" portion of the node and port names is the same + * and there is variation in the "uuuuuuuuuuuu" field, the short + * port name is calculated by subtracting the node name from the + * port name and returning 25 bits of difference. Hopefully this + * will be a small number reflecting the port number. + * + * If there is variation in both the "vvv" and "uuuuuuuuuuuu" fields, + * well, we punt and return the portname. This results in a long + * portname. One must draw the line somewhere! + * + * If the Node and Port names are IEEE Registered Names that begin with + * a 5, and the vendor is IBM, the port number is 3 bits wide in bits + * 22-24. + * + * If this isn't an IBM target, then we're assuming that the + * "serial number" portion of the port name is typically >= the node + * name, the difference reflecting the port number. Presuming that the + * upper 28 bits are the same (vendor information), we subtract the + * port name from the node name and return 37 bits of result. The + * upper bit is the "sign" bit. + */ + + switch ((uint) (node >> 60)) + { + case 1: /* common usage as an IP-compatible node name */ + if (node == port) + return 0; + break; + + case 2: /* variation in either 59-48 or 23-0 to reflect port number */ + /* + * 63-60, 47-0 same in node and port; + * 59-48 is 0 in node, port # in port + */ + if (node == (port & ~((uint64_t) 0xFFF << 48))) + return ((port >> 56) & 0xF) | ((port >> 44) & 0xFF0); + + /* + * 63-24 same in node and port; + * 23-0 of port minus 23-0 of node is effective port number + */ + if ((node & (0xFFFFFFFFFF << 24)) == (port & (0xFFFFFFFFFF << 24))) + return (port - node) & 0x1FFFFFF; + break; + + case 5: + switch ((uint) ((node >> 36) & 0xFFFFFF)) + { + case 0x006094: /* IBM disks, e.g., 5006094670008457 */ + if (node == (port & ~((uint64_t) 0x3 << 22))) + return (port >> 22) & 0x3; + break; + + default: + if (((node >> 36) & 0xfffffff) == ((port >> 36) & 0xfffffff)) + return (port - node) & 0x1fffffffff; + break; + } + break; + } + return port; +} + +void +xscsi_notify(void) +{ + dksc_notify(); + mmsc_notify(); +} + +#ifdef CONFIG_KDB +#undef printf +#include +#include +static int +scsi(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + struct scsi_request *req; + long offset=0; + int nextarg; + unsigned long addr; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + req = (struct scsi_request *)addr; + + kdb_printf("SCSI request @ 0x%p\n", (void *) req); + if (req == NULL) + return 0; + kdb_printf("lun_vhdl %lx, ctlr/targ/lun/tag %d/%d/%d/%d\n", + (unsigned long) req->sr_lun_vhdl, + req->sr_ctlr, req->sr_target, (int)req->sr_lun, req->sr_tag); + kdb_printf("command:"); + if (req == NULL) + kdb_printf(" NULL"); + else + for (i = 0; i < req->sr_cmdlen; i++) + kdb_printf(" 0x%x", req->sr_command[i]); + kdb_printf("\nflags 0x%x, timeout %d HZ (%d seconds)\n", req->sr_flags, + req->sr_timeout, req->sr_timeout/HZ); + kdb_printf("buffer 0x%p, buflen %d (0x%x), sense 0x%p, senselen %d\n", + (void *) req->sr_buffer, req->sr_buflen, req->sr_buflen, + (void *) req->sr_sense, req->sr_senselen); + kdb_printf("notify 0x%p, sr_dev 0x%p, sr_ha 0x%p, sr_spare 0x%Lx\n", + (void *) req->sr_notify, req->sr_dev, req->sr_ha, + (unsigned long long) req->sr_spare); + kdb_printf("status %d, scsi status 0x%x, ha_flags 0x%x, sensegotten %d, " + "resid %d (0x%x)\n", req->sr_status, req->sr_scsi_status, + req->sr_ha_flags, req->sr_sensegotten, req->sr_resid, req->sr_resid); + return 0; +} + +static void +xscsidbg_init(void) +{ + kdb_register("xscsi", scsi, "", "dump scsi_request_t", 0); +} +#endif diff -Nur linux-2.4.19/drivers/xscsi/xscsi_syms.c linux-2.4.19-sgi211r3/drivers/xscsi/xscsi_syms.c --- linux-2.4.19/drivers/xscsi/xscsi_syms.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/xscsi_syms.c Fri Jan 3 08:28:29 2003 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include + +#include "xscsi.h" + +EXPORT_SYMBOL(scsi_key_msgtab); +EXPORT_SYMBOL(scsi_addit_msgtab); +EXPORT_SYMBOL(scsi_adaperrs_tab); +EXPORT_SYMBOL(scsi_hwgraph_lock); + +EXPORT_SYMBOL(scsi_device_update); +EXPORT_SYMBOL(scsi_ctlr_vertex_add); +EXPORT_SYMBOL(scsi_node_port_vertex_exist); +EXPORT_SYMBOL(scsi_node_port_vertex_add); +EXPORT_SYMBOL(scsi_node_port_vertex_remove); +EXPORT_SYMBOL(scsi_targ_vertex_exist); +EXPORT_SYMBOL(scsi_targ_vertex_add); +EXPORT_SYMBOL(scsi_targ_vertex_remove); +EXPORT_SYMBOL(scsi_lun_vertex_exist); +EXPORT_SYMBOL(scsi_lun_vertex_add); +EXPORT_SYMBOL(scsi_lun_vertex_remove); +EXPORT_SYMBOL(scsi_bus_create); +EXPORT_SYMBOL(scsi_lun_vhdl_get); +EXPORT_SYMBOL(scsi_fabric_lun_vhdl_get); +EXPORT_SYMBOL(fc_short_portname); + +EXPORT_SYMBOL(xscsi_notify); diff -Nur linux-2.4.19/drivers/xscsi/xscsids.c linux-2.4.19-sgi211r3/drivers/xscsi/xscsids.c --- linux-2.4.19/drivers/xscsi/xscsids.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/xscsids.c Fri Jan 3 08:28:29 2003 @@ -0,0 +1,421 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include + +#include + +#include "xscsi.h" +#include "xscsids.h" +#include "alenlist.h" + +#define DS_SENSELEN 128 + +#define DS_SUPPORT_FLAGS \ + (DSRQ_SENSE | DSRQ_IOV | DSRQ_READ | DSRQ_WRITE | \ + DSRQ_CTRL1 | DSRQ_CTRL2 | DSRQ_SYNXFR | DSRQ_ASYNXFR) +#define DS_DEFAULT_FLAGS \ + (DSRQ_DISC | DSRQ_SELATN) + +static int +dsopen(struct inode *dsinode, struct file *dsfile) +{ + devfs_handle_t de; + scsi_dev_info_t *sdevi; + int ret; + + SCSI_HWG_ACCESS(); + de = devfs_get_handle_from_inode(dsinode); + sdevi = scsi_dev_info_get(de); + + if (sdevi == NULL) { + SCSI_HWG_UNACCESS(); + return -ENXIO; + } + ret = SDEVI_ALLOC(sdevi)(SDEVI_LUN_VHDL(sdevi), 1, NULL); + if (ret != SCSIALLOCOK) { + printk("ds: alloc failed\n"); + ret = ret ? -ret : -ENODEV; + } + SCSI_HWG_UNACCESS(); + + return ret; +} + +static int +dsclose(struct inode *dsinode, struct file *dsfile) +{ + devfs_handle_t de; + scsi_dev_info_t *sdevi; + + de = devfs_get_handle_from_inode(dsinode); + sdevi = scsi_dev_info_get(de); + SDEVI_FREE(sdevi)(SDEVI_LUN_VHDL(sdevi), NULL); + + return 0; +} + +static unsigned short +hosterr_to_ds(unsigned int srst) +{ + switch(srst) { + case SC_TIMEOUT: + return DSRT_TIMEOUT; + case SC_CMDTIME: + return DSRT_TIMEOUT; + case SC_HARDERR: + return DSRT_AGAIN; + case SC_PARITY: + return DSRT_PARITY; + case SC_MEMERR: + return DSRT_MEMORY; + default: + return DSRT_HOST; + } +} + +static void +ds_enter_cb(scsi_request_t *sp) +{ + struct semaphore *wait; + + wait = sp->sr_dev; + + up(wait); +} + +static int +ds_enter(vertex_hdl_t dev, struct dsreq *dp) +{ + unsigned char *sensedata; + unsigned char cmddata[SC_CLASS4_SZ]; + int cmdlen; + scsi_request_t *sp; + int group; + int rw; + int err = 0,mapping=0; + struct kiobuf *iobuf; + scsi_dev_info_t *sdevi; + struct alenlist_s alenlist; + DECLARE_MUTEX_LOCKED(wait); + + sdevi = scsi_dev_info_get(dev); + + dp->ds_flags |= DS_DEFAULT_FLAGS; + + if (dp->ds_flags & ~(DS_DEFAULT_FLAGS | DS_SUPPORT_FLAGS | + DSRQ_TRACE | DSRQ_PRINT)) { + dp->ds_ret = DSRT_UNIMPL; + return -ENXIO; + } + + if (CMDLEN(dp) > sizeof(cmddata)) + return -EINVAL; + + if (SENSELEN(dp) > DS_SENSELEN) + return -EINVAL; + + if (copy_from_user(cmddata, CMDBUF(dp), CMDLEN(dp))) + return -EFAULT; + + /* XXX - Has to be cache aligned for SNIA. */ + sensedata = kmalloc(DS_SENSELEN, GFP_KERNEL); + if (!sensedata) + return -ENOMEM; + + if (copy_from_user(sensedata, SENSEBUF(dp), SENSELEN(dp))) { + err = -EFAULT; + goto out1; + } + + group = (cmddata[0] & 0xe0) >> 5; + + switch (group) { + case 0: + cmdlen = 6; + break; + case 1: + case 2: + cmdlen = 10; + break; + case 5: + cmdlen = 12; + break; + default: + err = -EINVAL; + goto out1; + } + + rw = (dp->ds_flags & DSRQ_READ) ? READ : WRITE; + + if ((dp->ds_flags & DSRQ_IOV) || (DATALEN(dp) > 0)) + mapping = 1; + + if (mapping) { + err = alloc_kiovec(1, &iobuf); + if (err) + goto out1; + if (dp->ds_flags & DSRQ_IOV) { + dsiovec_t iov; + + if (copy_from_user(&iov, (void *) IOVBUF(dp), sizeof(iov))) { + err = -EFAULT; + goto out2; + } + if (iov.iov_len == 0) { + err = -EINVAL; + goto out2; + } + err = map_user_kiobuf(rw, iobuf, (unsigned long) iov.iov_base, + iov.iov_len); + if (err) + goto out2; + } + else { + err = map_user_kiobuf(rw, iobuf, (unsigned long) DATABUF(dp), + DATALEN(dp)); + if (err) + goto out2; + } + alenlist.maplist = iobuf->maplist; + alenlist.len = iobuf->length; + alenlist.pages = iobuf->nr_pages; + alenlist.offset = iobuf->offset; + alenlist.cursor.pos = 0; + alenlist.bhstart = NULL; + } + + sp = kmalloc(sizeof(scsi_request_t), GFP_KERNEL); + if (!sp) { + err = -ENOMEM; + goto out3; + } + memset(sp, 0, sizeof(scsi_request_t)); + if (rw == READ) + sp->sr_flags |= SRF_DIR_IN; + + if (dp->ds_flags & DSRQ_SYNXFR) + sp->sr_flags |= SRF_NEG_SYNC; + else if(dp->ds_flags & DSRQ_ASYNXFR) + sp->sr_flags |= SRF_NEG_ASYNC; + + sp->sr_flags |= SRF_ALENLIST | SRF_AEN_ACK; + sp->sr_ctlr = SDEVI_ADAP(sdevi); + sp->sr_target = SDEVI_TARG(sdevi); + sp->sr_lun = SDEVI_LUN(sdevi); + sp->sr_lun_vhdl = SDEVI_LUN_VHDL(sdevi); + sp->sr_sense = sensedata; + sp->sr_senselen = DS_SENSELEN; + sp->sr_command = cmddata; + sp->sr_cmdlen = cmdlen; + sp->sr_notify = ds_enter_cb; + sp->sr_timeout = ((999 + dp->ds_time)/1000) * HZ; + sp->sr_dev = &wait; + if (mapping) { + sp->sr_alenlist = &alenlist; + sp->sr_buflen = iobuf->length; + } + else { + sp->sr_alenlist = NULL; + sp->sr_buflen = 0; + } + + + (SDEVI_COMMAND(sdevi))(sp); + + down(&wait); + + __copy_to_user(CMDBUF(dp), cmddata, CMDLEN(dp)); + __copy_to_user(SENSEBUF(dp), sensedata, SENSELEN(dp)); + + CMDSENT(dp) = cmdlen; + if (mapping) + DATASENT(dp) = sp->sr_buflen - sp->sr_resid; + else + DATASENT(dp) = 0; + + if (sp->sr_status == SC_GOOD) { + if (sp->sr_sensegotten > 0) { + if (dp->ds_flags & DSRQ_SENSE) { + RET(dp) = DSRT_SENSE; + if (SENSELEN(dp) > sp->sr_sensegotten) + SENSELEN(dp) = sp->sr_sensegotten; + } else + RET(dp) = DSRT_HOST; + STATUS(dp) = ST_CHECK; + } else if (sp->sr_sensegotten == -1) { + RET(dp) = DSRT_NOSENSE; + STATUS(dp) = 0xff; + } else { + if (sp->sr_scsi_status != ST_GOOD) + RET(dp) = DSRT_HOST; + STATUS(dp) = sp->sr_scsi_status; + } + } else { + STATUS(dp) = 0xff; + RET(dp) = hosterr_to_ds(sp->sr_status); + } + + kfree(sp); +out3: + if (mapping) + unmap_kiobuf(iobuf); +out2: + if (mapping) + free_kiovec(1, &iobuf); +out1: + kfree(sensedata); + return err; +} + +static int +ds_abort(vertex_hdl_t dev, struct dsreq *dp) +{ + scsi_request_t *sp; + + sp = kmalloc(sizeof(scsi_request_t), GFP_KERNEL); + if (!sp) + return -ENOMEM; + memset(sp, 0, sizeof(scsi_request_t)); + + SDEVI_ABORT(dev)(sp); + + RET(dp) = hosterr_to_ds(sp->sr_status); + kfree(sp); + + return 0; +} + +static int +dsioctl(struct inode *dsinode, struct file *dsfile, unsigned int cmd, + unsigned long arg) +{ + devfs_handle_t dev; + scsi_dev_info_t *sdevi; + int err = 0; + + dev = devfs_get_handle_from_inode(dsinode); + sdevi = scsi_dev_info_get(dev); + + switch(cmd) { + case DS_GET: + { + scsi_target_info_t *info; + int flags = 0, status; + + info = (SDEVI_INQ(dev))(SDEVI_LUN_VHDL(sdevi)); + if (!info) + return 0; + + status = info->si_ha_status; + + if (status & SRH_CANTSYNC) + flags |= DSG_CANTSYNC; + if (status & SRH_SYNCXFR) + flags |= DSG_SYNCXFR; + if (status & SRH_TRIEDSYNC) + flags |= DSG_TRIEDSYNC; + if (status & SRH_BADSYNC) + flags |= DSG_BADSYNC; + if (status & SRH_NOADAPSYNC) + flags |= DSG_NOADAPSYNC; + if (status & SRH_WIDE) + flags |= DSG_WIDE; + if (status & SRH_DISC) + flags |= DSG_DISC; + if (status & SRH_TAGQ) + flags |= DSG_TAGQ; + + if (put_user(flags, (unsigned int *) arg)) + err = -EFAULT; + } + break; + case DS_CONF: + { + dsconf_t dsconf; + dsconf.dsc_flags = DS_SUPPORT_FLAGS; + dsconf.dsc_preset = DS_DEFAULT_FLAGS; + dsconf.dsc_bus = SDEVI_ADAP(scsi_dev_info_get(dev)); + /* unsupported fields */ + dsconf.dsc_imax = 0; + dsconf.dsc_lmax = 0; + dsconf.dsc_iomax = 0; + dsconf.dsc_biomax = 0; + if (copy_to_user((void *) arg, &dsconf, sizeof(dsconf))) + err = EFAULT; + } + break; + case DS_ENTER: + { + struct dsreq dsreq; + + if (copy_from_user(&dsreq, (void *) arg, sizeof(dsreq))) { + err = -EFAULT; + break; + } + + err = ds_enter(dev, &dsreq); + + __copy_to_user((void *) arg, &dsreq, sizeof(dsreq)); + } + break; + case DS_ABORT: + { + struct dsreq dsreq; + + if (copy_from_user(&dsreq, (void *) arg, sizeof(dsreq))) { + err = -EFAULT; + break; + } + + err = ds_abort(dev, &dsreq); + + __copy_to_user((void *) arg, &dsreq, sizeof(dsreq)); + } + break; + default: + err = -EINVAL; + } + + return err; +} + +struct file_operations xscsids_ops = { + ioctl: dsioctl, + open: dsopen, + release: dsclose +}; diff -Nur linux-2.4.19/drivers/xscsi/xscsids.h linux-2.4.19-sgi211r3/drivers/xscsi/xscsids.h --- linux-2.4.19/drivers/xscsi/xscsids.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/xscsids.h Fri Jan 3 08:28:29 2003 @@ -0,0 +1,315 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +#ifndef _XSCSI_DS_H +#define _XSCSI_DS_H + +#include + +/* + * These implementation constants are the only system-dependent + * things that should be in this file! + */ + +#define R_MAX 1 /* 1=>init role only, 2=>both roles */ +#define V_MAX 1 /* max number dma io vectors */ + +#define D(y,t) _IOWR('D',y,t) + +#define DS_ENTER D(101, struct dsreq) /* enter a request */ +#define DS_CANCEL D(102, struct dsreq) /* cancel a request */ +#define DS_POLL D(103, struct dsreq) /* sample async request */ +#define DS_CONTIN D(104, struct dsreq) /* continue a request */ +#define DS_SET D(106, int) /* set permanent flags (per device) */ +#define DS_CLEAR D(107, int) /* clear permanent flags */ +#define DS_GET D(108, int) /* get permanent flags (per device) */ +#define DS_CONF D(110, int) /* get flags supported by host */ +#define DS_ABORT D(111, int) /* send abort message to "idle" target. + Only useful if no commands active on the target; as it otherwise + delays until no commands are active. Commands like rewind immediate + and other commands with the immediate bit can be aborted in this + way */ +#define DS_MKALIAS D(112, int) + +/* flag values returned by DS_GET (for SGI, these may vary from system + * to system, as they are inherently system specific) */ +#define DSG_CANTSYNC 0x01 /* sync xfer negotiations attempted, but + * device doesn't support sync; BADSYNC will be set if the negotation + * itself also failed */ +#define DSG_SYNCXFR 0x02 /* sync xfer mode in effect; async if not set; + * async mode is the default for all devscsi devices; see also + * DSRQ_SYNXFR and DSRQ_ASYNXFR bits in ds_flags. */ +#define DSG_TRIEDSYNC 0x04 /* did sync negotations at some point. If + * DSG_CANTSYNC is not also set, the device supports sync mode. */ +#define DSG_BADSYNC 0x08 /* device doesn't handle sync negotations + * correctly; DSG_CANTSYNC will normally be set whenever this bit + * is set */ +#define DSG_NOADAPSYNC 0x10 /* scsi adapter doesn't handle sync + * negotations or system has been configured to not allow sync xfers + * on this target */ +#define DSG_WIDE 0x20 /* scsi adapter supports wide SCSI */ +#define DSG_DISC 0x40 /* scsi adapter supports disconnect and is configured + * for it */ +#define DSG_TAGQ 0x80 /* scsi adapter supports tagged queuing and is + * configured for it */ + +/* + * DEVSCSI dma scatter-gather control. + * Dma control is system-dependent; its implementation is optional + */ +typedef struct dsiovec { + caddr_t iov_base; /* i/o base */ + int iov_len; /* i/o length */ +} dsiovec_t; + +/* + * User DEVSCSI ioctl structure. + * This structure is passed and returned as the ioctl argument. + */ + +typedef struct dsreq { + +/* devscsi prefix */ + uint ds_flags; /* see flags defined below */ + uint ds_time; /* timeout in milliseconds */ + ulong ds_private; /* for private use by caller */ + +/* scsi request */ + caddr_t ds_cmdbuf; /* command buffer */ + uchar_t ds_cmdlen; /* command buffer length */ + caddr_t ds_databuf; /* data buffer start */ + uint ds_datalen; /* total data length */ + caddr_t ds_sensebuf; /* sense buffer */ + uchar_t ds_senselen; /* sense buffer length */ + +/* miscellaneous */ + dsiovec_t *ds_iovbuf; /* scatter-gather dma control */ + ushort ds_iovlen; /* length of scatter-gather */ + struct dsreq *ds_link; /* for linked requests */ + ushort ds_synch; /* synchronous xfer control */ + uchar_t ds_revcode; /* devscsi version code */ + +/* return portion */ + uchar_t ds_ret; /* devscsi return code */ + uchar_t ds_status; /* device status byte value */ + uchar_t ds_msg; /* device message byte value */ + uchar_t ds_cmdsent; /* actual length command */ + uint ds_datasent; /* actual length user data */ + uchar_t ds_sensesent; /* actual length sense data */ +} dsreq_t; + +/* + * DEVSCSI ds_flags option bits. + * These bits change the course of the devscsi bus transaction. + */ + +/* devscsi options */ +#define DSRQ_ASYNC 0x1 /* no (yes) sleep until request done */ +#define DSRQ_SENSE 0x2 /* yes (no) auto get sense on status */ +#define DSRQ_TARGET 0x4 /* target (initiator) role */ + +/* select options */ +#define DSRQ_SELATN 0x8 /* select with (without) atn */ +#define DSRQ_DISC 0x10 /* identify disconnect (not) allowed */ +#define DSRQ_SYNXFR 0x20 /* negotiate synchronous scsi xfer */ +#define DSRQ_ASYNXFR 0x200000 /* negotiate asynchronous scsi xfer (this + * is the default, and so is only needed if a transition back to + * async scsi is necessary after using DSRQ_SYNXFR) */ +#define DSRQ_SELMSG 0x40 /* send supplied (generate) message */ + +/* data transfer options */ +#define DSRQ_IOV 0x80 /* scatter-gather (not) specified */ +#define DSRQ_READ 0x100 /* input data from scsi bus */ +#define DSRQ_WRITE 0x200 /* output data to scsi bus */ +#define DSRQ_BUF 0x400 /* buffered (direct) data xfer */ + +/* progress/continuation callbacks */ +#define DSRQ_CALL 0x800 /* notify progress (completion-only) */ +#define DSRQ_ACKH 0x1000 /* hold (don't) ACK asserted */ +#define DSRQ_ATNH 0x2000 /* hold (don't) ATN asserted */ +#define DSRQ_ABORT 0x4000 /* abort msg until bus clear */ + +/* host options (likely non-portable) */ +#define DSRQ_TRACE 0x8000 /* trace (no) this request */ +#define DSRQ_PRINT 0x10000 /* print (no) this request */ +#define DSRQ_CTRL1 0x20000 /* request with host control bit 1 */ +#define DSRQ_CTRL2 0x40000 /* request with host control bit 2 */ + +/* additional flags */ +#define DSRQ_MIXRDWR 0x100000 /* request can both read and write */ +/* #define DSRQ_ASYNXFR 0x200000 : defined above; duplicated here + * so this value is shown as used in numeric sequence */ + + + +/* + * DEVSCSI ds_ret return codes. + * All error and 'abnormal' codes are non-zero; 0 is + * returned in ds_ret on success. Not all codes are returned + * by all implementations. + */ + +/* devscsi software returns */ +#define DSRT_DEVSCSI 0x47 /* general devscsi failure */ +#define DSRT_MULT 0x46 /* request rejected */ +#define DSRT_CANCEL 0x45 /* lower request cancelled */ +#define DSRT_REVCODE 0x44 /* software obsolete must recompile */ +#define DSRT_AGAIN 0x43 /* try again, recoverable bus error */ + +/* host scsi software returns */ +#define DSRT_HOST 0x37 /* general host failure */ +#define DSRT_NOSEL 0x36 /* no unit responded to select */ +#define DSRT_SHORT 0x35 /* incomplete xfer (not an error) */ +#define DSRT_OK 0x34 /* complete xfer w/ no error status */ +#define DSRT_SENSE 0x33 /* cmd w/ status, sense data gotten */ +#define DSRT_NOSENSE 0x32 /* cmd w/ status, error getting sense */ +#define DSRT_TIMEOUT 0x31 /* request idle longer than requested */ +#define DSRT_LONG 0x30 /* target overran data bounds */ + +/* protocol failures */ +#define DSRT_PROTO 0x27 /* misc. protocol failure */ +#define DSRT_EBSY 0x26 /* busy dropped unexpectedly */ +#define DSRT_REJECT 0x25 /* message reject */ +#define DSRT_PARITY 0x24 /* parity error on SCSI bus */ +#define DSRT_MEMORY 0x23 /* host memory error */ +#define DSRT_CMDO 0x22 /* error during command phase */ +#define DSRT_STAI 0x21 /* error during status phase */ +#define DSRT_UNIMPL 0x20 /* not implemented */ + + +/* + * SCSI device status byte codes returned in ds_status: + */ +#define STA_GOOD 0x00 /* scsi cmd finished normally */ +#define STA_CHECK 0x02 /* scsi cmd aborted, check */ +#define STA_BUSY 0x08 /* scsi cmd aborted, unit busy */ +#define STA_IGOOD 0x10 /* scsi cmd with link finished */ +#define STA_RESERV 0x18 /* scsi unit aborted, reserved */ + + +/* + * SCSI device message byte codes returned in ds_msg: + */ +#define MSG_COMPL 0x00 /* command complete */ +#define MSG_XMSG 0x01 /* extended message */ +#define MSG_SAVEP 0x02 /* save pointers */ +#define MSG_RESTP 0x03 /* restore pointers */ +#define MSG_DISC 0x04 /* disconnect */ +#define MSG_IERR 0x05 /* initiator error */ +#define MSG_ABORT 0x06 /* abort */ +#define MSG_REJECT 0x07 /* message reject */ +#define MSG_NOOP 0x08 /* no operation */ +#define MSG_MPARITY 0x09 /* message parity */ +#define MSG_LINK 0x0A /* linked command completed */ +#define MSG_LINKF 0x0B /* linked w/flag completed */ +#define MSG_BRESET 0x0C /* bus device reset */ +#define MSG_IDENT 0x80 /* 80 thru FF Identify */ + + +typedef struct dsconf { + uint dsc_flags; /* DSRQ flags implemented */ + uint dsc_preset; /* DSRQ flags always defaulted on */ + u_char dsc_bus; /* number scsi busses configured */ + u_char dsc_imax; /* number ID-s per bus */ + u_char dsc_lmax; /* number LUN-s per ID */ + uint dsc_iomax; /* maximum length i/o on this system */ + uint dsc_biomax; /* maximum length buffered i/o */ +} dsconf_t; + +/* + * DEVSCSI public access macros. We use macros internally to + * access the fields of the dsreq packet. This facilitates + * future additions or changes to the underlying packet. + */ + +/* devscsi prefix */ +#define FLAGS(dp) ((dp)->ds_flags) +#define TIME(dp) ((dp)->ds_time) +#define PRIVATE(dp) ((dp)->ds_private) + +/* base addresses */ +#define CMDBUF(dp) (dp)->ds_cmdbuf +#define DATABUF(dp) (dp)->ds_databuf +#define IOVBUF(dp) ((caddr_t) (dp)->ds_iovbuf) +#define SENSEBUF(dp) (dp)->ds_sensebuf + +/* item lengths */ +#define CMDLEN(dp) ((dp)->ds_cmdlen) +#define DATALEN(dp) ((dp)->ds_datalen) +#define IOVLEN(dp) ((dp)->ds_iovlen) +#define SENSELEN(dp) ((dp)->ds_senselen) + +/* devscsi returns */ +#define CMDSENT(dp) ((dp)->ds_cmdsent) +#define DATASENT(dp) ((dp)->ds_datasent) +#define SENSESENT(dp) ((dp)->ds_sensesent) +#define STATUS(dp) ((dp)->ds_status) +#define RET(dp) ((dp)->ds_ret) +#define MSG(dp) ((dp)->ds_msg) + +/* decompose minimal request-sense return struct */ +#define SENSEKEY(p) (((uchar_t *)(p))[2] & 0xF) +#define ADDSENSECODE(p) (((uchar_t *)(p))[12]) +#define FIELDPTR(p) V2( & ((uchar_t *)(p)) [16] ) +#define INFO(p) V4( & ((uchar_t *)(p)) [3] ) + + +/* additional runtime filler functions */ +#define FILLCMD(dp,b,l) ( CMDBUF(dp) = (b), CMDLEN(dp)=(l) ) +#define FILLIOV(iov,i,b,l) { (iov)[i].iov_base = (b); (iov)[i].iov_len = (l); } +#define FILLSENSE(dp,b,l) ( SENSEBUF(dp) = (b), SENSELEN(dp)=(l) ) + + +/* macros for building scsi msb array parameter lists */ +#define B(s,i) ((uchar_t)((s) >> i)) +#define B1(s) ((u_char)(s)) +#define B2(s) B((s),8), B1(s) +#define B3(s) B((s),16), B((s),8), B1(s) +#define B4(s) B((s),24), B((s),16), B((s),8), B1(s) + + +/* macros for converting scsi msb array to binary */ +#define V1(s) (s)[0] +#define V2(s) (((s)[0] << 8) | (s)[1]) +#define V3(s) (((((s)[0] << 8) | (s)[1]) << 8) | (s)[2]) +#define V4(s) (((((((s)[0] << 8) | (s)[1]) << 8) | (s)[2]) << 8) | (s)[3]) + +/* macros for converting binary into scsi msb array */ +#define MSB1(s,v) *(s)=B1(v) +#define MSB2(s,v) *(s)=B(v,8), (s)[1]=B1(v) +#define MSB3(s,v) *(s)=B(v,16), (s)[1]=B(v,8), (s)[2]=B1(v) +#define MSB4(s,v) *(s)=B(v,24),(s)[1]=B(v,16), (s)[2]=B(v,8), (s)[3]=B1(v) + +#endif diff -Nur linux-2.4.19/drivers/xscsi/xscsiha.c linux-2.4.19-sgi211r3/drivers/xscsi/xscsiha.c --- linux-2.4.19/drivers/xscsi/xscsiha.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/drivers/xscsi/xscsiha.c Fri Jan 3 08:28:29 2003 @@ -0,0 +1,91 @@ +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* From IRIX 6.5.9m */ + +#include +#include +#include + +#include + +#include "xscsi.h" + +static int +scsiha_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int +scsiha_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static int +scsiha_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + vertex_hdl_t ctlr; + struct scsi_ha_op ha_ioctl; + int err; + scsi_ctlr_info_t *scsi_ctlr_info; + + ctlr = devfs_get_parent(devfs_get_handle_from_inode(inode)); + + if (ctlr == NULL) + return -ENXIO; + + scsi_ctlr_info = scsi_ctlr_info_get(ctlr); + + if (cmd > 10) { + err = copy_from_user(&ha_ioctl, (void *) arg, + sizeof(ha_ioctl)); + if (err) + return -EFAULT; + } + + err = SCI_IOCTL(scsi_ctlr_info)(SCI_CTLR_VHDL(scsi_ctlr_info), + cmd, &ha_ioctl); + + return err; +} + +struct file_operations scsiha_ops = { + ioctl: scsiha_ioctl, + open: scsiha_open, + release: scsiha_close +}; + diff -Nur linux-2.4.19/drivers/zorro/proc.c linux-2.4.19-sgi211r3/drivers/zorro/proc.c --- linux-2.4.19/drivers/zorro/proc.c Tue Mar 7 10:52:41 2000 +++ linux-2.4.19-sgi211r3/drivers/zorro/proc.c Mon Oct 28 20:43:23 2002 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,8 +22,9 @@ static loff_t proc_bus_zorro_lseek(struct file *file, loff_t off, int whence) { - loff_t new; + loff_t new = -1; + lock_kernel(); switch (whence) { case 0: new = off; @@ -33,11 +35,12 @@ case 2: new = sizeof(struct ConfigDev) + off; break; - default: - return -EINVAL; } - if (new < 0 || new > sizeof(struct ConfigDev)) + if (new < 0 || new > sizeof(struct ConfigDev)) { + unlock_kernel(); return -EINVAL; + } + unlock_kernel(); return (file->f_pos = new); } diff -Nur linux-2.4.19/fs/Config.in linux-2.4.19-sgi211r3/fs/Config.in --- linux-2.4.19/fs/Config.in Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/Config.in Wed Oct 16 14:02:58 2002 @@ -4,7 +4,17 @@ mainmenu_option next_comment comment 'File systems' +bool 'POSIX Access Control Lists' CONFIG_FS_POSIX_ACL + bool 'Quota support' CONFIG_QUOTA +dep_tristate ' Old quota format support' CONFIG_QFMT_V1 $CONFIG_QUOTA +dep_tristate ' VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA +dep_mbool ' Compatible quota interfaces' CONFIG_QIFACE_COMPAT $CONFIG_QUOTA +if [ "$CONFIG_QUOTA" = "y" -a "$CONFIG_QIFACE_COMPAT" = "y" ]; then + choice ' Compatible quota interfaces' \ + "Original CONFIG_QIFACE_V1 \ + VFSv0 CONFIG_QIFACE_V2" Original +fi tristate 'Kernel automounter support' CONFIG_AUTOFS_FS tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS @@ -61,7 +71,11 @@ bool '/proc file system support' CONFIG_PROC_FS -dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL +if [ "$CONFIG_IA64_SGI_SN1" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ] ; then + define_bool CONFIG_DEVFS_FS y +else + dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL +fi dep_bool ' Automatically mount at boot' CONFIG_DEVFS_MOUNT $CONFIG_DEVFS_FS dep_bool ' Debug devfs' CONFIG_DEVFS_DEBUG $CONFIG_DEVFS_FS @@ -85,6 +99,13 @@ tristate 'UFS file system support (read only)' CONFIG_UFS_FS dep_mbool ' UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL + +tristate 'XFS filesystem support' CONFIG_XFS_FS +dep_mbool ' Realtime support (EXPERIMENTAL)' CONFIG_XFS_RT $CONFIG_XFS_FS $CONFIG_EXPERIMENTAL +dep_mbool ' Quota support' CONFIG_XFS_QUOTA $CONFIG_XFS_FS +dep_mbool ' DMAPI support' CONFIG_XFS_DMAPI $CONFIG_XFS_FS +dep_mbool ' Debugging support (EXPERIMENTAL)' CONFIG_XFS_DEBUG $CONFIG_XFS_FS $CONFIG_EXPERIMENTAL +dep_mbool ' Pagebuf debugging support (EXPERIMENTAL)' CONFIG_PAGEBUF_DEBUG $CONFIG_XFS_FS $CONFIG_EXPERIMENTAL if [ "$CONFIG_NET" = "y" ]; then diff -Nur linux-2.4.19/fs/Makefile linux-2.4.19-sgi211r3/fs/Makefile --- linux-2.4.19/fs/Makefile Mon Feb 25 11:38:07 2002 +++ linux-2.4.19-sgi211r3/fs/Makefile Wed Oct 16 14:02:58 2002 @@ -7,19 +7,19 @@ O_TARGET := fs.o -export-objs := filesystems.o open.o dcache.o buffer.o -mod-subdirs := nls +export-objs := filesystems.o open.o dcache.o buffer.o dquot.o +mod-subdirs := nls xfs obj-y := open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \ fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \ dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \ - filesystems.o namespace.o seq_file.o + filesystems.o namespace.o seq_file.o xattr.o quota.o ifeq ($(CONFIG_QUOTA),y) obj-y += dquot.o -else -obj-y += noquot.o +obj-$(CONFIG_QFMT_V1) += quota_v1.o +obj-$(CONFIG_QFMT_V2) += quota_v2.o endif subdir-$(CONFIG_PROC_FS) += proc @@ -67,7 +67,7 @@ subdir-$(CONFIG_REISERFS_FS) += reiserfs subdir-$(CONFIG_DEVPTS_FS) += devpts subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs - +subdir-$(CONFIG_XFS_FS) += xfs obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o diff -Nur linux-2.4.19/fs/adfs/inode.c linux-2.4.19-sgi211r3/fs/adfs/inode.c --- linux-2.4.19/fs/adfs/inode.c Sun Sep 30 12:26:08 2001 +++ linux-2.4.19-sgi211r3/fs/adfs/inode.c Mon Oct 28 20:43:23 2002 @@ -306,6 +306,8 @@ struct super_block *sb = inode->i_sb; unsigned int ia_valid = attr->ia_valid; int error; + + lock_kernel(); error = inode_change_ok(inode, attr); @@ -350,6 +352,7 @@ if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE)) mark_inode_dirty(inode); out: + unlock_kernel(); return error; } diff -Nur linux-2.4.19/fs/affs/dir.c linux-2.4.19-sgi211r3/fs/affs/dir.c --- linux-2.4.19/fs/affs/dir.c Tue Sep 11 08:19:35 2001 +++ linux-2.4.19-sgi211r3/fs/affs/dir.c Mon Oct 28 20:43:23 2002 @@ -79,7 +79,7 @@ stored++; } if (f_pos == 1) { - if (filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) + if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_dentry), DT_DIR) < 0) return stored; filp->f_pos = f_pos = 2; stored++; diff -Nur linux-2.4.19/fs/affs/inode.c linux-2.4.19-sgi211r3/fs/affs/inode.c --- linux-2.4.19/fs/affs/inode.c Mon Feb 25 11:38:07 2002 +++ linux-2.4.19-sgi211r3/fs/affs/inode.c Mon Oct 28 20:43:23 2002 @@ -226,6 +226,8 @@ struct inode *inode = dentry->d_inode; int error; + lock_kernel(); + pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid); error = inode_change_ok(inode,attr); @@ -245,6 +247,7 @@ if (!error && (attr->ia_valid & ATTR_MODE)) mode_to_prot(inode); out: + unlock_kernel(); return error; } diff -Nur linux-2.4.19/fs/attr.c linux-2.4.19-sgi211r3/fs/attr.c --- linux-2.4.19/fs/attr.c Mon Feb 25 11:38:07 2002 +++ linux-2.4.19-sgi211r3/fs/attr.c Mon Oct 28 20:43:23 2002 @@ -21,6 +21,8 @@ int retval = -EPERM; unsigned int ia_valid = attr->ia_valid; + lock_kernel(); + /* If force is set do it anyway. */ if (ia_valid & ATTR_FORCE) goto fine; @@ -55,6 +57,7 @@ fine: retval = 0; error: + unlock_kernel(); return retval; } @@ -62,7 +65,8 @@ { unsigned int ia_valid = attr->ia_valid; int error = 0; - + + lock_kernel(); if (ia_valid & ATTR_SIZE) { error = vmtruncate(inode, attr->ia_size); if (error) @@ -86,6 +90,7 @@ } mark_inode_dirty(inode); out: + unlock_kernel(); return error; } @@ -114,6 +119,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; + mode_t mode = inode->i_mode; int error; time_t now = CURRENT_TIME; unsigned int ia_valid = attr->ia_valid; @@ -126,8 +132,25 @@ attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; + if (ia_valid & ATTR_KILL_SUID) { + if (mode & S_ISUID) { + if (!ia_valid & ATTR_MODE) { + ia_valid = attr->ia_valid |= ATTR_MODE; + attr->ia_mode = inode->i_mode; + } + attr->ia_mode &= ~S_ISUID; + } + } + if (ia_valid & ATTR_KILL_SGID) { + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { + if (!ia_valid & ATTR_MODE) { + ia_valid = attr->ia_valid |= ATTR_MODE; + attr->ia_mode = inode->i_mode; + } + attr->ia_mode &= ~S_ISGID; + } + } - lock_kernel(); if (inode->i_op && inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else { @@ -140,7 +163,6 @@ error = inode_setattr(inode, attr); } } - unlock_kernel(); if (!error) { unsigned long dn_mask = setattr_mask(ia_valid); if (dn_mask) diff -Nur linux-2.4.19/fs/binfmt_elf.c linux-2.4.19-sgi211r3/fs/binfmt_elf.c --- linux-2.4.19/fs/binfmt_elf.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/binfmt_elf.c Mon Oct 28 20:43:23 2002 @@ -1143,7 +1143,7 @@ psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; - psinfo.pr_nice = current->nice; + psinfo.pr_nice = task_nice(current); psinfo.pr_flag = current->flags; psinfo.pr_uid = NEW_TO_OLD_UID(current->uid); psinfo.pr_gid = NEW_TO_OLD_GID(current->gid); diff -Nur linux-2.4.19/fs/block_dev.c linux-2.4.19-sgi211r3/fs/block_dev.c --- linux-2.4.19/fs/block_dev.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/block_dev.c Mon Oct 28 20:43:23 2002 @@ -167,6 +167,7 @@ loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size; loff_t retval; + lock_kernel(); switch (origin) { case 2: offset += size; @@ -183,6 +184,7 @@ } retval = offset; } + unlock_kernel(); return retval; } diff -Nur linux-2.4.19/fs/buffer.c linux-2.4.19-sgi211r3/fs/buffer.c --- linux-2.4.19/fs/buffer.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/buffer.c Fri Jan 3 06:12:57 2003 @@ -86,7 +86,8 @@ static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); static int grow_buffers(kdev_t dev, unsigned long block, int size); -static int osync_buffers_list(struct list_head *); +static void __buffer_insert_inode_data_queue(struct buffer_head *, struct inode *); +static int __osync_buffers_list(struct list_head *); static void __refile_buffer(struct buffer_head *); /* This is used by some architectures to estimate available memory. */ @@ -124,6 +125,36 @@ int bdflush_min[N_PARAM] = { 0, 1, 0, 0, 0, 1*HZ, 0, 0, 0}; int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 10000*HZ, 100, 100, 0}; +static inline int write_buffer_delay(struct buffer_head *bh) +{ + struct page *page = bh->b_page; + + if (!TryLockPage(page)) { + spin_unlock(&lru_list_lock); + unlock_buffer(bh); + page->mapping->a_ops->writepage(page); + return 1; + } + + return 0; +} + +static inline void write_buffer(struct buffer_head *bh) +{ + if (buffer_delay(bh)) { + struct page *page = bh->b_page; + + lock_page(page); + if (buffer_delay(bh)) { + page->mapping->a_ops->writepage(page); + return; + } + unlock_page(page); + } + + ll_rw_block(WRITE, 1, &bh); +} + void unlock_buffer(struct buffer_head *bh) { clear_bit(BH_Wait_IO, &bh->b_state); @@ -214,7 +245,13 @@ continue; if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; - if (atomic_set_buffer_clean(bh)) { + if (buffer_delay(bh)) { + if (write_buffer_delay(bh)) { + if (count) + write_locked_buffers(array, count); + return -EAGAIN; + } + } else if (atomic_set_buffer_clean(bh)) { __refile_buffer(bh); get_bh(bh); array[count++] = bh; @@ -324,7 +361,7 @@ lock_kernel(); sync_inodes_sb(sb); - DQUOT_SYNC(dev); + DQUOT_SYNC_SB(sb); lock_super(sb); if (sb->s_dirt && sb->s_op && sb->s_op->write_super) sb->s_op->write_super(sb); @@ -346,7 +383,7 @@ lock_kernel(); sync_inodes(dev); - DQUOT_SYNC(dev); + DQUOT_SYNC_DEV(dev); sync_supers(dev); unlock_kernel(); @@ -594,13 +631,18 @@ spin_unlock(&lru_list_lock); } -void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode) +static void __buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode) { - spin_lock(&lru_list_lock); if (bh->b_inode) list_del(&bh->b_inode_buffers); bh->b_inode = inode; list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers); +} + +void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode) +{ + spin_lock(&lru_list_lock); + __buffer_insert_inode_data_queue(bh, inode); spin_unlock(&lru_list_lock); } @@ -736,9 +778,8 @@ wakeup_bdflush(); try_to_free_pages(zone, GFP_NOFS, 0); run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; __set_current_state(TASK_RUNNING); - schedule(); + sys_sched_yield(); } void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private) @@ -754,6 +795,7 @@ unsigned long flags; struct buffer_head *tmp; struct page *page; + int fullup = 1; mark_buffer_uptodate(bh, uptodate); @@ -780,8 +822,11 @@ unlock_buffer(bh); tmp = bh->b_this_page; while (tmp != bh) { - if (buffer_async(tmp) && buffer_locked(tmp)) - goto still_busy; + if (buffer_locked(tmp)) { + if (buffer_async(tmp)) + goto still_busy; + } else if (!buffer_uptodate(tmp)) + fullup = 0; tmp = tmp->b_this_page; } @@ -789,10 +834,10 @@ spin_unlock_irqrestore(&page_uptodate_lock, flags); /* - * if none of the buffers had errors then we can set the - * page uptodate: + * if none of the buffers had errors and all were uptodate + * then we can set the page uptodate: */ - if (!PageError(page)) + if (fullup && !PageError(page)) SetPageUptodate(page); UnlockPage(page); @@ -859,7 +904,7 @@ * a noop) */ wait_on_buffer(bh); - ll_rw_block(WRITE, 1, &bh); + write_buffer(bh); brelse(bh); spin_lock(&lru_list_lock); } @@ -878,8 +923,8 @@ spin_lock(&lru_list_lock); } + err2 = __osync_buffers_list(list); spin_unlock(&lru_list_lock); - err2 = osync_buffers_list(list); if (err) return err; @@ -896,15 +941,15 @@ * you dirty the buffers, and then use osync_buffers_list to wait for * completion. Any other dirty buffers which are not yet queued for * write will not be flushed to disk by the osync. + * + * Expects lru_list_lock to be held at entry. */ -static int osync_buffers_list(struct list_head *list) +static int __osync_buffers_list(struct list_head *list) { struct buffer_head *bh; struct list_head *p; int err = 0; - spin_lock(&lru_list_lock); - repeat: list_for_each_prev(p, list) { bh = BH_ENTRY(p); @@ -920,7 +965,6 @@ } } - spin_unlock(&lru_list_lock); return err; } @@ -1032,10 +1076,18 @@ } } -inline void __mark_dirty(struct buffer_head *bh) +/* caller must hold lru_list_lock */ +static inline void __mark_dirty_locked(struct buffer_head *bh) { bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer; - refile_buffer(bh); + __refile_buffer(bh); +} + +inline void __mark_dirty(struct buffer_head *bh) +{ + spin_lock(&lru_list_lock); + __mark_dirty_locked(bh); + spin_unlock(&lru_list_lock); } /* atomic version, the user must call balance_dirty() by hand @@ -1305,13 +1357,14 @@ */ static void discard_buffer(struct buffer_head * bh) { - if (buffer_mapped(bh)) { + if (buffer_mapped(bh) || buffer_delay(bh)) { mark_buffer_clean(bh); lock_buffer(bh); clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Mapped, &bh->b_state); clear_bit(BH_Req, &bh->b_state); clear_bit(BH_New, &bh->b_state); + clear_bit(BH_Delay, &bh->b_state); remove_from_queues(bh); unlock_buffer(bh); } @@ -1599,7 +1652,7 @@ set_bit(BH_Uptodate, &bh->b_state); continue; } - if (!buffer_uptodate(bh) && + if (!buffer_uptodate(bh) && !buffer_delay(bh) && (block_start < from || block_end > to)) { ll_rw_block(READ, 1, &bh); *wait_bh++=bh; @@ -1619,8 +1672,20 @@ * Zero out any newly allocated blocks to avoid exposing stale * data. If BH_New is set, we know that the block was newly * allocated in the above loop. + * + * Details the buffer can be new and uptodate because: + * 1) hole in uptodate page, get_block(create) allocate the block, + * so the buffer is new and additionally we also mark it uptodate + * 2) The buffer is not mapped and uptodate due a previous partial read. + * + * We can always ignore uptodate buffers here, if you mark a buffer + * uptodate you must make sure it contains the right data first. + * + * We must stop the "undo/clear" fixup pass not at the caller "to" + * but at the last block that we successfully arrived in the main loop. */ bh = head; + to = block_start; /* stop at the last successfully handled block */ block_start = 0; do { block_end = block_start+blocksize; @@ -1628,10 +1693,9 @@ goto next_bh; if (block_start >= to) break; - if (buffer_new(bh)) { - if (buffer_uptodate(bh)) - printk(KERN_ERR "%s: zeroing uptodate buffer!\n", __FUNCTION__); + if (buffer_new(bh) && !buffer_uptodate(bh)) { memset(kaddr+block_start, 0, bh->b_size); + flush_dcache_page(page); set_bit(BH_Uptodate, &bh->b_state); mark_buffer_dirty(bh); } @@ -1662,8 +1726,10 @@ } else { set_bit(BH_Uptodate, &bh->b_state); if (!atomic_set_buffer_dirty(bh)) { - __mark_dirty(bh); - buffer_insert_inode_data_queue(bh, inode); + spin_lock(&lru_list_lock); + __mark_dirty_locked(bh); + __buffer_insert_inode_data_queue(bh, inode); + spin_unlock(&lru_list_lock); need_balance_dirty = 1; } } @@ -1978,7 +2044,7 @@ if (Page_Uptodate(page)) set_bit(BH_Uptodate, &bh->b_state); - if (!buffer_uptodate(bh)) { + if (!buffer_uptodate(bh) && !buffer_delay(bh)) { err = -EIO; ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); @@ -1991,7 +2057,12 @@ flush_dcache_page(page); kunmap(page); - __mark_buffer_dirty(bh); + if (!atomic_set_buffer_dirty(bh)) { + __mark_dirty(bh); + buffer_insert_inode_data_queue(bh, inode); + balance_dirty(); + } + err = 0; unlock: @@ -2688,7 +2759,7 @@ { #ifdef CONFIG_SMP struct buffer_head * bh; - int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0; + int delalloc = 0, found = 0, locked = 0, dirty = 0, used = 0, lastused = 0; int nlist; static char *buf_types[NR_LIST] = { "CLEAN", "LOCKED", "DIRTY", }; #endif @@ -2703,7 +2774,7 @@ if (!spin_trylock(&lru_list_lock)) return; for(nlist = 0; nlist < NR_LIST; nlist++) { - found = locked = dirty = used = lastused = 0; + delalloc = found = locked = dirty = used = lastused = 0; bh = lru_list[nlist]; if(!bh) continue; @@ -2713,6 +2784,8 @@ locked++; if (buffer_dirty(bh)) dirty++; + if (buffer_delay(bh)) + delalloc++; if (atomic_read(&bh->b_count)) used++, lastused = found; bh = bh->b_next_free; @@ -2723,10 +2796,10 @@ printk("%9s: BUG -> found %d, reported %d\n", buf_types[nlist], found, tmp); } - printk("%9s: %d buffers, %lu kbyte, %d used (last=%d), " - "%d locked, %d dirty\n", + printk("%7s: %d buffers, %lu kbyte, %d used (last=%d), " + "%d locked, %d dirty %d delay\n", buf_types[nlist], found, size_buffers_type[nlist]>>10, - used, lastused, locked, dirty); + used, lastused, locked, dirty, delalloc); } spin_unlock(&lru_list_lock); #endif diff -Nur linux-2.4.19/fs/coda/dir.c linux-2.4.19-sgi211r3/fs/coda/dir.c --- linux-2.4.19/fs/coda/dir.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/coda/dir.c Wed Dec 11 20:43:45 2002 @@ -560,7 +560,7 @@ filp->f_pos++; /* fallthrough */ case 1: - ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR); + ret = filldir(dirent, "..", 2, 1, parent_ino(dir), DT_DIR); if (ret < 0) break; result++; filp->f_pos++; diff -Nur linux-2.4.19/fs/coda/inode.c linux-2.4.19-sgi211r3/fs/coda/inode.c --- linux-2.4.19/fs/coda/inode.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/coda/inode.c Mon Oct 28 20:43:23 2002 @@ -219,6 +219,8 @@ memset(&vattr, 0, sizeof(vattr)); + lock_kernel(); + inode->i_ctime = CURRENT_TIME; coda_iattr_to_vattr(iattr, &vattr); vattr.va_type = C_VNON; /* cannot set type */ @@ -231,6 +233,8 @@ coda_vattr_to_iattr(inode, &vattr); coda_cache_clear_inode(inode); } + unlock_kernel(); + CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error); return error; @@ -246,7 +250,9 @@ { int error; + lock_kernel(); error = venus_statfs(sb, buf); + unlock_kernel(); if (error) { /* fake something like AFS does */ diff -Nur linux-2.4.19/fs/dcache.c linux-2.4.19-sgi211r3/fs/dcache.c --- linux-2.4.19/fs/dcache.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/dcache.c Thu Dec 19 08:34:59 2002 @@ -30,6 +30,7 @@ /* #define DCACHE_DEBUG 1 */ spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +rwlock_t dparent_lock __cacheline_aligned_in_smp = RW_LOCK_UNLOCKED; /* Right now the dcache depends on the kernel lock */ #define check_lock() if (!kernel_locked()) BUG() @@ -913,14 +914,24 @@ list_del(&dentry->d_child); list_del(&target->d_child); - /* Switch the parents and the names.. */ + /* Switch the names.. */ switch_names(dentry, target); - do_switch(dentry->d_parent, target->d_parent); do_switch(dentry->d_name.len, target->d_name.len); do_switch(dentry->d_name.hash, target->d_name.hash); + /* ... and switch the parents */ + write_lock(&dparent_lock); + if (IS_ROOT(dentry)) { + dentry->d_parent = target->d_parent; + target->d_parent = target; + INIT_LIST_HEAD(&target->d_child); + } else { + do_switch(dentry->d_parent, target->d_parent); + + /* And add them back to the (new) parent lists */ + list_add(&target->d_child, &target->d_parent->d_subdirs); + } + write_unlock(&dparent_lock); - /* And add them back to the (new) parent lists */ - list_add(&target->d_child, &target->d_parent->d_subdirs); list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); spin_unlock(&dcache_lock); } @@ -1282,6 +1293,7 @@ dcache_init(mempages); inode_init(mempages); + files_init(mempages); mnt_init(mempages); bdev_cache_init(); cdev_cache_init(); diff -Nur linux-2.4.19/fs/devfs/base.c linux-2.4.19-sgi211r3/fs/devfs/base.c --- linux-2.4.19/fs/devfs/base.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/devfs/base.c Fri Dec 20 12:01:57 2002 @@ -1752,7 +1752,7 @@ de->u.symlink.length = linklength; if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 ) { - PRINTK ("(%s): could not append to parent, err: %d\n", name, err); + DPRINTK (DEBUG_UNREGISTER, "(%s): could not append to parent, err: %d\n", name, err); devfs_put (dir); return err; } @@ -2711,7 +2711,7 @@ case 0: scan_dir_for_removable (parent); err = (*filldir) (dirent, "..", 2, file->f_pos, - file->f_dentry->d_parent->d_inode->i_ino, DT_DIR); + parent_ino(file->f_dentry), DT_DIR); if (err == -EINVAL) break; if (err < 0) return err; file->f_pos++; diff -Nur linux-2.4.19/fs/dquot.c linux-2.4.19-sgi211r3/fs/dquot.c --- linux-2.4.19/fs/dquot.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/dquot.c Wed Oct 16 14:02:58 2002 @@ -35,7 +35,7 @@ * Jan Kara, , sponsored by SuSE CR, 10-11/99 * * Used struct list_head instead of own list struct - * Invalidation of dquots with dq_count > 0 no longer possible + * Invalidation of referenced dquots is no longer possible * Improved free_dquots list management * Quota and i_blocks are now updated in one place to avoid races * Warnings are now delayed so we won't block in critical section @@ -45,6 +45,10 @@ * Added dynamic quota structure allocation * Jan Kara 12/2000 * + * Rewritten quota interface. Implemented new quota format and + * formats registering. + * Jan Kara, , 2001,2002 + * * (C) Copyright 1994 - 1997 Marco van Wieringen */ @@ -59,20 +63,53 @@ #include #include #include +#include #include #include +#include +#include #include -#define __DQUOT_VERSION__ "dquot_6.4.0" +static char *quotatypes[] = INITQFNAMES; +static struct quota_format_type *quota_formats; /* List of registered formats */ -int nr_dquots, nr_free_dquots; +int register_quota_format(struct quota_format_type *fmt) +{ + lock_kernel(); + fmt->qf_next = quota_formats; + quota_formats = fmt; + unlock_kernel(); + return 0; +} -static char *quotatypes[] = INITQFNAMES; +void unregister_quota_format(struct quota_format_type *fmt) +{ + struct quota_format_type **actqf; -static inline struct quota_mount_options *sb_dqopt(struct super_block *sb) + lock_kernel(); + for (actqf = "a_formats; *actqf && *actqf != fmt; actqf = &(*actqf)->qf_next); + if (*actqf) + *actqf = (*actqf)->qf_next; + unlock_kernel(); +} + +static struct quota_format_type *find_quota_format(int id) { - return &sb->s_dquot; + struct quota_format_type *actqf; + + lock_kernel(); + for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); + if (actqf && !try_inc_mod_count(actqf->qf_owner)) + actqf = NULL; + unlock_kernel(); + return actqf; +} + +static void put_quota_format(struct quota_format_type *fmt) +{ + if (fmt->qf_owner) + __MOD_DEC_USE_COUNT(fmt->qf_owner); } /* @@ -85,11 +122,11 @@ * list is used for the sync and invalidate operations, which must look * at every dquot. * - * Unused dquots (dq_count == 0) are added to the free_dquots list when - * freed, and this list is searched whenever we need an available dquot. - * Dquots are removed from the list as soon as they are used again, and - * nr_free_dquots gives the number of dquots on the list. When dquot is - * invalidated it's completely released from memory. + * Unused dquots (dq_count == 0) are added to the free_dquots list when freed, + * and this list is searched whenever we need an available dquot. Dquots are + * removed from the list as soon as they are used again, and + * dqstats.free_dquots gives the number of dquots on the list. When + * dquot is invalidated it's completely released from memory. * * Dquots with a specific identity (device, type and id) are placed on * one of the dquot_hash[] hash chains. The provides an efficient search @@ -115,35 +152,39 @@ static LIST_HEAD(free_dquots); static struct list_head dquot_hash[NR_DQHASH]; -static struct dqstats dqstats; +struct dqstats dqstats; static void dqput(struct dquot *); static struct dquot *dqduplicate(struct dquot *); -static inline char is_enabled(struct quota_mount_options *dqopt, short type) +static inline void get_dquot_ref(struct dquot *dquot) { - switch (type) { - case USRQUOTA: - return((dqopt->flags & DQUOT_USR_ENABLED) != 0); - case GRPQUOTA: - return((dqopt->flags & DQUOT_GRP_ENABLED) != 0); - } - return(0); + dquot->dq_count++; +} + +static inline void put_dquot_ref(struct dquot *dquot) +{ + dquot->dq_count--; +} + +static inline void get_dquot_dup_ref(struct dquot *dquot) +{ + dquot->dq_dup_ref++; } -static inline char sb_has_quota_enabled(struct super_block *sb, short type) +static inline void put_dquot_dup_ref(struct dquot *dquot) { - return is_enabled(sb_dqopt(sb), type); + dquot->dq_dup_ref--; } -static inline int const hashfn(kdev_t dev, unsigned int id, short type) +static inline int const hashfn(struct super_block *sb, unsigned int id, int type) { - return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; + return((HASHDEV(sb->s_dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; } static inline void insert_dquot_hash(struct dquot *dquot) { - struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type); + struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); list_add(&dquot->dq_hash, head); } @@ -153,14 +194,14 @@ INIT_LIST_HEAD(&dquot->dq_hash); } -static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type) +static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type) { struct list_head *head; struct dquot *dquot; for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) { dquot = list_entry(head, struct dquot, dq_hash); - if (dquot->dq_dev == dev && dquot->dq_id == id && dquot->dq_type == type) + if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type) return dquot; } return NODQUOT; @@ -170,14 +211,14 @@ static inline void put_dquot_head(struct dquot *dquot) { list_add(&dquot->dq_free, &free_dquots); - nr_free_dquots++; + dqstats.free_dquots++; } /* Add a dquot to the tail of the free list */ static inline void put_dquot_last(struct dquot *dquot) { list_add(&dquot->dq_free, free_dquots.prev); - nr_free_dquots++; + dqstats.free_dquots++; } /* Move dquot to the head of free list (it must be already on it) */ @@ -193,7 +234,7 @@ return; list_del(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_free); - nr_free_dquots--; + dqstats.free_dquots--; } static inline void put_inuse(struct dquot *dquot) @@ -201,12 +242,12 @@ /* We add to the back of inuse list so we don't have to restart * when traversing this list and we block */ list_add(&dquot->dq_inuse, inuse_list.prev); - nr_dquots++; + dqstats.allocated_dquots++; } static inline void remove_inuse(struct dquot *dquot) { - nr_dquots--; + dqstats.allocated_dquots--; list_del(&dquot->dq_inuse); } @@ -243,6 +284,7 @@ wake_up(&dquot->dq_wait_lock); } +/* Wait for dquot to be unused */ static void __wait_dquot_unused(struct dquot *dquot) { DECLARE_WAITQUEUE(wait, current); @@ -258,85 +300,56 @@ current->state = TASK_RUNNING; } -/* - * We don't have to be afraid of deadlocks as we never have quotas on quota files... - */ -static void write_dquot(struct dquot *dquot) +/* Wait for all duplicated dquot references to be dropped */ +static void __wait_dup_drop(struct dquot *dquot) { - short type = dquot->dq_type; - struct file *filp; - mm_segment_t fs; - loff_t offset; - ssize_t ret; - struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem; - struct dqblk dqbuf; - - down(sem); - filp = dquot->dq_sb->s_dquot.files[type]; - offset = dqoff(dquot->dq_id); - fs = get_fs(); - set_fs(KERNEL_DS); + DECLARE_WAITQUEUE(wait, current); - /* - * Note: clear the DQ_MOD flag unconditionally, - * so we don't loop forever on failure. - */ - memcpy(&dqbuf, &dquot->dq_dqb, sizeof(struct dqblk)); - dquot->dq_flags &= ~DQ_MOD; - ret = 0; - if (filp) - ret = filp->f_op->write(filp, (char *)&dqbuf, - sizeof(struct dqblk), &offset); - if (ret != sizeof(struct dqblk)) - printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", - kdevname(dquot->dq_dev)); - - set_fs(fs); - up(sem); - dqstats.writes++; -} - -static void read_dquot(struct dquot *dquot) -{ - short type = dquot->dq_type; - struct file *filp; - mm_segment_t fs; - loff_t offset; + add_wait_queue(&dquot->dq_wait_free, &wait); +repeat: + set_current_state(TASK_UNINTERRUPTIBLE); + if (dquot->dq_dup_ref) { + schedule(); + goto repeat; + } + remove_wait_queue(&dquot->dq_wait_free, &wait); + current->state = TASK_RUNNING; +} - filp = dquot->dq_sb->s_dquot.files[type]; - if (filp == (struct file *)NULL) - return; +static int read_dqblk(struct dquot *dquot) +{ + int ret; + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); lock_dquot(dquot); - if (!dquot->dq_sb) /* Invalidated quota? */ - goto out_lock; - /* Now we are sure filp is valid - the dquot isn't invalidated */ - down(&dquot->dq_sb->s_dquot.dqio_sem); - offset = dqoff(dquot->dq_id); - fs = get_fs(); - set_fs(KERNEL_DS); - filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset); - up(&dquot->dq_sb->s_dquot.dqio_sem); - set_fs(fs); - - if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 && - dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0) - dquot->dq_flags |= DQ_FAKE; - dqstats.reads++; -out_lock: + down(&dqopt->dqio_sem); + ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot); + up(&dqopt->dqio_sem); unlock_dquot(dquot); + return ret; +} + +static int commit_dqblk(struct dquot *dquot) +{ + int ret; + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + + down(&dqopt->dqio_sem); + ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); + up(&dqopt->dqio_sem); + return ret; } /* Invalidate all dquots on the list, wait for all users. Note that this function is called * after quota is disabled so no new quota might be created. As we only insert to the end of * inuse list, we don't have to restart searching... */ -static void invalidate_dquots(struct super_block *sb, short type) +static void invalidate_dquots(struct super_block *sb, int type) { struct dquot *dquot; struct list_head *head; restart: - for (head = inuse_list.next; head != &inuse_list; head = head->next) { + list_for_each(head, &inuse_list) { dquot = list_entry(head, struct dquot, dq_inuse); if (dquot->dq_sb != sb) continue; @@ -359,37 +372,107 @@ } } -int sync_dquots(kdev_t dev, short type) +static int vfs_quota_sync(struct super_block *sb, int type) { struct list_head *head; struct dquot *dquot; + struct quota_info *dqopt = sb_dqopt(sb); + int cnt; - lock_kernel(); restart: - for (head = inuse_list.next; head != &inuse_list; head = head->next) { + list_for_each(head, &inuse_list) { dquot = list_entry(head, struct dquot, dq_inuse); - if (dev && dquot->dq_dev != dev) + if (sb && dquot->dq_sb != sb) continue; if (type != -1 && dquot->dq_type != type) continue; if (!dquot->dq_sb) /* Invalidated? */ continue; - if (!(dquot->dq_flags & (DQ_MOD | DQ_LOCKED))) + if (!dquot_dirty(dquot) && !(dquot->dq_flags & DQ_LOCKED)) continue; - /* Raise use count so quota won't be invalidated. We can't use dqduplicate() as it does too many tests */ - dquot->dq_count++; + /* Get reference to quota so it won't be invalidated. get_dquot_ref() + * is enough since if dquot is locked/modified it can't be + * on the free list */ + get_dquot_ref(dquot); if (dquot->dq_flags & DQ_LOCKED) wait_on_dquot(dquot); - if (dquot->dq_flags & DQ_MOD) - write_dquot(dquot); + if (dquot_dirty(dquot)) + commit_dqblk(dquot); dqput(dquot); goto restart; } + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt)) + dqopt->info[cnt].dqi_flags &= ~DQF_ANY_DQUOT_DIRTY; + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) + dqopt->ops[cnt]->write_file_info(sb, cnt); dqstats.syncs++; - unlock_kernel(); + return 0; } +static struct super_block *get_super_to_sync(int type) +{ + struct list_head *head; + int cnt, dirty; + +restart: + spin_lock(&sb_lock); + list_for_each(head, &super_blocks) { + struct super_block *sb = list_entry(head, struct super_block, s_list); + + for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) + if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) + && sb_dqopt(sb)->info[cnt].dqi_flags & DQF_ANY_DQUOT_DIRTY) + dirty = 1; + if (!dirty) + continue; + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); + if (!sb->s_root) { + drop_super(sb); + goto restart; + } + return sb; + } + spin_unlock(&sb_lock); + return NULL; +} + +void sync_dquots_dev(kdev_t dev, int type) +{ + struct super_block *sb; + + if (dev) { + if ((sb = get_super(dev))) { + lock_kernel(); + if (sb->s_qcop->quota_sync) + sb->s_qcop->quota_sync(sb, type); + unlock_kernel(); + drop_super(sb); + } + } + else { + while ((sb = get_super_to_sync(type))) { + lock_kernel(); + if (sb->s_qcop->quota_sync) + sb->s_qcop->quota_sync(sb, type); + unlock_kernel(); + drop_super(sb); + } + } +} + +void sync_dquots_sb(struct super_block *sb, int type) +{ + lock_kernel(); + if (sb->s_qcop->quota_sync) + sb->s_qcop->quota_sync(sb, type); + unlock_kernel(); +} + /* Free unused dquots from cache */ static void prune_dqcache(int count) { @@ -408,19 +491,38 @@ } } +/* + * This is called from kswapd when we think we need some + * more memory, but aren't really sure how much. So we + * carefully try to free a _bit_ of our dqcache, but not + * too much. + * + * Priority: + * 1 - very urgent: shrink everything + * ... + * 6 - base-level: try to shrink a bit. + */ + int shrink_dqcache_memory(int priority, unsigned int gfp_mask) { + int count = 0; + lock_kernel(); - prune_dqcache(nr_free_dquots / (priority + 1)); + count = dqstats.free_dquots / priority; + prune_dqcache(count); unlock_kernel(); return kmem_cache_shrink(dquot_cachep); } -/* NOTE: If you change this function please check whether dqput_blocks() works right... */ +/* + * Put reference to dquot + * NOTE: If you change this function please check whether dqput_blocks() works right... + */ static void dqput(struct dquot *dquot) { if (!dquot) return; +#ifdef __DQUOT_PARANOIA if (!dquot->dq_count) { printk("VFS: dqput: trying to free free dquot\n"); printk("VFS: device %s, dquot of %s %d\n", @@ -428,33 +530,38 @@ dquot->dq_id); return; } +#endif dqstats.drops++; we_slept: + if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) { /* Last unduplicated reference? */ + __wait_dup_drop(dquot); + goto we_slept; + } if (dquot->dq_count > 1) { /* We have more than one user... We can simply decrement use count */ - dquot->dq_count--; + put_dquot_ref(dquot); return; } - if (dquot->dq_flags & DQ_MOD) { - write_dquot(dquot); + if (dquot_dirty(dquot)) { + commit_dqblk(dquot); goto we_slept; } /* sanity check */ if (!list_empty(&dquot->dq_free)) { printk(KERN_ERR "dqput: dquot already on free list??\n"); - dquot->dq_count--; /* J.K. Just decrementing use count seems safer... */ + put_dquot_ref(dquot); return; } - dquot->dq_count--; + put_dquot_ref(dquot); /* If dquot is going to be invalidated invalidate_dquots() is going to free it so */ if (!(dquot->dq_flags & DQ_INVAL)) put_dquot_last(dquot); /* Place at end of LRU free queue */ wake_up(&dquot->dq_wait_free); } -static struct dquot *get_empty_dquot(void) +static struct dquot *get_empty_dquot(struct super_block *sb, int type) { struct dquot *dquot; @@ -468,6 +575,9 @@ INIT_LIST_HEAD(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_inuse); INIT_LIST_HEAD(&dquot->dq_hash); + dquot->dq_sb = sb; + dquot->dq_dev = sb->s_dev; + dquot->dq_type = type; dquot->dq_count = 1; /* all dquots go on the inuse_list */ put_inuse(dquot); @@ -475,11 +585,11 @@ return dquot; } -static struct dquot *dqget(struct super_block *sb, unsigned int id, short type) +static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) { - unsigned int hashent = hashfn(sb->s_dev, id, type); + unsigned int hashent = hashfn(sb, id, type); struct dquot *dquot, *empty = NODQUOT; - struct quota_mount_options *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = sb_dqopt(sb); we_slept: if (!is_enabled(dqopt, type)) { @@ -488,23 +598,21 @@ return NODQUOT; } - if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) { + if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { if (empty == NODQUOT) { - if ((empty = get_empty_dquot()) == NODQUOT) + if ((empty = get_empty_dquot(sb, type)) == NODQUOT) schedule(); /* Try to wait for a moment... */ goto we_slept; } dquot = empty; - dquot->dq_id = id; - dquot->dq_type = type; - dquot->dq_dev = sb->s_dev; - dquot->dq_sb = sb; + dquot->dq_id = id; /* hash it first so it can be found */ insert_dquot_hash(dquot); - read_dquot(dquot); + read_dqblk(dquot); } else { - if (!dquot->dq_count++) + if (!dquot->dq_count) remove_free_dquot(dquot); + get_dquot_ref(dquot); dqstats.cache_hits++; wait_on_dquot(dquot); if (empty) @@ -516,30 +624,47 @@ dqput(dquot); return NODQUOT; } - dquot->dq_referenced++; + ++dquot->dq_referenced; dqstats.lookups++; return dquot; } +/* Duplicate reference to dquot got from inode */ static struct dquot *dqduplicate(struct dquot *dquot) { if (dquot == NODQUOT) return NODQUOT; - dquot->dq_count++; + get_dquot_ref(dquot); if (!dquot->dq_sb) { printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n"); - dquot->dq_count--; + put_dquot_ref(dquot); return NODQUOT; } if (dquot->dq_flags & DQ_LOCKED) printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n"); + get_dquot_dup_ref(dquot); dquot->dq_referenced++; dqstats.lookups++; + return dquot; } -static int dqinit_needed(struct inode *inode, short type) +/* Put duplicated reference */ +static void dqputduplicate(struct dquot *dquot) +{ + if (!dquot->dq_dup_ref) { + printk(KERN_ERR "VFS: dqputduplicate(): Duplicated dquot put without duplicate reference.\n"); + return; + } + put_dquot_dup_ref(dquot); + if (!dquot->dq_dup_ref) + wake_up(&dquot->dq_wait_free); + put_dquot_ref(dquot); + dqstats.drops++; +} + +static int dqinit_needed(struct inode *inode, int type) { int cnt; @@ -553,16 +678,13 @@ return 0; } -static void add_dquot_ref(struct super_block *sb, short type) +static void add_dquot_ref(struct super_block *sb, int type) { struct list_head *p; - if (!sb->dq_op) - return; /* nothing to do */ - restart: file_list_lock(); - for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + list_for_each(p, &sb->s_files) { struct file *filp = list_entry(p, struct file, f_list); struct inode *inode = filp->f_dentry->d_inode; if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { @@ -582,13 +704,15 @@ /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ static inline int dqput_blocks(struct dquot *dquot) { - if (dquot->dq_count == 1) + if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) + return 1; + if (dquot->dq_count <= 1 && dquot->dq_flags & DQ_MOD) return 1; return 0; } /* Remove references to dquots from inode - add dquot to list for freeing if needed */ -int remove_inode_dquot_ref(struct inode *inode, short type, struct list_head *tofree_head) +int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head) { struct dquot *dquot = inode->i_dquot[type]; int cnt; @@ -635,38 +759,38 @@ static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) { - dquot->dq_curinodes += number; - dquot->dq_flags |= DQ_MOD; + dquot->dq_dqb.dqb_curinodes += number; + mark_dquot_dirty(dquot); } -static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number) +static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) { - dquot->dq_curblocks += number; - dquot->dq_flags |= DQ_MOD; + dquot->dq_dqb.dqb_curspace += number; + mark_dquot_dirty(dquot); } static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number) { - if (dquot->dq_curinodes > number) - dquot->dq_curinodes -= number; + if (dquot->dq_dqb.dqb_curinodes > number) + dquot->dq_dqb.dqb_curinodes -= number; else - dquot->dq_curinodes = 0; - if (dquot->dq_curinodes < dquot->dq_isoftlimit) - dquot->dq_itime = (time_t) 0; + dquot->dq_dqb.dqb_curinodes = 0; + if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit) + dquot->dq_dqb.dqb_itime = (time_t) 0; dquot->dq_flags &= ~DQ_INODES; - dquot->dq_flags |= DQ_MOD; + mark_dquot_dirty(dquot); } -static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number) +static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) { - if (dquot->dq_curblocks > number) - dquot->dq_curblocks -= number; + if (dquot->dq_dqb.dqb_curspace > number) + dquot->dq_dqb.dqb_curspace -= number; else - dquot->dq_curblocks = 0; - if (dquot->dq_curblocks < dquot->dq_bsoftlimit) - dquot->dq_btime = (time_t) 0; + dquot->dq_dqb.dqb_curspace = 0; + if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit) + dquot->dq_dqb.dqb_btime = (time_t) 0; dquot->dq_flags &= ~DQ_BLKS; - dquot->dq_flags |= DQ_MOD; + mark_dquot_dirty(dquot); } static inline int need_print_warning(struct dquot *dquot, int flag) @@ -739,7 +863,10 @@ static inline char ignore_hardlimit(struct dquot *dquot) { - return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type]; + struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type]; + + return capable(CAP_SYS_RESOURCE) && + (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH)); } static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) @@ -748,60 +875,60 @@ if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; - if (dquot->dq_ihardlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && + if (dquot->dq_dqb.dqb_ihardlimit && + (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit && !ignore_hardlimit(dquot)) { *warntype = IHARDWARN; return NO_QUOTA; } - if (dquot->dq_isoftlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && + if (dquot->dq_dqb.dqb_isoftlimit && + (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && + dquot->dq_dqb.dqb_itime && CURRENT_TIME >= dquot->dq_dqb.dqb_itime && !ignore_hardlimit(dquot)) { *warntype = ISOFTLONGWARN; return NO_QUOTA; } - if (dquot->dq_isoftlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime == 0) { + if (dquot->dq_dqb.dqb_isoftlimit && + (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && + dquot->dq_dqb.dqb_itime == 0) { *warntype = ISOFTWARN; - dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type]; + dquot->dq_dqb.dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; } return QUOTA_OK; } -static int check_bdq(struct dquot *dquot, ulong blocks, char prealloc, char *warntype) +static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) { *warntype = 0; - if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) + if (space <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; - if (dquot->dq_bhardlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && + if (dquot->dq_dqb.dqb_bhardlimit && + toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = BHARDWARN; return NO_QUOTA; } - if (dquot->dq_bsoftlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && + if (dquot->dq_dqb.dqb_bsoftlimit && + toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_btime && CURRENT_TIME >= dquot->dq_dqb.dqb_btime && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = BSOFTLONGWARN; return NO_QUOTA; } - if (dquot->dq_bsoftlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime == 0) { + if (dquot->dq_dqb.dqb_bsoftlimit && + toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_btime == 0) { if (!prealloc) { *warntype = BSOFTWARN; - dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type]; + dquot->dq_dqb.dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; } else /* @@ -815,148 +942,15 @@ } /* - * Initialize a dquot-struct with new quota info. This is used by the - * system call interface functions. - */ -static int set_dqblk(struct super_block *sb, int id, short type, int flags, struct dqblk *dqblk) -{ - struct dquot *dquot; - int error = -EFAULT; - struct dqblk dq_dqblk; - - if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk))) - return error; - - if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) { - /* We can't block while changing quota structure... */ - if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) { - dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit; - dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit; - dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit; - dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit; - } - - if ((flags & SET_QUOTA) || (flags & SET_USE)) { - if (dquot->dq_isoftlimit && - dquot->dq_curinodes < dquot->dq_isoftlimit && - dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit) - dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[type]; - dquot->dq_curinodes = dq_dqblk.dqb_curinodes; - if (dquot->dq_curinodes < dquot->dq_isoftlimit) - dquot->dq_flags &= ~DQ_INODES; - if (dquot->dq_bsoftlimit && - dquot->dq_curblocks < dquot->dq_bsoftlimit && - dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit) - dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[type]; - dquot->dq_curblocks = dq_dqblk.dqb_curblocks; - if (dquot->dq_curblocks < dquot->dq_bsoftlimit) - dquot->dq_flags &= ~DQ_BLKS; - } - - if (id == 0) { - dquot->dq_sb->s_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime; - dquot->dq_sb->s_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime; - } - - if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 && - dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0) - dquot->dq_flags |= DQ_FAKE; - else - dquot->dq_flags &= ~DQ_FAKE; - - dquot->dq_flags |= DQ_MOD; - dqput(dquot); - } - return 0; -} - -static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk) -{ - struct dquot *dquot; - struct dqblk data; - int error = -ESRCH; - - if (!sb || !sb_has_quota_enabled(sb, type)) - goto out; - dquot = dqget(sb, id, type); - if (dquot == NODQUOT) - goto out; - - memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk)); /* We copy data to preserve them from changing */ - dqput(dquot); - error = -EFAULT; - if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct dqblk))) - error = 0; -out: - return error; -} - -static int get_stats(caddr_t addr) -{ - int error = -EFAULT; - struct dqstats stats; - - dqstats.allocated_dquots = nr_dquots; - dqstats.free_dquots = nr_free_dquots; - - /* make a copy, in case we page-fault in user space */ - memcpy(&stats, &dqstats, sizeof(struct dqstats)); - if (!copy_to_user(addr, &stats, sizeof(struct dqstats))) - error = 0; - return error; -} - -static int quota_root_squash(struct super_block *sb, short type, int *addr) -{ - int new_value, error; - - if (!sb) - return(-ENODEV); - - error = -EFAULT; - if (!copy_from_user(&new_value, addr, sizeof(int))) { - sb_dqopt(sb)->rsquash[type] = new_value; - error = 0; - } - return error; -} - -#if 0 /* We are not going to support filesystems without i_blocks... */ -/* - * This is a simple algorithm that calculates the size of a file in blocks. - * This is only used on filesystems that do not have an i_blocks count. - */ -static u_long isize_to_blocks(loff_t isize, size_t blksize_bits) -{ - u_long blocks; - u_long indirect; - - if (!blksize_bits) - blksize_bits = BLOCK_SIZE_BITS; - blocks = (isize >> blksize_bits) + ((isize & ~((1 << blksize_bits)-1)) ? 1 : 0); - if (blocks > 10) { - indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */ - if (blocks > (10 + 256)) { - indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */ - if (blocks > (10 + 256 + (256 << 8))) - indirect++; /* triple indirect blocks */ - } - blocks += indirect; - } - return blocks; -} -#endif - -/* * Externally referenced functions through dquot_operations in inode. * * Note: this is a blocking operation. */ -void dquot_initialize(struct inode *inode, short type) +void dquot_initialize(struct inode *inode, int type) { struct dquot *dquot[MAXQUOTAS]; unsigned int id = 0; - short cnt; + int cnt; if (IS_NOQUOTA(inode)) return; @@ -1002,7 +996,7 @@ void dquot_drop(struct inode *inode) { struct dquot *dquot; - short cnt; + int cnt; inode->i_flags &= ~S_QUOTA; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1017,7 +1011,7 @@ /* * This operation can block, but only after everything is updated */ -int dquot_alloc_block(struct inode *inode, unsigned long number, char warn) +int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) { int cnt, ret = NO_QUOTA; struct dquot *dquot[MAXQUOTAS]; @@ -1038,16 +1032,16 @@ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (dquot[cnt] == NODQUOT) continue; - dquot_incr_blocks(dquot[cnt], number); + dquot_incr_space(dquot[cnt], number); } - inode->i_blocks += number << (BLOCK_SIZE_BITS - 9); + inode_add_bytes(inode, number); /* NOBLOCK End */ ret = QUOTA_OK; warn_put_all: flush_warnings(dquot, warntype); for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (dquot[cnt] != NODQUOT) - dqput(dquot[cnt]); + dqputduplicate(dquot[cnt]); return ret; } @@ -1084,16 +1078,16 @@ flush_warnings(dquot, warntype); for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (dquot[cnt] != NODQUOT) - dqput(dquot[cnt]); + dqputduplicate(dquot[cnt]); return ret; } /* * This is a non-blocking operation. */ -void dquot_free_block(struct inode *inode, unsigned long number) +void dquot_free_space(struct inode *inode, qsize_t number) { - unsigned short cnt; + unsigned int cnt; struct dquot *dquot; /* NOBLOCK Start */ @@ -1101,10 +1095,10 @@ dquot = dqduplicate(inode->i_dquot[cnt]); if (dquot == NODQUOT) continue; - dquot_decr_blocks(dquot, number); - dqput(dquot); + dquot_decr_space(dquot, number); + dqputduplicate(dquot); } - inode->i_blocks -= number << (BLOCK_SIZE_BITS - 9); + inode_sub_bytes(inode, number); /* NOBLOCK End */ } @@ -1113,7 +1107,7 @@ */ void dquot_free_inode(const struct inode *inode, unsigned long number) { - unsigned short cnt; + unsigned int cnt; struct dquot *dquot; /* NOBLOCK Start */ @@ -1122,7 +1116,7 @@ if (dquot == NODQUOT) continue; dquot_decr_inodes(dquot, number); - dqput(dquot); + dqputduplicate(dquot); } /* NOBLOCK End */ } @@ -1134,7 +1128,7 @@ */ int dquot_transfer(struct inode *inode, struct iattr *iattr) { - unsigned long blocks; + qsize_t space; struct dquot *transfer_from[MAXQUOTAS]; struct dquot *transfer_to[MAXQUOTAS]; int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid, @@ -1164,7 +1158,7 @@ } } /* NOBLOCK START: From now on we shouldn't block */ - blocks = (inode->i_blocks >> 1); + space = inode_get_bytes(inode); /* Build the transfer_from list and check the limits */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { /* The second test can fail when quotaoff is in progress... */ @@ -1174,7 +1168,7 @@ if (transfer_from[cnt] == NODQUOT) /* Can happen on quotafiles (quota isn't initialized on them)... */ continue; if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA || - check_bdq(transfer_to[cnt], blocks, 0, warntype+cnt) == NO_QUOTA) + check_bdq(transfer_to[cnt], space, 0, warntype+cnt) == NO_QUOTA) goto warn_put_all; } @@ -1189,10 +1183,10 @@ continue; dquot_decr_inodes(transfer_from[cnt], 1); - dquot_decr_blocks(transfer_from[cnt], blocks); + dquot_decr_space(transfer_from[cnt], space); dquot_incr_inodes(transfer_to[cnt], 1); - dquot_incr_blocks(transfer_to[cnt], blocks); + dquot_incr_space(transfer_to[cnt], space); if (inode->i_dquot[cnt] == NODQUOT) BUG(); @@ -1208,39 +1202,29 @@ warn_put_all: flush_warnings(transfer_to, warntype); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + /* First we must put duplicate - otherwise we might deadlock */ if (transfer_to[cnt] != NODQUOT) - dqput(transfer_to[cnt]); + dqputduplicate(transfer_to[cnt]); if (transfer_from[cnt] != NODQUOT) dqput(transfer_from[cnt]); } return ret; } -static int __init dquot_init(void) -{ - int i; - - for (i = 0; i < NR_DQHASH; i++) - INIT_LIST_HEAD(dquot_hash + i); - printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__); - return 0; -} -__initcall(dquot_init); - /* * Definitions of diskquota operations. */ struct dquot_operations dquot_operations = { - dquot_initialize, /* mandatory */ - dquot_drop, /* mandatory */ - dquot_alloc_block, - dquot_alloc_inode, - dquot_free_block, - dquot_free_inode, - dquot_transfer + initialize: dquot_initialize, /* mandatory */ + drop: dquot_drop, /* mandatory */ + alloc_space: dquot_alloc_space, + alloc_inode: dquot_alloc_inode, + free_space: dquot_free_space, + free_inode: dquot_free_inode, + transfer: dquot_transfer }; -static inline void set_enable_flags(struct quota_mount_options *dqopt, short type) +static inline void set_enable_flags(struct quota_info *dqopt, int type) { switch (type) { case USRQUOTA: @@ -1252,7 +1236,7 @@ } } -static inline void reset_enable_flags(struct quota_mount_options *dqopt, short type) +static inline void reset_enable_flags(struct quota_info *dqopt, int type) { switch (type) { case USRQUOTA: @@ -1265,16 +1249,15 @@ } /* Function in inode.c - remove pointers to dquots in icache */ -extern void remove_dquot_ref(struct super_block *, short); +extern void remove_dquot_ref(struct super_block *, int); /* * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) */ -int quota_off(struct super_block *sb, short type) +int vfs_quota_off(struct super_block *sb, int type) { - struct file *filp; - short cnt; - struct quota_mount_options *dqopt = sb_dqopt(sb); + int cnt; + struct quota_info *dqopt = sb_dqopt(sb); lock_kernel(); if (!sb) @@ -1292,51 +1275,48 @@ /* Note: these are blocking operations */ remove_dquot_ref(sb, cnt); invalidate_dquots(sb, cnt); + if (info_dirty(&dqopt->info[cnt])) + dqopt->ops[cnt]->write_file_info(sb, cnt); + if (dqopt->ops[cnt]->free_file_info) + dqopt->ops[cnt]->free_file_info(sb, cnt); + put_quota_format(dqopt->info[cnt].dqi_format); - filp = dqopt->files[cnt]; + fput(dqopt->files[cnt]); dqopt->files[cnt] = (struct file *)NULL; - dqopt->inode_expire[cnt] = 0; - dqopt->block_expire[cnt] = 0; - fput(filp); - } + dqopt->info[cnt].dqi_flags = 0; + dqopt->info[cnt].dqi_igrace = 0; + dqopt->info[cnt].dqi_bgrace = 0; + dqopt->ops[cnt] = NULL; + } up(&dqopt->dqoff_sem); out: unlock_kernel(); return 0; } -static inline int check_quotafile_size(loff_t size) -{ - ulong blocks = size >> BLOCK_SIZE_BITS; - size_t off = size & (BLOCK_SIZE - 1); - - return !(((blocks % sizeof(struct dqblk)) * BLOCK_SIZE + off % sizeof(struct dqblk)) % sizeof(struct dqblk)); -} - -static int quota_on(struct super_block *sb, short type, char *path) +int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) { - struct file *f; + struct file *f = NULL; struct inode *inode; - struct dquot *dquot; - struct quota_mount_options *dqopt = sb_dqopt(sb); - char *tmp; + struct quota_info *dqopt = sb_dqopt(sb); + struct quota_format_type *fmt = find_quota_format(format_id); int error; - if (is_enabled(dqopt, type)) - return -EBUSY; + if (!fmt) + return -ESRCH; + if (is_enabled(dqopt, type)) { + error = -EBUSY; + goto out_fmt; + } down(&dqopt->dqoff_sem); - tmp = getname(path); - error = PTR_ERR(tmp); - if (IS_ERR(tmp)) - goto out_lock; - f = filp_open(tmp, O_RDWR, 0600); - putname(tmp); + f = filp_open(path, O_RDWR, 0600); error = PTR_ERR(f); if (IS_ERR(f)) goto out_lock; + dqopt->files[type] = f; error = -EIO; if (!f->f_op || !f->f_op->read || !f->f_op->write) goto out_f; @@ -1345,134 +1325,197 @@ if (!S_ISREG(inode->i_mode)) goto out_f; error = -EINVAL; - if (inode->i_size == 0 || !check_quotafile_size(inode->i_size)) + if (!fmt->qf_ops->check_quota_file(sb, type)) goto out_f; /* We don't want quota on quota files */ dquot_drop(inode); inode->i_flags |= S_NOQUOTA; - dqopt->files[type] = f; - sb->dq_op = &dquot_operations; + dqopt->ops[type] = fmt->qf_ops; + dqopt->info[type].dqi_format = fmt; + if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) + goto out_f; set_enable_flags(dqopt, type); - dquot = dqget(sb, 0, type); - dqopt->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME; - dqopt->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME; - dqput(dquot); - add_dquot_ref(sb, type); up(&dqopt->dqoff_sem); return 0; out_f: - filp_close(f, NULL); + if (f) + filp_close(f, NULL); + dqopt->files[type] = NULL; out_lock: up(&dqopt->dqoff_sem); +out_fmt: + put_quota_format(fmt); return error; } -/* - * This is the system call interface. This communicates with - * the user-level programs. Currently this only supports diskquota - * calls. Maybe we need to add the process quotas etc. in the future, - * but we probably should use rlimits for that. - */ -asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) +/* Generic routine for getting common part of quota structure */ +static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) { - int cmds = 0, type = 0, flags = 0; - kdev_t dev; - struct super_block *sb = NULL; - int ret = -EINVAL; + struct mem_dqblk *dm = &dquot->dq_dqb; - lock_kernel(); - cmds = cmd >> SUBCMDSHIFT; - type = cmd & SUBCMDMASK; + di->dqb_bhardlimit = dm->dqb_bhardlimit; + di->dqb_bsoftlimit = dm->dqb_bsoftlimit; + di->dqb_curspace = dm->dqb_curspace; + di->dqb_ihardlimit = dm->dqb_ihardlimit; + di->dqb_isoftlimit = dm->dqb_isoftlimit; + di->dqb_curinodes = dm->dqb_curinodes; + di->dqb_btime = dm->dqb_btime; + di->dqb_itime = dm->dqb_itime; + di->dqb_valid = QIF_ALL; +} - if ((u_int) type >= MAXQUOTAS) - goto out; - if (id & ~0xFFFF) - goto out; +int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +{ + struct dquot *dquot = dqget(sb, id, type); - ret = -EPERM; - switch (cmds) { - case Q_SYNC: - case Q_GETSTATS: - break; - case Q_GETQUOTA: - if (((type == USRQUOTA && current->euid != id) || - (type == GRPQUOTA && !in_egroup_p(id))) && - !capable(CAP_SYS_ADMIN)) - goto out; - break; - default: - if (!capable(CAP_SYS_ADMIN)) - goto out; - } - - ret = -EINVAL; - dev = NODEV; - if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) { - mode_t mode; - struct nameidata nd; - - ret = user_path_walk(special, &nd); - if (ret) - goto out; - - dev = nd.dentry->d_inode->i_rdev; - mode = nd.dentry->d_inode->i_mode; - path_release(&nd); - - ret = -ENOTBLK; - if (!S_ISBLK(mode)) - goto out; - ret = -ENODEV; - sb = get_super(dev); - if (!sb) - goto out; - } - - ret = -EINVAL; - switch (cmds) { - case Q_QUOTAON: - ret = quota_on(sb, type, (char *) addr); - goto out; - case Q_QUOTAOFF: - ret = quota_off(sb, type); - goto out; - case Q_GETQUOTA: - ret = get_quota(sb, id, type, (struct dqblk *) addr); - goto out; - case Q_SETQUOTA: - flags |= SET_QUOTA; - break; - case Q_SETUSE: - flags |= SET_USE; - break; - case Q_SETQLIM: - flags |= SET_QLIMIT; - break; - case Q_SYNC: - ret = sync_dquots(dev, type); - goto out; - case Q_GETSTATS: - ret = get_stats(addr); - goto out; - case Q_RSQUASH: - ret = quota_root_squash(sb, type, (int *) addr); - goto out; - default: - goto out; - } - - ret = -NODEV; - if (sb && sb_has_quota_enabled(sb, type)) - ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr); -out: - if (sb) - drop_super(sb); - unlock_kernel(); - return ret; + if (!dquot) + return -EINVAL; + do_get_dqblk(dquot, di); + dqput(dquot); + return 0; +} + +/* Generic routine for setting common part of quota structure */ +static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) +{ + struct mem_dqblk *dm = &dquot->dq_dqb; + int check_blim = 0, check_ilim = 0; + + if (di->dqb_valid & QIF_SPACE) { + dm->dqb_curspace = di->dqb_curspace; + check_blim = 1; + } + if (di->dqb_valid & QIF_BLIMITS) { + dm->dqb_bsoftlimit = di->dqb_bsoftlimit; + dm->dqb_bhardlimit = di->dqb_bhardlimit; + check_blim = 1; + } + if (di->dqb_valid & QIF_INODES) { + dm->dqb_curinodes = di->dqb_curinodes; + check_ilim = 1; + } + if (di->dqb_valid & QIF_ILIMITS) { + dm->dqb_isoftlimit = di->dqb_isoftlimit; + dm->dqb_ihardlimit = di->dqb_ihardlimit; + check_ilim = 1; + } + if (di->dqb_valid & QIF_BTIME) + dm->dqb_btime = di->dqb_btime; + if (di->dqb_valid & QIF_ITIME) + dm->dqb_itime = di->dqb_itime; + + if (check_blim) { + if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) { + dm->dqb_btime = 0; + dquot->dq_flags &= ~DQ_BLKS; + } + else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */ + dm->dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; + } + if (check_ilim) { + if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) { + dm->dqb_itime = 0; + dquot->dq_flags &= ~DQ_INODES; + } + else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */ + dm->dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; + } + if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit) + dquot->dq_flags &= ~DQ_FAKE; + else + dquot->dq_flags |= DQ_FAKE; + dquot->dq_flags |= DQ_MOD; +} + +int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +{ + struct dquot *dquot = dqget(sb, id, type); + + if (!dquot) + return -EINVAL; + do_set_dqblk(dquot, di); + dqput(dquot); + return 0; +} + +/* Generic routine for getting common part of quota file information */ +int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +{ + struct mem_dqinfo *mi = sb_dqopt(sb)->info + type; + + ii->dqi_bgrace = mi->dqi_bgrace; + ii->dqi_igrace = mi->dqi_igrace; + ii->dqi_flags = mi->dqi_flags & DQF_MASK; + ii->dqi_valid = IIF_ALL; + return 0; +} + +/* Generic routine for setting common part of quota file information */ +int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +{ + struct mem_dqinfo *mi = sb_dqopt(sb)->info + type; + + if (ii->dqi_valid & IIF_BGRACE) + mi->dqi_bgrace = ii->dqi_bgrace; + if (ii->dqi_valid & IIF_IGRACE) + mi->dqi_igrace = ii->dqi_igrace; + if (ii->dqi_valid & IIF_FLAGS) + mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK); + mark_info_dirty(mi); + return 0; +} + +struct quotactl_ops vfs_quotactl_ops = { + quota_on: vfs_quota_on, + quota_off: vfs_quota_off, + quota_sync: vfs_quota_sync, + get_info: vfs_get_dqinfo, + set_info: vfs_set_dqinfo, + get_dqblk: vfs_get_dqblk, + set_dqblk: vfs_set_dqblk +}; + +static ctl_table fs_dqstats_table[] = { + {FS_DQ_LOOKUPS, "lookups", &dqstats.lookups, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_DROPS, "drops", &dqstats.drops, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_READS, "reads", &dqstats.reads, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_WRITES, "writes", &dqstats.writes, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_CACHE_HITS, "cache_hits", &dqstats.cache_hits, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_ALLOCATED, "allocated_dquots", &dqstats.allocated_dquots, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_FREE, "free_dquots", &dqstats.free_dquots, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_SYNCS, "syncs", &dqstats.syncs, sizeof(int), 0444, NULL, &proc_dointvec}, + {}, +}; + +static ctl_table fs_table[] = { + {FS_DQSTATS, "quota", NULL, 0, 0555, fs_dqstats_table}, + {}, +}; + +static ctl_table sys_table[] = { + {CTL_FS, "fs", NULL, 0, 0555, fs_table}, + {}, +}; + +static int __init dquot_init(void) +{ + int i; + + register_sysctl_table(sys_table, 0); + for (i = 0; i < NR_DQHASH; i++) + INIT_LIST_HEAD(dquot_hash + i); + printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__); + + return 0; } +__initcall(dquot_init); + +EXPORT_SYMBOL(register_quota_format); +EXPORT_SYMBOL(unregister_quota_format); +EXPORT_SYMBOL(dqstats); diff -Nur linux-2.4.19/fs/exec.c linux-2.4.19-sgi211r3/fs/exec.c --- linux-2.4.19/fs/exec.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/exec.c Wed Feb 5 20:48:13 2003 @@ -37,6 +37,7 @@ #include #define __NO_VERSION__ #include +#include #include #include @@ -313,12 +314,15 @@ mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = STACK_TOP; - mpnt->vm_page_prot = PAGE_COPY; + mpnt->vm_page_prot = protection_map[VM_STACK_FLAGS & 0x7]; mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_ops = NULL; mpnt->vm_pgoff = 0; mpnt->vm_file = NULL; mpnt->vm_private_data = (void *) 0; +#ifdef CONFIG_CPUMEMSET + mpnt->vm_mems_allowed = cms_current_mems_allowed(); +#endif insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } @@ -904,9 +908,13 @@ goto out; retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + if (retval >= 0) { /* execve success */ + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); return retval; + } out: /* Something went wrong, return the inode and free the argument pages*/ diff -Nur linux-2.4.19/fs/ext2/balloc.c linux-2.4.19-sgi211r3/fs/ext2/balloc.c --- linux-2.4.19/fs/ext2/balloc.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-sgi211r3/fs/ext2/balloc.c Mon Oct 28 20:43:23 2002 @@ -539,6 +539,7 @@ */ #ifdef EXT2_PREALLOCATE /* Writer: ->i_prealloc* */ + write_lock(&inode->u.ext2_i.i_meta_lock); if (prealloc_count && !*prealloc_count) { int prealloc_goal; unsigned long next_block = tmp + 1; @@ -576,8 +577,8 @@ ext2_debug ("Preallocated a further %lu bits.\n", (k - 1)); } + write_unlock(&inode->u.ext2_i.i_meta_lock); #endif - j = tmp; mark_buffer_dirty(bh); diff -Nur linux-2.4.19/fs/ext2/ialloc.c linux-2.4.19-sgi211r3/fs/ext2/ialloc.c --- linux-2.4.19/fs/ext2/ialloc.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-sgi211r3/fs/ext2/ialloc.c Mon Oct 28 20:43:23 2002 @@ -392,6 +392,7 @@ inode->u.ext2_i.i_block_group = group; if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) inode->i_flags |= S_SYNC; + rwlock_init(&inode->u.ext2_i.i_meta_lock); insert_inode_hash(inode); inode->i_generation = event++; mark_inode_dirty(inode); diff -Nur linux-2.4.19/fs/ext2/inode.c linux-2.4.19-sgi211r3/fs/ext2/inode.c --- linux-2.4.19/fs/ext2/inode.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/ext2/inode.c Mon Oct 28 20:43:23 2002 @@ -51,8 +51,6 @@ */ void ext2_delete_inode (struct inode * inode) { - lock_kernel(); - if (is_bad_inode(inode) || inode->i_ino == EXT2_ACL_IDX_INO || inode->i_ino == EXT2_ACL_DATA_INO) @@ -60,6 +58,8 @@ inode->u.ext2_i.i_dtime = CURRENT_TIME; mark_inode_dirty(inode); ext2_update_inode(inode, IS_SYNC(inode)); + + lock_kernel(); inode->i_size = 0; if (inode->i_blocks) ext2_truncate (inode); @@ -68,24 +68,26 @@ unlock_kernel(); return; no_delete: - unlock_kernel(); clear_inode(inode); /* We must guarantee clearing of inode... */ } void ext2_discard_prealloc (struct inode * inode) { #ifdef EXT2_PREALLOCATE - lock_kernel(); + write_lock(&inode->u.ext2_i.i_meta_lock); /* Writer: ->i_prealloc* */ if (inode->u.ext2_i.i_prealloc_count) { unsigned short total = inode->u.ext2_i.i_prealloc_count; unsigned long block = inode->u.ext2_i.i_prealloc_block; inode->u.ext2_i.i_prealloc_count = 0; inode->u.ext2_i.i_prealloc_block = 0; + write_unlock(&inode->u.ext2_i.i_meta_lock); /* Writer: end */ ext2_free_blocks (inode, block, total); + } else { + write_unlock(&inode->u.ext2_i.i_meta_lock); } - unlock_kernel(); + #endif } @@ -99,6 +101,7 @@ #ifdef EXT2_PREALLOCATE /* Writer: ->i_prealloc* */ + write_lock(&inode->u.ext2_i.i_meta_lock); if (inode->u.ext2_i.i_prealloc_count && (goal == inode->u.ext2_i.i_prealloc_block || goal + 1 == inode->u.ext2_i.i_prealloc_block)) @@ -106,9 +109,11 @@ result = inode->u.ext2_i.i_prealloc_block++; inode->u.ext2_i.i_prealloc_count--; /* Writer: end */ + write_unlock(&inode->u.ext2_i.i_meta_lock); ext2_debug ("preallocation hit (%lu/%lu).\n", ++alloc_hits, ++alloc_attempts); } else { + write_unlock(&inode->u.ext2_i.i_meta_lock); ext2_discard_prealloc (inode); ext2_debug ("preallocation miss (%lu/%lu).\n", alloc_hits, ++alloc_attempts); @@ -253,9 +258,11 @@ if (!bh) goto failure; /* Reader: pointers */ + read_lock(&inode->u.ext2_i.i_meta_lock); if (!verify_chain(chain, p)) goto changed; add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + read_unlock(&inode->u.ext2_i.i_meta_lock); /* Reader: end */ if (!p->key) goto no_block; @@ -263,6 +270,7 @@ return NULL; changed: + read_unlock(&inode->u.ext2_i.i_meta_lock); *err = -EAGAIN; goto no_block; failure: @@ -328,6 +336,8 @@ unsigned long *goal) { /* Writer: ->i_next_alloc* */ + + write_lock(&inode->u.ext2_i.i_meta_lock); if (block == inode->u.ext2_i.i_next_alloc_block + 1) { inode->u.ext2_i.i_next_alloc_block++; inode->u.ext2_i.i_next_alloc_goal++; @@ -343,9 +353,11 @@ *goal = inode->u.ext2_i.i_next_alloc_goal; if (!*goal) *goal = ext2_find_near(inode, partial); + write_unlock(&inode->u.ext2_i.i_meta_lock); return 0; } /* Reader: end */ + write_unlock(&inode->u.ext2_i.i_meta_lock); return -EAGAIN; } @@ -451,6 +463,7 @@ /* Verify that place we are splicing to is still there and vacant */ + write_lock(&inode->u.ext2_i.i_meta_lock); /* Writer: pointers, ->i_next_alloc* */ if (!verify_chain(chain, where-1) || *where->p) /* Writer: end */ @@ -461,7 +474,7 @@ *where->p = where->key; inode->u.ext2_i.i_next_alloc_block = block; inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key); - + write_unlock(&inode->u.ext2_i.i_meta_lock); /* Writer: end */ /* We are done with atomic stuff, now do the rest of housekeeping */ @@ -476,6 +489,7 @@ return 0; changed: + write_unlock(&inode->u.ext2_i.i_meta_lock); for (i = 1; i < num; i++) bforget(where[i].bh); for (i = 0; i < num; i++) @@ -509,7 +523,6 @@ if (depth == 0) goto out; - lock_kernel(); reread: partial = ext2_get_branch(inode, depth, offsets, chain, &err); @@ -531,7 +544,6 @@ brelse(partial->bh); partial--; } - unlock_kernel(); out: return err; } @@ -932,6 +944,7 @@ inode->i_ctime = le32_to_cpu(raw_inode->i_ctime); inode->i_mtime = le32_to_cpu(raw_inode->i_mtime); inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime); + rwlock_init(&inode->u.ext2_i.i_meta_lock); /* We now have enough fields to check if the inode was active or not. * This is needed because nfsd might try to access dead inodes * the test is that same one that e2fsck uses @@ -1139,9 +1152,7 @@ void ext2_write_inode (struct inode * inode, int wait) { - lock_kernel(); ext2_update_inode (inode, wait); - unlock_kernel(); } int ext2_sync_inode (struct inode *inode) diff -Nur linux-2.4.19/fs/ext3/inode.c linux-2.4.19-sgi211r3/fs/ext3/inode.c --- linux-2.4.19/fs/ext3/inode.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/ext3/inode.c Mon Oct 28 20:43:23 2002 @@ -2367,6 +2367,8 @@ return error; } + lock_kernel(); + if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; @@ -2394,6 +2396,7 @@ err_out: ext3_std_error(inode->i_sb, error); + unlock_kernel(); if (!error) error = rc; return error; diff -Nur linux-2.4.19/fs/fat/dir.c linux-2.4.19-sgi211r3/fs/fat/dir.c --- linux-2.4.19/fs/fat/dir.c Fri Oct 12 13:48:42 2001 +++ linux-2.4.19-sgi211r3/fs/fat/dir.c Mon Oct 28 20:43:23 2002 @@ -539,7 +539,7 @@ inum = inode->i_ino; else if (!memcmp(de->name,MSDOS_DOTDOT,11)) { /* inum = fat_parent_ino(inode,0); */ - inum = filp->f_dentry->d_parent->d_inode->i_ino; + inum = parent_ino(filp->f_dentry); } else { struct inode *tmp = fat_iget(sb, ino); if (tmp) { diff -Nur linux-2.4.19/fs/fat/inode.c linux-2.4.19-sgi211r3/fs/fat/inode.c --- linux-2.4.19/fs/fat/inode.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/fat/inode.c Wed Dec 11 20:43:45 2002 @@ -521,7 +521,9 @@ fh[1] = inode->i_generation; fh[2] = MSDOS_I(inode)->i_location; fh[3] = MSDOS_I(inode)->i_logstart; + read_lock(&dparent_lock); fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart; + read_unlock(&dparent_lock); return 3; } @@ -1025,17 +1027,24 @@ { struct super_block *sb = dentry->d_sb; struct inode *inode = dentry->d_inode; - int error; + int error = 0; + + lock_kernel(); /* FAT cannot truncate to a longer file */ if (attr->ia_valid & ATTR_SIZE) { - if (attr->ia_size > inode->i_size) - return -EPERM; + if (attr->ia_size > inode->i_size) { + error = -EPERM; + goto out; + } } error = inode_change_ok(inode, attr); - if (error) - return MSDOS_SB(sb)->options.quiet ? 0 : error; + if (error) { + if( MSDOS_SB(sb)->options.quiet ) + error = 0; + goto out; + } if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != MSDOS_SB(sb)->options.fs_uid)) || @@ -1045,12 +1054,14 @@ (attr->ia_mode & ~MSDOS_VALID_MODE))) error = -EPERM; - if (error) - return MSDOS_SB(sb)->options.quiet ? 0 : error; - + if (error) { + if( MSDOS_SB(sb)->options.quiet ) + error = 0; + goto out; + } error = inode_setattr(inode, attr); if (error) - return error; + goto out; if (S_ISDIR(inode->i_mode)) inode->i_mode |= S_IXUGO; @@ -1058,6 +1069,8 @@ inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU & ~MSDOS_SB(sb)->options.fs_umask) | S_IRUSR) >> 6)*S_IXUGO)) & ~MSDOS_SB(sb)->options.fs_umask; - return 0; +out: + unlock_kernel(); + return error; } MODULE_LICENSE("GPL"); diff -Nur linux-2.4.19/fs/fcntl.c linux-2.4.19-sgi211r3/fs/fcntl.c --- linux-2.4.19/fs/fcntl.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/fcntl.c Wed Oct 16 14:02:58 2002 @@ -293,6 +293,7 @@ * to fix this will be in libc. */ err = filp->f_owner.pid; + force_successful_syscall_return(); break; case F_SETOWN: lock_kernel(); diff -Nur linux-2.4.19/fs/file_table.c linux-2.4.19-sgi211r3/fs/file_table.c --- linux-2.4.19/fs/file_table.c Mon Sep 17 13:16:30 2001 +++ linux-2.4.19-sgi211r3/fs/file_table.c Thu Dec 19 08:34:59 2002 @@ -186,3 +186,17 @@ file_list_unlock(); return 0; } + +void __init files_init(unsigned long mempages) +{ + int n; + /* One file with associated inode and dcache is very roughly 1K. + * Per default don't use more than 10% of our memory for files. + */ + + n = (mempages * (PAGE_SIZE / 1024)) / 10; + files_stat.max_files = n; + if (files_stat.max_files < NR_FILE) + files_stat.max_files = NR_FILE; +} + diff -Nur linux-2.4.19/fs/hfs/file_cap.c linux-2.4.19-sgi211r3/fs/hfs/file_cap.c --- linux-2.4.19/fs/hfs/file_cap.c Mon Sep 10 07:31:25 2001 +++ linux-2.4.19-sgi211r3/fs/hfs/file_cap.c Mon Oct 28 20:43:23 2002 @@ -24,6 +24,7 @@ #include #include #include +#include /*================ Forward declarations ================*/ static loff_t cap_info_llseek(struct file *, loff_t, @@ -91,6 +92,7 @@ { long long retval; + lock_kernel(); switch (origin) { case 2: offset += file->f_dentry->d_inode->i_size; @@ -107,6 +109,7 @@ } retval = offset; } + unlock_kernel(); return retval; } diff -Nur linux-2.4.19/fs/hfs/file_hdr.c linux-2.4.19-sgi211r3/fs/hfs/file_hdr.c --- linux-2.4.19/fs/hfs/file_hdr.c Sun Aug 12 10:56:56 2001 +++ linux-2.4.19-sgi211r3/fs/hfs/file_hdr.c Mon Oct 28 20:43:23 2002 @@ -29,6 +29,7 @@ #include #include #include +#include /* prodos types */ #define PRODOSI_FTYPE_DIR 0x0F @@ -347,6 +348,7 @@ { long long retval; + lock_kernel(); switch (origin) { case 2: offset += file->f_dentry->d_inode->i_size; @@ -363,6 +365,7 @@ } retval = offset; } + unlock_kernel(); return retval; } diff -Nur linux-2.4.19/fs/hfs/inode.c linux-2.4.19-sgi211r3/fs/hfs/inode.c --- linux-2.4.19/fs/hfs/inode.c Wed Sep 12 15:34:06 2001 +++ linux-2.4.19-sgi211r3/fs/hfs/inode.c Mon Oct 28 20:43:23 2002 @@ -117,17 +117,18 @@ struct hfs_cat_entry *entry = HFS_I(inode)->entry; struct dentry **de = entry->sys_entry; struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); - int error, i; + int error=0, i; + + lock_kernel(); error = inode_change_ok(inode, attr); /* basic permission checks */ if (error) { /* Let netatalk's afpd think chmod() always succeeds */ if (hsb->s_afpd && (attr->ia_valid == (ATTR_MODE | ATTR_CTIME))) { - return 0; - } else { - return error; + error = 0; } + goto out; } /* no uig/gid changes and limit which mode bits can be set */ @@ -139,7 +140,10 @@ (((entry->type == HFS_CDR_DIR) && (attr->ia_mode != inode->i_mode))|| (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) { - return hsb->s_quiet ? 0 : error; + if( hsb->s_quiet ) { + error = 0; + goto out; + } } if (entry->type == HFS_CDR_DIR) { @@ -170,9 +174,9 @@ } } error = inode_setattr(inode, attr); - if (error) - return error; - + if (error) + goto out; + /* We wouldn't want to mess with the sizes of the other fork */ attr->ia_valid &= ~ATTR_SIZE; @@ -204,7 +208,9 @@ } /* size changes handled in hfs_extent_adj() */ - return 0; +out: + unlock_kernel(); + return error; } int hfs_notify_change(struct dentry *dentry, struct iattr * attr) diff -Nur linux-2.4.19/fs/hpfs/dir.c linux-2.4.19-sgi211r3/fs/hpfs/dir.c --- linux-2.4.19/fs/hpfs/dir.c Mon Jun 11 19:15:27 2001 +++ linux-2.4.19-sgi211r3/fs/hpfs/dir.c Mon Oct 28 20:43:23 2002 @@ -29,6 +29,7 @@ struct inode *i = filp->f_dentry->d_inode; struct super_block *s = i->i_sb; /*printk("dir lseek\n");*/ + lock_kernel(); if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok; hpfs_lock_inode(i); pos = ((loff_t) hpfs_de_as_down_as_possible(s, i->i_hpfs_dno) << 4) + 1; @@ -39,10 +40,12 @@ } hpfs_unlock_inode(i); ok: + unlock_kernel(); return filp->f_pos = new_off; fail: hpfs_unlock_inode(i); /*printk("illegal lseek: %016llx\n", new_off);*/ + unlock_kernel(); return -ESPIPE; } diff -Nur linux-2.4.19/fs/hpfs/inode.c linux-2.4.19-sgi211r3/fs/hpfs/inode.c --- linux-2.4.19/fs/hpfs/inode.c Mon Sep 10 07:31:25 2001 +++ linux-2.4.19-sgi211r3/fs/hpfs/inode.c Mon Oct 28 20:43:23 2002 @@ -299,15 +299,18 @@ int hpfs_notify_change(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - int error; - if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) - return -EINVAL; - if (inode->i_sb->s_hpfs_root == inode->i_ino) return -EINVAL; - if ((error = inode_change_ok(inode, attr))) return error; - error = inode_setattr(inode, attr); - if (error) return error; - hpfs_write_inode(inode); - return 0; + int error=0; + lock_kernel(); + if ( ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) || + (inode->i_sb->s_hpfs_root == inode->i_ino) ) { + error = -EINVAL; + } else if ((error = inode_change_ok(inode, attr))) { + } else if ((error = inode_setattr(inode, attr))) { + } else { + hpfs_write_inode(inode); + } + unlock_kernel(); + return error; } void hpfs_write_if_changed(struct inode *inode) diff -Nur linux-2.4.19/fs/hpfs/namei.c linux-2.4.19-sgi211r3/fs/hpfs/namei.c --- linux-2.4.19/fs/hpfs/namei.c Fri Dec 29 14:07:57 2000 +++ linux-2.4.19-sgi211r3/fs/hpfs/namei.c Mon Oct 28 20:43:23 2002 @@ -340,11 +340,9 @@ goto ret; } /*printk("HPFS: truncating file before delete.\n");*/ - down(&inode->i_sem); newattrs.ia_size = 0; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; err = notify_change(dentry, &newattrs); - up(&inode->i_sem); put_write_access(inode); if (err) goto ret; diff -Nur linux-2.4.19/fs/inode.c linux-2.4.19-sgi211r3/fs/inode.c --- linux-2.4.19/fs/inode.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/inode.c Wed Oct 16 14:02:58 2002 @@ -75,13 +75,60 @@ static kmem_cache_t * inode_cachep; -#define alloc_inode() \ - ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL)) +static struct inode *alloc_inode(struct super_block *sb) +{ + static struct address_space_operations empty_aops; + static struct inode_operations empty_iops; + static struct file_operations empty_fops; + struct inode *inode; + + if (sb->s_op->alloc_inode) + inode = sb->s_op->alloc_inode(sb); + else { + inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL); + /* will die */ + if (inode) + memset(&inode->u, 0, sizeof(inode->u)); + } + + if (inode) { + struct address_space * const mapping = &inode->i_data; + + inode->i_sb = sb; + inode->i_dev = sb->s_dev; + inode->i_blkbits = sb->s_blocksize_bits; + inode->i_flags = 0; + atomic_set(&inode->i_count, 1); + inode->i_sock = 0; + inode->i_op = &empty_iops; + inode->i_fop = &empty_fops; + inode->i_nlink = 1; + atomic_set(&inode->i_writecount, 0); + inode->i_size = 0; + inode->i_blocks = 0; + inode->i_bytes = 0; + inode->i_generation = 0; + memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); + inode->i_pipe = NULL; + inode->i_bdev = NULL; + inode->i_cdev = NULL; + + mapping->a_ops = &empty_aops; + mapping->host = inode; + mapping->gfp_mask = GFP_HIGHUSER; + inode->i_mapping = mapping; + } + return inode; +} + static void destroy_inode(struct inode *inode) { if (inode_has_buffers(inode)) BUG(); - kmem_cache_free(inode_cachep, (inode)); + if (inode->i_sb->s_op->destroy_inode) + inode->i_sb->s_op->destroy_inode(inode); + else + kmem_cache_free(inode_cachep, inode); } @@ -90,27 +137,30 @@ * once, because the fields are idempotent across use * of the inode, so let the slab aware of that. */ +void inode_init_once(struct inode *inode) +{ + memset(inode, 0, sizeof(*inode)); + init_waitqueue_head(&inode->i_wait); + INIT_LIST_HEAD(&inode->i_hash); + INIT_LIST_HEAD(&inode->i_data.clean_pages); + INIT_LIST_HEAD(&inode->i_data.dirty_pages); + INIT_LIST_HEAD(&inode->i_data.locked_pages); + INIT_LIST_HEAD(&inode->i_dentry); + INIT_LIST_HEAD(&inode->i_dirty_buffers); + INIT_LIST_HEAD(&inode->i_dirty_data_buffers); + INIT_LIST_HEAD(&inode->i_devices); + sema_init(&inode->i_sem, 1); + sema_init(&inode->i_zombie, 1); + spin_lock_init(&inode->i_data.i_shared_lock); +} + static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) { struct inode * inode = (struct inode *) foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) - { - memset(inode, 0, sizeof(*inode)); - init_waitqueue_head(&inode->i_wait); - INIT_LIST_HEAD(&inode->i_hash); - INIT_LIST_HEAD(&inode->i_data.clean_pages); - INIT_LIST_HEAD(&inode->i_data.dirty_pages); - INIT_LIST_HEAD(&inode->i_data.locked_pages); - INIT_LIST_HEAD(&inode->i_dentry); - INIT_LIST_HEAD(&inode->i_dirty_buffers); - INIT_LIST_HEAD(&inode->i_dirty_data_buffers); - INIT_LIST_HEAD(&inode->i_devices); - sema_init(&inode->i_sem, 1); - sema_init(&inode->i_zombie, 1); - spin_lock_init(&inode->i_data.i_shared_lock); - } + inode_init_once(inode); } /* @@ -757,76 +807,46 @@ return inode; } -/* - * This just initializes the inode fields - * to known values before returning the inode.. - * - * i_sb, i_ino, i_count, i_state and the lists have - * been initialized elsewhere.. - */ -static void clean_inode(struct inode *inode) -{ - static struct address_space_operations empty_aops; - static struct inode_operations empty_iops; - static struct file_operations empty_fops; - memset(&inode->u, 0, sizeof(inode->u)); - inode->i_sock = 0; - inode->i_op = &empty_iops; - inode->i_fop = &empty_fops; - inode->i_nlink = 1; - atomic_set(&inode->i_writecount, 0); - inode->i_size = 0; - inode->i_blocks = 0; - inode->i_generation = 0; - memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); - inode->i_pipe = NULL; - inode->i_bdev = NULL; - inode->i_cdev = NULL; - inode->i_data.a_ops = &empty_aops; - inode->i_data.host = inode; - inode->i_data.gfp_mask = GFP_HIGHUSER; - inode->i_mapping = &inode->i_data; -} - /** - * get_empty_inode - obtain an inode - * - * This is called by things like the networking layer - * etc that want to get an inode without any inode - * number, or filesystems that allocate new inodes with - * no pre-existing information. + * new_inode - obtain an inode + * @sb: superblock * - * On a successful return the inode pointer is returned. On a failure - * a %NULL pointer is returned. The returned inode is not on any superblock - * lists. + * Allocates a new inode for given superblock. */ -struct inode * get_empty_inode(void) +struct inode * new_inode(struct super_block *sb) { static unsigned long last_ino; struct inode * inode; spin_lock_prefetch(&inode_lock); - inode = alloc_inode(); - if (inode) - { + inode = alloc_inode(sb); + if (inode) { spin_lock(&inode_lock); inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); - inode->i_sb = NULL; - inode->i_dev = 0; - inode->i_blkbits = 0; inode->i_ino = ++last_ino; - inode->i_flags = 0; - atomic_set(&inode->i_count, 1); inode->i_state = 0; spin_unlock(&inode_lock); - clean_inode(inode); } return inode; } +void unlock_new_inode(struct inode *inode) +{ + /* + * This is special! We do not need the spinlock + * when clearing I_LOCK, because we're guaranteed + * that nobody else tries to do anything about the + * state of the inode when it is locked, as we + * just created it (so there can be no old holders + * that haven't tested I_LOCK). + */ + inode->i_state &= ~(I_LOCK|I_NEW); + wake_up(&inode->i_wait); +} + /* * This is called without the inode lock held.. Be careful. * @@ -837,7 +857,7 @@ { struct inode * inode; - inode = alloc_inode(); + inode = alloc_inode(sb); if (inode) { struct inode * old; @@ -848,39 +868,14 @@ inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); list_add(&inode->i_hash, head); - inode->i_sb = sb; - inode->i_dev = sb->s_dev; - inode->i_blkbits = sb->s_blocksize_bits; inode->i_ino = ino; - inode->i_flags = 0; - atomic_set(&inode->i_count, 1); - inode->i_state = I_LOCK; + inode->i_state = I_LOCK|I_NEW; spin_unlock(&inode_lock); - clean_inode(inode); - - /* reiserfs specific hack right here. We don't - ** want this to last, and are looking for VFS changes - ** that will allow us to get rid of it. - ** -- mason@suse.com - */ - if (sb->s_op->read_inode2) { - sb->s_op->read_inode2(inode, opaque) ; - } else { - sb->s_op->read_inode(inode); - } - /* - * This is special! We do not need the spinlock - * when clearing I_LOCK, because we're guaranteed - * that nobody else tries to do anything about the - * state of the inode when it is locked, as we - * just created it (so there can be no old holders - * that haven't tested I_LOCK). + * Return the locked inode with I_NEW set, the + * caller is responsible for filling in the contents */ - inode->i_state &= ~I_LOCK; - wake_up(&inode->i_wait); - return inode; } @@ -960,8 +955,7 @@ return inode; } - -struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque) +struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque) { struct list_head * head = inode_hashtable + hash(sb,ino); struct inode * inode; @@ -1203,9 +1197,9 @@ /* Functions back in dquot.c */ void put_dquot_list(struct list_head *); -int remove_inode_dquot_ref(struct inode *, short, struct list_head *); +int remove_inode_dquot_ref(struct inode *, int, struct list_head *); -void remove_dquot_ref(struct super_block *sb, short type) +void remove_dquot_ref(struct super_block *sb, int type) { struct inode *inode; struct list_head *act_head; diff -Nur linux-2.4.19/fs/intermezzo/dir.c linux-2.4.19-sgi211r3/fs/intermezzo/dir.c --- linux-2.4.19/fs/intermezzo/dir.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-sgi211r3/fs/intermezzo/dir.c Mon Oct 28 20:43:23 2002 @@ -272,11 +272,13 @@ struct presto_file_set *fset; struct lento_vfs_context info = { 0, 0, 0 }; + lock_kernel(); + ENTRY; error = presto_prep(de, &cache, &fset); if ( error ) { EXIT; - return error; + goto out; } if (!iattr->ia_valid) @@ -290,7 +292,8 @@ if ( presto_get_permit(de->d_inode) < 0 ) { EXIT; - return -EROFS; + error = -EROFS; + goto out; } if (!ISLENTO(presto_c2m(cache))) @@ -298,6 +301,8 @@ info.flags |= LENTO_FL_IGNORE_TIME; error = presto_do_setattr(fset, de, iattr, &info); presto_put_permit(de->d_inode); +out: + unlock_kernel(); return error; } diff -Nur linux-2.4.19/fs/intermezzo/journal_xfs.c linux-2.4.19-sgi211r3/fs/intermezzo/journal_xfs.c --- linux-2.4.19/fs/intermezzo/journal_xfs.c Tue Nov 13 09:20:56 2001 +++ linux-2.4.19-sgi211r3/fs/intermezzo/journal_xfs.c Wed Jan 30 16:28:11 2002 @@ -15,6 +15,8 @@ #include #include #include +#if 0 +/* XFS support not there yet... */ #ifdef CONFIG_FS_XFS #include #endif @@ -133,5 +135,5 @@ }; #endif /* CONFIG_XFS_FS */ - +#endif /* 0 */ diff -Nur linux-2.4.19/fs/intermezzo/vfs.c linux-2.4.19-sgi211r3/fs/intermezzo/vfs.c --- linux-2.4.19/fs/intermezzo/vfs.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/intermezzo/vfs.c Wed Oct 16 14:02:58 2002 @@ -55,7 +55,7 @@ #ifdef CONFIG_FS_EXT_ATTR #include -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_INTERMEZZO_FS_POSIX_ACL #include #endif #endif @@ -317,7 +317,7 @@ struct dentry *dentry; struct presto_file_set *fset; int error; -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_INTERMEZZO_FS_POSIX_ACL int (*set_posix_acl)(struct inode *, int type, posix_acl_t *)=NULL; #endif @@ -358,7 +358,7 @@ (dentry->d_inode->i_mode & ~S_IALLUGO); CDEBUG(D_PIOCTL, "chmod: orig %#o, set %#o, result %#o\n", dentry->d_inode->i_mode, set_mode, iattr->ia_mode); -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_INTERMEZZO_FS_POSIX_ACL /* ACl code interacts badly with setattr * since it tries to modify the ACL using * set_ext_attr which recurses back into presto. @@ -378,7 +378,7 @@ error = presto_do_setattr(fset, dentry, iattr, info); -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_INTERMEZZO_FS_POSIX_ACL /* restore the inode_operations if we changed them*/ if (iattr->ia_valid & ATTR_MODE) dentry->d_inode->i_op->set_posix_acl=set_posix_acl; @@ -2129,7 +2129,7 @@ #ifdef CONFIG_FS_EXT_ATTR -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_INTERMEZZO_FS_POSIX_ACL /* Posix ACL code changes i_mode without using a notify_change (or * a mark_inode_dirty!). We need to duplicate this at the reintegrator * which is done by this function. This function also takes care of @@ -2272,7 +2272,7 @@ goto exit; } -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_INTERMEZZO_FS_POSIX_ACL /* Reset mode if specified*/ /* XXX: when we do native acl support, move this code out! */ if (mode != NULL) { diff -Nur linux-2.4.19/fs/iobuf.c linux-2.4.19-sgi211r3/fs/iobuf.c --- linux-2.4.19/fs/iobuf.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/iobuf.c Thu Oct 24 05:25:29 2002 @@ -4,13 +4,31 @@ * Keep track of the general-purpose IO-buffer structures used to track * abstract kernel-space io buffers. * + * 07/20/01 Rohit Seth Made the iobuf come from + * kiobuf cache instead of vmalloc (that is a killer for most of archs.) These + * changes are specifically targeted for increasing raw IO performance. + * Introducing the new *_sz functions that take the number of bhs actually + * required by kiovec. + * 12/11/01 Jesse Barnes added wrapper functions to preserve + * source compatibility as well as comments. */ #include #include -#include +#include -void end_kio_request(struct kiobuf *kiobuf, int uptodate) +static kmem_cache_t *kiobuf_cachep; + +/** + * end_kio_request - indicate completion of a kio request + * @kiobuf: the kiobuf that was completed + * @uptodate: request up to date? + * + * Indicates completion of a kio request and calls the + * end_io() routine of the kiobuf (if there is one). + */ +void +end_kio_request(struct kiobuf *kiobuf, int uptodate) { if ((!uptodate) && !kiobuf->errno) kiobuf->errno = -EIO; @@ -18,26 +36,80 @@ if (atomic_dec_and_test(&kiobuf->io_count)) { if (kiobuf->end_io) kiobuf->end_io(kiobuf); +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + /* + * The callback isn't responsible for + * waking up the sleeper, we are. + * + * If we are dumping and the dump was + * started while we are in an idle thread + * it seems the wake_up() call will put + * the idle task on the runqueue which + * leads to all sorts of problems. + * + * If dump_in_progress has been set + * the scheduler has been disabled, so + * we can just skip the call for dump + * I/O and we don't want to disturb the + * other threads; they are froozen. + */ + if(!dump_in_progress) { + wake_up(&kiobuf->wait_queue); + } +#else wake_up(&kiobuf->wait_queue); +#endif } } -static void kiobuf_init(struct kiobuf *iobuf) +/** + * kiobuf_setup - setup a cache for kiobuf objects + * + * Called in init/main.c to setup a slab cache for kiobuf objects. + */ +void __init +kiobuf_setup(void) +{ + kiobuf_cachep = kmem_cache_create("kiobuf", + sizeof(struct kiobuf), + 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if(!kiobuf_cachep) + panic("Cannot create kernel iobuf cache\n"); + return 0; +} + +/** + * kiobuf_init - setup a kiobuf + * + * Initializes various fields of the kiobuf that's passed in. + * Used by alloc_kiovec_sz(). + */ +static void +kiobuf_init(struct kiobuf *iobuf) { init_waitqueue_head(&iobuf->wait_queue); iobuf->array_len = KIO_STATIC_PAGES; - iobuf->maplist = iobuf->map_array; + iobuf->maplist = iobuf->map_array; iobuf->nr_pages = 0; iobuf->locked = 0; atomic_set(&iobuf->io_count, 0); iobuf->end_io = NULL; } -int alloc_kiobuf_bhs(struct kiobuf * kiobuf) +/** + * alloc_kiobuf_bhs_sz - allocate buffer_heads for a kiobuf + * @kiobuf: kiobuf to allocate buffer_heads for + * @sz: number of buffer_heads to allocate + * + * Allocates @sz buffer heads for the @kiobuf. + */ +int +alloc_kiobuf_bhs_sz(struct kiobuf * kiobuf, int sz) { int i; - for (i = 0; i < KIO_MAX_SECTORS; i++) + for (i = 0; i < sz; i++) if (!(kiobuf->bh[i] = kmem_cache_alloc(bh_cachep, SLAB_KERNEL))) { while (i--) { kmem_cache_free(bh_cachep, kiobuf->bh[i]); @@ -48,43 +120,114 @@ return 0; } -void free_kiobuf_bhs(struct kiobuf * kiobuf) +/** + * free_kiobuf_bhs_sz - free buffer_heads from a kiobuf + * @kiobuf: kiobuf to free buffer_heads from + * @sz: number of buffer_heads to free + * + * Frees @sz buffer_heads from @kiobuf. + */ +void +free_kiobuf_bhs_sz(struct kiobuf * kiobuf, int sz) { int i; - for (i = 0; i < KIO_MAX_SECTORS; i++) { + for (i = 0; i < sz; i++) { kmem_cache_free(bh_cachep, kiobuf->bh[i]); kiobuf->bh[i] = NULL; } } -int alloc_kiovec(int nr, struct kiobuf **bufp) +/** + * alloc_kiovec - allocate one or more default kiobufs + * @nr: number of kiobufs to allocate + * @bufp: where to put the kiobufs + * + * alloc_kiovec() allocates @nr kiobufs with %KIO_MAX_SECTORS + * buffer_heads associated with them. The new kiobufs are + * placed starting at @bufp. + */ +int +alloc_kiovec(int nr, struct kiobuf **bufp) +{ + return alloc_kiovec_sz(nr, bufp, 0); +} + +/** + * alloc_kiovec_sz - allocate one or more kiobufs and assocaited buffer_heads + * @nr: number of kiobufs to allocate + * @bufp: where to put the kiobufs + * @szp: respective number of buffer_heads per kiobuf to allocate + * + * Allocates @nr kiobufs. Each kiobuf will have a number of buffer_heads + * associated with it, as specified by the @szp array. For example, if @nr + * is >1, the second kiobuf allocated will have @szp[2] buffer_heads. This + * allows the caller to allocate a number of kiobufs, each with a different + * number of buffer_heads. + */ +int +alloc_kiovec_sz(int nr, struct kiobuf **bufp, int *szp) { int i; struct kiobuf *iobuf; + int *tszp = szp; + int nrbh = KIO_MAX_SECTORS; + if(!szp) + tszp = &nrbh; + for (i = 0; i < nr; i++) { - iobuf = vmalloc(sizeof(struct kiobuf)); + iobuf = kmem_cache_alloc(kiobuf_cachep, SLAB_KERNEL); if (!iobuf) { - free_kiovec(i, bufp); + free_kiovec_sz(i, bufp, szp); return -ENOMEM; } kiobuf_init(iobuf); - if (alloc_kiobuf_bhs(iobuf)) { - vfree(iobuf); - free_kiovec(i, bufp); + if (alloc_kiobuf_bhs_sz(iobuf, *tszp)) { + kmem_cache_free(kiobuf_cachep, iobuf); + free_kiovec_sz(i, bufp, szp); return -ENOMEM; } + if(!szp) + tszp++; bufp[i] = iobuf; } return 0; } -void free_kiovec(int nr, struct kiobuf **bufp) +/** + * free_kiovec - free one or more kiovecs with the default number of buffer_heads + * @nr: number of kiobufs to free + * @bufp: pointer to the array of kiobufs to free + * + * Frees @nr kiobufs and %KIO_MAX_SECTORS buffer_heads from each. + */ +void +free_kiovec(int nr, struct kiobuf **bufp) +{ + free_kiovec_sz(nr, bufp, 0); +} + +/** + * free_kiovec_sz - frees one or more kiobufs with an arbitrary number of buffer_heads + * @nr: number of kiobufs to free + * @bufp: pointer to the array of kiobufs to free + * @szp: array of ints specifying the number of buffer_heads to free from each kiobuf + * + * Frees @nr kiobufs and @szp buffer_heads from each (see comments for + * alloc_kiovec_sz above). + */ +void +free_kiovec_sz(int nr, struct kiobuf **bufp, int *szp) { int i; struct kiobuf *iobuf; + int *tszp = szp; + int nrbh = KIO_MAX_SECTORS; + + if(!szp) + tszp = &nrbh; for (i = 0; i < nr; i++) { iobuf = bufp[i]; @@ -92,12 +235,22 @@ unlock_kiovec(1, &iobuf); if (iobuf->array_len > KIO_STATIC_PAGES) kfree (iobuf->maplist); - free_kiobuf_bhs(iobuf); - vfree(bufp[i]); + free_kiobuf_bhs_sz(iobuf, *tszp); + kmem_cache_free(kiobuf_cachep, bufp[i]); + if(!szp) + tszp++; } } -int expand_kiobuf(struct kiobuf *iobuf, int wanted) +/** + * expand_kiobuf - add a number of pages to a kiobuf + * @iobuf: kiobuf to add pages to + * @wanted: number of pages required + * + * Allocates @wanted additional pages for @iobuf. + */ +int +expand_kiobuf(struct kiobuf *iobuf, int wanted) { struct page ** maplist; @@ -125,8 +278,15 @@ return 0; } - -void kiobuf_wait_for_io(struct kiobuf *kiobuf) +/** + * kiobuf_wait_for_io - wait for completion of a kiobuf request + * @kiobuf: kiobuf request to wait for + * + * Adds a completion event for the kiobuf in question and wakes up + * when the I/O has completed. + */ +void +kiobuf_wait_for_io(struct kiobuf *kiobuf) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); @@ -135,7 +295,7 @@ return; add_wait_queue(&kiobuf->wait_queue, &wait); -repeat: + repeat: set_task_state(tsk, TASK_UNINTERRUPTIBLE); if (atomic_read(&kiobuf->io_count) != 0) { run_task_queue(&tq_disk); @@ -146,6 +306,3 @@ tsk->state = TASK_RUNNING; remove_wait_queue(&kiobuf->wait_queue, &wait); } - - - diff -Nur linux-2.4.19/fs/ioctl.c linux-2.4.19-sgi211r3/fs/ioctl.c --- linux-2.4.19/fs/ioctl.c Fri Feb 9 11:29:44 2001 +++ linux-2.4.19-sgi211r3/fs/ioctl.c Fri Apr 26 11:07:18 2002 @@ -101,6 +101,16 @@ filp->f_flags &= ~FASYNC; break; + case FIOQSIZE: + if (S_ISDIR(filp->f_dentry->d_inode->i_mode) || + S_ISREG(filp->f_dentry->d_inode->i_mode) || + S_ISLNK(filp->f_dentry->d_inode->i_mode)) { + loff_t res = inode_get_bytes(filp->f_dentry->d_inode); + error = copy_to_user((loff_t *)arg, &res, sizeof(res)) ? -EFAULT : 0; + } + else + error = -ENOTTY; + break; default: error = -ENOTTY; if (S_ISREG(filp->f_dentry->d_inode->i_mode)) diff -Nur linux-2.4.19/fs/isofs/dir.c linux-2.4.19-sgi211r3/fs/isofs/dir.c --- linux-2.4.19/fs/isofs/dir.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-sgi211r3/fs/isofs/dir.c Mon Oct 28 20:43:23 2002 @@ -185,7 +185,7 @@ /* Handle the case of the '..' directory */ if (de->name_len[0] == 1 && de->name[0] == 1) { - inode_number = filp->f_dentry->d_parent->d_inode->i_ino; + inode_number = parent_ino(filp->f_dentry); if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0) break; filp->f_pos += de_len; diff -Nur linux-2.4.19/fs/jbd/journal.c linux-2.4.19-sgi211r3/fs/jbd/journal.c --- linux-2.4.19/fs/jbd/journal.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/jbd/journal.c Mon Oct 28 20:43:23 2002 @@ -462,8 +462,7 @@ printk (KERN_NOTICE __FUNCTION__ ": ENOMEM at get_unused_buffer_head, " "trying again.\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } while (!new_bh); /* keep subsequent assertions sane */ @@ -1543,8 +1542,7 @@ last_warning = jiffies; } - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } @@ -1602,8 +1600,7 @@ last_warning = jiffies; } while (ret == 0) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); } } diff -Nur linux-2.4.19/fs/jbd/revoke.c linux-2.4.19-sgi211r3/fs/jbd/revoke.c --- linux-2.4.19/fs/jbd/revoke.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-sgi211r3/fs/jbd/revoke.c Mon Oct 28 20:43:23 2002 @@ -137,8 +137,7 @@ if (!journal_oom_retry) return -ENOMEM; jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); goto repeat; } diff -Nur linux-2.4.19/fs/jbd/transaction.c linux-2.4.19-sgi211r3/fs/jbd/transaction.c --- linux-2.4.19/fs/jbd/transaction.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-sgi211r3/fs/jbd/transaction.c Mon Oct 28 20:43:23 2002 @@ -1379,8 +1379,7 @@ do { old_handle_count = transaction->t_handle_count; set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } while (old_handle_count != transaction->t_handle_count); } diff -Nur linux-2.4.19/fs/jffs/inode-v23.c linux-2.4.19-sgi211r3/fs/jffs/inode-v23.c --- linux-2.4.19/fs/jffs/inode-v23.c Thu Oct 4 15:14:35 2001 +++ linux-2.4.19-sgi211r3/fs/jffs/inode-v23.c Mon Oct 28 20:43:23 2002 @@ -198,11 +198,13 @@ struct jffs_file *f; struct jffs_node *new_node; int update_all; - int res; + int res = 0; int recoverable = 0; - if ((res = inode_change_ok(inode, iattr))) - return res; + lock_kernel(); + + if ((res = inode_change_ok(inode, iattr))) + goto out; c = (struct jffs_control *)inode->i_sb->u.generic_sbp; fmc = c->fmc; @@ -217,7 +219,8 @@ inode->i_ino); D3(printk (KERN_NOTICE "notify_change(): up biglock\n")); up(&fmc->biglock); - return -EINVAL; + res = -EINVAL; + goto out; }); D1(printk("***jffs_setattr(): file: \"%s\", ino: %u\n", @@ -237,7 +240,8 @@ D(printk("jffs_setattr(): Allocation failed!\n")); D3(printk (KERN_NOTICE "notify_change(): up biglock\n")); up(&fmc->biglock); - return -ENOMEM; + res = -ENOMEM; + goto out; } new_node->data_offset = 0; @@ -323,7 +327,7 @@ jffs_free_node(new_node); D3(printk (KERN_NOTICE "n_c(): up biglock\n")); up(&c->fmc->biglock); - return res; + goto out; } jffs_insert_node(c, f, &raw_inode, 0, new_node); @@ -331,7 +335,9 @@ mark_inode_dirty(inode); D3(printk (KERN_NOTICE "n_c(): up biglock\n")); up(&c->fmc->biglock); - return 0; +out: + unlock_kernel(); + return res; } /* jffs_notify_change() */ diff -Nur linux-2.4.19/fs/jffs2/background.c linux-2.4.19-sgi211r3/fs/jffs2/background.c --- linux-2.4.19/fs/jffs2/background.c Thu Oct 25 00:07:09 2001 +++ linux-2.4.19-sgi211r3/fs/jffs2/background.c Fri Nov 1 12:55:48 2002 @@ -107,7 +107,7 @@ sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); /* FIXME in the 2.2 backport */ - current->nice = 10; + set_user_nice(current, 10); for (;;) { spin_lock_irq(¤t->sigmask_lock); diff -Nur linux-2.4.19/fs/jffs2/dir.c linux-2.4.19-sgi211r3/fs/jffs2/dir.c --- linux-2.4.19/fs/jffs2/dir.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/jffs2/dir.c Mon Oct 28 20:43:23 2002 @@ -153,8 +153,8 @@ offset++; } if (offset == 1) { - D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", filp->f_dentry->d_parent->d_inode->i_ino)); - if (filldir(dirent, "..", 2, 1, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) + D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", parent_ino(filp->f_dentry))); + if (filldir(dirent, "..", 2, 1, parent_ino(filp->f_dentry), DT_DIR) < 0) goto out; offset++; } diff -Nur linux-2.4.19/fs/jffs2/file.c linux-2.4.19-sgi211r3/fs/jffs2/file.c --- linux-2.4.19/fs/jffs2/file.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/jffs2/file.c Mon Oct 28 20:43:23 2002 @@ -41,6 +41,7 @@ #include #include #include +#include #include "nodelist.h" #include "crc32.h" @@ -91,12 +92,12 @@ int mdatalen = 0; unsigned int ivalid; __u32 phys_ofs, alloclen; - int ret; + int ret = 0; + lock_kernel(); D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); ret = inode_change_ok(inode, iattr); if (ret) - return ret; - + goto out; /* Special cases - we don't want more than one data node for these types on the medium at any time. So setattr must read the original data associated with the node @@ -112,12 +113,14 @@ } else if (S_ISLNK(inode->i_mode)) { mdatalen = f->metadata->size; mdata = kmalloc(f->metadata->size, GFP_USER); - if (!mdata) - return -ENOMEM; + if (!mdata) { + ret = -ENOMEM; + goto out; + } ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen); if (ret) { kfree(mdata); - return ret; + goto out; } D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); } @@ -126,7 +129,8 @@ if (!ri) { if (S_ISLNK(inode->i_mode)) kfree(mdata); - return -ENOMEM; + ret = -ENOMEM; + goto out; } ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); @@ -134,7 +138,7 @@ jffs2_free_raw_inode(ri); if (S_ISLNK(inode->i_mode)) kfree(mdata); - return ret; + goto out; } down(&f->sem); ivalid = iattr->ia_valid; @@ -184,7 +188,8 @@ if (IS_ERR(new_metadata)) { jffs2_free_raw_inode(ri); up(&f->sem); - return PTR_ERR(new_metadata); + ret = PTR_ERR(new_metadata); + goto out; } /* It worked. Update the inode */ inode->i_atime = ri->atime; @@ -215,7 +220,9 @@ } jffs2_free_raw_inode(ri); up(&f->sem); - return 0; +out: + unlock_kernel(); + return ret; } int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) diff -Nur linux-2.4.19/fs/locks.c linux-2.4.19-sgi211r3/fs/locks.c --- linux-2.4.19/fs/locks.c Thu Oct 11 07:52:18 2001 +++ linux-2.4.19-sgi211r3/fs/locks.c Mon Oct 28 20:43:23 2002 @@ -445,8 +445,7 @@ /* Let the blocked process remove waiter from the * block list when it gets scheduled. */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); } else { /* Remove waiter from the block list, because by the * time it wakes up blocker won't exist any more. diff -Nur linux-2.4.19/fs/namei.c linux-2.4.19-sgi211r3/fs/namei.c --- linux-2.4.19/fs/namei.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/namei.c Tue Dec 3 16:22:12 2002 @@ -1039,8 +1039,9 @@ /* Negative dentry, just create the file */ if (!dentry->d_inode) { - error = vfs_create(dir->d_inode, dentry, - mode & ~current->fs->umask); + if (!IS_POSIXACL(dir->d_inode)) + mode &= ~current->fs->umask; + error = vfs_create(dir->d_inode, dentry, mode); up(&dir->d_inode->i_sem); dput(nd->dentry); nd->dentry = dentry; @@ -1272,7 +1273,8 @@ dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); - mode &= ~current->fs->umask; + if (!IS_POSIXACL(nd.dentry->d_inode)) + mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { switch (mode & S_IFMT) { case 0: case S_IFREG: @@ -1341,8 +1343,9 @@ dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_mkdir(nd.dentry->d_inode, dentry, - mode & ~current->fs->umask); + if (!IS_POSIXACL(nd.dentry->d_inode)) + mode &= ~current->fs->umask; + error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); dput(dentry); } up(&nd.dentry->d_inode->i_sem); diff -Nur linux-2.4.19/fs/ncpfs/dir.c linux-2.4.19-sgi211r3/fs/ncpfs/dir.c --- linux-2.4.19/fs/ncpfs/dir.c Wed Mar 7 16:53:48 2001 +++ linux-2.4.19-sgi211r3/fs/ncpfs/dir.c Mon Oct 28 20:43:23 2002 @@ -257,11 +257,17 @@ __ncp_lookup_validate(struct dentry * dentry, int flags) { struct ncp_server *server; + struct dentry *parent; struct inode *dir = dentry->d_parent->d_inode; struct ncp_entry_info finfo; int res, val = 0, len = dentry->d_name.len + 1; __u8 __name[len]; + read_lock(&dparent_lock); + parent = dget(dentry->d_parent); + read_unlock(&dparent_lock); + dir = parent->d_inode; + if (!dentry->d_inode || !dir) goto finished; @@ -313,6 +319,7 @@ finished: DDPRINTK("ncp_lookup_validate: result=%d\n", val); + dput(parent); return val; } @@ -412,7 +419,7 @@ } if (filp->f_pos == 1) { if (filldir(dirent, "..", 2, 1, - dentry->d_parent->d_inode->i_ino, DT_DIR)) + parent_ino(dentry), DT_DIR)) goto out; filp->f_pos = 2; } diff -Nur linux-2.4.19/fs/ncpfs/file.c linux-2.4.19-sgi211r3/fs/ncpfs/file.c --- linux-2.4.19/fs/ncpfs/file.c Mon Sep 10 09:04:53 2001 +++ linux-2.4.19-sgi211r3/fs/ncpfs/file.c Mon Oct 28 20:43:23 2002 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "ncplib_kernel.h" @@ -281,7 +282,7 @@ struct file_operations ncp_file_operations = { - llseek: generic_file_llseek, + llseek: remote_llseek, read: ncp_file_read, write: ncp_file_write, ioctl: ncp_ioctl, diff -Nur linux-2.4.19/fs/ncpfs/inode.c linux-2.4.19-sgi211r3/fs/ncpfs/inode.c --- linux-2.4.19/fs/ncpfs/inode.c Sun Sep 30 12:26:08 2001 +++ linux-2.4.19-sgi211r3/fs/ncpfs/inode.c Mon Oct 28 20:43:23 2002 @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -552,6 +553,8 @@ result = -EIO; + lock_kernel(); + server = NCP_SERVER(inode); if ((!server) || !ncp_conn_valid(server)) goto out; @@ -596,7 +599,8 @@ info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); } else if (!S_ISREG(inode->i_mode)) { - return -EPERM; + result = -EPERM; + goto out; } else { @@ -682,7 +686,8 @@ attr->ia_size); if ((result = ncp_make_open(inode, O_WRONLY)) < 0) { - return -EACCES; + result = -EACCES; + goto out; } ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, attr->ia_size, 0, "", &written); @@ -695,6 +700,7 @@ result = vmtruncate(inode, attr->ia_size); } out: + unlock_kernel(); return result; } diff -Nur linux-2.4.19/fs/nfs/dir.c linux-2.4.19-sgi211r3/fs/nfs/dir.c --- linux-2.4.19/fs/nfs/dir.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/nfs/dir.c Mon Oct 28 20:43:23 2002 @@ -467,12 +467,16 @@ { struct inode *dir; struct inode *inode; + struct dentry *parent; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; + read_lock(&dparent_lock); + parent = dget(dentry->d_parent); + read_unlock(&dparent_lock); lock_kernel(); - dir = dentry->d_parent->d_inode; + dir = parent->d_inode; inode = dentry->d_inode; if (!inode) { @@ -508,6 +512,7 @@ nfs_renew_times(dentry); out_valid: unlock_kernel(); + dput(parent); return 1; out_bad: NFS_CACHEINV(dir); @@ -521,6 +526,7 @@ } d_drop(dentry); unlock_kernel(); + dput(parent); return 0; } diff -Nur linux-2.4.19/fs/nfs/file.c linux-2.4.19-sgi211r3/fs/nfs/file.c --- linux-2.4.19/fs/nfs/file.c Mon Feb 25 11:38:09 2002 +++ linux-2.4.19-sgi211r3/fs/nfs/file.c Mon Oct 28 20:43:23 2002 @@ -41,7 +41,7 @@ static int nfs_fsync(struct file *, struct dentry *dentry, int datasync); struct file_operations nfs_file_operations = { - llseek: generic_file_llseek, + llseek: remote_llseek, read: nfs_file_read, write: nfs_file_write, mmap: nfs_file_mmap, diff -Nur linux-2.4.19/fs/nfs/inode.c linux-2.4.19-sgi211r3/fs/nfs/inode.c --- linux-2.4.19/fs/nfs/inode.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/nfs/inode.c Mon Oct 28 20:43:23 2002 @@ -746,6 +746,8 @@ struct nfs_fattr fattr; int error; + lock_kernel(); + /* * Make sure the inode is up-to-date. */ @@ -794,6 +796,7 @@ NFS_CACHEINV(inode); error = nfs_refresh_inode(inode, &fattr); out: + unlock_kernel(); return error; } diff -Nur linux-2.4.19/fs/nfs/nfs3proc.c linux-2.4.19-sgi211r3/fs/nfs/nfs3proc.c --- linux-2.4.19/fs/nfs/nfs3proc.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/nfs/nfs3proc.c Wed Oct 16 14:02:58 2002 @@ -222,10 +222,27 @@ int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; +/* define ia64_gcc_nfs_work_around if using a version of gcc that miscompiles + * nested structure initialisers. { 0, 0 } is 4 byte aligned but gcc thinks + * it is 8 byte aligned and does st8 [rxx]=r0, generating unaligned accesses. + * Remove ia64_gcc_nfs_work_around when everybody is using a fixed version of + * gcc. The bug exists in 2.96-ia64-000717 snap 001117, probably fixed in + * the next release. Keith Owens, May 8, 2001. + */ +#define ia64_gcc_nfs_work_around +#ifndef ia64_gcc_nfs_work_around struct nfs3_createargs arg = { NFS_FH(dir), name->name, name->len, sattr, 0, { 0, 0 } }; +#else + struct nfs3_createargs arg = { NFS_FH(dir), name->name, name->len, + sattr, 0 }; +#endif struct nfs3_diropres res = { &dir_attr, fhandle, fattr }; int status; + +#ifdef ia64_gcc_nfs_work_around + arg.verifier[0] = arg.verifier[1] = 0; /* ia64 gcc work around */ +#endif dprintk("NFS call create %s\n", name->name); arg.createmode = NFS3_CREATE_UNCHECKED; diff -Nur linux-2.4.19/fs/nfs/pagelist.c linux-2.4.19-sgi211r3/fs/nfs/pagelist.c --- linux-2.4.19/fs/nfs/pagelist.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/nfs/pagelist.c Mon Oct 28 20:43:23 2002 @@ -96,8 +96,7 @@ continue; if (signalled() && (server->flags & NFS_MOUNT_INTR)) return ERR_PTR(-ERESTARTSYS); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } /* Initialize the request struct. Initially, we assume a diff -Nur linux-2.4.19/fs/nfsd/nfs3xdr.c linux-2.4.19-sgi211r3/fs/nfsd/nfs3xdr.c --- linux-2.4.19/fs/nfsd/nfs3xdr.c Wed Oct 3 22:27:48 2001 +++ linux-2.4.19-sgi211r3/fs/nfsd/nfs3xdr.c Mon Oct 28 20:43:23 2002 @@ -700,9 +700,12 @@ fh_init(&fh, NFS3_FHSIZE); if (isdotent(name, namlen)) { dchild = dparent; - if (namlen == 2) - dchild = dchild->d_parent; - dchild = dget(dchild); + if (namlen == 2) { + read_lock(&dparent_lock); + dchild = dget(dparent->d_parent); + read_unlock(&dparent_lock); + } else + dchild = dget(dchild); } else dchild = lookup_one_len(name, dparent,namlen); if (IS_ERR(dchild)) diff -Nur linux-2.4.19/fs/nfsd/nfsfh.c linux-2.4.19-sgi211r3/fs/nfsd/nfsfh.c --- linux-2.4.19/fs/nfsd/nfsfh.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/nfsd/nfsfh.c Sun Jan 12 03:29:41 2003 @@ -227,7 +227,9 @@ */ spin_lock(&dcache_lock); list_del_init(&tdentry->d_child); + write_lock(&dparent_lock); tdentry->d_parent = tdentry; + write_unlock(&dparent_lock); spin_unlock(&dcache_lock); d_rehash(target); dput(tdentry); @@ -463,8 +465,10 @@ pdentry = nfsd_findparent(dentry); err = PTR_ERR(pdentry); - if (IS_ERR(pdentry)) + if (IS_ERR(pdentry)) { goto err_dentry; + } + parent = pdentry->d_inode; err = -EACCES; if (!parent) { @@ -752,7 +756,7 @@ *maxsize = 2; return 1; } - *datap++ = ino_t_to_u32(dentry->d_parent->d_inode->i_ino); + *datap++ = ino_t_to_u32(parent_ino(dentry)); *maxsize = 3; return 2; } @@ -812,7 +816,7 @@ fhp->fh_handle.ofh_dev = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino); - fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino); + fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); if (inode) _fh_update_old(dentry, exp, &fhp->fh_handle); } else { diff -Nur linux-2.4.19/fs/nfsd/vfs.c linux-2.4.19-sgi211r3/fs/nfsd/vfs.c --- linux-2.4.19/fs/nfsd/vfs.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/nfsd/vfs.c Tue Jan 7 16:26:28 2003 @@ -127,12 +127,16 @@ dentry = dget(dparent); while(follow_up(&mnt, &dentry)) ; + read_lock(&dparent_lock); dp = dget(dentry->d_parent); + read_unlock(&dparent_lock); dput(dentry); dentry = dp; + read_lock(&dparent_lock); for ( ; exp2 == NULL && dp->d_parent != dp; dp=dp->d_parent) exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino); + read_unlock(&dparent_lock); if (exp2==NULL) { dput(dentry); dentry = dget(dparent); @@ -141,8 +145,11 @@ } mntput(mnt); } - } else + } else { + read_lock(&dparent_lock); dentry = dget(dparent->d_parent); + read_unlock(&dparent_lock); + } } } else { fh_lock(fhp); @@ -267,6 +274,7 @@ if (err) goto out_nfserr; + size_change = 1; err = locks_verify_truncate(inode, NULL, iap->ia_size); if (err) { put_write_access(inode); @@ -282,35 +290,24 @@ } /* Revoke setuid/setgid bit on chown/chgrp */ - if ((iap->ia_valid & ATTR_UID) && (imode & S_ISUID) - && iap->ia_uid != inode->i_uid) { - iap->ia_valid |= ATTR_MODE; - iap->ia_mode = imode &= ~S_ISUID; - } - if ((iap->ia_valid & ATTR_GID) && (imode & S_ISGID) - && iap->ia_gid != inode->i_gid) { - iap->ia_valid |= ATTR_MODE; - iap->ia_mode = imode &= ~S_ISGID; - } + if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) + iap->ia_valid |= ATTR_KILL_SUID; + if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) + iap->ia_valid |= ATTR_KILL_SGID; /* Change the attributes. */ - iap->ia_valid |= ATTR_CTIME; - if (iap->ia_valid & ATTR_SIZE) { - fh_lock(fhp); - size_change = 1; - } err = nfserr_notsync; if (!check_guard || guardtime == inode->i_ctime) { + fh_lock(fhp); err = notify_change(dentry, iap); err = nfserrno(err); - } - if (size_change) { fh_unlock(fhp); - put_write_access(inode); } + if (size_change) + put_write_access(inode); if (!err) if (EX_ISSYNC(fhp->fh_export)) write_inode_now(inode, 1); @@ -720,10 +717,11 @@ /* clear setuid/setgid flag after write */ if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) { struct iattr ia; + ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID; - ia.ia_valid = ATTR_MODE; - ia.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID); + down(&inode->i_sem); notify_change(dentry, &ia); + up(&inode->i_sem); } if (err >= 0 && stable) { diff -Nur linux-2.4.19/fs/noquot.c linux-2.4.19-sgi211r3/fs/noquot.c --- linux-2.4.19/fs/noquot.c Fri May 12 11:21:20 2000 +++ linux-2.4.19-sgi211r3/fs/noquot.c Wed Dec 31 16:00:00 1969 @@ -1,15 +0,0 @@ -/* noquot.c: Quota stubs necessary for when quotas are not - * compiled into the kernel. - */ - -#include -#include -#include - -int nr_dquots, nr_free_dquots; -int max_dquots; - -asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) -{ - return(-ENOSYS); -} diff -Nur linux-2.4.19/fs/ntfs/fs.c linux-2.4.19-sgi211r3/fs/ntfs/fs.c --- linux-2.4.19/fs/ntfs/fs.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/ntfs/fs.c Mon Oct 28 20:43:23 2002 @@ -276,9 +276,9 @@ ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling " "filldir for .. with len 2, f_pos 0x%Lx, " "inode %lu, DT_DIR.\n", filp->f_pos, - filp->f_dentry->d_parent->d_inode->i_ino); + parent_ino(filp->f_dentry)); cb.ret_code = filldir(dirent, "..", 2, filp->f_pos, - filp->f_dentry->d_parent->d_inode->i_ino, + parent_ino(filp->f_dentry), DT_DIR); if (cb.ret_code) goto done; diff -Nur linux-2.4.19/fs/open.c linux-2.4.19-sgi211r3/fs/open.c --- linux-2.4.19/fs/open.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/open.c Mon Oct 28 20:43:23 2002 @@ -97,20 +97,19 @@ int do_truncate(struct dentry *dentry, loff_t length) { - struct inode *inode = dentry->d_inode; - int error; struct iattr newattrs; - + int err; + /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ if (length < 0) return -EINVAL; - down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - error = notify_change(dentry, &newattrs); - up(&inode->i_sem); - return error; + down(&dentry->d_inode->i_sem); + err = notify_change(dentry, &newattrs); + up(&dentry->d_inode->i_sem); + return err; } static inline long do_sys_truncate(const char * path, loff_t length) @@ -284,7 +283,9 @@ (error = permission(inode,MAY_WRITE)) != 0) goto dput_and_out; } + down(&inode->i_sem); error = notify_change(nd.dentry, &newattrs); + up(&inode->i_sem); dput_and_out: path_release(&nd); out: @@ -329,7 +330,9 @@ (error = permission(inode,MAY_WRITE)) != 0) goto dput_and_out; } + down(&inode->i_sem); error = notify_change(nd.dentry, &newattrs); + up(&inode->i_sem); dput_and_out: path_release(&nd); out: @@ -497,11 +500,13 @@ err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_putf; + down(&inode->i_sem); if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); + up(&inode->i_sem); out_putf: fput(file); @@ -529,11 +534,13 @@ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; + down(&inode->i_sem); if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(nd.dentry, &newattrs); + up(&inode->i_sem); dput_and_out: path_release(&nd); @@ -558,45 +565,20 @@ error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; - if (user == (uid_t) -1) - user = inode->i_uid; - if (group == (gid_t) -1) - group = inode->i_gid; - newattrs.ia_mode = inode->i_mode; - newattrs.ia_uid = user; - newattrs.ia_gid = group; - newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME; - /* - * If the user or group of a non-directory has been changed by a - * non-root user, remove the setuid bit. - * 19981026 David C Niemi - * - * Changed this to apply to all users, including root, to avoid - * some races. This is the behavior we had in 2.0. The check for - * non-root was definitely wrong for 2.2 anyway, as it should - * have been using CAP_FSETID rather than fsuid -- 19990830 SD. - */ - if ((inode->i_mode & S_ISUID) == S_ISUID && - !S_ISDIR(inode->i_mode)) - { - newattrs.ia_mode &= ~S_ISUID; - newattrs.ia_valid |= ATTR_MODE; + newattrs.ia_valid = ATTR_CTIME; + if (user != (uid_t) -1) { + newattrs.ia_valid |= ATTR_UID; + newattrs.ia_uid = user; } - /* - * Likewise, if the user or group of a non-directory has been changed - * by a non-root user, remove the setgid bit UNLESS there is no group - * execute bit (this would be a file marked for mandatory locking). - * 19981026 David C Niemi - * - * Removed the fsuid check (see the comment above) -- 19990830 SD. - */ - if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) - && !S_ISDIR(inode->i_mode)) - { - newattrs.ia_mode &= ~S_ISGID; - newattrs.ia_valid |= ATTR_MODE; + if (group != (gid_t) -1) { + newattrs.ia_valid |= ATTR_GID; + newattrs.ia_gid = group; } + if (!S_ISDIR(inode->i_mode)) + newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID; + down(&inode->i_sem); error = notify_change(dentry, &newattrs); + up(&inode->i_sem); out: return error; } diff -Nur linux-2.4.19/fs/partitions/Config.in linux-2.4.19-sgi211r3/fs/partitions/Config.in --- linux-2.4.19/fs/partitions/Config.in Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-sgi211r3/fs/partitions/Config.in Fri Apr 26 11:07:18 2002 @@ -32,6 +32,7 @@ bool ' SGI partition support' CONFIG_SGI_PARTITION bool ' Ultrix partition table support' CONFIG_ULTRIX_PARTITION bool ' Sun partition tables support' CONFIG_SUN_PARTITION + bool ' EFI GUID Partition support' CONFIG_EFI_PARTITION else if [ "$ARCH" = "alpha" ]; then define_bool CONFIG_OSF_PARTITION y diff -Nur linux-2.4.19/fs/partitions/Makefile linux-2.4.19-sgi211r3/fs/partitions/Makefile --- linux-2.4.19/fs/partitions/Makefile Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/partitions/Makefile Wed Oct 16 14:02:58 2002 @@ -24,6 +24,7 @@ obj-$(CONFIG_SUN_PARTITION) += sun.o obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o obj-$(CONFIG_IBM_PARTITION) += ibm.o +obj-$(CONFIG_EFI_PARTITION) += efi.o include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/fs/partitions/check.c linux-2.4.19-sgi211r3/fs/partitions/check.c --- linux-2.4.19/fs/partitions/check.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/partitions/check.c Thu Dec 12 17:42:31 2002 @@ -33,15 +33,23 @@ #include "sun.h" #include "ibm.h" #include "ultrix.h" +#include "efi.h" extern int *blk_size[]; +struct gendisk *major_gendisk[MAX_BLKDEV]; int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = { +#ifdef CONFIG_SGI_PARTITION + sgi_partition, +#endif #ifdef CONFIG_ACORN_PARTITION acorn_partition, #endif +#ifdef CONFIG_EFI_PARTITION + efi_partition, /* this must come before msdos */ +#endif #ifdef CONFIG_LDM_PARTITION ldm_partition, /* this must come before msdos */ #endif @@ -63,9 +71,6 @@ #ifdef CONFIG_MAC_PARTITION mac_partition, #endif -#ifdef CONFIG_SGI_PARTITION - sgi_partition, -#endif #ifdef CONFIG_ULTRIX_PARTITION ultrix_partition, #endif @@ -200,7 +205,7 @@ /* * Add a partitions details to the devices partition description. */ -void add_gd_partition(struct gendisk *hd, int minor, int start, int size) +void add_gd_partition(struct gendisk *hd, int minor, unsigned int start, unsigned int size) { #ifndef CONFIG_DEVFS_FS char buf[40]; @@ -209,13 +214,13 @@ hd->part[minor].start_sect = start; hd->part[minor].nr_sects = size; #ifdef CONFIG_DEVFS_FS - printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); + printk(KERN_INFO " p%d", (minor & ((1 << hd->minor_shift) - 1))); #else if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) || (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7)) - printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); + printk(KERN_INFO " p%d", (minor & ((1 << hd->minor_shift) - 1))); else - printk(" %s", disk_name(hd, minor, buf)); + printk(KERN_INFO " %s", disk_name(hd, minor, buf)); #endif } @@ -247,8 +252,10 @@ i = devfs_generate_path (de, buf, sizeof buf); if (i >= 0) printk(KERN_INFO " /dev/%s:", buf + i); - else + else if (hd->major_name) printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); + else + printk(KERN_INFO " [%d,%d]:", MAJOR(dev), MINOR(dev)); bdev = bdget(kdev_t_to_nr(dev)); bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9; bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev)); @@ -257,18 +264,20 @@ res = check_part[i](hd, bdev, first_sector, first_part_minor); if (res) { if (res < 0 && warn_no_part) - printk(" unable to read partition table\n"); + printk(KERN_INFO " unable to read partition table\n"); goto setup_devfs; } } - printk(" unknown partition table\n"); + printk(KERN_INFO " unknown partition table\n"); setup_devfs: invalidate_bdev(bdev, 1); truncate_inode_pages(bdev->bd_inode->i_mapping, 0); bdput(bdev); - i = first_part_minor - 1; - devfs_register_partitions (hd, i, hd->sizes ? 0 : 1); + if (hd->major_name) { + i = first_part_minor - 1; + devfs_register_partitions (hd, i, hd->sizes ? 0 : 1); + } } #ifdef CONFIG_DEVFS_FS @@ -375,6 +384,7 @@ if (!gdev) return; grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); + major_gendisk[MAJOR(dev)] = gdev; } void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) diff -Nur linux-2.4.19/fs/partitions/check.h linux-2.4.19-sgi211r3/fs/partitions/check.h --- linux-2.4.19/fs/partitions/check.h Mon Oct 1 20:03:26 2001 +++ linux-2.4.19-sgi211r3/fs/partitions/check.h Thu Dec 12 17:42:31 2002 @@ -2,7 +2,7 @@ * add_partition adds a partitions details to the devices partition * description. */ -void add_gd_partition(struct gendisk *hd, int minor, int start, int size); +void add_gd_partition(struct gendisk *hd, int minor, unsigned int start, unsigned int size); typedef struct {struct page *v;} Sector; diff -Nur linux-2.4.19/fs/partitions/efi.c linux-2.4.19-sgi211r3/fs/partitions/efi.c --- linux-2.4.19/fs/partitions/efi.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/partitions/efi.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,823 @@ +/************************************************************ + * EFI GUID Partition Table handling + * Per Intel EFI Specification v1.02 + * http://developer.intel.com/technology/efi/efi.htm + * efi.[ch] by Matt Domsch + * Copyright 2000,2001,2002 Dell Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * TODO: + * + * Changelog: + * Wed Mar 27 2002 Matt Domsch + * - Ported to 2.5.7-pre1 and 2.4.18 + * - Applied patch to avoid fault in alternate header handling + * - cleaned up find_valid_gpt + * - On-disk structure and copy in memory is *always* LE now - + * swab fields as needed + * - remove print_gpt_header() + * - only use first max_p partition entries, to keep the kernel minor number + * and partition numbers tied. + * - 2.4.18 patch needs own crc32() function - there's no official + * lib/crc32.c in 2.4.x. + * + * Mon Feb 04 2002 Matt Domsch + * - Removed __PRIPTR_PREFIX - not being used + * + * Mon Jan 14 2002 Matt Domsch + * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied + * + * Thu Dec 6 2001 Matt Domsch + * - Added compare_gpts(). + * - moved le_efi_guid_to_cpus() back into this file. GPT is the only + * thing that keeps EFI GUIDs on disk. + * - Changed gpt structure names and members to be simpler and more Linux-like. + * + * Wed Oct 17 2001 Matt Domsch + * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck + * + * Wed Oct 10 2001 Matt Domsch + * - Changed function comments to DocBook style per Andreas Dilger suggestion. + * + * Mon Oct 08 2001 Matt Domsch + * - Change read_lba() to use the page cache per Al Viro's work. + * - print u64s properly on all architectures + * - fixed debug_printk(), now Dprintk() + * + * Mon Oct 01 2001 Matt Domsch + * - Style cleanups + * - made most functions static + * - Endianness addition + * - remove test for second alternate header, as it's not per spec, + * and is unnecessary. There's now a method to read/write the last + * sector of an odd-sized disk from user space. No tools have ever + * been released which used this code, so it's effectively dead. + * - Per Asit Mallick of Intel, added a test for a valid PMBR. + * - Added kernel command line option 'gpt' to override valid PMBR test. + * + * Wed Jun 6 2001 Martin Wilck + * - added devfs volume UUID support (/dev/volumes/uuids) for + * mounting file systems by the partition GUID. + * + * Tue Dec 5 2000 Matt Domsch + * - Moved crc32() to linux/lib, added efi_crc32(). + * + * Thu Nov 30 2000 Matt Domsch + * - Replaced Intel's CRC32 function with an equivalent + * non-license-restricted version. + * + * Wed Oct 25 2000 Matt Domsch + * - Fixed the last_lba() call to return the proper last block + * + * Thu Oct 12 2000 Matt Domsch + * - Thanks to Andries Brouwer for his debugging assistance. + * - Code works, detects all the partitions. + * + ************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "check.h" +#include "efi.h" + +#if CONFIG_BLK_DEV_MD +extern void md_autodetect_dev(kdev_t dev); +#endif + +/* Handle printing of 64-bit values */ +/* Borrowed from /usr/include/inttypes.h */ +# if BITS_PER_LONG == 64 +# define __PRI64_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# endif +# define PRIx64 __PRI64_PREFIX "x" + + +#undef EFI_DEBUG +#ifdef EFI_DEBUG +#define Dprintk(x...) printk(KERN_DEBUG x) +#else +#define Dprintk(x...) +#endif + +/* This allows a kernel command line option 'gpt' to override + * the test for invalid PMBR. Not __initdata because reloading + * the partition tables happens after init too. + */ +static int force_gpt; +static int __init +force_gpt_fn(char *str) +{ + force_gpt = 1; + return 1; +} +__setup("gpt", force_gpt_fn); + + +/* + * There are multiple 16-bit CRC polynomials in common use, but this is + * *the* standard CRC-32 polynomial, first popularized by Ethernet. + * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 + */ +#define CRCPOLY_LE 0xedb88320 +/* How many bits at a time to use. Requires a table of 4<>= 1) { + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); + for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i) + crc32table_le[i + j] = crc ^ crc32table_le[j]; + } + return 0; +} + +/** + * crc32cleanup_le(): free LE table data + */ +static void __exit crc32cleanup_le(void) +{ + if (crc32table_le) kfree(crc32table_le); + crc32table_le = NULL; +} + +__initcall(crc32init_le); +__exitcall(crc32cleanup_le); + +/** + * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32 + * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for + * other uses, or the previous crc32 value if computing incrementally. + * @p - pointer to buffer over which CRC is run + * @len - length of buffer @p + * + */ +static u32 crc32_le(u32 crc, unsigned char const *p, size_t len) +{ + while (len--) { + crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255]; + } + return crc; +} + + +/** + * efi_crc32() - EFI version of crc32 function + * @buf: buffer to calculate crc32 of + * @len - length of buf + * + * Description: Returns EFI-style CRC32 value for @buf + * + * This function uses the little endian Ethernet polynomial + * but seeds the function with ~0, and xor's with ~0 at the end. + * Note, the EFI Specification, v1.02, has a reference to + * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). + */ +static inline u32 +efi_crc32(const void *buf, unsigned long len) +{ + return (crc32_le(~0L, buf, len) ^ ~0L); +} + +/** + * is_pmbr_valid(): test Protective MBR for validity + * @mbr: pointer to a legacy mbr structure + * + * Description: Returns 1 if PMBR is valid, 0 otherwise. + * Validity depends on two things: + * 1) MSDOS signature is in the last two bytes of the MBR + * 2) One partition of type 0xEE is found + */ +static int +is_pmbr_valid(legacy_mbr *mbr) +{ + int i, found = 0, signature = 0; + if (!mbr) + return 0; + signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE); + for (i = 0; signature && i < 4; i++) { + if (mbr->partition_record[i].sys_ind == + EFI_PMBR_OSTYPE_EFI_GPT) { + found = 1; + break; + } + } + return (signature && found); +} + +/** + * last_lba(): return number of last logical block of device + * @hd: gendisk with partition list + * @bdev: block device + * + * Description: Returns last LBA value on success, 0 on error. + * This is stored (by sd and ide-geometry) in + * the part[0] entry for this disk, and is the number of + * physical sectors available on the disk. + */ +static u64 +last_lba(struct gendisk *hd, struct block_device *bdev) +{ + if (!hd || !hd->part || !bdev) + return 0; + return hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects - 1; +} + +/** + * read_lba(): Read bytes from disk, starting at given LBA + * @hd + * @bdev + * @lba + * @buffer + * @size_t + * + * Description: Reads @count bytes from @bdev into @buffer. + * Returns number of bytes read on success, 0 on error. + */ +static size_t +read_lba(struct gendisk *hd, struct block_device *bdev, u64 lba, + u8 * buffer, size_t count) +{ + + size_t totalreadcount = 0, bytesread = 0; + unsigned long blocksize; + int i; + Sector sect; + unsigned char *data = NULL; + + if (!hd || !bdev || !buffer || !count) + return 0; + + blocksize = get_hardsect_size(to_kdev_t(bdev->bd_dev)); + if (!blocksize) + blocksize = 512; + + for (i = 0; count > 0; i++) { + data = read_dev_sector(bdev, lba, §); + if (!data) + return totalreadcount; + + bytesread = + PAGE_CACHE_SIZE - (data - + (unsigned char *) page_address(sect.v)); + bytesread = min(bytesread, count); + memcpy(buffer, data, bytesread); + put_dev_sector(sect); + + buffer += bytesread; + totalreadcount += bytesread; + count -= bytesread; + lba += (bytesread / blocksize); + } + return totalreadcount; +} + + +/** + * alloc_read_gpt_entries(): reads partition entries from disk + * @hd + * @bdev + * @gpt - GPT header + * + * Description: Returns ptes on success, NULL on error. + * Allocates space for PTEs based on information found in @gpt. + * Notes: remember to free pte when you're done! + */ +static gpt_entry * +alloc_read_gpt_entries(struct gendisk *hd, + struct block_device *bdev, gpt_header *gpt) +{ + size_t count; + gpt_entry *pte; + if (!hd || !bdev || !gpt) + return NULL; + + count = le32_to_cpu(gpt->num_partition_entries) * + le32_to_cpu(gpt->sizeof_partition_entry); + if (!count) + return NULL; + pte = kmalloc(count, GFP_KERNEL); + if (!pte) + return NULL; + memset(pte, 0, count); + + if (read_lba(hd, bdev, le64_to_cpu(gpt->partition_entry_lba), + (u8 *) pte, + count) < count) { + kfree(pte); + pte=NULL; + return NULL; + } + return pte; +} + +/** + * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk + * @hd + * @bdev + * @lba is the Logical Block Address of the partition table + * + * Description: returns GPT header on success, NULL on error. Allocates + * and fills a GPT header starting at @ from @bdev. + * Note: remember to free gpt when finished with it. + */ +static gpt_header * +alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba) +{ + gpt_header *gpt; + if (!hd || !bdev) + return NULL; + + gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL); + if (!gpt) + return NULL; + memset(gpt, 0, sizeof (gpt_header)); + + if (read_lba(hd, bdev, lba, (u8 *) gpt, + sizeof (gpt_header)) < sizeof (gpt_header)) { + kfree(gpt); + gpt=NULL; + return NULL; + } + + return gpt; +} + +/** + * is_gpt_valid() - tests one GPT header and PTEs for validity + * @hd + * @bdev + * @lba is the logical block address of the GPT header to test + * @gpt is a GPT header ptr, filled on return. + * @ptes is a PTEs ptr, filled on return. + * + * Description: returns 1 if valid, 0 on error. + * If valid, returns pointers to newly allocated GPT header and PTEs. + */ +static int +is_gpt_valid(struct gendisk *hd, struct block_device *bdev, u64 lba, + gpt_header **gpt, gpt_entry **ptes) +{ + u32 crc, origcrc; + + if (!hd || !bdev || !gpt || !ptes) + return 0; + if (!(*gpt = alloc_read_gpt_header(hd, bdev, lba))) + return 0; + + /* Check the GUID Partition Table signature */ + if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { + Dprintk("GUID Partition Table Header signature is wrong: %" + PRIx64 " != %" PRIx64 "\n", le64_to_cpu((*gpt)->signature), + GPT_HEADER_SIGNATURE); + kfree(*gpt); + *gpt = NULL; + return 0; + } + + /* Check the GUID Partition Table CRC */ + origcrc = le32_to_cpu((*gpt)->header_crc32); + (*gpt)->header_crc32 = 0; + crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); + + if (crc != origcrc) { + Dprintk + ("GUID Partition Table Header CRC is wrong: %x != %x\n", + crc, origcrc); + kfree(*gpt); + *gpt = NULL; + return 0; + } + (*gpt)->header_crc32 = cpu_to_le32(origcrc); + + /* Check that the my_lba entry points to the LBA that contains + * the GUID Partition Table */ + if (le64_to_cpu((*gpt)->my_lba) != lba) { + Dprintk("GPT my_lba incorrect: %" PRIx64 " != %" PRIx64 "\n", + le64_to_cpu((*gpt)->my_lba), lba); + kfree(*gpt); + *gpt = NULL; + return 0; + } + + if (!(*ptes = alloc_read_gpt_entries(hd, bdev, *gpt))) { + kfree(*gpt); + *gpt = NULL; + return 0; + } + + /* Check the GUID Partition Entry Array CRC */ + crc = efi_crc32((const unsigned char *) (*ptes), + le32_to_cpu((*gpt)->num_partition_entries) * + le32_to_cpu((*gpt)->sizeof_partition_entry)); + + if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { + Dprintk("GUID Partitition Entry Array CRC check failed.\n"); + kfree(*gpt); + *gpt = NULL; + kfree(*ptes); + *ptes = NULL; + return 0; + } + + /* We're done, all's well */ + return 1; +} + +/** + * compare_gpts() - Search disk for valid GPT headers and PTEs + * @pgpt is the primary GPT header + * @agpt is the alternate GPT header + * @lastlba is the last LBA number + * Description: Returns nothing. Sanity checks pgpt and agpt fields + * and prints warnings on discrepancies. + * + */ +static void +compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) +{ + int error_found = 0; + if (!pgpt || !agpt) + return; + if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) { + printk(KERN_WARNING + "GPT:Primary header LBA != Alt. header alternate_lba\n"); + printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n", + le64_to_cpu(pgpt->my_lba), + le64_to_cpu(agpt->alternate_lba)); + error_found++; + } + if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) { + printk(KERN_WARNING + "GPT:Primary header alternate_lba != Alt. header my_lba\n"); + printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n", + le64_to_cpu(pgpt->alternate_lba), + le64_to_cpu(agpt->my_lba)); + error_found++; + } + if (le64_to_cpu(pgpt->first_usable_lba) != + le64_to_cpu(agpt->first_usable_lba)) { + printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n"); + printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n", + le64_to_cpu(pgpt->first_usable_lba), + le64_to_cpu(agpt->first_usable_lba)); + error_found++; + } + if (le64_to_cpu(pgpt->last_usable_lba) != + le64_to_cpu(agpt->last_usable_lba)) { + printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n"); + printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n", + le64_to_cpu(pgpt->last_usable_lba), + le64_to_cpu(agpt->last_usable_lba)); + error_found++; + } + if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) { + printk(KERN_WARNING "GPT:disk_guids don't match.\n"); + error_found++; + } + if (le32_to_cpu(pgpt->num_partition_entries) != + le32_to_cpu(agpt->num_partition_entries)) { + printk(KERN_WARNING "GPT:num_partition_entries don't match: " + "0x%x != 0x%x\n", + le32_to_cpu(pgpt->num_partition_entries), + le32_to_cpu(agpt->num_partition_entries)); + error_found++; + } + if (le32_to_cpu(pgpt->sizeof_partition_entry) != + le32_to_cpu(agpt->sizeof_partition_entry)) { + printk(KERN_WARNING + "GPT:sizeof_partition_entry values don't match: " + "0x%x != 0x%x\n", + le32_to_cpu(pgpt->sizeof_partition_entry), + le32_to_cpu(agpt->sizeof_partition_entry)); + error_found++; + } + if (le32_to_cpu(pgpt->partition_entry_array_crc32) != + le32_to_cpu(agpt->partition_entry_array_crc32)) { + printk(KERN_WARNING + "GPT:partition_entry_array_crc32 values don't match: " + "0x%x != 0x%x\n", + le32_to_cpu(pgpt->partition_entry_array_crc32), + le32_to_cpu(agpt->partition_entry_array_crc32)); + error_found++; + } + if (le64_to_cpu(pgpt->alternate_lba) != lastlba) { + printk(KERN_WARNING + "GPT:Primary header thinks Alt. header is not at the end of the disk.\n"); + printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n", + le64_to_cpu(pgpt->alternate_lba), lastlba); + error_found++; + } + + if (le64_to_cpu(agpt->my_lba) != lastlba) { + printk(KERN_WARNING + "GPT:Alternate GPT header not at the end of the disk.\n"); + printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n", + le64_to_cpu(agpt->my_lba), lastlba); + error_found++; + } + + if (error_found) + printk(KERN_WARNING + "GPT: Use GNU Parted to correct GPT errors.\n"); + return; +} + +/** + * find_valid_gpt() - Search disk for valid GPT headers and PTEs + * @hd + * @bdev + * @gpt is a GPT header ptr, filled on return. + * @ptes is a PTEs ptr, filled on return. + * Description: Returns 1 if valid, 0 on error. + * If valid, returns pointers to newly allocated GPT header and PTEs. + * Validity depends on finding either the Primary GPT header and PTEs valid, + * or the Alternate GPT header and PTEs valid, and the PMBR valid. + */ +static int +find_valid_gpt(struct gendisk *hd, struct block_device *bdev, + gpt_header **gpt, gpt_entry **ptes) +{ + int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; + gpt_header *pgpt = NULL, *agpt = NULL; + gpt_entry *pptes = NULL, *aptes = NULL; + legacy_mbr *legacymbr = NULL; + u64 lastlba; + if (!hd || !bdev || !gpt || !ptes) + return 0; + + lastlba = last_lba(hd, bdev); + good_pgpt = is_gpt_valid(hd, bdev, GPT_PRIMARY_PARTITION_TABLE_LBA, + &pgpt, &pptes); + if (good_pgpt) { + good_agpt = is_gpt_valid(hd, bdev, + le64_to_cpu(pgpt->alternate_lba), + &agpt, &aptes); + if (!good_agpt) { + good_agpt = is_gpt_valid(hd, bdev, lastlba, + &agpt, &aptes); + } + } + else { + good_agpt = is_gpt_valid(hd, bdev, lastlba, + &agpt, &aptes); + } + + /* The obviously unsuccessful case */ + if (!good_pgpt && !good_agpt) { + goto fail; + } + + /* This will be added to the EFI Spec. per Intel after v1.02. */ + legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL); + if (legacymbr) { + memset(legacymbr, 0, sizeof (*legacymbr)); + read_lba(hd, bdev, 0, (u8 *) legacymbr, + sizeof (*legacymbr)); + good_pmbr = is_pmbr_valid(legacymbr); + kfree(legacymbr); + legacymbr=NULL; + } + + /* Failure due to bad PMBR */ + if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) { + printk(KERN_WARNING + " Warning: Disk has a valid GPT signature " + "but invalid PMBR.\n"); + printk(KERN_WARNING + " Assuming this disk is *not* a GPT disk anymore.\n"); + printk(KERN_WARNING + " Use gpt kernel option to override. " + "Use GNU Parted to correct disk.\n"); + goto fail; + } + + /* Would fail due to bad PMBR, but force GPT anyhow */ + if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) { + printk(KERN_WARNING + " Warning: Disk has a valid GPT signature but " + "invalid PMBR.\n"); + printk(KERN_WARNING + " Use GNU Parted to correct disk.\n"); + printk(KERN_WARNING + " gpt option taken, disk treated as GPT.\n"); + } + + compare_gpts(pgpt, agpt, lastlba); + + /* The good cases */ + if (good_pgpt && (good_pmbr || force_gpt)) { + *gpt = pgpt; + *ptes = pptes; + if (agpt) { kfree(agpt); agpt = NULL; } + if (aptes) { kfree(aptes); aptes = NULL; } + if (!good_agpt) { + printk(KERN_WARNING + "Alternate GPT is invalid, " + "using primary GPT.\n"); + } + return 1; + } + else if (good_agpt && (good_pmbr || force_gpt)) { + *gpt = agpt; + *ptes = aptes; + if (pgpt) { kfree(pgpt); pgpt = NULL; } + if (pptes) { kfree(pptes); pptes = NULL; } + printk(KERN_WARNING + "Primary GPT is invalid, using alternate GPT.\n"); + return 1; + } + + fail: + if (pgpt) { kfree(pgpt); pgpt=NULL; } + if (agpt) { kfree(agpt); agpt=NULL; } + if (pptes) { kfree(pptes); pptes=NULL; } + if (aptes) { kfree(aptes); aptes=NULL; } + *gpt = NULL; + *ptes = NULL; + return 0; +} + +/** + * add_gpt_partitions(struct gendisk *hd, struct block_device *bdev, + * @hd + * @bdev + * + * Description: Create devices for each entry in the GUID Partition Table + * Entries. + * + * We do not create a Linux partition for GPT, but + * only for the actual data partitions. + * Returns: + * -1 if unable to read the partition table + * 0 if this isn't our partition table + * 1 if successful + * + */ +static int +add_gpt_partitions(struct gendisk *hd, struct block_device *bdev, int nextminor) +{ + gpt_header *gpt = NULL; + gpt_entry *ptes = NULL; + u32 i; + int max_p; + + if (!hd || !bdev) + return -1; + + if (!find_valid_gpt(hd, bdev, &gpt, &ptes) || !gpt || !ptes) { + if (gpt) { + kfree(gpt); + gpt = NULL; + } + if (ptes) { + kfree(ptes); + ptes = NULL; + } + return 0; + } + + Dprintk("GUID Partition Table is valid! Yea!\n"); + + max_p = (1 << hd->minor_shift) - 1; + for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < max_p; i++) { + if (!efi_guidcmp(ptes[i].partition_type_guid, NULL_GUID)) + continue; + + add_gd_partition(hd, nextminor+i, + le64_to_cpu(ptes[i].starting_lba), + (le64_to_cpu(ptes[i].ending_lba) - + le64_to_cpu(ptes[i].starting_lba) + + 1)); + + /* If there's this is a RAID volume, tell md */ +#if CONFIG_BLK_DEV_MD + if (!efi_guidcmp(ptes[i].partition_type_guid, + PARTITION_LINUX_RAID_GUID)) { + md_autodetect_dev(MKDEV + (MAJOR(to_kdev_t(bdev->bd_dev)), + nextminor+i)); + } +#endif + } + kfree(ptes); + ptes=NULL; + kfree(gpt); + gpt=NULL; + printk("\n"); + return 1; +} + +/** + * efi_partition(): EFI GPT partition handling entry function + * @hd + * @bdev + * @first_sector: unused + * @first_part_minor: minor number assigned to first GPT partition found + * + * Description: called from check.c, if the disk contains GPT + * partitions, sets up partition entries in the kernel. + * + * If the first block on the disk is a legacy MBR, + * it will get handled by msdos_partition(). + * If it's a Protective MBR, we'll handle it here. + * + * set_blocksize() calls are necessary to be able to read + * a disk with an odd number of 512-byte sectors, as the + * default BLOCK_SIZE of 1024 bytes won't let that last + * sector be read otherwise. + * + * Returns: + * -1 if unable to read the partition table + * 0 if this isn't our partitoin table + * 1 if successful + */ +int +efi_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor) +{ + + kdev_t dev = to_kdev_t(bdev->bd_dev); + int hardblocksize = get_hardsect_size(dev); + int orig_blksize_size = BLOCK_SIZE; + int rc = 0; + + /* Need to change the block size that the block layer uses */ + if (blksize_size[MAJOR(dev)]) { + orig_blksize_size = blksize_size[MAJOR(dev)][MINOR(dev)]; + } + + if (orig_blksize_size != hardblocksize) + set_blocksize(dev, hardblocksize); + + rc = add_gpt_partitions(hd, bdev, first_part_minor); + + /* change back */ + if (orig_blksize_size != hardblocksize) + set_blocksize(dev, orig_blksize_size); + + return rc; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -Nur linux-2.4.19/fs/partitions/efi.h linux-2.4.19-sgi211r3/fs/partitions/efi.h --- linux-2.4.19/fs/partitions/efi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/partitions/efi.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,134 @@ +/************************************************************ + * EFI GUID Partition Table + * Per Intel EFI Specification v1.02 + * http://developer.intel.com/technology/efi/efi.htm + * + * By Matt Domsch Fri Sep 22 22:15:56 CDT 2000 + * Copyright 2000,2001 Dell Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ************************************************************/ + +#ifndef FS_PART_EFI_H_INCLUDED +#define FS_PART_EFI_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSDOS_MBR_SIGNATURE 0xaa55 +#define EFI_PMBR_OSTYPE_EFI 0xEF +#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE + +#define GPT_BLOCK_SIZE 512 +#define GPT_HEADER_SIGNATURE 0x5452415020494645L +#define GPT_HEADER_REVISION_V1 0x00010000 +#define GPT_PRIMARY_PARTITION_TABLE_LBA 1 + +#define PARTITION_SYSTEM_GUID \ + EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \ + 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) +#define LEGACY_MBR_PARTITION_GUID \ + EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \ + 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F) +#define PARTITION_MSFT_RESERVED_GUID \ + EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \ + 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE) +#define PARTITION_BASIC_DATA_GUID \ + EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \ + 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) +#define PARTITION_LINUX_RAID_GUID \ + EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \ + 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e) +#define PARTITION_LINUX_SWAP_GUID \ + EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \ + 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f) +#define PARTITION_LINUX_LVM_GUID \ + EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ + 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) + +typedef struct _gpt_header { + u64 signature; + u32 revision; + u32 header_size; + u32 header_crc32; + u32 reserved1; + u64 my_lba; + u64 alternate_lba; + u64 first_usable_lba; + u64 last_usable_lba; + efi_guid_t disk_guid; + u64 partition_entry_lba; + u32 num_partition_entries; + u32 sizeof_partition_entry; + u32 partition_entry_array_crc32; + u8 reserved2[GPT_BLOCK_SIZE - 92]; +} __attribute__ ((packed)) gpt_header; + +typedef struct _gpt_entry_attributes { + u64 required_to_function:1; + u64 reserved:47; + u64 type_guid_specific:16; +} __attribute__ ((packed)) gpt_entry_attributes; + +typedef struct _gpt_entry { + efi_guid_t partition_type_guid; + efi_guid_t unique_partition_guid; + u64 starting_lba; + u64 ending_lba; + gpt_entry_attributes attributes; + efi_char16_t partition_name[72 / sizeof (efi_char16_t)]; +} __attribute__ ((packed)) gpt_entry; + +typedef struct _legacy_mbr { + u8 boot_code[440]; + u32 unique_mbr_signature; + u16 unknown; + struct partition partition_record[4]; + u16 signature; +} __attribute__ ((packed)) legacy_mbr; + +/* Functions */ +extern int + efi_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * -------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -Nur linux-2.4.19/fs/partitions/msdos.c linux-2.4.19-sgi211r3/fs/partitions/msdos.c --- linux-2.4.19/fs/partitions/msdos.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/partitions/msdos.c Wed Oct 16 14:02:58 2002 @@ -41,6 +41,7 @@ #include "check.h" #include "msdos.h" +#include "efi.h" #if CONFIG_BLK_DEV_MD extern void md_autodetect_dev(kdev_t dev); @@ -573,6 +574,16 @@ return 0; } p = (struct partition *) (data + 0x1be); +#ifdef CONFIG_EFI_PARTITION + for (i=1 ; i<=4 ; i++,p++) { + /* If this is an EFI GPT disk, msdos should ignore it. */ + if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) { + put_dev_sector(sect); + return 0; + } + } + p = (struct partition *) (data + 0x1be); +#endif /* * Look for partitions in two passes: diff -Nur linux-2.4.19/fs/partitions/sgi.c linux-2.4.19-sgi211r3/fs/partitions/sgi.c --- linux-2.4.19/fs/partitions/sgi.c Mon Oct 1 20:03:26 2001 +++ linux-2.4.19-sgi211r3/fs/partitions/sgi.c Thu Dec 12 17:42:31 2002 @@ -35,8 +35,8 @@ int num_bytes; /* How big, in bytes */ } volume[15]; struct sgi_partition { - int num_blocks; /* Size in logical blocks */ - int first_block; /* First logical block */ + unsigned int num_blocks; /* Size in logical blocks */ + unsigned int first_block; /* First logical block */ int type; /* Type of this partition */ } partitions[16]; int csum; /* Disk label checksum */ @@ -71,12 +71,11 @@ * partitions which we don't care about so we never overflow the * current_minor. */ - for(i = 0; i < 16; i++, p++) { + for(i = 0; i < 15; i++, p++) { blocks = be32_to_cpu(p->num_blocks); start = be32_to_cpu(p->first_block); - if(!blocks) - continue; - add_gd_partition(hd, current_minor, start, blocks); + if (blocks) + add_gd_partition(hd, current_minor, start, blocks); current_minor++; } printk("\n"); diff -Nur linux-2.4.19/fs/proc/array.c linux-2.4.19-sgi211r3/fs/proc/array.c --- linux-2.4.19/fs/proc/array.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/proc/array.c Sat Feb 1 09:23:35 2003 @@ -338,9 +338,8 @@ /* scale priority and nice values from timeslices to -20..20 */ /* to make it look like a "normal" Unix priority/nice value */ - priority = task->counter; - priority = 20 - (priority * 10 + DEF_COUNTER / 2) / DEF_COUNTER; - nice = task->nice; + priority = task_prio(task); + nice = task_nice(task); read_lock(&tasklist_lock); ppid = task->pid ? task->p_opptr->pid : 0; @@ -390,87 +389,12 @@ task->nswap, task->cnswap, task->exit_signal, - task->processor); + task->cpu); if(mm) mmput(mm); return res; } -static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, - int * pages, int * shared, int * dirty, int * total) -{ - pte_t * pte; - unsigned long end; - - if (pmd_none(*pmd)) - return; - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - return; - } - pte = pte_offset(pmd, address); - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - do { - pte_t page = *pte; - struct page *ptpage; - - address += PAGE_SIZE; - pte++; - if (pte_none(page)) - continue; - ++*total; - if (!pte_present(page)) - continue; - ptpage = pte_page(page); - if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) - continue; - ++*pages; - if (pte_dirty(page)) - ++*dirty; - if (page_count(pte_page(page)) > 1) - ++*shared; - } while (address < end); -} - -static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size, - int * pages, int * shared, int * dirty, int * total) -{ - pmd_t * pmd; - unsigned long end; - - if (pgd_none(*pgd)) - return; - if (pgd_bad(*pgd)) { - pgd_ERROR(*pgd); - pgd_clear(pgd); - return; - } - pmd = pmd_offset(pgd, address); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - do { - statm_pte_range(pmd, address, end - address, pages, shared, dirty, total); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); -} - -static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end, - int * pages, int * shared, int * dirty, int * total) -{ - while (address < end) { - statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - pgd++; - } -} - int proc_pid_statm(struct task_struct *task, char * buffer) { struct mm_struct *mm; @@ -483,26 +407,20 @@ task_unlock(task); if (mm) { struct vm_area_struct * vma; + down_read(&mm->mmap_sem); - vma = mm->mmap; - while (vma) { - pgd_t *pgd = pgd_offset(mm, vma->vm_start); - int pages = 0, shared = 0, dirty = 0, total = 0; + resident = mm->rss; + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + int pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); - resident += pages; - share += shared; - dt += dirty; - size += total; + size += pages; + if (vma->vm_flags & VM_SHARED || vma->vm_next_share) + share += pages; if (vma->vm_flags & VM_EXECUTABLE) trs += pages; /* text */ - else if (vma->vm_flags & VM_GROWSDOWN) - drs += pages; /* stack */ - else if (vma->vm_end > 0x60000000) - lrs += pages; /* library */ else drs += pages; - vma = vma->vm_next; } up_read(&mm->mmap_sem); mmput(mm); diff -Nur linux-2.4.19/fs/proc/base.c linux-2.4.19-sgi211r3/fs/proc/base.c --- linux-2.4.19/fs/proc/base.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/proc/base.c Wed Oct 16 14:02:58 2002 @@ -438,7 +438,29 @@ } #endif +static loff_t mem_lseek(struct file * file, loff_t offset, int orig) +{ + loff_t ret; + + switch (orig) { + case 0: + file->f_pos = offset; + ret = file->f_pos; + force_successful_syscall_return(); + break; + case 1: + file->f_pos += offset; + ret = file->f_pos; + force_successful_syscall_return(); + break; + default: + return -EINVAL; + } + return ret; +} + static struct file_operations proc_mem_operations = { + llseek: mem_lseek, read: mem_read, write: mem_write, open: mem_open, diff -Nur linux-2.4.19/fs/proc/generic.c linux-2.4.19-sgi211r3/fs/proc/generic.c --- linux-2.4.19/fs/proc/generic.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/proc/generic.c Mon Oct 28 20:43:23 2002 @@ -16,6 +16,7 @@ #include #define __NO_VERSION__ #include +#include #include static ssize_t proc_file_read(struct file * file, char * buf, @@ -140,7 +141,9 @@ static loff_t proc_file_lseek(struct file * file, loff_t offset, int origin) { - long long retval; + loff_t retval; + + lock_kernel(); switch (origin) { case 2: @@ -157,6 +160,8 @@ } retval = offset; } + + unlock_kernel(); return retval; } diff -Nur linux-2.4.19/fs/proc/kcore.c linux-2.4.19-sgi211r3/fs/proc/kcore.c --- linux-2.4.19/fs/proc/kcore.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/proc/kcore.c Wed Oct 16 14:02:58 2002 @@ -21,6 +21,9 @@ #include #include +#ifdef CONFIG_NUMA +extern char _stext, __init_etext, __init_sdata, _end; +#endif static int open_kcore(struct inode * inode, struct file * filp) { @@ -112,6 +115,12 @@ extern char saved_command_line[]; +#ifdef CONFIG_NUMA +#define KCORE_NPHDRS 4 +#else +#define KCORE_NPHDRS 2 +#endif + static size_t get_kcore_size(int *num_vma, size_t *elf_buflen) { size_t try, size; @@ -131,7 +140,7 @@ *num_vma = *num_vma + 1; } *elf_buflen = sizeof(struct elfhdr) + - (*num_vma + 2)*sizeof(struct elf_phdr) + + (*num_vma + KCORE_NPHDRS)*sizeof(struct elf_phdr) + 3 * sizeof(struct memelfnote); *elf_buflen = PAGE_ALIGN(*elf_buflen); return (size - PAGE_OFFSET + *elf_buflen); @@ -212,7 +221,7 @@ elf->e_flags = 0; elf->e_ehsize = sizeof(struct elfhdr); elf->e_phentsize= sizeof(struct elf_phdr); - elf->e_phnum = 2 + num_vma; + elf->e_phnum = KCORE_NPHDRS + num_vma; elf->e_shentsize= 0; elf->e_shnum = 0; elf->e_shstrndx = 0; @@ -237,12 +246,38 @@ offset += sizeof(struct elf_phdr); phdr->p_type = PT_LOAD; phdr->p_flags = PF_R|PF_W|PF_X; - phdr->p_offset = dataoff; + phdr->p_offset = PAGE_OFFSET - 0x8000000000000000; phdr->p_vaddr = PAGE_OFFSET; phdr->p_paddr = __pa(PAGE_OFFSET); phdr->p_filesz = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET); phdr->p_align = PAGE_SIZE; +#ifdef CONFIG_NUMA + /* pernode area */ + phdr = (struct elf_phdr *) bufp; + bufp += sizeof(struct elf_phdr); + offset += sizeof(struct elf_phdr); + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_X; + phdr->p_offset = (size_t)&_stext - 0x8000000000000000; + phdr->p_vaddr = (unsigned long)&_stext; + phdr->p_paddr = __tpa(&_stext); + phdr->p_filesz = phdr->p_memsz = &__init_etext - &_stext; + phdr->p_align = PAGE_SIZE; + + /* global area */ + phdr = (struct elf_phdr *) bufp; + bufp += sizeof(struct elf_phdr); + offset += sizeof(struct elf_phdr); + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_offset = (size_t)&__init_sdata - 0x8000000000000000; + phdr->p_vaddr = (unsigned long)&__init_sdata; + phdr->p_paddr = __tpa(&__init_sdata); + phdr->p_filesz = phdr->p_memsz = &_end - &__init_sdata; + phdr->p_align = PAGE_SIZE; +#endif + /* setup ELF PT_LOAD program header for every vmalloc'd area */ for (m=vmlist; m; m=m->next) { if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */ @@ -254,9 +289,13 @@ phdr->p_type = PT_LOAD; phdr->p_flags = PF_R|PF_W|PF_X; - phdr->p_offset = (size_t)m->addr - PAGE_OFFSET + dataoff; + phdr->p_offset = (size_t)m->addr - 0x8000000000000000; phdr->p_vaddr = (size_t)m->addr; +#ifdef CONFIG_DISCONTIGMEM + phdr->p_paddr = __tpa(m->addr); +#else phdr->p_paddr = __pa(m->addr); +#endif phdr->p_filesz = phdr->p_memsz = m->size; phdr->p_align = PAGE_SIZE; } @@ -354,9 +393,7 @@ buffer += tsz; acc += tsz; - /* leave now if filled buffer already */ - if (buflen == 0) - return acc; + return acc; } else read_unlock(&vmlist_lock); @@ -387,7 +424,11 @@ * We said in the ELF header that the data which starts * at 'elf_buflen' is virtual address PAGE_OFFSET. --rmk */ +#ifdef CONFIG_DISCONTIGMEM + start = *fpos + 0x8000000000000000; //jh +#else start = PAGE_OFFSET + (*fpos - elf_buflen); +#endif if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) tsz = buflen; @@ -437,6 +478,16 @@ return -EFAULT; } kfree(elf_buf); +#ifdef CONFIG_NUMA + } else if (start >= (unsigned long)&_stext && + start < (unsigned long)&__init_etext) { + if (copy_to_user(buffer, (char *)start, tsz)) + return -EFAULT; + } else if (start >= (unsigned long)&__init_sdata && + start < (unsigned long)&_end) { + if (copy_to_user(buffer, (char *)start, tsz)) + return -EFAULT; +#endif } else if ((start > PAGE_OFFSET) && (start < (unsigned long)high_memory)) { if (kern_addr_valid(start)) { diff -Nur linux-2.4.19/fs/proc/proc_misc.c linux-2.4.19-sgi211r3/fs/proc/proc_misc.c --- linux-2.4.19/fs/proc/proc_misc.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/proc/proc_misc.c Thu Feb 6 16:27:15 2003 @@ -55,7 +55,6 @@ extern int get_module_list(char *); #endif extern int get_device_list(char *); -extern int get_partition_list(char *, char **, off_t, int); extern int get_filesystem_list(char *); extern int get_exec_domain_list(char *); extern int get_irq_list(char *); @@ -65,6 +64,9 @@ #ifdef CONFIG_SGI_DS1286 extern int get_ds1286_status(char *); #endif +#ifdef CONFIG_DISCONTIGMEM +extern int get_discontig_info(char *); +#endif void proc_sprintf(char *page, off_t *off, int *lenp, const char *format, ...) { @@ -107,11 +109,11 @@ a = avenrun[0] + (FIXED_1/200); b = avenrun[1] + (FIXED_1/200); c = avenrun[2] + (FIXED_1/200); - len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n", + len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running, nr_threads, last_pid); + nr_running(), nr_threads, last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } @@ -123,7 +125,7 @@ int len; uptime = jiffies; - idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime; + idle = init_task.times.tms_utime + init_task.times.tms_stime; /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but that would overflow about every five days at HZ == 100. @@ -236,6 +238,20 @@ release: seq_release, }; +#if defined(CONFIG_IA64) +extern struct seq_operations interrupts_op; +static int interrupts_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &interrupts_op); +} +static struct file_operations proc_interrupts_operations = { + open: interrupts_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; +#endif + #ifdef CONFIG_PROC_HARDWARE static int hardware_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -254,6 +270,18 @@ } #endif +extern struct seq_operations partitions_op; +static int partitions_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &partitions_op); +} +static struct file_operations proc_partitions_operations = { + open: partitions_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; + #ifdef CONFIG_MODULES static int modules_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -305,7 +333,7 @@ nice += kstat.per_cpu_nice[cpu]; system += kstat.per_cpu_system[cpu]; #if !defined(CONFIG_ARCH_S390) - for (j = 0 ; j < NR_IRQS ; j++) + for (j = 0 ; j < NR_IVECS; j++) sum += kstat.irqs[cpu][j]; #endif } @@ -334,7 +362,8 @@ sum ); #if !defined(CONFIG_ARCH_S390) - for (i = 0 ; i < NR_IRQS ; i++) + for (i = 0 ; i < NR_IVECS ; i++) + len += sprintf(page + len, " %u", kstat_irqs(i)); proc_sprintf(page, &off, &len, " %u", kstat_irqs(i)); #endif @@ -360,10 +389,10 @@ } proc_sprintf(page, &off, &len, - "\nctxt %u\n" + "\nctxt %lu\n" "btime %lu\n" "processes %lu\n", - kstat.context_swtch, + nr_context_switches(), xtime.tv_sec - jif / HZ, total_forks); @@ -377,15 +406,7 @@ return proc_calc_metrics(page, start, off, count, eof, len); } -static int partitions_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = get_partition_list(page, start, off, count); - if (len < count) *eof = 1; - return len; -} - -#if !defined(CONFIG_ARCH_S390) +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_IA64) static int interrupts_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -452,6 +473,15 @@ return proc_calc_metrics(page, start, off, count, eof, len); } +#ifdef CONFIG_DISCONTIGMEM +static int discontig_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_discontig_info(page); + return proc_calc_metrics(page, start, off, count, eof, len); +} +#endif + static int swaps_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -466,6 +496,7 @@ return proc_calc_metrics(page, start, off, count, eof, len); } + /* * This function accesses profiling information. The returned data is * binary: the sampling step and the actual contents of the profile @@ -561,8 +592,7 @@ #endif {"stat", kstat_read_proc}, {"devices", devices_read_proc}, - {"partitions", partitions_read_proc}, -#if !defined(CONFIG_ARCH_S390) +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_IA64) {"interrupts", interrupts_read_proc}, #endif {"filesystems", filesystems_read_proc}, @@ -576,6 +606,9 @@ {"swaps", swaps_read_proc}, {"iomem", memory_read_proc}, {"execdomains", execdomains_read_proc}, +#ifdef CONFIG_DISCONTIGMEM + {"discontig", discontig_read_proc}, +#endif {NULL,} }; for (p = simple_ones; p->name; p++) @@ -588,6 +621,10 @@ if (entry) entry->proc_fops = &proc_kmsg_operations; create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); + create_seq_entry("partitions", 0, &proc_partitions_operations); +#if defined(CONFIG_IA64) + create_seq_entry("interrupts", 0, &proc_interrupts_operations); +#endif create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); #ifdef CONFIG_MODULES create_seq_entry("ksyms", 0, &proc_ksyms_operations); diff -Nur linux-2.4.19/fs/quota.c linux-2.4.19-sgi211r3/fs/quota.c --- linux-2.4.19/fs/quota.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/quota.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,654 @@ +/* + * Quota code necessary even when VFS quota support is not compiled + * into the kernel. The interesting stuff is over in dquot.c, here + * we have symbols for initial quotactl(2) handling, the sysctl(2) + * variables, etc - things needed even when quota support disabled. + */ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_QIFACE_COMPAT +#include +#endif + + +/* Check validity of quotactl */ +static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +{ + if (type >= MAXQUOTAS) + return -EINVAL; + /* Is operation supported? */ + if (!sb->s_qcop) + return -ENOSYS; + + switch (cmd) { + case Q_GETFMT: + break; + case Q_QUOTAON: + if (!sb->s_qcop->quota_on) + return -ENOSYS; + break; + case Q_QUOTAOFF: + if (!sb->s_qcop->quota_off) + return -ENOSYS; + break; + case Q_SETINFO: + if (!sb->s_qcop->set_info) + return -ENOSYS; + break; + case Q_GETINFO: + if (!sb->s_qcop->get_info) + return -ENOSYS; + break; + case Q_SETQUOTA: + if (!sb->s_qcop->set_dqblk) + return -ENOSYS; + break; + case Q_GETQUOTA: + if (!sb->s_qcop->get_dqblk) + return -ENOSYS; + break; + case Q_SYNC: + if (!sb->s_qcop->quota_sync) + return -ENOSYS; + break; + case Q_XQUOTAON: + case Q_XQUOTAOFF: + case Q_XQUOTARM: + if (!sb->s_qcop->set_xstate) + return -ENOSYS; + break; + case Q_XGETQSTAT: + if (!sb->s_qcop->get_xstate) + return -ENOSYS; + break; + case Q_XSETQLIM: + if (!sb->s_qcop->set_xquota) + return -ENOSYS; + break; + case Q_XGETQUOTA: + if (!sb->s_qcop->get_xquota) + return -ENOSYS; + break; + default: + return -EINVAL; + } + + /* Is quota turned on for commands which need it? */ + switch (cmd) { + case Q_GETFMT: + case Q_GETINFO: + case Q_QUOTAOFF: + case Q_SETINFO: + case Q_SETQUOTA: + case Q_GETQUOTA: + if (!sb_has_quota_enabled(sb, type)) + return -ESRCH; + } + /* Check privileges */ + if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) { + if (((type == USRQUOTA && current->euid != id) || + (type == GRPQUOTA && !in_egroup_p(id))) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + } + else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT) + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + +/* Resolve device pathname to superblock */ +static struct super_block *resolve_dev(const char *path) +{ + int ret; + mode_t mode; + struct nameidata nd; + kdev_t dev; + struct super_block *sb; + + ret = user_path_walk(path, &nd); + if (ret) + goto out; + + dev = nd.dentry->d_inode->i_rdev; + mode = nd.dentry->d_inode->i_mode; + path_release(&nd); + + ret = -ENOTBLK; + if (!S_ISBLK(mode)) + goto out; + ret = -ENODEV; + sb = get_super(dev); + if (!sb) + goto out; + return sb; +out: + return ERR_PTR(ret); +} + +/* Copy parameters and call proper function */ +static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr) +{ + int ret; + + switch (cmd) { + case Q_QUOTAON: { + char *pathname; + + if (IS_ERR(pathname = getname(addr))) + return PTR_ERR(pathname); + ret = sb->s_qcop->quota_on(sb, type, id, pathname); + putname(pathname); + return ret; + } + case Q_QUOTAOFF: + return sb->s_qcop->quota_off(sb, type); + + case Q_GETFMT: { + __u32 fmt; + + fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; + if (copy_to_user(addr, &fmt, sizeof(fmt))) + return -EFAULT; + return 0; + } + case Q_GETINFO: { + struct if_dqinfo info; + + if ((ret = sb->s_qcop->get_info(sb, type, &info))) + return ret; + if (copy_to_user(addr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case Q_SETINFO: { + struct if_dqinfo info; + + if (copy_from_user(&info, addr, sizeof(info))) + return -EFAULT; + return sb->s_qcop->set_info(sb, type, &info); + } + case Q_GETQUOTA: { + struct if_dqblk idq; + + if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq))) + return ret; + if (copy_to_user(addr, &idq, sizeof(idq))) + return -EFAULT; + return 0; + } + case Q_SETQUOTA: { + struct if_dqblk idq; + + if (copy_from_user(&idq, addr, sizeof(idq))) + return -EFAULT; + return sb->s_qcop->set_dqblk(sb, type, id, &idq); + } + case Q_SYNC: + return sb->s_qcop->quota_sync(sb, type); + + case Q_XQUOTAON: + case Q_XQUOTAOFF: + case Q_XQUOTARM: { + __u32 flags; + + if (copy_from_user(&flags, addr, sizeof(flags))) + return -EFAULT; + return sb->s_qcop->set_xstate(sb, flags, cmd); + } + case Q_XGETQSTAT: { + struct fs_quota_stat fqs; + + if ((ret = sb->s_qcop->get_xstate(sb, &fqs))) + return ret; + if (copy_to_user(addr, &fqs, sizeof(fqs))) + return -EFAULT; + return 0; + } + case Q_XSETQLIM: { + struct fs_disk_quota fdq; + + if (copy_from_user(&fdq, addr, sizeof(fdq))) + return -EFAULT; + return sb->s_qcop->set_xquota(sb, type, id, &fdq); + } + case Q_XGETQUOTA: { + struct fs_disk_quota fdq; + + if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq))) + return ret; + if (copy_to_user(addr, &fdq, sizeof(fdq))) + return -EFAULT; + return 0; + } + /* We never reach here unless validity check is broken */ + default: + BUG(); + } + return 0; +} + +#ifdef CONFIG_QIFACE_COMPAT +static int check_compat_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +{ + if (type >= MAXQUOTAS) + return -EINVAL; + /* Is operation supported? */ + /* sb==NULL for GETSTATS calls */ + if (sb && !sb->s_qcop) + return -ENOSYS; + + switch (cmd) { + case Q_COMP_QUOTAON: + if (!sb->s_qcop->quota_on) + return -ENOSYS; + break; + case Q_COMP_QUOTAOFF: + if (!sb->s_qcop->quota_off) + return -ENOSYS; + break; + case Q_COMP_SYNC: + if (!sb->s_qcop->quota_sync) + return -ENOSYS; + break; +#ifdef CONFIG_QIFACE_V2 + case Q_V2_SETFLAGS: + case Q_V2_SETGRACE: + case Q_V2_SETINFO: + if (!sb->s_qcop->set_info) + return -ENOSYS; + break; + case Q_V2_GETINFO: + if (!sb->s_qcop->get_info) + return -ENOSYS; + break; + case Q_V2_SETQLIM: + case Q_V2_SETUSE: + case Q_V2_SETQUOTA: + if (!sb->s_qcop->set_dqblk) + return -ENOSYS; + break; + case Q_V2_GETQUOTA: + if (!sb->s_qcop->get_dqblk) + return -ENOSYS; + break; + case Q_V2_GETSTATS: + return 0; /* GETSTATS need no other checks */ +#endif +#ifdef CONFIG_QIFACE_V1 + case Q_V1_SETQLIM: + case Q_V1_SETUSE: + case Q_V1_SETQUOTA: + if (!sb->s_qcop->set_dqblk) + return -ENOSYS; + break; + case Q_V1_GETQUOTA: + if (!sb->s_qcop->get_dqblk) + return -ENOSYS; + break; + case Q_V1_RSQUASH: + if (!sb->s_qcop->set_info) + return -ENOSYS; + break; + case Q_V1_GETSTATS: + return 0; /* GETSTATS need no other checks */ +#endif + default: + return -EINVAL; + } + + /* Is quota turned on for commands which need it? */ + switch (cmd) { + case Q_V2_SETFLAGS: + case Q_V2_SETGRACE: + case Q_V2_SETINFO: + case Q_V2_GETINFO: + case Q_COMP_QUOTAOFF: + case Q_V1_RSQUASH: + case Q_V1_SETQUOTA: + case Q_V1_SETQLIM: + case Q_V1_SETUSE: + case Q_V2_SETQUOTA: + /* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */ + case Q_V2_SETUSE: + case Q_V1_GETQUOTA: + case Q_V2_GETQUOTA: + if (!sb_has_quota_enabled(sb, type)) + return -ESRCH; + } +#ifdef CONFIG_QIFACE_V1 + if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_OLD) +#else + if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_V0) +#endif + return -ESRCH; + + /* Check privileges */ + if (cmd == Q_V1_GETQUOTA || cmd == Q_V2_GETQUOTA) { + if (((type == USRQUOTA && current->euid != id) || + (type == GRPQUOTA && !in_egroup_p(id))) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + } + else if (cmd != Q_V1_GETSTATS && cmd != Q_V2_GETSTATS && cmd != Q_V2_GETINFO && cmd != Q_COMP_SYNC) + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + +#ifdef CONFIG_QIFACE_V1 +static int v1_set_rsquash(struct super_block *sb, int type, int flag) +{ + struct if_dqinfo info; + + info.dqi_valid = IIF_FLAGS; + info.dqi_flags = flag ? V1_DQF_RSQUASH : 0; + return sb->s_qcop->set_info(sb, type, &info); +} + +static int v1_get_dqblk(struct super_block *sb, int type, qid_t id, struct v1c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + int ret; + + if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0) + return ret; + mdq->dqb_ihardlimit = idq.dqb_ihardlimit; + mdq->dqb_isoftlimit = idq.dqb_isoftlimit; + mdq->dqb_curinodes = idq.dqb_curinodes; + mdq->dqb_bhardlimit = idq.dqb_bhardlimit; + mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit; + mdq->dqb_curblocks = toqb(idq.dqb_curspace); + mdq->dqb_itime = idq.dqb_itime; + mdq->dqb_btime = idq.dqb_btime; + if (id == 0) { /* Times for id 0 are in fact grace times */ + struct if_dqinfo info; + + if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0) + return ret; + mdq->dqb_btime = info.dqi_bgrace; + mdq->dqb_itime = info.dqi_igrace; + } + return 0; +} + +static int v1_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v1c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + int ret; + + idq.dqb_valid = 0; + if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETQLIM) { + idq.dqb_ihardlimit = mdq->dqb_ihardlimit; + idq.dqb_isoftlimit = mdq->dqb_isoftlimit; + idq.dqb_bhardlimit = mdq->dqb_bhardlimit; + idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit; + idq.dqb_valid |= QIF_LIMITS; + } + if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETUSE) { + idq.dqb_curinodes = mdq->dqb_curinodes; + idq.dqb_curspace = ((qsize_t)mdq->dqb_curblocks) << QUOTABLOCK_BITS; + idq.dqb_valid |= QIF_USAGE; + } + ret = sb->s_qcop->set_dqblk(sb, type, id, &idq); + if (!ret && id == 0 && cmd == Q_V1_SETQUOTA) { /* Times for id 0 are in fact grace times */ + struct if_dqinfo info; + + info.dqi_bgrace = mdq->dqb_btime; + info.dqi_igrace = mdq->dqb_itime; + info.dqi_valid = IIF_BGRACE | IIF_IGRACE; + ret = sb->s_qcop->set_info(sb, type, &info); + } + return ret; +} + +static void v1_get_stats(struct v1c_dqstats *dst) +{ + memcpy(dst, &dqstats, sizeof(dqstats)); +} +#endif + +#ifdef CONFIG_QIFACE_V2 +static int v2_get_info(struct super_block *sb, int type, struct v2c_mem_dqinfo *oinfo) +{ + struct if_dqinfo info; + int ret; + + if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0) + return ret; + oinfo->dqi_bgrace = info.dqi_bgrace; + oinfo->dqi_igrace = info.dqi_igrace; + oinfo->dqi_flags = info.dqi_flags; + oinfo->dqi_blocks = sb_dqopt(sb)->info[type].u.v2_i.dqi_blocks; + oinfo->dqi_free_blk = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_blk; + oinfo->dqi_free_entry = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_entry; + return 0; +} + +static int v2_set_info(struct super_block *sb, int type, int cmd, struct v2c_mem_dqinfo *oinfo) +{ + struct if_dqinfo info; + + info.dqi_valid = 0; + if (cmd == Q_V2_SETGRACE || cmd == Q_V2_SETINFO) { + info.dqi_bgrace = oinfo->dqi_bgrace; + info.dqi_igrace = oinfo->dqi_igrace; + info.dqi_valid |= IIF_BGRACE | IIF_IGRACE; + } + if (cmd == Q_V2_SETFLAGS || cmd == Q_V2_SETINFO) { + info.dqi_flags = oinfo->dqi_flags; + info.dqi_valid |= IIF_FLAGS; + } + /* We don't simulate deadly effects of setting other parameters ;-) */ + return sb->s_qcop->set_info(sb, type, &info); +} + +static int v2_get_dqblk(struct super_block *sb, int type, qid_t id, struct v2c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + int ret; + + if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0) + return ret; + mdq->dqb_ihardlimit = idq.dqb_ihardlimit; + mdq->dqb_isoftlimit = idq.dqb_isoftlimit; + mdq->dqb_curinodes = idq.dqb_curinodes; + mdq->dqb_bhardlimit = idq.dqb_bhardlimit; + mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit; + mdq->dqb_curspace = idq.dqb_curspace; + mdq->dqb_itime = idq.dqb_itime; + mdq->dqb_btime = idq.dqb_btime; + return 0; +} + +static int v2_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v2c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + + idq.dqb_valid = 0; + if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETQLIM) { + idq.dqb_ihardlimit = mdq->dqb_ihardlimit; + idq.dqb_isoftlimit = mdq->dqb_isoftlimit; + idq.dqb_bhardlimit = mdq->dqb_bhardlimit; + idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit; + idq.dqb_valid |= QIF_LIMITS; + } + if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETUSE) { + idq.dqb_curinodes = mdq->dqb_curinodes; + idq.dqb_curspace = mdq->dqb_curspace; + idq.dqb_valid |= QIF_USAGE; + } + return sb->s_qcop->set_dqblk(sb, type, id, &idq); +} + +static void v2_get_stats(struct v2c_dqstats *dst) +{ + memcpy(dst, &dqstats, sizeof(dqstats)); + dst->version = __DQUOT_NUM_VERSION__; +} +#endif + +/* Handle requests to old interface */ +static int do_compat_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr) +{ + int ret; + + switch (cmd) { + case Q_COMP_QUOTAON: { + char *pathname; + + if (IS_ERR(pathname = getname(addr))) + return PTR_ERR(pathname); +#ifdef CONFIG_QIFACE_V1 + ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_OLD, pathname); +#else + ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_V0, pathname); +#endif + putname(pathname); + return ret; + } + case Q_COMP_QUOTAOFF: + return sb->s_qcop->quota_off(sb, type); + case Q_COMP_SYNC: + return sb->s_qcop->quota_sync(sb, type); +#ifdef CONFIG_QIFACE_V1 + case Q_V1_RSQUASH: { + int flag; + + if (copy_from_user(&flag, addr, sizeof(flag))) + return -EFAULT; + return v1_set_rsquash(sb, type, flag); + } + case Q_V1_GETQUOTA: { + struct v1c_mem_dqblk mdq; + + if ((ret = v1_get_dqblk(sb, type, id, &mdq))) + return ret; + if (copy_to_user(addr, &mdq, sizeof(mdq))) + return -EFAULT; + return 0; + } + case Q_V1_SETQLIM: + case Q_V1_SETUSE: + case Q_V1_SETQUOTA: { + struct v1c_mem_dqblk mdq; + + if (copy_from_user(&mdq, addr, sizeof(mdq))) + return -EFAULT; + return v1_set_dqblk(sb, type, cmd, id, &mdq); + } + case Q_V1_GETSTATS: { + struct v1c_dqstats dst; + + v1_get_stats(&dst); + if (copy_to_user(addr, &dst, sizeof(dst))) + return -EFAULT; + return 0; + } +#endif +#ifdef CONFIG_QIFACE_V2 + case Q_V2_GETINFO: { + struct v2c_mem_dqinfo info; + + if ((ret = v2_get_info(sb, type, &info))) + return ret; + if (copy_to_user(addr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case Q_V2_SETFLAGS: + case Q_V2_SETGRACE: + case Q_V2_SETINFO: { + struct v2c_mem_dqinfo info; + + if (copy_from_user(&info, addr, sizeof(info))) + return -EFAULT; + + return v2_set_info(sb, type, cmd, &info); + } + case Q_V2_GETQUOTA: { + struct v2c_mem_dqblk mdq; + + if ((ret = v2_get_dqblk(sb, type, id, &mdq))) + return ret; + if (copy_to_user(addr, &mdq, sizeof(mdq))) + return -EFAULT; + return 0; + } + case Q_V2_SETUSE: + case Q_V2_SETQLIM: + case Q_V2_SETQUOTA: { + struct v2c_mem_dqblk mdq; + + if (copy_from_user(&mdq, addr, sizeof(mdq))) + return -EFAULT; + return v2_set_dqblk(sb, type, cmd, id, &mdq); + } + case Q_V2_GETSTATS: { + struct v2c_dqstats dst; + + v2_get_stats(&dst); + if (copy_to_user(addr, &dst, sizeof(dst))) + return -EFAULT; + return 0; + } +#endif + } + BUG(); + return 0; +} +#endif + +/* Macros for short-circuiting the compatibility tests */ +#define NEW_COMMAND(c) ((c) & (0x80 << 16)) +#define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8)) + +/* + * This is the system call interface. This communicates with + * the user-level programs. Currently this only supports diskquota + * calls. Maybe we need to add the process quotas etc. in the future, + * but we probably should use rlimits for that. + */ +asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr) +{ + uint cmds, type; + struct super_block *sb = NULL; + int ret = -EINVAL; + + lock_kernel(); + cmds = cmd >> SUBCMDSHIFT; + type = cmd & SUBCMDMASK; + +#ifdef CONFIG_QIFACE_COMPAT + if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) { + ret = PTR_ERR(sb); + sb = NULL; + goto out; + } + if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) { + if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0) + goto out; + ret = do_compat_quotactl(sb, type, cmds, id, addr); + goto out; + } +#else + if (IS_ERR(sb = resolve_dev(special))) { + ret = PTR_ERR(sb); + sb = NULL; + goto out; + } +#endif + if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0) + goto out; + ret = do_quotactl(sb, type, cmds, id, addr); +out: + if (sb) + drop_super(sb); + unlock_kernel(); + return ret; +} diff -Nur linux-2.4.19/fs/quota_v1.c linux-2.4.19-sgi211r3/fs/quota_v1.c --- linux-2.4.19/fs/quota_v1.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/quota_v1.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void v1_disk2mem_dqblk(struct mem_dqblk *m, struct v1_disk_dqblk *d) +{ + m->dqb_ihardlimit = d->dqb_ihardlimit; + m->dqb_isoftlimit = d->dqb_isoftlimit; + m->dqb_curinodes = d->dqb_curinodes; + m->dqb_bhardlimit = d->dqb_bhardlimit; + m->dqb_bsoftlimit = d->dqb_bsoftlimit; + m->dqb_curspace = d->dqb_curblocks << QUOTABLOCK_BITS; + m->dqb_itime = d->dqb_itime; + m->dqb_btime = d->dqb_btime; +} + +static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m) +{ + d->dqb_ihardlimit = m->dqb_ihardlimit; + d->dqb_isoftlimit = m->dqb_isoftlimit; + d->dqb_curinodes = m->dqb_curinodes; + d->dqb_bhardlimit = m->dqb_bhardlimit; + d->dqb_bsoftlimit = m->dqb_bsoftlimit; + d->dqb_curblocks = toqb(m->dqb_curspace); + d->dqb_itime = m->dqb_itime; + d->dqb_btime = m->dqb_btime; +} + +static int v1_read_dqblk(struct dquot *dquot) +{ + int type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + struct v1_disk_dqblk dqblk; + + filp = sb_dqopt(dquot->dq_sb)->files[type]; + if (filp == (struct file *)NULL) + return -EINVAL; + + /* Now we are sure filp is valid */ + offset = v1_dqoff(dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset); + set_fs(fs); + + v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk); + if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 && + dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0) + dquot->dq_flags |= DQ_FAKE; + dqstats.reads++; + return 0; +} + +static int v1_commit_dqblk(struct dquot *dquot) +{ + short type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + ssize_t ret; + struct v1_disk_dqblk dqblk; + + filp = sb_dqopt(dquot->dq_sb)->files[type]; + offset = v1_dqoff(dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + + /* + * Note: clear the DQ_MOD flag unconditionally, + * so we don't loop forever on failure. + */ + v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb); + dquot->dq_flags &= ~DQ_MOD; + if (dquot->dq_id == 0) { + dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace; + dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace; + } + ret = 0; + if (filp) + ret = filp->f_op->write(filp, (char *)&dqblk, + sizeof(struct v1_disk_dqblk), &offset); + if (ret != sizeof(struct v1_disk_dqblk)) { + printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", + kdevname(dquot->dq_dev)); + if (ret >= 0) + ret = -EIO; + goto out; + } + ret = 0; + +out: + set_fs(fs); + dqstats.writes++; + return ret; +} + +/* Magics of new quota format */ +#define V2_INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +/* Header of new quota format */ +struct v2_disk_dqheader { + __u32 dqh_magic; /* Magic number identifying file */ + __u32 dqh_version; /* File version */ +}; + +static int v1_check_quota_file(struct super_block *sb, int type) +{ + struct file *f = sb_dqopt(sb)->files[type]; + struct inode *inode = f->f_dentry->d_inode; + ulong blocks; + size_t off; + struct v2_disk_dqheader dqhead; + mm_segment_t fs; + ssize_t size; + loff_t offset = 0; + static const uint quota_magics[] = V2_INITQMAGICS; + + if (!inode->i_size) + return 0; + blocks = inode->i_size >> BLOCK_SIZE_BITS; + off = inode->i_size & (BLOCK_SIZE - 1); + if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk)) + return 0; + /* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */ + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqheader)) + return 1; /* Probably not new format */ + if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type]) + return 1; /* Definitely not new format */ + printk(KERN_INFO "VFS: %s: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n", kdevname(sb->s_dev)); + return 0; /* Seems like a new format file -> refuse it */ +} + +static int v1_read_file_info(struct super_block *sb, int type) +{ + struct quota_info *dqopt = sb_dqopt(sb); + mm_segment_t fs; + loff_t offset; + struct file *filp = dqopt->files[type]; + struct v1_disk_dqblk dqblk; + int ret; + + down(&dqopt->dqio_sem); + offset = v1_dqoff(0); + fs = get_fs(); + set_fs(KERNEL_DS); + if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) { + if (ret >= 0) + ret = -EIO; + goto out; + } + ret = 0; + dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME; + dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME; +out: + up(&dqopt->dqio_sem); + set_fs(fs); + return ret; +} + +static int v1_write_file_info(struct super_block *sb, int type) +{ + struct quota_info *dqopt = sb_dqopt(sb); + mm_segment_t fs; + struct file *filp = dqopt->files[type]; + struct v1_disk_dqblk dqblk; + loff_t offset; + int ret; + + down(&dqopt->dqio_sem); + dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY; + offset = v1_dqoff(0); + fs = get_fs(); + set_fs(KERNEL_DS); + if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) { + if (ret >= 0) + ret = -EIO; + goto out; + } + dqblk.dqb_itime = dqopt->info[type].dqi_igrace; + dqblk.dqb_btime = dqopt->info[type].dqi_bgrace; + offset = v1_dqoff(0); + ret = filp->f_op->write(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset); + if (ret == sizeof(struct v1_disk_dqblk)) + ret = 0; + else if (ret > 0) + ret = -EIO; +out: + up(&dqopt->dqio_sem); + set_fs(fs); + return ret; +} + +static struct quota_format_ops v1_format_ops = { + check_quota_file: v1_check_quota_file, + read_file_info: v1_read_file_info, + write_file_info: v1_write_file_info, + free_file_info: NULL, + read_dqblk: v1_read_dqblk, + commit_dqblk: v1_commit_dqblk, +}; + +static struct quota_format_type v1_quota_format = { + qf_fmt_id: QFMT_VFS_OLD, + qf_ops: &v1_format_ops, + qf_owner: THIS_MODULE +}; + +static int __init init_v1_quota_format(void) +{ + return register_quota_format(&v1_quota_format); +} + +static void __exit exit_v1_quota_format(void) +{ + unregister_quota_format(&v1_quota_format); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_v1_quota_format); +module_exit(exit_v1_quota_format); + diff -Nur linux-2.4.19/fs/quota_v2.c linux-2.4.19-sgi211r3/fs/quota_v2.c --- linux-2.4.19/fs/quota_v2.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/quota_v2.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,690 @@ +/* + * vfsv0 quota IO operations on file + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define __QUOTA_V2_PARANOIA + +typedef char *dqbuf_t; + +#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) +#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) + +/* Check whether given file is really vfsv0 quotafile */ +static int v2_check_quota_file(struct super_block *sb, int type) +{ + struct v2_disk_dqheader dqhead; + struct file *f = sb_dqopt(sb)->files[type]; + mm_segment_t fs; + ssize_t size; + loff_t offset = 0; + static const uint quota_magics[] = V2_INITQMAGICS; + static const uint quota_versions[] = V2_INITQVERSIONS; + + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqheader)) + return 0; + if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || + le32_to_cpu(dqhead.dqh_version) != quota_versions[type]) + return 0; + return 1; +} + +/* Read information header from quota file */ +static int v2_read_file_info(struct super_block *sb, int type) +{ + mm_segment_t fs; + struct v2_disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqopt(sb)->info+type; + struct file *f = sb_dqopt(sb)->files[type]; + ssize_t size; + loff_t offset = V2_DQINFOOFF; + + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqinfo)) { + printk(KERN_WARNING "Can't read info structure on device %s.\n", + kdevname(f->f_dentry->d_sb->s_dev)); + return -1; + } + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); + info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); + info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); + info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); + info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); + return 0; +} + +/* Write information header to quota file */ +static int v2_write_file_info(struct super_block *sb, int type) +{ + mm_segment_t fs; + struct v2_disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqopt(sb)->info+type; + struct file *f = sb_dqopt(sb)->files[type]; + ssize_t size; + loff_t offset = V2_DQINFOOFF; + + info->dqi_flags &= ~DQF_INFO_DIRTY; + dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); + dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); + dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); + dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks); + dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk); + dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry); + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->write(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqinfo)) { + printk(KERN_WARNING "Can't write info structure on device %s.\n", + kdevname(f->f_dentry->d_sb->s_dev)); + return -1; + } + return 0; +} + +static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) +{ + m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); + m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); + m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); + m->dqb_itime = le64_to_cpu(d->dqb_itime); + m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit); + m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit); + m->dqb_curspace = le64_to_cpu(d->dqb_curspace); + m->dqb_btime = le64_to_cpu(d->dqb_btime); +} + +static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) +{ + d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); + d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); + d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); + d->dqb_itime = cpu_to_le64(m->dqb_itime); + d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit); + d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit); + d->dqb_curspace = cpu_to_le64(m->dqb_curspace); + d->dqb_btime = cpu_to_le64(m->dqb_btime); + d->dqb_id = cpu_to_le32(id); +} + +static dqbuf_t getdqbuf(void) +{ + dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_KERNEL); + if (!buf) + printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); + return buf; +} + +static inline void freedqbuf(dqbuf_t buf) +{ + kfree(buf); +} + +static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf) +{ + mm_segment_t fs; + ssize_t ret; + loff_t offset = blk<f_op->read(filp, (char *)buf, V2_DQBLKSIZE, &offset); + set_fs(fs); + return ret; +} + +static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf) +{ + mm_segment_t fs; + ssize_t ret; + loff_t offset = blk<f_op->write(filp, (char *)buf, V2_DQBLKSIZE, &offset); + set_fs(fs); + return ret; + +} + +/* Remove empty block from list and return it */ +static int get_free_dqblk(struct file *filp, struct mem_dqinfo *info) +{ + dqbuf_t buf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + int ret, blk; + + if (!buf) + return -ENOMEM; + if (info->u.v2_i.dqi_free_blk) { + blk = info->u.v2_i.dqi_free_blk; + if ((ret = read_blk(filp, blk, buf)) < 0) + goto out_buf; + info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); + } + else { + memset(buf, 0, V2_DQBLKSIZE); + if ((ret = write_blk(filp, info->u.v2_i.dqi_blocks, buf)) < 0) /* Assure block allocation... */ + goto out_buf; + blk = info->u.v2_i.dqi_blocks++; + } + mark_info_dirty(info); + ret = blk; +out_buf: + freedqbuf(buf); + return ret; +} + +/* Insert empty block to the list */ +static int put_free_dqblk(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + int err; + + dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk); + dh->dqdh_prev_free = cpu_to_le32(0); + dh->dqdh_entries = cpu_to_le16(0); + info->u.v2_i.dqi_free_blk = blk; + mark_info_dirty(info); + if ((err = write_blk(filp, blk, buf)) < 0) /* Some strange block. We had better leave it... */ + return err; + return 0; +} + +/* Remove given block from the list of blocks with free entries */ +static int remove_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free); + int err; + + if (!tmpbuf) + return -ENOMEM; + if (nextblk) { + if ((err = read_blk(filp, nextblk, tmpbuf)) < 0) + goto out_buf; + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; + if ((err = write_blk(filp, nextblk, tmpbuf)) < 0) + goto out_buf; + } + if (prevblk) { + if ((err = read_blk(filp, prevblk, tmpbuf)) < 0) + goto out_buf; + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; + if ((err = write_blk(filp, prevblk, tmpbuf)) < 0) + goto out_buf; + } + else { + info->u.v2_i.dqi_free_entry = nextblk; + mark_info_dirty(info); + } + freedqbuf(tmpbuf); + dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); + if (write_blk(filp, blk, buf) < 0) /* No matter whether write succeeds block is out of list */ + printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); + return 0; +out_buf: + freedqbuf(tmpbuf); + return err; +} + +/* Insert given block to the beginning of list with free entries */ +static int insert_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + int err; + + if (!tmpbuf) + return -ENOMEM; + dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry); + dh->dqdh_prev_free = cpu_to_le32(0); + if ((err = write_blk(filp, blk, buf)) < 0) + goto out_buf; + if (info->u.v2_i.dqi_free_entry) { + if ((err = read_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) + goto out_buf; + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk); + if ((err = write_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) + goto out_buf; + } + freedqbuf(tmpbuf); + info->u.v2_i.dqi_free_entry = blk; + mark_info_dirty(info); + return 0; +out_buf: + freedqbuf(tmpbuf); + return err; +} + +/* Find space for dquot */ +static uint find_free_dqentry(struct dquot *dquot, int *err) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type; + uint blk, i; + struct v2_disk_dqdbheader *dh; + struct v2_disk_dqblk *ddquot; + struct v2_disk_dqblk fakedquot; + dqbuf_t buf; + + *err = 0; + if (!(buf = getdqbuf())) { + *err = -ENOMEM; + return 0; + } + dh = (struct v2_disk_dqdbheader *)buf; + ddquot = GETENTRIES(buf); + if (info->u.v2_i.dqi_free_entry) { + blk = info->u.v2_i.dqi_free_entry; + if ((*err = read_blk(filp, blk, buf)) < 0) + goto out_buf; + } + else { + blk = get_free_dqblk(filp, info); + if ((int)blk < 0) { + *err = blk; + return 0; + } + memset(buf, 0, V2_DQBLKSIZE); + info->u.v2_i.dqi_free_entry = blk; /* This is enough as block is already zeroed and entry list is empty... */ + mark_info_dirty(info); + } + if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */ + if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk); + goto out_buf; + } + dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1); + memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); + /* Find free structure in block */ + for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++); +#ifdef __QUOTA_V2_PARANOIA + if (i == V2_DQSTRINBLK) { + printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n"); + *err = -EIO; + goto out_buf; + } +#endif + if ((*err = write_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk); + goto out_buf; + } + dquot->dq_off = (blk<dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + dqbuf_t buf; + int ret = 0, newson = 0, newact = 0; + u32 *ref; + uint newblk; + + if (!(buf = getdqbuf())) + return -ENOMEM; + if (!*treeblk) { + ret = get_free_dqblk(filp, info); + if (ret < 0) + goto out_buf; + *treeblk = ret; + memset(buf, 0, V2_DQBLKSIZE); + newact = 1; + } + else { + if ((ret = read_blk(filp, *treeblk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk); + goto out_buf; + } + } + ref = (u32 *)buf; + newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (!newblk) + newson = 1; + if (depth == V2_DQTREEDEPTH-1) { +#ifdef __QUOTA_V2_PARANOIA + if (newblk) { + printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]); + ret = -EIO; + goto out_buf; + } +#endif + newblk = find_free_dqentry(dquot, &ret); + } + else + ret = do_insert_tree(dquot, &newblk, depth+1); + if (newson && ret >= 0) { + ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk); + ret = write_blk(filp, *treeblk, buf); + } + else if (newact && ret < 0) + put_free_dqblk(filp, info, buf, *treeblk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Wrapper for inserting quota structure into tree */ +static inline int dq_insert_tree(struct dquot *dquot) +{ + int tmp = V2_DQTREEOFF; + return do_insert_tree(dquot, &tmp, 0); +} + +/* + * We don't have to be afraid of deadlocks as we never have quotas on quota files... + */ +static int v2_write_dquot(struct dquot *dquot) +{ + int type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + ssize_t ret; + struct v2_disk_dqblk ddquot; + + if (!dquot->dq_off) + if ((ret = dq_insert_tree(dquot)) < 0) { + printk(KERN_ERR "VFS: Error %d occured while creating quota.\n", ret); + return ret; + } + filp = sb_dqopt(dquot->dq_sb)->files[type]; + offset = dquot->dq_off; + mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset); + set_fs(fs); + if (ret != sizeof(struct v2_disk_dqblk)) { + printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", kdevname(dquot->dq_dev)); + if (ret >= 0) + ret = -ENOSPC; + } + else + ret = 0; + dqstats.writes++; + return ret; +} + +/* Free dquot entry in data block */ +static int free_dqentry(struct dquot *dquot, uint blk) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + struct v2_disk_dqdbheader *dh; + dqbuf_t buf = getdqbuf(); + int ret = 0; + + if (!buf) + return -ENOMEM; + if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) { + printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS)); + goto out_buf; + } + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); + goto out_buf; + } + dh = (struct v2_disk_dqdbheader *)buf; + dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1); + if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ + if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 || + (ret = put_free_dqblk(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk); + goto out_buf; + } + } + else { + memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk)); + if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) { + /* Insert will write block itself */ + if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk); + goto out_buf; + } + } + else + if ((ret = write_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk); + goto out_buf; + } + } + dquot->dq_off = 0; /* Quota is now unattached */ +out_buf: + freedqbuf(buf); + return ret; +} + +/* Remove reference to dquot from tree */ +static int remove_tree(struct dquot *dquot, uint *blk, int depth) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + dqbuf_t buf = getdqbuf(); + int ret = 0; + uint newblk; + u32 *ref = (u32 *)buf; + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, *blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); + goto out_buf; + } + newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (depth == V2_DQTREEDEPTH-1) { + ret = free_dqentry(dquot, newblk); + newblk = 0; + } + else + ret = remove_tree(dquot, &newblk, depth+1); + if (ret >= 0 && !newblk) { + int i; + ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0); + for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */ + if (i == V2_DQBLKSIZE) { + put_free_dqblk(filp, info, buf, *blk); + *blk = 0; + } + else + if ((ret = write_blk(filp, *blk, buf)) < 0) + printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk); + } +out_buf: + freedqbuf(buf); + return ret; +} + +/* Delete dquot from tree */ +static int v2_delete_dquot(struct dquot *dquot) +{ + uint tmp = V2_DQTREEOFF; + + if (!dquot->dq_off) /* Even not allocated? */ + return 0; + return remove_tree(dquot, &tmp, 0); +} + +/* Find entry in block */ +static loff_t find_block_dqentry(struct dquot *dquot, uint blk) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + int i; + struct v2_disk_dqblk *ddquot = GETENTRIES(buf); + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); + goto out_buf; + } + if (dquot->dq_id) + for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++); + else { /* ID 0 as a bit more complicated searching... */ + struct v2_disk_dqblk fakedquot; + + memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); + for (i = 0; i < V2_DQSTRINBLK; i++) + if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk))) + break; + } + if (i == V2_DQSTRINBLK) { + printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id); + ret = -EIO; + goto out_buf; + } + else + ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree */ +static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + u32 *ref = (u32 *)buf; + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); + goto out_buf; + } + ret = 0; + blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (!blk) /* No reference? */ + goto out_buf; + if (depth < V2_DQTREEDEPTH-1) + ret = find_tree_dqentry(dquot, blk, depth+1); + else + ret = find_block_dqentry(dquot, blk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree - wrapper function */ +static inline loff_t find_dqentry(struct dquot *dquot) +{ + return find_tree_dqentry(dquot, V2_DQTREEOFF, 0); +} + +static int v2_read_dquot(struct dquot *dquot) +{ + int type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + struct v2_disk_dqblk ddquot; + int ret = 0; + + filp = sb_dqopt(dquot->dq_sb)->files[type]; + +#ifdef __QUOTA_V2_PARANOIA + if (!filp || !dquot->dq_sb) { /* Invalidated quota? */ + printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); + return -EIO; + } +#endif + offset = find_dqentry(dquot); + if (offset <= 0) { /* Entry not present? */ + if (offset < 0) + printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id); + dquot->dq_off = 0; + dquot->dq_flags |= DQ_FAKE; + memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); + ret = offset; + } + else { + dquot->dq_off = offset; + fs = get_fs(); + set_fs(KERNEL_DS); + if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) { + if (ret >= 0) + ret = -EIO; + printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id); + memset(&ddquot, 0, sizeof(struct v2_disk_dqblk)); + } + else + ret = 0; + set_fs(fs); + disk2memdqb(&dquot->dq_dqb, &ddquot); + } + dqstats.reads++; + return ret; +} + +/* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */ +static int v2_commit_dquot(struct dquot *dquot) +{ + /* We clear the flag everytime so we don't loop when there was an IO error... */ + dquot->dq_flags &= ~DQ_MOD; + if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) + return v2_delete_dquot(dquot); + else + return v2_write_dquot(dquot); +} + +static struct quota_format_ops v2_format_ops = { + check_quota_file: v2_check_quota_file, + read_file_info: v2_read_file_info, + write_file_info: v2_write_file_info, + free_file_info: NULL, + read_dqblk: v2_read_dquot, + commit_dqblk: v2_commit_dquot, +}; + +static struct quota_format_type v2_quota_format = { + qf_fmt_id: QFMT_VFS_V0, + qf_ops: &v2_format_ops, + qf_owner: THIS_MODULE +}; + +static int __init init_v2_quota_format(void) +{ + return register_quota_format(&v2_quota_format); +} + +static void __exit exit_v2_quota_format(void) +{ + unregister_quota_format(&v2_quota_format); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_v2_quota_format); +module_exit(exit_v2_quota_format); diff -Nur linux-2.4.19/fs/read_write.c linux-2.4.19-sgi211r3/fs/read_write.c --- linux-2.4.19/fs/read_write.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/read_write.c Mon Oct 28 20:43:23 2002 @@ -43,7 +43,37 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) { long long retval; + struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + down(&inode->i_sem); + + switch (origin) { + case 2: + offset += inode->i_size; + break; + case 1: + offset += file->f_pos; + } + retval = -EINVAL; + if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) { + if (offset>=0 && offset<=inode->i_sb->s_maxbytes) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + retval = offset; + } + + up(&inode->i_sem); + + return retval; +} + +loff_t remote_llseek(struct file *file, loff_t offset, int origin) +{ + long long retval; + + lock_kernel(); switch (origin) { case 2: offset += file->f_dentry->d_inode->i_size; @@ -60,6 +90,7 @@ } retval = offset; } + unlock_kernel(); return retval; } @@ -72,6 +103,7 @@ { long long retval; + lock_kernel(); switch (origin) { case 2: offset += file->f_dentry->d_inode->i_size; @@ -88,21 +120,18 @@ } retval = offset; } + unlock_kernel(); return retval; } static inline loff_t llseek(struct file *file, loff_t offset, int origin) { loff_t (*fn)(struct file *, loff_t, int); - loff_t retval; fn = default_llseek; if (file->f_op && file->f_op->llseek) fn = file->f_op->llseek; - lock_kernel(); - retval = fn(file, offset, origin); - unlock_kernel(); - return retval; + return fn(file, offset, origin); } asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) @@ -173,8 +202,13 @@ if (!ret) { ssize_t (*read)(struct file *, char *, size_t, loff_t *); ret = -EINVAL; - if (file->f_op && (read = file->f_op->read) != NULL) + if (file->f_op && (read = file->f_op->read) != NULL) { ret = read(file, buf, count, &file->f_pos); + if (ret > 0) { + current->rchar += ret; + } + current->syscr++; + } } } if (ret > 0) @@ -199,8 +233,13 @@ if (!ret) { ssize_t (*write)(struct file *, const char *, size_t, loff_t *); ret = -EINVAL; - if (file->f_op && (write = file->f_op->write) != NULL) + if (file->f_op && (write = file->f_op->write) != NULL) { ret = write(file, buf, count, &file->f_pos); + if (ret > 0) { + current->wchar += ret; + } + current->syscw++; + } } } if (ret > 0) @@ -334,6 +373,10 @@ (file->f_op->readv || file->f_op->read)) ret = do_readv_writev(VERIFY_WRITE, file, vector, count); fput(file); + if (ret > 0) { + current->rchar += ret; + } + current->syscr++; bad_file: return ret; @@ -354,6 +397,10 @@ (file->f_op->writev || file->f_op->write)) ret = do_readv_writev(VERIFY_READ, file, vector, count); fput(file); + if (ret > 0) { + current->wchar += ret; + } + current->syscw++; bad_file: return ret; @@ -386,8 +433,11 @@ if (pos < 0) goto out; ret = read(file, buf, count, &pos); - if (ret > 0) + if (ret > 0) { dnotify_parent(file->f_dentry, DN_ACCESS); + current->rchar += ret; + } + current->syscr++; out: fput(file); bad_file: @@ -418,8 +468,11 @@ goto out; ret = write(file, buf, count, &pos); - if (ret > 0) + if (ret > 0) { dnotify_parent(file->f_dentry, DN_MODIFY); + current->wchar += ret; + } + current->syscw++; out: fput(file); bad_file: diff -Nur linux-2.4.19/fs/readdir.c linux-2.4.19-sgi211r3/fs/readdir.c --- linux-2.4.19/fs/readdir.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/readdir.c Tue Dec 3 16:31:18 2002 @@ -114,10 +114,7 @@ i++; /* fallthrough */ case 1: - spin_lock(&dcache_lock); - ino = dentry->d_parent->d_inode->i_ino; - spin_unlock(&dcache_lock); - if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) + if (filldir(dirent, "..", 2, i, parent_ino(dentry), DT_DIR) < 0) break; filp->f_pos++; i++; diff -Nur linux-2.4.19/fs/reiserfs/buffer2.c linux-2.4.19-sgi211r3/fs/reiserfs/buffer2.c --- linux-2.4.19/fs/reiserfs/buffer2.c Fri Dec 21 09:42:03 2001 +++ linux-2.4.19-sgi211r3/fs/reiserfs/buffer2.c Mon Oct 28 20:43:23 2002 @@ -33,8 +33,7 @@ buffer_journal_dirty(bh) ? ' ' : '!'); } run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } if (repeat_counter > 30000000) { reiserfs_warning("vs-3051: done waiting, ignore vs-3050 messages for (%b)\n", bh) ; @@ -52,11 +51,11 @@ struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, int n_size) { struct buffer_head *result; - PROC_EXP( unsigned int ctx_switches = kstat.context_swtch ); + PROC_EXP( unsigned int ctx_switches = nr_context_switches(); ); result = bread (super -> s_dev, n_block, n_size); PROC_INFO_INC( super, breads ); - PROC_EXP( if( kstat.context_swtch != ctx_switches ) + PROC_EXP( if( nr_context_switches() != ctx_switches ) PROC_INFO_INC( super, bread_miss ) ); return result; } diff -Nur linux-2.4.19/fs/reiserfs/file.c linux-2.4.19-sgi211r3/fs/reiserfs/file.c --- linux-2.4.19/fs/reiserfs/file.c Mon Feb 25 11:38:09 2002 +++ linux-2.4.19-sgi211r3/fs/reiserfs/file.c Mon Oct 28 20:43:23 2002 @@ -93,13 +93,16 @@ static int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode ; int error ; + lock_kernel(); if (attr->ia_valid & ATTR_SIZE) { /* version 2 items will be caught by the s_maxbytes check ** done for us in vmtruncate */ if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 && - attr->ia_size > MAX_NON_LFS) - return -EFBIG ; + attr->ia_size > MAX_NON_LFS) { + error = -EFBIG ; + goto out; + } /* fill in hole pointers in the expanding truncate case. */ if (attr->ia_size > inode->i_size) { @@ -118,14 +121,18 @@ if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) || ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) && - (get_inode_sd_version (inode) == STAT_DATA_V1)) + (get_inode_sd_version (inode) == STAT_DATA_V1)) { /* stat data of format v3.5 has 16 bit uid and gid */ - return -EINVAL; + error = -EINVAL; + goto out; + } error = inode_change_ok(inode, attr) ; if (!error) inode_setattr(inode, attr) ; +out: + unlock_kernel(); return error ; } diff -Nur linux-2.4.19/fs/reiserfs/inode.c linux-2.4.19-sgi211r3/fs/reiserfs/inode.c --- linux-2.4.19/fs/reiserfs/inode.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/reiserfs/inode.c Mon Oct 28 20:43:23 2002 @@ -1356,6 +1356,7 @@ if (maxlen < 5 || ! need_parent) return 3 ; + read_lock(&dparent_lock); inode = dentry->d_parent->d_inode ; data[3] = inode->i_ino ; data[4] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; @@ -1364,6 +1365,7 @@ return 5 ; data[5] = inode->i_generation ; *lenp = 6 ; + read_unlock(&dparent_lock); return 6 ; } diff -Nur linux-2.4.19/fs/reiserfs/journal.c linux-2.4.19-sgi211r3/fs/reiserfs/journal.c --- linux-2.4.19/fs/reiserfs/journal.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/reiserfs/journal.c Mon Oct 28 20:43:23 2002 @@ -151,8 +151,7 @@ } bn = allocate_bitmap_node(p_s_sb) ; if (!bn) { - current->policy |= SCHED_YIELD ; - schedule() ; + yield(); goto repeat ; } return bn ; diff -Nur linux-2.4.19/fs/seq_file.c linux-2.4.19-sgi211r3/fs/seq_file.c --- linux-2.4.19/fs/seq_file.c Sat Nov 17 18:16:22 2001 +++ linux-2.4.19-sgi211r3/fs/seq_file.c Mon Feb 3 17:14:24 2003 @@ -94,8 +94,10 @@ m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); if (!m->buf) goto Enomem; + m->count = 0; } m->op->stop(m, p); + m->count = 0; goto Done; Fill: /* they want more? let's try to get some more */ diff -Nur linux-2.4.19/fs/smbfs/dir.c linux-2.4.19-sgi211r3/fs/smbfs/dir.c --- linux-2.4.19/fs/smbfs/dir.c Tue Oct 2 17:03:34 2001 +++ linux-2.4.19-sgi211r3/fs/smbfs/dir.c Mon Oct 28 20:43:23 2002 @@ -83,7 +83,7 @@ /* fallthrough */ case 1: if (filldir(dirent, "..", 2, 1, - dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) + parent_ino(dentry), DT_DIR) < 0) goto out; filp->f_pos = 2; } @@ -379,12 +379,14 @@ void smb_renew_times(struct dentry * dentry) { + read_lock(&dparent_lock); for (;;) { dentry->d_time = jiffies; if (IS_ROOT(dentry)) break; dentry = dentry->d_parent; } + read_unlock(&dparent_lock); } static struct dentry * diff -Nur linux-2.4.19/fs/smbfs/file.c linux-2.4.19-sgi211r3/fs/smbfs/file.c --- linux-2.4.19/fs/smbfs/file.c Mon Feb 25 11:38:09 2002 +++ linux-2.4.19-sgi211r3/fs/smbfs/file.c Mon Oct 28 20:43:23 2002 @@ -381,7 +381,7 @@ struct file_operations smb_file_operations = { - llseek: generic_file_llseek, + llseek: remote_llseek, read: smb_file_read, write: smb_file_write, ioctl: smb_ioctl, diff -Nur linux-2.4.19/fs/smbfs/inode.c linux-2.4.19-sgi211r3/fs/smbfs/inode.c --- linux-2.4.19/fs/smbfs/inode.c Mon Feb 25 11:38:09 2002 +++ linux-2.4.19-sgi211r3/fs/smbfs/inode.c Mon Oct 28 20:43:23 2002 @@ -551,6 +551,8 @@ int error, changed, refresh = 0; struct smb_fattr fattr; + lock_kernel(); + error = smb_revalidate_inode(dentry); if (error) goto out; @@ -645,6 +647,7 @@ out: if (refresh) smb_refresh_inode(dentry); + unlock_kernel(); return error; } diff -Nur linux-2.4.19/fs/smbfs/proc.c linux-2.4.19-sgi211r3/fs/smbfs/proc.c --- linux-2.4.19/fs/smbfs/proc.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/smbfs/proc.c Mon Oct 28 20:43:23 2002 @@ -267,15 +267,20 @@ * Build the path string walking the tree backward from end to ROOT * and store it in reversed order [see reverse_string()] */ + read_lock(&dparent_lock); while (!IS_ROOT(entry)) { - if (maxlen < 3) + if (maxlen < 3) { + read_unlock(&dparent_lock); return -ENAMETOOLONG; + } len = server->convert(path, maxlen-2, entry->d_name.name, entry->d_name.len, server->local_nls, server->remote_nls); - if (len < 0) + if (len < 0) { + read_unlock(&dparent_lock); return len; + } reverse_string(path, len); path += len; *path++ = '\\'; @@ -285,6 +290,7 @@ if (IS_ROOT(entry)) break; } + read_unlock(&dparent_lock); reverse_string(buf, path-buf); /* maxlen is at least 1 */ diff -Nur linux-2.4.19/fs/super.c linux-2.4.19-sgi211r3/fs/super.c --- linux-2.4.19/fs/super.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/super.c Wed Oct 16 14:02:58 2002 @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -262,6 +263,7 @@ */ static struct super_block *alloc_super(void) { + static struct super_operations empty_sops = {}; struct super_block *s = kmalloc(sizeof(struct super_block), GFP_USER); if (s) { memset(s, 0, sizeof(struct super_block)); @@ -279,6 +281,9 @@ sema_init(&s->s_dquot.dqio_sem, 1); sema_init(&s->s_dquot.dqoff_sem, 1); s->s_maxbytes = MAX_NON_LFS; + s->s_op = &empty_sops; + s->dq_op = sb_dquot_ops; + s->s_qcop = sb_quotactl_ops; } return s; } diff -Nur linux-2.4.19/fs/udf/dir.c linux-2.4.19-sgi211r3/fs/udf/dir.c --- linux-2.4.19/fs/udf/dir.c Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/fs/udf/dir.c Tue Oct 29 10:56:27 2002 @@ -221,7 +221,9 @@ if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT ) { + read_lock(&dparent_lock); iblock = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(filp->f_dentry->d_parent->d_inode), 0); + read_unlock(&dparent_lock); flen = 2; memcpy(fname, "..", flen); dt_type = DT_DIR; diff -Nur linux-2.4.19/fs/ufs/truncate.c linux-2.4.19-sgi211r3/fs/ufs/truncate.c --- linux-2.4.19/fs/ufs/truncate.c Mon Feb 25 11:38:09 2002 +++ linux-2.4.19-sgi211r3/fs/ufs/truncate.c Mon Oct 28 20:43:23 2002 @@ -448,10 +448,7 @@ if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) ufs_sync_inode (inode); run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule (); - - + yield(); } offset = inode->i_size & uspi->s_fshift; if (offset) { diff -Nur linux-2.4.19/fs/umsdos/inode.c linux-2.4.19-sgi211r3/fs/umsdos/inode.c --- linux-2.4.19/fs/umsdos/inode.c Sun Sep 30 12:26:08 2001 +++ linux-2.4.19-sgi211r3/fs/umsdos/inode.c Mon Oct 28 20:43:23 2002 @@ -19,7 +19,7 @@ #include #include #include - +#include extern struct dentry_operations umsdos_dentry_operations; struct dentry *saved_root; /* Original root if changed */ @@ -164,6 +164,8 @@ struct dentry *temp, *old_dentry = NULL; int ret; + lock_kernel(); + ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); if (ret) @@ -207,14 +209,13 @@ if (ret) goto out; - down(&dir->i_sem); ret = umsdos_notify_change_locked(dentry, attr); - up(&dir->i_sem); if (ret == 0) ret = inode_setattr (inode, attr); out: if (old_dentry) dput (dentry); /* if we had to use fake dentry for hardlinks, dput() it now */ + unlock_kernel(); return ret; } diff -Nur linux-2.4.19/fs/xattr.c linux-2.4.19-sgi211r3/fs/xattr.c --- linux-2.4.19/fs/xattr.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xattr.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,355 @@ +/* + File: fs/xattr.c + + Extended attribute handling. + + Copyright (C) 2001 by Andreas Gruenbacher + Copyright (C) 2001 SGI - Silicon Graphics, Inc + */ +#include +#include +#include +#include +#include +#include +#include + +/* + * Extended attribute memory allocation wrappers, originally + * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros. + * The vmalloc use here is very uncommon - extended attributes + * are supposed to be small chunks of metadata, and it is quite + * unusual to have very many extended attributes, so lists tend + * to be quite short as well. The 64K upper limit is derived + * from the extended attribute size limit used by XFS. + * Intentionally allow zero @size for value/list size requests. + */ +static void * +xattr_alloc(size_t size, size_t limit) +{ + void *ptr; + + if (size > limit) + return ERR_PTR(-E2BIG); + + if (!size) /* size request, no buffer is needed */ + return NULL; + else if (size <= PAGE_SIZE) + ptr = kmalloc((unsigned long) size, GFP_KERNEL); + else + ptr = vmalloc((unsigned long) size); + if (!ptr) + return ERR_PTR(-ENOMEM); + return ptr; +} + +static void +xattr_free(void *ptr, size_t size) +{ + if (!size) /* size request, no buffer was needed */ + return; + else if (size <= PAGE_SIZE) + kfree(ptr); + else + vfree(ptr); +} + +/* + * Extended attribute SET operations + */ +static long +setxattr(struct dentry *d, char *name, void *value, size_t size, int flags) +{ + int error; + void *kvalue; + char kname[XATTR_NAME_MAX + 1]; + + if (flags & ~(XATTR_CREATE|XATTR_REPLACE)) + return -EINVAL; + + error = strncpy_from_user(kname, name, sizeof(kname)); + if (error == 0 || error == sizeof(kname)) + error = -ERANGE; + if (error < 0) + return error; + + kvalue = xattr_alloc(size, XATTR_SIZE_MAX); + if (IS_ERR(kvalue)) + return PTR_ERR(kvalue); + + if (size > 0 && copy_from_user(kvalue, value, size)) { + xattr_free(kvalue, size); + return -EFAULT; + } + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + + xattr_free(kvalue, size); + return error; +} + +asmlinkage long +sys_setxattr(char *path, char *name, void *value, size_t size, int flags) +{ + struct nameidata nd; + int error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = setxattr(nd.dentry, name, value, size, flags); + path_release(&nd); + return error; +} + +asmlinkage long +sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags) +{ + struct nameidata nd; + int error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = setxattr(nd.dentry, name, value, size, flags); + path_release(&nd); + return error; +} + +asmlinkage long +sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags) +{ + struct file *f; + int error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = setxattr(f->f_dentry, name, value, size, flags); + fput(f); + return error; +} + +/* + * Extended attribute GET operations + */ +static ssize_t +getxattr(struct dentry *d, char *name, void *value, size_t size) +{ + ssize_t error; + void *kvalue; + char kname[XATTR_NAME_MAX + 1]; + + error = strncpy_from_user(kname, name, sizeof(kname)); + if (error == 0 || error == sizeof(kname)) + error = -ERANGE; + if (error < 0) + return error; + + kvalue = xattr_alloc(size, XATTR_SIZE_MAX); + if (IS_ERR(kvalue)) + return PTR_ERR(kvalue); + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + + if (kvalue && error > 0) + if (copy_to_user(value, kvalue, error)) + error = -EFAULT; + xattr_free(kvalue, size); + return error; +} + +asmlinkage ssize_t +sys_getxattr(char *path, char *name, void *value, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = getxattr(nd.dentry, name, value, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_lgetxattr(char *path, char *name, void *value, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = getxattr(nd.dentry, name, value, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_fgetxattr(int fd, char *name, void *value, size_t size) +{ + struct file *f; + ssize_t error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = getxattr(f->f_dentry, name, value, size); + fput(f); + return error; +} + +/* + * Extended attribute LIST operations + */ +static ssize_t +listxattr(struct dentry *d, char *list, size_t size) +{ + ssize_t error; + char *klist; + + klist = (char *)xattr_alloc(size, XATTR_LIST_MAX); + if (IS_ERR(klist)) + return PTR_ERR(klist); + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->listxattr(d, klist, size); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + + if (klist && error > 0) + if (copy_to_user(list, klist, error)) + error = -EFAULT; + xattr_free(klist, size); + return error; +} + +asmlinkage ssize_t +sys_listxattr(char *path, char *list, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = listxattr(nd.dentry, list, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_llistxattr(char *path, char *list, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = listxattr(nd.dentry, list, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_flistxattr(int fd, char *list, size_t size) +{ + struct file *f; + ssize_t error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = listxattr(f->f_dentry, list, size); + fput(f); + return error; +} + +/* + * Extended attribute REMOVE operations + */ +static long +removexattr(struct dentry *d, char *name) +{ + int error; + char kname[XATTR_NAME_MAX + 1]; + + error = strncpy_from_user(kname, name, sizeof(kname)); + if (error == 0 || error == sizeof(kname)) + error = -ERANGE; + if (error < 0) + return error; + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->removexattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->removexattr(d, kname); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + return error; +} + +asmlinkage long +sys_removexattr(char *path, char *name) +{ + struct nameidata nd; + int error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = removexattr(nd.dentry, name); + path_release(&nd); + return error; +} + +asmlinkage long +sys_lremovexattr(char *path, char *name) +{ + struct nameidata nd; + int error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = removexattr(nd.dentry, name); + path_release(&nd); + return error; +} + +asmlinkage long +sys_fremovexattr(int fd, char *name) +{ + struct file *f; + int error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = removexattr(f->f_dentry, name); + fput(f); + return error; +} diff -Nur linux-2.4.19/fs/xfs/Makefile linux-2.4.19-sgi211r3/fs/xfs/Makefile --- linux-2.4.19/fs/xfs/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/Makefile Wed Oct 16 14:02:58 2002 @@ -0,0 +1,155 @@ +# +# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# Makefile for XFS on Linux. +# + +# This needs -I. because everything does #include instead of "xfs.h". +# The code is wrong, local files should be included using "xfs.h", not +# but I am not going to change every file at the moment. +EXTRA_CFLAGS += -I. -funsigned-char + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -g -DSTATIC="" -DDEBUG -DXFSDEBUG +endif +ifeq ($(CONFIG_PAGEBUF_DEBUG),y) + EXTRA_CFLAGS += -DPAGEBUF_TRACE +endif + +subdir-$(CONFIG_XFS_FS) += pagebuf linux support + +ifeq ($(CONFIG_XFS_DMAPI),y) + subdir-$(CONFIG_XFS_FS) += dmapi +endif + +# fs/Makefile enters fs/xfs twice if CONFIG_XFS_FS is y, once for kernel and +# once for modules. This is necessary because xfsidbg can be built as a module +# even if xfs is in kernel. Alas the shorthand form +# O_TARGET := xfs.o +# obj-m := $(O_TARGET) +# fails when the makefile is run more than once, code gets compiled as both +# kernel and as module, which one gets linked depends on the phase of the moon. +# I just love these layer violations where a makefile behaves differently +# depending on changes to its parent. Work around by only setting obj-m when +# xfs is selected as a module. Keith Owens. + +O_TARGET := xfs.o +ifeq ($(CONFIG_XFS_FS),m) + obj-m := $(O_TARGET) +endif + +obj-$(CONFIG_XFS_DMAPI) += xfs_dmapi.o dmapi/dmapi_core.o + +obj-$(CONFIG_XFS_RT) += xfs_rtalloc.o + +obj-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \ + xfs_dquot_item.o \ + xfs_trans_dquot.o \ + xfs_qm_syscalls.o \ + xfs_qm.o + +obj-$(CONFIG_FS_POSIX_ACL) += xfs_acl.o +obj-$(CONFIG_FS_POSIX_CAP) += xfs_cap.o +obj-$(CONFIG_FS_POSIX_MAC) += xfs_mac.o + +obj-y += xfs_alloc.o \ + xfs_alloc_btree.o \ + xfs_attr.o \ + xfs_attr_fetch.o \ + xfs_attr_leaf.o \ + xfs_bit.o \ + xfs_bmap.o \ + xfs_bmap_btree.o \ + xfs_btree.o \ + xfs_buf_item.o \ + xfs_da_btree.o \ + xfs_dir.o \ + xfs_dir2.o \ + xfs_dir2_block.o \ + xfs_dir2_data.o \ + xfs_dir2_leaf.o \ + xfs_dir2_node.o \ + xfs_dir2_sf.o \ + xfs_dir2_trace.o \ + xfs_dir_leaf.o \ + xfs_error.o \ + xfs_extfree_item.o \ + xfs_fsops.o \ + xfs_ialloc.o \ + xfs_ialloc_btree.o \ + xfs_iget.o \ + xfs_inode.o \ + xfs_inode_item.o \ + xfs_iocore.o \ + xfs_itable.o \ + xfs_dfrag.o \ + xfs_log.o \ + xfs_log_recover.o \ + xfs_macros.o \ + xfs_mount.o \ + xfs_rename.o \ + xfs_trans.o \ + xfs_trans_ail.o \ + xfs_trans_buf.o \ + xfs_trans_extfree.o \ + xfs_trans_inode.o \ + xfs_trans_item.o \ + xfs_utils.o \ + xfs_vfsops.o \ + xfs_vnodeops.o \ + xfs_rw.o + +# Objects not built in this directory +obj-y += pagebuf/pagebuf.o \ + linux/linux_xfs.o \ + support/support_xfs.o + +# If both xfs and kdb modules are built in then xfsidbg is built in. If xfs is +# a module and kdb modules are being compiled then xfsidbg must be a module, to +# follow xfs. If xfs is built in then xfsidbg tracks the kdb module state. +# This must come after the main xfs code so xfs initialises before xfsidbg. +# KAO +ifneq ($(CONFIG_KDB_MODULES),) + ifeq ($(CONFIG_XFS_FS),y) + obj-$(CONFIG_KDB_MODULES) += xfsidbg.o + else + obj-$(CONFIG_XFS_FS) += xfsidbg.o + endif +endif + +CFLAGS_xfsidbg.o += -I $(TOPDIR)/arch/$(ARCH)/kdb + +include $(TOPDIR)/Rules.make + +# This is really nasty, but Rules.make was never designed for multi directory +# modules. Keith Owens. + +xfs.o: $(patsubst %,_modsubdir_%,$(subdir-m)) diff -Nur linux-2.4.19/fs/xfs/dmapi/Makefile linux-2.4.19-sgi211r3/fs/xfs/dmapi/Makefile --- linux-2.4.19/fs/xfs/dmapi/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/Makefile Wed Oct 16 14:02:58 2002 @@ -0,0 +1,59 @@ +# +# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +EXTRA_CFLAGS += -I $(TOPDIR)/fs/xfs + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -g -DDEBUG -DXFSDEBUG +endif + +O_TARGET := dmapi_core.o +ifneq ($(MAKECMDGOALS),modules_install) + obj-m := $(O_TARGET) +endif + +obj-y += dmapi_sysent.o \ + dmapi_attr.o \ + dmapi_config.o \ + dmapi_bulkattr.o \ + dmapi_dmattr.o \ + dmapi_event.o \ + dmapi_handle.o \ + dmapi_hole.o \ + dmapi_io.o \ + dmapi_mountinfo.o \ + dmapi_region.o \ + dmapi_register.o \ + dmapi_right.o \ + dmapi_session.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/fs/xfs/dmapi/Status linux-2.4.19-sgi211r3/fs/xfs/dmapi/Status --- linux-2.4.19/fs/xfs/dmapi/Status Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/Status Wed Oct 16 14:02:58 2002 @@ -0,0 +1,126 @@ +for linux: + + +68 external interfaces in libdm + + 56 of those interfaces go through to dmi(), the kernel side of DMAPI + + + +Functions known to work +---------------------------------------------- + +dm_create_session +dm_create_userevent +dm_destroy_session +dm_getall_sessions +dm_getall_tokens +dm_get_allocinfo +dm_get_bulkattr +dm_get_config_events +dm_get_dmattr +dm_get_eventlist +dm_get_events +dm_get_fileattr +dm_get_region +dm_handle_free +dm_init_attrloc +dm_init_service +dm_obj_ref_hold +dm_obj_ref_query +dm_obj_ref_rele +dm_path_to_fshandle +dm_path_to_handle +dm_punch_hole +dm_query_session +dm_read_invis +dm_remove_dmattr +dm_respond_event +dm_send_msg +dm_set_disp +dm_set_dmattr +dm_set_eventlist +dm_set_fileattr +dm_set_region +dm_sync_by_handle +dm_write_invis +34 + +Functions that seem to work (would like more rigorous test case) +------------------------------------------ + +dm_pending +dm_probe_hole - one test case of test_hole.c fails +dm_request_right +3 + +Functions untested but probably work +---------------------------------------------- + +dm_find_eventmsg +dm_handle_cmp +dm_handle_to_fshandle +dm_handle_to_ino +dm_release_right +5 + +Functions that do not work +----------------------------------------- + +dm_get_dioinfo - directio not implemented +1 + +Functions not supported in SGI DMAPI +------------------------------------------------------------- + +dm_clear_inherit +dm_create_by_handle +dm_getall_inherit +dm_get_bulkall +dm_mkdir_by_handle +dm_set_inherit +dm_symlink_by_handle + + + + +Functions that seem to work (would like more rigorous test case) +---------------------------------------------------------------- + +dm_get_config +dm_downgrade_right +dm_get_mountinfo +dm_set_return_on_destory +dm_upgrade_right + + + +Functions that do not work +----------------------------------------------------------------- + +dm_fd_to_handle - Irix getf not implemented on linux +dm_get_dirattrs - null pointer reference +dm_handle_to_path +dm_getall_dmattr - needs a copy_from_user in place of useracc + + +Functions that are untested, but probably work +----------------------------------------------------------------- + +dm_getall_disp +dm_handle_hash +dm_handle_is_valid +dm_handle_to_fsid +dm_handle_to_igen +dm_make_fshandle +dm_make_handle +dm_move_event +dm_query_right + + + +Other things not working +---------------------------------- + +- read/write events for memory-mapped I/O? + diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi.h linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi.h --- linux-2.4.19/fs/xfs/dmapi/dmapi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1043 @@ +/* + * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + * USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _SYS_DMAPI_H +#define _SYS_DMAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __KERNEL__ +#include +#endif +#include + +/************************************************************************** + * * + * The SGI implementation of DMAPI is based upon the X/Open document * + * Systems Management: Data Storage Managment (XDSM) API * + * dated February 1997. Not all DMAPI functions and structure fields * + * have been implemented. Most importantly, the DMAPI functions * + * dm_request_right, dm_release_right, dm_query_right, dm_upgrade_right * + * and dm_downgrade_right do not work as described in the specification. * + * * + * The XFS filesystem currently does not allow its locking mechanisms to * + * be externally accessed from user space. While the above-mentioned * + * dm_xxx_right functions exist and can be called by applications, they * + * always return successfully without actually obtaining any locks * + * within the filesystem. * + * * + * Applications which do not need full rights support and which only * + * make dm_xxx_right calls in order to satisfy the input requirements of * + * other DMAPI calls should be able to use these routines to avoid * + * having to implement special-case code for SGI platforms. Applications * + * which truely need the capabilities of a full implementation of rights * + * will unfortunately have to come up with alternate software solutions * + * until such time as rights can be completely implemented. * + * * + * Functions and structure fields defined within this file which are not * + * supported in the SGI implementation of DMAPI are indicated by comments * + * following their definitions such as "not supported", or "not * + * completely supported". Any function or field not so marked may be * + * assumed to work exactly according to the spec. * + * * + **************************************************************************/ + + + +/* The first portion of this file contains defines and typedefs that are + DMAPI implementation-dependent, and could be different on other platforms. +*/ + +typedef __s64 dm_attrloc_t; +typedef unsigned int dm_boolean_t; +typedef __u64 dm_eventset_t; +typedef __u64 dm_fsid_t; +typedef __u64 dm_ino_t; +typedef __u32 dm_igen_t; +typedef __s64 dm_off_t; +typedef unsigned int dm_sequence_t; +typedef int dm_sessid_t; +typedef __u64 dm_size_t; +typedef __s64 dm_ssize_t; +typedef int dm_token_t; + +/* XXX dev_t, mode_t, and nlink_t are not the same size in kernel space + and user space. This affects the field offsets for dm_stat_t. + The following solution is temporary. + + user space sizes: dev_t=8 mode_t=4 nlink_t=4 + kernel space : dev_t=2 mode_t=2 nlink_t=2 + +*/ +typedef __s64 dm_dev_t; +typedef int dm_mode_t; +typedef int dm_nlink_t; + + +#define DM_REGION_NOEVENT 0x0 +#define DM_REGION_READ 0x1 +#define DM_REGION_WRITE 0x2 +#define DM_REGION_TRUNCATE 0x4 + +/* Values for the mask argument used with dm_get_fileattr, dm_get_bulkattr, + dm_get_dirattrs, and dm_set_fileattr. +*/ + +#define DM_AT_MODE 0x0001 +#define DM_AT_UID 0x0002 +#define DM_AT_GID 0x0004 +#define DM_AT_ATIME 0x0008 +#define DM_AT_MTIME 0x0010 +#define DM_AT_CTIME 0x0020 +#define DM_AT_SIZE 0x0040 +#define DM_AT_DTIME 0x0080 +#define DM_AT_HANDLE 0x0100 +#define DM_AT_EMASK 0x0200 +#define DM_AT_PMANR 0x0400 +#define DM_AT_PATTR 0x0800 +#define DM_AT_STAT 0x1000 +#define DM_AT_CFLAG 0x2000 + +#define DM_EV_WAIT 0x1 /* used in dm_get_events() */ + +#define DM_MOUNT_RDONLY 0x1 /* me_mode field in dm_mount_event_t */ + +#define DM_RR_WAIT 0x1 + +#define DM_UNMOUNT_FORCE 0x1 /* ne_mode field in dm_namesp_event_t */ + +#define DM_WRITE_SYNC 0x1 /* used in dm_write_invis() */ + +#define DM_SESSION_INFO_LEN 256 +#define DM_NO_SESSION 0 +#define DM_TRUE 1 +#define DM_FALSE 0 +#define DM_INVALID_TOKEN 0 +#define DM_NO_TOKEN (-1) +#define DM_INVALID_HANP NULL +#define DM_INVALID_HLEN 0 +#define DM_GLOBAL_HANP ((void *)(1LL)) +#define DM_GLOBAL_HLEN ((size_t)(1)) +#define DM_VER_STR_CONTENTS "SGI DMAPI (XDSM) API, Release 1.0." + + +#define DMEV_SET(event_type, event_list) \ + ((event_list) |= (1 << (event_type))) +#define DMEV_CLR(event_type, event_list) \ + ((event_list) &= ~(1 << (event_type))) +#define DMEV_ISSET(event_type, event_list) \ + (int)(((event_list) & (1 << (event_type))) != 0) +#define DMEV_ZERO(event_list) \ + (event_list) = 0 + + +typedef struct { + int vd_offset; /* offset from start of containing struct */ + unsigned int vd_length; /* length of data starting at vd_offset */ +} dm_vardata_t; + +#define DM_GET_VALUE(p, field, type) \ + ((type) ((char *)(p) + (p)->field.vd_offset)) + +#define DM_GET_LEN(p, field) \ + ((p)->field.vd_length) + +#define DM_STEP_TO_NEXT(p, type) \ + ((type) ((p)->_link ? (char *)(p) + (p)->_link : NULL)) + + + + +/* The remainder of this include file contains defines, typedefs, and + structures which are strictly defined by the DMAPI 2.3 specification. + + (The _link field which appears in several structures is an + implementation-specific way to implement DM_STEP_TO_NEXT, and + should not be referenced directly by application code.) +*/ + + +#define DM_ATTR_NAME_SIZE 8 + + +struct dm_attrname { + unsigned char an_chars[DM_ATTR_NAME_SIZE]; +}; +typedef struct dm_attrname dm_attrname_t; + + +struct dm_attrlist { + int _link; + dm_attrname_t al_name; + dm_vardata_t al_data; +}; +typedef struct dm_attrlist dm_attrlist_t; + + +typedef enum { + DM_CONFIG_INVALID, + DM_CONFIG_BULKALL, + DM_CONFIG_CREATE_BY_HANDLE, + DM_CONFIG_DTIME_OVERLOAD, + DM_CONFIG_LEGACY, + DM_CONFIG_LOCK_UPGRADE, + DM_CONFIG_MAX_ATTR_ON_DESTROY, + DM_CONFIG_MAX_ATTRIBUTE_SIZE, + DM_CONFIG_MAX_HANDLE_SIZE, + DM_CONFIG_MAX_MANAGED_REGIONS, + DM_CONFIG_MAX_MESSAGE_DATA, + DM_CONFIG_OBJ_REF, + DM_CONFIG_PENDING, + DM_CONFIG_PERS_ATTRIBUTES, + DM_CONFIG_PERS_EVENTS, + DM_CONFIG_PERS_INHERIT_ATTRIBS, + DM_CONFIG_PERS_MANAGED_REGIONS, + DM_CONFIG_PUNCH_HOLE, + DM_CONFIG_TOTAL_ATTRIBUTE_SPACE, + DM_CONFIG_WILL_RETRY +} dm_config_t; + + +struct dm_dioinfo { /* non-standard SGI addition */ + unsigned int d_mem; + unsigned int d_miniosz; + unsigned int d_maxiosz; + dm_boolean_t d_dio_only; +}; +typedef struct dm_dioinfo dm_dioinfo_t; + + +struct dm_dispinfo { + int _link; + unsigned int di_pad1; /* reserved; do not reference */ + dm_vardata_t di_fshandle; + dm_eventset_t di_eventset; +}; +typedef struct dm_dispinfo dm_dispinfo_t; + + +typedef enum { + DM_EVENT_INVALID = -1, + DM_EVENT_CANCEL = 0, /* not supported */ + DM_EVENT_MOUNT = 1, + DM_EVENT_PREUNMOUNT = 2, + DM_EVENT_UNMOUNT = 3, + DM_EVENT_DEBUT = 4, /* not supported */ + DM_EVENT_CREATE = 5, + DM_EVENT_CLOSE = 6, /* not supported */ + DM_EVENT_POSTCREATE = 7, + DM_EVENT_REMOVE = 8, + DM_EVENT_POSTREMOVE = 9, + DM_EVENT_RENAME = 10, + DM_EVENT_POSTRENAME = 11, + DM_EVENT_LINK = 12, + DM_EVENT_POSTLINK = 13, + DM_EVENT_SYMLINK = 14, + DM_EVENT_POSTSYMLINK = 15, + DM_EVENT_READ = 16, + DM_EVENT_WRITE = 17, + DM_EVENT_TRUNCATE = 18, + DM_EVENT_ATTRIBUTE = 19, + DM_EVENT_DESTROY = 20, + DM_EVENT_NOSPACE = 21, + DM_EVENT_USER = 22, + DM_EVENT_MAX = 23 +} dm_eventtype_t; + + +struct dm_eventmsg { + int _link; + dm_eventtype_t ev_type; + dm_token_t ev_token; + dm_sequence_t ev_sequence; + dm_vardata_t ev_data; +}; +typedef struct dm_eventmsg dm_eventmsg_t; + + +struct dm_cancel_event { /* not supported */ + dm_sequence_t ce_sequence; + dm_token_t ce_token; +}; +typedef struct dm_cancel_event dm_cancel_event_t; + + +struct dm_data_event { + dm_vardata_t de_handle; + dm_off_t de_offset; + dm_size_t de_length; +}; +typedef struct dm_data_event dm_data_event_t; + +struct dm_destroy_event { + dm_vardata_t ds_handle; + dm_attrname_t ds_attrname; + dm_vardata_t ds_attrcopy; +}; +typedef struct dm_destroy_event dm_destroy_event_t; + +struct dm_mount_event { + dm_mode_t me_mode; + dm_vardata_t me_handle1; + dm_vardata_t me_handle2; + dm_vardata_t me_name1; + dm_vardata_t me_name2; + dm_vardata_t me_roothandle; +}; +typedef struct dm_mount_event dm_mount_event_t; + +struct dm_namesp_event { + dm_mode_t ne_mode; + dm_vardata_t ne_handle1; + dm_vardata_t ne_handle2; + dm_vardata_t ne_name1; + dm_vardata_t ne_name2; + int ne_retcode; +}; +typedef struct dm_namesp_event dm_namesp_event_t; + + +typedef enum { + DM_EXTENT_INVALID, + DM_EXTENT_RES, + DM_EXTENT_HOLE +} dm_extenttype_t; + + +struct dm_extent { + dm_extenttype_t ex_type; + unsigned int ex_pad1; /* reserved; do not reference */ + dm_off_t ex_offset; + dm_size_t ex_length; +}; +typedef struct dm_extent dm_extent_t; + +struct dm_fileattr { + dm_mode_t fa_mode; + uid_t fa_uid; + gid_t fa_gid; + time_t fa_atime; + time_t fa_mtime; + time_t fa_ctime; + time_t fa_dtime; + unsigned int fa_pad1; /* reserved; do not reference */ + dm_off_t fa_size; +}; +typedef struct dm_fileattr dm_fileattr_t; + + +struct dm_inherit { /* not supported */ + dm_attrname_t ih_name; + dm_mode_t ih_filetype; +}; +typedef struct dm_inherit dm_inherit_t; + + +typedef enum { + DM_MSGTYPE_INVALID, + DM_MSGTYPE_SYNC, + DM_MSGTYPE_ASYNC +} dm_msgtype_t; + + +struct dm_region { + dm_off_t rg_offset; + dm_size_t rg_size; + unsigned int rg_flags; + unsigned int rg_pad1; /* reserved; do not reference */ +}; +typedef struct dm_region dm_region_t; + + +typedef enum { + DM_RESP_INVALID, + DM_RESP_CONTINUE, + DM_RESP_ABORT, + DM_RESP_DONTCARE +} dm_response_t; + + +typedef enum { + DM_RIGHT_NULL, + DM_RIGHT_SHARED, + DM_RIGHT_EXCL +} dm_right_t; + + +struct dm_stat { + int _link; + dm_vardata_t dt_handle; + dm_vardata_t dt_compname; + int dt_nevents; + dm_eventset_t dt_emask; + int dt_pers; /* field not supported */ + int dt_pmanreg; + time_t dt_dtime; + unsigned int dt_change; /* field not supported */ + unsigned int dt_pad1; /* reserved; do not reference */ + dm_dev_t dt_dev; + dm_ino_t dt_ino; + dm_mode_t dt_mode; + dm_nlink_t dt_nlink; + uid_t dt_uid; + gid_t dt_gid; + dm_dev_t dt_rdev; + unsigned int dt_pad2; /* reserved; do not reference */ + dm_off_t dt_size; + time_t dt_atime; + time_t dt_mtime; + time_t dt_ctime; + unsigned int dt_blksize; + dm_size_t dt_blocks; + + /* Non-standard filesystem-specific fields. Currently XFS is the only + supported filesystem type. + */ + + __u64 dt_pad3; /* reserved; do not reference */ + int dt_fstype; /* filesystem index; see sysfs(2) */ + union { + struct { + dm_igen_t igen; + unsigned int xflags; + unsigned int extsize; + unsigned int extents; + unsigned short aextents; + unsigned short dmstate; + } sgi_xfs; + } fsys_dep; +}; +typedef struct dm_stat dm_stat_t; + +#define dt_xfs_igen fsys_dep.sgi_xfs.igen +#define dt_xfs_xflags fsys_dep.sgi_xfs.xflags +#define dt_xfs_extsize fsys_dep.sgi_xfs.extsize +#define dt_xfs_extents fsys_dep.sgi_xfs.extents +#define dt_xfs_aextents fsys_dep.sgi_xfs.aextents +#define dt_xfs_dmstate fsys_dep.sgi_xfs.dmstate + +/* Flags for the non-standard dt_xfs_xflags field. */ + +#define DM_XFLAG_REALTIME 0x1 +#define DM_XFLAG_PREALLOC 0x2 +#define DM_XFLAG_HASATTR 0x80000000 + + +struct dm_timestruct { + time_t dm_tv_sec; + int dm_tv_nsec; +}; +typedef struct dm_timestruct dm_timestruct_t; + + +struct dm_xstat { /* not supported */ + dm_stat_t dx_statinfo; + dm_vardata_t dx_attrdata; +}; +typedef struct dm_xstat dm_xstat_t; + + + +/* The following list provides the prototypes for all functions defined in + the DMAPI interface. +*/ + +extern int +dm_clear_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep); + +extern int +dm_create_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_create_session( + dm_sessid_t oldsid, + char *sessinfop, + dm_sessid_t *newsidp); + +extern int +dm_create_userevent( + dm_sessid_t sid, + size_t msglen, + void *msgdatap, + dm_token_t *tokenp); + +extern int +dm_destroy_session( + dm_sessid_t sid); + +extern int +dm_downgrade_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_fd_to_handle( + int fd, + void **hanpp, + size_t *hlenp); + +extern int +dm_find_eventmsg( + dm_sessid_t sid, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_allocinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + unsigned int nelem, + dm_extent_t *extentp, + unsigned int *nelemp); + +extern int +dm_get_bulkall( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_bulkattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_config( + void *hanp, + size_t hlen, + dm_config_t flagname, + dm_size_t *retvalp); + +extern int +dm_get_config_events( + void *hanp, + size_t hlen, + unsigned int nelem, + dm_eventset_t *eventsetp, + unsigned int *nelemp); + +extern int +dm_get_dirattrs( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_eventset_t *eventsetp, + unsigned int *nelemp); + +extern int +dm_get_events( + dm_sessid_t sid, + unsigned int maxmsgs, + unsigned int flags, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_stat_t *statp); + +extern int +dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_region_t *regbufp, + unsigned int *nelemp); + +extern int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_inherit_t *inheritbufp, + unsigned int *nelemp); + +extern int +dm_getall_sessions( + unsigned int nelem, + dm_sessid_t *sidbufp, + unsigned int *nelemp); + +extern int +dm_getall_tokens( + dm_sessid_t sid, + unsigned int nelem, + dm_token_t *tokenbufp, + unsigned int *nelemp); + +extern int +dm_handle_cmp( + void *hanp1, + size_t hlen1, + void *hanp2, + size_t hlen2); + +extern void +dm_handle_free( + void *hanp, + size_t hlen); + +extern u_int +dm_handle_hash( + void *hanp, + size_t hlen); + +extern dm_boolean_t +dm_handle_is_valid( + void *hanp, + size_t hlen); + +extern int +dm_handle_to_fshandle( + void *hanp, + size_t hlen, + void **fshanpp, + size_t *fshlenp); + +extern int +dm_handle_to_fsid( + void *hanp, + size_t hlen, + dm_fsid_t *fsidp); + +extern int +dm_handle_to_igen( + void *hanp, + size_t hlen, + dm_igen_t *igenp); + +extern int +dm_handle_to_ino( + void *hanp, + size_t hlen, + dm_ino_t *inop); + +extern int +dm_handle_to_path( + void *dirhanp, + size_t dirhlen, + void *targhanp, + size_t targhlen, + size_t buflen, + char *pathbufp, + size_t *rlenp); + +extern int +dm_init_attrloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrloc_t *locp); + +extern int +dm_init_service( + char **versionstrpp); + +extern int +dm_make_handle( + dm_fsid_t *fsidp, + dm_ino_t *inop, + dm_igen_t *igenp, + void **hanpp, + size_t *hlenp); + +extern int +dm_make_fshandle( + dm_fsid_t *fsidp, + void **hanpp, + size_t *hlenp); + +extern int +dm_mkdir_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_move_event( + dm_sessid_t srcsid, + dm_token_t token, + dm_sessid_t targetsid, + dm_token_t *rtokenp); + +extern int +dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_query( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_path_to_fshandle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_path_to_handle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay); + +extern int +dm_probe_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp); + +extern int +dm_punch_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len); + +extern int +dm_query_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp); + +extern int +dm_query_session( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern dm_ssize_t +dm_read_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp); + +extern int +dm_release_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_remove_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int setdtime, + dm_attrname_t *attrnamep); + +extern int +dm_request_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int flags, + dm_right_t right); + +extern int +dm_respond_event( + dm_sessid_t sid, + dm_token_t token, + dm_response_t response, + int reterror, + size_t buflen, + void *respbufp); + +extern int +dm_send_msg( + dm_sessid_t targetsid, + dm_msgtype_t msgtype, + size_t buflen, + void *bufp); + +extern int +dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + unsigned int maxevent); + +extern int +dm_set_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp); + +extern int +dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + unsigned int maxevent); + +extern int +dm_set_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_fileattr_t *attrp); + +extern int +dm_set_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode); + +extern int +dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp); + +extern int +dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable); + +extern int +dm_symlink_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname, + char *path); + +extern int +dm_sync_by_handle( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_upgrade_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern dm_ssize_t +dm_write_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp); + +/* Non-standard SGI additions to the DMAPI interface. */ + +int +dm_open_by_handle( + void *hanp, + size_t hlen, + int mode); + +extern int +dm_get_dioinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_dioinfo_t *diop); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_DMAPI_H */ + diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_attr.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_attr.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_attr.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_attr.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +/* Retrieve attributes for a single file, directory or symlink. */ + +int +dm_get_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_stat_t *statp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_fileattr(tdp->td_vp, tdp->td_right, + mask, statp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* Set one or more file attributes of a file, directory, or symlink. */ + +int +dm_set_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_fileattr_t *attrp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->set_fileattr(tdp->td_vp, tdp->td_right, + mask, attrp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_bulkattr.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_bulkattr.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_bulkattr.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_bulkattr.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_init_attrloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrloc_t *locp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS|DM_TDT_DIR, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->init_attrloc(tdp->td_vp, tdp->td_right, locp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* + * Retrieves both standard and DM specific file attributes for the file + * system indicated by the handle. (The FS has to be mounted). + * Syscall returns 1 to indicate SUCCESS and more information is available. + * -1 is returned on error, and errno will be set appropriately. + * 0 is returned upon successful completion. + */ + +int +dm_get_bulkattr_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_bulkattr_rvp(tdp->td_vp, tdp->td_right, + mask, locp, buflen, bufp, rlenp, rvp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* + * Retrieves attributes of directory entries given a handle to that + * directory. Iterative. + * Syscall returns 1 to indicate SUCCESS and more information is available. + * -1 is returned on error, and errno will be set appropriately. + * 0 is returned upon successful completion. + */ + +int +dm_get_dirattrs_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_DIR, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_dirattrs_rvp(tdp->td_vp, tdp->td_right, + mask, locp, buflen, bufp, rlenp, rvp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_bulkall_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_bulkall_rvp(tdp->td_vp, tdp->td_right, + mask, attrnamep, locp, buflen, bufp, rlenp, rvp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_config.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_config.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_config.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_config.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + +int +dm_get_config( + void *hanp, + size_t hlen, + dm_config_t flagname, + dm_size_t *retvalp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + dm_size_t retval; + int system = 1; + int error; + + /* Trap and process configuration parameters which are system-wide. */ + + switch (flagname) { + case DM_CONFIG_LEGACY: + case DM_CONFIG_PENDING: + case DM_CONFIG_OBJ_REF: + retval = DM_TRUE; + break; + case DM_CONFIG_MAX_MESSAGE_DATA: + retval = DM_MAX_MSG_DATA; + break; + default: + system = 0; + break; + } + if (system) { + if (copy_to_user(retvalp, &retval, sizeof(retval))) + return(EFAULT); + return(0); + } + + /* Must be filesystem-specific. Convert the handle into a vnode. */ + + if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0) + return(error); + + /* Now call the filesystem-specific routine to determine the + value of the configuration option for that filesystem. + */ + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_config(tdp->td_vp, tdp->td_right, + flagname, retvalp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_config_events( + void *hanp, + size_t hlen, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + /* Convert the handle into a vnode. */ + + if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0) + return(error); + + /* Now call the filesystem-specific routine to determine the + events supported by that filesystem. + */ + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_config_events(tdp->td_vp, tdp->td_right, + nelem, eventsetp, nelemp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_dmattr.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_dmattr.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_dmattr.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_dmattr.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_clear_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->clear_inherit(tdp->td_vp, tdp->td_right, + attrnamep); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_dmattr(tdp->td_vp, tdp->td_right, + attrnamep, buflen, bufp, rlenp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_getall_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->getall_dmattr(tdp->td_vp, tdp->td_right, + buflen, bufp, rlenp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_getall_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->getall_inherit(tdp->td_vp, tdp->td_right, + nelem, inheritbufp, nelemp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_remove_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int setdtime, + dm_attrname_t *attrnamep) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->remove_dmattr(tdp->td_vp, tdp->td_right, + setdtime, attrnamep); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_set_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->set_dmattr(tdp->td_vp, tdp->td_right, + attrnamep, setdtime, buflen, bufp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_set_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->set_inherit(tdp->td_vp, tdp->td_right, + attrnamep, mode); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_event.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_event.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_event.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_event.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,859 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + +/* The "rights" portion of the DMAPI spec is not currently implemented. A + framework for rights is provided in the code, but turns out to be a noop + in practice. The following comments are a brain dump to serve as input to + the poor soul that eventually has to get DMAPI rights working in IRIX. + + A DMAPI right is similar but not identical to the mrlock_t mechanism + already used within the kernel. The similarities are that it is a + sleeping lock, and that a multiple-reader, single-writer protocol is used. + How locks are obtained and dropped are different however. With a mrlock_t, + a thread grabs the lock, does some stuff, then drops the lock, and all other + threads block in the meantime (assuming a write lock). There is a one-to- + one relationship between the lock and the thread which obtained the lock. + Not so with DMAPI right locks. A DMAPI lock is associated with a particular + session/token/hanp/hlen quad; since there is a dm_tokdata_t structure for + each such quad, you can think of it as a one-to-one relationship between the + lock and a dm_tokdata_t. Any application thread which presents the correct + quad is entitled to grab or release the lock, or to use the rights + associated with that lock. The thread that grabs the lock does not have to + be the one to use the lock, nor does it have to be the thread which drops + the lock. The lock can be held for very long periods of time, even across + multiple systems calls by multiple application threads. The idea is that a + coordinated group of DMAPI application threads can grab the lock, issue a + series of inode accesses and/or updates, then drop the lock, and be assured + that no other thread in the system could be modifying the inode at the same + time. The kernel is expected to blindly trust that the application will + not forget to unlock inodes it has locked, and will not deadlock itself + against the kernel. + + There are two types of DMAPI rights, file object (inode) and filesystem + object (superblock?). An inode right is the equivalent of the combination + of both the XFS ilock and iolock; if held exclusively, no data or metadata + within the file can be changed by non-lock-holding threads. The filesystem + object lock is a little fuzzier; I think that if it is held, things like + unmounts can be blocked, plus there is an event mask associated with the + filesystem which can't be updated without the lock. (By the way, that + event mask is supposed to be persistent in the superblock; add that to + your worklist :-) + + All events generated by XFS currently arrive with no rights, i.e. + DM_RIGHT_NULL, and return to the filesystem with no rights. It would be + smart to leave it this way if possible, because it otherwise becomes more + likely that an application thread will deadlock against the kernel if the + one responsible for calling dm_get_events() happens to touch a file which + was locked at the time the event was queued. Since the thread is blocked, + it can't read the event in order to find and drop the lock. Catch-22. If + you do have events that arrive with non-null rights, then dm_enqueue() needs + to have code added for synchronous events which atomically switches the + right from being a thread-based right to a dm_tokdata_t-based right without + allowing the lock to drop in between. You will probably have to add a new + dm_fsys_vector entry point to do this. The lock can't be lost during the + switch, or other threads might change the inode or superblock in between. + Likewise, if you need to return to the filesystem holding a right, then + you need a DMAPI-to-thread atomic switch to occur, most likely in + dm_change_right(). Again, the lock must not be lost during the switch; the + DMAPI spec spends a couple of pages stressing this. Another dm_fsys_vector + entry point is probably the answer. + + There are several assumptions implied in the current layout of the code. + First of all, if an event returns to the filesystem with a return value of + zero, then the filesystem can assume that any locks (rights) held at the + start of the event are still in effect at the end of the event. (Note that + the application could have temporarily dropped and reaquired the right + while the event was outstanding, however). If the event returns to the + filesystem with an errno, then the filesystem must assume that it has lost + any and all rights associated with any of the objects in the event. This + was done for a couple of reasons. First of all, since an errno is being + returned, most likely the filesystem is going to immediately drop all the + locks anyway. If the DMAPI code was required to unconditionally reobtain + all locks before returning to the filesystem, then dm_pending() wouldn't + work for NFS server threads because the process would block indefinitely + trying to get its thread-based rights back, because the DMAPI-rights + associated with the dm_tokdata_t in the outstanding event would prevent + the rights from being obtained. That would be a bad thing. We wouldn't + be able to let users Cntl-C out of read/write/truncate events either. + + If a case should ever surface where the thread has lost its rights even + though it has a zero return status, or where the thread has rights even + though it is returning with an errno, then this logic will have to be + reworked. This could be done by changing the 'right' parameters on all + the event calls to (dm_right_t *), so that they could serve both as IN + and OUT parameters. + + Some events such as DM_EVENT_DESTROY arrive without holding a vnode + reference; if you don't have a vnode reference, you can't have a right + on the file. + + One more quirk. The DM_EVENT_UNMOUNT event is defined to be synchronous + when it's behavior is asynchronous. If an unmount event arrives with + rights, the event should return with the same rights and should NOT leave + any rights in the dm_tokdata_t where the application could use them. +*/ + + +#define GETNEXTOFF(vdat) ((vdat).vd_offset + (vdat).vd_length) +#define HANDLE_SIZE(tdp) \ + ((tdp)->td_type & DM_TDT_VFS ? FSHSIZE : XFS_HSIZE((tdp)->td_handle)) + + +/* Given a vnode pointer in a filesystem known to support DMAPI, + build a tdp structure for the corresponding vnode. +*/ + +static dm_tokdata_t * +dm_vp_data( + vnode_t *vp, + dm_right_t right, + int referenced) /* != 0, caller holds vnode reference */ +{ + int error; + dm_tokdata_t *tdp; + + tdp = kmem_cache_alloc(dm_tokdata_cachep, SLAB_KERNEL); + if (tdp == NULL) { + printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__); + return NULL; + } + + tdp->td_next = NULL; + tdp->td_tevp = NULL; + tdp->td_app_ref = 0; + tdp->td_orig_right = right; + tdp->td_right = right; + tdp->td_flags = DM_TDF_ORIG; + if (referenced) { + tdp->td_flags |= DM_TDF_EVTREF; + } + + if (vp->v_type == VREG) { + tdp->td_type = DM_TDT_REG; + } else if (vp->v_type == VDIR) { + tdp->td_type = DM_TDT_DIR; + } else if (vp->v_type == VLNK) { + tdp->td_type = DM_TDT_LNK; + } else { + tdp->td_type = DM_TDT_OTH; + } + + if (referenced) { + tdp->td_vp = vp; + } else { + tdp->td_vp = NULL; + } + tdp->td_vcount = 0; + + if ((error = dm_vp_to_handle(vp, &tdp->td_handle)) != 0) { + panic("dm_vp_data: dm_vp_to_handle failed for vp %p in " + "a DMAPI filesystem, errno %d\n", vp, error); + } + + return(tdp); +} + + +/* Given a vfs pointer to a filesystem known to support DMAPI, build a tdp + structure for that vfsp. +*/ +static dm_tokdata_t * +dm_vfs_data( + vfs_t *vfsp, + vnode_t *vp, /* will be NULL for DM_EVENT_UNMOUNT */ + dm_right_t right) +{ + dm_tokdata_t *tdp; + + tdp = kmem_cache_alloc(dm_tokdata_cachep, SLAB_KERNEL); + if (tdp == NULL) { + printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__); + return NULL; + } + + tdp->td_next = NULL; + tdp->td_tevp = NULL; + tdp->td_app_ref = 0; + tdp->td_orig_right = right; + tdp->td_right = right; + tdp->td_flags = DM_TDF_ORIG; + if (vp) { + tdp->td_flags |= DM_TDF_EVTREF; + } + tdp->td_type = DM_TDT_VFS; + if (vp) { + tdp->td_vp = vp; + } else { + tdp->td_vp = NULL; + } + tdp->td_vcount = 0; + + bcopy(vfsp->vfs_altfsid, &tdp->td_handle.ha_fsid, sizeof(fsid_t)); + bzero((char *)&tdp->td_handle.ha_fsid + sizeof(fsid_t), + sizeof(tdp->td_handle) - sizeof(fsid_t)); + + return(tdp); +} + + +/* Link a tdp structure into the tevp. */ + +static void +dm_add_handle_to_event( + dm_tokevent_t *tevp, + dm_tokdata_t *tdp) +{ + tdp->td_next = tevp->te_tdp; + tevp->te_tdp = tdp; + tdp->td_tevp = tevp; +} + + +/* Generate the given data event for the vnode, and wait for a reply. The + caller must guarantee that the vnode's reference count is greater than zero + so that the filesystem can't disappear while the request is outstanding. +*/ + +int +dm_send_data_event( + dm_eventtype_t event, + bhv_desc_t *bdp, + dm_right_t vp_right, /* current right for vp */ + off_t offset, + size_t length, + int flags) /* 0 or DM_FLAGS_NDELAY */ +{ + dm_data_event_t *datap; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp; + vnode_t *vp; + int error; + + vp = BHV_TO_VNODE(bdp); + tdp = dm_vp_data(vp, vp_right, /* reference held */ 1); + if (tdp == NULL) + return ENOMEM; + + /* Calculate the size of the event in bytes, create an event structure + for it, and insert the file's handle into the event. + */ + + tevp = dm_evt_create_tevp(event, HANDLE_SIZE(tdp), (void **)&datap); + if (tevp == NULL) { + kmem_cache_free(dm_tokdata_cachep, tdp); + return(ENOMEM); + } + dm_add_handle_to_event(tevp, tdp); + + /* Now fill in all the dm_data_event_t fields. */ + + datap->de_handle.vd_offset = sizeof(*datap); + datap->de_handle.vd_length = HANDLE_SIZE(tdp); + bcopy(&tdp->td_handle, (char *)datap + datap->de_handle.vd_offset, + datap->de_handle.vd_length); + datap->de_offset = offset; + datap->de_length = length; + + /* Queue the message and wait for the reply. */ + + error = dm_enqueue_normal_event(vp->v_vfsp, tevp, flags); + + /* If no errors occurred, we must leave with the same rights we had + upon entry. If errors occurred, we must leave with no rights. + */ + + dm_evt_rele_tevp(tevp, error); + + return(error); +} + + +/* Generate the destroy event for the vnode and wait until the request has been + queued. The caller does not hold a vnode reference or a right on the vnode, + but it must otherwise lock down the vnode such that the filesystem can't + disappear while the request is waiting to be queued. While waiting to be + queued, the vnode must not be referenceable either by path or by a call + to dm_handle_to_vp(). +*/ + +int +dm_send_destroy_event( + bhv_desc_t *bdp, + dm_right_t vp_right) /* always DM_RIGHT_NULL */ +{ + dm_fsys_vector_t *fsys_vector; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp; + dm_destroy_event_t *destp; + dm_attrname_t attrname; + vnode_t *vp; + char *value; + int value_len; + int error; + + vp = BHV_TO_VNODE(bdp); + tdp = dm_vp_data(vp, vp_right, /* no reference held */ 0); + if (tdp == NULL) + return ENOMEM; + + if ((error = dm_waitfor_destroy_attrname(vp->v_vfsp, &attrname)) != 0) + return(error); + + /* If a return-on-destroy attribute name exists for this filesystem, + see if the object being deleted has this attribute. If the object + doesn't have the attribute or if we encounter an error, then send + the event without the attribute. + */ + + value_len = -1; /* because zero is a valid attribute length */ + if (attrname.an_chars[0] != '\0') { + fsys_vector = dm_fsys_vector(vp); + error = fsys_vector->get_destroy_dmattr(vp, vp_right, &attrname, + &value, &value_len); + if (error) + return error; + } + + /* Now that we know the size of the attribute value, if any, calculate + the size of the event in bytes, create an event structure for it, + and insert the handle into the event. + */ + + tevp = dm_evt_create_tevp(DM_EVENT_DESTROY, + HANDLE_SIZE(tdp) + (value_len >= 0 ? value_len : 0), + (void **)&destp); + if (tevp == NULL) { + kmem_cache_free(dm_tokdata_cachep, tdp); + if (value_len > 0) + kfree(value); + return(ENOMEM); + } + dm_add_handle_to_event(tevp, tdp); + + /* Now fill in all the dm_destroy_event_t fields. */ + + destp->ds_handle.vd_offset = sizeof(*destp); + destp->ds_handle.vd_length = HANDLE_SIZE(tdp); + bcopy(&tdp->td_handle, (char *)destp + destp->ds_handle.vd_offset, + destp->ds_handle.vd_length); + if (value_len >= 0) { + destp->ds_attrname = attrname; + destp->ds_attrcopy.vd_length = value_len; + if (value_len == 0) { + destp->ds_attrcopy.vd_offset = 0; + } else { + destp->ds_attrcopy.vd_offset = GETNEXTOFF(destp->ds_handle); + bcopy(value, (char *)destp + destp->ds_attrcopy.vd_offset, + value_len); + kfree(value); + } + } + + /* Queue the message asynchronously. */ + + error = dm_enqueue_normal_event(vp->v_vfsp, tevp, 0); + + /* Since we had no rights upon entry, we have none to reobtain before + leaving. + */ + + dm_evt_rele_tevp(tevp, 1); + + return(error); +} + + +/* The dm_mount_event_t event is sent in turn to all sessions that have asked + for it until one either rejects it or accepts it. The filesystem is not + going anywhere because the mount is blocked until the event is answered. +*/ + +int +dm_send_mount_event( + vfs_t *vfsp, /* filesystem being mounted */ + dm_right_t vfsp_right, + bhv_desc_t *bdp, /* mounted on directory */ + dm_right_t vp_right, + bhv_desc_t *rootbdp, + dm_right_t rootvp_right, + char *name1, /* mount path */ + char *name2) /* filesystem device name */ +{ + int error; + dm_tokevent_t *tevp = NULL; + dm_tokdata_t *tdp1 = NULL; /* filesystem handle for event */ + dm_tokdata_t *tdp2 = NULL; /* file handle for mounted-on dir. */ + dm_tokdata_t *tdp3 = NULL; /* file handle for root vnode */ + dm_mount_event_t *mp; + size_t nextoff; + vnode_t *vp = NULL; /* mounted on directory */ + vnode_t *rootvp = BHV_TO_VNODE(rootbdp); + + /* Convert the vfsp to a filesystem handle, and vp and rootvp into + file handles. vp (the mounted-on directory) may not have a handle + if it is a different filesystem type such as EFS which does not + support DMAPI. + */ + + if(bdp) + vp = BHV_TO_VNODE(bdp); + + tdp1 = dm_vfs_data(vfsp, rootvp, vfsp_right); + if (tdp1 == NULL) + goto out_nomem; + + if ((vp == NULL) || dm_check_dmapi_vp(vp)) { + vp = NULL; /* assume we are mounting on non XFS */ + } else { + tdp2 = dm_vp_data(vp, vp_right, /* reference held */ 1); + if (tdp2 == NULL) + goto out_nomem; + } + + tdp3 = dm_vp_data(rootvp, rootvp_right, /* reference held */ 1); + if (tdp3 == NULL) + goto out_nomem; + + /* Calculate the size of the event in bytes, create an event structure + for it, and insert the handles into the event. + */ + + tevp = dm_evt_create_tevp(DM_EVENT_MOUNT, + HANDLE_SIZE(tdp1) + (vp ? HANDLE_SIZE(tdp2) : 0) + + HANDLE_SIZE(tdp3) + strlen(name1) + 1 + + strlen(name2) + 1, (void **)&mp); + if (tevp == NULL) + goto out_nomem; + + dm_add_handle_to_event(tevp, tdp1); + if (vp) + dm_add_handle_to_event(tevp, tdp2); + dm_add_handle_to_event(tevp, tdp3); + + /* Now fill in all the dm_mount_event_t fields. */ + + mp->me_handle1.vd_offset = sizeof(*mp); + mp->me_handle1.vd_length = HANDLE_SIZE(tdp1); + bcopy(&tdp1->td_handle, (char *) mp + mp->me_handle1.vd_offset, + mp->me_handle1.vd_length); + nextoff = GETNEXTOFF(mp->me_handle1); + + if (vp) { + mp->me_handle2.vd_offset = nextoff; + mp->me_handle2.vd_length = HANDLE_SIZE(tdp2); + bcopy(&tdp2->td_handle, (char *)mp + mp->me_handle2.vd_offset, + mp->me_handle2.vd_length); + nextoff = GETNEXTOFF(mp->me_handle2); + } + + mp->me_name1.vd_offset = nextoff; + mp->me_name1.vd_length = strlen(name1) + 1; + bcopy(name1, (char *)mp + mp->me_name1.vd_offset, mp->me_name1.vd_length); + nextoff = GETNEXTOFF(mp->me_name1); + + mp->me_name2.vd_offset = nextoff; + mp->me_name2.vd_length = strlen(name2) + 1; + bcopy(name2, (char *)mp + mp->me_name2.vd_offset, mp->me_name2.vd_length); + nextoff = GETNEXTOFF(mp->me_name2); + + mp->me_roothandle.vd_offset = nextoff; + mp->me_roothandle.vd_length = HANDLE_SIZE(tdp3); + bcopy(&tdp3->td_handle, (char *)mp + mp->me_roothandle.vd_offset, + mp->me_roothandle.vd_length); + + mp->me_mode = (vfsp->vfs_flag & VFS_RDONLY ? DM_MOUNT_RDONLY : 0); + + /* Queue the message and wait for the reply. */ + + error = dm_enqueue_mount_event(vfsp, tevp); + + /* If no errors occurred, we must leave with the same rights we had + upon entry. If errors occurred, we must leave with no rights. + */ + + dm_evt_rele_tevp(tevp, error); + + return(error); + +out_nomem: + if (tevp) + kfree(tevp); + if (tdp1) + kmem_cache_free(dm_tokdata_cachep, tdp1); + if (tdp2) + kmem_cache_free(dm_tokdata_cachep, tdp2); + if (tdp3) + kmem_cache_free(dm_tokdata_cachep, tdp3); + return ENOMEM; +} + + +/* Generate an DM_EVENT_UNMOUNT event and wait for a reply. The 'retcode' + field indicates whether this is a successful or unsuccessful unmount. + If successful, the filesystem is already unmounted, and any pending handle + reference to the filesystem will be failed. If the unmount was + unsuccessful, then the filesystem will be placed back into full service. + + The DM_EVENT_UNMOUNT event should really be asynchronous, because the + application has no control over whether or not the unmount succeeds. (The + DMAPI spec defined it that way because asynchronous events aren't always + guaranteed to be delivered.) + + Since the filesystem is already unmounted in the successful case, the + DM_EVENT_UNMOUNT event can't make available any vnode to be used in + subsequent sid/hanp/hlen/token calls by the application. The event will + hang around until the application does a DM_RESP_CONTINUE, but the handle + within the event is unusable by the application. +*/ + +void +dm_send_unmount_event( + vfs_t *vfsp, + vnode_t *vp, /* NULL if unmount successful */ + dm_right_t vfsp_right, + mode_t mode, + int retcode, /* errno, if unmount failed */ + int flags) +{ + dm_namesp_event_t *np; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp1; + + /* If the unmount failed, put the filesystem back into full service, + allowing blocked handle references to finish. If it succeeded, put + the filesystem into the DM_STATE_UNMOUNTED state and fail all + blocked DM_NO_TOKEN handle accesses. + */ + + if (retcode != 0) { /* unmount was unsuccessful */ + dm_change_fsys_entry(vfsp, DM_STATE_MOUNTED); + } else { + dm_change_fsys_entry(vfsp, DM_STATE_UNMOUNTED); + } + + /* If the event wasn't in the filesystem dm_eventset_t, just remove + the filesystem from the list of DMAPI filesystems and return. + */ + + if (flags & DM_FLAGS_UNWANTED) { + if (retcode == 0) + dm_remove_fsys_entry(vfsp); + return; + } + + /* Calculate the size of the event in bytes and allocate zeroed memory + for it. + */ + + tdp1 = dm_vfs_data(vfsp, vp, vfsp_right); + if (tdp1 == NULL) + return; + + tevp = dm_evt_create_tevp(DM_EVENT_UNMOUNT, HANDLE_SIZE(tdp1), + (void **)&np); + if (tevp == NULL) { + kmem_cache_free(dm_tokdata_cachep, tdp1); + return; + } + + dm_add_handle_to_event(tevp, tdp1); + + /* Now copy in all the dm_namesp_event_t specific fields. */ + + np->ne_handle1.vd_offset = sizeof(*np); + np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); + bcopy(&tdp1->td_handle, (char *) np + np->ne_handle1.vd_offset, + np->ne_handle1.vd_length); + np->ne_mode = mode; + np->ne_retcode = retcode; + + /* Since DM_EVENT_UNMOUNT is effectively asynchronous, queue the + message and ignore any error return for DM_EVENT_UNMOUNT. + */ + + (void)dm_enqueue_normal_event(vfsp, tevp, flags); + + if (retcode == 0) + dm_remove_fsys_entry(vfsp); + + dm_evt_rele_tevp(tevp, 0); +} + + +/* Generate the given namespace event and wait for a reply (if synchronous) or + until the event has been queued (asynchronous). The caller must guarantee + that at least one vnode within the filesystem has had its reference count + bumped so that the filesystem can't disappear while the event is + outstanding. +*/ + +int +dm_send_namesp_event( + dm_eventtype_t event, + bhv_desc_t *bdp1, + dm_right_t vp1_right, + bhv_desc_t *bdp2, + dm_right_t vp2_right, + char *name1, + char *name2, + mode_t mode, + int retcode, + int flags) +{ + dm_namesp_event_t *np; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp1 = NULL; /* primary handle for event */ + dm_tokdata_t *tdp2 = NULL; /* additional handle for event */ + vfs_t *sidvfsp; /* vfs event must be registered on */ + size_t nextoff; + int error; + vnode_t *vp1; + + vp1 = BHV_TO_VNODE(bdp1); + sidvfsp = vp1->v_vfsp; + + switch (event) { + case DM_EVENT_PREUNMOUNT: + /* + * PREUNMOUNT - Send the file system handle in handle1, + * and the handle for the root dir in the second. Otherwise + * it's a normal sync message; i.e. succeeds or fails + * depending on the app's return code. + * bdp1 and bdp2 are both the root dir of mounted FS + * vp1_right is the filesystem right. + * vp2_right is the root inode right. + */ + + tdp1 = dm_vfs_data(sidvfsp, vp1, vp1_right); + if (tdp1 == NULL) + return ENOMEM; + tdp2 = dm_vp_data(BHV_TO_VNODE(bdp2), vp2_right, /* reference held */ 1); + if (tdp2 == NULL) { + kmem_cache_free(dm_tokdata_cachep, tdp1); + return ENOMEM; + } + + if (flags & DM_FLAGS_UNWANTED) { + dm_change_fsys_entry(sidvfsp, DM_STATE_UNMOUNTING); + return(0); + } + break; + + case DM_EVENT_NOSPACE: + /* vp1_right is the filesystem right. */ + + tdp1 = dm_vfs_data(sidvfsp, vp1, vp1_right); + if (tdp1 == NULL) + return ENOMEM; + tdp2 = dm_vp_data(BHV_TO_VNODE(bdp2), vp2_right, /* reference held */ 1); /* additional info - not in the spec */ + if (tdp2 == NULL) { + kmem_cache_free(dm_tokdata_cachep, tdp1); + return ENOMEM; + } + break; + + default: + /* All other events only pass in vnodes and don't require any + special cases. + */ + + tdp1 = dm_vp_data(vp1, vp1_right, /* reference held */ 1); + if (tdp1 == NULL) + return ENOMEM; + if (bdp2) { + tdp2 = dm_vp_data(BHV_TO_VNODE(bdp2), vp2_right, /* reference held */ 1); + if (tdp2 == NULL) { + kmem_cache_free(dm_tokdata_cachep, tdp1); + return ENOMEM; + } + } + } + + /* Calculate the size of the event in bytes and allocate zeroed memory + for it. + */ + + tevp = dm_evt_create_tevp(event, + HANDLE_SIZE(tdp1) + (bdp2 ? HANDLE_SIZE(tdp2) : 0) + + (name1 ? strlen(name1) + 1 : 0) + + (name2 ? strlen(name2) + 1 : 0), (void **)&np); + if (tevp == NULL) { + if (tdp1) + kmem_cache_free(dm_tokdata_cachep, tdp1); + if (tdp2) + kmem_cache_free(dm_tokdata_cachep, tdp2); + return(ENOMEM); + } + + dm_add_handle_to_event(tevp, tdp1); + if (bdp2) + dm_add_handle_to_event(tevp, tdp2); + + /* Now copy in all the dm_namesp_event_t specific fields. */ + + np->ne_handle1.vd_offset = sizeof(*np); + np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); + bcopy(&tdp1->td_handle, (char *) np + np->ne_handle1.vd_offset, + np->ne_handle1.vd_length); + nextoff = GETNEXTOFF(np->ne_handle1); + if (bdp2) { + np->ne_handle2.vd_offset = nextoff; + np->ne_handle2.vd_length = HANDLE_SIZE(tdp2); + bcopy(&tdp2->td_handle, (char *)np + np->ne_handle2.vd_offset, + np->ne_handle2.vd_length); + nextoff = GETNEXTOFF(np->ne_handle2); + } + if (name1) { + np->ne_name1.vd_offset = nextoff; + np->ne_name1.vd_length = strlen(name1) + 1; + bcopy(name1, (char *)np + np->ne_name1.vd_offset, + np->ne_name1.vd_length); + nextoff = GETNEXTOFF(np->ne_name1); + } + if (name2) { + np->ne_name2.vd_offset = nextoff; + np->ne_name2.vd_length = strlen(name2) + 1; + bcopy(name2, (char *)np + np->ne_name2.vd_offset, + np->ne_name2.vd_length); + } + np->ne_mode = mode; + np->ne_retcode = retcode; + + /* Queue the message and wait for the reply. */ + + error = dm_enqueue_normal_event(sidvfsp, tevp, flags); + + /* If no errors occurred, we must leave with the same rights we had + upon entry. If errors occurred, we must leave with no rights. + */ + + dm_evt_rele_tevp(tevp, error); + + if (!error && event == DM_EVENT_PREUNMOUNT) { + dm_change_fsys_entry(sidvfsp, DM_STATE_UNMOUNTING); + } + + return(error); +} + + +/* + * Send a message of type "DM_EVENT_USER". Since no vnode is involved, we + * don't have to worry about rights here. + */ + +int +dm_send_msg( + dm_sessid_t targetsid, + dm_msgtype_t msgtype, /* SYNC or ASYNC */ + size_t buflen, + void *bufp) +{ + dm_tokevent_t *tevp; + int sync; + void *msgp; + int error; + + if (buflen > DM_MAX_MSG_DATA) + return(E2BIG); + if (msgtype == DM_MSGTYPE_ASYNC) { + sync = 0; + } else if (msgtype == DM_MSGTYPE_SYNC) { + sync = 1; + } else { + return(EINVAL); + } + + tevp = dm_evt_create_tevp(DM_EVENT_USER, buflen, (void **)&msgp); + if (tevp == NULL) + return ENOMEM; + + if (buflen && copy_from_user(msgp, bufp, buflen)) { + dm_evt_rele_tevp(tevp, 0); + return(EFAULT); + } + + /* Enqueue the request and wait for the reply. */ + + error = dm_enqueue_sendmsg_event(targetsid, tevp, sync); + + /* Destroy the tevp and return the reply. (dm_pending is not + supported here.) + */ + + dm_evt_rele_tevp(tevp, error); + + return(error); +} + + +/* + * Send a message of type "DM_EVENT_USER". Since no vnode is involved, we + * don't have to worry about rights here. + */ + +int +dm_create_userevent( + dm_sessid_t sid, + size_t msglen, + void *msgdatap, + dm_token_t *tokenp) /* return token created */ +{ + dm_tokevent_t *tevp; + dm_token_t token; + int error; + void *msgp; + + if (msglen > DM_MAX_MSG_DATA) + return(E2BIG); + + tevp = dm_evt_create_tevp(DM_EVENT_USER, msglen, (void **)&msgp); + if (tevp == NULL) + return(ENOMEM); + + if (msglen && copy_from_user(msgp, msgdatap, msglen)) { + dm_evt_rele_tevp(tevp, 0); + return(EFAULT); + } + + /* Queue the message. If that didn't work, free the tevp structure. */ + + if ((error = dm_enqueue_user_event(sid, tevp, &token)) != 0) + dm_evt_rele_tevp(tevp, 0); + + if (!error && copy_to_user(tokenp, &token, sizeof(token))) + error = EFAULT; + + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_handle.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_handle.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_handle.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_handle.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_create_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->create_by_handle(tdp->td_vp, tdp->td_right, + hanp, hlen, cname); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_mkdir_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->mkdir_by_handle(tdp->td_vp, tdp->td_right, + hanp, hlen, cname); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_symlink_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname, + char *path) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->symlink_by_handle(tdp->td_vp, tdp->td_right, + hanp, hlen, cname, path); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_hole.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_hole.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_hole.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_hole.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_get_allocinfo_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_allocinfo_rvp(tdp->td_vp, tdp->td_right, + offp, nelem, extentp, nelemp, rvp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_probe_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->probe_hole(tdp->td_vp, tdp->td_right, + off, len, roffp, rlenp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_punch_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->punch_hole(tdp->td_vp, tdp->td_right, off, len); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_io.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_io.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_io.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_io.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_read_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->read_invis_rvp(tdp->td_vp, tdp->td_right, + off, len, bufp, rvp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_write_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->write_invis_rvp(tdp->td_vp, tdp->td_right, + flags, off, len, bufp, rvp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_sync_by_handle ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->sync_by_handle(tdp->td_vp, tdp->td_right); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_dioinfo ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_dioinfo_t *diop) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_dioinfo(tdp->td_vp, tdp->td_right, diop); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_kern.h linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_kern.h --- linux-2.4.19/fs/xfs/dmapi/dmapi_kern.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_kern.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __DMAPI_KERN_H__ +#define __DMAPI_KERN_H__ + + +union sys_dmapi_uarg { + void *p; + __u64 u; +}; +typedef union sys_dmapi_uarg sys_dmapi_u; + +struct sys_dmapi_args { + sys_dmapi_u uarg1, uarg2, uarg3, uarg4, uarg5, uarg6, uarg7, uarg8, + uarg9, uarg10, uarg11; +}; +typedef struct sys_dmapi_args sys_dmapi_args_t; + +#define DM_Uarg(uap,i) uap->uarg##i.u +#define DM_Parg(uap,i) uap->uarg##i.p + +#ifdef __KERNEL__ + +struct xfs_handle_t; + +/* The first group of definitions and prototypes define the filesystem's + interface into the DMAPI code. +*/ + + +/* Definitions used for the flags field on dm_send_data_event(), + dm_send_unmount_event(), and dm_send_namesp_event() calls. +*/ + +#define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ +#define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ + +/* Possible code levels reported by dm_code_level(). */ + +#define DM_CLVL_INIT 0 /* DMAPI prior to X/Open compliance */ +#define DM_CLVL_XOPEN 1 /* X/Open compliant DMAPI */ + + +/* Prototypes used outside of the DMI module/directory. */ + +int dm_send_data_event( + dm_eventtype_t event, + struct bhv_desc *bdp, + dm_right_t vp_right, + off_t off, + size_t len, + int flags); + +int dm_send_destroy_event( + struct bhv_desc *bdp, + dm_right_t vp_right); + +int dm_send_mount_event( + struct vfs *vfsp, + dm_right_t vfsp_right, + struct bhv_desc *bdp, + dm_right_t vp_right, + struct bhv_desc *rootbdp, + dm_right_t rootvp_right, + char *name1, + char *name2); + +int dm_send_namesp_event( + dm_eventtype_t event, + struct bhv_desc *bdp1, + dm_right_t vp1_right, + struct bhv_desc *bdp2, + dm_right_t vp2_right, + char *name1, + char *name2, + mode_t mode, + int retcode, + int flags); + +void dm_send_unmount_event( + struct vfs *vfsp, + struct vnode *vp, + dm_right_t vfsp_right, + mode_t mode, + int retcode, + int flags); + +int dm_code_level(void); + +int dm_vp_to_handle ( + struct vnode *vp, + xfs_handle_t *handlep); + +/* The following prototypes and definitions are used by DMAPI as its + interface into the filesystem code. Communication between DMAPI and the + filesystem are established as follows: + 1. DMAPI uses the VFS_DMAPI_FSYS_VECTOR to ask for the addresses + of all the functions within the filesystem that it may need to call. + 2. The filesystem returns an array of function name/address pairs which + DMAPI builds into a function vector. + The VFS_DMAPI_FSYS_VECTOR call is only made one time for a particular + filesystem type. From then on, DMAPI uses its function vector to call the + filesystem functions directly. Functions in the array which DMAPI doesn't + recognize are ignored. A dummy function which returns ENOSYS is used for + any function that DMAPI needs but which was not provided by the filesystem. + If XFS doesn't recognize the VFS_DMAPI_FSYS_VECTOR, DMAPI assumes that it + doesn't have the X/Open support code; in this case DMAPI uses the XFS-code + originally bundled within DMAPI. + + The goal of this interface is allow incremental changes to be made to + both the filesystem and to DMAPI while minimizing inter-patch dependencies, + and to eventually allow DMAPI to support multiple filesystem types at the + same time should that become necessary. +*/ + +typedef enum { + DM_FSYS_CLEAR_INHERIT = 0, + DM_FSYS_CREATE_BY_HANDLE = 1, + DM_FSYS_DOWNGRADE_RIGHT = 2, + DM_FSYS_GET_ALLOCINFO_RVP = 3, + DM_FSYS_GET_BULKALL_RVP = 4, + DM_FSYS_GET_BULKATTR_RVP = 5, + DM_FSYS_GET_CONFIG = 6, + DM_FSYS_GET_CONFIG_EVENTS = 7, + DM_FSYS_GET_DESTROY_DMATTR = 8, + DM_FSYS_GET_DIOINFO = 9, + DM_FSYS_GET_DIRATTRS_RVP = 10, + DM_FSYS_GET_DMATTR = 11, + DM_FSYS_GET_EVENTLIST = 12, + DM_FSYS_GET_FILEATTR = 13, + DM_FSYS_GET_REGION = 14, + DM_FSYS_GETALL_DMATTR = 15, + DM_FSYS_GETALL_INHERIT = 16, + DM_FSYS_INIT_ATTRLOC = 17, + DM_FSYS_MKDIR_BY_HANDLE = 18, + DM_FSYS_PROBE_HOLE = 19, + DM_FSYS_PUNCH_HOLE = 20, + DM_FSYS_READ_INVIS_RVP = 21, + DM_FSYS_RELEASE_RIGHT = 22, + DM_FSYS_REMOVE_DMATTR = 23, + DM_FSYS_REQUEST_RIGHT = 24, + DM_FSYS_SET_DMATTR = 25, + DM_FSYS_SET_EVENTLIST = 26, + DM_FSYS_SET_FILEATTR = 27, + DM_FSYS_SET_INHERIT = 28, + DM_FSYS_SET_REGION = 29, + DM_FSYS_SYMLINK_BY_HANDLE = 30, + DM_FSYS_SYNC_BY_HANDLE = 31, + DM_FSYS_UPGRADE_RIGHT = 32, + DM_FSYS_WRITE_INVIS_RVP = 33, + DM_FSYS_OBJ_REF_HOLD = 34, + DM_FSYS_MAX = 35 +} dm_fsys_switch_t; + + +#define DM_FSYS_OBJ 0x1 /* object refers to a fsys handle */ + + +/* + * Prototypes for filesystem-specific functions. + */ + +typedef int (*dm_fsys_clear_inherit_t)( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep); + +typedef int (*dm_fsys_create_by_handle_t)( + vnode_t *vp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname); + +typedef int (*dm_fsys_downgrade_right_t)( + vnode_t *vp, + dm_right_t right, + u_int type); /* DM_FSYS_OBJ or zero */ + +typedef int (*dm_fsys_get_allocinfo_rvp_t)( + vnode_t *vp, + dm_right_t right, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvalp); + +typedef int (*dm_fsys_get_bulkall_rvp_t)( + vnode_t *vp, /* root vnode */ + dm_right_t right, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_bulkattr_rvp_t)( + vnode_t *vp, /* root vnode */ + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_config_t)( + vnode_t *vp, + dm_right_t right, + dm_config_t flagname, + dm_size_t *retvalp); + +typedef int (*dm_fsys_get_config_events_t)( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp); + +typedef int (*dm_fsys_get_destroy_dmattr_t)( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + char **valuepp, + int *vlenp); + +typedef int (*dm_fsys_get_dioinfo_t)( + vnode_t *vp, + dm_right_t right, + dm_dioinfo_t *diop); + +typedef int (*dm_fsys_get_dirattrs_rvp_t)( + vnode_t *vp, + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_dmattr_t)( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp); + +typedef int (*dm_fsys_get_eventlist_t)( + vnode_t *vp, + dm_right_t right, + u_int type, + u_int nelem, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int *nelemp); /* in kernel space! */ + +typedef int (*dm_fsys_get_fileattr_t)( + vnode_t *vp, + dm_right_t right, + u_int mask, + dm_stat_t *statp); + +typedef int (*dm_fsys_get_region_t)( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp); + +typedef int (*dm_fsys_getall_dmattr_t)( + vnode_t *vp, + dm_right_t right, + size_t buflen, + void *bufp, + size_t *rlenp); + +typedef int (*dm_fsys_getall_inherit_t)( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp); + +typedef int (*dm_fsys_init_attrloc_t)( + vnode_t *vp, /* sometimes root vnode */ + dm_right_t right, + dm_attrloc_t *locp); + +typedef int (*dm_fsys_mkdir_by_handle_t)( + vnode_t *vp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname); + +typedef int (*dm_fsys_probe_hole_t)( + vnode_t *vp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp); + +typedef int (*dm_fsys_punch_hole_t)( + vnode_t *vp, + dm_right_t right, + dm_off_t off, + dm_size_t len); + +typedef int (*dm_fsys_read_invis_rvp_t)( + vnode_t *vp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +typedef int (*dm_fsys_release_right_t)( + vnode_t *vp, + dm_right_t right, + u_int type); + +typedef int (*dm_fsys_remove_dmattr_t)( + vnode_t *vp, + dm_right_t right, + int setdtime, + dm_attrname_t *attrnamep); + +typedef int (*dm_fsys_request_right_t)( + vnode_t *vp, + dm_right_t right, + u_int type, /* DM_FSYS_OBJ or zero */ + u_int flags, + dm_right_t newright); + +typedef int (*dm_fsys_set_dmattr_t)( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp); + +typedef int (*dm_fsys_set_eventlist_t)( + vnode_t *vp, + dm_right_t right, + u_int type, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent); + +typedef int (*dm_fsys_set_fileattr_t)( + vnode_t *vp, + dm_right_t right, + u_int mask, + dm_fileattr_t *attrp); + +typedef int (*dm_fsys_set_inherit_t)( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + mode_t mode); + +typedef int (*dm_fsys_set_region_t)( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp); + +typedef int (*dm_fsys_symlink_by_handle_t)( + vnode_t *vp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname, + char *path); + +typedef int (*dm_fsys_sync_by_handle_t)( + vnode_t *vp, + dm_right_t right); + +typedef int (*dm_fsys_upgrade_right_t)( + vnode_t *vp, + dm_right_t right, + u_int type); /* DM_FSYS_OBJ or zero */ + +typedef int (*dm_fsys_write_invis_rvp_t)( + vnode_t *vp, + dm_right_t right, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +typedef void (*dm_fsys_obj_ref_hold_t)( + vnode_t *vp); + + +/* Structure definitions used by the VFS_DMAPI_FSYS_VECTOR call. */ + +typedef struct { + dm_fsys_switch_t func_no; /* function number */ + union { + dm_fsys_clear_inherit_t clear_inherit; + dm_fsys_create_by_handle_t create_by_handle; + dm_fsys_downgrade_right_t downgrade_right; + dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp; + dm_fsys_get_bulkall_rvp_t get_bulkall_rvp; + dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp; + dm_fsys_get_config_t get_config; + dm_fsys_get_config_events_t get_config_events; + dm_fsys_get_destroy_dmattr_t get_destroy_dmattr; + dm_fsys_get_dioinfo_t get_dioinfo; + dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp; + dm_fsys_get_dmattr_t get_dmattr; + dm_fsys_get_eventlist_t get_eventlist; + dm_fsys_get_fileattr_t get_fileattr; + dm_fsys_get_region_t get_region; + dm_fsys_getall_dmattr_t getall_dmattr; + dm_fsys_getall_inherit_t getall_inherit; + dm_fsys_init_attrloc_t init_attrloc; + dm_fsys_mkdir_by_handle_t mkdir_by_handle; + dm_fsys_probe_hole_t probe_hole; + dm_fsys_punch_hole_t punch_hole; + dm_fsys_read_invis_rvp_t read_invis_rvp; + dm_fsys_release_right_t release_right; + dm_fsys_remove_dmattr_t remove_dmattr; + dm_fsys_request_right_t request_right; + dm_fsys_set_dmattr_t set_dmattr; + dm_fsys_set_eventlist_t set_eventlist; + dm_fsys_set_fileattr_t set_fileattr; + dm_fsys_set_inherit_t set_inherit; + dm_fsys_set_region_t set_region; + dm_fsys_symlink_by_handle_t symlink_by_handle; + dm_fsys_sync_by_handle_t sync_by_handle; + dm_fsys_upgrade_right_t upgrade_right; + dm_fsys_write_invis_rvp_t write_invis_rvp; + dm_fsys_obj_ref_hold_t obj_ref_hold; + } u_fc; +} fsys_function_vector_t; + +struct dm_fcntl_vector { + int code_level; + int count; /* Number of functions in the vector */ + fsys_function_vector_t *vecp; +}; +typedef struct dm_fcntl_vector dm_fcntl_vector_t; + +struct dm_fcntl_mapevent { + size_t length; /* length of transfer */ + dm_eventtype_t max_event; /* Maximum (WRITE or READ) event */ + int error; /* returned error code */ +}; +typedef struct dm_fcntl_mapevent dm_fcntl_mapevent_t; + +#endif /* __KERNEL__ */ + + +/* The following definitions are needed both by the kernel and by the + library routines. +*/ + +#define DM_MAX_HANDLE_SIZE 56 /* maximum size for a file handle */ + + +/* + * Opcodes for dmapi ioctl. + */ + +#define DM_CLEAR_INHERIT 1 +#define DM_CREATE_BY_HANDLE 2 +#define DM_CREATE_SESSION 3 +#define DM_CREATE_USEREVENT 4 +#define DM_DESTROY_SESSION 5 +#define DM_DOWNGRADE_RIGHT 6 +#define DM_FD_TO_HANDLE 7 +#define DM_FIND_EVENTMSG 8 +#define DM_GET_ALLOCINFO 9 +#define DM_GET_BULKALL 10 +#define DM_GET_BULKATTR 11 +#define DM_GET_CONFIG 12 +#define DM_GET_CONFIG_EVENTS 13 +#define DM_GET_DIOINFO 14 +#define DM_GET_DIRATTRS 15 +#define DM_GET_DMATTR 16 +#define DM_GET_EVENTLIST 17 +#define DM_GET_EVENTS 18 +#define DM_GET_FILEATTR 19 +#define DM_GET_MOUNTINFO 20 +#define DM_GET_REGION 21 +#define DM_GETALL_DISP 22 +#define DM_GETALL_DMATTR 23 +#define DM_GETALL_INHERIT 24 +#define DM_GETALL_SESSIONS 25 +#define DM_GETALL_TOKENS 26 +#define DM_INIT_ATTRLOC 27 +#define DM_MKDIR_BY_HANDLE 28 +#define DM_MOVE_EVENT 29 +#define DM_OBJ_REF_HOLD 30 +#define DM_OBJ_REF_QUERY 31 +#define DM_OBJ_REF_RELE 32 +#define DM_PATH_TO_FSHANDLE 33 +#define DM_PATH_TO_HANDLE 34 +#define DM_PENDING 35 +#define DM_PROBE_HOLE 36 +#define DM_PUNCH_HOLE 37 +#define DM_QUERY_RIGHT 38 +#define DM_QUERY_SESSION 39 +#define DM_READ_INVIS 40 +#define DM_RELEASE_RIGHT 41 +#define DM_REMOVE_DMATTR 42 +#define DM_REQUEST_RIGHT 43 +#define DM_RESPOND_EVENT 44 +#define DM_SEND_MSG 45 +#define DM_SET_DISP 46 +#define DM_SET_DMATTR 47 +#define DM_SET_EVENTLIST 48 +#define DM_SET_FILEATTR 49 +#define DM_SET_INHERIT 50 +#define DM_SET_REGION 51 +#define DM_SET_RETURN_ON_DESTROY 52 +#define DM_SYMLINK_BY_HANDLE 53 +#define DM_SYNC_BY_HANDLE 54 +#define DM_UPGRADE_RIGHT 55 +#define DM_WRITE_INVIS 56 +#define DM_OPEN_BY_HANDLE 57 + +#endif /* __DMAPI_KERN_H__ */ diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_mountinfo.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_mountinfo.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_mountinfo.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_mountinfo.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + +#ifdef linux +/* XXX */ +#define vfsmax 1 +#endif + +typedef struct { + int support_type; + char name[16]; + dm_fsys_vector_t *vptr; +} dm_vector_map_t; + +/* Values for the support_type field. */ + +#define DM_SUPPORT_UNKNOWN 0 +#define DM_SUPPORT_AVAIL 1 + + +dm_vector_map_t *dm_fsys_map = NULL; + + +int +dm_code_level(void) +{ + return(DM_CLVL_XOPEN); /* initial X/Open compliant release */ +} + + +/* Dummy routine which is stored in each function vector slot for which the + filesystem provides no function of its own. If an application calls the + function, he will just get ENOSYS. +*/ + +static int +dm_enosys(void) +{ + return(ENOSYS); /* function not supported by filesystem */ +} + + +/* dm_query_fsys_for_vector() asks a filesystem for its list of supported + DMAPI functions, and builds a dm_vector_map_t structure based upon the + reply. We ignore functions supported by the filesystem which we do not + know about, and we substitute the subroutine 'dm_enosys' for each function + we know about but the filesystem does not support. +*/ + +static void +dm_query_fsys_for_vector( + vnode_t *vp) +{ + dm_vector_map_t *map; + fsys_function_vector_t *vecp; + dm_fsys_vector_t *vptr; + dm_fcntl_vector_t vecrq; + struct vfs *vfsp = vp->v_vfsp; + int fstype; + int error; + int i; + + /* XXX fstype = vfsp->vfs_fstype */ + fstype = 0; + map = &dm_fsys_map[fstype]; + + /* Clear out any information left from a previous filesystem that was + in this slot and initialize it for the new filesystem. + */ + + if (map->vptr) { + kfree(map->vptr); + map->vptr = NULL; + } + + /* XXX strcpy(map->name, vfssw[fstype].vsw_name); */ + strcpy(map->name, XFS_NAME); + + map->support_type = DM_SUPPORT_AVAIL; + + /* Next allocate a function vector and initialize all fields with a + dummy function that returns ENOSYS. + */ + + vptr = map->vptr = kmalloc(sizeof(*map->vptr), SLAB_KERNEL); + if (vptr == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return; + } + + strncpy(vptr->fsys_name, map->name, sizeof(vptr->fsys_name)); + vptr->code_level = 0; + vptr->clear_inherit = (dm_fsys_clear_inherit_t)dm_enosys; + vptr->create_by_handle = (dm_fsys_create_by_handle_t)dm_enosys; + vptr->downgrade_right = (dm_fsys_downgrade_right_t)dm_enosys; + vptr->get_allocinfo_rvp = (dm_fsys_get_allocinfo_rvp_t)dm_enosys; + vptr->get_bulkall_rvp = (dm_fsys_get_bulkall_rvp_t)dm_enosys; + vptr->get_bulkattr_rvp = (dm_fsys_get_bulkattr_rvp_t)dm_enosys; + vptr->get_config = (dm_fsys_get_config_t)dm_enosys; + vptr->get_config_events = (dm_fsys_get_config_events_t)dm_enosys; + vptr->get_destroy_dmattr = (dm_fsys_get_destroy_dmattr_t)dm_enosys; + vptr->get_dioinfo = (dm_fsys_get_dioinfo_t)dm_enosys; + vptr->get_dirattrs_rvp = (dm_fsys_get_dirattrs_rvp_t)dm_enosys; + vptr->get_dmattr = (dm_fsys_get_dmattr_t)dm_enosys; + vptr->get_eventlist = (dm_fsys_get_eventlist_t)dm_enosys; + vptr->get_fileattr = (dm_fsys_get_fileattr_t)dm_enosys; + vptr->get_region = (dm_fsys_get_region_t)dm_enosys; + vptr->getall_dmattr = (dm_fsys_getall_dmattr_t)dm_enosys; + vptr->getall_inherit = (dm_fsys_getall_inherit_t)dm_enosys; + vptr->init_attrloc = (dm_fsys_init_attrloc_t)dm_enosys; + vptr->mkdir_by_handle = (dm_fsys_mkdir_by_handle_t)dm_enosys; + vptr->probe_hole = (dm_fsys_probe_hole_t)dm_enosys; + vptr->punch_hole = (dm_fsys_punch_hole_t)dm_enosys; + vptr->read_invis_rvp = (dm_fsys_read_invis_rvp_t)dm_enosys; + vptr->release_right = (dm_fsys_release_right_t)dm_enosys; + vptr->request_right = (dm_fsys_request_right_t)dm_enosys; + vptr->remove_dmattr = (dm_fsys_remove_dmattr_t)dm_enosys; + vptr->set_dmattr = (dm_fsys_set_dmattr_t)dm_enosys; + vptr->set_eventlist = (dm_fsys_set_eventlist_t)dm_enosys; + vptr->set_fileattr = (dm_fsys_set_fileattr_t)dm_enosys; + vptr->set_inherit = (dm_fsys_set_inherit_t)dm_enosys; + vptr->set_region = (dm_fsys_set_region_t)dm_enosys; + vptr->symlink_by_handle = (dm_fsys_symlink_by_handle_t)dm_enosys; + vptr->sync_by_handle = (dm_fsys_sync_by_handle_t)dm_enosys; + vptr->upgrade_right = (dm_fsys_upgrade_right_t)dm_enosys; + vptr->write_invis_rvp = (dm_fsys_write_invis_rvp_t)dm_enosys; + vptr->obj_ref_hold = (dm_fsys_obj_ref_hold_t)dm_enosys; + + /* Issue a VFS_DMAPI_FSYS_VECTOR to the filesystem in order to obtain + its vector of filesystem-specific DMAPI routines. + */ + + vecrq.count = 0; + vecrq.vecp = NULL; + + VFS_DMAPI_FSYS_VECTOR(vfsp, &vecrq, error); + + /* If we still have an error at this point, then the filesystem simply + does not support DMAPI, so we give up with all functions set to + ENOSYS. + */ + + if (error || vecrq.count == 0) + return; + + /* The request succeeded and we were given a vector which we need to + map to our current level. Overlay the dummy function with every + filesystem function we understand. + */ + + vptr->code_level = vecrq.code_level; + vecp = vecrq.vecp; + for (i = 0; i < vecrq.count; i++) { + switch (vecp[i].func_no) { + case DM_FSYS_CLEAR_INHERIT: + vptr->clear_inherit = vecp[i].u_fc.clear_inherit; + break; + case DM_FSYS_CREATE_BY_HANDLE: + vptr->create_by_handle = vecp[i].u_fc.create_by_handle; + break; + case DM_FSYS_DOWNGRADE_RIGHT: + vptr->downgrade_right = vecp[i].u_fc.downgrade_right; + break; + case DM_FSYS_GET_ALLOCINFO_RVP: + vptr->get_allocinfo_rvp = vecp[i].u_fc.get_allocinfo_rvp; + break; + case DM_FSYS_GET_BULKALL_RVP: + vptr->get_bulkall_rvp = vecp[i].u_fc.get_bulkall_rvp; + break; + case DM_FSYS_GET_BULKATTR_RVP: + vptr->get_bulkattr_rvp = vecp[i].u_fc.get_bulkattr_rvp; + break; + case DM_FSYS_GET_CONFIG: + vptr->get_config = vecp[i].u_fc.get_config; + break; + case DM_FSYS_GET_CONFIG_EVENTS: + vptr->get_config_events = vecp[i].u_fc.get_config_events; + break; + case DM_FSYS_GET_DESTROY_DMATTR: + vptr->get_destroy_dmattr = vecp[i].u_fc.get_destroy_dmattr; + break; + case DM_FSYS_GET_DIOINFO: + vptr->get_dioinfo = vecp[i].u_fc.get_dioinfo; + break; + case DM_FSYS_GET_DIRATTRS_RVP: + vptr->get_dirattrs_rvp = vecp[i].u_fc.get_dirattrs_rvp; + break; + case DM_FSYS_GET_DMATTR: + vptr->get_dmattr = vecp[i].u_fc.get_dmattr; + break; + case DM_FSYS_GET_EVENTLIST: + vptr->get_eventlist = vecp[i].u_fc.get_eventlist; + break; + case DM_FSYS_GET_FILEATTR: + vptr->get_fileattr = vecp[i].u_fc.get_fileattr; + break; + case DM_FSYS_GET_REGION: + vptr->get_region = vecp[i].u_fc.get_region; + break; + case DM_FSYS_GETALL_DMATTR: + vptr->getall_dmattr = vecp[i].u_fc.getall_dmattr; + break; + case DM_FSYS_GETALL_INHERIT: + vptr->getall_inherit = vecp[i].u_fc.getall_inherit; + break; + case DM_FSYS_INIT_ATTRLOC: + vptr->init_attrloc = vecp[i].u_fc.init_attrloc; + break; + case DM_FSYS_MKDIR_BY_HANDLE: + vptr->mkdir_by_handle = vecp[i].u_fc.mkdir_by_handle; + break; + case DM_FSYS_PROBE_HOLE: + vptr->probe_hole = vecp[i].u_fc.probe_hole; + break; + case DM_FSYS_PUNCH_HOLE: + vptr->punch_hole = vecp[i].u_fc.punch_hole; + break; + case DM_FSYS_READ_INVIS_RVP: + vptr->read_invis_rvp = vecp[i].u_fc.read_invis_rvp; + break; + case DM_FSYS_RELEASE_RIGHT: + vptr->release_right = vecp[i].u_fc.release_right; + break; + case DM_FSYS_REMOVE_DMATTR: + vptr->remove_dmattr = vecp[i].u_fc.remove_dmattr; + break; + case DM_FSYS_REQUEST_RIGHT: + vptr->request_right = vecp[i].u_fc.request_right; + break; + case DM_FSYS_SET_DMATTR: + vptr->set_dmattr = vecp[i].u_fc.set_dmattr; + break; + case DM_FSYS_SET_EVENTLIST: + vptr->set_eventlist = vecp[i].u_fc.set_eventlist; + break; + case DM_FSYS_SET_FILEATTR: + vptr->set_fileattr = vecp[i].u_fc.set_fileattr; + break; + case DM_FSYS_SET_INHERIT: + vptr->set_inherit = vecp[i].u_fc.set_inherit; + break; + case DM_FSYS_SET_REGION: + vptr->set_region = vecp[i].u_fc.set_region; + break; + case DM_FSYS_SYMLINK_BY_HANDLE: + vptr->symlink_by_handle = vecp[i].u_fc.symlink_by_handle; + break; + case DM_FSYS_SYNC_BY_HANDLE: + vptr->sync_by_handle = vecp[i].u_fc.sync_by_handle; + break; + case DM_FSYS_UPGRADE_RIGHT: + vptr->upgrade_right = vecp[i].u_fc.upgrade_right; + break; + case DM_FSYS_WRITE_INVIS_RVP: + vptr->write_invis_rvp = vecp[i].u_fc.write_invis_rvp; + break; + case DM_FSYS_OBJ_REF_HOLD: + vptr->obj_ref_hold = vecp[i].u_fc.obj_ref_hold; + break; + default: /* ignore ones we don't understand */ + break; + } + } +} + + +/* Given a behavior pointer, dm_fsys_vector() returns a pointer to the DMAPI + function vector to be used for the corresponding vnode. There is one possible + function vector for each filesystem type, although currently XFS is the + only filesystem that actually supports DMAPI. +*/ + +dm_fsys_vector_t * +dm_fsys_vector( + vnode_t *vp) +{ + dm_vector_map_t *map; + int fstype; + + /* XXX fstype = vp->v_vfsp->vfs_fstype */ + fstype = 0; + + /* If this is the first call, initialize the filesystem function + vector map. + */ + + if (dm_fsys_map == NULL) { + int size = vfsmax * sizeof(*dm_fsys_map); + + dm_fsys_map = (dm_vector_map_t *)kmalloc(size, GFP_KERNEL); + if (dm_fsys_map == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return NULL; + } + memset(dm_fsys_map, 0, size); + } + map = &dm_fsys_map[fstype]; + + /* If a new filesystem has been dynamically loaded into a slot + previously held by another filesystem, then treat it as a + DM_SUPPORT_UNKNOWN. + */ + + /* XXX if (strcmp(map->name, vfssw[fstype].vsw_name)) */ + if (strcmp(map->name, XFS_NAME)) + map->support_type = DM_SUPPORT_UNKNOWN; + + /* If we don't yet know what the filesystem supports, ask it. */ + + if (map->support_type == DM_SUPPORT_UNKNOWN) + dm_query_fsys_for_vector(vp); + + /* Now return the function vector. */ + + return(map->vptr); +} + + +void +dm_fsys_vector_free() +{ + dm_vector_map_t *map; + int i; + + if (dm_fsys_map) { + for (i = 0; i < vfsmax; i++){ + map = &dm_fsys_map[i]; + if (map->vptr) + kfree(map->vptr); + } + kfree(dm_fsys_map); + } +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_private.h linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_private.h --- linux-2.4.19/fs/xfs/dmapi/dmapi_private.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_private.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _DMAPI_PRIVATE_H +#define _DMAPI_PRIVATE_H + +#include "xfs.h" + +#ifdef CONFIG_PROC_FS +#define DMAPI_PROCFS "fs/xfs_dmapi_v2" /* DMAPI device in /proc. */ +#define DMAPI_DBG_PROCFS "fs/xfs_dmapi_d" /* DMAPI debugging dir */ +#endif + +extern struct kmem_cache_s *dm_fsreg_cachep; +extern struct kmem_cache_s *dm_tokdata_cachep; +extern struct kmem_cache_s *dm_session_cachep; + + + +typedef struct dm_tokdata { + struct dm_tokdata *td_next; + struct dm_tokevent *td_tevp; /* pointer to owning tevp */ + int td_app_ref; /* # app threads currently active */ + dm_right_t td_orig_right; /* original right held when created */ + dm_right_t td_right; /* current right held for this handle */ + short td_flags; + short td_type; /* object type */ + int td_vcount; /* # of current application VN_HOLDs */ + vnode_t *td_vp; /* vnode pointer */ + xfs_handle_t td_handle; /* handle for vp or vfsp */ +} dm_tokdata_t; + +/* values for td_type */ + +#define DM_TDT_NONE 0x00 /* td_handle is empty */ +#define DM_TDT_VFS 0x01 /* td_handle points to a vfs */ +#define DM_TDT_REG 0x02 /* td_handle points to a file */ +#define DM_TDT_DIR 0x04 /* td_handle points to a directory */ +#define DM_TDT_LNK 0x08 /* td_handle points to a symlink */ +#define DM_TDT_OTH 0x10 /* some other object eg. pipe, socket */ + +#define DM_TDT_VNO (DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH) +#define DM_TDT_ANY (DM_TDT_VFS|DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH) + +/* values for td_flags */ + +#define DM_TDF_ORIG 0x0001 /* part of the original event */ +#define DM_TDF_EVTREF 0x0002 /* event thread holds vnode reference */ +#define DM_TDF_STHREAD 0x0004 /* only one app can use this handle */ +#define DM_TDF_RIGHT 0x0008 /* vcount bumped for dm_request_right */ +#define DM_TDF_HOLD 0x0010 /* vcount bumped for dm_obj_ref_hold */ + + +/* Because some events contain __u64 fields, we force te_msg and te_event + to always be 8-byte aligned. In order to send more than one message in + a single dm_get_events() call, we also ensure that each message is an + 8-byte multiple. +*/ + +typedef struct dm_tokevent { + struct dm_tokevent *te_next; + struct dm_tokevent *te_hashnext; /* hash chain */ + lock_t te_lock; /* lock for all fields but te_*next. + * te_next and te_hashnext are + * protected by the session lock. + */ + short te_flags; + short te_allocsize; /* alloc'ed size of this structure */ + sv_t te_evt_queue; /* queue waiting for dm_respond_event */ + sv_t te_app_queue; /* queue waiting for handle access */ + int te_evt_ref; /* number of event procs using token */ + int te_app_ref; /* number of app procs using token */ + int te_app_slp; /* number of app procs sleeping */ + int te_reply; /* return errno for sync messages */ + dm_tokdata_t *te_tdp; /* list of handle/right pairs */ + union { + __u64 align; /* force alignment of te_msg */ + dm_eventmsg_t te_msg; /* user visible part */ + } te_u; + __u64 te_event; /* start of dm_xxx_event_t message */ +} dm_tokevent_t; + +#define te_msg te_u.te_msg + +/* values for te_flags */ + +#define DM_TEF_LOCKED 0x0001 /* event "locked" by dm_get_events() */ +#define DM_TEF_INTERMED 0x0002 /* a dm_pending reply was received */ +#define DM_TEF_FINAL 0x0004 /* dm_respond_event has been received */ +#ifdef __sgi +#define DM_TEF_HASHED 0x0010 /* event is on hash chain */ +#endif + + +#ifdef __sgi +#ifdef DEBUG +#define DM_SHASH_DEBUG +#endif + +typedef struct dm_sesshash { + dm_tokevent_t *h_next; /* ptr to chain of tokevents */ +#ifdef DM_SHASH_DEBUG + int maxlength; + int curlength; + int num_adds; + int num_dels; + int dup_hits; +#endif +} dm_sesshash_t; +#endif + + +typedef struct dm_eventq { + dm_tokevent_t *eq_head; + dm_tokevent_t *eq_tail; + int eq_count; /* size of queue */ +} dm_eventq_t; + + +typedef struct dm_session { + struct dm_session *sn_next; /* sessions linkage */ + dm_sessid_t sn_sessid; /* user-visible session number */ + u_int sn_flags; + lock_t sn_qlock; /* lock for newq/delq related fields */ + sv_t sn_readerq; /* waiting for message on sn_newq */ + sv_t sn_writerq; /* waiting for room on sn_newq */ + u_int sn_readercnt; /* count of waiting readers */ + u_int sn_writercnt; /* count of waiting readers */ + dm_eventq_t sn_newq; /* undelivered event queue */ + dm_eventq_t sn_delq; /* delivered event queue */ + dm_eventq_t sn_evt_writerq; /* events of thrds in sn_writerq */ +#ifdef __sgi + dm_sesshash_t *sn_sesshash; /* buckets for tokevent hash chains */ +#ifdef DM_SHASH_DEBUG + int sn_buckets_in_use; + int sn_max_buckets_in_use; +#endif +#endif + char sn_info[DM_SESSION_INFO_LEN]; /* user-supplied info */ +} dm_session_t; + +/* values for sn_flags */ + +#define DM_SN_WANTMOUNT 0x0001 /* session wants to get mount events */ + + +typedef enum { + DM_STATE_MOUNTING, + DM_STATE_MOUNTED, + DM_STATE_UNMOUNTING, + DM_STATE_UNMOUNTED +} dm_fsstate_t; + + +typedef struct dm_fsreg { + struct dm_fsreg *fr_next; + vfs_t *fr_vfsp; /* filesystem pointer */ + dm_tokevent_t *fr_tevp; + fsid_t fr_fsid; /* filesystem ID */ + void *fr_msg; /* dm_mount_event_t for filesystem */ + int fr_msgsize; /* size of dm_mount_event_t */ + dm_fsstate_t fr_state; + sv_t fr_dispq; + int fr_dispcnt; + dm_eventq_t fr_evt_dispq; /* events of thrds in fr_dispq */ + sv_t fr_queue; /* queue for hdlcnt/vfscnt/unmount */ + lock_t fr_lock; + int fr_hdlcnt; /* threads blocked during unmount */ + int fr_vfscnt; /* threads in VFS_VGET or VFS_ROOT */ + int fr_unmount; /* if non-zero, umount is sleeping */ + dm_attrname_t fr_rattr; /* dm_set_return_on_destroy attribute */ + dm_session_t *fr_sessp [DM_EVENT_MAX]; +} dm_fsreg_t; + + + + +/* events valid in dm_set_disp() when called with a filesystem handle. */ + +#define DM_VALID_DISP_EVENTS ( \ + (1 << DM_EVENT_PREUNMOUNT) | \ + (1 << DM_EVENT_UNMOUNT) | \ + (1 << DM_EVENT_NOSPACE) | \ + (1 << DM_EVENT_DEBUT) | \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_READ) | \ + (1 << DM_EVENT_WRITE) | \ + (1 << DM_EVENT_TRUNCATE) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + + +/* isolate the read/write/trunc events of a dm_tokevent_t */ + +#define DM_EVENT_RDWRTRUNC(tevp) ( \ + ((tevp)->te_msg.ev_type == DM_EVENT_READ) || \ + ((tevp)->te_msg.ev_type == DM_EVENT_WRITE) || \ + ((tevp)->te_msg.ev_type == DM_EVENT_TRUNCATE) ) + + +/* + * Global handle hack isolation. + */ + +#define DM_GLOBALHAN(hanp, hlen) (((hanp) == DM_GLOBAL_HANP) && \ + ((hlen) == DM_GLOBAL_HLEN)) + + +#define DM_MAX_MSG_DATA 3960 + + + +/* Supported filesystem function vector functions. */ + + +typedef struct { + int code_level; + char fsys_name[16]; + dm_fsys_clear_inherit_t clear_inherit; + dm_fsys_create_by_handle_t create_by_handle; + dm_fsys_downgrade_right_t downgrade_right; + dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp; + dm_fsys_get_bulkall_rvp_t get_bulkall_rvp; + dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp; + dm_fsys_get_config_t get_config; + dm_fsys_get_config_events_t get_config_events; + dm_fsys_get_destroy_dmattr_t get_destroy_dmattr; + dm_fsys_get_dioinfo_t get_dioinfo; + dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp; + dm_fsys_get_dmattr_t get_dmattr; + dm_fsys_get_eventlist_t get_eventlist; + dm_fsys_get_fileattr_t get_fileattr; + dm_fsys_get_region_t get_region; + dm_fsys_getall_dmattr_t getall_dmattr; + dm_fsys_getall_inherit_t getall_inherit; + dm_fsys_init_attrloc_t init_attrloc; + dm_fsys_mkdir_by_handle_t mkdir_by_handle; + dm_fsys_probe_hole_t probe_hole; + dm_fsys_punch_hole_t punch_hole; + dm_fsys_read_invis_rvp_t read_invis_rvp; + dm_fsys_release_right_t release_right; + dm_fsys_remove_dmattr_t remove_dmattr; + dm_fsys_request_right_t request_right; + dm_fsys_set_dmattr_t set_dmattr; + dm_fsys_set_eventlist_t set_eventlist; + dm_fsys_set_fileattr_t set_fileattr; + dm_fsys_set_inherit_t set_inherit; + dm_fsys_set_region_t set_region; + dm_fsys_symlink_by_handle_t symlink_by_handle; + dm_fsys_sync_by_handle_t sync_by_handle; + dm_fsys_upgrade_right_t upgrade_right; + dm_fsys_write_invis_rvp_t write_invis_rvp; + dm_fsys_obj_ref_hold_t obj_ref_hold; +} dm_fsys_vector_t; + + +extern dm_session_t *dm_sessions; /* head of session list */ +extern dm_fsreg_t *dm_registers; +extern lock_t dm_reg_lock; /* lock for registration list */ + +/* + * Kernel only prototypes. + */ + +int dm_find_session_and_lock( + dm_sessid_t sid, + dm_session_t **sessionpp, + unsigned long *lcp); + +int dm_find_msg_and_lock( + dm_sessid_t sid, + dm_token_t token, + dm_tokevent_t **tevpp, + unsigned long *lcp); + +dm_tokevent_t * dm_evt_create_tevp( + dm_eventtype_t event, + int variable_size, + void **msgpp); + +int dm_app_get_tdp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + short types, + dm_right_t right, + dm_tokdata_t **tdpp); + +int dm_get_config_tdp( + void *hanp, + size_t hlen, + dm_tokdata_t **tdpp); + +void dm_app_put_tdp( + dm_tokdata_t *tdp); + +void dm_put_tevp( + dm_tokevent_t *tevp, + dm_tokdata_t *tdp); + +void dm_evt_rele_tevp( + dm_tokevent_t *tevp, + int droprights); + +int dm_enqueue_normal_event( + vfs_t *vfsp, + dm_tokevent_t *tevp, + int flags); + +int dm_enqueue_mount_event( + vfs_t *vfsp, + dm_tokevent_t *tevp); + +int dm_enqueue_sendmsg_event( + dm_sessid_t targetsid, + dm_tokevent_t *tevp, + int synch); + +int dm_enqueue_user_event( + dm_sessid_t sid, + dm_tokevent_t *tevp, + dm_token_t *tokenp); + +int dm_obj_ref_query_rvp( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen, + int *rvp); + +int dm_read_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +int dm_write_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +int dm_get_bulkattr_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp); + +int dm_get_bulkall_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp); + +int dm_get_dirattrs_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp); + +int dm_get_allocinfo_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvp); + +int dm_waitfor_destroy_attrname( + vfs_t *vfsp, + dm_attrname_t *attrnamep); + +void dm_clear_fsreg( + dm_session_t *s); + +int dm_add_fsys_entry( + vfs_t *vfsp, + dm_tokevent_t *tevp); + +void dm_change_fsys_entry( + vfs_t *vfsp, + dm_fsstate_t newstate); + +void dm_remove_fsys_entry( + vfs_t *vfsp); + +dm_fsys_vector_t *dm_fsys_vector( + vnode_t *vp); + +void dm_fsys_vector_free(void); + +int dm_waitfor_disp_session( + vfs_t *vfsp, + dm_tokevent_t *tevp, + dm_session_t **sessionpp, + unsigned long *lcp); + +vnode_t * dm_handle_to_vp ( + xfs_handle_t *handlep, + short *typep); + +int dm_check_dmapi_vp( + vnode_t *vp); + +dm_tokevent_t * dm_find_mount_tevp_and_lock( + fsid_t *fsidp, + unsigned long *lcp); + +int dm_path_to_hdl( + char *path, + void *hanp, + size_t *hlenp); + +int dm_path_to_fshdl( + char *path, + void *hanp, + size_t *hlenp); + +int dm_fd_to_hdl( + int fd, + void *hanp, + size_t *hlenp); + +int dm_upgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +int dm_downgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +int dm_request_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int flags, + dm_right_t right); + +int dm_release_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +int dm_query_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp); + + +int dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent); + +int dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +int dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +int dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp); + + +int dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent); + + +int dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable); + + +int dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +void dm_link_event( + dm_tokevent_t *tevp, + dm_eventq_t *queue); + +void dm_unlink_event( + dm_tokevent_t *tevp, + dm_eventq_t *queue); + +int dm_open_by_handle_rvp( + unsigned int fd, + void *hanp, + size_t hlen, + int mode, + int *rvp); + +int dm_copyin_handle( + void *hanp, + size_t hlen, + xfs_handle_t *handlep); + +#endif /* _DMAPI_PRIVATE_H */ diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_region.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_region.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_region.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_region.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_get_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_region(tdp->td_vp, tdp->td_right, + nelem, regbufp, nelemp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + + +int +dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->set_region(tdp->td_vp, tdp->td_right, + nelem, regbufp, exactflagp); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_register.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_register.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_register.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_register.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1555 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" +#include +#include +#include + +dm_fsreg_t *dm_registers; /* head of filesystem registration list */ +int dm_fsys_cnt; /* number of filesystems on dm_registers list */ +lock_t dm_reg_lock = SPIN_LOCK_UNLOCKED;/* lock for dm_registers */ + + + +#ifdef CONFIG_PROC_FS +static int +fsreg_read_pfs(char *buffer, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len; + int i; + dm_fsreg_t *fsrp = (dm_fsreg_t*)data; + char statebuf[30]; + +#define CHKFULL if(len >= count) break; +#define ADDBUF(a,b) len += sprintf(buffer + len, a, b); CHKFULL; + + switch (fsrp->fr_state) { + case DM_STATE_MOUNTING: sprintf(statebuf, "mounting"); break; + case DM_STATE_MOUNTED: sprintf(statebuf, "mounted"); break; + case DM_STATE_UNMOUNTING: sprintf(statebuf, "unmounting"); break; + case DM_STATE_UNMOUNTED: sprintf(statebuf, "unmounted"); break; + default: + sprintf(statebuf, "unknown:%d", (int)fsrp->fr_state); + break; + } + + len=0; + while(1){ + ADDBUF("fsrp=0x%p\n", fsrp); + ADDBUF("fr_next=0x%p\n", fsrp->fr_next); + ADDBUF("fr_vfsp=0x%p\n", fsrp->fr_vfsp); + ADDBUF("fr_tevp=0x%p\n", fsrp->fr_tevp); + ADDBUF("fr_fsid=%c\n", '?'); + ADDBUF("fr_msg=0x%p\n", fsrp->fr_msg); + ADDBUF("fr_msgsize=%d\n", fsrp->fr_msgsize); + ADDBUF("fr_state=%s\n", statebuf); + ADDBUF("fr_dispq=%c\n", '?'); + ADDBUF("fr_dispcnt=%d\n", fsrp->fr_dispcnt); + + ADDBUF("fr_evt_dispq.eq_head=0x%p\n", fsrp->fr_evt_dispq.eq_head); + ADDBUF("fr_evt_dispq.eq_tail=0x%p\n", fsrp->fr_evt_dispq.eq_tail); + ADDBUF("fr_evt_dispq.eq_count=%d\n", fsrp->fr_evt_dispq.eq_count); + + ADDBUF("fr_queue=%c\n", '?'); + ADDBUF("fr_lock=%c\n", '?'); + ADDBUF("fr_hdlcnt=%d\n", fsrp->fr_hdlcnt); + ADDBUF("fr_vfscnt=%d\n", fsrp->fr_vfscnt); + ADDBUF("fr_unmount=%d\n", fsrp->fr_unmount); + + len += sprintf(buffer + len, "fr_rattr="); + CHKFULL; + for(i = 0; i <= DM_ATTR_NAME_SIZE; ++i){ + ADDBUF("%c", fsrp->fr_rattr.an_chars[i]); + } + CHKFULL; + len += sprintf(buffer + len, "\n"); + CHKFULL; + + for(i = 0; i < DM_EVENT_MAX; i++){ + if( fsrp->fr_sessp[i] != NULL ){ + ADDBUF("fr_sessp[%d]=", i); + ADDBUF("0x%p\n", fsrp->fr_sessp[i]); + } + } + CHKFULL; + + break; + } + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} +#endif + + +/* Returns a pointer to the filesystem structure for the filesystem + referenced by vfsp. The caller is responsible for obtaining dm_reg_lock + before calling this routine. +*/ + +static dm_fsreg_t * +dm_find_fsreg( + fsid_t *fsidp) +{ + dm_fsreg_t *fsrp; + + for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) { + if (!bcmp(&fsrp->fr_fsid, fsidp, sizeof(*fsidp))) + break; + } + return(fsrp); +} + + +/* Given a fsid_t, dm_find_fsreg_and_lock() finds the dm_fsreg_t structure + for that filesytem if one exists, and returns a pointer to the structure + after obtaining its 'fr_lock' so that the caller can safely modify the + dm_fsreg_t. The caller is responsible for releasing 'fr_lock'. +*/ + +static dm_fsreg_t * +dm_find_fsreg_and_lock( + fsid_t *fsidp, + unsigned long *lcp) /* address of returned lock cookie */ +{ + dm_fsreg_t *fsrp; + + for (;;) { + *lcp = mutex_spinlock(&dm_reg_lock); + + if ((fsrp = dm_find_fsreg(fsidp)) == NULL) { + mutex_spinunlock(&dm_reg_lock, *lcp); + return(NULL); + } + if (spin_trylock(&fsrp->fr_lock)) { + nested_spinunlock(&dm_reg_lock); + return(fsrp); /* success */ + } + + /* If the second lock is not available, drop the first and + start over. This gives the CPU a chance to process any + interrupts, and also allows processes which want a fr_lock + for a different filesystem to proceed. + */ + + mutex_spinunlock(&dm_reg_lock, *lcp); + } +} + + +/* dm_add_fsys_entry() is called when a DM_EVENT_MOUNT event is about to be + sent. It creates a dm_fsreg_t structure for the filesystem and stores a + pointer to a copy of the mount event within that structure so that it is + available for subsequent dm_get_mountinfo() calls. +*/ + +int +dm_add_fsys_entry( + vfs_t *vfsp, + dm_tokevent_t *tevp) +{ + dm_fsreg_t *fsrp; + int msgsize; + void *msg; + unsigned long lc; /* lock cookie */ + + /* Allocate and initialize a dm_fsreg_t structure for the filesystem. */ + + msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_event); + msg = kmalloc(msgsize, GFP_KERNEL); + if (msg == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return ENOMEM; + } + bcopy(&tevp->te_event, msg, msgsize); + + fsrp = kmem_cache_alloc(dm_fsreg_cachep, SLAB_KERNEL); + if (fsrp == NULL) { + kfree(msg); + printk("%s/%d: kmem_cache_alloc(dm_fsreg_cachep) returned NULL\n", __FUNCTION__, __LINE__); + return ENOMEM; + } + memset(fsrp, 0, sizeof(*fsrp)); + + fsrp->fr_vfsp = vfsp; + fsrp->fr_tevp = tevp; + fsrp->fr_fsid = *vfsp->vfs_altfsid; + fsrp->fr_msg = msg; + fsrp->fr_msgsize = msgsize; + fsrp->fr_state = DM_STATE_MOUNTING; + sv_init(&fsrp->fr_dispq, SV_DEFAULT, "fr_dispq"); + sv_init(&fsrp->fr_queue, SV_DEFAULT, "fr_queue"); + spinlock_init(&fsrp->fr_lock, "fr_lock"); + + /* If no other mounted DMAPI filesystem already has this same + fsid_t, then add this filesystem to the list. + */ + + lc = mutex_spinlock(&dm_reg_lock); + + if (!dm_find_fsreg(vfsp->vfs_altfsid)) { + fsrp->fr_next = dm_registers; + dm_registers = fsrp; + dm_fsys_cnt++; +#ifdef CONFIG_PROC_FS + { + char buf[100]; + struct proc_dir_entry *entry; + + sprintf(buf, DMAPI_DBG_PROCFS "/fsreg/0x%p", fsrp); + entry = create_proc_read_entry(buf, 0, 0, fsreg_read_pfs, fsrp); + entry->owner = THIS_MODULE; + } +#endif + mutex_spinunlock(&dm_reg_lock, lc); + return(0); + } + + /* A fsid_t collision occurred, so prevent this new filesystem from + mounting. + */ + + mutex_spinunlock(&dm_reg_lock, lc); + + sv_destroy(&fsrp->fr_dispq); + sv_destroy(&fsrp->fr_queue); + spinlock_destroy(&fsrp->fr_lock); + kfree(msg); + kmem_cache_free(dm_fsreg_cachep, fsrp); + return(EBUSY); +} + + +/* dm_change_fsys_entry() is called whenever a filesystem's mount state is + about to change. The state is changed to DM_STATE_MOUNTED after a + successful DM_EVENT_MOUNT event or after a failed unmount. It is changed + to DM_STATE_UNMOUNTING after a successful DM_EVENT_PREUNMOUNT event. + Finally, the state is changed to DM_STATE_UNMOUNTED after a successful + unmount. It stays in this state until the DM_EVENT_UNMOUNT event is + queued, at which point the filesystem entry is removed. +*/ + +void +dm_change_fsys_entry( + vfs_t *vfsp, + dm_fsstate_t newstate) +{ + dm_fsreg_t *fsrp; + int seq_error; + unsigned long lc; /* lock cookie */ + + /* Find the filesystem referenced by the vfsp's fsid_t. This should + always succeed. + */ + + if ((fsrp = dm_find_fsreg_and_lock(vfsp->vfs_altfsid, &lc)) == NULL) { + panic("dm_change_fsys_entry: can't find DMAPI fsrp for " + "vfsp %p\n", vfsp); + } + + /* Make sure that the new state is acceptable given the current state + of the filesystem. Any error here is a major DMAPI/filesystem + screwup. + */ + + seq_error = 0; + switch (newstate) { + case DM_STATE_MOUNTED: + if (fsrp->fr_state != DM_STATE_MOUNTING && + fsrp->fr_state != DM_STATE_UNMOUNTING) { + seq_error++; + } + break; + case DM_STATE_UNMOUNTING: + if (fsrp->fr_state != DM_STATE_MOUNTED) + seq_error++; + break; + case DM_STATE_UNMOUNTED: + if (fsrp->fr_state != DM_STATE_UNMOUNTING) + seq_error++; + break; + default: + seq_error++; + break; + } + if (seq_error) { + panic("dm_change_fsys_entry: DMAPI sequence error: old state " + "%d, new state %d, fsrp %p\n", fsrp->fr_state, + newstate, fsrp); + } + + /* If the old state was DM_STATE_UNMOUNTING, then processes could be + sleeping in dm_handle_to_vp() waiting for their DM_NO_TOKEN handles + to be translated to vnodes. Wake them up so that they either + continue (new state is DM_STATE_MOUNTED) or fail (new state is + DM_STATE_UNMOUNTED). + */ + + if (fsrp->fr_state == DM_STATE_UNMOUNTING) { + if (fsrp->fr_hdlcnt) + sv_broadcast(&fsrp->fr_queue); + } + + /* Change the filesystem's mount state to its new value. */ + + fsrp->fr_state = newstate; + fsrp->fr_tevp = NULL; /* not valid after DM_STATE_MOUNTING */ + + /* If the new state is DM_STATE_UNMOUNTING, wait until any application + threads currently in the process of making VFS_VGET and VFS_ROOT + calls are done before we let this unmount thread continue the + unmount. (We want to make sure that the unmount will see these + vnode references during its scan.) + */ + + if (newstate == DM_STATE_UNMOUNTING) { + while (fsrp->fr_vfscnt) { + fsrp->fr_unmount++; + sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); + lc = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_unmount--; + } + } + + mutex_spinunlock(&fsrp->fr_lock, lc); +} + + +/* dm_remove_fsys_entry() gets called after a failed mount or after an + DM_EVENT_UNMOUNT event has been queued. (The filesystem entry must stay + until the DM_EVENT_UNMOUNT reply is queued so that the event can use the + 'fr_sessp' list to see which session to send the event to.) +*/ + +void +dm_remove_fsys_entry( + vfs_t *vfsp) +{ + dm_fsreg_t **fsrpp; + dm_fsreg_t *fsrp; + unsigned long lc; /* lock cookie */ + + /* Find the filesystem referenced by the vfsp's fsid_t and dequeue + it after verifying that the fr_state shows a filesystem that is + either mounting or unmounted. + */ + + lc = mutex_spinlock(&dm_reg_lock); + + fsrpp = &dm_registers; + while ((fsrp = *fsrpp) != NULL) { + if (!bcmp(&fsrp->fr_fsid, vfsp->vfs_altfsid, sizeof(fsrp->fr_fsid))) + break; + fsrpp = &fsrp->fr_next; + } + if (fsrp == NULL) { + mutex_spinunlock(&dm_reg_lock, lc); + panic("dm_remove_fsys_entry: can't find DMAPI fsrp for " + "vfsp %p\n", vfsp); + } + + nested_spinlock(&fsrp->fr_lock); + + /* Verify that it makes sense to remove this entry. */ + + if (fsrp->fr_state != DM_STATE_MOUNTING && + fsrp->fr_state != DM_STATE_UNMOUNTED) { + nested_spinunlock(&fsrp->fr_lock); + mutex_spinunlock(&dm_reg_lock, lc); + panic("dm_remove_fsys_entry: DMAPI sequence error: old state " + "%d, fsrp %p\n", fsrp->fr_state, fsrp); + } + + *fsrpp = fsrp->fr_next; + dm_fsys_cnt--; + + nested_spinunlock(&dm_reg_lock); + + /* Since the filesystem is about to finish unmounting, we must be sure + that no vnodes are being referenced within the filesystem before we + let this event thread continue. If the filesystem is currently in + state DM_STATE_MOUNTING, then we know by definition that there can't + be any references. If the filesystem is DM_STATE_UNMOUNTED, then + any application threads referencing handles with DM_NO_TOKEN should + have already been awakened by dm_change_fsys_entry and should be + long gone by now. Just in case they haven't yet left, sleep here + until they are really gone. + */ + + while (fsrp->fr_hdlcnt) { + fsrp->fr_unmount++; + sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); + lc = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_unmount--; + } + mutex_spinunlock(&fsrp->fr_lock, lc); + + /* Release all memory. */ + +#ifdef CONFIG_PROC_FS + { + char buf[100]; + sprintf(buf, DMAPI_DBG_PROCFS "/fsreg/0x%p", fsrp); + remove_proc_entry(buf, NULL); + } +#endif + sv_destroy(&fsrp->fr_dispq); + sv_destroy(&fsrp->fr_queue); + spinlock_destroy(&fsrp->fr_lock); + kfree(fsrp->fr_msg); + kmem_cache_free(dm_fsreg_cachep, fsrp); +} + + +/* Get a vnode for the object referenced by handlep. We cannot use + altgetvfs() because it fails if the VFS_OFFLINE bit is set, which means + that any call to dm_handle_to_vp() while a umount is in progress would + return an error, even if the umount can't possibly succeed because users + are in the filesystem. The requests would start to fail as soon as the + umount begins, even before the application receives the DM_EVENT_PREUNMOUNT + event. + + dm_handle_to_vp() emulates the behavior of lookup() while an unmount is + in progress. Any call to dm_handle_to_vp() while the filesystem is in the + DM_STATE_UNMOUNTING state will block. If the unmount eventually succeeds, + the requests will wake up and fail. If the unmount fails, the requests will + wake up and complete normally. + + While a filesystem is in state DM_STATE_MOUNTING, dm_handle_to_vp() will + fail all requests. Per the DMAPI spec, the only handles in the filesystem + which are valid during a mount event are the handles within the event + itself. +*/ + +vnode_t * +dm_handle_to_vp( + xfs_handle_t *handlep, + short *typep) +{ + dm_fsreg_t *fsrp; + vnode_t *vp; + short type; + unsigned long lc; /* lock cookie */ + int error; + fid_t *fidp; + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handlep->ha_fsid, &lc)) == NULL) + return(NULL); + + fidp = (fid_t*)&handlep->ha_fid; + /* If mounting, and we are not asking for a filesystem handle, + * then fail the request. (fid_len==0 for fshandle) + */ + if ((fsrp->fr_state == DM_STATE_MOUNTING) && + (fidp->fid_len != 0)) { + mutex_spinunlock(&fsrp->fr_lock, lc); + return(NULL); + } + + for (;;) { + if (fsrp->fr_state == DM_STATE_MOUNTING) + break; + if (fsrp->fr_state == DM_STATE_MOUNTED) + break; + if (fsrp->fr_state == DM_STATE_UNMOUNTED) { + if (fsrp->fr_unmount && fsrp->fr_hdlcnt == 0) + sv_broadcast(&fsrp->fr_queue); + mutex_spinunlock(&fsrp->fr_lock, lc); + return(NULL); + } + + /* Must be DM_STATE_UNMOUNTING. */ + + fsrp->fr_hdlcnt++; + sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); + lc = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_hdlcnt--; + } + + fsrp->fr_vfscnt++; + mutex_spinunlock(&fsrp->fr_lock, lc); + + /* Now that the mutex is released, wait until we have access to the + vnode. + */ + + if (fidp->fid_len == 0) { /* filesystem handle */ + VFS_ROOT(fsrp->fr_vfsp, &vp, error); + } else { /* file object handle */ + VFS_VGET(fsrp->fr_vfsp, &vp, fidp, error); + } + + lc = mutex_spinlock(&fsrp->fr_lock); + + fsrp->fr_vfscnt--; + if (fsrp->fr_unmount && fsrp->fr_vfscnt == 0) + sv_broadcast(&fsrp->fr_queue); + + mutex_spinunlock(&fsrp->fr_lock, lc); + if (error || vp == NULL) + return(NULL); + + if (fidp->fid_len == 0) { + type = DM_TDT_VFS; + } else if (vp->v_type == VREG) { + type = DM_TDT_REG; + } else if (vp->v_type == VDIR) { + type = DM_TDT_DIR; + } else if (vp->v_type == VLNK) { + type = DM_TDT_LNK; + } else { + type = DM_TDT_OTH; + } + *typep = type; + return(vp); +} + + +int +dm_vp_to_handle( + vnode_t *vp, + xfs_handle_t *handlep) +{ + int error; + struct fid fid; + int hsize; + + if (vp->v_vfsp->vfs_altfsid == NULL) + return(EINVAL); + + VOP_FID2(vp, &fid, error); + if (error) + return(error); + + bcopy (vp->v_vfsp->vfs_altfsid, &handlep->ha_fsid, sizeof(fsid_t)); + bcopy(&fid, &handlep->ha_fid, fid.fid_len + sizeof fid.fid_len); + hsize = XFS_HSIZE(*handlep); + bzero ((char *)handlep + hsize, sizeof(*handlep) - hsize); + return(0); +} + + +/* Given a vnode, check if that vnode resides in filesystem that supports + DMAPI. Returns zero if the vnode is in a DMAPI filesystem, otherwise + returns an errno. +*/ + +int +dm_check_dmapi_vp( + vnode_t *vp) +{ + xfs_handle_t handle; + /* REFERENCED */ + dm_fsreg_t *fsrp; + int error; + unsigned long lc; /* lock cookie */ + + if ((error = dm_vp_to_handle(vp, &handle)) != 0) + return(error); + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + return(0); +} + + +/* Return a pointer to the DM_EVENT_MOUNT event while a mount is still in + progress. This is only called by dm_get_config and dm_get_config_events + which need to access the filesystem during a mount but which don't have + a session and token to use. +*/ + +dm_tokevent_t * +dm_find_mount_tevp_and_lock( + fsid_t *fsidp, + unsigned long *lcp) /* address of returned lock cookie */ +{ + dm_fsreg_t *fsrp; + + if ((fsrp = dm_find_fsreg_and_lock(fsidp, lcp)) == NULL) + return(NULL); + + if (!fsrp->fr_tevp || fsrp->fr_state != DM_STATE_MOUNTING) { + mutex_spinunlock(&fsrp->fr_lock, *lcp); + return(NULL); + } + nested_spinlock(&fsrp->fr_tevp->te_lock); + nested_spinunlock(&fsrp->fr_lock); + return(fsrp->fr_tevp); +} + + +/* Wait interruptibly until a session registers disposition for 'event' in + filesystem 'vfsp'. Upon successful exit, both the filesystem's dm_fsreg_t + structure and the session's dm_session_t structure are locked. The caller + is responsible for unlocking both structures using the returned cookies. + + Warning: The locks can be dropped in any order, but the 'lc2p' cookie MUST + BE USED FOR THE FIRST UNLOCK, and the lc1p cookie must be used for the + second unlock. If this is not done, the CPU will be interruptible while + holding a mutex, which could deadlock the machine! +*/ + +static int +dm_waitfor_disp( + vfs_t *vfsp, + dm_tokevent_t *tevp, + dm_fsreg_t **fsrpp, + unsigned long *lc1p, /* addr of first returned lock cookie */ + dm_session_t **sessionpp, + unsigned long *lc2p) /* addr of 2nd returned lock cookie */ +{ + dm_eventtype_t event = tevp->te_msg.ev_type; + dm_session_t *s; + dm_fsreg_t *fsrp; + + if ((fsrp = dm_find_fsreg_and_lock(vfsp->vfs_altfsid, lc1p)) == NULL) + return(ENOENT); + + /* If no session is registered for this event in the specified + filesystem, then sleep interruptibly until one does. + */ + + for (;;) { + int rc = 0; + + /* The dm_find_session_and_lock() call is needed because a + session that is in the process of being removed might still + be in the dm_fsreg_t structure but won't be in the + dm_sessions list. + */ + + if ((s = fsrp->fr_sessp[event]) != NULL && + dm_find_session_and_lock(s->sn_sessid, &s, lc2p) == 0) { + break; + } + + /* Noone is currently registered. DM_EVENT_UNMOUNT events + don't wait for anyone to register because the unmount is + already past the point of no return. + */ + + if (event == DM_EVENT_UNMOUNT) { + mutex_spinunlock(&fsrp->fr_lock, *lc1p); + return(ENOENT); + } + + /* Wait until a session registers for disposition of this + event. + */ + + fsrp->fr_dispcnt++; + dm_link_event(tevp, &fsrp->fr_evt_dispq); + + sv_wait_sig(&fsrp->fr_dispq, 1, &fsrp->fr_lock, *lc1p); + rc = signal_pending(current); + + *lc1p = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_dispcnt--; + dm_unlink_event(tevp, &fsrp->fr_evt_dispq); + if (rc) { /* if signal was received */ + mutex_spinunlock(&fsrp->fr_lock, *lc1p); + return(EINTR); + } + } + *sessionpp = s; + *fsrpp = fsrp; + return(0); +} + + +/* Returns the session pointer for the session registered for an event + in the given vfsp. If successful, the session is locked upon return. The + caller is responsible for releasing the lock. If no session is currently + registered for the event, dm_waitfor_disp_session() will sleep interruptibly + until a registration occurs. +*/ + +int +dm_waitfor_disp_session( + vfs_t *vfsp, + dm_tokevent_t *tevp, + dm_session_t **sessionpp, + unsigned long *lcp) +{ + dm_fsreg_t *fsrp; + unsigned long lc2; + int error; + + if (tevp->te_msg.ev_type < 0 || tevp->te_msg.ev_type > DM_EVENT_MAX) + return(EIO); + + error = dm_waitfor_disp(vfsp, tevp, &fsrp, lcp, sessionpp, &lc2); + if (!error) + mutex_spinunlock(&fsrp->fr_lock, lc2); /* rev. cookie order*/ + return(error); +} + + +/* Find the session registered for the DM_EVENT_DESTROY event on the specified + filesystem, sleeping if necessary until registration occurs. Once found, + copy the session's return-on-destroy attribute name, if any, back to the + caller. +*/ + +int +dm_waitfor_destroy_attrname( + vfs_t *vfsp, + dm_attrname_t *attrnamep) +{ + dm_tokevent_t *tevp; + dm_session_t *s; + dm_fsreg_t *fsrp; + int error; + unsigned long lc1; /* first lock cookie */ + unsigned long lc2; /* second lock cookie */ + void *msgp; + + tevp = dm_evt_create_tevp(DM_EVENT_DESTROY, 1, (void**)&msgp); + error = dm_waitfor_disp(vfsp, tevp, &fsrp, &lc1, &s, &lc2); + if (!error) { + *attrnamep = fsrp->fr_rattr; /* attribute or zeros */ + mutex_spinunlock(&s->sn_qlock, lc2); /* rev. cookie order */ + mutex_spinunlock(&fsrp->fr_lock, lc1); + } + dm_evt_rele_tevp(tevp,0); + return(error); +} + + +/* Unregisters the session for the disposition of all events on all + filesystems. This routine is not called until the session has been + dequeued from the session list and its session lock has been dropped, + but before the actual structure is freed, so it is safe to grab the + 'dm_reg_lock' here. If dm_waitfor_disp_session() happens to be called + by another thread, it won't find this session on the session list and + will wait until a new session registers. +*/ + +void +dm_clear_fsreg( + dm_session_t *s) +{ + dm_fsreg_t *fsrp; + int event; + unsigned long lc; /* lock cookie */ + + lc = mutex_spinlock(&dm_reg_lock); + + for (fsrp = dm_registers; fsrp != NULL; fsrp = fsrp->fr_next) { + nested_spinlock(&fsrp->fr_lock); + for (event = 0; event < DM_EVENT_MAX; event++) { + if (fsrp->fr_sessp[event] != s) + continue; + fsrp->fr_sessp[event] = NULL; + if (event == DM_EVENT_DESTROY) + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + } + nested_spinunlock(&fsrp->fr_lock); + } + + mutex_spinunlock(&dm_reg_lock, lc); +} + + +/* + * Return the handle for the object named by path. + */ + +int +dm_path_to_hdl( + char *path, /* any path name */ + void *hanp, /* user's data buffer */ + size_t *hlenp) /* set to size of data copied */ +{ + /* REFERENCED */ + dm_fsreg_t *fsrp; + xfs_handle_t handle; + vnode_t *vp; + size_t hlen; + int error; + unsigned long lc; /* lock cookie */ + struct nameidata nd; + struct inode *inode; + size_t len; + char *name; + + /* XXX get things straightened out so getname() works here? */ + len = strnlen_user(path, 2000); + name = kmalloc(len, GFP_KERNEL); + if (name == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return(ENOMEM); + } + if (copy_from_user(name, path, len)) { + kfree(name); + return(EFAULT); + } + + error = 0; + if (path_init(name, LOOKUP_POSITIVE, &nd)) + error = path_walk(name, &nd); + kfree(name); + if (error) + return error; + + ASSERT(nd.dentry); + ASSERT(nd.dentry->d_inode); + inode = igrab(nd.dentry->d_inode); + path_release(&nd); + + if (inode->i_sb->s_magic != XFS_SB_MAGIC) { + /* we're not in XFS anymore, Toto */ + iput(inode); + return EINVAL; + } + + /* we need the vnode */ + vp = LINVFS_GET_VP(inode); + error = dm_vp_to_handle(vp, &handle); + iput(inode); + if (error) + return(error); + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + + hlen = XFS_HSIZE(handle); + + if (copy_to_user(hanp, &handle, (int)hlen)) + return(EFAULT); + return(put_user(hlen,hlenp)); +} + + +/* + * Return the handle for the file system containing the object named by path. + */ + +int +dm_path_to_fshdl( + char *path, /* any path name */ + void *hanp, /* user's data buffer */ + size_t *hlenp) /* set to size of data copied */ +{ + /* REFERENCED */ + dm_fsreg_t *fsrp; + xfs_handle_t handle; + vnode_t *vp; + size_t hlen; + int error; + unsigned long lc; /* lock cookie */ + struct nameidata nd; + struct inode *inode; + size_t len; + char *name; + + /* XXX get things straightened out so getname() works here? */ + len = strnlen_user(path, 2000); + name = kmalloc(len, GFP_KERNEL); + if (name == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return(ENOMEM); + } + if (copy_from_user(name, path, len)) { + kfree(name); + return(EFAULT); + } + + error = 0; + if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd)) + error = path_walk(name, &nd); + kfree(name); + if (error) + return error; + + ASSERT(nd.dentry); + ASSERT(nd.dentry->d_inode); + + inode = igrab(nd.dentry->d_inode); + path_release(&nd); + + if (inode->i_sb->s_magic != XFS_SB_MAGIC) { + /* we're not in XFS anymore, Toto */ + iput(inode); + return EINVAL; + } + + /* we need the vnode */ + vp = LINVFS_GET_VP(inode); + error = dm_vp_to_handle(vp, &handle); + iput(inode); + + if (error) + return(error); + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + + hlen = FSHSIZE; + if(copy_to_user(hanp, &handle, (int)hlen)) + return(EFAULT); + return(put_user(hlen,hlenp)); +} + + +int +dm_fd_to_hdl( + int fd, /* any file descriptor */ + void *hanp, /* user's data buffer */ + size_t *hlenp) /* set to size of data copied */ +{ + /* REFERENCED */ + dm_fsreg_t *fsrp; + xfs_handle_t handle; + size_t hlen; + int error; + unsigned long lc; /* lock cookie */ + struct file *filep = fget(fd); + + if (!filep) + return(EBADF); + if ((error = dm_vp_to_handle(LINVFS_GET_VP(filep->f_dentry->d_inode), &handle)) != 0) + return(error); + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + + hlen = XFS_HSIZE(handle); + if (copy_to_user(hanp, &handle, (int)hlen)) + return(EFAULT); + fput(filep); + return(put_user(hlen, hlenp)); +} + + +/* Enable events on an object. */ + +int +dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent) +{ + dm_fsys_vector_t *fsys_vector; + dm_eventset_t eventset; + dm_tokdata_t *tdp; + int error; + + if (copy_from_user(&eventset, eventsetp, sizeof(eventset))) + return(EFAULT); + + /* Do some minor sanity checking. */ + + if (maxevent == 0 || maxevent > DM_EVENT_MAX) + return(EINVAL); + + /* Access the specified object. */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->set_eventlist(tdp->td_vp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), + &eventset, maxevent); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* Return the list of enabled events for an object. */ + +int +dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + dm_eventset_t eventset; + u_int elem; + int error; + + if (nelem == 0) + return(EINVAL); + + /* Access the specified object. */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + /* Get the object's event list. */ + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->get_eventlist(tdp->td_vp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), + nelem, &eventset, &elem); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + dm_app_put_tdp(tdp); + + if (error) + return(error); + + if (copy_to_user(eventsetp, &eventset, sizeof(eventset))) + return(EFAULT); + if (put_user(nelem, nelemp)) + return(EFAULT); + return(0); +} + + +/* Register for disposition of events. The handle must either be the + global handle or must be the handle of a file system. The list of events + is pointed to by eventsetp. +*/ + +int +dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent) +{ + dm_session_t *s; + dm_fsreg_t *fsrp; + dm_tokdata_t *tdp; + dm_eventset_t eventset; + int error; + unsigned long lc1; /* first lock cookie */ + unsigned long lc2; /* second lock cookie */ + u_int i; + + /* Copy in and validate the event mask. Only the lower maxevent bits + are meaningful, so clear any bits set above maxevent. + */ + + if (maxevent == 0 || maxevent > DM_EVENT_MAX) + return(EINVAL); + if (copy_from_user(&eventset, eventsetp, sizeof(eventset))) + return(EFAULT); + eventset &= (1 << maxevent) - 1; + + /* If the caller specified the global handle, then the only valid token + is DM_NO_TOKEN, and the only valid event in the event mask is + DM_EVENT_MOUNT. If it is set, add the session to the list of + sessions that want to receive mount events. If it is clear, remove + the session from the list. Since DM_EVENT_MOUNT events never block + waiting for a session to register, there is noone to wake up if we + do add the session to the list. + */ + + if (DM_GLOBALHAN(hanp, hlen)) { + if (token != DM_NO_TOKEN) + return(EINVAL); + if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0) + return(error); + if (eventset == 0) { + s->sn_flags &= ~DM_SN_WANTMOUNT; + error = 0; + } else if (eventset == 1 << DM_EVENT_MOUNT) { + s->sn_flags |= DM_SN_WANTMOUNT; + error = 0; + } else { + error = EINVAL; + } + mutex_spinunlock(&s->sn_qlock, lc1); + return(error); + } + + /* Since it's not the global handle, it had better be a filesystem + handle. Verify that the first 'maxevent' events in the event list + are all valid for a filesystem handle. + */ + + if (eventset & ~DM_VALID_DISP_EVENTS) + return(EINVAL); + + /* Verify that the session is valid, that the handle is a filesystem + handle, and that the filesystem is capable of sending events. (If + a dm_fsreg_t structure exists, then the filesystem can issue events.) + */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsrp = dm_find_fsreg_and_lock((fsid_t*)&tdp->td_handle.ha_fsid, &lc1); + if (fsrp == NULL) { + dm_app_put_tdp(tdp); + return(EINVAL); + } + + /* Now that we own 'fsrp->fr_lock', get the lock on the session so that + it can't disappear while we add it to the filesystem's event mask. + */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { + mutex_spinunlock(&fsrp->fr_lock, lc1); + dm_app_put_tdp(tdp); + return(error); + } + + /* Update the event disposition array for this filesystem, adding + and/or removing the session as appropriate. If this session is + dropping registration for DM_EVENT_DESTROY, or is overriding some + other session's registration for DM_EVENT_DESTROY, then clear any + any attr-on-destroy attribute name also. + */ + + for (i = 0; i < DM_EVENT_MAX; i++) { + if (DMEV_ISSET(i, eventset)) { + if (i == DM_EVENT_DESTROY && fsrp->fr_sessp[i] != s) + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + fsrp->fr_sessp[i] = s; + } else if (fsrp->fr_sessp[i] == s) { + if (i == DM_EVENT_DESTROY) + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + fsrp->fr_sessp[i] = NULL; + } + } + mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ + + /* Wake up all processes waiting for a disposition on this filesystem + in case any of them happen to be waiting for an event which we just + added. + */ + + if (fsrp->fr_dispcnt) + sv_broadcast(&fsrp->fr_dispq); + + mutex_spinunlock(&fsrp->fr_lock, lc1); + + dm_app_put_tdp(tdp); + return(0); +} + + +/* + * Register a specific attribute name with a filesystem. The value of + * the attribute is to be returned with an asynchronous destroy event. + */ + +int +dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable) +{ + dm_attrname_t attrname; + dm_tokdata_t *tdp; + dm_fsreg_t *fsrp; + dm_session_t *s; + int error; + unsigned long lc1; /* first lock cookie */ + unsigned long lc2; /* second lock cookie */ + + /* If a dm_attrname_t is provided, copy it in and validate it. */ + + if (enable && (error = copy_from_user(&attrname, attrnamep, sizeof(attrname))) != 0) + return(error); + + /* Validate the filesystem handle and use it to get the filesystem's + disposition structure. + */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsrp = dm_find_fsreg_and_lock((fsid_t*)&tdp->td_handle.ha_fsid, &lc1); + if (fsrp == NULL) { + dm_app_put_tdp(tdp); + return(EINVAL); + } + + /* Now that we own 'fsrp->fr_lock', get the lock on the session so that + it can't disappear while we add it to the filesystem's event mask. + */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { + mutex_spinunlock(&fsrp->fr_lock, lc1); + dm_app_put_tdp(tdp); + return(error); + } + + /* A caller cannot disable return-on-destroy if he is not registered + for DM_EVENT_DESTROY. Enabling return-on-destroy is an implicit + dm_set_disp() for DM_EVENT_DESTROY; we wake up all processes + waiting for a disposition in case any was waiting for a + DM_EVENT_DESTROY event. + */ + + error = 0; + if (enable) { + fsrp->fr_sessp[DM_EVENT_DESTROY] = s; + fsrp->fr_rattr = attrname; + if (fsrp->fr_dispcnt) + sv_broadcast(&fsrp->fr_dispq); + } else if (fsrp->fr_sessp[DM_EVENT_DESTROY] != s) { + error = EINVAL; + } else { + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + } + mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ + mutex_spinunlock(&fsrp->fr_lock, lc1); + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_fsreg_t *fsrp; + dm_tokdata_t *tdp; + int error; + unsigned long lc; /* lock cookie */ + + /* Make sure that the caller's buffer is 8-byte aligned. */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Verify that the handle is a filesystem handle, and that the + filesystem is capable of sending events. If not, return an error. + */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + /* Find the filesystem entry. This should always succeed as the + dm_app_get_tdp call created a filesystem reference. Once we find + the entry, drop the lock. The mountinfo message is never modified, + the filesystem entry can't disappear, and we don't want to hold a + spinlock while doing copyout calls. + */ + + fsrp = dm_find_fsreg_and_lock((fsid_t*)&tdp->td_handle.ha_fsid, &lc); + if (fsrp == NULL) { + dm_app_put_tdp(tdp); + return(EINVAL); + } + mutex_spinunlock(&fsrp->fr_lock, lc); + + /* Copy the message into the user's buffer and update his 'rlenp'. */ + + if (put_user(fsrp->fr_msgsize, rlenp)) { + error = EFAULT; + } else if (fsrp->fr_msgsize > buflen) { /* user buffer not big enough */ + error = E2BIG; + } else if (copy_to_user(bufp, fsrp->fr_msg, fsrp->fr_msgsize)) { + error = EFAULT; + } else { + error = 0; + } + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_session_t *s; /* pointer to session given by sid */ + unsigned long lc1; /* first lock cookie */ + unsigned long lc2; /* second lock cookie */ + int totalsize; + int msgsize; + int fsyscnt; + dm_dispinfo_t *prevmsg; + dm_fsreg_t *fsrp; + int error; + char *kbuf; + + int tmp3; + int tmp4; + + /* Because the dm_getall_disp structure contains a __u64 field, + make sure that the buffer provided by the caller is aligned so + that he can read such fields successfully. + */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Compute the size of a dm_dispinfo structure, rounding up to an + 8-byte boundary so that any subsequent structures will also be + aligned. + */ + +#if 0 + /* XXX ug, what is going on here? */ + msgsize = (sizeof(dm_dispinfo_t) + FSHSIZE + sizeof(uint64_t) - 1) & + ~(sizeof(uint64_t) - 1); +#else + tmp3 = sizeof(dm_dispinfo_t) + FSHSIZE; + tmp3 += sizeof(__u64); + tmp3 -= 1; + tmp4 = ~(sizeof(__u64) - 1); + msgsize = tmp3 & tmp4; +#endif + + /* Loop until we can get the right amount of temp space, being careful + not to hold a mutex during the allocation. Usually only one trip. + */ + + for (;;) { + if ((fsyscnt = dm_fsys_cnt) == 0) { + /*if (dm_cpoutsizet(rlenp, 0))*/ + if (put_user(0,rlenp)) + return(EFAULT); + return(0); + } + kbuf = kmalloc(fsyscnt * msgsize, GFP_KERNEL); + if (kbuf == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return ENOMEM; + } + + lc1 = mutex_spinlock(&dm_reg_lock); + if (fsyscnt == dm_fsys_cnt) + break; + + mutex_spinunlock(&dm_reg_lock, lc1); + kfree(kbuf); + } + + /* Find the indicated session and lock it. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { + mutex_spinunlock(&dm_reg_lock, lc1); + kfree(kbuf); + return(error); + } + + /* Create a dm_dispinfo structure for each filesystem in which + this session has at least one event selected for disposition. + */ + + totalsize = 0; /* total bytes to transfer to the user */ + prevmsg = NULL; + + for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) { + dm_dispinfo_t *disp; + int event; + int found; + + disp = (dm_dispinfo_t *)(kbuf + totalsize); + + DMEV_ZERO(disp->di_eventset); + + for (event = 0, found = 0; event < DM_EVENT_MAX; event++) { + if (fsrp->fr_sessp[event] != s) + continue; + DMEV_SET(event, disp->di_eventset); + found++; + } + if (!found) + continue; + + disp->_link = 0; + disp->di_fshandle.vd_offset = sizeof(dm_dispinfo_t); + disp->di_fshandle.vd_length = FSHSIZE; + + bcopy(&fsrp->fr_fsid, + (char *)disp + disp->di_fshandle.vd_offset, + disp->di_fshandle.vd_length); + + if (prevmsg) + prevmsg->_link = msgsize; + + prevmsg = disp; + totalsize += msgsize; + } + mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ + mutex_spinunlock(&dm_reg_lock, lc1); + + if (put_user(totalsize, rlenp)) { + error = EFAULT; + } else if (totalsize > buflen) { /* no more room */ + error = E2BIG; + } else if (totalsize && copy_to_user(bufp, kbuf, totalsize)) { + error = EFAULT; + } else { + error = 0; + } + + kfree(kbuf); + return(error); +} + +int +dm_open_by_handle_rvp( + unsigned int fd, + void *hanp, + size_t hlen, + int flags, + int *rvp) +{ + xfs_handle_t handle; + int error; + vnode_t *vp; + short td_type; + struct dentry *dentry; + struct inode *inodep; + int new_fd; + struct file *mfilp; + struct file *filp; + struct list_head *lp; + + if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) { + return(error); + } + + if ((vp = dm_handle_to_vp(&handle, &td_type)) == NULL) { + return(EBADF); + } + inodep = LINVFS_GET_IP(vp); + if ((td_type == DM_TDT_VFS) || (td_type == DM_TDT_OTH)) { + iput(inodep); + return(EBADF); + } + + if ((new_fd = get_unused_fd()) < 0) { + iput(inodep); + return(EMFILE); + } + + /* Now to find a dentry. If possible, get a well-connected one. */ + spin_lock(&dcache_lock); + for (lp = inodep->i_dentry.next; lp != &inodep->i_dentry ; lp=lp->next) { + dentry = list_entry(lp,struct dentry, d_alias); + if (! (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) { + dget_locked(dentry); + dentry->d_vfs_flags |= DCACHE_REFERENCED; + spin_unlock(&dcache_lock); + iput(inodep); + goto found; + } + } + spin_unlock(&dcache_lock); + + /* ELSE didn't find dentry. Create anonymous dcache entry. */ + dentry = d_alloc_root(inodep); + if (dentry == NULL) { + iput(inodep); + put_unused_fd(new_fd); + return(ENOMEM); + } + /* keep nfsd happy. */ + dentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + +found: + + if( inodep->i_ino != dentry->d_inode->i_ino ){ + dput(dentry); + put_unused_fd(new_fd); + return(EINVAL); + } + + mfilp = fget(fd); + if (!mfilp) { + dput(dentry); + put_unused_fd(new_fd); + return(EBADF); + } + + mntget(mfilp->f_vfsmnt); + + /* Create file pointer */ + filp = dentry_open(dentry, mfilp->f_vfsmnt, flags); + if (IS_ERR(filp)) { + put_unused_fd(new_fd); + fput(mfilp); + return -PTR_ERR(filp); + } + + if (td_type == DM_TDT_REG) + filp->f_mode |= FINVIS; + fd_install(new_fd, filp); + fput(mfilp); + *rvp = new_fd; + return 0; +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_right.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_right.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_right.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_right.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1268 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +#define DM_FG_STHREAD 0x001 /* keep other threads from using tdp */ +#define DM_FG_MUSTEXIST 0x002 /* handle must exist in the event */ +#define DM_FG_DONTADD 0x004 /* don't add handle if not in event */ + +/* Get a handle of the form (void *, size_t) from user space and convert it to + a handle_t. Do as much validation of the result as possible; any error + other than a bad address should return EBADF per the DMAPI spec. +*/ + +int +dm_copyin_handle( + void *hanp, /* input, handle data */ + size_t hlen, /* input, size of handle data */ + xfs_handle_t *handlep) /* output, copy of data */ +{ + u_short len; + fid_t *fidp; + + fidp = (fid_t*)&handlep->ha_fid; + + if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) + return(EBADF); + + if (copy_from_user(handlep, hanp, hlen)) + return(EFAULT); + + if (hlen < sizeof(*handlep)) + bzero((char *)handlep + hlen, sizeof(*handlep) - hlen); + + if (hlen == sizeof(handlep->ha_fsid)) + return(0); /* FS handle, nothing more to check */ + + len = hlen - sizeof(handlep->ha_fsid) - sizeof(fidp->fid_len); + + if (fidp->fid_len != len || + *((short *) fidp->fid_data)) { + return(EBADF); + } + return(0); +} + +/* Allocate and initialize a tevp structure. Called from both application and + event threads. +*/ + +static dm_tokevent_t * +dm_init_tevp( + int ev_size, /* size of event structure */ + int var_size) /* size of variable-length data */ +{ + dm_tokevent_t *tevp; + int msgsize; + + /* Calculate the size of the event in bytes and allocate memory for it. + Zero all but the variable portion of the message, which will be + eventually overlaid by the caller with data. + */ + + msgsize = offsetof(dm_tokevent_t, te_event) + ev_size + var_size; + tevp = kmalloc(msgsize, GFP_KERNEL); + if (tevp == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return NULL; + } + bzero(tevp, msgsize - var_size); + + /* Now initialize all the non-zero fields. */ + + spinlock_init(&tevp->te_lock, "te_lock"); + sv_init(&tevp->te_evt_queue, SV_DEFAULT, "te_evt_queue"); + sv_init(&tevp->te_app_queue, SV_DEFAULT, "te_app_queue"); + tevp->te_allocsize = msgsize; + tevp->te_msg.ev_type = DM_EVENT_INVALID; + tevp->te_flags = 0; + + return(tevp); +} + + +/* Given the event type and the number of bytes of variable length data that + will follow the event, dm_evt_create_tevp() creates a dm_tokevent_t + structure to hold the event and initializes all the common event fields. + + No locking is required for this routine because the caller is an event + thread, and is therefore the only thread that can see the event. +*/ + +dm_tokevent_t * +dm_evt_create_tevp( + dm_eventtype_t event, + int variable_size, + void **msgpp) +{ + dm_tokevent_t *tevp; + int evsize; + + switch (event) { + case DM_EVENT_READ: + case DM_EVENT_WRITE: + case DM_EVENT_TRUNCATE: + evsize = sizeof(dm_data_event_t); + break; + + case DM_EVENT_DESTROY: + evsize = sizeof(dm_destroy_event_t); + break; + + case DM_EVENT_MOUNT: + evsize = sizeof(dm_mount_event_t); + break; + + case DM_EVENT_PREUNMOUNT: + case DM_EVENT_UNMOUNT: + case DM_EVENT_NOSPACE: + case DM_EVENT_CREATE: + case DM_EVENT_REMOVE: + case DM_EVENT_RENAME: + case DM_EVENT_SYMLINK: + case DM_EVENT_LINK: + case DM_EVENT_POSTCREATE: + case DM_EVENT_POSTREMOVE: + case DM_EVENT_POSTRENAME: + case DM_EVENT_POSTSYMLINK: + case DM_EVENT_POSTLINK: + case DM_EVENT_ATTRIBUTE: + case DM_EVENT_DEBUT: /* currently not supported */ + case DM_EVENT_CLOSE: /* currently not supported */ + evsize = sizeof(dm_namesp_event_t); + break; + + case DM_EVENT_CANCEL: /* currently not supported */ + evsize = sizeof(dm_cancel_event_t); + break; + + case DM_EVENT_USER: + evsize = 0; + break; + + default: + panic("dm_create_tevp: called with unknown event type %d\n", + event); + } + + /* Allocate and initialize an event structure of the correct size. */ + + tevp = dm_init_tevp(evsize, variable_size); + if (tevp == NULL) + return NULL; + tevp->te_evt_ref = 1; + + /* Fields ev_token, ev_sequence, and _link are all filled in when the + event is queued onto a session. Initialize all other fields here. + */ + + tevp->te_msg.ev_type = event; + tevp->te_msg.ev_data.vd_offset = offsetof(dm_tokevent_t, te_event) - + offsetof(dm_tokevent_t, te_msg); + tevp->te_msg.ev_data.vd_length = evsize + variable_size; + + /* Give the caller a pointer to the event-specific structure. */ + + *msgpp = ((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset); + return(tevp); +} + + +/* Given a pointer to an event (tevp) and a pointer to a handle_t, look for a + tdp structure within the event which contains the handle_t. Either verify + that the event contains the tdp, or optionally add the tdp to the + event. Called only from application threads. + + On entry, tevp->te_lock is held; it is dropped prior to return. +*/ + +static int +dm_app_lookup_tdp( + xfs_handle_t *handlep, /* the handle we are looking for */ + dm_tokevent_t *tevp, /* the event to search for the handle */ + unsigned long *lcp, /* address of active lock cookie */ + short types, /* acceptable object types */ + dm_right_t right, /* minimum right the object must have */ + u_int flags, + dm_tokdata_t **tdpp) /* if ! NULL, pointer to matching tdp */ +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + vnode_t *vp; + int error; + + /* Bump the tevp application reference counter so that the event + can't disappear in case we have to drop the lock for a while. + */ + + tevp->te_app_ref++; + *tdpp = NULL; /* assume failure */ + + for (;;) { + /* Look for a matching tdp in the tevp. */ + + for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { + if (XFS_HANDLE_CMP(&tdp->td_handle, handlep) == 0) + break; + } + + /* If the tdp exists, but either we need single-thread access + to the handle and can't get it, or some other thread already + has single-thread access, then sleep until we can try again. + */ + + if (tdp != NULL && tdp->td_app_ref && + ((flags & DM_FG_STHREAD) || + (tdp->td_flags & DM_TDF_STHREAD))) { + tevp->te_app_slp++; + sv_wait(&tevp->te_app_queue, 1, + &tevp->te_lock, *lcp); + *lcp = mutex_spinlock(&tevp->te_lock); + tevp->te_app_slp--; + continue; + } + + if (tdp != NULL && + (tdp->td_vcount > 0 || tdp->td_flags & DM_TDF_EVTREF)) { + /* We have an existing tdp with a non-zero vnode + reference count. If it's the wrong type, return + an appropriate errno. + */ + + if (!(tdp->td_type & types)) { + mutex_spinunlock(&tevp->te_lock, *lcp); + dm_put_tevp(tevp, NULL); /* no destroy events */ + return(EOPNOTSUPP); + } + + /* If the current access right isn't high enough, + complain. + */ + + if (tdp->td_right < right) { + mutex_spinunlock(&tevp->te_lock, *lcp); + dm_put_tevp(tevp, NULL); /* no destroy events */ + return(EACCES); + } + + /* The handle is acceptable. Increment the tdp + application and vnode references and mark the tdp + as single-threaded if necessary. + */ + + tdp->td_app_ref++; + if (flags & DM_FG_STHREAD) + tdp->td_flags |= DM_TDF_STHREAD; + tdp->td_vcount++; + + fsys_vector = dm_fsys_vector(tdp->td_vp); + (void)fsys_vector->obj_ref_hold(tdp->td_vp); + + mutex_spinunlock(&tevp->te_lock, *lcp); + *tdpp = tdp; + return(0); + } + + /* If the tdp is not in the tevp or does not have a vnode + reference, check to make sure it is okay to add/update it. + */ + + if (flags & DM_FG_MUSTEXIST) { + mutex_spinunlock(&tevp->te_lock, *lcp); + dm_put_tevp(tevp, NULL); /* no destroy events */ + return(EACCES); /* i.e. an insufficient right */ + } + if (flags & DM_FG_DONTADD) { + tevp->te_app_ref--; + mutex_spinunlock(&tevp->te_lock, *lcp); + return(0); + } + + /* If a tdp structure doesn't yet exist, create one and link + it into the tevp. Drop the lock while we are doing this as + zallocs can go to sleep. Once we have the memory, make + sure that another thread didn't simultaneously add the same + handle to the same event. If so, toss ours and start over. + */ + + if (tdp == NULL) { + dm_tokdata_t *tmp; + + mutex_spinunlock(&tevp->te_lock, *lcp); + + tdp = kmem_cache_alloc(dm_tokdata_cachep, SLAB_KERNEL); + if (tdp == NULL){ + printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__); + return(ENOMEM); + } + memset(tdp, 0, sizeof(*tdp)); + + *lcp = mutex_spinlock(&tevp->te_lock); + + for (tmp = tevp->te_tdp; tmp; tmp = tmp->td_next) { + if (XFS_HANDLE_CMP(&tmp->td_handle, handlep) == 0) + break; + } + if (tmp) { + kmem_cache_free(dm_tokdata_cachep, tdp); + continue; + } + + tdp->td_next = tevp->te_tdp; + tevp->te_tdp = tdp; + tdp->td_tevp = tevp; + tdp->td_handle = *handlep; + } + + /* Temporarily single-thread access to the tdp so that other + threads don't touch it while we are filling the rest of the + fields in. + */ + + tdp->td_app_ref = 1; + tdp->td_flags |= DM_TDF_STHREAD; + + /* Drop the spinlock while we access, validate, and obtain the + proper rights to the object. This can take a very long time + if the vnode is not in memory, if the filesystem is + unmounting, or if the request_right() call should block + because some other tdp or kernel thread is holding a right. + */ + + mutex_spinunlock(&tevp->te_lock, *lcp); + + if ((vp = dm_handle_to_vp(handlep, &tdp->td_type)) == NULL) { + error = EBADF; + } else { + tdp->td_vcount = 1; + tdp->td_vp = vp; + + /* The handle is usable. Check that the type of the + object matches one of the types that the caller + will accept. + */ + + if (!(types & tdp->td_type)) { + error = EOPNOTSUPP; + } else if (right > DM_RIGHT_NULL) { + /* Attempt to get the rights required by the + caller. If rights can't be obtained, return + an error. + */ + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->request_right(tdp->td_vp, + DM_RIGHT_NULL, + (tdp->td_type == DM_TDT_VFS ? + DM_FSYS_OBJ : 0), + DM_RR_WAIT, right); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + if (!error) { + tdp->td_right = right; + } + } else { + error = 0; + } + } + if (error != 0) { + dm_put_tevp(tevp, tdp); /* destroy event risk, although tiny */ + return(error); + } + + *lcp = mutex_spinlock(&tevp->te_lock); + + /* Wake up any threads which may have seen our tdp while we + were filling it in. + */ + + if (!(flags & DM_FG_STHREAD)) { + tdp->td_flags &= ~DM_TDF_STHREAD; + if (tevp->te_app_slp) + sv_broadcast(&tevp->te_app_queue); + } + + mutex_spinunlock(&tevp->te_lock, *lcp); + *tdpp = tdp; + return(0); + } +} + + +/* dm_app_get_tdp_by_token() is called whenever the application request + contains a session ID and contains a token other than DM_NO_TOKEN. + Most of the callers provide a right that is either DM_RIGHT_SHARED or + DM_RIGHT_EXCL, but a few of the callers such as dm_obj_ref_hold() may + specify a right of DM_RIGHT_NULL. +*/ + +static int +dm_app_get_tdp_by_token( + dm_sessid_t sid, /* an existing session ID */ + void *hanp, + size_t hlen, + dm_token_t token, /* an existing token */ + short types, /* acceptable object types */ + dm_right_t right, /* minimum right the object must have */ + u_int flags, + dm_tokdata_t **tdpp) +{ + dm_tokevent_t *tevp; + xfs_handle_t handle; + int error; + unsigned long lc; /* lock cookie */ + + if (right < DM_RIGHT_NULL || right > DM_RIGHT_EXCL) + return(EINVAL); + + if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) + return(error); + + /* Find and lock the event which corresponds to the specified + session/token pair. + */ + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) + return(error); + + return(dm_app_lookup_tdp(&handle, tevp, &lc, types, + right, flags, tdpp)); +} + + +/* Function dm_app_get_tdp() must ONLY be called from routines associated with + application calls, e.g. dm_read_invis, dm_set_disp, etc. It must not be + called by a thread responsible for generating an event such as + dm_send_data_event()! + + dm_app_get_tdp() is the interface used by all application calls other than + dm_get_events, dm_respond_event, dm_get_config, dm_get_config_events, and by + the dm_obj_ref_* and dm_*_right families of requests. + + dm_app_get_tdp() converts a sid/hanp/hlen/token quad into a tdp pointer, + increments the number of active application threads in the event, and + increments the number of active application threads using the tdp. The + 'right' parameter must be either DM_RIGHT_SHARED or DM_RIGHT_EXCL. The + token may either be DM_NO_TOKEN, or can be a token received in a synchronous + event. +*/ + +int +dm_app_get_tdp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + short types, + dm_right_t right, /* minimum right */ + dm_tokdata_t **tdpp) +{ + dm_session_t *s; + xfs_handle_t handle; + dm_tokevent_t *tevp; + int error; + unsigned long lc; /* lock cookie */ + + ASSERT(right >= DM_RIGHT_SHARED); + + /* If a token other than DM_NO_TOKEN is specified, find the event on + this session which owns the token and increment its reference count. + */ + + if (token != DM_NO_TOKEN) { /* look up existing tokevent struct */ + return(dm_app_get_tdp_by_token(sid, hanp, hlen, token, types, + right, DM_FG_MUSTEXIST, tdpp)); + } + + /* The token is DM_NO_TOKEN. In this case we only want to verify that + the session ID is valid, and do not need to continue holding the + session lock after we know that to be true. + */ + + if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) + return(error); + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + mutex_spinunlock(&s->sn_qlock, lc); + + /* When DM_NO_TOKEN is used, we simply block until we can obtain the + right that we want (since the tevp contains no tdp structures). + The blocking when we eventually support it will occur within + fsys_vector->request_right(). + */ + + tevp = dm_init_tevp(0, 0); + lc = mutex_spinlock(&tevp->te_lock); + + return(dm_app_lookup_tdp(&handle, tevp, &lc, types, right, 0, tdpp)); +} + + +/* dm_get_config_tdp() is only called by dm_get_config() and + dm_get_config_events(), which neither have a session ID nor a token. + Both of these calls are supposed to work even if the filesystem is in the + process of being mounted, as long as the caller only uses handles within + the mount event. +*/ + +int +dm_get_config_tdp( + void *hanp, + size_t hlen, + dm_tokdata_t **tdpp) +{ + xfs_handle_t handle; + dm_tokevent_t *tevp; + int error; + unsigned long lc; /* lock cookie */ + + if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) + return(error); + + tevp = dm_init_tevp(0, 0); + lc = mutex_spinlock(&tevp->te_lock); + + /* Try to use the handle provided by the caller and assume DM_NO_TOKEN. + This will fail if the filesystem is in the process of being mounted. + */ + + error = dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY, + DM_RIGHT_NULL, 0, tdpp); + + if (!error) { + return(0); + } + + /* Perhaps the filesystem is still mounting, in which case we need to + see if this is one of the handles in the DM_EVENT_MOUNT tevp. + */ + + if ((tevp = dm_find_mount_tevp_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + + return(dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY, + DM_RIGHT_NULL, DM_FG_MUSTEXIST, tdpp)); +} + + +/* dm_put_tdp() is called to release any right held on the vnode, and to + VN_RELE() all references held on the vnode. It is the caller's + responsibility to ensure that no other application threads are using the + tdp, and if necessary to unlink the tdp from the tevp before calling + this routine and to free the tdp afterwards. +*/ + +static void +dm_put_tdp( + dm_tokdata_t *tdp) +{ + ASSERT(tdp->td_app_ref <= 1); + + /* If the application thread is holding a right, or if the event + thread had a right but it has disappeared because of a dm_pending + or Cntl-C, then we need to release it here. + */ + + if (tdp->td_right != DM_RIGHT_NULL) { + dm_fsys_vector_t *fsys_vector; + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + (void)fsys_vector->release_right(tdp->td_vp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + tdp->td_right = DM_RIGHT_NULL; + } + + /* Given that we wouldn't be here if there was still an event thread, + this VN_RELE loop has the potential of generating a DM_EVENT_DESTROY + event if some other thread has unlinked the file. + */ + + while (tdp->td_vcount > 0) { + iput(LINVFS_GET_IP(tdp->td_vp)); + tdp->td_vcount--; + } + + tdp->td_flags &= ~(DM_TDF_HOLD|DM_TDF_RIGHT); + tdp->td_vp = NULL; +} + + +/* Function dm_put_tevp() must ONLY be called from routines associated with + application threads, e.g. dm_read_invis, dm_get_events, etc. It must not be + called by a thread responsible for generating an event, such as + dm_send_data_event. + + PLEASE NOTE: It is possible for this routine to generate DM_EVENT_DESTROY + events, because its calls to dm_put_tdp drop vnode references, and another + thread may have already unlinked a file whose vnode we are de-referencing. + This sets the stage for various types of deadlock if the thread calling + dm_put_tevp is the same thread that calls dm_respond_event! In particular, + the dm_sent_destroy_event routine needs to obtain the dm_reg_lock, + dm_session_lock, and sn_qlock in order to queue the destroy event. No + caller of dm_put_tevp can hold any of these locks! + + Other possible deadlocks are that dm_send_destroy_event could block waiting + for a thread to register for the event using dm_set_disp() and/or + dm_set_return_on_destroy, or it could block because the session's sn_newq + is at the dm_max_queued_msgs event limit. The only safe solution + (unimplemented) is to have a separate kernel thread for each filesystem + whose only job is to do the vnode-dereferencing. That way dm_respond_event + will not block, so the application can keep calling dm_get_events to read + events even if the filesystem thread should block. (If the filesystem + thread blocks, so will all subsequent destroy events for the same + filesystem.) +*/ + +void +dm_put_tevp( + dm_tokevent_t *tevp, + dm_tokdata_t *tdp) +{ + int free_tdp = 0; + unsigned long lc; /* lock cookie */ + + lc = mutex_spinlock(&tevp->te_lock); + + if (tdp != NULL) { + if (tdp->td_vcount > 1 || (tdp->td_flags & DM_TDF_EVTREF)) { + ASSERT(tdp->td_app_ref > 0); + + iput(LINVFS_GET_IP(tdp->td_vp)); + tdp->td_vcount--; + } else { + ASSERT(tdp->td_app_ref == 1); + + /* The vnode reference count is either already at + zero (e.g. a failed dm_handle_to_vp() call in + dm_app_lookup_tdp()) or is going to zero. We can't + hold the lock while we decrement the count because + we could potentially end up being busy for a long + time in VOP_INACTIVATE. Use single-threading to + lock others out while we clean house. + */ + + tdp->td_flags |= DM_TDF_STHREAD; + + /* WARNING - A destroy event is possible here if we are + giving up the last reference on a vnode which has + been previously unlinked by some other thread! + */ + + mutex_spinunlock(&tevp->te_lock, lc); + dm_put_tdp(tdp); + lc = mutex_spinlock(&tevp->te_lock); + + /* If this tdp is not one of the original tdps in the + event, then remove it from the tevp. + */ + + if (!(tdp->td_flags & DM_TDF_ORIG)) { + dm_tokdata_t **tdpp = &tevp->te_tdp; + + while (*tdpp && *tdpp != tdp) { + tdpp = &(*tdpp)->td_next; + } + if (*tdpp == NULL) { + panic("dm_remove_tdp_from_tevp: tdp " + "%p not in tevp %p\n", tdp, + tevp); + } + *tdpp = tdp->td_next; + free_tdp++; + } + } + + /* If this is the last app thread actively using the tdp, clear + any single-threading and wake up any other app threads who + might be waiting to use this tdp, single-threaded or + otherwise. + */ + + if (--tdp->td_app_ref == 0) { + if (tdp->td_flags & DM_TDF_STHREAD) { + tdp->td_flags &= ~DM_TDF_STHREAD; + if (tevp->te_app_slp) + sv_broadcast(&tevp->te_app_queue); + } + } + + if (free_tdp) { + kmem_cache_free(dm_tokdata_cachep, tdp); + } + } + + /* If other application threads are using this token/event, they will + do the cleanup. + */ + + if (--tevp->te_app_ref > 0) { + mutex_spinunlock(&tevp->te_lock, lc); + return; + } + + /* If event generation threads are waiting for this thread to go away, + wake them up and let them do the cleanup. + */ + + if (tevp->te_evt_ref > 0) { + sv_broadcast(&tevp->te_evt_queue); + mutex_spinunlock(&tevp->te_lock, lc); + return; + } + + /* This thread is the last active thread using the token/event. No + lock can be held while we disassemble the tevp because we could + potentially end up being busy for a long time in VOP_INACTIVATE. + */ + + mutex_spinunlock(&tevp->te_lock, lc); + + /* WARNING - One or more destroy events are possible here if we are + giving up references on vnodes which have been previously unlinked + by other kernel threads! + */ + + while ((tdp = tevp->te_tdp) != NULL) { + tevp->te_tdp = tdp->td_next; + dm_put_tdp(tdp); + kmem_cache_free(dm_tokdata_cachep, tdp); + } + spinlock_destroy(&tevp->te_lock); + sv_destroy(&tevp->te_evt_queue); + sv_destroy(&tevp->te_app_queue); + kfree(tevp); +} + + +/* No caller of dm_app_put_tevp can hold either of the locks dm_reg_lock, + dm_session_lock, or any sn_qlock! (See dm_put_tevp for details.) +*/ + +void +dm_app_put_tdp( + dm_tokdata_t *tdp) +{ + dm_put_tevp(tdp->td_tevp, tdp); +} + + +/* dm_change_right is only called if the event thread is the one doing the + cleanup on a completed event. It looks at the current rights of a tdp + and compares that with the rights it had on the tdp when the event was + created. If different, it reaquires the original rights, then transfers + the rights back to being thread-based. +*/ + +static void +dm_change_right( + dm_tokdata_t *tdp) +{ +#ifdef HAVE_DMAPI_RIGHTS + dm_fsys_vector_t *fsys_vector; + int error; + u_int type; +#endif + + /* If the event doesn't have a vnode reference, if the original right + was DM_RIGHT_NULL, or if the rights were never switched from being + thread-based to tdp-based, then there is nothing to do. + */ + + if (!(tdp->td_flags & DM_TDF_EVTREF)) + return; + + if (tdp->td_orig_right == DM_RIGHT_NULL) + return; + + /* DEBUG - Need a check here for event-based rights. */ + +#ifdef HAVE_DMAPI_RIGHTS + /* The "rights" vectors are stubs now anyway. When they are + * implemented then bhv locking will have to be sorted out. + */ + + /* If the current right is not the same as it was when the event was + created, first get back the original right. + */ + + if (tdp->td_right != tdp->td_orig_right) { + fsys_vector = dm_fsys_vector(tdp->td_vp); + type = (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0); + + switch (tdp->td_orig_right) { + case DM_RIGHT_SHARED: + if (tdp->td_right == DM_RIGHT_EXCL) { + error = fsys_vector->downgrade_right( + tdp->td_vp, tdp->td_right, type); + if (!error) + break; + (void)fsys_vector->release_right(tdp->td_vp, + tdp->td_right, type); + } + (void)fsys_vector->request_right(tdp->td_vp, + tdp->td_right, type, DM_RR_WAIT, + tdp->td_orig_right); + break; + + case DM_RIGHT_EXCL: + if (tdp->td_right == DM_RIGHT_SHARED) { + error = fsys_vector->upgrade_right(tdp->td_vp, + tdp->td_right, type); + if (!error) + break; + (void)fsys_vector->release_right(tdp->td_vp, + tdp->td_right, type); + } + (void)fsys_vector->request_right(tdp->td_vp, + tdp->td_right, type, DM_RR_WAIT, + tdp->td_orig_right); + break; + case DM_RIGHT_NULL: + break; + } + } +#endif + + /* We now have back the same level of rights as we had when the event + was generated. Now transfer the rights from being tdp-based back + to thread-based. + */ + + /* DEBUG - Add a call here to transfer rights back to thread-based. */ + + /* Finally, update the tdp so that we don't mess with the rights when + we eventually call dm_put_tdp. + */ + + tdp->td_right = DM_RIGHT_NULL; +} + + +/* This routine is only called by event threads. The calls to dm_put_tdp + are not a deadlock risk here because this is an event thread, and it is + okay for such a thread to block on an induced destroy event. Okay, maybe + there is a slight risk; say that the event contains three vnodes all of + which have DM_RIGHT_EXCL, and say that we are at the dm_max_queued_msgs + limit, and that the first vnode is already unlinked. In that case the + destroy event will block waiting to be queued, and the application thread + could happen to reference one of the other locked vnodes. Deadlock. +*/ + +void +dm_evt_rele_tevp( + dm_tokevent_t *tevp, + int droprights) /* non-zero, evt thread loses rights */ +{ + dm_tokdata_t *tdp; + unsigned long lc; /* lock cookie */ + + lc = mutex_spinlock(&tevp->te_lock); + + /* If we are here without DM_TEF_FINAL set and with at least one + application reference still remaining, then one of several + possibilities is true: + 1. This is an asynchronous event which has been queued but has not + yet been delivered, or which is in the process of being delivered. + 2. This is an unmount event (pseudo-asynchronous) yet to be + delivered or in the process of being delivered. + 3. This event had DM_FLAGS_NDELAY specified, and the application + has sent a dm_pending() reply for the event. + 4. This is a DM_EVENT_READ, DM_EVENT_WRITE, or DM_EVENT_TRUNCATE + event and the user typed a Cntl-C. + In all of these cases, the correct behavior is to leave the + responsibility of releasing any rights to the application threads + when they are done. + */ + + if (tevp->te_app_ref > 0 && !(tevp->te_flags & DM_TEF_FINAL)) { + tevp->te_evt_ref--; + for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { + if (tdp->td_flags & DM_TDF_EVTREF) { + tdp->td_flags &= ~DM_TDF_EVTREF; + if (tdp->td_vcount == 0) { + tdp->td_vp = NULL; + } + } + } + mutex_spinunlock(&tevp->te_lock, lc); + return; /* not the last thread */ + } + + /* If the application reference count is non-zero here, that can only + mean that dm_respond_event() has been called, but the application + still has one or more threads in the kernel that haven't let go of + the tevp. In these cases, the event thread must wait until all + application threads have given up their references, and their + rights to handles within the event. + */ + + while (tevp->te_app_ref) { + sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); + lc = mutex_spinlock(&tevp->te_lock); + } + + /* This thread is the last active thread using the token/event. Reset + the rights of any vnode that was part of the original event back + to their initial values before returning to the filesystem. The + exception is if the event failed (droprights is non-zero), in which + case we chose to return to the filesystem with all rights released. + Release the rights on any vnode that was not part of the original + event. Give up all remaining application vnode references + regardless of whether or not the vnode was part of the original + event. + */ + + mutex_spinunlock(&tevp->te_lock, lc); + + while ((tdp = tevp->te_tdp) != NULL) { + tevp->te_tdp = tdp->td_next; + if ((tdp->td_flags & DM_TDF_ORIG) && + (tdp->td_flags & DM_TDF_EVTREF) && + (!droprights)) { + dm_change_right(tdp); + } + dm_put_tdp(tdp); + kmem_cache_free(dm_tokdata_cachep, tdp); + } + spinlock_destroy(&tevp->te_lock); + sv_destroy(&tevp->te_evt_queue); + sv_destroy(&tevp->te_app_queue); + kfree(tevp); +} + + +/* dm_obj_ref_hold() is just a fancy way to get a vnode reference on an object + to hold it in kernel memory. +*/ + +int +dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_NULL, DM_FG_STHREAD, &tdp); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) { + if (tdp->td_flags & DM_TDF_HOLD) { /* if already held */ + error = EBUSY; + } else { + tdp->td_flags |= DM_TDF_HOLD; + tdp->td_vcount++; + + fsys_vector = dm_fsys_vector(tdp->td_vp); + (void)fsys_vector->obj_ref_hold(tdp->td_vp); + } + dm_app_put_tdp(tdp); + } + return(error); +} + + +int +dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen) +{ + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_NULL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) { + if (!(tdp->td_flags & DM_TDF_HOLD)) { /* if not held */ + error = EACCES; /* use the DM_FG_MUSTEXIST errno */ + } else { + tdp->td_flags &= ~DM_TDF_HOLD; + iput(LINVFS_GET_IP(tdp->td_vp)); + tdp->td_vcount--; + } + dm_app_put_tdp(tdp); + } + return(error); +} + + +int +dm_obj_ref_query_rvp( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen, + int *rvp) +{ + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* If the request is valid but the handle just isn't present in the + event or the hold flag isn't set, return zero, else return one. + */ + + if (tdp) { + if (tdp->td_flags & DM_TDF_HOLD) { /* if held */ + *rvp = 1; + } else { + *rvp = 0; + } + dm_app_put_tdp(tdp); + } else { + *rvp = 0; + } + return(0); +} + + +int +dm_downgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_EXCL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* Attempt the downgrade. Filesystems which support rights but not + the downgrading of rights will return ENOSYS. + */ + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->downgrade_right(tdp->td_vp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) + tdp->td_right = DM_RIGHT_SHARED; + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_query_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp) +{ + dm_tokdata_t *tdp; + dm_right_t right; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* Get the current right and copy it to the caller. The tdp is + single-threaded, so no mutex lock is needed. If the tdp is not in + the event we are supposed to return DM_RIGHT_NULL in order to be + compatible with Veritas. + */ + + if (tdp) { + right = tdp->td_right; + dm_app_put_tdp(tdp); + } else { + right = DM_RIGHT_NULL; + } + if (copy_to_user(rightp, &right, sizeof(right))) + return(EFAULT); + return(0); +} + + +int +dm_release_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->release_right(tdp->td_vp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) { + tdp->td_right = DM_RIGHT_NULL; + if (tdp->td_flags & DM_TDF_RIGHT) { + tdp->td_flags &= ~DM_TDF_RIGHT; + iput(LINVFS_GET_IP(tdp->td_vp)); + tdp->td_vcount--; + } + } + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_request_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int flags, + dm_right_t right) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_NULL, DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->request_right(tdp->td_vp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), flags, right); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + /* The tdp is single-threaded, so no mutex lock is needed for update. + + If this is the first dm_request_right call for this vnode, then we + need to bump the vnode reference count for two reasons. First of + all, it is supposed to be impossible for the file to disappear or + for the filesystem to be unmounted while a right is held on a file; + bumping the file's vnode reference count ensures this. Second, if + rights are ever actually implemented, it will most likely be done + without changes to the on-disk inode, which means that we can't let + the vnode become unreferenced while a right on it is held. + */ + + if (error == 0) { + if (!(tdp->td_flags & DM_TDF_RIGHT)) { /* if first call */ + tdp->td_flags |= DM_TDF_RIGHT; + tdp->td_vcount++; + (void)fsys_vector->obj_ref_hold(tdp->td_vp); + } + tdp->td_right = right; + } + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_upgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* If the object already has the DM_RIGHT_EXCL right, no need to + attempt an upgrade. + */ + + if (tdp->td_right == DM_RIGHT_EXCL) { + dm_app_put_tdp(tdp); + return(0); + } + + /* Attempt the upgrade. Filesystems which support rights but not + the upgrading of rights will return ENOSYS. + */ + + VN_BHV_READ_LOCK(VN_BHV_HEAD(tdp->td_vp)); + fsys_vector = dm_fsys_vector(tdp->td_vp); + error = fsys_vector->upgrade_right(tdp->td_vp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(tdp->td_vp)); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) + tdp->td_right = DM_RIGHT_EXCL; + + dm_app_put_tdp(tdp); + return(error); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_session.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_session.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_session.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_session.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1539 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_private.h" + +dm_session_t *dm_sessions = NULL; /* head of session list */ +u_int dm_sessions_active = 0; /* # sessions currently active */ +dm_sessid_t dm_next_sessid = 1; /* next session ID to use */ +lock_t dm_session_lock = SPIN_LOCK_UNLOCKED;/* lock for session list */ + +dm_token_t dm_next_token = 1; /* next token ID to use */ +dm_sequence_t dm_next_sequence = 1; /* next sequence number to use */ +lock_t dm_token_lock = SPIN_LOCK_UNLOCKED;/* dm_next_token/dm_next_sequence lock */ + +int dm_max_queued_msgs = 2048; /* max # undelivered msgs/session */ + +#ifdef __sgi +int dm_hash_buckets = 1009; /* prime -- number of buckets */ + +/* XXX floating point not allowed in Linux kernel. */ +#define DM_SHASH(sess,inodenum) ((sess)->sn_sesshash + \ + ((inodenum) % dm_hash_buckets)) +#endif + + +#ifdef CONFIG_PROC_FS +static int +sessions_read_pfs(char *buffer, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len; + dm_session_t *sessp = (dm_session_t*)data; + +#define CHKFULL if(len >= count) break; +#define ADDBUF(a,b) len += sprintf(buffer + len, a, b); CHKFULL; + + len=0; + while(1){ + ADDBUF("sessp=0x%p\n", sessp); + ADDBUF("sn_next=0x%p\n", sessp->sn_next); + ADDBUF("sn_sessid=%d\n", sessp->sn_sessid); + ADDBUF("sn_flags=%x\n", sessp->sn_flags); + ADDBUF("sn_qlock=%c\n", '?'); + ADDBUF("sn_readerq=%c\n", '?'); + ADDBUF("sn_writerq=%c\n", '?'); + ADDBUF("sn_readercnt=%u\n", sessp->sn_readercnt); + ADDBUF("sn_writercnt=%u\n", sessp->sn_writercnt); + + ADDBUF("sn_newq.eq_head=0x%p\n", sessp->sn_newq.eq_head); + ADDBUF("sn_newq.eq_tail=0x%p\n", sessp->sn_newq.eq_tail); + ADDBUF("sn_newq.eq_count=%d\n", sessp->sn_newq.eq_count); + + ADDBUF("sn_delq.eq_head=0x%p\n", sessp->sn_delq.eq_head); + ADDBUF("sn_delq.eq_tail=0x%p\n", sessp->sn_delq.eq_tail); + ADDBUF("sn_delq.eq_count=%d\n", sessp->sn_delq.eq_count); + + ADDBUF("sn_evt_writerq.eq_head=0x%p\n", sessp->sn_evt_writerq.eq_head); + ADDBUF("sn_evt_writerq.eq_tail=0x%p\n", sessp->sn_evt_writerq.eq_tail); + ADDBUF("sn_evt_writerq.eq_count=%d\n", sessp->sn_evt_writerq.eq_count); + + ADDBUF("sn_info=\"%s\"\n", sessp->sn_info); + + break; + } + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} +#endif + + +/* Link a session to the end of the session list. New sessions are always + added at the end of the list so that dm_enqueue_mount_event() doesn't + miss a session. The caller must have obtained dm_session_lock before + calling this routine. +*/ + +static void +link_session( + dm_session_t *s) +{ + dm_session_t *tmp; + + if ((tmp = dm_sessions) == NULL) { + dm_sessions = s; + } else { + while (tmp->sn_next != NULL) + tmp = tmp->sn_next; + tmp->sn_next = s; + } + s->sn_next = NULL; + dm_sessions_active++; +} + + +/* Remove a session from the session list. The caller must have obtained + dm_session_lock before calling this routine. unlink_session() should only + be used in situations where the session is known to be on the dm_sessions + list; otherwise it panics. +*/ + +static void +unlink_session( + dm_session_t *s) +{ + dm_session_t *tmp; + + if (dm_sessions == s) { + dm_sessions = dm_sessions->sn_next; + } else { + for (tmp = dm_sessions; tmp; tmp = tmp->sn_next) { + if (tmp->sn_next == s) + break; + } + if (tmp == NULL) { + panic("unlink_session: corrupt DMAPI session list, " + "dm_sessions %p, session %p\n", + dm_sessions, s); + } + tmp->sn_next = s->sn_next; + } + s->sn_next = NULL; + dm_sessions_active--; +} + + +/* Link an event to the end of an event queue. The caller must have obtained + the session's sn_qlock before calling this routine. +*/ + +void +dm_link_event( + dm_tokevent_t *tevp, + dm_eventq_t *queue) +{ + if (queue->eq_tail) { + queue->eq_tail->te_next = tevp; + queue->eq_tail = tevp; + } else { + queue->eq_head = queue->eq_tail = tevp; + } + tevp->te_next = NULL; + queue->eq_count++; +} + + +/* Remove an event from an event queue. The caller must have obtained the + session's sn_qlock before calling this routine. dm_unlink_event() should + only be used in situations where the event is known to be on the queue; + otherwise it panics. +*/ + +void +dm_unlink_event( + dm_tokevent_t *tevp, + dm_eventq_t *queue) +{ + dm_tokevent_t *tmp; + + if (queue->eq_head == tevp) { + queue->eq_head = tevp->te_next; + if (queue->eq_head == NULL) + queue->eq_tail = NULL; + } else { + tmp = queue->eq_head; + while (tmp && tmp->te_next != tevp) + tmp = tmp->te_next; + if (tmp == NULL) { + panic("dm_unlink_event: corrupt DMAPI queue %p, " + "tevp %p\n", queue, tevp); + } + tmp->te_next = tevp->te_next; + if (tmp->te_next == NULL) + queue->eq_tail = tmp; + } + tevp->te_next = NULL; + queue->eq_count--; +} + +/* Link a regular file event to a hash bucket. The caller must have obtained + the session's sn_qlock before calling this routine. + The tokevent must be for a regular file object--DM_TDT_REG. +*/ + +#ifdef __sgi +static void +hash_event( + dm_session_t *s, + dm_tokevent_t *tevp) +{ + dm_sesshash_t *sh; + xfs_ino_t ino; + + if (s->sn_sesshash == NULL) + s->sn_sesshash = kmem_zalloc(dm_hash_buckets * sizeof(dm_sesshash_t), KM_SLEEP); + + ino = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + sh = DM_SHASH(s, ino); + +#ifdef DM_SHASH_DEBUG + if (sh->h_next == NULL) { + s->sn_buckets_in_use++; + if (s->sn_buckets_in_use > s->sn_max_buckets_in_use) + s->sn_max_buckets_in_use++; + } + sh->maxlength++; + sh->curlength++; + sh->num_adds++; +#endif + + tevp->te_flags |= DM_TEF_HASHED; + tevp->te_hashnext = sh->h_next; + sh->h_next = tevp; +} +#endif + + +/* Remove a regular file event from a hash bucket. The caller must have + obtained the session's sn_qlock before calling this routine. + The tokevent must be for a regular file object--DM_TDT_REG. +*/ + +#ifdef __sgi +static void +unhash_event( + dm_session_t *s, + dm_tokevent_t *tevp) +{ + dm_sesshash_t *sh; + dm_tokevent_t *tmp; + xfs_ino_t ino; + + if (s->sn_sesshash == NULL) + return; + + ino = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + sh = DM_SHASH(s, ino); + + if (sh->h_next == tevp) { + sh->h_next = tevp->te_hashnext; /* leap frog */ + } else { + tmp = sh->h_next; + while (tmp->te_hashnext != tevp) { + tmp = tmp->te_hashnext; + } + tmp->te_hashnext = tevp->te_hashnext; /* leap frog */ + } + tevp->te_hashnext = NULL; + tevp->te_flags &= ~DM_TEF_HASHED; + +#ifdef DM_SHASH_DEBUG + if (sh->h_next == NULL) + s->sn_buckets_in_use--; + sh->curlength--; + sh->num_dels++; +#endif +} +#endif + + +/* Determine if this is a repeat event. The caller MUST be holding + the session lock. + The tokevent must be for a regular file object--DM_TDT_REG. + Returns: + 0 == match not found + 1 == match found +*/ + +#ifdef __sgi +static int +repeated_event( + dm_session_t *s, + dm_tokevent_t *tevp) +{ + dm_sesshash_t *sh; + dm_data_event_t *d_event1; + dm_data_event_t *d_event2; + dm_tokevent_t *tevph; + xfs_ino_t ino1; + xfs_ino_t ino2; + + if ((!s->sn_newq.eq_tail) && (!s->sn_delq.eq_tail)) { + return(0); + } + if (s->sn_sesshash == NULL) { + return(0); + } + + ino1 = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + sh = DM_SHASH(s, ino1); + + if (sh->h_next == NULL) { + /* bucket is empty, no match here */ + return(0); + } + + d_event1 = (dm_data_event_t *)((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset); + tevph = sh->h_next; + while (tevph) { + /* find something with the same event type and handle type */ + if ((tevph->te_msg.ev_type == tevp->te_msg.ev_type) && + (tevph->te_tdp->td_type == tevp->te_tdp->td_type)) { + + ino2 = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + d_event2 = (dm_data_event_t *)((char *)&tevph->te_msg + tevph->te_msg.ev_data.vd_offset); + + /* If the two events are operating on the same file, + and the same part of that file, then we have a + match. + */ + if ((ino1 == ino2) && + (d_event2->de_offset == d_event1->de_offset) && + (d_event2->de_length == d_event1->de_length)) { + /* found a match */ +#ifdef DM_SHASH_DEBUG + sh->dup_hits++; +#endif + return(1); + } + } + tevph = tevph->te_hashnext; + } + + /* No match found */ + return(0); +} +#endif + + +/* Return a pointer to a session given its session ID, or EINVAL if no session + has the session ID (per the DMAPI spec). The caller must have obtained + dm_session_lock before calling this routine. +*/ + +static int +dm_find_session( + dm_sessid_t sid, + dm_session_t **sessionpp) +{ + dm_session_t *s; + + for (s = dm_sessions; s; s = s->sn_next) { + if (s->sn_sessid == sid) { + *sessionpp = s; + return(0); + } + } + return(EINVAL); +} + + +/* Return a pointer to a locked session given its session ID. '*lcp' is + used to obtain the session's sn_qlock. Caller is responsible for eventually + unlocking it. +*/ + +int +dm_find_session_and_lock( + dm_sessid_t sid, + dm_session_t **sessionpp, + unsigned long *lcp) /* addr of returned lock cookie */ +{ + int error; + + for (;;) { + *lcp = mutex_spinlock(&dm_session_lock); + + if ((error = dm_find_session(sid, sessionpp)) != 0) { + mutex_spinunlock(&dm_session_lock, *lcp); + return(error); + } + if (spin_trylock(&(*sessionpp)->sn_qlock)) { + nested_spinunlock(&dm_session_lock); + return(0); /* success */ + } + + /* If the second lock is not available, drop the first and + start over. This gives the CPU a chance to process any + interrupts, and also allows processes which want a sn_qlock + for a different session to proceed. + */ + + mutex_spinunlock(&dm_session_lock, *lcp); + } +} + + +/* Return a pointer to the event on the specified session's sn_delq which + contains the given token. The caller must have obtained the session's + sn_qlock before calling this routine. +*/ + +static int +dm_find_msg( + dm_session_t *s, + dm_token_t token, + dm_tokevent_t **tevpp) +{ + dm_tokevent_t *tevp; + + if (token <= DM_INVALID_TOKEN) + return(EINVAL); + + for (tevp = s->sn_delq.eq_head; tevp; tevp = tevp->te_next) { + if (tevp->te_msg.ev_token == token) { + *tevpp = tevp; + return(0); + } + } + return(ESRCH); +} + + +/* Given a session ID and token, find the tevp on the specified session's + sn_delq which corresponds to that session ID/token pair. If a match is + found, lock the tevp's te_lock and return a pointer to the tevp. + '*lcp' is used to obtain the tevp's te_lock. The caller is responsible + for eventually unlocking it. +*/ + +int +dm_find_msg_and_lock( + dm_sessid_t sid, + dm_token_t token, + dm_tokevent_t **tevpp, + unsigned long *lcp) /* address of returned lock cookie */ +{ + dm_session_t *s; + int error; + + if ((error = dm_find_session_and_lock(sid, &s, lcp)) != 0) + return(error); + + if ((error = dm_find_msg(s, token, tevpp)) != 0) { + mutex_spinunlock(&s->sn_qlock, *lcp); + return(error); + } + nested_spinlock(&(*tevpp)->te_lock); + nested_spinunlock(&s->sn_qlock); + return(0); +} + + +/* Create a new session, or resume an old session if one is given. */ + +int +dm_create_session( + dm_sessid_t old, + char *info, + dm_sessid_t *new) +{ + dm_session_t *s; + dm_sessid_t sid; + char sessinfo[DM_SESSION_INFO_LEN]; + size_t len; + int error; + unsigned long lc; /* lock cookie */ + + len = strnlen_user(info, DM_SESSION_INFO_LEN-1); + if (copy_from_user(sessinfo, info, len)) + return(EFAULT); + lc = mutex_spinlock(&dm_session_lock); + sid = dm_next_sessid++; + mutex_spinunlock(&dm_session_lock, lc); + if (copy_to_user(new, &sid, sizeof(sid))) + return(EFAULT); + + if (old == DM_NO_SESSION) { + s = kmem_cache_alloc(dm_session_cachep, SLAB_KERNEL); + if (s == NULL) { + printk("%s/%d: kmem_cache_alloc(dm_session_cachep) returned NULL\n", __FUNCTION__, __LINE__); + return ENOMEM; + } + memset(s, 0, sizeof(*s)); + + sv_init(&s->sn_readerq, SV_DEFAULT, "dmreadq"); + sv_init(&s->sn_writerq, SV_DEFAULT, "dmwritq"); + spinlock_init(&s->sn_qlock, "sn_qlock"); + lc = mutex_spinlock(&dm_session_lock); + } else { + lc = mutex_spinlock(&dm_session_lock); + if ((error = dm_find_session(old, &s)) != 0) { + mutex_spinunlock(&dm_session_lock, lc); + return(error); + } +#ifdef CONFIG_PROC_FS + { + char buf[100]; + sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s); + remove_proc_entry(buf, NULL); + } +#endif + unlink_session(s); + } + bcopy(sessinfo, s->sn_info, len); + s->sn_info[len-1] = 0; /* if not NULL, then now 'tis */ + s->sn_sessid = sid; + link_session(s); +#ifdef CONFIG_PROC_FS + { + char buf[100]; + struct proc_dir_entry *entry; + + sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s); + entry = create_proc_read_entry(buf, 0, 0, sessions_read_pfs, s); + entry->owner = THIS_MODULE; + } +#endif + mutex_spinunlock(&dm_session_lock, lc); + return(0); +} + + +int +dm_destroy_session( + dm_sessid_t sid) +{ + dm_session_t *s; + int error; + unsigned long lc; /* lock cookie */ + + /* The dm_session_lock must be held until the session is unlinked. */ + + lc = mutex_spinlock(&dm_session_lock); + + if ((error = dm_find_session(sid, &s)) != 0) { + mutex_spinunlock(&dm_session_lock, lc); + return(error); + } + nested_spinlock(&s->sn_qlock); + + /* The session exists. Check to see if it is still in use. If any + messages still exist on the sn_newq or sn_delq, or if any processes + are waiting for messages to arrive on the session, then the session + must not be destroyed. + */ + + if (s->sn_newq.eq_head || s->sn_readercnt || s->sn_delq.eq_head) { + nested_spinunlock(&s->sn_qlock); + mutex_spinunlock(&dm_session_lock, lc); + return(EBUSY); + } + +#ifdef CONFIG_PROC_FS + { + char buf[100]; + sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s); + remove_proc_entry(buf, NULL); + } +#endif + + /* The session is not in use. Dequeue it from the session chain. */ + + unlink_session(s); + nested_spinunlock(&s->sn_qlock); + mutex_spinunlock(&dm_session_lock, lc); + + /* Now clear the sessions's disposition registration, and then destroy + the session structure. + */ + + dm_clear_fsreg(s); + + spinlock_destroy(&s->sn_qlock); + sv_destroy(&s->sn_readerq); + sv_destroy(&s->sn_writerq); +#ifdef __sgi + if (s->sn_sesshash) + kmem_free(s->sn_sesshash, dm_hash_buckets * sizeof(dm_sesshash_t)); +#endif + kmem_cache_free(dm_session_cachep, s); + return(0); +} + + +/* + * Return a list of all active sessions. + */ + +int +dm_getall_sessions( + u_int nelem, + dm_sessid_t *sidp, + u_int *nelemp) +{ + dm_session_t *s; + u_int sesscnt; + dm_sessid_t *sesslist; + unsigned long lc; /* lock cookie */ + int error; + int i; + + /* Loop until we can get the right amount of temp space, being careful + not to hold a mutex during the allocation. Usually only one trip. + */ + + for (;;) { + if ((sesscnt = dm_sessions_active) == 0) { + /*if (suword(nelemp, 0))*/ + if (put_user(0, nelemp)) + return(EFAULT); + return(0); + } + sesslist = kmalloc(sesscnt * sizeof(*sidp), GFP_KERNEL); + if (sesslist == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return ENOMEM; + } + + lc = mutex_spinlock(&dm_session_lock); + if (sesscnt == dm_sessions_active) + break; + + mutex_spinunlock(&dm_session_lock, lc); + kfree(sesslist); + } + + /* Make a temp copy of the data, then release the mutex. */ + + for (i = 0, s = dm_sessions; i < sesscnt; i++, s = s->sn_next) + sesslist[i] = s->sn_sessid; + + mutex_spinunlock(&dm_session_lock, lc); + + /* Now copy the data to the user. */ + + if(put_user(sesscnt, nelemp)) { + error = EFAULT; + } else if (sesscnt > nelem) { + error = E2BIG; + } else if (copy_to_user(sidp, sesslist, sesscnt * sizeof(*sidp))) { + error = EFAULT; + } else { + error = 0; + } + kfree(sesslist); + return(error); +} + + +/* + * Return the descriptive string associated with a session. + */ + +int +dm_query_session( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_session_t *s; /* pointer to session given by sid */ + int len; /* length of session info string */ + int error; + char sessinfo[DM_SESSION_INFO_LEN]; + unsigned long lc; /* lock cookie */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + + len = strlen(s->sn_info) + 1; /* NULL terminated when created */ + bcopy(s->sn_info, sessinfo, len); + + mutex_spinunlock(&s->sn_qlock, lc); + + /* Now that the mutex is released, copy the sessinfo to the user. */ + + if (put_user(len, rlenp)) { + error = EFAULT; + } else if (len > buflen) { + error = E2BIG; + } else if (copy_to_user(bufp, sessinfo, len)) { + error = EFAULT; + } else { + error = 0; + } + return(error); +} + + +/* + * Return all of the previously delivered tokens (that is, their IDs) + * for the given session. + */ + +int +dm_getall_tokens( + dm_sessid_t sid, /* session obtaining tokens from */ + u_int nelem, /* size of tokenbufp */ + dm_token_t *tokenbufp, /* buffer to copy token IDs to */ + u_int *nelemp) /* return number copied to tokenbufp */ +{ + dm_session_t *s; /* pointer to session given by sid */ + dm_tokevent_t *tevp; /* event message queue traversal */ + unsigned long lc; /* lock cookie */ + int tokcnt; + dm_token_t *toklist; + int error; + int i; + + /* Loop until we can get the right amount of temp space, being careful + not to hold a mutex during the allocation. Usually only one trip. + */ + + for (;;) { + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + tokcnt = s->sn_delq.eq_count; + mutex_spinunlock(&s->sn_qlock, lc); + + if (tokcnt == 0) { + /*if (suword(nelemp, 0))*/ + if (put_user(0, nelemp)) + return(EFAULT); + return(0); + } + toklist = kmalloc(tokcnt * sizeof(*tokenbufp), GFP_KERNEL); + if (toklist == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return ENOMEM; + } + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) { + kfree(toklist); + return(error); + } + + if (tokcnt == s->sn_delq.eq_count) + break; + + mutex_spinunlock(&s->sn_qlock, lc); + kfree(toklist); + } + + /* Make a temp copy of the data, then release the mutex. */ + + tevp = s->sn_delq.eq_head; + for (i = 0; i < tokcnt; i++, tevp = tevp->te_next) + toklist[i] = tevp->te_msg.ev_token; + + mutex_spinunlock(&s->sn_qlock, lc); + + /* Now copy the data to the user. */ + + if (put_user(tokcnt, nelemp)) { + error = EFAULT; + } else if (tokcnt > nelem) { + error = E2BIG; + } else if (copy_to_user(tokenbufp,toklist,tokcnt*sizeof(*tokenbufp))) { + error = EFAULT; + } else { + error = 0; + } + kfree(toklist); + return(error); +} + + +/* + * Return the message identified by token. + */ + +int +dm_find_eventmsg( + dm_sessid_t sid, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_tokevent_t *tevp; /* message identified by token */ + int msgsize; /* size of message to copy out */ + void *msg; + int error; + unsigned long lc; /* lock cookie */ + + /* Because some of the events (dm_data_event_t in particular) contain + __u64 fields, we need to make sure that the buffer provided by the + caller is aligned such that he can read those fields successfully. + */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Allocate the right amount of temp space, being careful not to hold + a mutex during the allocation. + */ + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) + return(error); + msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg); + mutex_spinunlock(&tevp->te_lock, lc); + + msg = kmalloc(msgsize, GFP_KERNEL); + if (msg == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return ENOMEM; + } + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) { + kfree(msg); + return(error); + } + + /* Make a temp copy of the data, then release the mutex. */ + + bcopy(&tevp->te_msg, msg, msgsize); + mutex_spinunlock(&tevp->te_lock, lc); + + /* Now copy the data to the user. */ + + if (put_user(msgsize,rlenp)) { + error = EFAULT; + } else if (msgsize > buflen) { /* user buffer not big enough */ + error = E2BIG; + } else if (copy_to_user( bufp, msg, msgsize )) { + error = EFAULT; + } else { + error = 0; + } + kfree(msg); + return(error); +} + + +int +dm_move_event( + dm_sessid_t srcsid, + dm_token_t token, + dm_sessid_t targetsid, + dm_token_t *rtokenp) +{ + dm_session_t *s1; + dm_session_t *s2; + dm_tokevent_t *tevp; + int error; + unsigned long lc; /* lock cookie */ +#ifdef __sgi + int hash_it; +#endif + + lc = mutex_spinlock(&dm_session_lock); + + if ((error = dm_find_session(srcsid, &s1)) != 0 || + (error = dm_find_session(targetsid, &s2)) != 0 || + (error = dm_find_msg(s1, token, &tevp)) != 0) { + mutex_spinunlock(&dm_session_lock, lc); + return(error); + } + dm_unlink_event(tevp, &s1->sn_delq); +#ifdef __sgi + if (tevp->te_flags & DM_TEF_HASHED) { + unhash_event(s1, tevp); + hash_it = 1; + } +#endif + dm_link_event(tevp, &s2->sn_delq); +#ifdef __sgi + if (hash_it) + hash_event(s2, tevp); +#endif + mutex_spinunlock(&dm_session_lock, lc); + + if (copy_to_user(rtokenp, &token, sizeof(token))) + return(EFAULT); + return(0); +} + + +/* ARGSUSED */ +int +dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay) /* unused */ +{ + dm_tokevent_t *tevp; + int error; + unsigned long lc; /* lock cookie */ + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) + return(error); + + tevp->te_flags |= DM_TEF_INTERMED; + if (tevp->te_evt_ref > 0) /* if event generation threads exist */ + sv_broadcast(&tevp->te_evt_queue); + + mutex_spinunlock(&tevp->te_lock, lc); + return(0); +} + + +int +dm_get_events( + dm_sessid_t sid, + u_int maxmsgs, + u_int flags, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_session_t *s; /* pointer to session given by sid */ + dm_tokevent_t *tevp; /* next event message on queue */ + int error; + unsigned long lc1; /* first lock cookie */ + unsigned long lc2 = 0; /* second lock cookie */ + int totalsize; + int msgsize; + dm_eventmsg_t *prevmsg; + int prev_msgsize = 0; + u_int msgcnt; + + /* Because some of the events (dm_data_event_t in particular) contain + __u64 fields, we need to make sure that the buffer provided by the + caller is aligned such that he can read those fields successfully. + */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Find the indicated session and lock it. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0) + return(error); + + /* Check for messages on sn_newq. If there aren't any that haven't + already been grabbed by another process, and if we are supposed to + to wait until one shows up, then go to sleep interruptibly on the + sn_readerq semaphore. The session can't disappear out from under + us as long as sn_readerq is non-zero. + */ + + for (;;) { + int rc; + + for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) { + lc2 = mutex_spinlock(&tevp->te_lock); + if (!(tevp->te_flags & DM_TEF_LOCKED)) + break; + mutex_spinunlock(&tevp->te_lock, lc2); + } + if (tevp) + break; /* got one! */ + + if (!(flags & DM_EV_WAIT)) { + mutex_spinunlock(&s->sn_qlock, lc1); + return(EAGAIN); + } + s->sn_readercnt++; + + sv_wait_sig(&s->sn_readerq, 1, &s->sn_qlock, lc1); + rc = signal_pending(current); + + lc1 = mutex_spinlock(&s->sn_qlock); + s->sn_readercnt--; + if (rc) { /* if signal was received */ + mutex_spinunlock(&s->sn_qlock, lc1); + return(EINTR); + } + } + + /* At least one message is available for delivery, and we have both the + session lock and event lock. Mark the event so that it is not + grabbed by other daemons, then drop both locks prior copying the + data to the caller's buffer. Leaving the event on the queue in a + marked state prevents both the session and the event from + disappearing out from under us while we don't have the locks. + */ + + tevp->te_flags |= DM_TEF_LOCKED; + mutex_spinunlock(&tevp->te_lock, lc2); /* reverse cookie order */ + mutex_spinunlock(&s->sn_qlock, lc1); + + /* Continue to deliver messages until there are no more, the + user's buffer becomes full, or we hit his maxmsgs limit. + */ + + totalsize = 0; /* total bytes transferred to the user */ + prevmsg = NULL; + msgcnt = 0; + + while (tevp) { + /* Compute the number of bytes to be moved, rounding up to an + 8-byte boundary so that any subsequent messages will also be + aligned. + */ + + msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg); + msgsize = (msgsize + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1); + totalsize += msgsize; + + /* If it fits, copy the message into the user's buffer and + update his 'rlenp'. Update the _link pointer for any + previous message. + */ + + if (totalsize > buflen) { /* no more room */ + error = E2BIG; + } else if (put_user(totalsize, rlenp)) { + error = EFAULT; + } else if (copy_to_user(bufp, &tevp->te_msg, msgsize)) { + error = EFAULT; + } else if (prevmsg && put_user(prev_msgsize, &prevmsg->_link)) { + error = EFAULT; + } else { + error = 0; + } + + /* If an error occurred, just unmark the event and leave it on + the queue for someone else. Note that other daemons may + have gone to sleep because this event was marked, so wake + them up. Also, if at least one message has already been + delivered, then an error here is not really an error. + */ + + lc1 = mutex_spinlock(&s->sn_qlock); + lc2 = mutex_spinlock(&tevp->te_lock); + tevp->te_flags &= ~DM_TEF_LOCKED; /* drop the mark */ + + if (error) { + if (s->sn_readercnt) + sv_signal(&s->sn_readerq); + + mutex_spinunlock(&tevp->te_lock, lc2); /* rev. order */ + mutex_spinunlock(&s->sn_qlock, lc1); + if (prevmsg) + return(0); + if (error == E2BIG && put_user(totalsize,rlenp)) + error = EFAULT; + return(error); + } + + /* The message was successfully delivered. Unqueue it. */ + + dm_unlink_event(tevp, &s->sn_newq); + + /* Wake up the first of any processes waiting for room on the + sn_newq. + */ + + if (s->sn_writercnt) + sv_signal(&s->sn_writerq); + + /* If the message is synchronous, add it to the sn_delq while + still holding the lock. If it is asynchronous, free it. + */ + + if (tevp->te_msg.ev_token != DM_INVALID_TOKEN) { /* synch */ + dm_link_event(tevp, &s->sn_delq); + mutex_spinunlock(&tevp->te_lock, lc2); + } else { + tevp->te_flags |= DM_TEF_FINAL; +#ifdef __sgi + if (tevp->te_flags & DM_TEF_HASHED) + unhash_event(s, tevp); +#endif + mutex_spinunlock(&tevp->te_lock, lc2); + dm_put_tevp(tevp, NULL);/* can't cause destroy events */ + } + + /* Update our notion of where we are in the user's buffer. If + he doesn't want any more messages, then stop. + */ + + prevmsg = (dm_eventmsg_t *)bufp; + prev_msgsize = msgsize; + bufp = (char *)bufp + msgsize; + + msgcnt++; + if (maxmsgs && msgcnt >= maxmsgs) { + mutex_spinunlock(&s->sn_qlock, lc1); + break; + } + + /* While still holding the sn_qlock, see if any additional + messages are available for delivery. + */ + + for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) { + lc2 = mutex_spinlock(&tevp->te_lock); + if (!(tevp->te_flags & DM_TEF_LOCKED)) { + tevp->te_flags |= DM_TEF_LOCKED; + mutex_spinunlock(&tevp->te_lock, lc2); + break; + } + mutex_spinunlock(&tevp->te_lock, lc2); + } + mutex_spinunlock(&s->sn_qlock, lc1); + } + return(0); +} + + +/* + * Remove an event message from the delivered queue, set the returned + * error where the event generator wants it, and wake up the generator. + * Also currently have the user side release any locks it holds... + */ + +/* ARGSUSED */ +int +dm_respond_event( + dm_sessid_t sid, + dm_token_t token, + dm_response_t response, + int reterror, + size_t buflen, /* unused */ + void *respbufp) /* unused */ +{ + dm_session_t *s; /* pointer to session given by sid */ + dm_tokevent_t *tevp; /* event message queue traversal */ + int error; + unsigned long lc; /* lock cookie */ + + /* Sanity check the input parameters. */ + + switch (response) { + case DM_RESP_CONTINUE: /* continue must have reterror == 0 */ + if (reterror != 0) + return(EINVAL); + break; + case DM_RESP_ABORT: /* abort must have errno set */ + if (reterror <= 0) + return(EINVAL); + break; + case DM_RESP_DONTCARE: + if (reterror > 0) + return(EINVAL); + reterror = -1; /* to distinguish DM_RESP_DONTCARE */ + break; + default: + return(EINVAL); + } + + /* Hold session lock until the event is unqueued. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + + if ((error = dm_find_msg(s, token, &tevp)) != 0) { + mutex_spinunlock(&s->sn_qlock, lc); + return(error); + } + nested_spinlock(&tevp->te_lock); + + if (reterror == -1 && tevp->te_msg.ev_type != DM_EVENT_MOUNT) { + error = EINVAL; + nested_spinunlock(&tevp->te_lock); + mutex_spinunlock(&s->sn_qlock, lc); + } else { + dm_unlink_event(tevp, &s->sn_delq); +#ifdef __sgi + if (tevp->te_flags & DM_TEF_HASHED) + unhash_event(s, tevp); +#endif + tevp->te_reply = reterror; + tevp->te_flags |= DM_TEF_FINAL; + if (tevp->te_evt_ref) + sv_broadcast(&tevp->te_evt_queue); + nested_spinunlock(&tevp->te_lock); + mutex_spinunlock(&s->sn_qlock, lc); + error = 0; + + /* Absolutely no locks can be held when calling dm_put_tevp! */ + + dm_put_tevp(tevp, NULL); /* this can generate destroy events */ + } + return(error); +} + + +/* Queue the filled in event message pointed to by tevp on the session s, and + (if a synchronous event) wait for the reply from the DMAPI application. + The caller MUST be holding the session lock before calling this routine! + The session lock is always released upon exit. + Returns: + -1 == don't care + 0 == success (or async event) + > 0 == errno describing reason for failure +*/ + +static int +dm_enqueue( + dm_session_t *s, + unsigned long lc, /* input lock cookie */ + dm_tokevent_t *tevp, /* in/out parameter */ + int sync, + int flags, + int interruptable) +{ + int is_unmount = 0; +#ifdef __sgi + int is_hashable = 0; +#endif + int reply; + +#ifdef __sgi + /* If the caller isn't planning to stick around for the result + and this request is identical to one that is already on the + queues then just give the caller an EAGAIN. Release the + session lock before returning. + + We look only at NDELAY requests with an event type of READ, + WRITE, or TRUNCATE on objects that are regular files. + */ + + if ((flags & DM_FLAGS_NDELAY) && DM_EVENT_RDWRTRUNC(tevp) && + (tevp->te_tdp->td_type == DM_TDT_REG)) { + if (repeated_event(s, tevp)) { + mutex_spinunlock(&s->sn_qlock, lc); + return(EAGAIN); + } + is_hashable = 1; + } +#endif + + if (tevp->te_msg.ev_type == DM_EVENT_UNMOUNT) + is_unmount = 1; + + /* Check for room on sn_newq. If there is no room for new messages, + then go to sleep on the sn_writerq semaphore. The + session cannot disappear out from under us as long as sn_writercnt + is non-zero. + */ + + while (s->sn_newq.eq_count >= dm_max_queued_msgs) { /* no room */ + s->sn_writercnt++; + dm_link_event(tevp, &s->sn_evt_writerq); + if (interruptable) { + sv_wait_sig(&s->sn_writerq, 1, &s->sn_qlock, lc); + if (signal_pending(current)) { + s->sn_writercnt--; + return(EINTR); + } + } else { + sv_wait(&s->sn_writerq, 1, &s->sn_qlock, lc); + } + lc = mutex_spinlock(&s->sn_qlock); + s->sn_writercnt--; + dm_unlink_event(tevp, &s->sn_evt_writerq); + } + + /* Assign a sequence number and token to the event and bump the + application reference count by one. We don't need 'te_lock' here + because this thread is still the only thread that can see the event. + */ + + nested_spinlock(&dm_token_lock); + tevp->te_msg.ev_sequence = dm_next_sequence++; + if (sync) { + tevp->te_msg.ev_token = dm_next_token++; + } else { + tevp->te_msg.ev_token = DM_INVALID_TOKEN; + } + nested_spinunlock(&dm_token_lock); + + tevp->te_app_ref++; + + /* Room exists on the sn_newq queue, so add this request. If the + queue was previously empty, wake up the first of any processes + that are waiting for an event. + */ + + dm_link_event(tevp, &s->sn_newq); +#ifdef __sgi + if (is_hashable) + hash_event(s, tevp); +#endif + + if (s->sn_readercnt) + sv_signal(&s->sn_readerq); + + mutex_spinunlock(&s->sn_qlock, lc); + + /* Now that the message is queued, processes issuing asynchronous + events or DM_EVENT_UNMOUNT events are ready to continue. + */ + + if (!sync || is_unmount) + return(0); + + /* Synchronous requests wait until a final reply is received. If the + caller supplied the DM_FLAGS_NDELAY flag, the process will return + EAGAIN if dm_pending() sets DM_TEF_INTERMED. We also let users + Cntl-C out of a read, write, and truncate requests. + */ + + lc = mutex_spinlock(&tevp->te_lock); + + while (!(tevp->te_flags & DM_TEF_FINAL)) { + if ((tevp->te_flags & DM_TEF_INTERMED) && + (flags & DM_FLAGS_NDELAY)) { + mutex_spinunlock(&tevp->te_lock, lc); + return(EAGAIN); + } + if (tevp->te_msg.ev_type == DM_EVENT_READ || + tevp->te_msg.ev_type == DM_EVENT_WRITE || + tevp->te_msg.ev_type == DM_EVENT_TRUNCATE) { + sv_wait_sig(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); + if (signal_pending(current)){ + return(EINTR); + } + } else { + sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); + } + lc = mutex_spinlock(&tevp->te_lock); + } + + /* Return both the tevp and the reply which was stored in the tevp by + dm_respond_event. The tevp structure has already been removed from + the reply queue by this point in dm_respond_event(). + */ + + reply = tevp->te_reply; + mutex_spinunlock(&tevp->te_lock, lc); + return(reply); +} + + +/* The filesystem is guaranteed to stay mounted while this event is + outstanding. +*/ + +int +dm_enqueue_normal_event( + vfs_t *vfsp, + dm_tokevent_t *tevp, + int flags) +{ + dm_session_t *s; + int error; + int sync; + unsigned long lc; /* lock cookie */ + + switch (tevp->te_msg.ev_type) { + case DM_EVENT_READ: + case DM_EVENT_WRITE: + case DM_EVENT_TRUNCATE: + case DM_EVENT_PREUNMOUNT: + case DM_EVENT_UNMOUNT: + case DM_EVENT_NOSPACE: + case DM_EVENT_CREATE: + case DM_EVENT_REMOVE: + case DM_EVENT_RENAME: + case DM_EVENT_SYMLINK: + case DM_EVENT_LINK: + case DM_EVENT_DEBUT: /* not currently supported */ + sync = 1; + break; + + case DM_EVENT_DESTROY: + case DM_EVENT_POSTCREATE: + case DM_EVENT_POSTREMOVE: + case DM_EVENT_POSTRENAME: + case DM_EVENT_POSTSYMLINK: + case DM_EVENT_POSTLINK: + case DM_EVENT_ATTRIBUTE: + case DM_EVENT_CLOSE: /* not currently supported */ + case DM_EVENT_CANCEL: /* not currently supported */ + sync = 0; + break; + + default: + return(EIO); /* garbage event number */ + } + + /* Wait until a session selects disposition for the event. The session + is locked upon return from dm_waitfor_disp_session(). + */ + + if ((error = dm_waitfor_disp_session(vfsp, tevp, &s, &lc)) != 0) + return(error); + + return(dm_enqueue(s, lc, tevp, sync, flags, 0)); +} + + +/* Traverse the session list checking for sessions with the WANTMOUNT flag + set. When one is found, send it the message. Possible responses to the + message are one of DONTCARE, CONTINUE, or ABORT. The action taken in each + case is: + DONTCARE (-1) - Send the event to the next session with WANTMOUNT set + CONTINUE ( 0) - Proceed with the mount, errno zero. + ABORT (>0) - Fail the mount, return the returned errno. + + The mount request is sent to sessions in ascending session ID order. + Since the session list can change dramatically while this process is + sleeping in dm_enqueue(), this routine must use session IDs rather than + session pointers when keeping track of where it is in the list. Since + new sessions are always added at the end of the queue, and have increasing + session ID values, we don't have to worry about missing any session. +*/ + +int +dm_enqueue_mount_event( + vfs_t *vfsp, + dm_tokevent_t *tevp) +{ + dm_session_t *s; + dm_sessid_t sid; + int error; + unsigned long lc; /* lock cookie */ + + /* Make the mounting filesystem visible to other DMAPI calls. */ + + if ((error = dm_add_fsys_entry(vfsp, tevp)) != 0){ + return(error); + } + + /* Walk through the session list presenting the mount event to each + session that is interested until a session accepts or rejects it, + or until all sessions ignore it. + */ + + for (sid = DM_NO_SESSION, error = -1; error < 0; sid = s->sn_sessid) { + + lc = mutex_spinlock(&dm_session_lock); + for (s = dm_sessions; s; s = s->sn_next) { + if (s->sn_sessid > sid && s->sn_flags & DM_SN_WANTMOUNT) { + nested_spinlock(&s->sn_qlock); + nested_spinunlock(&dm_session_lock); + break; + } + } + if (s == NULL) { + mutex_spinunlock(&dm_session_lock, lc); + break; /* noone wants it; proceed with mount */ + } + error = dm_enqueue(s, lc, tevp, 1, 0, 0); + } + + /* If the mount will be allowed to complete, then update the fsrp entry + accordingly. If the mount is to be aborted, remove the fsrp entry. + */ + + if (error <= 0) { + dm_change_fsys_entry(vfsp, DM_STATE_MOUNTED); + error = 0; + } else { + dm_remove_fsys_entry(vfsp); + } + return(error); +} + +int +dm_enqueue_sendmsg_event( + dm_sessid_t targetsid, + dm_tokevent_t *tevp, + int sync) +{ + dm_session_t *s; + int error; + unsigned long lc; /* lock cookie */ + + if ((error = dm_find_session_and_lock(targetsid, &s, &lc)) != 0) + return(error); + + return(dm_enqueue(s, lc, tevp, sync, 0, 1)); +} + + +dm_token_t +dm_enqueue_user_event( + dm_sessid_t sid, + dm_tokevent_t *tevp, + dm_token_t *tokenp) +{ + dm_session_t *s; + int error; + unsigned long lc; /* lock cookie */ + + /* Atomically find and lock the session whose session id is 'sid'. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + + /* Assign a sequence number and token to the event, bump the + application reference count by one, and decrement the event + count because the caller gives up all ownership of the event. + We don't need 'te_lock' here because this thread is still the + only thread that can see the event. + */ + + nested_spinlock(&dm_token_lock); + tevp->te_msg.ev_sequence = dm_next_sequence++; + *tokenp = tevp->te_msg.ev_token = dm_next_token++; + nested_spinunlock(&dm_token_lock); + + tevp->te_flags &= ~(DM_TEF_INTERMED|DM_TEF_FINAL); + tevp->te_app_ref++; + tevp->te_evt_ref--; + + /* Add the request to the tail of the sn_delq. Now it's visible. */ + + dm_link_event(tevp, &s->sn_delq); + mutex_spinunlock(&s->sn_qlock, lc); + + return(0); +} diff -Nur linux-2.4.19/fs/xfs/dmapi/dmapi_sysent.c linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_sysent.c --- linux-2.4.19/fs/xfs/dmapi/dmapi_sysent.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/dmapi/dmapi_sysent.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Data Migration API (DMAPI) + */ + + +/* We're using MISC_MAJOR / DMAPI_MINOR. */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "dmapi_private.h" + +kmem_cache_t *dm_fsreg_cachep = NULL; +kmem_cache_t *dm_tokdata_cachep = NULL; +kmem_cache_t *dm_session_cachep = NULL; + +static int +dmapi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + sys_dmapi_args_t kargs; + sys_dmapi_args_t *uap = &kargs; + int error = 0; + int rvp = -ENOSYS; + int use_rvp = 0; + + if (!capable(CAP_MKNOD)) + return(-EPERM); + + if( copy_from_user( &kargs, (sys_dmapi_args_t*)arg, + sizeof(sys_dmapi_args_t) ) ) + return -EFAULT; + + switch (cmd) { + case DM_CLEAR_INHERIT: + error = dm_clear_inherit( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_attrname_t *) DM_Parg(uap,5));/* attrnamep */ + break; + case DM_CREATE_BY_HANDLE: + error = dm_create_by_handle( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* dirhanp */ + (size_t) DM_Uarg(uap,3), /* dirhlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (void *) DM_Parg(uap,5), /* hanp */ + (size_t) DM_Uarg(uap,6), /* hlen */ + (char *) DM_Parg(uap,7));/* cname */ + break; + case DM_CREATE_SESSION: + error = dm_create_session( + (dm_sessid_t) DM_Uarg(uap,1), /* oldsid */ + (char *) DM_Parg(uap,2), /* sessinfop */ + (dm_sessid_t *) DM_Parg(uap,3));/* newsidp */ + break; + case DM_CREATE_USEREVENT: + error = dm_create_userevent( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (size_t) DM_Uarg(uap,2), /* msglen */ + (void *) DM_Parg(uap,3), /* msgdatap */ + (dm_token_t *) DM_Parg(uap,4));/* tokenp */ + break; + case DM_DESTROY_SESSION: + error = dm_destroy_session( + (dm_sessid_t) DM_Uarg(uap,1));/* sid */ + break; + case DM_DOWNGRADE_RIGHT: + error = dm_downgrade_right( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4));/* token */ + break; + case DM_FD_TO_HANDLE: + error = dm_fd_to_hdl( + (int) DM_Uarg(uap,1), /* fd */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t *) DM_Parg(uap,3));/* hlenp */ + break; + case DM_FIND_EVENTMSG: + error = dm_find_eventmsg( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (dm_token_t) DM_Uarg(uap,2), /* token */ + (size_t) DM_Uarg(uap,3), /* buflen */ + (void *) DM_Parg(uap,4), /* bufp */ + (size_t *) DM_Parg(uap,5));/* rlenp */ + break; + case DM_GET_ALLOCINFO: + use_rvp = 1; + error = dm_get_allocinfo_rvp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_off_t *) DM_Parg(uap,5), /* offp */ + (u_int) DM_Uarg(uap,6), /* nelem */ + (dm_extent_t *) DM_Parg(uap,7), /* extentp */ + (u_int *) DM_Parg(uap,8), /* nelemp */ + &rvp); + break; + case DM_GET_BULKALL: + use_rvp = 1; + error = dm_get_bulkall_rvp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* mask */ + (dm_attrname_t *) DM_Parg(uap,6),/* attrnamep */ + (dm_attrloc_t *) DM_Parg(uap,7),/* locp */ + (size_t) DM_Uarg(uap,8), /* buflen */ + (void *) DM_Parg(uap,9), /* bufp */ + (size_t *) DM_Parg(uap,10),/* rlenp */ + &rvp); + break; + case DM_GET_BULKATTR: + use_rvp = 1; + error = dm_get_bulkattr_rvp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* mask */ + (dm_attrloc_t *)DM_Parg(uap,6), /* locp */ + (size_t) DM_Uarg(uap,7), /* buflen */ + (void *) DM_Parg(uap,8), /* bufp */ + (size_t *) DM_Parg(uap,9), /* rlenp */ + &rvp); + break; + case DM_GET_CONFIG: + error = dm_get_config( + (void *) DM_Parg(uap,1), /* hanp */ + (size_t) DM_Uarg(uap,2), /* hlen */ + (dm_config_t) DM_Uarg(uap,3), /* flagname */ + (dm_size_t *) DM_Parg(uap,4));/* retvalp */ + break; + case DM_GET_CONFIG_EVENTS: + error = dm_get_config_events( + (void *) DM_Parg(uap,1), /* hanp */ + (size_t) DM_Uarg(uap,2), /* hlen */ + (u_int) DM_Uarg(uap,3), /* nelem */ + (dm_eventset_t *) DM_Parg(uap,4),/* eventsetp */ + (u_int *) DM_Parg(uap,5));/* nelemp */ + break; + case DM_GET_DIOINFO: + error = dm_get_dioinfo( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_dioinfo_t *)DM_Parg(uap,5));/* diop */ + break; + case DM_GET_DIRATTRS: + use_rvp = 1; + error = dm_get_dirattrs_rvp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* mask */ + (dm_attrloc_t *)DM_Parg(uap,6), /* locp */ + (size_t) DM_Uarg(uap,7), /* buflen */ + (void *) DM_Parg(uap,8), /* bufp */ + (size_t *) DM_Parg(uap,9), /* rlenp */ + &rvp); + break; + case DM_GET_DMATTR: + error = dm_get_dmattr( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_attrname_t *) DM_Parg(uap,5),/* attrnamep */ + (size_t) DM_Uarg(uap,6), /* buflen */ + (void *) DM_Parg(uap,7), /* bufp */ + (size_t *) DM_Parg(uap,8));/* rlenp */ + + break; + case DM_GET_EVENTLIST: + error = dm_get_eventlist( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* nelem */ + (dm_eventset_t *) DM_Parg(uap,6),/* eventsetp */ + (u_int *) DM_Parg(uap,7));/* nelemp */ + break; + case DM_GET_EVENTS: + error = dm_get_events( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (u_int) DM_Uarg(uap,2), /* maxmsgs */ + (u_int) DM_Uarg(uap,3), /* flags */ + (size_t) DM_Uarg(uap,4), /* buflen */ + (void *) DM_Parg(uap,5), /* bufp */ + (size_t *) DM_Parg(uap,6));/* rlenp */ + break; + case DM_GET_FILEATTR: + error = dm_get_fileattr( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* mask */ + (dm_stat_t *) DM_Parg(uap,6));/* statp */ + break; + case DM_GET_MOUNTINFO: + error = dm_get_mountinfo( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (size_t) DM_Uarg(uap,5), /* buflen */ + (void *) DM_Parg(uap,6), /* bufp */ + (size_t *) DM_Parg(uap,7));/* rlenp */ + break; + case DM_GET_REGION: + error = dm_get_region( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* nelem */ + (dm_region_t *) DM_Parg(uap,6), /* regbufp */ + (u_int *) DM_Parg(uap,7));/* nelemp */ + break; + case DM_GETALL_DISP: + error = dm_getall_disp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (size_t) DM_Uarg(uap,2), /* buflen */ + (void *) DM_Parg(uap,3), /* bufp */ + (size_t *) DM_Parg(uap,4));/* rlenp */ + break; + case DM_GETALL_DMATTR: + error = dm_getall_dmattr( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (size_t) DM_Uarg(uap,5), /* buflen */ + (void *) DM_Parg(uap,6), /* bufp */ + (size_t *) DM_Parg(uap,7));/* rlenp */ + break; + case DM_GETALL_INHERIT: + error = dm_getall_inherit( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* nelem */ + (dm_inherit_t *)DM_Parg(uap,6), /* inheritbufp*/ + (u_int *) DM_Parg(uap,7));/* nelemp */ + break; + case DM_GETALL_SESSIONS: + error = dm_getall_sessions( + (u_int) DM_Uarg(uap,1), /* nelem */ + (dm_sessid_t *) DM_Parg(uap,2), /* sidbufp */ + (u_int *) DM_Parg(uap,3));/* nelemp */ + break; + case DM_GETALL_TOKENS: + error = dm_getall_tokens( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (u_int) DM_Uarg(uap,2), /* nelem */ + (dm_token_t *) DM_Parg(uap,3), /* tokenbufp */ + (u_int *) DM_Parg(uap,4));/* nelemp */ + break; + case DM_INIT_ATTRLOC: + error = dm_init_attrloc( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_attrloc_t *) DM_Parg(uap,5));/* locp */ + break; + case DM_MKDIR_BY_HANDLE: + error = dm_mkdir_by_handle( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* dirhanp */ + (size_t) DM_Uarg(uap,3), /* dirhlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (void *) DM_Parg(uap,5), /* hanp */ + (size_t) DM_Uarg(uap,6), /* hlen */ + (char *) DM_Parg(uap,7));/* cname */ + break; + case DM_MOVE_EVENT: + error = dm_move_event( + (dm_sessid_t) DM_Uarg(uap,1), /* srcsid */ + (dm_token_t) DM_Uarg(uap,2), /* token */ + (dm_sessid_t) DM_Uarg(uap,3), /* targetsid */ + (dm_token_t *) DM_Parg(uap,4));/* rtokenp */ + break; + case DM_OBJ_REF_HOLD: + error = dm_obj_ref_hold( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (dm_token_t) DM_Uarg(uap,2), /* token */ + (void *) DM_Parg(uap,3), /* hanp */ + (size_t) DM_Uarg(uap,4));/* hlen */ + break; + case DM_OBJ_REF_QUERY: + use_rvp = 1; + error = dm_obj_ref_query_rvp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (dm_token_t) DM_Uarg(uap,2), /* token */ + (void *) DM_Parg(uap,3), /* hanp */ + (size_t) DM_Uarg(uap,4), /* hlen */ + &rvp); + break; + case DM_OBJ_REF_RELE: + error = dm_obj_ref_rele( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (dm_token_t) DM_Uarg(uap,2), /* token */ + (void *) DM_Parg(uap,3), /* hanp */ + (size_t) DM_Uarg(uap,4));/* hlen */ + break; + case DM_PATH_TO_FSHANDLE: + error = dm_path_to_fshdl( + (char *) DM_Parg(uap,1), /* path */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t *) DM_Parg(uap,3));/* hlenp */ + break; + case DM_PATH_TO_HANDLE: + error = dm_path_to_hdl( + (char *) DM_Parg(uap,1), /* path */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t *) DM_Parg(uap,3));/* hlenp */ + break; + case DM_PENDING: + error = dm_pending( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (dm_token_t) DM_Uarg(uap,2), /* token */ + (dm_timestruct_t *) DM_Parg(uap,3));/* delay */ + break; + case DM_PROBE_HOLE: + error = dm_probe_hole( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_off_t) DM_Uarg(uap,5), /* off */ + (dm_size_t) DM_Uarg(uap,6), /* len */ + (dm_off_t *) DM_Parg(uap,7), /* roffp */ + (dm_size_t *) DM_Parg(uap,8));/* rlenp */ + break; + case DM_PUNCH_HOLE: + error = dm_punch_hole( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_off_t) DM_Uarg(uap,5), /* off */ + (dm_size_t) DM_Uarg(uap,6));/* len */ + break; + case DM_QUERY_RIGHT: + error = dm_query_right( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_right_t *) DM_Parg(uap,5));/* rightp */ + break; + case DM_QUERY_SESSION: + error = dm_query_session( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (size_t) DM_Uarg(uap,2), /* buflen */ + (void *) DM_Parg(uap,3), /* bufp */ + (size_t *) DM_Parg(uap,4));/* rlenp */ + break; + case DM_READ_INVIS: + use_rvp = 1; + error = dm_read_invis_rvp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_off_t) DM_Uarg(uap,5), /* off */ + (dm_size_t) DM_Uarg(uap,6), /* len */ + (void *) DM_Parg(uap,7), /* bufp */ + &rvp); + break; + case DM_RELEASE_RIGHT: + error = dm_release_right( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4));/* token */ + break; + case DM_REMOVE_DMATTR: + error = dm_remove_dmattr( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (int) DM_Uarg(uap,5), /* setdtime */ + (dm_attrname_t *) DM_Parg(uap,6));/* attrnamep */ + break; + case DM_REQUEST_RIGHT: + error = dm_request_right( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* flags */ + (dm_right_t) DM_Uarg(uap,6));/* right */ + break; + case DM_RESPOND_EVENT: + error = dm_respond_event( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (dm_token_t) DM_Uarg(uap,2), /* token */ + (dm_response_t) DM_Uarg(uap,3), /* response */ + (int) DM_Uarg(uap,4), /* reterror */ + (size_t) DM_Uarg(uap,5), /* buflen */ + (void *) DM_Parg(uap,6));/* respbufp */ + break; + case DM_SEND_MSG: + error = dm_send_msg( + (dm_sessid_t) DM_Uarg(uap,1), /* targetsid */ + (dm_msgtype_t) DM_Uarg(uap,2), /* msgtype */ + (size_t) DM_Uarg(uap,3), /* buflen */ + (void *) DM_Parg(uap,4));/* bufp */ + break; + case DM_SET_DISP: + error = dm_set_disp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_eventset_t *) DM_Parg(uap,5),/* eventsetp */ + (u_int) DM_Uarg(uap,6));/* maxevent */ + break; + case DM_SET_DMATTR: + error = dm_set_dmattr( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_attrname_t *) DM_Parg(uap,5),/* attrnamep */ + (int) DM_Uarg(uap,6), /* setdtime */ + (size_t) DM_Uarg(uap,7), /* buflen */ + (void *) DM_Parg(uap,8));/* bufp */ + break; + case DM_SET_EVENTLIST: + error = dm_set_eventlist( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_eventset_t *) DM_Parg(uap,5),/* eventsetp */ + (u_int) DM_Uarg(uap,6));/* maxevent */ + break; + case DM_SET_FILEATTR: + error = dm_set_fileattr( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* mask */ + (dm_fileattr_t *)DM_Parg(uap,6));/* attrp */ + break; + case DM_SET_INHERIT: + error = dm_set_inherit( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_attrname_t *)DM_Parg(uap,5),/* attrnamep */ + (mode_t) DM_Uarg(uap,6));/* mode */ + break; + case DM_SET_REGION: + error = dm_set_region( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (u_int) DM_Uarg(uap,5), /* nelem */ + (dm_region_t *) DM_Parg(uap,6), /* regbufp */ + (dm_boolean_t *) DM_Parg(uap,7));/* exactflagp */ + break; + case DM_SET_RETURN_ON_DESTROY: + error = dm_set_return_on_destroy( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (dm_attrname_t *) DM_Parg(uap,5),/* attrnamep */ + (dm_boolean_t) DM_Uarg(uap,6));/* enable */ + break; + case DM_SYMLINK_BY_HANDLE: + error = dm_symlink_by_handle( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* dirhanp */ + (size_t) DM_Uarg(uap,3), /* dirhlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (void *) DM_Parg(uap,5), /* hanp */ + (size_t) DM_Uarg(uap,6), /* hlen */ + (char *) DM_Parg(uap,7), /* cname */ + (char *) DM_Parg(uap,8));/* path */ + break; + case DM_SYNC_BY_HANDLE: + error = dm_sync_by_handle( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4));/* token */ + break; + case DM_UPGRADE_RIGHT: + error = dm_upgrade_right( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4));/* token */ + break; + case DM_WRITE_INVIS: + use_rvp = 1; + error = dm_write_invis_rvp( + (dm_sessid_t) DM_Uarg(uap,1), /* sid */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (dm_token_t) DM_Uarg(uap,4), /* token */ + (int) DM_Uarg(uap,5), /* flags */ + (dm_off_t) DM_Uarg(uap,6), /* off */ + (dm_size_t) DM_Uarg(uap,7), /* len */ + (void *) DM_Parg(uap,8), /* bufp */ + &rvp); + break; + case DM_OPEN_BY_HANDLE: + use_rvp = 1; + error = dm_open_by_handle_rvp( + (unsigned int) DM_Uarg(uap,1), /* fd */ + (void *) DM_Parg(uap,2), /* hanp */ + (size_t) DM_Uarg(uap,3), /* hlen */ + (int) DM_Uarg(uap,4), /* flags */ + &rvp); + break; + default: + error = ENOSYS; + break; + } + /* If it was an *_rvp() function, then + if error==0, return |rvp| + */ + if( use_rvp && (error == 0) ) + return rvp; + else + return -error; +} + + + +static int +dmapi_open(struct inode *inode, struct file *file) +{ + return 0; +} + + +static int +dmapi_release(struct inode *inode, struct file *file) +{ + return 0; +} + + +/* say hello, and let me know the device is hooked up */ +static ssize_t +dmapi_dump(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + char tmp[50]; + int len; + if( *ppos == 0 ){ + len = sprintf( tmp, "# " DM_VER_STR_CONTENTS "\n" ); + if( copy_to_user(buf, tmp, len) ) + return -EFAULT; + *ppos += 1; + return len; + } + return 0; +} + +static struct file_operations dmapi_fops = { + open: dmapi_open, + ioctl: dmapi_ioctl, + read: dmapi_dump, + release: dmapi_release +}; + +static struct miscdevice dmapi_dev = { + minor: DMAPI_MINOR, + name: "dmapi", + fops: &dmapi_fops +}; + + + +#ifdef CONFIG_PROC_FS +static int +dmapi_summary(char *buffer, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len; + + extern u_int dm_sessions_active; + extern dm_sessid_t dm_next_sessid; + extern dm_token_t dm_next_token; + extern dm_sequence_t dm_next_sequence; + extern int dm_fsys_cnt; + +#define CHKFULL if(len >= count) break; +#define ADDBUF(a,b) len += sprintf(buffer + len, a, b); CHKFULL; + + len=0; + while(1){ + ADDBUF("dm_sessions_active=%u\n", dm_sessions_active); + ADDBUF("dm_next_sessid=%d\n", (int)dm_next_sessid); + ADDBUF("dm_next_token=%d\n", (int)dm_next_token); + ADDBUF("dm_next_sequence=%u\n", (u_int)dm_next_sequence); + ADDBUF("dm_fsys_cnt=%d\n", dm_fsys_cnt); + + break; + } + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} +#endif + + +void +dmapi_init_procfs(void) +{ +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *entry; + + if ((entry = proc_mkdir( DMAPI_DBG_PROCFS, 0)) == NULL ) + return; + entry->owner = THIS_MODULE; + entry->mode = S_IFDIR | S_IRUSR | S_IXUSR; + + if ((entry = proc_mkdir( DMAPI_DBG_PROCFS "/fsreg", 0)) == NULL ) + return; + entry->owner = THIS_MODULE; + + if ((entry = proc_mkdir( DMAPI_DBG_PROCFS "/sessions", 0)) == NULL ) + return; + entry->owner = THIS_MODULE; + + entry = create_proc_read_entry( DMAPI_DBG_PROCFS "/summary", 0, 0, dmapi_summary, NULL); + entry->owner = THIS_MODULE; + + entry = proc_mknod( DMAPI_PROCFS, S_IFCHR | S_IRUSR | S_IWUSR, + NULL, MKDEV(MISC_MAJOR,DMAPI_MINOR)); + if( entry == NULL ) + return; + entry->owner = THIS_MODULE; +#endif +} + +void +dmapi_cleanup_procfs(void) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry( DMAPI_PROCFS, NULL); + remove_proc_entry( DMAPI_DBG_PROCFS "/summary", NULL); + remove_proc_entry( DMAPI_DBG_PROCFS "/fsreg", NULL); + remove_proc_entry( DMAPI_DBG_PROCFS "/sessions", NULL); + remove_proc_entry( DMAPI_DBG_PROCFS, NULL); +#endif +} + + +int __init dmapi_init(void) +{ + int ret; + + dm_tokdata_cachep = kmem_cache_create("dm_tokdata", + sizeof(struct dm_tokdata), 0, 0, NULL, NULL); + if (dm_tokdata_cachep == NULL) + return -ENOMEM; + + dm_fsreg_cachep = kmem_cache_create("dm_fsreg", + sizeof(struct dm_fsreg), 0, 0, NULL, NULL); + if (dm_fsreg_cachep == NULL) { + kmem_cache_destroy(dm_tokdata_cachep); + return -ENOMEM; + } + + dm_session_cachep = kmem_cache_create("dm_session", + sizeof(struct dm_session), 0, 0, NULL, NULL); + if (dm_session_cachep == NULL) { + kmem_cache_destroy(dm_tokdata_cachep); + kmem_cache_destroy(dm_fsreg_cachep); + return -ENOMEM; + } + + ret = misc_register(&dmapi_dev); + if( ret != 0 ) + printk(KERN_ERR "dmapi_init: misc_register returned %d\n", ret); + dmapi_init_procfs(); + return(0); +} + +void __exit dmapi_uninit(void) +{ + misc_deregister(&dmapi_dev); + dmapi_cleanup_procfs(); + kmem_cache_destroy(dm_tokdata_cachep); + kmem_cache_destroy(dm_fsreg_cachep); + kmem_cache_destroy(dm_session_cachep); + dm_fsys_vector_free(); +} diff -Nur linux-2.4.19/fs/xfs/linux/Makefile linux-2.4.19-sgi211r3/fs/xfs/linux/Makefile --- linux-2.4.19/fs/xfs/linux/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/Makefile Wed Oct 16 14:02:58 2002 @@ -0,0 +1,65 @@ +# +# +# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# Makefile for XFS on Linux. + +# This needs -I.. because everything does #include instead of "xfs.h". +# The code is wrong, local files should be included using "xfs.h", not +# but I am not going to change every file at the moment. +EXTRA_CFLAGS += -I.. -funsigned-char + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -g -DSTATIC="" -DDEBUG -DXFSDEBUG +endif + +O_TARGET := linux_xfs.o +ifneq ($(MAKECMDGOALS),modules_install) + obj-m := $(O_TARGET) +endif + +export-objs := xfs_globals.o + +obj-$(CONFIG_PROC_FS) += xfs_stats.o +obj-$(CONFIG_SYSCTL) += xfs_sysctl.o + +obj-y += xfs_aops.o \ + xfs_behavior.o \ + xfs_file.o \ + xfs_fs_subr.o \ + xfs_globals.o \ + xfs_ioctl.o \ + xfs_iops.o \ + xfs_lrw.o \ + xfs_super.o \ + xfs_vnode.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/fs/xfs/linux/xfs_aops.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_aops.c --- linux-2.4.19/fs/xfs/linux/xfs_aops.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_aops.c Mon Dec 2 14:28:33 2002 @@ -0,0 +1,937 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,9) +#define page_buffers(page) ((page)->buffers) +#define page_has_buffers(page) ((page)->buffers) +#endif + +STATIC int linvfs_pb_bmap(struct inode *, loff_t, ssize_t, + struct page_buf_bmap_s *, int); +STATIC int delalloc_convert(struct inode *, struct page *, int, int); + +/* + * match_offset_to_mapping + * Finds the corresponding mapping in block @map array of the + * given @offset within a @page. + */ +STATIC page_buf_bmap_t * +match_offset_to_mapping( + struct page *page, + page_buf_bmap_t *map, + unsigned long offset) +{ + loff_t full_offset; /* offset from start of file */ + + ASSERT(offset < PAGE_CACHE_SIZE); + + full_offset = page->index; /* NB: using 64bit number */ + full_offset <<= PAGE_CACHE_SHIFT; /* offset from file start */ + full_offset += offset; /* offset from page start */ + + if (full_offset < map->pbm_offset) + return NULL; + if (map->pbm_offset + map->pbm_bsize > full_offset) + return map; + return NULL; +} + +STATIC void +map_buffer_at_offset( + struct page *page, + struct buffer_head *bh, + unsigned long offset, + int block_bits, + page_buf_bmap_t *mp) +{ + page_buf_daddr_t bn; + loff_t delta; + int sector_shift; + + ASSERT(!(mp->pbm_flags & PBMF_HOLE)); + ASSERT(!(mp->pbm_flags & PBMF_DELAY)); + ASSERT(!(mp->pbm_flags & PBMF_UNWRITTEN)); + ASSERT(mp->pbm_bn != PAGE_BUF_DADDR_NULL); + + delta = page->index; + delta <<= PAGE_CACHE_SHIFT; + delta += offset; + delta -= mp->pbm_offset; + delta >>= block_bits; + + sector_shift = block_bits - 9; + bn = mp->pbm_bn >> sector_shift; + bn += delta; + ASSERT((bn << sector_shift) >= mp->pbm_bn); + + lock_buffer(bh); + bh->b_blocknr = bn; + bh->b_dev = mp->pbm_target->pbr_kdev; + set_bit(BH_Mapped, &bh->b_state); + clear_bit(BH_Delay, &bh->b_state); +} + +/* + * Convert delalloc space to real space, do not flush the + * data out to disk, that will be done by the caller. + */ +STATIC int +release_page( + struct page *page) +{ + struct inode *inode = (struct inode*)page->mapping->host; + unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; + int ret; + + /* Are we off the end of the file ? */ + if (page->index >= end_index) { + unsigned offset = inode->i_size & (PAGE_CACHE_SIZE-1); + if ((page->index >= end_index+1) || !offset) { + ret = -EIO; + goto out; + } + } + + ret = delalloc_convert(inode, page, 0, 0); + +out: + if (ret < 0) { + block_flushpage(page, 0); + ClearPageUptodate(page); + + return 0; + } + + return 1; +} + +/* + * Convert delalloc or unmapped space to real space and flush out + * to disk. + */ +STATIC int +write_full_page( + struct page *page, + int delalloc) +{ + struct inode *inode = (struct inode*)page->mapping->host; + unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; + int ret; + + /* Are we off the end of the file ? */ + if (page->index >= end_index) { + unsigned offset = inode->i_size & (PAGE_CACHE_SIZE-1); + if ((page->index >= end_index+1) || !offset) { + ret = -EIO; + goto out; + } + } + + if (!page_has_buffers(page)) { + create_empty_buffers(page, inode->i_dev, 1 << inode->i_blkbits); + } + + ret = delalloc_convert(inode, page, 1, delalloc == 0); + +out: + if (ret < 0) { + /* + * If it's delalloc and we have nowhere to put it, + * throw it away. + */ + if (delalloc) + block_flushpage(page, 0); + ClearPageUptodate(page); + unlock_page(page); + } + + return ret; +} + +/* + * Look for a page at index which is unlocked and not mapped + * yet - clustering for mmap write case. + */ +STATIC unsigned int +probe_unmapped_page( + struct address_space *mapping, + unsigned long index, + unsigned int pg_offset) +{ + struct page *page; + int ret = 0; + + page = find_get_page(mapping, index); + if (!page) + return 0; + if (TryLockPage(page)) { + page_cache_release(page); + return 0; + } + if (page->mapping && PageDirty(page)) { + if (!page_has_buffers(page)) { + ret = PAGE_CACHE_SIZE; + } else { + struct buffer_head *bh, *head; + bh = head = page_buffers(page); + do { + if (buffer_mapped(bh) || !buffer_uptodate(bh)) { + break; + } + ret += bh->b_size; + if (ret >= pg_offset) + break; + } while ((bh = bh->b_this_page) != head); + } + } + + unlock_page(page); + page_cache_release(page); + return ret; +} + +STATIC unsigned int +probe_unmapped_cluster( + struct inode *inode, + struct page *startpage, + struct buffer_head *bh, + struct buffer_head *head) +{ + unsigned long tindex, tlast; + unsigned int len, total = 0; + struct address_space *mapping = inode->i_mapping; + + /* First sum forwards in this page */ + do { + if (buffer_mapped(bh)) + break; + total += bh->b_size; + } while ((bh = bh->b_this_page) != head); + + /* if we reached the end of the page, sum forwards in + * following pages. + */ + if (bh == head) { + tlast = inode->i_size >> PAGE_CACHE_SHIFT; + for (tindex = startpage->index + 1; tindex < tlast; tindex++) { + len = probe_unmapped_page(mapping, tindex, + PAGE_CACHE_SIZE); + if (!len) + break; + total += len; + } + if ((tindex == tlast) && (inode->i_size & ~PAGE_CACHE_MASK)) { + len = probe_unmapped_page(mapping, tindex, + inode->i_size & ~PAGE_CACHE_MASK); + total += len; + } + } + return total; +} + +/* + * Probe for a given page (index) in the inode & test if it is delayed. + * Returns page locked and with an extra reference count. + */ +STATIC struct page * +probe_page( + struct inode *inode, + unsigned long index) +{ + struct page *page; + + page = find_get_page(inode->i_mapping, index); + if (!page) + return NULL; + if (TryLockPage(page)) { + page_cache_release(page); + return NULL; + } + if (page->mapping && page_has_buffers(page)) { + struct buffer_head *bh, *head; + + bh = head = page_buffers(page); + do { + if (buffer_delay(bh)) + return page; + } while ((bh = bh->b_this_page) != head); + } + unlock_page(page); + page_cache_release(page); + return NULL; +} + +STATIC void +submit_page( + struct page *page, + struct buffer_head *bh_arr[], + int cnt) +{ + struct buffer_head *bh; + int i; + + if (cnt) { + for (i = 0; i < cnt; i++) { + bh = bh_arr[i]; + set_buffer_async_io(bh); + set_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + } + + for (i = 0; i < cnt; i++) + submit_bh(WRITE, bh_arr[i]); + } else + unlock_page(page); +} + +STATIC int +map_page( + struct inode *inode, + struct page *page, + page_buf_bmap_t *maps, + struct buffer_head *bh_arr[], + int startio, + int all_bh) +{ + struct buffer_head *bh, *head; + page_buf_bmap_t *mp = maps, *tmp; + unsigned long end, offset, end_index; + int i = 0, index = 0; + int bbits = inode->i_blkbits; + + end_index = inode->i_size >> PAGE_CACHE_SHIFT; + if (page->index < end_index) { + end = PAGE_CACHE_SIZE; + } else { + end = inode->i_size & (PAGE_CACHE_SIZE-1); + } + bh = head = page_buffers(page); + do { + offset = i << bbits; + if (!(Page_Uptodate(page) || buffer_uptodate(bh))) + continue; + if (buffer_mapped(bh) && !buffer_delay(bh) && all_bh) { + if (startio && (offset < end)) { + lock_buffer(bh); + bh_arr[index++] = bh; + } + continue; + } + tmp = match_offset_to_mapping(page, mp, offset); + if (!tmp) + continue; + ASSERT(!(tmp->pbm_flags & PBMF_HOLE)); + ASSERT(!(tmp->pbm_flags & PBMF_DELAY)); + map_buffer_at_offset(page, bh, offset, bbits, tmp); + if (startio && (offset < end)) { + bh_arr[index++] = bh; + } else { + unlock_buffer(bh); + } + } while (i++, (bh = bh->b_this_page) != head); + + return index; +} + +/* + * Allocate & map buffers for page given the extent map. Write it out. + * except for the original page of a writepage, this is called on + * delalloc pages only, for the original page it is possible that + * the page has no mapping at all. + */ +STATIC void +convert_page( + struct inode *inode, + struct page *page, + page_buf_bmap_t *maps, + int startio, + int all_bh) +{ + struct buffer_head *bh_arr[MAX_BUF_PER_PAGE]; + int cnt; + + cnt = map_page(inode, page, maps, bh_arr, startio, all_bh); + submit_page(page, bh_arr, cnt); + page_cache_release(page); +} + +/* + * Convert & write out a cluster of pages in the same extent as defined + * by mp and following the start page. + */ +STATIC void +cluster_write( + struct inode *inode, + unsigned long tindex, + page_buf_bmap_t *mp, + int startio, + int all_bh) +{ + unsigned long tlast; + struct page *page; + + tlast = (mp->pbm_offset + mp->pbm_bsize) >> PAGE_CACHE_SHIFT; + for (; tindex < tlast; tindex++) { + if (!(page = probe_page(inode, tindex))) + break; + convert_page(inode, page, mp, startio, all_bh); + } +} + +/* + * Calling this without allocate_space set means we are being asked to + * flush a dirty buffer head. When called with async_write set then we + * are coming from writepage. A writepage call with allocate_space set + * means we are being asked to write out all of the page which is before + * EOF and therefore need to allocate space for unmapped portions of the + * page. + * + * When called with startio e.g. from + * write page it is important that we write WHOLE page if possible. The + * bh->b_state's can not know of any of the blocks or which block for + * that matter are dirty due to map writes, and therefore bh uptodate is + * only vaild if the pagei itself isn't completely uptodate. Some layers + * may clear the page dirty flag prior to calling write page under the + * assumption the entire page will be written out, by not writing out the + * whole page the page can be reused before all vaild dirty data is + * written out. Note: in the case of a page that has been dirty'd by + * mapwrite and but partially setup by block_prepare_write the + * bh->b_states's will not agree and only ones setup by BPW/BCW will have + * valid state, thus the whole page must be written out thing. + */ + +STATIC int +delalloc_convert( + struct inode *inode, /* inode containing page */ + struct page *page, /* page to convert - locked */ + int startio, /* start io on the page */ + int allocate_space) +{ + struct buffer_head *bh, *head; + struct buffer_head *bh_arr[MAX_BUF_PER_PAGE]; + page_buf_bmap_t *mp, map; + int i, cnt = 0; + int len, err; + unsigned long p_offset = 0; + loff_t offset; + loff_t end_offset; + + offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + end_offset = offset + PAGE_CACHE_SIZE; + if (end_offset > inode->i_size) + end_offset = inode->i_size; + + bh = head = page_buffers(page); + mp = NULL; + + len = bh->b_size; + do { + if (!(Page_Uptodate(page) || buffer_uptodate(bh)) && !startio) { + goto next_bh; + } + + if (mp) { + mp = match_offset_to_mapping(page, &map, p_offset); + } + + if (buffer_delay(bh)) { + if (!mp) { + err = linvfs_pb_bmap(inode, offset, len, &map, + PBF_WRITE|PBF_FILE_ALLOCATE); + if (err) + goto error; + mp = match_offset_to_mapping(page, &map, + p_offset); + } + if (mp) { + map_buffer_at_offset(page, bh, p_offset, + inode->i_blkbits, mp); + if (startio) { + bh_arr[cnt++] = bh; + } else { + unlock_buffer(bh); + } + } + } else if ((buffer_uptodate(bh) || Page_Uptodate(page)) && + (allocate_space || startio)) { + if (!buffer_mapped(bh)){ + int size; + + /* Getting here implies an unmapped buffer was found, + * and we are in a path where we need to write the + * whole page out. + */ + if (!mp) { + size = probe_unmapped_cluster(inode, page, + bh, head); + err = linvfs_pb_bmap(inode, offset, size, &map, + PBF_WRITE|PBF_DIRECT); + if (err) { + goto error; + } + mp = match_offset_to_mapping(page, &map, + p_offset); + } + if (mp) { + map_buffer_at_offset(page, bh, p_offset, + inode->i_blkbits, mp); + if (startio) { + bh_arr[cnt++] = bh; + } else { + unlock_buffer(bh); + } + } + } else if (startio && buffer_mapped(bh)) { + if(buffer_uptodate(bh) && allocate_space) { + lock_buffer(bh); + bh_arr[cnt++] = bh; + } + } + } + +next_bh: + offset += len; + p_offset += len; + bh = bh->b_this_page; + } while (offset < end_offset); + + if (startio) + submit_page(page, bh_arr, cnt); + + if (mp) + cluster_write(inode, page->index + 1, mp, + startio, allocate_space); + + return 0; + +error: + for (i = 0; i < cnt; i++) { + unlock_buffer(bh_arr[i]); + } + + return err; +} + +STATIC int +linvfs_get_block_core( + struct inode *inode, + long iblock, + struct buffer_head *bh_result, + int create, + int direct, + page_buf_flags_t flags) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + page_buf_bmap_t pbmap; + int retpbbm = 1; + int error; + ssize_t size; + loff_t offset = (loff_t)iblock << inode->i_blkbits; + + /* If we are doing writes at the end of the file, + * allocate in chunks + */ + if (create && (offset >= inode->i_size) && !(flags & PBF_SYNC)) + size = 1 << XFS_WRITE_IO_LOG; + else + size = 1 << inode->i_blkbits; + + VOP_BMAP(vp, offset, size, + create ? flags : PBF_READ, NULL, + (struct page_buf_bmap_s *)&pbmap, &retpbbm, error); + if (error) + return -error; + + if (retpbbm == 0) + return 0; + + if (pbmap.pbm_bn != PAGE_BUF_DADDR_NULL) { + page_buf_daddr_t bn; + loff_t delta; + + delta = offset - pbmap.pbm_offset; + delta >>= inode->i_blkbits; + + bn = pbmap.pbm_bn >> (inode->i_blkbits - 9); + bn += delta; + + bh_result->b_blocknr = bn; + set_bit(BH_Mapped, &bh_result->b_state); + } + + /* If we previously allocated a block out beyond eof and + * we are now coming back to use it then we will need to + * flag it as new even if it has a disk address. + */ + if (create && + ((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) || + (offset >= inode->i_size))) { + set_bit(BH_New, &bh_result->b_state); + } + + if (pbmap.pbm_flags & PBMF_DELAY) { + if (unlikely(direct)) + BUG(); + + if (create) { + set_bit(BH_Mapped, &bh_result->b_state); + } + set_bit(BH_Delay, &bh_result->b_state); + } + + return 0; +} + +int +linvfs_get_block( + struct inode *inode, + long iblock, + struct buffer_head *bh_result, + int create) +{ + return linvfs_get_block_core(inode, iblock, bh_result, + create, 0, PBF_WRITE); +} + +STATIC int +linvfs_get_block_sync( + struct inode *inode, + long iblock, + struct buffer_head *bh_result, + int create) +{ + return linvfs_get_block_core(inode, iblock, bh_result, + create, 0, PBF_SYNC|PBF_WRITE); +} + + +STATIC int +linvfs_get_block_direct( + struct inode *inode, + long iblock, + struct buffer_head *bh_result, + int create) +{ + return linvfs_get_block_core(inode, iblock, bh_result, + create, 1, PBF_WRITE|PBF_DIRECT); +} + +STATIC int +linvfs_pb_bmap( + struct inode *inode, + loff_t offset, + ssize_t count, + page_buf_bmap_t *pbmapp, + int flags) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + int error, nmaps = 1; + +retry: + if (flags & PBF_FILE_ALLOCATE) { + VOP_STRATEGY(vp, offset, count, flags, NULL, + pbmapp, &nmaps, error); + } else { + VOP_BMAP(vp, offset, count, flags, NULL, + pbmapp, &nmaps, error); + } + if (flags & PBF_WRITE) { + if (unlikely((flags & PBF_DIRECT) && nmaps && + (pbmapp->pbm_flags & PBMF_DELAY))) { + flags = PBF_WRITE | PBF_FILE_ALLOCATE; + goto retry; + } + VMODIFY(vp); + } + return -error; +} + +STATIC int +linvfs_bmap( + struct address_space *mapping, + long block) +{ + struct inode *inode = (struct inode *)mapping->host; + vnode_t *vp = LINVFS_GET_VP(inode); + int error; + + /* block - Linux disk blocks 512b */ + /* bmap input offset - bytes 1b */ + /* bmap output bn - XFS BBs 512b */ + /* bmap output delta - bytes 1b */ + + vn_trace_entry(vp, "linvfs_bmap", (inst_t *)__return_address); + + VOP_RWLOCK(vp, VRWLOCK_READ); + VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); + VOP_RWUNLOCK(vp, VRWLOCK_READ); + return generic_block_bmap(mapping, block, linvfs_get_block_direct); +} + +STATIC int +linvfs_read_full_page( + struct file *unused, + struct page *page) +{ + return block_read_full_page(page, linvfs_get_block); +} + +STATIC int +count_page_state( + struct page *page, + int *nr_delalloc, + int *nr_unmapped) +{ + *nr_delalloc = *nr_unmapped = 0; + + if (page_has_buffers(page)) { + struct buffer_head *bh, *head; + + bh = head = page_buffers(page); + do { + if (buffer_uptodate(bh) && !buffer_mapped(bh)) { + (*nr_unmapped)++; + continue; + } + if (!buffer_delay(bh)) + continue; + (*nr_delalloc)++; + } while ((bh = bh->b_this_page) != head); + return 1; + } + + return 0; +} + +STATIC int +linvfs_write_full_page( + struct page *page) +{ + int flagset = 0; + int error; + int need_trans; + int nr_delalloc, nr_unmapped; + + if (count_page_state(page, &nr_delalloc, &nr_unmapped)) { + need_trans = nr_delalloc + nr_unmapped; + } else { + need_trans = 1; + } + + if ((current->flags & (PF_FSTRANS|PF_NOIO)) && need_trans) + goto out_fail; + + if (need_trans) { + current->flags |= PF_NOIO; + flagset = 1; + } + + error = write_full_page(page, nr_delalloc); + + if (flagset) + current->flags &= ~PF_NOIO; + return error; + +out_fail: + SetPageDirty(page); + unlock_page(page); + return 0; +} + +STATIC int +linvfs_prepare_write( + struct file *file, + struct page *page, + unsigned int from, + unsigned int to) +{ + if (file && (file->f_flags & O_SYNC)) { + return block_prepare_write(page, from, to, + linvfs_get_block_sync); + } else { + return block_prepare_write(page, from, to, + linvfs_get_block); + } +} + +/* + * Initiate I/O on a kiobuf of user memory + */ +STATIC int +linvfs_direct_IO( + int rw, + struct inode *inode, + struct kiobuf *iobuf, + unsigned long blocknr, + int blocksize) +{ + struct page **maplist; + size_t page_offset; + page_buf_t *pb; + page_buf_bmap_t map; + int error = 0; + int pb_flags, map_flags, pg_index = 0; + size_t length, total; + loff_t offset; + size_t map_size, size; + + total = length = iobuf->length; + offset = blocknr; + offset <<= inode->i_blkbits; + + maplist = iobuf->maplist; + page_offset = iobuf->offset; + + map_flags = (rw ? PBF_WRITE : PBF_READ) | PBF_DIRECT; + pb_flags = (rw ? PBF_WRITE : PBF_READ) | PBF_FORCEIO | _PBF_LOCKABLE; + while (length) { + error = linvfs_pb_bmap(inode, offset, length, &map, map_flags); + if (error) + break; + + map_size = map.pbm_bsize - map.pbm_delta; + size = min(map_size, length); + if (map.pbm_flags & PBMF_HOLE) { + size_t zero_len = size; + + if (rw == WRITE) + break; + + /* Need to zero it all */ + while (zero_len) { + struct page *page; + size_t pg_len; + + pg_len = min((size_t) + (PAGE_CACHE_SIZE - page_offset), + zero_len); + + page = maplist[pg_index]; + + memset(kmap(page) + page_offset, 0, pg_len); + flush_dcache_page(page); + kunmap(page); + + zero_len -= pg_len; + if ((pg_len + page_offset) == PAGE_CACHE_SIZE) { + pg_index++; + page_offset = 0; + } else { + page_offset = (page_offset + pg_len) & + ~PAGE_CACHE_MASK; + } + } + } else { + int pg_count; + + pg_count = (size + page_offset + PAGE_CACHE_SIZE - 1) + >> PAGE_CACHE_SHIFT; + if ((pb = pagebuf_lookup(map.pbm_target, inode, offset, + size, pb_flags)) == NULL) { + error = -ENOMEM; + break; + } + /* Need to hook up pagebuf to kiobuf pages */ + pb->pb_pages = &maplist[pg_index]; + pb->pb_offset = page_offset; + pb->pb_page_count = pg_count; + + pb->pb_bn = map.pbm_bn + (map.pbm_delta >> 9); + error = pagebuf_iostart(pb, pb_flags); + pb->pb_flags &= ~_PBF_LOCKABLE; + pagebuf_rele(pb); + if (error != 0) { + if (error > 0) + error = -error; + break; + } + + page_offset = (page_offset + size) & ~PAGE_CACHE_MASK; + if (page_offset) + pg_count--; + pg_index += pg_count; + } + + offset += size; + length -= size; + } + + return (error ? error : (int)(total - length)); +} + +/* + * This gets a page into cleanable state - page locked on entry + * kept locked on exit. If the page is marked dirty we should + * not come this way. + */ +STATIC int +linvfs_release_page( + struct page *page, + int gfp_mask) +{ + int need_trans; + int nr_delalloc, nr_unmapped; + + if (count_page_state(page, &nr_delalloc, &nr_unmapped)) { + need_trans = nr_delalloc; + } else { + need_trans = 0; + } + + if (need_trans == 0) { + return 1; + } + + if (gfp_mask & __GFP_FS) { + return release_page(page); + } + return 0; +} + + +struct address_space_operations linvfs_aops = { + .readpage = linvfs_read_full_page, + .writepage = linvfs_write_full_page, + .sync_page = block_sync_page, + .releasepage = linvfs_release_page, + .prepare_write = linvfs_prepare_write, + .commit_write = generic_commit_write, + .bmap = linvfs_bmap, + .direct_IO = linvfs_direct_IO, +}; diff -Nur linux-2.4.19/fs/xfs/linux/xfs_behavior.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_behavior.c --- linux-2.4.19/fs/xfs/linux/xfs_behavior.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_behavior.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * + */ + +/* + * Source file used to associate/disassociate behaviors with virtualized + * objects. See behavior.h for more information about behaviors, etc. + * + * The implementation is split between functions in this file and macros + * in behavior.h. + */ +#include + +kmem_zone_t *bhv_global_zone; + +/* + * Global initialization function called out of main. + */ +void +bhv_global_init(void) +{ + /* + * Initialize a behavior zone used by subsystems using behaviors + * but without any private data. In the UNIKERNEL case, this zone + * is used only for behaviors that are not yet isolated to a single + * cell. The only such user is in pshm.c in which a dummy vnode is + * obtained in support of vce avoidance logic. + */ + bhv_global_zone = kmem_zone_init(sizeof(bhv_desc_t), "bhv_global_zone"); +} + +/* + * Remove a behavior descriptor from a position in a behavior chain; + * the postition is guaranteed not to be the first position. + * Should only be called by the bhv_remove() macro. + * + * The act of modifying the chain is done atomically w.r.t. ops-in-progress + * (see comment at top of behavior.h for more info on synchronization). + */ +void +bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp) +{ + bhv_desc_t *curdesc, *prev; + + ASSERT(bhp->bh_first != NULL); + ASSERT(bhp->bh_first->bd_next != NULL); + + prev = bhp->bh_first; + for (curdesc = bhp->bh_first->bd_next; + curdesc != NULL; + curdesc = curdesc->bd_next) { + + if (curdesc == bdp) + break; /* found it */ + prev = curdesc; + } + + ASSERT(curdesc == bdp); + prev->bd_next = bdp->bd_next; /* remove from after prev */ + /* atomic wrt oip's */ +} + +/* + * Look for a specific ops vector on the specified behavior chain. + * Return the associated behavior descriptor. Or NULL, if not found. + */ +bhv_desc_t * +bhv_lookup(bhv_head_t *bhp, void *ops) +{ + bhv_desc_t *curdesc; + + for (curdesc = bhp->bh_first; + curdesc != NULL; + curdesc = curdesc->bd_next) { + + if (curdesc->bd_ops == ops) + return curdesc; + } + + return NULL; +} + +/* + * Look for a specific ops vector on the specified behavior chain. + * Return the associated behavior descriptor. Or NULL, if not found. + * + * The caller has not read locked the behavior chain, so acquire the + * lock before traversing the chain. + */ +bhv_desc_t * +bhv_lookup_unlocked(bhv_head_t *bhp, void *ops) +{ + bhv_desc_t *bdp; + + BHV_READ_LOCK(bhp); + bdp = bhv_lookup(bhp, ops); + BHV_READ_UNLOCK(bhp); + + return bdp; +} + +/* + * Return the base behavior in the chain, or NULL if the chain + * is empty. + * + * The caller has not read locked the behavior chain, so acquire the + * lock before traversing the chain. + */ +bhv_desc_t * +bhv_base_unlocked(bhv_head_t *bhp) +{ + bhv_desc_t *curdesc; + + BHV_READ_LOCK(bhp); + for (curdesc = bhp->bh_first; + curdesc != NULL; + curdesc = curdesc->bd_next) { + + if (curdesc->bd_next == NULL) { + BHV_READ_UNLOCK(bhp); + return curdesc; + } + } + + BHV_READ_UNLOCK(bhp); + return NULL; +} + +#define BHVMAGIC (void *)0xf00d + +/* ARGSUSED */ +void +bhv_head_init( + bhv_head_t *bhp, + char *name) +{ + bhp->bh_first = NULL; + bhp->bh_lockp = BHVMAGIC; +} + + +/* ARGSUSED */ +void +bhv_head_reinit( + bhv_head_t *bhp) +{ + ASSERT(bhp->bh_first == NULL); + ASSERT(bhp->bh_lockp == BHVMAGIC); +} + + +void +bhv_insert_initial( + bhv_head_t *bhp, + bhv_desc_t *bdp) +{ + ASSERT(bhp->bh_first == NULL); + ASSERT(bhp->bh_lockp == BHVMAGIC); + (bhp)->bh_first = bdp; +} + +void +bhv_head_destroy( + bhv_head_t *bhp) +{ + ASSERT(bhp->bh_first == NULL); + ASSERT(bhp->bh_lockp == BHVMAGIC); + bhp->bh_lockp = NULL; +} + diff -Nur linux-2.4.19/fs/xfs/linux/xfs_behavior.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_behavior.h --- linux-2.4.19/fs/xfs/linux/xfs_behavior.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_behavior.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BEHAVIOR_H__ +#define __XFS_BEHAVIOR_H__ + +/* + * Header file used to associate behaviors with virtualized objects. + * + * A virtualized object is an internal, virtualized representation of + * OS entities such as persistent files, processes, or sockets. Examples + * of virtualized objects include vnodes, vprocs, and vsockets. Often + * a virtualized object is referred to simply as an "object." + * + * A behavior is essentially an implementation layer associated with + * an object. Multiple behaviors for an object are chained together, + * the order of chaining determining the order of invocation. Each + * behavior of a given object implements the same set of interfaces + * (e.g., the VOP interfaces). + * + * Behaviors may be dynamically inserted into an object's behavior chain, + * such that the addition is transparent to consumers that already have + * references to the object. Typically, a given behavior will be inserted + * at a particular location in the behavior chain. Insertion of new + * behaviors is synchronized with operations-in-progress (oip's) so that + * the oip's always see a consistent view of the chain. + * + * The term "interpostion" is used to refer to the act of inserting + * a behavior such that it interposes on (i.e., is inserted in front + * of) a particular other behavior. A key example of this is when a + * system implementing distributed single system image wishes to + * interpose a distribution layer (providing distributed coherency) + * in front of an object that is otherwise only accessed locally. + * + * Note that the traditional vnode/inode combination is simply a virtualized + * object that has exactly one associated behavior. + * + * Behavior synchronization is logic which is necessary under certain + * circumstances that there is no conflict between ongoing operations + * traversing the behavior chain and those dunamically modifying the + * behavior chain. Because behavior synchronization adds extra overhead + * to virtual operation invocation, we want to restrict, as much as + * we can, the requirement for this extra code, to those situations + * in which it is truly necessary. + * + * Behavior synchronization is needed whenever there's at least one class + * of object in the system for which: + * 1) multiple behaviors for a given object are supported, + * -- AND -- + * 2a) insertion of a new behavior can happen dynamically at any time during + * the life of an active object, + * -- AND -- + * 3a) insertion of a new behavior needs to synchronize with existing + * ops-in-progress. + * -- OR -- + * 3b) multiple different behaviors can be dynamically inserted at + * any time during the life of an active object + * -- OR -- + * 3c) removal of a behavior can occur at any time during the life of + * an active object. + * -- OR -- + * 2b) removal of a behavior can occur at any time during the life of an + * active object + * + */ + +typedef void bhv_head_lock_t; + +/* + * Behavior head. Head of the chain of behaviors. + * Contained within each virtualized object data structure. + */ +typedef struct bhv_head { + struct bhv_desc *bh_first; /* first behavior in chain */ + bhv_head_lock_t *bh_lockp; /* pointer to lock info struct */ +} bhv_head_t; + +/* + * Behavior descriptor. Descriptor associated with each behavior. + * Contained within the behavior's private data structure. + */ +typedef struct bhv_desc { + void *bd_pdata; /* private data for this behavior */ + void *bd_vobj; /* virtual object associated with */ + void *bd_ops; /* ops for this behavior */ + struct bhv_desc *bd_next; /* next behavior in chain */ +} bhv_desc_t; + +/* + * Behavior identity field. A behavior's identity determines the position + * where it lives within a behavior chain, and it's always the first field + * of the behavior's ops vector. The optional id field further identifies the + * subsystem responsible for the behavior. + */ +typedef struct bhv_identity { + __u16 bi_id; /* owning subsystem id */ + __u16 bi_position; /* position in chain */ +} bhv_identity_t; + +typedef bhv_identity_t bhv_position_t; + +#define BHV_IDENTITY_INIT(id,pos) {id, pos} + +#define BHV_IDENTITY_INIT_POSITION(pos) BHV_IDENTITY_INIT(0, pos) + + +/* + * Define boundaries of position values. + */ +#define BHV_POSITION_INVALID 0 /* invalid position number */ +#define BHV_POSITION_BASE 1 /* base (last) implementation layer */ +#define BHV_POSITION_TOP 63 /* top (first) implementation layer */ + +/* + * Plumbing macros. + */ +#define BHV_HEAD_FIRST(bhp) (ASSERT((bhp)->bh_first), (bhp)->bh_first) +#define BHV_NEXT(bdp) (ASSERT((bdp)->bd_next), (bdp)->bd_next) +#define BHV_NEXTNULL(bdp) ((bdp)->bd_next) +#define BHV_VOBJ(bdp) (ASSERT((bdp)->bd_vobj), (bdp)->bd_vobj) +#define BHV_VOBJNULL(bdp) ((bdp)->bd_vobj) +#define BHV_PDATA(bdp) (bdp)->bd_pdata +#define BHV_OPS(bdp) (bdp)->bd_ops +#define BHV_IDENTITY(bdp) ((bhv_identity_t *)(bdp)->bd_ops) +#define BHV_POSITION(bdp) (BHV_IDENTITY(bdp)->bi_position) + + +#define BHV_READ_LOCK(bhp) +#define BHV_READ_UNLOCK(bhp) +#define BHV_NOT_READ_LOCKED(bhp) 1 +#define BHV_IS_WRITE_LOCKED(bhp) 1 +#define BHV_NOT_WRITE_LOCKED(bhp) 1 + +extern void bhv_head_init(bhv_head_t *, char *); +extern void bhv_head_destroy(bhv_head_t *); +extern void bhv_head_reinit(bhv_head_t *); +extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *); + +/* + * Initialize a new behavior descriptor. + * Arguments: + * bdp - pointer to behavior descriptor + * pdata - pointer to behavior's private data + * vobj - pointer to associated virtual object + * ops - pointer to ops for this behavior + */ +#define bhv_desc_init(bdp, pdata, vobj, ops) \ + { \ + (bdp)->bd_pdata = pdata; \ + (bdp)->bd_vobj = vobj; \ + (bdp)->bd_ops = ops; \ + (bdp)->bd_next = NULL; \ + } + +#define BHV_DESC_INIT(so,A,B) bhv_desc_init(&(so->so_bhv),so,A,B) + +/* + * Remove a behavior descriptor from a behavior chain. + */ +#define bhv_remove(bhp, bdp) \ + { \ + if ((bhp)->bh_first == (bdp)) { \ + /* \ + * Remove from front of chain. \ + * Atomic wrt oip's. \ + */ \ + (bhp)->bh_first = (bdp)->bd_next; \ + } else { \ + /* remove from non-front of chain */ \ + bhv_remove_not_first(bhp, bdp); \ + } \ + (bdp)->bd_vobj = NULL; \ + } + +/* + * Behavior module prototypes. + */ +extern void bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp); +extern bhv_desc_t * bhv_lookup(bhv_head_t *bhp, void *ops); +extern bhv_desc_t * bhv_lookup_unlocked(bhv_head_t *bhp, void *ops); +extern bhv_desc_t * bhv_base_unlocked(bhv_head_t *bhp); + +#endif /* __XFS_BEHAVIOR_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_cred.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_cred.h --- linux-2.4.19/fs/xfs/linux/xfs_cred.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_cred.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_CRED_H__ +#define __XFS_CRED_H__ + +/* + * Credentials + */ +typedef struct cred { + /* EMPTY */ +} cred_t; + +extern struct cred *sys_cred; + +/* this is a hack.. (assums sys_cred is the only cred_t in the system) */ +static __inline int capable_cred(cred_t *cr, int cid) +{ + return (cr == sys_cred) ? 1 : capable(cid); +} + +#endif /* __XFS_CRED_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_file.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_file.c --- linux-2.4.19/fs/xfs/linux/xfs_file.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_file.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include /* for PROT_WRITE */ + +static struct vm_operations_struct linvfs_file_vm_ops; + + +STATIC ssize_t +linvfs_read( + struct file *filp, + char *buf, + size_t size, + loff_t *offset) +{ + vnode_t *vp; + int error; + + vp = LINVFS_GET_VP(filp->f_dentry->d_inode); + ASSERT(vp); + + VOP_READ(vp, filp, buf, size, offset, NULL, error); + + return(error); +} + + +STATIC ssize_t +linvfs_write( + struct file *file, + const char *buf, + size_t count, + loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + loff_t pos; + vnode_t *vp; + int err; /* Use negative errors in this f'n */ + + if ((ssize_t) count < 0) + return -EINVAL; + + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + + pos = *ppos; + err = -EINVAL; + if (pos < 0) + goto out; + + err = file->f_error; + if (err) { + file->f_error = 0; + goto out; + } + + vp = LINVFS_GET_VP(inode); + ASSERT(vp); + + /* We allow multiple direct writers in, there is no + * potential call to vmtruncate in that path. + */ + if (!(file->f_flags & O_DIRECT)) + down(&inode->i_sem); + + VOP_WRITE(vp, file, buf, count, &pos, NULL, err); + *ppos = pos; + + if (!(file->f_flags & O_DIRECT)) + up(&inode->i_sem); +out: + + return(err); +} + + +STATIC int +linvfs_open( + struct inode *inode, + struct file *filp) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + int error; + + if (!(filp->f_flags & O_LARGEFILE) && inode->i_size > MAX_NON_LFS) + return -EFBIG; + + ASSERT(vp); + VOP_OPEN(vp, NULL, error); + return -error; +} + + +STATIC int +linvfs_release( + struct inode *inode, + struct file *filp) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + int error = 0; + + if (vp) + VOP_RELEASE(vp, error); + return -error; +} + + +STATIC int +linvfs_fsync( + struct file *filp, + struct dentry *dentry, + int datasync) +{ + struct inode *inode = dentry->d_inode; + vnode_t *vp = LINVFS_GET_VP(inode); + int error; + int flags = FSYNC_WAIT; + + if (datasync) + flags |= FSYNC_DATA; + + ASSERT(vp); + + VOP_FSYNC(vp, flags, NULL, (off_t)0, (off_t)-1, error); + + return -error; +} + +/* + * linvfs_readdir maps to VOP_READDIR(). + * We need to build a uio, cred, ... + */ + +#define nextdp(dp) ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen)) + +STATIC int +linvfs_readdir( + struct file *filp, + void *dirent, + filldir_t filldir) +{ + int error = 0; + vnode_t *vp; + uio_t uio; + iovec_t iov; + int eof = 0; + caddr_t read_buf; + int namelen, size = 0; + size_t rlen = PAGE_CACHE_SIZE << 2; + off_t start_offset; + xfs_dirent_t *dbp = NULL; + + vp = LINVFS_GET_VP(filp->f_dentry->d_inode); + ASSERT(vp); + + /* Try fairly hard to get memory */ + do { + if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL))) + break; + rlen >>= 1; + } while (rlen >= 1024); + + if (read_buf == NULL) + return -ENOMEM; + + uio.uio_iov = &iov; + uio.uio_fmode = filp->f_mode; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_offset = filp->f_pos; + + while (!eof) { + uio.uio_resid = iov.iov_len = rlen; + iov.iov_base = read_buf; + uio.uio_iovcnt = 1; + + start_offset = uio.uio_offset; + + VOP_READDIR(vp, &uio, NULL, &eof, error); + if ((uio.uio_offset == start_offset) || error) { + size = 0; + break; + } + + size = rlen - uio.uio_resid; + dbp = (xfs_dirent_t *)read_buf; + while (size > 0) { + namelen = strlen(dbp->d_name); + + if (filldir(dirent, dbp->d_name, namelen, + (loff_t) dbp->d_off, + (ino_t) dbp->d_ino, + DT_UNKNOWN)) { + goto done; + } + size -= dbp->d_reclen; + dbp = nextdp(dbp); + } + } +done: + if (!error) { + if (size == 0) + filp->f_pos = uio.uio_offset; + else if (dbp) + filp->f_pos = dbp->d_off; + } + + kfree(read_buf); + return -error; +} + +STATIC int +linvfs_file_mmap( + struct file *filp, + struct vm_area_struct *vma) +{ + struct inode *ip = filp->f_dentry->d_inode; + vnode_t *vp = LINVFS_GET_VP(ip); + vattr_t va = { .va_mask = AT_UPDATIME }; + int error; + + if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) { + error = -xfs_dm_send_mmap_event(vma, 0); + if (error) + return error; + } + + vma->vm_ops = &linvfs_file_vm_ops; + + VOP_SETATTR(vp, &va, AT_UPDATIME, NULL, error); + UPDATE_ATIME(ip); + return 0; +} + + +STATIC int +linvfs_ioctl( + struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + int error; + vnode_t *vp = LINVFS_GET_VP(inode); + + ASSERT(vp); + VOP_IOCTL(vp, inode, filp, cmd, arg, error); + VMODIFY(vp); + + /* NOTE: some of the ioctl's return positive #'s as a + * byte count indicating success, such as + * readlink_by_handle. So we don't "sign flip" + * like most other routines. This means true + * errors need to be returned as a negative value. + */ + return error; +} + +#ifdef HAVE_VMOP_MPROTECT +STATIC int +linvfs_mprotect( + struct vm_area_struct *vma, + unsigned int newflags) +{ + vnode_t *vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode); + int error = 0; + + if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) { + if ((vma->vm_flags & VM_MAYSHARE) && + (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)){ + error = xfs_dm_send_mmap_event(vma, VM_WRITE); + } + } + return error; +} +#endif /* HAVE_VMOP_MPROTECT */ + + +struct file_operations linvfs_file_operations = { + .llseek = generic_file_llseek, + .read = linvfs_read, + .write = linvfs_write, + .ioctl = linvfs_ioctl, + .mmap = linvfs_file_mmap, + .open = linvfs_open, + .release = linvfs_release, + .fsync = linvfs_fsync, +}; + +struct file_operations linvfs_dir_operations = { + .read = generic_read_dir, + .readdir = linvfs_readdir, + .ioctl = linvfs_ioctl, + .fsync = linvfs_fsync, +}; + +static struct vm_operations_struct linvfs_file_vm_ops = { + .nopage = filemap_nopage, +#ifdef HAVE_VMOP_MPROTECT + .mprotect = linvfs_mprotect, +#endif +}; diff -Nur linux-2.4.19/fs/xfs/linux/xfs_fs_subr.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_fs_subr.c --- linux-2.4.19/fs/xfs/linux/xfs_fs_subr.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_fs_subr.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Implementation for VFS_DOUNMOUNT. + */ +int +fs_dounmount( + bhv_desc_t *bdp, + int flags, + vnode_t *rootvp, + cred_t *cr) +{ + struct vfs *vfsp = bhvtovfs(bdp); + bhv_desc_t *fbdp = vfsp->vfs_fbhv; + int error; + + /* + * Wait for sync to finish and lock vfsp. This also sets the + * VFS_OFFLINE flag. Once we do this we can give up reference + * the root vnode which we hold to avoid the another unmount + * ripping the vfs out from under us before we get to lock it. + * The VFS_DOUNMOUNT calling convention is that the reference + * on the rot vnode is released whether the call succeeds or + * fails. + */ + if (rootvp) + VN_RELE(rootvp); + + /* + * Now invoke SYNC and UNMOUNT ops, using the PVFS versions is + * OK since we already have a behavior lock as a result of + * being in VFS_DOUNMOUNT. It is necessary to do things this + * way since using the VFS versions would cause us to get the + * behavior lock twice which can cause deadlock as well as + * making the coding of vfs relocation unnecessarilty difficult + * by making relocations invoked by unmount occur in a different + * environment than those invoked by mount-update. + */ + PVFS_SYNC(fbdp, SYNC_ATTR|SYNC_DELWRI, cr, error); + if (error == 0) + PVFS_UNMOUNT(fbdp, flags, cr, error); + return error; +} + +/* + * Stub for no-op vnode operations that return error status. + */ +int +fs_noerr() +{ + return 0; +} + +/* + * Operation unsupported under this file system. + */ +int +fs_nosys() +{ + return ENOSYS; +} + +/* + * Stub for inactive, strategy, and read/write lock/unlock. Does nothing. + */ +/* ARGSUSED */ +void +fs_noval() +{ +} + +/* + * vnode pcache layer for vnode_tosspages. + * 'last' parameter unused but left in for IRIX compatibility + */ +void +fs_tosspages( + bhv_desc_t *bdp, + xfs_off_t first, + xfs_off_t last, + int fiopt) +{ + vnode_t *vp = BHV_TO_VNODE(bdp); + struct inode *ip = LINVFS_GET_IP(vp); + + if (VN_CACHED(vp)) + truncate_inode_pages(ip->i_mapping, first); +} + + +/* + * vnode pcache layer for vnode_flushinval_pages. + * 'last' parameter unused but left in for IRIX compatibility + */ +void +fs_flushinval_pages( + bhv_desc_t *bdp, + xfs_off_t first, + xfs_off_t last, + int fiopt) +{ + vnode_t *vp = BHV_TO_VNODE(bdp); + struct inode *ip = LINVFS_GET_IP(vp); + + if (VN_CACHED(vp)) { + filemap_fdatasync(ip->i_mapping); + fsync_inode_data_buffers(ip); + filemap_fdatawait(ip->i_mapping); + + truncate_inode_pages(ip->i_mapping, first); + } +} + +/* + * vnode pcache layer for vnode_flush_pages. + * 'last' parameter unused but left in for IRIX compatibility + */ +int +fs_flush_pages( + bhv_desc_t *bdp, + xfs_off_t first, + xfs_off_t last, + uint64_t flags, + int fiopt) +{ + vnode_t *vp = BHV_TO_VNODE(bdp); + struct inode *ip = LINVFS_GET_IP(vp); + + if (VN_CACHED(vp)) { + filemap_fdatasync(ip->i_mapping); + fsync_inode_data_buffers(ip); + filemap_fdatawait(ip->i_mapping); + } + + return 0; +} + diff -Nur linux-2.4.19/fs/xfs/linux/xfs_fs_subr.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_fs_subr.h --- linux-2.4.19/fs/xfs/linux/xfs_fs_subr.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_fs_subr.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUBR_H__ +#define __XFS_SUBR_H__ + +/* + * Utilities shared among file system implementations. + */ + +struct cred; + +extern int fs_noerr(void); +extern int fs_nosys(void); +extern int fs_nodev(void); +extern void fs_noval(void); +extern int fs_dounmount(bhv_desc_t *, int, vnode_t *, struct cred *); +extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +extern void fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); + +#endif /* __XFS_FS_SUBR_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_globals.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_globals.c --- linux-2.4.19/fs/xfs/linux/xfs_globals.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_globals.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains globals needed by XFS that were normally defined + * somewhere else in IRIX. + */ + +#include + +uint64_t xfs_panic_mask; /* set to cause more panics */ +unsigned long xfs_physmem; + +/* + * Used to serialize atomicIncWithWrap. + */ +spinlock_t Atomic_spin = SPIN_LOCK_UNLOCKED; + +/* + * Global system credential structure. + */ +cred_t sys_cred_val, *sys_cred = &sys_cred_val; + +/* + * The global quota manager. There is only one of these for the entire + * system, _not_ one per file system. XQM keeps track of the overall + * quota functionality, including maintaining the freelist and hash + * tables of dquots. + */ +struct xfs_qm *xfs_Gqm; +mutex_t xfs_Gqm_lock; + +/* Export XFS symbols used by xfsidbg */ +EXPORT_SYMBOL(xfs_Gqm); +EXPORT_SYMBOL(xfs_next_bit); +EXPORT_SYMBOL(xfs_contig_bits); diff -Nur linux-2.4.19/fs/xfs/linux/xfs_globals.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_globals.h --- linux-2.4.19/fs/xfs/linux/xfs_globals.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_globals.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_GLOBALS_H__ +#define __XFS_GLOBALS_H__ + +/* + * This file declares globals needed by XFS that were normally defined + * somewhere else in IRIX. + */ + +extern uint64_t xfs_panic_mask; /* set to cause more panics */ + +extern unsigned long xfs_physmem; + +extern struct cred *sys_cred; + +extern struct xfs_qm *xfs_Gqm; +extern mutex_t xfs_Gqm_lock; + +#endif /* __XFS_GLOBALS_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_ioctl.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_ioctl.c --- linux-2.4.19/fs/xfs/linux/xfs_ioctl.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_ioctl.c Tue Dec 3 16:31:18 2002 @@ -0,0 +1,1094 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include + + +extern int xfs_change_file_space(bhv_desc_t *, int, + xfs_flock64_t *, xfs_off_t, cred_t *, int); +extern int xfs_set_dmattrs(bhv_desc_t *, u_int, u_int16_t, cred_t *); + + +/* + * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to + * a file or fs handle. + * + * XFS_IOC_PATH_TO_FSHANDLE + * returns fs handle for a mount point or path within that mount point + * XFS_IOC_FD_TO_HANDLE + * returns full handle for a FD opened in user space + * XFS_IOC_PATH_TO_HANDLE + * returns full handle for a path + */ +STATIC int +xfs_find_handle( + unsigned int cmd, + unsigned long arg) +{ + int hsize; + xfs_handle_t handle; + xfs_fsop_handlereq_t hreq; + struct inode *inode; + struct vnode *vp; + + if (copy_from_user(&hreq, (xfs_fsop_handlereq_t *)arg, sizeof(hreq))) + return -XFS_ERROR(EFAULT); + + bzero((char *)&handle, sizeof(handle)); + + switch (cmd) { + case XFS_IOC_PATH_TO_FSHANDLE: + case XFS_IOC_PATH_TO_HANDLE: { + struct nameidata nd; + char *path; + int error; + + /* we need the path */ + path = getname(hreq.path); + if (IS_ERR(path)) + return PTR_ERR(path); + + /* traverse the path */ + error = 0; + if (path_init(path, LOOKUP_POSITIVE, &nd)) + error = path_walk(path, &nd); + putname(path); + if (error) + return error; + + ASSERT(nd.dentry); + ASSERT(nd.dentry->d_inode); + inode = igrab(nd.dentry->d_inode); + path_release(&nd); + break; + } + + case XFS_IOC_FD_TO_HANDLE: { + struct file *file; + + file = fget(hreq.fd); + if (!file) + return -EBADF; + + ASSERT(file->f_dentry); + ASSERT(file->f_dentry->d_inode); + inode = igrab(file->f_dentry->d_inode); + fput(file); + + break; + } + + default: + ASSERT(0); + return -XFS_ERROR(EINVAL); + } + + if (inode->i_sb->s_magic != XFS_SB_MAGIC) { + /* we're not in XFS anymore, Toto */ + iput(inode); + return -XFS_ERROR(EINVAL); + } + + /* we need the vnode */ + vp = LINVFS_GET_VP(inode); + if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) { + iput(inode); + return -XFS_ERROR(EBADF); + } + + /* now we can grab the fsid */ + memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t)); + hsize = sizeof(xfs_fsid_t); + + if (cmd != XFS_IOC_PATH_TO_FSHANDLE) { + xfs_inode_t *ip; + bhv_desc_t *bhv; + int lock_mode; + + /* need to get access to the xfs_inode to read the generation */ + VN_BHV_READ_LOCK(&(vp)->v_bh); + bhv = VNODE_TO_FIRST_BHV(vp); + ASSERT(bhv); + ip = XFS_BHVTOI(bhv); + ASSERT(ip); + lock_mode = xfs_ilock_map_shared(ip); + + /* fill in fid section of handle from inode */ + handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.xfs_fid_len); + handle.ha_fid.xfs_fid_pad = 0; + handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen; + handle.ha_fid.xfs_fid_ino = ip->i_ino; + + xfs_iunlock_map_shared(ip, lock_mode); + VN_BHV_READ_UNLOCK(&(vp)->v_bh); + + hsize = XFS_HSIZE(handle); + } + + /* now copy our handle into the user buffer & write out the size */ + if (copy_to_user((xfs_handle_t *)hreq.ohandle, &handle, hsize) || + copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) { + iput(inode); + return -XFS_ERROR(EFAULT); + } + + iput(inode); + return 0; +} + + +/* + * Convert userspace handle data into vnode (and inode). + * We [ab]use the fact that all the fsop_handlereq ioctl calls + * have a data structure argument whose first component is always + * a xfs_fsop_handlereq_t, so we can cast to and from this type. + * This allows us to optimise the copy_from_user calls and gives + * a handy, shared routine. + * + * If no error, caller must always VN_RELE the returned vp. + */ +STATIC int +xfs_vget_fsop_handlereq( + xfs_mount_t *mp, + struct inode *parinode, /* parent inode pointer */ + int cap, /* capability level for op */ + unsigned long arg, /* userspace data pointer */ + unsigned long size, /* size of expected struct */ + /* output arguments */ + xfs_fsop_handlereq_t *hreq, + vnode_t **vp, + struct inode **inode) +{ + void *hanp; + size_t hlen; + xfs_fid_t *xfid; + xfs_handle_t *handlep; + xfs_handle_t handle; + xfs_inode_t *ip; + struct inode *inodep; + vnode_t *vpp; + __u32 igen; + ino_t ino; + int error; + + if (!capable(cap)) + return XFS_ERROR(EPERM); + + /* + * Only allow handle opens under a directory. + */ + if (!S_ISDIR(parinode->i_mode)) + return XFS_ERROR(ENOTDIR); + + /* + * Copy the handle down from the user and validate + * that it looks to be in the correct format. + */ + if (copy_from_user(hreq, (struct xfs_fsop_handlereq *)arg, size)) + return XFS_ERROR(EFAULT); + + hanp = hreq->ihandle; + hlen = hreq->ihandlen; + handlep = &handle; + + if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) + return XFS_ERROR(EINVAL); + if (copy_from_user(handlep, hanp, hlen)) + return XFS_ERROR(EFAULT); + if (hlen < sizeof(*handlep)) + bzero(((char *)handlep) + hlen, sizeof(*handlep) - hlen); + if (hlen > sizeof(handlep->ha_fsid)) { + if (handlep->ha_fid.xfs_fid_len != + (hlen - sizeof(handlep->ha_fsid) + - sizeof(handlep->ha_fid.xfs_fid_len)) + || handlep->ha_fid.xfs_fid_pad) + return XFS_ERROR(EINVAL); + } + + /* + * Crack the handle, obtain the inode # & generation # + */ + xfid = (struct xfs_fid *)&handlep->ha_fid; + if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { + ino = xfid->xfs_fid_ino; + igen = xfid->xfs_fid_gen; + } else { + return XFS_ERROR(EINVAL); + } + + /* + * Get the XFS inode, building a vnode to go with it. + */ + error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + if (error) + return error; + if (ip == NULL) + return XFS_ERROR(EIO); + if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { + xfs_iput_new(ip, XFS_ILOCK_SHARED); + return XFS_ERROR(ENOENT); + } + + vpp = XFS_ITOV(ip); + inodep = LINVFS_GET_IP(vpp); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + error = linvfs_revalidate_core(inodep, ATTR_COMM); + if (error) { + iput(inodep); + /* this error is (-) but our callers expect + */ + return XFS_ERROR(-error); + } + + *vp = vpp; + *inode = inodep; + return 0; +} + +STATIC int +xfs_open_by_handle( + xfs_mount_t *mp, + unsigned long arg, + struct file *parfilp, + struct inode *parinode) +{ + int error; + int new_fd; + int permflag; + struct file *filp; + struct inode *inode; + struct dentry *dentry; + vnode_t *vp; + xfs_fsop_handlereq_t hreq; + struct list_head *lp; + + error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, + sizeof(xfs_fsop_handlereq_t), + &hreq, &vp, &inode); + if (error) + return -error; + + /* Restrict xfs_open_by_handle to directories & regular files. */ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { + iput(inode); + return -XFS_ERROR(EINVAL); + } + +#if BITS_PER_LONG != 32 + hreq.oflags |= O_LARGEFILE; +#endif + /* Put open permission in namei format. */ + permflag = hreq.oflags; + if ((permflag+1) & O_ACCMODE) + permflag++; + if (permflag & O_TRUNC) + permflag |= 2; + + /* Can't write directories. */ + if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { + iput(inode); + return -XFS_ERROR(EISDIR); + } + + if ((new_fd = get_unused_fd()) < 0) { + iput(inode); + return new_fd; + } + + /* Now to find a dentry. If possible, get a well-connected one. */ + spin_lock(&dcache_lock); + for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { + dentry = list_entry(lp, struct dentry, d_alias); + if (! (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) { + dget_locked(dentry); + dentry->d_vfs_flags |= DCACHE_REFERENCED; + spin_unlock(&dcache_lock); + iput(inode); + goto found; + } + } + spin_unlock(&dcache_lock); + + /* ELSE didn't find dentry. Create anonymous dcache entry. */ + dentry = d_alloc_root(inode); + if (dentry == NULL) { + iput(inode); + put_unused_fd(new_fd); + return -XFS_ERROR(ENOMEM); + } + + /* Keep nfsd happy. */ + dentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + + found: + /* Ensure umount returns EBUSY on umounts while this file is open. */ + mntget(parfilp->f_vfsmnt); + + /* Create file pointer. */ + filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags); + if (IS_ERR(filp)) { + put_unused_fd(new_fd); + return -XFS_ERROR(-PTR_ERR(filp)); + } + filp->f_mode |= FINVIS; + + fd_install(new_fd, filp); + return new_fd; +} + +STATIC int +xfs_readlink_by_handle( + xfs_mount_t *mp, + unsigned long arg, + struct file *parfilp, + struct inode *parinode) +{ + int error; + struct iovec aiov; + struct uio auio; + struct inode *inode; + xfs_fsop_handlereq_t hreq; + vnode_t *vp; + __u32 olen; + + error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, + sizeof(xfs_fsop_handlereq_t), + &hreq, &vp, &inode); + if (error) + return -error; + + /* Restrict this handle operation to symlinks only. */ + if (vp->v_type != VLNK) { + VN_RELE(vp); + return -XFS_ERROR(EINVAL); + } + + if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) { + VN_RELE(vp); + return -XFS_ERROR(EFAULT); + } + aiov.iov_len = olen; + aiov.iov_base = hreq.ohandle; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_fmode = FINVIS; + auio.uio_offset = 0; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_resid = olen; + + VOP_READLINK(vp, &auio, NULL, error); + + VN_RELE(vp); + return (olen - auio.uio_resid); +} + +STATIC int +xfs_fssetdm_by_handle( + xfs_mount_t *mp, + unsigned long arg, + struct file *parfilp, + struct inode *parinode) +{ + int error; + struct fsdmidata fsd; + xfs_fsop_setdm_handlereq_t dmhreq; + struct inode *inode; + bhv_desc_t *bdp; + vnode_t *vp; + + error = xfs_vget_fsop_handlereq(mp, parinode, CAP_MKNOD, arg, + sizeof(xfs_fsop_setdm_handlereq_t), + (xfs_fsop_handlereq_t *)&dmhreq, + &vp, &inode); + if (error) + return -error; + + if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { + VN_RELE(vp); + return -XFS_ERROR(EFAULT); + } + + bdp = bhv_base_unlocked(VN_BHV_HEAD(vp)); + error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL); + + VN_RELE(vp); + if (error) + return -error; + return 0; +} + +STATIC int +xfs_attrlist_by_handle( + xfs_mount_t *mp, + unsigned long arg, + struct file *parfilp, + struct inode *parinode) +{ + int error; + attrlist_cursor_kern_t *cursor; + xfs_fsop_attrlist_handlereq_t al_hreq; + struct inode *inode; + vnode_t *vp; + + error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, + sizeof(xfs_fsop_attrlist_handlereq_t), + (xfs_fsop_handlereq_t *)&al_hreq, + &vp, &inode); + if (error) + return -error; + + cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; + VOP_ATTR_LIST(vp, al_hreq.buffer, al_hreq.buflen, al_hreq.flags, + cursor, NULL, error); + VN_RELE(vp); + if (error) + return -error; + return 0; +} + +STATIC int +xfs_attrmulti_by_handle( + xfs_mount_t *mp, + unsigned long arg, + struct file *parfilp, + struct inode *parinode) +{ + int error; + xfs_attr_multiop_t *ops; + xfs_fsop_attrmulti_handlereq_t am_hreq; + struct inode *inode; + vnode_t *vp; + int i, size; + + error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, + sizeof(xfs_fsop_attrmulti_handlereq_t), + (xfs_fsop_handlereq_t *)&am_hreq, + &vp, &inode); + if (error) + return -error; + + size = am_hreq.opcount * sizeof(attr_multiop_t); + ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL); + if (!ops) { + VN_RELE(vp); + return -XFS_ERROR(ENOMEM); + } + + if (copy_from_user(ops, am_hreq.ops, size)) { + kfree(ops); + VN_RELE(vp); + return -XFS_ERROR(EFAULT); + } + + for (i = 0; i < am_hreq.opcount; i++) { + switch(ops[i].am_opcode) { + case ATTR_OP_GET: + VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue, + &ops[i].am_length, ops[i].am_flags, + NULL, ops[i].am_error); + break; + case ATTR_OP_SET: + VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue, + ops[i].am_length, ops[i].am_flags, + NULL, ops[i].am_error); + break; + case ATTR_OP_REMOVE: + VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags, + NULL, ops[i].am_error); + break; + default: + ops[i].am_error = EINVAL; + } + } + + if (copy_to_user(am_hreq.ops, ops, size)) + error = -XFS_ERROR(EFAULT); + + kfree(ops); + VN_RELE(vp); + return error; +} + +/* prototypes for a few of the stack-hungry cases that have + * their own functions. Functions are defined after their use + * so gcc doesn't get fancy and inline them with -03 */ + +int xfs_ioc_space( + bhv_desc_t *bdp, + vnode_t *vp, + struct file *filp, + unsigned int cmd, + unsigned long arg); + +int xfs_ioc_bulkstat( + xfs_mount_t *mp, + unsigned int cmd, + unsigned long arg); + +int xfs_ioc_fsgeometry_v1( + xfs_mount_t *mp, + unsigned long arg); + +int xfs_ioc_fsgeometry( + xfs_mount_t *mp, + unsigned long arg); + +int xfs_ioc_xattr( + vnode_t *vp, + struct file *filp, + unsigned int cmd, + unsigned long arg); + +int xfs_ioc_getbmap( + bhv_desc_t *bdp, + struct file *filp, + unsigned int cmd, + unsigned long arg); + +int xfs_ioc_getbmapx( + bhv_desc_t *bdp, + unsigned long arg); + +int +xfs_ioctl( + bhv_desc_t *bdp, + struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + int error; + vnode_t *vp; + xfs_inode_t *ip; + xfs_mount_t *mp; + + vp = LINVFS_GET_VP(inode); + + vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + switch (cmd) { + + case XFS_IOC_ALLOCSP: + case XFS_IOC_FREESP: + case XFS_IOC_RESVSP: + case XFS_IOC_UNRESVSP: + case XFS_IOC_ALLOCSP64: + case XFS_IOC_FREESP64: + case XFS_IOC_RESVSP64: + case XFS_IOC_UNRESVSP64: + return xfs_ioc_space(bdp, vp, filp, cmd, arg); + + case XFS_IOC_DIOINFO: { + struct dioattr da; + + da.d_miniosz = mp->m_sb.sb_blocksize; + da.d_mem = mp->m_sb.sb_blocksize; + + /* + * this only really needs to be BBSIZE. + * it is set to the file system block size to + * avoid having to do block zeroing on short writes. + */ + da.d_maxiosz = XFS_FSB_TO_B(mp, + XFS_B_TO_FSBT(mp, KIO_MAX_ATOMIC_IO << 10)); + + if (copy_to_user((struct dioattr *)arg, &da, sizeof(da))) + return -XFS_ERROR(EFAULT); + return 0; + } + + case XFS_IOC_FSBULKSTAT_SINGLE: + case XFS_IOC_FSBULKSTAT: + case XFS_IOC_FSINUMBERS: + return xfs_ioc_bulkstat(mp, cmd, arg); + + case XFS_IOC_FSGEOMETRY_V1: + return xfs_ioc_fsgeometry_v1(mp, arg); + + case XFS_IOC_FSGEOMETRY: + return xfs_ioc_fsgeometry(mp, arg); + + case XFS_IOC_FSGETXATTR: + case XFS_IOC_FSSETXATTR: + case XFS_IOC_FSGETXATTRA: + return xfs_ioc_xattr(vp, filp, cmd, arg); + + case XFS_IOC_FSSETDM: { + struct fsdmidata dmi; + + if (copy_from_user(&dmi, (struct fsdmidata *)arg, sizeof(dmi))) + return -XFS_ERROR(EFAULT); + + error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate, + NULL); + if (error) + return -error; + return 0; + } + + case XFS_IOC_GETBMAP: + case XFS_IOC_GETBMAPA: + return xfs_ioc_getbmap(bdp, filp, cmd, arg); + + case XFS_IOC_GETBMAPX: + return xfs_ioc_getbmapx(bdp, arg); + + case XFS_IOC_FD_TO_HANDLE: + case XFS_IOC_PATH_TO_HANDLE: + case XFS_IOC_PATH_TO_FSHANDLE: + return xfs_find_handle(cmd, arg); + + case XFS_IOC_OPEN_BY_HANDLE: + return xfs_open_by_handle(mp, arg, filp, inode); + + case XFS_IOC_FSSETDM_BY_HANDLE: + return xfs_fssetdm_by_handle(mp, arg, filp, inode); + + case XFS_IOC_READLINK_BY_HANDLE: + return xfs_readlink_by_handle(mp, arg, filp, inode); + + case XFS_IOC_ATTRLIST_BY_HANDLE: + return xfs_attrlist_by_handle(mp, arg, filp, inode); + + case XFS_IOC_ATTRMULTI_BY_HANDLE: + return xfs_attrmulti_by_handle(mp, arg, filp, inode); + + case XFS_IOC_SWAPEXT: { + error = xfs_swapext((struct xfs_swapext *)arg); + if (error) + return -error; + return 0; + } + + case XFS_IOC_FSCOUNTS: { + xfs_fsop_counts_t out; + + error = xfs_fs_counts(mp, &out); + if (error) + return -error; + + if (copy_to_user((char *)arg, &out, sizeof(out))) + return -XFS_ERROR(EFAULT); + return 0; + } + + case XFS_IOC_SET_RESBLKS: { + xfs_fsop_resblks_t inout; + __uint64_t in; + + /* Only allow the sys admin to reserve space unless + * unwritten extents are enabled. + */ + if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&inout, (char *)arg, sizeof(inout))) + return -XFS_ERROR(EFAULT); + + /* input parameter is passed in resblks field of structure */ + in = inout.resblks; + error = xfs_reserve_blocks(mp, &in, &inout); + + if (copy_to_user((char *)arg, &inout, sizeof(inout))) + return -XFS_ERROR(EFAULT); + return 0; + } + + case XFS_IOC_GET_RESBLKS: { + xfs_fsop_resblks_t out; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + error = xfs_reserve_blocks(mp, NULL, &out); + if (error) + return -error; + + if (copy_to_user((char *)arg, &out, sizeof(out))) + return -XFS_ERROR(EFAULT); + + return 0; + } + + case XFS_IOC_FSGROWFSDATA: { + xfs_growfs_data_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&in, (char *)arg, sizeof(in))) + return -XFS_ERROR(EFAULT); + + error = xfs_growfs_data(mp, &in); + if (error) + return -error; + return 0; + } + + case XFS_IOC_FSGROWFSLOG: { + xfs_growfs_log_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&in, (char *)arg, sizeof(in))) + return -XFS_ERROR(EFAULT); + + error = xfs_growfs_log(mp, &in); + if (error) + return -error; + return 0; + } + + case XFS_IOC_FSGROWFSRT: { + xfs_growfs_rt_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&in, (char *)arg, sizeof(in))) + return -XFS_ERROR(EFAULT); + + error = xfs_growfs_rt(mp, &in); + if (error) + return -error; + return 0; + } + + case XFS_IOC_FREEZE: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + xfs_fs_freeze(mp); + return 0; + + case XFS_IOC_THAW: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + xfs_fs_thaw(mp); + return 0; + + case XFS_IOC_ERROR_INJECTION: { + xfs_error_injection_t in; + + if (copy_from_user(&in, (char *)arg, sizeof(in))) + return -XFS_ERROR(EFAULT); + + error = xfs_errortag_add(in.errtag, mp); + if (error) + return -error; + return 0; + } + + case XFS_IOC_ERROR_CLEARALL: + error = xfs_errortag_clearall(mp); + return -error; + + default: + return -ENOTTY; + } +} + +int xfs_ioc_space( + bhv_desc_t *bdp, + vnode_t *vp, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + xfs_flock64_t bf; + int attr_flags = 0; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -XFS_ERROR(EPERM); + + if (filp->f_flags & O_RDONLY) + return -XFS_ERROR(EBADF); + + if (vp->v_type != VREG) + return -XFS_ERROR(EINVAL); + + if (copy_from_user(&bf, (xfs_flock64_t *)arg, sizeof(bf))) + return -XFS_ERROR(EFAULT); + + if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) + attr_flags |= ATTR_NONBLOCK; + if (filp->f_mode & FINVIS) + attr_flags |= ATTR_DMI; + + error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos, + NULL, attr_flags); + return -error; +} + +int xfs_ioc_bulkstat( + xfs_mount_t *mp, + unsigned int cmd, + unsigned long arg) +{ + xfs_fsop_bulkreq_t bulkreq; + int count; /* # of records returned */ + xfs_ino_t inlast; /* last inode number */ + int done; + int error; + /* done = 1 if there are more stats to get and if bulkstat */ + /* should be called again (unused here, but used in dmapi) */ + + /* Do not allow space reservation if this is not the admin and + * unwritten extents are turned off. + */ + if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (XFS_FORCED_SHUTDOWN(mp)) + return -XFS_ERROR(EIO); + + if (copy_from_user(&bulkreq, (xfs_fsop_bulkreq_t *)arg, + sizeof(xfs_fsop_bulkreq_t))) + return -XFS_ERROR(EFAULT); + + if (copy_from_user(&inlast, (__s64 *)bulkreq.lastip, + sizeof(__s64))) + return -XFS_ERROR(EFAULT); + + if ((count = bulkreq.icount) <= 0) + return -XFS_ERROR(EINVAL); + + if (cmd == XFS_IOC_FSINUMBERS) + error = xfs_inumbers(mp, NULL, &inlast, &count, + bulkreq.ubuffer); + else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) + error = xfs_bulkstat_single(mp, &inlast, + bulkreq.ubuffer, &done); + else { /* XFS_IOC_FSBULKSTAT */ + if (count == 1 && inlast != 0) { + inlast++; + error = xfs_bulkstat_single(mp, &inlast, + bulkreq.ubuffer, &done); + } else { + error = xfs_bulkstat(mp, NULL, &inlast, &count, + (bulkstat_one_pf)xfs_bulkstat_one, + sizeof(xfs_bstat_t), bulkreq.ubuffer, + BULKSTAT_FG_QUICK, &done); + } + } + + if (error) + return -error; + + if (bulkreq.ocount != NULL) { + if (copy_to_user((xfs_ino_t *)bulkreq.lastip, &inlast, + sizeof(xfs_ino_t))) + return -XFS_ERROR(EFAULT); + + if (copy_to_user((__s32 *)bulkreq.ocount, &count, + sizeof(count))) + return -XFS_ERROR(EFAULT); + } + + return 0; +} + +int xfs_ioc_fsgeometry_v1( + xfs_mount_t *mp, + unsigned long arg) +{ + xfs_fsop_geom_v1_t fsgeo; + int error; + + error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3); + if (error) + return -error; + + if (copy_to_user((xfs_fsop_geom_t *)arg, &fsgeo, sizeof(fsgeo))) + return -XFS_ERROR(EFAULT); + return 0; +} + +int xfs_ioc_fsgeometry( + xfs_mount_t *mp, + unsigned long arg) +{ + xfs_fsop_geom_t fsgeo; + int error; + + error = xfs_fs_geometry(mp, &fsgeo, 4); + if (error) + return -error; + + if (copy_to_user((xfs_fsop_geom_t *)arg, &fsgeo, sizeof(fsgeo))) + return -XFS_ERROR(EFAULT); + return 0; +} + +int xfs_ioc_xattr( + vnode_t *vp, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + struct fsxattr fa; + vattr_t va; + int error; + + switch (cmd) { + case XFS_IOC_FSGETXATTR: { + va.va_mask = AT_XFLAGS|AT_EXTSIZE|AT_NEXTENTS; + VOP_GETATTR(vp, &va, 0, NULL, error); + if (error) + return -error; + + fa.fsx_xflags = va.va_xflags; + fa.fsx_extsize = va.va_extsize; + fa.fsx_nextents = va.va_nextents; + + if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa))) + return -XFS_ERROR(EFAULT); + return 0; + } + + case XFS_IOC_FSSETXATTR: { + int attr_flags = 0; + + if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa))) + return -XFS_ERROR(EFAULT); + + va.va_mask = AT_XFLAGS | AT_EXTSIZE; + va.va_xflags = fa.fsx_xflags; + va.va_extsize = fa.fsx_extsize; + + if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) + attr_flags |= ATTR_NONBLOCK; + + VOP_SETATTR(vp, &va, attr_flags, NULL, error); + return -error; + } + + case XFS_IOC_FSGETXATTRA: { + + va.va_mask = AT_XFLAGS|AT_EXTSIZE|AT_ANEXTENTS; + VOP_GETATTR(vp, &va, 0, NULL, error); + if (error) + return -error; + + fa.fsx_xflags = va.va_xflags; + fa.fsx_extsize = va.va_extsize; + fa.fsx_nextents = va.va_anextents; + + if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa))) + return -XFS_ERROR(EFAULT); + return 0; + } + + default: + return -ENOTTY; + + } +} + +int xfs_ioc_getbmap( + bhv_desc_t *bdp, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + struct getbmap bm; + int iflags; + int error; + + if (copy_from_user(&bm, (struct getbmap *)arg, sizeof(bm))) + return -XFS_ERROR(EFAULT); + + if (bm.bmv_count < 2) + return -XFS_ERROR(EINVAL); + + iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); + if (filp->f_mode & FINVIS) + iflags |= BMV_IF_NO_DMAPI_READ; + + error = xfs_getbmap(bdp, &bm, (struct getbmap *)arg+1, iflags); + if (error) + return -error; + + if (copy_to_user((struct getbmap *)arg, &bm, sizeof(bm))) + return -XFS_ERROR(EFAULT); + return 0; +} + +int xfs_ioc_getbmapx( + bhv_desc_t *bdp, + unsigned long arg) +{ + struct getbmapx bmx; + struct getbmap bm; + int iflags; + int error; + + if (copy_from_user(&bmx, (struct getbmapx *)arg, sizeof(bmx))) + return -XFS_ERROR(EFAULT); + + if (bmx.bmv_count < 2) + return -XFS_ERROR(EINVAL); + + /* + * Map input getbmapx structure to a getbmap + * structure for xfs_getbmap. + */ + GETBMAP_CONVERT(bmx, bm); + + iflags = bmx.bmv_iflags; + + if (iflags & (~BMV_IF_VALID)) + return -XFS_ERROR(EINVAL); + + iflags |= BMV_IF_EXTENDED; + + error = xfs_getbmap(bdp, &bm, (struct getbmapx *)arg+1, iflags); + if (error) + return -error; + + GETBMAP_CONVERT(bm, bmx); + + if (copy_to_user((struct getbmapx *)arg, &bmx, sizeof(bmx))) + return -XFS_ERROR(EFAULT); + + return 0; +} diff -Nur linux-2.4.19/fs/xfs/linux/xfs_iops.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_iops.c --- linux-2.4.19/fs/xfs/linux/xfs_iops.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_iops.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,871 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + + +/* + * Pull the link count and size up from the xfs inode to the linux inode + */ +STATIC void +validate_fields( + struct inode *ip) +{ + vnode_t *vp = LINVFS_GET_VP(ip); + vattr_t va; + int error; + + va.va_mask = AT_NLINK|AT_SIZE; + VOP_GETATTR(vp, &va, ATTR_LAZY, NULL, error); + ip->i_nlink = va.va_nlink; + ip->i_size = va.va_size; + ip->i_blocks = va.va_nblocks; +} + +#ifdef CONFIG_FS_POSIX_ACL +/* + * Determine whether a process has a valid fs_struct (kernel daemons + * like knfsd don't have an fs_struct). + */ +STATIC int inline +has_fs_struct(struct task_struct *task) +{ + return (task->fs != init_task.fs); +} +#endif + +STATIC int +linvfs_mknod( + struct inode *dir, + struct dentry *dentry, + int mode, + int rdev) +{ + struct inode *ip; + vattr_t va; + vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir); + xattr_exists_t test_default_acl = _ACL_DEFAULT_EXISTS; + int have_default_acl = 0; + int error = EINVAL; + + if (test_default_acl) + have_default_acl = test_default_acl(dvp); + +#ifdef CONFIG_FS_POSIX_ACL + /* + * Conditionally compiled so that the ACL base kernel changes can be + * split out into separate patches - remove this once MS_POSIXACL is + * accepted, or some other way to implement this exists. + */ + if (IS_POSIXACL(dir) && !have_default_acl && has_fs_struct(current)) + mode &= ~current->fs->umask; +#endif + + bzero(&va, sizeof(va)); + va.va_mask = AT_TYPE|AT_MODE; + va.va_type = IFTOVT(mode); + va.va_mode = mode; + + switch (mode & S_IFMT) { + case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: + va.va_rdev = rdev; + va.va_mask |= AT_RDEV; + /*FALLTHROUGH*/ + case S_IFREG: + VOP_CREATE(dvp, dentry, &va, &vp, NULL, error); + break; + case S_IFDIR: + VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error); + break; + default: + error = EINVAL; + break; + } + + if (!error) { + ASSERT(vp); + ip = LINVFS_GET_IP(vp); + if (!ip) { + VN_RELE(vp); + return -ENOMEM; + } + + if (S_ISCHR(mode) || S_ISBLK(mode)) + ip->i_rdev = to_kdev_t(rdev); + /* linvfs_revalidate_core returns (-) errors */ + error = -linvfs_revalidate_core(ip, ATTR_COMM); + validate_fields(dir); + d_instantiate(dentry, ip); + mark_inode_dirty_sync(ip); + mark_inode_dirty_sync(dir); + } + + if (!error && have_default_acl) { + _ACL_DECL (pdacl); + + if (!_ACL_ALLOC(pdacl)) { + error = -ENOMEM; + } else { + if (_ACL_GET_DEFAULT(dvp, pdacl)) + error = _ACL_INHERIT(vp, &va, pdacl); + VMODIFY(vp); + _ACL_FREE(pdacl); + } + } + return -error; +} + +STATIC int +linvfs_create( + struct inode *dir, + struct dentry *dentry, + int mode) +{ + return linvfs_mknod(dir, dentry, mode, 0); +} + +STATIC int +linvfs_mkdir( + struct inode *dir, + struct dentry *dentry, + int mode) +{ + return linvfs_mknod(dir, dentry, mode|S_IFDIR, 0); +} + + +STATIC struct dentry * +linvfs_lookup( + struct inode *dir, + struct dentry *dentry) +{ + int error; + vnode_t *vp, *cvp; + struct inode *ip = NULL; + + if (dentry->d_name.len >= MAXNAMELEN) + return ERR_PTR(-ENAMETOOLONG); + + cvp = NULL; + vp = LINVFS_GET_VP(dir); + VOP_LOOKUP(vp, dentry, &cvp, 0, NULL, NULL, error); + if (!error) { + ASSERT(cvp); + ip = LINVFS_GET_IP(cvp); + if (!ip) { + VN_RELE(cvp); + return ERR_PTR(-EACCES); + } + error = -linvfs_revalidate_core(ip, ATTR_COMM); + } + if (error && (error != ENOENT)) + return ERR_PTR(-error); + d_add(dentry, ip); /* Negative entry goes in if ip is NULL */ + return NULL; +} + +STATIC int +linvfs_link( + struct dentry *old_dentry, + struct inode *dir, + struct dentry *dentry) +{ + int error; + vnode_t *tdvp; /* Target directory for new name/link */ + vnode_t *vp; /* vp of name being linked */ + struct inode *ip; /* inode of guy being linked to */ + + ip = old_dentry->d_inode; /* inode being linked to */ + if (S_ISDIR(ip->i_mode)) + return -EPERM; + + tdvp = LINVFS_GET_VP(dir); + vp = LINVFS_GET_VP(ip); + + error = 0; + VOP_LINK(tdvp, vp, dentry, NULL, error); + if (!error) { + VMODIFY(tdvp); + VN_HOLD(vp); + validate_fields(ip); + d_instantiate(dentry, ip); + mark_inode_dirty_sync(ip); + } + return -error; +} + +STATIC int +linvfs_unlink( + struct inode *dir, + struct dentry *dentry) +{ + int error = 0; + struct inode *inode; + vnode_t *dvp; /* directory containing name to remove */ + + inode = dentry->d_inode; + + dvp = LINVFS_GET_VP(dir); + + VOP_REMOVE(dvp, dentry, NULL, error); + + if (!error) { + validate_fields(dir); /* For size only */ + validate_fields(inode); + mark_inode_dirty_sync(inode); + mark_inode_dirty_sync(dir); + } + + return -error; +} + +STATIC int +linvfs_symlink( + struct inode *dir, + struct dentry *dentry, + const char *symname) +{ + int error; + vnode_t *dvp; /* directory containing name to remove */ + vnode_t *cvp; /* used to lookup symlink to put in dentry */ + vattr_t va; + struct inode *ip = NULL; + + dvp = LINVFS_GET_VP(dir); + + bzero(&va, sizeof(va)); + va.va_type = VLNK; + va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO; + va.va_mask = AT_TYPE|AT_MODE; + + error = 0; + VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error); + if (!error) { + ASSERT(cvp); + ASSERT(cvp->v_type == VLNK); + ip = LINVFS_GET_IP(cvp); + if (!ip) { + error = ENOMEM; + VN_RELE(cvp); + } else { + /* linvfs_revalidate_core returns (-) errors */ + error = -linvfs_revalidate_core(ip, ATTR_COMM); + d_instantiate(dentry, ip); + validate_fields(dir); + validate_fields(ip); /* size needs update */ + mark_inode_dirty_sync(ip); + mark_inode_dirty_sync(dir); + } + } + return -error; +} + +STATIC int +linvfs_rmdir( + struct inode *dir, + struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + vnode_t *dvp = LINVFS_GET_VP(dir); + int error; + + VOP_RMDIR(dvp, dentry, NULL, error); + if (!error) { + validate_fields(inode); + validate_fields(dir); + mark_inode_dirty_sync(inode); + mark_inode_dirty_sync(dir); + } + return -error; +} + +STATIC int +linvfs_rename( + struct inode *odir, + struct dentry *odentry, + struct inode *ndir, + struct dentry *ndentry) +{ + int error; + vnode_t *fvp; /* from directory */ + vnode_t *tvp; /* target directory */ + struct inode *new_inode = NULL; + + fvp = LINVFS_GET_VP(odir); + tvp = LINVFS_GET_VP(ndir); + + new_inode = ndentry->d_inode; + + VOP_RENAME(fvp, odentry, tvp, ndentry, NULL, error); + if (error) + return -error; + + if (new_inode) { + validate_fields(new_inode); + } + + validate_fields(odir); + if (ndir != odir) + validate_fields(ndir); + mark_inode_dirty(ndir); + return 0; +} + +STATIC int +linvfs_readlink( + struct dentry *dentry, + char *buf, + int size) +{ + vnode_t *vp; + uio_t uio; + iovec_t iov; + int error; + + vp = LINVFS_GET_VP(dentry->d_inode); + + iov.iov_base = buf; + iov.iov_len = size; + + uio.uio_iov = &iov; + uio.uio_offset = 0; + uio.uio_segflg = UIO_USERSPACE; + uio.uio_resid = size; + + VOP_READLINK(vp, &uio, NULL, error); + if (error) + return -error; + + return (size - uio.uio_resid); +} + +/* + * careful here - this function can get called recursively, so + * we need to be very careful about how much stack we use. + * uio is kmalloced for this reason... + */ +STATIC int +linvfs_follow_link( + struct dentry *dentry, + struct nameidata *nd) +{ + vnode_t *vp; + uio_t *uio; + iovec_t iov; + int error; + char *link; + + ASSERT(dentry); + ASSERT(nd); + + link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL); + if (!link) + return -ENOMEM; + + uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL); + if (!uio) { + kfree(link); + return -ENOMEM; + } + + vp = LINVFS_GET_VP(dentry->d_inode); + + iov.iov_base = link; + iov.iov_len = MAXNAMELEN; + + uio->uio_iov = &iov; + uio->uio_offset = 0; + uio->uio_segflg = UIO_SYSSPACE; + uio->uio_resid = MAXNAMELEN; + uio->uio_fmode = 0; + + VOP_READLINK(vp, uio, NULL, error); + if (error) { + kfree(uio); + kfree(link); + return -error; + } + + link[MAXNAMELEN - uio->uio_resid] = '\0'; + kfree(uio); + + /* vfs_follow_link returns (-) errors */ + error = vfs_follow_link(nd, link); + kfree(link); + return error; +} + +STATIC int +linvfs_permission( + struct inode *inode, + int mode) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + int error; + + mode <<= 6; /* convert from linux to vnode access bits */ + VOP_ACCESS(vp, mode, NULL, error); + return -error; +} + +/* Brute force approach for now - copy data into linux inode + * from the results of a getattr. This gets called out of things + * like stat. + */ +int +linvfs_revalidate_core( + struct inode *inode, + int flags) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + + /* vn_revalidate returns (-) error so this is ok */ + return vn_revalidate(vp, flags); +} + +STATIC int +linvfs_revalidate( + struct dentry *dentry) +{ + vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); + + if (unlikely(vp->v_flag & VMODIFIED)) { + return linvfs_revalidate_core(dentry->d_inode, 0); + } + return 0; +} + +STATIC int +linvfs_setattr( + struct dentry *dentry, + struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + vnode_t *vp = LINVFS_GET_VP(inode); + vattr_t vattr; + unsigned int ia_valid = attr->ia_valid; + int error; + int flags = 0; + + memset(&vattr, 0, sizeof(vattr_t)); + if (ia_valid & ATTR_UID) { + vattr.va_mask |= AT_UID; + vattr.va_uid = attr->ia_uid; + } + if (ia_valid & ATTR_GID) { + vattr.va_mask |= AT_GID; + vattr.va_gid = attr->ia_gid; + } + if (ia_valid & ATTR_SIZE) { + vattr.va_mask |= AT_SIZE; + vattr.va_size = attr->ia_size; + } + if (ia_valid & ATTR_ATIME) { + vattr.va_mask |= AT_ATIME; + vattr.va_atime.tv_sec = attr->ia_atime; + vattr.va_atime.tv_nsec = 0; + } + if (ia_valid & ATTR_MTIME) { + vattr.va_mask |= AT_MTIME; + vattr.va_mtime.tv_sec = attr->ia_mtime; + vattr.va_mtime.tv_nsec = 0; + } + if (ia_valid & ATTR_CTIME) { + vattr.va_mask |= AT_CTIME; + vattr.va_ctime.tv_sec = attr->ia_ctime; + vattr.va_ctime.tv_nsec = 0; + } + if (ia_valid & ATTR_MODE) { + vattr.va_mask |= AT_MODE; + vattr.va_mode = attr->ia_mode; + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) + inode->i_mode &= ~S_ISGID; + } + + if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) + flags = ATTR_UTIME; + + VOP_SETATTR(vp, &vattr, flags, NULL, error); + if (error) + return(-error); /* Positive error up from XFS */ + if (ia_valid & ATTR_SIZE) { + error = vmtruncate(inode, attr->ia_size); + } + + if (!error) { + vn_revalidate(vp, 0); + mark_inode_dirty_sync(inode); + } + return error; +} + +STATIC void +linvfs_truncate( + struct inode *inode) +{ + block_truncate_page(inode->i_mapping, inode->i_size, linvfs_get_block); +} + + + +/* + * Extended attributes interfaces + */ + +#define SYSTEM_NAME "system." /* VFS shared names/values */ +#define ROOT_NAME "xfsroot." /* XFS ondisk names/values */ +#define USER_NAME "user." /* user's own names/values */ +STATIC xattr_namespace_t xfs_namespace_array[] = { + { .name= SYSTEM_NAME, .namelen= sizeof(SYSTEM_NAME)-1,.exists= NULL }, + { .name= ROOT_NAME, .namelen= sizeof(ROOT_NAME)-1, .exists= NULL }, + { .name= USER_NAME, .namelen= sizeof(USER_NAME)-1, .exists= NULL }, + { .name= NULL } +}; +xattr_namespace_t *xfs_namespaces = &xfs_namespace_array[0]; + +#define POSIXACL_ACCESS "posix_acl_access" +#define POSIXACL_ACCESS_SIZE (sizeof(POSIXACL_ACCESS)-1) +#define POSIXACL_DEFAULT "posix_acl_default" +#define POSIXACL_DEFAULT_SIZE (sizeof(POSIXACL_DEFAULT)-1) +#define POSIXCAP "posix_capabilities" +#define POSIXCAP_SIZE (sizeof(POSIXCAP)-1) +#define POSIXMAC "posix_mac" +#define POSIXMAC_SIZE (sizeof(POSIXMAC)-1) +STATIC xattr_namespace_t sys_namespace_array[] = { + { .name= POSIXACL_ACCESS, + .namelen= POSIXACL_ACCESS_SIZE, .exists= _ACL_ACCESS_EXISTS }, + { .name= POSIXACL_DEFAULT, + .namelen= POSIXACL_DEFAULT_SIZE, .exists= _ACL_DEFAULT_EXISTS }, + { .name= POSIXCAP, + .namelen= POSIXCAP_SIZE, .exists= _CAP_EXISTS }, + { .name= POSIXMAC, + .namelen= POSIXMAC_SIZE, .exists= _MAC_EXISTS }, + { .name= NULL } +}; + +/* + * Some checks to prevent people abusing EAs to get over quota: + * - Don't allow modifying user EAs on devices/symlinks; + * - Don't allow modifying user EAs if sticky bit set; + */ +STATIC int +capable_user_xattr( + struct inode *inode) +{ + if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && + !capable(CAP_SYS_ADMIN)) + return 0; + if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && + (current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return 0; + return 1; +} + +STATIC int +linvfs_setxattr( + struct dentry *dentry, + const char *name, + void *data, + size_t size, + int flags) +{ + int error; + int xflags = 0; + char *p = (char *)name; + struct inode *inode = dentry->d_inode; + vnode_t *vp = LINVFS_GET_VP(inode); + + if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name, + xfs_namespaces[SYSTEM_NAMES].namelen) == 0) { + error = -EINVAL; + if (flags & XATTR_CREATE) + return error; + error = -ENOATTR; + p += xfs_namespaces[SYSTEM_NAMES].namelen; + if (strcmp(p, POSIXACL_ACCESS) == 0) { + if (vp->v_flag & VMODIFIED) { + error = linvfs_revalidate_core(inode, 0); + if (error) + return error; + } + error = xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); + if (!error) { + VMODIFY(vp); + error = linvfs_revalidate_core(inode, 0); + } + } + else if (strcmp(p, POSIXACL_DEFAULT) == 0) { + error = linvfs_revalidate_core(inode, 0); + if (error) + return error; + error = xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); + if (!error) { + VMODIFY(vp); + error = linvfs_revalidate_core(inode, 0); + } + } + else if (strcmp(p, POSIXCAP) == 0) { + error = xfs_cap_vset(vp, data, size); + } + return error; + } + + /* Convert Linux syscall to XFS internal ATTR flags */ + if (flags & XATTR_CREATE) + xflags |= ATTR_CREATE; + if (flags & XATTR_REPLACE) + xflags |= ATTR_REPLACE; + + if (strncmp(name, xfs_namespaces[ROOT_NAMES].name, + xfs_namespaces[ROOT_NAMES].namelen) == 0) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + xflags |= ATTR_ROOT; + p += xfs_namespaces[ROOT_NAMES].namelen; + VOP_ATTR_SET(vp, p, data, size, xflags, NULL, error); + return -error; + } + if (strncmp(name, xfs_namespaces[USER_NAMES].name, + xfs_namespaces[USER_NAMES].namelen) == 0) { + if (!capable_user_xattr(inode)) + return -EPERM; + p += xfs_namespaces[USER_NAMES].namelen; + VOP_ATTR_SET(vp, p, data, size, xflags, NULL, error); + return -error; + } + return -ENOATTR; +} + +STATIC ssize_t +linvfs_getxattr( + struct dentry *dentry, + const char *name, + void *data, + size_t size) +{ + ssize_t error; + int xflags = 0; + char *p = (char *)name; + struct inode *inode = dentry->d_inode; + vnode_t *vp = LINVFS_GET_VP(inode); + + if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name, + xfs_namespaces[SYSTEM_NAMES].namelen) == 0) { + error = -ENOATTR; + p += xfs_namespaces[SYSTEM_NAMES].namelen; + if (strcmp(p, POSIXACL_ACCESS) == 0) { + if (vp->v_flag & VMODIFIED) { + error = linvfs_revalidate_core(inode, 0); + if (error) + return error; + } + error = xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); + } + else if (strcmp(p, POSIXACL_DEFAULT) == 0) { + if (vp->v_flag & VMODIFIED) { + error = linvfs_revalidate_core(inode, 0); + if (error) + return error; + } + error = xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); + } + else if (strcmp(p, POSIXCAP) == 0) { + error = xfs_cap_vget(vp, data, size); + } + return error; + } + + /* Convert Linux syscall to XFS internal ATTR flags */ + if (!size) + xflags |= ATTR_KERNOVAL; + + if (strncmp(name, xfs_namespaces[ROOT_NAMES].name, + xfs_namespaces[ROOT_NAMES].namelen) == 0) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + xflags |= ATTR_ROOT; + p += xfs_namespaces[ROOT_NAMES].namelen; + VOP_ATTR_GET(vp, p, data, (int *)&size, xflags, NULL, error); + if (!error) + error = -size; + return -error; + } + if (strncmp(name, xfs_namespaces[USER_NAMES].name, + xfs_namespaces[USER_NAMES].namelen) == 0) { + p += xfs_namespaces[USER_NAMES].namelen; + if (!capable_user_xattr(inode)) + return -EPERM; + VOP_ATTR_GET(vp, p, data, (int *)&size, xflags, NULL, error); + if (!error) + error = -size; + return -error; + } + return -ENOATTR; +} + + +STATIC ssize_t +linvfs_listxattr( + struct dentry *dentry, + char *data, + size_t size) +{ + ssize_t error; + int result = 0; + int xflags = ATTR_KERNAMELS; + char *k = data; + attrlist_cursor_kern_t cursor; + xattr_namespace_t *sys; + vnode_t *vp; + + vp = LINVFS_GET_VP(dentry->d_inode); + + if (!size) + xflags |= ATTR_KERNOVAL; + if (capable(CAP_SYS_ADMIN)) + xflags |= ATTR_KERNFULLS; + + memset(&cursor, 0, sizeof(cursor)); + VOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error); + if (error > 0) + return -error; + result += -error; + + k += result; /* advance start of our buffer */ + for (sys = &sys_namespace_array[0]; sys->name != NULL; sys++) { + if (sys->exists == NULL || !sys->exists(vp)) + continue; + result += xfs_namespaces[SYSTEM_NAMES].namelen; + result += sys->namelen + 1; + if (size) { + if (result > size) + return -ERANGE; + strcpy(k, xfs_namespaces[SYSTEM_NAMES].name); + k += xfs_namespaces[SYSTEM_NAMES].namelen; + strcpy(k, sys->name); + k += sys->namelen + 1; + } + } + return result; +} + +STATIC int +linvfs_removexattr( + struct dentry *dentry, + const char *name) +{ + int error; + int xflags = 0; + char *p = (char *)name; + struct inode *inode = dentry->d_inode; + vnode_t *vp = LINVFS_GET_VP(inode); + + if (strncmp(name, xfs_namespaces[SYSTEM_NAMES].name, + xfs_namespaces[SYSTEM_NAMES].namelen) == 0) { + error = -ENOATTR; + p += xfs_namespaces[SYSTEM_NAMES].namelen; + if (strcmp(p, POSIXACL_ACCESS) == 0) + error = xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); + else if (strcmp(p, POSIXACL_DEFAULT) == 0) + error = xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); + else if (strcmp(p, POSIXCAP) == 0) + error = xfs_cap_vremove(vp); + return error; + } + + if (strncmp(name, xfs_namespaces[ROOT_NAMES].name, + xfs_namespaces[ROOT_NAMES].namelen) == 0) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + xflags |= ATTR_ROOT; + p += xfs_namespaces[ROOT_NAMES].namelen; + VOP_ATTR_REMOVE(vp, p, xflags, NULL, error); + return -error; + } + if (strncmp(name, xfs_namespaces[USER_NAMES].name, + xfs_namespaces[USER_NAMES].namelen) == 0) { + p += xfs_namespaces[USER_NAMES].namelen; + if (!capable_user_xattr(inode)) + return -EPERM; + VOP_ATTR_REMOVE(vp, p, xflags, NULL, error); + return -error; + } + return -ENOATTR; +} + + +struct inode_operations linvfs_file_inode_operations = +{ + .permission = linvfs_permission, + .truncate = linvfs_truncate, + .revalidate = linvfs_revalidate, + .setattr = linvfs_setattr, + .setxattr = linvfs_setxattr, + .getxattr = linvfs_getxattr, + .listxattr = linvfs_listxattr, + .removexattr = linvfs_removexattr, +}; + +struct inode_operations linvfs_dir_inode_operations = +{ + .create = linvfs_create, + .lookup = linvfs_lookup, + .link = linvfs_link, + .unlink = linvfs_unlink, + .symlink = linvfs_symlink, + .mkdir = linvfs_mkdir, + .rmdir = linvfs_rmdir, + .mknod = linvfs_mknod, + .rename = linvfs_rename, + .permission = linvfs_permission, + .revalidate = linvfs_revalidate, + .setattr = linvfs_setattr, + .setxattr = linvfs_setxattr, + .getxattr = linvfs_getxattr, + .listxattr = linvfs_listxattr, + .removexattr = linvfs_removexattr, +}; + +struct inode_operations linvfs_symlink_inode_operations = +{ + .readlink = linvfs_readlink, + .follow_link = linvfs_follow_link, + .permission = linvfs_permission, + .revalidate = linvfs_revalidate, + .setattr = linvfs_setattr, + .setxattr = linvfs_setxattr, + .getxattr = linvfs_getxattr, + .listxattr = linvfs_listxattr, + .removexattr = linvfs_removexattr, +}; diff -Nur linux-2.4.19/fs/xfs/linux/xfs_iops.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_iops.h --- linux-2.4.19/fs/xfs/linux/xfs_iops.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_iops.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IOPS_H__ +#define __XFS_IOPS_H__ + +/* + * Extended system attributes. + * So far only POSIX ACLs are supported, but this will need to + * grow in time (capabilities, mandatory access control, etc). + */ +#define XFS_SYSTEM_NAMESPACE SYSTEM_POSIXACL + +/* + * Define a table of the namespaces XFS supports + */ +typedef int (*xattr_exists_t)(vnode_t *); + +typedef struct xattr_namespace { + char *name; + unsigned int namelen; + xattr_exists_t exists; +} xattr_namespace_t; + +#define SYSTEM_NAMES 0 +#define ROOT_NAMES 1 +#define USER_NAMES 2 +extern struct xattr_namespace *xfs_namespaces; + + +extern struct inode_operations linvfs_file_inode_operations; +extern struct inode_operations linvfs_dir_inode_operations; +extern struct inode_operations linvfs_symlink_inode_operations; + +extern struct file_operations linvfs_file_operations; +extern struct file_operations linvfs_dir_operations; + +extern struct address_space_operations linvfs_aops; + +extern int linvfs_revalidate_core(struct inode *, int); +extern int linvfs_get_block(struct inode *, long, struct buffer_head *, int); + +#endif /* __XFS_IOPS_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_linux.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_linux.h --- linux-2.4.19/fs/xfs/linux/xfs_linux.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_linux.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LINUX__ +#define __XFS_LINUX__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef STATIC +#define STATIC static +#endif + +#define restricted_chown xfs_params.restrict_chown +#define irix_sgid_inherit xfs_params.sgid_inherit +#define irix_symlink_mode xfs_params.symlink_mode + +typedef struct xfs_dirent { /* data from readdir() */ + xfs_ino_t d_ino; /* inode number of entry */ + xfs_off_t d_off; /* offset of disk directory entry */ + unsigned short d_reclen; /* length of this record */ + char d_name[1]; /* name of file */ +} xfs_dirent_t; + +#define DIRENTBASESIZE (((xfs_dirent_t *)0)->d_name - (char *)0) +#define DIRENTSIZE(namelen) \ + ((DIRENTBASESIZE + (namelen) + \ + sizeof(xfs_off_t)) & ~(sizeof(xfs_off_t) - 1)) + +#define NBPP PAGE_SIZE +#define DPPSHFT (PAGE_SHIFT - 9) +#define NDPP (1 << (PAGE_SHIFT - 9)) +#define dtop(DD) (((DD) + NDPP - 1) >> DPPSHFT) +#define dtopt(DD) ((DD) >> DPPSHFT) +#define dpoff(DD) ((DD) & (NDPP-1)) + +#define NBBY 8 /* number of bits per byte */ +#define NBPC PAGE_SIZE /* Number of bytes per click */ +#define BPCSHIFT PAGE_SHIFT /* LOG2(NBPC) if exact */ + +/* + * Size of block device i/o is parameterized here. + * Currently the system supports page-sized i/o. + */ +#define BLKDEV_IOSHIFT BPCSHIFT +#define BLKDEV_IOSIZE (1<>BPCSHIFT) +#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT) +#define btoc64(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) +#define btoct64(x) ((__uint64_t)(x)>>BPCSHIFT) +#define io_btoc(x) (((__psunsigned_t)(x)+(IO_NBPC-1))>>IO_BPCSHIFT) +#define io_btoct(x) ((__psunsigned_t)(x)>>IO_BPCSHIFT) + +/* off_t bytes to clicks */ +#define offtoc(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) +#define offtoct(x) ((xfs_off_t)(x)>>BPCSHIFT) + +/* clicks to off_t bytes */ +#define ctooff(x) ((xfs_off_t)(x)<>BPCSHIFT) +#define ctob64(x) ((__uint64_t)(x)<>BPCSHIFT) + +#ifndef CELL_CAPABLE +#define FSC_NOTIFY_NAME_CHANGED(vp) +#endif + +#ifndef ENOATTR +#define ENOATTR ENODATA /* Attribute not found */ +#endif + +/* Note: EWRONGFS never visible outside the kernel */ +#define EWRONGFS EINVAL /* Mount with wrong filesystem type */ + +/* + * XXX EFSCORRUPTED needs a real value in errno.h. asm-i386/errno.h won't + * return codes out of its known range in errno. + * XXX Also note: needs to be < 1000 and fairly unique on Linux (mustn't + * conflict with any code we use already or any code a driver may use) + * XXX Some options (currently we do #2): + * 1/ New error code ["Filesystem is corrupted", _after_ glibc updated] + * 2/ 990 ["Unknown error 990"] + * 3/ EUCLEAN ["Structure needs cleaning"] + * 4/ Convert EFSCORRUPTED to EIO [just prior to return into userspace] + */ +#define EFSCORRUPTED 990 /* Filesystem is corrupted */ + +#define SYNCHRONIZE() barrier() +#define lbolt jiffies +#define rootdev ROOT_DEV +#define __return_address __builtin_return_address(0) +#define LONGLONG_MAX 9223372036854775807LL /* max "long long int" */ +#define nopkg() ( ENOSYS ) + +/* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */ +/* we may well need to fine-tune this if it ever becomes an issue. */ +#define DQUOT_MAX_HEURISTIC 1024 /* NR_DQUOTS */ +#define ndquot DQUOT_MAX_HEURISTIC + +/* IRIX uses the current size of the name cache to guess a good value */ +/* - this isn't the same but is a good enough starting point for now. */ +#define DQUOT_HASH_HEURISTIC files_stat.nr_files + +/* IRIX inodes maintain the project ID also, zero this field on Linux */ +#define DEFAULT_PROJID 0 +#define dfltprid DEFAULT_PROJID + +#define MAXNAMELEN 256 +#define MAXPATHLEN 1024 + +#define FINVIS 0x0100 /* don't update timestamps - XFS */ + +#define MIN(a,b) (min(a,b)) +#define MAX(a,b) (max(a,b)) +#define howmany(x, y) (((x)+((y)-1))/(y)) +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) + +/* Move the kernel do_div definition off to one side */ + +#if defined __i386__ +/* For ia32 we need to pull some tricks to get past various versions + * of the compiler which do not like us using do_div in the middle + * of large functions. + */ +static inline __u32 xfs_do_div(void *a, __u32 b, int n) +{ + __u32 mod; + + switch (n) { + case 4: + mod = *(__u32 *)a % b; + *(__u32 *)a = *(__u32 *)a / b; + return mod; + case 8: + { + unsigned long __upper, __low, __high, __mod; + __u64 c = *(__u64 *)a; + __upper = __high = c >> 32; + __low = c; + if (__high) { + __upper = __high % (b); + __high = __high / (b); + } + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); + asm("":"=A" (c):"a" (__low),"d" (__high)); + *(__u64 *)a = c; + return __mod; + } + } + + /* NOTREACHED */ + return 0; +} + +/* Side effect free 64 bit mod operation */ +static inline __u32 xfs_do_mod(void *a, __u32 b, int n) +{ + switch (n) { + case 4: + return *(__u32 *)a % b; + case 8: + { + unsigned long __upper, __low, __high, __mod; + __u64 c = *(__u64 *)a; + __upper = __high = c >> 32; + __low = c; + if (__high) { + __upper = __high % (b); + __high = __high / (b); + } + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); + asm("":"=A" (c):"a" (__low),"d" (__high)); + return __mod; + } + } + + /* NOTREACHED */ + return 0; +} +#else +static inline __u32 xfs_do_div(void *a, __u32 b, int n) +{ + __u32 mod; + + switch (n) { + case 4: + mod = *(__u32 *)a % b; + *(__u32 *)a = *(__u32 *)a / b; + return mod; + case 8: + mod = do_div(*(__u64 *)a, b); + return mod; + } + + /* NOTREACHED */ + return 0; +} + +/* Side effect free 64 bit mod operation */ +static inline __u32 xfs_do_mod(void *a, __u32 b, int n) +{ + switch (n) { + case 4: + return *(__u32 *)a % b; + case 8: + { + __u64 c = *(__u64 *)a; + return do_div(c, b); + } + } + + /* NOTREACHED */ + return 0; +} +#endif + +#undef do_div +#define do_div(a, b) xfs_do_div(&(a), (b), sizeof(a)) +#define do_mod(a, b) xfs_do_mod(&(a), (b), sizeof(a)) + +static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y) +{ + x += y - 1; + do_div(x, y); + return(x * y); +} + +#endif /* __XFS_LINUX__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_lrw.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_lrw.c --- linux-2.4.19/fs/xfs/linux/xfs_lrw.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_lrw.c Tue Jan 7 21:41:51 2003 @@ -0,0 +1,1798 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * fs/xfs/linux/xfs_lrw.c (Linux Read Write stuff) + * + */ + +#include +#include +#include + + +#define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ + << mp->m_writeio_log) +#define XFS_STRAT_WRITE_IMAPS 2 + +STATIC int xfs_iomap_read(xfs_iocore_t *, loff_t, size_t, int, pb_bmap_t *, + int *, struct pm *); +STATIC int xfs_iomap_write(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *, + int *, int, struct pm *); +STATIC int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *, + int *, int, int); +STATIC int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *, + int *, int, int); +STATIC int _xfs_imap_to_bmap(xfs_iocore_t *, xfs_off_t, xfs_bmbt_irec_t *, + pb_bmap_t *, int, int); + + +/* + * xfs_iozero + * + * xfs_iozero clears the specified range of buffer supplied, + * and marks all the affected blocks as valid and modified. If + * an affected block is not allocated, it will be allocated. If + * an affected block is not completely overwritten, and is not + * valid before the operation, it will be read from disk before + * being partially zeroed. + */ +STATIC int +xfs_iozero( + struct inode *ip, /* inode */ + loff_t pos, /* offset in file */ + size_t count, /* size of data to zero */ + loff_t end_size) /* max file size to set */ +{ + unsigned bytes; + struct page *page; + struct address_space *mapping; + char *kaddr; + int status; + + mapping = ip->i_mapping; + do { + unsigned long index, offset; + + offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ + index = pos >> PAGE_CACHE_SHIFT; + bytes = PAGE_CACHE_SIZE - offset; + if (bytes > count) + bytes = count; + + status = -ENOMEM; + page = grab_cache_page(mapping, index); + if (!page) + break; + + kaddr = kmap(page); + status = mapping->a_ops->prepare_write(NULL, page, offset, + offset + bytes); + if (status) { + goto unlock; + } + + memset((void *) (kaddr + offset), 0, bytes); + flush_dcache_page(page); + status = mapping->a_ops->commit_write(NULL, page, offset, + offset + bytes); + if (!status) { + pos += bytes; + count -= bytes; + if (pos > ip->i_size) + ip->i_size = pos < end_size ? pos : end_size; + } + +unlock: + kunmap(page); + unlock_page(page); + page_cache_release(page); + if (status) + break; + } while (count); + + return (-status); +} + +ssize_t /* bytes read, or (-) error */ +xfs_read( + bhv_desc_t *bdp, + struct file *file, + char *buf, + size_t size, + loff_t *offset, + cred_t *credp) +{ + ssize_t ret; + xfs_fsize_t n; + xfs_inode_t *ip; + xfs_mount_t *mp; + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + XFS_STATS_INC(xfsstats.xs_read_calls); + + if (file->f_flags & O_DIRECT) { + if (((__psint_t)buf & BBMASK) || + (*offset & mp->m_blockmask) || + (size & mp->m_blockmask)) { + if (*offset == ip->i_d.di_size) { + return (0); + } + return -XFS_ERROR(EINVAL); + } + } + + + n = XFS_MAX_FILE_OFFSET - *offset; + if ((n <= 0) || (size == 0)) + return 0; + + if (n < size) + size = n; + + if (XFS_FORCED_SHUTDOWN(mp)) { + return -EIO; + } + + xfs_ilock(ip, XFS_IOLOCK_SHARED); + + if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) && + !(file->f_mode & FINVIS)) { + int error; + vrwlock_t locktype = VRWLOCK_READ; + + error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, + *offset, size, + FILP_DELAY_FLAG(file), + &locktype); + if (error) { + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + return -error; + } + } + + ret = generic_file_read(file, buf, size, offset); + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + + XFS_STATS_ADD(xfsstats.xs_read_bytes, ret); + + if (!(file->f_mode & FINVIS)) + xfs_ichgtime(ip, XFS_ICHGTIME_ACC); + + return ret; +} + +/* + * This routine is called to handle zeroing any space in the last + * block of the file that is beyond the EOF. We do this since the + * size is being increased without writing anything to that block + * and we don't want anyone to read the garbage on the disk. + */ +STATIC int /* error (positive) */ +xfs_zero_last_block( + struct inode *ip, + xfs_iocore_t *io, + xfs_off_t offset, + xfs_fsize_t isize, + xfs_fsize_t end_size, + struct pm *pmp) +{ + xfs_fileoff_t last_fsb; + xfs_mount_t *mp; + int nimaps; + int zero_offset; + int zero_len; + int isize_fsb_offset; + int error = 0; + xfs_bmbt_irec_t imap; + loff_t loff; + size_t lsize; + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); + ASSERT(offset > isize); + + mp = io->io_mount; + + isize_fsb_offset = XFS_B_FSB_OFFSET(mp, isize); + if (isize_fsb_offset == 0) { + /* + * There are no extra bytes in the last block on disk to + * zero, so return. + */ + return 0; + } + + last_fsb = XFS_B_TO_FSBT(mp, isize); + nimaps = 1; + error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap, + &nimaps, NULL); + if (error) { + return error; + } + ASSERT(nimaps > 0); + /* + * If the block underlying isize is just a hole, then there + * is nothing to zero. + */ + if (imap.br_startblock == HOLESTARTBLOCK) { + return 0; + } + /* + * Get a pagebuf for the last block, zero the part beyond the + * EOF, and write it out sync. We need to drop the ilock + * while we do this so we don't deadlock when the buffer cache + * calls back to us. + */ + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); + loff = XFS_FSB_TO_B(mp, last_fsb); + lsize = XFS_FSB_TO_B(mp, 1); + + zero_offset = isize_fsb_offset; + zero_len = mp->m_sb.sb_blocksize - isize_fsb_offset; + + error = xfs_iozero(ip, loff + zero_offset, zero_len, end_size); + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + ASSERT(error >= 0); + return error; +} + +/* + * Zero any on disk space between the current EOF and the new, + * larger EOF. This handles the normal case of zeroing the remainder + * of the last block in the file and the unusual case of zeroing blocks + * out beyond the size of the file. This second case only happens + * with fixed size extents and when the system crashes before the inode + * size was updated but after blocks were allocated. If fill is set, + * then any holes in the range are filled and zeroed. If not, the holes + * are left alone as holes. + */ + +int /* error (positive) */ +xfs_zero_eof( + vnode_t *vp, + xfs_iocore_t *io, + xfs_off_t offset, /* starting I/O offset */ + xfs_fsize_t isize, /* current inode size */ + xfs_fsize_t end_size, /* terminal inode size */ + struct pm *pmp) +{ + struct inode *ip = LINVFS_GET_IP(vp); + xfs_fileoff_t start_zero_fsb; + xfs_fileoff_t end_zero_fsb; + xfs_fileoff_t prev_zero_fsb; + xfs_fileoff_t zero_count_fsb; + xfs_fileoff_t last_fsb; + xfs_extlen_t buf_len_fsb; + xfs_extlen_t prev_zero_count; + xfs_mount_t *mp; + int nimaps; + int error = 0; + xfs_bmbt_irec_t imap; + loff_t loff; + size_t lsize; + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + + mp = io->io_mount; + + /* + * First handle zeroing the block on which isize resides. + * We only zero a part of that block so it is handled specially. + */ + error = xfs_zero_last_block(ip, io, offset, isize, end_size, pmp); + if (error) { + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + return error; + } + + /* + * Calculate the range between the new size and the old + * where blocks needing to be zeroed may exist. To get the + * block where the last byte in the file currently resides, + * we need to subtract one from the size and truncate back + * to a block boundary. We subtract 1 in case the size is + * exactly on a block boundary. + */ + last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1; + start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); + end_zero_fsb = XFS_B_TO_FSBT(mp, offset - 1); + + ASSERT((xfs_sfiloff_t)last_fsb < (xfs_sfiloff_t)start_zero_fsb); + if (last_fsb == end_zero_fsb) { + /* + * The size was only incremented on its last block. + * We took care of that above, so just return. + */ + return 0; + } + + ASSERT(start_zero_fsb <= end_zero_fsb); + prev_zero_fsb = NULLFILEOFF; + prev_zero_count = 0; + /* + * Maybe change this loop to do the bmapi call and + * loop while we split the mappings into pagebufs? + */ + while (start_zero_fsb <= end_zero_fsb) { + nimaps = 1; + zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; + error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb, + 0, NULL, 0, &imap, &nimaps, NULL); + if (error) { + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + return error; + } + ASSERT(nimaps > 0); + + if (imap.br_startblock == HOLESTARTBLOCK) { + /* + * This loop handles initializing pages that were + * partially initialized by the code below this + * loop. It basically zeroes the part of the page + * that sits on a hole and sets the page as P_HOLE + * and calls remapf if it is a mapped file. + */ + prev_zero_fsb = NULLFILEOFF; + prev_zero_count = 0; + start_zero_fsb = imap.br_startoff + + imap.br_blockcount; + ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); + continue; + } + + /* + * There are blocks in the range requested. + * Zero them a single write at a time. We actually + * don't zero the entire range returned if it is + * too big and simply loop around to get the rest. + * That is not the most efficient thing to do, but it + * is simple and this path should not be exercised often. + */ + buf_len_fsb = XFS_FILBLKS_MIN(imap.br_blockcount, + mp->m_writeio_blocks << 8); + /* + * Drop the inode lock while we're doing the I/O. + * We'll still have the iolock to protect us. + */ + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + + loff = XFS_FSB_TO_B(mp, start_zero_fsb); + lsize = XFS_FSB_TO_B(mp, buf_len_fsb); + + error = xfs_iozero(ip, loff, lsize, end_size); + + if (error) { + goto out_lock; + } + + prev_zero_fsb = start_zero_fsb; + prev_zero_count = buf_len_fsb; + start_zero_fsb = imap.br_startoff + buf_len_fsb; + ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + } + + return 0; + +out_lock: + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + ASSERT(error >= 0); + return error; +} + +ssize_t /* bytes written, or (-) error */ +xfs_write( + bhv_desc_t *bdp, + struct file *file, + const char *buf, + size_t size, + loff_t *offset, + cred_t *credp) +{ + xfs_inode_t *xip; + xfs_mount_t *mp; + ssize_t ret; + int error = 0; + xfs_fsize_t isize, new_size; + xfs_fsize_t n, limit = XFS_MAX_FILE_OFFSET; + xfs_iocore_t *io; + vnode_t *vp; + int iolock; + int direct = file->f_flags & O_DIRECT; + int eventsent = 0; + vrwlock_t locktype; + + XFS_STATS_INC(xfsstats.xs_write_calls); + + vp = BHV_TO_VNODE(bdp); + xip = XFS_BHVTOI(bdp); + + if (size == 0) + return 0; + + io = &(xip->i_iocore); + mp = io->io_mount; + + xfs_check_frozen(mp, bdp, XFS_FREEZE_WRITE); + + if (XFS_FORCED_SHUTDOWN(xip->i_mount)) { + return -EIO; + } + + if (direct) { + if (((__psint_t)buf & BBMASK) || + (*offset & mp->m_blockmask) || + (size & mp->m_blockmask)) { + return XFS_ERROR(-EINVAL); + } + iolock = XFS_IOLOCK_SHARED; + locktype = VRWLOCK_WRITE_DIRECT; + } else { + iolock = XFS_IOLOCK_EXCL; + locktype = VRWLOCK_WRITE; + } + + xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); + isize = xip->i_d.di_size; + + if (file->f_flags & O_APPEND) + *offset = isize; + +start: + n = limit - *offset; + if (n <= 0) { + xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); + return -EFBIG; + } + if (n < size) + size = n; + + new_size = *offset + size; + if (new_size > isize) { + io->io_new_size = new_size; + } + + if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && + !(file->f_mode & FINVIS) && !eventsent)) { + loff_t savedsize = *offset; + + xfs_iunlock(xip, XFS_ILOCK_EXCL); + error = xfs_dm_send_data_event(DM_EVENT_WRITE, bdp, + *offset, size, + FILP_DELAY_FLAG(file), &locktype); + if (error) { + xfs_iunlock(xip, iolock); + return -error; + } + xfs_ilock(xip, XFS_ILOCK_EXCL); + eventsent = 1; + + /* + * The iolock was dropped and reaquired in + * xfs_dm_send_data_event so we have to recheck the size + * when appending. We will only "goto start;" once, + * since having sent the event prevents another call + * to xfs_dm_send_data_event, which is what + * allows the size to change in the first place. + */ + if ((file->f_flags & O_APPEND) && + savedsize != xip->i_d.di_size) { + *offset = isize = xip->i_d.di_size; + goto start; + } + } + + /* + * On Linux, generic_file_write updates the times even if + * no data is copied in so long as the write had a size. + * + * We must update xfs' times since revalidate will overcopy xfs. + */ + if (size) { + if (!(file->f_mode & FINVIS)) + xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + } + + /* + * If the offset is beyond the size of the file, we have a couple + * of things to do. First, if there is already space allocated + * we need to either create holes or zero the disk or ... + * + * If there is a page where the previous size lands, we need + * to zero it out up to the new size. + */ + + if (!direct && (*offset > isize && isize)) { + error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offset, + isize, *offset + size, NULL); + if (error) { + xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); + return(-error); + } + } + xfs_iunlock(xip, XFS_ILOCK_EXCL); + + /* + * If we're writing the file then make sure to clear the + * setuid and setgid bits if the process is not being run + * by root. This keeps people from modifying setuid and + * setgid binaries. + */ + + if (((xip->i_d.di_mode & ISUID) || + ((xip->i_d.di_mode & (ISGID | (IEXEC >> 3))) == + (ISGID | (IEXEC >> 3)))) && + !capable(CAP_FSETID)) { + error = xfs_write_clear_setuid(xip); + if (error) { + xfs_iunlock(xip, iolock); + return -error; + } + } + +retry: + if (direct) { + xfs_inval_cached_pages(vp, &xip->i_iocore, *offset, 1, 1); + } + + ret = generic_file_write_nolock(file, buf, size, offset); + + if ((ret == -ENOSPC) && + DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) && + !(file->f_mode & FINVIS)) { + + xfs_rwunlock(bdp, locktype); + error = dm_send_namesp_event(DM_EVENT_NOSPACE, bdp, + DM_RIGHT_NULL, bdp, DM_RIGHT_NULL, NULL, NULL, + 0, 0, 0); /* Delay flag intentionally unused */ + if (error) + return -error; + xfs_rwlock(bdp, locktype); + *offset = xip->i_d.di_size; + goto retry; + + } + + if (ret <= 0) { + xfs_rwunlock(bdp, locktype); + return ret; + } + + XFS_STATS_ADD(xfsstats.xs_write_bytes, ret); + + if (*offset > xip->i_d.di_size) { + xfs_ilock(xip, XFS_ILOCK_EXCL); + if (*offset > xip->i_d.di_size) { + struct inode *inode = LINVFS_GET_IP(vp); + + inode->i_size = xip->i_d.di_size = *offset; + xip->i_update_core = 1; + xip->i_update_size = 1; + } + xfs_iunlock(xip, XFS_ILOCK_EXCL); + } + + /* Handle various SYNC-type writes */ + if ((file->f_flags & O_SYNC) || IS_SYNC(file->f_dentry->d_inode)) { + + /* + * If we're treating this as O_DSYNC and we have not updated the + * size, force the log. + */ + + if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) + && !(xip->i_update_size)) { + /* + * If an allocation transaction occurred + * without extending the size, then we have to force + * the log up the proper point to ensure that the + * allocation is permanent. We can't count on + * the fact that buffered writes lock out direct I/O + * writes - the direct I/O write could have extended + * the size nontransactionally, then finished before + * we started. xfs_write_file will think that the file + * didn't grow but the update isn't safe unless the + * size change is logged. + * + * Force the log if we've committed a transaction + * against the inode or if someone else has and + * the commit record hasn't gone to disk (e.g. + * the inode is pinned). This guarantees that + * all changes affecting the inode are permanent + * when we return. + */ + + xfs_inode_log_item_t *iip; + xfs_lsn_t lsn; + + iip = xip->i_itemp; + if (iip && iip->ili_last_lsn) { + lsn = iip->ili_last_lsn; + xfs_log_force(mp, lsn, + XFS_LOG_FORCE | XFS_LOG_SYNC); + } else if (xfs_ipincount(xip) > 0) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + } + + } else { + xfs_trans_t *tp; + + /* + * O_SYNC or O_DSYNC _with_ a size update are handled + * the same way. + * + * If the write was synchronous then we need to make + * sure that the inode modification time is permanent. + * We'll have updated the timestamp above, so here + * we use a synchronous transaction to log the inode. + * It's not fast, but it's necessary. + * + * If this a dsync write and the size got changed + * non-transactionally, then we need to ensure that + * the size change gets logged in a synchronous + * transaction. + */ + + tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC); + if ((error = xfs_trans_reserve(tp, 0, + XFS_SWRITE_LOG_RES(mp), + 0, 0, 0))) { + /* Transaction reserve failed */ + xfs_trans_cancel(tp, 0); + } else { + /* Transaction reserve successful */ + xfs_ilock(xip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, xip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, xip); + xfs_trans_log_inode(tp, xip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, (xfs_lsn_t)0); + xfs_iunlock(xip, XFS_ILOCK_EXCL); + } + } + } /* (ioflags & O_SYNC) */ + + /* + * If we are coming from an nfsd thread then insert into the + * reference cache. + */ + + if (!strcmp(current->comm, "nfsd")) + xfs_refcache_insert(xip); + + /* Drop lock this way - the old refcache release is in here */ + xfs_rwunlock(bdp, locktype); + + return(ret); +} + +/* + * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c + * execpt for slight changes to the params + */ +int +xfs_bmap(bhv_desc_t *bdp, + xfs_off_t offset, + ssize_t count, + int flags, + struct cred *cred, + pb_bmap_t *pbmapp, + int *npbmaps) +{ + xfs_inode_t *ip; + int error; + int lockmode; + int fsynced = 0; + vnode_t *vp; + + ip = XFS_BHVTOI(bdp); + ASSERT((ip->i_d.di_mode & IFMT) == IFREG); + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); + ASSERT((flags & PBF_READ) || (flags & PBF_WRITE)); + + if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount)) + return XFS_ERROR(EIO); + + if (flags & PBF_READ) { + lockmode = xfs_ilock_map_shared(ip); + error = xfs_iomap_read(&ip->i_iocore, offset, count, + XFS_BMAPI_ENTIRE, pbmapp, npbmaps, NULL); + xfs_iunlock_map_shared(ip, lockmode); + } else { /* PBF_WRITE */ + ASSERT(flags & PBF_WRITE); + vp = BHV_TO_VNODE(bdp); + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Make sure that the dquots are there. This doesn't hold + * the ilock across a disk read. + */ + + if (XFS_IS_QUOTA_ON(ip->i_mount)) { + if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) { + if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return XFS_ERROR(error); + } + } + } +retry: + error = xfs_iomap_write(&ip->i_iocore, offset, count, + pbmapp, npbmaps, flags, NULL); + /* xfs_iomap_write unlocks/locks/unlocks */ + + if (error == ENOSPC) { + switch (fsynced) { + case 0: + if (ip->i_delayed_blks) { + fsync_inode_data_buffers(LINVFS_GET_IP(vp)); + fsynced = 1; + } else { + fsynced = 2; + flags |= PBF_SYNC; + } + error = 0; + xfs_ilock(ip, XFS_ILOCK_EXCL); + goto retry; + case 1: + fsynced = 2; + if (!(flags & PBF_SYNC)) { + flags |= PBF_SYNC; + error = 0; + xfs_ilock(ip, XFS_ILOCK_EXCL); + goto retry; + } + case 2: + fsync_no_super(LINVFS_GET_IP(vp)->i_dev); + xfs_log_force(ip->i_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE|XFS_LOG_SYNC); + + error = 0; +/** + delay(HZ); +**/ + fsynced++; + xfs_ilock(ip, XFS_ILOCK_EXCL); + goto retry; + } + } + } + + return XFS_ERROR(error); +} + +int +xfs_strategy(bhv_desc_t *bdp, + xfs_off_t offset, + ssize_t count, + int flags, + struct cred *cred, + pb_bmap_t *pbmapp, + int *npbmaps) +{ + xfs_inode_t *ip; + xfs_iocore_t *io; + xfs_mount_t *mp; + int error; + xfs_fileoff_t offset_fsb; + xfs_fileoff_t end_fsb; + xfs_fileoff_t map_start_fsb; + xfs_fileoff_t last_block; + xfs_fsblock_t first_block; + xfs_bmap_free_t free_list; + xfs_filblks_t count_fsb; + int committed, i, loops, nimaps; + int is_xfs = 1; /* This will be a variable at some point */ + xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS]; + xfs_trans_t *tp; + + ip = XFS_BHVTOI(bdp); + io = &ip->i_iocore; + mp = ip->i_mount; + /* is_xfs = IO_IS_XFS(io); */ + ASSERT((ip->i_d.di_mode & IFMT) == IFREG); + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((io->io_flags & XFS_IOCORE_RT) != 0)); + ASSERT((flags & PBF_READ) || (flags & PBF_WRITE)); + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + ASSERT(flags & PBF_WRITE); + + offset_fsb = XFS_B_TO_FSBT(mp, offset); + nimaps = min(XFS_MAX_RW_NBMAPS, *npbmaps); + end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + first_block = NULLFSBLOCK; + + XFS_ILOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD); + error = XFS_BMAPI(mp, NULL, io, offset_fsb, + (xfs_filblks_t)(end_fsb - offset_fsb), + XFS_BMAPI_ENTIRE, &first_block, 0, imap, + &nimaps, NULL); + XFS_IUNLOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD); + if (error) { + return XFS_ERROR(error); + } + + if (nimaps && !ISNULLSTARTBLOCK(imap[0].br_startblock)) { + *npbmaps = _xfs_imap_to_bmap(&ip->i_iocore, offset, imap, + pbmapp, nimaps, *npbmaps); + return 0; + } + + /* + * Make sure that the dquots are there. + */ + + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) { + return XFS_ERROR(error); + } + } + } + XFS_STATS_ADD(xfsstats.xs_xstrat_bytes, + XFS_FSB_TO_B(mp, imap[0].br_blockcount)); + + offset_fsb = imap[0].br_startoff; + count_fsb = imap[0].br_blockcount; + map_start_fsb = offset_fsb; + while (count_fsb != 0) { + /* + * Set up a transaction with which to allocate the + * backing store for the file. Do allocations in a + * loop until we get some space in the range we are + * interested in. The other space that might be allocated + * is in the delayed allocation extent on which we sit + * but before our buffer starts. + */ + nimaps = 0; + loops = 0; + while (nimaps == 0) { + if (is_xfs) { + tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE); + error = xfs_trans_reserve(tp, 0, + XFS_WRITE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + if (error) { + xfs_trans_cancel(tp, 0); + goto error0; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, + XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + } else { + tp = NULL; + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_WR); + } + + + /* + * Allocate the backing store for the file. + */ + XFS_BMAP_INIT(&(free_list), + &(first_block)); + nimaps = XFS_STRAT_WRITE_IMAPS; + + /* + * Ensure we don't go beyond eof - it is possible + * the extents changed since we did the read call, + * we dropped the ilock in the interim. + */ + + end_fsb = XFS_B_TO_FSB(mp, XFS_SIZE(mp, io)); + xfs_bmap_last_offset(NULL, ip, &last_block, + XFS_DATA_FORK); + last_block = XFS_FILEOFF_MAX(last_block, end_fsb); + if ((map_start_fsb + count_fsb) > last_block) { + count_fsb = last_block - map_start_fsb; + if (count_fsb == 0) { + if (is_xfs) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + } + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_WR); + return XFS_ERROR(EAGAIN); + } + } + + error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb, + XFS_BMAPI_WRITE, &first_block, 1, + imap, &nimaps, &free_list); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_WR); + + goto error0; + } + + if (is_xfs) { + error = xfs_bmap_finish(&(tp), &(free_list), + first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + goto error0; + } + + error = xfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES, + NULL); + if (error) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + goto error0; + } + } + + if (nimaps == 0) { + XFS_IUNLOCK(mp, io, + XFS_ILOCK_EXCL|XFS_EXTSIZE_WR); + } /* else hold 'till we maybe loop again below */ + } + + /* + * See if we were able to allocate an extent that + * covers at least part of the user's requested size. + */ + + offset_fsb = XFS_B_TO_FSBT(mp, offset); + for(i = 0; i < nimaps; i++) { + int maps; + if (offset_fsb >= imap[i].br_startoff && + (offset_fsb < (imap[i].br_startoff + imap[i].br_blockcount))) { + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | XFS_EXTSIZE_WR); + maps = min(nimaps, *npbmaps); + *npbmaps = _xfs_imap_to_bmap(io, offset, &imap[i], + pbmapp, maps, *npbmaps); + XFS_STATS_INC(xfsstats.xs_xstrat_quick); + return 0; + } + count_fsb -= imap[i].br_blockcount; /* for next bmapi, + if needed. */ + } + + /* + * We didn't get an extent the caller can write into so + * loop around and try starting after the last imap we got back. + */ + + nimaps--; /* Index of last entry */ + ASSERT(nimaps >= 0); + ASSERT(offset_fsb >= imap[nimaps].br_startoff + imap[nimaps].br_blockcount); + ASSERT(count_fsb); + offset_fsb = imap[nimaps].br_startoff + imap[nimaps].br_blockcount; + map_start_fsb = offset_fsb; + XFS_STATS_INC(xfsstats.xs_xstrat_split); + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_WR); + } + + ASSERT(0); /* Should never get here */ + + error0: + if (error) { + ASSERT(count_fsb != 0); + ASSERT(is_xfs || XFS_FORCED_SHUTDOWN(mp)); + } + + return XFS_ERROR(error); +} + + +STATIC int +_xfs_imap_to_bmap( + xfs_iocore_t *io, + xfs_off_t offset, + xfs_bmbt_irec_t *imap, + pb_bmap_t *pbmapp, + int imaps, /* Number of imap entries */ + int pbmaps) /* Number of pbmap entries */ +{ + xfs_mount_t *mp; + xfs_fsize_t nisize; + int im, pbm; + xfs_fsblock_t start_block; + + mp = io->io_mount; + nisize = XFS_SIZE(mp, io); + if (io->io_new_size > nisize) + nisize = io->io_new_size; + + for (im=0, pbm=0; im < imaps && pbm < pbmaps; im++,pbmapp++,imap++,pbm++) { + pbmapp->pbm_target = io->io_flags & XFS_IOCORE_RT ? + mp->m_rtdev_targp : + mp->m_ddev_targp; + pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imap->br_startoff); + pbmapp->pbm_delta = offset - pbmapp->pbm_offset; + pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount); + pbmapp->pbm_flags = 0; + + start_block = imap->br_startblock; + if (start_block == HOLESTARTBLOCK) { + pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL; + pbmapp->pbm_flags = PBMF_HOLE; + } else if (start_block == DELAYSTARTBLOCK) { + pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL; + pbmapp->pbm_flags = PBMF_DELAY; + } else { + pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block); + if (imap->br_state == XFS_EXT_UNWRITTEN) + pbmapp->pbm_flags |= PBMF_UNWRITTEN; + } + + if ((pbmapp->pbm_offset + pbmapp->pbm_bsize) >= nisize) { + pbmapp->pbm_flags |= PBMF_EOF; + } + + offset += pbmapp->pbm_bsize - pbmapp->pbm_delta; + } + return(pbm); /* Return the number filled */ +} + +STATIC int +xfs_iomap_read( + xfs_iocore_t *io, + loff_t offset, + size_t count, + int flags, + pb_bmap_t *pbmapp, + int *npbmaps, + struct pm *pmp) +{ + xfs_fileoff_t offset_fsb; + xfs_fileoff_t end_fsb; + int nimaps; + int error; + xfs_mount_t *mp; + xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS]; + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE | MR_ACCESS) != 0); +/** ASSERT(ismrlocked(io->io_iolock, MR_UPDATE | MR_ACCESS) != 0); **/ +/* xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count); */ + + mp = io->io_mount; + offset_fsb = XFS_B_TO_FSBT(mp, offset); + nimaps = sizeof(imap) / sizeof(imap[0]); + nimaps = min(nimaps, *npbmaps); /* Don't ask for more than caller has */ + end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + error = XFS_BMAPI(mp, NULL, io, offset_fsb, + (xfs_filblks_t)(end_fsb - offset_fsb), + flags, NULL, 0, imap, + &nimaps, NULL); + if (error) { + return XFS_ERROR(error); + } + + if(nimaps) { + *npbmaps = _xfs_imap_to_bmap(io, offset, imap, pbmapp, nimaps, + *npbmaps); + } else + *npbmaps = 0; + return XFS_ERROR(error); +} + +/* + * xfs_iomap_write: return pagebuf_bmap_t's telling higher layers + * where to write. + * There are 2 main cases: + * 1 the extents already exist + * 2 must allocate. + * There are 3 cases when we allocate: + * delay allocation (doesn't really allocate or use transactions) + * direct allocation (no previous delay allocation + * convert delay to real allocations + */ + +STATIC int +xfs_iomap_write( + xfs_iocore_t *io, + loff_t offset, + size_t count, + pb_bmap_t *pbmapp, + int *npbmaps, + int ioflag, + struct pm *pmp) +{ + int maps; + int error = 0; + int found; + int flags = 0; + + maps = *npbmaps; + if (!maps) + goto out; + + /* + * If we have extents that are allocated for this range, + * return them. + */ + + found = 0; + error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps, NULL); + if (error) + goto out; + + /* + * If we found mappings and they can just have data written + * without conversion, + * let the caller write these and call us again. + * + * If we have a HOLE or UNWRITTEN, proceed down lower to + * get the space or to convert to written. + */ + + if (*npbmaps) { + if (!(pbmapp->pbm_flags & PBMF_HOLE)) { + *npbmaps = 1; /* Only checked the first one. */ + /* We could check more, ... */ + goto out; + } + } + found = *npbmaps; + *npbmaps = maps; /* Restore to original requested */ + + if (ioflag & PBF_DIRECT) { + error = xfs_iomap_write_direct(io, offset, count, pbmapp, + npbmaps, ioflag, found); + } else { + error = xfs_iomap_write_delay(io, offset, count, pbmapp, + npbmaps, ioflag, found); + } + +out: + XFS_IUNLOCK(io->io_mount, io, XFS_ILOCK_EXCL); + return XFS_ERROR(error); +} + +/* + * Map the given I/O size and I/O alignment over the given extent. + * If we're at the end of the file and the underlying extent is + * delayed alloc, make sure we extend out to the + * next i_writeio_blocks boundary. Otherwise make sure that we + * are confined to the given extent. + */ +/*ARGSUSED*/ +STATIC void +xfs_write_bmap( + xfs_mount_t *mp, + xfs_iocore_t *io, + xfs_bmbt_irec_t *imapp, + pb_bmap_t *pbmapp, + int iosize, + xfs_fileoff_t ioalign, + xfs_fsize_t isize) +{ + __int64_t extra_blocks; + xfs_fileoff_t size_diff; + xfs_fileoff_t ext_offset; + xfs_fsblock_t start_block; + int length; /* length of this mapping in blocks */ + xfs_off_t offset; /* logical block offset of this mapping */ + + if (ioalign < imapp->br_startoff) { + /* + * The desired alignment doesn't end up on this + * extent. Move up to the beginning of the extent. + * Subtract whatever we drop from the iosize so that + * we stay aligned on iosize boundaries. + */ + size_diff = imapp->br_startoff - ioalign; + iosize -= (int)size_diff; + ASSERT(iosize > 0); + ext_offset = 0; + offset = imapp->br_startoff; + pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imapp->br_startoff); + } else { + /* + * The alignment requested fits on this extent, + * so use it. + */ + ext_offset = ioalign - imapp->br_startoff; + offset = ioalign; + pbmapp->pbm_offset = XFS_FSB_TO_B(mp, ioalign); + } + start_block = imapp->br_startblock; + ASSERT(start_block != HOLESTARTBLOCK); + if (start_block != DELAYSTARTBLOCK) { + pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block + ext_offset); + if (imapp->br_state == XFS_EXT_UNWRITTEN) { + pbmapp->pbm_flags = PBMF_UNWRITTEN; + } + } else { + pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL; + pbmapp->pbm_flags = PBMF_DELAY; + } + pbmapp->pbm_target = io->io_flags & XFS_IOCORE_RT ? + mp->m_rtdev_targp : + mp->m_ddev_targp; + length = iosize; + + /* + * If the iosize from our offset extends beyond the end of + * the extent, then trim down length to match that of the extent. + */ + extra_blocks = (xfs_off_t)(offset + length) - + (__uint64_t)(imapp->br_startoff + + imapp->br_blockcount); + if (extra_blocks > 0) { + length -= extra_blocks; + ASSERT(length > 0); + } + + pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, length); +} + +STATIC int +xfs_iomap_write_delay( + xfs_iocore_t *io, + loff_t offset, + size_t count, + pb_bmap_t *pbmapp, + int *npbmaps, + int ioflag, + int found) +{ + xfs_fileoff_t offset_fsb; + xfs_fileoff_t ioalign; + xfs_fileoff_t last_fsb; + xfs_fileoff_t start_fsb; + xfs_filblks_t count_fsb; + xfs_off_t aligned_offset; + xfs_fsize_t isize; + xfs_fsblock_t firstblock; + __uint64_t last_page_offset; + int nimaps; + int error; + int n; + unsigned int iosize; + short small_write; + xfs_mount_t *mp; +#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP + xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS]; + int aeof; + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); + +/* xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count); */ + + mp = io->io_mount; +/*** + ASSERT(! XFS_NOT_DQATTACHED(mp, ip)); +***/ + + isize = XFS_SIZE(mp, io); + if (io->io_new_size > isize) { + isize = io->io_new_size; + } + + aeof = 0; + offset_fsb = XFS_B_TO_FSBT(mp, offset); + last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + /* + * If the caller is doing a write at the end of the file, + * then extend the allocation (and the buffer used for the write) + * out to the file system's write iosize. We clean up any extra + * space left over when the file is closed in xfs_inactive(). + * We can only do this if we are sure that we will create buffers + * over all of the space we allocate beyond the end of the file. + * Not doing so would allow us to create delalloc blocks with + * no pages in memory covering them. So, we need to check that + * there are not any real blocks in the area beyond the end of + * the file which we are optimistically going to preallocate. If + * there are then our buffers will stop when they encounter them + * and we may accidentally create delalloc blocks beyond them + * that we never cover with a buffer. All of this is because + * we are not actually going to write the extra blocks preallocated + * at this point. + * + * We don't bother with this for sync writes, because we need + * to minimize the amount we write for good performance. + */ + if (!(ioflag & PBF_SYNC) && ((offset + count) > XFS_SIZE(mp, io))) { + start_fsb = XFS_B_TO_FSBT(mp, + ((xfs_ufsize_t)(offset + count - 1))); + count_fsb = mp->m_writeio_blocks; + while (count_fsb > 0) { + nimaps = XFS_WRITE_IMAPS; + error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, + 0, NULL, 0, imap, &nimaps, + NULL); + if (error) { + return error; + } + for (n = 0; n < nimaps; n++) { + if ((imap[n].br_startblock != HOLESTARTBLOCK) && + (imap[n].br_startblock != DELAYSTARTBLOCK)) { + goto write_map; + } + start_fsb += imap[n].br_blockcount; + count_fsb -= imap[n].br_blockcount; + ASSERT(count_fsb < 0xffff000); + } + } + iosize = mp->m_writeio_blocks; + aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1)); + ioalign = XFS_B_TO_FSBT(mp, aligned_offset); + last_fsb = ioalign + iosize; + aeof = 1; + } + write_map: + nimaps = XFS_WRITE_IMAPS; + firstblock = NULLFSBLOCK; + + /* + * roundup the allocation request to m_dalign boundary if file size + * is greater that 512K and we are allocating past the allocation eof + */ + if (mp->m_dalign && (XFS_SIZE(mp, io) >= mp->m_dalign) && aeof) { + int eof; + xfs_fileoff_t new_last_fsb; + new_last_fsb = roundup_64(last_fsb, mp->m_dalign); + error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); + if (error) { + return error; + } + if (eof) { + last_fsb = new_last_fsb; + } + } + + error = XFS_BMAPI(mp, NULL, io, offset_fsb, + (xfs_filblks_t)(last_fsb - offset_fsb), + XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | + XFS_BMAPI_ENTIRE, &firstblock, 1, imap, + &nimaps, NULL); + /* + * This can be EDQUOT, if nimaps == 0 + */ + if (error) { + return XFS_ERROR(error); + } + /* + * If bmapi returned us nothing, and if we didn't get back EDQUOT, + * then we must have run out of space. + */ + if (nimaps == 0) { +/* xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE, + io, offset, count); */ + return XFS_ERROR(ENOSPC); + } + + if (!(ioflag & PBF_SYNC) || + ((last_fsb - offset_fsb) >= mp->m_writeio_blocks)) { + /* + * For normal or large sync writes, align everything + * into i_writeio_blocks sized chunks. + */ + iosize = mp->m_writeio_blocks; + aligned_offset = XFS_WRITEIO_ALIGN(mp, offset); + ioalign = XFS_B_TO_FSBT(mp, aligned_offset); + small_write = 0; + /* XXX - Are we shrinking? XXXXX */ + } else { + /* + * For small sync writes try to minimize the amount + * of I/O we do. Round down and up to the larger of + * page or block boundaries. Set the small_write + * variable to 1 to indicate to the code below that + * we are not using the normal buffer alignment scheme. + */ + if (NBPP > mp->m_sb.sb_blocksize) { + aligned_offset = ctooff(offtoct(offset)); + ioalign = XFS_B_TO_FSBT(mp, aligned_offset); + last_page_offset = ctob64(btoc64(offset + count)); + iosize = XFS_B_TO_FSBT(mp, last_page_offset - + aligned_offset); + } else { + ioalign = offset_fsb; + iosize = last_fsb - offset_fsb; + } + small_write = 1; + /* XXX - Are we shrinking? XXXXX */ + } + + /* + * Now map our desired I/O size and alignment over the + * extents returned by xfs_bmapi(). + */ + xfs_write_bmap(mp, io, imap, pbmapp, iosize, ioalign, isize); + pbmapp->pbm_delta = offset - pbmapp->pbm_offset; + + ASSERT((pbmapp->pbm_bsize > 0) + && (pbmapp->pbm_bsize - pbmapp->pbm_delta > 0)); + + /* + * A bmap is the EOF bmap when it reaches to or beyond the new + * inode size. + */ + if ((pbmapp->pbm_offset + pbmapp->pbm_bsize ) >= isize) { + pbmapp->pbm_flags |= PBMF_EOF; + } + +/* xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, + io, offset, count, bmapp, imap); */ + + /* On IRIX, we walk more imaps filling in more bmaps. On Linux + just handle one for now. To find the code on IRIX, + look in xfs_iomap_write() in xfs_rw.c. */ + + *npbmaps = 1; + return 0; +} + +STATIC int +xfs_iomap_write_direct( + xfs_iocore_t *io, + loff_t offset, + size_t count, + pb_bmap_t *pbmapp, + int *npbmaps, + int ioflag, + int found) +{ + xfs_inode_t *ip = XFS_IO_INODE(io); + xfs_mount_t *mp; + xfs_fileoff_t offset_fsb; + xfs_fileoff_t last_fsb; + xfs_filblks_t count_fsb; + xfs_fsize_t isize; + xfs_fsblock_t firstfsb; + int nimaps, maps; + int error; + xfs_trans_t *tp; + +#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP + xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp; + xfs_bmap_free_t free_list; + int aeof; + int bmapi_flags; + xfs_filblks_t datablocks; + int rt; + int committed; + int numrtextents; + uint resblks; + int rtextsize; + + maps = min(XFS_WRITE_IMAPS, *npbmaps); + nimaps = maps; + + mp = io->io_mount; + isize = XFS_SIZE(mp, io); + if (io->io_new_size > isize) + isize = io->io_new_size; + + if ((offset + count) > isize) { + aeof = 1; + } else { + aeof = 0; + } + + offset_fsb = XFS_B_TO_FSBT(mp, offset); + last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + count_fsb = last_fsb - offset_fsb; + if (found && (pbmapp->pbm_flags & PBMF_HOLE)) { + xfs_fileoff_t map_last_fsb; + map_last_fsb = XFS_B_TO_FSB(mp, + (pbmapp->pbm_bsize + pbmapp->pbm_offset)); + + if (map_last_fsb < last_fsb) { + last_fsb = map_last_fsb; + count_fsb = last_fsb - offset_fsb; + } + ASSERT(count_fsb > 0); + } + + /* + * roundup the allocation request to m_dalign boundary if file size + * is greater that 512K and we are allocating past the allocation eof + */ + if (!found && mp->m_dalign && (isize >= 524288) && aeof) { + int eof; + xfs_fileoff_t new_last_fsb; + new_last_fsb = roundup_64(last_fsb, mp->m_dalign); + printk("xfs_iomap_write_direct: about to XFS_BMAP_EOF %Ld\n", + new_last_fsb); + error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); + if (error) { + goto error_out; + } + if (eof) + last_fsb = new_last_fsb; + } + + bmapi_flags = XFS_BMAPI_WRITE|XFS_BMAPI_DIRECT_IO|XFS_BMAPI_ENTIRE; + bmapi_flags &= ~XFS_BMAPI_DIRECT_IO; + + /* + * determine if this is a realtime file + */ + if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) { + rtextsize = mp->m_sb.sb_rextsize; + } else + rtextsize = 0; + + error = 0; + + /* + * allocate file space for the bmapp entries passed in. + */ + + /* + * determine if reserving space on + * the data or realtime partition. + */ + if (rt) { + numrtextents = (count_fsb + rtextsize - 1); + do_div(numrtextents, rtextsize); + datablocks = 0; + } else { + datablocks = count_fsb; + numrtextents = 0; + } + + /* + * allocate and setup the transaction + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); + resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks); + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + error = xfs_trans_reserve(tp, + resblks, + XFS_WRITE_LOG_RES(mp), + numrtextents, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + + /* + * check for running out of space + */ + if (error) { + /* + * Free the transaction structure. + */ + xfs_trans_cancel(tp, 0); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + + if (error) { + goto error_out; /* Don't return in above if .. trans .., + need lock to return */ + } + + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, + ip->i_udquot, + ip->i_gdquot, + resblks, 0, 0)) { + error = (EDQUOT); + goto error1; + } + nimaps = 1; + } else { + nimaps = 2; + } + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * issue the bmapi() call to allocate the blocks + */ + XFS_BMAP_INIT(&free_list, &firstfsb); + imapp = &imap[0]; + error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, + bmapi_flags, &firstfsb, 1, imapp, &nimaps, &free_list); + if (error) { + goto error0; + } + + /* + * complete the transaction + */ + + error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + if (error) { + goto error0; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + goto error_out; + } + + /* copy any maps to caller's array and return any error. */ + if (nimaps == 0) { + error = (ENOSPC); + goto error_out; + } + + maps = min(nimaps, maps); + *npbmaps = _xfs_imap_to_bmap(io, offset, &imap[0], pbmapp, maps, + *npbmaps); + if(*npbmaps) { + /* + * this is new since xfs_iomap_read + * didn't find it. + */ + if (*npbmaps != 1) { + printk("NEED MORE WORK FOR MULTIPLE BMAPS (which are new)\n"); + } + } + goto out; + + error0: /* Cancel bmap, unlock inode, and cancel trans */ + xfs_bmap_cancel(&free_list); + + error1: /* Just cancel transaction */ + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + *npbmaps = 0; /* nothing set-up here */ + +error_out: +out: /* Just return error and any tracing at end of routine */ + return XFS_ERROR(error); +} + + +/* + * All xfs metadata buffers except log state machine buffers + * get this attached as their b_bdstrat callback function. + * This is so that we can catch a buffer + * after prematurely unpinning it to forcibly shutdown the filesystem. + */ +int +xfs_bdstrat_cb(struct xfs_buf *bp) +{ + xfs_mount_t *mp; + + mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); + if (!XFS_FORCED_SHUTDOWN(mp)) { + pagebuf_iorequest(bp); + return 0; + } else { + xfs_buftrace("XFS__BDSTRAT IOERROR", bp); + /* + * Metadata write that didn't get logged but + * written delayed anyway. These aren't associated + * with a transaction, and can be ignored. + */ + if (XFS_BUF_IODONE_FUNC(bp) == NULL && + (XFS_BUF_ISREAD(bp)) == 0) + return (xfs_bioerror_relse(bp)); + else + return (xfs_bioerror(bp)); + } +} +/* + * Wrapper around bdstrat so that we can stop data + * from going to disk in case we are shutting down the filesystem. + * Typically user data goes thru this path; one of the exceptions + * is the superblock. + */ +int +xfsbdstrat( + struct xfs_mount *mp, + struct xfs_buf *bp) +{ + ASSERT(mp); + if (!XFS_FORCED_SHUTDOWN(mp)) { + /* Grio redirection would go here + * if (XFS_BUF_IS_GRIO(bp)) { + */ + + pagebuf_iorequest(bp); + return 0; + } + + xfs_buftrace("XFSBDSTRAT IOERROR", bp); + return (xfs_bioerror_relse(bp)); +} + + +void +XFS_bflush(xfs_buftarg_t *target) +{ + pagebuf_delwri_flush(target, PBDF_WAIT, NULL); +} + + +/* Push all fs state out to disk + */ + +void +XFS_log_write_unmount_ro(bhv_desc_t *bdp) +{ + xfs_mount_t *mp; + int pincount = 0; + int count = 0; + int error; + + mp = XFS_BHVTOM(bdp); + xfs_refcache_purge_mp(mp); + pagebuf_delwri_flush(mp->m_ddev_targp, PBDF_WAIT, &pincount); + xfs_finish_reclaim_all(mp); + + do { + VFS_SYNC(XFS_MTOVFS(mp), SYNC_ATTR|SYNC_WAIT, NULL, error); + pagebuf_delwri_flush(mp->m_ddev_targp, PBDF_WAIT, &pincount); + if (pincount == 0) {delay(50); count++;} + } while (count < 2); + + /* Ok now write out an unmount record */ + xfs_log_unmount_write(mp); + xfs_unmountfs_writesb(mp); +} + +/* + * If the underlying (log or data) device is readonly, there are some + * operations that cannot proceed. + */ +int +xfs_dev_is_read_only(xfs_mount_t *mp, char *message) +{ + if (is_read_only(mp->m_ddev_targp->pbr_kdev) || + is_read_only(mp->m_logdev_targp->pbr_kdev) || + (mp->m_rtdev_targp && is_read_only(mp->m_rtdev_targp->pbr_kdev))) { + cmn_err(CE_NOTE, + "XFS: %s required on read-only device.", message); + cmn_err(CE_NOTE, + "XFS: write access unavailable, cannot proceed."); + return EROFS; + } + + return 0; +} + diff -Nur linux-2.4.19/fs/xfs/linux/xfs_lrw.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_lrw.h --- linux-2.4.19/fs/xfs/linux/xfs_lrw.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_lrw.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_LRW_H__ +#define __XFS_LRW_H__ + +#define XFS_IOMAP_READ_ENTER 3 +/* + * Maximum count of bmaps used by read and write paths. + */ +#define XFS_MAX_RW_NBMAPS 4 + +extern int xfs_bmap (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *); +extern int xfs_strategy (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *); +extern int xfsbdstrat (struct xfs_mount *, struct xfs_buf *); +extern int xfs_bdstrat_cb (struct xfs_buf *); + +extern int xfs_zero_eof (vnode_t *, struct xfs_iocore *, xfs_off_t, + xfs_fsize_t, xfs_fsize_t, struct pm *); +extern ssize_t xfs_read ( + struct bhv_desc *bdp, + struct file *file, + char *buf, + size_t size, + loff_t *offset, + struct cred *credp); + +extern ssize_t xfs_write ( + struct bhv_desc *bdp, + struct file *file, + const char *buf, + size_t size, + loff_t *offset, + struct cred *credp); + +extern int xfs_dev_is_read_only(xfs_mount_t *, char *); + +extern void XFS_log_write_unmount_ro (bhv_desc_t *); + +#define XFS_FSB_TO_DB_IO(io,fsb) \ + (((io)->io_flags & XFS_IOCORE_RT) ? \ + XFS_FSB_TO_BB((io)->io_mount, (fsb)) : \ + XFS_FSB_TO_DADDR((io)->io_mount, (fsb))) + +#endif /* __XFS_LRW_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_stats.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_stats.c --- linux-2.4.19/fs/xfs/linux/xfs_stats.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_stats.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +static int +xfs_read_xfsstats(char *buffer, char **start, off_t offset, + int count, int *eof, void *data) +{ + int i, j, len; + static struct xstats_entry { + char *desc; + int endpoint; + } xstats[] = { + { "extent_alloc", XFSSTAT_END_EXTENT_ALLOC }, + { "abt", XFSSTAT_END_ALLOC_BTREE }, + { "blk_map", XFSSTAT_END_BLOCK_MAPPING }, + { "bmbt", XFSSTAT_END_BLOCK_MAP_BTREE }, + { "dir", XFSSTAT_END_DIRECTORY_OPS }, + { "trans", XFSSTAT_END_TRANSACTIONS }, + { "ig", XFSSTAT_END_INODE_OPS }, + { "log", XFSSTAT_END_LOG_OPS }, + { "push_ail", XFSSTAT_END_TAIL_PUSHING }, + { "xstrat", XFSSTAT_END_WRITE_CONVERT }, + { "rw", XFSSTAT_END_READ_WRITE_OPS }, + { "attr", XFSSTAT_END_ATTRIBUTE_OPS }, + { "qm", XFSSTAT_END_QUOTA_OPS }, + { "icluster", XFSSTAT_END_INODE_CLUSTER }, + { "vnodes", XFSSTAT_END_VNODE_OPS }, + }; + + for (i=j=len = 0; i < sizeof(xstats)/sizeof(struct xstats_entry); i++) { + len += sprintf(buffer + len, xstats[i].desc); + /* inner loop does each group */ + while (j < xstats[i].endpoint) { + len += sprintf(buffer + len, " %u", + *(((__u32*)&xfsstats) + j)); + j++; + } + buffer[len++] = '\n'; + } + /* extra precision counters */ + len += sprintf(buffer + len, "xpc %Lu %Lu %Lu\n", + xfsstats.xs_xstrat_bytes, + xfsstats.xs_write_bytes, + xfsstats.xs_read_bytes); + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} + +static int +xfs_read_xfsquota(char *buffer, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len; + + /* maximum; incore; ratio free to inuse; freelist */ + len = sprintf(buffer, "%d\t%d\t%d\t%u\n", + ndquot, + xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0, + xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0, + xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0); + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} + +void +xfs_init_procfs(void) +{ + if (!proc_mkdir("fs/xfs", 0)) + return; + create_proc_read_entry("fs/xfs/stat", 0, 0, xfs_read_xfsstats, NULL); + create_proc_read_entry("fs/xfs/xqm", 0, 0, xfs_read_xfsquota, NULL); +} + +void +xfs_cleanup_procfs(void) +{ + remove_proc_entry("fs/xfs/stat", NULL); + remove_proc_entry("fs/xfs/xqm", NULL); + remove_proc_entry("fs/xfs", NULL); +} diff -Nur linux-2.4.19/fs/xfs/linux/xfs_stats.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_stats.h --- linux-2.4.19/fs/xfs/linux/xfs_stats.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_stats.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_STATS_H__ +#define __XFS_STATS_H__ + +/* + * procfs interface + */ +#ifdef CONFIG_PROC_FS +extern void xfs_init_procfs(void); +extern void xfs_cleanup_procfs(void); +#else +static __inline void xfs_init_procfs(void) { }; +static __inline void xfs_cleanup_procfs(void) { }; +#endif + +#endif /* __XFS_STATS_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_super.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_super.c --- linux-2.4.19/fs/xfs/linux/xfs_super.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_super.c Fri Dec 13 10:22:56 2002 @@ -0,0 +1,953 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include "xfs_version.h" + +/* xfs_vfs[ops].c */ +extern int xfs_init(void); +extern void xfs_cleanup(void); + +/* For kernels which have the s_maxbytes field - set it */ +#ifdef MAX_NON_LFS +# define set_max_bytes(sb) ((sb)->s_maxbytes = XFS_MAX_FILE_OFFSET) +#else +# define set_max_bytes(sb) do { } while (0) +#endif + +#ifdef CONFIG_FS_POSIX_ACL +# define set_posix_acl(sb) ((sb)->s_flags |= MS_POSIXACL) +#else +# define set_posix_acl(sb) do { } while (0) +#endif + +#ifdef CONFIG_XFS_QUOTA +STATIC struct quotactl_ops linvfs_qops = { + .get_xstate = linvfs_getxstate, + .set_xstate = linvfs_setxstate, + .get_xquota = linvfs_getxquota, + .set_xquota = linvfs_setxquota, +}; +# define set_quota_ops(sb) ((sb)->s_qcop = &linvfs_qops) +#else +# define set_quota_ops(sb) do { } while (0) +#endif + +#ifdef CONFIG_XFS_DMAPI +int dmapi_init(void); +void dmapi_uninit(void); +#else +#define dmapi_init() +#define dmapi_uninit() +#endif + +STATIC struct super_operations linvfs_sops; + +#define MNTOPT_LOGBUFS "logbufs" /* number of XFS log buffers */ +#define MNTOPT_LOGBSIZE "logbsize" /* size of XFS log buffers */ +#define MNTOPT_LOGDEV "logdev" /* log device */ +#define MNTOPT_RTDEV "rtdev" /* realtime I/O device */ +#define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_BIOSIZE "biosize" /* log2 of preferred buffered io size */ +#define MNTOPT_WSYNC "wsync" /* safe-mode nfs compatible mount */ +#define MNTOPT_INO64 "ino64" /* force inodes into 64-bit range */ +#define MNTOPT_NOALIGN "noalign" /* turn off stripe alignment */ +#define MNTOPT_SUNIT "sunit" /* data volume stripe unit */ +#define MNTOPT_SWIDTH "swidth" /* data volume stripe width */ +#define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ +#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */ +#define MNTOPT_QUOTA "quota" /* disk quotas */ +#define MNTOPT_MRQUOTA "mrquota" /* don't turnoff if SB has quotas on */ +#define MNTOPT_NOQUOTA "noquota" /* no quotas */ +#define MNTOPT_UQUOTA "usrquota" /* user quota enabled */ +#define MNTOPT_GQUOTA "grpquota" /* group quota enabled */ +#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ +#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ +#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ +#define MNTOPT_NOUUID "nouuid" /* Ignore FS uuid */ +#define MNTOPT_NOLOGFLUSH "nologflush" /* Don't use hard flushes in + log writing */ +#define MNTOPT_MTPT "mtpt" /* filesystem mount point */ + +STATIC int +xfs_parseargs( + char *options, + int flags, + struct xfs_mount_args *args) +{ + char *this_char, *value, *eov; + int logbufs = -1; + int logbufsize = -1; + int dsunit, dswidth, vol_dsunit, vol_dswidth; + int iosize; + int rval = 1; /* failure is default */ + + iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0; + + /* Copy the already-parsed mount(2) flags we're interested in */ + if (flags & MS_NOATIME) + args->flags |= XFSMNT_NOATIME; + + if (!options) { + args->logbufs = logbufs; + args->logbufsize = logbufsize; + return 0; + } + + while ((this_char = strsep(&options, ",")) != NULL) { + if (!*this_char) + continue; + if ((value = strchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!strcmp(this_char, MNTOPT_LOGBUFS)) { + logbufs = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { + int in_kilobytes = 0; + + if (toupper(value[strlen(value)-1]) == 'K') { + in_kilobytes = 1; + value[strlen(value)-1] = '\0'; + } + logbufsize = simple_strtoul(value, &eov, 10); + if (in_kilobytes) + logbufsize = logbufsize * 1024; + } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { + strncpy(args->logname, value, MAXNAMELEN); + } else if (!strcmp(this_char, MNTOPT_MTPT)) { + strncpy(args->mtpt, value, MAXNAMELEN); +#if CONFIG_XFS_DMAPI + } else if (!strcmp(this_char, MNTOPT_DMAPI)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, MNTOPT_XDSM)) { + args->flags |= XFSMNT_DMAPI; +#else + } else if (!strcmp(this_char, MNTOPT_DMAPI) || + !strcmp(this_char, MNTOPT_XDSM)) { + printk("XFS: this kernel does not support dmapi/xdsm.\n"); + return rval; +#endif + } else if (!strcmp(this_char, MNTOPT_RTDEV)) { + strncpy(args->rtname, value, MAXNAMELEN); + } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { + iosize = simple_strtoul(value, &eov, 10); + args->flags |= XFSMNT_IOSIZE; + args->iosizelog = (uint8_t) iosize; + } else if (!strcmp(this_char, MNTOPT_WSYNC)) { + args->flags |= XFSMNT_WSYNC; + } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) { + args->flags |= XFSMNT_OSYNCISOSYNC; + } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) { + args->flags |= XFSMNT_NORECOVERY; + } else if (!strcmp(this_char, MNTOPT_INO64)) { +#ifdef XFS_BIG_FILESYSTEMS + args->flags |= XFSMNT_INO64; +#else + printk("XFS: ino64 option not allowed on this system\n"); + return rval; +#endif + } else if (!strcmp(this_char, MNTOPT_UQUOTA)) { + args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_QUOTA)) { + args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_UQUOTANOENF)) { + args->flags |= XFSMNT_UQUOTA; + args->flags &= ~XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_QUOTANOENF)) { + args->flags |= XFSMNT_UQUOTA; + args->flags &= ~XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_GQUOTA)) { + args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { + args->flags |= XFSMNT_GQUOTA; + args->flags &= ~XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_NOALIGN)) { + args->flags |= XFSMNT_NOALIGN; + } else if (!strcmp(this_char, MNTOPT_SUNIT)) { + dsunit = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { + dswidth = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_NOUUID)) { + args->flags |= XFSMNT_NOUUID; + } else if (!strcmp(this_char, MNTOPT_NOLOGFLUSH)) { + args->flags |= XFSMNT_NOLOGFLUSH; + } else if (!strcmp(this_char, "osyncisdsync")) { + /* no-op, this is now the default */ +printk("XFS: osyncisdsync is now the default, option is deprecated.\n"); + } else if (!strcmp(this_char, "irixsgid")) { +printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n"); + } else { + printk("XFS: unknown mount option [%s].\n", this_char); + return rval; + } + } + + if (args->flags & XFSMNT_NORECOVERY) { + if ((flags & MS_RDONLY) == 0) { + printk("XFS: no-recovery mounts must be read-only.\n"); + return rval; + } + } + + if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) { + printk( + "XFS: sunit and swidth options incompatible with the noalign option\n"); + return rval; + } + + if ((dsunit && !dswidth) || (!dsunit && dswidth)) { + printk("XFS: sunit and swidth must be specified together\n"); + return rval; + } + + if (dsunit && (dswidth % dsunit != 0)) { + printk( + "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)\n", + dswidth, dsunit); + return rval; + } + + if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { + if (dsunit) { + args->sunit = dsunit; + args->flags |= XFSMNT_RETERR; + } else + args->sunit = vol_dsunit; + dswidth ? (args->swidth = dswidth) : + (args->swidth = vol_dswidth); + } else + args->sunit = args->swidth = 0; + + args->logbufs = logbufs; + args->logbufsize = logbufsize; + + return 0; +} + +STATIC int +xfs_showargs( + struct vfs *vfsp, + struct seq_file *m) +{ + static struct proc_xfs_info { + int flag; + char *str; + } xfs_info[] = { + /* the few simple ones we can get from the mount struct */ + { XFS_MOUNT_NOALIGN, "," MNTOPT_NOALIGN }, + { XFS_MOUNT_NORECOVERY, "," MNTOPT_NORECOVERY }, + { XFS_MOUNT_OSYNCISOSYNC, "," MNTOPT_OSYNCISOSYNC }, + { XFS_MOUNT_NOUUID, "," MNTOPT_NOUUID }, + { 0, NULL } + }; + struct proc_xfs_info *xfs_infop; + struct xfs_mount *mp = XFS_BHVTOM(vfsp->vfs_fbhv); + + for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) { + if (mp->m_flags & xfs_infop->flag) + seq_puts(m, xfs_infop->str); + } + + if (mp->m_qflags & XFS_UQUOTA_ACCT) { + (mp->m_qflags & XFS_UQUOTA_ENFD) ? + seq_puts(m, "," MNTOPT_UQUOTA) : + seq_puts(m, "," MNTOPT_UQUOTANOENF); + } + + if (mp->m_qflags & XFS_GQUOTA_ACCT) { + (mp->m_qflags & XFS_GQUOTA_ENFD) ? + seq_puts(m, "," MNTOPT_GQUOTA) : + seq_puts(m, "," MNTOPT_GQUOTANOENF); + } + + if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) + seq_printf(m, "," MNTOPT_BIOSIZE "=%d", mp->m_writeio_log); + + if (mp->m_logbufs > 0) + seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs); + + if (mp->m_logbsize > 0) + seq_printf(m, "," MNTOPT_LOGBSIZE "=%d", mp->m_logbsize); + + if (mp->m_ddev_targp->pbr_dev != mp->m_logdev_targp->pbr_dev) + seq_printf(m, "," MNTOPT_LOGDEV "=%s", + bdevname(mp->m_logdev_targp->pbr_dev)); + + if (mp->m_rtdev_targp && + mp->m_ddev_targp->pbr_dev != mp->m_rtdev_targp->pbr_dev) + seq_printf(m, "," MNTOPT_RTDEV "=%s", + bdevname(mp->m_rtdev_targp->pbr_dev)); + + if (mp->m_dalign > 0) + seq_printf(m, "," MNTOPT_SUNIT "=%d", + (int)XFS_FSB_TO_BB(mp, mp->m_dalign)); + + if (mp->m_swidth > 0) + seq_printf(m, "," MNTOPT_SWIDTH "=%d", + (int)XFS_FSB_TO_BB(mp, mp->m_swidth)); + + if (vfsp->vfs_flag & VFS_DMI) + seq_puts(m, "," MNTOPT_DMAPI); + + return 0; +} + +/* + * Convert one device special file to a dev_t. + * Helper routine, used only by spectodevs below. + */ +STATIC int +spectodev( + const char *name, + const char *id, + dev_t *dev) +{ + struct nameidata nd; + int rval = 0; + + if (path_init(name, LOOKUP_FOLLOW, &nd)) + rval = path_walk(name, &nd); + /* Watch out for negative dentries */ + if (!nd.dentry->d_inode) + rval = -ENOENT; + if (rval) + printk("XFS: Invalid %s device [%s], err=%d\n", id, name, rval); + else + *dev = nd.dentry->d_inode->i_rdev; + path_release(&nd); + return rval; +} + +/* + * Convert device special files to dev_t for data, log, realtime. + */ +int +spectodevs( + struct super_block *sb, + struct xfs_mount_args *args, + dev_t *ddevp, + dev_t *logdevp, + dev_t *rtdevp) +{ + int rval = 0; + + *ddevp = sb->s_dev; + + if (args->logname[0]) + rval = spectodev(args->logname, "log", logdevp); + else + *logdevp = sb->s_dev; + + if (args->rtname[0] && !rval) + rval = spectodev(args->rtname, "realtime", rtdevp); + else + *rtdevp = 0; + return rval; +} + + +STATIC kmem_cache_t * linvfs_inode_cachep; + +STATIC __inline__ unsigned int gfp_mask(void) +{ + /* If we're not in a transaction, FS activity is ok */ + if (current->flags & PF_FSTRANS) return GFP_NOFS; + return GFP_KERNEL; +} + + +STATIC struct inode * +linvfs_alloc_inode( + struct super_block *sb) +{ + vnode_t *vp; + + vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep, gfp_mask()); + if (!vp) + return NULL; + return LINVFS_GET_IP(vp); +} + +STATIC void +linvfs_destroy_inode( + struct inode *inode) +{ + kmem_cache_free(linvfs_inode_cachep, LINVFS_GET_VP(inode)); +} + +STATIC void +init_once( + void *data, + kmem_cache_t *cachep, + unsigned long flags) +{ + vnode_t *vp = (vnode_t *)data; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once(LINVFS_GET_IP(vp)); +} + +STATIC int +init_inodecache( void ) +{ + linvfs_inode_cachep = kmem_cache_create("linvfs_icache", + sizeof(vnode_t), 0, SLAB_HWCACHE_ALIGN, + init_once, NULL); + + if (linvfs_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + +STATIC void +destroy_inodecache( void ) +{ + if (kmem_cache_destroy(linvfs_inode_cachep)) + printk(KERN_INFO + "linvfs_inode_cache: not all structures were freed\n"); +} + +struct super_block * +linvfs_read_super( + struct super_block *sb, + void *data, + int silent) +{ + vfs_t *vfsp; + vfsops_t *vfsops; + vnode_t *rootvp; + struct inode *ip; + struct xfs_mount_args *args; + struct statfs statvfs; + int error; + + args = kmalloc(sizeof(struct xfs_mount_args), GFP_KERNEL); + if (!args) + return NULL; + memset(args, 0, sizeof(struct xfs_mount_args)); + args->slcount = args->stimeout = args->ctimeout = -1; + strncpy(args->fsname, bdevname(sb->s_dev), MAXNAMELEN); + if (xfs_parseargs((char *)data, sb->s_flags, args)) + goto out_null; + + /* Kludge in XFS until we have other VFS/VNODE FSs */ + vfsops = &xfs_vfsops; + + /* Set up the vfs_t structure */ + vfsp = vfs_allocate(); + if (!vfsp) + goto out_null; + + if (sb->s_flags & MS_RDONLY) + vfsp->vfs_flag |= VFS_RDONLY; + + vfsp->vfs_super = sb; + set_blocksize(sb->s_dev, BBSIZE); + set_max_bytes(sb); + set_quota_ops(sb); + sb->s_op = &linvfs_sops; + + LINVFS_SET_VFS(sb, vfsp); + + VFSOPS_MOUNT(vfsops, vfsp, args, NULL, error); + if (error) + goto fail_vfsop; + + VFS_STATVFS(vfsp, &statvfs, NULL, error); + if (error) + goto fail_unmount; + + sb->s_magic = XFS_SB_MAGIC; + sb->s_dirt = 1; + sb->s_blocksize = statvfs.f_bsize; + sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1; + + VFS_ROOT(vfsp, &rootvp, error); + if (error) + goto fail_unmount; + + ip = LINVFS_GET_IP(rootvp); + linvfs_revalidate_core(ip, ATTR_COMM); + + sb->s_root = d_alloc_root(ip); + if (!sb->s_root) + goto fail_vnrele; + if (is_bad_inode(sb->s_root->d_inode)) + goto fail_vnrele; + + /* Don't set the VFS_DMI flag until here because we don't want + * to send events while replaying the log. + */ + if (args->flags & XFSMNT_DMAPI) { + vfsp->vfs_flag |= VFS_DMI; + VFSOPS_DMAPI_MOUNT(vfsops, vfsp, args->mtpt, args->fsname, + error); + if (error) { + if (atomic_read(&sb->s_active) == 1) + vfsp->vfs_flag &= ~VFS_DMI; + goto fail_vnrele; + } + } + set_posix_acl(sb); + + vn_trace_exit(rootvp, "linvfs_read_super", (inst_t *)__return_address); + + kfree(args); + return(sb); + +fail_vnrele: + if (sb->s_root) { + dput(sb->s_root); + sb->s_root = NULL; + } else { + VN_RELE(rootvp); + } + +fail_unmount: + VFS_UNMOUNT(vfsp, 0, NULL, error); + +fail_vfsop: + vfs_deallocate(vfsp); + +out_null: + kfree(args); + return(NULL); +} + +void +linvfs_set_inode_ops( + struct inode *inode) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + + inode->i_mode = VTTOIF(vp->v_type); + + /* If this isn't a new inode, nothing to do */ + if (!(inode->i_state & I_NEW)) + return; + + if (vp->v_type == VNON) { + remove_inode_hash(inode); + make_bad_inode(inode); + } else if (S_ISREG(inode->i_mode)) { + inode->i_op = &linvfs_file_inode_operations; + inode->i_fop = &linvfs_file_operations; + inode->i_mapping->a_ops = &linvfs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &linvfs_dir_inode_operations; + inode->i_fop = &linvfs_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &linvfs_symlink_inode_operations; + if (inode->i_blocks) + inode->i_mapping->a_ops = &linvfs_aops; + } else { + inode->i_op = &linvfs_file_inode_operations; + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); + } + + unlock_new_inode(inode); +} + +/* + * We do not actually write the inode here, just mark the + * super block dirty so that sync_supers calls us and + * forces the flush. + */ +void +linvfs_write_inode( + struct inode *inode, + int sync) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + int error, flags = FLUSH_INODE; + + if (vp) { + vn_trace_entry(vp, "linvfs_write_inode", + (inst_t *)__return_address); + + if (sync) + flags |= FLUSH_SYNC; + VOP_IFLUSH(vp, flags, error); + if (error == EAGAIN) + inode->i_sb->s_dirt = 1; + } +} + +void +linvfs_clear_inode( + struct inode *inode) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + + if (vp) { + vn_rele(vp); + vn_trace_entry(vp, "linvfs_clear_inode", + (inst_t *)__return_address); + /* + * Do all our cleanup, and remove this vnode. + */ + vp->v_flag |= VPURGE; + vn_remove(vp); + } +} + +void +linvfs_put_inode( + struct inode *ip) +{ + vnode_t *vp = LINVFS_GET_VP(ip); + int error; + + if (vp && vp->v_fbhv && (atomic_read(&ip->i_count) == 1)) + VOP_RELEASE(vp, error); +} + +void +linvfs_put_super( + struct super_block *sb) +{ + int error; + int sector_size = BBSIZE; + kdev_t dev = sb->s_dev; + vfs_t *vfsp = LINVFS_GET_VFS(sb); + + VFS_DOUNMOUNT(vfsp, 0, NULL, NULL, error); + if (error) { + printk("XFS unmount got error %d\n", error); + printk("linvfs_put_super: vfsp/0x%p left dangling!\n", vfsp); + return; + } + + vfs_deallocate(vfsp); + + /* Reset device block size */ + if (hardsect_size[MAJOR(dev)]) + sector_size = hardsect_size[MAJOR(dev)][MINOR(dev)]; + set_blocksize(dev, sector_size); +} + +void +linvfs_write_super( + struct super_block *sb) +{ + vfs_t *vfsp = LINVFS_GET_VFS(sb); + int error; + + sb->s_dirt = 0; + if (sb->s_flags & MS_RDONLY) + return; + VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, + NULL, error); +} + +int +linvfs_statfs( + struct super_block *sb, + struct statfs *statp) +{ + vfs_t *vfsp = LINVFS_GET_VFS(sb); + int error; + + VFS_STATVFS(vfsp, statp, NULL, error); + + return error; +} + +int +linvfs_remount( + struct super_block *sb, + int *flags, + char *options) +{ + struct xfs_mount_args *args; + vfs_t *vfsp; + xfs_mount_t *mp; + int error = 0; + + vfsp = LINVFS_GET_VFS(sb); + mp = XFS_BHVTOM(vfsp->vfs_fbhv); + + args = kmalloc(sizeof(struct xfs_mount_args), GFP_KERNEL); + if (!args) + return -ENOMEM; + memset(args, 0, sizeof(struct xfs_mount_args)); + args->slcount = args->stimeout = args->ctimeout = -1; + if (xfs_parseargs(options, *flags, args)) { + error = -EINVAL; + goto out; + } + + if (args->flags & XFSMNT_NOATIME) + mp->m_flags |= XFS_MOUNT_NOATIME; + else + mp->m_flags &= ~XFS_MOUNT_NOATIME; + + set_posix_acl(sb); + linvfs_write_super(sb); + + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + goto out; + + if (*flags & MS_RDONLY) { + sb->s_flags |= MS_RDONLY; + XFS_log_write_unmount_ro(vfsp->vfs_fbhv); + vfsp->vfs_flag |= VFS_RDONLY; + } else { + vfsp->vfs_flag &= ~VFS_RDONLY; + } + +out: + kfree(args); + return error; +} + +void +linvfs_freeze_fs( + struct super_block *sb) +{ + vfs_t *vfsp; + vnode_t *vp; + int error; + + vfsp = LINVFS_GET_VFS(sb); + if (sb->s_flags & MS_RDONLY) + return; + VFS_ROOT(vfsp, &vp, error); + VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, XFS_IOC_FREEZE, 0, error); + VN_RELE(vp); +} + +void +linvfs_unfreeze_fs( + struct super_block *sb) +{ + vfs_t *vfsp; + vnode_t *vp; + int error; + + vfsp = LINVFS_GET_VFS(sb); + VFS_ROOT(vfsp, &vp, error); + VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, XFS_IOC_THAW, 0, error); + VN_RELE(vp); +} + + +STATIC int +linvfs_dentry_to_fh( + struct dentry *dentry, + __u32 *data, + int *lenp, + int need_parent) +{ + struct inode *inode = dentry->d_inode ; + vnode_t *vp = LINVFS_GET_VP(inode); + int maxlen = *lenp; + xfs_fid2_t fid; + int error; + + if (maxlen < 3) + return 255 ; + + VOP_FID2(vp, (struct fid *)&fid, error); + data[0] = (__u32)fid.fid_ino; /* 32 bits of inode is OK */ + data[1] = fid.fid_gen; + + *lenp = 2 ; + if (maxlen < 4 || ! need_parent) + return 2 ; + + read_lock(&dparent_lock); + inode = dentry->d_parent->d_inode ; + vp = LINVFS_GET_VP(inode); + + VOP_FID2(vp, (struct fid *)&fid, error); + data[2] = (__u32)fid.fid_ino; /* 32 bits of inode is OK */ + *lenp = 3 ; + if (maxlen < 4) + return 3 ; + data[3] = fid.fid_gen; + *lenp = 4 ; + read_unlock(&dparent_lock); + return 4 ; +} + +STATIC struct dentry * +linvfs_fh_to_dentry( + struct super_block *sb, + __u32 *data, + int len, + int fhtype, + int parent) +{ + vnode_t *vp; + struct inode *inode = NULL; + struct list_head *lp; + struct dentry *result; + xfs_fid2_t xfid; + vfs_t *vfsp = LINVFS_GET_VFS(sb); + int error; + + xfid.fid_len = sizeof(xfs_fid2_t) - sizeof(xfid.fid_len); + xfid.fid_pad = 0; + + if (!parent) { + xfid.fid_gen = data[1]; + xfid.fid_ino = (__u64)data[0]; + } else { + if (fhtype == 4) + xfid.fid_gen = data[3]; + else + xfid.fid_gen = 0; + xfid.fid_ino = (__u64)data[2]; + } + + VFS_VGET(vfsp, &vp, (fid_t *)&xfid, error); + if (error || vp == NULL) + return ERR_PTR(-ESTALE) ; + + inode = LINVFS_GET_IP(vp); + spin_lock(&dcache_lock); + for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { + result = list_entry(lp,struct dentry, d_alias); + if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { + dget_locked(result); + result->d_vfs_flags |= DCACHE_REFERENCED; + spin_unlock(&dcache_lock); + iput(inode); + return result; + } + } + spin_unlock(&dcache_lock); + result = d_alloc_root(inode); + if (result == NULL) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + result->d_flags |= DCACHE_NFSD_DISCONNECTED; + return result; +} + +STATIC int +linvfs_show_options( + struct seq_file *m, + struct vfsmount *mnt) +{ + vfs_t *vfsp = LINVFS_GET_VFS(mnt->mnt_sb); + + return xfs_showargs(vfsp, m); +} + + +STATIC struct super_operations linvfs_sops = { + .alloc_inode = linvfs_alloc_inode, + .destroy_inode = linvfs_destroy_inode, + .write_inode = linvfs_write_inode, + .put_inode = linvfs_put_inode, + .clear_inode = linvfs_clear_inode, + .put_super = linvfs_put_super, + .write_super = linvfs_write_super, + .write_super_lockfs = linvfs_freeze_fs, + .unlockfs = linvfs_unfreeze_fs, + .statfs = linvfs_statfs, + .remount_fs = linvfs_remount, + .fh_to_dentry = linvfs_fh_to_dentry, + .dentry_to_fh = linvfs_dentry_to_fh, + .show_options = linvfs_show_options, +}; + +STATIC struct file_system_type xfs_fs_type = { + .owner = THIS_MODULE, + .name = "xfs", + .read_super = linvfs_read_super, + .fs_flags = FS_REQUIRES_DEV, +}; + +STATIC int __init +init_xfs_fs( void ) +{ + int error; + struct sysinfo si; + static char message[] __initdata = + KERN_INFO "SGI XFS " XFS_VERSION_STRING " with " + XFS_BUILD_OPTIONS " enabled\n"; + + printk(message); + + error = init_inodecache(); + if (error < 0) + return error; + + error = pagebuf_init(); + if (error < 0) + goto out; + + si_meminfo(&si); + xfs_physmem = si.totalram; + + vn_init(); + xfs_init(); + dmapi_init(); + + error = register_filesystem(&xfs_fs_type); + if (error) + goto out; + return 0; + +out: + destroy_inodecache(); + return error; +} + +STATIC void __exit +exit_xfs_fs( void ) +{ + dmapi_uninit(); + xfs_cleanup(); + unregister_filesystem(&xfs_fs_type); + pagebuf_terminate(); + destroy_inodecache(); +} + +module_init(init_xfs_fs); +module_exit(exit_xfs_fs); + +MODULE_AUTHOR("SGI "); +MODULE_DESCRIPTION("SGI XFS " XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled"); +MODULE_LICENSE("GPL"); diff -Nur linux-2.4.19/fs/xfs/linux/xfs_super.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_super.h --- linux-2.4.19/fs/xfs/linux/xfs_super.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_super.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPER_H__ +#define __XFS_SUPER_H__ + +#ifdef CONFIG_FS_POSIX_ACL +# define XFS_ACL_STRING "ACLs, " +#else +# define XFS_ACL_STRING +#endif + +#ifdef CONFIG_XFS_DMAPI +# define XFS_DMAPI_STRING "DMAPI, " +#else +# define XFS_DMAPI_STRING +#endif + +#ifdef CONFIG_XFS_QUOTA +# define XFS_QUOTA_STRING "quota, " +#else +# define XFS_QUOTA_STRING +#endif + +#ifdef CONFIG_XFS_RT +# define XFS_RT_STRING "realtime, " +#else +# define XFS_RT_STRING +#endif + +#ifdef CONFIG_XFS_VNODE_TRACING +# define XFS_VNTRACE_STRING "VN-trace, " +#else +# define XFS_VNTRACE_STRING +#endif + +#ifdef XFSDEBUG +# define XFS_DBG_STRING "debug" +#else +# define XFS_DBG_STRING "no debug" +#endif + +#define XFS_BUILD_OPTIONS XFS_ACL_STRING XFS_DMAPI_STRING \ + XFS_RT_STRING \ + XFS_QUOTA_STRING XFS_VNTRACE_STRING \ + XFS_DBG_STRING /* DBG must be last */ + + +#define LINVFS_GET_VFS(s) \ + (vfs_t *)((s)->u.generic_sbp) +#define LINVFS_SET_VFS(s, vfsp) \ + ((s)->u.generic_sbp = vfsp) + + +struct xfs_mount_args; + +extern void +linvfs_set_inode_ops( + struct inode *inode); + +extern int +spectodevs( + struct super_block *sb, + struct xfs_mount_args *args, + dev_t *ddevp, + dev_t *logdevp, + dev_t *rtdevp); + +#endif /* __XFS_SUPER_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_sysctl.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_sysctl.c --- linux-2.4.19/fs/xfs/linux/xfs_sysctl.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_sysctl.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +/* + * Tunable XFS parameters + */ + +extern struct xfsstats xfsstats; + +STATIC ulong xfs_min[XFS_PARAM] = { \ + 0, 0, 0, 0, 0, 0 }; +STATIC ulong xfs_max[XFS_PARAM] = { \ + XFS_REFCACHE_SIZE_MAX, XFS_REFCACHE_SIZE_MAX, 1, 1, 1, 1 }; + +xfs_param_t xfs_params = { 128, 32, 0, 1, 0, 0 }; + +static struct ctl_table_header *xfs_table_header; + + +/* Custom proc handlers */ + +STATIC int +xfs_refcache_resize_proc_handler( + ctl_table *ctl, + int write, + struct file *filp, + void *buffer, + size_t *lenp) +{ + int ret, *valp = ctl->data; + int xfs_refcache_new_size; + int xfs_refcache_old_size = *valp; + + ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp); + xfs_refcache_new_size = *valp; + + if (!ret && write && xfs_refcache_new_size != xfs_refcache_old_size) { + xfs_refcache_resize(xfs_refcache_new_size); + /* Don't purge more than size of the cache */ + if (xfs_refcache_new_size < xfs_params.refcache_purge) + xfs_params.refcache_purge = xfs_refcache_new_size; + } + + return ret; +} + +STATIC int +xfs_stats_clear_proc_handler( + ctl_table *ctl, + int write, + struct file *filp, + void *buffer, + size_t *lenp) +{ + int ret, *valp = ctl->data; + __uint32_t vn_active; + + ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp); + + if (!ret && write && *valp) { + printk("XFS Clearing xfsstats\n"); + /* save vn_active, it's a universal truth! */ + vn_active = xfsstats.vn_active; + memset(&xfsstats, 0, sizeof(xfsstats)); + xfsstats.vn_active = vn_active; + xfs_params.stats_clear = 0; + } + + return ret; +} + +STATIC ctl_table xfs_table[] = { + {XFS_REFCACHE_SIZE, "refcache_size", &xfs_params.refcache_size, + sizeof(ulong), 0644, NULL, &xfs_refcache_resize_proc_handler, + &sysctl_intvec, NULL, &xfs_min[0], &xfs_max[0]}, + + {XFS_REFCACHE_PURGE, "refcache_purge", &xfs_params.refcache_purge, + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, &xfs_min[1], &xfs_params.refcache_size}, + + {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear, + sizeof(ulong), 0644, NULL, &xfs_stats_clear_proc_handler, + &sysctl_intvec, NULL, &xfs_min[2], &xfs_max[2]}, + + {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown, + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, &xfs_min[3], &xfs_max[3]}, + + {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit, + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, &xfs_min[4], &xfs_max[4]}, + + {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode, + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, &xfs_min[5], &xfs_max[5]}, + + {0} +}; + +STATIC ctl_table xfs_dir_table[] = { + {FS_XFS, "xfs", NULL, 0, 0555, xfs_table}, + {0} +}; + +STATIC ctl_table xfs_root_table[] = { + {CTL_FS, "fs", NULL, 0, 0555, xfs_dir_table}, + {0} +}; + +void +xfs_sysctl_register(void) +{ + xfs_table_header = register_sysctl_table(xfs_root_table, 1); +} + +void +xfs_sysctl_unregister(void) +{ + if (xfs_table_header) + unregister_sysctl_table(xfs_table_header); +} diff -Nur linux-2.4.19/fs/xfs/linux/xfs_sysctl.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_sysctl.h --- linux-2.4.19/fs/xfs/linux/xfs_sysctl.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_sysctl.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_SYSCTL_H__ +#define __XFS_SYSCTL_H__ + +#include + +/* + * Tunable xfs parameters + */ + +#define XFS_PARAM (sizeof(struct xfs_param) / sizeof(ulong)) + +typedef struct xfs_param { + ulong refcache_size; /* Size of NFS reference cache. */ + ulong refcache_purge; /* # of entries to purge each time. */ + ulong stats_clear; /* Reset all XFS statistics to zero. */ + ulong restrict_chown; /* Root/non-root can give away files. */ + ulong sgid_inherit; /* Inherit ISGID bit if process' GID is */ + /* not a member of the parent dir GID. */ + ulong symlink_mode; /* Symlink creat mode affected by umask. */ +} xfs_param_t; + +enum { + XFS_REFCACHE_SIZE = 1, + XFS_REFCACHE_PURGE = 2, + XFS_STATS_CLEAR = 3, + XFS_RESTRICT_CHOWN = 4, + XFS_SGID_INHERIT = 5, + XFS_SYMLINK_MODE = 6, +}; + +extern xfs_param_t xfs_params; + +#ifdef CONFIG_SYSCTL +extern void xfs_sysctl_register(void); +extern void xfs_sysctl_unregister(void); +#else +static __inline void xfs_sysctl_register(void) { }; +static __inline void xfs_sysctl_unregister(void) { }; +#endif + +#endif /* __XFS_SYSCTL_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_version.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_version.h --- linux-2.4.19/fs/xfs/linux/xfs_version.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_version.h Fri Dec 13 10:22:56 2002 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Dummy file that can contain a timestamp to put into the + * XFS init string, to help users keep track of what they're + * running + */ + +#ifndef __XFS_VERSION_H__ +#define __XFS_VERSION_H__ + +#define XFS_VERSION_STRING "1.2pre4" + +#endif /* __XFS_VERSION_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_vfs.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_vfs.h --- linux-2.4.19/fs/xfs/linux/xfs_vfs.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_vfs.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_VFS_H__ +#define __XFS_VFS_H__ + +#include + +struct statfs; +struct vnode; +struct cred; +struct super_block; +struct fid; +struct dm_fcntl_vector; +struct xfs_mount_args; + +typedef struct vfs { + u_int vfs_flag; /* flags */ + fsid_t vfs_fsid; /* file system id */ + fsid_t *vfs_altfsid; /* An ID fixed for life of FS */ + bhv_head_t vfs_bh; /* head of vfs behavior chain */ + struct super_block *vfs_super; /* pointer to super block structure */ +} vfs_t; + +#define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */ +#define VFS_FOPS(vfsp) \ + ((vfsops_t *)((vfsp)->vfs_fbhv->bd_ops))/* ops for 1st behavior */ + + +#define bhvtovfs(bdp) ((struct vfs *)BHV_VOBJ(bdp)) +#define VFS_BHVHEAD(vfsp) (&(vfsp)->vfs_bh) + + +#define VFS_RDONLY 0x0001 /* read-only vfs */ +#define VFS_GRPID 0x0002 /* group-ID assigned from directory */ +#define VFS_DMI 0x0004 /* filesystem has the DMI enabled */ + +#define SYNC_ATTR 0x0001 /* sync attributes */ +#define SYNC_CLOSE 0x0002 /* close file system down */ +#define SYNC_DELWRI 0x0004 /* look at delayed writes */ +#define SYNC_WAIT 0x0008 /* wait for i/o to complete */ +#define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ +#define SYNC_BDFLUSH 0x0010 /* BDFLUSH is calling -- don't block */ + + +typedef struct vfsops { + int (*vfs_mount)(struct vfs *, struct xfs_mount_args *, + struct cred *); + /* mount file system */ + int (*vfs_dounmount)(bhv_desc_t *, int, struct vnode *, + struct cred *); + /* preparation and unmount */ + int (*vfs_unmount)(bhv_desc_t *, int, struct cred *); + /* unmount file system */ + int (*vfs_root)(bhv_desc_t *, struct vnode **); + /* get root vnode */ + int (*vfs_statvfs)(bhv_desc_t *, struct statfs *, struct vnode *); + /* get file system statistics */ + int (*vfs_sync)(bhv_desc_t *, int, struct cred *); + /* flush files */ + int (*vfs_vget)(bhv_desc_t *, struct vnode **, struct fid *); + /* get vnode from fid */ + int (*vfs_dmapi_mount)(struct vfs *, char *, char *); + /* send dmapi mount event */ + int (*vfs_dmapi_fsys_vector)(bhv_desc_t *, + struct dm_fcntl_vector *); + void (*vfs_force_shutdown)(bhv_desc_t *, + int, char *, int); +} vfsops_t; + +#define VFS_DOUNMOUNT(vfsp,f,vp,cr, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_dounmount))((vfsp)->vfs_fbhv, f, vp, cr); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_UNMOUNT(vfsp,f,cr, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_unmount))((vfsp)->vfs_fbhv, f, cr); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_ROOT(vfsp, vpp, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_root))((vfsp)->vfs_fbhv, vpp); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_STATVFS(vfsp, sp, vp, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_statvfs))((vfsp)->vfs_fbhv, sp, vp); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_SYNC(vfsp, flag, cr, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_sync))((vfsp)->vfs_fbhv, flag, cr); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_VGET(vfsp, vpp, fidp, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_vget))((vfsp)->vfs_fbhv, vpp, fidp); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +/* No behavior lock here */ +#define VFS_FORCE_SHUTDOWN(vfsp, flags) \ + (*(VFS_FOPS(vfsp)->vfs_force_shutdown))((vfsp)->vfs_fbhv, flags, __FILE__, __LINE__); + +#define VFS_DMAPI_FSYS_VECTOR(vfsp, df, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_dmapi_fsys_vector))((vfsp)->vfs_fbhv, df); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} + + +#define VFSOPS_DMAPI_MOUNT(vfs_op, vfsp, dir_name, fsname, rv) \ + rv = (*(vfs_op)->vfs_dmapi_mount)(vfsp, dir_name, fsname) +#define VFSOPS_MOUNT(vfs_op, vfsp, args, cr, rv) \ + rv = (*(vfs_op)->vfs_mount)(vfsp, args, cr) + +#define VFS_REMOVEBHV(vfsp, bdp)\ +{ \ + bhv_remove(VFS_BHVHEAD(vfsp), bdp); \ +} + +#define PVFS_UNMOUNT(bdp,f,cr, rv) \ +{ \ + rv = (*((vfsops_t *)(bdp)->bd_ops)->vfs_unmount)(bdp, f, cr); \ +} + +#define PVFS_SYNC(bdp, flag, cr, rv) \ +{ \ + rv = (*((vfsops_t *)(bdp)->bd_ops)->vfs_sync)(bdp, flag, cr); \ +} + + +static __inline vfs_t * +vfs_allocate(void) +{ + vfs_t *vfsp; + + vfsp = kmalloc(sizeof(vfs_t), GFP_KERNEL); + if (vfsp) { + memset(vfsp, 0, sizeof(vfs_t)); + bhv_head_init(VFS_BHVHEAD(vfsp), "vfs"); + } + return (vfsp); +} + +static __inline void +vfs_deallocate( + vfs_t *vfsp) +{ + bhv_head_destroy(VFS_BHVHEAD(vfsp)); + kfree(vfsp); +} + +/* + * Called by fs dependent VFS_MOUNT code to link the VFS base file system + * dependent behavior with the VFS virtual object. + */ +static __inline void +vfs_insertbhv( + vfs_t *vfsp, + bhv_desc_t *bdp, + vfsops_t *vfsops, + void *mount) +{ + /* + * Initialize behavior desc with ops and data and then + * attach it to the vfs. + */ + bhv_desc_init(bdp, mount, vfsp, vfsops); + bhv_insert_initial(&vfsp->vfs_bh, bdp); +} + +#endif /* __XFS_VFS_H__ */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_vnode.c linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_vnode.c --- linux-2.4.19/fs/xfs/linux/xfs_vnode.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_vnode.c Fri Dec 13 10:22:56 2002 @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +uint64_t vn_generation; /* vnode generation number */ + +spinlock_t vnumber_lock = SPIN_LOCK_UNLOCKED; + +/* + * Dedicated vnode inactive/reclaim sync semaphores. + * Prime number of hash buckets since address is used as the key. + */ +#define NVSYNC 37 +#define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC]) +sv_t vsync[NVSYNC]; + +/* + * Translate stat(2) file types to vnode types and vice versa. + * Aware of numeric order of S_IFMT and vnode type values. + */ +enum vtype iftovt_tab[] = { + VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, + VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON +}; + +u_short vttoif_tab[] = { + 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 0, S_IFSOCK +}; + +#define VN_LOCK(vp) spin_lock(&(vp)->v_lock) +#define VN_UNLOCK(vp) spin_unlock(&(vp)->v_lock) + + +void +vn_init(void) +{ + register sv_t *svp; + register int i; + + for (svp = vsync, i = 0; i < NVSYNC; i++, svp++) + init_sv(svp, SV_DEFAULT, "vsy", i); +} + + +/* + * Clean a vnode of filesystem-specific data and prepare it for reuse. + */ +STATIC int +vn_reclaim(struct vnode *vp) +{ + int error; + + XFS_STATS_INC(xfsstats.vn_reclaim); + + vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address); + + /* + * Only make the VOP_RECLAIM call if there are behaviors + * to call. + */ + if (vp->v_fbhv != NULL) { + VOP_RECLAIM(vp, error); + if (error) + return -error; + } + ASSERT(vp->v_fbhv == NULL); + + VN_LOCK(vp); + + vp->v_flag &= (VRECLM|VWAIT); + VN_UNLOCK(vp); + + vp->v_type = VNON; + vp->v_fbhv = NULL; + +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_free(vp->v_trace); + vp->v_trace = NULL; +#endif + + return 0; +} + +STATIC void +vn_wakeup(struct vnode *vp) +{ + VN_LOCK(vp); + if (vp->v_flag & VWAIT) { + sv_broadcast(vptosync(vp)); + } + vp->v_flag &= ~(VRECLM|VWAIT|VMODIFIED); + VN_UNLOCK(vp); +} + +int +vn_wait(struct vnode *vp) +{ + VN_LOCK(vp); + if (vp->v_flag & (VINACT | VRECLM)) { + vp->v_flag |= VWAIT; + sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0); + return 1; + } + VN_UNLOCK(vp); + return 0; +} + +struct vnode * +vn_initialize(struct inode *inode) +{ + struct vnode *vp = LINVFS_GET_VP(inode); + + XFS_STATS_INC(xfsstats.vn_active); + + vp->v_flag = VMODIFIED; + spinlock_init(&vp->v_lock, "v_lock"); + + spin_lock(&vnumber_lock); + if (!++vn_generation) /* v_number shouldn't be zero */ + vn_generation++; + vp->v_number = vn_generation; + spin_unlock(&vnumber_lock); + + ASSERT(VN_CACHED(vp) == 0); + + /* Initialize the first behavior and the behavior chain head. */ + vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode"); + +#ifdef CONFIG_XFS_VNODE_TRACING + vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); +#endif /* CONFIG_XFS_VNODE_TRACING */ + + vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address); + return vp; +} + +/* + * Get a reference on a vnode. + */ +vnode_t * +vn_get(struct vnode *vp, vmap_t *vmap) +{ + struct inode *inode; + + XFS_STATS_INC(xfsstats.vn_get); + inode = LINVFS_GET_IP(vp); + if (inode->i_state & I_FREEING) + return NULL; + + inode = iget_locked(vmap->v_vfsp->vfs_super, vmap->v_ino); + if (inode == NULL) /* Inode not present */ + return NULL; + + /* We do not want to create new inodes via vn_get, + * returning NULL here is OK. + */ + if (inode->i_state & I_NEW) { + remove_inode_hash(inode); + make_bad_inode(inode); + unlock_new_inode(inode); + iput(inode); + return NULL; + } + + vn_trace_exit(vp, "vn_get", (inst_t *)__return_address); + ASSERT((vp->v_flag & VPURGE) == 0); + + return vp; +} + +/* + * "revalidate" the linux inode. + */ +int +vn_revalidate(struct vnode *vp, int flags) +{ + int error; + struct inode *inode; + vattr_t va; + + vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address); + + va.va_mask = AT_STAT|AT_GENCOUNT; + + ASSERT(vp->v_bh.bh_first != NULL); + + VOP_GETATTR(vp, &va, flags & ATTR_LAZY, NULL, error); + + if (! error) { + inode = LINVFS_GET_IP(vp); + ASSERT(inode); + + inode->i_mode = VTTOIF(va.va_type) | va.va_mode; + inode->i_nlink = va.va_nlink; + inode->i_uid = va.va_uid; + inode->i_gid = va.va_gid; + inode->i_rdev = mk_kdev(MAJOR(va.va_rdev), + MINOR(va.va_rdev)); + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_generation = va.va_gencount; + if ((flags & ATTR_COMM) || + S_ISREG(inode->i_mode) || + S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode)) { + inode->i_size = va.va_size; + inode->i_blocks = va.va_nblocks; + inode->i_atime = va.va_atime.tv_sec; + inode->i_mtime = va.va_mtime.tv_sec; + inode->i_ctime = va.va_ctime.tv_sec; + } + if (flags & ATTR_LAZY) + vp->v_flag &= ~VMODIFIED; + else + VUNMODIFY(vp); + } else { + vn_trace_exit(vp, "vn_revalidate.error", + (inst_t *)__return_address); + } + + return -error; +} + + +/* + * purge a vnode from the cache + * At this point the vnode is guaranteed to have no references (vn_count == 0) + * The caller has to make sure that there are no ways someone could + * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock). + */ +void +vn_purge(struct vnode *vp, vmap_t *vmap) +{ + vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address); + + ASSERT(vp->v_flag & VPURGE); + +again: + /* + * Check whether vp has already been reclaimed since our caller + * sampled its version while holding a filesystem cache lock that + * its VOP_RECLAIM function acquires. + */ + VN_LOCK(vp); + if (vp->v_number != vmap->v_number) { + VN_UNLOCK(vp); + return; + } + + /* + * If vp is being reclaimed or inactivated, wait until it is inert, + * then proceed. Can't assume that vnode is actually reclaimed + * just because the reclaimed flag is asserted -- a vn_alloc + * reclaim can fail. + */ + if (vp->v_flag & (VINACT | VRECLM)) { + ASSERT(vn_count(vp) == 0); + vp->v_flag |= VWAIT; + sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0); + goto again; + } + + /* + * Another process could have raced in and gotten this vnode... + */ + if (vn_count(vp) > 0) { + VN_UNLOCK(vp); + return; + } + + XFS_STATS_DEC(xfsstats.vn_active); + vp->v_flag |= VRECLM; + VN_UNLOCK(vp); + + /* + * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells + * vp's filesystem to flush and invalidate all cached resources. + * When vn_reclaim returns, vp should have no private data, + * either in a system cache or attached to v_data. + */ + if (vn_reclaim(vp) != 0) + panic("vn_purge: cannot reclaim"); + + /* + * Wakeup anyone waiting for vp to be reclaimed. + */ + vn_wakeup(vp); +} + +/* + * Add a reference to a referenced vnode. + */ +struct vnode * +vn_hold(struct vnode *vp) +{ + struct inode *inode; + + XFS_STATS_INC(xfsstats.vn_hold); + + VN_LOCK(vp); + inode = igrab(LINVFS_GET_IP(vp)); + ASSERT(inode); + VN_UNLOCK(vp); + + return vp; +} + +/* + * Call VOP_INACTIVE on last reference. + */ +void +vn_rele(struct vnode *vp) +{ + int vcnt; + /* REFERENCED */ + int cache; + + XFS_STATS_INC(xfsstats.vn_rele); + + + VN_LOCK(vp); + + vn_trace_entry(vp, "vn_rele", (inst_t *)__return_address); + vcnt = vn_count(vp); + + /* + * Since we always get called from put_inode we know + * that i_count won't be decremented after we + * return. + */ + if (vcnt == 0) { + /* + * As soon as we turn this on, noone can find us in vn_get + * until we turn off VINACT or VRECLM + */ + vp->v_flag |= VINACT; + VN_UNLOCK(vp); + + /* + * Do not make the VOP_INACTIVE call if there + * are no behaviors attached to the vnode to call. + */ + if (vp->v_fbhv != NULL) { + VOP_INACTIVE(vp, NULL, cache); + } + + VN_LOCK(vp); + if (vp->v_flag & VWAIT) { + if (vp->v_flag & VWAIT) { + sv_broadcast(vptosync(vp)); + } + } + + vp->v_flag &= ~(VINACT|VWAIT|VRECLM|VMODIFIED); + + } + + VN_UNLOCK(vp); + + vn_trace_exit(vp, "vn_rele", (inst_t *)__return_address); +} + + +/* + * Finish the removal of a vnode. + */ +void +vn_remove(struct vnode *vp) +{ + /* REFERENCED */ + vmap_t vmap; + + /* Make sure we don't do this to the same vnode twice */ + if (!(vp->v_fbhv)) + return; + + XFS_STATS_INC(xfsstats.vn_remove); + + vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address); + + /* + * After the following purge the vnode + * will no longer exist. + */ + VMAP(vp, XFS_BHVTOI(vp->v_fbhv), vmap); + + vn_purge(vp, &vmap); +} + + +#ifdef CONFIG_XFS_VNODE_TRACING + +#define KTRACE_ENTER(vp, vk, s, line, ra) \ + ktrace_enter( (vp)->v_trace, \ +/* 0 */ (void *)(__psint_t)(vk), \ +/* 1 */ (void *)(s), \ +/* 2 */ (void *)(__psint_t) line, \ +/* 3 */ (void *)(vn_count(vp)), \ +/* 4 */ (void *)(ra), \ +/* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ +/* 6 */ (void *)(__psint_t)smp_processor_id(), \ +/* 7 */ (void *)(__psint_t)(current->pid), \ +/* 8 */ (void *)__return_address, \ +/* 9 */ 0, 0, 0, 0, 0, 0, 0) + +/* + * Vnode tracing code. + */ +void +vn_trace_entry(vnode_t *vp, char *func, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); +} + +void +vn_trace_exit(vnode_t *vp, char *func, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); +} + +void +vn_trace_hold(vnode_t *vp, char *file, int line, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra); +} + +void +vn_trace_ref(vnode_t *vp, char *file, int line, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra); +} + +void +vn_trace_rele(vnode_t *vp, char *file, int line, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra); +} +#endif /* CONFIG_XFS_VNODE_TRACING */ diff -Nur linux-2.4.19/fs/xfs/linux/xfs_vnode.h linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_vnode.h --- linux-2.4.19/fs/xfs/linux/xfs_vnode.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/linux/xfs_vnode.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_VNODE_H__ +#define __XFS_VNODE_H__ + +/* + * Vnode types (unrelated to on-disk inodes). VNON means no type. + */ +typedef enum vtype { + VNON = 0, + VREG = 1, + VDIR = 2, + VBLK = 3, + VCHR = 4, + VLNK = 5, + VFIFO = 6, + VBAD = 7, + VSOCK = 8 +} vtype_t; + +typedef __u64 vnumber_t; + +/* + * Define the type of behavior head used by vnodes. + */ +#define vn_bhv_head_t bhv_head_t + +/* + * MP locking protocols: + * v_flag, v_vfsp VN_LOCK/VN_UNLOCK + * v_type read-only or fs-dependent + */ +typedef struct vnode { + __u32 v_flag; /* vnode flags (see below) */ + enum vtype v_type; /* vnode type */ + struct vfs *v_vfsp; /* ptr to containing VFS*/ + vnumber_t v_number; /* in-core vnode number */ + vn_bhv_head_t v_bh; /* behavior head */ + + spinlock_t v_lock; /* don't use VLOCK on Linux */ + struct inode v_inode; /* linux inode */ +#ifdef CONFIG_XFS_VNODE_TRACING + struct ktrace *v_trace; /* trace header structure */ +#endif +} vnode_t; + +/* + * Vnode to Linux inode mapping. + */ +#define LINVFS_GET_VP(inode) ((vnode_t *)list_entry(inode, vnode_t, v_inode)) +#define LINVFS_GET_IP(vp) (&(vp)->v_inode) + +/* + * Conversion between vnode types/modes and encoded type/mode as + * seen by stat(2) and mknod(2). + */ +extern enum vtype iftovt_tab[]; +extern ushort vttoif_tab[]; +#define IFTOVT(M) (iftovt_tab[((M) & S_IFMT) >> 12]) +#define VTTOIF(T) (vttoif_tab[(int)(T)]) +#define MAKEIMODE(T, M) (VTTOIF(T) | ((M) & ~S_IFMT)) + +/* + * Vnode flags. + * + * The vnode flags fall into two categories: + * 1) Local only - + * Flags that are relevant only to a particular cell + * 2) Single system image - + * Flags that must be maintained coherent across all cells + */ + /* Local only flags */ +#define VINACT 0x1 /* vnode is being inactivated */ +#define VRECLM 0x2 /* vnode is being reclaimed */ +#define VWAIT 0x4 /* waiting for VINACT + or VRECLM to finish */ +#define VMODIFIED 0x8 /* xfs inode state possibly different + * from linux inode state. + */ + +/* Single system image flags */ +#define VROOT 0x100000 /* root of its file system */ +#define VNOSWAP 0x200000 /* cannot be used as virt swap device */ +#define VISSWAP 0x400000 /* vnode is part of virt swap device */ +#define VREPLICABLE 0x800000 /* Vnode can have replicated pages */ +#define VNONREPLICABLE 0x1000000 /* Vnode has writers. Don't replicate */ +#define VDOCMP 0x2000000 /* Vnode has special VOP_CMP impl. */ +#define VSHARE 0x4000000 /* vnode part of global cache */ + /* VSHARE applies to local cell only */ +#define VFRLOCKS 0x8000000 /* vnode has FR locks applied */ +#define VENF_LOCKING 0x10000000 /* enf. mode FR locking in effect */ +#define VOPLOCK 0x20000000 /* oplock set on the vnode */ +#define VPURGE 0x40000000 /* In the linux 'put' thread */ + +typedef enum vrwlock { VRWLOCK_NONE, VRWLOCK_READ, + VRWLOCK_WRITE, VRWLOCK_WRITE_DIRECT, + VRWLOCK_TRY_READ, VRWLOCK_TRY_WRITE } vrwlock_t; + +/* + * Return values for VOP_INACTIVE. A return value of + * VN_INACTIVE_NOCACHE implies that the file system behavior + * has disassociated its state and bhv_desc_t from the vnode. + */ +#define VN_INACTIVE_CACHE 0 +#define VN_INACTIVE_NOCACHE 1 + +/* + * Values for the cmd code given to VOP_VNODE_CHANGE. + */ +typedef enum vchange { + VCHANGE_FLAGS_FRLOCKS = 0, + VCHANGE_FLAGS_ENF_LOCKING = 1, + VCHANGE_FLAGS_TRUNCATED = 2, + VCHANGE_FLAGS_PAGE_DIRTY = 3, + VCHANGE_FLAGS_IOEXCL_COUNT = 4 +} vchange_t; + +/* + * Macros for dealing with the behavior descriptor inside of the vnode. + */ +#define BHV_TO_VNODE(bdp) ((vnode_t *)BHV_VOBJ(bdp)) +#define BHV_TO_VNODE_NULL(bdp) ((vnode_t *)BHV_VOBJNULL(bdp)) + +#define VNODE_TO_FIRST_BHV(vp) (BHV_HEAD_FIRST(&(vp)->v_bh)) +#define VN_BHV_HEAD(vp) ((vn_bhv_head_t *)(&((vp)->v_bh))) +#define VN_BHV_READ_LOCK(bhp) BHV_READ_LOCK(bhp) +#define VN_BHV_READ_UNLOCK(bhp) BHV_READ_UNLOCK(bhp) +#define VN_BHV_WRITE_LOCK(bhp) BHV_WRITE_LOCK(bhp) +#define VN_BHV_NOT_READ_LOCKED(bhp) BHV_NOT_READ_LOCKED(bhp) +#define VN_BHV_NOT_WRITE_LOCKED(bhp) BHV_NOT_WRITE_LOCKED(bhp) +#define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name) +#define vn_bhv_head_reinit(bhp) bhv_head_reinit(bhp) +#define vn_bhv_insert_initial(bhp,bdp) bhv_insert_initial(bhp,bdp) +#define vn_bhv_remove(bhp,bdp) bhv_remove(bhp,bdp) +#define vn_bhv_lookup(bhp,ops) bhv_lookup(bhp,ops) +#define vn_bhv_lookup_unlocked(bhp,ops) bhv_lookup_unlocked(bhp,ops) + +#define v_fbhv v_bh.bh_first /* first behavior */ +#define v_fops v_bh.bh_first->bd_ops /* ops for first behavior */ + + +struct uio; +struct file; +struct vattr; +struct page_buf_bmap_s; +struct attrlist_cursor_kern; + +typedef int (*vop_open_t)(bhv_desc_t *, struct cred *); +typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct file *, char *, size_t, + loff_t *, struct cred *); +typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct file *, const char *, size_t, + loff_t *, struct cred *); +typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, unsigned int, unsigned long); +typedef int (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int, + struct cred *); +typedef int (*vop_setattr_t)(bhv_desc_t *, struct vattr *, int, + struct cred *); +typedef int (*vop_access_t)(bhv_desc_t *, int, struct cred *); +typedef int (*vop_lookup_t)(bhv_desc_t *, struct dentry *, vnode_t **, + int, vnode_t *, struct cred *); +typedef int (*vop_create_t)(bhv_desc_t *, struct dentry *, struct vattr *, + vnode_t **, struct cred *); +typedef int (*vop_remove_t)(bhv_desc_t *, struct dentry *, struct cred *); +typedef int (*vop_link_t)(bhv_desc_t *, vnode_t *, struct dentry *, + struct cred *); +typedef int (*vop_rename_t)(bhv_desc_t *, struct dentry *, vnode_t *, + struct dentry *, struct cred *); +typedef int (*vop_mkdir_t)(bhv_desc_t *, struct dentry *, struct vattr *, + vnode_t **, struct cred *); +typedef int (*vop_rmdir_t)(bhv_desc_t *, struct dentry *, struct cred *); +typedef int (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *, + int *); +typedef int (*vop_symlink_t)(bhv_desc_t *, struct dentry *, + struct vattr *, char *, + vnode_t **, struct cred *); +typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, struct cred *); +typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, xfs_off_t, xfs_off_t); +typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *); +typedef int (*vop_fid2_t)(bhv_desc_t *, struct fid *); +typedef int (*vop_release_t)(bhv_desc_t *); +typedef int (*vop_rwlock_t)(bhv_desc_t *, vrwlock_t); +typedef void (*vop_rwunlock_t)(bhv_desc_t *, vrwlock_t); +typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *); +typedef int (*vop_strategy_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *); +typedef int (*vop_reclaim_t)(bhv_desc_t *); +typedef int (*vop_attr_get_t)(bhv_desc_t *, char *, char *, int *, int, + struct cred *); +typedef int (*vop_attr_set_t)(bhv_desc_t *, char *, char *, int, int, + struct cred *); +typedef int (*vop_attr_remove_t)(bhv_desc_t *, char *, int, struct cred *); +typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int, + struct attrlist_cursor_kern *, struct cred *); +typedef void (*vop_link_removed_t)(bhv_desc_t *, vnode_t *, int); +typedef void (*vop_vnode_change_t)(bhv_desc_t *, vchange_t, __psint_t); +typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +typedef void (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); +typedef int (*vop_iflush_t)(bhv_desc_t *, int); + + +typedef struct vnodeops { + bhv_position_t vn_position; /* position within behavior chain */ + vop_open_t vop_open; + vop_read_t vop_read; + vop_write_t vop_write; + vop_ioctl_t vop_ioctl; + vop_getattr_t vop_getattr; + vop_setattr_t vop_setattr; + vop_access_t vop_access; + vop_lookup_t vop_lookup; + vop_create_t vop_create; + vop_remove_t vop_remove; + vop_link_t vop_link; + vop_rename_t vop_rename; + vop_mkdir_t vop_mkdir; + vop_rmdir_t vop_rmdir; + vop_readdir_t vop_readdir; + vop_symlink_t vop_symlink; + vop_readlink_t vop_readlink; + vop_fsync_t vop_fsync; + vop_inactive_t vop_inactive; + vop_fid2_t vop_fid2; + vop_rwlock_t vop_rwlock; + vop_rwunlock_t vop_rwunlock; + vop_bmap_t vop_bmap; + vop_strategy_t vop_strategy; + vop_reclaim_t vop_reclaim; + vop_attr_get_t vop_attr_get; + vop_attr_set_t vop_attr_set; + vop_attr_remove_t vop_attr_remove; + vop_attr_list_t vop_attr_list; + vop_link_removed_t vop_link_removed; + vop_vnode_change_t vop_vnode_change; + vop_ptossvp_t vop_tosspages; + vop_pflushinvalvp_t vop_flushinval_pages; + vop_pflushvp_t vop_flush_pages; + vop_release_t vop_release; + vop_iflush_t vop_iflush; +} vnodeops_t; + +/* + * VOP's. + */ +#define _VOP_(op, vp) (*((vnodeops_t *)(vp)->v_fops)->op) + +#define VOP_READ(vp,file,buf,size,offset,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,buf,size,offset,cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_WRITE(vp,file,buf,size,offset,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,buf,size,offset,cr);\ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_BMAP(vp,of,sz,rw,cr,b,n,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_STRATEGY(vp,of,sz,rw,cr,b,n,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_strategy, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_OPEN(vp, cr, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_GETATTR(vp, vap, f, cr, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_SETATTR(vp, vap, f, cr, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ACCESS(vp, mode, cr, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_LOOKUP(vp,d,vpp,f,rdir,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_CREATE(dvp,d,vap,vpp,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dvp)->v_bh); \ + rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr); \ + VN_BHV_READ_UNLOCK(&(dvp)->v_bh); \ +} +#define VOP_REMOVE(dvp,d,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dvp)->v_bh); \ + rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr); \ + VN_BHV_READ_UNLOCK(&(dvp)->v_bh); \ +} +#define VOP_LINK(tdvp,fvp,d,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(tdvp)->v_bh); \ + rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr); \ + VN_BHV_READ_UNLOCK(&(tdvp)->v_bh); \ +} +#define VOP_RENAME(fvp,fnm,tdvp,tnm,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(fvp)->v_bh); \ + rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr); \ + VN_BHV_READ_UNLOCK(&(fvp)->v_bh); \ +} +#define VOP_MKDIR(dp,d,vap,vpp,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dp)->v_bh); \ + rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr); \ + VN_BHV_READ_UNLOCK(&(dp)->v_bh); \ +} +#define VOP_RMDIR(dp,d,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dp)->v_bh); \ + rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr); \ + VN_BHV_READ_UNLOCK(&(dp)->v_bh); \ +} +#define VOP_READDIR(vp,uiop,cr,eofp,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dvp)->v_bh); \ + rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr); \ + VN_BHV_READ_UNLOCK(&(dvp)->v_bh); \ +} +#define VOP_READLINK(vp,uiop,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_FSYNC(vp,f,cr,b,e,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_INACTIVE(vp, cr, rv) \ +{ /* vnode not reference-able, so no need to lock chain */ \ + rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr); \ +} +#define VOP_RELEASE(vp, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_release, vp)((vp)->v_fbhv); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_FID2(vp, fidp, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_RWLOCK(vp,i) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + (void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i); \ + /* "allow" is done by rwunlock */ \ +} +#define VOP_RWLOCK_TRY(vp,i) \ + _VOP_(vop_rwlock, vp)((vp)->v_fbhv, i) + +#define VOP_RWUNLOCK(vp,i) \ +{ /* "prevent" was done by rwlock */ \ + (void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_RECLAIM(vp, rv) \ +{ /* vnode not reference-able, so no need to lock chain */ \ + rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv); \ +} +#define VOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ATTR_REMOVE(vp, name, flags, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred);\ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_LINK_REMOVED(vp, dvp, linkzero) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + (void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_VNODE_CHANGE(vp, cmd, val) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + (void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +/* + * These are page cache functions that now go thru VOPs. + * 'last' parameter is unused and left in for IRIX compatibility + */ +#define VOP_TOSS_PAGES(vp, first, last, fiopt) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + _VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +/* + * 'last' parameter is unused and left in for IRIX compatibility + */ +#define VOP_FLUSHINVAL_PAGES(vp, first, last, fiopt) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + _VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +/* + * 'last' parameter is unused and left in for IRIX compatibility + */ +#define VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt);\ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_IOCTL(vp, inode, filp, cmd, arg, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,cmd,arg); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_IFLUSH(vp, flags, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} + +/* + * Flags for VOP_IFLUSH call + */ + +#define FLUSH_SYNC 1 /* wait for flush to complete */ +#define FLUSH_INODE 2 /* flush the inode itself */ +#define FLUSH_LOG 4 /* force the last log entry for + * this inode out to disk */ + +/* + * Flush/Invalidate options for VOP_TOSS_PAGES, VOP_FLUSHINVAL_PAGES and + * VOP_FLUSH_PAGES. + */ +#define FI_NONE 0 /* none */ +#define FI_REMAPF 1 /* Do a remapf prior to the operation */ +#define FI_REMAPF_LOCKED 2 /* Do a remapf prior to the operation. + Prevent VM access to the pages until + the operation completes. */ + +/* + * Vnode attributes. va_mask indicates those attributes the caller + * wants to set (setattr) or extract (getattr). + */ +typedef struct vattr { + int va_mask; /* bit-mask of attributes */ + vtype_t va_type; /* vnode type (for create) */ + mode_t va_mode; /* file access mode */ + uid_t va_uid; /* owner user id */ + gid_t va_gid; /* owner group id */ + dev_t va_fsid; /* file system id (dev for now) */ + xfs_ino_t va_nodeid; /* node id */ + nlink_t va_nlink; /* number of references to file */ + xfs_off_t va_size; /* file size in bytes */ + timespec_t va_atime; /* time of last access */ + timespec_t va_mtime; /* time of last modification */ + timespec_t va_ctime; /* time file ``created'' */ + dev_t va_rdev; /* device the file represents */ + u_long va_blksize; /* fundamental block size */ + __int64_t va_nblocks; /* # of blocks allocated */ + u_long va_vcode; /* version code */ + u_long va_xflags; /* random extended file flags */ + u_long va_extsize; /* file extent size */ + u_long va_nextents; /* number of extents in file */ + u_long va_anextents; /* number of attr extents in file */ + int va_projid; /* project id */ + u_int va_gencount; /* object generation count */ +} vattr_t; + +/* + * setattr or getattr attributes + */ +#define AT_TYPE 0x00000001 +#define AT_MODE 0x00000002 +#define AT_UID 0x00000004 +#define AT_GID 0x00000008 +#define AT_FSID 0x00000010 +#define AT_NODEID 0x00000020 +#define AT_NLINK 0x00000040 +#define AT_SIZE 0x00000080 +#define AT_ATIME 0x00000100 +#define AT_MTIME 0x00000200 +#define AT_CTIME 0x00000400 +#define AT_RDEV 0x00000800 +#define AT_BLKSIZE 0x00001000 +#define AT_NBLOCKS 0x00002000 +#define AT_VCODE 0x00004000 +#define AT_MAC 0x00008000 +#define AT_UPDATIME 0x00010000 +#define AT_UPDMTIME 0x00020000 +#define AT_UPDCTIME 0x00040000 +#define AT_ACL 0x00080000 +#define AT_CAP 0x00100000 +#define AT_INF 0x00200000 +#define AT_XFLAGS 0x00400000 +#define AT_EXTSIZE 0x00800000 +#define AT_NEXTENTS 0x01000000 +#define AT_ANEXTENTS 0x02000000 +#define AT_PROJID 0x04000000 +#define AT_SIZE_NOPERM 0x08000000 +#define AT_GENCOUNT 0x10000000 + +#define AT_ALL (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|\ + AT_NLINK|AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|AT_RDEV|\ + AT_BLKSIZE|AT_NBLOCKS|AT_VCODE|AT_MAC|AT_ACL|AT_CAP|\ + AT_INF|AT_XFLAGS|AT_EXTSIZE|AT_NEXTENTS|AT_ANEXTENTS|\ + AT_PROJID|AT_GENCOUNT) + +#define AT_STAT (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|AT_NLINK|\ + AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|AT_RDEV|AT_BLKSIZE|\ + AT_NBLOCKS|AT_PROJID) + +#define AT_TIMES (AT_ATIME|AT_MTIME|AT_CTIME) + +#define AT_UPDTIMES (AT_UPDATIME|AT_UPDMTIME|AT_UPDCTIME) + +#define AT_NOSET (AT_NLINK|AT_RDEV|AT_FSID|AT_NODEID|AT_TYPE|\ + AT_BLKSIZE|AT_NBLOCKS|AT_VCODE|AT_NEXTENTS|AT_ANEXTENTS|\ + AT_GENCOUNT) + +#define VREAD 00400 +#define VWRITE 00200 +#define VEXEC 00100 +#define VSGID 02000 /* set group id on execution */ +#define MODEMASK 07777 /* mode bits plus permission bits */ + +/* + * Check whether mandatory file locking is enabled. + */ +#define MANDLOCK(vp, mode) \ + ((vp)->v_type == VREG && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) + +extern void vn_init(void); +extern int vn_wait(struct vnode *); +extern vnode_t *vn_initialize(struct inode *); + +/* + * Acquiring and invalidating vnodes: + * + * if (vn_get(vp, version, 0)) + * ...; + * vn_purge(vp, version); + * + * vn_get and vn_purge must be called with vmap_t arguments, sampled + * while a lock that the vnode's VOP_RECLAIM function acquires is + * held, to ensure that the vnode sampled with the lock held isn't + * recycled (VOP_RECLAIMed) or deallocated between the release of the lock + * and the subsequent vn_get or vn_purge. + */ + +/* + * vnode_map structures _must_ match vn_epoch and vnode structure sizes. + */ +typedef struct vnode_map { + vfs_t *v_vfsp; + vnumber_t v_number; /* in-core vnode number */ + xfs_ino_t v_ino; /* inode # */ +} vmap_t; + +#define VMAP(vp, ip, vmap) {(vmap).v_vfsp = (vp)->v_vfsp, \ + (vmap).v_number = (vp)->v_number, \ + (vmap).v_ino = (ip)->i_ino; } +extern void vn_purge(struct vnode *, vmap_t *); +extern vnode_t *vn_get(struct vnode *, vmap_t *); +extern int vn_revalidate(struct vnode *, int); +extern void vn_remove(struct vnode *); + +static inline int vn_count(struct vnode *vp) +{ + return atomic_read(&LINVFS_GET_IP(vp)->i_count); +} + +/* + * Vnode reference counting functions (and macros for compatibility). + */ +extern vnode_t *vn_hold(struct vnode *); +extern void vn_rele(struct vnode *); + +#if defined(CONFIG_XFS_VNODE_TRACING) + +#define VN_HOLD(vp) \ + ((void)vn_hold(vp), \ + vn_trace_hold(vp, __FILE__, __LINE__, (inst_t *)__return_address)) +#define VN_RELE(vp) \ + (vn_trace_rele(vp, __FILE__, __LINE__, (inst_t *)__return_address), \ + iput(LINVFS_GET_IP(vp))) + +#else /* ! (defined(CONFIG_XFS_VNODE_TRACING)) */ + +#define VN_HOLD(vp) ((void)vn_hold(vp)) +#define VN_RELE(vp) (iput(LINVFS_GET_IP(vp))) + +#endif /* ! (defined(CONFIG_XFS_VNODE_TRACING) */ + +/* + * Vnode spinlock manipulation. + */ +#define VN_FLAGSET(vp,b) vn_flagset(vp,b) +#define VN_FLAGCLR(vp,b) vn_flagclr(vp,b) + +static __inline__ void vn_flagset(struct vnode *vp, uint flag) +{ + spin_lock(&vp->v_lock); + vp->v_flag |= flag; + spin_unlock(&vp->v_lock); +} + +static __inline__ void vn_flagclr(struct vnode *vp, uint flag) +{ + spin_lock(&vp->v_lock); + vp->v_flag &= ~flag; + spin_unlock(&vp->v_lock); +} + +/* + * Some useful predicates. + */ +#define VN_MAPPED(vp) ((LINVFS_GET_IP(vp)->i_mapping->i_mmap != NULL) || \ + (LINVFS_GET_IP(vp)->i_mapping->i_mmap_shared != NULL)) +#define VN_CACHED(vp) (LINVFS_GET_IP(vp)->i_mapping->nrpages) +#define VN_DIRTY(vp) (!list_empty(&(LINVFS_GET_IP(vp)->i_dirty_data_buffers))) +#define VMODIFY(vp) { VN_FLAGSET(vp, VMODIFIED); \ + mark_inode_dirty(LINVFS_GET_IP(vp)); } +#define VUNMODIFY(vp) VN_FLAGCLR(vp, VMODIFIED) + +/* + * Flags to VOP_SETATTR/VOP_GETATTR. + */ +#define ATTR_UTIME 0x01 /* non-default utime(2) request */ +#define ATTR_EXEC 0x02 /* invocation from exec(2) */ +#define ATTR_COMM 0x04 /* yield common vp attributes */ +#define ATTR_DMI 0x08 /* invocation from a DMI function */ +#define ATTR_LAZY 0x80 /* set/get attributes lazily */ +#define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ +#define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ +#define ATTR_NOSIZETOK 0x400 /* Don't get the DVN_SIZE_READ token */ + +/* + * Flags to VOP_FSYNC and VOP_RECLAIM. + */ +#define FSYNC_NOWAIT 0 /* asynchronous flush */ +#define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ +#define FSYNC_INVAL 0x2 /* flush and invalidate cached data */ +#define FSYNC_DATA 0x4 /* synchronous fsync of data only */ + +#if (defined(CONFIG_XFS_VNODE_TRACING)) + +#define VNODE_TRACE_SIZE 16 /* number of trace entries */ + +/* + * Tracing entries. + */ +#define VNODE_KTRACE_ENTRY 1 +#define VNODE_KTRACE_EXIT 2 +#define VNODE_KTRACE_HOLD 3 +#define VNODE_KTRACE_REF 4 +#define VNODE_KTRACE_RELE 5 + +extern void vn_trace_entry(struct vnode *, char *, inst_t *); +extern void vn_trace_exit(struct vnode *, char *, inst_t *); +extern void vn_trace_hold(struct vnode *, char *, int, inst_t *); +extern void vn_trace_ref(struct vnode *, char *, int, inst_t *); +extern void vn_trace_rele(struct vnode *, char *, int, inst_t *); +#define VN_TRACE(vp) \ + vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address) + +#else /* ! (defined(CONFIG_XFS_VNODE_TRACING)) */ + +#define vn_trace_entry(a,b,c) +#define vn_trace_exit(a,b,c) +#define vn_trace_hold(a,b,c,d) +#define vn_trace_ref(a,b,c,d) +#define vn_trace_rele(a,b,c,d) +#define VN_TRACE(vp) + +#endif /* ! (defined(CONFIG_XFS_VNODE_TRACING)) */ + +#endif /* __XFS_VNODE_H__ */ diff -Nur linux-2.4.19/fs/xfs/pagebuf/Makefile linux-2.4.19-sgi211r3/fs/xfs/pagebuf/Makefile --- linux-2.4.19/fs/xfs/pagebuf/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/pagebuf/Makefile Wed Oct 16 14:02:58 2002 @@ -0,0 +1,55 @@ +# +# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# Makefile for the linux pagebuf routines. +# + +# Debug options: +# -DDEBUG +# -DPAGEBUF_TRACKING +# -DPAGEBUF_TRACE +ifeq ($(CONFIG_PAGEBUF_DEBUG),y) + EXTRA_CFLAGS += -g -DDEBUG -DSTATIC="" \ + -DPAGEBUF_TRACKING -DPAGEBUF_TRACE +endif +EXTRA_CFLAGS += -I.. + +O_TARGET := pagebuf.o + +ifneq ($(MAKECMDGOALS),modules_install) + obj-m := $(O_TARGET) +endif + +export-objs += page_buf.o +obj-y += page_buf.o \ + page_buf_locking.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/fs/xfs/pagebuf/page_buf.c linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf.c --- linux-2.4.19/fs/xfs/pagebuf/page_buf.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf.c Fri Dec 20 21:39:10 2002 @@ -0,0 +1,2540 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * page_buf.c + * + * The page_buf module provides an abstract buffer cache model on top of + * the Linux page cache. Cached metadata blocks for a file system are + * hashed to the inode for the block device. The page_buf module + * assembles buffer (page_buf_t) objects on demand to aggregate such + * cached pages for I/O. + * + * + * Written by Steve Lord, Jim Mostek, Russell Cattelan + * and Rajagopal Ananthanarayanan ("ananth") at SGI. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "page_buf_internal.h" + +#define NBBY 8 +#define SECTOR_SHIFT 9 +#define SECTOR_SIZE (1<pb_flags; + pb_trace.buf[j].hold = pb->pb_hold.counter; + pb_trace.buf[j].lock_value = PBP(pb)->pb_sema.count.counter; + pb_trace.buf[j].task = (void *)current; + pb_trace.buf[j].misc = misc; + pb_trace.buf[j].ra = ra; + pb_trace.buf[j].offset = pb->pb_file_offset; + pb_trace.buf[j].size = pb->pb_buffer_length; +} +#endif /* PAGEBUF_TRACE */ + +#ifdef PAGEBUF_TRACKING +#define MAX_PB 10000 +page_buf_t *pb_array[MAX_PB]; +EXPORT_SYMBOL(pb_array); + +void +pb_tracking_get( + page_buf_t *pb) +{ + int i; + + for (i = 0; (pb_array[i] != 0) && (i < MAX_PB); i++) { } + if (i == MAX_PB) + printk("pb 0x%p not recorded in pb_array\n", pb); + else { + //printk("pb_get 0x%p in pb_array[%d]\n", pb, i); + pb_array[i] = pb; + } +} + +void +pb_tracking_free( + page_buf_t *pb) +{ + int i; + + for (i = 0; (pb_array[i] != pb) && (i < MAX_PB); i++) { } + if (i < MAX_PB) { + //printk("pb_free 0x%p from pb_array[%d]\n", pb, i); + pb_array[i] = NULL; + } + else + printk("Freed unmonitored pagebuf 0x%p\n", pb); +} +#else +#define pb_tracking_get(pb) do { } while (0) +#define pb_tracking_free(pb) do { } while (0) +#endif /* PAGEBUF_TRACKING */ + +/* + * File wide globals + */ + +STATIC kmem_cache_t *pagebuf_cache; +STATIC pagebuf_daemon_t *pb_daemon; +STATIC struct list_head pagebuf_iodone_tq[NR_CPUS]; +STATIC wait_queue_head_t pagebuf_iodone_wait[NR_CPUS]; + +/* + * For pre-allocated buffer head pool + */ + +#define NR_RESERVED_BH 64 +static wait_queue_head_t pb_resv_bh_wait; +static spinlock_t pb_resv_bh_lock = SPIN_LOCK_UNLOCKED; +struct buffer_head *pb_resv_bh = NULL; /* list of bh */ +int pb_resv_bh_cnt = 0; /* # of bh available */ + +STATIC void pagebuf_daemon_wakeup(int); +STATIC int _pagebuf_segment_apply(page_buf_t *); + +/* + * Pagebuf module configuration parameters, exported via + * /proc/sys/vm/pagebuf + */ + +unsigned long pagebuf_min[P_PARAM] = { HZ/2, 1*HZ, 0, 0 }; +unsigned long pagebuf_max[P_PARAM] = { HZ*30, HZ*300, 1, 1 }; + +pagebuf_param_t pb_params = {{ HZ, 15 * HZ, 0, 0 }}; + +/* + * Pagebuf statistics variables + */ + +struct pbstats pbstats; + +/* + * Pagebuf allocation / freeing. + */ + +#define pb_to_gfp(flags) \ + (((flags) & PBF_READ_AHEAD) ? GFP_READAHEAD : \ + ((flags) & PBF_DONT_BLOCK) ? GFP_NOFS : GFP_KERNEL) + +#define pagebuf_allocate(flags) \ + kmem_cache_alloc(pagebuf_cache, pb_to_gfp(flags)) +#define pagebuf_deallocate(pb) \ + kmem_cache_free(pagebuf_cache, (pb)); + +/* + * Pagebuf hashing + */ + +#define NBITS 5 +#define NHASH (1<pb_hash_index] + +STATIC int +_bhash( + dev_t dev, + loff_t base) +{ + int bit, hval; + + base >>= 9; + /* + * dev_t is 16 bits, loff_t is always 64 bits + */ + base ^= dev; + for (bit = hval = 0; base != 0 && bit < sizeof(base) * 8; bit += NBITS) { + hval ^= (int)base & (NHASH-1); + base >>= NBITS; + } + return hval; +} + +/* + * Mapping of multi-page buffers into contingous virtual space + */ + +STATIC void *pagebuf_mapout_locked(page_buf_t *); + +STATIC spinlock_t as_lock = SPIN_LOCK_UNLOCKED; +typedef struct a_list { + void *vm_addr; + struct a_list *next; +} a_list_t; +STATIC a_list_t *as_free_head; +STATIC int as_list_len; + +STATIC void +free_address( + void *addr) +{ + a_list_t *aentry; + + spin_lock(&as_lock); + aentry = kmalloc(sizeof(a_list_t), GFP_ATOMIC); + aentry->next = as_free_head; + aentry->vm_addr = addr; + as_free_head = aentry; + as_list_len++; + spin_unlock(&as_lock); +} + +STATIC void +purge_addresses(void) +{ + a_list_t *aentry, *old; + + if (as_free_head == NULL) return; + + spin_lock(&as_lock); + aentry = as_free_head; + as_free_head = NULL; + as_list_len = 0; + spin_unlock(&as_lock); + + while ((old = aentry) != NULL) { + vunmap(aentry->vm_addr); + aentry = aentry->next; + kfree(old); + } +} + +/* + * Locking model: + * + * Buffers associated with inodes for which buffer locking + * is not enabled are not protected by semaphores, and are + * assumed to be exclusively owned by the caller. There is + * spinlock in the buffer, for use by the caller when concurrent + * access is possible. + */ + +/* + * Internal pagebuf object manipulation + */ + +STATIC void +_pagebuf_initialize( + page_buf_t *pb, + pb_target_t *target, + loff_t range_base, + size_t range_length, + page_buf_flags_t flags) +{ + /* + * We don't want certain flags to appear in pb->pb_flags. + */ + flags &= ~(PBF_LOCK|PBF_ENTER_PAGES|PBF_MAPPED); + flags &= ~(PBF_DONT_BLOCK|PBF_READ_AHEAD); + + pb_tracking_get(pb); + + memset(pb, 0, sizeof(page_buf_private_t)); + atomic_set(&pb->pb_hold, 1); + init_MUTEX_LOCKED(&pb->pb_iodonesema); + INIT_LIST_HEAD(&pb->pb_list); + INIT_LIST_HEAD(&pb->pb_hash_list); + init_MUTEX_LOCKED(&PBP(pb)->pb_sema); /* held, no waiters */ + PB_SET_OWNER(pb); + pb->pb_target = target; + pb->pb_file_offset = range_base; + /* + * Set buffer_length and count_desired to the same value initially. + * IO routines should use count_desired, which will be the same in + * most cases but may be reset (e.g. XFS recovery). + */ + pb->pb_buffer_length = pb->pb_count_desired = range_length; + pb->pb_flags = flags | PBF_NONE; + pb->pb_bn = PAGE_BUF_DADDR_NULL; + atomic_set(&PBP(pb)->pb_pin_count, 0); + init_waitqueue_head(&PBP(pb)->pb_waiters); + + PB_STATS_INC(pbstats.pb_create); + PB_TRACE(pb, PB_TRACE_REC(get), target); +} + +/* + * Allocate a page array capable of holding a specified number + * of pages, and point the page buf at it. + */ +STATIC int +_pagebuf_get_pages( + page_buf_t *pb, + int page_count, + int flags) +{ + int gpf_mask = pb_to_gfp(flags); + + /* Make sure that we have a page list */ + if (pb->pb_pages == NULL) { + pb->pb_offset = page_buf_poff(pb->pb_file_offset); + pb->pb_page_count = page_count; + if (page_count <= PB_PAGES) { + pb->pb_pages = pb->pb_page_array; + } else { + pb->pb_pages = kmalloc(sizeof(struct page *) * + page_count, gpf_mask); + if (pb->pb_pages == NULL) + return -ENOMEM; + } + memset(pb->pb_pages, 0, sizeof(struct page *) * page_count); + } + return 0; +} + +/* + * Walk a pagebuf releasing all the pages contained within it. + */ +STATIC inline void +_pagebuf_freepages( + page_buf_t *pb) +{ + int buf_index; + + for (buf_index = 0; buf_index < pb->pb_page_count; buf_index++) { + struct page *page = pb->pb_pages[buf_index]; + + if (page) { + pb->pb_pages[buf_index] = NULL; + page_cache_release(page); + } + } + + if (pb->pb_pages != pb->pb_page_array) + kfree(pb->pb_pages); +} + +/* + * _pagebuf_free_object + * + * _pagebuf_free_object releases the contents specified buffer. + * The modification state of any associated pages is left unchanged. + */ +void +_pagebuf_free_object( + pb_hash_t *hash, /* hash bucket for buffer */ + page_buf_t *pb) /* buffer to deallocate */ +{ + int pb_flags = pb->pb_flags; + + PB_TRACE(pb, PB_TRACE_REC(free_obj), 0); + pb->pb_flags |= PBF_FREED; + + if (hash) { + if (!list_empty(&pb->pb_hash_list)) { + hash->pb_count--; + list_del_init(&pb->pb_hash_list); + } + spin_unlock(&hash->pb_hash_lock); + } + + if (!(pb_flags & PBF_FREED)) { + /* release any virtual mapping */ ; + if (pb->pb_flags & _PBF_ADDR_ALLOCATED) { + void *vaddr = pagebuf_mapout_locked(pb); + if (vaddr) { + free_address(vaddr); + } + } + + if (pb->pb_flags & _PBF_MEM_ALLOCATED) { + if (pb->pb_pages) { + /* release the pages in the address list */ + if (pb->pb_pages[0] && + PageSlab(pb->pb_pages[0])) { + /* + * This came from the slab + * allocator free it as such + */ + kfree(pb->pb_addr); + } else { + _pagebuf_freepages(pb); + } + + pb->pb_pages = NULL; + } + pb->pb_flags &= ~_PBF_MEM_ALLOCATED; + } + } + + pb_tracking_free(pb); + pagebuf_deallocate(pb); +} + +/* + * _pagebuf_lookup_pages + * + * _pagebuf_lookup_pages finds all pages which match the buffer + * in question and the range of file offsets supplied, + * and builds the page list for the buffer, if the + * page list is not already formed or if not all of the pages are + * already in the list. Invalid pages (pages which have not yet been + * read in from disk) are assigned for any pages which are not found. + */ +STATIC int +_pagebuf_lookup_pages( + page_buf_t *pb, + struct address_space *aspace, + page_buf_flags_t flags) +{ + loff_t next_buffer_offset; + unsigned long page_count, pi, index; + struct page *page; + int gfp_mask, retry_count = 5, rval = 0; + int all_mapped, good_pages; + size_t blocksize; + + /* For pagebufs where we want to map an address, do not use + * highmem pages - so that we do not need to use kmap resources + * to access the data. + * + * For pages where the caller has indicated there may be resource + * contention (e.g. called from a transaction) do not flush + * delalloc pages to obtain memory. + */ + + if (flags & PBF_READ_AHEAD) { + gfp_mask = GFP_READAHEAD; + retry_count = 0; + } else if (flags & PBF_DONT_BLOCK) { + gfp_mask = GFP_NOFS; + } else if (flags & PBF_MAPPABLE) { + gfp_mask = GFP_KERNEL; + } else { + gfp_mask = GFP_HIGHUSER; + } + + next_buffer_offset = pb->pb_file_offset + pb->pb_buffer_length; + + good_pages = page_count = (page_buf_btoc(next_buffer_offset) - + page_buf_btoct(pb->pb_file_offset)); + + if (pb->pb_flags & _PBF_ALL_PAGES_MAPPED) { + /* Bring pages forward in cache */ + for (pi = 0; pi < page_count; pi++) { + mark_page_accessed(pb->pb_pages[pi]); + } + if ((flags & PBF_MAPPED) && !(pb->pb_flags & PBF_MAPPED)) { + all_mapped = 1; + goto mapit; + } + return 0; + } + + /* Ensure pb_pages field has been initialised */ + rval = _pagebuf_get_pages(pb, page_count, flags); + if (rval) + return rval; + + rval = pi = 0; + blocksize = pb->pb_target->pbr_blocksize; + + /* Enter the pages in the page list */ + index = (pb->pb_file_offset - pb->pb_offset) >> PAGE_CACHE_SHIFT; + for (all_mapped = 1; pi < page_count; pi++, index++) { + if (pb->pb_pages[pi] == 0) { + retry: + page = find_or_create_page(aspace, index, gfp_mask); + if (!page) { + if (--retry_count > 0) { + PB_STATS_INC(pbstats.pb_page_retries); + pagebuf_daemon_wakeup(1); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(10); + goto retry; + } + rval = -ENOMEM; + all_mapped = 0; + continue; + } + PB_STATS_INC(pbstats.pb_page_found); + mark_page_accessed(page); + pb->pb_pages[pi] = page; + } else { + page = pb->pb_pages[pi]; + lock_page(page); + } + + /* If we need to do I/O on a page record the fact */ + if (!Page_Uptodate(page)) { + good_pages--; + if ((blocksize == PAGE_CACHE_SIZE) && + (flags & PBF_READ)) + pb->pb_locked = 1; + } + } + + if (!pb->pb_locked) { + for (pi = 0; pi < page_count; pi++) { + if (pb->pb_pages[pi]) + unlock_page(pb->pb_pages[pi]); + } + } + +mapit: + pb->pb_flags |= _PBF_MEM_ALLOCATED; + if (all_mapped) { + pb->pb_flags |= _PBF_ALL_PAGES_MAPPED; + + /* A single page buffer is always mappable */ + if (page_count == 1) { + pb->pb_addr = (caddr_t) + page_address(pb->pb_pages[0]) + pb->pb_offset; + pb->pb_flags |= PBF_MAPPED; + } else if (flags & PBF_MAPPED) { + if (as_list_len > 64) + purge_addresses(); + pb->pb_addr = vmap(pb->pb_pages, page_count); + if (pb->pb_addr == NULL) + return -ENOMEM; + pb->pb_addr += pb->pb_offset; + pb->pb_flags |= PBF_MAPPED | _PBF_ADDR_ALLOCATED; + } + } + /* If some pages were found with data in them + * we are not in PBF_NONE state. + */ + if (good_pages != 0) { + pb->pb_flags &= ~(PBF_NONE); + if (good_pages != page_count) { + pb->pb_flags |= PBF_PARTIAL; + } + } + + PB_TRACE(pb, PB_TRACE_REC(look_pg), good_pages); + + return rval; +} + + +/* + * Pre-allocation of a pool of buffer heads for use in + * low-memory situations. + */ + +/* + * _pagebuf_prealloc_bh + * + * Pre-allocate a pool of "count" buffer heads at startup. + * Puts them on a list at "pb_resv_bh" + * Returns number of bh actually allocated to pool. + */ +STATIC int +_pagebuf_prealloc_bh( + int count) +{ + struct buffer_head *bh; + int i; + + for (i = 0; i < count; i++) { + bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL); + if (!bh) + break; + bh->b_pprev = &pb_resv_bh; + bh->b_next = pb_resv_bh; + pb_resv_bh = bh; + pb_resv_bh_cnt++; + } + return i; +} + +/* + * _pagebuf_get_prealloc_bh + * + * Get one buffer head from our pre-allocated pool. + * If pool is empty, sleep 'til one comes back in. + * Returns aforementioned buffer head. + */ +STATIC struct buffer_head * +_pagebuf_get_prealloc_bh(void) +{ + unsigned long flags; + struct buffer_head *bh; + DECLARE_WAITQUEUE (wait, current); + + spin_lock_irqsave(&pb_resv_bh_lock, flags); + + if (pb_resv_bh_cnt < 1) { + add_wait_queue(&pb_resv_bh_wait, &wait); + do { + set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock_irqrestore(&pb_resv_bh_lock, flags); + run_task_queue(&tq_disk); + schedule(); + spin_lock_irqsave(&pb_resv_bh_lock, flags); + } while (pb_resv_bh_cnt < 1); + __set_current_state(TASK_RUNNING); + remove_wait_queue(&pb_resv_bh_wait, &wait); + } + + BUG_ON(pb_resv_bh_cnt < 1); + BUG_ON(!pb_resv_bh); + + bh = pb_resv_bh; + pb_resv_bh = bh->b_next; + bh->b_state = 0; + pb_resv_bh_cnt--; + + spin_unlock_irqrestore(&pb_resv_bh_lock, flags); + return bh; +} + +/* + * _pagebuf_free_bh + * + * Take care of buffer heads that we're finished with. + * Call this instead of just kmem_cache_free(bh_cachep, bh) + * when you're done with a bh. + * + * If our pre-allocated pool is full, just free the buffer head. + * Otherwise, put it back in the pool, and wake up anybody + * waiting for one. + */ +STATIC inline void +_pagebuf_free_bh( + struct buffer_head *bh) +{ + unsigned long flags; + + if (pb_resv_bh_cnt == NR_RESERVED_BH){ + kmem_cache_free(bh_cachep, bh); + } else { + spin_lock_irqsave(&pb_resv_bh_lock, flags); + + bh->b_pprev = &pb_resv_bh; + bh->b_next = pb_resv_bh; + pb_resv_bh = bh; + pb_resv_bh_cnt++; + + if (waitqueue_active(&pb_resv_bh_wait)) { + wake_up(&pb_resv_bh_wait); + } + + spin_unlock_irqrestore(&pb_resv_bh_lock, flags); + } +} + +/* + * Finding and Reading Buffers + */ + +/* + * _pagebuf_find + * + * Looks up, and creates if absent, a lockable buffer for + * a given range of an inode. The buffer is returned + * locked. If other overlapping buffers exist, they are + * released before the new buffer is created and locked, + * which may imply that this call will block until those buffers + * are unlocked. No I/O is implied by this call. + */ +STATIC page_buf_t * +_pagebuf_find( /* find buffer for block */ + pb_target_t *target,/* target for block */ + loff_t ioff, /* starting offset of range */ + size_t isize, /* length of range */ + page_buf_flags_t flags, /* PBF_TRYLOCK */ + page_buf_t *new_pb)/* newly allocated buffer */ +{ + loff_t range_base; + size_t range_length; + int hval; + pb_hash_t *h; + struct list_head *p; + page_buf_t *pb; + int not_locked; + + range_base = (ioff << SECTOR_SHIFT); + range_length = (isize << SECTOR_SHIFT); + + hval = _bhash(target->pbr_bdev->bd_dev, range_base); + h = &pbhash[hval]; + + spin_lock(&h->pb_hash_lock); + list_for_each(p, &h->pb_hash) { + pb = list_entry(p, page_buf_t, pb_hash_list); + + if ((target == pb->pb_target) && + (pb->pb_file_offset == range_base) && + (pb->pb_buffer_length == range_length)) { + if (pb->pb_flags & PBF_FREED) + break; + /* If we look at something bring it to the + * front of the list for next time + */ + list_del(&pb->pb_hash_list); + list_add(&pb->pb_hash_list, &h->pb_hash); + goto found; + } + } + + /* No match found */ + if (new_pb) { + _pagebuf_initialize(new_pb, target, range_base, + range_length, flags | _PBF_LOCKABLE); + new_pb->pb_hash_index = hval; + h->pb_count++; + list_add(&new_pb->pb_hash_list, &h->pb_hash); + } else { + PB_STATS_INC(pbstats.pb_miss_locked); + } + + spin_unlock(&h->pb_hash_lock); + return (new_pb); + +found: + atomic_inc(&pb->pb_hold); + spin_unlock(&h->pb_hash_lock); + + /* Attempt to get the semaphore without sleeping, + * if this does not work then we need to drop the + * spinlock and do a hard attempt on the semaphore. + */ + not_locked = down_trylock(&PBP(pb)->pb_sema); + if (not_locked) { + if (!(flags & PBF_TRYLOCK)) { + /* wait for buffer ownership */ + PB_TRACE(pb, PB_TRACE_REC(get_lk), 0); + pagebuf_lock(pb); + PB_STATS_INC(pbstats.pb_get_locked_waited); + } else { + /* We asked for a trylock and failed, no need + * to look at file offset and length here, we + * know that this pagebuf at least overlaps our + * pagebuf and is locked, therefore our buffer + * either does not exist, or is this buffer + */ + + pagebuf_rele(pb); + PB_STATS_INC(pbstats.pb_busy_locked); + return (NULL); + } + } else { + /* trylock worked */ + PB_SET_OWNER(pb); + } + + if (pb->pb_flags & PBF_STALE) + pb->pb_flags &= PBF_MAPPABLE | \ + PBF_MAPPED | \ + _PBF_LOCKABLE | \ + _PBF_ALL_PAGES_MAPPED | \ + _PBF_SOME_INVALID_PAGES | \ + _PBF_ADDR_ALLOCATED | \ + _PBF_MEM_ALLOCATED; + PB_TRACE(pb, PB_TRACE_REC(got_lk), 0); + PB_STATS_INC(pbstats.pb_get_locked); + return (pb); +} + + +/* + * pagebuf_find + * + * pagebuf_find returns a buffer matching the specified range of + * data for the specified target, if any of the relevant blocks + * are in memory. The buffer may have unallocated holes, if + * some, but not all, of the blocks are in memory. Even where + * pages are present in the buffer, not all of every page may be + * valid. The file system may use pagebuf_segment to visit the + * various segments of the buffer. + */ +page_buf_t * +pagebuf_find( /* find buffer for block */ + /* if the block is in memory */ + pb_target_t *target,/* target for block */ + loff_t ioff, /* starting offset of range */ + size_t isize, /* length of range */ + page_buf_flags_t flags) /* PBF_TRYLOCK */ +{ + return _pagebuf_find(target, ioff, isize, flags, NULL); +} + +/* + * pagebuf_get + * + * pagebuf_get assembles a buffer covering the specified range. + * Some or all of the blocks in the range may be valid. The file + * system may use pagebuf_segment to visit the various segments + * of the buffer. Storage in memory for all portions of the + * buffer will be allocated, although backing storage may not be. + * If PBF_READ is set in flags, pagebuf_read + */ +page_buf_t * +pagebuf_get( /* allocate a buffer */ + pb_target_t *target,/* target for buffer */ + loff_t ioff, /* starting offset of range */ + size_t isize, /* length of range */ + page_buf_flags_t flags) /* PBF_TRYLOCK */ +{ + page_buf_t *pb, *new_pb; + int error; + + new_pb = pagebuf_allocate(flags); + if (unlikely(!new_pb)) + return (NULL); + + pb = _pagebuf_find(target, ioff, isize, flags, new_pb); + if (pb != new_pb) { + pagebuf_deallocate(new_pb); + if (unlikely(!pb)) + return (NULL); + } + + PB_STATS_INC(pbstats.pb_get); + + /* fill in any missing pages */ + error = _pagebuf_lookup_pages(pb, pb->pb_target->pbr_mapping, flags); + if (unlikely(error)) { + pagebuf_free(pb); + return (NULL); + } + + /* + * Always fill in the block number now, the mapped cases can do + * their own overlay of this later. + */ + pb->pb_bn = ioff; + pb->pb_count_desired = pb->pb_buffer_length; + + if (flags & PBF_READ) { + if (PBF_NOT_DONE(pb)) { + PB_TRACE(pb, PB_TRACE_REC(get_read), flags); + PB_STATS_INC(pbstats.pb_get_read); + pagebuf_iostart(pb, flags); + } else if (flags & PBF_ASYNC) { + /* + * Read ahead call which is already satisfied, + * drop the buffer + */ + if (flags & (PBF_LOCK | PBF_TRYLOCK)) + pagebuf_unlock(pb); + pagebuf_rele(pb); + return NULL; + } else { + /* We do not want read in the flags */ + pb->pb_flags &= ~PBF_READ; + } + } + + PB_TRACE(pb, PB_TRACE_REC(get_obj), flags); + return (pb); +} + +/* + * Create a pagebuf and populate it with pages from the address + * space of the passed in inode. + */ +page_buf_t * +pagebuf_lookup( + struct pb_target *target, + struct inode *inode, + loff_t ioff, + size_t isize, + int flags) +{ + page_buf_t *pb = NULL; + int status; + + flags |= _PBF_PRIVATE_BH; + pb = pagebuf_allocate(flags); + if (pb) { + _pagebuf_initialize(pb, target, ioff, isize, flags); + if (flags & PBF_ENTER_PAGES) { + status = _pagebuf_lookup_pages(pb, &inode->i_data, 0); + if (status != 0) { + pagebuf_free(pb); + return (NULL); + } + } + } + return pb; +} + +/* + * If we are not low on memory then do the readahead in a deadlock + * safe manner. + */ +void +pagebuf_readahead( + pb_target_t *target, + loff_t ioff, + size_t isize, + int flags) +{ + if (!start_aggressive_readahead(GFP_KERNEL)) + return; + + flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_MAPPABLE|PBF_READ_AHEAD); + pagebuf_get(target, ioff, isize, flags); +} + +page_buf_t * +pagebuf_get_empty( + pb_target_t *target) +{ + page_buf_t *pb; + + pb = pagebuf_allocate(_PBF_LOCKABLE); + if (pb) + _pagebuf_initialize(pb, target, 0, 0, _PBF_LOCKABLE); + return pb; +} + +static inline struct page * +mem_to_page( + void *addr) +{ + if (((unsigned long)addr < VMALLOC_START) || + ((unsigned long)addr >= VMALLOC_END)) { + return virt_to_page(addr); + } else { + return vmalloc_to_page(addr); + } +} + +int +pagebuf_associate_memory( + page_buf_t *pb, + void *mem, + size_t len) +{ + int rval; + int i = 0; + size_t ptr; + size_t end, end_cur; + off_t offset; + int page_count; + + page_count = PAGE_CACHE_ALIGN(len) >> PAGE_CACHE_SHIFT; + offset = (off_t) mem - ((off_t)mem & PAGE_CACHE_MASK); + if (offset && (len > PAGE_CACHE_SIZE)) + page_count++; + + /* Free any previous set of page pointers */ + if (pb->pb_pages && (pb->pb_pages != pb->pb_page_array)) { + kfree(pb->pb_pages); + } + pb->pb_pages = NULL; + pb->pb_addr = mem; + + rval = _pagebuf_get_pages(pb, page_count, 0); + if (rval) + return rval; + + pb->pb_offset = offset; + ptr = (size_t) mem & PAGE_CACHE_MASK; + end = PAGE_CACHE_ALIGN((size_t) mem + len); + end_cur = end; + /* set up first page */ + pb->pb_pages[0] = mem_to_page(mem); + + ptr += PAGE_CACHE_SIZE; + pb->pb_page_count = ++i; + while (ptr < end) { + pb->pb_pages[i] = mem_to_page((void *)ptr); + pb->pb_page_count = ++i; + ptr += PAGE_CACHE_SIZE; + } + pb->pb_locked = 0; + + pb->pb_count_desired = pb->pb_buffer_length = len; + pb->pb_flags |= PBF_MAPPED | _PBF_PRIVATE_BH; + + return 0; +} + +page_buf_t * +pagebuf_get_no_daddr( + size_t len, + pb_target_t *target) +{ + int rval; + void *rmem = NULL; + int flags = _PBF_LOCKABLE | PBF_FORCEIO; + page_buf_t *pb; + size_t tlen = 0; + + if (len > 0x20000) + return(NULL); + + pb = pagebuf_allocate(flags); + if (!pb) + return NULL; + + _pagebuf_initialize(pb, target, 0, len, flags); + + do { + if (tlen == 0) { + tlen = len; /* first time */ + } else { + kfree(rmem); /* free the mem from the previous try */ + tlen <<= 1; /* double the size and try again */ + /* + printk( + "pb_get_no_daddr NOT block 0x%p mask 0x%p len %d\n", + rmem, ((size_t)rmem & (size_t)~SECTOR_MASK), + len); + */ + } + if ((rmem = kmalloc(tlen, GFP_KERNEL)) == 0) { + pagebuf_free(pb); + return NULL; + } + } while ((size_t)rmem != ((size_t)rmem & (size_t)~SECTOR_MASK)); + + if ((rval = pagebuf_associate_memory(pb, rmem, len)) != 0) { + kfree(rmem); + pagebuf_free(pb); + return NULL; + } + /* otherwise pagebuf_free just ignores it */ + pb->pb_flags |= _PBF_MEM_ALLOCATED; + PB_CLEAR_OWNER(pb); + up(&PBP(pb)->pb_sema); /* Return unlocked pagebuf */ + + PB_TRACE(pb, PB_TRACE_REC(no_daddr), rmem); + + return pb; +} + + +/* + * pagebuf_hold + * + * Increment reference count on buffer, to hold the buffer concurrently + * with another thread which may release (free) the buffer asynchronously. + * + * Must hold the buffer already to call this function. + */ +void +pagebuf_hold( + page_buf_t *pb) +{ + atomic_inc(&pb->pb_hold); + PB_TRACE(pb, PB_TRACE_REC(hold), 0); +} + +/* + * pagebuf_free + * + * pagebuf_free releases the specified buffer. The modification + * state of any associated pages is left unchanged. + */ +void +pagebuf_free( + page_buf_t *pb) +{ + if (pb->pb_flags & _PBF_LOCKABLE) { + pb_hash_t *h = pb_hash(pb); + + spin_lock(&h->pb_hash_lock); + _pagebuf_free_object(h, pb); + } else { + _pagebuf_free_object(NULL, pb); + } +} + +/* + * pagebuf_rele + * + * pagebuf_rele releases a hold on the specified buffer. If the + * the hold count is 1, pagebuf_rele calls pagebuf_free. + */ +void +pagebuf_rele( + page_buf_t *pb) +{ + pb_hash_t *h; + + PB_TRACE(pb, PB_TRACE_REC(rele), pb->pb_relse); + if (pb->pb_flags & _PBF_LOCKABLE) { + h = pb_hash(pb); + spin_lock(&h->pb_hash_lock); + } else { + h = NULL; + } + + if (atomic_dec_and_test(&pb->pb_hold)) { + int do_free = 1; + + if (pb->pb_relse) { + atomic_inc(&pb->pb_hold); + if (h) + spin_unlock(&h->pb_hash_lock); + (*(pb->pb_relse)) (pb); + do_free = 0; + } + if (pb->pb_flags & PBF_DELWRI) { + pb->pb_flags |= PBF_ASYNC; + atomic_inc(&pb->pb_hold); + if (h && do_free) + spin_unlock(&h->pb_hash_lock); + pagebuf_delwri_queue(pb, 0); + do_free = 0; + } else if (pb->pb_flags & PBF_FS_MANAGED) { + if (h) + spin_unlock(&h->pb_hash_lock); + do_free = 0; + } + + if (do_free) { + _pagebuf_free_object(h, pb); + } + } else if (h) { + spin_unlock(&h->pb_hash_lock); + } +} + + +/* + * Pinning Buffer Storage in Memory + */ + +/* + * pagebuf_pin + * + * pagebuf_pin locks all of the memory represented by a buffer in + * memory. Multiple calls to pagebuf_pin and pagebuf_unpin, for + * the same or different buffers affecting a given page, will + * properly count the number of outstanding "pin" requests. The + * buffer may be released after the pagebuf_pin and a different + * buffer used when calling pagebuf_unpin, if desired. + * pagebuf_pin should be used by the file system when it wants be + * assured that no attempt will be made to force the affected + * memory to disk. It does not assure that a given logical page + * will not be moved to a different physical page. + */ +void +pagebuf_pin( + page_buf_t *pb) +{ + atomic_inc(&PBP(pb)->pb_pin_count); + PB_TRACE(pb, PB_TRACE_REC(pin), PBP(pb)->pb_pin_count.counter); +} + +/* + * pagebuf_unpin + * + * pagebuf_unpin reverses the locking of memory performed by + * pagebuf_pin. Note that both functions affected the logical + * pages associated with the buffer, not the buffer itself. + */ +void +pagebuf_unpin( + page_buf_t *pb) +{ + if (atomic_dec_and_test(&PBP(pb)->pb_pin_count)) { + wake_up_all(&PBP(pb)->pb_waiters); + } + PB_TRACE(pb, PB_TRACE_REC(unpin), PBP(pb)->pb_pin_count.counter); +} + +int +pagebuf_ispin( + page_buf_t *pb) +{ + return atomic_read(&PBP(pb)->pb_pin_count); +} + +/* + * pagebuf_wait_unpin + * + * pagebuf_wait_unpin waits until all of the memory associated + * with the buffer is not longer locked in memory. It returns + * immediately if none of the affected pages are locked. + */ +static inline void +_pagebuf_wait_unpin( + page_buf_t *pb) +{ + DECLARE_WAITQUEUE (wait, current); + + if (atomic_read(&PBP(pb)->pb_pin_count) == 0) + return; + + add_wait_queue(&PBP(pb)->pb_waiters, &wait); + for (;;) { + current->state = TASK_UNINTERRUPTIBLE; + if (atomic_read(&PBP(pb)->pb_pin_count) == 0) { + break; + } + run_task_queue(&tq_disk); + schedule(); + } + remove_wait_queue(&PBP(pb)->pb_waiters, &wait); + current->state = TASK_RUNNING; +} + +void +pagebuf_queue_task( + struct tq_struct *task) +{ + queue_task(task, &pagebuf_iodone_tq[smp_processor_id()]); + wake_up(&pagebuf_iodone_wait[smp_processor_id()]); +} + + +/* + * Buffer Utility Routines + */ + +/* + * pagebuf_iodone + * + * pagebuf_iodone marks a buffer for which I/O is in progress + * done with respect to that I/O. The pb_done routine, if + * present, will be called as a side-effect. + */ +void +pagebuf_iodone_sched( + void *v) +{ + page_buf_t *pb = (page_buf_t *)v; + + if (pb->pb_iodone) { + (*(pb->pb_iodone)) (pb); + return; + } + + if (pb->pb_flags & PBF_ASYNC) { + if ((pb->pb_flags & _PBF_LOCKABLE) && !pb->pb_relse) + pagebuf_unlock(pb); + pagebuf_rele(pb); + } +} + +void +pagebuf_iodone( + page_buf_t *pb) +{ + pb->pb_flags &= ~(PBF_READ | PBF_WRITE); + if (pb->pb_error == 0) { + pb->pb_flags &= ~(PBF_PARTIAL | PBF_NONE); + } + + PB_TRACE(pb, PB_TRACE_REC(done), pb->pb_iodone); + + if ((pb->pb_iodone) || (pb->pb_flags & PBF_ASYNC)) { + INIT_TQUEUE(&pb->pb_iodone_sched, + pagebuf_iodone_sched, (void *)pb); + + queue_task(&pb->pb_iodone_sched, + &pagebuf_iodone_tq[smp_processor_id()]); + wake_up(&pagebuf_iodone_wait[smp_processor_id()]); + } else { + up(&pb->pb_iodonesema); + } +} + +/* + * pagebuf_ioerror + * + * pagebuf_ioerror sets the error code for a buffer. + */ +void +pagebuf_ioerror( /* mark/clear buffer error flag */ + page_buf_t *pb, /* buffer to mark */ + unsigned int error) /* error to store (0 if none) */ +{ + pb->pb_error = error; + PB_TRACE(pb, PB_TRACE_REC(ioerror), error); +} + +/* + * pagebuf_iostart + * + * pagebuf_iostart initiates I/O on a buffer, based on the flags supplied. + * If necessary, it will arrange for any disk space allocation required, + * and it will break up the request if the block mappings require it. + * An pb_iodone routine in the buffer supplied will only be called + * when all of the subsidiary I/O requests, if any, have been completed. + * pagebuf_iostart calls the pagebuf_ioinitiate routine or + * pagebuf_iorequest, if the former routine is not defined, to start + * the I/O on a given low-level request. + */ +int +pagebuf_iostart( /* start I/O on a buffer */ + page_buf_t *pb, /* buffer to start */ + page_buf_flags_t flags) /* PBF_LOCK, PBF_ASYNC, PBF_READ, */ + /* PBF_WRITE, PBF_ALLOCATE, */ + /* PBF_DELWRI, */ + /* PBF_SYNC, PBF_DONT_BLOCK */ + /* PBF_RELEASE */ +{ + int status = 0; + + PB_TRACE(pb, PB_TRACE_REC(iostart), flags); + + if (flags & PBF_DELWRI) { + pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC); + pb->pb_flags |= flags & + (PBF_DELWRI | PBF_ASYNC | PBF_SYNC); + pagebuf_delwri_queue(pb, 1); + return status; + } + + pb->pb_flags &= ~(PBF_READ|PBF_WRITE|PBF_ASYNC|PBF_DELWRI|PBF_READ_AHEAD); + pb->pb_flags |= flags & (PBF_READ|PBF_WRITE|PBF_ASYNC|PBF_SYNC|PBF_READ_AHEAD); + + if (pb->pb_bn == PAGE_BUF_DADDR_NULL) { + BUG(); + } + + /* For writes call internal function which checks for + * filesystem specific callout function and execute it. + */ + if (flags & PBF_WRITE) { + status = __pagebuf_iorequest(pb); + } else { + status = pagebuf_iorequest(pb); + } + + /* Wait for I/O if we are not an async request */ + if ((status == 0) && (flags & PBF_ASYNC) == 0) { + status = pagebuf_iowait(pb); + } + + return status; +} + + +/* + * Helper routines for pagebuf_iorequest (pagebuf I/O completion) + * + * (different routines for locked/unlocked, and single/multi-bh pagebufs) + */ + +STATIC inline void +_pb_io_done( + page_buf_t *pb) +{ + if (atomic_dec_and_test(&PBP(pb)->pb_io_remaining) == 1) { + pb->pb_locked = 0; + pagebuf_iodone(pb); + } +} + +STATIC void +_end_pagebuf_page_io( + struct buffer_head *bh, + int uptodate, + int locked) +{ + struct page *page; + page_buf_t *pb = (page_buf_t *) bh->b_private; + + mark_buffer_uptodate(bh, uptodate); + atomic_dec(&bh->b_count); + + page = bh->b_page; + if (!test_bit(BH_Uptodate, &bh->b_state)) { + set_bit(PG_error, &page->flags); + pb->pb_error = EIO; + } + + unlock_buffer(bh); + _pagebuf_free_bh(bh); + + SetPageUptodate(page); + if (locked) + unlock_page(page); + _pb_io_done(pb); +} + +STATIC void +_end_io_locked( + struct buffer_head *bh, + int uptodate) +{ + _end_pagebuf_page_io(bh, uptodate, 1); +} + +STATIC void +_end_io_nolock( + struct buffer_head *bh, + int uptodate) +{ + _end_pagebuf_page_io(bh, uptodate, 0); +} + +typedef struct { + page_buf_t *pb; /* pointer to pagebuf page is within */ + int locking; /* are pages locked? */ + atomic_t remain; /* count of remaining I/O requests */ +} pagesync_t; + +STATIC void +_end_pagebuf_page_io_multi( + struct buffer_head *bh, + int uptodate, + int fullpage) +{ + pagesync_t *psync = (pagesync_t *) bh->b_private; + page_buf_t *pb = psync->pb; + struct page *page; + + mark_buffer_uptodate(bh, uptodate); + put_bh(bh); + + page = bh->b_page; + if (!test_bit(BH_Uptodate, &bh->b_state)) { + set_bit(PG_error, &page->flags); + pb->pb_error = EIO; + } + + unlock_buffer(bh); + if (fullpage) + _pagebuf_free_bh(bh); + + if (atomic_dec_and_test(&psync->remain) == 1) { + if (fullpage) + SetPageUptodate(page); + if (psync->locking) + unlock_page(page); + kfree(psync); + _pb_io_done(pb); + } +} + +STATIC void +_end_io_multi_full( + struct buffer_head *bh, + int uptodate) +{ + _end_pagebuf_page_io_multi(bh, uptodate, 1); +} + +STATIC void +_end_io_multi_part( + struct buffer_head *bh, + int uptodate) +{ + _end_pagebuf_page_io_multi(bh, uptodate, 0); +} + + +/* + * Initiate I/O on part of a page we are interested in + */ +STATIC int +_pagebuf_page_io( + struct page *page, /* Page structure we are dealing with */ + page_buf_t *pb, /* pagebuf holding it, can be NULL */ + page_buf_daddr_t bn, /* starting block number */ + kdev_t dev, /* device for I/O */ + size_t blocksize, /* filesystem block size */ + off_t pg_offset, /* starting offset in page */ + size_t pg_length, /* count of data to process */ + int locking, /* page locking in use */ + int rw, /* read/write operation */ + int flush) +{ + size_t sector; + size_t blk_length = 0; + struct buffer_head *bh, *head, *bufferlist[MAX_BUF_PER_PAGE]; + int multi_ok; + int i = 0, cnt = 0, err = 0; + int public_bh = 0; + + if ((blocksize < PAGE_CACHE_SIZE) && + !(pb->pb_flags & _PBF_PRIVATE_BH)) { + int cache_ok; + + cache_ok = !((pb->pb_flags & PBF_FORCEIO) || (rw == WRITE)); + public_bh = multi_ok = 1; + + if (!page_has_buffers(page)) { + if (!locking) { + lock_page(page); + if (!page_has_buffers(page)) { + create_empty_buffers(page, dev, + SECTOR_SIZE); + } + unlock_page(page); + } else { + create_empty_buffers(page, dev, SECTOR_SIZE); + } + } + + /* Find buffer_heads belonging to just this pagebuf */ + bh = head = page_buffers(page); + do { + if (buffer_uptodate(bh) && cache_ok) + continue; + blk_length = i << SECTOR_SHIFT; + if (blk_length < pg_offset) + continue; + if (blk_length >= pg_offset + pg_length) + break; + + lock_buffer(bh); + get_bh(bh); + ASSERT(!waitqueue_active(&bh->b_wait)); + + bh->b_size = SECTOR_SIZE; + bh->b_blocknr = bn + (i - (pg_offset >> SECTOR_SHIFT)); + bufferlist[cnt++] = bh; + } while (i++, (bh = bh->b_this_page) != head); + + goto request; + } + + /* Calculate the block offsets and length we will be using */ + if (pg_offset) { + size_t block_offset; + + block_offset = pg_offset >> SECTOR_SHIFT; + block_offset = pg_offset - (block_offset << SECTOR_SHIFT); + blk_length = (pg_length + block_offset + SECTOR_MASK) >> + SECTOR_SHIFT; + } else { + blk_length = (pg_length + SECTOR_MASK) >> SECTOR_SHIFT; + } + + /* This will attempt to make a request bigger than the sector + * size if we are well aligned. + */ + switch (pb->pb_target->pbr_flags) { + case 0: + sector = blk_length << SECTOR_SHIFT; + blk_length = 1; + break; + case PBR_ALIGNED_ONLY: + if ((pg_offset == 0) && (pg_length == PAGE_CACHE_SIZE) && + (((unsigned int) bn) & BN_ALIGN_MASK) == 0) { + sector = blk_length << SECTOR_SHIFT; + blk_length = 1; + break; + } + case PBR_SECTOR_ONLY: + /* Fallthrough, same as default */ + default: + sector = SECTOR_SIZE; + } + + /* The b_size field of struct buffer_head is an unsigned short + * ... we may need to split this request up. [64K is too big] + */ + while (sector > (((u64)1 << NBBY * sizeof(bh->b_size)) - 1)) { + sector >>= 1; + blk_length++; + } + + multi_ok = (blk_length != 1); + + for (; blk_length > 0; blk_length--, pg_offset += sector) { + bh = kmem_cache_alloc(bh_cachep, SLAB_NOFS); + if (!bh) { + bh = _pagebuf_get_prealloc_bh(); + if (!bh) { + /* This should never happen */ + err = -ENOMEM; + goto error; + } + } + memset(bh, 0, sizeof(*bh)); + bh->b_size = sector; + bh->b_blocknr = bn++; + bh->b_dev = dev; + set_bit(BH_Lock, &bh->b_state); + set_bh_page(bh, page, pg_offset); + init_waitqueue_head(&bh->b_wait); + atomic_set(&bh->b_count, 1); + bufferlist[cnt++] = bh; + } + +request: + if (cnt) { + pagesync_t *psync = NULL; + void (*callback)(struct buffer_head *, int); + + if (multi_ok) { + size_t size = sizeof(pagesync_t); + + psync = (pagesync_t *) kmalloc(size, GFP_NOFS); + if (!psync) + BUG(); /* Ugh - out of memory condition here */ + psync->pb = pb; + psync->locking = locking; + atomic_set(&psync->remain, cnt); + + callback = public_bh ? + _end_io_multi_part : _end_io_multi_full; + } else { + callback = locking ? _end_io_locked : _end_io_nolock; + } + + /* Indicate that there is another page in progress */ + atomic_inc(&PBP(pb)->pb_io_remaining); + +#ifdef RQ_WRITE_ORDERED + if (flush) + set_bit(BH_Ordered_Flush, &bufferlist[cnt-1]->b_state); +#endif + + for (i = 0; i < cnt; i++) { + bh = bufferlist[i]; + + /* Complete the buffer_head, then submit the IO */ + if (psync) { + init_buffer(bh, callback, psync); + } else { + init_buffer(bh, callback, pb); + } + + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr; + set_bit(BH_Mapped, &bh->b_state); + set_bit(BH_Req, &bh->b_state); + + if (rw == WRITE) { + set_bit(BH_Uptodate, &bh->b_state); + } + generic_make_request(rw, bh); + } + } else { + if (locking) + unlock_page(page); + } + + return err; +error: + /* If we ever do get here then clean up what we already did */ + for (i = 0; i < cnt; i++) { + atomic_set_buffer_clean(bufferlist[i]); + bufferlist[i]->b_end_io(bufferlist[i], 0); + } + return err; +} + +STATIC int +_page_buf_page_apply( + page_buf_t *pb, + loff_t offset, + struct page *page, + size_t pg_offset, + size_t pg_length, + int last) +{ + page_buf_daddr_t bn = pb->pb_bn; + kdev_t dev = pb->pb_target->pbr_kdev; + size_t blocksize = pb->pb_target->pbr_blocksize; + loff_t pb_offset; + size_t ret_len = pg_length; + + ASSERT(page); + + if ((blocksize == PAGE_CACHE_SIZE) && + (pb->pb_buffer_length < PAGE_CACHE_SIZE) && + (pb->pb_flags & PBF_READ) && pb->pb_locked) { + bn -= (pb->pb_offset >> SECTOR_SHIFT); + pg_offset = 0; + pg_length = PAGE_CACHE_SIZE; + } else { + pb_offset = offset - pb->pb_file_offset; + if (pb_offset) { + bn += (pb_offset + SECTOR_MASK) >> SECTOR_SHIFT; + } + } + + if (pb->pb_flags & PBF_READ) { + _pagebuf_page_io(page, pb, bn, dev, blocksize, + (off_t)pg_offset, pg_length, pb->pb_locked, READ, 0); + } else if (pb->pb_flags & PBF_WRITE) { + int locking = (pb->pb_flags & _PBF_LOCKABLE) == 0; + + /* Check we need to lock pages */ + if (locking && (pb->pb_locked == 0)) + lock_page(page); + _pagebuf_page_io(page, pb, bn, dev, blocksize, + (off_t)pg_offset, pg_length, locking, WRITE, + last && (pb->pb_flags & PBF_FLUSH)); + } + + return ret_len; +} + +/* + * pagebuf_iorequest + * + * pagebuf_iorequest is the core I/O request routine. + * It assumes that the buffer is well-formed and + * mapped and ready for physical I/O, unlike + * pagebuf_iostart() and pagebuf_iophysio(). Those + * routines call the pagebuf_ioinitiate routine to start I/O, + * if it is present, or else call pagebuf_iorequest() + * directly if the pagebuf_ioinitiate routine is not present. + * + * This function will be responsible for ensuring access to the + * pages is restricted whilst I/O is in progress - for locking + * pagebufs the pagebuf lock is the mediator, for non-locking + * pagebufs the pages will be locked. In the locking case we + * need to use the pagebuf lock as multiple meta-data buffers + * will reference the same page. + */ +int +pagebuf_iorequest( /* start real I/O */ + page_buf_t *pb) /* buffer to convey to device */ +{ + int status = 0; + + PB_TRACE(pb, PB_TRACE_REC(ioreq), 0); + + if (pb->pb_flags & PBF_DELWRI) { + pagebuf_delwri_queue(pb, 1); + return status; + } + + if (pb->pb_flags & PBF_WRITE) { + _pagebuf_wait_unpin(pb); + } + + /* Set the count to 1 initially, this will stop an I/O + * completion callout which happens before we have started + * all the I/O from calling iodone too early + */ + atomic_set(&PBP(pb)->pb_io_remaining, 1); + status = _pagebuf_segment_apply(pb); + + /* Drop our count and if everything worked we are done */ + if (atomic_dec_and_test(&PBP(pb)->pb_io_remaining) == 1) { + pagebuf_iodone(pb); + } else if ((pb->pb_flags & (PBF_SYNC|PBF_ASYNC)) == PBF_SYNC) { + run_task_queue(&tq_disk); + } + + return status < 0 ? status : 0; +} + +/* + * pagebuf_iowait + * + * pagebuf_iowait waits for I/O to complete on the buffer supplied. + * It returns immediately if no I/O is pending. In any case, it returns + * the error code, if any, or 0 if there is no error. + */ +int +pagebuf_iowait( + page_buf_t *pb) +{ + PB_TRACE(pb, PB_TRACE_REC(iowait), 0); + run_task_queue(&tq_disk); + down(&pb->pb_iodonesema); + PB_TRACE(pb, PB_TRACE_REC(iowaited), (int)pb->pb_error); + return pb->pb_error; +} + +STATIC void * +pagebuf_mapout_locked( + page_buf_t *pb) +{ + void *old_addr = NULL; + + if (pb->pb_flags & PBF_MAPPED) { + if (pb->pb_flags & _PBF_ADDR_ALLOCATED) + old_addr = pb->pb_addr - pb->pb_offset; + pb->pb_addr = NULL; + pb->pb_flags &= ~(PBF_MAPPED | _PBF_ADDR_ALLOCATED); + } + + return old_addr; /* Caller must free the address space, + * we are under a spin lock, probably + * not safe to do vfree here + */ +} + +caddr_t +pagebuf_offset( + page_buf_t *pb, + off_t offset) +{ + struct page *page; + + offset += pb->pb_offset; + + page = pb->pb_pages[offset >> PAGE_CACHE_SHIFT]; + return (caddr_t) page_address(page) + (offset & (PAGE_CACHE_SIZE - 1)); +} + +/* + * pagebuf_segment + * + * pagebuf_segment is used to retrieve the various contiguous + * segments of a buffer. The variable addressed by the + * loff_t * should be initialized to 0, and successive + * calls will update to point to the segment following the one + * returned. + */ +STATIC void +pagebuf_segment( + page_buf_t *pb, /* buffer to examine */ + loff_t *boff_p,/* offset in buffer of next */ + /* next segment (updated) */ + struct page **spage_p, /* page (updated) */ + /* (NULL if not in page array) */ + size_t *soff_p,/* offset in page (updated) */ + size_t *ssize_p) /* segment length (updated) */ +{ + loff_t kpboff; /* offset in pagebuf */ + int kpi; /* page index in pagebuf */ + size_t slen; /* segment length */ + + kpboff = *boff_p; + + kpi = page_buf_btoct(kpboff + pb->pb_offset); + + *spage_p = pb->pb_pages[kpi]; + + *soff_p = page_buf_poff(kpboff + pb->pb_offset); + slen = PAGE_CACHE_SIZE - *soff_p; + if (slen > (pb->pb_count_desired - kpboff)) + slen = (pb->pb_count_desired - kpboff); + *ssize_p = slen; + + *boff_p = *boff_p + slen; +} + +/* + * pagebuf_iomove + * + * Move data into or out of a buffer. + */ +void +pagebuf_iomove( + page_buf_t *pb, /* buffer to process */ + off_t boff, /* starting buffer offset */ + size_t bsize, /* length to copy */ + caddr_t data, /* data address */ + page_buf_rw_t mode) /* read/write flag */ +{ + loff_t cboff; + size_t cpoff; + size_t csize; + struct page *page; + + cboff = boff; + boff += bsize; /* last */ + + while (cboff < boff) { + pagebuf_segment(pb, &cboff, &page, &cpoff, &csize); + ASSERT(((csize + cpoff) <= PAGE_CACHE_SIZE)); + + switch (mode) { + case PBRW_ZERO: + memset(page_address(page) + cpoff, 0, csize); + break; + case PBRW_READ: + memcpy(data, page_address(page) + cpoff, csize); + break; + case PBRW_WRITE: + memcpy(page_address(page) + cpoff, data, csize); + } + + data += csize; + } +} + +/* + * _pagebuf_segment_apply + * + * Applies _page_buf_page_apply to each segment of the page_buf_t. + */ +STATIC int +_pagebuf_segment_apply( /* apply function to segments */ + page_buf_t *pb) /* buffer to examine */ +{ + int buf_index, sval, status = 0; + loff_t buffer_offset = pb->pb_file_offset; + size_t buffer_len = pb->pb_count_desired; + size_t page_offset, len, total = 0; + size_t cur_offset, cur_len; + + pagebuf_hold(pb); + + cur_offset = pb->pb_offset; + cur_len = buffer_len; + + for (buf_index = 0; buf_index < pb->pb_page_count; buf_index++) { + if (cur_len == 0) + break; + if (cur_offset >= PAGE_CACHE_SIZE) { + cur_offset -= PAGE_CACHE_SIZE; + continue; + } + + page_offset = cur_offset; + cur_offset = 0; + + len = PAGE_CACHE_SIZE - page_offset; + if (len > cur_len) + len = cur_len; + cur_len -= len; + + sval = _page_buf_page_apply(pb, buffer_offset, + pb->pb_pages[buf_index], page_offset, len, + buf_index+1 == pb->pb_page_count); + if (sval <= 0) { + status = sval; + break; + } else { + len = sval; + total += len; + } + + buffer_offset += len; + buffer_len -= len; + } + + pagebuf_rele(pb); + + if (!status) + status = total; + + return (status); +} + + +/* + * Pagebuf delayed write buffer handling + */ + +void +pagebuf_delwri_queue( + page_buf_t *pb, + int unlock) +{ + PB_TRACE(pb, PB_TRACE_REC(delwri_q), unlock); + spin_lock(&pb_daemon->pb_delwrite_lock); + /* If already in the queue, dequeue and place at tail */ + if (!list_empty(&pb->pb_list)) { + if (unlock) { + atomic_dec(&pb->pb_hold); + } + list_del(&pb->pb_list); + } else { + pb_daemon->pb_delwri_cnt++; + } + list_add_tail(&pb->pb_list, &pb_daemon->pb_delwrite_l); + PBP(pb)->pb_flushtime = jiffies + pb_params.p_un.age_buffer; + spin_unlock(&pb_daemon->pb_delwrite_lock); + + if (unlock && (pb->pb_flags & _PBF_LOCKABLE)) { + pagebuf_unlock(pb); + } +} + +void +pagebuf_delwri_dequeue( + page_buf_t *pb) +{ + PB_TRACE(pb, PB_TRACE_REC(delwri_uq), 0); + spin_lock(&pb_daemon->pb_delwrite_lock); + list_del_init(&pb->pb_list); + pb->pb_flags &= ~PBF_DELWRI; + pb_daemon->pb_delwri_cnt--; + spin_unlock(&pb_daemon->pb_delwrite_lock); +} + + +/* + * The pagebuf iodone daemon + */ + +STATIC int pb_daemons[NR_CPUS]; + +STATIC int +pagebuf_iodone_daemon( + void *__bind_cpu) +{ + int bind_cpu = (int) (long) __bind_cpu; + int cpu = cpu_logical_map(bind_cpu); + DECLARE_WAITQUEUE (wait, current); + + /* Set up the thread */ + daemonize(); + + /* Avoid signals */ + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + /* Migrate to the right CPU */ +#ifdef __HAVE_NEW_SCHEDULER + set_cpus_allowed(current, 1UL << cpu); + if (smp_processor_id() != cpu) + BUG(); +#else + current->cpus_allowed = 1UL << cpu; + while (smp_processor_id() != cpu) + schedule(); +#endif + + sprintf(current->comm, "pagebuf_%d", bind_cpu); + INIT_LIST_HEAD(&pagebuf_iodone_tq[cpu]); + init_waitqueue_head(&pagebuf_iodone_wait[cpu]); + __set_current_state(TASK_INTERRUPTIBLE); + mb(); + + pb_daemons[cpu] = 1; + + for (;;) { + add_wait_queue(&pagebuf_iodone_wait[cpu], + &wait); + + if (TQ_ACTIVE(pagebuf_iodone_tq[cpu])) + __set_task_state(current, TASK_RUNNING); + schedule(); + remove_wait_queue(&pagebuf_iodone_wait[cpu], + &wait); + run_task_queue(&pagebuf_iodone_tq[cpu]); + if (pb_daemons[cpu] == 0) + break; + __set_current_state(TASK_INTERRUPTIBLE); + } + + pb_daemons[cpu] = -1; + wake_up_interruptible(&pagebuf_iodone_wait[cpu]); + return 0; +} + +/* Defines for pagebuf daemon */ +DECLARE_WAIT_QUEUE_HEAD(pbd_waitq); +STATIC int force_flush; + +STATIC void +pagebuf_daemon_wakeup( + int flag) +{ + force_flush = flag; + if (waitqueue_active(&pbd_waitq)) { + wake_up_interruptible(&pbd_waitq); + } +} + +typedef void (*timeout_fn)(unsigned long); + +STATIC int +pagebuf_daemon( + void *data) +{ + int count; + page_buf_t *pb; + struct list_head *curr, *next, tmp; + struct timer_list pb_daemon_timer = + { {NULL, NULL}, 0, 0, (timeout_fn)pagebuf_daemon_wakeup }; + + /* Set up the thread */ + daemonize(); + + /* Avoid signals */ + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + strcpy(current->comm, "pagebufd"); + current->flags |= PF_MEMALLOC; + + INIT_LIST_HEAD(&tmp); + do { + if (pb_daemon->active == 1) { + del_timer(&pb_daemon_timer); + pb_daemon_timer.expires = jiffies + + pb_params.p_un.flush_interval; + add_timer(&pb_daemon_timer); + interruptible_sleep_on(&pbd_waitq); + } + + if (pb_daemon->active == 0) { + del_timer(&pb_daemon_timer); + } + + spin_lock(&pb_daemon->pb_delwrite_lock); + + count = 0; + list_for_each_safe(curr, next, &pb_daemon->pb_delwrite_l) { + pb = list_entry(curr, page_buf_t, pb_list); + + PB_TRACE(pb, PB_TRACE_REC(walkq1), pagebuf_ispin(pb)); + + if ((pb->pb_flags & PBF_DELWRI) && !pagebuf_ispin(pb) && + (((pb->pb_flags & _PBF_LOCKABLE) == 0) || + !pagebuf_cond_lock(pb))) { + + if (!force_flush && time_before(jiffies, + PBP(pb)->pb_flushtime)) { + pagebuf_unlock(pb); + break; + } + + list_del(&pb->pb_list); + list_add(&pb->pb_list, &tmp); + + count++; + } + } + + spin_unlock(&pb_daemon->pb_delwrite_lock); + while (!list_empty(&tmp)) { + pb = list_entry(tmp.next, + page_buf_t, pb_list); + list_del_init(&pb->pb_list); + pb->pb_flags &= ~PBF_DELWRI; + pb->pb_flags |= PBF_WRITE; + + __pagebuf_iorequest(pb); + } + + if (count) + run_task_queue(&tq_disk); + if (as_list_len > 0) + purge_addresses(); + + force_flush = 0; + } while (pb_daemon->active == 1); + + pb_daemon->active = -1; + wake_up_interruptible(&pbd_waitq); + + return 0; +} + +void +pagebuf_delwri_flush( + pb_target_t *target, + u_long flags, + int *pinptr) +{ + page_buf_t *pb; + struct list_head *curr, *next, tmp; + int pincount = 0; + + spin_lock(&pb_daemon->pb_delwrite_lock); + INIT_LIST_HEAD(&tmp); + + list_for_each_safe(curr, next, &pb_daemon->pb_delwrite_l) { + pb = list_entry(curr, page_buf_t, pb_list); + + /* + * Skip other targets, markers and in progress buffers + */ + + if ((pb->pb_flags == 0) || (pb->pb_target != target) || + !(pb->pb_flags & PBF_DELWRI)) { + continue; + } + + PB_TRACE(pb, PB_TRACE_REC(walkq2), pagebuf_ispin(pb)); + if (pagebuf_ispin(pb)) { + pincount++; + continue; + } + + if (flags & PBDF_TRYLOCK) { + if (!pagebuf_cond_lock(pb)) { + pincount++; + continue; + } + } + + list_del_init(&pb->pb_list); + if (flags & PBDF_WAIT) { + list_add(&pb->pb_list, &tmp); + pb->pb_flags &= ~PBF_ASYNC; + } + + spin_unlock(&pb_daemon->pb_delwrite_lock); + + if ((flags & PBDF_TRYLOCK) == 0) { + pagebuf_lock(pb); + } + + pb->pb_flags &= ~PBF_DELWRI; + pb->pb_flags |= PBF_WRITE; + + __pagebuf_iorequest(pb); + + spin_lock(&pb_daemon->pb_delwrite_lock); + } + + spin_unlock(&pb_daemon->pb_delwrite_lock); + + run_task_queue(&tq_disk); + + if (pinptr) + *pinptr = pincount; + + if ((flags & PBDF_WAIT) == 0) + return; + + while (!list_empty(&tmp)) { + pb = list_entry(tmp.next, page_buf_t, pb_list); + + list_del_init(&pb->pb_list); + pagebuf_iowait(pb); + if (!pb->pb_relse) + pagebuf_unlock(pb); + pagebuf_rele(pb); + } +} + +STATIC int +pagebuf_daemon_start(void) +{ + if (!pb_daemon) { + int cpu; + + pb_daemon = (pagebuf_daemon_t *) + kmalloc(sizeof(pagebuf_daemon_t), GFP_KERNEL); + if (!pb_daemon) { + return -1; /* error */ + } + + pb_daemon->active = 1; + pb_daemon->io_active = 1; + pb_daemon->pb_delwri_cnt = 0; + pb_daemon->pb_delwrite_lock = SPIN_LOCK_UNLOCKED; + + INIT_LIST_HEAD(&pb_daemon->pb_delwrite_l); + + kernel_thread(pagebuf_daemon, (void *)pb_daemon, + CLONE_FS|CLONE_FILES|CLONE_VM); + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (kernel_thread(pagebuf_iodone_daemon, + (void *)(long) cpu, + CLONE_FS|CLONE_FILES|CLONE_VM) < 0) { + printk("pagebuf_daemon_start failed\n"); + } else { + while (!pb_daemons[cpu_logical_map(cpu)]) { +#ifdef __HAVE_NEW_SCHEDULER + yield(); +#else + current->policy |= SCHED_YIELD; + schedule(); +#endif + } + } + } + } + return 0; +} + +/* + * pagebuf_daemon_stop + * + * Note: do not mark as __exit, it is called from pagebuf_terminate. + */ +STATIC void +pagebuf_daemon_stop(void) +{ + if (pb_daemon) { + int cpu; + + pb_daemon->active = 0; + pb_daemon->io_active = 0; + + wake_up_interruptible(&pbd_waitq); + while (pb_daemon->active == 0) { + interruptible_sleep_on(&pbd_waitq); + } + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + pb_daemons[cpu_logical_map(cpu)] = 0; + wake_up(&pagebuf_iodone_wait[cpu_logical_map(cpu)]); + while (pb_daemons[cpu_logical_map(cpu)] != -1) { + interruptible_sleep_on( + &pagebuf_iodone_wait[cpu_logical_map(cpu)]); + } + } + + kfree(pb_daemon); + pb_daemon = NULL; + } +} + + +/* + * Pagebuf sysctl interface + */ + +STATIC int +pb_stats_clear_handler( + ctl_table *ctl, + int write, + struct file *filp, + void *buffer, + size_t *lenp) +{ + int ret; + int *valp = ctl->data; + + ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp); + + if (!ret && write && *valp) { + printk("XFS Clearing pbstats\n"); + memset(&pbstats, 0, sizeof(pbstats)); + pb_params.p_un.stats_clear = 0; + } + + return ret; +} + +STATIC struct ctl_table_header *pagebuf_table_header; + +STATIC ctl_table pagebuf_table[] = { + {PB_FLUSH_INT, "flush_int", &pb_params.data[0], + sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, + &sysctl_intvec, NULL, &pagebuf_min[0], &pagebuf_max[0]}, + + {PB_FLUSH_AGE, "flush_age", &pb_params.data[1], + sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, + &sysctl_intvec, NULL, &pagebuf_min[1], &pagebuf_max[1]}, + + {PB_STATS_CLEAR, "stats_clear", &pb_params.data[2], + sizeof(ulong), 0644, NULL, &pb_stats_clear_handler, + &sysctl_intvec, NULL, &pagebuf_min[2], &pagebuf_max[2]}, + +#ifdef PAGEBUF_TRACE + {PB_DEBUG, "debug", &pb_params.data[3], + sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, + &sysctl_intvec, NULL, &pagebuf_min[3], &pagebuf_max[3]}, +#endif + {0} +}; + +STATIC ctl_table pagebuf_dir_table[] = { + {VM_PAGEBUF, "pagebuf", NULL, 0, 0555, pagebuf_table}, + {0} +}; + +STATIC ctl_table pagebuf_root_table[] = { + {CTL_VM, "vm", NULL, 0, 0555, pagebuf_dir_table}, + {0} +}; + +#ifdef CONFIG_PROC_FS +STATIC int +pagebuf_readstats( + char *buffer, + char **start, + off_t offset, + int count, + int *eof, + void *data) +{ + int i, len; + + len = 0; + len += sprintf(buffer + len, "pagebuf"); + for (i = 0; i < sizeof(pbstats) / sizeof(u_int32_t); i++) { + len += sprintf(buffer + len, " %u", + *(((u_int32_t*)&pbstats) + i)); + } + buffer[len++] = '\n'; + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} +#endif /* CONFIG_PROC_FS */ + +STATIC void +pagebuf_shaker(void) +{ + pagebuf_daemon_wakeup(1); +} + + +/* + * Initialization and Termination + */ + +int __init +pagebuf_init(void) +{ + int i; + + pagebuf_table_header = register_sysctl_table(pagebuf_root_table, 1); + +#ifdef CONFIG_PROC_FS + if (proc_mkdir("fs/pagebuf", 0)) + create_proc_read_entry( + "fs/pagebuf/stat", 0, 0, pagebuf_readstats, NULL); +#endif + + pagebuf_cache = kmem_cache_create("page_buf_t", + sizeof(page_buf_private_t), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (pagebuf_cache == NULL) { + printk("pagebuf: couldn't init pagebuf cache\n"); + pagebuf_terminate(); + return -ENOMEM; + } + + if (_pagebuf_prealloc_bh(NR_RESERVED_BH) < NR_RESERVED_BH) { + printk("pagebuf: couldn't pre-allocate %d buffer heads\n", + NR_RESERVED_BH); + pagebuf_terminate(); + return -ENOMEM; + } + + init_waitqueue_head(&pb_resv_bh_wait); + + for (i = 0; i < NHASH; i++) { + spin_lock_init(&pbhash[i].pb_hash_lock); + INIT_LIST_HEAD(&pbhash[i].pb_hash); + } + +#ifdef PAGEBUF_TRACE +# if 1 + pb_trace.buf = (pagebuf_trace_t *)kmalloc( + PB_TRACE_BUFSIZE * sizeof(pagebuf_trace_t), GFP_KERNEL); +# else + /* Alternatively, for really really long trace bufs */ + pb_trace.buf = (pagebuf_trace_t *)vmalloc( + PB_TRACE_BUFSIZE * sizeof(pagebuf_trace_t)); +# endif + memset(pb_trace.buf, 0, PB_TRACE_BUFSIZE * sizeof(pagebuf_trace_t)); + pb_trace.start = 0; + pb_trace.end = PB_TRACE_BUFSIZE - 1; +#endif + + pagebuf_daemon_start(); + kmem_shake_register(pagebuf_shaker); + return 0; +} + +/* + * pagebuf_terminate. + * + * Note: do not mark as __exit, this is also called from the __init code. + */ +void +pagebuf_terminate(void) +{ + pagebuf_daemon_stop(); + + kmem_cache_destroy(pagebuf_cache); + kmem_shake_deregister(pagebuf_shaker); + + unregister_sysctl_table(pagebuf_table_header); +#ifdef CONFIG_PROC_FS + remove_proc_entry("fs/pagebuf/stat", NULL); + remove_proc_entry("fs/pagebuf", NULL); +#endif +} + + +/* + * Module management (for kernel debugger module) + */ +EXPORT_SYMBOL(pagebuf_offset); diff -Nur linux-2.4.19/fs/xfs/pagebuf/page_buf.h linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf.h --- linux-2.4.19/fs/xfs/pagebuf/page_buf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Written by Steve Lord, Jim Mostek, Russell Cattelan at SGI + */ + +#ifndef __PAGE_BUF_H__ +#define __PAGE_BUF_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Turn this on to get pagebuf lock ownership +#define PAGEBUF_LOCK_TRACKING +*/ + +/* + * Base types + */ + +/* daddr must be signed since -1 is used for bmaps that are not yet allocated */ +typedef loff_t page_buf_daddr_t; + +#define PAGE_BUF_DADDR_NULL ((page_buf_daddr_t) (-1LL)) + +typedef size_t page_buf_dsize_t; /* size of buffer in blocks */ + +#define page_buf_ctob(pp) ((pp) * PAGE_CACHE_SIZE) +#define page_buf_btoc(dd) (((dd) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) +#define page_buf_btoct(dd) ((dd) >> PAGE_CACHE_SHIFT) +#define page_buf_poff(aa) ((aa) & ~PAGE_CACHE_MASK) + +typedef enum page_buf_rw_e { + PBRW_READ = 1, /* transfer into target memory */ + PBRW_WRITE = 2, /* transfer from target memory */ + PBRW_ZERO = 3 /* Zero target memory */ +} page_buf_rw_t; + +typedef enum { /* pbm_flags values */ + PBMF_EOF = 0x01, /* mapping contains EOF */ + PBMF_HOLE = 0x02, /* mapping covers a hole */ + PBMF_DELAY = 0x04, /* mapping covers delalloc region */ + PBMF_UNWRITTEN = 0x20 /* mapping covers allocated */ + /* but uninitialized XFS data */ +} bmap_flags_t; + +typedef enum page_buf_flags_e { /* pb_flags values */ + PBF_READ = (1 << 0), /* buffer intended for reading from device */ + PBF_WRITE = (1 << 1), /* buffer intended for writing to device */ + PBF_MAPPED = (1 << 2), /* buffer mapped (pb_addr valid) */ + PBF_PARTIAL = (1 << 3), /* buffer partially read */ + PBF_ASYNC = (1 << 4), /* initiator will not wait for completion */ + PBF_NONE = (1 << 5), /* buffer not read at all */ + PBF_DELWRI = (1 << 6), /* buffer has dirty pages */ + PBF_FREED = (1 << 7), /* buffer has been freed and is invalid */ + PBF_SYNC = (1 << 8), /* force updates to disk */ + PBF_MAPPABLE = (1 << 9),/* use directly-addressable pages */ + PBF_STALE = (1 << 10), /* buffer has been staled, do not find it */ + PBF_FS_MANAGED = (1 << 11), /* filesystem controls freeing memory */ + PBF_RELEASE = (1 << 12),/* buffer to be released after I/O is done */ + + /* flags used only as arguments to access routines */ + PBF_LOCK = (1 << 13), /* lock requested */ + PBF_TRYLOCK = (1 << 14), /* lock requested, but do not wait */ + PBF_ALLOCATE = (1 << 15), /* allocate all pages (UNUSED) */ + PBF_FILE_ALLOCATE = (1 << 16), /* allocate all file space */ + PBF_DONT_BLOCK = (1 << 17), /* do not block in current thread */ + PBF_DIRECT = (1 << 18), /* direct I/O desired */ + PBF_ENTER_PAGES = (1 << 21), /* create invalid pages for all */ + /* pages in the range of the buffer */ + /* not already associated with buffer */ + + /* flags used only internally */ + _PBF_LOCKABLE = (1 << 19), /* page_buf_t may be locked */ + _PBF_PRIVATE_BH = (1 << 20), /* do not use public buffer heads */ + _PBF_ALL_PAGES_MAPPED = (1 << 22), + /* all pages in rage are mapped */ + _PBF_SOME_INVALID_PAGES = (1 << 23), + /* some mapped pages are not valid */ + _PBF_ADDR_ALLOCATED = (1 << 24), + /* pb_addr space was allocated */ + _PBF_MEM_ALLOCATED = (1 << 25), + /* pb_mem and underlying pages allocated */ + + PBF_FORCEIO = (1 << 27), + PBF_FLUSH = (1 << 28), /* flush disk write cache */ + PBF_READ_AHEAD = (1 << 29), + PBF_FS_RESERVED_3 = (1 << 31) /* reserved (XFS use: XFS_B_STALE) */ + +} page_buf_flags_t; + +#define PBF_UPDATE (PBF_READ | PBF_WRITE) +#define PBF_NOT_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) != 0) +#define PBF_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) == 0) + +#define PBR_SECTOR_ONLY 1 /* only use sector size buffer heads */ +#define PBR_ALIGNED_ONLY 2 /* only use aligned I/O */ + +typedef struct pb_target { + int pbr_flags; + dev_t pbr_dev; + kdev_t pbr_kdev; + struct block_device *pbr_bdev; + struct address_space *pbr_mapping; + unsigned int pbr_blocksize; + unsigned int pbr_blocksize_bits; +} pb_target_t; + +/* + * page_buf_bmap_t: File system I/O map + * + * The pbm_bn, pbm_offset and pbm_length fields are expressed in disk blocks. + * The pbm_length field specifies the size of the underlying backing store + * for the particular mapping. + * + * The pbm_bsize, pbm_size and pbm_delta fields are in bytes and indicate + * the size of the mapping, the number of bytes that are valid to access + * (read or write), and the offset into the mapping, given the offset + * supplied to the file I/O map routine. pbm_delta is the offset of the + * desired data from the beginning of the mapping. + * + * When a request is made to read beyond the logical end of the object, + * pbm_size may be set to 0, but pbm_offset and pbm_length should be set to + * the actual amount of underlying storage that has been allocated, if any. + */ + +typedef struct page_buf_bmap_s { + page_buf_daddr_t pbm_bn; /* block number in file system */ + pb_target_t *pbm_target; /* device to do I/O to */ + loff_t pbm_offset; /* byte offset of mapping in file */ + size_t pbm_delta; /* offset of request into bmap */ + size_t pbm_bsize; /* size of this mapping in bytes */ + bmap_flags_t pbm_flags; /* options flags for mapping */ +} page_buf_bmap_t; + +typedef page_buf_bmap_t pb_bmap_t; + + +/* + * page_buf_t: Buffer structure for page cache-based buffers + * + * This buffer structure is used by the page cache buffer management routines + * to refer to an assembly of pages forming a logical buffer. The actual + * I/O is performed with buffer_head or bio structures, as required by drivers, + * for drivers which do not understand this structure. The buffer structure is + * used on temporary basis only, and discarded when released. + * + * The real data storage is recorded in the page cache. Metadata is + * hashed to the inode for the block device on which the file system resides. + * File data is hashed to the inode for the file. Pages which are only + * partially filled with data have bits set in their block_map entry + * to indicate which disk blocks in the page are not valid. + */ + +struct page_buf_s; +typedef void (*page_buf_iodone_t)(struct page_buf_s *); + /* call-back function on I/O completion */ +typedef void (*page_buf_relse_t)(struct page_buf_s *); + /* call-back function on I/O completion */ +typedef int (*page_buf_bdstrat_t)(struct page_buf_s *); + +#define PB_PAGES 4 + +typedef struct page_buf_s { + struct list_head pb_list; + page_buf_flags_t pb_flags; /* status flags */ + struct list_head pb_hash_list; + struct pb_target *pb_target; /* logical object */ + atomic_t pb_hold; /* reference count */ + page_buf_daddr_t pb_bn; /* block number for I/O */ + loff_t pb_file_offset; /* offset in file */ + size_t pb_buffer_length; /* size of buffer in bytes */ + size_t pb_count_desired; /* desired transfer size */ + void *pb_addr; /* virtual address of buffer */ + struct tq_struct pb_iodone_sched; + page_buf_iodone_t pb_iodone; /* I/O completion function */ + page_buf_relse_t pb_relse; /* releasing function */ + page_buf_bdstrat_t pb_strat; /* pre-write function */ + struct semaphore pb_iodonesema; /* Semaphore for I/O waiters */ + void *pb_fspriv; + void *pb_fspriv2; + void *pb_fspriv3; + unsigned short pb_error; /* error code on I/O */ + unsigned short pb_page_count; /* size of page array */ + unsigned short pb_offset; /* page offset in first page */ + unsigned char pb_locked; /* page array is locked */ + unsigned char pb_hash_index; /* hash table index */ + struct page **pb_pages; /* array of page pointers */ + struct page *pb_page_array[PB_PAGES]; /* inline pages */ +} page_buf_t; + + +/* + * page_buf module entry points + */ + +/* Finding and Reading Buffers */ + +extern page_buf_t *pagebuf_find( /* find buffer for block if */ + /* the block is in memory */ + struct pb_target *, /* inode for block */ + loff_t, /* starting offset of range */ + size_t, /* length of range */ + page_buf_flags_t); /* PBF_LOCK */ + +extern page_buf_t *pagebuf_get( /* allocate a buffer */ + struct pb_target *, /* inode for buffer */ + loff_t, /* starting offset of range */ + size_t, /* length of range */ + page_buf_flags_t); /* PBF_LOCK, PBF_READ, PBF_ALLOCATE, */ + /* PBF_ASYNC, */ + +extern page_buf_t *pagebuf_lookup( + struct pb_target *, + struct inode *, + loff_t, /* starting offset of range */ + size_t, /* length of range */ + int); /* PBF_ENTER_PAGES */ + +extern page_buf_t *pagebuf_get_empty( /* allocate pagebuf struct with */ + /* no memory or disk address */ + struct pb_target *); /* mount point "fake" inode */ + +extern page_buf_t *pagebuf_get_no_daddr(/* allocate pagebuf struct */ + /* without disk address */ + size_t len, + struct pb_target *); /* mount point "fake" inode */ + +extern int pagebuf_associate_memory( + page_buf_t *, + void *, + size_t); + + +extern void pagebuf_hold( /* increment reference count */ + page_buf_t *); /* buffer to hold */ + +extern void pagebuf_readahead( /* read ahead into cache */ + struct pb_target *, /* target for buffer (or NULL) */ + loff_t, /* starting offset of range */ + size_t, /* length of range */ + int); /* additional read flags */ + +/* Writing and Releasing Buffers */ + +extern void pagebuf_free( /* deallocate a buffer */ + page_buf_t *); /* buffer to deallocate */ + +extern void pagebuf_rele( /* release hold on a buffer */ + page_buf_t *); /* buffer to release */ + +/* Locking and Unlocking Buffers */ + +extern int pagebuf_cond_lock( /* lock buffer, if not locked */ + /* (returns -EBUSY if locked) */ + page_buf_t *); /* buffer to lock */ + +extern int pagebuf_lock_value( /* return count on lock */ + page_buf_t *); /* buffer to check */ + +extern int pagebuf_lock( /* lock buffer */ + page_buf_t *); /* buffer to lock */ + +extern void pagebuf_lock_disable( /* disable buffer locking */ + struct pb_target *, /* inode for buffers */ + int); /* do blkdev_put? */ + +extern struct pb_target *pagebuf_lock_enable( + dev_t, + int); /* do blkdev_get? */ + +extern void pagebuf_target_blocksize( + pb_target_t *, + unsigned int); /* block size */ + +extern void pagebuf_target_clear(struct pb_target *); + +extern void pagebuf_unlock( /* unlock buffer */ + page_buf_t *); /* buffer to unlock */ + +/* Buffer Utility Routines */ +static inline int pagebuf_geterror(page_buf_t *pb) +{ + return (pb ? pb->pb_error : ENOMEM); +} + +extern void pagebuf_queue_task( + struct tq_struct *); + +extern void pagebuf_iodone( /* mark buffer I/O complete */ + page_buf_t *); /* buffer to mark */ + +extern void pagebuf_ioerror( /* mark buffer in error (or not) */ + page_buf_t *, /* buffer to mark */ + unsigned int); /* error to store (0 if none) */ + +extern int pagebuf_iostart( /* start I/O on a buffer */ + page_buf_t *, /* buffer to start */ + page_buf_flags_t); /* PBF_LOCK, PBF_ASYNC, PBF_READ, */ + /* PBF_WRITE, PBF_ALLOCATE, */ + /* PBF_DELWRI, */ + /* PBF_SYNC */ + +extern int pagebuf_iorequest( /* start real I/O */ + page_buf_t *); /* buffer to convey to device */ + + /* + * pagebuf_iorequest is the core I/O request routine. + * It assumes that the buffer is well-formed and + * mapped and ready for physical I/O, unlike + * pagebuf_iostart() and pagebuf_iophysio(). Those + * routines call the inode pagebuf_ioinitiate routine to start I/O, + * if it is present, or else call pagebuf_iorequest() + * directly if the inode pagebuf_ioinitiate routine is not present. + */ + +extern int pagebuf_iowait( /* wait for buffer I/O done */ + page_buf_t *); /* buffer to wait on */ + +extern caddr_t pagebuf_offset(page_buf_t *, off_t); + +extern void pagebuf_iomove( /* move data in/out of pagebuf */ + page_buf_t *, /* buffer to manipulate */ + off_t, /* starting buffer offset */ + size_t, /* length in buffer */ + caddr_t, /* data pointer */ + page_buf_rw_t); /* direction */ + +/* Pinning Buffer Storage in Memory */ + +extern void pagebuf_pin( /* pin buffer in memory */ + page_buf_t *); /* buffer to pin */ + +extern void pagebuf_unpin( /* unpin buffered data */ + page_buf_t *); /* buffer to unpin */ + +extern int pagebuf_ispin( page_buf_t *); /* check if pagebuf is pinned */ + +/* Reading and writing pages */ + +extern int pagebuf_write_full_page( /* write a page via pagebuf */ + struct page *, /* page to write */ + int delalloc); /* delalloc bh present */ + +extern int pagebuf_release_page( /* Attempt to convert a delalloc page */ + struct page *); /* page to release */ + +extern void pagebuf_delwri_queue(page_buf_t *, int); +extern void pagebuf_delwri_dequeue(page_buf_t *); + +#define PBDF_WAIT 0x01 +#define PBDF_TRYLOCK 0x02 +extern void pagebuf_delwri_flush( + struct pb_target *, + unsigned long, + int *); + +extern int pagebuf_init(void); +extern void pagebuf_terminate(void); + +static __inline__ int __pagebuf_iorequest(page_buf_t *pb) +{ + if (pb->pb_strat) + return pb->pb_strat(pb); + return pagebuf_iorequest(pb); +} + +#endif /* __PAGE_BUF_H__ */ diff -Nur linux-2.4.19/fs/xfs/pagebuf/page_buf_internal.h linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf_internal.h --- linux-2.4.19/fs/xfs/pagebuf/page_buf_internal.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf_internal.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Written by Steve Lord at SGI + */ + +#ifndef __PAGE_BUF_PRIVATE_H__ +#define __PAGE_BUF_PRIVATE_H__ + +#include "page_buf.h" + +#define _PAGE_BUF_INTERNAL_ +#define PB_DEFINE_TRACES +#include "page_buf_trace.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,9) +#define page_buffers(page) ((page)->buffers) +#define page_has_buffers(page) ((page)->buffers) +#endif + +typedef struct page_buf_private_s { + page_buf_t pb_common; /* public part of structure */ + struct semaphore pb_sema; /* semaphore for lockables */ + unsigned long pb_flushtime; /* time to flush pagebuf */ + atomic_t pb_io_remaining;/* #outstanding I/O requests */ + atomic_t pb_pin_count; /* pin count */ + wait_queue_head_t pb_waiters; /* unpin waiters */ +#ifdef PAGEBUF_LOCK_TRACKING + int pb_last_holder; +#endif +} page_buf_private_t; + +#define PBC(pb) (&((pb)->pb_common)) +#define PBP(pb) ((page_buf_private_t *) (pb)) + +#ifdef PAGEBUF_LOCK_TRACKING +#define PB_SET_OWNER(pb) (PBP(pb)->pb_last_holder = current->pid) +#define PB_CLEAR_OWNER(pb) (PBP(pb)->pb_last_holder = -1) +#define PB_GET_OWNER(pb) (PBP(pb)->pb_last_holder) +#else +#define PB_SET_OWNER(pb) +#define PB_CLEAR_OWNER(pb) +#define PB_GET_OWNER(pb) +#endif /* PAGEBUF_LOCK_TRACKING */ + +/* Tracing utilities for pagebuf */ +typedef struct { + int event; + unsigned long pb; + page_buf_flags_t flags; + unsigned short hold; + unsigned short lock_value; + void *task; + void *misc; + void *ra; + loff_t offset; + size_t size; +} pagebuf_trace_t; + +struct pagebuf_trace_buf { + pagebuf_trace_t *buf; + volatile int start; + volatile int end; +}; + +#define PB_TRACE_BUFSIZE 1024 +#define CIRC_INC(i) (((i) + 1) & (PB_TRACE_BUFSIZE - 1)) + +typedef struct pagebuf_daemon { + int active; + int io_active; + spinlock_t pb_delwrite_lock; + struct list_head pb_delwrite_l; + int pb_delwri_cnt; +} pagebuf_daemon_t; + +/* + * Tunable pagebuf parameters + */ + +#define P_PARAM 4 + +typedef union pagebuf_param { + struct { + ulong flush_interval; /* interval between runs of the + * delwri flush daemon. */ + ulong age_buffer; /* time for buffer to age before + * we flush it. */ + ulong debug; /* debug tracing on or off */ + ulong stats_clear; /* clear the pagebuf stats */ + } p_un; + ulong data[P_PARAM]; +} pagebuf_param_t; + +enum { + PB_FLUSH_INT = 1, + PB_FLUSH_AGE = 2, + PB_STATS_CLEAR = 3, + PB_DEBUG = 4 +}; + +extern pagebuf_param_t pb_params; + +/* + * Pagebuf statistics + */ + +struct pbstats { + u_int32_t pb_get; + u_int32_t pb_create; + u_int32_t pb_get_locked; + u_int32_t pb_get_locked_waited; + u_int32_t pb_busy_locked; + u_int32_t pb_miss_locked; + u_int32_t pb_page_retries; + u_int32_t pb_page_found; + u_int32_t pb_get_read; +}; + +extern struct pbstats pbstats; + +#define PB_STATS_INC(count) ( count ++ ) + +#ifndef STATIC +# define STATIC static +#endif + +#endif /* __PAGE_BUF_PRIVATE_H__ */ diff -Nur linux-2.4.19/fs/xfs/pagebuf/page_buf_locking.c linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf_locking.c --- linux-2.4.19/fs/xfs/pagebuf/page_buf_locking.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf_locking.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Portions Copyright (c) 2002 Christoph Hellwig. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * page_buf_locking.c + * + * The page_buf module provides an abstract buffer cache model on top of + * the Linux page cache. Cached metadata blocks for a file system are + * hashed to the inode for the block device. The page_buf module + * assembles buffer (page_buf_t) objects on demand to aggregate such + * cached pages for I/O. The page_buf_locking module adds support for + * locking such page buffers. + * + * Written by Steve Lord at SGI + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "page_buf_internal.h" + +#ifndef EVMS_MAJOR +#define EVMS_MAJOR 117 +#endif + +/* + * pagebuf_cond_lock + * + * pagebuf_cond_lock locks a buffer object, if it is not already locked. + * Note that this in no way + * locks the underlying pages, so it is only useful for synchronizing + * concurrent use of page buffer objects, not for synchronizing independent + * access to the underlying pages. + */ +int +pagebuf_cond_lock( /* lock buffer, if not locked */ + /* returns -EBUSY if locked) */ + page_buf_t *pb) +{ + int locked; + + ASSERT(pb->pb_flags & _PBF_LOCKABLE); + + locked = down_trylock(&PBP(pb)->pb_sema) == 0; + if (locked) { + PB_SET_OWNER(pb); + } + + PB_TRACE(pb, PB_TRACE_REC(condlck), locked); + + return(locked ? 0 : -EBUSY); +} + +/* + * pagebuf_lock_value + * + * Return lock value for a pagebuf + */ +int +pagebuf_lock_value( + page_buf_t *pb) +{ + ASSERT(pb->pb_flags & _PBF_LOCKABLE); + return(atomic_read(&PBP(pb)->pb_sema.count)); +} + +/* + * pagebuf_lock + * + * pagebuf_lock locks a buffer object. Note that this in no way + * locks the underlying pages, so it is only useful for synchronizing + * concurrent use of page buffer objects, not for synchronizing independent + * access to the underlying pages. + */ +int +pagebuf_lock( + page_buf_t *pb) +{ + ASSERT(pb->pb_flags & _PBF_LOCKABLE); + + PB_TRACE(pb, PB_TRACE_REC(lock), 0); + if (atomic_read(&PBP(pb)->pb_io_remaining)) + run_task_queue(&tq_disk); + down(&PBP(pb)->pb_sema); + PB_SET_OWNER(pb); + PB_TRACE(pb, PB_TRACE_REC(locked), 0); + return 0; +} + +/* + * pagebuf_lock_disable + * + * pagebuf_lock_disable disables buffer object locking for an inode. + * remove_super() does a blkdev_put for us on the data device, hence + * the do_blkdev_put argument. + */ +void +pagebuf_lock_disable( + pb_target_t *target, + int do_blkdev_put) +{ + pagebuf_delwri_flush(target, PBDF_WAIT, NULL); + if (do_blkdev_put) + blkdev_put(target->pbr_bdev, BDEV_FS); + kfree(target); +} + +/* + * pagebuf_lock_enable + * + * get_sb_bdev() does a blkdev_get for us on the data device, hence + * the do_blkdev_get argument. + */ +pb_target_t * +pagebuf_lock_enable( + dev_t dev, + int do_blkdev_get) +{ + struct block_device *bdev; + pb_target_t *target; + int error = -ENOMEM; + + target = kmalloc(sizeof(pb_target_t), GFP_KERNEL); + if (unlikely(!target)) + return ERR_PTR(error); + + bdev = bdget(dev); + if (unlikely(!bdev)) + goto fail; + + if (do_blkdev_get) { + error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS); + if (unlikely(error)) + goto fail; + } + + target->pbr_dev = dev; + target->pbr_kdev = to_kdev_t(dev); + target->pbr_bdev = bdev; + target->pbr_mapping = bdev->bd_inode->i_mapping; + + pagebuf_target_blocksize(target, PAGE_CACHE_SIZE); + + if ((MAJOR(dev) == MD_MAJOR) || (MAJOR(dev) == EVMS_MAJOR)) + target->pbr_flags = PBR_ALIGNED_ONLY; + else if (MAJOR(dev) == LVM_BLK_MAJOR) + target->pbr_flags = PBR_SECTOR_ONLY; + else + target->pbr_flags = 0; + + return target; + +fail: + kfree(target); + return ERR_PTR(error); +} + +void +pagebuf_target_blocksize( + pb_target_t *target, + unsigned int blocksize) +{ + target->pbr_blocksize = blocksize; + target->pbr_blocksize_bits = ffs(blocksize) - 1; +} + +void +pagebuf_target_clear( + pb_target_t *target) +{ + destroy_buffers(target->pbr_kdev); + truncate_inode_pages(target->pbr_mapping, 0LL); +} + +/* + * pagebuf_unlock + * + * pagebuf_unlock releases the lock on the buffer object created by + * pagebuf_lock or pagebuf_cond_lock (not any + * pinning of underlying pages created by pagebuf_pin). + */ +void +pagebuf_unlock( /* unlock buffer */ + page_buf_t *pb) /* buffer to unlock */ +{ + ASSERT(pb->pb_flags & _PBF_LOCKABLE); + PB_CLEAR_OWNER(pb); + up(&PBP(pb)->pb_sema); + PB_TRACE(pb, PB_TRACE_REC(unlock), 0); +} diff -Nur linux-2.4.19/fs/xfs/pagebuf/page_buf_trace.h linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf_trace.h --- linux-2.4.19/fs/xfs/pagebuf/page_buf_trace.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/pagebuf/page_buf_trace.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __PAGEBUF_TRACE__ +#define __PAGEBUF_TRACE__ + +#ifdef PB_DEFINE_TRACES +#define PB_TRACE_START typedef enum { +#define PB_TRACE_REC(x) pb_trace_point_##x +#define PB_TRACE_END } pb_trace_var_t; +#else +#define PB_TRACE_START static char *event_names[] = { +#define PB_TRACE_REC(x) #x +#define PB_TRACE_END }; +#endif + +PB_TRACE_START +PB_TRACE_REC(get), +PB_TRACE_REC(get_obj), +PB_TRACE_REC(free_obj), +PB_TRACE_REC(look_pg), +PB_TRACE_REC(get_read), +PB_TRACE_REC(no_daddr), +PB_TRACE_REC(hold), +PB_TRACE_REC(rele), +PB_TRACE_REC(done), +PB_TRACE_REC(ioerror), +PB_TRACE_REC(iostart), +PB_TRACE_REC(end_io), +PB_TRACE_REC(do_io), +PB_TRACE_REC(ioreq), +PB_TRACE_REC(iowait), +PB_TRACE_REC(iowaited), +PB_TRACE_REC(free_lk), +PB_TRACE_REC(freed_l), +PB_TRACE_REC(cmp), +PB_TRACE_REC(get_lk), +PB_TRACE_REC(got_lk), +PB_TRACE_REC(skip), +PB_TRACE_REC(lock), +PB_TRACE_REC(locked), +PB_TRACE_REC(unlock), +PB_TRACE_REC(avl_ret), +PB_TRACE_REC(condlck), +PB_TRACE_REC(avl_ins), +PB_TRACE_REC(walkq1), +PB_TRACE_REC(walkq2), +PB_TRACE_REC(walkq3), +PB_TRACE_REC(delwri_q), +PB_TRACE_REC(delwri_uq), +PB_TRACE_REC(pin), +PB_TRACE_REC(unpin), +PB_TRACE_REC(file_write), +PB_TRACE_REC(external), +PB_TRACE_END + +extern void pb_trace_func(page_buf_t *, int, void *, void *); +#ifdef PAGEBUF_TRACE +# define PB_TRACE(pb, event, misc) \ + pb_trace_func(pb, event, (void *) misc, \ + (void *)__builtin_return_address(0)) +#else +# define PB_TRACE(pb, event, misc) do { } while (0) +#endif + +#endif /* __PAGEBUF_TRACE__ */ diff -Nur linux-2.4.19/fs/xfs/support/Makefile linux-2.4.19-sgi211r3/fs/xfs/support/Makefile --- linux-2.4.19/fs/xfs/support/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/Makefile Sun Aug 4 23:38:44 2002 @@ -0,0 +1,54 @@ +# +# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +EXTRA_CFLAGS += -I.. + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG +endif + +O_TARGET := support_xfs.o +ifneq ($(MAKECMDGOALS),modules_install) + obj-m := $(O_TARGET) +endif + +export-objs := ktrace.o + +obj-y := debug.o \ + kmem.o \ + ktrace.o \ + move.o \ + mrlock.o \ + qsort.o \ + uuid.o + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/fs/xfs/support/atomic.h linux-2.4.19-sgi211r3/fs/xfs/support/atomic.h --- linux-2.4.19/fs/xfs/support/atomic.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/atomic.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_ATOMIC_H__ +#define __XFS_SUPPORT_ATOMIC_H__ + +#include +#include +#include +#include +#include +#include + +/* + * This is used for two variables in XFS, one of which is a debug trace + * buffer index. They are not accessed via any other atomic operations + * so this is safe. All other atomic increments and decrements in XFS + * now use the linux built in functions. + */ + +extern spinlock_t Atomic_spin; + +static __inline__ int atomicIncWithWrap(int *ip, int val) +{ + unsigned long flags; + int ret; + spin_lock_irqsave(&Atomic_spin, flags); + ret = *ip; + (*ip)++; + if (*ip == val) *ip = 0; + spin_unlock_irqrestore(&Atomic_spin, flags); + return ret; +} + +#endif /* __XFS_SUPPORT_ATOMIC_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/debug.c linux-2.4.19-sgi211r3/fs/xfs/support/debug.c --- linux-2.4.19/fs/xfs/support/debug.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/debug.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "debug.h" + +#include +#include +#include + +int doass = 1; +static char message[256]; /* keep it off the stack */ +static spinlock_t xfs_err_lock = SPIN_LOCK_UNLOCKED; + +/* Translate from CE_FOO to KERN_FOO, err_level(CE_FOO) == KERN_FOO */ +static char *err_level[8] = {KERN_EMERG, KERN_ALERT, KERN_CRIT, + KERN_ERR, KERN_WARNING, KERN_NOTICE, + KERN_INFO, KERN_DEBUG}; + +void +assfail(char *a, char *f, int l) +{ + printk("XFS assertion failed: %s, file: %s, line: %d\n", a, f, l); + BUG(); +} + +#ifdef DEBUG + +unsigned long +random(void) +{ + static unsigned long RandomValue = 1; + /* cycles pseudo-randomly through all values between 1 and 2^31 - 2 */ + register long rv = RandomValue; + register long lo; + register long hi; + + hi = rv / 127773; + lo = rv % 127773; + rv = 16807 * lo - 2836 * hi; + if( rv <= 0 ) rv += 2147483647; + return( RandomValue = rv ); +} + +int +get_thread_id(void) +{ + return current->pid; +} + +#endif /* DEBUG */ + +void +cmn_err(register int level, char *fmt, ...) +{ + char *fp = fmt; + va_list ap; + + spin_lock(&xfs_err_lock); + va_start(ap, fmt); + if (*fmt == '!') fp++; + vsprintf(message, fp, ap); + printk("%s%s\n", err_level[level], message); + va_end(ap); + spin_unlock(&xfs_err_lock); + + if (level == CE_PANIC) + BUG(); +} + + +void +icmn_err(register int level, char *fmt, va_list ap) +{ + spin_lock(&xfs_err_lock); + vsprintf(message, fmt, ap); + spin_unlock(&xfs_err_lock); + printk("%s%s\n", err_level[level], message); + if (level == CE_PANIC) + BUG(); +} diff -Nur linux-2.4.19/fs/xfs/support/debug.h linux-2.4.19-sgi211r3/fs/xfs/support/debug.h --- linux-2.4.19/fs/xfs/support/debug.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/debug.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_DEBUG_H__ +#define __XFS_SUPPORT_DEBUG_H__ + +#include + +#define CE_DEBUG 7 /* debug */ +#define CE_CONT 6 /* continuation */ +#define CE_NOTE 5 /* notice */ +#define CE_WARN 4 /* warning */ +#define CE_ALERT 1 /* alert */ +#define CE_PANIC 0 /* panic */ + +extern void icmn_err(int, char *, va_list); +extern void cmn_err(int, char *, ...); + +#ifdef DEBUG +# ifdef lint +# define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */ +# else +# define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__)) +# endif /* lint */ +#else +# define ASSERT(x) ((void)0) +#endif + +extern int doass; /* dynamically turn off asserts */ +extern void assfail(char *, char *, int); +#ifdef DEBUG +extern unsigned long random(void); +extern int get_thread_id(void); +#endif + +#define ASSERT_ALWAYS(EX) ((EX)?((void)0):assfail(#EX, __FILE__, __LINE__)) +#define debug_stop_all_cpus(param) /* param is "cpumask_t *" */ + +#endif /* __XFS_SUPPORT_DEBUG_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/kmem.c linux-2.4.19-sgi211r3/fs/xfs/support/kmem.c --- linux-2.4.19/fs/xfs/support/kmem.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/kmem.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +#include "time.h" +#include "kmem.h" + +#define DEF_PRIORITY (6) +#define MAX_SLAB_SIZE 0x10000 + +static __inline unsigned int flag_convert(int flags) +{ +#if DEBUG + if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS))) { + printk(KERN_WARNING + "XFS: memory allocation with wrong flags (%x)\n", flags); + BUG(); + } +#endif + + if (flags & KM_NOSLEEP) + return GFP_ATOMIC; + /* If we're in a transaction, FS activity is not ok */ + else if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) + return GFP_NOFS; + else + return GFP_KERNEL; +} + +#define MAX_SHAKE 8 + +static kmem_shake_func_t shake_list[MAX_SHAKE]; +static DECLARE_MUTEX(shake_sem); + +void kmem_shake_register(kmem_shake_func_t sfunc) +{ + int i; + + down(&shake_sem); + for (i = 0; i < MAX_SHAKE; i++) { + if (shake_list[i] == NULL) { + shake_list[i] = sfunc; + break; + } + } + if (i == MAX_SHAKE) + BUG(); + up(&shake_sem); +} + +void kmem_shake_deregister(kmem_shake_func_t sfunc) +{ + int i; + + down(&shake_sem); + for (i = 0; i < MAX_SHAKE; i++) { + if (shake_list[i] == sfunc) + break; + } + if (i == MAX_SHAKE) + BUG(); + for (; i < MAX_SHAKE - 1; i++) { + shake_list[i] = shake_list[i+1]; + } + shake_list[i] = NULL; + up(&shake_sem); +} + +static __inline__ void kmem_shake(void) +{ + int i; + + down(&shake_sem); + for (i = 0; i < MAX_SHAKE && shake_list[i]; i++) + (*shake_list[i])(); + up(&shake_sem); + delay(10); +} + +void * +kmem_alloc(size_t size, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *rval; + +repeat: + if (MAX_SLAB_SIZE < size) { + /* Avoid doing filesystem sensitive stuff to get this */ + rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); + } else { + rval = kmalloc(size, flag_convert(flags)); + } + + if (rval || (flags & KM_NOSLEEP)) + return rval; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(); + + shrink--; + goto repeat; + } + + rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); + if (!rval && !(flags & KM_SLEEP)) + panic("kmem_alloc: NULL memory on KM_SLEEP request!"); + + return rval; +} + +void * +kmem_zalloc(size_t size, int flags) +{ + void *ptr; + + ptr = kmem_alloc(size, flags); + + if (ptr) + memset((char *)ptr, 0, (int)size); + + return (ptr); +} + +void +kmem_free(void *ptr, size_t size) +{ + if (((unsigned long)ptr < VMALLOC_START) || + ((unsigned long)ptr >= VMALLOC_END)) { + kfree(ptr); + } else { + vfree(ptr); + } +} + +void * +kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags) +{ + void *new; + + new = kmem_alloc(newsize, flags); + if (ptr) { + memcpy(new, ptr, ((oldsize < newsize) ? oldsize : newsize)); + kmem_free(ptr, oldsize); + } + + return new; +} + +kmem_zone_t * +kmem_zone_init(int size, char *zone_name) +{ + return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL); +} + +void * +kmem_zone_alloc(kmem_zone_t *zone, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *ptr = NULL; + +repeat: + ptr = kmem_cache_alloc(zone, flag_convert(flags)); + + if (ptr || (flags & KM_NOSLEEP)) + return ptr; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(); + + shrink--; + goto repeat; + } + + if (flags & KM_SLEEP) + panic("kmem_zone_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} + +void * +kmem_zone_zalloc(kmem_zone_t *zone, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *ptr = NULL; + +repeat: + ptr = kmem_cache_alloc(zone, flag_convert(flags)); + + if (ptr) { + memset(ptr, 0, kmem_cache_size(zone)); + return ptr; + } + + if (flags & KM_NOSLEEP) + return ptr; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(); + + shrink--; + goto repeat; + } + + if (flags & KM_SLEEP) + panic("kmem_zone_zalloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} + +void +kmem_zone_free(kmem_zone_t *zone, void *ptr) +{ + kmem_cache_free(zone, ptr); +} diff -Nur linux-2.4.19/fs/xfs/support/kmem.h linux-2.4.19-sgi211r3/fs/xfs/support/kmem.h --- linux-2.4.19/fs/xfs/support/kmem.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/kmem.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_KMEM_H__ +#define __XFS_SUPPORT_KMEM_H__ + +#include + +/* + * memory management routines + */ +#define KM_SLEEP 0x0001 +#define KM_NOSLEEP 0x0002 +#define KM_NOFS 0x0004 + +#define kmem_zone kmem_cache_s +#define kmem_zone_t kmem_cache_t + +extern kmem_zone_t *kmem_zone_init(int, char *); +extern void *kmem_zone_zalloc(kmem_zone_t *, int); +extern void *kmem_zone_alloc(kmem_zone_t *, int); +extern void kmem_zone_free(kmem_zone_t *, void *); + +extern void *kmem_alloc(size_t, int); +extern void *kmem_realloc(void *, size_t, size_t, int); +extern void *kmem_zalloc(size_t, int); +extern void kmem_free(void *, size_t); + +typedef void (*kmem_shake_func_t)(void); + +extern void kmem_shake_register(kmem_shake_func_t); +extern void kmem_shake_deregister(kmem_shake_func_t); + +#endif /* __XFS_SUPPORT_KMEM_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/ktrace.c linux-2.4.19-sgi211r3/fs/xfs/support/ktrace.c --- linux-2.4.19/fs/xfs/support/ktrace.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/ktrace.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include "kmem.h" +#include "spin.h" +#include "debug.h" +#include "atomic.h" +#include "ktrace.h" + +#if (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) + +static kmem_zone_t *ktrace_hdr_zone; +static kmem_zone_t *ktrace_ent_zone; +static int ktrace_zentries; + +void +ktrace_init(int zentries) +{ + ktrace_zentries = zentries; + + ktrace_hdr_zone = kmem_zone_init(sizeof(ktrace_t), + "ktrace_hdr"); + ASSERT(ktrace_hdr_zone); + + ktrace_ent_zone = kmem_zone_init(ktrace_zentries + * sizeof(ktrace_entry_t), + "ktrace_ent"); + ASSERT(ktrace_ent_zone); +} + +void +ktrace_uninit(void) +{ + kmem_cache_destroy(ktrace_hdr_zone); + kmem_cache_destroy(ktrace_ent_zone); +} + +/* + * ktrace_alloc() + * + * Allocate a ktrace header and enough buffering for the given + * number of entries. + */ +ktrace_t * +ktrace_alloc(int nentries, int sleep) +{ + ktrace_t *ktp; + ktrace_entry_t *ktep; + + ktp = (ktrace_t*)kmem_zone_alloc(ktrace_hdr_zone, sleep); + + if (ktp == (ktrace_t*)NULL) { + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; + } + + /* + * Special treatment for buffers with the ktrace_zentries entries + */ + if (nentries == ktrace_zentries) { + ktep = (ktrace_entry_t*)kmem_zone_zalloc(ktrace_ent_zone, + sleep); + } else { + ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)), + sleep); + } + + if (ktep == NULL) { + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + kmem_free(ktp, sizeof(*ktp)); + + return NULL; + } + + spinlock_init(&(ktp->kt_lock), "kt_lock"); + + ktp->kt_entries = ktep; + ktp->kt_nentries = nentries; + ktp->kt_index = 0; + ktp->kt_rollover = 0; + + return ktp; +} + + +/* + * ktrace_free() + * + * Free up the ktrace header and buffer. It is up to the caller + * to ensure that no-one is referencing it. + */ +void +ktrace_free(ktrace_t *ktp) +{ + int entries_size; + + if (ktp == (ktrace_t *)NULL) + return; + + spinlock_destroy(&ktp->kt_lock); + + /* + * Special treatment for the Vnode trace buffer. + */ + if (ktp->kt_nentries == ktrace_zentries) { + kmem_zone_free(ktrace_ent_zone, ktp->kt_entries); + } else { + entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t)); + + kmem_free(ktp->kt_entries, entries_size); + } + + kmem_zone_free(ktrace_hdr_zone, ktp); +} + + +/* + * Enter the given values into the "next" entry in the trace buffer. + * kt_index is always the index of the next entry to be filled. + */ +void +ktrace_enter( + ktrace_t *ktp, + void *val0, + void *val1, + void *val2, + void *val3, + void *val4, + void *val5, + void *val6, + void *val7, + void *val8, + void *val9, + void *val10, + void *val11, + void *val12, + void *val13, + void *val14, + void *val15) +{ + int index; + ktrace_entry_t *ktep; + + ASSERT(ktp != NULL); + + /* + * Grab an entry by pushing the index up to the next one. + */ + index = atomicIncWithWrap(&ktp->kt_index, ktp->kt_nentries); + + if (!ktp->kt_rollover && index == ktp->kt_nentries - 1) + ktp->kt_rollover = 1; + + ASSERT((index >= 0) && (index < ktp->kt_nentries)); + + ktep = &(ktp->kt_entries[index]); + + ktep->val[0] = val0; + ktep->val[1] = val1; + ktep->val[2] = val2; + ktep->val[3] = val3; + ktep->val[4] = val4; + ktep->val[5] = val5; + ktep->val[6] = val6; + ktep->val[7] = val7; + ktep->val[8] = val8; + ktep->val[9] = val9; + ktep->val[10] = val10; + ktep->val[11] = val11; + ktep->val[12] = val12; + ktep->val[13] = val13; + ktep->val[14] = val14; + ktep->val[15] = val15; +} + +/* + * Return the number of entries in the trace buffer. + */ +int +ktrace_nentries( + ktrace_t *ktp) +{ + if (ktp == NULL) { + return 0; + } + + return (ktp->kt_rollover ? ktp->kt_nentries : ktp->kt_index); +} + + +/* + * ktrace_first() + * + * This is used to find the start of the trace buffer. + * In conjunction with ktrace_next() it can be used to + * iterate through the entire trace buffer. This code does + * not do any locking because it is assumed that it is called + * from the debugger. + * + * The caller must pass in a pointer to a ktrace_snap + * structure in which we will keep some state used to + * iterate through the buffer. This state must not touched + * by any code outside of this module. + */ +ktrace_entry_t * +ktrace_first(ktrace_t *ktp, ktrace_snap_t *ktsp) +{ + ktrace_entry_t *ktep; + int index; + int nentries; + + if (ktp->kt_rollover) + index = ktp->kt_index; + else + index = 0; + + ktsp->ks_start = index; + ktep = &(ktp->kt_entries[index]); + + nentries = ktrace_nentries(ktp); + index++; + if (index < nentries) { + ktsp->ks_index = index; + } else { + ktsp->ks_index = 0; + if (index > nentries) + ktep = NULL; + } + return ktep; +} + + +/* + * ktrace_next() + * + * This is used to iterate through the entries of the given + * trace buffer. The caller must pass in the ktrace_snap_t + * structure initialized by ktrace_first(). The return value + * will be either a pointer to the next ktrace_entry or NULL + * if all of the entries have been traversed. + */ +ktrace_entry_t * +ktrace_next( + ktrace_t *ktp, + ktrace_snap_t *ktsp) +{ + int index; + ktrace_entry_t *ktep; + + index = ktsp->ks_index; + if (index == ktsp->ks_start) { + ktep = NULL; + } else { + ktep = &ktp->kt_entries[index]; + } + + index++; + if (index == ktrace_nentries(ktp)) { + ktsp->ks_index = 0; + } else { + ktsp->ks_index = index; + } + + return ktep; +} + +#if (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) +EXPORT_SYMBOL(ktrace_first); +EXPORT_SYMBOL(ktrace_next); +#endif + +/* + * ktrace_skip() + * + * Skip the next "count" entries and return the entry after that. + * Return NULL if this causes us to iterate past the beginning again. + */ + +ktrace_entry_t * +ktrace_skip( + ktrace_t *ktp, + int count, + ktrace_snap_t *ktsp) +{ + int index; + int new_index; + ktrace_entry_t *ktep; + int nentries = ktrace_nentries(ktp); + + index = ktsp->ks_index; + new_index = index + count; + while (new_index >= nentries) { + new_index -= nentries; + } + if (index == ktsp->ks_start) { + /* + * We've iterated around to the start, so we're done. + */ + ktep = NULL; + } else if ((new_index < index) && (index < ktsp->ks_index)) { + /* + * We've skipped past the start again, so we're done. + */ + ktep = NULL; + ktsp->ks_index = ktsp->ks_start; + } else { + ktep = &(ktp->kt_entries[new_index]); + new_index++; + if (new_index == nentries) { + ktsp->ks_index = 0; + } else { + ktsp->ks_index = new_index; + } + } + return ktep; +} + +#else + +ktrace_t * +ktrace_alloc(int nentries, int sleep) +{ + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} +#endif diff -Nur linux-2.4.19/fs/xfs/support/ktrace.h linux-2.4.19-sgi211r3/fs/xfs/support/ktrace.h --- linux-2.4.19/fs/xfs/support/ktrace.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/ktrace.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_KTRACE_H__ +#define __XFS_SUPPORT_KTRACE_H__ + + +/* + * Trace buffer entry structure. + */ +typedef struct ktrace_entry { + void *val[16]; +} ktrace_entry_t; + +/* + * Trace buffer header structure. + */ +typedef struct ktrace { + lock_t kt_lock; /* mutex to guard counters */ + int kt_nentries; /* number of entries in trace buf */ + int kt_index; /* current index in entries */ + int kt_rollover; + ktrace_entry_t *kt_entries; /* buffer of entries */ +} ktrace_t; + +/* + * Trace buffer snapshot structure. + */ +typedef struct ktrace_snap { + int ks_start; /* kt_index at time of snap */ + int ks_index; /* current index */ +} ktrace_snap_t; + +/* + * Exported interfaces. + */ +extern ktrace_t *ktrace_alloc(int, int); + +#if (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) + +extern void ktrace_init(int zentries); +extern void ktrace_uninit(void); + +extern void ktrace_free(ktrace_t *); + +extern void ktrace_enter( + ktrace_t *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *); + +extern ktrace_entry_t *ktrace_first(ktrace_t *, ktrace_snap_t *); +extern int ktrace_nentries(ktrace_t *); +extern ktrace_entry_t *ktrace_next(ktrace_t *, ktrace_snap_t *); +extern ktrace_entry_t *ktrace_skip(ktrace_t *, int, ktrace_snap_t *); + +#else + +#define ktrace_free(ktp) +#define ktrace_enter(ktp,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15) + +#endif + +#endif /* __XFS_SUPPORT_KTRACE_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/move.c linux-2.4.19-sgi211r3/fs/xfs/support/move.c --- linux-2.4.19/fs/xfs/support/move.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/move.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include "debug.h" +#include "move.h" + +/* + * Move "n" bytes at byte address "cp"; "rw" indicates the direction + * of the move, and the I/O parameters are provided in "uio", which is + * update to reflect the data which was moved. Returns 0 on success or + * a non-zero errno on failure. + */ +int +uiomove(void *cp, size_t n, enum uio_rw rw, struct uio *uio) +{ + register struct iovec *iov; + u_int cnt; + int error; + + while (n > 0 && uio->uio_resid) { + iov = uio->uio_iov; + cnt = (u_int)iov->iov_len; + if (cnt == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + continue; + } + if (cnt > n) + cnt = (u_int)n; + switch (uio->uio_segflg) { + case UIO_USERSPACE: + if (rw == UIO_READ) + error = copy_to_user(iov->iov_base, cp, cnt); + else + error = copy_from_user(cp, iov->iov_base, cnt); + if (error) + return EFAULT; + break; + + + case UIO_SYSSPACE: + if (rw == UIO_READ) + bcopy(cp, iov->iov_base, cnt); + else + bcopy(iov->iov_base, cp, cnt); + break; + + default: + ASSERT(0); + break; + } + iov->iov_base = (void *)((char *)iov->iov_base + cnt); + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + cp = (void *)((char *)cp + cnt); + n -= cnt; + } + return 0; +} diff -Nur linux-2.4.19/fs/xfs/support/move.h linux-2.4.19-sgi211r3/fs/xfs/support/move.h --- linux-2.4.19/fs/xfs/support/move.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/move.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_SUPPORT_MOVE_H__ +#define __XFS_SUPPORT_MOVE_H__ + +#include +#include + +#define bzero(p,s) memset((p), 0, (s)) +#define bcopy(s,d,n) memcpy((d),(s),(n)) +#define bcmp(s1,s2,l) memcmp(s1,s2,l) +#define ovbcopy(from,to,count) memmove(to,from,count) + +typedef struct iovec iovec_t; + +typedef struct uio { + iovec_t *uio_iov; /* pointer to array of iovecs */ + int uio_iovcnt; /* number of iovecs */ + int uio_fmode; /* file mode flags */ + xfs_off_t uio_offset; /* file offset */ + short uio_segflg; /* address space (kernel or user) */ + ssize_t uio_resid; /* residual count */ +} uio_t; + +/* + * I/O direction. + */ +typedef enum uio_rw { UIO_READ, UIO_WRITE } uio_rw_t; + +/* + * Segment flag values. + */ +typedef enum uio_seg { + UIO_USERSPACE, /* uio_iov describes user space */ + UIO_SYSSPACE, /* uio_iov describes system space */ +} uio_seg_t; + + +extern int uiomove (void *, size_t, uio_rw_t, uio_t *); + +#endif /* __XFS_SUPPORT_MOVE_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/mrlock.c linux-2.4.19-sgi211r3/fs/xfs/support/mrlock.c --- linux-2.4.19/fs/xfs/support/mrlock.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/mrlock.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include + +#include "mrlock.h" + + +#if USE_RW_WAIT_QUEUE_SPINLOCK +# define wq_write_lock write_lock +#else +# define wq_write_lock spin_lock +#endif + +/* + * We don't seem to need lock_type (only one supported), name, or + * sequence. But, XFS will pass it so let's leave them here for now. + */ +/* ARGSUSED */ +void +mrlock_init(mrlock_t *mrp, int lock_type, char *name, long sequence) +{ + mrp->mr_count = 0; + mrp->mr_reads_waiting = 0; + mrp->mr_writes_waiting = 0; + init_waitqueue_head(&mrp->mr_readerq); + init_waitqueue_head(&mrp->mr_writerq); + mrp->mr_lock = SPIN_LOCK_UNLOCKED; +} + +/* + * Macros to lock/unlock the mrlock_t. + */ + +#define MRLOCK(m) spin_lock(&(m)->mr_lock); +#define MRUNLOCK(m) spin_unlock(&(m)->mr_lock); + + +/* + * lock_wait should never be called in an interrupt thread. + * + * mrlocks can sleep (i.e. call schedule) and so they can't ever + * be called from an interrupt thread. + * + * threads that wake-up should also never be invoked from interrupt threads. + * + * But, waitqueue_lock is locked from interrupt threads - and we are + * called with interrupts disabled, so it is all OK. + */ + +/* ARGSUSED */ +void +lock_wait(wait_queue_head_t *q, spinlock_t *lock, int rw) +{ + DECLARE_WAITQUEUE( wait, current ); + + set_current_state(TASK_UNINTERRUPTIBLE); + + wq_write_lock(&q->lock); + if (rw) { + __add_wait_queue_tail(q, &wait); + } else { + __add_wait_queue(q, &wait); + } + + wq_write_unlock(&q->lock); + spin_unlock(lock); + + schedule(); + + set_current_state(TASK_RUNNING); + + wq_write_lock(&q->lock); + __remove_wait_queue(q, &wait); + wq_write_unlock(&q->lock); + + spin_lock(lock); + + /* return with lock held */ +} + +/* ARGSUSED */ +void +mrfree(mrlock_t *mrp) +{ +} + +/* ARGSUSED */ +void +mrlock(mrlock_t *mrp, int type, int flags) +{ + if (type == MR_ACCESS) + mraccess(mrp); + else + mrupdate(mrp); +} + +/* ARGSUSED */ +void +mraccessf(mrlock_t *mrp, int flags) +{ + MRLOCK(mrp); + if(mrp->mr_writes_waiting > 0) { + mrp->mr_reads_waiting++; + lock_wait(&mrp->mr_readerq, &mrp->mr_lock, 0); + mrp->mr_reads_waiting--; + } + while (mrp->mr_count < 0) { + mrp->mr_reads_waiting++; + lock_wait(&mrp->mr_readerq, &mrp->mr_lock, 0); + mrp->mr_reads_waiting--; + } + mrp->mr_count++; + MRUNLOCK(mrp); +} + +/* ARGSUSED */ +void +mrupdatef(mrlock_t *mrp, int flags) +{ + MRLOCK(mrp); + while(mrp->mr_count) { + mrp->mr_writes_waiting++; + lock_wait(&mrp->mr_writerq, &mrp->mr_lock, 1); + mrp->mr_writes_waiting--; + } + + mrp->mr_count = -1; /* writer on it */ + MRUNLOCK(mrp); +} + +int +mrtryaccess(mrlock_t *mrp) +{ + MRLOCK(mrp); + /* + * If anyone is waiting for update access or the lock is held for update + * fail the request. + */ + if(mrp->mr_writes_waiting > 0 || mrp->mr_count < 0) { + MRUNLOCK(mrp); + return 0; + } + mrp->mr_count++; + MRUNLOCK(mrp); + return 1; +} + +int +mrtrypromote(mrlock_t *mrp) +{ + MRLOCK(mrp); + + if(mrp->mr_count == 1) { /* We are the only thread with the lock */ + mrp->mr_count = -1; /* writer on it */ + MRUNLOCK(mrp); + return 1; + } + + MRUNLOCK(mrp); + return 0; +} + +int +mrtryupdate(mrlock_t *mrp) +{ + MRLOCK(mrp); + + if(mrp->mr_count) { + MRUNLOCK(mrp); + return 0; + } + + mrp->mr_count = -1; /* writer on it */ + MRUNLOCK(mrp); + return 1; +} + +static __inline__ void mrwake(mrlock_t *mrp) +{ + /* + * First, if the count is now 0, we need to wake-up anyone waiting. + */ + if (!mrp->mr_count) { + if (mrp->mr_writes_waiting) { /* Wake-up first writer waiting */ + wake_up(&mrp->mr_writerq); + } else if (mrp->mr_reads_waiting) { /* Wakeup any readers waiting */ + wake_up(&mrp->mr_readerq); + } + } +} + +void +mraccunlock(mrlock_t *mrp) +{ + MRLOCK(mrp); + mrp->mr_count--; + mrwake(mrp); + MRUNLOCK(mrp); +} + +void +mrunlock(mrlock_t *mrp) +{ + MRLOCK(mrp); + if (mrp->mr_count < 0) { + mrp->mr_count = 0; + } else { + mrp->mr_count--; + } + mrwake(mrp); + MRUNLOCK(mrp); +} + +int +ismrlocked(mrlock_t *mrp, int type) /* No need to lock since info can change */ +{ + if (type == MR_ACCESS) + return (mrp->mr_count > 0); /* Read lock */ + else if (type == MR_UPDATE) + return (mrp->mr_count < 0); /* Write lock */ + else if (type == (MR_UPDATE | MR_ACCESS)) + return (mrp->mr_count); /* Any type of lock held */ + else /* Any waiters */ + return (mrp->mr_reads_waiting | mrp->mr_writes_waiting); +} + +/* + * Demote from update to access. We better be the only thread with the + * lock in update mode so it should be easy to set to 1. + * Wake-up any readers waiting. + */ + +void +mrdemote(mrlock_t *mrp) +{ + MRLOCK(mrp); + mrp->mr_count = 1; + if (mrp->mr_reads_waiting) { /* Wakeup all readers waiting */ + wake_up(&mrp->mr_readerq); + } + MRUNLOCK(mrp); +} + +int +mrislocked_access(mrlock_t *mrp) +{ + return(mrp->mr_count > 0); +} + +int +mrislocked_update(mrlock_t *mrp) +{ + return(mrp->mr_count < 0); +} diff -Nur linux-2.4.19/fs/xfs/support/mrlock.h linux-2.4.19-sgi211r3/fs/xfs/support/mrlock.h --- linux-2.4.19/fs/xfs/support/mrlock.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/mrlock.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_MRLOCK_H__ +#define __XFS_SUPPORT_MRLOCK_H__ + +#include +#include +#include +#include +#include + +/* + * Implement mrlocks on Linux that work for XFS. + * + * These are sleep locks and not spinlocks. If one wants read/write spinlocks, + * use read_lock, write_lock, ... see spinlock.h. + */ + +typedef struct mrlock_s { + int mr_count; + unsigned short mr_reads_waiting; + unsigned short mr_writes_waiting; + wait_queue_head_t mr_readerq; + wait_queue_head_t mr_writerq; + spinlock_t mr_lock; +} mrlock_t; + +#define MR_ACCESS 1 +#define MR_UPDATE 2 + +#define MRLOCK_BARRIER 0x1 +#define MRLOCK_ALLOW_EQUAL_PRI 0x8 + +/* + * mraccessf/mrupdatef take flags to be passed in while sleeping; + * only PLTWAIT is currently supported. + */ + +extern void mraccessf(mrlock_t *, int); +extern void mrupdatef(mrlock_t *, int); +extern void mrlock(mrlock_t *, int, int); +extern void mrunlock(mrlock_t *); +extern void mraccunlock(mrlock_t *); +extern int mrtryupdate(mrlock_t *); +extern int mrtryaccess(mrlock_t *); +extern int mrtrypromote(mrlock_t *); +extern void mrdemote(mrlock_t *); + +extern int ismrlocked(mrlock_t *, int); +extern void mrlock_init(mrlock_t *, int type, char *name, long sequence); +extern void mrfree(mrlock_t *); + +#define mrinit(mrp, name) mrlock_init(mrp, MRLOCK_BARRIER, name, -1) +#define mraccess(mrp) mraccessf(mrp, 0) /* grab for READ/ACCESS */ +#define mrupdate(mrp) mrupdatef(mrp, 0) /* grab for WRITE/UPDATE */ + +#endif /* __XFS_SUPPORT_MRLOCK_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/mutex.h linux-2.4.19-sgi211r3/fs/xfs/support/mutex.h --- linux-2.4.19/fs/xfs/support/mutex.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/mutex.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Portions Copyright (c) 2002 Christoph Hellwig. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_MUTEX_H__ +#define __XFS_SUPPORT_MUTEX_H__ + +#include +#include + +/* + * Map the mutex'es from IRIX to Linux semaphores. + * + * Destroy just simply initializes to -99 which should block all other + * callers. + */ +#define MUTEX_DEFAULT 0x0 +typedef struct semaphore mutex_t; + +#define mutex_init(lock, type, name) sema_init(lock, 1) +#define init_mutex(ptr, type, name, sequence) sema_init(lock, 1) +#define mutex_destroy(lock) sema_init(lock, -99) +#define mutex_lock(lock, num) down(lock) +#define mutex_trylock(lock) (down_trylock(lock) ? 0 : 1) +#define mutex_unlock(lock) up(lock) + +#endif /* __XFS_SUPPORT_MUTEX_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/qsort.c linux-2.4.19-sgi211r3/fs/xfs/support/qsort.c --- linux-2.4.19/fs/xfs/support/qsort.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/qsort.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,243 @@ +/* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Douglas C. Schmidt (schmidt@ics.uci.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* If you consider tuning this algorithm, you should consult first: + Engineering a sort function; Jon Bentley and M. Douglas McIlroy; + Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */ + +#include +#include + +/* Byte-wise swap two items of size SIZE. */ +#define SWAP(a, b, size) \ + do \ + { \ + register size_t __size = (size); \ + register char *__a = (a), *__b = (b); \ + do \ + { \ + char __tmp = *__a; \ + *__a++ = *__b; \ + *__b++ = __tmp; \ + } while (--__size > 0); \ + } while (0) + +/* Discontinue quicksort algorithm when partition gets below this size. + This particular magic number was chosen to work best on a Sun 4/260. */ +#define MAX_THRESH 4 + +/* Stack node declarations used to store unfulfilled partition obligations. */ +typedef struct + { + char *lo; + char *hi; + } stack_node; + +/* The next 4 #defines implement a very fast in-line stack abstraction. */ +/* The stack needs log (total_elements) entries (we could even subtract + log(MAX_THRESH)). Since total_elements has type size_t, we get as + upper bound for log (total_elements): + bits per byte (CHAR_BIT) * sizeof(size_t). */ +#define STACK_SIZE (8 * sizeof(unsigned long int)) +#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) +#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) +#define STACK_NOT_EMPTY (stack < top) + + +/* Order size using quicksort. This implementation incorporates + four optimizations discussed in Sedgewick: + + 1. Non-recursive, using an explicit stack of pointer that store the + next array partition to sort. To save time, this maximum amount + of space required to store an array of SIZE_MAX is allocated on the + stack. Assuming a 32-bit (64 bit) integer for size_t, this needs + only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes). + Pretty cheap, actually. + + 2. Chose the pivot element using a median-of-three decision tree. + This reduces the probability of selecting a bad pivot value and + eliminates certain extraneous comparisons. + + 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving + insertion sort to order the MAX_THRESH items within each partition. + This is a big win, since insertion sort is faster for small, mostly + sorted array segments. + + 4. The larger of the two sub-partitions is always pushed onto the + stack first, with the algorithm then concentrating on the + smaller partition. This *guarantees* no more than log (total_elems) + stack size is needed (actually O(1) in this case)! */ + +void +qsort (void *const pbase, size_t total_elems, size_t size, + int (*cmp)(const void *, const void *)) +{ + register char *base_ptr = (char *) pbase; + + const size_t max_thresh = MAX_THRESH * size; + + if (total_elems == 0) + /* Avoid lossage with unsigned arithmetic below. */ + return; + + if (total_elems > MAX_THRESH) + { + char *lo = base_ptr; + char *hi = &lo[size * (total_elems - 1)]; + stack_node stack[STACK_SIZE]; + stack_node *top = stack + 1; + + while (STACK_NOT_EMPTY) + { + char *left_ptr; + char *right_ptr; + + /* Select median value from among LO, MID, and HI. Rearrange + LO and HI so the three values are sorted. This lowers the + probability of picking a pathological pivot value and + skips a comparison for both the LEFT_PTR and RIGHT_PTR in + the while loops. */ + + char *mid = lo + size * ((hi - lo) / size >> 1); + + if ((*cmp) ((void *) mid, (void *) lo) < 0) + SWAP (mid, lo, size); + if ((*cmp) ((void *) hi, (void *) mid) < 0) + SWAP (mid, hi, size); + else + goto jump_over; + if ((*cmp) ((void *) mid, (void *) lo) < 0) + SWAP (mid, lo, size); + jump_over:; + + left_ptr = lo + size; + right_ptr = hi - size; + + /* Here's the famous ``collapse the walls'' section of quicksort. + Gotta like those tight inner loops! They are the main reason + that this algorithm runs much faster than others. */ + do + { + while ((*cmp) ((void *) left_ptr, (void *) mid) < 0) + left_ptr += size; + + while ((*cmp) ((void *) mid, (void *) right_ptr) < 0) + right_ptr -= size; + + if (left_ptr < right_ptr) + { + SWAP (left_ptr, right_ptr, size); + if (mid == left_ptr) + mid = right_ptr; + else if (mid == right_ptr) + mid = left_ptr; + left_ptr += size; + right_ptr -= size; + } + else if (left_ptr == right_ptr) + { + left_ptr += size; + right_ptr -= size; + break; + } + } + while (left_ptr <= right_ptr); + + /* Set up pointers for next iteration. First determine whether + left and right partitions are below the threshold size. If so, + ignore one or both. Otherwise, push the larger partition's + bounds on the stack and continue sorting the smaller one. */ + + if ((size_t) (right_ptr - lo) <= max_thresh) + { + if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore both small partitions. */ + POP (lo, hi); + else + /* Ignore small left partition. */ + lo = left_ptr; + } + else if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore small right partition. */ + hi = right_ptr; + else if ((right_ptr - lo) > (hi - left_ptr)) + { + /* Push larger left partition indices. */ + PUSH (lo, right_ptr); + lo = left_ptr; + } + else + { + /* Push larger right partition indices. */ + PUSH (left_ptr, hi); + hi = right_ptr; + } + } + } + + /* Once the BASE_PTR array is partially sorted by quicksort the rest + is completely sorted using insertion sort, since this is efficient + for partitions below MAX_THRESH size. BASE_PTR points to the beginning + of the array to sort, and END_PTR points at the very last element in + the array (*not* one beyond it!). */ + { + char *const end_ptr = &base_ptr[size * (total_elems - 1)]; + char *tmp_ptr = base_ptr; + char *thresh = min(end_ptr, base_ptr + max_thresh); + register char *run_ptr; + + /* Find smallest element in first threshold and place it at the + array's beginning. This is the smallest array element, + and the operation speeds up insertion sort's inner loop. */ + + for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) + if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr) < 0) + tmp_ptr = run_ptr; + + if (tmp_ptr != base_ptr) + SWAP (tmp_ptr, base_ptr, size); + + /* Insertion sort, running from left-hand-side up to right-hand-side. */ + + run_ptr = base_ptr + size; + while ((run_ptr += size) <= end_ptr) + { + tmp_ptr = run_ptr - size; + while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr) < 0) + tmp_ptr -= size; + + tmp_ptr += size; + if (tmp_ptr != run_ptr) + { + char *trav; + + trav = run_ptr + size; + while (--trav >= run_ptr) + { + char c = *trav; + char *hi, *lo; + + for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) + *hi = *lo; + *hi = c; + } + } + } + } +} diff -Nur linux-2.4.19/fs/xfs/support/qsort.h linux-2.4.19-sgi211r3/fs/xfs/support/qsort.h --- linux-2.4.19/fs/xfs/support/qsort.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/qsort.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef QSORT_H +#define QSORT_H + +extern void qsort (void *const pbase, + size_t total_elems, + size_t size, + int (*cmp)(const void *, const void *)); + +#endif diff -Nur linux-2.4.19/fs/xfs/support/sema.h linux-2.4.19-sgi211r3/fs/xfs/support/sema.h --- linux-2.4.19/fs/xfs/support/sema.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/sema.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_SEMA_H__ +#define __XFS_SUPPORT_SEMA_H__ + +#include +#include +#include +#include +#include + +/* + * sema_t structure just maps to struct semaphore in Linux kernel. + */ + +typedef struct semaphore sema_t; + +#define init_sema(sp, val, c, d) sema_init(sp, val) +#define initsema(sp, val) sema_init(sp, val) +#define initnsema(sp, val, name) sema_init(sp, val) +#define psema(sp, b) down(sp) +#define vsema(sp) up(sp) +#define valusema(sp) (atomic_read(&(sp)->count)) +#define freesema(sema) + +/* + * Map cpsema (try to get the sema) to down_trylock. We need to switch + * the return values since cpsema returns 1 (acquired) 0 (failed) and + * down_trylock returns the reverse 0 (acquired) 1 (failed). + */ + +#define cpsema(sp) (down_trylock(sp) ? 0 : 1) + +/* + * Didn't do cvsema(sp). Not sure how to map this to up/down/... + * It does a vsema if the values is < 0 other wise nothing. + */ + +#endif /* __XFS_SUPPORT_SEMA_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/spin.h linux-2.4.19-sgi211r3/fs/xfs/support/spin.h --- linux-2.4.19/fs/xfs/support/spin.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/spin.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Portions Copyright (c) 2002 Christoph Hellwig. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_SPIN_H__ +#define __XFS_SUPPORT_SPIN_H__ + +#include /* preempt needs this */ +#include + +/* + * Map lock_t from IRIX to Linux spinlocks. + * + * Note that linux turns on/off spinlocks depending on CONFIG_SMP. + * We don't need to worry about SMP or not here. + */ + +typedef spinlock_t lock_t; + +#define spinlock_init(lock, name) spin_lock_init(lock) +#define init_spinlock(lock, name, ll) spin_lock_init(lock) +#define spinlock_destroy(lock) + +static inline unsigned long mutex_spinlock(lock_t *lock) +{ + spin_lock(lock); + return 0; +} + +/*ARGSUSED*/ +static inline void mutex_spinunlock(lock_t *lock, unsigned long s) +{ + spin_unlock(lock); +} + +static inline void nested_spinlock(lock_t *lock) +{ + spin_lock(lock); +} + +static inline void nested_spinunlock(lock_t *lock) +{ + spin_unlock(lock); +} + +#endif /* __XFS_SUPPORT_SPIN_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/sv.h linux-2.4.19-sgi211r3/fs/xfs/support/sv.h --- linux-2.4.19/fs/xfs/support/sv.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/sv.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Portions Copyright (c) 2002 Christoph Hellwig. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_SV_H__ +#define __XFS_SUPPORT_SV_H__ + +#include +#include +#include + +/* + * Synchronisation variables. + * + * (Parameters "pri", "svf" and "rts" are not implemented) + */ + +typedef struct sv_s { + wait_queue_head_t waiters; +} sv_t; + +#define SV_FIFO 0x0 /* sv_t is FIFO type */ +#define SV_LIFO 0x2 /* sv_t is LIFO type */ +#define SV_PRIO 0x4 /* sv_t is PRIO type */ +#define SV_KEYED 0x6 /* sv_t is KEYED type */ +#define SV_DEFAULT SV_FIFO + + +static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state, + unsigned long timeout) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue_exclusive(&sv->waiters, &wait); + set_current_state(state); + spin_unlock(lock); + + schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&sv->waiters, &wait); +} + +#define init_sv(sv,type,name,flag) \ + init_waitqueue_head(&(sv)->waiters) +#define sv_init(sv,flag,name) \ + init_waitqueue_head(&(sv)->waiters) +#define sv_destroy(sv) \ + /*NOTHING*/ +#define sv_wait(sv, pri, lock, s) \ + _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT) +#define sv_wait_sig(sv, pri, lock, s) \ + _sv_wait(sv, lock, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT) +#define sv_timedwait(sv, pri, lock, s, svf, ts, rts) \ + _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, timespec_to_jiffies(ts)) +#define sv_timedwait_sig(sv, pri, lock, s, svf, ts, rts) \ + _sv_wait(sv, lock, TASK_INTERRUPTIBLE, timespec_to_jiffies(ts)) +#define sv_signal(sv) \ + wake_up(&(sv)->waiters) +#define sv_broadcast(sv) \ + wake_up_all(&(sv)->waiters) + +#endif /* __XFS_SUPPORT_SV_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/time.h linux-2.4.19-sgi211r3/fs/xfs/support/time.h --- linux-2.4.19/fs/xfs/support/time.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/time.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_TIME_H__ +#define __XFS_SUPPORT_TIME_H__ + +#include +#include + +static inline void delay(long ticks) +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(ticks); +} + +static inline void nanotime(struct timespec *tvp) +{ + struct timeval tv; + + do_gettimeofday(&tv); + tvp->tv_sec = tv.tv_sec; + tvp->tv_nsec = tv.tv_usec * 1000; +} + +#endif /* __XFS_SUPPORT_TIME_H__ */ diff -Nur linux-2.4.19/fs/xfs/support/uuid.c linux-2.4.19-sgi211r3/fs/xfs/support/uuid.c --- linux-2.4.19/fs/xfs/support/uuid.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/uuid.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +#ifdef __sparc__ +#include +#else +#include +#endif + +#include +#include +#include "time.h" +#include "move.h" +#include "uuid.h" + +#ifndef CONFIG_NET +#define dev_get_by_name(x) (NULL) +#define dev_put(x) do { } while (0) +#endif + +/* NODE_SIZE is the number of bytes used for the node identifier portion. */ +#define NODE_SIZE 6 + +/* + * Total size must be 128 bits. N.B. definition of uuid_t in uuid.h! + */ +typedef struct { + u_int32_t uu_timelow; /* time "low" */ + u_int16_t uu_timemid; /* time "mid" */ + u_int16_t uu_timehi; /* time "hi" and version */ + u_int16_t uu_clockseq; /* "reserved" and clock sequence */ + u_int16_t uu_node[NODE_SIZE / 2]; /* ethernet hardware address */ +} uu_t; + +/* + * The Time Base Correction is the amount to add on to a UNIX-based + * time value (i.e. seconds since 1 Jan. 1970) to convert it to the + * time base for UUIDs (15 Oct. 1582). + */ +#define UUID_TBC 0x01B21DD2138140LL + +static short uuid_eaddr[NODE_SIZE / 2]; /* ethernet address */ +static __int64_t uuid_time; /* last time basis used */ +static u_int16_t uuid_clockseq; /* boot-time randomizer */ +DECLARE_MUTEX(uuid_lock); + +/* + * uuid_init - called from out of init_tbl[] + */ +void +uuid_init(void) +{ +} + +/* + * uuid_getnodeuniq - obtain the node unique fields of a UUID. + * + * This is not in any way a standard or condoned UUID function; + * it just something that's needed for user-level file handles. + */ +void +uuid_getnodeuniq(uuid_t *uuid, int fsid [2]) +{ + char *uu=(char*)uuid; + + /* on IRIX, this function assumes big-endian fields within + * the uuid, so we use INT_GET to get the same result on + * little-endian systems + */ + + fsid[0] = (INT_GET(*(u_int16_t*)(uu+8), ARCH_CONVERT) << 16) + + INT_GET(*(u_int16_t*)(uu+4), ARCH_CONVERT); + fsid[1] = INT_GET(*(u_int32_t*)(uu ), ARCH_CONVERT); +} + +void +uuid_create_nil(uuid_t *uuid) +{ + bzero(uuid, sizeof *uuid); +} + +int +uuid_is_nil(uuid_t *uuid) +{ + int i; + char *cp = (char *)uuid; + + if (uuid == NULL) + return B_TRUE; + /* implied check of version number here... */ + for (i = 0; i < sizeof *uuid; i++) + if (*cp++) return B_FALSE; /* not nil */ + return B_TRUE; /* is nil */ +} + +int +uuid_equal(uuid_t *uuid1, uuid_t *uuid2) +{ + return bcmp(uuid1, uuid2, sizeof(uuid_t)) ? B_FALSE : B_TRUE; +} + +/* + * Given a 128-bit uuid, return a 64-bit value by adding the top and bottom + * 64-bit words. NOTE: This function can not be changed EVER. Although + * brain-dead, some applications depend on this 64-bit value remaining + * persistent. Specifically, DMI vendors store the value as a persistent + * filehandle. + */ +__uint64_t +uuid_hash64(uuid_t *uuid) +{ + __uint64_t *sp = (__uint64_t *)uuid; + + return sp[0] + sp[1]; +} /* uuid_hash64 */ + +static void +get_eaddr(char *junk) +{ +#ifdef __sparc__ + memcpy(uuid_eaddr, idprom->id_ethaddr, 6); +#else + struct net_device *dev; + + dev = dev_get_by_name("eth0"); + if (!dev || !dev->addr_len) { + get_random_bytes(uuid_eaddr, sizeof(uuid_eaddr)); + } else { + memcpy(uuid_eaddr, dev->dev_addr, + dev->addr_lenaddr_len:sizeof(uuid_eaddr)); + dev_put(dev); + } +#endif +} + +/* + * uuid_create - kernel version, does the actual work + */ +void +uuid_create(uuid_t *uuid) +{ + int i; + uu_t *uu = (uu_t *)uuid; + static int uuid_have_eaddr = 0; /* ethernet addr inited? */ + static int uuid_is_init = 0; /* time/clockseq inited? */ + + down(&uuid_lock); + if (!uuid_is_init) { + timespec_t ts; + + nanotime(&ts); + /* + * The clock sequence must be initialized randomly. + */ + uuid_clockseq = ((unsigned long)jiffies & 0xfff) | 0x8000; + /* + * Initialize the uuid time, it's in 100 nanosecond + * units since a time base in 1582. + */ + uuid_time = ts.tv_sec * 10000000LL + + ts.tv_nsec / 100LL + + UUID_TBC; + uuid_is_init = 1; + } + if (!uuid_have_eaddr) { + uuid_have_eaddr = 1; + get_eaddr((char *)uuid_eaddr); + } + uuid_time++; + uu->uu_timelow = (u_int32_t)(uuid_time & 0x00000000ffffffffLL); + uu->uu_timemid = (u_int16_t)((uuid_time >> 32) & 0x0000ffff); + uu->uu_timehi = (u_int16_t)((uuid_time >> 48) & 0x00000fff) | 0x1000; + up(&uuid_lock); + uu->uu_clockseq = uuid_clockseq; + for (i = 0; i < (NODE_SIZE / 2); i++) + uu->uu_node [i] = uuid_eaddr [i]; +} + +int +uuid_compare(uuid_t *uuid1, uuid_t *uuid2) +{ + int i; + char *cp1 = (char *) uuid1; + char *cp2 = (char *) uuid2; + + if (uuid1 == NULL) { + if (uuid2 == NULL) { + return 0; /* equal because both are nil */ + } else { + return -1; /* uuid1 nil, so precedes uuid2 */ + } + } else if (uuid2 == NULL) { + return 1; + } + + /* implied check of version number here... */ + for (i = 0; i < sizeof(uuid_t); i++) { + if (*cp1 < *cp2) + return -1; + if (*cp1++ > *cp2++) + return 1; + } + return 0; /* they're equal */ +} diff -Nur linux-2.4.19/fs/xfs/support/uuid.h linux-2.4.19-sgi211r3/fs/xfs/support/uuid.h --- linux-2.4.19/fs/xfs/support/uuid.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/support/uuid.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_UUID_H__ +#define __XFS_SUPPORT_UUID_H__ + +void uuid_create_nil(uuid_t *uuid); +int uuid_is_nil(uuid_t *uuid); +int uuid_equal(uuid_t *uuid1, uuid_t *uuid2); +void uuid_getnodeuniq(uuid_t *uuid, int fsid [2]); +__uint64_t uuid_hash64(uuid_t *uuid); + +#endif /* __XFS_SUPPORT_UUID_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs.h linux-2.4.19-sgi211r3/fs/xfs/xfs.h --- linux-2.4.19/fs/xfs/xfs.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_H__ +#define __XFS_H__ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#endif /* __XFS_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_acl.c linux-2.4.19-sgi211r3/fs/xfs/xfs_acl.c --- linux-2.4.19/fs/xfs/xfs_acl.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_acl.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +STATIC int xfs_acl_setmode(vnode_t *, xfs_acl_t *, int *); +STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); +STATIC void xfs_acl_get_endian(xfs_acl_t *); +STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); +STATIC int xfs_acl_invalid(xfs_acl_t *); +STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); +STATIC void xfs_acl_get_attr(vnode_t *, xfs_acl_t *, int, int, int *); +STATIC void xfs_acl_set_attr(vnode_t *, xfs_acl_t *, int, int *); +STATIC int xfs_acl_allow_set(vnode_t *, int); + +kmem_zone_t *xfs_acl_zone; + + +/* + * Test for existence of access ACL attribute as efficiently as possible. + */ +int +xfs_acl_vhasacl_access( + vnode_t *vp) +{ + int error; + + xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error); + return (error == 0); +} + +/* + * Test for existence of default ACL attribute as efficiently as possible. + */ +int +xfs_acl_vhasacl_default( + vnode_t *vp) +{ + int error; + + if (vp->v_type != VDIR) + return 0; + xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error); + return (error == 0); +} + +/* + * Convert from extended attribute representation to in-memory for XFS. + */ +STATIC int +posix_acl_xattr_to_xfs( + posix_acl_xattr_header *src, + size_t size, + xfs_acl_t *dest) +{ + posix_acl_xattr_entry *src_entry; + xfs_acl_entry_t *dest_entry; + int n; + + if (!src || !dest) + return EINVAL; + + if (size < sizeof(posix_acl_xattr_header)) + return EINVAL; + + if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return EINVAL; + + memset(dest, 0, sizeof(xfs_acl_t)); + dest->acl_cnt = posix_acl_xattr_count(size); + if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES) + return EINVAL; + + /* + * acl_set_file(3) may request that we set default ACLs with + * zero length -- defend (gracefully) against that here. + */ + if (!dest->acl_cnt) + return 0; + + src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src)); + dest_entry = &dest->acl_entry[0]; + + for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) { + dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm); + if (_ACL_PERM_INVALID(dest_entry->ae_perm)) + return EINVAL; + dest_entry->ae_tag = le16_to_cpu(src_entry->e_tag); + switch(dest_entry->ae_tag) { + case ACL_USER: + case ACL_GROUP: + dest_entry->ae_id = le32_to_cpu(src_entry->e_id); + break; + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + dest_entry->ae_id = ACL_UNDEFINED_ID; + break; + default: + return EINVAL; + } + } + if (xfs_acl_invalid(dest)) + return EINVAL; + + return 0; +} + +/* + * Comparison function called from qsort(). + * Primary key is ae_tag, secondary key is ae_id. + */ +STATIC int +xfs_acl_entry_compare( + const void *va, + const void *vb) +{ + xfs_acl_entry_t *a = (xfs_acl_entry_t *)va, + *b = (xfs_acl_entry_t *)vb; + + if (a->ae_tag == b->ae_tag) + return (a->ae_id - b->ae_id); + return (a->ae_tag - b->ae_tag); +} + +/* + * Convert from in-memory XFS to extended attribute representation. + */ +STATIC int +posix_acl_xfs_to_xattr( + xfs_acl_t *src, + posix_acl_xattr_header *dest, + size_t size) +{ + int n; + size_t new_size = posix_acl_xattr_size(src->acl_cnt); + posix_acl_xattr_entry *dest_entry; + xfs_acl_entry_t *src_entry; + + if (size < new_size) + return -ERANGE; + + /* Need to sort src XFS ACL by */ + qsort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]), + xfs_acl_entry_compare); + + dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); + dest_entry = &dest->a_entries[0]; + src_entry = &src->acl_entry[0]; + for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) { + dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm); + if (_ACL_PERM_INVALID(src_entry->ae_perm)) + return -EINVAL; + dest_entry->e_tag = cpu_to_le16(src_entry->ae_tag); + switch (src_entry->ae_tag) { + case ACL_USER: + case ACL_GROUP: + dest_entry->e_id = cpu_to_le32(src_entry->ae_id); + break; + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); + break; + default: + return -EINVAL; + } + } + return new_size; +} + +int +xfs_acl_vget( + vnode_t *vp, + void *acl, + size_t size, + int kind) +{ + int error; + xfs_acl_t *xfs_acl; + posix_acl_xattr_header *ext_acl = acl; + + VN_HOLD(vp); + if ((error = _MAC_VACCESS(vp, NULL, VREAD))) + goto out; + if (!(_ACL_ALLOC(xfs_acl))) { + error = ENOMEM; + goto out; + } + + memset(xfs_acl, 0, sizeof(xfs_acl_t)); + xfs_acl_get_attr(vp, xfs_acl, kind, size? 0 : ATTR_KERNOVAL, &error); + if (error) + goto out; + + if (!size) { + error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES); + } else { + if (xfs_acl_invalid(xfs_acl)) { + error = EINVAL; + goto out; + } + if (kind == _ACL_TYPE_ACCESS) { + vattr_t va; + + va.va_mask = AT_MODE; + VOP_GETATTR(vp, &va, 0, sys_cred, error); + if (error) + goto out; + xfs_acl_sync_mode(va.va_mode, xfs_acl); + } + error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size); + } +out: + VN_RELE(vp); + _ACL_FREE(xfs_acl); + return -error; +} + +int +xfs_acl_vremove( + vnode_t *vp, + int kind) +{ + int error; + + VN_HOLD(vp); + error = xfs_acl_allow_set(vp, kind); + if (!error) { + VOP_ATTR_REMOVE(vp, kind == _ACL_TYPE_DEFAULT? + SGI_ACL_DEFAULT: SGI_ACL_FILE, + ATTR_ROOT, sys_cred, error); + if (error == ENOATTR) + error = 0; /* 'scool */ + } + VN_RELE(vp); + return -error; +} + +int +xfs_acl_vset( + vnode_t *vp, + void *acl, + size_t size, + int kind) +{ + posix_acl_xattr_header *ext_acl = acl; + xfs_acl_t *xfs_acl; + int error; + int basicperms = 0; /* more than std unix perms? */ + + if (!acl) + return -EINVAL; + + if (!(_ACL_ALLOC(xfs_acl))) + return -ENOMEM; + + error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl); + if (error) { + _ACL_FREE(xfs_acl); + return -error; + } + if (!xfs_acl->acl_cnt) { + _ACL_FREE(xfs_acl); + return 0; + } + + VN_HOLD(vp); + error = xfs_acl_allow_set(vp, kind); + if (error) + goto out; + + /* Incoming ACL exists, set file mode based on its value */ + if (kind == _ACL_TYPE_ACCESS) + xfs_acl_setmode(vp, xfs_acl, &basicperms); + + /* + * If we have more than std unix permissions, set up the actual attr. + * Otherwise, delete any existing attr. This prevents us from + * having actual attrs for permissions that can be stored in the + * standard permission bits. + */ + if (!basicperms) { + xfs_acl_set_attr(vp, xfs_acl, kind, &error); + } else { + xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); + } + + +out: + VN_RELE(vp); + _ACL_FREE(xfs_acl); + return -error; +} + +int +xfs_acl_iaccess( + xfs_inode_t *ip, + mode_t mode, + cred_t *cr) +{ + xfs_acl_t *acl; + int error; + + if (!(_ACL_ALLOC(acl))) + return -1; + + /* If the file has no ACL return -1. */ + if (xfs_attr_fetch(ip, SGI_ACL_FILE, (char *)acl, sizeof(xfs_acl_t))) { + _ACL_FREE(acl); + return -1; + } + xfs_acl_get_endian(acl); + + /* If the file has an empty ACL return -1. */ + if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) { + _ACL_FREE(acl); + return -1; + } + + /* Synchronize ACL with mode bits */ + xfs_acl_sync_mode(ip->i_d.di_mode, acl); + + error = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr); + _ACL_FREE(acl); + return error; +} + +STATIC int +xfs_acl_allow_set( + vnode_t *vp, + int kind) +{ + vattr_t va; + int error; + + if (kind == _ACL_TYPE_DEFAULT && vp->v_type != VDIR) + return ENOTDIR; + if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + return EROFS; + if ((error = _MAC_VACCESS(vp, NULL, VWRITE))) + return error; + va.va_mask = AT_UID; + VOP_GETATTR(vp, &va, 0, NULL, error); + if (error) + return error; + if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) + return EPERM; + return error; +} + +/* + * Look for any effective exec access, to allow CAP_DAC_OVERRIDE for exec. + * Ignore checking for exec in USER_OBJ when there is no mask, because + * in this "minimal acl" case we don't have any actual acls, and we + * won't even be here. + */ +STATIC int +xfs_acl_find_any_exec( + xfs_acl_t *fap) +{ + int i; + int masked_aces = 0; + int mask = 0; + + for (i = 0; i < fap->acl_cnt; i++) { + if (fap->acl_entry[i].ae_perm & ACL_EXECUTE) { + if (fap->acl_entry[i].ae_tag & (ACL_USER_OBJ|ACL_OTHER)) + return 1; + + if (fap->acl_entry[i].ae_tag == ACL_MASK) + mask = fap->acl_entry[i].ae_perm; + else + masked_aces |= fap->acl_entry[i].ae_perm; + + if ((mask & masked_aces) & ACL_EXECUTE) + return 1; + } + } + + return 0; +} + +/* + * The access control process to determine the access permission: + * if uid == file owner id, use the file owner bits. + * if gid == file owner group id, use the file group bits. + * scan ACL for a maching user or group, and use matched entry + * permission. Use total permissions of all matching group entries, + * until all acl entries are exhausted. The final permission produced + * by matching acl entry or entries needs to be & with group permission. + * if not owner, owning group, or matching entry in ACL, use file + * other bits. Don't allow CAP_DAC_OVERRIDE on exec access unless + * there is some effective exec access somewhere. + */ +STATIC int +xfs_acl_capability_check( + mode_t mode, + cred_t *cr, + xfs_acl_t *fap) +{ + if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH)) + return EACCES; + if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE)) + return EACCES; + if ((mode & ACL_EXECUTE) && + (!capable_cred(cr, CAP_DAC_OVERRIDE) || + !xfs_acl_find_any_exec(fap))) { + return EACCES; + } + + return 0; +} + +/* + * Note: cr is only used here for the capability check if the ACL test fails. + * It is not used to find out the credentials uid or groups etc, as was + * done in IRIX. It is assumed that the uid and groups for the current + * thread are taken from "current" instead of the cr parameter. + */ +STATIC int +xfs_acl_access( + uid_t fuid, + gid_t fgid, + xfs_acl_t *fap, + mode_t md, + cred_t *cr) +{ + xfs_acl_entry_t matched; + int i, allows; + int maskallows = -1; /* true, but not 1, either */ + int seen_userobj = 0; + + matched.ae_tag = 0; /* Invalid type */ + md >>= 6; /* Normalize the bits for comparison */ + + for (i = 0; i < fap->acl_cnt; i++) { + /* + * Break out if we've got a user_obj entry or + * a user entry and the mask (and have processed USER_OBJ) + */ + if (matched.ae_tag == ACL_USER_OBJ) + break; + if (matched.ae_tag == ACL_USER) { + if (maskallows != -1 && seen_userobj) + break; + if (fap->acl_entry[i].ae_tag != ACL_MASK && + fap->acl_entry[i].ae_tag != ACL_USER_OBJ) + continue; + } + /* True if this entry allows the requested access */ + allows = ((fap->acl_entry[i].ae_perm & md) == md); + + switch (fap->acl_entry[i].ae_tag) { + case ACL_USER_OBJ: + seen_userobj = 1; + if (fuid != current->fsuid) + continue; + matched.ae_tag = ACL_USER_OBJ; + matched.ae_perm = allows; + break; + case ACL_USER: + if (fap->acl_entry[i].ae_id != current->fsuid) + continue; + matched.ae_tag = ACL_USER; + matched.ae_perm = allows; + break; + case ACL_GROUP_OBJ: + if ((matched.ae_tag == ACL_GROUP_OBJ || + matched.ae_tag == ACL_GROUP) && !allows) + continue; + if (!in_group_p(fgid)) + continue; + matched.ae_tag = ACL_GROUP_OBJ; + matched.ae_perm = allows; + break; + case ACL_GROUP: + if ((matched.ae_tag == ACL_GROUP_OBJ || + matched.ae_tag == ACL_GROUP) && !allows) + continue; + if (!in_group_p(fap->acl_entry[i].ae_id)) + continue; + matched.ae_tag = ACL_GROUP; + matched.ae_perm = allows; + break; + case ACL_MASK: + maskallows = allows; + break; + case ACL_OTHER: + if (matched.ae_tag != 0) + continue; + matched.ae_tag = ACL_OTHER; + matched.ae_perm = allows; + break; + } + } + /* + * First possibility is that no matched entry allows access. + * The capability to override DAC may exist, so check for it. + */ + switch (matched.ae_tag) { + case ACL_OTHER: + case ACL_USER_OBJ: + if (matched.ae_perm) + return 0; + break; + case ACL_USER: + case ACL_GROUP_OBJ: + case ACL_GROUP: + if (maskallows && matched.ae_perm) + return 0; + break; + case 0: + break; + } + + return xfs_acl_capability_check(md, cr, fap); +} + +/* + * ACL validity checker. + * This acl validation routine checks each ACL entry read in makes sense. + */ +STATIC int +xfs_acl_invalid( + xfs_acl_t *aclp) +{ + xfs_acl_entry_t *entry, *e; + int user = 0, group = 0, other = 0, mask = 0; + int mask_required = 0; + int i, j; + + if (!aclp) + goto acl_invalid; + + if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES) + goto acl_invalid; + + for (i = 0; i < aclp->acl_cnt; i++) { + entry = &aclp->acl_entry[i]; + switch (entry->ae_tag) { + case ACL_USER_OBJ: + if (user++) + goto acl_invalid; + break; + case ACL_GROUP_OBJ: + if (group++) + goto acl_invalid; + break; + case ACL_OTHER: + if (other++) + goto acl_invalid; + break; + case ACL_USER: + case ACL_GROUP: + for (j = i + 1; j < aclp->acl_cnt; j++) { + e = &aclp->acl_entry[j]; + if (e->ae_id == entry->ae_id && + e->ae_tag == entry->ae_tag) + goto acl_invalid; + } + mask_required++; + break; + case ACL_MASK: + if (mask++) + goto acl_invalid; + break; + default: + goto acl_invalid; + } + } + if (!user || !group || !other || (mask_required && !mask)) + goto acl_invalid; + else + return 0; +acl_invalid: + return EINVAL; +} + +/* + * Do ACL endian conversion. + */ +STATIC void +xfs_acl_get_endian( + xfs_acl_t *aclp) +{ + xfs_acl_entry_t *ace, *end; + + INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); + end = &aclp->acl_entry[0]+aclp->acl_cnt; + for (ace = &aclp->acl_entry[0]; ace < end; ace++) { + INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag); + INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id); + INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm); + } +} + +/* + * Get the ACL from the EA and do endian conversion. + */ +STATIC void +xfs_acl_get_attr( + vnode_t *vp, + xfs_acl_t *aclp, + int kind, + int flags, + int *error) +{ + int len = sizeof(xfs_acl_t); + + flags |= ATTR_ROOT; + VOP_ATTR_GET(vp, + kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT, + (char *)aclp, &len, flags, sys_cred, *error); + if (*error || (flags & ATTR_KERNOVAL)) + return; + xfs_acl_get_endian(aclp); +} + +/* + * Set the EA with the ACL and do endian conversion. + */ +STATIC void +xfs_acl_set_attr( + vnode_t *vp, + xfs_acl_t *aclp, + int kind, + int *error) +{ + xfs_acl_entry_t *ace, *newace, *end; + xfs_acl_t *newacl; + int len; + + if (!(_ACL_ALLOC(newacl))) { + *error = ENOMEM; + return; + } + + len = sizeof(xfs_acl_t) - + (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt)); + end = &aclp->acl_entry[0]+aclp->acl_cnt; + for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0]; + ace < end; + ace++, newace++) { + INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag); + INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id); + INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); + } + INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); + VOP_ATTR_SET(vp, + kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT, + (char *)newacl, len, ATTR_ROOT, sys_cred, *error); + _ACL_FREE(newacl); +} + +int +xfs_acl_vtoacl( + vnode_t *vp, + xfs_acl_t *access_acl, + xfs_acl_t *default_acl) +{ + vattr_t va; + int error = 0; + + if (access_acl) { + /* + * Get the Access ACL and the mode. If either cannot + * be obtained for some reason, invalidate the access ACL. + */ + xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error); + if (!error) { + /* Got the ACL, need the mode... */ + va.va_mask = AT_MODE; + VOP_GETATTR(vp, &va, 0, sys_cred, error); + } + + if (error) + access_acl->acl_cnt = XFS_ACL_NOT_PRESENT; + else /* We have a good ACL and the file mode, synchronize. */ + xfs_acl_sync_mode(va.va_mode, access_acl); + } + + if (default_acl) { + xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error); + if (error) + default_acl->acl_cnt = XFS_ACL_NOT_PRESENT; + } + return error; +} + +/* + * This function retrieves the parent directory's acl, processes it + * and lets the child inherit the acl(s) that it should. + */ +int +xfs_acl_inherit( + vnode_t *vp, + vattr_t *vap, + xfs_acl_t *pdaclp) +{ + xfs_acl_t *cacl; + int error = 0; + int basicperms = 0; + + /* + * If the parent does not have a default ACL, or it's an + * invalid ACL, we're done. + */ + if (!vp) + return 0; + if (!pdaclp || xfs_acl_invalid(pdaclp)) + return 0; + + /* + * Copy the default ACL of the containing directory to + * the access ACL of the new file and use the mode that + * was passed in to set up the correct initial values for + * the u::,g::[m::], and o:: entries. This is what makes + * umask() "work" with ACL's. + */ + + if (!(_ACL_ALLOC(cacl))) + return ENOMEM; + + memcpy(cacl, pdaclp, sizeof(xfs_acl_t)); + xfs_acl_filter_mode(vap->va_mode, cacl); + xfs_acl_setmode(vp, cacl, &basicperms); + + /* + * Set the Default and Access ACL on the file. The mode is already + * set on the file, so we don't need to worry about that. + * + * If the new file is a directory, its default ACL is a copy of + * the containing directory's default ACL. + */ + if (vp->v_type == VDIR) + xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error); + if (!error && !basicperms) + xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error); + _ACL_FREE(cacl); + return error; +} + +/* + * Set up the correct mode on the file based on the supplied ACL. This + * makes sure that the mode on the file reflects the state of the + * u::,g::[m::], and o:: entries in the ACL. Since the mode is where + * the ACL is going to get the permissions for these entries, we must + * synchronize the mode whenever we set the ACL on a file. + */ +STATIC int +xfs_acl_setmode( + vnode_t *vp, + xfs_acl_t *acl, + int *basicperms) +{ + vattr_t va; + xfs_acl_entry_t *ap; + xfs_acl_entry_t *gap = NULL; + int i, error, nomask = 1; + + *basicperms = 1; + + if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) + return 0; + + /* + * Copy the u::, g::, o::, and m:: bits from the ACL into the + * mode. The m:: bits take precedence over the g:: bits. + */ + va.va_mask = AT_MODE; + VOP_GETATTR(vp, &va, 0, sys_cred, error); + if (error) + return error; + + va.va_mask = AT_MODE; + va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); + ap = acl->acl_entry; + for (i = 0; i < acl->acl_cnt; ++i) { + switch (ap->ae_tag) { + case ACL_USER_OBJ: + va.va_mode |= ap->ae_perm << 6; + break; + case ACL_GROUP_OBJ: + gap = ap; + break; + case ACL_MASK: /* more than just standard modes */ + nomask = 0; + va.va_mode |= ap->ae_perm << 3; + *basicperms = 0; + break; + case ACL_OTHER: + va.va_mode |= ap->ae_perm; + break; + default: /* more than just standard modes */ + *basicperms = 0; + break; + } + ap++; + } + + /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ + if (gap && nomask) + va.va_mode |= gap->ae_perm << 3; + + VOP_SETATTR(vp, &va, 0, sys_cred, error); + return error; +} + +/* + * The permissions for the special ACL entries (u::, g::[m::], o::) are + * actually stored in the file mode (if there is both a group and a mask, + * the group is stored in the ACL entry and the mask is stored on the file). + * This allows the mode to remain automatically in sync with the ACL without + * the need for a call-back to the ACL system at every point where the mode + * could change. This function takes the permissions from the specified mode + * and places it in the supplied ACL. + * + * This implementation draws its validity from the fact that, when the ACL + * was assigned, the mode was copied from the ACL. + * If the mode did not change, therefore, the mode remains exactly what was + * taken from the special ACL entries at assignment. + * If a subsequent chmod() was done, the POSIX spec says that the change in + * mode must cause an update to the ACL seen at user level and used for + * access checks. Before and after a mode change, therefore, the file mode + * most accurately reflects what the special ACL entries should permit/deny. + * + * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly, + * the existing mode bits will override whatever is in the + * ACL. Similarly, if there is a pre-existing ACL that was + * never in sync with its mode (owing to a bug in 6.5 and + * before), it will now magically (or mystically) be + * synchronized. This could cause slight astonishment, but + * it is better than inconsistent permissions. + * + * The supplied ACL is a template that may contain any combination + * of special entries. These are treated as place holders when we fill + * out the ACL. This routine does not add or remove special entries, it + * simply unites each special entry with its associated set of permissions. + */ +STATIC void +xfs_acl_sync_mode( + mode_t mode, + xfs_acl_t *acl) +{ + int i, nomask = 1; + xfs_acl_entry_t *ap; + xfs_acl_entry_t *gap = NULL; + + /* + * Set ACL entries. POSIX1003.1eD16 requires that the MASK + * be set instead of the GROUP entry, if there is a MASK. + */ + for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { + switch (ap->ae_tag) { + case ACL_USER_OBJ: + ap->ae_perm = (mode >> 6) & 0x7; + break; + case ACL_GROUP_OBJ: + gap = ap; + break; + case ACL_MASK: + nomask = 0; + ap->ae_perm = (mode >> 3) & 0x7; + break; + case ACL_OTHER: + ap->ae_perm = mode & 0x7; + break; + default: + break; + } + } + /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ + if (gap && nomask) + gap->ae_perm = (mode >> 3) & 0x7; +} + +/* + * When inheriting an Access ACL from a directory Default ACL, + * the ACL bits are set to the intersection of the ACL default + * permission bits and the file permission bits in mode. If there + * are no permission bits on the file then we must not give them + * the ACL. This is what what makes umask() work with ACLs. + */ +STATIC void +xfs_acl_filter_mode( + mode_t mode, + xfs_acl_t *acl) +{ + int i, nomask = 1; + xfs_acl_entry_t *ap; + xfs_acl_entry_t *gap = NULL; + + /* + * Set ACL entries. POSIX1003.1eD16 requires that the MASK + * be merged with GROUP entry, if there is a MASK. + */ + for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { + switch (ap->ae_tag) { + case ACL_USER_OBJ: + ap->ae_perm &= (mode >> 6) & 0x7; + break; + case ACL_GROUP_OBJ: + gap = ap; + break; + case ACL_MASK: + nomask = 0; + ap->ae_perm &= (mode >> 3) & 0x7; + break; + case ACL_OTHER: + ap->ae_perm &= mode & 0x7; + break; + default: + break; + } + } + /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ + if (gap && nomask) + gap->ae_perm &= (mode >> 3) & 0x7; +} diff -Nur linux-2.4.19/fs/xfs/xfs_acl.h linux-2.4.19-sgi211r3/fs/xfs/xfs_acl.h --- linux-2.4.19/fs/xfs/xfs_acl.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_acl.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ACL_H__ +#define __XFS_ACL_H__ + +/* + * Access Control Lists + */ +typedef __uint16_t xfs_acl_perm_t; +typedef __int32_t xfs_acl_type_t; +typedef __int32_t xfs_acl_tag_t; +typedef __int32_t xfs_acl_id_t; + +#define XFS_ACL_MAX_ENTRIES 25 +#define XFS_ACL_NOT_PRESENT (-1) + +typedef struct xfs_acl_entry { + xfs_acl_tag_t ae_tag; + xfs_acl_id_t ae_id; + xfs_acl_perm_t ae_perm; +} xfs_acl_entry_t; + +typedef struct xfs_acl { + __int32_t acl_cnt; + xfs_acl_entry_t acl_entry[XFS_ACL_MAX_ENTRIES]; +} xfs_acl_t; + +/* On-disk XFS extended attribute names */ +#define SGI_ACL_FILE "SGI_ACL_FILE" +#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" +#define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) +#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) + + +#ifdef __KERNEL__ + +#ifdef CONFIG_FS_POSIX_ACL + +struct vattr; +struct vnode; +struct xfs_inode; + +extern int xfs_acl_inherit(struct vnode *, struct vattr *, xfs_acl_t *); +extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *); +extern int xfs_acl_get(struct vnode *, xfs_acl_t *, xfs_acl_t *); +extern int xfs_acl_set(struct vnode *, xfs_acl_t *, xfs_acl_t *); +extern int xfs_acl_vtoacl(struct vnode *, xfs_acl_t *, xfs_acl_t *); +extern int xfs_acl_vhasacl_access(struct vnode *); +extern int xfs_acl_vhasacl_default(struct vnode *); +extern int xfs_acl_vset(struct vnode *, void *, size_t, int); +extern int xfs_acl_vget(struct vnode *, void *, size_t, int); +extern int xfs_acl_vremove(struct vnode *vp, int); + +extern struct kmem_zone *xfs_acl_zone; + +#define _ACL_TYPE_ACCESS 1 +#define _ACL_TYPE_DEFAULT 2 +#define _ACL_PERM_INVALID(perm) ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) + +#define _ACL_DECL(a) xfs_acl_t *(a) = NULL +#define _ACL_ALLOC(a) ((a) = kmem_zone_alloc(xfs_acl_zone, KM_SLEEP)) +#define _ACL_FREE(a) ((a)? kmem_zone_free(xfs_acl_zone, (a)) : 0) +#define _ACL_ZONE_INIT(z,name) ((z) = kmem_zone_init(sizeof(xfs_acl_t), name)) +#define _ACL_ZONE_DESTROY(z) (kmem_cache_destroy(z)) +#define _ACL_INHERIT(c,v,d) (xfs_acl_inherit(c,v,d)) +#define _ACL_GET_ACCESS(pv,pa) (xfs_acl_vtoacl(pv,pa,NULL) == 0) +#define _ACL_GET_DEFAULT(pv,pd) (xfs_acl_vtoacl(pv,NULL,pd) == 0) +#define _ACL_ACCESS_EXISTS xfs_acl_vhasacl_access +#define _ACL_DEFAULT_EXISTS xfs_acl_vhasacl_default +#define _ACL_XFS_IACCESS(i,m,c) (XFS_IFORK_Q(i) ? xfs_acl_iaccess(i,m,c) : -1) + +#else +#define xfs_acl_vset(v,p,sz,t) (-EOPNOTSUPP) +#define xfs_acl_vget(v,p,sz,t) (-EOPNOTSUPP) +#define xfs_acl_vremove(v,t) (-EOPNOTSUPP) +#define _ACL_DECL(a) ((void)0) +#define _ACL_ALLOC(a) (1) /* successfully allocate nothing */ +#define _ACL_FREE(a) ((void)0) +#define _ACL_ZONE_INIT(z,name) ((void)0) +#define _ACL_ZONE_DESTROY(z) ((void)0) +#define _ACL_INHERIT(c,v,d) (0) +#define _ACL_GET_ACCESS(pv,pa) (0) +#define _ACL_GET_DEFAULT(pv,pd) (0) +#define _ACL_ACCESS_EXISTS (NULL) +#define _ACL_DEFAULT_EXISTS (NULL) +#define _ACL_XFS_IACCESS(i,m,c) (-1) +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_ACL_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_ag.h linux-2.4.19-sgi211r3/fs/xfs/xfs_ag.h --- linux-2.4.19/fs/xfs/xfs_ag.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_ag.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_AG_H__ +#define __XFS_AG_H__ + +/* + * Allocation group header + * This is divided into three structures, placed in sequential 512-byte + * buffers after a copy of the superblock (also in a 512-byte buffer). + */ + +struct xfs_buf; +struct xfs_mount; +struct xfs_trans; + +#define XFS_AGF_MAGIC 0x58414746 /* 'XAGF' */ +#define XFS_AGI_MAGIC 0x58414749 /* 'XAGI' */ +#define XFS_AGF_VERSION 1 +#define XFS_AGI_VERSION 1 +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGF_GOOD_VERSION) +int xfs_agf_good_version(unsigned v); +#define XFS_AGF_GOOD_VERSION(v) xfs_agf_good_version(v) +#else +#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGI_GOOD_VERSION) +int xfs_agi_good_version(unsigned v); +#define XFS_AGI_GOOD_VERSION(v) xfs_agi_good_version(v) +#else +#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION) +#endif + +/* + * Btree number 0 is bno, 1 is cnt. This value gives the size of the + * arrays below. + */ +#define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1) + +/* + * The second word of agf_levels in the first a.g. overlaps the EFS + * superblock's magic number. Since the magic numbers valid for EFS + * are > 64k, our value cannot be confused for an EFS superblock's. + */ + +typedef struct xfs_agf +{ + /* + * Common allocation group header information + */ + __uint32_t agf_magicnum; /* magic number == XFS_AGF_MAGIC */ + __uint32_t agf_versionnum; /* header version == XFS_AGF_VERSION */ + xfs_agnumber_t agf_seqno; /* sequence # starting from 0 */ + xfs_agblock_t agf_length; /* size in blocks of a.g. */ + /* + * Freespace information + */ + xfs_agblock_t agf_roots[XFS_BTNUM_AGF]; /* root blocks */ + __uint32_t agf_spare0; /* spare field */ + __uint32_t agf_levels[XFS_BTNUM_AGF]; /* btree levels */ + __uint32_t agf_spare1; /* spare field */ + __uint32_t agf_flfirst; /* first freelist block's index */ + __uint32_t agf_fllast; /* last freelist block's index */ + __uint32_t agf_flcount; /* count of blocks in freelist */ + xfs_extlen_t agf_freeblks; /* total free blocks */ + xfs_extlen_t agf_longest; /* longest free space */ +} xfs_agf_t; + +#define XFS_AGF_MAGICNUM 0x00000001 +#define XFS_AGF_VERSIONNUM 0x00000002 +#define XFS_AGF_SEQNO 0x00000004 +#define XFS_AGF_LENGTH 0x00000008 +#define XFS_AGF_ROOTS 0x00000010 +#define XFS_AGF_LEVELS 0x00000020 +#define XFS_AGF_FLFIRST 0x00000040 +#define XFS_AGF_FLLAST 0x00000080 +#define XFS_AGF_FLCOUNT 0x00000100 +#define XFS_AGF_FREEBLKS 0x00000200 +#define XFS_AGF_LONGEST 0x00000400 +#define XFS_AGF_NUM_BITS 11 +#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1) + +/* disk block (xfs_daddr_t) in the AG */ +#define XFS_AGF_DADDR ((xfs_daddr_t)1) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGF_BLOCK) +xfs_agblock_t xfs_agf_block(struct xfs_mount *mp); +#define XFS_AGF_BLOCK(mp) xfs_agf_block(mp) +#else +#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR) +#endif + +/* + * Size of the unlinked inode hash table in the agi. + */ +#define XFS_AGI_UNLINKED_BUCKETS 64 + +typedef struct xfs_agi +{ + /* + * Common allocation group header information + */ + __uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */ + __uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */ + xfs_agnumber_t agi_seqno; /* sequence # starting from 0 */ + xfs_agblock_t agi_length; /* size in blocks of a.g. */ + /* + * Inode information + * Inodes are mapped by interpreting the inode number, so no + * mapping data is needed here. + */ + xfs_agino_t agi_count; /* count of allocated inodes */ + xfs_agblock_t agi_root; /* root of inode btree */ + __uint32_t agi_level; /* levels in inode btree */ + xfs_agino_t agi_freecount; /* number of free inodes */ + xfs_agino_t agi_newino; /* new inode just allocated */ + xfs_agino_t agi_dirino; /* last directory inode chunk */ + /* + * Hash table of inodes which have been unlinked but are + * still being referenced. + */ + xfs_agino_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; +} xfs_agi_t; + +#define XFS_AGI_MAGICNUM 0x00000001 +#define XFS_AGI_VERSIONNUM 0x00000002 +#define XFS_AGI_SEQNO 0x00000004 +#define XFS_AGI_LENGTH 0x00000008 +#define XFS_AGI_COUNT 0x00000010 +#define XFS_AGI_ROOT 0x00000020 +#define XFS_AGI_LEVEL 0x00000040 +#define XFS_AGI_FREECOUNT 0x00000080 +#define XFS_AGI_NEWINO 0x00000100 +#define XFS_AGI_DIRINO 0x00000200 +#define XFS_AGI_UNLINKED 0x00000400 +#define XFS_AGI_NUM_BITS 11 +#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1) + +/* disk block (xfs_daddr_t) in the AG */ +#define XFS_AGI_DADDR ((xfs_daddr_t)2) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGI_BLOCK) +xfs_agblock_t xfs_agi_block(struct xfs_mount *mp); +#define XFS_AGI_BLOCK(mp) xfs_agi_block(mp) +#else +#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR) +#endif + +/* + * The third a.g. block contains the a.g. freelist, an array + * of block pointers to blocks owned by the allocation btree code. + */ +#define XFS_AGFL_DADDR ((xfs_daddr_t)3) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGFL_BLOCK) +xfs_agblock_t xfs_agfl_block(struct xfs_mount *mp); +#define XFS_AGFL_BLOCK(mp) xfs_agfl_block(mp) +#else +#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR) +#endif +#define XFS_AGFL_SIZE (BBSIZE / sizeof(xfs_agblock_t)) +typedef struct xfs_agfl +{ + xfs_agblock_t agfl_bno[XFS_AGFL_SIZE]; +} xfs_agfl_t; + +/* + * Busy block/extent entry. Used in perag to mark blocks that have been freed + * but whose transactions aren't committed to disk yet. + */ +typedef struct xfs_perag_busy { + xfs_agblock_t busy_start; + xfs_extlen_t busy_length; + struct xfs_trans *busy_tp; /* transaction that did the free */ +} xfs_perag_busy_t; + +/* + * Per-ag incore structure, copies of information in agf and agi, + * to improve the performance of allocation group selection. + * + * pick sizes which fit in allocation buckets well + */ +#if (BITS_PER_LONG == 32) +#define XFS_PAGB_NUM_SLOTS 84 +#elif (BITS_PER_LONG == 64) +#define XFS_PAGB_NUM_SLOTS 128 +#endif + +typedef struct xfs_perag +{ + char pagf_init; /* this agf's entry is initialized */ + char pagi_init; /* this agi's entry is initialized */ + char pagf_metadata; /* the agf is prefered to be metadata */ + char pagi_inodeok; /* The agi is ok for inodes */ + __uint8_t pagf_levels[XFS_BTNUM_AGF]; + /* # of levels in bno & cnt btree */ + __uint32_t pagf_flcount; /* count of blocks in freelist */ + xfs_extlen_t pagf_freeblks; /* total free blocks */ + xfs_extlen_t pagf_longest; /* longest free space */ + xfs_agino_t pagi_freecount; /* number of free inodes */ +#ifdef __KERNEL__ + lock_t pagb_lock; /* lock for pagb_list */ +#endif + int pagb_count; /* pagb slots in use */ + xfs_perag_busy_t *pagb_list; /* unstable blocks */ +} xfs_perag_t; + +#define XFS_AG_MIN_BYTES (1LL << 24) /* 16 MB */ +#define XFS_AG_BEST_BYTES (1LL << 30) /* 1 GB */ +#define XFS_AG_MAX_BYTES (1LL << 32) /* 4 GB */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MIN_BLOCKS) +xfs_extlen_t xfs_ag_min_blocks(int bl); +#define XFS_AG_MIN_BLOCKS(bl) xfs_ag_min_blocks(bl) +#else +#define XFS_AG_MIN_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MIN_BYTES >> bl)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_BEST_BLOCKS) +xfs_extlen_t xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks); +#define XFS_AG_BEST_BLOCKS(bl,blks) xfs_ag_best_blocks(bl,blks) +#else +/*--#define XFS_AG_BEST_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl))*/ +/* + * Best is XFS_AG_BEST_BLOCKS at and below 64 Gigabyte filesystems, and + * XFS_AG_MAX_BLOCKS above 64 Gigabytes. + */ +#define XFS_AG_BEST_BLOCKS(bl,blks) ((xfs_extlen_t)((1LL << (36 - bl)) >= \ + blks) ? \ + ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl)) : \ + XFS_AG_MAX_BLOCKS(bl)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAX_BLOCKS) +xfs_extlen_t xfs_ag_max_blocks(int bl); +#define XFS_AG_MAX_BLOCKS(bl) xfs_ag_max_blocks(bl) +#else +#define XFS_AG_MAX_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MAX_BYTES >> bl)) +#endif + +#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1)) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAXLEVELS) +int xfs_ag_maxlevels(struct xfs_mount *mp); +#define XFS_AG_MAXLEVELS(mp) xfs_ag_maxlevels(mp) +#else +#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST) +int xfs_min_freelist(xfs_agf_t *a, struct xfs_mount *mp); +#define XFS_MIN_FREELIST(a,mp) xfs_min_freelist(a,mp) +#else +#define XFS_MIN_FREELIST(a,mp) \ + XFS_MIN_FREELIST_RAW( \ + INT_GET((a)->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT), \ + INT_GET((a)->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT), mp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST_PAG) +int xfs_min_freelist_pag(xfs_perag_t *pag, struct xfs_mount *mp); +#define XFS_MIN_FREELIST_PAG(pag,mp) xfs_min_freelist_pag(pag,mp) +#else +#define XFS_MIN_FREELIST_PAG(pag,mp) \ + XFS_MIN_FREELIST_RAW((uint_t)(pag)->pagf_levels[XFS_BTNUM_BNOi], \ + (uint_t)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST_RAW) +int xfs_min_freelist_raw(int bl, int cl, struct xfs_mount *mp); +#define XFS_MIN_FREELIST_RAW(bl,cl,mp) xfs_min_freelist_raw(bl,cl,mp) +#else +#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \ + (MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + \ + MIN(cl + 1, XFS_AG_MAXLEVELS(mp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGB_TO_FSB) +xfs_fsblock_t xfs_agb_to_fsb(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno); +#define XFS_AGB_TO_FSB(mp,agno,agbno) xfs_agb_to_fsb(mp,agno,agbno) +#else +#define XFS_AGB_TO_FSB(mp,agno,agbno) \ + (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_AGNO) +xfs_agnumber_t xfs_fsb_to_agno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_AGNO(mp,fsbno) xfs_fsb_to_agno(mp,fsbno) +#else +#define XFS_FSB_TO_AGNO(mp,fsbno) \ + ((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_AGBNO) +xfs_agblock_t xfs_fsb_to_agbno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_AGBNO(mp,fsbno) xfs_fsb_to_agbno(mp,fsbno) +#else +#define XFS_FSB_TO_AGBNO(mp,fsbno) \ + ((xfs_agblock_t)((fsbno) & XFS_MASK32LO((mp)->m_sb.sb_agblklog))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGB_TO_DADDR) +xfs_daddr_t xfs_agb_to_daddr(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno); +#define XFS_AGB_TO_DADDR(mp,agno,agbno) xfs_agb_to_daddr(mp,agno,agbno) +#else +#define XFS_AGB_TO_DADDR(mp,agno,agbno) \ + ((xfs_daddr_t)(XFS_FSB_TO_BB(mp, \ + (xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno)))) +#endif +/* + * XFS_DADDR_TO_AGNO and XFS_DADDR_TO_AGBNO moved to xfs_mount.h + * to avoid header file ordering change + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_DADDR) +xfs_daddr_t xfs_ag_daddr(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_daddr_t d); +#define XFS_AG_DADDR(mp,agno,d) xfs_ag_daddr(mp,agno,d) +#else +#define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGF) +xfs_agf_t *xfs_buf_to_agf(struct xfs_buf *bp); +#define XFS_BUF_TO_AGF(bp) xfs_buf_to_agf(bp) +#else +#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)XFS_BUF_PTR(bp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGI) +xfs_agi_t *xfs_buf_to_agi(struct xfs_buf *bp); +#define XFS_BUF_TO_AGI(bp) xfs_buf_to_agi(bp) +#else +#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)XFS_BUF_PTR(bp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGFL) +xfs_agfl_t *xfs_buf_to_agfl(struct xfs_buf *bp); +#define XFS_BUF_TO_AGFL(bp) xfs_buf_to_agfl(bp) +#else +#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)XFS_BUF_PTR(bp)) +#endif + +/* + * For checking for bad ranges of xfs_daddr_t's, covering multiple + * allocation groups or a single xfs_daddr_t that's a superblock copy. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_CHECK_DADDR) +void xfs_ag_check_daddr(struct xfs_mount *mp, xfs_daddr_t d, xfs_extlen_t len); +#define XFS_AG_CHECK_DADDR(mp,d,len) xfs_ag_check_daddr(mp,d,len) +#else +#define XFS_AG_CHECK_DADDR(mp,d,len) \ + ((len) == 1 ? \ + ASSERT((d) == XFS_SB_DADDR || \ + XFS_DADDR_TO_AGBNO(mp, d) != XFS_SB_DADDR) : \ + ASSERT(XFS_DADDR_TO_AGNO(mp, d) == \ + XFS_DADDR_TO_AGNO(mp, (d) + (len) - 1))) +#endif + +#endif /* __XFS_AG_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_alloc.c linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc.c --- linux-2.4.19/fs/xfs/xfs_alloc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,2626 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free space allocation for XFS. + */ +#include + +#if defined(DEBUG) +/* + * Allocation tracing. + */ +ktrace_t *xfs_alloc_trace_buf; +#endif + +#define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b))) + +#define XFSA_FIXUP_BNO_OK 1 +#define XFSA_FIXUP_CNT_OK 2 + +int +xfs_alloc_search_busy(xfs_trans_t *tp, + xfs_agnumber_t agno, + xfs_agblock_t bno, + xfs_extlen_t len); + +#if defined(XFS_ALLOC_TRACE) +#define TRACE_ALLOC(s,a) \ + xfs_alloc_trace_alloc(fname, s, a, __LINE__) +#define TRACE_FREE(s,a,b,x,f) \ + xfs_alloc_trace_free(fname, s, mp, a, b, x, f, __LINE__) +#define TRACE_MODAGF(s,a,f) \ + xfs_alloc_trace_modagf(fname, s, mp, a, f, __LINE__) +#define TRACE_BUSY(fname,s,ag,agb,l,sl,tp) \ + xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__) +#define TRACE_UNBUSY(fname,s,ag,sl,tp) \ + xfs_alloc_trace_busy(fname, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__) +#define TRACE_BUSYSEARCH(fname,s,ag,agb,l,sl,tp) \ + xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__) + + +#else +#define TRACE_ALLOC(s,a) +#define TRACE_FREE(s,a,b,x,f) +#define TRACE_MODAGF(s,a,f) +#define TRACE_BUSY(s,a,ag,agb,l,sl,tp) +#define TRACE_UNBUSY(fname,s,ag,sl,tp) +#define TRACE_BUSYSEARCH(fname,s,ag,agb,l,sl,tp) +#endif /* XFS_ALLOC_TRACE */ + +/* + * Prototypes for per-ag allocation routines + */ + +STATIC int xfs_alloc_ag_vextent_exact(xfs_alloc_arg_t *); +STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *); +STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *); +STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *, + xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *); + +/* + * Internal functions. + */ + +/* + * Compute aligned version of the found extent. + * Takes alignment and min length into account. + */ +STATIC int /* success (>= minlen) */ +xfs_alloc_compute_aligned( + xfs_agblock_t foundbno, /* starting block in found extent */ + xfs_extlen_t foundlen, /* length in found extent */ + xfs_extlen_t alignment, /* alignment for allocation */ + xfs_extlen_t minlen, /* minimum length for allocation */ + xfs_agblock_t *resbno, /* result block number */ + xfs_extlen_t *reslen) /* result length */ +{ + xfs_agblock_t bno; + xfs_extlen_t diff; + xfs_extlen_t len; + + if (alignment > 1 && foundlen >= minlen) { + bno = roundup(foundbno, alignment); + diff = bno - foundbno; + len = diff >= foundlen ? 0 : foundlen - diff; + } else { + bno = foundbno; + len = foundlen; + } + *resbno = bno; + *reslen = len; + return len >= minlen; +} + +/* + * Compute best start block and diff for "near" allocations. + * freelen >= wantlen already checked by caller. + */ +STATIC xfs_extlen_t /* difference value (absolute) */ +xfs_alloc_compute_diff( + xfs_agblock_t wantbno, /* target starting block */ + xfs_extlen_t wantlen, /* target length */ + xfs_extlen_t alignment, /* target alignment */ + xfs_agblock_t freebno, /* freespace's starting block */ + xfs_extlen_t freelen, /* freespace's length */ + xfs_agblock_t *newbnop) /* result: best start block from free */ +{ + xfs_agblock_t freeend; /* end of freespace extent */ + xfs_agblock_t newbno1; /* return block number */ + xfs_agblock_t newbno2; /* other new block number */ + xfs_extlen_t newlen1=0; /* length with newbno1 */ + xfs_extlen_t newlen2=0; /* length with newbno2 */ + xfs_agblock_t wantend; /* end of target extent */ + + ASSERT(freelen >= wantlen); + freeend = freebno + freelen; + wantend = wantbno + wantlen; + if (freebno >= wantbno) { + if ((newbno1 = roundup(freebno, alignment)) >= freeend) + newbno1 = NULLAGBLOCK; + } else if (freeend >= wantend && alignment > 1) { + newbno1 = roundup(wantbno, alignment); + newbno2 = newbno1 - alignment; + if (newbno1 >= freeend) + newbno1 = NULLAGBLOCK; + else + newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1); + if (newbno2 < freebno) + newbno2 = NULLAGBLOCK; + else + newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2); + if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) { + if (newlen1 < newlen2 || + (newlen1 == newlen2 && + XFS_ABSDIFF(newbno1, wantbno) > + XFS_ABSDIFF(newbno2, wantbno))) + newbno1 = newbno2; + } else if (newbno2 != NULLAGBLOCK) + newbno1 = newbno2; + } else if (freeend >= wantend) { + newbno1 = wantbno; + } else if (alignment > 1) { + newbno1 = roundup(freeend - wantlen, alignment); + if (newbno1 > freeend - wantlen && + newbno1 - alignment >= freebno) + newbno1 -= alignment; + else if (newbno1 >= freeend) + newbno1 = NULLAGBLOCK; + } else + newbno1 = freeend - wantlen; + *newbnop = newbno1; + return newbno1 == NULLAGBLOCK ? 0 : XFS_ABSDIFF(newbno1, wantbno); +} + +/* + * Fix up the length, based on mod and prod. + * len should be k * prod + mod for some k. + * If len is too small it is returned unchanged. + * If len hits maxlen it is left alone. + */ +STATIC void +xfs_alloc_fix_len( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_extlen_t k; + xfs_extlen_t rlen; + + ASSERT(args->mod < args->prod); + rlen = args->len; + ASSERT(rlen >= args->minlen); + ASSERT(rlen <= args->maxlen); + if (args->prod <= 1 || rlen < args->mod || rlen == args->maxlen || + (args->mod == 0 && rlen < args->prod)) + return; + k = rlen % args->prod; + if (k == args->mod) + return; + if (k > args->mod) { + if ((int)(rlen = rlen - k - args->mod) < (int)args->minlen) + return; + } else { + if ((int)(rlen = rlen - args->prod - (args->mod - k)) < + (int)args->minlen) + return; + } + ASSERT(rlen >= args->minlen); + ASSERT(rlen <= args->maxlen); + args->len = rlen; +} + +/* + * Fix up length if there is too little space left in the a.g. + * Return 1 if ok, 0 if too little, should give up. + */ +STATIC int +xfs_alloc_fix_minleft( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_agf_t *agf; /* a.g. freelist header */ + int diff; /* free space difference */ + + if (args->minleft == 0) + return 1; + agf = XFS_BUF_TO_AGF(args->agbp); + diff = INT_GET(agf->agf_freeblks, ARCH_CONVERT) + + INT_GET(agf->agf_flcount, ARCH_CONVERT) + - args->len - args->minleft; + if (diff >= 0) + return 1; + args->len += diff; /* shrink the allocated space */ + if (args->len >= args->minlen) + return 1; + args->agbno = NULLAGBLOCK; + return 0; +} + +/* + * Update the two btrees, logically removing from freespace the extent + * starting at rbno, rlen blocks. The extent is contained within the + * actual (current) free extent fbno for flen blocks. + * Flags are passed in indicating whether the cursors are set to the + * relevant records. + */ +STATIC int /* error code */ +xfs_alloc_fixup_trees( + xfs_btree_cur_t *cnt_cur, /* cursor for by-size btree */ + xfs_btree_cur_t *bno_cur, /* cursor for by-block btree */ + xfs_agblock_t fbno, /* starting block of free extent */ + xfs_extlen_t flen, /* length of free extent */ + xfs_agblock_t rbno, /* starting block of returned extent */ + xfs_extlen_t rlen, /* length of returned extent */ + int flags) /* flags, XFSA_FIXUP_... */ +{ + int error; /* error code */ + int i; /* operation results */ + xfs_agblock_t nfbno1; /* first new free startblock */ + xfs_agblock_t nfbno2; /* second new free startblock */ + xfs_extlen_t nflen1=0; /* first new free length */ + xfs_extlen_t nflen2=0; /* second new free length */ + + /* + * Look up the record in the by-size tree if necessary. + */ + if (flags & XFSA_FIXUP_CNT_OK) { +#ifdef DEBUG + if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN( + i == 1 && nfbno1 == fbno && nflen1 == flen); +#endif + } else { + if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + /* + * Look up the record in the by-block tree if necessary. + */ + if (flags & XFSA_FIXUP_BNO_OK) { +#ifdef DEBUG + if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN( + i == 1 && nfbno1 == fbno && nflen1 == flen); +#endif + } else { + if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } +#ifdef DEBUG + { + xfs_alloc_block_t *bnoblock; + xfs_alloc_block_t *cntblock; + + if (bno_cur->bc_nlevels == 1 && + cnt_cur->bc_nlevels == 1) { + bnoblock = XFS_BUF_TO_ALLOC_BLOCK(bno_cur->bc_bufs[0]); + cntblock = XFS_BUF_TO_ALLOC_BLOCK(cnt_cur->bc_bufs[0]); + XFS_WANT_CORRUPTED_RETURN( + INT_GET(bnoblock->bb_numrecs, ARCH_CONVERT) == INT_GET(cntblock->bb_numrecs, ARCH_CONVERT)); + } + } +#endif + /* + * Deal with all four cases: the allocated record is contained + * within the freespace record, so we can have new freespace + * at either (or both) end, or no freespace remaining. + */ + if (rbno == fbno && rlen == flen) + nfbno1 = nfbno2 = NULLAGBLOCK; + else if (rbno == fbno) { + nfbno1 = rbno + rlen; + nflen1 = flen - rlen; + nfbno2 = NULLAGBLOCK; + } else if (rbno + rlen == fbno + flen) { + nfbno1 = fbno; + nflen1 = flen - rlen; + nfbno2 = NULLAGBLOCK; + } else { + nfbno1 = fbno; + nflen1 = rbno - fbno; + nfbno2 = rbno + rlen; + nflen2 = (fbno + flen) - nfbno2; + } + /* + * Delete the entry from the by-size btree. + */ + if ((error = xfs_alloc_delete(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + /* + * Add new by-size btree entry(s). + */ + if (nfbno1 != NULLAGBLOCK) { + if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + if (nfbno2 != NULLAGBLOCK) { + if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + /* + * Fix up the by-block btree entry(s). + */ + if (nfbno1 == NULLAGBLOCK) { + /* + * No remaining freespace, just delete the by-block tree entry. + */ + if ((error = xfs_alloc_delete(bno_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } else { + /* + * Update the by-block entry to start later|be shorter. + */ + if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1))) + return error; + } + if (nfbno2 != NULLAGBLOCK) { + /* + * 2 resulting free entries, need to add one. + */ + if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(bno_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + return 0; +} + +/* + * Read in the allocation group free block array. + */ +STATIC int /* error */ +xfs_alloc_read_agfl( + xfs_mount_t *mp, /* mount point structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_buf_t **bpp) /* buffer for the ag free block array */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* disk block address */ + int error; + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, 0, &bp))) + return error; + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF); + *bpp = bp; + return 0; +} + +#if defined(XFS_ALLOC_TRACE) +/* + * Add an allocation trace entry for an alloc call. + */ +STATIC void +xfs_alloc_trace_alloc( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_alloc_arg_t *args, /* allocation argument structure */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_ALLOC | (line << 16)), + (void *)name, + (void *)str, + (void *)args->mp, + (void *)(__psunsigned_t)args->agno, + (void *)(__psunsigned_t)args->agbno, + (void *)(__psunsigned_t)args->minlen, + (void *)(__psunsigned_t)args->maxlen, + (void *)(__psunsigned_t)args->mod, + (void *)(__psunsigned_t)args->prod, + (void *)(__psunsigned_t)args->minleft, + (void *)(__psunsigned_t)args->total, + (void *)(__psunsigned_t)args->alignment, + (void *)(__psunsigned_t)args->len, + (void *)((((__psint_t)args->type) << 16) | + (__psint_t)args->otype), + (void *)(__psint_t)((args->wasdel << 3) | + (args->wasfromfl << 2) | + (args->isfl << 1) | + (args->userdata << 0))); +} + +/* + * Add an allocation trace entry for a free call. + */ +STATIC void +xfs_alloc_trace_free( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_mount_t *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* a.g. relative block number */ + xfs_extlen_t len, /* length of extent */ + int isfl, /* set if is freelist allocation/free */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_FREE | (line << 16)), + (void *)name, + (void *)str, + (void *)mp, + (void *)(__psunsigned_t)agno, + (void *)(__psunsigned_t)agbno, + (void *)(__psunsigned_t)len, + (void *)(__psint_t)isfl, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add an allocation trace entry for modifying an agf. + */ +STATIC void +xfs_alloc_trace_modagf( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_mount_t *mp, /* file system mount point */ + xfs_agf_t *agf, /* new agf value */ + int flags, /* logging flags for agf */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_MODAGF | (line << 16)), + (void *)name, + (void *)str, + (void *)mp, + (void *)(__psint_t)flags, + (void *)(__psunsigned_t)INT_GET(agf->agf_seqno, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_length, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_BNO], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_CNT], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_BNO], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_CNT], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_flfirst, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_fllast, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_flcount, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_freeblks, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_longest, ARCH_CONVERT)); +} + +STATIC void +xfs_alloc_trace_busy( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_mount_t *mp, /* file system mount poing */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* a.g. relative block number */ + xfs_extlen_t len, /* length of extent */ + int slot, /* perag Busy slot */ + xfs_trans_t *tp, + int trtype, /* type: add, delete, search */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(trtype | (line << 16)), + (void *)name, + (void *)str, + (void *)mp, + (void *)(__psunsigned_t)agno, + (void *)(__psunsigned_t)agbno, + (void *)(__psunsigned_t)len, + (void *)(__psint_t)slot, + (void *)tp, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); +} +#endif /* XFS_ALLOC_TRACE */ + +/* + * Allocation group level functions. + */ + +/* + * Allocate a variable extent in the allocation group agno. + * Type and bno are used to determine where in the allocation group the + * extent will start. + * Extent's length (returned in *len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent( + xfs_alloc_arg_t *args) /* argument structure for allocation */ +{ + int error=0; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent"; +#endif + + ASSERT(args->minlen > 0); + ASSERT(args->maxlen > 0); + ASSERT(args->minlen <= args->maxlen); + ASSERT(args->mod < args->prod); + ASSERT(args->alignment > 0); + /* + * Branch to correct routine based on the type. + */ + args->wasfromfl = 0; + switch (args->type) { + case XFS_ALLOCTYPE_THIS_AG: + error = xfs_alloc_ag_vextent_size(args); + break; + case XFS_ALLOCTYPE_NEAR_BNO: + error = xfs_alloc_ag_vextent_near(args); + break; + case XFS_ALLOCTYPE_THIS_BNO: + error = xfs_alloc_ag_vextent_exact(args); + break; + default: + ASSERT(0); + /* NOTREACHED */ + } + if (error) + return error; + /* + * If the allocation worked, need to change the agf structure + * (and log it), and the superblock. + */ + if (args->agbno != NULLAGBLOCK) { + xfs_agf_t *agf; /* allocation group freelist header */ +#ifdef XFS_ALLOC_TRACE + xfs_mount_t *mp = args->mp; +#endif + long slen = (long)args->len; + + ASSERT(args->len >= args->minlen && args->len <= args->maxlen); + ASSERT(!(args->wasfromfl) || !args->isfl); + ASSERT(args->agbno % args->alignment == 0); + if (!(args->wasfromfl)) { + + agf = XFS_BUF_TO_AGF(args->agbp); + INT_MOD(agf->agf_freeblks, ARCH_CONVERT, -(args->len)); + xfs_trans_agblocks_delta(args->tp, + -((long)(args->len))); + args->pag->pagf_freeblks -= args->len; + ASSERT(INT_GET(agf->agf_freeblks, ARCH_CONVERT) + <= INT_GET(agf->agf_length, ARCH_CONVERT)); + TRACE_MODAGF(NULL, agf, XFS_AGF_FREEBLKS); + xfs_alloc_log_agf(args->tp, args->agbp, + XFS_AGF_FREEBLKS); + /* search the busylist for these blocks */ + xfs_alloc_search_busy(args->tp, args->agno, + args->agbno, args->len); + } + if (!args->isfl) + xfs_trans_mod_sb(args->tp, + args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : + XFS_TRANS_SB_FDBLOCKS, -slen); + XFS_STATS_INC(xfsstats.xs_allocx); + XFS_STATS_ADD(xfsstats.xs_allocb, args->len); + } + return 0; +} + +/* + * Allocate a variable extent at exactly agno/bno. + * Extent's length (returned in *len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block (bno), or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_exact( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */ + xfs_btree_cur_t *cnt_cur;/* by count btree cursor */ + xfs_agblock_t end; /* end of allocated extent */ + int error; + xfs_agblock_t fbno; /* start block of found extent */ + xfs_agblock_t fend; /* end block of found extent */ + xfs_extlen_t flen; /* length of found extent */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_exact"; +#endif + int i; /* success/failure of operation */ + xfs_agblock_t maxend; /* end of maximal extent */ + xfs_agblock_t minend; /* end of minimal extent */ + xfs_extlen_t rlen; /* length of returned extent */ + + ASSERT(args->alignment == 1); + /* + * Allocate/initialize a cursor for the by-number freespace btree. + */ + bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Lookup bno and minlen in the btree (minlen is irrelevant, really). + * Look for the closest free block <= bno, it must contain bno + * if any free block does. + */ + if ((error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i))) + goto error0; + if (!i) { + /* + * Didn't find it, return null. + */ + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * Grab the freespace record. + */ + if ((error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + ASSERT(fbno <= args->agbno); + minend = args->agbno + args->minlen; + maxend = args->agbno + args->maxlen; + fend = fbno + flen; + /* + * Give up if the freespace isn't long enough for the minimum request. + */ + if (fend < minend) { + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * End of extent will be smaller of the freespace end and the + * maximal requested end. + */ + end = XFS_AGBLOCK_MIN(fend, maxend); + /* + * Fix the length according to mod and prod if given. + */ + args->len = end - args->agbno; + xfs_alloc_fix_len(args); + if (!xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + return 0; + } + rlen = args->len; + ASSERT(args->agbno + rlen <= fend); + end = args->agbno + rlen; + /* + * We are allocating agbno for rlen [agbno .. end] + * Allocate/initialize a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + ASSERT(args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, + args->agbno, args->len, XFSA_FIXUP_BNO_OK))) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + goto error0; + } + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("normal", args); + args->wasfromfl = 0; + return 0; + +error0: + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + TRACE_ALLOC("error", args); + return error; +} + +/* + * Allocate a variable extent near bno in the allocation group agno. + * Extent's length (returned in len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_near( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */ + xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */ + xfs_btree_cur_t *cnt_cur; /* cursor for count btree */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_near"; +#endif + xfs_agblock_t gtbno; /* start bno of right side entry */ + xfs_agblock_t gtbnoa; /* aligned ... */ + xfs_extlen_t gtdiff; /* difference to right side entry */ + xfs_extlen_t gtlen; /* length of right side entry */ + xfs_extlen_t gtlena; /* aligned ... */ + xfs_agblock_t gtnew; /* useful start bno of right side */ + int error; /* error code */ + int i; /* result code, temporary */ + int j; /* result code, temporary */ + xfs_agblock_t ltbno; /* start bno of left side entry */ + xfs_agblock_t ltbnoa; /* aligned ... */ + xfs_extlen_t ltdiff; /* difference to left side entry */ + /*REFERENCED*/ + xfs_agblock_t ltend; /* end bno of left side entry */ + xfs_extlen_t ltlen; /* length of left side entry */ + xfs_extlen_t ltlena; /* aligned ... */ + xfs_agblock_t ltnew; /* useful start bno of left side */ + xfs_extlen_t rlen; /* length of returned extent */ +#if defined(DEBUG) && defined(__KERNEL__) + /* + * Randomly don't execute the first algorithm. + */ + static int seed; /* randomizing seed value */ + int dofirst; /* set to do first algorithm */ + timespec_t now; /* current time */ + + if (!seed) { + nanotime(&now); + seed = (int)now.tv_sec ^ (int)now.tv_nsec; + } + dofirst = random() & 1; +#endif + /* + * Get a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + ltlen = 0; + bno_cur_lt = bno_cur_gt = NULL; + /* + * See if there are any free extents as big as maxlen. + */ + if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i))) + goto error0; + /* + * If none, then pick up the last entry in the tree unless the + * tree is empty. + */ + if (!i) { + if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, <bno, + <len, &i))) + goto error0; + if (i == 0 || ltlen == 0) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + return 0; + } + ASSERT(i == 1); + } + args->wasfromfl = 0; + /* + * First algorithm. + * If the requested extent is large wrt the freespaces available + * in this a.g., then the cursor will be pointing to a btree entry + * near the right edge of the tree. If it's in the last btree leaf + * block, then we just examine all the entries in that block + * that are big enough, and pick the best one. + * This is written as a while loop so we can break out of it, + * but we never loop back to the top. + */ + while (xfs_btree_islastblock(cnt_cur, 0)) { + xfs_extlen_t bdiff; + int besti=0; + xfs_extlen_t blen=0; + xfs_agblock_t bnew=0; + +#if defined(DEBUG) && defined(__KERNEL__) + if (!dofirst) + break; +#endif + /* + * Start from the entry that lookup found, sequence through + * all larger free blocks. If we're actually pointing at a + * record smaller than maxlen, go to the start of this block, + * and skip all those smaller than minlen. + */ + if (ltlen || args->alignment > 1) { + cnt_cur->bc_ptrs[0] = 1; + do { + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, + <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (ltlen >= args->minlen) + break; + if ((error = xfs_alloc_increment(cnt_cur, 0, &i))) + goto error0; + } while (i); + ASSERT(ltlen >= args->minlen); + if (!i) + break; + } + i = cnt_cur->bc_ptrs[0]; + for (j = 1, blen = 0, bdiff = 0; + !error && j && (blen < args->maxlen || bdiff > 0); + error = xfs_alloc_increment(cnt_cur, 0, &j)) { + /* + * For each entry, decide if it's better than + * the previous best entry. + */ + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (!xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena)) + continue; + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + ASSERT(args->len >= args->minlen); + if (args->len < blen) + continue; + ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, + args->alignment, ltbno, ltlen, <new); + if (ltnew != NULLAGBLOCK && + (args->len > blen || ltdiff < bdiff)) { + bdiff = ltdiff; + bnew = ltnew; + blen = args->len; + besti = cnt_cur->bc_ptrs[0]; + } + } + /* + * It didn't work. We COULD be in a case where + * there's a good record somewhere, so try again. + */ + if (blen == 0) + break; + /* + * Point at the best entry, and retrieve it again. + */ + cnt_cur->bc_ptrs[0] = besti; + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + ltend = ltbno + ltlen; + ASSERT(ltend <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + args->len = blen; + if (!xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("nominleft", args); + return 0; + } + blen = args->len; + /* + * We are allocating starting at bnew for blen blocks. + */ + args->agbno = bnew; + ASSERT(bnew >= ltbno); + ASSERT(bnew + blen <= ltend); + /* + * Set up a cursor for the by-bno tree. + */ + bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, + args->agbp, args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Fix up the btree entries. + */ + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, + ltlen, bnew, blen, XFSA_FIXUP_CNT_OK))) + goto error0; + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + TRACE_ALLOC("first", args); + return 0; + } + /* + * Second algorithm. + * Search in the by-bno tree to the left and to the right + * simultaneously, until in each case we find a space big enough, + * or run into the edge of the tree. When we run into the edge, + * we deallocate that cursor. + * If both searches succeed, we compare the two spaces and pick + * the better one. + * With alignment, it's possible for both to fail; the upper + * level algorithm that picks allocation groups for allocations + * is not supposed to do this. + */ + /* + * Allocate and initialize the cursor for the leftward search. + */ + bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Lookup <= bno to find the leftward search's starting point. + */ + if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i))) + goto error0; + if (!i) { + /* + * Didn't find anything; use this cursor for the rightward + * search. + */ + bno_cur_gt = bno_cur_lt; + bno_cur_lt = 0; + } + /* + * Found something. Duplicate the cursor for the rightward search. + */ + else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt))) + goto error0; + /* + * Increment the cursor, so we will point at the entry just right + * of the leftward entry if any, or to the leftmost entry. + */ + if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + /* + * It failed, there are no rightward entries. + */ + xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + /* + * Loop going left with the leftward cursor, right with the + * rightward cursor, until either both directions give up or + * we find an entry at least as big as minlen. + */ + do { + if (bno_cur_lt) { + if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena)) + break; + if ((error = xfs_alloc_decrement(bno_cur_lt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + } + if (bno_cur_gt) { + if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (xfs_alloc_compute_aligned(gtbno, gtlen, + args->alignment, args->minlen, + >bnoa, >lena)) + break; + if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + } + } while (bno_cur_lt || bno_cur_gt); + /* + * Got both cursors still active, need to find better entry. + */ + if (bno_cur_lt && bno_cur_gt) { + /* + * Left side is long enough, look for a right side entry. + */ + if (ltlena >= args->minlen) { + /* + * Fix up the length. + */ + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + ltdiff = xfs_alloc_compute_diff(args->agbno, rlen, + args->alignment, ltbno, ltlen, <new); + /* + * Not perfect. + */ + if (ltdiff) { + /* + * Look until we find a better one, run out of + * space, or run off the end. + */ + while (bno_cur_lt && bno_cur_gt) { + if ((error = xfs_alloc_get_rec( + bno_cur_gt, >bno, + >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_alloc_compute_aligned(gtbno, gtlen, + args->alignment, args->minlen, + >bnoa, >lena); + /* + * The left one is clearly better. + */ + if (gtbnoa >= args->agbno + ltdiff) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + break; + } + /* + * If we reach a big enough entry, + * compare the two and pick the best. + */ + if (gtlena >= args->minlen) { + args->len = + XFS_EXTLEN_MIN(gtlena, + args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + gtdiff = xfs_alloc_compute_diff( + args->agbno, rlen, + args->alignment, + gtbno, gtlen, >new); + /* + * Right side is better. + */ + if (gtdiff < ltdiff) { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + /* + * Left side is better. + */ + else { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + break; + } + /* + * Fell off the right end. + */ + if ((error = xfs_alloc_increment( + bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + break; + } + } + } + /* + * The left side is perfect, trash the right side. + */ + else { + xfs_btree_del_cursor(bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + } + /* + * It's the right side that was found first, look left. + */ + else { + /* + * Fix up the length. + */ + args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + gtdiff = xfs_alloc_compute_diff(args->agbno, rlen, + args->alignment, gtbno, gtlen, >new); + /* + * Right side entry isn't perfect. + */ + if (gtdiff) { + /* + * Look until we find a better one, run out of + * space, or run off the end. + */ + while (bno_cur_lt && bno_cur_gt) { + if ((error = xfs_alloc_get_rec( + bno_cur_lt, <bno, + <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena); + /* + * The right one is clearly better. + */ + if (ltbnoa <= args->agbno - gtdiff) { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + break; + } + /* + * If we reach a big enough entry, + * compare the two and pick the best. + */ + if (ltlena >= args->minlen) { + args->len = XFS_EXTLEN_MIN( + ltlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + ltdiff = xfs_alloc_compute_diff( + args->agbno, rlen, + args->alignment, + ltbno, ltlen, <new); + /* + * Left side is better. + */ + if (ltdiff < gtdiff) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + /* + * Right side is better. + */ + else { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + break; + } + /* + * Fell off the left end. + */ + if ((error = xfs_alloc_decrement( + bno_cur_lt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + break; + } + } + } + /* + * The right side is perfect, trash the left side. + */ + else { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + } + } + /* + * If we couldn't get anything, give up. + */ + if (bno_cur_lt == NULL && bno_cur_gt == NULL) { + TRACE_ALLOC("neither", args); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * At this point we have selected a freespace entry, either to the + * left or to the right. If it's on the right, copy all the + * useful variables to the "left" set so we only have one + * copy of this code. + */ + if (bno_cur_gt) { + bno_cur_lt = bno_cur_gt; + bno_cur_gt = NULL; + ltbno = gtbno; + ltbnoa = gtbnoa; + ltlen = gtlen; + ltlena = gtlena; + j = 1; + } else + j = 0; + /* + * Fix up the length and compute the useful address. + */ + ltend = ltbno + ltlen; + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + if (!xfs_alloc_fix_minleft(args)) { + TRACE_ALLOC("nominleft", args); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + return 0; + } + rlen = args->len; + (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, ltbno, + ltlen, <new); + ASSERT(ltnew >= ltbno); + ASSERT(ltnew + rlen <= ltend); + ASSERT(ltnew + rlen <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + args->agbno = ltnew; + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, + ltnew, rlen, XFSA_FIXUP_BNO_OK))) + goto error0; + TRACE_ALLOC(j ? "gt" : "lt", args); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + return 0; + + error0: + TRACE_ALLOC("error", args); + if (cnt_cur != NULL) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + if (bno_cur_lt != NULL) + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR); + if (bno_cur_gt != NULL) + xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR); + return error; +} + +/* + * Allocate a variable extent anywhere in the allocation group agno. + * Extent's length (returned in len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_size( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur; /* cursor for bno btree */ + xfs_btree_cur_t *cnt_cur; /* cursor for cnt btree */ + int error; /* error result */ + xfs_agblock_t fbno; /* start of found freespace */ + xfs_extlen_t flen; /* length of found freespace */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_size"; +#endif + int i; /* temp status variable */ + xfs_agblock_t rbno; /* returned block number */ + xfs_extlen_t rlen; /* length of returned extent */ + + /* + * Allocate and initialize a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + bno_cur = NULL; + /* + * Look for an entry >= maxlen+alignment-1 blocks. + */ + if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, + args->maxlen + args->alignment - 1, &i))) + goto error0; + /* + * If none, then pick up the last entry in the tree unless the + * tree is empty. + */ + if (!i) { + if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, &fbno, + &flen, &i))) + goto error0; + if (i == 0 || flen == 0) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("noentry", args); + return 0; + } + ASSERT(i == 1); + } + /* + * There's a freespace as big as maxlen+alignment-1, get it. + */ + else { + if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + /* + * In the first case above, we got the last entry in the + * by-size btree. Now we check to see if the space hits maxlen + * once aligned; if not, we search left for something better. + * This can't happen in the second case above. + */ + xfs_alloc_compute_aligned(fbno, flen, args->alignment, args->minlen, + &rbno, &rlen); + rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); + XFS_WANT_CORRUPTED_GOTO(rlen == 0 || + (rlen <= flen && rbno + rlen <= fbno + flen), error0); + if (rlen < args->maxlen) { + xfs_agblock_t bestfbno; + xfs_extlen_t bestflen; + xfs_agblock_t bestrbno; + xfs_extlen_t bestrlen; + + bestrlen = rlen; + bestrbno = rbno; + bestflen = flen; + bestfbno = fbno; + for (;;) { + if ((error = xfs_alloc_decrement(cnt_cur, 0, &i))) + goto error0; + if (i == 0) + break; + if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (flen < bestrlen) + break; + xfs_alloc_compute_aligned(fbno, flen, args->alignment, + args->minlen, &rbno, &rlen); + rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); + XFS_WANT_CORRUPTED_GOTO(rlen == 0 || + (rlen <= flen && rbno + rlen <= fbno + flen), + error0); + if (rlen > bestrlen) { + bestrlen = rlen; + bestrbno = rbno; + bestflen = flen; + bestfbno = fbno; + if (rlen == args->maxlen) + break; + } + } + if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + rlen = bestrlen; + rbno = bestrbno; + flen = bestflen; + fbno = bestfbno; + } + args->wasfromfl = 0; + /* + * Fix up the length. + */ + args->len = rlen; + xfs_alloc_fix_len(args); + if (rlen < args->minlen || !xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("nominleft", args); + args->agbno = NULLAGBLOCK; + return 0; + } + rlen = args->len; + XFS_WANT_CORRUPTED_GOTO(rlen <= flen, error0); + /* + * Allocate and initialize a cursor for the by-block tree. + */ + bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, + rbno, rlen, XFSA_FIXUP_CNT_OK))) + goto error0; + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + cnt_cur = bno_cur = NULL; + args->len = rlen; + args->agbno = rbno; + XFS_WANT_CORRUPTED_GOTO( + args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT), + error0); + TRACE_ALLOC("normal", args); + return 0; + +error0: + TRACE_ALLOC("error", args); + if (cnt_cur) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + if (bno_cur) + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Deal with the case where only small freespaces remain. + * Either return the contents of the last freespace record, + * or allocate space from the freelist if there is nothing in the tree. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_small( + xfs_alloc_arg_t *args, /* allocation argument structure */ + xfs_btree_cur_t *ccur, /* by-size cursor */ + xfs_agblock_t *fbnop, /* result block number */ + xfs_extlen_t *flenp, /* result length */ + int *stat) /* status: 0-freelist, 1-normal/none */ +{ + int error; + xfs_agblock_t fbno; + xfs_extlen_t flen; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_small"; +#endif + int i; + + if ((error = xfs_alloc_decrement(ccur, 0, &i))) + goto error0; + if (i) { + if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + /* + * Nothing in the btree, try the freelist. Make sure + * to respect minleft even when pulling from the + * freelist. + */ + else if (args->minlen == 1 && args->alignment == 1 && !args->isfl && + (INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_flcount, + ARCH_CONVERT) > args->minleft)) { + if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno))) + goto error0; + if (fbno != NULLAGBLOCK) { + if (args->userdata) { + xfs_buf_t *bp; + + bp = xfs_btree_get_bufs(args->mp, args->tp, + args->agno, fbno, 0); + xfs_trans_binval(args->tp, bp); + } + args->len = 1; + args->agbno = fbno; + XFS_WANT_CORRUPTED_GOTO( + args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT), + error0); + args->wasfromfl = 1; + TRACE_ALLOC("freelist", args); + *stat = 0; + return 0; + } + /* + * Nothing in the freelist. + */ + else + flen = 0; + } + /* + * Can't allocate from the freelist for some reason. + */ + else + flen = 0; + /* + * Can't do the allocation, give up. + */ + if (flen < args->minlen) { + args->agbno = NULLAGBLOCK; + TRACE_ALLOC("notenough", args); + flen = 0; + } + *fbnop = fbno; + *flenp = flen; + *stat = 1; + TRACE_ALLOC("normal", args); + return 0; + +error0: + TRACE_ALLOC("error", args); + return error; +} + +/* + * Free the extent starting at agno/bno for length. + */ +STATIC int /* error */ +xfs_free_ag_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer for a.g. freelist header */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t bno, /* starting block number */ + xfs_extlen_t len, /* length of extent */ + int isfl) /* set if is freelist blocks - no sb acctg */ +{ + xfs_btree_cur_t *bno_cur; /* cursor for by-block btree */ + xfs_btree_cur_t *cnt_cur; /* cursor for by-size btree */ + int error; /* error return value */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_free_ag_extent"; +#endif + xfs_agblock_t gtbno; /* start of right neighbor block */ + xfs_extlen_t gtlen; /* length of right neighbor block */ + int haveleft; /* have a left neighbor block */ + int haveright; /* have a right neighbor block */ + int i; /* temp, result code */ + xfs_agblock_t ltbno; /* start of left neighbor block */ + xfs_extlen_t ltlen; /* length of left neighbor block */ + xfs_mount_t *mp; /* mount point struct for filesystem */ + xfs_agblock_t nbno; /* new starting block of freespace */ + xfs_extlen_t nlen; /* new length of freespace */ + + mp = tp->t_mountp; + /* + * Allocate and initialize a cursor for the by-block btree. + */ + bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, 0, + 0); + cnt_cur = NULL; + /* + * Look for a neighboring block on the left (lower block numbers) + * that is contiguous with this space. + */ + if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft))) + goto error0; + if (haveleft) { + /* + * There is a block to our left. + */ + if ((error = xfs_alloc_get_rec(bno_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * It's not contiguous, though. + */ + if (ltbno + ltlen < bno) + haveleft = 0; + else { + /* + * If this failure happens the request to free this + * space was invalid, it's (partly) already free. + * Very bad. + */ + XFS_WANT_CORRUPTED_GOTO(ltbno + ltlen <= bno, error0); + } + } + /* + * Look for a neighboring block on the right (higher block numbers) + * that is contiguous with this space. + */ + if ((error = xfs_alloc_increment(bno_cur, 0, &haveright))) + goto error0; + if (haveright) { + /* + * There is a block to our right. + */ + if ((error = xfs_alloc_get_rec(bno_cur, >bno, >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * It's not contiguous, though. + */ + if (bno + len < gtbno) + haveright = 0; + else { + /* + * If this failure happens the request to free this + * space was invalid, it's (partly) already free. + * Very bad. + */ + XFS_WANT_CORRUPTED_GOTO(gtbno >= bno + len, error0); + } + } + /* + * Now allocate and initialize a cursor for the by-size tree. + */ + cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, 0, + 0); + /* + * Have both left and right contiguous neighbors. + * Merge all three into a single free block. + */ + if (haveleft && haveright) { + /* + * Delete the old by-size entry on the left. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Delete the old by-size entry on the right. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Delete the old by-block entry for the right block. + */ + if ((error = xfs_alloc_delete(bno_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Move the by-block cursor back to the left neighbor. + */ + if ((error = xfs_alloc_decrement(bno_cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); +#ifdef DEBUG + /* + * Check that this is the right record: delete didn't + * mangle the cursor. + */ + { + xfs_agblock_t xxbno; + xfs_extlen_t xxlen; + + if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO( + i == 1 && xxbno == ltbno && xxlen == ltlen, + error0); + } +#endif + /* + * Update remaining by-block entry to the new, joined block. + */ + nbno = ltbno; + nlen = len + ltlen + gtlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * Have only a left contiguous neighbor. + * Merge it together with the new freespace. + */ + else if (haveleft) { + /* + * Delete the old by-size entry on the left. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Back up the by-block cursor to the left neighbor, and + * update its length. + */ + if ((error = xfs_alloc_decrement(bno_cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + nbno = ltbno; + nlen = len + ltlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * Have only a right contiguous neighbor. + * Merge it together with the new freespace. + */ + else if (haveright) { + /* + * Delete the old by-size entry on the right. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Update the starting block and length of the right + * neighbor in the by-block tree. + */ + nbno = bno; + nlen = len + gtlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * No contiguous neighbors. + * Insert the new freespace into the by-block tree. + */ + else { + nbno = bno; + nlen = len; + if ((error = xfs_alloc_insert(bno_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + bno_cur = NULL; + /* + * In all cases we need to insert the new freespace in the by-size tree. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 0, error0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + cnt_cur = NULL; + /* + * Update the freespace totals in the ag and superblock. + */ + { + xfs_agf_t *agf; + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + pag = &mp->m_perag[agno]; + INT_MOD(agf->agf_freeblks, ARCH_CONVERT, len); + xfs_trans_agblocks_delta(tp, len); + pag->pagf_freeblks += len; + XFS_WANT_CORRUPTED_GOTO( + INT_GET(agf->agf_freeblks, ARCH_CONVERT) + <= INT_GET(agf->agf_length, ARCH_CONVERT), + error0); + TRACE_MODAGF(NULL, agf, XFS_AGF_FREEBLKS); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); + if (!isfl) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len); + XFS_STATS_INC(xfsstats.xs_freex); + XFS_STATS_ADD(xfsstats.xs_freeb, len); + } + TRACE_FREE(haveleft ? + (haveright ? "both" : "left") : + (haveright ? "right" : "none"), + agno, bno, len, isfl); + + /* + * Since blocks move to the free list without the coordination + * used in xfs_bmap_finish, we can't allow block to be available + * for reallocation and non-transaction writing (user data) + * until we know that the transaction that moved it to the free + * list is permanently on disk. We track the blocks by declaring + * these blocks as "busy"; the busy list is maintained on a per-ag + * basis and each transaction records which entries should be removed + * when the iclog commits to disk. If a busy block is allocated, + * the iclog is pushed up to the LSN that freed the block. + */ + xfs_alloc_mark_busy(tp, agno, bno, len); + return 0; + + error0: + TRACE_FREE("error", agno, bno, len, isfl); + if (bno_cur) + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + if (cnt_cur) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Visible (exported) allocation/free functions. + * Some of these are used just by xfs_alloc_btree.c and this file. + */ + +/* + * Compute and fill in value of m_ag_maxlevels. + */ +void +xfs_alloc_compute_maxlevels( + xfs_mount_t *mp) /* file system mount structure */ +{ + int level; + uint maxblocks; + uint maxleafents; + int minleafrecs; + int minnoderecs; + + maxleafents = (mp->m_sb.sb_agblocks + 1) / 2; + minleafrecs = mp->m_alloc_mnr[0]; + minnoderecs = mp->m_alloc_mnr[1]; + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + mp->m_ag_maxlevels = level; +} + +/* + * Decide whether to use this allocation group for this allocation. + * If so, fix up the btree freelist's size. + * This is external so mkfs can call it, too. + */ +int /* error */ +xfs_alloc_fix_freelist( + xfs_alloc_arg_t *args, /* allocation argument structure */ + int flags) /* XFS_ALLOC_FLAG_... */ +{ + xfs_buf_t *agbp; /* agf buffer pointer */ + xfs_agf_t *agf; /* a.g. freespace structure pointer */ + xfs_buf_t *agflbp;/* agfl buffer pointer */ + xfs_agblock_t bno; /* freelist block */ + xfs_extlen_t delta; /* new blocks needed in freelist */ + int error; /* error result code */ + xfs_extlen_t longest;/* longest extent in allocation group */ + xfs_mount_t *mp; /* file system mount point structure */ + xfs_extlen_t need; /* total blocks needed in freelist */ + xfs_perag_t *pag; /* per-ag information structure */ + xfs_alloc_arg_t targs; /* local allocation arguments */ + xfs_trans_t *tp; /* transaction pointer */ + + mp = args->mp; + + pag = args->pag; + tp = args->tp; + if (!pag->pagf_init) { + if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, + &agbp))) + return error; + if (!pag->pagf_init) { + args->agbp = NULL; + return 0; + } + } else + agbp = NULL; + + /* If this is a metadata prefered pag and we are user data + * then try somewhere else if we are not being asked to + * try harder at this point + */ + if (pag->pagf_metadata && args->userdata && flags) { + args->agbp = NULL; + return 0; + } + + need = XFS_MIN_FREELIST_PAG(pag, mp); + delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0; + /* + * If it looks like there isn't a long enough extent, or enough + * total blocks, reject it. + */ + longest = (pag->pagf_longest > delta) ? + (pag->pagf_longest - delta) : + (pag->pagf_flcount > 0 || pag->pagf_longest > 0); + if (args->minlen + args->alignment + args->minalignslop - 1 > longest || + (args->minleft && + (int)(pag->pagf_freeblks + pag->pagf_flcount - + need - args->total) < + (int)args->minleft)) { + if (agbp) + xfs_trans_brelse(tp, agbp); + args->agbp = NULL; + return 0; + } + /* + * Get the a.g. freespace buffer. + * Can fail if we're not blocking on locks, and it's held. + */ + if (agbp == NULL) { + if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, + &agbp))) + return error; + if (agbp == NULL) { + args->agbp = NULL; + return 0; + } + } + /* + * Figure out how many blocks we should have in the freelist. + */ + agf = XFS_BUF_TO_AGF(agbp); + need = XFS_MIN_FREELIST(agf, mp); + delta = need > INT_GET(agf->agf_flcount, ARCH_CONVERT) ? + (need - INT_GET(agf->agf_flcount, ARCH_CONVERT)) : 0; + /* + * If there isn't enough total or single-extent, reject it. + */ + longest = INT_GET(agf->agf_longest, ARCH_CONVERT); + longest = (longest > delta) ? (longest - delta) : + (INT_GET(agf->agf_flcount, ARCH_CONVERT) > 0 || longest > 0); + if (args->minlen + args->alignment + args->minalignslop - 1 > longest || + (args->minleft && + (int)(INT_GET(agf->agf_freeblks, ARCH_CONVERT) + + INT_GET(agf->agf_flcount, ARCH_CONVERT) - need - args->total) < + (int)args->minleft)) { + xfs_trans_brelse(tp, agbp); + args->agbp = NULL; + return 0; + } + /* + * Make the freelist shorter if it's too long. + */ + while (INT_GET(agf->agf_flcount, ARCH_CONVERT) > need) { + xfs_buf_t *bp; + + if ((error = xfs_alloc_get_freelist(tp, agbp, &bno))) + return error; + if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1))) + return error; + bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0); + xfs_trans_binval(tp, bp); + } + /* + * Initialize the args structure. + */ + targs.tp = tp; + targs.mp = mp; + targs.agbp = agbp; + targs.agno = args->agno; + targs.mod = targs.minleft = targs.wasdel = targs.userdata = + targs.minalignslop = 0; + targs.alignment = targs.minlen = targs.prod = targs.isfl = 1; + targs.type = XFS_ALLOCTYPE_THIS_AG; + targs.pag = pag; + if ((error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp))) + return error; + /* + * Make the freelist longer if it's too short. + */ + while (INT_GET(agf->agf_flcount, ARCH_CONVERT) < need) { + targs.agbno = 0; + targs.maxlen = need - INT_GET(agf->agf_flcount, ARCH_CONVERT); + /* + * Allocate as many blocks as possible at once. + */ + if ((error = xfs_alloc_ag_vextent(&targs))) + return error; + /* + * Stop if we run out. Won't happen if callers are obeying + * the restrictions correctly. Can happen for free calls + * on a completely full ag. + */ + if (targs.agbno == NULLAGBLOCK) + break; + /* + * Put each allocated block on the list. + */ + for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) { + if ((error = xfs_alloc_put_freelist(tp, agbp, agflbp, + bno))) + return error; + } + } + args->agbp = agbp; + return 0; +} + +/* + * Get a block from the freelist. + * Returns with the buffer for the block gotten. + */ +int /* error */ +xfs_alloc_get_freelist( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer containing the agf structure */ + xfs_agblock_t *bnop) /* block address retrieved from freelist */ +{ + xfs_agf_t *agf; /* a.g. freespace structure */ + xfs_agfl_t *agfl; /* a.g. freelist structure */ + xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */ + xfs_agblock_t bno; /* block number returned */ + int error; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_get_freelist"; +#endif + xfs_mount_t *mp; /* mount structure */ + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + /* + * Freelist is empty, give up. + */ + if (INT_ISZERO(agf->agf_flcount, ARCH_CONVERT)) { + *bnop = NULLAGBLOCK; + return 0; + } + /* + * Read the array of free blocks. + */ + mp = tp->t_mountp; + if ((error = xfs_alloc_read_agfl(mp, tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), &agflbp))) + return error; + agfl = XFS_BUF_TO_AGFL(agflbp); + /* + * Get the block number and update the data structures. + */ + bno = INT_GET(agfl->agfl_bno[INT_GET(agf->agf_flfirst, ARCH_CONVERT)], ARCH_CONVERT); + INT_MOD(agf->agf_flfirst, ARCH_CONVERT, 1); + xfs_trans_brelse(tp, agflbp); + if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) == XFS_AGFL_SIZE) + INT_ZERO(agf->agf_flfirst, ARCH_CONVERT); + pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)]; + INT_MOD(agf->agf_flcount, ARCH_CONVERT, -1); + xfs_trans_agflist_delta(tp, -1); + pag->pagf_flcount--; + TRACE_MODAGF(NULL, agf, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT); + *bnop = bno; + + /* + * As blocks are freed, they are added to the per-ag busy list + * and remain there until the freeing transaction is committed to + * disk. Now that we have allocated blocks, this list must be + * searched to see if a block is being reused. If one is, then + * the freeing transaction must be pushed to disk NOW by forcing + * to disk all iclogs up that transaction's LSN. + */ + xfs_alloc_search_busy(tp, INT_GET(agf->agf_seqno, ARCH_CONVERT), bno, 1); + return 0; +} + +/* + * Log the given fields from the agf structure. + */ +void +xfs_alloc_log_agf( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer for a.g. freelist header */ + int fields) /* mask of fields to be logged (XFS_AGF_...) */ +{ + int first; /* first byte offset */ + int last; /* last byte offset */ + static const short offsets[] = { + offsetof(xfs_agf_t, agf_magicnum), + offsetof(xfs_agf_t, agf_versionnum), + offsetof(xfs_agf_t, agf_seqno), + offsetof(xfs_agf_t, agf_length), + offsetof(xfs_agf_t, agf_roots[0]), + offsetof(xfs_agf_t, agf_levels[0]), + offsetof(xfs_agf_t, agf_flfirst), + offsetof(xfs_agf_t, agf_fllast), + offsetof(xfs_agf_t, agf_flcount), + offsetof(xfs_agf_t, agf_freeblks), + offsetof(xfs_agf_t, agf_longest), + sizeof(xfs_agf_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); +} + +/* + * Interface for inode allocation to force the pag data to be initialized. + */ +int /* error */ +xfs_alloc_pagf_init( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags) /* XFS_ALLOC_FLAGS_... */ +{ + xfs_buf_t *bp; + int error; + + if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp))) + return error; + if (bp) + xfs_trans_brelse(tp, bp); + return 0; +} + +/* + * Put the block on the freelist for the allocation group. + */ +int /* error */ +xfs_alloc_put_freelist( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer for a.g. freelist header */ + xfs_buf_t *agflbp,/* buffer for a.g. free block array */ + xfs_agblock_t bno) /* block being freed */ +{ + xfs_agf_t *agf; /* a.g. freespace structure */ + xfs_agfl_t *agfl; /* a.g. free block array */ + xfs_agblock_t *blockp;/* pointer to array entry */ + int error; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_put_freelist"; +#endif + xfs_mount_t *mp; /* mount structure */ + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + mp = tp->t_mountp; + + if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), &agflbp))) + return error; + agfl = XFS_BUF_TO_AGFL(agflbp); + INT_MOD(agf->agf_fllast, ARCH_CONVERT, 1); + if (INT_GET(agf->agf_fllast, ARCH_CONVERT) == XFS_AGFL_SIZE) + INT_ZERO(agf->agf_fllast, ARCH_CONVERT); + pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)]; + INT_MOD(agf->agf_flcount, ARCH_CONVERT, 1); + xfs_trans_agflist_delta(tp, 1); + pag->pagf_flcount++; + ASSERT(INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE); + blockp = &agfl->agfl_bno[INT_GET(agf->agf_fllast, ARCH_CONVERT)]; + INT_SET(*blockp, ARCH_CONVERT, bno); + TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT); + xfs_trans_log_buf(tp, agflbp, + (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl), + (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl + + sizeof(xfs_agblock_t) - 1)); + return 0; +} + +/* + * Read in the allocation group header (free/alloc section). + */ +int /* error */ +xfs_alloc_read_agf( + xfs_mount_t *mp, /* mount point structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags, /* XFS_ALLOC_FLAG_... */ + xfs_buf_t **bpp) /* buffer for the ag freelist header */ +{ + xfs_agf_t *agf; /* ag freelist header */ + int agf_ok; /* set if agf is consistent */ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* disk block address */ + int error; + xfs_perag_t *pag; /* per allocation group data */ + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, + (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0U, + &bp))) + return error; + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (!bp) { + *bpp = NULL; + return 0; + } + /* + * Validate the magic number of the agf block. + */ + agf = XFS_BUF_TO_AGF(bp); + agf_ok = + INT_GET(agf->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC && + XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT)) && + INT_GET(agf->agf_freeblks, ARCH_CONVERT) <= + INT_GET(agf->agf_length, ARCH_CONVERT) && + INT_GET(agf->agf_flfirst, ARCH_CONVERT) < XFS_AGFL_SIZE && + INT_GET(agf->agf_fllast, ARCH_CONVERT) < XFS_AGFL_SIZE && + INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE; + if (XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF, + XFS_RANDOM_ALLOC_READ_AGF)) { + xfs_trans_brelse(tp, bp); +#ifdef __KERNEL__ /* additional, temporary, debugging code */ + cmn_err(CE_NOTE, + "xfs_alloc_read_agf: error in <%s> AG %d", + mp->m_fsname, agno); + if (INT_GET(agf->agf_magicnum, ARCH_CONVERT) != XFS_AGF_MAGIC) + cmn_err(CE_NOTE, "bad agf_magicnum 0x%x", + INT_GET(agf->agf_magicnum, ARCH_CONVERT)); + if (!XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT))) + cmn_err(CE_NOTE, "Bad version number 0x%x", + INT_GET(agf->agf_versionnum, ARCH_CONVERT)); + if (!(INT_GET(agf->agf_freeblks, ARCH_CONVERT) <= + INT_GET(agf->agf_length, ARCH_CONVERT))) + cmn_err(CE_NOTE, "Bad freeblks %d %d", + INT_GET(agf->agf_freeblks, ARCH_CONVERT), + INT_GET(agf->agf_length, ARCH_CONVERT)); + if (!(INT_GET(agf->agf_flfirst, ARCH_CONVERT) < XFS_AGFL_SIZE)) + cmn_err(CE_NOTE, "Bad flfirst %d", + INT_GET(agf->agf_flfirst, ARCH_CONVERT)); + if (!(INT_GET(agf->agf_fllast, ARCH_CONVERT) < XFS_AGFL_SIZE)) + cmn_err(CE_NOTE, "Bad fllast %d", + INT_GET(agf->agf_fllast, ARCH_CONVERT)); + if (!(INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE)) + cmn_err(CE_NOTE, "Bad flcount %d", + INT_GET(agf->agf_flcount, ARCH_CONVERT)); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + pag = &mp->m_perag[agno]; + if (!pag->pagf_init) { + pag->pagf_freeblks = INT_GET(agf->agf_freeblks, ARCH_CONVERT); + pag->pagf_flcount = INT_GET(agf->agf_flcount, ARCH_CONVERT); + pag->pagf_longest = INT_GET(agf->agf_longest, ARCH_CONVERT); + pag->pagf_levels[XFS_BTNUM_BNOi] = + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT); + pag->pagf_levels[XFS_BTNUM_CNTi] = + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT); + spinlock_init(&pag->pagb_lock, "xfspagb"); + pag->pagb_list = kmem_zalloc(XFS_PAGB_NUM_SLOTS * + sizeof(xfs_perag_busy_t), KM_SLEEP); + pag->pagf_init = 1; + } +#ifdef DEBUG + else if (!XFS_FORCED_SHUTDOWN(mp)) { + ASSERT(pag->pagf_freeblks == INT_GET(agf->agf_freeblks, ARCH_CONVERT)); + ASSERT(pag->pagf_flcount == INT_GET(agf->agf_flcount, ARCH_CONVERT)); + ASSERT(pag->pagf_longest == INT_GET(agf->agf_longest, ARCH_CONVERT)); + ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] == + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT)); + ASSERT(pag->pagf_levels[XFS_BTNUM_CNTi] == + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT)); + } +#endif + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGF, XFS_AGF_REF); + *bpp = bp; + return 0; +} + +/* + * Allocate an extent (variable-size). + * Depending on the allocation type, we either look in a single allocation + * group or loop over the allocation groups to find the result. + */ +int /* error */ +xfs_alloc_vextent( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_agblock_t agsize; /* allocation group size */ + int error; + int flags; /* XFS_ALLOC_FLAG_... locking flags */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_vextent"; +#endif + xfs_extlen_t minleft;/* minimum left value, temp copy */ + xfs_mount_t *mp; /* mount structure pointer */ + xfs_agnumber_t sagno; /* starting allocation group number */ + xfs_alloctype_t type; /* input allocation type */ + int bump_rotor = 0; + int no_min = 0; + + mp = args->mp; + type = args->otype = args->type; + args->agbno = NULLAGBLOCK; + /* + * Just fix this up, for the case where the last a.g. is shorter + * (or there's only one a.g.) and the caller couldn't easily figure + * that out (xfs_bmap_alloc). + */ + agsize = mp->m_sb.sb_agblocks; + if (args->maxlen > agsize) + args->maxlen = agsize; + if (args->alignment == 0) + args->alignment = 1; + ASSERT(XFS_FSB_TO_AGNO(mp, args->fsbno) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, args->fsbno) < agsize); + ASSERT(args->minlen <= args->maxlen); + ASSERT(args->minlen <= agsize); + ASSERT(args->mod < args->prod); + if (XFS_FSB_TO_AGNO(mp, args->fsbno) >= mp->m_sb.sb_agcount || + XFS_FSB_TO_AGBNO(mp, args->fsbno) >= agsize || + args->minlen > args->maxlen || args->minlen > agsize || + args->mod >= args->prod) { + args->fsbno = NULLFSBLOCK; + TRACE_ALLOC("badargs", args); + return 0; + } + minleft = args->minleft; + + switch (type) { + case XFS_ALLOCTYPE_THIS_AG: + case XFS_ALLOCTYPE_NEAR_BNO: + case XFS_ALLOCTYPE_THIS_BNO: + /* + * These three force us into a single a.g. + */ + args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); + down_read(&mp->m_peraglock); + args->pag = &mp->m_perag[args->agno]; + args->minleft = 0; + error = xfs_alloc_fix_freelist(args, 0); + args->minleft = minleft; + if (error) { + TRACE_ALLOC("nofix", args); + goto error0; + } + if (!args->agbp) { + up_read(&mp->m_peraglock); + TRACE_ALLOC("noagbp", args); + break; + } + args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + if ((error = xfs_alloc_ag_vextent(args))) + goto error0; + up_read(&mp->m_peraglock); + break; + case XFS_ALLOCTYPE_START_BNO: + /* + * Try near allocation first, then anywhere-in-ag after + * the first a.g. fails. + */ + if ((args->userdata == XFS_ALLOC_INITIAL_USER_DATA) && + (mp->m_flags & XFS_MOUNT_32BITINODES)) { + args->fsbno = XFS_AGB_TO_FSB(mp, mp->m_agfrotor, 0); + bump_rotor = 1; + } + args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + args->type = XFS_ALLOCTYPE_NEAR_BNO; + /* FALLTHROUGH */ + case XFS_ALLOCTYPE_ANY_AG: + case XFS_ALLOCTYPE_START_AG: + case XFS_ALLOCTYPE_FIRST_AG: + /* + * Rotate through the allocation groups looking for a winner. + */ + if (type == XFS_ALLOCTYPE_ANY_AG) { + /* + * Start with the last place we left off. + */ + args->agno = sagno = mp->m_agfrotor; + args->type = XFS_ALLOCTYPE_THIS_AG; + flags = XFS_ALLOC_FLAG_TRYLOCK; + } else if (type == XFS_ALLOCTYPE_FIRST_AG) { + /* + * Start with allocation group given by bno. + */ + args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); + args->type = XFS_ALLOCTYPE_THIS_AG; + sagno = 0; + flags = 0; + } else { + if (type == XFS_ALLOCTYPE_START_AG) + args->type = XFS_ALLOCTYPE_THIS_AG; + /* + * Start with the given allocation group. + */ + args->agno = sagno = XFS_FSB_TO_AGNO(mp, args->fsbno); + flags = XFS_ALLOC_FLAG_TRYLOCK; + } + /* + * Loop over allocation groups twice; first time with + * trylock set, second time without. + */ + down_read(&mp->m_peraglock); + for (;;) { + args->pag = &mp->m_perag[args->agno]; + if (no_min) args->minleft = 0; + error = xfs_alloc_fix_freelist(args, flags); + args->minleft = minleft; + if (error) { + TRACE_ALLOC("nofix", args); + goto error0; + } + /* + * If we get a buffer back then the allocation will fly. + */ + if (args->agbp) { + if ((error = xfs_alloc_ag_vextent(args))) + goto error0; + break; + } + TRACE_ALLOC("loopfailed", args); + /* + * Didn't work, figure out the next iteration. + */ + if (args->agno == sagno && + type == XFS_ALLOCTYPE_START_BNO) + args->type = XFS_ALLOCTYPE_THIS_AG; + if (++(args->agno) == mp->m_sb.sb_agcount) + args->agno = 0; + /* + * Reached the starting a.g., must either be done + * or switch to non-trylock mode. + */ + if (args->agno == sagno) { + if (no_min == 1) { + args->agbno = NULLAGBLOCK; + TRACE_ALLOC("allfailed", args); + break; + } + if (flags == 0) { + no_min = 1; + } else { + flags = 0; + if (type == XFS_ALLOCTYPE_START_BNO) { + args->agbno = XFS_FSB_TO_AGBNO(mp, + args->fsbno); + args->type = XFS_ALLOCTYPE_NEAR_BNO; + } + } + } + } + up_read(&mp->m_peraglock); + if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) + mp->m_agfrotor = (args->agno + 1) % mp->m_sb.sb_agcount; + break; + default: + ASSERT(0); + /* NOTREACHED */ + } + if (args->agbno == NULLAGBLOCK) + args->fsbno = NULLFSBLOCK; + else { + args->fsbno = XFS_AGB_TO_FSB(mp, args->agno, args->agbno); +#ifdef DEBUG + ASSERT(args->len >= args->minlen); + ASSERT(args->len <= args->maxlen); + ASSERT(args->agbno % args->alignment == 0); + XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno), + args->len); +#endif + } + return 0; +error0: + up_read(&mp->m_peraglock); + return error; +} + +/* + * Free an extent. + * Just break up the extent address and hand off to xfs_free_ag_extent + * after fixing up the freelist. + */ +int /* error */ +xfs_free_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t bno, /* starting block number of extent */ + xfs_extlen_t len) /* length of extent */ +{ +#ifdef DEBUG + xfs_agf_t *agf; /* a.g. freespace header */ +#endif + xfs_alloc_arg_t args; /* allocation argument structure */ + int error; + + ASSERT(len != 0); + args.tp = tp; + args.mp = tp->t_mountp; + args.agno = XFS_FSB_TO_AGNO(args.mp, bno); + ASSERT(args.agno < args.mp->m_sb.sb_agcount); + args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); + args.alignment = 1; + args.minlen = args.minleft = args.minalignslop = 0; + down_read(&args.mp->m_peraglock); + args.pag = &args.mp->m_perag[args.agno]; + if ((error = xfs_alloc_fix_freelist(&args, 0))) + goto error0; +#ifdef DEBUG + ASSERT(args.agbp != NULL); + agf = XFS_BUF_TO_AGF(args.agbp); + ASSERT(args.agbno + len <= INT_GET(agf->agf_length, ARCH_CONVERT)); +#endif + error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, + len, 0); +error0: + up_read(&args.mp->m_peraglock); + return error; +} + + +/* + * AG Busy list management + * The busy list contains block ranges that have been freed but whose + * transacations have not yet hit disk. If any block listed in a busy + * list is reused, the transaction that freed it must be forced to disk + * before continuing to use the block. + * + * xfs_alloc_mark_busy - add to the per-ag busy list + * xfs_alloc_clear_busy - remove an item from the per-ag busy list + */ +void +xfs_alloc_mark_busy(xfs_trans_t *tp, + xfs_agnumber_t agno, + xfs_agblock_t bno, + xfs_extlen_t len) +{ + xfs_mount_t *mp; + xfs_perag_busy_t *bsy; + int n; + SPLDECL(s); + + mp = tp->t_mountp; + s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); + + /* search pagb_list for an open slot */ + for (bsy = mp->m_perag[agno].pagb_list, n = 0; + n < XFS_PAGB_NUM_SLOTS; + bsy++, n++) { + if (bsy->busy_tp == NULL) { + break; + } + } + + if (n < XFS_PAGB_NUM_SLOTS) { + bsy = &mp->m_perag[agno].pagb_list[n]; + mp->m_perag[agno].pagb_count++; + TRACE_BUSY("xfs_alloc_mark_busy", "got", agno, bno, len, n, tp); + bsy->busy_start = bno; + bsy->busy_length = len; + bsy->busy_tp = tp; + xfs_trans_add_busy(tp, agno, n); + } else { + TRACE_BUSY("xfs_alloc_mark_busy", "FULL", agno, bno, len, -1, tp); + /* + * The busy list is full! Since it is now not possible to + * track the free block, make this a synchronous transaction + * to insure that the block is not reused before this + * transaction commits. + */ + xfs_trans_set_sync(tp); + } + + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); +} + +void +xfs_alloc_clear_busy(xfs_trans_t *tp, + xfs_agnumber_t agno, + int idx) +{ + xfs_mount_t *mp; + xfs_perag_busy_t *list; + SPLDECL(s); + + mp = tp->t_mountp; + + s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); + list = mp->m_perag[agno].pagb_list; + + ASSERT(idx < XFS_PAGB_NUM_SLOTS); + if (list[idx].busy_tp == tp) { + TRACE_UNBUSY("xfs_alloc_clear_busy", "found", agno, idx, tp); + list[idx].busy_tp = NULL; + mp->m_perag[agno].pagb_count--; + } else { + TRACE_UNBUSY("xfs_alloc_clear_busy", "missing", agno, idx, tp); + } + + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); +} + + +/* + * returns non-zero if any of (agno,bno):len is in a busy list + */ +int +xfs_alloc_search_busy(xfs_trans_t *tp, + xfs_agnumber_t agno, + xfs_agblock_t bno, + xfs_extlen_t len) +{ + xfs_mount_t *mp; + xfs_perag_busy_t *bsy; + int n; + xfs_agblock_t uend, bend; + xfs_lsn_t lsn; + int cnt; + SPLDECL(s); + + mp = tp->t_mountp; + + s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); + cnt = mp->m_perag[agno].pagb_count; + + uend = bno + len - 1; + + /* search pagb_list for this slot, skipping open slots */ + for (bsy = mp->m_perag[agno].pagb_list, n = 0; + cnt; bsy++, n++) { + + /* + * (start1,length1) within (start2, length2) + */ + if (bsy->busy_tp != NULL) { + bend = bsy->busy_start + bsy->busy_length - 1; + if ((bno > bend) || + (uend < bsy->busy_start)) { + cnt--; + } else { + TRACE_BUSYSEARCH("xfs_alloc_search_busy", + "found1", agno, bno, len, n, + tp); + break; + } + } + } + + /* + * If a block was found, force the log through the LSN of the + * transaction that freed the block + */ + if (cnt) { + TRACE_BUSYSEARCH("xfs_alloc_search_busy", "found", agno, bno, len, n, tp); + lsn = bsy->busy_tp->t_commit_lsn; + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); + xfs_log_force(mp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC); + } else { + TRACE_BUSYSEARCH("xfs_alloc_search_busy", "not-found", agno, bno, len, n, tp); + n = -1; + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); + } + + return n; +} diff -Nur linux-2.4.19/fs/xfs/xfs_alloc.h linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc.h --- linux-2.4.19/fs/xfs/xfs_alloc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ALLOC_H__ +#define __XFS_ALLOC_H__ + +struct xfs_buf; +struct xfs_mount; +struct xfs_perag; +struct xfs_trans; + +/* + * Freespace allocation types. Argument to xfs_alloc_[v]extent. + */ +typedef enum xfs_alloctype +{ + XFS_ALLOCTYPE_ANY_AG, /* allocate anywhere, use rotor */ + XFS_ALLOCTYPE_FIRST_AG, /* ... start at ag 0 */ + XFS_ALLOCTYPE_START_AG, /* anywhere, start in this a.g. */ + XFS_ALLOCTYPE_THIS_AG, /* anywhere in this a.g. */ + XFS_ALLOCTYPE_START_BNO, /* near this block else anywhere */ + XFS_ALLOCTYPE_NEAR_BNO, /* in this a.g. and near this block */ + XFS_ALLOCTYPE_THIS_BNO /* at exactly this block */ +} xfs_alloctype_t; + +/* + * Flags for xfs_alloc_fix_freelist. + */ +#define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ + +/* + * Argument structure for xfs_alloc routines. + * This is turned into a structure to avoid having 20 arguments passed + * down several levels of the stack. + */ +typedef struct xfs_alloc_arg { + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_mount *mp; /* file system mount point */ + struct xfs_buf *agbp; /* buffer for a.g. freelist header */ + struct xfs_perag *pag; /* per-ag struct for this agno */ + xfs_fsblock_t fsbno; /* file system block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agblock_t agbno; /* allocation group-relative block # */ + xfs_extlen_t minlen; /* minimum size of extent */ + xfs_extlen_t maxlen; /* maximum size of extent */ + xfs_extlen_t mod; /* mod value for extent size */ + xfs_extlen_t prod; /* prod value for extent size */ + xfs_extlen_t minleft; /* min blocks must be left after us */ + xfs_extlen_t total; /* total blocks needed in xaction */ + xfs_extlen_t alignment; /* align answer to multiple of this */ + xfs_extlen_t minalignslop; /* slop for minlen+alignment calcs */ + xfs_extlen_t len; /* output: actual size of extent */ + xfs_alloctype_t type; /* allocation type XFS_ALLOCTYPE_... */ + xfs_alloctype_t otype; /* original allocation type */ + char wasdel; /* set if allocation was prev delayed */ + char wasfromfl; /* set if allocation is from freelist */ + char isfl; /* set if is freelist blocks - !actg */ + char userdata; /* set if this is user data */ +} xfs_alloc_arg_t; + +/* + * Defines for userdata + */ +#define XFS_ALLOC_USERDATA 1 /* allocation is for user data*/ +#define XFS_ALLOC_INITIAL_USER_DATA 2 /* special case start of file */ + + +#ifdef __KERNEL__ + +/* + * Types for alloc tracing. + */ +#define XFS_ALLOC_KTRACE_ALLOC 1 +#define XFS_ALLOC_KTRACE_FREE 2 +#define XFS_ALLOC_KTRACE_MODAGF 3 +#define XFS_ALLOC_KTRACE_BUSY 4 +#define XFS_ALLOC_KTRACE_UNBUSY 5 +#define XFS_ALLOC_KTRACE_BUSYSEARCH 6 + + +/* + * Allocation tracing buffer size. + */ +#define XFS_ALLOC_TRACE_SIZE 4096 + +#ifdef XFS_ALL_TRACE +#define XFS_ALLOC_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ALLOC_TRACE +#endif + +/* + * Prototypes for visible xfs_alloc.c routines + */ + +/* + * Compute and fill in value of m_ag_maxlevels. + */ +void +xfs_alloc_compute_maxlevels( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Decide whether to use this allocation group for this allocation. + * If so, fix up the btree freelist's size. + * This is external so mkfs can call it, too. + */ +int /* error */ +xfs_alloc_fix_freelist( + xfs_alloc_arg_t *args, /* allocation argument structure */ + int flags); /* XFS_ALLOC_FLAG_... */ + +/* + * Get a block from the freelist. + * Returns with the buffer for the block gotten. + */ +int /* error */ +xfs_alloc_get_freelist( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* buffer containing the agf structure */ + xfs_agblock_t *bnop); /* block address retrieved from freelist */ + +/* + * Log the given fields from the agf structure. + */ +void +xfs_alloc_log_agf( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *bp, /* buffer for a.g. freelist header */ + int fields);/* mask of fields to be logged (XFS_AGF_...) */ + +/* + * Interface for inode allocation to force the pag data to be initialized. + */ +int /* error */ +xfs_alloc_pagf_init( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags); /* XFS_ALLOC_FLAGS_... */ + +/* + * Put the block on the freelist for the allocation group. + */ +int /* error */ +xfs_alloc_put_freelist( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* buffer for a.g. freelist header */ + struct xfs_buf *agflbp,/* buffer for a.g. free block array */ + xfs_agblock_t bno); /* block being freed */ + +/* + * Read in the allocation group header (free/alloc section). + */ +int /* error */ +xfs_alloc_read_agf( + struct xfs_mount *mp, /* mount point structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags, /* XFS_ALLOC_FLAG_... */ + struct xfs_buf **bpp); /* buffer for the ag freelist header */ + +/* + * Allocate an extent (variable-size). + */ +int /* error */ +xfs_alloc_vextent( + xfs_alloc_arg_t *args); /* allocation argument structure */ + +/* + * Free an extent. + */ +int /* error */ +xfs_free_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t bno, /* starting block number of extent */ + xfs_extlen_t len); /* length of extent */ + +void +xfs_alloc_mark_busy(xfs_trans_t *tp, + xfs_agnumber_t agno, + xfs_agblock_t bno, + xfs_extlen_t len); + +void +xfs_alloc_clear_busy(xfs_trans_t *tp, + xfs_agnumber_t ag, + int idx); + + +#endif /* __KERNEL__ */ + +#endif /* __XFS_ALLOC_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_alloc_btree.c linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc_btree.c --- linux-2.4.19/fs/xfs/xfs_alloc_btree.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc_btree.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,2187 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free space allocation for XFS. + */ + +#include + +/* + * Prototypes for internal functions. + */ + +STATIC void xfs_alloc_log_block(xfs_trans_t *, xfs_buf_t *, int); +STATIC void xfs_alloc_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_alloc_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_alloc_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC int xfs_alloc_lshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_alloc_newroot(xfs_btree_cur_t *, int *); +STATIC int xfs_alloc_rshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_alloc_split(xfs_btree_cur_t *, int, xfs_agblock_t *, + xfs_alloc_key_t *, xfs_btree_cur_t **, int *); +STATIC int xfs_alloc_updkey(xfs_btree_cur_t *, xfs_alloc_key_t *, int); + +/* + * Internal functions. + */ + +/* + * Single level of the xfs_alloc_delete record deletion routine. + * Delete record pointed to by cur/level. + * Remove the record from its block then rebalance the tree. + * Return 0 for error, 1 for done, 2 to go on to the next level. + */ +STATIC int /* error */ +xfs_alloc_delrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level removing record from */ + int *stat) /* fail/done/go-on */ +{ + xfs_agf_t *agf; /* allocation group freelist header */ + xfs_alloc_block_t *block; /* btree block record/key lives in */ + xfs_agblock_t bno; /* btree block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* kp points here if block is level 0 */ + xfs_agblock_t lbno; /* left block's block number */ + xfs_buf_t *lbp; /* left block's buffer pointer */ + xfs_alloc_block_t *left; /* left btree block */ + xfs_alloc_key_t *lkp=NULL; /* left block key pointer */ + xfs_alloc_ptr_t *lpp=NULL; /* left block address pointer */ + int lrecs=0; /* number of records in left block */ + xfs_alloc_rec_t *lrp; /* left block record pointer */ + xfs_mount_t *mp; /* mount structure */ + int ptr; /* index in btree block for this rec */ + xfs_agblock_t rbno; /* right block's block number */ + xfs_buf_t *rbp; /* right block's buffer pointer */ + xfs_alloc_block_t *right; /* right btree block */ + xfs_alloc_key_t *rkp; /* right block key pointer */ + xfs_alloc_ptr_t *rpp; /* right block address pointer */ + int rrecs=0; /* number of records in right block */ + xfs_alloc_rec_t *rrp; /* right block record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + + /* + * Get the index of the entry being deleted, check for nothing there. + */ + ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get the buffer & block containing the record or key/ptr. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Fail if we're off the end of the block. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_abt_delrec); + /* + * It's a nonleaf. Excise the key and ptr being deleted, by + * sliding the entries past them down one. + * Log the changed areas of the block. + */ + if (level > 0) { + lkp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + lpp = XFS_ALLOC_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&lkp[ptr], &lkp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lkp)); /* INT_: mem copy */ + ovbcopy(&lpp[ptr], &lpp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lpp)); /* INT_: mem copy */ + xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + } + /* + * It's a leaf. Excise the record being deleted, by sliding the + * entries past it down one. Log the changed areas of the block. + */ + else { + lrp = XFS_ALLOC_REC_ADDR(block, 1, cur); + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&lrp[ptr], &lrp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lrp)); + xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + /* + * If it's the first record in the block, we'll need a key + * structure to pass up to the next level (updkey). + */ + if (ptr == 1) { + key.ar_startblock = lrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = lrp->ar_blockcount; /* INT_: direct copy */ + lkp = &key; + } + } + /* + * Decrement and log the number of entries in the block. + */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * See if the longest free extent in the allocation group was + * changed by this operation. True if it's the by-size btree, and + * this is the leaf level, and there is no right sibling block, + * and this was the last record. + */ + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + mp = cur->bc_mp; + + if (level == 0 && + cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ASSERT(ptr == INT_GET(block->bb_numrecs, ARCH_CONVERT) + 1); + /* + * There are still records in the block. Grab the size + * from the last one. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + rrp = XFS_ALLOC_REC_ADDR(block, INT_GET(block->bb_numrecs, ARCH_CONVERT), cur); + INT_COPY(agf->agf_longest, rrp->ar_blockcount, ARCH_CONVERT); + } + /* + * No free extents left. + */ + else + INT_ZERO(agf->agf_longest, ARCH_CONVERT); + mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_longest = + INT_GET(agf->agf_longest, ARCH_CONVERT); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Is this the root level? If so, we're almost done. + */ + if (level == cur->bc_nlevels - 1) { + /* + * If this is the root level, + * and there's only one entry left, + * and it's NOT the leaf level, + * then we can get rid of this level. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == 1 && level > 0) { + /* + * lpp is still set to the first pointer in the block. + * Make it the new root of the btree. + */ + bno = INT_GET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT); + INT_COPY(agf->agf_roots[cur->bc_btnum], *lpp, ARCH_CONVERT); + INT_MOD(agf->agf_levels[cur->bc_btnum], ARCH_CONVERT, -1); + mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_levels[cur->bc_btnum]--; + /* + * Put this buffer/block on the ag's freelist. + */ + if ((error = xfs_alloc_put_freelist(cur->bc_tp, + cur->bc_private.a.agbp, NULL, bno))) + return error; + /* + * Since blocks move to the free list without the + * coordination used in xfs_bmap_finish, we can't allow + * block to be available for reallocation and + * non-transaction writing (user data) until we know + * that the transaction that moved it to the free list + * is permanently on disk. We track the blocks by + * declaring these blocks as "busy"; the busy list is + * maintained on a per-ag basis and each transaction + * records which entries should be removed when the + * iclog commits to disk. If a busy block is + * allocated, the iclog is pushed up to the LSN + * that freed the block. + */ + xfs_alloc_mark_busy(cur->bc_tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), bno, 1); + + xfs_trans_agbtree_delta(cur->bc_tp, -1); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_ROOTS | XFS_AGF_LEVELS); + /* + * Update the cursor so there's one fewer level. + */ + xfs_btree_setbuf(cur, level, 0); + cur->bc_nlevels--; + } else if (level > 0 && + (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * If we deleted the leftmost entry in the block, update the + * key values above us in the tree. + */ + if (ptr == 1 && (error = xfs_alloc_updkey(cur, lkp, level + 1))) + return error; + /* + * If the number of records remaining in the block is at least + * the minimum, we're done. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * Otherwise, we have to move some records around to keep the + * tree balanced. Look at the left and right sibling blocks to + * see if we can re-balance by moving only one record. + */ + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + bno = NULLAGBLOCK; + ASSERT(rbno != NULLAGBLOCK || lbno != NULLAGBLOCK); + /* + * Duplicate the cursor so our btree manipulations here won't + * disrupt the next level up. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + /* + * If there's a right sibling, see if it's ok to shift an entry + * out of it. + */ + if (rbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the last entry in the next block. + * Actually any entry but the first would suffice. + */ + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_increment(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Grab a pointer to the block. + */ + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + /* + * If right block is full enough so that removing one entry + * won't make it too empty, and left-shifting an entry out + * of right to us works, we're done. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if ((error = xfs_alloc_lshift(tcur, level, &i))) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level > 0 && + (error = xfs_alloc_decrement(cur, level, + &i))) + return error; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference, and fix up the temp cursor to point + * to our block again (last record). + */ + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLAGBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_decrement(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + /* + * If there's a left sibling, see if it's ok to shift an entry + * out of it. + */ + if (lbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the first entry in the + * previous block. + */ + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_decrement(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_btree_firstrec(tcur, level); + /* + * Grab a pointer to the block. + */ + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + /* + * If left block is full enough so that removing one entry + * won't make it too empty, and right-shifting an entry out + * of left to us works, we're done. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if ((error = xfs_alloc_rshift(tcur, level, &i))) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level == 0) + cur->bc_ptrs[0]++; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference. + */ + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * Delete the temp cursor, we're done with it. + */ + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + /* + * If here, we need to do a join to keep the tree balanced. + */ + ASSERT(bno != NULLAGBLOCK); + /* + * See if we can join with the left neighbor block. + */ + if (lbno != NULLAGBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * Set "right" to be the starting block, + * "left" to be the left neighbor. + */ + rbno = bno; + right = block; + rbp = bp; + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, lbno, 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + } + /* + * If that won't work, see if we can join with the right neighbor block. + */ + else if (rbno != NULLAGBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * Set "left" to be the starting block, + * "right" to be the right neighbor. + */ + lbno = bno; + left = block; + lbp = bp; + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, rbno, 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + } + /* + * Otherwise, we can't fix the imbalance. + * Just return. This is probably a logic error, but it's not fatal. + */ + else { + if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * We're now going to join "left" and "right" by moving all the stuff + * in "right" to "left" and deleting "right". + */ + if (level > 0) { + /* + * It's a non-leaf. Move keys and pointers. + */ + lkp = XFS_ALLOC_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + lpp = XFS_ALLOC_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); /* INT_: structure copy */ + bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); /* INT_: structure copy */ + xfs_alloc_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf. Move records. + */ + lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp)); + xfs_alloc_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } + /* + * If we joined with the left neighbor, set the buffer in the + * cursor to the left block, and fix up the index. + */ + if (bp != lbp) { + xfs_btree_setbuf(cur, level, lbp); + cur->bc_ptrs[level] += INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If we joined with the right neighbor and there's a level above + * us, increment the cursor at that level. + */ + else if (level + 1 < cur->bc_nlevels && + (error = xfs_alloc_increment(cur, level + 1, &i))) + return error; + /* + * Fix up the number of records in the surviving block. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + /* + * Fix up the right block pointer in the surviving block, and log it. + */ + left->bb_rightsib = right->bb_rightsib; /* INT_: direct copy */ + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there is a right sibling now, make it point to the + * remaining block. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_alloc_block_t *rrblock; + xfs_buf_t *rrbp; + + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_ALLOC_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * Free the deleting block by putting it on the freelist. + */ + if ((error = xfs_alloc_put_freelist(cur->bc_tp, cur->bc_private.a.agbp, + NULL, rbno))) + return error; + /* + * Since blocks move to the free list without the coordination + * used in xfs_bmap_finish, we can't allow block to be available + * for reallocation and non-transaction writing (user data) + * until we know that the transaction that moved it to the free + * list is permanently on disk. We track the blocks by declaring + * these blocks as "busy"; the busy list is maintained on a + * per-ag basis and each transaction records which entries + * should be removed when the iclog commits to disk. If a + * busy block is allocated, the iclog is pushed up to the + * LSN that freed the block. + */ + xfs_alloc_mark_busy(cur->bc_tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), bno, 1); + + xfs_trans_agbtree_delta(cur->bc_tp, -1); + /* + * Adjust the current level's cursor so that we're left referring + * to the right node, after we're done. + * If this leaves the ptr value 0 our caller will fix it up. + */ + if (level > 0) + cur->bc_ptrs[level]--; + /* + * Return value means the next level up has something to do. + */ + *stat = 2; + return 0; + +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_alloc_insrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to insert record at */ + xfs_agblock_t *bnop, /* i/o: block number inserted */ + xfs_alloc_rec_t *recp, /* i/o: record data inserted */ + xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ + int *stat) /* output: success/failure */ +{ + xfs_agf_t *agf; /* allocation group freelist header */ + xfs_alloc_block_t *block; /* btree block record/key lives in */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* key value being inserted */ + xfs_alloc_key_t *kp; /* pointer to btree keys */ + xfs_agblock_t nbno; /* block number of allocated block */ + xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ + xfs_alloc_key_t nkey; /* new key value, from split */ + xfs_alloc_rec_t nrec; /* new record value, for caller */ + int optr; /* old ptr value */ + xfs_alloc_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_alloc_rec_t *rp; /* pointer to btree records */ + + ASSERT(INT_GET(recp->ar_blockcount, ARCH_CONVERT) > 0); + /* + * If we made it to the root level, allocate a new root block + * and we're done. + */ + if (level >= cur->bc_nlevels) { + XFS_STATS_INC(xfsstats.xs_abt_insrec); + if ((error = xfs_alloc_newroot(cur, &i))) + return error; + *bnop = NULLAGBLOCK; + *stat = i; + return 0; + } + /* + * Make a key out of the record data to be inserted, and save it. + */ + key.ar_startblock = recp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = recp->ar_blockcount; /* INT_: direct copy */ + optr = ptr = cur->bc_ptrs[level]; + /* + * If we're off the left edge, return failure. + */ + if (ptr == 0) { + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_abt_insrec); + /* + * Get pointers to the btree buffer and block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; + /* + * Check that the new entry is being inserted in the right place. + */ + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); + xfs_btree_check_rec(cur->bc_btnum, recp, rp); + } else { + kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur); + xfs_btree_check_key(cur->bc_btnum, &key, kp); + } + } +#endif + nbno = NULLAGBLOCK; + ncur = (xfs_btree_cur_t *)0; + /* + * If the block is full, we can't insert the new entry until we + * make the block un-full. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * First, try shifting an entry to the right neighbor. + */ + if ((error = xfs_alloc_rshift(cur, level, &i))) + return error; + if (i) { + /* nothing */ + } + /* + * Next, try shifting an entry to the left neighbor. + */ + else { + if ((error = xfs_alloc_lshift(cur, level, &i))) + return error; + if (i) + optr = ptr = cur->bc_ptrs[level]; + else { + /* + * Next, try splitting the current block in + * half. If this works we have to re-set our + * variables because we could be in a + * different block now. + */ + if ((error = xfs_alloc_split(cur, level, &nbno, + &nkey, &ncur, &i))) + return error; + if (i) { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = + xfs_btree_check_sblock(cur, + block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + nrec.ar_startblock = nkey.ar_startblock; /* INT_: direct copy */ + nrec.ar_blockcount = nkey.ar_blockcount; /* INT_: direct copy */ + } + /* + * Otherwise the insert fails. + */ + else { + *stat = 0; + return 0; + } + } + } + } + /* + * At this point we know there's room for our new entry in the block + * we're pointing at. + */ + if (level > 0) { + /* + * It's a non-leaf entry. Make a hole for the new data + * in the key and ptr regions of the block. + */ + kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); /* INT_: copy */ + ovbcopy(&pp[ptr - 1], &pp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); /* INT_: copy */ +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, *bnop, level))) + return error; +#endif + /* + * Now stuff the new data in, bump numrecs and log the new data. + */ + kp[ptr - 1] = key; + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) + xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, + kp + ptr); +#endif + } else { + /* + * It's a leaf entry. Make a hole for the new record. + */ + rp = XFS_ALLOC_REC_ADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + /* + * Now stuff the new record in, bump numrecs + * and log the new data. + */ + rp[ptr - 1] = *recp; /* INT_: struct copy */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) + xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, + rp + ptr); +#endif + } + /* + * Log the new number of records in the btree header. + */ + xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * If we inserted at the start of a block, update the parents' keys. + */ + if (optr == 1 && (error = xfs_alloc_updkey(cur, &key, level + 1))) + return error; + /* + * Look to see if the longest extent in the allocation group + * needs to be updated. + */ + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + if (level == 0 && + cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + INT_GET(recp->ar_blockcount, ARCH_CONVERT) > INT_GET(agf->agf_longest, ARCH_CONVERT)) { + /* + * If this is a leaf in the by-size btree and there + * is no right sibling block and this block is bigger + * than the previous longest block, update it. + */ + INT_COPY(agf->agf_longest, recp->ar_blockcount, ARCH_CONVERT); + cur->bc_mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_longest + = INT_GET(recp->ar_blockcount, ARCH_CONVERT); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Return the new block number, if any. + * If there is one, give back a record value and a cursor too. + */ + *bnop = nbno; + if (nbno != NULLAGBLOCK) { + *recp = nrec; /* INT_: struct copy */ + *curp = ncur; /* INT_: struct copy */ + } + *stat = 1; + return 0; +} + +/* + * Log header fields from a btree block. + */ +STATIC void +xfs_alloc_log_block( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer containing btree block */ + int fields) /* mask of fields: XFS_BB_... */ +{ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + static const short offsets[] = { /* table of offsets */ + offsetof(xfs_alloc_block_t, bb_magic), + offsetof(xfs_alloc_block_t, bb_level), + offsetof(xfs_alloc_block_t, bb_numrecs), + offsetof(xfs_alloc_block_t, bb_leftsib), + offsetof(xfs_alloc_block_t, bb_rightsib), + sizeof(xfs_alloc_block_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Log keys from a btree block (nonleaf). + */ +STATIC void +xfs_alloc_log_keys( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int kfirst, /* index of first key to log */ + int klast) /* index of last key to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + xfs_alloc_key_t *kp; /* key pointer in btree block */ + int last; /* last byte offset logged */ + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log block pointer fields from a btree block (nonleaf). + */ +STATIC void +xfs_alloc_log_ptrs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int pfirst, /* index of first pointer to log */ + int plast) /* index of last pointer to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_alloc_ptr_t *pp; /* block-pointer pointer in btree blk */ + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log records from a btree block (leaf). + */ +STATIC void +xfs_alloc_log_recs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int rfirst, /* index of first record to log */ + int rlast) /* index of last record to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_alloc_rec_t *rp; /* record pointer for btree block */ + + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + rp = XFS_ALLOC_REC_ADDR(block, 1, cur); +#ifdef DEBUG + { + xfs_agf_t *agf; + xfs_alloc_rec_t *p; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + for (p = &rp[rfirst - 1]; p <= &rp[rlast - 1]; p++) + ASSERT(INT_GET(p->ar_startblock, ARCH_CONVERT) + INT_GET(p->ar_blockcount, ARCH_CONVERT) <= + INT_GET(agf->agf_length, ARCH_CONVERT)); + } +#endif + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + * Return 0 if can't find any such record, 1 for success. + */ +STATIC int /* error */ +xfs_alloc_lookup( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_lookup_t dir, /* <=, ==, or >= */ + int *stat) /* success/failure */ +{ + xfs_agblock_t agbno; /* a.g. relative btree block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_alloc_block_t *block=NULL; /* current btree block */ + int diff; /* difference for the current key */ + int error; /* error return value */ + int keyno=0; /* current key number */ + int level; /* level in the btree */ + xfs_mount_t *mp; /* file system mount point */ + + XFS_STATS_INC(xfsstats.xs_abt_lookup); + /* + * Get the allocation group header, and the root block number. + */ + mp = cur->bc_mp; + + { + xfs_agf_t *agf; /* a.g. freespace header */ + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + agno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + agbno = INT_GET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT); + } + /* + * Iterate over each level in the btree, starting at the root. + * For each level above the leaves, find the key we need, based + * on the lookup record, then follow the corresponding block + * pointer down to the next level. + */ + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + xfs_buf_t *bp; /* buffer pointer for btree block */ + xfs_daddr_t d; /* disk address of btree block */ + + /* + * Get the disk address we're looking for. + */ + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + /* + * If the old buffer at this level is for a different block, + * throw it away, otherwise just use it. + */ + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, agno, + agbno, 0, &bp, XFS_ALLOC_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + /* + * If we already had a key match at a higher level, we know + * we need to use the first entry in this block. + */ + if (diff == 0) + keyno = 1; + /* + * Otherwise we need to search this block. Do a binary search. + */ + else { + int high; /* high entry number */ + xfs_alloc_key_t *kkbase=NULL;/* base of keys in block */ + xfs_alloc_rec_t *krbase=NULL;/* base of records in block */ + int low; /* low entry number */ + + /* + * Get a pointer to keys or records. + */ + if (level > 0) + kkbase = XFS_ALLOC_KEY_ADDR(block, 1, cur); + else + krbase = XFS_ALLOC_REC_ADDR(block, 1, cur); + /* + * Set low and high entry numbers, 1-based. + */ + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + /* + * If the block is empty, the tree must + * be an empty leaf. + */ + ASSERT(level == 0 && cur->bc_nlevels == 1); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + *stat = 0; + return 0; + } + /* + * Binary search the block. + */ + while (low <= high) { + xfs_extlen_t blockcount; /* key value */ + xfs_agblock_t startblock; /* key value */ + + XFS_STATS_INC(xfsstats.xs_abt_compare); + /* + * keyno is average of low and high. + */ + keyno = (low + high) >> 1; + /* + * Get startblock & blockcount. + */ + if (level > 0) { + xfs_alloc_key_t *kkp; + + kkp = kkbase + keyno - 1; + startblock = INT_GET(kkp->ar_startblock, ARCH_CONVERT); + blockcount = INT_GET(kkp->ar_blockcount, ARCH_CONVERT); + } else { + xfs_alloc_rec_t *krp; + + krp = krbase + keyno - 1; + startblock = INT_GET(krp->ar_startblock, ARCH_CONVERT); + blockcount = INT_GET(krp->ar_blockcount, ARCH_CONVERT); + } + /* + * Compute difference to get next direction. + */ + if (cur->bc_btnum == XFS_BTNUM_BNO) + diff = (int)startblock - + (int)cur->bc_rec.a.ar_startblock; + else if (!(diff = (int)blockcount - + (int)cur->bc_rec.a.ar_blockcount)) + diff = (int)startblock - + (int)cur->bc_rec.a.ar_startblock; + /* + * Less than, move right. + */ + if (diff < 0) + low = keyno + 1; + /* + * Greater than, move left. + */ + else if (diff > 0) + high = keyno - 1; + /* + * Equal, we're done. + */ + else + break; + } + } + /* + * If there are more levels, set up for the next level + * by getting the block number and filling in the cursor. + */ + if (level > 0) { + /* + * If we moved left, need the previous key number, + * unless there isn't one. + */ + if (diff > 0 && --keyno < 1) + keyno = 1; + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, keyno, cur), ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, agbno, level))) + return error; +#endif + cur->bc_ptrs[level] = keyno; + } + } + /* + * Done with the search. + * See if we need to adjust the results. + */ + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && + keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + int i; + + cur->bc_ptrs[0] = keyno; + if ((error = xfs_alloc_increment(cur, 0, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + /* + * Return if we succeeded or not. + */ + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) + *stat = 0; + else + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_alloc_lshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef DEBUG + int i; /* loop index */ +#endif + xfs_alloc_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left neighbor block */ + xfs_alloc_block_t *left; /* left neighbor btree block */ + int nrec; /* new number of left block entries */ + xfs_buf_t *rbp; /* buffer for right (current) block */ + xfs_alloc_block_t *right; /* right (current) btree block */ + xfs_alloc_key_t *rkp=NULL; /* key pointer for right block */ + xfs_alloc_ptr_t *rpp=NULL; /* address pointer for right block */ + xfs_alloc_rec_t *rrp=NULL; /* record pointer for right block */ + + /* + * Set up variables for this block as "right". + */ + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; +#endif + /* + * If we've got no left sibling then we can't shift an entry left. + */ + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] <= 1) { + *stat = 0; + return 0; + } + /* + * Set up the left neighbor as "left". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + nrec = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + /* + * If non-leaf, copy a key and a ptr to the left block. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* key pointer for left block */ + xfs_alloc_ptr_t *lpp; /* address pointer for left block */ + + lkp = XFS_ALLOC_KEY_ADDR(left, nrec, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + *lkp = *rkp; + xfs_alloc_log_keys(cur, lbp, nrec, nrec); + lpp = XFS_ALLOC_PTR_ADDR(left, nrec, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) + return error; +#endif + *lpp = *rpp; /* INT_: copy */ + xfs_alloc_log_ptrs(cur, lbp, nrec, nrec); + xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp); + } + /* + * If leaf, copy a record to the left block. + */ + else { + xfs_alloc_rec_t *lrp; /* record pointer for left block */ + + lrp = XFS_ALLOC_REC_ADDR(left, nrec, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + *lrp = *rrp; + xfs_alloc_log_recs(cur, lbp, nrec, nrec); + xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); + } + /* + * Bump and log left's numrecs, decrement and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Slide the contents of right down one entry. + */ + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) + return error; + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + rkp = &key; + } + /* + * Update the parent key values of right. + */ + if ((error = xfs_alloc_updkey(cur, rkp, level + 1))) + return error; + /* + * Slide the cursor value left one. + */ + cur->bc_ptrs[level]--; + *stat = 1; + return 0; +} + +/* + * Allocate a new root block, fill it in. + */ +STATIC int /* error */ +xfs_alloc_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + xfs_agblock_t lbno; /* left block number */ + xfs_buf_t *lbp; /* left btree buffer */ + xfs_alloc_block_t *left; /* left btree block */ + xfs_mount_t *mp; /* mount structure */ + xfs_agblock_t nbno; /* new block number */ + xfs_buf_t *nbp; /* new (root) buffer */ + xfs_alloc_block_t *new; /* new (root) btree block */ + int nptr; /* new value for key index, 1 or 2 */ + xfs_agblock_t rbno; /* right block number */ + xfs_buf_t *rbp; /* right btree buffer */ + xfs_alloc_block_t *right; /* right btree block */ + + mp = cur->bc_mp; + + ASSERT(cur->bc_nlevels < XFS_AG_MAXLEVELS(mp)); + /* + * Get a buffer from the freelist blocks, for the new root. + */ + if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, + &nbno))) + return error; + /* + * None available, we fail. + */ + if (nbno == NULLAGBLOCK) { + *stat = 0; + return 0; + } + xfs_trans_agbtree_delta(cur->bc_tp, 1); + nbp = xfs_btree_get_bufs(mp, cur->bc_tp, cur->bc_private.a.agno, nbno, + 0); + new = XFS_BUF_TO_ALLOC_BLOCK(nbp); + /* + * Set the root data in the a.g. freespace structure. + */ + { + xfs_agf_t *agf; /* a.g. freespace header */ + xfs_agnumber_t seqno; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + INT_SET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT, nbno); + INT_MOD(agf->agf_levels[cur->bc_btnum], ARCH_CONVERT, 1); + seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + mp->m_perag[seqno].pagf_levels[cur->bc_btnum]++; + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_ROOTS | XFS_AGF_LEVELS); + } + /* + * At the previous root level there are now two blocks: the old + * root, and the new block generated when it was split. + * We don't know which one the cursor is pointing at, so we + * set up variables "left" and "right" for each case. + */ + lbp = cur->bc_bufs[cur->bc_nlevels - 1]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, cur->bc_nlevels - 1, lbp))) + return error; +#endif + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + /* + * Our block is left, pick up the right block. + */ + lbno = XFS_DADDR_TO_AGBNO(mp, XFS_BUF_ADDR(lbp)); + rbno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, rbno, 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, + cur->bc_nlevels - 1, rbp))) + return error; + nptr = 1; + } else { + /* + * Our block is right, pick up the left block. + */ + rbp = lbp; + right = left; + rbno = XFS_DADDR_TO_AGBNO(mp, XFS_BUF_ADDR(rbp)); + lbno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, lbno, 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, + cur->bc_nlevels - 1, lbp))) + return error; + nptr = 2; + } + /* + * Fill in the new block's btree header and log it. + */ + INT_SET(new->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + INT_SET(new->bb_level, ARCH_CONVERT, (__uint16_t)cur->bc_nlevels); + INT_SET(new->bb_numrecs, ARCH_CONVERT, 2); + INT_SET(new->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(new->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + xfs_alloc_log_block(cur->bc_tp, nbp, XFS_BB_ALL_BITS); + ASSERT(lbno != NULLAGBLOCK && rbno != NULLAGBLOCK); + /* + * Fill in the key data in the new root. + */ + { + xfs_alloc_key_t *kp; /* btree key pointer */ + + kp = XFS_ALLOC_KEY_ADDR(new, 1, cur); + if (INT_GET(left->bb_level, ARCH_CONVERT) > 0) { + kp[0] = *XFS_ALLOC_KEY_ADDR(left, 1, cur); /* INT_: structure copy */ + kp[1] = *XFS_ALLOC_KEY_ADDR(right, 1, cur);/* INT_: structure copy */ + } else { + xfs_alloc_rec_t *rp; /* btree record pointer */ + + rp = XFS_ALLOC_REC_ADDR(left, 1, cur); + kp[0].ar_startblock = rp->ar_startblock; /* INT_: direct copy */ + kp[0].ar_blockcount = rp->ar_blockcount; /* INT_: direct copy */ + rp = XFS_ALLOC_REC_ADDR(right, 1, cur); + kp[1].ar_startblock = rp->ar_startblock; /* INT_: direct copy */ + kp[1].ar_blockcount = rp->ar_blockcount; /* INT_: direct copy */ + } + } + xfs_alloc_log_keys(cur, nbp, 1, 2); + /* + * Fill in the pointer data in the new root. + */ + { + xfs_alloc_ptr_t *pp; /* btree address pointer */ + + pp = XFS_ALLOC_PTR_ADDR(new, 1, cur); + INT_SET(pp[0], ARCH_CONVERT, lbno); + INT_SET(pp[1], ARCH_CONVERT, rbno); + } + xfs_alloc_log_ptrs(cur, nbp, 1, 2); + /* + * Fix up the cursor. + */ + xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); + cur->bc_ptrs[cur->bc_nlevels] = nptr; + cur->bc_nlevels++; + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_alloc_rshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left (current) block */ + xfs_alloc_block_t *left; /* left (current) btree block */ + xfs_buf_t *rbp; /* buffer for right neighbor block */ + xfs_alloc_block_t *right; /* right neighbor btree block */ + xfs_alloc_key_t *rkp; /* key pointer for right block */ + xfs_btree_cur_t *tcur; /* temporary cursor */ + + /* + * Set up variables for this block as "left". + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * If we've got no right sibling then we can't shift an entry right. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * Set up the right neighbor as "right". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + /* + * Make a hole at the start of the right neighbor block, then + * copy the last left block entry to the hole. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* key pointer for left block */ + xfs_alloc_ptr_t *lpp; /* address pointer for left block */ + xfs_alloc_ptr_t *rpp; /* address pointer for right block */ + + lkp = XFS_ALLOC_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_ALLOC_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) + return error; +#endif + *rkp = *lkp; /* INT_: copy */ + *rpp = *lpp; /* INT_: copy */ + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); + } else { + xfs_alloc_rec_t *lrp; /* record pointer for left block */ + xfs_alloc_rec_t *rrp; /* record pointer for right block */ + + lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + rkp = &key; + xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1); + } + /* + * Decrement and log left's numrecs, bump and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Using a temporary cursor, update the parent key values of the + * block on the right. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_increment(tcur, level, &i)) || + (error = xfs_alloc_updkey(tcur, rkp, level + 1))) + goto error0; + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + *stat = 1; + return 0; +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_alloc_split( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to split */ + xfs_agblock_t *bnop, /* output: block number allocated */ + xfs_alloc_key_t *keyp, /* output: first key of new block */ + xfs_btree_cur_t **curp, /* output: new cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index/record number */ + xfs_agblock_t lbno; /* left (current) block number */ + xfs_buf_t *lbp; /* buffer for left block */ + xfs_alloc_block_t *left; /* left (current) btree block */ + xfs_agblock_t rbno; /* right (new) block number */ + xfs_buf_t *rbp; /* buffer for right block */ + xfs_alloc_block_t *right; /* right (new) btree block */ + + /* + * Allocate the new block from the freelist. + * If we can't do it, we're toast. Give up. + */ + if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, + &rbno))) + return error; + if (rbno == NULLAGBLOCK) { + *stat = 0; + return 0; + } + xfs_trans_agbtree_delta(cur->bc_tp, 1); + rbp = xfs_btree_get_bufs(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agno, + rbno, 0); + /* + * Set up the new block as "right". + */ + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + /* + * "Left" is the current (according to the cursor) block. + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * Fill in the btree header for the new block. + */ + INT_SET(right->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + /* + * Make sure that if there's an odd number of entries now, that + * each new block will have the same number of entries. + */ + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + /* + * For non-leaf blocks, copy keys and addresses over to the new block. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* left btree key pointer */ + xfs_alloc_ptr_t *lpp; /* left btree address pointer */ + xfs_alloc_key_t *rkp; /* right btree key pointer */ + xfs_alloc_ptr_t *rpp; /* right btree address pointer */ + + lkp = XFS_ALLOC_KEY_ADDR(left, i, cur); + lpp = XFS_ALLOC_PTR_ADDR(left, i, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); /* INT_: copy */ + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));/* INT_: copy */ + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + *keyp = *rkp; + } + /* + * For leaf blocks, copy records over to the new block. + */ + else { + xfs_alloc_rec_t *lrp; /* left btree record pointer */ + xfs_alloc_rec_t *rrp; /* right btree record pointer */ + + lrp = XFS_ALLOC_REC_ADDR(left, i, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + keyp->ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + } + /* + * Find the left block number by looking in the buffer. + * Adjust numrecs, sibling pointers. + */ + lbno = XFS_DADDR_TO_AGBNO(cur->bc_mp, XFS_BUF_ADDR(lbp)); + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, rbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_ALL_BITS); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there's a block to the new block's right, make that block + * point back to right instead of to left. + */ + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_alloc_block_t *rrblock; /* rr btree block */ + xfs_buf_t *rrbp; /* buffer for rrblock */ + + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_ALLOC_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, rbno); + xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * If the cursor is really in the right block, move it there. + * If it's just pointing past the last entry in left, then we'll + * insert there, so don't change anything in that case. + */ + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If there are more levels, we'll need another cursor which refers to + * the right block, no matter where this cursor was. + */ + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) + return error; + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = rbno; + *stat = 1; + return 0; +} + +/* + * Update keys at all levels from here to the root along the cursor's path. + */ +STATIC int /* error */ +xfs_alloc_updkey( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_alloc_key_t *keyp, /* new key value to update to */ + int level) /* starting level for update */ +{ + int ptr; /* index of key in block */ + + /* + * Go up the tree from this level toward the root. + * At each level, update the key value to the value input. + * Stop when we reach a level where the cursor isn't pointing + * at the first entry in the block. + */ + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + xfs_alloc_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer for block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + xfs_alloc_key_t *kp; /* ptr to btree block keys */ + + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur); + *kp = *keyp; + xfs_alloc_log_keys(cur, bp, ptr, ptr); + } + return 0; +} + +/* + * Externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_decrement( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the left at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + /* + * Decrement the ptr at this level. If we're still in the block + * then we're done. + */ + if (--cur->bc_ptrs[level] > 0) { + *stat = 1; + return 0; + } + /* + * Get a pointer to the btree block. + */ + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[level]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, + cur->bc_bufs[level]))) + return error; +#endif + /* + * If we just went off the left edge of the tree, return failure. + */ + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree decrementing pointers. + * Stop when we don't go off the left edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + /* + * Read-ahead the left block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[lev]); lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + xfs_buf_t *bp; /* buffer pointer for block */ + + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, agbno, 0, &bp, + XFS_ALLOC_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_alloc_delete( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result code */ + int level; /* btree level */ + + /* + * Go up the tree, starting at leaf level. + * If 2 is returned then a join was done; go to the next level. + * Otherwise we are done. + */ + for (level = 0, i = 2; i == 2; level++) { + if ((error = xfs_alloc_delrec(cur, level, &i))) + return error; + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if ((error = xfs_alloc_decrement(cur, level, &i))) + return error; + break; + } + } + } + *stat = i; + return 0; +} + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_alloc_get_rec( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t *bno, /* output: starting block of extent */ + xfs_extlen_t *len, /* output: length of extent */ + int *stat) /* output: success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + int ptr; /* record number */ + + ptr = cur->bc_ptrs[0]; + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[0]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, cur->bc_bufs[0]))) + return error; +#endif + /* + * Off the right end or left end, return failure. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + /* + * Point to the record and extract its data. + */ + { + xfs_alloc_rec_t *rec; /* record data */ + + rec = XFS_ALLOC_REC_ADDR(block, ptr, cur); + *bno = INT_GET(rec->ar_startblock, ARCH_CONVERT); + *len = INT_GET(rec->ar_blockcount, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_increment( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ + xfs_buf_t *bp; /* tree block buffer */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the right at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + /* + * Get a pointer to the btree block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Increment the ptr at this level. If we're still in the block + * then we're done. + */ + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 1; + return 0; + } + /* + * If we just went off the right edge of the tree, return failure. + */ + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree incrementing pointers. + * Stop when we don't go off the right edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + bp = cur->bc_bufs[lev]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + /* + * Read-ahead the right block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (bp = cur->bc_bufs[lev], block = XFS_BUF_TO_ALLOC_BLOCK(bp); + lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, agbno, 0, &bp, + XFS_ALLOC_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = 1; + } + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_alloc_insert( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result value, 0 for failure */ + int level; /* current level number in btree */ + xfs_agblock_t nbno; /* new block number (split result) */ + xfs_btree_cur_t *ncur; /* new cursor (split result) */ + xfs_alloc_rec_t nrec; /* record being inserted this level */ + xfs_btree_cur_t *pcur; /* previous level's cursor */ + + level = 0; + nbno = NULLAGBLOCK; + INT_SET(nrec.ar_startblock, ARCH_CONVERT, cur->bc_rec.a.ar_startblock); + INT_SET(nrec.ar_blockcount, ARCH_CONVERT, cur->bc_rec.a.ar_blockcount); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + /* + * Loop going up the tree, starting at the leaf level. + * Stop when we don't get a split block, that must mean that + * the insert is finished with this level. + */ + do { + /* + * Insert nrec/nbno into this level of the tree. + * Note if we fail, nbno will be null. + */ + if ((error = xfs_alloc_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + return error; + } + /* + * See if the cursor we just used is trash. + * Can't trash the caller's cursor, but otherwise we should + * if ncur is a new cursor or we're about to be done. + */ + if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + /* + * If we got a new cursor, switch to it. + */ + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLAGBLOCK); + *stat = i; + return 0; +} + +/* + * Lookup the record equal to [bno, len] in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_eq( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +/* + * Lookup the first record greater than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_ge( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_GE, stat); +} + +/* + * Lookup the first record less than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_le( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Update the record referred to by cur, to the value given by [bno, len]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_alloc_update( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len) /* length of extent */ +{ + xfs_alloc_block_t *block; /* btree block to update */ + int error; /* error return value */ + int ptr; /* current record number (updating) */ + + ASSERT(len > 0); + /* + * Pick up the a.g. freelist struct and the current block. + */ + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[0]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, cur->bc_bufs[0]))) + return error; +#endif + /* + * Get the address of the rec to be updated. + */ + ptr = cur->bc_ptrs[0]; + { + xfs_alloc_rec_t *rp; /* pointer to updated record */ + + rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); + /* + * Fill in the new contents and log them. + */ + INT_SET(rp->ar_startblock, ARCH_CONVERT, bno); + INT_SET(rp->ar_blockcount, ARCH_CONVERT, len); + xfs_alloc_log_recs(cur, cur->bc_bufs[0], ptr, ptr); + } + /* + * If it's the by-size btree and it's the last leaf block and + * it's the last record... then update the size of the longest + * extent in the a.g., which we cache in the a.g. freelist header. + */ + if (cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + ptr == INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + xfs_agf_t *agf; /* a.g. freespace header */ + xfs_agnumber_t seqno; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + cur->bc_mp->m_perag[seqno].pagf_longest = len; + INT_SET(agf->agf_longest, ARCH_CONVERT, len); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Updating first record in leaf. Pass new key value up to our parent. + */ + if (ptr == 1) { + xfs_alloc_key_t key; /* key containing [bno, len] */ + + INT_SET(key.ar_startblock, ARCH_CONVERT, bno); + INT_SET(key.ar_blockcount, ARCH_CONVERT, len); + if ((error = xfs_alloc_updkey(cur, &key, 1))) + return error; + } + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_alloc_btree.h linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc_btree.h --- linux-2.4.19/fs/xfs/xfs_alloc_btree.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_alloc_btree.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ALLOC_BTREE_H__ +#define __XFS_ALLOC_BTREE_H__ + +/* + * Freespace on-disk structures + */ + +struct xfs_buf; +struct xfs_btree_cur; +struct xfs_btree_sblock; +struct xfs_mount; + +/* + * There are two on-disk btrees, one sorted by blockno and one sorted + * by blockcount and blockno. All blocks look the same to make the code + * simpler; if we have time later, we'll make the optimizations. + */ +#define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */ +#define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */ + +/* + * Data record/key structure + */ +typedef struct xfs_alloc_rec +{ + xfs_agblock_t ar_startblock; /* starting block number */ + xfs_extlen_t ar_blockcount; /* count of free blocks */ +} xfs_alloc_rec_t, xfs_alloc_key_t; + +typedef xfs_agblock_t xfs_alloc_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_sblock xfs_alloc_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_ALLOC_BLOCK) +xfs_alloc_block_t *xfs_buf_to_alloc_block(struct xfs_buf *bp); +#define XFS_BUF_TO_ALLOC_BLOCK(bp) xfs_buf_to_alloc_block(bp) +#else +#define XFS_BUF_TO_ALLOC_BLOCK(bp) ((xfs_alloc_block_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Real block structures have a size equal to the disk block size. + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_SIZE) +int xfs_alloc_block_size(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_SIZE(lev,cur) xfs_alloc_block_size(lev,cur) +#else +#define XFS_ALLOC_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_MAXRECS) +int xfs_alloc_block_maxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) xfs_alloc_block_maxrecs(lev,cur) +#else +#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) \ + ((cur)->bc_mp->m_alloc_mxr[lev != 0]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_MINRECS) +int xfs_alloc_block_minrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) xfs_alloc_block_minrecs(lev,cur) +#else +#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) \ + ((cur)->bc_mp->m_alloc_mnr[lev != 0]) +#endif + +/* + * Minimum and maximum blocksize. + * The blocksize upper limit is pretty much arbitrary. + */ +#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ +#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ +#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) +#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) + +/* + * block numbers in the AG; SB is BB 0, AGF is BB 1, AGI is BB 2, AGFL is BB 3 + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BNO_BLOCK) +xfs_agblock_t xfs_bno_block(struct xfs_mount *mp); +#define XFS_BNO_BLOCK(mp) xfs_bno_block(mp) +#else +#define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CNT_BLOCK) +xfs_agblock_t xfs_cnt_block(struct xfs_mount *mp); +#define XFS_CNT_BLOCK(mp) xfs_cnt_block(mp) +#else +#define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1)) +#endif + +/* + * Record, key, and pointer address macros for btree blocks. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_REC_ADDR) +xfs_alloc_rec_t *xfs_alloc_rec_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_REC_ADDR(bb,i,cur) xfs_alloc_rec_addr(bb,i,cur) +#else +#define XFS_ALLOC_REC_ADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_ALLOC_BLOCK_SIZE(0,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(0, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_KEY_ADDR) +xfs_alloc_key_t *xfs_alloc_key_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_KEY_ADDR(bb,i,cur) xfs_alloc_key_addr(bb,i,cur) +#else +#define XFS_ALLOC_KEY_ADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(1, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_PTR_ADDR) +xfs_alloc_ptr_t *xfs_alloc_ptr_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_PTR_ADDR(bb,i,cur) xfs_alloc_ptr_addr(bb,i,cur) +#else +#define XFS_ALLOC_PTR_ADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(1, cur)) +#endif + +/* + * Prototypes for externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_decrement( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_alloc_delete( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_alloc_get_rec( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t *bno, /* output: starting block of extent */ + xfs_extlen_t *len, /* output: length of extent */ + int *stat); /* output: success/failure */ + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_increment( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_alloc_insert( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Lookup the record equal to [bno, len] in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_eq( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Lookup the first record greater than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_ge( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Lookup the first record less than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_le( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Update the record referred to by cur, to the value given by [bno, len]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_alloc_update( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len); /* length of extent */ + +#endif /* __XFS_ALLOC_BTREE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_arch.h linux-2.4.19-sgi211r3/fs/xfs/xfs_arch.h --- linux-2.4.19/fs/xfs/xfs_arch.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_arch.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ARCH_H__ +#define __XFS_ARCH_H__ + +#ifndef XFS_BIG_FILESYSTEMS +#error XFS_BIG_FILESYSTEMS must be defined true or false +#endif + +#ifdef __KERNEL__ + +#include + +#ifdef __LITTLE_ENDIAN +# define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#ifdef __BIG_ENDIAN +# define __BYTE_ORDER __BIG_ENDIAN +#endif + +#endif /* __KERNEL__ */ + +/* do we need conversion? */ + +#define ARCH_NOCONVERT 1 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ARCH_CONVERT 0 +#else +#define ARCH_CONVERT ARCH_NOCONVERT +#endif + +/* generic swapping macros */ + +#define INT_SWAP16(type,var) ((typeof(type))(__swab16((__u16)(var)))) +#define INT_SWAP32(type,var) ((typeof(type))(__swab32((__u32)(var)))) +#define INT_SWAP64(type,var) ((typeof(type))(__swab64((__u64)(var)))) + +#define INT_SWAP(type, var) \ + ((sizeof(type) == 8) ? INT_SWAP64(type,var) : \ + ((sizeof(type) == 4) ? INT_SWAP32(type,var) : \ + ((sizeof(type) == 2) ? INT_SWAP16(type,var) : \ + (var)))) + +#define INT_SWAP_UNALIGNED_32(from,to) \ + { \ + ((__u8*)(to))[0] = ((__u8*)(from))[3]; \ + ((__u8*)(to))[1] = ((__u8*)(from))[2]; \ + ((__u8*)(to))[2] = ((__u8*)(from))[1]; \ + ((__u8*)(to))[3] = ((__u8*)(from))[0]; \ + } + +#define INT_SWAP_UNALIGNED_64(from,to) \ + { \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)) + 4, ((__u8*)(to))); \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)), ((__u8*)(to)) + 4); \ + } + +/* + * get and set integers from potentially unaligned locations + */ + +#define INT_GET_UNALIGNED_16_LE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ))) +#define INT_GET_UNALIGNED_16_BE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] << 8) | (((__u8*)(pointer))[1]))) +#define INT_SET_UNALIGNED_16_LE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) ) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) >> 8) & 0xff); \ + } +#define INT_SET_UNALIGNED_16_BE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) >> 8) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) ) & 0xff); \ + } + +#define INT_GET_UNALIGNED_32_LE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ) \ + |(((__u8*)(pointer))[2] << 16) | (((__u8*)(pointer))[3] << 24))) +#define INT_GET_UNALIGNED_32_BE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] << 24) | (((__u8*)(pointer))[1] << 16) \ + |(((__u8*)(pointer))[2] << 8) | (((__u8*)(pointer))[3] ))) + +#define INT_GET_UNALIGNED_64_LE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer))+4)) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer)) )) )) +#define INT_GET_UNALIGNED_64_BE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer)) )) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer))+4)) )) + +/* + * now pick the right ones for our MACHINE ARCHITECTURE + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_LE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_LE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_LE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_LE(pointer) +#else +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_BE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_BE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_BE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_BE(pointer) +#endif + +/* define generic INT_ macros */ + +#define INT_GET(reference,arch) \ + (((arch) == ARCH_NOCONVERT) \ + ? \ + (reference) \ + : \ + INT_SWAP((reference),(reference)) \ + ) + +/* does not return a value */ +#define INT_SET(reference,arch,valueref) \ + (__builtin_constant_p(valueref) ? \ + (void)( (reference) = ( ((arch) != ARCH_NOCONVERT) ? (INT_SWAP((reference),(valueref))) : (valueref)) ) : \ + (void)( \ + ((reference) = (valueref)), \ + ( ((arch) != ARCH_NOCONVERT) ? (reference) = INT_SWAP((reference),(reference)) : 0 ) \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD_EXPR(reference,arch,code) \ + (void)(((arch) == ARCH_NOCONVERT) \ + ? \ + ((reference) code) \ + : \ + ( \ + (reference) = INT_GET((reference),arch) , \ + ((reference) code), \ + INT_SET(reference, arch, reference) \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD(reference,arch,delta) \ + (void)( \ + INT_MOD_EXPR(reference,arch,+=(delta)) \ + ) + +/* + * INT_COPY - copy a value between two locations with the + * _same architecture_ but _potentially different sizes_ + * + * if the types of the two parameters are equal or they are + * in native architecture, a simple copy is done + * + * otherwise, architecture conversions are done + * + */ + +/* does not return a value */ +#define INT_COPY(dst,src,arch) \ + (void)( \ + ((sizeof(dst) == sizeof(src)) || ((arch) == ARCH_NOCONVERT)) \ + ? \ + ((dst) = (src)) \ + : \ + INT_SET(dst, arch, INT_GET(src, arch)) \ + ) + +/* + * INT_XLATE - copy a value in either direction between two locations + * with different architectures + * + * dir < 0 - copy from memory to buffer (native to arch) + * dir > 0 - copy from buffer to memory (arch to native) + */ + +/* does not return a value */ +#define INT_XLATE(buf,mem,dir,arch) {\ + ASSERT(dir); \ + if (dir>0) { \ + (mem)=INT_GET(buf, arch); \ + } else { \ + INT_SET(buf, arch, mem); \ + } \ +} + +#define INT_ISZERO(reference,arch) \ + ((reference) == 0) + +#define INT_ZERO(reference,arch) \ + ((reference) = 0) + +#define INT_GET_UNALIGNED_16_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_16(pointer)) \ + : \ + (INT_GET_UNALIGNED_16_BE(pointer)) \ + ) +#define INT_SET_UNALIGNED_16_ARCH(pointer,value,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + INT_SET_UNALIGNED_16(pointer,value); \ + } else { \ + INT_SET_UNALIGNED_16_BE(pointer,value); \ + } + +#define DIRINO4_GET_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_32(pointer)) \ + : \ + (INT_GET_UNALIGNED_32_BE(pointer)) \ + ) + +#if XFS_BIG_FILESYSTEMS +#define DIRINO_GET_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_64(pointer)) \ + : \ + (INT_GET_UNALIGNED_64_BE(pointer)) \ + ) +#else +/* MACHINE ARCHITECTURE dependent */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define DIRINO_GET_ARCH(pointer,arch) \ + DIRINO4_GET_ARCH((((__u8*)pointer)+4),arch) +#else +#define DIRINO_GET_ARCH(pointer,arch) \ + DIRINO4_GET_ARCH(pointer,arch) +#endif +#endif + +#define DIRINO_COPY_ARCH(from,to,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + bcopy(from,to,sizeof(xfs_ino_t)); \ + } else { \ + INT_SWAP_UNALIGNED_64(from,to); \ + } +#define DIRINO4_COPY_ARCH(from,to,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + bcopy((((__u8*)from+4)),to,sizeof(xfs_dir2_ino4_t)); \ + } else { \ + INT_SWAP_UNALIGNED_32(from,to); \ + } + +#endif /* __XFS_ARCH_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_attr.c linux-2.4.19-sgi211r3/fs/xfs/xfs_attr.c --- linux-2.4.19/fs/xfs/xfs_attr.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_attr.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,2294 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * xfs_attr.c + * + * Provide the external interfaces to manage attribute lists. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when attribute list fits inside the inode. + */ +STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); + +/* + * Internal routines when attribute list is one block. + */ +STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); +STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); +STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); + +/* + * Internal routines when attribute list is more than one block. + */ +STATIC int xfs_attr_node_addname(xfs_da_args_t *args); +STATIC int xfs_attr_node_removename(xfs_da_args_t *args); +STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); +STATIC int xfs_attr_fillstate(xfs_da_state_t *state); +STATIC int xfs_attr_refillstate(xfs_da_state_t *state); + +/* + * Routines to manipulate out-of-line attribute values. + */ +STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args); +STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); +STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); + +#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ +#define ATTR_RMTVALUE_TRANSBLKS 8 /* max # of blks in a transaction */ + +#if defined(DEBUG) +ktrace_t *xfs_attr_trace_buf; +#endif + + + +/*======================================================================== + * Overall external interface routines. + *========================================================================*/ + +/*ARGSUSED*/ +int /* error */ +xfs_attr_get(bhv_desc_t *bdp, char *name, char *value, int *valuelenp, + int flags, struct cred *cred) +{ + xfs_da_args_t args; + int error; + int namelen; + xfs_inode_t *ip = XFS_BHVTOI(bdp); + + if (!name) + return EINVAL; + ASSERT(MAXNAMELEN-1 <= 0xff); /* length is stored in uint8 */ + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return EFAULT; /* match IRIX behaviour */ + XFS_STATS_INC(xfsstats.xs_attr_get); + + if (XFS_IFORK_Q(ip) == 0) + return ENOATTR; + + + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return (EIO); + + /* + * Do we answer them, or ignore them? + */ + xfs_ilock(ip, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(XFS_BHVTOI(bdp), IREAD, cred))) { + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } + + /* + * Fill in the arg structure for this request. + */ + bzero((char *)&args, sizeof(args)); + args.name = name; + args.namelen = namelen; + args.value = value; + args.valuelen = *valuelenp; + args.flags = flags; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.dp = ip; + args.whichfork = XFS_ATTR_FORK; + args.trans = NULL; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (XFS_IFORK_Q(ip) == 0 || + (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_anextents == 0)) { + error = XFS_ERROR(ENOATTR); + } else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + error = xfs_attr_shortform_getvalue(&args); + } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_get(&args); + } else { + error = xfs_attr_node_get(&args); + } + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + /* + * Return the number of bytes in the value to the caller. + */ + *valuelenp = args.valuelen; + + if (error == EEXIST) + error = 0; + return(error); +} + +/*ARGSUSED*/ +int /* error */ +xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags, + struct cred *cred) +{ + xfs_da_args_t args; + xfs_inode_t *dp; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + int error, err2, committed; + int local, size; + uint nblks; + xfs_mount_t *mp; + int rsvd = (flags & ATTR_ROOT) != 0; + int namelen; + + ASSERT(MAXNAMELEN-1 <= 0xff); /* length is stored in uint8 */ + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return EFAULT; /* match irix behaviour */ + + XFS_STATS_INC(xfsstats.xs_attr_set); + /* + * Do we answer them, or ignore them? + */ + dp = XFS_BHVTOI(bdp); + mp = dp->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return (EIO); + + xfs_ilock(dp, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(dp, IWRITE, cred))) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } + xfs_iunlock(dp, XFS_ILOCK_SHARED); + + /* + * Attach the dquots to the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if ((error = xfs_qm_dqattach(dp, 0))) + return (error); + } + + /* + * If the inode doesn't have an attribute fork, add one. + * (inode must not be locked when we call this routine) + */ + if (XFS_IFORK_Q(dp) == 0) { + error = xfs_bmap_add_attrfork(dp, rsvd); + if (error) + return(error); + } + + /* + * Fill in the arg structure for this request. + */ + bzero((char *)&args, sizeof(args)); + args.name = name; + args.namelen = namelen; + args.value = value; + args.valuelen = valuelen; + args.flags = flags; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.dp = dp; + args.firstblock = &firstblock; + args.flist = &flist; + args.whichfork = XFS_ATTR_FORK; + args.oknoent = 1; + + /* Determine space new attribute will use, and if it will be inline + * or out of line. + */ + size = xfs_attr_leaf_newentsize(&args, mp->m_sb.sb_blocksize, &local); + + nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); + if (local) { + if (size > (mp->m_sb.sb_blocksize >> 1)) { + /* Double split possible */ + nblks <<= 1; + } + } else { + uint dblocks = XFS_B_TO_FSB(mp, valuelen); + /* Out of line attribute, cannot double split, but make + * room for the attribute value itself. + */ + nblks += dblocks; + nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); + } + + /* Size is now blocks for attribute data */ + args.total = nblks; + + /* + * Start our first transaction of the day. + * + * All future transactions during this code must be "chained" off + * this one via the trans_dup() call. All transactions will contain + * the inode, and the inode will always be marked with trans_ihold(). + * Since the inode will be locked in all transactions, we must log + * the inode in every transaction to let it float upward through + * the log. + */ + args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET); + + /* + * Root fork attributes can use reserved data blocks for this + * operation if necessary + */ + + if (rsvd) + args.trans->t_flags |= XFS_TRANS_RESERVE; + + if ((error = xfs_trans_reserve(args.trans, (uint) nblks, + XFS_ATTRSET_LOG_RES(mp, nblks), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ATTRSET_LOG_COUNT))) { + xfs_trans_cancel(args.trans, 0); + return(error); + } + xfs_ilock(dp, XFS_ILOCK_EXCL); + + if (XFS_IS_QUOTA_ON(mp)) { + if (rsvd) { + error = xfs_trans_reserve_blkquota_force(args.trans, + dp, nblks); + } else { + error = xfs_trans_reserve_blkquota(args.trans, + dp, nblks); + } + if (error) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); + return (error); + } + } + + xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args.trans, dp); + + /* + * If the attribute list is non-existant or a shortform list, + * upgrade it to a single-leaf-block attribute list. + */ + if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || + ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) && + (dp->i_d.di_anextents == 0))) { + + /* + * Build initial attribute list (if required). + */ + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) + (void)xfs_attr_shortform_create(&args); + + /* + * Try to add the attr to the attribute list in + * the inode. + */ + error = xfs_attr_shortform_addname(&args); + if (error != ENOSPC) { + /* + * Commit the shortform mods, and we're done. + * NOTE: this is also the error path (EEXIST, etc). + */ + ASSERT(args.trans != NULL); + + /* + * If this is a synchronous mount, make sure that + * the transaction goes to disk before returning + * to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(args.trans); + } + err2 = xfs_trans_commit(args.trans, + XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Hit the inode change time. + */ + if (!error && (flags & ATTR_KERNOTIME) == 0) { + xfs_ichgtime(dp, XFS_ICHGTIME_CHG); + } + return(error == 0 ? err2 : error); + } + + /* + * It won't fit in the shortform, transform to a leaf block. + * GROT: another possible req'mt for a double-split btree op. + */ + XFS_BMAP_INIT(args.flist, args.firstblock); + error = xfs_attr_shortform_to_leaf(&args); + if (!error) { + error = xfs_bmap_finish(&args.trans, args.flist, + *args.firstblock, &committed); + } + if (error) { + ASSERT(committed); + args.trans = NULL; + xfs_bmap_cancel(&flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args.trans, dp); + } + + /* + * Commit the leaf transformation. We'll need another (linked) + * transaction to add the new attribute to the leaf. + */ + if ((error = xfs_attr_rolltrans(&args.trans, dp))) + goto out; + + } + + if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_addname(&args); + } else { + error = xfs_attr_node_addname(&args); + } + if (error) { + goto out; + } + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(args.trans); + } + + /* + * Commit the last in the sequence of transactions. + */ + xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); + error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Hit the inode change time. + */ + if (!error && (flags & ATTR_KERNOTIME) == 0) { + xfs_ichgtime(dp, XFS_ICHGTIME_CHG); + } + + return(error); + +out: + if (args.trans) + xfs_trans_cancel(args.trans, + XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(error); +} + +/* + * Generic handler routine to remove a name from an attribute list. + * Transitions attribute list from Btree to shortform as necessary. + */ +/*ARGSUSED*/ +int /* error */ +xfs_attr_remove(bhv_desc_t *bdp, char *name, int flags, struct cred *cred) +{ + xfs_da_args_t args; + xfs_inode_t *dp; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + int error; + xfs_mount_t *mp; + int namelen; + + ASSERT(MAXNAMELEN-1<=0xff); /* length is stored in uint8 */ + namelen = strlen(name); + if (namelen>=MAXNAMELEN) + return EFAULT; /* match irix behaviour */ + + XFS_STATS_INC(xfsstats.xs_attr_remove); + + /* + * Do we answer them, or ignore them? + */ + dp = XFS_BHVTOI(bdp); + mp = dp->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return (EIO); + + xfs_ilock(dp, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(dp, IWRITE, cred))) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } else if (XFS_IFORK_Q(dp) == 0 || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(ENOATTR)); + } + xfs_iunlock(dp, XFS_ILOCK_SHARED); + + /* + * Fill in the arg structure for this request. + */ + bzero((char *)&args, sizeof(args)); + args.name = name; + args.namelen = namelen; + args.flags = flags; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.dp = dp; + args.firstblock = &firstblock; + args.flist = &flist; + args.total = 0; + args.whichfork = XFS_ATTR_FORK; + + /* + * Attach the dquots to the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, dp)) { + if ((error = xfs_qm_dqattach(dp, 0))) + return (error); + } + } + /* + * Start our first transaction of the day. + * + * All future transactions during this code must be "chained" off + * this one via the trans_dup() call. All transactions will contain + * the inode, and the inode will always be marked with trans_ihold(). + * Since the inode will be locked in all transactions, we must log + * the inode in every transaction to let it float upward through + * the log. + */ + args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM); + + /* + * Root fork attributes can use reserved data blocks for this + * operation if necessary + */ + + if (flags & ATTR_ROOT) + args.trans->t_flags |= XFS_TRANS_RESERVE; + + if ((error = xfs_trans_reserve(args.trans, + XFS_ATTRRM_SPACE_RES(mp), + XFS_ATTRRM_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ATTRRM_LOG_COUNT))) { + xfs_trans_cancel(args.trans, 0); + return(error); + + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + /* + * No need to make quota reservations here. We expect to release some + * blocks not allocate in the common case. + */ + xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args.trans, dp); + + /* + * Decide on what work routines to call based on the inode size. + */ + if (XFS_IFORK_Q(dp) == 0 || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + error = XFS_ERROR(ENOATTR); + goto out; + } + if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); + error = xfs_attr_shortform_remove(&args); + if (error) { + goto out; + } + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_removename(&args); + } else { + error = xfs_attr_node_removename(&args); + } + if (error) { + goto out; + } + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(args.trans); + } + + /* + * Commit the last in the sequence of transactions. + */ + xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); + error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Hit the inode change time. + */ + if (!error && (flags & ATTR_KERNOTIME) == 0) { + xfs_ichgtime(dp, XFS_ICHGTIME_CHG); + } + + return(error); + +out: + if (args.trans) + xfs_trans_cancel(args.trans, + XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(error); +} + +/* + * Generate a list of extended attribute names and optionally + * also value lengths. Positive return value follows the XFS + * convention of being an error, zero or negative return code + * is the length of the buffer returned (negated), indicating + * success. + */ +int +xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, + attrlist_cursor_kern_t *cursor, struct cred *cred) +{ + xfs_attr_list_context_t context; + xfs_inode_t *dp; + int error; + + XFS_STATS_INC(xfsstats.xs_attr_list); + + /* + * Validate the cursor. + */ + if (cursor->pad1 || cursor->pad2) + return(XFS_ERROR(EINVAL)); + if ((cursor->initted == 0) && + (cursor->hashval || cursor->blkno || cursor->offset)) + return(XFS_ERROR(EINVAL)); + + /* + * Check for a properly aligned buffer. + */ + if (((long)buffer) & (sizeof(int)-1)) + return(XFS_ERROR(EFAULT)); + if (flags & ATTR_KERNOVAL) + bufsize = 0; + + /* + * Initialize the output buffer. + */ + context.dp = dp = XFS_BHVTOI(bdp); + context.cursor = cursor; + context.count = 0; + context.dupcnt = 0; + context.resynch = 1; + context.flags = flags; + if (!(flags & ATTR_KERNAMELS)) { + context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ + context.firstu = context.bufsize; + context.alist = (attrlist_t *)buffer; + context.alist->al_count = 0; + context.alist->al_more = 0; + context.alist->al_offset[0] = context.bufsize; + } + else { + context.bufsize = bufsize; + context.firstu = context.bufsize; + context.alist = (attrlist_t *)buffer; + } + + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) + return (EIO); + /* + * Do they have permission? + */ + xfs_ilock(dp, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(dp, IREAD, cred))) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } + + /* + * Decide on what work routines to call based on the inode size. + */ + xfs_attr_trace_l_c("syscall start", &context); + if (XFS_IFORK_Q(dp) == 0 || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + error = 0; + } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + error = xfs_attr_shortform_list(&context); + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_list(&context); + } else { + error = xfs_attr_node_list(&context); + } + xfs_iunlock(dp, XFS_ILOCK_SHARED); + xfs_attr_trace_l_c("syscall end", &context); + + if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) { + ASSERT(error >= 0); + } + else { /* must return negated buffer size or the error */ + if (context.count < 0) + error = XFS_ERROR(ERANGE); + else + error = -context.count; + } + + return(error); +} + +int /* error */ +xfs_attr_inactive(xfs_inode_t *dp) +{ + xfs_trans_t *trans; + xfs_mount_t *mp; + int error; + + mp = dp->i_mount; + ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); + + /* XXXsup - why on earth are we taking ILOCK_EXCL here??? */ + xfs_ilock(dp, XFS_ILOCK_EXCL); + if ((XFS_IFORK_Q(dp) == 0) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(0); + } + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Start our first transaction of the day. + * + * All future transactions during this code must be "chained" off + * this one via the trans_dup() call. All transactions will contain + * the inode, and the inode will always be marked with trans_ihold(). + * Since the inode will be locked in all transactions, we must log + * the inode in every transaction to let it float upward through + * the log. + */ + trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); + if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ATTRINVAL_LOG_COUNT))) { + xfs_trans_cancel(trans, 0); + return(error); + } + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * No need to make quota reservations here. We expect to release some + * blocks, not allocate, in the common case. + */ + xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(trans, dp); + + /* + * Decide on what work routines to call based on the inode size. + */ + if ((XFS_IFORK_Q(dp) == 0) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + error = 0; + goto out; + } + error = xfs_attr_root_inactive(&trans, dp); + if (error) + goto out; + /* + * signal synchronous inactive transactions unless this + * is a synchronous mount filesystem in which case we + * know that we're here because we've been called out of + * xfs_inactive which means that the last reference is gone + * and the unlink transaction has already hit the disk so + * async inactive transactions are safe. + */ + if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, + (!(mp->m_flags & XFS_MOUNT_WSYNC) + ? 1 : 0)))) + goto out; + + /* + * Commit the last in the sequence of transactions. + */ + xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); + error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + return(error); + +out: + xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(error); +} + + + +/*======================================================================== + * External routines when attribute list is inside the inode + *========================================================================*/ + +/* + * Add a name to the shortform attribute list structure + * This is the external routine. + */ +STATIC int +xfs_attr_shortform_addname(xfs_da_args_t *args) +{ + int newsize, retval; + + retval = xfs_attr_shortform_lookup(args); + if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { + return(retval); + } else if (retval == EEXIST) { + if (args->flags & ATTR_CREATE) + return(retval); + retval = xfs_attr_shortform_remove(args); + ASSERT(retval == 0); + } + + newsize = XFS_ATTR_SF_TOTSIZE(args->dp); + newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); + if ((newsize <= XFS_IFORK_ASIZE(args->dp)) && + (args->namelen < XFS_ATTR_SF_ENTSIZE_MAX) && + (args->valuelen < XFS_ATTR_SF_ENTSIZE_MAX)) { + retval = xfs_attr_shortform_add(args); + ASSERT(retval == 0); + } else { + return(XFS_ERROR(ENOSPC)); + } + return(0); +} + + +/*======================================================================== + * External routines when attribute list is one block + *========================================================================*/ + +/* + * Add a name to the leaf attribute list structure + * + * This leaf block cannot have a "remote" value, we only call this routine + * if bmap_one_block() says there is only one block (ie: no remote blks). + */ +int +xfs_attr_leaf_addname(xfs_da_args_t *args) +{ + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int retval, error, committed; + + /* + * Read the (only) block in the attribute list in. + */ + dp = args->dp; + args->blkno = 0; + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + /* + * Look up the given attribute in the leaf block. Figure out if + * the given flags produce an error or call for an atomic rename. + */ + retval = xfs_attr_leaf_lookup_int(bp, args); + if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { + xfs_da_brelse(args->trans, bp); + return(retval); + } else if (retval == EEXIST) { + if (args->flags & ATTR_CREATE) { /* pure create op */ + xfs_da_brelse(args->trans, bp); + return(retval); + } + args->rename = 1; /* an atomic rename */ + args->blkno2 = args->blkno; /* set 2nd entry info*/ + args->index2 = args->index; + args->rmtblkno2 = args->rmtblkno; + args->rmtblkcnt2 = args->rmtblkcnt; + } + + /* + * Add the attribute to the leaf block, transitioning to a Btree + * if required. + */ + retval = xfs_attr_leaf_add(bp, args); + xfs_da_buf_done(bp); + if (retval == ENOSPC) { + /* + * Promote the attribute list to the Btree format, then + * Commit that transaction so that the node_addname() call + * can manage its own transactions. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_node(args); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + /* + * Commit the current trans (including the inode) and start + * a new one. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + return (error); + + /* + * Fob the whole rest of the problem off on the Btree code. + */ + error = xfs_attr_node_addname(args); + return(error); + } + + /* + * Commit the transaction that added the attr name so that + * later routines can manage their own transactions. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + return (error); + + /* + * If there was an out-of-line value, allocate the blocks we + * identified for its storage and copy the value. This is done + * after we create the attribute so that we don't overflow the + * maximum size of a transaction and/or hit a deadlock. + */ + if (args->rmtblkno > 0) { + error = xfs_attr_rmtval_set(args); + if (error) + return(error); + } + + /* + * If this is an atomic rename operation, we must "flip" the + * incomplete flags on the "new" and "old" attribute/value pairs + * so that one disappears and one appears atomically. Then we + * must remove the "old" attribute/value pair. + */ + if (args->rename) { + /* + * In a separate transaction, set the incomplete flag on the + * "old" attr and clear the incomplete flag on the "new" attr. + */ + error = xfs_attr_leaf_flipflags(args); + if (error) + return(error); + + /* + * Dismantle the "old" attribute/value pair by removing + * a "remote" value (if it exists). + */ + args->index = args->index2; + args->blkno = args->blkno2; + args->rmtblkno = args->rmtblkno2; + args->rmtblkcnt = args->rmtblkcnt2; + if (args->rmtblkno) { + error = xfs_attr_rmtval_remove(args); + if (error) + return(error); + } + + /* + * Read in the block containing the "old" attr, then + * remove the "old" attr from that block (neat, huh!) + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, + &bp, XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + (void)xfs_attr_leaf_remove(bp, args); + + /* + * If the result is small enough, shrink it all into the inode. + */ + if (xfs_attr_shortform_allfit(bp, dp)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_shortform(bp, args); + /* bp is gone due to xfs_da_shrink_inode */ + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else + xfs_da_buf_done(bp); + + /* + * Commit the remove and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, dp); + + } else if (args->rmtblkno > 0) { + /* + * Added a "remote" value, just clear the incomplete flag. + */ + error = xfs_attr_leaf_clearflag(args); + } + return(error); +} + +/* + * Remove a name from the leaf attribute list structure + * + * This leaf block cannot have a "remote" value, we only call this routine + * if bmap_one_block() says there is only one block (ie: no remote blks). + */ +STATIC int +xfs_attr_leaf_removename(xfs_da_args_t *args) +{ + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int committed; + int error; + + /* + * Remove the attribute. + */ + dp = args->dp; + args->blkno = 0; + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) { + return(error); + } + + ASSERT(bp != NULL); + error = xfs_attr_leaf_lookup_int(bp, args); + if (error == ENOATTR) { + xfs_da_brelse(args->trans, bp); + return(error); + } + + (void)xfs_attr_leaf_remove(bp, args); + + /* + * If the result is small enough, shrink it all into the inode. + */ + if (xfs_attr_shortform_allfit(bp, dp)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_shortform(bp, args); + /* bp is gone due to xfs_da_shrink_inode */ + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else + xfs_da_buf_done(bp); + return(0); +} + +/* + * Look up a name in a leaf attribute list structure. + * + * This leaf block cannot have a "remote" value, we only call this routine + * if bmap_one_block() says there is only one block (ie: no remote blks). + */ +int +xfs_attr_leaf_get(xfs_da_args_t *args) +{ + xfs_dabuf_t *bp; + int error; + + args->blkno = 0; + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + error = xfs_attr_leaf_lookup_int(bp, args); + if (error != EEXIST) { + xfs_da_brelse(args->trans, bp); + return(error); + } + error = xfs_attr_leaf_getvalue(bp, args); + xfs_da_brelse(args->trans, bp); + if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { + error = xfs_attr_rmtval_get(args); + } + return(error); +} + +/* + * Copy out attribute entries for attr_list(), for leaf attribute lists. + */ +STATIC int +xfs_attr_leaf_list(xfs_attr_list_context_t *context) +{ + xfs_attr_leafblock_t *leaf; + int error; + xfs_dabuf_t *bp; + + context->cursor->blkno = 0; + error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) { + xfs_da_brelse(NULL, bp); + return(XFS_ERROR(EFSCORRUPTED)); + } + + (void)xfs_attr_leaf_list_int(bp, context); + xfs_da_brelse(NULL, bp); + return(0); +} + + +/*======================================================================== + * External routines when attribute list size > XFS_LBSIZE(mp). + *========================================================================*/ + +/* + * Add a name to a Btree-format attribute list. + * + * This will involve walking down the Btree, and may involve splitting + * leaf nodes and even splitting intermediate nodes up to and including + * the root node (a special case of an intermediate node). + * + * "Remote" attribute values confuse the issue and atomic rename operations + * add a whole extra layer of confusion on top of that. + */ +STATIC int +xfs_attr_node_addname(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + xfs_inode_t *dp; + xfs_mount_t *mp; + int committed, retval, error; + + /* + * Fill in bucket of arguments/results/context to carry around. + */ + dp = args->dp; + mp = dp->i_mount; +restart: + state = xfs_da_state_alloc(); + state->args = args; + state->mp = mp; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name already exists, and get back a pointer + * to where it should go. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + goto out; + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { + goto out; + } else if (retval == EEXIST) { + if (args->flags & ATTR_CREATE) + goto out; + args->rename = 1; /* atomic rename op */ + args->blkno2 = args->blkno; /* set 2nd entry info*/ + args->index2 = args->index; + args->rmtblkno2 = args->rmtblkno; + args->rmtblkcnt2 = args->rmtblkcnt; + args->rmtblkno = 0; + args->rmtblkcnt = 0; + } + + retval = xfs_attr_leaf_add(blk->bp, state->args); + if (retval == ENOSPC) { + if (state->path.active == 1) { + /* + * Its really a single leaf node, but it had + * out-of-line values so it looked like it *might* + * have been a b-tree. + */ + xfs_da_state_free(state); + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_node(args); + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + /* + * Commit the node conversion and start the next + * trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + + goto restart; + } + + /* + * Split as many Btree elements as required. + * This code tracks the new and old attr's location + * in the index/blkno/rmtblkno/rmtblkcnt fields and + * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_da_split(state); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else { + /* + * Addition succeeded, update Btree hashvals. + */ + xfs_da_fixhashpath(state, &state->path); + } + + /* + * Kill the state structure, we're done with it and need to + * allow the buffers to come back later. + */ + xfs_da_state_free(state); + state = NULL; + + /* + * Commit the leaf addition or btree split and start the next + * trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + + /* + * If there was an out-of-line value, allocate the blocks we + * identified for its storage and copy the value. This is done + * after we create the attribute so that we don't overflow the + * maximum size of a transaction and/or hit a deadlock. + */ + if (args->rmtblkno > 0) { + error = xfs_attr_rmtval_set(args); + if (error) + return(error); + } + + /* + * If this is an atomic rename operation, we must "flip" the + * incomplete flags on the "new" and "old" attribute/value pairs + * so that one disappears and one appears atomically. Then we + * must remove the "old" attribute/value pair. + */ + if (args->rename) { + /* + * In a separate transaction, set the incomplete flag on the + * "old" attr and clear the incomplete flag on the "new" attr. + */ + error = xfs_attr_leaf_flipflags(args); + if (error) + goto out; + + /* + * Dismantle the "old" attribute/value pair by removing + * a "remote" value (if it exists). + */ + args->index = args->index2; + args->blkno = args->blkno2; + args->rmtblkno = args->rmtblkno2; + args->rmtblkcnt = args->rmtblkcnt2; + if (args->rmtblkno) { + error = xfs_attr_rmtval_remove(args); + if (error) + return(error); + } + + /* + * Re-find the "old" attribute entry after any split ops. + * The INCOMPLETE flag means that we will find the "old" + * attr, not the "new" one. + */ + args->flags |= XFS_ATTR_INCOMPLETE; + state = xfs_da_state_alloc(); + state->args = args; + state->mp = mp; + state->blocksize = state->mp->m_sb.sb_blocksize; + state->inleaf = 0; + error = xfs_da_node_lookup_int(state, &retval); + if (error) + goto out; + + /* + * Remove the name and update the hashvals in the tree. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + error = xfs_attr_leaf_remove(blk->bp, args); + xfs_da_fixhashpath(state, &state->path); + + /* + * Check to see if the tree needs to be collapsed. + */ + if (retval && (state->path.active > 1)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_da_join(state); + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } + + /* + * Commit and start the next trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + + } else if (args->rmtblkno > 0) { + /* + * Added a "remote" value, just clear the incomplete flag. + */ + error = xfs_attr_leaf_clearflag(args); + if (error) + goto out; + } + retval = error = 0; + +out: + if (state) + xfs_da_state_free(state); + if (error) + return(error); + return(retval); +} + +/* + * Remove a name from a B-tree attribute list. + * + * This will involve walking down the Btree, and may involve joining + * leaf nodes and even joining intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_attr_node_removename(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int retval, error, committed; + + /* + * Tie a string around our finger to remind us where we are. + */ + dp = args->dp; + state = xfs_da_state_alloc(); + state->args = args; + state->mp = dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error || (retval != EEXIST)) { + if (error == 0) + error = retval; + goto out; + } + + /* + * If there is an out-of-line value, de-allocate the blocks. + * This is done before we remove the attribute so that we don't + * overflow the maximum size of a transaction and/or hit a deadlock. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->bp != NULL); + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + if (args->rmtblkno > 0) { + /* + * Fill in disk block numbers in the state structure + * so that we can get the buffers back after we commit + * several transactions in the following calls. + */ + error = xfs_attr_fillstate(state); + if (error) + goto out; + + /* + * Mark the attribute as INCOMPLETE, then bunmapi() the + * remote value. + */ + error = xfs_attr_leaf_setflag(args); + if (error) + goto out; + error = xfs_attr_rmtval_remove(args); + if (error) + goto out; + + /* + * Refill the state structure with buffers, the prior calls + * released our buffers. + */ + error = xfs_attr_refillstate(state); + if (error) + goto out; + } + + /* + * Remove the name and update the hashvals in the tree. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + retval = xfs_attr_leaf_remove(blk->bp, args); + xfs_da_fixhashpath(state, &state->path); + + /* + * Check to see if the tree needs to be collapsed. + */ + if (retval && (state->path.active > 1)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_da_join(state); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + /* + * Commit the Btree join operation and start a new trans. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + } + + /* + * If the result is small enough, push it all into the inode. + */ + if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + /* + * Have to get rid of the copy of this dabuf in the state. + */ + ASSERT(state->path.active == 1); + ASSERT(state->path.blk[0].bp); + xfs_da_buf_done(state->path.blk[0].bp); + state->path.blk[0].bp = NULL; + + error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_ATTR_FORK); + if (error) + goto out; + ASSERT(INT_GET(((xfs_attr_leafblock_t *) + bp->data)->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + + if (xfs_attr_shortform_allfit(bp, dp)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_shortform(bp, args); + /* bp is gone due to xfs_da_shrink_inode */ + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else + xfs_da_brelse(args->trans, bp); + } + error = 0; + +out: + xfs_da_state_free(state); + return(error); +} + +/* + * Fill in the disk block numbers in the state structure for the buffers + * that are attached to the state structure. + * This is done so that we can quickly reattach ourselves to those buffers + * after some set of transaction commit's has released these buffers. + */ +STATIC int +xfs_attr_fillstate(xfs_da_state_t *state) +{ + xfs_da_state_path_t *path; + xfs_da_state_blk_t *blk; + int level; + + /* + * Roll down the "path" in the state structure, storing the on-disk + * block number for those buffers in the "path". + */ + path = &state->path; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->bp) { + blk->disk_blkno = xfs_da_blkno(blk->bp); + xfs_da_buf_done(blk->bp); + blk->bp = NULL; + } else { + blk->disk_blkno = 0; + } + } + + /* + * Roll down the "altpath" in the state structure, storing the on-disk + * block number for those buffers in the "altpath". + */ + path = &state->altpath; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->bp) { + blk->disk_blkno = xfs_da_blkno(blk->bp); + xfs_da_buf_done(blk->bp); + blk->bp = NULL; + } else { + blk->disk_blkno = 0; + } + } + + return(0); +} + +/* + * Reattach the buffers to the state structure based on the disk block + * numbers stored in the state structure. + * This is done after some set of transaction commit's has released those + * buffers from our grip. + */ +STATIC int +xfs_attr_refillstate(xfs_da_state_t *state) +{ + xfs_da_state_path_t *path; + xfs_da_state_blk_t *blk; + int level, error; + + /* + * Roll down the "path" in the state structure, storing the on-disk + * block number for those buffers in the "path". + */ + path = &state->path; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->disk_blkno) { + error = xfs_da_read_buf(state->args->trans, + state->args->dp, + blk->blkno, blk->disk_blkno, + &blk->bp, XFS_ATTR_FORK); + if (error) + return(error); + } else { + blk->bp = NULL; + } + } + + /* + * Roll down the "altpath" in the state structure, storing the on-disk + * block number for those buffers in the "altpath". + */ + path = &state->altpath; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->disk_blkno) { + error = xfs_da_read_buf(state->args->trans, + state->args->dp, + blk->blkno, blk->disk_blkno, + &blk->bp, XFS_ATTR_FORK); + if (error) + return(error); + } else { + blk->bp = NULL; + } + } + + return(0); +} + +/* + * Look up a filename in a node attribute list. + * + * This routine gets called for any attribute fork that has more than one + * block, ie: both true Btree attr lists and for single-leaf-blocks with + * "remote" values taking up more blocks. + */ +int +xfs_attr_node_get(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int error, retval; + int i; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } else if (retval == EEXIST) { + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->bp != NULL); + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + + /* + * Get the value, local or "remote" + */ + retval = xfs_attr_leaf_getvalue(blk->bp, args); + if (!retval && (args->rmtblkno > 0) + && !(args->flags & ATTR_KERNOVAL)) { + retval = xfs_attr_rmtval_get(args); + } + } + + /* + * If not in a transaction, we have to release all the buffers. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} + +STATIC int /* error */ +xfs_attr_node_list(xfs_attr_list_context_t *context) +{ + attrlist_cursor_kern_t *cursor; + xfs_attr_leafblock_t *leaf; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int error, i; + xfs_dabuf_t *bp; + + cursor = context->cursor; + cursor->initted = 1; + + /* + * Do all sorts of validation on the passed-in cursor structure. + * If anything is amiss, ignore the cursor and look up the hashval + * starting from the btree root. + */ + bp = NULL; + if (cursor->blkno > 0) { + error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, + &bp, XFS_ATTR_FORK); + if ((error != 0) && (error != EFSCORRUPTED)) + return(error); + if (bp) { + node = bp->data; + switch (INT_GET(node->hdr.info.magic, ARCH_CONVERT)) { + case XFS_DA_NODE_MAGIC: + xfs_attr_trace_l_cn("wrong blk", context, node); + xfs_da_brelse(NULL, bp); + bp = NULL; + break; + case XFS_ATTR_LEAF_MAGIC: + leaf = bp->data; + if (cursor->hashval > + INT_GET(leaf->entries[ + INT_GET(leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT)) { + xfs_attr_trace_l_cl("wrong blk", + context, leaf); + xfs_da_brelse(NULL, bp); + bp = NULL; + } else if (cursor->hashval <= + INT_GET(leaf->entries[0].hashval, + ARCH_CONVERT)) { + xfs_attr_trace_l_cl("maybe wrong blk", + context, leaf); + xfs_da_brelse(NULL, bp); + bp = NULL; + } + break; + default: + xfs_attr_trace_l_c("wrong blk - ??", context); + xfs_da_brelse(NULL, bp); + bp = NULL; + } + } + } + + /* + * We did not find what we expected given the cursor's contents, + * so we start from the top and work down based on the hash value. + * Note that start of node block is same as start of leaf block. + */ + if (bp == NULL) { + cursor->blkno = 0; + for (;;) { + error = xfs_da_read_buf(NULL, context->dp, + cursor->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + node = bp->data; + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC) + break; + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) + != XFS_DA_NODE_MAGIC) { + xfs_da_brelse(NULL, bp); + return(XFS_ERROR(EFSCORRUPTED)); + } + btree = node->btree; + for (i = 0; + i < INT_GET(node->hdr.count, ARCH_CONVERT); + btree++, i++) { + if (cursor->hashval + <= INT_GET(btree->hashval, + ARCH_CONVERT)) { + cursor->blkno = INT_GET(btree->before, ARCH_CONVERT); + xfs_attr_trace_l_cb("descending", + context, btree); + break; + } + } + if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) { + xfs_da_brelse(NULL, bp); + return(0); + } + xfs_da_brelse(NULL, bp); + } + } + ASSERT(bp != NULL); + + /* + * Roll upward through the blocks, processing each leaf block in + * order. As long as there is space in the result buffer, keep + * adding the information. + */ + for (;;) { + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) { + xfs_da_brelse(NULL, bp); + return(XFS_ERROR(EFSCORRUPTED)); + } + error = xfs_attr_leaf_list_int(bp, context); + if (error || (INT_ISZERO(leaf->hdr.info.forw, ARCH_CONVERT))) + break; /* not really an error, buffer full or EOF */ + cursor->blkno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + xfs_da_brelse(NULL, bp); + error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, + &bp, XFS_ATTR_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + } + xfs_da_brelse(NULL, bp); + return(0); +} + + +/*======================================================================== + * External routines for manipulating out-of-line attribute values. + *========================================================================*/ + +/* + * Read the value associated with an attribute from the out-of-line buffer + * that we stored it in. + */ +STATIC int +xfs_attr_rmtval_get(xfs_da_args_t *args) +{ + xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; + xfs_mount_t *mp; + xfs_daddr_t dblkno; + xfs_caddr_t dst; + xfs_buf_t *bp; + int nmap, error, tmp, valuelen, blkcnt, i; + xfs_dablk_t lblkno; + + ASSERT(!(args->flags & ATTR_KERNOVAL)); + + mp = args->dp->i_mount; + dst = args->value; + valuelen = args->valuelen; + lblkno = args->rmtblkno; + while (valuelen > 0) { + nmap = ATTR_RMTVALUE_MAPSIZE; + error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, + args->rmtblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + NULL, 0, map, &nmap, NULL); + if (error) + return(error); + ASSERT(nmap >= 1); + + for (i = 0; (i < nmap) && (valuelen > 0); i++) { + ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && + (map[i].br_startblock != HOLESTARTBLOCK)); + dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); + blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); + error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, + blkcnt, XFS_BUF_LOCK, &bp); + if (error) + return(error); + + tmp = (valuelen < XFS_BUF_SIZE(bp)) + ? valuelen : XFS_BUF_SIZE(bp); + xfs_biomove(bp, 0, tmp, dst, XFS_B_READ); + xfs_buf_relse(bp); + dst += tmp; + valuelen -= tmp; + + lblkno += map[i].br_blockcount; + } + } + ASSERT(valuelen == 0); + return(0); +} + +/* + * Write the value associated with an attribute into the out-of-line buffer + * that we have defined for it. + */ +STATIC int +xfs_attr_rmtval_set(xfs_da_args_t *args) +{ + xfs_mount_t *mp; + xfs_fileoff_t lfileoff; + xfs_inode_t *dp; + xfs_bmbt_irec_t map; + xfs_daddr_t dblkno; + xfs_caddr_t src; + xfs_buf_t *bp; + xfs_dablk_t lblkno; + int blkcnt, valuelen, nmap, error, tmp, committed; + + dp = args->dp; + mp = dp->i_mount; + src = args->value; + + /* + * Find a "hole" in the attribute address space large enough for + * us to drop the new attribute's value into. + */ + blkcnt = XFS_B_TO_FSB(mp, args->valuelen); + lfileoff = 0; + error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, + XFS_ATTR_FORK); + if (error) { + return(error); + } + args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; + args->rmtblkcnt = blkcnt; + + /* + * Roll through the "value", allocating blocks on disk as required. + */ + while (blkcnt > 0) { + /* + * Allocate a single extent, up to the size of the value. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + nmap = 1; + error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno, + blkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA | + XFS_BMAPI_WRITE, + args->firstblock, args->total, &map, &nmap, + args->flist); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + ASSERT(nmap == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + lblkno += map.br_blockcount; + blkcnt -= map.br_blockcount; + + /* + * Start the next trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + return (error); + } + + /* + * Roll through the "value", copying the attribute value to the + * already-allocated blocks. Blocks are written synchronously + * so that we can know they are all on disk before we turn off + * the INCOMPLETE flag. + */ + lblkno = args->rmtblkno; + valuelen = args->valuelen; + while (valuelen > 0) { + /* + * Try to remember where we decided to put the value. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + nmap = 1; + error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno, + args->rmtblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + args->firstblock, 0, &map, &nmap, NULL); + if (error) { + return(error); + } + ASSERT(nmap == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + + dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), + blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); + + bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, + blkcnt, XFS_BUF_LOCK); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + + tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : + XFS_BUF_SIZE(bp); + xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE); + if (tmp < XFS_BUF_SIZE(bp)) + xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp); + if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */ + return (error); + } + src += tmp; + valuelen -= tmp; + + lblkno += map.br_blockcount; + } + ASSERT(valuelen == 0); + return(0); +} + +/* + * Remove the value associated with an attribute by deleting the + * out-of-line buffer that it is stored on. + */ +STATIC int +xfs_attr_rmtval_remove(xfs_da_args_t *args) +{ + xfs_mount_t *mp; + xfs_bmbt_irec_t map; + xfs_buf_t *bp; + xfs_daddr_t dblkno; + xfs_dablk_t lblkno; + int valuelen, blkcnt, nmap, error, done, committed; + + mp = args->dp->i_mount; + + /* + * Roll through the "value", invalidating the attribute value's + * blocks. + */ + lblkno = args->rmtblkno; + valuelen = args->rmtblkcnt; + while (valuelen > 0) { + /* + * Try to remember where we decided to put the value. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + nmap = 1; + error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno, + args->rmtblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + args->firstblock, 0, &map, &nmap, + args->flist); + if (error) { + return(error); + } + ASSERT(nmap == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + + dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), + blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); + + /* + * If the "remote" value is in the cache, remove it. + */ + /* bp = incore(mp->m_dev, dblkno, blkcnt, 1); */ + bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, 1); + if (bp) { + XFS_BUF_STALE(bp); + XFS_BUF_UNDELAYWRITE(bp); + xfs_buf_relse(bp); + bp = NULL; + } + + valuelen -= map.br_blockcount; + + lblkno += map.br_blockcount; + } + + /* + * Keep de-allocating extents until the remote-value region is gone. + */ + lblkno = args->rmtblkno; + blkcnt = args->rmtblkcnt; + done = 0; + while (!done) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + 1, args->firstblock, args->flist, &done); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, args->dp); + } + + /* + * Close out trans and start the next one in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, args->dp))) + return (error); + } + return(0); +} + +#if defined(XFS_ATTR_TRACE) +/* + * Add a trace buffer entry for an attr_list context structure. + */ +void +xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)NULL, + (__psunsigned_t)NULL, + (__psunsigned_t)NULL); +} + +/* + * Add a trace buffer entry for a context structure and a Btree node. + */ +void +xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, + struct xfs_da_intnode *node) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)INT_GET(node->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[INT_GET(node->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); +} + +/* + * Add a trace buffer entry for a context structure and a Btree element. + */ +void +xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, + struct xfs_da_node_entry *btree) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)INT_GET(btree->hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(btree->before, ARCH_CONVERT), + (__psunsigned_t)NULL); +} + +/* + * Add a trace buffer entry for a context structure and a leaf block. + */ +void +xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, + struct xfs_attr_leafblock *leaf) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)INT_GET(leaf->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); +} + +/* + * Add a trace buffer entry for the arguments given to the routine, + * generic form. + */ +void +xfs_attr_trace_enter(int type, char *where, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11, + __psunsigned_t a12, __psunsigned_t a13, + __psunsigned_t a14, __psunsigned_t a15) +{ + ASSERT(xfs_attr_trace_buf); + ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), + (void *)where, + (void *)a2, (void *)a3, (void *)a4, + (void *)a5, (void *)a6, (void *)a7, + (void *)a8, (void *)a9, (void *)a10, + (void *)a11, (void *)a12, (void *)a13, + (void *)a14, (void *)a15); +} +#endif /* XFS_ATTR_TRACE */ diff -Nur linux-2.4.19/fs/xfs/xfs_attr.h linux-2.4.19-sgi211r3/fs/xfs/xfs_attr.h --- linux-2.4.19/fs/xfs/xfs_attr.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_attr.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_H__ +#define __XFS_ATTR_H__ + +/* + * xfs_attr.h + * + * Large attribute lists are structured around Btrees where all the data + * elements are in the leaf nodes. Attribute names are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of an attribute name may not be unique, we may have duplicate keys. + * The internal links in the Btree are logical block offsets into the file. + * + * Small attribute lists use a different format and are packed as tightly + * as possible so as to fit into the literal area of the inode. + */ + +#ifdef XFS_ALL_TRACE +#define XFS_ATTR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ATTR_TRACE +#endif + + +/*======================================================================== + * External interfaces + *========================================================================*/ + +#define ATTR_ROOT 0x0002 /* use attrs in root namespace, not user */ +#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ +#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ +#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ +#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ +#define ATTR_KERNAMELS 0x4000 /* [kernel] list attr names (simple list) */ +#define ATTR_KERNFULLS 0x8000 /* [kernel] full attr list, ie. root+user */ + +/* + * The maximum size (into the kernel or returned from the kernel) of an + * attribute value or the buffer used for an attr_list() call. Larger + * sizes will result in an E2BIG return code. + */ +#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */ + +/* + * Define how lists of attribute names are returned to the user from + * the attr_list() call. A large, 32bit aligned, buffer is passed in + * along with its size. We put an array of offsets at the top that each + * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom. + */ +typedef struct attrlist { + __s32 al_count; /* number of entries in attrlist */ + __s32 al_more; /* T/F: more attrs (do call again) */ + __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */ +} attrlist_t; + +/* + * Show the interesting info about one attribute. This is what the + * al_offset[i] entry points to. + */ +typedef struct attrlist_ent { /* data from attr_list() */ + __u32 a_valuelen; /* number bytes in value of attr */ + char a_name[1]; /* attr name (NULL terminated) */ +} attrlist_ent_t; + +/* + * Given a pointer to the (char*) buffer containing the attr_list() result, + * and an index, return a pointer to the indicated attribute in the buffer. + */ +#define ATTR_ENTRY(buffer, index) \ + ((attrlist_ent_t *) \ + &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) + +/* + * Multi-attribute operation vector. + */ +typedef struct attr_multiop { + int am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */ + int am_error; /* [out arg] result of this sub-op (an errno) */ + char *am_attrname; /* attribute name to work with */ + char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */ + int am_length; /* [in/out arg] length of value */ + int am_flags; /* bitwise OR of attr API flags defined above */ +} attr_multiop_t; + +#define ATTR_OP_GET 1 /* return the indicated attr's value */ +#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ +#define ATTR_OP_REMOVE 3 /* remove the indicated attr */ + +/* + * Kernel-internal version of the attrlist cursor. + */ +typedef struct attrlist_cursor_kern { + __u32 hashval; /* hash value of next entry to add */ + __u32 blkno; /* block containing entry (suggestion) */ + __u32 offset; /* offset in list of equal-hashvals */ + __u16 pad1; /* padding to match user-level */ + __u8 pad2; /* padding to match user-level */ + __u8 initted; /* T/F: cursor has been initialized */ +} attrlist_cursor_kern_t; + + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +struct cred; +struct vnode; +struct xfs_inode; +struct attrlist_cursor_kern; +struct xfs_ext_attr; +struct xfs_da_args; + +/* + * Overall external interface routines. + */ +int xfs_attr_get(bhv_desc_t *, char *, char *, int *, int, struct cred *); +int xfs_attr_set(bhv_desc_t *, char *, char *, int, int, struct cred *); +int xfs_attr_remove(bhv_desc_t *, char *, int, struct cred *); +int xfs_attr_list(bhv_desc_t *, char *, int, int, + struct attrlist_cursor_kern *, struct cred *); +int xfs_attr_inactive(struct xfs_inode *dp); + +int xfs_attr_node_get(struct xfs_da_args *); +int xfs_attr_leaf_get(struct xfs_da_args *); +int xfs_attr_shortform_getvalue(struct xfs_da_args *); +int xfs_attr_fetch(struct xfs_inode *, char *, char *, int); + +#endif /* __XFS_ATTR_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_attr_fetch.c linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_fetch.c --- linux-2.4.19/fs/xfs/xfs_attr_fetch.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_fetch.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +int +xfs_attr_fetch(xfs_inode_t *ip, char *name, char *value, int valuelen) +{ + xfs_da_args_t args; + int error; + + if (XFS_IFORK_Q(ip) == 0) + return ENOATTR; + /* + * Do the argument setup for the xfs_attr routines. + */ + bzero((char *)&args, sizeof(args)); + args.dp = ip; + args.flags = ATTR_ROOT; + args.whichfork = XFS_ATTR_FORK; + args.name = name; + args.namelen = strlen(name); + args.value = value; + args.valuelen = valuelen; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (args.dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) + error = xfs_attr_shortform_getvalue(&args); + else if (xfs_bmap_one_block(args.dp, XFS_ATTR_FORK)) + error = xfs_attr_leaf_get(&args); + else + error = xfs_attr_node_get(&args); + + if (error == EEXIST) + error = 0; + + return(error); +} diff -Nur linux-2.4.19/fs/xfs/xfs_attr_leaf.c linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_leaf.c --- linux-2.4.19/fs/xfs/xfs_attr_leaf.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_leaf.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,2971 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * xfs_attr_leaf.c + * + * GROT: figure out how to recover gracefully when bmap returns ENOSPC. + */ + +#include + +/* + * xfs_attr_leaf.c + * + * Routines to implement leaf blocks of attributes as Btrees of hashed names. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, + int freemap_index); +STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer); +STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2); +STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *leaf_blk_1, + xfs_da_state_blk_t *leaf_blk_2, + int *number_entries_in_blk1, + int *number_usedbytes_in_blk1); + +/* + * Utility routines. + */ +STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, + int src_start, + xfs_attr_leafblock_t *dst_leaf, + int dst_start, int move_count, + xfs_mount_t *mp); + + +/*======================================================================== + * External routines when dirsize < XFS_LITINO(mp). + *========================================================================*/ + +/* + * Create the initial contents of a shortform attribute list. + */ +int +xfs_attr_shortform_create(xfs_da_args_t *args) +{ + xfs_attr_sf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_ifork_t *ifp; + + dp = args->dp; + ASSERT(dp != NULL); + ifp = dp->i_afp; + ASSERT(ifp != NULL); + ASSERT(ifp->if_bytes == 0); + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) { + ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL; + ifp->if_flags |= XFS_IFINLINE; + } else { + ASSERT(ifp->if_flags & XFS_IFINLINE); + } + xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK); + hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data; + INT_ZERO(hdr->count, ARCH_CONVERT); + INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr)); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); + return(0); +} + +/* + * Add a name/value pair to the shortform attribute list. + * Overflow from the inode has already been checked for. + */ +int +xfs_attr_shortform_add(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int i, offset, size; + xfs_inode_t *dp; + xfs_ifork_t *ifp; + + dp = args->dp; + ifp = dp->i_afp; + ASSERT(ifp->if_flags & XFS_IFINLINE); + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { + if (sfe->namelen != args->namelen) + continue; + if (bcmp(args->name, sfe->nameval, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + return(XFS_ERROR(EEXIST)); + } + + offset = (char *)sfe - (char *)sf; + size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); + xfs_idata_realloc(dp, size, XFS_ATTR_FORK); + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset); + + sfe->namelen = args->namelen; + INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen); + sfe->flags = (args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0; + bcopy(args->name, sfe->nameval, args->namelen); + bcopy(args->value, &sfe->nameval[args->namelen], args->valuelen); + INT_MOD(sf->hdr.count, ARCH_CONVERT, 1); + INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); + + return(0); +} + +/* + * Remove a name from the shortform attribute list structure. + */ +int +xfs_attr_shortform_remove(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int base, size=0, end, totsize, i; + xfs_inode_t *dp; + + /* + * Remove the attribute. + */ + dp = args->dp; + base = sizeof(xfs_attr_sf_hdr_t); + sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), + base += size, i++) { + size = XFS_ATTR_SF_ENTSIZE(sfe); + if (sfe->namelen != args->namelen) + continue; + if (bcmp(sfe->nameval, args->name, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + break; + } + if (i == INT_GET(sf->hdr.count, ARCH_CONVERT)) + return(XFS_ERROR(ENOATTR)); + + end = base + size; + totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT); + if (end != totsize) { + ovbcopy(&((char *)sf)[end], &((char *)sf)[base], + totsize - end); + } + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size); + xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); + + return(0); +} + +/* + * Look up a name in a shortform attribute list structure. + */ +/*ARGSUSED*/ +int +xfs_attr_shortform_lookup(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int i; + xfs_ifork_t *ifp; + + ifp = args->dp->i_afp; + ASSERT(ifp->if_flags & XFS_IFINLINE); + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { + if (sfe->namelen != args->namelen) + continue; + if (bcmp(args->name, sfe->nameval, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + return(XFS_ERROR(EEXIST)); + } + return(XFS_ERROR(ENOATTR)); +} + +/* + * Look up a name in a shortform attribute list structure. + */ +/*ARGSUSED*/ +int +xfs_attr_shortform_getvalue(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int i; + + ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE); + sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { + if (sfe->namelen != args->namelen) + continue; + if (bcmp(args->name, sfe->nameval, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + if (args->flags & ATTR_KERNOVAL) { + args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); + return(XFS_ERROR(EEXIST)); + } + if (args->valuelen < INT_GET(sfe->valuelen, ARCH_CONVERT)) { + args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); + return(XFS_ERROR(ERANGE)); + } + args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); + bcopy(&sfe->nameval[args->namelen], args->value, + args->valuelen); + return(XFS_ERROR(EEXIST)); + } + return(XFS_ERROR(ENOATTR)); +} + +/* + * Convert from using the shortform to the leaf. + */ +int +xfs_attr_shortform_to_leaf(xfs_da_args_t *args) +{ + xfs_inode_t *dp; + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + xfs_da_args_t nargs; + char *tmpbuffer; + int error, i, size; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + xfs_ifork_t *ifp; + + dp = args->dp; + ifp = dp->i_afp; + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + size = INT_GET(sf->hdr.totsize, ARCH_CONVERT); + tmpbuffer = kmem_alloc(size, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(ifp->if_u1.if_data, tmpbuffer, size); + sf = (xfs_attr_shortform_t *)tmpbuffer; + + xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); + bp = NULL; + error = xfs_da_grow_inode(args, &blkno); + if (error) { + /* + * If we hit an IO error middle of the transaction inside + * grow_inode(), we may have inconsistent data. Bail out. + */ + if (error == EIO) + goto out; + xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ + bcopy(tmpbuffer, ifp->if_u1.if_data, size); /* it back */ + goto out; + } + + ASSERT(blkno == 0); + error = xfs_attr_leaf_create(args, blkno, &bp); + if (error) { + error = xfs_da_shrink_inode(args, 0, bp); + bp = NULL; + if (error) + goto out; + xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ + bcopy(tmpbuffer, ifp->if_u1.if_data, size); /* it back */ + goto out; + } + + bzero((char *)&nargs, sizeof(nargs)); + nargs.dp = dp; + nargs.firstblock = args->firstblock; + nargs.flist = args->flist; + nargs.total = args->total; + nargs.whichfork = XFS_ATTR_FORK; + nargs.trans = args->trans; + nargs.oknoent = 1; + + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + nargs.name = (char *)sfe->nameval; + nargs.namelen = sfe->namelen; + nargs.value = (char *)&sfe->nameval[nargs.namelen]; + nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); + nargs.hashval = xfs_da_hashname((char *)sfe->nameval, + sfe->namelen); + nargs.flags = (sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0; + error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */ + ASSERT(error == ENOATTR); + error = xfs_attr_leaf_add(bp, &nargs); + ASSERT(error != ENOSPC); + if (error) + goto out; + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + } + error = 0; + +out: + if(bp) + xfs_da_buf_done(bp); + kmem_free(tmpbuffer, size); + return(error); +} + +STATIC int +xfs_attr_shortform_compare(const void *a, const void *b) +{ + xfs_attr_sf_sort_t *sa, *sb; + + sa = (xfs_attr_sf_sort_t *)a; + sb = (xfs_attr_sf_sort_t *)b; + if (INT_GET(sa->hash, ARCH_CONVERT) + < INT_GET(sb->hash, ARCH_CONVERT)) { + return(-1); + } else if (INT_GET(sa->hash, ARCH_CONVERT) + > INT_GET(sb->hash, ARCH_CONVERT)) { + return(1); + } else { + return(sa->entno - sb->entno); + } +} + +/* + * Copy out entries of shortform attribute lists for attr_list(). + * Shortform atrtribute lists are not stored in hashval sorted order. + * If the output buffer is not large enough to hold them all, then we + * we have to calculate each entries' hashvalue and sort them before + * we can begin returning them to the user. + */ +/*ARGSUSED*/ +int +xfs_attr_shortform_list(xfs_attr_list_context_t *context) +{ + attrlist_cursor_kern_t *cursor; + xfs_attr_sf_sort_t *sbuf, *sbp; + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + xfs_inode_t *dp; + int sbsize, nsbuf, count, i; + + ASSERT(context != NULL); + dp = context->dp; + ASSERT(dp != NULL); + ASSERT(dp->i_afp != NULL); + sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; + ASSERT(sf != NULL); + if (INT_ISZERO(sf->hdr.count, ARCH_CONVERT)) + return(0); + cursor = context->cursor; + ASSERT(cursor != NULL); + + xfs_attr_trace_l_c("sf start", context); + + /* + * If the buffer is large enough, do not bother with sorting. + * Note the generous fudge factor of 16 overhead bytes per entry. + */ + if ((dp->i_afp->if_bytes + INT_GET(sf->hdr.count, ARCH_CONVERT) * 16) + < context->bufsize) { + for (i = 0, sfe = &sf->list[0]; + i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + int ns = (sfe->flags & XFS_ATTR_ROOT)? + ROOT_NAMES : USER_NAMES; + if (((context->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0) && + !(context->flags & ATTR_KERNFULLS)) { + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + continue; + } + if (context->flags & ATTR_KERNOVAL) { + ASSERT(context->flags & ATTR_KERNAMELS); + context->count += xfs_namespaces[ns].namelen + + INT_GET(sfe->namelen, ARCH_CONVERT) + 1; + } + else { + if (xfs_attr_put_listent(context, ns, + (char *)sfe->nameval, + (int)sfe->namelen, + (int)INT_GET(sfe->valuelen, + ARCH_CONVERT))) + break; + } + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + } + xfs_attr_trace_l_c("sf big-gulp", context); + return(0); + } + + /* + * It didn't all fit, so we have to sort everything on hashval. + */ + sbsize = INT_GET(sf->hdr.count, ARCH_CONVERT) * sizeof(*sbuf); + sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP); + + /* + * Scan the attribute list for the rest of the entries, storing + * the relevant info from only those that match into a buffer. + */ + nsbuf = 0; + for (i = 0, sfe = &sf->list[0]; + i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + if (((char *)sfe < (char *)sf) || + ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)) || + (sfe->namelen >= MAXNAMELEN)) { + xfs_attr_trace_l_c("sf corrupted", context); + kmem_free(sbuf, sbsize); + return XFS_ERROR(EFSCORRUPTED); + } + if (((context->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0) && + !(context->flags & ATTR_KERNFULLS)) { + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + continue; + } + sbp->entno = i; + INT_SET(sbp->hash, ARCH_CONVERT, + xfs_da_hashname((char *)sfe->nameval, sfe->namelen)); + sbp->name = (char *)sfe->nameval; + sbp->namelen = sfe->namelen; + /* These are bytes, and both on-disk, don't endian-flip */ + sbp->valuelen = sfe->valuelen; + sbp->flags = sfe->flags; + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + sbp++; + nsbuf++; + } + + /* + * Sort the entries on hash then entno. + */ + qsort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare); + + /* + * Re-find our place IN THE SORTED LIST. + */ + count = 0; + cursor->initted = 1; + cursor->blkno = 0; + for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) { + if (INT_GET(sbp->hash, ARCH_CONVERT) == cursor->hashval) { + if (cursor->offset == count) { + break; + } + count++; + } else if (INT_GET(sbp->hash, ARCH_CONVERT) > cursor->hashval) { + break; + } + } + if (i == nsbuf) { + kmem_free(sbuf, sbsize); + xfs_attr_trace_l_c("blk end", context); + return(0); + } + + /* + * Loop putting entries into the user buffer. + */ + for ( ; i < nsbuf; i++, sbp++) { + int ns = (sbp->flags & XFS_ATTR_ROOT)? ROOT_NAMES:USER_NAMES; + if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) { + cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT); + cursor->offset = 0; + } + if (context->flags & ATTR_KERNOVAL) { + ASSERT(context->flags & ATTR_KERNAMELS); + context->count += xfs_namespaces[ns].namelen + + sbp->namelen + 1; + } + else { + if (xfs_attr_put_listent(context, ns, + sbp->name, sbp->namelen, + INT_GET(sbp->valuelen, ARCH_CONVERT))) + break; + } + cursor->offset++; + } + + kmem_free(sbuf, sbsize); + xfs_attr_trace_l_c("sf E-O-F", context); + return(0); +} + +/* + * Check a leaf attribute block to see if all the entries would fit into + * a shortform attribute list. + */ +int +xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + int bytes, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + + entry = &leaf->entries[0]; + bytes = sizeof(struct xfs_attr_sf_hdr); + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if (entry->flags & XFS_ATTR_INCOMPLETE) + continue; /* don't copy partial entries */ + if (!(entry->flags & XFS_ATTR_LOCAL)) + return(0); + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); + if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX) + return(0); + if (INT_GET(name_loc->valuelen, ARCH_CONVERT) >= XFS_ATTR_SF_ENTSIZE_MAX) + return(0); + bytes += sizeof(struct xfs_attr_sf_entry)-1 + + name_loc->namelen + + INT_GET(name_loc->valuelen, ARCH_CONVERT); + } + return( bytes < XFS_IFORK_ASIZE(dp) ); +} + +/* + * Convert a leaf attribute list to shortform attribute list + */ +int +xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_da_args_t nargs; + xfs_inode_t *dp; + char *tmpbuffer; + int error, i; + + dp = args->dp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + ASSERT(bp != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount)); + leaf = (xfs_attr_leafblock_t *)tmpbuffer; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + bzero(bp->data, XFS_LBSIZE(dp->i_mount)); + + /* + * Clean out the prior contents of the attribute list. + */ + error = xfs_da_shrink_inode(args, 0, bp); + if (error) + goto out; + error = xfs_attr_shortform_create(args); + if (error) + goto out; + + /* + * Copy the attributes + */ + bzero((char *)&nargs, sizeof(nargs)); + nargs.dp = dp; + nargs.firstblock = args->firstblock; + nargs.flist = args->flist; + nargs.total = args->total; + nargs.whichfork = XFS_ATTR_FORK; + nargs.trans = args->trans; + nargs.oknoent = 1; + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if (entry->flags & XFS_ATTR_INCOMPLETE) + continue; /* don't copy partial entries */ + if (INT_ISZERO(entry->nameidx, ARCH_CONVERT)) + continue; + ASSERT(entry->flags & XFS_ATTR_LOCAL); + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); + nargs.name = (char *)name_loc->nameval; + nargs.namelen = name_loc->namelen; + nargs.value = (char *)&name_loc->nameval[nargs.namelen]; + nargs.valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT); + nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT); + nargs.flags = (entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0; + xfs_attr_shortform_add(&nargs); + } + error = 0; + +out: + kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); + return(error); +} + +/* + * Convert from using a single leaf to a root node and a leaf. + */ +int +xfs_attr_leaf_to_node(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_da_intnode_t *node; + xfs_inode_t *dp; + xfs_dabuf_t *bp1, *bp2; + xfs_dablk_t blkno; + int error; + + dp = args->dp; + bp1 = bp2 = NULL; + error = xfs_da_grow_inode(args, &blkno); + if (error) + goto out; + error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, + XFS_ATTR_FORK); + if (error) + goto out; + ASSERT(bp1 != NULL); + bp2 = NULL; + error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp2, + XFS_ATTR_FORK); + if (error) + goto out; + ASSERT(bp2 != NULL); + bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount)); + xfs_da_buf_done(bp1); + bp1 = NULL; + xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); + + /* + * Set up the new root node. + */ + error = xfs_da_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK); + if (error) + goto out; + node = bp1->data; + leaf = bp2->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + /* both on-disk, don't endian-flip twice */ + node->btree[0].hashval = + leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval; + INT_SET(node->btree[0].before, ARCH_CONVERT, blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 1); + xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1); + error = 0; +out: + if (bp1) + xfs_da_buf_done(bp1); + if (bp2) + xfs_da_buf_done(bp2); + return(error); +} + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of a leaf attribute list + * or a leaf in a node attribute list. + */ +int +xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int error; + + dp = args->dp; + ASSERT(dp != NULL); + error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + leaf = bp->data; + bzero((char *)leaf, XFS_LBSIZE(dp->i_mount)); + hdr = &leaf->hdr; + INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC); + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); + if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) { + INT_SET(hdr->firstused, ARCH_CONVERT, + XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN); + } + + INT_SET(hdr->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_SET(hdr->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr->firstused, ARCH_CONVERT) + - INT_GET(hdr->freemap[0].base, + ARCH_CONVERT)); + + xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); + + *bpp = bp; + return(0); +} + +/* + * Split the leaf node, rebalance, then add the new entry. + */ +int +xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_dablk_t blkno; + int error; + + /* + * Allocate space for a new leaf node. + */ + ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); + error = xfs_da_grow_inode(state->args, &blkno); + if (error) + return(error); + error = xfs_attr_leaf_create(state->args, blkno, &newblk->bp); + if (error) + return(error); + newblk->blkno = blkno; + newblk->magic = XFS_ATTR_LEAF_MAGIC; + + /* + * Rebalance the entries across the two leaves. + * NOTE: rebalance() currently depends on the 2nd block being empty. + */ + xfs_attr_leaf_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + + /* + * Save info on "old" attribute for "atomic rename" ops, leaf_add() + * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the + * "new" attrs info. Will need the "old" info to remove it later. + * + * Insert the "new" entry in the correct block. + */ + if (state->inleaf) + error = xfs_attr_leaf_add(oldblk->bp, state->args); + else + error = xfs_attr_leaf_add(newblk->bp, state->args); + + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); + return(error); +} + +/* + * Add a name to the leaf attribute list structure. + */ +int +xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_map_t *map; + int tablesize, entsize, sum, tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT((args->index >= 0) + && (args->index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); + hdr = &leaf->hdr; + entsize = xfs_attr_leaf_newentsize(args, + args->trans->t_mountp->m_sb.sb_blocksize, NULL); + + /* + * Search through freemap for first-fit on new name length. + * (may need to figure in size of entry struct too) + */ + tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[XFS_ATTR_LEAF_MAPSIZE-1]; + for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { + if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { + sum += INT_GET(map->size, ARCH_CONVERT); + continue; + } + if (INT_ISZERO(map->size, ARCH_CONVERT)) + continue; /* no space in this map */ + tmp = entsize; + if (INT_GET(map->base, ARCH_CONVERT) + < INT_GET(hdr->firstused, ARCH_CONVERT)) + tmp += sizeof(xfs_attr_leaf_entry_t); + if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { + tmp = xfs_attr_leaf_add_work(bp, args, i); + return(tmp); + } + sum += INT_GET(map->size, ARCH_CONVERT); + } + + /* + * If there are no holes in the address space of the block, + * and we don't have enough freespace, then compaction will do us + * no good and we should just give up. + */ + if (!hdr->holes && (sum < entsize)) + return(XFS_ERROR(ENOSPC)); + + /* + * Compact the entries to coalesce free space. + * This may change the hdr->count via dropping INCOMPLETE entries. + */ + xfs_attr_leaf_compact(args->trans, bp); + + /* + * After compaction, the block is guaranteed to have only one + * free region, in freemap[0]. If it is not big enough, give up. + */ + if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) + < (entsize + sizeof(xfs_attr_leaf_entry_t))) + return(XFS_ERROR(ENOSPC)); + + return(xfs_attr_leaf_add_work(bp, args, 0)); +} + +/* + * Add a name to a leaf attribute list structure. + */ +STATIC int +xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_attr_leaf_map_t *map; + xfs_mount_t *mp; + int tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr = &leaf->hdr; + ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE)); + ASSERT((args->index >= 0) + && (args->index <= INT_GET(hdr->count, ARCH_CONVERT))); + + /* + * Force open some space in the entry array and fill it in. + */ + entry = &leaf->entries[args->index]; + if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr->count, ARCH_CONVERT) - args->index; + tmp *= sizeof(xfs_attr_leaf_entry_t); + ovbcopy((char *)entry, (char *)(entry+1), tmp); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); + } + INT_MOD(hdr->count, ARCH_CONVERT, 1); + + /* + * Allocate space for the new string (at the end of the run). + */ + map = &hdr->freemap[mapindex]; + mp = args->trans->t_mountp; + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT((INT_GET(map->base, ARCH_CONVERT) & 0x3) == 0); + ASSERT(INT_GET(map->size, ARCH_CONVERT) + >= xfs_attr_leaf_newentsize(args, + mp->m_sb.sb_blocksize, NULL)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT((INT_GET(map->size, ARCH_CONVERT) & 0x3) == 0); + INT_MOD(map->size, ARCH_CONVERT, + -xfs_attr_leaf_newentsize(args, mp->m_sb.sb_blocksize, &tmp)); + INT_SET(entry->nameidx, ARCH_CONVERT, + INT_GET(map->base, ARCH_CONVERT) + + INT_GET(map->size, ARCH_CONVERT)); + INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); + entry->flags = tmp ? XFS_ATTR_LOCAL : 0; + entry->flags |= (args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0; + if (args->rename) { + entry->flags |= XFS_ATTR_INCOMPLETE; + if ((args->blkno2 == args->blkno) && + (args->index2 <= args->index)) { + args->index2++; + } + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + ASSERT((args->index == 0) || (INT_GET(entry->hashval, ARCH_CONVERT) + >= INT_GET((entry-1)->hashval, + ARCH_CONVERT))); + ASSERT((args->index == INT_GET(hdr->count, ARCH_CONVERT)-1) || + (INT_GET(entry->hashval, ARCH_CONVERT) + <= (INT_GET((entry+1)->hashval, ARCH_CONVERT)))); + + /* + * Copy the attribute name and value into the new space. + * + * For "remote" attribute values, simply note that we need to + * allocate space for the "remote" value. We can't actually + * allocate the extents in this transaction, and we can't decide + * which blocks they should be as we might allocate more blocks + * as part of this transaction (a split operation for example). + */ + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); + name_loc->namelen = args->namelen; + INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen); + bcopy(args->name, (char *)name_loc->nameval, args->namelen); + bcopy(args->value, (char *)&name_loc->nameval[args->namelen], + INT_GET(name_loc->valuelen, ARCH_CONVERT)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + name_rmt->namelen = args->namelen; + bcopy(args->name, (char *)name_rmt->name, args->namelen); + entry->flags |= XFS_ATTR_INCOMPLETE; + /* just in case */ + INT_ZERO(name_rmt->valuelen, ARCH_CONVERT); + INT_ZERO(name_rmt->valueblk, ARCH_CONVERT); + args->rmtblkno = 1; + args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen); + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), + xfs_attr_leaf_entsize(leaf, args->index))); + + /* + * Update the control info for this leaf node + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) + < INT_GET(hdr->firstused, ARCH_CONVERT)) { + /* both on-disk, don't endian-flip twice */ + hdr->firstused = entry->nameidx; + } + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) + >= ((INT_GET(hdr->count, ARCH_CONVERT) + * sizeof(*entry))+sizeof(*hdr))); + tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[0]; + for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { + if (INT_GET(map->base, ARCH_CONVERT) == tmp) { + INT_MOD(map->base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, + -sizeof(xfs_attr_leaf_entry_t)); + } + } + INT_MOD(hdr->usedbytes, ARCH_CONVERT, + xfs_attr_leaf_entsize(leaf, args->index)); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + return(0); +} + +/* + * Garbage collect a leaf attribute list block by copying it to a new buffer. + */ +STATIC void +xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp) +{ + xfs_attr_leafblock_t *leaf_s, *leaf_d; + xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; + xfs_mount_t *mp; + char *tmpbuffer; + + mp = trans->t_mountp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(mp)); + bzero(bp->data, XFS_LBSIZE(mp)); + + /* + * Copy basic information + */ + leaf_s = (xfs_attr_leafblock_t *)tmpbuffer; + leaf_d = bp->data; + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + hdr_d->info = hdr_s->info; /* struct copy */ + INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp)); + /* handle truncation gracefully */ + if (INT_ISZERO(hdr_d->firstused, ARCH_CONVERT)) { + INT_SET(hdr_d->firstused, ARCH_CONVERT, + XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN); + } + INT_ZERO(hdr_d->usedbytes, ARCH_CONVERT); + INT_ZERO(hdr_d->count, ARCH_CONVERT); + hdr_d->holes = 0; + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr_d->firstused, ARCH_CONVERT) + - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + + /* + * Copy all entry's in the same (sorted) order, + * but allocate name/value pairs packed and in sequence. + */ + xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0, + (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); + + xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); + + kmem_free(tmpbuffer, XFS_LBSIZE(mp)); +} + +/* + * Redistribute the attribute list entries between two leaf nodes, + * taking into account the size of the new entry. + * + * NOTE: if new block is empty, then it will get the upper half of the + * old block. At present, all (one) callers pass in an empty second block. + * + * This code adjusts the args->index/blkno and args->index2/blkno2 fields + * to match what it is doing in splitting the attribute leaf block. Those + * values are used in "atomic rename" operations on attributes. Note that + * the "new" and "old" values can end up in different blocks. + */ +STATIC void +xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_args_t *args; + xfs_da_state_blk_t *tmp_blk; + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_hdr_t *hdr1, *hdr2; + int count, totallen, max, space, swap; + + /* + * Set up environment. + */ + ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + args = state->args; + + /* + * Check ordering of blocks, reverse if it makes things simpler. + * + * NOTE: Given that all (current) callers pass in an empty + * second block, this code should never set "swap". + */ + swap = 0; + if (xfs_attr_leaf_order(blk1->bp, blk2->bp)) { + tmp_blk = blk1; + blk1 = blk2; + blk2 = tmp_blk; + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + swap = 1; + } + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. Then get + * the direction to copy and the number of elements to move. + * + * "inleaf" is true if the new entry should be inserted into blk1. + * If "swap" is also true, then reverse the sense of "inleaf". + */ + state->inleaf = xfs_attr_leaf_figure_balance(state, blk1, blk2, + &count, &totallen); + if (swap) + state->inleaf = !state->inleaf; + + /* + * Move any entries required from leaf to leaf: + */ + if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + /* number entries being moved */ + count = INT_GET(hdr1->count, ARCH_CONVERT) - count; + space = INT_GET(hdr1->usedbytes, ARCH_CONVERT) - totallen; + space += count * sizeof(xfs_attr_leaf_entry_t); + + /* + * leaf2 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr2->firstused, ARCH_CONVERT) + - sizeof(xfs_attr_leaf_hdr_t); + max -= INT_GET(hdr2->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + if (space > max) { + xfs_attr_leaf_compact(args->trans, blk2->bp); + } + + /* + * Move high entries from leaf1 to low end of leaf2. + */ + xfs_attr_leaf_moveents(leaf1, + INT_GET(hdr1->count, ARCH_CONVERT)-count, + leaf2, 0, count, state->mp); + + xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); + xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); + } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * I assert that since all callers pass in an empty + * second buffer, this code should never execute. + */ + + /* + * Figure the total bytes to be added to the destination leaf. + */ + /* number entries being moved */ + count -= INT_GET(hdr1->count, ARCH_CONVERT); + space = totallen - INT_GET(hdr1->usedbytes, ARCH_CONVERT); + space += count * sizeof(xfs_attr_leaf_entry_t); + + /* + * leaf1 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr1->firstused, ARCH_CONVERT) + - sizeof(xfs_attr_leaf_hdr_t); + max -= INT_GET(hdr1->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + if (space > max) { + xfs_attr_leaf_compact(args->trans, blk1->bp); + } + + /* + * Move low entries from leaf2 to high end of leaf1. + */ + xfs_attr_leaf_moveents(leaf2, 0, leaf1, + (int)INT_GET(hdr1->count, ARCH_CONVERT), count, + state->mp); + + xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); + xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); + } + + /* + * Copy out last hashval in each block for B-tree code. + */ + blk1->hashval = + INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT); + blk2->hashval = + INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + * NOTE: this code depends on the (current) situation that the + * second block was originally empty. + * + * If the insertion point moved to the 2nd block, we must adjust + * the index. We must also track the entry just following the + * new entry for use in an "atomic rename" operation, that entry + * is always the "old" entry and the "new" entry is what we are + * inserting. The index/blkno fields refer to the "old" entry, + * while the index2/blkno2 fields refer to the "new" entry. + */ + if (blk1->index > INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { + ASSERT(state->inleaf == 0); + blk2->index = blk1->index + - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + args->index = args->index2 = blk2->index; + args->blkno = args->blkno2 = blk2->blkno; + } else if (blk1->index == INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { + if (state->inleaf) { + args->index = blk1->index; + args->blkno = blk1->blkno; + args->index2 = 0; + args->blkno2 = blk2->blkno; + } else { + blk2->index = blk1->index + - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + args->index = args->index2 = blk2->index; + args->blkno = args->blkno2 = blk2->blkno; + } + } else { + ASSERT(state->inleaf == 1); + args->index = args->index2 = blk1->index; + args->blkno = args->blkno2 = blk1->blkno; + } +} + +/* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + * GROT: Is this really necessary? With other than a 512 byte blocksize, + * GROT: there will always be enough room in either block for a new entry. + * GROT: Do a double-split for this case? + */ +STATIC int +xfs_attr_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2, + int *countarg, int *usedbytesarg) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_hdr_t *hdr1, *hdr2; + xfs_attr_leaf_entry_t *entry; + int count, max, index, totallen, half; + int lastdelta, foundit, tmp; + + /* + * Set up environment. + */ + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + foundit = 0; + totallen = 0; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + */ + max = INT_GET(hdr1->count, ARCH_CONVERT) + + INT_GET(hdr2->count, ARCH_CONVERT); + half = (max+1) * sizeof(*entry); + half += INT_GET(hdr1->usedbytes, ARCH_CONVERT) + + INT_GET(hdr2->usedbytes, ARCH_CONVERT) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, NULL); + half /= 2; + lastdelta = state->blocksize; + entry = &leaf1->entries[0]; + for (count = index = 0; count < max; entry++, index++, count++) { + +#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) + /* + * The new entry is in the first block, account for it. + */ + if (count == blk1->index) { + tmp = totallen + sizeof(*entry) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, + NULL); + if (XFS_ATTR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_ATTR_ABS(half - tmp); + totallen = tmp; + foundit = 1; + } + + /* + * Wrap around into the second block if necessary. + */ + if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { + leaf1 = leaf2; + entry = &leaf1->entries[0]; + index = 0; + } + + /* + * Figure out if next leaf entry would be too much. + */ + tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, + index); + if (XFS_ATTR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_ATTR_ABS(half - tmp); + totallen = tmp; +#undef XFS_ATTR_ABS + } + + /* + * Calculate the number of usedbytes that will end up in lower block. + * If new entry not in lower block, fix up the count. + */ + totallen -= count * sizeof(*entry); + if (foundit) { + totallen -= sizeof(*entry) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, + NULL); + } + + *countarg = count; + *usedbytesarg = totallen; + return(foundit); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + * + * GROT: allow for INCOMPLETE entries in calculation. + */ +int +xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_attr_leafblock_t *leaf; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, bytes, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + leaf = (xfs_attr_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = sizeof(xfs_attr_leaf_hdr_t) + + count * sizeof(xfs_attr_leaf_entry_t) + + INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + if (bytes > (state->blocksize >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = (!INT_ISZERO(info->forw, ARCH_CONVERT)); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink an attribute list over time. + */ + /* start with smaller blk num */ + forward = (INT_GET(info->forw, ARCH_CONVERT) + < INT_GET(info->back, ARCH_CONVERT)); + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + leaf = (xfs_attr_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize>>2); + bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + bytes -= count * sizeof(xfs_attr_leaf_entry_t); + bytes -= sizeof(xfs_attr_leaf_hdr_t); + xfs_da_brelse(state->args->trans, bp); + if (bytes >= 0) + break; /* fits with at least 25% to spare */ + } + if (i >= 2) { + *action = 0; + return(0); + } + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + } + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 1; + } + return(0); +} + +/* + * Remove a name from the leaf attribute list structure. + * + * Return 1 if leaf is less than 37% full, 0 if >= 37% full. + * If two leaves are 37% full, when combined they will leave 25% free. + */ +int +xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_map_t *map; + xfs_attr_leaf_entry_t *entry; + int before, after, smallest, entsize; + int tablesize, tmp, i; + xfs_mount_t *mp; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr = &leaf->hdr; + mp = args->trans->t_mountp; + ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) + && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT((args->index >= 0) + && (args->index < INT_GET(hdr->count, ARCH_CONVERT))); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) + >= ((INT_GET(hdr->count, ARCH_CONVERT) + * sizeof(*entry))+sizeof(*hdr))); + entry = &leaf->entries[args->index]; + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) + >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + + /* + * Scan through free region table: + * check for adjacency of free'd entry with an existing one, + * find smallest free region in case we need to replace it, + * adjust any map that borders the entry table, + */ + tablesize = INT_GET(hdr->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[0]; + tmp = INT_GET(map->size, ARCH_CONVERT); + before = after = -1; + smallest = XFS_ATTR_LEAF_MAPSIZE - 1; + entsize = xfs_attr_leaf_entsize(leaf, args->index); + for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { + INT_MOD(map->base, ARCH_CONVERT, + -sizeof(xfs_attr_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, + sizeof(xfs_attr_leaf_entry_t)); + } + + if ((INT_GET(map->base, ARCH_CONVERT) + + INT_GET(map->size, ARCH_CONVERT)) + == INT_GET(entry->nameidx, ARCH_CONVERT)) { + before = i; + } else if (INT_GET(map->base, ARCH_CONVERT) + == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { + after = i; + } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { + tmp = INT_GET(map->size, ARCH_CONVERT); + smallest = i; + } + } + + /* + * Coalesce adjacent freemap regions, + * or replace the smallest region. + */ + if ((before >= 0) || (after >= 0)) { + if ((before >= 0) && (after >= 0)) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + INT_MOD(map->size, ARCH_CONVERT, + INT_GET(hdr->freemap[after].size, + ARCH_CONVERT)); + INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT); + INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT); + } else if (before >= 0) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + } else { + map = &hdr->freemap[after]; + /* both on-disk, don't endian flip twice */ + map->base = entry->nameidx; + INT_MOD(map->size, ARCH_CONVERT, entsize); + } + } else { + /* + * Replace smallest region (if it is smaller than free'd entry) + */ + map = &hdr->freemap[smallest]; + if (INT_GET(map->size, ARCH_CONVERT) < entsize) { + INT_SET(map->base, ARCH_CONVERT, + INT_GET(entry->nameidx, ARCH_CONVERT)); + INT_SET(map->size, ARCH_CONVERT, entsize); + } + } + + /* + * Did we remove the first entry? + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) + == INT_GET(hdr->firstused, ARCH_CONVERT)) + smallest = 1; + else + smallest = 0; + + /* + * Compress the remaining entries and zero out the removed stuff. + */ + bzero(XFS_ATTR_LEAF_NAME(leaf, args->index), entsize); + INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), + entsize)); + + tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index) + * sizeof(xfs_attr_leaf_entry_t); + ovbcopy((char *)(entry+1), (char *)entry, tmp); + INT_MOD(hdr->count, ARCH_CONVERT, -1); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); + entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; + bzero((char *)entry, sizeof(xfs_attr_leaf_entry_t)); + + /* + * If we removed the first entry, re-find the first used byte + * in the name area. Note that if the entry was the "firstused", + * then we don't have a "hole" in our block resulting from + * removing the name. + */ + if (smallest) { + tmp = XFS_LBSIZE(mp); + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; + i >= 0; entry++, i--) { + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) + >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) + < XFS_LBSIZE(mp)); + if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) + tmp = INT_GET(entry->nameidx, ARCH_CONVERT); + } + INT_SET(hdr->firstused, ARCH_CONVERT, tmp); + if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) { + INT_SET(hdr->firstused, ARCH_CONVERT, + tmp - XFS_ATTR_LEAF_NAME_ALIGN); + } + } else { + hdr->holes = 1; /* mark as needing compaction */ + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + + /* + * Check if leaf is less than 50% full, caller may want to + * "join" the leaf with a sibling if so. + */ + tmp = sizeof(xfs_attr_leaf_hdr_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + tmp += INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + return(tmp < mp->m_attr_magicpct); /* leaf is < 37% full */ +} + +/* + * Move all the attribute list entries from drop_leaf into save_leaf. + */ +void +xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_attr_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; + xfs_attr_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; + xfs_mount_t *mp; + char *tmpbuffer; + + /* + * Set up environment. + */ + mp = state->mp; + ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(save_blk->magic == XFS_ATTR_LEAF_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + drop_hdr = &drop_leaf->hdr; + save_hdr = &save_leaf->hdr; + + /* + * Save last hashval from dying block for later Btree fixup. + */ + drop_blk->hashval = + INT_GET(drop_leaf->entries[INT_GET(drop_leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT); + + /* + * Check if we need a temp buffer, or can we do it in place. + * Note that we don't check "leaf" for holes because we will + * always be dropping it, toosmall() decided that for us already. + */ + if (save_hdr->holes == 0) { + /* + * dest leaf has no holes, so we add there. May need + * to make some room in the entry array. + */ + if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, + INT_GET(save_hdr->count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + } + } else { + /* + * Destination has holes, so we make a temporary copy + * of the leaf and add them both to that. + */ + tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bzero(tmpbuffer, state->blocksize); + tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer; + tmp_hdr = &tmp_leaf->hdr; + tmp_hdr->info = save_hdr->info; /* struct copy */ + INT_ZERO(tmp_hdr->count, ARCH_CONVERT); + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); + if (INT_ISZERO(tmp_hdr->firstused, ARCH_CONVERT)) { + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, + state->blocksize - XFS_ATTR_LEAF_NAME_ALIGN); + } + INT_ZERO(tmp_hdr->usedbytes, ARCH_CONVERT); + if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, + INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(save_hdr->count, ARCH_CONVERT), + mp); + } else { + xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, 0, + (int)INT_GET(save_hdr->count, ARCH_CONVERT), + mp); + xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, + INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + } + bcopy((char *)tmp_leaf, (char *)save_leaf, state->blocksize); + kmem_free(tmpbuffer, state->blocksize); + } + + xfs_da_log_buf(state->args->trans, save_blk->bp, 0, + state->blocksize - 1); + + /* + * Copy out last hashval in each block for B-tree code. + */ + save_blk->hashval = + INT_GET(save_leaf->entries[INT_GET(save_leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Look up a name in a leaf attribute list structure. + * This is the internal routine, it uses the caller's buffer. + * + * Note that duplicate keys are allowed, but only check within the + * current leaf node. The Btree code must check in adjacent leaf nodes. + * + * Return in args->index the index into the entry[] array of either + * the found entry, or where the entry should have been (insert before + * that entry). + * + * Don't change the args->value unless we find the attribute. + */ +int +xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + int probe, span; + xfs_dahash_t hashval; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) + < (XFS_LBSIZE(args->dp->i_mount)/8)); + + /* + * Binary search. (note: small blocks will skip this loop) + */ + hashval = args->hashval; + probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2; + for (entry = &leaf->entries[probe]; span > 4; + entry = &leaf->entries[probe]) { + span /= 2; + if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && \ + ((INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) + || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)))); + ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) + == hashval)); + + /* + * Since we may have duplicate hashval's, find the first matching + * hashval in the leaf. + */ + while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) + >= hashval)) { + entry--; + probe--; + } + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) { + entry++; + probe++; + } + if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) + || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) { + args->index = probe; + return(XFS_ERROR(ENOATTR)); + } + + /* + * Duplicate keys may be present, so search all of them for a match. + */ + for ( ; (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval); + entry++, probe++) { +/* + * GROT: Add code to remove incomplete entries. + */ + /* + * If we are looking for INCOMPLETE entries, show only those. + * If we are looking for complete entries, show only those. + */ + if ((args->flags & XFS_ATTR_INCOMPLETE) != + (entry->flags & XFS_ATTR_INCOMPLETE)) { + continue; + } + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe); + if (name_loc->namelen != args->namelen) + continue; + if (bcmp(args->name, (char *)name_loc->nameval, + args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((entry->flags & XFS_ATTR_ROOT) != 0)) + continue; + args->index = probe; + return(XFS_ERROR(EEXIST)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, probe); + if (name_rmt->namelen != args->namelen) + continue; + if (bcmp(args->name, (char *)name_rmt->name, + args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((entry->flags & XFS_ATTR_ROOT) != 0)) + continue; + args->index = probe; + args->rmtblkno + = INT_GET(name_rmt->valueblk, ARCH_CONVERT); + args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, + INT_GET(name_rmt->valuelen, + ARCH_CONVERT)); + return(XFS_ERROR(EEXIST)); + } + } + args->index = probe; + return(XFS_ERROR(ENOATTR)); +} + +/* + * Get the value associated with an attribute name from a leaf attribute + * list structure. + */ +int +xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + int valuelen; + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) + < (XFS_LBSIZE(args->dp->i_mount)/8)); + ASSERT(args->index < ((int)INT_GET(leaf->hdr.count, ARCH_CONVERT))); + + entry = &leaf->entries[args->index]; + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); + ASSERT(name_loc->namelen == args->namelen); + ASSERT(bcmp(args->name, name_loc->nameval, args->namelen) == 0); + valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT); + if (args->flags & ATTR_KERNOVAL) { + args->valuelen = valuelen; + return(0); + } + if (args->valuelen < valuelen) { + args->valuelen = valuelen; + return(XFS_ERROR(ERANGE)); + } + args->valuelen = valuelen; + bcopy(&name_loc->nameval[args->namelen], args->value, valuelen); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + ASSERT(name_rmt->namelen == args->namelen); + ASSERT(bcmp(args->name, name_rmt->name, args->namelen) == 0); + valuelen = INT_GET(name_rmt->valuelen, ARCH_CONVERT); + args->rmtblkno = INT_GET(name_rmt->valueblk, ARCH_CONVERT); + args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, valuelen); + if (args->flags & ATTR_KERNOVAL) { + args->valuelen = valuelen; + return(0); + } + if (args->valuelen < valuelen) { + args->valuelen = valuelen; + return(XFS_ERROR(ERANGE)); + } + args->valuelen = valuelen; + } + return(0); +} + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Move the indicated entries from one leaf to another. + * NOTE: this routine modifies both source and destination leaves. + */ +/*ARGSUSED*/ +STATIC void +xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s, + xfs_attr_leafblock_t *leaf_d, int start_d, + int count, xfs_mount_t *mp) +{ + xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; + xfs_attr_leaf_entry_t *entry_s, *entry_d; + int desti, tmp, i; + + /* + * Check for nothing to do. + */ + if (count == 0) + return; + + /* + * Set up environment. + */ + ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) + && (INT_GET(hdr_s->count, ARCH_CONVERT) + < (XFS_LBSIZE(mp)/8))); + ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_s->count, ARCH_CONVERT) + * sizeof(*entry_s))+sizeof(*hdr_s))); + ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(*entry_d))+sizeof(*hdr_d))); + + ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); + ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); + ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); + + /* + * Move the entries in the destination leaf up to make a hole? + */ + if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; + tmp *= sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_d->entries[start_d]; + entry_d = &leaf_d->entries[start_d + count]; + ovbcopy((char *)entry_s, (char *)entry_d, tmp); + } + + /* + * Copy all entry's in the same (sorted) order, + * but allocate attribute info packed and in sequence. + */ + entry_s = &leaf_s->entries[start_s]; + entry_d = &leaf_d->entries[start_d]; + desti = start_d; + for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) { + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); + tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i); +#ifdef GROT + /* + * Code to drop INCOMPLETE entries. Difficult to use as we + * may also need to change the insertion index. Code turned + * off for 6.2, should be revisited later. + */ + if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ + bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp); + INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + entry_d--; /* to compensate for ++ in loop hdr */ + desti--; + if ((start_s + i) < offset) + result++; /* insertion index adjustment */ + } else { +#endif /* GROT */ + INT_MOD(hdr_d->firstused, ARCH_CONVERT, -tmp); + /* both on-disk, don't endian flip twice */ + entry_d->hashval = entry_s->hashval; + /* both on-disk, don't endian flip twice */ + entry_d->nameidx = hdr_d->firstused; + entry_d->flags = entry_s->flags; + ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp + <= XFS_LBSIZE(mp)); + ovbcopy(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), + XFS_ATTR_LEAF_NAME(leaf_d, desti), tmp); + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp + <= XFS_LBSIZE(mp)); + bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp); + INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); + INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + INT_MOD(hdr_d->count, ARCH_CONVERT, 1); + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); +#ifdef GROT + } +#endif /* GROT */ + } + + /* + * Zero out the entries we just copied. + */ + if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { + tmp = count * sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[start_s]; + ASSERT(((char *)entry_s + tmp) <= + ((char *)leaf_s + XFS_LBSIZE(mp))); + bzero((char *)entry_s, tmp); + } else { + /* + * Move the remaining entries down to fill the hole, + * then zero the entries at the top. + */ + tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; + tmp *= sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[start_s + count]; + entry_d = &leaf_s->entries[start_s]; + ovbcopy((char *)entry_s, (char *)entry_d, tmp); + + tmp = count * sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[INT_GET(hdr_s->count, + ARCH_CONVERT)]; + ASSERT(((char *)entry_s + tmp) <= + ((char *)leaf_s + XFS_LBSIZE(mp))); + bzero((char *)entry_s, tmp); + } + + /* + * Fill in the freemap information + */ + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, + INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr_d->firstused, ARCH_CONVERT) + - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + INT_ZERO(hdr_d->freemap[1].base, ARCH_CONVERT); + INT_ZERO(hdr_d->freemap[2].base, ARCH_CONVERT); + INT_ZERO(hdr_d->freemap[1].size, ARCH_CONVERT); + INT_ZERO(hdr_d->freemap[2].size, ARCH_CONVERT); + hdr_s->holes = 1; /* leaf may not be compact */ +} + +/* + * Compare two leaf blocks "order". + * Return 0 unless leaf2 should go before leaf1. + */ +int +xfs_attr_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC) && + (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC)); + if ( (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) + && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) + && ( (INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) + || (INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT))) ) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from a leaf block. + */ +xfs_dahash_t +xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_attr_leafblock_t *leaf; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) + return(0); + return(INT_GET(leaf->entries[INT_GET(leaf->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); +} + +/* + * Calculate the number of bytes used to store the indicated attribute + * (whether local or remote only calculate bytes in this block). + */ +int +xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) +{ + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + int size; + + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + if (leaf->entries[index].flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, index); + size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(name_loc->namelen, + INT_GET(name_loc->valuelen, + ARCH_CONVERT)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, index); + size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(name_rmt->namelen); + } + return(size); +} + +/* + * Calculate the number of bytes that would be required to store the new + * attribute (whether local or remote only calculate bytes in this block). + * This routine decides as a side effect whether the attribute will be + * a "local" or a "remote" attribute. + */ +int +xfs_attr_leaf_newentsize(xfs_da_args_t *args, int blocksize, int *local) +{ + int size; + + size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(args->namelen, args->valuelen); + if (size < XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(blocksize)) { + if (local) { + *local = 1; + } + } else { + size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(args->namelen); + if (local) { + *local = 0; + } + } + return(size); +} + +/* + * Copy out attribute list entries for attr_list(), for leaf attribute lists. + */ +int +xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) +{ + attrlist_cursor_kern_t *cursor; + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + int retval, i; + + ASSERT(bp != NULL); + leaf = bp->data; + cursor = context->cursor; + cursor->initted = 1; + + xfs_attr_trace_l_cl("blk start", context, leaf); + + /* + * Re-find our place in the leaf block if this is a new syscall. + */ + if (context->resynch) { + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + entry++, i++) { + if (INT_GET(entry->hashval, ARCH_CONVERT) + == cursor->hashval) { + if (cursor->offset == context->dupcnt) { + context->dupcnt = 0; + break; + } + context->dupcnt++; + } else if (INT_GET(entry->hashval, ARCH_CONVERT) + > cursor->hashval) { + context->dupcnt = 0; + break; + } + } + if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) { + xfs_attr_trace_l_c("not found", context); + return(0); + } + } else { + entry = &leaf->entries[0]; + i = 0; + } + context->resynch = 0; + + /* + * We have found our place, start copying out the new attributes. + */ + retval = 0; + for ( ; (i < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + && (retval == 0); entry++, i++) { + int ns = (entry->flags & XFS_ATTR_ROOT)? ROOT_NAMES:USER_NAMES; + + if (INT_GET(entry->hashval, ARCH_CONVERT) != cursor->hashval) { + cursor->hashval = INT_GET(entry->hashval, ARCH_CONVERT); + cursor->offset = 0; + } + + if (entry->flags & XFS_ATTR_INCOMPLETE) + continue; /* skip incomplete entries */ + if (((context->flags & ATTR_ROOT) != 0) != + ((entry->flags & XFS_ATTR_ROOT) != 0) && + !(context->flags & ATTR_KERNFULLS)) + continue; /* skip non-matching entries */ + + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); + if (context->flags & ATTR_KERNOVAL) { + ASSERT(context->flags & ATTR_KERNAMELS); + context->count += xfs_namespaces[ns].namelen + + (int)name_loc->namelen + 1; + } else { + retval = xfs_attr_put_listent(context, ns, + (char *)name_loc->nameval, + (int)name_loc->namelen, + (int)INT_GET(name_loc->valuelen, + ARCH_CONVERT)); + } + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); + if (context->flags & ATTR_KERNOVAL) { + ASSERT(context->flags & ATTR_KERNAMELS); + context->count += xfs_namespaces[ns].namelen + + (int)name_rmt->namelen + 1; + } else { + retval = xfs_attr_put_listent(context, ns, + (char *)name_rmt->name, + (int)name_rmt->namelen, + (int)INT_GET(name_rmt->valuelen, + ARCH_CONVERT)); + } + } + if (retval == 0) { + cursor->offset++; + } + } + xfs_attr_trace_l_cl("blk end", context, leaf); + return(retval); +} + +#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \ + (((struct attrlist_ent *) 0)->a_name - (char *) 0) +#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \ + ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \ + & ~(sizeof(u_int32_t)-1)) + +/* + * Format an attribute and copy it out to the user's buffer. + * Take care to check values and protect against them changing later, + * we may be reading them directly out of a user buffer. + */ +/*ARGSUSED*/ +int +xfs_attr_put_listent(xfs_attr_list_context_t *context, + int ns, char *name, int namelen, int valuelen) +{ + attrlist_ent_t *aep; + int arraytop; + + ASSERT(!(context->flags & ATTR_KERNOVAL)); + if (context->flags & ATTR_KERNAMELS) { + char *offset; + xattr_namespace_t *nsp; + + ASSERT(context->count >= 0); + + nsp = &xfs_namespaces[ns]; + arraytop = context->count + nsp->namelen + namelen+1; + if (arraytop > context->firstu) { + context->count = -1; /* insufficient space */ + return(1); + } + offset = (char *)context->alist + context->count; + strncpy(offset, nsp->name, nsp->namelen); /* namespace */ + offset += nsp->namelen; + strncpy(offset, name, namelen); /* real name */ + offset += namelen; + *offset = '\0'; + context->count += nsp->namelen + namelen + 1; + return(0); + } + + ASSERT(context->count >= 0); + ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); + ASSERT(context->firstu >= sizeof(*context->alist)); + ASSERT(context->firstu <= context->bufsize); + + arraytop = sizeof(*context->alist) + + context->count * sizeof(context->alist->al_offset[0]); + context->firstu -= ATTR_ENTSIZE(namelen); + if (context->firstu < arraytop) { + xfs_attr_trace_l_c("buffer full", context); + context->alist->al_more = 1; + return(1); + } + + aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); + aep->a_valuelen = valuelen; + bcopy(name, aep->a_name, namelen); + aep->a_name[ namelen ] = 0; + context->alist->al_offset[ context->count++ ] = context->firstu; + context->alist->al_count = context->count; + xfs_attr_trace_l_c("add", context); + return(0); +} + +/*======================================================================== + * Manage the INCOMPLETE flag in a leaf entry + *========================================================================*/ + +/* + * Clear the INCOMPLETE flag on an entry in a leaf block. + */ +int +xfs_attr_leaf_clearflag(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_dabuf_t *bp; + int error; +#ifdef DEBUG + xfs_attr_leaf_name_local_t *name_loc; + int namelen; + char *name; +#endif /* DEBUG */ + + /* + * Set up the operation. + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp != NULL); + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT)); + ASSERT(args->index >= 0); + entry = &leaf->entries[ args->index ]; + ASSERT(entry->flags & XFS_ATTR_INCOMPLETE); + +#ifdef DEBUG + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); + namelen = name_loc->namelen; + name = (char *)name_loc->nameval; + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + namelen = name_rmt->namelen; + name = (char *)name_rmt->name; + } + ASSERT(INT_GET(entry->hashval, ARCH_CONVERT) == args->hashval); + ASSERT(namelen == args->namelen); + ASSERT(bcmp(name, args->name, namelen) == 0); +#endif /* DEBUG */ + + entry->flags &= ~XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + + if (args->rmtblkno) { + ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0); + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno); + INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); + } + xfs_da_buf_done(bp); + + /* + * Commit the flag value change and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, args->dp); + + return(error); +} + +/* + * Set the INCOMPLETE flag on an entry in a leaf block. + */ +int +xfs_attr_leaf_setflag(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_dabuf_t *bp; + int error; + + /* + * Set up the operation. + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp != NULL); + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT)); + ASSERT(args->index >= 0); + entry = &leaf->entries[ args->index ]; + + ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0); + entry->flags |= XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + if ((entry->flags & XFS_ATTR_LOCAL) == 0) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + INT_ZERO(name_rmt->valueblk, ARCH_CONVERT); + INT_ZERO(name_rmt->valuelen, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); + } + xfs_da_buf_done(bp); + + /* + * Commit the flag value change and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, args->dp); + + return(error); +} + +/* + * In a single transaction, clear the INCOMPLETE flag on the leaf entry + * given by args->blkno/index and set the INCOMPLETE flag on the leaf + * entry given by args->blkno2/index2. + * + * Note that they could be in different blocks, or in the same block. + */ +int +xfs_attr_leaf_flipflags(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_entry_t *entry1, *entry2; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_dabuf_t *bp1, *bp2; + int error; +#ifdef DEBUG + xfs_attr_leaf_name_local_t *name_loc; + int namelen1, namelen2; + char *name1, *name2; +#endif /* DEBUG */ + + /* + * Read the block containing the "old" attr + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp1, + XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp1 != NULL); + + /* + * Read the block containing the "new" attr, if it is different + */ + if (args->blkno2 != args->blkno) { + error = xfs_da_read_buf(args->trans, args->dp, args->blkno2, + -1, &bp2, XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp2 != NULL); + } else { + bp2 = bp1; + } + + leaf1 = bp1->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index < INT_GET(leaf1->hdr.count, ARCH_CONVERT)); + ASSERT(args->index >= 0); + entry1 = &leaf1->entries[ args->index ]; + + leaf2 = bp2->data; + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index2 < INT_GET(leaf2->hdr.count, ARCH_CONVERT)); + ASSERT(args->index2 >= 0); + entry2 = &leaf2->entries[ args->index2 ]; + +#ifdef DEBUG + if (entry1->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf1, args->index); + namelen1 = name_loc->namelen; + name1 = (char *)name_loc->nameval; + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index); + namelen1 = name_rmt->namelen; + name1 = (char *)name_rmt->name; + } + if (entry2->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf2, args->index2); + namelen2 = name_loc->namelen; + name2 = (char *)name_loc->nameval; + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2); + namelen2 = name_rmt->namelen; + name2 = (char *)name_rmt->name; + } + ASSERT(INT_GET(entry1->hashval, ARCH_CONVERT) == INT_GET(entry2->hashval, ARCH_CONVERT)); + ASSERT(namelen1 == namelen2); + ASSERT(bcmp(name1, name2, namelen1) == 0); +#endif /* DEBUG */ + + ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE); + ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0); + + entry1->flags &= ~XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp1, + XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1))); + if (args->rmtblkno) { + ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0); + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno); + INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen); + xfs_da_log_buf(args->trans, bp1, + XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt))); + } + + entry2->flags |= XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp2, + XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2))); + if ((entry2->flags & XFS_ATTR_LOCAL) == 0) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2); + INT_ZERO(name_rmt->valueblk, ARCH_CONVERT); + INT_ZERO(name_rmt->valuelen, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp2, + XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt))); + } + xfs_da_buf_done(bp1); + if (bp1 != bp2) + xfs_da_buf_done(bp2); + + /* + * Commit the flag value change and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, args->dp); + + return(error); +} + +/*======================================================================== + * Indiscriminately delete the entire attribute fork + *========================================================================*/ + +/* + * Recurse (gasp!) through the attribute nodes until we find leaves. + * We're doing a depth-first traversal in order to invalidate everything. + */ +int +xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp) +{ + xfs_da_blkinfo_t *info; + xfs_daddr_t blkno; + xfs_dabuf_t *bp; + int error; + + /* + * Read block 0 to see what we have to work with. + * We only get here if we have extents, since we remove + * the extents in reverse order the extent containing + * block 0 must still be there. + */ + error = xfs_da_read_buf(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK); + if (error) + return(error); + blkno = xfs_da_blkno(bp); + + /* + * Invalidate the tree, even if the "tree" is only a single leaf block. + * This is a depth-first traversal! + */ + info = bp->data; + if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + error = xfs_attr_node_inactive(trans, dp, bp, 1); + } else if (INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { + error = xfs_attr_leaf_inactive(trans, dp, bp); + } else { + error = XFS_ERROR(EIO); + xfs_da_brelse(*trans, bp); + } + if (error) + return(error); + + /* + * Invalidate the incore copy of the root block. + */ + error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK); + if (error) + return(error); + xfs_da_binval(*trans, bp); /* remove from cache */ + /* + * Commit the invalidate and start the next transaction. + */ + error = xfs_attr_rolltrans(trans, dp); + + return (error); +} + +/* + * Recurse (gasp!) through the attribute nodes until we find leaves. + * We're doing a depth-first traversal in order to invalidate everything. + */ +int +xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, + int level) +{ + xfs_da_blkinfo_t *info; + xfs_da_intnode_t *node; + xfs_dablk_t child_fsb; + xfs_daddr_t parent_blkno, child_blkno; + int error, count, i; + xfs_dabuf_t *child_bp; + + /* + * Since this code is recursive (gasp!) we must protect ourselves. + */ + if (level > XFS_DA_NODE_MAXDEPTH) { + xfs_da_brelse(*trans, bp); /* no locks for later trans */ + return(XFS_ERROR(EIO)); + } + + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) + == XFS_DA_NODE_MAGIC); + parent_blkno = xfs_da_blkno(bp); /* save for re-read later */ + count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (!count) { + xfs_da_brelse(*trans, bp); + return(0); + } + child_fsb = INT_GET(node->btree[0].before, ARCH_CONVERT); + xfs_da_brelse(*trans, bp); /* no locks for later trans */ + + /* + * If this is the node level just above the leaves, simply loop + * over the leaves removing all of them. If this is higher up + * in the tree, recurse downward. + */ + for (i = 0; i < count; i++) { + /* + * Read the subsidiary block to see what we have to work with. + * Don't do this in a transaction. This is a depth-first + * traversal of the tree so we may deal with many blocks + * before we come back to this one. + */ + error = xfs_da_read_buf(*trans, dp, child_fsb, -2, &child_bp, + XFS_ATTR_FORK); + if (error) + return(error); + if (child_bp) { + /* save for re-read later */ + child_blkno = xfs_da_blkno(child_bp); + + /* + * Invalidate the subtree, however we have to. + */ + info = child_bp->data; + if (INT_GET(info->magic, ARCH_CONVERT) + == XFS_DA_NODE_MAGIC) { + error = xfs_attr_node_inactive(trans, dp, + child_bp, level+1); + } else if (INT_GET(info->magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC) { + error = xfs_attr_leaf_inactive(trans, dp, + child_bp); + } else { + error = XFS_ERROR(EIO); + xfs_da_brelse(*trans, child_bp); + } + if (error) + return(error); + + /* + * Remove the subsidiary block from the cache + * and from the log. + */ + error = xfs_da_get_buf(*trans, dp, 0, child_blkno, + &child_bp, XFS_ATTR_FORK); + if (error) + return(error); + xfs_da_binval(*trans, child_bp); + } + + /* + * If we're not done, re-read the parent to get the next + * child block number. + */ + if ((i+1) < count) { + error = xfs_da_read_buf(*trans, dp, 0, parent_blkno, + &bp, XFS_ATTR_FORK); + if (error) + return(error); + child_fsb = INT_GET(node->btree[i+1].before, ARCH_CONVERT); + xfs_da_brelse(*trans, bp); + } + /* + * Atomically commit the whole invalidate stuff. + */ + if ((error = xfs_attr_rolltrans(trans, dp))) + return (error); + } + + return(0); +} + +/* + * Invalidate all of the "remote" value regions pointed to by a particular + * leaf block. + * Note that we must release the lock on the buffer so that we are not + * caught holding something that the logging code wants to flush to disk. + */ +int +xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_attr_inactive_list_t *list, *lp; + int error, count, size, tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + + /* + * Count the number of "remote" value extents. + */ + count = 0; + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if ( INT_GET(entry->nameidx, ARCH_CONVERT) + && ((entry->flags & XFS_ATTR_LOCAL) == 0)) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); + if (!INT_ISZERO(name_rmt->valueblk, ARCH_CONVERT)) + count++; + } + } + + /* + * If there are no "remote" values, we're done. + */ + if (count == 0) { + xfs_da_brelse(*trans, bp); + return(0); + } + + /* + * Allocate storage for a list of all the "remote" value extents. + */ + size = count * sizeof(xfs_attr_inactive_list_t); + list = (xfs_attr_inactive_list_t *)kmem_alloc(size, KM_SLEEP); + + /* + * Identify each of the "remote" value extents. + */ + lp = list; + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if ( INT_GET(entry->nameidx, ARCH_CONVERT) + && ((entry->flags & XFS_ATTR_LOCAL) == 0)) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); + if (!INT_ISZERO(name_rmt->valueblk, ARCH_CONVERT)) { + /* both on-disk, don't endian flip twice */ + lp->valueblk = name_rmt->valueblk; + INT_SET(lp->valuelen, ARCH_CONVERT, + XFS_B_TO_FSB(dp->i_mount, + INT_GET(name_rmt->valuelen, + ARCH_CONVERT))); + lp++; + } + } + } + xfs_da_brelse(*trans, bp); /* unlock for trans. in freextent() */ + + /* + * Invalidate each of the "remote" value extents. + */ + error = 0; + for (lp = list, i = 0; i < count; i++, lp++) { + tmp = xfs_attr_leaf_freextent(trans, dp, + INT_GET(lp->valueblk, + ARCH_CONVERT), + INT_GET(lp->valuelen, + ARCH_CONVERT)); + if (error == 0) + error = tmp; /* save only the 1st errno */ + } + + kmem_free((xfs_caddr_t)list, size); + return(error); +} + +/* + * Look at all the extents for this logical region, + * invalidate any buffers that are incore/in transactions. + */ +int +xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, + xfs_dablk_t blkno, int blkcnt) +{ + xfs_bmbt_irec_t map; + xfs_dablk_t tblkno; + int tblkcnt, dblkcnt, nmap, error; + xfs_daddr_t dblkno; + xfs_buf_t *bp; + + /* + * Roll through the "value", invalidating the attribute value's + * blocks. + */ + tblkno = blkno; + tblkcnt = blkcnt; + while (tblkcnt > 0) { + /* + * Try to remember where we decided to put the value. + */ + nmap = 1; + error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + NULL, 0, &map, &nmap, NULL); + if (error) { + return(error); + } + ASSERT(nmap == 1); + ASSERT(map.br_startblock != DELAYSTARTBLOCK); + + /* + * If it's a hole, these are already unmapped + * so there's nothing to invalidate. + */ + if (map.br_startblock != HOLESTARTBLOCK) { + + dblkno = XFS_FSB_TO_DADDR(dp->i_mount, + map.br_startblock); + dblkcnt = XFS_FSB_TO_BB(dp->i_mount, + map.br_blockcount); + bp = xfs_trans_get_buf(*trans, + dp->i_mount->m_ddev_targp, + dblkno, dblkcnt, 0); + xfs_trans_binval(*trans, bp); + /* + * Roll to next transaction. + */ + if ((error = xfs_attr_rolltrans(trans, dp))) + return (error); + } + + tblkno += map.br_blockcount; + tblkcnt -= map.br_blockcount; + } + + return(0); +} + + +/* + * Roll from one trans in the sequence of PERMANENT transactions to the next. + */ +int +xfs_attr_rolltrans(xfs_trans_t **transp, xfs_inode_t *dp) +{ + xfs_trans_t *trans; + unsigned int logres, count; + int error; + + /* + * Ensure that the inode is always logged. + */ + trans = *transp; + xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); + + /* + * Copy the critical parameters from one trans to the next. + */ + logres = trans->t_log_res; + count = trans->t_log_count; + *transp = xfs_trans_dup(trans); + + /* + * Commit the current transaction. + * If this commit failed, then it'd just unlock those items that + * are not marked ihold. That also means that a filesystem shutdown + * is in progress. The caller takes the responsibility to cancel + * the duplicate transaction that gets returned. + */ + if ((error = xfs_trans_commit(trans, 0, NULL))) + return (error); + + trans = *transp; + + /* + * Reserve space in the log for th next transaction. + * This also pushes items in the "AIL", the list of logged items, + * out to disk if they are taking up space at the tail of the log + * that we want to use. This requires that either nothing be locked + * across this call, or that anything that is locked be logged in + * the prior and the next transactions. + */ + error = xfs_trans_reserve(trans, 0, logres, 0, + XFS_TRANS_PERM_LOG_RES, count); + /* + * Ensure that the inode is in the new transaction and locked. + */ + if (!error) { + xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(trans, dp); + } + return (error); + +} diff -Nur linux-2.4.19/fs/xfs/xfs_attr_leaf.h linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_leaf.h --- linux-2.4.19/fs/xfs/xfs_attr_leaf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_leaf.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_LEAF_H__ +#define __XFS_ATTR_LEAF_H__ + +/* + * Attribute storage layout, internal structure, access macros, etc. + * + * Attribute lists are structured around Btrees where all the data + * elements are in the leaf nodes. Attribute names are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of an attribute name may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + */ + +struct attrlist; +struct attrlist_cursor_kern; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_inode; +struct xfs_trans; + +/*======================================================================== + * Attribute structure when equal to XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This is the structure of the leaf nodes in the Btree. + * + * Struct leaf_entry's are packed from the top. Name/values grow from the + * bottom but are not packed. The freemap contains run-length-encoded entries + * for the free bytes after the leaf_entry's, but only the N largest such, + * smaller runs are dropped. When the freemap doesn't show enough space + * for an allocation, we compact the name/value area and try again. If we + * still don't have enough space, then we have to split the block. The + * name/value structs (both local and remote versions) must be 32bit aligned. + * + * Since we have duplicate hash keys, for each key that matches, compare + * the actual name string. The root and intermediate node search always + * takes the first-in-the-block key match found, so we should only have + * to work "forw"ard. If none matches, continue with the "forw"ard leaf + * nodes until the hash key changes or the attribute name is found. + * + * We store the fact that an attribute is a ROOT versus USER attribute in + * the leaf_entry. The namespaces are independent only because we also look + * at the root/user bit when we are looking for a matching attribute name. + * + * We also store a "incomplete" bit in the leaf_entry. It shows that an + * attribute is in the middle of being created and should not be shown to + * the user if we crash during the time that the bit is set. We clear the + * bit when we have finished setting up the attribute. We do this because + * we cannot create some large attributes inside a single transaction, and we + * need some indication that we weren't finished if we crash in the middle. + */ +#define XFS_ATTR_LEAF_MAPSIZE 3 /* how many freespace slots */ + +typedef struct xfs_attr_leafblock { + struct xfs_attr_leaf_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active leaf_entry's */ + __uint16_t usedbytes; /* num bytes of names/values stored */ + __uint16_t firstused; /* first used byte in name area */ + __uint8_t holes; /* != 0 if blk needs compaction */ + __uint8_t pad1; + struct xfs_attr_leaf_map { /* RLE map of free bytes */ + __uint16_t base; /* base of free region */ + __uint16_t size; /* length of free region */ + } freemap[XFS_ATTR_LEAF_MAPSIZE]; /* N largest free regions */ + } hdr; + struct xfs_attr_leaf_entry { /* sorted on key, not name */ + xfs_dahash_t hashval; /* hash value of name */ + __uint16_t nameidx; /* index into buffer of name/value */ + __uint8_t flags; /* LOCAL, ROOT and INCOMPLETE flags */ + __uint8_t pad2; /* unused pad byte */ + } entries[1]; /* variable sized array */ + struct xfs_attr_leaf_name_local { + __uint16_t valuelen; /* number of bytes in value */ + __uint8_t namelen; /* length of name bytes */ + __uint8_t nameval[1]; /* name/value bytes */ + } namelist; /* grows from bottom of buf */ + struct xfs_attr_leaf_name_remote { + xfs_dablk_t valueblk; /* block number of value bytes */ + __uint32_t valuelen; /* number of bytes in value */ + __uint8_t namelen; /* length of name bytes */ + __uint8_t name[1]; /* name bytes */ + } valuelist; /* grows from bottom of buf */ +} xfs_attr_leafblock_t; +typedef struct xfs_attr_leaf_hdr xfs_attr_leaf_hdr_t; +typedef struct xfs_attr_leaf_map xfs_attr_leaf_map_t; +typedef struct xfs_attr_leaf_entry xfs_attr_leaf_entry_t; +typedef struct xfs_attr_leaf_name_local xfs_attr_leaf_name_local_t; +typedef struct xfs_attr_leaf_name_remote xfs_attr_leaf_name_remote_t; + +/* + * Flags used in the leaf_entry[i].flags field. + * NOTE: the INCOMPLETE bit must not collide with the flags bits specified + * on the system call, they are "or"ed together for various operations. + */ +#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ +#define XFS_ATTR_ROOT_BIT 1 /* limit access to attr to userid 0 */ +#define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ +#define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT) +#define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT) +#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT) + +/* + * Alignment for namelist and valuelist entries (since they are mixed + * there can be only one alignment value) + */ +#define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t)) + +/* + * Cast typed pointers for "local" and "remote" name/value structs. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME_REMOTE) +xfs_attr_leaf_name_remote_t * +xfs_attr_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME_REMOTE(leafp,idx) \ + xfs_attr_leaf_name_remote(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME_REMOTE(leafp,idx) /* remote name struct ptr */ \ + ((xfs_attr_leaf_name_remote_t *) \ + &((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME_LOCAL) +xfs_attr_leaf_name_local_t * +xfs_attr_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx) \ + xfs_attr_leaf_name_local(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx) /* local name struct ptr */ \ + ((xfs_attr_leaf_name_local_t *) \ + &((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME) +char *xfs_attr_leaf_name(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME(leafp,idx) xfs_attr_leaf_name(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME(leafp,idx) /* generic name struct ptr */ \ + (&((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif + +/* + * Calculate total bytes used (including trailing pad for alignment) for + * a "local" name/value structure, a "remote" name/value structure, and + * a pointer which might be either. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_REMOTE) +int xfs_attr_leaf_entsize_remote(int nlen); +#define XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen) \ + xfs_attr_leaf_entsize_remote(nlen) +#else +#define XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen) /* space for remote struct */ \ + (((uint)sizeof(xfs_attr_leaf_name_remote_t) - 1 + (nlen) + \ + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL) +int xfs_attr_leaf_entsize_local(int nlen, int vlen); +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen,vlen) \ + xfs_attr_leaf_entsize_local(nlen,vlen) +#else +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen,vlen) /* space for local struct */ \ + (((uint)sizeof(xfs_attr_leaf_name_local_t) - 1 + (nlen) + (vlen) + \ + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX) +int xfs_attr_leaf_entsize_local_max(int bsize); +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize) \ + xfs_attr_leaf_entsize_local_max(bsize) +#else +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize) /* max local struct size */ \ + (((bsize) >> 1) + ((bsize) >> 2)) +#endif + + +/*======================================================================== + * Structure used to pass context around among the routines. + *========================================================================*/ + +typedef struct xfs_attr_list_context { + struct xfs_inode *dp; /* inode */ + struct attrlist_cursor_kern *cursor;/* position in list */ + struct attrlist *alist; /* output buffer */ + int count; /* num used entries */ + int dupcnt; /* count dup hashvals seen */ + int bufsize;/* total buffer size */ + int firstu; /* first used byte in buffer */ + int flags; /* from VOP call */ + int resynch;/* T/F: resynch with cursor */ +} xfs_attr_list_context_t; + +/* + * Used to keep a list of "remote value" extents when unlinking an inode. + */ +typedef struct xfs_attr_inactive_list { + xfs_dablk_t valueblk; /* block number of value bytes */ + int valuelen; /* number of bytes in value */ +} xfs_attr_inactive_list_t; + + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when dirsize < XFS_LITINO(mp). + */ +int xfs_attr_shortform_create(struct xfs_da_args *args); +int xfs_attr_shortform_add(struct xfs_da_args *add); +int xfs_attr_shortform_lookup(struct xfs_da_args *args); +int xfs_attr_shortform_getvalue(struct xfs_da_args *args); +int xfs_attr_shortform_to_leaf(struct xfs_da_args *args); +int xfs_attr_shortform_remove(struct xfs_da_args *remove); +int xfs_attr_shortform_list(struct xfs_attr_list_context *context); +int xfs_attr_shortform_replace(struct xfs_da_args *args); +int xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp); + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +int xfs_attr_leaf_to_node(struct xfs_da_args *args); +int xfs_attr_leaf_to_shortform(struct xfs_dabuf *bp, + struct xfs_da_args *args); +int xfs_attr_leaf_clearflag(struct xfs_da_args *args); +int xfs_attr_leaf_setflag(struct xfs_da_args *args); +int xfs_attr_leaf_flipflags(xfs_da_args_t *args); + +/* + * Routines used for growing the Btree. + */ +int xfs_attr_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, + struct xfs_dabuf **bpp); +int xfs_attr_leaf_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); +int xfs_attr_leaf_lookup_int(struct xfs_dabuf *leaf, + struct xfs_da_args *args); +int xfs_attr_leaf_getvalue(struct xfs_dabuf *bp, struct xfs_da_args *args); +int xfs_attr_leaf_add(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args); +int xfs_attr_leaf_remove(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args); +int xfs_attr_leaf_list_int(struct xfs_dabuf *bp, + struct xfs_attr_list_context *context); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_attr_leaf_toosmall(struct xfs_da_state *state, int *retval); +void xfs_attr_leaf_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); +int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp); +int xfs_attr_node_inactive(struct xfs_trans **trans, struct xfs_inode *dp, + struct xfs_dabuf *bp, int level); +int xfs_attr_leaf_inactive(struct xfs_trans **trans, struct xfs_inode *dp, + struct xfs_dabuf *bp); +int xfs_attr_leaf_freextent(struct xfs_trans **trans, struct xfs_inode *dp, + xfs_dablk_t blkno, int blkcnt); + +/* + * Utility routines. + */ +xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_dabuf *bp, int *count); +int xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); +int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize, + int *local); +int xfs_attr_leaf_entsize(struct xfs_attr_leafblock *leaf, int index); +int xfs_attr_put_listent(struct xfs_attr_list_context *context, + int ns, char *name, int namelen, int valuelen); +int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp); + +#endif /* __XFS_ATTR_LEAF_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_attr_sf.h linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_sf.h --- linux-2.4.19/fs/xfs/xfs_attr_sf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_attr_sf.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_SF_H__ +#define __XFS_ATTR_SF_H__ + +/* + * Attribute storage when stored inside the inode. + * + * Small attribute lists are packed as tightly as possible so as + * to fit into the literal area of the inode. + */ + +struct xfs_inode; + +/* + * Entries are packed toward the top as tight as possible. + */ +typedef struct xfs_attr_shortform { + struct xfs_attr_sf_hdr { /* constant-structure header block */ + __uint16_t totsize; /* total bytes in shortform list */ + __uint8_t count; /* count of active entries */ + } hdr; + struct xfs_attr_sf_entry { + __uint8_t namelen; /* actual length of name (no NULL) */ + __uint8_t valuelen; /* actual length of value (no NULL) */ + __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ + __uint8_t nameval[1]; /* name & value bytes concatenated */ + } list[1]; /* variable sized array */ +} xfs_attr_shortform_t; +typedef struct xfs_attr_sf_hdr xfs_attr_sf_hdr_t; +typedef struct xfs_attr_sf_entry xfs_attr_sf_entry_t; + +/* + * We generate this then sort it, attr_list() must return things in hash-order. + */ +typedef struct xfs_attr_sf_sort { + __uint8_t entno; /* entry number in original list */ + __uint8_t namelen; /* length of name value (no null) */ + __uint8_t valuelen; /* length of value */ + __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ + xfs_dahash_t hash; /* this entry's hash value */ + char *name; /* name value, pointer into buffer */ +} xfs_attr_sf_sort_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_ENTSIZE_BYNAME) +int xfs_attr_sf_entsize_byname(int nlen, int vlen); +#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) \ + xfs_attr_sf_entsize_byname(nlen,vlen) +#else +#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ + ((int)sizeof(xfs_attr_sf_entry_t)-1 + (nlen)+(vlen)) +#endif +#define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ + ((1 << (NBBY*(int)sizeof(__uint8_t))) - 1) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_ENTSIZE) +int xfs_attr_sf_entsize(xfs_attr_sf_entry_t *sfep); +#define XFS_ATTR_SF_ENTSIZE(sfep) xfs_attr_sf_entsize(sfep) +#else +#define XFS_ATTR_SF_ENTSIZE(sfep) /* space an entry uses */ \ + ((int)sizeof(xfs_attr_sf_entry_t)-1 + (sfep)->namelen+(sfep)->valuelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_NEXTENTRY) +xfs_attr_sf_entry_t *xfs_attr_sf_nextentry(xfs_attr_sf_entry_t *sfep); +#define XFS_ATTR_SF_NEXTENTRY(sfep) xfs_attr_sf_nextentry(sfep) +#else +#define XFS_ATTR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ + ((xfs_attr_sf_entry_t *) \ + ((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_TOTSIZE) +int xfs_attr_sf_totsize(struct xfs_inode *dp); +#define XFS_ATTR_SF_TOTSIZE(dp) xfs_attr_sf_totsize(dp) +#else +#define XFS_ATTR_SF_TOTSIZE(dp) /* total space in use */ \ + (INT_GET(((xfs_attr_shortform_t *)((dp)->i_afp->if_u1.if_data))->hdr.totsize, ARCH_CONVERT)) +#endif + +#ifdef XFS_ALL_TRACE +#define XFS_ATTR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ATTR_TRACE +#endif + +/* + * Kernel tracing support for attribute lists + */ +struct xfs_attr_list_context; +struct xfs_da_intnode; +struct xfs_da_node_entry; +struct xfs_attr_leafblock; + +#define XFS_ATTR_TRACE_SIZE 4096 /* size of global trace buffer */ + +/* + * Trace record types. + */ +#define XFS_ATTR_KTRACE_L_C 1 /* context */ +#define XFS_ATTR_KTRACE_L_CN 2 /* context, node */ +#define XFS_ATTR_KTRACE_L_CB 3 /* context, btree */ +#define XFS_ATTR_KTRACE_L_CL 4 /* context, leaf */ + +#if defined(XFS_ATTR_TRACE) + +void xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context); +void xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, + struct xfs_da_intnode *node); +void xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, + struct xfs_da_node_entry *btree); +void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, + struct xfs_attr_leafblock *leaf); +void xfs_attr_trace_enter(int type, char *where, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11, + __psunsigned_t a12, __psunsigned_t a13, + __psunsigned_t a14, __psunsigned_t a15); +#else +#define xfs_attr_trace_l_c(w,c) +#define xfs_attr_trace_l_cn(w,c,n) +#define xfs_attr_trace_l_cb(w,c,b) +#define xfs_attr_trace_l_cl(w,c,l) +#endif /* XFS_ATTR_TRACE */ + +#endif /* __XFS_ATTR_SF_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_bit.c linux-2.4.19-sgi211r3/fs/xfs/xfs_bit.c --- linux-2.4.19/fs/xfs/xfs_bit.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_bit.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS bit manipulation routines, used in non-realtime code. + */ + +#include + +#ifndef HAVE_ARCH_HIGHBIT +/* + * Index of high bit number in byte, -1 for none set, 0..7 otherwise. + */ +const char xfs_highbit[256] = { + -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 18 .. 1f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 20 .. 27 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 28 .. 2f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 30 .. 37 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 38 .. 3f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 40 .. 47 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 48 .. 4f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 50 .. 57 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 58 .. 5f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 60 .. 67 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 68 .. 6f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 70 .. 77 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 78 .. 7f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 80 .. 87 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 88 .. 8f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 90 .. 97 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 98 .. 9f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a0 .. a7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a8 .. af */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b0 .. b7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b8 .. bf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c0 .. c7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c8 .. cf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d0 .. d7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d8 .. df */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e0 .. e7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e8 .. ef */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f0 .. f7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f8 .. ff */ +}; +#endif + +/* + * Count of bits set in byte, 0..8. + */ +static const char xfs_countbit[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, /* 00 .. 07 */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 08 .. 0f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 10 .. 17 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 18 .. 1f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 20 .. 27 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 28 .. 2f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 30 .. 37 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 38 .. 3f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 40 .. 47 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 48 .. 4f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 50 .. 57 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 58 .. 5f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 60 .. 67 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 68 .. 6f */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 70 .. 77 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* 78 .. 7f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 80 .. 87 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 88 .. 8f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 90 .. 97 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 98 .. 9f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* a0 .. a7 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* a8 .. af */ + 3, 4, 4, 5, 4, 5, 5, 6, /* b0 .. b7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* b8 .. bf */ + 2, 3, 3, 4, 3, 4, 4, 5, /* c0 .. c7 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* c8 .. cf */ + 3, 4, 4, 5, 4, 5, 5, 6, /* d0 .. d7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* d8 .. df */ + 3, 4, 4, 5, 4, 5, 5, 6, /* e0 .. e7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* e8 .. ef */ + 4, 5, 5, 6, 5, 6, 6, 7, /* f0 .. f7 */ + 5, 6, 6, 7, 6, 7, 7, 8, /* f8 .. ff */ +}; + +/* + * xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set. + */ +int inline +xfs_highbit32( + __uint32_t v) +{ +#ifdef HAVE_ARCH_HIGHBIT + return highbit32(v); +#else + int i; + + if (v & 0xffff0000) + if (v & 0xff000000) + i = 24; + else + i = 16; + else if (v & 0x0000ffff) + if (v & 0x0000ff00) + i = 8; + else + i = 0; + else + return -1; + return i + xfs_highbit[(v >> i) & 0xff]; +#endif +} + +/* + * xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_lowbit64( + __uint64_t v) +{ + int n; + n = ffs((unsigned)v); + if (n == 0) { + n = ffs(v >> 32); + if (n >= 0) + n+=32; + } + return n-1; +} + +/* + * xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_highbit64( + __uint64_t v) +{ + __uint32_t h = v >> 32; + if (h) + return xfs_highbit32(h) + 32; + return xfs_highbit32((__u32)v); +} + + +/* + * Count the number of bits set in the bitmap starting with bit + * start_bit. Size is the size of the bitmap in words. + * + * Do the counting by mapping a byte value to the number of set + * bits for that value using the xfs_countbit array, i.e. + * xfs_countbit[0] == 0, xfs_countbit[1] == 1, xfs_countbit[2] == 1, + * xfs_countbit[3] == 2, etc. + */ +int +xfs_count_bits(uint *map, uint size, uint start_bit) +{ + register int bits; + register unsigned char *bytep; + register unsigned char *end_map; + int byte_bit; + + bits = 0; + end_map = (char*)(map + size); + bytep = (char*)(map + (start_bit & ~0x7)); + byte_bit = start_bit & 0x7; + + /* + * If the caller fell off the end of the map, return 0. + */ + if (bytep >= end_map) { + return (0); + } + + /* + * If start_bit is not byte aligned, then process the + * first byte separately. + */ + if (byte_bit != 0) { + /* + * Shift off the bits we don't want to look at, + * before indexing into xfs_countbit. + */ + bits += xfs_countbit[(*bytep >> byte_bit)]; + bytep++; + } + + /* + * Count the bits in each byte until the end of the bitmap. + */ + while (bytep < end_map) { + bits += xfs_countbit[*bytep]; + bytep++; + } + + return (bits); +} + +/* + * Count the number of contiguous bits set in the bitmap starting with bit + * start_bit. Size is the size of the bitmap in words. + */ +int +xfs_contig_bits(uint *map, uint size, uint start_bit) +{ +#if BITS_PER_LONG == 32 + return find_next_zero_bit(map,size*sizeof(uint)*8,start_bit) - start_bit; +#else + /* + * The first argument to find_next_zero_bit needs to be aligned, + * but this is coming from the xfs_buf_log_format_t on-disk + * struct, which can't be padded or otherwise modified w/o breaking + * on-disk compatibility... so create a temporary, aligned + * variable, copy over the bitmap, and send that to find_next_zero_bit + * This only happens in recovery, so it's ugly but not too bad. + */ + void * addr; + int bit; + size_t bitmap_size = size * sizeof(uint); + + addr = (void *)kmem_alloc(bitmap_size, KM_SLEEP); + memcpy(addr, map, size * sizeof(uint)); + + bit = find_next_zero_bit(addr,size*sizeof(uint)*8,start_bit) - start_bit; + + kmem_free(addr, bitmap_size); + + return bit; +#endif +} + +/* + * This takes the bit number to start looking from and + * returns the next set bit from there. It returns -1 + * if there are no more bits set or the start bit is + * beyond the end of the bitmap. + * + * Size is the number of words, not bytes, in the bitmap. + */ +int xfs_next_bit(uint *map, uint size, uint start_bit) +{ + uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); + uint result = start_bit & ~(NBWORD - 1); + uint tmp; + + size <<= BIT_TO_WORD_SHIFT; + + if (start_bit >= size) + return -1; + size -= result; + start_bit &= (NBWORD - 1); + if (start_bit) { + tmp = *p++; + /* set to zero first offset bits */ + tmp &= (~0U << start_bit); + if (size < NBWORD) + goto found_first; + if (tmp != 0U) + goto found_middle; + size -= NBWORD; + result += NBWORD; + } + while (size >= NBWORD) { + if ((tmp = *p++) != 0U) + goto found_middle; + result += NBWORD; + size -= NBWORD; + } + if (!size) + return -1; + tmp = *p; +found_first: +found_middle: + return result + ffs(tmp) - 1; +} diff -Nur linux-2.4.19/fs/xfs/xfs_bit.h linux-2.4.19-sgi211r3/fs/xfs/xfs_bit.h --- linux-2.4.19/fs/xfs/xfs_bit.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_bit.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BIT_H__ +#define __XFS_BIT_H__ + +/* + * XFS bit manipulation routines. + */ + +/* + * masks with n high/low bits set, 32-bit values & 64-bit values + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK32HI) +__uint32_t xfs_mask32hi(int n); +#define XFS_MASK32HI(n) xfs_mask32hi(n) +#else +#define XFS_MASK32HI(n) ((__uint32_t)-1 << (32 - (n))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK64HI) +__uint64_t xfs_mask64hi(int n); +#define XFS_MASK64HI(n) xfs_mask64hi(n) +#else +#define XFS_MASK64HI(n) ((__uint64_t)-1 << (64 - (n))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK32LO) +__uint32_t xfs_mask32lo(int n); +#define XFS_MASK32LO(n) xfs_mask32lo(n) +#else +#define XFS_MASK32LO(n) (((__uint32_t)1 << (n)) - 1) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK64LO) +__uint64_t xfs_mask64lo(int n); +#define XFS_MASK64LO(n) xfs_mask64lo(n) +#else +#define XFS_MASK64LO(n) (((__uint64_t)1 << (n)) - 1) +#endif + +/* Get high bit set out of 32-bit argument, -1 if none set */ +extern int xfs_highbit32(__uint32_t v); + +/* Get low bit set out of 64-bit argument, -1 if none set */ +extern int xfs_lowbit64(__uint64_t v); + +/* Get high bit set out of 64-bit argument, -1 if none set */ +extern int xfs_highbit64(__uint64_t); + +/* Count set bits in map starting with start_bit */ +extern int xfs_count_bits(uint *map, uint size, uint start_bit); + +/* Count continuous one bits in map starting with start_bit */ +extern int xfs_contig_bits(uint *map, uint size, uint start_bit); + +/* Find next set bit in map */ +extern int xfs_next_bit(uint *map, uint size, uint start_bit); + +#endif /* __XFS_BIT_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_bmap.c linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap.c --- linux-2.4.19/fs/xfs/xfs_bmap.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,6323 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#ifdef DEBUG +ktrace_t *xfs_bmap_trace_buf; +#endif + +#ifdef XFSDEBUG +STATIC void +xfs_bmap_check_leaf_extents(xfs_btree_cur_t *cur, xfs_inode_t *ip, int whichfork); +#endif + +kmem_zone_t *xfs_bmap_free_item_zone; + +/* + * Prototypes for internal bmap routines. + */ + + +/* + * Called from xfs_bmap_add_attrfork to handle extents format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags); /* inode logging flags */ + +/* + * Called from xfs_bmap_add_attrfork to handle local format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_local( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags); /* inode logging flags */ + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after allocating space (or doing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_add_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting a delayed + * allocation to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_delay_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a delayed allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_hole_delay( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp,/* inode logging flags */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_hole_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int whichfork); /* data or attr fork */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting an unwritten + * allocation to a real allocation or vice versa. + */ +STATIC int /* error */ +xfs_bmap_add_extent_unwritten_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp); /* inode logging flags */ + +/* + * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. + * It figures out where to ask the underlying allocator to put the new extent. + */ +STATIC int /* error */ +xfs_bmap_alloc( + xfs_bmalloca_t *ap); /* bmap alloc argument struct */ + +/* + * Transform a btree format file with only one leaf node, where the + * extents list will fit in the inode, into an extents format file. + * Since the extent list is already in-core, all we have to do is + * give up the space for the btree root and pitch the leaf block. + */ +STATIC int /* error */ +xfs_bmap_btree_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int async); /* xaction can be async */ + +#ifdef XFSDEBUG +/* + * Check that the extents list for the inode ip is in the right order. + */ +STATIC void +xfs_bmap_check_extents( + xfs_inode_t *ip, /* incore inode pointer */ + int whichfork); /* data or attr fork */ +#else +#define xfs_bmap_check_extents(ip,w) +#endif + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after removing space (or undoing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_del_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_trans_t *tp, /* current trans pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int iflags, /* input flags (meta-data or not) */ + int *logflagsp,/* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Remove the entry "free" from the free item list. Prev points to the + * previous entry, unless "free" is the head of the list. + */ +STATIC void +xfs_bmap_del_free( + xfs_bmap_free_t *flist, /* free item list header */ + xfs_bmap_free_item_t *prev, /* previous item on list, if any */ + xfs_bmap_free_item_t *free); /* list item to be freed */ + +/* + * Remove count entries from the extents array for inode "ip", starting + * at index "idx". Copies the remaining items down over the deleted ones, + * and gives back the excess memory. + */ +STATIC void +xfs_bmap_delete_exlist( + xfs_inode_t *ip, /* incode inode pointer */ + xfs_extnum_t idx, /* starting delete index */ + xfs_extnum_t count, /* count of items to delete */ + int whichfork); /* data or attr fork */ + +/* + * Convert an extents-format file into a btree-format file. + * The new file will have a root block (in the inode) and a single child block. + */ +STATIC int /* error */ +xfs_bmap_extents_to_btree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first-block-allocated */ + xfs_bmap_free_t *flist, /* blocks freed in xaction */ + xfs_btree_cur_t **curp, /* cursor returned to caller */ + int wasdel, /* converting a delayed alloc */ + int *logflagsp, /* inode logging flags */ + int whichfork); /* data or attr fork */ + +/* + * Insert new item(s) in the extent list for inode "ip". + * Count new items are inserted at offset idx. + */ +STATIC void +xfs_bmap_insert_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting index of new items */ + xfs_extnum_t count, /* number of inserted items */ + xfs_bmbt_irec_t *new, /* items to insert */ + int whichfork); /* data or attr fork */ + +/* + * Convert a local file to an extents file. + * This code is sort of bogus, since the file data needs to get + * logged so it won't be lost. The bmap-level manipulations are ok, though. + */ +STATIC int /* error */ +xfs_bmap_local_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated in xaction */ + xfs_extlen_t total, /* total blocks needed by transaction */ + int *logflagsp, /* inode logging flags */ + int whichfork); /* data or attr fork */ + +/* + * Search the extents list for the inode, for the extent containing bno. + * If bno lies in a hole, point to the next entry. If bno lies past eof, + * *eofp will be set, and *prevp will contain the last entry (null if none). + * Else, *lastxp will be set to the index of the found + * entry; *gotp will contain the entry. + */ +STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_search_extents( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t bno, /* block number searched for */ + int whichfork, /* data or attr fork */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */ + +#ifdef XFS_BMAP_TRACE +/* + * Add a bmap trace buffer entry. Base routine for the others. + */ +STATIC void +xfs_bmap_trace_addentry( + int opcode, /* operation */ + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(ies) */ + xfs_extnum_t cnt, /* count of entries, 1 or 2 */ + xfs_bmbt_rec_t *r1, /* first record */ + xfs_bmbt_rec_t *r2, /* second record or null */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry prior to a call to xfs_bmap_delete_exlist. + */ +STATIC void +xfs_bmap_trace_delete( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) deleted */ + xfs_extnum_t cnt, /* count of entries deleted, 1 or 2 */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry prior to a call to xfs_bmap_insert_exlist, or + * reading in the extents list from the disk (in the btree). + */ +STATIC void +xfs_bmap_trace_insert( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) inserted */ + xfs_extnum_t cnt, /* count of entries inserted, 1 or 2 */ + xfs_bmbt_irec_t *r1, /* inserted record 1 */ + xfs_bmbt_irec_t *r2, /* inserted record 2 or null */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry after updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_post_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry updated */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry prior to updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_pre_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry to be updated */ + int whichfork); /* data or attr fork */ + +#else +#define xfs_bmap_trace_delete(f,d,ip,i,c,w) +#define xfs_bmap_trace_insert(f,d,ip,i,c,r1,r2,w) +#define xfs_bmap_trace_post_update(f,d,ip,i,w) +#define xfs_bmap_trace_pre_update(f,d,ip,i,w) +#endif /* XFS_BMAP_TRACE */ + +/* + * Compute the worst-case number of indirect blocks that will be used + * for ip's delayed extent of length "len". + */ +STATIC xfs_filblks_t +xfs_bmap_worst_indlen( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_filblks_t len); /* delayed extent length */ + +#ifdef DEBUG +/* + * Perform various validation checks on the values being returned + * from xfs_bmapi(). + */ +STATIC void +xfs_bmap_validate_ret( + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + xfs_bmbt_irec_t *mval, + int nmap, + int ret_nmap); +#else +#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) +#endif /* DEBUG */ + +#if defined(DEBUG) && defined(XFS_RW_TRACE) +STATIC void +xfs_bunmap_trace( + xfs_inode_t *ip, + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + inst_t *ra); +#else +#define xfs_bunmap_trace(ip, bno, len, flags, ra) +#endif /* DEBUG && XFS_RW_TRACE */ + +STATIC int +xfs_bmap_count_tree( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_fsblock_t blockno, + int levelin, + int *count); + +STATIC int +xfs_bmap_count_leaves( + xfs_bmbt_rec_t *frp, + int numrecs, + int *count); + +/* + * Bmap internal routines. + */ + +/* + * Called from xfs_bmap_add_attrfork to handle btree format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_btree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags) /* inode logging flags */ +{ + xfs_btree_cur_t *cur; /* btree cursor */ + int error; /* error return value */ + xfs_mount_t *mp; /* file system mount struct */ + int stat; /* newroot status */ + + mp = ip->i_mount; + if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip)) + *flags |= XFS_ILOG_DBROOT; + else { + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + XFS_DATA_FORK); + cur->bc_private.b.flist = flist; + cur->bc_private.b.firstblock = *firstblock; + if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat))) + goto error0; + ASSERT(stat == 1); /* must be at least one entry */ + if ((error = xfs_bmbt_newroot(cur, flags, &stat))) + goto error0; + if (stat == 0) { + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + return XFS_ERROR(ENOSPC); + } + *firstblock = cur->bc_private.b.firstblock; + cur->bc_private.b.allocated = 0; + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + } + return 0; +error0: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Called from xfs_bmap_add_attrfork to handle extents format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags) /* inode logging flags */ +{ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + int error; /* error return value */ + + if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip)) + return 0; + cur = NULL; + error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0, + flags, XFS_DATA_FORK); + if (cur) { + cur->bc_private.b.allocated = 0; + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + return error; +} + +/* + * Called from xfs_bmap_add_attrfork to handle local format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_local( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags) /* inode logging flags */ +{ + xfs_da_args_t dargs; /* args for dir/attr code */ + int error; /* error return value */ + xfs_mount_t *mp; /* mount structure pointer */ + + if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) + return 0; + if ((ip->i_d.di_mode & IFMT) == IFDIR) { + mp = ip->i_mount; + bzero(&dargs, sizeof(dargs)); + dargs.dp = ip; + dargs.firstblock = firstblock; + dargs.flist = flist; + dargs.total = mp->m_dirblkfsbs; + dargs.whichfork = XFS_DATA_FORK; + dargs.trans = tp; + error = XFS_DIR_SHORTFORM_TO_SINGLE(mp, &dargs); + } else + error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, + XFS_DATA_FORK); + return error; +} + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after allocating space (or doing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_add_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd) /* OK to use reserved data blocks */ +{ + xfs_btree_cur_t *cur; /* btree cursor or null */ + xfs_filblks_t da_new; /* new count del alloc blocks used */ + xfs_filblks_t da_old; /* old count del alloc blocks used */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent"; +#endif + xfs_ifork_t *ifp; /* inode fork ptr */ + int logflags; /* returned value */ + xfs_extnum_t nextents; /* number of extents in file now */ + + XFS_STATS_INC(xfsstats.xs_add_exlist); + cur = *curp; + ifp = XFS_IFORK_PTR(ip, whichfork); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(idx <= nextents); + da_old = da_new = 0; + error = 0; + /* + * This is the first extent added to a new/empty file. + * Special case this one, so other routines get to assume there are + * already extents in the list. + */ + if (nextents == 0) { + xfs_bmap_trace_insert(fname, "insert empty", ip, 0, 1, new, + NULL, whichfork); + xfs_bmap_insert_exlist(ip, 0, 1, new, whichfork); + ASSERT(cur == NULL); + ifp->if_lastex = 0; + if (!ISNULLSTARTBLOCK(new->br_startblock)) { + XFS_IFORK_NEXT_SET(ip, whichfork, 1); + logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + } else + logflags = 0; + } + /* + * Any kind of new delayed allocation goes here. + */ + else if (ISNULLSTARTBLOCK(new->br_startblock)) { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new, + &logflags, rsvd))) + goto done; + } + /* + * Real allocation off the end of the file. + */ + else if (idx == nextents) { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new, + &logflags, whichfork))) + goto done; + } else { + xfs_bmbt_irec_t prev; /* old extent at offset idx */ + + /* + * Get the record referred to by idx. + */ + xfs_bmbt_get_all(&ifp->if_u1.if_extents[idx], &prev); + /* + * If it's a real allocation record, and the new allocation ends + * after the start of the referred to record, then we're filling + * in a delayed or unwritten allocation with a real one, or + * converting real back to unwritten. + */ + if (!ISNULLSTARTBLOCK(new->br_startblock) && + new->br_startoff + new->br_blockcount > prev.br_startoff) { + if (prev.br_state != XFS_EXT_UNWRITTEN && + ISNULLSTARTBLOCK(prev.br_startblock)) { + da_old = STARTBLOCKVAL(prev.br_startblock); + if (cur) + ASSERT(cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL); + if ((error = xfs_bmap_add_extent_delay_real(ip, + idx, &cur, new, &da_new, first, flist, + &logflags, rsvd))) + goto done; + } else if (new->br_state == XFS_EXT_NORM) { + ASSERT(new->br_state == XFS_EXT_NORM); + if ((error = xfs_bmap_add_extent_unwritten_real( + ip, idx, &cur, new, &logflags))) + goto done; + } else { + ASSERT(new->br_state == XFS_EXT_UNWRITTEN); + if ((error = xfs_bmap_add_extent_unwritten_real( + ip, idx, &cur, new, &logflags))) + goto done; + } + ASSERT(*curp == cur || *curp == NULL); + } + /* + * Otherwise we're filling in a hole with an allocation. + */ + else { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, + new, &logflags, whichfork))) + goto done; + } + } + + ASSERT(*curp == cur || *curp == NULL); + /* + * Convert to a btree if necessary. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { + int tmp_logflags; /* partial log flag return val */ + + ASSERT(cur == NULL); + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, first, + flist, &cur, da_old > 0, &tmp_logflags, whichfork); + logflags |= tmp_logflags; + if (error) + goto done; + } + /* + * Adjust for changes in reserved delayed indirect blocks. + * Nothing to do for disk quotas here. + */ + if (da_old || da_new) { + xfs_filblks_t nblks; + + nblks = da_new; + if (cur) + nblks += cur->bc_private.b.allocated; + ASSERT(nblks <= da_old); + if (nblks < da_old) + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, + (int)(da_old - nblks), rsvd); + } + /* + * Clear out the allocated field, done with it now in any case. + */ + if (cur) { + cur->bc_private.b.allocated = 0; + *curp = cur; + } +done: +#ifdef XFSDEBUG + if (!error) + xfs_bmap_check_leaf_extents(*curp, ip, whichfork); +#endif + *logflagsp = logflags; + return error; +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a delayed + * allocation to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_delay_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int rsvd) /* OK to use reserved data block allocation */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_btree_cur_t *cur; /* btree cursor */ + int diff; /* temp value */ + xfs_bmbt_rec_t *ep; /* extent entry for idx */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_delay_real"; +#endif + int i; /* temp state */ + xfs_fileoff_t new_endoff; /* end offset of new entry */ + xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ + /* left is 0, right is 1, prev is 2 */ + int rval=0; /* return value (logging flags) */ + int state = 0;/* state bits, accessed thru macros */ + xfs_filblks_t temp; /* value for dnew calculations */ + xfs_filblks_t temp2; /* value for dnew calculations */ + int tmp_rval; /* partial logging flags */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_FILLING, RIGHT_FILLING, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define LEFT r[0] +#define RIGHT r[1] +#define PREV r[2] +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define MASK3(a,b,c) (MASK2(a,b) | MASK(c)) +#define MASK4(a,b,c,d) (MASK3(a,b,c) | MASK(d)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE \ + (state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG)) + + /* + * Set up a bunch of variables to make the tests simpler. + */ + cur = *curp; + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_get_all(ep, &PREV); + new_endoff = new->br_startoff + new->br_blockcount; + ASSERT(PREV.br_startoff <= new->br_startoff); + ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); + /* + * Set flags determining what part of the previous delayed allocation + * extent is being replaced by a real allocation. + */ + STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff); + STATE_SET(RIGHT_FILLING, + PREV.br_startoff + PREV.br_blockcount == new_endoff); + /* + * Check and set flags if this segment has a left neighbor. + * Don't set contiguous if the combined extent would be too large. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &LEFT); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock)); + } + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && + LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && + LEFT.br_state == new->br_state && + LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN); + /* + * Check and set flags if this segment has a right neighbor. + * Don't set contiguous if the combined extent would be too large. + * Also check for all-three-contiguous being too large. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) { + xfs_bmbt_get_all(ep + 1, &RIGHT); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock)); + } + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new_endoff == RIGHT.br_startoff && + new->br_startblock + new->br_blockcount == + RIGHT.br_startblock && + new->br_state == RIGHT.br_state && + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && + ((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) != + MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) || + LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount + <= MAXEXTLEN)); + error = 0; + /* + * Switch out based on the FILLING and CONTIG state bits. + */ + switch (SWITCH_STATE) { + + case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The left and right neighbors are both contiguous with new. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 2, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + PREV.br_blockcount + + RIGHT.br_blockcount, LEFT.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The left neighbor is contiguous, the right is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff, + LEFT.br_startblock, LEFT.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + PREV.br_blockcount, LEFT.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The right neighbor is contiguous, the left is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, new->br_startblock); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx + 1, 1, XFS_DATA_FORK); + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + new->br_startblock, + PREV.br_blockcount + + RIGHT.br_blockcount, PREV.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK2(LEFT_FILLING, RIGHT_FILLING): + /* + * Filling in all of a previously delayed allocation extent. + * Neither the left nor right neighbors are contiguous with + * the new one. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, new->br_startblock); + xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + *dnew = 0; + break; + + case MASK2(LEFT_FILLING, LEFT_CONTIG): + /* + * Filling in the first part of a previous delayed allocation. + * The left neighbor is contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + new->br_blockcount); + xfs_bmbt_set_startoff(ep, + PREV.br_startoff + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + ip->i_df.if_lastex = idx - 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff, + LEFT.br_startblock, LEFT.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + new->br_blockcount, + LEFT.br_state))) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock)); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK(LEFT_FILLING): + /* + * Filling in the first part of a previous delayed allocation. + * The left neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_startoff(ep, new_endoff); + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + base = ip->i_df.if_u1.if_extents; + ep = &base[idx + 1]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK2(RIGHT_FILLING, RIGHT_CONTIG): + /* + * Filling in the last part of a previous delayed allocation. + * The right neighbor is contiguous with the new allocation. + */ + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmbt_set_allf(ep + 1, new->br_startoff, new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + RIGHT.br_state); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + + RIGHT.br_blockcount, + RIGHT.br_state))) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock)); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK(RIGHT_FILLING): + /* + * Filling in the last part of a previous delayed allocation. + * The right neighbor is not contiguous. + */ + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1, + new, NULL, XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); + *dnew = temp; + break; + + case 0: + /* + * Filling in the middle part of a previous delayed allocation. + * Contiguity is impossible here. + * This case is avoided almost all the time. + */ + temp = new->br_startoff - PREV.br_startoff; + xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + r[0] = *new; + r[1].br_startoff = new_endoff; + temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff; + r[1].br_blockcount = temp2; + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1], + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 2, &r[0], XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = xfs_bmap_worst_indlen(ip, temp); + temp2 = xfs_bmap_worst_indlen(ip, temp2); + diff = (int)(temp + temp2 - STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + if (diff > 0 && + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, -diff, rsvd)) { + /* + * Ick gross gag me with a spoon. + */ + ASSERT(0); /* want to see if this ever happens! */ + while (diff > 0) { + if (temp) { + temp--; + diff--; + if (!diff || + !xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, -diff, rsvd)) + break; + } + if (temp2) { + temp2--; + diff--; + if (!diff || + !xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, -diff, rsvd)) + break; + } + } + } + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "0", ip, idx + 2, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep + 2, NULLSTARTBLOCK((int)temp2)); + xfs_bmap_trace_post_update(fname, "0", ip, idx + 2, + XFS_DATA_FORK); + *dnew = temp + temp2; + break; + + case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK2(LEFT_FILLING, RIGHT_CONTIG): + case MASK2(RIGHT_FILLING, LEFT_CONTIG): + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + case MASK(LEFT_CONTIG): + case MASK(RIGHT_CONTIG): + /* + * These cases are all impossible. + */ + ASSERT(0); + } + *curp = cur; +done: + *logflagsp = rval; + return error; +#undef LEFT +#undef RIGHT +#undef PREV +#undef MASK +#undef MASK2 +#undef MASK3 +#undef MASK4 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting an unwritten + * allocation to a real allocation or vice versa. + */ +STATIC int /* error */ +xfs_bmap_add_extent_unwritten_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp) /* inode logging flags */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_btree_cur_t *cur; /* btree cursor */ + xfs_bmbt_rec_t *ep; /* extent entry for idx */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_unwritten_real"; +#endif + int i; /* temp state */ + xfs_fileoff_t new_endoff; /* end offset of new entry */ + xfs_exntst_t newext; /* new extent state */ + xfs_exntst_t oldext; /* old extent state */ + xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ + /* left is 0, right is 1, prev is 2 */ + int rval=0; /* return value (logging flags) */ + int state = 0;/* state bits, accessed thru macros */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_FILLING, RIGHT_FILLING, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define LEFT r[0] +#define RIGHT r[1] +#define PREV r[2] +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define MASK3(a,b,c) (MASK2(a,b) | MASK(c)) +#define MASK4(a,b,c,d) (MASK3(a,b,c) | MASK(d)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE \ + (state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG)) + + /* + * Set up a bunch of variables to make the tests simpler. + */ + error = 0; + cur = *curp; + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_get_all(ep, &PREV); + newext = new->br_state; + oldext = (newext == XFS_EXT_UNWRITTEN) ? + XFS_EXT_NORM : XFS_EXT_UNWRITTEN; + ASSERT(PREV.br_state == oldext); + new_endoff = new->br_startoff + new->br_blockcount; + ASSERT(PREV.br_startoff <= new->br_startoff); + ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); + /* + * Set flags determining what part of the previous oldext allocation + * extent is being replaced by a newext allocation. + */ + STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff); + STATE_SET(RIGHT_FILLING, + PREV.br_startoff + PREV.br_blockcount == new_endoff); + /* + * Check and set flags if this segment has a left neighbor. + * Don't set contiguous if the combined extent would be too large. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &LEFT); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock)); + } + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && + LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && + LEFT.br_state == newext && + LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN); + /* + * Check and set flags if this segment has a right neighbor. + * Don't set contiguous if the combined extent would be too large. + * Also check for all-three-contiguous being too large. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) { + xfs_bmbt_get_all(ep + 1, &RIGHT); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock)); + } + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new_endoff == RIGHT.br_startoff && + new->br_startblock + new->br_blockcount == + RIGHT.br_startblock && + newext == RIGHT.br_state && + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && + ((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) != + MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) || + LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount + <= MAXEXTLEN)); + /* + * Switch out based on the FILLING and CONTIG state bits. + */ + switch (SWITCH_STATE) { + + case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The left and right neighbors are both contiguous with new. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 2, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + ip->i_d.di_nextents -= 2; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount, LEFT.br_state))) + goto done; + } + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The left neighbor is contiguous, the right is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + PREV.br_blockcount, + LEFT.br_state))) + goto done; + } + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The right neighbor is contiguous, the left is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount + RIGHT.br_blockcount); + xfs_bmbt_set_state(ep, newext); + xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx + 1, 1, XFS_DATA_FORK); + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + newext))) + goto done; + } + break; + + case MASK2(LEFT_FILLING, RIGHT_FILLING): + /* + * Setting all of a previous oldext extent to newext. + * Neither the left nor right neighbors are contiguous with + * the new one. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_state(ep, newext); + xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + newext))) + goto done; + } + break; + + case MASK2(LEFT_FILLING, LEFT_CONTIG): + /* + * Setting the first part of a previous oldext extent to newext. + * The left neighbor is contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + new->br_blockcount); + xfs_bmbt_set_startoff(ep, + PREV.br_startoff + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, + new->br_startblock + new->br_blockcount); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, + PREV.br_startoff + new->br_blockcount, + PREV.br_startblock + new->br_blockcount, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + if (xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + new->br_blockcount, + LEFT.br_state)) + goto done; + } + break; + + case MASK(LEFT_FILLING): + /* + * Setting the first part of a previous oldext extent to newext. + * The left neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK); + ASSERT(ep && xfs_bmbt_get_state(ep) == oldext); + xfs_bmbt_set_startoff(ep, new_endoff); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmbt_set_startblock(ep, + new->br_startblock + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, + PREV.br_startoff + new->br_blockcount, + PREV.br_startblock + new->br_blockcount, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + cur->bc_rec.b = *new; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case MASK2(RIGHT_FILLING, RIGHT_CONTIG): + /* + * Setting the last part of a previous oldext extent to newext. + * The right neighbor is contiguous with the new allocation. + */ + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_allf(ep + 1, new->br_startoff, new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, newext); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + newext))) + goto done; + } + break; + + case MASK(RIGHT_FILLING): + /* + * Setting the last part of a previous oldext extent to newext. + * The right neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1, + new, NULL, XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case 0: + /* + * Setting the middle part of a previous oldext extent to + * newext. Contiguity is impossible here. + * One extent becomes three extents. + */ + xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + new->br_startoff - PREV.br_startoff); + xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK); + r[0] = *new; + r[1].br_startoff = new_endoff; + r[1].br_blockcount = + PREV.br_startoff + PREV.br_blockcount - new_endoff; + r[1].br_startblock = new->br_startblock + new->br_blockcount; + r[1].br_state = oldext; + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1], + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 2, &r[0], XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents += 2; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + /* new right extent - oldext */ + if ((error = xfs_bmbt_update(cur, r[1].br_startoff, + r[1].br_startblock, r[1].br_blockcount, + r[1].br_state))) + goto done; + /* new left extent - oldext */ + PREV.br_blockcount = + new->br_startoff - PREV.br_startoff; + cur->bc_rec.b = PREV; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + ASSERT(i == 1); + /* new middle extent - newext */ + cur->bc_rec.b = *new; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK2(LEFT_FILLING, RIGHT_CONTIG): + case MASK2(RIGHT_FILLING, LEFT_CONTIG): + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + case MASK(LEFT_CONTIG): + case MASK(RIGHT_CONTIG): + /* + * These cases are all impossible. + */ + ASSERT(0); + } + *curp = cur; +done: + *logflagsp = rval; + return error; +#undef LEFT +#undef RIGHT +#undef PREV +#undef MASK +#undef MASK2 +#undef MASK3 +#undef MASK4 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a delayed allocation. + */ +/*ARGSUSED*/ +STATIC int /* error */ +xfs_bmap_add_extent_hole_delay( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int rsvd) /* OK to allocate reserved blocks */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_bmbt_rec_t *ep; /* extent list entry for idx */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_hole_delay"; +#endif + xfs_bmbt_irec_t left; /* left neighbor extent entry */ + xfs_filblks_t newlen=0; /* new indirect size */ + xfs_filblks_t oldlen=0; /* old indirect size */ + xfs_bmbt_irec_t right; /* right neighbor extent entry */ + int state; /* state bits, accessed thru macros */ + xfs_filblks_t temp; /* temp for indirect calculations */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE (state & MASK2(LEFT_CONTIG, RIGHT_CONTIG)) + + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + state = 0; + ASSERT(ISNULLSTARTBLOCK(new->br_startblock)); + /* + * Check and set flags if this segment has a left neighbor + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &left); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock)); + } + /* + * Check and set flags if the current (right) segment exists. + * If it doesn't exist, we're converting the hole at end-of-file. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { + xfs_bmbt_get_all(ep, &right); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock)); + } + /* + * Set contiguity flags on the left and right neighbors. + * Don't let extents get too large, even if the pieces are contiguous. + */ + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && STATE_TEST(LEFT_DELAY) && + left.br_startoff + left.br_blockcount == new->br_startoff && + left.br_blockcount + new->br_blockcount <= MAXEXTLEN); + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && STATE_TEST(RIGHT_DELAY) && + new->br_startoff + new->br_blockcount == right.br_startoff && + new->br_blockcount + right.br_blockcount <= MAXEXTLEN && + (!STATE_TEST(LEFT_CONTIG) || + (left.br_blockcount + new->br_blockcount + + right.br_blockcount <= MAXEXTLEN))); + /* + * Switch out based on the contiguity flags. + */ + switch (SWITCH_STATE) { + + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + /* + * New allocation is contiguous with delayed allocations + * on the left and on the right. + * Merge all three into a single extent list entry. + */ + temp = left.br_blockcount + new->br_blockcount + + right.br_blockcount; + xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, temp); + oldlen = STARTBLOCKVAL(left.br_startblock) + + STARTBLOCKVAL(new->br_startblock) + + STARTBLOCKVAL(right.br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep - 1, NULLSTARTBLOCK((int)newlen)); + xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LC|RC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + break; + + case MASK(LEFT_CONTIG): + /* + * New allocation is contiguous with a delayed allocation + * on the left. + * Merge the new allocation with the left neighbor. + */ + temp = left.br_blockcount + new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, temp); + oldlen = STARTBLOCKVAL(left.br_startblock) + + STARTBLOCKVAL(new->br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep - 1, NULLSTARTBLOCK((int)newlen)); + xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + break; + + case MASK(RIGHT_CONTIG): + /* + * New allocation is contiguous with a delayed allocation + * on the right. + * Merge the new allocation with the right neighbor. + */ + xfs_bmap_trace_pre_update(fname, "RC", ip, idx, XFS_DATA_FORK); + temp = new->br_blockcount + right.br_blockcount; + oldlen = STARTBLOCKVAL(new->br_startblock) + + STARTBLOCKVAL(right.br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_allf(ep, new->br_startoff, + NULLSTARTBLOCK((int)newlen), temp, right.br_state); + xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + break; + + case 0: + /* + * New allocation is not contiguous with another + * delayed allocation. + * Insert a new entry. + */ + oldlen = newlen = 0; + xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + break; + } + if (oldlen != newlen) { + ASSERT(oldlen > newlen); + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, + (int)(oldlen - newlen), rsvd); + /* + * Nothing to do for disk quota accounting here. + */ + } + *logflagsp = 0; + return 0; +#undef MASK +#undef MASK2 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_hole_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_hole_real"; +#endif + int i; /* temp state */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_irec_t left; /* left neighbor extent entry */ + xfs_bmbt_irec_t right; /* right neighbor extent entry */ + int state; /* state bits, accessed thru macros */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE (state & MASK2(LEFT_CONTIG, RIGHT_CONTIG)) + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)); + ep = &ifp->if_u1.if_extents[idx]; + state = 0; + /* + * Check and set flags if this segment has a left neighbor. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &left); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock)); + } + /* + * Check and set flags if this segment has a current value. + * Not true if we're inserting into the "hole" at eof. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { + xfs_bmbt_get_all(ep, &right); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock)); + } + /* + * We're inserting a real allocation between "left" and "right". + * Set the contiguity flags. Don't let extents get too large. + */ + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + left.br_startoff + left.br_blockcount == new->br_startoff && + left.br_startblock + left.br_blockcount == new->br_startblock && + left.br_state == new->br_state && + left.br_blockcount + new->br_blockcount <= MAXEXTLEN); + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new->br_startoff + new->br_blockcount == right.br_startoff && + new->br_startblock + new->br_blockcount == + right.br_startblock && + new->br_state == right.br_state && + new->br_blockcount + right.br_blockcount <= MAXEXTLEN && + (!STATE_TEST(LEFT_CONTIG) || + left.br_blockcount + new->br_blockcount + + right.br_blockcount <= MAXEXTLEN)); + + /* + * Select which case we're in here, and implement it. + */ + switch (SWITCH_STATE) { + + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + /* + * New allocation is contiguous with real allocations on the + * left and on the right. + * Merge all three into a single extent list entry. + */ + xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1, + whichfork); + xfs_bmbt_set_blockcount(ep - 1, + left.br_blockcount + new->br_blockcount + + right.br_blockcount); + xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1, + whichfork); + xfs_bmap_trace_delete(fname, "LC|RC", ip, + idx, 1, whichfork); + xfs_bmap_delete_exlist(ip, idx, 1, whichfork); + ifp->if_lastex = idx - 1; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); + if (cur == NULL) { + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, + right.br_startblock, right.br_blockcount, &i))) + return error; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + return error; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, left.br_startoff, + left.br_startblock, + left.br_blockcount + new->br_blockcount + + right.br_blockcount, left.br_state); + return error; + + case MASK(LEFT_CONTIG): + /* + * New allocation is contiguous with a real allocation + * on the left. + * Merge the new allocation with the left neighbor. + */ + xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, whichfork); + xfs_bmbt_set_blockcount(ep - 1, + left.br_blockcount + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork); + ifp->if_lastex = idx - 1; + if (cur == NULL) { + *logflagsp = XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = 0; + if ((error = xfs_bmbt_lookup_eq(cur, left.br_startoff, + left.br_startblock, left.br_blockcount, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, left.br_startoff, + left.br_startblock, + left.br_blockcount + new->br_blockcount, + left.br_state); + return error; + + case MASK(RIGHT_CONTIG): + /* + * New allocation is contiguous with a real allocation + * on the right. + * Merge the new allocation with the right neighbor. + */ + xfs_bmap_trace_pre_update(fname, "RC", ip, idx, whichfork); + xfs_bmbt_set_allf(ep, new->br_startoff, new->br_startblock, + new->br_blockcount + right.br_blockcount, + right.br_state); + xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork); + ifp->if_lastex = idx; + if (cur == NULL) { + *logflagsp = XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = 0; + if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, + right.br_startblock, right.br_blockcount, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + right.br_blockcount, + right.br_state); + return error; + + case 0: + /* + * New allocation is not contiguous with another + * real allocation. + * Insert a new entry. + */ + xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL, + whichfork); + xfs_bmap_insert_exlist(ip, idx, 1, new, whichfork); + ifp->if_lastex = idx; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) + 1); + if (cur == NULL) { + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, &i))) + return error; + ASSERT(i == 0); + cur->bc_rec.b.br_state = new->br_state; + if ((error = xfs_bmbt_insert(cur, &i))) + return error; + ASSERT(i == 1); + return 0; + } +#undef MASK +#undef MASK2 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE + /* NOTREACHED */ + ASSERT(0); + return 0; /* keep gcc quite */ +} + +#define XFS_ALLOC_GAP_UNITS 4 + +/* + * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. + * It figures out where to ask the underlying allocator to put the new extent. + */ +STATIC int /* error */ +xfs_bmap_alloc( + xfs_bmalloca_t *ap) /* bmap alloc argument struct */ +{ + xfs_fsblock_t adjust; /* adjustment to block numbers */ + xfs_alloctype_t atype=0; /* type for allocation routines */ + int error; /* error return value */ + xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ + xfs_mount_t *mp; /* mount point structure */ + int nullfb; /* true if ap->firstblock isn't set */ + int rt; /* true if inode is realtime */ +#ifdef __KERNEL__ + xfs_extlen_t prod=0; /* product factor for allocators */ + xfs_extlen_t ralen=0; /* realtime allocation length */ +#endif + +#define ISLEGAL(x,y) \ + (rt ? \ + (x) < mp->m_sb.sb_rblocks : \ + XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \ + XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ + XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) + + /* + * Set up variables. + */ + mp = ap->ip->i_mount; + nullfb = ap->firstblock == NULLFSBLOCK; + rt = (ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata; + fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); +#ifdef __KERNEL__ + if (rt) { + xfs_extlen_t extsz; /* file extent size for rt */ + xfs_fileoff_t nexto; /* next file offset */ + xfs_extlen_t orig_alen; /* original ap->alen */ + xfs_fileoff_t orig_end; /* original off+len */ + xfs_fileoff_t orig_off; /* original ap->off */ + xfs_extlen_t mod_off; /* modulus calculations */ + xfs_fileoff_t prevo; /* previous file offset */ + xfs_rtblock_t rtx; /* realtime extent number */ + xfs_extlen_t temp; /* temp for rt calculations */ + + /* + * Set prod to match the realtime extent size. + */ + if (!(extsz = ap->ip->i_d.di_extsize)) + extsz = mp->m_sb.sb_rextsize; + prod = extsz / mp->m_sb.sb_rextsize; + orig_off = ap->off; + orig_alen = ap->alen; + orig_end = orig_off + orig_alen; + /* + * If the file offset is unaligned vs. the extent size + * we need to align it. This will be possible unless + * the file was previously written with a kernel that didn't + * perform this alignment. + */ + mod_off = do_mod(orig_off, extsz); + if (mod_off) { + ap->alen += mod_off; + ap->off -= mod_off; + } + /* + * Same adjustment for the end of the requested area. + */ + if ((temp = (ap->alen % extsz))) + ap->alen += extsz - temp; + /* + * If the previous block overlaps with this proposed allocation + * then move the start forward without adjusting the length. + */ + prevo = + ap->prevp->br_startoff == NULLFILEOFF ? + 0 : + (ap->prevp->br_startoff + + ap->prevp->br_blockcount); + if (ap->off != orig_off && ap->off < prevo) + ap->off = prevo; + /* + * If the next block overlaps with this proposed allocation + * then move the start back without adjusting the length, + * but not before offset 0. + * This may of course make the start overlap previous block, + * and if we hit the offset 0 limit then the next block + * can still overlap too. + */ + nexto = (ap->eof || ap->gotp->br_startoff == NULLFILEOFF) ? + NULLFILEOFF : ap->gotp->br_startoff; + if (!ap->eof && + ap->off + ap->alen != orig_end && + ap->off + ap->alen > nexto) + ap->off = nexto > ap->alen ? nexto - ap->alen : 0; + /* + * If we're now overlapping the next or previous extent that + * means we can't fit an extsz piece in this hole. Just move + * the start forward to the first legal spot and set + * the length so we hit the end. + */ + if ((ap->off != orig_off && ap->off < prevo) || + (ap->off + ap->alen != orig_end && + ap->off + ap->alen > nexto)) { + ap->off = prevo; + ap->alen = nexto - prevo; + } + /* + * If the result isn't a multiple of rtextents we need to + * remove blocks until it is. + */ + if ((temp = (ap->alen % mp->m_sb.sb_rextsize))) { + /* + * We're not covering the original request, or + * we won't be able to once we fix the length. + */ + if (orig_off < ap->off || + orig_end > ap->off + ap->alen || + ap->alen - temp < orig_alen) + return XFS_ERROR(EINVAL); + /* + * Try to fix it by moving the start up. + */ + if (ap->off + temp <= orig_off) { + ap->alen -= temp; + ap->off += temp; + } + /* + * Try to fix it by moving the end in. + */ + else if (ap->off + ap->alen - temp >= orig_end) + ap->alen -= temp; + /* + * Set the start to the minimum then trim the length. + */ + else { + ap->alen -= orig_off - ap->off; + ap->off = orig_off; + ap->alen -= ap->alen % mp->m_sb.sb_rextsize; + } + /* + * Result doesn't cover the request, fail it. + */ + if (orig_off < ap->off || orig_end > ap->off + ap->alen) + return XFS_ERROR(EINVAL); + } + ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0); + /* + * If the offset & length are not perfectly aligned + * then kill prod, it will just get us in trouble. + */ + if (do_mod(ap->off, extsz) || ap->alen % extsz) + prod = 1; + /* + * Set ralen to be the actual requested length in rtextents. + */ + ralen = ap->alen / mp->m_sb.sb_rextsize; + /* + * If the old value was close enough to MAXEXTLEN that + * we rounded up to it, cut it back so it's legal again. + * Note that if it's a really large request (bigger than + * MAXEXTLEN), we don't hear about that number, and can't + * adjust the starting point to match it. + */ + if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN) + ralen = MAXEXTLEN / mp->m_sb.sb_rextsize; + /* + * If it's an allocation to an empty file at offset 0, + * pick an extent that will space things out in the rt area. + */ + if (ap->eof && ap->off == 0) { + error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx); + if (error) + return error; + ap->rval = rtx * mp->m_sb.sb_rextsize; + } else + ap->rval = 0; + } +#else + if (rt) + ap->rval = 0; +#endif /* __KERNEL__ */ + else if (nullfb) + ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino); + else + ap->rval = ap->firstblock; + /* + * If allocating at eof, and there's a previous real block, + * try to use it's last block as our starting point. + */ + if (ap->eof && ap->prevp->br_startoff != NULLFILEOFF && + !ISNULLSTARTBLOCK(ap->prevp->br_startblock) && + ISLEGAL(ap->prevp->br_startblock + ap->prevp->br_blockcount, + ap->prevp->br_startblock)) { + ap->rval = ap->prevp->br_startblock + ap->prevp->br_blockcount; + /* + * Adjust for the gap between prevp and us. + */ + adjust = ap->off - + (ap->prevp->br_startoff + ap->prevp->br_blockcount); + if (adjust && + ISLEGAL(ap->rval + adjust, ap->prevp->br_startblock)) + ap->rval += adjust; + } + /* + * If not at eof, then compare the two neighbor blocks. + * Figure out whether either one gives us a good starting point, + * and pick the better one. + */ + else if (!ap->eof) { + xfs_fsblock_t gotbno; /* right side block number */ + xfs_fsblock_t gotdiff=0; /* right side difference */ + xfs_fsblock_t prevbno; /* left side block number */ + xfs_fsblock_t prevdiff=0; /* left side difference */ + + /* + * If there's a previous (left) block, select a requested + * start block based on it. + */ + if (ap->prevp->br_startoff != NULLFILEOFF && + !ISNULLSTARTBLOCK(ap->prevp->br_startblock) && + (prevbno = ap->prevp->br_startblock + + ap->prevp->br_blockcount) && + ISLEGAL(prevbno, ap->prevp->br_startblock)) { + /* + * Calculate gap to end of previous block. + */ + adjust = prevdiff = ap->off - + (ap->prevp->br_startoff + + ap->prevp->br_blockcount); + /* + * Figure the startblock based on the previous block's + * end and the gap size. + * Heuristic! + * If the gap is large relative to the piece we're + * allocating, or using it gives us an illegal block + * number, then just use the end of the previous block. + */ + if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->alen && + ISLEGAL(prevbno + prevdiff, + ap->prevp->br_startblock)) + prevbno += adjust; + else + prevdiff += adjust; + /* + * If the firstblock forbids it, can't use it, + * must use default. + */ + if (!rt && !nullfb && + XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno) + prevbno = NULLFSBLOCK; + } + /* + * No previous block or can't follow it, just default. + */ + else + prevbno = NULLFSBLOCK; + /* + * If there's a following (right) block, select a requested + * start block based on it. + */ + if (!ISNULLSTARTBLOCK(ap->gotp->br_startblock)) { + /* + * Calculate gap to start of next block. + */ + adjust = gotdiff = ap->gotp->br_startoff - ap->off; + /* + * Figure the startblock based on the next block's + * start and the gap size. + */ + gotbno = ap->gotp->br_startblock; + /* + * Heuristic! + * If the gap is large relative to the piece we're + * allocating, or using it gives us an illegal block + * number, then just use the start of the next block + * offset by our length. + */ + if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->alen && + ISLEGAL(gotbno - gotdiff, gotbno)) + gotbno -= adjust; + else if (ISLEGAL(gotbno - ap->alen, gotbno)) { + gotbno -= ap->alen; + gotdiff += adjust - ap->alen; + } else + gotdiff += adjust; + /* + * If the firstblock forbids it, can't use it, + * must use default. + */ + if (!rt && !nullfb && + XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno) + gotbno = NULLFSBLOCK; + } + /* + * No next block, just default. + */ + else + gotbno = NULLFSBLOCK; + /* + * If both valid, pick the better one, else the only good + * one, else ap->rval is already set (to 0 or the inode block). + */ + if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK) + ap->rval = prevdiff <= gotdiff ? prevbno : gotbno; + else if (prevbno != NULLFSBLOCK) + ap->rval = prevbno; + else if (gotbno != NULLFSBLOCK) + ap->rval = gotbno; + } + /* + * If allowed, use ap->rval; otherwise must use firstblock since + * it's in the right allocation group. + */ + if (nullfb || rt || XFS_FSB_TO_AGNO(mp, ap->rval) == fb_agno) + ; + else + ap->rval = ap->firstblock; + /* + * Realtime allocation, done through xfs_rtallocate_extent. + */ + if (rt) { +#ifndef __KERNEL__ + ASSERT(0); +#else + xfs_rtblock_t rtb; + + atype = ap->rval == 0 ? + XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO; + do_div(ap->rval, mp->m_sb.sb_rextsize); + rtb = ap->rval; + ap->alen = ralen; + if ((error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, ap->alen, + &ralen, atype, ap->wasdel, prod, &rtb))) + return error; + if (rtb == NULLFSBLOCK && prod > 1 && + (error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, + ap->alen, &ralen, atype, + ap->wasdel, 1, &rtb))) + return error; + ap->rval = rtb; + if (ap->rval != NULLFSBLOCK) { + ap->rval *= mp->m_sb.sb_rextsize; + ralen *= mp->m_sb.sb_rextsize; + ap->alen = ralen; + ap->ip->i_d.di_nblocks += ralen; + xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); + if (ap->wasdel) + ap->ip->i_delayed_blks -= ralen; + /* + * Adjust the disk quota also. This was reserved + * earlier. + */ + if (XFS_IS_QUOTA_ON(mp) && + ap->ip->i_ino != mp->m_sb.sb_uquotino && + ap->ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(ap->tp, ap->ip, + ap->wasdel ? + XFS_TRANS_DQ_DELRTBCOUNT : + XFS_TRANS_DQ_RTBCOUNT, + (long)ralen); + } else + ap->alen = 0; +#endif /* __KERNEL__ */ + } + /* + * Normal allocation, done through xfs_alloc_vextent. + */ + else { + xfs_agnumber_t ag; + xfs_alloc_arg_t args; + xfs_extlen_t blen; + xfs_extlen_t delta; + int isaligned; + xfs_extlen_t longest; + xfs_extlen_t need; + xfs_extlen_t nextminlen=0; + int notinit; + xfs_perag_t *pag; + xfs_agnumber_t startag; + int tryagain; + + tryagain = isaligned = 0; + args.tp = ap->tp; + args.mp = mp; + args.fsbno = ap->rval; + args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); + blen = 0; + if (nullfb) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.total = ap->total; + /* + * Find the longest available space. + * We're going to try for the whole allocation at once. + */ + startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno); + notinit = 0; + down_read(&mp->m_peraglock); + while (blen < ap->alen) { + pag = &mp->m_perag[ag]; + if (!pag->pagf_init && + (error = xfs_alloc_pagf_init(mp, args.tp, + ag, XFS_ALLOC_FLAG_TRYLOCK))) { + up_read(&mp->m_peraglock); + return error; + } + /* + * See xfs_alloc_fix_freelist... + */ + if (pag->pagf_init) { + need = XFS_MIN_FREELIST_PAG(pag, mp); + delta = need > pag->pagf_flcount ? + need - pag->pagf_flcount : 0; + longest = (pag->pagf_longest > delta) ? + (pag->pagf_longest - delta) : + (pag->pagf_flcount > 0 || + pag->pagf_longest > 0); + if (blen < longest) + blen = longest; + } else + notinit = 1; + if (++ag == mp->m_sb.sb_agcount) + ag = 0; + if (ag == startag) + break; + } + up_read(&mp->m_peraglock); + /* + * Since the above loop did a BUF_TRYLOCK, it is + * possible that there is space for this request. + */ + if (notinit || blen < ap->minlen) + args.minlen = ap->minlen; + /* + * If the best seen length is less than the request + * length, use the best as the minimum. + */ + else if (blen < ap->alen) + args.minlen = blen; + /* + * Otherwise we've seen an extent as big as alen, + * use that as the minimum. + */ + else + args.minlen = ap->alen; + } else if (ap->low) { + args.type = XFS_ALLOCTYPE_FIRST_AG; + args.total = args.minlen = ap->minlen; + } else { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.total = ap->total; + args.minlen = ap->minlen; + } + if (ap->ip->i_d.di_extsize) { + args.prod = ap->ip->i_d.di_extsize; + if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) + args.mod = (xfs_extlen_t)(args.prod - args.mod); + } else if (mp->m_sb.sb_blocksize >= NBPP) { + args.prod = 1; + args.mod = 0; + } else { + args.prod = NBPP >> mp->m_sb.sb_blocklog; + if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod)))) + args.mod = (xfs_extlen_t)(args.prod - args.mod); + } + /* + * If we are not low on available data blocks, and the + * underlying logical volume manager is a stripe, and + * the file offset is zero then try to allocate data + * blocks on stripe unit boundary. + * NOTE: ap->aeof is only set if the allocation length + * is >= the stripe unit and the allocation offset is + * at the end of file. + */ + if (!ap->low && ap->aeof) { + if (!ap->off) { + args.alignment = mp->m_dalign; + atype = args.type; + isaligned = 1; + /* + * Adjust for alignment + */ + if (blen > args.alignment && blen <= ap->alen) + args.minlen = blen - args.alignment; + args.minalignslop = 0; + } else { + /* + * First try an exact bno allocation. + * If it fails then do a near or start bno + * allocation with alignment turned on. + */ + atype = args.type; + tryagain = 1; + args.type = XFS_ALLOCTYPE_THIS_BNO; + args.alignment = 1; + /* + * Compute the minlen+alignment for the + * next case. Set slop so that the value + * of minlen+alignment+slop doesn't go up + * between the calls. + */ + if (blen > mp->m_dalign && blen <= ap->alen) + nextminlen = blen - mp->m_dalign; + else + nextminlen = args.minlen; + if (nextminlen + mp->m_dalign > args.minlen + 1) + args.minalignslop = + nextminlen + mp->m_dalign - + args.minlen - 1; + else + args.minalignslop = 0; + } + } else { + args.alignment = 1; + args.minalignslop = 0; + } + args.minleft = ap->minleft; + args.wasdel = ap->wasdel; + args.isfl = 0; + args.userdata = ap->userdata; + if ((error = xfs_alloc_vextent(&args))) + return error; + if (tryagain && args.fsbno == NULLFSBLOCK) { + /* + * Exact allocation failed. Now try with alignment + * turned on. + */ + args.type = atype; + args.fsbno = ap->rval; + args.alignment = mp->m_dalign; + args.minlen = nextminlen; + args.minalignslop = 0; + isaligned = 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (isaligned && args.fsbno == NULLFSBLOCK) { + /* + * allocation failed, so turn off alignment and + * try again. + */ + args.type = atype; + args.fsbno = ap->rval; + args.alignment = 0; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (args.fsbno == NULLFSBLOCK && nullfb && + args.minlen > ap->minlen) { + args.minlen = ap->minlen; + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = ap->rval; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (args.fsbno == NULLFSBLOCK && nullfb) { + args.fsbno = 0; + args.type = XFS_ALLOCTYPE_FIRST_AG; + args.total = ap->minlen; + args.minleft = 0; + if ((error = xfs_alloc_vextent(&args))) + return error; + ap->low = 1; + } + if (args.fsbno != NULLFSBLOCK) { + ap->firstblock = ap->rval = args.fsbno; + ASSERT(nullfb || fb_agno == args.agno || + (ap->low && fb_agno < args.agno)); + ap->alen = args.len; + ap->ip->i_d.di_nblocks += args.len; + xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); + if (ap->wasdel) + ap->ip->i_delayed_blks -= args.len; + /* + * Adjust the disk quota also. This was reserved + * earlier. + */ + if (XFS_IS_QUOTA_ON(mp) && + ap->ip->i_ino != mp->m_sb.sb_uquotino && + ap->ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(ap->tp, ap->ip, + ap->wasdel ? + XFS_TRANS_DQ_DELBCOUNT : + XFS_TRANS_DQ_BCOUNT, + (long)args.len); + } else { + ap->rval = NULLFSBLOCK; + ap->alen = 0; + } + } + return 0; +#undef ISLEGAL +} + +/* + * Transform a btree format file with only one leaf node, where the + * extents list will fit in the inode, into an extents format file. + * Since the extent list is already in-core, all we have to do is + * give up the space for the btree root and pitch the leaf block. + */ +STATIC int /* error */ +xfs_bmap_btree_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int async) /* xaction can be async */ +{ + /* REFERENCED */ + xfs_bmbt_block_t *cblock;/* child btree block */ + xfs_fsblock_t cbno; /* child block number */ + xfs_buf_t *cbp; /* child block's buffer */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork data */ + xfs_mount_t *mp; /* mount point structure */ + xfs_bmbt_ptr_t *pp; /* ptr to block address */ + xfs_bmbt_block_t *rblock;/* root btree block */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); + rblock = ifp->if_broot; + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) == 1); + ASSERT(INT_GET(rblock->bb_numrecs, ARCH_CONVERT) == 1); + ASSERT(XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes) == 1); + mp = ip->i_mount; + pp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, ifp->if_broot_bytes); + *logflagsp = 0; +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), 1))) + return error; +#endif + cbno = INT_GET(*pp, ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, + XFS_BMAP_BTREE_REF))) + return error; + cblock = XFS_BUF_TO_BMBT_BLOCK(cbp); + if ((error = xfs_btree_check_lblock(cur, cblock, 0, cbp))) + return error; + xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp); + if (!async) + xfs_trans_set_sync(tp); + ip->i_d.di_nblocks--; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); + xfs_trans_binval(tp, cbp); + if (cur->bc_bufs[0] == cbp) + cur->bc_bufs[0] = NULL; + xfs_iroot_realloc(ip, -1, whichfork); + ASSERT(ifp->if_broot == NULL); + ASSERT((ifp->if_flags & XFS_IFBROOT) == 0); + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; +} + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after removing space (or undoing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_del_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_trans_t *tp, /* current transaction pointer */ + xfs_extnum_t idx, /* extent number to update/delete */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *del, /* data to remove from extent list */ + int iflags, /* input flags */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd) /* OK to allocate reserved blocks */ +{ + xfs_filblks_t da_new; /* new delay-alloc indirect blocks */ + xfs_filblks_t da_old; /* old delay-alloc indirect blocks */ + xfs_fsblock_t del_endblock=0; /* first block past del */ + xfs_fileoff_t del_endoff; /* first offset past del */ + int delay; /* current block is delayed allocated */ + int do_fx; /* free extent at end of routine */ + xfs_bmbt_rec_t *ep; /* current extent entry pointer */ + int error; /* error return value */ + int flags; /* inode logging flags */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_del_extent"; +#endif + xfs_bmbt_irec_t got; /* current extent entry */ + xfs_fileoff_t got_endoff; /* first offset past got */ + int i; /* temp state */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_mount_t *mp; /* mount structure */ + xfs_filblks_t nblks; /* quota/sb block count */ + xfs_bmbt_irec_t new; /* new record to be inserted */ + /* REFERENCED */ + xfs_extnum_t nextents; /* number of extents in list */ + uint qfield; /* quota field to update */ + xfs_filblks_t temp; /* for indirect length calculations */ + xfs_filblks_t temp2; /* for indirect length calculations */ + + XFS_STATS_INC(xfsstats.xs_del_exlist); + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(idx >= 0 && idx < nextents); + ASSERT(del->br_blockcount > 0); + ep = &ifp->if_u1.if_extents[idx]; + xfs_bmbt_get_all(ep, &got); + ASSERT(got.br_startoff <= del->br_startoff); + del_endoff = del->br_startoff + del->br_blockcount; + got_endoff = got.br_startoff + got.br_blockcount; + ASSERT(got_endoff >= del_endoff); + delay = ISNULLSTARTBLOCK(got.br_startblock); + ASSERT(ISNULLSTARTBLOCK(del->br_startblock) == delay); + flags = 0; + qfield = 0; + error = 0; + /* + * If deleting a real allocation, must free up the disk space. + */ + if (!delay) { + flags = XFS_ILOG_CORE; + /* + * Realtime allocation. Free it and record di_nblocks update. + */ + if (whichfork == XFS_DATA_FORK && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + xfs_fsblock_t bno; + xfs_filblks_t len; + + ASSERT(do_mod(del->br_blockcount, + mp->m_sb.sb_rextsize) == 0); + ASSERT(do_mod(del->br_startblock, + mp->m_sb.sb_rextsize) == 0); + bno = del->br_startblock; + len = del->br_blockcount; + do_div(bno, mp->m_sb.sb_rextsize); + do_div(len, mp->m_sb.sb_rextsize); + if ((error = xfs_rtfree_extent(ip->i_transp, bno, + (xfs_extlen_t)len))) + goto done; + do_fx = 0; + nblks = len * mp->m_sb.sb_rextsize; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + qfield = XFS_TRANS_DQ_RTBCOUNT; + } + /* + * Ordinary allocation. + */ + else { + do_fx = 1; + nblks = del->br_blockcount; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + qfield = XFS_TRANS_DQ_BCOUNT; + } + /* + * Set up del_endblock and cur for later. + */ + del_endblock = del->br_startblock + del->br_blockcount; + if (cur) { + if ((error = xfs_bmbt_lookup_eq(cur, got.br_startoff, + got.br_startblock, got.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + } + da_old = da_new = 0; + } else { + da_old = STARTBLOCKVAL(got.br_startblock); + da_new = 0; + nblks = 0; + do_fx = 0; + } + /* + * Set flag value to use in switch statement. + * Left-contig is 2, right-contig is 1. + */ + switch (((got.br_startoff == del->br_startoff) << 1) | + (got_endoff == del_endoff)) { + case 3: + /* + * Matches the whole extent. Delete the entry. + */ + xfs_bmap_trace_delete(fname, "3", ip, idx, 1, whichfork); + xfs_bmap_delete_exlist(ip, idx, 1, whichfork); + ifp->if_lastex = idx; + if (delay) + break; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); + flags |= XFS_ILOG_CORE; + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_delete(cur, iflags & XFS_BMAPI_ASYNC, &i))) + goto done; + ASSERT(i == 1); + break; + + case 2: + /* + * Deleting the first part of the extent. + */ + xfs_bmap_trace_pre_update(fname, "2", ip, idx, whichfork); + xfs_bmbt_set_startoff(ep, del_endoff); + temp = got.br_blockcount - del->br_blockcount; + xfs_bmbt_set_blockcount(ep, temp); + ifp->if_lastex = idx; + if (delay) { + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + da_old); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "2", ip, idx, + whichfork); + da_new = temp; + break; + } + xfs_bmbt_set_startblock(ep, del_endblock); + xfs_bmap_trace_post_update(fname, "2", ip, idx, whichfork); + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_update(cur, del_endoff, del_endblock, + got.br_blockcount - del->br_blockcount, + got.br_state))) + goto done; + break; + + case 1: + /* + * Deleting the last part of the extent. + */ + temp = got.br_blockcount - del->br_blockcount; + xfs_bmap_trace_pre_update(fname, "1", ip, idx, whichfork); + xfs_bmbt_set_blockcount(ep, temp); + ifp->if_lastex = idx; + if (delay) { + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + da_old); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "1", ip, idx, + whichfork); + da_new = temp; + break; + } + xfs_bmap_trace_post_update(fname, "1", ip, idx, whichfork); + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_update(cur, got.br_startoff, + got.br_startblock, + got.br_blockcount - del->br_blockcount, + got.br_state))) + goto done; + break; + + case 0: + /* + * Deleting the middle of the extent. + */ + temp = del->br_startoff - got.br_startoff; + xfs_bmap_trace_pre_update(fname, "0", ip, idx, whichfork); + xfs_bmbt_set_blockcount(ep, temp); + new.br_startoff = del_endoff; + temp2 = got_endoff - del_endoff; + new.br_blockcount = temp2; + new.br_state = got.br_state; + if (!delay) { + new.br_startblock = del_endblock; + flags |= XFS_ILOG_CORE; + if (cur) { + if ((error = xfs_bmbt_update(cur, + got.br_startoff, + got.br_startblock, temp, + got.br_state))) + goto done; + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + cur->bc_rec.b = new; + error = xfs_bmbt_insert(cur, &i); + if (error && error != ENOSPC) + goto done; + /* + * If get no-space back from btree insert, + * it tried a split, and we have a zero + * block reservation. + * Fix up our state and return the error. + */ + if (error == ENOSPC) { + /* + * Reset the cursor, don't trust + * it after any insert operation. + */ + if ((error = xfs_bmbt_lookup_eq(cur, + got.br_startoff, + got.br_startblock, + temp, &i))) + goto done; + ASSERT(i == 1); + /* + * Update the btree record back + * to the original value. + */ + if ((error = xfs_bmbt_update(cur, + got.br_startoff, + got.br_startblock, + got.br_blockcount, + got.br_state))) + goto done; + /* + * Reset the extent record back + * to the original value. + */ + xfs_bmbt_set_blockcount(ep, + got.br_blockcount); + flags = 0; + error = XFS_ERROR(ENOSPC); + goto done; + } + ASSERT(i == 1); + } else + flags |= XFS_ILOG_FEXT(whichfork); + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) + 1); + } else { + ASSERT(whichfork == XFS_DATA_FORK); + temp = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + temp2 = xfs_bmap_worst_indlen(ip, temp2); + new.br_startblock = NULLSTARTBLOCK((int)temp2); + da_new = temp + temp2; + while (da_new > da_old) { + if (temp) { + temp--; + da_new--; + xfs_bmbt_set_startblock(ep, + NULLSTARTBLOCK((int)temp)); + } + if (da_new == da_old) + break; + if (temp2) { + temp2--; + da_new--; + new.br_startblock = + NULLSTARTBLOCK((int)temp2); + } + } + } + xfs_bmap_trace_post_update(fname, "0", ip, idx, whichfork); + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 1, &new, NULL, + whichfork); + xfs_bmap_insert_exlist(ip, idx + 1, 1, &new, whichfork); + ifp->if_lastex = idx + 1; + break; + } + /* + * If we need to, add to list of extents to delete. + */ + if (do_fx) + xfs_bmap_add_free(del->br_startblock, del->br_blockcount, flist, + mp); + /* + * Adjust inode # blocks in the file. + */ + if (nblks) + ip->i_d.di_nblocks -= nblks; + /* + * Adjust quota data. + */ + if (qfield) + xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks); + /* + * Account for change in delayed indirect blocks. + * Nothing to do for disk quota accounting here. + */ + ASSERT(da_old >= da_new); + if (da_old > da_new) + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new), + rsvd); +done: + *logflagsp = flags; + return error; +} + +/* + * Remove the entry "free" from the free item list. Prev points to the + * previous entry, unless "free" is the head of the list. + */ +STATIC void +xfs_bmap_del_free( + xfs_bmap_free_t *flist, /* free item list header */ + xfs_bmap_free_item_t *prev, /* previous item on list, if any */ + xfs_bmap_free_item_t *free) /* list item to be freed */ +{ + if (prev) + prev->xbfi_next = free->xbfi_next; + else + flist->xbf_first = free->xbfi_next; + flist->xbf_count--; + kmem_zone_free(xfs_bmap_free_item_zone, free); +} + +/* + * Remove count entries from the extents array for inode "ip", starting + * at index "idx". Copies the remaining items down over the deleted ones, + * and gives back the excess memory. + */ +STATIC void +xfs_bmap_delete_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting delete index */ + xfs_extnum_t count, /* count of items to delete */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extents in list after */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - count; + ovbcopy(&base[idx + count], &base[idx], + (nextents - idx) * sizeof(*base)); + xfs_iext_realloc(ip, -count, whichfork); +} + +/* + * Convert an extents-format file into a btree-format file. + * The new file will have a root block (in the inode) and a single child block. + */ +STATIC int /* error */ +xfs_bmap_extents_to_btree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first-block-allocated */ + xfs_bmap_free_t *flist, /* blocks freed in xaction */ + xfs_btree_cur_t **curp, /* cursor returned to caller */ + int wasdel, /* converting a delayed alloc */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *ablock; /* allocated (child) bt block */ + xfs_buf_t *abp; /* buffer for ablock */ + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_bmbt_rec_t *arp; /* child record pointer */ + xfs_bmbt_block_t *block; /* btree root block */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + xfs_bmbt_rec_t *ep; /* extent list pointer */ + int error; /* error return value */ + xfs_extnum_t i; /* extent list index */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_key_t *kp; /* root block key pointer */ + xfs_mount_t *mp; /* mount structure */ + xfs_extnum_t nextents; /* extent list size */ + xfs_bmbt_ptr_t *pp; /* root block address pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* + * Make space in the inode incore. + */ + xfs_iroot_realloc(ip, 1, whichfork); + ifp->if_flags |= XFS_IFBROOT; + /* + * Fill in the root. + */ + block = ifp->if_broot; + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 1); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + /* + * Need a cursor. Can't allocate until bb_level is filled in. + */ + mp = ip->i_mount; + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + whichfork); + cur->bc_private.b.firstblock = *firstblock; + cur->bc_private.b.flist = flist; + cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; + /* + * Convert to a btree with two levels, one record in root. + */ + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); + args.tp = tp; + args.mp = mp; + if (*firstblock == NULLFSBLOCK) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); + } else if (flist->xbf_low) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = *firstblock; + } else { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.fsbno = *firstblock; + } + args.minlen = args.maxlen = args.prod = 1; + args.total = args.minleft = args.alignment = args.mod = args.isfl = + args.minalignslop = 0; + args.wasdel = wasdel; + *logflagsp = 0; + if ((error = xfs_alloc_vextent(&args))) { + xfs_iroot_realloc(ip, -1, whichfork); + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + /* + * Allocation can't fail, the space was reserved. + */ + ASSERT(args.fsbno != NULLFSBLOCK); + ASSERT(*firstblock == NULLFSBLOCK || + args.agno == XFS_FSB_TO_AGNO(mp, *firstblock) || + (flist->xbf_low && + args.agno > XFS_FSB_TO_AGNO(mp, *firstblock))); + *firstblock = cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + ip->i_d.di_nblocks++; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); + abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0); + /* + * Fill in the child block. + */ + ablock = XFS_BUF_TO_BMBT_BLOCK(abp); + INT_SET(ablock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + INT_ZERO(ablock->bb_level, ARCH_CONVERT); + INT_ZERO(ablock->bb_numrecs, ARCH_CONVERT); + INT_SET(ablock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(ablock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + arp = XFS_BMAP_REC_IADDR(ablock, 1, cur); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + for (ep = ifp->if_u1.if_extents, i = 0; i < nextents; i++, ep++) { + if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) { + *arp++ = *ep; + INT_MOD(ablock->bb_numrecs, ARCH_CONVERT, +1); + } + } + ASSERT(INT_GET(ablock->bb_numrecs, ARCH_CONVERT) == XFS_IFORK_NEXTENTS(ip, whichfork)); + /* + * Fill in the root key and pointer. + */ + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + arp = XFS_BMAP_REC_IADDR(ablock, 1, cur); + INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(arp)); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + INT_SET(*pp, ARCH_CONVERT, args.fsbno); + /* + * Do all this logging at the end so that + * the root is at the right level. + */ + xfs_bmbt_log_block(cur, abp, XFS_BB_ALL_BITS); + xfs_bmbt_log_recs(cur, abp, 1, INT_GET(ablock->bb_numrecs, ARCH_CONVERT)); + ASSERT(*curp == NULL); + *curp = cur; + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FBROOT(whichfork); + return 0; +} + +/* + * Insert new item(s) in the extent list for inode "ip". + * Count new items are inserted at offset idx. + */ +STATIC void +xfs_bmap_insert_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting index of new items */ + xfs_extnum_t count, /* number of inserted items */ + xfs_bmbt_irec_t *new, /* items to insert */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* extent list base */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* extent list size */ + xfs_extnum_t to; /* extent list index */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + xfs_iext_realloc(ip, count, whichfork); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ovbcopy(&base[idx], &base[idx + count], + (nextents - (idx + count)) * sizeof(*base)); + for (to = idx; to < idx + count; to++, new++) + xfs_bmbt_set_all(&base[to], new); +} + +/* + * Convert a local file to an extents file. + * This code is out of bounds for data forks of regular files, + * since the file data needs to get logged so things will stay consistent. + * (The bmap-level manipulations are ok, though). + */ +STATIC int /* error */ +xfs_bmap_local_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated in xaction */ + xfs_extlen_t total, /* total blocks needed by transaction */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + int error; /* error return value */ + int flags; /* logging flags returned */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_local_to_extents"; +#endif + xfs_ifork_t *ifp; /* inode fork pointer */ + + /* + * We don't want to deal with the case of keeping inode data inline yet. + * So sending the data fork of a regular inode is illegal. + */ + ASSERT(!((ip->i_d.di_mode & IFMT) == IFREG && + whichfork == XFS_DATA_FORK)); + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); + flags = 0; + error = 0; + if (ifp->if_bytes) { + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_buf_t *bp; /* buffer for extent list block */ + xfs_bmbt_rec_t *ep; /* extent list pointer */ + + args.tp = tp; + args.mp = ip->i_mount; + ASSERT(ifp->if_flags & XFS_IFINLINE); + /* + * Allocate a block. We know we need only one, since the + * file currently fits in an inode. + */ + if (*firstblock == NULLFSBLOCK) { + args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); + args.type = XFS_ALLOCTYPE_START_BNO; + } else { + args.fsbno = *firstblock; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + } + args.total = total; + args.mod = args.minleft = args.alignment = args.wasdel = + args.isfl = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + if ((error = xfs_alloc_vextent(&args))) + goto done; + /* + * Can't fail, the space was reserved. + */ + ASSERT(args.fsbno != NULLFSBLOCK); + ASSERT(args.len == 1); + *firstblock = args.fsbno; + bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); + bcopy(ifp->if_u1.if_data, (char *)XFS_BUF_PTR(bp), + ifp->if_bytes); + xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); + xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); + xfs_iext_realloc(ip, 1, whichfork); + ep = ifp->if_u1.if_extents; + xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); + xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork); + XFS_IFORK_NEXT_SET(ip, whichfork, 1); + ip->i_d.di_nblocks = 1; + if (XFS_IS_QUOTA_ON(args.mp) && + ip->i_ino != args.mp->m_sb.sb_uquotino && + ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, + 1L); + flags |= XFS_ILOG_FEXT(whichfork); + } else + ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); + ifp->if_flags &= ~XFS_IFINLINE; + ifp->if_flags |= XFS_IFEXTENTS; + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); + flags |= XFS_ILOG_CORE; +done: + *logflagsp = flags; + return error; +} + +xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_do_search_extents( + xfs_bmbt_rec_t *base, /* base of extent list */ + xfs_extnum_t lastx, /* last extent index used */ + xfs_extnum_t nextents, /* extent list size */ + xfs_fileoff_t bno, /* block number searched for */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ +{ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + xfs_bmbt_irec_t got; /* extent list entry, decoded */ + int high; /* high index of binary search */ + int low; /* low index of binary search */ + + if (lastx != NULLEXTNUM && lastx < nextents) + ep = base + lastx; + else + ep = NULL; + prevp->br_startoff = NULLFILEOFF; + if (ep && bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep)) && + bno < got.br_startoff + + (got.br_blockcount = xfs_bmbt_get_blockcount(ep))) + *eofp = 0; + else if (ep && lastx < nextents - 1 && + bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep + 1)) && + bno < got.br_startoff + + (got.br_blockcount = xfs_bmbt_get_blockcount(ep + 1))) { + lastx++; + ep++; + *eofp = 0; + } else if (nextents == 0) + *eofp = 1; + else if (bno == 0 && + (got.br_startoff = xfs_bmbt_get_startoff(base)) == 0) { + ep = base; + lastx = 0; + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + *eofp = 0; + } else { + /* binary search the extents array */ + low = 0; + high = nextents - 1; + while (low <= high) { + XFS_STATS_INC(xfsstats.xs_cmp_exlist); + lastx = (low + high) >> 1; + ep = base + lastx; + got.br_startoff = xfs_bmbt_get_startoff(ep); + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + if (bno < got.br_startoff) + high = lastx - 1; + else if (bno >= got.br_startoff + got.br_blockcount) + low = lastx + 1; + else { + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + *eofp = 0; + *lastxp = lastx; + *gotp = got; + return ep; + } + } + if (bno >= got.br_startoff + got.br_blockcount) { + lastx++; + if (lastx == nextents) { + *eofp = 1; + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + *prevp = got; + ep = NULL; + } else { + *eofp = 0; + xfs_bmbt_get_all(ep, prevp); + ep++; + got.br_startoff = xfs_bmbt_get_startoff(ep); + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + } + } else { + *eofp = 0; + if (ep > base) + xfs_bmbt_get_all(ep - 1, prevp); + } + } + if (ep) { + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + } + *lastxp = lastx; + *gotp = got; + return ep; +} + +/* + * Search the extents list for the inode, for the extent containing bno. + * If bno lies in a hole, point to the next entry. If bno lies past eof, + * *eofp will be set, and *prevp will contain the last entry (null if none). + * Else, *lastxp will be set to the index of the found + * entry; *gotp will contain the entry. + */ +STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_search_extents( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t bno, /* block number searched for */ + int whichfork, /* data or attr fork */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_extnum_t lastx; /* last extent index used */ + xfs_extnum_t nextents; /* extent list size */ + + XFS_STATS_INC(xfsstats.xs_look_exlist); + ifp = XFS_IFORK_PTR(ip, whichfork); + lastx = ifp->if_lastex; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + + return xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, + lastxp, gotp, prevp); +} + + +#ifdef XFS_BMAP_TRACE +/* + * Add a bmap trace buffer entry. Base routine for the others. + */ +STATIC void +xfs_bmap_trace_addentry( + int opcode, /* operation */ + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(ies) */ + xfs_extnum_t cnt, /* count of entries, 1 or 2 */ + xfs_bmbt_rec_t *r1, /* first record */ + xfs_bmbt_rec_t *r2, /* second record or null */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t tr2; + + ASSERT(cnt == 1 || cnt == 2); + ASSERT(r1 != NULL); + if (cnt == 1) { + ASSERT(r2 == NULL); + r2 = &tr2; + bzero(&tr2, sizeof(tr2)); + } else + ASSERT(r2 != NULL); + ktrace_enter(xfs_bmap_trace_buf, + (void *)(__psint_t)(opcode | (whichfork << 16)), + (void *)fname, (void *)desc, (void *)ip, + (void *)(__psint_t)idx, + (void *)(__psint_t)cnt, + (void *)(__psunsigned_t)(ip->i_ino >> 32), + (void *)(__psunsigned_t)(unsigned)ip->i_ino, + (void *)(__psunsigned_t)(INT_GET(r1->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l1, ARCH_CONVERT)) + ); + ASSERT(ip->i_xtrace); + ktrace_enter(ip->i_xtrace, + (void *)(__psint_t)(opcode | (whichfork << 16)), + (void *)fname, (void *)desc, (void *)ip, + (void *)(__psint_t)idx, + (void *)(__psint_t)cnt, + (void *)(__psunsigned_t)(ip->i_ino >> 32), + (void *)(__psunsigned_t)(unsigned)ip->i_ino, + (void *)(__psunsigned_t)(INT_GET(r1->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l1, ARCH_CONVERT)) + ); +} + +/* + * Add bmap trace entry prior to a call to xfs_bmap_delete_exlist. + */ +STATIC void +xfs_bmap_trace_delete( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) deleted */ + xfs_extnum_t cnt, /* count of entries deleted, 1 or 2 */ + int whichfork) /* data or attr fork */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_DELETE, fname, desc, ip, idx, + cnt, &ifp->if_u1.if_extents[idx], + cnt == 2 ? &ifp->if_u1.if_extents[idx + 1] : NULL, + whichfork); +} + +/* + * Add bmap trace entry prior to a call to xfs_bmap_insert_exlist, or + * reading in the extents list from the disk (in the btree). + */ +STATIC void +xfs_bmap_trace_insert( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) inserted */ + xfs_extnum_t cnt, /* count of entries inserted, 1 or 2 */ + xfs_bmbt_irec_t *r1, /* inserted record 1 */ + xfs_bmbt_irec_t *r2, /* inserted record 2 or null */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t tr1; /* compressed record 1 */ + xfs_bmbt_rec_t tr2; /* compressed record 2 if needed */ + + xfs_bmbt_set_all(&tr1, r1); + if (cnt == 2) { + ASSERT(r2 != NULL); + xfs_bmbt_set_all(&tr2, r2); + } else { + ASSERT(cnt == 1); + ASSERT(r2 == NULL); + } + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_INSERT, fname, desc, ip, idx, + cnt, &tr1, cnt == 2 ? &tr2 : NULL, whichfork); +} + +/* + * Add bmap trace entry after updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_post_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry updated */ + int whichfork) /* data or attr fork */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_POST_UP, fname, desc, ip, idx, + 1, &ifp->if_u1.if_extents[idx], NULL, whichfork); +} + +/* + * Add bmap trace entry prior to updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_pre_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry to be updated */ + int whichfork) /* data or attr fork */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_PRE_UP, fname, desc, ip, idx, 1, + &ifp->if_u1.if_extents[idx], NULL, whichfork); +} +#endif /* XFS_BMAP_TRACE */ + +/* + * Compute the worst-case number of indirect blocks that will be used + * for ip's delayed extent of length "len". + */ +STATIC xfs_filblks_t +xfs_bmap_worst_indlen( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_filblks_t len) /* delayed extent length */ +{ + int level; /* btree level number */ + int maxrecs; /* maximum record count at this level */ + xfs_mount_t *mp; /* mount structure */ + xfs_filblks_t rval; /* return value */ + + mp = ip->i_mount; + maxrecs = mp->m_bmap_dmxr[0]; + for (level = 0, rval = 0; + level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK); + level++) { + len += maxrecs - 1; + do_div(len, maxrecs); + rval += len; + if (len == 1) + return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - + level - 1; + if (level == 0) + maxrecs = mp->m_bmap_dmxr[1]; + } + return rval; +} + +#if defined(DEBUG) && defined(XFS_RW_TRACE) +STATIC void +xfs_bunmap_trace( + xfs_inode_t *ip, + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + inst_t *ra) +{ + if (ip->i_rwtrace == NULL) + return; + ktrace_enter(ip->i_rwtrace, + (void *)(__psint_t)XFS_BUNMAPI, + (void *)ip, + (void *)(__psint_t)((ip->i_d.di_size >> 32) & 0xffffffff), + (void *)(__psint_t)(ip->i_d.di_size & 0xffffffff), + (void *)(__psint_t)(((xfs_dfiloff_t)bno >> 32) & 0xffffffff), + (void *)(__psint_t)((xfs_dfiloff_t)bno & 0xffffffff), + (void *)(__psint_t)len, + (void *)(__psint_t)flags, + (void *)(__psint_t)private.p_cpuid, + (void *)ra, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0); +} +#endif + +/* + * Convert inode from non-attributed to attributed. + * Must not be in a transaction, ip must not be locked. + */ +int /* error code */ +xfs_bmap_add_attrfork( + xfs_inode_t *ip, /* incore inode pointer */ + int rsvd) /* OK to allocated reserved blocks in trans */ +{ + int blks; /* space reservation */ + int committed; /* xaction was committed */ + int error; /* error return value */ + xfs_fsblock_t firstblock; /* 1st block/ag allocated */ + xfs_bmap_free_t flist; /* freed extent list */ + int logflags; /* logging flags */ + xfs_mount_t *mp; /* mount structure */ + unsigned long s; /* spinlock spl value */ + xfs_trans_t *tp; /* transaction pointer */ + + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + if (XFS_IFORK_Q(ip)) + return 0; + mp = ip->i_mount; + ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); + tp = xfs_trans_alloc(mp, XFS_TRANS_ADDAFORK); + blks = XFS_ADDAFORK_SPACE_RES(mp); + if (rsvd) + tp->t_flags |= XFS_TRANS_RESERVE; + if ((error = xfs_trans_reserve(tp, blks, XFS_ADDAFORK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT))) + goto error0; + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (XFS_IS_QUOTA_ON(mp)) { + if (rsvd) { + error = xfs_trans_reserve_blkquota_force(tp, ip, blks); + } else { + error = xfs_trans_reserve_blkquota(tp, ip, blks); + } + + if (error) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); + return error; + } + } + if (XFS_IFORK_Q(ip)) + goto error1; + if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { + /* + * For inodes coming from pre-6.2 filesystems. + */ + ASSERT(ip->i_d.di_aformat == 0); + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + } + ASSERT(ip->i_d.di_anextents == 0); + VN_HOLD(XFS_ITOV(ip)); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_DEV: + ip->i_d.di_forkoff = roundup(sizeof(dev_t), 8) >> 3; + break; + case XFS_DINODE_FMT_UUID: + ip->i_d.di_forkoff = roundup(sizeof(uuid_t), 8) >> 3; + break; + case XFS_DINODE_FMT_LOCAL: + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + ip->i_d.di_forkoff = mp->m_attroffset >> 3; + break; + default: + ASSERT(0); + error = XFS_ERROR(EINVAL); + goto error1; + } + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(ip->i_afp == NULL); + ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); + ip->i_afp->if_ext_max = + XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + ip->i_afp->if_flags = XFS_IFEXTENTS; + logflags = 0; + XFS_BMAP_INIT(&flist, &firstblock); + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_LOCAL: + error = xfs_bmap_add_attrfork_local(tp, ip, &firstblock, &flist, + &logflags); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_bmap_add_attrfork_extents(tp, ip, &firstblock, + &flist, &logflags); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_bmap_add_attrfork_btree(tp, ip, &firstblock, &flist, + &logflags); + break; + default: + error = 0; + break; + } + if (logflags) + xfs_trans_log_inode(tp, ip, logflags); + if (error) + goto error2; + if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { + s = XFS_SB_LOCK(mp); + if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { + XFS_SB_VERSION_ADDATTR(&mp->m_sb); + XFS_SB_UNLOCK(mp, s); + xfs_mod_sb(tp, XFS_SB_VERSIONNUM); + } else + XFS_SB_UNLOCK(mp, s); + } + if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) + goto error2; + error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES, NULL); + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + return error; +error2: + xfs_bmap_cancel(&flist); +error1: + ASSERT(ismrlocked(&ip->i_lock,MR_UPDATE)); + xfs_iunlock(ip, XFS_ILOCK_EXCL); +error0: + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + return error; +} + +/* + * Add the extent to the list of extents to be free at transaction end. + * The list is maintained sorted (by block number). + */ +/* ARGSUSED */ +void +xfs_bmap_add_free( + xfs_fsblock_t bno, /* fs block number of extent */ + xfs_filblks_t len, /* length of extent */ + xfs_bmap_free_t *flist, /* list of extents */ + xfs_mount_t *mp) /* mount point structure */ +{ + xfs_bmap_free_item_t *cur; /* current (next) element */ + xfs_bmap_free_item_t *new; /* new element */ + xfs_bmap_free_item_t *prev; /* previous element */ +#ifdef DEBUG + xfs_agnumber_t agno; + xfs_agblock_t agbno; + + ASSERT(bno != NULLFSBLOCK); + ASSERT(len > 0); + ASSERT(len <= MAXEXTLEN); + ASSERT(!ISNULLSTARTBLOCK(bno)); + agno = XFS_FSB_TO_AGNO(mp, bno); + agbno = XFS_FSB_TO_AGBNO(mp, bno); + ASSERT(agno < mp->m_sb.sb_agcount); + ASSERT(agbno < mp->m_sb.sb_agblocks); + ASSERT(len < mp->m_sb.sb_agblocks); + ASSERT(agbno + len <= mp->m_sb.sb_agblocks); +#endif + ASSERT(xfs_bmap_free_item_zone != NULL); + new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); + new->xbfi_startblock = bno; + new->xbfi_blockcount = (xfs_extlen_t)len; + for (prev = NULL, cur = flist->xbf_first; + cur != NULL; + prev = cur, cur = cur->xbfi_next) { + if (cur->xbfi_startblock >= bno) + break; + } + if (prev) + prev->xbfi_next = new; + else + flist->xbf_first = new; + new->xbfi_next = cur; + flist->xbf_count++; +} + +/* + * Compute and fill in the value of the maximum depth of a bmap btree + * in this filesystem. Done once, during mount. + */ +void +xfs_bmap_compute_maxlevels( + xfs_mount_t *mp, /* file system mount structure */ + int whichfork) /* data or attr fork */ +{ + int level; /* btree level */ + uint maxblocks; /* max blocks at this level */ + uint maxleafents; /* max leaf entries possible */ + int maxrootrecs; /* max records in root block */ + int minleafrecs; /* min records in leaf block */ + int minnoderecs; /* min records in node block */ + int sz; /* root block size */ + + /* + * The maximum number of extents in a file, hence the maximum + * number of leaf entries, is controlled by the type of di_nextents + * (a signed 32-bit number, xfs_extnum_t), or by di_anextents + * (a signed 16-bit number, xfs_aextnum_t). + */ + maxleafents = (whichfork == XFS_DATA_FORK) ? MAXEXTNUM : MAXAEXTNUM; + minleafrecs = mp->m_bmap_dmnr[0]; + minnoderecs = mp->m_bmap_dmnr[1]; + sz = (whichfork == XFS_DATA_FORK) ? + mp->m_attroffset : + mp->m_sb.sb_inodesize - mp->m_attroffset; + maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0); + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) { + if (maxblocks <= maxrootrecs) + maxblocks = 1; + else + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + } + mp->m_bm_maxlevels[whichfork] = level; +} + +/* + * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi + * caller. Frees all the extents that need freeing, which must be done + * last due to locking considerations. We never free any extents in + * the first transaction. This is to allow the caller to make the first + * transaction a synchronous one so that the pointers to the data being + * broken in this transaction will be permanent before the data is actually + * freed. This is necessary to prevent blocks from being reallocated + * and written to before the free and reallocation are actually permanent. + * We do not just make the first transaction synchronous here, because + * there are more efficient ways to gain the same protection in some cases + * (see the file truncation code). + * + * Return 1 if the given transaction was committed and a new one + * started, and 0 otherwise in the committed parameter. + */ +/*ARGSUSED*/ +int /* error */ +xfs_bmap_finish( + xfs_trans_t **tp, /* transaction pointer addr */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + xfs_fsblock_t firstblock, /* controlled ag for allocs */ + int *committed) /* xact committed or not */ +{ + xfs_efd_log_item_t *efd; /* extent free data */ + xfs_efi_log_item_t *efi; /* extent free intention */ + int error; /* error return value */ + xfs_bmap_free_item_t *free; /* free extent list item */ + unsigned int logres; /* new log reservation */ + unsigned int logcount; /* new log count */ + xfs_mount_t *mp; /* filesystem mount structure */ + xfs_bmap_free_item_t *next; /* next item on free list */ + xfs_trans_t *ntp; /* new transaction pointer */ + + ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); + if (flist->xbf_count == 0) { + *committed = 0; + return 0; + } + ntp = *tp; + efi = xfs_trans_get_efi(ntp, flist->xbf_count); + for (free = flist->xbf_first; free; free = free->xbfi_next) + xfs_trans_log_efi_extent(ntp, efi, free->xbfi_startblock, + free->xbfi_blockcount); + logres = ntp->t_log_res; + logcount = ntp->t_log_count; + ntp = xfs_trans_dup(*tp); + error = xfs_trans_commit(*tp, 0, NULL); + *tp = ntp; + *committed = 1; + /* + * We have a new transaction, so we should return committed=1, + * even though we're returning an error. + */ + if (error) { + return error; + } + if ((error = xfs_trans_reserve(ntp, 0, logres, 0, XFS_TRANS_PERM_LOG_RES, + logcount))) + return error; + efd = xfs_trans_get_efd(ntp, efi, flist->xbf_count); + for (free = flist->xbf_first; free != NULL; free = next) { + next = free->xbfi_next; + if ((error = xfs_free_extent(ntp, free->xbfi_startblock, + free->xbfi_blockcount))) { + /* + * The bmap free list will be cleaned up at a + * higher level. The EFI will be canceled when + * this transaction is aborted. + * Need to force shutdown here to make sure it + * happens, since this transaction may not be + * dirty yet. + */ + mp = ntp->t_mountp; + if (!XFS_FORCED_SHUTDOWN(mp)) + xfs_force_shutdown(mp, + (error == EFSCORRUPTED) ? + XFS_CORRUPT_INCORE : + XFS_METADATA_IO_ERROR); + return error; + } + xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock, + free->xbfi_blockcount); + xfs_bmap_del_free(flist, NULL, free); + } + return 0; +} + +/* + * Free up any items left in the list. + */ +void +xfs_bmap_cancel( + xfs_bmap_free_t *flist) /* list of bmap_free_items */ +{ + xfs_bmap_free_item_t *free; /* free list item */ + xfs_bmap_free_item_t *next; + + if (flist->xbf_count == 0) + return; + ASSERT(flist->xbf_first != NULL); + for (free = flist->xbf_first; free; free = next) { + next = free->xbfi_next; + xfs_bmap_del_free(flist, NULL, free); + } + ASSERT(flist->xbf_count == 0); +} + +/* + * Returns EINVAL if the specified file is not swappable. + */ +int /* error */ +xfs_bmap_check_swappable( + xfs_inode_t *ip) /* incore inode */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ + xfs_fileoff_t end_fsb; /* last block of file within size */ + xfs_bmbt_irec_t ext; /* extent list entry, decoded */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_fileoff_t lastaddr; /* last block number seen */ + xfs_extnum_t nextents; /* number of extent entries */ + int retval = 0; /* return value */ + + xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + + /* + * Check for a zero length file. + */ + if (ip->i_d.di_size == 0) + goto check_done; + + ASSERT(XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_BTREE || + XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS); + + ifp = &ip->i_df; + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (retval = xfs_iread_extents(NULL, ip, XFS_DATA_FORK))) + goto check_done; + /* + * Scan extents until the file size is reached. Look for + * holes or unwritten extents, since I/O to these would cause + * a transaction. + */ + end_fsb = XFS_B_TO_FSB(ip->i_mount, ip->i_d.di_size); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + for (lastaddr = 0, ep = base; ep < &base[nextents]; ep++) { + xfs_bmbt_get_all(ep, &ext); + if (lastaddr < ext.br_startoff || + ext.br_state != XFS_EXT_NORM) { + goto error_done; + } + if (end_fsb <= (lastaddr = ext.br_startoff + + ext.br_blockcount)) + goto check_done; + } +error_done: + retval = XFS_ERROR(EINVAL); + + +check_done: + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + return retval; +} + +/* + * Returns the file-relative block number of the first unused block(s) + * in the file with at least "len" logically contiguous blocks free. + * This is the lowest-address hole if the file has holes, else the first block + * past the end of file. + * Return 0 if the file is currently local (in-inode). + */ +int /* error */ +xfs_bmap_first_unused( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_extlen_t len, /* size of hole to find */ + xfs_fileoff_t *first_unused, /* unused block */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_fileoff_t lastaddr; /* last block number seen */ + xfs_fileoff_t lowest; /* lowest useful block */ + xfs_fileoff_t max; /* starting useful block */ + xfs_fileoff_t off; /* offset for this block */ + xfs_extnum_t nextents; /* number of extent entries */ + + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE || + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS || + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *first_unused = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + lowest = *first_unused; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + for (lastaddr = 0, max = lowest, ep = base; + ep < &base[nextents]; + ep++) { + off = xfs_bmbt_get_startoff(ep); + /* + * See if the hole before this extent will work. + */ + if (off >= lowest + len && off - max >= len) { + *first_unused = max; + return 0; + } + lastaddr = off + xfs_bmbt_get_blockcount(ep); + max = XFS_FILEOFF_MAX(lastaddr, lowest); + } + *first_unused = max; + return 0; +} + +/* + * Returns the file-relative block number of the last block + 1 before + * last_block (input value) in the file. + * This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_before( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork) /* data or attr fork */ +{ + xfs_fileoff_t bno; /* input file offset */ + int eof; /* hit end of file */ + xfs_bmbt_rec_t *ep; /* pointer to last extent */ + int error; /* error return value */ + xfs_bmbt_irec_t got; /* current extent value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t lastx; /* last extent used */ + xfs_bmbt_irec_t prev; /* previous extent value */ + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EIO); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *last_block = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + bno = *last_block - 1; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + if (eof || xfs_bmbt_get_startoff(ep) > bno) { + if (prev.br_startoff == NULLFILEOFF) + *last_block = 0; + else + *last_block = prev.br_startoff + prev.br_blockcount; + } + /* + * Otherwise *last_block is already the right answer. + */ + return 0; +} + +/* + * Returns the file-relative block number of the first block past eof in + * the file. This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_offset( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to last extent */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extent entries */ + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EIO); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *last_block = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (!nextents) { + *last_block = 0; + return 0; + } + base = &ifp->if_u1.if_extents[0]; + ASSERT(base != NULL); + ep = &base[nextents - 1]; + *last_block = xfs_bmbt_get_startoff(ep) + xfs_bmbt_get_blockcount(ep); + return 0; +} + +/* + * Returns whether the selected fork of the inode has exactly one + * block or not. For the data fork we check this matches di_size, + * implying the file's range is 0..bsize-1. + */ +int /* 1=>1 block, 0=>otherwise */ +xfs_bmap_one_block( + xfs_inode_t *ip, /* incore inode */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *ep; /* ptr to fork's extent */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int rval; /* return value */ + xfs_bmbt_irec_t s; /* internal version of extent */ + +#ifndef DEBUG + if (whichfork == XFS_DATA_FORK) + return ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize; +#endif /* !DEBUG */ + if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1) + return 0; + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + return 0; + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + ep = ifp->if_u1.if_extents; + xfs_bmbt_get_all(ep, &s); + rval = s.br_startoff == 0 && s.br_blockcount == 1; + if (rval && whichfork == XFS_DATA_FORK) + ASSERT(ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize); + return rval; +} + +/* + * Read in the extents to if_extents. + * All inode fields are set up by caller, we just traverse the btree + * and copy the records in. If the file system cannot contain unwritten + * extents, the records are checked for no "state" flags. + */ +int /* error */ +xfs_bmap_read_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *block; /* current btree block */ + xfs_fsblock_t bno; /* block # of "block" */ + xfs_buf_t *bp; /* buffer for "block" */ + int error; /* error return value */ + xfs_exntfmt_t exntf; /* XFS_EXTFMT_NOSTATE, if checking */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_read_extents"; +#endif + xfs_extnum_t i; /* index into the extents list */ + xfs_ifork_t *ifp; /* fork structure */ + int level; /* btree level, for checking */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_bmbt_ptr_t *pp; /* pointer to block address */ + /* REFERENCED */ + xfs_extnum_t room; /* number of entries there's room for */ + xfs_bmbt_rec_t *trp; /* target record pointer */ + + bno = NULLFSBLOCK; + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + exntf = (whichfork != XFS_DATA_FORK) ? XFS_EXTFMT_NOSTATE : + XFS_EXTFMT_INODE(ip); + block = ifp->if_broot; + /* + * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. + */ + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + level = INT_GET(block->bb_level, ARCH_CONVERT); + pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes); + ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO); + ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks); + bno = INT_GET(*pp, ARCH_CONVERT); + /* + * Go down the tree until leaf level is reached, following the first + * pointer (leftmost) at each level. + */ + while (level-- > 0) { + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, level), + error0); + if (level == 0) + break; + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, + 1, mp->m_bmap_dmxr[1]); +#ifndef __KERNEL__ + XFS_WANT_CORRUPTED_GOTO( + XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), + error0); +#else /* additional, temporary, debugging code */ + if (!(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)))) { + cmn_err(CE_NOTE, + "xfs_bmap_read_extents: FSB Sanity Check:"); + if (!(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount)) + cmn_err(CE_NOTE, + "bad AG count %d < agcount %d", + XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)), + mp->m_sb.sb_agcount); + if (!(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks)) + cmn_err(CE_NOTE, + "bad AG BNO %d < %d", + XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)), + mp->m_sb.sb_agblocks); + error = XFS_ERROR(EFSCORRUPTED); + goto error0; + } +#endif + bno = INT_GET(*pp, ARCH_CONVERT); + xfs_trans_brelse(tp, bp); + } + /* + * Here with bp and block set to the leftmost leaf node in the tree. + */ + room = ifp->if_bytes / (uint)sizeof(*trp); + trp = ifp->if_u1.if_extents; + i = 0; + /* + * Loop over all leaf nodes. Copy information to the extent list. + */ + for (;;) { + xfs_bmbt_rec_t *frp; + xfs_fsblock_t nextbno; + xfs_extnum_t num_recs; + + + num_recs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + if (i + num_recs > room) { + ASSERT(i + num_recs <= room); + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, (btree extents). " + "Unmount and run xfs_repair.", + (unsigned long long) ip->i_ino); + goto error0; + } +#ifndef __KERNEL__ + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, 0), + error0); +#else /* additional, temporary, debugging code */ + if (!(XFS_BMAP_SANITY_CHECK(mp, block, 0))) { + cmn_err(CE_NOTE, + "xfs_bmap_read_extents: BMAP Sanity Check:"); + if (!(INT_GET(block->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC)) + cmn_err(CE_NOTE, + "bb_magic 0x%x", + INT_GET(block->bb_magic, ARCH_CONVERT)); + if (!(INT_GET(block->bb_level, ARCH_CONVERT) == level)) + cmn_err(CE_NOTE, + "bb_level %d", + INT_GET(block->bb_level, ARCH_CONVERT)); + if (!(INT_GET(block->bb_numrecs, ARCH_CONVERT) > 0)) + cmn_err(CE_NOTE, + "bb_numrecs %d", + INT_GET(block->bb_numrecs, ARCH_CONVERT)); + if (!(INT_GET(block->bb_numrecs, ARCH_CONVERT) <= (mp)->m_bmap_dmxr[(level) != 0])) + cmn_err(CE_NOTE, + "bb_numrecs %d < m_bmap_dmxr[] %d", + INT_GET(block->bb_numrecs, ARCH_CONVERT), + (mp)->m_bmap_dmxr[(level) != 0]); + error = XFS_ERROR(EFSCORRUPTED); + goto error0; + } +#endif + /* + * Read-ahead the next leaf block, if any. + */ + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + if (nextbno != NULLFSBLOCK) + xfs_btree_reada_bufl(mp, nextbno, 1); + /* + * Copy records into the extent list. + */ + frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + bcopy(frp, trp, num_recs * sizeof(*frp)); + if (exntf == XFS_EXTFMT_NOSTATE) { + /* + * Check all attribute bmap btree records and + * any "older" data bmap btree records for a + * set bit in the "extent flag" position. + */ + if (xfs_check_nostate_extents(trp, num_recs)) { + goto error0; + } + } + trp += num_recs; + i += num_recs; + xfs_trans_brelse(tp, bp); + bno = nextbno; + /* + * If we've reached the end, stop. + */ + if (bno == NULLFSBLOCK) + break; + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + ASSERT(i == ifp->if_bytes / (uint)sizeof(*trp)); + ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork)); + xfs_bmap_trace_exlist(fname, ip, i, whichfork); + return 0; +error0: + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); +} + +#ifdef XFS_BMAP_TRACE +/* + * Add bmap trace insert entries for all the contents of the extent list. + */ +void +xfs_bmap_trace_exlist( + char *fname, /* function name */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t cnt, /* count of entries in the list */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_bmbt_rec_t *ep; /* current entry in extent list */ + xfs_extnum_t idx; /* extent list entry number */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_irec_t s; /* extent list record */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(cnt == ifp->if_bytes / (uint)sizeof(*base)); + base = ifp->if_u1.if_extents; + for (idx = 0, ep = base; idx < cnt; idx++, ep++) { + xfs_bmbt_get_all(ep, &s); + xfs_bmap_trace_insert(fname, "exlist", ip, idx, 1, &s, NULL, + whichfork); + } +} +#endif + +#ifdef DEBUG +/* + * Validate that the bmbt_irecs being returned from bmapi are valid + * given the callers original parameters. Specifically check the + * ranges of the returned irecs to ensure that they only extent beyond + * the given parameters if the XFS_BMAPI_ENTIRE flag was set. + */ +STATIC void +xfs_bmap_validate_ret( + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + xfs_bmbt_irec_t *mval, + int nmap, + int ret_nmap) +{ + int i; /* index to map values */ + + ASSERT(ret_nmap <= nmap); + + for (i = 0; i < ret_nmap; i++) { + ASSERT(mval[i].br_blockcount > 0); + if (!(flags & XFS_BMAPI_ENTIRE)) { + ASSERT(mval[i].br_startoff >= bno); + ASSERT(mval[i].br_blockcount <= len); + ASSERT(mval[i].br_startoff + mval[i].br_blockcount <= + bno + len); + } else { + ASSERT(mval[i].br_startoff < bno + len); + ASSERT(mval[i].br_startoff + mval[i].br_blockcount > + bno); + } + ASSERT(i == 0 || + mval[i - 1].br_startoff + mval[i - 1].br_blockcount == + mval[i].br_startoff); + if ((flags & XFS_BMAPI_WRITE) && !(flags & XFS_BMAPI_DELAY)) + ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK && + mval[i].br_startblock != HOLESTARTBLOCK); + ASSERT(mval[i].br_state == XFS_EXT_NORM || + mval[i].br_state == XFS_EXT_UNWRITTEN); + } +} +#endif /* DEBUG */ + + +/* + * Map file blocks to filesystem blocks. + * File range is given by the bno/len pair. + * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set) + * into a hole or past eof. + * Only allocates blocks from a single allocation group, + * to avoid locking problems. + * The returned value in "firstblock" from the first call in a transaction + * must be remembered and presented to subsequent calls in "firstblock". + * An upper bound for the number of blocks to be allocated is supplied to + * the first call in "total"; if no allocation group has that many free + * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). + */ +int /* error */ +xfs_bmapi( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting file offs. mapped */ + xfs_filblks_t len, /* length to map in file */ + int flags, /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_extlen_t total, /* total blocks needed */ + xfs_bmbt_irec_t *mval, /* output: map values */ + int *nmap, /* i/o: mval size/count */ + xfs_bmap_free_t *flist) /* i/o: list extents to free */ +{ + xfs_fsblock_t abno; /* allocated block number */ + xfs_extlen_t alen; /* allocated extent length */ + xfs_fileoff_t aoff; /* allocated file offset */ + xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ + char contig; /* allocation must be one extent */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + char delay; /* this request is for delayed alloc */ + xfs_fileoff_t end; /* end of mapped file region */ + int eof; /* we've hit the end of extent list */ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + int error; /* error return */ + char exact; /* don't do all of wasdelayed extent */ + xfs_bmbt_irec_t got; /* current extent list record */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extlen_t indlen; /* indirect blocks length */ + char inhole; /* current location is hole in file */ + xfs_extnum_t lastx; /* last useful extent number */ + int logflags; /* flags for transaction logging */ + xfs_extlen_t minleft; /* min blocks left after allocation */ + xfs_extlen_t minlen; /* min allocation size */ + xfs_mount_t *mp; /* xfs mount structure */ + int n; /* current extent index */ + int nallocs; /* number of extents alloc\'d */ + xfs_extnum_t nextents; /* number of extents in file */ + xfs_fileoff_t obno; /* old block number (offset) */ + xfs_bmbt_irec_t prev; /* previous extent list record */ + char stateless; /* ignore state flag set */ + int tmp_logflags; /* temp flags holder */ + char trim; /* output trimmed to match range */ + char userdata; /* allocating non-metadata */ + char wasdelay; /* old extent was delayed */ + int whichfork; /* data or attr fork */ + char wr; /* this is a write request */ + char rsvd; /* OK to allocate reserved blocks */ +#ifdef DEBUG + xfs_fileoff_t orig_bno; /* original block number value */ + int orig_flags; /* original flags arg value */ + xfs_filblks_t orig_len; /* original value of len arg */ + xfs_bmbt_irec_t *orig_mval; /* original value of mval */ + int orig_nmap; /* original value of *nmap */ + + orig_bno = bno; + orig_len = len; + orig_flags = flags; + orig_mval = mval; + orig_nmap = *nmap; +#endif + ASSERT(*nmap >= 1); + ASSERT(*nmap <= XFS_BMAP_MAX_NMAP || !(flags & XFS_BMAPI_WRITE)); + whichfork = (flags & XFS_BMAPI_ATTRFORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) { +#ifdef __KERNEL__ /* additional, temporary, debugging code */ + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + mp = ip->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + if ((wr = (flags & XFS_BMAPI_WRITE)) != 0) + XFS_STATS_INC(xfsstats.xs_blk_mapw); + else + XFS_STATS_INC(xfsstats.xs_blk_mapr); + delay = (flags & XFS_BMAPI_DELAY) != 0; + trim = (flags & XFS_BMAPI_ENTIRE) == 0; + userdata = (flags & XFS_BMAPI_METADATA) == 0; + exact = (flags & XFS_BMAPI_EXACT) != 0; + rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; + contig = (flags & XFS_BMAPI_CONTIG) != 0; + /* + * stateless is used to combine extents which + * differ only due to the state of the extents. + * This technique is used from xfs_getbmap() + * when the caller does not wish to see the + * separation (which is the default). + * + * This technique is also used when writing a + * buffer which has been partially written, + * (usually by being flushed during a chunkread), + * to ensure one write takes place. This also + * prevents a change in the xfs inode extents at + * this time, intentionally. This change occurs + * on completion of the write operation, in + * xfs_strat_comp(), where the xfs_bmapi() call + * is transactioned, and the extents combined. + */ + stateless = (flags & XFS_BMAPI_IGSTATE) != 0; + if (stateless && wr) /* if writing unwritten space, no */ + wr = 0; /* allocations are allowed */ + ASSERT(wr || !delay); + logflags = 0; + nallocs = 0; + cur = NULL; + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + ASSERT(wr && tp); + if ((error = xfs_bmap_local_to_extents(tp, ip, firstblock, total, + &logflags, whichfork))) + goto error0; + } + if (wr && *firstblock == NULLFSBLOCK) { + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) + minleft = INT_GET(ifp->if_broot->bb_level, ARCH_CONVERT) + 1; + else + minleft = 1; + } else + minleft = 0; + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + goto error0; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + n = 0; + end = bno + len; + obno = bno; + bma.ip = NULL; + while (bno < end && n < *nmap) { + /* + * Reading past eof, act as though there's a hole + * up to end. + */ + if (eof && !wr) + got.br_startoff = end; + inhole = eof || got.br_startoff > bno; + wasdelay = wr && !inhole && !delay && + ISNULLSTARTBLOCK(got.br_startblock); + /* + * First, deal with the hole before the allocated space + * that we found, if any. + */ + if (wr && (inhole || wasdelay)) { + /* + * For the wasdelay case, we could also just + * allocate the stuff asked for in this bmap call + * but that wouldn't be as good. + */ + if (wasdelay && !exact) { + alen = (xfs_extlen_t)got.br_blockcount; + aoff = got.br_startoff; + if (lastx != NULLEXTNUM && lastx) { + ep = &ifp->if_u1.if_extents[lastx - 1]; + xfs_bmbt_get_all(ep, &prev); + } + } else if (wasdelay) { + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(len, + (got.br_startoff + + got.br_blockcount) - bno); + aoff = bno; + } else { + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(len, MAXEXTLEN); + if (!eof) + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(alen, + got.br_startoff - bno); + aoff = bno; + } + minlen = contig ? alen : 1; + if (delay) { + indlen = (xfs_extlen_t) + xfs_bmap_worst_indlen(ip, alen); + ASSERT(indlen > 0); + /* + * Make a transaction-less quota reservation for + * delayed allocation blocks. This number gets + * adjusted later. + * We return EDQUOT if we haven't allocated + * blks already inside this loop; + */ + if (XFS_IS_QUOTA_ON(ip->i_mount) && + xfs_trans_reserve_blkquota(NULL, ip, + (long)alen)) { + if (n == 0) { + *nmap = 0; + ASSERT(cur == NULL); + return XFS_ERROR(EDQUOT); + } + break; + } + if (xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, + -(alen + indlen), rsvd)) { + if (XFS_IS_QUOTA_ON(ip->i_mount)) + xfs_trans_unreserve_blkquota( + NULL, ip, (long)alen); + break; + } + ip->i_delayed_blks += alen; + abno = NULLSTARTBLOCK(indlen); + } else { + /* + * If first time, allocate and fill in + * once-only bma fields. + */ + if (bma.ip == NULL) { + bma.tp = tp; + bma.ip = ip; + bma.prevp = &prev; + bma.gotp = &got; + bma.total = total; + bma.userdata = 0; + } + /* Indicate if this is the first user data + * in the file, or just any user data. + */ + if (userdata) { + bma.userdata = (aoff == 0) ? + XFS_ALLOC_INITIAL_USER_DATA : + XFS_ALLOC_USERDATA; + } + /* + * Fill in changeable bma fields. + */ + bma.eof = eof; + bma.firstblock = *firstblock; + bma.alen = alen; + bma.off = aoff; + bma.wasdel = wasdelay; + bma.minlen = minlen; + bma.low = flist->xbf_low; + bma.minleft = minleft; + /* + * Only want to do the alignment at the + * eof if it is userdata and allocation length + * is larger than a stripe unit. + */ + if (mp->m_dalign && alen >= mp->m_dalign && + userdata && whichfork == XFS_DATA_FORK) { + if ((error = xfs_bmap_isaeof(ip, aoff, + whichfork, &bma.aeof))) + goto error0; + } else + bma.aeof = 0; + /* + * Call allocator. + */ + if ((error = xfs_bmap_alloc(&bma))) + goto error0; + /* + * Copy out result fields. + */ + abno = bma.rval; + if ((flist->xbf_low = bma.low)) + minleft = 0; + alen = bma.alen; + aoff = bma.off; + ASSERT(*firstblock == NULLFSBLOCK || + XFS_FSB_TO_AGNO(ip->i_mount, + *firstblock) == + XFS_FSB_TO_AGNO(ip->i_mount, + bma.firstblock) || + (flist->xbf_low && + XFS_FSB_TO_AGNO(ip->i_mount, + *firstblock) < + XFS_FSB_TO_AGNO(ip->i_mount, + bma.firstblock))); + *firstblock = bma.firstblock; + if (cur) + cur->bc_private.b.firstblock = + *firstblock; + if (abno == NULLFSBLOCK) + break; + if ((ifp->if_flags & XFS_IFBROOT) && !cur) { + cur = xfs_btree_init_cursor(ip->i_mount, + tp, NULL, 0, XFS_BTNUM_BMAP, + ip, whichfork); + cur->bc_private.b.firstblock = + *firstblock; + cur->bc_private.b.flist = flist; + } + /* + * Bump the number of extents we've allocated + * in this call. + */ + nallocs++; + } + if (cur) + cur->bc_private.b.flags = + wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0; + got.br_startoff = aoff; + got.br_startblock = abno; + got.br_blockcount = alen; + got.br_state = XFS_EXT_NORM; /* assume normal */ + /* + * Determine state of extent, and the filesystem. + * A wasdelay extent has been initialized, so + * shouldn't be flagged as unwritten. + */ + if (wr && XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + if (!wasdelay && (flags & XFS_BMAPI_PREALLOC)) + got.br_state = XFS_EXT_UNWRITTEN; + } + error = xfs_bmap_add_extent(ip, lastx, &cur, &got, + firstblock, flist, &tmp_logflags, whichfork, + rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + lastx = ifp->if_lastex; + ep = &ifp->if_u1.if_extents[lastx]; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmbt_get_all(ep, &got); + ASSERT(got.br_startoff <= aoff); + ASSERT(got.br_startoff + got.br_blockcount >= + aoff + alen); +#ifdef DEBUG + if (delay) { + ASSERT(ISNULLSTARTBLOCK(got.br_startblock)); + ASSERT(STARTBLOCKVAL(got.br_startblock) > 0); + } + ASSERT(got.br_state == XFS_EXT_NORM || + got.br_state == XFS_EXT_UNWRITTEN); +#endif + /* + * Fall down into the found allocated space case. + */ + } else if (inhole) { + /* + * Reading in a hole. + */ + mval->br_startoff = bno; + mval->br_startblock = HOLESTARTBLOCK; + mval->br_blockcount = + XFS_FILBLKS_MIN(len, got.br_startoff - bno); + mval->br_state = XFS_EXT_NORM; + bno += mval->br_blockcount; + len -= mval->br_blockcount; + mval++; + n++; + continue; + } + /* + * Then deal with the allocated space we found. + */ + ASSERT(ep != NULL); + if (trim && (got.br_startoff + got.br_blockcount > obno)) { + if (obno > bno) + bno = obno; + ASSERT((bno >= obno) || (n == 0)); + ASSERT(bno < end); + mval->br_startoff = bno; + if (ISNULLSTARTBLOCK(got.br_startblock)) { + ASSERT(!wr || delay); + mval->br_startblock = DELAYSTARTBLOCK; + } else + mval->br_startblock = + got.br_startblock + + (bno - got.br_startoff); + /* + * Return the minimum of what we got and what we + * asked for for the length. We can use the len + * variable here because it is modified below + * and we could have been there before coming + * here if the first part of the allocation + * didn't overlap what was asked for. + */ + mval->br_blockcount = + XFS_FILBLKS_MIN(end - bno, got.br_blockcount - + (bno - got.br_startoff)); + mval->br_state = got.br_state; + ASSERT(mval->br_blockcount <= len); + } else { + *mval = got; + if (ISNULLSTARTBLOCK(mval->br_startblock)) { + ASSERT(!wr || delay); + mval->br_startblock = DELAYSTARTBLOCK; + } + } + + /* + * Check if writing previously allocated but + * unwritten extents. + */ + if (wr && mval->br_state == XFS_EXT_UNWRITTEN && + ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) { + /* + * Modify (by adding) the state flag, if writing. + */ + ASSERT(mval->br_blockcount <= len); + if ((ifp->if_flags & XFS_IFBROOT) && !cur) { + cur = xfs_btree_init_cursor(ip->i_mount, + tp, NULL, 0, XFS_BTNUM_BMAP, + ip, whichfork); + cur->bc_private.b.firstblock = + *firstblock; + cur->bc_private.b.flist = flist; + } + mval->br_state = XFS_EXT_NORM; + error = xfs_bmap_add_extent(ip, lastx, &cur, mval, + firstblock, flist, &tmp_logflags, whichfork, + rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + lastx = ifp->if_lastex; + ep = &ifp->if_u1.if_extents[lastx]; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmbt_get_all(ep, &got); + /* + * We may have combined previously unwritten + * space with written space, so generate + * another request. + */ + if (mval->br_blockcount < len) + continue; + } + + ASSERT(!trim || + ((mval->br_startoff + mval->br_blockcount) <= end)); + ASSERT(!trim || (mval->br_blockcount <= len) || + (mval->br_startoff < obno)); + bno = mval->br_startoff + mval->br_blockcount; + len = end - bno; + if (n > 0 && mval->br_startoff == mval[-1].br_startoff) { + ASSERT(mval->br_startblock == mval[-1].br_startblock); + ASSERT(mval->br_blockcount > mval[-1].br_blockcount); + ASSERT(mval->br_state == mval[-1].br_state); + mval[-1].br_blockcount = mval->br_blockcount; + mval[-1].br_state = mval->br_state; + } else if (n > 0 && mval->br_startblock != DELAYSTARTBLOCK && + mval[-1].br_startblock != DELAYSTARTBLOCK && + mval[-1].br_startblock != HOLESTARTBLOCK && + mval->br_startblock == + mval[-1].br_startblock + mval[-1].br_blockcount && + (stateless || mval[-1].br_state == mval->br_state)) { + ASSERT(mval->br_startoff == + mval[-1].br_startoff + mval[-1].br_blockcount); + mval[-1].br_blockcount += mval->br_blockcount; + } else if (n > 0 && + mval->br_startblock == DELAYSTARTBLOCK && + mval[-1].br_startblock == DELAYSTARTBLOCK && + mval->br_startoff == + mval[-1].br_startoff + mval[-1].br_blockcount) { + mval[-1].br_blockcount += mval->br_blockcount; + mval[-1].br_state = mval->br_state; + } else if (!((n == 0) && + ((mval->br_startoff + mval->br_blockcount) <= + obno))) { + mval++; + n++; + } + /* + * If we're done, stop now. Stop when we've allocated + * XFS_BMAP_MAX_NMAP extents no matter what. Otherwise + * the transaction may get too big. + */ + if (bno >= end || n >= *nmap || nallocs >= *nmap) + break; + /* + * Else go on to the next record. + */ + ep++; + lastx++; + if (lastx >= nextents) { + eof = 1; + prev = got; + } else + xfs_bmbt_get_all(ep, &got); + } + ifp->if_lastex = lastx; + *nmap = n; + /* + * Transform from btree to extents, give it cur. + */ + if (tp && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && + XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + ASSERT(wr && cur); + error = xfs_bmap_btree_to_extents(tp, ip, cur, + &tmp_logflags, whichfork, 0); + logflags |= tmp_logflags; + if (error) + goto error0; + } + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max); + error = 0; + +error0: + /* + * Log everything. Do this after conversion, there's no point in + * logging the extent list if we've converted to btree format. + */ + if ((logflags & XFS_ILOG_FEXT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + logflags &= ~XFS_ILOG_FEXT(whichfork); + else if ((logflags & XFS_ILOG_FBROOT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + logflags &= ~XFS_ILOG_FBROOT(whichfork); + /* + * Log whatever the flags say, even if error. Otherwise we might miss + * detecting a case where the data is changed, there's an error, + * and it's not logged so we don't shutdown when we should. + */ + if (logflags) { + ASSERT(tp && wr); + xfs_trans_log_inode(tp, ip, logflags); + } + if (cur) { + if (!error) { + ASSERT(*firstblock == NULLFSBLOCK || + XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) == + XFS_FSB_TO_AGNO(ip->i_mount, + cur->bc_private.b.firstblock) || + (flist->xbf_low && + XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) < + XFS_FSB_TO_AGNO(ip->i_mount, + cur->bc_private.b.firstblock))); + *firstblock = cur->bc_private.b.firstblock; + } + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + if (!error) + xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, + orig_nmap, *nmap); + return error; +} + +/* + * Map file blocks to filesystem blocks, simple version. + * One block (extent) only, read-only. + * For flags, only the XFS_BMAPI_ATTRFORK flag is examined. + * For the other flag values, the effect is as if XFS_BMAPI_METADATA + * was set and all the others were clear. + */ +int /* error */ +xfs_bmapi_single( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + xfs_fsblock_t *fsb, /* output: mapped block */ + xfs_fileoff_t bno) /* starting file offs. mapped */ +{ + int eof; /* we've hit the end of extent list */ + int error; /* error return */ + xfs_bmbt_irec_t got; /* current extent list record */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t lastx; /* last useful extent number */ + xfs_bmbt_irec_t prev; /* previous extent list record */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) { +#ifdef __KERNEL__ /* additional, temporary, debugging code */ + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return XFS_ERROR(EIO); + XFS_STATS_INC(xfsstats.xs_blk_mapr); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + (void)xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + /* + * Reading past eof, act as though there's a hole + * up to end. + */ + if (eof || got.br_startoff > bno) { + *fsb = NULLFSBLOCK; + return 0; + } + ASSERT(!ISNULLSTARTBLOCK(got.br_startblock)); + ASSERT(bno < got.br_startoff + got.br_blockcount); + *fsb = got.br_startblock + (bno - got.br_startoff); + ifp->if_lastex = lastx; + return 0; +} + +/* + * Unmap (remove) blocks from a file. + * If nexts is nonzero then the number of extents to remove is limited to + * that value. If not all extents in the block range can be removed then + * *done is set. + */ +int /* error */ +xfs_bunmapi( + xfs_trans_t *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting offset to unmap */ + xfs_filblks_t len, /* length to unmap in file */ + int flags, /* misc flags */ + xfs_extnum_t nexts, /* number of extents max */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + int *done) /* set if not done yet */ +{ + int async; /* xactions can be async */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + xfs_bmbt_irec_t del; /* extent being deleted */ + int eof; /* is deleting at eof */ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + int error; /* error return value */ + xfs_extnum_t extno; /* extent number in list */ + xfs_bmbt_irec_t got; /* current extent list entry */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int isrt; /* freeing in rt area */ + xfs_extnum_t lastx; /* last extent index used */ + int logflags; /* transaction logging flags */ + xfs_extlen_t mod; /* rt extent offset */ + xfs_mount_t *mp; /* mount structure */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_bmbt_irec_t prev; /* previous extent list entry */ + xfs_fileoff_t start; /* first file offset deleted */ + int tmp_logflags; /* partial logging flags */ + int wasdel; /* was a delayed alloc extent */ + int whichfork; /* data or attribute fork */ + int rsvd; /* OK to allocate reserved blocks */ + xfs_fsblock_t sum; + + xfs_bunmap_trace(ip, bno, len, flags, (inst_t *)__return_address); + whichfork = (flags & XFS_BMAPI_ATTRFORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + ifp = XFS_IFORK_PTR(ip, whichfork); + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) { +#ifdef __KERNEL__ /* additional, temporary, debugging code */ + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + mp = ip->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + async = flags & XFS_BMAPI_ASYNC; + rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; + ASSERT(len > 0); + ASSERT(nexts >= 0); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *done = 1; + return 0; + } + XFS_STATS_INC(xfsstats.xs_blk_unmap); + isrt = (whichfork == XFS_DATA_FORK) && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME); + start = bno; + bno = start + len - 1; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + /* + * Check to see if the given block number is past the end of the + * file, back up to the last block if so... + */ + if (eof) { + ep = &ifp->if_u1.if_extents[--lastx]; + xfs_bmbt_get_all(ep, &got); + bno = got.br_startoff + got.br_blockcount - 1; + } + logflags = 0; + if (ifp->if_flags & XFS_IFBROOT) { + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + whichfork); + cur->bc_private.b.firstblock = *firstblock; + cur->bc_private.b.flist = flist; + cur->bc_private.b.flags = 0; + } else + cur = NULL; + extno = 0; + while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 && + (nexts == 0 || extno < nexts)) { + /* + * Is the found extent after a hole in which bno lives? + * Just back up to the previous extent, if so. + */ + if (got.br_startoff > bno) { + if (--lastx < 0) + break; + ep--; + xfs_bmbt_get_all(ep, &got); + } + /* + * Is the last block of this extent before the range + * we're supposed to delete? If so, we're done. + */ + bno = XFS_FILEOFF_MIN(bno, + got.br_startoff + got.br_blockcount - 1); + if (bno < start) + break; + /* + * Then deal with the (possibly delayed) allocated space + * we found. + */ + ASSERT(ep != NULL); + del = got; + wasdel = ISNULLSTARTBLOCK(del.br_startblock); + if (got.br_startoff < start) { + del.br_startoff = start; + del.br_blockcount -= start - got.br_startoff; + if (!wasdel) + del.br_startblock += start - got.br_startoff; + } + if (del.br_startoff + del.br_blockcount > bno + 1) + del.br_blockcount = bno + 1 - del.br_startoff; + sum = del.br_startblock + del.br_blockcount; + if (isrt && + (mod = do_mod(sum, mp->m_sb.sb_rextsize))) { + /* + * Realtime extent not lined up at the end. + * The extent could have been split into written + * and unwritten pieces, or we could just be + * unmapping part of it. But we can't really + * get rid of part of a realtime extent. + */ + if (del.br_state == XFS_EXT_UNWRITTEN || + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + /* + * This piece is unwritten, or we're not + * using unwritten extents. Skip over it. + */ + ASSERT(bno >= mod); + bno -= mod > del.br_blockcount ? + del.br_blockcount : mod; + if (bno < got.br_startoff) { + if (--lastx >= 0) + xfs_bmbt_get_all(--ep, &got); + } + continue; + } + /* + * It's written, turn it unwritten. + * This is better than zeroing it. + */ + ASSERT(del.br_state == XFS_EXT_NORM); + ASSERT(xfs_trans_get_block_res(tp) > 0); + /* + * If this spans a realtime extent boundary, + * chop it back to the start of the one we end at. + */ + if (del.br_blockcount > mod) { + del.br_startoff += del.br_blockcount - mod; + del.br_startblock += del.br_blockcount - mod; + del.br_blockcount = mod; + } + del.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx, &cur, &del, + firstblock, flist, &logflags, XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } + if (isrt && (mod = do_mod(del.br_startblock, mp->m_sb.sb_rextsize))) { + /* + * Realtime extent is lined up at the end but not + * at the front. We'll get rid of full extents if + * we can. + */ + mod = mp->m_sb.sb_rextsize - mod; + if (del.br_blockcount > mod) { + del.br_blockcount -= mod; + del.br_startoff += mod; + del.br_startblock += mod; + } else if ((del.br_startoff == start && + (del.br_state == XFS_EXT_UNWRITTEN || + xfs_trans_get_block_res(tp) == 0)) || + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + /* + * Can't make it unwritten. There isn't + * a full extent here so just skip it. + */ + ASSERT(bno >= del.br_blockcount); + bno -= del.br_blockcount; + if (bno < got.br_startoff) { + if (--lastx >= 0) + xfs_bmbt_get_all(--ep, &got); + } + continue; + } else if (del.br_state == XFS_EXT_UNWRITTEN) { + /* + * This one is already unwritten. + * It must have a written left neighbor. + * Unwrite the killed part of that one and + * try again. + */ + ASSERT(lastx > 0); + xfs_bmbt_get_all(ep - 1, &prev); + ASSERT(prev.br_state == XFS_EXT_NORM); + ASSERT(!ISNULLSTARTBLOCK(prev.br_startblock)); + ASSERT(del.br_startblock == + prev.br_startblock + prev.br_blockcount); + if (prev.br_startoff < start) { + mod = start - prev.br_startoff; + prev.br_blockcount -= mod; + prev.br_startblock += mod; + prev.br_startoff = start; + } + prev.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx - 1, &cur, + &prev, firstblock, flist, &logflags, + XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } else { + ASSERT(del.br_state == XFS_EXT_NORM); + del.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx, &cur, + &del, firstblock, flist, &logflags, + XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } + } + if (wasdel) { + ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, + (int)del.br_blockcount, rsvd); + if (XFS_IS_QUOTA_ON(ip->i_mount)) { + ASSERT(ip->i_ino != mp->m_sb.sb_uquotino); + ASSERT(ip->i_ino != mp->m_sb.sb_gquotino); + if (!isrt) + xfs_trans_unreserve_blkquota(NULL, ip, + (long)del.br_blockcount); + else + xfs_trans_unreserve_rtblkquota(NULL, ip, + (long)del.br_blockcount); + } + ip->i_delayed_blks -= del.br_blockcount; + if (cur) + cur->bc_private.b.flags |= + XFS_BTCUR_BPRV_WASDEL; + } else if (cur) + cur->bc_private.b.flags &= ~XFS_BTCUR_BPRV_WASDEL; + /* + * If it's the case where the directory code is running + * with no block reservation, and the deleted block is in + * the middle of its extent, and the resulting insert + * of an extent would cause transformation to btree format, + * then reject it. The calling code will then swap + * blocks around instead. + * We have to do this now, rather than waiting for the + * conversion to btree format, since the transaction + * will be dirty. + */ + if (!wasdel && xfs_trans_get_block_res(tp) == 0 && + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) >= ifp->if_ext_max && + del.br_startoff > got.br_startoff && + del.br_startoff + del.br_blockcount < + got.br_startoff + got.br_blockcount) { + error = XFS_ERROR(ENOSPC); + goto error0; + } + error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del, + flags, &tmp_logflags, whichfork, rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + bno = del.br_startoff - 1; +nodelete: + lastx = ifp->if_lastex; + /* + * If not done go on to the next (previous) record. + * Reset ep in case the extents array was re-alloced. + */ + ep = &ifp->if_u1.if_extents[lastx]; + if (bno != (xfs_fileoff_t)-1 && bno >= start) { + if (lastx >= XFS_IFORK_NEXTENTS(ip, whichfork) || + xfs_bmbt_get_startoff(ep) > bno) { + lastx--; + ep--; + } + if (lastx >= 0) + xfs_bmbt_get_all(ep, &got); + extno++; + } + } + ifp->if_lastex = lastx; + *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0; + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* + * Convert to a btree if necessary. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { + ASSERT(cur == NULL); + error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, + &cur, 0, &tmp_logflags, whichfork); + logflags |= tmp_logflags; + if (error) + goto error0; + } + /* + * transform from btree to extents, give it cur + */ + else if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && + XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + ASSERT(cur != NULL); + error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags, + whichfork, async); + logflags |= tmp_logflags; + if (error) + goto error0; + } + /* + * transform from extents to local? + */ + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + error = 0; +error0: + /* + * Log everything. Do this after conversion, there's no point in + * logging the extent list if we've converted to btree format. + */ + if ((logflags & XFS_ILOG_FEXT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + logflags &= ~XFS_ILOG_FEXT(whichfork); + else if ((logflags & XFS_ILOG_FBROOT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + logflags &= ~XFS_ILOG_FBROOT(whichfork); + /* + * Log inode even in the error case, if the transaction + * is dirty we'll need to shut down the filesystem. + */ + if (logflags) + xfs_trans_log_inode(tp, ip, logflags); + if (cur) { + if (!error) { + *firstblock = cur->bc_private.b.firstblock; + cur->bc_private.b.allocated = 0; + } + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + return error; +} + +/* + * Fcntl interface to xfs_bmapi. + */ +int /* error code */ +xfs_getbmap( + bhv_desc_t *bdp, /* XFS behavior descriptor*/ + struct getbmap *bmv, /* user bmap structure */ + void *ap, /* pointer to user's array */ + int interface) /* interface flags */ +{ + __int64_t bmvend; /* last block requested */ + int error; /* return value */ + __int64_t fixlen; /* length for -1 case */ + int i; /* extent number */ + xfs_inode_t *ip; /* xfs incore inode pointer */ + vnode_t *vp; /* corresponding vnode */ + int lock; /* lock state */ + xfs_bmbt_irec_t *map; /* buffer for user's data */ + xfs_mount_t *mp; /* file system mount point */ + int nex; /* # of user extents can do */ + int nexleft; /* # of user extents left */ + int subnex; /* # of bmapi's can do */ + int nmap; /* number of map entries */ + struct getbmap out; /* output structure */ + int whichfork; /* data or attr fork */ + int prealloced; /* this is a file with + * preallocated data space */ + int sh_unwritten; /* true, if unwritten */ + /* extents listed seperately */ + int bmapi_flags; /* flags for xfs_bmapi */ + __int32_t oflags; /* getbmapx bmv_oflags field */ + + ip = XFS_BHVTOI(bdp); + vp = BHV_TO_VNODE(bdp); + + whichfork = interface & BMV_IF_ATTRFORK ? + XFS_ATTR_FORK : XFS_DATA_FORK; + sh_unwritten = (interface & BMV_IF_PREALLOC) != 0; + + + /* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not + * generate a DMAPI read event. Otherwise, if the DM_EVENT_READ + * bit is set for the file, generate a read event in order + * that the DMAPI application may do its thing before we return + * the extents. Usually this means restoring user file data to + * regions of the file that look like holes. + * + * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify + * BMV_IF_NO_DMAPI_READ so that read events are generated. + * If this were not true, callers of ioctl( XFS_IOC_GETBMAP ) + * could misinterpret holes in a DMAPI file as true holes, + * when in fact they may represent offline user data. + */ + if ( (interface & BMV_IF_NO_DMAPI_READ) == 0 + && DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) + && whichfork == XFS_DATA_FORK) { + + error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, + 0, 0, 0, NULL); + if (error) + return XFS_ERROR(error); + } + + if (whichfork == XFS_ATTR_FORK) { + if (XFS_IFORK_Q(ip)) { + if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE && + ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EINVAL); + } else if (ip->i_d.di_aformat != 0 && + ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); + return XFS_ERROR(EFSCORRUPTED); + } + } else if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_format != XFS_DINODE_FMT_BTREE && + ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EINVAL); + + mp = ip->i_mount; + + if (whichfork == XFS_DATA_FORK) { + if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) { + prealloced = 1; + fixlen = XFS_MAX_FILE_OFFSET; + } else { + prealloced = 0; + fixlen = ip->i_d.di_size; + } + } else { + prealloced = 0; + fixlen = 1LL << 32; + } + + if (bmv->bmv_length == -1) { + fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); + bmv->bmv_length = MAX( (__int64_t)(fixlen - bmv->bmv_offset), + (__int64_t)0); + } else if (bmv->bmv_length < 0) + return XFS_ERROR(EINVAL); + if (bmv->bmv_length == 0) { + bmv->bmv_entries = 0; + return 0; + } + + nex = bmv->bmv_count - 1; + + if (nex <= 0) + return XFS_ERROR(EINVAL); + + bmvend = bmv->bmv_offset + bmv->bmv_length; + + xfs_ilock(ip, XFS_IOLOCK_SHARED); + + if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) { + + VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); + } + + ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0); + + lock = xfs_ilock_map_shared(ip); + + /* + * Don't let nex be bigger than the number of extents + * we can have assuming alternating holes and real extents. + */ + if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) + nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; + + bmapi_flags = XFS_BMAPI_AFLAG(whichfork) | + ((sh_unwritten) ? 0 : XFS_BMAPI_IGSTATE); + + subnex = 16; /* XXXjtk - need a #define? */ + + /* + * Allocate enough space to handle "subnex" maps at a time. + */ + map = kmem_alloc(subnex * sizeof(*map), KM_SLEEP); + + bmv->bmv_entries = 0; + + if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0) { + error = 0; + goto unlock_and_return; + } + + nexleft = nex; + + do { + if (nexleft > subnex) + nmap = subnex; + else + nmap = nexleft; + + error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), + XFS_BB_TO_FSB(mp, bmv->bmv_length), + bmapi_flags, NULL, 0, + map, &nmap, NULL); + ASSERT(nmap <= subnex); + + if (error) + goto unlock_and_return; + + for (error = i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { + nexleft--; + + oflags = 0; + + out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff); + out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount); + + ASSERT(map[i].br_startblock != DELAYSTARTBLOCK); + + if ( prealloced + && map[i].br_startblock == HOLESTARTBLOCK + && out.bmv_offset + out.bmv_length == bmvend) { + /* + * came to hole at end of file + */ + goto unlock_and_return; + } else { + if (map[i].br_startblock == HOLESTARTBLOCK) + out.bmv_block = -1; + else + out.bmv_block = + XFS_FSB_TO_DB(ip, map[i].br_startblock); + + /* return either a getbmap or a getbmapx structure. */ + + if (interface & BMV_IF_EXTENDED) { + struct getbmapx outx; + + GETBMAP_CONVERT(out,outx); + + outx.bmv_oflags = oflags; + outx.bmv_unused1 = outx.bmv_unused2 = 0; + + if (copy_to_user(ap, &outx, sizeof(outx))) { + error = XFS_ERROR(EFAULT); + goto unlock_and_return; + } + } else { + if (copy_to_user(ap, &out, sizeof(out))) { + error = XFS_ERROR(EFAULT); + goto unlock_and_return; + } + } + + bmv->bmv_offset = out.bmv_offset + out.bmv_length; + bmv->bmv_length = MAX( (__int64_t)0, + (__int64_t)(bmvend - bmv->bmv_offset) ); + + bmv->bmv_entries++; + + if (interface & BMV_IF_EXTENDED) + ap = (void *)((struct getbmapx *)ap + 1); + else + ap = (void *)((struct getbmap *)ap + 1); + } + } + } while (nmap && nexleft && bmv->bmv_length); + +unlock_and_return: + xfs_iunlock_map_shared(ip, lock); + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + + kmem_free(map, subnex * sizeof(*map)); + + return error; +} + +/* + * Check the last inode extent to determine whether this allocation will result + * in blocks being allocated at the end of the file. When we allocate new data + * blocks at the end of the file which do not start at the previous data block, + * we will try to align the new blocks at stripe unit boundaries. + */ +int /* error */ +xfs_bmap_isaeof( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t off, /* file offset in fsblocks */ + int whichfork, /* data or attribute fork */ + char *aeof) /* return value */ +{ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *lastrec; /* extent list entry pointer */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_bmbt_irec_t s; /* expanded extent list entry */ + + ASSERT(whichfork == XFS_DATA_FORK); + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(NULL, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *aeof = 1; + return 0; + } + /* + * Go to the last extent + */ + lastrec = &ifp->if_u1.if_extents[nextents - 1]; + xfs_bmbt_get_all(lastrec, &s); + /* + * Check we are allocating in the last extent (for delayed allocations) + * or past the last extent for non-delayed allocations. + */ + *aeof = (off >= s.br_startoff && + off < s.br_startoff + s.br_blockcount && + ISNULLSTARTBLOCK(s.br_startblock)) || + off >= s.br_startoff + s.br_blockcount; + return 0; +} + +/* + * Check if the endoff is outside the last extent. If so the caller will grow + * the allocation to a stripe unit boundary. + */ +int /* error */ +xfs_bmap_eof( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t endoff, /* file offset in fsblocks */ + int whichfork, /* data or attribute fork */ + int *eof) /* result value */ +{ + xfs_fsblock_t blockcount; /* extent block count */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *lastrec; /* extent list entry pointer */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_fileoff_t startoff; /* extent starting file offset */ + + ASSERT(whichfork == XFS_DATA_FORK); + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(NULL, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *eof = 1; + return 0; + } + /* + * Go to the last extent + */ + lastrec = &ifp->if_u1.if_extents[nextents - 1]; + startoff = xfs_bmbt_get_startoff(lastrec); + blockcount = xfs_bmbt_get_blockcount(lastrec); + *eof = endoff >= startoff + blockcount; + return 0; +} + +#ifdef XFSDEBUG +/* + * Check that the extents list for the inode ip is in the right order. + */ +STATIC void +xfs_bmap_check_extents( + xfs_inode_t *ip, /* incore inode pointer */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extents list */ + xfs_bmbt_rec_t *ep; /* current extent entry */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extents in list */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + for (ep = base; ep < &base[nextents - 1]; ep++) { + xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)ep, + (void *)(ep + 1)); + } +} + +STATIC +xfs_buf_t * +xfs_bmap_get_bp( + xfs_btree_cur_t *cur, + xfs_fsblock_t bno) +{ + int i; + xfs_buf_t *bp; + + if (!cur) + return(NULL); + + bp = NULL; + for(i = 0; i < XFS_BTREE_MAXLEVELS; i++) { + bp = cur->bc_bufs[i]; + if (!bp) break; + if (XFS_BUF_ADDR(bp) == bno) + break; /* Found it */ + } + if (i == XFS_BTREE_MAXLEVELS) + bp = NULL; + + if (!bp) { /* Chase down all the log items to see if the bp is there */ + xfs_log_item_chunk_t *licp; + xfs_trans_t *tp; + + tp = cur->bc_tp; + licp = &tp->t_items; + while (!bp && licp != NULL) { + if (XFS_LIC_ARE_ALL_FREE(licp)) { + licp = licp->lic_next; + continue; + } + for (i = 0; i < licp->lic_unused; i++) { + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + xfs_buf_log_item_t *bip; + xfs_buf_t *lbp; + + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + lip = lidp->lid_item; + if (lip->li_type != XFS_LI_BUF) + continue; + + bip = (xfs_buf_log_item_t *)lip; + lbp = bip->bli_buf; + + if (XFS_BUF_ADDR(lbp) == bno) { + bp = lbp; + break; /* Found it */ + } + } + licp = licp->lic_next; + } + } + return(bp); +} + +void +xfs_check_block( + xfs_bmbt_block_t *block, + xfs_mount_t *mp, + int root, + short sz) +{ + int i, j, dmxr; + xfs_bmbt_ptr_t *pp, *thispa; /* pointer to block address */ + xfs_bmbt_key_t *prevp, *keyp; + + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + + prevp = NULL; + for( i = 1; i <= INT_GET(block->bb_numrecs, ARCH_CONVERT);i++) { + dmxr = mp->m_bmap_dmxr[0]; + + if (root) { + keyp = XFS_BMAP_BROOT_KEY_ADDR(block, i, sz); + } else { + keyp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, i, dmxr); + } + + if (prevp) { + xfs_btree_check_key(XFS_BTNUM_BMAP, prevp, keyp); + } + prevp = keyp; + + /* + * Compare the block numbers to see if there are dups. + */ + + if (root) { + pp = XFS_BMAP_BROOT_PTR_ADDR(block, i, sz); + } else { + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, i, dmxr); + } + for (j = i+1; j <= INT_GET(block->bb_numrecs, ARCH_CONVERT); j++) { + if (root) { + thispa = XFS_BMAP_BROOT_PTR_ADDR(block, j, sz); + } else { + thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, j, dmxr); + } + if (INT_GET(*thispa, ARCH_CONVERT) == INT_GET(*pp, ARCH_CONVERT)) { + printk("xfs_check_block: thispa(%d) == pp(%d) %Ld\n", + j, i, INT_GET(*thispa, ARCH_CONVERT)); + panic("xfs_check_block: ptrs are equal in node\n"); + } + } + } +} + +/* + * Check that the extents for the inode ip are in the right order in all + * btree leaves. + */ + +STATIC void +xfs_bmap_check_leaf_extents( + xfs_btree_cur_t *cur, /* btree cursor or null */ + xfs_inode_t *ip, /* incore inode pointer */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *block; /* current btree block */ + xfs_fsblock_t bno; /* block # of "block" */ + xfs_buf_t *bp; /* buffer for "block" */ + int error; /* error return value */ + xfs_extnum_t i=0; /* index into the extents list */ + xfs_ifork_t *ifp; /* fork structure */ + int level; /* btree level, for checking */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_bmbt_ptr_t *pp; /* pointer to block address */ + xfs_bmbt_rec_t *ep, *lastp; /* extent pointers in block entry */ + int bp_release = 0; + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) { + return; + } + + bno = NULLFSBLOCK; + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + block = ifp->if_broot; + /* + * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. + */ + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + level = INT_GET(block->bb_level, ARCH_CONVERT); + xfs_check_block(block, mp, 1, ifp->if_broot_bytes); + pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes); + ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO); + ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks); + bno = INT_GET(*pp, ARCH_CONVERT); + /* + * Go down the tree until leaf level is reached, following the first + * pointer (leftmost) at each level. + */ + while (level-- > 0) { + /* See if buf is in cur first */ + bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); + if (bp) { + bp_release = 0; + } else { + bp_release = 1; + } + if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + goto error_norelse; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, level), + error0); + if (level == 0) + break; + + /* + * Check this block for basic sanity (increasing keys and + * no duplicate blocks). + */ + + xfs_check_block(block, mp, 0, 0); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, + 1, mp->m_bmap_dmxr[1]); + XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), error0); + bno = INT_GET(*pp, ARCH_CONVERT); + if (bp_release) { + bp_release = 0; + xfs_trans_brelse(NULL, bp); + } + } + + /* + * Here with bp and block set to the leftmost leaf node in the tree. + */ + i = 0; + + /* + * Loop over all leaf nodes checking that all extents are in the right order. + */ + lastp = NULL; + for (;;) { + xfs_bmbt_rec_t *frp; + xfs_fsblock_t nextbno; + xfs_extnum_t num_recs; + + + num_recs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + + /* + * Read-ahead the next leaf block, if any. + */ + + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + + /* + * Check all the extents to make sure they are OK. + * If we had a previous block, the last entry should + * conform with the first entry in this one. + */ + + frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + + for (ep = frp;ep < frp + (num_recs - 1); ep++) { + if (lastp) { + xfs_btree_check_rec(XFS_BTNUM_BMAP, + (void *)lastp, (void *)ep); + } + xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)ep, + (void *)(ep + 1)); + } + lastp = frp + num_recs - 1; /* For the next iteration */ + + i += num_recs; + if (bp_release) { + bp_release = 0; + xfs_trans_brelse(NULL, bp); + } + bno = nextbno; + /* + * If we've reached the end, stop. + */ + if (bno == NULLFSBLOCK) + break; + + bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); + if (bp) { + bp_release = 0; + } else { + bp_release = 1; + } + if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + goto error_norelse; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + if (bp_release) { + bp_release = 0; + xfs_trans_brelse(NULL, bp); + } + return; + +error0: + printk("at error0\n"); + if (bp_release) + xfs_trans_brelse(NULL, bp); +error_norelse: + printk("xfs_bmap_check_leaf_extents: BAD after btree leaves for %d extents\n", i); + panic("xfs_bmap_check_leaf_extents: CORRUPTED BTREE OR SOMETHING"); + return; +} +#endif + +/* + * Count fsblocks of the given fork. + */ +int /* error */ +xfs_bmap_count_blocks( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + int *count) /* out: count of blocks */ +{ + xfs_bmbt_block_t *block; /* current btree block */ + xfs_fsblock_t bno; /* block # of "block" */ + xfs_ifork_t *ifp; /* fork structure */ + int level; /* btree level, for checking */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_bmbt_ptr_t *pp; /* pointer to block address */ + + bno = NULLFSBLOCK; + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) { + if (xfs_bmap_count_leaves(ifp->if_u1.if_extents, + ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t), + count) < 0) { + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; + } + + /* + * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. + */ + block = ifp->if_broot; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + level = INT_GET(block->bb_level, ARCH_CONVERT); + pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes); + ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO); + ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks); + bno = INT_GET(*pp, ARCH_CONVERT); + + if (xfs_bmap_count_tree(mp, tp, bno, level, count) < 0) { + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); + return XFS_ERROR(EFSCORRUPTED); + } + + return 0; +} + +/* + * Recursively walks each level of a btree + * to count total fsblocks is use. + */ +int /* error */ +xfs_bmap_count_tree( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t blockno, /* file system block number */ + int levelin, /* level in btree */ + int *count) /* Count of blocks */ +{ + int error; + xfs_buf_t *bp, *nbp; + int level = levelin; + xfs_bmbt_ptr_t *pp; + xfs_fsblock_t bno = blockno; + xfs_fsblock_t nextbno; + xfs_bmbt_block_t *block, *nextblock; + int numrecs; + xfs_bmbt_rec_t *frp; + + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF))) + return error; + *count += 1; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + + if (--level) { + /* Not at node above leafs, count this level of nodes */ + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + while (nextbno != NULLFSBLOCK) { + if ((error = xfs_btree_read_bufl(mp, tp, nextbno, + 0, &nbp, XFS_BMAP_BTREE_REF))) + return error; + *count += 1; + nextblock = XFS_BUF_TO_BMBT_BLOCK(nbp); + nextbno = INT_GET(nextblock->bb_rightsib, ARCH_CONVERT); + xfs_trans_brelse(tp, nbp); + } + + /* Dive to the next level */ + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); + bno = INT_GET(*pp, ARCH_CONVERT); + if ((error = + xfs_bmap_count_tree(mp, tp, bno, level, count)) < 0) { + xfs_trans_brelse(tp, bp); + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); + return XFS_ERROR(EFSCORRUPTED); + } + xfs_trans_brelse(tp, bp); + } else { + /* count all level 1 nodes and their leaves */ + for (;;) { + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, 1, mp->m_bmap_dmxr[0]); + if (xfs_bmap_count_leaves(frp, numrecs, count) < 0) { + xfs_trans_brelse(tp, bp); + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); + return XFS_ERROR(EFSCORRUPTED); + } + xfs_trans_brelse(tp, bp); + if (nextbno == NULLFSBLOCK) + break; + bno = nextbno; + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + *count += 1; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + } + return 0; +} + +/* + * Count leaf blocks given a pointer to an extent list. + */ +int +xfs_bmap_count_leaves( + xfs_bmbt_rec_t *frp, + int numrecs, + int *count) +{ + int b; + + for ( b = 1; b <= numrecs; b++, frp++) + *count += xfs_bmbt_get_blockcount(frp); + return 0; +} + diff -Nur linux-2.4.19/fs/xfs/xfs_bmap.h linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap.h --- linux-2.4.19/fs/xfs/xfs_bmap.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BMAP_H__ +#define __XFS_BMAP_H__ + +struct getbmap; +struct xfs_bmbt_irec; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * List of extents to be free "later". + * The list is kept sorted on xbf_startblock. + */ +typedef struct xfs_bmap_free_item +{ + xfs_fsblock_t xbfi_startblock;/* starting fs block number */ + xfs_extlen_t xbfi_blockcount;/* number of blocks in extent */ + struct xfs_bmap_free_item *xbfi_next; /* link to next entry */ +} xfs_bmap_free_item_t; + +/* + * Header for free extent list. + */ +typedef struct xfs_bmap_free +{ + xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ + int xbf_count; /* count of items on list */ + int xbf_low; /* kludge: alloc in low mode */ +} xfs_bmap_free_t; + +#define XFS_BMAP_MAX_NMAP 4 + +/* + * Flags for xfs_bmapi + */ +#define XFS_BMAPI_WRITE 0x001 /* write operation: allocate space */ +#define XFS_BMAPI_DELAY 0x002 /* delayed write operation */ +#define XFS_BMAPI_ENTIRE 0x004 /* return entire extent, not trimmed */ +#define XFS_BMAPI_METADATA 0x008 /* mapping metadata not user data */ +#define XFS_BMAPI_EXACT 0x010 /* allocate only to spec'd bounds */ +#define XFS_BMAPI_ATTRFORK 0x020 /* use attribute fork not data */ +#define XFS_BMAPI_ASYNC 0x040 /* bunmapi xactions can be async */ +#define XFS_BMAPI_RSVBLOCKS 0x080 /* OK to alloc. reserved data blocks */ +#define XFS_BMAPI_PREALLOC 0x100 /* preallocation op: unwritten space */ +#define XFS_BMAPI_IGSTATE 0x200 /* Ignore state - */ + /* combine contig. space */ +#define XFS_BMAPI_CONTIG 0x400 /* must allocate only one extent */ +#define XFS_BMAPI_DIRECT_IO 0x800 /* Flag from cxfs client, not used + * by xfs directly. Indicates alloc + * request is for direct I/O not + * extent conversion by server */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAPI_AFLAG) +int xfs_bmapi_aflag(int w); +#define XFS_BMAPI_AFLAG(w) xfs_bmapi_aflag(w) +#else +#define XFS_BMAPI_AFLAG(w) ((w) == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : 0) +#endif + +/* + * Special values for xfs_bmbt_irec_t br_startblock field. + */ +#define DELAYSTARTBLOCK ((xfs_fsblock_t)-1LL) +#define HOLESTARTBLOCK ((xfs_fsblock_t)-2LL) + +/* + * Trace operations for bmap extent tracing + */ +#define XFS_BMAP_KTRACE_DELETE 1 +#define XFS_BMAP_KTRACE_INSERT 2 +#define XFS_BMAP_KTRACE_PRE_UP 3 +#define XFS_BMAP_KTRACE_POST_UP 4 + +#define XFS_BMAP_TRACE_SIZE 4096 /* size of global trace buffer */ +#define XFS_BMAP_KTRACE_SIZE 32 /* size of per-inode trace buffer */ + +#if defined(XFS_ALL_TRACE) +#define XFS_BMAP_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BMAP_TRACE +#endif + + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_INIT) +void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp); +#define XFS_BMAP_INIT(flp,fbp) xfs_bmap_init(flp,fbp) +#else +#define XFS_BMAP_INIT(flp,fbp) \ + ((flp)->xbf_first = NULL, (flp)->xbf_count = 0, \ + (flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK) +#endif + +/* + * Argument structure for xfs_bmap_alloc. + */ +typedef struct xfs_bmalloca { + xfs_fsblock_t firstblock; /* i/o first block allocated */ + xfs_fsblock_t rval; /* starting block of new extent */ + xfs_fileoff_t off; /* offset in file filling in */ + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_inode *ip; /* incore inode pointer */ + struct xfs_bmbt_irec *prevp; /* extent before the new one */ + struct xfs_bmbt_irec *gotp; /* extent after, or delayed */ + xfs_extlen_t alen; /* i/o length asked/allocated */ + xfs_extlen_t total; /* total blocks needed for xaction */ + xfs_extlen_t minlen; /* mininum allocation size (blocks) */ + xfs_extlen_t minleft; /* amount must be left after alloc */ + char eof; /* set if allocating past last extent */ + char wasdel; /* replacing a delayed allocation */ + char userdata;/* set if is user data */ + char low; /* low on space, using seq'l ags */ + char aeof; /* allocated space at eof */ +} xfs_bmalloca_t; + +#ifdef __KERNEL__ +/* + * Convert inode from non-attributed to attributed. + * Must not be in a transaction, ip must not be locked. + */ +int /* error code */ +xfs_bmap_add_attrfork( + struct xfs_inode *ip, /* incore inode pointer */ + int rsvd); /* flag for reserved block allocation */ + +/* + * Add the extent to the list of extents to be free at transaction end. + * The list is maintained sorted (by block number). + */ +void +xfs_bmap_add_free( + xfs_fsblock_t bno, /* fs block number of extent */ + xfs_filblks_t len, /* length of extent */ + xfs_bmap_free_t *flist, /* list of extents */ + struct xfs_mount *mp); /* mount point structure */ + +/* + * Routine to clean up the free list data structure when + * an error occurs during a transaction. + */ +void +xfs_bmap_cancel( + xfs_bmap_free_t *flist); /* free list to clean up */ + +/* + * Routine to check if a specified inode is swap capable. + */ +int +xfs_bmap_check_swappable( + struct xfs_inode *ip); /* incore inode */ + +/* + * Compute and fill in the value of the maximum depth of a bmap btree + * in this filesystem. Done once, during mount. + */ +void +xfs_bmap_compute_maxlevels( + struct xfs_mount *mp, /* file system mount structure */ + int whichfork); /* data or attr fork */ + +/* + * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi + * caller. Frees all the extents that need freeing, which must be done + * last due to locking considerations. + * + * Return 1 if the given transaction was committed and a new one allocated, + * and 0 otherwise. + */ +int /* error */ +xfs_bmap_finish( + struct xfs_trans **tp, /* transaction pointer addr */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + xfs_fsblock_t firstblock, /* controlled a.g. for allocs */ + int *committed); /* xact committed or not */ + +/* + * Returns the file-relative block number of the first unused block in the file. + * This is the lowest-address hole if the file has holes, else the first block + * past the end of file. + */ +int /* error */ +xfs_bmap_first_unused( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_extlen_t len, /* size of hole to find */ + xfs_fileoff_t *unused, /* unused block num */ + int whichfork); /* data or attr fork */ + +/* + * Returns the file-relative block number of the last block + 1 before + * last_block (input value) in the file. + * This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_before( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork); /* data or attr fork */ + +/* + * Returns the file-relative block number of the first block past eof in + * the file. This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_offset( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t *unused, /* last block num */ + int whichfork); /* data or attr fork */ + +/* + * Returns whether the selected fork of the inode has exactly one + * block or not. For the data fork we check this matches di_size, + * implying the file's range is 0..bsize-1. + */ +int +xfs_bmap_one_block( + struct xfs_inode *ip, /* incore inode */ + int whichfork); /* data or attr fork */ + +/* + * Read in the extents to iu_extents. + * All inode fields are set up by caller, we just traverse the btree + * and copy the records in. + */ +int /* error */ +xfs_bmap_read_extents( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + int whichfork); /* data or attr fork */ + +#if defined(XFS_BMAP_TRACE) +/* + * Add bmap trace insert entries for all the contents of the extent list. + */ +void +xfs_bmap_trace_exlist( + char *fname, /* function name */ + struct xfs_inode *ip, /* incore inode pointer */ + xfs_extnum_t cnt, /* count of entries in list */ + int whichfork); /* data or attr fork */ +#else +#define xfs_bmap_trace_exlist(f,ip,c,w) +#endif + +/* + * Map file blocks to filesystem blocks. + * File range is given by the bno/len pair. + * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set) + * into a hole or past eof. + * Only allocates blocks from a single allocation group, + * to avoid locking problems. + * The returned value in "firstblock" from the first call in a transaction + * must be remembered and presented to subsequent calls in "firstblock". + * An upper bound for the number of blocks to be allocated is supplied to + * the first call in "total"; if no allocation group has that many free + * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). + */ +int /* error */ +xfs_bmapi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting file offs. mapped */ + xfs_filblks_t len, /* length to map in file */ + int flags, /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_extlen_t total, /* total blocks needed */ + struct xfs_bmbt_irec *mval, /* output: map values */ + int *nmap, /* i/o: mval size/count */ + xfs_bmap_free_t *flist); /* i/o: list extents to free */ + +/* + * Map file blocks to filesystem blocks, simple version. + * One block only, read-only. + * For flags, only the XFS_BMAPI_ATTRFORK flag is examined. + * For the other flag values, the effect is as if XFS_BMAPI_METADATA + * was set and all the others were clear. + */ +int /* error */ +xfs_bmapi_single( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + xfs_fsblock_t *fsb, /* output: mapped block */ + xfs_fileoff_t bno); /* starting file offs. mapped */ + +/* + * Unmap (remove) blocks from a file. + * If nexts is nonzero then the number of extents to remove is limited to + * that value. If not all extents in the block range can be removed then + * *done is set. + */ +int /* error */ +xfs_bunmapi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting offset to unmap */ + xfs_filblks_t len, /* length to unmap in file */ + int flags, /* XFS_BMAPI_... */ + xfs_extnum_t nexts, /* number of extents max */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + int *done); /* set if not done yet */ + +/* + * Fcntl interface to xfs_bmapi. + */ +int /* error code */ +xfs_getbmap( + bhv_desc_t *bdp, /* XFS behavior descriptor*/ + struct getbmap *bmv, /* user bmap structure */ + void *ap, /* pointer to user's array */ + int iflags); /* interface flags */ + +/* + * Check the last inode extent to determine whether this allocation will result + * in blocks being allocated at the end of the file. When we allocate new data + * blocks at the end of the file which do not start at the previous data block, + * we will try to align the new blocks at stripe unit boundaries. + */ +int +xfs_bmap_isaeof( + struct xfs_inode *ip, + xfs_fileoff_t off, + int whichfork, + char *aeof); + +/* + * Check if the endoff is outside the last extent. If so the caller will grow + * the allocation to a stripe unit boundary + */ +int +xfs_bmap_eof( + struct xfs_inode *ip, + xfs_fileoff_t endoff, + int whichfork, + int *eof); + +/* + * Count fsblocks of the given fork. + */ +int +xfs_bmap_count_blocks( + xfs_trans_t *tp, + xfs_inode_t *ip, + int whichfork, + int *count); + +/* + * Check an extent list, which has just been read, for + * any bit in the extent flag field. + */ +int +xfs_check_nostate_extents( + xfs_bmbt_rec_t *ep, + xfs_extnum_t num); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_BMAP_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_bmap_btree.c linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap_btree.c --- linux-2.4.19/fs/xfs/xfs_bmap_btree.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap_btree.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,2634 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#ifdef DEBUG +ktrace_t *xfs_bmbt_trace_buf; +#endif + +/* + * Prototypes for internal btree functions. + */ + + +STATIC int xfs_bmbt_killroot(xfs_btree_cur_t *, int); +STATIC void xfs_bmbt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_bmbt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC int xfs_bmbt_lshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_bmbt_rshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_bmbt_split(xfs_btree_cur_t *, int, xfs_fsblock_t *, + xfs_bmbt_key_t *, xfs_btree_cur_t **, int *); +STATIC int xfs_bmbt_updkey(xfs_btree_cur_t *, xfs_bmbt_key_t *, int); + + +#if defined(XFS_BMBT_TRACE) +/* + * Add a trace buffer entry for the arguments given to the routine, + * generic form. + */ +STATIC void +xfs_bmbt_trace_enter( + char *func, + xfs_btree_cur_t *cur, + char *s, + int type, + int line, + __psunsigned_t a0, + __psunsigned_t a1, + __psunsigned_t a2, + __psunsigned_t a3, + __psunsigned_t a4, + __psunsigned_t a5, + __psunsigned_t a6, + __psunsigned_t a7, + __psunsigned_t a8, + __psunsigned_t a9, + __psunsigned_t a10) +{ + xfs_inode_t *ip; + int whichfork; + + ip = cur->bc_private.b.ip; + whichfork = cur->bc_private.b.whichfork; + ktrace_enter(xfs_bmbt_trace_buf, + (void *)((__psint_t)type | (whichfork << 8) | (line << 16)), + (void *)func, (void *)s, (void *)ip, (void *)cur, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, (void *)a7, + (void *)a8, (void *)a9, (void *)a10); + ASSERT(ip->i_btrace); + ktrace_enter(ip->i_btrace, + (void *)((__psint_t)type | (whichfork << 8) | (line << 16)), + (void *)func, (void *)s, (void *)ip, (void *)cur, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, (void *)a7, + (void *)a8, (void *)a9, (void *)a10); +} +/* + * Add a trace buffer entry for arguments, for a buffer & 1 integer arg. + */ +STATIC void +xfs_bmbt_trace_argbi( + char *func, + xfs_btree_cur_t *cur, + xfs_buf_t *b, + int i, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGBI, line, + (__psunsigned_t)b, i, 0, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for a buffer & 2 integer args. + */ +STATIC void +xfs_bmbt_trace_argbii( + char *func, + xfs_btree_cur_t *cur, + xfs_buf_t *b, + int i0, + int i1, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGBII, line, + (__psunsigned_t)b, i0, i1, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for 3 block-length args + * and an integer arg. + */ +STATIC void +xfs_bmbt_trace_argfffi( + char *func, + xfs_btree_cur_t *cur, + xfs_dfiloff_t o, + xfs_dfsbno_t b, + xfs_dfilblks_t i, + int j, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGFFFI, line, + o >> 32, (int)o, b >> 32, (int)b, + i >> 32, (int)i, (int)j, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for one integer arg. + */ +STATIC void +xfs_bmbt_trace_argi( + char *func, + xfs_btree_cur_t *cur, + int i, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGI, line, + i, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for int, fsblock, key. + */ +STATIC void +xfs_bmbt_trace_argifk( + char *func, + xfs_btree_cur_t *cur, + int i, + xfs_fsblock_t f, + xfs_bmbt_key_t *k, + int line) +{ + xfs_dfsbno_t d; + xfs_dfiloff_t o; + + d = (xfs_dfsbno_t)f; + o = INT_GET(k->br_startoff, ARCH_CONVERT); + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line, + i, d >> 32, (int)d, o >> 32, + (int)o, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for int, fsblock, rec. + */ +STATIC void +xfs_bmbt_trace_argifr( + char *func, + xfs_btree_cur_t *cur, + int i, + xfs_fsblock_t f, + xfs_bmbt_rec_t *r, + int line) +{ + xfs_dfsbno_t b; + xfs_dfilblks_t c; + xfs_dfsbno_t d; + xfs_dfiloff_t o; + xfs_bmbt_irec_t s; + + d = (xfs_dfsbno_t)f; + xfs_bmbt_get_all(r, &s); + o = (xfs_dfiloff_t)s.br_startoff; + b = (xfs_dfsbno_t)s.br_startblock; + c = s.br_blockcount; + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFR, line, + i, d >> 32, (int)d, o >> 32, + (int)o, b >> 32, (int)b, c >> 32, + (int)c, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for int, key. + */ +STATIC void +xfs_bmbt_trace_argik( + char *func, + xfs_btree_cur_t *cur, + int i, + xfs_bmbt_key_t *k, + int line) +{ + xfs_dfiloff_t o; + + o = INT_GET(k->br_startoff, ARCH_CONVERT); + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line, + i, o >> 32, (int)o, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for the cursor/operation. + */ +STATIC void +xfs_bmbt_trace_cursor( + char *func, + xfs_btree_cur_t *cur, + char *s, + int line) +{ + xfs_bmbt_rec_t r; + + xfs_bmbt_set_all(&r, &cur->bc_rec.b); + xfs_bmbt_trace_enter(func, cur, s, XFS_BMBT_KTRACE_CUR, line, + (cur->bc_nlevels << 24) | (cur->bc_private.b.flags << 16) | + cur->bc_private.b.allocated, +#if BMBT_USE_64 + INT_GET(r.l0, ARCH_CONVERT) >> 32, (int)INT_GET(r.l0, ARCH_CONVERT), INT_GET(r.l1, ARCH_CONVERT) >> 32, (int)INT_GET(r.l1, ARCH_CONVERT), +#else + INT_GET(r.l0, ARCH_CONVERT), INT_GET(r.l1, ARCH_CONVERT), INT_GET(r.l2, ARCH_CONVERT), INT_GET(r.l3, ARCH_CONVERT), +#endif + (unsigned long)cur->bc_bufs[0], (unsigned long)cur->bc_bufs[1], + (unsigned long)cur->bc_bufs[2], (unsigned long)cur->bc_bufs[3], + (cur->bc_ptrs[0] << 16) | cur->bc_ptrs[1], + (cur->bc_ptrs[2] << 16) | cur->bc_ptrs[3]); +} + +#define XFS_BMBT_TRACE_ARGBI(c,b,i) \ + xfs_bmbt_trace_argbi(fname, c, b, i, __LINE__) +#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) \ + xfs_bmbt_trace_argbii(fname, c, b, i, j, __LINE__) +#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) \ + xfs_bmbt_trace_argfffi(fname, c, o, b, i, j, __LINE__) +#define XFS_BMBT_TRACE_ARGI(c,i) \ + xfs_bmbt_trace_argi(fname, c, i, __LINE__) +#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k) \ + xfs_bmbt_trace_argifk(fname, c, i, f, k, __LINE__) +#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) \ + xfs_bmbt_trace_argifr(fname, c, i, f, r, __LINE__) +#define XFS_BMBT_TRACE_ARGIK(c,i,k) \ + xfs_bmbt_trace_argik(fname, c, i, k, __LINE__) +#define XFS_BMBT_TRACE_CURSOR(c,s) \ + xfs_bmbt_trace_cursor(fname, c, s, __LINE__) +static char ARGS[] = "args"; +static char ENTRY[] = "entry"; +static char ERROR[] = "error"; +#undef EXIT +static char EXIT[] = "exit"; +#else +#define XFS_BMBT_TRACE_ARGBI(c,b,i) +#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) +#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) +#define XFS_BMBT_TRACE_ARGI(c,i) +#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k) +#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) +#define XFS_BMBT_TRACE_ARGIK(c,i,k) +#define XFS_BMBT_TRACE_CURSOR(c,s) +#endif /* XFS_BMBT_TRACE */ + + +/* + * Internal functions. + */ + +/* + * Delete record pointed to by cur/level. + */ +STATIC int /* error */ +xfs_bmbt_delrec( + xfs_btree_cur_t *cur, + int level, + int async, /* deletion can be async */ + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_fsblock_t bno; /* fs-relative block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_delrec"; +#endif + int i; /* loop counter */ + int j; /* temp state */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */ + xfs_fsblock_t lbno; /* left sibling block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + int lrecs=0; /* left record count */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + int ptr; /* key/record index */ + xfs_fsblock_t rbno; /* right sibling block number */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_rec_t *rp; /* pointer to bmap btree rec */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_block_t *rrblock; /* right-right btree block */ + xfs_buf_t *rrbp; /* right-right buffer pointer */ + int rrecs=0; /* right record count */ + xfs_bmbt_rec_t *rrp; /* right record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + int numrecs; /* temporary numrec count */ + int numlrecs, numrrecs; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ptr = cur->bc_ptrs[level]; + tcur = (xfs_btree_cur_t *)0; + if (ptr == 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + block = xfs_bmbt_get_block(cur, level, &bp); + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + if (ptr > numrecs) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_bmbt_delrec); + if (level > 0) { + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < numrecs; i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } +#endif + if (ptr < numrecs) { + ovbcopy(&kp[ptr], &kp[ptr - 1], + (numrecs - ptr) * sizeof(*kp)); + ovbcopy(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */ + (numrecs - ptr) * sizeof(*pp)); + xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs - 1); + xfs_bmbt_log_keys(cur, bp, ptr, numrecs - 1); + } + } else { + rp = XFS_BMAP_REC_IADDR(block, 1, cur); + if (ptr < numrecs) { + ovbcopy(&rp[ptr], &rp[ptr - 1], + (numrecs - ptr) * sizeof(*rp)); + xfs_bmbt_log_recs(cur, bp, ptr, numrecs - 1); + } + if (ptr == 1) { + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rp)); + kp = &key; + } + } + numrecs--; + INT_SET(block->bb_numrecs, ARCH_CONVERT, numrecs); + xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS); + /* + * We're at the root level. + * First, shrink the root block in-memory. + * Try to get rid of the next level down. + * If we can't then there's nothing left to do. + */ + if (level == cur->bc_nlevels - 1) { + xfs_iroot_realloc(cur->bc_private.b.ip, -1, + cur->bc_private.b.whichfork); + if ((error = xfs_bmbt_killroot(cur, async))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &j))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (ptr == 1 && (error = xfs_bmbt_updkey(cur, kp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (numrecs >= XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &j))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + /* + * One child of root, need to get a chance to copy its contents + * into the root and delete it. Can't go up to next level, + * there's nothing to delete there. + */ + if (lbno == NULLFSBLOCK && rbno == NULLFSBLOCK && + level == cur->bc_nlevels - 2) { + if ((error = xfs_bmbt_killroot(cur, async))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + ASSERT(rbno != NULLFSBLOCK || lbno != NULLFSBLOCK); + if ((error = xfs_btree_dup_cursor(cur, &tcur))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + bno = NULLFSBLOCK; + if (rbno != NULLFSBLOCK) { + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_increment(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if ((error = xfs_bmbt_lshift(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_BMAP_BLOCK_IMINRECS(level, tcur)); + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + if (level > 0) { + if ((error = xfs_bmbt_decrement(cur, + level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, + ERROR); + goto error0; + } + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLFSBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_decrement(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + if (lbno != NULLFSBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * decrement to last in block + */ + if ((error = xfs_bmbt_decrement(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_BMBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if ((error = xfs_bmbt_rshift(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_BMAP_BLOCK_IMINRECS(level, tcur)); + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + if (level == 0) + cur->bc_ptrs[0]++; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + mp = cur->bc_mp; + ASSERT(bno != NULLFSBLOCK); + if (lbno != NULLFSBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + rbno = bno; + right = block; + rbp = bp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, lbno, 0, &lbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } else if (rbno != NULLFSBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + lbno = bno; + left = block; + lbp = bp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, rbno, 0, &rbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + right = XFS_BUF_TO_BMBT_BLOCK(rbp); + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } else { + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + numlrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + numrrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, numlrecs + 1, cur); + lpp = XFS_BMAP_PTR_IADDR(left, numlrecs + 1, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < numrrecs; i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } +#endif + bcopy(rkp, lkp, numrrecs * sizeof(*lkp)); + bcopy(rpp, lpp, numrrecs * sizeof(*lpp)); + xfs_bmbt_log_keys(cur, lbp, numlrecs + 1, numlrecs + numrrecs); + xfs_bmbt_log_ptrs(cur, lbp, numlrecs + 1, numlrecs + numrrecs); + } else { + lrp = XFS_BMAP_REC_IADDR(left, numlrecs + 1, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + bcopy(rrp, lrp, numrrecs * sizeof(*lrp)); + xfs_bmbt_log_recs(cur, lbp, numlrecs + 1, numlrecs + numrrecs); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, numrrecs); + left->bb_rightsib = right->bb_rightsib; /* INT_: direct copy */ + xfs_bmbt_log_block(cur, lbp, XFS_BB_RIGHTSIB | XFS_BB_NUMRECS); + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, + INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp); + if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB); + } + xfs_bmap_add_free(XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(rbp)), 1, + cur->bc_private.b.flist, mp); + if (!async) + xfs_trans_set_sync(cur->bc_tp); + cur->bc_private.b.ip->i_d.di_nblocks--; + xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, XFS_ILOG_CORE); + if (XFS_IS_QUOTA_ON(mp) && + cur->bc_private.b.ip->i_ino != mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(cur->bc_tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, -1L); + xfs_trans_binval(cur->bc_tp, rbp); + if (bp != lbp) { + cur->bc_bufs[level] = lbp; + cur->bc_ptrs[level] += lrecs; + cur->bc_ra[level] = 0; + } else if ((error = xfs_bmbt_increment(cur, level + 1, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0) + cur->bc_ptrs[level]--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 2; + return 0; + +error0: + if (tcur) + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +#ifdef XFSDEBUG +/* + * Get the data from the pointed-to record. + */ +int +xfs_bmbt_get_rec( + xfs_btree_cur_t *cur, + xfs_fileoff_t *off, + xfs_fsblock_t *bno, + xfs_filblks_t *len, + xfs_exntst_t *state, + int *stat) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; +#ifdef DEBUG + int error; +#endif + int ptr; + xfs_bmbt_rec_t *rp; + + block = xfs_bmbt_get_block(cur, 0, &bp); + ptr = cur->bc_ptrs[0]; +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, 0, bp))) + return error; +#endif + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + *off = xfs_bmbt_get_startoff(rp); + *bno = xfs_bmbt_get_startblock(rp); + *len = xfs_bmbt_get_blockcount(rp); + *state = xfs_bmbt_get_state(rp); + *stat = 1; + return 0; +} +#endif + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_bmbt_insrec( + xfs_btree_cur_t *cur, + int level, + xfs_fsblock_t *bnop, + xfs_bmbt_rec_t *recp, + xfs_btree_cur_t **curp, + int *stat) /* no-go/done/continue */ +{ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_insrec"; +#endif + int i; /* loop index */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */ + int logflags; /* inode logging flags */ + xfs_fsblock_t nbno; /* new block number */ + struct xfs_btree_cur *ncur; /* new btree cursor */ + xfs_bmbt_key_t nkey; /* new btree key value */ + xfs_bmbt_rec_t nrec; /* new record count */ + int optr; /* old key/record index */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + int ptr; /* key/record index */ + xfs_bmbt_rec_t *rp=NULL; /* pointer to bmap btree rec */ + int numrecs; + + ASSERT(level < cur->bc_nlevels); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp); + ncur = (xfs_btree_cur_t *)0; + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(recp)); + optr = ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_bmbt_insrec); + block = xfs_bmbt_get_block(cur, level, &bp); + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (ptr <= numrecs) { + if (level == 0) { + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + xfs_btree_check_rec(XFS_BTNUM_BMAP, recp, rp); + } else { + kp = XFS_BMAP_KEY_IADDR(block, ptr, cur); + xfs_btree_check_key(XFS_BTNUM_BMAP, &key, kp); + } + } +#endif + nbno = NULLFSBLOCK; + if (numrecs == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + if (numrecs < XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { + /* + * A root block, that can be made bigger. + */ + xfs_iroot_realloc(cur->bc_private.b.ip, 1, + cur->bc_private.b.whichfork); + block = xfs_bmbt_get_block(cur, level, &bp); + } else if (level == cur->bc_nlevels - 1) { + if ((error = xfs_bmbt_newroot(cur, &logflags, stat)) || + *stat == 0) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, + logflags); + block = xfs_bmbt_get_block(cur, level, &bp); + } else { + if ((error = xfs_bmbt_rshift(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (i) { + /* nothing */ + } else { + if ((error = xfs_bmbt_lshift(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (i) { + optr = ptr = cur->bc_ptrs[level]; + } else { + if ((error = xfs_bmbt_split(cur, level, + &nbno, &nkey, &ncur, + &i))) { + XFS_BMBT_TRACE_CURSOR(cur, + ERROR); + return error; + } + if (i) { + block = xfs_bmbt_get_block( + cur, level, &bp); +#ifdef DEBUG + if ((error = + xfs_btree_check_lblock(cur, + block, level, bp))) { + XFS_BMBT_TRACE_CURSOR( + cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[level]; + xfs_bmbt_set_allf(&nrec, + nkey.br_startoff, 0, 0, + XFS_EXT_NORM); + } else { + XFS_BMBT_TRACE_CURSOR(cur, + EXIT); + *stat = 0; + return 0; + } + } + } + } + } + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + if (level > 0) { + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); +#ifdef DEBUG + for (i = numrecs; i >= ptr; i--) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (numrecs - ptr + 1) * sizeof(*kp)); + ovbcopy(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */ + (numrecs - ptr + 1) * sizeof(*pp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)*bnop, + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + kp[ptr - 1] = key; + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + numrecs++; + INT_SET(block->bb_numrecs, ARCH_CONVERT, numrecs); + xfs_bmbt_log_keys(cur, bp, ptr, numrecs); + xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs); + } else { + rp = XFS_BMAP_REC_IADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (numrecs - ptr + 1) * sizeof(*rp)); + rp[ptr - 1] = *recp; + numrecs++; + INT_SET(block->bb_numrecs, ARCH_CONVERT, numrecs); + xfs_bmbt_log_recs(cur, bp, ptr, numrecs); + } + xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (ptr < numrecs) { + if (level == 0) + xfs_btree_check_rec(XFS_BTNUM_BMAP, rp + ptr - 1, + rp + ptr); + else + xfs_btree_check_key(XFS_BTNUM_BMAP, kp + ptr - 1, + kp + ptr); + } +#endif + if (optr == 1 && (error = xfs_bmbt_updkey(cur, &key, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + *bnop = nbno; + if (nbno != NULLFSBLOCK) { + *recp = nrec; + *curp = ncur; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +STATIC int +xfs_bmbt_killroot( + xfs_btree_cur_t *cur, + int async) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_block_t *cblock; + xfs_buf_t *cbp; + xfs_bmbt_key_t *ckp; + xfs_bmbt_ptr_t *cpp; +#ifdef DEBUG + int error; +#endif +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_killroot"; +#endif + int i; + xfs_bmbt_key_t *kp; + xfs_inode_t *ip; + xfs_ifork_t *ifp; + int level; + xfs_bmbt_ptr_t *pp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = cur->bc_nlevels - 1; + ASSERT(level >= 1); + /* + * Don't deal with the root block needs to be a leaf case. + * We're just going to turn the thing back into extents anyway. + */ + if (level == 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + block = xfs_bmbt_get_block(cur, level, &cbp); + /* + * Give up if the root has multiple children. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) != 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + /* + * Only do this if the next level will fit. + * Then the data must be copied up to the inode, + * instead of freeing the root you free the next level. + */ + cbp = cur->bc_bufs[level - 1]; + cblock = XFS_BUF_TO_BMBT_BLOCK(cbp); + if (INT_GET(cblock->bb_numrecs, ARCH_CONVERT) > XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + ASSERT(INT_GET(cblock->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(cblock->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO); + ip = cur->bc_private.b.ip; + ifp = XFS_IFORK_PTR(ip, cur->bc_private.b.whichfork); + ASSERT(XFS_BMAP_BLOCK_IMAXRECS(level, cur) == + XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes)); + i = (int)(INT_GET(cblock->bb_numrecs, ARCH_CONVERT) - XFS_BMAP_BLOCK_IMAXRECS(level, cur)); + if (i) { + xfs_iroot_realloc(ip, i, cur->bc_private.b.whichfork); + block = ifp->if_broot; + } + INT_MOD(block->bb_numrecs, ARCH_CONVERT, i); + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) == INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); + bcopy(ckp, kp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*kp)); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(cpp[i], ARCH_CONVERT), level - 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(cpp, pp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp)); + xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1, + cur->bc_private.b.flist, cur->bc_mp); + if (!async) + xfs_trans_set_sync(cur->bc_tp); + ip->i_d.di_nblocks--; + if (XFS_IS_QUOTA_ON(cur->bc_mp) && + ip->i_ino != cur->bc_mp->m_sb.sb_uquotino && + ip->i_ino != cur->bc_mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(cur->bc_tp, ip, XFS_TRANS_DQ_BCOUNT, + -1L); + xfs_trans_binval(cur->bc_tp, cbp); + cur->bc_bufs[level - 1] = NULL; + INT_MOD(block->bb_level, ARCH_CONVERT, -1); + xfs_trans_log_inode(cur->bc_tp, ip, + XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + cur->bc_nlevels--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Log key values from the btree block. + */ +STATIC void +xfs_bmbt_log_keys( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int kfirst, + int klast) +{ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_keys"; +#endif + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, kfirst, klast); + tp = cur->bc_tp; + if (bp) { + xfs_bmbt_block_t *block; + int first; + xfs_bmbt_key_t *kp; + int last; + + block = XFS_BUF_TO_BMBT_BLOCK(bp); + kp = XFS_BMAP_KEY_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + } else { + xfs_inode_t *ip; + + ip = cur->bc_private.b.ip; + xfs_trans_log_inode(tp, ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Log pointer values from the btree block. + */ +STATIC void +xfs_bmbt_log_ptrs( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int pfirst, + int plast) +{ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_ptrs"; +#endif + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, pfirst, plast); + tp = cur->bc_tp; + if (bp) { + xfs_bmbt_block_t *block; + int first; + int last; + xfs_bmbt_ptr_t *pp; + + block = XFS_BUF_TO_BMBT_BLOCK(bp); + pp = XFS_BMAP_PTR_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + } else { + xfs_inode_t *ip; + + ip = cur->bc_private.b.ip; + xfs_trans_log_inode(tp, ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + */ +STATIC int /* error */ +xfs_bmbt_lookup( + xfs_btree_cur_t *cur, + xfs_lookup_t dir, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block=NULL; + xfs_buf_t *bp; + xfs_daddr_t d; + xfs_sfiloff_t diff; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_lookup"; +#endif + xfs_fsblock_t fsbno=0; + int high; + int i; + int keyno=0; + xfs_bmbt_key_t *kkbase=NULL; + xfs_bmbt_key_t *kkp; + xfs_bmbt_rec_t *krbase=NULL; + xfs_bmbt_rec_t *krp; + int level; + int low; + xfs_mount_t *mp; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_irec_t *rp; + xfs_fileoff_t startoff; + xfs_trans_t *tp; + + XFS_STATS_INC(xfsstats.xs_bmbt_lookup); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, (int)dir); + tp = cur->bc_tp; + mp = cur->bc_mp; + rp = &cur->bc_rec.b; + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + if (level < cur->bc_nlevels - 1) { + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, + 0, &bp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + xfs_btree_setbuf(cur, level, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, + level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } else + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } else + block = xfs_bmbt_get_block(cur, level, &bp); + if (diff == 0) + keyno = 1; + else { + if (level > 0) + kkbase = XFS_BMAP_KEY_IADDR(block, 1, cur); + else + krbase = XFS_BMAP_REC_IADDR(block, 1, cur); + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + ASSERT(level == 0); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + while (low <= high) { + XFS_STATS_INC(xfsstats.xs_bmbt_compare); + keyno = (low + high) >> 1; + if (level > 0) { + kkp = kkbase + keyno - 1; + startoff = INT_GET(kkp->br_startoff, ARCH_CONVERT); + } else { + krp = krbase + keyno - 1; + startoff = xfs_bmbt_get_startoff(krp); + } + diff = (xfs_sfiloff_t) + (startoff - rp->br_startoff); + if (diff < 0) + low = keyno + 1; + else if (diff > 0) + high = keyno - 1; + else + break; + } + } + if (level > 0) { + if (diff > 0 && --keyno < 1) + keyno = 1; + pp = XFS_BMAP_PTR_IADDR(block, keyno, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + fsbno = INT_GET(*pp, ARCH_CONVERT); + cur->bc_ptrs[level] = keyno; + } + } + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + cur->bc_ptrs[0] = keyno; + if ((error = xfs_bmbt_increment(cur, 0, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_WANT_CORRUPTED_RETURN(i == 1); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + } else { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + } + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_bmbt_lshift( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_lshift"; +#endif +#ifdef DEBUG + int i; /* loop counter */ +#endif + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp=NULL; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + int lrecs; /* left record count */ + xfs_bmbt_rec_t *lrp=NULL; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp=NULL; /* right btree key */ + xfs_bmbt_ptr_t *rpp=NULL; /* right address pointer */ + xfs_bmbt_rec_t *rrp=NULL; /* right record pointer */ + int rrecs; /* right record count */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + if (level == cur->bc_nlevels - 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (cur->bc_ptrs[level] <= 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + mp = cur->bc_mp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, + &lbp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, lrecs, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + *lkp = *rkp; + xfs_bmbt_log_keys(cur, lbp, lrecs, lrecs); + lpp = XFS_BMAP_PTR_IADDR(left, lrecs, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + *lpp = *rpp; /* INT_: direct copy */ + xfs_bmbt_log_ptrs(cur, lbp, lrecs, lrecs); + } else { + lrp = XFS_BMAP_REC_IADDR(left, lrecs, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + *lrp = *rrp; + xfs_bmbt_log_recs(cur, lbp, lrecs, lrecs); + } + INT_SET(left->bb_numrecs, ARCH_CONVERT, lrecs); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(XFS_BTNUM_BMAP, lkp - 1, lkp); + else + xfs_btree_check_rec(XFS_BTNUM_BMAP, lrp - 1, lrp); +#endif + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; + INT_SET(right->bb_numrecs, ARCH_CONVERT, rrecs); + xfs_bmbt_log_block(cur, rbp, XFS_BB_NUMRECS); + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < rrecs; i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(rkp + 1, rkp, rrecs * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, rrecs * sizeof(*rpp)); + xfs_bmbt_log_keys(cur, rbp, 1, rrecs); + xfs_bmbt_log_ptrs(cur, rbp, 1, rrecs); + } else { + ovbcopy(rrp + 1, rrp, rrecs * sizeof(*rrp)); + xfs_bmbt_log_recs(cur, rbp, 1, rrecs); + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp)); + rkp = &key; + } + if ((error = xfs_bmbt_updkey(cur, rkp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[level]--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_bmbt_rshift( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_rshift"; +#endif + int i; /* loop counter */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_rec_t *rrp=NULL; /* right record pointer */ + struct xfs_btree_cur *tcur; /* temporary btree cursor */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + if (level == cur->bc_nlevels - 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_BMBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + mp = cur->bc_mp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rbp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + right = XFS_BUF_TO_BMBT_BLOCK(rbp); + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + *rkp = *lkp; + *rpp = *lpp; /* INT_: direct copy */ + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + } else { + lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp)); + rkp = &key; + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(XFS_BTNUM_BMAP, rkp, rkp + 1); + else + xfs_btree_check_rec(XFS_BTNUM_BMAP, rrp, rrp + 1); +#endif + xfs_bmbt_log_block(cur, rbp, XFS_BB_NUMRECS); + if ((error = xfs_btree_dup_cursor(cur, &tcur))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_increment(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(tcur, ERROR); + goto error1; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_updkey(tcur, rkp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(tcur, ERROR); + goto error1; + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +error0: + XFS_BMBT_TRACE_CURSOR(cur, ERROR); +error1: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Determine the extent state. + */ +/* ARGSUSED */ +STATIC xfs_exntst_t +xfs_extent_state( + xfs_filblks_t blks, + int extent_flag) +{ + if (extent_flag) { + ASSERT(blks != 0); /* saved for DMIG */ + return XFS_EXT_UNWRITTEN; + } + return XFS_EXT_NORM; +} + + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_bmbt_split( + xfs_btree_cur_t *cur, + int level, + xfs_fsblock_t *bnop, + xfs_bmbt_key_t *keyp, + xfs_btree_cur_t **curp, + int *stat) /* success/failure */ +{ + xfs_alloc_arg_t args; /* block allocation args */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_split"; +#endif + int i; /* loop counter */ + xfs_fsblock_t lbno; /* left sibling block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_block_t *rrblock; /* right-right btree block */ + xfs_buf_t *rrbp; /* right-right buffer pointer */ + xfs_bmbt_rec_t *rrp; /* right record pointer */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, keyp); + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + lbp = cur->bc_bufs[level]; + lbno = XFS_DADDR_TO_FSB(args.mp, XFS_BUF_ADDR(lbp)); + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + args.fsbno = cur->bc_private.b.firstblock; + if (args.fsbno == NULLFSBLOCK) { + args.fsbno = lbno; + args.type = XFS_ALLOCTYPE_START_BNO; + } else if (cur->bc_private.b.flist->xbf_low) + args.type = XFS_ALLOCTYPE_FIRST_AG; + else + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.mod = args.minleft = args.alignment = args.total = args.isfl = + args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; + if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return XFS_ERROR(ENOSPC); + } + if ((error = xfs_alloc_vextent(&args))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (args.fsbno == NULLFSBLOCK) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + cur->bc_private.b.ip->i_d.di_nblocks++; + xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); + if (XFS_IS_QUOTA_ON(args.mp) && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, 1L); + rbp = xfs_btree_get_bufl(args.mp, args.tp, args.fsbno, 0); + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + INT_SET(right->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, i, cur); + lpp = XFS_BMAP_PTR_IADDR(left, i, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT); + } else { + lrp = XFS_BMAP_REC_IADDR(left, i, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->br_startoff = xfs_bmbt_get_startoff(rrp); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, args.fsbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_bmbt_log_block(cur, rbp, XFS_BB_ALL_BITS); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + if ((error = xfs_btree_read_bufl(args.mp, args.tp, + INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp); + if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, args.fsbno); + xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB); + } + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = args.fsbno; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + + +/* + * Update keys for the record. + */ +STATIC int +xfs_bmbt_updkey( + xfs_btree_cur_t *cur, + xfs_bmbt_key_t *keyp, /* on-disk format */ + int level) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; +#ifdef DEBUG + int error; +#endif +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_updkey"; +#endif + xfs_bmbt_key_t *kp; + int ptr; + + ASSERT(level >= 1); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIK(cur, level, keyp); + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_BMAP_KEY_IADDR(block, ptr, cur); + *kp = *keyp; + xfs_bmbt_log_keys(cur, bp, ptr, ptr); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Convert on-disk form of btree root to in-memory form. + */ +void +xfs_bmdr_to_bmbt( + xfs_bmdr_block_t *dblock, + int dblocklen, + xfs_bmbt_block_t *rblock, + int rblocklen) +{ + int dmxr; + xfs_bmbt_key_t *fkp; + xfs_bmbt_ptr_t *fpp; + xfs_bmbt_key_t *tkp; + xfs_bmbt_ptr_t *tpp; + + INT_SET(rblock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + rblock->bb_level = dblock->bb_level; /* both in on-disk format */ + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) > 0); + rblock->bb_numrecs = dblock->bb_numrecs;/* both in on-disk format */ + INT_SET(rblock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(rblock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); + fkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); + fpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); + dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT); + bcopy(fkp, tkp, sizeof(*fkp) * dmxr); + bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */ +} + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_bmbt_decrement( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_decrement"; +#endif + xfs_fsblock_t fsbno; + int lev; + xfs_mount_t *mp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ASSERT(level < cur->bc_nlevels); + if (level < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + if (--cur->bc_ptrs[level] > 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + if (lev < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + if (lev == cur->bc_nlevels) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + tp = cur->bc_tp; + mp = cur->bc_mp; + for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) { + fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Delete the record pointed to by cur. + */ +int /* error */ +xfs_bmbt_delete( + xfs_btree_cur_t *cur, + int async, /* deletion can be async */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_delete"; +#endif + int i; + int level; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + for (level = 0, i = 2; i == 2; level++) { + if ((error = xfs_bmbt_delrec(cur, level, async, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if ((error = xfs_bmbt_decrement(cur, level, + &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + break; + } + } + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = i; + return 0; +} + +/* + * Convert a compressed bmap extent record to an uncompressed form. + * This code must be in sync with the routines xfs_bmbt_get_startoff, + * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. + */ +void +xfs_bmbt_get_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s) +{ + int ext_flag; + xfs_exntst_t st; + __uint64_t l0, l1; + + l0 = INT_GET(r->l0, ARCH_CONVERT); + l1 = INT_GET(r->l1, ARCH_CONVERT); + ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN)); + s->br_startoff = ((xfs_fileoff_t)l0 & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; +#if XFS_BIG_FILESYSTEMS + s->br_startblock = (((xfs_fsblock_t)l0 & XFS_MASK64LO(9)) << 43) | + (((xfs_fsblock_t)l1) >> 21); +#else +#ifdef DEBUG + { + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)l0 & XFS_MASK64LO(9)) << 43) | + (((xfs_dfsbno_t)l1) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + s->br_startblock = (xfs_fsblock_t)b; + } +#else /* !DEBUG */ + s->br_startblock = (xfs_fsblock_t)(((xfs_dfsbno_t)l1) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ + s->br_blockcount = (xfs_filblks_t)(l1 & XFS_MASK64LO(21)); + /* This is xfs_extent_state() in-line */ + if (ext_flag) { + ASSERT(s->br_blockcount != 0); /* saved for DMIG */ + st = XFS_EXT_UNWRITTEN; + } else + st = XFS_EXT_NORM; + s->br_state = st; +} + +/* + * Get the block pointer for the given level of the cursor. + * Fill in the buffer pointer, if applicable. + */ +xfs_bmbt_block_t * +xfs_bmbt_get_block( + xfs_btree_cur_t *cur, + int level, + xfs_buf_t **bpp) +{ + xfs_ifork_t *ifp; + xfs_bmbt_block_t *rval; + + if (level < cur->bc_nlevels - 1) { + *bpp = cur->bc_bufs[level]; + rval = XFS_BUF_TO_BMBT_BLOCK(*bpp); + } else { + *bpp = 0; + ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, + cur->bc_private.b.whichfork); + rval = ifp->if_broot; + } + return rval; +} + +/* + * Extract the blockcount field from a bmap extent record. + */ +xfs_filblks_t +xfs_bmbt_get_blockcount( + xfs_bmbt_rec_t *r) +{ + return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21)); +} + +/* + * Extract the startblock field from a bmap extent record. + */ +xfs_fsblock_t +xfs_bmbt_get_startblock( + xfs_bmbt_rec_t *r) +{ +#if XFS_BIG_FILESYSTEMS + return (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + return (xfs_fsblock_t)b; +#else /* !DEBUG */ + return (xfs_fsblock_t)(((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ +} + +/* + * Extract the startoff field from a bmap extent record. + */ +xfs_fileoff_t +xfs_bmbt_get_startoff( + xfs_bmbt_rec_t *r) +{ + return ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; +} + +xfs_exntst_t +xfs_bmbt_get_state( + xfs_bmbt_rec_t *r) +{ + int ext_flag; + + ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)); + return xfs_extent_state(xfs_bmbt_get_blockcount(r), + ext_flag); +} + + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_bmbt_increment( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_increment"; +#endif + xfs_fsblock_t fsbno; + int lev; + xfs_mount_t *mp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ASSERT(level < cur->bc_nlevels); + if (level < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + block = xfs_bmbt_get_block(cur, lev, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + if (lev < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + if (lev == cur->bc_nlevels) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + tp = cur->bc_tp; + mp = cur->bc_mp; + for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) { + fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[lev] = 1; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + */ +int /* error */ +xfs_bmbt_insert( + xfs_btree_cur_t *cur, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_insert"; +#endif + int i; + int level; + xfs_fsblock_t nbno; + xfs_btree_cur_t *ncur; + xfs_bmbt_rec_t nrec; + xfs_btree_cur_t *pcur; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = 0; + nbno = NULLFSBLOCK; + xfs_bmbt_set_all(&nrec, &cur->bc_rec.b); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + do { + if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + cur->bc_private.b.allocated += + pcur->bc_private.b.allocated; + pcur->bc_private.b.allocated = 0; + ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) || + (cur->bc_private.b.ip->i_d.di_flags & + XFS_DIFLAG_REALTIME)); + cur->bc_private.b.firstblock = + pcur->bc_private.b.firstblock; + ASSERT(cur->bc_private.b.flist == + pcur->bc_private.b.flist); + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLFSBLOCK); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = i; + return 0; +error0: + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; +} + +/* + * Log fields from the btree block header. + */ +void +xfs_bmbt_log_block( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int fields) +{ + int first; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_block"; +#endif + int last; + xfs_trans_t *tp; + static const short offsets[] = { + offsetof(xfs_bmbt_block_t, bb_magic), + offsetof(xfs_bmbt_block_t, bb_level), + offsetof(xfs_bmbt_block_t, bb_numrecs), + offsetof(xfs_bmbt_block_t, bb_leftsib), + offsetof(xfs_bmbt_block_t, bb_rightsib), + sizeof(xfs_bmbt_block_t) + }; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBI(cur, bp, fields); + tp = cur->bc_tp; + if (bp) { + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, + &last); + xfs_trans_log_buf(tp, bp, first, last); + } else + xfs_trans_log_inode(tp, cur->bc_private.b.ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Log record values from the btree block. + */ +void +xfs_bmbt_log_recs( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int rfirst, + int rlast) +{ + xfs_bmbt_block_t *block; + int first; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_recs"; +#endif + int last; + xfs_bmbt_rec_t *rp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, rfirst, rlast); + ASSERT(bp); + tp = cur->bc_tp; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + rp = XFS_BMAP_REC_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +int /* error */ +xfs_bmbt_lookup_eq( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +int /* error */ +xfs_bmbt_lookup_ge( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_GE, stat); +} + +int /* error */ +xfs_bmbt_lookup_le( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Give the bmap btree a new root block. Copy the old broot contents + * down into a real block and make the broot point to it. + */ +int /* error */ +xfs_bmbt_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflags, /* logging flags for inode */ + int *stat) /* return status - 0 fail */ +{ + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_buf_t *bp; /* buffer for block */ + xfs_bmbt_block_t *cblock; /* child btree block */ + xfs_bmbt_key_t *ckp; /* child key pointer */ + xfs_bmbt_ptr_t *cpp; /* child ptr pointer */ + int error; /* error return code */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_newroot"; +#endif +#ifdef DEBUG + int i; /* loop counter */ +#endif + xfs_bmbt_key_t *kp; /* pointer to bmap btree key */ + int level; /* btree level */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = cur->bc_nlevels - 1; + block = xfs_bmbt_get_block(cur, level, &bp); + /* + * Copy the root into a real block. + */ + args.mp = cur->bc_mp; + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + args.tp = cur->bc_tp; + args.fsbno = cur->bc_private.b.firstblock; + args.mod = args.minleft = args.alignment = args.total = args.isfl = + args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; + if (args.fsbno == NULLFSBLOCK) { +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + args.fsbno = INT_GET(*pp, ARCH_CONVERT); + args.type = XFS_ALLOCTYPE_START_BNO; + } else if (args.wasdel) + args.type = XFS_ALLOCTYPE_FIRST_AG; + else + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (args.fsbno == NULLFSBLOCK) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + cur->bc_private.b.ip->i_d.di_nblocks++; + if (XFS_IS_QUOTA_ON(args.mp) && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, 1L); + bp = xfs_btree_get_bufl(args.mp, cur->bc_tp, args.fsbno, 0); + cblock = XFS_BUF_TO_BMBT_BLOCK(bp); + *cblock = *block; + INT_MOD(block->bb_level, ARCH_CONVERT, +1); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + cur->bc_nlevels++; + cur->bc_ptrs[level + 1] = 1; + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); + bcopy(kp, ckp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*kp)); + cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(pp, cpp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*pp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)args.fsbno, + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + INT_SET(*pp, ARCH_CONVERT, args.fsbno); + xfs_iroot_realloc(cur->bc_private.b.ip, 1 - INT_GET(cblock->bb_numrecs, ARCH_CONVERT), + cur->bc_private.b.whichfork); + xfs_btree_setbuf(cur, level, bp); + /* + * Do all this logging at the end so that + * the root is at the right level. + */ + xfs_bmbt_log_block(cur, bp, XFS_BB_ALL_BITS); + xfs_bmbt_log_keys(cur, bp, 1, INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, bp, 1, INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *logflags |= + XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork); + *stat = 1; + return 0; +} + +/* + * Set all the fields in a bmap extent record from the uncompressed form. + */ +void +xfs_bmbt_set_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s) +{ + int extent_flag; + + ASSERT((s->br_state == XFS_EXT_NORM) || + (s->br_state == XFS_EXT_UNWRITTEN)); + extent_flag = (s->br_state == XFS_EXT_NORM) ? 0 : 1; + ASSERT((s->br_startoff & XFS_MASK64HI(9)) == 0); + ASSERT((s->br_blockcount & XFS_MASK64HI(43)) == 0); +#if XFS_BIG_FILESYSTEMS + ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | + ((xfs_bmbt_rec_base_t)s->br_startblock >> 43)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(s->br_startblock)) { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); + INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +} + +/* + * Set all the fields in a bmap extent record from the arguments. + */ +void +xfs_bmbt_set_allf( + xfs_bmbt_rec_t *r, + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_filblks_t c, + xfs_exntst_t v) +{ + int extent_flag; + + ASSERT((v == XFS_EXT_NORM) || (v == XFS_EXT_UNWRITTEN)); + extent_flag = (v == XFS_EXT_NORM) ? 0 : 1; + ASSERT((o & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0); + ASSERT((c & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); +#if XFS_BIG_FILESYSTEMS + ASSERT((b & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9) | + ((xfs_bmbt_rec_base_t)b >> 43)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(b)) { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); + INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +} + +/* + * Set the blockcount field in a bmap extent record. + */ +void +xfs_bmbt_set_blockcount( + xfs_bmbt_rec_t *r, + xfs_filblks_t v) +{ + ASSERT((v & XFS_MASK64HI(43)) == 0); + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) | + (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21))); +} + +/* + * Set the startblock field in a bmap extent record. + */ +void +xfs_bmbt_set_startblock( + xfs_bmbt_rec_t *r, + xfs_fsblock_t v) +{ +#if XFS_BIG_FILESYSTEMS + ASSERT((v & XFS_MASK64HI(12)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) | + (xfs_bmbt_rec_base_t)(v >> 43)); + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) | + (xfs_bmbt_rec_base_t)(v << 21)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(v)) { + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) | (xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)v << 21) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)v << 21) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +} + +/* + * Set the startoff field in a bmap extent record. + */ +void +xfs_bmbt_set_startoff( + xfs_bmbt_rec_t *r, + xfs_fileoff_t v) +{ + ASSERT((v & XFS_MASK64HI(9)) == 0); + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) | + ((xfs_bmbt_rec_base_t)v << 9) | + (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); +} + +/* + * Set the extent state field in a bmap extent record. + */ +void +xfs_bmbt_set_state( + xfs_bmbt_rec_t *r, + xfs_exntst_t v) +{ + ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); + if (v == XFS_EXT_NORM) + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)); + else + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) | XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN)); +} + +/* + * Convert in-memory form of btree root to on-disk form. + */ +void +xfs_bmbt_to_bmdr( + xfs_bmbt_block_t *rblock, + int rblocklen, + xfs_bmdr_block_t *dblock, + int dblocklen) +{ + int dmxr; + xfs_bmbt_key_t *fkp; + xfs_bmbt_ptr_t *fpp; + xfs_bmbt_key_t *tkp; + xfs_bmbt_ptr_t *tpp; + + ASSERT(INT_GET(rblock->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC); + ASSERT(INT_GET(rblock->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(rblock->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) > 0); + dblock->bb_level = rblock->bb_level; /* both in on-disk format */ + dblock->bb_numrecs = rblock->bb_numrecs;/* both in on-disk format */ + dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); + fkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); + tkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + fpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); + tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT); + bcopy(fkp, tkp, sizeof(*fkp) * dmxr); + bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */ +} + +/* + * Update the record to the passed values. + */ +int +xfs_bmbt_update( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + xfs_exntst_t state) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_update"; +#endif + xfs_bmbt_key_t key; + int ptr; + xfs_bmbt_rec_t *rp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGFFFI(cur, (xfs_dfiloff_t)off, (xfs_dfsbno_t)bno, + (xfs_dfilblks_t)len, (int)state); + block = xfs_bmbt_get_block(cur, 0, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, 0, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[0]; + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + xfs_bmbt_set_allf(rp, off, bno, len, state); + xfs_bmbt_log_recs(cur, bp, ptr, ptr); + if (ptr > 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + INT_SET(key.br_startoff, ARCH_CONVERT, off); + if ((error = xfs_bmbt_updkey(cur, &key, 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Check an extent list, which has just been read, for + * any bit in the extent flag field. ASSERT on debug + * kernels, as this condition should not occur. + * Return an error condition (1) if any flags found, + * otherwise return 0. + */ +int +xfs_check_nostate_extents( + xfs_bmbt_rec_t *ep, + xfs_extnum_t num) +{ + for (; num > 0; num--, ep++) { + if (((INT_GET(ep->l0, ARCH_CONVERT)) >> + (64 - BMBT_EXNTFLAG_BITLEN)) != 0) { + ASSERT(0); + return 1; + } + } + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_bmap_btree.h linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap_btree.h --- linux-2.4.19/fs/xfs/xfs_bmap_btree.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_bmap_btree.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BMAP_BTREE_H__ +#define __XFS_BMAP_BTREE_H__ + +#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */ + +struct xfs_btree_cur; +struct xfs_btree_lblock; +struct xfs_mount; +struct xfs_inode; + +/* + * Bmap root header, on-disk form only. + */ +typedef struct xfs_bmdr_block +{ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_bmdr_block_t; + +/* + * Bmap btree record and extent descriptor. + * For 32-bit kernels, + * l0:31 is an extent flag (value 1 indicates non-normal). + * l0:0-30 and l1:9-31 are startoff. + * l1:0-8, l2:0-31, and l3:21-31 are startblock. + * l3:0-20 are blockcount. + * For 64-bit kernels, + * l0:63 is an extent flag (value 1 indicates non-normal). + * l0:9-62 are startoff. + * l0:0-8 and l1:21-63 are startblock. + * l1:0-20 are blockcount. + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ +#define BMBT_EXNTFLAG_BITOFF 0 +#define BMBT_EXNTFLAG_BITLEN 1 +#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF + BMBT_EXNTFLAG_BITLEN) +#define BMBT_STARTOFF_BITLEN 54 +#define BMBT_STARTBLOCK_BITOFF (BMBT_STARTOFF_BITOFF + BMBT_STARTOFF_BITLEN) +#define BMBT_STARTBLOCK_BITLEN 52 +#define BMBT_BLOCKCOUNT_BITOFF \ + (BMBT_STARTBLOCK_BITOFF + BMBT_STARTBLOCK_BITLEN) +#define BMBT_BLOCKCOUNT_BITLEN (BMBT_TOTAL_BITLEN - BMBT_BLOCKCOUNT_BITOFF) + +#else + +#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ +#define BMBT_EXNTFLAG_BITOFF 63 +#define BMBT_EXNTFLAG_BITLEN 1 +#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF - BMBT_STARTOFF_BITLEN) +#define BMBT_STARTOFF_BITLEN 54 +#define BMBT_STARTBLOCK_BITOFF 85 /* 128 - 43 (other 9 is in first word) */ +#define BMBT_STARTBLOCK_BITLEN 52 +#define BMBT_BLOCKCOUNT_BITOFF 64 /* Start of second 64 bit container */ +#define BMBT_BLOCKCOUNT_BITLEN 21 + +#endif + + +#define BMBT_USE_64 1 + +typedef struct xfs_bmbt_rec_32 +{ + __uint32_t l0, l1, l2, l3; +} xfs_bmbt_rec_32_t; +typedef struct xfs_bmbt_rec_64 +{ + __uint64_t l0, l1; +} xfs_bmbt_rec_64_t; + +typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ +typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; + +/* + * Values and macros for delayed-allocation startblock fields. + */ +#define STARTBLOCKVALBITS 17 +#define STARTBLOCKMASKBITS (15 + XFS_BIG_FILESYSTEMS * 20) +#define DSTARTBLOCKMASKBITS (15 + 20) +#define STARTBLOCKMASK \ + (((((xfs_fsblock_t)1) << STARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) +#define DSTARTBLOCKMASK \ + (((((xfs_dfsbno_t)1) << DSTARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_ISNULLSTARTBLOCK) +int isnullstartblock(xfs_fsblock_t x); +#define ISNULLSTARTBLOCK(x) isnullstartblock(x) +#else +#define ISNULLSTARTBLOCK(x) (((x) & STARTBLOCKMASK) == STARTBLOCKMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_ISNULLDSTARTBLOCK) +int isnulldstartblock(xfs_dfsbno_t x); +#define ISNULLDSTARTBLOCK(x) isnulldstartblock(x) +#else +#define ISNULLDSTARTBLOCK(x) (((x) & DSTARTBLOCKMASK) == DSTARTBLOCKMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_NULLSTARTBLOCK) +xfs_fsblock_t nullstartblock(int k); +#define NULLSTARTBLOCK(k) nullstartblock(k) +#else +#define NULLSTARTBLOCK(k) \ + ((ASSERT(k < (1 << STARTBLOCKVALBITS))), (STARTBLOCKMASK | (k))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_STARTBLOCKVAL) +xfs_filblks_t startblockval(xfs_fsblock_t x); +#define STARTBLOCKVAL(x) startblockval(x) +#else +#define STARTBLOCKVAL(x) ((xfs_filblks_t)((x) & ~STARTBLOCKMASK)) +#endif + +/* + * Possible extent formats. + */ +typedef enum { + XFS_EXTFMT_NOSTATE = 0, + XFS_EXTFMT_HASSTATE +} xfs_exntfmt_t; + +/* + * Possible extent states. + */ +typedef enum { + XFS_EXT_NORM, XFS_EXT_UNWRITTEN, + XFS_EXT_DMAPI_OFFLINE +} xfs_exntst_t; + +/* + * Extent state and extent format macros. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTFMT_INODE ) +xfs_exntfmt_t xfs_extfmt_inode(struct xfs_inode *ip); +#define XFS_EXTFMT_INODE(x) xfs_extfmt_inode(x) +#else +#define XFS_EXTFMT_INODE(x) \ + (XFS_SB_VERSION_HASEXTFLGBIT(&((x)->i_mount->m_sb)) ? \ + XFS_EXTFMT_HASSTATE : XFS_EXTFMT_NOSTATE) +#endif +#define ISUNWRITTEN(x) ((x) == XFS_EXT_UNWRITTEN) + +/* + * Incore version of above. + */ +typedef struct xfs_bmbt_irec +{ + xfs_fileoff_t br_startoff; /* starting file offset */ + xfs_fsblock_t br_startblock; /* starting block number */ + xfs_filblks_t br_blockcount; /* number of blocks */ + xfs_exntst_t br_state; /* extent state */ +} xfs_bmbt_irec_t; + +/* + * Key structure for non-leaf levels of the tree. + */ +typedef struct xfs_bmbt_key +{ + xfs_dfiloff_t br_startoff; /* starting file offset */ +} xfs_bmbt_key_t, xfs_bmdr_key_t; + +typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_lblock xfs_bmbt_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_BMBT_BLOCK) +xfs_bmbt_block_t *xfs_buf_to_bmbt_block(struct xfs_buf *bp); +#define XFS_BUF_TO_BMBT_BLOCK(bp) xfs_buf_to_bmbt_block(bp) +#else +#define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)(XFS_BUF_PTR(bp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_RBLOCK_DSIZE) +int xfs_bmap_rblock_dsize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) xfs_bmap_rblock_dsize(lev,cur) +#else +#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) ((cur)->bc_private.b.forksize) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_RBLOCK_ISIZE) +int xfs_bmap_rblock_isize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) xfs_bmap_rblock_isize(lev,cur) +#else +#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) \ + ((int)XFS_IFORK_PTR((cur)->bc_private.b.ip, \ + (cur)->bc_private.b.whichfork)->if_broot_bytes) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_IBLOCK_SIZE) +int xfs_bmap_iblock_size(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_IBLOCK_SIZE(lev,cur) xfs_bmap_iblock_size(lev,cur) +#else +#define XFS_BMAP_IBLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DSIZE) +int xfs_bmap_block_dsize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DSIZE(lev,cur) xfs_bmap_block_dsize(lev,cur) +#else +#define XFS_BMAP_BLOCK_DSIZE(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BMAP_RBLOCK_DSIZE(lev,cur) : \ + XFS_BMAP_IBLOCK_SIZE(lev,cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_ISIZE) +int xfs_bmap_block_isize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_ISIZE(lev,cur) xfs_bmap_block_isize(lev,cur) +#else +#define XFS_BMAP_BLOCK_ISIZE(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BMAP_RBLOCK_ISIZE(lev,cur) : \ + XFS_BMAP_IBLOCK_SIZE(lev,cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DMAXRECS) +int xfs_bmap_block_dmaxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) xfs_bmap_block_dmaxrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \ + xfs_bmdr, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_IMAXRECS) +int xfs_bmap_block_imaxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) xfs_bmap_block_imaxrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur), \ + xfs_bmbt, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DMINRECS) +int xfs_bmap_block_dminrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) xfs_bmap_block_dminrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \ + xfs_bmdr, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_IMINRECS) +int xfs_bmap_block_iminrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) xfs_bmap_block_iminrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur), \ + xfs_bmbt, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_REC_DADDR) +xfs_bmbt_rec_t * +xfs_bmap_rec_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_REC_DADDR(bb,i,cur) xfs_bmap_rec_daddr(bb,i,cur) +#else +#define XFS_BMAP_REC_DADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_REC_IADDR) +xfs_bmbt_rec_t * +xfs_bmap_rec_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_REC_IADDR(bb,i,cur) xfs_bmap_rec_iaddr(bb,i,cur) +#else +#define XFS_BMAP_REC_IADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_KEY_DADDR) +xfs_bmbt_key_t * +xfs_bmap_key_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_KEY_DADDR(bb,i,cur) xfs_bmap_key_daddr(bb,i,cur) +#else +#define XFS_BMAP_KEY_DADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_KEY_IADDR) +xfs_bmbt_key_t * +xfs_bmap_key_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_KEY_IADDR(bb,i,cur) xfs_bmap_key_iaddr(bb,i,cur) +#else +#define XFS_BMAP_KEY_IADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_PTR_DADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_PTR_DADDR(bb,i,cur) xfs_bmap_ptr_daddr(bb,i,cur) +#else +#define XFS_BMAP_PTR_DADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_PTR_IADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_PTR_IADDR(bb,i,cur) xfs_bmap_ptr_iaddr(bb,i,cur) +#else +#define XFS_BMAP_PTR_IADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +/* + * These are to be used when we know the size of the block and + * we don't have a cursor. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_REC_ADDR) +xfs_bmbt_rec_t *xfs_bmap_broot_rec_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) xfs_bmap_broot_rec_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) \ + XFS_BTREE_REC_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_KEY_ADDR) +xfs_bmbt_key_t *xfs_bmap_broot_key_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) xfs_bmap_broot_key_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) \ + XFS_BTREE_KEY_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_PTR_ADDR) +xfs_bmbt_ptr_t *xfs_bmap_broot_ptr_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) xfs_bmap_broot_ptr_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) \ + XFS_BTREE_PTR_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_NUMRECS) +int xfs_bmap_broot_numrecs(xfs_bmdr_block_t *bb); +#define XFS_BMAP_BROOT_NUMRECS(bb) xfs_bmap_broot_numrecs(bb) +#else +#define XFS_BMAP_BROOT_NUMRECS(bb) (INT_GET((bb)->bb_numrecs, ARCH_CONVERT)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_MAXRECS) +int xfs_bmap_broot_maxrecs(int sz); +#define XFS_BMAP_BROOT_MAXRECS(sz) xfs_bmap_broot_maxrecs(sz) +#else +#define XFS_BMAP_BROOT_MAXRECS(sz) XFS_BTREE_BLOCK_MAXRECS(sz,xfs_bmbt,0) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_SPACE_CALC) +int xfs_bmap_broot_space_calc(int nrecs); +#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) xfs_bmap_broot_space_calc(nrecs) +#else +#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) \ + ((int)(sizeof(xfs_bmbt_block_t) + \ + ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_SPACE) +int xfs_bmap_broot_space(xfs_bmdr_block_t *bb); +#define XFS_BMAP_BROOT_SPACE(bb) xfs_bmap_broot_space(bb) +#else +#define XFS_BMAP_BROOT_SPACE(bb) \ + XFS_BMAP_BROOT_SPACE_CALC(INT_GET((bb)->bb_numrecs, ARCH_CONVERT)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMDR_SPACE_CALC) +int xfs_bmdr_space_calc(int nrecs); +#define XFS_BMDR_SPACE_CALC(nrecs) xfs_bmdr_space_calc(nrecs) +#else +#define XFS_BMDR_SPACE_CALC(nrecs) \ + ((int)(sizeof(xfs_bmdr_block_t) + \ + ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))) +#endif + +/* + * Maximum number of bmap btree levels. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BM_MAXLEVELS) +int xfs_bm_maxlevels(struct xfs_mount *mp, int w); +#define XFS_BM_MAXLEVELS(mp,w) xfs_bm_maxlevels(mp,w) +#else +#define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[w]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_SANITY_CHECK) +int xfs_bmap_sanity_check(struct xfs_mount *mp, xfs_bmbt_block_t *bb, + int level); +#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \ + xfs_bmap_sanity_check(mp,bb,level) +#else +#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \ + (INT_GET((bb)->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC && \ + INT_GET((bb)->bb_level, ARCH_CONVERT) == level && \ + INT_GET((bb)->bb_numrecs, ARCH_CONVERT) > 0 && \ + INT_GET((bb)->bb_numrecs, ARCH_CONVERT) <= (mp)->m_bmap_dmxr[(level) != 0]) +#endif + +/* + * Trace buffer entry types. + */ +#define XFS_BMBT_KTRACE_ARGBI 1 +#define XFS_BMBT_KTRACE_ARGBII 2 +#define XFS_BMBT_KTRACE_ARGFFFI 3 +#define XFS_BMBT_KTRACE_ARGI 4 +#define XFS_BMBT_KTRACE_ARGIFK 5 +#define XFS_BMBT_KTRACE_ARGIFR 6 +#define XFS_BMBT_KTRACE_ARGIK 7 +#define XFS_BMBT_KTRACE_CUR 8 + +#define XFS_BMBT_TRACE_SIZE 4096 /* size of global trace buffer */ +#define XFS_BMBT_KTRACE_SIZE 32 /* size of per-inode trace buffer */ + +#if defined(XFS_ALL_TRACE) +#define XFS_BMBT_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BMBT_TRACE +#endif + + +/* + * Prototypes for xfs_bmap.c to call. + */ + +void +xfs_bmdr_to_bmbt( + xfs_bmdr_block_t *, + int, + xfs_bmbt_block_t *, + int); + +int +xfs_bmbt_decrement( + struct xfs_btree_cur *, + int, + int *); + +int +xfs_bmbt_delete( + struct xfs_btree_cur *, + int, + int *); + +void +xfs_bmbt_get_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s); + +xfs_bmbt_block_t * +xfs_bmbt_get_block( + struct xfs_btree_cur *cur, + int level, + struct xfs_buf **bpp); + +xfs_filblks_t +xfs_bmbt_get_blockcount( + xfs_bmbt_rec_t *r); + +xfs_fsblock_t +xfs_bmbt_get_startblock( + xfs_bmbt_rec_t *r); + +xfs_fileoff_t +xfs_bmbt_get_startoff( + xfs_bmbt_rec_t *r); + +xfs_exntst_t +xfs_bmbt_get_state( + xfs_bmbt_rec_t *r); + +int +xfs_bmbt_increment( + struct xfs_btree_cur *, + int, + int *); + +int +xfs_bmbt_insert( + struct xfs_btree_cur *, + int *); + +int +xfs_bmbt_insert_many( + struct xfs_btree_cur *, + int, + xfs_bmbt_rec_t *, + int *); + +void +xfs_bmbt_log_block( + struct xfs_btree_cur *, + struct xfs_buf *, + int); + +void +xfs_bmbt_log_recs( + struct xfs_btree_cur *, + struct xfs_buf *, + int, + int); + +int +xfs_bmbt_lookup_eq( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +int +xfs_bmbt_lookup_ge( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +int +xfs_bmbt_lookup_le( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +/* + * Give the bmap btree a new root block. Copy the old broot contents + * down into a real block and make the broot point to it. + */ +int /* error */ +xfs_bmbt_newroot( + struct xfs_btree_cur *cur, /* btree cursor */ + int *logflags, /* logging flags for inode */ + int *stat); /* return status - 0 fail */ + +void +xfs_bmbt_set_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s); + +void +xfs_bmbt_set_allf( + xfs_bmbt_rec_t *r, + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_filblks_t c, + xfs_exntst_t v); + +void +xfs_bmbt_set_blockcount( + xfs_bmbt_rec_t *r, + xfs_filblks_t v); + +void +xfs_bmbt_set_startblock( + xfs_bmbt_rec_t *r, + xfs_fsblock_t v); + +void +xfs_bmbt_set_startoff( + xfs_bmbt_rec_t *r, + xfs_fileoff_t v); + +void +xfs_bmbt_set_state( + xfs_bmbt_rec_t *r, + xfs_exntst_t v); + +void +xfs_bmbt_to_bmdr( + xfs_bmbt_block_t *, + int, + xfs_bmdr_block_t *, + int); + +int +xfs_bmbt_update( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + xfs_exntst_t); + +#ifdef XFSDEBUG +/* + * Get the data from the pointed-to record. + */ +int +xfs_bmbt_get_rec( + struct xfs_btree_cur *, + xfs_fileoff_t *, + xfs_fsblock_t *, + xfs_filblks_t *, + xfs_exntst_t *, + int *); +#endif + + +/* + * Search an extent list for the extent which includes block + * bno. + */ +xfs_bmbt_rec_t * +xfs_bmap_do_search_extents( + xfs_bmbt_rec_t *, + xfs_extnum_t, + xfs_extnum_t, + xfs_fileoff_t, + int *, + xfs_extnum_t *, + xfs_bmbt_irec_t *, + xfs_bmbt_irec_t *); + + +#endif /* __XFS_BMAP_BTREE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_btree.c linux-2.4.19-sgi211r3/fs/xfs/xfs_btree.c --- linux-2.4.19/fs/xfs/xfs_btree.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_btree.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,937 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains common code for the space manager's btree implementations. + */ + +#include + +/* + * Cursor allocation zone. + */ +kmem_zone_t *xfs_btree_cur_zone; + +/* + * Btree magic numbers. + */ +const __uint32_t xfs_magics[XFS_BTNUM_MAX] = +{ + XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC +}; + +/* + * Prototypes for internal routines. + */ + +/* + * Checking routine: return maxrecs for the block. + */ +STATIC int /* number of records fitting in block */ +xfs_btree_maxrecs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block);/* generic btree block pointer */ + +/* + * Internal routines. + */ + +/* + * Checking routine: return maxrecs for the block. + */ +STATIC int /* number of records fitting in block */ +xfs_btree_maxrecs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block) /* generic btree block pointer */ +{ + switch (cur->bc_btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + return (int)XFS_ALLOC_BLOCK_MAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + case XFS_BTNUM_BMAP: + return (int)XFS_BMAP_BLOCK_IMAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + case XFS_BTNUM_INO: + return (int)XFS_INOBT_BLOCK_MAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + default: + ASSERT(0); + return 0; + } +} + +/* + * External routines. + */ + +#ifdef DEBUG +/* + * Debug routine: check that block header is ok. + */ +void +xfs_btree_check_block( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block, /* generic btree block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer containing block, if any */ +{ + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) + xfs_btree_check_lblock(cur, (xfs_btree_lblock_t *)block, level, + bp); + else + xfs_btree_check_sblock(cur, (xfs_btree_sblock_t *)block, level, + bp); +} + +/* + * Debug routine: check that keys are in the right order. + */ +void +xfs_btree_check_key( + xfs_btnum_t btnum, /* btree identifier */ + void *ak1, /* pointer to left (lower) key */ + void *ak2) /* pointer to right (higher) key */ +{ + switch (btnum) { + case XFS_BTNUM_BNO: { + xfs_alloc_key_t *k1; + xfs_alloc_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ar_startblock, ARCH_CONVERT) < INT_GET(k2->ar_startblock, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_CNT: { + xfs_alloc_key_t *k1; + xfs_alloc_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ar_blockcount, ARCH_CONVERT) < INT_GET(k2->ar_blockcount, ARCH_CONVERT) || + (INT_GET(k1->ar_blockcount, ARCH_CONVERT) == INT_GET(k2->ar_blockcount, ARCH_CONVERT) && + INT_GET(k1->ar_startblock, ARCH_CONVERT) < INT_GET(k2->ar_startblock, ARCH_CONVERT))); + break; + } + case XFS_BTNUM_BMAP: { + xfs_bmbt_key_t *k1; + xfs_bmbt_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->br_startoff, ARCH_CONVERT) < INT_GET(k2->br_startoff, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_INO: { + xfs_inobt_key_t *k1; + xfs_inobt_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ir_startino, ARCH_CONVERT) < INT_GET(k2->ir_startino, ARCH_CONVERT)); + break; + } + default: + ASSERT(0); + } +} +#endif /* DEBUG */ + +/* + * Checking routine: check that long form block header is ok. + */ +/* ARGSUSED */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_lblock_t *block, /* btree long form block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer for block, if any */ +{ + int lblock_ok; /* block passes checks */ + xfs_mount_t *mp; /* file system mount point */ + + mp = cur->bc_mp; + lblock_ok = + INT_GET(block->bb_magic, ARCH_CONVERT) == xfs_magics[cur->bc_btnum] && + INT_GET(block->bb_level, ARCH_CONVERT) == level && + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) && + !INT_ISZERO(block->bb_leftsib, ARCH_CONVERT) && + (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO || + XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_leftsib, ARCH_CONVERT))) && + !INT_ISZERO(block->bb_rightsib, ARCH_CONVERT) && + (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO || + XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_rightsib, ARCH_CONVERT))); + if (XFS_TEST_ERROR(!lblock_ok, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK, + XFS_RANDOM_BTREE_CHECK_LBLOCK)) { + if (bp) + xfs_buftrace("LBTREE ERROR", bp); +#ifdef __KERNEL__ /* additional, temporary, debugging code */ + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Checking routine: check that (long) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_dfsbno_t ptr, /* btree block disk address */ + int level) /* btree block level */ +{ + xfs_mount_t *mp; /* file system mount point */ + + mp = cur->bc_mp; + XFS_WANT_CORRUPTED_RETURN( + level > 0 && + ptr != NULLDFSBNO && + XFS_FSB_SANITY_CHECK(mp, ptr)); + return 0; +} + +#ifdef DEBUG +/* + * Debug routine: check that records are in the right order. + */ +void +xfs_btree_check_rec( + xfs_btnum_t btnum, /* btree identifier */ + void *ar1, /* pointer to left (lower) record */ + void *ar2) /* pointer to right (higher) record */ +{ + switch (btnum) { + case XFS_BTNUM_BNO: { + xfs_alloc_rec_t *r1; + xfs_alloc_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ar_startblock, ARCH_CONVERT) + INT_GET(r1->ar_blockcount, ARCH_CONVERT) <= + INT_GET(r2->ar_startblock, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_CNT: { + xfs_alloc_rec_t *r1; + xfs_alloc_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ar_blockcount, ARCH_CONVERT) < INT_GET(r2->ar_blockcount, ARCH_CONVERT) || + (INT_GET(r1->ar_blockcount, ARCH_CONVERT) == INT_GET(r2->ar_blockcount, ARCH_CONVERT) && + INT_GET(r1->ar_startblock, ARCH_CONVERT) < INT_GET(r2->ar_startblock, ARCH_CONVERT))); + break; + } + case XFS_BTNUM_BMAP: { + xfs_bmbt_rec_t *r1; + xfs_bmbt_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(xfs_bmbt_get_startoff(r1) + + xfs_bmbt_get_blockcount(r1) <= + xfs_bmbt_get_startoff(r2)); + break; + } + case XFS_BTNUM_INO: { + xfs_inobt_rec_t *r1; + xfs_inobt_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ir_startino, ARCH_CONVERT) + XFS_INODES_PER_CHUNK <= + INT_GET(r2->ir_startino, ARCH_CONVERT)); + break; + } + default: + ASSERT(0); + } +} +#endif /* DEBUG */ + +/* + * Checking routine: check that block header is ok. + */ +/* ARGSUSED */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_sblock_t *block, /* btree short form block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer containing block */ +{ + xfs_buf_t *agbp; /* buffer for ag. freespace struct */ + xfs_agf_t *agf; /* ag. freespace structure */ + xfs_agblock_t agflen; /* native ag. freespace length */ + int sblock_ok; /* block passes checks */ + + agbp = cur->bc_private.a.agbp; + agf = XFS_BUF_TO_AGF(agbp); + agflen = INT_GET(agf->agf_length, ARCH_CONVERT); + sblock_ok = + INT_GET(block->bb_magic, ARCH_CONVERT) == xfs_magics[cur->bc_btnum] && + INT_GET(block->bb_level, ARCH_CONVERT) == level && + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) && + (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK || + INT_GET(block->bb_leftsib, ARCH_CONVERT) < agflen) && + !INT_ISZERO(block->bb_leftsib, ARCH_CONVERT) && + (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK || + INT_GET(block->bb_rightsib, ARCH_CONVERT) < agflen) && + !INT_ISZERO(block->bb_rightsib, ARCH_CONVERT); + if (XFS_TEST_ERROR(!sblock_ok, cur->bc_mp, + XFS_ERRTAG_BTREE_CHECK_SBLOCK, + XFS_RANDOM_BTREE_CHECK_SBLOCK)) { + if (bp) + xfs_buftrace("SBTREE ERROR", bp); +#ifdef __KERNEL__ /* additional, temporary, debugging code */ + cmn_err(CE_NOTE, + "xfs_btree_check_sblock: Not OK:"); + cmn_err(CE_NOTE, + "magic 0x%x level %d numrecs %d leftsib %d rightsib %d", + INT_GET(block->bb_magic, ARCH_CONVERT), + INT_GET(block->bb_level, ARCH_CONVERT), + INT_GET(block->bb_numrecs, ARCH_CONVERT), + INT_GET(block->bb_leftsib, ARCH_CONVERT), + INT_GET(block->bb_rightsib, ARCH_CONVERT)); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Checking routine: check that (short) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t ptr, /* btree block disk address */ + int level) /* btree block level */ +{ + xfs_buf_t *agbp; /* buffer for ag. freespace struct */ + xfs_agf_t *agf; /* ag. freespace structure */ + + agbp = cur->bc_private.a.agbp; + agf = XFS_BUF_TO_AGF(agbp); + XFS_WANT_CORRUPTED_RETURN( + level > 0 && + ptr != NULLAGBLOCK && ptr != 0 && + ptr < INT_GET(agf->agf_length, ARCH_CONVERT)); + return 0; +} + +/* + * Delete the btree cursor. + */ +void +xfs_btree_del_cursor( + xfs_btree_cur_t *cur, /* btree cursor */ + int error) /* del because of error */ +{ + int i; /* btree level */ + + /* + * Clear the buffer pointers, and release the buffers. + * If we're doing this in the face of an error, we + * need to make sure to inspect all of the entries + * in the bc_bufs array for buffers to be unlocked. + * This is because some of the btree code works from + * level n down to 0, and if we get an error along + * the way we won't have initialized all the entries + * down to 0. + */ + for (i = 0; i < cur->bc_nlevels; i++) { + if (cur->bc_bufs[i]) + xfs_btree_setbuf(cur, i, NULL); + else if (!error) + break; + } + /* + * Can't free a bmap cursor without having dealt with the + * allocated indirect blocks' accounting. + */ + ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP || + cur->bc_private.b.allocated == 0); + /* + * Free the cursor. + */ + kmem_zone_free(xfs_btree_cur_zone, cur); +} + +/* + * Duplicate the btree cursor. + * Allocate a new one, copy the record, re-get the buffers. + */ +int /* error */ +xfs_btree_dup_cursor( + xfs_btree_cur_t *cur, /* input cursor */ + xfs_btree_cur_t **ncur) /* output cursor */ +{ + xfs_buf_t *bp; /* btree block's buffer pointer */ + int error; /* error return value */ + int i; /* level number of btree block */ + xfs_mount_t *mp; /* mount structure for filesystem */ + xfs_btree_cur_t *new; /* new cursor value */ + xfs_trans_t *tp; /* transaction pointer, can be NULL */ + + tp = cur->bc_tp; + mp = cur->bc_mp; + /* + * Allocate a new cursor like the old one. + */ + new = xfs_btree_init_cursor(mp, tp, cur->bc_private.a.agbp, + cur->bc_private.a.agno, cur->bc_btnum, cur->bc_private.b.ip, + cur->bc_private.b.whichfork); + /* + * Copy the record currently in the cursor. + */ + new->bc_rec = cur->bc_rec; + /* + * For each level current, re-get the buffer and copy the ptr value. + */ + for (i = 0; i < new->bc_nlevels; i++) { + new->bc_ptrs[i] = cur->bc_ptrs[i]; + new->bc_ra[i] = cur->bc_ra[i]; + if ((bp = cur->bc_bufs[i])) { + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, + XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp))) { + xfs_btree_del_cursor(new, error); + *ncur = NULL; + return error; + } + new->bc_bufs[i] = bp; + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + } else + new->bc_bufs[i] = NULL; + } + /* + * For bmap btrees, copy the firstblock, flist, and flags values, + * since init cursor doesn't get them. + */ + if (new->bc_btnum == XFS_BTNUM_BMAP) { + new->bc_private.b.firstblock = cur->bc_private.b.firstblock; + new->bc_private.b.flist = cur->bc_private.b.flist; + new->bc_private.b.flags = cur->bc_private.b.flags; + } + *ncur = new; + return 0; +} + +/* + * Change the cursor to point to the first record at the given level. + * Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_firstrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to change */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + /* + * Get the block pointer for this level. + */ + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + /* + * It's empty, there is no such record. + */ + if (INT_ISZERO(block->bb_h.bb_numrecs, ARCH_CONVERT)) + return 0; + /* + * Set the ptr value to 1, that's the first record/key. + */ + cur->bc_ptrs[level] = 1; + return 1; +} + +/* + * Retrieve the block pointer from the cursor at the given level. + * This may be a bmap btree root or from a buffer. + */ +xfs_btree_block_t * /* generic btree block pointer */ +xfs_btree_get_block( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree */ + xfs_buf_t **bpp) /* buffer containing the block */ +{ + xfs_btree_block_t *block; /* return value */ + xfs_buf_t *bp; /* return buffer */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int whichfork; /* data or attr fork */ + + if (cur->bc_btnum == XFS_BTNUM_BMAP && level == cur->bc_nlevels - 1) { + whichfork = cur->bc_private.b.whichfork; + ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, whichfork); + block = (xfs_btree_block_t *)ifp->if_broot; + bp = NULL; + } else { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_BLOCK(bp); + } + ASSERT(block != NULL); + *bpp = bp; + return block; +} + +/* + * Get a buffer for the block, return it with no data read. + * Long-form addressing. + */ +xfs_buf_t * /* buffer for fsbno */ +xfs_btree_get_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock) /* lock flags for get_buf */ +{ + xfs_buf_t *bp; /* buffer pointer (return value) */ + xfs_daddr_t d; /* real disk block address */ + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + return bp; +} + +/* + * Get a buffer for the block, return it with no data read. + * Short-form addressing. + */ +xfs_buf_t * /* buffer for agno/agbno */ +xfs_btree_get_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock) /* lock flags for get_buf */ +{ + xfs_buf_t *bp; /* buffer pointer (return value) */ + xfs_daddr_t d; /* real disk block address */ + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + return bp; +} + +/* + * Allocate a new btree cursor. + * The cursor is either for allocation (A) or bmap (B) or inodes (I). + */ +xfs_btree_cur_t * /* new btree cursor */ +xfs_btree_init_cursor( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* (A only) buffer for agf structure */ + /* (I only) buffer for agi structure */ + xfs_agnumber_t agno, /* (AI only) allocation group number */ + xfs_btnum_t btnum, /* btree identifier */ + xfs_inode_t *ip, /* (B only) inode owning the btree */ + int whichfork) /* (B only) data or attr fork */ +{ + xfs_agf_t *agf; /* (A) allocation group freespace */ + xfs_agi_t *agi; /* (I) allocation group inodespace */ + xfs_btree_cur_t *cur; /* return value */ + xfs_ifork_t *ifp; /* (I) inode fork pointer */ + int nlevels=0; /* number of levels in the btree */ + + ASSERT(xfs_btree_cur_zone != NULL); + /* + * Allocate a new cursor. + */ + cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); + /* + * Deduce the number of btree levels from the arguments. + */ + switch (btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + agf = XFS_BUF_TO_AGF(agbp); + nlevels = INT_GET(agf->agf_levels[btnum], ARCH_CONVERT); + break; + case XFS_BTNUM_BMAP: + ifp = XFS_IFORK_PTR(ip, whichfork); + nlevels = INT_GET(ifp->if_broot->bb_level, ARCH_CONVERT) + 1; + break; + case XFS_BTNUM_INO: + agi = XFS_BUF_TO_AGI(agbp); + nlevels = INT_GET(agi->agi_level, ARCH_CONVERT); + break; + default: + ASSERT(0); + } + /* + * Fill in the common fields. + */ + cur->bc_tp = tp; + cur->bc_mp = mp; + cur->bc_nlevels = nlevels; + cur->bc_btnum = btnum; + cur->bc_blocklog = mp->m_sb.sb_blocklog; + /* + * Fill in private fields. + */ + switch (btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + /* + * Allocation btree fields. + */ + cur->bc_private.a.agbp = agbp; + cur->bc_private.a.agno = agno; + break; + case XFS_BTNUM_BMAP: + /* + * Bmap btree fields. + */ + cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); + cur->bc_private.b.ip = ip; + cur->bc_private.b.firstblock = NULLFSBLOCK; + cur->bc_private.b.flist = NULL; + cur->bc_private.b.allocated = 0; + cur->bc_private.b.flags = 0; + cur->bc_private.b.whichfork = whichfork; + break; + case XFS_BTNUM_INO: + /* + * Inode allocation btree fields. + */ + cur->bc_private.i.agbp = agbp; + cur->bc_private.i.agno = agno; + break; + default: + ASSERT(0); + } + return cur; +} + +/* + * Check for the cursor referring to the last block at the given level. + */ +int /* 1=is last block, 0=not last block */ +xfs_btree_islastblock( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to check */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) + return INT_GET(block->bb_u.l.bb_rightsib, ARCH_CONVERT) == NULLDFSBNO; + else + return INT_GET(block->bb_u.s.bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK; +} + +/* + * Change the cursor to point to the last record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_lastrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to change */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + /* + * Get the block pointer for this level. + */ + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + /* + * It's empty, there is no such record. + */ + if (INT_ISZERO(block->bb_h.bb_numrecs, ARCH_CONVERT)) + return 0; + /* + * Set the ptr value to numrecs, that's the last record/key. + */ + cur->bc_ptrs[level] = INT_GET(block->bb_h.bb_numrecs, ARCH_CONVERT); + return 1; +} + +/* + * Compute first and last byte offsets for the fields given. + * Interprets the offsets table, which contains struct field offsets. + */ +void +xfs_btree_offsets( + __int64_t fields, /* bitmask of fields */ + const short *offsets, /* table of field offsets */ + int nbits, /* number of bits to inspect */ + int *first, /* output: first byte offset */ + int *last) /* output: last byte offset */ +{ + int i; /* current bit number */ + __int64_t imask; /* mask for current bit number */ + + ASSERT(fields != 0); + /* + * Find the lowest bit, so the first byte offset. + */ + for (i = 0, imask = 1LL; ; i++, imask <<= 1) { + if (imask & fields) { + *first = offsets[i]; + break; + } + } + /* + * Find the highest bit, so the last byte offset. + */ + for (i = nbits - 1, imask = 1LL << i; ; i--, imask >>= 1) { + if (imask & fields) { + *last = offsets[i + 1] - 1; + break; + } + } +} + +/* + * Get a buffer for the block, return it read in. + * Long-form addressing. + */ +int /* error */ +xfs_btree_read_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock, /* lock flags for read_buf */ + xfs_buf_t **bpp, /* buffer for fsbno */ + int refval) /* ref count value for buffer */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* real disk block address */ + int error; + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, lock, &bp))) { + return error; + } + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (bp != NULL) { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval); + } + *bpp = bp; + return 0; +} + +/* + * Get a buffer for the block, return it read in. + * Short-form addressing. + */ +int /* error */ +xfs_btree_read_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock, /* lock flags for read_buf */ + xfs_buf_t **bpp, /* buffer for agno/agbno */ + int refval) /* ref count value for buffer */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* real disk block address */ + int error; + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, lock, &bp))) { + return error; + } + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (bp != NULL) { + switch (refval) { + case XFS_ALLOC_BTREE_REF: + XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval); + break; + case XFS_INO_BTREE_REF: + XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, refval); + break; + } + } + *bpp = bp; + return 0; +} + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Long-form addressing. + */ +/* ARGSUSED */ +void +xfs_btree_reada_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_fsblock_t fsbno, /* file system block number */ + xfs_extlen_t count) /* count of filesystem blocks */ +{ + xfs_daddr_t d; + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count); +} + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Short-form addressing. + */ +/* ARGSUSED */ +void +xfs_btree_reada_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + xfs_extlen_t count) /* count of filesystem blocks */ +{ + xfs_daddr_t d; + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count); +} + +/* + * Read-ahead btree blocks, at the given level. + * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. + */ +int +xfs_btree_readahead_core( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr) /* left/right bits */ +{ + xfs_alloc_block_t *a; + xfs_bmbt_block_t *b; + xfs_inobt_block_t *i; + int rval = 0; + + ASSERT(cur->bc_bufs[lev] != NULL); + cur->bc_ra[lev] |= lr; + switch (cur->bc_btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + a = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(a->bb_leftsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, + INT_GET(a->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(a->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, + INT_GET(a->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + case XFS_BTNUM_BMAP: + b = XFS_BUF_TO_BMBT_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(b->bb_leftsib, ARCH_CONVERT) != NULLDFSBNO) { + xfs_btree_reada_bufl(cur->bc_mp, INT_GET(b->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(b->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + xfs_btree_reada_bufl(cur->bc_mp, INT_GET(b->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + case XFS_BTNUM_INO: + i = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(i->bb_leftsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, + INT_GET(i->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(i->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, + INT_GET(i->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + default: + ASSERT(0); + } + return rval; +} + +/* + * Set the buffer for level "lev" in the cursor to bp, releasing + * any previous buffer. + */ +void +xfs_btree_setbuf( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + xfs_buf_t *bp) /* new buffer to set */ +{ + xfs_btree_block_t *b; /* btree block */ + xfs_buf_t *obp; /* old buffer pointer */ + + obp = cur->bc_bufs[lev]; + if (obp) + xfs_trans_brelse(cur->bc_tp, obp); + cur->bc_bufs[lev] = bp; + cur->bc_ra[lev] = 0; + if (!bp) + return; + b = XFS_BUF_TO_BLOCK(bp); + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) { + if (INT_GET(b->bb_u.l.bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) + cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; + if (INT_GET(b->bb_u.l.bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) + cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; + } else { + if (INT_GET(b->bb_u.s.bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) + cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; + if (INT_GET(b->bb_u.s.bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) + cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; + } +} diff -Nur linux-2.4.19/fs/xfs/xfs_btree.h linux-2.4.19-sgi211r3/fs/xfs/xfs_btree.h --- linux-2.4.19/fs/xfs/xfs_btree.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_btree.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BTREE_H__ +#define __XFS_BTREE_H__ + +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * This nonsense is to make -wlint happy. + */ +#define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) +#define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) +#define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) + +#define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) +#define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) +#define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) +#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) + +/* + * Short form header: space allocation btrees. + */ +typedef struct xfs_btree_sblock +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ + xfs_agblock_t bb_leftsib; /* left sibling block or NULLAGBLOCK */ + xfs_agblock_t bb_rightsib; /* right sibling block or NULLAGBLOCK */ +} xfs_btree_sblock_t; + +/* + * Long form header: bmap btrees. + */ +typedef struct xfs_btree_lblock +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ + xfs_dfsbno_t bb_leftsib; /* left sibling block or NULLDFSBNO */ + xfs_dfsbno_t bb_rightsib; /* right sibling block or NULLDFSBNO */ +} xfs_btree_lblock_t; + +/* + * Combined header and structure, used by common code. + */ +typedef struct xfs_btree_hdr +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_btree_hdr_t; + +typedef struct xfs_btree_block +{ + xfs_btree_hdr_t bb_h; /* header */ + union { + struct { + xfs_agblock_t bb_leftsib; + xfs_agblock_t bb_rightsib; + } s; /* short form pointers */ + struct { + xfs_dfsbno_t bb_leftsib; + xfs_dfsbno_t bb_rightsib; + } l; /* long form pointers */ + } bb_u; /* rest */ +} xfs_btree_block_t; + +/* + * For logging record fields. + */ +#define XFS_BB_MAGIC 0x01 +#define XFS_BB_LEVEL 0x02 +#define XFS_BB_NUMRECS 0x04 +#define XFS_BB_LEFTSIB 0x08 +#define XFS_BB_RIGHTSIB 0x10 +#define XFS_BB_NUM_BITS 5 +#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) + +/* + * Boolean to select which form of xfs_btree_block_t.bb_u to use. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BTREE_LONG_PTRS) +int xfs_btree_long_ptrs(xfs_btnum_t btnum); +#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP) +#else +#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP) +#endif + +/* + * Magic numbers for btree blocks. + */ +extern const __uint32_t xfs_magics[]; + +/* + * Maximum and minimum records in a btree block. + * Given block size, type prefix, and leaf flag (0 or 1). + * The divisor below is equivalent to lf ? (e1) : (e2) but that produces + * compiler warnings. + */ +#define XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) \ + ((int)(((bsz) - (uint)sizeof(t ## _block_t)) / \ + (((lf) * (uint)sizeof(t ## _rec_t)) + \ + ((1 - (lf)) * \ + ((uint)sizeof(t ## _key_t) + (uint)sizeof(t ## _ptr_t)))))) +#define XFS_BTREE_BLOCK_MINRECS(bsz,t,lf) \ + (XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) / 2) + +/* + * Record, key, and pointer address calculation macros. + * Given block size, type prefix, block pointer, and index of requested entry + * (first entry numbered 1). + */ +#define XFS_BTREE_REC_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _rec_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + ((i) - 1) * sizeof(t ## _rec_t))) +#define XFS_BTREE_KEY_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _key_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + ((i) - 1) * sizeof(t ## _key_t))) +#define XFS_BTREE_PTR_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _ptr_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + (mxr) * sizeof(t ## _key_t) + ((i) - 1) * sizeof(t ## _ptr_t))) + +#define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */ + +/* + * Btree cursor structure. + * This collects all information needed by the btree code in one place. + */ +typedef struct xfs_btree_cur +{ + struct xfs_trans *bc_tp; /* transaction we're in, if any */ + struct xfs_mount *bc_mp; /* file system mount struct */ + union { + xfs_alloc_rec_t a; + xfs_bmbt_irec_t b; + xfs_inobt_rec_t i; + } bc_rec; /* current insert/search record value */ + struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ + int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ + __uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ +#define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ +#define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ + __uint8_t bc_nlevels; /* number of levels in the tree */ + __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ + xfs_btnum_t bc_btnum; /* identifies which btree type */ + union { + struct { /* needed for BNO, CNT */ + struct xfs_buf *agbp; /* agf buffer pointer */ + xfs_agnumber_t agno; /* ag number */ + } a; + struct { /* needed for BMAP */ + struct xfs_inode *ip; /* pointer to our inode */ + struct xfs_bmap_free *flist; /* list to free after */ + xfs_fsblock_t firstblock; /* 1st blk allocated */ + int allocated; /* count of alloced */ + short forksize; /* fork's inode space */ + char whichfork; /* data or attr fork */ + char flags; /* flags */ +#define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ + } b; + struct { /* needed for INO */ + struct xfs_buf *agbp; /* agi buffer pointer */ + xfs_agnumber_t agno; /* ag number */ + } i; + } bc_private; /* per-btree type data */ +} xfs_btree_cur_t; + +#define XFS_BTREE_NOERROR 0 +#define XFS_BTREE_ERROR 1 + +/* + * Convert from buffer to btree block header. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_BLOCK) +xfs_btree_block_t *xfs_buf_to_block(struct xfs_buf *bp); +#define XFS_BUF_TO_BLOCK(bp) xfs_buf_to_block(bp) +#else +#define XFS_BUF_TO_BLOCK(bp) ((xfs_btree_block_t *)(XFS_BUF_PTR(bp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_LBLOCK) +xfs_btree_lblock_t *xfs_buf_to_lblock(struct xfs_buf *bp); +#define XFS_BUF_TO_LBLOCK(bp) xfs_buf_to_lblock(bp) +#else +#define XFS_BUF_TO_LBLOCK(bp) ((xfs_btree_lblock_t *)(XFS_BUF_PTR(bp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBLOCK) +xfs_btree_sblock_t *xfs_buf_to_sblock(struct xfs_buf *bp); +#define XFS_BUF_TO_SBLOCK(bp) xfs_buf_to_sblock(bp) +#else +#define XFS_BUF_TO_SBLOCK(bp) ((xfs_btree_sblock_t *)(XFS_BUF_PTR(bp))) +#endif + +#ifdef __KERNEL__ + +#ifdef DEBUG +/* + * Debug routine: check that block header is ok. + */ +void +xfs_btree_check_block( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block, /* generic btree block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block, if any */ + +/* + * Debug routine: check that keys are in the right order. + */ +void +xfs_btree_check_key( + xfs_btnum_t btnum, /* btree identifier */ + void *ak1, /* pointer to left (lower) key */ + void *ak2); /* pointer to right (higher) key */ + +/* + * Debug routine: check that records are in the right order. + */ +void +xfs_btree_check_rec( + xfs_btnum_t btnum, /* btree identifier */ + void *ar1, /* pointer to left (lower) record */ + void *ar2); /* pointer to right (higher) record */ +#else +#define xfs_btree_check_block(a,b,c,d) +#define xfs_btree_check_key(a,b,c) +#define xfs_btree_check_rec(a,b,c) +#endif /* DEBUG */ + +/* + * Checking routine: check that long form block header is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_lblock_t *block, /* btree long form block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block, if any */ + +/* + * Checking routine: check that (long) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_dfsbno_t ptr, /* btree block disk address */ + int level); /* btree block level */ + +/* + * Checking routine: check that short form block header is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_sblock_t *block, /* btree short form block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block */ + +/* + * Checking routine: check that (short) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t ptr, /* btree block disk address */ + int level); /* btree block level */ + +/* + * Delete the btree cursor. + */ +void +xfs_btree_del_cursor( + xfs_btree_cur_t *cur, /* btree cursor */ + int error); /* del because of error */ + +/* + * Duplicate the btree cursor. + * Allocate a new one, copy the record, re-get the buffers. + */ +int /* error */ +xfs_btree_dup_cursor( + xfs_btree_cur_t *cur, /* input cursor */ + xfs_btree_cur_t **ncur);/* output cursor */ + +/* + * Change the cursor to point to the first record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_firstrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to change */ + +/* + * Retrieve the block pointer from the cursor at the given level. + * This may be a bmap btree root or from a buffer. + */ +xfs_btree_block_t * /* generic btree block pointer */ +xfs_btree_get_block( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree */ + struct xfs_buf **bpp); /* buffer containing the block */ + +/* + * Get a buffer for the block, return it with no data read. + * Long-form addressing. + */ +struct xfs_buf * /* buffer for fsbno */ +xfs_btree_get_bufl( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock); /* lock flags for get_buf */ + +/* + * Get a buffer for the block, return it with no data read. + * Short-form addressing. + */ +struct xfs_buf * /* buffer for agno/agbno */ +xfs_btree_get_bufs( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock); /* lock flags for get_buf */ + +/* + * Allocate a new btree cursor. + * The cursor is either for allocation (A) or bmap (B). + */ +xfs_btree_cur_t * /* new btree cursor */ +xfs_btree_init_cursor( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* (A only) buffer for agf structure */ + xfs_agnumber_t agno, /* (A only) allocation group number */ + xfs_btnum_t btnum, /* btree identifier */ + struct xfs_inode *ip, /* (B only) inode owning the btree */ + int whichfork); /* (B only) data/attr fork */ + +/* + * Check for the cursor referring to the last block at the given level. + */ +int /* 1=is last block, 0=not last block */ +xfs_btree_islastblock( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to check */ + +/* + * Change the cursor to point to the last record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_lastrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to change */ + +/* + * Compute first and last byte offsets for the fields given. + * Interprets the offsets table, which contains struct field offsets. + */ +void +xfs_btree_offsets( + __int64_t fields, /* bitmask of fields */ + const short *offsets,/* table of field offsets */ + int nbits, /* number of bits to inspect */ + int *first, /* output: first byte offset */ + int *last); /* output: last byte offset */ + +/* + * Get a buffer for the block, return it read in. + * Long-form addressing. + */ +int /* error */ +xfs_btree_read_bufl( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock, /* lock flags for read_buf */ + struct xfs_buf **bpp, /* buffer for fsbno */ + int refval);/* ref count value for buffer */ + +/* + * Get a buffer for the block, return it read in. + * Short-form addressing. + */ +int /* error */ +xfs_btree_read_bufs( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock, /* lock flags for read_buf */ + struct xfs_buf **bpp, /* buffer for agno/agbno */ + int refval);/* ref count value for buffer */ + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Long-form addressing. + */ +void /* error */ +xfs_btree_reada_bufl( + struct xfs_mount *mp, /* file system mount point */ + xfs_fsblock_t fsbno, /* file system block number */ + xfs_extlen_t count); /* count of filesystem blocks */ + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Short-form addressing. + */ +void /* error */ +xfs_btree_reada_bufs( + struct xfs_mount *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + xfs_extlen_t count); /* count of filesystem blocks */ + +/* + * Read-ahead btree blocks, at the given level. + * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. + */ +int /* readahead block count */ +xfs_btree_readahead_core( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr); /* left/right bits */ + +static inline int /* readahead block count */ +xfs_btree_readahead( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr) /* left/right bits */ +{ + if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev]) + return 0; + + return xfs_btree_readahead_core(cur, lev, lr); +} + + +/* + * Set the buffer for level "lev" in the cursor to bp, releasing + * any previous buffer. + */ +void +xfs_btree_setbuf( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + struct xfs_buf *bp); /* new buffer to set */ + +#endif /* __KERNEL__ */ + + +/* + * Min and max functions for extlen, agblock, fileoff, and filblks types. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTLEN_MIN) +xfs_extlen_t xfs_extlen_min(xfs_extlen_t a, xfs_extlen_t b); +#define XFS_EXTLEN_MIN(a,b) xfs_extlen_min(a,b) +#else +#define XFS_EXTLEN_MIN(a,b) \ + ((xfs_extlen_t)(a) < (xfs_extlen_t)(b) ? \ + (xfs_extlen_t)(a) : (xfs_extlen_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTLEN_MAX) +xfs_extlen_t xfs_extlen_max(xfs_extlen_t a, xfs_extlen_t b); +#define XFS_EXTLEN_MAX(a,b) xfs_extlen_max(a,b) +#else +#define XFS_EXTLEN_MAX(a,b) \ + ((xfs_extlen_t)(a) > (xfs_extlen_t)(b) ? \ + (xfs_extlen_t)(a) : (xfs_extlen_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGBLOCK_MIN) +xfs_agblock_t xfs_agblock_min(xfs_agblock_t a, xfs_agblock_t b); +#define XFS_AGBLOCK_MIN(a,b) xfs_agblock_min(a,b) +#else +#define XFS_AGBLOCK_MIN(a,b) \ + ((xfs_agblock_t)(a) < (xfs_agblock_t)(b) ? \ + (xfs_agblock_t)(a) : (xfs_agblock_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGBLOCK_MAX) +xfs_agblock_t xfs_agblock_max(xfs_agblock_t a, xfs_agblock_t b); +#define XFS_AGBLOCK_MAX(a,b) xfs_agblock_max(a,b) +#else +#define XFS_AGBLOCK_MAX(a,b) \ + ((xfs_agblock_t)(a) > (xfs_agblock_t)(b) ? \ + (xfs_agblock_t)(a) : (xfs_agblock_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILEOFF_MIN) +xfs_fileoff_t xfs_fileoff_min(xfs_fileoff_t a, xfs_fileoff_t b); +#define XFS_FILEOFF_MIN(a,b) xfs_fileoff_min(a,b) +#else +#define XFS_FILEOFF_MIN(a,b) \ + ((xfs_fileoff_t)(a) < (xfs_fileoff_t)(b) ? \ + (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILEOFF_MAX) +xfs_fileoff_t xfs_fileoff_max(xfs_fileoff_t a, xfs_fileoff_t b); +#define XFS_FILEOFF_MAX(a,b) xfs_fileoff_max(a,b) +#else +#define XFS_FILEOFF_MAX(a,b) \ + ((xfs_fileoff_t)(a) > (xfs_fileoff_t)(b) ? \ + (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILBLKS_MIN) +xfs_filblks_t xfs_filblks_min(xfs_filblks_t a, xfs_filblks_t b); +#define XFS_FILBLKS_MIN(a,b) xfs_filblks_min(a,b) +#else +#define XFS_FILBLKS_MIN(a,b) \ + ((xfs_filblks_t)(a) < (xfs_filblks_t)(b) ? \ + (xfs_filblks_t)(a) : (xfs_filblks_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILBLKS_MAX) +xfs_filblks_t xfs_filblks_max(xfs_filblks_t a, xfs_filblks_t b); +#define XFS_FILBLKS_MAX(a,b) xfs_filblks_max(a,b) +#else +#define XFS_FILBLKS_MAX(a,b) \ + ((xfs_filblks_t)(a) > (xfs_filblks_t)(b) ? \ + (xfs_filblks_t)(a) : (xfs_filblks_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_SANITY_CHECK) +int xfs_fsb_sanity_check(struct xfs_mount *mp, xfs_fsblock_t fsb); +#define XFS_FSB_SANITY_CHECK(mp,fsb) xfs_fsb_sanity_check(mp,fsb) +#else +#define XFS_FSB_SANITY_CHECK(mp,fsb) \ + (XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \ + XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks) +#endif + +/* + * Macros to set EFSCORRUPTED & return/branch. + */ +#define XFS_WANT_CORRUPTED_GOTO(x,l) \ + { \ + int fs_is_ok = (x); \ + ASSERT(fs_is_ok); \ + if (!fs_is_ok) { \ + error = XFS_ERROR(EFSCORRUPTED); \ + goto l; \ + } \ + } + +#define XFS_WANT_CORRUPTED_RETURN(x) \ + { \ + int fs_is_ok = (x); \ + ASSERT(fs_is_ok); \ + if (!fs_is_ok) \ + return XFS_ERROR(EFSCORRUPTED); \ + } + +#endif /* __XFS_BTREE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_buf.h linux-2.4.19-sgi211r3/fs/xfs/xfs_buf.h --- linux-2.4.19/fs/xfs/xfs_buf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_buf.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BUF_H__ +#define __XFS_BUF_H__ + +/* These are just for xfs_syncsub... it sets an internal variable + * then passes it to VOP_FLUSH_PAGES or adds the flags to a newly gotten buf_t + */ +#define XFS_B_ASYNC PBF_ASYNC +#define XFS_B_DELWRI PBF_DELWRI +#define XFS_B_READ PBF_READ +#define XFS_B_WRITE PBF_WRITE +#define XFS_B_STALE PBF_STALE +#define XFS_BUF_TRYLOCK PBF_TRYLOCK +#define XFS_INCORE_TRYLOCK PBF_TRYLOCK +#define XFS_BUF_LOCK PBF_LOCK +#define XFS_BUF_MAPPED PBF_MAPPED + +#define BUF_BUSY PBF_DONT_BLOCK + +#define XFS_BUF_BFLAGS(x) ((x)->pb_flags) /* debugging routines might need this */ +#define XFS_BUF_ZEROFLAGS(x) \ + ((x)->pb_flags &= ~(PBF_READ|PBF_WRITE|PBF_ASYNC|PBF_SYNC|PBF_DELWRI)) + +#define XFS_BUF_STALE(x) ((x)->pb_flags |= XFS_B_STALE) +#define XFS_BUF_UNSTALE(x) ((x)->pb_flags &= ~XFS_B_STALE) +#define XFS_BUF_ISSTALE(x) ((x)->pb_flags & XFS_B_STALE) +#define XFS_BUF_SUPER_STALE(x) (x)->pb_flags |= XFS_B_STALE;\ + xfs_buf_undelay(x);\ + (x)->pb_flags &= ~(PBF_PARTIAL|PBF_NONE) + +static inline void xfs_buf_undelay(page_buf_t *pb) +{ + if (pb->pb_flags & PBF_DELWRI) { + if (pb->pb_list.next != &pb->pb_list) { + pagebuf_delwri_dequeue(pb); + pagebuf_rele(pb); + } else { + pb->pb_flags &= ~PBF_DELWRI; + } + } +} + +#define XFS_BUF_DELAYWRITE(x) ((x)->pb_flags |= PBF_DELWRI) +#define XFS_BUF_UNDELAYWRITE(x) xfs_buf_undelay(x) +#define XFS_BUF_ISDELAYWRITE(x) ((x)->pb_flags & PBF_DELWRI) + +#define XFS_BUF_ERROR(x,no) pagebuf_ioerror(x,no) +#define XFS_BUF_GETERROR(x) pagebuf_geterror(x) +#define XFS_BUF_ISERROR(x) (pagebuf_geterror(x)?1:0) + +#define XFS_BUF_DONE(x) ((x)->pb_flags &= ~(PBF_PARTIAL|PBF_NONE)) +#define XFS_BUF_UNDONE(x) ((x)->pb_flags |= PBF_PARTIAL|PBF_NONE) +#define XFS_BUF_ISDONE(x) (!(PBF_NOT_DONE(x))) + +#define XFS_BUF_BUSY(x) ((x)->pb_flags |= PBF_FORCEIO) +#define XFS_BUF_UNBUSY(x) ((x)->pb_flags &= ~PBF_FORCEIO) +#define XFS_BUF_ISBUSY(x) (1) + +#define XFS_BUF_ASYNC(x) ((x)->pb_flags |= PBF_ASYNC) +#define XFS_BUF_UNASYNC(x) ((x)->pb_flags &= ~PBF_ASYNC) +#define XFS_BUF_ISASYNC(x) ((x)->pb_flags & PBF_ASYNC) + +#define XFS_BUF_FLUSH(x) ((x)->pb_flags |= PBF_FLUSH) +#define XFS_BUF_UNFLUSH(x) ((x)->pb_flags &= ~PBF_FLUSH) +#define XFS_BUF_ISFLUSH(x) ((x)->pb_flags & PBF_FLUSH) + +#define XFS_BUF_SHUT(x) printk("XFS_BUF_SHUT not implemented yet\n") +#define XFS_BUF_UNSHUT(x) printk("XFS_BUF_UNSHUT not implemented yet\n") +#define XFS_BUF_ISSHUT(x) (0) + +#define XFS_BUF_HOLD(x) pagebuf_hold(x) +#define XFS_BUF_READ(x) ((x)->pb_flags |= PBF_READ) +#define XFS_BUF_UNREAD(x) ((x)->pb_flags &= ~PBF_READ) +#define XFS_BUF_ISREAD(x) ((x)->pb_flags & PBF_READ) + +#define XFS_BUF_WRITE(x) ((x)->pb_flags |= PBF_WRITE) +#define XFS_BUF_UNWRITE(x) ((x)->pb_flags &= ~PBF_WRITE) +#define XFS_BUF_ISWRITE(x) ((x)->pb_flags & PBF_WRITE) + +#define XFS_BUF_ISUNINITIAL(x) ((x)->pb_flags & PBF_UNINITIAL) +#define XFS_BUF_UNUNINITIAL(x) ((x)->pb_flags &= ~PBF_UNINITIAL) + +#define XFS_BUF_BP_ISMAPPED(bp) 1 + +typedef struct page_buf_s xfs_buf_t; +#define xfs_buf page_buf_s + +typedef struct pb_target xfs_buftarg_t; +#define xfs_buftarg pb_target + +#define XFS_BUF_IODONE_FUNC(buf) (buf)->pb_iodone +#define XFS_BUF_SET_IODONE_FUNC(buf, func) \ + (buf)->pb_iodone = (func) +#define XFS_BUF_CLR_IODONE_FUNC(buf) \ + (buf)->pb_iodone = NULL +#define XFS_BUF_SET_BDSTRAT_FUNC(buf, func) \ + (buf)->pb_strat = (func) +#define XFS_BUF_CLR_BDSTRAT_FUNC(buf) \ + (buf)->pb_strat = NULL + +#define XFS_BUF_FSPRIVATE(buf, type) \ + ((type)(buf)->pb_fspriv) +#define XFS_BUF_SET_FSPRIVATE(buf, value) \ + (buf)->pb_fspriv = (void *)(value) +#define XFS_BUF_FSPRIVATE2(buf, type) \ + ((type)(buf)->pb_fspriv2) +#define XFS_BUF_SET_FSPRIVATE2(buf, value) \ + (buf)->pb_fspriv2 = (void *)(value) +#define XFS_BUF_FSPRIVATE3(buf, type) \ + ((type)(buf)->pb_fspriv3) +#define XFS_BUF_SET_FSPRIVATE3(buf, value) \ + (buf)->pb_fspriv3 = (void *)(value) +#define XFS_BUF_SET_START(buf) + +#define XFS_BUF_SET_BRELSE_FUNC(buf, value) \ + (buf)->pb_relse = (value) + +#define XFS_BUF_PTR(bp) (xfs_caddr_t)((bp)->pb_addr) + +extern inline xfs_caddr_t xfs_buf_offset(page_buf_t *bp, off_t offset) +{ + if (bp->pb_flags & PBF_MAPPED) + return XFS_BUF_PTR(bp) + offset; + return (xfs_caddr_t) pagebuf_offset(bp, offset); +} + +#define XFS_BUF_SET_PTR(bp, val, count) \ + pagebuf_associate_memory(bp, val, count) +#define XFS_BUF_ADDR(bp) ((bp)->pb_bn) +#define XFS_BUF_OFFSET(bp) ((bp)->pb_file_offset >> 9) +#define XFS_BUF_SET_ADDR(bp, blk) \ + ((bp)->pb_bn = (page_buf_daddr_t)(blk)) +#define XFS_BUF_COUNT(bp) ((bp)->pb_count_desired) +#define XFS_BUF_SET_COUNT(bp, cnt) \ + ((bp)->pb_count_desired = cnt) +#define XFS_BUF_SIZE(bp) ((bp)->pb_buffer_length) +#define XFS_BUF_SET_SIZE(bp, cnt) \ + ((bp)->pb_buffer_length = cnt) +#define XFS_BUF_SET_VTYPE_REF(bp, type, ref) +#define XFS_BUF_SET_VTYPE(bp, type) +#define XFS_BUF_SET_REF(bp, ref) + +#define XFS_BUF_ISPINNED(bp) pagebuf_ispin(bp) + +#define XFS_BUF_VALUSEMA(bp) pagebuf_lock_value(bp) +#define XFS_BUF_CPSEMA(bp) (pagebuf_cond_lock(bp) == 0) +#define XFS_BUF_VSEMA(bp) pagebuf_unlock(bp) +#define XFS_BUF_PSEMA(bp,x) pagebuf_lock(bp) +#define XFS_BUF_V_IODONESEMA(bp) up(&bp->pb_iodonesema); + +/* setup the buffer target from a buftarg structure */ +#define XFS_BUF_SET_TARGET(bp, target) \ + (bp)->pb_target = (target) + +#define XFS_BUF_TARGET_DEV(bp) ((bp)->pb_target->pbr_dev) +#define XFS_BUF_SET_VTYPE_REF(bp, type, ref) +#define XFS_BUF_SET_VTYPE(bp, type) +#define XFS_BUF_SET_REF(bp, ref) + +#define xfs_buf_read(target, blkno, len, flags) \ + pagebuf_get((target), (blkno), (len), \ + PBF_LOCK | PBF_READ | PBF_MAPPED | PBF_MAPPABLE) +#define xfs_buf_get(target, blkno, len, flags) \ + pagebuf_get((target), (blkno), (len), \ + PBF_LOCK | PBF_MAPPED | PBF_MAPPABLE) + +#define xfs_buf_read_flags(target, blkno, len, flags) \ + pagebuf_get((target), (blkno), (len), \ + PBF_READ | PBF_MAPPABLE | flags) +#define xfs_buf_get_flags(target, blkno, len, flags) \ + pagebuf_get((target), (blkno), (len), \ + PBF_MAPPABLE | flags) + +static inline int xfs_bawrite(void *mp, page_buf_t *bp) +{ + extern int xfs_bdstrat_cb(struct xfs_buf *); + int ret; + + bp->pb_fspriv3 = mp; + bp->pb_strat = xfs_bdstrat_cb; + xfs_buf_undelay(bp); + if ((ret = pagebuf_iostart(bp, PBF_WRITE | PBF_ASYNC)) == 0) + run_task_queue(&tq_disk); + return ret; +} + +static inline void xfs_buf_relse(page_buf_t *bp) +{ + if ((bp->pb_flags & _PBF_LOCKABLE) && !bp->pb_relse) + pagebuf_unlock(bp); + + pagebuf_rele(bp); +} + + +#define xfs_bpin(bp) pagebuf_pin(bp) +#define xfs_bunpin(bp) pagebuf_unpin(bp) + +#ifdef PAGEBUF_TRACE +# define PB_DEFINE_TRACES +# include +# define xfs_buftrace(id, bp) PB_TRACE(bp, PB_TRACE_REC(external), (void *)id) +#else +# define xfs_buftrace(id, bp) do { } while (0) +#endif + + +#define xfs_biodone(pb) \ + pagebuf_iodone(pb) + +#define xfs_incore(buftarg,blkno,len,lockit) \ + pagebuf_find(buftarg, blkno ,len, lockit) + + +#define xfs_biomove(pb, off, len, data, rw) \ + pagebuf_iomove((pb), (off), (len), (data), \ + ((rw) == XFS_B_WRITE) ? PBRW_WRITE : PBRW_READ) + +#define xfs_biozero(pb, off, len) \ + pagebuf_iomove((pb), (off), (len), NULL, PBRW_ZERO) + + +static inline int XFS_bwrite(page_buf_t *pb) +{ + int sync = (pb->pb_flags & PBF_ASYNC) == 0; + int error; + + pb->pb_flags |= PBF_SYNC; + + xfs_buf_undelay(pb); + + __pagebuf_iorequest(pb); + + if (sync) { + error = pagebuf_iowait(pb); + xfs_buf_relse(pb); + } else { + run_task_queue(&tq_disk); + error = 0; + } + + return error; +} + + +#define XFS_bdwrite(pb) \ + pagebuf_iostart(pb, PBF_DELWRI | PBF_ASYNC) + +static inline int xfs_bdwrite(void *mp, page_buf_t *bp) +{ + extern int xfs_bdstrat_cb(struct xfs_buf *); + + bp->pb_strat = xfs_bdstrat_cb; + bp->pb_fspriv3 = mp; + + return pagebuf_iostart(bp, PBF_DELWRI | PBF_ASYNC); +} + +#define XFS_bdstrat(bp) pagebuf_iorequest(bp) + +#define xfs_iowait(pb) pagebuf_iowait(pb) + + +/* + * Go through all incore buffers, and release buffers + * if they belong to the given device. This is used in + * filesystem error handling to preserve the consistency + * of its metadata. + */ + +extern void XFS_bflush(xfs_buftarg_t *); +#define xfs_binval(buftarg) XFS_bflush(buftarg) + +#define xfs_incore_relse(buftarg,delwri_only,wait) \ + pagebuf_target_clear(buftarg) + + +#define xfs_baread(target, rablkno, ralen) \ + pagebuf_readahead((target), (rablkno), \ + (ralen), PBF_DONT_BLOCK) + +#define XFS_getrbuf(sleep,mp) \ + pagebuf_get_empty((mp)->m_ddev_targp) +#define XFS_ngetrbuf(len,mp) \ + pagebuf_get_no_daddr(len,(mp)->m_ddev_targp) +#define XFS_freerbuf(bp) pagebuf_free(bp) +#define XFS_nfreerbuf(bp) pagebuf_free(bp) + +#endif diff -Nur linux-2.4.19/fs/xfs/xfs_buf_item.c linux-2.4.19-sgi211r3/fs/xfs/xfs_buf_item.c --- linux-2.4.19/fs/xfs/xfs_buf_item.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_buf_item.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1203 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains the implementation of the xfs_buf_log_item. + * It contains the item operations used to manipulate the buf log + * items as well as utility routines used by the buffer specific + * transaction routines. + */ + +#include + + +#define ROUNDUPNBWORD(x) (((x) + (NBWORD - 1)) & ~(NBWORD - 1)) + +kmem_zone_t *xfs_buf_item_zone; + +#ifdef XFS_TRANS_DEBUG +/* + * This function uses an alternate strategy for tracking the bytes + * that the user requests to be logged. This can then be used + * in conjunction with the bli_orig array in the buf log item to + * catch bugs in our callers' code. + * + * We also double check the bits set in xfs_buf_item_log using a + * simple algorithm to check that every byte is accounted for. + */ +STATIC void +xfs_buf_item_log_debug( + xfs_buf_log_item_t *bip, + uint first, + uint last) +{ + uint x; + uint byte; + uint nbytes; + uint chunk_num; + uint word_num; + uint bit_num; + uint bit_set; + uint *wordp; + + ASSERT(bip->bli_logged != NULL); + byte = first; + nbytes = last - first + 1; + bfset(bip->bli_logged, first, nbytes); + for (x = 0; x < nbytes; x++) { + chunk_num = byte >> XFS_BLI_SHIFT; + word_num = chunk_num >> BIT_TO_WORD_SHIFT; + bit_num = chunk_num & (NBWORD - 1); + wordp = &(bip->bli_format.blf_data_map[word_num]); + bit_set = *wordp & (1 << bit_num); + ASSERT(bit_set); + byte++; + } +} + +/* + * This function is called when we flush something into a buffer without + * logging it. This happens for things like inodes which are logged + * separately from the buffer. + */ +void +xfs_buf_item_flush_log_debug( + xfs_buf_t *bp, + uint first, + uint last) +{ + xfs_buf_log_item_t *bip; + uint nbytes; + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + if ((bip == NULL) || (bip->bli_item.li_type != XFS_LI_BUF)) { + return; + } + + ASSERT(bip->bli_logged != NULL); + nbytes = last - first + 1; + bfset(bip->bli_logged, first, nbytes); +} + +/* + * This function is called to verify that our caller's have logged + * all the bytes that they changed. + * + * It does this by comparing the original copy of the buffer stored in + * the buf log item's bli_orig array to the current copy of the buffer + * and ensuring that all bytes which miscompare are set in the bli_logged + * array of the buf log item. + */ +STATIC void +xfs_buf_item_log_check( + xfs_buf_log_item_t *bip) +{ + char *orig; + char *buffer; + int x; + xfs_buf_t *bp; + + ASSERT(bip->bli_orig != NULL); + ASSERT(bip->bli_logged != NULL); + + bp = bip->bli_buf; + ASSERT(XFS_BUF_COUNT(bp) > 0); + ASSERT(XFS_BUF_PTR(bp) != NULL); + orig = bip->bli_orig; + buffer = XFS_BUF_PTR(bp); + for (x = 0; x < XFS_BUF_COUNT(bp); x++) { + if (orig[x] != buffer[x] && !btst(bip->bli_logged, x)) + cmn_err(CE_PANIC, + "xfs_buf_item_log_check bip %x buffer %x orig %x index %d", + bip, bp, orig, x); + } +} +#else +#define xfs_buf_item_log_debug(x,y,z) +#define xfs_buf_item_log_check(x) +#endif + +STATIC void xfs_buf_error_relse(xfs_buf_t *bp); + +/* + * This returns the number of log iovecs needed to log the + * given buf log item. + * + * It calculates this as 1 iovec for the buf log format structure + * and 1 for each stretch of non-contiguous chunks to be logged. + * Contiguous chunks are logged in a single iovec. + * + * If the XFS_BLI_STALE flag has been set, then log nothing. + */ +uint +xfs_buf_item_size( + xfs_buf_log_item_t *bip) +{ + uint nvecs; + int next_bit; + int last_bit; + xfs_buf_t *bp; + + ASSERT(atomic_read(&bip->bli_refcount) > 0); + if (bip->bli_flags & XFS_BLI_STALE) { + /* + * The buffer is stale, so all we need to log + * is the buf log format structure with the + * cancel flag in it. + */ + xfs_buf_item_trace("SIZE STALE", bip); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + return 1; + } + + bp = bip->bli_buf; + ASSERT(bip->bli_flags & XFS_BLI_LOGGED); + nvecs = 1; + last_bit = xfs_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, 0); + ASSERT(last_bit != -1); + nvecs++; + while (last_bit != -1) { + /* + * This takes the bit number to start looking from and + * returns the next set bit from there. It returns -1 + * if there are no more bits set or the start bit is + * beyond the end of the bitmap. + */ + next_bit = xfs_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, + last_bit + 1); + /* + * If we run out of bits, leave the loop, + * else if we find a new set of bits bump the number of vecs, + * else keep scanning the current set of bits. + */ + if (next_bit == -1) { + last_bit = -1; + } else if (next_bit != last_bit + 1) { + last_bit = next_bit; + nvecs++; + } else if (xfs_buf_offset(bp, next_bit * XFS_BLI_CHUNK) != + (xfs_buf_offset(bp, last_bit * XFS_BLI_CHUNK) + + XFS_BLI_CHUNK)) { + last_bit = next_bit; + nvecs++; + } else { + last_bit++; + } + } + + xfs_buf_item_trace("SIZE NORM", bip); + return nvecs; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given log buf item. It fills the first entry with a buf log + * format structure, and the rest point to contiguous chunks + * within the buffer. + */ +void +xfs_buf_item_format( + xfs_buf_log_item_t *bip, + xfs_log_iovec_t *log_vector) +{ + uint base_size; + uint nvecs; + xfs_log_iovec_t *vecp; + xfs_buf_t *bp; + int first_bit; + int last_bit; + int next_bit; + uint nbits; + uint buffer_offset; + + ASSERT(atomic_read(&bip->bli_refcount) > 0); + ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || + (bip->bli_flags & XFS_BLI_STALE)); + bp = bip->bli_buf; + ASSERT(XFS_BUF_BP_ISMAPPED(bp)); + vecp = log_vector; + + /* + * The size of the base structure is the size of the + * declared structure plus the space for the extra words + * of the bitmap. We subtract one from the map size, because + * the first element of the bitmap is accounted for in the + * size of the base structure. + */ + base_size = + (uint)(sizeof(xfs_buf_log_format_t) + + ((bip->bli_format.blf_map_size - 1) * sizeof(uint))); + vecp->i_addr = (xfs_caddr_t)&bip->bli_format; + vecp->i_len = base_size; + vecp++; + nvecs = 1; + + if (bip->bli_flags & XFS_BLI_STALE) { + /* + * The buffer is stale, so all we need to log + * is the buf log format structure with the + * cancel flag in it. + */ + xfs_buf_item_trace("FORMAT STALE", bip); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + bip->bli_format.blf_size = nvecs; + return; + } + + /* + * Fill in an iovec for each set of contiguous chunks. + */ + first_bit = xfs_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, 0); + ASSERT(first_bit != -1); + last_bit = first_bit; + nbits = 1; + for (;;) { + /* + * This takes the bit number to start looking from and + * returns the next set bit from there. It returns -1 + * if there are no more bits set or the start bit is + * beyond the end of the bitmap. + */ + next_bit = xfs_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, + (uint)last_bit + 1); + /* + * If we run out of bits fill in the last iovec and get + * out of the loop. + * Else if we start a new set of bits then fill in the + * iovec for the series we were looking at and start + * counting the bits in the new one. + * Else we're still in the same set of bits so just + * keep counting and scanning. + */ + if (next_bit == -1) { + buffer_offset = first_bit * XFS_BLI_CHUNK; + vecp->i_addr = xfs_buf_offset(bp, buffer_offset); + vecp->i_len = nbits * XFS_BLI_CHUNK; + nvecs++; + break; + } else if (next_bit != last_bit + 1) { + buffer_offset = first_bit * XFS_BLI_CHUNK; + vecp->i_addr = xfs_buf_offset(bp, buffer_offset); + vecp->i_len = nbits * XFS_BLI_CHUNK; + nvecs++; + vecp++; + first_bit = next_bit; + last_bit = next_bit; + nbits = 1; + } else if (xfs_buf_offset(bp, next_bit << XFS_BLI_SHIFT) != + (xfs_buf_offset(bp, last_bit << XFS_BLI_SHIFT) + + XFS_BLI_CHUNK)) { + buffer_offset = first_bit * XFS_BLI_CHUNK; + vecp->i_addr = xfs_buf_offset(bp, buffer_offset); + vecp->i_len = nbits * XFS_BLI_CHUNK; +/* You would think we need to bump the nvecs here too, but we do not + * this number is used by recovery, and it gets confused by the boundary + * split here + * nvecs++; + */ + vecp++; + first_bit = next_bit; + last_bit = next_bit; + } else { + last_bit++; + nbits++; + } + } + bip->bli_format.blf_size = nvecs; + + /* + * Check to make sure everything is consistent. + */ + xfs_buf_item_trace("FORMAT NORM", bip); + xfs_buf_item_log_check(bip); +} + +/* + * This is called to pin the buffer associated with the buf log + * item in memory so it cannot be written out. Simply call bpin() + * on the buffer to do this. + */ +void +xfs_buf_item_pin( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + bp = bip->bli_buf; + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || + (bip->bli_flags & XFS_BLI_STALE)); + xfs_buf_item_trace("PIN", bip); + xfs_buftrace("XFS_PIN", bp); + xfs_bpin(bp); +} + + +/* + * This is called to unpin the buffer associated with the buf log + * item which was previously pinned with a call to xfs_buf_item_pin(). + * Just call bunpin() on the buffer to do this. + * + * Also drop the reference to the buf item for the current transaction. + * If the XFS_BLI_STALE flag is set and we are the last reference, + * then free up the buf log item and unlock the buffer. + */ +void +xfs_buf_item_unpin( + xfs_buf_log_item_t *bip) +{ + xfs_mount_t *mp; + xfs_buf_t *bp; + int freed; + SPLDECL(s); + + bp = bip->bli_buf; + ASSERT(bp != NULL); + ASSERT(XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *) == bip); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + xfs_buf_item_trace("UNPIN", bip); + xfs_buftrace("XFS_UNPIN", bp); + + freed = atomic_dec_and_test(&bip->bli_refcount); + mp = bip->bli_item.li_mountp; + xfs_bunpin(bp); + if (freed && (bip->bli_flags & XFS_BLI_STALE)) { + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); + ASSERT(XFS_BUF_ISSTALE(bp)); +/** + ASSERT(bp->b_pincount == 0); +**/ + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + xfs_buf_item_trace("UNPIN STALE", bip); + xfs_buftrace("XFS_UNPIN STALE", bp); + AIL_LOCK(mp,s); + /* + * If we get called here because of an IO error, we may + * or may not have the item on the AIL. xfs_trans_delete_ail() + * will take care of that situation. + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); + xfs_buf_item_relse(bp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL); + xfs_buf_relse(bp); + } + +} + +/* + * this is called from uncommit in the forced-shutdown path. + * we need to check to see if the reference count on the log item + * is going to drop to zero. If so, unpin will free the log item + * so we need to free the item's descriptor (that points to the item) + * in the transaction. + */ +void +xfs_buf_item_unpin_remove( + xfs_buf_log_item_t *bip, + xfs_trans_t *tp) +{ + xfs_buf_t *bp; + xfs_log_item_desc_t *lidp; + + bp = bip->bli_buf; + /* + * will xfs_buf_item_unpin() call xfs_buf_item_relse()? + */ + if ((atomic_read(&bip->bli_refcount) == 1) && + (bip->bli_flags & XFS_BLI_STALE)) { + ASSERT(XFS_BUF_VALUSEMA(bip->bli_buf) <= 0); + xfs_buf_item_trace("UNPIN REMOVE", bip); + xfs_buftrace("XFS_UNPIN_REMOVE", bp); + /* + * yes -- clear the xaction descriptor in-use flag + * and free the chunk if required. We can safely + * do some work here and then call buf_item_unpin + * to do the rest because if the if is true, then + * we are holding the buffer locked so no one else + * will be able to bump up the refcount. + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) bip); + xfs_trans_free_item(tp, lidp); + /* + * Since the transaction no longer refers to the buffer, + * the buffer should no longer refer to the transaction. + */ + XFS_BUF_SET_FSPRIVATE2(bp, NULL); + } + + xfs_buf_item_unpin(bip); + + return; +} + +/* + * This is called to attempt to lock the buffer associated with this + * buf log item. Don't sleep on the buffer lock. If we can't get + * the lock right away, return 0. If we can get the lock, pull the + * buffer from the free list, mark it busy, and return 1. + */ +uint +xfs_buf_item_trylock( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + bp = bip->bli_buf; + + if (XFS_BUF_ISPINNED(bp)) { + return XFS_ITEM_PINNED; + } + + if (!XFS_BUF_CPSEMA(bp)) { + return XFS_ITEM_LOCKED; + } + + /* + * Remove the buffer from the free list. Only do this + * if it's on the free list. Private buffers like the + * superblock buffer are not. + */ + XFS_BUF_HOLD(bp); + + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + xfs_buf_item_trace("TRYLOCK SUCCESS", bip); + return XFS_ITEM_SUCCESS; +} + +/* + * Release the buffer associated with the buf log item. + * If there is no dirty logged data associated with the + * buffer recorded in the buf log item, then free the + * buf log item and remove the reference to it in the + * buffer. + * + * This call ignores the recursion count. It is only called + * when the buffer should REALLY be unlocked, regardless + * of the recursion count. + * + * If the XFS_BLI_HOLD flag is set in the buf log item, then + * free the log item if necessary but do not unlock the buffer. + * This is for support of xfs_trans_bhold(). Make sure the + * XFS_BLI_HOLD field is cleared if we don't free the item. + */ +void +xfs_buf_item_unlock( + xfs_buf_log_item_t *bip) +{ + int aborted; + xfs_buf_t *bp; + uint hold; + + bp = bip->bli_buf; + xfs_buftrace("XFS_UNLOCK", bp); + + /* + * Clear the buffer's association with this transaction. + */ + XFS_BUF_SET_FSPRIVATE2(bp, NULL); + + /* + * If this is a transaction abort, don't return early. + * Instead, allow the brelse to happen. + * Normally it would be done for stale (cancelled) buffers + * at unpin time, but we'll never go through the pin/unpin + * cycle if we abort inside commit. + */ + aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0; + + /* + * If the buf item is marked stale, then don't do anything. + * We'll unlock the buffer and free the buf item when the + * buffer is unpinned for the last time. + */ + if (bip->bli_flags & XFS_BLI_STALE) { + bip->bli_flags &= ~XFS_BLI_LOGGED; + xfs_buf_item_trace("UNLOCK STALE", bip); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + if (!aborted) + return; + } + + /* + * Drop the transaction's reference to the log item if + * it was not logged as part of the transaction. Otherwise + * we'll drop the reference in xfs_buf_item_unpin() when + * the transaction is really through with the buffer. + */ + if (!(bip->bli_flags & XFS_BLI_LOGGED)) { + atomic_dec(&bip->bli_refcount); + } else { + /* + * Clear the logged flag since this is per + * transaction state. + */ + bip->bli_flags &= ~XFS_BLI_LOGGED; + } + + /* + * Before possibly freeing the buf item, determine if we should + * release the buffer at the end of this routine. + */ + hold = bip->bli_flags & XFS_BLI_HOLD; + xfs_buf_item_trace("UNLOCK", bip); + + /* + * If the buf item isn't tracking any data, free it. + * Otherwise, if XFS_BLI_HOLD is set clear it. + */ + if (xfs_count_bits(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, 0) == 0) { + xfs_buf_item_relse(bp); + } else if (hold) { + bip->bli_flags &= ~XFS_BLI_HOLD; + } + + /* + * Release the buffer if XFS_BLI_HOLD was not set. + */ + if (!hold) { + xfs_buf_relse(bp); + } +} + +/* + * This is called to find out where the oldest active copy of the + * buf log item in the on disk log resides now that the last log + * write of it completed at the given lsn. + * We always re-log all the dirty data in a buffer, so usually the + * latest copy in the on disk log is the only one that matters. For + * those cases we simply return the given lsn. + * + * The one exception to this is for buffers full of newly allocated + * inodes. These buffers are only relogged with the XFS_BLI_INODE_BUF + * flag set, indicating that only the di_next_unlinked fields from the + * inodes in the buffers will be replayed during recovery. If the + * original newly allocated inode images have not yet been flushed + * when the buffer is so relogged, then we need to make sure that we + * keep the old images in the 'active' portion of the log. We do this + * by returning the original lsn of that transaction here rather than + * the current one. + */ +xfs_lsn_t +xfs_buf_item_committed( + xfs_buf_log_item_t *bip, + xfs_lsn_t lsn) +{ + xfs_buf_item_trace("COMMITTED", bip); + if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && + (bip->bli_item.li_lsn != 0)) { + return bip->bli_item.li_lsn; + } + return (lsn); +} + +/* + * This is called when the transaction holding the buffer is aborted. + * Just behave as if the transaction had been cancelled. If we're shutting down + * and have aborted this transaction, we'll trap this buffer when it tries to + * get written out. + */ +void +xfs_buf_item_abort( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + bp = bip->bli_buf; + xfs_buftrace("XFS_ABORT", bp); + XFS_BUF_SUPER_STALE(bp); + xfs_buf_item_unlock(bip); + return; +} + +/* + * This is called to asynchronously write the buffer associated with this + * buf log item out to disk. The buffer will already have been locked by + * a successful call to xfs_buf_item_trylock(). If the buffer still has + * B_DELWRI set, then get it going out to disk with a call to bawrite(). + * If not, then just release the buffer. + */ +void +xfs_buf_item_push( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + xfs_buf_item_trace("PUSH", bip); + + bp = bip->bli_buf; + + if (XFS_BUF_ISDELAYWRITE(bp)) { + xfs_bawrite(bip->bli_item.li_mountp, bp); + } else { + xfs_buf_relse(bp); + } +} + +/* ARGSUSED */ +void +xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) +{ +} + +/* + * This is the ops vector shared by all buf log items. + */ +struct xfs_item_ops xfs_buf_item_ops = { + .iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size, + .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_buf_item_format, + .iop_pin = (void(*)(xfs_log_item_t*))xfs_buf_item_pin, + .iop_unpin = (void(*)(xfs_log_item_t*))xfs_buf_item_unpin, + .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *)) + xfs_buf_item_unpin_remove, + .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_buf_item_trylock, + .iop_unlock = (void(*)(xfs_log_item_t*))xfs_buf_item_unlock, + .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_buf_item_committed, + .iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push, + .iop_abort = (void(*)(xfs_log_item_t*))xfs_buf_item_abort, + .iop_pushbuf = NULL, + .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_buf_item_committing +}; + + +/* + * Allocate a new buf log item to go with the given buffer. + * Set the buffer's b_fsprivate field to point to the new + * buf log item. If there are other item's attached to the + * buffer (see xfs_buf_attach_iodone() below), then put the + * buf log item at the front. + */ +void +xfs_buf_item_init( + xfs_buf_t *bp, + xfs_mount_t *mp) +{ + xfs_log_item_t *lip; + xfs_buf_log_item_t *bip; + int chunks; + int map_size; + + /* + * Check to see if there is already a buf log item for + * this buffer. If there is, it is guaranteed to be + * the first. If we do already have one, there is + * nothing to do here so return. + */ + if (XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *) != mp) + XFS_BUF_SET_FSPRIVATE3(bp, mp); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + if (lip->li_type == XFS_LI_BUF) { + return; + } + } + + /* + * chunks is the number of XFS_BLI_CHUNK size pieces + * the buffer can be divided into. Make sure not to + * truncate any pieces. map_size is the size of the + * bitmap needed to describe the chunks of the buffer. + */ + chunks = (int)((XFS_BUF_COUNT(bp) + (XFS_BLI_CHUNK - 1)) >> XFS_BLI_SHIFT); + map_size = (int)((chunks + NBWORD) >> BIT_TO_WORD_SHIFT); + + bip = (xfs_buf_log_item_t*)kmem_zone_zalloc(xfs_buf_item_zone, + KM_SLEEP); + bip->bli_item.li_type = XFS_LI_BUF; + bip->bli_item.li_ops = &xfs_buf_item_ops; + bip->bli_item.li_mountp = mp; + bip->bli_buf = bp; + bip->bli_format.blf_type = XFS_LI_BUF; + bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp); + bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp)); + bip->bli_format.blf_map_size = map_size; +#ifdef XFS_BLI_TRACE + bip->bli_trace = ktrace_alloc(XFS_BLI_TRACE_SIZE, KM_SLEEP); +#endif + +#ifdef XFS_TRANS_DEBUG + /* + * Allocate the arrays for tracking what needs to be logged + * and what our callers request to be logged. bli_orig + * holds a copy of the original, clean buffer for comparison + * against, and bli_logged keeps a 1 bit flag per byte in + * the buffer to indicate which bytes the callers have asked + * to have logged. + */ + bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP); + bcopy(XFS_BUF_PTR(bp), bip->bli_orig, XFS_BUF_COUNT(bp)); + bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP); +#endif + + /* + * Put the buf item into the list of items attached to the + * buffer at the front. + */ + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + bip->bli_item.li_bio_list = + XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + } + XFS_BUF_SET_FSPRIVATE(bp, bip); +} + + +/* + * Mark bytes first through last inclusive as dirty in the buf + * item's bitmap. + */ +void +xfs_buf_item_log( + xfs_buf_log_item_t *bip, + uint first, + uint last) +{ + uint first_bit; + uint last_bit; + uint bits_to_set; + uint bits_set; + uint word_num; + uint *wordp; + uint bit; + uint end_bit; + uint mask; + + /* + * Mark the item as having some dirty data for + * quick reference in xfs_buf_item_dirty. + */ + bip->bli_flags |= XFS_BLI_DIRTY; + + /* + * Convert byte offsets to bit numbers. + */ + first_bit = first >> XFS_BLI_SHIFT; + last_bit = last >> XFS_BLI_SHIFT; + + /* + * Calculate the total number of bits to be set. + */ + bits_to_set = last_bit - first_bit + 1; + + /* + * Get a pointer to the first word in the bitmap + * to set a bit in. + */ + word_num = first_bit >> BIT_TO_WORD_SHIFT; + wordp = &(bip->bli_format.blf_data_map[word_num]); + + /* + * Calculate the starting bit in the first word. + */ + bit = first_bit & (uint)(NBWORD - 1); + + /* + * First set any bits in the first word of our range. + * If it starts at bit 0 of the word, it will be + * set below rather than here. That is what the variable + * bit tells us. The variable bits_set tracks the number + * of bits that have been set so far. End_bit is the number + * of the last bit to be set in this word plus one. + */ + if (bit) { + end_bit = MIN(bit + bits_to_set, (uint)NBWORD); + mask = ((1 << (end_bit - bit)) - 1) << bit; + *wordp |= mask; + wordp++; + bits_set = end_bit - bit; + } else { + bits_set = 0; + } + + /* + * Now set bits a whole word at a time that are between + * first_bit and last_bit. + */ + while ((bits_to_set - bits_set) >= NBWORD) { + *wordp |= 0xffffffff; + bits_set += NBWORD; + wordp++; + } + + /* + * Finally, set any bits left to be set in one last partial word. + */ + end_bit = bits_to_set - bits_set; + if (end_bit) { + mask = (1 << end_bit) - 1; + *wordp |= mask; + } + + xfs_buf_item_log_debug(bip, first, last); +} + + +/* + * Return 1 if the buffer has some data that has been logged (at any + * point, not just the current transaction) and 0 if not. + */ +uint +xfs_buf_item_dirty( + xfs_buf_log_item_t *bip) +{ + return (bip->bli_flags & XFS_BLI_DIRTY); +} + +/* + * This is called when the buf log item is no longer needed. It should + * free the buf log item associated with the given buffer and clear + * the buffer's pointer to the buf log item. If there are no more + * items in the list, clear the b_iodone field of the buffer (see + * xfs_buf_attach_iodone() below). + */ +void +xfs_buf_item_relse( + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + xfs_buftrace("XFS_RELSE", bp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + XFS_BUF_SET_FSPRIVATE(bp, bip->bli_item.li_bio_list); + if ((XFS_BUF_FSPRIVATE(bp, void *) == NULL) && + (XFS_BUF_IODONE_FUNC(bp) != NULL)) { +/** + ASSERT((XFS_BUF_ISUNINITIAL(bp)) == 0); +***/ + XFS_BUF_CLR_IODONE_FUNC(bp); + } + +#ifdef XFS_TRANS_DEBUG + kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); + bip->bli_orig = NULL; + kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); + bip->bli_logged = NULL; +#endif /* XFS_TRANS_DEBUG */ + +#ifdef XFS_BLI_TRACE + ktrace_free(bip->bli_trace); +#endif + kmem_zone_free(xfs_buf_item_zone, bip); +} + + +/* + * Add the given log item with it's callback to the list of callbacks + * to be called when the buffer's I/O completes. If it is not set + * already, set the buffer's b_iodone() routine to be + * xfs_buf_iodone_callbacks() and link the log item into the list of + * items rooted at b_fsprivate. Items are always added as the second + * entry in the list if there is a first, because the buf item code + * assumes that the buf log item is first. + */ +void +xfs_buf_attach_iodone( + xfs_buf_t *bp, + void (*cb)(xfs_buf_t *, xfs_log_item_t *), + xfs_log_item_t *lip) +{ + xfs_log_item_t *head_lip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + + lip->li_cb = cb; + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + head_lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + lip->li_bio_list = head_lip->li_bio_list; + head_lip->li_bio_list = lip; + } else { + XFS_BUF_SET_FSPRIVATE(bp, lip); + } + + ASSERT((XFS_BUF_IODONE_FUNC(bp) == xfs_buf_iodone_callbacks) || + (XFS_BUF_IODONE_FUNC(bp) == NULL)); + XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks); +} + +STATIC void +xfs_buf_do_callbacks( + xfs_buf_t *bp, + xfs_log_item_t *lip) +{ + xfs_log_item_t *nlip; + + while (lip != NULL) { + nlip = lip->li_bio_list; + ASSERT(lip->li_cb != NULL); + /* + * Clear the next pointer so we don't have any + * confusion if the item is added to another buf. + * Don't touch the log item after calling its + * callback, because it could have freed itself. + */ + lip->li_bio_list = NULL; + lip->li_cb(bp, lip); + lip = nlip; + } +} + +/* + * This is the iodone() function for buffers which have had callbacks + * attached to them by xfs_buf_attach_iodone(). It should remove each + * log item from the buffer's list and call the callback of each in turn. + * When done, the buffer's fsprivate field is set to NULL and the buffer + * is unlocked with a call to iodone(). + */ +void +xfs_buf_iodone_callbacks( + xfs_buf_t *bp) +{ + xfs_log_item_t *lip; + static time_t lasttime; + static dev_t lastdev; + xfs_mount_t *mp; + + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + + if (XFS_BUF_GETERROR(bp) != 0) { + /* + * If we've already decided to shutdown the filesystem + * because of IO errors, there's no point in giving this + * a retry. + */ + mp = lip->li_mountp; + if (XFS_FORCED_SHUTDOWN(mp)) { + ASSERT(XFS_BUF_TARGET_DEV(bp) == mp->m_dev); + XFS_BUF_SUPER_STALE(bp); + xfs_buftrace("BUF_IODONE_CB", bp); + xfs_buf_do_callbacks(bp, lip); + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + + /* + * XFS_SHUT flag gets set when we go thru the + * entire buffer cache and deliberately start + * throwing away delayed write buffers. + * Since there's no biowait done on those, + * we should just brelse them. + */ + if (XFS_BUF_ISSHUT(bp)) { + XFS_BUF_UNSHUT(bp); + xfs_buf_relse(bp); + } else { + xfs_biodone(bp); + } + + return; + } + + if ((XFS_BUF_TARGET_DEV(bp) != lastdev) || + ((lbolt - lasttime) > 500)) { + prdev("XFS write error in file system meta-data " + "block 0x%Lx in %s", + XFS_BUF_TARGET_DEV(bp), + XFS_BUF_ADDR(bp), mp->m_fsname); + lasttime = lbolt; + } + lastdev = XFS_BUF_TARGET_DEV(bp); + + if (XFS_BUF_ISASYNC(bp)) { + /* + * If the write was asynchronous then noone will be + * looking for the error. Clear the error state + * and write the buffer out again delayed write. + * + * XXXsup This is OK, so long as we catch these + * before we start the umount; we don't want these + * DELWRI metadata bufs to be hanging around. + */ + XFS_BUF_ERROR(bp,0); /* errno of 0 unsets the flag */ + + if (!(XFS_BUF_ISSTALE(bp))) { + XFS_BUF_DELAYWRITE(bp); + XFS_BUF_DONE(bp); + XFS_BUF_SET_START(bp); + } + ASSERT(XFS_BUF_IODONE_FUNC(bp)); + xfs_buftrace("BUF_IODONE ASYNC", bp); + xfs_buf_relse(bp); + } else { + /* + * If the write of the buffer was not asynchronous, + * then we want to make sure to return the error + * to the caller of bwrite(). Because of this we + * cannot clear the B_ERROR state at this point. + * Instead we install a callback function that + * will be called when the buffer is released, and + * that routine will clear the error state and + * set the buffer to be written out again after + * some delay. + */ + /* We actually overwrite the existing b-relse + function at times, but we're gonna be shutting down + anyway. */ + XFS_BUF_SET_BRELSE_FUNC(bp,xfs_buf_error_relse); + XFS_BUF_DONE(bp); + XFS_BUF_V_IODONESEMA(bp); + } + return; + } +#ifdef XFSERRORDEBUG + xfs_buftrace("XFS BUFCB NOERR", bp); +#endif + xfs_buf_do_callbacks(bp, lip); + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + xfs_biodone(bp); +} + +/* + * This is a callback routine attached to a buffer which gets an error + * when being written out synchronously. + */ +STATIC void +xfs_buf_error_relse( + xfs_buf_t *bp) +{ + xfs_log_item_t *lip; + xfs_mount_t *mp; + + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + mp = (xfs_mount_t *)lip->li_mountp; + ASSERT(XFS_BUF_TARGET_DEV(bp) == mp->m_dev); + + XFS_BUF_STALE(bp); + XFS_BUF_DONE(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_ERROR(bp,0); + xfs_buftrace("BUF_ERROR_RELSE", bp); + if (! XFS_FORCED_SHUTDOWN(mp)) + xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); + /* + * We have to unpin the pinned buffers so do the + * callbacks. + */ + xfs_buf_do_callbacks(bp, lip); + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + XFS_BUF_SET_BRELSE_FUNC(bp,NULL); + xfs_buf_relse(bp); +} + + +/* + * This is the iodone() function for buffers which have been + * logged. It is called when they are eventually flushed out. + * It should remove the buf item from the AIL, and free the buf item. + * It is called by xfs_buf_iodone_callbacks() above which will take + * care of cleaning up the buffer itself. + */ +/* ARGSUSED */ +void +xfs_buf_iodone( + xfs_buf_t *bp, + xfs_buf_log_item_t *bip) +{ + struct xfs_mount *mp; + SPLDECL(s); + + ASSERT(bip->bli_buf == bp); + + mp = bip->bli_item.li_mountp; + + /* + * If we are forcibly shutting down, this may well be + * off the AIL already. That's because we simulate the + * log-committed callbacks to unpin these buffers. Or we may never + * have put this item on AIL because of the transaction was + * aborted forcibly. xfs_trans_delete_ail() takes care of these. + * + * Either way, AIL is useless if we're forcing a shutdown. + */ + AIL_LOCK(mp,s); + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); + +#ifdef XFS_TRANS_DEBUG + kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); + bip->bli_orig = NULL; + kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); + bip->bli_logged = NULL; +#endif /* XFS_TRANS_DEBUG */ + +#ifdef XFS_BLI_TRACE + ktrace_free(bip->bli_trace); +#endif + kmem_zone_free(xfs_buf_item_zone, bip); +} + +#if defined(XFS_BLI_TRACE) +void +xfs_buf_item_trace( + char *id, + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + ASSERT(bip->bli_trace != NULL); + + bp = bip->bli_buf; + ktrace_enter(bip->bli_trace, + (void *)id, + (void *)bip->bli_buf, + (void *)((unsigned long)bip->bli_flags), + (void *)((unsigned long)bip->bli_recur), + (void *)((unsigned long)atomic_read(&bip->bli_refcount)), + (void *)XFS_BUF_ADDR(bp), + (void *)((unsigned long)XFS_BUF_COUNT(bp)), + (void *)((unsigned long)(0xFFFFFFFF & (XFS_BFLAGS(bp) >> 32))), + (void *)((unsigned long)(0xFFFFFFFF & XFS_BFLAGS(bp))), + XFS_BUF_FSPRIVATE(bp, void *), + XFS_BUF_FSPRIVATE2(bp, void *), + (void *)((unsigned long)bp->b_pincount), + (void *)XFS_BUF_IODONE_FUNC(bp), + (void *)((unsigned long)(XFS_BUF_VALUSEMA(bp))), + (void *)bip->bli_item.li_desc, + (void *)((unsigned long)bip->bli_item.li_flags)); +} +#endif /* XFS_BLI_TRACE */ + + diff -Nur linux-2.4.19/fs/xfs/xfs_buf_item.h linux-2.4.19-sgi211r3/fs/xfs/xfs_buf_item.h --- linux-2.4.19/fs/xfs/xfs_buf_item.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_buf_item.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BUF_ITEM_H__ +#define __XFS_BUF_ITEM_H__ + +/* + * This is the structure used to lay out a buf log item in the + * log. The data map describes which 128 byte chunks of the buffer + * have been logged. This structure works only on buffers that + * reside up to the first TB in the filesystem. These buffers are + * generated only by pre-6.2 systems and are known as XFS_LI_6_1_BUF. + */ +typedef struct xfs_buf_log_format_v1 { + unsigned short blf_type; /* buf log item type indicator */ + unsigned short blf_size; /* size of this item */ + __int32_t blf_blkno; /* starting blkno of this buf */ + ushort blf_flags; /* misc state */ + ushort blf_len; /* number of blocks in this buf */ + unsigned int blf_map_size; /* size of data bitmap in words */ + unsigned int blf_data_map[1];/* variable size bitmap of */ + /* regions of buffer in this item */ +} xfs_buf_log_format_v1_t; + +/* + * This is a form of the above structure with a 64 bit blkno field. + * For 6.2 and beyond, this is XFS_LI_BUF. We use this to log everything. + */ +typedef struct xfs_buf_log_format_t { + unsigned short blf_type; /* buf log item type indicator */ + unsigned short blf_size; /* size of this item */ + ushort blf_flags; /* misc state */ + ushort blf_len; /* number of blocks in this buf */ + __int64_t blf_blkno; /* starting blkno of this buf */ + unsigned int blf_map_size; /* size of data bitmap in words */ + unsigned int blf_data_map[1];/* variable size bitmap of */ + /* regions of buffer in this item */ +} xfs_buf_log_format_t; + +/* + * This flag indicates that the buffer contains on disk inodes + * and requires special recovery handling. + */ +#define XFS_BLI_INODE_BUF 0x1 +/* + * This flag indicates that the buffer should not be replayed + * during recovery because its blocks are being freed. + */ +#define XFS_BLI_CANCEL 0x2 +/* + * This flag indicates that the buffer contains on disk + * user or group dquots and may require special recovery handling. + */ +#define XFS_BLI_UDQUOT_BUF 0x4 +/* #define XFS_BLI_PDQUOT_BUF 0x8 */ +#define XFS_BLI_GDQUOT_BUF 0x10 + +#define XFS_BLI_CHUNK 128 +#define XFS_BLI_SHIFT 7 +#define BIT_TO_WORD_SHIFT 5 +#define NBWORD (NBBY * sizeof(unsigned int)) + +/* + * buf log item flags + */ +#define XFS_BLI_HOLD 0x01 +#define XFS_BLI_DIRTY 0x02 +#define XFS_BLI_STALE 0x04 +#define XFS_BLI_LOGGED 0x08 +#define XFS_BLI_INODE_ALLOC_BUF 0x10 + + +#ifdef __KERNEL__ + +struct xfs_buf; +struct ktrace; +struct xfs_mount; + +/* + * This is the in core log item structure used to track information + * needed to log buffers. It tracks how many times the lock has been + * locked, and which 128 byte chunks of the buffer are dirty. + */ +typedef struct xfs_buf_log_item { + xfs_log_item_t bli_item; /* common item structure */ + struct xfs_buf *bli_buf; /* real buffer pointer */ + unsigned int bli_flags; /* misc flags */ + unsigned int bli_recur; /* lock recursion count */ + atomic_t bli_refcount; /* cnt of tp refs */ +#ifdef DEBUG + struct ktrace *bli_trace; /* event trace buf */ +#endif +#ifdef XFS_TRANS_DEBUG + char *bli_orig; /* original buffer copy */ + char *bli_logged; /* bytes logged (bitmap) */ +#endif + xfs_buf_log_format_t bli_format; /* in-log header */ +} xfs_buf_log_item_t; + +/* + * This structure is used during recovery to record the buf log + * items which have been canceled and should not be replayed. + */ +typedef struct xfs_buf_cancel { + xfs_daddr_t bc_blkno; + uint bc_len; + int bc_refcount; + struct xfs_buf_cancel *bc_next; +} xfs_buf_cancel_t; + +#define XFS_BLI_TRACE_SIZE 32 + + +#if defined(XFS_ALL_TRACE) +#define XFS_BLI_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BLI_TRACE +#endif + +#if defined(XFS_BLI_TRACE) +void xfs_buf_item_trace(char *, xfs_buf_log_item_t *); +#else +#define xfs_buf_item_trace(id, bip) +#endif + +void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); +void xfs_buf_item_relse(struct xfs_buf *); +void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint); +uint xfs_buf_item_dirty(xfs_buf_log_item_t *); +void xfs_buf_attach_iodone(struct xfs_buf *, + void(*)(struct xfs_buf *, xfs_log_item_t *), + xfs_log_item_t *); +void xfs_buf_iodone_callbacks(struct xfs_buf *); +void xfs_buf_iodone(struct xfs_buf *, xfs_buf_log_item_t *); + +#ifdef XFS_TRANS_DEBUG +void +xfs_buf_item_flush_log_debug( + struct xfs_buf *bp, + uint first, + uint last); +#else +#define xfs_buf_item_flush_log_debug(bp, first, last) +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_BUF_ITEM_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_cap.c linux-2.4.19-sgi211r3/fs/xfs/xfs_cap.c --- linux-2.4.19/fs/xfs/xfs_cap.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_cap.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +STATIC int xfs_cap_allow_set(vnode_t *); + + +/* + * Test for existence of capability attribute as efficiently as possible. + */ +int +xfs_cap_vhascap( + vnode_t *vp) +{ + int error; + int len = sizeof(xfs_cap_set_t); + int flags = ATTR_KERNOVAL|ATTR_ROOT; + + VOP_ATTR_GET(vp, SGI_CAP_LINUX, NULL, &len, flags, sys_cred, error); + return (error == 0); +} + +/* + * Convert from extended attribute representation to in-memory for XFS. + */ +STATIC int +posix_cap_xattr_to_xfs( + posix_cap_xattr *src, + size_t size, + xfs_cap_set_t *dest) +{ + if (!src || !dest) + return EINVAL; + + if (src->c_version != cpu_to_le32(POSIX_CAP_XATTR_VERSION)) + return EINVAL; + if (src->c_abiversion != cpu_to_le32(_LINUX_CAPABILITY_VERSION)) + return EINVAL; + + if (size < sizeof(posix_cap_xattr)) + return EINVAL; + + ASSERT(sizeof(dest->cap_effective) == sizeof(src->c_effective)); + + dest->cap_effective = src->c_effective; + dest->cap_permitted = src->c_permitted; + dest->cap_inheritable = src->c_inheritable; + + return 0; +} + +/* + * Convert from in-memory XFS to extended attribute representation. + */ +STATIC int +posix_cap_xfs_to_xattr( + xfs_cap_set_t *src, + posix_cap_xattr *xattr_cap, + size_t size) +{ + size_t new_size = posix_cap_xattr_size(); + + if (size < new_size) + return -ERANGE; + + ASSERT(sizeof(xattr_cap->c_effective) == sizeof(src->cap_effective)); + + xattr_cap->c_version = cpu_to_le32(POSIX_CAP_XATTR_VERSION); + xattr_cap->c_abiversion = cpu_to_le32(_LINUX_CAPABILITY_VERSION); + xattr_cap->c_effective = src->cap_effective; + xattr_cap->c_permitted = src->cap_permitted; + xattr_cap->c_inheritable= src->cap_inheritable; + + return new_size; +} + +int +xfs_cap_vget( + vnode_t *vp, + void *cap, + size_t size) +{ + int error; + int len = sizeof(xfs_cap_set_t); + int flags = ATTR_ROOT; + xfs_cap_set_t xfs_cap = { 0 }; + posix_cap_xattr *xattr_cap = cap; + + VN_HOLD(vp); + if ((error = _MAC_VACCESS(vp, NULL, VREAD))) + goto out; + + if (!size) + flags |= ATTR_KERNOVAL; + VOP_ATTR_GET(vp, SGI_CAP_LINUX, (char *)&xfs_cap, + &len, flags, sys_cred, error); + if (error) + goto out; + ASSERT(len == sizeof(xfs_cap_set_t)); + + error = (size)? -posix_cap_xattr_size() : + -posix_cap_xfs_to_xattr(&xfs_cap, xattr_cap, size); +out: + VN_RELE(vp); + return -error; +} + +int +xfs_cap_vremove( + vnode_t *vp) +{ + int error; + + VN_HOLD(vp); + error = xfs_cap_allow_set(vp); + if (!error) { + VOP_ATTR_REMOVE(vp, SGI_CAP_LINUX, ATTR_ROOT, sys_cred, error); + if (error == ENOATTR) + error = 0; /* 'scool */ + } + VN_RELE(vp); + return -error; +} + +int +xfs_cap_vset( + vnode_t *vp, + void *cap, + size_t size) +{ + posix_cap_xattr *xattr_cap = cap; + xfs_cap_set_t xfs_cap; + int error; + + if (!cap) + return -EINVAL; + + error = posix_cap_xattr_to_xfs(xattr_cap, size, &xfs_cap); + if (error) + return -error; + + VN_HOLD(vp); + error = xfs_cap_allow_set(vp); + if (error) + goto out; + + VOP_ATTR_SET(vp, SGI_CAP_LINUX, (char *)&xfs_cap, + sizeof(xfs_cap_set_t), ATTR_ROOT, sys_cred, error); +out: + VN_RELE(vp); + return -error; +} + +STATIC int +xfs_cap_allow_set( + vnode_t *vp) +{ + vattr_t va; + int error; + + if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + return EROFS; + if ((error = _MAC_VACCESS(vp, NULL, VWRITE))) + return error; + va.va_mask = AT_UID; + VOP_GETATTR(vp, &va, 0, NULL, error); + if (error) + return error; + if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) + return EPERM; + return error; +} diff -Nur linux-2.4.19/fs/xfs/xfs_cap.h linux-2.4.19-sgi211r3/fs/xfs/xfs_cap.h --- linux-2.4.19/fs/xfs/xfs_cap.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_cap.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_CAP_H__ +#define __XFS_CAP_H__ + +/* + * Capabilities + */ +typedef __uint64_t xfs_cap_value_t; + +typedef struct xfs_cap_set { + xfs_cap_value_t cap_effective; /* use in capability checks */ + xfs_cap_value_t cap_permitted; /* combined with file attrs */ + xfs_cap_value_t cap_inheritable;/* pass through exec */ +} xfs_cap_set_t; + +/* On-disk XFS extended attribute names */ +#define SGI_CAP_FILE "SGI_CAP_FILE" +#define SGI_CAP_FILE_SIZE (sizeof(SGI_CAP_FILE)-1) +#define SGI_CAP_LINUX "SGI_CAP_LINUX" +#define SGI_CAP_LINUX_SIZE (sizeof(SGI_CAP_LINUX)-1) + +/* + * For Linux, we take the bitfields directly from capability.h + * and no longer attempt to keep this attribute ondisk compatible + * with IRIX. Since this attribute is only set on exectuables, + * it just doesn't make much sense to try. We do use a different + * named attribute though, to avoid confusion. + */ + +#ifdef __KERNEL__ + +#ifdef CONFIG_FS_POSIX_CAP + +#include + +struct vnode; + +extern int xfs_cap_vhascap(struct vnode *); +extern int xfs_cap_vset(struct vnode *, void *, size_t); +extern int xfs_cap_vget(struct vnode *, void *, size_t); +extern int xfs_cap_vremove(struct vnode *vp); + +#define _CAP_EXISTS xfs_cap_vhascap + +#else +#define xfs_cap_vset(v,p,sz) (-EOPNOTSUPP) +#define xfs_cap_vget(v,p,sz) (-EOPNOTSUPP) +#define xfs_cap_vremove(v) (-EOPNOTSUPP) +#define _CAP_EXISTS (NULL) +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_CAP_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_clnt.h linux-2.4.19-sgi211r3/fs/xfs/xfs_clnt.h --- linux-2.4.19/fs/xfs/xfs_clnt.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_clnt.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_CLNT_H__ +#define __XFS_CLNT_H__ + +/* + * XFS arguments structure, constructed from the arguments we + * are passed via the mount system call. + * + * NOTE: The mount system call is handled differently between + * Linux and IRIX. In IRIX we worked work with a binary data + * structure coming in across the syscall interface from user + * space (the mount userspace knows about each filesystem type + * and the set of valid options for it, and converts the users + * argument string into a binary structure _before_ making the + * system call), and the ABI issues that this implies. + * + * In Linux, we are passed a comma separated set of options; + * ie. a NULL terminated string of characters. Userspace mount + * code does not have any knowledge of mount options expected by + * each filesystem type and so each filesystem parses its mount + * options in kernel space. + * + * For the Linux port, we kept this structure pretty much intact + * and use it internally (because the existing code groks it). + */ +struct xfs_mount_args { + int flags; /* flags -> see XFSMNT_... macros below */ + int logbufs; /* Number of log buffers, -1 to default */ + int logbufsize; /* Size of log buffers, -1 to default */ + char fsname[MAXNAMELEN]; /* data device name */ + char rtname[MAXNAMELEN]; /* realtime device filename */ + char logname[MAXNAMELEN]; /* journal device filename */ + char mtpt[MAXNAMELEN]; /* filesystem mount point */ + int sunit; /* stripe unit (BBs) */ + int swidth; /* stripe width (BBs), multiple of sunit */ + uchar_t iosizelog; /* log2 of the preferred I/O size */ + + /* The remainder is for CXFS support. */ + char **servlist; /* Table of hosts which may be servers */ + int *servlistlen; /* Table of hostname lengths. */ + int slcount; /* Count of hosts which may be servers. */ + int stimeout; /* Server timeout in milliseconds */ + int ctimeout; /* Client timeout in milliseconds */ + char *server; /* Designated server hostname (for remount). */ + int servlen; /* Length of server hostname (for remount). */ + int servcell; /* Server cell (internal testing only) */ +}; + +/* + * XFS mount option flags + */ +#define XFSMNT_CHKLOG 0x00000001 /* check log */ +#define XFSMNT_WSYNC 0x00000002 /* safe mode nfs mount + * compatible */ +#define XFSMNT_INO64 0x00000004 /* move inode numbers up + * past 2^32 */ +#define XFSMNT_UQUOTA 0x00000008 /* user quota accounting */ +#define XFSMNT_PQUOTA 0x00000010 /* IRIX prj quota accounting */ +#define XFSMNT_UQUOTAENF 0x00000020 /* user quota limit + * enforcement */ +#define XFSMNT_PQUOTAENF 0x00000040 /* IRIX project quota limit + * enforcement */ +#define XFSMNT_NOATIME 0x00000100 /* don't modify access + * times on reads */ +#define XFSMNT_NOALIGN 0x00000200 /* don't allocate at + * stripe boundaries*/ +#define XFSMNT_RETERR 0x00000400 /* return error to user */ +#define XFSMNT_NORECOVERY 0x00000800 /* no recovery, implies + * read-only mount */ +#define XFSMNT_SHARED 0x00001000 /* shared XFS mount */ +#define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */ +#define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */ + /* (osyncisdsync is now default) */ +#define XFSMNT_CLNTONLY 0x00008000 /* cxfs mount as client only */ +#define XFSMNT_UNSHARED 0x00010000 /* cxfs filesystem mounted + * unshared */ +#define XFSMNT_CHGCLNTONLY 0x00020000 /* changing client only flag */ + /* (for remount only) */ +#define XFSMNT_SERVCELL 0x00040000 /* setting server cell */ + /* (allowed on remount) */ +#define XFSMNT_MAKESERVER 0x00080000 /* become the server (remount */ + /* only) */ +#define XFSMNT_NOTSERVER 0x00100000 /* give up being the server */ + /* (remount only) */ +#define XFSMNT_DMAPI 0x00200000 /* enable dmapi/xdsm */ +#define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */ +#define XFSMNT_GQUOTAENF 0x00800000 /* group quota limit + * enforcement */ +#define XFSMNT_NOUUID 0x01000000 /* Ignore fs uuid */ +#define XFSMNT_32BITINODES 0x02000000 /* restrict inodes to 32 + * bits of address space */ +#define XFSMNT_NOLOGFLUSH 0x04000000 /* Don't flush for log blocks */ + +/* Did we get any args for CXFS to consume? */ +#define XFSARGS_FOR_CXFSARR(ap) \ + ((ap)->servlist || (ap)->slcount >= 0 || \ + (ap)->stimeout >= 0 || (ap)->ctimeout >= 0 || \ + (ap)->flags & (XFSMNT_CLNTONLY | XFSMNT_UNSHARED)) + +#endif /* __XFS_CLNT_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_da_btree.c linux-2.4.19-sgi211r3/fs/xfs/xfs_da_btree.c --- linux-2.4.19/fs/xfs/xfs_da_btree.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_da_btree.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,2579 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +#if defined(XFSDEBUG) && defined(CONFIG_KDB) +#undef xfs_buftrace +#define xfs_buftrace(A,B) \ + printk(" xfs_buftrace : %s (0x%p)\n", A, B); \ + BUG(); +#endif + +/* + * xfs_da_btree.c + * + * Routines to implement directories as Btrees of hashed names. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +STATIC int xfs_da_root_split(xfs_da_state_t *state, + xfs_da_state_blk_t *existing_root, + xfs_da_state_blk_t *new_child); +STATIC int xfs_da_node_split(xfs_da_state_t *state, + xfs_da_state_blk_t *existing_blk, + xfs_da_state_blk_t *split_blk, + xfs_da_state_blk_t *blk_to_add, + int treelevel, + int *result); +STATIC void xfs_da_node_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *node_blk_1, + xfs_da_state_blk_t *node_blk_2); +STATIC void xfs_da_node_add(xfs_da_state_t *state, + xfs_da_state_blk_t *old_node_blk, + xfs_da_state_blk_t *new_node_blk); + +/* + * Routines used for shrinking the Btree. + */ +STATIC int xfs_da_root_join(xfs_da_state_t *state, + xfs_da_state_blk_t *root_blk); +STATIC int xfs_da_node_toosmall(xfs_da_state_t *state, int *retval); +STATIC void xfs_da_node_remove(xfs_da_state_t *state, + xfs_da_state_blk_t *drop_blk); +STATIC void xfs_da_node_unbalance(xfs_da_state_t *state, + xfs_da_state_blk_t *src_node_blk, + xfs_da_state_blk_t *dst_node_blk); + +/* + * Utility routines. + */ +STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count); +STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp); +STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra); + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of an intermediate node. + */ +int +xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level, + xfs_dabuf_t **bpp, int whichfork) +{ + xfs_da_intnode_t *node; + xfs_dabuf_t *bp; + int error; + xfs_trans_t *tp; + + tp = args->trans; + error = xfs_da_get_buf(tp, args->dp, blkno, -1, &bp, whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + node = bp->data; + INT_ZERO(node->hdr.info.forw, ARCH_CONVERT); + INT_ZERO(node->hdr.info.back, ARCH_CONVERT); + INT_SET(node->hdr.info.magic, ARCH_CONVERT, XFS_DA_NODE_MAGIC); + INT_ZERO(node->hdr.info.pad, ARCH_CONVERT); + INT_ZERO(node->hdr.count, ARCH_CONVERT); + INT_SET(node->hdr.level, ARCH_CONVERT, level); + + xfs_da_log_buf(tp, bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + *bpp = bp; + return(0); +} + +/* + * Split a leaf node, rebalance, then possibly split + * intermediate nodes, rebalance, etc. + */ +int /* error */ +xfs_da_split(xfs_da_state_t *state) +{ + xfs_da_state_blk_t *oldblk, *newblk, *addblk; + xfs_da_intnode_t *node; + xfs_dabuf_t *bp; + int max, action, error, i; + + /* + * Walk back up the tree splitting/inserting/adjusting as necessary. + * If we need to insert and there isn't room, split the node, then + * decide which fragment to insert the new block from below into. + * Note that we may split the root this way, but we need more fixup. + */ + max = state->path.active - 1; + ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); + ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || + state->path.blk[max].magic == XFS_DIRX_LEAF_MAGIC(state->mp)); + + addblk = &state->path.blk[max]; /* initial dummy value */ + for (i = max; (i >= 0) && addblk; state->path.active--, i--) { + oldblk = &state->path.blk[i]; + newblk = &state->altpath.blk[i]; + + /* + * If a leaf node then + * Allocate a new leaf node, then rebalance across them. + * else if an intermediate node then + * We split on the last layer, must we split the node? + */ + switch (oldblk->magic) { + case XFS_ATTR_LEAF_MAGIC: +#ifndef __KERNEL__ + return(ENOTTY); +#else + error = xfs_attr_leaf_split(state, oldblk, newblk); + if ((error != 0) && (error != ENOSPC)) { + return(error); /* GROT: attr is inconsistent */ + } + if (!error) { + addblk = newblk; + break; + } + /* + * Entry wouldn't fit, split the leaf again. + */ + state->extravalid = 1; + if (state->inleaf) { + state->extraafter = 0; /* before newblk */ + error = xfs_attr_leaf_split(state, oldblk, + &state->extrablk); + } else { + state->extraafter = 1; /* after newblk */ + error = xfs_attr_leaf_split(state, newblk, + &state->extrablk); + } + if (error) + return(error); /* GROT: attr inconsistent */ + addblk = newblk; + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + error = xfs_dir_leaf_split(state, oldblk, newblk); + if ((error != 0) && (error != ENOSPC)) { + return(error); /* GROT: dir is inconsistent */ + } + if (!error) { + addblk = newblk; + break; + } + /* + * Entry wouldn't fit, split the leaf again. + */ + state->extravalid = 1; + if (state->inleaf) { + state->extraafter = 0; /* before newblk */ + error = xfs_dir_leaf_split(state, oldblk, + &state->extrablk); + if (error) + return(error); /* GROT: dir incon. */ + addblk = newblk; + } else { + state->extraafter = 1; /* after newblk */ + error = xfs_dir_leaf_split(state, newblk, + &state->extrablk); + if (error) + return(error); /* GROT: dir incon. */ + addblk = newblk; + } + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + error = xfs_dir2_leafn_split(state, oldblk, newblk); + if (error) + return error; + addblk = newblk; + break; + case XFS_DA_NODE_MAGIC: + error = xfs_da_node_split(state, oldblk, newblk, addblk, + max - i, &action); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + if (error) + return(error); /* GROT: dir is inconsistent */ + /* + * Record the newly split block for the next time thru? + */ + if (action) + addblk = newblk; + else + addblk = NULL; + break; + } + + /* + * Update the btree to show the new hashval for this child. + */ + xfs_da_fixhashpath(state, &state->path); + /* + * If we won't need this block again, it's getting dropped + * from the active path by the loop control, so we need + * to mark it done now. + */ + if (i > 0 || !addblk) + xfs_da_buf_done(oldblk->bp); + } + if (!addblk) + return(0); + + /* + * Split the root node. + */ + ASSERT(state->path.active == 0); + oldblk = &state->path.blk[0]; + error = xfs_da_root_split(state, oldblk, addblk); + if (error) { + xfs_da_buf_done(oldblk->bp); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + return(error); /* GROT: dir is inconsistent */ + } + + /* + * Update pointers to the node which used to be block 0 and + * just got bumped because of the addition of a new root node. + * There might be three blocks involved if a double split occurred, + * and the original block 0 could be at any position in the list. + */ + + node = oldblk->bp->data; + if (!INT_ISZERO(node->hdr.info.forw, ARCH_CONVERT)) { + if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) == addblk->blkno) { + bp = addblk->bp; + } else { + ASSERT(state->extravalid); + bp = state->extrablk.bp; + } + node = bp->data; + INT_SET(node->hdr.info.back, ARCH_CONVERT, oldblk->blkno); + xfs_da_log_buf(state->args->trans, bp, + XFS_DA_LOGRANGE(node, &node->hdr.info, + sizeof(node->hdr.info))); + } + node = oldblk->bp->data; + if (INT_GET(node->hdr.info.back, ARCH_CONVERT)) { + if (INT_GET(node->hdr.info.back, ARCH_CONVERT) == addblk->blkno) { + bp = addblk->bp; + } else { + ASSERT(state->extravalid); + bp = state->extrablk.bp; + } + node = bp->data; + INT_SET(node->hdr.info.forw, ARCH_CONVERT, oldblk->blkno); + xfs_da_log_buf(state->args->trans, bp, + XFS_DA_LOGRANGE(node, &node->hdr.info, + sizeof(node->hdr.info))); + } + xfs_da_buf_done(oldblk->bp); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + return(0); +} + +/* + * Split the root. We have to create a new root and point to the two + * parts (the split old root) that we just created. Copy block zero to + * the EOF, extending the inode in process. + */ +STATIC int /* error */ +xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_intnode_t *node, *oldroot; + xfs_da_args_t *args; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + int error, size; + xfs_inode_t *dp; + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_dir2_leaf_t *leaf; + + /* + * Copy the existing (incorrect) block from the root node position + * to a free space somewhere. + */ + args = state->args; + ASSERT(args != NULL); + error = xfs_da_grow_inode(args, &blkno); + if (error) + return(error); + dp = args->dp; + tp = args->trans; + mp = state->mp; + error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + node = bp->data; + oldroot = blk1->bp->data; + if (INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + size = (int)((char *)&oldroot->btree[INT_GET(oldroot->hdr.count, ARCH_CONVERT)] - + (char *)oldroot); + } else { + ASSERT(XFS_DIR_IS_V2(mp)); + ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + leaf = (xfs_dir2_leaf_t *)oldroot; + size = (int)((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] - + (char *)leaf); + } + bcopy(oldroot, node, size); + xfs_da_log_buf(tp, bp, 0, size - 1); + xfs_da_buf_done(blk1->bp); + blk1->bp = bp; + blk1->blkno = blkno; + + /* + * Set up the new root node. + */ + error = xfs_da_node_create(args, + args->whichfork == XFS_DATA_FORK && + XFS_DIR_IS_V2(mp) ? mp->m_dirleafblk : 0, + INT_GET(node->hdr.level, ARCH_CONVERT) + 1, &bp, args->whichfork); + if (error) + return(error); + node = bp->data; + INT_SET(node->btree[0].hashval, ARCH_CONVERT, blk1->hashval); + INT_SET(node->btree[0].before, ARCH_CONVERT, blk1->blkno); + INT_SET(node->btree[1].hashval, ARCH_CONVERT, blk2->hashval); + INT_SET(node->btree[1].before, ARCH_CONVERT, blk2->blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 2); + if (XFS_DIR_IS_V2(mp)) { + ASSERT(blk1->blkno >= mp->m_dirleafblk && + blk1->blkno < mp->m_dirfreeblk); + ASSERT(blk2->blkno >= mp->m_dirleafblk && + blk2->blkno < mp->m_dirfreeblk); + } + /* Header is already logged by xfs_da_node_create */ + xfs_da_log_buf(tp, bp, + XFS_DA_LOGRANGE(node, node->btree, + sizeof(xfs_da_node_entry_t) * 2)); + xfs_da_buf_done(bp); + + return(0); +} + +/* + * Split the node, rebalance, then add the new entry. + */ +STATIC int /* error */ +xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk, + xfs_da_state_blk_t *addblk, + int treelevel, int *result) +{ + xfs_da_intnode_t *node; + xfs_dablk_t blkno; + int newcount, error; + int useextra; + + node = oldblk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + + /* + * With V2 the extra block is data or freespace. + */ + useextra = state->extravalid && XFS_DIR_IS_V1(state->mp); + newcount = 1 + useextra; + /* + * Do we have to split the node? + */ + if ((INT_GET(node->hdr.count, ARCH_CONVERT) + newcount) > XFS_DA_NODE_ENTRIES(state->mp)) { + /* + * Allocate a new node, add to the doubly linked chain of + * nodes, then move some of our excess entries into it. + */ + error = xfs_da_grow_inode(state->args, &blkno); + if (error) + return(error); /* GROT: dir is inconsistent */ + + error = xfs_da_node_create(state->args, blkno, treelevel, + &newblk->bp, state->args->whichfork); + if (error) + return(error); /* GROT: dir is inconsistent */ + newblk->blkno = blkno; + newblk->magic = XFS_DA_NODE_MAGIC; + xfs_da_node_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + *result = 1; + } else { + *result = 0; + } + + /* + * Insert the new entry(s) into the correct block + * (updating last hashval in the process). + * + * xfs_da_node_add() inserts BEFORE the given index, + * and as a result of using node_lookup_int() we always + * point to a valid entry (not after one), but a split + * operation always results in a new block whose hashvals + * FOLLOW the current block. + * + * If we had double-split op below us, then add the extra block too. + */ + node = oldblk->bp->data; + if (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT)) { + oldblk->index++; + xfs_da_node_add(state, oldblk, addblk); + if (useextra) { + if (state->extraafter) + oldblk->index++; + xfs_da_node_add(state, oldblk, &state->extrablk); + state->extravalid = 0; + } + } else { + newblk->index++; + xfs_da_node_add(state, newblk, addblk); + if (useextra) { + if (state->extraafter) + newblk->index++; + xfs_da_node_add(state, newblk, &state->extrablk); + state->extravalid = 0; + } + } + + return(0); +} + +/* + * Balance the btree elements between two intermediate nodes, + * usually one full and one empty. + * + * NOTE: if blk2 is empty, then it will get the upper half of blk1. + */ +STATIC void +xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_intnode_t *node1, *node2, *tmpnode; + xfs_da_node_entry_t *btree_s, *btree_d; + int count, tmp; + xfs_trans_t *tp; + + node1 = blk1->bp->data; + node2 = blk2->bp->data; + /* + * Figure out how many entries need to move, and in which direction. + * Swap the nodes around if that makes it simpler. + */ + if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + tmpnode = node1; + node1 = node2; + node2 = tmpnode; + } + ASSERT(INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + count = (INT_GET(node1->hdr.count, ARCH_CONVERT) - INT_GET(node2->hdr.count, ARCH_CONVERT)) / 2; + if (count == 0) + return; + tp = state->args->trans; + /* + * Two cases: high-to-low and low-to-high. + */ + if (count > 0) { + /* + * Move elements in node2 up to make a hole. + */ + if ((tmp = INT_GET(node2->hdr.count, ARCH_CONVERT)) > 0) { + tmp *= (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[0]; + btree_d = &node2->btree[count]; + ovbcopy(btree_s, btree_d, tmp); + } + + /* + * Move the req'd B-tree elements from high in node1 to + * low in node2. + */ + INT_MOD(node2->hdr.count, ARCH_CONVERT, count); + tmp = count * (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT) - count]; + btree_d = &node2->btree[0]; + bcopy(btree_s, btree_d, tmp); + INT_MOD(node1->hdr.count, ARCH_CONVERT, -(count)); + + } else { + /* + * Move the req'd B-tree elements from low in node2 to + * high in node1. + */ + count = -count; + tmp = count * (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[0]; + btree_d = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT)]; + bcopy(btree_s, btree_d, tmp); + INT_MOD(node1->hdr.count, ARCH_CONVERT, count); + xfs_da_log_buf(tp, blk1->bp, + XFS_DA_LOGRANGE(node1, btree_d, tmp)); + + /* + * Move elements in node2 down to fill the hole. + */ + tmp = INT_GET(node2->hdr.count, ARCH_CONVERT) - count; + tmp *= (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[count]; + btree_d = &node2->btree[0]; + ovbcopy(btree_s, btree_d, tmp); + INT_MOD(node2->hdr.count, ARCH_CONVERT, -(count)); + } + + /* + * Log header of node 1 and all current bits of node 2. + */ + xfs_da_log_buf(tp, blk1->bp, + XFS_DA_LOGRANGE(node1, &node1->hdr, sizeof(node1->hdr))); + xfs_da_log_buf(tp, blk2->bp, + XFS_DA_LOGRANGE(node2, &node2->hdr, + sizeof(node2->hdr) + + sizeof(node2->btree[0]) * INT_GET(node2->hdr.count, ARCH_CONVERT))); + + /* + * Record the last hashval from each block for upward propagation. + * (note: don't use the swapped node pointers) + */ + node1 = blk1->bp->data; + node2 = blk2->bp->data; + blk1->hashval = INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + blk2->hashval = INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + */ + if (blk1->index >= INT_GET(node1->hdr.count, ARCH_CONVERT)) { + blk2->index = blk1->index - INT_GET(node1->hdr.count, ARCH_CONVERT); + blk1->index = INT_GET(node1->hdr.count, ARCH_CONVERT) + 1; /* make it invalid */ + } +} + +/* + * Add a new entry to an intermediate node. + */ +STATIC void +xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int tmp; + xfs_mount_t *mp; + + node = oldblk->bp->data; + mp = state->mp; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT((oldblk->index >= 0) && (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT))); + ASSERT(newblk->blkno != 0); + if (state->args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + ASSERT(newblk->blkno >= mp->m_dirleafblk && + newblk->blkno < mp->m_dirfreeblk); + + /* + * We may need to make some room before we insert the new node. + */ + tmp = 0; + btree = &node->btree[ oldblk->index ]; + if (oldblk->index < INT_GET(node->hdr.count, ARCH_CONVERT)) { + tmp = (INT_GET(node->hdr.count, ARCH_CONVERT) - oldblk->index) * (uint)sizeof(*btree); + ovbcopy(btree, btree + 1, tmp); + } + INT_SET(btree->hashval, ARCH_CONVERT, newblk->hashval); + INT_SET(btree->before, ARCH_CONVERT, newblk->blkno); + xfs_da_log_buf(state->args->trans, oldblk->bp, + XFS_DA_LOGRANGE(node, btree, tmp + sizeof(*btree))); + INT_MOD(node->hdr.count, ARCH_CONVERT, +1); + xfs_da_log_buf(state->args->trans, oldblk->bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + /* + * Copy the last hash value from the oldblk to propagate upwards. + */ + oldblk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Deallocate an empty leaf node, remove it from its parent, + * possibly deallocating that block, etc... + */ +int +xfs_da_join(xfs_da_state_t *state) +{ + xfs_da_state_blk_t *drop_blk, *save_blk; + int action, error; + + action = 0; + drop_blk = &state->path.blk[ state->path.active-1 ]; + save_blk = &state->altpath.blk[ state->path.active-1 ]; + ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); + ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || + drop_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp)); + + /* + * Walk back up the tree joining/deallocating as necessary. + * When we stop dropping blocks, break out. + */ + for ( ; state->path.active >= 2; drop_blk--, save_blk--, + state->path.active--) { + /* + * See if we can combine the block with a neighbor. + * (action == 0) => no options, just leave + * (action == 1) => coalesce, then unlink + * (action == 2) => block empty, unlink it + */ + switch (drop_blk->magic) { + case XFS_ATTR_LEAF_MAGIC: +#ifndef __KERNEL__ + error = ENOTTY; +#else + error = xfs_attr_leaf_toosmall(state, &action); +#endif + if (error) + return(error); + if (action == 0) + return(0); +#ifdef __KERNEL__ + xfs_attr_leaf_unbalance(state, drop_blk, save_blk); +#endif + break; + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + error = xfs_dir_leaf_toosmall(state, &action); + if (error) + return(error); + if (action == 0) + return(0); + xfs_dir_leaf_unbalance(state, drop_blk, save_blk); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + error = xfs_dir2_leafn_toosmall(state, &action); + if (error) + return error; + if (action == 0) + return 0; + xfs_dir2_leafn_unbalance(state, drop_blk, save_blk); + break; + case XFS_DA_NODE_MAGIC: + /* + * Remove the offending node, fixup hashvals, + * check for a toosmall neighbor. + */ + xfs_da_node_remove(state, drop_blk); + xfs_da_fixhashpath(state, &state->path); + error = xfs_da_node_toosmall(state, &action); + if (error) + return(error); + if (action == 0) + return 0; + xfs_da_node_unbalance(state, drop_blk, save_blk); + break; + } + xfs_da_fixhashpath(state, &state->altpath); + error = xfs_da_blk_unlink(state, drop_blk, save_blk); + xfs_da_state_kill_altpath(state); + if (error) + return(error); + error = xfs_da_shrink_inode(state->args, drop_blk->blkno, + drop_blk->bp); + drop_blk->bp = NULL; + if (error) + return(error); + } + /* + * We joined all the way to the top. If it turns out that + * we only have one entry in the root, make the child block + * the new root. + */ + xfs_da_node_remove(state, drop_blk); + xfs_da_fixhashpath(state, &state->path); + error = xfs_da_root_join(state, &state->path.blk[0]); + return(error); +} + +/* + * We have only one entry in the root. Copy the only remaining child of + * the old root to block 0 as the new root node. + */ +STATIC int +xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk) +{ + xfs_da_intnode_t *oldroot; + /* REFERENCED */ + xfs_da_blkinfo_t *blkinfo; + xfs_da_args_t *args; + xfs_dablk_t child; + xfs_dabuf_t *bp; + int error; + + args = state->args; + ASSERT(args != NULL); + ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC); + oldroot = root_blk->bp->data; + ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_ISZERO(oldroot->hdr.info.forw, ARCH_CONVERT)); + ASSERT(INT_ISZERO(oldroot->hdr.info.back, ARCH_CONVERT)); + + /* + * If the root has more than one child, then don't do anything. + */ + if (INT_GET(oldroot->hdr.count, ARCH_CONVERT) > 1) + return(0); + + /* + * Read in the (only) child block, then copy those bytes into + * the root block's buffer and free the original child block. + */ + child = INT_GET(oldroot->btree[ 0 ].before, ARCH_CONVERT); + ASSERT(child != 0); + error = xfs_da_read_buf(args->trans, args->dp, child, -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + blkinfo = bp->data; + if (INT_GET(oldroot->hdr.level, ARCH_CONVERT) == 1) { + ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + } else { + ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + } + ASSERT(INT_ISZERO(blkinfo->forw, ARCH_CONVERT)); + ASSERT(INT_ISZERO(blkinfo->back, ARCH_CONVERT)); + bcopy(bp->data, root_blk->bp->data, state->blocksize); + xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1); + error = xfs_da_shrink_inode(args, child, bp); + return(error); +} + +/* + * Check a node block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +STATIC int +xfs_da_node_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_da_intnode_t *node; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + node = (xfs_da_intnode_t *)info; + count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (count > (XFS_DA_NODE_ENTRIES(state->mp) >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); /* blk over 50%, dont try to join */ + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = (!INT_ISZERO(info->forw, ARCH_CONVERT)); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + /* start with smaller blk num */ + forward = (INT_GET(info->forw, ARCH_CONVERT) + < INT_GET(info->back, ARCH_CONVERT)); + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, state->args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + + node = (xfs_da_intnode_t *)info; + count = XFS_DA_NODE_ENTRIES(state->mp); + count -= XFS_DA_NODE_ENTRIES(state->mp) >> 2; + count -= INT_GET(node->hdr.count, ARCH_CONVERT); + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + count -= INT_GET(node->hdr.count, ARCH_CONVERT); + xfs_da_brelse(state->args->trans, bp); + if (count >= 0) + break; /* fits with at least 25% to spare */ + } + if (i >= 2) { + *action = 0; + return(0); + } + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) { + return(error); + } + if (retval) { + *action = 0; + return(0); + } + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + if (error) { + return(error); + } + if (retval) { + *action = 0; + return(0); + } + } + *action = 1; + return(0); +} + +/* + * Walk back up the tree adjusting hash values as necessary, + * when we stop making changes, return. + */ +void +xfs_da_fixhashpath(xfs_da_state_t *state, xfs_da_state_path_t *path) +{ + xfs_da_state_blk_t *blk; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dahash_t lasthash=0; + int level, count; + + level = path->active-1; + blk = &path->blk[ level ]; + switch (blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + lasthash = xfs_attr_leaf_lasthash(blk->bp, &count); + if (count == 0) + return; + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + lasthash = xfs_dir_leaf_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + lasthash = xfs_dir2_leafn_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + case XFS_DA_NODE_MAGIC: + lasthash = xfs_da_node_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + } + for (blk--, level--; level >= 0; blk--, level--) { + node = blk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + btree = &node->btree[ blk->index ]; + if (INT_GET(btree->hashval, ARCH_CONVERT) == lasthash) + break; + blk->hashval = lasthash; + INT_SET(btree->hashval, ARCH_CONVERT, lasthash); + xfs_da_log_buf(state->args->trans, blk->bp, + XFS_DA_LOGRANGE(node, btree, sizeof(*btree))); + + lasthash = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + } +} + +/* + * Remove an entry from an intermediate node. + */ +STATIC void +xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int tmp; + + node = drop_blk->bp->data; + ASSERT(drop_blk->index < INT_GET(node->hdr.count, ARCH_CONVERT)); + ASSERT(drop_blk->index >= 0); + + /* + * Copy over the offending entry, or just zero it out. + */ + btree = &node->btree[drop_blk->index]; + if (drop_blk->index < (INT_GET(node->hdr.count, ARCH_CONVERT)-1)) { + tmp = INT_GET(node->hdr.count, ARCH_CONVERT) - drop_blk->index - 1; + tmp *= (uint)sizeof(xfs_da_node_entry_t); + ovbcopy(btree + 1, btree, tmp); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, btree, tmp)); + btree = &node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ]; + } + bzero((char *)btree, sizeof(xfs_da_node_entry_t)); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, btree, sizeof(*btree))); + INT_MOD(node->hdr.count, ARCH_CONVERT, -1); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + /* + * Copy the last hash value from the block to propagate upwards. + */ + btree--; + drop_blk->hashval = INT_GET(btree->hashval, ARCH_CONVERT); +} + +/* + * Unbalance the btree elements between two intermediate nodes, + * move all Btree elements from one node into another. + */ +STATIC void +xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_da_intnode_t *drop_node, *save_node; + xfs_da_node_entry_t *btree; + int tmp; + xfs_trans_t *tp; + + drop_node = drop_blk->bp->data; + save_node = save_blk->bp->data; + ASSERT(INT_GET(drop_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_GET(save_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + tp = state->args->trans; + + /* + * If the dying block has lower hashvals, then move all the + * elements in the remaining block up to make a hole. + */ + if ((INT_GET(drop_node->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(save_node->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(drop_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT))) + { + btree = &save_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT) ]; + tmp = INT_GET(save_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t); + ovbcopy(&save_node->btree[0], btree, tmp); + btree = &save_node->btree[0]; + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, btree, + (INT_GET(save_node->hdr.count, ARCH_CONVERT) + INT_GET(drop_node->hdr.count, ARCH_CONVERT)) * + sizeof(xfs_da_node_entry_t))); + } else { + btree = &save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT) ]; + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, btree, + INT_GET(drop_node->hdr.count, ARCH_CONVERT) * + sizeof(xfs_da_node_entry_t))); + } + + /* + * Move all the B-tree elements from drop_blk to save_blk. + */ + tmp = INT_GET(drop_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t); + bcopy(&drop_node->btree[0], btree, tmp); + INT_MOD(save_node->hdr.count, ARCH_CONVERT, INT_GET(drop_node->hdr.count, ARCH_CONVERT)); + + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, &save_node->hdr, + sizeof(save_node->hdr))); + + /* + * Save the last hashval in the remaining block for upward propagation. + */ + save_blk->hashval = INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Walk down the Btree looking for a particular filename, filling + * in the state structure as we go. + * + * We will set the state structure to point to each of the elements + * in each of the nodes where either the hashval is or should be. + * + * We support duplicate hashval's so for each entry in the current + * node that could contain the desired hashval, descend. This is a + * pruned depth-first tree search. + */ +int /* error */ +xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) +{ + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *curr; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dablk_t blkno; + int probe, span, max, error, retval; + xfs_dahash_t hashval; + xfs_da_args_t *args; + + args = state->args; + /* + * Descend thru the B-tree searching each level for the right + * node to use, until the right hashval is found. + */ + if (args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(state->mp)) + blkno = state->mp->m_dirleafblk; + else + blkno = 0; + for (blk = &state->path.blk[0], state->path.active = 1; + state->path.active <= XFS_DA_NODE_MAXDEPTH; + blk++, state->path.active++) { + /* + * Read the next node down in the tree. + */ + blk->blkno = blkno; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &blk->bp, + state->args->whichfork); + if (error) { + blk->blkno = 0; + state->path.active--; + return(error); + } + ASSERT(blk->bp != NULL); + curr = blk->bp->data; + ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || + INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + + /* + * Search an intermediate node for a match. + */ + blk->magic = INT_GET(curr->magic, ARCH_CONVERT); + if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + node = blk->bp->data; + blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Binary search. (note: small blocks will skip loop) + */ + max = INT_GET(node->hdr.count, ARCH_CONVERT); + probe = span = max / 2; + hashval = state->args->hashval; + for (btree = &node->btree[probe]; span > 4; + btree = &node->btree[probe]) { + span /= 2; + if (INT_GET(btree->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(btree->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && (probe < max)); + ASSERT((span <= 4) || (INT_GET(btree->hashval, ARCH_CONVERT) == hashval)); + + /* + * Since we may have duplicate hashval's, find the first + * matching hashval in the node. + */ + while ((probe > 0) && (INT_GET(btree->hashval, ARCH_CONVERT) >= hashval)) { + btree--; + probe--; + } + while ((probe < max) && (INT_GET(btree->hashval, ARCH_CONVERT) < hashval)) { + btree++; + probe++; + } + + /* + * Pick the right block to descend on. + */ + if (probe == max) { + blk->index = max-1; + blkno = INT_GET(node->btree[ max-1 ].before, ARCH_CONVERT); + } else { + blk->index = probe; + blkno = INT_GET(btree->before, ARCH_CONVERT); + } + } +#ifdef __KERNEL__ + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { + blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); + break; + } +#endif + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + blk->hashval = xfs_dir_leaf_lasthash(blk->bp, NULL); + break; + } + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL); + break; + } + } + + /* + * A leaf block that ends in the hashval that we are interested in + * (final hashval == search hashval) means that the next block may + * contain more entries with the same hashval, shift upward to the + * next leaf and keep searching. + */ + for (;;) { + if (blk->magic == XFS_DIR_LEAF_MAGIC) { + ASSERT(XFS_DIR_IS_V1(state->mp)); + retval = xfs_dir_leaf_lookup_int(blk->bp, state->args, + &blk->index); + } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { + ASSERT(XFS_DIR_IS_V2(state->mp)); + retval = xfs_dir2_leafn_lookup_int(blk->bp, state->args, + &blk->index, state); + } +#ifdef __KERNEL__ + else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { + retval = xfs_attr_leaf_lookup_int(blk->bp, state->args); + blk->index = state->args->index; + state->args->blkno = blk->blkno; + } +#endif + if (((retval == ENOENT) || (retval == ENOATTR)) && + (blk->hashval == state->args->hashval)) { + error = xfs_da_path_shift(state, &state->path, 1, 1, + &retval); + if (error) + return(error); + if (retval == 0) { + continue; + } +#ifdef __KERNEL__ + else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { + /* path_shift() gives ENOENT */ + retval = XFS_ERROR(ENOATTR); + } +#endif + } + break; + } + *result = retval; + return(0); +} + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Link a new block into a doubly linked list of blocks (of whatever type). + */ +int /* error */ +xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, + xfs_da_state_blk_t *new_blk) +{ + xfs_da_blkinfo_t *old_info, *new_info, *tmp_info; + xfs_da_args_t *args; + int before=0, error; + xfs_dabuf_t *bp; + + /* + * Set up environment. + */ + args = state->args; + ASSERT(args != NULL); + old_info = old_blk->bp->data; + new_info = new_blk->bp->data; + ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || + old_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || + old_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(old_blk->magic == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(new_blk->magic == INT_GET(new_info->magic, ARCH_CONVERT)); + ASSERT(old_blk->magic == new_blk->magic); + + switch (old_blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + before = xfs_dir_leaf_order(old_blk->bp, new_blk->bp); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp); + break; + case XFS_DA_NODE_MAGIC: + before = xfs_da_node_order(old_blk->bp, new_blk->bp); + break; + } + + /* + * Link blocks in appropriate order. + */ + if (before) { + /* + * Link new block in before existing block. + */ + INT_SET(new_info->forw, ARCH_CONVERT, old_blk->blkno); + new_info->back = old_info->back; /* INT_: direct copy */ + if (INT_GET(old_info->back, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(old_info->back, + ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == old_blk->blkno); + INT_SET(tmp_info->forw, ARCH_CONVERT, new_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); + xfs_da_buf_done(bp); + } + INT_SET(old_info->back, ARCH_CONVERT, new_blk->blkno); + } else { + /* + * Link new block in after existing block. + */ + new_info->forw = old_info->forw; /* INT_: direct copy */ + INT_SET(new_info->back, ARCH_CONVERT, old_blk->blkno); + if (INT_GET(old_info->forw, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(old_info->forw, ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) + == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT) + == old_blk->blkno); + INT_SET(tmp_info->back, ARCH_CONVERT, new_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); + xfs_da_buf_done(bp); + } + INT_SET(old_info->forw, ARCH_CONVERT, new_blk->blkno); + } + + xfs_da_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1); + xfs_da_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1); + return(0); +} + +/* + * Compare two intermediate nodes for "order". + */ +STATIC int +xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp) +{ + xfs_da_intnode_t *node1, *node2; + + node1 = node1_bp->data; + node2 = node2_bp->data; + ASSERT((INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) && + (INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC)); + if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from an intermediate node. + */ +STATIC uint +xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_da_intnode_t *node; + + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + if (count) + *count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (INT_ISZERO(node->hdr.count, ARCH_CONVERT)) + return(0); + return(INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); +} + +/* + * Unlink a block from a doubly linked list of blocks. + */ +int /* error */ +xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_da_blkinfo_t *drop_info, *save_info, *tmp_info; + xfs_da_args_t *args; + xfs_dabuf_t *bp; + int error; + + /* + * Set up environment. + */ + args = state->args; + ASSERT(args != NULL); + save_info = save_blk->bp->data; + drop_info = drop_blk->bp->data; + ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || + save_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || + save_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(save_blk->magic == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(drop_blk->magic == INT_GET(drop_info->magic, ARCH_CONVERT)); + ASSERT(save_blk->magic == drop_blk->magic); + ASSERT((INT_GET(save_info->forw, ARCH_CONVERT) == drop_blk->blkno) || + (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno)); + ASSERT((INT_GET(drop_info->forw, ARCH_CONVERT) == save_blk->blkno) || + (INT_GET(drop_info->back, ARCH_CONVERT) == save_blk->blkno)); + + /* + * Unlink the leaf block from the doubly linked chain of leaves. + */ + if (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno) { + save_info->back = drop_info->back; /* INT_: direct copy */ + if (INT_GET(drop_info->back, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(drop_info->back, + ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == drop_blk->blkno); + INT_SET(tmp_info->forw, ARCH_CONVERT, save_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, + sizeof(*tmp_info) - 1); + xfs_da_buf_done(bp); + } + } else { + save_info->forw = drop_info->forw; /* INT_: direct copy */ + if (INT_GET(drop_info->forw, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(drop_info->forw, ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) + == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT) + == drop_blk->blkno); + INT_SET(tmp_info->back, ARCH_CONVERT, save_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, + sizeof(*tmp_info) - 1); + xfs_da_buf_done(bp); + } + } + + xfs_da_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1); + return(0); +} + +/* + * Move a path "forward" or "!forward" one block at the current level. + * + * This routine will adjust a "path" to point to the next block + * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the + * Btree, including updating pointers to the intermediate nodes between + * the new bottom and the root. + */ +int /* error */ +xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, + int forward, int release, int *result) +{ + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + xfs_da_intnode_t *node; + xfs_da_args_t *args; + xfs_dablk_t blkno=0; + int level, error; + + /* + * Roll up the Btree looking for the first block where our + * current index is not at the edge of the block. Note that + * we skip the bottom layer because we want the sibling block. + */ + args = state->args; + ASSERT(args != NULL); + ASSERT(path != NULL); + ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + level = (path->active-1) - 1; /* skip bottom layer in path */ + for (blk = &path->blk[level]; level >= 0; blk--, level--) { + ASSERT(blk->bp != NULL); + node = blk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + if (forward && (blk->index < INT_GET(node->hdr.count, ARCH_CONVERT)-1)) { + blk->index++; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + break; + } else if (!forward && (blk->index > 0)) { + blk->index--; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + break; + } + } + if (level < 0) { + *result = XFS_ERROR(ENOENT); /* we're out of our tree */ + ASSERT(args->oknoent); + return(0); + } + + /* + * Roll down the edge of the subtree until we reach the + * same depth we were at originally. + */ + for (blk++, level++; level < path->active; blk++, level++) { + /* + * Release the old block. + * (if it's dirty, trans won't actually let go) + */ + if (release) + xfs_da_brelse(args->trans, blk->bp); + + /* + * Read the next child block. + */ + blk->blkno = blkno; + error = xfs_da_read_buf(args->trans, args->dp, blkno, -1, + &blk->bp, args->whichfork); + if (error) + return(error); + ASSERT(blk->bp != NULL); + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || + INT_GET(info->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + blk->magic = INT_GET(info->magic, ARCH_CONVERT); + if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + node = (xfs_da_intnode_t *)info; + blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + if (forward) + blk->index = 0; + else + blk->index = INT_GET(node->hdr.count, ARCH_CONVERT)-1; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + } else { + ASSERT(level == path->active-1); + blk->index = 0; + switch(blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + blk->hashval = xfs_attr_leaf_lasthash(blk->bp, + NULL); + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + blk->hashval = xfs_dir_leaf_lasthash(blk->bp, + NULL); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, + NULL); + break; + default: + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC || + blk->magic == + XFS_DIRX_LEAF_MAGIC(state->mp)); + break; + } + } + } + *result = 0; + return(0); +} + + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Implement a simple hash on a character string. + * Rotate the hash value by 7 bits, then XOR each character in. + * This is implemented with some source-level loop unrolling. + */ +xfs_dahash_t +xfs_da_hashname(uchar_t *name, int namelen) +{ + xfs_dahash_t hash; + +#define ROTL(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#ifdef SLOWVERSION + /* + * This is the old one-byte-at-a-time version. + */ + for (hash = 0; namelen > 0; namelen--) { + hash = *name++ ^ ROTL(hash, 7); + } + return(hash); +#else + /* + * Do four characters at a time as long as we can. + */ + for (hash = 0; namelen >= 4; namelen -= 4, name += 4) { + hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ + (name[3] << 0) ^ ROTL(hash, 7 * 4); + } + /* + * Now do the rest of the characters. + */ + switch (namelen) { + case 3: + return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ + ROTL(hash, 7 * 3); + case 2: + return (name[0] << 7) ^ (name[1] << 0) ^ ROTL(hash, 7 * 2); + case 1: + return (name[0] << 0) ^ ROTL(hash, 7 * 1); + case 0: + return hash; + } + /* NOTREACHED */ +#endif +#undef ROTL + return 0; /* keep gcc happy */ +} + +/* + * Add a block to the btree ahead of the file. + * Return the new block number to the caller. + */ +int +xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) +{ + xfs_fileoff_t bno, b; + xfs_bmbt_irec_t map; + xfs_bmbt_irec_t *mapp; + xfs_inode_t *dp; + int nmap, error, w, count, c, got, i, mapi; + xfs_fsize_t size; + xfs_trans_t *tp; + xfs_mount_t *mp; + + dp = args->dp; + mp = dp->i_mount; + w = args->whichfork; + tp = args->trans; + /* + * For new directories adjust the file offset and block count. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) { + bno = mp->m_dirleafblk; + count = mp->m_dirblkfsbs; + } else { + bno = 0; + count = 1; + } + /* + * Find a spot in the file space to put the new block. + */ + if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w))) { + return error; + } + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + ASSERT(bno >= mp->m_dirleafblk && bno < mp->m_dirfreeblk); + /* + * Try mapping it in one filesystem block. + */ + nmap = 1; + ASSERT(args->firstblock != NULL); + if ((error = xfs_bmapi(tp, dp, bno, count, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA| + XFS_BMAPI_CONTIG, + args->firstblock, args->total, &map, &nmap, + args->flist))) { + return error; + } + ASSERT(nmap <= 1); + if (nmap == 1) { + mapp = ↦ + mapi = 1; + } + /* + * If we didn't get it and the block might work if fragmented, + * try without the CONTIG flag. Loop until we get it all. + */ + else if (nmap == 0 && count > 1) { + mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); + for (b = bno, mapi = 0; b < bno + count; ) { + nmap = MIN(XFS_BMAP_MAX_NMAP, count); + c = (int)(bno + count - b); + if ((error = xfs_bmapi(tp, dp, b, c, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE| + XFS_BMAPI_METADATA, + args->firstblock, args->total, + &mapp[mapi], &nmap, args->flist))) { + kmem_free(mapp, sizeof(*mapp) * count); + return error; + } + if (nmap < 1) + break; + mapi += nmap; + b = mapp[mapi - 1].br_startoff + + mapp[mapi - 1].br_blockcount; + } + } else { + mapi = 0; + mapp = NULL; + } + /* + * Count the blocks we got, make sure it matches the total. + */ + for (i = 0, got = 0; i < mapi; i++) + got += mapp[i].br_blockcount; + if (got != count || mapp[0].br_startoff != bno || + mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != + bno + count) { + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + return XFS_ERROR(ENOSPC); + } + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + *new_blkno = (xfs_dablk_t)bno; + /* + * For version 1 directories, adjust the file size if it changed. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { + ASSERT(mapi == 1); + if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) + return error; + size = XFS_FSB_TO_B(mp, bno); + if (size != dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +} + +/* + * Ick. We need to always be able to remove a btree block, even + * if there's no space reservation because the filesystem is full. + * This is called if xfs_bunmapi on a btree block fails due to ENOSPC. + * It swaps the target block with the last block in the file. The + * last block in the file can always be removed since it can't cause + * a bmap btree split to do that. + */ +STATIC int +xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop, + xfs_dabuf_t **dead_bufp) +{ + xfs_dablk_t dead_blkno, last_blkno, sib_blkno, par_blkno; + xfs_dabuf_t *dead_buf, *last_buf, *sib_buf, *par_buf; + xfs_fileoff_t lastoff; + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error, w, entno, level, dead_level; + xfs_da_blkinfo_t *dead_info, *sib_info; + xfs_da_intnode_t *par_node, *dead_node; + xfs_dir_leafblock_t *dead_leaf; + xfs_dir2_leaf_t *dead_leaf2; + xfs_dahash_t dead_hash; + + dead_buf = *dead_bufp; + dead_blkno = *dead_blknop; + tp = args->trans; + ip = args->dp; + w = args->whichfork; + ASSERT(w == XFS_DATA_FORK); + mp = ip->i_mount; + if (XFS_DIR_IS_V2(mp)) { + lastoff = mp->m_dirfreeblk; + error = xfs_bmap_last_before(tp, ip, &lastoff, w); + } else + error = xfs_bmap_last_offset(tp, ip, &lastoff, w); + if (error) + return error; + if (lastoff == 0) + return XFS_ERROR(EFSCORRUPTED); + /* + * Read the last block in the btree space. + */ + last_blkno = (xfs_dablk_t)lastoff - mp->m_dirblkfsbs; + if ((error = xfs_da_read_buf(tp, ip, last_blkno, -1, &last_buf, w))) + return error; + /* + * Copy the last block into the dead buffer and log it. + */ + bcopy(last_buf->data, dead_buf->data, mp->m_dirblksize); + xfs_da_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1); + dead_info = dead_buf->data; + /* + * Get values from the moved block. + */ + if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + ASSERT(XFS_DIR_IS_V1(mp)); + dead_leaf = (xfs_dir_leafblock_t *)dead_info; + dead_level = 0; + dead_hash = + INT_GET(dead_leaf->entries[INT_GET(dead_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } else if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + ASSERT(XFS_DIR_IS_V2(mp)); + dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; + dead_level = 0; + dead_hash = INT_GET(dead_leaf2->ents[INT_GET(dead_leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } else { + ASSERT(INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + dead_node = (xfs_da_intnode_t *)dead_info; + dead_level = INT_GET(dead_node->hdr.level, ARCH_CONVERT); + dead_hash = INT_GET(dead_node->btree[INT_GET(dead_node->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } + sib_buf = par_buf = NULL; + /* + * If the moved block has a left sibling, fix up the pointers. + */ + if ((sib_blkno = INT_GET(dead_info->back, ARCH_CONVERT))) { + if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w))) + goto done; + sib_info = sib_buf->data; + if (INT_GET(sib_info->forw, ARCH_CONVERT) != last_blkno || + INT_GET(sib_info->magic, ARCH_CONVERT) != INT_GET(dead_info->magic, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + INT_SET(sib_info->forw, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, sib_buf, + XFS_DA_LOGRANGE(sib_info, &sib_info->forw, + sizeof(sib_info->forw))); + xfs_da_buf_done(sib_buf); + sib_buf = NULL; + } + /* + * If the moved block has a right sibling, fix up the pointers. + */ + if ((sib_blkno = INT_GET(dead_info->forw, ARCH_CONVERT))) { + if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w))) + goto done; + sib_info = sib_buf->data; + if ( INT_GET(sib_info->back, ARCH_CONVERT) != last_blkno + || INT_GET(sib_info->magic, ARCH_CONVERT) + != INT_GET(dead_info->magic, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + INT_SET(sib_info->back, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, sib_buf, + XFS_DA_LOGRANGE(sib_info, &sib_info->back, + sizeof(sib_info->back))); + xfs_da_buf_done(sib_buf); + sib_buf = NULL; + } + par_blkno = XFS_DIR_IS_V1(mp) ? 0 : mp->m_dirleafblk; + level = -1; + /* + * Walk down the tree looking for the parent of the moved block. + */ + for (;;) { + if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w))) + goto done; + par_node = par_buf->data; + if (INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC || + (level >= 0 && level != INT_GET(par_node->hdr.level, ARCH_CONVERT) + 1)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + level = INT_GET(par_node->hdr.level, ARCH_CONVERT); + for (entno = 0; + entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) && + INT_GET(par_node->btree[entno].hashval, ARCH_CONVERT) < dead_hash; + entno++) + continue; + if (entno == INT_GET(par_node->hdr.count, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + par_blkno = INT_GET(par_node->btree[entno].before, ARCH_CONVERT); + if (level == dead_level + 1) + break; + xfs_da_brelse(tp, par_buf); + par_buf = NULL; + } + /* + * We're in the right parent block. + * Look for the right entry. + */ + for (;;) { + for (; + entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) && + INT_GET(par_node->btree[entno].before, ARCH_CONVERT) != last_blkno; + entno++) + continue; + if (entno < INT_GET(par_node->hdr.count, ARCH_CONVERT)) + break; + par_blkno = INT_GET(par_node->hdr.info.forw, ARCH_CONVERT); + xfs_da_brelse(tp, par_buf); + par_buf = NULL; + if (par_blkno == 0) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w))) + goto done; + par_node = par_buf->data; + if (INT_GET(par_node->hdr.level, ARCH_CONVERT) != level || + INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + entno = 0; + } + /* + * Update the parent entry pointing to the moved block. + */ + INT_SET(par_node->btree[entno].before, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, par_buf, + XFS_DA_LOGRANGE(par_node, &par_node->btree[entno].before, + sizeof(par_node->btree[entno].before))); + xfs_da_buf_done(par_buf); + xfs_da_buf_done(dead_buf); + *dead_blknop = last_blkno; + *dead_bufp = last_buf; + return 0; +done: + if (par_buf) + xfs_da_brelse(tp, par_buf); + if (sib_buf) + xfs_da_brelse(tp, sib_buf); + xfs_da_brelse(tp, last_buf); + return error; +} + +/* + * Remove a btree block from a directory or attribute. + */ +int +xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, + xfs_dabuf_t *dead_buf) +{ + xfs_inode_t *dp; + int done, error, w, count; + xfs_fileoff_t bno; + xfs_fsize_t size; + xfs_trans_t *tp; + xfs_mount_t *mp; + + dp = args->dp; + w = args->whichfork; + tp = args->trans; + mp = dp->i_mount; + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + count = mp->m_dirblkfsbs; + else + count = 1; + for (;;) { + /* + * Remove extents. If we get ENOSPC for a dir we have to move + * the last block to the place we want to kill. + */ + if ((error = xfs_bunmapi(tp, dp, dead_blkno, count, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_METADATA, + 0, args->firstblock, args->flist, + &done)) == ENOSPC) { + if (w != XFS_DATA_FORK) + goto done; + if ((error = xfs_da_swap_lastblock(args, &dead_blkno, + &dead_buf))) + goto done; + } else if (error) + goto done; + else + break; + } + ASSERT(done); + xfs_da_binval(tp, dead_buf); + /* + * Adjust the directory size for version 1. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { + if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) + return error; + size = XFS_FSB_TO_B(dp->i_mount, bno); + if (size != dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +done: + xfs_da_binval(tp, dead_buf); + return error; +} + +/* + * See if the mapping(s) for this btree block are valid, i.e. + * don't contain holes, are logically contiguous, and cover the whole range. + */ +STATIC int +xfs_da_map_covers_blocks( + int nmap, + xfs_bmbt_irec_t *mapp, + xfs_dablk_t bno, + int count) +{ + int i; + xfs_fileoff_t off; + + for (i = 0, off = bno; i < nmap; i++) { + if (mapp[i].br_startblock == HOLESTARTBLOCK || + mapp[i].br_startblock == DELAYSTARTBLOCK) { + return 0; + } + if (off != mapp[i].br_startoff) { + return 0; + } + off += mapp[i].br_blockcount; + } + return off == bno + count; +} + +/* + * Make a dabuf. + * Used for get_buf, read_buf, read_bufr, and reada_buf. + */ +STATIC int +xfs_da_do_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t *mappedbnop, + xfs_dabuf_t **bpp, + int whichfork, + int caller, + inst_t *ra) +{ + xfs_buf_t *bp = 0; + xfs_buf_t **bplist; + int error=0; + int i; + xfs_bmbt_irec_t map; + xfs_bmbt_irec_t *mapp; + xfs_daddr_t mappedbno; + xfs_mount_t *mp; + int nbplist=0; + int nfsb; + int nmap; + xfs_dabuf_t *rbp; + + mp = dp->i_mount; + if (whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + nfsb = mp->m_dirblkfsbs; + else + nfsb = 1; + mappedbno = *mappedbnop; + /* + * Caller doesn't have a mapping. -2 means don't complain + * if we land in a hole. + */ + if (mappedbno == -1 || mappedbno == -2) { + /* + * Optimize the one-block case. + */ + if (nfsb == 1) { + xfs_fsblock_t fsb; + + if ((error = + xfs_bmapi_single(trans, dp, whichfork, &fsb, + (xfs_fileoff_t)bno))) { + return error; + } + mapp = ↦ + if (fsb == NULLFSBLOCK) { + nmap = 0; + } else { + map.br_startblock = fsb; + map.br_startoff = (xfs_fileoff_t)bno; + map.br_blockcount = 1; + nmap = 1; + } + } else { + mapp = kmem_alloc(sizeof(*mapp) * nfsb, KM_SLEEP); + nmap = nfsb; + if ((error = xfs_bmapi(trans, dp, (xfs_fileoff_t)bno, + nfsb, + XFS_BMAPI_METADATA | + XFS_BMAPI_AFLAG(whichfork), + NULL, 0, mapp, &nmap, NULL))) + goto exit0; + } + } else { + map.br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno); + map.br_startoff = (xfs_fileoff_t)bno; + map.br_blockcount = nfsb; + mapp = ↦ + nmap = 1; + } + if (!xfs_da_map_covers_blocks(nmap, mapp, bno, nfsb)) { + error = mappedbno == -2 ? 0 : XFS_ERROR(EFSCORRUPTED); + goto exit0; + } + if (caller != 3 && nmap > 1) { + bplist = kmem_alloc(sizeof(*bplist) * nmap, KM_SLEEP); + nbplist = 0; + } else + bplist = NULL; + /* + * Turn the mapping(s) into buffer(s). + */ + for (i = 0; i < nmap; i++) { + int nmapped; + + mappedbno = XFS_FSB_TO_DADDR(mp, mapp[i].br_startblock); + if (i == 0) + *mappedbnop = mappedbno; + nmapped = (int)XFS_FSB_TO_BB(mp, mapp[i].br_blockcount); + switch (caller) { + case 0: + bp = xfs_trans_get_buf(trans, mp->m_ddev_targp, + mappedbno, nmapped, 0); + error = bp ? XFS_BUF_GETERROR(bp) : XFS_ERROR(EIO); + break; + case 1: +#ifndef __KERNEL__ + case 2: +#endif + bp = NULL; + error = xfs_trans_read_buf(mp, trans, mp->m_ddev_targp, + mappedbno, nmapped, 0, &bp); + break; +#ifdef __KERNEL__ + case 3: + xfs_baread(mp->m_ddev_targp, mappedbno, nmapped); + error = 0; + bp = NULL; + break; +#endif + } + if (error) { + if (bp) + xfs_trans_brelse(trans, bp); + goto exit1; + } + if (!bp) + continue; + if (caller == 1) { + if (whichfork == XFS_ATTR_FORK) { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_ATTR_BTREE, + XFS_ATTR_BTREE_REF); + } else { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_DIR_BTREE, + XFS_DIR_BTREE_REF); + } + } + if (bplist) { + bplist[nbplist++] = bp; + } + } + /* + * Build a dabuf structure. + */ + if (bplist) { + rbp = xfs_da_buf_make(nbplist, bplist, ra); + } else if (bp) + rbp = xfs_da_buf_make(1, &bp, ra); + else + rbp = NULL; + /* + * For read_buf, check the magic number. + */ + if (caller == 1) { + xfs_dir2_data_t *data; + xfs_dir2_free_t *free; + xfs_da_blkinfo_t *info; + uint magic, magic1; + + info = rbp->data; + data = rbp->data; + free = rbp->data; + magic = INT_GET(info->magic, ARCH_CONVERT); + magic1 = INT_GET(data->hdr.magic, ARCH_CONVERT); + if (XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) && + (magic != XFS_DIR_LEAF_MAGIC) && + (magic != XFS_ATTR_LEAF_MAGIC) && + (magic != XFS_DIR2_LEAF1_MAGIC) && + (magic != XFS_DIR2_LEAFN_MAGIC) && + (magic1 != XFS_DIR2_BLOCK_MAGIC) && + (magic1 != XFS_DIR2_DATA_MAGIC) && + (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC), + mp, XFS_ERRTAG_DA_READ_BUF, + XFS_RANDOM_DA_READ_BUF)) { + xfs_buftrace("DA READ ERROR", rbp->bps[0]); + error = XFS_ERROR(EFSCORRUPTED); + xfs_da_brelse(trans, rbp); + nbplist = 0; + goto exit1; + } + } + if (bplist) { + kmem_free(bplist, sizeof(*bplist) * nmap); + } + if (mapp != &map) { + kmem_free(mapp, sizeof(*mapp) * nfsb); + } + if (bpp) + *bpp = rbp; + return 0; +exit1: + if (bplist) { + for (i = 0; i < nbplist; i++) + xfs_trans_brelse(trans, bplist[i]); + kmem_free(bplist, sizeof(*bplist) * nmap); + } +exit0: + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * nfsb); + if (bpp) + *bpp = NULL; + return error; +} + +/* + * Get a buffer for the dir/attr block. + */ +int +xfs_da_get_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, + int whichfork) +{ + return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 0, + (inst_t *)__return_address); +} + +/* + * Get a buffer for the dir/attr block, fill in the contents. + */ +int +xfs_da_read_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, + int whichfork) +{ + return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 1, + (inst_t *)__return_address); +} + +/* + * Readahead the dir/attr block. + */ +xfs_daddr_t +xfs_da_reada_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + int whichfork) +{ + xfs_daddr_t rval; + + rval = -1; + if (xfs_da_do_buf(trans, dp, bno, &rval, NULL, whichfork, 3, + (inst_t *)__return_address)) + return -1; + else + return rval; +} + +/* + * Calculate the number of bits needed to hold i different values. + */ +uint +xfs_da_log2_roundup(uint i) +{ + uint rval; + + for (rval = 0; rval < NBBY * sizeof(i); rval++) { + if ((1 << rval) >= i) + break; + } + return(rval); +} + +kmem_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ +kmem_zone_t *xfs_dabuf_zone; /* dabuf zone */ + +/* + * Allocate a dir-state structure. + * We don't put them on the stack since they're large. + */ +xfs_da_state_t * +xfs_da_state_alloc(void) +{ + return kmem_zone_zalloc(xfs_da_state_zone, KM_SLEEP); +} + +/* + * Kill the altpath contents of a da-state structure. + */ +void +xfs_da_state_kill_altpath(xfs_da_state_t *state) +{ + int i; + + for (i = 0; i < state->altpath.active; i++) { + if (state->altpath.blk[i].bp) { + if (state->altpath.blk[i].bp != state->path.blk[i].bp) + xfs_da_buf_done(state->altpath.blk[i].bp); + state->altpath.blk[i].bp = NULL; + } + } + state->altpath.active = 0; +} + +/* + * Free a da-state structure. + */ +void +xfs_da_state_free(xfs_da_state_t *state) +{ + int i; + + xfs_da_state_kill_altpath(state); + for (i = 0; i < state->path.active; i++) { + if (state->path.blk[i].bp) + xfs_da_buf_done(state->path.blk[i].bp); + } + if (state->extravalid && state->extrablk.bp) + xfs_da_buf_done(state->extrablk.bp); +#ifdef DEBUG + bzero((char *)state, sizeof(*state)); +#endif /* DEBUG */ + kmem_zone_free(xfs_da_state_zone, state); +} + +#ifdef XFS_DABUF_DEBUG +xfs_dabuf_t *xfs_dabuf_global_list; +lock_t xfs_dabuf_global_lock; +#endif + +/* + * Create a dabuf. + */ +/* ARGSUSED */ +STATIC xfs_dabuf_t * +xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra) +{ + xfs_buf_t *bp; + xfs_dabuf_t *dabuf; + int i; + int off; + + if (nbuf == 1) + dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_SLEEP); + else + dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_SLEEP); + dabuf->dirty = 0; +#ifdef XFS_DABUF_DEBUG + dabuf->ra = ra; + dabuf->dev = XFS_BUF_TARGET_DEV(bps[0]); + dabuf->blkno = XFS_BUF_ADDR(bps[0]); +#endif + if (nbuf == 1) { + dabuf->nbuf = 1; + bp = bps[0]; + dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp)); + dabuf->data = XFS_BUF_PTR(bp); + dabuf->bps[0] = bp; + } else { + dabuf->nbuf = nbuf; + for (i = 0, dabuf->bbcount = 0; i < nbuf; i++) { + dabuf->bps[i] = bp = bps[i]; + dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp)); + } + dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP); + for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) { + bp = bps[i]; + bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off, + XFS_BUF_COUNT(bp)); + } + } +#ifdef XFS_DABUF_DEBUG + { + SPLDECL(s); + xfs_dabuf_t *p; + + s = mutex_spinlock(&xfs_dabuf_global_lock); + for (p = xfs_dabuf_global_list; p; p = p->next) { + ASSERT(p->blkno != dabuf->blkno || + p->dev != dabuf->dev); + } + dabuf->prev = NULL; + if (xfs_dabuf_global_list) + xfs_dabuf_global_list->prev = dabuf; + dabuf->next = xfs_dabuf_global_list; + xfs_dabuf_global_list = dabuf; + mutex_spinunlock(&xfs_dabuf_global_lock, s); + } +#endif + return dabuf; +} + +/* + * Un-dirty a dabuf. + */ +STATIC void +xfs_da_buf_clean(xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + int i; + int off; + + if (dabuf->dirty) { + ASSERT(dabuf->nbuf > 1); + dabuf->dirty = 0; + for (i = off = 0; i < dabuf->nbuf; + i++, off += XFS_BUF_COUNT(bp)) { + bp = dabuf->bps[i]; + bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp), + XFS_BUF_COUNT(bp)); + } + } +} + +/* + * Release a dabuf. + */ +void +xfs_da_buf_done(xfs_dabuf_t *dabuf) +{ + ASSERT(dabuf); + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if (dabuf->dirty) + xfs_da_buf_clean(dabuf); + if (dabuf->nbuf > 1) + kmem_free(dabuf->data, BBTOB(dabuf->bbcount)); +#ifdef XFS_DABUF_DEBUG + { + SPLDECL(s); + + s = mutex_spinlock(&xfs_dabuf_global_lock); + if (dabuf->prev) + dabuf->prev->next = dabuf->next; + else + xfs_dabuf_global_list = dabuf->next; + if (dabuf->next) + dabuf->next->prev = dabuf->prev; + mutex_spinunlock(&xfs_dabuf_global_lock, s); + } + bzero(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); +#endif + if (dabuf->nbuf == 1) + kmem_zone_free(xfs_dabuf_zone, dabuf); + else + kmem_free(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); +} + +/* + * Log transaction from a dabuf. + */ +void +xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last) +{ + xfs_buf_t *bp; + uint f; + int i; + uint l; + int off; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if (dabuf->nbuf == 1) { + ASSERT(dabuf->data == (void *)XFS_BUF_PTR(dabuf->bps[0])); + xfs_trans_log_buf(tp, dabuf->bps[0], first, last); + return; + } + dabuf->dirty = 1; + ASSERT(first <= last); + for (i = off = 0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) { + bp = dabuf->bps[i]; + f = off; + l = f + XFS_BUF_COUNT(bp) - 1; + if (f < first) + f = first; + if (l > last) + l = last; + if (f <= l) + xfs_trans_log_buf(tp, bp, f - off, l - off); + /* + * B_DONE is set by xfs_trans_log buf. + * If we don't set it on a new buffer (get not read) + * then if we don't put anything in the buffer it won't + * be set, and at commit it it released into the cache, + * and then a read will fail. + */ + else if (!(XFS_BUF_ISDONE(bp))) + XFS_BUF_DONE(bp); + } + ASSERT(last < off); +} + +/* + * Release dabuf from a transaction. + * Have to free up the dabuf before the buffers are released, + * since the synchronization on the dabuf is really the lock on the buffer. + */ +void +xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int i; + int nbuf; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP); + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + xfs_da_buf_done(dabuf); + for (i = 0; i < nbuf; i++) + xfs_trans_brelse(tp, bplist[i]); + if (bplist != &bp) + kmem_free(bplist, nbuf * sizeof(*bplist)); +} + +/* + * Invalidate dabuf from a transaction. + */ +void +xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int i; + int nbuf; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP); + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + xfs_da_buf_done(dabuf); + for (i = 0; i < nbuf; i++) + xfs_trans_binval(tp, bplist[i]); + if (bplist != &bp) + kmem_free(bplist, nbuf * sizeof(*bplist)); +} + +/* + * Get the first daddr from a dabuf. + */ +xfs_daddr_t +xfs_da_blkno(xfs_dabuf_t *dabuf) +{ + ASSERT(dabuf->nbuf); + ASSERT(dabuf->data); + return XFS_BUF_ADDR(dabuf->bps[0]); +} diff -Nur linux-2.4.19/fs/xfs/xfs_da_btree.h linux-2.4.19-sgi211r3/fs/xfs/xfs_da_btree.h --- linux-2.4.19/fs/xfs/xfs_da_btree.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_da_btree.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DA_BTREE_H__ +#define __XFS_DA_BTREE_H__ + +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; +struct zone; + +/*======================================================================== + * Directory Structure when greater than XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This structure is common to both leaf nodes and non-leaf nodes in the Btree. + * + * Is is used to manage a doubly linked list of all blocks at the same + * level in the Btree, and to identify which type of block this is. + */ +#define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */ +#define XFS_DIR_LEAF_MAGIC 0xfeeb /* magic number: directory leaf blks */ +#define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */ +#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ +#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ + +#define XFS_DIRX_LEAF_MAGIC(mp) \ + (XFS_DIR_IS_V1(mp) ? XFS_DIR_LEAF_MAGIC : XFS_DIR2_LEAFN_MAGIC) + +typedef struct xfs_da_blkinfo { + xfs_dablk_t forw; /* previous block in list */ + xfs_dablk_t back; /* following block in list */ + __uint16_t magic; /* validity check on block */ + __uint16_t pad; /* unused */ +} xfs_da_blkinfo_t; + +/* + * This is the structure of the root and intermediate nodes in the Btree. + * The leaf nodes are defined above. + * + * Entries are not packed. + * + * Since we have duplicate keys, use a binary search but always follow + * all match in the block, not just the first match found. + */ +#define XFS_DA_NODE_MAXDEPTH 5 /* max depth of Btree */ + +typedef struct xfs_da_intnode { + struct xfs_da_node_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active entries */ + __uint16_t level; /* level above leaves (leaf == 0) */ + } hdr; + struct xfs_da_node_entry { + xfs_dahash_t hashval; /* hash value for this descendant */ + xfs_dablk_t before; /* Btree block before this key */ + } btree[1]; /* variable sized array of keys */ +} xfs_da_intnode_t; +typedef struct xfs_da_node_hdr xfs_da_node_hdr_t; +typedef struct xfs_da_node_entry xfs_da_node_entry_t; + +#define XFS_DA_NODE_ENTSIZE_BYNAME /* space a name uses */ \ + (sizeof(xfs_da_node_entry_t)) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_NODE_ENTRIES) +int xfs_da_node_entries(struct xfs_mount *mp); +#define XFS_DA_NODE_ENTRIES(mp) xfs_da_node_entries(mp) +#else +#define XFS_DA_NODE_ENTRIES(mp) ((mp)->m_da_node_ents) +#endif + +#define XFS_DA_MAXHASH ((xfs_dahash_t)-1) /* largest valid hash value */ + +/* + * Macros used by directory code to interface to the filesystem. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LBSIZE) +int xfs_lbsize(struct xfs_mount *mp); +#define XFS_LBSIZE(mp) xfs_lbsize(mp) +#else +#define XFS_LBSIZE(mp) ((mp)->m_sb.sb_blocksize) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LBLOG) +int xfs_lblog(struct xfs_mount *mp); +#define XFS_LBLOG(mp) xfs_lblog(mp) +#else +#define XFS_LBLOG(mp) ((mp)->m_sb.sb_blocklog) +#endif + +/* + * Macros used by directory code to interface to the kernel + */ + +/* + * Macros used to manipulate directory off_t's + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_MAKE_BNOENTRY) +__uint32_t xfs_da_make_bnoentry(struct xfs_mount *mp, xfs_dablk_t bno, + int entry); +#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \ + xfs_da_make_bnoentry(mp,bno,entry) +#else +#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \ + (((bno) << (mp)->m_dircook_elog) | (entry)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_MAKE_COOKIE) +xfs_off_t xfs_da_make_cookie(struct xfs_mount *mp, xfs_dablk_t bno, int entry, + xfs_dahash_t hash); +#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \ + xfs_da_make_cookie(mp,bno,entry,hash) +#else +#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \ + (((xfs_off_t)XFS_DA_MAKE_BNOENTRY(mp, bno, entry) << 32) | (hash)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_HASH) +xfs_dahash_t xfs_da_cookie_hash(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_HASH(mp,cookie) xfs_da_cookie_hash(mp,cookie) +#else +#define XFS_DA_COOKIE_HASH(mp,cookie) ((xfs_dahash_t)(cookie)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_BNO) +xfs_dablk_t xfs_da_cookie_bno(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_BNO(mp,cookie) xfs_da_cookie_bno(mp,cookie) +#else +#define XFS_DA_COOKIE_BNO(mp,cookie) \ + (((xfs_off_t)(cookie) >> 31) == -1LL ? \ + (xfs_dablk_t)0 : \ + (xfs_dablk_t)((xfs_off_t)(cookie) >> ((mp)->m_dircook_elog + 32))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_ENTRY) +int xfs_da_cookie_entry(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_ENTRY(mp,cookie) xfs_da_cookie_entry(mp,cookie) +#else +#define XFS_DA_COOKIE_ENTRY(mp,cookie) \ + (((xfs_off_t)(cookie) >> 31) == -1LL ? \ + (xfs_dablk_t)0 : \ + (xfs_dablk_t)(((xfs_off_t)(cookie) >> 32) & \ + ((1 << (mp)->m_dircook_elog) - 1))) +#endif + + +/*======================================================================== + * Btree searching and modification structure definitions. + *========================================================================*/ + +/* + * Structure to ease passing around component names. + */ +typedef struct xfs_da_args { + uchar_t *name; /* string (maybe not NULL terminated) */ + int namelen; /* length of string (maybe no NULL) */ + uchar_t *value; /* set of bytes (maybe contain NULLs) */ + int valuelen; /* length of value */ + int flags; /* argument flags (eg: ATTR_NOCREATE) */ + xfs_dahash_t hashval; /* hash value of name */ + xfs_ino_t inumber; /* input/output inode number */ + struct xfs_inode *dp; /* directory inode to manipulate */ + xfs_fsblock_t *firstblock; /* ptr to firstblock for bmap calls */ + struct xfs_bmap_free *flist; /* ptr to freelist for bmap_finish */ + struct xfs_trans *trans; /* current trans (changes over time) */ + xfs_extlen_t total; /* total blocks needed, for 1st bmap */ + int whichfork; /* data or attribute fork */ + xfs_dablk_t blkno; /* blkno of attr leaf of interest */ + int index; /* index of attr of interest in blk */ + xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ + int rmtblkcnt; /* remote attr value block count */ + int rename; /* T/F: this is an atomic rename op */ + xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */ + int index2; /* index of 2nd attr in blk */ + xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ + int rmtblkcnt2; /* remote attr value block count */ + int justcheck; /* check for ok with no space */ + int addname; /* T/F: this is an add operation */ + int oknoent; /* T/F: ok to return ENOENT, else die */ +} xfs_da_args_t; + +/* + * Structure to describe buffer(s) for a block. + * This is needed in the directory version 2 format case, when + * multiple non-contiguous fsblocks might be needed to cover one + * logical directory block. + * If the buffer count is 1 then the data pointer points to the + * same place as the b_addr field for the buffer, else to kmem_alloced memory. + */ +typedef struct xfs_dabuf { + int nbuf; /* number of buffer pointers present */ + short dirty; /* data needs to be copied back */ + short bbcount; /* how large is data in bbs */ + void *data; /* pointer for buffers' data */ +#ifdef XFS_DABUF_DEBUG + inst_t *ra; /* return address of caller to make */ + struct xfs_dabuf *next; /* next in global chain */ + struct xfs_dabuf *prev; /* previous in global chain */ + dev_t dev; /* device for buffer */ + xfs_daddr_t blkno; /* daddr first in bps[0] */ +#endif + struct xfs_buf *bps[1]; /* actually nbuf of these */ +} xfs_dabuf_t; +#define XFS_DA_BUF_SIZE(n) \ + (sizeof(xfs_dabuf_t) + sizeof(struct xfs_buf *) * ((n) - 1)) + +#ifdef XFS_DABUF_DEBUG +extern xfs_dabuf_t *xfs_dabuf_global_list; +#endif + +/* + * Storage for holding state during Btree searches and split/join ops. + * + * Only need space for 5 intermediate nodes. With a minimum of 62-way + * fanout to the Btree, we can support over 900 million directory blocks, + * which is slightly more than enough. + */ +typedef struct xfs_da_state_blk { + xfs_dabuf_t *bp; /* buffer containing block */ + xfs_dablk_t blkno; /* filesystem blkno of buffer */ + xfs_daddr_t disk_blkno; /* on-disk blkno (in BBs) of buffer */ + int index; /* relevant index into block */ + xfs_dahash_t hashval; /* last hash value in block */ + int magic; /* blk's magic number, ie: blk type */ +} xfs_da_state_blk_t; + +typedef struct xfs_da_state_path { + int active; /* number of active levels */ + xfs_da_state_blk_t blk[XFS_DA_NODE_MAXDEPTH]; +} xfs_da_state_path_t; + +typedef struct xfs_da_state { + xfs_da_args_t *args; /* filename arguments */ + struct xfs_mount *mp; /* filesystem mount point */ + int blocksize; /* logical block size */ + int inleaf; /* insert into 1->lf, 0->splf */ + xfs_da_state_path_t path; /* search/split paths */ + xfs_da_state_path_t altpath; /* alternate path for join */ + int extravalid; /* T/F: extrablk is in use */ + int extraafter; /* T/F: extrablk is after new */ + xfs_da_state_blk_t extrablk; /* for double-splits on leafs */ + /* for dirv2 extrablk is data */ +} xfs_da_state_t; + +/* + * Utility macros to aid in logging changed structure fields. + */ +#define XFS_DA_LOGOFF(BASE, ADDR) ((char *)(ADDR) - (char *)(BASE)) +#define XFS_DA_LOGRANGE(BASE, ADDR, SIZE) \ + (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ + (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) + + +#ifdef __KERNEL__ +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +int xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level, + xfs_dabuf_t **bpp, int whichfork); +int xfs_da_split(xfs_da_state_t *state); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_da_join(xfs_da_state_t *state); +void xfs_da_fixhashpath(xfs_da_state_t *state, + xfs_da_state_path_t *path_to_to_fix); + +/* + * Routines used for finding things in the Btree. + */ +int xfs_da_node_lookup_int(xfs_da_state_t *state, int *result); +int xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, + int forward, int release, int *result); +/* + * Utility routines. + */ +int xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk); +int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, + xfs_da_state_blk_t *new_blk); + +/* + * Utility routines. + */ +int xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno); +int xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, xfs_daddr_t mappedbno, + xfs_dabuf_t **bp, int whichfork); +int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, int whichfork); +xfs_daddr_t xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, int whichfork); +int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, + xfs_dabuf_t *dead_buf); + +uint xfs_da_hashname(uchar_t *name_string, int name_length); +uint xfs_da_log2_roundup(uint i); +xfs_da_state_t *xfs_da_state_alloc(void); +void xfs_da_state_free(xfs_da_state_t *state); +void xfs_da_state_kill_altpath(xfs_da_state_t *state); + +void xfs_da_buf_done(xfs_dabuf_t *dabuf); +void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first, + uint last); +void xfs_da_brelse(struct xfs_trans *tp, xfs_dabuf_t *dabuf); +void xfs_da_binval(struct xfs_trans *tp, xfs_dabuf_t *dabuf); +xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf); + +extern struct kmem_zone *xfs_da_state_zone; +#endif /* __KERNEL__ */ + +#endif /* __XFS_DA_BTREE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dfrag.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dfrag.c --- linux-2.4.19/fs/xfs/xfs_dfrag.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dfrag.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +/* + * Syssgi interface for swapext + */ +int +xfs_swapext( + xfs_swapext_t *sxp) +{ + xfs_swapext_t sx; + xfs_inode_t *ip=NULL, *tip=NULL, *ips[2]; + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_bstat_t *sbp; + struct file *fp = NULL, *tfp = NULL; + vnode_t *vp, *tvp; + bhv_desc_t *bdp, *tbdp; + vn_bhv_head_t *bhp, *tbhp; + uint lock_flags=0; + int ilf_fields, tilf_fields; + int error = 0; + xfs_ifork_t tempif, *ifp, *tifp; + __uint64_t tmp; + int aforkblks = 0; + int taforkblks = 0; + int locked = 0; + + if (copy_from_user(&sx, sxp, sizeof(sx))) + return XFS_ERROR(EFAULT); + + /* Pull information for the target fd */ + if (((fp = fget((int)sx.sx_fdtarget)) == NULL) || + ((vp = LINVFS_GET_VP(fp->f_dentry->d_inode)) == NULL)) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + bhp = VN_BHV_HEAD(vp); + VN_BHV_READ_LOCK(bhp); + bdp = vn_bhv_lookup(bhp, &xfs_vnodeops); + if (bdp == NULL) { + VN_BHV_READ_UNLOCK(bhp); + error = XFS_ERROR(EBADF); + goto error0; + } else { + ip = XFS_BHVTOI(bdp); + VN_BHV_READ_UNLOCK(bhp); + } + + if (((tfp = fget((int)sx.sx_fdtmp)) == NULL) || + ((tvp = LINVFS_GET_VP(tfp->f_dentry->d_inode)) == NULL)) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + tbhp = VN_BHV_HEAD(tvp); + VN_BHV_READ_LOCK(tbhp); + tbdp = vn_bhv_lookup(tbhp, &xfs_vnodeops); + if (tbdp == NULL) { + VN_BHV_READ_UNLOCK(tbhp); + error = XFS_ERROR(EBADF); + goto error0; + } else { + tip = XFS_BHVTOI(tbdp); + VN_BHV_READ_UNLOCK(tbhp); + } + + if (ip->i_ino == tip->i_ino) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + mp = ip->i_mount; + + sbp = &sx.sx_stat; + + if (XFS_FORCED_SHUTDOWN(mp)) { + error = XFS_ERROR(EIO); + goto error0; + } + + locked = 1; + + /* Lock in i_ino order */ + if (ip->i_ino < tip->i_ino) { + ips[0] = ip; + ips[1] = tip; + } else { + ips[0] = tip; + ips[1] = ip; + } + lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; + xfs_lock_inodes(ips, 2, 0, lock_flags); + + /* Check permissions */ + if ((error = _MAC_XFS_IACCESS(ip, MACWRITE, NULL))) { + goto error0; + } + if ((error = _MAC_XFS_IACCESS(tip, MACWRITE, NULL))) { + goto error0; + } + if ((current->fsuid != ip->i_d.di_uid) && + (error = xfs_iaccess(ip, IWRITE, NULL)) && + !capable_cred(NULL, CAP_FOWNER)) { + goto error0; + } + if ((current->fsuid != tip->i_d.di_uid) && + (error = xfs_iaccess(tip, IWRITE, NULL)) && + !capable_cred(NULL, CAP_FOWNER)) { + goto error0; + } + + /* Verify both files are either real-time or non-realtime */ + if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != + (tip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + /* Should never get a local format */ + if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL || + tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + if (VN_CACHED(tvp) != 0) + xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore), + (loff_t)0, 0, 0); + + /* Verify O_DIRECT for ftmp */ + if (VN_CACHED(tvp) != 0) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + /* Verify all data are being swapped */ + if (sx.sx_offset != 0 || + sx.sx_length != ip->i_d.di_size || + sx.sx_length != tip->i_d.di_size) { + error = XFS_ERROR(EFAULT); + goto error0; + } + + /* + * If the target has extended attributes, the tmp file + * must also in order to ensure the correct data fork + * format. + */ + if ( XFS_IFORK_Q(ip) != XFS_IFORK_Q(tip) ) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + /* + * Compare the current change & modify times with that + * passed in. If they differ, we abort this swap. + * This is the mechanism used to ensure the calling + * process that the file was not changed out from + * under it. + */ + if ((sbp->bs_ctime.tv_sec != ip->i_d.di_ctime.t_sec) || + (sbp->bs_ctime.tv_nsec != ip->i_d.di_ctime.t_nsec) || + (sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) || + (sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) { + error = XFS_ERROR(EBUSY); + goto error0; + } + + /* We need to fail if the file is memory mapped. Once we have tossed + * all existing pages, the page fault will have no option + * but to go to the filesystem for pages. By making the page fault call + * VOP_READ (or write in the case of autogrow) they block on the iolock + * until we have switched the extents. + */ + if (VN_MAPPED(vp)) { + error = XFS_ERROR(EBUSY); + goto error0; + } + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_iunlock(tip, XFS_ILOCK_EXCL); + + /* + * There is a race condition here since we gave up the + * ilock. However, the data fork will not change since + * we have the iolock (locked for truncation too) so we + * are safe. We don't really care if non-io related + * fields change. + */ + + VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF); + + tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); + if ((error = xfs_trans_reserve(tp, 0, + XFS_ICHANGE_LOG_RES(mp), 0, + 0, 0))) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + xfs_iunlock(tip, XFS_IOLOCK_EXCL); + xfs_trans_cancel(tp, 0); + return error; + } + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); + + /* + * Count the number of extended attribute blocks + */ + if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) && + (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { + error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks); + if (error) { + xfs_iunlock(ip, lock_flags); + xfs_iunlock(tip, lock_flags); + xfs_trans_cancel(tp, 0); + return error; + } + } + if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) && + (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { + error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, + &taforkblks); + if (error) { + xfs_iunlock(ip, lock_flags); + xfs_iunlock(tip, lock_flags); + xfs_trans_cancel(tp, 0); + return error; + } + } + + /* + * Swap the data forks of the inodes + */ + ifp = &ip->i_df; + tifp = &tip->i_df; + tempif = *ifp; /* struct copy */ + *ifp = *tifp; /* struct copy */ + *tifp = tempif; /* struct copy */ + + /* + * Fix the on-disk inode values + */ + tmp = (__uint64_t)ip->i_d.di_nblocks; + ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks; + tip->i_d.di_nblocks = tmp + taforkblks - aforkblks; + + tmp = (__uint64_t) ip->i_d.di_nextents; + ip->i_d.di_nextents = tip->i_d.di_nextents; + tip->i_d.di_nextents = tmp; + + tmp = (__uint64_t) ip->i_d.di_format; + ip->i_d.di_format = tip->i_d.di_format; + tip->i_d.di_format = tmp; + + ilf_fields = XFS_ILOG_CORE; + + switch(ip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + /* If the extents fit in the inode, fix the + * pointer. Otherwise it's already NULL or + * pointing to the extent. + */ + if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) { + ifp->if_u1.if_extents = + ifp->if_u2.if_inline_ext; + } + ilf_fields |= XFS_ILOG_DEXT; + break; + case XFS_DINODE_FMT_BTREE: + ilf_fields |= XFS_ILOG_DBROOT; + break; + } + + tilf_fields = XFS_ILOG_CORE; + + switch(tip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + /* If the extents fit in the inode, fix the + * pointer. Otherwise it's already NULL or + * pointing to the extent. + */ + if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) { + tifp->if_u1.if_extents = + tifp->if_u2.if_inline_ext; + } + tilf_fields |= XFS_ILOG_DEXT; + break; + case XFS_DINODE_FMT_BTREE: + tilf_fields |= XFS_ILOG_DBROOT; + break; + } + + /* + * Increment vnode ref counts since xfs_trans_commit & + * xfs_trans_cancel will both unlock the inodes and + * decrement the associated ref counts. + */ + VN_HOLD(vp); + VN_HOLD(tvp); + + xfs_trans_ijoin(tp, ip, lock_flags); + xfs_trans_ijoin(tp, tip, lock_flags); + + xfs_trans_log_inode(tp, ip, ilf_fields); + xfs_trans_log_inode(tp, tip, tilf_fields); + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL); + + fput(fp); + fput(tfp); + + return error; + + error0: + if (locked) { + xfs_iunlock(ip, lock_flags); + xfs_iunlock(tip, lock_flags); + } + + if (fp != NULL) fput(fp); + if (tfp != NULL) fput(tfp); + + return error; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dfrag.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dfrag.h --- linux-2.4.19/fs/xfs/xfs_dfrag.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dfrag.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DFRAG_H__ +#define __XFS_DFRAG_H__ + +/* + * Structure passed to xfs_swapext + */ + +typedef struct xfs_swapext +{ + __int64_t sx_version; /* version */ + __int64_t sx_fdtarget; /* fd of target file */ + __int64_t sx_fdtmp; /* fd of tmp file */ + xfs_off_t sx_offset; /* offset into file */ + xfs_off_t sx_length; /* leng from offset */ + char sx_pad[16]; /* pad space, unused */ + xfs_bstat_t sx_stat; /* stat of target b4 copy */ +} xfs_swapext_t; + +/* + * Version flag + */ +#define XFS_SX_VERSION 0 + +#ifdef __KERNEL__ +/* + * Prototypes for visible xfs_dfrag.c routines. + */ + +/* + * Syscall interface for xfs_swapext + */ +int xfs_swapext(struct xfs_swapext *sx); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_DFRAG_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dinode.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dinode.h --- linux-2.4.19/fs/xfs/xfs_dinode.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dinode.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DINODE_H__ +#define __XFS_DINODE_H__ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_DINODE_VERSION_1 1 +#define XFS_DINODE_VERSION_2 2 +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DINODE_GOOD_VERSION) +int xfs_dinode_good_version(int v); +#define XFS_DINODE_GOOD_VERSION(v) xfs_dinode_good_version(v) +#else +#define XFS_DINODE_GOOD_VERSION(v) (((v) == XFS_DINODE_VERSION_1) || \ + ((v) == XFS_DINODE_VERSION_2)) +#endif +#define XFS_DINODE_MAGIC 0x494e /* 'IN' */ + +/* + * Disk inode structure. + * This is just the header; the inode is expanded to fill a variable size + * with the last field expanding. It is split into the core and "other" + * because we only need the core part in the in-core inode. + */ +typedef struct xfs_timestamp { + __int32_t t_sec; /* timestamp seconds */ + __int32_t t_nsec; /* timestamp nanoseconds */ +} xfs_timestamp_t; + +/* + * Note: Coordinate changes to this structure with the XFS_DI_* #defines + * below and the offsets table in xfs_ialloc_log_di(). + */ +typedef struct xfs_dinode_core +{ + __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ + __uint16_t di_mode; /* mode and type of file */ + __int8_t di_version; /* inode version */ + __int8_t di_format; /* format of di_c data */ + __uint16_t di_onlink; /* old number of links to file */ + __uint32_t di_uid; /* owner's user id */ + __uint32_t di_gid; /* owner's group id */ + __uint32_t di_nlink; /* number of links to file */ + __uint16_t di_projid; /* owner's project id */ + __uint8_t di_pad[10]; /* unused, zeroed space */ + xfs_timestamp_t di_atime; /* time last accessed */ + xfs_timestamp_t di_mtime; /* time last modified */ + xfs_timestamp_t di_ctime; /* time created/inode modified */ + xfs_fsize_t di_size; /* number of bytes in file */ + xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */ + xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ + xfs_extnum_t di_nextents; /* number of extents in data fork */ + xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ + __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ + __int8_t di_aformat; /* format of attr fork's data */ + __uint32_t di_dmevmask; /* DMIG event mask */ + __uint16_t di_dmstate; /* DMIG state info */ + __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ + __uint32_t di_gen; /* generation number */ +} xfs_dinode_core_t; + +typedef struct xfs_dinode +{ + xfs_dinode_core_t di_core; + /* + * In adding anything between the core and the union, be + * sure to update the macros like XFS_LITINO below and + * XFS_BMAP_RBLOCK_DSIZE in xfs_bmap_btree.h. + */ + xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ + union { + xfs_bmdr_block_t di_bmbt; /* btree root block */ + xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */ + xfs_dir_shortform_t di_dirsf; /* shortform directory */ + xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */ + char di_c[1]; /* local contents */ + xfs_dev_t di_dev; /* device for IFCHR/IFBLK */ + uuid_t di_muuid; /* mount point value */ + char di_symlink[1]; /* local symbolic link */ + } di_u; + union { + xfs_bmdr_block_t di_abmbt; /* btree root block */ + xfs_bmbt_rec_32_t di_abmx[1]; /* extent list */ + xfs_attr_shortform_t di_attrsf; /* shortform attribute list */ + } di_a; +} xfs_dinode_t; + +/* + * The 32 bit link count in the inode theoretically maxes out at UINT_MAX. + * Since the pathconf interface is signed, we use 2^31 - 1 instead. + * The old inode format had a 16 bit link count, so its maximum is USHRT_MAX. + */ +#define XFS_MAXLINK ((1U << 31) - 1U) +#define XFS_MAXLINK_1 65535U + +/* + * Bit names for logging disk inodes only + */ +#define XFS_DI_MAGIC 0x0000001 +#define XFS_DI_MODE 0x0000002 +#define XFS_DI_VERSION 0x0000004 +#define XFS_DI_FORMAT 0x0000008 +#define XFS_DI_ONLINK 0x0000010 +#define XFS_DI_UID 0x0000020 +#define XFS_DI_GID 0x0000040 +#define XFS_DI_NLINK 0x0000080 +#define XFS_DI_PROJID 0x0000100 +#define XFS_DI_PAD 0x0000200 +#define XFS_DI_ATIME 0x0000400 +#define XFS_DI_MTIME 0x0000800 +#define XFS_DI_CTIME 0x0001000 +#define XFS_DI_SIZE 0x0002000 +#define XFS_DI_NBLOCKS 0x0004000 +#define XFS_DI_EXTSIZE 0x0008000 +#define XFS_DI_NEXTENTS 0x0010000 +#define XFS_DI_NAEXTENTS 0x0020000 +#define XFS_DI_FORKOFF 0x0040000 +#define XFS_DI_AFORMAT 0x0080000 +#define XFS_DI_DMEVMASK 0x0100000 +#define XFS_DI_DMSTATE 0x0200000 +#define XFS_DI_FLAGS 0x0400000 +#define XFS_DI_GEN 0x0800000 +#define XFS_DI_NEXT_UNLINKED 0x1000000 +#define XFS_DI_U 0x2000000 +#define XFS_DI_A 0x4000000 +#define XFS_DI_NUM_BITS 27 +#define XFS_DI_ALL_BITS ((1 << XFS_DI_NUM_BITS) - 1) +#define XFS_DI_CORE_BITS (XFS_DI_ALL_BITS & ~(XFS_DI_U|XFS_DI_A)) + +/* + * Values for di_format + */ +typedef enum xfs_dinode_fmt +{ + XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */ + XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */ + /* LNK: di_symlink */ + XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */ + XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */ + XFS_DINODE_FMT_UUID /* MNT: di_uuid */ +} xfs_dinode_fmt_t; + +/* + * Inode minimum and maximum sizes. + */ +#define XFS_DINODE_MIN_LOG 8 +#define XFS_DINODE_MAX_LOG 11 +#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) +#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) + +/* + * Inode size for given fs. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LITINO) +int xfs_litino(struct xfs_mount *mp); +#define XFS_LITINO(mp) xfs_litino(mp) +#else +#define XFS_LITINO(mp) ((mp)->m_litino) +#endif +#define XFS_BROOT_SIZE_ADJ \ + (sizeof(xfs_bmbt_block_t) - sizeof(xfs_bmdr_block_t)) + +/* + * Fork identifiers. Here so utilities can use them without including + * xfs_inode.h. + */ +#define XFS_DATA_FORK 0 +#define XFS_ATTR_FORK 1 + +/* + * Inode data & attribute fork sizes, per inode. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_Q) +int xfs_cfork_q_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch); +int xfs_cfork_q(xfs_dinode_core_t *dcp); +#define XFS_CFORK_Q_ARCH(dcp,arch) xfs_cfork_q_arch(dcp,arch) +#define XFS_CFORK_Q(dcp) xfs_cfork_q(dcp) +#else +#define XFS_CFORK_Q_ARCH(dcp,arch) (!INT_ISZERO((dcp)->di_forkoff, arch)) +#define XFS_CFORK_Q(dcp) ((dcp)->di_forkoff != 0) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_BOFF) +int xfs_cfork_boff_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch); +int xfs_cfork_boff(xfs_dinode_core_t *dcp); +#define XFS_CFORK_BOFF_ARCH(dcp,arch) xfs_cfork_boff_arch(dcp,arch) +#define XFS_CFORK_BOFF(dcp) xfs_cfork_boff(dcp) +#else +#define XFS_CFORK_BOFF_ARCH(dcp,arch) ((int)(INT_GET((dcp)->di_forkoff, arch) << 3)) +#define XFS_CFORK_BOFF(dcp) ((int)((dcp)->di_forkoff << 3)) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_DSIZE) +int xfs_cfork_dsize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_cfork_dsize(xfs_dinode_core_t *dcp, struct xfs_mount *mp); +#define XFS_CFORK_DSIZE_ARCH(dcp,mp,arch) xfs_cfork_dsize_arch(dcp,mp,arch) +#define XFS_CFORK_DSIZE(dcp,mp) xfs_cfork_dsize(dcp,mp) +#else +#define XFS_CFORK_DSIZE_ARCH(dcp,mp,arch) \ + (XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_CFORK_BOFF_ARCH(dcp, arch) : XFS_LITINO(mp)) +#define XFS_CFORK_DSIZE(dcp,mp) \ + (XFS_CFORK_Q(dcp) ? XFS_CFORK_BOFF(dcp) : XFS_LITINO(mp)) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_ASIZE) +int xfs_cfork_asize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_cfork_asize(xfs_dinode_core_t *dcp, struct xfs_mount *mp); +#define XFS_CFORK_ASIZE_ARCH(dcp,mp,arch) xfs_cfork_asize_arch(dcp,mp,arch) +#define XFS_CFORK_ASIZE(dcp,mp) xfs_cfork_asize(dcp,mp) +#else +#define XFS_CFORK_ASIZE_ARCH(dcp,mp,arch) \ + (XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_LITINO(mp) - XFS_CFORK_BOFF_ARCH(dcp, arch) : 0) +#define XFS_CFORK_ASIZE(dcp,mp) \ + (XFS_CFORK_Q(dcp) ? XFS_LITINO(mp) - XFS_CFORK_BOFF(dcp) : 0) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_SIZE) +int xfs_cfork_size_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w, xfs_arch_t arch); +int xfs_cfork_size(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w); +#define XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch) xfs_cfork_size_arch(dcp,mp,w,arch) +#define XFS_CFORK_SIZE(dcp,mp,w) xfs_cfork_size(dcp,mp,w) +#else +#define XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch) \ + ((w) == XFS_DATA_FORK ? \ + XFS_CFORK_DSIZE_ARCH(dcp, mp, arch) : XFS_CFORK_ASIZE_ARCH(dcp, mp, arch)) +#define XFS_CFORK_SIZE(dcp,mp,w) \ + ((w) == XFS_DATA_FORK ? \ + XFS_CFORK_DSIZE(dcp, mp) : XFS_CFORK_ASIZE(dcp, mp)) + +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DSIZE) +int xfs_dfork_dsize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_dfork_dsize(xfs_dinode_t *dip, struct xfs_mount *mp); +#define XFS_DFORK_DSIZE_ARCH(dip,mp,arch) xfs_dfork_dsize_arch(dip,mp,arch) +#define XFS_DFORK_DSIZE(dip,mp) xfs_dfork_dsize(dip,mp) +#else +#define XFS_DFORK_DSIZE_ARCH(dip,mp,arch) XFS_CFORK_DSIZE_ARCH(&(dip)->di_core, mp, arch) +#define XFS_DFORK_DSIZE(dip,mp) XFS_DFORK_DSIZE_ARCH(dip,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_ASIZE) +int xfs_dfork_asize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_dfork_asize(xfs_dinode_t *dip, struct xfs_mount *mp); +#define XFS_DFORK_ASIZE_ARCH(dip,mp,arch) xfs_dfork_asize_arch(dip,mp,arch) +#define XFS_DFORK_ASIZE(dip,mp) xfs_dfork_asize(dip,mp) +#else +#define XFS_DFORK_ASIZE_ARCH(dip,mp,arch) XFS_CFORK_ASIZE_ARCH(&(dip)->di_core, mp, arch) +#define XFS_DFORK_ASIZE(dip,mp) XFS_DFORK_ASIZE_ARCH(dip,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_SIZE) +int xfs_dfork_size_arch(xfs_dinode_t *dip, struct xfs_mount *mp, int w, xfs_arch_t arch); +int xfs_dfork_size(xfs_dinode_t *dip, struct xfs_mount *mp, int w); +#define XFS_DFORK_SIZE_ARCH(dip,mp,w,arch) xfs_dfork_size_arch(dip,mp,w,arch) +#define XFS_DFORK_SIZE(dip,mp,w) xfs_dfork_size(dip,mp,w) +#else +#define XFS_DFORK_SIZE_ARCH(dip,mp,w,arch) XFS_CFORK_SIZE_ARCH(&(dip)->di_core, mp, w, arch) +#define XFS_DFORK_SIZE(dip,mp,w) XFS_DFORK_SIZE_ARCH(dip,mp,w,ARCH_NOCONVERT) + +#endif + +/* + * Macros for accessing per-fork disk inode information. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_Q) +int xfs_dfork_q_arch(xfs_dinode_t *dip, xfs_arch_t arch); +int xfs_dfork_q(xfs_dinode_t *dip); +#define XFS_DFORK_Q_ARCH(dip,arch) xfs_dfork_q_arch(dip,arch) +#define XFS_DFORK_Q(dip) xfs_dfork_q(dip) +#else +#define XFS_DFORK_Q_ARCH(dip,arch) XFS_CFORK_Q_ARCH(&(dip)->di_core, arch) +#define XFS_DFORK_Q(dip) XFS_DFORK_Q_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_BOFF) +int xfs_dfork_boff_arch(xfs_dinode_t *dip, xfs_arch_t arch); +int xfs_dfork_boff(xfs_dinode_t *dip); +#define XFS_DFORK_BOFF_ARCH(dip,arch) xfs_dfork_boff_arch(dip,arch) +#define XFS_DFORK_BOFF(dip) xfs_dfork_boff(dip) +#else +#define XFS_DFORK_BOFF_ARCH(dip,arch) XFS_CFORK_BOFF_ARCH(&(dip)->di_core, arch) +#define XFS_DFORK_BOFF(dip) XFS_DFORK_BOFF_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DPTR) +char *xfs_dfork_dptr_arch(xfs_dinode_t *dip, xfs_arch_t arch); +char *xfs_dfork_dptr(xfs_dinode_t *dip); +#define XFS_DFORK_DPTR_ARCH(dip,arch) xfs_dfork_dptr_arch(dip,arch) +#define XFS_DFORK_DPTR(dip) xfs_dfork_dptr(dip) +#else +#define XFS_DFORK_DPTR_ARCH(dip,arch) ((dip)->di_u.di_c) +#define XFS_DFORK_DPTR(dip) XFS_DFORK_DPTR_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_APTR) +char *xfs_dfork_aptr_arch(xfs_dinode_t *dip, xfs_arch_t arch); +char *xfs_dfork_aptr(xfs_dinode_t *dip); +#define XFS_DFORK_APTR_ARCH(dip,arch) xfs_dfork_aptr_arch(dip,arch) +#define XFS_DFORK_APTR(dip) xfs_dfork_aptr(dip) +#else +#define XFS_DFORK_APTR_ARCH(dip,arch) ((dip)->di_u.di_c + XFS_DFORK_BOFF_ARCH(dip, arch)) +#define XFS_DFORK_APTR(dip) XFS_DFORK_APTR_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_PTR) +char *xfs_dfork_ptr_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +char *xfs_dfork_ptr(xfs_dinode_t *dip, int w); +#define XFS_DFORK_PTR_ARCH(dip,w,arch) xfs_dfork_ptr_arch(dip,w,arch) +#define XFS_DFORK_PTR(dip,w) xfs_dfork_ptr(dip,w) +#else +#define XFS_DFORK_PTR_ARCH(dip,w,arch) \ + ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR_ARCH(dip, arch) : XFS_DFORK_APTR_ARCH(dip, arch)) +#define XFS_DFORK_PTR(dip,w) XFS_DFORK_PTR_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FORMAT) +int xfs_cfork_format_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch); +int xfs_cfork_format(xfs_dinode_core_t *dcp, int w); +#define XFS_CFORK_FORMAT_ARCH(dcp,w,arch) xfs_cfork_format_arch(dcp,w,arch) +#define XFS_CFORK_FORMAT(dcp,w) xfs_cfork_format(dcp,w) +#else +#define XFS_CFORK_FORMAT_ARCH(dcp,w,arch) \ + ((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_format, arch) : INT_GET((dcp)->di_aformat, arch)) +#define XFS_CFORK_FORMAT(dcp,w) XFS_CFORK_FORMAT_ARCH(dcp,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FMT_SET) +void xfs_cfork_fmt_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch); +void xfs_cfork_fmt_set(xfs_dinode_core_t *dcp, int w, int n); +#define XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) xfs_cfork_fmt_set_arch(dcp,w,n,arch) +#define XFS_CFORK_FMT_SET(dcp,w,n) xfs_cfork_fmt_set(dcp,w,n) +#else +#define XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) \ + ((w) == XFS_DATA_FORK ? \ + (INT_SET((dcp)->di_format, arch, (n))) : \ + (INT_SET((dcp)->di_aformat, arch, (n)))) +#define XFS_CFORK_FMT_SET(dcp,w,n) XFS_CFORK_FMT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXTENTS) +int xfs_cfork_nextents_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch); +int xfs_cfork_nextents(xfs_dinode_core_t *dcp, int w); +#define XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch) xfs_cfork_nextents_arch(dcp,w,arch) +#define XFS_CFORK_NEXTENTS(dcp,w) xfs_cfork_nextents(dcp,w) +#else +#define XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch) \ + ((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_nextents, arch) : INT_GET((dcp)->di_anextents, arch)) +#define XFS_CFORK_NEXTENTS(dcp,w) XFS_CFORK_NEXTENTS_ARCH(dcp,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXT_SET) +void xfs_cfork_next_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch); +void xfs_cfork_next_set(xfs_dinode_core_t *dcp, int w, int n); +#define XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch) xfs_cfork_next_set_arch(dcp,w,n,arch) +#define XFS_CFORK_NEXT_SET(dcp,w,n) xfs_cfork_next_set(dcp,w,n) +#else +#define XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch) \ + ((w) == XFS_DATA_FORK ? \ + (INT_SET((dcp)->di_nextents, arch, (n))) : \ + (INT_SET((dcp)->di_anextents, arch, (n)))) +#define XFS_CFORK_NEXT_SET(dcp,w,n) XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FORMAT) +int xfs_dfork_format_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +int xfs_dfork_format(xfs_dinode_t *dip, int w); +#define XFS_DFORK_FORMAT_ARCH(dip,w,arch) xfs_dfork_format_arch(dip,w,arch) +#define XFS_DFORK_FORMAT(dip,w) xfs_dfork_format(dip,w) +#else +#define XFS_DFORK_FORMAT_ARCH(dip,w,arch) XFS_CFORK_FORMAT_ARCH(&(dip)->di_core, w, arch) +#define XFS_DFORK_FORMAT(dip,w) XFS_DFORK_FORMAT_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FMT_SET) +void xfs_dfork_fmt_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch); +void xfs_dfork_fmt_set(xfs_dinode_t *dip, int w, int n); +#define XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch) xfs_dfork_fmt_set_arch(dip,w,n,arch) +#define XFS_DFORK_FMT_SET(dip,w,n) xfs_dfork_fmt_set(dip,w,n) +#else +#define XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch) XFS_CFORK_FMT_SET_ARCH(&(dip)->di_core, w, n, arch) +#define XFS_DFORK_FMT_SET(dip,w,n) XFS_DFORK_FMT_SET_ARCH(dip,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXTENTS) +int xfs_dfork_nextents_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +int xfs_dfork_nextents(xfs_dinode_t *dip, int w); +#define XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) xfs_dfork_nextents_arch(dip,w,arch) +#define XFS_DFORK_NEXTENTS(dip,w) xfs_dfork_nextents(dip,w) +#else +#define XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) XFS_CFORK_NEXTENTS_ARCH(&(dip)->di_core, w, arch) +#define XFS_DFORK_NEXTENTS(dip,w) XFS_DFORK_NEXTENTS_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXT_SET) +void xfs_dfork_next_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch); +void xfs_dfork_next_set(xfs_dinode_t *dip, int w, int n); +#define XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch) xfs_dfork_next_set_arch(dip,w,n,arch) +#define XFS_DFORK_NEXT_SET(dip,w,n) xfs_dfork_next_set(dip,w,n) +#else +#define XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch) XFS_CFORK_NEXT_SET_ARCH(&(dip)->di_core, w, n, arch) +#define XFS_DFORK_NEXT_SET(dip,w,n) XFS_DFORK_NEXT_SET_ARCH(dip,w,n,ARCH_NOCONVERT) + +#endif + +/* + * File types (mode field) + */ +#define IFMT 0170000 /* type of file */ +#define IFIFO 0010000 /* named pipe (fifo) */ +#define IFCHR 0020000 /* character special */ +#define IFDIR 0040000 /* directory */ +#define IFBLK 0060000 /* block special */ +#define IFREG 0100000 /* regular */ +#define IFLNK 0120000 /* symbolic link */ +#define IFSOCK 0140000 /* socket */ +#define IFMNT 0160000 /* mount point */ + +/* + * File execution and access modes. + */ +#define ISUID 04000 /* set user id on execution */ +#define ISGID 02000 /* set group id on execution */ +#define ISVTX 01000 /* sticky directory */ +#define IREAD 0400 /* read, write, execute permissions */ +#define IWRITE 0200 +#define IEXEC 0100 + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_DINODE) +xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp); +#define XFS_BUF_TO_DINODE(bp) xfs_buf_to_dinode(bp) +#else +#define XFS_BUF_TO_DINODE(bp) ((xfs_dinode_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Values for di_flags + * There should be a one-to-one correspondence between these flags and the + * XFS_XFLAG_s. + */ +#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ +#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ +#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ +#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) +#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) +#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) +#define XFS_DIFLAG_ALL \ + (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM) + +#endif /* __XFS_DINODE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir.c --- linux-2.4.19/fs/xfs/xfs_dir.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,1183 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * xfs_dir.c + * + * Provide the external interfaces to manage directories. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Functions for the dirops interfaces. + */ +static void xfs_dir_mount(struct xfs_mount *mp); + +static int xfs_dir_isempty(struct xfs_inode *dp); + +static int xfs_dir_init(struct xfs_trans *trans, + struct xfs_inode *dir, + struct xfs_inode *parent_dir); + +static int xfs_dir_createname(struct xfs_trans *trans, + struct xfs_inode *dp, + char *name_string, + int name_len, + xfs_ino_t inode_number, + xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, + xfs_extlen_t total); + +static int xfs_dir_lookup(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name_string, + int name_length, + xfs_ino_t *inode_number); + +static int xfs_dir_removename(struct xfs_trans *trans, + struct xfs_inode *dp, + char *name_string, + int name_length, + xfs_ino_t ino, + xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, + xfs_extlen_t total); + +static int xfs_dir_getdents(struct xfs_trans *tp, + struct xfs_inode *dp, + struct uio *uiop, + int *eofp); + +static int xfs_dir_replace(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name_string, + int name_length, + xfs_ino_t inode_number, + xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, + xfs_extlen_t total); + +static int xfs_dir_canenter(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name_string, + int name_length); + +static int xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, + xfs_dinode_t *dip); + +xfs_dirops_t xfsv1_dirops = { + .xd_mount = xfs_dir_mount, + .xd_isempty = xfs_dir_isempty, + .xd_init = xfs_dir_init, + .xd_createname = xfs_dir_createname, + .xd_lookup = xfs_dir_lookup, + .xd_removename = xfs_dir_removename, + .xd_getdents = xfs_dir_getdents, + .xd_replace = xfs_dir_replace, + .xd_canenter = xfs_dir_canenter, + .xd_shortform_validate_ondisk = xfs_dir_shortform_validate_ondisk, + .xd_shortform_to_single = xfs_dir_shortform_to_leaf, +}; + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +STATIC int xfs_dir_leaf_lookup(xfs_da_args_t *args); +STATIC int xfs_dir_leaf_removename(xfs_da_args_t *args, int *number_entries, + int *total_namebytes); +STATIC int xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, + uio_t *uio, int *eofp, + xfs_dirent_t *dbp, + xfs_dir_put_t put); +STATIC int xfs_dir_leaf_replace(xfs_da_args_t *args); + +/* + * Internal routines when dirsize > XFS_LBSIZE(mp). + */ +STATIC int xfs_dir_node_addname(xfs_da_args_t *args); +STATIC int xfs_dir_node_lookup(xfs_da_args_t *args); +STATIC int xfs_dir_node_removename(xfs_da_args_t *args); +STATIC int xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, + uio_t *uio, int *eofp, + xfs_dirent_t *dbp, + xfs_dir_put_t put); +STATIC int xfs_dir_node_replace(xfs_da_args_t *args); + +#if defined(DEBUG) +ktrace_t *xfs_dir_trace_buf; +#endif + + +/*======================================================================== + * Overall external interface routines. + *========================================================================*/ + +xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; + +/* + * One-time startup routine called from xfs_init(). + */ +void +xfs_dir_startup(void) +{ + xfs_dir_hash_dot = xfs_da_hashname(".", 1); + xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); +} + +/* + * Initialize directory-related fields in the mount structure. + */ +static void +xfs_dir_mount(xfs_mount_t *mp) +{ + uint shortcount, leafcount, count; + + mp->m_dirversion = 1; + shortcount = (mp->m_attroffset - (uint)sizeof(xfs_dir_sf_hdr_t)) / + (uint)sizeof(xfs_dir_sf_entry_t); + leafcount = (XFS_LBSIZE(mp) - (uint)sizeof(xfs_dir_leaf_hdr_t)) / + ((uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_name_t)); + count = shortcount > leafcount ? shortcount : leafcount; + mp->m_dircook_elog = xfs_da_log2_roundup(count + 1); + ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog); + mp->m_da_node_ents = + (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) / + (uint)sizeof(xfs_da_node_entry_t); + mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100; + mp->m_dirblksize = mp->m_sb.sb_blocksize; + mp->m_dirblkfsbs = 1; +} + +/* + * Return 1 if directory contains only "." and "..". + */ +static int +xfs_dir_isempty(xfs_inode_t *dp) +{ + xfs_dir_sf_hdr_t *hdr; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (dp->i_d.di_size == 0) + return(1); + if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) + return(0); + hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; + return(hdr->count == 0); +} + +/* + * Initialize a directory with its "." and ".." entries. + */ +static int +xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir) +{ + xfs_da_args_t args; + int error; + + bzero((char *)&args, sizeof(args)); + args.dp = dir; + args.trans = trans; + + ASSERT((dir->i_d.di_mode & IFMT) == IFDIR); + if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino))) + return error; + + return(xfs_dir_shortform_create(&args, parent_dir->i_ino)); +} + +/* + * Generic handler routine to add a name to a directory. + * Transitions directory from shortform to Btree as necessary. + */ +static int /* error */ +xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int retval, newsize, done; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + + if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) + return (retval); + + XFS_STATS_INC(xfsstats.xs_dir_create); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + done = 0; + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); + if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) { + retval = xfs_dir_shortform_addname(&args); + done = 1; + } else { + if (total == 0) + return XFS_ERROR(ENOSPC); + retval = xfs_dir_shortform_to_leaf(&args); + done = retval != 0; + } + } + if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_addname(&args); + done = retval != ENOSPC; + if (!done) { + if (total == 0) + return XFS_ERROR(ENOSPC); + retval = xfs_dir_leaf_to_node(&args); + done = retval != 0; + } + } + if (!done) { + retval = xfs_dir_node_addname(&args); + } + return(retval); +} + +/* + * Generic handler routine to check if a name can be added to a directory, + * without adding any blocks to the directory. + */ +static int /* error */ +xfs_dir_canenter(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen) +{ + xfs_da_args_t args; + int retval, newsize; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); + if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) + retval = 0; + else + retval = XFS_ERROR(ENOSPC); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_addname(&args); + } else { + retval = xfs_dir_node_addname(&args); + } + return(retval); +} + +/* + * Generic handler routine to remove a name from a directory. + * Transitions directory from Btree to shortform as necessary. + */ +static int /* error */ +xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int count, totallen, newsize, retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_remove); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = ino; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 0; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_removename(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_removename(&args, &count, &totallen); + if (retval == 0) { + newsize = XFS_DIR_SF_ALLFIT(count, totallen); + if (newsize <= XFS_IFORK_DSIZE(dp)) { + retval = xfs_dir_leaf_to_shortform(&args); + } + } + } else { + retval = xfs_dir_node_removename(&args); + } + return(retval); +} + +static int /* error */ +xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, + xfs_ino_t *inum) +{ + xfs_da_args_t args; + int retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return(XFS_ERROR(EINVAL)); + } + + XFS_STATS_INC(xfsstats.xs_dir_lookup); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = 0; + args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_lookup(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_lookup(&args); + } else { + retval = xfs_dir_node_lookup(&args); + } + if (retval == EEXIST) + retval = 0; + *inum = args.inumber; + return(retval); +} + +/* + * Implement readdir. + */ +static int /* error */ +xfs_dir_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp) +{ + xfs_dirent_t *dbp; + int alignment, retval; + xfs_dir_put_t put; + + XFS_STATS_INC(xfsstats.xs_dir_getdents); + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + + /* + * If our caller has given us a single contiguous memory buffer, + * just work directly within that buffer. If it's in user memory, + * lock it down first. + */ + alignment = sizeof(xfs_off_t) - 1; + if ((uio->uio_iovcnt == 1) && + (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && + ((uio->uio_iov[0].iov_len & alignment) == 0)) { + dbp = NULL; + put = xfs_dir_put_dirent64_direct; + } else { + dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); + put = xfs_dir_put_dirent64_uio; + } + + /* + * Decide on what work routines to call based on the inode size. + */ + *eofp = 0; + + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_getdents(dp, uio, eofp, dbp, put); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_getdents(trans, dp, uio, eofp, dbp, put); + } else { + retval = xfs_dir_node_getdents(trans, dp, uio, eofp, dbp, put); + } + if (dbp != NULL) + kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); + + return(retval); +} + +static int /* error */ +xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, + xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return(XFS_ERROR(EINVAL)); + } + + if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) + return retval; + + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 0; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_replace(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_replace(&args); + } else { + retval = xfs_dir_node_replace(&args); + } + + return(retval); +} + +static int +xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp) +{ + xfs_ino_t ino; + int namelen_sum; + int count; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i; + + + + if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & IFMT) != IFDIR) { + return 0; + } + if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) { + return 0; + } + if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) { + xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p", + dp); + return 1; + } + sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf); + ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT); + if (xfs_dir_ino_validate(mp, ino)) + return 1; + + count = sf->hdr.count; + if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid shortform count: dp 0x%p", dp); + return(1); + } + + if (count == 0) { + return 0; + } + + namelen_sum = 0; + sfe = &sf->list[0]; + for (i = sf->hdr.count - 1; i >= 0; i--) { + ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT); + xfs_dir_ino_validate(mp, ino); + if (sfe->namelen >= XFS_LITINO(mp)) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid shortform namelen: dp 0x%p", dp); + return 1; + } + namelen_sum += sfe->namelen; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + if (namelen_sum >= XFS_LITINO(mp)) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid shortform namelen: dp 0x%p", dp); + return 1; + } + + return 0; +} + +/*======================================================================== + * External routines when dirsize == XFS_LBSIZE(dp->i_mount). + *========================================================================*/ + +/* + * Add a name to the leaf directory structure + * This is the external routine. + */ +int +xfs_dir_leaf_addname(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == ENOENT) + retval = xfs_dir_leaf_add(bp, args, index); + xfs_da_buf_done(bp); + return(retval); +} + +/* + * Remove a name from the leaf directory structure + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen) +{ + xfs_dir_leafblock_t *leaf; + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == EEXIST) { + (void)xfs_dir_leaf_remove(args->trans, bp, index); + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + *totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + retval = 0; + } + xfs_da_buf_done(bp); + return(retval); +} + +/* + * Look up a name in a leaf directory structure. + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_lookup(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + xfs_da_brelse(args->trans, bp); + return(retval); +} + +/* + * Copy out directory entries for getdents(), for leaf directories. + */ +STATIC int +xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, + int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) +{ + xfs_dabuf_t *bp; + int retval, eob; + + retval = xfs_da_read_buf(dp->i_transp, dp, 0, -1, &bp, XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_getdents_int(bp, dp, 0, uio, &eob, dbp, put, -1); + xfs_da_brelse(trans, bp); + *eofp = (eob == 0); + return(retval); +} + +/* + * Look up a name in a leaf directory structure, replace the inode number. + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_replace(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + xfs_ino_t inum; + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + + inum = args->inumber; + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == EEXIST) { + leaf = bp->data; + entry = &leaf->entries[index]; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + /* XXX - replace assert? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); + xfs_da_buf_done(bp); + retval = 0; + } else + xfs_da_brelse(args->trans, bp); + return(retval); +} + + +/*======================================================================== + * External routines when dirsize > XFS_LBSIZE(mp). + *========================================================================*/ + +/* + * Add a name to a Btree-format directory. + * + * This will involve walking down the Btree, and may involve splitting + * leaf nodes and even splitting intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_dir_node_addname(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int retval, error; + + /* + * Fill in bucket of arguments/results/context to carry around. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name already exists, and get back a pointer + * to where it should go. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + retval = error; + if (retval != ENOENT) + goto error; + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_add(blk->bp, args, blk->index); + if (retval == 0) { + /* + * Addition succeeded, update Btree hashvals. + */ + if (!args->justcheck) + xfs_da_fixhashpath(state, &state->path); + } else { + /* + * Addition failed, split as many Btree elements as required. + */ + if (args->total == 0) { + ASSERT(retval == ENOSPC); + goto error; + } + retval = xfs_da_split(state); + } +error: + xfs_da_state_free(state); + + return(retval); +} + +/* + * Remove a name from a B-tree directory. + * + * This will involve walking down the Btree, and may involve joining + * leaf nodes and even joining intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_dir_node_removename(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int retval, error; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + retval = error; + if (retval != EEXIST) { + xfs_da_state_free(state); + return(retval); + } + + /* + * Remove the name and update the hashvals in the tree. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_remove(args->trans, blk->bp, blk->index); + xfs_da_fixhashpath(state, &state->path); + + /* + * Check to see if the tree needs to be collapsed. + */ + error = 0; + if (retval) { + error = xfs_da_join(state); + } + + xfs_da_state_free(state); + if (error) + return(error); + return(0); +} + +/* + * Look up a filename in a int directory. + * Use an internal routine to actually do all the work. + */ +STATIC int +xfs_dir_node_lookup(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + int retval, error, i; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, + * and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } + + /* + * If not in a transaction, we have to release all the buffers. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} + +STATIC int +xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, + int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dir_leafblock_t *leaf = NULL; + xfs_dablk_t bno, nextbno; + xfs_dahash_t cookhash; + xfs_mount_t *mp; + int error, eob, i; + xfs_dabuf_t *bp; + xfs_daddr_t nextda; + + /* + * Pick up our context. + */ + mp = dp->i_mount; + bp = NULL; + bno = XFS_DA_COOKIE_BNO(mp, uio->uio_offset); + cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); + + xfs_dir_trace_g_du("node: start", dp, uio); + + /* + * Re-find our place, even if we're confused about what our place is. + * + * First we check the block number from the magic cookie, it is a + * cache of where we ended last time. If we find a leaf block, and + * the starting hashval in that block is less than our desired + * hashval, then we run with it. + */ + if (bno > 0) { + error = xfs_da_read_buf(trans, dp, bno, -1, &bp, XFS_DATA_FORK); + if ((error != 0) && (error != EFSCORRUPTED)) + return(error); + if (bp) + leaf = bp->data; + if (bp && INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + xfs_dir_trace_g_dub("node: block not a leaf", + dp, uio, bno); + xfs_da_brelse(trans, bp); + bp = NULL; + } + if (bp && INT_GET(leaf->entries[0].hashval, ARCH_CONVERT) > cookhash) { + xfs_dir_trace_g_dub("node: leaf hash too large", + dp, uio, bno); + xfs_da_brelse(trans, bp); + bp = NULL; + } + if (bp && + cookhash > INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)) { + xfs_dir_trace_g_dub("node: leaf hash too small", + dp, uio, bno); + xfs_da_brelse(trans, bp); + bp = NULL; + } + } + + /* + * If we did not find a leaf block from the blockno in the cookie, + * or we there was no blockno in the cookie (eg: first time thru), + * the we start at the top of the Btree and re-find our hashval. + */ + if (bp == NULL) { + xfs_dir_trace_g_du("node: start at root" , dp, uio); + bno = 0; + for (;;) { + error = xfs_da_read_buf(trans, dp, bno, -1, &bp, + XFS_DATA_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + node = bp->data; + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) + break; + btree = &node->btree[0]; + xfs_dir_trace_g_dun("node: node detail", dp, uio, node); + for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); btree++, i++) { + if (INT_GET(btree->hashval, ARCH_CONVERT) >= cookhash) { + bno = INT_GET(btree->before, ARCH_CONVERT); + break; + } + } + if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) { + xfs_da_brelse(trans, bp); + xfs_dir_trace_g_du("node: hash beyond EOF", + dp, uio); + uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, + XFS_DA_MAXHASH); + *eofp = 1; + return(0); + } + xfs_dir_trace_g_dub("node: going to block", + dp, uio, bno); + xfs_da_brelse(trans, bp); + } + } + ASSERT(cookhash != XFS_DA_MAXHASH); + + /* + * We've dropped down to the (first) leaf block that contains the + * hashval we are interested in. Continue rolling upward thru the + * leaf blocks until we fill up our buffer. + */ + for (;;) { + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + xfs_dir_trace_g_dul("node: not a leaf", dp, uio, leaf); + xfs_da_brelse(trans, bp); + return XFS_ERROR(EFSCORRUPTED); + } + xfs_dir_trace_g_dul("node: leaf detail", dp, uio, leaf); + if ((nextbno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT))) { + nextda = xfs_da_reada_buf(trans, dp, nextbno, + XFS_DATA_FORK); + } else + nextda = -1; + error = xfs_dir_leaf_getdents_int(bp, dp, bno, uio, &eob, dbp, + put, nextda); + xfs_da_brelse(trans, bp); + bno = nextbno; + if (eob) { + xfs_dir_trace_g_dub("node: E-O-B", dp, uio, bno); + *eofp = 0; + return(error); + } + if (bno == 0) + break; + error = xfs_da_read_buf(trans, dp, bno, nextda, &bp, + XFS_DATA_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + } + *eofp = 1; + xfs_dir_trace_g_du("node: E-O-F", dp, uio); + return(0); +} + +/* + * Look up a filename in an int directory, replace the inode number. + * Use an internal routine to actually do the lookup. + */ +STATIC int +xfs_dir_node_replace(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_ino_t inum; + int retval, error, i; + xfs_dabuf_t *bp; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + inum = args->inumber; + + /* + * Search to see if name exists, + * and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } + + if (retval == EEXIST) { + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + bp = blk->bp; + leaf = bp->data; + entry = &leaf->entries[blk->index]; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + /* XXX - replace assert ? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); + xfs_da_buf_done(bp); + blk->bp = NULL; + retval = 0; + } else { + i = state->path.active - 1; + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + for (i = 0; i < state->path.active - 1; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} + +#if defined(XFS_DIR_TRACE) +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_du(char *where, xfs_inode_t *dp, uio_t *uio) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DU, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_dub(char *where, xfs_inode_t *dp, uio_t *uio, xfs_dablk_t bno) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUB, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)bno, + NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_dun(char *where, xfs_inode_t *dp, uio_t *uio, + xfs_da_intnode_t *node) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUN, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)INT_GET(node->hdr.info.forw, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[INT_GET(node->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT), + NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_dul(char *where, xfs_inode_t *dp, uio_t *uio, + xfs_dir_leafblock_t *leaf) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUL, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)INT_GET(leaf->hdr.info.forw, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT), + NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_due(char *where, xfs_inode_t *dp, uio_t *uio, + xfs_dir_leaf_entry_t *entry) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUE, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)INT_GET(entry->hashval, ARCH_CONVERT), + NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_duc(char *where, xfs_inode_t *dp, uio_t *uio, xfs_off_t cookie) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUC, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)(cookie >> 32), + (__psunsigned_t)(cookie & 0xFFFFFFFF), + NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for the arguments given to the routine, + * generic form. + */ +void +xfs_dir_trace_enter(int type, char *where, + __psunsigned_t a0, __psunsigned_t a1, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11) +{ + ASSERT(xfs_dir_trace_buf); + ktrace_enter(xfs_dir_trace_buf, (void *)((__psunsigned_t)type), + (void *)where, + (void *)a0, (void *)a1, (void *)a2, + (void *)a3, (void *)a4, (void *)a5, + (void *)a6, (void *)a7, (void *)a8, + (void *)a9, (void *)a10, (void *)a11, + NULL, NULL); +} +#endif /* XFS_DIR_TRACE */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir.h --- linux-2.4.19/fs/xfs/xfs_dir.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_H__ +#define __XFS_DIR_H__ + +/* + * Large directories are structured around Btrees where all the data + * elements are in the leaf nodes. Filenames are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of a filename may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + * + * Small directories use a different format and are packed as tightly + * as possible so as to fit into the literal area of the inode. + */ + +#ifdef XFS_ALL_TRACE +#define XFS_DIR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_DIR_TRACE +#endif + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +struct uio; +struct xfs_bmap_free; +struct xfs_da_args; +struct xfs_dinode; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Directory function types. + * Put in structures (xfs_dirops_t) for v1 and v2 directories. + */ +typedef void (*xfs_dir_mount_t)(struct xfs_mount *mp); +typedef int (*xfs_dir_isempty_t)(struct xfs_inode *dp); +typedef int (*xfs_dir_init_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + struct xfs_inode *pdp); +typedef int (*xfs_dir_createname_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t inum, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_lookup_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t *inum); +typedef int (*xfs_dir_removename_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t ino, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_getdents_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + struct uio *uio, + int *eofp); +typedef int (*xfs_dir_replace_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t inum, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_canenter_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen); +typedef int (*xfs_dir_shortform_validate_ondisk_t)(struct xfs_mount *mp, + struct xfs_dinode *dip); +typedef int (*xfs_dir_shortform_to_single_t)(struct xfs_da_args *args); + +typedef struct xfs_dirops { + xfs_dir_mount_t xd_mount; + xfs_dir_isempty_t xd_isempty; + xfs_dir_init_t xd_init; + xfs_dir_createname_t xd_createname; + xfs_dir_lookup_t xd_lookup; + xfs_dir_removename_t xd_removename; + xfs_dir_getdents_t xd_getdents; + xfs_dir_replace_t xd_replace; + xfs_dir_canenter_t xd_canenter; + xfs_dir_shortform_validate_ondisk_t xd_shortform_validate_ondisk; + xfs_dir_shortform_to_single_t xd_shortform_to_single; +} xfs_dirops_t; + +/* + * Overall external interface routines. + */ +void xfs_dir_startup(void); /* called exactly once */ + +#define XFS_DIR_MOUNT(mp) \ + ((mp)->m_dirops.xd_mount(mp)) +#define XFS_DIR_ISEMPTY(mp,dp) \ + ((mp)->m_dirops.xd_isempty(dp)) +#define XFS_DIR_INIT(mp,tp,dp,pdp) \ + ((mp)->m_dirops.xd_init(tp,dp,pdp)) +#define XFS_DIR_CREATENAME(mp,tp,dp,name,namelen,inum,first,flist,total) \ + ((mp)->m_dirops.xd_createname(tp,dp,name,namelen,inum,first,flist,\ + total)) +#define XFS_DIR_LOOKUP(mp,tp,dp,name,namelen,inum) \ + ((mp)->m_dirops.xd_lookup(tp,dp,name,namelen,inum)) +#define XFS_DIR_REMOVENAME(mp,tp,dp,name,namelen,ino,first,flist,total) \ + ((mp)->m_dirops.xd_removename(tp,dp,name,namelen,ino,first,flist,total)) +#define XFS_DIR_GETDENTS(mp,tp,dp,uio,eofp) \ + ((mp)->m_dirops.xd_getdents(tp,dp,uio,eofp)) +#define XFS_DIR_REPLACE(mp,tp,dp,name,namelen,inum,first,flist,total) \ + ((mp)->m_dirops.xd_replace(tp,dp,name,namelen,inum,first,flist,total)) +#define XFS_DIR_CANENTER(mp,tp,dp,name,namelen) \ + ((mp)->m_dirops.xd_canenter(tp,dp,name,namelen)) +#define XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp,dip) \ + ((mp)->m_dirops.xd_shortform_validate_ondisk(mp,dip)) +#define XFS_DIR_SHORTFORM_TO_SINGLE(mp,args) \ + ((mp)->m_dirops.xd_shortform_to_single(args)) + +#define XFS_DIR_IS_V1(mp) ((mp)->m_dirversion == 1) +extern xfs_dirops_t xfsv1_dirops; + +#endif /* __XFS_DIR_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2.c --- linux-2.4.19/fs/xfs/xfs_dir2.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,830 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS v2 directory implmentation. + * Top-level and utility routines. + */ + +#include + +/* + * Declarations for interface routines. + */ +static void xfs_dir2_mount(xfs_mount_t *mp); +static int xfs_dir2_isempty(xfs_inode_t *dp); +static int xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp, + xfs_inode_t *pdp); +static int xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp, + char *name, int namelen, xfs_ino_t inum, + xfs_fsblock_t *first, + xfs_bmap_free_t *flist, xfs_extlen_t total); +static int xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t *inum); +static int xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp, + char *name, int namelen, xfs_ino_t ino, + xfs_fsblock_t *first, + xfs_bmap_free_t *flist, xfs_extlen_t total); +static int xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio, + int *eofp); +static int xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t inum, + xfs_fsblock_t *first, xfs_bmap_free_t *flist, + xfs_extlen_t total); +static int xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen); +static int xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp, + xfs_dinode_t *dip); + +/* + * Utility routine declarations. + */ +static int xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa); +static int xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa); + +/* + * Directory operations vector. + */ +xfs_dirops_t xfsv2_dirops = { + .xd_mount = xfs_dir2_mount, + .xd_isempty = xfs_dir2_isempty, + .xd_init = xfs_dir2_init, + .xd_createname = xfs_dir2_createname, + .xd_lookup = xfs_dir2_lookup, + .xd_removename = xfs_dir2_removename, + .xd_getdents = xfs_dir2_getdents, + .xd_replace = xfs_dir2_replace, + .xd_canenter = xfs_dir2_canenter, + .xd_shortform_validate_ondisk = xfs_dir2_shortform_validate_ondisk, + .xd_shortform_to_single = xfs_dir2_sf_to_block, +}; + +/* + * Interface routines. + */ + +/* + * Initialize directory-related fields in the mount structure. + */ +static void +xfs_dir2_mount( + xfs_mount_t *mp) /* filesystem mount point */ +{ + mp->m_dirversion = 2; + ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= + XFS_MAX_BLOCKSIZE); + mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog); + mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog; + mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp)); + mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp)); + mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp)); + mp->m_da_node_ents = + (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / + (uint)sizeof(xfs_da_node_entry_t); + mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; +} + +/* + * Return 1 if directory contains only "." and "..". + */ +static int /* return code */ +xfs_dir2_isempty( + xfs_inode_t *dp) /* incore inode structure */ +{ + xfs_dir2_sf_t *sfp; /* shortform directory structure */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + /* + * Might happen during shutdown. + */ + if (dp->i_d.di_size == 0) { + return 1; + } + if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) + return 0; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + return INT_ISZERO(sfp->hdr.count, ARCH_CONVERT); +} + +/* + * Initialize a directory with its "." and ".." entries. + */ +static int /* error */ +xfs_dir2_init( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + xfs_inode_t *pdp) /* incore parent directory inode */ +{ + xfs_da_args_t args; /* operation arguments */ + int error; /* error return value */ + + bzero((char *)&args, sizeof(args)); + args.dp = dp; + args.trans = tp; + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) { + return error; + } + return xfs_dir2_sf_create(&args, pdp->i_ino); +} + +/* + Enter a name in a directory. + */ +static int /* error */ +xfs_dir2_createname( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* new entry name */ + int namelen, /* new entry name length */ + xfs_ino_t inum, /* new entry inode number */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { + return rval; + } + XFS_STATS_INC(xfsstats.xs_dir_create); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = 0; + args.addname = args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_addname(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_addname(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_addname(&args); + else + rval = xfs_dir2_node_addname(&args); + return rval; +} + +/* + * Lookup a name in a directory, give back the inode number. + */ +static int /* error */ +xfs_dir2_lookup( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* lookup name */ + int namelen, /* lookup name length */ + xfs_ino_t *inum) /* out: inode number */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return XFS_ERROR(EINVAL); + } + XFS_STATS_INC(xfsstats.xs_dir_lookup); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = 0; + args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_lookup(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_lookup(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_lookup(&args); + else + rval = xfs_dir2_node_lookup(&args); + if (rval == EEXIST) + rval = 0; + if (rval == 0) + *inum = args.inumber; + return rval; +} + +/* + * Remove an entry from a directory. + */ +static int /* error */ +xfs_dir2_removename( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to remove */ + int namelen, /* name length of entry to remove */ + xfs_ino_t ino, /* inode number of entry to remove */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_remove); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = ino; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_removename(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_removename(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_removename(&args); + else + rval = xfs_dir2_node_removename(&args); + return rval; +} + +/* + * Read a directory. + */ +static int /* error */ +xfs_dir2_getdents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + uio_t *uio, /* caller's buffer control */ + int *eofp) /* out: eof reached */ +{ + int alignment; /* alignment required for ABI */ + xfs_dirent_t *dbp; /* malloc'ed buffer */ + xfs_dir2_put_t put; /* entry formatting routine */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_getdents); + /* + * If our caller has given us a single contiguous aligned memory buffer, + * just work directly within that buffer. If it's in user memory, + * lock it down first. + */ + alignment = sizeof(xfs_off_t) - 1; + if ((uio->uio_iovcnt == 1) && + (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && + ((uio->uio_iov[0].iov_len & alignment) == 0)) { + dbp = NULL; + put = xfs_dir2_put_dirent64_direct; + } else { + dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); + put = xfs_dir2_put_dirent64_uio; + } + + *eofp = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + ; + } else if (v) + rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put); + else + rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put); + if (dbp != NULL) + kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); + return rval; +} + +/* + * Replace the inode number of a directory entry. + */ +static int /* error */ +xfs_dir2_replace( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to replace */ + int namelen, /* name length of entry to replace */ + xfs_ino_t inum, /* new inode number */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return XFS_ERROR(EINVAL); + } + if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { + return rval; + } + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_replace(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_replace(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_replace(&args); + else + rval = xfs_dir2_node_replace(&args); + return rval; +} + +/* + * See if this entry can be added to the directory without allocating space. + */ +static int /* error */ +xfs_dir2_canenter( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to add */ + int namelen) /* name length of entry to add */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_addname(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_addname(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_addname(&args); + else + rval = xfs_dir2_node_addname(&args); + return rval; +} + +/* + * Dummy routine for shortform inode validation. + * Can't really do this. + */ +/* ARGSUSED */ +static int /* error */ +xfs_dir2_shortform_validate_ondisk( + xfs_mount_t *mp, /* filesystem mount point */ + xfs_dinode_t *dip) /* ondisk inode */ +{ + return 0; +} + +/* + * Utility routines. + */ + +/* + * Add a block to the directory. + * This routine is for data and free blocks, not leaf/node blocks + * which are handled by xfs_da_grow_inode. + */ +int /* error */ +xfs_dir2_grow_inode( + xfs_da_args_t *args, /* operation arguments */ + int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ + xfs_dir2_db_t *dbp) /* out: block number added */ +{ + xfs_fileoff_t bno; /* directory offset of new block */ + int count; /* count of filesystem blocks */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int got; /* blocks actually mapped */ + int i; /* temp mapping index */ + xfs_bmbt_irec_t map; /* single structure for bmap */ + int mapi; /* mapping index */ + xfs_bmbt_irec_t *mapp; /* bmap mapping structure(s) */ + xfs_mount_t *mp; /* filesystem mount point */ + int nmap; /* number of bmap entries */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_s("grow_inode", args, space); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Set lowest possible block in the space requested. + */ + bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); + count = mp->m_dirblkfsbs; + /* + * Find the first hole for our block. + */ + if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) { + return error; + } + nmap = 1; + ASSERT(args->firstblock != NULL); + /* + * Try mapping the new block contiguously (one extent). + */ + if ((error = xfs_bmapi(tp, dp, bno, count, + XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, + args->firstblock, args->total, &map, &nmap, + args->flist))) { + return error; + } + ASSERT(nmap <= 1); + /* + * Got it in 1. + */ + if (nmap == 1) { + mapp = ↦ + mapi = 1; + } + /* + * Didn't work and this is a multiple-fsb directory block. + * Try again with contiguous flag turned on. + */ + else if (nmap == 0 && count > 1) { + xfs_fileoff_t b; /* current file offset */ + + /* + * Space for maximum number of mappings. + */ + mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); + /* + * Iterate until we get to the end of our block. + */ + for (b = bno, mapi = 0; b < bno + count; ) { + int c; /* current fsb count */ + + /* + * Can't map more than MAX_NMAP at once. + */ + nmap = MIN(XFS_BMAP_MAX_NMAP, count); + c = (int)(bno + count - b); + if ((error = xfs_bmapi(tp, dp, b, c, + XFS_BMAPI_WRITE|XFS_BMAPI_METADATA, + args->firstblock, args->total, + &mapp[mapi], &nmap, args->flist))) { + kmem_free(mapp, sizeof(*mapp) * count); + return error; + } + if (nmap < 1) + break; + /* + * Add this bunch into our table, go to the next offset. + */ + mapi += nmap; + b = mapp[mapi - 1].br_startoff + + mapp[mapi - 1].br_blockcount; + } + } + /* + * Didn't work. + */ + else { + mapi = 0; + mapp = NULL; + } + /* + * See how many fsb's we got. + */ + for (i = 0, got = 0; i < mapi; i++) + got += mapp[i].br_blockcount; + /* + * Didn't get enough fsb's, or the first/last block's are wrong. + */ + if (got != count || mapp[0].br_startoff != bno || + mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != + bno + count) { + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + return XFS_ERROR(ENOSPC); + } + /* + * Done with the temporary mapping table. + */ + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + *dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno); + /* + * Update file's size if this is the data space and it grew. + */ + if (space == XFS_DIR2_DATA_SPACE) { + xfs_fsize_t size; /* directory file (data) size */ + + size = XFS_FSB_TO_B(mp, bno + count); + if (size > dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +} + +/* + * See if the directory is a single-block form directory. + */ +int /* error */ +xfs_dir2_isblock( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + int *vp) /* out: 1 is block, 0 is not block */ +{ + xfs_fileoff_t last; /* last file offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* return value */ + + mp = dp->i_mount; + if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { + return rval; + } + rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize; + ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize); + *vp = rval; + return 0; +} + +/* + * See if the directory is a single-leaf form directory. + */ +int /* error */ +xfs_dir2_isleaf( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + int *vp) /* out: 1 is leaf, 0 is not leaf */ +{ + xfs_fileoff_t last; /* last file offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* return value */ + + mp = dp->i_mount; + if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { + return rval; + } + *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog); + return 0; +} + +/* + * Getdents put routine for 64-bit ABI, direct form. + */ +static int /* error */ +xfs_dir2_put_dirent64_direct( + xfs_dir2_put_args_t *pa) /* argument bundle */ +{ + xfs_dirent_t *idbp; /* dirent pointer */ + iovec_t *iovp; /* io vector */ + int namelen; /* entry name length */ + int reclen; /* entry total length */ + uio_t *uio; /* I/O control */ + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + /* + * Won't fit in the remaining space. + */ + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + iovp = uio->uio_iov; + idbp = (xfs_dirent_t *)iovp->iov_base; + iovp->iov_base = (char *)idbp + reclen; + iovp->iov_len -= reclen; + uio->uio_resid -= reclen; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook; + idbp->d_name[namelen] = '\0'; + pa->done = 1; + bcopy(pa->name, idbp->d_name, namelen); + return 0; +} + +/* + * Getdents put routine for 64-bit ABI, uio form. + */ +static int /* error */ +xfs_dir2_put_dirent64_uio( + xfs_dir2_put_args_t *pa) /* argument bundle */ +{ + xfs_dirent_t *idbp; /* dirent pointer */ + int namelen; /* entry name length */ + int reclen; /* entry total length */ + int rval; /* return value */ + uio_t *uio; /* I/O control */ + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + /* + * Won't fit in the remaining space. + */ + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + idbp = pa->dbp; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook; + idbp->d_name[namelen] = '\0'; + bcopy(pa->name, idbp->d_name, namelen); + rval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio); + pa->done = (rval == 0); + return rval; +} + +/* + * Remove the given block from the directory. + * This routine is used for data and free blocks, leaf/node are done + * by xfs_da_shrink_inode. + */ +int +xfs_dir2_shrink_inode( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_db_t db, /* directory block number */ + xfs_dabuf_t *bp) /* block's buffer */ +{ + xfs_fileoff_t bno; /* directory file offset */ + xfs_dablk_t da; /* directory file offset */ + int done; /* bunmap is finished */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_db("shrink_inode", args, db, bp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + da = XFS_DIR2_DB_TO_DA(mp, db); + /* + * Unmap the fsblock(s). + */ + if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs, + XFS_BMAPI_METADATA, 0, args->firstblock, args->flist, + &done))) { + /* + * ENOSPC actually can happen if we're in a removename with + * no space reservation, and the resulting block removal + * would cause a bmap btree split or conversion from extents + * to btree. This can only happen for un-fragmented + * directory blocks, since you need to be punching out + * the middle of an extent. + * In this case we need to leave the block in the file, + * and not binval it. + * So the block has to be in a consistent empty state + * and appropriately logged. + * We don't free up the buffer, the caller can tell it + * hasn't happened since it got an error back. + */ + return error; + } + ASSERT(done); + /* + * Invalidate the buffer from the transaction. + */ + xfs_da_binval(tp, bp); + /* + * If it's not a data block, we're done. + */ + if (db >= XFS_DIR2_LEAF_FIRSTDB(mp)) + return 0; + /* + * If the block isn't the last one in the directory, we're done. + */ + if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0)) + return 0; + bno = da; + if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { + /* + * This can't really happen unless there's kernel corruption. + */ + return error; + } + if (db == mp->m_dirdatablk) + ASSERT(bno == 0); + else + ASSERT(bno > 0); + /* + * Set the size to the new last block. + */ + dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dir2.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2.h --- linux-2.4.19/fs/xfs/xfs_dir2.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_H__ +#define __XFS_DIR2_H__ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_put_args; +struct xfs_inode; +struct xfs_trans; + +/* + * Directory version 2. + * There are 4 possible formats: + * shortform + * single block - data with embedded leaf at the end + * multiple data blocks, single leaf+freeindex block + * data blocks, node&leaf blocks (btree), freeindex blocks + * + * The shortform format is in xfs_dir2_sf.h. + * The single block format is in xfs_dir2_block.h. + * The data block format is in xfs_dir2_data.h. + * The leaf and freeindex block formats are in xfs_dir2_leaf.h. + * Node blocks are the same as the other version, in xfs_da_btree.h. + */ + +/* + * Byte offset in data block and shortform entry. + */ +typedef __uint16_t xfs_dir2_data_off_t; +#define NULLDATAOFF 0xffffU +typedef uint xfs_dir2_data_aoff_t; /* argument form */ + +/* + * Directory block number (logical dirblk in file) + */ +typedef __uint32_t xfs_dir2_db_t; + +/* + * Byte offset in a directory. + */ +typedef xfs_off_t xfs_dir2_off_t; + +/* + * For getdents, argument struct for put routines. + */ +typedef int (*xfs_dir2_put_t)(struct xfs_dir2_put_args *pa); +typedef struct xfs_dir2_put_args { + xfs_off_t cook; /* cookie of (next) entry */ + xfs_intino_t ino; /* inode number */ + struct xfs_dirent *dbp; /* buffer pointer */ + char *name; /* directory entry name */ + int namelen; /* length of name */ + int done; /* output: set if value was stored */ + xfs_dir2_put_t put; /* put function ptr (i/o) */ + struct uio *uio; /* uio control structure */ +} xfs_dir2_put_args_t; + +#define XFS_DIR_IS_V2(mp) ((mp)->m_dirversion == 2) +extern xfs_dirops_t xfsv2_dirops; + +/* + * Other interfaces used by the rest of the dir v2 code. + */ +extern int + xfs_dir2_grow_inode(struct xfs_da_args *args, int space, + xfs_dir2_db_t *dbp); + +extern int + xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp, int *vp); + +extern int + xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *vp); + +extern int + xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, + struct xfs_dabuf *bp); + +#endif /* __XFS_DIR2_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_block.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_block.c --- linux-2.4.19/fs/xfs/xfs_dir2_block.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_block.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,1231 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_block.c + * XFS V2 directory implementation, single-block form. + * See xfs_dir2_block.h for the format. + */ + +#include + + +/* + * Local function prototypes. + */ +static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, xfs_dabuf_t *bp, int first, + int last); +static void xfs_dir2_block_log_tail(xfs_trans_t *tp, xfs_dabuf_t *bp); +static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **bpp, + int *entno); +static int xfs_dir2_block_sort(const void *a, const void *b); + +/* + * Add an entry to a block directory. + */ +int /* error */ +xfs_dir2_block_addname( + xfs_da_args_t *args) /* directory op arguments */ +{ + xfs_dir2_data_free_t *bf; /* bestfree table in block */ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* buffer for block */ + xfs_dir2_block_tail_t *btp; /* block tail */ + int compact; /* need to compact leaf ents */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* directory inode */ + xfs_dir2_data_unused_t *dup; /* block unused entry */ + int error; /* error return value */ + xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */ + xfs_dahash_t hash; /* hash value of found entry */ + int high; /* high index for binary srch */ + int highstale; /* high stale index */ + int lfloghigh=0; /* last final leaf to log */ + int lfloglow=0; /* first final leaf to log */ + int len; /* length of the new entry */ + int low; /* low index for binary srch */ + int lowstale; /* low stale index */ + int mid=0; /* midpoint for binary srch */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log header */ + int needscan; /* need to rescan freespace */ + xfs_dir2_data_off_t *tagp; /* pointer to tag value */ + xfs_trans_t *tp; /* transaction structure */ + + xfs_dir2_trace_args("block_addname", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the (one and only) directory block into dabuf bp. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + block = bp->data; + /* + * Check the magic number, corrupted if wrong. + */ + if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) { + xfs_da_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + len = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * Set up pointers to parts of the block. + */ + bf = block->hdr.bestfree; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * No stale entries? Need space for entry and new leaf. + */ + if (INT_ISZERO(btp->stale, ARCH_CONVERT)) { + /* + * Tag just before the first leaf entry. + */ + tagp = (xfs_dir2_data_off_t *)blp - 1; + /* + * Data object just before the first leaf entry. + */ + enddup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free then can't do this add without cleaning up: + * the space before the first leaf entry needs to be free so it + * can be expanded to hold the pointer to the new entry. + */ + if (INT_GET(enddup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + dup = enddup = NULL; + /* + * Check out the biggest freespace and see if it's the same one. + */ + else { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); + if (dup == enddup) { + /* + * It is the biggest freespace, is it too small + * to hold the new leaf too? + */ + if (INT_GET(dup->length, ARCH_CONVERT) < len + (uint)sizeof(*blp)) { + /* + * Yes, we use the second-largest + * entry instead if it works. + */ + if (INT_GET(bf[1].length, ARCH_CONVERT) >= len) + dup = (xfs_dir2_data_unused_t *) + ((char *)block + + INT_GET(bf[1].offset, ARCH_CONVERT)); + else + dup = NULL; + } + } else { + /* + * Not the same free entry, + * just check its length. + */ + if (INT_GET(dup->length, ARCH_CONVERT) < len) { + dup = NULL; + } + } + } + compact = 0; + } + /* + * If there are stale entries we'll use one for the leaf. + * Is the biggest entry enough to avoid compaction? + */ + else if (INT_GET(bf[0].length, ARCH_CONVERT) >= len) { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); + compact = 0; + } + /* + * Will need to compact to make this work. + */ + else { + /* + * Tag just before the first leaf entry. + */ + tagp = (xfs_dir2_data_off_t *)blp - 1; + /* + * Data object just before the first leaf entry. + */ + dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free then the data will go where the + * leaf data starts now, if it works at all. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + if (INT_GET(dup->length, ARCH_CONVERT) + (INT_GET(btp->stale, ARCH_CONVERT) - 1) * + (uint)sizeof(*blp) < len) + dup = NULL; + } else if ((INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len) + dup = NULL; + else + dup = (xfs_dir2_data_unused_t *)blp; + compact = 1; + } + /* + * If this isn't a real add, we're done with the buffer. + */ + if (args->justcheck) + xfs_da_brelse(tp, bp); + /* + * If we don't have space for the new entry & leaf ... + */ + if (!dup) { + /* + * Not trying to actually do anything, or don't have + * a space reservation: return no-space. + */ + if (args->justcheck || args->total == 0) + return XFS_ERROR(ENOSPC); + /* + * Convert to the next larger format. + * Then add the new entry in that format. + */ + error = xfs_dir2_block_to_leaf(args, bp); + xfs_da_buf_done(bp); + if (error) + return error; + return xfs_dir2_leaf_addname(args); + } + /* + * Just checking, and it would work, so say so. + */ + if (args->justcheck) + return 0; + needlog = needscan = 0; + /* + * If need to compact the leaf entries, do it now. + * Leave the highest-numbered stale entry stale. + * XXX should be the one closest to mid but mid is not yet computed. + */ + if (compact) { + int fromidx; /* source leaf index */ + int toidx; /* target leaf index */ + + for (fromidx = toidx = INT_GET(btp->count, ARCH_CONVERT) - 1, + highstale = lfloghigh = -1; + fromidx >= 0; + fromidx--) { + if (INT_GET(blp[fromidx].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { + if (highstale == -1) + highstale = toidx; + else { + if (lfloghigh == -1) + lfloghigh = toidx; + continue; + } + } + if (fromidx < toidx) + blp[toidx] = blp[fromidx]; + toidx--; + } + lfloglow = toidx + 1 - (INT_GET(btp->stale, ARCH_CONVERT) - 1); + lfloghigh -= INT_GET(btp->stale, ARCH_CONVERT) - 1; + INT_MOD(btp->count, ARCH_CONVERT, -(INT_GET(btp->stale, ARCH_CONVERT) - 1)); + xfs_dir2_data_make_free(tp, bp, + (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), + (xfs_dir2_data_aoff_t)((INT_GET(btp->stale, ARCH_CONVERT) - 1) * sizeof(*blp)), + &needlog, &needscan); + blp += INT_GET(btp->stale, ARCH_CONVERT) - 1; + INT_SET(btp->stale, ARCH_CONVERT, 1); + /* + * If we now need to rebuild the bestfree map, do so. + * This needs to happen before the next call to use_free. + */ + if (needscan) { + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, + &needlog, NULL); + needscan = 0; + } + } + /* + * Set leaf logging boundaries to impossible state. + * For the no-stale case they're set explicitly. + */ + else if (INT_GET(btp->stale, ARCH_CONVERT)) { + lfloglow = INT_GET(btp->count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * Find the slot that's first lower than our hash value, -1 if none. + */ + for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; low <= high; ) { + mid = (low + high) >> 1; + if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval) + break; + if (hash < args->hashval) + low = mid + 1; + else + high = mid - 1; + } + while (mid >= 0 && INT_GET(blp[mid].hashval, ARCH_CONVERT) >= args->hashval) { + mid--; + } + /* + * No stale entries, will use enddup space to hold new leaf. + */ + if (INT_ISZERO(btp->stale, ARCH_CONVERT)) { + /* + * Mark the space needed for the new leaf entry, now in use. + */ + xfs_dir2_data_use_free(tp, bp, enddup, + (xfs_dir2_data_aoff_t) + ((char *)enddup - (char *)block + INT_GET(enddup->length, ARCH_CONVERT) - + sizeof(*blp)), + (xfs_dir2_data_aoff_t)sizeof(*blp), + &needlog, &needscan); + /* + * Update the tail (entry count). + */ + INT_MOD(btp->count, ARCH_CONVERT, +1); + /* + * If we now need to rebuild the bestfree map, do so. + * This needs to happen before the next call to use_free. + */ + if (needscan) { + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, + &needlog, NULL); + needscan = 0; + } + /* + * Adjust pointer to the first leaf entry, we're about to move + * the table up one to open up space for the new leaf entry. + * Then adjust our index to match. + */ + blp--; + mid++; + if (mid) + ovbcopy(&blp[1], blp, mid * sizeof(*blp)); + lfloglow = 0; + lfloghigh = mid; + } + /* + * Use a stale leaf for our new entry. + */ + else { + for (lowstale = mid; + lowstale >= 0 && + INT_GET(blp[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + for (highstale = mid + 1; + highstale < INT_GET(btp->count, ARCH_CONVERT) && + INT_GET(blp[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || mid - lowstale > highstale - mid); + highstale++) + continue; + /* + * Move entries toward the low-numbered stale entry. + */ + if (lowstale >= 0 && + (highstale == INT_GET(btp->count, ARCH_CONVERT) || + mid - lowstale <= highstale - mid)) { + if (mid - lowstale) + ovbcopy(&blp[lowstale + 1], &blp[lowstale], + (mid - lowstale) * sizeof(*blp)); + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(mid, lfloghigh); + } + /* + * Move entries toward the high-numbered stale entry. + */ + else { + ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT)); + mid++; + if (highstale - mid) + ovbcopy(&blp[mid], &blp[mid + 1], + (highstale - mid) * sizeof(*blp)); + lfloglow = MIN(mid, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(btp->stale, ARCH_CONVERT, -1); + } + /* + * Point to the new data entry. + */ + dep = (xfs_dir2_data_entry_t *)dup; + /* + * Fill in the leaf entry. + */ + INT_SET(blp[mid].hashval, ARCH_CONVERT, args->hashval); + INT_SET(blp[mid].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); + /* + * Mark space for the data entry used. + */ + xfs_dir2_data_use_free(tp, bp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)block), + (xfs_dir2_data_aoff_t)len, &needlog, &needscan); + /* + * Create the new data entry. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, args->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + /* + * Clean up the bestfree array and log the header, tail, and entry. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_block_log_tail(tp, bp); + xfs_dir2_data_log_entry(tp, bp, dep); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} + +/* + * Readdir for block directories. + */ +int /* error */ +xfs_dir2_block_getdents( + xfs_trans_t *tp, /* transaction (NULL) */ + xfs_inode_t *dp, /* incore inode */ + uio_t *uio, /* caller's buffer control */ + int *eofp, /* eof reached? (out) */ + xfs_dirent_t *dbp, /* caller's buffer */ + xfs_dir2_put_t put) /* abi's formatting function */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dabuf_t *bp; /* buffer for block */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_dir2_data_unused_t *dup; /* block unused entry */ + char *endptr; /* end of the data entries */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_put_args_t p; /* arg package for put rtn */ + char *ptr; /* current data entry */ + char *savptr; /* saved data entry */ + int wantoff; /* starting block offset */ + + mp = dp->i_mount; + /* + * If the block number in the offset is out of range, we're done. + */ + if (XFS_DIR2_DATAPTR_TO_DB(mp, uio->uio_offset) > mp->m_dirdatablk) { + *eofp = 1; + return 0; + } + /* + * Can't read the block, give up, else get dabuf in bp. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + /* + * Extract the byte offset we start at from the seek pointer. + * We'll skip entries before this. + */ + wantoff = XFS_DIR2_DATAPTR_TO_OFF(mp, uio->uio_offset); + block = bp->data; + xfs_dir2_data_check(dp, bp); + /* + * Set up values for the loop. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + ptr = (char *)block->u; + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + p.dbp = dbp; + p.put = put; + p.uio = uio; + /* + * Loop over the data portion of the block. + * Each object is a real entry (dep) or an unused one (dup). + */ + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + /* + * Unused, skip it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + + dep = (xfs_dir2_data_entry_t *)ptr; + + savptr = ptr; /* In case we need it.. */ + + /* + * Bump pointer for the next iteration. + */ + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + /* + * The entry is before the desired starting point, skip it. + */ + if ((char *)dep - (char *)block < wantoff) + continue; + /* + * Set up argument structure for put routine. + */ + p.namelen = dep->namelen; + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + savptr - (char *)block); +#if XFS_BIG_FILESYSTEMS + p.ino = INT_GET(dep->inumber, ARCH_CONVERT) + mp->m_inoadd; +#else + p.ino = INT_GET(dep->inumber, ARCH_CONVERT); +#endif + p.name = (char *)dep->name; + + /* + * Put the entry in the caller's buffer. + */ + error = p.put(&p); + + /* + * If it didn't fit, set the final offset to here & return. + */ + if (!p.done) { + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + (char *)dep - (char *)block); + xfs_da_brelse(tp, bp); + return error; + } + } + + /* + * Reached the end of the block. + * Set the offset to a nonexistent block 1 and return. + */ + *eofp = 1; + + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0); + + xfs_da_brelse(tp, bp); + + return 0; +} + +/* + * Log leaf entries from the block. + */ +static void +xfs_dir2_block_log_leaf( + xfs_trans_t *tp, /* transaction structure */ + xfs_dabuf_t *bp, /* block buffer */ + int first, /* index of first logged leaf */ + int last) /* index of last logged leaf */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block), + (uint)((char *)&blp[last + 1] - (char *)block - 1)); +} + +/* + * Log the block tail. + */ +static void +xfs_dir2_block_log_tail( + xfs_trans_t *tp, /* transaction structure */ + xfs_dabuf_t *bp) /* block buffer */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)block), + (uint)((char *)(btp + 1) - (char *)block - 1)); +} + +/* + * Look up an entry in the block. This is the external routine, + * xfs_dir2_block_lookup_int does the real work. + */ +int /* error */ +xfs_dir2_block_lookup( + xfs_da_args_t *args) /* dir lookup arguments */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + xfs_dir2_trace_args("block_lookup", args); + /* + * Get the buffer, look up the entry. + * If not found (ENOENT) then return, have no buffer. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) + return error; + dp = args->dp; + mp = dp->i_mount; + block = bp->data; + xfs_dir2_data_check(dp, bp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Get the offset from the leaf entry, to point to the data. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + /* + * Fill in inode number, release the block. + */ + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + xfs_da_brelse(args->trans, bp); + return XFS_ERROR(EEXIST); +} + +/* + * Internal block lookup routine. + */ +static int /* error */ +xfs_dir2_block_lookup_int( + xfs_da_args_t *args, /* dir lookup arguments */ + xfs_dabuf_t **bpp, /* returned block buffer */ + int *entno) /* returned entry number */ +{ + xfs_dir2_dataptr_t addr; /* data entry address */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int error; /* error return value */ + xfs_dahash_t hash; /* found hash value */ + int high; /* binary search high index */ + int low; /* binary search low index */ + int mid; /* binary search current idx */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the buffer, return error if we can't get it. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + block = bp->data; + xfs_dir2_data_check(dp, bp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Loop doing a binary search for our hash value. + * Find our entry, ENOENT if it's not there. + */ + for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; ; ) { + ASSERT(low <= high); + mid = (low + high) >> 1; + if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval) + break; + if (hash < args->hashval) + low = mid + 1; + else + high = mid - 1; + if (low > high) { + ASSERT(args->oknoent); + xfs_da_brelse(tp, bp); + return XFS_ERROR(ENOENT); + } + } + /* + * Back up to the first one with the right hash value. + */ + while (mid > 0 && INT_GET(blp[mid - 1].hashval, ARCH_CONVERT) == args->hashval) { + mid--; + } + /* + * Now loop forward through all the entries with the + * right hash value looking for our name. + */ + do { + if ((addr = INT_GET(blp[mid].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Get pointer to the entry from the leaf. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr)); + /* + * Compare, if it's right give back buffer & entry number. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + *bpp = bp; + *entno = mid; + return 0; + } + } while (++mid < INT_GET(btp->count, ARCH_CONVERT) && INT_GET(blp[mid].hashval, ARCH_CONVERT) == hash); + /* + * No match, release the buffer and return ENOENT. + */ + ASSERT(args->oknoent); + xfs_da_brelse(tp, bp); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a block format directory. + * If that makes the block small enough to fit in shortform, transform it. + */ +int /* error */ +xfs_dir2_block_removename( + xfs_da_args_t *args) /* directory operation args */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf pointer */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* block leaf entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to fixup bestfree */ + xfs_dir2_sf_hdr_t sfh; /* shortform header */ + int size; /* shortform size */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("block_removename", args); + /* + * Look up the entry in the block. Gets the buffer and entry index. + * It will always be there, the vnodeops level does a lookup first. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { + return error; + } + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Point to the data entry using the leaf entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + /* + * Mark the data entry's space free. + */ + needlog = needscan = 0; + xfs_dir2_data_make_free(tp, bp, + (xfs_dir2_data_aoff_t)((char *)dep - (char *)block), + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * Fix up the block tail. + */ + INT_MOD(btp->stale, ARCH_CONVERT, +1); + xfs_dir2_block_log_tail(tp, bp); + /* + * Remove the leaf entry by marking it stale. + */ + INT_SET(blp[ent].address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_block_log_leaf(tp, bp, ent, ent); + /* + * Fix up bestfree, log the header if necessary. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_data_check(dp, bp); + /* + * See if the size as a shortform is good enough. + */ + if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) > + XFS_IFORK_DSIZE(dp)) { + xfs_da_buf_done(bp); + return 0; + } + /* + * If it works, do the conversion. + */ + return xfs_dir2_block_to_sf(args, bp, size, &sfh); +} + +/* + * Replace an entry in a V2 block directory. + * Change the inode number to the new value. + */ +int /* error */ +xfs_dir2_block_replace( + xfs_da_args_t *args) /* directory operation args */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* leaf entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + xfs_dir2_trace_args("block_replace", args); + /* + * Lookup the entry in the directory. Get buffer and entry index. + * This will always succeed since the caller has already done a lookup. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { + return error; + } + dp = args->dp; + mp = dp->i_mount; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Point to the data entry we need to change. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber); + /* + * Change the inode number to the new value. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + xfs_dir2_data_log_entry(args->trans, bp, dep); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} + +/* + * Qsort comparison routine for the block leaf entries. + */ +static int /* sort order */ +xfs_dir2_block_sort( + const void *a, /* first leaf entry */ + const void *b) /* second leaf entry */ +{ + const xfs_dir2_leaf_entry_t *la; /* first leaf entry */ + const xfs_dir2_leaf_entry_t *lb; /* second leaf entry */ + + la = a; + lb = b; + return INT_GET(la->hashval, ARCH_CONVERT) < INT_GET(lb->hashval, ARCH_CONVERT) ? -1 : + (INT_GET(la->hashval, ARCH_CONVERT) > INT_GET(lb->hashval, ARCH_CONVERT) ? 1 : 0); +} + +/* + * Convert a V2 leaf directory to a V2 block directory if possible. + */ +int /* error */ +xfs_dir2_leaf_to_block( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp, /* leaf buffer */ + xfs_dabuf_t *dbp) /* data buffer */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf bests table */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused data entry */ + int error; /* error return value */ + int from; /* leaf from index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* file system mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to scan for bestfree */ + xfs_dir2_sf_hdr_t sfh; /* shortform header */ + int size; /* bytes used */ + xfs_dir2_data_off_t *tagp; /* end of entry (tag) */ + int to; /* block/leaf to index */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_bb("leaf_to_block", args, lbp, dbp); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = lbp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * If there are data blocks other than the first one, take this + * opportunity to remove trailing empty data blocks that may have + * been left behind during no-space-reservation operations. + * These will show up in the leaf bests table. + */ + while (dp->i_d.di_size > mp->m_dirblksize) { + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + if (INT_GET(bestsp[INT_GET(ltp->bestcount, ARCH_CONVERT) - 1], ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(block->hdr)) { + if ((error = + xfs_dir2_leaf_trim_data(args, lbp, + (xfs_dir2_db_t)(INT_GET(ltp->bestcount, ARCH_CONVERT) - 1)))) + goto out; + } else { + error = 0; + goto out; + } + } + /* + * Read the data block if we don't already have it, give up if it fails. + */ + if (dbp == NULL && + (error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &dbp, + XFS_DATA_FORK))) { + goto out; + } + block = dbp->data; + ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); + /* + * Size of the "leaf" area in the block. + */ + size = (uint)sizeof(block->tail) + + (uint)sizeof(*lep) * (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + /* + * Look at the last data entry. + */ + tagp = (xfs_dir2_data_off_t *)((char *)block + mp->m_dirblksize) - 1; + dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free or is too short we can't do it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG || INT_GET(dup->length, ARCH_CONVERT) < size) { + error = 0; + goto out; + } + /* + * Start converting it to block form. + */ + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC); + needlog = 1; + needscan = 0; + /* + * Use up the space at the end of the block (blp/btp). + */ + xfs_dir2_data_use_free(tp, dbp, dup, mp->m_dirblksize - size, size, + &needlog, &needscan); + /* + * Initialize the block tail. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + INT_SET(btp->count, ARCH_CONVERT, INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + INT_ZERO(btp->stale, ARCH_CONVERT); + xfs_dir2_block_log_tail(tp, dbp); + /* + * Initialize the block leaf area. We compact out stale entries. + */ + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + lep[to++] = leaf->ents[from]; + } + ASSERT(to == INT_GET(btp->count, ARCH_CONVERT)); + xfs_dir2_block_log_leaf(tp, dbp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1); + /* + * Scan the bestfree if we need it and log the data block header. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * Pitch the old leaf block. + */ + error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp); + lbp = NULL; + if (error) { + goto out; + } + /* + * Now see if the resulting block can be shrunken to shortform. + */ + if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) > + XFS_IFORK_DSIZE(dp)) { + error = 0; + goto out; + } + return xfs_dir2_block_to_sf(args, dbp, size, &sfh); +out: + if (lbp) + xfs_da_buf_done(lbp); + if (dbp) + xfs_da_buf_done(dbp); + return error; +} + +/* + * Convert the shortform directory to block form. + */ +int /* error */ +xfs_dir2_sf_to_block( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_db_t blkno; /* dir-relative block # (0) */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail pointer */ + char *buf; /* sf buffer */ + int buf_len; + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + int dummy; /* trash */ + xfs_dir2_data_unused_t *dup; /* unused entry pointer */ + int endoffset; /* end of data objects */ + int error; /* error return value */ + int i; /* index */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to scan block freespc */ + int newoffset; /* offset from current entry */ + int offset; /* target block offset */ + xfs_dir2_sf_entry_t *sfep; /* sf entry pointer */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_dir2_data_off_t *tagp; /* end of data entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("sf_to_block", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bomb out if the shortform directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Copy the directory into the stack buffer. + * Then pitch the incore inode data so we can make extents. + */ + + buf_len = dp->i_df.if_bytes; + buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP); + + bcopy(sfp, buf, dp->i_df.if_bytes); + xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK); + dp->i_d.di_size = 0; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + /* + * Reset pointer - old sfp is gone. + */ + sfp = (xfs_dir2_sf_t *)buf; + /* + * Add block 0 to the inode. + */ + error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); + if (error) { + kmem_free(buf, buf_len); + return error; + } + /* + * Initialize the data block. + */ + error = xfs_dir2_data_init(args, blkno, &bp); + if (error) { + kmem_free(buf, buf_len); + return error; + } + block = bp->data; + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC); + /* + * Compute size of block "tail" area. + */ + i = (uint)sizeof(*btp) + + (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t); + /* + * The whole thing is initialized to free by the init routine. + * Say we're using the leaf and tail area. + */ + dup = (xfs_dir2_data_unused_t *)block->u; + needlog = needscan = 0; + xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, + &needscan); + ASSERT(needscan == 0); + /* + * Fill in the tail. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + INT_SET(btp->count, ARCH_CONVERT, INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2); /* ., .. */ + INT_ZERO(btp->stale, ARCH_CONVERT); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endoffset = (uint)((char *)blp - (char *)block); + /* + * Remove the freespace, we'll manage it. + */ + xfs_dir2_data_use_free(tp, bp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)block), + INT_GET(dup->length, ARCH_CONVERT), &needlog, &needscan); + /* + * Create entry for . + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATA_DOT_OFFSET); + INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino); + dep->namelen = 1; + dep->name[0] = '.'; + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[0].hashval, ARCH_CONVERT, xfs_dir_hash_dot); + INT_SET(blp[0].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + /* + * Create entry for .. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET); + INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT)); + dep->namelen = 2; + dep->name[0] = dep->name[1] = '.'; + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[1].hashval, ARCH_CONVERT, xfs_dir_hash_dotdot); + INT_SET(blp[1].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + /* + * Loop over existing entries, stuff them in. + */ + if ((i = 0) == INT_GET(sfp->hdr.count, ARCH_CONVERT)) + sfep = NULL; + else + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + /* + * Need to preserve the existing offset values in the sf directory. + * Insert holes (unused entries) where necessary. + */ + while (offset < endoffset) { + /* + * sfep is null when we reach the end of the list. + */ + if (sfep == NULL) + newoffset = endoffset; + else + newoffset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT); + /* + * There should be a hole here, make one. + */ + if (offset < newoffset) { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + offset); + INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(dup->length, ARCH_CONVERT, newoffset - offset); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t) + ((char *)dup - (char *)block)); + xfs_dir2_data_log_unused(tp, bp, dup); + (void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block, + dup, &dummy); + offset += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + /* + * Copy a real entry. + */ + dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset); + INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT)); + dep->namelen = sfep->namelen; + bcopy(sfep->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[2 + i].hashval, ARCH_CONVERT, xfs_da_hashname((char *)sfep->name, sfep->namelen)); + INT_SET(blp[2 + i].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, + (char *)dep - (char *)block)); + offset = (int)((char *)(tagp + 1) - (char *)block); + if (++i == INT_GET(sfp->hdr.count, ARCH_CONVERT)) + sfep = NULL; + else + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + /* Done with the temporary buffer */ + kmem_free(buf, buf_len); + /* + * Sort the leaf entries by hash value. + */ + qsort(blp, INT_GET(btp->count, ARCH_CONVERT), sizeof(*blp), xfs_dir2_block_sort); + /* + * Log the leaf entry area and tail. + * Already logged the header in data_init, ignore needlog. + */ + ASSERT(needscan == 0); + xfs_dir2_block_log_leaf(tp, bp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1); + xfs_dir2_block_log_tail(tp, bp); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_block.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_block.h --- linux-2.4.19/fs/xfs/xfs_dir2_block.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_block.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_BLOCK_H__ +#define __XFS_DIR2_BLOCK_H__ + +/* + * xfs_dir2_block.h + * Directory version 2, single block format structures + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_data_hdr; +struct xfs_dir2_leaf_entry; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * The single block format is as follows: + * xfs_dir2_data_hdr_t structure + * xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures + * xfs_dir2_leaf_entry_t structures + * xfs_dir2_block_tail_t structure + */ + +#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: for one block dirs */ + +typedef struct xfs_dir2_block_tail { + __uint32_t count; /* count of leaf entries */ + __uint32_t stale; /* count of stale lf entries */ +} xfs_dir2_block_tail_t; + +/* + * Generic single-block structure, for xfs_db. + */ +typedef struct xfs_dir2_block { + xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_BLOCK_MAGIC */ + xfs_dir2_data_union_t u[1]; + xfs_dir2_leaf_entry_t leaf[1]; + xfs_dir2_block_tail_t tail; +} xfs_dir2_block_t; + +/* + * Pointer to the leaf header embedded in a data block (1-block format) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BLOCK_TAIL_P) +xfs_dir2_block_tail_t * +xfs_dir2_block_tail_p(struct xfs_mount *mp, xfs_dir2_block_t *block); +#define XFS_DIR2_BLOCK_TAIL_P(mp,block) xfs_dir2_block_tail_p(mp,block) +#else +#define XFS_DIR2_BLOCK_TAIL_P(mp,block) \ + (((xfs_dir2_block_tail_t *)((char *)(block) + (mp)->m_dirblksize)) - 1) +#endif + +/* + * Pointer to the leaf entries embedded in a data block (1-block format) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BLOCK_LEAF_P) +struct xfs_dir2_leaf_entry *xfs_dir2_block_leaf_p_arch( + xfs_dir2_block_tail_t *btp, xfs_arch_t arch); +#define XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch) \ + xfs_dir2_block_leaf_p_arch(btp,arch) +#else +#define XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch) \ + (((struct xfs_dir2_leaf_entry *)(btp)) - INT_GET((btp)->count, arch)) +#endif + +/* + * Function declarations. + */ + +extern int + xfs_dir2_block_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_block_getdents(struct xfs_trans *tp, struct xfs_inode *dp, + struct uio *uio, int *eofp, struct xfs_dirent *dbp, + xfs_dir2_put_t put); + +extern int + xfs_dir2_block_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_block_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_block_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_to_block(struct xfs_da_args *args, struct xfs_dabuf *lbp, + struct xfs_dabuf *dbp); + +extern int + xfs_dir2_sf_to_block(struct xfs_da_args *args); + +#endif /* __XFS_DIR2_BLOCK_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_data.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_data.c --- linux-2.4.19/fs/xfs/xfs_dir2_data.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_data.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,833 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_data.c + * Core data block handling routines for XFS V2 directories. + * See xfs_dir2_data.h for data structures. + */ + +#include + + +#ifdef DEBUG +/* + * Check the consistency of the data block. + * The input can also be a block-format directory. + * Pop an assert if we find anything bad. + */ +void +xfs_dir2_data_check( + xfs_inode_t *dp, /* incore inode pointer */ + xfs_dabuf_t *bp) /* data block's buffer */ +{ + xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ + xfs_dir2_data_free_t *bf; /* bestfree table */ + xfs_dir2_block_tail_t *btp=NULL; /* block tail */ + int count; /* count of entries found */ + xfs_dir2_data_t *d; /* data block pointer */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_dir2_data_free_t *dfp; /* bestfree entry */ + xfs_dir2_data_unused_t *dup; /* unused entry */ + char *endp; /* end of useful data */ + int freeseen; /* mask of bestfrees seen */ + xfs_dahash_t hash; /* hash of current name */ + int i; /* leaf index */ + int lastfree; /* last entry was unused */ + xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ + xfs_mount_t *mp; /* filesystem mount point */ + char *p; /* current data position */ + int stale; /* count of stale leaves */ + + mp = dp->i_mount; + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + bf = d->hdr.bestfree; + p = (char *)d->u; + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endp = (char *)lep; + } else + endp = (char *)d + mp->m_dirblksize; + count = lastfree = freeseen = 0; + /* + * Account for zero bestfree entries. + */ + if (INT_ISZERO(bf[0].length, ARCH_CONVERT)) { + ASSERT(INT_ISZERO(bf[0].offset, ARCH_CONVERT)); + freeseen |= 1 << 0; + } + if (INT_ISZERO(bf[1].length, ARCH_CONVERT)) { + ASSERT(INT_ISZERO(bf[1].offset, ARCH_CONVERT)); + freeseen |= 1 << 1; + } + if (INT_ISZERO(bf[2].length, ARCH_CONVERT)) { + ASSERT(INT_ISZERO(bf[2].offset, ARCH_CONVERT)); + freeseen |= 1 << 2; + } + ASSERT(INT_GET(bf[0].length, ARCH_CONVERT) >= INT_GET(bf[1].length, ARCH_CONVERT)); + ASSERT(INT_GET(bf[1].length, ARCH_CONVERT) >= INT_GET(bf[2].length, ARCH_CONVERT)); + /* + * Loop over the data/unused entries. + */ + while (p < endp) { + dup = (xfs_dir2_data_unused_t *)p; + /* + * If it's unused, look for the space in the bestfree table. + * If we find it, account for that, else make sure it + * doesn't need to be there. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ASSERT(lastfree == 0); + ASSERT(INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT) == + (char *)dup - (char *)d); + dfp = xfs_dir2_data_freefind(d, dup); + if (dfp) { + i = (int)(dfp - bf); + ASSERT((freeseen & (1 << i)) == 0); + freeseen |= 1 << i; + } else + ASSERT(INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(bf[2].length, ARCH_CONVERT)); + p += INT_GET(dup->length, ARCH_CONVERT); + lastfree = 1; + continue; + } + /* + * It's a real entry. Validate the fields. + * If this is a block directory then make sure it's + * in the leaf section of the block. + * The linear search is crude but this is DEBUG code. + */ + dep = (xfs_dir2_data_entry_t *)p; + ASSERT(dep->namelen != 0); + ASSERT(xfs_dir_ino_validate(mp, INT_GET(dep->inumber, ARCH_CONVERT)) == 0); + ASSERT(INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) == + (char *)dep - (char *)d); + count++; + lastfree = 0; + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + (xfs_dir2_data_aoff_t) + ((char *)dep - (char *)d)); + hash = xfs_da_hashname((char *)dep->name, dep->namelen); + for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if (INT_GET(lep[i].address, ARCH_CONVERT) == addr && + INT_GET(lep[i].hashval, ARCH_CONVERT) == hash) + break; + } + ASSERT(i < INT_GET(btp->count, ARCH_CONVERT)); + } + p += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + /* + * Need to have seen all the entries and all the bestfree slots. + */ + ASSERT(freeseen == 7); + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + for (i = stale = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if (INT_GET(lep[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + if (i > 0) + ASSERT(INT_GET(lep[i].hashval, ARCH_CONVERT) >= INT_GET(lep[i - 1].hashval, ARCH_CONVERT)); + } + ASSERT(count == INT_GET(btp->count, ARCH_CONVERT) - INT_GET(btp->stale, ARCH_CONVERT)); + ASSERT(stale == INT_GET(btp->stale, ARCH_CONVERT)); + } +} +#endif + +/* + * Given a data block and an unused entry from that block, + * return the bestfree entry if any that corresponds to it. + */ +xfs_dir2_data_free_t * +xfs_dir2_data_freefind( + xfs_dir2_data_t *d, /* data block */ + xfs_dir2_data_unused_t *dup) /* data unused entry */ +{ + xfs_dir2_data_free_t *dfp; /* bestfree entry */ + xfs_dir2_data_aoff_t off; /* offset value needed */ +#if defined(DEBUG) && defined(__KERNEL__) + int matched; /* matched the value */ + int seenzero; /* saw a 0 bestfree entry */ +#endif + + off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)d); +#if defined(DEBUG) && defined(__KERNEL__) + /* + * Validate some consistency in the bestfree table. + * Check order, non-overlapping entries, and if we find the + * one we're looking for it has to be exact. + */ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + for (dfp = &d->hdr.bestfree[0], seenzero = matched = 0; + dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT]; + dfp++) { + if (INT_ISZERO(dfp->offset, ARCH_CONVERT)) { + ASSERT(INT_ISZERO(dfp->length, ARCH_CONVERT)); + seenzero = 1; + continue; + } + ASSERT(seenzero == 0); + if (INT_GET(dfp->offset, ARCH_CONVERT) == off) { + matched = 1; + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(dup->length, ARCH_CONVERT)); + } else if (off < INT_GET(dfp->offset, ARCH_CONVERT)) + ASSERT(off + INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(dfp->offset, ARCH_CONVERT)); + else + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) + INT_GET(dfp->length, ARCH_CONVERT) <= off); + ASSERT(matched || INT_GET(dfp->length, ARCH_CONVERT) >= INT_GET(dup->length, ARCH_CONVERT)); + if (dfp > &d->hdr.bestfree[0]) + ASSERT(INT_GET(dfp[-1].length, ARCH_CONVERT) >= INT_GET(dfp[0].length, ARCH_CONVERT)); + } +#endif + /* + * If this is smaller than the smallest bestfree entry, + * it can't be there since they're sorted. + */ + if (INT_GET(dup->length, ARCH_CONVERT) < INT_GET(d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length, ARCH_CONVERT)) + return NULL; + /* + * Look at the three bestfree entries for our guy. + */ + for (dfp = &d->hdr.bestfree[0]; + dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT]; + dfp++) { + if (INT_ISZERO(dfp->offset, ARCH_CONVERT)) + return NULL; + if (INT_GET(dfp->offset, ARCH_CONVERT) == off) + return dfp; + } + /* + * Didn't find it. This only happens if there are duplicate lengths. + */ + return NULL; +} + +/* + * Insert an unused-space entry into the bestfree table. + */ +xfs_dir2_data_free_t * /* entry inserted */ +xfs_dir2_data_freeinsert( + xfs_dir2_data_t *d, /* data block pointer */ + xfs_dir2_data_unused_t *dup, /* unused space */ + int *loghead) /* log the data header (out) */ +{ + xfs_dir2_data_free_t *dfp; /* bestfree table pointer */ + xfs_dir2_data_free_t new; /* new bestfree entry */ + +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + dfp = d->hdr.bestfree; + INT_COPY(new.length, dup->length, ARCH_CONVERT); + INT_SET(new.offset, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dup - (char *)d)); + /* + * Insert at position 0, 1, or 2; or not at all. + */ + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[0].length, ARCH_CONVERT)) { + dfp[2] = dfp[1]; + dfp[1] = dfp[0]; + dfp[0] = new; + *loghead = 1; + return &dfp[0]; + } + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[1].length, ARCH_CONVERT)) { + dfp[2] = dfp[1]; + dfp[1] = new; + *loghead = 1; + return &dfp[1]; + } + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[2].length, ARCH_CONVERT)) { + dfp[2] = new; + *loghead = 1; + return &dfp[2]; + } + return NULL; +} + +/* + * Remove a bestfree entry from the table. + */ +void +xfs_dir2_data_freeremove( + xfs_dir2_data_t *d, /* data block pointer */ + xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ + int *loghead) /* out: log data header */ +{ +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + /* + * It's the first entry, slide the next 2 up. + */ + if (dfp == &d->hdr.bestfree[0]) { + d->hdr.bestfree[0] = d->hdr.bestfree[1]; + d->hdr.bestfree[1] = d->hdr.bestfree[2]; + } + /* + * It's the second entry, slide the 3rd entry up. + */ + else if (dfp == &d->hdr.bestfree[1]) + d->hdr.bestfree[1] = d->hdr.bestfree[2]; + /* + * Must be the last entry. + */ + else + ASSERT(dfp == &d->hdr.bestfree[2]); + /* + * Clear the 3rd entry, must be zero now. + */ + INT_ZERO(d->hdr.bestfree[2].length, ARCH_CONVERT); + INT_ZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT); + *loghead = 1; +} + +/* + * Given a data block, reconstruct its bestfree map. + */ +void +xfs_dir2_data_freescan( + xfs_mount_t *mp, /* filesystem mount point */ + xfs_dir2_data_t *d, /* data block pointer */ + int *loghead, /* out: log data header */ + char *aendp) /* in: caller's endp */ +{ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* active data entry */ + xfs_dir2_data_unused_t *dup; /* unused data entry */ + char *endp; /* end of block's data */ + char *p; /* current entry pointer */ + +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + /* + * Start by clearing the table. + */ + bzero(d->hdr.bestfree, sizeof(d->hdr.bestfree)); + *loghead = 1; + /* + * Set up pointers. + */ + p = (char *)d->u; + if (aendp) + endp = aendp; + else if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + endp = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } else + endp = (char *)d + mp->m_dirblksize; + /* + * Loop over the block's entries. + */ + while (p < endp) { + dup = (xfs_dir2_data_unused_t *)p; + /* + * If it's a free entry, insert it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ASSERT((char *)dup - (char *)d == + INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT)); + xfs_dir2_data_freeinsert(d, dup, loghead); + p += INT_GET(dup->length, ARCH_CONVERT); + } + /* + * For active entries, check their tags and skip them. + */ + else { + dep = (xfs_dir2_data_entry_t *)p; + ASSERT((char *)dep - (char *)d == + INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT)); + p += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + } +} + +/* + * Initialize a data block at the given block number in the directory. + * Give back the buffer for the created block. + */ +int /* error */ +xfs_dir2_data_init( + xfs_da_args_t *args, /* directory operation args */ + xfs_dir2_db_t blkno, /* logical dir block number */ + xfs_dabuf_t **bpp) /* output block buffer */ +{ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_data_t *d; /* pointer to block */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused entry pointer */ + int error; /* error return value */ + int i; /* bestfree index */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + int t; /* temp */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Get the buffer set up for the block. + */ + error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(bp != NULL); + /* + * Initialize the header. + */ + d = bp->data; + INT_SET(d->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); + INT_SET(d->hdr.bestfree[0].offset, ARCH_CONVERT, (xfs_dir2_data_off_t)sizeof(d->hdr)); + for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { + INT_ZERO(d->hdr.bestfree[i].length, ARCH_CONVERT); + INT_ZERO(d->hdr.bestfree[i].offset, ARCH_CONVERT); + } + /* + * Set up an unused entry for the block's body. + */ + dup = &d->u[0].unused; + INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + + t=mp->m_dirblksize - (uint)sizeof(d->hdr); + INT_SET(d->hdr.bestfree[0].length, ARCH_CONVERT, t); + INT_SET(dup->length, ARCH_CONVERT, t); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)dup - (char *)d)); + /* + * Log it and return it. + */ + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_data_log_unused(tp, bp, dup); + *bpp = bp; + return 0; +} + +/* + * Log an active data entry from the block. + */ +void +xfs_dir2_data_log_entry( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_entry_t *dep) /* data entry pointer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d), + (uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) - + (char *)d - 1)); +} + +/* + * Log a data block header. + */ +void +xfs_dir2_data_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* block buffer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&d->hdr - (char *)d), + (uint)(sizeof(d->hdr) - 1)); +} + +/* + * Log a data unused entry. + */ +void +xfs_dir2_data_log_unused( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_unused_t *dup) /* data unused pointer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + /* + * Log the first part of the unused entry. + */ + xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)d), + (uint)((char *)&dup->length + sizeof(dup->length) - + 1 - (char *)d)); + /* + * Log the end (tag) of the unused entry. + */ + xfs_da_log_buf(tp, bp, + (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d), + (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d + + sizeof(xfs_dir2_data_off_t) - 1)); +} + +/* + * Make a byte range in the data block unused. + * Its current contents are unimportant. + */ +void +xfs_dir2_data_make_free( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_aoff_t offset, /* starting byte offset */ + xfs_dir2_data_aoff_t len, /* length in bytes */ + int *needlogp, /* out: log header */ + int *needscanp) /* out: regen bestfree */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + xfs_dir2_data_free_t *dfp; /* bestfree pointer */ + char *endptr; /* end of data area */ + xfs_mount_t *mp; /* filesystem mount point */ + int needscan; /* need to regen bestfree */ + xfs_dir2_data_unused_t *newdup; /* new unused entry */ + xfs_dir2_data_unused_t *postdup; /* unused entry after us */ + xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ + + mp = tp->t_mountp; + d = bp->data; + /* + * Figure out where the end of the data area is. + */ + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) + endptr = (char *)d + mp->m_dirblksize; + else { + xfs_dir2_block_tail_t *btp; /* block tail */ + + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } + /* + * If this isn't the start of the block, then back up to + * the previous entry and see if it's free. + */ + if (offset > sizeof(d->hdr)) { + xfs_dir2_data_off_t *tagp; /* tag just before us */ + + tagp = (xfs_dir2_data_off_t *)((char *)d + offset) - 1; + prevdup = (xfs_dir2_data_unused_t *)((char *)d + INT_GET(*tagp, ARCH_CONVERT)); + if (INT_GET(prevdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + prevdup = NULL; + } else + prevdup = NULL; + /* + * If this isn't the end of the block, see if the entry after + * us is free. + */ + if ((char *)d + offset + len < endptr) { + postdup = + (xfs_dir2_data_unused_t *)((char *)d + offset + len); + if (INT_GET(postdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + postdup = NULL; + } else + postdup = NULL; + ASSERT(*needscanp == 0); + needscan = 0; + /* + * Previous and following entries are both free, + * merge everything into a single free entry. + */ + if (prevdup && postdup) { + xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ + + /* + * See if prevdup and/or postdup are in bestfree table. + */ + dfp = xfs_dir2_data_freefind(d, prevdup); + dfp2 = xfs_dir2_data_freefind(d, postdup); + /* + * We need a rescan unless there are exactly 2 free entries + * namely our two. Then we know what's happening, otherwise + * since the third bestfree is there, there might be more + * entries. + */ + needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT); + /* + * Fix up the new big freespace. + */ + INT_MOD(prevdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, prevdup); + if (!needscan) { + /* + * Has to be the case that entries 0 and 1 are + * dfp and dfp2 (don't know which is which), and + * entry 2 is empty. + * Remove entry 1 first then entry 0. + */ + ASSERT(dfp && dfp2); + if (dfp == &d->hdr.bestfree[1]) { + dfp = &d->hdr.bestfree[0]; + ASSERT(dfp2 == dfp); + dfp2 = &d->hdr.bestfree[1]; + } + xfs_dir2_data_freeremove(d, dfp2, needlogp); + xfs_dir2_data_freeremove(d, dfp, needlogp); + /* + * Now insert the new entry. + */ + dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp); + ASSERT(dfp == &d->hdr.bestfree[0]); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(prevdup->length, ARCH_CONVERT)); + ASSERT(INT_ISZERO(dfp[1].length, ARCH_CONVERT)); + ASSERT(INT_ISZERO(dfp[2].length, ARCH_CONVERT)); + } + } + /* + * The entry before us is free, merge with it. + */ + else if (prevdup) { + dfp = xfs_dir2_data_freefind(d, prevdup); + INT_MOD(prevdup->length, ARCH_CONVERT, len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, prevdup); + /* + * If the previous entry was in the table, the new entry + * is longer, so it will be in the table too. Remove + * the old one and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, prevdup, needlogp); + } + /* + * Otherwise we need a scan if the new entry is big enough. + */ + else + needscan = INT_GET(prevdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); + } + /* + * The following entry is free, merge with it. + */ + else if (postdup) { + dfp = xfs_dir2_data_freefind(d, postdup); + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If the following entry was in the table, the new entry + * is longer, so it will be in the table too. Remove + * the old one and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); + } + /* + * Otherwise we need a scan if the new entry is big enough. + */ + else + needscan = INT_GET(newdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); + } + /* + * Neither neighbor is free. Make a new entry. + */ + else { + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); + } + *needscanp = needscan; +} + +/* + * Take a byte range out of an existing unused space and make it un-free. + */ +void +xfs_dir2_data_use_free( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* data block buffer */ + xfs_dir2_data_unused_t *dup, /* unused entry */ + xfs_dir2_data_aoff_t offset, /* starting offset to use */ + xfs_dir2_data_aoff_t len, /* length to use */ + int *needlogp, /* out: need to log header */ + int *needscanp) /* out: need regen bestfree */ +{ + xfs_dir2_data_t *d; /* data block */ + xfs_dir2_data_free_t *dfp; /* bestfree pointer */ + int matchback; /* matches end of freespace */ + int matchfront; /* matches start of freespace */ + int needscan; /* need to regen bestfree */ + xfs_dir2_data_unused_t *newdup; /* new unused entry */ + xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ + int oldlen; /* old unused entry's length */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + ASSERT(INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG); + ASSERT(offset >= (char *)dup - (char *)d); + ASSERT(offset + len <= (char *)dup + INT_GET(dup->length, ARCH_CONVERT) - (char *)d); + ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT)); + /* + * Look up the entry in the bestfree table. + */ + dfp = xfs_dir2_data_freefind(d, dup); + oldlen = INT_GET(dup->length, ARCH_CONVERT); + ASSERT(dfp || oldlen <= INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT)); + /* + * Check for alignment with front and back of the entry. + */ + matchfront = (char *)dup - (char *)d == offset; + matchback = (char *)dup + oldlen - (char *)d == offset + len; + ASSERT(*needscanp == 0); + needscan = 0; + /* + * If we matched it exactly we just need to get rid of it from + * the bestfree table. + */ + if (matchfront && matchback) { + if (dfp) { + needscan = !INT_ISZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT); + if (!needscan) + xfs_dir2_data_freeremove(d, dfp, needlogp); + } + } + /* + * We match the first part of the entry. + * Make a new entry with the remaining freespace. + */ + else if (matchfront) { + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, oldlen - len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If it was in the table, remove it and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); + ASSERT(dfp != NULL); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); + /* + * If we got inserted at the last slot, + * that means we don't know if there was a better + * choice for the last slot, or not. Rescan. + */ + needscan = dfp == &d->hdr.bestfree[2]; + } + } + /* + * We match the last part of the entry. + * Trim the allocated space off the tail of the entry. + */ + else if (matchback) { + newdup = dup; + INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) + (((char *)d + offset) - (char *)newdup)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If it was in the table, remove it and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); + ASSERT(dfp != NULL); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); + /* + * If we got inserted at the last slot, + * that means we don't know if there was a better + * choice for the last slot, or not. Rescan. + */ + needscan = dfp == &d->hdr.bestfree[2]; + } + } + /* + * Poking out the middle of an entry. + * Make two new entries. + */ + else { + newdup = dup; + INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) + (((char *)d + offset) - (char *)newdup)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len); + INT_SET(newdup2->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup2->length, ARCH_CONVERT, oldlen - len - INT_GET(newdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup2, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup2 - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup2); + /* + * If the old entry was in the table, we need to scan + * if the 3rd entry was valid, since these entries + * are smaller than the old one. + * If we don't need to scan that means there were 1 or 2 + * entries in the table, and removing the old and adding + * the 2 new will work. + */ + if (dfp) { + needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT); + if (!needscan) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup, + needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup2, + needlogp); + } + } + } + *needscanp = needscan; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_data.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_data.h --- linux-2.4.19/fs/xfs/xfs_dir2_data.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_data.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_DATA_H__ +#define __XFS_DIR2_DATA_H__ + +/* + * Directory format 2, data block structures. + */ + +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_inode; +struct xfs_trans; + +/* + * Constants. + */ +#define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: for multiblock dirs */ +#define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */ +#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG) +#define XFS_DIR2_DATA_FREE_TAG 0xffff +#define XFS_DIR2_DATA_FD_COUNT 3 + +/* + * Directory address space divided into sections, + * spaces separated by 32gb. + */ +#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG)) +#define XFS_DIR2_DATA_SPACE 0 +#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_DATA_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATA_OFFSET) + +/* + * Offsets of . and .. in data space (always block 0) + */ +#define XFS_DIR2_DATA_DOT_OFFSET \ + ((xfs_dir2_data_aoff_t)sizeof(xfs_dir2_data_hdr_t)) +#define XFS_DIR2_DATA_DOTDOT_OFFSET \ + (XFS_DIR2_DATA_DOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(1)) +#define XFS_DIR2_DATA_FIRST_OFFSET \ + (XFS_DIR2_DATA_DOTDOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(2)) + +/* + * Structures. + */ + +/* + * Describe a free area in the data block. + * The freespace will be formatted as a xfs_dir2_data_unused_t. + */ +typedef struct xfs_dir2_data_free { + xfs_dir2_data_off_t offset; /* start of freespace */ + xfs_dir2_data_off_t length; /* length of freespace */ +} xfs_dir2_data_free_t; + +/* + * Header for the data blocks. + * Always at the beginning of a directory-sized block. + * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. + */ +typedef struct xfs_dir2_data_hdr { + __uint32_t magic; /* XFS_DIR2_DATA_MAGIC */ + /* or XFS_DIR2_BLOCK_MAGIC */ + xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; +} xfs_dir2_data_hdr_t; + +/* + * Active entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_entry { + xfs_ino_t inumber; /* inode number */ + __uint8_t namelen; /* name length */ + __uint8_t name[1]; /* name bytes, no null */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_entry_t; + +/* + * Unused entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_unused { + __uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */ + xfs_dir2_data_off_t length; /* total free length */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_unused_t; + +typedef union { + xfs_dir2_data_entry_t entry; + xfs_dir2_data_unused_t unused; +} xfs_dir2_data_union_t; + +/* + * Generic data block structure, for xfs_db. + */ +typedef struct xfs_dir2_data { + xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_DATA_MAGIC */ + xfs_dir2_data_union_t u[1]; +} xfs_dir2_data_t; + +/* + * Macros. + */ + +/* + * Size of a data entry. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_ENTSIZE) +int xfs_dir2_data_entsize(int n); +#define XFS_DIR2_DATA_ENTSIZE(n) xfs_dir2_data_entsize(n) +#else +#define XFS_DIR2_DATA_ENTSIZE(n) \ + ((int)(roundup(offsetof(xfs_dir2_data_entry_t, name[0]) + (n) + \ + (uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN))) +#endif + +/* + * Pointer to an entry's tag word. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_ENTRY_TAG_P) +xfs_dir2_data_off_t *xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep); +#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) xfs_dir2_data_entry_tag_p(dep) +#else +#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) \ + ((xfs_dir2_data_off_t *)\ + ((char *)(dep) + XFS_DIR2_DATA_ENTSIZE((dep)->namelen) - \ + (uint)sizeof(xfs_dir2_data_off_t))) +#endif + +/* + * Pointer to a freespace's tag word. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_UNUSED_TAG_P) +xfs_dir2_data_off_t *xfs_dir2_data_unused_tag_p_arch( + xfs_dir2_data_unused_t *dup, xfs_arch_t arch); +#define XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch) \ + xfs_dir2_data_unused_tag_p_arch(dup,arch) +#else +#define XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch) \ + ((xfs_dir2_data_off_t *)\ + ((char *)(dup) + INT_GET((dup)->length, arch) \ + - (uint)sizeof(xfs_dir2_data_off_t))) +#endif + +/* + * Function declarations. + */ + +#ifdef DEBUG +extern void + xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_dabuf *bp); +#else +#define xfs_dir2_data_check(dp,bp) +#endif + +extern xfs_dir2_data_free_t * + xfs_dir2_data_freefind(xfs_dir2_data_t *d, + xfs_dir2_data_unused_t *dup); + +extern xfs_dir2_data_free_t * + xfs_dir2_data_freeinsert(xfs_dir2_data_t *d, + xfs_dir2_data_unused_t *dup, int *loghead); + +extern void + xfs_dir2_data_freeremove(xfs_dir2_data_t *d, + xfs_dir2_data_free_t *dfp, int *loghead); + +extern void + xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d, + int *loghead, char *aendp); + +extern int + xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, + struct xfs_dabuf **bpp); + +extern void + xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_entry_t *dep); + +extern void + xfs_dir2_data_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern void + xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_unused_t *dup); + +extern void + xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_aoff_t offset, + xfs_dir2_data_aoff_t len, int *needlogp, + int *needscanp); + +extern void + xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_unused_t *dup, + xfs_dir2_data_aoff_t offset, + xfs_dir2_data_aoff_t len, int *needlogp, + int *needscanp); + +#endif /* __XFS_DIR2_DATA_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_leaf.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_leaf.c --- linux-2.4.19/fs/xfs/xfs_dir2_leaf.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_leaf.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,1873 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_leaf.c + * XFS directory version 2 implementation - single leaf form + * see xfs_dir2_leaf.h for data structures. + * These directories have multiple XFS_DIR2_DATA blocks and one + * XFS_DIR2_LEAF1 block containing the hash table and freespace map. + */ + +#include + +/* + * Local function declarations. + */ +#ifdef DEBUG +static void xfs_dir2_leaf_check(xfs_inode_t *dp, xfs_dabuf_t *bp); +#else +#define xfs_dir2_leaf_check(dp, bp) +#endif +static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp, + int *indexp, xfs_dabuf_t **dbpp); + +/* + * Convert a block form directory to a leaf form directory. + */ +int /* error */ +xfs_dir2_block_to_leaf( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *dbp) /* input block's buffer */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf's bestsp entries */ + xfs_dablk_t blkno; /* leaf block's bno */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block's leaf entries */ + xfs_dir2_block_tail_t *btp; /* block's tail */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dabuf_t *lbp; /* leaf block's buffer */ + xfs_dir2_db_t ldb; /* leaf block's bno */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf's tail */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to rescan bestfree */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_b("block_to_leaf", args, dbp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Add the leaf block to the inode. + * This interface will only put blocks in the leaf/node range. + * Since that's empty now, we'll get the root (block 0 in range). + */ + if ((error = xfs_da_grow_inode(args, &blkno))) { + return error; + } + ldb = XFS_DIR2_DA_TO_DB(mp, blkno); + ASSERT(ldb == XFS_DIR2_LEAF_FIRSTDB(mp)); + /* + * Initialize the leaf block, get a buffer for it. + */ + if ((error = xfs_dir2_leaf_init(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC))) { + return error; + } + ASSERT(lbp != NULL); + leaf = lbp->data; + block = dbp->data; + xfs_dir2_data_check(dp, dbp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Set the counts in the leaf header. + */ + INT_COPY(leaf->hdr.count, btp->count, ARCH_CONVERT); /* INT_: type change */ + INT_COPY(leaf->hdr.stale, btp->stale, ARCH_CONVERT); /* INT_: type change */ + /* + * Could compact these but I think we always do the conversion + * after squeezing out stale entries. + */ + bcopy(blp, leaf->ents, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, lbp, 0, INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1); + needscan = 0; + needlog = 1; + /* + * Make the space formerly occupied by the leaf entries and block + * tail be free. + */ + xfs_dir2_data_make_free(tp, dbp, + (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), + (xfs_dir2_data_aoff_t)((char *)block + mp->m_dirblksize - + (char *)blp), + &needlog, &needscan); + /* + * Fix up the block header, make it a data block. + */ + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + /* + * Set up leaf tail and bests table. + */ + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_SET(ltp->bestcount, ARCH_CONVERT, 1); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + INT_COPY(bestsp[0], block->hdr.bestfree[0].length, ARCH_CONVERT); + /* + * Log the data header and leaf bests table. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_leaf_check(dp, lbp); + xfs_dir2_data_check(dp, dbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, 0); + xfs_da_buf_done(lbp); + return 0; +} + +/* + * Add an entry to a leaf form directory. + */ +int /* error */ +xfs_dir2_leaf_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_data_off_t *bestsp; /* freespace table in leaf */ + int compact; /* need to compact leaves */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* data unused entry */ + int error; /* error return value */ + int grown; /* allocated new data block */ + int highstale; /* index of next stale leaf */ + int i; /* temporary, index */ + int index; /* leaf table position */ + xfs_dabuf_t *lbp; /* leaf's buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int length; /* length of new entry */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ + int lfloglow; /* low leaf logging index */ + int lfloghigh; /* high leaf logging index */ + int lowstale; /* index of prev stale leaf */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ + xfs_mount_t *mp; /* filesystem mount point */ + int needbytes; /* leaf block bytes needed */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data free */ + xfs_dir2_data_off_t *tagp; /* end of data entry */ + xfs_trans_t *tp; /* transaction pointer */ + xfs_dir2_db_t use_block; /* data block number */ + + xfs_dir2_trace_args("leaf_addname", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the leaf block. + */ + error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(lbp != NULL); + /* + * Look up the entry by hash value and name. + * We know it's not there, our caller has already done a lookup. + * So the index is of the entry to insert in front of. + * But if there are dup hash values the index is of the first of those. + */ + index = xfs_dir2_leaf_search_hash(args, lbp); + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * See if there are any entries with the same hash value + * and space in their block for the new entry. + * This is good because it puts multiple same-hash value entries + * in a data block, improving the lookup of those entries. + */ + for (use_block = -1, lep = &leaf->ents[index]; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + index++, lep++) { + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + i = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(i < INT_GET(ltp->bestcount, ARCH_CONVERT)); + ASSERT(INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF); + if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) { + use_block = i; + break; + } + } + /* + * Didn't find a block yet, linear search all the data blocks. + */ + if (use_block == -1) { + for (i = 0; i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++) { + /* + * Remember a block we see that's missing. + */ + if (INT_GET(bestsp[i], ARCH_CONVERT) == NULLDATAOFF && use_block == -1) + use_block = i; + else if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) { + use_block = i; + break; + } + } + } + /* + * How many bytes do we need in the leaf block? + */ + needbytes = + (!INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT) ? 0 : (uint)sizeof(leaf->ents[0])) + + (use_block != -1 ? 0 : (uint)sizeof(leaf->bests[0])); + /* + * Now kill use_block if it refers to a missing block, so we + * can use it as an indication of allocation needed. + */ + if (use_block != -1 && INT_GET(bestsp[use_block], ARCH_CONVERT) == NULLDATAOFF) + use_block = -1; + /* + * If we don't have enough free bytes but we can make enough + * by compacting out stale entries, we'll do that. + */ + if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] < needbytes && + INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1) { + compact = 1; + } + /* + * Otherwise if we don't have enough free bytes we need to + * convert to node form. + */ + else if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] < + needbytes) { + /* + * Just checking or no space reservation, give up. + */ + if (args->justcheck || args->total == 0) { + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOSPC); + } + /* + * Convert to node form. + */ + error = xfs_dir2_leaf_to_node(args, lbp); + xfs_da_buf_done(lbp); + if (error) + return error; + /* + * Then add the new entry. + */ + return xfs_dir2_node_addname(args); + } + /* + * Otherwise it will fit without compaction. + */ + else + compact = 0; + /* + * If just checking, then it will fit unless we needed to allocate + * a new data block. + */ + if (args->justcheck) { + xfs_da_brelse(tp, lbp); + return use_block == -1 ? XFS_ERROR(ENOSPC) : 0; + } + /* + * If no allocations are allowed, return now before we've + * changed anything. + */ + if (args->total == 0 && use_block == -1) { + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOSPC); + } + /* + * Need to compact the leaf entries, removing stale ones. + * Leave one stale entry behind - the one closest to our + * insertion index - and we'll shift that one to our insertion + * point later. + */ + if (compact) { + xfs_dir2_leaf_compact_x1(lbp, &index, &lowstale, &highstale, + &lfloglow, &lfloghigh); + } + /* + * There are stale entries, so we'll need log-low and log-high + * impossibly bad values later. + */ + else if (INT_GET(leaf->hdr.stale, ARCH_CONVERT)) { + lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * If there was no data block space found, we need to allocate + * a new one. + */ + if (use_block == -1) { + /* + * Add the new data block. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, + &use_block))) { + xfs_da_brelse(tp, lbp); + return error; + } + /* + * Initialize the block. + */ + if ((error = xfs_dir2_data_init(args, use_block, &dbp))) { + xfs_da_brelse(tp, lbp); + return error; + } + /* + * If we're adding a new data block on the end we need to + * extend the bests table. Copy it up one entry. + */ + if (use_block >= INT_GET(ltp->bestcount, ARCH_CONVERT)) { + bestsp--; + ovbcopy(&bestsp[1], &bestsp[0], + INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(bestsp[0])); + INT_MOD(ltp->bestcount, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + } + /* + * If we're filling in a previously empty block just log it. + */ + else + xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block); + data = dbp->data; + INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT); + grown = 1; + } + /* + * Already had space in some data block. + * Just read that one in. + */ + else { + if ((error = + xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, use_block), + -1, &dbp, XFS_DATA_FORK))) { + xfs_da_brelse(tp, lbp); + return error; + } + data = dbp->data; + grown = 0; + } + xfs_dir2_data_check(dp, dbp); + /* + * Point to the biggest freespace in our data block. + */ + dup = (xfs_dir2_data_unused_t *) + ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT)); + ASSERT(INT_GET(dup->length, ARCH_CONVERT) >= length); + needscan = needlog = 0; + /* + * Mark the initial part of our freespace in use for the new entry. + */ + xfs_dir2_data_use_free(tp, dbp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length, + &needlog, &needscan); + /* + * Initialize our new entry (at last). + */ + dep = (xfs_dir2_data_entry_t *)dup; + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data)); + /* + * Need to scan fix up the bestfree table. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + /* + * Need to log the data block's header. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_data_log_entry(tp, dbp, dep); + /* + * If the bests table needs to be changed, do it. + * Log the change unless we've already done that. + */ + if (INT_GET(bestsp[use_block], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT); + if (!grown) + xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block); + } + /* + * Now we need to make room to insert the leaf entry. + * If there are no stale entries, we just insert a hole at index. + */ + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + /* + * lep is still good as the index leaf entry. + */ + if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ovbcopy(lep, lep + 1, + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep)); + /* + * Record low and high logging indices for the leaf. + */ + lfloglow = index; + lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1); + } + /* + * There are stale entries. + * We will use one of them for the new entry. + * It's probably not at the right location, so we'll have to + * shift some up or down first. + */ + else { + /* + * If we didn't compact before, we need to find the nearest + * stale entries before and after our insertion point. + */ + if (compact == 0) { + /* + * Find the first stale entry before the insertion + * point, if any. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find the next stale entry at or after the insertion + * point, if any. Stop if we go so far that the + * lowstale entry would be better. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || + index - lowstale - 1 >= highstale - index); + highstale++) + continue; + } + /* + * If the low one is better, use it. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale - 1 < highstale - index)) { + ASSERT(index - lowstale - 1 >= 0); + ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + /* + * Copy entries up to cover the stale entry + * and make room for the new entry. + */ + if (index - lowstale - 1 > 0) + ovbcopy(&leaf->ents[lowstale + 1], + &leaf->ents[lowstale], + (index - lowstale - 1) * sizeof(*lep)); + lep = &leaf->ents[index - 1]; + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(index - 1, lfloghigh); + } + /* + * The high one is better, so use that one. + */ + else { + ASSERT(highstale - index >= 0); + ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + /* + * Copy entries down to copver the stale entry + * and make room for the new entry. + */ + if (highstale - index > 0) + ovbcopy(&leaf->ents[index], + &leaf->ents[index + 1], + (highstale - index) * sizeof(*lep)); + lep = &leaf->ents[index]; + lfloglow = MIN(index, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1); + } + /* + * Fill in the new leaf entry. + */ + INT_SET(lep->hashval, ARCH_CONVERT, args->hashval); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block, INT_GET(*tagp, ARCH_CONVERT))); + /* + * Log the leaf fields and give up the buffers. + */ + xfs_dir2_leaf_log_header(tp, lbp); + xfs_dir2_leaf_log_ents(tp, lbp, lfloglow, lfloghigh); + xfs_dir2_leaf_check(dp, lbp); + xfs_da_buf_done(lbp); + xfs_dir2_data_check(dp, dbp); + xfs_da_buf_done(dbp); + return 0; +} + +#ifdef DEBUG +/* + * Check the internal consistency of a leaf1 block. + * Pop an assert if something is wrong. + */ +void +xfs_dir2_leaf_check( + xfs_inode_t *dp, /* incore directory inode */ + xfs_dabuf_t *bp) /* leaf's buffer */ +{ + int i; /* leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ + xfs_mount_t *mp; /* filesystem mount point */ + int stale; /* count of stale leaves */ + + leaf = bp->data; + mp = dp->i_mount; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + /* + * This value is not restrictive enough. + * Should factor in the size of the bests table as well. + * We can deduce a value for that from di_size. + */ + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp)); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * Leaves and bests don't overlap. + */ + ASSERT((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] <= + (char *)XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT)); + /* + * Check hash value order, count stale entries. + */ + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <= + INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT)); + if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale); +} +#endif /* DEBUG */ + +/* + * Compact out any stale entries in the leaf. + * Log the header and changed leaf entries, if any. + */ +void +xfs_dir2_leaf_compact( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + int from; /* source leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int loglow; /* first leaf entry to log */ + int to; /* target leaf index */ + + leaf = bp->data; + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + return; + } + /* + * Compress out the stale entries in place. + */ + for (from = to = 0, loglow = -1; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Only actually copy the entries that are different. + */ + if (from > to) { + if (loglow == -1) + loglow = to; + leaf->ents[to] = leaf->ents[from]; + } + to++; + } + /* + * Update and log the header, log the leaf entries. + */ + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == from - to); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(INT_GET(leaf->hdr.stale, ARCH_CONVERT))); + INT_ZERO(leaf->hdr.stale, ARCH_CONVERT); + xfs_dir2_leaf_log_header(args->trans, bp); + if (loglow != -1) + xfs_dir2_leaf_log_ents(args->trans, bp, loglow, to - 1); +} + +/* + * Compact the leaf entries, removing stale ones. + * Leave one stale entry behind - the one closest to our + * insertion index - and the caller will shift that one to our insertion + * point later. + * Return new insertion index, where the remaining stale entry is, + * and leaf logging indices. + */ +void +xfs_dir2_leaf_compact_x1( + xfs_dabuf_t *bp, /* leaf buffer */ + int *indexp, /* insertion index */ + int *lowstalep, /* out: stale entry before us */ + int *highstalep, /* out: stale entry after us */ + int *lowlogp, /* out: low log index */ + int *highlogp) /* out: high log index */ +{ + int from; /* source copy index */ + int highstale; /* stale entry at/after index */ + int index; /* insertion index */ + int keepstale; /* source index of kept stale */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int lowstale; /* stale entry before index */ + int newindex=0; /* new insertion index */ + int to; /* destination copy index */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1); + index = *indexp; + /* + * Find the first stale entry before our index, if any. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find the first stale entry at or after our index, if any. + * Stop if the answer would be worse than lowstale. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || index - lowstale > highstale - index); + highstale++) + continue; + /* + * Pick the better of lowstale and highstale. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale <= highstale - index)) + keepstale = lowstale; + else + keepstale = highstale; + /* + * Copy the entries in place, removing all the stale entries + * except keepstale. + */ + for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + /* + * Notice the new value of index. + */ + if (index == from) + newindex = to; + if (from != keepstale && + INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { + if (from == to) + *lowlogp = to; + continue; + } + /* + * Record the new keepstale value for the insertion. + */ + if (from == keepstale) + lowstale = highstale = to; + /* + * Copy only the entries that have moved. + */ + if (from > to) + leaf->ents[to] = leaf->ents[from]; + to++; + } + ASSERT(from > to); + /* + * If the insertion point was past the last entry, + * set the new insertion point accordingly. + */ + if (index == from) + newindex = to; + *indexp = newindex; + /* + * Adjust the leaf header values. + */ + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(from - to)); + INT_SET(leaf->hdr.stale, ARCH_CONVERT, 1); + /* + * Remember the low/high stale value only in the "right" + * direction. + */ + if (lowstale >= newindex) + lowstale = -1; + else + highstale = INT_GET(leaf->hdr.count, ARCH_CONVERT); + *highlogp = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1; + *lowstalep = lowstale; + *highstalep = highstale; +} + +/* + * Getdents (readdir) for leaf and node directories. + * This reads the data blocks only, so is the same for both forms. + */ +int /* error */ +xfs_dir2_leaf_getdents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + uio_t *uio, /* I/O control & vectors */ + int *eofp, /* out: reached end of dir */ + xfs_dirent_t *dbp, /* caller's buffer */ + xfs_dir2_put_t put) /* ABI formatting routine */ +{ + xfs_dabuf_t *bp; /* data block buffer */ + int byteoff; /* offset in current block */ + xfs_dir2_db_t curdb; /* db for current block */ + xfs_dir2_off_t curoff; /* current overall offset */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_dir2_data_unused_t *dup; /* unused entry */ + int eof; /* reached end of directory */ + int error=0; /* error return value */ + int i; /* temporary loop index */ + int j; /* temporary loop index */ + int length; /* temporary length value */ + xfs_bmbt_irec_t *map; /* map vector for blocks */ + xfs_extlen_t map_blocks; /* number of fsbs in map */ + xfs_dablk_t map_off; /* last mapped file offset */ + int map_size; /* total entries in *map */ + int map_valid; /* valid entries in *map */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_off_t newoff; /* new curoff after new blk */ + int nmap; /* mappings to ask xfs_bmapi */ + xfs_dir2_put_args_t p; /* formatting arg bundle */ + char *ptr=NULL; /* pointer to current data */ + int ra_current; /* number of read-ahead blks */ + int ra_index; /* *map index for read-ahead */ + int ra_offset; /* map entry offset for ra */ + int ra_want; /* readahead count wanted */ + + /* + * If the offset is at or past the largest allowed value, + * give up right away, return eof. + */ + if (uio->uio_offset >= XFS_DIR2_MAX_DATAPTR) { + *eofp = 1; + return 0; + } + mp = dp->i_mount; + /* + * Setup formatting arguments. + */ + p.dbp = dbp; + p.put = put; + p.uio = uio; + /* + * Set up to bmap a number of blocks based on the caller's + * buffer size, the directory block size, and the filesystem + * block size. + */ + map_size = + howmany(uio->uio_resid + mp->m_dirblksize, + mp->m_sb.sb_blocksize); + map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP); + map_valid = ra_index = ra_offset = ra_current = map_blocks = 0; + bp = NULL; + eof = 1; + /* + * Inside the loop we keep the main offset value as a byte offset + * in the directory file. + */ + curoff = XFS_DIR2_DATAPTR_TO_BYTE(mp, uio->uio_offset); + /* + * Force this conversion through db so we truncate the offset + * down to get the start of the data block. + */ + map_off = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, curoff)); + /* + * Loop over directory entries until we reach the end offset. + * Get more blocks and readahead as necessary. + */ + while (curoff < XFS_DIR2_LEAF_OFFSET) { + /* + * If we have no buffer, or we're off the end of the + * current buffer, need to get another one. + */ + if (!bp || ptr >= (char *)bp->data + mp->m_dirblksize) { + /* + * If we have a buffer, we need to release it and + * take it out of the mapping. + */ + if (bp) { + xfs_da_brelse(tp, bp); + bp = NULL; + map_blocks -= mp->m_dirblkfsbs; + /* + * Loop to get rid of the extents for the + * directory block. + */ + for (i = mp->m_dirblkfsbs; i > 0; ) { + j = MIN((int)map->br_blockcount, i); + map->br_blockcount -= j; + map->br_startblock += j; + map->br_startoff += j; + /* + * If mapping is done, pitch it from + * the table. + */ + if (!map->br_blockcount && --map_valid) + ovbcopy(&map[1], &map[0], + sizeof(map[0]) * + map_valid); + i -= j; + } + } + /* + * Recalculate the readahead blocks wanted. + */ + ra_want = howmany(uio->uio_resid + mp->m_dirblksize, + mp->m_sb.sb_blocksize) - 1; + /* + * If we don't have as many as we want, and we haven't + * run out of data blocks, get some more mappings. + */ + if (1 + ra_want > map_blocks && + map_off < + XFS_DIR2_BYTE_TO_DA(mp, XFS_DIR2_LEAF_OFFSET)) { + /* + * Get more bmaps, fill in after the ones + * we already have in the table. + */ + nmap = map_size - map_valid; + error = xfs_bmapi(tp, dp, + map_off, + XFS_DIR2_BYTE_TO_DA(mp, + XFS_DIR2_LEAF_OFFSET) - map_off, + XFS_BMAPI_METADATA, NULL, 0, + &map[map_valid], &nmap, NULL); + /* + * Don't know if we should ignore this or + * try to return an error. + * The trouble with returning errors + * is that readdir will just stop without + * actually passing the error through. + */ + if (error) + break; /* XXX */ + /* + * If we got all the mappings we asked for, + * set the final map offset based on the + * last bmap value received. + * Otherwise, we've reached the end. + */ + if (nmap == map_size - map_valid) + map_off = + map[map_valid + nmap - 1].br_startoff + + map[map_valid + nmap - 1].br_blockcount; + else + map_off = + XFS_DIR2_BYTE_TO_DA(mp, + XFS_DIR2_LEAF_OFFSET); + /* + * Look for holes in the mapping, and + * eliminate them. Count up the valid blocks. + */ + for (i = map_valid; i < map_valid + nmap; ) { + if (map[i].br_startblock == + HOLESTARTBLOCK) { + nmap--; + length = map_valid + nmap - i; + if (length) + ovbcopy(&map[i + 1], + &map[i], + sizeof(map[i]) * + length); + } else { + map_blocks += + map[i].br_blockcount; + i++; + } + } + map_valid += nmap; + } + /* + * No valid mappings, so no more data blocks. + */ + if (!map_valid) { + curoff = XFS_DIR2_DA_TO_BYTE(mp, map_off); + break; + } + /* + * Read the directory block starting at the first + * mapping. + */ + curdb = XFS_DIR2_DA_TO_DB(mp, map->br_startoff); + error = xfs_da_read_buf(tp, dp, map->br_startoff, + map->br_blockcount >= mp->m_dirblkfsbs ? + XFS_FSB_TO_DADDR(mp, map->br_startblock) : + -1, + &bp, XFS_DATA_FORK); + /* + * Should just skip over the data block instead + * of giving up. + */ + if (error) + break; /* XXX */ + /* + * Adjust the current amount of read-ahead: we just + * read a block that was previously ra. + */ + if (ra_current) + ra_current -= mp->m_dirblkfsbs; + /* + * Do we need more readahead? + */ + for (ra_index = ra_offset = i = 0; + ra_want > ra_current && i < map_blocks; + i += mp->m_dirblkfsbs) { + ASSERT(ra_index < map_valid); + /* + * Read-ahead a contiguous directory block. + */ + if (i > ra_current && + map[ra_index].br_blockcount >= + mp->m_dirblkfsbs) { + xfs_baread(mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, + map[ra_index].br_startblock + + ra_offset), + (int)BTOBB(mp->m_dirblksize)); + ra_current = i; + } + /* + * Read-ahead a non-contiguous directory block. + * This doesn't use our mapping, but this + * is a very rare case. + */ + else if (i > ra_current) { + (void)xfs_da_reada_buf(tp, dp, + map[ra_index].br_startoff + + ra_offset, XFS_DATA_FORK); + ra_current = i; + } + /* + * Advance offset through the mapping table. + */ + for (j = 0; j < mp->m_dirblkfsbs; j++) { + /* + * The rest of this extent but not + * more than a dir block. + */ + length = MIN(mp->m_dirblkfsbs, + (int)(map[ra_index].br_blockcount - + ra_offset)); + j += length; + ra_offset += length; + /* + * Advance to the next mapping if + * this one is used up. + */ + if (ra_offset == + map[ra_index].br_blockcount) { + ra_offset = 0; + ra_index++; + } + } + } + /* + * Having done a read, we need to set a new offset. + */ + newoff = XFS_DIR2_DB_OFF_TO_BYTE(mp, curdb, 0); + /* + * Start of the current block. + */ + if (curoff < newoff) + curoff = newoff; + /* + * Make sure we're in the right block. + */ + else if (curoff > newoff) + ASSERT(XFS_DIR2_BYTE_TO_DB(mp, curoff) == + curdb); + data = bp->data; + xfs_dir2_data_check(dp, bp); + /* + * Find our position in the block. + */ + ptr = (char *)&data->u; + byteoff = XFS_DIR2_BYTE_TO_OFF(mp, curoff); + /* + * Skip past the header. + */ + if (byteoff == 0) + curoff += (uint)sizeof(data->hdr); + /* + * Skip past entries until we reach our offset. + */ + else { + while ((char *)ptr - (char *)data < byteoff) { + dup = (xfs_dir2_data_unused_t *)ptr; + + if (INT_GET(dup->freetag, ARCH_CONVERT) + == XFS_DIR2_DATA_FREE_TAG) { + + length = INT_GET(dup->length, + ARCH_CONVERT); + ptr += length; + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + length = + XFS_DIR2_DATA_ENTSIZE(dep->namelen); + ptr += length; + } + /* + * Now set our real offset. + */ + curoff = + XFS_DIR2_DB_OFF_TO_BYTE(mp, + XFS_DIR2_BYTE_TO_DB(mp, curoff), + (char *)ptr - (char *)data); + } + } + /* + * We have a pointer to an entry. + * Is it a live one? + */ + dup = (xfs_dir2_data_unused_t *)ptr; + /* + * No, it's unused, skip over it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) + == XFS_DIR2_DATA_FREE_TAG) { + length = INT_GET(dup->length, ARCH_CONVERT); + ptr += length; + curoff += length; + continue; + } + + /* + * Copy the entry into the putargs, and try formatting it. + */ + dep = (xfs_dir2_data_entry_t *)ptr; + + p.namelen = dep->namelen; + + length = XFS_DIR2_DATA_ENTSIZE(p.namelen); + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff); + +#if XFS_BIG_FILESYSTEMS + p.ino = INT_GET(dep->inumber, ARCH_CONVERT) + mp->m_inoadd; +#else + p.ino = INT_GET(dep->inumber, ARCH_CONVERT); +#endif + p.name = (char *)dep->name; + + error = p.put(&p); + + /* + * Won't fit. Return to caller. + */ + if (!p.done) { + eof = 0; + break; + } + /* + * Advance to next entry in the block. + */ + ptr += length; + curoff += length; + } + + /* + * All done. Set output offset value to current offset. + */ + *eofp = eof; + if (curoff > XFS_DIR2_DATAPTR_TO_BYTE(mp, XFS_DIR2_MAX_DATAPTR)) + uio->uio_offset = XFS_DIR2_MAX_DATAPTR; + else + uio->uio_offset = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff); + kmem_free(map, map_size * sizeof(*map)); + if (bp) + xfs_da_brelse(tp, bp); + return error; +} + +/* + * Initialize a new leaf block, leaf1 or leafn magic accepted. + */ +int +xfs_dir2_leaf_init( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_db_t bno, /* directory block number */ + xfs_dabuf_t **bpp, /* out: leaf buffer */ + int magic) /* magic number for block */ +{ + xfs_dabuf_t *bp; /* leaf buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + ASSERT(dp != NULL); + tp = args->trans; + mp = dp->i_mount; + ASSERT(bno >= XFS_DIR2_LEAF_FIRSTDB(mp) && + bno < XFS_DIR2_FREE_FIRSTDB(mp)); + /* + * Get the buffer for the block. + */ + error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, bno), -1, &bp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(bp != NULL); + leaf = bp->data; + /* + * Initialize the header. + */ + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, magic); + INT_ZERO(leaf->hdr.info.forw, ARCH_CONVERT); + INT_ZERO(leaf->hdr.info.back, ARCH_CONVERT); + INT_ZERO(leaf->hdr.count, ARCH_CONVERT); + INT_ZERO(leaf->hdr.stale, ARCH_CONVERT); + xfs_dir2_leaf_log_header(tp, bp); + /* + * If it's a leaf-format directory initialize the tail. + * In this case our caller has the real bests table to copy into + * the block. + */ + if (magic == XFS_DIR2_LEAF1_MAGIC) { + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_ZERO(ltp->bestcount, ARCH_CONVERT); + xfs_dir2_leaf_log_tail(tp, bp); + } + *bpp = bp; + return 0; +} + +/* + * Log the bests entries indicated from a leaf1 block. + */ +void +xfs_dir2_leaf_log_bests( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* leaf buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_data_off_t *firstb; /* pointer to first entry */ + xfs_dir2_data_off_t *lastb; /* pointer to last entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf); + firstb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + first; + lastb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + last; + xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf), + (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1)); +} + +/* + * Log the leaf entries indicated from a leaf1 or leafn block. + */ +void +xfs_dir2_leaf_log_ents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* leaf buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_leaf_entry_t *firstlep; /* pointer to first entry */ + xfs_dir2_leaf_entry_t *lastlep; /* pointer to last entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + firstlep = &leaf->ents[first]; + lastlep = &leaf->ents[last]; + xfs_da_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf), + (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1)); +} + +/* + * Log the header of the leaf1 or leafn block. + */ +void +xfs_dir2_leaf_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf), + (uint)(sizeof(leaf->hdr) - 1)); +} + +/* + * Log the tail of the leaf1 block. + */ +void +xfs_dir2_leaf_log_tail( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf), + (uint)(mp->m_dirblksize - 1)); +} + +/* + * Look up the entry referred to by args in the leaf format directory. + * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which + * is also used by the node-format code. + */ +int +xfs_dir2_leaf_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* found entry index */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_lookup", args); + /* + * Look up name in the leaf block, returning both buffers and index. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + tp = args->trans; + dp = args->dp; + xfs_dir2_leaf_check(dp, lbp); + leaf = lbp->data; + /* + * Get to the leaf entry and contained data entry address. + */ + lep = &leaf->ents[index]; + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT))); + /* + * Return the found inode number. + */ + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + xfs_da_brelse(tp, dbp); + xfs_da_brelse(tp, lbp); + return XFS_ERROR(EEXIST); +} + +/* + * Look up name/hash in the leaf block. + * Fill in indexp with the found index, and dbpp with the data buffer. + * If not found dbpp will be NULL, and ENOENT comes back. + * lbpp will always be filled in with the leaf buffer unless there's an error. + */ +static int /* error */ +xfs_dir2_leaf_lookup_int( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t **lbpp, /* out: leaf buffer */ + int *indexp, /* out: index in leaf block */ + xfs_dabuf_t **dbpp) /* out: data buffer */ +{ + xfs_dir2_db_t curdb; /* current data block number */ + xfs_dabuf_t *dbp; /* data buffer */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* index in leaf block */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_db_t newdb; /* new data block number */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the leaf block into the buffer. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, + XFS_DATA_FORK))) { + return error; + } + *lbpp = lbp; + leaf = lbp->data; + xfs_dir2_leaf_check(dp, lbp); + /* + * Look for the first leaf entry with our hash value. + */ + index = xfs_dir2_leaf_search_hash(args, lbp); + /* + * Loop over all the entries with the right hash value + * looking to match the name. + */ + for (lep = &leaf->ents[index], dbp = NULL, curdb = -1; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + lep++, index++) { + /* + * Skip over stale leaf entries. + */ + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Get the new data block number. + */ + newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + /* + * If it's not the same as the old data block number, + * need to pitch the old one and read the new one. + */ + if (newdb != curdb) { + if (dbp) + xfs_da_brelse(tp, dbp); + if ((error = + xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, newdb), -1, &dbp, + XFS_DATA_FORK))) { + xfs_da_brelse(tp, lbp); + return error; + } + xfs_dir2_data_check(dp, dbp); + curdb = newdb; + } + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + /* + * If it matches then return it. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + *dbpp = dbp; + *indexp = index; + return 0; + } + } + /* + * No match found, return ENOENT. + */ + ASSERT(args->oknoent); + if (dbp) + xfs_da_brelse(tp, dbp); + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a leaf format directory. + */ +int /* error */ +xfs_dir2_leaf_removename( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf block best freespace */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t db; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data entry structure */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_db_t i; /* temporary data block # */ + int index; /* index into leaf entries */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_dir2_data_off_t oldbest; /* old value of best free */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_removename", args); + /* + * Lookup the leaf entry, get the leaf and data blocks read in. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = lbp->data; + data = dbp->data; + xfs_dir2_data_check(dp, dbp); + /* + * Point to the leaf entry, use that to point to the data entry. + */ + lep = &leaf->ents[index]; + db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + dep = (xfs_dir2_data_entry_t *) + ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + needscan = needlog = 0; + oldbest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + ASSERT(INT_GET(bestsp[db], ARCH_CONVERT) == oldbest); + /* + * Mark the former data entry unused. + */ + xfs_dir2_data_make_free(tp, dbp, + (xfs_dir2_data_aoff_t)((char *)dep - (char *)data), + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * We just mark the leaf entry stale by putting a null in it. + */ + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_header(tp, lbp); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_leaf_log_ents(tp, lbp, index, index); + /* + * Scan the freespace in the data block again if necessary, + * log the data block header if necessary. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * If the longest freespace in the data block has changed, + * put the new value in the bests table and log that. + */ + if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) != oldbest) { + INT_COPY(bestsp[db], data->hdr.bestfree[0].length, ARCH_CONVERT); + xfs_dir2_leaf_log_bests(tp, lbp, db, db); + } + xfs_dir2_data_check(dp, dbp); + /* + * If the data block is now empty then get rid of the data block. + */ + if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(data->hdr)) { + ASSERT(db != mp->m_dirdatablk); + if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { + /* + * Nope, can't get rid of it because it caused + * allocation of a bmap btree block to do so. + * Just go on, returning success, leaving the + * empty block in place. + */ + if (error == ENOSPC && args->total == 0) { + xfs_da_buf_done(dbp); + error = 0; + } + xfs_dir2_leaf_check(dp, lbp); + xfs_da_buf_done(lbp); + return error; + } + dbp = NULL; + /* + * If this is the last data block then compact the + * bests table by getting rid of entries. + */ + if (db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1) { + /* + * Look for the last active entry (i). + */ + for (i = db - 1; i > 0; i--) { + if (INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF) + break; + } + /* + * Copy the table down so inactive entries at the + * end are removed. + */ + ovbcopy(bestsp, &bestsp[db - i], + (INT_GET(ltp->bestcount, ARCH_CONVERT) - (db - i)) * sizeof(*bestsp)); + INT_MOD(ltp->bestcount, ARCH_CONVERT, -(db - i)); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + } else + INT_SET(bestsp[db], ARCH_CONVERT, NULLDATAOFF); + } + /* + * If the data block was not the first one, drop it. + */ + else if (db != mp->m_dirdatablk && dbp != NULL) { + xfs_da_buf_done(dbp); + dbp = NULL; + } + xfs_dir2_leaf_check(dp, lbp); + /* + * See if we can convert to block form. + */ + return xfs_dir2_leaf_to_block(args, lbp, dbp); +} + +/* + * Replace the inode number in a leaf format directory entry. + */ +int /* error */ +xfs_dir2_leaf_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* index of leaf entry */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_replace", args); + /* + * Look up the entry. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + dp = args->dp; + leaf = lbp->data; + /* + * Point to the leaf entry, get data address from it. + */ + lep = &leaf->ents[index]; + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT))); + ASSERT(args->inumber != INT_GET(dep->inumber, ARCH_CONVERT)); + /* + * Put the new inode number in, log it. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + tp = args->trans; + xfs_dir2_data_log_entry(tp, dbp, dep); + xfs_da_buf_done(dbp); + xfs_dir2_leaf_check(dp, lbp); + xfs_da_brelse(tp, lbp); + return 0; +} + +/* + * Return index in the leaf block (lbp) which is either the first + * one with this hash value, or if there are none, the insert point + * for that hash value. + */ +int /* index value */ +xfs_dir2_leaf_search_hash( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp) /* leaf buffer */ +{ + xfs_dahash_t hash=0; /* hash from this entry */ + xfs_dahash_t hashwant; /* hash value looking for */ + int high; /* high leaf index */ + int low; /* low leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int mid=0; /* current leaf index */ + + leaf = lbp->data; +#ifndef __KERNEL__ + if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) + return 0; +#endif + /* + * Note, the table cannot be empty, so we have to go through the loop. + * Binary search the leaf entries looking for our hash value. + */ + for (lep = leaf->ents, low = 0, high = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1, + hashwant = args->hashval; + low <= high; ) { + mid = (low + high) >> 1; + if ((hash = INT_GET(lep[mid].hashval, ARCH_CONVERT)) == hashwant) + break; + if (hash < hashwant) + low = mid + 1; + else + high = mid - 1; + } + /* + * Found one, back up through all the equal hash values. + */ + if (hash == hashwant) { + while (mid > 0 && INT_GET(lep[mid - 1].hashval, ARCH_CONVERT) == hashwant) { + mid--; + } + } + /* + * Need to point to an entry higher than ours. + */ + else if (hash < hashwant) + mid++; + return mid; +} + +/* + * Trim off a trailing data block. We know it's empty since the leaf + * freespace table says so. + */ +int /* error */ +xfs_dir2_leaf_trim_data( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp, /* leaf buffer */ + xfs_dir2_db_t db) /* data block number */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf bests table */ +#ifdef DEBUG + xfs_dir2_data_t *data; /* data block structure */ +#endif + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Read the offending data block. We need its buffer. + */ + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, db), -1, &dbp, + XFS_DATA_FORK))) { + return error; + } +#ifdef DEBUG + data = dbp->data; + ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); +#endif + /* this seems to be an error + * data is only valid if DEBUG is defined? + * RMC 09/08/1999 + */ + + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(data->hdr)); + ASSERT(db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + /* + * Get rid of the data block. + */ + if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { + ASSERT(error != ENOSPC); + xfs_da_brelse(tp, dbp); + return error; + } + /* + * Eliminate the last bests entry from the table. + */ + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + INT_MOD(ltp->bestcount, ARCH_CONVERT, -1); + ovbcopy(&bestsp[0], &bestsp[1], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp)); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + return 0; +} + +/* + * Convert node form directory to leaf form directory. + * The root of the node form dir needs to already be a LEAFN block. + * Just return if we can't do anything. + */ +int /* error */ +xfs_dir2_node_to_leaf( + xfs_da_state_t *state) /* directory operation state */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dabuf_t *fbp; /* buffer for freespace block */ + xfs_fileoff_t fo; /* freespace file offset */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_dabuf_t *lbp; /* buffer for leaf block */ + xfs_dir2_leaf_tail_t *ltp; /* tail of leaf structure */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* successful free trim? */ + xfs_trans_t *tp; /* transaction pointer */ + + /* + * There's more than a leaf level in the btree, so there must + * be multiple leafn blocks. Give up. + */ + if (state->path.active > 1) + return 0; + args = state->args; + xfs_dir2_trace_args("node_to_leaf", args); + mp = state->mp; + dp = args->dp; + tp = args->trans; + /* + * Get the last offset in the file. + */ + if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) { + return error; + } + fo -= mp->m_dirblkfsbs; + /* + * If there are freespace blocks other than the first one, + * take this opportunity to remove trailing empty freespace blocks + * that may have been left behind during no-space-reservation + * operations. + */ + while (fo > mp->m_dirfreeblk) { + if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) { + return error; + } + if (rval) + fo -= mp->m_dirblkfsbs; + else + return 0; + } + /* + * Now find the block just before the freespace block. + */ + if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) { + return error; + } + /* + * If it's not the single leaf block, give up. + */ + if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + mp->m_dirblksize) + return 0; + lbp = state->path.blk[0].bp; + leaf = lbp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * Read the freespace block. + */ + if ((error = xfs_da_read_buf(tp, dp, mp->m_dirfreeblk, -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + ASSERT(INT_ISZERO(free->hdr.firstdb, ARCH_CONVERT)); + /* + * Now see if the leafn and free data will fit in a leaf1. + * If not, release the buffer and give up. + */ + if ((uint)sizeof(leaf->hdr) + + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)) * (uint)sizeof(leaf->ents[0]) + + INT_GET(free->hdr.nvalid, ARCH_CONVERT) * (uint)sizeof(leaf->bests[0]) + + (uint)sizeof(leaf->tail) > + mp->m_dirblksize) { + xfs_da_brelse(tp, fbp); + return 0; + } + /* + * If the leaf has any stale entries in it, compress them out. + * The compact routine will log the header. + */ + if (INT_GET(leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, lbp); + else + xfs_dir2_leaf_log_header(tp, lbp); + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAF1_MAGIC); + /* + * Set up the leaf tail from the freespace block. + */ + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_COPY(ltp->bestcount, free->hdr.nvalid, ARCH_CONVERT); + /* + * Set up the leaf bests table. + */ + bcopy(free->bests, XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), + INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0])); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_check(dp, lbp); + /* + * Get rid of the freespace block. + */ + error = xfs_dir2_shrink_inode(args, XFS_DIR2_FREE_FIRSTDB(mp), fbp); + if (error) { + /* + * This can't fail here because it can only happen when + * punching out the middle of an extent, and this is an + * isolated block. + */ + ASSERT(error != ENOSPC); + return error; + } + fbp = NULL; + /* + * Now see if we can convert the single-leaf directory + * down to a block form directory. + * This routine always kills the dabuf for the leaf, so + * eliminate it from the path. + */ + error = xfs_dir2_leaf_to_block(args, lbp, NULL); + state->path.blk[0].bp = NULL; + return error; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_leaf.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_leaf.h --- linux-2.4.19/fs/xfs/xfs_dir2_leaf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_leaf.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_LEAF_H__ +#define __XFS_DIR2_LEAF_H__ + +/* + * Directory version 2, leaf block structures. + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Constants. + */ + +/* + * Offset of the leaf/node space. First block in this space + * is the btree root. + */ +#define XFS_DIR2_LEAF_SPACE 1 +#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_LEAF_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_LEAF_OFFSET) + +/* + * Types. + */ + +/* + * Offset in data space of a data entry. + */ +typedef __uint32_t xfs_dir2_dataptr_t; +#define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0x7fffffff) +#define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0) + +/* + * Structures. + */ + +/* + * Leaf block header. + */ +typedef struct xfs_dir2_leaf_hdr { + xfs_da_blkinfo_t info; /* header for da routines */ + __uint16_t count; /* count of entries */ + __uint16_t stale; /* count of stale entries */ +} xfs_dir2_leaf_hdr_t; + +/* + * Leaf block entry. + */ +typedef struct xfs_dir2_leaf_entry { + xfs_dahash_t hashval; /* hash value of name */ + xfs_dir2_dataptr_t address; /* address of data entry */ +} xfs_dir2_leaf_entry_t; + +/* + * Leaf block tail. + */ +typedef struct xfs_dir2_leaf_tail { + __uint32_t bestcount; +} xfs_dir2_leaf_tail_t; + +/* + * Leaf block. + * bests and tail are at the end of the block for single-leaf only + * (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC). + */ +typedef struct xfs_dir2_leaf { + xfs_dir2_leaf_hdr_t hdr; /* leaf header */ + xfs_dir2_leaf_entry_t ents[1]; /* entries */ + /* ... */ + xfs_dir2_data_off_t bests[1]; /* best free counts */ + xfs_dir2_leaf_tail_t tail; /* leaf tail */ +} xfs_dir2_leaf_t; + +/* + * Macros. + * The DB blocks are logical directory block numbers, not filesystem blocks. + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_MAX_LEAF_ENTS) +int +xfs_dir2_max_leaf_ents(struct xfs_mount *mp); +#define XFS_DIR2_MAX_LEAF_ENTS(mp) \ + xfs_dir2_max_leaf_ents(mp) +#else +#define XFS_DIR2_MAX_LEAF_ENTS(mp) \ + ((int)(((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_leaf_hdr_t)) / \ + (uint)sizeof(xfs_dir2_leaf_entry_t))) +#endif + +/* + * Get address of the bestcount field in the single-leaf block. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_LEAF_TAIL_P) +xfs_dir2_leaf_tail_t * +xfs_dir2_leaf_tail_p(struct xfs_mount *mp, xfs_dir2_leaf_t *lp); +#define XFS_DIR2_LEAF_TAIL_P(mp,lp) \ + xfs_dir2_leaf_tail_p(mp, lp) +#else +#define XFS_DIR2_LEAF_TAIL_P(mp,lp) \ + ((xfs_dir2_leaf_tail_t *)\ + ((char *)(lp) + (mp)->m_dirblksize - \ + (uint)sizeof(xfs_dir2_leaf_tail_t))) +#endif + +/* + * Get address of the bests array in the single-leaf block. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_LEAF_BESTS_P) +xfs_dir2_data_off_t * +xfs_dir2_leaf_bests_p_arch(xfs_dir2_leaf_tail_t *ltp, xfs_arch_t arch); +#define XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch) xfs_dir2_leaf_bests_p_arch(ltp,arch) +#else +#define XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch) \ + ((xfs_dir2_data_off_t *)(ltp) - INT_GET((ltp)->bestcount, arch)) +#endif + +/* + * Convert dataptr to byte in file space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) xfs_dir2_dataptr_to_byte(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) \ + ((xfs_dir2_off_t)(dp) << XFS_DIR2_DATA_ALIGN_LOG) +#endif + +/* + * Convert byte in file space to dataptr. It had better be aligned. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) xfs_dir2_byte_to_dataptr(mp,by) +#else +#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) \ + ((xfs_dir2_dataptr_t)((by) >> XFS_DIR2_DATA_ALIGN_LOG)) +#endif + +/* + * Convert dataptr to a block number + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_DB) +xfs_dir2_db_t +xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) xfs_dir2_dataptr_to_db(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp)) +#endif + +/* + * Convert dataptr to a byte offset in a block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) xfs_dir2_dataptr_to_off(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) \ + XFS_DIR2_BYTE_TO_OFF(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp)) +#endif + +/* + * Convert block and offset to byte in space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_OFF_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o); +#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \ + xfs_dir2_db_off_to_byte(mp, db, o) +#else +#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \ + (((xfs_dir2_off_t)(db) << \ + ((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog)) + (o)) +#endif + +/* + * Convert byte in space to (DB) block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DB) +xfs_dir2_db_t xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DB(mp,by) xfs_dir2_byte_to_db(mp, by) +#else +#define XFS_DIR2_BYTE_TO_DB(mp,by) \ + ((xfs_dir2_db_t)((by) >> \ + ((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog))) +#endif + +/* + * Convert byte in space to (DA) block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DA) +xfs_dablk_t xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DA(mp,by) xfs_dir2_byte_to_da(mp, by) +#else +#define XFS_DIR2_BYTE_TO_DA(mp,by) \ + XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, by)) +#endif + +/* + * Convert byte in space to offset in a block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_OFF(mp,by) xfs_dir2_byte_to_off(mp, by) +#else +#define XFS_DIR2_BYTE_TO_OFF(mp,by) \ + ((xfs_dir2_data_aoff_t)((by) & \ + ((1 << ((mp)->m_sb.sb_blocklog + \ + (mp)->m_sb.sb_dirblklog)) - 1))) +#endif + +/* + * Convert block and offset to dataptr + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_OFF_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o); +#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \ + xfs_dir2_db_off_to_dataptr(mp, db, o) +#else +#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \ + XFS_DIR2_BYTE_TO_DATAPTR(mp, XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o)) +#endif + +/* + * Convert block (DB) to block (dablk) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_DA) +xfs_dablk_t xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_DA(mp,db) xfs_dir2_db_to_da(mp, db) +#else +#define XFS_DIR2_DB_TO_DA(mp,db) \ + ((xfs_dablk_t)((db) << (mp)->m_sb.sb_dirblklog)) +#endif + +/* + * Convert block (dablk) to block (DB) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DA_TO_DB) +xfs_dir2_db_t xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da); +#define XFS_DIR2_DA_TO_DB(mp,da) xfs_dir2_da_to_db(mp, da) +#else +#define XFS_DIR2_DA_TO_DB(mp,da) \ + ((xfs_dir2_db_t)((da) >> (mp)->m_sb.sb_dirblklog)) +#endif + +/* + * Convert block (dablk) to byte offset in space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DA_TO_BYTE) +xfs_dir2_off_t xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da); +#define XFS_DIR2_DA_TO_BYTE(mp,da) xfs_dir2_da_to_byte(mp, da) +#else +#define XFS_DIR2_DA_TO_BYTE(mp,da) \ + XFS_DIR2_DB_OFF_TO_BYTE(mp, XFS_DIR2_DA_TO_DB(mp, da), 0) +#endif + +/* + * Function declarations. + */ + +extern int + xfs_dir2_block_to_leaf(struct xfs_da_args *args, struct xfs_dabuf *dbp); + +extern int + xfs_dir2_leaf_addname(struct xfs_da_args *args); + +extern void + xfs_dir2_leaf_compact(struct xfs_da_args *args, struct xfs_dabuf *bp); + +extern void + xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp, + int *lowstalep, int *highstalep, int *lowlogp, + int *highlogp); + +extern int + xfs_dir2_leaf_getdents(struct xfs_trans *tp, struct xfs_inode *dp, + struct uio *uio, int *eofp, struct xfs_dirent *dbp, + xfs_dir2_put_t put); + +extern int + xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno, + struct xfs_dabuf **bpp, int magic); + +extern void + xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern void + xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern void + xfs_dir2_leaf_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern void + xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern int + xfs_dir2_leaf_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_search_hash(struct xfs_da_args *args, + struct xfs_dabuf *lbp); +extern int + xfs_dir2_leaf_trim_data(struct xfs_da_args *args, struct xfs_dabuf *lbp, xfs_dir2_db_t db); + +extern int + xfs_dir2_node_to_leaf(struct xfs_da_state *state); + +#endif /* __XFS_DIR2_LEAF_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_node.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_node.c --- linux-2.4.19/fs/xfs/xfs_dir2_node.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_node.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,1976 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_node.c + * XFS directory implementation, version 2, node form files + * See data structures in xfs_dir2_node.h and xfs_da_btree.h. + */ + +#include + +/* + * Function declarations. + */ +static void xfs_dir2_free_log_header(xfs_trans_t *tp, xfs_dabuf_t *bp); +static int xfs_dir2_leafn_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index); +#ifdef DEBUG +static void xfs_dir2_leafn_check(xfs_inode_t *dp, xfs_dabuf_t *bp); +#else +#define xfs_dir2_leafn_check(dp, bp) +#endif +static void xfs_dir2_leafn_moveents(xfs_da_args_t *args, xfs_dabuf_t *bp_s, + int start_s, xfs_dabuf_t *bp_d, int start_d, + int count); +static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2); +static int xfs_dir2_leafn_remove(xfs_da_args_t *args, xfs_dabuf_t *bp, + int index, xfs_da_state_blk_t *dblk, + int *rval); +static int xfs_dir2_node_addname_int(xfs_da_args_t *args, + xfs_da_state_blk_t *fblk); + +/* + * Log entries from a freespace block. + */ +void +xfs_dir2_free_log_bests( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* freespace buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_free_t *free; /* freespace structure */ + + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + xfs_da_log_buf(tp, bp, + (uint)((char *)&free->bests[first] - (char *)free), + (uint)((char *)&free->bests[last] - (char *)free + + sizeof(free->bests[0]) - 1)); +} + +/* + * Log header from a freespace block. + */ +static void +xfs_dir2_free_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* freespace buffer */ +{ + xfs_dir2_free_t *free; /* freespace structure */ + + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free), + (uint)(sizeof(xfs_dir2_free_hdr_t) - 1)); +} + +/* + * Convert a leaf-format directory to a node-format directory. + * We need to change the magic number of the leaf block, and copy + * the freespace table out of the leaf block into its own block. + */ +int /* error */ +xfs_dir2_leaf_to_node( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp) /* leaf buffer */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_dabuf_t *fbp; /* freespace buffer */ + xfs_dir2_db_t fdb; /* freespace block number */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_dir2_data_off_t *from; /* pointer to freespace entry */ + int i; /* leaf freespace index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int n; /* count of live freespc ents */ + xfs_dir2_data_off_t off; /* freespace entry value */ + xfs_dir2_data_off_t *to; /* pointer to freespace entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_b("leaf_to_node", args, lbp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Add a freespace block to the directory. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { + return error; + } + ASSERT(fdb == XFS_DIR2_FREE_FIRSTDB(mp)); + /* + * Get the buffer for the new freespace block. + */ + if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * Initialize the freespace block header. + */ + INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC); + INT_ZERO(free->hdr.firstdb, ARCH_CONVERT); + ASSERT(INT_GET(ltp->bestcount, ARCH_CONVERT) <= (uint)dp->i_d.di_size / mp->m_dirblksize); + INT_COPY(free->hdr.nvalid, ltp->bestcount, ARCH_CONVERT); + /* + * Copy freespace entries from the leaf block to the new block. + * Count active entries. + */ + for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), to = free->bests; + i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++, from++, to++) { + if ((off = INT_GET(*from, ARCH_CONVERT)) != NULLDATAOFF) + n++; + INT_SET(*to, ARCH_CONVERT, off); + } + INT_SET(free->hdr.nused, ARCH_CONVERT, n); + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAFN_MAGIC); + /* + * Log everything. + */ + xfs_dir2_leaf_log_header(tp, lbp); + xfs_dir2_free_log_header(tp, fbp); + xfs_dir2_free_log_bests(tp, fbp, 0, INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1); + xfs_da_buf_done(fbp); + xfs_dir2_leafn_check(dp, lbp); + return 0; +} + +/* + * Add a leaf entry to a leaf block in a node-form directory. + * The other work necessary is done from the caller. + */ +static int /* error */ +xfs_dir2_leafn_add( + xfs_dabuf_t *bp, /* leaf buffer */ + xfs_da_args_t *args, /* operation arguments */ + int index) /* insertion pt for new entry */ +{ + int compact; /* compacting stale leaves */ + xfs_inode_t *dp; /* incore directory inode */ + int highstale; /* next stale entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int lfloghigh; /* high leaf entry logging */ + int lfloglow; /* low leaf entry logging */ + int lowstale; /* previous stale entry */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_sb("leafn_add", args, index, bp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + leaf = bp->data; + /* + * If there are already the maximum number of leaf entries in + * the block, if there are no stale entries it won't fit. + * Caller will do a split. If there are stale entries we'll do + * a compact. + */ + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == XFS_DIR2_MAX_LEAF_ENTS(mp)) { + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) + return XFS_ERROR(ENOSPC); + compact = INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1; + } else + compact = 0; + ASSERT(index == 0 || INT_GET(leaf->ents[index - 1].hashval, ARCH_CONVERT) <= args->hashval); + ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + INT_GET(leaf->ents[index].hashval, ARCH_CONVERT) >= args->hashval); + + if (args->justcheck) + return 0; + + /* + * Compact out all but one stale leaf entry. Leaves behind + * the entry closest to index. + */ + if (compact) { + xfs_dir2_leaf_compact_x1(bp, &index, &lowstale, &highstale, + &lfloglow, &lfloghigh); + } + /* + * Set impossible logging indices for this case. + */ + else if (!INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * No stale entries, just insert a space for the new entry. + */ + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + lep = &leaf->ents[index]; + if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ovbcopy(lep, lep + 1, + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep)); + lfloglow = index; + lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1); + } + /* + * There are stale entries. We'll use one for the new entry. + */ + else { + /* + * If we didn't do a compact then we need to figure out + * which stale entry will be used. + */ + if (compact == 0) { + /* + * Find first stale entry before our insertion point. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find next stale entry after insertion point. + * Stop looking if the answer would be worse than + * lowstale already found. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || + index - lowstale - 1 >= highstale - index); + highstale++) + continue; + } + /* + * Using the low stale entry. + * Shift entries up toward the stale slot. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale - 1 < highstale - index)) { + ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + ASSERT(index - lowstale - 1 >= 0); + if (index - lowstale - 1 > 0) + ovbcopy(&leaf->ents[lowstale + 1], + &leaf->ents[lowstale], + (index - lowstale - 1) * sizeof(*lep)); + lep = &leaf->ents[index - 1]; + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(index - 1, lfloghigh); + } + /* + * Using the high stale entry. + * Shift entries down toward the stale slot. + */ + else { + ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + ASSERT(highstale - index >= 0); + if (highstale - index > 0) + ovbcopy(&leaf->ents[index], + &leaf->ents[index + 1], + (highstale - index) * sizeof(*lep)); + lep = &leaf->ents[index]; + lfloglow = MIN(index, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1); + } + /* + * Insert the new entry, log everything. + */ + INT_SET(lep->hashval, ARCH_CONVERT, args->hashval); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, args->blkno, args->index)); + xfs_dir2_leaf_log_header(tp, bp); + xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh); + xfs_dir2_leafn_check(dp, bp); + return 0; +} + +#ifdef DEBUG +/* + * Check internal consistency of a leafn block. + */ +void +xfs_dir2_leafn_check( + xfs_inode_t *dp, /* incore directory inode */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + int i; /* leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int stale; /* count of stale leaves */ + + leaf = bp->data; + mp = dp->i_mount; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp)); + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT)) { + ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <= + INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT)); + } + if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale); +} +#endif /* DEBUG */ + +/* + * Return the last hash value in the leaf. + * Stale entries are ok. + */ +xfs_dahash_t /* hash value */ +xfs_dir2_leafn_lasthash( + xfs_dabuf_t *bp, /* leaf buffer */ + int *count) /* count of entries in leaf */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) + return 0; + return INT_GET(leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); +} + +/* + * Look up a leaf entry in a node-format leaf block. + * If this is an addname then the extrablk in state is a freespace block, + * otherwise it's a data block. + */ +int +xfs_dir2_leafn_lookup_int( + xfs_dabuf_t *bp, /* leaf buffer */ + xfs_da_args_t *args, /* operation arguments */ + int *indexp, /* out: leaf entry index */ + xfs_da_state_t *state) /* state to fill in */ +{ + xfs_dabuf_t *curbp; /* current data/free buffer */ + xfs_dir2_db_t curdb; /* current data block number */ + xfs_dir2_db_t curfdb; /* current free block number */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int fi; /* free entry index */ + xfs_dir2_free_t *free=NULL; /* free block structure */ + int index; /* leaf entry index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int length=0; /* length of new data entry */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_db_t newdb; /* new data block number */ + xfs_dir2_db_t newfdb; /* new free block number */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); +#ifdef __KERNEL__ + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > 0); +#endif + xfs_dir2_leafn_check(dp, bp); + /* + * Look up the hash value in the leaf entries. + */ + index = xfs_dir2_leaf_search_hash(args, bp); + /* + * Do we have a buffer coming in? + */ + if (state->extravalid) + curbp = state->extrablk.bp; + else + curbp = NULL; + /* + * For addname, it's a free block buffer, get the block number. + */ + if (args->addname) { + curfdb = curbp ? state->extrablk.blkno : -1; + curdb = -1; + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + if ((free = (curbp ? curbp->data : NULL))) + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * For others, it's a data block buffer, get the block number. + */ + else { + curfdb = -1; + curdb = curbp ? state->extrablk.blkno : -1; + } + /* + * Loop over leaf entries with the right hash value. + */ + for (lep = &leaf->ents[index]; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + lep++, index++) { + /* + * Skip stale leaf entries. + */ + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Pull the data block number from the entry. + */ + newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + /* + * For addname, we're looking for a place to put the new entry. + * We want to use a data block with an entry of equal + * hash value to ours if there is one with room. + */ + if (args->addname) { + /* + * If this block isn't the data block we already have + * in hand, take a look at it. + */ + if (newdb != curdb) { + curdb = newdb; + /* + * Convert the data block to the free block + * holding its freespace information. + */ + newfdb = XFS_DIR2_DB_TO_FDB(mp, newdb); + /* + * If it's not the one we have in hand, + * read it in. + */ + if (newfdb != curfdb) { + /* + * If we had one before, drop it. + */ + if (curbp) + xfs_da_brelse(tp, curbp); + /* + * Read the free block. + */ + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, + newfdb), + -1, &curbp, + XFS_DATA_FORK))) { + return error; + } + curfdb = newfdb; + free = curbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == + XFS_DIR2_FREE_MAGIC); + ASSERT((INT_GET(free->hdr.firstdb, ARCH_CONVERT) % + XFS_DIR2_MAX_FREE_BESTS(mp)) == + 0); + ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) <= curdb); + ASSERT(curdb < + INT_GET(free->hdr.firstdb, ARCH_CONVERT) + + INT_GET(free->hdr.nvalid, ARCH_CONVERT)); + } + /* + * Get the index for our entry. + */ + fi = XFS_DIR2_DB_TO_FDINDEX(mp, curdb); + /* + * If it has room, return it. + */ + if (INT_GET(free->bests[fi], ARCH_CONVERT) == NULLDATAOFF) { + return XFS_ERROR(EFSCORRUPTED); + } + if (INT_GET(free->bests[fi], ARCH_CONVERT) >= length) { + *indexp = index; + state->extravalid = 1; + state->extrablk.bp = curbp; + state->extrablk.blkno = curfdb; + state->extrablk.index = fi; + state->extrablk.magic = + XFS_DIR2_FREE_MAGIC; + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); + } + } + } + /* + * Not adding a new entry, so we really want to find + * the name given to us. + */ + else { + /* + * If it's a different data block, go get it. + */ + if (newdb != curdb) { + /* + * If we had a block before, drop it. + */ + if (curbp) + xfs_da_brelse(tp, curbp); + /* + * Read the data block. + */ + if ((error = + xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, newdb), -1, + &curbp, XFS_DATA_FORK))) { + return error; + } + xfs_dir2_data_check(dp, curbp); + curdb = newdb; + } + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)curbp->data + + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + /* + * Compare the entry, return it if it matches. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + *indexp = index; + state->extravalid = 1; + state->extrablk.bp = curbp; + state->extrablk.blkno = curdb; + state->extrablk.index = + (int)((char *)dep - + (char *)curbp->data); + state->extrablk.magic = XFS_DIR2_DATA_MAGIC; + return XFS_ERROR(EEXIST); + } + } + } + /* + * Didn't find a match. + * If we are holding a buffer, give it back in case our caller + * finds it useful. + */ + if ((state->extravalid = (curbp != NULL))) { + state->extrablk.bp = curbp; + state->extrablk.index = -1; + /* + * For addname, giving back a free block. + */ + if (args->addname) { + state->extrablk.blkno = curfdb; + state->extrablk.magic = XFS_DIR2_FREE_MAGIC; + } + /* + * For other callers, giving back a data block. + */ + else { + state->extrablk.blkno = curdb; + state->extrablk.magic = XFS_DIR2_DATA_MAGIC; + } + } + /* + * Return the final index, that will be the insertion point. + */ + *indexp = index; + ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent); + return XFS_ERROR(ENOENT); +} + +/* + * Move count leaf entries from source to destination leaf. + * Log entries and headers. Stale entries are preserved. + */ +static void +xfs_dir2_leafn_moveents( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp_s, /* source leaf buffer */ + int start_s, /* source leaf index */ + xfs_dabuf_t *bp_d, /* destination leaf buffer */ + int start_d, /* destination leaf index */ + int count) /* count of leaves to copy */ +{ + xfs_dir2_leaf_t *leaf_d; /* destination leaf structure */ + xfs_dir2_leaf_t *leaf_s; /* source leaf structure */ + int stale; /* count stale leaves copied */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_bibii("leafn_moveents", args, bp_s, start_s, bp_d, + start_d, count); + /* + * Silently return if nothing to do. + */ + if (count == 0) { + return; + } + tp = args->trans; + leaf_s = bp_s->data; + leaf_d = bp_d->data; + /* + * If the destination index is not the end of the current + * destination leaf entries, open up a hole in the destination + * to hold the new entries. + */ + if (start_d < INT_GET(leaf_d->hdr.count, ARCH_CONVERT)) { + ovbcopy(&leaf_d->ents[start_d], &leaf_d->ents[start_d + count], + (INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - start_d) * + sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_d, start_d + count, + count + INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - 1); + } + /* + * If the source has stale leaves, count the ones in the copy range + * so we can update the header correctly. + */ + if (!INT_ISZERO(leaf_s->hdr.stale, ARCH_CONVERT)) { + int i; /* temp leaf index */ + + for (i = start_s, stale = 0; i < start_s + count; i++) { + if (INT_GET(leaf_s->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + } else + stale = 0; + /* + * Copy the leaf entries from source to destination. + */ + bcopy(&leaf_s->ents[start_s], &leaf_d->ents[start_d], + count * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1); + /* + * If there are source entries after the ones we copied, + * delete the ones we copied by sliding the next ones down. + */ + if (start_s + count < INT_GET(leaf_s->hdr.count, ARCH_CONVERT)) { + ovbcopy(&leaf_s->ents[start_s + count], &leaf_s->ents[start_s], + count * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1); + } + /* + * Update the headers and log them. + */ + INT_MOD(leaf_s->hdr.count, ARCH_CONVERT, -(count)); + INT_MOD(leaf_s->hdr.stale, ARCH_CONVERT, -(stale)); + INT_MOD(leaf_d->hdr.count, ARCH_CONVERT, count); + INT_MOD(leaf_d->hdr.stale, ARCH_CONVERT, stale); + xfs_dir2_leaf_log_header(tp, bp_s); + xfs_dir2_leaf_log_header(tp, bp_d); + xfs_dir2_leafn_check(args->dp, bp_s); + xfs_dir2_leafn_check(args->dp, bp_d); +} + +/* + * Determine the sort order of two leaf blocks. + * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. + */ +int /* sort order */ +xfs_dir2_leafn_order( + xfs_dabuf_t *leaf1_bp, /* leaf1 buffer */ + xfs_dabuf_t *leaf2_bp) /* leaf2 buffer */ +{ + xfs_dir2_leaf_t *leaf1; /* leaf1 structure */ + xfs_dir2_leaf_t *leaf2; /* leaf2 structure */ + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0 && + INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0 && + (INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT) < INT_GET(leaf1->ents[0].hashval, ARCH_CONVERT) || + INT_GET(leaf2->ents[INT_GET(leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT) < + INT_GET(leaf1->ents[INT_GET(leaf1->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT))) + return 1; + return 0; +} + +/* + * Rebalance leaf entries between two leaf blocks. + * This is actually only called when the second block is new, + * though the code deals with the general case. + * A new entry will be inserted in one of the blocks, and that + * entry is taken into account when balancing. + */ +static void +xfs_dir2_leafn_rebalance( + xfs_da_state_t *state, /* btree cursor */ + xfs_da_state_blk_t *blk1, /* first btree block */ + xfs_da_state_blk_t *blk2) /* second btree block */ +{ + xfs_da_args_t *args; /* operation arguments */ + int count; /* count (& direction) leaves */ + int isleft; /* new goes in left leaf */ + xfs_dir2_leaf_t *leaf1; /* first leaf structure */ + xfs_dir2_leaf_t *leaf2; /* second leaf structure */ + int mid; /* midpoint leaf index */ +#ifdef DEBUG + int oldstale; /* old count of stale leaves */ +#endif + int oldsum; /* old total leaf count */ + int swap; /* swapped leaf blocks */ + + args = state->args; + /* + * If the block order is wrong, swap the arguments. + */ + if ((swap = xfs_dir2_leafn_order(blk1->bp, blk2->bp))) { + xfs_da_state_blk_t *tmp; /* temp for block swap */ + + tmp = blk1; + blk1 = blk2; + blk2 = tmp; + } + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + oldsum = INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT); +#ifdef DEBUG + oldstale = INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT); +#endif + mid = oldsum >> 1; + /* + * If the old leaf count was odd then the new one will be even, + * so we need to divide the new count evenly. + */ + if (oldsum & 1) { + xfs_dahash_t midhash; /* middle entry hash value */ + + if (mid >= INT_GET(leaf1->hdr.count, ARCH_CONVERT)) + midhash = INT_GET(leaf2->ents[mid - INT_GET(leaf1->hdr.count, ARCH_CONVERT)].hashval, ARCH_CONVERT); + else + midhash = INT_GET(leaf1->ents[mid].hashval, ARCH_CONVERT); + isleft = args->hashval <= midhash; + } + /* + * If the old count is even then the new count is odd, so there's + * no preferred side for the new entry. + * Pick the left one. + */ + else + isleft = 1; + /* + * Calculate moved entry count. Positive means left-to-right, + * negative means right-to-left. Then move the entries. + */ + count = INT_GET(leaf1->hdr.count, ARCH_CONVERT) - mid + (isleft == 0); + if (count > 0) + xfs_dir2_leafn_moveents(args, blk1->bp, + INT_GET(leaf1->hdr.count, ARCH_CONVERT) - count, blk2->bp, 0, count); + else if (count < 0) + xfs_dir2_leafn_moveents(args, blk2->bp, 0, blk1->bp, + INT_GET(leaf1->hdr.count, ARCH_CONVERT), count); + ASSERT(INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT) == oldsum); + ASSERT(INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT) == oldstale); + /* + * Mark whether we're inserting into the old or new leaf. + */ + if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) < INT_GET(leaf2->hdr.count, ARCH_CONVERT)) + state->inleaf = swap; + else if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > INT_GET(leaf2->hdr.count, ARCH_CONVERT)) + state->inleaf = !swap; + else + state->inleaf = + swap ^ (args->hashval < INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT)); + /* + * Adjust the expected index for insertion. + */ + if (!state->inleaf) + blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); +} + +/* + * Remove an entry from a node directory. + * This removes the leaf entry and the data entry, + * and updates the free block if necessary. + */ +static int /* error */ +xfs_dir2_leafn_remove( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp, /* leaf buffer */ + int index, /* leaf entry index */ + xfs_da_state_blk_t *dblk, /* data block */ + int *rval) /* resulting block needs join */ +{ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t db; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int longest; /* longest data free entry */ + int off; /* data block entry offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_sb("leafn_remove", args, index, bp); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * Point to the entry we're removing. + */ + lep = &leaf->ents[index]; + /* + * Extract the data block and offset from the entry. + */ + db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(dblk->blkno == db); + off = XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(dblk->index == off); + /* + * Kill the leaf entry by marking it stale. + * Log the leaf block changes. + */ + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_header(tp, bp); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_leaf_log_ents(tp, bp, index, index); + /* + * Make the data entry free. Keep track of the longest freespace + * in the data block in case it changes. + */ + dbp = dblk->bp; + data = dbp->data; + dep = (xfs_dir2_data_entry_t *)((char *)data + off); + longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + needlog = needscan = 0; + xfs_dir2_data_make_free(tp, dbp, off, + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * Rescan the data block freespaces for bestfree. + * Log the data block header if needed. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_data_check(dp, dbp); + /* + * If the longest data block freespace changes, need to update + * the corresponding freeblock entry. + */ + if (longest < INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + int error; /* error return value */ + xfs_dabuf_t *fbp; /* freeblock buffer */ + xfs_dir2_db_t fdb; /* freeblock block number */ + int findex; /* index in freeblock entries */ + xfs_dir2_free_t *free; /* freeblock structure */ + int logfree; /* need to log free entry */ + + /* + * Convert the data block number to a free block, + * read in the free block. + */ + fdb = XFS_DIR2_DB_TO_FDB(mp, db); + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) == + XFS_DIR2_MAX_FREE_BESTS(mp) * + (fdb - XFS_DIR2_FREE_FIRSTDB(mp))); + /* + * Calculate which entry we need to fix. + */ + findex = XFS_DIR2_DB_TO_FDINDEX(mp, db); + longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + /* + * If the data block is now empty we can get rid of it + * (usually). + */ + if (longest == mp->m_dirblksize - (uint)sizeof(data->hdr)) { + /* + * Try to punch out the data block. + */ + error = xfs_dir2_shrink_inode(args, db, dbp); + if (error == 0) { + dblk->bp = NULL; + data = NULL; + } + /* + * We can get ENOSPC if there's no space reservation. + * In this case just drop the buffer and some one else + * will eventually get rid of the empty block. + */ + else if (error == ENOSPC && args->total == 0) + xfs_da_buf_done(dbp); + else + return error; + } + /* + * If we got rid of the data block, we can eliminate that entry + * in the free block. + */ + if (data == NULL) { + /* + * One less used entry in the free table. + */ + INT_MOD(free->hdr.nused, ARCH_CONVERT, -1); + xfs_dir2_free_log_header(tp, fbp); + /* + * If this was the last entry in the table, we can + * trim the table size back. There might be other + * entries at the end referring to non-existent + * data blocks, get those too. + */ + if (findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1) { + int i; /* free entry index */ + + for (i = findex - 1; + i >= 0 && INT_GET(free->bests[i], ARCH_CONVERT) == NULLDATAOFF; + i--) + continue; + INT_SET(free->hdr.nvalid, ARCH_CONVERT, i + 1); + logfree = 0; + } + /* + * Not the last entry, just punch it out. + */ + else { + INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF); + logfree = 1; + } + /* + * If there are no useful entries left in the block, + * get rid of the block if we can. + */ + if (INT_ISZERO(free->hdr.nused, ARCH_CONVERT)) { + error = xfs_dir2_shrink_inode(args, fdb, fbp); + if (error == 0) { + fbp = NULL; + logfree = 0; + } else if (error != ENOSPC || args->total != 0) + return error; + /* + * It's possible to get ENOSPC if there is no + * space reservation. In this case some one + * else will eventually get rid of this block. + */ + } + } + /* + * Data block is not empty, just set the free entry to + * the new value. + */ + else { + INT_SET(free->bests[findex], ARCH_CONVERT, longest); + logfree = 1; + } + /* + * Log the free entry that changed, unless we got rid of it. + */ + if (logfree) + xfs_dir2_free_log_bests(tp, fbp, findex, findex); + /* + * Drop the buffer if we still have it. + */ + if (fbp) + xfs_da_buf_done(fbp); + } + xfs_dir2_leafn_check(dp, bp); + /* + * Return indication of whether this leaf block is emtpy enough + * to justify trying to join it with a neighbor. + */ + *rval = + ((uint)sizeof(leaf->hdr) + + (uint)sizeof(leaf->ents[0]) * + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT))) < + mp->m_dir_magicpct; + return 0; +} + +/* + * Split the leaf entries in the old block into old and new blocks. + */ +int /* error */ +xfs_dir2_leafn_split( + xfs_da_state_t *state, /* btree cursor */ + xfs_da_state_blk_t *oldblk, /* original block */ + xfs_da_state_blk_t *newblk) /* newly created block */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_dablk_t blkno; /* new leaf block number */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + /* + * Allocate space for a new leaf node. + */ + args = state->args; + mp = args->dp->i_mount; + ASSERT(args != NULL); + ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); + error = xfs_da_grow_inode(args, &blkno); + if (error) { + return error; + } + /* + * Initialize the new leaf block. + */ + error = xfs_dir2_leaf_init(args, XFS_DIR2_DA_TO_DB(mp, blkno), + &newblk->bp, XFS_DIR2_LEAFN_MAGIC); + if (error) { + return error; + } + newblk->blkno = blkno; + newblk->magic = XFS_DIR2_LEAFN_MAGIC; + /* + * Rebalance the entries across the two leaves, link the new + * block into the leaves. + */ + xfs_dir2_leafn_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) { + return error; + } + /* + * Insert the new entry in the correct block. + */ + if (state->inleaf) + error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); + else + error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_dir2_leafn_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_dir2_leafn_lasthash(newblk->bp, NULL); + xfs_dir2_leafn_check(args->dp, oldblk->bp); + xfs_dir2_leafn_check(args->dp, newblk->bp); + return error; +} + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +int /* error */ +xfs_dir2_leafn_toosmall( + xfs_da_state_t *state, /* btree cursor */ + int *action) /* resulting action to take */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + xfs_dablk_t blkno; /* leaf block number */ + xfs_dabuf_t *bp; /* leaf buffer */ + int bytes; /* bytes in use */ + int count; /* leaf live entry count */ + int error; /* error return value */ + int forward; /* sibling block direction */ + int i; /* sibling counter */ + xfs_da_blkinfo_t *info; /* leaf block header */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int rval; /* result from path_shift */ + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[state->path.active - 1]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + leaf = (xfs_dir2_leaf_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes = (uint)sizeof(leaf->hdr) + count * (uint)sizeof(leaf->ents[0]); + if (bytes > (state->blocksize >> 1)) { + /* + * Blk over 50%, don't try to join. + */ + *action = 0; + return 0; + } + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (arbitrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = !INT_ISZERO(info->forw, ARCH_CONVERT); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, 0, + &rval); + if (error) + return error; + *action = rval ? 2 : 0; + return 0; + } + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + forward = INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT); + for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { + blkno = forward ?INT_GET( info->forw, ARCH_CONVERT) : INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + /* + * Read the sibling leaf block. + */ + if ((error = + xfs_da_read_buf(state->args->trans, state->args->dp, blkno, + -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + /* + * Count bytes in the two blocks combined. + */ + leaf = (xfs_dir2_leaf_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize >> 2); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes -= count * (uint)sizeof(leaf->ents[0]); + /* + * Fits with at least 25% to spare. + */ + if (bytes >= 0) + break; + xfs_da_brelse(state->args->trans, bp); + } + /* + * Didn't like either block, give up. + */ + if (i >= 2) { + *action = 0; + return 0; + } + /* + * Done with the sibling leaf block here, drop the dabuf + * so path_shift can get it. + */ + xfs_da_buf_done(bp); + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) + error = xfs_da_path_shift(state, &state->altpath, forward, 0, + &rval); + else + error = xfs_da_path_shift(state, &state->path, forward, 0, + &rval); + if (error) { + return error; + } + *action = rval ? 0 : 1; + return 0; +} + +/* + * Move all the leaf entries from drop_blk to save_blk. + * This is done as part of a join operation. + */ +void +xfs_dir2_leafn_unbalance( + xfs_da_state_t *state, /* cursor */ + xfs_da_state_blk_t *drop_blk, /* dead block */ + xfs_da_state_blk_t *save_blk) /* surviving block */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ + xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ + + args = state->args; + ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); + ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * If there are any stale leaf entries, take this opportunity + * to purge them. + */ + if (INT_GET(drop_leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, drop_blk->bp); + if (INT_GET(save_leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, save_blk->bp); + /* + * Move the entries from drop to the appropriate end of save. + */ + drop_blk->hashval = INT_GET(drop_leaf->ents[INT_GET(drop_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp)) + xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, 0, + INT_GET(drop_leaf->hdr.count, ARCH_CONVERT)); + else + xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, + INT_GET(save_leaf->hdr.count, ARCH_CONVERT), INT_GET(drop_leaf->hdr.count, ARCH_CONVERT)); + save_blk->hashval = INT_GET(save_leaf->ents[INT_GET(save_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + xfs_dir2_leafn_check(args->dp, save_blk->bp); +} + +/* + * Top-level node form directory addname routine. + */ +int /* error */ +xfs_dir2_node_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block for insert */ + int error; /* error return value */ + int rval; /* sub-return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_addname", args); + /* + * Allocate and initialize the state (btree cursor). + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Look up the name. We're not supposed to find it, but + * this gives us the insertion point. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) + rval = error; + if (rval != ENOENT) { + goto done; + } + /* + * Add the data entry to a data block. + * Extravalid is set to a freeblock found by lookup. + */ + rval = xfs_dir2_node_addname_int(args, + state->extravalid ? &state->extrablk : NULL); + if (rval) { + goto done; + } + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + /* + * Add the new leaf entry. + */ + rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); + if (rval == 0) { + /* + * It worked, fix the hash values up the btree. + */ + if (!args->justcheck) + xfs_da_fixhashpath(state, &state->path); + } else { + /* + * It didn't work, we need to split the leaf block. + */ + if (args->total == 0) { + ASSERT(rval == ENOSPC); + goto done; + } + /* + * Split the leaf block and insert the new entry. + */ + rval = xfs_da_split(state); + } +done: + xfs_da_state_free(state); + return rval; +} + +/* + * Add the data entry for a node-format directory name addition. + * The leaf entry is added in xfs_dir2_leafn_add. + * We may enter with a freespace block that the lookup found. + */ +static int /* error */ +xfs_dir2_node_addname_int( + xfs_da_args_t *args, /* operation arguments */ + xfs_da_state_blk_t *fblk) /* optional freespace block */ +{ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t dbno; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ + int error; /* error return value */ + xfs_dir2_db_t fbno; /* freespace block number */ + xfs_dabuf_t *fbp; /* freespace buffer */ + int findex; /* freespace entry index */ + xfs_dir2_db_t foundbno=0; /* found freespace block no */ + int foundindex=0; /* found freespace entry idx */ + xfs_dir2_free_t *free=NULL; /* freespace block structure */ + xfs_dir2_db_t ifbno; /* initial freespace block no */ + xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ + int length; /* length of the new entry */ + int logfree; /* need to log free entry */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_dir2_data_off_t *tagp; /* data entry tag pointer */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * If we came in with a freespace block that means that lookup + * found an entry with our hash value. This is the freespace + * block for that data entry. + */ + if (fblk) { + fbp = fblk->bp; + /* + * Remember initial freespace block number. + */ + ifbno = fblk->blkno; + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + findex = fblk->index; + /* + * This means the free entry showed that the data block had + * space for our entry, so we remembered it. + * Use that data block. + */ + if (findex >= 0) { + ASSERT(findex < INT_GET(free->hdr.nvalid, ARCH_CONVERT)); + ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF); + ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) >= length); + dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex; + } + /* + * The data block looked at didn't have enough room. + * We'll start at the beginning of the freespace entries. + */ + else { + dbno = -1; + findex = 0; + } + } + /* + * Didn't come in with a freespace block, so don't have a data block. + */ + else { + ifbno = dbno = -1; + fbp = NULL; + findex = 0; + } + /* + * If we don't have a data block yet, we're going to scan the + * freespace blocks looking for one. Figure out what the + * highest freespace block number is. + */ + if (dbno == -1) { + xfs_fileoff_t fo; /* freespace block number */ + + if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) + return error; + lastfbno = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo); + fbno = ifbno; + foundindex = -1; + } + /* + * While we haven't identified a data block, search the freeblock + * data for a good data block. If we find a null freeblock entry, + * indicating a hole in the data blocks, remember that. + */ + while (dbno == -1) { + /* + * If we don't have a freeblock in hand, get the next one. + */ + if (fbp == NULL) { + /* + * Happens the first time through unless lookup gave + * us a freespace block to start with. + */ + if (++fbno == 0) + fbno = XFS_DIR2_FREE_FIRSTDB(mp); + /* + * If it's ifbno we already looked at it. + */ + if (fbno == ifbno) + fbno++; + /* + * If it's off the end we're done. + */ + if (fbno >= lastfbno) + break; + /* + * Read the block. There can be holes in the + * freespace blocks, so this might not succeed. + * This should be really rare, so there's no reason + * to avoid it. + */ + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, fbno), -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + if (fbp == NULL) { + continue; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + findex = 0; + } + /* + * Look at the current free entry. Is it good enough? + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF && + INT_GET(free->bests[findex], ARCH_CONVERT) >= length) + dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex; + else { + /* + * If we haven't found an empty entry yet, and this + * one is empty, remember this slot. + */ + if (foundindex == -1 && + INT_GET(free->bests[findex], ARCH_CONVERT) == NULLDATAOFF) { + foundindex = findex; + foundbno = fbno; + } + /* + * Are we done with the freeblock? + */ + if (++findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT)) { + /* + * If there is space left in this freeblock, + * and we don't have an empty entry yet, + * remember this slot. + */ + if (foundindex == -1 && + findex < XFS_DIR2_MAX_FREE_BESTS(mp)) { + foundindex = findex; + foundbno = fbno; + } + /* + * Drop the block. + */ + xfs_da_brelse(tp, fbp); + fbp = NULL; + if (fblk && fblk->bp) + fblk->bp = NULL; + } + } + } + /* + * If we don't have a data block, and there's no free slot in a + * freeblock, we need to add a new freeblock. + */ + if (dbno == -1 && foundindex == -1) { + /* + * Not allowed to allocate, so return failure. + */ + if (args->justcheck || args->total == 0) { + return XFS_ERROR(ENOSPC); + } + /* + * Add the new freeblock. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, + &fbno))) { + return error; + } + /* + * Get a buffer for the new block. + */ + if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fbno), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + /* + * Initialize the new block to be empty, and remember + * its first slot as our empty slot. + */ + free = fbp->data; + INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC); + INT_SET(free->hdr.firstdb, ARCH_CONVERT, (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * + XFS_DIR2_MAX_FREE_BESTS(mp)); + INT_ZERO(free->hdr.nused, ARCH_CONVERT); + INT_ZERO(free->hdr.nvalid, ARCH_CONVERT); + foundindex = 0; + foundbno = fbno; + } + /* + * If we don't have a data block, and we don't have a freeblock buffer + * in hand (we dropped the one with the free slot in it), + * go read the freeblock again. + */ + if (dbno == -1 && fbp == NULL) { + /* + * We're going to use the empty slot we found before. + */ + findex = foundindex; + fbno = foundbno; + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fbno), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * If we don't have a data block, we need to allocate one and make + * the freespace entries refer to it. + */ + if (dbno == -1) { + /* + * Not allowed to allocate, return failure. + */ + if (args->justcheck || args->total == 0) { + /* + * Drop the freespace buffer unless it came from our + * caller. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return XFS_ERROR(ENOSPC); + } + /* + * Allocate and initialize the new data block. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, + &dbno)) || + (error = xfs_dir2_data_init(args, dbno, &dbp))) { + /* + * Drop the freespace buffer unless it came from our + * caller. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return error; + } + /* + * If the freespace entry for this data block is not in the + * freespace block we have in hand, drop the one we have + * and get the right one. + */ + if (XFS_DIR2_DB_TO_FDB(mp, dbno) != fbno) { + xfs_da_brelse(tp, fbp); + if (fblk && fblk->bp) + fblk->bp = NULL; + fbno = XFS_DIR2_DB_TO_FDB(mp, dbno); + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, fbno), -1, &fbp, + XFS_DATA_FORK))) { + xfs_da_buf_done(dbp); + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * Set the freespace block index from the data block number. + */ + findex = XFS_DIR2_DB_TO_FDINDEX(mp, dbno); + /* + * If it's after the end of the current entries in the + * freespace block, extend that table. + */ + if (findex >= INT_GET(free->hdr.nvalid, ARCH_CONVERT)) { + ASSERT(findex < XFS_DIR2_MAX_FREE_BESTS(mp)); + INT_SET(free->hdr.nvalid, ARCH_CONVERT, findex + 1); + /* + * Tag new entry so nused will go up. + */ + INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF); + } + /* + * If this entry was for an empty data block + * (this should always be true) then update the header. + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) == NULLDATAOFF) { + INT_MOD(free->hdr.nused, ARCH_CONVERT, +1); + xfs_dir2_free_log_header(tp, fbp); + } + /* + * Update the real value in the table. + * We haven't allocated the data entry yet so this will + * change again. + */ + data = dbp->data; + INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT); + logfree = 1; + } + /* + * We had a data block so we don't have to make a new one. + */ + else { + /* + * If just checking, we succeeded. + */ + if (args->justcheck) { + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return 0; + } + /* + * Read the data block in. + */ + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, dbno), + -1, &dbp, XFS_DATA_FORK))) { + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return error; + } + data = dbp->data; + logfree = 0; + } + ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) >= length); + /* + * Point to the existing unused space. + */ + dup = (xfs_dir2_data_unused_t *) + ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT)); + needscan = needlog = 0; + /* + * Mark the first part of the unused space, inuse for us. + */ + xfs_dir2_data_use_free(tp, dbp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length, + &needlog, &needscan); + /* + * Fill in the new entry and log it. + */ + dep = (xfs_dir2_data_entry_t *)dup; + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data)); + xfs_dir2_data_log_entry(tp, dbp, dep); + /* + * Rescan the block for bestfree if needed. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + /* + * Log the data block header if needed. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * If the freespace entry is now wrong, update it. + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT); + logfree = 1; + } + /* + * Log the freespace entry if needed. + */ + if (logfree) + xfs_dir2_free_log_bests(tp, fbp, findex, findex); + /* + * If the caller didn't hand us the freespace block, drop it. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + /* + * Return the data block and offset in args, then drop the data block. + */ + args->blkno = (xfs_dablk_t)dbno; + args->index = INT_GET(*tagp, ARCH_CONVERT); + xfs_da_buf_done(dbp); + return 0; +} + +/* + * Lookup an entry in a node-format directory. + * All the real work happens in xfs_da_node_lookup_int. + * The only real output is the inode number of the entry. + */ +int /* error */ +xfs_dir2_node_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + int error; /* error return value */ + int i; /* btree level */ + int rval; /* operation return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_lookup", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Fill in the path to the entry in the cursor. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) + rval = error; + /* + * Release the btree blocks and leaf block. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + /* + * Release the data block if we have it. + */ + if (state->extravalid && state->extrablk.bp) { + xfs_da_brelse(args->trans, state->extrablk.bp); + state->extrablk.bp = NULL; + } + xfs_da_state_free(state); + return rval; +} + +/* + * Remove an entry from a node-format directory. + */ +int /* error */ +xfs_dir2_node_removename( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + int error; /* error return value */ + int rval; /* operation return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_removename", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Look up the entry we're deleting, set up the cursor. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) { + rval = error; + } + /* + * Didn't find it, upper layer screwed up. + */ + if (rval != EEXIST) { + xfs_da_state_free(state); + return rval; + } + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + ASSERT(state->extravalid); + /* + * Remove the leaf and data entries. + * Extrablk refers to the data block. + */ + error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, + &state->extrablk, &rval); + if (error) { + return error; + } + /* + * Fix the hash values up the btree. + */ + xfs_da_fixhashpath(state, &state->path); + /* + * If we need to join leaf blocks, do it. + */ + if (rval && state->path.active > 1) + error = xfs_da_join(state); + /* + * If no errors so far, try conversion to leaf format. + */ + if (!error) + error = xfs_dir2_node_to_leaf(state); + xfs_da_state_free(state); + return error; +} + +/* + * Replace an entry's inode number in a node-format directory. + */ +int /* error */ +xfs_dir2_node_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_data_entry_t *dep; /* data entry changed */ + int error; /* error return value */ + int i; /* btree level */ + xfs_ino_t inum; /* new inode number */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ + int rval; /* internal return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_replace", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + inum = args->inumber; + /* + * Lookup the entry to change in the btree. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) { + rval = error; + } + /* + * It should be found, since the vnodeops layer has looked it up + * and locked it. But paranoia is good. + */ + if (rval == EEXIST) { + /* + * Find the leaf entry. + */ + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + leaf = blk->bp->data; + lep = &leaf->ents[blk->index]; + ASSERT(state->extravalid); + /* + * Point to the data entry. + */ + data = state->extrablk.bp->data; + ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); + dep = (xfs_dir2_data_entry_t *) + ((char *)data + + XFS_DIR2_DATAPTR_TO_OFF(state->mp, INT_GET(lep->address, ARCH_CONVERT))); + ASSERT(inum != INT_GET(dep->inumber, ARCH_CONVERT)); + /* + * Fill in the new inode number and log the entry. + */ + INT_SET(dep->inumber, ARCH_CONVERT, inum); + xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); + rval = 0; + } + /* + * Didn't find it, and we're holding a data block. Drop it. + */ + else if (state->extravalid) { + xfs_da_brelse(args->trans, state->extrablk.bp); + state->extrablk.bp = NULL; + } + /* + * Release all the buffers in the cursor. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + xfs_da_state_free(state); + return rval; +} + +/* + * Trim off a trailing empty freespace block. + * Return (in rvalp) 1 if we did it, 0 if not. + */ +int /* error */ +xfs_dir2_node_trim_free( + xfs_da_args_t *args, /* operation arguments */ + xfs_fileoff_t fo, /* free block number */ + int *rvalp) /* out: did something */ +{ + xfs_dabuf_t *bp; /* freespace buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Read the freespace block. + */ + if ((error = xfs_da_read_buf(tp, dp, (xfs_dablk_t)fo, -1, &bp, + XFS_DATA_FORK))) { + return error; + } + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + /* + * If there are used entries, there's nothing to do. + */ + if (INT_GET(free->hdr.nused, ARCH_CONVERT) > 0) { + xfs_da_brelse(tp, bp); + *rvalp = 0; + return 0; + } + /* + * Blow the block away. + */ + if ((error = + xfs_dir2_shrink_inode(args, XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo), + bp))) { + /* + * Can't fail with ENOSPC since that only happens with no + * space reservation, when breaking up an extent into two + * pieces. This is the last block of an extent. + */ + ASSERT(error != ENOSPC); + xfs_da_brelse(tp, bp); + return error; + } + /* + * Return that we succeeded. + */ + *rvalp = 1; + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_node.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_node.h --- linux-2.4.19/fs/xfs/xfs_dir2_node.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_node.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_NODE_H__ +#define __XFS_DIR2_NODE_H__ + +/* + * Directory version 2, btree node format structures + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_inode; +struct xfs_trans; + +/* + * Constants. + */ + +/* + * Offset of the freespace index. + */ +#define XFS_DIR2_FREE_SPACE 2 +#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_FREE_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_FREE_OFFSET) + +#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F */ + +/* + * Structures. + */ +typedef struct xfs_dir2_free_hdr { + __uint32_t magic; /* XFS_DIR2_FREE_MAGIC */ + __int32_t firstdb; /* db of first entry */ + __int32_t nvalid; /* count of valid entries */ + __int32_t nused; /* count of used entries */ +} xfs_dir2_free_hdr_t; + +typedef struct xfs_dir2_free { + xfs_dir2_free_hdr_t hdr; /* block header */ + xfs_dir2_data_off_t bests[1]; /* best free counts */ + /* unused entries are -1 */ +} xfs_dir2_free_t; +#define XFS_DIR2_MAX_FREE_BESTS(mp) \ + (((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_free_hdr_t)) / \ + (uint)sizeof(xfs_dir2_data_off_t)) + +/* + * Macros. + */ + +/* + * Convert data space db to the corresponding free db. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_FDB) +xfs_dir2_db_t +xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_FDB(mp,db) xfs_dir2_db_to_fdb(mp, db) +#else +#define XFS_DIR2_DB_TO_FDB(mp,db) \ + (XFS_DIR2_FREE_FIRSTDB(mp) + (db) / XFS_DIR2_MAX_FREE_BESTS(mp)) +#endif + +/* + * Convert data space db to the corresponding index in a free db. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_FDINDEX) +int +xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_FDINDEX(mp,db) xfs_dir2_db_to_fdindex(mp, db) +#else +#define XFS_DIR2_DB_TO_FDINDEX(mp,db) ((db) % XFS_DIR2_MAX_FREE_BESTS(mp)) +#endif + +/* + * Functions. + */ + +extern void + xfs_dir2_free_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern int + xfs_dir2_leaf_to_node(struct xfs_da_args *args, struct xfs_dabuf *lbp); + +extern xfs_dahash_t + xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count); + +extern int + xfs_dir2_leafn_lookup_int(struct xfs_dabuf *bp, + struct xfs_da_args *args, int *indexp, + struct xfs_da_state *state); + +extern int + xfs_dir2_leafn_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); + +extern int + xfs_dir2_leafn_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); + +extern int + xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action); + +extern void + xfs_dir2_leafn_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); + +extern int + xfs_dir2_node_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_node_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_node_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_node_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo, + int *rvalp); + +#endif /* __XFS_DIR2_NODE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_sf.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_sf.c --- linux-2.4.19/fs/xfs/xfs_dir2_sf.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_sf.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,1320 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_sf.c + * Shortform directory implementation for v2 directories. + */ + +#include + +/* + * Prototypes for internal functions. + */ +static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args, + xfs_dir2_sf_entry_t *sfep, + xfs_dir2_data_aoff_t offset, + int new_isize); +static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange, + int new_isize); +static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange, + xfs_dir2_sf_entry_t **sfepp, + xfs_dir2_data_aoff_t *offsetp); +#ifdef DEBUG +static void xfs_dir2_sf_check(xfs_da_args_t *args); +#else +#define xfs_dir2_sf_check(args) +#endif /* DEBUG */ +#if XFS_BIG_FILESYSTEMS +static void xfs_dir2_sf_toino4(xfs_da_args_t *args); +static void xfs_dir2_sf_toino8(xfs_da_args_t *args); +#endif /* XFS_BIG_FILESYSTEMS */ + +/* + * Given a block directory (dp/block), calculate its size as a shortform (sf) + * directory and a header for the sf directory, if it will fit it the + * space currently present in the inode. If it won't fit, the output + * size is too big (but not accurate). + */ +int /* size for sf form */ +xfs_dir2_block_sfsize( + xfs_inode_t *dp, /* incore inode pointer */ + xfs_dir2_block_t *block, /* block directory data */ + xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ +{ + xfs_dir2_dataptr_t addr; /* data entry address */ + xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ + xfs_dir2_block_tail_t *btp; /* tail area of the block */ + int count; /* shortform entry count */ + xfs_dir2_data_entry_t *dep; /* data entry in the block */ + int i; /* block entry index */ + int i8count; /* count of big-inode entries */ + int isdot; /* entry is "." */ + int isdotdot; /* entry is ".." */ + xfs_mount_t *mp; /* mount structure pointer */ + int namelen; /* total name bytes */ + xfs_ino_t parent; /* parent inode number */ + int size=0; /* total computed size */ + + mp = dp->i_mount; + + count = i8count = namelen = 0; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + + /* + * Iterate over the block's data entries by using the leaf pointers. + */ + for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if ((addr = INT_GET(blp[i].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Calculate the pointer to the entry at hand. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr)); + /* + * Detect . and .., so we can special-case them. + * . is not included in sf directories. + * .. is included by just the parent inode number. + */ + isdot = dep->namelen == 1 && dep->name[0] == '.'; + isdotdot = + dep->namelen == 2 && + dep->name[0] == '.' && dep->name[1] == '.'; +#if XFS_BIG_FILESYSTEMS + if (!isdot) + i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM; +#endif + if (!isdot && !isdotdot) { + count++; + namelen += dep->namelen; + } else if (isdotdot) + parent = INT_GET(dep->inumber, ARCH_CONVERT); + /* + * Calculate the new size, see if we should give up yet. + */ + size = XFS_DIR2_SF_HDR_SIZE(i8count) + /* header */ + count + /* namelen */ + count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */ + namelen + /* name */ + (i8count ? /* inumber */ + (uint)sizeof(xfs_dir2_ino8_t) * count : + (uint)sizeof(xfs_dir2_ino4_t) * count); + if (size > XFS_IFORK_DSIZE(dp)) + return size; /* size value is a failure */ + } + /* + * Create the output header, if it worked. + */ + sfhp->count = count; + sfhp->i8count = i8count; + XFS_DIR2_SF_PUT_INUMBER_ARCH((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent, ARCH_CONVERT); + return size; +} + +/* + * Convert a block format directory to shortform. + * Caller has already checked that it will fit, and built us a header. + */ +int /* error */ +xfs_dir2_block_to_sf( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp, /* block buffer */ + int size, /* shortform directory size */ + xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_block_tail_t *btp; /* block tail pointer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused data pointer */ + char *endptr; /* end of data entries */ + int error; /* error return value */ + int logflags; /* inode logging flags */ + xfs_mount_t *mp; /* filesystem mount point */ + char *ptr; /* current data pointer */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_ino_t temp; + + xfs_dir2_trace_args_sb("block_to_sf", args, size, bp); + dp = args->dp; + mp = dp->i_mount; + + /* + * Make a copy of the block data, so we can shrink the inode + * and add local data. + */ + block = kmem_alloc(mp->m_dirblksize, KM_SLEEP); + bcopy(bp->data, block, mp->m_dirblksize); + logflags = XFS_ILOG_CORE; + if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) { + ASSERT(error != ENOSPC); + goto out; + } + /* + * The buffer is now unconditionally gone, whether + * xfs_dir2_shrink_inode worked or not. + * + * Convert the inode to local format. + */ + dp->i_df.if_flags &= ~XFS_IFEXTENTS; + dp->i_df.if_flags |= XFS_IFINLINE; + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + ASSERT(dp->i_df.if_bytes == 0); + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + logflags |= XFS_ILOG_DDATA; + /* + * Copy the header into the newly allocate local space. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + bcopy(sfhp, sfp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count)); + dp->i_d.di_size = size; + /* + * Set up to loop over the block's entries. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + ptr = (char *)block->u; + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + /* + * Loop over the active and unused entries. + * Stop when we reach the leaf/tail portion of the block. + */ + while (ptr < endptr) { + /* + * If it's unused, just skip over it. + */ + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + /* + * Skip . + */ + if (dep->namelen == 1 && dep->name[0] == '.') + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == dp->i_ino); + /* + * Skip .., but make sure the inode number is right. + */ + else if (dep->namelen == 2 && + dep->name[0] == '.' && dep->name[1] == '.') + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == + XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT)); + /* + * Normal entry, copy it into shortform. + */ + else { + sfep->namelen = dep->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, + (xfs_dir2_data_aoff_t) + ((char *)dep - (char *)block), ARCH_CONVERT); + bcopy(dep->name, sfep->name, dep->namelen); + temp=INT_GET(dep->inumber, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &temp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + ASSERT((char *)sfep - (char *)sfp == size); + xfs_dir2_sf_check(args); +out: + xfs_trans_log_inode(args->trans, dp, logflags); + kmem_free(block, mp->m_dirblksize); + return error; +} + +/* + * Add a name to a shortform directory. + * There are two algorithms, "easy" and "hard" which we decide on + * before changing anything. + * Convert to block form if necessary, if the new entry won't fit. + */ +int /* error */ +xfs_dir2_sf_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + int add_entsize; /* size of the new entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int incr_isize; /* total change in size */ + int new_isize; /* di_size after adding name */ + int objchange; /* changing to 8-byte inodes */ + xfs_dir2_data_aoff_t offset; /* offset for new entry */ + int old_isize; /* di_size before adding name */ + int pick; /* which algorithm to use */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + + xfs_dir2_trace_args("sf_addname", args); + ASSERT(xfs_dir2_sf_lookup(args) == ENOENT); + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Make sure the shortform value has some of its header. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Compute entry (and change in) size. + */ + add_entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen); + incr_isize = add_entsize; +#if XFS_BIG_FILESYSTEMS + /* + * Do we have to change to 8 byte inodes? + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) { + /* + * Yes, adjust the entry size and the total size. + */ + add_entsize += + (uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t); + incr_isize += + (sfp->hdr.count + 2) * + ((uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t)); + objchange = 1; + } else + objchange = 0; +#else + objchange = 0; +#endif + old_isize = (int)dp->i_d.di_size; + new_isize = old_isize + incr_isize; + /* + * Won't fit as shortform any more (due to size), + * or the pick routine says it won't (due to offset values). + */ + if (new_isize > XFS_IFORK_DSIZE(dp) || + (pick = + xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { + /* + * Just checking or no space reservation, it doesn't fit. + */ + if (args->justcheck || args->total == 0) + return XFS_ERROR(ENOSPC); + /* + * Convert to block form then add the name. + */ + error = xfs_dir2_sf_to_block(args); + if (error) + return error; + return xfs_dir2_block_addname(args); + } + /* + * Just checking, it fits. + */ + if (args->justcheck) + return 0; + /* + * Do it the easy way - just add it at the end. + */ + if (pick == 1) + xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); + /* + * Do it the hard way - look for a place to insert the new entry. + * Convert to 8 byte inode numbers first if necessary. + */ + else { + ASSERT(pick == 2); +#if XFS_BIG_FILESYSTEMS + if (objchange) + xfs_dir2_sf_toino8(args); +#endif + xfs_dir2_sf_addname_hard(args, objchange, new_isize); + } + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +/* + * Add the new entry the "easy" way. + * This is copying the old directory and adding the new entry at the end. + * Since it's sorted by "offset" we need room after the last offset + * that's already there, and then room to convert to a block directory. + * This is already checked by the pick routine. + */ +static void +xfs_dir2_sf_addname_easy( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ + xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ + int new_isize) /* new directory size */ +{ + int byteoff; /* byte offset in sf dir */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + byteoff = (int)((char *)sfep - (char *)sfp); + /* + * Grow the in-inode space. + */ + xfs_idata_realloc(dp, XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen), + XFS_DATA_FORK); + /* + * Need to set up again due to realloc of the inode data. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); + /* + * Fill in the new entry. + */ + sfep->namelen = args->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT); + bcopy(args->name, sfep->name, sfep->namelen); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + /* + * Update the header and inode. + */ + sfp->hdr.count++; +#if XFS_BIG_FILESYSTEMS + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) + sfp->hdr.i8count++; +#endif + dp->i_d.di_size = new_isize; + xfs_dir2_sf_check(args); +} + +/* + * Add the new entry the "hard" way. + * The caller has already converted to 8 byte inode numbers if necessary, + * in which case we need to leave the i8count at 1. + * Find a hole that the new entry will fit into, and copy + * the first part of the entries, the new entry, and the last part of + * the entries. + */ +/* ARGSUSED */ +static void +xfs_dir2_sf_addname_hard( + xfs_da_args_t *args, /* operation arguments */ + int objchange, /* changing inode number size */ + int new_isize) /* new directory size */ +{ + int add_datasize; /* data size need for new ent */ + char *buf; /* buffer for old */ + xfs_inode_t *dp; /* incore directory inode */ + int eof; /* reached end of old dir */ + int nbytes; /* temp for byte copies */ + xfs_dir2_data_aoff_t new_offset; /* next offset value */ + xfs_dir2_data_aoff_t offset; /* current offset value */ + int old_isize; /* previous di_size */ + xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ + xfs_dir2_sf_t *oldsfp; /* original shortform dir */ + xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ + xfs_dir2_sf_t *sfp; /* new shortform dir */ + + /* + * Copy the old directory to the stack buffer. + */ + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + old_isize = (int)dp->i_d.di_size; + buf = kmem_alloc(old_isize, KM_SLEEP); + oldsfp = (xfs_dir2_sf_t *)buf; + bcopy(sfp, oldsfp, old_isize); + /* + * Loop over the old directory finding the place we're going + * to insert the new entry. + * If it's going to end up at the end then oldsfep will point there. + */ + for (offset = XFS_DIR2_DATA_FIRST_OFFSET, + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp), + add_datasize = XFS_DIR2_DATA_ENTSIZE(args->namelen), + eof = (char *)oldsfep == &buf[old_isize]; + !eof; + offset = new_offset + XFS_DIR2_DATA_ENTSIZE(oldsfep->namelen), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep), + eof = (char *)oldsfep == &buf[old_isize]) { + new_offset = XFS_DIR2_SF_GET_OFFSET_ARCH(oldsfep, ARCH_CONVERT); + if (offset + add_datasize <= new_offset) + break; + } + /* + * Get rid of the old directory, then allocate space for + * the new one. We do this so xfs_idata_realloc won't copy + * the data. + */ + xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); + xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); + /* + * Reset the pointer since the buffer was reallocated. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Copy the first part of the directory, including the header. + */ + nbytes = (int)((char *)oldsfep - (char *)oldsfp); + bcopy(oldsfp, sfp, nbytes); + sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); + /* + * Fill in the new entry, and update the header counts. + */ + sfep->namelen = args->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT); + bcopy(args->name, sfep->name, sfep->namelen); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + sfp->hdr.count++; +#if XFS_BIG_FILESYSTEMS + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) + sfp->hdr.i8count++; +#endif + /* + * If there's more left to copy, do that. + */ + if (!eof) { + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + bcopy(oldsfep, sfep, old_isize - nbytes); + } + kmem_free(buf, old_isize); + dp->i_d.di_size = new_isize; + xfs_dir2_sf_check(args); +} + +/* + * Decide if the new entry will fit at all. + * If it will fit, pick between adding the new entry to the end (easy) + * or somewhere else (hard). + * Return 0 (won't fit), 1 (easy), 2 (hard). + */ +/*ARGSUSED*/ +static int /* pick result */ +xfs_dir2_sf_addname_pick( + xfs_da_args_t *args, /* operation arguments */ + int objchange, /* inode # size changes */ + xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ + xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int holefit; /* found hole it will fit in */ + int i; /* entry number */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_data_aoff_t offset; /* data block offset */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + int size; /* entry's data size */ + int used; /* data bytes used */ + + dp = args->dp; + mp = dp->i_mount; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + size = XFS_DIR2_DATA_ENTSIZE(args->namelen); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + holefit = 0; + /* + * Loop over sf entries. + * Keep track of data offset and whether we've seen a place + * to insert the new entry. + */ + for (i = 0; i < sfp->hdr.count; i++) { + if (!holefit) + holefit = offset + size <= XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT); + offset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(sfep->namelen); + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + /* + * Calculate data bytes used excluding the new entry, if this + * was a data block (block form directory). + */ + used = offset + + (sfp->hdr.count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + + (uint)sizeof(xfs_dir2_block_tail_t); + /* + * If it won't fit in a block form then we can't insert it, + * we'll go back, convert to block, then try the insert and convert + * to leaf. + */ + if (used + (holefit ? 0 : size) > mp->m_dirblksize) + return 0; + /* + * If changing the inode number size, do it the hard way. + */ +#if XFS_BIG_FILESYSTEMS + if (objchange) { + return 2; + } +#else + ASSERT(objchange == 0); +#endif + /* + * If it won't fit at the end then do it the hard way (use the hole). + */ + if (used + size > mp->m_dirblksize) + return 2; + /* + * Do it the easy way. + */ + *sfepp = sfep; + *offsetp = offset; + return 1; +} + +#ifdef DEBUG +/* + * Check consistency of shortform directory, assert if bad. + */ +static void +xfs_dir2_sf_check( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry number */ + int i8count; /* number of big inode#s */ + xfs_ino_t ino; /* entry inode number */ + int offset; /* data offset */ + xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + offset = XFS_DIR2_DATA_FIRST_OFFSET; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + i8count = ino > XFS_DIR2_MAX_SHORT_INUM; + + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + ASSERT(XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) >= offset); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + i8count += ino > XFS_DIR2_MAX_SHORT_INUM; + offset = + XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(sfep->namelen); + } + ASSERT(i8count == sfp->hdr.i8count); +#if !XFS_BIG_FILESYSTEMS + ASSERT(i8count == 0); +#endif + ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); + ASSERT(offset + + (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + + (uint)sizeof(xfs_dir2_block_tail_t) <= + dp->i_mount->m_dirblksize); +} +#endif /* DEBUG */ + +/* + * Create a new (shortform) directory. + */ +int /* error, always 0 */ +xfs_dir2_sf_create( + xfs_da_args_t *args, /* operation arguments */ + xfs_ino_t pino) /* parent inode number */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i8count; /* parent inode is an 8-byte number */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + int size; /* directory size */ + + xfs_dir2_trace_args_i("sf_create", args, pino); + dp = args->dp; + + ASSERT(dp != NULL); + ASSERT(dp->i_d.di_size == 0); + /* + * If it's currently a zero-length extent file, + * convert it to local format. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { + dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); + dp->i_df.if_flags |= XFS_IFINLINE; + } + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + ASSERT(dp->i_df.if_bytes == 0); + i8count = pino > XFS_DIR2_MAX_SHORT_INUM; + size = XFS_DIR2_SF_HDR_SIZE(i8count); + /* + * Make a buffer for the data. + */ + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + /* + * Fill in the header, + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + sfp->hdr.i8count = i8count; + /* + * Now can put in the inode number, since i8count is set. + */ + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &pino, &sfp->hdr.parent, ARCH_CONVERT); + sfp->hdr.count = 0; + dp->i_d.di_size = size; + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +int /* error */ +xfs_dir2_sf_getdents( + xfs_inode_t *dp, /* incore directory inode */ + uio_t *uio, /* caller's buffer control */ + int *eofp, /* eof reached? (out) */ + xfs_dirent_t *dbp, /* caller's buffer */ + xfs_dir2_put_t put) /* abi's formatting function */ +{ + int error; /* error return value */ + int i; /* shortform entry number */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_dataptr_t off; /* current entry's offset */ + xfs_dir2_put_args_t p; /* arg package for put rtn */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_off_t dir_offset; + + mp = dp->i_mount; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Give up if the directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + return XFS_ERROR(EIO); + } + + dir_offset = uio->uio_offset; + + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + + /* + * If the block number in the offset is out of range, we're done. + */ + if (XFS_DIR2_DATAPTR_TO_DB(mp, dir_offset) > mp->m_dirdatablk) { + *eofp = 1; + return 0; + } + + /* + * Set up putargs structure. + */ + p.dbp = dbp; + p.put = put; + p.uio = uio; + /* + * Put . entry unless we're starting past it. + */ + if (dir_offset <= + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOT_OFFSET)) { + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, 0, + XFS_DIR2_DATA_DOT_OFFSET); +#if XFS_BIG_FILESYSTEMS + p.ino = dp->i_ino + mp->m_inoadd; +#else + p.ino = dp->i_ino; +#endif + p.name = "."; + p.namelen = 1; + + error = p.put(&p); + + if (!p.done) { + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOT_OFFSET); + return error; + } + } + + /* + * Put .. entry unless we're starting past it. + */ + if (dir_offset <= + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOTDOT_OFFSET)) { + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOTDOT_OFFSET); +#if XFS_BIG_FILESYSTEMS + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT) + + mp->m_inoadd; +#else + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); +#endif + p.name = ".."; + p.namelen = 2; + + error = p.put(&p); + + if (!p.done) { + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOTDOT_OFFSET); + return error; + } + } + + /* + * Loop while there are more entries and put'ing works. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + + off = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT)); + + if (dir_offset > off) + continue; + + p.namelen = sfep->namelen; + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT)); + +#if XFS_BIG_FILESYSTEMS + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) + + mp->m_inoadd; +#else + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); +#endif + p.name = (char *)sfep->name; + + error = p.put(&p); + + if (!p.done) { + uio->uio_offset = off; + return error; + } + } + + /* + * They all fit. + */ + *eofp = 1; + + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0); + + return 0; +} + +/* + * Lookup an entry in a shortform directory. + * Returns EEXIST if found, ENOENT if not found. + */ +int /* error */ +xfs_dir2_sf_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_lookup", args); + xfs_dir2_sf_check(args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bail out if the directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Special case for . + */ + if (args->namelen == 1 && args->name[0] == '.') { + args->inumber = dp->i_ino; + return XFS_ERROR(EEXIST); + } + /* + * Special case for .. + */ + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + args->inumber = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + return XFS_ERROR(EEXIST); + } + /* + * Loop over all the entries trying to match ours. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(args->name, sfep->name, args->namelen) == 0) { + args->inumber = + XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + return XFS_ERROR(EEXIST); + } + } + /* + * Didn't find it. + */ + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a shortform directory. + */ +int /* error */ +xfs_dir2_sf_removename( + xfs_da_args_t *args) +{ + int byteoff; /* offset of removed entry */ + xfs_inode_t *dp; /* incore directory inode */ + int entsize; /* this entry's size */ + int i; /* shortform entry index */ + int newsize; /* new inode size */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_removename", args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + oldsize = (int)dp->i_d.di_size; + /* + * Bail out if the directory is way too short. + */ + if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == oldsize); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsize >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Loop over the old directory entries. + * Find the one we're deleting. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(sfep->name, args->name, args->namelen) == 0) { + ASSERT(XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) == + args->inumber); + break; + } + } + /* + * Didn't find it. + */ + if (i == sfp->hdr.count) { + return XFS_ERROR(ENOENT); + } + /* + * Calculate sizes. + */ + byteoff = (int)((char *)sfep - (char *)sfp); + entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen); + newsize = oldsize - entsize; + /* + * Copy the part if any after the removed entry, sliding it down. + */ + if (byteoff + entsize < oldsize) + ovbcopy((char *)sfp + byteoff + entsize, (char *)sfp + byteoff, + oldsize - (byteoff + entsize)); + /* + * Fix up the header and file size. + */ + sfp->hdr.count--; + dp->i_d.di_size = newsize; + /* + * Reallocate, making it smaller. + */ + xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; +#if XFS_BIG_FILESYSTEMS + /* + * Are we changing inode number size? + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { + if (sfp->hdr.i8count == 1) + xfs_dir2_sf_toino4(args); + else + sfp->hdr.i8count--; + } +#endif + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +/* + * Replace the inode number of an entry in a shortform directory. + */ +int /* error */ +xfs_dir2_sf_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + xfs_ino_t ino=0; /* entry old inode number */ +#endif +#if XFS_BIG_FILESYSTEMS + int i8elevated; /* sf_toino8 set i8count=1 */ +#endif + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_replace", args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bail out if the shortform directory is way too small. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); +#if XFS_BIG_FILESYSTEMS + /* + * New inode number is large, and need to convert to 8-byte inodes. + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) { + int error; /* error return value */ + int newsize; /* new inode size */ + + newsize = + dp->i_df.if_bytes + + (sfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t)); + /* + * Won't fit as shortform, convert to block then do replace. + */ + if (newsize > XFS_IFORK_DSIZE(dp)) { + error = xfs_dir2_sf_to_block(args); + if (error) { + return error; + } + return xfs_dir2_block_replace(args); + } + /* + * Still fits, convert to 8-byte now. + */ + xfs_dir2_sf_toino8(args); + i8elevated = 1; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + } else + i8elevated = 0; +#endif + ASSERT(args->namelen != 1 || args->name[0] != '.'); + /* + * Replace ..'s entry. + */ + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + ASSERT(args->inumber != ino); +#endif + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, &sfp->hdr.parent, ARCH_CONVERT); + } + /* + * Normal entry, look for the name. + */ + else { + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(args->name, sfep->name, args->namelen) == 0) { +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + ASSERT(args->inumber != ino); +#endif + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + break; + } + } + /* + * Didn't find it. + */ + if (i == sfp->hdr.count) { + ASSERT(args->oknoent); +#if XFS_BIG_FILESYSTEMS + if (i8elevated) + xfs_dir2_sf_toino4(args); +#endif + return XFS_ERROR(ENOENT); + } + } +#if XFS_BIG_FILESYSTEMS + /* + * See if the old number was large, the new number is small. + */ + if (ino > XFS_DIR2_MAX_SHORT_INUM && + args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { + /* + * And the old count was one, so need to convert to small. + */ + if (sfp->hdr.i8count == 1) + xfs_dir2_sf_toino4(args); + else + sfp->hdr.i8count--; + } + /* + * See if the old number was small, the new number is large. + */ + if (ino <= XFS_DIR2_MAX_SHORT_INUM && + args->inumber > XFS_DIR2_MAX_SHORT_INUM) { + /* + * add to the i8count unless we just converted to 8-byte + * inodes (which does an implied i8count = 1) + */ + ASSERT(sfp->hdr.i8count != 0); + if (!i8elevated) + sfp->hdr.i8count++; + } +#endif + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return 0; +} + +#if XFS_BIG_FILESYSTEMS +/* + * Convert from 8-byte inode numbers to 4-byte inode numbers. + * The last 8-byte inode number is gone, but the count is still 1. + */ +static void +xfs_dir2_sf_toino4( + xfs_da_args_t *args) /* operation arguments */ +{ + char *buf; /* old dir's buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_ino_t ino; /* entry inode number */ + int newsize; /* new inode size */ + xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ + xfs_dir2_sf_t *oldsfp; /* old sf directory */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* new sf entry */ + xfs_dir2_sf_t *sfp; /* new sf directory */ + + xfs_dir2_trace_args("sf_toino4", args); + dp = args->dp; + + /* + * Copy the old directory to the buffer. + * Then nuke it from the inode, and add the new buffer to the inode. + * Don't want xfs_idata_realloc copying the data here. + */ + oldsize = dp->i_df.if_bytes; + buf = kmem_alloc(oldsize, KM_SLEEP); + oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsfp->hdr.i8count == 1); + bcopy(oldsfp, buf, oldsize); + /* + * Compute the new inode size. + */ + newsize = + oldsize - + (oldsfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); + xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); + xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); + /* + * Reset our pointers, the data has moved. + */ + oldsfp = (xfs_dir2_sf_t *)buf; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Fill in the new header. + */ + sfp->hdr.count = oldsfp->hdr.count; + sfp->hdr.i8count = 0; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT); + /* + * Copy the entries field by field. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp), + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) { + sfep->namelen = oldsfep->namelen; + sfep->offset = oldsfep->offset; + bcopy(oldsfep->name, sfep->name, sfep->namelen); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, + XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + } + /* + * Clean up the inode. + */ + kmem_free(buf, oldsize); + dp->i_d.di_size = newsize; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); +} + +/* + * Convert from 4-byte inode numbers to 8-byte inode numbers. + * The new 8-byte inode number is not there yet, we leave with the + * count 1 but no corresponding entry. + */ +static void +xfs_dir2_sf_toino8( + xfs_da_args_t *args) /* operation arguments */ +{ + char *buf; /* old dir's buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_ino_t ino; /* entry inode number */ + int newsize; /* new inode size */ + xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ + xfs_dir2_sf_t *oldsfp; /* old sf directory */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* new sf entry */ + xfs_dir2_sf_t *sfp; /* new sf directory */ + + xfs_dir2_trace_args("sf_toino8", args); + dp = args->dp; + + /* + * Copy the old directory to the buffer. + * Then nuke it from the inode, and add the new buffer to the inode. + * Don't want xfs_idata_realloc copying the data here. + */ + oldsize = dp->i_df.if_bytes; + buf = kmem_alloc(oldsize, KM_SLEEP); + oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsfp->hdr.i8count == 0); + bcopy(oldsfp, buf, oldsize); + /* + * Compute the new inode size. + */ + newsize = + oldsize + + (oldsfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); + xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); + xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); + /* + * Reset our pointers, the data has moved. + */ + oldsfp = (xfs_dir2_sf_t *)buf; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Fill in the new header. + */ + sfp->hdr.count = oldsfp->hdr.count; + sfp->hdr.i8count = 1; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT); + /* + * Copy the entries field by field. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp), + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) { + sfep->namelen = oldsfep->namelen; + sfep->offset = oldsfep->offset; + bcopy(oldsfep->name, sfep->name, sfep->namelen); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, + XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + } + /* + * Clean up the inode. + */ + kmem_free(buf, oldsize); + dp->i_d.di_size = newsize; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); +} +#endif /* XFS_BIG_FILESYSTEMS */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_sf.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_sf.h --- linux-2.4.19/fs/xfs/xfs_dir2_sf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_sf.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_SF_H__ +#define __XFS_DIR2_SF_H__ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_block; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Maximum size of a shortform directory. + */ +#define XFS_DIR2_SF_MAX_SIZE \ + (XFS_DINODE_MAX_SIZE - (uint)sizeof(xfs_dinode_core_t) - \ + (uint)sizeof(xfs_agino_t)) + +/* + * Inode number stored as 8 8-bit values. + */ +typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t; + +#define XFS_DIR2_SF_GET_INO8_ARCH(di,arch) \ + (xfs_ino_t)(DIRINO_GET_ARCH(&di,arch)) +#define XFS_DIR2_SF_GET_INO8(di) \ + XFS_DIR2_SF_GET_INO8_ARCH(di,ARCH_NOCONVERT) + +/* + * Inode number stored as 4 8-bit values. + * Works a lot of the time, when all the inode numbers in a directory + * fit in 32 bits. + */ +typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t; +#define XFS_DIR2_SF_GET_INO4_ARCH(di,arch) \ + (xfs_ino_t)(DIRINO4_GET_ARCH(&di,arch)) +#define XFS_DIR2_SF_GET_INO4(di) \ + XFS_DIR2_SF_GET_INO4_ARCH(di,ARCH_NOCONVERT) + +typedef union { + xfs_dir2_ino8_t i8; + xfs_dir2_ino4_t i4; +} xfs_dir2_inou_t; +#define XFS_DIR2_MAX_SHORT_INUM ((xfs_ino_t)0xffffffffULL) + +/* + * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. + * Only need 16 bits, this is the byte offset into the single block form. + */ +typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tightly as possible. The header + * and the elements must be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir2_sf_hdr { + __uint8_t count; /* count of entries */ + __uint8_t i8count; /* count of 8-byte inode #s */ + xfs_dir2_inou_t parent; /* parent dir inode number */ +} xfs_dir2_sf_hdr_t; + +typedef struct xfs_dir2_sf_entry { + __uint8_t namelen; /* actual name length */ + xfs_dir2_sf_off_t offset; /* saved offset */ + __uint8_t name[1]; /* name, variable size */ + xfs_dir2_inou_t inumber; /* inode number, var. offset */ +} xfs_dir2_sf_entry_t; + +typedef struct xfs_dir2_sf { + xfs_dir2_sf_hdr_t hdr; /* shortform header */ + xfs_dir2_sf_entry_t list[1]; /* shortform entries */ +} xfs_dir2_sf_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_HDR_SIZE) +int xfs_dir2_sf_hdr_size(int i8count); +#define XFS_DIR2_SF_HDR_SIZE(i8count) xfs_dir2_sf_hdr_size(i8count) +#else +#define XFS_DIR2_SF_HDR_SIZE(i8count) \ + ((uint)sizeof(xfs_dir2_sf_hdr_t) - \ + ((i8count) == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_INUMBERP) +xfs_dir2_inou_t *xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_INUMBERP(sfep) xfs_dir2_sf_inumberp(sfep) +#else +#define XFS_DIR2_SF_INUMBERP(sfep) \ + ((xfs_dir2_inou_t *)&(sfep)->name[(sfep)->namelen]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_INUMBER) +xfs_intino_t xfs_dir2_sf_get_inumber_arch(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from, + xfs_arch_t arch); +#define XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch) \ + xfs_dir2_sf_get_inumber_arch(sfp, from, arch) + +#else +#define XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch) \ + ((sfp)->hdr.i8count == 0 ? \ + (xfs_intino_t)XFS_DIR2_SF_GET_INO4_ARCH(*(from), arch) : \ + (xfs_intino_t)XFS_DIR2_SF_GET_INO8_ARCH(*(from), arch)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_INUMBER) +void xfs_dir2_sf_put_inumber_arch(xfs_dir2_sf_t *sfp, xfs_ino_t *from, + xfs_dir2_inou_t *to, xfs_arch_t arch); +#define XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch) \ + xfs_dir2_sf_put_inumber_arch(sfp,from,to,arch) +#else +#define XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch) \ + if ((sfp)->hdr.i8count == 0) { \ + DIRINO4_COPY_ARCH(from,to,arch); \ + } else { \ + DIRINO_COPY_ARCH(from,to,arch); \ + } +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_OFFSET) +xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset_arch(xfs_dir2_sf_entry_t *sfep, + xfs_arch_t arch); +xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch) \ + xfs_dir2_sf_get_offset_arch(sfep,arch) +#else +#define XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch) \ + INT_GET_UNALIGNED_16_ARCH(&(sfep)->offset.i,arch) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_OFFSET) +void xfs_dir2_sf_put_offset_arch(xfs_dir2_sf_entry_t *sfep, + xfs_dir2_data_aoff_t off, xfs_arch_t arch); +#define XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch) \ + xfs_dir2_sf_put_offset_arch(sfep,off,arch) +#else +#define XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch) \ + INT_SET_UNALIGNED_16_ARCH(&(sfep)->offset.i,off,arch) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_ENTSIZE_BYNAME) +int xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len); +#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) \ + xfs_dir2_sf_entsize_byname(sfp,len) +#else +#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) /* space a name uses */ \ + ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (len) - \ + ((sfp)->hdr.i8count == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_ENTSIZE_BYENTRY) +int xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) \ + xfs_dir2_sf_entsize_byentry(sfp,sfep) +#else +#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) /* space an entry uses */ \ + ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (sfep)->namelen - \ + ((sfp)->hdr.i8count == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_FIRSTENTRY) +xfs_dir2_sf_entry_t *xfs_dir2_sf_firstentry(xfs_dir2_sf_t *sfp); +#define XFS_DIR2_SF_FIRSTENTRY(sfp) xfs_dir2_sf_firstentry(sfp) +#else +#define XFS_DIR2_SF_FIRSTENTRY(sfp) /* first entry in struct */ \ + ((xfs_dir2_sf_entry_t *) \ + ((char *)(sfp) + XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_NEXTENTRY) +xfs_dir2_sf_entry_t *xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp, + xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) xfs_dir2_sf_nextentry(sfp,sfep) +#else +#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) /* next entry in struct */ \ + ((xfs_dir2_sf_entry_t *) \ + ((char *)(sfep) + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep))) +#endif + +/* + * Functions. + */ + +extern int + xfs_dir2_block_sfsize(struct xfs_inode *dp, + struct xfs_dir2_block *block, + xfs_dir2_sf_hdr_t *sfhp); + +extern int + xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_dabuf *bp, + int size, xfs_dir2_sf_hdr_t *sfhp); + +extern int + xfs_dir2_sf_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); + +extern int + xfs_dir2_sf_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp, + struct xfs_dirent *dbp, xfs_dir2_put_t put); + +extern int + xfs_dir2_sf_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_replace(struct xfs_da_args *args); + +#endif /* __XFS_DIR2_SF_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_trace.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_trace.c --- linux-2.4.19/fs/xfs/xfs_dir2_trace.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_trace.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_trace.c + * Tracing for xfs v2 directories. + */ +#include + + +#ifdef DEBUG +ktrace_t *xfs_dir2_trace_buf; +#endif /* DEBUG */ + +#ifdef XFS_DIR2_TRACE +/* + * Enter something in the trace buffers. + */ +static void +xfs_dir2_trace_enter( + xfs_inode_t *dp, + int type, + char *where, + char *name, + int namelen, + __psunsigned_t a0, + __psunsigned_t a1, + __psunsigned_t a2, + __psunsigned_t a3, + __psunsigned_t a4, + __psunsigned_t a5, + __psunsigned_t a6) +{ + __psunsigned_t n[6]; + + ASSERT(xfs_dir2_trace_buf); + ASSERT(dp->i_dir_trace); + if (name) + bcopy(name, n, min(sizeof(n), namelen)); + else + bzero((char *)n, sizeof(n)); + ktrace_enter(xfs_dir2_trace_buf, + (void *)(__psunsigned_t)type, (void *)where, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, + (void *)(__psunsigned_t)namelen, + (void *)n[0], (void *)n[1], (void *)n[2], + (void *)n[3], (void *)n[4], (void *)n[5]); + ktrace_enter(dp->i_dir_trace, + (void *)(__psunsigned_t)type, (void *)where, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, + (void *)(__psunsigned_t)namelen, + (void *)n[0], (void *)n[1], (void *)n[2], + (void *)n[3], (void *)n[4], (void *)n[5]); +} + +void +xfs_dir2_trace_args( + char *where, + xfs_da_args_t *args) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, 0, 0); +} + +void +xfs_dir2_trace_args_b( + char *where, + xfs_da_args_t *args, + xfs_dabuf_t *bp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_B, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, + (__psunsigned_t)(bp ? bp->bps[0] : NULL), 0); +} + +void +xfs_dir2_trace_args_bb( + char *where, + xfs_da_args_t *args, + xfs_dabuf_t *lbp, + xfs_dabuf_t *dbp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_BB, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, + (__psunsigned_t)(lbp ? lbp->bps[0] : NULL), + (__psunsigned_t)(dbp ? dbp->bps[0] : NULL)); +} + +void +xfs_dir2_trace_args_bibii( + char *where, + xfs_da_args_t *args, + xfs_dabuf_t *bs, + int ss, + xfs_dabuf_t *bd, + int sd, + int c) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_BIBII, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)(bs ? bs->bps[0] : NULL), (__psunsigned_t)ss, + (__psunsigned_t)(bd ? bd->bps[0] : NULL), (__psunsigned_t)sd, + (__psunsigned_t)c); +} + +void +xfs_dir2_trace_args_db( + char *where, + xfs_da_args_t *args, + xfs_dir2_db_t db, + xfs_dabuf_t *bp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_DB, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)db, + (__psunsigned_t)(bp ? bp->bps[0] : NULL)); +} + +void +xfs_dir2_trace_args_i( + char *where, + xfs_da_args_t *args, + xfs_ino_t i) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_I, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)i, 0); +} + +void +xfs_dir2_trace_args_s( + char *where, + xfs_da_args_t *args, + int s) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_S, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)s, 0); +} + +void +xfs_dir2_trace_args_sb( + char *where, + xfs_da_args_t *args, + int s, + xfs_dabuf_t *bp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_SB, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)s, + (__psunsigned_t)(bp ? bp->bps[0] : NULL)); +} +#endif /* XFS_DIR2_TRACE */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir2_trace.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_trace.h --- linux-2.4.19/fs/xfs/xfs_dir2_trace.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir2_trace.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_TRACE_H__ +#define __XFS_DIR2_TRACE_H__ + +/* + * Tracing for xfs v2 directories. + */ + +struct ktrace; +struct xfs_dabuf; +struct xfs_da_args; + +#ifdef XFS_ALL_TRACE +#define XFS_DIR2_TRACE +#endif /* XFS_ALL_TRACE */ + +#if !defined(DEBUG) +#undef XFS_DIR2_TRACE +#endif /* !DEBUG */ + +#define XFS_DIR2_GTRACE_SIZE 4096 /* global buffer */ +#define XFS_DIR2_KTRACE_SIZE 32 /* per-inode buffer */ + +#define XFS_DIR2_KTRACE_ARGS 1 /* args only */ +#define XFS_DIR2_KTRACE_ARGS_B 2 /* args + buffer */ +#define XFS_DIR2_KTRACE_ARGS_BB 3 /* args + 2 buffers */ +#define XFS_DIR2_KTRACE_ARGS_DB 4 /* args, db, buffer */ +#define XFS_DIR2_KTRACE_ARGS_I 5 /* args, inum */ +#define XFS_DIR2_KTRACE_ARGS_S 6 /* args, int */ +#define XFS_DIR2_KTRACE_ARGS_SB 7 /* args, int, buffer */ +#define XFS_DIR2_KTRACE_ARGS_BIBII 8 /* args, buf/int/buf/int/int */ + +#ifdef XFS_DIR2_TRACE + +void xfs_dir2_trace_args(char *where, struct xfs_da_args *args); +void xfs_dir2_trace_args_b(char *where, struct xfs_da_args *args, + struct xfs_dabuf *bp); +void xfs_dir2_trace_args_bb(char *where, struct xfs_da_args *args, + struct xfs_dabuf *lbp, struct xfs_dabuf *dbp); +void xfs_dir2_trace_args_bibii(char *where, struct xfs_da_args *args, + struct xfs_dabuf *bs, int ss, + struct xfs_dabuf *bd, int sd, int c); +void xfs_dir2_trace_args_db(char *where, struct xfs_da_args *args, + xfs_dir2_db_t db, struct xfs_dabuf *bp); +void xfs_dir2_trace_args_i(char *where, struct xfs_da_args *args, xfs_ino_t i); +void xfs_dir2_trace_args_s(char *where, struct xfs_da_args *args, int s); +void xfs_dir2_trace_args_sb(char *where, struct xfs_da_args *args, int s, + struct xfs_dabuf *bp); + +#else /* XFS_DIR2_TRACE */ + +#define xfs_dir2_trace_args(where, args) +#define xfs_dir2_trace_args_b(where, args, bp) +#define xfs_dir2_trace_args_bb(where, args, lbp, dbp) +#define xfs_dir2_trace_args_bibii(where, args, bs, ss, bd, sd, c) +#define xfs_dir2_trace_args_db(where, args, db, bp) +#define xfs_dir2_trace_args_i(where, args, i) +#define xfs_dir2_trace_args_s(where, args, s) +#define xfs_dir2_trace_args_sb(where, args, s, bp) + +#endif /* XFS_DIR2_TRACE */ + +extern struct ktrace *xfs_dir2_trace_buf; + +#endif /* __XFS_DIR2_TRACE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir_leaf.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dir_leaf.c --- linux-2.4.19/fs/xfs/xfs_dir_leaf.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir_leaf.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,2224 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir_leaf.c + * + * GROT: figure out how to recover gracefully when bmap returns ENOSPC. + */ + +#include + + +/* + * xfs_dir_leaf.c + * + * Routines to implement leaf blocks of directories as Btrees of hashed names. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +STATIC void xfs_dir_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, + int insertion_index, + int freemap_index); +STATIC int xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer, + int musthave, int justcheck); +STATIC void xfs_dir_leaf_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2); +STATIC int xfs_dir_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *leaf_blk_1, + xfs_da_state_blk_t *leaf_blk_2, + int *number_entries_in_blk1, + int *number_namebytes_in_blk1); + +/* + * Utility routines. + */ +STATIC void xfs_dir_leaf_moveents(xfs_dir_leafblock_t *src_leaf, + int src_start, + xfs_dir_leafblock_t *dst_leaf, + int dst_start, int move_count, + xfs_mount_t *mp); + + +/*======================================================================== + * External routines when dirsize < XFS_IFORK_DSIZE(dp). + *========================================================================*/ + + +/* + * Validate a given inode number. + */ +int +xfs_dir_ino_validate(xfs_mount_t *mp, xfs_ino_t ino) +{ + xfs_agblock_t agblkno; + xfs_agino_t agino; + xfs_agnumber_t agno; + int ino_ok; + int ioff; + + agno = XFS_INO_TO_AGNO(mp, ino); + agblkno = XFS_INO_TO_AGBNO(mp, ino); + ioff = XFS_INO_TO_OFFSET(mp, ino); + agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); + ino_ok = + agno < mp->m_sb.sb_agcount && + agblkno < mp->m_sb.sb_agblocks && + agblkno != 0 && + ioff < (1 << mp->m_sb.sb_inopblog) && + XFS_AGINO_TO_INO(mp, agno, agino) == ino; + if (XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, + XFS_RANDOM_DIR_INO_VALIDATE)) { + xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx", + (unsigned long long) ino); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Create the initial contents of a shortform directory. + */ +int +xfs_dir_shortform_create(xfs_da_args_t *args, xfs_ino_t parent) +{ + xfs_dir_sf_hdr_t *hdr; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp != NULL); + ASSERT(dp->i_d.di_size == 0); + if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { + dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); + dp->i_df.if_flags |= XFS_IFINLINE; + } + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + ASSERT(dp->i_df.if_bytes == 0); + xfs_idata_realloc(dp, sizeof(*hdr), XFS_DATA_FORK); + hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; + XFS_DIR_SF_PUT_DIRINO_ARCH(&parent, &hdr->parent, ARCH_CONVERT); + + INT_ZERO(hdr->count, ARCH_CONVERT); + dp->i_d.di_size = sizeof(*hdr); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return(0); +} + +/* + * Add a name to the shortform directory structure. + * Overflow from the inode has already been checked for. + */ +int +xfs_dir_shortform_addname(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i, offset, size; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + args->name[0] == sfe->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) + return(XFS_ERROR(EEXIST)); + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + + offset = (int)((char *)sfe - (char *)sf); + size = XFS_DIR_SF_ENTSIZE_BYNAME(args->namelen); + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = (xfs_dir_sf_entry_t *)((char *)sf + offset); + + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT); + sfe->namelen = args->namelen; + bcopy(args->name, sfe->name, sfe->namelen); + INT_MOD(sf->hdr.count, ARCH_CONVERT, +1); + + dp->i_d.di_size += size; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + + return(0); +} + +/* + * Remove a name from the shortform directory structure. + */ +int +xfs_dir_shortform_removename(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int base, size = 0, i; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + base = sizeof(xfs_dir_sf_hdr_t); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe); + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(sfe->name, args->name, args->namelen) == 0) + break; + base += size; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + if (i < 0) { + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); + } + + if ((base + size) != dp->i_d.di_size) { + ovbcopy(&((char *)sf)[base+size], &((char *)sf)[base], + dp->i_d.di_size - (base+size)); + } + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + + xfs_idata_realloc(dp, -size, XFS_DATA_FORK); + dp->i_d.di_size -= size; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + + return(0); +} + +/* + * Look up a name in a shortform directory structure. + */ +int +xfs_dir_shortform_lookup(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &args->inumber, ARCH_CONVERT); + return(XFS_ERROR(EEXIST)); + } + if (args->namelen == 1 && args->name[0] == '.') { + args->inumber = dp->i_ino; + return(XFS_ERROR(EEXIST)); + } + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) { + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args->inumber, ARCH_CONVERT); + return(XFS_ERROR(EEXIST)); + } + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/* + * Convert from using the shortform to the leaf. + */ +int +xfs_dir_shortform_to_leaf(xfs_da_args_t *iargs) +{ + xfs_inode_t *dp; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + xfs_da_args_t args; + xfs_ino_t inumber; + char *tmpbuffer; + int retval, i, size; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + dp = iargs->dp; + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + size = dp->i_df.if_bytes; + tmpbuffer = kmem_alloc(size, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + bcopy(dp->i_df.if_u1.if_data, tmpbuffer, size); + + sf = (xfs_dir_shortform_t *)tmpbuffer; + XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &inumber, ARCH_CONVERT); + + xfs_idata_realloc(dp, -size, XFS_DATA_FORK); + dp->i_d.di_size = 0; + xfs_trans_log_inode(iargs->trans, dp, XFS_ILOG_CORE); + retval = xfs_da_grow_inode(iargs, &blkno); + if (retval) + goto out; + + ASSERT(blkno == 0); + retval = xfs_dir_leaf_create(iargs, blkno, &bp); + if (retval) + goto out; + xfs_da_buf_done(bp); + + args.name = "."; + args.namelen = 1; + args.hashval = xfs_dir_hash_dot; + args.inumber = dp->i_ino; + args.dp = dp; + args.firstblock = iargs->firstblock; + args.flist = iargs->flist; + args.total = iargs->total; + args.whichfork = XFS_DATA_FORK; + args.trans = iargs->trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + + args.name = ".."; + args.namelen = 2; + args.hashval = xfs_dir_hash_dotdot; + args.inumber = inumber; + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + args.name = (char *)(sfe->name); + args.namelen = sfe->namelen; + args.hashval = xfs_da_hashname((char *)(sfe->name), + sfe->namelen); + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args.inumber, ARCH_CONVERT); + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + retval = 0; + +out: + kmem_free(tmpbuffer, size); + return(retval); +} + +STATIC int +xfs_dir_shortform_compare(const void *a, const void *b) +{ + xfs_dir_sf_sort_t *sa, *sb; + + sa = (xfs_dir_sf_sort_t *)a; + sb = (xfs_dir_sf_sort_t *)b; + if (sa->hash < sb->hash) + return -1; + else if (sa->hash > sb->hash) + return 1; + else + return sa->entno - sb->entno; +} + +/* + * Copy out directory entries for getdents(), for shortform directories. + */ +/*ARGSUSED*/ +int +xfs_dir_shortform_getdents(xfs_inode_t *dp, uio_t *uio, int *eofp, + xfs_dirent_t *dbp, xfs_dir_put_t put) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int retval, i, sbsize, nsbuf, lastresid=0, want_entno; + xfs_mount_t *mp; + xfs_dahash_t cookhash, hash; + xfs_dir_put_args_t p; + xfs_dir_sf_sort_t *sbuf, *sbp; + + mp = dp->i_mount; + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); + want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset); + nsbuf = INT_GET(sf->hdr.count, ARCH_CONVERT) + 2; + sbsize = (nsbuf + 1) * sizeof(*sbuf); + sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP); + + xfs_dir_trace_g_du("sf: start", dp, uio); + + /* + * Collect all the entries into the buffer. + * Entry 0 is . + */ + sbp->entno = 0; + sbp->seqno = 0; + sbp->hash = xfs_dir_hash_dot; + sbp->ino = dp->i_ino; + sbp->name = "."; + sbp->namelen = 1; + sbp++; + + /* + * Entry 1 is .. + */ + sbp->entno = 1; + sbp->seqno = 0; + sbp->hash = xfs_dir_hash_dotdot; + sbp->ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT); + sbp->name = ".."; + sbp->namelen = 2; + sbp++; + + /* + * Scan the directory data for the rest of the entries. + */ + for (i = 0, sfe = &sf->list[0]; + i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + + if (((char *)sfe < (char *)sf) || + ((char *)sfe >= ((char *)sf + dp->i_df.if_bytes)) || + (sfe->namelen >= MAXNAMELEN)) { + xfs_dir_trace_g_du("sf: corrupted", dp, uio); + kmem_free(sbuf, sbsize); + return XFS_ERROR(EFSCORRUPTED); + } + + sbp->entno = i + 2; + sbp->seqno = 0; + sbp->hash = xfs_da_hashname((char *)sfe->name, sfe->namelen); + sbp->ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT); + sbp->name = (char *)sfe->name; + sbp->namelen = sfe->namelen; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + sbp++; + } + + /* + * Sort the entries on hash then entno. + */ + qsort(sbuf, nsbuf, sizeof(*sbuf), xfs_dir_shortform_compare); + /* + * Stuff in last entry. + */ + sbp->entno = nsbuf; + sbp->hash = XFS_DA_MAXHASH; + sbp->seqno = 0; + /* + * Figure out the sequence numbers in case there's a hash duplicate. + */ + for (hash = sbuf->hash, sbp = sbuf + 1; + sbp < &sbuf[nsbuf + 1]; sbp++) { + if (sbp->hash == hash) + sbp->seqno = sbp[-1].seqno + 1; + else + hash = sbp->hash; + } + + /* + * Set up put routine. + */ + p.dbp = dbp; + p.put = put; + p.uio = uio; + + /* + * Find our place. + */ + for (sbp = sbuf; sbp < &sbuf[nsbuf + 1]; sbp++) { + if (sbp->hash > cookhash || + (sbp->hash == cookhash && sbp->seqno >= want_entno)) + break; + } + + /* + * Did we fail to find anything? We stop at the last entry, + * the one we put maxhash into. + */ + if (sbp == &sbuf[nsbuf]) { + kmem_free(sbuf, sbsize); + xfs_dir_trace_g_du("sf: hash beyond end", dp, uio); + uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH); + *eofp = 1; + return 0; + } + + /* + * Loop putting entries into the user buffer. + */ + while (sbp < &sbuf[nsbuf]) { + /* + * Save the first resid in a run of equal-hashval entries + * so that we can back them out if they don't all fit. + */ + if (sbp->seqno == 0 || sbp == sbuf) + lastresid = uio->uio_resid; + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + XFS_PUT_COOKIE(p.cook, mp, 0, sbp->seqno, sbp->hash); + +#if XFS_BIG_FILESYSTEMS + p.ino = sbp->ino + mp->m_inoadd; +#else + p.ino = sbp->ino; +#endif + p.name = sbp->name; + p.namelen = sbp->namelen; + + retval = p.put(&p); + + if (!p.done) { + uio->uio_offset = + XFS_DA_MAKE_COOKIE(mp, 0, 0, sbp->hash); + kmem_free(sbuf, sbsize); + uio->uio_resid = lastresid; + xfs_dir_trace_g_du("sf: E-O-B", dp, uio); + return retval; + } + + sbp++; + } + + kmem_free(sbuf, sbsize); + + XFS_PUT_COOKIE(p.cook, mp, 0, 0, XFS_DA_MAXHASH); + + uio->uio_offset = p.cook.o; + + *eofp = 1; + + xfs_dir_trace_g_du("sf: E-O-F", dp, uio); + + return 0; +} + +/* + * Look up a name in a shortform directory structure, replace the inode number. + */ +int +xfs_dir_shortform_replace(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + xfs_inode_t *dp; + int i; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + /* XXX - replace assert? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sf->hdr.parent, ARCH_CONVERT); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return(0); + } + ASSERT(args->namelen != 1 || args->name[0] != '.'); + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) { + ASSERT(bcmp((char *)&args->inumber, + (char *)&sfe->inumber, sizeof(xfs_ino_t))); + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return(0); + } + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/* + * Convert a leaf directory to shortform structure + */ +int +xfs_dir_leaf_to_shortform(xfs_da_args_t *iargs) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_da_args_t args; + xfs_inode_t *dp; + xfs_ino_t parent; + char *tmpbuffer; + int retval, i; + xfs_dabuf_t *bp; + + dp = iargs->dp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + retval = xfs_da_read_buf(iargs->trans, iargs->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount)); + leaf = (xfs_dir_leafblock_t *)tmpbuffer; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + bzero(bp->data, XFS_LBSIZE(dp->i_mount)); + + /* + * Find and special case the parent inode number + */ + hdr = &leaf->hdr; + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + if ((entry->namelen == 2) && + (namest->name[0] == '.') && + (namest->name[1] == '.')) { + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &parent, ARCH_CONVERT); + INT_ZERO(entry->nameidx, ARCH_CONVERT); + } else if ((entry->namelen == 1) && (namest->name[0] == '.')) { + INT_ZERO(entry->nameidx, ARCH_CONVERT); + } + } + retval = xfs_da_shrink_inode(iargs, 0, bp); + if (retval) + goto out; + retval = xfs_dir_shortform_create(iargs, parent); + if (retval) + goto out; + + /* + * Copy the rest of the filenames + */ + entry = &leaf->entries[0]; + args.dp = dp; + args.firstblock = iargs->firstblock; + args.flist = iargs->flist; + args.total = iargs->total; + args.whichfork = XFS_DATA_FORK; + args.trans = iargs->trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + for (i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) { + if (INT_ISZERO(entry->nameidx, ARCH_CONVERT)) + continue; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + args.name = (char *)(namest->name); + args.namelen = entry->namelen; + args.hashval = INT_GET(entry->hashval, ARCH_CONVERT); + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args.inumber, ARCH_CONVERT); + xfs_dir_shortform_addname(&args); + } + +out: + kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); + return(retval); +} + +/* + * Convert from using a single leaf to a root node and a leaf. + */ +int +xfs_dir_leaf_to_node(xfs_da_args_t *args) +{ + xfs_dir_leafblock_t *leaf; + xfs_da_intnode_t *node; + xfs_inode_t *dp; + xfs_dabuf_t *bp1, *bp2; + xfs_dablk_t blkno; + int retval; + + dp = args->dp; + retval = xfs_da_grow_inode(args, &blkno); + ASSERT(blkno == 1); + if (retval) + return(retval); + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp1 != NULL); + retval = xfs_da_get_buf(args->trans, args->dp, 1, -1, &bp2, + XFS_DATA_FORK); + if (retval) { + xfs_da_buf_done(bp1); + return(retval); + } + ASSERT(bp2 != NULL); + bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount)); + xfs_da_buf_done(bp1); + xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); + + /* + * Set up the new root node. + */ + retval = xfs_da_node_create(args, 0, 1, &bp1, XFS_DATA_FORK); + if (retval) { + xfs_da_buf_done(bp2); + return(retval); + } + node = bp1->data; + leaf = bp2->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + INT_SET(node->btree[0].hashval, ARCH_CONVERT, INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); + xfs_da_buf_done(bp2); + INT_SET(node->btree[0].before, ARCH_CONVERT, blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 1); + xfs_da_log_buf(args->trans, bp1, + XFS_DA_LOGRANGE(node, &node->btree[0], sizeof(node->btree[0]))); + xfs_da_buf_done(bp1); + + return(retval); +} + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of a leaf directory + * or a leaf in a node directory. + */ +int +xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int retval; + + dp = args->dp; + ASSERT(dp != NULL); + retval = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp, XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + leaf = bp->data; + bzero((char *)leaf, XFS_LBSIZE(dp->i_mount)); + hdr = &leaf->hdr; + INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_DIR_LEAF_MAGIC); + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); + if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - 1); + INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); + INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT)); + + xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); + + *bpp = bp; + return(0); +} + +/* + * Split the leaf node, rebalance, then add the new entry. + */ +int +xfs_dir_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_dablk_t blkno; + xfs_da_args_t *args; + int error; + + /* + * Allocate space for a new leaf node. + */ + args = state->args; + ASSERT(args != NULL); + ASSERT(oldblk->magic == XFS_DIR_LEAF_MAGIC); + error = xfs_da_grow_inode(args, &blkno); + if (error) + return(error); + error = xfs_dir_leaf_create(args, blkno, &newblk->bp); + if (error) + return(error); + newblk->blkno = blkno; + newblk->magic = XFS_DIR_LEAF_MAGIC; + + /* + * Rebalance the entries across the two leaves. + */ + xfs_dir_leaf_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + + /* + * Insert the new entry in the correct block. + */ + if (state->inleaf) { + error = xfs_dir_leaf_add(oldblk->bp, args, oldblk->index); + } else { + error = xfs_dir_leaf_add(newblk->bp, args, newblk->index); + } + + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_dir_leaf_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_dir_leaf_lasthash(newblk->bp, NULL); + return(error); +} + +/* + * Add a name to the leaf directory structure. + * + * Must take into account fragmented leaves and leaves where spacemap has + * lost some freespace information (ie: holes). + */ +int +xfs_dir_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_map_t *map; + int tablesize, entsize, sum, i, tmp, error; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT((index >= 0) && (index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); + hdr = &leaf->hdr; + entsize = XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen); + + /* + * Search through freemap for first-fit on new name length. + * (may need to figure in size of entry struct too) + */ + tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[XFS_DIR_LEAF_MAPSIZE-1]; + for (sum = 0, i = XFS_DIR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { + if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { + sum += INT_GET(map->size, ARCH_CONVERT); + continue; + } + if (INT_ISZERO(map->size, ARCH_CONVERT)) + continue; /* no space in this map */ + tmp = entsize; + if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) + tmp += (uint)sizeof(xfs_dir_leaf_entry_t); + if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { + if (!args->justcheck) + xfs_dir_leaf_add_work(bp, args, index, i); + return(0); + } + sum += INT_GET(map->size, ARCH_CONVERT); + } + + /* + * If there are no holes in the address space of the block, + * and we don't have enough freespace, then compaction will do us + * no good and we should just give up. + */ + if (!hdr->holes && (sum < entsize)) + return(XFS_ERROR(ENOSPC)); + + /* + * Compact the entries to coalesce free space. + * Pass the justcheck flag so the checking pass can return + * an error, without changing anything, if it won't fit. + */ + error = xfs_dir_leaf_compact(args->trans, bp, + args->total == 0 ? + entsize + + (uint)sizeof(xfs_dir_leaf_entry_t) : 0, + args->justcheck); + if (error) + return(error); + /* + * After compaction, the block is guaranteed to have only one + * free region, in freemap[0]. If it is not big enough, give up. + */ + if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) < + (entsize + (uint)sizeof(xfs_dir_leaf_entry_t))) + return(XFS_ERROR(ENOSPC)); + + if (!args->justcheck) + xfs_dir_leaf_add_work(bp, args, index, 0); + return(0); +} + +/* + * Add a name to a leaf directory structure. + */ +STATIC void +xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index, + int mapindex) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_dir_leaf_map_t *map; + /* REFERENCED */ + xfs_mount_t *mp; + int tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr = &leaf->hdr; + ASSERT((mapindex >= 0) && (mapindex < XFS_DIR_LEAF_MAPSIZE)); + ASSERT((index >= 0) && (index <= INT_GET(hdr->count, ARCH_CONVERT))); + + /* + * Force open some space in the entry array and fill it in. + */ + entry = &leaf->entries[index]; + if (index < INT_GET(hdr->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr->count, ARCH_CONVERT) - index; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + ovbcopy(entry, entry + 1, tmp); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); + } + INT_MOD(hdr->count, ARCH_CONVERT, +1); + + /* + * Allocate space for the new string (at the end of the run). + */ + map = &hdr->freemap[mapindex]; + mp = args->trans->t_mountp; + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + INT_MOD(map->size, ARCH_CONVERT, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen))); + INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)); + INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); + entry->namelen = args->namelen; + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + + /* + * Copy the string and inode number into the new space. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &namest->inumber, ARCH_CONVERT); + bcopy(args->name, namest->name, args->namelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry))); + + /* + * Update the control info for this leaf node + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) + INT_COPY(hdr->firstused, entry->nameidx, ARCH_CONVERT); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); + tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[0]; + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { + if (INT_GET(map->base, ARCH_CONVERT) == tmp) { + INT_MOD(map->base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); + } + } + INT_MOD(hdr->namebytes, ARCH_CONVERT, args->namelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); +} + +/* + * Garbage collect a leaf directory block by copying it to a new buffer. + */ +STATIC int +xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave, + int justcheck) +{ + xfs_dir_leafblock_t *leaf_s, *leaf_d; + xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; + xfs_mount_t *mp; + char *tmpbuffer; + char *tmpbuffer2=NULL; + int rval; + int lbsize; + + mp = trans->t_mountp; + lbsize = XFS_LBSIZE(mp); + tmpbuffer = kmem_alloc(lbsize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(bp->data, tmpbuffer, lbsize); + + /* + * Make a second copy in case xfs_dir_leaf_moveents() + * below destroys the original. + */ + if (musthave || justcheck) { + tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP); + bcopy(bp->data, tmpbuffer2, lbsize); + } + bzero(bp->data, lbsize); + + /* + * Copy basic information + */ + leaf_s = (xfs_dir_leafblock_t *)tmpbuffer; + leaf_d = bp->data; + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + hdr_d->info = hdr_s->info; /* struct copy */ + INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize); + if (INT_ISZERO(hdr_d->firstused, ARCH_CONVERT)) + INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize - 1); + INT_ZERO(hdr_d->namebytes, ARCH_CONVERT); + INT_ZERO(hdr_d->count, ARCH_CONVERT); + hdr_d->holes = 0; + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + + /* + * Copy all entry's in the same (sorted) order, + * but allocate filenames packed and in sequence. + * This changes the source (leaf_s) as well. + */ + xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); + + if (musthave && INT_GET(hdr_d->freemap[0].size, ARCH_CONVERT) < musthave) + rval = XFS_ERROR(ENOSPC); + else + rval = 0; + + if (justcheck || rval == ENOSPC) { + ASSERT(tmpbuffer2); + bcopy(tmpbuffer2, bp->data, lbsize); + } else { + xfs_da_log_buf(trans, bp, 0, lbsize - 1); + } + + kmem_free(tmpbuffer, lbsize); + if (musthave || justcheck) + kmem_free(tmpbuffer2, lbsize); + return(rval); +} + +/* + * Redistribute the directory entries between two leaf nodes, + * taking into account the size of the new entry. + * + * NOTE: if new block is empty, then it will get the upper half of old block. + */ +STATIC void +xfs_dir_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_state_blk_t *tmp_blk; + xfs_dir_leafblock_t *leaf1, *leaf2; + xfs_dir_leaf_hdr_t *hdr1, *hdr2; + int count, totallen, max, space, swap; + + /* + * Set up environment. + */ + ASSERT(blk1->magic == XFS_DIR_LEAF_MAGIC); + ASSERT(blk2->magic == XFS_DIR_LEAF_MAGIC); + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + + /* + * Check ordering of blocks, reverse if it makes things simpler. + */ + swap = 0; + if (xfs_dir_leaf_order(blk1->bp, blk2->bp)) { + tmp_blk = blk1; + blk1 = blk2; + blk2 = tmp_blk; + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + swap = 1; + } + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. Then get + * the direction to copy and the number of elements to move. + */ + state->inleaf = xfs_dir_leaf_figure_balance(state, blk1, blk2, + &count, &totallen); + if (swap) + state->inleaf = !state->inleaf; + + /* + * Move any entries required from leaf to leaf: + */ + if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + count = INT_GET(hdr1->count, ARCH_CONVERT) - count; /* number entries being moved */ + space = INT_GET(hdr1->namebytes, ARCH_CONVERT) - totallen; + space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); + space += count * (uint)sizeof(xfs_dir_leaf_entry_t); + + /* + * leaf2 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr2->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); + max -= INT_GET(hdr2->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + if (space > max) { + xfs_dir_leaf_compact(state->args->trans, blk2->bp, + 0, 0); + } + + /* + * Move high entries from leaf1 to low end of leaf2. + */ + xfs_dir_leaf_moveents(leaf1, INT_GET(hdr1->count, ARCH_CONVERT) - count, + leaf2, 0, count, state->mp); + + xfs_da_log_buf(state->args->trans, blk1->bp, 0, + state->blocksize-1); + xfs_da_log_buf(state->args->trans, blk2->bp, 0, + state->blocksize-1); + + } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + count -= INT_GET(hdr1->count, ARCH_CONVERT); /* number entries being moved */ + space = totallen - INT_GET(hdr1->namebytes, ARCH_CONVERT); + space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); + space += count * (uint)sizeof(xfs_dir_leaf_entry_t); + + /* + * leaf1 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr1->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); + max -= INT_GET(hdr1->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + if (space > max) { + xfs_dir_leaf_compact(state->args->trans, blk1->bp, + 0, 0); + } + + /* + * Move low entries from leaf2 to high end of leaf1. + */ + xfs_dir_leaf_moveents(leaf2, 0, leaf1, (int)INT_GET(hdr1->count, ARCH_CONVERT), + count, state->mp); + + xfs_da_log_buf(state->args->trans, blk1->bp, 0, + state->blocksize-1); + xfs_da_log_buf(state->args->trans, blk2->bp, 0, + state->blocksize-1); + } + + /* + * Copy out last hashval in each block for B-tree code. + */ + blk1->hashval = INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + blk2->hashval = INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + * GROT: this doesn't work unless blk2 was originally empty. + */ + if (!state->inleaf) { + blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + } +} + +/* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + * GROT: Is this really necessary? With other than a 512 byte blocksize, + * GROT: there will always be enough room in either block for a new entry. + * GROT: Do a double-split for this case? + */ +STATIC int +xfs_dir_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2, + int *countarg, int *namebytesarg) +{ + xfs_dir_leafblock_t *leaf1, *leaf2; + xfs_dir_leaf_hdr_t *hdr1, *hdr2; + xfs_dir_leaf_entry_t *entry; + int count, max, totallen, half; + int lastdelta, foundit, tmp; + + /* + * Set up environment. + */ + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + foundit = 0; + totallen = 0; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + */ + max = INT_GET(hdr1->count, ARCH_CONVERT) + INT_GET(hdr2->count, ARCH_CONVERT); + half = (max+1) * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); + half += INT_GET(hdr1->namebytes, ARCH_CONVERT) + INT_GET(hdr2->namebytes, ARCH_CONVERT) + state->args->namelen; + half /= 2; + lastdelta = state->blocksize; + entry = &leaf1->entries[0]; + for (count = 0; count < max; entry++, count++) { + +#define XFS_DIR_ABS(A) (((A) < 0) ? -(A) : (A)) + /* + * The new entry is in the first block, account for it. + */ + if (count == blk1->index) { + tmp = totallen + (uint)sizeof(*entry) + + XFS_DIR_LEAF_ENTSIZE_BYNAME(state->args->namelen); + if (XFS_DIR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_DIR_ABS(half - tmp); + totallen = tmp; + foundit = 1; + } + + /* + * Wrap around into the second block if necessary. + */ + if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { + leaf1 = leaf2; + entry = &leaf1->entries[0]; + } + + /* + * Figure out if next leaf entry would be too much. + */ + tmp = totallen + (uint)sizeof(*entry) + + XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); + if (XFS_DIR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_DIR_ABS(half - tmp); + totallen = tmp; +#undef XFS_DIR_ABS + } + + /* + * Calculate the number of namebytes that will end up in lower block. + * If new entry not in lower block, fix up the count. + */ + totallen -= + count * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); + if (foundit) { + totallen -= (sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1) + + state->args->namelen; + } + + *countarg = count; + *namebytesarg = totallen; + return(foundit); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +int +xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_dir_leafblock_t *leaf; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, bytes, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + leaf = (xfs_dir_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = (uint)sizeof(xfs_dir_leaf_hdr_t) + + count * (uint)sizeof(xfs_dir_leaf_entry_t) + + count * ((uint)sizeof(xfs_dir_leaf_name_t)-1) + + INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + if (bytes > (state->blocksize >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = !INT_ISZERO(info->forw, ARCH_CONVERT); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + forward = (INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT)); /* start with smaller blk num */ + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, + XFS_DATA_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + leaf = (xfs_dir_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize>>2); + bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + bytes -= count * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); + bytes -= count * (uint)sizeof(xfs_dir_leaf_entry_t); + bytes -= (uint)sizeof(xfs_dir_leaf_hdr_t); + if (bytes >= 0) + break; /* fits with at least 25% to spare */ + + xfs_da_brelse(state->args->trans, bp); + } + if (i >= 2) { + *action = 0; + return(0); + } + xfs_da_buf_done(bp); + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + } + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 1; + } + return(0); +} + +/* + * Remove a name from the leaf directory structure. + * + * Return 1 if leaf is less than 37% full, 0 if >= 37% full. + * If two leaves are 37% full, when combined they will leave 25% free. + */ +int +xfs_dir_leaf_remove(xfs_trans_t *trans, xfs_dabuf_t *bp, int index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_map_t *map; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int before, after, smallest, entsize; + int tablesize, tmp, i; + xfs_mount_t *mp; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr = &leaf->hdr; + mp = trans->t_mountp; + ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT((index >= 0) && (index < INT_GET(hdr->count, ARCH_CONVERT))); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); + entry = &leaf->entries[index]; + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + + /* + * Scan through free region table: + * check for adjacency of free'd entry with an existing one, + * find smallest free region in case we need to replace it, + * adjust any map that borders the entry table, + */ + tablesize = INT_GET(hdr->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[0]; + tmp = INT_GET(map->size, ARCH_CONVERT); + before = after = -1; + smallest = XFS_DIR_LEAF_MAPSIZE - 1; + entsize = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { + INT_MOD(map->base, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); + INT_MOD(map->size, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); + } + + if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == INT_GET(entry->nameidx, ARCH_CONVERT)) { + before = i; + } else if (INT_GET(map->base, ARCH_CONVERT) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { + after = i; + } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { + tmp = INT_GET(map->size, ARCH_CONVERT); + smallest = i; + } + } + + /* + * Coalesce adjacent freemap regions, + * or replace the smallest region. + */ + if ((before >= 0) || (after >= 0)) { + if ((before >= 0) && (after >= 0)) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT)); + INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT); + INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT); + } else if (before >= 0) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + } else { + map = &hdr->freemap[after]; + INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); + INT_MOD(map->size, ARCH_CONVERT, entsize); + } + } else { + /* + * Replace smallest region (if it is smaller than free'd entry) + */ + map = &hdr->freemap[smallest]; + if (INT_GET(map->size, ARCH_CONVERT) < entsize) { + INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); + INT_SET(map->size, ARCH_CONVERT, entsize); + } + } + + /* + * Did we remove the first entry? + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) == INT_GET(hdr->firstused, ARCH_CONVERT)) + smallest = 1; + else + smallest = 0; + + /* + * Compress the remaining entries and zero out the removed stuff. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + bzero((char *)namest, entsize); + xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize)); + + INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen)); + tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t); + ovbcopy(entry + 1, entry, tmp); + INT_MOD(hdr->count, ARCH_CONVERT, -1); + xfs_da_log_buf(trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); + entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; + bzero((char *)entry, sizeof(xfs_dir_leaf_entry_t)); + + /* + * If we removed the first entry, re-find the first used byte + * in the name area. Note that if the entry was the "firstused", + * then we don't have a "hole" in our block resulting from + * removing the name. + */ + if (smallest) { + tmp = XFS_LBSIZE(mp); + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) + tmp = INT_GET(entry->nameidx, ARCH_CONVERT); + } + INT_SET(hdr->firstused, ARCH_CONVERT, tmp); + if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) + INT_SET(hdr->firstused, ARCH_CONVERT, tmp - 1); + } else { + hdr->holes = 1; /* mark as needing compaction */ + } + + xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + + /* + * Check if leaf is less than 50% full, caller may want to + * "join" the leaf with a sibling if so. + */ + tmp = (uint)sizeof(xfs_dir_leaf_hdr_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); + tmp += INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + if (tmp < mp->m_dir_magicpct) + return(1); /* leaf is < 37% full */ + return(0); +} + +/* + * Move all the directory entries from drop_leaf into save_leaf. + */ +void +xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_dir_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; + xfs_dir_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; + xfs_mount_t *mp; + char *tmpbuffer; + + /* + * Set up environment. + */ + mp = state->mp; + ASSERT(drop_blk->magic == XFS_DIR_LEAF_MAGIC); + ASSERT(save_blk->magic == XFS_DIR_LEAF_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + drop_hdr = &drop_leaf->hdr; + save_hdr = &save_leaf->hdr; + + /* + * Save last hashval from dying block for later Btree fixup. + */ + drop_blk->hashval = INT_GET(drop_leaf->entries[ drop_leaf->hdr.count-1 ].hashval, ARCH_CONVERT); + + /* + * Check if we need a temp buffer, or can we do it in place. + * Note that we don't check "leaf" for holes because we will + * always be dropping it, toosmall() decided that for us already. + */ + if (save_hdr->holes == 0) { + /* + * dest leaf has no holes, so we add there. May need + * to make some room in the entry array. + */ + if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_dir_leaf_moveents(drop_leaf, 0, save_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_dir_leaf_moveents(drop_leaf, 0, + save_leaf, INT_GET(save_hdr->count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } + } else { + /* + * Destination has holes, so we make a temporary copy + * of the leaf and add them both to that. + */ + tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bzero(tmpbuffer, state->blocksize); + tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer; + tmp_hdr = &tmp_leaf->hdr; + tmp_hdr->info = save_hdr->info; /* struct copy */ + INT_ZERO(tmp_hdr->count, ARCH_CONVERT); + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); + if (INT_ISZERO(tmp_hdr->firstused, ARCH_CONVERT)) + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize - 1); + INT_ZERO(tmp_hdr->namebytes, ARCH_CONVERT); + if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + xfs_dir_leaf_moveents(save_leaf, 0, + tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_dir_leaf_moveents(save_leaf, 0, tmp_leaf, 0, + (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); + xfs_dir_leaf_moveents(drop_leaf, 0, + tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } + bcopy(tmp_leaf, save_leaf, state->blocksize); + kmem_free(tmpbuffer, state->blocksize); + } + + xfs_da_log_buf(state->args->trans, save_blk->bp, 0, + state->blocksize - 1); + + /* + * Copy out last hashval in each block for B-tree code. + */ + save_blk->hashval = INT_GET(save_leaf->entries[ INT_GET(save_leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Look up a name in a leaf directory structure. + * This is the internal routine, it uses the caller's buffer. + * + * Note that duplicate keys are allowed, but only check within the + * current leaf node. The Btree code must check in adjacent leaf nodes. + * + * Return in *index the index into the entry[] array of either the found + * entry, or where the entry should have been (insert before that entry). + * + * Don't change the args->inumber unless we find the filename. + */ +int +xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args, int *index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int probe, span; + xfs_dahash_t hashval; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) < (XFS_LBSIZE(args->dp->i_mount)/8)); + + /* + * Binary search. (note: small blocks will skip this loop) + */ + hashval = args->hashval; + probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2; + for (entry = &leaf->entries[probe]; span > 4; + entry = &leaf->entries[probe]) { + span /= 2; + if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && \ + ((INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)))); + ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)); + + /* + * Since we may have duplicate hashval's, find the first matching + * hashval in the leaf. + */ + while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) >= hashval)) { + entry--; + probe--; + } + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) { + entry++; + probe++; + } + if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) { + *index = probe; + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); + } + + /* + * Duplicate keys may be present, so search all of them for a match. + */ + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + if (entry->namelen == args->namelen && + namest->name[0] == args->name[0] && + bcmp(args->name, namest->name, args->namelen) == 0) { + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args->inumber, ARCH_CONVERT); + *index = probe; + return(XFS_ERROR(EEXIST)); + } + entry++; + probe++; + } + *index = probe; + ASSERT(probe == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Move the indicated entries from one leaf to another. + * NOTE: this routine modifies both source and destination leaves. + */ +/* ARGSUSED */ +STATIC void +xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s, + xfs_dir_leafblock_t *leaf_d, int start_d, + int count, xfs_mount_t *mp) +{ + xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; + xfs_dir_leaf_entry_t *entry_s, *entry_d; + int tmp, i; + + /* + * Check for nothing to do. + */ + if (count == 0) + return; + + /* + * Set up environment. + */ + ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) && (INT_GET(hdr_s->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_s->count, ARCH_CONVERT)*sizeof(*entry_s))+sizeof(*hdr_s))); + ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_d->count, ARCH_CONVERT)*sizeof(*entry_d))+sizeof(*hdr_d))); + + ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); + ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); + ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); + + /* + * Move the entries in the destination leaf up to make a hole? + */ + if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_d->entries[start_d]; + entry_d = &leaf_d->entries[start_d + count]; + bcopy(entry_s, entry_d, tmp); + } + + /* + * Copy all entry's in the same (sorted) order, + * but allocate filenames packed and in sequence. + */ + entry_s = &leaf_s->entries[start_s]; + entry_d = &leaf_d->entries[start_d]; + for (i = 0; i < count; entry_s++, entry_d++, i++) { + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); + ASSERT(entry_s->namelen < MAXNAMELEN); + tmp = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry_s); + INT_MOD(hdr_d->firstused, ARCH_CONVERT, -(tmp)); + entry_d->hashval = entry_s->hashval; /* INT_: direct copy */ + INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT); + entry_d->namelen = entry_s->namelen; + ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); + bcopy(XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), + XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)), tmp); + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); + bzero((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), + tmp); + INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen)); + INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + INT_MOD(hdr_d->count, ARCH_CONVERT, +1); + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); + + } + + /* + * Zero out the entries we just copied. + */ + if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { + tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[start_s]; + ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); + bzero((char *)entry_s, tmp); + } else { + /* + * Move the remaining entries down to fill the hole, + * then zero the entries at the top. + */ + tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[start_s + count]; + entry_d = &leaf_s->entries[start_s]; + bcopy(entry_s, entry_d, tmp); + + tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)]; + ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); + bzero((char *)entry_s, tmp); + } + + /* + * Fill in the freemap information + */ + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_hdr_t)); + INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].size, ARCH_CONVERT)); + hdr_s->holes = 1; /* leaf may not be compact */ +} + +/* + * Compare two leaf blocks "order". + */ +int +xfs_dir_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) +{ + xfs_dir_leafblock_t *leaf1, *leaf2; + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) && + (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC)); + if ((INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from a leaf block. + */ +xfs_dahash_t +xfs_dir_leaf_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_dir_leafblock_t *leaf; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) + return(0); + return(INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); +} + +/* + * Copy out directory entries for getdents(), for leaf directories. + */ +int +xfs_dir_leaf_getdents_int( + xfs_dabuf_t *bp, + xfs_inode_t *dp, + xfs_dablk_t bno, + uio_t *uio, + int *eobp, + xfs_dirent_t *dbp, + xfs_dir_put_t put, + xfs_daddr_t nextda) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int entno, want_entno, i, nextentno; + xfs_mount_t *mp; + xfs_dahash_t cookhash; + xfs_dahash_t nexthash = 0; +#if (BITS_PER_LONG == 32) + xfs_dahash_t lasthash = XFS_DA_MAXHASH; +#endif + xfs_dir_put_args_t p; + + mp = dp->i_mount; + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + *eobp = 1; + return(XFS_ERROR(ENOENT)); /* XXX wrong code */ + } + + want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset); + + cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); + + xfs_dir_trace_g_dul("leaf: start", dp, uio, leaf); + + /* + * Re-find our place. + */ + for (i = entno = 0, entry = &leaf->entries[0]; + i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + entry++, i++) { + + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + + if (((char *)namest < (char *)leaf) || + ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)) || + (entry->namelen >= MAXNAMELEN)) { + xfs_dir_trace_g_du("leaf: corrupted", dp, uio); + return XFS_ERROR(EFSCORRUPTED); + } + if (INT_GET(entry->hashval, ARCH_CONVERT) >= cookhash) { + if ( entno < want_entno + && INT_GET(entry->hashval, ARCH_CONVERT) + == cookhash) { + /* + * Trying to get to a particular offset in a + * run of equal-hashval entries. + */ + entno++; + } else if ( want_entno > 0 + && entno == want_entno + && INT_GET(entry->hashval, ARCH_CONVERT) + == cookhash) { + break; + } else { + entno = 0; + break; + } + } + } + + if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) { + xfs_dir_trace_g_du("leaf: hash not found", dp, uio); + if (!INT_GET(leaf->hdr.info.forw, ARCH_CONVERT)) + uio->uio_offset = + XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH); + /* + * Don't set uio_offset if there's another block: + * the node code will be setting uio_offset anyway. + */ + *eobp = 0; + return(0); + } + xfs_dir_trace_g_due("leaf: hash found", dp, uio, entry); + + p.dbp = dbp; + p.put = put; + p.uio = uio; + + /* + * We're synchronized, start copying entries out to the user. + */ + for (; entno >= 0 && i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + entry++, i++, (entno = nextentno)) { + int lastresid=0, retval; + xfs_dircook_t lastoffset; + xfs_dahash_t thishash; + + /* + * Check for a damaged directory leaf block and pick up + * the inode number from this entry. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + + if (((char *)namest < (char *)leaf) || + ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)) || + (entry->namelen >= MAXNAMELEN)) { + xfs_dir_trace_g_du("leaf: corrupted", dp, uio); + return XFS_ERROR(EFSCORRUPTED); + } + + thishash = INT_GET(entry->hashval, ARCH_CONVERT); + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + XFS_PUT_COOKIE(p.cook, mp, bno, entno, thishash); + + xfs_dir_trace_g_duc("leaf: middle cookie ", + dp, uio, p.cook.o); + + if (i < (INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1)) { + nexthash = INT_GET(entry[1].hashval, ARCH_CONVERT); + + if (nexthash == INT_GET(entry->hashval, ARCH_CONVERT)) + nextentno = entno + 1; + else + nextentno = 0; + + } else if (INT_GET(leaf->hdr.info.forw, ARCH_CONVERT)) { + xfs_dabuf_t *bp2; + xfs_dir_leafblock_t *leaf2; + + ASSERT(nextda != -1); + + retval = xfs_da_read_buf(dp->i_transp, dp, + INT_GET(leaf->hdr.info.forw, + ARCH_CONVERT), nextda, + &bp2, XFS_DATA_FORK); + if (retval) + return(retval); + + ASSERT(bp2 != NULL); + + leaf2 = bp2->data; + + if ( (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + != XFS_DIR_LEAF_MAGIC) + || (INT_GET(leaf2->hdr.info.back, ARCH_CONVERT) + != bno)) { /* GROT */ + + xfs_da_brelse(dp->i_transp, bp2); + + return(XFS_ERROR(EFSCORRUPTED)); + } + + nexthash = INT_GET(leaf2->entries[0].hashval, + ARCH_CONVERT); + nextentno = -1; + + xfs_da_brelse(dp->i_transp, bp2); + xfs_dir_trace_g_duc("leaf: next blk cookie", + dp, uio, p.cook.o); + } else { + nextentno = -1; + nexthash = XFS_DA_MAXHASH; + } + + /* + * Save off the cookie so we can fall back should the + * 'put' into the outgoing buffer fails. To handle a run + * of equal-hashvals, the off_t structure on 64bit + * builds has entno built into the cookie to ID the + * entry. On 32bit builds, we only have space for the + * hashval so we can't ID specific entries within a group + * of same hashval entries. For this, lastoffset is set + * to the first in the run of equal hashvals so we don't + * include any entries unless we can include all entries + * that share the same hashval. Hopefully the buffer + * provided is big enough to handle it (see pv763517). + */ +#if (BITS_PER_LONG == 32) + if (INT_GET(entry->hashval, ARCH_CONVERT) != lasthash) { + XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash); + lastresid = uio->uio_resid; + lasthash = thishash; + } else { + xfs_dir_trace_g_duc("leaf: DUP COOKIES, skipped", + dp, uio, p.cook.o); + } +#else + XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash); + lastresid = uio->uio_resid; +#endif /* BITS_PER_LONG == 32 */ + + /* + * Put the current entry into the outgoing buffer. If we fail + * then restore the UIO to the first entry in the current + * run of equal-hashval entries (probably one 1 entry long). + */ +#if XFS_BIG_FILESYSTEMS + p.ino = XFS_GET_DIR_INO_ARCH(mp, namest->inumber, ARCH_CONVERT) + mp->m_inoadd; +#else + p.ino = XFS_GET_DIR_INO_ARCH(mp, namest->inumber, ARCH_CONVERT); +#endif + p.name = (char *)namest->name; + p.namelen = entry->namelen; + + retval = p.put(&p); + + if (!p.done) { + uio->uio_offset = lastoffset.o; + uio->uio_resid = lastresid; + + *eobp = 1; + + xfs_dir_trace_g_du("leaf: E-O-B", dp, uio); + + return(retval); + } + } + + XFS_PUT_COOKIE(p.cook, mp, 0, 0, nexthash); + + uio->uio_offset = p.cook.o; + + *eobp = 0; + + xfs_dir_trace_g_du("leaf: E-O-F", dp, uio); + + return(0); +} + +/* + * Format a dirent64 structure and copy it out the the user's buffer. + */ +int +xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa) +{ + iovec_t *iovp; + int reclen, namelen; + xfs_dirent_t *idbp; + uio_t *uio; + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + iovp = uio->uio_iov; + idbp = (xfs_dirent_t *)iovp->iov_base; + iovp->iov_base = (char *)idbp + reclen; + iovp->iov_len -= reclen; + uio->uio_resid -= reclen; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook.o; + idbp->d_name[namelen] = '\0'; + pa->done = 1; + bcopy(pa->name, idbp->d_name, namelen); + return 0; +} + +/* + * Format a dirent64 structure and copy it out the the user's buffer. + */ +int +xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa) +{ + int retval, reclen, namelen; + xfs_dirent_t *idbp; + uio_t *uio; + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + idbp = pa->dbp; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook.o; + idbp->d_name[namelen] = '\0'; + bcopy(pa->name, idbp->d_name, namelen); + retval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio); + pa->done = (retval == 0); + return retval; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dir_leaf.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir_leaf.h --- linux-2.4.19/fs/xfs/xfs_dir_leaf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir_leaf.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_LEAF_H__ +#define __XFS_DIR_LEAF_H__ + +/* + * Directory layout, internal structure, access macros, etc. + * + * Large directories are structured around Btrees where all the data + * elements are in the leaf nodes. Filenames are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of a filename may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + */ + +struct dirent; +struct uio; +struct xfs_bmap_free; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_dir_put_args; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/*======================================================================== + * Directory Structure when equal to XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This is the structure of the leaf nodes in the Btree. + * + * Struct leaf_entry's are packed from the top. Names grow from the bottom + * but are not packed. The freemap contains run-length-encoded entries + * for the free bytes after the leaf_entry's, but only the N largest such, + * smaller runs are dropped. When the freemap doesn't show enough space + * for an allocation, we compact the namelist area and try again. If we + * still don't have enough space, then we have to split the block. + * + * Since we have duplicate hash keys, for each key that matches, compare + * the actual string. The root and intermediate node search always takes + * the first-in-the-block key match found, so we should only have to work + * "forw"ard. If none matches, continue with the "forw"ard leaf nodes + * until the hash key changes or the filename is found. + * + * The parent directory and the self-pointer are explicitly represented + * (ie: there are entries for "." and ".."). + * + * Note that the count being a __uint16_t limits us to something like a + * blocksize of 1.3MB in the face of worst case (short) filenames. + */ +#define XFS_DIR_LEAF_MAPSIZE 3 /* how many freespace slots */ + +typedef struct xfs_dir_leafblock { + struct xfs_dir_leaf_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active leaf_entry's */ + __uint16_t namebytes; /* num bytes of name strings stored */ + __uint16_t firstused; /* first used byte in name area */ + __uint8_t holes; /* != 0 if blk needs compaction */ + __uint8_t pad1; + struct xfs_dir_leaf_map {/* RLE map of free bytes */ + __uint16_t base; /* base of free region */ + __uint16_t size; /* run length of free region */ + } freemap[XFS_DIR_LEAF_MAPSIZE]; /* N largest free regions */ + } hdr; + struct xfs_dir_leaf_entry { /* sorted on key, not name */ + xfs_dahash_t hashval; /* hash value of name */ + __uint16_t nameidx; /* index into buffer of name */ + __uint8_t namelen; /* length of name string */ + __uint8_t pad2; + } entries[1]; /* var sized array */ + struct xfs_dir_leaf_name { + xfs_dir_ino_t inumber; /* inode number for this key */ + __uint8_t name[1]; /* name string itself */ + } namelist[1]; /* grows from bottom of buf */ +} xfs_dir_leafblock_t; +typedef struct xfs_dir_leaf_hdr xfs_dir_leaf_hdr_t; +typedef struct xfs_dir_leaf_map xfs_dir_leaf_map_t; +typedef struct xfs_dir_leaf_entry xfs_dir_leaf_entry_t; +typedef struct xfs_dir_leaf_name xfs_dir_leaf_name_t; + +/* + * Length of name for which a 512-byte block filesystem + * can get a double split. + */ +#define XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN \ + (512 - (uint)sizeof(xfs_dir_leaf_hdr_t) - \ + (uint)sizeof(xfs_dir_leaf_entry_t) * 2 - \ + (uint)sizeof(xfs_dir_leaf_name_t) * 2 - (MAXNAMELEN - 2) + 1 + 1) + +typedef int (*xfs_dir_put_t)(struct xfs_dir_put_args *pa); + +typedef union { + xfs_off_t o; /* offset (cookie) */ + /* + * Watch the order here (endian-ness dependent). + */ + struct { +#if __BYTE_ORDER == __LITTLE_ENDIAN + xfs_dahash_t h; /* hash value */ + __uint32_t be; /* block and entry */ +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + __uint32_t be; /* block and entry */ + xfs_dahash_t h; /* hash value */ +#endif /* __BYTE_ORDER == __BIG_ENDIAN */ + } s; +} xfs_dircook_t; + +#define XFS_PUT_COOKIE(c,mp,bno,entry,hash) \ + ((c).s.be = XFS_DA_MAKE_BNOENTRY(mp, bno, entry), (c).s.h = (hash)) + +#define XFS_GET_DIR_INO_ARCH(mp,di,arch) \ + DIRINO_GET_ARCH(&(di),arch) +#define XFS_GET_DIR_INO(mp,di) \ + XFS_GET_DIR_INO_ARCH(mp,di,ARCH_NOCONVERT) + +typedef struct xfs_dir_put_args +{ + xfs_dircook_t cook; /* cookie of (next) entry */ + xfs_intino_t ino; /* inode number */ + struct xfs_dirent *dbp; /* buffer pointer */ + char *name; /* directory entry name */ + int namelen; /* length of name */ + int done; /* output: set if value was stored */ + xfs_dir_put_t put; /* put function ptr (i/o) */ + struct uio *uio; /* uio control structure */ +} xfs_dir_put_args_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYNAME) +int xfs_dir_leaf_entsize_byname(int len); +#define XFS_DIR_LEAF_ENTSIZE_BYNAME(len) xfs_dir_leaf_entsize_byname(len) +#else +#define XFS_DIR_LEAF_ENTSIZE_BYNAME(len) /* space a name will use */ \ + ((uint)sizeof(xfs_dir_leaf_name_t)-1 + len) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYENTRY) +int xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry); +#define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry) \ + xfs_dir_leaf_entsize_byentry(entry) +#else +#define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry) /* space an entry will use */ \ + ((uint)sizeof(xfs_dir_leaf_name_t)-1 + (entry)->namelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_NAMESTRUCT) +xfs_dir_leaf_name_t * +xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset); +#define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset) \ + xfs_dir_leaf_namestruct(leafp,offset) +#else +#define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset) /* point to name struct */ \ + ((xfs_dir_leaf_name_t *)&((char *)(leafp))[offset]) +#endif + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when dirsize < XFS_LITINO(mp). + */ +int xfs_dir_shortform_create(struct xfs_da_args *args, xfs_ino_t parent); +int xfs_dir_shortform_addname(struct xfs_da_args *args); +int xfs_dir_shortform_lookup(struct xfs_da_args *args); +int xfs_dir_shortform_to_leaf(struct xfs_da_args *args); +int xfs_dir_shortform_removename(struct xfs_da_args *args); +int xfs_dir_shortform_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp, + struct xfs_dirent *dbp, xfs_dir_put_t put); +int xfs_dir_shortform_replace(struct xfs_da_args *args); + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +int xfs_dir_leaf_to_node(struct xfs_da_args *args); +int xfs_dir_leaf_to_shortform(struct xfs_da_args *args); + +/* + * Routines used for growing the Btree. + */ +int xfs_dir_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, + struct xfs_dabuf **bpp); +int xfs_dir_leaf_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); +int xfs_dir_leaf_add(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args, int insertion_index); +int xfs_dir_leaf_addname(struct xfs_da_args *args); +int xfs_dir_leaf_lookup_int(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args, + int *index_found_at); +int xfs_dir_leaf_remove(struct xfs_trans *trans, + struct xfs_dabuf *leaf_buffer, + int index_to_remove); +int xfs_dir_leaf_getdents_int(struct xfs_dabuf *bp, struct xfs_inode *dp, + xfs_dablk_t bno, struct uio *uio, + int *eobp, struct xfs_dirent *dbp, + xfs_dir_put_t put, xfs_daddr_t nextda); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_dir_leaf_toosmall(struct xfs_da_state *state, int *retval); +void xfs_dir_leaf_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); + +/* + * Utility routines. + */ +uint xfs_dir_leaf_lasthash(struct xfs_dabuf *bp, int *count); +int xfs_dir_leaf_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); +int xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa); +int xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa); +int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); + + +/* + * Global data. + */ +extern xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; + +#endif /* __XFS_DIR_LEAF_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dir_sf.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dir_sf.h --- linux-2.4.19/fs/xfs/xfs_dir_sf.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dir_sf.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_SF_H__ +#define __XFS_DIR_SF_H__ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tight as possible. The header + * and the elements much be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir_shortform { + struct xfs_dir_sf_hdr { /* constant-structure header block */ + xfs_dir_ino_t parent; /* parent dir inode number */ + __uint8_t count; /* count of active entries */ + } hdr; + struct xfs_dir_sf_entry { + xfs_dir_ino_t inumber; /* referenced inode number */ + __uint8_t namelen; /* actual length of name (no NULL) */ + __uint8_t name[1]; /* name */ + } list[1]; /* variable sized array */ +} xfs_dir_shortform_t; +typedef struct xfs_dir_sf_hdr xfs_dir_sf_hdr_t; +typedef struct xfs_dir_sf_entry xfs_dir_sf_entry_t; + +/* + * We generate this then sort it, so that readdirs are returned in + * hash-order. Else seekdir won't work. + */ +typedef struct xfs_dir_sf_sort { + __uint8_t entno; /* .=0, ..=1, else entry# + 2 */ + __uint8_t seqno; /* sequence # with same hash value */ + __uint8_t namelen; /* length of name value (no null) */ + xfs_dahash_t hash; /* this entry's hash value */ + xfs_intino_t ino; /* this entry's inode number */ + char *name; /* name value, pointer into buffer */ +} xfs_dir_sf_sort_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_GET_DIRINO) +void xfs_dir_sf_get_dirino_arch(xfs_dir_ino_t *from, xfs_ino_t *to, xfs_arch_t arch); +void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to); +#define XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch) xfs_dir_sf_get_dirino_arch(from, to, arch) +#define XFS_DIR_SF_GET_DIRINO(from,to) xfs_dir_sf_get_dirino(from, to) +#else +#define XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch) DIRINO_COPY_ARCH(from,to,arch) +#define XFS_DIR_SF_GET_DIRINO(from,to) DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_PUT_DIRINO) +void xfs_dir_sf_put_dirino_arch(xfs_ino_t *from, xfs_dir_ino_t *to, xfs_arch_t arch); +void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to); +#define XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch) xfs_dir_sf_put_dirino_arch(from, to, arch) +#define XFS_DIR_SF_PUT_DIRINO(from,to) xfs_dir_sf_put_dirino(from, to) +#else +#define XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch) DIRINO_COPY_ARCH(from,to,arch) +#define XFS_DIR_SF_PUT_DIRINO(from,to) DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ENTSIZE_BYNAME) +int xfs_dir_sf_entsize_byname(int len); +#define XFS_DIR_SF_ENTSIZE_BYNAME(len) xfs_dir_sf_entsize_byname(len) +#else +#define XFS_DIR_SF_ENTSIZE_BYNAME(len) /* space a name uses */ \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1 + (len)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ENTSIZE_BYENTRY) +int xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep); +#define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep) xfs_dir_sf_entsize_byentry(sfep) +#else +#define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep) /* space an entry uses */ \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1 + (sfep)->namelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_NEXTENTRY) +xfs_dir_sf_entry_t *xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep); +#define XFS_DIR_SF_NEXTENTRY(sfep) xfs_dir_sf_nextentry(sfep) +#else +#define XFS_DIR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ + ((xfs_dir_sf_entry_t *) \ + ((char *)(sfep) + XFS_DIR_SF_ENTSIZE_BYENTRY(sfep))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ALLFIT) +int xfs_dir_sf_allfit(int count, int totallen); +#define XFS_DIR_SF_ALLFIT(count,totallen) \ + xfs_dir_sf_allfit(count,totallen) +#else +#define XFS_DIR_SF_ALLFIT(count,totallen) /* will all entries fit? */ \ + ((uint)sizeof(xfs_dir_sf_hdr_t) + \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1)*(count) + (totallen)) +#endif + +#ifdef XFS_ALL_TRACE +#define XFS_DIR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_DIR_TRACE +#endif + +/* + * Kernel tracing support for directories. + */ +struct uio; +struct xfs_inode; +struct xfs_da_intnode; +struct xfs_dinode; +struct xfs_dir_leafblock; +struct xfs_dir_leaf_entry; + +#define XFS_DIR_TRACE_SIZE 4096 /* size of global trace buffer */ + +/* + * Trace record types. + */ +#define XFS_DIR_KTRACE_G_DU 1 /* dp, uio */ +#define XFS_DIR_KTRACE_G_DUB 2 /* dp, uio, bno */ +#define XFS_DIR_KTRACE_G_DUN 3 /* dp, uio, node */ +#define XFS_DIR_KTRACE_G_DUL 4 /* dp, uio, leaf */ +#define XFS_DIR_KTRACE_G_DUE 5 /* dp, uio, leaf entry */ +#define XFS_DIR_KTRACE_G_DUC 6 /* dp, uio, cookie */ + +#if defined(XFS_DIR_TRACE) + +void xfs_dir_trace_g_du(char *where, struct xfs_inode *dp, struct uio *uio); +void xfs_dir_trace_g_dub(char *where, struct xfs_inode *dp, struct uio *uio, + xfs_dablk_t bno); +void xfs_dir_trace_g_dun(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_da_intnode *node); +void xfs_dir_trace_g_dul(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_dir_leafblock *leaf); +void xfs_dir_trace_g_due(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_dir_leaf_entry *entry); +void xfs_dir_trace_g_duc(char *where, struct xfs_inode *dp, struct uio *uio, + xfs_off_t cookie); +void xfs_dir_trace_enter(int type, char *where, + __psunsigned_t a0, __psunsigned_t a1, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11); +#else +#define xfs_dir_trace_g_du(w,d,u) +#define xfs_dir_trace_g_dub(w,d,u,b) +#define xfs_dir_trace_g_dun(w,d,u,n) +#define xfs_dir_trace_g_dul(w,d,u,l) +#define xfs_dir_trace_g_due(w,d,u,e) +#define xfs_dir_trace_g_duc(w,d,u,c) +#endif /* DEBUG */ + +#endif /* __XFS_DIR_SF_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dmapi.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dmapi.c --- linux-2.4.19/fs/xfs/xfs_dmapi.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dmapi.c Tue Dec 3 16:31:18 2002 @@ -0,0 +1,2836 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +#define MAXNAMLEN MAXNAMELEN + +#define XFS_BHV_LOOKUP(vp, xbdp) \ + xbdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops); \ + ASSERT(xbdp); + +STATIC int prohibited_mr_events(vnode_t *vp); + +/* Structure used to hold the on-disk version of a dm_attrname_t. All + on-disk attribute names start with the 8-byte string "SGI_DMI_". +*/ + +typedef struct { + char dan_chars[DMATTR_PREFIXLEN + DM_ATTR_NAME_SIZE + 1]; +} dm_dkattrname_t; + +/* In the on-disk inode, DMAPI attribute names consist of the user-provided + name with the DMATTR_PREFIXSTRING pre-pended. This string must NEVER be + changed! +*/ + +STATIC const char dmattr_prefix[DMATTR_PREFIXLEN + 1] = DMATTR_PREFIXSTRING; + +STATIC dm_size_t dm_min_dio_xfer = 0; /* direct I/O disabled for now */ + + +/* See xfs_dm_get_dmattr() for a description of why this is needed. */ + +#define XFS_BUG_KLUDGE 256 /* max size of an in-inode attribute value */ + +#define DM_MAX_ATTR_BYTES_ON_DESTROY 256 + +#define DM_STAT_SIZE(namelen) \ + (sizeof(dm_stat_t) + sizeof(xfs_handle_t) + namelen) +#define MAX_DIRENT_SIZE (sizeof(dirent_t) + MAXNAMELEN) + +#define DM_STAT_ALIGN (sizeof(__uint64_t)) + +/* DMAPI's E2BIG == EA's ERANGE */ +#define DM_EA_XLATE_ERR(err) { if (err == ERANGE) err = E2BIG; } + +/* + * xfs_dm_send_data_event() + * + * Send data event to DMAPI. Drop IO lock (if specified) before + * the dm_send_data_event() call and reacquire it afterwards. + */ +int +xfs_dm_send_data_event( + dm_eventtype_t event, + bhv_desc_t *bdp, + xfs_off_t offset, + size_t length, + int flags, + vrwlock_t *locktype) +{ + int error; + xfs_inode_t *ip = XFS_BHVTOI(bdp); + uint16_t dmstate; + + /* + * Now we need to simulate VOP_RWLOCK/VOP_RWLOCK. We can't + * just call the VOP though, or we'll wind up going through + * the dsvn layer for CXFS. We have to avoid getting tokens, + * so we go straight to XFS. + */ + ASSERT(BHV_IS_XFS(bdp)); + do { + dmstate = ip->i_iocore.io_dmstate; + if (locktype) + xfs_rwunlock(bdp, *locktype); + error = dm_send_data_event(event, bdp, DM_RIGHT_NULL, + offset, length, flags); + if (locktype) + xfs_rwlock(bdp, *locktype); + } while (!error && (ip->i_iocore.io_dmstate != dmstate)); + + return error; +} + +/* xfs_dm_create_event + * + * Conditionally send a DM_EVENT_CREATE. The event will not be sent if + * we can check the directory and find the name (to be created) already + * there. Some sort of a "double check" is required since in the + * xfs_create and xfs_mkdir routines, we determine that there is not a + * duplicate with the directory ilock held. We cannot send an event with + * the ilock held, since this can potentially lead to a deadlock. + * Dropping the ilock while the event is being sent is unwise since the + * directory may have changed by the time we reacquire the lock. Hence + * this workaround. + * + * Note that after we have determined that the name does/does not exist, + * the situation might have changed by the time we get back to + * xfs_create/xfs_mkdir. So the workaround does not really solve the + * problem. The results can be missing or redundant create events. + */ + +int +xfs_dm_send_create_event( + bhv_desc_t *dir_bdp, + char *name, + mode_t new_mode, + int *good_event_sent) +{ + xfs_inode_t *dip; + xfs_ino_t inum; + vnode_t *dir_vp; + int error; + int name_len; + + dir_vp = BHV_TO_VNODE(dir_bdp); + + if (*name == '\0') + return 0; + + dip = XFS_BHVTOI (dir_bdp); + xfs_ilock (dip, XFS_ILOCK_EXCL); + + vn_trace_entry(dir_vp, "xfs_dm_send_create_event", + (inst_t *)__return_address); + + /* + * Handle degenerate pathname component. + */ + +#ifdef __sgi + /* + * Try the directory name lookup cache. + */ + if (bdp = dnlc_lookup_fast(dir_vp, name, NULL, &fd, NOCRED, VN_GET_NOWAIT)) { + xfs_iunlock (dip, XFS_ILOCK_EXCL); + VN_RELE (BHV_TO_VNODE(bdp)); + return 0; + } +#endif + + /* + * Else call the directory code. + */ + + name_len = strlen(name); + error = XFS_DIR_LOOKUP(dip->i_mount, NULL, dip, name, name_len, &inum); + xfs_iunlock (dip, XFS_ILOCK_EXCL); + if (error != ENOENT) + return 0; + error = dm_send_namesp_event(DM_EVENT_CREATE, dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, new_mode, 0, 0); + if (!error) + *good_event_sent = 1; + return error; +} + +/* prohibited_mr_events + * + * Return event bits representing any events which cannot have managed + * region events set due to memory mapping of the file. If the maximum + * protection allowed in any pregion includes PROT_WRITE, and the region + * is shared and not text, then neither READ nor WRITE events can be set. + * Otherwise if the file is memory mapped, no READ event can be set. + * + */ + +STATIC int +prohibited_mr_events(vnode_t *vp) +{ + int prohibited; + struct address_space *mapping; + struct vm_area_struct *vma; + + if(!VN_MAPPED(vp)) + return 0; + + prohibited = 1 << DM_EVENT_READ; + mapping = LINVFS_GET_IP(vp)->i_mapping; + + spin_lock(&mapping->i_shared_lock); + + for( vma = mapping->i_mmap_shared; vma; vma = vma->vm_next ) { + if( vma && (!vma->vm_flags & VM_DENYWRITE) ){ + prohibited |= 1 << DM_EVENT_WRITE; + break; + } + } + + spin_unlock(&mapping->i_shared_lock); + return prohibited; +} + + +#ifdef DEBUG_RIGHTS +STATIC int +xfs_bdp_to_hexhandle( + bhv_desc_t *bdp, + u_int type, + char *buffer) +{ + xfs_handle_t handle; + vnode_t *vp; + u_char *ip; + int length; + int error; + int i; + + vp = BHV_TO_VNODE(bdp); + + if ((error = dm_vp_to_handle(vp, &handle))) + return(error); + + if (type == DM_FSYS_OBJ) { /* a filesystem handle */ + length = FSHSIZE; + } else { + length = XFS_HSIZE(handle); + } + for (ip = (u_char *)&handle, i = 0; i < length; i++) { + *buffer++ = "0123456789abcdef"[ip[i] >> 4]; + *buffer++ = "0123456789abcdef"[ip[i] & 0xf]; + } + *buffer = '\0'; + return(0); +} +#endif /* DEBUG_RIGHTS */ + + + + +/* Copy in and validate an attribute name from user space. It should be a + string of at least one and at most DM_ATTR_NAME_SIZE characters. Because + the dm_attrname_t structure doesn't provide room for the trailing NULL + byte, we just copy in one extra character and then zero it if it + happens to be non-NULL. +*/ + +STATIC int +xfs_copyin_attrname( + dm_attrname_t *from, /* dm_attrname_t in user space */ + dm_dkattrname_t *to) /* name buffer in kernel space */ +{ + int error; + size_t len; + + strcpy(to->dan_chars, dmattr_prefix); + + len = strnlen_user((char*)from, DM_ATTR_NAME_SIZE); + error = copy_from_user(&to->dan_chars[DMATTR_PREFIXLEN], from, len); + + if (!error && (to->dan_chars[DMATTR_PREFIXLEN] == '\0')) + error = EINVAL; + if (error == ENAMETOOLONG) { + to->dan_chars[sizeof(to->dan_chars) - 1] = '\0'; + error = 0; + } + return(error); +} + + +/* This copies selected fields in an inode into a dm_stat structure. Because + these fields must return the same values as they would in stat(), the + majority of this code was copied directly from xfs_getattr(). Any future + changes to xfs_gettattr() must also be reflected here. + + The inode must be kept locked SHARED by the caller. +*/ + +STATIC void +xfs_ip_to_stat( + xfs_mount_t *mp, + dm_stat_t *buf, + xfs_inode_t *ip) +{ + vnode_t *vp = XFS_ITOV(ip); + + buf->dt_size = ip->i_d.di_size; + buf->dt_dev = ip->i_mount->m_dev; + + buf->dt_ino = ip->i_ino; +#if XFS_BIG_FILESYSTEMS + buf->dt_ino += mp->m_inoadd; +#endif + /* + * Copy from in-core inode. + */ + buf->dt_mode = VTTOIF(vp->v_type) | (ip->i_d.di_mode & MODEMASK); + buf->dt_uid = ip->i_d.di_uid; + buf->dt_gid = ip->i_d.di_gid; + buf->dt_nlink = ip->i_d.di_nlink; + /* + * Minor optimization, check the common cases first. + */ + if ((vp->v_type == VREG) || (vp->v_type == VDIR)) { + buf->dt_rdev = 0; + } else if ((vp->v_type == VCHR) || (vp->v_type == VBLK) ) { + buf->dt_rdev = IRIX_DEV_TO_KDEVT(ip->i_df.if_u2.if_rdev); + } else { + buf->dt_rdev = 0; /* not a b/c spec. */ + } + + buf->dt_atime = ip->i_d.di_atime.t_sec; + buf->dt_mtime = ip->i_d.di_mtime.t_sec; + buf->dt_ctime = ip->i_d.di_ctime.t_sec; + + switch (ip->i_d.di_mode & IFMT) { + case IFBLK: + case IFCHR: + buf->dt_blksize = BLKDEV_IOSIZE; + break; + default: + /* + * We use the read buffer size as a recommended I/O + * size. This should always be larger than the + * write buffer size, so it should be OK. + * The value returned is in bytes. + */ + buf->dt_blksize = 1 << mp->m_readio_log; + break; + } + + /* + * XXX : truncate to 32 bits for now. + */ + buf->dt_blocks = + XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); + + /* + * XFS-added attributes + */ + + /* + * convert di_flags to xflags + */ + buf->dt_xfs_xflags = 0; + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) + buf->dt_xfs_xflags |= DM_XFLAG_REALTIME; + if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) + buf->dt_xfs_xflags |= DM_XFLAG_PREALLOC; + if (XFS_IFORK_Q(ip)) + buf->dt_xfs_xflags |= DM_XFLAG_HASATTR; + buf->dt_xfs_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; + buf->dt_xfs_extents = (ip->i_df.if_flags & XFS_IFEXTENTS) ? + ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_nextents; + if (ip->i_afp != NULL) { + buf->dt_xfs_aextents = + (ip->i_afp->if_flags & XFS_IFEXTENTS) ? + ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_anextents; + } else { + buf->dt_xfs_aextents = 0; + } + + /* Now fill in the fields that xfs_getattr() doesn't do. */ + + buf->dt_emask = ip->i_d.di_dmevmask; + buf->dt_nevents = DM_EVENT_MAX; + buf->dt_pers = 0; + buf->dt_change = 0; + buf->dt_dtime = ip->i_d.di_ctime.t_sec; + buf->dt_xfs_dmstate = ip->i_d.di_dmstate; + buf->dt_xfs_igen = ip->i_d.di_gen; + + /* Set if one of READ, WRITE or TRUNCATE bits is set in emask */ + + buf->dt_pmanreg = ( DMEV_ISSET(DM_EVENT_READ, buf->dt_emask) || + DMEV_ISSET(DM_EVENT_WRITE, buf->dt_emask) || + DMEV_ISSET(DM_EVENT_TRUNCATE, buf->dt_emask) ) ? 1 : 0; +} + + +/* + * This is used by dm_get_bulkattr() as well as dm_get_dirattrs(). + * Given a inumber, it igets the inode and fills the given buffer + * with the dm_stat structure for the file. + */ +/* ARGSUSED */ +STATIC int +xfs_dm_bulkstat_one( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* buffer to place output in */ + xfs_daddr_t bno, /* starting block of inode cluster */ + void *dip, /* on-disk inode pointer */ + int *res) /* bulkstat result code */ +{ + xfs_inode_t *ip; + dm_stat_t *buf; + xfs_handle_t handle; + u_int statstruct_sz; + int error; + + buf = (dm_stat_t *)buffer; + + if (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino) { + *res = BULKSTAT_RV_NOTHING; + return EINVAL; + } + error = xfs_iget(mp, tp, ino, XFS_ILOCK_SHARED, &ip, bno); + if (error) { + *res = BULKSTAT_RV_NOTHING; + return(error); + } + if (ip->i_d.di_mode == 0) { + xfs_iput_new(ip, XFS_ILOCK_SHARED); + *res = BULKSTAT_RV_NOTHING; + return(ENOENT); + } + + /* + * copy everything to the dm_stat buffer + */ + xfs_ip_to_stat(mp, buf, ip); + + /* + * Make the handle and the link to the next dm_stat buffer + */ + dm_vp_to_handle(XFS_ITOV(ip), &handle); + bcopy(&handle, buf+1, sizeof(handle)); /* handle follows stat struct */ + + buf->dt_handle.vd_offset = (ssize_t) sizeof(dm_stat_t); + buf->dt_handle.vd_length = (size_t) XFS_HSIZE(handle); + + /* + * xfs_bulkstat increments the buf if calls the formatter with + * by the size passed into it, which is this here size. + */ + statstruct_sz = DM_STAT_SIZE(0); + statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); + buf->_link = statstruct_sz; + + /* + * This is unused in bulkstat - so we zero it out. + */ + bzero((void *) &buf->dt_compname, sizeof(dm_vardata_t)); + + xfs_iput(ip, XFS_ILOCK_SHARED); + + *res = BULKSTAT_RV_DIDONE; + return(0); +} + + +STATIC int +xfs_get_dirents( + xfs_inode_t *dirp, + void *bufp, + size_t bufsz, + off_t *locp, + size_t *nreadp) +{ + int sink; + struct uio auio; + struct iovec aiov; + int rval; + + *nreadp = 0; + + aiov.iov_base = bufp; + aiov.iov_len = bufsz; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = *locp; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_resid = bufsz; + + rval = XFS_DIR_GETDENTS(dirp->i_mount, NULL, dirp, &auio, &sink); + if (! rval) { + *locp = (off_t) auio.uio_offset; + + /* + * number of bytes read into the dirent buffer + */ + *nreadp = bufsz - auio.uio_resid; + } + return(rval); +} + + +STATIC int +xfs_dirents_to_stats( + xfs_mount_t *mp, + xfs_dirent_t *direntp, /* array of dirent structs */ + void *bufp, /* buffer to fill */ + size_t direntbufsz, /* sz of filled part of dirent buf */ + size_t *spaceleftp, /* IO - space left in user buffer */ + size_t *nwrittenp, /* number of bytes written to 'bufp' */ + off_t *locp) +{ + xfs_dirent_t *p; + dm_stat_t *statp; + size_t reclen; + size_t namelen; + size_t spaceleft; + off_t prevoff; + int res; + + spaceleft = *spaceleftp; + *spaceleftp = 0; + *nwrittenp = 0; + prevoff = 0; /* sizeof this getdents record */ + + /* + * Go thru all the dirent records, making dm_stat structures from + * them, one by one, until dirent buffer is empty or stat buffer + * is full. + */ + p = direntp; + statp = (dm_stat_t *) bufp; + for (reclen = (size_t) p->d_reclen; direntbufsz > 0; + direntbufsz -= reclen, + p = (xfs_dirent_t *) ((char *) p + reclen), + reclen = (size_t) p->d_reclen) { + + namelen = strlen(p->d_name) + 1; + + /* + * Make sure we have enough space. + */ + if (spaceleft <= DM_STAT_SIZE(namelen)) { + /* + * d_off field in dirent_t points at the next entry. + */ + if (prevoff) /* did at least one; update location */ + *locp = prevoff; + *spaceleftp = 0; + + /* + * The last link is NULL. + */ + statp->_link = 0; + return(0); + } + + statp = (dm_stat_t *) bufp; + + (void)xfs_dm_bulkstat_one(mp, NULL, (xfs_ino_t)p->d_ino, statp, 0, 0, &res); + if (res != BULKSTAT_RV_DIDONE) + continue; + + /* + * On return from bulkstat_one(), stap->_link points + * at the end of the handle in the stat structure. + */ + statp->dt_compname.vd_offset = statp->_link; + statp->dt_compname.vd_length = namelen; + /* + * Directory entry name is guaranteed to be + * null terminated; the copy gets the '\0' too. + */ + bcopy(p->d_name, (char *) statp + statp->_link, namelen); + + /* Word-align the record */ + statp->_link = (statp->_link + namelen + (DM_STAT_ALIGN - 1)) + & ~(DM_STAT_ALIGN - 1); + + spaceleft -= statp->_link; + *nwrittenp += statp->_link; + bufp = (char *)statp + statp->_link; + + /* + * We need to rollback to this position if something happens. + * So we remember it. + */ + prevoff = p->d_off; + } + statp->_link = 0; + + /* + * If there's space left to put in more, caller should know that.. + */ + if (spaceleft > DM_STAT_SIZE(MAXNAMLEN)) { + *spaceleftp = spaceleft; + } + return(0); +} + + +/* xfs_dm_f_get_eventlist - return the dm_eventset_t mask for inode vp. */ + +STATIC int +xfs_dm_f_get_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int *nelemp) /* in kernel space! */ +{ + dm_eventset_t eventset; + xfs_inode_t *ip; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + /* Note that we MUST return a regular file's managed region bits as + part of the mask because dm_get_eventlist is supposed to return the + union of all managed region flags in those bits. Since we only + support one region, we can just return the bits as they are. For + all other object types, the bits will already be zero. Handy, huh? + */ + + ip = XFS_BHVTOI(bdp); + eventset = ip->i_d.di_dmevmask; + + /* Now copy the event mask and event count back to the caller. We + return the lesser of nelem and DM_EVENT_MAX. + */ + + if (nelem > DM_EVENT_MAX) + nelem = DM_EVENT_MAX; + eventset &= (1 << nelem) - 1; + + *eventsetp = eventset; + *nelemp = nelem; + return(0); +} + + +/* xfs_dm_f_set_eventlist - update the dm_eventset_t mask in the inode vp. Only the + bits from zero to maxevent-1 are being replaced; higher bits are preserved. +*/ + +STATIC int +xfs_dm_f_set_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent) +{ + dm_eventset_t eventset; + dm_eventset_t max_mask; + dm_eventset_t valid_events; + vnode_t *vp; + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + eventset = *eventsetp; + if (maxevent >= sizeof(ip->i_d.di_dmevmask) * NBBY) + return(EINVAL); + max_mask = (1 << maxevent) - 1; + + vp = BHV_TO_VNODE(bdp); + if (vp->v_type == VDIR) { + valid_events = DM_XFS_VALID_DIRECTORY_EVENTS; + } else { /* file or symlink */ + valid_events = DM_XFS_VALID_FILE_EVENTS; + } + if ((eventset & max_mask) & ~valid_events) + return(EINVAL); + + /* Adjust the event mask so that the managed region bits will not + be altered. + */ + + max_mask &= ~(1 <i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return(error); + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + + ip->i_d.di_dmevmask = (eventset & max_mask) | (ip->i_d.di_dmevmask & ~max_mask); + ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + VN_HOLD(vp); + xfs_trans_commit(tp, 0, NULL); + + return(0); +} + + +/* xfs_dm_fs_get_eventlist - return the dm_eventset_t mask for filesystem vfsp. */ + +STATIC int +xfs_dm_fs_get_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int *nelemp) /* in kernel space! */ +{ + dm_eventset_t eventset; + xfs_mount_t *mp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + mp = XFS_BHVTOI(bdp)->i_mount; + eventset = mp->m_dmevmask; + + /* Now copy the event mask and event count back to the caller. We + return the lesser of nelem and DM_EVENT_MAX. + */ + + if (nelem > DM_EVENT_MAX) + nelem = DM_EVENT_MAX; + eventset &= (1 << nelem) - 1; + + *eventsetp = eventset; + *nelemp = nelem; + return(0); +} + + +/* xfs_dm_fs_set_eventlist - update the dm_eventset_t mask in the mount structure for + filesystem vfsp. Only the bits from zero to maxevent-1 are being replaced; + higher bits are preserved. +*/ + +STATIC int +xfs_dm_fs_set_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent) +{ + dm_eventset_t eventset; + dm_eventset_t max_mask; + xfs_mount_t *mp; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + eventset = *eventsetp; + + mp = XFS_BHVTOI(bdp)->i_mount; + if (maxevent >= sizeof(mp->m_dmevmask) * NBBY) + return(EINVAL); + max_mask = (1 << maxevent) - 1; + + if ((eventset & max_mask) & ~DM_XFS_VALID_FS_EVENTS) + return(EINVAL); + + mp->m_dmevmask = (eventset & max_mask) | (mp->m_dmevmask & ~max_mask); + return(0); +} + + +/* Code in this routine must exactly match the logic in xfs_diordwr() in + order for this to work! +*/ + +STATIC int +xfs_dm_direct_ok( + bhv_desc_t *bdp, + dm_off_t off, + dm_size_t len, + void *bufp) +{ + xfs_mount_t *mp; + xfs_inode_t *ip; + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + /* Realtime files can ONLY do direct I/O. */ + + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) + return(1); + + /* If direct I/O is disabled, or if the request is too small, use + buffered I/O. + */ + + if (!dm_min_dio_xfer || len < dm_min_dio_xfer) + return(0); + +#if 0 + /* If the request is not well-formed or is too large, use + buffered I/O. + */ + + if ((__psint_t)bufp & scache_linemask) /* if buffer not aligned */ + return(0); + if (off & mp->m_blockmask) /* if file offset not aligned */ + return(0); + if (len & mp->m_blockmask) /* if xfer length not aligned */ + return(0); + if (len > ctooff(v.v_maxdmasz - 1)) /* if transfer too large */ + return(0); + + /* A valid direct I/O candidate. */ + + return(1); +#else + return(0); +#endif +} + + +/* We need to be able to select various combinations of FINVIS, O_NONBLOCK, + O_DIRECT, and O_SYNC, yet we don't have a file descriptor and we don't have + the file's pathname. All we have is a handle. +*/ + +STATIC int +xfs_dm_rdwr( + vnode_t *vp, + uint fflag, + mode_t fmode, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + int error; + int oflags; + ssize_t xfer; + struct file file; + struct inode *ip; + struct dentry *dentry; + struct list_head *lp; + bhv_desc_t *xbdp; + + if (off < 0 || vp->v_type != VREG) + return(EINVAL); + + if (fmode & FMODE_READ) { + XFS_STATS_INC(xfsstats.xs_read_calls); + oflags = O_RDONLY; + } else { + XFS_STATS_INC(xfsstats.xs_write_calls); + oflags = O_WRONLY; + } + + /* Build file descriptor flags and I/O flags. O_NONBLOCK is needed so + that we don't block on mandatory file locks. FINVIS is needed so + that we don't change any file timestamps. + */ + + fmode |= FINVIS; + oflags |= O_NONBLOCK; + XFS_BHV_LOOKUP(vp, xbdp); + if (xfs_dm_direct_ok(xbdp, off, len, bufp)) + oflags |= O_DIRECT; + + if (fflag & O_SYNC) + oflags |= O_SYNC; + + ip = LINVFS_GET_IP(vp); + if( ip->i_fop == NULL ){ + /* no iput; caller did get, and will do put */ + return(EINVAL); + } + igrab(ip); + + /* Find a dentry. Get a well-connected one, if possible. */ + spin_lock(&dcache_lock); + for (lp = ip->i_dentry.next; lp != &ip->i_dentry ; lp=lp->next) { + dentry = list_entry(lp,struct dentry, d_alias); + if (! (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) { + dget_locked(dentry); + dentry->d_vfs_flags |= DCACHE_REFERENCED; + spin_unlock(&dcache_lock); + iput(ip); + goto found; + } + } + spin_unlock(&dcache_lock); + dentry = d_alloc_root(ip); + if (dentry == NULL) { + iput(ip); + return ENOMEM; + } + dentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + +found: + if( ip->i_ino != dentry->d_inode->i_ino ){ + dput(dentry); + return EINVAL; + } + + if (fmode & FMODE_WRITE) { + error = get_write_access(ip); + if (error) { + dput(dentry); + return(-error); + } + } + + error = init_private_file( &file, dentry, fmode ); + if(error){ + if (error == -EFBIG) { + /* try again */ + oflags |= O_LARGEFILE; + file.f_flags = oflags; + error = file.f_op->open( dentry->d_inode, &file ); + } + if (error) { + if (fmode & FMODE_WRITE) + put_write_access(ip); + dput(dentry); + return(EINVAL); + } + } + + file.f_flags = oflags; + + if (fmode & FMODE_READ) { + VOP_READ(vp, &file, bufp, len, &off, NULL, xfer); + } else { + VOP_WRITE(vp, &file, bufp, len, &off, NULL, xfer); + } + if (xfer >= 0) { + *rvp = xfer; + error = 0; + linvfs_revalidate_core(ip, ATTR_COMM); + if (fmode & FMODE_READ) { + XFS_STATS_ADD(xfsstats.xs_read_bytes, xfer); + } else { + XFS_STATS_ADD(xfsstats.xs_write_bytes, xfer); + } + } else { + error = -(int)xfer; + } + + if (file.f_mode & FMODE_WRITE) + put_write_access(ip); + if (file.f_op->release) + file.f_op->release(ip, &file); + dput(dentry); + return error; +} + +/* ARGSUSED */ +STATIC int +xfs_dm_clear_inherit( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_create_by_handle( + vnode_t *vp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_downgrade_right( + vnode_t *vp, + dm_right_t right, + u_int type) /* DM_FSYS_OBJ or zero */ +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + bhv_desc_t *bdp; + + XFS_BHV_LOOKUP(vp, bdp); + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_downgrade_right: old %d new %d type %d handle %s\n", + right, DM_RIGHT_SHARED, type, buffer); + } else { + printf("dm_downgrade_right: old %d new %d type %d handle " + "\n", right, DM_RIGHT_SHARED, type); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +/* Note: xfs_dm_get_allocinfo() makes no attempt to coalesce two adjacent + extents when both are of type DM_EXTENT_RES; this is left to the caller. + XFS guarantees that there will never be two adjacent DM_EXTENT_HOLE extents. + + In order to provide the caller with all extents in a file including + those beyond the file's last byte offset, we have to use the xfs_bmapi() + interface. (VOP_BMAP won't let us see past EOF, and xfs_getbmap is too + buggy.) +*/ + +STATIC int +xfs_dm_get_allocinfo_rvp( + vnode_t *vp, + dm_right_t right, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvp) +{ + xfs_inode_t *ip; /* xfs incore inode pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_fileoff_t fsb_offset; + xfs_filblks_t fsb_length; + dm_off_t startoff; + int elem; + bhv_desc_t *xbdp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + if (copy_from_user( &startoff, offp, sizeof(startoff))) + return(EFAULT); + + if (startoff > XFS_MAX_FILE_OFFSET) + return(EINVAL); + + if (nelem == 0) { + if (put_user(1, nelemp)) + return(EFAULT); + return(E2BIG); + } + + XFS_BHV_LOOKUP(vp, xbdp); + + ip = XFS_BHVTOI(xbdp); + mp = ip->i_mount; + + /* Convert the caller's starting offset into filesystem allocation + units as required by xfs_bmapi(). Round the offset down so that + it is sure to be included in the reply. + */ + + fsb_offset = XFS_B_TO_FSBT(mp, startoff); + fsb_length = XFS_B_TO_FSB(mp, XFS_MAX_FILE_OFFSET) - fsb_offset; + elem = 0; + + while (fsb_length && elem < nelem) { + xfs_bmbt_irec_t bmp[50]; + dm_extent_t extent; + xfs_filblks_t fsb_bias; + dm_size_t bias; + int error; + int lock; + int num; + int i; + + /* Compute how many getbmap structures to use on the xfs_bmapi + call. + */ + + num = MIN(nelem - elem, sizeof(bmp) / sizeof(bmp[0])); + + xfs_ilock(ip, XFS_IOLOCK_SHARED); + lock = xfs_ilock_map_shared(ip); + + error = xfs_bmapi(NULL, ip, fsb_offset, fsb_length, + XFS_BMAPI_ENTIRE, NULL, 0, bmp, &num, NULL); + + xfs_iunlock_map_shared(ip, lock); + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + + if (error) + return(error); + + /* Fill in the caller's extents, adjusting the bias in the + first entry if necessary. + */ + + for (i = 0; i < num; i++, extentp++) { + bias = startoff - XFS_FSB_TO_B(mp, bmp[i].br_startoff); + extent.ex_offset = startoff; + extent.ex_length = + XFS_FSB_TO_B(mp, bmp[i].br_blockcount) - bias; + if (bmp[i].br_startblock == HOLESTARTBLOCK) { + extent.ex_type = DM_EXTENT_HOLE; + } else { + extent.ex_type = DM_EXTENT_RES; + } + startoff = extent.ex_offset + extent.ex_length; + + if (copy_to_user( extentp, &extent, sizeof(extent))) + return(EFAULT); + + fsb_bias = fsb_offset - bmp[i].br_startoff; + fsb_offset += bmp[i].br_blockcount - fsb_bias; + fsb_length -= bmp[i].br_blockcount - fsb_bias; + elem++; + } + } + + if (fsb_length == 0) { + startoff = 0; + } + if (copy_to_user( offp, &startoff, sizeof(startoff))) + return(EFAULT); + + if (copy_to_user( nelemp, &elem, sizeof(elem))) + return(EFAULT); + + *rvp = (fsb_length == 0 ? 0 : 1); + + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_bulkall_rvp( + vnode_t *vp, + dm_right_t right, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, /* address of buffer in user space */ + size_t *rlenp, /* user space address */ + int *rvalp) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_bulkattr_rvp( + vnode_t *vp, + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp) +{ + int error, done; + int nelems; + u_int statstruct_sz; + dm_attrloc_t loc; + bhv_desc_t *mp_bdp; + xfs_mount_t *mp; + vfs_t *vfsp = vp->v_vfsp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + if (copy_from_user( &loc, locp, sizeof(loc))) + return(EFAULT); + + /* Because we will write directly to the user's buffer, make sure that + the buffer is properly aligned. + */ + + if (((__psint_t)bufp & (DM_STAT_ALIGN - 1)) != 0) + return(EFAULT); + + /* size of the handle is constant for this function */ + + statstruct_sz = DM_STAT_SIZE(0); + statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); + + nelems = buflen / statstruct_sz; + if (nelems < 1) { + if (put_user( statstruct_sz, rlenp )) + return(EFAULT); + return(E2BIG); + } + + mp_bdp = bhv_lookup(VFS_BHVHEAD(vfsp), &xfs_vfsops); + ASSERT(mp_bdp); + mp = XFS_BHVTOM(mp_bdp); + + + /* + * fill the buffer with dm_stat_t's + */ + + error = xfs_bulkstat(mp, NULL, + (xfs_ino_t *)&loc, + &nelems, + xfs_dm_bulkstat_one, + statstruct_sz, + bufp, + BULKSTAT_FG_IGET, + &done); + if (error) + return(error); + if (!done) { + *rvalp = 1; + } else { + *rvalp = 0; + } + + if (put_user( statstruct_sz * nelems, rlenp )) + return(EFAULT); + + if (copy_to_user( locp, &loc, sizeof(loc))) + return(EFAULT); + + /* + * If we didn't do any, we must not have any more to do. + */ + if (nelems < 1) + return(0); + /* set _link in the last struct to zero */ + if (put_user( 0, + &((dm_stat_t *)((char *)bufp + statstruct_sz*(nelems-1)))->_link) + ) + return(EFAULT); + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_config( + vnode_t *vp, + dm_right_t right, + dm_config_t flagname, + dm_size_t *retvalp) +{ + dm_size_t retval; + + switch (flagname) { + case DM_CONFIG_DTIME_OVERLOAD: + case DM_CONFIG_PERS_ATTRIBUTES: + case DM_CONFIG_PERS_EVENTS: + case DM_CONFIG_PERS_MANAGED_REGIONS: + case DM_CONFIG_PUNCH_HOLE: + case DM_CONFIG_WILL_RETRY: + retval = DM_TRUE; + break; + + case DM_CONFIG_CREATE_BY_HANDLE: /* these will never be done */ + case DM_CONFIG_LOCK_UPGRADE: + case DM_CONFIG_PERS_INHERIT_ATTRIBS: + retval = DM_FALSE; + break; + + case DM_CONFIG_BULKALL: /* these will be done someday */ + retval = DM_FALSE; + break; + case DM_CONFIG_MAX_ATTR_ON_DESTROY: + retval = DM_MAX_ATTR_BYTES_ON_DESTROY; + break; + + case DM_CONFIG_MAX_ATTRIBUTE_SIZE: + retval = ATTR_MAX_VALUELEN; + break; + + case DM_CONFIG_MAX_HANDLE_SIZE: + retval = DM_MAX_HANDLE_SIZE; + break; + + case DM_CONFIG_MAX_MANAGED_REGIONS: + retval = 1; + break; + + case DM_CONFIG_TOTAL_ATTRIBUTE_SPACE: + retval = 0x7fffffff; /* actually it's unlimited */ + break; + + default: + return(EINVAL); + } + + /* Copy the results back to the user. */ + + if (copy_to_user( retvalp, &retval, sizeof(retval))) + return(EFAULT); + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_config_events( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + dm_eventset_t eventset; + + if (nelem == 0) + return(EINVAL); + + eventset = DM_XFS_SUPPORTED_EVENTS; + + /* Now copy the event mask and event count back to the caller. We + return the lesser of nelem and DM_EVENT_MAX. + */ + + if (nelem > DM_EVENT_MAX) + nelem = DM_EVENT_MAX; + eventset &= (1 << nelem) - 1; + + if (copy_to_user( eventsetp, &eventset, sizeof(eventset))) + return(EFAULT); + + if (put_user(nelem, nelemp)) + return(EFAULT); + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_destroy_dmattr( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + char **valuepp, + int *vlenp) +{ + char buffer[XFS_BUG_KLUDGE]; + dm_dkattrname_t dkattrname; + int alloc_size; + int value_len; + char *value; + int error; + + *vlenp = -1; /* assume failure by default */ + + if (attrnamep->an_chars[0] == '\0') + return(EINVAL); + + /* Build the on-disk version of the attribute name. */ + + strcpy(dkattrname.dan_chars, dmattr_prefix); + strncpy(&dkattrname.dan_chars[DMATTR_PREFIXLEN], + (char *)attrnamep->an_chars, DM_ATTR_NAME_SIZE + 1); + dkattrname.dan_chars[sizeof(dkattrname.dan_chars) - 1] = '\0'; + + /* VOP_ATTR_GET will not return anything if the buffer is too small, + and we don't know how big to make the buffer, so this may take + two tries to get it right. The initial try must use a buffer of + at least XFS_BUG_KLUDGE bytes to prevent buffer overflow because + of a bug in XFS. + */ + + alloc_size = 0; + value_len = sizeof(buffer); /* in/out parameter */ + value = buffer; + + VOP_ATTR_GET(vp, dkattrname.dan_chars, value, &value_len, + ATTR_ROOT, sys_cred, error); + + if (error == ERANGE) { + alloc_size = value_len; + value = kmalloc(alloc_size, SLAB_KERNEL); + if (value == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return(ENOMEM); + } + + VOP_ATTR_GET(vp, dkattrname.dan_chars, value, + &value_len, ATTR_ROOT, sys_cred, error); + } + if (error) { + if (alloc_size) + kfree(value); + DM_EA_XLATE_ERR(error); + return(error); + } + + /* The attribute exists and has a value. Note that a value_len of + zero is valid! + */ + + if (value_len == 0) { + *vlenp = 0; + return(0); + } + + if (!alloc_size) { + value = kmalloc(value_len, SLAB_KERNEL); + if (value == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + return(ENOMEM); + } + bcopy(buffer, value, value_len); + } else if (value_len > DM_MAX_ATTR_BYTES_ON_DESTROY) { + int value_len2 = DM_MAX_ATTR_BYTES_ON_DESTROY; + char *value2; + + value2 = kmalloc(value_len2, SLAB_KERNEL); + if (value2 == NULL) { + printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); + kfree(value); + return(ENOMEM); + } + bcopy(value, value2, value_len2); + kfree(value); + value = value2; + value_len = value_len2; + } + *vlenp = value_len; + *valuepp = value; + return(0); +} + +/* This code was taken from xfs_fcntl(F_DIOINFO) and modified slightly because + we don't have a flags parameter (no open file). + Taken from xfs_ioctl(XFS_IOC_DIOINFO) on Linux. +*/ + +STATIC int +xfs_dm_get_dioinfo( + vnode_t *vp, + dm_right_t right, + dm_dioinfo_t *diop) +{ + dm_dioinfo_t dio; + xfs_mount_t *mp; + xfs_inode_t *ip; + bhv_desc_t *xbdp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + XFS_BHV_LOOKUP(vp, xbdp); + + ip = XFS_BHVTOI(xbdp); + mp = ip->i_mount; + + /* + * this only really needs to be BBSIZE. + * it is set to the file system block size to + * avoid having to do block zeroing on short writes. + */ + dio.d_miniosz = mp->m_sb.sb_blocksize; + dio.d_maxiosz = XFS_FSB_TO_B(mp, + XFS_B_TO_FSBT(mp, KIO_MAX_ATOMIC_IO << 10)); + dio.d_mem = 512; + + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + dio.d_dio_only = DM_TRUE; + } else { + dio.d_dio_only = DM_FALSE; + } + + if (copy_to_user(diop, &dio, sizeof(dio))) + return(EFAULT); + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_dirattrs_rvp( + vnode_t *vp, + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, /* address of buffer in user space */ + size_t *rlenp, /* user space address */ + int *rvp) +{ + xfs_inode_t *dp; + xfs_mount_t *mp; + size_t direntbufsz, statbufsz; + size_t nread, spaceleft, nwritten=0; + void *direntp, *statbufp; + uint lock_mode; + int error; + dm_attrloc_t loc; + bhv_desc_t *xbdp; + bhv_desc_t *mp_bdp; + vfs_t *vfsp = vp->v_vfsp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + if (copy_from_user( &loc, locp, sizeof(loc))) + return(EFAULT); + + if ((buflen / DM_STAT_SIZE(MAXNAMLEN)) == 0) { + if (put_user( DM_STAT_SIZE(MAXNAMLEN), rlenp )) + return(EFAULT); + return(E2BIG); + } + + mp_bdp = bhv_lookup(VFS_BHVHEAD(vfsp), &xfs_vfsops); + ASSERT(mp_bdp); + xbdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops); + ASSERT(xbdp); + + mp = XFS_BHVTOM(mp_bdp); + dp = XFS_BHVTOI(xbdp); + if ((dp->i_d.di_mode & IFMT) != IFDIR) + return(ENOTDIR); + + /* + * Don't get more dirents than are guaranteed to fit. + * The minimum that the stat buf holds is the buf size over + * maximum entry size. That times the minimum dirent size + * is an overly conservative size for the dirent buf. + */ + statbufsz = NBPP; + direntbufsz = (NBPP / DM_STAT_SIZE(MAXNAMLEN)) * sizeof(xfs_dirent_t); + + direntp = kmem_alloc(direntbufsz, KM_SLEEP); + statbufp = kmem_alloc(statbufsz, KM_SLEEP); + error = 0; + spaceleft = buflen; + /* + * Keep getting dirents until the ubuffer is packed with + * dm_stat structures. + */ + do { + ulong dir_gen = 0; + + lock_mode = xfs_ilock_map_shared(dp); + /* See if the directory was removed after it was opened. */ + if (dp->i_d.di_nlink <= 0) { + xfs_iunlock_map_shared(dp, lock_mode); + error = ENOENT; + break; + } + if (dir_gen == 0) + dir_gen = dp->i_gen; + else if (dir_gen != dp->i_gen) { + /* if dir changed, quit. May be overzealous... */ + xfs_iunlock_map_shared(dp, lock_mode); + break; + } + error = xfs_get_dirents(dp, direntp, direntbufsz, (off_t *)&loc, + &nread); + xfs_iunlock_map_shared(dp, lock_mode); + + if (error) { + break; + } + if (nread == 0) + break; + /* + * Now iterate thru them and call bulkstat_one() on all + * of them + */ + error = xfs_dirents_to_stats(mp, + (xfs_dirent_t *) direntp, + statbufp, + nread, + &spaceleft, + &nwritten, + (off_t *)&loc); + if (error) { + break; + } + + if (nwritten) { + if (copy_to_user( bufp, statbufp, nwritten)) { + error = EFAULT; + break; + } + break; + } + } while (spaceleft); + /* + * If xfs_get_dirents found anything, there might be more to do. + * If it didn't read anything, signal all done (rval == 0). + * (Doesn't matter either way if there was an error.) + */ + if (nread) { + *rvp = 1; + } else { + *rvp = 0; + } + + kmem_free(statbufp, statbufsz); + kmem_free(direntp, direntbufsz); + if (!error){ + if (put_user( buflen - spaceleft, rlenp)) + return(EFAULT); + } + + if (!error && copy_to_user(locp, &loc, sizeof(loc))) + error = EFAULT; + return(error); +} + + +STATIC int +xfs_dm_get_dmattr( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_dkattrname_t name; + char *value; + int value_len; + int alloc_size; + int error; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) + return(error); + + /* Allocate a buffer to receive the attribute's value. We allocate + at least one byte even if the caller specified a buflen of zero. + (A buflen of zero is considered valid.) + + Allocating a minimum of XFS_BUG_KLUDGE bytes temporarily works + around a bug within XFS in which in-inode attribute values are not + checked to see if they will fit in the buffer before they are + copied. Since no in-core attribute value can be larger than 256 + bytes (an 8-bit size field), we allocate that minimum size here to + prevent buffer overrun in both the kernel's and user's buffers. + */ + + alloc_size = buflen; + if (alloc_size < XFS_BUG_KLUDGE) + alloc_size = XFS_BUG_KLUDGE; + if (alloc_size > ATTR_MAX_VALUELEN) + alloc_size = ATTR_MAX_VALUELEN; + value = kmem_alloc(alloc_size, KM_SLEEP); + + /* Get the attribute's value. */ + + value_len = alloc_size; /* in/out parameter */ + + VOP_ATTR_GET(vp, name.dan_chars, value, &value_len, + ATTR_ROOT, NULL, error); + DM_EA_XLATE_ERR(error); + + /* DMAPI requires an errno of ENOENT if an attribute does not exist, + so remap ENOATTR here. + */ + + if (error == ENOATTR) + error = ENOENT; + if (!error && value_len > buflen) + error = E2BIG; + if (!error && copy_to_user(bufp, value, value_len)) + error = EFAULT; + if (!error || error == E2BIG) { + if (put_user(value_len, rlenp)) + error = EFAULT; + } + + kmem_free(value, alloc_size); + return(error); +} + +STATIC int +xfs_dm_get_eventlist( + vnode_t *vp, + dm_right_t right, + u_int type, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + int error; + bhv_desc_t *xbdp; + + XFS_BHV_LOOKUP(vp, xbdp); + + if (type == DM_FSYS_OBJ) { + error = xfs_dm_fs_get_eventlist(xbdp, right, nelem, + eventsetp, nelemp); + } else { + error = xfs_dm_f_get_eventlist(xbdp, right, nelem, + eventsetp, nelemp); + } + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_fileattr( + vnode_t *vp, + dm_right_t right, + u_int mask, /* not used; always return everything */ + dm_stat_t *statp) +{ + dm_stat_t stat; + xfs_inode_t *ip; + xfs_mount_t *mp; + bhv_desc_t *xbdp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + XFS_BHV_LOOKUP(vp, xbdp); + + /* Find the mount point. */ + + ip = XFS_BHVTOI(xbdp); + mp = ip->i_mount; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + xfs_ip_to_stat(mp, &stat, ip); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + if (copy_to_user( statp, &stat, sizeof(stat))) + return(EFAULT); + return(0); +} + + +/* We currently only support a maximum of one managed region per file, and + use the DM_EVENT_READ, DM_EVENT_WRITE, and DM_EVENT_TRUNCATE events in + the file's dm_eventset_t event mask to implement the DM_REGION_READ, + DM_REGION_WRITE, and DM_REGION_TRUNCATE flags for that single region. +*/ + +STATIC int +xfs_dm_get_region( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp) +{ + dm_eventset_t evmask; + dm_region_t region; + xfs_inode_t *ip; + u_int elem; + bhv_desc_t *xbdp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + XFS_BHV_LOOKUP(vp, xbdp); + + ip = XFS_BHVTOI(xbdp); + evmask = ip->i_d.di_dmevmask; /* read the mask "atomically" */ + + /* Get the file's current managed region flags out of the + dm_eventset_t mask and use them to build a managed region that + covers the entire file, i.e. set rg_offset and rg_size to zero. + */ + + bzero((char *)®ion, sizeof(region)); + + if (evmask & (1 << DM_EVENT_READ)) + region.rg_flags |= DM_REGION_READ; + if (evmask & (1 << DM_EVENT_WRITE)) + region.rg_flags |= DM_REGION_WRITE; + if (evmask & (1 << DM_EVENT_TRUNCATE)) + region.rg_flags |= DM_REGION_TRUNCATE; + + elem = (region.rg_flags ? 1 : 0); + + if (copy_to_user( nelemp, &elem, sizeof(elem))) + return(EFAULT); + if (elem > nelem) + return(E2BIG); + if (elem && copy_to_user(regbufp, ®ion, sizeof(region))) + return(EFAULT); + return(0); +} + + +STATIC int +xfs_dm_getall_dmattr( + vnode_t *vp, + dm_right_t right, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + attrlist_cursor_kern_t cursor; + attrlist_t *attrlist; + dm_attrlist_t *ulist; + int *last_link; + int alignment; + int total_size; + int list_size = 8192; /* should be big enough */ + int error; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + /* Verify that the user gave us a buffer that is 4-byte aligned, lock + it down, and work directly within that buffer. As a side-effect, + values of buflen < sizeof(int) return EINVAL. + */ + + alignment = sizeof(int) - 1; + if (((__psint_t)bufp & alignment) != 0) { + return(EFAULT); + } + buflen &= ~alignment; /* round down the alignment */ + +#if defined(HAVE_USERACC) + if ((error = useracc(bufp, buflen, B_READ, NULL)) != 0) + return error; +#endif + + /* Initialize all the structures and variables for the main loop. */ + + bzero(&cursor, sizeof(cursor)); + attrlist = (attrlist_t *)kmem_alloc(list_size, KM_SLEEP); + total_size = 0; + ulist = (dm_attrlist_t *)bufp; + last_link = NULL; + + /* Use VOP_ATTR_LIST to get the names of DMAPI attributes, and use + VOP_ATTR_GET to get their values. There is a risk here that the + DMAPI attributes could change between the VOP_ATTR_LIST and + VOP_ATTR_GET calls. If we can detect it, we return EIO to notify + the user. + */ + + do { + int i; + + /* Get a buffer full of attribute names. If there aren't any + more or if we encounter an error, then finish up. + */ + + VOP_ATTR_LIST(vp, (char *)attrlist, list_size, + ATTR_ROOT, &cursor, NULL, error); + DM_EA_XLATE_ERR(error); + + if (error || attrlist->al_count == 0) + break; + + for (i = 0; i < attrlist->al_count; i++) { + attrlist_ent_t *entry; + char *user_name; + int size_needed; + int value_len; + + /* Skip over all non-DMAPI attributes. If the + attribute name is too long, we assume it is + non-DMAPI even if it starts with the correct + prefix. + */ + + entry = ATTR_ENTRY(attrlist, i); + if (strncmp(entry->a_name, dmattr_prefix, DMATTR_PREFIXLEN)) + continue; + user_name = &entry->a_name[DMATTR_PREFIXLEN]; + if (strlen(user_name) > DM_ATTR_NAME_SIZE) + continue; + + /* We have a valid DMAPI attribute to return. If it + won't fit in the user's buffer, we still need to + keep track of the number of bytes for the user's + next call. + */ + + + size_needed = sizeof(*ulist) + entry->a_valuelen; + size_needed = (size_needed + alignment) & ~alignment; + + total_size += size_needed; + if (total_size > buflen) + continue; + + /* Start by filling in all the fields in the + dm_attrlist_t structure. + */ + + strncpy((char *)ulist->al_name.an_chars, user_name, + DM_ATTR_NAME_SIZE); + ulist->al_data.vd_offset = sizeof(*ulist); + ulist->al_data.vd_length = entry->a_valuelen; + ulist->_link = size_needed; + last_link = &ulist->_link; + + /* Next read the attribute's value into its correct + location after the dm_attrlist structure. Any sort + of error indicates that the data is moving under us, + so we return EIO to let the user know. + */ + + value_len = entry->a_valuelen; + + VOP_ATTR_GET(vp, entry->a_name, + (void *)(ulist + 1), &value_len, + ATTR_ROOT, NULL, error); + DM_EA_XLATE_ERR(error); + + if (error || value_len != entry->a_valuelen) { + error = EIO; + break; + } + + ulist = (dm_attrlist_t *)((char *)ulist + ulist->_link); + } + } while (!error && attrlist->al_more); + if (last_link) + *last_link = 0; + + if (!error && total_size > buflen) + error = E2BIG; + if (!error || error == E2BIG) { + if (put_user(total_size, rlenp)) + error = EFAULT; + } + + kmem_free(attrlist, list_size); + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_getall_inherit( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp) +{ + return(ENOSYS); +} + + +/* Initialize location pointer for subsequent dm_get_dirattrs, + dm_get_bulkattr, and dm_get_bulkall calls. The same initialization must + work for vnode-based routines (dm_get_dirattrs) and filesystem-based + routines (dm_get_bulkattr and dm_get_bulkall). Filesystem-based functions + call this routine using the filesystem's root vnode. +*/ + +/* ARGSUSED */ +STATIC int +xfs_dm_init_attrloc( + vnode_t *vp, + dm_right_t right, + dm_attrloc_t *locp) +{ + dm_attrloc_t loc = 0; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + if (copy_to_user( locp, &loc, sizeof(loc))) + return(EFAULT); + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_mkdir_by_handle( + vnode_t *vp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_probe_hole( + vnode_t *vp, + dm_right_t right, + dm_off_t off, + dm_size_t len, /* we ignore this for now */ + dm_off_t *roffp, + dm_size_t *rlenp) +{ + dm_off_t roff; + dm_size_t rlen; + xfs_inode_t *ip; + xfs_mount_t *mp; + uint lock_flags; + xfs_fsize_t realsize; + u_int bsize; + bhv_desc_t *xbdp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + XFS_BHV_LOOKUP(vp, xbdp); + + ip = XFS_BHVTOI(xbdp); + if ((ip->i_d.di_mode & IFMT) != IFREG) + return(EINVAL); + + mp = ip->i_mount; + bsize = mp->m_sb.sb_blocksize; + + lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; + xfs_ilock(ip, lock_flags); + realsize = ip->i_d.di_size; + xfs_iunlock(ip, lock_flags); + if (off >= realsize) + return(E2BIG); + + roff = (off + bsize-1) & ~(bsize-1); + rlen = 0; /* Only support punches to EOF for now */ + if (copy_to_user( roffp, &roff, sizeof(roff))) + return(EFAULT); + if (copy_to_user( rlenp, &rlen, sizeof(rlen))) + return(EFAULT); + return(0); +} + + +STATIC int +xfs_dm_punch_hole( + vnode_t *vp, + dm_right_t right, + dm_off_t off, + dm_size_t len) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_trans_t *tp2; + xfs_mount_t *mp; + int error; + uint lock_flags; + uint commit_flags; + xfs_fsize_t realsize; + u_int bsize; + bhv_desc_t *xbdp; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if (vp->v_type != VREG) + return(EINVAL); + if (len != 0) /* Only support punches to EOF for now */ + return(EAGAIN); + if (VN_MAPPED(vp)) + return(EBUSY); + + XFS_BHV_LOOKUP(vp, xbdp); + + ip = XFS_BHVTOI(xbdp); + mp = ip->i_mount; + bsize = mp->m_sb.sb_blocksize; + + if (off & (bsize-1)) + return(EAGAIN); + + lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; + xfs_ilock(ip, lock_flags); + + realsize = ip->i_d.di_size; /* saved size to restore to */ + if (off >= realsize) { /* also check block boundary */ + xfs_iunlock(ip, lock_flags); + return(EINVAL); + } + + /* + * Before we join the inode to the transaction, take care of + * the part of the truncation that must be done without the + * inode lock. This needs to be done before joining the inode + * to the transaction, because the inode cannot be unlocked + * once it is a part of the transaction. + */ + xfs_iunlock(ip, XFS_ILOCK_EXCL); + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); + if ((error = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return(error); + } + tp2 = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); + if ((error = xfs_trans_reserve(tp2, 0, + XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_trans_cancel(tp2, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return(error); + } + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + /* --- start of truncate --- */ + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t) off); + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, lock_flags); + xfs_trans_ihold(tp, ip); + xfs_itruncate_finish(&tp, ip, (xfs_fsize_t) off, XFS_DATA_FORK, 0); + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + xfs_trans_commit(tp, commit_flags, NULL); + /* --- end of truncate --- */ + + /* --- start of grow --- */ + /* ip left locked after previous commit */ + xfs_igrow_start(ip, realsize, NULL); + xfs_trans_ijoin(tp2, ip, lock_flags); + xfs_igrow_finish(tp2, ip, realsize, 0); + + /* Let threads in send_data_event know we punched the file. */ + ip->i_iocore.io_dmstate++; + + VN_HOLD(vp); + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp2); + } + xfs_trans_commit(tp2, commit_flags, NULL); + /* --- end of grow --- */ + + /* ip unlocked during the commit */ + return(0); +} + + +STATIC int +xfs_dm_read_invis_rvp( + vnode_t *vp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + if (right < DM_RIGHT_SHARED) + return(EACCES); + + return(xfs_dm_rdwr(vp, 0, FMODE_READ, off, len, bufp, rvp)); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_release_right( + vnode_t *vp, + dm_right_t right, + u_int type) /* DM_FSYS_OBJ or zero */ +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + bhv_desc_t *bdp; + + XFS_BHV_LOOKUP(vp, bdp); + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_release_right: old %d type %d handle %s\n", + right, type, buffer); + } else { + printf("dm_release_right: old %d type %d handle " + " \n", right, type); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +STATIC int +xfs_dm_remove_dmattr( + vnode_t *vp, + dm_right_t right, + int setdtime, + dm_attrname_t *attrnamep) +{ + dm_dkattrname_t name; + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) + return(error); + + /* Remove the attribute from the object. */ + + VOP_ATTR_REMOVE(vp, name.dan_chars, + (setdtime ? ATTR_ROOT : ATTR_ROOT|ATTR_KERNOTIME), + NULL, error); + DM_EA_XLATE_ERR(error); + + if (error == ENOATTR) + error = ENOENT; + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_request_right( + vnode_t *vp, + dm_right_t right, + u_int type, /* DM_FSYS_OBJ or zero */ + u_int flags, + dm_right_t newright) +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + bhv_desc_t *bdp; + + XFS_BHV_LOOKUP(vp, bdp); + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_request_right: old %d new %d type %d flags 0x%x " + "handle %s\n", right, newright, type, flags, buffer); + } else { + printf("dm_request_right: old %d new %d type %d flags 0x%x " + "handle \n", right, newright, type, flags); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +STATIC int +xfs_dm_set_dmattr( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp) +{ + dm_dkattrname_t name; + char *value; + int alloc_size; + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) + return(error); + if (buflen > ATTR_MAX_VALUELEN) + return(E2BIG); + + /* Copy in the attribute's value and store the pair in + the object. We allocate a buffer of at least one byte even if the + caller specified a buflen of zero. (A buflen of zero is considered + valid.) + */ + + alloc_size = (buflen == 0) ? 1 : buflen; + value = kmem_alloc(alloc_size, KM_SLEEP); + if (copy_from_user( value, bufp, buflen)) { + error = EFAULT; + } else { + VOP_ATTR_SET(vp, name.dan_chars, value, buflen, + (setdtime ? ATTR_ROOT : ATTR_ROOT|ATTR_KERNOTIME), + NULL, error); + DM_EA_XLATE_ERR(error); + } + kmem_free(value, alloc_size); + return(error); +} + +STATIC int +xfs_dm_set_eventlist( + vnode_t *vp, + dm_right_t right, + u_int type, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent) +{ + int error; + bhv_desc_t *xbdp; + + XFS_BHV_LOOKUP(vp, xbdp); + + if (type == DM_FSYS_OBJ) { + error = xfs_dm_fs_set_eventlist(xbdp, right, eventsetp, maxevent); + } else { + error = xfs_dm_f_set_eventlist(xbdp, right, eventsetp, maxevent); + } + return(error); +} + + +/* + * This turned out not XFS-specific, but leave it here with get_fileattr. + */ + +STATIC int +xfs_dm_set_fileattr( + vnode_t *vp, + dm_right_t right, + u_int mask, + dm_fileattr_t *statp) +{ + dm_fileattr_t stat; + vattr_t vat; + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if (copy_from_user( &stat, statp, sizeof(stat))) + return(EFAULT); + + vat.va_mask = 0; + + if (mask & DM_AT_MODE) { + vat.va_mask |= AT_MODE; + vat.va_mode = stat.fa_mode; + } + if (mask & DM_AT_UID) { + vat.va_mask |= AT_UID; + vat.va_uid = stat.fa_uid; + } + if (mask & DM_AT_GID) { + vat.va_mask |= AT_GID; + vat.va_gid = stat.fa_gid; + } + if (mask & DM_AT_ATIME) { + vat.va_mask |= AT_ATIME; + vat.va_atime.tv_sec = stat.fa_atime; + vat.va_atime.tv_nsec = 0; + } + if (mask & DM_AT_MTIME) { + vat.va_mask |= AT_MTIME; + vat.va_mtime.tv_sec = stat.fa_mtime; + vat.va_mtime.tv_nsec = 0; + } + if (mask & DM_AT_CTIME) { + vat.va_mask |= AT_CTIME; + vat.va_ctime.tv_sec = stat.fa_ctime; + vat.va_ctime.tv_nsec = 0; + } + + /* DM_AT_DTIME only takes effect if DM_AT_CTIME is not specified. We + overload ctime to also act as dtime, i.e. DM_CONFIG_DTIME_OVERLOAD. + */ + + if ((mask & DM_AT_DTIME) && !(mask & DM_AT_CTIME)) { + vat.va_mask |= AT_CTIME; + vat.va_ctime.tv_sec = stat.fa_dtime; + vat.va_ctime.tv_nsec = 0; + } + if (mask & DM_AT_SIZE) { + vat.va_mask |= AT_SIZE; + vat.va_size = stat.fa_size; + } + + VOP_SETATTR(vp, &vat, ATTR_DMI, NULL, error); + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_set_inherit( + vnode_t *vp, + dm_right_t right, + dm_attrname_t *attrnamep, + mode_t mode) +{ + return(ENOSYS); +} + + +STATIC int +xfs_dm_set_region( + vnode_t *vp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + dm_region_t region; + dm_eventset_t new_mask; + dm_eventset_t mr_mask; + int error; + u_int exactflag; + bhv_desc_t *xbdp; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + /* If the caller gave us more than one dm_region_t structure, complain. + (He has to call dm_get_config() to find out what our limit is.) + */ + + if (nelem > 1) + return(E2BIG); + + /* If the user provided a dm_region_t structure, then copy it in, + validate it, and convert its flags to the corresponding bits in a + dm_set_eventlist() event mask. A call with zero regions is + equivalent to clearing all region flags. + */ + + new_mask = 0; + if (nelem == 1) { + if (copy_from_user( ®ion, regbufp, sizeof(region))) + return(EFAULT); + + if (region.rg_flags & ~(DM_REGION_READ|DM_REGION_WRITE|DM_REGION_TRUNCATE)) + return(EINVAL); + if (region.rg_flags & DM_REGION_READ) + new_mask |= 1 << DM_EVENT_READ; + if (region.rg_flags & DM_REGION_WRITE) + new_mask |= 1 << DM_EVENT_WRITE; + if (region.rg_flags & DM_REGION_TRUNCATE) + new_mask |= 1 << DM_EVENT_TRUNCATE; + } + if ((new_mask & prohibited_mr_events(vp)) != 0) + return(EBUSY); + mr_mask = (1 << DM_EVENT_READ) | (1 << DM_EVENT_WRITE) | (1 << DM_EVENT_TRUNCATE); + + /* Get the file's existing event mask, clear the old managed region + bits, add in the new ones, and update the file's mask. + */ + + XFS_BHV_LOOKUP(vp, xbdp); + + ip = XFS_BHVTOI(xbdp); + mp = ip->i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return(error); + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + + ip->i_d.di_dmevmask = (ip->i_d.di_dmevmask & ~mr_mask) | new_mask; + ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + VN_HOLD(vp); + xfs_trans_commit(tp, 0, NULL); + + /* Return the proper value for *exactflagp depending upon whether or not + we "changed" the user's managed region. In other words, if the user + specified a non-zero value for either rg_offset or rg_size, we + round each of those values back to zero. + */ + + if (nelem && (region.rg_offset || region.rg_size)) { + exactflag = DM_FALSE; /* user region was changed */ + } else { + exactflag = DM_TRUE; /* user region was unchanged */ + } + if (copy_to_user( exactflagp, &exactflag, sizeof(exactflag))) + return(EFAULT); + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_symlink_by_handle( + vnode_t *vp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname, + char *path) +{ + return(ENOSYS); +} + + +STATIC int +xfs_dm_sync_by_handle ( + vnode_t *vp, + dm_right_t right) +{ + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + VOP_FSYNC(vp, FSYNC_WAIT, NULL, (off_t)0, (off_t)-1, error); + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_upgrade_right( + vnode_t *vp, + dm_right_t right, + u_int type) /* DM_FSYS_OBJ or zero */ +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + bhv_desc_t *bdp; + + XFS_BHV_LOOKUP(vp, bdp); + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_upgrade_right: old %d new %d type %d handle %s\n", + right, DM_RIGHT_EXCL, type, buffer); + } else { + printf("dm_upgrade_right: old %d new %d type %d handle " + "\n", right, DM_RIGHT_EXCL, type); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +STATIC int +xfs_dm_write_invis_rvp( + vnode_t *vp, + dm_right_t right, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + int fflag = 0; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if (flags & DM_WRITE_SYNC) + fflag |= O_SYNC; + return(xfs_dm_rdwr(vp, fflag, FMODE_WRITE, off, len, bufp, rvp)); +} + + +STATIC void +xfs_dm_obj_ref_hold( + vnode_t *vp) +{ + VN_HOLD(vp); +} + + +STATIC fsys_function_vector_t xfs_fsys_vector[DM_FSYS_MAX]; + + +int +xfs_dm_get_fsys_vector( + bhv_desc_t *bdp, + dm_fcntl_vector_t *vecrq) +{ + static int initialized = 0; + fsys_function_vector_t *vecp; + int i = 0; + + vecrq->count = + sizeof(xfs_fsys_vector) / sizeof(xfs_fsys_vector[0]); + vecrq->vecp = xfs_fsys_vector; + if (initialized) + return(0); + vecrq->code_level = DM_CLVL_XOPEN; + vecp = xfs_fsys_vector; + + vecp[i].func_no = DM_FSYS_CLEAR_INHERIT; + vecp[i++].u_fc.clear_inherit = xfs_dm_clear_inherit; + vecp[i].func_no = DM_FSYS_CREATE_BY_HANDLE; + vecp[i++].u_fc.create_by_handle = xfs_dm_create_by_handle; + vecp[i].func_no = DM_FSYS_DOWNGRADE_RIGHT; + vecp[i++].u_fc.downgrade_right = xfs_dm_downgrade_right; + vecp[i].func_no = DM_FSYS_GET_ALLOCINFO_RVP; + vecp[i++].u_fc.get_allocinfo_rvp = xfs_dm_get_allocinfo_rvp; + vecp[i].func_no = DM_FSYS_GET_BULKALL_RVP; + vecp[i++].u_fc.get_bulkall_rvp = xfs_dm_get_bulkall_rvp; + vecp[i].func_no = DM_FSYS_GET_BULKATTR_RVP; + vecp[i++].u_fc.get_bulkattr_rvp = xfs_dm_get_bulkattr_rvp; + vecp[i].func_no = DM_FSYS_GET_CONFIG; + vecp[i++].u_fc.get_config = xfs_dm_get_config; + vecp[i].func_no = DM_FSYS_GET_CONFIG_EVENTS; + vecp[i++].u_fc.get_config_events = xfs_dm_get_config_events; + vecp[i].func_no = DM_FSYS_GET_DESTROY_DMATTR; + vecp[i++].u_fc.get_destroy_dmattr = xfs_dm_get_destroy_dmattr; + vecp[i].func_no = DM_FSYS_GET_DIOINFO; + vecp[i++].u_fc.get_dioinfo = xfs_dm_get_dioinfo; + vecp[i].func_no = DM_FSYS_GET_DIRATTRS_RVP; + vecp[i++].u_fc.get_dirattrs_rvp = xfs_dm_get_dirattrs_rvp; + vecp[i].func_no = DM_FSYS_GET_DMATTR; + vecp[i++].u_fc.get_dmattr = xfs_dm_get_dmattr; + vecp[i].func_no = DM_FSYS_GET_EVENTLIST; + vecp[i++].u_fc.get_eventlist = xfs_dm_get_eventlist; + vecp[i].func_no = DM_FSYS_GET_FILEATTR; + vecp[i++].u_fc.get_fileattr = xfs_dm_get_fileattr; + vecp[i].func_no = DM_FSYS_GET_REGION; + vecp[i++].u_fc.get_region = xfs_dm_get_region; + vecp[i].func_no = DM_FSYS_GETALL_DMATTR; + vecp[i++].u_fc.getall_dmattr = xfs_dm_getall_dmattr; + vecp[i].func_no = DM_FSYS_GETALL_INHERIT; + vecp[i++].u_fc.getall_inherit = xfs_dm_getall_inherit; + vecp[i].func_no = DM_FSYS_INIT_ATTRLOC; + vecp[i++].u_fc.init_attrloc = xfs_dm_init_attrloc; + vecp[i].func_no = DM_FSYS_MKDIR_BY_HANDLE; + vecp[i++].u_fc.mkdir_by_handle = xfs_dm_mkdir_by_handle; + vecp[i].func_no = DM_FSYS_PROBE_HOLE; + vecp[i++].u_fc.probe_hole = xfs_dm_probe_hole; + vecp[i].func_no = DM_FSYS_PUNCH_HOLE; + vecp[i++].u_fc.punch_hole = xfs_dm_punch_hole; + vecp[i].func_no = DM_FSYS_READ_INVIS_RVP; + vecp[i++].u_fc.read_invis_rvp = xfs_dm_read_invis_rvp; + vecp[i].func_no = DM_FSYS_RELEASE_RIGHT; + vecp[i++].u_fc.release_right = xfs_dm_release_right; + vecp[i].func_no = DM_FSYS_REMOVE_DMATTR; + vecp[i++].u_fc.remove_dmattr = xfs_dm_remove_dmattr; + vecp[i].func_no = DM_FSYS_REQUEST_RIGHT; + vecp[i++].u_fc.request_right = xfs_dm_request_right; + vecp[i].func_no = DM_FSYS_SET_DMATTR; + vecp[i++].u_fc.set_dmattr = xfs_dm_set_dmattr; + vecp[i].func_no = DM_FSYS_SET_EVENTLIST; + vecp[i++].u_fc.set_eventlist = xfs_dm_set_eventlist; + vecp[i].func_no = DM_FSYS_SET_FILEATTR; + vecp[i++].u_fc.set_fileattr = xfs_dm_set_fileattr; + vecp[i].func_no = DM_FSYS_SET_INHERIT; + vecp[i++].u_fc.set_inherit = xfs_dm_set_inherit; + vecp[i].func_no = DM_FSYS_SET_REGION; + vecp[i++].u_fc.set_region = xfs_dm_set_region; + vecp[i].func_no = DM_FSYS_SYMLINK_BY_HANDLE; + vecp[i++].u_fc.symlink_by_handle = xfs_dm_symlink_by_handle; + vecp[i].func_no = DM_FSYS_SYNC_BY_HANDLE; + vecp[i++].u_fc.sync_by_handle = xfs_dm_sync_by_handle; + vecp[i].func_no = DM_FSYS_UPGRADE_RIGHT; + vecp[i++].u_fc.upgrade_right = xfs_dm_upgrade_right; + vecp[i].func_no = DM_FSYS_WRITE_INVIS_RVP; + vecp[i++].u_fc.write_invis_rvp = xfs_dm_write_invis_rvp; + vecp[i].func_no = DM_FSYS_OBJ_REF_HOLD; + vecp[i++].u_fc.obj_ref_hold = xfs_dm_obj_ref_hold; + + return(0); +} + + +/* xfs_dm_mapevent - send events needed for memory mapping a file. + * + * xfs_dm_map is a workaround called for files that are about to be + * mapped. DMAPI events are not being generated at a low enough level + * in the kernel for page reads/writes to generate the correct events. + * So for memory-mapped files we generate read or write events for the + * whole byte range being mapped. If the mmap call can never cause a + * write to the file, then only a read event is sent. + * + * Code elsewhere prevents adding managed regions to a file while it + * is still mapped. + */ + +/* ARGSUSED */ +static int +xfs_dm_mapevent( + bhv_desc_t *bdp, + int flags, + xfs_off_t offset, + dm_fcntl_mapevent_t *mapevp) +{ + xfs_fsize_t filesize; /* event read/write "size" */ + xfs_inode_t *ip; + off_t end_of_area, evsize; + vnode_t *vp = BHV_TO_VNODE(bdp); + struct vfs *vfsp = vp->v_vfsp; + + /* exit immediately if not regular file in a DMAPI file system */ + + mapevp->error = 0; /* assume success */ + + if ((vp->v_type != VREG) || !(vfsp->vfs_flag & VFS_DMI)) + return 0; + + if (mapevp->max_event != DM_EVENT_WRITE && + mapevp->max_event != DM_EVENT_READ) + return 0; + + /* Set file size to work with. */ + + ip = XFS_BHVTOI(bdp); + filesize = ip->i_iocore.io_new_size; + if (filesize < ip->i_d.di_size) { + filesize = ip->i_d.di_size; + } + + /* Set first byte number beyond the map area. */ + + if (mapevp->length) { + end_of_area = offset + mapevp->length; + if (end_of_area > filesize) + end_of_area = filesize; + } else { + end_of_area = filesize; + } + + /* Set the real amount being mapped. */ + evsize = end_of_area - offset; + if (evsize < 0) + evsize = 0; + + /* If write possible, try a DMAPI write event */ + if (mapevp->max_event == DM_EVENT_WRITE && + DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_WRITE)) { + mapevp->error = xfs_dm_send_data_event(DM_EVENT_WRITE, bdp, + offset, evsize, 0, NULL); + return(0); + } + + /* Try a read event if max_event was != DM_EVENT_WRITE or if it + * was DM_EVENT_WRITE but the WRITE event was not enabled. + */ + if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_READ)) { + mapevp->error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, + offset, evsize, 0, NULL); + } + + return 0; +} + + +int +xfs_dm_send_mmap_event( + struct vm_area_struct *vma, + unsigned int wantflag) +{ + vnode_t *vp; + xfs_inode_t *ip; + bhv_desc_t *bdp; + int ret = 0; + dm_fcntl_mapevent_t maprq; + dm_eventtype_t max_event = DM_EVENT_READ; + + if (!vma->vm_file) + return 0; + + vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode); + ASSERT(vp); + + if ((vp->v_type != VREG) || !(vp->v_vfsp->vfs_flag & VFS_DMI)) + return 0; + + /* If they specifically asked for 'read', then give it to them. + * Otherwise, see if it's possible to give them 'write'. + */ + if( wantflag & VM_READ ){ + max_event = DM_EVENT_READ; + } + else if( ! (vma->vm_flags & VM_DENYWRITE) ) { + if((wantflag & VM_WRITE) || (vma->vm_flags & VM_WRITE)) + max_event = DM_EVENT_WRITE; + } + + if( (wantflag & VM_WRITE) && (max_event != DM_EVENT_WRITE) ){ + return -EACCES; + } + + maprq.max_event = max_event; + + /* Figure out how much of the file is being requested by the user. */ + maprq.length = 0; /* whole file, for now */ + + VN_BHV_READ_LOCK(VN_BHV_HEAD(vp)); + XFS_BHV_LOOKUP(vp, bdp); + ip = XFS_BHVTOI(bdp); + + if(DM_EVENT_ENABLED(vp->v_vfsp, ip, max_event)){ + xfs_dm_mapevent(bdp, 0, 0, &maprq); + ret = maprq.error; + } + VN_BHV_READ_UNLOCK(VN_BHV_HEAD(vp)); + + return -ret; +} + + +int +xfs_dm_mount( + vfs_t *vfsp, + char *dir_name, + char *fsname) +{ + vnode_t *rootvp; + bhv_desc_t *rootbdp; + int error; + + if (*dir_name == '\0') + return EINVAL; + VFS_ROOT(vfsp, &rootvp, error); + if (error) + return error; + + rootbdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(rootvp), &xfs_vnodeops); + VN_RELE(rootvp); + error = dm_send_mount_event(vfsp, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, + rootbdp, DM_RIGHT_NULL, dir_name, + fsname); + + return error; +} diff -Nur linux-2.4.19/fs/xfs/xfs_dmapi.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dmapi.h --- linux-2.4.19/fs/xfs/xfs_dmapi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dmapi.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DMAPI_H__ +#define __XFS_DMAPI_H__ + +#ifdef CONFIG_XFS_DMAPI + +#include +#include + +/* Values used to define the on-disk version of dm_attrname_t. All + * on-disk attribute names start with the 8-byte string "SGI_DMI_". + * + * In the on-disk inode, DMAPI attribute names consist of the user-provided + * name with the DMATTR_PREFIXSTRING pre-pended. This string must NEVER be + * changed. + */ + +#define DMATTR_PREFIXLEN 8 +#define DMATTR_PREFIXSTRING "SGI_DMI_" + +/* Defines for determining if an event message should be sent. */ +#define DM_EVENT_ENABLED(vfsp, ip, event) ( \ + unlikely ((vfsp)->vfs_flag & VFS_DMI) && \ + ( ((ip)->i_d.di_dmevmask & (1 << event)) || \ + ((ip)->i_mount->m_dmevmask & (1 << event)) ) \ + ) + +#define DM_EVENT_ENABLED_IO(vfsp, io, event) ( \ + unlikely ((vfsp)->vfs_flag & VFS_DMI) && \ + ( ((io)->io_dmevmask & (1 << event)) || \ + ((io)->io_mount->m_dmevmask & (1 << event)) ) \ + ) + +/* + * Macros to turn caller specified delay/block flags into + * dm_send_xxxx_event flag DM_FLAGS_NDELAY. + */ + +#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \ + DM_FLAGS_NDELAY : 0) +#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) + + + +/* events valid in dm_set_eventlist() when called with a filesystem handle. + These events are not persistent. +*/ + +#define DM_XFS_VALID_FS_EVENTS ( \ + (1 << DM_EVENT_PREUNMOUNT) | \ + (1 << DM_EVENT_UNMOUNT) | \ + (1 << DM_EVENT_NOSPACE) | \ + (1 << DM_EVENT_DEBUT) | \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + +/* Events valid in dm_set_eventlist() when called with a file handle for + a regular file or a symlink. These events are persistent. +*/ + +#define DM_XFS_VALID_FILE_EVENTS ( \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + +/* Events valid in dm_set_eventlist() when called with a file handle for + a directory. These events are persistent. +*/ + +#define DM_XFS_VALID_DIRECTORY_EVENTS ( \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + + +/* Events supported by the XFS filesystem. */ +#define DM_XFS_SUPPORTED_EVENTS ( \ + (1 << DM_EVENT_MOUNT) | \ + (1 << DM_EVENT_PREUNMOUNT) | \ + (1 << DM_EVENT_UNMOUNT) | \ + (1 << DM_EVENT_NOSPACE) | \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_READ) | \ + (1 << DM_EVENT_WRITE) | \ + (1 << DM_EVENT_TRUNCATE) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + + +extern int +xfs_dm_mount( + vfs_t *vfsp, + char *dir_name, + char *fsname); + +extern int +xfs_dm_get_fsys_vector( + bhv_desc_t *bdp, + dm_fcntl_vector_t *vecrq); + +extern int +xfs_dm_send_data_event( + dm_eventtype_t event, + bhv_desc_t *bdp, + xfs_off_t offset, + size_t length, + int flags, + vrwlock_t *locktype); + +extern int +xfs_dm_send_create_event( + bhv_desc_t *dir_bdp, + char *name, + mode_t new_mode, + int *good_event_sent); + +extern int +xfs_dm_send_mmap_event( + struct vm_area_struct *vma, + unsigned int wantflag); + +#else /* CONFIG_XFS_DMAPI */ + +/* + * Flags needed to build with dmapi disabled. + */ + +typedef enum { + DM_EVENT_INVALID = -1, + DM_EVENT_CANCEL = 0, /* not supported */ + DM_EVENT_MOUNT = 1, + DM_EVENT_PREUNMOUNT = 2, + DM_EVENT_UNMOUNT = 3, + DM_EVENT_DEBUT = 4, /* not supported */ + DM_EVENT_CREATE = 5, + DM_EVENT_CLOSE = 6, /* not supported */ + DM_EVENT_POSTCREATE = 7, + DM_EVENT_REMOVE = 8, + DM_EVENT_POSTREMOVE = 9, + DM_EVENT_RENAME = 10, + DM_EVENT_POSTRENAME = 11, + DM_EVENT_LINK = 12, + DM_EVENT_POSTLINK = 13, + DM_EVENT_SYMLINK = 14, + DM_EVENT_POSTSYMLINK = 15, + DM_EVENT_READ = 16, + DM_EVENT_WRITE = 17, + DM_EVENT_TRUNCATE = 18, + DM_EVENT_ATTRIBUTE = 19, + DM_EVENT_DESTROY = 20, + DM_EVENT_NOSPACE = 21, + DM_EVENT_USER = 22, + DM_EVENT_MAX = 23 +} dm_eventtype_t; + +typedef enum { + DM_RIGHT_NULL, + DM_RIGHT_SHARED, + DM_RIGHT_EXCL +} dm_right_t; + +/* + * Defines for determining if an event message should be sent. + */ +#define DM_EVENT_ENABLED(vfsp, ip, event) 0 +#define DM_EVENT_ENABLED_IO(vfsp, io, event) 0 + +/* + * Stubbed out DMAPI delay macros. + */ + +#define FILP_DELAY_FLAG(filp) 0 +#define AT_DELAY_FLAG(f) 0 + +/* + * Events supported by the XFS filesystem. + */ + +#define DM_XFS_VALID_FS_EVENTS 0 +#define DM_XFS_VALID_FILE_EVENTS 0 +#define DM_XFS_VALID_DIRECTORY_EVENTS 0 +#define DM_XFS_SUPPORTED_EVENTS 0 + +/* + * Dummy definitions used for the flags field on dm_send_*_event(). + */ + +#define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ +#define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ + +/* + * Stubs for XFS DMAPI utility routines. + */ + +static __inline int +xfs_dm_send_create_event( + bhv_desc_t *dir_bdp, + char *name, + mode_t new_mode, + int *good_event_sent) +{ + return 0; +} + +static __inline int +xfs_dm_send_data_event( + dm_eventtype_t event, + bhv_desc_t *bdp, + xfs_off_t offset, + size_t length, + int flags, + vrwlock_t *locktype) +{ + return nopkg(); +} + +static __inline int +xfs_dm_send_mmap_event( + struct vm_area_struct *vma, + unsigned int wantflag) +{ + return 0; +} + +/* + * Stubs for routines needed for the X/Open version of DMAPI. + */ + +static __inline int +dm_send_destroy_event( + bhv_desc_t *bdp, + dm_right_t vp_right) +{ + return nopkg(); +} + +static __inline int +dm_send_namesp_event( + dm_eventtype_t event, + bhv_desc_t *bdp1, + dm_right_t vp1_right, + bhv_desc_t *bdp2, + dm_right_t vp2_right, + char *name1, + char *name2, + mode_t mode, + int retcode, + int flags) +{ + return nopkg(); +} + +static __inline void +dm_send_unmount_event( + vfs_t *vfsp, + vnode_t *vp, + dm_right_t vfsp_right, + mode_t mode, + int retcode, + int flags) +{ +} + +#endif /* CONFIG_XFS_DMAPI */ +#endif /* __XFS_DMAPI_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dqblk.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dqblk.h --- linux-2.4.19/fs/xfs/xfs_dqblk.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dqblk.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQBLK_H__ +#define __XFS_DQBLK_H__ + +/* + * The ondisk form of a dquot structure. + */ +#define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */ +#define XFS_DQUOT_VERSION (u_int8_t)0x01 /* latest version number */ + +/* + * This is the main portion of the on-disk representation of quota + * information for a user. This is the q_core of the xfs_dquot_t that + * is kept in kernel memory. We pad this with some more expansion room + * to construct the on disk structure. + */ +typedef struct xfs_disk_dquot { +/*16*/ u_int16_t d_magic; /* dquot magic = XFS_DQUOT_MAGIC */ +/*8 */ u_int8_t d_version; /* dquot version */ +/*8 */ u_int8_t d_flags; /* XFS_DQ_USER/PROJ/GROUP */ +/*32*/ xfs_dqid_t d_id; /* user,project,group id */ +/*64*/ xfs_qcnt_t d_blk_hardlimit;/* absolute limit on disk blks */ +/*64*/ xfs_qcnt_t d_blk_softlimit;/* preferred limit on disk blks */ +/*64*/ xfs_qcnt_t d_ino_hardlimit;/* maximum # allocated inodes */ +/*64*/ xfs_qcnt_t d_ino_softlimit;/* preferred inode limit */ +/*64*/ xfs_qcnt_t d_bcount; /* disk blocks owned by the user */ +/*64*/ xfs_qcnt_t d_icount; /* inodes owned by the user */ +/*32*/ __int32_t d_itimer; /* zero if within inode limits if not, + this is when we refuse service */ +/*32*/ __int32_t d_btimer; /* similar to above; for disk blocks */ +/*16*/ xfs_qwarncnt_t d_iwarns; /* warnings issued wrt num inodes */ +/*16*/ xfs_qwarncnt_t d_bwarns; /* warnings issued wrt disk blocks */ +/*32*/ __int32_t d_pad0; /* 64 bit align */ +/*64*/ xfs_qcnt_t d_rtb_hardlimit;/* absolute limit on realtime blks */ +/*64*/ xfs_qcnt_t d_rtb_softlimit;/* preferred limit on RT disk blks */ +/*64*/ xfs_qcnt_t d_rtbcount; /* realtime blocks owned */ +/*32*/ __int32_t d_rtbtimer; /* similar to above; for RT disk blocks */ +/*16*/ xfs_qwarncnt_t d_rtbwarns; /* warnings issued wrt RT disk blocks */ +/*16*/ __uint16_t d_pad; +} xfs_disk_dquot_t; + +/* + * This is what goes on disk. This is separated from the xfs_disk_dquot because + * carrying the unnecessary padding would be a waste of memory. + */ +typedef struct xfs_dqblk { + xfs_disk_dquot_t dd_diskdq; /* portion that lives incore as well */ + char dd_fill[32]; /* filling for posterity */ +} xfs_dqblk_t; + +/* + * flags for q_flags field in the dquot. + */ +#define XFS_DQ_USER 0x0001 /* a user quota */ +/* #define XFS_DQ_PROJ 0x0002 -- project quota (IRIX) */ +#define XFS_DQ_GROUP 0x0004 /* a group quota */ +#define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */ +#define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */ +#define XFS_DQ_WANT 0x0020 /* for lookup/reclaim race */ +#define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */ +#define XFS_DQ_MARKER 0x0080 /* sentinel */ + +/* + * In the worst case, when both user and group quotas are on, + * we can have a max of three dquots changing in a single transaction. + */ +#define XFS_DQUOT_LOGRES(mp) (sizeof(xfs_disk_dquot_t) * 3) + +#endif /* __XFS_DQBLK_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dquot.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot.c --- linux-2.4.19/fs/xfs/xfs_dquot.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1660 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + LOCK ORDER + + inode lock (ilock) + dquot hash-chain lock (hashlock) + xqm dquot freelist lock (freelistlock + mount's dquot list lock (mplistlock) + user dquot lock - lock ordering among dquots is based on the uid or gid + group dquot lock - similar to udquots. Between the two dquots, the udquot + has to be locked first. + pin lock - the dquot lock must be held to take this lock. + flush lock - ditto. +*/ + +STATIC void xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *); + +#ifdef DEBUG +dev_t xfs_dqerror_dev = 0; +int xfs_do_dqerror = 0; +int xfs_dqreq_num = 0; +int xfs_dqerror_mod = 33; +#endif + +/* + * Allocate and initialize a dquot. We don't always allocate fresh memory; + * we try to reclaim a free dquot if the number of incore dquots are above + * a threshold. + * The only field inside the core that gets initialized at this point + * is the d_id field. The idea is to fill in the entire q_core + * when we read in the on disk dquot. + */ +xfs_dquot_t * +xfs_qm_dqinit( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type) +{ + xfs_dquot_t *dqp; + boolean_t brandnewdquot; + + brandnewdquot = xfs_qm_dqalloc_incore(&dqp); + dqp->dq_flags = type; + INT_SET(dqp->q_core.d_id, ARCH_CONVERT, id); + dqp->q_mount = mp; + + /* + * No need to re-initialize these if this is a reclaimed dquot. + */ + if (brandnewdquot) { + dqp->dq_flnext = dqp->dq_flprev = dqp; + mutex_init(&dqp->q_qlock, MUTEX_DEFAULT, "xdq"); + initnsema(&dqp->q_flock, 1, "fdq"); + sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq"); + +#ifdef DQUOT_TRACING + dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP); + xfs_dqtrace_entry(dqp, "DQINIT"); +#endif + } else { + /* + * Only the q_core portion was bzeroed in dqreclaim_one(). + * So, we need to reset others. + */ + dqp->q_nrefs = 0; + dqp->q_blkno = 0; + dqp->MPL_NEXT = dqp->HL_NEXT = NULL; + dqp->HL_PREVP = dqp->MPL_PREVP = NULL; + dqp->q_bufoffset = 0; + dqp->q_fileoffset = 0; + dqp->q_transp = NULL; + dqp->q_gdquot = NULL; + dqp->q_res_bcount = 0; + dqp->q_res_icount = 0; + dqp->q_res_rtbcount = 0; + dqp->q_pincount = 0; + dqp->q_hash = 0; + ASSERT(dqp->dq_flnext == dqp->dq_flprev); + +#ifdef DQUOT_TRACING + ASSERT(dqp->q_trace); + xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT"); +#endif + } + + /* + * log item gets initialized later + */ + return (dqp); +} + +/* + * This is called to free all the memory associated with a dquot + */ +void +xfs_qm_dqdestroy( + xfs_dquot_t *dqp) +{ + ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp)); + + mutex_destroy(&dqp->q_qlock); + freesema(&dqp->q_flock); + sv_destroy(&dqp->q_pinwait); + +#ifdef DQUOT_TRACING + if (dqp->q_trace) + ktrace_free(dqp->q_trace); + dqp->q_trace = NULL; +#endif + kmem_zone_free(xfs_Gqm->qm_dqzone, dqp); + atomic_dec(&xfs_Gqm->qm_totaldquots); +} + +/* + * This is what a 'fresh' dquot inside a dquot chunk looks like on disk. + */ +STATIC void +xfs_qm_dqinit_core( + xfs_dqid_t id, + uint type, + xfs_dqblk_t *d) +{ + /* + * Caller has bzero'd the entire dquot 'chunk' already. + */ + INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC); + INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION); + INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id); + INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type); +} + + +#ifdef DQUOT_TRACING +/* + * Dquot tracing for debugging. + */ +/* ARGSUSED */ +void +xfs_dqtrace_entry__( + xfs_dquot_t *dqp, + char *func, + void *retaddr, + xfs_inode_t *ip) +{ + xfs_dquot_t *udqp = NULL; + int ino; + + ASSERT(dqp->q_trace); + if (ip) { + ino = ip->i_ino; + udqp = ip->i_udquot; + } + ktrace_enter(dqp->q_trace, + (void *)(__psint_t)DQUOT_KTRACE_ENTRY, + (void *)func, + (void *)(__psint_t)dqp->q_nrefs, + (void *)(__psint_t)dqp->dq_flags, + (void *)(__psint_t)dqp->q_res_bcount, + (void *)(__psint_t)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_id, ARCH_CONVERT), /* 11 */ + (void *)(__psint_t)current_pid(), + (void *)(__psint_t)ino, + (void *)(__psint_t)retaddr, + (void *)(__psint_t)udqp); + return; +} +#endif + + +/* + * Check the limits and timers of a dquot and start or reset timers + * if necessary. + * This gets called even when quota enforcement is OFF, which makes our + * life a little less complicated. (We just don't reject any quota + * reservations in that case, when enforcement is off). + * We also return 0 as the values of the timers in Q_GETQUOTA calls, when + * enforcement's off. + * In contrast, warnings are a little different in that they don't + * 'automatically' get started when limits get exceeded. + */ +void +xfs_qm_adjust_dqtimers( + xfs_mount_t *mp, + xfs_disk_dquot_t *d) +{ + /* + * The dquot had better be locked. We are modifying it here. + */ + + /* + * root's limits are not real limits. + */ + if (INT_ISZERO(d->d_id, ARCH_CONVERT)) + return; + +#ifdef QUOTADEBUG + if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)) + ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)); + if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)) + ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)); +#endif + if (INT_ISZERO(d->d_btimer, ARCH_CONVERT)) { + if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && + (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) || + (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) && + (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { + INT_SET(d->d_btimer, ARCH_CONVERT, CURRENT_TIME + XFS_QI_BTIMELIMIT(mp)); + } + } else { + if ((INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) || + (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) && + (INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT) || + (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { + INT_ZERO(d->d_btimer, ARCH_CONVERT); + } + } + + if (INT_ISZERO(d->d_itimer, ARCH_CONVERT)) { + if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) && + (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) || + (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) && + (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { + INT_SET(d->d_itimer, ARCH_CONVERT, CURRENT_TIME + XFS_QI_ITIMELIMIT(mp)); + } + } else { + if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT) || + (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) && + (INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT) || + (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { + INT_ZERO(d->d_itimer, ARCH_CONVERT); + } + } +} + +/* + * Increment or reset warnings of a given dquot. + */ +int +xfs_qm_dqwarn( + xfs_disk_dquot_t *d, + uint flags) +{ + int warned; + + /* + * root's limits are not real limits. + */ + if (INT_ISZERO(d->d_id, ARCH_CONVERT)) + return (0); + + warned = 0; + if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && + (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { + if (flags & XFS_QMOPT_DOWARN) { + INT_MOD(d->d_bwarns, ARCH_CONVERT, +1); + warned++; + } + } else { + if (INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) || + (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { + INT_ZERO(d->d_bwarns, ARCH_CONVERT); + } + } + + if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 && + (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { + if (flags & XFS_QMOPT_DOWARN) { + INT_MOD(d->d_iwarns, ARCH_CONVERT, +1); + warned++; + } + } else { + if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT)) || + (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { + INT_ZERO(d->d_iwarns, ARCH_CONVERT); + } + } +#ifdef QUOTADEBUG + if (INT_GET(d->d_iwarns, ARCH_CONVERT)) + printk("--------@@Inode warnings running : %Lu >= %Lu\n", + INT_GET(d->d_icount, ARCH_CONVERT), INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); + if (INT_GET(d->d_bwarns, ARCH_CONVERT)) + printk("--------@@Blks warnings running : %Lu >= %Lu\n", + INT_GET(d->d_bcount, ARCH_CONVERT), INT_GET(d->d_blk_softlimit, ARCH_CONVERT)); +#endif + return (warned); +} + + +/* + * initialize a buffer full of dquots and log the whole thing + */ +STATIC void +xfs_qm_init_dquot_blk( + xfs_trans_t *tp, + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + xfs_buf_t *bp) +{ + xfs_dqblk_t *d; + int curid, i; + + ASSERT(tp); + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + + d = (xfs_dqblk_t *)XFS_BUF_PTR(bp); + + /* + * ID of the first dquot in the block - id's are zero based. + */ + curid = id - (id % XFS_QM_DQPERBLK(mp)); + ASSERT(curid >= 0); + bzero(d, BBTOB(XFS_QI_DQCHUNKLEN(mp))); + for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++) + xfs_qm_dqinit_core(curid, type, d); + xfs_trans_dquot_buf(tp, bp, + type & XFS_DQ_USER ? + XFS_BLI_UDQUOT_BUF : + XFS_BLI_GDQUOT_BUF); + xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1); +} + + + +/* + * Allocate a block and fill it with dquots. + * This is called when the bmapi finds a hole. + */ +STATIC int +xfs_qm_dqalloc( + xfs_trans_t *tp, + xfs_mount_t *mp, + xfs_dquot_t *dqp, + xfs_inode_t *quotip, + xfs_fileoff_t offset_fsb, + xfs_buf_t **O_bpp) +{ + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + xfs_bmbt_irec_t map; + int nmaps, error, committed; + xfs_buf_t *bp; + + ASSERT(tp != NULL); + xfs_dqtrace_entry(dqp, "DQALLOC"); + + /* + * Initialize the bmap freelist prior to calling bmapi code. + */ + XFS_BMAP_INIT(&flist, &firstblock); + xfs_ilock(quotip, XFS_ILOCK_EXCL); + /* + * Return if this type of quotas is turned off while we didn't + * have an inode lock + */ + if (XFS_IS_THIS_QUOTA_OFF(dqp)) { + xfs_iunlock(quotip, XFS_ILOCK_EXCL); + return (ESRCH); + } + + /* + * xfs_trans_commit normally decrements the vnode ref count + * when it unlocks the inode. Since we want to keep the quota + * inode around, we bump the vnode ref count now. + */ + VN_HOLD(XFS_ITOV(quotip)); + + xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL); + nmaps = 1; + if ((error = xfs_bmapi(tp, quotip, + offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB, + XFS_BMAPI_METADATA | XFS_BMAPI_WRITE, + &firstblock, + XFS_QM_DQALLOC_SPACE_RES(mp), + &map, &nmaps, &flist))) { + goto error0; + } + ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); + ASSERT(nmaps == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + + /* + * Keep track of the blkno to save a lookup later + */ + dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); + + /* now we can just get the buffer (there's nothing to read yet) */ + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, + dqp->q_blkno, + XFS_QI_DQCHUNKLEN(mp), + 0); + if (!bp || (error = XFS_BUF_GETERROR(bp))) + goto error1; + /* + * Make a chunk of dquots out of this buffer and log + * the entire thing. + */ + xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT), + dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), + bp); + + if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) { + goto error1; + } + + *O_bpp = bp; + return 0; + + error1: + xfs_bmap_cancel(&flist); + error0: + xfs_iunlock(quotip, XFS_ILOCK_EXCL); + + return (error); +} + +/* + * Maps a dquot to the buffer containing its on-disk version. + * This returns a ptr to the buffer containing the on-disk dquot + * in the bpp param, and a ptr to the on-disk dquot within that buffer + */ +STATIC int +xfs_qm_dqtobp( + xfs_trans_t *tp, + xfs_dquot_t *dqp, + xfs_disk_dquot_t **O_ddpp, + xfs_buf_t **O_bpp, + uint flags) +{ + xfs_bmbt_irec_t map; + int nmaps, error; + xfs_buf_t *bp; + xfs_inode_t *quotip; + xfs_mount_t *mp; + xfs_disk_dquot_t *ddq; + xfs_dqid_t id; + boolean_t newdquot; + + mp = dqp->q_mount; + id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT); + nmaps = 1; + newdquot = B_FALSE; + + /* + * If we don't know where the dquot lives, find out. + */ + if (dqp->q_blkno == (xfs_daddr_t) 0) { + /* We use the id as an index */ + dqp->q_fileoffset = (xfs_fileoff_t) ((uint)id / + XFS_QM_DQPERBLK(mp)); + nmaps = 1; + quotip = XFS_DQ_TO_QIP(dqp); + xfs_ilock(quotip, XFS_ILOCK_SHARED); + /* + * Return if this type of quotas is turned off while we didn't + * have an inode lock + */ + if (XFS_IS_THIS_QUOTA_OFF(dqp)) { + xfs_iunlock(quotip, XFS_ILOCK_SHARED); + return (ESRCH); + } + /* + * Find the block map; no allocations yet + */ + error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset, + XFS_DQUOT_CLUSTER_SIZE_FSB, + XFS_BMAPI_METADATA, + NULL, 0, &map, &nmaps, NULL); + + xfs_iunlock(quotip, XFS_ILOCK_SHARED); + if (error) + return (error); + ASSERT(nmaps == 1); + ASSERT(map.br_blockcount == 1); + + /* + * offset of dquot in the (fixed sized) dquot chunk. + */ + dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) * + sizeof(xfs_dqblk_t); + if (map.br_startblock == HOLESTARTBLOCK) { + /* + * We don't allocate unless we're asked to + */ + if (!(flags & XFS_QMOPT_DQALLOC)) + return (ENOENT); + + ASSERT(tp); + if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip, + dqp->q_fileoffset, &bp))) + return (error); + newdquot = B_TRUE; + } else { + /* + * store the blkno etc so that we don't have to do the + * mapping all the time + */ + dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); + } + } + ASSERT(dqp->q_blkno != DELAYSTARTBLOCK); + ASSERT(dqp->q_blkno != HOLESTARTBLOCK); + + /* + * Read in the buffer, unless we've just done the allocation + * (in which case we already have the buf). + */ + if (! newdquot) { + xfs_dqtrace_entry(dqp, "DQTOBP READBUF"); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, + dqp->q_blkno, + XFS_QI_DQCHUNKLEN(mp), + 0, &bp))) { + return (error); + } + if (error || !bp) + return XFS_ERROR(error); + } + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + + /* + * calculate the location of the dquot inside the buffer. + */ + ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset); + + /* + * A simple sanity check in case we got a corrupted dquot... + */ + if (xfs_qm_dqcheck(ddq, id, + dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), + flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN), + "dqtobp")) { + if (!(flags & XFS_QMOPT_DQREPAIR)) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EIO); + } + XFS_BUF_BUSY(bp); /* We dirtied this */ + } + + *O_bpp = bp; + *O_ddpp = ddq; + + return (0); +} + + +/* + * Read in the ondisk dquot using dqtobp() then copy it to an incore version, + * and release the buffer immediately. + * + */ +/* ARGSUSED */ +STATIC int +xfs_qm_dqread( + xfs_trans_t *tp, + xfs_dqid_t id, + xfs_dquot_t *dqp, /* dquot to get filled in */ + uint flags) +{ + xfs_disk_dquot_t *ddqp; + xfs_buf_t *bp; + int error; + + /* + * get a pointer to the on-disk dquot and the buffer containing it + * dqp already knows its own type (GROUP/USER). + */ + xfs_dqtrace_entry(dqp, "DQREAD"); + if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) { + return (error); + } + + /* copy everything from disk dquot to the incore dquot */ + bcopy(ddqp, &dqp->q_core, sizeof(xfs_disk_dquot_t)); + ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id); + xfs_qm_dquot_logitem_init(dqp); + + /* + * Reservation counters are defined as reservation plus current usage + * to avoid having to add everytime. + */ + dqp->q_res_bcount = INT_GET(ddqp->d_bcount, ARCH_CONVERT); + dqp->q_res_icount = INT_GET(ddqp->d_icount, ARCH_CONVERT); + dqp->q_res_rtbcount = INT_GET(ddqp->d_rtbcount, ARCH_CONVERT); + + /* Mark the buf so that this will stay incore a little longer */ + XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF); + + /* + * We got the buffer with a xfs_trans_read_buf() (in dqtobp()) + * So we need to release with xfs_trans_brelse(). + * The strategy here is identical to that of inodes; we lock + * the dquot in xfs_qm_dqget() before making it accessible to + * others. This is because dquots, like inodes, need a good level of + * concurrency, and we don't want to take locks on the entire buffers + * for dquot accesses. + * Note also that the dquot buffer may even be dirty at this point, if + * this particular dquot was repaired. We still aren't afraid to + * brelse it because we have the changes incore. + */ + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + xfs_trans_brelse(tp, bp); + + return (error); +} + + +/* + * allocate an incore dquot from the kernel heap, + * and fill its core with quota information kept on disk. + * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk + * if it wasn't already allocated. + */ +STATIC int +xfs_qm_idtodq( + xfs_mount_t *mp, + xfs_dqid_t id, /* gid or uid, depending on type */ + uint type, /* UDQUOT or GDQUOT */ + uint flags, /* DQALLOC, DQREPAIR */ + xfs_dquot_t **O_dqpp)/* OUT : incore dquot, not locked */ +{ + xfs_dquot_t *dqp; + int error; + xfs_trans_t *tp; + int cancelflags=0; + + dqp = xfs_qm_dqinit(mp, id, type); + tp = NULL; + if (flags & XFS_QMOPT_DQALLOC) { + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC); + if ((error = xfs_trans_reserve(tp, + XFS_QM_DQALLOC_SPACE_RES(mp), + XFS_WRITE_LOG_RES(mp) + + BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 + + 128, + 0, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT))) { + cancelflags = 0; + goto error0; + } + cancelflags = XFS_TRANS_RELEASE_LOG_RES; + } + + /* + * Read it from disk; xfs_dqread() takes care of + * all the necessary initialization of dquot's fields (locks, etc) + */ + if ((error = xfs_qm_dqread(tp, id, dqp, flags))) { + /* + * This can happen if quotas got turned off (ESRCH), + * or if the dquot didn't exist on disk and we ask to + * allocate (ENOENT). + */ + xfs_dqtrace_entry(dqp, "DQREAD FAIL"); + cancelflags |= XFS_TRANS_ABORT; + goto error0; + } + if (tp) { + if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, + NULL))) + goto error1; + } + + *O_dqpp = dqp; + ASSERT(! XFS_DQ_IS_LOCKED(dqp)); + return (0); + + error0: + ASSERT(error); + if (tp) + xfs_trans_cancel(tp, cancelflags); + error1: + xfs_qm_dqdestroy(dqp); + *O_dqpp = NULL; + return (error); +} + +/* + * Lookup a dquot in the incore dquot hashtable. We keep two separate + * hashtables for user and group dquots; and, these are global tables + * inside the XQM, not per-filesystem tables. + * The hash chain must be locked by caller, and it is left locked + * on return. Returning dquot is locked. + */ +STATIC int +xfs_qm_dqlookup( + xfs_mount_t *mp, + xfs_dqid_t id, + xfs_dqhash_t *qh, + xfs_dquot_t **O_dqpp) +{ + xfs_dquot_t *dqp; + uint flist_locked; + xfs_dquot_t *d; + + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + + flist_locked = B_FALSE; + + /* + * Traverse the hashchain looking for a match + */ + for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) { + /* + * We already have the hashlock. We don't need the + * dqlock to look at the id field of the dquot, since the + * id can't be modified without the hashlock anyway. + */ + if (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id && dqp->q_mount == mp) { + xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP"); + /* + * All in core dquots must be on the dqlist of mp + */ + ASSERT(dqp->MPL_PREVP != NULL); + + xfs_dqlock(dqp); + if (dqp->q_nrefs == 0) { + ASSERT (XFS_DQ_IS_ON_FREELIST(dqp)); + if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) { + xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT"); + + /* + * We may have raced with dqreclaim_one() + * (and lost). So, flag that we don't + * want the dquot to be reclaimed. + */ + dqp->dq_flags |= XFS_DQ_WANT; + xfs_dqunlock(dqp); + xfs_qm_freelist_lock(xfs_Gqm); + xfs_dqlock(dqp); + dqp->dq_flags &= ~(XFS_DQ_WANT); + } + flist_locked = B_TRUE; + } + + /* + * id couldn't have changed; we had the hashlock all + * along + */ + ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id); + + if (flist_locked) { + if (dqp->q_nrefs != 0) { + xfs_qm_freelist_unlock(xfs_Gqm); + flist_locked = B_FALSE; + } else { + /* + * take it off the freelist + */ + xfs_dqtrace_entry(dqp, + "DQLOOKUP: TAKEOFF FL"); + XQM_FREELIST_REMOVE(dqp); + /* xfs_qm_freelist_print(&(xfs_Gqm-> + qm_dqfreelist), + "after removal"); */ + } + } + + /* + * grab a reference + */ + XFS_DQHOLD(dqp); + + if (flist_locked) + xfs_qm_freelist_unlock(xfs_Gqm); + /* + * move the dquot to the front of the hashchain + */ + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + if (dqp->HL_PREVP != &qh->qh_next) { + xfs_dqtrace_entry(dqp, + "DQLOOKUP: HASH MOVETOFRONT"); + if ((d = dqp->HL_NEXT)) + d->HL_PREVP = dqp->HL_PREVP; + *(dqp->HL_PREVP) = d; + d = qh->qh_next; + d->HL_PREVP = &dqp->HL_NEXT; + dqp->HL_NEXT = d; + dqp->HL_PREVP = &qh->qh_next; + qh->qh_next = dqp; + } + xfs_dqtrace_entry(dqp, "LOOKUP END"); + *O_dqpp = dqp; + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + return (0); + } + } + + *O_dqpp = NULL; + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + return (1); +} + +/* + * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a + * a locked dquot, doing an allocation (if requested) as needed. + * When both an inode and an id are given, the inode's id takes precedence. + * That is, if the id changes while we dont hold the ilock inside this + * function, the new dquot is returned, not necessarily the one requested + * in the id argument. + */ +int +xfs_qm_dqget( + xfs_mount_t *mp, + xfs_inode_t *ip, /* locked inode (optional) */ + xfs_dqid_t id, /* gid or uid, depending on type */ + uint type, /* UDQUOT or GDQUOT */ + uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */ + xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */ +{ + xfs_dquot_t *dqp; + xfs_dqhash_t *h; + uint version; + int error; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || + (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { + return (ESRCH); + } + h = XFS_DQ_HASH(mp, id, type); + +#ifdef DEBUG + if (xfs_do_dqerror) { + if ((xfs_dqerror_dev == mp->m_dev) && + (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) { + printk("Returning error in dqget\n"); + return (EIO); + } + } +#endif + + again: + +#ifdef DEBUG + ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP); + if (ip) { + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + if (type == XFS_DQ_USER) + ASSERT(ip->i_udquot == NULL); + else + ASSERT(ip->i_gdquot == NULL); + } +#endif + XFS_DQ_HASH_LOCK(h); + + /* + * Look in the cache (hashtable). + * The chain is kept locked during lookup. + */ + if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) { + XFS_STATS_INC(xfsstats.xs_qm_dqcachehits); + /* + * The dquot was found, moved to the front of the chain, + * taken off the freelist if it was on it, and locked + * at this point. Just unlock the hashchain and return. + */ + ASSERT(*O_dqpp); + ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp)); + XFS_DQ_HASH_UNLOCK(h); + xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)"); + return (0); /* success */ + } + XFS_STATS_INC(xfsstats.xs_qm_dqcachemisses); + + /* + * Dquot cache miss. We don't want to keep the inode lock across + * a (potential) disk read. Also we don't want to deal with the lock + * ordering between quotainode and this inode. OTOH, dropping the inode + * lock here means dealing with a chown that can happen before + * we re-acquire the lock. + */ + if (ip) + xfs_iunlock(ip, XFS_ILOCK_EXCL); + /* + * Save the hashchain version stamp, and unlock the chain, so that + * we don't keep the lock across a disk read + */ + version = h->qh_version; + XFS_DQ_HASH_UNLOCK(h); + + /* + * Allocate the dquot on the kernel heap, and read the ondisk + * portion off the disk. Also, do all the necessary initialization + * This can return ENOENT if dquot didn't exist on disk and we didn't + * ask it to allocate; ESRCH if quotas got turned off suddenly. + */ + if ((error = xfs_qm_idtodq(mp, id, type, + flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR| + XFS_QMOPT_DOWARN), + &dqp))) { + if (ip) + xfs_ilock(ip, XFS_ILOCK_EXCL); + return (error); + } + + /* + * See if this is mount code calling to look at the overall quota limits + * which are stored in the id == 0 user or group's dquot. + * Since we may not have done a quotacheck by this point, just return + * the dquot without attaching it to any hashtables, lists, etc, or even + * taking a reference. + * The caller must dqdestroy this once done. + */ + if (flags & XFS_QMOPT_DQSUSER) { + ASSERT(id == 0); + ASSERT(! ip); + goto dqret; + } + + /* + * Dquot lock comes after hashlock in the lock ordering + */ + ASSERT(! XFS_DQ_IS_LOCKED(dqp)); + if (ip) { + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (! XFS_IS_DQTYPE_ON(mp, type)) { + /* inode stays locked on return */ + xfs_qm_dqdestroy(dqp); + return XFS_ERROR(ESRCH); + } + /* + * A dquot could be attached to this inode by now, since + * we had dropped the ilock. + */ + if (type == XFS_DQ_USER) { + if (ip->i_udquot) { + xfs_qm_dqdestroy(dqp); + dqp = ip->i_udquot; + xfs_dqlock(dqp); + goto dqret; + } + } else { + if (ip->i_gdquot) { + xfs_qm_dqdestroy(dqp); + dqp = ip->i_gdquot; + xfs_dqlock(dqp); + goto dqret; + } + } + } + + /* + * Hashlock comes after ilock in lock order + */ + XFS_DQ_HASH_LOCK(h); + if (version != h->qh_version) { + xfs_dquot_t *tmpdqp; + /* + * Now, see if somebody else put the dquot in the + * hashtable before us. This can happen because we didn't + * keep the hashchain lock. We don't have to worry about + * lock order between the two dquots here since dqp isn't + * on any findable lists yet. + */ + if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) { + /* + * Duplicate found. Just throw away the new dquot + * and start over. + */ + xfs_qm_dqput(tmpdqp); + XFS_DQ_HASH_UNLOCK(h); + xfs_qm_dqdestroy(dqp); + XFS_STATS_INC(xfsstats.xs_qm_dquot_dups); + goto again; + } + } + + /* + * Put the dquot at the beginning of the hash-chain and mp's list + * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock .. + */ + ASSERT(XFS_DQ_IS_HASH_LOCKED(h)); + dqp->q_hash = h; + XQM_HASHLIST_INSERT(h, dqp); + + /* + * Attach this dquot to this filesystem's list of all dquots, + * kept inside the mount structure in m_quotainfo field + */ + xfs_qm_mplist_lock(mp); + + /* + * We return a locked dquot to the caller, with a reference taken + */ + xfs_dqlock(dqp); + dqp->q_nrefs = 1; + + XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp); + + xfs_qm_mplist_unlock(mp); + XFS_DQ_HASH_UNLOCK(h); + dqret: + ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip)); + xfs_dqtrace_entry(dqp, "DQGET DONE"); + *O_dqpp = dqp; + return (0); +} + + +/* + * Release a reference to the dquot (decrement ref-count) + * and unlock it. If there is a group quota attached to this + * dquot, carefully release that too without tripping over + * deadlocks'n'stuff. + */ +void +xfs_qm_dqput( + xfs_dquot_t *dqp) +{ + xfs_dquot_t *gdqp; + + ASSERT(dqp->q_nrefs > 0); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + xfs_dqtrace_entry(dqp, "DQPUT"); + + if (dqp->q_nrefs != 1) { + dqp->q_nrefs--; + xfs_dqunlock(dqp); + return; + } + + /* + * drop the dqlock and acquire the freelist and dqlock + * in the right order; but try to get it out-of-order first + */ + if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) { + xfs_dqtrace_entry(dqp, "DQPUT: FLLOCK-WAIT"); + xfs_dqunlock(dqp); + xfs_qm_freelist_lock(xfs_Gqm); + xfs_dqlock(dqp); + } + + while (1) { + gdqp = NULL; + + /* We can't depend on nrefs being == 1 here */ + if (--dqp->q_nrefs == 0) { + xfs_dqtrace_entry(dqp, "DQPUT: ON FREELIST"); + /* + * insert at end of the freelist. + */ + XQM_FREELIST_INSERT(&(xfs_Gqm->qm_dqfreelist), dqp); + + /* + * If we just added a udquot to the freelist, then + * we want to release the gdquot reference that + * it (probably) has. Otherwise it'll keep the + * gdquot from getting reclaimed. + */ + if ((gdqp = dqp->q_gdquot)) { + /* + * Avoid a recursive dqput call + */ + xfs_dqlock(gdqp); + dqp->q_gdquot = NULL; + } + + /* xfs_qm_freelist_print(&(xfs_Gqm->qm_dqfreelist), + "@@@@@++ Free list (after append) @@@@@+"); + */ + } + xfs_dqunlock(dqp); + + /* + * If we had a group quota inside the user quota as a hint, + * release it now. + */ + if (! gdqp) + break; + dqp = gdqp; + } + xfs_qm_freelist_unlock(xfs_Gqm); +} + +/* + * Release a dquot. Flush it if dirty, then dqput() it. + * dquot must not be locked. + */ +void +xfs_qm_dqrele( + xfs_dquot_t *dqp) +{ + ASSERT(dqp); + xfs_dqtrace_entry(dqp, "DQRELE"); + + xfs_dqlock(dqp); + /* + * We don't care to flush it if the dquot is dirty here. + * That will create stutters that we want to avoid. + * Instead we do a delayed write when we try to reclaim + * a dirty dquot. Also xfs_sync will take part of the burden... + */ + xfs_qm_dqput(dqp); +} + + +/* + * Write a modified dquot to disk. + * The dquot must be locked and the flush lock too taken by caller. + * The flush lock will not be unlocked until the dquot reaches the disk, + * but the dquot is free to be unlocked and modified by the caller + * in the interim. Dquot is still locked on return. This behavior is + * identical to that of inodes. + */ +int +xfs_qm_dqflush( + xfs_dquot_t *dqp, + uint flags) +{ + xfs_mount_t *mp; + xfs_buf_t *bp; + xfs_disk_dquot_t *ddqp; + int error; + SPLDECL(s); + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp)); + xfs_dqtrace_entry(dqp, "DQFLUSH"); + + /* + * If not dirty, nada. + */ + if (!XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqfunlock(dqp); + return (0); + } + + /* + * Cant flush a pinned dquot. Wait for it. + */ + xfs_qm_dqunpin_wait(dqp); + + /* + * This may have been unpinned because the filesystem is shutting + * down forcibly. If that's the case we must not write this dquot + * to disk, because the log record didn't make it to disk! + */ + if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) { + dqp->dq_flags &= ~(XFS_DQ_DIRTY); + xfs_dqfunlock(dqp); + return XFS_ERROR(EIO); + } + + /* + * Get the buffer containing the on-disk dquot + * We don't need a transaction envelope because we know that the + * the ondisk-dquot has already been allocated for. + */ + if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) { + xfs_dqtrace_entry(dqp, "DQTOBP FAIL"); + ASSERT(error != ENOENT); + /* + * Quotas could have gotten turned off (ESRCH) + */ + xfs_dqfunlock(dqp); + return (error); + } + + if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN, + "dqflush (incore copy)")) { + xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE); + return XFS_ERROR(EIO); + } + + /* This is the only portion of data that needs to persist */ + bcopy(&(dqp->q_core), ddqp, sizeof(xfs_disk_dquot_t)); + + /* + * Clear the dirty field and remember the flush lsn for later use. + */ + dqp->dq_flags &= ~(XFS_DQ_DIRTY); + mp = dqp->q_mount; + + /* lsn is 64 bits */ + AIL_LOCK(mp, s); + dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn; + AIL_UNLOCK(mp, s); + + /* + * Attach an iodone routine so that we can remove this dquot from the + * AIL and release the flush lock once the dquot is synced to disk. + */ + xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *)) + xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item)); + /* + * If the buffer is pinned then push on the log so we won't + * get stuck waiting in the write for too long. + */ + if (XFS_BUF_ISPINNED(bp)) { + xfs_dqtrace_entry(dqp, "DQFLUSH LOG FORCE"); + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + } + + if (flags & XFS_QMOPT_DELWRI) { + xfs_bdwrite(mp, bp); + } else if (flags & XFS_QMOPT_ASYNC) { + xfs_bawrite(mp, bp); + } else { + error = xfs_bwrite(mp, bp); + } + xfs_dqtrace_entry(dqp, "DQFLUSH END"); + /* + * dqp is still locked, but caller is free to unlock it now. + */ + return (error); + +} + +/* + * This is the dquot flushing I/O completion routine. It is called + * from interrupt level when the buffer containing the dquot is + * flushed to disk. It is responsible for removing the dquot logitem + * from the AIL if it has not been re-logged, and unlocking the dquot's + * flush lock. This behavior is very similar to that of inodes.. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_dqflush_done( + xfs_buf_t *bp, + xfs_dq_logitem_t *qip) +{ + xfs_dquot_t *dqp; + SPLDECL(s); + + dqp = qip->qli_dquot; + + /* + * We only want to pull the item from the AIL if its + * location in the log has not changed since we started the flush. + * Thus, we only bother if the dquot's lsn has + * not changed. First we check the lsn outside the lock + * since it's cheaper, and then we recheck while + * holding the lock before removing the dquot from the AIL. + */ + if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && + qip->qli_item.li_lsn == qip->qli_flush_lsn) { + + AIL_LOCK(dqp->q_mount, s); + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + if (qip->qli_item.li_lsn == qip->qli_flush_lsn) + xfs_trans_delete_ail(dqp->q_mount, + (xfs_log_item_t*)qip, s); + else + AIL_UNLOCK(dqp->q_mount, s); + } + + /* + * Release the dq's flush lock since we're done with it. + */ + xfs_dqfunlock(dqp); +} + + +int +xfs_qm_dqflock_nowait( + xfs_dquot_t *dqp) +{ + int locked; + + locked = cpsema(&((dqp)->q_flock)); + + /* XXX ifdef these out */ + if (locked) + (dqp)->dq_flags |= XFS_DQ_FLOCKED; + return (locked); +} + + +int +xfs_qm_dqlock_nowait( + xfs_dquot_t *dqp) +{ + return (mutex_trylock(&((dqp)->q_qlock))); +} + +void +xfs_dqlock( + xfs_dquot_t *dqp) +{ + mutex_lock(&(dqp->q_qlock), PINOD); +} + +void +xfs_dqunlock( + xfs_dquot_t *dqp) +{ + mutex_unlock(&(dqp->q_qlock)); + if (dqp->q_logitem.qli_dquot == dqp) { + /* Once was dqp->q_mount, but might just have been cleared */ + xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp, + (xfs_log_item_t*)&(dqp->q_logitem)); + } +} + + +void +xfs_dqunlock_nonotify( + xfs_dquot_t *dqp) +{ + mutex_unlock(&(dqp->q_qlock)); +} + +void +xfs_dqlock2( + xfs_dquot_t *d1, + xfs_dquot_t *d2) +{ + if (d1 && d2) { + ASSERT(d1 != d2); + if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) { + xfs_dqlock(d2); + xfs_dqlock(d1); + } else { + xfs_dqlock(d1); + xfs_dqlock(d2); + } + } else { + if (d1) { + xfs_dqlock(d1); + } else if (d2) { + xfs_dqlock(d2); + } + } +} + + +/* + * A rarely used accessor. This exists because we don't really want + * to expose the internals of a dquot to the outside world. + */ +xfs_dqid_t +xfs_qm_dqid( + xfs_dquot_t *dqp) +{ + return (INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); +} + + +/* + * Take a dquot out of the mount's dqlist as well as the hashlist. + * This is called via unmount as well as quotaoff, and the purge + * will always succeed unless there are soft (temp) references + * outstanding. + * + * This returns 0 if it was purged, 1 if it wasn't. It's not an error code + * that we're returning! XXXsup - not cool. + */ +/* ARGSUSED */ +int +xfs_qm_dqpurge( + xfs_dquot_t *dqp, + uint flags) +{ + xfs_dqhash_t *thishash; + xfs_mount_t *mp; + + mp = dqp->q_mount; + + ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp)); + ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash)); + + xfs_dqlock(dqp); + /* + * We really can't afford to purge a dquot that is + * referenced, because these are hard refs. + * It shouldn't happen in general because we went thru _all_ inodes in + * dqrele_all_inodes before calling this and didn't let the mountlock go. + * However it is possible that we have dquots with temporary + * references that are not attached to an inode. e.g. see xfs_setattr(). + */ + if (dqp->q_nrefs != 0) { + xfs_dqunlock(dqp); + XFS_DQ_HASH_UNLOCK(dqp->q_hash); + return (1); + } + + ASSERT(XFS_DQ_IS_ON_FREELIST(dqp)); + + /* + * If we're turning off quotas, we have to make sure that, for + * example, we don't delete quota disk blocks while dquots are + * in the process of getting written to those disk blocks. + * This dquot might well be on AIL, and we can't leave it there + * if we're turning off quotas. Basically, we need this flush + * lock, and are willing to block on it. + */ + if (! xfs_qm_dqflock_nowait(dqp)) { + /* + * Block on the flush lock after nudging dquot buffer, + * if it is incore. + */ + xfs_qm_dqflock_pushbuf_wait(dqp); + } + + /* + * XXXIf we're turning this type of quotas off, we don't care + * about the dirty metadata sitting in this dquot. OTOH, if + * we're unmounting, we do care, so we flush it and wait. + */ + if (XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqtrace_entry(dqp, "DQPURGE ->DQFLUSH: DQDIRTY"); + /* dqflush unlocks dqflock */ + /* + * Given that dqpurge is a very rare occurence, it is OK + * that we're holding the hashlist and mplist locks + * across the disk write. But, ... XXXsup + * + * We don't care about getting disk errors here. We need + * to purge this dquot anyway, so we go ahead regardless. + */ + (void) xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC); + xfs_dqflock(dqp); + } + ASSERT(dqp->q_pincount == 0); + ASSERT(XFS_FORCED_SHUTDOWN(mp) || + !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL)); + + thishash = dqp->q_hash; + XQM_HASHLIST_REMOVE(thishash, dqp); + XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(mp)), dqp); + /* + * XXX Move this to the front of the freelist, if we can get the + * freelist lock. + */ + ASSERT(XFS_DQ_IS_ON_FREELIST(dqp)); + + dqp->q_mount = NULL;; + dqp->q_hash = NULL; + dqp->dq_flags = XFS_DQ_INACTIVE; + bzero(&dqp->q_core, sizeof(dqp->q_core)); + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + XFS_DQ_HASH_UNLOCK(thishash); + return (0); +} + + +/* + * Do some primitive error checking on ondisk dquot + * data structures. Not just for debugging, actually; + * this can be useful for detecting data corruption mainly due to + * disk failures. + */ +/* ARGSUSED */ +int +xfs_qm_dqcheck( + xfs_disk_dquot_t *ddq, + xfs_dqid_t id, + uint type, /* used only when IO_dorepair is true */ + uint flags, + char *str) +{ + int errs; + + errs = 0; + /* ASSERT(flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN)); */ + /* + * We can encounter an uninitialized dquot buffer for 2 reasons: + * 1. If we crash while deleting the quotainode(s), and those blks get used + * for some user data. This is because we take the path of regular + * file deletion; however, the size field of quotainodes is never + * updated, so all the tricks that we play in itruncate_finish + * don't quite matter. + * + * 2. We don't play the quota buffers when there's a quotaoff logitem. + * But the allocation will be replayed so we'll end up with an + * uninitialized quota block. + * + * This is all fine; things are still consistent, and we haven't lost + * any quota information. Just don't complain about bad dquot blks. + */ + if (INT_GET(ddq->d_magic, ARCH_CONVERT) != XFS_DQUOT_MAGIC) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", + str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_MAGIC); + errs++; + } + if (INT_GET(ddq->d_version, ARCH_CONVERT) != XFS_DQUOT_VERSION) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", + str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_VERSION); + errs++; + } + + if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER && INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : XFS dquot ID 0x%x, unknown flags 0x%x", + str, id, INT_GET(ddq->d_flags, ARCH_CONVERT)); + errs++; + } + + if (id != -1 && id != INT_GET(ddq->d_id, ARCH_CONVERT)) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : ondisk-dquot 0x%x, ID mismatch: " + "0x%x expected, found id 0x%x", + str, ddq, id, INT_GET(ddq->d_id, ARCH_CONVERT)); + errs++; + } + + if (! errs) { + if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) && + INT_GET(ddq->d_bcount, ARCH_CONVERT) >= INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) { + if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT) && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : Dquot ID 0x%x (0x%x) " + "BLK TIMER NOT STARTED", + str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq); + errs++; + } + } + if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) && + INT_GET(ddq->d_icount, ARCH_CONVERT) >= INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) { + if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT) && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : Dquot ID 0x%x (0x%x) " + "INODE TIMER NOT STARTED", + str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq); + errs++; + } + } + } + + if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) + return (errs); + + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_NOTE, "Re-initializing dquot ID 0x%x", id); + + /* + * Typically, a repair is only requested by quotacheck. + */ + ASSERT(id != -1); + ASSERT(flags & XFS_QMOPT_DQREPAIR); + bzero(ddq, sizeof(xfs_dqblk_t)); + xfs_qm_dqinit_core(id, type, (xfs_dqblk_t *)ddq); + return (errs); +} + +#ifdef QUOTADEBUG +void +xfs_qm_dqprint(xfs_dquot_t *dqp) +{ + printk( "-----------KERNEL DQUOT----------------\n"); + printk( "---- dquot ID = %d\n", (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); + printk( "---- type = %s\n", XFS_QM_ISUDQ(dqp) ? "USR" : "GRP"); + printk( "---- fs = 0x%p\n", dqp->q_mount); + printk( "---- blkno = 0x%x\n", (int) dqp->q_blkno); + printk( "---- boffset = 0x%x\n", (int) dqp->q_bufoffset); + printk( "---- blkhlimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT), + (int) INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT)); + printk( "---- blkslimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)); + printk( "---- inohlimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)); + printk( "---- inoslimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)); + printk( "---- bcount = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); + printk( "---- icount = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); + printk( "---- btimer = %d\n", (int)INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT)); + printk( "---- itimer = %d\n", (int)INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)); + + printk( "---------------------------\n"); +} +#endif + +/* + * Give the buffer a little push if it is incore and + * wait on the flush lock. + */ +void +xfs_qm_dqflock_pushbuf_wait( + xfs_dquot_t *dqp) +{ + xfs_buf_t *bp; + + /* + * Check to see if the dquot has been flushed delayed + * write. If so, grab its buffer and send it + * out immediately. We'll be able to acquire + * the flush lock when the I/O completes. + */ + bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno, + XFS_QI_DQCHUNKLEN(dqp->q_mount), + XFS_INCORE_TRYLOCK); + if (bp != NULL) { + if (XFS_BUF_ISDELAYWRITE(bp)) { + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(dqp->q_mount, + (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + xfs_bawrite(dqp->q_mount, bp); + } else { + xfs_buf_relse(bp); + } + } + xfs_dqflock(dqp); +} diff -Nur linux-2.4.19/fs/xfs/xfs_dquot.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot.h --- linux-2.4.19/fs/xfs/xfs_dquot.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQUOT_H__ +#define __XFS_DQUOT_H__ + +/* + * Dquots are structures that hold quota information about a user or a group, + * much like inodes are for files. In fact, dquots share many characteristics + * with inodes. However, dquots can also be a centralized resource, relative + * to a collection of inodes. In this respect, dquots share some characteristics + * of the superblock. + * XFS dquots exploit both those in its algorithms. They make every attempt + * to not be a bottleneck when quotas are on and have minimal impact, if any, + * when quotas are off. + */ + +/* + * The hash chain headers (hash buckets) + */ +typedef struct xfs_dqhash { + struct xfs_dquot *qh_next; + mutex_t qh_lock; + uint qh_version; /* ever increasing version */ + uint qh_nelems; /* number of dquots on the list */ +} xfs_dqhash_t; + +typedef struct xfs_dqlink { + struct xfs_dquot *ql_next; /* forward link */ + struct xfs_dquot **ql_prevp; /* pointer to prev ql_next */ +} xfs_dqlink_t; + +struct xfs_mount; +struct xfs_trans; + +/* + * This is the marker which is designed to occupy the first few + * bytes of the xfs_dquot_t structure. Even inside this, the freelist pointers + * must come first. + * This serves as the marker ("sentinel") when we have to restart list + * iterations because of locking considerations. + */ +typedef struct xfs_dqmarker { + struct xfs_dquot*dqm_flnext; /* link to freelist: must be first */ + struct xfs_dquot*dqm_flprev; + xfs_dqlink_t dqm_mplist; /* link to mount's list of dquots */ + xfs_dqlink_t dqm_hashlist; /* link to the hash chain */ + uint dqm_flags; /* various flags (XFS_DQ_*) */ +} xfs_dqmarker_t; + +/* + * The incore dquot structure + */ +typedef struct xfs_dquot { + xfs_dqmarker_t q_lists; /* list ptrs, q_flags (marker) */ + xfs_dqhash_t *q_hash; /* the hashchain header */ + struct xfs_mount*q_mount; /* filesystem this relates to */ + struct xfs_trans*q_transp; /* trans this belongs to currently */ + uint q_nrefs; /* # active refs from inodes */ + xfs_daddr_t q_blkno; /* blkno of dquot buffer */ + int q_bufoffset; /* off of dq in buffer (# dquots) */ + xfs_fileoff_t q_fileoffset; /* offset in quotas file */ + + struct xfs_dquot*q_gdquot; /* group dquot, hint only */ + xfs_disk_dquot_t q_core; /* actual usage & quotas */ + xfs_dq_logitem_t q_logitem; /* dquot log item */ + xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */ + xfs_qcnt_t q_res_icount; /* total inos allocd+reserved */ + xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */ + mutex_t q_qlock; /* quota lock */ + sema_t q_flock; /* flush lock */ + uint q_pincount; /* pin count for this dquot */ + sv_t q_pinwait; /* sync var for pinning */ +#ifdef DQUOT_TRACING + struct ktrace *q_trace; /* trace header structure */ +#endif +} xfs_dquot_t; + + +#define dq_flnext q_lists.dqm_flnext +#define dq_flprev q_lists.dqm_flprev +#define dq_mplist q_lists.dqm_mplist +#define dq_hashlist q_lists.dqm_hashlist +#define dq_flags q_lists.dqm_flags + +#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++) + +/* + * Quota Accounting flags + */ +#define XFS_ALL_QUOTA_ACCT (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT) +#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD) +#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD) +#define XFS_ALL_QUOTA_ACTV (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE) +#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ + XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD) + +#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) +#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) +#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) + +/* + * Quota Limit Enforcement flags + */ +#define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD) +#define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD) +#define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD) + +#ifdef DEBUG +static inline int +XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) +{ + if (mutex_trylock(&dqp->q_qlock)) { + mutex_unlock(&dqp->q_qlock); + return 0; + } + return 1; +} +#endif + +/* + * The following three routines simply manage the q_flock + * semaphore embedded in the dquot. This semaphore synchronizes + * processes attempting to flush the in-core dquot back to disk. + */ +#define xfs_dqflock(dqp) { psema(&((dqp)->q_flock), PINOD | PRECALC);\ + (dqp)->dq_flags |= XFS_DQ_FLOCKED; } +#define xfs_dqfunlock(dqp) { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \ + vsema(&((dqp)->q_flock)); \ + (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); } + +#define XFS_DQ_PINLOCK(dqp) mutex_spinlock( \ + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock)) +#define XFS_DQ_PINUNLOCK(dqp, s) mutex_spinunlock( \ + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s) + +#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0) +#define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) +#define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) +#define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) +#define XFS_DQ_TO_QINF(dqp) ((dqp)->q_mount->m_quotainfo) +#define XFS_DQ_TO_QIP(dqp) (XFS_QM_ISUDQ(dqp) ? \ + XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \ + XFS_DQ_TO_QINF(dqp)->qi_gquotaip) + +#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \ + (XFS_IS_UQUOTA_ON((d)->q_mount)) : \ + (XFS_IS_GQUOTA_ON((d)->q_mount)))) +#ifdef DQUOT_TRACING +/* + * Dquot Tracing stuff. + */ +#define DQUOT_TRACE_SIZE 64 +#define DQUOT_KTRACE_ENTRY 1 + +#define xfs_dqtrace_entry_ino(a,b,ip) \ +xfs_dqtrace_entry__((a), (b), (void*)__return_address, (ip)) +#define xfs_dqtrace_entry(a,b) \ +xfs_dqtrace_entry__((a), (b), (void*)__return_address, NULL) +extern void xfs_dqtrace_entry__(xfs_dquot_t *dqp, char *func, + void *, xfs_inode_t *); +#else +#define xfs_dqtrace_entry(a,b) +#define xfs_dqtrace_entry_ino(a,b,ip) +#endif +#ifdef QUOTADEBUG +extern void xfs_qm_dqprint(xfs_dquot_t *); +#else +#define xfs_qm_dqprint(a) +#endif + +extern xfs_dquot_t *xfs_qm_dqinit(xfs_mount_t *, xfs_dqid_t, uint); +extern void xfs_qm_dqdestroy(xfs_dquot_t *); +extern int xfs_qm_dqflush(xfs_dquot_t *, uint); +extern int xfs_qm_dqpurge(xfs_dquot_t *, uint); +extern void xfs_qm_dqunpin_wait(xfs_dquot_t *); +extern int xfs_qm_dqlock_nowait(xfs_dquot_t *); +extern int xfs_qm_dqflock_nowait(xfs_dquot_t *); +extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp); +extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, + xfs_disk_dquot_t *); +extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint); + +#endif /* __XFS_DQUOT_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_dquot_item.c linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot_item.c --- linux-2.4.19/fs/xfs/xfs_dquot_item.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot_item.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + * returns the number of iovecs needed to log the given dquot item. + */ +/* ARGSUSED */ +STATIC uint +xfs_qm_dquot_logitem_size( + xfs_dq_logitem_t *logitem) +{ + /* + * we need only two iovecs, one for the format, one for the real thing + */ + return (2); +} + +/* + * fills in the vector of log iovecs for the given dquot log item. + */ +STATIC void +xfs_qm_dquot_logitem_format( + xfs_dq_logitem_t *logitem, + xfs_log_iovec_t *logvec) +{ + ASSERT(logitem); + ASSERT(logitem->qli_dquot); + + logvec->i_addr = (xfs_caddr_t)&logitem->qli_format; + logvec->i_len = sizeof(xfs_dq_logformat_t); + logvec++; + logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core; + logvec->i_len = sizeof(xfs_disk_dquot_t); + + ASSERT(2 == logitem->qli_item.li_desc->lid_size); + logitem->qli_format.qlf_size = 2; + +} + +/* + * Increment the pin count of the given dquot. + * This value is protected by pinlock spinlock in the xQM structure. + */ +STATIC void +xfs_qm_dquot_logitem_pin( + xfs_dq_logitem_t *logitem) +{ + unsigned long s; + xfs_dquot_t *dqp; + + dqp = logitem->qli_dquot; + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + s = XFS_DQ_PINLOCK(dqp); + dqp->q_pincount++; + XFS_DQ_PINUNLOCK(dqp, s); +} + +/* + * Decrement the pin count of the given dquot, and wake up + * anyone in xfs_dqwait_unpin() if the count goes to 0. The + * dquot must have been previously pinned with a call to xfs_dqpin(). + */ +STATIC void +xfs_qm_dquot_logitem_unpin( + xfs_dq_logitem_t *logitem) +{ + unsigned long s; + xfs_dquot_t *dqp; + + dqp = logitem->qli_dquot; + ASSERT(dqp->q_pincount > 0); + s = XFS_DQ_PINLOCK(dqp); + dqp->q_pincount--; + if (dqp->q_pincount == 0) { + sv_broadcast(&dqp->q_pinwait); + } + XFS_DQ_PINUNLOCK(dqp, s); +} + +/* ARGSUSED */ +STATIC void +xfs_qm_dquot_logitem_unpin_remove( + xfs_dq_logitem_t *logitem, + xfs_trans_t *tp) +{ + xfs_qm_dquot_logitem_unpin(logitem); +} + +/* + * Given the logitem, this writes the corresponding dquot entry to disk + * asynchronously. This is called with the dquot entry securely locked; + * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot + * at the end. + */ +STATIC void +xfs_qm_dquot_logitem_push( + xfs_dq_logitem_t *logitem) +{ + xfs_dquot_t *dqp; + + dqp = logitem->qli_dquot; + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp)); + + /* + * Since we were able to lock the dquot's flush lock and + * we found it on the AIL, the dquot must be dirty. This + * is because the dquot is removed from the AIL while still + * holding the flush lock in xfs_dqflush_done(). Thus, if + * we found it in the AIL and were able to obtain the flush + * lock without sleeping, then there must not have been + * anyone in the process of flushing the dquot. + */ + xfs_qm_dqflush(dqp, XFS_B_DELWRI); + xfs_dqunlock(dqp); +} + +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_qm_dquot_logitem_committed( + xfs_dq_logitem_t *l, + xfs_lsn_t lsn) +{ + /* + * We always re-log the entire dquot when it becomes dirty, + * so, the latest copy _is_ the only one that matters. + */ + return (lsn); +} + + +/* + * This is called to wait for the given dquot to be unpinned. + * Most of these pin/unpin routines are plagiarized from inode code. + */ +void +xfs_qm_dqunpin_wait( + xfs_dquot_t *dqp) +{ + SPLDECL(s); + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (dqp->q_pincount == 0) { + return; + } + + /* + * Give the log a push so we don't wait here too long. + */ + xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE); + s = XFS_DQ_PINLOCK(dqp); + if (dqp->q_pincount == 0) { + XFS_DQ_PINUNLOCK(dqp, s); + return; + } + sv_wait(&(dqp->q_pinwait), PINOD, + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s); +} + +/* + * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that + * the dquot is locked by us, but the flush lock isn't. So, here we are + * going to see if the relevant dquot buffer is incore, waiting on DELWRI. + * If so, we want to push it out to help us take this item off the AIL as soon + * as possible. + * + * We must not be holding the AIL_LOCK at this point. Calling incore() to + * search the buffercache can be a time consuming thing, and AIL_LOCK is a + * spinlock. + */ +STATIC void +xfs_qm_dquot_logitem_pushbuf( + xfs_dq_logitem_t *qip) +{ + xfs_dquot_t *dqp; + xfs_mount_t *mp; + xfs_buf_t *bp; + uint dopush; + + dqp = qip->qli_dquot; + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + + /* + * The qli_pushbuf_flag keeps others from + * trying to duplicate our effort. + */ + ASSERT(qip->qli_pushbuf_flag != 0); + ASSERT(qip->qli_push_owner == get_thread_id()); + + /* + * If flushlock isn't locked anymore, chances are that the + * inode flush completed and the inode was taken off the AIL. + * So, just get out. + */ + if ((valusema(&(dqp->q_flock)) > 0) || + ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); + return; + } + mp = dqp->q_mount; + bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno, + XFS_QI_DQCHUNKLEN(mp), + XFS_INCORE_TRYLOCK); + if (bp != NULL) { + if (XFS_BUF_ISDELAYWRITE(bp)) { + dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && + (valusema(&(dqp->q_flock)) <= 0)); + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); + + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + if (dopush) { +#ifdef XFSRACEDEBUG + delay_for_intr(); + delay(300); +#endif + xfs_bawrite(mp, bp); + } else { + xfs_buf_relse(bp); + } + } else { + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); + xfs_buf_relse(bp); + } + return; + } + + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); +} + +/* + * This is called to attempt to lock the dquot associated with this + * dquot log item. Don't sleep on the dquot lock or the flush lock. + * If the flush lock is already held, indicating that the dquot has + * been or is in the process of being flushed, then see if we can + * find the dquot's buffer in the buffer cache without sleeping. If + * we can and it is marked delayed write, then we want to send it out. + * We delay doing so until the push routine, though, to avoid sleeping + * in any device strategy routines. + */ +STATIC uint +xfs_qm_dquot_logitem_trylock( + xfs_dq_logitem_t *qip) +{ + xfs_dquot_t *dqp; + uint retval; + + dqp = qip->qli_dquot; + if (dqp->q_pincount > 0) + return (XFS_ITEM_PINNED); + + if (! xfs_qm_dqlock_nowait(dqp)) + return (XFS_ITEM_LOCKED); + + retval = XFS_ITEM_SUCCESS; + if (! xfs_qm_dqflock_nowait(dqp)) { + /* + * The dquot is already being flushed. It may have been + * flushed delayed write, however, and we don't want to + * get stuck waiting for that to complete. So, we want to check + * to see if we can lock the dquot's buffer without sleeping. + * If we can and it is marked for delayed write, then we + * hold it and send it out from the push routine. We don't + * want to do that now since we might sleep in the device + * strategy routine. We also don't want to grab the buffer lock + * here because we'd like not to call into the buffer cache + * while holding the AIL_LOCK. + * Make sure to only return PUSHBUF if we set pushbuf_flag + * ourselves. If someone else is doing it then we don't + * want to go to the push routine and duplicate their efforts. + */ + if (qip->qli_pushbuf_flag == 0) { + qip->qli_pushbuf_flag = 1; + ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno); +#ifdef DEBUG + qip->qli_push_owner = get_thread_id(); +#endif + /* + * The dquot is left locked. + */ + retval = XFS_ITEM_PUSHBUF; + } else { + retval = XFS_ITEM_FLUSHING; + xfs_dqunlock_nonotify(dqp); + } + } + + ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL); + return (retval); +} + + +/* + * Unlock the dquot associated with the log item. + * Clear the fields of the dquot and dquot log item that + * are specific to the current transaction. If the + * hold flags is set, do not unlock the dquot. + */ +STATIC void +xfs_qm_dquot_logitem_unlock( + xfs_dq_logitem_t *ql) +{ + xfs_dquot_t *dqp; + + ASSERT(ql != NULL); + dqp = ql->qli_dquot; + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + + /* + * Clear the transaction pointer in the dquot + */ + dqp->q_transp = NULL; + + /* + * dquots are never 'held' from getting unlocked at the end of + * a transaction. Their locking and unlocking is hidden inside the + * transaction layer, within trans_commit. Hence, no LI_HOLD flag + * for the logitem. + */ + xfs_dqunlock(dqp); +} + + +/* + * The transaction with the dquot locked has aborted. The dquot + * must not be dirty within the transaction. We simply unlock just + * as if the transaction had been cancelled. + */ +STATIC void +xfs_qm_dquot_logitem_abort( + xfs_dq_logitem_t *ql) +{ + xfs_qm_dquot_logitem_unlock(ql); +} + +/* + * this needs to stamp an lsn into the dquot, I think. + * rpc's that look at user dquot's would then have to + * push on the dependency recorded in the dquot + */ +/* ARGSUSED */ +STATIC void +xfs_qm_dquot_logitem_committing( + xfs_dq_logitem_t *l, + xfs_lsn_t lsn) +{ + return; +} + + +/* + * This is the ops vector for dquots + */ +struct xfs_item_ops xfs_dquot_item_ops = { + .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size, + .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_qm_dquot_logitem_format, + .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin, + .iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unpin, + .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*)) + xfs_qm_dquot_logitem_unpin_remove, + .iop_trylock = (uint(*)(xfs_log_item_t*)) + xfs_qm_dquot_logitem_trylock, + .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock, + .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_dquot_logitem_committed, + .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push, + .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort, + .iop_pushbuf = (void(*)(xfs_log_item_t*)) + xfs_qm_dquot_logitem_pushbuf, + .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_dquot_logitem_committing +}; + +/* + * Initialize the dquot log item for a newly allocated dquot. + * The dquot isn't locked at this point, but it isn't on any of the lists + * either, so we don't care. + */ +void +xfs_qm_dquot_logitem_init( + struct xfs_dquot *dqp) +{ + xfs_dq_logitem_t *lp; + lp = &dqp->q_logitem; + + lp->qli_item.li_type = XFS_LI_DQUOT; + lp->qli_item.li_ops = &xfs_dquot_item_ops; + lp->qli_item.li_mountp = dqp->q_mount; + lp->qli_dquot = dqp; + lp->qli_format.qlf_type = XFS_LI_DQUOT; + lp->qli_format.qlf_id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT); + lp->qli_format.qlf_blkno = dqp->q_blkno; + lp->qli_format.qlf_len = 1; + /* + * This is just the offset of this dquot within its buffer + * (which is currently 1 FSB and probably won't change). + * Hence 32 bits for this offset should be just fine. + * Alternatively, we can store (bufoffset / sizeof(xfs_dqblk_t)) + * here, and recompute it at recovery time. + */ + lp->qli_format.qlf_boffset = (__uint32_t)dqp->q_bufoffset; +} + +/*------------------ QUOTAOFF LOG ITEMS -------------------*/ + +/* + * This returns the number of iovecs needed to log the given quotaoff item. + * We only need 1 iovec for an quotaoff item. It just logs the + * quotaoff_log_format structure. + */ +/*ARGSUSED*/ +STATIC uint +xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf) +{ + return (1); +} + +/* + * This is called to fill in the vector of log iovecs for the + * given quotaoff log item. We use only 1 iovec, and we point that + * at the quotaoff_log_format structure embedded in the quotaoff item. + * It is at this point that we assert that all of the extent + * slots in the quotaoff item have been filled. + */ +STATIC void +xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t *qf, + xfs_log_iovec_t *log_vector) +{ + ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF); + + log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format); + log_vector->i_len = sizeof(xfs_qoff_logitem_t); + qf->qql_format.qf_size = 1; +} + + +/* + * Pinning has no meaning for an quotaoff item, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf) +{ + return; +} + + +/* + * Since pinning has no meaning for an quotaoff item, unpinning does + * not either. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf) +{ + return; +} + +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp) +{ + return; +} + +/* + * Quotaoff items have no locking, so just return success. + */ +/*ARGSUSED*/ +STATIC uint +xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf) +{ + return XFS_ITEM_LOCKED; +} + +/* + * Quotaoff items have no locking or pushing, so return failure + * so that the caller doesn't bother with us. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf) +{ + return; +} + +/* + * The quotaoff-start-item is logged only once and cannot be moved in the log, + * so simply return the lsn at which it's been logged. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn) +{ + return (lsn); +} + +/* + * The transaction of which this QUOTAOFF is a part has been aborted. + * Just clean up after ourselves. + * Shouldn't this never happen in the case of qoffend logitems? XXX + */ +STATIC void +xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf) +{ + kmem_free(qf, sizeof(xfs_qoff_logitem_t)); +} + +/* + * There isn't much you can do to push on an quotaoff item. It is simply + * stuck waiting for the log to be flushed to disk. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf) +{ + return; +} + + +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_qm_qoffend_logitem_committed( + xfs_qoff_logitem_t *qfe, + xfs_lsn_t lsn) +{ + xfs_qoff_logitem_t *qfs; + SPLDECL(s); + + qfs = qfe->qql_start_lip; + AIL_LOCK(qfs->qql_item.li_mountp,s); + /* + * Delete the qoff-start logitem from the AIL. + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s); + kmem_free(qfs, sizeof(xfs_qoff_logitem_t)); + kmem_free(qfe, sizeof(xfs_qoff_logitem_t)); + return (xfs_lsn_t)-1; +} + +/* + * XXX rcc - don't know quite what to do with this. I think we can + * just ignore it. The only time that isn't the case is if we allow + * the client to somehow see that quotas have been turned off in which + * we can't allow that to get back until the quotaoff hits the disk. + * So how would that happen? Also, do we need different routines for + * quotaoff start and quotaoff end? I suspect the answer is yes but + * to be sure, I need to look at the recovery code and see how quota off + * recovery is handled (do we roll forward or back or do something else). + * If we roll forwards or backwards, then we need two separate routines, + * one that does nothing and one that stamps in the lsn that matters + * (truly makes the quotaoff irrevocable). If we do something else, + * then maybe we don't need two. + */ +/* ARGSUSED */ +STATIC void +xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn) +{ + return; +} + +/* ARGSUSED */ +STATIC void +xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn) +{ + return; +} + +struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { + .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, + .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_qm_qoff_logitem_format, + .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin, + .iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin, + .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*)) + xfs_qm_qoff_logitem_unpin_remove, + .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock, + .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock, + .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoffend_logitem_committed, + .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push, + .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort, + .iop_pushbuf = NULL, + .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoffend_logitem_committing +}; + +/* + * This is the ops vector shared by all quotaoff-start log items. + */ +struct xfs_item_ops xfs_qm_qoff_logitem_ops = { + .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, + .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_qm_qoff_logitem_format, + .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin, + .iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin, + .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*)) + xfs_qm_qoff_logitem_unpin_remove, + .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock, + .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock, + .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoff_logitem_committed, + .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push, + .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort, + .iop_pushbuf = NULL, + .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoff_logitem_committing +}; + +/* + * Allocate and initialize an quotaoff item of the correct quota type(s). + */ +xfs_qoff_logitem_t * +xfs_qm_qoff_logitem_init( + struct xfs_mount *mp, + xfs_qoff_logitem_t *start, + uint flags) +{ + xfs_qoff_logitem_t *qf; + + qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP); + + qf->qql_item.li_type = XFS_LI_QUOTAOFF; + if (start) + qf->qql_item.li_ops = &xfs_qm_qoffend_logitem_ops; + else + qf->qql_item.li_ops = &xfs_qm_qoff_logitem_ops; + qf->qql_item.li_mountp = mp; + qf->qql_format.qf_type = XFS_LI_QUOTAOFF; + qf->qql_format.qf_flags = flags; + qf->qql_start_lip = start; + return (qf); +} diff -Nur linux-2.4.19/fs/xfs/xfs_dquot_item.h linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot_item.h --- linux-2.4.19/fs/xfs/xfs_dquot_item.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_dquot_item.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQUOT_ITEM_H__ +#define __XFS_DQUOT_ITEM_H__ + +/* + * These are the structures used to lay out dquots and quotaoff + * records on the log. Quite similar to those of inodes. + */ + +/* + * log format struct for dquots. + * The first two fields must be the type and size fitting into + * 32 bits : log_recovery code assumes that. + */ +typedef struct xfs_dq_logformat { + __uint16_t qlf_type; /* dquot log item type */ + __uint16_t qlf_size; /* size of this item */ + xfs_dqid_t qlf_id; /* usr/grp id number : 32 bits */ + __int64_t qlf_blkno; /* blkno of dquot buffer */ + __int32_t qlf_len; /* len of dquot buffer */ + __uint32_t qlf_boffset; /* off of dquot in buffer */ +} xfs_dq_logformat_t; + +/* + * log format struct for QUOTAOFF records. + * The first two fields must be the type and size fitting into + * 32 bits : log_recovery code assumes that. + * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer + * to the first and ensures that the first logitem is taken out of the AIL + * only when the last one is securely committed. + */ +typedef struct xfs_qoff_logformat { + unsigned short qf_type; /* quotaoff log item type */ + unsigned short qf_size; /* size of this item */ + unsigned int qf_flags; /* USR and/or GRP */ + char qf_pad[12]; /* padding for future */ +} xfs_qoff_logformat_t; + + +#ifdef __KERNEL__ + +struct xfs_dquot; +struct xfs_trans; +struct xfs_mount; +typedef struct xfs_dq_logitem { + xfs_log_item_t qli_item; /* common portion */ + struct xfs_dquot *qli_dquot; /* dquot ptr */ + xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ + unsigned short qli_pushbuf_flag; /* one bit used in push_ail */ +#ifdef DEBUG + uint64_t qli_push_owner; +#endif + xfs_dq_logformat_t qli_format; /* logged structure */ +} xfs_dq_logitem_t; + + +typedef struct xfs_qoff_logitem { + xfs_log_item_t qql_item; /* common portion */ + struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */ + xfs_qoff_logformat_t qql_format; /* logged structure */ +} xfs_qoff_logitem_t; + + +extern void xfs_qm_dquot_logitem_init(struct xfs_dquot *); +extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *, + xfs_qoff_logitem_t *, uint); +extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *, + xfs_qoff_logitem_t *, uint); +extern void xfs_trans_log_quotaoff_item(struct xfs_trans *, + xfs_qoff_logitem_t *); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_DQUOT_ITEM_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_error.c linux-2.4.19-sgi211r3/fs/xfs/xfs_error.c --- linux-2.4.19/fs/xfs/xfs_error.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_error.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +#ifdef DEBUG + +int xfs_etrap[XFS_ERROR_NTRAP] = { + 0, +}; + +int +xfs_error_trap(int e) +{ + int i; + + if (!e) + return 0; + for (i = 0; i < XFS_ERROR_NTRAP; i++) { + if (xfs_etrap[i] == 0) + break; + if (e != xfs_etrap[i]) + continue; + cmn_err(CE_NOTE, "xfs_error_trap: error %d", e); + debug_stop_all_cpus((void *)-1LL); + BUG(); + break; + } + return e; +} +#endif + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) + +int xfs_etest[XFS_NUM_INJECT_ERROR]; +int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR]; +char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR]; + +void +xfs_error_test_init(void) +{ + bzero(xfs_etest, sizeof(xfs_etest)); + bzero(xfs_etest_fsid, sizeof(xfs_etest_fsid)); + bzero(xfs_etest_fsname, sizeof(xfs_etest_fsname)); +} + +int +xfs_error_test(int error_tag, int *fsidp, char *expression, + int line, char *file, unsigned long randfactor) +{ + int i; + int64_t fsid; + + if (random() % randfactor) + return 0; + + bcopy(fsidp, &fsid, sizeof(fsid_t)); + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) { + cmn_err(CE_WARN, + "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"", + expression, file, line, xfs_etest_fsname[i]); + return 1; + } + } + + return 0; +} + +int +xfs_errortag_add(int error_tag, xfs_mount_t *mp) +{ + int i; + int len; + int64_t fsid; + + bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t)); + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) { + cmn_err(CE_WARN, "XFS error tag #%d on", error_tag); + return 0; + } + } + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest[i] == 0) { + cmn_err(CE_WARN, "Turned on XFS error tag #%d", + error_tag); + xfs_etest[i] = error_tag; + xfs_etest_fsid[i] = fsid; + len = strlen(mp->m_fsname); + xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP); + strcpy(xfs_etest_fsname[i], mp->m_fsname); + return 0; + } + } + + cmn_err(CE_WARN, "error tag overflow, too many turned on"); + + return 1; +} + +int +xfs_errortag_clear(int error_tag, xfs_mount_t *mp) +{ + int i; + int64_t fsid; + + bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t)); + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) { + xfs_etest[i] = 0; + xfs_etest_fsid[i] = 0LL; + kmem_free(xfs_etest_fsname[i], + strlen(xfs_etest_fsname[i]) + 1); + xfs_etest_fsname[i] = NULL; + cmn_err(CE_WARN, "Cleared XFS error tag #%d", + error_tag); + return 0; + } + } + + cmn_err(CE_WARN, "XFS error tag %d not on", error_tag); + + return 1; +} + +int +xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud) +{ + int i; + int cleared = 0; + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) && + xfs_etest[i] != 0) { + cleared = 1; + cmn_err(CE_WARN, "Clearing XFS error tag #%d", + xfs_etest[i]); + xfs_etest[i] = 0; + xfs_etest_fsid[i] = 0LL; + kmem_free(xfs_etest_fsname[i], + strlen(xfs_etest_fsname[i]) + 1); + xfs_etest_fsname[i] = NULL; + } + } + + if (loud || cleared) + cmn_err(CE_WARN, + "Cleared all XFS error tags for filesystem \"%s\"", + fsname); + + return 0; +} + +int +xfs_errortag_clearall(xfs_mount_t *mp) +{ + int64_t fsid; + + bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t)); + + return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1); +} +#endif /* DEBUG || INDUCE_IO_ERROR */ + +static void +xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap) +{ + char *newfmt; + int len = 16 + mp->m_fsname_len + strlen(fmt); + + newfmt = kmem_alloc(len, KM_SLEEP); + sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt); + icmn_err(level, newfmt, ap); + kmem_free(newfmt, len); +} + +void +xfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xfs_fs_vcmn_err(level, mp, fmt, ap); + va_end(ap); +} + +void +xfs_cmn_err(uint64_t panic_tag, int level, xfs_mount_t *mp, char *fmt, ...) +{ + va_list ap; + + if (xfs_panic_mask && (xfs_panic_mask & panic_tag) + && (level & CE_ALERT)) { + level &= ~CE_ALERT; + level |= CE_PANIC; + cmn_err(CE_ALERT, "Transforming an alert into a panic."); + } + va_start(ap, fmt); + xfs_fs_vcmn_err(level, mp, fmt, ap); + va_end(ap); +} diff -Nur linux-2.4.19/fs/xfs/xfs_error.h linux-2.4.19-sgi211r3/fs/xfs/xfs_error.h --- linux-2.4.19/fs/xfs/xfs_error.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_error.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ERROR_H__ +#define __XFS_ERROR_H__ + +#define prdev(fmt,dev,args...) \ + printk("XFS: device 0x%x- " fmt "\n", dev, ## args) + +#define XFS_ERECOVER 1 /* Failure to recover log */ +#define XFS_ELOGSTAT 2 /* Failure to stat log in user space */ +#define XFS_ENOLOGSPACE 3 /* Reservation too large */ +#define XFS_ENOTSUP 4 /* Operation not supported */ +#define XFS_ENOLSN 5 /* Can't find the lsn you asked for */ +#define XFS_ENOTFOUND 6 +#define XFS_ENOTXFS 7 /* Not XFS filesystem */ + +#ifdef DEBUG +#define XFS_ERROR_NTRAP 10 +extern int xfs_etrap[XFS_ERROR_NTRAP]; +extern int xfs_error_trap(int); +#define XFS_ERROR(e) xfs_error_trap(e) +#else +#define XFS_ERROR(e) (e) +#endif + + +/* + * error injection tags - the labels can be anything you want + * but each tag should have its own unique number + */ + +#define XFS_ERRTAG_NOERROR 0 +#define XFS_ERRTAG_IFLUSH_1 1 +#define XFS_ERRTAG_IFLUSH_2 2 +#define XFS_ERRTAG_IFLUSH_3 3 +#define XFS_ERRTAG_IFLUSH_4 4 +#define XFS_ERRTAG_IFLUSH_5 5 +#define XFS_ERRTAG_IFLUSH_6 6 +#define XFS_ERRTAG_DA_READ_BUF 7 +#define XFS_ERRTAG_BTREE_CHECK_LBLOCK 8 +#define XFS_ERRTAG_BTREE_CHECK_SBLOCK 9 +#define XFS_ERRTAG_ALLOC_READ_AGF 10 +#define XFS_ERRTAG_IALLOC_READ_AGI 11 +#define XFS_ERRTAG_ITOBP_INOTOBP 12 +#define XFS_ERRTAG_IUNLINK 13 +#define XFS_ERRTAG_IUNLINK_REMOVE 14 +#define XFS_ERRTAG_DIR_INO_VALIDATE 15 +#define XFS_ERRTAG_BULKSTAT_READ_CHUNK 16 +#define XFS_ERRTAG_IODONE_IOERR 17 +#define XFS_ERRTAG_STRATREAD_IOERR 18 +#define XFS_ERRTAG_STRATCMPL_IOERR 19 +#define XFS_ERRTAG_DIOWRITE_IOERR 20 +#define XFS_ERRTAG_MAX 21 + +/* + * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. + */ +#define XFS_RANDOM_DEFAULT 100 +#define XFS_RANDOM_IFLUSH_1 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_2 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_3 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_4 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_5 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_6 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_DA_READ_BUF XFS_RANDOM_DEFAULT +#define XFS_RANDOM_BTREE_CHECK_LBLOCK (XFS_RANDOM_DEFAULT/4) +#define XFS_RANDOM_BTREE_CHECK_SBLOCK XFS_RANDOM_DEFAULT +#define XFS_RANDOM_ALLOC_READ_AGF XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IALLOC_READ_AGI XFS_RANDOM_DEFAULT +#define XFS_RANDOM_ITOBP_INOTOBP XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IUNLINK XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IUNLINK_REMOVE XFS_RANDOM_DEFAULT +#define XFS_RANDOM_DIR_INO_VALIDATE XFS_RANDOM_DEFAULT +#define XFS_RANDOM_BULKSTAT_READ_CHUNK XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IODONE_IOERR (XFS_RANDOM_DEFAULT/10) +#define XFS_RANDOM_STRATREAD_IOERR (XFS_RANDOM_DEFAULT/10) +#define XFS_RANDOM_STRATCMPL_IOERR (XFS_RANDOM_DEFAULT/10) +#define XFS_RANDOM_DIOWRITE_IOERR (XFS_RANDOM_DEFAULT/10) + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) +extern int xfs_error_test(int, int *, char *, int, char *, unsigned long); +void xfs_error_test_init(void); + +#define XFS_NUM_INJECT_ERROR 10 + +#ifdef __ANSI_CPP__ +#define XFS_TEST_ERROR(expr, mp, tag, rf) \ + ((expr) || \ + xfs_error_test((tag), (mp)->m_fixedfsid, #expr, __LINE__, __FILE__, \ + (rf))) +#else +#define XFS_TEST_ERROR(expr, mp, tag, rf) \ + ((expr) || \ + xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \ + (rf))) +#endif /* __ANSI_CPP__ */ + +int xfs_errortag_add(int error_tag, xfs_mount_t *mp); +int xfs_errortag_clear(int error_tag, xfs_mount_t *mp); + +int xfs_errortag_clearall(xfs_mount_t *mp); +int xfs_errortag_clearall_umount(int64_t fsid, char *fsname, + int loud); +#else +#define XFS_TEST_ERROR(expr, mp, tag, rf) (expr) +#define xfs_errortag_add(tag, mp) (ENOSYS) +#define xfs_errortag_clearall(mp) (ENOSYS) +#endif /* (DEBUG || INDUCE_IO_ERROR) */ + +/* + * XFS panic tags -- allow a call to xfs_cmn_err() be turned into + * a panic by setting xfs_panic_mask in the + * stune file. + */ +#define XFS_NO_PTAG 0LL +#define XFS_PTAG_IFLUSH 0x0000000000000001LL +#define XFS_PTAG_LOGRES 0x0000000000000002LL +#define XFS_PTAG_AILDELETE 0x0000000000000004LL + +struct xfs_mount; +/* PRINTFLIKE4 */ +void xfs_cmn_err(uint64_t panic_tag, int level, struct xfs_mount *mp, + char *fmt, ...); +/* PRINTFLIKE3 */ +void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...); + +#endif /* __XFS_ERROR_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_extfree_item.c linux-2.4.19-sgi211r3/fs/xfs/xfs_extfree_item.c --- linux-2.4.19/fs/xfs/xfs_extfree_item.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_extfree_item.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains the implementation of the xfs_efi_log_item + * and xfs_efd_log_item items. + */ + +#include + + +kmem_zone_t *xfs_efi_zone; +kmem_zone_t *xfs_efd_zone; + +STATIC void xfs_efi_item_unlock(xfs_efi_log_item_t *); +STATIC void xfs_efi_item_abort(xfs_efi_log_item_t *); +STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *); + + + +/* + * This returns the number of iovecs needed to log the given efi item. + * We only need 1 iovec for an efi item. It just logs the efi_log_format + * structure. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efi_item_size(xfs_efi_log_item_t *efip) +{ + return 1; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given efi log item. We use only 1 iovec, and we point that + * at the efi_log_format structure embedded in the efi item. + * It is at this point that we assert that all of the extent + * slots in the efi item have been filled. + */ +STATIC void +xfs_efi_item_format(xfs_efi_log_item_t *efip, + xfs_log_iovec_t *log_vector) +{ + uint size; + + ASSERT(efip->efi_next_extent == efip->efi_format.efi_nextents); + + efip->efi_format.efi_type = XFS_LI_EFI; + + size = sizeof(xfs_efi_log_format_t); + size += (efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t); + efip->efi_format.efi_size = 1; + + log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format); + log_vector->i_len = size; + ASSERT(size >= sizeof(xfs_efi_log_format_t)); +} + + +/* + * Pinning has no meaning for an efi item, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_pin(xfs_efi_log_item_t *efip) +{ + return; +} + + +/* + * While EFIs cannot really be pinned, the unpin operation is the + * last place at which the EFI is manipulated during a transaction. + * Here we coordinate with xfs_efi_cancel() to determine who gets to + * free the EFI. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_unpin(xfs_efi_log_item_t *efip) +{ + int nexts; + int size; + xfs_mount_t *mp; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + AIL_LOCK(mp, s); + if (efip->efi_flags & XFS_EFI_CANCELED) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } else { + efip->efi_flags |= XFS_EFI_COMMITTED; + AIL_UNLOCK(mp, s); + } + + return; +} + +/* + * like unpin only we have to also clear the xaction descriptor + * pointing the log item if we free the item. This routine duplicates + * unpin because efi_flags is protected by the AIL lock. Freeing + * the descriptor and then calling unpin would force us to drop the AIL + * lock which would open up a race condition. + */ +STATIC void +xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) +{ + int nexts; + int size; + xfs_mount_t *mp; + xfs_log_item_desc_t *lidp; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + AIL_LOCK(mp, s); + if (efip->efi_flags & XFS_EFI_CANCELED) { + /* + * free the xaction descriptor pointing to this item + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) efip); + xfs_trans_free_item(tp, lidp); + /* + * pull the item off the AIL. + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + /* + * now free the item itself + */ + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } else { + efip->efi_flags |= XFS_EFI_COMMITTED; + AIL_UNLOCK(mp, s); + } + + return; +} + +/* + * Efi items have no locking or pushing. However, since EFIs are + * pulled from the AIL when their corresponding EFDs are committed + * to disk, their situation is very similar to being pinned. Return + * XFS_ITEM_PINNED so that the caller will eventually flush the log. + * This should help in getting the EFI out of the AIL. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efi_item_trylock(xfs_efi_log_item_t *efip) +{ + return XFS_ITEM_PINNED; +} + +/* + * Efi items have no locking, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_unlock(xfs_efi_log_item_t *efip) +{ + if (efip->efi_item.li_flags & XFS_LI_ABORTED) + xfs_efi_item_abort(efip); + return; +} + +/* + * The EFI is logged only once and cannot be moved in the log, so + * simply return the lsn at which it's been logged. The canceled + * flag is not paid any attention here. Checking for that is delayed + * until the EFI is unpinned. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) +{ + return lsn; +} + +/* + * This is called when the transaction logging the EFI is aborted. + * Free up the EFI and return. No need to clean up the slot for + * the item in the transaction. That was done by the unpin code + * which is called prior to this routine in the abort/fs-shutdown path. + */ +STATIC void +xfs_efi_item_abort(xfs_efi_log_item_t *efip) +{ + int nexts; + int size; + + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + return; +} + +/* + * There isn't much you can do to push on an efi item. It is simply + * stuck waiting for all of its corresponding efd items to be + * committed to disk. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_push(xfs_efi_log_item_t *efip) +{ + return; +} + +/* + * The EFI dependency tracking op doesn't do squat. It can't because + * it doesn't know where the free extent is coming from. The dependency + * tracking has to be handled by the "enclosing" metadata object. For + * example, for inodes, the inode is locked throughout the extent freeing + * so the dependency should be recorded there. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_committing(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) +{ + return; +} + +/* + * This is the ops vector shared by all efi log items. + */ +struct xfs_item_ops xfs_efi_item_ops = { + .iop_size = (uint(*)(xfs_log_item_t*))xfs_efi_item_size, + .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_efi_item_format, + .iop_pin = (void(*)(xfs_log_item_t*))xfs_efi_item_pin, + .iop_unpin = (void(*)(xfs_log_item_t*))xfs_efi_item_unpin, + .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *)) + xfs_efi_item_unpin_remove, + .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efi_item_trylock, + .iop_unlock = (void(*)(xfs_log_item_t*))xfs_efi_item_unlock, + .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efi_item_committed, + .iop_push = (void(*)(xfs_log_item_t*))xfs_efi_item_push, + .iop_abort = (void(*)(xfs_log_item_t*))xfs_efi_item_abort, + .iop_pushbuf = NULL, + .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efi_item_committing +}; + + +/* + * Allocate and initialize an efi item with the given number of extents. + */ +xfs_efi_log_item_t * +xfs_efi_init(xfs_mount_t *mp, + uint nextents) + +{ + xfs_efi_log_item_t *efip; + uint size; + + ASSERT(nextents > 0); + if (nextents > XFS_EFI_MAX_FAST_EXTENTS) { + size = (uint)(sizeof(xfs_efi_log_item_t) + + ((nextents - 1) * sizeof(xfs_extent_t))); + efip = (xfs_efi_log_item_t*)kmem_zalloc(size, KM_SLEEP); + } else { + efip = (xfs_efi_log_item_t*)kmem_zone_zalloc(xfs_efi_zone, + KM_SLEEP); + } + + efip->efi_item.li_type = XFS_LI_EFI; + efip->efi_item.li_ops = &xfs_efi_item_ops; + efip->efi_item.li_mountp = mp; + efip->efi_format.efi_nextents = nextents; + efip->efi_format.efi_id = (__psint_t)(void*)efip; + + return (efip); +} + +/* + * This is called by the efd item code below to release references to + * the given efi item. Each efd calls this with the number of + * extents that it has logged, and when the sum of these reaches + * the total number of extents logged by this efi item we can free + * the efi item. + * + * Freeing the efi item requires that we remove it from the AIL. + * We'll use the AIL lock to protect our counters as well as + * the removal from the AIL. + */ +void +xfs_efi_release(xfs_efi_log_item_t *efip, + uint nextents) +{ + xfs_mount_t *mp; + int extents_left; + uint size; + int nexts; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + ASSERT(efip->efi_next_extent > 0); + ASSERT(efip->efi_flags & XFS_EFI_COMMITTED); + + AIL_LOCK(mp, s); + ASSERT(efip->efi_next_extent >= nextents); + efip->efi_next_extent -= nextents; + extents_left = efip->efi_next_extent; + if (extents_left == 0) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + } else { + AIL_UNLOCK(mp, s); + } + + if (extents_left == 0) { + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } +} + +/* + * This is called when the transaction that should be committing the + * EFD corresponding to the given EFI is aborted. The committed and + * canceled flags are used to coordinate the freeing of the EFI and + * the references by the transaction that committed it. + */ +STATIC void +xfs_efi_cancel( + xfs_efi_log_item_t *efip) +{ + int nexts; + int size; + xfs_mount_t *mp; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + AIL_LOCK(mp, s); + if (efip->efi_flags & XFS_EFI_COMMITTED) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } else { + efip->efi_flags |= XFS_EFI_CANCELED; + AIL_UNLOCK(mp, s); + } + + return; +} + + + + + +/* + * This returns the number of iovecs needed to log the given efd item. + * We only need 1 iovec for an efd item. It just logs the efd_log_format + * structure. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efd_item_size(xfs_efd_log_item_t *efdp) +{ + return 1; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given efd log item. We use only 1 iovec, and we point that + * at the efd_log_format structure embedded in the efd item. + * It is at this point that we assert that all of the extent + * slots in the efd item have been filled. + */ +STATIC void +xfs_efd_item_format(xfs_efd_log_item_t *efdp, + xfs_log_iovec_t *log_vector) +{ + uint size; + + ASSERT(efdp->efd_next_extent == efdp->efd_format.efd_nextents); + + efdp->efd_format.efd_type = XFS_LI_EFD; + + size = sizeof(xfs_efd_log_format_t); + size += (efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t); + efdp->efd_format.efd_size = 1; + + log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format); + log_vector->i_len = size; + ASSERT(size >= sizeof(xfs_efd_log_format_t)); +} + + +/* + * Pinning has no meaning for an efd item, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_pin(xfs_efd_log_item_t *efdp) +{ + return; +} + + +/* + * Since pinning has no meaning for an efd item, unpinning does + * not either. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_unpin(xfs_efd_log_item_t *efdp) +{ + return; +} + +/*ARGSUSED*/ +STATIC void +xfs_efd_item_unpin_remove(xfs_efd_log_item_t *efdp, xfs_trans_t *tp) +{ + return; +} + +/* + * Efd items have no locking, so just return success. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efd_item_trylock(xfs_efd_log_item_t *efdp) +{ + return XFS_ITEM_LOCKED; +} + +/* + * Efd items have no locking or pushing, so return failure + * so that the caller doesn't bother with us. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_unlock(xfs_efd_log_item_t *efdp) +{ + if (efdp->efd_item.li_flags & XFS_LI_ABORTED) + xfs_efd_item_abort(efdp); + return; +} + +/* + * When the efd item is committed to disk, all we need to do + * is delete our reference to our partner efi item and then + * free ourselves. Since we're freeing ourselves we must + * return -1 to keep the transaction code from further referencing + * this item. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) +{ + uint size; + int nexts; + + /* + * If we got a log I/O error, it's always the case that the LR with the + * EFI got unpinned and freed before the EFD got aborted. + */ + if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) + xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents); + + nexts = efdp->efd_format.efd_nextents; + if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efd_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efdp, size); + } else { + kmem_zone_free(xfs_efd_zone, efdp); + } + + return (xfs_lsn_t)-1; +} + +/* + * The transaction of which this EFD is a part has been aborted. + * Inform its companion EFI of this fact and then clean up after + * ourselves. No need to clean up the slot for the item in the + * transaction. That was done by the unpin code which is called + * prior to this routine in the abort/fs-shutdown path. + */ +STATIC void +xfs_efd_item_abort(xfs_efd_log_item_t *efdp) +{ + int nexts; + int size; + + /* + * If we got a log I/O error, it's always the case that the LR with the + * EFI got unpinned and freed before the EFD got aborted. So don't + * reference the EFI at all in that case. + */ + if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) + xfs_efi_cancel(efdp->efd_efip); + + nexts = efdp->efd_format.efd_nextents; + if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efd_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efdp, size); + } else { + kmem_zone_free(xfs_efd_zone, efdp); + } + return; +} + +/* + * There isn't much you can do to push on an efd item. It is simply + * stuck waiting for the log to be flushed to disk. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_push(xfs_efd_log_item_t *efdp) +{ + return; +} + +/* + * The EFD dependency tracking op doesn't do squat. It can't because + * it doesn't know where the free extent is coming from. The dependency + * tracking has to be handled by the "enclosing" metadata object. For + * example, for inodes, the inode is locked throughout the extent freeing + * so the dependency should be recorded there. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_committing(xfs_efd_log_item_t *efip, xfs_lsn_t lsn) +{ + return; +} + +/* + * This is the ops vector shared by all efd log items. + */ +struct xfs_item_ops xfs_efd_item_ops = { + .iop_size = (uint(*)(xfs_log_item_t*))xfs_efd_item_size, + .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_efd_item_format, + .iop_pin = (void(*)(xfs_log_item_t*))xfs_efd_item_pin, + .iop_unpin = (void(*)(xfs_log_item_t*))xfs_efd_item_unpin, + .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*)) + xfs_efd_item_unpin_remove, + .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efd_item_trylock, + .iop_unlock = (void(*)(xfs_log_item_t*))xfs_efd_item_unlock, + .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efd_item_committed, + .iop_push = (void(*)(xfs_log_item_t*))xfs_efd_item_push, + .iop_abort = (void(*)(xfs_log_item_t*))xfs_efd_item_abort, + .iop_pushbuf = NULL, + .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efd_item_committing +}; + + +/* + * Allocate and initialize an efd item with the given number of extents. + */ +xfs_efd_log_item_t * +xfs_efd_init(xfs_mount_t *mp, + xfs_efi_log_item_t *efip, + uint nextents) + +{ + xfs_efd_log_item_t *efdp; + uint size; + + ASSERT(nextents > 0); + if (nextents > XFS_EFD_MAX_FAST_EXTENTS) { + size = (uint)(sizeof(xfs_efd_log_item_t) + + ((nextents - 1) * sizeof(xfs_extent_t))); + efdp = (xfs_efd_log_item_t*)kmem_zalloc(size, KM_SLEEP); + } else { + efdp = (xfs_efd_log_item_t*)kmem_zone_zalloc(xfs_efd_zone, + KM_SLEEP); + } + + efdp->efd_item.li_type = XFS_LI_EFD; + efdp->efd_item.li_ops = &xfs_efd_item_ops; + efdp->efd_item.li_mountp = mp; + efdp->efd_efip = efip; + efdp->efd_format.efd_nextents = nextents; + efdp->efd_format.efd_efi_id = efip->efi_format.efi_id; + + return (efdp); +} diff -Nur linux-2.4.19/fs/xfs/xfs_extfree_item.h linux-2.4.19-sgi211r3/fs/xfs/xfs_extfree_item.h --- linux-2.4.19/fs/xfs/xfs_extfree_item.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_extfree_item.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_EXTFREE_ITEM_H__ +#define __XFS_EXTFREE_ITEM_H__ + +struct xfs_mount; +struct kmem_zone; + +typedef struct xfs_extent { + xfs_dfsbno_t ext_start; + xfs_extlen_t ext_len; +} xfs_extent_t; + +/* + * This is the structure used to lay out an efi log item in the + * log. The efi_extents field is a variable size array whose + * size is given by efi_nextents. + */ +typedef struct xfs_efi_log_format { + unsigned short efi_type; /* efi log item type */ + unsigned short efi_size; /* size of this item */ + uint efi_nextents; /* # extents to free */ + __uint64_t efi_id; /* efi identifier */ + xfs_extent_t efi_extents[1]; /* array of extents to free */ +} xfs_efi_log_format_t; + +/* + * This is the structure used to lay out an efd log item in the + * log. The efd_extents array is a variable size array whose + * size is given by efd_nextents; + */ +typedef struct xfs_efd_log_format { + unsigned short efd_type; /* efd log item type */ + unsigned short efd_size; /* size of this item */ + uint efd_nextents; /* # of extents freed */ + __uint64_t efd_efi_id; /* id of corresponding efi */ + xfs_extent_t efd_extents[1]; /* array of extents freed */ +} xfs_efd_log_format_t; + + +#ifdef __KERNEL__ + +/* + * Max number of extents in fast allocation path. + */ +#define XFS_EFI_MAX_FAST_EXTENTS 16 + +/* + * Define EFI flags. + */ +#define XFS_EFI_RECOVERED 0x1 +#define XFS_EFI_COMMITTED 0x2 +#define XFS_EFI_CANCELED 0x4 + +/* + * This is the "extent free intention" log item. It is used + * to log the fact that some extents need to be free. It is + * used in conjunction with the "extent free done" log item + * described below. + */ +typedef struct xfs_efi_log_item { + xfs_log_item_t efi_item; + uint efi_flags; /* misc flags */ + uint efi_next_extent; + xfs_efi_log_format_t efi_format; +} xfs_efi_log_item_t; + +/* + * This is the "extent free done" log item. It is used to log + * the fact that some extents earlier mentioned in an efi item + * have been freed. + */ +typedef struct xfs_efd_log_item { + xfs_log_item_t efd_item; + xfs_efi_log_item_t *efd_efip; + uint efd_next_extent; + xfs_efd_log_format_t efd_format; +} xfs_efd_log_item_t; + +/* + * Max number of extents in fast allocation path. + */ +#define XFS_EFD_MAX_FAST_EXTENTS 16 + +extern struct kmem_zone *xfs_efi_zone; +extern struct kmem_zone *xfs_efd_zone; + +xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); +xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, + uint); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_EXTFREE_ITEM_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_fs.h linux-2.4.19-sgi211r3/fs/xfs/xfs_fs.h --- linux-2.4.19/fs/xfs/xfs_fs.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_fs.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,510 @@ +/* + * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + * USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _LINUX_XFS_FS_H +#define _LINUX_XFS_FS_H + +#include +#include + + +/* + * SGI's XFS filesystem's major stuff (constants, structures) + */ + +#define XFS_NAME "xfs" + +/* + * Direct I/O attribute record used with XFS_IOC_DIOINFO + * d_miniosz is the min xfer size, xfer size multiple and file seek offset + * alignment. + */ +struct dioattr { + __u32 d_mem; /* data buffer memory alignment */ + __u32 d_miniosz; /* min xfer size */ + __u32 d_maxiosz; /* max xfer size */ +}; + +/* + * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR. + */ +struct fsxattr { + __u32 fsx_xflags; /* xflags field value (get/set) */ + __u32 fsx_extsize; /* extsize field value (get/set)*/ + __u32 fsx_nextents; /* nextents field value (get) */ + unsigned char fsx_pad[16]; +}; + +/* + * Flags for the bs_xflags/fsx_xflags field + * There should be a one-to-one correspondence between these flags and the + * XFS_DIFLAG_s. + */ +#define XFS_XFLAG_REALTIME 0x00000001 +#define XFS_XFLAG_PREALLOC 0x00000002 +#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ +#define XFS_XFLAG_ALL \ + ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_HASATTR ) + + +/* + * Structure for XFS_IOC_GETBMAP. + * On input, fill in bmv_offset and bmv_length of the first structure + * to indicate the area of interest in the file, and bmv_entry with the + * number of array elements given. The first structure is updated on + * return to give the offset and length for the next call. + */ +struct getbmap { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output) */ +}; + +/* + * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries + * are used exactly as in the getbmap structure. The getbmapx structure + * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field + * is only used for the first structure. It contains input flags + * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled + * in by the XFS_IOC_GETBMAPX command for each returned structure after + * the first. + */ +struct getbmapx { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output). */ + __s32 bmv_iflags; /* input flags (1st structure) */ + __s32 bmv_oflags; /* output flags (after 1st structure)*/ + __s32 bmv_unused1; /* future use */ + __s32 bmv_unused2; /* future use */ +}; + +/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */ +#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ +#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ +#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ +#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC) +#ifdef __KERNEL__ +#define BMV_IF_EXTENDED 0x40000000 /* getpmapx if set */ +#endif + +/* bmv_oflags values - returned for for each non-header segment */ +#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ + +/* Convert getbmap <-> getbmapx - move fields from p1 to p2. */ +#define GETBMAP_CONVERT(p1,p2) { \ + p2.bmv_offset = p1.bmv_offset; \ + p2.bmv_block = p1.bmv_block; \ + p2.bmv_length = p1.bmv_length; \ + p2.bmv_count = p1.bmv_count; \ + p2.bmv_entries = p1.bmv_entries; } + + +/* + * Structure for XFS_IOC_FSSETDM. + * For use by backup and restore programs to set the XFS on-disk inode + * fields di_dmevmask and di_dmstate. These must be set to exactly and + * only values previously obtained via xfs_bulkstat! (Specifically the + * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) + */ +struct fsdmidata { + __u32 fsd_dmevmask; /* corresponds to di_dmevmask */ + __u16 fsd_padding; + __u16 fsd_dmstate; /* corresponds to di_dmstate */ +}; + +/* + * File segment locking set data type for 64 bit access. + * Also used for all the RESV/FREE interfaces. + */ +typedef struct xfs_flock64 { + __s16 l_type; + __s16 l_whence; + __s64 l_start; + __s64 l_len; /* len == 0 means until end of file */ + __s32 l_sysid; + pid_t l_pid; + __s32 l_pad[4]; /* reserve area */ +} xfs_flock64_t; + +/* + * Output for XFS_IOC_FSGEOMETRY_V1 + */ +typedef struct xfs_fsop_geom_v1 { + __u32 blocksize; /* filesystem (data) block size */ + __u32 rtextsize; /* realtime extent size */ + __u32 agblocks; /* fsblocks in an AG */ + __u32 agcount; /* number of allocation groups */ + __u32 logblocks; /* fsblocks in the log */ + __u32 sectsize; /* (data) sector size, bytes */ + __u32 inodesize; /* inode size in bytes */ + __u32 imaxpct; /* max allowed inode space(%) */ + __u64 datablocks; /* fsblocks in data subvolume */ + __u64 rtblocks; /* fsblocks in realtime subvol */ + __u64 rtextents; /* rt extents in realtime subvol*/ + __u64 logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + __u32 sunit; /* stripe unit, fsblocks */ + __u32 swidth; /* stripe width, fsblocks */ + __s32 version; /* structure version */ + __u32 flags; /* superblock version flags */ + __u32 logsectsize; /* log sector size, bytes */ + __u32 rtsectsize; /* realtime sector size, bytes */ + __u32 dirblocksize; /* directory block size, bytes */ +} xfs_fsop_geom_v1_t; + +/* + * Output for XFS_IOC_FSGEOMETRY + */ +typedef struct xfs_fsop_geom { + __u32 blocksize; /* filesystem (data) block size */ + __u32 rtextsize; /* realtime extent size */ + __u32 agblocks; /* fsblocks in an AG */ + __u32 agcount; /* number of allocation groups */ + __u32 logblocks; /* fsblocks in the log */ + __u32 sectsize; /* (data) sector size, bytes */ + __u32 inodesize; /* inode size in bytes */ + __u32 imaxpct; /* max allowed inode space(%) */ + __u64 datablocks; /* fsblocks in data subvolume */ + __u64 rtblocks; /* fsblocks in realtime subvol */ + __u64 rtextents; /* rt extents in realtime subvol*/ + __u64 logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + __u32 sunit; /* stripe unit, fsblocks */ + __u32 swidth; /* stripe width, fsblocks */ + __s32 version; /* structure version */ + __u32 flags; /* superblock version flags */ + __u32 logsectsize; /* log sector size, bytes */ + __u32 rtsectsize; /* realtime sector size, bytes */ + __u32 dirblocksize; /* directory block size, bytes */ + __u32 logsunit; /* log stripe unit, bytes */ +} xfs_fsop_geom_t; + +/* Output for XFS_FS_COUNTS */ +typedef struct xfs_fsop_counts { + __u64 freedata; /* free data section blocks */ + __u64 freertx; /* free rt extents */ + __u64 freeino; /* free inodes */ + __u64 allocino; /* total allocated inodes */ +} xfs_fsop_counts_t; + +/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ +typedef struct xfs_fsop_resblks { + __u64 resblks; + __u64 resblks_avail; +} xfs_fsop_resblks_t; + +#define XFS_FSOP_GEOM_VERSION 0 + +#define XFS_FSOP_GEOM_FLAGS_ATTR 0x01 /* attributes in use */ +#define XFS_FSOP_GEOM_FLAGS_NLINK 0x02 /* 32-bit nlink values */ +#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x04 /* quotas enabled */ +#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x08 /* inode alignment */ +#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x10 /* large data alignment */ +#define XFS_FSOP_GEOM_FLAGS_SHARED 0x20 /* read-only shared */ +#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x40 /* special extent flag */ +#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x80 /* directory version 2 */ +#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x100 /* log format version 2 */ + + +/* + * Minimum and maximum sizes need for growth checks + */ +#define XFS_MIN_AG_BLOCKS 64 +#define XFS_MIN_LOG_BLOCKS 512 +#define XFS_MAX_LOG_BLOCKS (64 * 1024) +#define XFS_MIN_LOG_BYTES (256 * 1024) +#define XFS_MAX_LOG_BYTES (128 * 1024 * 1024) + +/* + * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT + */ +typedef struct xfs_growfs_data { + __u64 newblocks; /* new data subvol size, fsblocks */ + __u32 imaxpct; /* new inode space percentage limit */ +} xfs_growfs_data_t; + +typedef struct xfs_growfs_log { + __u32 newblocks; /* new log size, fsblocks */ + __u32 isint; /* 1 if new log is internal */ +} xfs_growfs_log_t; + +typedef struct xfs_growfs_rt { + __u64 newblocks; /* new realtime size, fsblocks */ + __u32 extsize; /* new realtime extent size, fsblocks */ +} xfs_growfs_rt_t; + + +/* + * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE + */ +typedef struct xfs_bstime { + time_t tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} xfs_bstime_t; + +typedef struct xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + xfs_bstime_t bs_atime; /* access time */ + xfs_bstime_t bs_mtime; /* modify time */ + xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid; /* project id */ + unsigned char bs_pad[14]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} xfs_bstat_t; + +/* + * The user-level BulkStat Request interface structure. + */ +typedef struct xfs_fsop_bulkreq { + __u64 *lastip; /* last inode # pointer */ + __s32 icount; /* count of entries in buffer */ + void *ubuffer; /* user buffer for inode desc. */ + __s32 *ocount; /* output count pointer */ +} xfs_fsop_bulkreq_t; + + +/* + * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS). + */ +typedef struct xfs_inogrp { + __u64 xi_startino; /* starting inode number */ + __s32 xi_alloccount; /* # bits set in allocmask */ + __u64 xi_allocmask; /* mask of allocated inodes */ +} xfs_inogrp_t; + + +/* + * Error injection. + */ +typedef struct xfs_error_injection { + __s32 fd; + __s32 errtag; +} xfs_error_injection_t; + + +/* + * The user-level Handle Request interface structure. + */ +typedef struct xfs_fsop_handlereq { + __u32 fd; /* fd for FD_TO_HANDLE */ + void *path; /* user pathname */ + __u32 oflags; /* open flags */ + void *ihandle; /* user supplied handle */ + __u32 ihandlen; /* user supplied length */ + void *ohandle; /* user buffer for handle */ + __u32 *ohandlen; /* user buffer length */ +} xfs_fsop_handlereq_t; + +/* + * Compound structures for passing args through Handle Request interfaces + * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle + * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and + * XFS_IOC_ATTRMULTI_BY_HANDLE + */ + +typedef struct xfs_fsop_setdm_handlereq { + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + struct fsdmidata *data; /* DMAPI data to set */ +} xfs_fsop_setdm_handlereq_t; + +typedef struct xfs_attrlist_cursor { + __u32 opaque[4]; +} xfs_attrlist_cursor_t; + +typedef struct xfs_fsop_attrlist_handlereq { + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ + __u32 flags; /* flags, use ROOT/USER names */ + __u32 buflen; /* length of buffer supplied */ + void *buffer; /* attrlist data to return */ +} xfs_fsop_attrlist_handlereq_t; + +typedef struct xfs_attr_multiop { + __u32 am_opcode; + __s32 am_error; + void *am_attrname; + void *am_attrvalue; + __u32 am_length; + __u32 am_flags; +} xfs_attr_multiop_t; + +typedef struct xfs_fsop_attrmulti_handlereq { + struct xfs_fsop_handlereq hreq; /* handle interface structure */ + __u32 opcount; /* count of following multiop */ + struct xfs_attr_multiop *ops; /* attr_multi data to get/set */ +} xfs_fsop_attrmulti_handlereq_t; + +/* + * File system identifier. Should be unique (at least per machine). + */ +typedef struct { + __u32 val[2]; /* file system id type */ +} xfs_fsid_t; + +/* + * File identifier. Should be unique per filesystem on a single machine. + * This is typically called by a stateless file server in order to generate + * "file handles". + */ +#define MAXFIDSZ 46 +typedef struct fid { + __u16 fid_len; /* length of data in bytes */ + unsigned char fid_data[MAXFIDSZ]; /* data (variable length) */ +} fid_t; + +typedef struct xfs_fid { + __u16 xfs_fid_len; /* length of remainder */ + __u16 xfs_fid_pad; + __u32 xfs_fid_gen; /* generation number */ + __u64 xfs_fid_ino; /* 64 bits inode number */ +} xfs_fid_t; + +typedef struct xfs_fid2 { + __u16 fid_len; /* length of remainder */ + __u16 fid_pad; /* padding, must be zero */ + __u32 fid_gen; /* generation number */ + __u64 fid_ino; /* inode number */ +} xfs_fid2_t; + +typedef struct xfs_handle { + union { + __s64 align; /* force alignment of ha_fid */ + xfs_fsid_t _ha_fsid; /* unique file system identifier */ + } ha_u; + xfs_fid_t ha_fid; /* file system specific file ID */ +} xfs_handle_t; +#define ha_fsid ha_u._ha_fsid + +#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.xfs_fid_pad \ + - (char *) &(handle)) \ + + (handle).ha_fid.xfs_fid_len) + +#define XFS_HANDLE_CMP(h1, h2) bcmp(h1, h2, sizeof (xfs_handle_t)) + +#define FSHSIZE sizeof (fsid_t) + + +/* + * ioctl commands that replace IRIX fcntl()'s + * For 'documentation' purposed more than anything else, + * the "cmd #" field reflects the IRIX fcntl number. + */ +#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) +#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) +#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) +#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) +#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) +#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) +#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) +#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) +#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) +#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) +#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) +#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) +#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) +#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) +#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) +/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ +/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ +#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) + +/* + * ioctl commands that replace IRIX syssgi()'s + */ +#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1) +#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) +#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) +#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) +#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) +#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) +#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) +#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) +#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) +#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log) +#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt) +#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) +#define XFS_IOC_SET_RESBLKS _IOR ('X', 114, struct xfs_fsop_resblks) +#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) +#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection) +#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection) +/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */ +#define XFS_IOC_FREEZE _IOWR('X', 119, int) +#define XFS_IOC_THAW _IOWR('X', 120, int) +#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq) +#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) +#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) +#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) +/* XFS_IOC_GETFSUUID ---------- deprecated 140 */ + + +/* + * Block I/O parameterization. A basic block (BB) is the lowest size of + * filesystem allocation, and must equal 512. Length units given to bio + * routines are in BB's. + */ +#define BBSHIFT 9 +#define BBSIZE (1<> BBSHIFT) +#define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) +#define BBTOB(bbs) ((bbs) << BBSHIFT) +#define OFFTOBB(bytes) (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT) +#define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) +#define BBTOOFF(bbs) ((__u64)(bbs) << BBSHIFT) + +#define SEEKLIMIT32 0x7fffffff +#define BBSEEKLIMIT32 BTOBBT(SEEKLIMIT32) +#define SEEKLIMIT 0x7fffffffffffffffLL +#define BBSEEKLIMIT OFFTOBBT(SEEKLIMIT) + +#endif /* _LINUX_XFS_FS_H */ diff -Nur linux-2.4.19/fs/xfs/xfs_fsops.c linux-2.4.19-sgi211r3/fs/xfs/xfs_fsops.c --- linux-2.4.19/fs/xfs/xfs_fsops.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_fsops.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * File system operations + */ + +int +xfs_fs_geometry( + xfs_mount_t *mp, + xfs_fsop_geom_t *geo, + int new_version) +{ + geo->blocksize = mp->m_sb.sb_blocksize; + geo->rtextsize = mp->m_sb.sb_rextsize; + geo->agblocks = mp->m_sb.sb_agblocks; + geo->agcount = mp->m_sb.sb_agcount; + geo->logblocks = mp->m_sb.sb_logblocks; + geo->sectsize = mp->m_sb.sb_sectsize; + geo->inodesize = mp->m_sb.sb_inodesize; + geo->imaxpct = mp->m_sb.sb_imax_pct; + geo->datablocks = mp->m_sb.sb_dblocks; + geo->rtblocks = mp->m_sb.sb_rblocks; + geo->rtextents = mp->m_sb.sb_rextents; + geo->logstart = mp->m_sb.sb_logstart; + ASSERT(sizeof(geo->uuid)==sizeof(mp->m_sb.sb_uuid)); + memcpy(geo->uuid, &mp->m_sb.sb_uuid, sizeof(mp->m_sb.sb_uuid)); + if (new_version >= 2) { + geo->sunit = mp->m_sb.sb_unit; + geo->swidth = mp->m_sb.sb_width; + } + if (new_version >= 3) { + geo->version = XFS_FSOP_GEOM_VERSION; + geo->flags = + (XFS_SB_VERSION_HASATTR(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_ATTR : 0) | + (XFS_SB_VERSION_HASNLINK(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_NLINK : 0) | + (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_QUOTA : 0) | + (XFS_SB_VERSION_HASALIGN(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_IALIGN : 0) | + (XFS_SB_VERSION_HASDALIGN(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_DALIGN : 0) | + (XFS_SB_VERSION_HASSHARED(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_SHARED : 0) | + (XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) | + (XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_DIRV2 : 0); + geo->logsectsize = mp->m_sb.sb_sectsize; /* XXX */ + geo->rtsectsize = mp->m_sb.sb_sectsize; /* XXX */ + geo->dirblocksize = mp->m_dirblksize; + } + if (new_version >= 4) { + geo->flags |= + (XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_LOGV2 : 0); + geo->logsunit = mp->m_sb.sb_logsunit; + } + return 0; +} + +static int +xfs_growfs_data_private( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_data_t *in) /* growfs data input struct */ +{ + xfs_agf_t *agf; + xfs_agi_t *agi; + xfs_agnumber_t agno; + xfs_extlen_t agsize; + xfs_extlen_t tmpsize; + xfs_alloc_rec_t *arec; + xfs_btree_sblock_t *block; + xfs_buf_t *bp; + int bsize; + int bucket; + xfs_daddr_t disk_addr; + int dpct; + int error; + xfs_agnumber_t nagcount; + xfs_rfsblock_t nb, nb_mod; + xfs_rfsblock_t new; + xfs_rfsblock_t nfree; + xfs_agnumber_t oagcount; + int pct; + xfs_sb_t *sbp; + int sectbb; + xfs_trans_t *tp; + + nb = in->newblocks; + pct = in->imaxpct; + if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100) + return XFS_ERROR(EINVAL); + dpct = pct - mp->m_sb.sb_imax_pct; + error = xfs_read_buf(mp, mp->m_ddev_targp, XFS_FSB_TO_BB(mp, nb) - 1, 1, + 0, &bp); + if (error) + return error; + ASSERT(bp); + xfs_buf_relse(bp); + + new = nb; /* use new as a temporary here */ + nb_mod = do_div(new, mp->m_sb.sb_agblocks); + nagcount = new + (nb_mod != 0); + if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) { + nagcount--; + nb = nagcount * mp->m_sb.sb_agblocks; + if (nb < mp->m_sb.sb_dblocks) + return XFS_ERROR(EINVAL); + } + new = in->newblocks - mp->m_sb.sb_dblocks; + oagcount = mp->m_sb.sb_agcount; + if (nagcount > oagcount) { + down_write(&mp->m_peraglock); + mp->m_perag = kmem_realloc(mp->m_perag, + sizeof(xfs_perag_t) * nagcount, + sizeof(xfs_perag_t) * oagcount, + KM_SLEEP); + bzero(&mp->m_perag[oagcount], + (nagcount - oagcount) * sizeof(xfs_perag_t)); + mp->m_flags |= XFS_MOUNT_32BITINODES; + xfs_initialize_perag(mp, nagcount); + up_write(&mp->m_peraglock); + } + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); + if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp), + XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + return error; + } + /* new ag's */ + sectbb = BTOBB(mp->m_sb.sb_sectsize); + bsize = mp->m_sb.sb_blocksize; + + nfree = 0; + for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { + /* + * AG freelist header block + */ + disk_addr = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR); + bp = xfs_buf_get(mp->m_ddev_targp, + disk_addr, + sectbb, 0); + agf = XFS_BUF_TO_AGF(bp); + bzero(agf, mp->m_sb.sb_sectsize); + INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC); + INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION); + INT_SET(agf->agf_seqno, ARCH_CONVERT, agno); + if (agno == nagcount - 1) + agsize = + nb - + (agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks); + else + agsize = mp->m_sb.sb_agblocks; + INT_SET(agf->agf_length, ARCH_CONVERT, agsize); + INT_SET(agf->agf_roots[XFS_BTNUM_BNOi], ARCH_CONVERT, XFS_BNO_BLOCK(mp)); + INT_SET(agf->agf_roots[XFS_BTNUM_CNTi], ARCH_CONVERT, XFS_CNT_BLOCK(mp)); + INT_SET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT, 1); + INT_SET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT, 1); + INT_ZERO(agf->agf_flfirst, ARCH_CONVERT); + INT_SET(agf->agf_fllast, ARCH_CONVERT, XFS_AGFL_SIZE - 1); + INT_ZERO(agf->agf_flcount, ARCH_CONVERT); + tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp); + INT_SET(agf->agf_freeblks, ARCH_CONVERT, tmpsize); + INT_SET(agf->agf_longest, ARCH_CONVERT, tmpsize); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * AG inode header block + */ + disk_addr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + bp = xfs_buf_get(mp->m_ddev_targp, + disk_addr, + sectbb, 0); + agi = XFS_BUF_TO_AGI(bp); + bzero(agi, mp->m_sb.sb_sectsize); + INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC); + INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION); + INT_SET(agi->agi_seqno, ARCH_CONVERT, agno); + INT_SET(agi->agi_length, ARCH_CONVERT, agsize); + INT_ZERO(agi->agi_count, ARCH_CONVERT); + INT_SET(agi->agi_root, ARCH_CONVERT, XFS_IBT_BLOCK(mp)); + INT_SET(agi->agi_level, ARCH_CONVERT, 1); + INT_ZERO(agi->agi_freecount, ARCH_CONVERT); + INT_SET(agi->agi_newino, ARCH_CONVERT, NULLAGINO); + INT_SET(agi->agi_dirino, ARCH_CONVERT, NULLAGINO); + for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) + INT_SET(agi->agi_unlinked[bucket], ARCH_CONVERT, NULLAGINO); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * BNO btree root block + */ + disk_addr = XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)); + bp = xfs_buf_get(mp->m_ddev_targp, + disk_addr, + BTOBB(bsize), 0); + block = XFS_BUF_TO_SBLOCK(bp); + bzero(block, bsize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTB_MAGIC); + INT_ZERO(block->bb_level, ARCH_CONVERT); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + arec = XFS_BTREE_REC_ADDR(bsize, xfs_alloc, block, 1, + mp->m_alloc_mxr[0]); + INT_SET(arec->ar_startblock, ARCH_CONVERT, XFS_PREALLOC_BLOCKS(mp)); + INT_SET(arec->ar_blockcount, ARCH_CONVERT, agsize - INT_GET(arec->ar_startblock, ARCH_CONVERT)); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * CNT btree root block + */ + disk_addr = XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)); + bp = xfs_buf_get(mp->m_ddev_targp, + disk_addr, + BTOBB(bsize), 0); + block = XFS_BUF_TO_SBLOCK(bp); + bzero(block, bsize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTC_MAGIC); + INT_ZERO(block->bb_level, ARCH_CONVERT); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + arec = XFS_BTREE_REC_ADDR(bsize, xfs_alloc, block, 1, + mp->m_alloc_mxr[0]); + INT_SET(arec->ar_startblock, ARCH_CONVERT, XFS_PREALLOC_BLOCKS(mp)); + INT_SET(arec->ar_blockcount, ARCH_CONVERT, agsize - INT_GET(arec->ar_startblock, ARCH_CONVERT)); + nfree += INT_GET(arec->ar_blockcount, ARCH_CONVERT); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * INO btree root block + */ + disk_addr = XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)); + bp = xfs_buf_get(mp->m_ddev_targp, + disk_addr, + BTOBB(bsize), 0); + block = XFS_BUF_TO_SBLOCK(bp); + bzero(block, bsize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC); + INT_ZERO(block->bb_level, ARCH_CONVERT); + INT_ZERO(block->bb_numrecs, ARCH_CONVERT); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + } + xfs_trans_agblocks_delta(tp, nfree); + /* + * There are new blocks in the old last a.g. + */ + if (new) { + /* + * Change the agi length. + */ + error = xfs_ialloc_read_agi(mp, tp, agno, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agi = XFS_BUF_TO_AGI(bp); + INT_MOD(agi->agi_length, ARCH_CONVERT, new); + ASSERT(nagcount == oagcount + || INT_GET(agi->agi_length, ARCH_CONVERT) == mp->m_sb.sb_agblocks); + xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); + /* + * Change agf length. + */ + error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agf = XFS_BUF_TO_AGF(bp); + INT_MOD(agf->agf_length, ARCH_CONVERT, new); + ASSERT(INT_GET(agf->agf_length, ARCH_CONVERT) == + INT_GET(agi->agi_length, ARCH_CONVERT)); + /* + * Free the new space. + */ + error = xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, agno, + INT_GET(agf->agf_length, ARCH_CONVERT) - new), new); + if (error) { + goto error0; + } + } + if (nagcount > oagcount) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); + if (nb > mp->m_sb.sb_dblocks) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, + nb - mp->m_sb.sb_dblocks); + if (nfree) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree); + if (dpct) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); + error = xfs_trans_commit(tp, 0, NULL); + if (error) { + return error; + } + if (mp->m_sb.sb_imax_pct) { + __uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; + do_div(icount, 100); + mp->m_maxicount = icount << mp->m_sb.sb_inopblog; + } else + mp->m_maxicount = 0; + for (agno = 1; agno < nagcount; agno++) { + error = xfs_read_buf(mp, mp->m_ddev_targp, + XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), + sectbb, 0, &bp); + if (error) { + xfs_fs_cmn_err(CE_WARN, mp, + "error %d reading secondary superblock for ag %d", + error, agno); + break; + } + sbp = XFS_BUF_TO_SBP(bp); + xfs_xlatesb(sbp, &mp->m_sb, -1, ARCH_CONVERT, XFS_SB_ALL_BITS); + /* + * If we get an error writing out the alternate superblocks, + * just issue a warning and continue. The real work is + * already done and committed. + */ + if (!(error = xfs_bwrite(mp, bp))) { + continue; + } else { + xfs_fs_cmn_err(CE_WARN, mp, + "write error %d updating secondary superblock for ag %d", + error, agno); + break; /* no point in continuing */ + } + } + return 0; + + error0: + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return error; +} + +static int +xfs_growfs_log_private( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_log_t *in) /* growfs log input struct */ +{ + xfs_extlen_t nb; + + nb = in->newblocks; + if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES)) + return XFS_ERROR(EINVAL); + if (nb == mp->m_sb.sb_logblocks && + in->isint == (mp->m_sb.sb_logstart != 0)) + return XFS_ERROR(EINVAL); + /* + * Moving the log is hard, need new interfaces to sync + * the log first, hold off all activity while moving it. + * Can have shorter or longer log in the same space, + * or transform internal to external log or vice versa. + */ + return XFS_ERROR(ENOSYS); +} + +/* + * protected versions of growfs function acquire and release locks on the mount + * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG, + * XFS_IOC_FSGROWFSRT + */ + + +int +xfs_growfs_data( + xfs_mount_t *mp, + xfs_growfs_data_t *in) +{ + int error; + if (!cpsema(&mp->m_growlock)) + return XFS_ERROR(EWOULDBLOCK); + error = xfs_growfs_data_private(mp, in); + vsema(&mp->m_growlock); + return error; +} + +int +xfs_growfs_log( + xfs_mount_t *mp, + xfs_growfs_log_t *in) +{ + int error; + if (!cpsema(&mp->m_growlock)) + return XFS_ERROR(EWOULDBLOCK); + error = xfs_growfs_log_private(mp, in); + vsema(&mp->m_growlock); + return error; +} + +/* + * exported through ioctl XFS_IOC_FSCOUNTS + */ + +int +xfs_fs_counts( + xfs_mount_t *mp, + xfs_fsop_counts_t *cnt) +{ + unsigned long s; + + s = XFS_SB_LOCK(mp); + cnt->freedata = mp->m_sb.sb_fdblocks; + cnt->freertx = mp->m_sb.sb_frextents; + cnt->freeino = mp->m_sb.sb_ifree; + cnt->allocino = mp->m_sb.sb_icount; + XFS_SB_UNLOCK(mp, s); + return 0; +} + +/* + * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS + * + * xfs_reserve_blocks is called to set m_resblks + * in the in-core mount table. The number of unused reserved blocks + * is kept in m_resbls_avail. + * + * Reserve the requested number of blocks if available. Otherwise return + * as many as possible to satisfy the request. The actual number + * reserved are returned in outval + * + * A null inval pointer indicates that only the current reserved blocks + * available should be returned no settings are changed. + */ + +int +xfs_reserve_blocks( + xfs_mount_t *mp, + __uint64_t *inval, + xfs_fsop_resblks_t *outval) +{ + __uint64_t lcounter, delta; + __uint64_t request; + unsigned long s; + + /* If inval is null, report current values and return */ + + if (inval == (__uint64_t *)NULL) { + outval->resblks = mp->m_resblks; + outval->resblks_avail = mp->m_resblks_avail; + return(0); + } + + request = *inval; + s = XFS_SB_LOCK(mp); + + /* + * If our previous reservation was larger than the current value, + * then move any unused blocks back to the free pool. + */ + + if (mp->m_resblks > request) { + lcounter = mp->m_resblks_avail - request; + if (lcounter > 0) { /* release unused blocks */ + mp->m_sb.sb_fdblocks += lcounter; + mp->m_resblks_avail -= lcounter; + } + mp->m_resblks = request; + } else { + delta = request - mp->m_resblks; + lcounter = mp->m_sb.sb_fdblocks; + lcounter -= delta; + if (lcounter < 0) { + /* We can't satisfy the request, just get what we can */ + mp->m_resblks += mp->m_sb.sb_fdblocks; + mp->m_resblks_avail += mp->m_sb.sb_fdblocks; + mp->m_sb.sb_fdblocks = 0; + } else { + mp->m_sb.sb_fdblocks = lcounter; + mp->m_resblks = request; + mp->m_resblks_avail += delta; + } + } + + outval->resblks = mp->m_resblks; + outval->resblks_avail = mp->m_resblks_avail; + XFS_SB_UNLOCK(mp, s); + return(0); +} + +void +xfs_fs_log_dummy(xfs_mount_t *mp) +{ + xfs_trans_t *tp; + xfs_inode_t *ip; + + + tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); + atomic_inc(&mp->m_active_trans); + if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) { + xfs_trans_cancel(tp, 0); + return; + } + + ip = mp->m_rootip; + xfs_ilock(ip, XFS_ILOCK_EXCL); + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_trans_commit(tp, XFS_TRANS_SYNC, NULL); + + xfs_iunlock(ip, XFS_ILOCK_EXCL); +} + +int +xfs_fs_freeze( + xfs_mount_t *mp) +{ + vfs_t *vfsp; + /*REFERENCED*/ + int error; + + vfsp = XFS_MTOVFS(mp); + + /* Stop new writers */ + xfs_start_freeze(mp, XFS_FREEZE_WRITE); + + /* Flush the refcache */ + xfs_refcache_purge_mp(mp); + + /* Flush delalloc and delwri data */ + VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, NULL, error); + + /* Pause transaction subsystem */ + xfs_start_freeze(mp, XFS_FREEZE_TRANS); + + /* Flush any remaining inodes into buffers */ + VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error); + + /* Push all buffers out to disk */ + xfs_binval(mp->m_ddev_targp); + if (mp->m_rtdev_targp) { + xfs_binval(mp->m_rtdev_targp); + } + + /* Push the superblock and write an unmount record */ + xfs_log_unmount_write(mp); + xfs_unmountfs_writesb(mp); + + return 0; +} + + +int +xfs_fs_thaw( + xfs_mount_t *mp) +{ + xfs_finish_freeze(mp); + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_fsops.h linux-2.4.19-sgi211r3/fs/xfs/xfs_fsops.h --- linux-2.4.19/fs/xfs/xfs_fsops.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_fsops.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_FSOPS_H__ +#define __XFS_FSOPS_H__ + +int +xfs_fs_geometry( + xfs_mount_t *mp, + xfs_fsop_geom_t *geo, + int new_version); + +int +xfs_growfs_data( + xfs_mount_t *mp, + xfs_growfs_data_t *in); + +int +xfs_growfs_log( + xfs_mount_t *mp, + xfs_growfs_log_t *in); + +int +xfs_fs_counts( + xfs_mount_t *mp, + xfs_fsop_counts_t *cnt); + +int +xfs_reserve_blocks( + xfs_mount_t *mp, + __uint64_t *inval, + xfs_fsop_resblks_t *outval); + +int +xfs_fs_freeze( + xfs_mount_t *mp); + +int +xfs_fs_thaw( + xfs_mount_t *mp); + +#endif /* __XFS_FSOPS_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_ialloc.c linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc.c --- linux-2.4.19/fs/xfs/xfs_ialloc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,1336 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * Log specified fields for the inode given by bp and off. + */ +STATIC void +xfs_ialloc_log_di( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* inode buffer */ + int off, /* index of inode in buffer */ + int fields) /* bitmask of fields to log */ +{ + int first; /* first byte number */ + int ioffset; /* off in bytes */ + int last; /* last byte number */ + xfs_mount_t *mp; /* mount point structure */ + static const short offsets[] = { /* field offsets */ + /* keep in sync with bits */ + offsetof(xfs_dinode_core_t, di_magic), + offsetof(xfs_dinode_core_t, di_mode), + offsetof(xfs_dinode_core_t, di_version), + offsetof(xfs_dinode_core_t, di_format), + offsetof(xfs_dinode_core_t, di_onlink), + offsetof(xfs_dinode_core_t, di_uid), + offsetof(xfs_dinode_core_t, di_gid), + offsetof(xfs_dinode_core_t, di_nlink), + offsetof(xfs_dinode_core_t, di_projid), + offsetof(xfs_dinode_core_t, di_pad), + offsetof(xfs_dinode_core_t, di_atime), + offsetof(xfs_dinode_core_t, di_mtime), + offsetof(xfs_dinode_core_t, di_ctime), + offsetof(xfs_dinode_core_t, di_size), + offsetof(xfs_dinode_core_t, di_nblocks), + offsetof(xfs_dinode_core_t, di_extsize), + offsetof(xfs_dinode_core_t, di_nextents), + offsetof(xfs_dinode_core_t, di_anextents), + offsetof(xfs_dinode_core_t, di_forkoff), + offsetof(xfs_dinode_core_t, di_aformat), + offsetof(xfs_dinode_core_t, di_dmevmask), + offsetof(xfs_dinode_core_t, di_dmstate), + offsetof(xfs_dinode_core_t, di_flags), + offsetof(xfs_dinode_core_t, di_gen), + offsetof(xfs_dinode_t, di_next_unlinked), + offsetof(xfs_dinode_t, di_u), + offsetof(xfs_dinode_t, di_a), + sizeof(xfs_dinode_t) + }; + + + ASSERT(offsetof(xfs_dinode_t, di_core) == 0); + ASSERT((fields & (XFS_DI_U|XFS_DI_A)) == 0); + mp = tp->t_mountp; + /* + * Get the inode-relative first and last bytes for these fields + */ + xfs_btree_offsets(fields, offsets, XFS_DI_NUM_BITS, &first, &last); + /* + * Convert to buffer offsets and log it. + */ + ioffset = off << mp->m_sb.sb_inodelog; + first += ioffset; + last += ioffset; + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Allocation group level functions. + */ + +/* + * Allocate new inodes in the allocation group specified by agbp. + * Return 0 for success, else error code. + */ +STATIC int /* error code or 0 */ +xfs_ialloc_ag_alloc( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* alloc group buffer */ + int *alloc) +{ + xfs_agi_t *agi; /* allocation group header */ + xfs_alloc_arg_t args; /* allocation argument structure */ + int blks_per_cluster; /* fs blocks per inode cluster */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + xfs_daddr_t d; /* disk addr of buffer */ + int error; + xfs_buf_t *fbuf; /* new free inodes' buffer */ + xfs_dinode_t *free; /* new free inode structure */ + int i; /* inode counter */ + int j; /* block counter */ + int nbufs; /* num bufs of new inodes */ + xfs_agino_t newino; /* new first inode's number */ + xfs_agino_t newlen; /* new number of inodes */ + int ninodes; /* num inodes per buf */ + xfs_agino_t thisino; /* current inode number, for loop */ + int version; /* inode version number to use */ + static xfs_timestamp_t ztime; /* zero xfs timestamp */ + int isaligned; /* inode allocation at stripe unit */ + /* boundary */ + xfs_dinode_core_t dic; /* a dinode_core to copy to new */ + /* inodes */ + + args.tp = tp; + args.mp = tp->t_mountp; + + /* + * Locking will ensure that we don't have two callers in here + * at one time. + */ + newlen = XFS_IALLOC_INODES(args.mp); + if (args.mp->m_maxicount && + args.mp->m_sb.sb_icount + newlen > args.mp->m_maxicount) + return XFS_ERROR(ENOSPC); + args.minlen = args.maxlen = XFS_IALLOC_BLOCKS(args.mp); + /* + * Set the alignment for the allocation. + * If stripe alignment is turned on then align at stripe unit + * boundary. + * If the cluster size is smaller than a filesystem block + * then we're doing I/O for inodes in filesystem block size pieces, + * so don't need alignment anyway. + */ + isaligned = 0; + if (args.mp->m_sinoalign) { + ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN)); + args.alignment = args.mp->m_dalign; + isaligned = 1; + } else if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) && + args.mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp))) + args.alignment = args.mp->m_sb.sb_inoalignmt; + else + args.alignment = 1; + agi = XFS_BUF_TO_AGI(agbp); + /* + * Need to figure out where to allocate the inode blocks. + * Ideally they should be spaced out through the a.g. + * For now, just allocate blocks up front. + */ + args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + args.fsbno = XFS_AGB_TO_FSB(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + args.agbno); + /* + * Allocate a fixed-size extent of inodes. + */ + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.mod = args.total = args.wasdel = args.isfl = args.userdata = + args.minalignslop = 0; + args.prod = 1; + /* + * Allow space for the inode btree to split. + */ + args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + + /* + * If stripe alignment is turned on, then try again with cluster + * alignment. + */ + if (isaligned && args.fsbno == NULLFSBLOCK) { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + args.fsbno = XFS_AGB_TO_FSB(args.mp, + INT_GET(agi->agi_seqno, ARCH_CONVERT), args.agbno); + if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) && + args.mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp))) + args.alignment = args.mp->m_sb.sb_inoalignmt; + else + args.alignment = 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + + if (args.fsbno == NULLFSBLOCK) { + *alloc = 0; + return 0; + } + ASSERT(args.len == args.minlen); + /* + * Convert the results. + */ + newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); + /* + * Loop over the new block(s), filling in the inodes. + * For small block sizes, manipulate the inodes in buffers + * which are multiples of the blocks size. + */ + if (args.mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(args.mp)) { + blks_per_cluster = 1; + nbufs = (int)args.len; + ninodes = args.mp->m_sb.sb_inopblock; + } else { + blks_per_cluster = XFS_INODE_CLUSTER_SIZE(args.mp) / + args.mp->m_sb.sb_blocksize; + nbufs = (int)args.len / blks_per_cluster; + ninodes = blks_per_cluster * args.mp->m_sb.sb_inopblock; + } + /* + * Figure out what version number to use in the inodes we create. + * If the superblock version has caught up to the one that supports + * the new inode format, then use the new inode version. Otherwise + * use the old version so that old kernels will continue to be + * able to use the file system. + */ + if (XFS_SB_VERSION_HASNLINK(&args.mp->m_sb)) + version = XFS_DINODE_VERSION_2; + else + version = XFS_DINODE_VERSION_1; + for (j = 0; j < nbufs; j++) { + /* + * Get the block. + */ + d = XFS_AGB_TO_DADDR(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + args.agbno + (j * blks_per_cluster)); + fbuf = xfs_trans_get_buf(tp, args.mp->m_ddev_targp, d, + args.mp->m_bsize * blks_per_cluster, + XFS_BUF_LOCK); + ASSERT(fbuf); + ASSERT(!XFS_BUF_GETERROR(fbuf)); + /* + * Loop over the inodes in this buffer. + */ + INT_SET(dic.di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC); + INT_ZERO(dic.di_mode, ARCH_CONVERT); + INT_SET(dic.di_version, ARCH_CONVERT, version); + INT_ZERO(dic.di_format, ARCH_CONVERT); + INT_ZERO(dic.di_onlink, ARCH_CONVERT); + INT_ZERO(dic.di_uid, ARCH_CONVERT); + INT_ZERO(dic.di_gid, ARCH_CONVERT); + INT_ZERO(dic.di_nlink, ARCH_CONVERT); + INT_ZERO(dic.di_projid, ARCH_CONVERT); + bzero(&(dic.di_pad[0]),sizeof(dic.di_pad)); + INT_SET(dic.di_atime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_atime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_SET(dic.di_mtime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_mtime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_SET(dic.di_ctime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_ctime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_ZERO(dic.di_size, ARCH_CONVERT); + INT_ZERO(dic.di_nblocks, ARCH_CONVERT); + INT_ZERO(dic.di_extsize, ARCH_CONVERT); + INT_ZERO(dic.di_nextents, ARCH_CONVERT); + INT_ZERO(dic.di_anextents, ARCH_CONVERT); + INT_ZERO(dic.di_forkoff, ARCH_CONVERT); + INT_ZERO(dic.di_aformat, ARCH_CONVERT); + INT_ZERO(dic.di_dmevmask, ARCH_CONVERT); + INT_ZERO(dic.di_dmstate, ARCH_CONVERT); + INT_ZERO(dic.di_flags, ARCH_CONVERT); + INT_ZERO(dic.di_gen, ARCH_CONVERT); + + for (i = 0; i < ninodes; i++) { + free = XFS_MAKE_IPTR(args.mp, fbuf, i); + bcopy (&dic, &(free->di_core), sizeof(xfs_dinode_core_t)); + INT_SET(free->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + xfs_ialloc_log_di(tp, fbuf, i, + XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); + } + xfs_trans_inode_alloc_buf(tp, fbuf); + } + INT_MOD(agi->agi_count, ARCH_CONVERT, newlen); + INT_MOD(agi->agi_freecount, ARCH_CONVERT, newlen); + down_read(&args.mp->m_peraglock); + args.mp->m_perag[INT_GET(agi->agi_seqno, ARCH_CONVERT)].pagi_freecount += newlen; + up_read(&args.mp->m_peraglock); + INT_SET(agi->agi_newino, ARCH_CONVERT, newino); + /* + * Insert records describing the new inode chunk into the btree. + */ + cur = xfs_btree_init_cursor(args.mp, tp, agbp, + INT_GET(agi->agi_seqno, ARCH_CONVERT), + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + for (thisino = newino; + thisino < newino + newlen; + thisino += XFS_INODES_PER_CHUNK) { + if ((error = xfs_inobt_lookup_eq(cur, thisino, + XFS_INODES_PER_CHUNK, XFS_INOBT_ALL_FREE, &i))) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 0); + if ((error = xfs_inobt_insert(cur, &i))) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 1); + } + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + /* + * Log allocation group header fields + */ + xfs_ialloc_log_agi(tp, agbp, + XFS_AGI_COUNT | XFS_AGI_FREECOUNT | XFS_AGI_NEWINO); + /* + * Modify/log superblock values for inode count and inode free count. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, (long)newlen); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, (long)newlen); + *alloc = 1; + return 0; +} + +/* + * Select an allocation group to look for a free inode in, based on the parent + * inode and then mode. Return the allocation group buffer. + */ +STATIC xfs_buf_t * /* allocation group buffer */ +xfs_ialloc_ag_select( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent directory inode number */ + mode_t mode, /* bits set to indicate file type */ + int okalloc) /* ok to allocate more space */ +{ + xfs_buf_t *agbp; /* allocation group header buffer */ + xfs_agnumber_t agcount; /* number of ag's in the filesystem */ + xfs_agnumber_t agno; /* current ag number */ + int flags; /* alloc buffer locking flags */ + xfs_extlen_t ineed; /* blocks needed for inode allocation */ + xfs_extlen_t longest = 0; /* longest extent available */ + xfs_mount_t *mp; /* mount point structure */ + int needspace; /* file mode implies space allocated */ + xfs_perag_t *pag; /* per allocation group data */ + xfs_agnumber_t pagno; /* parent (starting) ag number */ + + /* + * Files of these types need at least one block if length > 0 + * (and they won't fit in the inode, but that's hard to figure out). + */ + needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); + mp = tp->t_mountp; + agcount = mp->m_maxagi; + if (S_ISDIR(mode)) + pagno = atomicIncWithWrap((int *)&mp->m_agirotor, agcount); + else { + pagno = XFS_INO_TO_AGNO(mp, parent); + if (pagno >= agcount) + pagno = 0; + } + ASSERT(pagno < agcount); + /* + * Loop through allocation groups, looking for one with a little + * free space in it. Note we don't look for free inodes, exactly. + * Instead, we include whether there is a need to allocate inodes + * to mean that blocks must be allocated for them, + * if none are currently free. + */ + agno = pagno; + flags = XFS_ALLOC_FLAG_TRYLOCK; + down_read(&mp->m_peraglock); + for (;;) { + pag = &mp->m_perag[agno]; + if (!pag->pagi_init) { + if (xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + goto nextag; + } + } else + agbp = NULL; + + if (!pag->pagi_inodeok) { + atomicIncWithWrap((int *)&mp->m_agirotor, agcount); + goto unlock_nextag; + } + + /* + * Is there enough free space for the file plus a block + * of inodes (if we need to allocate some)? + */ + ineed = pag->pagi_freecount ? 0 : XFS_IALLOC_BLOCKS(mp); + if (ineed && !pag->pagf_init) { + if (agbp == NULL && + xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + goto nextag; + } + (void)xfs_alloc_pagf_init(mp, tp, agno, flags); + } + if (!ineed || pag->pagf_init) { + if (ineed && !(longest = pag->pagf_longest)) + longest = pag->pagf_flcount > 0; + if (!ineed || + (pag->pagf_freeblks >= needspace + ineed && + longest >= ineed && + okalloc)) { + if (agbp == NULL && + xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + goto nextag; + } + up_read(&mp->m_peraglock); + return agbp; + } + } +unlock_nextag: + if (agbp) + xfs_trans_brelse(tp, agbp); +nextag: + /* + * No point in iterating over the rest, if we're shutting + * down. + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + up_read(&mp->m_peraglock); + return (xfs_buf_t *)0; + } + agno++; + if (agno >= agcount) + agno = 0; + if (agno == pagno) { + if (flags == 0) { + up_read(&mp->m_peraglock); + return (xfs_buf_t *)0; + } + flags = 0; + } + } +} + +/* + * Visible inode allocation functions. + */ + +/* + * Allocate an inode on disk. + * Mode is used to tell whether the new inode will need space, and whether + * it is a directory. + * + * The arguments IO_agbp and alloc_done are defined to work within + * the constraint of one allocation per transaction. + * xfs_dialloc() is designed to be called twice if it has to do an + * allocation to make more free inodes. On the first call, + * IO_agbp should be set to NULL. If an inode is available, + * i.e., xfs_dialloc() did not need to do an allocation, an inode + * number is returned. In this case, IO_agbp would be set to the + * current ag_buf and alloc_done set to false. + * If an allocation needed to be done, xfs_dialloc would return + * the current ag_buf in IO_agbp and set alloc_done to true. + * The caller should then commit the current transaction, allocate a new + * transaction, and call xfs_dialloc() again, passing in the previous + * value of IO_agbp. IO_agbp should be held across the transactions. + * Since the agbp is locked across the two calls, the second call is + * guaranteed to have a free inode available. + * + * Once we successfully pick an inode its number is returned and the + * on-disk data structures are updated. The inode itself is not read + * in, since doing so would break ordering constraints with xfs_reclaim. + */ +int +xfs_dialloc( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent inode (directory) */ + mode_t mode, /* mode bits for new inode */ + int okalloc, /* ok to allocate more space */ + xfs_buf_t **IO_agbp, /* in/out ag header's buffer */ + boolean_t *alloc_done, /* true if we needed to replenish + inode freelist */ + xfs_ino_t *inop) /* inode number allocated */ +{ + xfs_agnumber_t agcount; /* number of allocation groups */ + xfs_buf_t *agbp; /* allocation group header's buffer */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agi_t *agi; /* allocation group header structure */ + xfs_btree_cur_t *cur; /* inode allocation btree cursor */ + int error; /* error return value */ + int i; /* result code */ + int ialloced; /* inode allocation status */ + int noroom = 0; /* no space for inode blk allocation */ + xfs_ino_t ino; /* fs-relative inode to be returned */ + /* REFERENCED */ + int j; /* result code */ + xfs_mount_t *mp; /* file system mount structure */ + int offset; /* index of inode in chunk */ + xfs_agino_t pagino; /* parent's a.g. relative inode # */ + xfs_agnumber_t pagno; /* parent's allocation group number */ + xfs_inobt_rec_t rec; /* inode allocation record */ + xfs_agnumber_t tagno; /* testing allocation group number */ + xfs_btree_cur_t *tcur; /* temp cursor */ + xfs_inobt_rec_t trec; /* temp inode allocation record */ + + + if (*IO_agbp == NULL) { + /* + * We do not have an agbp, so select an initial allocation + * group for inode allocation. + */ + agbp = xfs_ialloc_ag_select(tp, parent, mode, okalloc); + /* + * Couldn't find an allocation group satisfying the + * criteria, give up. + */ + if (!agbp) { + *inop = NULLFSINO; + return 0; + } + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } else { + /* + * Continue where we left off before. In this case, we + * know that the allocation group has free inodes. + */ + agbp = *IO_agbp; + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0); + } + mp = tp->t_mountp; + agcount = mp->m_sb.sb_agcount; + agno = INT_GET(agi->agi_seqno, ARCH_CONVERT); + tagno = agno; + pagno = XFS_INO_TO_AGNO(mp, parent); + pagino = XFS_INO_TO_AGINO(mp, parent); + + /* + * If we have already hit the ceiling of inode blocks then clear + * okalloc so we scan all available agi structures for a free + * inode. + */ + + if (mp->m_maxicount && + mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) { + noroom = 1; + okalloc = 0; + } + + /* + * Loop until we find an allocation group that either has free inodes + * or in which we can allocate some inodes. Iterate through the + * allocation groups upward, wrapping at the end. + */ + *alloc_done = B_FALSE; + while (INT_ISZERO(agi->agi_freecount, ARCH_CONVERT)) { + /* + * Don't do anything if we're not supposed to allocate + * any blocks, just go on to the next ag. + */ + if (okalloc) { + /* + * Try to allocate some new inodes in the allocation + * group. + */ + if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) { + xfs_trans_brelse(tp, agbp); + if (error == ENOSPC) { + *inop = NULLFSINO; + return 0; + } else + return error; + } + if (ialloced) { + /* + * We successfully allocated some inodes, return + * the current context to the caller so that it + * can commit the current transaction and call + * us again where we left off. + */ + ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0); + *alloc_done = B_TRUE; + *IO_agbp = agbp; + *inop = NULLFSINO; + return 0; + } + } + /* + * If it failed, give up on this ag. + */ + xfs_trans_brelse(tp, agbp); + /* + * Go on to the next ag: get its ag header. + */ +nextag: + if (++tagno == agcount) + tagno = 0; + if (tagno == agno) { + *inop = NULLFSINO; + return noroom ? ENOSPC : 0; + } + down_read(&mp->m_peraglock); + if (mp->m_perag[tagno].pagi_inodeok == 0) { + up_read(&mp->m_peraglock); + goto nextag; + } + error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); + up_read(&mp->m_peraglock); + if (error) + goto nextag; + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } + /* + * Here with an allocation group that has a free inode. + * Reset agno since we may have chosen a new ag in the + * loop above. + */ + agno = tagno; + *IO_agbp = NULL; + cur = xfs_btree_init_cursor(mp, tp, agbp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + /* + * If pagino is 0 (this is the root inode allocation) use newino. + * This must work because we've just allocated some. + */ + if (!pagino) + pagino = INT_GET(agi->agi_newino, ARCH_CONVERT); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + /* + * If in the same a.g. as the parent, try to get near the parent. + */ + if (pagno == agno) { + if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i))) + goto error0; + if (i != 0 && + (error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 && + j == 1 && + rec.ir_freecount > 0) { + /* + * Found a free inode in the same chunk + * as parent, done. + */ + } + /* + * In the same a.g. as parent, but parent's chunk is full. + */ + else { + int doneleft; /* done, to the left */ + int doneright; /* done, to the right */ + + if (error) + goto error0; + ASSERT(i == 1); + ASSERT(j == 1); + /* + * Duplicate the cursor, search left & right + * simultaneously. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + goto error0; + /* + * Search left with tcur, back up 1 record. + */ + if ((error = xfs_inobt_decrement(tcur, 0, &i))) + goto error1; + doneleft = !i; + if (!doneleft) { + if ((error = xfs_inobt_get_rec(tcur, + &trec.ir_startino, + &trec.ir_freecount, + &trec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, error1); + } + /* + * Search right with cur, go forward 1 record. + */ + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error1; + doneright = !i; + if (!doneright) { + if ((error = xfs_inobt_get_rec(cur, + &rec.ir_startino, + &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, error1); + } + /* + * Loop until we find the closest inode chunk + * with a free one. + */ + while (!doneleft || !doneright) { + int useleft; /* using left inode + chunk this time */ + + /* + * Figure out which block is closer, + * if both are valid. + */ + if (!doneleft && !doneright) + useleft = + pagino - + (trec.ir_startino + + XFS_INODES_PER_CHUNK - 1) < + rec.ir_startino - pagino; + else + useleft = !doneleft; + /* + * If checking the left, does it have + * free inodes? + */ + if (useleft && trec.ir_freecount) { + /* + * Yes, set it up as the chunk to use. + */ + rec = trec; + xfs_btree_del_cursor(cur, + XFS_BTREE_NOERROR); + cur = tcur; + break; + } + /* + * If checking the right, does it have + * free inodes? + */ + if (!useleft && rec.ir_freecount) { + /* + * Yes, it's already set up. + */ + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + break; + } + /* + * If used the left, get another one + * further left. + */ + if (useleft) { + if ((error = xfs_inobt_decrement(tcur, 0, + &i))) + goto error1; + doneleft = !i; + if (!doneleft) { + if ((error = xfs_inobt_get_rec( + tcur, + &trec.ir_startino, + &trec.ir_freecount, + &trec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, + error1); + } + } + /* + * If used the right, get another one + * further right. + */ + else { + if ((error = xfs_inobt_increment(cur, 0, + &i))) + goto error1; + doneright = !i; + if (!doneright) { + if ((error = xfs_inobt_get_rec( + cur, + &rec.ir_startino, + &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, + error1); + } + } + } + ASSERT(!doneleft || !doneright); + } + } + /* + * In a different a.g. from the parent. + * See if the most recently allocated block has any free. + */ + else if (INT_GET(agi->agi_newino, ARCH_CONVERT) != NULLAGINO) { + if ((error = xfs_inobt_lookup_eq(cur, + INT_GET(agi->agi_newino, ARCH_CONVERT), 0, 0, &i))) + goto error0; + if (i == 1 && + (error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 && + j == 1 && + rec.ir_freecount > 0) { + /* + * The last chunk allocated in the group still has + * a free inode. + */ + } + /* + * None left in the last group, search the whole a.g. + */ + else { + if (error) + goto error0; + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + ASSERT(i == 1); + for (;;) { + if ((error = xfs_inobt_get_rec(cur, + &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, + &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (rec.ir_freecount > 0) + break; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + } + offset = XFS_IALLOC_FIND_FREE(&rec.ir_free); + ASSERT(offset >= 0); + ASSERT(offset < XFS_INODES_PER_CHUNK); + ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % + XFS_INODES_PER_CHUNK) == 0); + ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); + XFS_INOBT_CLR_FREE(&rec, offset, ARCH_NOCONVERT); + rec.ir_freecount--; + if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, + rec.ir_free))) + goto error0; + INT_MOD(agi->agi_freecount, ARCH_CONVERT, -1); + xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); + down_read(&mp->m_peraglock); + mp->m_perag[tagno].pagi_freecount--; + up_read(&mp->m_peraglock); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); + *inop = ino; + return 0; +error1: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); +error0: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Free disk inode. Carefully avoids touching the incore inode, all + * manipulations incore are the caller's responsibility. + * The on-disk inode is not changed by this operation, only the + * btree (free inode mask) is changed. + */ +int +xfs_difree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t inode) /* inode to be freed */ +{ + /* REFERENCED */ + xfs_agblock_t agbno; /* block number containing inode */ + xfs_buf_t *agbp; /* buffer containing allocation group header */ + xfs_agino_t agino; /* inode number relative to allocation group */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agi_t *agi; /* allocation group header */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + int error; /* error return value */ + int i; /* result code */ + xfs_mount_t *mp; /* mount structure for filesystem */ + int off; /* offset of inode in inode chunk */ + xfs_inobt_rec_t rec; /* btree record */ + + mp = tp->t_mountp; + + /* + * Break up inode number into its components. + */ + agno = XFS_INO_TO_AGNO(mp, inode); + if (agno >= mp->m_sb.sb_agcount) { + cmn_err(CE_WARN, + "xfs_difree: agno >= mp->m_sb.sb_agcount (%d >= %d) on %s. Returning EINVAL.", + agno, mp->m_sb.sb_agcount, mp->m_fsname); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + agino = XFS_INO_TO_AGINO(mp, inode); + if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { + cmn_err(CE_WARN, + "xfs_difree: inode != XFS_AGINO_TO_INO() (%d != %d) on %s. Returning EINVAL.", + inode, XFS_AGINO_TO_INO(mp, agno, agino), mp->m_fsname); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + if (agbno >= mp->m_sb.sb_agblocks) { + cmn_err(CE_WARN, + "xfs_difree: agbno >= mp->m_sb.sb_agblocks (%d >= %d) on %s. Returning EINVAL.", + agbno, mp->m_sb.sb_agblocks, mp->m_fsname); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + /* + * Get the allocation group header. + */ + down_read(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + up_read(&mp->m_peraglock); + if (error) { + cmn_err(CE_WARN, + "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + ASSERT(agbno < INT_GET(agi->agi_length, ARCH_CONVERT)); + /* + * Initialize the cursor. + */ + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, + (xfs_inode_t *)0, 0); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + /* + * Look for the entry describing this inode. + */ + if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) { + cmn_err(CE_WARN, + "xfs_difree: xfs_inobt_lookup_le returned() an error %d on %s. Returning error.", + error, mp->m_fsname); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) { + cmn_err(CE_WARN, + "xfs_difree: xfs_inobt_get_rec() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Get the offset in the inode chunk. + */ + off = agino - rec.ir_startino; + ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK); + ASSERT(!XFS_INOBT_IS_FREE(&rec, off, ARCH_NOCONVERT)); + /* + * Mark the inode free & increment the count. + */ + XFS_INOBT_SET_FREE(&rec, off, ARCH_NOCONVERT); + rec.ir_freecount++; + if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, rec.ir_free))) { + cmn_err(CE_WARN, + "xfs_difree: xfs_inobt_update() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + goto error0; + } + /* + * Change the inode free counts and log the ag/sb changes. + */ + INT_MOD(agi->agi_freecount, ARCH_CONVERT, 1); + xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); + down_read(&mp->m_peraglock); + mp->m_perag[agno].pagi_freecount++; + up_read(&mp->m_peraglock); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); + return 0; + +error0: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Return the location of the inode in bno/off, for mapping it into a buffer. + */ +/*ARGSUSED*/ +int +xfs_dilocate( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode to locate */ + xfs_fsblock_t *bno, /* output: block containing inode */ + int *len, /* output: num blocks in inode cluster */ + int *off, /* output: index in block of inode */ + uint flags) /* flags concerning inode lookup */ +{ + xfs_agblock_t agbno; /* block number of inode in the alloc group */ + xfs_buf_t *agbp; /* agi buffer */ + xfs_agino_t agino; /* inode number within alloc group */ + xfs_agnumber_t agno; /* allocation group number */ + int blks_per_cluster; /* num blocks per inode cluster */ + xfs_agblock_t chunk_agbno; /* first block in inode chunk */ + xfs_agino_t chunk_agino; /* first agino in inode chunk */ + __int32_t chunk_cnt; /* count of free inodes in chunk */ + xfs_inofree_t chunk_free; /* mask of free inodes in chunk */ + xfs_agblock_t cluster_agbno; /* first block in inode cluster */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + int error; /* error code */ + int i; /* temp state */ + int offset; /* index of inode in its buffer */ + int offset_agbno; /* blks from chunk start to inode */ + + ASSERT(ino != NULLFSINO); + /* + * Split up the inode number into its parts. + */ + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || + ino != XFS_AGINO_TO_INO(mp, agno, agino)) { +#ifdef DEBUG + if (agno >= mp->m_sb.sb_agcount) { + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_dilocate: agno (%d) >= " + "mp->m_sb.sb_agcount (%d)", + agno, mp->m_sb.sb_agcount); + } + if (agbno >= mp->m_sb.sb_agblocks) { + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_dilocate: agbno (0x%llx) >= " + "mp->m_sb.sb_agblocks (0x%lx)", + (unsigned long long) agbno, + (unsigned long) mp->m_sb.sb_agblocks); + } + if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_dilocate: ino (0x%llx) != " + "XFS_AGINO_TO_INO(mp, agno, agino) " + "(0x%llx)", + ino, XFS_AGINO_TO_INO(mp, agno, agino)); + } +#endif /* DEBUG */ + return XFS_ERROR(EINVAL); + } + if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) || + !(flags & XFS_IMAP_LOOKUP)) { + offset = XFS_INO_TO_OFFSET(mp, ino); + ASSERT(offset < mp->m_sb.sb_inopblock); + *bno = XFS_AGB_TO_FSB(mp, agno, agbno); + *off = offset; + *len = 1; + return 0; + } + blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; + if (*bno != NULLFSBLOCK) { + offset = XFS_INO_TO_OFFSET(mp, ino); + ASSERT(offset < mp->m_sb.sb_inopblock); + cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno); + *off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + + offset; + *len = blks_per_cluster; + return 0; + } + if (mp->m_inoalign_mask) { + offset_agbno = agbno & mp->m_inoalign_mask; + chunk_agbno = agbno - offset_agbno; + } else { + down_read(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + up_read(&mp->m_peraglock); + if (error) { +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " + "xfs_ialloc_read_agi() returned " + "error %d, agno %d", + error, agno); +#endif /* DEBUG */ + return error; + } + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, + (xfs_inode_t *)0, 0); + if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) { +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " + "xfs_inobt_lookup_le() failed"); +#endif /* DEBUG */ + goto error0; + } + if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, + &chunk_free, &i, ARCH_NOCONVERT))) { +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " + "xfs_inobt_get_rec() failed"); +#endif /* DEBUG */ + goto error0; + } + if (i == 0) { +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " + "xfs_inobt_get_rec() failed"); +#endif /* DEBUG */ + error = XFS_ERROR(EINVAL); + } + xfs_trans_brelse(tp, agbp); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + if (error) + return error; + chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); + offset_agbno = agbno - chunk_agbno; + } + ASSERT(agbno >= chunk_agbno); + cluster_agbno = chunk_agbno + + ((offset_agbno / blks_per_cluster) * blks_per_cluster); + offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + + XFS_INO_TO_OFFSET(mp, ino); + *bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno); + *off = offset; + *len = blks_per_cluster; + return 0; +error0: + xfs_trans_brelse(tp, agbp); + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Compute and fill in value of m_in_maxlevels. + */ +void +xfs_ialloc_compute_maxlevels( + xfs_mount_t *mp) /* file system mount structure */ +{ + int level; + uint maxblocks; + uint maxleafents; + int minleafrecs; + int minnoderecs; + + maxleafents = (1LL << XFS_INO_AGINO_BITS(mp)) >> + XFS_INODES_PER_CHUNK_LOG; + minleafrecs = mp->m_alloc_mnr[0]; + minnoderecs = mp->m_alloc_mnr[1]; + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + mp->m_in_maxlevels = level; +} + +/* + * Log specified fields for the ag hdr (inode section) + */ +void +xfs_ialloc_log_agi( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* allocation group header buffer */ + int fields) /* bitmask of fields to log */ +{ + int first; /* first byte number */ + int last; /* last byte number */ + static const short offsets[] = { /* field starting offsets */ + /* keep in sync with bit definitions */ + offsetof(xfs_agi_t, agi_magicnum), + offsetof(xfs_agi_t, agi_versionnum), + offsetof(xfs_agi_t, agi_seqno), + offsetof(xfs_agi_t, agi_length), + offsetof(xfs_agi_t, agi_count), + offsetof(xfs_agi_t, agi_root), + offsetof(xfs_agi_t, agi_level), + offsetof(xfs_agi_t, agi_freecount), + offsetof(xfs_agi_t, agi_newino), + offsetof(xfs_agi_t, agi_dirino), + offsetof(xfs_agi_t, agi_unlinked), + sizeof(xfs_agi_t) + }; +#ifdef DEBUG + xfs_agi_t *agi; /* allocation group header */ + + agi = XFS_BUF_TO_AGI(bp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == + XFS_AGI_MAGIC); +#endif + /* + * Compute byte offsets for the first and last fields. + */ + xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last); + /* + * Log the allocation group inode header buffer. + */ + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Read in the allocation group header (inode allocation section) + */ +int +xfs_ialloc_read_agi( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_buf_t **bpp) /* allocation group hdr buf */ +{ + xfs_agi_t *agi; /* allocation group header */ + int agi_ok; /* agi is consistent */ + xfs_buf_t *bp; /* allocation group hdr buf */ + xfs_daddr_t d; /* disk block address */ + int error; +#ifdef DEBUG + int i; +#endif + xfs_perag_t *pag; /* per allocation group data */ + + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, 0, &bp))) + return error; + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + /* + * Validate the magic number of the agi block. + */ + agi = XFS_BUF_TO_AGI(bp); + agi_ok = + INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC && + XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, + XFS_RANDOM_IALLOC_READ_AGI)) { + xfs_trans_brelse(tp, bp); +#ifdef __KERNEL__ /* additional, temporary, debugging code */ + cmn_err(CE_NOTE, + "EFSCORRUPTED returned from file %s line %d", + __FILE__, __LINE__); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + pag = &mp->m_perag[agno]; + if (!pag->pagi_init) { + pag->pagi_freecount = INT_GET(agi->agi_freecount, ARCH_CONVERT); + pag->pagi_init = 1; + } else { + /* + * It's possible for these to be out of sync if + * we are in the middle of a forced shutdown. + */ + ASSERT(pag->pagi_freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) + || XFS_FORCED_SHUTDOWN(mp)); + } +#ifdef DEBUG + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) + ASSERT(!INT_ISZERO(agi->agi_unlinked[i], ARCH_CONVERT)); +#endif + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGI, XFS_AGI_REF); + *bpp = bp; + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_ialloc.h linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc.h --- linux-2.4.19/fs/xfs/xfs_ialloc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IALLOC_H__ +#define __XFS_IALLOC_H__ + +struct xfs_buf; +struct xfs_dinode; +struct xfs_mount; +struct xfs_trans; + +/* + * Allocation parameters for inode allocation. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_INODES) +int xfs_ialloc_inodes(struct xfs_mount *mp); +#define XFS_IALLOC_INODES(mp) xfs_ialloc_inodes(mp) +#else +#define XFS_IALLOC_INODES(mp) ((mp)->m_ialloc_inos) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_BLOCKS) +xfs_extlen_t xfs_ialloc_blocks(struct xfs_mount *mp); +#define XFS_IALLOC_BLOCKS(mp) xfs_ialloc_blocks(mp) +#else +#define XFS_IALLOC_BLOCKS(mp) ((mp)->m_ialloc_blks) +#endif + +/* + * For small block file systems, move inodes in clusters of this size. + * When we don't have a lot of memory, however, we go a bit smaller + * to reduce the number of AGI and ialloc btree blocks we need to keep + * around for xfs_dilocate(). We choose which one to use in + * xfs_mount_int(). + */ +#define XFS_INODE_BIG_CLUSTER_SIZE 8192 +#define XFS_INODE_SMALL_CLUSTER_SIZE 4096 +#define XFS_INODE_CLUSTER_SIZE(mp) (mp)->m_inode_cluster_size + +/* + * Make an inode pointer out of the buffer/offset. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MAKE_IPTR) +struct xfs_dinode *xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o); +#define XFS_MAKE_IPTR(mp,b,o) xfs_make_iptr(mp,b,o) +#else +#define XFS_MAKE_IPTR(mp,b,o) \ + ((xfs_dinode_t *)(xfs_buf_offset(b, (o) << (mp)->m_sb.sb_inodelog))) +#endif + +/* + * Find a free (set) bit in the inode bitmask. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_FIND_FREE) +int xfs_ialloc_find_free(xfs_inofree_t *fp); +#define XFS_IALLOC_FIND_FREE(fp) xfs_ialloc_find_free(fp) +#else +#define XFS_IALLOC_FIND_FREE(fp) xfs_lowbit64(*(fp)) +#endif + + +#ifdef __KERNEL__ + +/* + * Prototypes for visible xfs_ialloc.c routines. + */ + +/* + * Allocate an inode on disk. + * Mode is used to tell whether the new inode will need space, and whether + * it is a directory. + * + * To work within the constraint of one allocation per transaction, + * xfs_dialloc() is designed to be called twice if it has to do an + * allocation to make more free inodes. If an inode is + * available without an allocation, agbp would be set to the current + * agbp and alloc_done set to false. + * If an allocation needed to be done, agbp would be set to the + * inode header of the allocation group and alloc_done set to true. + * The caller should then commit the current transaction and allocate a new + * transaction. xfs_dialloc() should then be called again with + * the agbp value returned from the previous call. + * + * Once we successfully pick an inode its number is returned and the + * on-disk data structures are updated. The inode itself is not read + * in, since doing so would break ordering constraints with xfs_reclaim. + * + * *agbp should be set to NULL on the first call, *alloc_done set to FALSE. + */ +int /* error */ +xfs_dialloc( + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent inode (directory) */ + mode_t mode, /* mode bits for new inode */ + int okalloc, /* ok to allocate more space */ + struct xfs_buf **agbp, /* buf for a.g. inode header */ + boolean_t *alloc_done, /* an allocation was done to replenish + the free inodes */ + xfs_ino_t *inop); /* inode number allocated */ + +/* + * Free disk inode. Carefully avoids touching the incore inode, all + * manipulations incore are the caller's responsibility. + * The on-disk inode is not changed by this operation, only the + * btree (free inode mask) is changed. + */ +int /* error */ +xfs_difree( + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t inode); /* inode to be freed */ + +/* + * Return the location of the inode in bno/len/off, + * for mapping it into a buffer. + */ +int +xfs_dilocate( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode to locate */ + xfs_fsblock_t *bno, /* output: block containing inode */ + int *len, /* output: num blocks in cluster*/ + int *off, /* output: index in block of inode */ + uint flags); /* flags for inode btree lookup */ + +/* + * Compute and fill in value of m_in_maxlevels. + */ +void +xfs_ialloc_compute_maxlevels( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Log specified fields for the ag hdr (inode section) + */ +void +xfs_ialloc_log_agi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *bp, /* allocation group header buffer */ + int fields); /* bitmask of fields to log */ + +/* + * Read in the allocation group header (inode allocation section) + */ +int /* error */ +xfs_ialloc_read_agi( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + struct xfs_buf **bpp); /* allocation group hdr buf */ + +#endif /* __KERNEL__ */ + +#endif /* __XFS_IALLOC_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_ialloc_btree.c linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc_btree.c --- linux-2.4.19/fs/xfs/xfs_ialloc_btree.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc_btree.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,2104 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Inode allocation management for XFS. + */ + +#include + + +/* + * Prototypes for internal functions. + */ + +STATIC void xfs_inobt_log_block(xfs_trans_t *, xfs_buf_t *, int); +STATIC void xfs_inobt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC int xfs_inobt_lshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *); +STATIC int xfs_inobt_rshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_inobt_split(xfs_btree_cur_t *, int, xfs_agblock_t *, + xfs_inobt_key_t *, xfs_btree_cur_t **, int *); +STATIC int xfs_inobt_updkey(xfs_btree_cur_t *, xfs_inobt_key_t *, int); + +/* + * Internal functions. + */ + +#ifdef _NOTYET_ +/* + * Single level of the xfs_inobt_delete record deletion routine. + * Delete record pointed to by cur/level. + * Remove the record from its block then rebalance the tree. + * Return 0 for error, 1 for done, 2 to go on to the next level. + */ +STATIC int /* error */ +xfs_inobt_delrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level removing record from */ + int *stat) /* fail/done/go-on */ +{ + xfs_buf_t *agbp; /* buffer for a.g. inode header */ + xfs_agnumber_t agfbno; /* agf block of freed btree block */ + xfs_buf_t *agfbp; /* bp of agf block of freed block */ + xfs_agi_t *agi; /* allocation group inode header */ + xfs_inobt_block_t *block; /* btree block record/key lives in */ + xfs_agblock_t bno; /* btree block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* kp points here if block is level 0 */ + xfs_inobt_key_t *kp; /* pointer to btree keys */ + xfs_agblock_t lbno; /* left block's block number */ + xfs_buf_t *lbp; /* left block's buffer pointer */ + xfs_inobt_block_t *left; /* left btree block */ + xfs_inobt_key_t *lkp; /* left block key pointer */ + xfs_inobt_ptr_t *lpp; /* left block address pointer */ + int lrecs; /* number of records in left block */ + xfs_inobt_rec_t *lrp; /* left block record pointer */ + xfs_inobt_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_agblock_t rbno; /* right block's block number */ + xfs_buf_t *rbp; /* right block's buffer pointer */ + xfs_inobt_block_t *right; /* right btree block */ + xfs_inobt_key_t *rkp; /* right block key pointer */ + xfs_inobt_rec_t *rp; /* pointer to btree records */ + xfs_inobt_ptr_t *rpp; /* right block address pointer */ + int rrecs; /* number of records in right block */ + xfs_inobt_rec_t *rrp; /* right block record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + + + /* + * Get the index of the entry being deleted, check for nothing there. + */ + ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get the buffer & block containing the record or key/ptr. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if (error = xfs_btree_check_sblock(cur, block, level, bp)) + return error; +#endif + /* + * Fail if we're off the end of the block. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * It's a nonleaf. Excise the key and ptr being deleted, by + * sliding the entries past them down one. + * Log the changed areas of the block. + */ + if (level > 0) { + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + if (error = xfs_btree_check_sptr(cur, INT_GET(pp[i], ARCH_CONVERT), level)) + return error; + } +#endif + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&kp[ptr], &kp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*kp)); + ovbcopy(&pp[ptr], &pp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*pp)); + xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + } + /* + * It's a leaf. Excise the record being deleted, by sliding the + * entries past it down one. Log the changed areas of the block. + */ + else { + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&rp[ptr], &rp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*rp)); + xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + /* + * If it's the first record in the block, we'll need a key + * structure to pass up to the next level (updkey). + */ + if (ptr == 1) { + INT_COPY(key.ir_startino, rp->ir_startino, ARCH_CONVERT); + kp = &key; + } + } + /* + * Decrement and log the number of entries in the block. + */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * Is this the root level? If so, we're almost done. + */ + if (level == cur->bc_nlevels - 1) { + /* + * If this is the root level, + * and there's only one entry left, + * and it's NOT the leaf level, + * then we can get rid of this level. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == 1 && level > 0) { + agbp = cur->bc_private.i.agbp; + agi = XFS_BUF_TO_AGI(agbp); + /* + * pp is still set to the first pointer in the block. + * Make it the new root of the btree. + */ + bno = INT_GET(agi->agi_root, ARCH_CONVERT); + INT_COPY(agi->agi_root, *pp, ARCH_CONVERT); + INT_MOD(agi->agi_level, ARCH_CONVERT, -1); + /* + * Free the block. + */ + if (error = xfs_free_extent(cur->bc_tp, bno, 1)) + return error; + xfs_trans_binval(cur->bc_tp, bp); + xfs_ialloc_log_agi(cur->bc_tp, agbp, + XFS_AGI_ROOT | XFS_AGI_LEVEL); + /* + * Update the cursor so there's one fewer level. + */ + cur->bc_bufs[level] = NULL; + cur->bc_nlevels--; + /* + * To ensure that the freed block is not used for + * user data until this transaction is permanent, + * we lock the agf buffer for this ag until the + * transaction record makes it to the on-disk log. + */ + agfbno = XFS_AG_DADDR(cur->bc_mp, + cur->bc_private.i.agno, + XFS_AGF_DADDR); + if (error = xfs_trans_read_buf(cur->bc_mp, cur->bc_tp, + cur->bc_mp->m_ddev_targp, agfbno, 1, 0, + &agfbp)) + return error; + ASSERT(!XFS_BUF_GETERROR(agfbp)); + xfs_trans_bhold_until_committed(cur->bc_tp, agfbp); + } else if (level > 0 && + (error = xfs_inobt_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * If we deleted the leftmost entry in the block, update the + * key values above us in the tree. + */ + if (ptr == 1 && (error = xfs_inobt_updkey(cur, kp, level + 1))) + return error; + /* + * If the number of records remaining in the block is at least + * the minimum, we're done. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_INOBT_BLOCK_MINRECS(level, cur)) { + if (level > 0 && + (error = xfs_inobt_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * Otherwise, we have to move some records around to keep the + * tree balanced. Look at the left and right sibling blocks to + * see if we can re-balance by moving only one record. + */ + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + bno = NULLAGBLOCK; + ASSERT(rbno != NULLAGBLOCK || lbno != NULLAGBLOCK); + /* + * Duplicate the cursor so our btree manipulations here won't + * disrupt the next level up. + */ + if (error = xfs_btree_dup_cursor(cur, &tcur)) + return error; + /* + * If there's a right sibling, see if it's ok to shift an entry + * out of it. + */ + if (rbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the last entry in the next block. + * Actually any entry but the first would suffice. + */ + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (error = xfs_inobt_increment(tcur, level, &i)) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Grab a pointer to the block. + */ + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); +#ifdef DEBUG + if (error = xfs_btree_check_sblock(cur, right, level, rbp)) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + /* + * If right block is full enough so that removing one entry + * won't make it too empty, and left-shifting an entry out + * of right to us works, we're done. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_INOBT_BLOCK_MINRECS(level, cur)) { + if (error = xfs_inobt_lshift(tcur, level, &i)) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_INOBT_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level > 0 && + (error = xfs_inobt_decrement(cur, level, + &i))) + return error; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference, and fix up the temp cursor to point + * to our block again (last record). + */ + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLAGBLOCK) { + xfs_btree_firstrec(tcur, level); + if (error = xfs_inobt_decrement(tcur, level, &i)) + goto error0; + } + } + /* + * If there's a left sibling, see if it's ok to shift an entry + * out of it. + */ + if (lbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the first entry in the + * previous block. + */ + xfs_btree_firstrec(tcur, level); + if (error = xfs_inobt_decrement(tcur, level, &i)) + goto error0; + xfs_btree_firstrec(tcur, level); + /* + * Grab a pointer to the block. + */ + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if (error = xfs_btree_check_sblock(cur, left, level, lbp)) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + /* + * If left block is full enough so that removing one entry + * won't make it too empty, and right-shifting an entry out + * of left to us works, we're done. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_INOBT_BLOCK_MINRECS(level, cur)) { + if (error = xfs_inobt_rshift(tcur, level, &i)) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_INOBT_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level == 0) + cur->bc_ptrs[0]++; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference. + */ + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * Delete the temp cursor, we're done with it. + */ + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + /* + * If here, we need to do a join to keep the tree balanced. + */ + ASSERT(bno != NULLAGBLOCK); + /* + * See if we can join with the left neighbor block. + */ + if (lbno != NULLAGBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + /* + * Set "right" to be the starting block, + * "left" to be the left neighbor. + */ + rbno = bno; + right = block; + rbp = bp; + if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, lbno, 0, &lbp, + XFS_INO_BTREE_REF)) + return error; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if (error = xfs_btree_check_sblock(cur, left, level, lbp)) + return error; + } + /* + * If that won't work, see if we can join with the right neighbor block. + */ + else if (rbno != NULLAGBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + /* + * Set "left" to be the starting block, + * "right" to be the right neighbor. + */ + lbno = bno; + left = block; + lbp = bp; + if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, rbno, 0, &rbp, + XFS_INO_BTREE_REF)) + return error; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if (error = xfs_btree_check_sblock(cur, right, level, rbp)) + return error; + } + /* + * Otherwise, we can't fix the imbalance. + * Just return. This is probably a logic error, but it's not fatal. + */ + else { + if (level > 0 && (error = xfs_inobt_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * We're now going to join "left" and "right" by moving all the stuff + * in "right" to "left" and deleting "right". + */ + if (level > 0) { + /* + * It's a non-leaf. Move keys and pointers. + */ + lkp = XFS_INOBT_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + lpp = XFS_INOBT_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if (error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level)) + return error; + } +#endif + bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); + bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); + xfs_inobt_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf. Move records. + */ + lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp)); + xfs_inobt_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } + /* + * Fix up the number of records in the surviving block. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + /* + * Fix up the right block pointer in the surviving block, and log it. + */ + INT_COPY(left->bb_rightsib, right->bb_rightsib, ARCH_CONVERT); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there is a right sibling now, make it point to the + * remaining block. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_inobt_block_t *rrblock; + xfs_buf_t *rrbp; + + if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_INO_BTREE_REF)) + return error; + rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp); + if (error = xfs_btree_check_sblock(cur, rrblock, level, rrbp)) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_inobt_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * Free the deleting block. + */ + if (error = xfs_free_extent(cur->bc_tp, rbno, 1)) + return error; + xfs_trans_binval(cur->bc_tp, rbp); + /* + * To ensure that the freed block is not used for + * user data until this transaction is permanent, + * we lock the agf buffer for this ag until the + * transaction record makes it to the on-disk log. + */ + agfbno = XFS_AG_DADDR(cur->bc_mp, cur->bc_private.i.agno, + XFS_AGF_DADDR); + if (error = xfs_trans_read_buf(cur->bc_mp, cur->bc_tp, + cur->bc_mp->m_ddev_targp, agfbno, 1, 0, &agfbp)) + return error; + ASSERT(!XFS_BUF_GETERROR(agfbp)); + xfs_trans_bhold_until_committed(cur->bc_tp, agfbp); + /* + * If we joined with the left neighbor, set the buffer in the + * cursor to the left block, and fix up the index. + */ + if (bp != lbp) { + cur->bc_bufs[level] = lbp; + cur->bc_ptrs[level] += INT_GET(left->bb_numrecs, ARCH_CONVERT); + cur->bc_ra[level] = 0; + } + /* + * If we joined with the right neighbor and there's a level above + * us, increment the cursor at that level. + */ + else if (level + 1 < cur->bc_nlevels && + (error = xfs_inobt_increment(cur, level + 1, &i))) { + return error; + } + /* + * Readjust the ptr at this level if it's not a leaf, since it's + * still pointing at the deletion point, which makes the cursor + * inconsistent. If this makes the ptr 0, the caller fixes it up. + * We can't use decrement because it would change the next level up. + */ + if (level > 0) + cur->bc_ptrs[level]--; + /* + * Return value means the next level up has something to do. + */ + *stat = 2; + return 0; + +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} +#endif /* _NOTYET_ */ + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_inobt_insrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to insert record at */ + xfs_agblock_t *bnop, /* i/o: block number inserted */ + xfs_inobt_rec_t *recp, /* i/o: record data inserted */ + xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block record/key lives in */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* key value being inserted */ + xfs_inobt_key_t *kp=NULL; /* pointer to btree keys */ + xfs_agblock_t nbno; /* block number of allocated block */ + xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ + xfs_inobt_key_t nkey; /* new key value, from split */ + xfs_inobt_rec_t nrec; /* new record value, for caller */ + int optr; /* old ptr value */ + xfs_inobt_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_inobt_rec_t *rp=NULL; /* pointer to btree records */ + + /* + * If we made it to the root level, allocate a new root block + * and we're done. + */ + if (level >= cur->bc_nlevels) { + error = xfs_inobt_newroot(cur, &i); + *bnop = NULLAGBLOCK; + *stat = i; + return error; + } + /* + * Make a key out of the record data to be inserted, and save it. + */ + key.ir_startino = recp->ir_startino; /* INT_: direct copy */ + optr = ptr = cur->bc_ptrs[level]; + /* + * If we're off the left edge, return failure. + */ + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get pointers to the btree buffer and block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; + /* + * Check that the new entry is being inserted in the right place. + */ + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_INOBT_REC_ADDR(block, ptr, cur); + xfs_btree_check_rec(cur->bc_btnum, recp, rp); + } else { + kp = XFS_INOBT_KEY_ADDR(block, ptr, cur); + xfs_btree_check_key(cur->bc_btnum, &key, kp); + } + } +#endif + nbno = NULLAGBLOCK; + ncur = (xfs_btree_cur_t *)0; + /* + * If the block is full, we can't insert the new entry until we + * make the block un-full. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + /* + * First, try shifting an entry to the right neighbor. + */ + if ((error = xfs_inobt_rshift(cur, level, &i))) + return error; + if (i) { + /* nothing */ + } + /* + * Next, try shifting an entry to the left neighbor. + */ + else { + if ((error = xfs_inobt_lshift(cur, level, &i))) + return error; + if (i) { + optr = ptr = cur->bc_ptrs[level]; + } else { + /* + * Next, try splitting the current block + * in half. If this works we have to + * re-set our variables because + * we could be in a different block now. + */ + if ((error = xfs_inobt_split(cur, level, &nbno, + &nkey, &ncur, &i))) + return error; + if (i) { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, + block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + nrec.ir_startino = nkey.ir_startino; /* INT_: direct copy */ + } else { + /* + * Otherwise the insert fails. + */ + *stat = 0; + return 0; + } + } + } + } + /* + * At this point we know there's room for our new entry in the block + * we're pointing at. + */ + if (level > 0) { + /* + * It's a non-leaf entry. Make a hole for the new data + * in the key and ptr regions of the block. + */ + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); + ovbcopy(&pp[ptr - 1], &pp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); + /* + * Now stuff the new data in, bump numrecs and log the new data. + */ +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, *bnop, level))) + return error; +#endif + kp[ptr - 1] = key; /* INT_: struct copy */ + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf entry. Make a hole for the new record. + */ + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + /* + * Now stuff the new record in, bump numrecs + * and log the new data. + */ + rp[ptr - 1] = *recp; /* INT_: struct copy */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } + /* + * Log the new number of records in the btree header. + */ + xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); +#ifdef DEBUG + /* + * Check that the key/record is in the right place, now. + */ + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) + xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, + rp + ptr); + else + xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, + kp + ptr); + } +#endif + /* + * If we inserted at the start of a block, update the parents' keys. + */ + if (optr == 1 && (error = xfs_inobt_updkey(cur, &key, level + 1))) + return error; + /* + * Return the new block number, if any. + * If there is one, give back a record value and a cursor too. + */ + *bnop = nbno; + if (nbno != NULLAGBLOCK) { + *recp = nrec; /* INT_: struct copy */ + *curp = ncur; + } + *stat = 1; + return 0; +} + +/* + * Log header fields from a btree block. + */ +STATIC void +xfs_inobt_log_block( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer containing btree block */ + int fields) /* mask of fields: XFS_BB_... */ +{ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + static const short offsets[] = { /* table of offsets */ + offsetof(xfs_inobt_block_t, bb_magic), + offsetof(xfs_inobt_block_t, bb_level), + offsetof(xfs_inobt_block_t, bb_numrecs), + offsetof(xfs_inobt_block_t, bb_leftsib), + offsetof(xfs_inobt_block_t, bb_rightsib), + sizeof(xfs_inobt_block_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Log keys from a btree block (nonleaf). + */ +STATIC void +xfs_inobt_log_keys( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int kfirst, /* index of first key to log */ + int klast) /* index of last key to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + xfs_inobt_key_t *kp; /* key pointer in btree block */ + int last; /* last byte offset logged */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log block pointer fields from a btree block (nonleaf). + */ +STATIC void +xfs_inobt_log_ptrs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int pfirst, /* index of first pointer to log */ + int plast) /* index of last pointer to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_inobt_ptr_t *pp; /* block-pointer pointer in btree blk */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log records from a btree block (leaf). + */ +STATIC void +xfs_inobt_log_recs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int rfirst, /* index of first record to log */ + int rlast) /* index of last record to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_inobt_rec_t *rp; /* record pointer for btree block */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + * Return 0 if can't find any such record, 1 for success. + */ +STATIC int /* error */ +xfs_inobt_lookup( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_lookup_t dir, /* <=, ==, or >= */ + int *stat) /* success/failure */ +{ + xfs_agblock_t agbno; /* a.g. relative btree block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_inobt_block_t *block=NULL; /* current btree block */ + int diff; /* difference for the current key */ + int error; /* error return value */ + int keyno=0; /* current key number */ + int level; /* level in the btree */ + xfs_mount_t *mp; /* file system mount point */ + + /* + * Get the allocation group header, and the root block number. + */ + mp = cur->bc_mp; + { + xfs_agi_t *agi; /* a.g. inode header */ + + agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); + agno = INT_GET(agi->agi_seqno, ARCH_CONVERT); + agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + } + /* + * Iterate over each level in the btree, starting at the root. + * For each level above the leaves, find the key we need, based + * on the lookup record, then follow the corresponding block + * pointer down to the next level. + */ + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + xfs_buf_t *bp; /* buffer pointer for btree block */ + xfs_daddr_t d; /* disk address of btree block */ + + /* + * Get the disk address we're looking for. + */ + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + /* + * If the old buffer at this level is for a different block, + * throw it away, otherwise just use it. + */ + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + agno, agbno, 0, &bp, XFS_INO_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_INOBT_BLOCK(bp); + /* + * If we already had a key match at a higher level, we know + * we need to use the first entry in this block. + */ + if (diff == 0) + keyno = 1; + /* + * Otherwise we need to search this block. Do a binary search. + */ + else { + int high; /* high entry number */ + xfs_inobt_key_t *kkbase=NULL;/* base of keys in block */ + xfs_inobt_rec_t *krbase=NULL;/* base of records in block */ + int low; /* low entry number */ + + /* + * Get a pointer to keys or records. + */ + if (level > 0) + kkbase = XFS_INOBT_KEY_ADDR(block, 1, cur); + else + krbase = XFS_INOBT_REC_ADDR(block, 1, cur); + /* + * Set low and high entry numbers, 1-based. + */ + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + /* + * If the block is empty, the tree must + * be an empty leaf. + */ + ASSERT(level == 0 && cur->bc_nlevels == 1); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + *stat = 0; + return 0; + } + /* + * Binary search the block. + */ + while (low <= high) { + xfs_agino_t startino; /* key value */ + + /* + * keyno is average of low and high. + */ + keyno = (low + high) >> 1; + /* + * Get startino. + */ + if (level > 0) { + xfs_inobt_key_t *kkp; + + kkp = kkbase + keyno - 1; + startino = INT_GET(kkp->ir_startino, ARCH_CONVERT); + } else { + xfs_inobt_rec_t *krp; + + krp = krbase + keyno - 1; + startino = INT_GET(krp->ir_startino, ARCH_CONVERT); + } + /* + * Compute difference to get next direction. + */ + diff = (int)startino - cur->bc_rec.i.ir_startino; + /* + * Less than, move right. + */ + if (diff < 0) + low = keyno + 1; + /* + * Greater than, move left. + */ + else if (diff > 0) + high = keyno - 1; + /* + * Equal, we're done. + */ + else + break; + } + } + /* + * If there are more levels, set up for the next level + * by getting the block number and filling in the cursor. + */ + if (level > 0) { + /* + * If we moved left, need the previous key number, + * unless there isn't one. + */ + if (diff > 0 && --keyno < 1) + keyno = 1; + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, keyno, cur), ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, agbno, level))) + return error; +#endif + cur->bc_ptrs[level] = keyno; + } + } + /* + * Done with the search. + * See if we need to adjust the results. + */ + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && + keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + int i; + + cur->bc_ptrs[0] = keyno; + if ((error = xfs_inobt_increment(cur, 0, &i))) + return error; + ASSERT(i == 1); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + /* + * Return if we succeeded or not. + */ + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) + *stat = 0; + else + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_inobt_lshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef DEBUG + int i; /* loop index */ +#endif + xfs_inobt_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left neighbor block */ + xfs_inobt_block_t *left; /* left neighbor btree block */ + xfs_inobt_key_t *lkp=NULL; /* key pointer for left block */ + xfs_inobt_ptr_t *lpp; /* address pointer for left block */ + xfs_inobt_rec_t *lrp=NULL; /* record pointer for left block */ + int nrec; /* new number of left block entries */ + xfs_buf_t *rbp; /* buffer for right (current) block */ + xfs_inobt_block_t *right; /* right (current) btree block */ + xfs_inobt_key_t *rkp=NULL; /* key pointer for right block */ + xfs_inobt_ptr_t *rpp=NULL; /* address pointer for right block */ + xfs_inobt_rec_t *rrp=NULL; /* record pointer for right block */ + + /* + * Set up variables for this block as "right". + */ + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; +#endif + /* + * If we've got no left sibling then we can't shift an entry left. + */ + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] <= 1) { + *stat = 0; + return 0; + } + /* + * Set up the left neighbor as "left". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, &lbp, + XFS_INO_BTREE_REF))) + return error; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + nrec = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + /* + * If non-leaf, copy a key and a ptr to the left block. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, nrec, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + *lkp = *rkp; + xfs_inobt_log_keys(cur, lbp, nrec, nrec); + lpp = XFS_INOBT_PTR_ADDR(left, nrec, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) + return error; +#endif + *lpp = *rpp; /* INT_: no-change copy */ + xfs_inobt_log_ptrs(cur, lbp, nrec, nrec); + } + /* + * If leaf, copy a record to the left block. + */ + else { + lrp = XFS_INOBT_REC_ADDR(left, nrec, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + *lrp = *rrp; + xfs_inobt_log_recs(cur, lbp, nrec, nrec); + } + /* + * Bump and log left's numrecs, decrement and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp); + else + xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); +#endif + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Slide the contents of right down one entry. + */ + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) + return error; + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + key.ir_startino = rrp->ir_startino; /* INT_: direct copy */ + rkp = &key; + } + /* + * Update the parent key values of right. + */ + if ((error = xfs_inobt_updkey(cur, rkp, level + 1))) + return error; + /* + * Slide the cursor value left one. + */ + cur->bc_ptrs[level]--; + *stat = 1; + return 0; +} + +/* + * Allocate a new root block, fill it in. + */ +STATIC int /* error */ +xfs_inobt_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + xfs_agi_t *agi; /* a.g. inode header */ + xfs_alloc_arg_t args; /* allocation argument structure */ + xfs_inobt_block_t *block; /* one half of the old root block */ + xfs_buf_t *bp; /* buffer containing block */ + int error; /* error return value */ + xfs_inobt_key_t *kp; /* btree key pointer */ + xfs_agblock_t lbno; /* left block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_inobt_block_t *left; /* left btree block */ + xfs_buf_t *nbp; /* new (root) buffer */ + xfs_inobt_block_t *new; /* new (root) btree block */ + int nptr; /* new value for key index, 1 or 2 */ + xfs_inobt_ptr_t *pp; /* btree address pointer */ + xfs_agblock_t rbno; /* right block number */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_inobt_block_t *right; /* right btree block */ + xfs_inobt_rec_t *rp; /* btree record pointer */ + + ASSERT(cur->bc_nlevels < XFS_IN_MAXLEVELS(cur->bc_mp)); + + /* + * Get a block & a buffer. + */ + agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, + INT_GET(agi->agi_root, ARCH_CONVERT)); + args.mod = args.minleft = args.alignment = args.total = args.wasdel = + args.isfl = args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) + return error; + /* + * None available, we fail. + */ + if (args.fsbno == NULLFSBLOCK) { + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + nbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0); + new = XFS_BUF_TO_INOBT_BLOCK(nbp); + /* + * Set the root data in the a.g. inode structure. + */ + INT_SET(agi->agi_root, ARCH_CONVERT, args.agbno); + INT_MOD(agi->agi_level, ARCH_CONVERT, 1); + xfs_ialloc_log_agi(args.tp, cur->bc_private.i.agbp, + XFS_AGI_ROOT | XFS_AGI_LEVEL); + /* + * At the previous root level there are now two blocks: the old + * root, and the new block generated when it was split. + * We don't know which one the cursor is pointing at, so we + * set up variables "left" and "right" for each case. + */ + bp = cur->bc_bufs[cur->bc_nlevels - 1]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, cur->bc_nlevels - 1, bp))) + return error; +#endif + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + /* + * Our block is left, pick up the right block. + */ + lbp = bp; + lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp)); + left = block; + rbno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + rbno, 0, &rbp, XFS_INO_BTREE_REF))) + return error; + bp = rbp; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, + cur->bc_nlevels - 1, rbp))) + return error; + nptr = 1; + } else { + /* + * Our block is right, pick up the left block. + */ + rbp = bp; + rbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(rbp)); + right = block; + lbno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + lbno, 0, &lbp, XFS_INO_BTREE_REF))) + return error; + bp = lbp; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, + cur->bc_nlevels - 1, lbp))) + return error; + nptr = 2; + } + /* + * Fill in the new block's btree header and log it. + */ + INT_SET(new->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + INT_SET(new->bb_level, ARCH_CONVERT, (__uint16_t)cur->bc_nlevels); + INT_SET(new->bb_numrecs, ARCH_CONVERT, 2); + INT_SET(new->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(new->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + xfs_inobt_log_block(args.tp, nbp, XFS_BB_ALL_BITS); + ASSERT(lbno != NULLAGBLOCK && rbno != NULLAGBLOCK); + /* + * Fill in the key data in the new root. + */ + kp = XFS_INOBT_KEY_ADDR(new, 1, cur); + if (INT_GET(left->bb_level, ARCH_CONVERT) > 0) { + kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur); /* INT_: struct copy */ + kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur); /* INT_: struct copy */ + } else { + rp = XFS_INOBT_REC_ADDR(left, 1, cur); + INT_COPY(kp[0].ir_startino, rp->ir_startino, ARCH_CONVERT); + rp = XFS_INOBT_REC_ADDR(right, 1, cur); + INT_COPY(kp[1].ir_startino, rp->ir_startino, ARCH_CONVERT); + } + xfs_inobt_log_keys(cur, nbp, 1, 2); + /* + * Fill in the pointer data in the new root. + */ + pp = XFS_INOBT_PTR_ADDR(new, 1, cur); + INT_SET(pp[0], ARCH_CONVERT, lbno); + INT_SET(pp[1], ARCH_CONVERT, rbno); + xfs_inobt_log_ptrs(cur, nbp, 1, 2); + /* + * Fix up the cursor. + */ + xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); + cur->bc_ptrs[cur->bc_nlevels] = nptr; + cur->bc_nlevels++; + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_inobt_rshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left (current) block */ + xfs_inobt_block_t *left; /* left (current) btree block */ + xfs_inobt_key_t *lkp; /* key pointer for left block */ + xfs_inobt_ptr_t *lpp; /* address pointer for left block */ + xfs_inobt_rec_t *lrp; /* record pointer for left block */ + xfs_buf_t *rbp; /* buffer for right neighbor block */ + xfs_inobt_block_t *right; /* right neighbor btree block */ + xfs_inobt_key_t *rkp; /* key pointer for right block */ + xfs_inobt_ptr_t *rpp; /* address pointer for right block */ + xfs_inobt_rec_t *rrp=NULL; /* record pointer for right block */ + xfs_btree_cur_t *tcur; /* temporary cursor */ + + /* + * Set up variables for this block as "left". + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * If we've got no right sibling then we can't shift an entry right. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * Set up the right neighbor as "right". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rbp, + XFS_INO_BTREE_REF))) + return error; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + /* + * Make a hole at the start of the right neighbor block, then + * copy the last left block entry to the hole. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_INOBT_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) + return error; +#endif + *rkp = *lkp; /* INT_: no change copy */ + *rpp = *lpp; /* INT_: no change copy */ + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + } else { + lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + key.ir_startino = rrp->ir_startino; /* INT_: direct copy */ + rkp = &key; + } + /* + * Decrement and log left's numrecs, bump and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); + else + xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1); +#endif + xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Using a temporary cursor, update the parent key values of the + * block on the right. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + xfs_btree_lastrec(tcur, level); + if ((error = xfs_inobt_increment(tcur, level, &i)) || + (error = xfs_inobt_updkey(tcur, rkp, level + 1))) { + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + *stat = 1; + return 0; +} + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_inobt_split( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to split */ + xfs_agblock_t *bnop, /* output: block number allocated */ + xfs_inobt_key_t *keyp, /* output: first key of new block */ + xfs_btree_cur_t **curp, /* output: new cursor */ + int *stat) /* success/failure */ +{ + xfs_alloc_arg_t args; /* allocation argument structure */ + int error; /* error return value */ + int i; /* loop index/record number */ + xfs_agblock_t lbno; /* left (current) block number */ + xfs_buf_t *lbp; /* buffer for left block */ + xfs_inobt_block_t *left; /* left (current) btree block */ + xfs_inobt_key_t *lkp; /* left btree key pointer */ + xfs_inobt_ptr_t *lpp; /* left btree address pointer */ + xfs_inobt_rec_t *lrp; /* left btree record pointer */ + xfs_buf_t *rbp; /* buffer for right block */ + xfs_inobt_block_t *right; /* right (new) btree block */ + xfs_inobt_key_t *rkp; /* right btree key pointer */ + xfs_inobt_ptr_t *rpp; /* right btree address pointer */ + xfs_inobt_rec_t *rrp; /* right btree record pointer */ + + /* + * Set up left block (current one). + */ + lbp = cur->bc_bufs[level]; + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp)); + /* + * Allocate the new block. + * If we can't do it, we're toast. Give up. + */ + args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, lbno); + args.mod = args.minleft = args.alignment = args.total = args.wasdel = + args.isfl = args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) + return error; + if (args.fsbno == NULLFSBLOCK) { + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + rbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0); + /* + * Set up the new block as "right". + */ + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + /* + * "Left" is the current (according to the cursor) block. + */ + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * Fill in the btree header for the new block. + */ + INT_SET(right->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + /* + * Make sure that if there's an odd number of entries now, that + * each new block will have the same number of entries. + */ + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + /* + * For non-leaf blocks, copy keys and addresses over to the new block. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, i, cur); + lpp = XFS_INOBT_PTR_ADDR(left, i, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + *keyp = *rkp; + } + /* + * For leaf blocks, copy records over to the new block. + */ + else { + lrp = XFS_INOBT_REC_ADDR(left, i, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->ir_startino = rrp->ir_startino; /* INT_: direct copy */ + } + /* + * Find the left block number by looking in the buffer. + * Adjust numrecs, sibling pointers. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, args.agbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_inobt_log_block(args.tp, rbp, XFS_BB_ALL_BITS); + xfs_inobt_log_block(args.tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there's a block to the new block's right, make that block + * point back to right instead of to left. + */ + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_inobt_block_t *rrblock; /* rr btree block */ + xfs_buf_t *rrbp; /* buffer for rrblock */ + + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_INO_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, args.agbno); + xfs_inobt_log_block(args.tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * If the cursor is really in the right block, move it there. + * If it's just pointing past the last entry in left, then we'll + * insert there, so don't change anything in that case. + */ + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If there are more levels, we'll need another cursor which refers + * the right block, no matter where this cursor was. + */ + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) + return error; + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = args.agbno; + *stat = 1; + return 0; +} + +/* + * Update keys at all levels from here to the root along the cursor's path. + */ +STATIC int /* error */ +xfs_inobt_updkey( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_inobt_key_t *keyp, /* new key value to update to */ + int level) /* starting level for update */ +{ + int ptr; /* index of key in block */ + + /* + * Go up the tree from this level toward the root. + * At each level, update the key value to the value input. + * Stop when we reach a level where the cursor isn't pointing + * at the first entry in the block. + */ + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + xfs_buf_t *bp; /* buffer for block */ + xfs_inobt_block_t *block; /* btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + xfs_inobt_key_t *kp; /* ptr to btree block keys */ + + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_INOBT_KEY_ADDR(block, ptr, cur); + *kp = *keyp; + xfs_inobt_log_keys(cur, bp, ptr, ptr); + } + return 0; +} + +/* + * Externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_decrement( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block */ + int error; + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the left at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + /* + * Decrement the ptr at this level. If we're still in the block + * then we're done. + */ + if (--cur->bc_ptrs[level] > 0) { + *stat = 1; + return 0; + } + /* + * Get a pointer to the btree block. + */ + block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[level]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, + cur->bc_bufs[level]))) + return error; +#endif + /* + * If we just went off the left edge of the tree, return failure. + */ + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree decrementing pointers. + * Stop when we don't go off the left edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + /* + * Read-ahead the left block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ + + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, agbno, 0, &bp, + XFS_INO_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +#ifdef _NOTYET_ +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_inobt_delete( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; + int i; /* result code */ + int level; /* btree level */ + + /* + * Go up the tree, starting at leaf level. + * If 2 is returned then a join was done; go to the next level. + * Otherwise we are done. + */ + for (level = 0, i = 2; i == 2; level++) { + if (error = xfs_inobt_delrec(cur, level, &i)) + return error; + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if (error = xfs_inobt_decrement(cur, level, &i)) + return error; + break; + } + } + } + *stat = i; + return 0; +} +#endif /* _NOTYET_ */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_inobt_get_rec( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t *ino, /* output: starting inode of chunk */ + __int32_t *fcnt, /* output: number of free inodes */ + xfs_inofree_t *free, /* output: free inode mask */ + int *stat, /* output: success/failure */ + xfs_arch_t arch) /* input: architecture */ +{ + xfs_inobt_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + int ptr; /* record number */ + xfs_inobt_rec_t *rec; /* record data */ + + bp = cur->bc_bufs[0]; + ptr = cur->bc_ptrs[0]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, bp))) + return error; +#endif + /* + * Off the right end or left end, return failure. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + /* + * Point to the record and extract its data. + */ + rec = XFS_INOBT_REC_ADDR(block, ptr, cur); + ASSERT(arch == ARCH_NOCONVERT || arch == ARCH_CONVERT); + if (arch == ARCH_NOCONVERT) { + *ino = INT_GET(rec->ir_startino, ARCH_CONVERT); + *fcnt = INT_GET(rec->ir_freecount, ARCH_CONVERT); + *free = INT_GET(rec->ir_free, ARCH_CONVERT); + } else { + INT_COPY(*ino, rec->ir_startino, ARCH_CONVERT); + INT_COPY(*fcnt, rec->ir_freecount, ARCH_CONVERT); + INT_COPY(*free, rec->ir_free, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_increment( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the right at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + /* + * Get a pointer to the btree block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Increment the ptr at this level. If we're still in the block + * then we're done. + */ + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 1; + return 0; + } + /* + * If we just went off the right edge of the tree, return failure. + */ + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree incrementing pointers. + * Stop when we don't go off the right edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + bp = cur->bc_bufs[lev]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + /* + * Read-ahead the right block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (bp = cur->bc_bufs[lev], block = XFS_BUF_TO_INOBT_BLOCK(bp); + lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, agbno, 0, &bp, + XFS_INO_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = 1; + } + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_inobt_insert( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result value, 0 for failure */ + int level; /* current level number in btree */ + xfs_agblock_t nbno; /* new block number (split result) */ + xfs_btree_cur_t *ncur; /* new cursor (split result) */ + xfs_inobt_rec_t nrec; /* record being inserted this level */ + xfs_btree_cur_t *pcur; /* previous level's cursor */ + + level = 0; + nbno = NULLAGBLOCK; + INT_SET(nrec.ir_startino, ARCH_CONVERT, cur->bc_rec.i.ir_startino); + INT_SET(nrec.ir_freecount, ARCH_CONVERT, cur->bc_rec.i.ir_freecount); + INT_SET(nrec.ir_free, ARCH_CONVERT, cur->bc_rec.i.ir_free); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + /* + * Loop going up the tree, starting at the leaf level. + * Stop when we don't get a split block, that must mean that + * the insert is finished with this level. + */ + do { + /* + * Insert nrec/nbno into this level of the tree. + * Note if we fail, nbno will be null. + */ + if ((error = xfs_inobt_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + return error; + } + /* + * See if the cursor we just used is trash. + * Can't trash the caller's cursor, but otherwise we should + * if ncur is a new cursor or we're about to be done. + */ + if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + /* + * If we got a new cursor, switch to it. + */ + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLAGBLOCK); + *stat = i; + return 0; +} + +/* + * Lookup the record equal to ino in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_eq( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +/* + * Lookup the first record greater than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_ge( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_GE, stat); +} + +/* + * Lookup the first record less than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_le( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Update the record referred to by cur, to the value given + * by [ino, fcnt, free]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_inobt_update( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free) /* free inode mask */ +{ + xfs_inobt_block_t *block; /* btree block to update */ + xfs_buf_t *bp; /* buffer containing btree block */ + int error; /* error return value */ + int ptr; /* current record number (updating) */ + xfs_inobt_rec_t *rp; /* pointer to updated record */ + + /* + * Pick up the current block. + */ + bp = cur->bc_bufs[0]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, bp))) + return error; +#endif + /* + * Get the address of the rec to be updated. + */ + ptr = cur->bc_ptrs[0]; + rp = XFS_INOBT_REC_ADDR(block, ptr, cur); + /* + * Fill in the new contents and log them. + */ + INT_SET(rp->ir_startino, ARCH_CONVERT, ino); + INT_SET(rp->ir_freecount, ARCH_CONVERT, fcnt); + INT_SET(rp->ir_free, ARCH_CONVERT, free); + xfs_inobt_log_recs(cur, bp, ptr, ptr); + /* + * Updating first record in leaf. Pass new key value up to our parent. + */ + if (ptr == 1) { + xfs_inobt_key_t key; /* key containing [ino] */ + + INT_SET(key.ir_startino, ARCH_CONVERT, ino); + if ((error = xfs_inobt_updkey(cur, &key, 1))) + return error; + } + return 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_ialloc_btree.h linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc_btree.h --- linux-2.4.19/fs/xfs/xfs_ialloc_btree.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_ialloc_btree.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IALLOC_BTREE_H__ +#define __XFS_IALLOC_BTREE_H__ + +/* + * Inode map on-disk structures + */ + +struct xfs_buf; +struct xfs_btree_cur; +struct xfs_btree_sblock; +struct xfs_mount; + +/* + * There is a btree for the inode map per allocation group. + */ +#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ + +typedef __uint64_t xfs_inofree_t; +#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) +#define XFS_INODES_PER_CHUNK_LOG (XFS_NBBYLOG + 3) +#define XFS_INOBT_ALL_FREE ((xfs_inofree_t)-1) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_MASKN) +xfs_inofree_t xfs_inobt_maskn(int i, int n); +#define XFS_INOBT_MASKN(i,n) xfs_inobt_maskn(i,n) +#else +#define XFS_INOBT_MASKN(i,n) \ + ((((n) >= XFS_INODES_PER_CHUNK ? \ + (xfs_inofree_t)0 : ((xfs_inofree_t)1 << (n))) - 1) << (i)) +#endif + +/* + * Data record structure + */ +typedef struct xfs_inobt_rec +{ + xfs_agino_t ir_startino; /* starting inode number */ + __int32_t ir_freecount; /* count of free inodes (set bits) */ + xfs_inofree_t ir_free; /* free inode mask */ +} xfs_inobt_rec_t; + +/* + * Key structure + */ +typedef struct xfs_inobt_key +{ + xfs_agino_t ir_startino; /* starting inode number */ +} xfs_inobt_key_t; + +typedef xfs_agblock_t xfs_inobt_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_sblock xfs_inobt_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_INOBT_BLOCK) +xfs_inobt_block_t *xfs_buf_to_inobt_block(struct xfs_buf *bp); +#define XFS_BUF_TO_INOBT_BLOCK(bp) xfs_buf_to_inobt_block(bp) +#else +#define XFS_BUF_TO_INOBT_BLOCK(bp) ((xfs_inobt_block_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Bit manipulations for ir_free. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_MASK) +xfs_inofree_t xfs_inobt_mask(int i); +#define XFS_INOBT_MASK(i) xfs_inobt_mask(i) +#else +#define XFS_INOBT_MASK(i) ((xfs_inofree_t)1 << (i)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE) +int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_IS_FREE(rp,i,arch) xfs_inobt_is_free(rp,i,arch) +#else +#define XFS_INOBT_IS_FREE(rp,i,arch) ((INT_GET((rp)->ir_free, arch) \ + & XFS_INOBT_MASK(i)) != 0) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE) +void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_SET_FREE(rp,i,arch) xfs_inobt_set_free(rp,i,arch) +#else +#define XFS_INOBT_SET_FREE(rp,i,arch) (INT_MOD_EXPR((rp)->ir_free, arch, |= XFS_INOBT_MASK(i))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_CLR_FREE) +void xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_CLR_FREE(rp,i,arch) xfs_inobt_clr_free(rp,i,arch) +#else +#define XFS_INOBT_CLR_FREE(rp,i,arch) (INT_MOD_EXPR((rp)->ir_free, arch, &= ~XFS_INOBT_MASK(i))) +#endif + +/* + * Real block structures have a size equal to the disk block size. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_SIZE) +int xfs_inobt_block_size(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_SIZE(lev,cur) xfs_inobt_block_size(lev,cur) +#else +#define XFS_INOBT_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_MAXRECS) +int xfs_inobt_block_maxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_MAXRECS(lev,cur) xfs_inobt_block_maxrecs(lev,cur) +#else +#define XFS_INOBT_BLOCK_MAXRECS(lev,cur) \ + ((cur)->bc_mp->m_inobt_mxr[lev != 0]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_MINRECS) +int xfs_inobt_block_minrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_MINRECS(lev,cur) xfs_inobt_block_minrecs(lev,cur) +#else +#define XFS_INOBT_BLOCK_MINRECS(lev,cur) \ + ((cur)->bc_mp->m_inobt_mnr[lev != 0]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_LAST_REC) +int xfs_inobt_is_last_rec(struct xfs_btree_cur *cur); +#define XFS_INOBT_IS_LAST_REC(cur) xfs_inobt_is_last_rec(cur) +#else +#define XFS_INOBT_IS_LAST_REC(cur) \ + ((cur)->bc_ptrs[0] == \ + INT_GET(XFS_BUF_TO_INOBT_BLOCK((cur)->bc_bufs[0])->bb_numrecs, ARCH_CONVERT)) +#endif + +/* + * Maximum number of inode btree levels. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IN_MAXLEVELS) +int xfs_in_maxlevels(struct xfs_mount *mp); +#define XFS_IN_MAXLEVELS(mp) xfs_in_maxlevels(mp) +#else +#define XFS_IN_MAXLEVELS(mp) ((mp)->m_in_maxlevels) +#endif + +/* + * block numbers in the AG. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IBT_BLOCK) +xfs_agblock_t xfs_ibt_block(struct xfs_mount *mp); +#define XFS_IBT_BLOCK(mp) xfs_ibt_block(mp) +#else +#define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_PREALLOC_BLOCKS) +xfs_agblock_t xfs_prealloc_blocks(struct xfs_mount *mp); +#define XFS_PREALLOC_BLOCKS(mp) xfs_prealloc_blocks(mp) +#else +#define XFS_PREALLOC_BLOCKS(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) +#endif + +/* + * Record, key, and pointer address macros for btree blocks. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_REC_ADDR) +xfs_inobt_rec_t * +xfs_inobt_rec_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_REC_ADDR(bb,i,cur) xfs_inobt_rec_addr(bb,i,cur) +#else +#define XFS_INOBT_REC_ADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_INOBT_BLOCK_SIZE(0,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(0, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_KEY_ADDR) +xfs_inobt_key_t * +xfs_inobt_key_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_KEY_ADDR(bb,i,cur) xfs_inobt_key_addr(bb,i,cur) +#else +#define XFS_INOBT_KEY_ADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(1, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_PTR_ADDR) +xfs_inobt_ptr_t * +xfs_inobt_ptr_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_PTR_ADDR(bb,i,cur) xfs_inobt_ptr_addr(bb,i,cur) +#else +#define XFS_INOBT_PTR_ADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(1, cur)) +#endif + +/* + * Prototypes for externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_decrement( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +#ifdef _NOTYET_ +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_inobt_delete( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ +#endif /* _NOTYET_ */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_inobt_get_rec( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t *ino, /* output: starting inode of chunk */ + __int32_t *fcnt, /* output: number of free inodes */ + xfs_inofree_t *free, /* output: free inode mask */ + int *stat, /* output: success/failure */ + xfs_arch_t arch); /* output: architecture */ + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_increment( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_inobt_insert( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Lookup the record equal to ino in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_eq( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Lookup the first record greater than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_ge( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Lookup the first record less than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_le( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Update the record referred to by cur, to the value given + * by [ino, fcnt, free]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_inobt_update( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free); /* free inode mask */ + +#endif /* __XFS_IALLOC_BTREE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_iget.c linux-2.4.19-sgi211r3/fs/xfs/xfs_iget.c --- linux-2.4.19/fs/xfs/xfs_iget.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_iget.c Fri Dec 13 10:22:56 2002 @@ -0,0 +1,1047 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * Initialize the inode hash table for the newly mounted file system. + * + * mp -- this is the mount point structure for the file system being + * initialized + */ +void +xfs_ihash_init(xfs_mount_t *mp) +{ + int i; + + mp->m_ihsize = XFS_BUCKETS(mp); + mp->m_ihash = (xfs_ihash_t *)kmem_zalloc(mp->m_ihsize + * sizeof(xfs_ihash_t), KM_SLEEP); + ASSERT(mp->m_ihash != NULL); + for (i = 0; i < mp->m_ihsize; i++) { + rwlock_init(&(mp->m_ihash[i].ih_lock)); + } +} + +/* + * Free up structures allocated by xfs_ihash_init, at unmount time. + */ +void +xfs_ihash_free(xfs_mount_t *mp) +{ + kmem_free(mp->m_ihash, mp->m_ihsize*sizeof(xfs_ihash_t)); + mp->m_ihash = NULL; +} + +/* + * Initialize the inode cluster hash table for the newly mounted file system. + * + * mp -- this is the mount point structure for the file system being + * initialized + */ +void +xfs_chash_init(xfs_mount_t *mp) +{ + int i; + + /* + * m_chash size is based on m_ihash + * with a minimum of 37 entries + */ + mp->m_chsize = (XFS_BUCKETS(mp)) / + (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); + if (mp->m_chsize < 37) { + mp->m_chsize = 37; + } + mp->m_chash = (xfs_chash_t *)kmem_zalloc(mp->m_chsize + * sizeof(xfs_chash_t), + KM_SLEEP); + ASSERT(mp->m_chash != NULL); + + for (i = 0; i < mp->m_chsize; i++) { + spinlock_init(&mp->m_chash[i].ch_lock,"xfshash"); + } +} + +/* + * Free up structures allocated by xfs_chash_init, at unmount time. + */ +void +xfs_chash_free(xfs_mount_t *mp) +{ + int i; + + for (i = 0; i < mp->m_chsize; i++) { + spinlock_destroy(&mp->m_chash[i].ch_lock); + } + + kmem_free(mp->m_chash, mp->m_chsize*sizeof(xfs_chash_t)); + mp->m_chash = NULL; +} + + +static inline void +xfs_iget_vnode_init( + xfs_mount_t *mp, + vnode_t *vp, + xfs_inode_t *ip) +{ + vp->v_vfsp = XFS_MTOVFS(mp); + vp->v_type = IFTOVT(ip->i_d.di_mode); +} + + +/* + * Look up an inode by number in the given file system. + * The inode is looked up in the hash table for the file system + * represented by the mount point parameter mp. Each bucket of + * the hash table is guarded by an individual semaphore. + * + * If the inode is found in the hash table, its corresponding vnode + * is obtained with a call to vn_get(). This call takes care of + * coordination with the reclamation of the inode and vnode. Note + * that the vmap structure is filled in while holding the hash lock. + * This gives us the state of the inode/vnode when we found it and + * is used for coordination in vn_get(). + * + * If it is not in core, read it in from the file system's device and + * add the inode into the hash table. + * + * The inode is locked according to the value of the lock_flags parameter. + * This flag parameter indicates how and if the inode's IO lock and inode lock + * should be taken. + * + * mp -- the mount point structure for the current file system. It points + * to the inode hash table. + * tp -- a pointer to the current transaction if there is one. This is + * simply passed through to the xfs_iread() call. + * ino -- the number of the inode desired. This is the unique identifier + * within the file system for the inode being requested. + * lock_flags -- flags indicating how to lock the inode. See the comment + * for xfs_ilock() for a list of valid values. + * bno -- the block number starting the buffer containing the inode, + * if known (as by bulkstat), else 0. + */ +STATIC int +xfs_iget_core( + vnode_t *vp, + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + uint lock_flags, + xfs_inode_t **ipp, + xfs_daddr_t bno) +{ + xfs_ihash_t *ih; + xfs_inode_t *ip; + xfs_inode_t *iq; + vnode_t *inode_vp; + ulong version; + int error; + /* REFERENCED */ + int newnode; + xfs_chash_t *ch; + xfs_chashlist_t *chl, *chlnew; + SPLDECL(s); + + + ih = XFS_IHASH(mp, ino); + +again: + read_lock(&ih->ih_lock); + + for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { + if (ip->i_ino == ino) { + + inode_vp = XFS_ITOV_NULL(ip); + + if (inode_vp == NULL) { + /* If IRECLAIM is set this inode is + * on its way out of the system, + * we need to pause and try again. + */ + if (ip->i_flags & XFS_IRECLAIM) { + read_unlock(&ih->ih_lock); + delay(1); + XFS_STATS_INC(xfsstats.xs_ig_frecycle); + + goto again; + } + + xfs_iget_vnode_init(mp, vp, ip); + + vn_trace_exit(vp, "xfs_iget.alloc", + (inst_t *)__return_address); + + bhv_desc_init(&(ip->i_bhv_desc), ip, vp, + &xfs_vnodeops); + vn_bhv_insert_initial(VN_BHV_HEAD(vp), + &(ip->i_bhv_desc)); + + XFS_STATS_INC(xfsstats.xs_ig_found); + + read_unlock(&ih->ih_lock); + goto finish_inode; + + } else if (vp != inode_vp) { + struct inode *inode = LINVFS_GET_IP(inode_vp); + + /* The inode is being torn down, pause and + * try again. + */ + if (inode->i_state & (I_FREEING | I_CLEAR)) { + read_unlock(&ih->ih_lock); + delay(1); + XFS_STATS_INC(xfsstats.xs_ig_frecycle); + + goto again; + } +/* Chances are the other vnode (the one in the inode) is being torn + * down right now, and we landed on top of it. Question is, what do + * we do? Unhook the old inode and hook up the new one? + */ + cmn_err(CE_PANIC, + "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p", + inode_vp, vp); + } + + read_unlock(&ih->ih_lock); + + XFS_STATS_INC(xfsstats.xs_ig_found); + + /* + * Make sure the vnode and the inode are hooked up + */ + xfs_iget_vnode_init(mp, vp, ip); + +finish_inode: + if (lock_flags != 0) { + xfs_ilock(ip, lock_flags); + } + + newnode = (ip->i_d.di_mode == 0); + if (newnode) { + xfs_iocore_inode_reinit(ip); + } + vn_trace_exit(vp, "xfs_iget.found", + (inst_t *)__return_address); + goto return_ip; + } + } + + /* + * Inode cache miss: save the hash chain version stamp and unlock + * the chain, so we don't deadlock in vn_alloc. + */ + XFS_STATS_INC(xfsstats.xs_ig_missed); + + version = ih->ih_version; + + read_unlock(&ih->ih_lock); + + /* + * Read the disk inode attributes into a new inode structure and get + * a new vnode for it. Initialize the inode lock so we can idestroy + * it soon if it's a dup. This should also initialize i_dev, i_ino, + * i_bno, i_mount, and i_index. + */ + error = xfs_iread(mp, tp, ino, &ip, bno); + if (error) { + return error; + } + + /* + * Vnode provided by vn_initialize. + */ + + xfs_iget_vnode_init(mp, vp, ip); + + vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address); + + if (vp->v_fbhv == NULL) { + bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops); + vn_bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc)); + } + + xfs_inode_lock_init(ip, vp); + xfs_iocore_inode_init(ip); + + if (lock_flags != 0) { + xfs_ilock(ip, lock_flags); + } + + /* + * Put ip on its hash chain, unless someone else hashed a duplicate + * after we released the hash lock. + */ + write_lock(&ih->ih_lock); + + if (ih->ih_version != version) { + for (iq = ih->ih_next; iq != NULL; iq = iq->i_next) { + if (iq->i_ino == ino) { + write_unlock(&ih->ih_lock); + xfs_idestroy(ip); + + XFS_STATS_INC(xfsstats.xs_ig_dup); + goto again; + } + } + } + + /* + * These values _must_ be set before releasing ihlock! + */ + ip->i_hash = ih; + if ((iq = ih->ih_next)) { + iq->i_prevp = &ip->i_next; + } + ip->i_next = iq; + ip->i_prevp = &ih->ih_next; + ih->ih_next = ip; + ip->i_udquot = ip->i_gdquot = NULL; + ih->ih_version++; + + write_unlock(&ih->ih_lock); + + /* + * put ip on its cluster's hash chain + */ + ASSERT(ip->i_chash == NULL && ip->i_cprev == NULL && + ip->i_cnext == NULL); + + chlnew = NULL; + ch = XFS_CHASH(mp, ip->i_blkno); + chlredo: + s = mutex_spinlock(&ch->ch_lock); + for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) { + if (chl->chl_blkno == ip->i_blkno) { + + /* insert this inode into the doubly-linked list + * where chl points */ + if ((iq = chl->chl_ip)) { + ip->i_cprev = iq->i_cprev; + iq->i_cprev->i_cnext = ip; + iq->i_cprev = ip; + ip->i_cnext = iq; + } else { + ip->i_cnext = ip; + ip->i_cprev = ip; + } + chl->chl_ip = ip; + ip->i_chash = chl; + break; + } + } + + /* no hash list found for this block; add a new hash list */ + if (chl == NULL) { + if (chlnew == NULL) { + mutex_spinunlock(&ch->ch_lock, s); + ASSERT(xfs_chashlist_zone != NULL); + chlnew = (xfs_chashlist_t *) + kmem_zone_alloc(xfs_chashlist_zone, + KM_SLEEP); + ASSERT(chlnew != NULL); + goto chlredo; + } else { + ip->i_cnext = ip; + ip->i_cprev = ip; + ip->i_chash = chlnew; + chlnew->chl_ip = ip; + chlnew->chl_blkno = ip->i_blkno; + chlnew->chl_next = ch->ch_list; + ch->ch_list = chlnew; + chlnew = NULL; + } + } else { + if (chlnew != NULL) { + kmem_zone_free(xfs_chashlist_zone, chlnew); + } + } + + mutex_spinunlock(&ch->ch_lock, s); + + + /* + * Link ip to its mount and thread it on the mount's inode list. + */ + XFS_MOUNT_ILOCK(mp); + if ((iq = mp->m_inodes)) { + ASSERT(iq->i_mprev->i_mnext == iq); + ip->i_mprev = iq->i_mprev; + iq->i_mprev->i_mnext = ip; + iq->i_mprev = ip; + ip->i_mnext = iq; + } else { + ip->i_mnext = ip; + ip->i_mprev = ip; + } + mp->m_inodes = ip; + + XFS_MOUNT_IUNLOCK(mp); + + newnode = 1; + + return_ip: + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t)); + + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); + + *ipp = ip; + + /* + * If we have a real type for an on-disk inode, we can set ops(&unlock) + * now. If it's a new inode being created, xfs_ialloc will handle it. + */ + if (vp->v_type != VNON) { + linvfs_set_inode_ops(LINVFS_GET_IP(vp)); + } + + /* Update the linux inode */ + error = vn_revalidate(vp, ATTR_COMM|ATTR_LAZY); + + return 0; +} + + +/* + * The 'normal' internal xfs_iget, if needed it will + * 'allocate', or 'get', the vnode. + */ +int +xfs_iget( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + uint lock_flags, + xfs_inode_t **ipp, + xfs_daddr_t bno) +{ + struct inode *inode; + vnode_t *vp = NULL; + int error; + +retry: + XFS_STATS_INC(xfsstats.xs_ig_attempts); + + if ((inode = iget_locked(XFS_MTOVFS(mp)->vfs_super, ino))) { + bhv_desc_t *bdp; + xfs_inode_t *ip; + int newnode; + + + vp = LINVFS_GET_VP(inode); + if (inode->i_state & I_NEW) { +inode_allocate: + XFS_STATS_INC(xfsstats.vn_alloc); + vn_initialize(inode); + error = xfs_iget_core(vp, mp, tp, ino, + lock_flags, ipp, bno); + if (error) { + remove_inode_hash(inode); + make_bad_inode(inode); + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + iput(inode); + } + } else { + /* These are true if the inode is in inactive or + * reclaim. The linux inode is about to go away, + * wait for that path to finish, and try again. + */ + if (vp->v_flag & (VINACT | VRECLM)) { + vn_wait(vp); + iput(inode); + goto retry; + } + + if (is_bad_inode(inode)) { + iput(inode); + return EIO; + } + + bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops); + if (bdp == NULL) + goto inode_allocate; + ip = XFS_BHVTOI(bdp); + if (lock_flags != 0) + xfs_ilock(ip, lock_flags); + newnode = (ip->i_d.di_mode == 0); + if (newnode) + xfs_iocore_inode_reinit(ip); + vn_revalidate(vp, ATTR_COMM|ATTR_LAZY); + XFS_STATS_INC(xfsstats.xs_ig_found); + *ipp = ip; + error = 0; + } + } else + error = ENOMEM; /* If we got no inode we are out of memory */ + + return error; +} + + +/* + * A 'special' interface to xfs_iget, where the + * vnode is already allocated. + */ +int +xfs_vn_iget( + vfs_t *vfsp, + struct vnode *vp, + xfs_ino_t ino) +{ + xfs_inode_t *ip; + xfs_mount_t *mp = XFS_BHVTOM(vfsp->vfs_fbhv); + int error; + + error = xfs_iget_core(vp, mp, NULL, ino, 0, &ip, 0); + + return error; +} + + +/* + * Do the setup for the various locks within the incore inode. + */ +void +xfs_inode_lock_init( + xfs_inode_t *ip, + vnode_t *vp) +{ + mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, + "xfsino", (long)vp->v_number); + mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", vp->v_number); +#ifdef NOTYET + mutex_init(&ip->i_range_lock.r_spinlock, MUTEX_SPIN, "xrange"); +#endif /* NOTYET */ + init_waitqueue_head(&ip->i_ipin_wait); + atomic_set(&ip->i_pincount, 0); + init_sema(&ip->i_flock, 1, "xfsfino", vp->v_number); +} + +/* + * Look for the inode corresponding to the given ino in the hash table. + * If it is there and its i_transp pointer matches tp, return it. + * Otherwise, return NULL. + */ +xfs_inode_t * +xfs_inode_incore(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_trans_t *tp) +{ + xfs_ihash_t *ih; + xfs_inode_t *ip; + + ih = XFS_IHASH(mp, ino); + read_lock(&ih->ih_lock); + for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { + if (ip->i_ino == ino) { + /* + * If we find it and tp matches, return it. + * Otherwise break from the loop and return + * NULL. + */ + if (ip->i_transp == tp) { + read_unlock(&ih->ih_lock); + return (ip); + } + break; + } + } + read_unlock(&ih->ih_lock); + return (NULL); +} + +/* + * Decrement reference count of an inode structure and unlock it. + * + * ip -- the inode being released + * lock_flags -- this parameter indicates the inode's locks to be + * to be released. See the comment on xfs_iunlock() for a list + * of valid values. + */ +void +xfs_iput(xfs_inode_t *ip, + uint lock_flags) +{ + vnode_t *vp = XFS_ITOV(ip); + + vn_trace_entry(vp, "xfs_iput", (inst_t *)__return_address); + + xfs_iunlock(ip, lock_flags); + + VN_RELE(vp); +} + +/* + * Special iput for brand-new inodes that are still locked + */ +void +xfs_iput_new(xfs_inode_t *ip, + uint lock_flags) +{ + vnode_t *vp = XFS_ITOV(ip); + struct inode *inode = LINVFS_GET_IP(vp); + + vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address); + + /* We shouldn't get here without this being true, but just in case */ + if (inode->i_state & I_NEW) { + remove_inode_hash(inode); + make_bad_inode(inode); + unlock_new_inode(inode); + } + if (lock_flags) + xfs_iunlock(ip, lock_flags); + VN_RELE(vp); +} + + +/* + * This routine embodies the part of the reclaim code that pulls + * the inode from the inode hash table and the mount structure's + * inode list. + * This should only be called from xfs_reclaim(). + */ +void +xfs_ireclaim(xfs_inode_t *ip) +{ + vnode_t *vp; + + /* + * Remove from old hash list and mount list. + */ + XFS_STATS_INC(xfsstats.xs_ig_reclaims); + + xfs_iextract(ip); + + /* + * Here we do a spurious inode lock in order to coordinate with + * xfs_sync(). This is because xfs_sync() references the inodes + * in the mount list without taking references on the corresponding + * vnodes. We make that OK here by ensuring that we wait until + * the inode is unlocked in xfs_sync() before we go ahead and + * free it. We get both the regular lock and the io lock because + * the xfs_sync() code may need to drop the regular one but will + * still hold the io lock. + */ + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + + /* + * Release dquots (and their references) if any. An inode may escape + * xfs_inactive and get here via vn_alloc->vn_reclaim path. + */ + if (ip->i_udquot || ip->i_gdquot) { + xfs_qm_dqdettach_inode(ip); + } + + /* + * Pull our behavior descriptor from the vnode chain. + */ + vp = XFS_ITOV_NULL(ip); + if (vp) { + vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); + } + + /* + * Free all memory associated with the inode. + */ + xfs_idestroy(ip); +} + +/* + * This routine removes an about-to-be-destroyed inode from + * all of the lists in which it is lcoated with the exception + * of the behavior chain. It is used by xfs_ireclaim and + * by cxfs relocation cocde, in which case, we are removing + * the xfs_inode but leaving the vnode alone since it has + * been transformed into a client vnode. + */ +void +xfs_iextract( + xfs_inode_t *ip) +{ + xfs_ihash_t *ih; + xfs_inode_t *iq; + xfs_mount_t *mp; + xfs_chash_t *ch; + xfs_chashlist_t *chl, *chm; + SPLDECL(s); + + ih = ip->i_hash; + write_lock(&ih->ih_lock); + if ((iq = ip->i_next)) { + iq->i_prevp = ip->i_prevp; + } + *ip->i_prevp = iq; + write_unlock(&ih->ih_lock); + + /* + * Remove from cluster hash list + * 1) delete the chashlist if this is the last inode on the chashlist + * 2) unchain from list of inodes + * 3) point chashlist->chl_ip to 'chl_next' if to this inode. + */ + mp = ip->i_mount; + ch = XFS_CHASH(mp, ip->i_blkno); + s = mutex_spinlock(&ch->ch_lock); + + if (ip->i_cnext == ip) { + /* Last inode on chashlist */ + ASSERT(ip->i_cnext == ip && ip->i_cprev == ip); + ASSERT(ip->i_chash != NULL); + chm=NULL; + for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) { + if (chl->chl_blkno == ip->i_blkno) { + if (chm == NULL) { + /* first item on the list */ + ch->ch_list = chl->chl_next; + } else { + chm->chl_next = chl->chl_next; + } + kmem_zone_free(xfs_chashlist_zone, chl); + break; + } else { + ASSERT(chl->chl_ip != ip); + chm = chl; + } + } + ASSERT_ALWAYS(chl != NULL); + } else { + /* delete one inode from a non-empty list */ + iq = ip->i_cnext; + iq->i_cprev = ip->i_cprev; + ip->i_cprev->i_cnext = iq; + if (ip->i_chash->chl_ip == ip) { + ip->i_chash->chl_ip = iq; + } + ip->i_chash = __return_address; + ip->i_cprev = __return_address; + ip->i_cnext = __return_address; + } + mutex_spinunlock(&ch->ch_lock, s); + + /* + * Remove from mount's inode list. + */ + XFS_MOUNT_ILOCK(mp); + ASSERT((ip->i_mnext != NULL) && (ip->i_mprev != NULL)); + iq = ip->i_mnext; + iq->i_mprev = ip->i_mprev; + ip->i_mprev->i_mnext = iq; + + /* + * Fix up the head pointer if it points to the inode being deleted. + */ + if (mp->m_inodes == ip) { + if (ip == iq) { + mp->m_inodes = NULL; + } else { + mp->m_inodes = iq; + } + } + + mp->m_ireclaims++; + XFS_MOUNT_IUNLOCK(mp); +} + +/* + * This is a wrapper routine around the xfs_ilock() routine + * used to centralize some grungy code. It is used in places + * that wish to lock the inode solely for reading the extents. + * The reason these places can't just call xfs_ilock(SHARED) + * is that the inode lock also guards to bringing in of the + * extents from disk for a file in b-tree format. If the inode + * is in b-tree format, then we need to lock the inode exclusively + * until the extents are read in. Locking it exclusively all + * the time would limit our parallelism unnecessarily, though. + * What we do instead is check to see if the extents have been + * read in yet, and only lock the inode exclusively if they + * have not. + * + * The function returns a value which should be given to the + * corresponding xfs_iunlock_map_shared(). This value is + * the mode in which the lock was actually taken. + */ +uint +xfs_ilock_map_shared( + xfs_inode_t *ip) +{ + uint lock_mode; + + if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) && + ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) { + lock_mode = XFS_ILOCK_EXCL; + } else { + lock_mode = XFS_ILOCK_SHARED; + } + + xfs_ilock(ip, lock_mode); + + return lock_mode; +} + +/* + * This is simply the unlock routine to go with xfs_ilock_map_shared(). + * All it does is call xfs_iunlock() with the given lock_mode. + */ +void +xfs_iunlock_map_shared( + xfs_inode_t *ip, + unsigned int lock_mode) +{ + xfs_iunlock(ip, lock_mode); +} + +/* + * The xfs inode contains 2 locks: a multi-reader lock called the + * i_iolock and a multi-reader lock called the i_lock. This routine + * allows either or both of the locks to be obtained. + * + * The 2 locks should always be ordered so that the IO lock is + * obtained first in order to prevent deadlock. + * + * ip -- the inode being locked + * lock_flags -- this parameter indicates the inode's locks + * to be locked. It can be: + * XFS_IOLOCK_SHARED, + * XFS_IOLOCK_EXCL, + * XFS_ILOCK_SHARED, + * XFS_ILOCK_EXCL, + * XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED, + * XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL, + * XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED, + * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL + */ +void +xfs_ilock(xfs_inode_t *ip, + uint lock_flags) +{ + /* + * You can't set both SHARED and EXCL for the same lock, + * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, + * and XFS_ILOCK_EXCL are valid values to set in lock_flags. + */ + ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != + (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); + ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != + (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0); + + if (lock_flags & XFS_IOLOCK_EXCL) { + mrupdate(&ip->i_iolock); + } else if (lock_flags & XFS_IOLOCK_SHARED) { + mraccess(&ip->i_iolock); + } + if (lock_flags & XFS_ILOCK_EXCL) { + mrupdate(&ip->i_lock); + } else if (lock_flags & XFS_ILOCK_SHARED) { + mraccess(&ip->i_lock); + } +#ifdef XFS_ILOCK_TRACE + xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)return_address); +#endif +} + +/* + * This is just like xfs_ilock(), except that the caller + * is guaranteed not to sleep. It returns 1 if it gets + * the requested locks and 0 otherwise. If the IO lock is + * obtained but the inode lock cannot be, then the IO lock + * is dropped before returning. + * + * ip -- the inode being locked + * lock_flags -- this parameter indicates the inode's locks to be + * to be locked. See the comment for xfs_ilock() for a list + * of valid values. + * + */ +int +xfs_ilock_nowait(xfs_inode_t *ip, + uint lock_flags) +{ + int iolocked; + int ilocked; + + /* + * You can't set both SHARED and EXCL for the same lock, + * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, + * and XFS_ILOCK_EXCL are valid values to set in lock_flags. + */ + ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != + (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); + ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != + (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0); + + iolocked = 0; + if (lock_flags & XFS_IOLOCK_EXCL) { + iolocked = mrtryupdate(&ip->i_iolock); + if (!iolocked) { + return 0; + } + } else if (lock_flags & XFS_IOLOCK_SHARED) { + iolocked = mrtryaccess(&ip->i_iolock); + if (!iolocked) { + return 0; + } + } + if (lock_flags & XFS_ILOCK_EXCL) { + ilocked = mrtryupdate(&ip->i_lock); + if (!ilocked) { + if (iolocked) { + mrunlock(&ip->i_iolock); + } + return 0; + } + } else if (lock_flags & XFS_ILOCK_SHARED) { + ilocked = mrtryaccess(&ip->i_lock); + if (!ilocked) { + if (iolocked) { + mrunlock(&ip->i_iolock); + } + return 0; + } + } +#ifdef XFS_ILOCK_TRACE + xfs_ilock_trace(ip, 2, lock_flags, (inst_t *)__return_address); +#endif + return 1; +} + +/* + * xfs_iunlock() is used to drop the inode locks acquired with + * xfs_ilock() and xfs_ilock_nowait(). The caller must pass + * in the flags given to xfs_ilock() or xfs_ilock_nowait() so + * that we know which locks to drop. + * + * ip -- the inode being unlocked + * lock_flags -- this parameter indicates the inode's locks to be + * to be unlocked. See the comment for xfs_ilock() for a list + * of valid values for this parameter. + * + */ +void +xfs_iunlock(xfs_inode_t *ip, + uint lock_flags) +{ + /* + * You can't set both SHARED and EXCL for the same lock, + * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, + * and XFS_ILOCK_EXCL are valid values to set in lock_flags. + */ + ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != + (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); + ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != + (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY)) == 0); + ASSERT(lock_flags != 0); + + if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) { + ASSERT(!(lock_flags & XFS_IOLOCK_SHARED) || + (ismrlocked(&ip->i_iolock, MR_ACCESS))); + ASSERT(!(lock_flags & XFS_IOLOCK_EXCL) || + (ismrlocked(&ip->i_iolock, MR_UPDATE))); + mrunlock(&ip->i_iolock); + } + + if (lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) { + ASSERT(!(lock_flags & XFS_ILOCK_SHARED) || + (ismrlocked(&ip->i_lock, MR_ACCESS))); + ASSERT(!(lock_flags & XFS_ILOCK_EXCL) || + (ismrlocked(&ip->i_lock, MR_UPDATE))); + mrunlock(&ip->i_lock); + + /* + * Let the AIL know that this item has been unlocked in case + * it is in the AIL and anyone is waiting on it. Don't do + * this if the caller has asked us not to. + */ + if (!(lock_flags & XFS_IUNLOCK_NONOTIFY) && + ip->i_itemp != NULL) { + xfs_trans_unlocked_item(ip->i_mount, + (xfs_log_item_t*)(ip->i_itemp)); + } + } +#ifdef XFS_ILOCK_TRACE + xfs_ilock_trace(ip, 3, lock_flags, (inst_t *)__return_address); +#endif +} + +/* + * give up write locks. the i/o lock cannot be held nested + * if it is being demoted. + */ +void +xfs_ilock_demote(xfs_inode_t *ip, + uint lock_flags) +{ + ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0); + + if (lock_flags & XFS_ILOCK_EXCL) { + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + mrdemote(&ip->i_lock); + } + if (lock_flags & XFS_IOLOCK_EXCL) { + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + mrdemote(&ip->i_iolock); + } +} + +/* + * The following three routines simply manage the i_flock + * semaphore embedded in the inode. This semaphore synchronizes + * processes attempting to flush the in-core inode back to disk. + */ +void +xfs_iflock(xfs_inode_t *ip) +{ + psema(&(ip->i_flock), PINOD|PLTWAIT); +} + +int +xfs_iflock_nowait(xfs_inode_t *ip) +{ + return (cpsema(&(ip->i_flock))); +} + +void +xfs_ifunlock(xfs_inode_t *ip) +{ + ASSERT(valusema(&(ip->i_flock)) <= 0); + vsema(&(ip->i_flock)); +} diff -Nur linux-2.4.19/fs/xfs/xfs_imap.h linux-2.4.19-sgi211r3/fs/xfs/xfs_imap.h --- linux-2.4.19/fs/xfs/xfs_imap.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_imap.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IMAP_H__ +#define __XFS_IMAP_H__ + +/* + * This is the structure passed to xfs_imap() to map + * an inode number to its on disk location. + */ +typedef struct xfs_imap { + xfs_daddr_t im_blkno; /* starting BB of inode chunk */ + uint im_len; /* length in BBs of inode chunk */ + xfs_agblock_t im_agblkno; /* logical block of inode chunk in ag */ + ushort im_ioffset; /* inode offset in block in "inodes" */ + ushort im_boffset; /* inode offset in block in bytes */ +} xfs_imap_t; + +#ifdef __KERNEL__ +struct xfs_mount; +struct xfs_trans; +int xfs_imap(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_imap_t *, uint); +#endif + +#endif /* __XFS_IMAP_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_inode.c linux-2.4.19-sgi211r3/fs/xfs/xfs_inode.c --- linux-2.4.19/fs/xfs/xfs_inode.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_inode.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,3625 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +kmem_zone_t *xfs_ifork_zone; +kmem_zone_t *xfs_inode_zone; +kmem_zone_t *xfs_chashlist_zone; + +/* + * Used in xfs_itruncate(). This is the maximum number of extents + * freed from a file in a single transaction. + */ +#define XFS_ITRUNC_MAX_EXTENTS 2 + +STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); +STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int); +STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int); +STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int); + + +#ifdef DEBUG +/* + * Make sure that the extents in the given memory buffer + * are valid. + */ +STATIC void +xfs_validate_extents( + xfs_bmbt_rec_32_t *ep, + int nrecs, + xfs_exntfmt_t fmt) +{ + xfs_bmbt_irec_t irec; + int i; + xfs_bmbt_rec_t rec; + + for (i = 0; i < nrecs; i++) { + bcopy(ep, &rec, sizeof(rec)); + xfs_bmbt_get_all(&rec, &irec); + if (fmt == XFS_EXTFMT_NOSTATE) + ASSERT(irec.br_state == XFS_EXT_NORM); + ep++; + } +} +#else /* DEBUG */ +#define xfs_validate_extents(ep, nrecs, fmt) +#endif /* DEBUG */ + +/* + * Check that none of the inode's in the buffer have a next + * unlinked field of 0. + */ +#if defined(DEBUG) +void +xfs_inobp_check( + xfs_mount_t *mp, + xfs_buf_t *bp) +{ + int i; + int j; + xfs_dinode_t *dip; + + j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; + + for (i = 0; i < j; i++) { + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + i * mp->m_sb.sb_inodesize); + if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_ALERT, mp, + "Detected a bogus zero next_unlinked field in incore inode buffer 0x%p. About to pop an ASSERT.", + bp); + ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)); + } + } +} +#endif + +/* + * called from bwrite on xfs inode buffers + */ +void +xfs_inobp_bwcheck(xfs_buf_t *bp) +{ + xfs_mount_t *mp; + int i; + int j; + xfs_dinode_t *dip; + + ASSERT(XFS_BUF_FSPRIVATE3(bp, void *) != NULL); + + mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); + + + j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; + + for (i = 0; i < j; i++) { + dip = (xfs_dinode_t *) xfs_buf_offset(bp, + i * mp->m_sb.sb_inodesize); + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + cmn_err(CE_WARN, +"Bad magic # 0x%x in XFS inode buffer 0x%Lx, starting blockno %Ld, offset 0x%x", + INT_GET(dip->di_core.di_magic, ARCH_CONVERT), + (__uint64_t)(__psunsigned_t) bp, + (__int64_t) XFS_BUF_ADDR(bp), + xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); + xfs_fs_cmn_err(CE_WARN, mp, + "corrupt, unmount and run xfs_repair"); + } + if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)) { + cmn_err(CE_WARN, +"Bad next_unlinked field (0) in XFS inode buffer 0x%x, starting blockno %Ld, offset 0x%x", + (__uint64_t)(__psunsigned_t) bp, + (__int64_t) XFS_BUF_ADDR(bp), + xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); + xfs_fs_cmn_err(CE_WARN, mp, + "corrupt, unmount and run xfs_repair"); + } + } + + return; +} + +/* + * This routine is called to map an inode number within a file + * system to the buffer containing the on-disk version of the + * inode. It returns a pointer to the buffer containing the + * on-disk inode in the bpp parameter, and in the dip parameter + * it returns a pointer to the on-disk inode within that buffer. + * + * If a non-zero error is returned, then the contents of bpp and + * dipp are undefined. + * + * Use xfs_imap() to determine the size and location of the + * buffer to read from disk. + */ +int +xfs_inotobp( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_dinode_t **dipp, + xfs_buf_t **bpp, + int *offset) +{ + int di_ok; + xfs_imap_t imap; + xfs_buf_t *bp; + int error; + xfs_dinode_t *dip; + + /* + * Call the space managment code to find the location of the + * inode on disk. + */ + imap.im_blkno = 0; + error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP); + if (error != 0) { + cmn_err(CE_WARN, + "xfs_inotobp: xfs_imap() returned an " + "error %d on %s. Returning error.", error, mp->m_fsname); + return error; + } + + /* + * If the inode number maps to a block outside the bounds of the + * file system then return NULL rather than calling read_buf + * and panicing when we get an error from the driver. + */ + if ((imap.im_blkno + imap.im_len) > + XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { + cmn_err(CE_WARN, + "xfs_inotobp: inode number (%d + %d) maps to a block outside the bounds " + "of the file system %s. Returning EINVAL.", + imap.im_blkno, imap.im_len,mp->m_fsname); + return XFS_ERROR(EINVAL); + } + + /* + * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will + * default to just a read_buf() call. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, + (int)imap.im_len, XFS_BUF_LOCK, &bp); + + if (error) { + cmn_err(CE_WARN, + "xfs_inotobp: xfs_trans_read_buf() returned an " + "error %d on %s. Returning error.", error, mp->m_fsname); + return error; + } + dip = (xfs_dinode_t *)xfs_buf_offset(bp, 0); + di_ok = + INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && + XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, + XFS_RANDOM_ITOBP_INOTOBP)) { + xfs_trans_brelse(tp, bp); + cmn_err(CE_WARN, + "xfs_inotobp: XFS_TEST_ERROR() returned an " + "error on %s. Returning EFSCORRUPTED.", mp->m_fsname); + return XFS_ERROR(EFSCORRUPTED); + } + + xfs_inobp_check(mp, bp); + + /* + * Set *dipp to point to the on-disk inode in the buffer. + */ + *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); + *bpp = bp; + *offset = imap.im_boffset; + return 0; +} + + +/* + * This routine is called to map an inode to the buffer containing + * the on-disk version of the inode. It returns a pointer to the + * buffer containing the on-disk inode in the bpp parameter, and in + * the dip parameter it returns a pointer to the on-disk inode within + * that buffer. + * + * If a non-zero error is returned, then the contents of bpp and + * dipp are undefined. + * + * If the inode is new and has not yet been initialized, use xfs_imap() + * to determine the size and location of the buffer to read from disk. + * If the inode has already been mapped to its buffer and read in once, + * then use the mapping information stored in the inode rather than + * calling xfs_imap(). This allows us to avoid the overhead of looking + * at the inode btree for small block file systems (see xfs_dilocate()). + * We can tell whether the inode has been mapped in before by comparing + * its disk block address to 0. Only uninitialized inodes will have + * 0 for the disk block address. + */ +int +xfs_itobp( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dinode_t **dipp, + xfs_buf_t **bpp, + xfs_daddr_t bno) +{ + xfs_buf_t *bp; + int error; + xfs_imap_t imap; +#ifdef __KERNEL__ + int i; + int ni; +#endif + + if (ip->i_blkno == (xfs_daddr_t)0) { + /* + * Call the space management code to find the location of the + * inode on disk. + */ + imap.im_blkno = bno; + error = xfs_imap(mp, tp, ip->i_ino, &imap, XFS_IMAP_LOOKUP); + if (error != 0) { + return error; + } + + /* + * If the inode number maps to a block outside the bounds + * of the file system then return NULL rather than calling + * read_buf and panicing when we get an error from the + * driver. + */ + if ((imap.im_blkno + imap.im_len) > + XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: " + "(imap.im_blkno (0x%llx) " + "+ imap.im_len (0x%llx)) > " + " XFS_FSB_TO_BB(mp, " + "mp->m_sb.sb_dblocks) (0x%llx)", + (unsigned long long) imap.im_blkno, + (unsigned long long) imap.im_len, + XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); +#endif /* DEBUG */ + return XFS_ERROR(EINVAL); + } + + /* + * Fill in the fields in the inode that will be used to + * map the inode to its buffer from now on. + */ + ip->i_blkno = imap.im_blkno; + ip->i_len = imap.im_len; + ip->i_boffset = imap.im_boffset; + } else { + /* + * We've already mapped the inode once, so just use the + * mapping that we saved the first time. + */ + imap.im_blkno = ip->i_blkno; + imap.im_len = ip->i_len; + imap.im_boffset = ip->i_boffset; + } + ASSERT(bno == 0 || bno == imap.im_blkno); + + /* + * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will + * default to just a read_buf() call. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, + (int)imap.im_len, XFS_BUF_LOCK, &bp); + + if (error) { +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: " + "xfs_trans_read_buf() returned error %d, " + "imap.im_blkno 0x%llx, imap.im_len 0x%llx", + error, (unsigned long long) imap.im_blkno, + (unsigned long long) imap.im_len); +#endif /* DEBUG */ + return error; + } +#ifdef __KERNEL__ + /* + * Validate the magic number and version of every inode in the buffer + * (if DEBUG kernel) or the first inode in the buffer, otherwise. + */ +#ifdef DEBUG + ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog; +#else + ni = 1; +#endif + for (i = 0; i < ni; i++) { + int di_ok; + xfs_dinode_t *dip; + + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + (i << mp->m_sb.sb_inodelog)); + di_ok = INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && + XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, + XFS_RANDOM_ITOBP_INOTOBP)) { +#ifdef DEBUG + prdev("bad inode magic/vsn daddr 0x%llx #%d (magic=%x)", + mp->m_dev, (unsigned long long)imap.im_blkno, i, + INT_GET(dip->di_core.di_magic, ARCH_CONVERT)); +#endif + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + } +#endif /* __KERNEL__ */ + + xfs_inobp_check(mp, bp); + + /* + * Mark the buffer as an inode buffer now that it looks good + */ + XFS_BUF_SET_VTYPE(bp, B_FS_INO); + + /* + * Set *dipp to point to the on-disk inode in the buffer. + */ + *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); + *bpp = bp; + return 0; +} + +/* + * Move inode type and inode format specific information from the + * on-disk inode to the in-core inode. For fifos, devs, and sockets + * this means set if_rdev to the proper value. For files, directories, + * and symlinks this means to bring in the in-line data or extent + * pointers. For a file in B-tree format, only the root is immediately + * brought in-core. The rest will be in-lined in if_extents when it + * is first referenced (see xfs_iread_extents()). + */ +STATIC int +xfs_iformat( + xfs_inode_t *ip, + xfs_dinode_t *dip) +{ + xfs_attr_shortform_t *atp; + int size; + int error; + xfs_fsize_t di_size; + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + error = 0; + + if (INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) + + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) > + INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, extent total = %d, nblocks = %Lu." + " Unmount and run xfs_repair.", + (unsigned long long)ip->i_ino, + (int)(INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) + + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT)), + (unsigned long long) + INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT)); + return XFS_ERROR(EFSCORRUPTED); + } + + if (INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT) > ip->i_mount->m_sb.sb_inodesize) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, forkoff = 0x%x." + " Unmount and run xfs_repair.", + (unsigned long long)ip->i_ino, + (int)(INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT))); + return XFS_ERROR(EFSCORRUPTED); + } + + switch (ip->i_d.di_mode & IFMT) { + case IFIFO: + case IFCHR: + case IFBLK: + case IFSOCK: + if (INT_GET(dip->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_DEV) + return XFS_ERROR(EFSCORRUPTED); + ip->i_d.di_size = 0; + ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT); + break; + + case IFREG: + case IFLNK: + case IFDIR: + switch (INT_GET(dip->di_core.di_format, ARCH_CONVERT)) { + case XFS_DINODE_FMT_LOCAL: + /* + * no local regular files yet + */ + if ((INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFREG) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode " + "(local format for regular file) %Lu. " + "Unmount and run xfs_repair.", + (unsigned long long) ip->i_ino); + return XFS_ERROR(EFSCORRUPTED); + } + + di_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT); + if (di_size > + XFS_DFORK_DSIZE_ARCH(dip, ip->i_mount, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu " + "(bad size %Ld for local inode). " + "Unmount and run xfs_repair.", + (unsigned long long) ip->i_ino, + (long long) di_size); + return XFS_ERROR(EFSCORRUPTED); + } + + size = (int)di_size; + error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK); + break; + default: + return XFS_ERROR(EFSCORRUPTED); + } + break; + + default: + return XFS_ERROR(EFSCORRUPTED); + } + if (error) { + return error; + } + if (!XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT)) + return 0; + ASSERT(ip->i_afp == NULL); + ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); + ip->i_afp->if_ext_max = + XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) { + case XFS_DINODE_FMT_LOCAL: + atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT); + size = (int)INT_GET(atp->hdr.totsize, ARCH_CONVERT); + error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK); + break; + default: + error = XFS_ERROR(EFSCORRUPTED); + break; + } + if (error) { + kmem_zone_free(xfs_ifork_zone, ip->i_afp); + ip->i_afp = NULL; + xfs_idestroy_fork(ip, XFS_DATA_FORK); + } + return error; +} + +/* + * The file is in-lined in the on-disk inode. + * If it fits into if_inline_data, then copy + * it there, otherwise allocate a buffer for it + * and copy the data there. Either way, set + * if_data to point at the data. + * If we allocate a buffer for the data, make + * sure that its size is a multiple of 4 and + * record the real size in i_real_bytes. + */ +STATIC int +xfs_iformat_local( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork, + int size) +{ + xfs_ifork_t *ifp; + int real_size; + + /* + * If the size is unreasonable, then something + * is wrong and we just bail out rather than crash in + * kmem_alloc() or bcopy() below. + */ + if (size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu " + "(bad size %d for local fork, size = %d). " + "Unmount and run xfs_repair.", + (unsigned long long) ip->i_ino, size, + XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)); + return XFS_ERROR(EFSCORRUPTED); + } + ifp = XFS_IFORK_PTR(ip, whichfork); + real_size = 0; + if (size == 0) + ifp->if_u1.if_data = NULL; + else if (size <= sizeof(ifp->if_u2.if_inline_data)) + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + else { + real_size = roundup(size, 4); + ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); + } + ifp->if_bytes = size; + ifp->if_real_bytes = real_size; + if (size) + bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_data, size); + ifp->if_flags &= ~XFS_IFEXTENTS; + ifp->if_flags |= XFS_IFINLINE; + return 0; +} + +/* + * The file consists of a set of extents all + * of which fit into the on-disk inode. + * If there are few enough extents to fit into + * the if_inline_ext, then copy them there. + * Otherwise allocate a buffer for them and copy + * them into it. Either way, set if_extents + * to point at the extents. + */ +STATIC int +xfs_iformat_extents( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork) +{ + xfs_ifork_t *ifp; + int nex; + int real_size; + int size; + + ifp = XFS_IFORK_PTR(ip, whichfork); + nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT); + size = nex * (uint)sizeof(xfs_bmbt_rec_t); + + /* + * If the number of extents is unreasonable, then something + * is wrong and we just bail out rather than crash in + * kmem_alloc() or bcopy() below. + */ + if (size < 0 || size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu ((a)extents = %d). " + "Unmount and run xfs_repair.", + (unsigned long long) ip->i_ino, nex); + return XFS_ERROR(EFSCORRUPTED); + } + + real_size = 0; + if (nex == 0) + ifp->if_u1.if_extents = NULL; + else if (nex <= XFS_INLINE_EXTS) + ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; + else { + ifp->if_u1.if_extents = kmem_alloc(size, KM_SLEEP); + ASSERT(ifp->if_u1.if_extents != NULL); + real_size = size; + } + ifp->if_bytes = size; + ifp->if_real_bytes = real_size; + if (size) { + xfs_validate_extents( + (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), + nex, XFS_EXTFMT_INODE(ip)); + bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_extents, + size); + xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex, + whichfork); + if (whichfork != XFS_DATA_FORK || + XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) + if (xfs_check_nostate_extents( + ifp->if_u1.if_extents, nex)) + return XFS_ERROR(EFSCORRUPTED); + } + ifp->if_flags |= XFS_IFEXTENTS; + return 0; +} + +/* + * The file has too many extents to fit into + * the inode, so they are in B-tree format. + * Allocate a buffer for the root of the B-tree + * and copy the root into it. The i_extents + * field will remain NULL until all of the + * extents are read in (when they are needed). + */ +STATIC int +xfs_iformat_btree( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork) +{ + xfs_bmdr_block_t *dfp; + xfs_ifork_t *ifp; + /* REFERENCED */ + int nrecs; + int size; + + ifp = XFS_IFORK_PTR(ip, whichfork); + dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + size = XFS_BMAP_BROOT_SPACE(dfp); + nrecs = XFS_BMAP_BROOT_NUMRECS(dfp); + + /* + * blow out if -- fork has less extents than can fit in + * fork (fork shouldn't be a btree format), root btree + * block has more records than can fit into the fork, + * or the number of extents is greater than the number of + * blocks. + */ + if (XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max + || XFS_BMDR_SPACE_CALC(nrecs) > + XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT) + || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu (btree). " + "Unmount and run xfs_repair.", + (unsigned long long) ip->i_ino); + return XFS_ERROR(EFSCORRUPTED); + } + + ifp->if_broot_bytes = size; + ifp->if_broot = kmem_alloc(size, KM_SLEEP); + ASSERT(ifp->if_broot != NULL); + /* + * Copy and convert from the on-disk structure + * to the in-memory structure. + */ + xfs_bmdr_to_bmbt(dfp, XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT), + ifp->if_broot, size); + ifp->if_flags &= ~XFS_IFEXTENTS; + ifp->if_flags |= XFS_IFBROOT; + + return 0; +} + +/* + * xfs_xlate_dinode_core - translate an xfs_inode_core_t between ondisk + * and native format + * + * buf = on-disk representation + * dip = native representation + * dir = direction - +ve -> disk to native + * -ve -> native to disk + * arch = on-disk architecture + */ + +void +xfs_xlate_dinode_core(xfs_caddr_t buf, xfs_dinode_core_t *dip, + int dir, xfs_arch_t arch) +{ + xfs_dinode_core_t *buf_core; + xfs_dinode_core_t *mem_core; + + ASSERT(dir); + + buf_core=(xfs_dinode_core_t*)buf; + mem_core=(xfs_dinode_core_t*)dip; + + if (arch == ARCH_NOCONVERT) { + if (dir>0) { + bcopy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core, sizeof(xfs_dinode_core_t)); + } else { + bcopy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core, sizeof(xfs_dinode_core_t)); + } + return; + } + + INT_XLATE(buf_core->di_magic, mem_core->di_magic, dir, arch); + INT_XLATE(buf_core->di_mode, mem_core->di_mode, dir, arch); + INT_XLATE(buf_core->di_version, mem_core->di_version, dir, arch); + INT_XLATE(buf_core->di_format, mem_core->di_format, dir, arch); + INT_XLATE(buf_core->di_onlink, mem_core->di_onlink, dir, arch); + INT_XLATE(buf_core->di_uid, mem_core->di_uid, dir, arch); + INT_XLATE(buf_core->di_gid, mem_core->di_gid, dir, arch); + INT_XLATE(buf_core->di_nlink, mem_core->di_nlink, dir, arch); + INT_XLATE(buf_core->di_projid, mem_core->di_projid, dir, arch); + + if (dir>0) { + bcopy(buf_core->di_pad, mem_core->di_pad, sizeof(buf_core->di_pad)); + } else { + bcopy(mem_core->di_pad, buf_core->di_pad, sizeof(buf_core->di_pad)); + } + + INT_XLATE(buf_core->di_atime.t_sec, mem_core->di_atime.t_sec, dir, arch); + INT_XLATE(buf_core->di_atime.t_nsec,mem_core->di_atime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_mtime.t_sec, mem_core->di_mtime.t_sec, dir, arch); + INT_XLATE(buf_core->di_mtime.t_nsec,mem_core->di_mtime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_ctime.t_sec, mem_core->di_ctime.t_sec, dir, arch); + INT_XLATE(buf_core->di_ctime.t_nsec,mem_core->di_ctime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_size, mem_core->di_size, dir, arch); + INT_XLATE(buf_core->di_nblocks, mem_core->di_nblocks, dir, arch); + INT_XLATE(buf_core->di_extsize, mem_core->di_extsize, dir, arch); + + INT_XLATE(buf_core->di_nextents, mem_core->di_nextents, dir, arch); + INT_XLATE(buf_core->di_anextents, mem_core->di_anextents, dir, arch); + INT_XLATE(buf_core->di_forkoff, mem_core->di_forkoff, dir, arch); + INT_XLATE(buf_core->di_aformat, mem_core->di_aformat, dir, arch); + INT_XLATE(buf_core->di_dmevmask, mem_core->di_dmevmask, dir, arch); + INT_XLATE(buf_core->di_dmstate, mem_core->di_dmstate, dir, arch); + INT_XLATE(buf_core->di_flags, mem_core->di_flags, dir, arch); + INT_XLATE(buf_core->di_gen, mem_core->di_gen, dir, arch); + +} + +/* + * Given a mount structure and an inode number, return a pointer + * to a newly allocated in-core inode coresponding to the given + * inode number. + * + * Initialize the inode's attributes and extent pointers if it + * already has them (it will not if the inode has no links). + */ +int +xfs_iread( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_inode_t **ipp, + xfs_daddr_t bno) +{ + xfs_buf_t *bp; + xfs_dinode_t *dip; + xfs_inode_t *ip; + int error; + + ASSERT(xfs_inode_zone != NULL); + + ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP); + ip->i_ino = ino; + ip->i_mount = mp; + + /* + * Get pointer's to the on-disk inode and the buffer containing it. + * If the inode number refers to a block outside the file system + * then xfs_itobp() will return NULL. In this case we should + * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will + * know that this is a new incore inode. + */ + error = xfs_itobp(mp, tp, ip, &dip, &bp, bno); + + if (error != 0) { + kmem_zone_free(xfs_inode_zone, ip); + return error; + } + + /* + * Initialize inode's trace buffers. + * Do this before xfs_iformat in case it adds entries. + */ +#ifdef XFS_BMAP_TRACE + ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_BMBT_TRACE + ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_RW_TRACE + ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_STRAT_TRACE + ip->i_strat_trace = ktrace_alloc(XFS_STRAT_KTRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_ILOCK_TRACE + ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_DIR2_TRACE + ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_SLEEP); +#endif + + /* + * If we got something that isn't an inode it means someone + * (nfs or dmi) has a stale handle. + */ + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + kmem_zone_free(xfs_inode_zone, ip); + xfs_trans_brelse(tp, bp); +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: " + "dip->di_core.di_magic (0x%x) != " + "XFS_DINODE_MAGIC (0x%x)", + INT_GET(dip->di_core.di_magic, ARCH_CONVERT), + XFS_DINODE_MAGIC); +#endif /* DEBUG */ + return XFS_ERROR(EINVAL); + } + + /* + * If the on-disk inode is already linked to a directory + * entry, copy all of the inode into the in-core inode. + * xfs_iformat() handles copying in the inode format + * specific information. + * Otherwise, just get the truly permanent information. + */ + if (!INT_ISZERO(dip->di_core.di_mode, ARCH_CONVERT)) { + xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, + &(ip->i_d), 1, ARCH_CONVERT); + error = xfs_iformat(ip, dip); + if (error) { + kmem_zone_free(xfs_inode_zone, ip); + xfs_trans_brelse(tp, bp); +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: " + "xfs_iformat() returned error %d", + error); +#endif /* DEBUG */ + return error; + } + } else { + ip->i_d.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); + ip->i_d.di_version = INT_GET(dip->di_core.di_version, ARCH_CONVERT); + ip->i_d.di_gen = INT_GET(dip->di_core.di_gen, ARCH_CONVERT); + /* + * Make sure to pull in the mode here as well in + * case the inode is released without being used. + * This ensures that xfs_inactive() will see that + * the inode is already free and not try to mess + * with the uninitialized part of it. + */ + ip->i_d.di_mode = 0; + /* + * Initialize the per-fork minima and maxima for a new + * inode here. xfs_iformat will do it for old inodes. + */ + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + } + + /* + * The inode format changed when we moved the link count and + * made it 32 bits long. If this is an old format inode, + * convert it in memory to look like a new one. If it gets + * flushed to disk we will convert back before flushing or + * logging it. We zero out the new projid field and the old link + * count field. We'll handle clearing the pad field (the remains + * of the old uuid field) when we actually convert the inode to + * the new format. We don't change the version number so that we + * can distinguish this from a real new format inode. + */ + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + ip->i_d.di_nlink = ip->i_d.di_onlink; + ip->i_d.di_onlink = 0; + ip->i_d.di_projid = 0; + } + + ip->i_delayed_blks = 0; + + /* + * Mark the buffer containing the inode as something to keep + * around for a while. This helps to keep recently accessed + * meta-data in-core longer. + */ + XFS_BUF_SET_REF(bp, XFS_INO_REF); + + /* + * Use xfs_trans_brelse() to release the buffer containing the + * on-disk inode, because it was acquired with xfs_trans_read_buf() + * in xfs_itobp() above. If tp is NULL, this is just a normal + * brelse(). If we're within a transaction, then xfs_trans_brelse() + * will only release the buffer if it is not dirty within the + * transaction. It will be OK to release the buffer in this case, + * because inodes on disk are never destroyed and we will be + * locking the new in-core inode before putting it in the hash + * table where other processes can find it. Thus we don't have + * to worry about the inode being changed just because we released + * the buffer. + */ + xfs_trans_brelse(tp, bp); + *ipp = ip; + return 0; +} + +/* + * Read in extents from a btree-format inode. + * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. + */ +int +xfs_iread_extents( + xfs_trans_t *tp, + xfs_inode_t *ip, + int whichfork) +{ + int error; + xfs_ifork_t *ifp; + size_t size; + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + return XFS_ERROR(EFSCORRUPTED); + size = XFS_IFORK_NEXTENTS(ip, whichfork) * (uint)sizeof(xfs_bmbt_rec_t); + ifp = XFS_IFORK_PTR(ip, whichfork); + /* + * We know that the size is legal (it's checked in iformat_btree) + */ + ifp->if_u1.if_extents = kmem_alloc(size, KM_SLEEP); + ASSERT(ifp->if_u1.if_extents != NULL); + ifp->if_lastex = NULLEXTNUM; + ifp->if_bytes = ifp->if_real_bytes = (int)size; + ifp->if_flags |= XFS_IFEXTENTS; + error = xfs_bmap_read_extents(tp, ip, whichfork); + if (error) { + kmem_free(ifp->if_u1.if_extents, size); + ifp->if_u1.if_extents = NULL; + ifp->if_bytes = ifp->if_real_bytes = 0; + ifp->if_flags &= ~XFS_IFEXTENTS; + return error; + } + xfs_validate_extents((xfs_bmbt_rec_32_t *)ifp->if_u1.if_extents, + XFS_IFORK_NEXTENTS(ip, whichfork), XFS_EXTFMT_INODE(ip)); + return 0; +} + +/* + * Allocate an inode on disk and return a copy of it's in-core version. + * The in-core inode is locked exclusively. Set mode, nlink, and rdev + * appropriately within the inode. The uid and gid for the inode are + * set according to the contents of the given cred structure. + * + * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() + * has a free inode available, call xfs_iget() + * to obtain the in-core version of the allocated inode. Finally, + * fill in the inode and log its initial contents. In this case, + * ialloc_context would be set to NULL and call_again set to false. + * + * If xfs_dialloc() does not have an available inode, + * it will replenish its supply by doing an allocation. Since we can + * only do one allocation within a transaction without deadlocks, we + * must commit the current transaction before returning the inode itself. + * In this case, therefore, we will set call_again to true and return. + * The caller should then commit the current transaction, start a new + * transaction, and call xfs_ialloc() again to actually get the inode. + * + * To ensure that some other process does not grab the inode that + * was allocated during the first call to xfs_ialloc(), this routine + * also returns the [locked] bp pointing to the head of the freelist + * as ialloc_context. The caller should hold this buffer across + * the commit and pass it back into this routine on the second call. + */ +int +xfs_ialloc( + xfs_trans_t *tp, + xfs_inode_t *pip, + mode_t mode, + nlink_t nlink, + dev_t rdev, + cred_t *cr, + xfs_prid_t prid, + int okalloc, + xfs_buf_t **ialloc_context, + boolean_t *call_again, + xfs_inode_t **ipp) +{ + xfs_ino_t ino; + xfs_inode_t *ip; + vnode_t *vp; + uint flags; + int error; + + /* + * Call the space management code to pick + * the on-disk inode to be allocated. + */ + ASSERT(pip != NULL); + error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, + ialloc_context, call_again, &ino); + if (error != 0) { + return error; + } + if (*call_again || ino == NULLFSINO) { + *ipp = NULL; + return 0; + } + ASSERT(*ialloc_context == NULL); + + /* + * Get the in-core inode with the lock held exclusively. + * This is because we're setting fields here we need + * to prevent others from looking at until we're done. + */ + error = xfs_trans_iget(tp->t_mountp, tp, ino, XFS_ILOCK_EXCL, &ip); + if (error != 0) { + return error; + } + ASSERT(ip != NULL); + + vp = XFS_ITOV(ip); + vp->v_type = IFTOVT(mode); + ip->i_d.di_mode = (__uint16_t)mode; + ip->i_d.di_onlink = 0; + ip->i_d.di_nlink = nlink; + ASSERT(ip->i_d.di_nlink == nlink); + ip->i_d.di_uid = current->fsuid; + ip->i_d.di_gid = current->fsgid; + ip->i_d.di_projid = prid; + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + + /* now that we have a v_type we can set Linux inode ops (& unlock) */ + linvfs_set_inode_ops(LINVFS_GET_IP(XFS_ITOV(ip))); + + /* + * If the superblock version is up to where we support new format + * inodes and this is currently an old format inode, then change + * the inode version number now. This way we only do the conversion + * here rather than here and in the flush/logging code. + */ + if (XFS_SB_VERSION_HASNLINK(&tp->t_mountp->m_sb) && + ip->i_d.di_version == XFS_DINODE_VERSION_1) { + ip->i_d.di_version = XFS_DINODE_VERSION_2; + /* + * We've already zeroed the old link count, the projid field, + * and the pad field. + */ + } + + /* + * Project ids won't be stored on disk if we are using a version 1 inode. + */ + if ( (prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1)) + xfs_bump_ino_vers2(tp, ip); + + if (XFS_INHERIT_GID(pip, vp->v_vfsp)) { + ip->i_d.di_gid = pip->i_d.di_gid; + if ((pip->i_d.di_mode & ISGID) && (mode & IFMT) == IFDIR) { + ip->i_d.di_mode |= ISGID; + } + } + + /* + * If the group ID of the new file does not match the effective group + * ID or one of the supplementary group IDs, the ISGID bit is cleared + * (and only if the irix_sgid_inherit compatibility variable is set). + */ + if ((irix_sgid_inherit) && + (ip->i_d.di_mode & ISGID) && + (!in_group_p((gid_t)ip->i_d.di_gid))) { + ip->i_d.di_mode &= ~ISGID; + } + + ip->i_d.di_size = 0; + ip->i_d.di_nextents = 0; + ASSERT(ip->i_d.di_nblocks == 0); + xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD); + /* + * di_gen will have been taken care of in xfs_iread. + */ + ip->i_d.di_extsize = 0; + ip->i_d.di_dmevmask = 0; + ip->i_d.di_dmstate = 0; + ip->i_d.di_flags = 0; + flags = XFS_ILOG_CORE; + switch (mode & IFMT) { + case IFIFO: + case IFCHR: + case IFBLK: + case IFSOCK: + ip->i_d.di_format = XFS_DINODE_FMT_DEV; + ip->i_df.if_u2.if_rdev = IRIX_MKDEV(MAJOR(rdev), MINOR(rdev)); + ip->i_df.if_flags = 0; + flags |= XFS_ILOG_DEV; + break; + case IFREG: + case IFDIR: + case IFLNK: + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_df.if_flags = XFS_IFEXTENTS; + ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; + ip->i_df.if_u1.if_extents = NULL; + break; + default: + ASSERT(0); + } + /* + * Attribute fork settings for new inode. + */ + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_anextents = 0; + +#if DEBUG + { + uint badflags = VNOSWAP | + VISSWAP | + VREPLICABLE | + /* VNONREPLICABLE | XXX uncomment this */ + VDOCMP | + VFRLOCKS; + + /* + * For shared mounts, VNOSWAP is set in xfs_iget + */ + if (tp->t_mountp->m_cxfstype != XFS_CXFS_NOT) + badflags &= ~VNOSWAP; + + ASSERT(!(vp->v_flag & badflags)); + } +#endif /* DEBUG */ + + /* + * Log the new values stuffed into the inode. + */ + xfs_trans_log_inode(tp, ip, flags); + *ipp = ip; + return 0; +} + +/* + * Check to make sure that there are no blocks allocated to the + * file beyond the size of the file. We don't check this for + * files with fixed size extents or real time extents, but we + * at least do it for regular files. + */ +#ifdef DEBUG +void +xfs_isize_check( + xfs_mount_t *mp, + xfs_inode_t *ip, + xfs_fsize_t isize) +{ + xfs_fileoff_t map_first; + int nimaps; + xfs_bmbt_irec_t imaps[2]; + + if ((ip->i_d.di_mode & IFMT) != IFREG) + return; + + if ( ip->i_d.di_flags & XFS_DIFLAG_REALTIME ) + return; + + nimaps = 2; + map_first = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); + /* + * The filesystem could be shutting down, so bmapi may return + * an error. + */ + if (xfs_bmapi(NULL, ip, map_first, + (XFS_B_TO_FSB(mp, + (xfs_ufsize_t)XFS_MAX_FILE_OFFSET) - + map_first), + XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps, + NULL)) + return; + ASSERT(nimaps == 1); + ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK); +} +#endif /* DEBUG */ + +/* + * Calculate the last possible buffered byte in a file. This must + * include data that was buffered beyond the EOF by the write code. + * This also needs to deal with overflowing the xfs_fsize_t type + * which can happen for sizes near the limit. + * + * We also need to take into account any blocks beyond the EOF. It + * may be the case that they were buffered by a write which failed. + * In that case the pages will still be in memory, but the inode size + * will never have been updated. + */ +xfs_fsize_t +xfs_file_last_byte( + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + xfs_fsize_t last_byte; + xfs_fileoff_t last_block; + xfs_fileoff_t size_last_block; + int error; + + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE | MR_ACCESS)); + + mp = ip->i_mount; + /* + * Only check for blocks beyond the EOF if the extents have + * been read in. This eliminates the need for the inode lock, + * and it also saves us from looking when it really isn't + * necessary. + */ + if (ip->i_df.if_flags & XFS_IFEXTENTS) { + error = xfs_bmap_last_offset(NULL, ip, &last_block, + XFS_DATA_FORK); + if (error) { + last_block = 0; + } + } else { + last_block = 0; + } + size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_d.di_size); + last_block = XFS_FILEOFF_MAX(last_block, size_last_block); + + last_byte = XFS_FSB_TO_B(mp, last_block); + if (last_byte < 0) { + return XFS_MAX_FILE_OFFSET; + } + last_byte += (1 << mp->m_writeio_log); + if (last_byte < 0) { + return XFS_MAX_FILE_OFFSET; + } + return last_byte; +} + +#if defined(XFS_RW_TRACE) +STATIC void +xfs_itrunc_trace( + int tag, + xfs_inode_t *ip, + int flag, + xfs_fsize_t new_size, + xfs_off_t toss_start, + xfs_off_t toss_finish) +{ + if (ip->i_rwtrace == NULL) { + return; + } + + ktrace_enter(ip->i_rwtrace, + (void*)((long)tag), + (void*)ip, + (void*)((ip->i_d.di_size >> 32) & 0xffffffff), + (void*)(ip->i_d.di_size & 0xffffffff), + (void*)((long)flag), + (void*)((new_size >> 32) & 0xffffffff), + (void*)(new_size & 0xffffffff), + (void*)((toss_start >> 32) & 0xffffffff), + (void*)(toss_start & 0xffffffff), + (void*)((toss_finish >> 32) & 0xffffffff), + (void*)(toss_finish & 0xffffffff), + (void*)((long)private.p_cpuid), + (void*)0, + (void*)0, + (void*)0, + (void*)0); +} +#else +#define xfs_itrunc_trace(tag, ip, flag, new_size, toss_start, toss_finish) +#endif + +/* + * Start the truncation of the file to new_size. The new size + * must be smaller than the current size. This routine will + * clear the buffer and page caches of file data in the removed + * range, and xfs_itruncate_finish() will remove the underlying + * disk blocks. + * + * The inode must have its I/O lock locked EXCLUSIVELY, and it + * must NOT have the inode lock held at all. This is because we're + * calling into the buffer/page cache code and we can't hold the + * inode lock when we do so. + * + * The flags parameter can have either the value XFS_ITRUNC_DEFINITE + * or XFS_ITRUNC_MAYBE. The XFS_ITRUNC_MAYBE value should be used + * in the case that the caller is locking things out of order and + * may not be able to call xfs_itruncate_finish() with the inode lock + * held without dropping the I/O lock. If the caller must drop the + * I/O lock before calling xfs_itruncate_finish(), then xfs_itruncate_start() + * must be called again with all the same restrictions as the initial + * call. + */ +void +xfs_itruncate_start( + xfs_inode_t *ip, + uint flags, + xfs_fsize_t new_size) +{ + xfs_fsize_t last_byte; + xfs_off_t toss_start; + xfs_mount_t *mp; + vnode_t *vp; + + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); + ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); + ASSERT((flags == XFS_ITRUNC_DEFINITE) || + (flags == XFS_ITRUNC_MAYBE)); + + mp = ip->i_mount; + vp = XFS_ITOV(ip); + /* + * Call VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES() to get rid of pages and buffers + * overlapping the region being removed. We have to use + * the less efficient VOP_FLUSHINVAL_PAGES() in the case that the + * caller may not be able to finish the truncate without + * dropping the inode's I/O lock. Make sure + * to catch any pages brought in by buffers overlapping + * the EOF by searching out beyond the isize by our + * block size. We round new_size up to a block boundary + * so that we don't toss things on the same block as + * new_size but before it. + * + * Before calling VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES(), make sure to + * call remapf() over the same region if the file is mapped. + * This frees up mapped file references to the pages in the + * given range and for the VOP_FLUSHINVAL_PAGES() case it ensures + * that we get the latest mapped changes flushed out. + */ + toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); + toss_start = XFS_FSB_TO_B(mp, toss_start); + if (toss_start < 0) { + /* + * The place to start tossing is beyond our maximum + * file size, so there is no way that the data extended + * out there. + */ + return; + } + last_byte = xfs_file_last_byte(ip); + xfs_itrunc_trace(XFS_ITRUNC_START, ip, flags, new_size, toss_start, + last_byte); + if (last_byte > toss_start) { + if (flags & XFS_ITRUNC_DEFINITE) { + VOP_TOSS_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED); + } else { + VOP_FLUSHINVAL_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED); + } + } + +#ifdef DEBUG + if (new_size == 0) { + ASSERT(VN_CACHED(vp) == 0); + } +#endif +} + +/* + * Shrink the file to the given new_size. The new + * size must be smaller than the current size. + * This will free up the underlying blocks + * in the removed range after a call to xfs_itruncate_start() + * or xfs_atruncate_start(). + * + * The transaction passed to this routine must have made + * a permanent log reservation of at least XFS_ITRUNCATE_LOG_RES. + * This routine may commit the given transaction and + * start new ones, so make sure everything involved in + * the transaction is tidy before calling here. + * Some transaction will be returned to the caller to be + * committed. The incoming transaction must already include + * the inode, and both inode locks must be held exclusively. + * The inode must also be "held" within the transaction. On + * return the inode will be "held" within the returned transaction. + * This routine does NOT require any disk space to be reserved + * for it within the transaction. + * + * The fork parameter must be either xfs_attr_fork or xfs_data_fork, + * and it indicates the fork which is to be truncated. For the + * attribute fork we only support truncation to size 0. + * + * We use the sync parameter to indicate whether or not the first + * transaction we perform might have to be synchronous. For the attr fork, + * it needs to be so if the unlink of the inode is not yet known to be + * permanent in the log. This keeps us from freeing and reusing the + * blocks of the attribute fork before the unlink of the inode becomes + * permanent. + * + * For the data fork, we normally have to run synchronously if we're + * being called out of the inactive path or we're being called + * out of the create path where we're truncating an existing file. + * Either way, the truncate needs to be sync so blocks don't reappear + * in the file with altered data in case of a crash. wsync filesystems + * can run the first case async because anything that shrinks the inode + * has to run sync so by the time we're called here from inactive, the + * inode size is permanently set to 0. + * + * Calls from the truncate path always need to be sync unless we're + * in a wsync filesystem and the file has already been unlinked. + * + * The caller is responsible for correctly setting the sync parameter. + * It gets too hard for us to guess here which path we're being called + * out of just based on inode state. + */ +int +xfs_itruncate_finish( + xfs_trans_t **tp, + xfs_inode_t *ip, + xfs_fsize_t new_size, + int fork, + int sync) +{ + xfs_fsblock_t first_block; + xfs_fileoff_t first_unmap_block; + xfs_fileoff_t last_block; + xfs_filblks_t unmap_len=0; + xfs_mount_t *mp; + xfs_trans_t *ntp; + int done; + int committed; + xfs_bmap_free_t free_list; + int error; + + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); + ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); + ASSERT(*tp != NULL); + ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); + ASSERT(ip->i_transp == *tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD); + + + ntp = *tp; + mp = (ntp)->t_mountp; + ASSERT(! XFS_NOT_DQATTACHED(mp, ip)); + + /* + * We only support truncating the entire attribute fork. + */ + if (fork == XFS_ATTR_FORK) { + new_size = 0LL; + } + first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); + xfs_itrunc_trace(XFS_ITRUNC_FINISH1, ip, 0, new_size, 0, 0); + /* + * The first thing we do is set the size to new_size permanently + * on disk. This way we don't have to worry about anyone ever + * being able to look at the data being freed even in the face + * of a crash. What we're getting around here is the case where + * we free a block, it is allocated to another file, it is written + * to, and then we crash. If the new data gets written to the + * file but the log buffers containing the free and reallocation + * don't, then we'd end up with garbage in the blocks being freed. + * As long as we make the new_size permanent before actually + * freeing any blocks it doesn't matter if they get writtten to. + * + * The callers must signal into us whether or not the size + * setting here must be synchronous. There are a few cases + * where it doesn't have to be synchronous. Those cases + * occur if the file is unlinked and we know the unlink is + * permanent or if the blocks being truncated are guaranteed + * to be beyond the inode eof (regardless of the link count) + * and the eof value is permanent. Both of these cases occur + * only on wsync-mounted filesystems. In those cases, we're + * guaranteed that no user will ever see the data in the blocks + * that are being truncated so the truncate can run async. + * In the free beyond eof case, the file may wind up with + * more blocks allocated to it than it needs if we crash + * and that won't get fixed until the next time the file + * is re-opened and closed but that's ok as that shouldn't + * be too many blocks. + * + * However, we can't just make all wsync xactions run async + * because there's one call out of the create path that needs + * to run sync where it's truncating an existing file to size + * 0 whose size is > 0. + * + * It's probably possible to come up with a test in this + * routine that would correctly distinguish all the above + * cases from the values of the function parameters and the + * inode state but for sanity's sake, I've decided to let the + * layers above just tell us. It's simpler to correctly figure + * out in the layer above exactly under what conditions we + * can run async and I think it's easier for others read and + * follow the logic in case something has to be changed. + * cscope is your friend -- rcc. + * + * The attribute fork is much simpler. + * + * For the attribute fork we allow the caller to tell us whether + * the unlink of the inode that led to this call is yet permanent + * in the on disk log. If it is not and we will be freeing extents + * in this inode then we make the first transaction synchronous + * to make sure that the unlink is permanent by the time we free + * the blocks. + */ + if (fork == XFS_DATA_FORK) { + if (ip->i_d.di_nextents > 0) { + ip->i_d.di_size = new_size; + xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); + } + } else if (sync) { + ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC)); + if (ip->i_d.di_anextents > 0) + xfs_trans_set_sync(ntp); + } + ASSERT(fork == XFS_DATA_FORK || + (fork == XFS_ATTR_FORK && + ((sync && !(mp->m_flags & XFS_MOUNT_WSYNC)) || + (sync == 0 && (mp->m_flags & XFS_MOUNT_WSYNC))))); + + /* + * Since it is possible for space to become allocated beyond + * the end of the file (in a crash where the space is allocated + * but the inode size is not yet updated), simply remove any + * blocks which show up between the new EOF and the maximum + * possible file size. If the first block to be removed is + * beyond the maximum file size (ie it is the same as last_block), + * then there is nothing to do. + */ + last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET); + ASSERT(first_unmap_block <= last_block); + done = 0; + if (last_block == first_unmap_block) { + done = 1; + } else { + unmap_len = last_block - first_unmap_block + 1; + } + while (!done) { + /* + * Free up up to XFS_ITRUNC_MAX_EXTENTS. xfs_bunmapi() + * will tell us whether it freed the entire range or + * not. If this is a synchronous mount (wsync), + * then we can tell bunmapi to keep all the + * transactions asynchronous since the unlink + * transaction that made this inode inactive has + * already hit the disk. There's no danger of + * the freed blocks being reused, there being a + * crash, and the reused blocks suddenly reappearing + * in this file with garbage in them once recovery + * runs. + */ + XFS_BMAP_INIT(&free_list, &first_block); + error = xfs_bunmapi(ntp, ip, first_unmap_block, + unmap_len, + XFS_BMAPI_AFLAG(fork) | + (sync ? 0 : XFS_BMAPI_ASYNC), + XFS_ITRUNC_MAX_EXTENTS, + &first_block, &free_list, &done); + if (error) { + /* + * If the bunmapi call encounters an error, + * return to the caller where the transaction + * can be properly aborted. We just need to + * make sure we're not holding any resources + * that we were not when we came in. + */ + xfs_bmap_cancel(&free_list); + return error; + } + + /* + * Duplicate the transaction that has the permanent + * reservation and commit the old transaction. + */ + error = xfs_bmap_finish(tp, &free_list, first_block, + &committed); + ntp = *tp; + if (error) { + /* + * If the bmap finish call encounters an error, + * return to the caller where the transaction + * can be properly aborted. We just need to + * make sure we're not holding any resources + * that we were not when we came in. + * + * Aborting from this point might lose some + * blocks in the file system, but oh well. + */ + xfs_bmap_cancel(&free_list); + if (committed) { + /* + * If the passed in transaction committed + * in xfs_bmap_finish(), then we want to + * add the inode to this one before returning. + * This keeps things simple for the higher + * level code, because it always knows that + * the inode is locked and held in the + * transaction that returns to it whether + * errors occur or not. We don't mark the + * inode dirty so that this transaction can + * be easily aborted if possible. + */ + xfs_trans_ijoin(ntp, ip, + XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(ntp, ip); + } + return error; + } + + if (committed) { + /* + * The first xact was committed, + * so add the inode to the new one. + * Mark it dirty so it will be logged + * and moved forward in the log as + * part of every commit. + */ + xfs_trans_ijoin(ntp, ip, + XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(ntp, ip); + xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); + } + ntp = xfs_trans_dup(ntp); + (void) xfs_trans_commit(*tp, 0, NULL); + *tp = ntp; + error = xfs_trans_reserve(ntp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + /* + * Add the inode being truncated to the next chained + * transaction. + */ + xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(ntp, ip); + if (error) + return (error); + } + /* + * Only update the size in the case of the data fork, but + * always re-log the inode so that our permanent transaction + * can keep on rolling it forward in the log. + */ + if (fork == XFS_DATA_FORK) { + xfs_isize_check(mp, ip, new_size); + ip->i_d.di_size = new_size; + } + xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); + ASSERT((new_size != 0) || + (fork == XFS_ATTR_FORK) || + (ip->i_delayed_blks == 0)); + ASSERT((new_size != 0) || + (fork == XFS_ATTR_FORK) || + (ip->i_d.di_nextents == 0)); + xfs_itrunc_trace(XFS_ITRUNC_FINISH2, ip, 0, new_size, 0, 0); + return 0; +} + + +/* + * xfs_igrow_start + * + * Do the first part of growing a file: zero any data in the last + * block that is beyond the old EOF. We need to do this before + * the inode is joined to the transaction to modify the i_size. + * That way we can drop the inode lock and call into the buffer + * cache to get the buffer mapping the EOF. + */ +int +xfs_igrow_start( + xfs_inode_t *ip, + xfs_fsize_t new_size, + cred_t *credp) +{ + xfs_fsize_t isize; + int error; + + ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0); + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); + ASSERT(new_size > ip->i_d.di_size); + + error = 0; + isize = ip->i_d.di_size; + /* + * Zero any pages that may have been created by + * xfs_write_file() beyond the end of the file + * and any blocks between the old and new file sizes. + */ + error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, isize, + new_size, NULL); + return error; +} + +/* + * xfs_igrow_finish + * + * This routine is called to extend the size of a file. + * The inode must have both the iolock and the ilock locked + * for update and it must be a part of the current transaction. + * The xfs_igrow_start() function must have been called previously. + * If the change_flag is not zero, the inode change timestamp will + * be updated. + */ +void +xfs_igrow_finish( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_fsize_t new_size, + int change_flag) +{ + ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0); + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); + ASSERT(ip->i_transp == tp); + ASSERT(new_size > ip->i_d.di_size); + + /* + * Update the file size. Update the inode change timestamp + * if change_flag set. + */ + ip->i_d.di_size = new_size; + if (change_flag) + xfs_ichgtime(ip, XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + +} + + +/* + * This is called when the inode's link count goes to 0. + * We place the on-disk inode on a list in the AGI. It + * will be pulled from this list when the inode is freed. + */ +int +xfs_iunlink( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + xfs_agi_t *agi; + xfs_dinode_t *dip; + xfs_buf_t *agibp; + xfs_buf_t *ibp; + xfs_agnumber_t agno; + xfs_daddr_t agdaddr; + xfs_agino_t agino; + short bucket_index; + int offset; + int error; + int agi_ok; + + ASSERT(ip->i_d.di_nlink == 0); + ASSERT(ip->i_d.di_mode != 0); + ASSERT(ip->i_transp == tp); + + mp = tp->t_mountp; + + agno = XFS_INO_TO_AGNO(mp, ip->i_ino); + agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + + /* + * Get the agi buffer first. It ensures lock ordering + * on the list. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr, + 1, 0, &agibp); + if (error) { + return error; + } + /* + * Validate the magic number of the agi block. + */ + agi = XFS_BUF_TO_AGI(agibp); + agi_ok = + INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC && + XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK, + XFS_RANDOM_IUNLINK)) { + xfs_trans_brelse(tp, agibp); + return XFS_ERROR(EFSCORRUPTED); + } + /* + * Get the index into the agi hash table for the + * list this inode will go on. + */ + agino = XFS_INO_TO_AGINO(mp, ip->i_ino); + ASSERT(agino != 0); + bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; + ASSERT(!INT_ISZERO(agi->agi_unlinked[bucket_index], ARCH_CONVERT)); + ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != agino); + + if (INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != NULLAGINO) { + /* + * There is already another inode in the bucket we need + * to add ourselves to. Add us at the front of the list. + * Here we put the head pointer into our next pointer, + * and then we fall through to point the head at us. + */ + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); + if (error) { + return error; + } + ASSERT(INT_GET(dip->di_next_unlinked, ARCH_CONVERT) == NULLAGINO); + ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)); + /* both on-disk, don't endian flip twice */ + dip->di_next_unlinked = agi->agi_unlinked[bucket_index]; + offset = ip->i_boffset + + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, ibp); + xfs_trans_log_buf(tp, ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, ibp); + } + + /* + * Point the bucket head pointer at the inode being inserted. + */ + ASSERT(agino != 0); + INT_SET(agi->agi_unlinked[bucket_index], ARCH_CONVERT, agino); + offset = offsetof(xfs_agi_t, agi_unlinked) + + (sizeof(xfs_agino_t) * bucket_index); + xfs_trans_log_buf(tp, agibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + return 0; +} + +/* + * Pull the on-disk inode from the AGI unlinked list. + */ +STATIC int +xfs_iunlink_remove( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + xfs_ino_t next_ino; + xfs_mount_t *mp; + xfs_agi_t *agi; + xfs_dinode_t *dip; + xfs_buf_t *agibp; + xfs_buf_t *ibp; + xfs_agnumber_t agno; + xfs_daddr_t agdaddr; + xfs_agino_t agino; + xfs_agino_t next_agino; + xfs_buf_t *last_ibp; + xfs_dinode_t *last_dip; + short bucket_index; + int offset, last_offset; + int error; + int agi_ok; + + /* + * First pull the on-disk inode from the AGI unlinked list. + */ + mp = tp->t_mountp; + + agno = XFS_INO_TO_AGNO(mp, ip->i_ino); + agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + + /* + * Get the agi buffer first. It ensures lock ordering + * on the list. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr, + 1, 0, &agibp); + if (error != 0) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_trans_read_buf() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + /* + * Validate the magic number of the agi block. + */ + agi = XFS_BUF_TO_AGI(agibp); + agi_ok = + INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC && + XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK_REMOVE, + XFS_RANDOM_IUNLINK_REMOVE)) { + xfs_trans_brelse(tp, agibp); + cmn_err(CE_WARN, + "xfs_iunlink_remove: XFS_TEST_ERROR() returned an error on %s. Returning EFSCORRUPTED.", + mp->m_fsname); + return XFS_ERROR(EFSCORRUPTED); + } + /* + * Get the index into the agi hash table for the + * list this inode will go on. + */ + agino = XFS_INO_TO_AGINO(mp, ip->i_ino); + ASSERT(agino != 0); + bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; + ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != NULLAGINO); + ASSERT(!INT_ISZERO(agi->agi_unlinked[bucket_index], ARCH_CONVERT)); + + if (INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) == agino) { + /* + * We're at the head of the list. Get the inode's + * on-disk buffer to see if there is anyone after us + * on the list. Only modify our next pointer if it + * is not already NULLAGINO. This saves us the overhead + * of dealing with the buffer when there is no need to + * change it. + */ + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); + if (error) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + next_agino = INT_GET(dip->di_next_unlinked, ARCH_CONVERT); + ASSERT(next_agino != 0); + if (next_agino != NULLAGINO) { + INT_SET(dip->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + offset = ip->i_boffset + + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, ibp); + xfs_trans_log_buf(tp, ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, ibp); + } else { + xfs_trans_brelse(tp, ibp); + } + /* + * Point the bucket head pointer at the next inode. + */ + ASSERT(next_agino != 0); + ASSERT(next_agino != agino); + INT_SET(agi->agi_unlinked[bucket_index], ARCH_CONVERT, next_agino); + offset = offsetof(xfs_agi_t, agi_unlinked) + + (sizeof(xfs_agino_t) * bucket_index); + xfs_trans_log_buf(tp, agibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + } else { + /* + * We need to search the list for the inode being freed. + */ + next_agino = INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT); + last_ibp = NULL; + while (next_agino != agino) { + /* + * If the last inode wasn't the one pointing to + * us, then release its buffer since we're not + * going to do anything with it. + */ + if (last_ibp != NULL) { + xfs_trans_brelse(tp, last_ibp); + } + next_ino = XFS_AGINO_TO_INO(mp, agno, next_agino); + error = xfs_inotobp(mp, tp, next_ino, &last_dip, + &last_ibp, &last_offset); + if (error) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_inotobp() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + next_agino = INT_GET(last_dip->di_next_unlinked, ARCH_CONVERT); + ASSERT(next_agino != NULLAGINO); + ASSERT(next_agino != 0); + } + /* + * Now last_ibp points to the buffer previous to us on + * the unlinked list. Pull us from the list. + */ + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); + if (error) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + next_agino = INT_GET(dip->di_next_unlinked, ARCH_CONVERT); + ASSERT(next_agino != 0); + ASSERT(next_agino != agino); + if (next_agino != NULLAGINO) { + INT_SET(dip->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + offset = ip->i_boffset + + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, ibp); + xfs_trans_log_buf(tp, ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, ibp); + } else { + xfs_trans_brelse(tp, ibp); + } + /* + * Point the previous inode on the list to the next inode. + */ + INT_SET(last_dip->di_next_unlinked, ARCH_CONVERT, next_agino); + ASSERT(next_agino != 0); + offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, last_ibp); + xfs_trans_log_buf(tp, last_ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, last_ibp); + } + return 0; +} + +/* + * This is called to return an inode to the inode free list. + * The inode should already be truncated to 0 length and have + * no pages associated with it. This routine also assumes that + * the inode is already a part of the transaction. + * + * The on-disk copy of the inode will have been added to the list + * of unlinked inodes in the AGI. We need to remove the inode from + * that list atomically with respect to freeing it here. + */ +int +xfs_ifree( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + int error; + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_d.di_nlink == 0); + ASSERT(ip->i_d.di_nextents == 0); + ASSERT(ip->i_d.di_anextents == 0); + ASSERT((ip->i_d.di_size == 0) || + ((ip->i_d.di_mode & IFMT) != IFREG)); + ASSERT(ip->i_d.di_nblocks == 0); + + /* + * Pull the on-disk inode from the AGI unlinked list. + */ + error = xfs_iunlink_remove(tp, ip); + if (error != 0) { + return error; + } + + error = xfs_difree(tp, ip->i_ino); + if (error != 0) { + return error; + } + ip->i_d.di_mode = 0; /* mark incore inode as free */ + ip->i_d.di_flags = 0; + ip->i_d.di_dmevmask = 0; + ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + + /* + * Bump the generation count so no one will be confused + * by reincarnations of this inode. + */ + ip->i_d.di_gen++; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + return 0; +} + +/* + * Reallocate the space for if_broot based on the number of records + * being added or deleted as indicated in rec_diff. Move the records + * and pointers in if_broot to fit the new size. When shrinking this + * will eliminate holes between the records and pointers created by + * the caller. When growing this will create holes to be filled in + * by the caller. + * + * The caller must not request to add more records than would fit in + * the on-disk inode root. If the if_broot is currently NULL, then + * if we adding records one will be allocated. The caller must also + * not request that the number of records go below zero, although + * it can go to zero. + * + * ip -- the inode whose if_broot area is changing + * ext_diff -- the change in the number of records, positive or negative, + * requested for the if_broot array. + */ +void +xfs_iroot_realloc( + xfs_inode_t *ip, + int rec_diff, + int whichfork) +{ + int cur_max; + xfs_ifork_t *ifp; + xfs_bmbt_block_t *new_broot; + int new_max; + size_t new_size; + char *np; + char *op; + + /* + * Handle the degenerate case quietly. + */ + if (rec_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (rec_diff > 0) { + /* + * If there wasn't any memory allocated before, just + * allocate it now and get out. + */ + if (ifp->if_broot_bytes == 0) { + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff); + ifp->if_broot = (xfs_bmbt_block_t*)kmem_alloc(new_size, + KM_SLEEP); + ifp->if_broot_bytes = (int)new_size; + return; + } + + /* + * If there is already an existing if_broot, then we need + * to realloc() it and shift the pointers to their new + * location. The records don't change location because + * they are kept butted up against the btree block header. + */ + cur_max = XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes); + new_max = cur_max + rec_diff; + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); + ifp->if_broot = (xfs_bmbt_block_t *) + kmem_realloc(ifp->if_broot, + new_size, + (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */ + KM_SLEEP); + op = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + (int)new_size); + ifp->if_broot_bytes = (int)new_size; + ASSERT(ifp->if_broot_bytes <= + XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); + ovbcopy(op, np, cur_max * (uint)sizeof(xfs_dfsbno_t)); + return; + } + + /* + * rec_diff is less than 0. In this case, we are shrinking the + * if_broot buffer. It must already exist. If we go to zero + * records, just get rid of the root and clear the status bit. + */ + ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); + cur_max = XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes); + new_max = cur_max + rec_diff; + ASSERT(new_max >= 0); + if (new_max > 0) + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); + else + new_size = 0; + if (new_size > 0) { + new_broot = (xfs_bmbt_block_t *)kmem_alloc(new_size, KM_SLEEP); + /* + * First copy over the btree block header. + */ + bcopy(ifp->if_broot, new_broot, sizeof(xfs_bmbt_block_t)); + } else { + new_broot = NULL; + ifp->if_flags &= ~XFS_IFBROOT; + } + + /* + * Only copy the records and pointers if there are any. + */ + if (new_max > 0) { + /* + * First copy the records. + */ + op = (char *)XFS_BMAP_BROOT_REC_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_REC_ADDR(new_broot, 1, + (int)new_size); + bcopy(op, np, new_max * (uint)sizeof(xfs_bmbt_rec_t)); + + /* + * Then copy the pointers. + */ + op = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_PTR_ADDR(new_broot, 1, + (int)new_size); + bcopy(op, np, new_max * (uint)sizeof(xfs_dfsbno_t)); + } + kmem_free(ifp->if_broot, ifp->if_broot_bytes); + ifp->if_broot = new_broot; + ifp->if_broot_bytes = (int)new_size; + ASSERT(ifp->if_broot_bytes <= + XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); + return; +} + + +/* + * This is called when the amount of space needed for if_extents + * is increased or decreased. The change in size is indicated by + * the number of extents that need to be added or deleted in the + * ext_diff parameter. + * + * If the amount of space needed has decreased below the size of the + * inline buffer, then switch to using the inline buffer. Otherwise, + * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer + * to what is needed. + * + * ip -- the inode whose if_extents area is changing + * ext_diff -- the change in the number of extents, positive or negative, + * requested for the if_extents array. + */ +void +xfs_iext_realloc( + xfs_inode_t *ip, + int ext_diff, + int whichfork) +{ + int byte_diff; + xfs_ifork_t *ifp; + int new_size; + uint rnew_size; + + if (ext_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + byte_diff = ext_diff * (uint)sizeof(xfs_bmbt_rec_t); + new_size = (int)ifp->if_bytes + byte_diff; + ASSERT(new_size >= 0); + + if (new_size == 0) { + if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); + } + ifp->if_u1.if_extents = NULL; + rnew_size = 0; + } else if (new_size <= sizeof(ifp->if_u2.if_inline_ext)) { + /* + * If the valid extents can fit in if_inline_ext, + * copy them from the malloc'd vector and free it. + */ + if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) { + /* + * For now, empty files are format EXTENTS, + * so the if_extents pointer is null. + */ + if (ifp->if_u1.if_extents) { + bcopy(ifp->if_u1.if_extents, + ifp->if_u2.if_inline_ext, new_size); + kmem_free(ifp->if_u1.if_extents, + ifp->if_real_bytes); + } + ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; + } + rnew_size = 0; + } else { + rnew_size = new_size; + if ((rnew_size & (rnew_size - 1)) != 0) + rnew_size = xfs_iroundup(rnew_size); + /* + * Stuck with malloc/realloc. + */ + if (ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext) { + ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) + kmem_alloc(rnew_size, KM_SLEEP); + bcopy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, + sizeof(ifp->if_u2.if_inline_ext)); + } else if (rnew_size != ifp->if_real_bytes) { + ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) + kmem_realloc(ifp->if_u1.if_extents, + rnew_size, + ifp->if_real_bytes, + KM_NOFS); + } + } + ifp->if_real_bytes = rnew_size; + ifp->if_bytes = new_size; +} + + +/* + * This is called when the amount of space needed for if_data + * is increased or decreased. The change in size is indicated by + * the number of bytes that need to be added or deleted in the + * byte_diff parameter. + * + * If the amount of space needed has decreased below the size of the + * inline buffer, then switch to using the inline buffer. Otherwise, + * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer + * to what is needed. + * + * ip -- the inode whose if_data area is changing + * byte_diff -- the change in the number of bytes, positive or negative, + * requested for the if_data array. + */ +void +xfs_idata_realloc( + xfs_inode_t *ip, + int byte_diff, + int whichfork) +{ + xfs_ifork_t *ifp; + int new_size; + int real_size; + + if (byte_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + new_size = (int)ifp->if_bytes + byte_diff; + ASSERT(new_size >= 0); + + if (new_size == 0) { + if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + } + ifp->if_u1.if_data = NULL; + real_size = 0; + } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) { + /* + * If the valid extents/data can fit in if_inline_ext/data, + * copy them from the malloc'd vector and free it. + */ + if (ifp->if_u1.if_data == NULL) { + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + ASSERT(ifp->if_real_bytes != 0); + bcopy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, + new_size); + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + } + real_size = 0; + } else { + /* + * Stuck with malloc/realloc. + * For inline data, the underlying buffer must be + * a multiple of 4 bytes in size so that it can be + * logged and stay on word boundaries. We enforce + * that here. + */ + real_size = roundup(new_size, 4); + if (ifp->if_u1.if_data == NULL) { + ASSERT(ifp->if_real_bytes == 0); + ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); + } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + /* + * Only do the realloc if the underlying size + * is really changing. + */ + if (ifp->if_real_bytes != real_size) { + ifp->if_u1.if_data = + kmem_realloc(ifp->if_u1.if_data, + real_size, + ifp->if_real_bytes, + KM_SLEEP); + } + } else { + ASSERT(ifp->if_real_bytes == 0); + ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); + bcopy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, + ifp->if_bytes); + } + } + ifp->if_real_bytes = real_size; + ifp->if_bytes = new_size; + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); +} + + + + +/* + * Map inode to disk block and offset. + * + * mp -- the mount point structure for the current file system + * tp -- the current transaction + * ino -- the inode number of the inode to be located + * imap -- this structure is filled in with the information necessary + * to retrieve the given inode from disk + * flags -- flags to pass to xfs_dilocate indicating whether or not + * lookups in the inode btree were OK or not + */ +int +xfs_imap( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_imap_t *imap, + uint flags) +{ + xfs_fsblock_t fsbno; + int len; + int off; + int error; + + fsbno = imap->im_blkno ? + XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK; + error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags); + if (error != 0) { + return error; + } + imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno); + imap->im_len = XFS_FSB_TO_BB(mp, len); + imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno); + imap->im_ioffset = (ushort)off; + imap->im_boffset = (ushort)(off << mp->m_sb.sb_inodelog); + return 0; +} + +void +xfs_idestroy_fork( + xfs_inode_t *ip, + int whichfork) +{ + xfs_ifork_t *ifp; + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (ifp->if_broot != NULL) { + kmem_free(ifp->if_broot, ifp->if_broot_bytes); + ifp->if_broot = NULL; + } + + /* + * If the format is local, then we can't have an extents + * array so just look for an inline data array. If we're + * not local then we may or may not have an extents list, + * so check and free it up if we do. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && + (ifp->if_u1.if_data != NULL)) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + ifp->if_u1.if_data = NULL; + ifp->if_real_bytes = 0; + } + } else if ((ifp->if_flags & XFS_IFEXTENTS) && + (ifp->if_u1.if_extents != NULL) && + (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); + ifp->if_u1.if_extents = NULL; + ifp->if_real_bytes = 0; + } + ASSERT(ifp->if_u1.if_extents == NULL || + ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); + ASSERT(ifp->if_real_bytes == 0); + if (whichfork == XFS_ATTR_FORK) { + kmem_zone_free(xfs_ifork_zone, ip->i_afp); + ip->i_afp = NULL; + } +} + +/* + * This is called free all the memory associated with an inode. + * It must free the inode itself and any buffers allocated for + * if_extents/if_data and if_broot. It must also free the lock + * associated with the inode. + */ +void +xfs_idestroy( + xfs_inode_t *ip) +{ + + switch (ip->i_d.di_mode & IFMT) { + case IFREG: + case IFDIR: + case IFLNK: + xfs_idestroy_fork(ip, XFS_DATA_FORK); + break; + } + if (ip->i_afp) + xfs_idestroy_fork(ip, XFS_ATTR_FORK); +#ifdef NOTYET + if (ip->i_range_lock.r_sleep != NULL) { + freesema(ip->i_range_lock.r_sleep); + kmem_free(ip->i_range_lock.r_sleep, sizeof(sema_t)); + } +#endif /* NOTYET */ + mrfree(&ip->i_lock); + mrfree(&ip->i_iolock); +#ifdef NOTYET + mutex_destroy(&ip->i_range_lock.r_spinlock); +#endif /* NOTYET */ + freesema(&ip->i_flock); +#ifdef XFS_BMAP_TRACE + ktrace_free(ip->i_xtrace); +#endif +#ifdef XFS_BMBT_TRACE + ktrace_free(ip->i_btrace); +#endif +#ifdef XFS_RW_TRACE + ktrace_free(ip->i_rwtrace); +#endif +#ifdef XFS_STRAT_TRACE + ktrace_free(ip->i_strat_trace); +#endif +#ifdef XFS_ILOCK_TRACE + ktrace_free(ip->i_lock_trace); +#endif +#ifdef XFS_DIR2_TRACE + ktrace_free(ip->i_dir_trace); +#endif + if (ip->i_itemp) { + /* XXXdpd should be able to assert this but shutdown + * is leaving the AIL behind. */ + ASSERT(((ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL) == 0) || + XFS_FORCED_SHUTDOWN(ip->i_mount)); + xfs_inode_item_destroy(ip); + } + kmem_zone_free(xfs_inode_zone, ip); +} + + +/* + * Increment the pin count of the given buffer. + * This value is protected by ipinlock spinlock in the mount structure. + */ +void +xfs_ipin( + xfs_inode_t *ip) +{ + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + + atomic_inc(&ip->i_pincount); +} + +/* + * Decrement the pin count of the given inode, and wake up + * anyone in xfs_iwait_unpin() if the count goes to 0. The + * inode must have been previoulsy pinned with a call to xfs_ipin(). + */ +void +xfs_iunpin( + xfs_inode_t *ip) +{ + ASSERT(atomic_read(&ip->i_pincount) > 0); + + if (atomic_dec_and_test(&ip->i_pincount)) { + wake_up(&ip->i_ipin_wait); + } +} + +/* + * This is called to wait for the given inode to be unpinned. + * It will sleep until this happens. The caller must have the + * inode locked in at least shared mode so that the buffer cannot + * be subsequently pinned once someone is waiting for it to be + * unpinned. + */ +void +xfs_iunpin_wait( + xfs_inode_t *ip) +{ + xfs_inode_log_item_t *iip; + xfs_lsn_t lsn; + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE | MR_ACCESS)); + + if (atomic_read(&ip->i_pincount) == 0) { + return; + } + + iip = ip->i_itemp; + if (iip && iip->ili_last_lsn) { + lsn = iip->ili_last_lsn; + } else { + lsn = (xfs_lsn_t)0; + } + + /* + * Give the log a push so we don't wait here too long. + */ + xfs_log_force(ip->i_mount, lsn, XFS_LOG_FORCE); + + wait_event(ip->i_ipin_wait, (atomic_read(&ip->i_pincount) == 0)); +} + + +/* + * xfs_iextents_copy() + * + * This is called to copy the REAL extents (as opposed to the delayed + * allocation extents) from the inode into the given buffer. It + * returns the number of bytes copied into the buffer. + * + * If there are no delayed allocation extents, then we can just + * bcopy() the extents into the buffer. Otherwise, we need to + * examine each extent in turn and skip those which are delayed. + */ +int +xfs_iextents_copy( + xfs_inode_t *ip, + xfs_bmbt_rec_32_t *buffer, + int whichfork) +{ + int copied; + xfs_bmbt_rec_32_t *dest_ep; + xfs_bmbt_rec_t *ep; +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_iextents_copy"; +#endif + int i; + xfs_ifork_t *ifp; + int nrecs; + xfs_fsblock_t start_block; + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); + ASSERT(ifp->if_bytes > 0); + + nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork); + ASSERT(nrecs > 0); + if (nrecs == XFS_IFORK_NEXTENTS(ip, whichfork)) { + /* + * There are no delayed allocation extents, + * so just copy everything. + */ + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); + ASSERT(ifp->if_bytes == + (XFS_IFORK_NEXTENTS(ip, whichfork) * + (uint)sizeof(xfs_bmbt_rec_t))); + bcopy(ifp->if_u1.if_extents, buffer, ifp->if_bytes); + xfs_validate_extents(buffer, nrecs, XFS_EXTFMT_INODE(ip)); + return ifp->if_bytes; + } + + ASSERT(whichfork == XFS_DATA_FORK); + /* + * There are some delayed allocation extents in the + * inode, so copy the extents one at a time and skip + * the delayed ones. There must be at least one + * non-delayed extent. + */ + ASSERT(nrecs > ip->i_d.di_nextents); + ep = ifp->if_u1.if_extents; + dest_ep = buffer; + copied = 0; + for (i = 0; i < nrecs; i++) { + start_block = xfs_bmbt_get_startblock(ep); + if (ISNULLSTARTBLOCK(start_block)) { + /* + * It's a delayed allocation extent, so skip it. + */ + ep++; + continue; + } + + *dest_ep = *(xfs_bmbt_rec_32_t *)ep; + dest_ep++; + ep++; + copied++; + } + ASSERT(copied != 0); + ASSERT(copied == ip->i_d.di_nextents); + ASSERT((copied * (uint)sizeof(xfs_bmbt_rec_t)) <= XFS_IFORK_DSIZE(ip)); + xfs_validate_extents(buffer, copied, XFS_EXTFMT_INODE(ip)); + + return (copied * (uint)sizeof(xfs_bmbt_rec_t)); +} + +/* + * Each of the following cases stores data into the same region + * of the on-disk inode, so only one of them can be valid at + * any given time. While it is possible to have conflicting formats + * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is + * in EXTENTS format, this can only happen when the fork has + * changed formats after being modified but before being flushed. + * In these cases, the format always takes precedence, because the + * format indicates the current state of the fork. + */ +/*ARGSUSED*/ +STATIC int +xfs_iflush_fork( + xfs_inode_t *ip, + xfs_dinode_t *dip, + xfs_inode_log_item_t *iip, + int whichfork, + xfs_buf_t *bp) +{ + char *cp; + xfs_ifork_t *ifp; + xfs_mount_t *mp; +#ifdef XFS_TRANS_DEBUG + int first; +#endif + static const short brootflag[2] = + { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; + static const short dataflag[2] = + { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; + static const short extflag[2] = + { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; + + if (iip == NULL) + return 0; + ifp = XFS_IFORK_PTR(ip, whichfork); + /* + * This can happen if we gave up in iformat in an error path, + * for the attribute fork. + */ + if (ifp == NULL) { + ASSERT(whichfork == XFS_ATTR_FORK); + return 0; + } + cp = XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + mp = ip->i_mount; + switch (XFS_IFORK_FORMAT(ip, whichfork)) { + case XFS_DINODE_FMT_LOCAL: + if ((iip->ili_format.ilf_fields & dataflag[whichfork]) && + (ifp->if_bytes > 0)) { + ASSERT(ifp->if_u1.if_data != NULL); + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); + bcopy(ifp->if_u1.if_data, cp, ifp->if_bytes); + } + if (whichfork == XFS_DATA_FORK) { + if (XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip)) { + return XFS_ERROR(EFSCORRUPTED); + } + } + break; + + case XFS_DINODE_FMT_EXTENTS: + ASSERT((ifp->if_flags & XFS_IFEXTENTS) || + !(iip->ili_format.ilf_fields & extflag[whichfork])); + ASSERT((ifp->if_u1.if_extents != NULL) || (ifp->if_bytes == 0)); + ASSERT((ifp->if_u1.if_extents == NULL) || (ifp->if_bytes > 0)); + if ((iip->ili_format.ilf_fields & extflag[whichfork]) && + (ifp->if_bytes > 0)) { + ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); + (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_32_t *)cp, + whichfork); + } + break; + + case XFS_DINODE_FMT_BTREE: + if ((iip->ili_format.ilf_fields & brootflag[whichfork]) && + (ifp->if_broot_bytes > 0)) { + ASSERT(ifp->if_broot != NULL); + ASSERT(ifp->if_broot_bytes <= + (XFS_IFORK_SIZE(ip, whichfork) + + XFS_BROOT_SIZE_ADJ)); + xfs_bmbt_to_bmdr(ifp->if_broot, ifp->if_broot_bytes, + (xfs_bmdr_block_t *)cp, + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT)); + } + break; + + case XFS_DINODE_FMT_DEV: + if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) { + ASSERT(whichfork == XFS_DATA_FORK); + INT_SET(dip->di_u.di_dev, ARCH_CONVERT, ip->i_df.if_u2.if_rdev); + } + break; + + case XFS_DINODE_FMT_UUID: + if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) { + ASSERT(whichfork == XFS_DATA_FORK); + bcopy(&ip->i_df.if_u2.if_uuid, &dip->di_u.di_muuid, + sizeof(uuid_t)); + } + break; + + default: + ASSERT(0); + break; + } + + return 0; +} + +/* + * xfs_iflush() will write a modified inode's changes out to the + * inode's on disk home. The caller must have the inode lock held + * in at least shared mode and the inode flush semaphore must be + * held as well. The inode lock will still be held upon return from + * the call and the caller is free to unlock it. + * The inode flush lock will be unlocked when the inode reaches the disk. + * The flags indicate how the inode's buffer should be written out. + */ +int +xfs_iflush( + xfs_inode_t *ip, + uint flags) +{ + xfs_inode_log_item_t *iip; + xfs_buf_t *bp; + xfs_dinode_t *dip; + xfs_mount_t *mp; + int error; + /* REFERENCED */ + xfs_chash_t *ch; + xfs_inode_t *iq; + int clcount; /* count of inodes clustered */ + int bufwasdelwri; + enum { INT_DELWRI = (1 << 0), INT_ASYNC = (1 << 1) }; + SPLDECL(s); + + XFS_STATS_INC(xfsstats.xs_iflush_count); + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); + ASSERT(valusema(&ip->i_flock) <= 0); + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || + ip->i_d.di_nextents > ip->i_df.if_ext_max); + + iip = ip->i_itemp; + mp = ip->i_mount; + + /* + * If the inode isn't dirty, then just release the inode + * flush lock and do nothing. + */ + if ((ip->i_update_core == 0) && + ((iip == NULL) || !(iip->ili_format.ilf_fields & XFS_ILOG_ALL))) { + ASSERT((iip != NULL) ? + !(iip->ili_item.li_flags & XFS_LI_IN_AIL) : 1); + xfs_ifunlock(ip); + return 0; + } + + /* + * We can't flush the inode until it is unpinned, so + * wait for it. We know noone new can pin it, because + * we are holding the inode lock shared and you need + * to hold it exclusively to pin the inode. + */ + xfs_iunpin_wait(ip); + + /* + * This may have been unpinned because the filesystem is shutting + * down forcibly. If that's the case we must not write this inode + * to disk, because the log record didn't make it to disk! + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + ip->i_update_core = 0; + if (iip) + iip->ili_format.ilf_fields = 0; + xfs_ifunlock(ip); + return XFS_ERROR(EIO); + } + + /* + * Get the buffer containing the on-disk inode. + */ + error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0); + if (error != 0) { + xfs_ifunlock(ip); + return error; + } + + /* + * Decide how buffer will be flushed out. This is done before + * the call to xfs_iflush_int because this field is zeroed by it. + */ + if (iip != NULL && iip->ili_format.ilf_fields != 0) { + /* + * Flush out the inode buffer according to the directions + * of the caller. In the cases where the caller has given + * us a choice choose the non-delwri case. This is because + * the inode is in the AIL and we need to get it out soon. + */ + switch (flags) { + case XFS_IFLUSH_SYNC: + case XFS_IFLUSH_DELWRI_ELSE_SYNC: + flags = 0; + break; + case XFS_IFLUSH_ASYNC: + case XFS_IFLUSH_DELWRI_ELSE_ASYNC: + flags = INT_ASYNC; + break; + case XFS_IFLUSH_DELWRI: + flags = INT_DELWRI; + break; + default: + ASSERT(0); + flags = 0; + break; + } + } else { + switch (flags) { + case XFS_IFLUSH_DELWRI_ELSE_SYNC: + case XFS_IFLUSH_DELWRI_ELSE_ASYNC: + case XFS_IFLUSH_DELWRI: + flags = INT_DELWRI; + break; + case XFS_IFLUSH_ASYNC: + flags = INT_ASYNC; + break; + case XFS_IFLUSH_SYNC: + flags = 0; + break; + default: + ASSERT(0); + flags = 0; + break; + } + } + + /* + * First flush out the inode that xfs_iflush was called with. + */ + error = xfs_iflush_int(ip, bp); + if (error) { + goto corrupt_out; + } + + /* + * inode clustering: + * see if other inodes can be gathered into this write + */ + +#ifdef DEBUG + ip->i_chash->chl_buf = bp; /* inode clustering debug */ +#endif + + ch = XFS_CHASH(mp, ip->i_blkno); + s = mutex_spinlock(&ch->ch_lock); + + clcount = 0; + for (iq = ip->i_cnext; iq != ip; iq = iq->i_cnext) { + /* + * Do an un-protected check to see if the inode is dirty and + * is a candidate for flushing. These checks will be repeated + * later after the appropriate locks are acquired. + */ + iip = iq->i_itemp; + if ((iq->i_update_core == 0) && + ((iip == NULL) || + !(iip->ili_format.ilf_fields & XFS_ILOG_ALL)) && + xfs_ipincount(iq) == 0) { + continue; + } + + /* + * Try to get locks. If any are unavailable, + * then this inode cannot be flushed and is skipped. + */ + + /* get inode locks (just i_lock) */ + if (xfs_ilock_nowait(iq, XFS_ILOCK_SHARED)) { + /* get inode flush lock */ + if (xfs_iflock_nowait(iq)) { + /* check if pinned */ + if (xfs_ipincount(iq) == 0) { + /* arriving here means that + * this inode can be flushed. + * first re-check that it's + * dirty + */ + iip = iq->i_itemp; + if ((iq->i_update_core != 0)|| + ((iip != NULL) && + (iip->ili_format.ilf_fields & XFS_ILOG_ALL))) { + clcount++; + error = xfs_iflush_int(iq, bp); + if (error) { + xfs_iunlock(iq, + XFS_ILOCK_SHARED); + goto cluster_corrupt_out; + } + } else { + xfs_ifunlock(iq); + } + } else { + xfs_ifunlock(iq); + } + } + xfs_iunlock(iq, XFS_ILOCK_SHARED); + } + } + mutex_spinunlock(&ch->ch_lock, s); + + if (clcount) { + XFS_STATS_INC(xfsstats.xs_icluster_flushcnt); + XFS_STATS_ADD(xfsstats.xs_icluster_flushinode, clcount); + } + + /* + * If the buffer is pinned then push on the log so we won't + * get stuck waiting in the write for too long. + */ + if (XFS_BUF_ISPINNED(bp)){ + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + } + + if (flags & INT_DELWRI) { + xfs_bdwrite(mp, bp); + } else if (flags & INT_ASYNC) { + xfs_bawrite(mp, bp); + } else { + error = xfs_bwrite(mp, bp); + } + return error; + +corrupt_out: + xfs_buf_relse(bp); + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); + xfs_iflush_abort(ip); + /* + * Unlocks the flush lock + */ + return XFS_ERROR(EFSCORRUPTED); + +cluster_corrupt_out: + /* Corruption detected in the clustering loop. Invalidate the + * inode buffer and shut down the filesystem. + */ + mutex_spinunlock(&ch->ch_lock, s); + + /* + * Clean up the buffer. If it was B_DELWRI, just release it -- + * brelse can handle it with no problems. If not, shut down the + * filesystem before releasing the buffer. + */ + if ((bufwasdelwri= XFS_BUF_ISDELAYWRITE(bp))) { + xfs_buf_relse(bp); + } + + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); + + if(!bufwasdelwri) { + /* + * Just like incore_relse: if we have b_iodone functions, + * mark the buffer as an error and call them. Otherwise + * mark it as stale and brelse. + */ + if (XFS_BUF_IODONE_FUNC(bp)) { + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + XFS_BUF_UNDONE(bp); + XFS_BUF_STALE(bp); + XFS_BUF_SHUT(bp); + XFS_BUF_ERROR(bp,EIO); + xfs_biodone(bp); + } else { + XFS_BUF_STALE(bp); + xfs_buf_relse(bp); + } + } + + xfs_iflush_abort(iq); + /* + * Unlocks the flush lock + */ + return XFS_ERROR(EFSCORRUPTED); +} + + +STATIC int +xfs_iflush_int( + xfs_inode_t *ip, + xfs_buf_t *bp) +{ + xfs_inode_log_item_t *iip; + xfs_dinode_t *dip; + xfs_mount_t *mp; +#ifdef XFS_TRANS_DEBUG + int first; +#endif + SPLDECL(s); + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); + ASSERT(valusema(&ip->i_flock) <= 0); + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || + ip->i_d.di_nextents > ip->i_df.if_ext_max); + + iip = ip->i_itemp; + mp = ip->i_mount; + + + /* + * If the inode isn't dirty, then just release the inode + * flush lock and do nothing. + */ + if ((ip->i_update_core == 0) && + ((iip == NULL) || !(iip->ili_format.ilf_fields & XFS_ILOG_ALL))) { + xfs_ifunlock(ip); + return 0; + } + + /* set *dip = inode's place in the buffer */ + dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_boffset); + + /* + * Clear i_update_core before copying out the data. + * This is for coordination with our timestamp updates + * that don't hold the inode lock. They will always + * update the timestamps BEFORE setting i_update_core, + * so if we clear i_update_core after they set it we + * are guaranteed to see their updates to the timestamps. + * I believe that this depends on strongly ordered memory + * semantics, but we have that. We use the SYNCHRONIZE + * macro to make sure that the compiler does not reorder + * the i_update_core access below the data copy below. + */ + ip->i_update_core = 0; + SYNCHRONIZE(); + + if (XFS_TEST_ERROR(INT_GET(dip->di_core.di_magic,ARCH_CONVERT) != XFS_DINODE_MAGIC, + mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad inode %Lu magic number 0x%x, ptr 0x%p", + ip->i_ino, (int) INT_GET(dip->di_core.di_magic, ARCH_CONVERT), dip); + goto corrupt_out; + } + if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC, + mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad inode %Lu, ptr 0x%p, magic number 0x%x", + ip->i_ino, ip, ip->i_d.di_magic); + goto corrupt_out; + } + if ((ip->i_d.di_mode & IFMT) == IFREG) { + if (XFS_TEST_ERROR( + (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && + (ip->i_d.di_format != XFS_DINODE_FMT_BTREE), + mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad regular inode %Lu, ptr 0x%p", + ip->i_ino, ip); + goto corrupt_out; + } + } else if ((ip->i_d.di_mode & IFMT) == IFDIR) { + if (XFS_TEST_ERROR( + (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && + (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && + (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL), + mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad directory inode %Lu, ptr 0x%p", + ip->i_ino, ip); + goto corrupt_out; + } + } + if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents > + ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5, + XFS_RANDOM_IFLUSH_5)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: detected corrupt incore inode %Lu, total extents = %d, nblocks = %Ld, ptr 0x%p", + ip->i_ino, + ip->i_d.di_nextents + ip->i_d.di_anextents, + ip->i_d.di_nblocks, + ip); + goto corrupt_out; + } + if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize, + mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: bad inode %Lu, forkoff 0x%x, ptr 0x%p", + ip->i_ino, ip->i_d.di_forkoff, ip); + goto corrupt_out; + } + /* + * Copy the dirty parts of the inode into the on-disk + * inode. We always copy out the core of the inode, + * because if the inode is dirty at all the core must + * be. + */ + xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), + -1, ARCH_CONVERT); + + /* + * If this is really an old format inode and the superblock version + * has not been updated to support only new format inodes, then + * convert back to the old inode format. If the superblock version + * has been updated, then make the conversion permanent. + */ + ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 || + XFS_SB_VERSION_HASNLINK(&mp->m_sb)); + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + /* + * Convert it back. + */ + ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); + INT_SET(dip->di_core.di_onlink, ARCH_CONVERT, ip->i_d.di_nlink); + } else { + /* + * The superblock version has already been bumped, + * so just make the conversion to the new inode + * format permanent. + */ + ip->i_d.di_version = XFS_DINODE_VERSION_2; + INT_SET(dip->di_core.di_version, ARCH_CONVERT, XFS_DINODE_VERSION_2); + ip->i_d.di_onlink = 0; + INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT); + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + bzero(&(dip->di_core.di_pad[0]), + sizeof(dip->di_core.di_pad)); + ASSERT(ip->i_d.di_projid == 0); + } + } + + if (xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp) == EFSCORRUPTED) { + goto corrupt_out; + } + + if (XFS_IFORK_Q(ip)) { + /* + * The only error from xfs_iflush_fork is on the data fork. + */ + (void) xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp); + } + xfs_inobp_check(mp, bp); + + /* + * We've recorded everything logged in the inode, so we'd + * like to clear the ilf_fields bits so we don't log and + * flush things unnecessarily. However, we can't stop + * logging all this information until the data we've copied + * into the disk buffer is written to disk. If we did we might + * overwrite the copy of the inode in the log with all the + * data after re-logging only part of it, and in the face of + * a crash we wouldn't have all the data we need to recover. + * + * What we do is move the bits to the ili_last_fields field. + * When logging the inode, these bits are moved back to the + * ilf_fields field. In the xfs_iflush_done() routine we + * clear ili_last_fields, since we know that the information + * those bits represent is permanently on disk. As long as + * the flush completes before the inode is logged again, then + * both ilf_fields and ili_last_fields will be cleared. + * + * We can play with the ilf_fields bits here, because the inode + * lock must be held exclusively in order to set bits there + * and the flush lock protects the ili_last_fields bits. + * Set ili_logged so the flush done + * routine can tell whether or not to look in the AIL. + * Also, store the current LSN of the inode so that we can tell + * whether the item has moved in the AIL from xfs_iflush_done(). + * In order to read the lsn we need the AIL lock, because + * it is a 64 bit value that cannot be read atomically. + */ + if (iip != NULL && iip->ili_format.ilf_fields != 0) { + iip->ili_last_fields = iip->ili_format.ilf_fields; + iip->ili_format.ilf_fields = 0; + iip->ili_logged = 1; + + ASSERT(sizeof(xfs_lsn_t) == 8); /* don't lock if it shrinks */ + AIL_LOCK(mp,s); + iip->ili_flush_lsn = iip->ili_item.li_lsn; + AIL_UNLOCK(mp, s); + + /* + * Attach the function xfs_iflush_done to the inode's + * buffer. This will remove the inode from the AIL + * and unlock the inode's flush lock when the inode is + * completely written to disk. + */ + xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*)) + xfs_iflush_done, (xfs_log_item_t *)iip); + + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT(XFS_BUF_IODONE_FUNC(bp) != NULL); + } else { + /* + * We're flushing an inode which is not in the AIL and has + * not been logged but has i_update_core set. For this + * case we can use a B_DELWRI flush and immediately drop + * the inode flush lock because we can avoid the whole + * AIL state thing. It's OK to drop the flush lock now, + * because we've already locked the buffer and to do anything + * you really need both. + */ + if (iip != NULL) { + ASSERT(iip->ili_logged == 0); + ASSERT(iip->ili_last_fields == 0); + ASSERT((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0); + } + xfs_ifunlock(ip); + } + + return 0; + +corrupt_out: + return XFS_ERROR(EFSCORRUPTED); +} + +/* + * Flush all inactive inodes in mp. Return true if no user references + * were found, false otherwise. + */ +int +xfs_iflush_all( + xfs_mount_t *mp, + int flag) +{ + int busy; + int done; + int purged; + xfs_inode_t *ip; + vmap_t vmap; + vnode_t *vp; + + busy = done = 0; + while (!done) { + purged = 0; + XFS_MOUNT_ILOCK(mp); + ip = mp->m_inodes; + if (ip == NULL) { + break; + } + do { + /* Make sure we skip markers inserted by sync */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + /* + * It's up to our caller to purge the root + * and quota vnodes later. + */ + vp = XFS_ITOV_NULL(ip); + + if (!vp) { + XFS_MOUNT_IUNLOCK(mp); + xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); + purged = 1; + break; + } + + if (vn_count(vp) != 0) { + if (vn_count(vp) == 1 && + (ip == mp->m_rootip || + (mp->m_quotainfo && + (ip->i_ino == mp->m_sb.sb_uquotino || + ip->i_ino == mp->m_sb.sb_gquotino)))) { + + ip = ip->i_mnext; + continue; + } + if (!(flag & XFS_FLUSH_ALL)) { + ASSERT(0); + busy = 1; + done = 1; + break; + } + /* + * Ignore busy inodes but continue flushing + * others. + */ + ip = ip->i_mnext; + continue; + } + /* + * Sample vp mapping while holding mp locked on MP + * systems, so we don't purge a reclaimed or + * nonexistent vnode. We break from the loop + * since we know that we modify + * it by pulling ourselves from it in xfs_reclaim() + * called via vn_purge() below. Set ip to the next + * entry in the list anyway so we'll know below + * whether we reached the end or not. + */ + VMAP(vp, ip, vmap); + vp->v_flag |= VPURGE; /* OK for vn_purge */ + XFS_MOUNT_IUNLOCK(mp); + + vn_purge(vp, &vmap); + + purged = 1; + break; + } while (ip != mp->m_inodes); + /* + * We need to distinguish between when we exit the loop + * after a purge and when we simply hit the end of the + * list. We can't use the (ip == mp->m_inodes) test, + * because when we purge an inode at the start of the list + * the next inode on the list becomes mp->m_inodes. That + * would cause such a test to bail out early. The purged + * variable tells us how we got out of the loop. + */ + if (!purged) { + done = 1; + } + } + XFS_MOUNT_IUNLOCK(mp); + return !busy; +} + + +/* + * xfs_iaccess: check accessibility of inode for mode. + */ +int +xfs_iaccess( + xfs_inode_t *ip, + mode_t mode, + cred_t *cr) +{ + int error; + mode_t orgmode = mode; + struct inode *inode = LINVFS_GET_IP(XFS_ITOV(ip)); + + /* + * Verify that the MAC policy allows the requested access. + */ + if ((error = _MAC_XFS_IACCESS(ip, mode, cr))) + return XFS_ERROR(error); + + if (mode & IWRITE) { + umode_t imode = inode->i_mode; + + if (IS_RDONLY(inode) && + (S_ISREG(imode) || S_ISDIR(imode) || S_ISLNK(imode))) + return XFS_ERROR(EROFS); + } + + /* + * If there's an Access Control List it's used instead of + * the mode bits. + */ + if ((error = _ACL_XFS_IACCESS(ip, mode, cr)) != -1) + return error ? XFS_ERROR(error) : 0; + + if (current->fsuid != ip->i_d.di_uid) { + mode >>= 3; + if (!in_group_p((gid_t)ip->i_d.di_gid)) + mode >>= 3; + } + + /* + * If the DACs are ok we don't need any capability check. + */ + if ((ip->i_d.di_mode & mode) == mode) + return 0; + /* + * Read/write DACs are always overridable. + * Executable DACs are overridable if at least one exec bit is set. + */ + if ((orgmode & (IREAD|IWRITE)) || (inode->i_mode & S_IXUGO)) + if (capable_cred(cr, CAP_DAC_OVERRIDE)) + return 0; + + if ((orgmode == IREAD) || + (((ip->i_d.di_mode & IFMT) == IFDIR) && + (!(orgmode & ~(IWRITE|IEXEC))))) { + if (capable_cred(cr, CAP_DAC_READ_SEARCH)) + return 0; +#ifdef NOISE + cmn_err(CE_NOTE, "Ick: mode=%o, orgmode=%o", mode, orgmode); +#endif /* NOISE */ + return XFS_ERROR(EACCES); + } + return XFS_ERROR(EACCES); +} + +/* + * Return whether or not it is OK to swap to the given file in the + * given range. Return 0 for OK and otherwise return the error. + * + * It is only OK to swap to a file if it has no holes, and all + * extents have been initialized. + * + * We use the vnode behavior chain prevent and allow primitives + * to ensure that the vnode chain stays coherent while we do this. + * This allows us to walk the chain down to the bottom where XFS + * lives without worrying about it changing out from under us. + */ +int +xfs_swappable( + bhv_desc_t *bdp) +{ + xfs_inode_t *ip; + + ip = XFS_BHVTOI(bdp); + /* + * Verify that the file does not have any + * holes or unwritten exents. + */ + return xfs_bmap_check_swappable(ip); +} + +/* + * xfs_iroundup: round up argument to next power of two + */ +uint +xfs_iroundup( + uint v) +{ + int i; + uint m; + + if ((v & (v - 1)) == 0) + return v; + ASSERT((v & 0x80000000) == 0); + if ((v & (v + 1)) == 0) + return v + 1; + for (i = 0, m = 1; i < 31; i++, m <<= 1) { + if (v & m) + continue; + v |= m; + if ((v & (v + 1)) == 0) + return v + 1; + } + ASSERT(0); + return( 0 ); +} + +/* + * Change the requested timestamp in the given inode. + * We don't lock across timestamp updates, and we don't log them but + * we do record the fact that there is dirty information in core. + * + * NOTE -- callers MUST combine XFS_ICHGTIME_MOD or XFS_ICHGTIME_CHG + * with XFS_ICHGTIME_ACC to be sure that access time + * update will take. Calling first with XFS_ICHGTIME_ACC + * and then XFS_ICHGTIME_MOD may fail to modify the access + * timestamp if the filesystem is mounted noacctm. + */ +void +xfs_ichgtime(xfs_inode_t *ip, + int flags) +{ + timespec_t tv; + vnode_t *vp = XFS_ITOV(ip); + struct inode *inode = LINVFS_GET_IP(vp); + + /* + * We're not supposed to change timestamps in readonly-mounted + * filesystems. Throw it away if anyone asks us. + */ + if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + return; + + /* + * Don't update access timestamps on reads if mounted "noatime" + * Throw it away if anyone asks us. + */ + if (ip->i_mount->m_flags & XFS_MOUNT_NOATIME && + ((flags & (XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD|XFS_ICHGTIME_CHG)) + == XFS_ICHGTIME_ACC)) + return; + + nanotime(&tv); + if (flags & XFS_ICHGTIME_MOD) { + inode->i_mtime = ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; + } + if (flags & XFS_ICHGTIME_ACC) { + inode->i_atime = ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec; + } + if (flags & XFS_ICHGTIME_CHG) { + inode->i_ctime = ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec; + } + + /* + * We update the i_update_core field _after_ changing + * the timestamps in order to coordinate properly with + * xfs_iflush() so that we don't lose timestamp updates. + * This keeps us from having to hold the inode lock + * while doing this. We use the SYNCHRONIZE macro to + * ensure that the compiler does not reorder the update + * of i_update_core above the timestamp updates above. + */ + SYNCHRONIZE(); + ip->i_update_core = 1; +} + +/* + * xfs_ibusy_check -- Checks whether inode reference count allows unmount + * + * The value returned is one if the reference count would prevent an unmount. + */ +int +xfs_ibusy_check( + xfs_inode_t *ip, + int refs) +{ + xfs_mount_t *mp = ip->i_mount; + + if ((refs == 1) && (ip == mp->m_rootip)) + return (0); + if ((refs == 1) && (ip == mp->m_rbmip)) + return (0); + if ((refs == 1) && (ip == mp->m_rsumip)) + return (0); + if (mp->m_quotainfo && ip->i_ino == mp->m_sb.sb_uquotino) + return (0); + if (mp->m_quotainfo && ip->i_ino == mp->m_sb.sb_gquotino) + return (0); + return (1); +} + +#ifdef XFS_ILOCK_TRACE +void +xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, inst_t *ra) +{ + ktrace_enter(ip->i_lock_trace, + (void *)ip, + (void *)(__psint_t)lock, /* 1 = LOCK, 3=UNLOCK, etc */ + (void *)(__psint_t)lockflags, /* XFS_ILOCK_EXCL etc */ + (void *)ra, /* caller of ilock */ + (void *)(__psint_t)cpuid(), + (void *)(__psint_t)current_pid(), + 0,0,0,0,0,0,0,0,0,0); + +} +#endif /* ILOCK_TRACE */ diff -Nur linux-2.4.19/fs/xfs/xfs_inode.h linux-2.4.19-sgi211r3/fs/xfs/xfs_inode.h --- linux-2.4.19/fs/xfs/xfs_inode.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_inode.h Tue Jan 14 09:26:24 2003 @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INODE_H__ +#define __XFS_INODE_H__ + +/* + * File incore extent information, present for each of data & attr forks. + */ +#define XFS_INLINE_EXTS 2 +#define XFS_INLINE_DATA 32 +typedef struct xfs_ifork { + int if_bytes; /* bytes in if_u1 */ + int if_real_bytes; /* bytes allocated in if_u1 */ + xfs_bmbt_block_t *if_broot; /* file's incore btree root */ + short if_broot_bytes; /* bytes allocated for root */ + unsigned char if_flags; /* per-fork flags */ + unsigned char if_ext_max; /* max # of extent records */ + xfs_extnum_t if_lastex; /* last if_extents used */ + union { + xfs_bmbt_rec_t *if_extents; /* linear map file exts */ + char *if_data; /* inline file data */ + } if_u1; + union { + xfs_bmbt_rec_t if_inline_ext[XFS_INLINE_EXTS]; + /* very small file extents */ + char if_inline_data[XFS_INLINE_DATA]; + /* very small file data */ + xfs_dev_t if_rdev; /* dev number if special */ + uuid_t if_uuid; /* mount point value */ + } if_u2; +} xfs_ifork_t; + +/* + * Flags for xfs_ichgtime(). + */ +#define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ +#define XFS_ICHGTIME_ACC 0x2 /* data fork access timestamp */ +#define XFS_ICHGTIME_CHG 0x4 /* inode field change timestamp */ + +/* + * Per-fork incore inode flags. + */ +#define XFS_IFINLINE 0x0001 /* Inline data is read in */ +#define XFS_IFEXTENTS 0x0002 /* All extent pointers are read in */ +#define XFS_IFBROOT 0x0004 /* i_broot points to the bmap b-tree root */ + +/* + * Flags for xfs_imap() and xfs_dilocate(). + */ +#define XFS_IMAP_LOOKUP 0x1 + +/* + * Maximum number of extent pointers in if_u1.if_extents. + */ +#define XFS_MAX_INCORE_EXTENTS 32768 + + +#ifdef __KERNEL__ +struct bhv_desc; +struct cred; +struct ktrace; +struct vnode; +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_bmbt_irec; +struct xfs_bmbt_block; +struct xfs_inode; +struct xfs_inode_log_item; +struct xfs_mount; +struct xfs_trans; +struct xfs_dquot; +struct pm; + + +/* + * This structure is used to communicate which extents of a file + * were holes when a write started from xfs_write_file() to + * xfs_strat_read(). This is necessary so that we can know which + * blocks need to be zeroed when they are read in in xfs_strat_read() + * if they weren\'t allocated when the buffer given to xfs_strat_read() + * was mapped. + * + * We keep a list of these attached to the inode. The list is + * protected by the inode lock and the fact that the io lock is + * held exclusively by writers. + */ +typedef struct xfs_gap { + struct xfs_gap *xg_next; + xfs_fileoff_t xg_offset_fsb; + xfs_extlen_t xg_count_fsb; +} xfs_gap_t; + +/* + * This structure is used to hold common pieces of the buffer + * and file for xfs_dio_write and xfs_dio_read. + */ +typedef struct xfs_dio { + struct xfs_buf *xd_bp; + bhv_desc_t *xd_bdp; + struct xfs_inode *xd_ip; + struct xfs_iocore *xd_io; + struct cred *xd_cr; + struct pm *xd_pmp; + int xd_blkalgn; + int xd_ioflag; + xfs_off_t xd_start; + size_t xd_length; +} xfs_dio_t; + +typedef struct dm_attrs_s { + __uint32_t da_dmevmask; /* DMIG event mask */ + __uint16_t da_dmstate; /* DMIG state info */ + __uint16_t da_pad; /* DMIG extra padding */ +} dm_attrs_t; + +typedef struct xfs_iocore { + void *io_obj; /* pointer to container + * inode or dcxvn structure */ + struct xfs_mount *io_mount; /* fs mount struct ptr */ +#ifdef DEBUG + mrlock_t *io_lock; /* inode IO lock */ + mrlock_t *io_iolock; /* inode IO lock */ +#endif + + /* I/O state */ + xfs_fsize_t io_new_size; /* sz when write completes */ + + /* Miscellaneous state. */ + unsigned int io_flags; /* IO related flags */ + + /* DMAPI state */ + dm_attrs_t io_dmattrs; + +} xfs_iocore_t; + +#define io_dmevmask io_dmattrs.da_dmevmask +#define io_dmstate io_dmattrs.da_dmstate + +#define XFS_IO_INODE(io) ((xfs_inode_t *) ((io)->io_obj)) +#define XFS_IO_DCXVN(io) ((dcxvn_t *) ((io)->io_obj)) + +/* + * Flags in the flags field + */ + +#define XFS_IOCORE_ISXFS 0x01 +#define XFS_IOCORE_ISCXFS 0x02 +#define XFS_IOCORE_RT 0x04 + +#define IO_IS_XFS(io) ((io)->io_flags & XFS_IOCORE_ISXFS) + +/* + * xfs_iocore prototypes + */ + +extern void xfs_iocore_inode_init(struct xfs_inode *); +extern void xfs_iocore_inode_reinit(struct xfs_inode *); + + +/* + * This is the type used in the xfs inode hash table. + * An array of these is allocated for each mounted + * file system to hash the inodes for that file system. + */ +typedef struct xfs_ihash { + struct xfs_inode *ih_next; + rwlock_t ih_lock; + uint ih_version; +} xfs_ihash_t; + +/* + * Inode hashing and hash bucket locking. + */ +#define XFS_BUCKETS(mp) (37*(mp)->m_sb.sb_agcount-1) +#define XFS_IHASH(mp,ino) ((mp)->m_ihash + (((uint)ino) % (mp)->m_ihsize)) + +/* + * This is the xfs inode cluster hash. This hash is used by xfs_iflush to + * find inodes that share a cluster and can be flushed to disk at the same + * time. + */ + +typedef struct xfs_chashlist { + struct xfs_chashlist *chl_next; + struct xfs_inode *chl_ip; + xfs_daddr_t chl_blkno; /* starting block number of + * the cluster */ +#ifdef DEBUG + struct xfs_buf *chl_buf; /* debug: the inode buffer */ +#endif +} xfs_chashlist_t; + +typedef struct xfs_chash { + xfs_chashlist_t *ch_list; + lock_t ch_lock; +} xfs_chash_t; + + +/* + * This is the xfs in-core inode structure. + * Most of the on-disk inode is embedded in the i_d field. + * + * The extent pointers/inline file space, however, are managed + * separately. The memory for this information is pointed to by + * the if_u1 unions depending on the type of the data. + * This is used to linearize the array of extents for fast in-core + * access. This is used until the file's number of extents + * surpasses XFS_MAX_INCORE_EXTENTS, at which point all extent pointers + * are accessed through the buffer cache. + * + * Other state kept in the in-core inode is used for identification, + * locking, transactional updating, etc of the inode. + * + * Generally, we do not want to hold the i_rlock while holding the + * i_ilock. Hierarchy is i_iolock followed by i_rlock. + * + * xfs_iptr_t contains all the inode fields upto and including the + * i_mnext and i_mprev fields, it is used as a marker in the inode + * chain off the mount structure by xfs_sync calls. + */ + +typedef struct { + struct xfs_ihash *ip_hash; /* pointer to hash header */ + struct xfs_inode *ip_next; /* inode hash link forw */ + struct xfs_inode *ip_mnext; /* next inode in mount list */ + struct xfs_inode *ip_mprev; /* ptr to prev inode */ + struct xfs_inode **ip_prevp; /* ptr to prev i_next */ + struct xfs_mount *ip_mount; /* fs mount struct ptr */ +} xfs_iptr_t; + +typedef struct xfs_inode { + /* Inode linking and identification information. */ + struct xfs_ihash *i_hash; /* pointer to hash header */ + struct xfs_inode *i_next; /* inode hash link forw */ + struct xfs_inode *i_mnext; /* next inode in mount list */ + struct xfs_inode *i_mprev; /* ptr to prev inode */ + struct xfs_inode **i_prevp; /* ptr to prev i_next */ + struct xfs_mount *i_mount; /* fs mount struct ptr */ + struct bhv_desc i_bhv_desc; /* inode behavior descriptor*/ + struct xfs_dquot *i_udquot; /* user dquot */ + struct xfs_dquot *i_gdquot; /* group dquot */ + + /* Inode location stuff */ + xfs_ino_t i_ino; /* inode number (agno/agino)*/ + xfs_daddr_t i_blkno; /* blkno of inode buffer */ + ushort i_len; /* len of inode buffer */ + ushort i_boffset; /* off of inode in buffer */ + + /* Extent information. */ + xfs_ifork_t *i_afp; /* attribute fork pointer */ + xfs_ifork_t i_df; /* data fork */ + + /* Transaction and locking information. */ + struct xfs_trans *i_transp; /* ptr to owning transaction*/ + struct xfs_inode_log_item *i_itemp; /* logging information */ + mrlock_t i_lock; /* inode lock */ + mrlock_t i_iolock; /* inode IO lock */ + sema_t i_flock; /* inode flush lock */ + atomic_t i_pincount; /* inode pin count */ + wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */ + struct xfs_inode **i_refcache; /* ptr to entry in ref cache */ + struct xfs_inode *i_release; /* inode to unref */ + + /* I/O state */ + xfs_iocore_t i_iocore; /* I/O core */ + + /* Miscellaneous state. */ + unsigned short i_flags; /* see defined flags below */ + unsigned char i_update_core; /* timestamps/size is dirty */ + unsigned char i_update_size; /* di_size field is dirty */ + unsigned int i_gen; /* generation count */ + unsigned int i_delayed_blks; /* count of delay alloc blks */ + + xfs_dinode_core_t i_d; /* most of ondisk inode */ + xfs_chashlist_t *i_chash; /* cluster hash list header */ + struct xfs_inode *i_cnext; /* cluster hash link forward */ + struct xfs_inode *i_cprev; /* cluster hash link backward */ + +#ifdef DEBUG + /* Trace buffers per inode. */ + struct ktrace *i_xtrace; /* inode extent list trace */ + struct ktrace *i_btrace; /* inode bmap btree trace */ + struct ktrace *i_rwtrace; /* inode read/write trace */ + struct ktrace *i_strat_trace; /* inode strat_write trace */ + struct ktrace *i_lock_trace; /* inode lock/unlock trace */ + struct ktrace *i_dir_trace; /* inode directory trace */ +#endif /* DEBUG */ +} xfs_inode_t; + +#endif /* __KERNEL__ */ + + +/* + * Fork handling. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_PTR) +xfs_ifork_t *xfs_ifork_ptr(xfs_inode_t *ip, int w); +#define XFS_IFORK_PTR(ip,w) xfs_ifork_ptr(ip,w) +#else +#define XFS_IFORK_PTR(ip,w) ((w) == XFS_DATA_FORK ? &(ip)->i_df : (ip)->i_afp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_Q) +int xfs_ifork_q(xfs_inode_t *ip); +#define XFS_IFORK_Q(ip) xfs_ifork_q(ip) +#else +#define XFS_IFORK_Q(ip) XFS_CFORK_Q(&(ip)->i_d) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_DSIZE) +int xfs_ifork_dsize(xfs_inode_t *ip); +#define XFS_IFORK_DSIZE(ip) xfs_ifork_dsize(ip) +#else +#define XFS_IFORK_DSIZE(ip) XFS_CFORK_DSIZE(&ip->i_d, ip->i_mount) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_ASIZE) +int xfs_ifork_asize(xfs_inode_t *ip); +#define XFS_IFORK_ASIZE(ip) xfs_ifork_asize(ip) +#else +#define XFS_IFORK_ASIZE(ip) XFS_CFORK_ASIZE(&ip->i_d, ip->i_mount) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_SIZE) +int xfs_ifork_size(xfs_inode_t *ip, int w); +#define XFS_IFORK_SIZE(ip,w) xfs_ifork_size(ip,w) +#else +#define XFS_IFORK_SIZE(ip,w) XFS_CFORK_SIZE(&ip->i_d, ip->i_mount, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_FORMAT) +int xfs_ifork_format(xfs_inode_t *ip, int w); +#define XFS_IFORK_FORMAT(ip,w) xfs_ifork_format(ip,w) +#else +#define XFS_IFORK_FORMAT(ip,w) XFS_CFORK_FORMAT(&ip->i_d, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_FMT_SET) +void xfs_ifork_fmt_set(xfs_inode_t *ip, int w, int n); +#define XFS_IFORK_FMT_SET(ip,w,n) xfs_ifork_fmt_set(ip,w,n) +#else +#define XFS_IFORK_FMT_SET(ip,w,n) XFS_CFORK_FMT_SET(&ip->i_d, w, n) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_NEXTENTS) +int xfs_ifork_nextents(xfs_inode_t *ip, int w); +#define XFS_IFORK_NEXTENTS(ip,w) xfs_ifork_nextents(ip,w) +#else +#define XFS_IFORK_NEXTENTS(ip,w) XFS_CFORK_NEXTENTS(&ip->i_d, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_NEXT_SET) +void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n); +#define XFS_IFORK_NEXT_SET(ip,w,n) xfs_ifork_next_set(ip,w,n) +#else +#define XFS_IFORK_NEXT_SET(ip,w,n) XFS_CFORK_NEXT_SET(&ip->i_d, w, n) +#endif + + +#ifdef __KERNEL__ + +/* + * In-core inode flags. + */ +#define XFS_IGRIO 0x0001 /* inode used for guaranteed rate i/o */ +#define XFS_IUIOSZ 0x0002 /* inode i/o sizes have been explicitly set */ +#define XFS_IQUIESCE 0x0004 /* we have started quiescing for this inode */ +#define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */ + +/* + * Flags for inode locking. + */ +#define XFS_IOLOCK_EXCL 0x001 +#define XFS_IOLOCK_SHARED 0x002 +#define XFS_ILOCK_EXCL 0x004 +#define XFS_ILOCK_SHARED 0x008 +#define XFS_IUNLOCK_NONOTIFY 0x010 +#define XFS_EXTENT_TOKEN_RD 0x040 +#define XFS_SIZE_TOKEN_RD 0x080 +#define XFS_EXTSIZE_RD (XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD) +#define XFS_WILLLEND 0x100 /* Always acquire tokens for lending */ +#define XFS_EXTENT_TOKEN_WR (XFS_EXTENT_TOKEN_RD | XFS_WILLLEND) +#define XFS_SIZE_TOKEN_WR (XFS_SIZE_TOKEN_RD | XFS_WILLLEND) +#define XFS_EXTSIZE_WR (XFS_EXTSIZE_RD | XFS_WILLLEND) + + +#define XFS_LOCK_MASK \ + (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL | \ + XFS_ILOCK_SHARED | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD | \ + XFS_WILLLEND) + +/* + * Flags for xfs_iflush() + */ +#define XFS_IFLUSH_DELWRI_ELSE_SYNC 1 +#define XFS_IFLUSH_DELWRI_ELSE_ASYNC 2 +#define XFS_IFLUSH_SYNC 3 +#define XFS_IFLUSH_ASYNC 4 +#define XFS_IFLUSH_DELWRI 5 + +/* + * Flags for xfs_iflush_all. + */ +#define XFS_FLUSH_ALL 0x1 + +/* + * Flags for xfs_itruncate_start(). + */ +#define XFS_ITRUNC_DEFINITE 0x1 +#define XFS_ITRUNC_MAYBE 0x2 + +/* + * max file offset is 2^(31+PAGE_SHIFT) - 1 (due to linux page cache) + * + * NOTE: XFS itself can handle 2^63 - 1 (largest positive value of xfs_fsize_t) + * but Linux can't go above 2^(31+PAGE_SHIFT)-1: the Linux VM uses a 32 bit + * signed variable to index cache data, so 2^31 * PAGE_SIZE is as big as + * you can go. + */ +#define XFS_MAX_FILE_OFFSET ((long long)((1ULL<<(31+PAGE_SHIFT))-1ULL)) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ITOV) +struct vnode *xfs_itov(xfs_inode_t *ip); +#define XFS_ITOV(ip) xfs_itov(ip) +#else +#define XFS_ITOV(ip) BHV_TO_VNODE(XFS_ITOBHV(ip)) +#endif +#define XFS_ITOV_NULL(ip) BHV_TO_VNODE_NULL(XFS_ITOBHV(ip)) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ITOBHV) +struct bhv_desc *xfs_itobhv(xfs_inode_t *ip); +#define XFS_ITOBHV(ip) xfs_itobhv(ip) +#else +#define XFS_ITOBHV(ip) ((struct bhv_desc *)(&((ip)->i_bhv_desc))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BHVTOI) +xfs_inode_t *xfs_bhvtoi(struct bhv_desc *bhvp); +#define XFS_BHVTOI(bhvp) xfs_bhvtoi(bhvp) +#else +#define XFS_BHVTOI(bhvp) \ + ((xfs_inode_t *)((char *)(bhvp) - \ + (char *)&(((xfs_inode_t *)0)->i_bhv_desc))) +#endif + +#define BHV_IS_XFS(bdp) (BHV_OPS(bdp) == &xfs_vnodeops) + +/* + * Pick the inode cluster hash bucket + * (m_chash is the same size as m_ihash) + */ +#define XFS_CHASH(mp,blk) ((mp)->m_chash + (((uint)blk) % (mp)->m_chsize)) + +/* + * For multiple groups support: if ISGID bit is set in the parent + * directory, group of new file is set to that of the parent, and + * new subdirectory gets ISGID bit from parent. + */ +#define XFS_INHERIT_GID(pip, vfsp) ((pip) != NULL && \ + (((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & ISGID))) + +/* + * xfs_iget.c prototypes. + */ +void xfs_ihash_init(struct xfs_mount *); +void xfs_ihash_free(struct xfs_mount *); +void xfs_chash_init(struct xfs_mount *); +void xfs_chash_free(struct xfs_mount *); +xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, + struct xfs_trans *); +void xfs_inode_lock_init(xfs_inode_t *, struct vnode *); +int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + uint, xfs_inode_t **, xfs_daddr_t); +int xfs_vn_iget(vfs_t *, struct vnode *, xfs_ino_t); +void xfs_iput(xfs_inode_t *, uint); +void xfs_iput_new(xfs_inode_t *, uint); +void xfs_ilock(xfs_inode_t *, uint); +int xfs_ilock_nowait(xfs_inode_t *, uint); +void xfs_iunlock(xfs_inode_t *, uint); +void xfs_ilock_demote(xfs_inode_t *, uint); +void xfs_iflock(xfs_inode_t *); +int xfs_iflock_nowait(xfs_inode_t *); +uint xfs_ilock_map_shared(xfs_inode_t *); +void xfs_iunlock_map_shared(xfs_inode_t *, uint); +void xfs_ifunlock(xfs_inode_t *); +void xfs_ireclaim(xfs_inode_t *); +int xfs_finish_reclaim(xfs_inode_t *, int, int); +int xfs_finish_reclaim_all(struct xfs_mount *); + +/* + * xfs_inode.c prototypes. + */ +int xfs_inotobp(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_dinode_t **, struct xfs_buf **, int *); +int xfs_itobp(struct xfs_mount *, struct xfs_trans *, + xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, + xfs_daddr_t); +int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_inode_t **, xfs_daddr_t); +int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int); +int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, nlink_t, + dev_t, struct cred *, xfs_prid_t, int, + struct xfs_buf **, boolean_t *, xfs_inode_t **); +void xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, int, + xfs_arch_t); +int xfs_ifree(struct xfs_trans *, xfs_inode_t *); +int xfs_atruncate_start(xfs_inode_t *); +void xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t); +int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, + xfs_fsize_t, int, int); +int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); +int xfs_igrow_start(xfs_inode_t *, xfs_fsize_t, struct cred *); +void xfs_igrow_finish(struct xfs_trans *, xfs_inode_t *, + xfs_fsize_t, int); + +void xfs_idestroy_fork(xfs_inode_t *, int); +void xfs_idestroy(xfs_inode_t *); +void xfs_idata_realloc(xfs_inode_t *, int, int); +void xfs_iextract(xfs_inode_t *); +void xfs_iext_realloc(xfs_inode_t *, int, int); +void xfs_iroot_realloc(xfs_inode_t *, int, int); +void xfs_ipin(xfs_inode_t *); +void xfs_iunpin(xfs_inode_t *); +int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_32_t *, int); +int xfs_iflush(xfs_inode_t *, uint); +int xfs_iflush_all(struct xfs_mount *, int); +int xfs_ibusy_check(xfs_inode_t *, int); +int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *); +uint xfs_iroundup(uint); +void xfs_ichgtime(xfs_inode_t *, int); +xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); +void xfs_lock_inodes(xfs_inode_t **, int, int, uint); + +#define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount)) + + + +#ifdef DEBUG +void xfs_isize_check(struct xfs_mount *, xfs_inode_t *, xfs_fsize_t); +#else /* DEBUG */ +#define xfs_isize_check(mp, ip, isize) +#endif /* DEBUG */ + +#if defined(DEBUG) +void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); +#else +#define xfs_inobp_check(mp, bp) +#endif /* DEBUG */ + +extern struct kmem_zone *xfs_chashlist_zone; +extern struct kmem_zone *xfs_ifork_zone; +extern struct kmem_zone *xfs_inode_zone; +extern struct kmem_zone *xfs_ili_zone; +extern struct vnodeops xfs_vnodeops; + +#ifdef XFS_ILOCK_TRACE +#define XFS_ILOCK_KTRACE_SIZE 32 +void xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, + inst_t *ra); +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_INODE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_inode_item.c linux-2.4.19-sgi211r3/fs/xfs/xfs_inode_item.c --- linux-2.4.19/fs/xfs/xfs_inode_item.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_inode_item.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains the implementation of the xfs_inode_log_item. + * It contains the item operations used to manipulate the inode log + * items as well as utility routines used by the inode specific + * transaction routines. + */ +#include + + +kmem_zone_t *xfs_ili_zone; /* inode log item zone */ + +/* + * This returns the number of iovecs needed to log the given inode item. + * + * We need one iovec for the inode log format structure, one for the + * inode core, and possibly one for the inode data/extents/b-tree root + * and one for the inode attribute data/extents/b-tree root. + */ +STATIC uint +xfs_inode_item_size( + xfs_inode_log_item_t *iip) +{ + uint nvecs; + xfs_inode_t *ip; + + ip = iip->ili_inode; + nvecs = 2; + + /* + * Only log the data/extents/b-tree root if there is something + * left to log. + */ + iip->ili_format.ilf_fields |= XFS_ILOG_CORE; + + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEV | XFS_ILOG_UUID); + if ((iip->ili_format.ilf_fields & XFS_ILOG_DEXT) && + (ip->i_d.di_nextents > 0) && + (ip->i_df.if_bytes > 0)) { + ASSERT(ip->i_df.if_u1.if_extents != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_DEXT; + } + break; + + case XFS_DINODE_FMT_BTREE: + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT | + XFS_ILOG_DEV | XFS_ILOG_UUID); + if ((iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) && + (ip->i_df.if_broot_bytes > 0)) { + ASSERT(ip->i_df.if_broot != NULL); + nvecs++; + } else { + ASSERT(!(iip->ili_format.ilf_fields & + XFS_ILOG_DBROOT)); +#ifdef XFS_TRANS_DEBUG + if (iip->ili_root_size > 0) { + ASSERT(iip->ili_root_size == + ip->i_df.if_broot_bytes); + ASSERT(bcmp(iip->ili_orig_root, + ip->i_df.if_broot, + iip->ili_root_size) == 0); + } else { + ASSERT(ip->i_df.if_broot_bytes == 0); + } +#endif + iip->ili_format.ilf_fields &= ~XFS_ILOG_DBROOT; + } + break; + + case XFS_DINODE_FMT_LOCAL: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT | + XFS_ILOG_DEV | XFS_ILOG_UUID); + if ((iip->ili_format.ilf_fields & XFS_ILOG_DDATA) && + (ip->i_df.if_bytes > 0)) { + ASSERT(ip->i_df.if_u1.if_data != NULL); + ASSERT(ip->i_d.di_size > 0); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_DDATA; + } + break; + + case XFS_DINODE_FMT_DEV: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEXT | XFS_ILOG_UUID); + break; + + case XFS_DINODE_FMT_UUID: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEXT | XFS_ILOG_DEV); + break; + + default: + ASSERT(0); + break; + } + + /* + * If there are no attributes associated with this file, + * then there cannot be anything more to log. + * Clear all attribute-related log flags. + */ + if (!XFS_IFORK_Q(ip)) { + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT); + return nvecs; + } + + /* + * Log any necessary attribute data. + */ + switch (ip->i_d.di_aformat) { + case XFS_DINODE_FMT_EXTENTS: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT); + if ((iip->ili_format.ilf_fields & XFS_ILOG_AEXT) && + (ip->i_d.di_anextents > 0) && + (ip->i_afp->if_bytes > 0)) { + ASSERT(ip->i_afp->if_u1.if_extents != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_AEXT; + } + break; + + case XFS_DINODE_FMT_BTREE: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_ADATA | XFS_ILOG_AEXT); + if ((iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) && + (ip->i_afp->if_broot_bytes > 0)) { + ASSERT(ip->i_afp->if_broot != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_ABROOT; + } + break; + + case XFS_DINODE_FMT_LOCAL: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT); + if ((iip->ili_format.ilf_fields & XFS_ILOG_ADATA) && + (ip->i_afp->if_bytes > 0)) { + ASSERT(ip->i_afp->if_u1.if_data != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_ADATA; + } + break; + + default: + ASSERT(0); + break; + } + + return nvecs; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given inode log item. It fills the first item with an inode + * log format structure, the second with the on-disk inode structure, + * and a possible third and/or fourth with the inode data/extents/b-tree + * root and inode attributes data/extents/b-tree root. + */ +STATIC void +xfs_inode_item_format( + xfs_inode_log_item_t *iip, + xfs_log_iovec_t *log_vector) +{ + uint nvecs; + xfs_log_iovec_t *vecp; + xfs_inode_t *ip; + size_t data_bytes; + xfs_bmbt_rec_32_t *ext_buffer; + int nrecs; + xfs_mount_t *mp; + + ip = iip->ili_inode; + vecp = log_vector; + + vecp->i_addr = (xfs_caddr_t)&iip->ili_format; + vecp->i_len = sizeof(xfs_inode_log_format_t); + vecp++; + nvecs = 1; + + /* + * Clear i_update_core if the timestamps (or any other + * non-transactional modification) need flushing/logging + * and we're about to log them with the rest of the core. + * + * This is the same logic as xfs_iflush() but this code can't + * run at the same time as xfs_iflush because we're in commit + * processing here and so we have the inode lock held in + * exclusive mode. Although it doesn't really matter + * for the timestamps if both routines were to grab the + * timestamps or not. That would be ok. + * + * We clear i_update_core before copying out the data. + * This is for coordination with our timestamp updates + * that don't hold the inode lock. They will always + * update the timestamps BEFORE setting i_update_core, + * so if we clear i_update_core after they set it we + * are guaranteed to see their updates to the timestamps + * either here. Likewise, if they set it after we clear it + * here, we'll see it either on the next commit of this + * inode or the next time the inode gets flushed via + * xfs_iflush(). This depends on strongly ordered memory + * semantics, but we have that. We use the SYNCHRONIZE + * macro to make sure that the compiler does not reorder + * the i_update_core access below the data copy below. + */ + if (ip->i_update_core) { + ip->i_update_core = 0; + SYNCHRONIZE(); + } + + /* + * We don't have to worry about re-ordering here because + * the update_size field is protected by the inode lock + * and we have that held in exclusive mode. + */ + if (ip->i_update_size) + ip->i_update_size = 0; + + vecp->i_addr = (xfs_caddr_t)&ip->i_d; + vecp->i_len = sizeof(xfs_dinode_core_t); + vecp++; + nvecs++; + iip->ili_format.ilf_fields |= XFS_ILOG_CORE; + + /* + * If this is really an old format inode, then we need to + * log it as such. This means that we have to copy the link + * count from the new field to the old. We don't have to worry + * about the new fields, because nothing trusts them as long as + * the old inode version number is there. If the superblock already + * has a new version number, then we don't bother converting back. + */ + mp = ip->i_mount; + ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 || + XFS_SB_VERSION_HASNLINK(&mp->m_sb)); + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + /* + * Convert it back. + */ + ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); + ip->i_d.di_onlink = ip->i_d.di_nlink; + } else { + /* + * The superblock version has already been bumped, + * so just make the conversion to the new inode + * format permanent. + */ + ip->i_d.di_version = XFS_DINODE_VERSION_2; + ip->i_d.di_onlink = 0; + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + } + } + + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEV | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DEXT) { + ASSERT(ip->i_df.if_bytes > 0); + ASSERT(ip->i_df.if_u1.if_extents != NULL); + ASSERT(ip->i_d.di_nextents > 0); + ASSERT(iip->ili_extents_buf == NULL); + nrecs = ip->i_df.if_bytes / + (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(nrecs > 0); + if (nrecs == ip->i_d.di_nextents) { + /* + * There are no delayed allocation + * extents, so just point to the + * real extents array. + */ + vecp->i_addr = + (char *)(ip->i_df.if_u1.if_extents); + vecp->i_len = ip->i_df.if_bytes; + } else { + /* + * There are delayed allocation extents + * in the inode. Use xfs_iextents_copy() + * to copy only the real extents into + * a separate buffer. We'll free the + * buffer in the unlock routine. + */ + ext_buffer = kmem_alloc(ip->i_df.if_bytes, + KM_SLEEP); + iip->ili_extents_buf = ext_buffer; + vecp->i_addr = (xfs_caddr_t)ext_buffer; + vecp->i_len = xfs_iextents_copy(ip, ext_buffer, + XFS_DATA_FORK); + } + ASSERT(vecp->i_len <= ip->i_df.if_bytes); + iip->ili_format.ilf_dsize = vecp->i_len; + vecp++; + nvecs++; + } + break; + + case XFS_DINODE_FMT_BTREE: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DDATA | XFS_ILOG_DEXT | + XFS_ILOG_DEV | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) { + ASSERT(ip->i_df.if_broot_bytes > 0); + ASSERT(ip->i_df.if_broot != NULL); + vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot; + vecp->i_len = ip->i_df.if_broot_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes; + } + break; + + case XFS_DINODE_FMT_LOCAL: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DBROOT | XFS_ILOG_DEXT | + XFS_ILOG_DEV | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DDATA) { + ASSERT(ip->i_df.if_bytes > 0); + ASSERT(ip->i_df.if_u1.if_data != NULL); + ASSERT(ip->i_d.di_size > 0); + + vecp->i_addr = (xfs_caddr_t)ip->i_df.if_u1.if_data; + /* + * Round i_bytes up to a word boundary. + * The underlying memory is guaranteed to + * to be there by xfs_idata_realloc(). + */ + data_bytes = roundup(ip->i_df.if_bytes, 4); + ASSERT((ip->i_df.if_real_bytes == 0) || + (ip->i_df.if_real_bytes == data_bytes)); + vecp->i_len = (int)data_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_dsize = (unsigned)data_bytes; + } + break; + + case XFS_DINODE_FMT_DEV: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DBROOT | XFS_ILOG_DEXT | + XFS_ILOG_DDATA | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) { + iip->ili_format.ilf_u.ilfu_rdev = + ip->i_df.if_u2.if_rdev; + } + break; + + case XFS_DINODE_FMT_UUID: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DBROOT | XFS_ILOG_DEXT | + XFS_ILOG_DDATA | XFS_ILOG_DEV))); + if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) { + iip->ili_format.ilf_u.ilfu_uuid = + ip->i_df.if_u2.if_uuid; + } + break; + + default: + ASSERT(0); + break; + } + + /* + * If there are no attributes associated with the file, + * then we're done. + * Assert that no attribute-related log flags are set. + */ + if (!XFS_IFORK_Q(ip)) { + ASSERT(nvecs == iip->ili_item.li_desc->lid_size); + iip->ili_format.ilf_size = nvecs; + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT))); + return; + } + + switch (ip->i_d.di_aformat) { + case XFS_DINODE_FMT_EXTENTS: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ADATA | XFS_ILOG_ABROOT))); + if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) { + ASSERT(ip->i_afp->if_bytes > 0); + ASSERT(ip->i_afp->if_u1.if_extents != NULL); + ASSERT(ip->i_d.di_anextents > 0); +#ifdef DEBUG + nrecs = ip->i_afp->if_bytes / + (uint)sizeof(xfs_bmbt_rec_t); +#endif + ASSERT(nrecs > 0); + ASSERT(nrecs == ip->i_d.di_anextents); + /* + * There are not delayed allocation extents + * for attributes, so just point at the array. + */ + vecp->i_addr = (char *)(ip->i_afp->if_u1.if_extents); + vecp->i_len = ip->i_afp->if_bytes; + iip->ili_format.ilf_asize = vecp->i_len; + vecp++; + nvecs++; + } + break; + + case XFS_DINODE_FMT_BTREE: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ADATA | XFS_ILOG_AEXT))); + if (iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) { + ASSERT(ip->i_afp->if_broot_bytes > 0); + ASSERT(ip->i_afp->if_broot != NULL); + vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot; + vecp->i_len = ip->i_afp->if_broot_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes; + } + break; + + case XFS_DINODE_FMT_LOCAL: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ABROOT | XFS_ILOG_AEXT))); + if (iip->ili_format.ilf_fields & XFS_ILOG_ADATA) { + ASSERT(ip->i_afp->if_bytes > 0); + ASSERT(ip->i_afp->if_u1.if_data != NULL); + + vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_u1.if_data; + /* + * Round i_bytes up to a word boundary. + * The underlying memory is guaranteed to + * to be there by xfs_idata_realloc(). + */ + data_bytes = roundup(ip->i_afp->if_bytes, 4); + ASSERT((ip->i_afp->if_real_bytes == 0) || + (ip->i_afp->if_real_bytes == data_bytes)); + vecp->i_len = (int)data_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_asize = (unsigned)data_bytes; + } + break; + + default: + ASSERT(0); + break; + } + + ASSERT(nvecs == iip->ili_item.li_desc->lid_size); + iip->ili_format.ilf_size = nvecs; +} + + +/* + * This is called to pin the inode associated with the inode log + * item in memory so it cannot be written out. Do this by calling + * xfs_ipin() to bump the pin count in the inode while holding the + * inode pin lock. + */ +STATIC void +xfs_inode_item_pin( + xfs_inode_log_item_t *iip) +{ + ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE)); + xfs_ipin(iip->ili_inode); +} + + +/* + * This is called to unpin the inode associated with the inode log + * item which was previously pinned with a call to xfs_inode_item_pin(). + * Just call xfs_iunpin() on the inode to do this. + */ +STATIC void +xfs_inode_item_unpin( + xfs_inode_log_item_t *iip) +{ + xfs_iunpin(iip->ili_inode); +} + +/* ARGSUSED */ +STATIC void +xfs_inode_item_unpin_remove( + xfs_inode_log_item_t *iip, + xfs_trans_t *tp) +{ + xfs_iunpin(iip->ili_inode); +} + +/* + * This is called to attempt to lock the inode associated with this + * inode log item, in preparation for the push routine which does the actual + * iflush. Don't sleep on the inode lock or the flush lock. + * + * If the flush lock is already held, indicating that the inode has + * been or is in the process of being flushed, then (ideally) we'd like to + * see if the inode's buffer is still incore, and if so give it a nudge. + * We delay doing so until the pushbuf routine, though, to avoid holding + * the AIL lock across a call to the blackhole which is the buffercache. + * Also we don't want to sleep in any device strategy routines, which can happen + * if we do the subsequent bawrite in here. + */ +STATIC uint +xfs_inode_item_trylock( + xfs_inode_log_item_t *iip) +{ + register xfs_inode_t *ip; + + ip = iip->ili_inode; + + if (xfs_ipincount(ip) > 0) { + return XFS_ITEM_PINNED; + } + + if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) { + return XFS_ITEM_LOCKED; + } + + if (!xfs_iflock_nowait(ip)) { + /* + * If someone else isn't already trying to push the inode + * buffer, we get to do it. + */ + if (iip->ili_pushbuf_flag == 0) { + iip->ili_pushbuf_flag = 1; +#ifdef DEBUG + iip->ili_push_owner = get_thread_id(); +#endif + /* + * Inode is left locked in shared mode. + * Pushbuf routine gets to unlock it. + */ + return XFS_ITEM_PUSHBUF; + } else { + /* + * We hold the AIL_LOCK, so we must specify the + * NONOTIFY flag so that we won't double trip. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY); + return XFS_ITEM_FLUSHING; + } + /* NOTREACHED */ + } +#ifdef DEBUG + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + ASSERT(iip->ili_format.ilf_fields != 0); + ASSERT(iip->ili_logged == 0); + ASSERT(iip->ili_item.li_flags & XFS_LI_IN_AIL); + } +#endif + return XFS_ITEM_SUCCESS; +} + +/* + * Unlock the inode associated with the inode log item. + * Clear the fields of the inode and inode log item that + * are specific to the current transaction. If the + * hold flags is set, do not unlock the inode. + */ +STATIC void +xfs_inode_item_unlock( + xfs_inode_log_item_t *iip) +{ + uint hold; + uint iolocked; + uint lock_flags; + xfs_inode_t *ip; + + ASSERT(iip != NULL); + ASSERT(iip->ili_inode->i_itemp != NULL); + ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE)); + ASSERT((!(iip->ili_inode->i_itemp->ili_flags & + XFS_ILI_IOLOCKED_EXCL)) || + ismrlocked(&(iip->ili_inode->i_iolock), MR_UPDATE)); + ASSERT((!(iip->ili_inode->i_itemp->ili_flags & + XFS_ILI_IOLOCKED_SHARED)) || + ismrlocked(&(iip->ili_inode->i_iolock), MR_ACCESS)); + /* + * Clear the transaction pointer in the inode. + */ + ip = iip->ili_inode; + ip->i_transp = NULL; + + /* + * If the inode needed a separate buffer with which to log + * its extents, then free it now. + */ + /* FIXME */ + if (iip->ili_extents_buf != NULL) { + ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS); + ASSERT(ip->i_d.di_nextents > 0); + ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT); + ASSERT(ip->i_df.if_bytes > 0); + kmem_free(iip->ili_extents_buf, ip->i_df.if_bytes); + iip->ili_extents_buf = NULL; + } + + /* + * Figure out if we should unlock the inode or not. + */ + hold = iip->ili_flags & XFS_ILI_HOLD; + + /* + * Before clearing out the flags, remember whether we + * are holding the inode's IO lock. + */ + iolocked = iip->ili_flags & XFS_ILI_IOLOCKED_ANY; + + /* + * Clear out the fields of the inode log item particular + * to the current transaction. + */ + iip->ili_ilock_recur = 0; + iip->ili_iolock_recur = 0; + iip->ili_flags = 0; + + /* + * Unlock the inode if XFS_ILI_HOLD was not set. + */ + if (!hold) { + lock_flags = XFS_ILOCK_EXCL; + if (iolocked & XFS_ILI_IOLOCKED_EXCL) { + lock_flags |= XFS_IOLOCK_EXCL; + } else if (iolocked & XFS_ILI_IOLOCKED_SHARED) { + lock_flags |= XFS_IOLOCK_SHARED; + } + xfs_iput(iip->ili_inode, lock_flags); + } +} + +/* + * This is called to find out where the oldest active copy of the + * inode log item in the on disk log resides now that the last log + * write of it completed at the given lsn. Since we always re-log + * all dirty data in an inode, the latest copy in the on disk log + * is the only one that matters. Therefore, simply return the + * given lsn. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_inode_item_committed( + xfs_inode_log_item_t *iip, + xfs_lsn_t lsn) +{ + return (lsn); +} + +/* + * The transaction with the inode locked has aborted. The inode + * must not be dirty within the transaction (unless we're forcibly + * shutting down). We simply unlock just as if the transaction + * had been cancelled. + */ +STATIC void +xfs_inode_item_abort( + xfs_inode_log_item_t *iip) +{ + xfs_inode_item_unlock(iip); + return; +} + + +/* + * This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK + * failed to get the inode flush lock but did get the inode locked SHARED. + * Here we're trying to see if the inode buffer is incore, and if so whether it's + * marked delayed write. If that's the case, we'll initiate a bawrite on that + * buffer to expedite the process. + * + * We aren't holding the AIL_LOCK (or the flush lock) when this gets called, + * so it is inherently race-y. + */ +STATIC void +xfs_inode_item_pushbuf( + xfs_inode_log_item_t *iip) +{ + xfs_inode_t *ip; + xfs_mount_t *mp; + xfs_buf_t *bp; + uint dopush; + + ip = iip->ili_inode; + + ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); + + /* + * The ili_pushbuf_flag keeps others from + * trying to duplicate our effort. + */ + ASSERT(iip->ili_pushbuf_flag != 0); + ASSERT(iip->ili_push_owner == get_thread_id()); + + /* + * If flushlock isn't locked anymore, chances are that the + * inode flush completed and the inode was taken off the AIL. + * So, just get out. + */ + if ((valusema(&(ip->i_flock)) > 0) || + ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return; + } + + mp = ip->i_mount; + bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno, + iip->ili_format.ilf_len, XFS_INCORE_TRYLOCK); + + if (bp != NULL) { + if (XFS_BUF_ISDELAYWRITE(bp)) { + /* + * We were racing with iflush because we don't hold + * the AIL_LOCK or the flush lock. However, at this point, + * we have the buffer, and we know that it's dirty. + * So, it's possible that iflush raced with us, and + * this item is already taken off the AIL. + * If not, we can flush it async. + */ + dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && + (valusema(&(ip->i_flock)) <= 0)); + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + xfs_buftrace("INODE ITEM PUSH", bp); + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + if (dopush) { + xfs_bawrite(mp, bp); + } else { + xfs_buf_relse(bp); + } + } else { + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + xfs_buf_relse(bp); + } + return; + } + /* + * We have to be careful about resetting pushbuf flag too early (above). + * Even though in theory we can do it as soon as we have the buflock, + * we don't want others to be doing work needlessly. They'll come to + * this function thinking that pushing the buffer is their + * responsibility only to find that the buffer is still locked by + * another doing the same thing + */ + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return; +} + + +/* + * This is called to asynchronously write the inode associated with this + * inode log item out to disk. The inode will already have been locked by + * a successful call to xfs_inode_item_trylock(). + */ +STATIC void +xfs_inode_item_push( + xfs_inode_log_item_t *iip) +{ + xfs_inode_t *ip; + + ip = iip->ili_inode; + + ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); + ASSERT(valusema(&(ip->i_flock)) <= 0); + /* + * Since we were able to lock the inode's flush lock and + * we found it on the AIL, the inode must be dirty. This + * is because the inode is removed from the AIL while still + * holding the flush lock in xfs_iflush_done(). Thus, if + * we found it in the AIL and were able to obtain the flush + * lock without sleeping, then there must not have been + * anyone in the process of flushing the inode. + */ + ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || + iip->ili_format.ilf_fields != 0); + + /* + * Write out the inode. The completion routine ('iflush_done') will + * pull it from the AIL, mark it clean, unlock the flush lock. + */ + (void) xfs_iflush(ip, XFS_IFLUSH_DELWRI); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + return; +} + +/* + * XXX rcc - this one really has to do something. Probably needs + * to stamp in a new field in the incore inode. + */ +/* ARGSUSED */ +STATIC void +xfs_inode_item_committing( + xfs_inode_log_item_t *iip, + xfs_lsn_t lsn) +{ + iip->ili_last_lsn = lsn; + return; +} + +/* + * This is the ops vector shared by all buf log items. + */ +struct xfs_item_ops xfs_inode_item_ops = { + .iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size, + .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_inode_item_format, + .iop_pin = (void(*)(xfs_log_item_t*))xfs_inode_item_pin, + .iop_unpin = (void(*)(xfs_log_item_t*))xfs_inode_item_unpin, + .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*)) + xfs_inode_item_unpin_remove, + .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_inode_item_trylock, + .iop_unlock = (void(*)(xfs_log_item_t*))xfs_inode_item_unlock, + .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_inode_item_committed, + .iop_push = (void(*)(xfs_log_item_t*))xfs_inode_item_push, + .iop_abort = (void(*)(xfs_log_item_t*))xfs_inode_item_abort, + .iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_inode_item_pushbuf, + .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_inode_item_committing +}; + + +/* + * Initialize the inode log item for a newly allocated (in-core) inode. + */ +void +xfs_inode_item_init( + xfs_inode_t *ip, + xfs_mount_t *mp) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_itemp == NULL); + iip = ip->i_itemp = kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP); + + iip->ili_item.li_type = XFS_LI_INODE; + iip->ili_item.li_ops = &xfs_inode_item_ops; + iip->ili_item.li_mountp = mp; + iip->ili_inode = ip; + + /* + We have bzeroed memory. No need ... + iip->ili_extents_buf = NULL; + iip->ili_pushbuf_flag = 0; + */ + + iip->ili_format.ilf_type = XFS_LI_INODE; + iip->ili_format.ilf_ino = ip->i_ino; + iip->ili_format.ilf_blkno = ip->i_blkno; + iip->ili_format.ilf_len = ip->i_len; + iip->ili_format.ilf_boffset = ip->i_boffset; +} + +/* + * Free the inode log item and any memory hanging off of it. + */ +void +xfs_inode_item_destroy( + xfs_inode_t *ip) +{ +#ifdef XFS_TRANS_DEBUG + if (ip->i_itemp->ili_root_size != 0) { + kmem_free(ip->i_itemp->ili_orig_root, + ip->i_itemp->ili_root_size); + } +#endif + kmem_zone_free(xfs_ili_zone, ip->i_itemp); +} + + +/* + * This is the inode flushing I/O completion routine. It is called + * from interrupt level when the buffer containing the inode is + * flushed to disk. It is responsible for removing the inode item + * from the AIL if it has not been re-logged, and unlocking the inode's + * flush lock. + */ +/*ARGSUSED*/ +void +xfs_iflush_done( + xfs_buf_t *bp, + xfs_inode_log_item_t *iip) +{ + xfs_inode_t *ip; + SPLDECL(s); + + ip = iip->ili_inode; + + /* + * We only want to pull the item from the AIL if it is + * actually there and its location in the log has not + * changed since we started the flush. Thus, we only bother + * if the ili_logged flag is set and the inode's lsn has not + * changed. First we check the lsn outside + * the lock since it's cheaper, and then we recheck while + * holding the lock before removing the inode from the AIL. + */ + if (iip->ili_logged && + (iip->ili_item.li_lsn == iip->ili_flush_lsn)) { + AIL_LOCK(ip->i_mount, s); + if (iip->ili_item.li_lsn == iip->ili_flush_lsn) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(ip->i_mount, + (xfs_log_item_t*)iip, s); + } else { + AIL_UNLOCK(ip->i_mount, s); + } + } + + iip->ili_logged = 0; + + /* + * Clear the ili_last_fields bits now that we know that the + * data corresponding to them is safely on disk. + */ + iip->ili_last_fields = 0; + + /* + * Release the inode's flush lock since we're done with it. + */ + xfs_ifunlock(ip); + + return; +} + +/* + * This is the inode flushing abort routine. It is called + * from xfs_iflush when the filesystem is shutting down to clean + * up the inode state. + * It is responsible for removing the inode item + * from the AIL if it has not been re-logged, and unlocking the inode's + * flush lock. + */ +void +xfs_iflush_abort( + xfs_inode_t *ip) +{ + xfs_inode_log_item_t *iip; + xfs_mount_t *mp; + SPLDECL(s); + + iip = ip->i_itemp; + mp = ip->i_mount; + if (iip) { + if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { + AIL_LOCK(mp, s); + if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip, + s); + } else + AIL_UNLOCK(mp, s); + } + iip->ili_logged = 0; + /* + * Clear the ili_last_fields bits now that we know that the + * data corresponding to them is safely on disk. + */ + iip->ili_last_fields = 0; + /* + * Clear the inode logging fields so no more flushes are + * attempted. + */ + iip->ili_format.ilf_fields = 0; + } + /* + * Release the inode's flush lock since we're done with it. + */ + xfs_ifunlock(ip); +} diff -Nur linux-2.4.19/fs/xfs/xfs_inode_item.h linux-2.4.19-sgi211r3/fs/xfs/xfs_inode_item.h --- linux-2.4.19/fs/xfs/xfs_inode_item.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_inode_item.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INODE_ITEM_H__ +#define __XFS_INODE_ITEM_H__ + +/* + * This is the structure used to lay out an inode log item in the + * log. The size of the inline data/extents/b-tree root to be logged + * (if any) is indicated in the ilf_dsize field. Changes to this structure + * must be added on to the end. + * + * Convention for naming inode log item versions : The current version + * is always named XFS_LI_INODE. When an inode log item gets superseded, + * add the latest version of IRIX that will generate logs with that item + * to the version name. + * + * -Version 1 of this structure (XFS_LI_5_3_INODE) included up to the first + * union (ilf_u) field. This was released with IRIX 5.3-XFS. + * -Version 2 of this structure (XFS_LI_6_1_INODE) is currently the entire + * structure. This was released with IRIX 6.0.1-XFS and IRIX 6.1. + * -Version 3 of this structure (XFS_LI_INODE) is the same as version 2 + * so a new structure definition wasn't necessary. However, we had + * to add a new type because the inode cluster size changed from 4K + * to 8K and the version number had to be rev'ved to keep older kernels + * from trying to recover logs with the 8K buffers in them. The logging + * code can handle recovery on different-sized clusters now so hopefully + * this'll be the last time we need to change the inode log item just + * for a change in the inode cluster size. This new version was + * released with IRIX 6.2. + */ +typedef struct xfs_inode_log_format { + unsigned short ilf_type; /* inode log item type */ + unsigned short ilf_size; /* size of this item */ + uint ilf_fields; /* flags for fields logged */ + ushort ilf_asize; /* size of attr d/ext/root */ + ushort ilf_dsize; /* size of data/ext/root */ + xfs_ino_t ilf_ino; /* inode number */ + union { + xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/ + uuid_t ilfu_uuid; /* mount point value */ + } ilf_u; + __int64_t ilf_blkno; /* blkno of inode buffer */ + int ilf_len; /* len of inode buffer */ + int ilf_boffset; /* off of inode in buffer */ +} xfs_inode_log_format_t; + +/* Initial version shipped with IRIX 5.3-XFS */ +typedef struct xfs_inode_log_format_v1 { + unsigned short ilf_type; /* inode log item type */ + unsigned short ilf_size; /* size of this item */ + uint ilf_fields; /* flags for fields logged */ + uint ilf_dsize; /* size of data/ext/root */ + xfs_ino_t ilf_ino; /* inode number */ + union { + xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/ + uuid_t ilfu_uuid; /* mount point value */ + } ilf_u; +} xfs_inode_log_format_t_v1; + +/* + * Flags for xfs_trans_log_inode flags field. + */ +#define XFS_ILOG_CORE 0x001 /* log standard inode fields */ +#define XFS_ILOG_DDATA 0x002 /* log i_df.if_data */ +#define XFS_ILOG_DEXT 0x004 /* log i_df.if_extents */ +#define XFS_ILOG_DBROOT 0x008 /* log i_df.i_broot */ +#define XFS_ILOG_DEV 0x010 /* log the dev field */ +#define XFS_ILOG_UUID 0x020 /* log the uuid field */ +#define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ +#define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ +#define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ + +#define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ + XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ + XFS_ILOG_UUID | XFS_ILOG_ADATA | \ + XFS_ILOG_AEXT | XFS_ILOG_ABROOT) + +#define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ + XFS_ILOG_DBROOT) + +#define XFS_ILOG_AFORK (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ + XFS_ILOG_ABROOT) + +#define XFS_ILOG_ALL (XFS_ILOG_CORE | XFS_ILOG_DDATA | \ + XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ + XFS_ILOG_DEV | XFS_ILOG_UUID | \ + XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ + XFS_ILOG_ABROOT) + +#define XFS_ILI_HOLD 0x1 +#define XFS_ILI_IOLOCKED_EXCL 0x2 +#define XFS_ILI_IOLOCKED_SHARED 0x4 + +#define XFS_ILI_IOLOCKED_ANY (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED) + + +#ifdef __KERNEL__ + +struct xfs_buf; +struct xfs_bmbt_rec_32; +struct xfs_inode; +struct xfs_mount; + + +typedef struct xfs_inode_log_item { + xfs_log_item_t ili_item; /* common portion */ + struct xfs_inode *ili_inode; /* inode ptr */ + xfs_lsn_t ili_flush_lsn; /* lsn at last flush */ + xfs_lsn_t ili_last_lsn; /* lsn at last transaction */ + unsigned short ili_ilock_recur; /* lock recursion count */ + unsigned short ili_iolock_recur; /* lock recursion count */ + unsigned short ili_flags; /* misc flags */ + unsigned short ili_logged; /* flushed logged data */ + unsigned int ili_last_fields; /* fields when flushed */ + struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged exts */ + unsigned int ili_pushbuf_flag; /* one bit used in push_ail */ + +#ifdef DEBUG + uint64_t ili_push_owner; /* one who sets pushbuf_flag + above gets to push the buf */ +#endif +#ifdef XFS_TRANS_DEBUG + int ili_root_size; + char *ili_orig_root; +#endif + xfs_inode_log_format_t ili_format; /* logged structure */ +} xfs_inode_log_item_t; + + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FDATA) +int xfs_ilog_fdata(int w); +#define XFS_ILOG_FDATA(w) xfs_ilog_fdata(w) +#else +#define XFS_ILOG_FDATA(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA) +#endif + +#endif /* __KERNEL__ */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FBROOT) +int xfs_ilog_fbroot(int w); +#define XFS_ILOG_FBROOT(w) xfs_ilog_fbroot(w) +#else +#define XFS_ILOG_FBROOT(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FEXT) +int xfs_ilog_fext(int w); +#define XFS_ILOG_FEXT(w) xfs_ilog_fext(w) +#else +#define XFS_ILOG_FEXT(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT) +#endif + +#ifdef __KERNEL__ + +void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *); +void xfs_inode_item_destroy(struct xfs_inode *); +void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *); +void xfs_iflush_abort(struct xfs_inode *); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_INODE_ITEM_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_inum.h linux-2.4.19-sgi211r3/fs/xfs/xfs_inum.h --- linux-2.4.19/fs/xfs/xfs_inum.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_inum.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INUM_H__ +#define __XFS_INUM_H__ + +/* + * Inode number format: + * low inopblog bits - offset in block + * next agblklog bits - block number in ag + * next agno_log bits - ag number + * high agno_log-agblklog-inopblog bits - 0 + */ + +typedef __uint32_t xfs_agino_t; /* within allocation grp inode number */ + +/* + * Useful inode bits for this kernel. + * Used in some places where having 64-bits in the 32-bit kernels + * costs too much. + */ +#if XFS_BIG_FILESYSTEMS +typedef xfs_ino_t xfs_intino_t; +#else +typedef __uint32_t xfs_intino_t; +#endif + +#define NULLFSINO ((xfs_ino_t)-1) +#define NULLAGINO ((xfs_agino_t)-1) + +struct xfs_mount; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_MASK) +__uint32_t xfs_ino_mask(int k); +#define XFS_INO_MASK(k) xfs_ino_mask(k) +#else +#define XFS_INO_MASK(k) ((__uint32_t)((1ULL << (k)) - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_OFFSET_BITS) +int xfs_ino_offset_bits(struct xfs_mount *mp); +#define XFS_INO_OFFSET_BITS(mp) xfs_ino_offset_bits(mp) +#else +#define XFS_INO_OFFSET_BITS(mp) ((mp)->m_sb.sb_inopblog) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGBNO_BITS) +int xfs_ino_agbno_bits(struct xfs_mount *mp); +#define XFS_INO_AGBNO_BITS(mp) xfs_ino_agbno_bits(mp) +#else +#define XFS_INO_AGBNO_BITS(mp) ((mp)->m_sb.sb_agblklog) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGINO_BITS) +int xfs_ino_agino_bits(struct xfs_mount *mp); +#define XFS_INO_AGINO_BITS(mp) xfs_ino_agino_bits(mp) +#else +#define XFS_INO_AGINO_BITS(mp) ((mp)->m_agino_log) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGNO_BITS) +int xfs_ino_agno_bits(struct xfs_mount *mp); +#define XFS_INO_AGNO_BITS(mp) xfs_ino_agno_bits(mp) +#else +#define XFS_INO_AGNO_BITS(mp) ((mp)->m_agno_log) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_BITS) +int xfs_ino_bits(struct xfs_mount *mp); +#define XFS_INO_BITS(mp) xfs_ino_bits(mp) +#else +#define XFS_INO_BITS(mp) (XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGNO) +xfs_agnumber_t xfs_ino_to_agno(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGNO(mp,i) xfs_ino_to_agno(mp,i) +#else +#define XFS_INO_TO_AGNO(mp,i) \ + ((xfs_agnumber_t)((i) >> XFS_INO_AGINO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGINO) +xfs_agino_t xfs_ino_to_agino(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGINO(mp,i) xfs_ino_to_agino(mp,i) +#else +#define XFS_INO_TO_AGINO(mp,i) \ + ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGBNO) +xfs_agblock_t xfs_ino_to_agbno(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGBNO(mp,i) xfs_ino_to_agbno(mp,i) +#else +#define XFS_INO_TO_AGBNO(mp,i) \ + (((xfs_agblock_t)(i) >> XFS_INO_OFFSET_BITS(mp)) & \ + XFS_INO_MASK(XFS_INO_AGBNO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_OFFSET) +int xfs_ino_to_offset(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_OFFSET(mp,i) xfs_ino_to_offset(mp,i) +#else +#define XFS_INO_TO_OFFSET(mp,i) \ + ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_FSB) +xfs_fsblock_t xfs_ino_to_fsb(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_FSB(mp,i) xfs_ino_to_fsb(mp,i) +#else +#define XFS_INO_TO_FSB(mp,i) \ + XFS_AGB_TO_FSB(mp, XFS_INO_TO_AGNO(mp,i), XFS_INO_TO_AGBNO(mp,i)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_INO) +xfs_ino_t +xfs_agino_to_ino(struct xfs_mount *mp, xfs_agnumber_t a, xfs_agino_t i); +#define XFS_AGINO_TO_INO(mp,a,i) xfs_agino_to_ino(mp,a,i) +#else +#define XFS_AGINO_TO_INO(mp,a,i) \ + (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_AGBNO) +xfs_agblock_t xfs_agino_to_agbno(struct xfs_mount *mp, xfs_agino_t i); +#define XFS_AGINO_TO_AGBNO(mp,i) xfs_agino_to_agbno(mp,i) +#else +#define XFS_AGINO_TO_AGBNO(mp,i) ((i) >> XFS_INO_OFFSET_BITS(mp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_OFFSET) +int xfs_agino_to_offset(struct xfs_mount *mp, xfs_agino_t i); +#define XFS_AGINO_TO_OFFSET(mp,i) xfs_agino_to_offset(mp,i) +#else +#define XFS_AGINO_TO_OFFSET(mp,i) \ + ((i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_OFFBNO_TO_AGINO) +xfs_agino_t xfs_offbno_to_agino(struct xfs_mount *mp, xfs_agblock_t b, int o); +#define XFS_OFFBNO_TO_AGINO(mp,b,o) xfs_offbno_to_agino(mp,b,o) +#else +#define XFS_OFFBNO_TO_AGINO(mp,b,o) \ + ((xfs_agino_t)(((b) << XFS_INO_OFFSET_BITS(mp)) | (o))) +#endif + +#if XFS_BIG_FILESYSTEMS +#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) +#define XFS_INO64_OFFSET ((xfs_ino_t)(1ULL << 32)) +#else +#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 32) - 1ULL)) +#endif +#define XFS_MAXINUMBER_32 ((xfs_ino_t)((1ULL << 32) - 1ULL)) + +#endif /* __XFS_INUM_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_iocore.c linux-2.4.19-sgi211r3/fs/xfs/xfs_iocore.c --- linux-2.4.19/fs/xfs/xfs_iocore.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_iocore.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +static xfs_fsize_t +xfs_size_fn( + xfs_inode_t *ip) +{ + return (ip->i_d.di_size); +} + +xfs_ioops_t xfs_iocore_xfs = { + .xfs_bmapi_func = (xfs_bmapi_t) xfs_bmapi, + .xfs_bmap_eof_func = (xfs_bmap_eof_t) xfs_bmap_eof, + .xfs_ilock = (xfs_lock_t) xfs_ilock, + .xfs_ilock_demote = (xfs_lock_demote_t) xfs_ilock_demote, + .xfs_ilock_nowait = (xfs_lock_nowait_t) xfs_ilock_nowait, + .xfs_unlock = (xfs_unlk_t) xfs_iunlock, + .xfs_size_func = (xfs_size_t) xfs_size_fn, + .xfs_lastbyte = (xfs_lastbyte_t) xfs_file_last_byte, +}; + +void +xfs_iocore_inode_reinit( + xfs_inode_t *ip) +{ + xfs_iocore_t *io = &ip->i_iocore; + + io->io_flags = XFS_IOCORE_ISXFS; + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + io->io_flags |= XFS_IOCORE_RT; + } + + io->io_dmevmask = ip->i_d.di_dmevmask; + io->io_dmstate = ip->i_d.di_dmstate; +} + +void +xfs_iocore_inode_init( + xfs_inode_t *ip) +{ + xfs_iocore_t *io = &ip->i_iocore; + xfs_mount_t *mp = ip->i_mount; + + io->io_mount = mp; +#ifdef DEBUG + io->io_lock = &ip->i_lock; + io->io_iolock = &ip->i_iolock; +#endif + + io->io_obj = (void *)ip; + + xfs_iocore_inode_reinit(ip); +} + diff -Nur linux-2.4.19/fs/xfs/xfs_itable.c linux-2.4.19-sgi211r3/fs/xfs/xfs_itable.c --- linux-2.4.19/fs/xfs/xfs_itable.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_itable.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,770 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Return stat information for one inode. + * Return 0 if ok, else errno. + */ +int /* error status */ +xfs_bulkstat_one( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* buffer to place output in */ + xfs_daddr_t bno, /* starting bno of inode cluster */ + void *dibuff, /* on-disk inode buffer */ + int *stat) /* BULKSTAT_RV_... */ +{ + xfs_bstat_t *buf; /* return buffer */ + int error; /* error value */ + xfs_dinode_t *dip; /* dinode inode pointer */ + xfs_dinode_core_t *dic; /* dinode core info pointer */ + xfs_inode_t *ip = NULL; /* incore inode pointer */ + xfs_arch_t arch; /* these are set according to */ + __uint16_t di_flags; /* temp */ + + buf = (xfs_bstat_t *)buffer; + dip = (xfs_dinode_t *)dibuff; + + if (! buf || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || + (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && + (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))) { + *stat = BULKSTAT_RV_NOTHING; + return XFS_ERROR(EINVAL); + } + + if (dip == NULL) { + /* We're not being passed a pointer to a dinode. This happens + * if BULKSTAT_FG_IGET is selected. Do the iget. + */ + error = xfs_iget(mp, tp, ino, XFS_ILOCK_SHARED, &ip, bno); + if (error) { + *stat = BULKSTAT_RV_NOTHING; + return error; + } + ASSERT(ip != NULL); + ASSERT(ip->i_blkno != (xfs_daddr_t)0); + if (ip->i_d.di_mode == 0) { + xfs_iput_new(ip, XFS_ILOCK_SHARED); + *stat = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + dic = &ip->i_d; + arch = ARCH_NOCONVERT; /* in-core! */ + ASSERT(dic != NULL); + + /* xfs_iget returns the following without needing + * further change. + */ + buf->bs_nlink = dic->di_nlink; + buf->bs_projid = dic->di_projid; + + } else { + dic = &dip->di_core; + ASSERT(dic != NULL); + + /* buffer dinode_core is in on-disk arch */ + arch = ARCH_CONVERT; + + /* + * The inode format changed when we moved the link count and + * made it 32 bits long. If this is an old format inode, + * convert it in memory to look like a new one. If it gets + * flushed to disk we will convert back before flushing or + * logging it. We zero out the new projid field and the old link + * count field. We'll handle clearing the pad field (the remains + * of the old uuid field) when we actually convert the inode to + * the new format. We don't change the version number so that we + * can distinguish this from a real new format inode. + */ + if (INT_GET(dic->di_version, arch) == XFS_DINODE_VERSION_1) { + buf->bs_nlink = INT_GET(dic->di_onlink, arch); + buf->bs_projid = 0; + } + else { + buf->bs_nlink = INT_GET(dic->di_nlink, arch); + buf->bs_projid = INT_GET(dic->di_projid, arch); + } + + } + + buf->bs_ino = ino; + buf->bs_mode = INT_GET(dic->di_mode, arch); + buf->bs_uid = INT_GET(dic->di_uid, arch); + buf->bs_gid = INT_GET(dic->di_gid, arch); + buf->bs_size = INT_GET(dic->di_size, arch); + buf->bs_atime.tv_sec = INT_GET(dic->di_atime.t_sec, arch); + buf->bs_atime.tv_nsec = INT_GET(dic->di_atime.t_nsec, arch); + buf->bs_mtime.tv_sec = INT_GET(dic->di_mtime.t_sec, arch); + buf->bs_mtime.tv_nsec = INT_GET(dic->di_mtime.t_nsec, arch); + buf->bs_ctime.tv_sec = INT_GET(dic->di_ctime.t_sec, arch); + buf->bs_ctime.tv_nsec = INT_GET(dic->di_ctime.t_nsec, arch); + /* + * convert di_flags to bs_xflags. + */ + di_flags=INT_GET(dic->di_flags, arch); + + buf->bs_xflags = + ((di_flags & XFS_DIFLAG_REALTIME) ? + XFS_XFLAG_REALTIME : 0) | + ((di_flags & XFS_DIFLAG_PREALLOC) ? + XFS_XFLAG_PREALLOC : 0) | + (XFS_CFORK_Q_ARCH(dic, arch) ? + XFS_XFLAG_HASATTR : 0); + + buf->bs_extsize = INT_GET(dic->di_extsize, arch) << mp->m_sb.sb_blocklog; + buf->bs_extents = INT_GET(dic->di_nextents, arch); + buf->bs_gen = INT_GET(dic->di_gen, arch); + bzero(buf->bs_pad, sizeof(buf->bs_pad)); + buf->bs_dmevmask = INT_GET(dic->di_dmevmask, arch); + buf->bs_dmstate = INT_GET(dic->di_dmstate, arch); + buf->bs_aextents = INT_GET(dic->di_anextents, arch); + + switch (INT_GET(dic->di_format, arch)) { + case XFS_DINODE_FMT_DEV: + if ( ip ) { + buf->bs_rdev = ip->i_df.if_u2.if_rdev; + } else { + buf->bs_rdev = INT_GET(dip->di_u.di_dev, arch); + } + + buf->bs_blksize = BLKDEV_IOSIZE; + buf->bs_blocks = 0; + break; + case XFS_DINODE_FMT_LOCAL: + case XFS_DINODE_FMT_UUID: + buf->bs_rdev = 0; + buf->bs_blksize = mp->m_sb.sb_blocksize; + buf->bs_blocks = 0; + break; + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + buf->bs_rdev = 0; + buf->bs_blksize = mp->m_sb.sb_blocksize; + if ( ip ) { + buf->bs_blocks = INT_GET(dic->di_nblocks, arch) + ip->i_delayed_blks; + } else { + buf->bs_blocks = INT_GET(dic->di_nblocks, arch); + } + break; + } + + if (ip) { + xfs_iput(ip, XFS_ILOCK_SHARED); + } + + *stat = BULKSTAT_RV_DIDONE; + return 0; +} + +/* + * Return stat information in bulk (by-inode) for the filesystem. + */ +int /* error status */ +xfs_bulkstat( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t *lastinop, /* last inode returned */ + int *ubcountp, /* size of buffer/count returned */ + bulkstat_one_pf formatter, /* func that'd fill a single buf */ + size_t statstruct_size, /* sizeof struct filling */ + xfs_caddr_t ubuffer, /* buffer with inode stats */ + int flags, /* defined in xfs_itable.h */ + int *done) /* 1 if there're more stats to get */ +{ + xfs_agblock_t agbno=0;/* allocation group block number */ + xfs_buf_t *agbp; /* agi header buffer */ + xfs_agi_t *agi; /* agi header data */ + xfs_agino_t agino; /* inode # in allocation group */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_daddr_t bno; /* inode cluster start daddr */ + int chunkidx; /* current index into inode chunk */ + int clustidx; /* current index into inode cluster */ + xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ + int end_of_ag; /* set if we've seen the ag end */ + int error; /* error code */ + int fmterror;/* bulkstat formatter result */ + __int32_t gcnt; /* current btree rec's count */ + xfs_inofree_t gfree; /* current btree rec's free mask */ + xfs_agino_t gino; /* current btree rec's start inode */ + int i; /* loop index */ + int icount; /* count of inodes good in irbuf */ + xfs_ino_t ino; /* inode number (filesystem) */ + xfs_inobt_rec_t *irbp; /* current irec buffer pointer */ + xfs_inobt_rec_t *irbuf; /* start of irec buffer */ + xfs_inobt_rec_t *irbufend; /* end of good irec buffer entries */ + xfs_ino_t lastino=0; /* last inode number returned */ + int nbcluster; /* # of blocks in a cluster */ + int nicluster; /* # of inodes in a cluster */ + int nimask; /* mask for inode clusters */ + int nirbuf; /* size of irbuf */ + int rval; /* return value error code */ + int tmp; /* result value from btree calls */ + int ubcount; /* size of user's buffer */ + int ubleft; /* spaces left in user's buffer */ + xfs_caddr_t ubufp; /* current pointer into user's buffer */ + xfs_buf_t *bp; /* ptr to on-disk inode cluster buf */ + xfs_dinode_t *dip; /* ptr into bp for specific inode */ + xfs_inode_t *ip; /* ptr to in-core inode struct */ + + /* + * Get the last inode value, see if there's nothing to do. + */ + ino = (xfs_ino_t)*lastinop; + dip = NULL; + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + if (agno >= mp->m_sb.sb_agcount || + ino != XFS_AGINO_TO_INO(mp, agno, agino)) { + *done = 1; + *ubcountp = 0; + return 0; + } + ubcount = ubleft = *ubcountp; + *ubcountp = 0; + *done = 0; + fmterror = 0; + ubufp = ubuffer; + nicluster = mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp) ? + mp->m_sb.sb_inopblock : + (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); + nimask = ~(nicluster - 1); + nbcluster = nicluster >> mp->m_sb.sb_inopblog; + /* + * Lock down the user's buffer. If a buffer was not sent, as in the case + * disk quota code calls here, we skip this. + */ +#if defined(HAVE_USERACC) + if (ubuffer && + (error = useracc(ubuffer, ubcount * statstruct_size, + (B_READ|B_PHYS), NULL))) { + return error; + } +#endif + /* + * Allocate a page-sized buffer for inode btree records. + * We could try allocating something smaller, but for normal + * calls we'll always (potentially) need the whole page. + */ + irbuf = kmem_alloc(NBPC, KM_SLEEP); + nirbuf = NBPC / sizeof(*irbuf); + /* + * Loop over the allocation groups, starting from the last + * inode returned; 0 means start of the allocation group. + */ + rval = 0; + while (ubleft > 0 && agno < mp->m_sb.sb_agcount) { + bp = NULL; + down_read(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + up_read(&mp->m_peraglock); + if (error) { + /* + * Skip this allocation group and go to the next one. + */ + agno++; + agino = 0; + continue; + } + agi = XFS_BUF_TO_AGI(agbp); + /* + * Allocate and initialize a btree cursor for ialloc btree. + */ + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, + (xfs_inode_t *)0, 0); + irbp = irbuf; + irbufend = irbuf + nirbuf; + end_of_ag = 0; + /* + * If we're returning in the middle of an allocation group, + * we need to get the remainder of the chunk we're in. + */ + if (agino > 0) { + /* + * Lookup the inode chunk that this inode lives in. + */ + error = xfs_inobt_lookup_le(cur, agino, 0, 0, &tmp); + if (!error && /* no I/O error */ + tmp && /* lookup succeeded */ + /* got the record, should always work */ + !(error = xfs_inobt_get_rec(cur, &gino, &gcnt, + &gfree, &i, ARCH_NOCONVERT)) && + i == 1 && + /* this is the right chunk */ + agino < gino + XFS_INODES_PER_CHUNK && + /* lastino was not last in chunk */ + (chunkidx = agino - gino + 1) < + XFS_INODES_PER_CHUNK && + /* there are some left allocated */ + XFS_INOBT_MASKN(chunkidx, + XFS_INODES_PER_CHUNK - chunkidx) & ~gfree) { + /* + * Grab the chunk record. Mark all the + * uninteresting inodes (because they're + * before our start point) free. + */ + for (i = 0; i < chunkidx; i++) { + if (XFS_INOBT_MASK(i) & ~gfree) + gcnt++; + } + gfree |= XFS_INOBT_MASKN(0, chunkidx); + INT_SET(irbp->ir_startino, ARCH_CONVERT, gino); + INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt); + INT_SET(irbp->ir_free, ARCH_CONVERT, gfree); + irbp++; + agino = gino + XFS_INODES_PER_CHUNK; + icount = XFS_INODES_PER_CHUNK - gcnt; + } else { + /* + * If any of those tests failed, bump the + * inode number (just in case). + */ + agino++; + icount = 0; + } + /* + * In any case, increment to the next record. + */ + if (!error) + error = xfs_inobt_increment(cur, 0, &tmp); + } else { + /* + * Start of ag. Lookup the first inode chunk. + */ + error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &tmp); + icount = 0; + } + /* + * Loop through inode btree records in this ag, + * until we run out of inodes or space in the buffer. + */ + while (irbp < irbufend && icount < ubcount) { + /* + * Loop as long as we're unable to read the + * inode btree. + */ + while (error) { + agino += XFS_INODES_PER_CHUNK; + if (XFS_AGINO_TO_AGBNO(mp, agino) >= + INT_GET(agi->agi_length, ARCH_CONVERT)) + break; + error = xfs_inobt_lookup_ge(cur, agino, 0, 0, + &tmp); + } + /* + * If ran off the end of the ag either with an error, + * or the normal way, set end and stop collecting. + */ + if (error || + (error = xfs_inobt_get_rec(cur, &gino, &gcnt, + &gfree, &i, ARCH_NOCONVERT)) || + i == 0) { + end_of_ag = 1; + break; + } + /* + * If this chunk has any allocated inodes, save it. + */ + if (gcnt < XFS_INODES_PER_CHUNK) { + INT_SET(irbp->ir_startino, ARCH_CONVERT, gino); + INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt); + INT_SET(irbp->ir_free, ARCH_CONVERT, gfree); + irbp++; + icount += XFS_INODES_PER_CHUNK - gcnt; + } + /* + * Set agino to after this chunk and bump the cursor. + */ + agino = gino + XFS_INODES_PER_CHUNK; + error = xfs_inobt_increment(cur, 0, &tmp); + } + /* + * Drop the btree buffers and the agi buffer. + * We can't hold any of the locks these represent + * when calling iget. + */ + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_trans_brelse(tp, agbp); + /* + * Now format all the good inodes into the user's buffer. + */ + irbufend = irbp; + for (irbp = irbuf; irbp < irbufend && ubleft > 0; irbp++) { + /* + * Read-ahead the next chunk's worth of inodes. + */ + if (&irbp[1] < irbufend) { + /* + * Loop over all clusters in the next chunk. + * Do a readahead if there are any allocated + * inodes in that cluster. + */ + for (agbno = XFS_AGINO_TO_AGBNO(mp, + INT_GET(irbp[1].ir_startino, ARCH_CONVERT)), + chunkidx = 0; + chunkidx < XFS_INODES_PER_CHUNK; + chunkidx += nicluster, + agbno += nbcluster) { + if (XFS_INOBT_MASKN(chunkidx, + nicluster) & + ~(INT_GET(irbp[1].ir_free, ARCH_CONVERT))) + xfs_btree_reada_bufs(mp, agno, + agbno, nbcluster); + } + } + /* + * Now process this chunk of inodes. + */ + for (agino = INT_GET(irbp->ir_startino, ARCH_CONVERT), chunkidx = 0, clustidx = 0; + ubleft > 0 && + INT_GET(irbp->ir_freecount, ARCH_CONVERT) < XFS_INODES_PER_CHUNK; + chunkidx++, clustidx++, agino++) { + ASSERT(chunkidx < XFS_INODES_PER_CHUNK); + /* + * Recompute agbno if this is the + * first inode of the cluster. + * + * Careful with clustidx. There can be + * multple clusters per chunk, a single + * cluster per chunk or a cluster that has + * inodes represented from several different + * chunks (if blocksize is large). + * + * Because of this, the starting clustidx is + * initialized to zero in this loop but must + * later be reset after reading in the cluster + * buffer. + */ + if ((chunkidx & (nicluster - 1)) == 0) { + agbno = XFS_AGINO_TO_AGBNO(mp, + INT_GET(irbp->ir_startino, ARCH_CONVERT)) + + ((chunkidx & nimask) >> + mp->m_sb.sb_inopblog); + + if (flags & BULKSTAT_FG_QUICK) { + ino = XFS_AGINO_TO_INO(mp, agno, + agino); + bno = XFS_AGB_TO_DADDR(mp, agno, + agbno); + + /* + * Get the inode cluster buffer + */ + ASSERT(xfs_inode_zone != NULL); + ip = kmem_zone_zalloc(xfs_inode_zone, + KM_SLEEP); + ip->i_ino = ino; + ip->i_mount = mp; + if (bp) + xfs_trans_brelse(tp, bp); + error = xfs_itobp(mp, tp, ip, + &dip, &bp, bno); + if (!error) + clustidx = ip->i_boffset / mp->m_sb.sb_inodesize; + kmem_zone_free(xfs_inode_zone, ip); + if (XFS_TEST_ERROR(error != 0, + mp, XFS_ERRTAG_BULKSTAT_READ_CHUNK, + XFS_RANDOM_BULKSTAT_READ_CHUNK)) { + bp = NULL; + break; + } + } + } + /* + * Skip if this inode is free. + */ + if (XFS_INOBT_MASK(chunkidx) & INT_GET(irbp->ir_free, ARCH_CONVERT)) + continue; + /* + * Count used inodes as free so we can tell + * when the chunk is used up. + */ + INT_MOD(irbp->ir_freecount, ARCH_CONVERT, +1); + ino = XFS_AGINO_TO_INO(mp, agno, agino); + bno = XFS_AGB_TO_DADDR(mp, agno, agbno); + if (flags & BULKSTAT_FG_QUICK) { + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + (clustidx << mp->m_sb.sb_inodelog)); + + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) + != XFS_DINODE_MAGIC + || !XFS_DINODE_GOOD_VERSION( + INT_GET(dip->di_core.di_version, ARCH_CONVERT))) + continue; + } + + /* + * Get the inode and fill in a single buffer. + * BULKSTAT_FG_QUICK uses dip to fill it in. + * BULKSTAT_FG_IGET uses igets. + * See: xfs_bulkstat_one & dm_bulkstat_one. + * This is also used to count inodes/blks, etc + * in xfs_qm_quotacheck. + */ + error = formatter(mp, tp, ino, ubufp, bno, dip, + &fmterror); + if (fmterror == BULKSTAT_RV_NOTHING) + continue; + if (fmterror == BULKSTAT_RV_GIVEUP) { + ubleft = 0; + ASSERT(error); + rval = error; + break; + } + if (ubufp) + ubufp += statstruct_size; + ubleft--; + lastino = ino; + } + } + + if (bp) + xfs_trans_brelse(tp, bp); + + /* + * Set up for the next loop iteration. + */ + if (ubleft > 0) { + if (end_of_ag) { + agno++; + agino = 0; + } else + agino = XFS_INO_TO_AGINO(mp, lastino); + } else + break; + } + /* + * Done, we're either out of filesystem or space to put the data. + */ + kmem_free(irbuf, NBPC); +#if defined(HAVE_USERACC) + if (ubuffer) + unuseracc(ubuffer, ubcount * statstruct_size, (B_READ|B_PHYS)); +#endif + *ubcountp = ubcount - ubleft; + if (agno >= mp->m_sb.sb_agcount) { + /* + * If we ran out of filesystem, mark lastino as off + * the end of the filesystem, so the next call + * will return immediately. + */ + *lastinop = (xfs_ino_t)XFS_AGINO_TO_INO(mp, agno, 0); + *done = 1; + } else + *lastinop = (xfs_ino_t)lastino; + + return rval; +} + +/* + * Return stat information in bulk (by-inode) for the filesystem. + * Special case for non-sequential one inode bulkstat. + */ +int /* error status */ +xfs_bulkstat_single( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t *lastinop, /* inode to return */ + xfs_caddr_t buffer, /* buffer with inode stats */ + int *done) /* 1 if there're more stats to get */ +{ + xfs_bstat_t bstat; /* one bulkstat result structure */ + int count; /* count value for bulkstat call */ + int error; /* return value */ + xfs_ino_t ino; /* filesystem inode number */ + int res; /* result from bs1 */ + + /* + * note that requesting valid inode numbers which are not allocated + * to inodes will most likely cause xfs_itobp to generate warning + * messages about bad magic numbers. This is ok. The fact that + * the inode isn't actually an inode is handled by the + * error check below. Done this way to make the usual case faster + * at the expense of the error case. + */ + + ino = (xfs_ino_t)*lastinop; + error = xfs_bulkstat_one(mp, NULL, ino, &bstat, 0, 0, &res); + if (error) { + /* + * Special case way failed, do it the "long" way + * to see if that works. + */ + (*lastinop)--; + count = 1; + if (xfs_bulkstat(mp, NULL, lastinop, &count, xfs_bulkstat_one, + sizeof(bstat), buffer, BULKSTAT_FG_IGET, done)) + return error; + if (count == 0 || (xfs_ino_t)*lastinop != ino) + return error == EFSCORRUPTED ? + XFS_ERROR(EINVAL) : error; + else + return 0; + } + *done = 0; + if (copy_to_user(buffer, &bstat, sizeof(bstat))) + return XFS_ERROR(EFAULT); + return 0; +} + +/* + * Return inode number table for the filesystem. + */ +int /* error status */ +xfs_inumbers( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t *lastino, /* last inode returned */ + int *count, /* size of buffer/count returned */ + xfs_caddr_t ubuffer) /* buffer with inode descriptions */ +{ + xfs_buf_t *agbp; + xfs_agino_t agino; + xfs_agnumber_t agno; + int bcount; + xfs_inogrp_t *buffer; + int bufidx; + xfs_btree_cur_t *cur; + int error; + __int32_t gcnt; + xfs_inofree_t gfree; + xfs_agino_t gino; + int i; + xfs_ino_t ino; + int left; + int tmp; + + ino = (xfs_ino_t)*lastino; + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + left = *count; + *count = 0; + bcount = MIN(left, (int)(NBPP / sizeof(*buffer))); + buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP); + error = bufidx = 0; + cur = NULL; + agbp = NULL; + while (left > 0 && agno < mp->m_sb.sb_agcount) { + if (agbp == NULL) { + down_read(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + up_read(&mp->m_peraglock); + if (error) { + /* + * If we can't read the AGI of this ag, + * then just skip to the next one. + */ + ASSERT(cur == NULL); + agbp = NULL; + agno++; + agino = 0; + continue; + } + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + error = xfs_inobt_lookup_ge(cur, agino, 0, 0, &tmp); + if (error) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + cur = NULL; + xfs_trans_brelse(tp, agbp); + agbp = NULL; + /* + * Move up the the last inode in the current + * chunk. The lookup_ge will always get + * us the first inode in the next chunk. + */ + agino += XFS_INODES_PER_CHUNK - 1; + continue; + } + } + if ((error = xfs_inobt_get_rec(cur, &gino, &gcnt, &gfree, + &i, ARCH_NOCONVERT)) || + i == 0) { + xfs_trans_brelse(tp, agbp); + agbp = NULL; + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + cur = NULL; + agno++; + agino = 0; + continue; + } + agino = gino + XFS_INODES_PER_CHUNK - 1; + buffer[bufidx].xi_startino = XFS_AGINO_TO_INO(mp, agno, gino); + buffer[bufidx].xi_alloccount = XFS_INODES_PER_CHUNK - gcnt; + buffer[bufidx].xi_allocmask = ~gfree; + bufidx++; + left--; + if (bufidx == bcount) { + if (copy_to_user(ubuffer, buffer, + bufidx * sizeof(*buffer))) { + error = XFS_ERROR(EFAULT); + break; + } + ubuffer += bufidx * sizeof(*buffer); + *count += bufidx; + bufidx = 0; + } + if (left) { + error = xfs_inobt_increment(cur, 0, &tmp); + if (error) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + cur = NULL; + xfs_trans_brelse(tp, agbp); + agbp = NULL; + /* + * The agino value has already been bumped. + * Just try to skip up to it. + */ + agino += XFS_INODES_PER_CHUNK; + continue; + } + } + } + if (!error) { + if (bufidx) { + if (copy_to_user(ubuffer, buffer, + bufidx * sizeof(*buffer))) + error = XFS_ERROR(EFAULT); + else + *count += bufidx; + } + *lastino = XFS_AGINO_TO_INO(mp, agno, agino); + } + kmem_free(buffer, bcount * sizeof(*buffer)); + if (cur) + xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : + XFS_BTREE_NOERROR)); + if (agbp) + xfs_trans_brelse(tp, agbp); + return error; +} diff -Nur linux-2.4.19/fs/xfs/xfs_itable.h linux-2.4.19-sgi211r3/fs/xfs/xfs_itable.h --- linux-2.4.19/fs/xfs/xfs_itable.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_itable.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ITABLE_H__ +#define __XFS_ITABLE_H__ + +/* + * xfs_bulkstat() is used to fill in xfs_bstat structures as well as dm_stat + * structures (by the dmi library). This is a pointer to a formatter function + * that will iget the inode and fill in the appropriate structure. + * see xfs_bulkstat_one() and dm_bulkstat_one() in dmi_xfs.c + */ +typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, + struct xfs_trans *tp, + xfs_ino_t ino, + void *buffer, + xfs_daddr_t bno, + void *dip, + int *stat); +/* + * Values for stat return value. + */ +#define BULKSTAT_RV_NOTHING 0 +#define BULKSTAT_RV_DIDONE 1 +#define BULKSTAT_RV_GIVEUP 2 + +/* + * Values for bulkstat flag argument. + */ +#define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */ +#define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */ +#define BULKSTAT_FG_VFSLOCKED 0x4 /* Already have vfs lock */ + +/* + * Return stat information in bulk (by-inode) for the filesystem. + */ +int /* error status */ +xfs_bulkstat( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t *lastino, /* last inode returned */ + int *count, /* size of buffer/count returned */ + bulkstat_one_pf formatter, /* func that'd fill a single buf */ + size_t statstruct_size,/* sizeof struct that we're filling */ + xfs_caddr_t ubuffer, /* buffer with inode stats */ + int flags, /* flag to control access method */ + int *done); /* 1 if there're more stats to get */ + +int +xfs_bulkstat_single( + xfs_mount_t *mp, + xfs_ino_t *lastinop, + xfs_caddr_t buffer, + int *done); + +int +xfs_bulkstat_one( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + void *buffer, + xfs_daddr_t bno, + void *dibuff, + int *stat); + +int /* error status */ +xfs_inumbers( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t *last, /* last inode returned */ + int *count, /* size of buffer/count returned */ + xfs_caddr_t buffer);/* buffer with inode descriptions */ + +#endif /* __XFS_ITABLE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_log.c linux-2.4.19-sgi211r3/fs/xfs/xfs_log.c --- linux-2.4.19/fs/xfs/xfs_log.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_log.c Fri Dec 13 10:22:56 2002 @@ -0,0 +1,3611 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * High level interface routines for log manager + */ + +#include + + +#define xlog_write_adv_cnt(ptr, len, off, bytes) \ + { (ptr) += (bytes); \ + (len) -= (bytes); \ + (off) += (bytes);} + +/* Local miscellaneous function prototypes */ +STATIC int xlog_bdstrat_cb(struct xfs_buf *); +STATIC int xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket, + xfs_lsn_t *); +STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, + dev_t log_dev, + xfs_daddr_t blk_offset, + int num_bblks); +STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes); +STATIC int xlog_sync(xlog_t *log, xlog_in_core_t *iclog); +STATIC void xlog_unalloc_log(xlog_t *log); +STATIC int xlog_write(xfs_mount_t *mp, xfs_log_iovec_t region[], + int nentries, xfs_log_ticket_t tic, + xfs_lsn_t *start_lsn, uint flags); + +/* local state machine functions */ +STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int); +STATIC void xlog_state_do_callback(xlog_t *log,int aborted, xlog_in_core_t *iclog); +static inline void xlog_state_finish_copy(xlog_t *log, + xlog_in_core_t *iclog, + int first_write, + int bytes); +STATIC int xlog_state_get_iclog_space(xlog_t *log, + int len, + xlog_in_core_t **iclog, + xlog_ticket_t *ticket, + int *continued_write, + int *logoffsetp); +STATIC int xlog_state_lsn_is_synced(xlog_t *log, + xfs_lsn_t lsn, + xfs_log_callback_t *cb, + int *abortflg); +STATIC void xlog_state_put_ticket(xlog_t *log, + xlog_ticket_t *tic); +STATIC int xlog_state_release_iclog(xlog_t *log, + xlog_in_core_t *iclog); +STATIC void xlog_state_switch_iclogs(xlog_t *log, + xlog_in_core_t *iclog, + int eventual_size); +STATIC int xlog_state_sync(xlog_t *log, xfs_lsn_t lsn, uint flags); +STATIC int xlog_state_sync_all(xlog_t *log, uint flags); +STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog); + +/* local functions to manipulate grant head */ +STATIC int xlog_grant_log_space(xlog_t *log, + xlog_ticket_t *xtic); +STATIC void xlog_grant_push_ail(xfs_mount_t *mp, + int need_bytes); +STATIC void xlog_regrant_reserve_log_space(xlog_t *log, + xlog_ticket_t *ticket); +STATIC int xlog_regrant_write_log_space(xlog_t *log, + xlog_ticket_t *ticket); +STATIC void xlog_ungrant_log_space(xlog_t *log, + xlog_ticket_t *ticket); + + +/* local ticket functions */ +STATIC void xlog_state_ticket_alloc(xlog_t *log); +STATIC xlog_ticket_t *xlog_ticket_get(xlog_t *log, + int unit_bytes, + int count, + char clientid, + uint flags); +STATIC void xlog_ticket_put(xlog_t *log, xlog_ticket_t *ticket); + +/* local debug functions */ +#if defined(DEBUG) && !defined(XLOG_NOLOG) +STATIC void xlog_verify_dest_ptr(xlog_t *log, __psint_t ptr); +#ifdef XFSDEBUG +STATIC void xlog_verify_disk_cycle_no(xlog_t *log, xlog_in_core_t *iclog); +#endif +STATIC void xlog_verify_grant_head(xlog_t *log, int equals); +STATIC void xlog_verify_iclog(xlog_t *log, xlog_in_core_t *iclog, + int count, boolean_t syncing); +STATIC void xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog, + xfs_lsn_t tail_lsn); +#else +#define xlog_verify_dest_ptr(a,b) +#define xlog_verify_disk_cycle_no(a,b) +#define xlog_verify_grant_head(a,b) +#define xlog_verify_iclog(a,b,c,d) +#define xlog_verify_tail_lsn(a,b,c) +#endif + +int xlog_iclogs_empty(xlog_t *log); + +#ifdef DEBUG +int xlog_do_error = 0; +int xlog_req_num = 0; +int xlog_error_mod = 33; +#endif + +#define XLOG_FORCED_SHUTDOWN(log) (log->l_flags & XLOG_IO_ERROR) + +/* + * 0 => disable log manager + * 1 => enable log manager + * 2 => enable log manager and log debugging + */ +#if defined(XLOG_NOLOG) || defined(DEBUG) +int xlog_debug = 1; +dev_t xlog_devt = 0; +#endif + +#if defined(XFS_LOG_TRACE) +void +xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string) +{ + if (! log->l_grant_trace) + log->l_grant_trace = ktrace_alloc(1024, KM_SLEEP); + + ktrace_enter(log->l_grant_trace, + (void *)tic, + (void *)log->l_reserve_headq, + (void *)log->l_write_headq, + (void *)((unsigned long)log->l_grant_reserve_cycle), + (void *)((unsigned long)log->l_grant_reserve_bytes), + (void *)((unsigned long)log->l_grant_write_cycle), + (void *)((unsigned long)log->l_grant_write_bytes), + (void *)((unsigned long)log->l_curr_cycle), + (void *)((unsigned long)log->l_curr_block), + (void *)((unsigned long)CYCLE_LSN(log->l_tail_lsn, ARCH_NOCONVERT)), + (void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn, ARCH_NOCONVERT)), + (void *)string, + (void *)((unsigned long)13), + (void *)((unsigned long)14), + (void *)((unsigned long)15), + (void *)((unsigned long)16)); +} + +void +xlog_trace_tic(xlog_t *log, xlog_ticket_t *tic) +{ + if (! log->l_trace) + log->l_trace = ktrace_alloc(256, KM_SLEEP); + + ktrace_enter(log->l_trace, + (void *)tic, + (void *)((unsigned long)tic->t_curr_res), + (void *)((unsigned long)tic->t_unit_res), + (void *)((unsigned long)tic->t_ocnt), + (void *)((unsigned long)tic->t_cnt), + (void *)((unsigned long)tic->t_flags), + (void *)((unsigned long)7), + (void *)((unsigned long)8), + (void *)((unsigned long)9), + (void *)((unsigned long)10), + (void *)((unsigned long)11), + (void *)((unsigned long)12), + (void *)((unsigned long)13), + (void *)((unsigned long)14), + (void *)((unsigned long)15), + (void *)((unsigned long)16)); +} + +void +xlog_trace_iclog(xlog_in_core_t *iclog, uint state) +{ + pid_t pid; + + pid = current_pid(); + + if (!iclog->ic_trace) + iclog->ic_trace = ktrace_alloc(256, KM_SLEEP); + ktrace_enter(iclog->ic_trace, + (void *)((unsigned long)state), + (void *)((unsigned long)pid), + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0); +} + +#else +#define xlog_trace_loggrant(log,tic,string) +#define xlog_trace_iclog(iclog,state) +#endif /* XFS_LOG_TRACE */ + +/* + * NOTES: + * + * 1. currblock field gets updated at startup and after in-core logs + * marked as with WANT_SYNC. + */ + +/* + * This routine is called when a user of a log manager ticket is done with + * the reservation. If the ticket was ever used, then a commit record for + * the associated transaction is written out as a log operation header with + * no data. The flag XLOG_TIC_INITED is set when the first write occurs with + * a given ticket. If the ticket was one with a permanent reservation, then + * a few operations are done differently. Permanent reservation tickets by + * default don't release the reservation. They just commit the current + * transaction with the belief that the reservation is still needed. A flag + * must be passed in before permanent reservations are actually released. + * When these type of tickets are not released, they need to be set into + * the inited state again. By doing this, a start record will be written + * out when the next write occurs. + */ +xfs_lsn_t +xfs_log_done(xfs_mount_t *mp, + xfs_log_ticket_t xtic, + uint flags) +{ + xlog_t *log = mp->m_log; + xlog_ticket_t *ticket = (xfs_log_ticket_t) xtic; + xfs_lsn_t lsn = 0; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + + if (XLOG_FORCED_SHUTDOWN(log) || + /* + * If nothing was ever written, don't write out commit record. + * If we get an error, just continue and give back the log ticket. + */ + (((ticket->t_flags & XLOG_TIC_INITED) == 0) && + (xlog_commit_record(mp, ticket, &lsn)))) { + lsn = (xfs_lsn_t) -1; + if (ticket->t_flags & XLOG_TIC_PERM_RESERV) { + flags |= XFS_LOG_REL_PERM_RESERV; + } + } + + + if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) == 0 || + (flags & XFS_LOG_REL_PERM_RESERV)) { + /* + * Release ticket if not permanent reservation or a specifc + * request has been made to release a permanent reservation. + */ + xlog_ungrant_log_space(log, ticket); + xlog_state_put_ticket(log, ticket); + } else { + xlog_regrant_reserve_log_space(log, ticket); + } + + /* If this ticket was a permanent reservation and we aren't + * trying to release it, reset the inited flags; so next time + * we write, a start record will be written out. + */ + if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) && + (flags & XFS_LOG_REL_PERM_RESERV) == 0) + ticket->t_flags |= XLOG_TIC_INITED; + + return lsn; +} /* xfs_log_done */ + + +/* + * Force the in-core log to disk. If flags == XFS_LOG_SYNC, + * the force is done synchronously. + * + * Asynchronous forces are implemented by setting the WANT_SYNC + * bit in the appropriate in-core log and then returning. + * + * Synchronous forces are implemented with a semaphore. All callers + * to force a given lsn to disk will wait on a semaphore attached to the + * specific in-core log. When given in-core log finally completes its + * write to disk, that thread will wake up all threads waiting on the + * semaphore. + */ +int +xfs_log_force(xfs_mount_t *mp, + xfs_lsn_t lsn, + uint flags) +{ + int rval; + xlog_t *log = mp->m_log; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + + ASSERT(flags & XFS_LOG_FORCE); + + XFS_STATS_INC(xfsstats.xs_log_force); + + if ((log->l_flags & XLOG_IO_ERROR) == 0) { + if (lsn == 0) + rval = xlog_state_sync_all(log, flags); + else + rval = xlog_state_sync(log, lsn, flags); + } else { + rval = XFS_ERROR(EIO); + } + + return rval; + +} /* xfs_log_force */ + + +/* + * This function will take a log sequence number and check to see if that + * lsn has been flushed to disk. If it has, then the callback function is + * called with the callback argument. If the relevant in-core log has not + * been synced to disk, we add the callback to the callback list of the + * in-core log. + */ +void +xfs_log_notify(xfs_mount_t *mp, /* mount of partition */ + xfs_lsn_t lsn, /* lsn looking for */ + xfs_log_callback_t *cb) +{ + xlog_t *log = mp->m_log; + int abortflg; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return; +#endif + cb->cb_next = 0; + if (xlog_state_lsn_is_synced(log, lsn, cb, &abortflg)) + cb->cb_func(cb->cb_arg, abortflg); +} /* xfs_log_notify */ + + +/* + * Initialize log manager data. This routine is intended to be called when + * a system boots up. It is not a per filesystem initialization. + * + * As you can see, we currently do nothing. + */ +int +xfs_log_init(void) +{ + return( 0 ); +} + + +/* + * 1. Reserve an amount of on-disk log space and return a ticket corresponding + * to the reservation. + * 2. Potentially, push buffers at tail of log to disk. + * + * Each reservation is going to reserve extra space for a log record header. + * When writes happen to the on-disk log, we don't subtract the length of the + * log record header from any reservation. By wasting space in each + * reservation, we prevent over allocation problems. + */ +int +xfs_log_reserve(xfs_mount_t *mp, + int unit_bytes, + int cnt, + xfs_log_ticket_t *ticket, + __uint8_t client, + uint flags) +{ + xlog_t *log = mp->m_log; + xlog_ticket_t *internal_ticket; + int retval; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + retval = 0; + ASSERT(client == XFS_TRANSACTION || client == XFS_LOG); + ASSERT((flags & XFS_LOG_NOSLEEP) == 0); + + if (XLOG_FORCED_SHUTDOWN(log)) + return XFS_ERROR(EIO); + + XFS_STATS_INC(xfsstats.xs_try_logspace); + + if (*ticket != NULL) { + ASSERT(flags & XFS_LOG_PERM_RESERV); + internal_ticket = (xlog_ticket_t *)*ticket; + xlog_grant_push_ail(mp, internal_ticket->t_unit_res); + retval = xlog_regrant_write_log_space(log, internal_ticket); + } else { + /* may sleep if need to allocate more tickets */ + internal_ticket = xlog_ticket_get(log, unit_bytes, cnt, + client, flags); + *ticket = internal_ticket; + xlog_grant_push_ail(mp, + (internal_ticket->t_unit_res * + internal_ticket->t_cnt)); + retval = xlog_grant_log_space(log, internal_ticket); + } + + return retval; +} /* xfs_log_reserve */ + + +/* + * Mount a log filesystem + * + * mp - ubiquitous xfs mount point structure + * log_dev - device number of on-disk log device + * blk_offset - Start block # where block size is 512 bytes (BBSIZE) + * num_bblocks - Number of BBSIZE blocks in on-disk log + * + * Return error or zero. + */ +int +xfs_log_mount(xfs_mount_t *mp, + dev_t log_dev, + xfs_daddr_t blk_offset, + int num_bblks) +{ + xlog_t *log; + + if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) + cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname); + else { + cmn_err(CE_NOTE, + "!Mounting filesystem \"%s\" in no-recovery mode. Filesystem will be inconsistent.", + mp->m_fsname); + ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); + } + + mp->m_log = log = xlog_alloc_log(mp, log_dev, blk_offset, num_bblks); + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug) { + cmn_err(CE_NOTE, "log dev: 0x%x", log_dev); + return 0; + } +#endif + /* + * skip log recovery on a norecovery mount. pretend it all + * just worked. + */ + if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { + int error; + vfs_t *vfsp = XFS_MTOVFS(mp); + int readonly = (vfsp->vfs_flag & VFS_RDONLY); + + if (readonly) + vfsp->vfs_flag &= ~VFS_RDONLY; + + error = xlog_recover(log, readonly); + + if (readonly) + vfsp->vfs_flag |= VFS_RDONLY; + if (error) { + cmn_err(CE_WARN, "XFS: log mount/recovery failed"); + xlog_unalloc_log(log); + return error; + } + } + + /* Normal transactions can now occur */ + log->l_flags &= ~XLOG_ACTIVE_RECOVERY; + + /* End mounting message in xfs_log_mount_finish */ + return 0; +} /* xfs_log_mount */ + +/* + * Finish the recovery of the file system. This is separate from + * the xfs_log_mount() call, because it depends on the code in + * xfs_mountfs() to read in the root and real-time bitmap inodes + * between calling xfs_log_mount() and here. + * + * mp - ubiquitous xfs mount point structure + */ +int +xfs_log_mount_finish(xfs_mount_t *mp, int mfsi_flags) +{ + int error; + + if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) + error = xlog_recover_finish(mp->m_log, mfsi_flags); + else { + error = 0; + ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); + } + + return error; +} + +/* + * Unmount processing for the log. + */ +int +xfs_log_unmount(xfs_mount_t *mp) +{ + int error; + + error = xfs_log_unmount_write(mp); + xfs_log_unmount_dealloc(mp); + return (error); +} + +/* + * Final log writes as part of unmount. + * + * Mark the filesystem clean as unmount happens. Note that during relocation + * this routine needs to be executed as part of source-bag while the + * deallocation must not be done until source-end. + */ + +/* + * Unmount record used to have a string "Unmount filesystem--" in the + * data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE). + * We just write the magic number now since that particular field isn't + * currently architecture converted and "nUmount" is a bit foo. + * As far as I know, there weren't any dependencies on the old behaviour. + */ + +int +xfs_log_unmount_write(xfs_mount_t *mp) +{ + xlog_t *log = mp->m_log; + xlog_in_core_t *iclog; +#ifdef DEBUG + xlog_in_core_t *first_iclog; +#endif + xfs_log_iovec_t reg[1]; + xfs_log_ticket_t tic = 0; + xfs_lsn_t lsn; + int error; + SPLDECL(s); + + /* the data section must be 32 bit size aligned */ + struct { + __uint16_t magic; + __uint16_t pad1; + __uint32_t pad2; /* may as well make it 64 bits */ + } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + + /* + * Don't write out unmount record on read-only mounts. + * Or, if we are doing a forced umount (typically because of IO errors). + */ + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + return 0; + + xfs_log_force(mp, 0, XFS_LOG_FORCE|XFS_LOG_SYNC); + +#ifdef DEBUG + first_iclog = iclog = log->l_iclog; + do { + if (!(iclog->ic_state & XLOG_STATE_IOERROR)) { + ASSERT(iclog->ic_state & XLOG_STATE_ACTIVE); + ASSERT(iclog->ic_offset == 0); + } + iclog = iclog->ic_next; + } while (iclog != first_iclog); +#endif + if (! (XLOG_FORCED_SHUTDOWN(log))) { + reg[0].i_addr = (void*)&magic; + reg[0].i_len = sizeof(magic); + + error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0); + if (!error) { + /* remove inited flag */ + ((xlog_ticket_t *)tic)->t_flags = 0; + error = xlog_write(mp, reg, 1, tic, &lsn, + XLOG_UNMOUNT_TRANS); + /* + * At this point, we're umounting anyway, + * so there's no point in transitioning log state + * to IOERROR. Just continue... + */ + } + + if (error) { + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_log_unmount: unmount record failed"); + } + + + s = LOG_LOCK(log); + iclog = log->l_iclog; + iclog->ic_refcnt++; + LOG_UNLOCK(log, s); + xlog_state_want_sync(log, iclog); + (void) xlog_state_release_iclog(log, iclog); + + s = LOG_LOCK(log); + if (!(iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_DIRTY)) { + if (!XLOG_FORCED_SHUTDOWN(log)) { + sv_wait(&iclog->ic_forcesema, PMEM, + &log->l_icloglock, s); + } else { + LOG_UNLOCK(log, s); + } + } else { + LOG_UNLOCK(log, s); + } + if (tic) + xlog_state_put_ticket(log, tic); + } else { + /* + * We're already in forced_shutdown mode, couldn't + * even attempt to write out the unmount transaction. + * + * Go through the motions of sync'ing and releasing + * the iclog, even though no I/O will actually happen, + * we need to wait for other log I/O's that may already + * be in progress. Do this as a separate section of + * code so we'll know if we ever get stuck here that + * we're in this odd situation of trying to unmount + * a file system that went into forced_shutdown as + * the result of an unmount.. + */ + s = LOG_LOCK(log); + iclog = log->l_iclog; + iclog->ic_refcnt++; + LOG_UNLOCK(log, s); + + xlog_state_want_sync(log, iclog); + (void) xlog_state_release_iclog(log, iclog); + + s = LOG_LOCK(log); + + if ( ! ( iclog->ic_state == XLOG_STATE_ACTIVE + || iclog->ic_state == XLOG_STATE_DIRTY + || iclog->ic_state == XLOG_STATE_IOERROR) ) { + + sv_wait(&iclog->ic_forcesema, PMEM, + &log->l_icloglock, s); + } else { + LOG_UNLOCK(log, s); + } + } + + return 0; +} /* xfs_log_unmount_write */ + +/* + * Deallocate log structures for unmount/relocation. + */ +void +xfs_log_unmount_dealloc(xfs_mount_t *mp) +{ + xlog_unalloc_log(mp->m_log); +} + +/* + * Write region vectors to log. The write happens using the space reservation + * of the ticket (tic). It is not a requirement that all writes for a given + * transaction occur with one call to xfs_log_write(). + */ +int +xfs_log_write(xfs_mount_t * mp, + xfs_log_iovec_t reg[], + int nentries, + xfs_log_ticket_t tic, + xfs_lsn_t *start_lsn) +{ + int error; + xlog_t *log = mp->m_log; +#if defined(DEBUG) || defined(XLOG_NOLOG) + + if (! xlog_debug && xlog_devt == log->l_dev) { + *start_lsn = 0; + return 0; + } +#endif + if (XLOG_FORCED_SHUTDOWN(log)) + return XFS_ERROR(EIO); + + if ((error = xlog_write(mp, reg, nentries, tic, start_lsn, 0))) { + xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); + } + return (error); +} /* xfs_log_write */ + + +void +xfs_log_move_tail(xfs_mount_t *mp, + xfs_lsn_t tail_lsn) +{ + xlog_ticket_t *tic; + xlog_t *log = mp->m_log; + int need_bytes, free_bytes, cycle, bytes; + SPLDECL(s); + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (!xlog_debug && xlog_devt == log->l_dev) + return; +#endif + /* XXXsup tmp */ + if (XLOG_FORCED_SHUTDOWN(log)) + return; + ASSERT(!XFS_FORCED_SHUTDOWN(mp)); + + if (tail_lsn == 0) { + /* needed since sync_lsn is 64 bits */ + s = LOG_LOCK(log); + tail_lsn = log->l_last_sync_lsn; + LOG_UNLOCK(log, s); + } + + s = GRANT_LOCK(log); + + /* Also an illegal lsn. 1 implies that we aren't passing in a legal + * tail_lsn. + */ + if (tail_lsn != 1) + log->l_tail_lsn = tail_lsn; + + if ((tic = log->l_write_headq)) { +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("Recovery problem"); +#endif + cycle = log->l_grant_write_cycle; + bytes = log->l_grant_write_bytes; + free_bytes = xlog_space_left(log, cycle, bytes); + do { + ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV); + + if (free_bytes < tic->t_unit_res) + break; + free_bytes -= tic->t_unit_res; + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_write_headq); + } + if ((tic = log->l_reserve_headq)) { +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("Recovery problem"); +#endif + cycle = log->l_grant_reserve_cycle; + bytes = log->l_grant_reserve_bytes; + free_bytes = xlog_space_left(log, cycle, bytes); + do { + if (tic->t_flags & XLOG_TIC_PERM_RESERV) + need_bytes = tic->t_unit_res*tic->t_cnt; + else + need_bytes = tic->t_unit_res; + if (free_bytes < need_bytes) + break; + free_bytes -= need_bytes; + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_reserve_headq); + } + GRANT_UNLOCK(log, s); +} /* xfs_log_move_tail */ + +/* + * Determine if we have a transaction that has gone to disk + * that needs to be covered. Log activity needs to be idle (no AIL and + * nothing in the iclogs). And, we need to be in the right state indicating + * something has gone out. + */ +int +xfs_log_need_covered(xfs_mount_t *mp) +{ + SPLDECL(s); + int needed = 0, gen; + xlog_t *log = mp->m_log; + + if (mp->m_frozen || XFS_FORCED_SHUTDOWN(mp)) + return 0; + + s = LOG_LOCK(log); + if (((log->l_covered_state == XLOG_STATE_COVER_NEED) || + (log->l_covered_state == XLOG_STATE_COVER_NEED2)) + && !xfs_trans_first_ail(mp, &gen) + && xlog_iclogs_empty(log)) { + if (log->l_covered_state == XLOG_STATE_COVER_NEED) + log->l_covered_state = XLOG_STATE_COVER_DONE; + else { + ASSERT(log->l_covered_state == XLOG_STATE_COVER_NEED2); + log->l_covered_state = XLOG_STATE_COVER_DONE2; + } + needed = 1; + } + LOG_UNLOCK(log, s); + return(needed); +} + +/****************************************************************************** + * + * local routines + * + ****************************************************************************** + */ + +/* xfs_trans_tail_ail returns 0 when there is nothing in the list. + * The log manager must keep track of the last LR which was committed + * to disk. The lsn of this LR will become the new tail_lsn whenever + * xfs_trans_tail_ail returns 0. If we don't do this, we run into + * the situation where stuff could be written into the log but nothing + * was ever in the AIL when asked. Eventually, we panic since the + * tail hits the head. + * + * We may be holding the log iclog lock upon entering this routine. + */ +xfs_lsn_t +xlog_assign_tail_lsn(xfs_mount_t *mp, xlog_in_core_t *iclog) +{ + xfs_lsn_t tail_lsn; + SPLDECL(s); + xlog_t *log = mp->m_log; + + tail_lsn = xfs_trans_tail_ail(mp); + s = GRANT_LOCK(log); + if (tail_lsn != 0) + log->l_tail_lsn = tail_lsn; + else + tail_lsn = log->l_tail_lsn = log->l_last_sync_lsn; + if (iclog) + INT_SET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT, tail_lsn); + GRANT_UNLOCK(log, s); + + return tail_lsn; +} /* xlog_assign_tail_lsn */ + + +/* + * Return the space in the log between the tail and the head. The head + * is passed in the cycle/bytes formal parms. In the special case where + * the reserve head has wrapped passed the tail, this calculation is no + * longer valid. In this case, just return 0 which means there is no space + * in the log. This works for all places where this function is called + * with the reserve head. Of course, if the write head were to ever + * wrap the tail, we should blow up. Rather than catch this case here, + * we depend on other ASSERTions in other parts of the code. XXXmiken + * + * This code also handles the case where the reservation head is behind + * the tail. The details of this case are described below, but the end + * result is that we return the size of the log as the amount of space left. + */ +int +xlog_space_left(xlog_t *log, int cycle, int bytes) +{ + int free_bytes; + int tail_bytes; + int tail_cycle; + + tail_bytes = BBTOB(BLOCK_LSN(log->l_tail_lsn, ARCH_NOCONVERT)); + tail_cycle = CYCLE_LSN(log->l_tail_lsn, ARCH_NOCONVERT); + if ((tail_cycle == cycle) && (bytes >= tail_bytes)) { + free_bytes = log->l_logsize - (bytes - tail_bytes); + } else if ((tail_cycle + 1) < cycle) { + return 0; + } else if (tail_cycle < cycle) { + ASSERT(tail_cycle == (cycle - 1)); + free_bytes = tail_bytes - bytes; + } else { + /* + * The reservation head is behind the tail. + * This can only happen when the AIL is empty so the tail + * is equal to the head and the l_roundoff value in the + * log structure is taking up the difference between the + * reservation head and the tail. The bytes accounted for + * by the l_roundoff field are temporarily 'lost' to the + * reservation mechanism, but they are cleaned up when the + * log buffers that created them are reused. These lost + * bytes are what allow the reservation head to fall behind + * the tail in the case that the log is 'empty'. + * In this case we just want to return the size of the + * log as the amount of space left. + */ +/* This assert does not take into account padding from striped log writes * + ASSERT((tail_cycle == (cycle + 1)) || + ((bytes + log->l_roundoff) >= tail_bytes)); +*/ + free_bytes = log->l_logsize; + } + return free_bytes; +} /* xlog_space_left */ + + +/* + * Log function which is called when an io completes. + * + * The log manager needs its own routine, in order to control what + * happens with the buffer after the write completes. + */ +void +xlog_iodone(xfs_buf_t *bp) +{ + xlog_in_core_t *iclog; + int aborted; + + iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *); + ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == (unsigned long) 2); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); + aborted = 0; + + /* + * Race to shutdown the filesystem if we see an error. + */ + if (XFS_BUF_GETERROR(bp)) { + /* Some versions of cpp barf on the recursive definition of + * ic_log -> hic_fields.ic_log and expand ic_log twice when + * it is passed through two macros. Workaround for broken cpp + */ + struct log *l; + xfs_ioerror_alert("xlog_iodone", + iclog->ic_log->l_mp, bp, XFS_BUF_ADDR(bp)); + XFS_BUF_STALE(bp); + l = iclog->ic_log; + xfs_force_shutdown(l->l_mp, XFS_LOG_IO_ERROR); + /* + * This flag will be propagated to the trans-committed + * callback routines to let them know that the log-commit + * didn't succeed. + */ + aborted = XFS_LI_ABORTED; + } else if (iclog->ic_state & XLOG_STATE_IOERROR) { + aborted = XFS_LI_ABORTED; + } + xlog_state_done_syncing(iclog, aborted); + if (!(XFS_BUF_ISASYNC(bp))) { + /* + * Corresponding psema() will be done in bwrite(). If we don't + * vsema() here, panic. + */ + XFS_BUF_V_IODONESEMA(bp); + } +} /* xlog_iodone */ + +/* + * The bdstrat callback function for log bufs. This gives us a central + * place to trap bufs in case we get hit by a log I/O error and need to + * shutdown. Actually, in practice, even when we didn't get a log error, + * we transition the iclogs to IOERROR state *after* flushing all existing + * iclogs to disk. This is because we don't want anymore new transactions to be + * started or completed afterwards. + */ +STATIC int +xlog_bdstrat_cb(struct xfs_buf *bp) +{ + xlog_in_core_t *iclog; + + iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *); + + if ((iclog->ic_state & XLOG_STATE_IOERROR) == 0) { + /* note for irix bstrat will need struct bdevsw passed + * Fix the following macro if the code ever is merged + */ + XFS_bdstrat(bp); + return 0; + } + + xfs_buftrace("XLOG__BDSTRAT IOERROR", bp); + XFS_BUF_ERROR(bp, EIO); + XFS_BUF_STALE(bp); + xfs_biodone(bp); + return (XFS_ERROR(EIO)); + + +} + +/* + * Return size of each in-core log record buffer. + * + * Low memory machines only get 2 16KB buffers. We don't want to waste + * memory here. However, all other machines get at least 2 32KB buffers. + * The number is hard coded because we don't care about the minimum + * memory size, just 32MB systems. + * + * If the filesystem blocksize is too large, we may need to choose a + * larger size since the directory code currently logs entire blocks. + * XXXmiken XXXcurtis + */ + +STATIC void +xlog_get_iclog_buffer_size(xfs_mount_t *mp, + xlog_t *log) +{ + int size; + int xhdrs; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + /* + * When logbufs == 0, someone has disabled the log from the FSTAB + * file. This is not a documented feature. We need to set xlog_debug + * to zero (this deactivates the log) and set xlog_devt to the + * appropriate dev_t. Only one filesystem may be affected as such + * since this is just a performance hack to test what we might be able + * to get if the log were not present. + */ + if (mp->m_logbufs == 0) { + xlog_debug = 0; + xlog_devt = log->l_dev; + log->l_iclog_bufs = XLOG_NUM_ICLOGS; + } else +#endif + { + /* + * This is the normal path. If m_logbufs == -1, then the + * admin has chosen to use the system defaults for logbuffers. + */ + if (mp->m_logbufs == -1) + log->l_iclog_bufs = XLOG_NUM_ICLOGS; + else + log->l_iclog_bufs = mp->m_logbufs; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + /* We are reactivating a filesystem after it was active */ + if (log->l_dev == xlog_devt) { + xlog_devt = 1; + xlog_debug = 1; + } +#endif + } + + /* + * Buffer size passed in from mount system call. + */ + if (mp->m_logbsize != -1) { + size = log->l_iclog_size = mp->m_logbsize; + log->l_iclog_size_log = 0; + while (size != 1) { + log->l_iclog_size_log++; + size >>= 1; + } + + if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb)) { + /* # headers = size / 32K + * one header holds cycles from 32K of data + */ + + xhdrs = mp->m_logbsize / XLOG_HEADER_CYCLE_SIZE; + if (mp->m_logbsize % XLOG_HEADER_CYCLE_SIZE) + xhdrs++; + log->l_iclog_hsize = xhdrs << BBSHIFT; + log->l_iclog_heads = xhdrs; + } else { + ASSERT(mp->m_logbsize <= XLOG_BIG_RECORD_BSIZE); + log->l_iclog_hsize = BBSIZE; + log->l_iclog_heads = 1; + } + return; + } + + /* + * Special case machines that have less than 32MB of memory. + * All machines with more memory use 32KB buffers. + */ + if (xfs_physmem <= btoc(32*1024*1024)) { + /* Don't change; min configuration */ + log->l_iclog_size = XLOG_RECORD_BSIZE; /* 16k */ + log->l_iclog_size_log = XLOG_RECORD_BSHIFT; + } else { + log->l_iclog_size = XLOG_BIG_RECORD_BSIZE; /* 32k */ + log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT; + } + + /* the default log size is 16k or 32k which is one header sector */ + log->l_iclog_hsize = BBSIZE; + log->l_iclog_heads = 1; + + /* + * For 16KB, we use 3 32KB buffers. For 32KB block sizes, we use + * 4 32KB buffers. For 64KB block sizes, we use 8 32KB buffers. + */ + if (mp->m_sb.sb_blocksize >= 16*1024) { + log->l_iclog_size = XLOG_BIG_RECORD_BSIZE; + log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT; + if (mp->m_logbufs == -1) { + switch (mp->m_sb.sb_blocksize) { + case 16*1024: /* 16 KB */ + log->l_iclog_bufs = 3; + break; + case 32*1024: /* 32 KB */ + log->l_iclog_bufs = 4; + break; + case 64*1024: /* 64 KB */ + log->l_iclog_bufs = 8; + break; + default: + xlog_panic("XFS: Illegal blocksize"); + break; + } + } + } +} /* xlog_get_iclog_buffer_size */ + + +/* + * This routine initializes some of the log structure for a given mount point. + * Its primary purpose is to fill in enough, so recovery can occur. However, + * some other stuff may be filled in too. + */ +STATIC xlog_t * +xlog_alloc_log(xfs_mount_t *mp, + dev_t log_dev, + xfs_daddr_t blk_offset, + int num_bblks) +{ + xlog_t *log; + xlog_rec_header_t *head; + xlog_in_core_t **iclogp; + xlog_in_core_t *iclog, *prev_iclog=NULL; + xfs_buf_t *bp; + int i; + int iclogsize; + + log = (void *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP); + + log->l_mp = mp; + log->l_dev = log_dev; + log->l_logsize = BBTOB(num_bblks); + log->l_logBBstart = blk_offset; + log->l_logBBsize = num_bblks; + log->l_roundoff = 0; + log->l_covered_state = XLOG_STATE_COVER_IDLE; + log->l_flags |= XLOG_ACTIVE_RECOVERY; + + log->l_prev_block = -1; + ASSIGN_ANY_LSN(log->l_tail_lsn, 1, 0, ARCH_NOCONVERT); + /* log->l_tail_lsn = 0x100000000LL; cycle = 1; current block = 0 */ + log->l_last_sync_lsn = log->l_tail_lsn; + log->l_curr_cycle = 1; /* 0 is bad since this is initial value */ + log->l_curr_block = 0; /* filled in by xlog_recover */ + log->l_grant_reserve_bytes = 0; + log->l_grant_reserve_cycle = 1; + log->l_grant_write_bytes = 0; + log->l_grant_write_cycle = 1; + log->l_quotaoffs_flag = 0; /* XFS_LI_QUOTAOFF logitems */ + + xlog_get_iclog_buffer_size(mp, log); + + bp = log->l_xbuf = XFS_getrbuf(0,mp); /* get my locked buffer */ /* mp needed for pagebuf/linux only */ + + XFS_BUF_SET_TARGET(bp, mp->m_logdev_targp); + XFS_BUF_SET_SIZE(bp, log->l_iclog_size); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); + ASSERT(XFS_BUF_ISBUSY(log->l_xbuf)); + ASSERT(XFS_BUF_VALUSEMA(log->l_xbuf) <= 0); + spinlock_init(&log->l_icloglock, "iclog"); + spinlock_init(&log->l_grant_lock, "grhead_iclog"); + initnsema(&log->l_flushsema, 0, "ic-flush"); + xlog_state_ticket_alloc(log); /* wait until after icloglock inited */ + + /* log record size must be multiple of BBSIZE; see xlog_rec_header_t */ + ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0); + + iclogp = &log->l_iclog; + /* + * The amount of memory to allocate for the iclog structure is + * rather funky due to the way the structure is defined. It is + * done this way so that we can use different sizes for machines + * with different amounts of memory. See the definition of + * xlog_in_core_t in xfs_log_priv.h for details. + */ + iclogsize = log->l_iclog_size; + ASSERT(log->l_iclog_size >= 4096); + for (i=0; i < log->l_iclog_bufs; i++) { + *iclogp = (xlog_in_core_t *) + kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP); + iclog = *iclogp; + iclog->hic_data = (xlog_in_core_2_t *) + kmem_alloc(iclogsize, KM_SLEEP); + + iclog->ic_prev = prev_iclog; + prev_iclog = iclog; + log->l_iclog_bak[i] = (xfs_caddr_t)&(iclog->ic_header); + + head = &iclog->ic_header; + memset(head, 0, sizeof(xlog_rec_header_t)); + INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(head->h_version, ARCH_CONVERT, + XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); + INT_SET(head->h_size, ARCH_CONVERT, log->l_iclog_size); + /* new fields */ + INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT); + memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t)); + + bp = iclog->ic_bp = XFS_getrbuf(0,mp); /* my locked buffer */ /* mp need for pagebuf/linux only */ + XFS_BUF_SET_TARGET(bp, mp->m_logdev_targp); + XFS_BUF_SET_SIZE(bp, log->l_iclog_size); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); + + iclog->ic_size = XFS_BUF_SIZE(bp) - log->l_iclog_hsize; + iclog->ic_state = XLOG_STATE_ACTIVE; + iclog->ic_log = log; + iclog->ic_callback_tail = &(iclog->ic_callback); + iclog->ic_datap = (char *)iclog->hic_data + log->l_iclog_hsize; + + ASSERT(XFS_BUF_ISBUSY(iclog->ic_bp)); + ASSERT(XFS_BUF_VALUSEMA(iclog->ic_bp) <= 0); + sv_init(&iclog->ic_forcesema, SV_DEFAULT, "iclog-force"); + sv_init(&iclog->ic_writesema, SV_DEFAULT, "iclog-write"); + + iclogp = &iclog->ic_next; + } + *iclogp = log->l_iclog; /* complete ring */ + log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */ + + return log; +} /* xlog_alloc_log */ + + +/* + * Write out the commit record of a transaction associated with the given + * ticket. Return the lsn of the commit record. + */ +STATIC int +xlog_commit_record(xfs_mount_t *mp, + xlog_ticket_t *ticket, + xfs_lsn_t *commitlsnp) +{ + int error; + xfs_log_iovec_t reg[1]; + + reg[0].i_addr = 0; + reg[0].i_len = 0; + + if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp, + XLOG_COMMIT_TRANS))) { + xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); + } + return (error); +} /* xlog_commit_record */ + + +/* + * Push on the buffer cache code if we ever use more than 75% of the on-disk + * log space. This code pushes on the lsn which would supposedly free up + * the 25% which we want to leave free. We may need to adopt a policy which + * pushes on an lsn which is further along in the log once we reach the high + * water mark. In this manner, we would be creating a low water mark. + */ +void +xlog_grant_push_ail(xfs_mount_t *mp, + int need_bytes) +{ + xlog_t *log = mp->m_log; /* pointer to the log */ + xfs_lsn_t tail_lsn; /* lsn of the log tail */ + xfs_lsn_t threshold_lsn = 0; /* lsn we'd like to be at */ + int free_blocks; /* free blocks left to write to */ + int free_bytes; /* free bytes left to write to */ + int threshold_block; /* block in lsn we'd like to be at */ + int threshold_cycle; /* lsn cycle we'd like to be at */ + int free_threshold; + SPLDECL(s); + + ASSERT(BTOBB(need_bytes) < log->l_logBBsize); + + s = GRANT_LOCK(log); + free_bytes = xlog_space_left(log, + log->l_grant_reserve_cycle, + log->l_grant_reserve_bytes); + tail_lsn = log->l_tail_lsn; + free_blocks = BTOBBT(free_bytes); + + /* + * Set the threshold for the minimum number of free blocks in the + * log to the maximum of what the caller needs, one quarter of the + * log, and 256 blocks. + */ + free_threshold = BTOBB(need_bytes); + free_threshold = MAX(free_threshold, (log->l_logBBsize >> 2)); + free_threshold = MAX(free_threshold, 256); + if (free_blocks < free_threshold) { + threshold_block = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) + free_threshold; + threshold_cycle = CYCLE_LSN(tail_lsn, ARCH_NOCONVERT); + if (threshold_block >= log->l_logBBsize) { + threshold_block -= log->l_logBBsize; + threshold_cycle += 1; + } + ASSIGN_ANY_LSN(threshold_lsn, threshold_cycle, + threshold_block, ARCH_NOCONVERT); + + /* Don't pass in an lsn greater than the lsn of the last + * log record known to be on disk. + */ + if (XFS_LSN_CMP_ARCH(threshold_lsn, log->l_last_sync_lsn, ARCH_NOCONVERT) > 0) + threshold_lsn = log->l_last_sync_lsn; + } + GRANT_UNLOCK(log, s); + + /* + * Get the transaction layer to kick the dirty buffers out to + * disk asynchronously. No point in trying to do this if + * the filesystem is shutting down. + */ + if (threshold_lsn && + !XLOG_FORCED_SHUTDOWN(log)) + xfs_trans_push_ail(mp, threshold_lsn); +} /* xlog_grant_push_ail */ + + +/* + * Flush out the in-core log (iclog) to the on-disk log in a synchronous or + * asynchronous fashion. Previously, we should have moved the current iclog + * ptr in the log to point to the next available iclog. This allows further + * write to continue while this code syncs out an iclog ready to go. + * Before an in-core log can be written out, the data section must be scanned + * to save away the 1st word of each BBSIZE block into the header. We replace + * it with the current cycle count. Each BBSIZE block is tagged with the + * cycle count because there in an implicit assumption that drives will + * guarantee that entire 512 byte blocks get written at once. In other words, + * we can't have part of a 512 byte block written and part not written. By + * tagging each block, we will know which blocks are valid when recovering + * after an unclean shutdown. + * + * This routine is single threaded on the iclog. No other thread can be in + * this routine with the same iclog. Changing contents of iclog can there- + * fore be done without grabbing the state machine lock. Updating the global + * log will require grabbing the lock though. + * + * The entire log manager uses a logical block numbering scheme. Only + * log_sync (and then only bwrite()) know about the fact that the log may + * not start with block zero on a given device. The log block start offset + * is added immediately before calling bwrite(). + */ + +int +xlog_sync(xlog_t *log, + xlog_in_core_t *iclog) +{ + xfs_caddr_t dptr; /* pointer to byte sized element */ + xfs_buf_t *bp; + int i; + uint roundup; + uint count; /* byte count of bwrite */ + int split = 0; /* split write into two regions */ + int error; + + XFS_STATS_INC(xfsstats.xs_log_writes); + ASSERT(iclog->ic_refcnt == 0); + + /* Round out the log write size */ + if (iclog->ic_offset & BBMASK) { + /* count of 0 is already accounted for up in + * xlog_state_sync_all(). Once in this routine, + * operations on the iclog are single threaded. + * + * Difference between rounded up size and size + */ + count = iclog->ic_offset & BBMASK; + iclog->ic_roundoff += BBSIZE - count; + } + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + unsigned sunit = BTOBB(log->l_mp->m_sb.sb_logsunit); + if (!sunit) + sunit = 1; + + count = BTOBB(log->l_iclog_hsize + iclog->ic_offset); + if (count & (sunit - 1)) { + roundup = sunit - (count & (sunit - 1)); + } else { + roundup = 0; + } + iclog->ic_offset += BBTOB(roundup); + } + + log->l_roundoff += iclog->ic_roundoff; + + xlog_pack_data(log, iclog); /* put cycle number in every block */ + INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset); /* real byte length */ + + bp = iclog->ic_bp; + ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == (unsigned long)1); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)2); + XFS_BUF_SET_ADDR(bp, BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT)); + + /* Count is already rounded up to a BBSIZE above */ + count = iclog->ic_offset + iclog->ic_roundoff; + ASSERT((count & BBMASK) == 0); + + /* Add for LR header */ + count += log->l_iclog_hsize; + XFS_STATS_ADD(xfsstats.xs_log_blocks, BTOBB(count)); + + /* Do we need to split this write into 2 parts? */ + if (XFS_BUF_ADDR(bp) + BTOBB(count) > log->l_logBBsize) { + split = count - (BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp))); + count = BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp)); + iclog->ic_bwritecnt = 2; /* split into 2 writes */ + } else { + iclog->ic_bwritecnt = 1; + } + XFS_BUF_SET_PTR(bp, (xfs_caddr_t) &(iclog->ic_header), count); + XFS_BUF_SET_FSPRIVATE(bp, iclog); /* save for later */ + XFS_BUF_BUSY(bp); + XFS_BUF_ASYNC(bp); + /* + * Do a disk write cache flush for the log block. + * This is a bit of a sledgehammer, it would be better + * to use a tag barrier here that just prevents reordering. + * It may not be needed to flush the first split block in the log wrap + * case, but do it anyways to be safe -AK + */ + if (!(log->l_mp->m_flags & XFS_MOUNT_NOLOGFLUSH)) + XFS_BUF_FLUSH(bp); + + ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1); + ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize); + + xlog_verify_iclog(log, iclog, count, B_TRUE); + + /* account for log which doesn't start at block #0 */ + XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); + /* + * Don't call xfs_bwrite here. We do log-syncs even when the filesystem + * is shutting down. + */ + XFS_BUF_WRITE(bp); + + if ((error = XFS_bwrite(bp))) { + xfs_ioerror_alert("xlog_sync", log->l_mp, bp, + XFS_BUF_ADDR(bp)); + return (error); + } + if (split) { + bp = iclog->ic_log->l_xbuf; + ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == + (unsigned long)1); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)2); + XFS_BUF_SET_ADDR(bp, 0); /* logical 0 */ + XFS_BUF_SET_PTR(bp, (xfs_caddr_t)((__psint_t)&(iclog->ic_header)+ + (__psint_t)count), split); + XFS_BUF_SET_FSPRIVATE(bp, iclog); + XFS_BUF_BUSY(bp); + XFS_BUF_ASYNC(bp); + if (!(log->l_mp->m_flags & XFS_MOUNT_NOLOGFLUSH)) + XFS_BUF_FLUSH(bp); + dptr = XFS_BUF_PTR(bp); + /* + * Bump the cycle numbers at the start of each block + * since this part of the buffer is at the start of + * a new cycle. Watch out for the header magic number + * case, though. + */ + for (i=0; il_logBBsize-1); + ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize); + + /* account for internal log which does't start at block #0 */ + XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); + XFS_BUF_WRITE(bp); + if ((error = XFS_bwrite(bp))) { + xfs_ioerror_alert("xlog_sync (split)", log->l_mp, + bp, XFS_BUF_ADDR(bp)); + return (error); + } + } + return (0); +} /* xlog_sync */ + + +/* + * Unallocate a log structure + */ +void +xlog_unalloc_log(xlog_t *log) +{ + xlog_in_core_t *iclog, *next_iclog; + xlog_ticket_t *tic, *next_tic; + int i; + + + iclog = log->l_iclog; + for (i=0; il_iclog_bufs; i++) { + sv_destroy(&iclog->ic_forcesema); + sv_destroy(&iclog->ic_writesema); + XFS_freerbuf(iclog->ic_bp); +#ifdef DEBUG + if (iclog->ic_trace != NULL) { + ktrace_free(iclog->ic_trace); + } +#endif + next_iclog = iclog->ic_next; + kmem_free(iclog->hic_data, log->l_iclog_size); + kmem_free(iclog, sizeof(xlog_in_core_t)); + iclog = next_iclog; + } + freesema(&log->l_flushsema); + spinlock_destroy(&log->l_icloglock); + spinlock_destroy(&log->l_grant_lock); + + /* XXXsup take a look at this again. */ + if ((log->l_ticket_cnt != log->l_ticket_tcnt) && + !XLOG_FORCED_SHUTDOWN(log)) { + xfs_fs_cmn_err(CE_WARN, log->l_mp, + "xlog_unalloc_log: (cnt: %d, total: %d)", + log->l_ticket_cnt, log->l_ticket_tcnt); + /* ASSERT(log->l_ticket_cnt == log->l_ticket_tcnt); */ + + } else { + tic = log->l_unmount_free; + while (tic) { + next_tic = tic->t_next; + kmem_free(tic, NBPP); + tic = next_tic; + } + } + XFS_freerbuf(log->l_xbuf); +#ifdef DEBUG + if (log->l_trace != NULL) { + ktrace_free(log->l_trace); + } + if (log->l_grant_trace != NULL) { + ktrace_free(log->l_grant_trace); + } +#endif + log->l_mp->m_log = NULL; + kmem_free(log, sizeof(xlog_t)); +} /* xlog_unalloc_log */ + + +/* + * Write some region out to in-core log + * + * This will be called when writing externally provided regions or when + * writing out a commit record for a given transaction. + * + * General algorithm: + * 1. Find total length of this write. This may include adding to the + * lengths passed in. + * 2. Check whether we violate the tickets reservation. + * 3. While writing to this iclog + * A. Reserve as much space in this iclog as can get + * B. If this is first write, save away start lsn + * C. While writing this region: + * 1. If first write of transaction, write start record + * 2. Write log operation header (header per region) + * 3. Find out if we can fit entire region into this iclog + * 4. Potentially, verify destination bcopy ptr + * 5. Bcopy (partial) region + * 6. If partial copy, release iclog; otherwise, continue + * copying more regions into current iclog + * 4. Mark want sync bit (in simulation mode) + * 5. Release iclog for potential flush to on-disk log. + * + * ERRORS: + * 1. Panic if reservation is overrun. This should never happen since + * reservation amounts are generated internal to the filesystem. + * NOTES: + * 1. Tickets are single threaded data structures. + * 2. The XLOG_END_TRANS & XLOG_CONTINUE_TRANS flags are passed down to the + * syncing routine. When a single log_write region needs to span + * multiple in-core logs, the XLOG_CONTINUE_TRANS bit should be set + * on all log operation writes which don't contain the end of the + * region. The XLOG_END_TRANS bit is used for the in-core log + * operation which contains the end of the continued log_write region. + * 3. When xlog_state_get_iclog_space() grabs the rest of the current iclog, + * we don't really know exactly how much space will be used. As a result, + * we don't update ic_offset until the end when we know exactly how many + * bytes have been written out. + */ +int +xlog_write(xfs_mount_t * mp, + xfs_log_iovec_t reg[], + int nentries, + xfs_log_ticket_t tic, + xfs_lsn_t *start_lsn, + uint flags) +{ + xlog_t *log = mp->m_log; + xlog_ticket_t *ticket = (xlog_ticket_t *)tic; + xlog_op_header_t *logop_head; /* ptr to log operation header */ + xlog_in_core_t *iclog; /* ptr to current in-core log */ + __psint_t ptr; /* copy address into data region */ + int len; /* # xlog_write() bytes 2 still copy */ + int index; /* region index currently copying */ + int log_offset; /* offset (from 0) into data region */ + int start_rec_copy; /* # bytes to copy for start record */ + int partial_copy; /* did we split a region? */ + int partial_copy_len;/* # bytes copied if split region */ + int need_copy; /* # bytes need to bcopy this region */ + int copy_len; /* # bytes actually bcopy'ing */ + int copy_off; /* # bytes from entry start */ + int contwr; /* continued write of in-core log? */ + int firstwr = 0; /* first write of transaction */ + int error; + + partial_copy_len = partial_copy = 0; + + /* Calculate potential maximum space. Each region gets its own + * xlog_op_header_t and may need to be double word aligned. + */ + len = 0; + if (ticket->t_flags & XLOG_TIC_INITED) /* acct for start rec of xact */ + len += sizeof(xlog_op_header_t); + + for (index = 0; index < nentries; index++) { + len += sizeof(xlog_op_header_t); /* each region gets >= 1 */ + len += reg[index].i_len; + } + contwr = *start_lsn = 0; + + if (ticket->t_curr_res < len) { +#ifdef DEBUG + xlog_panic( + "xfs_log_write: reservation ran out. Need to up reservation"); +#else + /* Customer configurable panic */ + xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp, + "xfs_log_write: reservation ran out. Need to up reservation"); + /* If we did not panic, shutdown the filesystem */ + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); +#endif + } else + ticket->t_curr_res -= len; + + for (index = 0; index < nentries; ) { + if ((error = xlog_state_get_iclog_space(log, len, &iclog, ticket, + &contwr, &log_offset))) + return (error); + + ASSERT(log_offset <= iclog->ic_size - 1); + ptr = (__psint_t) ((char *)iclog->ic_datap+log_offset); + + /* start_lsn is the first lsn written to. That's all we need. */ + if (! *start_lsn) + *start_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + + /* This loop writes out as many regions as can fit in the amount + * of space which was allocated by xlog_state_get_iclog_space(). + */ + while (index < nentries) { + ASSERT(reg[index].i_len % sizeof(__int32_t) == 0); + ASSERT((__psint_t)ptr % sizeof(__int32_t) == 0); + start_rec_copy = 0; + + /* If first write for transaction, insert start record. + * We can't be trying to commit if we are inited. We can't + * have any "partial_copy" if we are inited. + */ + if (ticket->t_flags & XLOG_TIC_INITED) { + logop_head = (xlog_op_header_t *)ptr; + INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); + logop_head->oh_clientid = ticket->t_clientid; + INT_ZERO(logop_head->oh_len, ARCH_CONVERT); + logop_head->oh_flags = XLOG_START_TRANS; + INT_ZERO(logop_head->oh_res2, ARCH_CONVERT); + ticket->t_flags &= ~XLOG_TIC_INITED; /* clear bit */ + firstwr++; /* increment log ops below */ + + start_rec_copy = sizeof(xlog_op_header_t); + xlog_write_adv_cnt(ptr, len, log_offset, start_rec_copy); + } + + /* Copy log operation header directly into data section */ + logop_head = (xlog_op_header_t *)ptr; + INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); + logop_head->oh_clientid = ticket->t_clientid; + INT_ZERO(logop_head->oh_res2, ARCH_CONVERT); + + /* header copied directly */ + xlog_write_adv_cnt(ptr, len, log_offset, sizeof(xlog_op_header_t)); + + /* are we copying a commit or unmount record? */ + logop_head->oh_flags = flags; + + /* + * We've seen logs corrupted with bad transaction client + * ids. This makes sure that XFS doesn't generate them on. + * Turn this into an EIO and shut down the filesystem. + */ + switch (logop_head->oh_clientid) { + case XFS_TRANSACTION: + case XFS_VOLUME: + case XFS_LOG: + break; + default: + xfs_fs_cmn_err(CE_WARN, mp, + "Bad XFS transaction clientid 0x%x in ticket 0x%p", + logop_head->oh_clientid, tic); + return XFS_ERROR(EIO); + } + + /* Partial write last time? => (partial_copy != 0) + * need_copy is the amount we'd like to copy if everything could + * fit in the current bcopy. + */ + need_copy = reg[index].i_len - partial_copy_len; + + copy_off = partial_copy_len; + if (need_copy <= iclog->ic_size - log_offset) { /*complete write */ + INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len = need_copy); + if (partial_copy) + logop_head->oh_flags|= (XLOG_END_TRANS|XLOG_WAS_CONT_TRANS); + partial_copy_len = partial_copy = 0; + } else { /* partial write */ + copy_len = iclog->ic_size - log_offset; + INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len); + logop_head->oh_flags |= XLOG_CONTINUE_TRANS; + if (partial_copy) + logop_head->oh_flags |= XLOG_WAS_CONT_TRANS; + partial_copy_len += copy_len; + partial_copy++; + len += sizeof(xlog_op_header_t); /* from splitting of region */ + /* account for new log op header */ + ticket->t_curr_res -= sizeof(xlog_op_header_t); + } + xlog_verify_dest_ptr(log, ptr); + + /* copy region */ + ASSERT(copy_len >= 0); + bcopy(reg[index].i_addr + copy_off, (xfs_caddr_t)ptr, copy_len); + xlog_write_adv_cnt(ptr, len, log_offset, copy_len); + + /* make copy_len total bytes copied, including headers */ + copy_len += start_rec_copy + sizeof(xlog_op_header_t); + xlog_state_finish_copy(log, iclog, firstwr, (contwr? copy_len : 0)); + firstwr = 0; + if (partial_copy) { /* copied partial region */ + /* already marked WANT_SYNC by xlog_state_get_iclog_space */ + if ((error = xlog_state_release_iclog(log, iclog))) + return (error); + break; /* don't increment index */ + } else { /* copied entire region */ + index++; + partial_copy_len = partial_copy = 0; + + if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) { + xlog_state_want_sync(log, iclog); + if ((error = xlog_state_release_iclog(log, iclog))) + return (error); + if (index == nentries) + return 0; /* we are done */ + else + break; + } + } /* if (partial_copy) */ + } /* while (index < nentries) */ + } /* for (index = 0; index < nentries; ) */ + ASSERT(len == 0); + + return (xlog_state_release_iclog(log, iclog)); +} /* xlog_write */ + + +/***************************************************************************** + * + * State Machine functions + * + ***************************************************************************** + */ + +/* Clean iclogs starting from the head. This ordering must be + * maintained, so an iclog doesn't become ACTIVE beyond one that + * is SYNCING. This is also required to maintain the notion that we use + * a counting semaphore to hold off would be writers to the log when every + * iclog is trying to sync to disk. + * + * State Change: DIRTY -> ACTIVE + */ +void +xlog_state_clean_log(xlog_t *log) +{ + xlog_in_core_t *iclog; + int changed = 0; + + iclog = log->l_iclog; + do { + if (iclog->ic_state == XLOG_STATE_DIRTY) { + iclog->ic_state = XLOG_STATE_ACTIVE; + iclog->ic_offset = 0; + iclog->ic_callback = 0; /* don't need to free */ + /* + * If the number of ops in this iclog indicate it just + * contains the dummy transaction, we can + * change state into IDLE (the second time around). + * Otherwise we should change the state into + * NEED a dummy. + * We don't need to cover the dummy. + */ + if (!changed && + (INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT) == XLOG_COVER_OPS)) { + changed = 1; + } else { + /* + * We have two dirty iclogs so start over + * This could also be num of ops indicates + * this is not the dummy going out. + */ + changed = 2; + } + INT_ZERO(iclog->ic_header.h_num_logops, ARCH_CONVERT); + bzero(iclog->ic_header.h_cycle_data, + sizeof(iclog->ic_header.h_cycle_data)); + INT_ZERO(iclog->ic_header.h_lsn, ARCH_CONVERT); + } else if (iclog->ic_state == XLOG_STATE_ACTIVE) + /* do nothing */; + else + break; /* stop cleaning */ + iclog = iclog->ic_next; + } while (iclog != log->l_iclog); + + /* log is locked when we are called */ + /* + * Change state for the dummy log recording. + * We usually go to NEED. But we go to NEED2 if the changed indicates + * we are done writing the dummy record. + * If we are done with the second dummy recored (DONE2), then + * we go to IDLE. + */ + if (changed) { + switch (log->l_covered_state) { + case XLOG_STATE_COVER_IDLE: + case XLOG_STATE_COVER_NEED: + case XLOG_STATE_COVER_NEED2: + log->l_covered_state = XLOG_STATE_COVER_NEED; + break; + + case XLOG_STATE_COVER_DONE: + if (changed == 1) + log->l_covered_state = XLOG_STATE_COVER_NEED2; + else + log->l_covered_state = XLOG_STATE_COVER_NEED; + break; + + case XLOG_STATE_COVER_DONE2: + if (changed == 1) + log->l_covered_state = XLOG_STATE_COVER_IDLE; + else + log->l_covered_state = XLOG_STATE_COVER_NEED; + break; + + default: + ASSERT(0); + } + } +} /* xlog_state_clean_log */ + +STATIC xfs_lsn_t +xlog_get_lowest_lsn( + xlog_t *log) +{ + xlog_in_core_t *lsn_log; + xfs_lsn_t lowest_lsn, lsn; + + lsn_log = log->l_iclog; + lowest_lsn = 0; + do { + if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) { + lsn = INT_GET(lsn_log->ic_header.h_lsn, ARCH_CONVERT); + if ((lsn && !lowest_lsn) || + (XFS_LSN_CMP_ARCH(lsn, lowest_lsn, ARCH_NOCONVERT) < 0)) { + lowest_lsn = lsn; + } + } + lsn_log = lsn_log->ic_next; + } while (lsn_log != log->l_iclog); + return(lowest_lsn); +} + + +STATIC void +xlog_state_do_callback( + xlog_t *log, + int aborted, + xlog_in_core_t *ciclog) +{ + xlog_in_core_t *iclog; + xlog_in_core_t *first_iclog; /* used to know when we've + * processed all iclogs once */ + xfs_log_callback_t *cb, *cb_next; + int flushcnt = 0; + xfs_lsn_t lowest_lsn; + int ioerrors; /* counter: iclogs with errors */ + int loopdidcallbacks; /* flag: inner loop did callbacks*/ + int funcdidcallbacks; /* flag: function did callbacks */ + int repeats; /* for issuing console warnings if + * looping too many times */ + SPLDECL(s); + + s = LOG_LOCK(log); + first_iclog = iclog = log->l_iclog; + ioerrors = 0; + funcdidcallbacks = 0; + repeats = 0; + + do { + /* + * Scan all iclogs starting with the one pointed to by the + * log. Reset this starting point each time the log is + * unlocked (during callbacks). + * + * Keep looping through iclogs until one full pass is made + * without running any callbacks. + */ + first_iclog = log->l_iclog; + iclog = log->l_iclog; + loopdidcallbacks = 0; + repeats++; + + do { + + /* skip all iclogs in the ACTIVE & DIRTY states */ + if (iclog->ic_state & + (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY)) { + iclog = iclog->ic_next; + continue; + } + + /* + * Between marking a filesystem SHUTDOWN and stopping + * the log, we do flush all iclogs to disk (if there + * wasn't a log I/O error). So, we do want things to + * go smoothly in case of just a SHUTDOWN w/o a + * LOG_IO_ERROR. + */ + if (!(iclog->ic_state & XLOG_STATE_IOERROR)) { + /* + * Can only perform callbacks in order. Since + * this iclog is not in the DONE_SYNC/ + * DO_CALLBACK state, we skip the rest and + * just try to clean up. If we set our iclog + * to DO_CALLBACK, we will not process it when + * we retry since a previous iclog is in the + * CALLBACK and the state cannot change since + * we are holding the LOG_LOCK. + */ + if (!(iclog->ic_state & + (XLOG_STATE_DONE_SYNC | + XLOG_STATE_DO_CALLBACK))) { + if (ciclog && (ciclog->ic_state == + XLOG_STATE_DONE_SYNC)) { + ciclog->ic_state = XLOG_STATE_DO_CALLBACK; + } + break; + } + /* + * We now have an iclog that is in either the + * DO_CALLBACK or DONE_SYNC states. The other + * states (WANT_SYNC, SYNCING, or CALLBACK were + * caught by the above if and are going to + * clean (i.e. we aren't doing their callbacks) + * see the above if. + */ + + /* + * We will do one more check here to see if we + * have chased our tail around. + */ + + lowest_lsn = xlog_get_lowest_lsn(log); + if (lowest_lsn && ( + XFS_LSN_CMP_ARCH( + lowest_lsn, + INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT), + ARCH_NOCONVERT + )<0)) { + iclog = iclog->ic_next; + continue; /* Leave this iclog for + * another thread */ + } + + iclog->ic_state = XLOG_STATE_CALLBACK; + + LOG_UNLOCK(log, s); + + /* l_last_sync_lsn field protected by + * GRANT_LOCK. Don't worry about iclog's lsn. + * No one else can be here except us. + */ + s = GRANT_LOCK(log); + ASSERT(XFS_LSN_CMP_ARCH( + log->l_last_sync_lsn, + INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT), + ARCH_NOCONVERT + )<=0); + log->l_last_sync_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + GRANT_UNLOCK(log, s); + + /* + * Keep processing entries in the callback list + * until we come around and it is empty. We + * need to atomically see that the list is + * empty and change the state to DIRTY so that + * we don't miss any more callbacks being added. + */ + s = LOG_LOCK(log); + } else { + ioerrors++; + } + cb = iclog->ic_callback; + + while (cb != 0) { + iclog->ic_callback_tail = &(iclog->ic_callback); + iclog->ic_callback = 0; + LOG_UNLOCK(log, s); + + /* perform callbacks in the order given */ + for (; cb != 0; cb = cb_next) { + cb_next = cb->cb_next; + cb->cb_func(cb->cb_arg, aborted); + } + s = LOG_LOCK(log); + cb = iclog->ic_callback; + } + + loopdidcallbacks++; + funcdidcallbacks++; + + ASSERT(iclog->ic_callback == 0); + if (!(iclog->ic_state & XLOG_STATE_IOERROR)) + iclog->ic_state = XLOG_STATE_DIRTY; + + /* wake up threads waiting in xfs_log_force() */ + sv_broadcast(&iclog->ic_forcesema); + + iclog = iclog->ic_next; + } while (first_iclog != iclog); + if (repeats && (repeats % 10) == 0) { + xfs_fs_cmn_err(CE_WARN, log->l_mp, + "xlog_state_do_callback: looping %d", repeats); + } + } while (!ioerrors && loopdidcallbacks); + + /* + * make one last gasp attempt to see if iclogs are being left in + * limbo.. + */ +#ifdef DEBUG + if (funcdidcallbacks) { + first_iclog = iclog = log->l_iclog; + do { + ASSERT(iclog->ic_state != XLOG_STATE_DO_CALLBACK); + /* + * Terminate the loop if iclogs are found in states + * which will cause other threads to clean up iclogs. + * + * SYNCING - i/o completion will go through logs + * DONE_SYNC - interrupt thread should be waiting for + * LOG_LOCK + * IOERROR - give up hope all ye who enter here + */ + if (iclog->ic_state == XLOG_STATE_SYNCING || + iclog->ic_state == XLOG_STATE_DONE_SYNC || + iclog->ic_state == XLOG_STATE_IOERROR ) + break; + iclog = iclog->ic_next; + } while (first_iclog != iclog); + } +#endif + + /* + * Transition from DIRTY to ACTIVE if applicable. NOP if + * STATE_IOERROR. + */ + xlog_state_clean_log(log); + + if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) { + flushcnt = log->l_flushcnt; + log->l_flushcnt = 0; + } + LOG_UNLOCK(log, s); + while (flushcnt--) + vsema(&log->l_flushsema); +} /* xlog_state_do_callback */ + + +/* + * Finish transitioning this iclog to the dirty state. + * + * Make sure that we completely execute this routine only when this is + * the last call to the iclog. There is a good chance that iclog flushes, + * when we reach the end of the physical log, get turned into 2 separate + * calls to bwrite. Hence, one iclog flush could generate two calls to this + * routine. By using the reference count bwritecnt, we guarantee that only + * the second completion goes through. + * + * Callbacks could take time, so they are done outside the scope of the + * global state machine log lock. Assume that the calls to cvsema won't + * take a long time. At least we know it won't sleep. + */ +void +xlog_state_done_syncing( + xlog_in_core_t *iclog, + int aborted) +{ + xlog_t *log = iclog->ic_log; + SPLDECL(s); + + s = LOG_LOCK(log); + + ASSERT(iclog->ic_state == XLOG_STATE_SYNCING || + iclog->ic_state == XLOG_STATE_IOERROR); + ASSERT(iclog->ic_refcnt == 0); + ASSERT(iclog->ic_bwritecnt == 1 || iclog->ic_bwritecnt == 2); + + + /* + * If we got an error, either on the first buffer, or in the case of + * split log writes, on the second, we mark ALL iclogs STATE_IOERROR, + * and none should ever be attempted to be written to disk + * again. + */ + if (iclog->ic_state != XLOG_STATE_IOERROR) { + if (--iclog->ic_bwritecnt == 1) { + LOG_UNLOCK(log, s); + return; + } + iclog->ic_state = XLOG_STATE_DONE_SYNC; + } + + /* + * Someone could be sleeping prior to writing out the next + * iclog buffer, we wake them all, one will get to do the + * I/O, the others get to wait for the result. + */ + sv_broadcast(&iclog->ic_writesema); + LOG_UNLOCK(log, s); + xlog_state_do_callback(log, aborted, iclog); /* also cleans log */ +} /* xlog_state_done_syncing */ + + +/* + * Update counters atomically now that bcopy is done. + */ +/* ARGSUSED */ +static inline void +xlog_state_finish_copy(xlog_t *log, + xlog_in_core_t *iclog, + int first_write, + int copy_bytes) +{ + SPLDECL(s); + + s = LOG_LOCK(log); + + if (first_write) + INT_MOD(iclog->ic_header.h_num_logops, ARCH_CONVERT, +1); + INT_MOD(iclog->ic_header.h_num_logops, ARCH_CONVERT, +1); + iclog->ic_offset += copy_bytes; + + LOG_UNLOCK(log, s); +} /* xlog_state_finish_copy */ + + + +/* + * If the head of the in-core log ring is not (ACTIVE or DIRTY), then we must + * sleep. The flush semaphore is set to the number of in-core buffers and + * decremented around disk syncing. Therefore, if all buffers are syncing, + * this semaphore will cause new writes to sleep until a sync completes. + * Otherwise, this code just does p() followed by v(). This approximates + * a sleep/wakeup except we can't race. + * + * The in-core logs are used in a circular fashion. They are not used + * out-of-order even when an iclog past the head is free. + * + * return: + * * log_offset where xlog_write() can start writing into the in-core + * log's data space. + * * in-core log pointer to which xlog_write() should write. + * * boolean indicating this is a continued write to an in-core log. + * If this is the last write, then the in-core log's offset field + * needs to be incremented, depending on the amount of data which + * is copied. + */ +int +xlog_state_get_iclog_space(xlog_t *log, + int len, + xlog_in_core_t **iclogp, + xlog_ticket_t *ticket, + int *continued_write, + int *logoffsetp) +{ + SPLDECL(s); + int log_offset; + xlog_rec_header_t *head; + xlog_in_core_t *iclog; + int error; + +restart: + s = LOG_LOCK(log); + if (XLOG_FORCED_SHUTDOWN(log)) { + LOG_UNLOCK(log, s); + return XFS_ERROR(EIO); + } + + iclog = log->l_iclog; + if (! (iclog->ic_state == XLOG_STATE_ACTIVE)) { + log->l_flushcnt++; + LOG_UNLOCK(log, s); + xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH); + XFS_STATS_INC(xfsstats.xs_log_noiclogs); + /* Ensure that log writes happen */ + psema(&log->l_flushsema, PINOD); + goto restart; + } + ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE); + head = &iclog->ic_header; + + iclog->ic_refcnt++; /* prevents sync */ + log_offset = iclog->ic_offset; + + /* On the 1st write to an iclog, figure out lsn. This works + * if iclogs marked XLOG_STATE_WANT_SYNC always write out what they are + * committing to. If the offset is set, that's how many blocks + * must be written. + */ + if (log_offset == 0) { + ticket->t_curr_res -= log->l_iclog_hsize; + INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle); + ASSIGN_LSN(head->h_lsn, log, ARCH_CONVERT); + ASSERT(log->l_curr_block >= 0); + + /* round off error from last write with this iclog */ + ticket->t_curr_res -= iclog->ic_roundoff; + log->l_roundoff -= iclog->ic_roundoff; + iclog->ic_roundoff = 0; + } + + /* If there is enough room to write everything, then do it. Otherwise, + * claim the rest of the region and make sure the XLOG_STATE_WANT_SYNC + * bit is on, so this will get flushed out. Don't update ic_offset + * until you know exactly how many bytes get copied. Therefore, wait + * until later to update ic_offset. + * + * xlog_write() algorithm assumes that at least 2 xlog_op_header_t's + * can fit into remaining data section. + */ + if (iclog->ic_size - iclog->ic_offset < 2*sizeof(xlog_op_header_t)) { + xlog_state_switch_iclogs(log, iclog, iclog->ic_size); + + /* If I'm the only one writing to this iclog, sync it to disk */ + if (iclog->ic_refcnt == 1) { + LOG_UNLOCK(log, s); + if ((error = xlog_state_release_iclog(log, iclog))) + return (error); + } else { + iclog->ic_refcnt--; + LOG_UNLOCK(log, s); + } + goto restart; + } + + /* Do we have enough room to write the full amount in the remainder + * of this iclog? Or must we continue a write on the next iclog and + * mark this iclog as completely taken? In the case where we switch + * iclogs (to mark it taken), this particular iclog will release/sync + * to disk in xlog_write(). + */ + if (len <= iclog->ic_size - iclog->ic_offset) { + *continued_write = 0; + iclog->ic_offset += len; + } else { + *continued_write = 1; + xlog_state_switch_iclogs(log, iclog, iclog->ic_size); + } + *iclogp = iclog; + + ASSERT(iclog->ic_offset <= iclog->ic_size); + LOG_UNLOCK(log, s); + + *logoffsetp = log_offset; + return 0; +} /* xlog_state_get_iclog_space */ + +/* + * Atomically get the log space required for a log ticket. + * + * Once a ticket gets put onto the reserveq, it will only return after + * the needed reservation is satisfied. + */ +STATIC int +xlog_grant_log_space(xlog_t *log, + xlog_ticket_t *tic) +{ + int free_bytes; + int need_bytes; + SPLDECL(s); +#ifdef DEBUG + xfs_lsn_t tail_lsn; +#endif + + +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("grant Recovery problem"); +#endif + + /* Is there space or do we need to sleep? */ + s = GRANT_LOCK(log); + xlog_trace_loggrant(log, tic, "xlog_grant_log_space: enter"); + + /* something is already sleeping; insert new transaction at end */ + if (log->l_reserve_headq) { + XLOG_INS_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: sleep 1"); + /* + * Gotta check this before going to sleep, while we're + * holding the grant lock. + */ + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); + /* + * If we got an error, and the filesystem is shutting down, + * we'll catch it down below. So just continue... + */ + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: wake 1"); + s = GRANT_LOCK(log); + } + if (tic->t_flags & XFS_LOG_PERM_RESERV) + need_bytes = tic->t_unit_res*tic->t_ocnt; + else + need_bytes = tic->t_unit_res; + +redo: + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + free_bytes = xlog_space_left(log, log->l_grant_reserve_cycle, + log->l_grant_reserve_bytes); + if (free_bytes < need_bytes) { + if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) + XLOG_INS_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: sleep 2"); + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); + + if (XLOG_FORCED_SHUTDOWN(log)) { + s = GRANT_LOCK(log); + goto error_return; + } + + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: wake 2"); + xlog_grant_push_ail(log->l_mp, need_bytes); + s = GRANT_LOCK(log); + goto redo; + } else if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_reserve_headq, tic); + + /* we've got enough space */ + XLOG_GRANT_ADD_SPACE(log, need_bytes, 'w'); + XLOG_GRANT_ADD_SPACE(log, need_bytes, 'r'); +#ifdef DEBUG + tail_lsn = log->l_tail_lsn; + /* + * Check to make sure the grant write head didn't just over lap the + * tail. If the cycles are the same, we can't be overlapping. + * Otherwise, make sure that the cycles differ by exactly one and + * check the byte count. + */ + if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) != log->l_grant_write_cycle) { + ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn, ARCH_NOCONVERT)); + ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn, ARCH_NOCONVERT))); + } +#endif + xlog_trace_loggrant(log, tic, "xlog_grant_log_space: exit"); + xlog_verify_grant_head(log, 1); + GRANT_UNLOCK(log, s); + return 0; + + error_return: + if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, "xlog_grant_log_space: err_ret"); + /* + * If we are failing, make sure the ticket doesn't have any + * current reservations. We don't want to add this back when + * the ticket/transaction gets cancelled. + */ + tic->t_curr_res = 0; + tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ + GRANT_UNLOCK(log, s); + return XFS_ERROR(EIO); +} /* xlog_grant_log_space */ + + +/* + * Replenish the byte reservation required by moving the grant write head. + * + * + */ +STATIC int +xlog_regrant_write_log_space(xlog_t *log, + xlog_ticket_t *tic) +{ + SPLDECL(s); + int free_bytes, need_bytes; + xlog_ticket_t *ntic; +#ifdef DEBUG + xfs_lsn_t tail_lsn; +#endif + + tic->t_curr_res = tic->t_unit_res; + + if (tic->t_cnt > 0) + return (0); + +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("regrant Recovery problem"); +#endif + + s = GRANT_LOCK(log); + xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: enter"); + + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + /* If there are other waiters on the queue then give them a + * chance at logspace before us. Wake up the first waiters, + * if we do not wake up all the waiters then go to sleep waiting + * for more free space, otherwise try to get some space for + * this transaction. + */ + + if ((ntic = log->l_write_headq)) { + free_bytes = xlog_space_left(log, log->l_grant_write_cycle, + log->l_grant_write_bytes); + do { + ASSERT(ntic->t_flags & XLOG_TIC_PERM_RESERV); + + if (free_bytes < ntic->t_unit_res) + break; + free_bytes -= ntic->t_unit_res; + sv_signal(&ntic->t_sema); + ntic = ntic->t_next; + } while (ntic != log->l_write_headq); + + if (ntic != log->l_write_headq) { + if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) + XLOG_INS_TICKETQ(log->l_write_headq, tic); + + xlog_trace_loggrant(log, tic, + "xlog_regrant_write_log_space: sleep 1"); + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, + &log->l_grant_lock, s); + + /* If we're shutting down, this tic is already + * off the queue */ + if (XLOG_FORCED_SHUTDOWN(log)) { + s = GRANT_LOCK(log); + goto error_return; + } + + xlog_trace_loggrant(log, tic, + "xlog_regrant_write_log_space: wake 1"); + xlog_grant_push_ail(log->l_mp, tic->t_unit_res); + s = GRANT_LOCK(log); + } + } + + need_bytes = tic->t_unit_res; + +redo: + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + free_bytes = xlog_space_left(log, log->l_grant_write_cycle, + log->l_grant_write_bytes); + if (free_bytes < need_bytes) { + if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) + XLOG_INS_TICKETQ(log->l_write_headq, tic); + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); + + /* If we're shutting down, this tic is already off the queue */ + if (XLOG_FORCED_SHUTDOWN(log)) { + s = GRANT_LOCK(log); + goto error_return; + } + + xlog_trace_loggrant(log, tic, + "xlog_regrant_write_log_space: wake 2"); + xlog_grant_push_ail(log->l_mp, need_bytes); + s = GRANT_LOCK(log); + goto redo; + } else if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_write_headq, tic); + + XLOG_GRANT_ADD_SPACE(log, need_bytes, 'w'); /* we've got enough space */ +#ifdef DEBUG + tail_lsn = log->l_tail_lsn; + if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) != log->l_grant_write_cycle) { + ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn, ARCH_NOCONVERT)); + ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn, ARCH_NOCONVERT))); + } +#endif + + xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: exit"); + xlog_verify_grant_head(log, 1); + GRANT_UNLOCK(log, s); + return (0); + + + error_return: + if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: err_ret"); + /* + * If we are failing, make sure the ticket doesn't have any + * current reservations. We don't want to add this back when + * the ticket/transaction gets cancelled. + */ + tic->t_curr_res = 0; + tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ + GRANT_UNLOCK(log, s); + return XFS_ERROR(EIO); +} /* xlog_regrant_write_log_space */ + + +/* The first cnt-1 times through here we don't need to + * move the grant write head because the permanent + * reservation has reserved cnt times the unit amount. + * Release part of current permanent unit reservation and + * reset current reservation to be one units worth. Also + * move grant reservation head forward. + */ +STATIC void +xlog_regrant_reserve_log_space(xlog_t *log, + xlog_ticket_t *ticket) +{ + SPLDECL(s); + + xlog_trace_loggrant(log, ticket, + "xlog_regrant_reserve_log_space: enter"); + if (ticket->t_cnt > 0) + ticket->t_cnt--; + + s = GRANT_LOCK(log); + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'w'); + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'r'); + ticket->t_curr_res = ticket->t_unit_res; + xlog_trace_loggrant(log, ticket, + "xlog_regrant_reserve_log_space: sub current res"); + xlog_verify_grant_head(log, 1); + + /* just return if we still have some of the pre-reserved space */ + if (ticket->t_cnt > 0) { + GRANT_UNLOCK(log, s); + return; + } + + XLOG_GRANT_ADD_SPACE(log, ticket->t_unit_res, 'r'); + xlog_trace_loggrant(log, ticket, + "xlog_regrant_reserve_log_space: exit"); + xlog_verify_grant_head(log, 0); + GRANT_UNLOCK(log, s); + ticket->t_curr_res = ticket->t_unit_res; +} /* xlog_regrant_reserve_log_space */ + + +/* + * Give back the space left from a reservation. + * + * All the information we need to make a correct determination of space left + * is present. For non-permanent reservations, things are quite easy. The + * count should have been decremented to zero. We only need to deal with the + * space remaining in the current reservation part of the ticket. If the + * ticket contains a permanent reservation, there may be left over space which + * needs to be released. A count of N means that N-1 refills of the current + * reservation can be done before we need to ask for more space. The first + * one goes to fill up the first current reservation. Once we run out of + * space, the count will stay at zero and the only space remaining will be + * in the current reservation field. + */ +STATIC void +xlog_ungrant_log_space(xlog_t *log, + xlog_ticket_t *ticket) +{ + SPLDECL(s); + + if (ticket->t_cnt > 0) + ticket->t_cnt--; + + s = GRANT_LOCK(log); + xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: enter"); + + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'w'); + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'r'); + + xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: sub current"); + + /* If this is a permanent reservation ticket, we may be able to free + * up more space based on the remaining count. + */ + if (ticket->t_cnt > 0) { + ASSERT(ticket->t_flags & XLOG_TIC_PERM_RESERV); + XLOG_GRANT_SUB_SPACE(log, ticket->t_unit_res*ticket->t_cnt,'w'); + XLOG_GRANT_SUB_SPACE(log, ticket->t_unit_res*ticket->t_cnt,'r'); + } + + xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: exit"); + xlog_verify_grant_head(log, 1); + GRANT_UNLOCK(log, s); + xfs_log_move_tail(log->l_mp, 1); +} /* xlog_ungrant_log_space */ + + +/* + * If the lsn is not found or the iclog with the lsn is in the callback + * state, we need to call the function directly. This is done outside + * this function's scope. Otherwise, we insert the callback at the end + * of the iclog's callback list. + */ +int +xlog_state_lsn_is_synced(xlog_t *log, + xfs_lsn_t lsn, + xfs_log_callback_t *cb, + int *abortflg) +{ + xlog_in_core_t *iclog; + SPLDECL(s); + int lsn_is_synced = 1; + + *abortflg = 0; + s = LOG_LOCK(log); + + iclog = log->l_iclog; + do { + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) != lsn) { + iclog = iclog->ic_next; + continue; + } else { + if (iclog->ic_state & XLOG_STATE_DIRTY) /* call it*/ + break; + + if (iclog->ic_state & XLOG_STATE_IOERROR) { + *abortflg = XFS_LI_ABORTED; + break; + } + /* insert callback onto end of list */ + cb->cb_next = 0; + *(iclog->ic_callback_tail) = cb; + iclog->ic_callback_tail = &(cb->cb_next); + lsn_is_synced = 0; + break; + } + } while (iclog != log->l_iclog); + + LOG_UNLOCK(log, s); + return lsn_is_synced; +} /* xlog_state_lsn_is_synced */ + + +/* + * Atomically put back used ticket. + */ +void +xlog_state_put_ticket(xlog_t *log, + xlog_ticket_t *tic) +{ + unsigned long s; + + s = LOG_LOCK(log); + xlog_ticket_put(log, tic); + LOG_UNLOCK(log, s); +} /* xlog_state_put_ticket */ + +/* + * Flush iclog to disk if this is the last reference to the given iclog and + * the WANT_SYNC bit is set. + * + * When this function is entered, the iclog is not necessarily in the + * WANT_SYNC state. It may be sitting around waiting to get filled. + * + * + */ +int +xlog_state_release_iclog(xlog_t *log, + xlog_in_core_t *iclog) +{ + SPLDECL(s); + int sync = 0; /* do we sync? */ + + xlog_assign_tail_lsn(log->l_mp, 0); + + s = LOG_LOCK(log); + + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, s); + return XFS_ERROR(EIO); + } + + ASSERT(iclog->ic_refcnt > 0); + ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_WANT_SYNC); + + if (--iclog->ic_refcnt == 0 && + iclog->ic_state == XLOG_STATE_WANT_SYNC) { + sync++; + iclog->ic_state = XLOG_STATE_SYNCING; + INT_SET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT, log->l_tail_lsn); + xlog_verify_tail_lsn(log, iclog, log->l_tail_lsn); + /* cycle incremented when incrementing curr_block */ + } + + LOG_UNLOCK(log, s); + + /* + * We let the log lock go, so it's possible that we hit a log I/O + * error or someother SHUTDOWN condition that marks the iclog + * as XLOG_STATE_IOERROR before the bwrite. However, we know that + * this iclog has consistent data, so we ignore IOERROR + * flags after this point. + */ + if (sync) { + return xlog_sync(log, iclog); + } + return (0); + +} /* xlog_state_release_iclog */ + + +/* + * This routine will mark the current iclog in the ring as WANT_SYNC + * and move the current iclog pointer to the next iclog in the ring. + * When this routine is called from xlog_state_get_iclog_space(), the + * exact size of the iclog has not yet been determined. All we know is + * that every data block. We have run out of space in this log record. + */ +STATIC void +xlog_state_switch_iclogs(xlog_t *log, + xlog_in_core_t *iclog, + int eventual_size) +{ + uint roundup; + + ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE); + if (!eventual_size) + eventual_size = iclog->ic_offset; + iclog->ic_state = XLOG_STATE_WANT_SYNC; + INT_SET(iclog->ic_header.h_prev_block, ARCH_CONVERT, log->l_prev_block); + log->l_prev_block = log->l_curr_block; + log->l_prev_cycle = log->l_curr_cycle; + + /* roll log?: ic_offset changed later */ + log->l_curr_block += BTOBB(eventual_size)+BTOBB(log->l_iclog_hsize); + + /* Round up to next log-sunit */ + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + if (log->l_curr_block & (log->l_mp->m_lstripemask - 1)) { + roundup = log->l_mp->m_lstripemask - + (log->l_curr_block & + (log->l_mp->m_lstripemask - 1)); + } else { + roundup = 0; + } + log->l_curr_block += roundup; + } + + if (log->l_curr_block >= log->l_logBBsize) { + log->l_curr_cycle++; + if (log->l_curr_cycle == XLOG_HEADER_MAGIC_NUM) + log->l_curr_cycle++; + log->l_curr_block -= log->l_logBBsize; + ASSERT(log->l_curr_block >= 0); + } + ASSERT(iclog == log->l_iclog); + log->l_iclog = iclog->ic_next; +} /* xlog_state_switch_iclogs */ + + +/* + * Write out all data in the in-core log as of this exact moment in time. + * + * Data may be written to the in-core log during this call. However, + * we don't guarantee this data will be written out. A change from past + * implementation means this routine will *not* write out zero length LRs. + * + * Basically, we try and perform an intelligent scan of the in-core logs. + * If we determine there is no flushable data, we just return. There is no + * flushable data if: + * + * 1. the current iclog is active and has no data; the previous iclog + * is in the active or dirty state. + * 2. the current iclog is drity, and the previous iclog is in the + * active or dirty state. + * + * We may sleep (call psema) if: + * + * 1. the current iclog is not in the active nor dirty state. + * 2. the current iclog dirty, and the previous iclog is not in the + * active nor dirty state. + * 3. the current iclog is active, and there is another thread writing + * to this particular iclog. + * 4. a) the current iclog is active and has no other writers + * b) when we return from flushing out this iclog, it is still + * not in the active nor dirty state. + */ +STATIC int +xlog_state_sync_all(xlog_t *log, uint flags) +{ + xlog_in_core_t *iclog; + xfs_lsn_t lsn; + SPLDECL(s); + + s = LOG_LOCK(log); + + iclog = log->l_iclog; + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, s); + return XFS_ERROR(EIO); + } + + /* If the head iclog is not active nor dirty, we just attach + * ourselves to the head and go to sleep. + */ + if (iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_DIRTY) { + /* + * If the head is dirty or (active and empty), then + * we need to look at the previous iclog. If the previous + * iclog is active or dirty we are done. There is nothing + * to sync out. Otherwise, we attach ourselves to the + * previous iclog and go to sleep. + */ + if (iclog->ic_state == XLOG_STATE_DIRTY || + (iclog->ic_refcnt == 0 && iclog->ic_offset == 0)) { + iclog = iclog->ic_prev; + if (iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_DIRTY) + goto no_sleep; + else + goto maybe_sleep; + } else { + if (iclog->ic_refcnt == 0) { + /* We are the only one with access to this + * iclog. Flush it out now. There should + * be a roundoff of zero to show that someone + * has already taken care of the roundoff from + * the previous sync. + */ + ASSERT(iclog->ic_roundoff == 0); + iclog->ic_refcnt++; + lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + xlog_state_switch_iclogs(log, iclog, 0); + LOG_UNLOCK(log, s); + + if (xlog_state_release_iclog(log, iclog)) + return XFS_ERROR(EIO); + s = LOG_LOCK(log); + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) == lsn && + iclog->ic_state != XLOG_STATE_DIRTY) + goto maybe_sleep; + else + goto no_sleep; + } else { + /* Someone else is writing to this iclog. + * Use its call to flush out the data. However, + * the other thread may not force out this LR, + * so we mark it WANT_SYNC. + */ + xlog_state_switch_iclogs(log, iclog, 0); + goto maybe_sleep; + } + } + } + + /* By the time we come around again, the iclog could've been filled + * which would give it another lsn. If we have a new lsn, just + * return because the relevant data has been flushed. + */ +maybe_sleep: + if (flags & XFS_LOG_SYNC) { + /* + * We must check if we're shutting down here, before + * we wait, while we're holding the LOG_LOCK. + * Then we check again after waking up, in case our + * sleep was disturbed by a bad news. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, s); + return XFS_ERROR(EIO); + } + XFS_STATS_INC(xfsstats.xs_log_force_sleep); + sv_wait(&iclog->ic_forcesema, PINOD, &log->l_icloglock, s); + /* + * No need to grab the log lock here since we're + * only deciding whether or not to return EIO + * and the memory read should be atomic. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) + return XFS_ERROR(EIO); + + } else { + +no_sleep: + LOG_UNLOCK(log, s); + } + return 0; +} /* xlog_state_sync_all */ + + +/* + * Used by code which implements synchronous log forces. + * + * Find in-core log with lsn. + * If it is in the DIRTY state, just return. + * If it is in the ACTIVE state, move the in-core log into the WANT_SYNC + * state and go to sleep or return. + * If it is in any other state, go to sleep or return. + * + * If filesystem activity goes to zero, the iclog will get flushed only by + * bdflush(). + */ +int +xlog_state_sync(xlog_t *log, + xfs_lsn_t lsn, + uint flags) +{ + xlog_in_core_t *iclog; + int already_slept = 0; + SPLDECL(s); + + +try_again: + s = LOG_LOCK(log); + iclog = log->l_iclog; + + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, s); + return XFS_ERROR(EIO); + } + + do { + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) != lsn) { + iclog = iclog->ic_next; + continue; + } + + if (iclog->ic_state == XLOG_STATE_DIRTY) { + LOG_UNLOCK(log, s); + return 0; + } + + if (iclog->ic_state == XLOG_STATE_ACTIVE) { + /* + * We sleep here if we haven't already slept (e.g. + * this is the first time we've looked at the correct + * iclog buf) and the buffer before us is going to + * be sync'ed. The reason for this is that if we + * are doing sync transactions here, by waiting for + * the previous I/O to complete, we can allow a few + * more transactions into this iclog before we close + * it down. + * + * Otherwise, we mark the buffer WANT_SYNC, and bump + * up the refcnt so we can release the log (which drops + * the ref count). The state switch keeps new transaction + * commits from using this buffer. When the current commits + * finish writing into the buffer, the refcount will drop to + * zero and the buffer will go out then. + */ + if (!already_slept && + (iclog->ic_prev->ic_state & (XLOG_STATE_WANT_SYNC | + XLOG_STATE_SYNCING))) { + ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); + XFS_STATS_INC(xfsstats.xs_log_force_sleep); + sv_wait(&iclog->ic_prev->ic_writesema, PSWP, + &log->l_icloglock, s); + already_slept = 1; + goto try_again; + } else { + iclog->ic_refcnt++; + xlog_state_switch_iclogs(log, iclog, 0); + LOG_UNLOCK(log, s); + if (xlog_state_release_iclog(log, iclog)) + return XFS_ERROR(EIO); + s = LOG_LOCK(log); + } + } + + if ((flags & XFS_LOG_SYNC) && /* sleep */ + !(iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { + + /* + * Don't wait on the forcesema if we know that we've + * gotten a log write error. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, s); + return XFS_ERROR(EIO); + } + XFS_STATS_INC(xfsstats.xs_log_force_sleep); + sv_wait(&iclog->ic_forcesema, PSWP, &log->l_icloglock, s); + /* + * No need to grab the log lock here since we're + * only deciding whether or not to return EIO + * and the memory read should be atomic. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) + return XFS_ERROR(EIO); + } else { /* just return */ + LOG_UNLOCK(log, s); + } + return 0; + + } while (iclog != log->l_iclog); + + LOG_UNLOCK(log, s); + return (0); +} /* xlog_state_sync */ + + +/* + * Called when we want to mark the current iclog as being ready to sync to + * disk. + */ +void +xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) +{ + SPLDECL(s); + + s = LOG_LOCK(log); + + if (iclog->ic_state == XLOG_STATE_ACTIVE) { + xlog_state_switch_iclogs(log, iclog, 0); + } else { + ASSERT(iclog->ic_state & + (XLOG_STATE_WANT_SYNC|XLOG_STATE_IOERROR)); + } + + LOG_UNLOCK(log, s); +} /* xlog_state_want_sync */ + + + +/***************************************************************************** + * + * TICKET functions + * + ***************************************************************************** + */ + +/* + * Algorithm doesn't take into account page size. ;-( + */ +STATIC void +xlog_state_ticket_alloc(xlog_t *log) +{ + xlog_ticket_t *t_list; + xlog_ticket_t *next; + xfs_caddr_t buf; + uint i = (NBPP / sizeof(xlog_ticket_t)) - 2; + SPLDECL(s); + + /* + * The kmem_zalloc may sleep, so we shouldn't be holding the + * global lock. XXXmiken: may want to use zone allocator. + */ + buf = (xfs_caddr_t) kmem_zalloc(NBPP, 0); + + s = LOG_LOCK(log); + + /* Attach 1st ticket to Q, so we can keep track of allocated memory */ + t_list = (xlog_ticket_t *)buf; + t_list->t_next = log->l_unmount_free; + log->l_unmount_free = t_list++; + log->l_ticket_cnt++; + log->l_ticket_tcnt++; + + /* Next ticket becomes first ticket attached to ticket free list */ + if (log->l_freelist != NULL) { + ASSERT(log->l_tail != NULL); + log->l_tail->t_next = t_list; + } else { + log->l_freelist = t_list; + } + log->l_ticket_cnt++; + log->l_ticket_tcnt++; + + /* Cycle through rest of alloc'ed memory, building up free Q */ + for ( ; i > 0; i--) { + next = t_list + 1; + t_list->t_next = next; + t_list = next; + log->l_ticket_cnt++; + log->l_ticket_tcnt++; + } + t_list->t_next = 0; + log->l_tail = t_list; + LOG_UNLOCK(log, s); +} /* xlog_state_ticket_alloc */ + + +/* + * Put ticket into free list + * + * Assumption: log lock is held around this call. + */ +STATIC void +xlog_ticket_put(xlog_t *log, + xlog_ticket_t *ticket) +{ + sv_destroy(&ticket->t_sema); + + /* + * Don't think caching will make that much difference. It's + * more important to make debug easier. + */ +#if 0 + /* real code will want to use LIFO for caching */ + ticket->t_next = log->l_freelist; + log->l_freelist = ticket; + /* no need to clear fields */ +#else + /* When we debug, it is easier if tickets are cycled */ + ticket->t_next = 0; + if (log->l_tail != 0) { + log->l_tail->t_next = ticket; + } else { + ASSERT(log->l_freelist == 0); + log->l_freelist = ticket; + } + log->l_tail = ticket; +#endif /* DEBUG */ + log->l_ticket_cnt++; +} /* xlog_ticket_put */ + + +/* + * Grab ticket off freelist or allocation some more + */ +xlog_ticket_t * +xlog_ticket_get(xlog_t *log, + int unit_bytes, + int cnt, + char client, + uint xflags) +{ + xlog_ticket_t *tic; + SPLDECL(s); + + alloc: + if (log->l_freelist == NULL) + xlog_state_ticket_alloc(log); /* potentially sleep */ + + s = LOG_LOCK(log); + if (log->l_freelist == NULL) { + LOG_UNLOCK(log, s); + goto alloc; + } + tic = log->l_freelist; + log->l_freelist = tic->t_next; + if (log->l_freelist == NULL) + log->l_tail = NULL; + log->l_ticket_cnt--; + LOG_UNLOCK(log, s); + + /* + * Permanent reservations have up to 'cnt'-1 active log operations + * in the log. A unit in this case is the amount of space for one + * of these log operations. Normal reservations have a cnt of 1 + * and their unit amount is the total amount of space required. + * The following line of code adds one log record header length + * for each part of an operation which may fall on a different + * log record. + * + * One more XLOG_HEADER_SIZE is added to account for possible + * round off errors when syncing a LR to disk. The bytes are + * subtracted if the thread using this ticket is the first writer + * to a new LR. + * + * We add an extra log header for the possibility that the commit + * record is the first data written to a new log record. In this + * case it is separate from the rest of the transaction data and + * will be charged for the log record header. + */ + unit_bytes += log->l_iclog_hsize * (XLOG_BTOLRBB(unit_bytes) + 2); + + tic->t_unit_res = unit_bytes; + tic->t_curr_res = unit_bytes; + tic->t_cnt = cnt; + tic->t_ocnt = cnt; + tic->t_tid = (xlog_tid_t)((__psint_t)tic & 0xffffffff); + tic->t_clientid = client; + tic->t_flags = XLOG_TIC_INITED; + if (xflags & XFS_LOG_PERM_RESERV) + tic->t_flags |= XLOG_TIC_PERM_RESERV; + sv_init(&(tic->t_sema), SV_DEFAULT, "logtick"); + + return tic; +} /* xlog_ticket_get */ + + +/****************************************************************************** + * + * Log debug routines + * + ****************************************************************************** + */ +#if defined(DEBUG) && !defined(XLOG_NOLOG) +/* + * Make sure that the destination ptr is within the valid data region of + * one of the iclogs. This uses backup pointers stored in a different + * part of the log in case we trash the log structure. + */ +void +xlog_verify_dest_ptr(xlog_t *log, + __psint_t ptr) +{ + int i; + int good_ptr = 0; + + for (i=0; i < log->l_iclog_bufs; i++) { + if (ptr >= (__psint_t)log->l_iclog_bak[i] && + ptr <= (__psint_t)log->l_iclog_bak[i]+log->l_iclog_size) + good_ptr++; + } + if (! good_ptr) + xlog_panic("xlog_verify_dest_ptr: invalid ptr"); +} /* xlog_verify_dest_ptr */ + + +#ifdef XFSDEBUG +/* check split LR write */ +STATIC void +xlog_verify_disk_cycle_no(xlog_t *log, + xlog_in_core_t *iclog) +{ + xfs_buf_t *bp; + uint cycle_no; + xfs_daddr_t i; + + if (BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT) < 10) { + cycle_no = CYCLE_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT); + bp = xlog_get_bp(1, log->l_mp); + ASSERT(bp); + for (i = 0; i < BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT); i++) { + xlog_bread(log, i, 1, bp); + if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) != cycle_no) + xlog_warn("XFS: xlog_verify_disk_cycle_no: bad cycle no"); + } + xlog_put_bp(bp); + } +} /* xlog_verify_disk_cycle_no */ +#endif + +STATIC void +xlog_verify_grant_head(xlog_t *log, int equals) +{ + if (log->l_grant_reserve_cycle == log->l_grant_write_cycle) { + if (equals) + ASSERT(log->l_grant_reserve_bytes >= log->l_grant_write_bytes); + else + ASSERT(log->l_grant_reserve_bytes > log->l_grant_write_bytes); + } else { + ASSERT(log->l_grant_reserve_cycle-1 == log->l_grant_write_cycle); + ASSERT(log->l_grant_write_bytes >= log->l_grant_reserve_bytes); + } +} /* xlog_verify_grant_head */ + +/* check if it will fit */ +STATIC void +xlog_verify_tail_lsn(xlog_t *log, + xlog_in_core_t *iclog, + xfs_lsn_t tail_lsn) +{ + int blocks; + + if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) == log->l_prev_cycle) { + blocks = + log->l_logBBsize - (log->l_prev_block - BLOCK_LSN(tail_lsn, ARCH_NOCONVERT)); + if (blocks < BTOBB(iclog->ic_offset)+BTOBB(log->l_iclog_hsize)) + xlog_panic("xlog_verify_tail_lsn: ran out of log space"); + } else { + ASSERT(CYCLE_LSN(tail_lsn, ARCH_NOCONVERT)+1 == log->l_prev_cycle); + + if (BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) == log->l_prev_block) + xlog_panic("xlog_verify_tail_lsn: tail wrapped"); + + blocks = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) - log->l_prev_block; + if (blocks < BTOBB(iclog->ic_offset) + 1) + xlog_panic("xlog_verify_tail_lsn: ran out of log space"); + } +} /* xlog_verify_tail_lsn */ + +/* + * Perform a number of checks on the iclog before writing to disk. + * + * 1. Make sure the iclogs are still circular + * 2. Make sure we have a good magic number + * 3. Make sure we don't have magic numbers in the data + * 4. Check fields of each log operation header for: + * A. Valid client identifier + * B. tid ptr value falls in valid ptr space (user space code) + * C. Length in log record header is correct according to the + * individual operation headers within record. + * 5. When a bwrite will occur within 5 blocks of the front of the physical + * log, check the preceding blocks of the physical log to make sure all + * the cycle numbers agree with the current cycle number. + */ +STATIC void +xlog_verify_iclog(xlog_t *log, + xlog_in_core_t *iclog, + int count, + boolean_t syncing) +{ + xlog_op_header_t *ophead; + xlog_in_core_t *icptr; + xfs_caddr_t ptr; + xfs_caddr_t base_ptr; + __psint_t field_offset; + __uint8_t clientid; + int len, i, j, k, op_len; + int idx; + SPLDECL(s); + + union ich { + xlog_rec_ext_header_t hic_xheader; + char hic_sector[XLOG_HEADER_SIZE]; + }*xhdr; + + /* check validity of iclog pointers */ + s = LOG_LOCK(log); + icptr = log->l_iclog; + for (i=0; i < log->l_iclog_bufs; i++) { + if (icptr == 0) + xlog_panic("xlog_verify_iclog: illegal ptr"); + icptr = icptr->ic_next; + } + if (icptr != log->l_iclog) + xlog_panic("xlog_verify_iclog: corrupt iclog ring"); + LOG_UNLOCK(log, s); + + /* check log magic numbers */ + ptr = (xfs_caddr_t) &(iclog->ic_header); + if (INT_GET(*(uint *)ptr, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) + xlog_panic("xlog_verify_iclog: illegal magic num"); + + for (ptr += BBSIZE; ptr < ((xfs_caddr_t)&(iclog->ic_header))+count; + ptr += BBSIZE) { + if (INT_GET(*(uint *)ptr, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) + xlog_panic("xlog_verify_iclog: unexpected magic num"); + } + + /* check fields */ + len = INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT); + ptr = iclog->ic_datap; + base_ptr = ptr; + ophead = (xlog_op_header_t *)ptr; + xhdr = (union ich*)&iclog->ic_header; + for (i = 0; i < len; i++) { + ophead = (xlog_op_header_t *)ptr; + + /* clientid is only 1 byte */ + field_offset = (__psint_t) + ((xfs_caddr_t)&(ophead->oh_clientid) - base_ptr); + if (syncing == B_FALSE || (field_offset & 0x1ff)) { + clientid = ophead->oh_clientid; + } else { + idx = BTOBB((xfs_caddr_t)&(ophead->oh_clientid) - iclog->ic_datap); + if (idx > (XLOG_HEADER_CYCLE_SIZE / BBSIZE)) { + j = idx / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + k = idx % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + clientid = GET_CLIENT_ID(xhdr[j].hic_xheader.xh_cycle_data[k], ARCH_CONVERT); + } else { + clientid = GET_CLIENT_ID(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); + } + } + if (clientid != XFS_TRANSACTION && clientid != XFS_LOG) + cmn_err(CE_WARN, "xlog_verify_iclog: illegal clientid %d op 0x%p offset 0x%x", clientid, ophead, field_offset); + + /* check length */ + field_offset = (__psint_t) + ((xfs_caddr_t)&(ophead->oh_len) - base_ptr); + if (syncing == B_FALSE || (field_offset & 0x1ff)) { + op_len = INT_GET(ophead->oh_len, ARCH_CONVERT); + } else { + idx = BTOBB((__psint_t)&ophead->oh_len - + (__psint_t)iclog->ic_datap); + if (idx > (XLOG_HEADER_CYCLE_SIZE / BBSIZE)) { + j = idx / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + k = idx % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + op_len = INT_GET(xhdr[j].hic_xheader.xh_cycle_data[k], ARCH_CONVERT); + } else { + op_len = INT_GET(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); + } + } + ptr += sizeof(xlog_op_header_t) + op_len; + } +} /* xlog_verify_iclog */ +#endif /* DEBUG && !XLOG_NOLOG */ + +/* + * Mark all iclogs IOERROR. LOG_LOCK is held by the caller. + */ +STATIC int +xlog_state_ioerror( + xlog_t *log) +{ + xlog_in_core_t *iclog, *ic; + + iclog = log->l_iclog; + if (! (iclog->ic_state & XLOG_STATE_IOERROR)) { + /* + * Mark all the incore logs IOERROR. + * From now on, no log flushes will result. + */ + ic = iclog; + do { + ic->ic_state = XLOG_STATE_IOERROR; + ic = ic->ic_next; + } while (ic != iclog); + return (0); + } + /* + * Return non-zero, if state transition has already happened. + */ + return (1); +} + +/* + * This is called from xfs_force_shutdown, when we're forcibly + * shutting down the filesystem, typically because of an IO error. + * Our main objectives here are to make sure that: + * a. the filesystem gets marked 'SHUTDOWN' for all interested + * parties to find out, 'atomically'. + * b. those who're sleeping on log reservations, pinned objects and + * other resources get woken up, and be told the bad news. + * c. nothing new gets queued up after (a) and (b) are done. + * d. if !logerror, flush the iclogs to disk, then seal them off + * for business. + */ +int +xfs_log_force_umount( + struct xfs_mount *mp, + int logerror) +{ + xlog_ticket_t *tic; + xlog_t *log; + int retval; + SPLDECL(s); + SPLDECL(s2); + + log = mp->m_log; + + /* + * If this happens during log recovery, don't worry about + * locking; the log isn't open for business yet. + */ + if (!log || + log->l_flags & XLOG_ACTIVE_RECOVERY) { + mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; + XFS_BUF_DONE(mp->m_sb_bp); + return (0); + } + + /* + * Somebody could've already done the hard work for us. + * No need to get locks for this. + */ + if (logerror && log->l_iclog->ic_state & XLOG_STATE_IOERROR) { + ASSERT(XLOG_FORCED_SHUTDOWN(log)); + return (1); + } + retval = 0; + /* + * We must hold both the GRANT lock and the LOG lock, + * before we mark the filesystem SHUTDOWN and wake + * everybody up to tell the bad news. + */ + s = GRANT_LOCK(log); + s2 = LOG_LOCK(log); + mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; + XFS_BUF_DONE(mp->m_sb_bp); + /* + * This flag is sort of redundant because of the mount flag, but + * it's good to maintain the separation between the log and the rest + * of XFS. + */ + log->l_flags |= XLOG_IO_ERROR; + + /* + * If we hit a log error, we want to mark all the iclogs IOERROR + * while we're still holding the loglock. + */ + if (logerror) + retval = xlog_state_ioerror(log); + LOG_UNLOCK(log, s2); + + /* + * We don't want anybody waiting for log reservations + * after this. That means we have to wake up everybody + * queued up on reserve_headq as well as write_headq. + * In addition, we make sure in xlog_{re}grant_log_space + * that we don't enqueue anything once the SHUTDOWN flag + * is set, and this action is protected by the GRANTLOCK. + */ + if ((tic = log->l_reserve_headq)) { + do { + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_reserve_headq); + } + + if ((tic = log->l_write_headq)) { + do { + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_write_headq); + } + GRANT_UNLOCK(log, s); + + if (! (log->l_iclog->ic_state & XLOG_STATE_IOERROR)) { + ASSERT(!logerror); + /* + * Force the incore logs to disk before shutting the + * log down completely. + */ + xlog_state_sync_all(log, XFS_LOG_FORCE|XFS_LOG_SYNC); + s2 = LOG_LOCK(log); + retval = xlog_state_ioerror(log); + LOG_UNLOCK(log, s2); + } + /* + * Wake up everybody waiting on xfs_log_force. + * Callback all log item committed functions as if the + * log writes were completed. + */ + xlog_state_do_callback(log, XFS_LI_ABORTED, NULL); + +#ifdef XFSERRORDEBUG + { + xlog_in_core_t *iclog; + + s = LOG_LOCK(log); + iclog = log->l_iclog; + do { + ASSERT(iclog->ic_callback == 0); + iclog = iclog->ic_next; + } while (iclog != log->l_iclog); + LOG_UNLOCK(log, s); + } +#endif + /* return non-zero if log IOERROR transition had already happened */ + return (retval); +} + +int +xlog_iclogs_empty(xlog_t *log) +{ + xlog_in_core_t *iclog; + + iclog = log->l_iclog; + do { + if (INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT)) + return(0); + iclog = iclog->ic_next; + } while (iclog != log->l_iclog); + return(1); +} + diff -Nur linux-2.4.19/fs/xfs/xfs_log.h linux-2.4.19-sgi211r3/fs/xfs/xfs_log.h --- linux-2.4.19/fs/xfs/xfs_log.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_log.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LOG_H__ +#define __XFS_LOG_H__ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LSN_FIELD_CYCLE(arch) (((arch)==ARCH_NOCONVERT)?1:0) +#define LSN_FIELD_BLOCK(arch) (((arch)==ARCH_NOCONVERT)?0:1) +#else +#define LSN_FIELD_CYCLE(arch) (0) +#define LSN_FIELD_BLOCK(arch) (1) +#endif + +/* get lsn fields */ + +#define CYCLE_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch)) +#define BLOCK_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch)) +/* this is used in a spot where we might otherwise double-endian-flip */ +#define CYCLE_LSN_NOCONV(lsn,arch) (((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)]) + +#ifdef __KERNEL__ +/* + * By comparing each compnent, we don't have to worry about extra + * endian issues in treating two 32 bit numbers as one 64 bit number + */ +static +#ifdef __GNUC__ +# if !((__GNUC__ == 2) && (__GNUC_MINOR__ == 95)) +__inline__ +#endif +#endif +xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2, xfs_arch_t arch) +{ + if (CYCLE_LSN(lsn1, arch) != CYCLE_LSN(lsn2, arch)) + return (CYCLE_LSN(lsn1, arch)> XLOG_RECORD_BSHIFT) +#endif + +#define XLOG_HEADER_SIZE 512 + +#define XLOG_TOTAL_REC_SHIFT(log) \ + BTOBB(XLOG_MAX_ICLOGS << (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? \ + XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) + +/* + * set lsns + */ + +#define ASSIGN_LSN_CYCLE(lsn,cycle,arch) \ + INT_SET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch, (cycle)); +#define ASSIGN_LSN_BLOCK(lsn,block,arch) \ + INT_SET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch, (block)); +#define ASSIGN_ANY_LSN(lsn,cycle,block,arch) \ + { \ + ASSIGN_LSN_CYCLE(lsn,cycle,arch); \ + ASSIGN_LSN_BLOCK(lsn,block,arch); \ + } +#define ASSIGN_LSN(lsn,log,arch) \ + ASSIGN_ANY_LSN(lsn,(log)->l_curr_cycle,(log)->l_curr_block,arch); + +#define XLOG_SET(f,b) (((f) & (b)) == (b)) + +#define GET_CYCLE(ptr, arch) \ + (INT_GET(*(uint *)(ptr), arch) == XLOG_HEADER_MAGIC_NUM ? \ + INT_GET(*((uint *)(ptr)+1), arch) : \ + INT_GET(*(uint *)(ptr), arch) \ + ) + +#define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) + + +#ifdef __KERNEL__ +/* + * get client id from packed copy. + * + * this hack is here because the xlog_pack code copies four bytes + * of xlog_op_header containing the fields oh_clientid, oh_flags + * and oh_res2 into the packed copy. + * + * later on this four byte chunk is treated as an int and the + * client id is pulled out. + * + * this has endian issues, of course. + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define GET_CLIENT_ID(i,arch) \ + ((i) & 0xff) +#else +#define GET_CLIENT_ID(i,arch) \ + ((i) >> 24) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_GRANT_SUB_SPACE) +void xlog_grant_sub_space(struct log *log, int bytes, int type); +#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ + xlog_grant_sub_space(log,bytes,type) +#else +#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ + { \ + if (type == 'w') { \ + (log)->l_grant_write_bytes -= (bytes); \ + if ((log)->l_grant_write_bytes < 0) { \ + (log)->l_grant_write_bytes += (log)->l_logsize; \ + (log)->l_grant_write_cycle--; \ + } \ + } else { \ + (log)->l_grant_reserve_bytes -= (bytes); \ + if ((log)->l_grant_reserve_bytes < 0) { \ + (log)->l_grant_reserve_bytes += (log)->l_logsize;\ + (log)->l_grant_reserve_cycle--; \ + } \ + } \ + } +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_GRANT_ADD_SPACE) +void xlog_grant_add_space(struct log *log, int bytes, int type); +#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ + xlog_grant_add_space(log,bytes,type) +#else +#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ + { \ + if (type == 'w') { \ + (log)->l_grant_write_bytes += (bytes); \ + if ((log)->l_grant_write_bytes > (log)->l_logsize) { \ + (log)->l_grant_write_bytes -= (log)->l_logsize; \ + (log)->l_grant_write_cycle++; \ + } \ + } else { \ + (log)->l_grant_reserve_bytes += (bytes); \ + if ((log)->l_grant_reserve_bytes > (log)->l_logsize) { \ + (log)->l_grant_reserve_bytes -= (log)->l_logsize;\ + (log)->l_grant_reserve_cycle++; \ + } \ + } \ + } +#endif +#define XLOG_INS_TICKETQ(q,tic) \ + { \ + if (q) { \ + (tic)->t_next = (q); \ + (tic)->t_prev = (q)->t_prev; \ + (q)->t_prev->t_next = (tic); \ + (q)->t_prev = (tic); \ + } else { \ + (tic)->t_prev = (tic)->t_next = (tic); \ + (q) = (tic); \ + } \ + (tic)->t_flags |= XLOG_TIC_IN_Q; \ + } +#define XLOG_DEL_TICKETQ(q,tic) \ + { \ + if ((tic) == (tic)->t_next) { \ + (q) = NULL; \ + } else { \ + (q) = (tic)->t_next; \ + (tic)->t_next->t_prev = (tic)->t_prev; \ + (tic)->t_prev->t_next = (tic)->t_next; \ + } \ + (tic)->t_next = (tic)->t_prev = NULL; \ + (tic)->t_flags &= ~XLOG_TIC_IN_Q; \ + } + + +#define GRANT_LOCK(log) mutex_spinlock(&(log)->l_grant_lock) +#define GRANT_UNLOCK(log, s) mutex_spinunlock(&(log)->l_grant_lock, s) +#define LOG_LOCK(log) mutex_spinlock(&(log)->l_icloglock) +#define LOG_UNLOCK(log, s) mutex_spinunlock(&(log)->l_icloglock, s) + +#define xlog_panic(s) {cmn_err(CE_PANIC, s); } +#define xlog_exit(s) {cmn_err(CE_PANIC, s); } +#define xlog_warn(s) {cmn_err(CE_WARN, s); } + +/* + * In core log state + */ +#define XLOG_STATE_ACTIVE 0x0001 /* Current IC log being written to */ +#define XLOG_STATE_WANT_SYNC 0x0002 /* Want to sync this iclog; no more writes */ +#define XLOG_STATE_SYNCING 0x0004 /* This IC log is syncing */ +#define XLOG_STATE_DONE_SYNC 0x0008 /* Done syncing to disk */ +#define XLOG_STATE_DO_CALLBACK \ + 0x0010 /* Process callback functions */ +#define XLOG_STATE_CALLBACK 0x0020 /* Callback functions now */ +#define XLOG_STATE_DIRTY 0x0040 /* Dirty IC log, not ready for ACTIVE status*/ +#define XLOG_STATE_IOERROR 0x0080 /* IO error happened in sync'ing log */ +#define XLOG_STATE_ALL 0x7FFF /* All possible valid flags */ +#define XLOG_STATE_NOTUSED 0x8000 /* This IC log not being used */ +#endif /* __KERNEL__ */ + +/* + * Flags to log operation header + * + * The first write of a new transaction will be preceded with a start + * record, XLOG_START_TRANS. Once a transaction is committed, a commit + * record is written, XLOG_COMMIT_TRANS. If a single region can not fit into + * the remainder of the current active in-core log, it is split up into + * multiple regions. Each partial region will be marked with a + * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS. + * + */ +#define XLOG_START_TRANS 0x01 /* Start a new transaction */ +#define XLOG_COMMIT_TRANS 0x02 /* Commit this transaction */ +#define XLOG_CONTINUE_TRANS 0x04 /* Cont this trans into new region */ +#define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */ +#define XLOG_END_TRANS 0x10 /* End a continued transaction */ +#define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */ +#define XLOG_SKIP_TRANS (XLOG_COMMIT_TRANS | XLOG_CONTINUE_TRANS | \ + XLOG_WAS_CONT_TRANS | XLOG_END_TRANS | \ + XLOG_UNMOUNT_TRANS) + +#ifdef __KERNEL__ +/* + * Flags to log ticket + */ +#define XLOG_TIC_INITED 0x1 /* has been initialized */ +#define XLOG_TIC_PERM_RESERV 0x2 /* permanent reservation */ +#define XLOG_TIC_IN_Q 0x4 +#endif /* __KERNEL__ */ + +#define XLOG_UNMOUNT_TYPE 0x556e /* Un for Unmount */ + +/* + * Flags for log structure + */ +#define XLOG_CHKSUM_MISMATCH 0x1 /* used only during recovery */ +#define XLOG_ACTIVE_RECOVERY 0x2 /* in the middle of recovery */ +#define XLOG_RECOVERY_NEEDED 0x4 /* log was recovered */ +#define XLOG_IO_ERROR 0x8 /* log hit an I/O error, and being + shutdown */ +typedef __uint32_t xlog_tid_t; + + +#ifdef __KERNEL__ +/* + * Below are states for covering allocation transactions. + * By covering, we mean changing the h_tail_lsn in the last on-disk + * log write such that no allocation transactions will be re-done during + * recovery after a system crash. Recovery starts at the last on-disk + * log write. + * + * These states are used to insert dummy log entries to cover + * space allocation transactions which can undo non-transactional changes + * after a crash. Writes to a file with space + * already allocated do not result in any transactions. Allocations + * might include space beyond the EOF. So if we just push the EOF a + * little, the last transaction for the file could contain the wrong + * size. If there is no file system activity, after an allocation + * transaction, and the system crashes, the allocation transaction + * will get replayed and the file will be truncated. This could + * be hours/days/... after the allocation occurred. + * + * The fix for this is to do two dummy transactions when the + * system is idle. We need two dummy transaction because the h_tail_lsn + * in the log record header needs to point beyond the last possible + * non-dummy transaction. The first dummy changes the h_tail_lsn to + * the first transaction before the dummy. The second dummy causes + * h_tail_lsn to point to the first dummy. Recovery starts at h_tail_lsn. + * + * These dummy transactions get committed when everything + * is idle (after there has been some activity). + * + * There are 5 states used to control this. + * + * IDLE -- no logging has been done on the file system or + * we are done covering previous transactions. + * NEED -- logging has occurred and we need a dummy transaction + * when the log becomes idle. + * DONE -- we were in the NEED state and have committed a dummy + * transaction. + * NEED2 -- we detected that a dummy transaction has gone to the + * on disk log with no other transactions. + * DONE2 -- we committed a dummy transaction when in the NEED2 state. + * + * There are two places where we switch states: + * + * 1.) In xfs_sync, when we detect an idle log and are in NEED or NEED2. + * We commit the dummy transaction and switch to DONE or DONE2, + * respectively. In all other states, we don't do anything. + * + * 2.) When we finish writing the on-disk log (xlog_state_clean_log). + * + * No matter what state we are in, if this isn't the dummy + * transaction going out, the next state is NEED. + * So, if we aren't in the DONE or DONE2 states, the next state + * is NEED. We can't be finishing a write of the dummy record + * unless it was committed and the state switched to DONE or DONE2. + * + * If we are in the DONE state and this was a write of the + * dummy transaction, we move to NEED2. + * + * If we are in the DONE2 state and this was a write of the + * dummy transaction, we move to IDLE. + * + * + * Writing only one dummy transaction can get appended to + * one file space allocation. When this happens, the log recovery + * code replays the space allocation and a file could be truncated. + * This is why we have the NEED2 and DONE2 states before going idle. + */ + +#define XLOG_STATE_COVER_IDLE 0 +#define XLOG_STATE_COVER_NEED 1 +#define XLOG_STATE_COVER_DONE 2 +#define XLOG_STATE_COVER_NEED2 3 +#define XLOG_STATE_COVER_DONE2 4 + +#define XLOG_COVER_OPS 5 + +typedef struct xlog_ticket { + sv_t t_sema; /* sleep on this semaphore :20 */ + struct xlog_ticket *t_next; /* : 4 */ + struct xlog_ticket *t_prev; /* : 4 */ + xlog_tid_t t_tid; /* transaction identifier : 4 */ + int t_curr_res; /* current reservation in bytes : 4 */ + int t_unit_res; /* unit reservation in bytes : 4 */ + __uint8_t t_ocnt; /* original count : 1 */ + __uint8_t t_cnt; /* current count : 1 */ + __uint8_t t_clientid; /* who does this belong to; : 1 */ + __uint8_t t_flags; /* properties of reservation : 1 */ +} xlog_ticket_t; +#endif + + +typedef struct xlog_op_header { + xlog_tid_t oh_tid; /* transaction id of operation : 4 b */ + int oh_len; /* bytes in data region : 4 b */ + __uint8_t oh_clientid; /* who sent me this : 1 b */ + __uint8_t oh_flags; /* : 1 b */ + ushort oh_res2; /* 32 bit align : 2 b */ +} xlog_op_header_t; + + +/* valid values for h_fmt */ +#define XLOG_FMT_UNKNOWN 0 +#define XLOG_FMT_LINUX_LE 1 +#define XLOG_FMT_LINUX_BE 2 +#define XLOG_FMT_IRIX_BE 3 + +/* our fmt */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define XLOG_FMT XLOG_FMT_LINUX_LE +#else +#if __BYTE_ORDER == __BIG_ENDIAN +#define XLOG_FMT XLOG_FMT_LINUX_BE +#else +#error unknown byte order +#endif +#endif + +typedef struct xlog_rec_header { + uint h_magicno; /* log record (LR) identifier : 4 */ + uint h_cycle; /* write cycle of log : 4 */ + int h_version; /* LR version : 4 */ + int h_len; /* len in bytes; should be 64-bit aligned: 4 */ + xfs_lsn_t h_lsn; /* lsn of this LR : 8 */ + xfs_lsn_t h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ + uint h_chksum; /* may not be used; non-zero if used : 4 */ + int h_prev_block; /* block number to previous LR : 4 */ + int h_num_logops; /* number of log operations in this LR : 4 */ + uint h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; + /* new fields */ + int h_fmt; /* format of log record : 4 */ + uuid_t h_fs_uuid; /* uuid of FS : 16 */ + int h_size; /* iclog size : 4 */ +} xlog_rec_header_t; + +typedef struct xlog_rec_ext_header { + uint xh_cycle; /* write cycle of log : 4 */ + uint xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ +} xlog_rec_ext_header_t; +#ifdef __KERNEL__ +/* + * - A log record header is 512 bytes. There is plenty of room to grow the + * xlog_rec_header_t into the reserved space. + * - ic_data follows, so a write to disk can start at the beginning of + * the iclog. + * - ic_forcesema is used to implement synchronous forcing of the iclog to disk. + * - ic_next is the pointer to the next iclog in the ring. + * - ic_bp is a pointer to the buffer used to write this incore log to disk. + * - ic_log is a pointer back to the global log structure. + * - ic_callback is a linked list of callback function/argument pairs to be + * called after an iclog finishes writing. + * - ic_size is the full size of the header plus data. + * - ic_offset is the current number of bytes written to in this iclog. + * - ic_refcnt is bumped when someone is writing to the log. + * - ic_state is the state of the iclog. + */ +typedef struct xlog_iclog_fields { + sv_t ic_forcesema; + sv_t ic_writesema; + struct xlog_in_core *ic_next; + struct xlog_in_core *ic_prev; + struct xfs_buf *ic_bp; + struct log *ic_log; + xfs_log_callback_t *ic_callback; + xfs_log_callback_t **ic_callback_tail; +#ifdef DEBUG + struct ktrace *ic_trace; +#endif + int ic_size; + int ic_offset; + int ic_refcnt; + int ic_roundoff; + int ic_bwritecnt; + ushort_t ic_state; + char *ic_datap; /* pointer to iclog data */ +} xlog_iclog_fields_t; + +typedef struct xlog_in_core2 { + union { + xlog_rec_header_t hic_header; + xlog_rec_ext_header_t hic_xheader; + char hic_sector[XLOG_HEADER_SIZE]; + } ic_h; +} xlog_in_core_2_t; + +typedef struct xlog_in_core { + xlog_iclog_fields_t hic_fields; + xlog_in_core_2_t *hic_data; +} xlog_in_core_t; + +/* + * Defines to save our code from this glop. + */ +#define ic_forcesema hic_fields.ic_forcesema +#define ic_writesema hic_fields.ic_writesema +#define ic_next hic_fields.ic_next +#define ic_prev hic_fields.ic_prev +#define ic_bp hic_fields.ic_bp +#define ic_log hic_fields.ic_log +#define ic_callback hic_fields.ic_callback +#define ic_callback_tail hic_fields.ic_callback_tail +#define ic_trace hic_fields.ic_trace +#define ic_size hic_fields.ic_size +#define ic_offset hic_fields.ic_offset +#define ic_refcnt hic_fields.ic_refcnt +#define ic_roundoff hic_fields.ic_roundoff +#define ic_bwritecnt hic_fields.ic_bwritecnt +#define ic_state hic_fields.ic_state +#define ic_datap hic_fields.ic_datap +#define ic_header hic_data->ic_h.hic_header + +/* + * The reservation head lsn is not made up of a cycle number and block number. + * Instead, it uses a cycle number and byte number. Logs don't expect to + * overflow 31 bits worth of byte offset, so using a byte number will mean + * that round off problems won't occur when releasing partial reservations. + */ +typedef struct log { + /* The following block of fields are changed while holding icloglock */ + sema_t l_flushsema; /* iclog flushing semaphore */ + int l_flushcnt; /* # of procs waiting on this sema */ + int l_ticket_cnt; /* free ticket count */ + int l_ticket_tcnt; /* total ticket count */ + int l_covered_state;/* state of "covering disk log entries" */ + xlog_ticket_t *l_freelist; /* free list of tickets */ + xlog_ticket_t *l_unmount_free;/* kmem_free these addresses */ + xlog_ticket_t *l_tail; /* free list of tickets */ + xlog_in_core_t *l_iclog; /* head log queue */ + lock_t l_icloglock; /* grab to change iclog state */ + xfs_lsn_t l_tail_lsn; /* lsn of 1st LR w/ unflush buffers */ + xfs_lsn_t l_last_sync_lsn;/* lsn of last LR on disk */ + struct xfs_mount *l_mp; /* mount point */ + struct xfs_buf *l_xbuf; /* extra buffer for log wrapping */ + dev_t l_dev; /* dev_t of log */ + xfs_daddr_t l_logBBstart; /* start block of log */ + int l_logsize; /* size of log in bytes */ + int l_logBBsize; /* size of log in 512 byte chunks */ + int l_roundoff; /* round off error of all iclogs */ + int l_curr_cycle; /* Cycle number of log writes */ + int l_prev_cycle; /* Cycle # b4 last block increment */ + int l_curr_block; /* current logical block of log */ + int l_prev_block; /* previous logical block of log */ + int l_iclog_size; /* size of log in bytes */ + int l_iclog_size_log;/* log power size of log */ + int l_iclog_bufs; /* number of iclog buffers */ + + /* The following field are used for debugging; need to hold icloglock */ + char *l_iclog_bak[XLOG_MAX_ICLOGS]; + + /* The following block of fields are changed while holding grant_lock */ + lock_t l_grant_lock; /* protects below fields */ + xlog_ticket_t *l_reserve_headq; /* */ + xlog_ticket_t *l_write_headq; /* */ + int l_grant_reserve_cycle; /* */ + int l_grant_reserve_bytes; /* */ + int l_grant_write_cycle; /* */ + int l_grant_write_bytes; /* */ + + /* The following fields don't need locking */ +#ifdef DEBUG + struct ktrace *l_trace; + struct ktrace *l_grant_trace; +#endif + uint l_flags; + uint l_quotaoffs_flag;/* XFS_DQ_*, if QUOTAOFFs found */ + struct xfs_buf_cancel **l_buf_cancel_table; + int l_iclog_hsize; /* size of iclog header */ + int l_iclog_heads; /* number of iclog header sectors */ +} xlog_t; + + +/* common routines */ +extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp, + xlog_in_core_t *iclog); +extern int xlog_find_head(xlog_t *log, xfs_daddr_t *head_blk); +extern int xlog_find_tail(xlog_t *log, + xfs_daddr_t *head_blk, + xfs_daddr_t *tail_blk, + int readonly); +extern int xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk); +extern int xlog_recover(xlog_t *log, int readonly); +extern int xlog_recover_finish(xlog_t *log, int mfsi_flags); +extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog); +extern struct xfs_buf *xlog_get_bp(int,xfs_mount_t *); +extern void xlog_put_bp(struct xfs_buf *); +extern int xlog_bread(xlog_t *, xfs_daddr_t blkno, int bblks, struct xfs_buf *bp); +extern void xlog_recover_process_iunlinks(xlog_t *log); + +#define XLOG_TRACE_GRAB_FLUSH 1 +#define XLOG_TRACE_REL_FLUSH 2 +#define XLOG_TRACE_SLEEP_FLUSH 3 +#define XLOG_TRACE_WAKE_FLUSH 4 + +#endif /* __KERNEL__ */ + +#endif /* __XFS_LOG_PRIV_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_log_recover.c linux-2.4.19-sgi211r3/fs/xfs/xfs_log_recover.c --- linux-2.4.19/fs/xfs/xfs_log_recover.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_log_recover.c Fri Jan 10 10:14:15 2003 @@ -0,0 +1,3717 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +STATIC int xlog_find_zeroed(struct log *log, xfs_daddr_t *blk_no); + +STATIC int xlog_clear_stale_blocks(xlog_t *log, xfs_lsn_t tail_lsn); +STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q, + xlog_recover_item_t *item); + +#if defined(DEBUG) +STATIC void xlog_recover_check_summary(xlog_t *log); +STATIC void xlog_recover_check_ail(xfs_mount_t *mp, xfs_log_item_t *lip, + int gen); +#else +#define xlog_recover_check_summary(log) +#define xlog_recover_check_ail(mp, lip, gen) +#endif /* DEBUG */ + + +xfs_buf_t * +xlog_get_bp(int num_bblks,xfs_mount_t *mp) +{ + xfs_buf_t *bp; + + ASSERT(num_bblks > 0); + + bp = XFS_ngetrbuf(BBTOB(num_bblks),mp); + return bp; +} /* xlog_get_bp */ + + +void +xlog_put_bp(xfs_buf_t *bp) +{ + XFS_nfreerbuf(bp); +} /* xlog_put_bp */ + + +/* + * nbblks should be uint, but oh well. Just want to catch that 32-bit length. + */ +int +xlog_bread(xlog_t *log, + xfs_daddr_t blk_no, + int nbblks, + xfs_buf_t *bp) +{ + int error; + + ASSERT(log); + ASSERT(nbblks > 0); + ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); + ASSERT(bp); + + XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); + XFS_BUF_READ(bp); + XFS_BUF_BUSY(bp); + XFS_BUF_SET_COUNT(bp, BBTOB(nbblks)); + XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp); + + xfsbdstrat(log->l_mp, bp); + if ((error = xfs_iowait(bp))) { + xfs_ioerror_alert("xlog_bread", log->l_mp, + bp, XFS_BUF_ADDR(bp)); + return (error); + } + return error; +} /* xlog_bread */ + + +/* + * Write out the buffer at the given block for the given number of blocks. + * The buffer is kept locked across the write and is returned locked. + * This can only be used for synchronous log writes. + */ +int +xlog_bwrite( + xlog_t *log, + int blk_no, + int nbblks, + xfs_buf_t *bp) +{ + int error; + + ASSERT(nbblks > 0); + ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); + + XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); + XFS_BUF_ZEROFLAGS(bp); + XFS_BUF_BUSY(bp); + XFS_BUF_HOLD(bp); + XFS_BUF_PSEMA(bp, PRIBIO); + XFS_BUF_SET_COUNT(bp, BBTOB(nbblks)); + XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp); + + if ((error = xfs_bwrite(log->l_mp, bp))) + xfs_ioerror_alert("xlog_bwrite", log->l_mp, + bp, XFS_BUF_ADDR(bp)); + + return (error); +} /* xlog_bwrite */ + +#ifdef DEBUG +/* + * check log record header for recovery + */ + +static void +xlog_header_check_dump(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + int b; + + printk("xlog_header_check_dump:\n SB : uuid = "); + for (b=0;b<16;b++) printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]); + printk(", fmt = %d\n",XLOG_FMT); + printk(" log: uuid = "); + for (b=0;b<16;b++) printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]); + printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT)); +} +#endif + +/* + * check log record header for recovery + */ + +STATIC int +xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + + /* + * IRIX doesn't write the h_fmt field and leaves it zeroed + * (XLOG_FMT_UNKNOWN). This stops us from trying to recover + * a dirty log created in IRIX. + */ + + if (INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT) { + xlog_warn("XFS: dirty log written in incompatible format - can't recover"); +#ifdef DEBUG + xlog_header_check_dump(mp, head); +#endif + return XFS_ERROR(EFSCORRUPTED); + } else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) { + xlog_warn("XFS: dirty log entry has mismatched uuid - can't recover"); +#ifdef DEBUG + xlog_header_check_dump(mp, head); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + + return 0; +} + +/* + * read the head block of the log and check the header + */ + +STATIC int +xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + + if (uuid_is_nil(&head->h_fs_uuid)) { + + /* + * IRIX doesn't write the h_fs_uuid or h_fmt fields. If + * h_fs_uuid is nil, we assume this log was last mounted + * by IRIX and continue. + */ + + xlog_warn("XFS: nil uuid in log - IRIX style log"); + + } else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) { + xlog_warn("XFS: log has mismatched uuid - can't recover"); +#ifdef DEBUG + xlog_header_check_dump(mp, head); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + + return 0; +} + +STATIC void +xlog_recover_iodone( + struct xfs_buf *bp) +{ + xfs_mount_t *mp; + ASSERT(XFS_BUF_FSPRIVATE(bp, void *)); + + if (XFS_BUF_GETERROR(bp)) { + /* + * We're not going to bother about retrying + * this during recovery. One strike! + */ + mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *); + xfs_ioerror_alert("xlog_recover_iodone", + mp, bp, XFS_BUF_ADDR(bp)); + xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); + } + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + xfs_biodone(bp); +} + +/* + * This routine finds (to an approximation) the first block in the physical + * log which contains the given cycle. It uses a binary search algorithm. + * Note that the algorithm can not be perfect because the disk will not + * necessarily be perfect. + */ +int +xlog_find_cycle_start(xlog_t *log, + xfs_buf_t *bp, + xfs_daddr_t first_blk, + xfs_daddr_t *last_blk, + uint cycle) +{ + xfs_daddr_t mid_blk; + uint mid_cycle; + int error; + + mid_blk = BLK_AVG(first_blk, *last_blk); + while (mid_blk != first_blk && mid_blk != *last_blk) { + if ((error = xlog_bread(log, mid_blk, 1, bp))) + return error; + mid_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (mid_cycle == cycle) { + *last_blk = mid_blk; + /* last_half_cycle == mid_cycle */ + } else { + first_blk = mid_blk; + /* first_half_cycle == mid_cycle */ + } + mid_blk = BLK_AVG(first_blk, *last_blk); + } + ASSERT((mid_blk == first_blk && mid_blk+1 == *last_blk) || + (mid_blk == *last_blk && mid_blk-1 == first_blk)); + + return 0; +} /* xlog_find_cycle_start */ + + +/* + * Check that the range of blocks does not contain the cycle number + * given. The scan needs to occur from front to back and the ptr into the + * region must be updated since a later routine will need to perform another + * test. If the region is completely good, we end up returning the same + * last block number. + * + * Set blkno to -1 if we encounter no errors. This is an invalid block number + * since we don't ever expect logs to get this large. + */ + +STATIC int +xlog_find_verify_cycle( xlog_t *log, + xfs_daddr_t start_blk, + int nbblks, + uint stop_on_cycle_no, + xfs_daddr_t *new_blk) +{ + xfs_daddr_t i, j; + uint cycle; + xfs_buf_t *bp; + char *buf = NULL; + int error = 0; + xfs_daddr_t bufblks; + + bufblks = 1 << ffs(nbblks); + + while (!(bp = xlog_get_bp(bufblks, log->l_mp))) { + /* can't get enough memory to do everything in one big buffer */ + bufblks >>= 1; + if (!bufblks) + return ENOMEM; + } + + + for (i = start_blk; i < start_blk + nbblks; i += bufblks) { + int bcount = min(bufblks, (start_blk + nbblks - i)); + + if ((error = xlog_bread(log, i, bcount, bp))) + goto out; + + buf = XFS_BUF_PTR(bp); + for (j = 0; j < bcount; j++) { + cycle = GET_CYCLE(buf, ARCH_CONVERT); + if (cycle == stop_on_cycle_no) { + *new_blk = i+j; + goto out; + } + + buf += BBSIZE; + } + } + + *new_blk = -1; + +out: + xlog_put_bp(bp); + + return error; +} /* xlog_find_verify_cycle */ + + +/* + * Potentially backup over partial log record write. + * + * In the typical case, last_blk is the number of the block directly after + * a good log record. Therefore, we subtract one to get the block number + * of the last block in the given buffer. extra_bblks contains the number + * of blocks we would have read on a previous read. This happens when the + * last log record is split over the end of the physical log. + * + * extra_bblks is the number of blocks potentially verified on a previous + * call to this routine. + */ + +STATIC int +xlog_find_verify_log_record(xlog_t *log, + xfs_daddr_t start_blk, + xfs_daddr_t *last_blk, + int extra_bblks) +{ + xfs_daddr_t i; + xfs_buf_t *bp; + char *buf = NULL; + xlog_rec_header_t *head = NULL; + int error = 0; + int smallmem = 0; + int num_blks = *last_blk - start_blk; + int xhdrs; + + ASSERT(start_blk != 0 || *last_blk != start_blk); + + if (!(bp = xlog_get_bp(num_blks, log->l_mp))) { + if (!(bp = xlog_get_bp(1, log->l_mp))) + return ENOMEM; + smallmem = 1; + buf = XFS_BUF_PTR(bp); + } else { + if ((error = xlog_bread(log, start_blk, num_blks, bp))) + goto out; + buf = XFS_BUF_PTR(bp) + (num_blks - 1) * BBSIZE; + } + + + for (i=(*last_blk)-1; i>=0; i--) { + if (i < start_blk) { + /* legal log record not found */ + xlog_warn("XFS: Log inconsistent (didn't find previous header)"); + ASSERT(0); + error = XFS_ERROR(EIO); + goto out; + } + + if (smallmem && (error = xlog_bread(log, i, 1, bp))) + goto out; + head = (xlog_rec_header_t*)buf; + + if (INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) + break; + + if (!smallmem) + buf -= BBSIZE; + } + + /* + * We hit the beginning of the physical log & still no header. Return + * to caller. If caller can handle a return of -1, then this routine + * will be called again for the end of the physical log. + */ + if (i == -1) { + error = -1; + goto out; + } + + /* we have the final block of the good log (the first block + * of the log record _before_ the head. So we check the uuid. + */ + + if ((error = xlog_header_check_mount(log->l_mp, head))) + goto out; + + /* + * We may have found a log record header before we expected one. + * last_blk will be the 1st block # with a given cycle #. We may end + * up reading an entire log record. In this case, we don't want to + * reset last_blk. Only when last_blk points in the middle of a log + * record do we update last_blk. + */ + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + int h_size = INT_GET(head->h_size, ARCH_CONVERT); + xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE; + if (h_size % XLOG_HEADER_CYCLE_SIZE) + xhdrs++; + } else { + xhdrs = 1; + } + + if (*last_blk - i + extra_bblks + != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+xhdrs) + *last_blk = i; + +out: + xlog_put_bp(bp); + + return error; +} /* xlog_find_verify_log_record */ + +/* + * Head is defined to be the point of the log where the next log write + * write could go. This means that incomplete LR writes at the end are + * eliminated when calculating the head. We aren't guaranteed that previous + * LR have complete transactions. We only know that a cycle number of + * current cycle number -1 won't be present in the log if we start writing + * from our current block number. + * + * last_blk contains the block number of the first block with a given + * cycle number. + * + * Also called from xfs_log_print.c + * + * Return: zero if normal, non-zero if error. + */ +int +xlog_find_head(xlog_t *log, + xfs_daddr_t *return_head_blk) +{ + xfs_buf_t *bp; + xfs_daddr_t new_blk, first_blk, start_blk, last_blk, head_blk; + int num_scan_bblks; + uint first_half_cycle, last_half_cycle; + uint stop_on_cycle; + int error, log_bbnum = log->l_logBBsize; + + /* Is the end of the log device zeroed? */ + if ((error = xlog_find_zeroed(log, &first_blk)) == -1) { + *return_head_blk = first_blk; + + /* is the whole lot zeroed? */ + if (!first_blk) { + /* Linux XFS shouldn't generate totally zeroed logs - + * mkfs etc write a dummy unmount record to a fresh + * log so we can store the uuid in there + */ + xlog_warn("XFS: totally zeroed log"); + } + + return 0; + } else if (error) { + xlog_warn("XFS: empty log check failed"); + return error; + } + + first_blk = 0; /* get cycle # of 1st block */ + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return ENOMEM; + if ((error = xlog_bread(log, 0, 1, bp))) + goto bp_err; + first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + + last_blk = head_blk = log_bbnum-1; /* get cycle # of last block */ + if ((error = xlog_bread(log, last_blk, 1, bp))) + goto bp_err; + last_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + ASSERT(last_half_cycle != 0); + + /* + * If the 1st half cycle number is equal to the last half cycle number, + * then the entire log is stamped with the same cycle number. In this + * case, head_blk can't be set to zero (which makes sense). The below + * math doesn't work out properly with head_blk equal to zero. Instead, + * we set it to log_bbnum which is an illegal block number, but this + * value makes the math correct. If head_blk doesn't changed through + * all the tests below, *head_blk is set to zero at the very end rather + * than log_bbnum. In a sense, log_bbnum and zero are the same block + * in a circular file. + */ + if (first_half_cycle == last_half_cycle) { + /* + * In this case we believe that the entire log should have cycle + * number last_half_cycle. We need to scan backwards from the + * end verifying that there are no holes still containing + * last_half_cycle - 1. If we find such a hole, then the start + * of that hole will be the new head. The simple case looks like + * x | x ... | x - 1 | x + * Another case that fits this picture would be + * x | x + 1 | x ... | x + * In this case the head really is somwhere at the end of the + * log, as one of the latest writes at the beginning was incomplete. + * One more case is + * x | x + 1 | x ... | x - 1 | x + * This is really the combination of the above two cases, and the + * head has to end up at the start of the x-1 hole at the end of + * the log. + * + * In the 256k log case, we will read from the beginning to the + * end of the log and search for cycle numbers equal to x-1. We + * don't worry about the x+1 blocks that we encounter, because + * we know that they cannot be the head since the log started with + * x. + */ + head_blk = log_bbnum; + stop_on_cycle = last_half_cycle - 1; + } else { + /* + * In this case we want to find the first block with cycle number + * matching last_half_cycle. We expect the log to be some + * variation on + * x + 1 ... | x ... + * The first block with cycle number x (last_half_cycle) will be + * where the new head belongs. First we do a binary search for + * the first occurrence of last_half_cycle. The binary search + * may not be totally accurate, so then we scan back from there + * looking for occurrences of last_half_cycle before us. If + * that backwards scan wraps around the beginning of the log, + * then we look for occurrences of last_half_cycle - 1 at the + * end of the log. The cases we're looking for look like + * x + 1 ... | x | x + 1 | x ... + * ^ binary search stopped here + * or + * x + 1 ... | x ... | x - 1 | x + * <---------> less than scan distance + */ + stop_on_cycle = last_half_cycle; + if ((error = xlog_find_cycle_start(log, bp, first_blk, + &head_blk, last_half_cycle))) + goto bp_err; + } + + /* + * Now validate the answer. Scan back some number of maximum possible + * blocks and make sure each one has the expected cycle number. The + * maximum is determined by the total possible amount of buffering + * in the in-core log. The following number can be made tighter if + * we actually look at the block size of the filesystem. + */ + num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); + if (head_blk >= num_scan_bblks) { + /* + * We are guaranteed that the entire check can be performed + * in one buffer. + */ + start_blk = head_blk - num_scan_bblks; + if ((error = xlog_find_verify_cycle(log, start_blk, num_scan_bblks, + stop_on_cycle, &new_blk))) + goto bp_err; + if (new_blk != -1) + head_blk = new_blk; + } else { /* need to read 2 parts of log */ + /* + * We are going to scan backwards in the log in two parts. First + * we scan the physical end of the log. In this part of the log, + * we are looking for blocks with cycle number last_half_cycle - 1. + * If we find one, then we know that the log starts there, as we've + * found a hole that didn't get written in going around the end + * of the physical log. The simple case for this is + * x + 1 ... | x ... | x - 1 | x + * <---------> less than scan distance + * If all of the blocks at the end of the log have cycle number + * last_half_cycle, then we check the blocks at the start of the + * log looking for occurrences of last_half_cycle. If we find one, + * then our current estimate for the location of the first + * occurrence of last_half_cycle is wrong and we move back to the + * hole we've found. This case looks like + * x + 1 ... | x | x + 1 | x ... + * ^ binary search stopped here + * Another case we need to handle that only occurs in 256k logs is + * x + 1 ... | x ... | x+1 | x ... + * ^ binary search stops here + * In a 256k log, the scan at the end of the log will see the x+1 + * blocks. We need to skip past those since that is certainly not + * the head of the log. By searching for last_half_cycle-1 we + * accomplish that. + */ + start_blk = log_bbnum - num_scan_bblks + head_blk; + ASSERT(head_blk <= INT_MAX && (xfs_daddr_t) num_scan_bblks-head_blk >= 0); + if ((error = xlog_find_verify_cycle(log, start_blk, + num_scan_bblks-(int)head_blk, (stop_on_cycle - 1), + &new_blk))) + goto bp_err; + if (new_blk != -1) { + head_blk = new_blk; + goto bad_blk; + } + + /* + * Scan beginning of log now. The last part of the physical log + * is good. This scan needs to verify that it doesn't find the + * last_half_cycle. + */ + start_blk = 0; + ASSERT(head_blk <= INT_MAX); + if ((error = xlog_find_verify_cycle(log, start_blk, (int) head_blk, + stop_on_cycle, &new_blk))) + goto bp_err; + if (new_blk != -1) + head_blk = new_blk; + } + +bad_blk: + /* + * Now we need to make sure head_blk is not pointing to a block in + * the middle of a log record. + */ + num_scan_bblks = BTOBB(XLOG_MAX_RECORD_BSIZE); + if (head_blk >= num_scan_bblks) { + start_blk = head_blk - num_scan_bblks; /* don't read head_blk */ + + /* start ptr at last block ptr before head_blk */ + if ((error = xlog_find_verify_log_record(log, + start_blk, + &head_blk, + 0)) == -1) { + error = XFS_ERROR(EIO); + goto bp_err; + } else if (error) + goto bp_err; + } else { + start_blk = 0; + ASSERT(head_blk <= INT_MAX); + if ((error = xlog_find_verify_log_record(log, + start_blk, + &head_blk, + 0)) == -1) { + /* We hit the beginning of the log during our search */ + start_blk = log_bbnum - num_scan_bblks + head_blk; + new_blk = log_bbnum; + ASSERT(start_blk <= INT_MAX && (xfs_daddr_t) log_bbnum-start_blk >= 0); + ASSERT(head_blk <= INT_MAX); + if ((error = xlog_find_verify_log_record(log, + start_blk, + &new_blk, + (int)head_blk)) == -1) { + error = XFS_ERROR(EIO); + goto bp_err; + } else if (error) + goto bp_err; + if (new_blk != log_bbnum) + head_blk = new_blk; + } else if (error) + goto bp_err; + } + + xlog_put_bp(bp); + if (head_blk == log_bbnum) + *return_head_blk = 0; + else + *return_head_blk = head_blk; + /* + * When returning here, we have a good block number. Bad block + * means that during a previous crash, we didn't have a clean break + * from cycle number N to cycle number N-1. In this case, we need + * to find the first block with cycle number N-1. + */ + return 0; + +bp_err: + xlog_put_bp(bp); + + if (error) + xlog_warn("XFS: failed to find log head"); + + return error; +} /* xlog_find_head */ + +/* + * Find the sync block number or the tail of the log. + * + * This will be the block number of the last record to have its + * associated buffers synced to disk. Every log record header has + * a sync lsn embedded in it. LSNs hold block numbers, so it is easy + * to get a sync block number. The only concern is to figure out which + * log record header to believe. + * + * The following algorithm uses the log record header with the largest + * lsn. The entire log record does not need to be valid. We only care + * that the header is valid. + * + * We could speed up search by using current head_blk buffer, but it is not + * available. + */ +int +xlog_find_tail(xlog_t *log, + xfs_daddr_t *head_blk, + xfs_daddr_t *tail_blk, + int readonly) +{ + xlog_rec_header_t *rhead; + xlog_op_header_t *op_head; + xfs_buf_t *bp; + int error, i, found; + xfs_daddr_t umount_data_blk; + xfs_daddr_t after_umount_blk; + xfs_lsn_t tail_lsn; + int hblks; + + found = 0; + + /* + * Find previous log record + */ + if ((error = xlog_find_head(log, head_blk))) + return error; + + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return ENOMEM; + if (*head_blk == 0) { /* special case */ + if ((error = xlog_bread(log, 0, 1, bp))) + goto bread_err; + if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) == 0) { + *tail_blk = 0; + /* leave all other log inited values alone */ + goto exit; + } + } + + /* + * Search backwards looking for log record header block + */ + ASSERT(*head_blk < INT_MAX); + for (i = (int)(*head_blk) - 1; i >= 0; i--) { + if ((error = xlog_bread(log, i, 1, bp))) + goto bread_err; + if (XLOG_HEADER_MAGIC_NUM == + INT_GET(*(uint *)(XFS_BUF_PTR(bp)), ARCH_CONVERT)) { + found = 1; + break; + } + } + /* + * If we haven't found the log record header block, start looking + * again from the end of the physical log. XXXmiken: There should be + * a check here to make sure we didn't search more than N blocks in + * the previous code. + */ + if (!found) { + for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) { + if ((error = xlog_bread(log, i, 1, bp))) + goto bread_err; + if (XLOG_HEADER_MAGIC_NUM == + INT_GET(*(uint*)(XFS_BUF_PTR(bp)), ARCH_CONVERT)) { + found = 2; + break; + } + } + } + if (!found) { + xlog_warn("XFS: xlog_find_tail: couldn't find sync record"); + ASSERT(0); + return XFS_ERROR(EIO); + } + + /* find blk_no of tail of log */ + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(bp); + *tail_blk = BLOCK_LSN(rhead->h_tail_lsn, ARCH_CONVERT); + + /* + * Reset log values according to the state of the log when we + * crashed. In the case where head_blk == 0, we bump curr_cycle + * one because the next write starts a new cycle rather than + * continuing the cycle of the last good log record. At this + * point we have guaranteed that all partial log records have been + * accounted for. Therefore, we know that the last good log record + * written was complete and ended exactly on the end boundary + * of the physical log. + */ + log->l_prev_block = i; + log->l_curr_block = (int)*head_blk; + log->l_curr_cycle = INT_GET(rhead->h_cycle, ARCH_CONVERT); + if (found == 2) + log->l_curr_cycle++; + log->l_tail_lsn = INT_GET(rhead->h_tail_lsn, ARCH_CONVERT); + log->l_last_sync_lsn = INT_GET(rhead->h_lsn, ARCH_CONVERT); + log->l_grant_reserve_cycle = log->l_curr_cycle; + log->l_grant_reserve_bytes = BBTOB(log->l_curr_block); + log->l_grant_write_cycle = log->l_curr_cycle; + log->l_grant_write_bytes = BBTOB(log->l_curr_block); + + /* + * Look for unmount record. If we find it, then we know there + * was a clean unmount. Since 'i' could be the last block in + * the physical log, we convert to a log block before comparing + * to the head_blk. + * + * Save the current tail lsn to use to pass to + * xlog_clear_stale_blocks() below. We won't want to clear the + * unmount record if there is one, so we pass the lsn of the + * unmount record rather than the block after it. + */ + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + int h_size = INT_GET(rhead->h_size, ARCH_CONVERT); + int h_version = INT_GET(rhead->h_version, ARCH_CONVERT); + + if ((h_version & XLOG_VERSION_2) && + (h_size > XLOG_HEADER_CYCLE_SIZE)) { + hblks = h_size / XLOG_HEADER_CYCLE_SIZE; + if (h_size % XLOG_HEADER_CYCLE_SIZE) + hblks++; + } else { + hblks = 1; + } + } else { + hblks = 1; + } + after_umount_blk = (i + hblks + (int) + BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT))) % log->l_logBBsize; + tail_lsn = log->l_tail_lsn; + if (*head_blk == after_umount_blk && + INT_GET(rhead->h_num_logops, ARCH_CONVERT) == 1) { + umount_data_blk = (i + hblks) % log->l_logBBsize; + if ((error = xlog_bread(log, umount_data_blk, 1, bp))) { + goto bread_err; + } + op_head = (xlog_op_header_t *)XFS_BUF_PTR(bp); + if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { + /* + * Set tail and last sync so that newly written + * log records will point recovery to after the + * current unmount record. + */ + ASSIGN_ANY_LSN(log->l_tail_lsn, log->l_curr_cycle, + after_umount_blk, ARCH_NOCONVERT); + ASSIGN_ANY_LSN(log->l_last_sync_lsn, log->l_curr_cycle, + after_umount_blk, ARCH_NOCONVERT); + *tail_blk = after_umount_blk; + } + } + +#ifdef __KERNEL__ + /* + * Make sure that there are no blocks in front of the head + * with the same cycle number as the head. This can happen + * because we allow multiple outstanding log writes concurrently, + * and the later writes might make it out before earlier ones. + * + * We use the lsn from before modifying it so that we'll never + * overwrite the unmount record after a clean unmount. + * + * Do this only if we are going to recover the filesystem + * + * NOTE: This used to say "if (!readonly)" + * However on Linux, we can & do recover a read-only filesystem. + * We only skip recovery if NORECOVERY is specified on mount, + * in which case we would not be here. + * + * But... if the -device- itself is readonly, just skip this. + * We can't recover this device anyway, so it won't matter. + */ + + if (!is_read_only(log->l_mp->m_logdev_targp->pbr_kdev)) { + error = xlog_clear_stale_blocks(log, tail_lsn); + } +#endif + +bread_err: +exit: + xlog_put_bp(bp); + + if (error) + xlog_warn("XFS: failed to locate log tail"); + + return error; +} /* xlog_find_tail */ + + +/* + * Is the log zeroed at all? + * + * The last binary search should be changed to perform an X block read + * once X becomes small enough. You can then search linearly through + * the X blocks. This will cut down on the number of reads we need to do. + * + * If the log is partially zeroed, this routine will pass back the blkno + * of the first block with cycle number 0. It won't have a complete LR + * preceding it. + * + * Return: + * 0 => the log is completely written to + * -1 => use *blk_no as the first block of the log + * >0 => error has occurred + */ +int +xlog_find_zeroed(struct log *log, + xfs_daddr_t *blk_no) +{ + xfs_buf_t *bp; + uint first_cycle, last_cycle; + xfs_daddr_t new_blk, last_blk, start_blk; + xfs_daddr_t num_scan_bblks; + int error, log_bbnum = log->l_logBBsize; + + error = 0; + /* check totally zeroed log */ + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return ENOMEM; + if ((error = xlog_bread(log, 0, 1, bp))) + goto bp_err; + first_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (first_cycle == 0) { /* completely zeroed log */ + *blk_no = 0; + xlog_put_bp(bp); + return -1; + } + + /* check partially zeroed log */ + if ((error = xlog_bread(log, log_bbnum-1, 1, bp))) + goto bp_err; + last_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (last_cycle != 0) { /* log completely written to */ + xlog_put_bp(bp); + return 0; + } else if (first_cycle != 1) { + /* + * If the cycle of the last block is zero, the cycle of + * the first block must be 1. If it's not, maybe we're + * not looking at a log... Bail out. + */ + xlog_warn("XFS: Log inconsistent or not a log (last==0, first!=1)"); + return XFS_ERROR(EINVAL); + } + + /* we have a partially zeroed log */ + last_blk = log_bbnum-1; + if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0))) + goto bp_err; + + /* + * Validate the answer. Because there is no way to guarantee that + * the entire log is made up of log records which are the same size, + * we scan over the defined maximum blocks. At this point, the maximum + * is not chosen to mean anything special. XXXmiken + */ + num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); + ASSERT(num_scan_bblks <= INT_MAX); + + if (last_blk < num_scan_bblks) + num_scan_bblks = last_blk; + start_blk = last_blk - num_scan_bblks; + + /* + * We search for any instances of cycle number 0 that occur before + * our current estimate of the head. What we're trying to detect is + * 1 ... | 0 | 1 | 0... + * ^ binary search ends here + */ + if ((error = xlog_find_verify_cycle(log, start_blk, + (int)num_scan_bblks, 0, &new_blk))) + goto bp_err; + if (new_blk != -1) + last_blk = new_blk; + + /* + * Potentially backup over partial log record write. We don't need + * to search the end of the log because we know it is zero. + */ + if ((error = xlog_find_verify_log_record(log, start_blk, + &last_blk, 0)) == -1) { + error = XFS_ERROR(EIO); + goto bp_err; + } else if (error) + goto bp_err; + + *blk_no = last_blk; +bp_err: + xlog_put_bp(bp); + if (error) + return error; + return -1; +} /* xlog_find_zeroed */ + +/* + * This is simply a subroutine used by xlog_clear_stale_blocks() below + * to initialize a buffer full of empty log record headers and write + * them into the log. + */ +STATIC int +xlog_write_log_records( + xlog_t *log, + int cycle, + int start_block, + int blocks, + int tail_cycle, + int tail_block) +{ + xlog_rec_header_t *recp; + int i, j; + int end_block = start_block + blocks; + int error = 0; + xfs_buf_t *bp; + char *buf; + int bufblks; + + bufblks = 1 << ffs(blocks); + while (!(bp = xlog_get_bp(bufblks, log->l_mp))) { + bufblks >>= 1; + if (!bufblks) + return ENOMEM; + } + + buf = XFS_BUF_PTR(bp); + recp = (xlog_rec_header_t*)buf; + + memset(buf, 0, BBSIZE); + INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(recp->h_cycle, ARCH_CONVERT, cycle); + INT_SET(recp->h_version, ARCH_CONVERT, + XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); + ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT); + + for (i = start_block; i < end_block; i += bufblks) { + int bcount = min(bufblks, end_block - start_block); + /* with plenty of memory, we duplicate the block + * right through the buffer and modify each entry + */ + ASSIGN_ANY_LSN(recp->h_lsn, cycle, i, ARCH_CONVERT); + for (j = 1; j < bcount; j++) { + buf += BBSIZE; + recp = (xlog_rec_header_t*)buf; + memcpy(buf, XFS_BUF_PTR(bp), BBSIZE); + ASSIGN_ANY_LSN(recp->h_lsn, cycle, i+j, ARCH_CONVERT); + } + /* then write the whole lot out at once */ + error = xlog_bwrite(log, start_block, bcount, bp); + start_block += bcount; + buf = XFS_BUF_PTR(bp); + recp = (xlog_rec_header_t*)buf; + } + xlog_put_bp(bp); + + return error; +} + +/* + * This routine is called to blow away any incomplete log writes out + * in front of the log head. We do this so that we won't become confused + * if we come up, write only a little bit more, and then crash again. + * If we leave the partial log records out there, this situation could + * cause us to think those partial writes are valid blocks since they + * have the current cycle number. We get rid of them by overwriting them + * with empty log records with the old cycle number rather than the + * current one. + * + * The tail lsn is passed in rather than taken from + * the log so that we will not write over the unmount record after a + * clean unmount in a 512 block log. Doing so would leave the log without + * any valid log records in it until a new one was written. If we crashed + * during that time we would not be able to recover. + */ +STATIC int +xlog_clear_stale_blocks( + xlog_t *log, + xfs_lsn_t tail_lsn) +{ + int tail_cycle; + int head_cycle; + int tail_block; + int head_block; + int tail_distance; + int max_distance; + int distance; + int error; + + tail_cycle = CYCLE_LSN(tail_lsn, ARCH_NOCONVERT); + tail_block = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT); + head_cycle = log->l_curr_cycle; + head_block = log->l_curr_block; + + /* + * Figure out the distance between the new head of the log + * and the tail. We want to write over any blocks beyond the + * head that we may have written just before the crash, but + * we don't want to overwrite the tail of the log. + */ + if (head_cycle == tail_cycle) { + /* + * The tail is behind the head in the physical log, + * so the distance from the head to the tail is the + * distance from the head to the end of the log plus + * the distance from the beginning of the log to the + * tail. + */ + if (head_block < tail_block || head_block >= log->l_logBBsize) + return XFS_ERROR(EFSCORRUPTED); + tail_distance = tail_block + + (log->l_logBBsize - head_block); + } else { + /* + * The head is behind the tail in the physical log, + * so the distance from the head to the tail is just + * the tail block minus the head block. + */ + if (head_block >= tail_block || head_cycle != (tail_cycle + 1)) + return XFS_ERROR(EFSCORRUPTED); + tail_distance = tail_block - head_block; + } + + /* + * If the head is right up against the tail, we can't clear + * anything. + */ + if (tail_distance <= 0) { + ASSERT(tail_distance == 0); + return 0; + } + + max_distance = XLOG_TOTAL_REC_SHIFT(log); + /* + * Take the smaller of the maximum amount of outstanding I/O + * we could have and the distance to the tail to clear out. + * We take the smaller so that we don't overwrite the tail and + * we don't waste all day writing from the head to the tail + * for no reason. + */ + max_distance = MIN(max_distance, tail_distance); + + if ((head_block + max_distance) <= log->l_logBBsize) { + /* + * We can stomp all the blocks we need to without + * wrapping around the end of the log. Just do it + * in a single write. Use the cycle number of the + * current cycle minus one so that the log will look like: + * n ... | n - 1 ... + */ + error = xlog_write_log_records(log, (head_cycle - 1), + head_block, max_distance, tail_cycle, + tail_block); + if (error) + return error; + } else { + /* + * We need to wrap around the end of the physical log in + * order to clear all the blocks. Do it in two separate + * I/Os. The first write should be from the head to the + * end of the physical log, and it should use the current + * cycle number minus one just like above. + */ + distance = log->l_logBBsize - head_block; + error = xlog_write_log_records(log, (head_cycle - 1), + head_block, distance, tail_cycle, + tail_block); + + if (error) + return error; + + /* + * Now write the blocks at the start of the physical log. + * This writes the remainder of the blocks we want to clear. + * It uses the current cycle number since we're now on the + * same cycle as the head so that we get: + * n ... n ... | n - 1 ... + * ^^^^^ blocks we're writing + */ + distance = max_distance - (log->l_logBBsize - head_block); + error = xlog_write_log_records(log, head_cycle, 0, distance, + tail_cycle, tail_block); + if (error) + return error; + } + + return 0; +} + +/****************************************************************************** + * + * Log recover routines + * + ****************************************************************************** + */ + +STATIC xlog_recover_t * +xlog_recover_find_tid(xlog_recover_t *q, + xlog_tid_t tid) +{ + xlog_recover_t *p = q; + + while (p != NULL) { + if (p->r_log_tid == tid) + break; + p = p->r_next; + } + return p; +} /* xlog_recover_find_tid */ + + +STATIC void +xlog_recover_put_hashq(xlog_recover_t **q, + xlog_recover_t *trans) +{ + trans->r_next = *q; + *q = trans; +} /* xlog_recover_put_hashq */ + + +STATIC void +xlog_recover_add_item(xlog_recover_item_t **itemq) +{ + xlog_recover_item_t *item; + + item = kmem_zalloc(sizeof(xlog_recover_item_t), 0); + xlog_recover_insert_item_backq(itemq, item); +} /* xlog_recover_add_item */ + + +STATIC int +xlog_recover_add_to_cont_trans(xlog_recover_t *trans, + xfs_caddr_t dp, + int len) +{ + xlog_recover_item_t *item; + xfs_caddr_t ptr, old_ptr; + int old_len; + + item = trans->r_itemq; + if (item == 0) { + /* finish copying rest of trans header */ + xlog_recover_add_item(&trans->r_itemq); + ptr = (xfs_caddr_t)&trans->r_theader+sizeof(xfs_trans_header_t)-len; + bcopy(dp, ptr, len); /* s, d, l */ + return 0; + } + item = item->ri_prev; + + old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; + old_len = item->ri_buf[item->ri_cnt-1].i_len; + + ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0); + bcopy(dp , &ptr[old_len], len); /* s, d, l */ + item->ri_buf[item->ri_cnt-1].i_len += len; + item->ri_buf[item->ri_cnt-1].i_addr = ptr; + return 0; +} /* xlog_recover_add_to_cont_trans */ + + +/* The next region to add is the start of a new region. It could be + * a whole region or it could be the first part of a new region. Because + * of this, the assumption here is that the type and size fields of all + * format structures fit into the first 32 bits of the structure. + * + * This works because all regions must be 32 bit aligned. Therefore, we + * either have both fields or we have neither field. In the case we have + * neither field, the data part of the region is zero length. We only have + * a log_op_header and can throw away the header since a new one will appear + * later. If we have at least 4 bytes, then we can determine how many regions + * will appear in the current log item. + */ +STATIC int +xlog_recover_add_to_trans(xlog_recover_t *trans, + xfs_caddr_t dp, + int len) +{ + xfs_inode_log_format_t *in_f; /* any will do */ + xlog_recover_item_t *item; + xfs_caddr_t ptr; + + if (!len) + return 0; + ptr = kmem_zalloc(len, 0); + bcopy(dp, ptr, len); + + in_f = (xfs_inode_log_format_t *)ptr; + item = trans->r_itemq; + if (item == 0) { + ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC); + if (len == sizeof(xfs_trans_header_t)) + xlog_recover_add_item(&trans->r_itemq); + bcopy(dp, &trans->r_theader, len); /* s, d, l */ + return 0; + } + if (item->ri_prev->ri_total != 0 && + item->ri_prev->ri_total == item->ri_prev->ri_cnt) { + xlog_recover_add_item(&trans->r_itemq); + } + item = trans->r_itemq; + item = item->ri_prev; + + if (item->ri_total == 0) { /* first region to be added */ + item->ri_total = in_f->ilf_size; + ASSERT(item->ri_total <= XLOG_MAX_REGIONS_IN_ITEM); + item->ri_buf = kmem_zalloc((item->ri_total * + sizeof(xfs_log_iovec_t)), 0); + } + ASSERT(item->ri_total > item->ri_cnt); + /* Description region is ri_buf[0] */ + item->ri_buf[item->ri_cnt].i_addr = ptr; + item->ri_buf[item->ri_cnt].i_len = len; + item->ri_cnt++; + return 0; +} /* xlog_recover_add_to_trans */ + + +STATIC void +xlog_recover_new_tid(xlog_recover_t **q, + xlog_tid_t tid, + xfs_lsn_t lsn) +{ + xlog_recover_t *trans; + + trans = kmem_zalloc(sizeof(xlog_recover_t), 0); + trans->r_log_tid = tid; + trans->r_lsn = lsn; + xlog_recover_put_hashq(q, trans); +} /* xlog_recover_new_tid */ + + +STATIC int +xlog_recover_unlink_tid(xlog_recover_t **q, + xlog_recover_t *trans) +{ + xlog_recover_t *tp; + int found = 0; + + ASSERT(trans != 0); + if (trans == *q) { + *q = (*q)->r_next; + } else { + tp = *q; + while (tp != 0) { + if (tp->r_next == trans) { + found = 1; + break; + } + tp = tp->r_next; + } + if (!found) { + xlog_warn( + "XFS: xlog_recover_unlink_tid: trans not found"); + ASSERT(0); + return XFS_ERROR(EIO); + } + tp->r_next = tp->r_next->r_next; + } + return 0; +} /* xlog_recover_unlink_tid */ + +STATIC void +xlog_recover_insert_item_backq(xlog_recover_item_t **q, + xlog_recover_item_t *item) +{ + if (*q == 0) { + item->ri_prev = item->ri_next = item; + *q = item; + } else { + item->ri_next = *q; + item->ri_prev = (*q)->ri_prev; + (*q)->ri_prev = item; + item->ri_prev->ri_next = item; + } +} /* xlog_recover_insert_item_backq */ + +STATIC void +xlog_recover_insert_item_frontq(xlog_recover_item_t **q, + xlog_recover_item_t *item) +{ + xlog_recover_insert_item_backq(q, item); + *q = item; +} /* xlog_recover_insert_item_frontq */ + +STATIC int +xlog_recover_reorder_trans(xlog_t *log, + xlog_recover_t *trans) +{ + xlog_recover_item_t *first_item, *itemq, *itemq_next; + + first_item = itemq = trans->r_itemq; + trans->r_itemq = NULL; + do { + itemq_next = itemq->ri_next; + switch (ITEM_TYPE(itemq)) { + case XFS_LI_BUF: + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: { + xlog_recover_insert_item_frontq(&trans->r_itemq, itemq); + break; + } + case XFS_LI_INODE: + case XFS_LI_6_1_INODE: + case XFS_LI_5_3_INODE: + case XFS_LI_DQUOT: + case XFS_LI_QUOTAOFF: + case XFS_LI_EFD: + case XFS_LI_EFI: { + xlog_recover_insert_item_backq(&trans->r_itemq, itemq); + break; + } + default: { + xlog_warn( + "XFS: xlog_recover_reorder_trans: unrecognized type of log operation"); + ASSERT(0); + return XFS_ERROR(EIO); + } + } + itemq = itemq_next; + } while (first_item != itemq); + return 0; +} /* xlog_recover_reorder_trans */ + + +/* + * Build up the table of buf cancel records so that we don't replay + * cancelled data in the second pass. For buffer records that are + * not cancel records, there is nothing to do here so we just return. + * + * If we get a cancel record which is already in the table, this indicates + * that the buffer was cancelled multiple times. In order to ensure + * that during pass 2 we keep the record in the table until we reach its + * last occurrence in the log, we keep a reference count in the cancel + * record in the table to tell us how many times we expect to see this + * record during the second pass. + */ +STATIC void +xlog_recover_do_buffer_pass1(xlog_t *log, + xfs_buf_log_format_t *buf_f) +{ + xfs_buf_cancel_t *bcp; + xfs_buf_cancel_t *nextp; + xfs_buf_cancel_t *prevp; + xfs_buf_cancel_t **bucket; + xfs_buf_log_format_v1_t *obuf_f; + xfs_daddr_t blkno=0; + uint len=0; + ushort flags=0; + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + blkno = buf_f->blf_blkno; + len = buf_f->blf_len; + flags = buf_f->blf_flags; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + blkno = (xfs_daddr_t) obuf_f->blf_blkno; + len = obuf_f->blf_len; + flags = obuf_f->blf_flags; + break; + } + + /* + * If this isn't a cancel buffer item, then just return. + */ + if (!(flags & XFS_BLI_CANCEL)) { + return; + } + + /* + * Insert an xfs_buf_cancel record into the hash table of + * them. If there is already an identical record, bump + * its reference count. + */ + bucket = &log->l_buf_cancel_table[(__uint64_t)blkno % + XLOG_BC_TABLE_SIZE]; + /* + * If the hash bucket is empty then just insert a new record into + * the bucket. + */ + if (*bucket == NULL) { + bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t), + KM_SLEEP); + bcp->bc_blkno = blkno; + bcp->bc_len = len; + bcp->bc_refcount = 1; + bcp->bc_next = NULL; + *bucket = bcp; + return; + } + + /* + * The hash bucket is not empty, so search for duplicates of our + * record. If we find one them just bump its refcount. If not + * then add us at the end of the list. + */ + prevp = NULL; + nextp = *bucket; + while (nextp != NULL) { + if (nextp->bc_blkno == blkno && nextp->bc_len == len) { + nextp->bc_refcount++; + return; + } + prevp = nextp; + nextp = nextp->bc_next; + } + ASSERT(prevp != NULL); + bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t), + KM_SLEEP); + bcp->bc_blkno = blkno; + bcp->bc_len = len; + bcp->bc_refcount = 1; + bcp->bc_next = NULL; + prevp->bc_next = bcp; +} + +/* + * Check to see whether the buffer being recovered has a corresponding + * entry in the buffer cancel record table. If it does then return 1 + * so that it will be cancelled, otherwise return 0. If the buffer is + * actually a buffer cancel item (XFS_BLI_CANCEL is set), then decrement + * the refcount on the entry in the table and remove it from the table + * if this is the last reference. + * + * We remove the cancel record from the table when we encounter its + * last occurrence in the log so that if the same buffer is re-used + * again after its last cancellation we actually replay the changes + * made at that point. + */ +STATIC int +xlog_recover_do_buffer_pass2(xlog_t *log, + xfs_buf_log_format_t *buf_f) +{ + xfs_buf_cancel_t *bcp; + xfs_buf_cancel_t *prevp; + xfs_buf_cancel_t **bucket; + xfs_buf_log_format_v1_t *obuf_f; + xfs_daddr_t blkno=0; + ushort flags=0; + uint len=0; + + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + blkno = buf_f->blf_blkno; + flags = buf_f->blf_flags; + len = buf_f->blf_len; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + blkno = (xfs_daddr_t) obuf_f->blf_blkno; + flags = obuf_f->blf_flags; + len = (xfs_daddr_t) obuf_f->blf_len; + break; + } + if (log->l_buf_cancel_table == NULL) { + /* + * There is nothing in the table built in pass one, + * so this buffer must not be cancelled. + */ + ASSERT(!(flags & XFS_BLI_CANCEL)); + return 0; + } + + bucket = &log->l_buf_cancel_table[(__uint64_t)blkno % + XLOG_BC_TABLE_SIZE]; + bcp = *bucket; + if (bcp == NULL) { + /* + * There is no corresponding entry in the table built + * in pass one, so this buffer has not been cancelled. + */ + ASSERT(!(flags & XFS_BLI_CANCEL)); + return 0; + } + + /* + * Search for an entry in the buffer cancel table that + * matches our buffer. + */ + prevp = NULL; + while (bcp != NULL) { + if (bcp->bc_blkno == blkno && bcp->bc_len == len) { + /* + * We've go a match, so return 1 so that the + * recovery of this buffer is cancelled. + * If this buffer is actually a buffer cancel + * log item, then decrement the refcount on the + * one in the table and remove it if this is the + * last reference. + */ + if (flags & XFS_BLI_CANCEL) { + bcp->bc_refcount--; + if (bcp->bc_refcount == 0) { + if (prevp == NULL) { + *bucket = bcp->bc_next; + } else { + prevp->bc_next = bcp->bc_next; + } + kmem_free(bcp, + sizeof(xfs_buf_cancel_t)); + } + } + return 1; + } + prevp = bcp; + bcp = bcp->bc_next; + } + /* + * We didn't find a corresponding entry in the table, so + * return 0 so that the buffer is NOT cancelled. + */ + ASSERT(!(flags & XFS_BLI_CANCEL)); + return 0; +} + + +/* + * Perform recovery for a buffer full of inodes. In these buffers, + * the only data which should be recovered is that which corresponds + * to the di_next_unlinked pointers in the on disk inode structures. + * The rest of the data for the inodes is always logged through the + * inodes themselves rather than the inode buffer and is recovered + * in xlog_recover_do_inode_trans(). + * + * The only time when buffers full of inodes are fully recovered is + * when the buffer is full of newly allocated inodes. In this case + * the buffer will not be marked as an inode buffer and so will be + * sent to xlog_recover_do_reg_buffer() below during recovery. + */ +STATIC int +xlog_recover_do_inode_buffer(xfs_mount_t *mp, + xlog_recover_item_t *item, + xfs_buf_t *bp, + xfs_buf_log_format_t *buf_f) +{ + int i; + int item_index; + int bit; + int nbits; + int reg_buf_offset; + int reg_buf_bytes; + int next_unlinked_offset; + int inodes_per_buf; + xfs_agino_t *logged_nextp; + xfs_agino_t *buffer_nextp; + xfs_buf_log_format_v1_t *obuf_f; + unsigned int *data_map=NULL; + unsigned int map_size=0; + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + data_map = buf_f->blf_data_map; + map_size = buf_f->blf_map_size; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + data_map = obuf_f->blf_data_map; + map_size = obuf_f->blf_map_size; + break; + } + /* + * Set the variables corresponding to the current region to + * 0 so that we'll initialize them on the first pass through + * the loop. + */ + reg_buf_offset = 0; + reg_buf_bytes = 0; + bit = 0; + nbits = 0; + item_index = 0; + inodes_per_buf = XFS_BUF_COUNT(bp) >> mp->m_sb.sb_inodelog; + for (i = 0; i < inodes_per_buf; i++) { + next_unlinked_offset = (i * mp->m_sb.sb_inodesize) + + offsetof(xfs_dinode_t, di_next_unlinked); + + while (next_unlinked_offset >= + (reg_buf_offset + reg_buf_bytes)) { + /* + * The next di_next_unlinked field is beyond + * the current logged region. Find the next + * logged region that contains or is beyond + * the current di_next_unlinked field. + */ + bit += nbits; + bit = xfs_next_bit(data_map, map_size, bit); + + /* + * If there are no more logged regions in the + * buffer, then we're done. + */ + if (bit == -1) { + return 0; + } + + nbits = xfs_contig_bits(data_map, map_size, + bit); + reg_buf_offset = bit << XFS_BLI_SHIFT; + reg_buf_bytes = nbits << XFS_BLI_SHIFT; + item_index++; + } + + /* + * If the current logged region starts after the current + * di_next_unlinked field, then move on to the next + * di_next_unlinked field. + */ + if (next_unlinked_offset < reg_buf_offset) { + continue; + } + + ASSERT(item->ri_buf[item_index].i_addr != NULL); + ASSERT((item->ri_buf[item_index].i_len % XFS_BLI_CHUNK) == 0); + ASSERT((reg_buf_offset + reg_buf_bytes) <= XFS_BUF_COUNT(bp)); + + /* + * The current logged region contains a copy of the + * current di_next_unlinked field. Extract its value + * and copy it to the buffer copy. + */ + logged_nextp = (xfs_agino_t *) + ((char *)(item->ri_buf[item_index].i_addr) + + (next_unlinked_offset - reg_buf_offset)); + if (*logged_nextp == 0) { + xfs_fs_cmn_err(CE_ALERT, mp, + "bad inode buffer log record (ptr = 0x%p, bp = 0x%p). XFS trying to replay bad (0) inode di_next_unlinked field", + item, bp); + return XFS_ERROR(EFSCORRUPTED); + } + + buffer_nextp = (xfs_agino_t *)xfs_buf_offset(bp, + next_unlinked_offset); + INT_SET(*buffer_nextp, ARCH_CONVERT, *logged_nextp); + } + + return 0; +} /* xlog_recover_do_inode_buffer */ + +/* + * Perform a 'normal' buffer recovery. Each logged region of the + * buffer should be copied over the corresponding region in the + * given buffer. The bitmap in the buf log format structure indicates + * where to place the logged data. + */ +/*ARGSUSED*/ +STATIC void +xlog_recover_do_reg_buffer(xfs_mount_t *mp, + xlog_recover_item_t *item, + xfs_buf_t *bp, + xfs_buf_log_format_t *buf_f) +{ + int i; + int bit; + int nbits; + xfs_buf_log_format_v1_t *obuf_f; + unsigned int *data_map=NULL; + unsigned int map_size=0; + int error; + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + data_map = buf_f->blf_data_map; + map_size = buf_f->blf_map_size; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + data_map = obuf_f->blf_data_map; + map_size = obuf_f->blf_map_size; + break; + } + bit = 0; + i = 1; /* 0 is the buf format structure */ + while (1) { + bit = xfs_next_bit(data_map, map_size, bit); + if (bit == -1) + break; + nbits = xfs_contig_bits(data_map, map_size, bit); + ASSERT(item->ri_buf[i].i_addr != 0); + ASSERT(item->ri_buf[i].i_len % XFS_BLI_CHUNK == 0); + ASSERT(XFS_BUF_COUNT(bp) >= + ((uint)bit << XFS_BLI_SHIFT)+(nbits<blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { + /* OK, if this returns nopkg() */ + error = xfs_qm_dqcheck((xfs_disk_dquot_t *) + item->ri_buf[i].i_addr, + -1, 0, XFS_QMOPT_DOWARN, + "dquot_buf_recover"); + } + if (!error) + bcopy(item->ri_buf[i].i_addr, /* source */ + xfs_buf_offset(bp, (uint)bit << XFS_BLI_SHIFT), /* dest */ + nbits<ri_total); +} /* xlog_recover_do_reg_buffer */ + + +/* + * Perform a dquot buffer recovery. + * Simple algorithm: if we have found a QUOTAOFF logitem of the same type + * (ie. USR or GRP), then just toss this buffer away; don't recover it. + * Else, treat it as a regular buffer and do recovery. + */ +STATIC void +xlog_recover_do_dquot_buffer( + xfs_mount_t *mp, + xlog_t *log, + xlog_recover_item_t *item, + xfs_buf_t *bp, + xfs_buf_log_format_t *buf_f) +{ + uint type; + + /* + * Non-root filesystems are required to send in quota flags + * at mount time. + */ + if (mp->m_qflags == 0 && mp->m_dev != rootdev) { + return; + } + + type = 0; + if (buf_f->blf_flags & XFS_BLI_UDQUOT_BUF) + type |= XFS_DQ_USER; + if (buf_f->blf_flags & XFS_BLI_GDQUOT_BUF) + type |= XFS_DQ_GROUP; + /* + * This type of quotas was turned off, so ignore this buffer + */ + if (log->l_quotaoffs_flag & type) + return; + + xlog_recover_do_reg_buffer(mp, item, bp, buf_f); +} + +/* + * This routine replays a modification made to a buffer at runtime. + * There are actually two types of buffer, regular and inode, which + * are handled differently. Inode buffers are handled differently + * in that we only recover a specific set of data from them, namely + * the inode di_next_unlinked fields. This is because all other inode + * data is actually logged via inode records and any data we replay + * here which overlaps that may be stale. + * + * When meta-data buffers are freed at run time we log a buffer item + * with the XFS_BLI_CANCEL bit set to indicate that previous copies + * of the buffer in the log should not be replayed at recovery time. + * This is so that if the blocks covered by the buffer are reused for + * file data before we crash we don't end up replaying old, freed + * meta-data into a user's file. + * + * To handle the cancellation of buffer log items, we make two passes + * over the log during recovery. During the first we build a table of + * those buffers which have been cancelled, and during the second we + * only replay those buffers which do not have corresponding cancel + * records in the table. See xlog_recover_do_buffer_pass[1,2] above + * for more details on the implementation of the table of cancel records. + */ +STATIC int +xlog_recover_do_buffer_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_buf_log_format_t *buf_f; + xfs_buf_log_format_v1_t *obuf_f; + xfs_mount_t *mp; + xfs_buf_t *bp; + int error; + int cancel; + xfs_daddr_t blkno; + int len; + ushort flags; + + buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; + + if (pass == XLOG_RECOVER_PASS1) { + /* + * In this pass we're only looking for buf items + * with the XFS_BLI_CANCEL bit set. + */ + xlog_recover_do_buffer_pass1(log, buf_f); + return 0; + } else { + /* + * In this pass we want to recover all the buffers + * which have not been cancelled and are not + * cancellation buffers themselves. The routine + * we call here will tell us whether or not to + * continue with the replay of this buffer. + */ + cancel = xlog_recover_do_buffer_pass2(log, buf_f); + if (cancel) { + return 0; + } + } + switch (buf_f->blf_type) { + case XFS_LI_BUF: + blkno = buf_f->blf_blkno; + len = buf_f->blf_len; + flags = buf_f->blf_flags; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + blkno = obuf_f->blf_blkno; + len = obuf_f->blf_len; + flags = obuf_f->blf_flags; + break; + default: + xfs_fs_cmn_err(CE_ALERT, log->l_mp, + "xfs_log_recover: unknown buffer type 0x%x, dev 0x%x", + buf_f->blf_type, log->l_dev); + return XFS_ERROR(EFSCORRUPTED); + } + + mp = log->l_mp; + if (flags & XFS_BLI_INODE_BUF) { + bp = xfs_buf_read_flags(mp->m_ddev_targp, blkno, len, + XFS_BUF_LOCK); + } else { + bp = xfs_buf_read(mp->m_ddev_targp, blkno, len, 0); + } + if (XFS_BUF_ISERROR(bp)) { + xfs_ioerror_alert("xlog_recover_do..(read#1)", log->l_mp, + bp, blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + return error; + } + + error = 0; + if (flags & XFS_BLI_INODE_BUF) { + error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f); + } else if (flags & (XFS_BLI_UDQUOT_BUF | XFS_BLI_GDQUOT_BUF)) { + xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); + } else { + xlog_recover_do_reg_buffer(mp, item, bp, buf_f); + } + if (error) + return XFS_ERROR(error); + + /* + * Perform delayed write on the buffer. Asynchronous writes will be + * slower when taking into account all the buffers to be flushed. + * + * Also make sure that only inode buffers with good sizes stay in + * the buffer cache. The kernel moves inodes in buffers of 1 block + * or XFS_INODE_CLUSTER_SIZE bytes, whichever is bigger. The inode + * buffers in the log can be a different size if the log was generated + * by an older kernel using unclustered inode buffers or a newer kernel + * running with a different inode cluster size. Regardless, if the + * the inode buffer size isn't MAX(blocksize, XFS_INODE_CLUSTER_SIZE) + * for *our* value of XFS_INODE_CLUSTER_SIZE, then we need to keep + * the buffer out of the buffer cache so that the buffer won't + * overlap with future reads of those inodes. + */ + error = 0; + + if ((INT_GET(*((__uint16_t *)(xfs_buf_offset(bp, 0))), ARCH_CONVERT) == XFS_DINODE_MAGIC) && + (XFS_BUF_COUNT(bp) != MAX(log->l_mp->m_sb.sb_blocksize, + (__uint32_t)XFS_INODE_CLUSTER_SIZE(log->l_mp)))) { + XFS_BUF_STALE(bp); + error = xfs_bwrite(mp, bp); + } else { + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL || + XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp); + XFS_BUF_SET_FSPRIVATE(bp, mp); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone); + xfs_bdwrite(mp, bp); + } + + return (error); +} /* xlog_recover_do_buffer_trans */ + +STATIC int +xlog_recover_do_inode_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_inode_log_format_t *in_f; + xfs_mount_t *mp; + xfs_buf_t *bp; + xfs_imap_t imap; + xfs_dinode_t *dip; + xfs_ino_t ino; + int len; + xfs_caddr_t src; + xfs_caddr_t dest; + int error; + int attr_index; + uint fields; + xfs_dinode_core_t *dicp; + + if (pass == XLOG_RECOVER_PASS1) { + return 0; + } + + in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr; + ino = in_f->ilf_ino; + mp = log->l_mp; + if (ITEM_TYPE(item) == XFS_LI_INODE) { + imap.im_blkno = (xfs_daddr_t)in_f->ilf_blkno; + imap.im_len = in_f->ilf_len; + imap.im_boffset = in_f->ilf_boffset; + } else { + /* + * It's an old inode format record. We don't know where + * its cluster is located on disk, and we can't allow + * xfs_imap() to figure it out because the inode btrees + * are not ready to be used. Therefore do not pass the + * XFS_IMAP_LOOKUP flag to xfs_imap(). This will give + * us only the single block in which the inode lives + * rather than its cluster, so we must make sure to + * invalidate the buffer when we write it out below. + */ + imap.im_blkno = 0; + xfs_imap(log->l_mp, 0, ino, &imap, 0); + } + bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len, + XFS_BUF_LOCK); + if (XFS_BUF_ISERROR(bp)) { + xfs_ioerror_alert("xlog_recover_do..(read#2)", mp, + bp, imap.im_blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + return error; + } + error = 0; + xfs_inobp_check(mp, bp); + ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); + dip = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); + + /* + * Make sure the place we're flushing out to really looks + * like an inode! + */ + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode magic number, dino ptr = 0x%p, dino bp = 0x%p, ino = %Ld", + dip, bp, ino); + return XFS_ERROR(EFSCORRUPTED); + } + dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr); + if (dicp->di_magic != XFS_DINODE_MAGIC) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log record, rec ptr 0x%p, ino %Ld", + item, ino); + return XFS_ERROR(EFSCORRUPTED); + } + if ((dicp->di_mode & IFMT) == IFREG) { + if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && + (dicp->di_format != XFS_DINODE_FMT_BTREE)) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", + item, dip, bp, ino); + return XFS_ERROR(EFSCORRUPTED); + } + } else if ((dicp->di_mode & IFMT) == IFDIR) { + if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && + (dicp->di_format != XFS_DINODE_FMT_BTREE) && + (dicp->di_format != XFS_DINODE_FMT_LOCAL)) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", + item, dip, bp, ino); + return XFS_ERROR(EFSCORRUPTED); + } + } + if (dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld", + item, dip, bp, ino, + dicp->di_nextents + dicp->di_anextents, + dicp->di_nblocks); + return XFS_ERROR(EFSCORRUPTED); + } + if (dicp->di_forkoff > mp->m_sb.sb_inodesize) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x", + item, dip, bp, ino, dicp->di_forkoff); + return XFS_ERROR(EFSCORRUPTED); + } + if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p", + item->ri_buf[1].i_len, item); + return XFS_ERROR(EFSCORRUPTED); + } + + /* The core is in in-core format */ + xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, + (xfs_dinode_core_t*)item->ri_buf[1].i_addr, + -1, ARCH_CONVERT); + /* the rest is in on-disk format */ + if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) { + bcopy(item->ri_buf[1].i_addr + sizeof(xfs_dinode_core_t), + (xfs_caddr_t) dip + sizeof(xfs_dinode_core_t), + item->ri_buf[1].i_len - sizeof(xfs_dinode_core_t)); + } + + fields = in_f->ilf_fields; + switch (fields & (XFS_ILOG_DEV | XFS_ILOG_UUID)) { + case XFS_ILOG_DEV: + INT_SET(dip->di_u.di_dev, ARCH_CONVERT, in_f->ilf_u.ilfu_rdev); + + break; + case XFS_ILOG_UUID: + dip->di_u.di_muuid = in_f->ilf_u.ilfu_uuid; + break; + } + + if (in_f->ilf_size == 2) + goto write_inode_buffer; + len = item->ri_buf[2].i_len; + src = item->ri_buf[2].i_addr; + ASSERT(in_f->ilf_size <= 4); + ASSERT((in_f->ilf_size == 3) || (fields & XFS_ILOG_AFORK)); + ASSERT(!(fields & XFS_ILOG_DFORK) || + (len == in_f->ilf_dsize)); + + switch (fields & XFS_ILOG_DFORK) { + case XFS_ILOG_DDATA: + case XFS_ILOG_DEXT: + bcopy(src, &dip->di_u, len); + break; + + case XFS_ILOG_DBROOT: + xfs_bmbt_to_bmdr((xfs_bmbt_block_t *)src, len, + &(dip->di_u.di_bmbt), + XFS_DFORK_DSIZE(dip, mp)); + break; + + default: + /* + * There are no data fork flags set. + */ + ASSERT((fields & XFS_ILOG_DFORK) == 0); + break; + } + + + + /* + * If we logged any attribute data, recover it. There may or + * may not have been any other non-core data logged in this + * transaction. + */ + if (in_f->ilf_fields & XFS_ILOG_AFORK) { + if (in_f->ilf_fields & XFS_ILOG_DFORK) { + attr_index = 3; + } else { + attr_index = 2; + } + len = item->ri_buf[attr_index].i_len; + src = item->ri_buf[attr_index].i_addr; + ASSERT(len == in_f->ilf_asize); + + switch (in_f->ilf_fields & XFS_ILOG_AFORK) { + case XFS_ILOG_ADATA: + case XFS_ILOG_AEXT: + dest = XFS_DFORK_APTR(dip); + ASSERT(len <= XFS_DFORK_ASIZE(dip, mp)); + bcopy(src, dest, len); + break; + + case XFS_ILOG_ABROOT: + dest = XFS_DFORK_APTR(dip); + xfs_bmbt_to_bmdr((xfs_bmbt_block_t *)src, len, + (xfs_bmdr_block_t*)dest, + XFS_DFORK_ASIZE(dip, mp)); + break; + + default: + xlog_warn("XFS: xlog_recover_do_inode_trans: Illegal flag"); + ASSERT(0); + xfs_buf_relse(bp); + return XFS_ERROR(EIO); + } + } + + +write_inode_buffer: +#if 0 + /* + * Can't do this if the transaction didn't log the current + * contents, e.g. rmdir. + */ + XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip); +#endif + xfs_inobp_check(mp, bp); + if (ITEM_TYPE(item) == XFS_LI_INODE) { + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL || + XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp); + XFS_BUF_SET_FSPRIVATE(bp, mp); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone); + xfs_bdwrite(mp, bp); + } else { + XFS_BUF_STALE(bp); + error = xfs_bwrite(mp, bp); + } + + return (error); +} /* xlog_recover_do_inode_trans */ + + +/* + * Recover QUOTAOFF records. We simply make a note of it in the xlog_t + * structure, so that we know not to do any dquot item or dquot buffer recovery, + * of that type. + */ +STATIC int +xlog_recover_do_quotaoff_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_qoff_logformat_t *qoff_f; + + if (pass == XLOG_RECOVER_PASS2) { + return (0); + } + + qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr; + ASSERT(qoff_f); + + /* + * The logitem format's flag tells us if this was user quotaoff, + * group quotaoff or both. + */ + if (qoff_f->qf_flags & XFS_UQUOTA_ACCT) + log->l_quotaoffs_flag |= XFS_DQ_USER; + if (qoff_f->qf_flags & XFS_GQUOTA_ACCT) + log->l_quotaoffs_flag |= XFS_DQ_GROUP; + + return (0); +} + + +/* + * Recover a dquot record + */ +STATIC int +xlog_recover_do_dquot_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_mount_t *mp; + xfs_buf_t *bp; + struct xfs_disk_dquot *ddq, *recddq; + int error; + xfs_dq_logformat_t *dq_f; + uint type; + + if (pass == XLOG_RECOVER_PASS1) { + return 0; + } + mp = log->l_mp; + + /* + * Non-root filesystems are required to send in quota flags + * at mount time. + */ + if (mp->m_qflags == 0 && mp->m_dev != rootdev) { + return (0); + } + + recddq = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr; + ASSERT(recddq); + /* + * This type of quotas was turned off, so ignore this record. + */ + type = INT_GET(recddq->d_flags, ARCH_CONVERT)&(XFS_DQ_USER|XFS_DQ_GROUP); + ASSERT(type); + if (log->l_quotaoffs_flag & type) + return (0); + + /* + * At this point we know that if we are recovering a root filesystem + * then quota was _not_ turned off. Since there is no other flag + * indicate to us otherwise, this must mean that quota's on, + * and the dquot needs to be replayed. Remember that we may not have + * fully recovered the superblock yet, so we can't do the usual trick + * of looking at the SB quota bits. + * + * The other possibility, of course, is that the quota subsystem was + * removed since the last mount - nopkg(). + */ + dq_f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr; + ASSERT(dq_f); + if ((error = xfs_qm_dqcheck(recddq, + dq_f->qlf_id, + 0, XFS_QMOPT_DOWARN, + "xlog_recover_do_dquot_trans (log copy)"))) { + if ((error == nopkg())) + return (0); + return XFS_ERROR(EIO); + } + ASSERT(dq_f->qlf_len == 1); + + error = xfs_read_buf(mp, mp->m_ddev_targp, + dq_f->qlf_blkno, + XFS_FSB_TO_BB(mp, dq_f->qlf_len), + 0, &bp); + if (error) { + xfs_ioerror_alert("xlog_recover_do..(read#3)", mp, + bp, dq_f->qlf_blkno); + return error; + } + ASSERT(bp); + ddq = (xfs_disk_dquot_t *)xfs_buf_offset(bp, dq_f->qlf_boffset); + + /* + * At least the magic num portion should be on disk because this + * was among a chunk of dquots created earlier, and we did some + * minimal initialization then. + */ + if (xfs_qm_dqcheck(ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, + "xlog_recover_do_dquot_trans")) { + xfs_buf_relse(bp); + return XFS_ERROR(EIO); + } + + bcopy(recddq, ddq, item->ri_buf[1].i_len); + + ASSERT(dq_f->qlf_size == 2); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL || + XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp); + XFS_BUF_SET_FSPRIVATE(bp, mp); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone); + xfs_bdwrite(mp, bp); + + return (0); +} /* xlog_recover_do_dquot_trans */ + +/* + * This routine is called to create an in-core extent free intent + * item from the efi format structure which was logged on disk. + * It allocates an in-core efi, copies the extents from the format + * structure into it, and adds the efi to the AIL with the given + * LSN. + */ +STATIC void +xlog_recover_do_efi_trans(xlog_t *log, + xlog_recover_item_t *item, + xfs_lsn_t lsn, + int pass) +{ + xfs_mount_t *mp; + xfs_efi_log_item_t *efip; + xfs_efi_log_format_t *efi_formatp; + SPLDECL(s); + + if (pass == XLOG_RECOVER_PASS1) { + return; + } + + efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr; + ASSERT(item->ri_buf[0].i_len == + (sizeof(xfs_efi_log_format_t) + + ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)))); + + mp = log->l_mp; + efip = xfs_efi_init(mp, efi_formatp->efi_nextents); + bcopy((char *)efi_formatp, (char *)&(efip->efi_format), + sizeof(xfs_efi_log_format_t) + + ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t))); + efip->efi_next_extent = efi_formatp->efi_nextents; + efip->efi_flags |= XFS_EFI_COMMITTED; + + AIL_LOCK(mp,s); + /* + * xfs_trans_update_ail() drops the AIL lock. + */ + xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s); +} /* xlog_recover_do_efi_trans */ + + +/* + * This routine is called when an efd format structure is found in + * a committed transaction in the log. It's purpose is to cancel + * the corresponding efi if it was still in the log. To do this + * it searches the AIL for the efi with an id equal to that in the + * efd format structure. If we find it, we remove the efi from the + * AIL and free it. + */ +STATIC void +xlog_recover_do_efd_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_mount_t *mp; + xfs_efd_log_format_t *efd_formatp; + xfs_efi_log_item_t *efip=NULL; + xfs_log_item_t *lip; + int gen; + int nexts; + __uint64_t efi_id; + SPLDECL(s); + + if (pass == XLOG_RECOVER_PASS1) { + return; + } + + efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr; + ASSERT(item->ri_buf[0].i_len == + (sizeof(xfs_efd_log_format_t) + + ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_t)))); + efi_id = efd_formatp->efd_efi_id; + + /* + * Search for the efi with the id in the efd format structure + * in the AIL. + */ + mp = log->l_mp; + AIL_LOCK(mp,s); + lip = xfs_trans_first_ail(mp, &gen); + while (lip != NULL) { + if (lip->li_type == XFS_LI_EFI) { + efip = (xfs_efi_log_item_t *)lip; + if (efip->efi_format.efi_id == efi_id) { + /* + * xfs_trans_delete_ail() drops the + * AIL lock. + */ + xfs_trans_delete_ail(mp, lip, s); + break; + } + } + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + } + if (lip == NULL) { + AIL_UNLOCK(mp, s); + } + + /* + * If we found it, then free it up. If it wasn't there, it + * must have been overwritten in the log. Oh well. + */ + if (lip != NULL) { + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + kmem_free(lip, sizeof(xfs_efi_log_item_t) + + ((nexts - 1) * sizeof(xfs_extent_t))); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } +} /* xlog_recover_do_efd_trans */ + +/* + * Perform the transaction + * + * If the transaction modifies a buffer or inode, do it now. Otherwise, + * EFIs and EFDs get queued up by adding entries into the AIL for them. + */ +STATIC int +xlog_recover_do_trans(xlog_t *log, + xlog_recover_t *trans, + int pass) +{ + int error = 0; + xlog_recover_item_t *item, *first_item; + + if ((error = xlog_recover_reorder_trans(log, trans))) + return error; + first_item = item = trans->r_itemq; + do { + /* + * we don't need to worry about the block number being + * truncated in > 1 TB buffers because in user-land, + * we're now n32 or 64-bit so xfs_daddr_t is 64-bits so + * the blkno's will get through the user-mode buffer + * cache properly. The only bad case is o32 kernels + * where xfs_daddr_t is 32-bits but mount will warn us + * off a > 1 TB filesystem before we get here. + */ + if ((ITEM_TYPE(item) == XFS_LI_BUF) || + (ITEM_TYPE(item) == XFS_LI_6_1_BUF) || + (ITEM_TYPE(item) == XFS_LI_5_3_BUF)) { + if ((error = xlog_recover_do_buffer_trans(log, item, + pass))) + break; + } else if ((ITEM_TYPE(item) == XFS_LI_INODE) || + (ITEM_TYPE(item) == XFS_LI_6_1_INODE) || + (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) { + if ((error = xlog_recover_do_inode_trans(log, item, + pass))) + break; + } else if (ITEM_TYPE(item) == XFS_LI_EFI) { + xlog_recover_do_efi_trans(log, item, trans->r_lsn, + pass); + } else if (ITEM_TYPE(item) == XFS_LI_EFD) { + xlog_recover_do_efd_trans(log, item, pass); + } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) { + if ((error = xlog_recover_do_dquot_trans(log, item, + pass))) + break; + } else if ((ITEM_TYPE(item) == XFS_LI_QUOTAOFF)) { + if ((error = xlog_recover_do_quotaoff_trans(log, item, + pass))) + break; + } else { + xlog_warn("XFS: xlog_recover_do_trans"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + item = item->ri_next; + } while (first_item != item); + + return error; +} /* xlog_recover_do_trans */ + + +/* + * Free up any resources allocated by the transaction + * + * Remember that EFIs, EFDs, and IUNLINKs are handled later. + */ +STATIC void +xlog_recover_free_trans(xlog_recover_t *trans) +{ + xlog_recover_item_t *first_item, *item, *free_item; + int i; + + item = first_item = trans->r_itemq; + do { + free_item = item; + item = item->ri_next; + /* Free the regions in the item. */ + for (i = 0; i < free_item->ri_cnt; i++) { + kmem_free(free_item->ri_buf[i].i_addr, + free_item->ri_buf[i].i_len); + } + /* Free the item itself */ + kmem_free(free_item->ri_buf, + (free_item->ri_total * sizeof(xfs_log_iovec_t))); + kmem_free(free_item, sizeof(xlog_recover_item_t)); + } while (first_item != item); + /* Free the transaction recover structure */ + kmem_free(trans, sizeof(xlog_recover_t)); +} /* xlog_recover_free_trans */ + + +STATIC int +xlog_recover_commit_trans(xlog_t *log, + xlog_recover_t **q, + xlog_recover_t *trans, + int pass) +{ + int error; + + if ((error = xlog_recover_unlink_tid(q, trans))) + return error; + if ((error = xlog_recover_do_trans(log, trans, pass))) + return error; + xlog_recover_free_trans(trans); /* no error */ + return 0; +} /* xlog_recover_commit_trans */ + + +/*ARGSUSED*/ +STATIC int +xlog_recover_unmount_trans(xlog_recover_t *trans) +{ + /* Do nothing now */ + xlog_warn("XFS: xlog_recover_unmount_trans: Unmount LR"); + return( 0 ); +} /* xlog_recover_unmount_trans */ + + +/* + * There are two valid states of the r_state field. 0 indicates that the + * transaction structure is in a normal state. We have either seen the + * start of the transaction or the last operation we added was not a partial + * operation. If the last operation we added to the transaction was a + * partial operation, we need to mark r_state with XLOG_WAS_CONT_TRANS. + * + * NOTE: skip LRs with 0 data length. + */ +STATIC int +xlog_recover_process_data(xlog_t *log, + xlog_recover_t *rhash[], + xlog_rec_header_t *rhead, + xfs_caddr_t dp, + int pass) +{ + xfs_caddr_t lp = dp+INT_GET(rhead->h_len, ARCH_CONVERT); + int num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT); + xlog_op_header_t *ohead; + xlog_recover_t *trans; + xlog_tid_t tid; + int error; + unsigned long hash; + uint flags; + + /* check the log format matches our own - else we can't recover */ + if (xlog_header_check_recover(log->l_mp, rhead)) + return (XFS_ERROR(EIO)); + + while ((dp < lp) && num_logops) { + ASSERT(dp + sizeof(xlog_op_header_t) <= lp); + ohead = (xlog_op_header_t *)dp; + dp += sizeof(xlog_op_header_t); + if (ohead->oh_clientid != XFS_TRANSACTION && + ohead->oh_clientid != XFS_LOG) { + xlog_warn("XFS: xlog_recover_process_data: bad clientid"); + ASSERT(0); + return (XFS_ERROR(EIO)); + } + tid = INT_GET(ohead->oh_tid, ARCH_CONVERT); + hash = XLOG_RHASH(tid); + trans = xlog_recover_find_tid(rhash[hash], tid); + if (trans == NULL) { /* not found; add new tid */ + if (ohead->oh_flags & XLOG_START_TRANS) + xlog_recover_new_tid(&rhash[hash], tid, INT_GET(rhead->h_lsn, ARCH_CONVERT)); + } else { + ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp); + flags = ohead->oh_flags & ~XLOG_END_TRANS; + if (flags & XLOG_WAS_CONT_TRANS) + flags &= ~XLOG_CONTINUE_TRANS; + switch (flags) { + case XLOG_COMMIT_TRANS: { + error = xlog_recover_commit_trans(log, &rhash[hash], + trans, pass); + break; + } + case XLOG_UNMOUNT_TRANS: { + error = xlog_recover_unmount_trans(trans); + break; + } + case XLOG_WAS_CONT_TRANS: { + error = xlog_recover_add_to_cont_trans(trans, dp, + INT_GET(ohead->oh_len, ARCH_CONVERT)); + break; + } + case XLOG_START_TRANS : { + xlog_warn("XFS: xlog_recover_process_data: bad transaction"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + case 0: + case XLOG_CONTINUE_TRANS: { + error = xlog_recover_add_to_trans(trans, dp, + INT_GET(ohead->oh_len, ARCH_CONVERT)); + break; + } + default: { + xlog_warn("XFS: xlog_recover_process_data: bad flag"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + } /* switch */ + if (error) + return error; + } /* if */ + dp += INT_GET(ohead->oh_len, ARCH_CONVERT); + num_logops--; + } + return( 0 ); +} /* xlog_recover_process_data */ + + +/* + * Process an extent free intent item that was recovered from + * the log. We need to free the extents that it describes. + */ +STATIC void +xlog_recover_process_efi(xfs_mount_t *mp, + xfs_efi_log_item_t *efip) +{ + xfs_efd_log_item_t *efdp; + xfs_trans_t *tp; + int i; + xfs_extent_t *extp; + xfs_fsblock_t startblock_fsb; + + ASSERT(!(efip->efi_flags & XFS_EFI_RECOVERED)); + + /* + * First check the validity of the extents described by the + * EFI. If any are bad, then assume that all are bad and + * just toss the EFI. + */ + for (i = 0; i < efip->efi_format.efi_nextents; i++) { + extp = &(efip->efi_format.efi_extents[i]); + startblock_fsb = XFS_BB_TO_FSB(mp, + XFS_FSB_TO_DADDR(mp, extp->ext_start)); + if ((startblock_fsb == 0) || + (extp->ext_len == 0) || + (startblock_fsb >= mp->m_sb.sb_dblocks) || + (extp->ext_len >= mp->m_sb.sb_agblocks)) { + /* + * This will pull the EFI from the AIL and + * free the memory associated with it. + */ + xfs_efi_release(efip, efip->efi_format.efi_nextents); + return; + } + } + + tp = xfs_trans_alloc(mp, 0); + xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, 0, 0); + efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); + + for (i = 0; i < efip->efi_format.efi_nextents; i++) { + extp = &(efip->efi_format.efi_extents[i]); + xfs_free_extent(tp, extp->ext_start, extp->ext_len); + xfs_trans_log_efd_extent(tp, efdp, extp->ext_start, + extp->ext_len); + } + + efip->efi_flags |= XFS_EFI_RECOVERED; + xfs_trans_commit(tp, 0, NULL); +} /* xlog_recover_process_efi */ + + +/* + * Verify that once we've encountered something other than an EFI + * in the AIL that there are no more EFIs in the AIL. + */ +#if defined(DEBUG) +STATIC void +xlog_recover_check_ail(xfs_mount_t *mp, + xfs_log_item_t *lip, + int gen) +{ + int orig_gen; + + orig_gen = gen; + do { + ASSERT(lip->li_type != XFS_LI_EFI); + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + /* + * The check will be bogus if we restart from the + * beginning of the AIL, so ASSERT that we don't. + * We never should since we're holding the AIL lock + * the entire time. + */ + ASSERT(gen == orig_gen); + } while (lip != NULL); +} +#endif /* DEBUG */ + + +/* + * When this is called, all of the EFIs which did not have + * corresponding EFDs should be in the AIL. What we do now + * is free the extents associated with each one. + * + * Since we process the EFIs in normal transactions, they + * will be removed at some point after the commit. This prevents + * us from just walking down the list processing each one. + * We'll use a flag in the EFI to skip those that we've already + * processed and use the AIL iteration mechanism's generation + * count to try to speed this up at least a bit. + * + * When we start, we know that the EFIs are the only things in + * the AIL. As we process them, however, other items are added + * to the AIL. Since everything added to the AIL must come after + * everything already in the AIL, we stop processing as soon as + * we see something other than an EFI in the AIL. + */ +STATIC void +xlog_recover_process_efis(xlog_t *log) +{ + xfs_log_item_t *lip; + xfs_efi_log_item_t *efip; + int gen; + xfs_mount_t *mp; + SPLDECL(s); + + mp = log->l_mp; + AIL_LOCK(mp,s); + + lip = xfs_trans_first_ail(mp, &gen); + while (lip != NULL) { + /* + * We're done when we see something other than an EFI. + */ + if (lip->li_type != XFS_LI_EFI) { + xlog_recover_check_ail(mp, lip, gen); + break; + } + + /* + * Skip EFIs that we've already processed. + */ + efip = (xfs_efi_log_item_t *)lip; + if (efip->efi_flags & XFS_EFI_RECOVERED) { + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + continue; + } + + AIL_UNLOCK(mp, s); + xlog_recover_process_efi(mp, efip); + AIL_LOCK(mp,s); + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + } + AIL_UNLOCK(mp, s); +} /* xlog_recover_process_efis */ + + +/* + * This routine performs a transaction to null out a bad inode pointer + * in an agi unlinked inode hash bucket. + */ +STATIC void +xlog_recover_clear_agi_bucket( + xfs_mount_t *mp, + xfs_agnumber_t agno, + int bucket) +{ + xfs_trans_t *tp; + xfs_agi_t *agi; + xfs_daddr_t agidaddr; + xfs_buf_t *agibp; + int offset; + int error; + + tp = xfs_trans_alloc(mp, XFS_TRANS_CLEAR_AGI_BUCKET); + xfs_trans_reserve(tp, 0, XFS_CLEAR_AGI_BUCKET_LOG_RES(mp), 0, 0, 0); + + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agidaddr, + 1, 0, &agibp); + if (error) { + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return; + } + + agi = XFS_BUF_TO_AGI(agibp); + if (INT_GET(agi->agi_magicnum, ARCH_CONVERT) != XFS_AGI_MAGIC) { + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return; + } + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + + INT_SET(agi->agi_unlinked[bucket], ARCH_CONVERT, NULLAGINO); + offset = offsetof(xfs_agi_t, agi_unlinked) + + (sizeof(xfs_agino_t) * bucket); + xfs_trans_log_buf(tp, agibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + + (void) xfs_trans_commit(tp, 0, NULL); +} /* xlog_recover_clear_agi_bucket */ + + +/* + * xlog_iunlink_recover + * + * This is called during recovery to process any inodes which + * we unlinked but not freed when the system crashed. These + * inodes will be on the lists in the AGI blocks. What we do + * here is scan all the AGIs and fully truncate and free any + * inodes found on the lists. Each inode is removed from the + * lists when it has been fully truncated and is freed. The + * freeing of the inode and its removal from the list must be + * atomic. + */ +void +xlog_recover_process_iunlinks(xlog_t *log) +{ + xfs_mount_t *mp; + xfs_agnumber_t agno; + xfs_agi_t *agi; + xfs_daddr_t agidaddr; + xfs_buf_t *agibp; + xfs_buf_t *ibp; + xfs_dinode_t *dip; + xfs_inode_t *ip; + xfs_agino_t agino; + xfs_ino_t ino; + int bucket; + int error; + uint mp_dmevmask; + + mp = log->l_mp; + + /* + * Prevent any DMAPI event from being sent while in this function. + * Not a problem for xfs since the file system isn't mounted + * yet. It is a problem for cxfs recovery. + */ + mp_dmevmask = mp->m_dmevmask; + mp->m_dmevmask = 0; + + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + /* + * Find the agi for this ag. + */ + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + agibp = xfs_buf_read(mp->m_ddev_targp, agidaddr, 1, 0); + if (XFS_BUF_ISERROR(agibp)) { + xfs_ioerror_alert("xlog_recover_process_iunlinks(agi#1)", + log->l_mp, agibp, agidaddr); + } + agi = XFS_BUF_TO_AGI(agibp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + + for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) { + + agino = INT_GET(agi->agi_unlinked[bucket], ARCH_CONVERT); + while (agino != NULLAGINO) { + + /* + * Release the agi buffer so that it can + * be acquired in the normal course of the + * transaction to truncate and free the inode. + */ + xfs_buf_relse(agibp); + + ino = XFS_AGINO_TO_INO(mp, agno, agino); + error = xfs_iget(mp, NULL, ino, 0, &ip, 0); + ASSERT(error || (ip != NULL)); + + if (!error) { + /* + * Get the on disk inode to find the + * next inode in the bucket. + */ + error = xfs_itobp(mp, NULL, ip, &dip, + &ibp, 0); + ASSERT(error || (dip != NULL)); + } + + if (!error) { + ASSERT(ip->i_d.di_nlink == 0); + + /* setup for the next pass */ + agino = INT_GET(dip->di_next_unlinked, + ARCH_CONVERT); + xfs_buf_relse(ibp); + /* + * Prevent any DMAPI event from + * being sent when the + * reference on the inode is + * dropped. Not a problem for + * xfs since the file system + * isn't mounted yet. It is a + * problem for cxfs recovery. + */ + ip->i_d.di_dmevmask = 0; + + /* + * If this is a new inode, handle + * it specially. Otherwise, + * just drop our reference to the + * inode. If there are no + * other references, this will + * send the inode to + * xfs_inactive() which will + * truncate the file and free + * the inode. + */ + if (ip->i_d.di_mode == 0) + xfs_iput_new(ip, 0); + else + VN_RELE(XFS_ITOV(ip)); + } else { + /* + * We can't read in the inode + * this bucket points to, or + * this inode is messed up. Just + * ditch this bucket of inodes. We + * will lose some inodes and space, + * but at least we won't hang. Call + * xlog_recover_clear_agi_bucket() + * to perform a transaction to clear + * the inode pointer in the bucket. + */ + xlog_recover_clear_agi_bucket(mp, agno, + bucket); + + agino = NULLAGINO; + } + + /* + * Reacquire the agibuffer and continue around + * the loop. + */ + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + agibp = xfs_buf_read(mp->m_ddev_targp, + agidaddr, 1, 0); + if (XFS_BUF_ISERROR(agibp)) { + xfs_ioerror_alert("xlog_recover_process_iunlinks(agi#2)", + log->l_mp, agibp, agidaddr); + } + agi = XFS_BUF_TO_AGI(agibp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } + } + + /* + * Release the buffer for the current agi so we can + * go on to the next one. + */ + xfs_buf_relse(agibp); + } + + mp->m_dmevmask = mp_dmevmask; + +} /* xlog_recover_process_iunlinks */ + + +/* + * Stamp cycle number in every block + * + * This routine is also called in xfs_log.c + */ +/*ARGSUSED*/ +void +xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog) +{ + int i, j, k; + int size = iclog->ic_offset + iclog->ic_roundoff; + xfs_caddr_t dp; + union ich { + xlog_rec_ext_header_t hic_xheader; + char hic_sector[XLOG_HEADER_SIZE]; + } *xhdr; + uint cycle_lsn; + +#ifdef DEBUG + uint *up; + uint chksum = 0; + + up = (uint *)iclog->ic_datap; + /* divide length by 4 to get # words */ + for (i=0; i> 2; i++) { + chksum ^= INT_GET(*up, ARCH_CONVERT); + up++; + } + INT_SET(iclog->ic_header.h_chksum, ARCH_CONVERT, chksum); +#endif /* DEBUG */ + + cycle_lsn = CYCLE_LSN_NOCONV(iclog->ic_header.h_lsn, ARCH_CONVERT); + + dp = iclog->ic_datap; + for (i = 0; i < BTOBB(size) && + i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { + iclog->ic_header.h_cycle_data[i] = *(uint *)dp; + *(uint *)dp = cycle_lsn; + dp += BBSIZE; + } + + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + xhdr = (union ich*)&iclog->ic_header; + for ( ; i < BTOBB(size); i++) { + j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + xhdr[j].hic_xheader.xh_cycle_data[k] = *(uint *)dp; + *(uint *)dp = cycle_lsn; + dp += BBSIZE; + } + + for (i = 1; i < log->l_iclog_heads; i++) { + xhdr[i].hic_xheader.xh_cycle = cycle_lsn; + } + } + +} /* xlog_pack_data */ + + +/*ARGSUSED*/ +STATIC void +xlog_unpack_data(xlog_rec_header_t *rhead, + xfs_caddr_t dp, + xlog_t *log) +{ + int i, j, k; + union ich { + xlog_rec_header_t hic_header; + xlog_rec_ext_header_t hic_xheader; + char hic_sector[XLOG_HEADER_SIZE]; + } *xhdr; + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + uint *up = (uint *)dp; + uint chksum = 0; +#endif + + for (i=0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) && + i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { + *(uint *)dp = *(uint *)&rhead->h_cycle_data[i]; + dp += BBSIZE; + } + + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + xhdr = (union ich*)rhead; + for ( ; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) { + j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); + *(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; + dp += BBSIZE; + } + } + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + /* divide length by 4 to get # words */ + for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) { + chksum ^= INT_GET(*up, ARCH_CONVERT); + up++; + } + if (chksum != INT_GET(rhead->h_chksum, ARCH_CONVERT)) { + if (!INT_ISZERO(rhead->h_chksum, ARCH_CONVERT) || + ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) { + cmn_err(CE_DEBUG, + "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)", + INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum); + cmn_err(CE_DEBUG, +"XFS: Disregard message if filesystem was created with non-DEBUG kernel"); + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + cmn_err(CE_DEBUG, + "XFS: LogR this is a LogV2 filesystem"); + } + log->l_flags |= XLOG_CHKSUM_MISMATCH; + } + } +#endif /* DEBUG && XFS_LOUD_RECOVERY */ +} /* xlog_unpack_data */ + + +/* + * Read the log from tail to head and process the log records found. + * Handle the two cases where the tail and head are in the same cycle + * and where the active portion of the log wraps around the end of + * the physical log separately. The pass parameter is passed through + * to the routines called to process the data and is not looked at + * here. + */ +STATIC int +xlog_do_recovery_pass(xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk, + int pass) +{ + xlog_rec_header_t *rhead; + xfs_daddr_t blk_no; + xfs_caddr_t bufaddr; + xfs_buf_t *hbp, *dbp; + int error, h_size; + int bblks, split_bblks; + int hblks, split_hblks, wrapped_hblks; + xlog_recover_t *rhash[XLOG_RHASH_SIZE]; + + error = 0; + + + /* + * Read the header of the tail block and get the iclog buffer size from + * h_size. Use this to tell how many sectors make up the log header. + */ + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { + /* + * When using variable length iclogs, read first sector of iclog + * header and extract the header size from it. Get a new hbp that + * is the correct size. + */ + hbp = xlog_get_bp(1, log->l_mp); + if (!hbp) + return ENOMEM; + if ((error = xlog_bread(log, tail_blk, 1, hbp))) + goto bread_err1; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == + XLOG_HEADER_MAGIC_NUM); + if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) { + xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number."); + error = XFS_ERROR(EIO); + goto bread_err1; + } + h_size = INT_GET(rhead->h_size, ARCH_CONVERT); + + if ((INT_GET(rhead->h_version, ARCH_CONVERT) & XLOG_VERSION_2) && + (h_size > XLOG_HEADER_CYCLE_SIZE)) { + hblks = h_size / XLOG_HEADER_CYCLE_SIZE; + if (h_size % XLOG_HEADER_CYCLE_SIZE) + hblks++; + xlog_put_bp(hbp); + hbp = xlog_get_bp(hblks, log->l_mp); + } else { + hblks=1; + } + } else { + hblks=1; + hbp = xlog_get_bp(1, log->l_mp); + h_size = XLOG_BIG_RECORD_BSIZE; + } + + if (!hbp) + return ENOMEM; + dbp = xlog_get_bp(BTOBB(h_size),log->l_mp); + if (!dbp) { + xlog_put_bp(hbp); + return ENOMEM; + } + + bzero(rhash, sizeof(rhash)); + if (tail_blk <= head_blk) { + for (blk_no = tail_blk; blk_no < head_blk; ) { + if ((error = xlog_bread(log, blk_no, hblks, hbp))) + goto bread_err2; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); /* blocks in data section */ + + if ((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) || + (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) || + (bblks <= 0) || + (blk_no > log->l_logBBsize)) { + error = EFSCORRUPTED; + goto bread_err2; + } + + if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) { + xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number."); + error = XFS_ERROR(EIO); + goto bread_err2; + } + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); /* blocks in data section */ + if (bblks > 0) { + if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp))) + goto bread_err2; + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err2; + } + blk_no += (bblks+hblks); + } + } else { + /* + * Perform recovery around the end of the physical log. When the head + * is not on the same cycle number as the tail, we can't do a sequential + * recovery as above. + */ + blk_no = tail_blk; + while (blk_no < log->l_logBBsize) { + /* + * Check for header wrapping around physical end-of-log + */ + wrapped_hblks = 0; + if (blk_no+hblks <= log->l_logBBsize) { + /* Read header in one read */ + if ((error = xlog_bread(log, blk_no, hblks, hbp))) + goto bread_err2; + } else { + /* This log record is split across physical end of log */ + split_hblks = 0; + if (blk_no != log->l_logBBsize) { + /* some data is before physical end of log */ + ASSERT(blk_no <= INT_MAX); + split_hblks = log->l_logBBsize - (int)blk_no; + ASSERT(split_hblks > 0); + if ((error = xlog_bread(log, blk_no, split_hblks, hbp))) + goto bread_err2; + } + bufaddr = XFS_BUF_PTR(hbp); + XFS_BUF_SET_PTR(hbp, bufaddr + BBTOB(split_hblks), + BBTOB(hblks - split_hblks)); + wrapped_hblks = hblks - split_hblks; + if ((error = xlog_bread(log, 0, wrapped_hblks, hbp))) + goto bread_err2; + XFS_BUF_SET_PTR(hbp, bufaddr, hblks); + } + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + + /* LR body must have data or it wouldn't have been written */ + ASSERT(bblks > 0); + blk_no += hblks; /* successfully read header */ + + if ((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) || + (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) || + (bblks <= 0)) { + error = EFSCORRUPTED; + goto bread_err2; + } + + /* Read in data for log record */ + if (blk_no+bblks <= log->l_logBBsize) { + if ((error = xlog_bread(log, blk_no, bblks, dbp))) + goto bread_err2; + } else { + /* This log record is split across physical end of log */ + split_bblks = 0; + if (blk_no != log->l_logBBsize) { + + /* some data is before physical end of log */ + ASSERT(blk_no <= INT_MAX); + split_bblks = log->l_logBBsize - (int)blk_no; + ASSERT(split_bblks > 0); + if ((error = xlog_bread(log, blk_no, split_bblks, dbp))) + goto bread_err2; + } + bufaddr = XFS_BUF_PTR(dbp); + XFS_BUF_SET_PTR(dbp, bufaddr + BBTOB(split_bblks), + BBTOB(bblks - split_bblks)); + if ((error = xlog_bread(log, wrapped_hblks, + bblks - split_bblks, dbp))) + goto bread_err2; + XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_BIG_RECORD_BSIZE); + } + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err2; + blk_no += bblks; + } + + ASSERT(blk_no >= log->l_logBBsize); + blk_no -= log->l_logBBsize; + + /* read first part of physical log */ + while (blk_no < head_blk) { + if ((error = xlog_bread(log, blk_no, hblks, hbp))) + goto bread_err2; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + ASSERT(bblks > 0); + if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp))) + goto bread_err2; + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err2; + blk_no += (bblks+hblks); + } + } + +bread_err2: + xlog_put_bp(dbp); +bread_err1: + xlog_put_bp(hbp); + + return error; +} + +/* + * Do the recovery of the log. We actually do this in two phases. + * The two passes are necessary in order to implement the function + * of cancelling a record written into the log. The first pass + * determines those things which have been cancelled, and the + * second pass replays log items normally except for those which + * have been cancelled. The handling of the replay and cancellations + * takes place in the log item type specific routines. + * + * The table of items which have cancel records in the log is allocated + * and freed at this level, since only here do we know when all of + * the log recovery has been completed. + */ +STATIC int +xlog_do_log_recovery(xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk) +{ + int error; +#ifdef DEBUG + int i; +#endif + + /* + * First do a pass to find all of the cancelled buf log items. + * Store them in the buf_cancel_table for use in the second pass. + */ + log->l_buf_cancel_table = + (xfs_buf_cancel_t **)kmem_zalloc(XLOG_BC_TABLE_SIZE * + sizeof(xfs_buf_cancel_t*), + KM_SLEEP); + error = xlog_do_recovery_pass(log, head_blk, tail_blk, + XLOG_RECOVER_PASS1); + if (error != 0) { + kmem_free(log->l_buf_cancel_table, + XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*)); + log->l_buf_cancel_table = NULL; + return error; + } + /* + * Then do a second pass to actually recover the items in the log. + * When it is complete free the table of buf cancel items. + */ + error = xlog_do_recovery_pass(log, head_blk, tail_blk, + XLOG_RECOVER_PASS2); +#ifdef DEBUG + for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) { + ASSERT(log->l_buf_cancel_table[i] == NULL); + } +#endif /* DEBUG */ + kmem_free(log->l_buf_cancel_table, + XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*)); + log->l_buf_cancel_table = NULL; + + return error; +} + +/* + * Do the actual recovery + */ +STATIC int +xlog_do_recover(xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk) +{ + int error; + xfs_buf_t *bp; + xfs_sb_t *sbp; + + /* + * First replay the images in the log. + */ + error = xlog_do_log_recovery(log, head_blk, tail_blk); + if (error) { + return error; + } + + XFS_bflush(log->l_mp->m_ddev_targp); + + /* + * If IO errors happened during recovery, bail out. + */ + if (XFS_FORCED_SHUTDOWN(log->l_mp)) { + return (EIO); + } + + /* + * We now update the tail_lsn since much of the recovery has completed + * and there may be space available to use. If there were no extent + * or iunlinks, we can free up the entire log and set the tail_lsn to + * be the last_sync_lsn. This was set in xlog_find_tail to be the + * lsn of the last known good LR on disk. If there are extent frees + * or iunlinks they will have some entries in the AIL; so we look at + * the AIL to determine how to set the tail_lsn. + */ + xlog_assign_tail_lsn(log->l_mp, NULL); + + /* + * Now that we've finished replaying all buffer and inode + * updates, re-read in the superblock. + */ + bp = xfs_getsb(log->l_mp, 0); + XFS_BUF_UNDONE(bp); + XFS_BUF_READ(bp); + xfsbdstrat(log->l_mp, bp); + if ((error = xfs_iowait(bp))) { + xfs_ioerror_alert("xlog_do_recover", + log->l_mp, bp, XFS_BUF_ADDR(bp)); + ASSERT(0); + xfs_buf_relse(bp); + return error; + } + + /* convert superblock from on-disk format */ + + sbp=&log->l_mp->m_sb; + xfs_xlatesb(XFS_BUF_TO_SBP(bp), sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC); + ASSERT(XFS_SB_GOOD_VERSION(sbp)); + xfs_buf_relse(bp); + + xlog_recover_check_summary(log); + + /* Normal transactions can now occur */ + log->l_flags &= ~XLOG_ACTIVE_RECOVERY; + return 0; +} /* xlog_do_recover */ + +/* + * Perform recovery and re-initialize some log variables in xlog_find_tail. + * + * Return error or zero. + */ +int +xlog_recover(xlog_t *log, int readonly) +{ + xfs_daddr_t head_blk, tail_blk; + int error; + + /* find the tail of the log */ + + if ((error = xlog_find_tail(log, &head_blk, &tail_blk, readonly))) + return error; + + if (tail_blk != head_blk) { +#ifndef __KERNEL__ + extern xfs_daddr_t HEAD_BLK, TAIL_BLK; + head_blk = HEAD_BLK; + tail_blk = TAIL_BLK; +#endif + /* There used to be a comment here: + * + * disallow recovery on read-only mounts. note -- mount + * checks for ENOSPC and turns it into an intelligent + * error message. + * ...but this is no longer true. Now, unless you specify + * NORECOVERY (in which case this function would never be + * called), we just go ahead and recover. We do this all + * under the vfs layer, so we can get away with it unless + * the device itself is read-only, in which case we fail. + */ +#ifdef __KERNEL__ + if ((error = xfs_dev_is_read_only(log->l_mp, + "recovery required"))) { + return error; + } +#else + if (readonly) { + return ENOSPC; + } +#endif + +#ifdef __KERNEL__ +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, + "Starting XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#else + cmn_err(CE_NOTE, + "!Starting XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#endif +#endif + error = xlog_do_recover(log, head_blk, tail_blk); + log->l_flags |= XLOG_RECOVERY_NEEDED; + } + return error; +} /* xlog_recover */ + + +/* + * In the first part of recovery we replay inodes and buffers and build + * up the list of extent free items which need to be processed. Here + * we process the extent free items and clean up the on disk unlinked + * inode lists. This is separated from the first part of recovery so + * that the root and real-time bitmap inodes can be read in from disk in + * between the two stages. This is necessary so that we can free space + * in the real-time portion of the file system. + */ +int +xlog_recover_finish(xlog_t *log, int mfsi_flags) +{ + /* + * Now we're ready to do the transactions needed for the + * rest of recovery. Start with completing all the extent + * free intent records and then process the unlinked inode + * lists. At this point, we essentially run in normal mode + * except that we're still performing recovery actions + * rather than accepting new requests. + */ + if (log->l_flags & XLOG_RECOVERY_NEEDED) { + xlog_recover_process_efis(log); + /* + * Sync the log to get all the EFIs out of the AIL. + * This isn't absolutely necessary, but it helps in + * case the unlink transactions would have problems + * pushing the EFIs out of the way. + */ + xfs_log_force(log->l_mp, (xfs_lsn_t)0, + (XFS_LOG_FORCE | XFS_LOG_SYNC)); + + if ( (mfsi_flags & XFS_MFSI_NOUNLINK) == 0 ) { + + xlog_recover_process_iunlinks(log); + } + + xlog_recover_check_summary(log); + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, + "Ending XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#else + cmn_err(CE_NOTE, + "!Ending XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#endif + log->l_flags &= ~XLOG_RECOVERY_NEEDED; + } else { + cmn_err(CE_DEBUG, + "!Ending clean XFS mount for filesystem: %s", + log->l_mp->m_fsname); + } + return 0; +} /* xlog_recover_finish */ + + +#if defined(DEBUG) +/* + * Read all of the agf and agi counters and check that they + * are consistent with the superblock counters. + */ +void +xlog_recover_check_summary(xlog_t *log) +{ + xfs_mount_t *mp; + xfs_agf_t *agfp; + xfs_agi_t *agip; + xfs_buf_t *agfbp; + xfs_buf_t *agibp; + xfs_daddr_t agfdaddr; + xfs_daddr_t agidaddr; + xfs_buf_t *sbbp; +#ifdef XFS_LOUD_RECOVERY + xfs_sb_t *sbp; +#endif + xfs_agnumber_t agno; + __uint64_t freeblks; + __uint64_t itotal; + __uint64_t ifree; + + mp = log->l_mp; + + freeblks = 0LL; + itotal = 0LL; + ifree = 0LL; + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + agfdaddr = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR); + agfbp = xfs_buf_read(mp->m_ddev_targp, agfdaddr, 1, 0); + if (XFS_BUF_ISERROR(agfbp)) { + xfs_ioerror_alert("xlog_recover_check_summary(agf)", + log->l_mp, agfbp, agfdaddr); + } + agfp = XFS_BUF_TO_AGF(agfbp); + ASSERT(INT_GET(agfp->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC); + ASSERT(XFS_AGF_GOOD_VERSION(INT_GET(agfp->agf_versionnum, ARCH_CONVERT))); + ASSERT(INT_GET(agfp->agf_seqno, ARCH_CONVERT) == agno); + + freeblks += INT_GET(agfp->agf_freeblks, ARCH_CONVERT) + + INT_GET(agfp->agf_flcount, ARCH_CONVERT); + xfs_buf_relse(agfbp); + + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + agibp = xfs_buf_read(mp->m_ddev_targp, agidaddr, 1, 0); + if (XFS_BUF_ISERROR(agibp)) { + xfs_ioerror_alert("xlog_recover_check_summary(agi)", + log->l_mp, agibp, agidaddr); + } + agip = XFS_BUF_TO_AGI(agibp); + ASSERT(INT_GET(agip->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + ASSERT(XFS_AGI_GOOD_VERSION(INT_GET(agip->agi_versionnum, ARCH_CONVERT))); + ASSERT(INT_GET(agip->agi_seqno, ARCH_CONVERT) == agno); + + itotal += INT_GET(agip->agi_count, ARCH_CONVERT); + ifree += INT_GET(agip->agi_freecount, ARCH_CONVERT); + xfs_buf_relse(agibp); + } + + sbbp = xfs_getsb(mp, 0); +#ifdef XFS_LOUD_RECOVERY + sbp = XFS_BUF_TO_SBP(sbbp); + cmn_err(CE_NOTE, + "xlog_recover_check_summary: sb_icount %Lu itotal %Lu", + sbp->sb_icount, itotal); + cmn_err(CE_NOTE, + "xlog_recover_check_summary: sb_ifree %Lu itotal %Lu", + sbp->sb_ifree, ifree); + cmn_err(CE_NOTE, + "xlog_recover_check_summary: sb_fdblocks %Lu freeblks %Lu", + sbp->sb_fdblocks, freeblks); +#if 0 + /* + * This is turned off until I account for the allocation + * btree blocks which live in free space. + */ + ASSERT(sbp->sb_icount == itotal); + ASSERT(sbp->sb_ifree == ifree); + ASSERT(sbp->sb_fdblocks == freeblks); +#endif +#endif + xfs_buf_relse(sbbp); +} +#endif /* DEBUG */ diff -Nur linux-2.4.19/fs/xfs/xfs_log_recover.h linux-2.4.19-sgi211r3/fs/xfs/xfs_log_recover.h --- linux-2.4.19/fs/xfs/xfs_log_recover.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_log_recover.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LOG_RECOVER_H__ +#define __XFS_LOG_RECOVER_H__ + +/* + * Macros, structures, prototypes for internal log manager use. + */ + +#define XLOG_RHASH_BITS 4 +#define XLOG_RHASH_SIZE 16 +#define XLOG_RHASH_SHIFT 2 +#define XLOG_RHASH(tid) \ + ((((__uint32_t)tid)>>XLOG_RHASH_SHIFT) & (XLOG_RHASH_SIZE-1)) + +#define XLOG_MAX_REGIONS_IN_ITEM (XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK / 2 + 1) + + +/* + * item headers are in ri_buf[0]. Additional buffers follow. + */ +typedef struct xlog_recover_item { + struct xlog_recover_item *ri_next; + struct xlog_recover_item *ri_prev; + int ri_type; + int ri_cnt; /* count of regions found */ + int ri_total; /* total regions */ + xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ +} xlog_recover_item_t; + +struct xlog_tid; +typedef struct xlog_recover { + struct xlog_recover *r_next; + xlog_tid_t r_log_tid; /* log's transaction id */ + xfs_trans_header_t r_theader; /* trans header for partial */ + int r_state; /* not needed */ + xfs_lsn_t r_lsn; /* xact lsn */ + xlog_recover_item_t *r_itemq; /* q for items */ +} xlog_recover_t; + +#define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) + +/* + * This is the number of entries in the l_buf_cancel_table used during + * recovery. + */ +#define XLOG_BC_TABLE_SIZE 64 + +#define XLOG_RECOVER_PASS1 1 +#define XLOG_RECOVER_PASS2 2 + +#endif /* __XFS_LOG_RECOVER_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_mac.c linux-2.4.19-sgi211r3/fs/xfs/xfs_mac.c --- linux-2.4.19/fs/xfs/xfs_mac.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_mac.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +static xfs_mac_label_t *mac_low_high_lp; +static xfs_mac_label_t *mac_high_low_lp; +static xfs_mac_label_t *mac_admin_high_lp; +static xfs_mac_label_t *mac_equal_equal_lp; + +/* + * Test for the existence of a MAC label as efficiently as possible. + */ +int +xfs_mac_vhaslabel( + vnode_t *vp) +{ + int error; + int len = sizeof(xfs_mac_label_t); + int flags = ATTR_KERNOVAL|ATTR_ROOT; + + VOP_ATTR_GET(vp, SGI_MAC_FILE, NULL, &len, flags, sys_cred, error); + return (error == 0); +} + +int +xfs_mac_iaccess(xfs_inode_t *ip, mode_t mode, struct cred *cr) +{ + xfs_mac_label_t mac; + xfs_mac_label_t *mp = mac_high_low_lp; + + if (cr == NULL || sys_cred == NULL ) { + return EACCES; + } + + if (xfs_attr_fetch(ip, SGI_MAC_FILE, (char *)&mac, sizeof(mac)) == 0) { + if ((mp = mac_add_label(&mac)) == NULL) { + return mac_access(mac_high_low_lp, cr, mode); + } + } + + return mac_access(mp, cr, mode); +} diff -Nur linux-2.4.19/fs/xfs/xfs_mac.h linux-2.4.19-sgi211r3/fs/xfs/xfs_mac.h --- linux-2.4.19/fs/xfs/xfs_mac.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_mac.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_MAC_H__ +#define __XFS_MAC_H__ + +/* + * Mandatory Access Control + * + * Layout of a composite MAC label: + * ml_list contains the list of categories (MSEN) followed by the list of + * divisions (MINT). This is actually a header for the data structure which + * will have an ml_list with more than one element. + * + * ------------------------------- + * | ml_msen_type | ml_mint_type | + * ------------------------------- + * | ml_level | ml_grade | + * ------------------------------- + * | ml_catcount | + * ------------------------------- + * | ml_divcount | + * ------------------------------- + * | category 1 | + * | . . . | + * | category N | (where N = ml_catcount) + * ------------------------------- + * | division 1 | + * | . . . | + * | division M | (where M = ml_divcount) + * ------------------------------- + */ +#define XFS_MAC_MAX_SETS 250 +typedef struct xfs_mac_label { + __uint8_t ml_msen_type; /* MSEN label type */ + __uint8_t ml_mint_type; /* MINT label type */ + __uint8_t ml_level; /* Hierarchical level */ + __uint8_t ml_grade; /* Hierarchical grade */ + __uint16_t ml_catcount; /* Category count */ + __uint16_t ml_divcount; /* Division count */ + /* Category set, then Division set */ + __uint16_t ml_list[XFS_MAC_MAX_SETS]; +} xfs_mac_label_t; + +/* MSEN label type names. Choose an upper case ASCII character. */ +#define XFS_MSEN_ADMIN_LABEL 'A' /* Admin: low + + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_ISNULLDSTARTBLOCK) +int +isnulldstartblock(xfs_dfsbno_t x) +{ + return ISNULLDSTARTBLOCK(x); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_ISNULLSTARTBLOCK) +int +isnullstartblock(xfs_fsblock_t x) +{ + return ISNULLSTARTBLOCK(x); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_NULLSTARTBLOCK) +xfs_fsblock_t +nullstartblock(int k) +{ + return NULLSTARTBLOCK(k); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_STARTBLOCKVAL) +xfs_filblks_t +startblockval(xfs_fsblock_t x) +{ + return STARTBLOCKVAL(x); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_CHECK_DADDR) +void +xfs_ag_check_daddr(xfs_mount_t *mp, xfs_daddr_t d, xfs_extlen_t len) +{ + XFS_AG_CHECK_DADDR(mp, d, len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_DADDR) +xfs_daddr_t +xfs_ag_daddr(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_daddr_t d) +{ + return XFS_AG_DADDR(mp, agno, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_BEST_BLOCKS) +xfs_extlen_t +xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks) +{ + return XFS_AG_BEST_BLOCKS(bl, blks); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MAX_BLOCKS) +xfs_extlen_t +xfs_ag_max_blocks(int bl) +{ + return XFS_AG_MAX_BLOCKS(bl); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MAXLEVELS) +int +xfs_ag_maxlevels(xfs_mount_t *mp) +{ + return XFS_AG_MAXLEVELS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MIN_BLOCKS) +xfs_extlen_t +xfs_ag_min_blocks(int bl) +{ + return XFS_AG_MIN_BLOCKS(bl); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGB_TO_DADDR) +xfs_daddr_t +xfs_agb_to_daddr(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) +{ + return XFS_AGB_TO_DADDR(mp, agno, agbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGB_TO_FSB) +xfs_fsblock_t +xfs_agb_to_fsb(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) +{ + return XFS_AGB_TO_FSB(mp, agno, agbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGBLOCK_MAX) +xfs_agblock_t +xfs_agblock_max(xfs_agblock_t a, xfs_agblock_t b) +{ + return XFS_AGBLOCK_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGBLOCK_MIN) +xfs_agblock_t +xfs_agblock_min(xfs_agblock_t a, xfs_agblock_t b) +{ + return XFS_AGBLOCK_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGF_BLOCK) +xfs_agblock_t +xfs_agf_block(xfs_mount_t *mp) +{ + return XFS_AGF_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGF_GOOD_VERSION) +int +xfs_agf_good_version(unsigned v) +{ + return XFS_AGF_GOOD_VERSION(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGFL_BLOCK) +xfs_agblock_t +xfs_agfl_block(xfs_mount_t *mp) +{ + return XFS_AGFL_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGI_BLOCK) +xfs_agblock_t +xfs_agi_block(xfs_mount_t *mp) +{ + return XFS_AGI_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGI_GOOD_VERSION) +int +xfs_agi_good_version(unsigned v) +{ + return XFS_AGI_GOOD_VERSION(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGINO_TO_AGBNO) +xfs_agblock_t +xfs_agino_to_agbno(xfs_mount_t *mp, xfs_agino_t i) +{ + return XFS_AGINO_TO_AGBNO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGINO_TO_INO) +xfs_ino_t +xfs_agino_to_ino(xfs_mount_t *mp, xfs_agnumber_t a, xfs_agino_t i) +{ + return XFS_AGINO_TO_INO(mp, a, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGINO_TO_OFFSET) +int +xfs_agino_to_offset(xfs_mount_t *mp, xfs_agino_t i) +{ + return XFS_AGINO_TO_OFFSET(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_BLOCK_MAXRECS) +int +xfs_alloc_block_maxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_BLOCK_MAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_BLOCK_MINRECS) +int +xfs_alloc_block_minrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_BLOCK_MINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_BLOCK_SIZE) +/*ARGSUSED1*/ +int +xfs_alloc_block_size(int lev, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_BLOCK_SIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_KEY_ADDR) +/*ARGSUSED3*/ +xfs_alloc_key_t * +xfs_alloc_key_addr(xfs_alloc_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_KEY_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_PTR_ADDR) +xfs_alloc_ptr_t * +xfs_alloc_ptr_addr(xfs_alloc_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_PTR_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_REC_ADDR) +/*ARGSUSED3*/ +xfs_alloc_rec_t * +xfs_alloc_rec_addr(xfs_alloc_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_REC_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL) +int +xfs_attr_leaf_entsize_local(int nlen, int vlen) +{ + return XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen, vlen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX) +int +xfs_attr_leaf_entsize_local_max(int bsize) +{ + return XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_ENTSIZE_REMOTE) +int +xfs_attr_leaf_entsize_remote(int nlen) +{ + return XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_NAME) +char * +xfs_attr_leaf_name(xfs_attr_leafblock_t *leafp, int idx) +{ + return XFS_ATTR_LEAF_NAME(leafp, idx); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_NAME_LOCAL) +xfs_attr_leaf_name_local_t * +xfs_attr_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx) +{ + return XFS_ATTR_LEAF_NAME_LOCAL(leafp, idx); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_NAME_REMOTE) +xfs_attr_leaf_name_remote_t * +xfs_attr_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) +{ + return XFS_ATTR_LEAF_NAME_REMOTE(leafp, idx); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_ENTSIZE) +int +xfs_attr_sf_entsize(xfs_attr_sf_entry_t *sfep) +{ + return XFS_ATTR_SF_ENTSIZE(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_ENTSIZE_BYNAME) +int +xfs_attr_sf_entsize_byname(int nlen, int vlen) +{ + return XFS_ATTR_SF_ENTSIZE_BYNAME(nlen, vlen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_NEXTENTRY) +xfs_attr_sf_entry_t * +xfs_attr_sf_nextentry(xfs_attr_sf_entry_t *sfep) +{ + return XFS_ATTR_SF_NEXTENTRY(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_TOTSIZE) +int +xfs_attr_sf_totsize(xfs_inode_t *dp) +{ + return XFS_ATTR_SF_TOTSIZE(dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BHVTOI) +xfs_inode_t * +xfs_bhvtoi(bhv_desc_t *bhvp) +{ + return XFS_BHVTOI(bhvp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BHVTOM) +xfs_mount_t * +xfs_bhvtom(bhv_desc_t *bdp) +{ + return XFS_BHVTOM(bdp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BM_MAXLEVELS) +int +xfs_bm_maxlevels(xfs_mount_t *mp, int w) +{ + return XFS_BM_MAXLEVELS(mp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_DMAXRECS) +int +xfs_bmap_block_dmaxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_DMAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_DMINRECS) +int +xfs_bmap_block_dminrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_DMINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_DSIZE) +int +xfs_bmap_block_dsize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_DSIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_IMAXRECS) +int +xfs_bmap_block_imaxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_IMAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_IMINRECS) +int +xfs_bmap_block_iminrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_IMINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_ISIZE) +int +xfs_bmap_block_isize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_ISIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_KEY_ADDR) +/*ARGSUSED3*/ +xfs_bmbt_key_t * +xfs_bmap_broot_key_addr(xfs_bmbt_block_t *bb, int i, int sz) +{ + return XFS_BMAP_BROOT_KEY_ADDR(bb, i, sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_MAXRECS) +int +xfs_bmap_broot_maxrecs(int sz) +{ + return XFS_BMAP_BROOT_MAXRECS(sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_NUMRECS) +int +xfs_bmap_broot_numrecs(xfs_bmdr_block_t *bb) +{ + return XFS_BMAP_BROOT_NUMRECS(bb); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_PTR_ADDR) +xfs_bmbt_ptr_t * +xfs_bmap_broot_ptr_addr(xfs_bmbt_block_t *bb, int i, int sz) +{ + return XFS_BMAP_BROOT_PTR_ADDR(bb, i, sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_REC_ADDR) +/*ARGSUSED3*/ +xfs_bmbt_rec_t * +xfs_bmap_broot_rec_addr(xfs_bmbt_block_t *bb, int i, int sz) +{ + return XFS_BMAP_BROOT_REC_ADDR(bb, i, sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_SPACE) +int +xfs_bmap_broot_space(xfs_bmdr_block_t *bb) +{ + return XFS_BMAP_BROOT_SPACE(bb); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_SPACE_CALC) +int +xfs_bmap_broot_space_calc(int nrecs) +{ + return XFS_BMAP_BROOT_SPACE_CALC(nrecs); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_IBLOCK_SIZE) +/*ARGSUSED1*/ +int +xfs_bmap_iblock_size(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_IBLOCK_SIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_INIT) +void +xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp) +{ + XFS_BMAP_INIT(flp, fbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_KEY_DADDR) +/*ARGSUSED3*/ +xfs_bmbt_key_t * +xfs_bmap_key_daddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_KEY_DADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_KEY_IADDR) +/*ARGSUSED3*/ +xfs_bmbt_key_t * +xfs_bmap_key_iaddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_KEY_IADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_PTR_DADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_daddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_PTR_DADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_PTR_IADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_iaddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_PTR_IADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_RBLOCK_DSIZE) +/*ARGSUSED1*/ +int +xfs_bmap_rblock_dsize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_RBLOCK_DSIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_RBLOCK_ISIZE) +/*ARGSUSED1*/ +int +xfs_bmap_rblock_isize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_RBLOCK_ISIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_REC_DADDR) +/*ARGSUSED3*/ +xfs_bmbt_rec_t * +xfs_bmap_rec_daddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_REC_DADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_REC_IADDR) +/*ARGSUSED3*/ +xfs_bmbt_rec_t * +xfs_bmap_rec_iaddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_REC_IADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_SANITY_CHECK) +int +xfs_bmap_sanity_check(xfs_mount_t *mp, xfs_bmbt_block_t *bb, int level) +{ + return XFS_BMAP_SANITY_CHECK(mp, bb, level); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAPI_AFLAG) +int +xfs_bmapi_aflag(int w) +{ + return XFS_BMAPI_AFLAG(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMDR_SPACE_CALC) +int +xfs_bmdr_space_calc(int nrecs) +{ + return XFS_BMDR_SPACE_CALC(nrecs); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BNO_BLOCK) +xfs_agblock_t +xfs_bno_block(xfs_mount_t *mp) +{ + return XFS_BNO_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BTREE_LONG_PTRS) +int +xfs_btree_long_ptrs(xfs_btnum_t btnum) +{ + return XFS_BTREE_LONG_PTRS(btnum); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_AGF) +xfs_agf_t * +xfs_buf_to_agf(xfs_buf_t *bp) +{ + return XFS_BUF_TO_AGF(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_AGFL) +xfs_agfl_t * +xfs_buf_to_agfl(xfs_buf_t *bp) +{ + return XFS_BUF_TO_AGFL(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_AGI) +xfs_agi_t * +xfs_buf_to_agi(xfs_buf_t *bp) +{ + return XFS_BUF_TO_AGI(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_ALLOC_BLOCK) +xfs_alloc_block_t * +xfs_buf_to_alloc_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_ALLOC_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_BLOCK) +xfs_btree_block_t * +xfs_buf_to_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_BMBT_BLOCK) +xfs_bmbt_block_t * +xfs_buf_to_bmbt_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_BMBT_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_DINODE) +xfs_dinode_t * +xfs_buf_to_dinode(xfs_buf_t *bp) +{ + return XFS_BUF_TO_DINODE(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_INOBT_BLOCK) +xfs_inobt_block_t * +xfs_buf_to_inobt_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_INOBT_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_LBLOCK) +xfs_btree_lblock_t * +xfs_buf_to_lblock(xfs_buf_t *bp) +{ + return XFS_BUF_TO_LBLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_SBLOCK) +xfs_btree_sblock_t * +xfs_buf_to_sblock(xfs_buf_t *bp) +{ + return XFS_BUF_TO_SBLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_SBP) +xfs_sb_t * +xfs_buf_to_sbp(xfs_buf_t *bp) +{ + return XFS_BUF_TO_SBP(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_ASIZE) +int +xfs_cfork_asize_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_CFORK_ASIZE_ARCH(dcp, mp, arch); +} +int +xfs_cfork_asize(xfs_dinode_core_t *dcp, xfs_mount_t *mp) +{ + return XFS_CFORK_ASIZE(dcp, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_BOFF) +int +xfs_cfork_boff_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch) +{ + return XFS_CFORK_BOFF_ARCH(dcp, arch); +} +int +xfs_cfork_boff(xfs_dinode_core_t *dcp) +{ + return XFS_CFORK_BOFF(dcp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_DSIZE) +int +xfs_cfork_dsize_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_CFORK_DSIZE_ARCH(dcp, mp, arch); +} +int +xfs_cfork_dsize(xfs_dinode_core_t *dcp, xfs_mount_t *mp) +{ + return XFS_CFORK_DSIZE(dcp, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_FMT_SET) +void +xfs_cfork_fmt_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch) +{ + XFS_CFORK_FMT_SET_ARCH(dcp, w, n, arch); +} +void +xfs_cfork_fmt_set(xfs_dinode_core_t *dcp, int w, int n) +{ + XFS_CFORK_FMT_SET(dcp, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_FORMAT) +int +xfs_cfork_format_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch) +{ + return XFS_CFORK_FORMAT_ARCH(dcp, w, arch); +} +int +xfs_cfork_format(xfs_dinode_core_t *dcp, int w) +{ + return XFS_CFORK_FORMAT(dcp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_NEXT_SET) +void +xfs_cfork_next_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch) +{ + XFS_CFORK_NEXT_SET_ARCH(dcp, w, n, arch); +} +void +xfs_cfork_next_set(xfs_dinode_core_t *dcp, int w, int n) +{ + XFS_CFORK_NEXT_SET(dcp, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_NEXTENTS) +int +xfs_cfork_nextents_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch) +{ + return XFS_CFORK_NEXTENTS_ARCH(dcp, w, arch); +} +int +xfs_cfork_nextents(xfs_dinode_core_t *dcp, int w) +{ + return XFS_CFORK_NEXTENTS(dcp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_Q) +int +xfs_cfork_q_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch) +{ + return XFS_CFORK_Q_ARCH(dcp, arch); +} +int +xfs_cfork_q(xfs_dinode_core_t *dcp) +{ + return XFS_CFORK_Q(dcp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_SIZE) +int +xfs_cfork_size_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, int w, xfs_arch_t arch) +{ + return XFS_CFORK_SIZE_ARCH(dcp, mp, w, arch); +} +int +xfs_cfork_size(xfs_dinode_core_t *dcp, xfs_mount_t *mp, int w) +{ + return XFS_CFORK_SIZE(dcp, mp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CNT_BLOCK) +xfs_agblock_t +xfs_cnt_block(xfs_mount_t *mp) +{ + return XFS_CNT_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_COOKIE_BNO) +xfs_dablk_t +xfs_da_cookie_bno(xfs_mount_t *mp, xfs_off_t cookie) +{ + return XFS_DA_COOKIE_BNO(mp, cookie); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_COOKIE_ENTRY) +int +xfs_da_cookie_entry(xfs_mount_t *mp, xfs_off_t cookie) +{ + return XFS_DA_COOKIE_ENTRY(mp, cookie); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_COOKIE_HASH) +/*ARGSUSED1*/ +xfs_dahash_t +xfs_da_cookie_hash(xfs_mount_t *mp, xfs_off_t cookie) +{ + return XFS_DA_COOKIE_HASH(mp, cookie); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_MAKE_BNOENTRY) +__uint32_t +xfs_da_make_bnoentry(xfs_mount_t *mp, xfs_dablk_t bno, int entry) +{ + return XFS_DA_MAKE_BNOENTRY(mp, bno, entry); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_MAKE_COOKIE) +xfs_off_t +xfs_da_make_cookie(xfs_mount_t *mp, xfs_dablk_t bno, int entry, + xfs_dahash_t hash) +{ + return XFS_DA_MAKE_COOKIE(mp, bno, entry, hash); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_NODE_ENTRIES) +int +xfs_da_node_entries(xfs_mount_t *mp) +{ + return XFS_DA_NODE_ENTRIES(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DADDR_TO_AGBNO) +xfs_agblock_t +xfs_daddr_to_agbno(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_DADDR_TO_AGBNO(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DADDR_TO_AGNO) +xfs_agnumber_t +xfs_daddr_to_agno(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_DADDR_TO_AGNO(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DADDR_TO_FSB) +xfs_fsblock_t +xfs_daddr_to_fsb(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_DADDR_TO_FSB(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_APTR) +char * +xfs_dfork_aptr_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_APTR_ARCH(dip, arch); +} +char * +xfs_dfork_aptr(xfs_dinode_t *dip) +{ + return XFS_DFORK_APTR(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_ASIZE) +int +xfs_dfork_asize_arch(xfs_dinode_t *dip, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_DFORK_ASIZE_ARCH(dip, mp, arch); +} +int +xfs_dfork_asize(xfs_dinode_t *dip, xfs_mount_t *mp) +{ + return XFS_DFORK_ASIZE(dip, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_BOFF) +int +xfs_dfork_boff_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_BOFF_ARCH(dip, arch); +} +int +xfs_dfork_boff(xfs_dinode_t *dip) +{ + return XFS_DFORK_BOFF(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_DPTR) +char * +xfs_dfork_dptr_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_DPTR_ARCH(dip, arch); +} +char * +xfs_dfork_dptr(xfs_dinode_t *dip) +{ + return XFS_DFORK_DPTR(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_DSIZE) +int +xfs_dfork_dsize_arch(xfs_dinode_t *dip, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_DFORK_DSIZE_ARCH(dip, mp, arch); +} +int +xfs_dfork_dsize(xfs_dinode_t *dip, xfs_mount_t *mp) +{ + return XFS_DFORK_DSIZE(dip, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_FMT_SET) +void +xfs_dfork_fmt_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch) +{ + XFS_DFORK_FMT_SET_ARCH(dip, w, n, arch); +} +void +xfs_dfork_fmt_set(xfs_dinode_t *dip, int w, int n) +{ + XFS_DFORK_FMT_SET(dip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_FORMAT) +int +xfs_dfork_format_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch) +{ + return XFS_DFORK_FORMAT_ARCH(dip, w, arch); +} +int +xfs_dfork_format(xfs_dinode_t *dip, int w) +{ + return XFS_DFORK_FORMAT(dip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_NEXT_SET) +void +xfs_dfork_next_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch) +{ + XFS_DFORK_NEXT_SET_ARCH(dip, w, n, arch); +} +void +xfs_dfork_next_set(xfs_dinode_t *dip, int w, int n) +{ + XFS_DFORK_NEXT_SET(dip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_NEXTENTS) +int +xfs_dfork_nextents_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch) +{ + return XFS_DFORK_NEXTENTS_ARCH(dip, w, arch); +} +int +xfs_dfork_nextents(xfs_dinode_t *dip, int w) +{ + return XFS_DFORK_NEXTENTS(dip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_PTR) +char * +xfs_dfork_ptr_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch) +{ + return XFS_DFORK_PTR_ARCH(dip, w, arch); +} +char * +xfs_dfork_ptr(xfs_dinode_t *dip, int w) +{ + return XFS_DFORK_PTR(dip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_Q) +int +xfs_dfork_q_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_Q_ARCH(dip, arch); +} +int +xfs_dfork_q(xfs_dinode_t *dip) +{ + return XFS_DFORK_Q(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_SIZE) +int +xfs_dfork_size_arch(xfs_dinode_t *dip, xfs_mount_t *mp, int w, xfs_arch_t arch) +{ + return XFS_DFORK_SIZE_ARCH(dip, mp, w, arch); +} +int +xfs_dfork_size(xfs_dinode_t *dip, xfs_mount_t *mp, int w) +{ + return XFS_DFORK_SIZE(dip, mp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DINODE_GOOD_VERSION) +int +xfs_dinode_good_version(int v) +{ + return XFS_DINODE_GOOD_VERSION(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYENTRY) +int +xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry) +{ + return XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYNAME) +int +xfs_dir_leaf_entsize_byname(int len) +{ + return XFS_DIR_LEAF_ENTSIZE_BYNAME(len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_LEAF_NAMESTRUCT) +xfs_dir_leaf_name_t * +xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset) +{ + return XFS_DIR_LEAF_NAMESTRUCT(leafp, offset); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_ALLFIT) +int +xfs_dir_sf_allfit(int count, int totallen) +{ + return XFS_DIR_SF_ALLFIT(count, totallen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_ENTSIZE_BYENTRY) +int +xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep) +{ + return XFS_DIR_SF_ENTSIZE_BYENTRY(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_ENTSIZE_BYNAME) +int +xfs_dir_sf_entsize_byname(int len) +{ + return XFS_DIR_SF_ENTSIZE_BYNAME(len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_GET_DIRINO) +void +xfs_dir_sf_get_dirino_arch(xfs_dir_ino_t *from, xfs_ino_t *to, xfs_arch_t arch) +{ + XFS_DIR_SF_GET_DIRINO_ARCH(from, to, arch); +} +void +xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to) +{ + XFS_DIR_SF_GET_DIRINO(from, to); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_NEXTENTRY) +xfs_dir_sf_entry_t * +xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep) +{ + return XFS_DIR_SF_NEXTENTRY(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_PUT_DIRINO) +void +xfs_dir_sf_put_dirino_arch(xfs_ino_t *from, xfs_dir_ino_t *to, xfs_arch_t arch) +{ + XFS_DIR_SF_PUT_DIRINO_ARCH(from, to, arch); +} +void +xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to) +{ + XFS_DIR_SF_PUT_DIRINO(from, to); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BLOCK_LEAF_P) +xfs_dir2_leaf_entry_t * +xfs_dir2_block_leaf_p_arch(xfs_dir2_block_tail_t *btp, xfs_arch_t arch) +{ + return XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BLOCK_TAIL_P) +xfs_dir2_block_tail_t * +xfs_dir2_block_tail_p(xfs_mount_t *mp, xfs_dir2_block_t *block) +{ + return XFS_DIR2_BLOCK_TAIL_P(mp, block); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_DA) +xfs_dablk_t +xfs_dir2_byte_to_da(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_DA(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_DATAPTR) +/* ARGSUSED */ +xfs_dir2_dataptr_t +xfs_dir2_byte_to_dataptr(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_DATAPTR(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_DB) +xfs_dir2_db_t +xfs_dir2_byte_to_db(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_DB(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_byte_to_off(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_OFF(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DA_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_da_to_byte(xfs_mount_t *mp, xfs_dablk_t da) +{ + return XFS_DIR2_DA_TO_BYTE(mp, da); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DA_TO_DB) +xfs_dir2_db_t +xfs_dir2_da_to_db(xfs_mount_t *mp, xfs_dablk_t da) +{ + return XFS_DIR2_DA_TO_DB(mp, da); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATA_ENTRY_TAG_P) +xfs_dir2_data_off_t * +xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep) +{ + return XFS_DIR2_DATA_ENTRY_TAG_P(dep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATA_ENTSIZE) +int +xfs_dir2_data_entsize(int n) +{ + return XFS_DIR2_DATA_ENTSIZE(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATA_UNUSED_TAG_P) +xfs_dir2_data_off_t * +xfs_dir2_data_unused_tag_p_arch(xfs_dir2_data_unused_t *dup, xfs_arch_t arch) +{ + return XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATAPTR_TO_BYTE) +/* ARGSUSED */ +xfs_dir2_off_t +xfs_dir2_dataptr_to_byte(xfs_mount_t *mp, xfs_dir2_dataptr_t dp) +{ + return XFS_DIR2_DATAPTR_TO_BYTE(mp, dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATAPTR_TO_DB) +xfs_dir2_db_t +xfs_dir2_dataptr_to_db(xfs_mount_t *mp, xfs_dir2_dataptr_t dp) +{ + return XFS_DIR2_DATAPTR_TO_DB(mp, dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATAPTR_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_dataptr_to_off(xfs_mount_t *mp, xfs_dir2_dataptr_t dp) +{ + return XFS_DIR2_DATAPTR_TO_OFF(mp, dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_OFF_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_db_off_to_byte(xfs_mount_t *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o) +{ + return XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_OFF_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_db_off_to_dataptr(xfs_mount_t *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o) +{ + return XFS_DIR2_DB_OFF_TO_DATAPTR(mp, db, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_TO_DA) +xfs_dablk_t +xfs_dir2_db_to_da(xfs_mount_t *mp, xfs_dir2_db_t db) +{ + return XFS_DIR2_DB_TO_DA(mp, db); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_TO_FDB) +xfs_dir2_db_t +xfs_dir2_db_to_fdb(xfs_mount_t *mp, xfs_dir2_db_t db) +{ + return XFS_DIR2_DB_TO_FDB(mp, db); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_TO_FDINDEX) +int +xfs_dir2_db_to_fdindex(xfs_mount_t *mp, xfs_dir2_db_t db) +{ + return XFS_DIR2_DB_TO_FDINDEX(mp, db); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_LEAF_BESTS_P) +xfs_dir2_data_off_t * +xfs_dir2_leaf_bests_p_arch(xfs_dir2_leaf_tail_t *ltp, xfs_arch_t arch) +{ + return XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_LEAF_TAIL_P) +xfs_dir2_leaf_tail_t * +xfs_dir2_leaf_tail_p(xfs_mount_t *mp, xfs_dir2_leaf_t *lp) +{ + return XFS_DIR2_LEAF_TAIL_P(mp, lp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_MAX_LEAF_ENTS) +int +xfs_dir2_max_leaf_ents(xfs_mount_t *mp) +{ + return XFS_DIR2_MAX_LEAF_ENTS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_ENTSIZE_BYENTRY) +int +xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep) +{ + return XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_FIRSTENTRY) +xfs_dir2_sf_entry_t * +xfs_dir2_sf_firstentry(xfs_dir2_sf_t *sfp) +{ + return XFS_DIR2_SF_FIRSTENTRY(sfp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_ENTSIZE_BYNAME) +int +xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len) +{ + return XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_GET_INUMBER) +xfs_intino_t +xfs_dir2_sf_get_inumber_arch(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from, xfs_arch_t arch) +{ + return XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_GET_OFFSET) +xfs_dir2_data_aoff_t +xfs_dir2_sf_get_offset_arch(xfs_dir2_sf_entry_t *sfep, xfs_arch_t arch) +{ + return XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_HDR_SIZE) +int +xfs_dir2_sf_hdr_size(int i8count) +{ + return XFS_DIR2_SF_HDR_SIZE(i8count); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_INUMBERP) +xfs_dir2_inou_t * +xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep) +{ + return XFS_DIR2_SF_INUMBERP(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_NEXTENTRY) +xfs_dir2_sf_entry_t * +xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep) +{ + return XFS_DIR2_SF_NEXTENTRY(sfp, sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_PUT_INUMBER) +void +xfs_dir2_sf_put_inumber_arch(xfs_dir2_sf_t *sfp, xfs_ino_t *from, xfs_dir2_inou_t *to, xfs_arch_t arch) +{ + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, from, to, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_PUT_OFFSET) +void +xfs_dir2_sf_put_offset_arch(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off, xfs_arch_t arch) +{ + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, off, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_EXTFMT_INODE ) +xfs_exntfmt_t +xfs_extfmt_inode(struct xfs_inode *ip) +{ + return XFS_EXTFMT_INODE(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_EXTLEN_MAX) +xfs_extlen_t +xfs_extlen_max(xfs_extlen_t a, xfs_extlen_t b) +{ + return XFS_EXTLEN_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_EXTLEN_MIN) +xfs_extlen_t +xfs_extlen_min(xfs_extlen_t a, xfs_extlen_t b) +{ + return XFS_EXTLEN_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILBLKS_MAX) +xfs_filblks_t +xfs_filblks_max(xfs_filblks_t a, xfs_filblks_t b) +{ + return XFS_FILBLKS_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILBLKS_MIN) +xfs_filblks_t +xfs_filblks_min(xfs_filblks_t a, xfs_filblks_t b) +{ + return XFS_FILBLKS_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILEOFF_MAX) +xfs_fileoff_t +xfs_fileoff_max(xfs_fileoff_t a, xfs_fileoff_t b) +{ + return XFS_FILEOFF_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILEOFF_MIN) +xfs_fileoff_t +xfs_fileoff_min(xfs_fileoff_t a, xfs_fileoff_t b) +{ + return XFS_FILEOFF_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_SANITY_CHECK) +int +xfs_fsb_sanity_check(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_SANITY_CHECK(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_AGBNO) +xfs_agblock_t +xfs_fsb_to_agbno(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_TO_AGBNO(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_AGNO) +xfs_agnumber_t +xfs_fsb_to_agno(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_TO_AGNO(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_DADDR) +xfs_daddr_t +xfs_fsb_to_daddr(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_TO_DADDR(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_DB) +xfs_daddr_t +xfs_fsb_to_db(xfs_inode_t *ip, xfs_fsblock_t fsb) +{ + return XFS_FSB_TO_DB(ip, fsb); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_HDR_BLOCK) +xfs_agblock_t +xfs_hdr_block(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_HDR_BLOCK(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IALLOC_BLOCKS) +xfs_extlen_t +xfs_ialloc_blocks(xfs_mount_t *mp) +{ + return XFS_IALLOC_BLOCKS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IALLOC_FIND_FREE) +int +xfs_ialloc_find_free(xfs_inofree_t *fp) +{ + return XFS_IALLOC_FIND_FREE(fp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IALLOC_INODES) +int +xfs_ialloc_inodes(xfs_mount_t *mp) +{ + return XFS_IALLOC_INODES(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IBT_BLOCK) +xfs_agblock_t +xfs_ibt_block(xfs_mount_t *mp) +{ + return XFS_IBT_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_ASIZE) +int +xfs_ifork_asize(xfs_inode_t *ip) +{ + return XFS_IFORK_ASIZE(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_DSIZE) +int +xfs_ifork_dsize(xfs_inode_t *ip) +{ + return XFS_IFORK_DSIZE(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_FMT_SET) +void +xfs_ifork_fmt_set(xfs_inode_t *ip, int w, int n) +{ + XFS_IFORK_FMT_SET(ip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_FORMAT) +int +xfs_ifork_format(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_FORMAT(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_NEXT_SET) +void +xfs_ifork_next_set(xfs_inode_t *ip, int w, int n) +{ + XFS_IFORK_NEXT_SET(ip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_NEXTENTS) +int +xfs_ifork_nextents(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_NEXTENTS(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_PTR) +xfs_ifork_t * +xfs_ifork_ptr(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_PTR(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_Q) +int +xfs_ifork_q(xfs_inode_t *ip) +{ + return XFS_IFORK_Q(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_SIZE) +int +xfs_ifork_size(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_SIZE(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ILOG_FBROOT) +int +xfs_ilog_fbroot(int w) +{ + return XFS_ILOG_FBROOT(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ILOG_FDATA) +int +xfs_ilog_fdata(int w) +{ + return XFS_ILOG_FDATA(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ILOG_FEXT) +int +xfs_ilog_fext(int w) +{ + return XFS_ILOG_FEXT(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IN_MAXLEVELS) +int +xfs_in_maxlevels(xfs_mount_t *mp) +{ + return XFS_IN_MAXLEVELS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_AGBNO_BITS) +int +xfs_ino_agbno_bits(xfs_mount_t *mp) +{ + return XFS_INO_AGBNO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_AGINO_BITS) +int +xfs_ino_agino_bits(xfs_mount_t *mp) +{ + return XFS_INO_AGINO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_AGNO_BITS) +int +xfs_ino_agno_bits(xfs_mount_t *mp) +{ + return XFS_INO_AGNO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_BITS) +int +xfs_ino_bits(xfs_mount_t *mp) +{ + return XFS_INO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_MASK) +__uint32_t +xfs_ino_mask(int k) +{ + return XFS_INO_MASK(k); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_OFFSET_BITS) +int +xfs_ino_offset_bits(xfs_mount_t *mp) +{ + return XFS_INO_OFFSET_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_AGBNO) +xfs_agblock_t +xfs_ino_to_agbno(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_AGBNO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_AGINO) +xfs_agino_t +xfs_ino_to_agino(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_AGINO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_AGNO) +xfs_agnumber_t +xfs_ino_to_agno(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_AGNO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_FSB) +xfs_fsblock_t +xfs_ino_to_fsb(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_FSB(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_OFFSET) +int +xfs_ino_to_offset(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_OFFSET(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_BLOCK_MAXRECS) +int +xfs_inobt_block_maxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_BLOCK_MAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_BLOCK_MINRECS) +int +xfs_inobt_block_minrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_BLOCK_MINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_BLOCK_SIZE) +/*ARGSUSED1*/ +int +xfs_inobt_block_size(int lev, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_BLOCK_SIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_CLR_FREE) +void +xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch) +{ + XFS_INOBT_CLR_FREE(rp, i, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_FREE) +int +xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch) +{ + return XFS_INOBT_IS_FREE(rp, i, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_LAST_REC) +int +xfs_inobt_is_last_rec(xfs_btree_cur_t *cur) +{ + return XFS_INOBT_IS_LAST_REC(cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_KEY_ADDR) +/*ARGSUSED3*/ +xfs_inobt_key_t * +xfs_inobt_key_addr(xfs_inobt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_KEY_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_MASK) +xfs_inofree_t +xfs_inobt_mask(int i) +{ + return XFS_INOBT_MASK(i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_MASKN) +xfs_inofree_t +xfs_inobt_maskn(int i, int n) +{ + return XFS_INOBT_MASKN(i, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_PTR_ADDR) +xfs_inobt_ptr_t * +xfs_inobt_ptr_addr(xfs_inobt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_PTR_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_REC_ADDR) +/*ARGSUSED3*/ +xfs_inobt_rec_t * +xfs_inobt_rec_addr(xfs_inobt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_REC_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_SET_FREE) +void +xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch) +{ + XFS_INOBT_SET_FREE(rp, i, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ITOBHV) +bhv_desc_t * +xfs_itobhv(xfs_inode_t *ip) +{ + return XFS_ITOBHV(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ITOV) +vnode_t * +xfs_itov(xfs_inode_t *ip) +{ + return XFS_ITOV(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LBLOG) +int +xfs_lblog(xfs_mount_t *mp) +{ + return XFS_LBLOG(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LBSIZE) +int +xfs_lbsize(xfs_mount_t *mp) +{ + return XFS_LBSIZE(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_ALL_FREE) +void +xfs_lic_all_free(xfs_log_item_chunk_t *cp) +{ + XFS_LIC_ALL_FREE(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_ARE_ALL_FREE) +int +xfs_lic_are_all_free(xfs_log_item_chunk_t *cp) +{ + return XFS_LIC_ARE_ALL_FREE(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_CLAIM) +void +xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot) +{ + XFS_LIC_CLAIM(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_DESC_TO_CHUNK) +xfs_log_item_chunk_t * +xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp) +{ + return XFS_LIC_DESC_TO_CHUNK(dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_DESC_TO_SLOT) +int +xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp) +{ + return XFS_LIC_DESC_TO_SLOT(dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_INIT) +void +xfs_lic_init(xfs_log_item_chunk_t *cp) +{ + XFS_LIC_INIT(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_INIT_SLOT) +void +xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot) +{ + XFS_LIC_INIT_SLOT(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_ISFREE) +int +xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot) +{ + return XFS_LIC_ISFREE(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_RELSE) +void +xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot) +{ + XFS_LIC_RELSE(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_SLOT) +xfs_log_item_desc_t * +xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot) +{ + return XFS_LIC_SLOT(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_VACANCY) +int +xfs_lic_vacancy(xfs_log_item_chunk_t *cp) +{ + return XFS_LIC_VACANCY(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LITINO) +int +xfs_litino(xfs_mount_t *mp) +{ + return XFS_LITINO(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MAKE_IPTR) +xfs_dinode_t * +xfs_make_iptr(xfs_mount_t *mp, xfs_buf_t *b, int o) +{ + return XFS_MAKE_IPTR(mp, b, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK32HI) +__uint32_t +xfs_mask32hi(int n) +{ + return XFS_MASK32HI(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK32LO) +__uint32_t +xfs_mask32lo(int n) +{ + return XFS_MASK32LO(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK64HI) +__uint64_t +xfs_mask64hi(int n) +{ + return XFS_MASK64HI(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK64LO) +__uint64_t +xfs_mask64lo(int n) +{ + return XFS_MASK64LO(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MIN_FREELIST) +int +xfs_min_freelist(xfs_agf_t *a, xfs_mount_t *mp) +{ + return XFS_MIN_FREELIST(a, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MIN_FREELIST_PAG) +int +xfs_min_freelist_pag(xfs_perag_t *pag, xfs_mount_t *mp) +{ + return XFS_MIN_FREELIST_PAG(pag, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MIN_FREELIST_RAW) +int +xfs_min_freelist_raw(uint bl, uint cl, xfs_mount_t *mp) +{ + return XFS_MIN_FREELIST_RAW(bl, cl, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MTOVFS) +vfs_t * +xfs_mtovfs(xfs_mount_t *mp) +{ + return XFS_MTOVFS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_OFFBNO_TO_AGINO) +xfs_agino_t +xfs_offbno_to_agino(xfs_mount_t *mp, xfs_agblock_t b, int o) +{ + return XFS_OFFBNO_TO_AGINO(mp, b, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_PREALLOC_BLOCKS) +xfs_agblock_t +xfs_prealloc_blocks(xfs_mount_t *mp) +{ + return XFS_PREALLOC_BLOCKS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_BLOCK) +xfs_agblock_t +xfs_sb_block(xfs_mount_t *mp) +{ + return XFS_SB_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_GOOD_VERSION) +int +xfs_sb_good_version(xfs_sb_t *sbp) +{ + return XFS_SB_GOOD_VERSION(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDATTR) +void +xfs_sb_version_addattr(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDATTR(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDDALIGN) +void +xfs_sb_version_adddalign(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDDALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDNLINK) +void +xfs_sb_version_addnlink(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDNLINK(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDQUOTA) +void +xfs_sb_version_addquota(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDQUOTA(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDSHARED) +void +xfs_sb_version_addshared(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDSHARED(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASALIGN) +int +xfs_sb_version_hasalign(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASATTR) +int +xfs_sb_version_hasattr(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASATTR(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASDALIGN) +int +xfs_sb_version_hasdalign(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASDALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASDIRV2) +int +xfs_sb_version_hasdirv2(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASDIRV2(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT) +int +xfs_sb_version_hasextflgbit(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASEXTFLGBIT(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASNLINK) +int +xfs_sb_version_hasnlink(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASNLINK(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASQUOTA) +int +xfs_sb_version_hasquota(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASQUOTA(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASSHARED) +int +xfs_sb_version_hasshared(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASSHARED(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_NUM) +int +xfs_sb_version_num(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_SUBALIGN) +void +xfs_sb_version_subalign(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_SUBALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_SUBSHARED) +void +xfs_sb_version_subshared(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_SUBSHARED(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASLOGV2) +int +xfs_sb_version_haslogv2(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASLOGV2(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_TONEW) +unsigned +xfs_sb_version_tonew(unsigned v) +{ + return XFS_SB_VERSION_TONEW(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_TOOLD) +unsigned +xfs_sb_version_toold(unsigned v) +{ + return XFS_SB_VERSION_TOOLD(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_BTOLRBB) +int +xlog_btolrbb(int b) +{ + return XLOG_BTOLRBB(b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_GRANT_ADD_SPACE) +void +xlog_grant_add_space(xlog_t *log, int bytes, int type) +{ + XLOG_GRANT_ADD_SPACE(log, bytes, type); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_GRANT_SUB_SPACE) +void +xlog_grant_sub_space(xlog_t *log, int bytes, int type) +{ + XLOG_GRANT_SUB_SPACE(log, bytes, type); +} +#endif diff -Nur linux-2.4.19/fs/xfs/xfs_macros.h linux-2.4.19-sgi211r3/fs/xfs/xfs_macros.h --- linux-2.4.19/fs/xfs/xfs_macros.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_macros.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_MACROS_H__ +#define __XFS_MACROS_H__ + +/* + * Set for debug kernels and simulation, and 32-bit kernels, + * but not for standalone. These replacements save space. + * Used in xfs_macros.c. + */ +#define XFS_WANT_SPACE_C \ + (!defined(_STANDALONE) && \ + (defined(DEBUG) || (defined(_KERNEL)))) + +/* + * Set for debug simulation and kernel builds, but not for standalone. + * These replacements do not save space. + * Used in xfs_macros.c. + */ +#define XFS_WANT_FUNCS_C \ + (!defined(_STANDALONE) && defined(DEBUG)) + +/* + * Corresponding names used in .h files. + */ +#define XFS_WANT_SPACE (XFS_WANT_SPACE_C && !defined(XFS_MACRO_C)) +#define XFS_WANT_FUNCS (XFS_WANT_FUNCS_C && !defined(XFS_MACRO_C)) + +/* + * These are the macros that get turned into functions to save space. + */ +#define XFSSO_NULLSTARTBLOCK 1 +#define XFSSO_XFS_AGB_TO_DADDR 1 +#define XFSSO_XFS_AGB_TO_FSB 1 +#define XFSSO_XFS_AGINO_TO_INO 1 +#define XFSSO_XFS_ALLOC_BLOCK_MINRECS 1 +#define XFSSO_XFS_ATTR_SF_NEXTENTRY 1 +#define XFSSO_XFS_BMAP_BLOCK_DMAXRECS 1 +#define XFSSO_XFS_BMAP_BLOCK_IMAXRECS 1 +#define XFSSO_XFS_BMAP_BLOCK_IMINRECS 1 +#define XFSSO_XFS_BMAP_INIT 1 +#define XFSSO_XFS_BMAP_PTR_IADDR 1 +#define XFSSO_XFS_BMAP_SANITY_CHECK 1 +#define XFSSO_XFS_BMAPI_AFLAG 1 +#define XFSSO_XFS_CFORK_SIZE 1 +#define XFSSO_XFS_DA_COOKIE_BNO 1 +#define XFSSO_XFS_DA_COOKIE_ENTRY 1 +#define XFSSO_XFS_DADDR_TO_AGBNO 1 +#define XFSSO_XFS_DADDR_TO_FSB 1 +#define XFSSO_XFS_DFORK_PTR 1 +#define XFSSO_XFS_DIR_SF_GET_DIRINO 1 +#define XFSSO_XFS_DIR_SF_NEXTENTRY 1 +#define XFSSO_XFS_DIR_SF_PUT_DIRINO 1 +#define XFSSO_XFS_FILBLKS_MIN 1 +#define XFSSO_XFS_FSB_SANITY_CHECK 1 +#define XFSSO_XFS_FSB_TO_DADDR 1 +#define XFSSO_XFS_FSB_TO_DB 1 +#define XFSSO_XFS_IALLOC_INODES 1 +#define XFSSO_XFS_IFORK_ASIZE 1 +#define XFSSO_XFS_IFORK_DSIZE 1 +#define XFSSO_XFS_IFORK_FORMAT 1 +#define XFSSO_XFS_IFORK_NEXT_SET 1 +#define XFSSO_XFS_IFORK_NEXTENTS 1 +#define XFSSO_XFS_IFORK_PTR 1 +#define XFSSO_XFS_ILOG_FBROOT 1 +#define XFSSO_XFS_ILOG_FEXT 1 +#define XFSSO_XFS_INO_MASK 1 +#define XFSSO_XFS_INO_TO_FSB 1 +#define XFSSO_XFS_INODE_CLEAR_READ_AHEAD 1 +#define XFSSO_XFS_MIN_FREELIST 1 +#define XFSSO_XFS_SB_GOOD_VERSION 1 +#define XFSSO_XFS_SB_VERSION_HASNLINK 1 +#define XFSSO_XLOG_GRANT_ADD_SPACE 1 +#define XFSSO_XLOG_GRANT_SUB_SPACE 1 + +#endif /* __XFS_MACROS_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_mount.c linux-2.4.19-sgi211r3/fs/xfs/xfs_mount.c --- linux-2.4.19/fs/xfs/xfs_mount.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_mount.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,1743 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +STATIC void xfs_mount_reset_sbqflags(xfs_mount_t *); +STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); +STATIC int xfs_uuid_mount(xfs_mount_t *); + +mutex_t xfs_uuidtabmon; /* monitor for uuidtab */ +STATIC int xfs_uuidtab_size; +STATIC uuid_t *xfs_uuidtab; + +STATIC void xfs_uuid_unmount(xfs_mount_t *); + +void xfs_xlatesb(void *, xfs_sb_t *, int, xfs_arch_t, __int64_t); + +static struct { + short offset; + short type; /* 0 = integer + * 1 = binary / string (no translation) + */ +} xfs_sb_info[] = { + { offsetof(xfs_sb_t, sb_magicnum), 0 }, + { offsetof(xfs_sb_t, sb_blocksize), 0 }, + { offsetof(xfs_sb_t, sb_dblocks), 0 }, + { offsetof(xfs_sb_t, sb_rblocks), 0 }, + { offsetof(xfs_sb_t, sb_rextents), 0 }, + { offsetof(xfs_sb_t, sb_uuid), 1 }, + { offsetof(xfs_sb_t, sb_logstart), 0 }, + { offsetof(xfs_sb_t, sb_rootino), 0 }, + { offsetof(xfs_sb_t, sb_rbmino), 0 }, + { offsetof(xfs_sb_t, sb_rsumino), 0 }, + { offsetof(xfs_sb_t, sb_rextsize), 0 }, + { offsetof(xfs_sb_t, sb_agblocks), 0 }, + { offsetof(xfs_sb_t, sb_agcount), 0 }, + { offsetof(xfs_sb_t, sb_rbmblocks), 0 }, + { offsetof(xfs_sb_t, sb_logblocks), 0 }, + { offsetof(xfs_sb_t, sb_versionnum), 0 }, + { offsetof(xfs_sb_t, sb_sectsize), 0 }, + { offsetof(xfs_sb_t, sb_inodesize), 0 }, + { offsetof(xfs_sb_t, sb_inopblock), 0 }, + { offsetof(xfs_sb_t, sb_fname[0]), 1 }, + { offsetof(xfs_sb_t, sb_blocklog), 0 }, + { offsetof(xfs_sb_t, sb_sectlog), 0 }, + { offsetof(xfs_sb_t, sb_inodelog), 0 }, + { offsetof(xfs_sb_t, sb_inopblog), 0 }, + { offsetof(xfs_sb_t, sb_agblklog), 0 }, + { offsetof(xfs_sb_t, sb_rextslog), 0 }, + { offsetof(xfs_sb_t, sb_inprogress), 0 }, + { offsetof(xfs_sb_t, sb_imax_pct), 0 }, + { offsetof(xfs_sb_t, sb_icount), 0 }, + { offsetof(xfs_sb_t, sb_ifree), 0 }, + { offsetof(xfs_sb_t, sb_fdblocks), 0 }, + { offsetof(xfs_sb_t, sb_frextents), 0 }, + { offsetof(xfs_sb_t, sb_uquotino), 0 }, + { offsetof(xfs_sb_t, sb_gquotino), 0 }, + { offsetof(xfs_sb_t, sb_qflags), 0 }, + { offsetof(xfs_sb_t, sb_flags), 0 }, + { offsetof(xfs_sb_t, sb_shared_vn), 0 }, + { offsetof(xfs_sb_t, sb_inoalignmt), 0 }, + { offsetof(xfs_sb_t, sb_unit), 0 }, + { offsetof(xfs_sb_t, sb_width), 0 }, + { offsetof(xfs_sb_t, sb_dirblklog), 0 }, + { offsetof(xfs_sb_t, sb_dummy), 1 }, + { offsetof(xfs_sb_t, sb_logsunit), 0 }, + { sizeof(xfs_sb_t), 0 } +}; + +/* + * Return a pointer to an initialized xfs_mount structure. + */ +xfs_mount_t * +xfs_mount_init(void) +{ + xfs_mount_t *mp; + + mp = kmem_zalloc(sizeof(*mp), KM_SLEEP); + + AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); + spinlock_init(&mp->m_sb_lock, "xfs_sb"); + mutex_init(&mp->m_ilock, MUTEX_DEFAULT, "xfs_ilock"); + initnsema(&mp->m_growlock, 1, "xfs_grow"); + /* + * Initialize the AIL. + */ + xfs_trans_ail_init(mp); + + /* Init freeze sync structures */ + spinlock_init(&mp->m_freeze_lock, "xfs_freeze"); + init_sv(&mp->m_wait_unfreeze, SV_DEFAULT, "xfs_freeze", 0); + atomic_set(&mp->m_active_trans, 0); + + return mp; +} /* xfs_mount_init */ + +/* + * Free up the resources associated with a mount structure. Assume that + * the structure was initially zeroed, so we can tell which fields got + * initialized. + */ +void +xfs_mount_free( + xfs_mount_t *mp, + int remove_bhv) +{ + if (mp->m_ihash) + xfs_ihash_free(mp); + if (mp->m_chash) + xfs_chash_free(mp); + + if (mp->m_perag) { + int agno; + + for (agno = 0; agno < mp->m_maxagi; agno++) + if (mp->m_perag[agno].pagb_list) + kmem_free(mp->m_perag[agno].pagb_list, + sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS); + kmem_free(mp->m_perag, + sizeof(xfs_perag_t) * mp->m_sb.sb_agcount); + } + +#if 0 + /* + * XXXdpd - Doesn't work now for shutdown case. + * Should at least free the memory. + */ + ASSERT(mp->m_ail.ail_back == (xfs_log_item_t*)&(mp->m_ail)); + ASSERT(mp->m_ail.ail_forw == (xfs_log_item_t*)&(mp->m_ail)); +#endif + AIL_LOCK_DESTROY(&mp->m_ail_lock); + spinlock_destroy(&mp->m_sb_lock); + mutex_destroy(&mp->m_ilock); + freesema(&mp->m_growlock); + + if (mp->m_fsname != NULL) { + kmem_free(mp->m_fsname, mp->m_fsname_len); + } + if (mp->m_quotainfo != NULL) { + xfs_qm_unmount_quotadestroy(mp); + } + + if (remove_bhv) { + VFS_REMOVEBHV(XFS_MTOVFS(mp), &mp->m_bhv); + } + spinlock_destroy(&mp->m_freeze_lock); + sv_destroy(&mp->m_wait_unfreeze); + kmem_free(mp, sizeof(xfs_mount_t)); +} + + +/* + * Check the validity of the SB found. + */ +STATIC int +xfs_mount_validate_sb( + xfs_mount_t *mp, + xfs_sb_t *sbp) +{ + /* + * If the log device and data device have the + * same device number, the log is internal. + * Consequently, the sb_logstart should be non-zero. If + * we have a zero sb_logstart in this case, we may be trying to mount + * a volume filesystem in a non-volume manner. + */ + if (sbp->sb_magicnum != XFS_SB_MAGIC) { + cmn_err(CE_WARN, "XFS: bad magic number"); + return XFS_ERROR(EWRONGFS); + } + + if (!XFS_SB_GOOD_VERSION(sbp)) { + cmn_err(CE_WARN, "XFS: bad version"); + return XFS_ERROR(EWRONGFS); + } + + if (sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp) { + cmn_err(CE_WARN, "XFS: filesystem is marked as having an external log; specify logdev on the\nmount command line."); + return XFS_ERROR(EFSCORRUPTED); + } + + if (sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp) { + cmn_err(CE_WARN, "XFS: filesystem is marked as having an internal log; don't specify logdev on\nthe mount command line."); + return XFS_ERROR(EFSCORRUPTED); + } + + /* + * More sanity checking. These were stolen directly from + * xfs_repair. + */ + if (sbp->sb_blocksize <= 0 || + sbp->sb_agcount <= 0 || + sbp->sb_sectsize <= 0 || + sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || + sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || + sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || + (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || + (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || + sbp->sb_imax_pct > 100) { + cmn_err(CE_WARN, "XFS: SB sanity check 1 failed"); + return XFS_ERROR(EFSCORRUPTED); + } + + /* + * sanity check ag count, size fields against data size field + */ + if (sbp->sb_dblocks == 0 || + sbp->sb_dblocks > + (xfs_drfsbno_t)sbp->sb_agcount * sbp->sb_agblocks || + sbp->sb_dblocks < (xfs_drfsbno_t)(sbp->sb_agcount - 1) * + sbp->sb_agblocks + XFS_MIN_AG_BLOCKS) { + cmn_err(CE_WARN, "XFS: SB sanity check 2 failed"); + return XFS_ERROR(EFSCORRUPTED); + } + +#if !XFS_BIG_FILESYSTEMS + if (sbp->sb_dblocks > INT_MAX || sbp->sb_rblocks > INT_MAX) { + cmn_err(CE_WARN, +"XFS: File systems greater than 1TB not supported on this system."); + return XFS_ERROR(E2BIG); + } +#endif + + if (sbp->sb_inprogress) { + cmn_err(CE_WARN, "XFS: file system busy"); + return XFS_ERROR(EFSCORRUPTED); + } + + /* + * Until this is fixed only page-sized or smaller data blocks work. + */ + if (sbp->sb_blocksize > PAGE_SIZE) { + cmn_err(CE_WARN, + "XFS: Trying to mount file system with blocksize %d bytes", + sbp->sb_blocksize); + cmn_err(CE_WARN, + "XFS: Only page-sized (%d bytes) or less blocksizes currently work.", + PAGE_SIZE); + return XFS_ERROR(EWRONGFS); + } + return (0); +} + +void +xfs_initialize_perag(xfs_mount_t *mp, int agcount) +{ + int index, max_metadata; + xfs_perag_t *pag; + xfs_agino_t agino; + xfs_ino_t ino; + xfs_sb_t *sbp = &mp->m_sb; + xfs_ino_t max_inum = XFS_MAXINUMBER_32; + + /* Check to see if the filesystem can overflow 32 bit inodes */ + agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); + ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); + + /* Clear the mount flag if no inode can overflow 32 bits + * on this filesystem. + */ + if (ino <= max_inum) { + mp->m_flags &= ~XFS_MOUNT_32BITINODES; + } + + /* If we can overflow then setup the ag headers accordingly */ + if (mp->m_flags & XFS_MOUNT_32BITINODES) { + /* Calculate how much should be reserved for inodes to + * meet the max inode percentage. + */ + if (mp->m_maxicount) { + __uint64_t icount; + + icount = sbp->sb_dblocks * sbp->sb_imax_pct; + do_div(icount, 100); + icount += sbp->sb_agblocks - 1; + do_div(icount, mp->m_ialloc_blks); + max_metadata = icount; + } else { + max_metadata = agcount; + } + for (index = 0; index < agcount; index++) { + ino = XFS_AGINO_TO_INO(mp, index, agino); + if (ino > max_inum) { + index++; + break; + } + + /* This ag is prefered for inodes */ + pag = &mp->m_perag[index]; + pag->pagi_inodeok = 1; + if (index < max_metadata) + pag->pagf_metadata = 1; + } + } else { + /* Setup default behavior for smaller filesystems */ + for (index = 0; index < agcount; index++) { + pag = &mp->m_perag[index]; + pag->pagi_inodeok = 1; + } + } + mp->m_maxagi = index; +} + +/* + * xfs_xlatesb + * + * data - on disk version of sb + * sb - a superblock + * dir - conversion direction: <0 - convert sb to buf + * >0 - convert buf to sb + * arch - architecture to read/write from/to buf + * fields - which fields to copy (bitmask) + */ +void +xfs_xlatesb( + void *data, + xfs_sb_t *sb, + int dir, + xfs_arch_t arch, + __int64_t fields) +{ + xfs_caddr_t buf_ptr; + xfs_caddr_t mem_ptr; + xfs_sb_field_t f; + int first; + int size; + + ASSERT(dir); + ASSERT(fields); + + if (!fields) + return; + + buf_ptr = (xfs_caddr_t)data; + mem_ptr = (xfs_caddr_t)sb; + + while (fields) { + f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); + first = xfs_sb_info[f].offset; + size = xfs_sb_info[f + 1].offset - first; + + ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1); + + if (arch == ARCH_NOCONVERT || + size == 1 || + xfs_sb_info[f].type == 1) { + if (dir > 0) { + bcopy(buf_ptr + first, mem_ptr + first, size); + } else { + bcopy(mem_ptr + first, buf_ptr + first, size); + } + } else { + switch (size) { + case 2: + INT_XLATE(*(__uint16_t*)(buf_ptr+first), + *(__uint16_t*)(mem_ptr+first), + dir, arch); + break; + case 4: + INT_XLATE(*(__uint32_t*)(buf_ptr+first), + *(__uint32_t*)(mem_ptr+first), + dir, arch); + break; + case 8: + INT_XLATE(*(__uint64_t*)(buf_ptr+first), + *(__uint64_t*)(mem_ptr+first), dir, arch); + break; + default: + ASSERT(0); + } + } + + fields &= ~(1LL << f); + } +} + +/* + * xfs_readsb + * + * Does the initial read of the superblock. + */ +int +xfs_readsb(xfs_mount_t *mp) +{ + xfs_buf_t *bp; + xfs_sb_t *sbp; + int error = 0; + + ASSERT(mp->m_sb_bp == 0); + + /* + * Allocate a (locked) buffer to hold the superblock. + * This will be kept around at all time to optimize + * access to the superblock. + */ + bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR, 1, + PBF_LOCK|PBF_READ|PBF_MAPPED|PBF_MAPPABLE|PBF_FS_MANAGED); + ASSERT(bp != NULL); + ASSERT(XFS_BUF_ISBUSY(bp) && XFS_BUF_VALUSEMA(bp) <= 0); + + /* + * Initialize the mount structure from the superblock. + * But first do some basic consistency checking. + */ + sbp = XFS_BUF_TO_SBP(bp); + xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + if ((error = xfs_mount_validate_sb(mp, &(mp->m_sb)))) { + cmn_err(CE_WARN, "XFS: SB validate failed"); + goto err; + } + + mp->m_sb_bp = bp; + xfs_buf_relse(bp); + ASSERT(XFS_BUF_VALUSEMA(bp) > 0); + return 0; + + err: + bp->pb_flags &= ~PBF_FS_MANAGED; + xfs_buf_relse(bp); + return error; +} + + +/* + * xfs_mount_common + * + * Mount initialization code establishing various mount + * fields from the superblock associated with the given + * mount structure + */ +void +xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) +{ + int i; + + mp->m_agfrotor = mp->m_agirotor = 0; + mp->m_maxagi = mp->m_sb.sb_agcount; + mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; + mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; + mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; + mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; + mp->m_litino = sbp->sb_inodesize - + ((uint)sizeof(xfs_dinode_core_t) + (uint)sizeof(xfs_agino_t)); + mp->m_blockmask = sbp->sb_blocksize - 1; + mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; + mp->m_blockwmask = mp->m_blockwsize - 1; + + + if (XFS_SB_VERSION_HASLOGV2(sbp)) { + if (sbp->sb_logsunit <= 1) { + mp->m_lstripemask = 1; + } else { + mp->m_lstripemask = + 1 << xfs_highbit32(sbp->sb_logsunit >> BBSHIFT); + } + } + + /* + * Setup for attributes, in case they get created. + * This value is for inodes getting attributes for the first time, + * the per-inode value is for old attribute values. + */ + ASSERT(sbp->sb_inodesize >= 256 && sbp->sb_inodesize <= 2048); + switch (sbp->sb_inodesize) { + case 256: + mp->m_attroffset = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(2); + break; + case 512: + case 1024: + case 2048: + mp->m_attroffset = XFS_BMDR_SPACE_CALC(12); + break; + default: + ASSERT(0); + } + ASSERT(mp->m_attroffset < XFS_LITINO(mp)); + + for (i = 0; i < 2; i++) { + mp->m_alloc_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + mp->m_alloc_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + } + for (i = 0; i < 2; i++) { + mp->m_bmap_dmxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + mp->m_bmap_dmnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + } + for (i = 0; i < 2; i++) { + mp->m_inobt_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + mp->m_inobt_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + } + + mp->m_bsize = XFS_FSB_TO_BB(mp, 1); + mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK, + sbp->sb_inopblock); + mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; +} + +extern void xfs_refcache_sbdirty(struct super_block*); + +/* + * xfs_mountfs + * + * This function does the following on an initial mount of a file system: + * - reads the superblock from disk and init the mount struct + * - if we're a 32-bit kernel, do a size check on the superblock + * so we don't mount terabyte filesystems + * - init mount struct realtime fields + * - allocate inode hash table for fs + * - init directory manager + * - perform recovery and init the log manager + */ +int +xfs_mountfs( + vfs_t *vfsp, + xfs_mount_t *mp, + dev_t dev, + int mfsi_flags) +{ + xfs_buf_t *bp; + xfs_sb_t *sbp = &(mp->m_sb); + int error = 0; + xfs_inode_t *rip; + vnode_t *rvp = 0; + int readio_log; + int writeio_log; + vmap_t vmap; + xfs_daddr_t d; + extern xfs_ioops_t xfs_iocore_xfs; /* from xfs_iocore.c */ + __uint64_t ret64; + uint quotaflags, quotaondisk, rootqcheck, needquotacheck; + uint uquotaondisk = 0, gquotaondisk = 0; + boolean_t needquotamount; + __int64_t update_flags; + int agno, noio; + int uuid_mounted = 0; + + noio = dev == 0 && mp->m_sb_bp != NULL; + if (mp->m_sb_bp == NULL) { + if ((error = xfs_readsb(mp))) { + return (error); + } + } + xfs_mount_common(mp, sbp); + + /* + * Check if sb_agblocks is aligned at stripe boundary + * If sb_agblocks is NOT aligned turn off m_dalign since + * allocator alignment is within an ag, therefore ag has + * to be aligned at stripe boundary. + */ + update_flags = 0LL; + if (mp->m_dalign && !(mfsi_flags & XFS_MFSI_SECOND)) { + /* + * If stripe unit and stripe width are not multiples + * of the fs blocksize turn off alignment. + */ + if ((BBTOB(mp->m_dalign) & mp->m_blockmask) || + (BBTOB(mp->m_swidth) & mp->m_blockmask)) { + if (mp->m_flags & XFS_MOUNT_RETERR) { + cmn_err(CE_WARN, "XFS: alignment check 1 failed"); + error = XFS_ERROR(EINVAL); + goto error1; + } + mp->m_dalign = mp->m_swidth = 0; + } else { + /* + * Convert the stripe unit and width to FSBs. + */ + mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign); + if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) { + if (mp->m_flags & XFS_MOUNT_RETERR) { + error = XFS_ERROR(EINVAL); + goto error1; + } + mp->m_dalign = 0; + mp->m_swidth = 0; + } else if (mp->m_dalign) { + mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth); + } else { + if (mp->m_flags & XFS_MOUNT_RETERR) { + cmn_err(CE_WARN, "XFS: alignment check 3 failed"); + error = XFS_ERROR(EINVAL); + goto error1; + } + mp->m_swidth = 0; + } + } + + /* + * Update superblock with new values + * and log changes + */ + if (XFS_SB_VERSION_HASDALIGN(sbp)) { + if (sbp->sb_unit != mp->m_dalign) { + sbp->sb_unit = mp->m_dalign; + update_flags |= XFS_SB_UNIT; + } + if (sbp->sb_width != mp->m_swidth) { + sbp->sb_width = mp->m_swidth; + update_flags |= XFS_SB_WIDTH; + } + } + } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && + XFS_SB_VERSION_HASDALIGN(&mp->m_sb)) { + mp->m_dalign = sbp->sb_unit; + mp->m_swidth = sbp->sb_width; + } + + xfs_alloc_compute_maxlevels(mp); + xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); + xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); + xfs_ialloc_compute_maxlevels(mp); + + if (sbp->sb_imax_pct) { + __uint64_t icount; + + /* Make sure the maximum inode count is a multiple of the + * units we allocate inodes in. + */ + + icount = sbp->sb_dblocks * sbp->sb_imax_pct; + do_div(icount, 100); + do_div(icount, mp->m_ialloc_blks); + mp->m_maxicount = (icount * mp->m_ialloc_blks) << + sbp->sb_inopblog; + } else + mp->m_maxicount = 0; + + /* + * XFS uses the uuid from the superblock as the unique + * identifier for fsid. We can not use the uuid from the volume + * since a single partition filesystem is identical to a single + * partition volume/filesystem. + */ + if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && (mp->m_flags & XFS_MOUNT_NOUUID) == 0) { + if (xfs_uuid_mount(mp)) { + error = XFS_ERROR(EINVAL); + goto error1; + } + uuid_mounted=1; + ret64 = uuid_hash64(&sbp->sb_uuid); + bcopy(&ret64, &vfsp->vfs_fsid, sizeof(ret64)); + } + + /* + * Set the default minimum read and write sizes unless + * already specified in a mount option. + * We use smaller I/O sizes when the file system + * is being used for NFS service (wsync mount option). + */ + if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) { + if (mp->m_flags & XFS_MOUNT_WSYNC) { + readio_log = XFS_WSYNC_READIO_LOG; + writeio_log = XFS_WSYNC_WRITEIO_LOG; + } else { + readio_log = XFS_READIO_LOG_LARGE; + writeio_log = XFS_WRITEIO_LOG_LARGE; + } + } else { + readio_log = mp->m_readio_log; + writeio_log = mp->m_writeio_log; + } + + /* + * Set the number of readahead buffers to use based on + * physical memory size. + */ + if (xfs_physmem <= 4096) /* <= 16MB */ + mp->m_nreadaheads = XFS_RW_NREADAHEAD_16MB; + else if (xfs_physmem <= 8192) /* <= 32MB */ + mp->m_nreadaheads = XFS_RW_NREADAHEAD_32MB; + else + mp->m_nreadaheads = XFS_RW_NREADAHEAD_K32; + if (sbp->sb_blocklog > readio_log) { + mp->m_readio_log = sbp->sb_blocklog; + } else { + mp->m_readio_log = readio_log; + } + mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog); + if (sbp->sb_blocklog > writeio_log) { + mp->m_writeio_log = sbp->sb_blocklog; + } else { + mp->m_writeio_log = writeio_log; + } + mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog); + + /* + * Set the inode cluster size based on the physical memory + * size. This may still be overridden by the file system + * block size if it is larger than the chosen cluster size. + */ + if (xfs_physmem <= btoc(32 * 1024 * 1024)) { /* <= 32 MB */ + mp->m_inode_cluster_size = XFS_INODE_SMALL_CLUSTER_SIZE; + } else { + mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; + } + /* + * Set whether we're using inode alignment. + */ + if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && + mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) + mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; + else + mp->m_inoalign_mask = 0; + /* + * If we are using stripe alignment, check whether + * the stripe unit is a multiple of the inode alignment + */ + if (mp->m_dalign && mp->m_inoalign_mask && + !(mp->m_dalign & mp->m_inoalign_mask)) + mp->m_sinoalign = mp->m_dalign; + else + mp->m_sinoalign = 0; + /* + * Check that the data (and log if separate) are an ok size. + */ + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { + cmn_err(CE_WARN, "XFS: size check 1 failed"); + error = XFS_ERROR(E2BIG); + goto error1; + } + if (!noio) { + error = xfs_read_buf(mp, mp->m_ddev_targp, d - 1, 1, 0, &bp); + if (!error) { + xfs_buf_relse(bp); + } else { + cmn_err(CE_WARN, "XFS: size check 2 failed"); + if (error == ENOSPC) { + error = XFS_ERROR(E2BIG); + } + goto error1; + } + } + + if (!noio && ((mfsi_flags & XFS_MFSI_CLIENT) == 0) && + mp->m_logdev_targp != mp->m_ddev_targp) { + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { + cmn_err(CE_WARN, "XFS: size check 3 failed"); + error = XFS_ERROR(E2BIG); + goto error1; + } + error = xfs_read_buf(mp, mp->m_logdev_targp, d - 1, 1, 0, &bp); + if (!error) { + xfs_buf_relse(bp); + } else { + cmn_err(CE_WARN, "XFS: size check 3 failed"); + if (error == ENOSPC) { + error = XFS_ERROR(E2BIG); + } + goto error1; + } + } + + /* + * Disallow mount attempts with (IRIX) project quota enabled + */ + if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && + (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT)) { + cmn_err(CE_WARN, "XFS: IRIX project quota are enabled"); + error = XFS_ERROR(ENOSYS); + goto error1; + } + + /* + * Initialize realtime fields in the mount structure + */ + if ((error = xfs_rtmount_init(mp))) { + cmn_err(CE_WARN, "XFS: RT mount failed"); + goto error1; + } + + /* + * For client case we are done now + */ + if (mfsi_flags & XFS_MFSI_CLIENT) { + return(0); + } + + /* + * Set up timer list structure for nfs refcache + */ + init_timer(&mp->m_sbdirty_timer); + mp->m_sbdirty_timer.function = (void (*)(unsigned long)) xfs_refcache_sbdirty; + + /* Initialize the I/O function vector with XFS functions */ + mp->m_io_ops = xfs_iocore_xfs; + + /* + * Copies the low order bits of the timestamp and the randomly + * set "sequence" number out of a UUID. + */ + uuid_getnodeuniq(&sbp->sb_uuid, mp->m_fixedfsid); + + /* + * The vfs structure needs to have a file system independent + * way of checking for the invariant file system ID. Since it + * can't look at mount structures it has a pointer to the data + * in the mount structure. + * + * File systems that don't support user level file handles (i.e. + * all of them except for XFS) will leave vfs_altfsid as NULL. + */ + vfsp->vfs_altfsid = (fsid_t *)mp->m_fixedfsid; + mp->m_dmevmask = 0; /* not persistent; set after each mount */ + + /* + * Select the right directory manager. + */ + mp->m_dirops = + XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ? + xfsv2_dirops : + xfsv1_dirops; + + /* + * Initialize directory manager's entries. + */ + XFS_DIR_MOUNT(mp); + + /* + * Initialize the attribute manager's entries. + */ + mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100; + + /* + * Initialize the precomputed transaction reservations values. + */ + xfs_trans_init(mp); + if (noio) { + ASSERT((mfsi_flags & XFS_MFSI_CLIENT) == 0); + return 0; + } + + /* + * Allocate and initialize the inode hash table for this + * file system. + */ + xfs_ihash_init(mp); + xfs_chash_init(mp); + + /* + * Allocate and initialize the per-ag data. + */ + init_rwsem(&mp->m_peraglock); + mp->m_perag = + kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP); + + xfs_initialize_perag(mp, sbp->sb_agcount); + + /* + * log's mount-time initialization. Perform 1st part recovery if needed + */ + if (sbp->sb_logblocks > 0) { /* check for volume case */ + error = xfs_log_mount(mp, mp->m_logdev_targp->pbr_dev, + XFS_FSB_TO_DADDR(mp, sbp->sb_logstart), + XFS_FSB_TO_BB(mp, sbp->sb_logblocks)); + if (error) { + cmn_err(CE_WARN, "XFS: log mount failed"); + goto error2; + } + } else { /* No log has been defined */ + cmn_err(CE_WARN, "XFS: no log defined"); + error = XFS_ERROR(EFSCORRUPTED); + goto error2; + } + + /* + * Get and sanity-check the root inode. + * Save the pointer to it in the mount structure. + */ + error = xfs_iget(mp, NULL, sbp->sb_rootino, XFS_ILOCK_EXCL, &rip, 0); + if (error) { + cmn_err(CE_WARN, "XFS: failed to read root inode"); + goto error3; + } + + ASSERT(rip != NULL); + rvp = XFS_ITOV(rip); + if ((rip->i_d.di_mode & IFMT) != IFDIR) { + cmn_err(CE_WARN, "XFS: corrupted root inode"); + VMAP(rvp, rip, vmap); + prdev("Root inode %llu is not a directory", + mp->m_dev, (unsigned long long)rip->i_ino); + rvp->v_flag |= VPURGE; + xfs_iunlock(rip, XFS_ILOCK_EXCL); + VN_RELE(rvp); + vn_purge(rvp, &vmap); + error = XFS_ERROR(EFSCORRUPTED); + goto error3; + } + mp->m_rootip = rip; /* save it */ + + xfs_iunlock(rip, XFS_ILOCK_EXCL); + + quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && + mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT); + + if (quotaondisk) { + uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT; + gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT; + } + + /* + * If the device itself is read-only, we can't allow + * the user to change the state of quota on the mount - + * this would generate a transaction on the ro device, + * which would lead to an I/O error and shutdown + */ + + if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) || + (!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) || + (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) || + (!gquotaondisk && XFS_IS_GQUOTA_ON(mp))) && + xfs_dev_is_read_only(mp, "changing quota state")) { + cmn_err(CE_WARN, + "XFS: please mount with%s%s%s.", + (!quotaondisk ? "out quota" : ""), + (uquotaondisk ? " usrquota" : ""), + (gquotaondisk ? " grpquota" : "")); + rvp->v_flag |= VPURGE; + VN_RELE(rvp); + vn_remove(rvp); + error = XFS_ERROR(EPERM); + goto error3; + } + + /* + * Initialize realtime inode pointers in the mount structure + */ + if ((error = xfs_rtmount_inodes(mp))) { + /* + * Free up the root inode. + */ + cmn_err(CE_WARN, "XFS: failed to read RT inodes"); + rvp->v_flag |= VPURGE; + VMAP(rvp, rip, vmap); + VN_RELE(rvp); + vn_purge(rvp, &vmap); + goto error3; + } + + /* + * If fs is not mounted readonly, then update the superblock + * unit and width changes. + */ + if (update_flags && !(vfsp->vfs_flag & VFS_RDONLY)) + xfs_mount_log_sbunit(mp, update_flags); + + quotaflags = 0; + needquotamount = B_FALSE; + + /* + * Figure out if we'll need to do a quotacheck. + * The requirements are a little different depending on whether + * this fs is root or not. + */ + rootqcheck = (mp->m_dev == rootdev && quotaondisk && + ((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT && + (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || + (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT && + (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD) == 0))); + needquotacheck = rootqcheck || XFS_QM_NEED_QUOTACHECK(mp); + if (XFS_IS_QUOTA_ON(mp) || quotaondisk) { + /* + * Call mount_quotas at this point only if we won't have to do + * a quotacheck. + */ + if (quotaondisk && !needquotacheck) { + /* + * If the xfs quota code isn't installed, + * we have to reset the quotachk'd bit. + * If an error occured, qm_mount_quotas code + * has already disabled quotas. So, just finish + * mounting, and get on with the boring life + * without disk quotas. + */ + if (xfs_qm_mount_quotas(mp)) + xfs_mount_reset_sbqflags(mp); + } else { + /* + * Clear the quota flags, but remember them. This + * is so that the quota code doesn't get invoked + * before we're ready. This can happen when an + * inode goes inactive and wants to free blocks, + * or via xfs_log_mount_finish. + */ + quotaflags = mp->m_qflags; + mp->m_qflags = 0; + needquotamount = B_TRUE; + } + } + + /* + * Finish recovering the file system. This part needed to be + * delayed until after the root and real-time bitmap inodes + * were consistently read in. + */ + error = xfs_log_mount_finish(mp, mfsi_flags); + if (error) { + cmn_err(CE_WARN, "XFS: log mount finish failed"); + goto error3; + } + + if (needquotamount) { + ASSERT(mp->m_qflags == 0); + mp->m_qflags = quotaflags; + rootqcheck = (mp->m_dev == rootdev && needquotacheck); + if (rootqcheck && (error = xfs_dev_is_read_only(mp, + "quotacheck"))) + goto error2; + if (xfs_qm_mount_quotas(mp)) + xfs_mount_reset_sbqflags(mp); + } + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + if (! (XFS_IS_QUOTA_ON(mp))) + xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on"); + else + xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on"); +#endif + +#ifdef QUOTADEBUG + if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp)) + cmn_err(CE_WARN, "XFS: mount internalqcheck failed"); +#endif + + return (0); + + error3: + xfs_log_unmount_dealloc(mp); + error2: + xfs_ihash_free(mp); + xfs_chash_free(mp); + for (agno = 0; agno < sbp->sb_agcount; agno++) + if (mp->m_perag[agno].pagb_list) + kmem_free(mp->m_perag[agno].pagb_list, + sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS); + kmem_free(mp->m_perag, sbp->sb_agcount * sizeof(xfs_perag_t)); + mp->m_perag = NULL; + /* FALLTHROUGH */ + error1: + if (uuid_mounted) + xfs_uuid_unmount(mp); + xfs_freesb(mp); + return error; +} + +/* + * xfs_unmountfs + * + * This flushes out the inodes,dquots and the superblock, unmounts the + * log and makes sure that incore structures are freed. + */ +int +xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) +{ + int ndquots; +#if defined(DEBUG) || defined(INDUCE_IO_ERROR) + int64_t fsid; +#endif + + xfs_iflush_all(mp, XFS_FLUSH_ALL); + + /* + * Purge the dquot cache. + * None of the dquots should really be busy at this point. + */ + if (mp->m_quotainfo) { + while ((ndquots = xfs_qm_dqpurge_all(mp, + XFS_QMOPT_UQUOTA| + XFS_QMOPT_GQUOTA| + XFS_QMOPT_UMOUNTING))) { + delay(ndquots * 10); + } + } + + /* + * Flush out the log synchronously so that we know for sure + * that nothing is pinned. This is important because bflush() + * will skip pinned buffers. + */ + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + + xfs_binval(mp->m_ddev_targp); + if (mp->m_rtdev_targp) { + xfs_binval(mp->m_rtdev_targp); + } + + xfs_unmountfs_writesb(mp); + + xfs_log_unmount(mp); /* Done! No more fs ops. */ + + xfs_freesb(mp); + + /* + * All inodes from this mount point should be freed. + */ + ASSERT(mp->m_inodes == NULL); + + /* + * We may have bufs that are in the process of getting written still. + * We must wait for the I/O completion of those. The sync flag here + * does a two pass iteration thru the bufcache. + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + xfs_incore_relse(mp->m_ddev_targp, 0, 1); /* synchronous */ + } + + xfs_unmountfs_close(mp, cr); + if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) + xfs_uuid_unmount(mp); + +#if defined(DEBUG) || defined(INDUCE_IO_ERROR) + /* + * clear all error tags on this filesystem + */ + bcopy(&(XFS_MTOVFS(mp)->vfs_fsid), &fsid, sizeof(int64_t)); + (void) xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0); +#endif + + xfs_mount_free(mp, 1); + return 0; +} + +void +xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr) +{ + int have_logdev = (mp->m_logdev_targp != mp->m_ddev_targp); + + if (mp->m_ddev_targp) { + pagebuf_lock_disable(mp->m_ddev_targp, 0); + mp->m_ddev_targp = NULL; + } + if (mp->m_rtdev_targp) { + pagebuf_lock_disable(mp->m_rtdev_targp, 1); + mp->m_rtdev_targp = NULL; + } + if (mp->m_logdev_targp && have_logdev) { + pagebuf_lock_disable(mp->m_logdev_targp, 1); + mp->m_logdev_targp = NULL; + } +} + +int +xfs_unmountfs_writesb(xfs_mount_t *mp) +{ + xfs_buf_t *sbp; + xfs_sb_t *sb; + int error = 0; + + /* + * skip superblock write if fs is read-only, or + * if we are doing a forced umount. + */ + sbp = xfs_getsb(mp, 0); + if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY || + XFS_FORCED_SHUTDOWN(mp))) { + /* + * mark shared-readonly if desired + */ + sb = XFS_BUF_TO_SBP(sbp); + if (mp->m_mk_sharedro) { + if (!(sb->sb_flags & XFS_SBF_READONLY)) + sb->sb_flags |= XFS_SBF_READONLY; + if (!XFS_SB_VERSION_HASSHARED(sb)) + XFS_SB_VERSION_ADDSHARED(sb); + xfs_fs_cmn_err(CE_NOTE, mp, + "Unmounting, marking shared read-only"); + } + XFS_BUF_UNDONE(sbp); + XFS_BUF_UNREAD(sbp); + XFS_BUF_UNDELAYWRITE(sbp); + XFS_BUF_WRITE(sbp); + XFS_BUF_UNASYNC(sbp); + ASSERT(XFS_BUF_TARGET_DEV(sbp) == mp->m_dev); + xfsbdstrat(mp, sbp); + /* Nevermind errors we might get here. */ + error = xfs_iowait(sbp); + if (error) + xfs_ioerror_alert("xfs_unmountfs_writesb", + mp, sbp, XFS_BUF_ADDR(sbp)); + if (error && mp->m_mk_sharedro) + xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting. Filesystem may not be marked shared readonly"); + } + xfs_buf_relse(sbp); + return (error); +} + +/* + * xfs_mod_sb() can be used to copy arbitrary changes to the + * in-core superblock into the superblock buffer to be logged. + * It does not provide the higher level of locking that is + * needed to protect the in-core superblock from concurrent + * access. + */ +void +xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) +{ + xfs_buf_t *bp; + int first; + int last; + xfs_mount_t *mp; + xfs_sb_t *sbp; + xfs_sb_field_t f; + + ASSERT(fields); + if (!fields) + return; + mp = tp->t_mountp; + bp = xfs_trans_getsb(tp, mp, 0); + sbp = XFS_BUF_TO_SBP(bp); + first = sizeof(xfs_sb_t); + last = 0; + + /* translate/copy */ + + xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, ARCH_CONVERT, fields); + + /* find modified range */ + + f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); + ASSERT((1LL << f) & XFS_SB_MOD_BITS); + first = xfs_sb_info[f].offset; + + f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields); + ASSERT((1LL << f) & XFS_SB_MOD_BITS); + last = xfs_sb_info[f + 1].offset - 1; + + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply + * a delta to a specified field in the in-core superblock. Simply + * switch on the field indicated and apply the delta to that field. + * Fields are not allowed to dip below zero, so if the delta would + * do this do not apply it and return EINVAL. + * + * The SB_LOCK must be held when this routine is called. + */ +STATIC int +xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, + int delta, int rsvd) +{ + int scounter; /* short counter for 32 bit fields */ + long long lcounter; /* long counter for 64 bit fields */ + long long res_used, rem; + + /* + * With the in-core superblock spin lock held, switch + * on the indicated field. Apply the delta to the + * proper field. If the fields value would dip below + * 0, then do not apply the delta and return EINVAL. + */ + switch (field) { + case XFS_SBS_ICOUNT: + lcounter = (long long)mp->m_sb.sb_icount; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_icount = lcounter; + return (0); + case XFS_SBS_IFREE: + lcounter = (long long)mp->m_sb.sb_ifree; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_ifree = lcounter; + return (0); + case XFS_SBS_FDBLOCKS: + + lcounter = (long long)mp->m_sb.sb_fdblocks; + res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); + + if (delta > 0) { /* Putting blocks back */ + if (res_used > delta) { + mp->m_resblks_avail += delta; + } else { + rem = delta - res_used; + mp->m_resblks_avail = mp->m_resblks; + lcounter += rem; + } + } else { /* Taking blocks away */ + + lcounter += delta; + + /* + * If were out of blocks, use any available reserved blocks if + * were allowed to. + */ + + if (lcounter < 0) { + if (rsvd) { + lcounter = (long long)mp->m_resblks_avail + delta; + if (lcounter < 0) { + return (XFS_ERROR(ENOSPC)); + } + mp->m_resblks_avail = lcounter; + return (0); + } else { /* not reserved */ + return (XFS_ERROR(ENOSPC)); + } + } + } + + mp->m_sb.sb_fdblocks = lcounter; + return (0); + case XFS_SBS_FREXTENTS: + lcounter = (long long)mp->m_sb.sb_frextents; + lcounter += delta; + if (lcounter < 0) { + return (XFS_ERROR(ENOSPC)); + } + mp->m_sb.sb_frextents = lcounter; + return (0); + case XFS_SBS_DBLOCKS: + lcounter = (long long)mp->m_sb.sb_dblocks; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_dblocks = lcounter; + return (0); + case XFS_SBS_AGCOUNT: + scounter = mp->m_sb.sb_agcount; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_agcount = scounter; + return (0); + case XFS_SBS_IMAX_PCT: + scounter = mp->m_sb.sb_imax_pct; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_imax_pct = scounter; + return (0); + case XFS_SBS_REXTSIZE: + scounter = mp->m_sb.sb_rextsize; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rextsize = scounter; + return (0); + case XFS_SBS_RBMBLOCKS: + scounter = mp->m_sb.sb_rbmblocks; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rbmblocks = scounter; + return (0); + case XFS_SBS_RBLOCKS: + lcounter = (long long)mp->m_sb.sb_rblocks; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rblocks = lcounter; + return (0); + case XFS_SBS_REXTENTS: + lcounter = (long long)mp->m_sb.sb_rextents; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rextents = lcounter; + return (0); + case XFS_SBS_REXTSLOG: + scounter = mp->m_sb.sb_rextslog; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rextslog = scounter; + return (0); + default: + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } +} + +/* + * xfs_mod_incore_sb() is used to change a field in the in-core + * superblock structure by the specified delta. This modification + * is protected by the SB_LOCK. Just use the xfs_mod_incore_sb_unlocked() + * routine to do the work. + */ +int +xfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd) +{ + unsigned long s; + int status; + + s = XFS_SB_LOCK(mp); + status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); + XFS_SB_UNLOCK(mp, s); + return (status); +} + +/* + * xfs_mod_incore_sb_batch() is used to change more than one field + * in the in-core superblock structure at a time. This modification + * is protected by a lock internal to this module. The fields and + * changes to those fields are specified in the array of xfs_mod_sb + * structures passed in. + * + * Either all of the specified deltas will be applied or none of + * them will. If any modified field dips below 0, then all modifications + * will be backed out and EINVAL will be returned. + */ +int +xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) +{ + unsigned long s; + int status=0; + xfs_mod_sb_t *msbp; + + /* + * Loop through the array of mod structures and apply each + * individually. If any fail, then back out all those + * which have already been applied. Do all of this within + * the scope of the SB_LOCK so that all of the changes will + * be atomic. + */ + s = XFS_SB_LOCK(mp); + msbp = &msb[0]; + for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) { + /* + * Apply the delta at index n. If it fails, break + * from the loop so we'll fall into the undo loop + * below. + */ + status = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field, + msbp->msb_delta, rsvd); + if (status != 0) { + break; + } + } + + /* + * If we didn't complete the loop above, then back out + * any changes made to the superblock. If you add code + * between the loop above and here, make sure that you + * preserve the value of status. Loop back until + * we step below the beginning of the array. Make sure + * we don't touch anything back there. + */ + if (status != 0) { + msbp--; + while (msbp >= msb) { + status = xfs_mod_incore_sb_unlocked(mp, + msbp->msb_field, -(msbp->msb_delta), rsvd); + ASSERT(status == 0); + msbp--; + } + } + XFS_SB_UNLOCK(mp, s); + return (status); +} + +/* + * xfs_getsb() is called to obtain the buffer for the superblock. + * The buffer is returned locked and read in from disk. + * The buffer should be released with a call to xfs_brelse(). + * + * If the flags parameter is BUF_TRYLOCK, then we'll only return + * the superblock buffer if it can be locked without sleeping. + * If it can't then we'll return NULL. + */ +xfs_buf_t * +xfs_getsb(xfs_mount_t *mp, + int flags) +{ + xfs_buf_t *bp; + ASSERT(mp->m_sb_bp != NULL); + bp = mp->m_sb_bp; + if (flags & XFS_BUF_TRYLOCK) { + if (!XFS_BUF_CPSEMA(bp)) { + return NULL; + } + } else { + XFS_BUF_PSEMA(bp, PRIBIO); + } + XFS_BUF_HOLD(bp); + ASSERT(XFS_BUF_ISDONE(bp)); + return (bp); +} + +/* + * Used to free the superblock along various error paths. + */ +void +xfs_freesb( + xfs_mount_t *mp) +{ + xfs_buf_t *bp; + + /* + * Use xfs_getsb() so that the buffer will be locked + * when we call nfreerbuf(). + */ + bp = xfs_getsb(mp, 0); + bp->pb_flags &= ~PBF_FS_MANAGED; + xfs_buf_relse(bp); + mp->m_sb_bp = NULL; +} + +/* + * See if the uuid is unique among mounted xfs filesystems. + * Mount fails if UUID is nil or a FS with the same UUID is already + * mounted + */ +STATIC int +xfs_uuid_mount(xfs_mount_t *mp) +{ + int hole; + int i; + + if (uuid_is_nil(&mp->m_sb.sb_uuid)) { + cmn_err(CE_WARN, "XFS: Filesystem %s has nil UUID - can't mount", + mp->m_fsname); + return -1; + } + + mutex_lock(&xfs_uuidtabmon, PVFS); + for (i = 0, hole = -1; i < xfs_uuidtab_size; i++) { + if (uuid_is_nil(&xfs_uuidtab[i])) { + hole = i; + continue; + } + if (uuid_equal(&mp->m_sb.sb_uuid, &xfs_uuidtab[i])) { + cmn_err(CE_WARN, "XFS: Filesystem %s has duplicate UUID - can't mount", + mp->m_fsname); + mutex_unlock(&xfs_uuidtabmon); + return -1; + } + } + if (hole < 0) { + xfs_uuidtab = kmem_realloc(xfs_uuidtab, + (xfs_uuidtab_size + 1) * sizeof(*xfs_uuidtab), + xfs_uuidtab_size * sizeof(*xfs_uuidtab), + KM_SLEEP); + hole = xfs_uuidtab_size++; + } + xfs_uuidtab[hole] = mp->m_sb.sb_uuid; + mutex_unlock(&xfs_uuidtabmon); + + return 0; +} + +/* + * Remove filesystem from the uuid table. + */ +STATIC void +xfs_uuid_unmount(xfs_mount_t *mp) +{ + int i; + + mutex_lock(&xfs_uuidtabmon, PVFS); + for (i = 0; i < xfs_uuidtab_size; i++) { + if (uuid_is_nil(&xfs_uuidtab[i])) + continue; + if (!uuid_equal(&mp->m_sb.sb_uuid, &xfs_uuidtab[i])) + continue; + uuid_create_nil(&xfs_uuidtab[i]); + break; + } + ASSERT(i < xfs_uuidtab_size); + mutex_unlock(&xfs_uuidtabmon); +} + +/* + * When xfsquotas isn't installed and the superblock had quotas, we need to + * clear the quotaflags from superblock. + */ +STATIC void +xfs_mount_reset_sbqflags( + xfs_mount_t *mp) +{ + xfs_trans_t *tp; + unsigned long s; + + mp->m_qflags = 0; + /* + * It is OK to look at sb_qflags here in mount path, + * without SB_LOCK. + */ + if (mp->m_sb.sb_qflags == 0) + return; + s = XFS_SB_LOCK(mp); + mp->m_sb.sb_qflags = 0; + XFS_SB_UNLOCK(mp, s); + + /* + * if the fs is readonly, let the incore superblock run + * with quotas off but don't flush the update out to disk + */ + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + return; +#ifdef QUOTADEBUG + xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes"); +#endif + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE); + if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, + XFS_DEFAULT_LOG_COUNT)) { + xfs_trans_cancel(tp, 0); + return; + } + xfs_mod_sb(tp, XFS_SB_QFLAGS); + (void)xfs_trans_commit(tp, 0, NULL); +} + +/* + * Used to log changes to the superblock unit and width fields which could + * be altered by the mount options. Only the first superblock is updated. + */ +STATIC void +xfs_mount_log_sbunit( + xfs_mount_t *mp, + __int64_t fields) +{ + xfs_trans_t *tp; + + ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID)); + + tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); + if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, + XFS_DEFAULT_LOG_COUNT)) { + xfs_trans_cancel(tp, 0); + return; + } + xfs_mod_sb(tp, fields); + (void)xfs_trans_commit(tp, 0, NULL); +} + +/* Functions to lock access out of the filesystem for forced + * shutdown or snapshot. + */ + +void +xfs_start_freeze( + xfs_mount_t *mp, + int level) +{ + unsigned long s = mutex_spinlock(&mp->m_freeze_lock); + + mp->m_frozen = level; + mutex_spinunlock(&mp->m_freeze_lock, s); + + if (level == XFS_FREEZE_TRANS) { + while (atomic_read(&mp->m_active_trans) > 0) + delay(100); + } +} + +void +xfs_finish_freeze( + xfs_mount_t *mp) +{ + unsigned long s = mutex_spinlock(&mp->m_freeze_lock); + + if (mp->m_frozen) { + mp->m_frozen = 0; + sv_broadcast(&mp->m_wait_unfreeze); + } + + mutex_spinunlock(&mp->m_freeze_lock, s); +} + +void +xfs_check_frozen( + xfs_mount_t *mp, + bhv_desc_t *bdp, + int level) +{ + SPLDECL(s); + + if (mp->m_frozen) { + s = mutex_spinlock(&mp->m_freeze_lock); + + if (mp->m_frozen < level) { + mutex_spinunlock(&mp->m_freeze_lock, s); + } else { + sv_wait(&mp->m_wait_unfreeze, 0, &mp->m_freeze_lock, s); + } + } + + if (level == XFS_FREEZE_TRANS) + atomic_inc(&mp->m_active_trans); +} diff -Nur linux-2.4.19/fs/xfs/xfs_mount.h linux-2.4.19-sgi211r3/fs/xfs/xfs_mount.h --- linux-2.4.19/fs/xfs/xfs_mount.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_mount.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_MOUNT_H__ +#define __XFS_MOUNT_H__ + + +typedef struct xfs_trans_reservations { + uint tr_write; /* extent alloc trans */ + uint tr_itruncate; /* truncate trans */ + uint tr_rename; /* rename trans */ + uint tr_link; /* link trans */ + uint tr_remove; /* unlink trans */ + uint tr_symlink; /* symlink trans */ + uint tr_create; /* create trans */ + uint tr_mkdir; /* mkdir trans */ + uint tr_ifree; /* inode free trans */ + uint tr_ichange; /* inode update trans */ + uint tr_growdata; /* fs data section grow trans */ + uint tr_swrite; /* sync write inode trans */ + uint tr_addafork; /* cvt inode to attributed trans */ + uint tr_writeid; /* write setuid/setgid file */ + uint tr_attrinval; /* attr fork buffer invalidation */ + uint tr_attrset; /* set/create an attribute */ + uint tr_attrrm; /* remove an attribute */ + uint tr_clearagi; /* clear bad agi unlinked ino bucket */ + uint tr_growrtalloc; /* grow realtime allocations */ + uint tr_growrtzero; /* grow realtime zeroing */ + uint tr_growrtfree; /* grow realtime freeing */ +} xfs_trans_reservations_t; + + +#ifndef __KERNEL__ +/* + * Moved here from xfs_ag.h to avoid reordering header files + */ +#define XFS_DADDR_TO_AGNO(mp,d) \ + ((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks)) +#define XFS_DADDR_TO_AGBNO(mp,d) \ + ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks)) +#else +struct cred; +struct vfs; +struct vnode; +struct xfs_mount_args; +struct xfs_ihash; +struct xfs_chash; +struct xfs_inode; +struct xfs_perag; +struct xfs_quotainfo; +struct xfs_iocore; +struct xfs_dio; +struct xfs_bmbt_irec; +struct xfs_bmap_free; + +#define SPLDECL(s) unsigned long s +#define AIL_LOCK_T lock_t +#define AIL_LOCKINIT(x,y) spinlock_init(x,y) +#define AIL_LOCK_DESTROY(x) spinlock_destroy(x) +#define AIL_LOCK(mp,s) s=mutex_spinlock(&(mp)->m_ail_lock) +#define AIL_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_ail_lock, s) + + +/* Prototypes and functions for I/O core modularization, a vector + * of functions is used to indirect from xfs/cxfs independent code + * to the xfs/cxfs dependent code. + * The vector is placed in the mount structure so that we can + * minimize the number of memory indirections involved. + */ + +typedef int (*xfs_dio_write_t)(struct xfs_dio *); +typedef int (*xfs_dio_read_t)(struct xfs_dio *); +typedef int (*xfs_strat_write_t)(struct xfs_iocore *, struct xfs_buf *); +typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, + xfs_fileoff_t, xfs_filblks_t, int, + xfs_fsblock_t *, xfs_extlen_t, + struct xfs_bmbt_irec *, int *, + struct xfs_bmap_free *); +typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *); +typedef int (*xfs_rsync_t)(void *, int, xfs_off_t, xfs_off_t); +typedef uint (*xfs_lck_map_shared_t)(void *); +typedef void (*xfs_lock_t)(void *, uint); +typedef void (*xfs_lock_demote_t)(void *, uint); +typedef int (*xfs_lock_nowait_t)(void *, uint); +typedef void (*xfs_unlk_t)(void *, unsigned int); +typedef void (*xfs_chgtime_t)(void *, int); +typedef xfs_fsize_t (*xfs_size_t)(void *); +typedef xfs_fsize_t (*xfs_setsize_t)(void *, xfs_off_t); +typedef xfs_fsize_t (*xfs_lastbyte_t)(void *); + +typedef struct xfs_ioops { + xfs_bmapi_t xfs_bmapi_func; + xfs_bmap_eof_t xfs_bmap_eof_func; + xfs_lock_t xfs_ilock; + xfs_lock_demote_t xfs_ilock_demote; + xfs_lock_nowait_t xfs_ilock_nowait; + xfs_unlk_t xfs_unlock; + xfs_chgtime_t xfs_chgtime; + xfs_size_t xfs_size_func; + xfs_lastbyte_t xfs_lastbyte; +} xfs_ioops_t; + + +#define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist) \ + (*(mp)->m_io_ops.xfs_bmapi_func) \ + (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist) + +#define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \ + (*(mp)->m_io_ops.xfs_bmap_eof_func) \ + ((io)->io_obj, endoff, whichfork, eof) + +#define XFS_ILOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock)((io)->io_obj, mode) + +#define XFS_IUNLOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode) + +#define XFS_ILOCK_DEMOTE(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock_demote)((io)->io_obj, mode) + +#define XFS_SIZE(mp, io) \ + (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj) + +#define XFS_LASTBYTE(mp, io) \ + (*(mp)->m_io_ops.xfs_lastbyte)((io)->io_obj) + + +typedef struct xfs_mount { + bhv_desc_t m_bhv; /* vfs xfs behavior */ + xfs_tid_t m_tid; /* next unused tid for fs */ + AIL_LOCK_T m_ail_lock; /* fs AIL mutex */ + xfs_ail_entry_t m_ail; /* fs active log item list */ + uint m_ail_gen; /* fs AIL generation count */ + xfs_sb_t m_sb; /* copy of fs superblock */ + lock_t m_sb_lock; /* sb counter mutex */ + struct xfs_buf *m_sb_bp; /* buffer for superblock */ + char *m_fsname; /* filesystem name */ + int m_fsname_len; /* strlen of fs name */ + int m_bsize; /* fs logical block size */ + xfs_agnumber_t m_agfrotor; /* last ag where space found */ + xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ + xfs_agnumber_t m_maxagi; /* highest inode alloc group */ + int m_ihsize; /* size of next field */ + struct xfs_ihash *m_ihash; /* fs private inode hash table*/ + struct xfs_inode *m_inodes; /* active inode list */ + mutex_t m_ilock; /* inode list mutex */ + uint m_ireclaims; /* count of calls to reclaim*/ + uint m_readio_log; /* min read size log bytes */ + uint m_readio_blocks; /* min read size blocks */ + uint m_writeio_log; /* min write size log bytes */ + uint m_writeio_blocks; /* min write size blocks */ + void *m_log; /* log specific stuff */ + int m_logbufs; /* number of log buffers */ + int m_logbsize; /* size of each log buffer */ + uint m_rsumlevels; /* rt summary levels */ + uint m_rsumsize; /* size of rt summary, bytes */ + struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ + struct xfs_inode *m_rsumip; /* pointer to summary inode */ + struct xfs_inode *m_rootip; /* pointer to root directory */ + struct xfs_quotainfo *m_quotainfo; /* disk quota information */ + xfs_buftarg_t *m_ddev_targp; /* saves taking the address */ + xfs_buftarg_t *m_logdev_targp;/* ptr to log device */ + xfs_buftarg_t *m_rtdev_targp; /* ptr to rt device */ +#define m_dev m_ddev_targp->pbr_dev + __uint8_t m_dircook_elog; /* log d-cookie entry bits */ + __uint8_t m_blkbit_log; /* blocklog + NBBY */ + __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ + __uint8_t m_agno_log; /* log #ag's */ + __uint8_t m_agino_log; /* #bits for agino in inum */ + __uint8_t m_nreadaheads; /* #readahead buffers */ + __uint16_t m_inode_cluster_size;/* min inode buf size */ + uint m_blockmask; /* sb_blocksize-1 */ + uint m_blockwsize; /* sb_blocksize in words */ + uint m_blockwmask; /* blockwsize-1 */ + uint m_alloc_mxr[2]; /* XFS_ALLOC_BLOCK_MAXRECS */ + uint m_alloc_mnr[2]; /* XFS_ALLOC_BLOCK_MINRECS */ + uint m_bmap_dmxr[2]; /* XFS_BMAP_BLOCK_DMAXRECS */ + uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */ + uint m_inobt_mxr[2]; /* XFS_INOBT_BLOCK_MAXRECS */ + uint m_inobt_mnr[2]; /* XFS_INOBT_BLOCK_MINRECS */ + uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ + uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ + uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */ + struct xfs_perag *m_perag; /* per-ag accounting info */ + struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ + sema_t m_growlock; /* growfs mutex */ + int m_fixedfsid[2]; /* unchanged for life of FS */ + uint m_dmevmask; /* DMI events for this FS */ + uint m_flags; /* global mount flags */ + uint m_attroffset; /* inode attribute offset */ + int m_da_node_ents; /* how many entries in danode */ + int m_ialloc_inos; /* inodes in inode allocation */ + int m_ialloc_blks; /* blocks in inode allocation */ + int m_litino; /* size of inode union area */ + int m_inoalign_mask;/* mask sb_inoalignmt if used */ + uint m_qflags; /* quota status flags */ + xfs_trans_reservations_t m_reservations;/* precomputed res values */ + __uint64_t m_maxicount; /* maximum inode count */ + __uint64_t m_resblks; /* total reserved blocks */ + __uint64_t m_resblks_avail;/* available reserved blocks */ +#if XFS_BIG_FILESYSTEMS + xfs_ino_t m_inoadd; /* add value for ino64_offset */ +#endif + int m_dalign; /* stripe unit */ + int m_swidth; /* stripe width */ + int m_lstripemask; /* log stripe mask */ + int m_sinoalign; /* stripe unit inode alignmnt */ + int m_attr_magicpct;/* 37% of the blocksize */ + int m_dir_magicpct; /* 37% of the dir blocksize */ + __uint8_t m_mk_sharedro; /* mark shared ro on unmount */ + __uint8_t m_inode_quiesce;/* call quiesce on new inodes. + field governed by m_ilock */ + __uint8_t m_dirversion; /* 1 or 2 */ + xfs_dirops_t m_dirops; /* table of dir funcs */ + int m_dirblksize; /* directory block sz--bytes */ + int m_dirblkfsbs; /* directory block sz--fsbs */ + xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ + xfs_dablk_t m_dirleafblk; /* blockno of dir non-data v2 */ + xfs_dablk_t m_dirfreeblk; /* blockno of dirfreeindex v2 */ + int m_chsize; /* size of next field */ + struct xfs_chash *m_chash; /* fs private inode per-cluster + * hash table */ + struct xfs_ioops m_io_ops; /* vector of I/O ops */ + struct xfs_expinfo *m_expinfo; /* info to export to other + cells. */ + uint64_t m_shadow_pinmask; + /* which bits matter in rpc + log item pin masks */ + uint m_cxfstype; /* mounted shared, etc. */ + lock_t m_freeze_lock; /* Lock for m_frozen */ + uint m_frozen; /* FS frozen for shutdown or + * snapshot */ + sv_t m_wait_unfreeze;/* waiting to unfreeze */ + atomic_t m_active_trans; /* number trans frozen */ + struct timer_list m_sbdirty_timer;/* superblock dirty timer + * for nfs refcache */ +} xfs_mount_t; + +/* + * Flags for m_flags. + */ +#define XFS_MOUNT_WSYNC 0x00000001 /* for nfs - all metadata ops + must be synchronous except + for space allocations */ +#if XFS_BIG_FILESYSTEMS +#define XFS_MOUNT_INO64 0x00000002 +#endif +#define XFS_MOUNT_ROOTQCHECK 0x00000004 + /* 0x00000008 -- currently unused */ +#define XFS_MOUNT_FS_SHUTDOWN 0x00000010 /* atomic stop of all filesystem + operations, typically for + disk errors in metadata */ +#define XFS_MOUNT_NOATIME 0x00000020 /* don't modify inode access + times on reads */ +#define XFS_MOUNT_RETERR 0x00000040 /* return alignment errors to + user */ +#define XFS_MOUNT_NOALIGN 0x00000080 /* turn off stripe alignment + allocations */ + /* 0x00000100 -- currently unused */ +#define XFS_MOUNT_REGISTERED 0x00000200 /* registered with cxfs master + cell logic */ +#define XFS_MOUNT_NORECOVERY 0x00000400 /* no recovery - dirty fs */ +#define XFS_MOUNT_SHARED 0x00000800 /* shared mount */ +#define XFS_MOUNT_DFLT_IOSIZE 0x00001000 /* set default i/o size */ +#define XFS_MOUNT_OSYNCISOSYNC 0x00002000 /* o_sync is REALLY o_sync */ + /* osyncisdsync is now default*/ +#define XFS_MOUNT_NOUUID 0x00004000 /* ignore uuid during mount */ +#define XFS_MOUNT_32BITINODES 0x00008000 /* do not create inodes above + * 32 bits in size */ +#define XFS_MOUNT_NOLOGFLUSH 0x00010000 + +/* + * Flags for m_cxfstype + */ +#define XFS_CXFS_NOT 0x00000001 /* local mount */ +#define XFS_CXFS_SERVER 0x00000002 /* we're the CXFS server */ +#define XFS_CXFS_CLIENT 0x00000004 /* We're a CXFS client */ +#define XFS_CXFS_REC_ENABLED 0x00000008 /* recovery is enabled */ + +#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) + +/* + * Default minimum read and write sizes. + */ +#define XFS_READIO_LOG_LARGE 12 +#define XFS_WRITEIO_LOG_LARGE 12 +/* + * Default allocation size + */ +#define XFS_WRITE_IO_LOG 16 + +/* + * Max and min values for UIO and mount-option defined I/O sizes; + * min value can't be less than a page. Currently unused. + */ +#define XFS_MAX_IO_LOG 16 /* 64K */ +#define XFS_MIN_IO_LOG PAGE_SHIFT + +/* + * Synchronous read and write sizes. This should be + * better for NFSv2 wsync filesystems. + */ +#define XFS_WSYNC_READIO_LOG 15 /* 32K */ +#define XFS_WSYNC_WRITEIO_LOG 14 /* 16K */ + +#define xfs_force_shutdown(m,f) VFS_FORCE_SHUTDOWN(XFS_MTOVFS(m),f) +/* + * Flags sent to xfs_force_shutdown. + */ +#define XFS_METADATA_IO_ERROR 0x1 +#define XFS_LOG_IO_ERROR 0x2 +#define XFS_FORCE_UMOUNT 0x4 +#define XFS_CORRUPT_INCORE 0x8 /* corrupt in-memory data structures */ +#define XFS_SHUTDOWN_REMOTE_REQ 0x10 /* shutdown came from remote cell */ + +/* + * xflags for xfs_syncsub + */ +#define XFS_XSYNC_RELOC 0x01 + +/* + * Flags for xfs_mountfs + */ +#define XFS_MFSI_SECOND 0x01 /* Is a cxfs secondary mount -- skip */ + /* stuff which should only be done */ + /* once. */ +#define XFS_MFSI_CLIENT 0x02 /* Is a client -- skip lots of stuff */ +#define XFS_MFSI_NOUNLINK 0x08 /* Skip unlinked inode processing in */ + /* log recovery */ + +/* + * Macros for getting from mount to vfs and back. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MTOVFS) +struct vfs *xfs_mtovfs(xfs_mount_t *mp); +#define XFS_MTOVFS(mp) xfs_mtovfs(mp) +#else +#define XFS_MTOVFS(mp) (bhvtovfs(&(mp)->m_bhv)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BHVTOM) +xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp); +#define XFS_BHVTOM(bdp) xfs_bhvtom(bdp) +#else +#define XFS_BHVTOM(bdp) ((xfs_mount_t *)BHV_PDATA(bdp)) +#endif + + +/* + * Moved here from xfs_ag.h to avoid reordering header files + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_AGNO) +xfs_agnumber_t xfs_daddr_to_agno(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d) +#else + +static inline xfs_agnumber_t XFS_DADDR_TO_AGNO(xfs_mount_t *mp, xfs_daddr_t d) +{ + d = XFS_BB_TO_FSBT(mp, d); + do_div(d, mp->m_sb.sb_agblocks); + return (xfs_agnumber_t) d; +} + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_AGBNO) +xfs_agblock_t xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_AGBNO(mp,d) xfs_daddr_to_agbno(mp,d) +#else + +static inline xfs_agblock_t XFS_DADDR_TO_AGBNO(xfs_mount_t *mp, xfs_daddr_t d) +{ + d = XFS_BB_TO_FSBT(mp, d); + return (xfs_agblock_t) do_div(d, mp->m_sb.sb_agblocks); +} + +#endif + +/* + * This structure is for use by the xfs_mod_incore_sb_batch() routine. + */ +typedef struct xfs_mod_sb { + xfs_sb_field_t msb_field; /* Field to modify, see below */ + int msb_delta; /* change to make to the specified field */ +} xfs_mod_sb_t; + +#define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock), PINOD) +#define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock)) +#define XFS_SB_LOCK(mp) mutex_spinlock(&(mp)->m_sb_lock) +#define XFS_SB_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_sb_lock,(s)) + +void xfs_mod_sb(xfs_trans_t *, __int64_t); +xfs_mount_t *xfs_mount_init(void); +void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); +int xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int); + +int xfs_unmountfs(xfs_mount_t *, struct cred *); +void xfs_unmountfs_close(xfs_mount_t *, struct cred *); +int xfs_unmountfs_writesb(xfs_mount_t *); +int xfs_unmount_flush(xfs_mount_t *, int); +int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int); +int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, uint, int); +int xfs_readsb(xfs_mount_t *mp); +struct xfs_buf *xfs_getsb(xfs_mount_t *, int); +void xfs_freesb(xfs_mount_t *); +void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int); +int xfs_syncsub(xfs_mount_t *, int, int, int *); +void xfs_initialize_perag(xfs_mount_t *, int); +void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t); + +/* + * Flags for freeze operations. + */ +#define XFS_FREEZE_WRITE 1 +#define XFS_FREEZE_TRANS 2 + +void xfs_start_freeze(xfs_mount_t *, int); +void xfs_finish_freeze(xfs_mount_t *); +void xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int); + +extern struct vfsops xfs_vfsops; + +#endif /* __KERNEL__ */ + +#endif /* __XFS_MOUNT_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_qm.c linux-2.4.19-sgi211r3/fs/xfs/xfs_qm.c --- linux-2.4.19/fs/xfs/xfs_qm.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_qm.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,2893 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +kmem_zone_t *qm_dqzone; +kmem_zone_t *qm_dqtrxzone; + +STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); +STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); +STATIC int xfs_qm_quotacheck(xfs_mount_t *); + +STATIC int xfs_qm_init_quotainos(xfs_mount_t *); +STATIC void xfs_qm_shake(void); + +#ifdef DEBUG +extern mutex_t qcheck_lock; +#endif + +#ifdef QUOTADEBUG +#define XQM_LIST_PRINT(l, NXT, title) \ +{ \ + xfs_dquot_t *dqp; int i = 0;\ + printk("%s (#%d)\n", title, (int) (l)->qh_nelems); \ + for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \ + printk("\t%d.\t\"%d (%s)\"\t bcnt = %d, icnt = %d refs = %d\n", \ + ++i, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \ + DQFLAGTO_TYPESTR(dqp), \ + (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \ + (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \ + (int) dqp->q_nrefs); } \ +} +#endif + +/* + * Initialize the XQM structure. + * Note that there is not one quota manager per file system. + */ +struct xfs_qm * +xfs_qm_init(void) +{ + xfs_qm_t *xqm; + int hsize, i; + + xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP); + ASSERT(xqm); + + /* + * Initialize the dquot hash tables. + */ + hsize = (DQUOT_HASH_HEURISTIC < XFS_QM_NCSIZE_THRESHOLD) ? + XFS_QM_HASHSIZE_LOW : XFS_QM_HASHSIZE_HIGH; + xqm->qm_dqhashmask = hsize - 1; + + /* + * XXXsup We could keep reference counts on usr and grp quotas + * inside XQM separately, and avoid having two hashtables even + * when only one 'type' is active in the system. + */ + xqm->qm_usr_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize * + sizeof(xfs_dqhash_t), + KM_SLEEP); + xqm->qm_grp_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize * + sizeof(xfs_dqhash_t), + KM_SLEEP); + ASSERT(xqm->qm_usr_dqhtable != NULL); + ASSERT(xqm->qm_grp_dqhtable != NULL); + + for (i = 0; i < hsize; i++) { + xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i); + xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i); + } + + /* + * Freelist of all dquots of all file systems + */ + xfs_qm_freelist_init(&(xqm->qm_dqfreelist)); + + /* + * dquot zone. we register our own low-memory callback. + */ + if (!qm_dqzone) { + xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t), + "xfs_dquots"); + qm_dqzone = xqm->qm_dqzone; + } else + xqm->qm_dqzone = qm_dqzone; + + kmem_shake_register(xfs_qm_shake); + + /* + * The t_dqinfo portion of transactions. + */ + if (!qm_dqtrxzone) { + xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t), + "xfs_dqtrx"); + qm_dqtrxzone = xqm->qm_dqtrxzone; + } else + xqm->qm_dqtrxzone = qm_dqtrxzone; + + atomic_set(&xqm->qm_totaldquots, 0); + xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO; + xqm->qm_nrefs = 0; +#ifdef DEBUG + mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk"); +#endif + return (xqm); +} + +/* + * Destroy the global quota manager when its reference count goes to zero. + */ +void +xfs_qm_destroy( + struct xfs_qm *xqm) +{ + int hsize, i; + + ASSERT(xqm != NULL); + ASSERT(xqm->qm_nrefs == 0); + kmem_shake_deregister(xfs_qm_shake); + hsize = xqm->qm_dqhashmask + 1; + for (i = 0; i < hsize; i++) { + xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); + xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); + } + kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t)); + kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t)); + xqm->qm_usr_dqhtable = NULL; + xqm->qm_grp_dqhtable = NULL; + xqm->qm_dqhashmask = 0; + xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist)); +#ifdef DEBUG + mutex_destroy(&qcheck_lock); +#endif + kmem_free(xqm, sizeof(xfs_qm_t)); +} + +/* + * Called at mount time to let XQM know that another file system is + * starting quotas. This isn't crucial information as the individual mount + * structures are pretty independent, but it helps the XQM keep a + * global view of what's going on. + */ +/* ARGSUSED */ +STATIC int +xfs_qm_hold_quotafs_ref( + struct xfs_mount *mp) +{ + /* + * Need to lock the xfs_Gqm structure for things like this. For example, + * the structure could disappear between the entry to this routine and + * a HOLD operation if not locked. + */ + XFS_QM_LOCK(xfs_Gqm); + + if (xfs_Gqm == NULL) { + if ((xfs_Gqm = xfs_qm_init()) == NULL) { + return (XFS_ERROR(EINVAL)); + } + } + /* + * We can keep a list of all filesystems with quotas mounted for + * debugging and statistical purposes, but ... + * Just take a reference and get out. + */ + XFS_QM_HOLD(xfs_Gqm); + XFS_QM_UNLOCK(xfs_Gqm); + + return 0; +} + + +/* + * Release the reference that a filesystem took at mount time, + * so that we know when we need to destroy the entire quota manager. + */ +/* ARGSUSED */ +STATIC void +xfs_qm_rele_quotafs_ref( + struct xfs_mount *mp) +{ + xfs_dquot_t *dqp, *nextdqp; + + ASSERT(xfs_Gqm); + ASSERT(xfs_Gqm->qm_nrefs > 0); + + /* + * Go thru the freelist and destroy all inactive dquots. + */ + xfs_qm_freelist_lock(xfs_Gqm); + + for (dqp = xfs_Gqm->qm_dqfreelist.qh_next; + dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) { + xfs_dqlock(dqp); + nextdqp = dqp->dq_flnext; + if (dqp->dq_flags & XFS_DQ_INACTIVE) { + ASSERT(dqp->q_mount == NULL); + ASSERT(! XFS_DQ_IS_DIRTY(dqp)); + ASSERT(dqp->HL_PREVP == NULL); + ASSERT(dqp->MPL_PREVP == NULL); + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + xfs_qm_dqdestroy(dqp); + } else { + xfs_dqunlock(dqp); + } + dqp = nextdqp; + } + xfs_qm_freelist_unlock(xfs_Gqm); + + /* + * Destroy the entire XQM. If somebody mounts with quotaon, this'll + * be restarted. + */ + XFS_QM_LOCK(xfs_Gqm); + XFS_QM_RELE(xfs_Gqm); + if (xfs_Gqm->qm_nrefs == 0) { + xfs_qm_destroy(xfs_Gqm); + xfs_Gqm = NULL; + } + XFS_QM_UNLOCK(xfs_Gqm); +} + +/* + * This is called at mount time from xfs_mountfs to initialize the quotainfo + * structure and start the global quotamanager (xfs_Gqm) if it hasn't done + * so already. Note that the superblock has not been read in yet. + */ +void +xfs_qm_mount_quotainit( + xfs_mount_t *mp, + uint flags) +{ + /* + * User or group quotas has to be on. + */ + ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA)); + + /* + * Initialize the flags in the mount structure. From this point + * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc. + * Note that we enforce nothing if accounting is off. + * ie. XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF. + * It isn't necessary to take the quotaoff lock to do this; this is + * called from mount. + */ + if (flags & XFSMNT_UQUOTA) { + mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); + if (flags & XFSMNT_UQUOTAENF) + mp->m_qflags |= XFS_UQUOTA_ENFD; + } + if (flags & XFSMNT_GQUOTA) { + mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); + if (flags & XFSMNT_GQUOTAENF) + mp->m_qflags |= XFS_GQUOTA_ENFD; + } +} + +/* + * Just destroy the quotainfo structure. + */ +void +xfs_qm_unmount_quotadestroy( + xfs_mount_t *mp) +{ + xfs_qm_destroy_quotainfo(mp); +} + + +/* + * This is called from xfs_mountfs to start quotas and initialize all + * necessary data structures like quotainfo, and in the rootfs's case + * xfs_Gqm. This is also responsible for running a quotacheck as necessary. + * We are guaranteed that the superblock is consistently read in at this + * point. + */ +int +xfs_qm_mount_quotas( + xfs_mount_t *mp) +{ + unsigned long s; + int error; + uint sbf; + + error = 0; + /* + * If a non-root file system had quotas running earlier, but decided + * to mount without -o quota/pquota options, revoke the quotachecked + * license, and bail out. + */ + if (! XFS_IS_QUOTA_ON(mp) && + (mp->m_dev != rootdev) && + (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) { + mp->m_qflags = 0; + goto write_changes; + } + + /* + * If quotas on realtime volumes is not supported, we disable + * quotas immediately. + */ + if (mp->m_sb.sb_rextents) { + cmn_err(CE_NOTE, + "Cannot turn on quotas for realtime filesystem %s", + mp->m_fsname); + mp->m_qflags = 0; + goto write_changes; + } + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, "Attempting to turn on disk quotas."); +#endif + /* + * If this is the root file system, mark flags in mount struct first. + * We couldn't do this earlier because we didn't have the superblock + * read in. + */ + if (mp->m_dev == rootdev) { + ASSERT(XFS_SB_VERSION_HASQUOTA(&mp->m_sb)); + ASSERT(mp->m_sb.sb_qflags & + (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)); + if (xfs_Gqm == NULL) { + if ((xfs_Gqm = xfs_qm_init()) == NULL) { + mp->m_qflags = 0; + error = EINVAL; + goto write_changes; + } + } + mp->m_qflags = mp->m_sb.sb_qflags; + if (mp->m_qflags & XFS_UQUOTA_ACCT) + mp->m_qflags |= XFS_UQUOTA_ACTIVE; + if (mp->m_qflags & XFS_GQUOTA_ACCT) + mp->m_qflags |= XFS_GQUOTA_ACTIVE; + /* + * The quotainode of the root file system may or may not + * exist at this point. + */ + } + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + /* + * Allocate the quotainfo structure inside the mount struct, and + * create quotainode(s), and change/rev superblock if necessary. + */ + if ((error = xfs_qm_init_quotainfo(mp))) { + /* + * We must turn off quotas. + */ + ASSERT(mp->m_quotainfo == NULL); + mp->m_qflags = 0; + goto write_changes; + } + /* + * If any of the quotas are not consistent, do a quotacheck. + */ + if (XFS_QM_NEED_QUOTACHECK(mp)) { +#ifdef DEBUG + cmn_err(CE_NOTE, "Doing a quotacheck. Please wait."); +#endif + if ((error = xfs_qm_quotacheck(mp))) { + cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): " + "Disabling quotas.", + error); + /* + * We must turn off quotas. + */ + ASSERT(mp->m_quotainfo != NULL); + ASSERT(xfs_Gqm != NULL); + xfs_qm_destroy_quotainfo(mp); + mp->m_qflags = 0; + goto write_changes; + } +#ifdef DEBUG + cmn_err(CE_NOTE, "Done quotacheck."); +#endif + } + write_changes: + /* + * We actually don't have to acquire the SB_LOCK at all. + * This can only be called from mount, and that's single threaded. XXX + */ + s = XFS_SB_LOCK(mp); + sbf = mp->m_sb.sb_qflags; + mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL; + XFS_SB_UNLOCK(mp, s); + + if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) { + if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) { + /* + * We could only have been turning quotas off. + * We aren't in very good shape actually because + * the incore structures are convinced that quotas are + * off, but the on disk superblock doesn't know that ! + */ + ASSERT(!(XFS_IS_QUOTA_RUNNING(mp))); + xfs_fs_cmn_err(CE_ALERT, mp, + "XFS mount_quotas: Superblock update failed!"); + } + } + + if (error) { + xfs_fs_cmn_err(CE_WARN, mp, + "Failed to initialize disk quotas."); + } + return XFS_ERROR(error); +} + +/* + * Called from the vfsops layer. + */ +int +xfs_qm_unmount_quotas( + xfs_mount_t *mp) +{ + xfs_inode_t *uqp, *gqp; + int error; + + error = 0; + + /* + * Release the dquots that root inode, et al might be holding, + * before we flush quotas and blow away the quotainfo structure. + */ + ASSERT(mp->m_rootip); + if (mp->m_rootip->i_udquot || mp->m_rootip->i_gdquot) + xfs_qm_dqdettach_inode(mp->m_rootip); + if (mp->m_rbmip && + (mp->m_rbmip->i_udquot || mp->m_rbmip->i_gdquot)) + xfs_qm_dqdettach_inode(mp->m_rbmip); + if (mp->m_rsumip && + (mp->m_rsumip->i_udquot || mp->m_rsumip->i_gdquot)) + xfs_qm_dqdettach_inode(mp->m_rsumip); + + /* + * Flush out the quota inodes. + */ + uqp = gqp = NULL; + if (mp->m_quotainfo) { + if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) { + xfs_ilock(uqp, XFS_ILOCK_EXCL); + xfs_iflock(uqp); + error = xfs_iflush(uqp, XFS_IFLUSH_SYNC); + xfs_iunlock(uqp, XFS_ILOCK_EXCL); + if (error == EFSCORRUPTED) + goto out; + } + if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) { + xfs_ilock(gqp, XFS_ILOCK_EXCL); + xfs_iflock(gqp); + error = xfs_iflush(gqp, XFS_IFLUSH_SYNC); + xfs_iunlock(gqp, XFS_ILOCK_EXCL); + if (error == EFSCORRUPTED) + goto out; + } + } + if (uqp) { + XFS_PURGE_INODE(uqp); + mp->m_quotainfo->qi_uquotaip = NULL; + } + if (gqp) { + XFS_PURGE_INODE(gqp); + mp->m_quotainfo->qi_gquotaip = NULL; + } +out: + return XFS_ERROR(error); +} + +/* + * Flush all dquots of the given file system to disk. The dquots are + * _not_ purged from memory here, just their data written to disk. + */ +int +xfs_qm_dqflush_all( + xfs_mount_t *mp, + int flags) +{ + int recl; + xfs_dquot_t *dqp; + int niters; + int error; + + if (mp->m_quotainfo == NULL) + return (0); + niters = 0; +again: + xfs_qm_mplist_lock(mp); + FOREACH_DQUOT_IN_MP(dqp, mp) { + xfs_dqlock(dqp); + if (! XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqunlock(dqp); + continue; + } + xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY"); + /* XXX a sentinel would be better */ + recl = XFS_QI_MPLRECLAIMS(mp); + if (! xfs_qm_dqflock_nowait(dqp)) { + /* + * If we can't grab the flush lock then check + * to see if the dquot has been flushed delayed + * write. If so, grab its buffer and send it + * out immediately. We'll be able to acquire + * the flush lock when the I/O completes. + */ + xfs_qm_dqflock_pushbuf_wait(dqp); + } + /* + * Let go of the mplist lock. We don't want to hold it + * across a disk write. + */ + xfs_qm_mplist_unlock(mp); + error = xfs_qm_dqflush(dqp, flags); + xfs_dqunlock(dqp); + if (error) + return (error); + + /* + * If this is the root filesystem doing a quotacheck, + * we should do periodic bflushes. This is because there's + * no bflushd at this point. + */ + if (mp->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (++niters == XFS_QM_MAX_DQCLUSTER_LOGSZ) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targp); + niters = 0; + } + } + + xfs_qm_mplist_lock(mp); + if (recl != XFS_QI_MPLRECLAIMS(mp)) { + xfs_qm_mplist_unlock(mp); + /* XXX restart limit */ + goto again; + } + } + + xfs_qm_mplist_unlock(mp); + /* return ! busy */ + return (0); +} +/* + * Release the group dquot pointers the user dquots may be + * carrying around as a hint. mplist is locked on entry and exit. + */ +STATIC void +xfs_qm_detach_gdquots( + xfs_mount_t *mp) +{ + xfs_dquot_t *dqp, *gdqp; + int nrecl; + + again: + ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp)); + dqp = XFS_QI_MPLNEXT(mp); + while (dqp) { + xfs_dqlock(dqp); + if ((gdqp = dqp->q_gdquot)) { + xfs_dqlock(gdqp); + dqp->q_gdquot = NULL; + } + xfs_dqunlock(dqp); + + if (gdqp) { + /* + * Can't hold the mplist lock across a dqput. + * XXXmust convert to marker based iterations here. + */ + nrecl = XFS_QI_MPLRECLAIMS(mp); + xfs_qm_mplist_unlock(mp); + xfs_qm_dqput(gdqp); + + xfs_qm_mplist_lock(mp); + if (nrecl != XFS_QI_MPLRECLAIMS(mp)) + goto again; + } + dqp = dqp->MPL_NEXT; + } +} + +/* + * Go through all the incore dquots of this file system and take them + * off the mplist and hashlist, if the dquot type matches the dqtype + * parameter. This is used when turning off quota accounting for + * users and/or groups, as well as when the filesystem is unmounting. + */ +int +xfs_qm_dqpurge_all( + xfs_mount_t *mp, + uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */ +{ + xfs_dquot_t *dqp; + uint dqtype; + int nrecl; + xfs_dquot_t *nextdqp; + int nmisses; + + if (mp->m_quotainfo == NULL) + return (0); + + dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0; + dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0; + + xfs_qm_mplist_lock(mp); + + /* + * In the first pass through all incore dquots of this filesystem, + * we release the group dquot pointers the user dquots may be + * carrying around as a hint. We need to do this irrespective of + * what's being turned off. + */ + xfs_qm_detach_gdquots(mp); + + again: + nmisses = 0; + ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp)); + /* + * Try to get rid of all of the unwanted dquots. The idea is to + * get them off mplist and hashlist, but leave them on freelist. + */ + dqp = XFS_QI_MPLNEXT(mp); + while (dqp) { + /* + * It's OK to look at the type without taking dqlock here. + * We're holding the mplist lock here, and that's needed for + * a dqreclaim. + */ + if ((dqp->dq_flags & dqtype) == 0) { + dqp = dqp->MPL_NEXT; + continue; + } + + if (! xfs_qm_dqhashlock_nowait(dqp)) { + nrecl = XFS_QI_MPLRECLAIMS(mp); + xfs_qm_mplist_unlock(mp); + XFS_DQ_HASH_LOCK(dqp->q_hash); + xfs_qm_mplist_lock(mp); + + /* + * XXXTheoretically, we can get into a very long + * ping pong game here. + * No one can be adding dquots to the mplist at + * this point, but somebody might be taking things off. + */ + if (nrecl != XFS_QI_MPLRECLAIMS(mp)) { + XFS_DQ_HASH_UNLOCK(dqp->q_hash); + goto again; + } + } + + /* + * Take the dquot off the mplist and hashlist. It may remain on + * freelist in INACTIVE state. + */ + nextdqp = dqp->MPL_NEXT; + nmisses += xfs_qm_dqpurge(dqp, flags); + dqp = nextdqp; + } + xfs_qm_mplist_unlock(mp); + return (nmisses); +} + +STATIC int +xfs_qm_dqattach_one( + xfs_inode_t *ip, + xfs_dqid_t id, + uint type, + uint doalloc, + uint dolock, + xfs_dquot_t *udqhint, /* hint */ + xfs_dquot_t **IO_idqpp) +{ + xfs_dquot_t *dqp; + int error; + + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + error = 0; + /* + * See if we already have it in the inode itself. IO_idqpp is + * &i_udquot or &i_gdquot. This made the code look weird, but + * made the logic a lot simpler. + */ + if ((dqp = *IO_idqpp)) { + if (dolock) + xfs_dqlock(dqp); + xfs_dqtrace_entry(dqp, "DQATTACH: found in ip"); + goto done; + } + + /* + * udqhint is the i_udquot field in inode, and is non-NULL only + * when the type arg is XFS_DQ_GROUP. Its purpose is to save a + * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside + * the user dquot. + */ + ASSERT(!udqhint || type == XFS_DQ_GROUP); + if (udqhint && !dolock) + xfs_dqlock(udqhint); + + /* + * No need to take dqlock to look at the id. + * The ID can't change until it gets reclaimed, and it won't + * be reclaimed as long as we have a ref from inode and we hold + * the ilock. + */ + if (udqhint && + (dqp = udqhint->q_gdquot) && + (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id)) { + ASSERT(XFS_DQ_IS_LOCKED(udqhint)); + xfs_dqlock(dqp); + XFS_DQHOLD(dqp); + ASSERT(*IO_idqpp == NULL); + *IO_idqpp = dqp; + if (!dolock) { + xfs_dqunlock(dqp); + xfs_dqunlock(udqhint); + } + /* XXX XFS_STATS */ + goto done; + } + /* + * We can't hold a dquot lock when we call the dqget code. + * We'll deadlock in no time, because of (not conforming to) + * lock ordering - the inodelock comes before any dquot lock, + * and we may drop and reacquire the ilock in xfs_qm_dqget(). + */ + if (udqhint) + xfs_dqunlock(udqhint); + /* + * Find the dquot from somewhere. This bumps the + * reference count of dquot and returns it locked. + * This can return ENOENT if dquot didn't exist on + * disk and we didn't ask it to allocate; + * ESRCH if quotas got turned off suddenly. + */ + if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type, + doalloc|XFS_QMOPT_DOWARN, &dqp))) { + if (udqhint && dolock) + xfs_dqlock(udqhint); + goto done; + } + + xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget"); + /* + * dqget may have dropped and re-acquired the ilock, but it guarantees + * that the dquot returned is the one that should go in the inode. + */ + *IO_idqpp = dqp; + ASSERT(dqp); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (! dolock) { + xfs_dqunlock(dqp); + ASSERT(!udqhint || !XFS_DQ_IS_LOCKED(udqhint)); + goto done; + } + if (! udqhint) + goto done; + + ASSERT(udqhint); + ASSERT(dolock); + ASSERT(! XFS_DQ_IS_LOCKED(udqhint)); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (! xfs_qm_dqlock_nowait(udqhint)) { + xfs_dqunlock(dqp); + xfs_dqlock(udqhint); + xfs_dqlock(dqp); + } + done: +#ifdef QUOTADEBUG + if (udqhint) { + if (dolock) + ASSERT(XFS_DQ_IS_LOCKED(udqhint)); + else + ASSERT(! XFS_DQ_IS_LOCKED(udqhint)); + } + if (! error) { + if (dolock) + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + else + ASSERT(! XFS_DQ_IS_LOCKED(dqp)); + } +#endif + return (error); +} + + +/* + * Given a udquot and gdquot, attach a ptr to the group dquot in the + * udquot as a hint for future lookups. The idea sounds simple, but the + * execution isn't, because the udquot might have a group dquot attached + * already and getting rid of that gets us into lock ordering contraints. + * The process is complicated more by the fact that the dquots may or may not + * be locked on entry. + */ +STATIC void +xfs_qm_dqattach_grouphint( + xfs_dquot_t *udq, + xfs_dquot_t *gdq, + uint locked) +{ + xfs_dquot_t *tmp; + +#ifdef QUOTADEBUG + if (locked) { + ASSERT(XFS_DQ_IS_LOCKED(udq)); + ASSERT(XFS_DQ_IS_LOCKED(gdq)); + } else { + ASSERT(! XFS_DQ_IS_LOCKED(udq)); + ASSERT(! XFS_DQ_IS_LOCKED(gdq)); + } +#endif + if (! locked) + xfs_dqlock(udq); + + if ((tmp = udq->q_gdquot)) { + if (tmp == gdq) { + if (! locked) + xfs_dqunlock(udq); + return; + } + + udq->q_gdquot = NULL; + /* + * We can't keep any dqlocks when calling dqrele, + * because the freelist lock comes before dqlocks. + */ + xfs_dqunlock(udq); + if (locked) + xfs_dqunlock(gdq); + /* + * we took a hard reference once upon a time in dqget, + * so give it back when the udquot no longer points at it + * dqput() does the unlocking of the dquot. + */ + xfs_qm_dqrele(tmp); + + ASSERT(! XFS_DQ_IS_LOCKED(udq)); + ASSERT(! XFS_DQ_IS_LOCKED(gdq)); + xfs_dqlock(udq); + xfs_dqlock(gdq); + + } else { + ASSERT(XFS_DQ_IS_LOCKED(udq)); + if (! locked) { + ASSERT(! XFS_DQ_IS_LOCKED(gdq)); + xfs_dqlock(gdq); + } + } + + ASSERT(XFS_DQ_IS_LOCKED(udq)); + ASSERT(XFS_DQ_IS_LOCKED(gdq)); + /* + * Somebody could have attached a gdquot here, + * when we dropped the uqlock. If so, just do nothing. + */ + if (udq->q_gdquot == NULL) { + XFS_DQHOLD(gdq); + udq->q_gdquot = gdq; + } + if (! locked) { + xfs_dqunlock(gdq); + xfs_dqunlock(udq); + } +} + + +/* + * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON + * in to account. + * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed. + * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty + * much made this code a complete mess, but it has been pretty useful. + * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL. + * Inode may get unlocked and relocked in here, and the caller must deal with + * the consequences. + */ +int +xfs_qm_dqattach( + xfs_inode_t *ip, + uint flags) +{ + int error; + xfs_mount_t *mp; + uint nquotas; + + mp = ip->i_mount; + ASSERT(ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino); + + ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 || + XFS_ISLOCKED_INODE_EXCL(ip)); + + nquotas = 0; + error = 0; + if (! (flags & XFS_QMOPT_ILOCKED)) + xfs_ilock(ip, XFS_ILOCK_EXCL); + + if (XFS_IS_UQUOTA_ON(mp)) { + if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER, + flags & XFS_QMOPT_DQALLOC, + flags & XFS_QMOPT_DQLOCK, + NULL, &ip->i_udquot))) + goto done; + nquotas++; + } + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + if (XFS_IS_GQUOTA_ON(mp)) { + if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, + flags & XFS_QMOPT_DQALLOC, + flags & XFS_QMOPT_DQLOCK, + ip->i_udquot, &ip->i_gdquot))) + /* + * Don't worry about the udquot that we may have + * attached above. It'll get dettached, if not already. + */ + goto done; + nquotas++; + } + + /* + * Attach this group quota to the user quota as a hint. + * This WON'T, in general, result in a thrash. + */ + if (nquotas == 2) { + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(ip->i_udquot); + ASSERT(ip->i_gdquot); + + /* + * We may or may not have the i_udquot locked at this point, + * but this check is OK since we don't depend on the i_gdquot to + * be accurate 100% all the time. It is just a hint, and this + * will succeed in general. + */ + if (ip->i_udquot->q_gdquot == ip->i_gdquot) + goto done; + /* + * Attach i_gdquot to the gdquot hint inside the i_udquot. + */ + xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot, + flags & XFS_QMOPT_DQLOCK); + } + + done: + +#ifdef QUOTADEBUG + if (! error) { + if (ip->i_udquot) { + if (flags & XFS_QMOPT_DQLOCK) + ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot)); + else + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot)); + } + if (ip->i_gdquot) { + if (flags & XFS_QMOPT_DQLOCK) + ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot)); + else + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot)); + } + if (XFS_IS_UQUOTA_ON(mp)) + ASSERT(ip->i_udquot); + if (XFS_IS_GQUOTA_ON(mp)) + ASSERT(ip->i_gdquot); + } +#endif + + if (! (flags & XFS_QMOPT_ILOCKED)) + xfs_iunlock(ip, XFS_ILOCK_EXCL); + +#ifdef QUOTADEBUG + else + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); +#endif + return (error); +} + +/* + * Release dquots (and their references) if any. + * The inode should be locked EXCL except when this's called by + * xfs_ireclaim. + */ +void +xfs_qm_dqdettach_inode( + xfs_inode_t *ip) +{ + ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino); + ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino); + if (ip->i_udquot) + xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip); + if (ip->i_udquot) { + xfs_qm_dqrele(ip->i_udquot); + ip->i_udquot = NULL; + } + if (ip->i_gdquot) { + xfs_qm_dqrele(ip->i_gdquot); + ip->i_gdquot = NULL; + } +} + +int +xfs_qm_unmount( + xfs_mount_t *mp) +{ + vnode_t *vp; + + if (XFS_IS_UQUOTA_ON(mp)) { + vp = XFS_ITOV(XFS_QI_UQIP(mp)); + VN_RELE(vp); + if (vn_count(vp) > 1) + cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d", + vp, vn_count(vp)); + } + if (XFS_IS_GQUOTA_ON(mp)) { + vp = XFS_ITOV(XFS_QI_GQIP(mp)); + VN_RELE(vp); + if (vn_count(vp) > 1) + cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d", + vp, vn_count(vp)); + } + + return (0); +} + + +/* + * This is called by xfs_sync and flags arg determines the caller, + * and its motives, as done in xfs_sync. + * + * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31 + * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25 + * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA + */ + +int +xfs_qm_sync( + xfs_mount_t *mp, + short flags) +{ + int recl, restarts; + xfs_dquot_t *dqp; + uint flush_flags; + boolean_t nowait; + int error; + + restarts = 0; + /* + * We won't block unless we are asked to. + */ + nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0); + + again: + xfs_qm_mplist_lock(mp); + /* + * dqpurge_all() also takes the mplist lock and iterate thru all dquots + * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared + * when we have the mplist lock, we know that dquots will be consistent + * as long as we have it locked. + */ + if (! XFS_IS_QUOTA_ON(mp)) { + xfs_qm_mplist_unlock(mp); + return (0); + } + FOREACH_DQUOT_IN_MP(dqp, mp) { + /* + * If this is vfs_sync calling, then skip the dquots that + * don't 'seem' to be dirty. ie. don't acquire dqlock. + * This is very similar to what xfs_sync does with inodes. + */ + if (flags & SYNC_BDFLUSH) { + if (! XFS_DQ_IS_DIRTY(dqp)) + continue; + } + + if (nowait) { + /* + * Try to acquire the dquot lock. We are NOT out of + * lock order, but we just don't want to wait for this + * lock, unless somebody wanted us to. + */ + if (! xfs_qm_dqlock_nowait(dqp)) + continue; + } else { + xfs_dqlock(dqp); + } + + /* + * Now, find out for sure if this dquot is dirty or not. + */ + if (! XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqunlock(dqp); + continue; + } + + /* XXX a sentinel would be better */ + recl = XFS_QI_MPLRECLAIMS(mp); + if (! xfs_qm_dqflock_nowait(dqp)) { + if (nowait) { + xfs_dqunlock(dqp); + continue; + } + /* + * If we can't grab the flush lock then if the caller + * really wanted us to give this our best shot, + * see if we can give a push to the buffer before we wait + * on the flush lock. At this point, we know that + * eventhough the dquot is being flushed, + * it has (new) dirty data. + */ + xfs_qm_dqflock_pushbuf_wait(dqp); + } + /* + * Let go of the mplist lock. We don't want to hold it + * across a disk write + */ + flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC; + xfs_qm_mplist_unlock(mp); + xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH"); + error = xfs_qm_dqflush(dqp, flush_flags); + xfs_dqunlock(dqp); + if (error && XFS_FORCED_SHUTDOWN(mp)) + return(0); /* Need to prevent umount failure */ + else if (error) + return (error); + + xfs_qm_mplist_lock(mp); + if (recl != XFS_QI_MPLRECLAIMS(mp)) { + if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS) + break; + + xfs_qm_mplist_unlock(mp); + goto again; + } + } + + xfs_qm_mplist_unlock(mp); + return (0); +} + + +/* + * This initializes all the quota information that's kept in the + * mount structure + */ +int +xfs_qm_init_quotainfo( + xfs_mount_t *mp) +{ + xfs_quotainfo_t *qinf; + int error; + xfs_dquot_t *dqp; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + /* + * Tell XQM that we exist as soon as possible. + */ + if ((error = xfs_qm_hold_quotafs_ref(mp))) { + return (error); + } + + qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP); + + /* + * See if quotainodes are setup, and if not, allocate them, + * and change the superblock accordingly. + */ + if ((error = xfs_qm_init_quotainos(mp))) { + kmem_free(qinf, sizeof(xfs_quotainfo_t)); + mp->m_quotainfo = NULL; + return (error); + } + + spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin"); + xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0); + qinf->qi_dqreclaims = 0; + + /* mutex used to serialize quotaoffs */ + mutex_init(&qinf->qi_quotaofflock, MUTEX_DEFAULT, "qoff"); + + /* Precalc some constants */ + qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); + ASSERT(qinf->qi_dqchunklen); + qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen); + do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t)); + + mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD); + + /* + * We try to get the limits from the superuser's limits fields. + * This is quite hacky, but it is standard quota practice. + * We look at the USR dquot with id == 0 first, but if user quotas + * are not enabled we goto the GRP dquot with id == 0. + * We don't really care to keep separate default limits for user + * and group quotas, at least not at this point. + */ + error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0, + (XFS_IS_UQUOTA_RUNNING(mp)) ? + XFS_DQ_USER : XFS_DQ_GROUP, + XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN, + &dqp); + if (! error) { + /* + * The warnings and timers set the grace period given to + * a user or group before he or she can not perform any + * more writing. If it is zero, a default is used. + */ + qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT; + qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT; + qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT; + qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT; + qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT; + + /* + * We sent the XFS_QMOPT_DQSUSER flag to dqget because + * we don't want this dquot cached. We haven't done a + * quotacheck yet, and quotacheck doesn't like incore dquots. + */ + xfs_qm_dqdestroy(dqp); + } else { + qinf->qi_btimelimit = XFS_QM_BTIMELIMIT; + qinf->qi_itimelimit = XFS_QM_ITIMELIMIT; + qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT; + qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT; + qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT; + } + + return (0); +} + + +/* + * Gets called when unmounting a filesystem or when all quotas get + * turned off. + * This purges the quota inodes, destroys locks and frees itself. + */ +void +xfs_qm_destroy_quotainfo( + xfs_mount_t *mp) +{ + xfs_quotainfo_t *qi; + + qi = mp->m_quotainfo; + ASSERT(qi != NULL); + ASSERT(xfs_Gqm != NULL); + + /* + * Release the reference that XQM kept, so that we know + * when the XQM structure should be freed. We cannot assume + * that xfs_Gqm is non-null after this point. + */ + xfs_qm_rele_quotafs_ref(mp); + + spinlock_destroy(&qi->qi_pinlock); + xfs_qm_list_destroy(&qi->qi_dqlist); + + if (qi->qi_uquotaip) { + XFS_PURGE_INODE(qi->qi_uquotaip); + qi->qi_uquotaip = NULL; /* paranoia */ + } + if (qi->qi_gquotaip) { + XFS_PURGE_INODE(qi->qi_gquotaip); + qi->qi_gquotaip = NULL; + } + mutex_destroy(&qi->qi_quotaofflock); + kmem_free(qi, sizeof(xfs_quotainfo_t)); + mp->m_quotainfo = NULL; +} + + + +/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */ + +/* ARGSUSED */ +STATIC void +xfs_qm_list_init( + xfs_dqlist_t *list, + char *str, + int n) +{ + mutex_init(&list->qh_lock, MUTEX_DEFAULT, str); + list->qh_next = NULL; + list->qh_version = 0; + list->qh_nelems = 0; +} + +STATIC void +xfs_qm_list_destroy( + xfs_dqlist_t *list) +{ + mutex_destroy(&(list->qh_lock)); +} + + +/* + * Stripped down version of dqattach. This doesn't attach, or even look at the + * dquots attached to the inode. The rationale is that there won't be any + * attached at the time this is called from quotacheck. + */ +STATIC int +xfs_qm_dqget_noattach( + xfs_inode_t *ip, + xfs_dquot_t **O_udqpp, + xfs_dquot_t **O_gdqpp) +{ + int error; + xfs_mount_t *mp; + xfs_dquot_t *udqp, *gdqp; + + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + mp = ip->i_mount; + udqp = NULL; + gdqp = NULL; + + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(ip->i_udquot == NULL); + /* + * We want the dquot allocated if it doesn't exist. + */ + if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER, + XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, + &udqp))) { + /* + * Shouldn't be able to turn off quotas here. + */ + ASSERT(error != ESRCH); + ASSERT(error != ENOENT); + return (error); + } + ASSERT(udqp); + } + + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(ip->i_gdquot == NULL); + if (udqp) + xfs_dqunlock(udqp); + if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP, + XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, + &gdqp))) { + if (udqp) + xfs_qm_dqrele(udqp); + ASSERT(error != ESRCH); + ASSERT(error != ENOENT); + return (error); + } + ASSERT(gdqp); + + /* Reacquire the locks in the right order */ + if (udqp) { + if (! xfs_qm_dqlock_nowait(udqp)) { + xfs_dqunlock(gdqp); + xfs_dqlock(udqp); + xfs_dqlock(gdqp); + } + } + } + + *O_udqpp = udqp; + *O_gdqpp = gdqp; + +#ifdef QUOTADEBUG + if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp)); + if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp)); +#endif + return (0); +} + +/* + * Create an inode and return with a reference already taken, but unlocked + * This is how we create quota inodes + */ +STATIC int +xfs_qm_qino_alloc( + xfs_mount_t *mp, + xfs_inode_t **ip, + __int64_t sbfields, + uint flags) +{ + xfs_trans_t *tp; + int error; + unsigned long s; + cred_t zerocr; + int committed; + + tp = xfs_trans_alloc(mp,XFS_TRANS_QM_QINOCREATE); + if ((error = xfs_trans_reserve(tp, + XFS_QM_QINOCREATE_SPACE_RES(mp), + XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_CREATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + bzero(&zerocr, sizeof(zerocr)); + + if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, mp->m_dev, + &zerocr, 0, 1, ip, &committed))) { + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT); + return (error); + } + + /* + * Keep an extra reference to this quota inode. This inode is + * locked exclusively and joined to the transaction already. + */ + ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip)); + VN_HOLD(XFS_ITOV((*ip))); + + /* + * Make the changes in the superblock, and log those too. + * sbfields arg may contain fields other than *QUOTINO; + * VERSIONNUM for example. + */ + s = XFS_SB_LOCK(mp); + if (flags & XFS_QMOPT_SBVERSION) { +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + unsigned oldv = mp->m_sb.sb_versionnum; +#endif + ASSERT(!XFS_SB_VERSION_HASQUOTA(&mp->m_sb)); + ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) == + (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS)); + + XFS_SB_VERSION_ADDQUOTA(&mp->m_sb); + mp->m_sb.sb_uquotino = NULLFSINO; + mp->m_sb.sb_gquotino = NULLFSINO; + + /* qflags will get updated _after_ quotacheck */ + mp->m_sb.sb_qflags = 0; +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, + "Old superblock version %x, converting to %x.", + oldv, mp->m_sb.sb_versionnum); +#endif + } + if (flags & XFS_QMOPT_UQUOTA) + mp->m_sb.sb_uquotino = (*ip)->i_ino; + else + mp->m_sb.sb_gquotino = (*ip)->i_ino; + XFS_SB_UNLOCK(mp, s); + xfs_mod_sb(tp, sbfields); + + if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, + NULL))) { + xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!"); + return (error); + } + return (0); +} + + +STATIC int +xfs_qm_reset_dqcounts( + xfs_mount_t *mp, + xfs_buf_t *bp, + xfs_dqid_t id, + uint type) +{ + xfs_disk_dquot_t *ddq; + int j; + + xfs_buftrace("RESET DQUOTS", bp); + /* + * Reset all counters and timers. They'll be + * started afresh by xfs_qm_quotacheck. + */ +#ifdef DEBUG + j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); + do_div(j, sizeof(xfs_dqblk_t)); + ASSERT(XFS_QM_DQPERBLK(mp) == j); +#endif + ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp); + for (j = 0; j < XFS_QM_DQPERBLK(mp); j++) { + /* + * Do a sanity check, and if needed, repair the dqblk. Don't + * output any warnings because it's perfectly possible to + * find unitialized dquot blks. See comment in xfs_qm_dqcheck. + */ + (void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR, + "xfs_quotacheck"); + INT_SET(ddq->d_bcount, ARCH_CONVERT, 0ULL); + INT_SET(ddq->d_icount, ARCH_CONVERT, 0ULL); + INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL); + INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0); + INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0); + INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL); + INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL); + ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1); + } + + return (0); +} + +STATIC int +xfs_qm_dqiter_bufs( + xfs_mount_t *mp, + xfs_dqid_t firstid, + xfs_fsblock_t bno, + xfs_filblks_t blkcnt, + uint flags) +{ + xfs_buf_t *bp; + int error; + int notcommitted; + int incr; + + ASSERT(blkcnt > 0); + notcommitted = 0; + incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ? + XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt; + error = 0; + + /* + * Blkcnt arg can be a very big number, and might even be + * larger than the log itself. So, we have to break it up into + * manageable-sized transactions. + * Note that we don't start a permanent transaction here; we might + * not be able to get a log reservation for the whole thing up front, + * and we don't really care to either, because we just discard + * everything if we were to crash in the middle of this loop. + */ + while (blkcnt--) { + error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, bno), + (int)XFS_QI_DQCHUNKLEN(mp), 0, &bp); + if (error) + break; + + (void) xfs_qm_reset_dqcounts(mp, bp, firstid, + flags & XFS_QMOPT_UQUOTA ? + XFS_DQ_USER : XFS_DQ_GROUP); + xfs_bdwrite(mp, bp); + /* + * When quotachecking the root filesystem, + * we may not have bdflush, and we may fill + * up all available freebufs. + * The workaround here is to push on the + * log and do a bflush on the rootdev + * periodically. + */ + if (mp->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (++notcommitted == incr) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targp); + notcommitted = 0; + } + } + /* + * goto the next block. + */ + bno++; + firstid += XFS_QM_DQPERBLK(mp); + } + return (error); +} + +/* + * Iterate over all allocated USR/GRP dquots in the system, calling a + * caller supplied function for every chunk of dquots that we find. + */ +STATIC int +xfs_qm_dqiterate( + xfs_mount_t *mp, + xfs_inode_t *qip, + uint flags) +{ + xfs_bmbt_irec_t *map; + int i, nmaps; /* number of map entries */ + int error; /* return value */ + xfs_fileoff_t lblkno; + xfs_filblks_t maxlblkcnt; + xfs_dqid_t firstid; + xfs_fsblock_t rablkno; + xfs_filblks_t rablkcnt; + + error = 0; + /* + * This looks racey, but we can't keep an inode lock across a + * trans_reserve. But, this gets called during quotacheck, and that + * happens only at mount time which is single threaded. + */ + if (qip->i_d.di_nblocks == 0) + return (0); + + map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP); + + lblkno = 0; + maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET); + do { + nmaps = XFS_DQITER_MAP_SIZE; + /* + * We aren't changing the inode itself. Just changing + * some of its data. No new blocks are added here, and + * the inode is never added to the transaction. + */ + xfs_ilock(qip, XFS_ILOCK_SHARED); + error = xfs_bmapi(NULL, qip, lblkno, + maxlblkcnt - lblkno, + XFS_BMAPI_METADATA, + NULL, + 0, map, &nmaps, NULL); + xfs_iunlock(qip, XFS_ILOCK_SHARED); + if (error) + break; + + ASSERT(nmaps <= XFS_DQITER_MAP_SIZE); + for (i = 0; i < nmaps; i++) { + ASSERT(map[i].br_startblock != DELAYSTARTBLOCK); + ASSERT(map[i].br_blockcount); + + + lblkno += map[i].br_blockcount; + + if (map[i].br_startblock == HOLESTARTBLOCK) + continue; + + firstid = (xfs_dqid_t) map[i].br_startoff * + XFS_QM_DQPERBLK(mp); + /* + * Do a read-ahead on the next extent. + */ + if ((i+1 < nmaps) && + (map[i+1].br_startblock != HOLESTARTBLOCK)) { + rablkcnt = map[i+1].br_blockcount; + rablkno = map[i+1].br_startblock; + while (rablkcnt--) { + xfs_baread(mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, rablkno), + (int)XFS_QI_DQCHUNKLEN(mp)); + rablkno++; + } + } + /* + * Iterate thru all the blks in the extent and + * reset the counters of all the dquots inside them. + */ + if ((error = xfs_qm_dqiter_bufs(mp, + firstid, + map[i].br_startblock, + map[i].br_blockcount, + flags))) { + break; + } + } + + if (error) + break; + } while (nmaps > 0); + + kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map)); + + return (error); +} + +/* + * Called by dqusage_adjust in doing a quotacheck. + * Given the inode, and a dquot (either USR or GRP, doesn't matter), + * this updates its incore copy as well as the buffer copy. This is + * so that once the quotacheck is done, we can just log all the buffers, + * as opposed to logging numerous updates to individual dquots. + */ +STATIC void +xfs_qm_quotacheck_dqadjust( + xfs_dquot_t *dqp, + xfs_qcnt_t nblks, + xfs_qcnt_t rtblks) +{ + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + xfs_dqtrace_entry(dqp, "QCHECK DQADJUST"); + /* + * Adjust the inode count and the block count to reflect this inode's + * resource usage. + */ + INT_MOD(dqp->q_core.d_icount, ARCH_CONVERT, +1); + dqp->q_res_icount++; + if (nblks) { + INT_MOD(dqp->q_core.d_bcount, ARCH_CONVERT, nblks); + dqp->q_res_bcount += nblks; + } + if (rtblks) { + INT_MOD(dqp->q_core.d_rtbcount, ARCH_CONVERT, rtblks); + dqp->q_res_rtbcount += rtblks; + } + + /* + * Adjust the timers since we just changed usages + */ + if (! XFS_IS_SUSER_DQUOT(dqp)) + xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core); + + dqp->dq_flags |= XFS_DQ_DIRTY; +} + +STATIC int +xfs_qm_get_rtblks( + xfs_inode_t *ip, + xfs_qcnt_t *O_rtblks) +{ + xfs_filblks_t rtblks; /* total rt blks */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extent entries */ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ + int error; + + ASSERT(XFS_IS_REALTIME_INODE(ip)); + ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); + if (!(ifp->if_flags & XFS_IFEXTENTS)) { + if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK))) + return (error); + } + rtblks = 0; + nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + for (ep = base; ep < &base[nextents]; ep++) + rtblks += xfs_bmbt_get_blockcount(ep); + *O_rtblks = (xfs_qcnt_t)rtblks; + return (0); +} + +/* + * callback routine supplied to bulkstat(). Given an inumber, find its + * dquots and update them to account for resources taken by that inode. + */ +/* ARGSUSED */ +STATIC int +xfs_qm_dqusage_adjust( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer - NULL */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* not used */ + xfs_daddr_t bno, /* starting block of inode cluster */ + void *dip, /* on-disk inode pointer (not used) */ + int *res) /* result code value */ +{ + xfs_inode_t *ip; + xfs_dquot_t *udqp, *gdqp; + xfs_qcnt_t nblks, rtblks; + int error; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + /* + * rootino must have its resources accounted for, not so with the quota + * inodes. + */ + if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) { + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(EINVAL); + } + + /* + * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget + * interface expects the inode to be exclusively locked because that's + * the case in all other instances. It's OK that we do this because + * quotacheck is done only at mount time. + */ + if ((error = xfs_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip, bno))) { + *res = BULKSTAT_RV_NOTHING; + return (error); + } + + if (ip->i_d.di_mode == 0) { + xfs_iput_new(ip, XFS_ILOCK_EXCL); + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + + /* + * Obtain the locked dquots. In case of an error (eg. allocation + * fails for ENOSPC), we return the negative of the error number + * to bulkstat, so that it can get propagated to quotacheck() and + * making us disable quotas for the file system. + */ + if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) { + xfs_iput(ip, XFS_ILOCK_EXCL); + *res = BULKSTAT_RV_GIVEUP; + return (error); + } + + rtblks = 0; + if (! XFS_IS_REALTIME_INODE(ip)) { + nblks = (xfs_qcnt_t)ip->i_d.di_nblocks; + } else { + /* + * Walk thru the extent list and count the realtime blocks. + */ + if ((error = xfs_qm_get_rtblks(ip, &rtblks))) { + xfs_iput(ip, XFS_ILOCK_EXCL); + if (udqp) + xfs_qm_dqput(udqp); + if (gdqp) + xfs_qm_dqput(gdqp); + *res = BULKSTAT_RV_GIVEUP; + return (error); + } + nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks; + } + ASSERT(ip->i_delayed_blks == 0); + + /* + * We can't release the inode while holding its dquot locks. + * The inode can go into inactive and might try to acquire the dquotlocks. + * So, just unlock here and do a vn_rele at the end. + */ + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + /* + * Add the (disk blocks and inode) resources occupied by this + * inode to its dquots. We do this adjustment in the incore dquot, + * and also copy the changes to its buffer. + * We don't care about putting these changes in a transaction + * envelope because if we crash in the middle of a 'quotacheck' + * we have to start from the beginning anyway. + * Once we're done, we'll log all the dquot bufs. + * + * The *QUOTA_ON checks below may look pretty racey, but quotachecks + * and quotaoffs don't race. (Quotachecks happen at mount time only). + */ + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(udqp); + xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); + xfs_qm_dqput(udqp); + } + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(gdqp); + xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); + xfs_qm_dqput(gdqp); + } + /* + * Now release the inode. This will send it to 'inactive', and + * possibly even free blocks. + */ + VN_RELE(XFS_ITOV(ip)); + + /* + * Goto next inode. + */ + *res = BULKSTAT_RV_DIDONE; + return (0); +} + +/* + * Walk thru all the filesystem inodes and construct a consistent view + * of the disk quota world. + */ +STATIC int +xfs_qm_quotacheck( + xfs_mount_t *mp) +{ + int done, count, error; + xfs_ino_t lastino; + size_t structsz; + xfs_inode_t *uip, *gip; + uint flags; + + count = INT_MAX; + structsz = 1; + lastino = 0; + flags = 0; + + ASSERT(XFS_QI_UQIP(mp) || XFS_QI_GQIP(mp)); + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + /* + * There should be no cached dquots. The (simplistic) quotacheck + * algorithm doesn't like that. + */ + ASSERT(XFS_QI_MPLNDQUOTS(mp) == 0); + + cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname); + + /* + * First we go thru all the dquots on disk, USR and GRP, and reset + * their counters to zero. We need a clean slate. + * We don't log our changes till later. + */ + if ((uip = XFS_QI_UQIP(mp))) { + if ((error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA))) + goto error_return; + flags |= XFS_UQUOTA_CHKD; + } + + if ((gip = XFS_QI_GQIP(mp))) { + if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA))) + goto error_return; + flags |= XFS_GQUOTA_CHKD; + } + + do { + /* + * Iterate thru all the inodes in the file system, + * adjusting the corresponding dquot counters in core. + */ + if ((error = xfs_bulkstat(mp, NULL, &lastino, &count, + xfs_qm_dqusage_adjust, + structsz, NULL, + BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED, + &done))) + break; + + } while (! done); + + /* + * We can get this error if we couldn't do a dquot allocation inside + * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the + * dirty dquots that might be cached, we just want to get rid of them + * and turn quotaoff. The dquots won't be attached to any of the inodes + * at this point (because we intentionally didn't in dqget_noattach). + */ + if (error) { + xfs_qm_dqpurge_all(mp, + XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA| + XFS_QMOPT_QUOTAOFF); + goto error_return; + } + /* + * We've made all the changes that we need to make incore. + * Now flush_them down to disk buffers. + */ + xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI); + + /* + * We didn't log anything, because if we crashed, we'll have to + * start the quotacheck from scratch anyway. However, we must make + * sure that our dquot changes are secure before we put the + * quotacheck'd stamp on the superblock. So, here we do a synchronous + * flush. + */ + XFS_bflush(mp->m_ddev_targp); + + /* + * If one type of quotas is off, then it will lose its + * quotachecked status, since we won't be doing accounting for + * that type anymore. + */ + mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD); + mp->m_qflags |= flags; + +#ifdef QUOTADEBUG + XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++"); +#endif + + error_return: + cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname); + mp->m_flags &= ~(XFS_MOUNT_ROOTQCHECK); + return (error); +} + +/* + * This is called after the superblock has been read in and we're ready to + * iget the quota inodes. + */ +STATIC int +xfs_qm_init_quotainos( + xfs_mount_t *mp) +{ + xfs_inode_t *uip, *gip; + int error; + __int64_t sbflags; + uint flags; + + ASSERT(mp->m_quotainfo); + uip = gip = NULL; + sbflags = 0; + flags = 0; + + /* + * Get the uquota and gquota inodes + */ + if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) { + if (XFS_IS_UQUOTA_ON(mp) && + mp->m_sb.sb_uquotino != NULLFSINO) { + ASSERT(mp->m_sb.sb_uquotino > 0); + if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, + 0, &uip, 0))) + return XFS_ERROR(error); + } + if (XFS_IS_GQUOTA_ON(mp) && + mp->m_sb.sb_gquotino != NULLFSINO) { + ASSERT(mp->m_sb.sb_gquotino > 0); + if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, + 0, &gip, 0))) { + if (uip) + VN_RELE(XFS_ITOV(uip)); + return XFS_ERROR(error); + } + } + } else { + flags |= XFS_QMOPT_SBVERSION; + sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS); + } + + /* + * Create the two inodes, if they don't exist already. The changes + * made above will get added to a transaction and logged in one of + * the qino_alloc calls below. + */ + + if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) { + if ((error = xfs_qm_qino_alloc(mp, &uip, + sbflags | XFS_SB_UQUOTINO, + flags | XFS_QMOPT_UQUOTA))) + return XFS_ERROR(error); + + flags &= ~XFS_QMOPT_SBVERSION; + } + if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) { + if ((error = xfs_qm_qino_alloc(mp, &gip, + sbflags | XFS_SB_GQUOTINO, + flags | XFS_QMOPT_GQUOTA))) { + if (uip) + VN_RELE(XFS_ITOV(uip)); + + return XFS_ERROR(error); + } + } + + XFS_QI_UQIP(mp) = uip; + XFS_QI_GQIP(mp) = gip; + + return (0); +} + + +/* + * Traverse the freelist of dquots and attempt to reclaim a maximum of + * 'howmany' dquots. This operation races with dqlookup(), and attempts to + * favor the lookup function ... + * XXXsup merge this with qm_reclaim_one(). + */ +STATIC int +xfs_qm_shake_freelist( + int howmany) +{ + int nreclaimed; + xfs_dqhash_t *hash; + xfs_dquot_t *dqp, *nextdqp; + int restarts; + int nflushes; + + if (howmany <= 0) + return (0); + + nreclaimed = 0; + restarts = 0; + nflushes = 0; + +#ifdef QUOTADEBUG + printk("Shake free 0x%x\n", howmany); +#endif + /* lock order is : hashchainlock, freelistlock, mplistlock */ + tryagain: + xfs_qm_freelist_lock(xfs_Gqm); + + for (dqp = xfs_Gqm->qm_dqfreelist.qh_next; + ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) && + nreclaimed < howmany); ) { + xfs_dqlock(dqp); + + /* + * We are racing with dqlookup here. Naturally we don't + * want to reclaim a dquot that lookup wants. + */ + if (dqp->dq_flags & XFS_DQ_WANT) { + xfs_dqunlock(dqp); + xfs_qm_freelist_unlock(xfs_Gqm); + if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) + return (nreclaimed != howmany); + XFS_STATS_INC(xfsstats.xs_qm_dqwants); + goto tryagain; + } + + /* + * If the dquot is inactive, we are assured that it is + * not on the mplist or the hashlist, and that makes our + * life easier. + */ + if (dqp->dq_flags & XFS_DQ_INACTIVE) { + ASSERT(dqp->q_mount == NULL); + ASSERT(! XFS_DQ_IS_DIRTY(dqp)); + ASSERT(dqp->HL_PREVP == NULL); + ASSERT(dqp->MPL_PREVP == NULL); + XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims); + nextdqp = dqp->dq_flnext; + goto off_freelist; + } + + ASSERT(dqp->MPL_PREVP); + /* + * Try to grab the flush lock. If this dquot is in the process of + * getting flushed to disk, we don't want to reclaim it. + */ + if (! xfs_qm_dqflock_nowait(dqp)) { + xfs_dqunlock(dqp); + dqp = dqp->dq_flnext; + continue; + } + + /* + * We have the flush lock so we know that this is not in the + * process of being flushed. So, if this is dirty, flush it + * DELWRI so that we don't get a freelist infested with + * dirty dquots. + */ + if (XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY"); + /* + * We'll be doing a dqflush, and it is + * possible to fill up the entire buffer cache + * with dirty delayed write buffers when doing + * this on a root filesystem, if bdflush isn't + * running. So, do a flush periodically. + */ + if (dqp->q_mount->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (!(++nflushes % XFS_QM_MAX_DQCLUSTER_LOGSZ)){ + xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(dqp->q_mount->m_ddev_targp); + } + } + /* + * We flush it delayed write, so don't bother + * releasing the mplock. + */ + (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); + xfs_dqunlock(dqp); /* dqflush unlocks dqflock */ + dqp = dqp->dq_flnext; + continue; + } + /* + * We're trying to get the hashlock out of order. This races + * with dqlookup; so, we giveup and goto the next dquot if + * we couldn't get the hashlock. This way, we won't starve + * a dqlookup process that holds the hashlock that is + * waiting for the freelist lock. + */ + if (! xfs_qm_dqhashlock_nowait(dqp)) { + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + dqp = dqp->dq_flnext; + continue; + } + /* + * This races with dquot allocation code as well as dqflush_all + * and reclaim code. So, if we failed to grab the mplist lock, + * giveup everything and start over. + */ + hash = dqp->q_hash; + ASSERT(hash); + if (! xfs_qm_mplist_nowait(dqp->q_mount)) { + /* XXX put a sentinel so that we can come back here */ + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + XFS_DQ_HASH_UNLOCK(hash); + xfs_qm_freelist_unlock(xfs_Gqm); + if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) + return (nreclaimed != howmany); + goto tryagain; + } + xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING"); +#ifdef QUOTADEBUG + printk("Shake 0x%p, ID 0x%x\n", dqp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); +#endif + ASSERT(dqp->q_nrefs == 0); + nextdqp = dqp->dq_flnext; + XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp); + XQM_HASHLIST_REMOVE(hash, dqp); + xfs_dqfunlock(dqp); + xfs_qm_mplist_unlock(dqp->q_mount); + XFS_DQ_HASH_UNLOCK(hash); + + off_freelist: + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + nreclaimed++; + XFS_STATS_INC(xfsstats.xs_qm_dqshake_reclaims); + xfs_qm_dqdestroy(dqp); + dqp = nextdqp; + } + xfs_qm_freelist_unlock(xfs_Gqm); + return (nreclaimed != howmany); +} + + +/* + * The shake manager routine called by shaked() when memory is + * running low. + */ +/* ARGSUSED */ +STATIC void +xfs_qm_shake(void) +{ + int ndqused, nfree, n; + + if (!xfs_Gqm) + return; + + nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */ + /* incore dquots in all f/s's */ + ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree; + + ASSERT(ndqused >= 0); + + if (nfree <= ndqused && nfree < ndquot) + return; + + ndqused *= xfs_Gqm->qm_dqfree_ratio; /* target # of free dquots */ + n = nfree - ndqused - ndquot; /* # over target */ + + (void) xfs_qm_shake_freelist(MAX(nfree, n)); +} + + +/* + * Just pop the least recently used dquot off the freelist and + * recycle it. The returned dquot is locked. + */ +STATIC xfs_dquot_t * +xfs_qm_dqreclaim_one(void) +{ + xfs_dquot_t *dqpout; + xfs_dquot_t *dqp; + int restarts; + int nflushes; + + restarts = 0; + dqpout = NULL; + nflushes = 0; + + /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */ + startagain: + xfs_qm_freelist_lock(xfs_Gqm); + + FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) { + xfs_dqlock(dqp); + + /* + * We are racing with dqlookup here. Naturally we don't + * want to reclaim a dquot that lookup wants. We release the + * freelist lock and start over, so that lookup will grab + * both the dquot and the freelistlock. + */ + if (dqp->dq_flags & XFS_DQ_WANT) { + ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE)); + xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT"); + xfs_dqunlock(dqp); + xfs_qm_freelist_unlock(xfs_Gqm); + if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) + return (NULL); + XFS_STATS_INC(xfsstats.xs_qm_dqwants); + goto startagain; + } + + /* + * If the dquot is inactive, we are assured that it is + * not on the mplist or the hashlist, and that makes our + * life easier. + */ + if (dqp->dq_flags & XFS_DQ_INACTIVE) { + ASSERT(dqp->q_mount == NULL); + ASSERT(! XFS_DQ_IS_DIRTY(dqp)); + ASSERT(dqp->HL_PREVP == NULL); + ASSERT(dqp->MPL_PREVP == NULL); + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + dqpout = dqp; + XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims); + break; + } + + ASSERT(dqp->q_hash); + ASSERT(dqp->MPL_PREVP); + + /* + * Try to grab the flush lock. If this dquot is in the process of + * getting flushed to disk, we don't want to reclaim it. + */ + if (! xfs_qm_dqflock_nowait(dqp)) { + xfs_dqunlock(dqp); + continue; + } + + /* + * We have the flush lock so we know that this is not in the + * process of being flushed. So, if this is dirty, flush it + * DELWRI so that we don't get a freelist infested with + * dirty dquots. + */ + if (XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY"); + /* + * We'll be doing a dqflush, and it is + * possible to fill up the entire buffer cache + * with dirty delayed write buffers when doing + * this on a root filesystem, if bdflush isn't + * running. So, do a flush periodically. + */ + if (dqp->q_mount->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (!(++nflushes % XFS_QM_MAX_DQCLUSTER_LOGSZ)) { + xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(dqp->q_mount->m_ddev_targp); + } + } + + /* + * We flush it delayed write, so don't bother + * releasing the freelist lock. + */ + (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); + xfs_dqunlock(dqp); /* dqflush unlocks dqflock */ + continue; + } + + if (! xfs_qm_mplist_nowait(dqp->q_mount)) { + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + continue; + } + + if (! xfs_qm_dqhashlock_nowait(dqp)) + goto mplistunlock; + + ASSERT(dqp->q_nrefs == 0); + xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING"); + XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp); + XQM_HASHLIST_REMOVE(dqp->q_hash, dqp); + XQM_FREELIST_REMOVE(dqp); + dqpout = dqp; + XFS_DQ_HASH_UNLOCK(dqp->q_hash); + mplistunlock: + xfs_qm_mplist_unlock(dqp->q_mount); + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + if (dqpout) + break; + } + + xfs_qm_freelist_unlock(xfs_Gqm); + return (dqpout); +} + + +/*------------------------------------------------------------------*/ + +/* + * Return a new incore dquot. Depending on the number of + * dquots in the system, we either allocate a new one on the kernel heap, + * or reclaim a free one. + * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed + * to reclaim an existing one from the freelist. + */ +boolean_t +xfs_qm_dqalloc_incore( + xfs_dquot_t **O_dqpp) +{ + xfs_dquot_t *dqp; + + /* + * Check against high water mark to see if we want to pop + * a nincompoop dquot off the freelist. + */ + if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) { + /* + * Try to recycle a dquot from the freelist. + */ + if ((dqp = xfs_qm_dqreclaim_one())) { + XFS_STATS_INC(xfsstats.xs_qm_dqreclaims); + /* + * Just bzero the core here. The rest will get + * reinitialized by caller. XXX we shouldn't even + * do this bzero ... + */ + bzero(&dqp->q_core, sizeof(dqp->q_core)); + *O_dqpp = dqp; + return (B_FALSE); + } + XFS_STATS_INC(xfsstats.xs_qm_dqreclaim_misses); + } + + /* + * Allocate a brand new dquot on the kernel heap and return it + * to the caller to initialize. + */ + ASSERT(xfs_Gqm->qm_dqzone != NULL); + *O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP); + atomic_inc(&xfs_Gqm->qm_totaldquots); + + return (B_TRUE); +} + + +/* + * Start a transaction and write the incore superblock changes to + * disk. flags parameter indicates which fields have changed. + */ +int +xfs_qm_write_sb_changes( + xfs_mount_t *mp, + __int64_t flags) +{ + xfs_trans_t *tp; + int error; + +#ifdef QUOTADEBUG + cmn_err(CE_NOTE, + "Writing superblock quota changes :%s", + mp->m_fsname); +#endif + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE); + if ((error = xfs_trans_reserve(tp, 0, + mp->m_sb.sb_sectsize + 128, 0, + 0, + XFS_DEFAULT_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + + xfs_mod_sb(tp, flags); + (void) xfs_trans_commit(tp, 0, NULL); + + return (0); +} + + +/* --------------- utility functions for vnodeops ---------------- */ + + +/* + * Given an inode, a uid and gid (from cred_t) make sure that we have + * allocated relevant dquot(s) on disk, and that we won't exceed inode + * quotas by creating this file. + * This also attaches dquot(s) to the given inode after locking it, + * and returns the dquots corresponding to the uid and/or gid. + * + * in : inode (unlocked) + * out : udquot, gdquot with references taken and unlocked + */ +int +xfs_qm_vop_dqalloc( + xfs_mount_t *mp, + xfs_inode_t *ip, + uid_t uid, + gid_t gid, + uint flags, + xfs_dquot_t **O_udqpp, + xfs_dquot_t **O_gdqpp) +{ + int error; + xfs_dquot_t *uq, *gq; + uint lockflags; + + lockflags = XFS_ILOCK_EXCL; + xfs_ilock(ip, lockflags); + + if ((flags & XFS_QMOPT_INHERIT) && + XFS_INHERIT_GID(ip, XFS_MTOVFS(mp))) + gid = ip->i_d.di_gid; + + /* + * Attach the dquot(s) to this inode, doing a dquot allocation + * if necessary. The dquot(s) will not be locked. + */ + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC | + XFS_QMOPT_ILOCKED))) { + xfs_iunlock(ip, lockflags); + return (error); + } + } + + uq = gq = NULL; + if ((flags & XFS_QMOPT_UQUOTA) && + XFS_IS_UQUOTA_ON(mp)) { + if (ip->i_d.di_uid != uid) { + /* + * What we need is the dquot that has this uid, and + * if we send the inode to dqget, the uid of the inode + * takes priority over what's sent in the uid argument. + * We must unlock inode here before calling dqget if + * we're not sending the inode, because otherwise + * we'll deadlock by doing trans_reserve while + * holding ilock. + */ + xfs_iunlock(ip, lockflags); + if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid, + XFS_DQ_USER, + XFS_QMOPT_DQALLOC | + XFS_QMOPT_DOWARN, + &uq))) { + ASSERT(error != ENOENT); + return (error); + } + /* + * Get the ilock in the right order. + */ + xfs_dqunlock(uq); + lockflags = XFS_ILOCK_SHARED; + xfs_ilock(ip, lockflags); + } else { + /* + * Take an extra reference, because we'll return + * this to caller + */ + ASSERT(ip->i_udquot); + uq = ip->i_udquot; + xfs_dqlock(uq); + XFS_DQHOLD(uq); + xfs_dqunlock(uq); + } + } + if ((flags & XFS_QMOPT_GQUOTA) && + XFS_IS_GQUOTA_ON(mp)) { + if (ip->i_d.di_gid != gid) { + xfs_iunlock(ip, lockflags); + if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid, + XFS_DQ_GROUP, + XFS_QMOPT_DQALLOC | + XFS_QMOPT_DOWARN, + &gq))) { + if (uq) + xfs_qm_dqrele(uq); + ASSERT(error != ENOENT); + return (error); + } + xfs_dqunlock(gq); + lockflags = XFS_ILOCK_SHARED; + xfs_ilock(ip, lockflags); + } else { + ASSERT(ip->i_gdquot); + gq = ip->i_gdquot; + xfs_dqlock(gq); + XFS_DQHOLD(gq); + xfs_dqunlock(gq); + } + } + if (uq) + xfs_dqtrace_entry_ino(uq, "DQALLOC", ip); + + xfs_iunlock(ip, lockflags); + if (O_udqpp) + *O_udqpp = uq; + else if (uq) + xfs_qm_dqrele(uq); + if (O_gdqpp) + *O_gdqpp = gq; + else if (gq) + xfs_qm_dqrele(gq); + return (0); +} + +/* + * Actually transfer ownership, and do dquot modifications. + * These were already reserved. + */ +xfs_dquot_t * +xfs_qm_vop_chown( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dquot_t **IO_olddq, + xfs_dquot_t *newdq) +{ + xfs_dquot_t *prevdq; + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); + + /* old dquot */ + prevdq = *IO_olddq; + ASSERT(prevdq); + ASSERT(prevdq != newdq); + + xfs_trans_mod_dquot(tp, prevdq, + XFS_TRANS_DQ_BCOUNT, + -(ip->i_d.di_nblocks)); + xfs_trans_mod_dquot(tp, prevdq, + XFS_TRANS_DQ_ICOUNT, + -1); + + /* the sparkling new dquot */ + xfs_trans_mod_dquot(tp, newdq, + XFS_TRANS_DQ_BCOUNT, + ip->i_d.di_nblocks); + xfs_trans_mod_dquot(tp, newdq, + XFS_TRANS_DQ_ICOUNT, + 1); + + /* + * Take an extra reference, because the inode + * is going to keep this dquot pointer even + * after the trans_commit. + */ + xfs_dqlock(newdq); + XFS_DQHOLD(newdq); + xfs_dqunlock(newdq); + *IO_olddq = newdq; + + return (prevdq); +} + +/* + * Quota reservations for setattr(AT_UID|AT_GID). + */ +int +xfs_qm_vop_chown_reserve( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dquot_t *udqp, + xfs_dquot_t *gdqp, + uint privileged) +{ + int error; + xfs_mount_t *mp; + uint delblks; + xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq; + + ASSERT(XFS_ISLOCKED_INODE(ip)); + mp = ip->i_mount; + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + delblks = ip->i_delayed_blks; + delblksudq = delblksgdq = unresudq = unresgdq = NULL; + + if (XFS_IS_UQUOTA_ON(mp) && udqp && + ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) { + delblksudq = udqp; + /* + * If there are delayed allocation blocks, then we have to + * unreserve those from the old dquot, and add them to the + * new dquot. + */ + if (delblks) { + ASSERT(ip->i_udquot); + unresudq = ip->i_udquot; + } + } + if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp && + ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) { + delblksgdq = gdqp; + if (delblks) { + ASSERT(ip->i_gdquot); + unresgdq = ip->i_gdquot; + } + } + + if ((error = xfs_trans_reserve_quota(tp, delblksudq, + delblksgdq, + ip->i_d.di_nblocks, 1, + privileged))) + return (error); + + + /* + * Do the delayed blks reservations/unreservations now. Since, these + * are done without the help of a transaction, if a reservation fails + * its previous reservations won't be automatically undone by trans + * code. So, we have to do it manually here. + */ + if (delblks) { + /* + * Do the reservations first. Unreservation can't fail. + */ + ASSERT(delblksudq || delblksgdq); + ASSERT(unresudq || unresgdq); + if ((error = xfs_trans_reserve_quota(NULL, + delblksudq, delblksgdq, + (xfs_qcnt_t)delblks, 0, + privileged))) + return (error); + (void) xfs_trans_unreserve_quota(NULL, + unresudq, unresgdq, + (xfs_qcnt_t)delblks, 0, + 0); + } + + return (0); +} + +int +xfs_qm_vop_rename_dqattach( + xfs_inode_t **i_tab) +{ + xfs_inode_t *ip; + int i; + int error; + + ip = i_tab[0]; + + if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) { + error = xfs_qm_dqattach(ip, 0); + if (error) + return (error); + } + for (i = 1; (i < 4 && i_tab[i]); i++) { + /* + * Watch out for duplicate entries in the table. + */ + if ((ip = i_tab[i]) != i_tab[i-1]) { + if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) { + error = xfs_qm_dqattach(ip, 0); + if (error) + return (error); + } + } + } + return (0); +} + +void +xfs_qm_vop_dqattach_and_dqmod_newinode( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dquot_t *udqp, + xfs_dquot_t *gdqp) +{ + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp)); + + if (udqp) { + xfs_dqlock(udqp); + XFS_DQHOLD(udqp); + xfs_dqunlock(udqp); + ASSERT(ip->i_udquot == NULL); + ip->i_udquot = udqp; + ASSERT(ip->i_d.di_uid == INT_GET(udqp->q_core.d_id, ARCH_CONVERT)); + xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1); + } + if (gdqp) { + xfs_dqlock(gdqp); + XFS_DQHOLD(gdqp); + xfs_dqunlock(gdqp); + ASSERT(ip->i_gdquot == NULL); + ip->i_gdquot = gdqp; + ASSERT(ip->i_d.di_gid == INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)); + xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1); + } +} + +/* ------------- list stuff -----------------*/ +void +xfs_qm_freelist_init(xfs_frlist_t *ql) +{ + ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql; + mutex_init(&ql->qh_lock, MUTEX_DEFAULT, "dqf"); + ql->qh_version = 0; + ql->qh_nelems = 0; +} + +void +xfs_qm_freelist_destroy(xfs_frlist_t *ql) +{ + xfs_dquot_t *dqp, *nextdqp; + + mutex_lock(&ql->qh_lock, PINOD); + for (dqp = ql->qh_next; + dqp != (xfs_dquot_t *)ql; ) { + xfs_dqlock(dqp); + nextdqp = dqp->dq_flnext; +#ifdef QUOTADEBUG + printk("FREELIST destroy 0x%p\n", dqp); +#endif + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + xfs_qm_dqdestroy(dqp); + dqp = nextdqp; + } + /* + * Don't bother about unlocking. + */ + mutex_destroy(&ql->qh_lock); + + ASSERT(ql->qh_nelems == 0); +} + +void +xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq) +{ + dq->dq_flnext = ql->qh_next; + dq->dq_flprev = (xfs_dquot_t *)ql; + ql->qh_next = dq; + dq->dq_flnext->dq_flprev = dq; + xfs_Gqm->qm_dqfreelist.qh_nelems++; + xfs_Gqm->qm_dqfreelist.qh_version++; +} + +void +xfs_qm_freelist_unlink(xfs_dquot_t *dq) +{ + xfs_dquot_t *next = dq->dq_flnext; + xfs_dquot_t *prev = dq->dq_flprev; + + next->dq_flprev = prev; + prev->dq_flnext = next; + dq->dq_flnext = dq->dq_flprev = dq; + xfs_Gqm->qm_dqfreelist.qh_nelems--; + xfs_Gqm->qm_dqfreelist.qh_version++; +} + +#ifdef QUOTADEBUG +void +xfs_qm_freelist_print(xfs_frlist_t *qlist, char *title) +{ + xfs_dquot_t *dq; + int i = 0; + printk("%s (#%d)\n", title, (int) qlist->qh_nelems); + FOREACH_DQUOT_IN_FREELIST(dq, qlist) { + printk("\t%d.\t\"%d (%s:0x%p)\"\t bcnt = %d, icnt = %d " + "refs = %d\n", + ++i, INT_GET(dq->q_core.d_id, ARCH_CONVERT), + DQFLAGTO_TYPESTR(dq), dq, + (int) INT_GET(dq->q_core.d_bcount, ARCH_CONVERT), + (int) INT_GET(dq->q_core.d_icount, ARCH_CONVERT), + (int) dq->q_nrefs); + } +} +#endif + +void +xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq) +{ + xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq); +} + +int +xfs_qm_dqhashlock_nowait( + xfs_dquot_t *dqp) +{ + int locked; + + locked = mutex_trylock(&((dqp)->q_hash->qh_lock)); + return (locked); +} + +int +xfs_qm_freelist_lock_nowait( + xfs_qm_t *xqm) +{ + int locked; + + locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock)); + return (locked); +} + +int +xfs_qm_mplist_nowait( + xfs_mount_t *mp) +{ + int locked; + + ASSERT(mp->m_quotainfo); + locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp))); + return (locked); +} diff -Nur linux-2.4.19/fs/xfs/xfs_qm.h linux-2.4.19-sgi211r3/fs/xfs/xfs_qm.h --- linux-2.4.19/fs/xfs/xfs_qm.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_qm.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_QM_H__ +#define __XFS_QM_H__ + +struct xfs_dqhash; +struct xfs_inode; +struct xfs_dquot; + +extern kmem_zone_t *qm_dqzone; +extern kmem_zone_t *qm_dqtrxzone; + +/* + * Used in xfs_qm_sync called by xfs_sync to count the max times that it can + * iterate over the mountpt's dquot list in one call. + */ +#define XFS_QM_SYNC_MAX_RESTARTS 7 + +/* + * Ditto, for xfs_qm_dqreclaim_one. + */ +#define XFS_QM_RECLAIM_MAX_RESTARTS 4 + +/* + * Ideal ratio of free to in use dquots. Quota manager makes an attempt + * to keep this balance. + */ +#define XFS_QM_DQFREE_RATIO 2 + +/* + * Dquot hashtable constants/threshold values. + */ +#define XFS_QM_NCSIZE_THRESHOLD 5000 +#define XFS_QM_HASHSIZE_LOW 32 +#define XFS_QM_HASHSIZE_HIGH 64 + +/* + * We output a cmn_err when quotachecking a quota file with more than + * this many fsbs. + */ +#define XFS_QM_BIG_QCHECK_NBLKS 500 + +/* + * This defines the unit of allocation of dquots. + * Currently, it is just one file system block, and a 4K blk contains 30 + * (136 * 30 = 4080) dquots. It's probably not worth trying to make + * this more dynamic. + * XXXsup However, if this number is changed, we have to make sure that we don't + * implicitly assume that we do allocations in chunks of a single filesystem + * block in the dquot/xqm code. + */ +#define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 +/* + * When doing a quotacheck, we log dquot clusters of this many FSBs at most + * in a single transaction. We don't want to ask for too huge a log reservation. + */ +#define XFS_QM_MAX_DQCLUSTER_LOGSZ 3 + +typedef xfs_dqhash_t xfs_dqlist_t; +/* + * The freelist head. The first two fields match the first two in the + * xfs_dquot_t structure (in xfs_dqmarker_t) + */ +typedef struct xfs_frlist { + struct xfs_dquot *qh_next; + struct xfs_dquot *qh_prev; + mutex_t qh_lock; + uint qh_version; + uint qh_nelems; +} xfs_frlist_t; + +/* + * Quota Manager (global) structure. Lives only in core. + */ +typedef struct xfs_qm { + xfs_dqlist_t *qm_usr_dqhtable;/* udquot hash table */ + xfs_dqlist_t *qm_grp_dqhtable;/* gdquot hash table */ + uint qm_dqhashmask; /* # buckets in dq hashtab - 1 */ + xfs_frlist_t qm_dqfreelist; /* freelist of dquots */ + atomic_t qm_totaldquots; /* total incore dquots */ + uint qm_nrefs; /* file systems with quota on */ + int qm_dqfree_ratio;/* ratio of free to inuse dquots */ + kmem_zone_t *qm_dqzone; /* dquot mem-alloc zone */ + kmem_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */ +} xfs_qm_t; + +/* + * Various quota information for individual filesystems. + * The mount structure keeps a pointer to this. + */ +typedef struct xfs_quotainfo { + xfs_inode_t *qi_uquotaip; /* user quota inode */ + xfs_inode_t *qi_gquotaip; /* group quota inode */ + lock_t qi_pinlock; /* dquot pinning mutex */ + xfs_dqlist_t qi_dqlist; /* all dquots in filesys */ + int qi_dqreclaims; /* a change here indicates + a removal in the dqlist */ + time_t qi_btimelimit; /* limit for blks timer */ + time_t qi_itimelimit; /* limit for inodes timer */ + time_t qi_rtbtimelimit;/* limit for rt blks timer */ + xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */ + xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */ + mutex_t qi_quotaofflock;/* to serialize quotaoff */ + /* Some useful precalculated constants */ + xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ + uint qi_dqperchunk; /* # ondisk dqs in above chunk */ +} xfs_quotainfo_t; + + +/* + * The structure kept inside the xfs_trans_t keep track of dquot changes + * within a transaction and apply them later. + */ +typedef struct xfs_dqtrx { + struct xfs_dquot *qt_dquot; /* the dquot this refers to */ + ulong qt_blk_res; /* blks reserved on a dquot */ + ulong qt_blk_res_used; /* blks used from the reservation */ + ulong qt_ino_res; /* inode reserved on a dquot */ + ulong qt_ino_res_used; /* inodes used from the reservation */ + long qt_bcount_delta; /* dquot blk count changes */ + long qt_delbcnt_delta; /* delayed dquot blk count changes */ + long qt_icount_delta; /* dquot inode count changes */ + ulong qt_rtblk_res; /* # blks reserved on a dquot */ + ulong qt_rtblk_res_used;/* # blks used from reservation */ + long qt_rtbcount_delta;/* dquot realtime blk changes */ + long qt_delrtb_delta; /* delayed RT blk count changes */ +} xfs_dqtrx_t; + +/* + * We keep the usr and grp dquots separately so that locking will be easier + * to do at commit time. All transactions that we know of at this point + * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value. + */ +#define XFS_QM_TRANS_MAXDQS 2 +typedef struct xfs_dquot_acct { + xfs_dqtrx_t dqa_usrdquots[XFS_QM_TRANS_MAXDQS]; + xfs_dqtrx_t dqa_grpdquots[XFS_QM_TRANS_MAXDQS]; +} xfs_dquot_acct_t; + +/* + * Users are allowed to have a usage exceeding their softlimit for + * a period this long. + */ +#define XFS_QM_BTIMELIMIT DQ_BTIMELIMIT +#define XFS_QM_RTBTIMELIMIT DQ_BTIMELIMIT +#define XFS_QM_ITIMELIMIT DQ_FTIMELIMIT + +#define XFS_QM_BWARNLIMIT 5 +#define XFS_QM_IWARNLIMIT 5 + +#define XFS_QM_LOCK(xqm) (mutex_lock(&xqm##_lock, PINOD)) +#define XFS_QM_UNLOCK(xqm) (mutex_unlock(&xqm##_lock)) +#define XFS_QM_HOLD(xqm) ((xqm)->qm_nrefs++) +#define XFS_QM_RELE(xqm) ((xqm)->qm_nrefs--) + +extern int xfs_qm_init_quotainfo(xfs_mount_t *); +extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); +extern void xfs_qm_dqunlink(xfs_dquot_t *); +extern boolean_t xfs_qm_dqalloc_incore(xfs_dquot_t **); +extern int xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t); + +/* list stuff */ +extern void xfs_qm_freelist_init(xfs_frlist_t *); +extern void xfs_qm_freelist_destroy(xfs_frlist_t *); +extern void xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *); +extern void xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *); +extern void xfs_qm_freelist_unlink(xfs_dquot_t *); +extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *); +extern int xfs_qm_mplist_nowait(xfs_mount_t *); +extern int xfs_qm_dqhashlock_nowait(xfs_dquot_t *); + +/* system call interface */ +extern int linvfs_getxstate(struct super_block *, struct fs_quota_stat *); +extern int linvfs_setxstate(struct super_block *, unsigned int, int); +extern int linvfs_getxquota(struct super_block *, int, qid_t, struct fs_disk_quota *); +extern int linvfs_setxquota(struct super_block *, int, qid_t, struct fs_disk_quota *); + +#ifdef DEBUG +extern int xfs_qm_internalqcheck(xfs_mount_t *); +#else +#define xfs_qm_internalqcheck(mp) (0) +#endif + +#ifdef QUOTADEBUG +extern void xfs_qm_freelist_print(xfs_frlist_t *, char *); +#else +#define xfs_qm_freelist_print(a, b) do { } while (0) +#endif + +#endif /* __XFS_QM_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_qm_syscalls.c linux-2.4.19-sgi211r3/fs/xfs/xfs_qm_syscalls.c --- linux-2.4.19/fs/xfs/xfs_qm_syscalls.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_qm_syscalls.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,1465 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#ifdef DEBUG +# define qdprintk(s, args...) printk(s, ## args) +#else +# define qdprintk(s, args...) do { } while (0) +#endif + +STATIC int xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint); +STATIC int xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint, + fs_disk_quota_t *); +STATIC int xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *); +STATIC int xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint, + fs_disk_quota_t *); +STATIC int xfs_qm_scall_quotaon(xfs_mount_t *, uint); +STATIC int xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t); +STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint); +STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *, + uint); +STATIC uint xfs_qm_import_flags(uint); +STATIC uint xfs_qm_export_flags(uint); +STATIC uint xfs_qm_import_qtype_flags(uint); +STATIC uint xfs_qm_export_qtype_flags(uint); +STATIC void xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *, + fs_disk_quota_t *); + + +int +linvfs_getxstate( + struct super_block *sb, + struct fs_quota_stat *fqs) +{ + xfs_mount_t *mp; + vfs_t *vfsp; + + vfsp = LINVFS_GET_VFS(sb); + mp = XFS_BHVTOM(vfsp->vfs_fbhv); + return -xfs_qm_scall_getqstat(mp, fqs); +} + +int +linvfs_setxstate( + struct super_block *sb, + unsigned int flags, + int op) +{ + xfs_mount_t *mp; + vfs_t *vfsp; + uint qflags; + + vfsp = LINVFS_GET_VFS(sb); + mp = XFS_BHVTOM(vfsp->vfs_fbhv); + if (vfsp->vfs_flag & VFS_RDONLY) + return -EROFS; + + switch (op) { + case Q_XQUOTARM: + if (XFS_IS_QUOTA_ON(mp)) { + qdprintk("cannot remove, quota on: flags=%x\n", flags); + return -EINVAL; + } + qflags = xfs_qm_import_qtype_flags(flags); + return -xfs_qm_scall_trunc_qfiles(mp, qflags); + case Q_XQUOTAON: + qflags = xfs_qm_import_flags(flags); + return -xfs_qm_scall_quotaon(mp, qflags); + case Q_XQUOTAOFF: + qflags = xfs_qm_import_flags(flags); + if (mp->m_dev == rootdev) + return -xfs_qm_scall_quotaoff(mp, qflags, B_FALSE); + if (!XFS_IS_QUOTA_ON(mp)) + return -ESRCH; + return -xfs_qm_scall_quotaoff(mp, qflags, B_FALSE); + } + qdprintk("cannot set state, invalid op: op=%x flags=%x\n", op, flags); + return -EINVAL; +} + +int +linvfs_getxquota( + struct super_block *sb, + int type, + qid_t id, + struct fs_disk_quota *fdq) +{ + xfs_mount_t *mp; + vfs_t *vfsp; + int qtype; + + vfsp = LINVFS_GET_VFS(sb); + mp = XFS_BHVTOM(vfsp->vfs_fbhv); + if (!XFS_IS_QUOTA_ON(mp)) + return -ESRCH; + qtype = (type == GRPQUOTA)? XFS_DQ_GROUP : XFS_DQ_USER; + return -xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, qtype, fdq); +} + +int +linvfs_setxquota( + struct super_block *sb, + int type, + qid_t id, + struct fs_disk_quota *fdq) +{ + xfs_mount_t *mp; + vfs_t *vfsp; + int qtype; + + vfsp = LINVFS_GET_VFS(sb); + mp = XFS_BHVTOM(vfsp->vfs_fbhv); + if (!XFS_IS_QUOTA_ON(mp)) + return -ESRCH; + if (vfsp->vfs_flag & VFS_RDONLY) + return -EROFS; + qtype = (type == GRPQUOTA)? XFS_DQ_GROUP : XFS_DQ_USER; + return xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, qtype, fdq); +} + + +/* + * Turn off quota accounting and/or enforcement for all udquots and/or + * gdquots. Called only at unmount time. + * + * This assumes that there are no dquots of this file system cached + * incore, and modifies the ondisk dquot directly. Therefore, for example, + * it is an error to call this twice, without purging the cache. + */ +STATIC int +xfs_qm_scall_quotaoff( + xfs_mount_t *mp, + uint flags, + boolean_t force) +{ + uint dqtype; + unsigned long s; + int error; + uint inactivate_flags; + xfs_qoff_logitem_t *qoffstart; + uint sbflags, newflags; + int nculprits; + + if (!force && !capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + /* + * Only root file system can have quotas enabled on disk but not + * in core. Note that quota utilities (like quotaoff) _expect_ + * errno == EEXIST here. + */ + if (mp->m_dev != rootdev && (mp->m_qflags & flags) == 0) + return XFS_ERROR(EEXIST); + error = 0; + + flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); + + /* + * We don't want to deal with two quotaoffs messing up each other, + * so we're going to serialize it. quotaoff isn't exactly a performance + * critical thing. + * If quotaoff, then we must be dealing with the root filesystem. + */ + ASSERT(mp->m_quotainfo || mp->m_dev == rootdev); + if (mp->m_quotainfo) + mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); + + /* + * Root file system may or may not have quotas on in core. + * We have to perform the quotaoff accordingly. + */ + if (mp->m_dev == rootdev) { + s = XFS_SB_LOCK(mp); + sbflags = mp->m_sb.sb_qflags; + if ((mp->m_qflags & flags) == 0) { + mp->m_sb.sb_qflags &= ~(flags); + newflags = mp->m_sb.sb_qflags; + XFS_SB_UNLOCK(mp, s); + if (mp->m_quotainfo) + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + if (sbflags != newflags) + error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS); + return (error); + } + XFS_SB_UNLOCK(mp, s); + + if ((sbflags & flags) != (mp->m_qflags & flags)) { + /* + * This can happen only with grp+usr quota + * combination. Note: 1) accounting cannot be turned + * off without enforcement also getting turned off. + * 2) Every flag that exists in mpqflags MUST exist + * in sbqflags (but not vice versa). + * which means at this point sbqflags = UQ+GQ+.., + * and mpqflags = UQ or GQ. + */ + ASSERT(sbflags & XFS_GQUOTA_ACCT); + ASSERT((sbflags & XFS_ALL_QUOTA_ACCT) != + (mp->m_qflags & XFS_ALL_QUOTA_ACCT)); + + qdprintk("quotaoff, sbflags=%x flags=%x m_qflags=%x\n", + sbflags, flags, mp->m_qflags); + /* XXX TBD Finish this for group quota support */ + /* We need to update the SB and mp separately */ + return XFS_ERROR(EINVAL); + } + } + ASSERT(mp->m_quotainfo); + + /* + * if we're just turning off quota enforcement, change mp and go. + */ + if ((flags & XFS_ALL_QUOTA_ACCT) == 0) { + mp->m_qflags &= ~(flags); + + s = XFS_SB_LOCK(mp); + mp->m_sb.sb_qflags = mp->m_qflags; + XFS_SB_UNLOCK(mp, s); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + /* XXX what to do if error ? Revert back to old vals incore ? */ + error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS); + return (error); + } + + dqtype = 0; + inactivate_flags = 0; + /* + * If accounting is off, we must turn enforcement off, clear the + * quota 'CHKD' certificate to make it known that we have to + * do a quotacheck the next time this quota is turned on. + */ + if (flags & XFS_UQUOTA_ACCT) { + dqtype |= XFS_QMOPT_UQUOTA; + flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD); + inactivate_flags |= XFS_UQUOTA_ACTIVE; + } + if (flags & XFS_GQUOTA_ACCT) { + dqtype |= XFS_QMOPT_GQUOTA; + flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD); + inactivate_flags |= XFS_GQUOTA_ACTIVE; + } + + /* + * Nothing to do? Don't complain. + * This happens when we're just turning off quota enforcement. + */ + if ((mp->m_qflags & flags) == 0) { + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + return (0); + } + + /* + * Write the LI_QUOTAOFF log record, and do SB changes atomically, + * and synchronously. + */ + xfs_qm_log_quotaoff(mp, &qoffstart, flags); + + /* + * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct + * to take care of the race between dqget and quotaoff. We don't take + * any special locks to reset these bits. All processes need to check + * these bits *after* taking inode lock(s) to see if the particular + * quota type is in the process of being turned off. If *ACTIVE, it is + * guaranteed that all dquot structures and all quotainode ptrs will all + * stay valid as long as that inode is kept locked. + * + * There is no turning back after this. + */ + mp->m_qflags &= ~inactivate_flags; + + /* + * Give back all the dquot reference(s) held by inodes. + * Here we go thru every single incore inode in this file system, and + * do a dqrele on the i_udquot/i_gdquot that it may have. + * Essentially, as long as somebody has an inode locked, this guarantees + * that quotas will not be turned off. This is handy because in a + * transaction once we lock the inode(s) and check for quotaon, we can + * depend on the quota inodes (and other things) being valid as long as + * we keep the lock(s). + */ + xfs_qm_dqrele_all_inodes(mp, flags); + + /* + * Next we make the changes in the quota flag in the mount struct. + * This isn't protected by a particular lock directly, because we + * don't want to take a mrlock everytime we depend on quotas being on. + */ + mp->m_qflags &= ~(flags); + + /* + * Go through all the dquots of this file system and purge them, + * according to what was turned off. We may not be able to get rid + * of all dquots, because dquots can have temporary references that + * are not attached to inodes. eg. xfs_setattr, xfs_create. + * So, if we couldn't purge all the dquots from the filesystem, + * we can't get rid of the incore data structures. + */ + while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF))) { + delay(10 * nculprits); + } + + /* + * Transactions that had started before ACTIVE state bit was cleared + * could have logged many dquots, so they'd have higher LSNs than + * the first QUOTAOFF log record does. If we happen to crash when + * the tail of the log has gone past the QUOTAOFF record, but + * before the last dquot modification, those dquots __will__ + * recover, and that's not good. + * + * So, we have QUOTAOFF start and end logitems; the start + * logitem won't get overwritten until the end logitem appears... + */ + xfs_qm_log_quotaoff_end(mp, qoffstart, flags); + + /* + * If quotas is completely disabled, close shop. + */ + if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) { + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + xfs_qm_destroy_quotainfo(mp); + return (0); + } + + /* + * Release our quotainode references, and vn_purge them, + * if we don't need them anymore. + */ + if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) { + XFS_PURGE_INODE(XFS_QI_UQIP(mp)); + XFS_QI_UQIP(mp) = NULL; + } + if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) { + XFS_PURGE_INODE(XFS_QI_GQIP(mp)); + XFS_QI_GQIP(mp) = NULL; + } + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + return (error); +} + +STATIC int +xfs_qm_scall_trunc_qfiles( + xfs_mount_t *mp, + uint flags) +{ + int error; + xfs_inode_t *qip; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + error = 0; + if (!XFS_SB_VERSION_HASQUOTA(&mp->m_sb) || flags == 0) { + qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags); + return XFS_ERROR(EINVAL); + } + + if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) { + error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0); + if (! error) { + (void) xfs_truncate_file(mp, qip); + VN_RELE(XFS_ITOV(qip)); + } + } + + if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) { + error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0); + if (! error) { + (void) xfs_truncate_file(mp, qip); + VN_RELE(XFS_ITOV(qip)); + } + } + + return (error); +} + + +/* + * This does two separate functions: + * Switch on quotas for the root file system. This will take effect only + * on reboot. + * Switch on (a given) quota enforcement for both root and non-root filesystems. + * This takes effect immediately. + */ +STATIC int +xfs_qm_scall_quotaon( + xfs_mount_t *mp, + uint flags) +{ + int error; + unsigned long s; + uint qf; + uint accflags; + __int64_t sbflags; + boolean_t rootfs; + boolean_t delay; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + + rootfs = (boolean_t) (mp->m_dev == rootdev); + + flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); + /* + * If caller wants to turn on accounting on /, but accounting + * is already turned on, ignore ACCTing flags. + * Switching on quota accounting for non-root filesystems + * must be done at mount time. + */ + accflags = flags & XFS_ALL_QUOTA_ACCT; + if (!rootfs || + (accflags && rootfs && ((mp->m_qflags & accflags) == accflags))) { + flags &= ~(XFS_ALL_QUOTA_ACCT); + } + + sbflags = 0; + delay = (boolean_t) ((flags & XFS_ALL_QUOTA_ACCT) != 0); + + if (flags == 0) { + qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags); + return XFS_ERROR(EINVAL); + } + + /* Only rootfs can turn on quotas with a delayed effect */ + ASSERT(!delay || rootfs); + + /* + * Can't enforce without accounting. We check the superblock + * qflags here instead of m_qflags because rootfs can have + * quota acct on ondisk without m_qflags' knowing. + */ + if (((flags & XFS_UQUOTA_ACCT) == 0 && + (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 && + (flags & XFS_UQUOTA_ENFD)) + || + ((flags & XFS_GQUOTA_ACCT) == 0 && + (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 && + (flags & XFS_GQUOTA_ENFD))) { + qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n", + flags, mp->m_sb.sb_qflags); + return XFS_ERROR(EINVAL); + } + /* + * If everything's upto-date incore, then don't waste time. + */ + if ((mp->m_qflags & flags) == flags) + return XFS_ERROR(EEXIST); + + /* + * Change superblock version (if needed) for the root filesystem + */ + if (rootfs && !XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) { + qdprintk("Old superblock version %x\n", mp->m_sb.sb_versionnum); + s = XFS_SB_LOCK(mp); + XFS_SB_VERSION_ADDQUOTA(&mp->m_sb); + mp->m_sb.sb_uquotino = NULLFSINO; + mp->m_sb.sb_gquotino = NULLFSINO; + mp->m_sb.sb_qflags = 0; + XFS_SB_UNLOCK(mp, s); + qdprintk("Converted to version %x\n", mp->m_sb.sb_versionnum); + sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS); + } + + /* + * Change sb_qflags on disk but not incore mp->qflags + * if this is the root filesystem. + */ + s = XFS_SB_LOCK(mp); + qf = mp->m_sb.sb_qflags; + mp->m_sb.sb_qflags = qf | flags; + XFS_SB_UNLOCK(mp, s); + + /* + * There's nothing to change if it's the same. + */ + if ((qf & flags) == flags && sbflags == 0) + return XFS_ERROR(EEXIST); + sbflags |= XFS_SB_QFLAGS; + + if ((error = xfs_qm_write_sb_changes(mp, sbflags))) + return (error); + /* + * If we had just turned on quotas (ondisk) for rootfs, or if we aren't + * trying to switch on quota enforcement, we are done. + */ + if (delay || + ((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) != + (mp->m_qflags & XFS_UQUOTA_ACCT)) || + (flags & XFS_ALL_QUOTA_ENFD) == 0) + return (0); + + if (! XFS_IS_QUOTA_RUNNING(mp)) + return XFS_ERROR(ESRCH); + + /* + * Switch on quota enforcement in core. This applies to both root + * and non-root file systems. + */ + mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); + mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + return (0); +} + + + +/* + * Return quota status information, such as uquota-off, enforcements, etc. + */ +STATIC int +xfs_qm_scall_getqstat( + xfs_mount_t *mp, + fs_quota_stat_t *out) +{ + xfs_inode_t *uip, *gip; + boolean_t tempuqip, tempgqip; + __uint16_t sbflags; + + uip = gip = NULL; + tempuqip = tempgqip = B_FALSE; + bzero(out, sizeof(fs_quota_stat_t)); + + out->qs_version = FS_QSTAT_VERSION; + if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) { + out->qs_uquota.qfs_ino = NULLFSINO; + out->qs_gquota.qfs_ino = NULLFSINO; + return (0); + } + out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & + (XFS_ALL_QUOTA_ACCT| + XFS_ALL_QUOTA_ENFD)); + /* + * If the qflags are different on disk, as can be the case when + * root filesystem's quotas are being turned on, return them in the + * HI 8 bits. + */ + if (mp->m_dev == rootdev) { + sbflags = (__uint16_t) xfs_qm_export_flags(mp->m_sb.sb_qflags & + (XFS_ALL_QUOTA_ACCT| + XFS_ALL_QUOTA_ENFD)); + ASSERT((out->qs_flags & 0xff00) == 0); + if (sbflags != out->qs_flags) + out->qs_flags |= ((sbflags & 0x00ff) << 8); + } + + out->qs_pad = 0; + out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; + out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; + if (mp->m_quotainfo) { + uip = mp->m_quotainfo->qi_uquotaip; + gip = mp->m_quotainfo->qi_gquotaip; + } + if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { + if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0) + tempuqip = B_TRUE; + } + if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { + if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0) + tempgqip = B_TRUE; + } + if (uip) { + out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks; + out->qs_uquota.qfs_nextents = uip->i_d.di_nextents; + if (tempuqip) + VN_RELE(XFS_ITOV(uip)); + } + if (gip) { + out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks; + out->qs_gquota.qfs_nextents = gip->i_d.di_nextents; + if (tempgqip) + VN_RELE(XFS_ITOV(gip)); + } + if (mp->m_quotainfo) { + out->qs_incoredqs = XFS_QI_MPLNDQUOTS(mp); + out->qs_btimelimit = XFS_QI_BTIMELIMIT(mp); + out->qs_itimelimit = XFS_QI_ITIMELIMIT(mp); + out->qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp); + out->qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp); + out->qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp); + } + return (0); +} + +/* + * Adjust quota limits, and start/stop timers accordingly. + */ +STATIC int +xfs_qm_scall_setqlim( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + fs_disk_quota_t *newlim) +{ + xfs_disk_dquot_t *ddq; + xfs_dquot_t *dqp; + xfs_trans_t *tp; + int error; + xfs_qcnt_t hard, soft; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + + if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0) + return (0); + + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); + if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128, + 0, 0, XFS_DEFAULT_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + + /* + * We don't want to race with a quotaoff so take the quotaoff lock. + * (We don't hold an inode lock, so there's nothing else to stop + * a quotaoff from happening). (XXXThis doesn't currently happen + * because we take the vfslock before calling xfs_qm_sysent). + */ + mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); + + /* + * Get the dquot (locked), and join it to the transaction. + * Allocate the dquot if this doesn't exist. + */ + if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) { + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + ASSERT(error != ENOENT); + return (error); + } + xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET"); + xfs_trans_dqjoin(tp, dqp); + ddq = &dqp->q_core; + + /* + * Make sure that hardlimits are >= soft limits before changing. + */ + hard = (newlim->d_fieldmask & FS_DQ_BHARD) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) : + INT_GET(ddq->d_blk_hardlimit, ARCH_CONVERT); + soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) : + INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT); + if (hard == 0 || hard >= soft) { + INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard); + INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft); + } + else { + qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft); + } + hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) : + INT_GET(ddq->d_rtb_hardlimit, ARCH_CONVERT); + soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) : + INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT); + if (hard == 0 || hard >= soft) { + INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard); + INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft); + } + else + qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft); + + hard = (newlim->d_fieldmask & FS_DQ_IHARD) ? + (xfs_qcnt_t) newlim->d_ino_hardlimit : + INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT); + soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ? + (xfs_qcnt_t) newlim->d_ino_softlimit : + INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT); + if (hard == 0 || hard >= soft) { + INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard); + INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft); + } + else + qdprintk("ihard %Ld < isoft %Ld\n", hard, soft); + + if (id == 0) { + /* + * Timelimits for the super user set the relative time + * the other users can be over quota for this file system. + * If it is zero a default is used. + */ + if (newlim->d_fieldmask & FS_DQ_BTIMER) { + mp->m_quotainfo->qi_btimelimit = newlim->d_btimer; + INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim->d_btimer); + } + if (newlim->d_fieldmask & FS_DQ_ITIMER) { + mp->m_quotainfo->qi_itimelimit = newlim->d_itimer; + INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim->d_itimer); + } + if (newlim->d_fieldmask & FS_DQ_RTBTIMER) { + mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer; + INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer); + } + } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ { + /* + * If the user is now over quota, start the timelimit. + * The user will not be 'warned'. + * Note that we keep the timers ticking, whether enforcement + * is on or off. We don't really want to bother with iterating + * over all ondisk dquots and turning the timers on/off. + */ + xfs_qm_adjust_dqtimers(mp, ddq); + } + dqp->dq_flags |= XFS_DQ_DIRTY; + xfs_trans_log_dquot(tp, dqp); + + xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT"); + xfs_trans_commit(tp, 0, NULL); + xfs_qm_dqprint(dqp); + xfs_qm_dqrele(dqp); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + return (0); +} + +STATIC int +xfs_qm_scall_getquota( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + fs_disk_quota_t *out) +{ + xfs_dquot_t *dqp; + int error; + + /* + * Try to get the dquot. We don't want it allocated on disk, so + * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't + * exist, we'll get ENOENT back. + */ + if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) { + return (error); + } + + xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS"); + /* + * If everything's NULL, this dquot doesn't quite exist as far as + * our utility programs are concerned. + */ + if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) { + xfs_qm_dqput(dqp); + return XFS_ERROR(ENOENT); + } + /* xfs_qm_dqprint(dqp); */ + /* + * Convert the disk dquot to the exportable format + */ + xfs_qm_export_dquot(mp, &dqp->q_core, out); + xfs_qm_dqput(dqp); + return (error ? XFS_ERROR(EFAULT) : 0); +} + + +STATIC int +xfs_qm_log_quotaoff_end( + xfs_mount_t *mp, + xfs_qoff_logitem_t *startqoff, + uint flags) +{ + xfs_trans_t *tp; + int error; + xfs_qoff_logitem_t *qoffi; + + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); + + if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2, + 0, 0, XFS_DEFAULT_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + + qoffi = xfs_trans_get_qoff_item(tp, startqoff, + flags & XFS_ALL_QUOTA_ACCT); + xfs_trans_log_quotaoff_item(tp, qoffi); + + /* + * We have to make sure that the transaction is secure on disk before we + * return and actually stop quota accounting. So, make it synchronous. + * We don't care about quotoff's performance. + */ + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + return (error); +} + + +STATIC int +xfs_qm_log_quotaoff( + xfs_mount_t *mp, + xfs_qoff_logitem_t **qoffstartp, + uint flags) +{ + xfs_trans_t *tp; + int error; + unsigned long s; + xfs_qoff_logitem_t *qoffi=NULL; + uint oldsbqflag=0; + + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF); + if ((error = xfs_trans_reserve(tp, 0, + sizeof(xfs_qoff_logitem_t) * 2 + + mp->m_sb.sb_sectsize + 128, + 0, + 0, + XFS_DEFAULT_LOG_COUNT))) { + goto error0; + } + + qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT); + xfs_trans_log_quotaoff_item(tp, qoffi); + + s = XFS_SB_LOCK(mp); + oldsbqflag = mp->m_sb.sb_qflags; + mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; + XFS_SB_UNLOCK(mp, s); + + xfs_mod_sb(tp, XFS_SB_QFLAGS); + + /* + * We have to make sure that the transaction is secure on disk before we + * return and actually stop quota accounting. So, make it synchronous. + * We don't care about quotoff's performance. + */ + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + +error0: + if (error) { + xfs_trans_cancel(tp, 0); + /* + * No one else is modifying sb_qflags, so this is OK. + * We still hold the quotaofflock. + */ + s = XFS_SB_LOCK(mp); + mp->m_sb.sb_qflags = oldsbqflag; + XFS_SB_UNLOCK(mp, s); + } + *qoffstartp = qoffi; + return (error); +} + + +/* + * Translate an internal style on-disk-dquot to the exportable format. + * The main differences are that the counters/limits are all in Basic + * Blocks (BBs) instead of the internal FSBs, and all on-disk data has + * to be converted to the native endianness. + */ +STATIC void +xfs_qm_export_dquot( + xfs_mount_t *mp, + xfs_disk_dquot_t *src, + struct fs_disk_quota *dst) +{ + bzero(dst, sizeof(*dst)); + dst->d_version = FS_DQUOT_VERSION; /* different from src->d_version */ + dst->d_flags = + xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT)); + dst->d_id = INT_GET(src->d_id, ARCH_CONVERT); + dst->d_blk_hardlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT)); + dst->d_blk_softlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT)); + dst->d_ino_hardlimit = (__uint64_t) + INT_GET(src->d_ino_hardlimit, ARCH_CONVERT); + dst->d_ino_softlimit = (__uint64_t) + INT_GET(src->d_ino_softlimit, ARCH_CONVERT); + dst->d_bcount = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT)); + dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT); + dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT); + dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT); + dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT); + dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT); + + dst->d_rtb_hardlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT)); + dst->d_rtb_softlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT)); + dst->d_rtbcount = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT)); + dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT); + dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT); + + /* + * Internally, we don't reset all the timers when quota enforcement + * gets turned off. No need to confuse the userlevel code, + * so return zeroes in that case. + */ + if (! XFS_IS_QUOTA_ENFORCED(mp)) { + dst->d_btimer = 0; + dst->d_itimer = 0; + dst->d_rtbtimer = 0; + } + +#ifdef DEBUG + if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) { + if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) && + (dst->d_blk_softlimit > 0)) { + ASSERT(dst->d_btimer != 0); + } + if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) && + (dst->d_ino_softlimit > 0)) { + ASSERT(dst->d_itimer != 0); + } + } +#endif +} + +STATIC uint +xfs_qm_import_qtype_flags( + uint uflags) +{ + /* + * Can't be both at the same time. + */ + if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == + (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) || + ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0)) + return (0); + + return (uflags & XFS_USER_QUOTA) ? + XFS_DQ_USER : XFS_DQ_GROUP; +} + +STATIC uint +xfs_qm_export_qtype_flags( + uint flags) +{ + /* + * Can't be both at the same time. + */ + ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != + (XFS_GROUP_QUOTA | XFS_USER_QUOTA)); + ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0); + + return (flags & XFS_DQ_USER) ? + XFS_USER_QUOTA : XFS_GROUP_QUOTA; +} + +STATIC uint +xfs_qm_import_flags( + uint uflags) +{ + uint flags = 0; + + if (uflags & XFS_QUOTA_UDQ_ACCT) + flags |= XFS_UQUOTA_ACCT; + if (uflags & XFS_QUOTA_GDQ_ACCT) + flags |= XFS_GQUOTA_ACCT; + if (uflags & XFS_QUOTA_UDQ_ENFD) + flags |= XFS_UQUOTA_ENFD; + if (uflags & XFS_QUOTA_GDQ_ENFD) + flags |= XFS_GQUOTA_ENFD; + return (flags); +} + + +STATIC uint +xfs_qm_export_flags( + uint flags) +{ + uint uflags; + + uflags = 0; + if (flags & XFS_UQUOTA_ACCT) + uflags |= XFS_QUOTA_UDQ_ACCT; + if (flags & XFS_GQUOTA_ACCT) + uflags |= XFS_QUOTA_GDQ_ACCT; + if (flags & XFS_UQUOTA_ENFD) + uflags |= XFS_QUOTA_UDQ_ENFD; + if (flags & XFS_GQUOTA_ENFD) + uflags |= XFS_QUOTA_GDQ_ENFD; + return (uflags); +} + + +/* + * Go thru all the inodes in the file system, releasing their dquots. + * Note that the mount structure gets modified to indicate that quotas are off + * AFTER this, in the case of quotaoff. This also gets called from + * xfs_rootumount. + */ +void +xfs_qm_dqrele_all_inodes( + struct xfs_mount *mp, + uint flags) +{ + vmap_t vmap; + xfs_inode_t *ip, *topino; + uint ireclaims; + vnode_t *vp; + boolean_t vnode_refd; + + ASSERT(mp->m_quotainfo); + +again: + XFS_MOUNT_ILOCK(mp); + ip = mp->m_inodes; + if (ip == NULL) { + XFS_MOUNT_IUNLOCK(mp); + return; + } + do { + /* Skip markers inserted by xfs_sync */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + /* Root inode, rbmip and rsumip have associated blocks */ + if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) { + ASSERT(ip->i_udquot == NULL); + ASSERT(ip->i_gdquot == NULL); + ip = ip->i_mnext; + continue; + } + vp = XFS_ITOV_NULL(ip); + if (!vp) { + ASSERT(ip->i_udquot == NULL); + ASSERT(ip->i_gdquot == NULL); + ip = ip->i_mnext; + continue; + } + vnode_refd = B_FALSE; + if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) { + /* + * Sample vp mapping while holding the mplock, lest + * we come across a non-existent vnode. + */ + VMAP(vp, ip, vmap); + ireclaims = mp->m_ireclaims; + topino = mp->m_inodes; + XFS_MOUNT_IUNLOCK(mp); + + /* XXX restart limit ? */ + if ( ! (vp = vn_get(vp, &vmap))) + goto again; + xfs_ilock(ip, XFS_ILOCK_EXCL); + vnode_refd = B_TRUE; + } else { + ireclaims = mp->m_ireclaims; + topino = mp->m_inodes; + XFS_MOUNT_IUNLOCK(mp); + } + + /* + * We don't keep the mountlock across the dqrele() call, + * since it can take a while.. + */ + if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) { + xfs_qm_dqrele(ip->i_udquot); + ip->i_udquot = NULL; + } + if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) { + xfs_qm_dqrele(ip->i_gdquot); + ip->i_gdquot = NULL; + } + xfs_iunlock(ip, XFS_ILOCK_EXCL); + /* + * Wait until we've dropped the ilock and mountlock to + * do the vn_rele. Or be condemned to an eternity in the + * inactive code in hell. + */ + if (vnode_refd) + VN_RELE(vp); + XFS_MOUNT_ILOCK(mp); + /* + * If an inode was inserted or removed, we gotta + * start over again. + */ + if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) { + /* XXX use a sentinel */ + XFS_MOUNT_IUNLOCK(mp); + goto again; + } + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + + XFS_MOUNT_IUNLOCK(mp); +} + +/*------------------------------------------------------------------------*/ +#ifdef DEBUG +/* + * This contains all the test functions for XFS disk quotas. + * Currently it does a quota accounting check. ie. it walks through + * all inodes in the file system, calculating the dquot accounting fields, + * and prints out any inconsistencies. + */ +xfs_dqhash_t *qmtest_udqtab; +xfs_dqhash_t *qmtest_gdqtab; +int qmtest_hashmask; +int qmtest_nfails; +mutex_t qcheck_lock; + +#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \ + (__psunsigned_t)(id)) & \ + (qmtest_hashmask - 1)) + +#define DQTEST_HASH(mp, id, type) ((type & XFS_DQ_USER) ? \ + (qmtest_udqtab + \ + DQTEST_HASHVAL(mp, id)) : \ + (qmtest_gdqtab + \ + DQTEST_HASHVAL(mp, id))) + +#define DQTEST_LIST_PRINT(l, NXT, title) \ +{ \ + xfs_dqtest_t *dqp; int i = 0;\ + printk("%s (#%d)\n", title, (int) (l)->qh_nelems); \ + for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \ + dqp = (xfs_dqtest_t *)dqp->NXT) { \ + printk("\t%d\.\t\"%d (%s)\"\t bcnt = %d, icnt = %d\n", \ + ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp), \ + dqp->d_bcount, dqp->d_icount); } \ +} + +typedef struct dqtest { + xfs_dqmarker_t q_lists; + xfs_dqhash_t *q_hash; /* the hashchain header */ + xfs_mount_t *q_mount; /* filesystem this relates to */ + xfs_dqid_t d_id; /* user id or group id */ + xfs_qcnt_t d_bcount; /* # disk blocks owned by the user */ + xfs_qcnt_t d_icount; /* # inodes owned by the user */ +} xfs_dqtest_t; + +STATIC void +xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp) +{ + xfs_dquot_t *d; + if (((d) = (h)->qh_next)) + (d)->HL_PREVP = &((dqp)->HL_NEXT); + (dqp)->HL_NEXT = d; + (dqp)->HL_PREVP = &((h)->qh_next); + (h)->qh_next = (xfs_dquot_t *)dqp; + (h)->qh_version++; + (h)->qh_nelems++; +} +STATIC void +xfs_qm_dqtest_print( + xfs_dqtest_t *d) +{ + printk("-----------DQTEST DQUOT----------------\n"); + printk("---- dquot ID = %d\n", d->d_id); + printk("---- type = %s\n", XFS_QM_ISUDQ(d) ? "USR" : "GRP"); + printk("---- fs = 0x%p\n", d->q_mount); + printk("---- bcount = %Lu (0x%x)\n", d->d_bcount, (int)d->d_bcount); + printk("---- icount = %Lu (0x%x)\n", d->d_icount, (int)d->d_icount); + printk("---------------------------\n"); +} + +STATIC void +xfs_qm_dqtest_failed( + xfs_dqtest_t *d, + xfs_dquot_t *dqp, + char *reason, + xfs_qcnt_t a, + xfs_qcnt_t b, + int error) +{ + qmtest_nfails++; + if (error) + printk("quotacheck failed for %d, error = %d\nreason = %s\n", + INT_GET(d->d_id, ARCH_CONVERT), error, reason); + else + printk("quotacheck failed for %d (%s) [%d != %d]\n", + INT_GET(d->d_id, ARCH_CONVERT), reason, (int)a, (int)b); + xfs_qm_dqtest_print(d); + if (dqp) + xfs_qm_dqprint(dqp); +} + +STATIC int +xfs_dqtest_cmp2( + xfs_dqtest_t *d, + xfs_dquot_t *dqp) +{ + int err = 0; + if (INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) != d->d_icount) { + xfs_qm_dqtest_failed(d, dqp, "icount mismatch", + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), d->d_icount, 0); + err++; + } + if (INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) != d->d_bcount) { + xfs_qm_dqtest_failed(d, dqp, "bcount mismatch", + INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), d->d_bcount, 0); + err++; + } + if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && + INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) { + if (INT_ISZERO(dqp->q_core.d_btimer, ARCH_CONVERT) && + !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) { + printk("%d [%s] [0x%p] BLK TIMER NOT STARTED\n", + d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); + err++; + } + } + if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) { + if (INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) && + !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) { + printk("%d [%s] [0x%p] INO TIMER NOT STARTED\n", + d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); + err++; + } + } +#if 0 + if (!err) { + printk("%d [%s] [0x%p] qchecked\n", + d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount); + } +#endif + return (err); +} + +STATIC void +xfs_dqtest_cmp( + xfs_dqtest_t *d) +{ + xfs_dquot_t *dqp; + int error; + + /* xfs_qm_dqtest_print(d); */ + if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0, + &dqp))) { + xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error); + return; + } + xfs_dqtest_cmp2(d, dqp); + xfs_qm_dqput(dqp); +} + +STATIC int +xfs_qm_internalqcheck_dqget( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + xfs_dqtest_t **O_dq) +{ + xfs_dqtest_t *d; + xfs_dqhash_t *h; + + h = DQTEST_HASH(mp, id, type); + for (d = (xfs_dqtest_t *) h->qh_next; d != NULL; + d = (xfs_dqtest_t *) d->HL_NEXT) { + /* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */ + if (d->d_id == id && mp == d->q_mount) { + *O_dq = d; + return (0); + } + } + d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP); + d->dq_flags = type; + d->d_id = id; + d->q_mount = mp; + d->q_hash = h; + xfs_qm_hashinsert(h, d); + *O_dq = d; + return (0); +} + +STATIC void +xfs_qm_internalqcheck_get_dquots( + xfs_mount_t *mp, + xfs_dqid_t uid, + xfs_dqid_t gid, + xfs_dqtest_t **ud, + xfs_dqtest_t **gd) +{ + if (XFS_IS_UQUOTA_ON(mp)) + xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud); + if (XFS_IS_GQUOTA_ON(mp)) + xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd); +} + + +STATIC void +xfs_qm_internalqcheck_dqadjust( + xfs_inode_t *ip, + xfs_dqtest_t *d) +{ + d->d_icount++; + d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks; +} + +STATIC int +xfs_qm_internalqcheck_adjust( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* not used */ + xfs_daddr_t bno, /* starting block of inode cluster */ + void *dip, /* not used */ + int *res) /* bulkstat result code */ +{ + xfs_inode_t *ip; + xfs_dqtest_t *ud, *gd; + uint lock_flags; + boolean_t ipreleased; + int error; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) { + *res = BULKSTAT_RV_NOTHING; + qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n", + (unsigned long long) ino, + (unsigned long long) mp->m_sb.sb_uquotino, + (unsigned long long) mp->m_sb.sb_gquotino); + return XFS_ERROR(EINVAL); + } + ipreleased = B_FALSE; + again: + lock_flags = XFS_ILOCK_SHARED; + if ((error = xfs_iget(mp, tp, ino, lock_flags, &ip, bno))) { + *res = BULKSTAT_RV_NOTHING; + return (error); + } + + if (ip->i_d.di_mode == 0) { + xfs_iput_new(ip, lock_flags); + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + + /* + * This inode can have blocks after eof which can get released + * when we send it to inactive. Since we don't check the dquot + * until the after all our calculations are done, we must get rid + * of those now. + */ + if (! ipreleased) { + xfs_iput(ip, lock_flags); + ipreleased = B_TRUE; + goto again; + } + xfs_qm_internalqcheck_get_dquots(mp, + (xfs_dqid_t) ip->i_d.di_uid, + (xfs_dqid_t) ip->i_d.di_gid, + &ud, &gd); + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(ud); + xfs_qm_internalqcheck_dqadjust(ip, ud); + } + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(gd); + xfs_qm_internalqcheck_dqadjust(ip, gd); + } + xfs_iput(ip, lock_flags); + *res = BULKSTAT_RV_DIDONE; + return (0); +} + + +/* PRIVATE, debugging */ +int +xfs_qm_internalqcheck( + xfs_mount_t *mp) +{ + xfs_ino_t lastino; + int done, count; + int i; + xfs_dqtest_t *d, *e; + xfs_dqhash_t *h1; + int error; + + lastino = 0; + qmtest_hashmask = 32; + count = 5; + done = 0; + qmtest_nfails = 0; + + if (! XFS_IS_QUOTA_ON(mp)) + return XFS_ERROR(ESRCH); + + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targp); + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targp); + + mutex_lock(&qcheck_lock, PINOD); + /* There should be absolutely no quota activity while this + is going on. */ + qmtest_udqtab = kmem_zalloc(qmtest_hashmask * + sizeof(xfs_dqhash_t), KM_SLEEP); + qmtest_gdqtab = kmem_zalloc(qmtest_hashmask * + sizeof(xfs_dqhash_t), KM_SLEEP); + do { + /* + * Iterate thru all the inodes in the file system, + * adjusting the corresponding dquot counters + */ + if ((error = xfs_bulkstat(mp, NULL, &lastino, &count, + xfs_qm_internalqcheck_adjust, + 0, NULL, BULKSTAT_FG_IGET, &done))) { + break; + } + } while (! done); + if (error) { + printk("Bulkstat returned error 0x%x\n", + error); + } + printk("Checking results against system dquots\n"); + for (i = 0; i < qmtest_hashmask; i++) { + h1 = &qmtest_udqtab[i]; + for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { + xfs_dqtest_cmp(d); + e = (xfs_dqtest_t *) d->HL_NEXT; + kmem_free(d, sizeof(xfs_dqtest_t)); + d = e; + } + h1 = &qmtest_gdqtab[i]; + for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { + xfs_dqtest_cmp(d); + e = (xfs_dqtest_t *) d->HL_NEXT; + kmem_free(d, sizeof(xfs_dqtest_t)); + d = e; + } + } + + if (qmtest_nfails) { + printk("************** quotacheck failed **************\n"); + printk("failures = %d\n", qmtest_nfails); + } else { + printk("************** quotacheck successful! **************\n"); + } + kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); + kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); + mutex_unlock(&qcheck_lock); + return (qmtest_nfails); +} + +#endif /* DEBUG */ diff -Nur linux-2.4.19/fs/xfs/xfs_quota.h linux-2.4.19-sgi211r3/fs/xfs/xfs_quota.h --- linux-2.4.19/fs/xfs/xfs_quota.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_quota.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_QUOTA_H__ +#define __XFS_QUOTA_H__ + +/* + * uid_t and gid_t are hard-coded to 32 bits in the inode. + * Hence, an 'id' in a dquot is 32 bits.. + */ +typedef __int32_t xfs_dqid_t; + +/* + * Eventhough users may not have quota limits occupying all 64-bits, + * they may need 64-bit accounting. Hence, 64-bit quota-counters, + * and quota-limits. This is a waste in the common case, but hey ... + */ +typedef __uint64_t xfs_qcnt_t; +typedef __uint16_t xfs_qwarncnt_t; + +/* + * Disk quotas status in m_qflags, and also sb_qflags. 16 bits. + */ +#define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ +#define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ +#define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ +#define XFS_PQUOTA_ACCT 0x0008 /* (IRIX) project quota accounting ON */ +#define XFS_GQUOTA_ENFD 0x0010 /* group quota limits enforced */ +#define XFS_GQUOTA_CHKD 0x0020 /* quotacheck run on grp quotas */ +#define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ + +/* + * Incore only flags for quotaoff - these bits get cleared when quota(s) + * are in the process of getting turned off. These flags are in m_qflags but + * never in sb_qflags. + */ +#define XFS_UQUOTA_ACTIVE 0x0080 /* uquotas are being turned off */ +#define XFS_GQUOTA_ACTIVE 0x0100 /* gquotas are being turned off */ + +/* + * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees + * quota will be not be switched off as long as that inode lock is held. + */ +#define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ + XFS_GQUOTA_ACTIVE)) +#define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) +#define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) + +/* + * Flags to tell various functions what to do. Not all of these are meaningful + * to a single function. None of these XFS_QMOPT_* flags are meant to have + * persistent values (ie. their values can and will change between versions) + */ +#define XFS_QMOPT_DQLOCK 0x0000001 /* dqlock */ +#define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ +#define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ +#define XFS_QMOPT_GQUOTA 0x0000008 /* group dquot requested */ +#define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ +#define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */ +#define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ +#define XFS_QMOPT_QUOTAOFF 0x0000080 /* quotas are being turned off */ +#define XFS_QMOPT_UMOUNTING 0x0000100 /* filesys is being unmounted */ +#define XFS_QMOPT_DOLOG 0x0000200 /* log buf changes (in quotacheck) */ +#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */ +#define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */ +#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */ + +/* + * flags to xfs_trans_mod_dquot to indicate which field needs to be + * modified. + */ +#define XFS_QMOPT_RES_REGBLKS 0x0010000 +#define XFS_QMOPT_RES_RTBLKS 0x0020000 +#define XFS_QMOPT_BCOUNT 0x0040000 +#define XFS_QMOPT_ICOUNT 0x0080000 +#define XFS_QMOPT_RTBCOUNT 0x0100000 +#define XFS_QMOPT_DELBCOUNT 0x0200000 +#define XFS_QMOPT_DELRTBCOUNT 0x0400000 +#define XFS_QMOPT_RES_INOS 0x0800000 + +/* + * flags for dqflush and dqflush_all. + */ +#define XFS_QMOPT_SYNC 0x1000000 +#define XFS_QMOPT_ASYNC 0x2000000 +#define XFS_QMOPT_DELWRI 0x4000000 + +/* + * flags for dqalloc. + */ +#define XFS_QMOPT_INHERIT 0x8000000 + +/* + * flags to xfs_trans_mod_dquot. + */ +#define XFS_TRANS_DQ_RES_BLKS XFS_QMOPT_RES_REGBLKS +#define XFS_TRANS_DQ_RES_RTBLKS XFS_QMOPT_RES_RTBLKS +#define XFS_TRANS_DQ_RES_INOS XFS_QMOPT_RES_INOS +#define XFS_TRANS_DQ_BCOUNT XFS_QMOPT_BCOUNT +#define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT +#define XFS_TRANS_DQ_ICOUNT XFS_QMOPT_ICOUNT +#define XFS_TRANS_DQ_RTBCOUNT XFS_QMOPT_RTBCOUNT +#define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT + + +#define XFS_QMOPT_QUOTALL (XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA) +#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) + +/* + * This check is done typically without holding the inode lock; + * that may seem racey, but it is harmless in the context that it is used. + * The inode cannot go inactive as long a reference is kept, and + * therefore if dquot(s) were attached, they'll stay consistent. + * If, for example, the ownership of the inode changes while + * we didnt have the inode locked, the appropriate dquot(s) will be + * attached atomically. + */ +#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\ + (ip)->i_udquot == NULL) || \ + (XFS_IS_GQUOTA_ON(mp) && \ + (ip)->i_gdquot == NULL)) + +#define XFS_QM_NEED_QUOTACHECK(mp) ((XFS_IS_UQUOTA_ON(mp) && \ + (mp->m_sb.sb_qflags & \ + XFS_UQUOTA_CHKD) == 0) || \ + (XFS_IS_GQUOTA_ON(mp) && \ + (mp->m_sb.sb_qflags & \ + XFS_GQUOTA_CHKD) == 0)) + +#define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ + XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ + XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD) +#define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \ + XFS_GQUOTA_ACTIVE) + +#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) + + +#ifdef __KERNEL__ + +#ifdef CONFIG_XFS_QUOTA +/* + * External Interface to the XFS disk quota subsystem. + */ +struct xfs_disk_dquot; +struct xfs_dqhash; +struct xfs_dquot; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Quota Manager Interface. + */ +extern struct xfs_qm *xfs_qm_init(void); +extern void xfs_qm_destroy(struct xfs_qm *); +extern int xfs_qm_dqflush_all(struct xfs_mount *, int); +extern int xfs_qm_dqattach(struct xfs_inode *, uint); +extern int xfs_qm_dqpurge_all(struct xfs_mount *, uint); +extern void xfs_qm_mount_quotainit(struct xfs_mount *, uint); +extern void xfs_qm_unmount_quotadestroy(struct xfs_mount *); +extern int xfs_qm_mount_quotas(struct xfs_mount *); +extern int xfs_qm_unmount_quotas(struct xfs_mount *); +extern void xfs_qm_dqdettach_inode(struct xfs_inode *); +extern int xfs_qm_sync(struct xfs_mount *, short); + +/* + * Dquot interface. + */ +extern void xfs_dqlock(struct xfs_dquot *); +extern void xfs_dqunlock(struct xfs_dquot *); +extern void xfs_dqunlock_nonotify(struct xfs_dquot *); +extern void xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *); +extern void xfs_qm_dqput(struct xfs_dquot *); +extern void xfs_qm_dqrele(struct xfs_dquot *); +extern xfs_dqid_t xfs_qm_dqid(struct xfs_dquot *); +extern int xfs_qm_dqget(struct xfs_mount *, + struct xfs_inode *, xfs_dqid_t, + uint, uint, struct xfs_dquot **); +extern int xfs_qm_dqcheck(struct xfs_disk_dquot *, + xfs_dqid_t, uint, uint, char *); + +/* + * Vnodeops specific code that should actually be _in_ xfs_vnodeops.c, but + * is here because it's nicer to keep vnodeops (therefore, XFS) lean + * and clean. + */ +extern struct xfs_dquot * xfs_qm_vop_chown(struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot **, + struct xfs_dquot *); +extern int xfs_qm_vop_dqalloc(struct xfs_mount *, + struct xfs_inode *, + uid_t, gid_t, uint, + struct xfs_dquot **, + struct xfs_dquot **); + +extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot *, + struct xfs_dquot *, + uint); + +extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **); +extern void xfs_qm_vop_dqattach_and_dqmod_newinode( + struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot *, + struct xfs_dquot *); + + +/* + * Dquot Transaction interface + */ +extern void xfs_trans_alloc_dqinfo(struct xfs_trans *); +extern void xfs_trans_free_dqinfo(struct xfs_trans *); +extern void xfs_trans_dup_dqinfo(struct xfs_trans *, + struct xfs_trans *); +extern void xfs_trans_mod_dquot(struct xfs_trans *, + struct xfs_dquot *, + uint, long); +extern void xfs_trans_mod_dquot_byino(struct xfs_trans *, + struct xfs_inode *, + uint, long); +extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *); +extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *); + +extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *, + struct xfs_inode *, + long, long, uint); + + +extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, + struct xfs_dquot *, + struct xfs_dquot *, + long, long, uint); +extern void xfs_trans_log_dquot(struct xfs_trans *, + struct xfs_dquot *); +extern void xfs_trans_dqjoin(struct xfs_trans *, + struct xfs_dquot *); +extern void xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint); + +# define _XQM_ZONE_DESTROY(z) ((z)? kmem_cache_destroy(z) : (void)0) + +#else +# define xfs_qm_init() (NULL) +# define xfs_qm_destroy(xqm) do { } while (0) +# define xfs_qm_dqflush_all(m,t) (ENOSYS) +# define xfs_qm_dqattach(i,t) (ENOSYS) +# define xfs_qm_dqpurge_all(m,t) (ENOSYS) +# define xfs_qm_mount_quotainit(m,t) do { } while (0) +# define xfs_qm_unmount_quotadestroy(m) do { } while (0) +# define xfs_qm_mount_quotas(m) (ENOSYS) +# define xfs_qm_unmount_quotas(m) (ENOSYS) +# define xfs_qm_dqdettach_inode(i) do { } while (0) +# define xfs_qm_sync(m,t) (ENOSYS) +# define xfs_dqlock(d) do { } while (0) +# define xfs_dqunlock(d) do { } while (0) +# define xfs_dqunlock_nonotify(d) do { } while (0) +# define xfs_dqlock2(d1,d2) do { } while (0) +# define xfs_qm_dqput(d) do { } while (0) +# define xfs_qm_dqrele(d) do { } while (0) +# define xfs_qm_dqid(d) (-1) +# define xfs_qm_dqget(m,i,di,t,f,d) (ENOSYS) +# define xfs_qm_dqcheck(dd,di,t,f,s) (ENOSYS) +# define xfs_trans_alloc_dqinfo(t) do { } while (0) +# define xfs_trans_free_dqinfo(t) do { } while (0) +# define xfs_trans_dup_dqinfo(t1,t2) do { } while (0) +# define xfs_trans_mod_dquot(t,d,f,x) do { } while (0) +# define xfs_trans_mod_dquot_byino(t,i,f,x) do { } while (0) +# define xfs_trans_apply_dquot_deltas(t) do { } while (0) +# define xfs_trans_unreserve_and_mod_dquots(t) do { } while (0) +# define xfs_trans_reserve_quota_nblks(t,i,nb,ni,f) (ENOSYS) +# define xfs_trans_reserve_quota_bydquots(t,x,y,b,i,f) (ENOSYS) +# define xfs_trans_log_dquot(t,d) do { } while (0) +# define xfs_trans_dqjoin(t,d) do { } while (0) +# define xfs_qm_dqrele_all_inodes(m,t) do { } while (0) +# define xfs_qm_vop_chown(t,i,d1,d2) (NULL) +# define xfs_qm_vop_dqalloc(m,i,u,g,f,d1,d2) (ENOSYS) +# define xfs_qm_vop_chown_reserve(t,i,d1,d2,f) (ENOSYS) +# define xfs_qm_vop_rename_dqattach(i) (ENOSYS) +# define xfs_qm_vop_dqattach_and_dqmod_newinode(t,i,x,y) do { } while (0) +# define _XQM_ZONE_DESTROY(z) do { } while (0) +#endif /* CONFIG_XFS_QUOTA */ + +/* + * Regular disk block quota reservations + */ +#define xfs_trans_reserve_blkquota(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_reserve_blkquota_force(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, \ + XFS_QMOPT_RES_REGBLKS|XFS_QMOPT_FORCE_RES) + +#define xfs_trans_unreserve_blkquota(tp, ip, nblks) \ +(void)xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_reserve_quota(tp, udq, gdq, nb, ni, f) \ +xfs_trans_reserve_quota_bydquots(tp, udq, gdq, nb, ni, f|XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_unreserve_quota(tp, ud, gd, b, i, f) \ +xfs_trans_reserve_quota_bydquots(tp, ud, gd, -(b), -(i), f|XFS_QMOPT_RES_REGBLKS) + +/* + * Realtime disk block quota reservations + */ +#define xfs_trans_reserve_rtblkquota(mp, tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_unreserve_rtblkquota(tp, ip, nblks) \ +(void)xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_reserve_rtquota(mp, tp, uq, pq, blks, f) \ +xfs_trans_reserve_quota_bydquots(mp, tp, uq, pq, blks, 0, f|XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_unreserve_rtquota(tp, uq, pq, blks) \ +xfs_trans_reserve_quota_bydquots(tp, uq, pq, -(blks), XFS_QMOPT_RES_RTBLKS) + + +#endif /* __KERNEL__ */ + +#endif /* __XFS_QUOTA_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_quota_priv.h linux-2.4.19-sgi211r3/fs/xfs/xfs_quota_priv.h --- linux-2.4.19/fs/xfs/xfs_quota_priv.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_quota_priv.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_QUOTA_PRIV_H__ +#define __XFS_QUOTA_PRIV_H__ + +/* + * Number of bmaps that we ask from bmapi when doing a quotacheck. + * We make this restriction to keep the memory usage to a minimum. + */ +#define XFS_DQITER_MAP_SIZE 10 + +/* Number of dquots that fit in to a dquot block */ +#define XFS_QM_DQPERBLK(mp) ((mp)->m_quotainfo->qi_dqperchunk) + +#define XFS_ISLOCKED_INODE(ip) (ismrlocked(&(ip)->i_lock, \ + MR_UPDATE | MR_ACCESS) != 0) +#define XFS_ISLOCKED_INODE_EXCL(ip) (ismrlocked(&(ip)->i_lock, \ + MR_UPDATE) != 0) + +#define XFS_DQ_IS_ADDEDTO_TRX(t, d) ((d)->q_transp == (t)) + +#define XFS_QI_MPLRECLAIMS(mp) ((mp)->m_quotainfo->qi_dqreclaims) +#define XFS_QI_UQIP(mp) ((mp)->m_quotainfo->qi_uquotaip) +#define XFS_QI_GQIP(mp) ((mp)->m_quotainfo->qi_gquotaip) +#define XFS_QI_DQCHUNKLEN(mp) ((mp)->m_quotainfo->qi_dqchunklen) +#define XFS_QI_BTIMELIMIT(mp) ((mp)->m_quotainfo->qi_btimelimit) +#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit) +#define XFS_QI_ITIMELIMIT(mp) ((mp)->m_quotainfo->qi_itimelimit) +#define XFS_QI_BWARNLIMIT(mp) ((mp)->m_quotainfo->qi_bwarnlimit) +#define XFS_QI_IWARNLIMIT(mp) ((mp)->m_quotainfo->qi_iwarnlimit) +#define XFS_QI_QOFFLOCK(mp) ((mp)->m_quotainfo->qi_quotaofflock) + +#define XFS_QI_MPL_LIST(mp) ((mp)->m_quotainfo->qi_dqlist) +#define XFS_QI_MPLLOCK(mp) ((mp)->m_quotainfo->qi_dqlist.qh_lock) +#define XFS_QI_MPLNEXT(mp) ((mp)->m_quotainfo->qi_dqlist.qh_next) +#define XFS_QI_MPLNDQUOTS(mp) ((mp)->m_quotainfo->qi_dqlist.qh_nelems) + +#define XQMLCK(h) (mutex_lock(&((h)->qh_lock), PINOD)) +#define XQMUNLCK(h) (mutex_unlock(&((h)->qh_lock))) +#ifdef DEBUG +static inline int +XQMISLCKD(xfs_dqhash_t *h) +{ + if (mutex_trylock(&h->qh_lock)) { + mutex_unlock(&h->qh_lock); + return 0; + } + return 1; +} +#endif + +#define XFS_DQ_HASH_LOCK(h) XQMLCK(h) +#define XFS_DQ_HASH_UNLOCK(h) XQMUNLCK(h) +#define XFS_DQ_IS_HASH_LOCKED(h) XQMISLCKD(h) + +#define xfs_qm_mplist_lock(mp) XQMLCK(&(XFS_QI_MPL_LIST(mp))) +#define xfs_qm_mplist_unlock(mp) XQMUNLCK(&(XFS_QI_MPL_LIST(mp))) +#define XFS_QM_IS_MPLIST_LOCKED(mp) XQMISLCKD(&(XFS_QI_MPL_LIST(mp))) + +#define xfs_qm_freelist_lock(qm) XQMLCK(&((qm)->qm_dqfreelist)) +#define xfs_qm_freelist_unlock(qm) XQMUNLCK(&((qm)->qm_dqfreelist)) +#define XFS_QM_IS_FREELIST_LOCKED(qm) XQMISLCKD(&((qm)->qm_dqfreelist)) + +/* + * Hash into a bucket in the dquot hash table, based on . + */ +#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \ + (__psunsigned_t)(id)) & \ + (xfs_Gqm->qm_dqhashmask - 1)) +#define XFS_DQ_HASH(mp, id, type) (type == XFS_DQ_USER ? \ + (xfs_Gqm->qm_usr_dqhtable + \ + XFS_DQ_HASHVAL(mp, id)) : \ + (xfs_Gqm->qm_grp_dqhtable + \ + XFS_DQ_HASHVAL(mp, id))) +#define XFS_IS_DQTYPE_ON(mp, type) (type == XFS_DQ_USER ? \ + XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp)) +#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ + INT_ISZERO(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_bcount, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_rtbcount, ARCH_CONVERT) && \ + INT_ISZERO(dqp->q_core.d_icount, ARCH_CONVERT)) + +#define HL_PREVP dq_hashlist.ql_prevp +#define HL_NEXT dq_hashlist.ql_next +#define MPL_PREVP dq_mplist.ql_prevp +#define MPL_NEXT dq_mplist.ql_next + + +#define _LIST_REMOVE(h, dqp, PVP, NXT) \ + { \ + xfs_dquot_t *d; \ + if (((d) = (dqp)->NXT)) \ + (d)->PVP = (dqp)->PVP; \ + *((dqp)->PVP) = d; \ + (dqp)->NXT = NULL; \ + (dqp)->PVP = NULL; \ + (h)->qh_version++; \ + (h)->qh_nelems--; \ + } + +#define _LIST_INSERT(h, dqp, PVP, NXT) \ + { \ + xfs_dquot_t *d; \ + if (((d) = (h)->qh_next)) \ + (d)->PVP = &((dqp)->NXT); \ + (dqp)->NXT = d; \ + (dqp)->PVP = &((h)->qh_next); \ + (h)->qh_next = dqp; \ + (h)->qh_version++; \ + (h)->qh_nelems++; \ + } + +#define FOREACH_DQUOT_IN_MP(dqp, mp) \ + for ((dqp) = XFS_QI_MPLNEXT(mp); (dqp) != NULL; (dqp) = (dqp)->MPL_NEXT) + +#define FOREACH_DQUOT_IN_FREELIST(dqp, qlist) \ +for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \ + (dqp) = (dqp)->dq_flnext) + +#define XQM_HASHLIST_INSERT(h, dqp) \ + _LIST_INSERT(h, dqp, HL_PREVP, HL_NEXT) + +#define XQM_FREELIST_INSERT(h, dqp) \ + xfs_qm_freelist_append(h, dqp) + +#define XQM_MPLIST_INSERT(h, dqp) \ + _LIST_INSERT(h, dqp, MPL_PREVP, MPL_NEXT) + +#define XQM_HASHLIST_REMOVE(h, dqp) \ + _LIST_REMOVE(h, dqp, HL_PREVP, HL_NEXT) +#define XQM_FREELIST_REMOVE(dqp) \ + xfs_qm_freelist_unlink(dqp) +#define XQM_MPLIST_REMOVE(h, dqp) \ + { _LIST_REMOVE(h, dqp, MPL_PREVP, MPL_NEXT); \ + XFS_QI_MPLRECLAIMS((dqp)->q_mount)++; } + +#define XFS_DQ_IS_LOGITEM_INITD(dqp) ((dqp)->q_logitem.qli_dquot == (dqp)) + +#define XFS_QM_DQP_TO_DQACCT(tp, dqp) (XFS_QM_ISUDQ(dqp) ? \ + (tp)->t_dqinfo->dqa_usrdquots : \ + (tp)->t_dqinfo->dqa_grpdquots) +#define XFS_IS_SUSER_DQUOT(dqp) \ + (INT_ISZERO((dqp)->q_core.d_id, ARCH_CONVERT)) + +#define XFS_PURGE_INODE(ip) \ + { \ + vmap_t dqvmap; \ + vnode_t *dqvp; \ + dqvp = XFS_ITOV(ip); \ + VMAP(dqvp, ip, dqvmap); \ + VN_RELE(dqvp); \ + } + +#define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ + (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???")) +#define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY") + +#endif /* __XFS_QUOTA_PRIV_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_rename.c linux-2.4.19-sgi211r3/fs/xfs/xfs_rename.c --- linux-2.4.19/fs/xfs/xfs_rename.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_rename.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * Given an array of up to 4 inode pointers, unlock the pointed to inodes. + * If there are fewer than 4 entries in the array, the empty entries will + * be at the end and will have NULL pointers in them. + */ +STATIC void +xfs_rename_unlock4( + xfs_inode_t **i_tab, + uint lock_mode) +{ + int i; + + xfs_iunlock(i_tab[0], lock_mode); + for (i = 1; i < 4; i++) { + if (i_tab[i] == NULL) { + break; + } + /* + * Watch out for duplicate entries in the table. + */ + if (i_tab[i] != i_tab[i-1]) { + xfs_iunlock(i_tab[i], lock_mode); + } + } +} + +#ifdef DEBUG +int xfs_rename_skip, xfs_rename_nskip; +#endif + +/* + * The following routine will acquire the locks required for a rename + * operation. The code understands the semantics of renames and will + * validate that name1 exists under dp1 & that name2 may or may not + * exist under dp2. + * + * We are renaming dp1/name1 to dp2/name2. + * + * Return ENOENT if dp1 does not exist, other lookup errors, or 0 for success. + * Return EAGAIN if the caller needs to try again. + */ +STATIC int +xfs_lock_for_rename( + xfs_inode_t *dp1, /* old (source) directory inode */ + xfs_inode_t *dp2, /* new (target) directory inode */ + struct dentry *dentry1, /* old entry name */ + struct dentry *dentry2, /* new entry name */ + xfs_inode_t **ipp1, /* inode of old entry */ + xfs_inode_t **ipp2, /* inode of new entry, if it + already exists, NULL otherwise. */ + xfs_inode_t **i_tab,/* array of inode returned, sorted */ + int *num_inodes) /* number of inodes in array */ +{ + xfs_inode_t *ip1, *ip2, *temp; + xfs_ino_t inum1, inum2; + int error; + int i, j; + uint lock_mode; + uint lookup_flags; + int diff_dirs = (dp1 != dp2); + + ip2 = NULL; + + /* + * First, find out the current inums of the entries so that we + * can determine the initial locking order. We'll have to + * sanity check stuff after all the locks have been acquired + * to see if we still have the right inodes, directories, etc. + */ + lock_mode = xfs_ilock_map_shared(dp1); + error = xfs_get_dir_entry(dentry1, &ip1); + if (error) { + xfs_iunlock_map_shared(dp1, lock_mode); + return error; + } + + inum1 = ip1->i_ino; + + ASSERT(ip1); + ITRACE(ip1); + + /* + * Unlock dp1 and lock dp2 if they are different. + */ + + if (diff_dirs) { + xfs_iunlock_map_shared(dp1, lock_mode); + lock_mode = xfs_ilock_map_shared(dp2); + } + + lookup_flags = DLF_IGET; + if (lock_mode == XFS_ILOCK_SHARED) { + lookup_flags |= DLF_LOCK_SHARED; + } + error = xfs_dir_lookup_int(XFS_ITOBHV(dp2), lookup_flags, + dentry2, &inum2, &ip2); + if (error == ENOENT) { /* target does not need to exist. */ + inum2 = 0; + } else if (error) { + /* + * If dp2 and dp1 are the same, the next line unlocks dp1. + * Got it? + */ + xfs_iunlock_map_shared(dp2, lock_mode); + IRELE (ip1); + return error; + } else { + ITRACE(ip2); + } + + /* + * i_tab contains a list of pointers to inodes. We initialize + * the table here & we'll sort it. We will then use it to + * order the acquisition of the inode locks. + * + * Note that the table may contain duplicates. e.g., dp1 == dp2. + */ + i_tab[0] = dp1; + i_tab[1] = dp2; + i_tab[2] = ip1; + if (inum2 == 0) { + *num_inodes = 3; + i_tab[3] = NULL; + } else { + *num_inodes = 4; + i_tab[3] = ip2; + } + + /* + * Sort the elements via bubble sort. (Remember, there are at + * most 4 elements to sort, so this is adequate.) + */ + for (i=0; i < *num_inodes; i++) { + for (j=1; j < *num_inodes; j++) { + if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { + temp = i_tab[j]; + i_tab[j] = i_tab[j-1]; + i_tab[j-1] = temp; + } + } + } + + /* + * We have dp2 locked. If it isn't first, unlock it. + * If it is first, tell xfs_lock_inodes so it can skip it + * when locking. if dp1 == dp2, xfs_lock_inodes will skip both + * since they are equal. xfs_lock_inodes needs all these inodes + * so that it can unlock and retry if there might be a dead-lock + * potential with the log. + */ + + if (i_tab[0] == dp2 && lock_mode == XFS_ILOCK_SHARED) { +#ifdef DEBUG + xfs_rename_skip++; +#endif + xfs_lock_inodes(i_tab, *num_inodes, 1, XFS_ILOCK_SHARED); + } else { +#ifdef DEBUG + xfs_rename_nskip++; +#endif + xfs_iunlock_map_shared(dp2, lock_mode); + xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED); + } + + /* + * Set the return value. Null out any unused entries in i_tab. + */ + *ipp1 = *ipp2 = NULL; + for (i=0; i < *num_inodes; i++) { + if (i_tab[i]->i_ino == inum1) { + *ipp1 = i_tab[i]; + } + if (i_tab[i]->i_ino == inum2) { + *ipp2 = i_tab[i]; + } + } + for (;i < 4; i++) { + i_tab[i] = NULL; + } + return 0; +} + + +int rename_which_error_return = 0; + +#ifdef DEBUG +int xfs_rename_agains; +int xfs_renames; +#endif + +/* + * xfs_rename + */ +int +xfs_rename( + bhv_desc_t *src_dir_bdp, + struct dentry *src_dentry, + vnode_t *target_dir_vp, + struct dentry *target_dentry, + cred_t *credp) +{ + xfs_trans_t *tp; + xfs_inode_t *src_dp, *target_dp, *src_ip, *target_ip; + xfs_mount_t *mp; + int new_parent; /* moving to a new dir */ + int src_is_directory; /* src_name is a directory */ + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + xfs_inode_t *inodes[4]; + int target_ip_dropped = 0; /* dropped target_ip link? */ + vnode_t *src_dir_vp; + bhv_desc_t *target_dir_bdp; + int spaceres; + int target_link_zero = 0; + int num_inodes; + char *src_name = (char *)src_dentry->d_name.name; + char *target_name = (char *)target_dentry->d_name.name; + int src_namelen; + int target_namelen; +#ifdef DEBUG + int retries; + + xfs_renames++; +#endif + src_dir_vp = BHV_TO_VNODE(src_dir_bdp); + vn_trace_entry(src_dir_vp, "xfs_rename", (inst_t *)__return_address); + vn_trace_entry(target_dir_vp, "xfs_rename", (inst_t *)__return_address); + + /* + * Find the XFS behavior descriptor for the target directory + * vnode since it was not handed to us. + */ + target_dir_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(target_dir_vp), + &xfs_vnodeops); + if (target_dir_bdp == NULL) { + return XFS_ERROR(EXDEV); + } + src_namelen = src_dentry->d_name.len; + if (src_namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + target_namelen = target_dentry->d_name.len; + if (target_namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + src_dp = XFS_BHVTOI(src_dir_bdp); + target_dp = XFS_BHVTOI(target_dir_bdp); + if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_RENAME) || + DM_EVENT_ENABLED(target_dir_vp->v_vfsp, + target_dp, DM_EVENT_RENAME)) { + error = dm_send_namesp_event(DM_EVENT_RENAME, + src_dir_bdp, DM_RIGHT_NULL, + target_dir_bdp, DM_RIGHT_NULL, + src_name, target_name, + 0, 0, 0); + if (error) { + return error; + } + } + /* Return through std_return after this point. */ + +#ifdef DEBUG + retries = 0; +#endif + /* + * Lock all the participating inodes. Depending upon whether + * the target_name exists in the target directory, and + * whether the target directory is the same as the source + * directory, we can lock from 2 to 4 inodes. + * xfs_lock_for_rename() will return ENOENT if src_name + * does not exist in the source directory. + */ + tp = NULL; + do { + error = xfs_lock_for_rename(src_dp, target_dp, src_dentry, + target_dentry, &src_ip, &target_ip, inodes, + &num_inodes); +#ifdef DEBUG + if (error == EAGAIN) + xfs_rename_agains++; +#endif + } while (error == EAGAIN); + + if (error) { + rename_which_error_return = __LINE__; + /* + * We have nothing locked, no inode references, and + * no transaction, so just get out. + */ + goto std_return; + } + + ASSERT(src_ip != NULL); + + if ((src_ip->i_d.di_mode & IFMT) == IFDIR) { + /* + * Check for link count overflow on target_dp + */ + if (target_ip == NULL && (src_dp != target_dp) && + target_dp->i_d.di_nlink >= XFS_MAXLINK) { + rename_which_error_return = __LINE__; + error = XFS_ERROR(EMLINK); + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + goto rele_return; + } + } + + new_parent = (src_dp != target_dp); + src_is_directory = ((src_ip->i_d.di_mode & IFMT) == IFDIR); + + /* + * Drop the locks on our inodes so that we can do the ancestor + * check if necessary and start the transaction. + */ + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + + XFS_BMAP_INIT(&free_list, &first_block); + mp = src_dp->i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + spaceres = XFS_RENAME_SPACE_RES(mp, target_namelen); + error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); + if (error == ENOSPC) { + spaceres = 0; + error = xfs_trans_reserve(tp, 0, XFS_RENAME_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); + } + if (error) { + rename_which_error_return = __LINE__; + xfs_trans_cancel(tp, 0); + goto rele_return; + } + + /* + * Attach the dquots to the inodes + */ + if (XFS_IS_QUOTA_ON(mp)) { + if ((error = xfs_qm_vop_rename_dqattach(inodes))) { + xfs_trans_cancel(tp, cancel_flags); + rename_which_error_return = __LINE__; + goto rele_return; + } + } + + /* + * Reacquire the inode locks we dropped above. + */ + xfs_lock_inodes(inodes, num_inodes, 0, XFS_ILOCK_EXCL); + + /* + * Join all the inodes to the transaction. From this point on, + * we can rely on either trans_commit or trans_cancel to unlock + * them. Note that we need to add a vnode reference to the + * directories since trans_commit & trans_cancel will decrement + * them when they unlock the inodes. Also, we need to be careful + * not to add an inode to the transaction more than once. + */ + VN_HOLD(src_dir_vp); + xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL); + if (new_parent) { + VN_HOLD(target_dir_vp); + xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL); + } + if ((src_ip != src_dp) && (src_ip != target_dp)) { + xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); + } + if ((target_ip != NULL) && + (target_ip != src_ip) && + (target_ip != src_dp) && + (target_ip != target_dp)) { + xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); + } + + /* + * Set up the target. + */ + if (target_ip == NULL) { + /* + * If there's no space reservation, check the entry will + * fit before actually inserting it. + */ + if (spaceres == 0 && + (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name, + target_namelen))) { + rename_which_error_return = __LINE__; + goto error_return; + } + /* + * If target does not exist and the rename crosses + * directories, adjust the target directory link count + * to account for the ".." reference from the new entry. + */ + error = XFS_DIR_CREATENAME(mp, tp, target_dp, target_name, + target_namelen, src_ip->i_ino, + &first_block, &free_list, spaceres); + if (error == ENOSPC) { + rename_which_error_return = __LINE__; + goto error_return; + } + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + if (new_parent && src_is_directory) { + error = xfs_bumplink(tp, target_dp); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + } + } else { /* target_ip != NULL */ + + /* + * If target exists and it's a directory, check that both + * target and source are directories and that target can be + * destroyed, or that neither is a directory. + */ + if ((target_ip->i_d.di_mode & IFMT) == IFDIR) { + /* + * Make sure target dir is empty. + */ + if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) || + (target_ip->i_d.di_nlink > 2)) { + error = XFS_ERROR(EEXIST); + rename_which_error_return = __LINE__; + goto error_return; + } + } + + /* + * Link the source inode under the target name. + * If the source inode is a directory and we are moving + * it across directories, its ".." entry will be + * inconsistent until we replace that down below. + * + * In case there is already an entry with the same + * name at the destination directory, remove it first. + */ + error = XFS_DIR_REPLACE(mp, tp, target_dp, target_name, + target_namelen, src_ip->i_ino, &first_block, + &free_list, spaceres); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Decrement the link count on the target since the target + * dir no longer points to it. + */ + error = xfs_droplink(tp, target_ip); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return;; + } + target_ip_dropped = 1; + + /* Do this test while we still hold the locks */ + target_link_zero = (target_ip)->i_d.di_nlink==0; + + if (src_is_directory) { + /* + * Drop the link from the old "." entry. + */ + error = xfs_droplink(tp, target_ip); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + } + + } /* target_ip != NULL */ + + /* + * Remove the source. + */ + if (new_parent && src_is_directory) { + + /* + * Rewrite the ".." entry to point to the new + * directory. + */ + error = XFS_DIR_REPLACE(mp, tp, src_ip, "..", 2, + target_dp->i_ino, &first_block, + &free_list, spaceres); + ASSERT(error != EEXIST); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + } else { + /* + * We always want to hit the ctime on the source inode. + * We do it in the if clause above for the 'new_parent && + * src_is_directory' case, and here we get all the other + * cases. This isn't strictly required by the standards + * since the source inode isn't really being changed, + * but old unix file systems did it and some incremental + * backup programs won't work without it. + */ + xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG); + } + + /* + * Adjust the link count on src_dp. This is necessary when + * renaming a directory, either within one parent when + * the target existed, or across two parent directories. + */ + if (src_is_directory && (new_parent || target_ip != NULL)) { + + /* + * Decrement link count on src_directory since the + * entry that's moved no longer points to it. + */ + error = xfs_droplink(tp, src_dp); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + } + + error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen, + src_ip->i_ino, &first_block, &free_list, spaceres); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Update the generation counts on all the directory inodes + * that we're modifying. + */ + src_dp->i_gen++; + xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); + + if (new_parent) { + target_dp->i_gen++; + xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); + } + + /* + * If there was a target inode, take an extra reference on + * it here so that it doesn't go to xfs_inactive() from + * within the commit. + */ + if (target_ip != NULL) { + IHOLD(target_ip); + } + + /* + * If this is a synchronous mount, make sure that the + * rename transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + /* + * Take refs. for vop_link_removed calls below. No need to worry + * about directory refs. because the caller holds them. + * + * Do holds before the xfs_bmap_finish since it might rele them down + * to zero. + */ + + if (target_ip_dropped) + IHOLD(target_ip); + IHOLD(src_ip); + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + if (target_ip != NULL) { + IRELE(target_ip); + } + if (target_ip_dropped) { + IRELE(target_ip); + } + IRELE(src_ip); + goto std_return; + } + + /* + * trans_commit will unlock src_ip, target_ip & decrement + * the vnode references. + */ + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (target_ip != NULL) { + xfs_refcache_purge_ip(target_ip); + IRELE(target_ip); + } + /* + * Let interposed file systems know about removed links. + */ + if (target_ip_dropped) { + VOP_LINK_REMOVED(XFS_ITOV(target_ip), target_dir_vp, + target_link_zero); + IRELE(target_ip); + } + + FSC_NOTIFY_NAME_CHANGED(XFS_ITOV(src_ip)); + + IRELE(src_ip); + + /* Fall through to std_return with error = 0 or errno from + * xfs_trans_commit */ +std_return: + if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_POSTRENAME) || + DM_EVENT_ENABLED(target_dir_vp->v_vfsp, + target_dp, DM_EVENT_POSTRENAME)) { + (void) dm_send_namesp_event(DM_EVENT_POSTRENAME, + src_dir_bdp, DM_RIGHT_NULL, + target_dir_bdp, DM_RIGHT_NULL, + src_name, target_name, + 0, error, 0); + } + return error; + + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, cancel_flags); + goto std_return; + + rele_return: + IRELE(src_ip); + if (target_ip != NULL) { + IRELE(target_ip); + } + goto std_return; +} diff -Nur linux-2.4.19/fs/xfs/xfs_rtalloc.c linux-2.4.19-sgi211r3/fs/xfs/xfs_rtalloc.c --- linux-2.4.19/fs/xfs/xfs_rtalloc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_rtalloc.c Wed Oct 16 14:02:58 2002 @@ -0,0 +1,2438 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free realtime space allocation for XFS. + */ + +#include + + +/* + * Prototypes for internal functions. + */ + + +STATIC int xfs_rtallocate_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t, xfs_buf_t **, xfs_fsblock_t *); +STATIC int xfs_rtany_summary(xfs_mount_t *, xfs_trans_t *, int, int, + xfs_rtblock_t, xfs_buf_t **, xfs_fsblock_t *, int *); +STATIC int xfs_rtcheck_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t, int, xfs_rtblock_t *, int *); +STATIC int xfs_rtfind_back(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_rtblock_t, xfs_rtblock_t *); +STATIC int xfs_rtfind_forw(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_rtblock_t, xfs_rtblock_t *); +STATIC int xfs_rtget_summary( xfs_mount_t *, xfs_trans_t *, int, + xfs_rtblock_t, xfs_buf_t **, xfs_fsblock_t *, xfs_suminfo_t *); +STATIC int xfs_rtmodify_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t, int); +STATIC int xfs_rtmodify_summary(xfs_mount_t *, xfs_trans_t *, int, + xfs_rtblock_t, int, xfs_buf_t **, xfs_fsblock_t *); + +/* + * Internal functions. + */ + +/* + * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. + */ +STATIC int +xfs_lowbit32( + __uint32_t v) +{ + return ffs(v)-1; +} + +/* + * Allocate space to the bitmap or summary file, and zero it, for growfs. + */ +STATIC int /* error */ +xfs_growfs_rt_alloc( + xfs_mount_t *mp, /* file system mount point */ + xfs_extlen_t oblocks, /* old count of blocks */ + xfs_extlen_t nblocks, /* new count of blocks */ + xfs_ino_t ino) /* inode number (bitmap/summary) */ +{ + xfs_fileoff_t bno; /* block number in file */ + xfs_buf_t *bp; /* temporary buffer for zeroing */ + int cancelflags; /* flags for xfs_trans_cancel */ + int committed; /* transaction committed flag */ + xfs_daddr_t d; /* disk block address */ + int error; /* error return value */ + xfs_fsblock_t firstblock; /* first block allocated in xaction */ + xfs_bmap_free_t flist; /* list of freed blocks */ + xfs_fsblock_t fsbno; /* filesystem block for bno */ + xfs_inode_t *ip; /* pointer to incore inode */ + xfs_bmbt_irec_t map; /* block map output */ + int nmap; /* number of block maps */ + int resblks; /* space reservation */ + xfs_trans_t *tp; /* transaction pointer */ + + /* + * Allocate space to the file, as necessary. + */ + while (oblocks < nblocks) { + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC); + resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks); + cancelflags = 0; + /* + * Reserve space & log for one extent added to the file. + */ + if ((error = xfs_trans_reserve(tp, resblks, + XFS_GROWRTALLOC_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_DEFAULT_PERM_LOG_COUNT))) + goto error_exit; + cancelflags = XFS_TRANS_RELEASE_LOG_RES; + /* + * Lock the inode. + */ + if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip))) + goto error_exit; + XFS_BMAP_INIT(&flist, &firstblock); + /* + * Allocate blocks to the bitmap file. + */ + nmap = 1; + cancelflags |= XFS_TRANS_ABORT; + error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks, + XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock, + resblks, &map, &nmap, &flist); + if (!error && nmap < 1) + error = XFS_ERROR(ENOSPC); + if (error) + goto error_exit; + /* + * Free any blocks freed up in the transaction, then commit. + */ + error = xfs_bmap_finish(&tp, &flist, firstblock, &committed); + if (error) + goto error_exit; + xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + /* + * Now we need to clear the allocated blocks. + * Do this one block per transaction, to keep it simple. + */ + cancelflags = 0; + for (bno = map.br_startoff, fsbno = map.br_startblock; + bno < map.br_startoff + map.br_blockcount; + bno++, fsbno++) { + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ZERO); + /* + * Reserve log for one block zeroing. + */ + if ((error = xfs_trans_reserve(tp, 0, + XFS_GROWRTZERO_LOG_RES(mp), 0, 0, 0))) + goto error_exit; + /* + * Lock the bitmap inode. + */ + if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, + &ip))) + goto error_exit; + /* + * Get a buffer for the block. + */ + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, + mp->m_bsize, 0); + if (bp == NULL) { + error = XFS_ERROR(EIO); + goto error_exit; + } + bzero(XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize); + xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); + /* + * Commit the transaction. + */ + xfs_trans_commit(tp, 0, NULL); + } + /* + * Go on to the next extent, if any. + */ + oblocks = map.br_startoff + map.br_blockcount; + } + return 0; +error_exit: + xfs_trans_cancel(tp, cancelflags); + return error; +} + +/* + * Attempt to allocate an extent minlen<=len<=maxlen starting from + * bitmap block bbno. If we don't get maxlen then use prod to trim + * the length, if given. Returns error; returns starting block in *rtblock. + * The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_block( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bbno, /* bitmap block number */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_rtblock_t *nextp, /* out: next block to try */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + xfs_rtblock_t besti; /* best rtblock found so far */ + xfs_rtblock_t bestlen; /* best length found so far */ + xfs_rtblock_t end; /* last rtblock in chunk */ + int error; /* error value */ + xfs_rtblock_t i; /* current rtblock trying */ + xfs_rtblock_t next; /* next rtblock to try */ + int stat; /* status from internal calls */ + + /* + * Loop over all the extents starting in this bitmap block, + * looking for one that's long enough. + */ + for (i = XFS_BLOCKTOBIT(mp, bbno), besti = -1, bestlen = 0, + end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1; + i <= end; + i++) { + /* + * See if there's a free extent of maxlen starting at i. + * If it's not so then next will contain the first non-free. + */ + error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat); + if (error) { + return error; + } + if (stat) { + /* + * i for maxlen is all free, allocate and return that. + */ + error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp, + rsb); + if (error) { + return error; + } + *len = maxlen; + *rtblock = i; + return 0; + } + /* + * In the case where we have a variable-sized allocation + * request, figure out how big this free piece is, + * and if it's big enough for the minimum, and the best + * so far, remember it. + */ + if (minlen < maxlen) { + xfs_rtblock_t thislen; /* this extent size */ + + thislen = next - i; + if (thislen >= minlen && thislen > bestlen) { + besti = i; + bestlen = thislen; + } + } + /* + * If not done yet, find the start of the next free space. + */ + if (next < end) { + error = xfs_rtfind_forw(mp, tp, next, end, &i); + if (error) { + return error; + } + } else + break; + } + /* + * Searched the whole thing & didn't find a maxlen free extent. + */ + if (minlen < maxlen && besti != -1) { + xfs_extlen_t p; /* amount to trim length by */ + + /* + * If size should be a multiple of prod, make that so. + */ + if (prod > 1 && (p = do_mod(bestlen, prod))) + bestlen -= p; + /* + * Allocate besti for bestlen & return that. + */ + error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb); + if (error) { + return error; + } + *len = bestlen; + *rtblock = besti; + return 0; + } + /* + * Allocation failed. Set *nextp to the next block to try. + */ + *nextp = next; + *rtblock = NULLRTBLOCK; + return 0; +} + +/* + * Allocate an extent of length minlen<=len<=maxlen, starting at block + * bno. If we don't get maxlen then use prod to trim the length, if given. + * Returns error; returns starting block in *rtblock. + * The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_exact( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int error; /* error value */ + xfs_extlen_t i; /* extent length trimmed due to prod */ + int isfree; /* extent is free */ + xfs_rtblock_t next; /* next block to try (dummy) */ + + ASSERT(minlen % prod == 0 && maxlen % prod == 0); + /* + * Check if the range in question (for maxlen) is free. + */ + error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree); + if (error) { + return error; + } + if (isfree) { + /* + * If it is, allocate it and return success. + */ + error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb); + if (error) { + return error; + } + *len = maxlen; + *rtblock = bno; + return 0; + } + /* + * If not, allocate what there is, if it's at least minlen. + */ + maxlen = next - bno; + if (maxlen < minlen) { + /* + * Failed, return failure status. + */ + *rtblock = NULLRTBLOCK; + return 0; + } + /* + * Trim off tail of extent, if prod is specified. + */ + if (prod > 1 && (i = maxlen % prod)) { + maxlen -= i; + if (maxlen < minlen) { + /* + * Now we can't do it, return failure status. + */ + *rtblock = NULLRTBLOCK; + return 0; + } + } + /* + * Allocate what we can and return it. + */ + error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb); + if (error) { + return error; + } + *len = maxlen; + *rtblock = bno; + return 0; +} + +/* + * Allocate an extent of length minlen<=len<=maxlen, starting as near + * to bno as possible. If we don't get maxlen then use prod to trim + * the length, if given. The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_near( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int any; /* any useful extents from summary */ + xfs_rtblock_t bbno; /* bitmap block number */ + int error; /* error value */ + int i; /* bitmap block offset (loop control) */ + int j; /* secondary loop control */ + int log2len; /* log2 of minlen */ + xfs_rtblock_t n; /* next block to try */ + xfs_rtblock_t r; /* result block */ + + ASSERT(minlen % prod == 0 && maxlen % prod == 0); + /* + * If the block number given is off the end, silently set it to + * the last block. + */ + if (bno >= mp->m_sb.sb_rextents) + bno = mp->m_sb.sb_rextents - 1; + /* + * Try the exact allocation first. + */ + error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len, + rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If the exact allocation worked, return that. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + bbno = XFS_BITTOBLOCK(mp, bno); + i = 0; + log2len = xfs_highbit32(minlen); + /* + * Loop over all bitmap blocks (bbno + i is current block). + */ + for (;;) { + /* + * Get summary information of extents of all useful levels + * starting in this bitmap block. + */ + error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1, + bbno + i, rbpp, rsb, &any); + if (error) { + return error; + } + /* + * If there are any useful extents starting here, try + * allocating one. + */ + if (any) { + /* + * On the positive side of the starting location. + */ + if (i >= 0) { + /* + * Try to allocate an extent starting in + * this block. + */ + error = xfs_rtallocate_extent_block(mp, tp, + bbno + i, minlen, maxlen, len, &n, rbpp, + rsb, prod, &r); + if (error) { + return error; + } + /* + * If it worked, return it. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + } + /* + * On the negative side of the starting location. + */ + else { /* i < 0 */ + /* + * Loop backwards through the bitmap blocks from + * the starting point-1 up to where we are now. + * There should be an extent which ends in this + * bitmap block and is long enough. + */ + for (j = -1; j > i; j--) { + /* + * Grab the summary information for + * this bitmap block. + */ + error = xfs_rtany_summary(mp, tp, + log2len, mp->m_rsumlevels - 1, + bbno + j, rbpp, rsb, &any); + if (error) { + return error; + } + /* + * If there's no extent given in the + * summary that means the extent we + * found must carry over from an + * earlier block. If there is an + * extent given, we've already tried + * that allocation, don't do it again. + */ + if (any) + continue; + error = xfs_rtallocate_extent_block(mp, + tp, bbno + j, minlen, maxlen, + len, &n, rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If it works, return the extent. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + } + /* + * There weren't intervening bitmap blocks + * with a long enough extent, or the + * allocation didn't work for some reason + * (i.e. it's a little * too short). + * Try to allocate from the summary block + * that we found. + */ + error = xfs_rtallocate_extent_block(mp, tp, + bbno + i, minlen, maxlen, len, &n, rbpp, + rsb, prod, &r); + if (error) { + return error; + } + /* + * If it works, return the extent. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + } + } + /* + * Loop control. If we were on the positive side, and there's + * still more blocks on the negative side, go there. + */ + if (i > 0 && (int)bbno - i >= 0) + i = -i; + /* + * If positive, and no more negative, but there are more + * positive, go there. + */ + else if (i > 0 && (int)bbno + i < mp->m_sb.sb_rbmblocks - 1) + i++; + /* + * If negative or 0 (just started), and there are positive + * blocks to go, go there. The 0 case moves to block 1. + */ + else if (i <= 0 && (int)bbno - i < mp->m_sb.sb_rbmblocks - 1) + i = 1 - i; + /* + * If negative or 0 and there are more negative blocks, + * go there. + */ + else if (i <= 0 && (int)bbno + i > 0) + i--; + /* + * Must be done. Return failure. + */ + else + break; + } + *rtblock = NULLRTBLOCK; + return 0; +} + +/* + * Allocate an extent of length minlen<=len<=maxlen, with no position + * specified. If we don't get maxlen then use prod to trim + * the length, if given. The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_size( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int error; /* error value */ + int i; /* bitmap block number */ + int l; /* level number (loop control) */ + xfs_rtblock_t n; /* next block to be tried */ + xfs_rtblock_t r; /* result block number */ + xfs_suminfo_t sum; /* summary information for extents */ + + ASSERT(minlen % prod == 0 && maxlen % prod == 0); + /* + * Loop over all the levels starting with maxlen. + * At each level, look at all the bitmap blocks, to see if there + * are extents starting there that are long enough (>= maxlen). + * Note, only on the initial level can the allocation fail if + * the summary says there's an extent. + */ + for (l = xfs_highbit32(maxlen); l < mp->m_rsumlevels; l++) { + /* + * Loop over all the bitmap blocks. + */ + for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) { + /* + * Get the summary for this level/block. + */ + error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb, + &sum); + if (error) { + return error; + } + /* + * Nothing there, on to the next block. + */ + if (!sum) + continue; + /* + * Try allocating the extent. + */ + error = xfs_rtallocate_extent_block(mp, tp, i, maxlen, + maxlen, len, &n, rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If it worked, return that. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + /* + * If the "next block to try" returned from the + * allocator is beyond the next bitmap block, + * skip to that bitmap block. + */ + if (XFS_BITTOBLOCK(mp, n) > i + 1) + i = XFS_BITTOBLOCK(mp, n) - 1; + } + } + /* + * Didn't find any maxlen blocks. Try smaller ones, unless + * we're asking for a fixed size extent. + */ + if (minlen > --maxlen) { + *rtblock = NULLRTBLOCK; + return 0; + } + /* + * Loop over sizes, from maxlen down to minlen. + * This time, when we do the allocations, allow smaller ones + * to succeed. + */ + for (l = xfs_highbit32(maxlen); l >= xfs_highbit32(minlen); l--) { + /* + * Loop over all the bitmap blocks, try an allocation + * starting in that block. + */ + for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) { + /* + * Get the summary information for this level/block. + */ + error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb, + &sum); + if (error) { + return error; + } + /* + * If nothing there, go on to next. + */ + if (!sum) + continue; + /* + * Try the allocation. Make sure the specified + * minlen/maxlen are in the possible range for + * this summary level. + */ + error = xfs_rtallocate_extent_block(mp, tp, i, + XFS_RTMAX(minlen, 1 << l), + XFS_RTMIN(maxlen, (1 << (l + 1)) - 1), + len, &n, rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If it worked, return that extent. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + /* + * If the "next block to try" returned from the + * allocator is beyond the next bitmap block, + * skip to that bitmap block. + */ + if (XFS_BITTOBLOCK(mp, n) > i + 1) + i = XFS_BITTOBLOCK(mp, n) - 1; + } + } + /* + * Got nothing, return failure. + */ + *rtblock = NULLRTBLOCK; + return 0; +} + +/* + * Mark an extent specified by start and len allocated. + * Updates all the summary information as well as the bitmap. + */ +STATIC int /* error */ +xfs_rtallocate_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* start block to allocate */ + xfs_extlen_t len, /* length to allocate */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_rtblock_t end; /* end of the allocated extent */ + int error; /* error value */ + xfs_rtblock_t postblock; /* first block allocated > end */ + xfs_rtblock_t preblock; /* first block allocated < start */ + + end = start + len - 1; + /* + * Assume we're allocating out of the middle of a free extent. + * We need to find the beginning and end of the extent so we can + * properly update the summary. + */ + error = xfs_rtfind_back(mp, tp, start, 0, &preblock); + if (error) { + return error; + } + /* + * Find the next allocated block (end of free extent). + */ + error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, + &postblock); + if (error) { + return error; + } + /* + * Decrement the summary information corresponding to the entire + * (old) free extent. + */ + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock + 1 - preblock), + XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); + if (error) { + return error; + } + /* + * If there are blocks not being allocated at the front of the + * old extent, add summary data for them to be free. + */ + if (preblock < start) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(start - preblock), + XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * If there are blocks not being allocated at the end of the + * old extent, add summary data for them to be free. + */ + if (postblock > end) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock - end), + XFS_BITTOBLOCK(mp, end + 1), 1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * Modify the bitmap to mark this extent allocated. + */ + error = xfs_rtmodify_range(mp, tp, start, len, 0); + return error; +} + +/* + * Return whether there are any free extents in the size range given + * by low and high, for the bitmap block bbno. + */ +STATIC int /* error */ +xfs_rtany_summary( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + int low, /* low log2 extent size */ + int high, /* high log2 extent size */ + xfs_rtblock_t bbno, /* bitmap block number */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + int *stat) /* out: any good extents here? */ +{ + int error; /* error value */ + int log; /* loop counter, log2 of ext. size */ + xfs_suminfo_t sum; /* summary data */ + + /* + * Loop over logs of extent sizes. Order is irrelevant. + */ + for (log = low; log <= high; log++) { + /* + * Get one summary datum. + */ + error = xfs_rtget_summary(mp, tp, log, bbno, rbpp, rsb, &sum); + if (error) { + return error; + } + /* + * If there are any, return success. + */ + if (sum) { + *stat = 1; + return 0; + } + } + /* + * Found nothing, return failure. + */ + *stat = 0; + return 0; +} + +/* + * Get a buffer for the bitmap or summary file block specified. + * The buffer is returned read and locked. + */ +STATIC int /* error */ +xfs_rtbuf_get( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t block, /* block number in bitmap or summary */ + int issum, /* is summary not bitmap */ + xfs_buf_t **bpp) /* output: buffer for the block */ +{ + xfs_buf_t *bp; /* block buffer, result */ + xfs_daddr_t d; /* disk addr of block */ + int error; /* error value */ + xfs_fsblock_t fsb; /* fs block number for block */ + xfs_inode_t *ip; /* bitmap or summary inode */ + + ip = issum ? mp->m_rsumip : mp->m_rbmip; + /* + * Map from the file offset (block) and inode number to the + * file system block. + */ + error = xfs_bmapi_single(tp, ip, XFS_DATA_FORK, &fsb, block); + if (error) { + return error; + } + ASSERT(fsb != NULLFSBLOCK); + /* + * Convert to disk address for buffer cache. + */ + d = XFS_FSB_TO_DADDR(mp, fsb); + /* + * Read the buffer. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, 0, &bp); + if (error) { + return error; + } + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + *bpp = bp; + return 0; +} + +#ifdef DEBUG +/* + * Check that the given extent (block range) is allocated already. + */ +STATIC int /* error */ +xfs_rtcheck_alloc_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* out: 1 for allocated, 0 for not */ +{ + xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ + + return xfs_rtcheck_range(mp, tp, bno, len, 0, &new, stat); +} +#endif + +#ifdef DEBUG +/* + * Check whether the given block in the bitmap has the given value. + */ +STATIC int /* 1 for matches, 0 for not */ +xfs_rtcheck_bit( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* bit (block) to check */ + int val) /* 1 for free, 0 for allocated */ +{ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* pointer into the buffer */ + /* REFERENCED */ + int error; /* error value */ + xfs_rtword_t wdiff; /* difference between bit & expected */ + int word; /* word number in the buffer */ + xfs_rtword_t wval; /* word value from buffer */ + + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BITTOWORD(mp, start); + bit = (int)(start & (XFS_NBWORD - 1)); + wval = bufp[word]; + xfs_trans_brelse(tp, bp); + wdiff = (wval ^ -val) & ((xfs_rtword_t)1 << bit); + return !wdiff; +} +#endif /* DEBUG */ + +#if 0 +/* + * Check that the given extent (block range) is free already. + */ +STATIC int /* error */ +xfs_rtcheck_free_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* out: 1 for free, 0 for not */ +{ + xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ + + return xfs_rtcheck_range(mp, tp, bno, len, 1, &new, stat); +} +#endif + +/* + * Check that the given range is either all allocated (val = 0) or + * all free (val = 1). + */ +STATIC int /* error */ +xfs_rtcheck_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block number of extent */ + xfs_extlen_t len, /* length of extent */ + int val, /* 1 for free, 0 for allocated */ + xfs_rtblock_t *new, /* out: first block not matching */ + int *stat) /* out: 1 for matches, 0 for not */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t lastbit; /* last useful bit in word */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute starting bitmap block number + */ + block = XFS_BITTOBLOCK(mp, start); + /* + * Read the bitmap block. + */ + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Compute the starting word's address, and starting bit. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + /* + * 0 (allocated) => all zero's; 1 (free) => all one's. + */ + val = -val; + /* + * If not starting on a word boundary, deal with the first + * (partial) word. + */ + if (bit) { + /* + * Compute first bit not examined. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + /* + * Mask of relevant bits. + */ + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ val) & mask)) { + /* + * Different, compute first wrong bit and return. + */ + xfs_trans_brelse(tp, bp); + i = XFS_RTLOBIT(wdiff) - bit; + *new = start + i; + *stat = 0; + return 0; + } + i = lastbit - bit; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the next one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer. + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ val)) { + /* + * Different, compute first wrong bit and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *new = start + i; + *stat = 0; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the next one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer. + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Mask of relevant bits. + */ + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ val) & mask)) { + /* + * Different, compute first wrong bit and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *new = start + i; + *stat = 0; + return 0; + } else + i = len; + } + /* + * Successful, return. + */ + xfs_trans_brelse(tp, bp); + *new = start + i; + *stat = 1; + return 0; +} + +/* + * Copy and transform the summary file, given the old and new + * parameters in the mount structures. + */ +STATIC int /* error */ +xfs_rtcopy_summary( + xfs_mount_t *omp, /* old file system mount point */ + xfs_mount_t *nmp, /* new file system mount point */ + xfs_trans_t *tp) /* transaction pointer */ +{ + xfs_rtblock_t bbno; /* bitmap block number */ + xfs_buf_t *bp; /* summary buffer */ + int error; /* error return value */ + int log; /* summary level number (log length) */ + xfs_suminfo_t sum; /* summary data */ + xfs_fsblock_t sumbno; /* summary block number */ + + bp = NULL; + for (log = omp->m_rsumlevels - 1; log >= 0; log--) { + for (bbno = omp->m_sb.sb_rbmblocks - 1; + (xfs_srtblock_t)bbno >= 0; + bbno--) { + error = xfs_rtget_summary(omp, tp, log, bbno, &bp, + &sumbno, &sum); + if (error) + return error; + if (sum == 0) + continue; + error = xfs_rtmodify_summary(omp, tp, log, bbno, -sum, + &bp, &sumbno); + if (error) + return error; + error = xfs_rtmodify_summary(nmp, tp, log, bbno, sum, + &bp, &sumbno); + if (error) + return error; + ASSERT(sum > 0); + } + } + return 0; +} + +/* + * Searching backward from start to limit, find the first block whose + * allocated/free state is different from start's. + */ +STATIC int /* error */ +xfs_rtfind_back( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to look at */ + xfs_rtblock_t limit, /* last block to look at */ + xfs_rtblock_t *rtblock) /* out: start block found */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t firstbit; /* first useful bit in the word */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t len; /* length of inspected area */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t want; /* mask for "good" values */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute and read in starting bitmap block for starting block. + */ + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Get the first word's index & point to it. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + len = start - limit + 1; + /* + * Compute match value, based on the bit at start: if 1 (free) + * then all-ones, else all-zeroes. + */ + want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; + /* + * If the starting position is not word-aligned, deal with the + * partial word. + */ + if (bit < XFS_NBWORD - 1) { + /* + * Calculate first (leftmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0); + mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << + firstbit; + /* + * Calculate the difference between the value there + * and what we're looking for. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different. Mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i = bit - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } + i = bit - firstbit + 1; + /* + * Go on to previous block if that's where the previous word is + * and we need the previous word. + */ + if (--word == -1 && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BLOCKWMASK(mp); + b = &bufp[word]; + } else { + /* + * Go on to the previous word in the buffer. + */ + b--; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the previous one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ want)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to previous block if that's where the previous word is + * and we need the previous word. + */ + if (--word == -1 && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BLOCKWMASK(mp); + b = &bufp[word]; + } else { + /* + * Go on to the previous word in the buffer. + */ + b--; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if (len - i) { + /* + * Calculate first (leftmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + firstbit = XFS_NBWORD - (len - i); + mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } else + i = len; + } + /* + * No match, return that we scanned the whole area. + */ + xfs_trans_brelse(tp, bp); + *rtblock = start - i + 1; + return 0; +} + +/* + * Searching forward from start to limit, find the first block whose + * allocated/free state is different from start's. + */ +STATIC int /* error */ +xfs_rtfind_forw( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to look at */ + xfs_rtblock_t limit, /* last block to look at */ + xfs_rtblock_t *rtblock) /* out: start block found */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t lastbit; /* last useful bit in the word */ + xfs_rtblock_t len; /* length of inspected area */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t want; /* mask for "good" values */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute and read in starting bitmap block for starting block. + */ + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Get the first word's index & point to it. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + len = limit - start + 1; + /* + * Compute match value, based on the bit at start: if 1 (free) + * then all-ones, else all-zeroes. + */ + want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; + /* + * If the starting position is not word-aligned, deal with the + * partial word. + */ + if (bit) { + /* + * Calculate last (rightmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Calculate the difference between the value there + * and what we're looking for. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different. Mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i = XFS_RTLOBIT(wdiff) - bit; + *rtblock = start + i - 1; + return 0; + } + i = lastbit - bit; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the previous word in the buffer. + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ want)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *rtblock = start + i - 1; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the next one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer. + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Calculate mask for all the relevant bits in this word. + */ + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *rtblock = start + i - 1; + return 0; + } else + i = len; + } + /* + * No match, return that we scanned the whole area. + */ + xfs_trans_brelse(tp, bp); + *rtblock = start + i - 1; + return 0; +} + +/* + * Mark an extent specified by start and len freed. + * Updates all the summary information as well as the bitmap. + */ +STATIC int /* error */ +xfs_rtfree_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to free */ + xfs_extlen_t len, /* length to free */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_rtblock_t end; /* end of the freed extent */ + int error; /* error value */ + xfs_rtblock_t postblock; /* first block freed > end */ + xfs_rtblock_t preblock; /* first block freed < start */ + + end = start + len - 1; + /* + * Modify the bitmap to mark this extent freed. + */ + error = xfs_rtmodify_range(mp, tp, start, len, 1); + if (error) { + return error; + } + /* + * Assume we're freeing out of the middle of an allocated extent. + * We need to find the beginning and end of the extent so we can + * properly update the summary. + */ + error = xfs_rtfind_back(mp, tp, start, 0, &preblock); + if (error) { + return error; + } + /* + * Find the next allocated block (end of allocated extent). + */ + error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, + &postblock); + /* + * If there are blocks not being freed at the front of the + * old extent, add summary data for them to be allocated. + */ + if (preblock < start) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(start - preblock), + XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * If there are blocks not being freed at the end of the + * old extent, add summary data for them to be allocated. + */ + if (postblock > end) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock - end), + XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * Increment the summary information corresponding to the entire + * (new) free extent. + */ + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock + 1 - preblock), + XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); + return error; +} + +/* + * Read and return the summary information for a given extent size, + * bitmap block combination. + * Keeps track of a current summary block, so we don't keep reading + * it from the buffer cache. + */ +STATIC int /* error */ +xfs_rtget_summary( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + int log, /* log2 of extent size */ + xfs_rtblock_t bbno, /* bitmap block number */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_suminfo_t *sum) /* out: summary info for this block */ +{ + xfs_buf_t *bp; /* buffer for summary block */ + int error; /* error value */ + xfs_fsblock_t sb; /* summary fsblock */ + int so; /* index into the summary file */ + xfs_suminfo_t *sp; /* pointer to returned data */ + + /* + * Compute entry number in the summary file. + */ + so = XFS_SUMOFFS(mp, log, bbno); + /* + * Compute the block number in the summary file. + */ + sb = XFS_SUMOFFSTOBLOCK(mp, so); + /* + * If we have an old buffer, and the block number matches, use that. + */ + if (rbpp && *rbpp && *rsb == sb) + bp = *rbpp; + /* + * Otherwise we have to get the buffer. + */ + else { + /* + * If there was an old one, get rid of it first. + */ + if (rbpp && *rbpp) + xfs_trans_brelse(tp, *rbpp); + error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); + if (error) { + return error; + } + /* + * Remember this buffer and block for the next call. + */ + if (rbpp) { + *rbpp = bp; + *rsb = sb; + } + } + /* + * Point to the summary information & copy it out. + */ + sp = XFS_SUMPTR(mp, bp, so); + *sum = *sp; + /* + * Drop the buffer if we're not asked to remember it. + */ + if (!rbpp) + xfs_trans_brelse(tp, bp); + return 0; +} + +/* + * Set the given range of bitmap bits to the given value. + * Do whatever I/O and logging is required. + */ +STATIC int /* error */ +xfs_rtmodify_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to modify */ + xfs_extlen_t len, /* length of extent to modify */ + int val) /* 1 for free, 0 for allocated */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtword_t *first; /* first used word in the buffer */ + int i; /* current bit number rel. to start */ + int lastbit; /* last useful bit in word */ + xfs_rtword_t mask; /* mask o frelevant bits for value */ + int word; /* word number in the buffer */ + + /* + * Compute starting bitmap block number. + */ + block = XFS_BITTOBLOCK(mp, start); + /* + * Read the bitmap block, and point to its data. + */ + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Compute the starting word's address, and starting bit. + */ + word = XFS_BITTOWORD(mp, start); + first = b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + /* + * 0 (allocated) => all zeroes; 1 (free) => all ones. + */ + val = -val; + /* + * If not starting on a word boundary, deal with the first + * (partial) word. + */ + if (bit) { + /* + * Compute first bit not changed and mask of relevant bits. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Set/clear the active bits. + */ + if (val) + *b |= mask; + else + *b &= ~mask; + i = lastbit - bit; + /* + * Go on to the next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * Log the changed part of this block. + * Get the next one. + */ + xfs_trans_log_buf(tp, bp, + (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp)); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Set the word value correctly. + */ + *b = val; + i += XFS_NBWORD; + /* + * Go on to the next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * Log the changed part of this block. + * Get the next one. + */ + xfs_trans_log_buf(tp, bp, + (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp)); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Compute a mask of relevant bits. + */ + bit = 0; + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Set/clear the active bits. + */ + if (val) + *b |= mask; + else + *b &= ~mask; + b++; + } + /* + * Log any remaining changed bytes. + */ + if (b > first) + xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp - 1)); + return 0; +} + +/* + * Read and modify the summary information for a given extent size, + * bitmap block combination. + * Keeps track of a current summary block, so we don't keep reading + * it from the buffer cache. + */ +STATIC int /* error */ +xfs_rtmodify_summary( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + int log, /* log2 of extent size */ + xfs_rtblock_t bbno, /* bitmap block number */ + int delta, /* change to make to summary info */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_buf_t *bp; /* buffer for the summary block */ + int error; /* error value */ + xfs_fsblock_t sb; /* summary fsblock */ + int so; /* index into the summary file */ + xfs_suminfo_t *sp; /* pointer to returned data */ + + /* + * Compute entry number in the summary file. + */ + so = XFS_SUMOFFS(mp, log, bbno); + /* + * Compute the block number in the summary file. + */ + sb = XFS_SUMOFFSTOBLOCK(mp, so); + /* + * If we have an old buffer, and the block number matches, use that. + */ + if (rbpp && *rbpp && *rsb == sb) + bp = *rbpp; + /* + * Otherwise we have to get the buffer. + */ + else { + /* + * If there was an old one, get rid of it first. + */ + if (rbpp && *rbpp) + xfs_trans_brelse(tp, *rbpp); + error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); + if (error) { + return error; + } + /* + * Remember this buffer and block for the next call. + */ + if (rbpp) { + *rbpp = bp; + *rsb = sb; + } + } + /* + * Point to the summary information, modify and log it. + */ + sp = XFS_SUMPTR(mp, bp, so); + *sp += delta; + xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)XFS_BUF_PTR(bp)), + (uint)((char *)sp - (char *)XFS_BUF_PTR(bp) + sizeof(*sp) - 1)); + return 0; +} + +/* + * Visible (exported) functions. + */ + +/* + * Grow the realtime area of the filesystem. + */ +int +xfs_growfs_rt( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_rt_t *in) /* growfs rt input struct */ +{ + xfs_rtblock_t bmbno; /* bitmap block number */ + xfs_buf_t *bp; /* temporary buffer */ + int cancelflags; /* flags for xfs_trans_cancel */ + int error; /* error return value */ + xfs_inode_t *ip; /* bitmap inode, used as lock */ + xfs_mount_t *nmp; /* new (fake) mount structure */ + xfs_drfsbno_t nrblocks; /* new number of realtime blocks */ + xfs_extlen_t nrbmblocks; /* new number of rt bitmap blocks */ + xfs_drtbno_t nrextents; /* new number of realtime extents */ + uint8_t nrextslog; /* new log2 of sb_rextents */ + xfs_extlen_t nrsumblocks; /* new number of summary blocks */ + uint nrsumlevels; /* new rt summary levels */ + uint nrsumsize; /* new size of rt summary, bytes */ + xfs_sb_t *nsbp; /* new superblock */ + xfs_extlen_t rbmblocks; /* current number of rt bitmap blocks */ + xfs_extlen_t rsumblocks; /* current number of rt summary blks */ + xfs_sb_t *sbp; /* old superblock */ + xfs_fsblock_t sumbno; /* summary block number */ + xfs_trans_t *tp; /* transaction pointer */ + + sbp = &mp->m_sb; + /* + * Initial error checking. + */ + if (mp->m_rtdev_targp || mp->m_rbmip == NULL || + (nrblocks = in->newblocks) <= sbp->sb_rblocks || + (sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize))) + return XFS_ERROR(EINVAL); + /* + * Read in the last block of the device, make sure it exists. + */ + error = xfs_read_buf(mp, mp->m_rtdev_targp, + XFS_FSB_TO_BB(mp, in->newblocks) - 1, 1, 0, &bp); + if (error) + return error; + ASSERT(bp); + xfs_buf_relse(bp); + /* + * Calculate new parameters. These are the final values to be reached. + */ + nrextents = do_div(nrblocks, in->extsize); + nrbmblocks = roundup_64(nrextents, NBBY * sbp->sb_blocksize); + nrextslog = xfs_highbit32(nrextents); + nrsumlevels = nrextslog + 1; + nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks; + nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize); + nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks); + /* + * New summary size can't be more than half the size of + * the log. This prevents us from getting a log overflow, + * since we'll log basically the whole summary file at once. + */ + if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1)) + return XFS_ERROR(EINVAL); + /* + * Get the old block counts for bitmap and summary inodes. + * These can't change since other growfs callers are locked out. + */ + rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_d.di_size); + rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_d.di_size); + /* + * Allocate space to the bitmap and summary files, as necessary. + */ + if ((error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, + mp->m_sb.sb_rbmino))) + return error; + if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, + mp->m_sb.sb_rsumino))) + return error; + nmp = NULL; + /* + * Loop over the bitmap blocks. + * We will do everything one bitmap block at a time. + * Skip the current block if it is exactly full. + * This also deals with the case where there were no rtextents before. + */ + for (bmbno = sbp->sb_rbmblocks - + ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0); + bmbno < nrbmblocks; + bmbno++) { + /* + * Allocate a new (fake) mount/sb. + */ + nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP); + *nmp = *mp; + nsbp = &nmp->m_sb; + /* + * Calculate new sb and mount fields for this round. + */ + nsbp->sb_rextsize = in->extsize; + nsbp->sb_rbmblocks = bmbno + 1; + nsbp->sb_rblocks = + XFS_RTMIN(nrblocks, + nsbp->sb_rbmblocks * NBBY * + nsbp->sb_blocksize * nsbp->sb_rextsize); + nsbp->sb_rextents = do_div(nsbp->sb_rblocks, nsbp->sb_rextsize); + nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents); + nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1; + nrsumsize = + (uint)sizeof(xfs_suminfo_t) * nrsumlevels * + nsbp->sb_rbmblocks; + nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize); + nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks); + /* + * Start a transaction, get the log reservation. + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_FREE); + cancelflags = 0; + if ((error = xfs_trans_reserve(tp, 0, + XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0))) + goto error_exit; + /* + * Lock out other callers by grabbing the bitmap inode lock. + */ + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, + XFS_ILOCK_EXCL, &ip))) + goto error_exit; + ASSERT(ip == mp->m_rbmip); + /* + * Update the bitmap inode's size. + */ + mp->m_rbmip->i_d.di_size = + nsbp->sb_rbmblocks * nsbp->sb_blocksize; + xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); + cancelflags |= XFS_TRANS_ABORT; + /* + * Get the summary inode into the transaction. + */ + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, + XFS_ILOCK_EXCL, &ip))) + goto error_exit; + ASSERT(ip == mp->m_rsumip); + /* + * Update the summary inode's size. + */ + mp->m_rsumip->i_d.di_size = nmp->m_rsumsize; + xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE); + /* + * Copy summary data from old to new sizes. + * Do this when the real size (not block-aligned) changes. + */ + if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks || + mp->m_rsumlevels != nmp->m_rsumlevels) { + error = xfs_rtcopy_summary(mp, nmp, tp); + if (error) + goto error_exit; + } + /* + * Update superblock fields. + */ + if (nsbp->sb_rextsize != sbp->sb_rextsize) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSIZE, + nsbp->sb_rextsize - sbp->sb_rextsize); + if (nsbp->sb_rbmblocks != sbp->sb_rbmblocks) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS, + nsbp->sb_rbmblocks - sbp->sb_rbmblocks); + if (nsbp->sb_rblocks != sbp->sb_rblocks) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBLOCKS, + nsbp->sb_rblocks - sbp->sb_rblocks); + if (nsbp->sb_rextents != sbp->sb_rextents) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTENTS, + nsbp->sb_rextents - sbp->sb_rextents); + if (nsbp->sb_rextslog != sbp->sb_rextslog) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG, + nsbp->sb_rextslog - sbp->sb_rextslog); + /* + * Free new extent. + */ + bp = NULL; + error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents, + nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno); + if (error) + goto error_exit; + /* + * Mark more blocks free in the superblock. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, + nsbp->sb_rextents - sbp->sb_rextents); + /* + * Free the fake mp structure. + */ + kmem_free(nmp, sizeof(*nmp)); + nmp = NULL; + /* + * Update mp values into the real mp structure. + */ + mp->m_rsumlevels = nrsumlevels; + mp->m_rsumsize = nrsumsize; + /* + * Commit the transaction. + */ + xfs_trans_commit(tp, 0, NULL); + } + return 0; + + /* + * Error paths come here. + */ +error_exit: + if (nmp) + kmem_free(nmp, sizeof(*nmp)); + xfs_trans_cancel(tp, cancelflags); + return error; +} + +/* + * Allocate an extent in the realtime subvolume, with the usual allocation + * parameters. The length units are all in realtime extents, as is the + * result block number. + */ +int /* error */ +xfs_rtallocate_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_alloctype_t type, /* allocation type XFS_ALLOCTYPE... */ + int wasdel, /* was a delayed allocation extent */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int error; /* error value */ + xfs_inode_t *ip; /* inode for bitmap file */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_rtblock_t r; /* result allocated block */ + xfs_fsblock_t sb; /* summary file block number */ + xfs_buf_t *sumbp; /* summary file block buffer */ + + ASSERT(minlen > 0 && minlen <= maxlen); + mp = tp->t_mountp; + /* + * If prod is set then figure out what to do to minlen and maxlen. + */ + if (prod > 1) { + xfs_extlen_t i; + + if ((i = maxlen % prod)) + maxlen -= i; + if ((i = minlen % prod)) + minlen += prod - i; + if (maxlen < minlen) { + *rtblock = NULLRTBLOCK; + return 0; + } + } + /* + * Lock out other callers by grabbing the bitmap inode lock. + */ + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + if (error) { + return error; + } + sumbp = NULL; + /* + * Allocate by size, or near another block, or exactly at some block. + */ + switch (type) { + case XFS_ALLOCTYPE_ANY_AG: + error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len, + &sumbp, &sb, prod, &r); + break; + case XFS_ALLOCTYPE_NEAR_BNO: + error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen, + len, &sumbp, &sb, prod, &r); + break; + case XFS_ALLOCTYPE_THIS_BNO: + error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, + len, &sumbp, &sb, prod, &r); + break; + default: + ASSERT(0); + } + if (error) { + return error; + } + /* + * If it worked, update the superblock. + */ + if (r != NULLRTBLOCK) { + long slen = (long)*len; + + ASSERT(*len >= minlen && *len <= maxlen); + if (wasdel) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FREXTENTS, -slen); + else + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -slen); + } + *rtblock = r; + return 0; +} + +/* + * Free an extent in the realtime subvolume. Length is expressed in + * realtime extents, as is the block number. + */ +int /* error */ +xfs_rtfree_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to free */ + xfs_extlen_t len) /* length of extent freed */ +{ + int error; /* error value */ + xfs_inode_t *ip; /* bitmap file inode */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_fsblock_t sb; /* summary file block number */ + xfs_buf_t *sumbp; /* summary file block buffer */ + + mp = tp->t_mountp; + /* + * Synchronize by locking the bitmap inode. + */ + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + if (error) { + return error; + } +#if defined(__KERNEL__) && defined(DEBUG) + /* + * Check to see that this whole range is currently allocated. + */ + { + int stat; /* result from checking range */ + + error = xfs_rtcheck_alloc_range(mp, tp, bno, len, &stat); + if (error) { + return error; + } + ASSERT(stat); + } +#endif + sumbp = NULL; + /* + * Free the range of realtime blocks. + */ + error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); + if (error) { + return error; + } + /* + * Mark more blocks free in the superblock. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); + /* + * If we've now freed all the blocks, reset the file sequence + * number to 0. + */ + if (tp->t_frextents_delta + mp->m_sb.sb_frextents == + mp->m_sb.sb_rextents) { + if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) + ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; + *(__uint64_t *)&ip->i_d.di_atime = 0; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + } + return 0; +} + +/* + * Initialize realtime fields in the mount structure. + */ +int /* error */ +xfs_rtmount_init( + xfs_mount_t *mp) /* file system mount structure */ +{ + xfs_buf_t *bp; /* buffer for last block of subvolume */ + xfs_daddr_t d; /* address of last block of subvolume */ + int error; /* error return value */ + xfs_sb_t *sbp; /* filesystem superblock copy in mount */ + + sbp = &mp->m_sb; + if (sbp->sb_rblocks == 0) + return 0; + if (mp->m_rtdev_targp != NULL) { + printk(KERN_WARNING + "XFS: This FS has an RT subvol - specify -o rtdev on mount\n"); + return XFS_ERROR(ENODEV); + } + mp->m_rsumlevels = sbp->sb_rextslog + 1; + mp->m_rsumsize = + (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels * + sbp->sb_rbmblocks; + mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize); + mp->m_rbmip = mp->m_rsumip = NULL; + /* + * Check that the realtime section is an ok size. + */ + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) { + printk(KERN_WARNING "XFS: RT mount - %llu != %llu\n", + (unsigned long long) XFS_BB_TO_FSB(mp, d), + (unsigned long long) mp->m_sb.sb_rblocks); + return XFS_ERROR(E2BIG); + } + error = xfs_read_buf(mp, mp->m_rtdev_targp, d - 1, 1, 0, &bp); + if (error) { + printk(KERN_WARNING + "XFS: RT mount - xfs_read_buf returned %d\n", error); + if (error == ENOSPC) + return XFS_ERROR(E2BIG); + return error; + } + xfs_buf_relse(bp); + return 0; +} + +/* + * Get the bitmap and summary inodes into the mount structure + * at mount time. + */ +int /* error */ +xfs_rtmount_inodes( + xfs_mount_t *mp) /* file system mount structure */ +{ + int error; /* error return value */ + xfs_sb_t *sbp; + + sbp = &mp->m_sb; + if (sbp->sb_rbmino == NULLFSINO) + return 0; + error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, &mp->m_rbmip, 0); + if (error) + return error; + ASSERT(mp->m_rbmip != NULL); + ASSERT(sbp->sb_rsumino != NULLFSINO); + error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, &mp->m_rsumip, 0); + if (error) { + vnode_t *rbmvp; /* vnode for bitmap file */ + vmap_t vmap; /* vmap to delete vnode */ + + rbmvp = XFS_ITOV(mp->m_rbmip); + VMAP(rbmvp, mp->m_rbmip, vmap); + VN_RELE(rbmvp); + vn_purge(rbmvp, &vmap); + return error; + } + ASSERT(mp->m_rsumip != NULL); + return 0; +} + +/* + * Pick an extent for allocation at the start of a new realtime file. + * Use the sequence number stored in the atime field of the bitmap inode. + * Translate this to a fraction of the rtextents, and return the product + * of rtextents and the fraction. + * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... + */ +int /* error */ +xfs_rtpick_extent( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_extlen_t len, /* allocation length (rtextents) */ + xfs_rtblock_t *pick) /* result rt extent */ +{ + xfs_rtblock_t b; /* result block */ + int error; /* error return value */ + xfs_inode_t *ip; /* bitmap incore inode */ + int log2; /* log of sequence number */ + __uint64_t resid; /* residual after log removed */ + __uint64_t seq; /* sequence number of file creation */ + __uint64_t *seqp; /* pointer to seqno in inode */ + + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + if (error) + return error; + ASSERT(ip == mp->m_rbmip); + seqp = (__uint64_t *)&ip->i_d.di_atime; + if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) { + ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; + *seqp = 0; + } + seq = *seqp; + if ((log2 = xfs_highbit64(seq)) == -1) + b = 0; + else { + resid = seq - (1ULL << log2); + b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >> + (log2 + 1); + if (b >= mp->m_sb.sb_rextents) + b = do_mod(b, mp->m_sb.sb_rextents); + if (b + len > mp->m_sb.sb_rextents) + b = mp->m_sb.sb_rextents - len; + } + *seqp = seq + 1; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + *pick = b; + return 0; +} + +#ifdef DEBUG +/* + * Debug code: print out the value of a range in the bitmap. + */ +void +xfs_rtprint_range( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to print */ + xfs_extlen_t len) /* length to print */ +{ + xfs_extlen_t i; /* block number in the extent */ + + printk("%Ld: ", (long long)start); + for (i = 0; i < len; i++) + printk("%d", xfs_rtcheck_bit(mp, tp, start + i, 1)); + printk("\n"); +} + +/* + * Debug code: print the summary file. + */ +void +xfs_rtprint_summary( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp) /* transaction pointer */ +{ + xfs_suminfo_t c; /* summary data */ + xfs_rtblock_t i; /* bitmap block number */ + int l; /* summary information level */ + int p; /* flag for printed anything */ + xfs_fsblock_t sb; /* summary block number */ + xfs_buf_t *sumbp; /* summary block buffer */ + + sumbp = NULL; + for (l = 0; l < mp->m_rsumlevels; l++) { + for (p = 0, i = 0; i < mp->m_sb.sb_rbmblocks; i++) { + (void)xfs_rtget_summary(mp, tp, l, i, &sumbp, &sb, &c); + if (c) { + if (!p) { + printk("%Ld-%Ld:", 1LL << l, + XFS_RTMIN((1LL << l) + + ((1LL << l) - 1LL), + mp->m_sb.sb_rextents)); + p = 1; + } + printk(" %Ld:%d", (long long)i, c); + } + } + if (p) + printk("\n"); + } + if (sumbp) + xfs_trans_brelse(tp, sumbp); +} +#endif /* DEBUG */ diff -Nur linux-2.4.19/fs/xfs/xfs_rtalloc.h linux-2.4.19-sgi211r3/fs/xfs/xfs_rtalloc.h --- linux-2.4.19/fs/xfs/xfs_rtalloc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_rtalloc.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_RTALLOC_H__ +#define __XFS_RTALLOC_H__ + +struct xfs_mount; +struct xfs_trans; + +/* Min and max rt extent sizes, specified in bytes */ +#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ +#define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64KB */ +#define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4KB */ + +/* + * Constants for bit manipulations. + */ +#define XFS_NBBYLOG 3 /* log2(NBBY) */ +#define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ +#define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) +#define XFS_NBWORD (1 << XFS_NBWORDLOG) +#define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) + +#define XFS_BLOCKSIZE(mp) ((mp)->m_sb.sb_blocksize) +#define XFS_BLOCKMASK(mp) ((mp)->m_blockmask) +#define XFS_BLOCKWSIZE(mp) ((mp)->m_blockwsize) +#define XFS_BLOCKWMASK(mp) ((mp)->m_blockwmask) + +/* + * Summary and bit manipulation macros. + */ +#define XFS_SUMOFFS(mp,ls,bb) ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb))) +#define XFS_SUMOFFSTOBLOCK(mp,s) \ + (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog) +#define XFS_SUMPTR(mp,bp,so) \ + ((xfs_suminfo_t *)((char *)XFS_BUF_PTR(bp) + \ + (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp)))) + +#define XFS_BITTOBLOCK(mp,bi) ((bi) >> (mp)->m_blkbit_log) +#define XFS_BLOCKTOBIT(mp,bb) ((bb) << (mp)->m_blkbit_log) +#define XFS_BITTOWORD(mp,bi) \ + ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp))) + +#define XFS_RTMIN(a,b) ((a) < (b) ? (a) : (b)) +#define XFS_RTMAX(a,b) ((a) > (b) ? (a) : (b)) + +#define XFS_RTLOBIT(w) xfs_lowbit32(w) +#define XFS_RTHIBIT(w) xfs_highbit32(w) + +#if XFS_BIG_FILESYSTEMS +#define XFS_RTBLOCKLOG(b) xfs_highbit64(b) +#else +#define XFS_RTBLOCKLOG(b) xfs_highbit32(b) +#endif + + +#ifdef __KERNEL__ + +#ifdef CONFIG_XFS_RT +/* + * Function prototypes for exported functions. + */ + +/* + * Allocate an extent in the realtime subvolume, with the usual allocation + * parameters. The length units are all in realtime extents, as is the + * result block number. + */ +int /* error */ +xfs_rtallocate_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_alloctype_t type, /* allocation type XFS_ALLOCTYPE... */ + int wasdel, /* was a delayed allocation extent */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock); /* out: start block allocated */ + +/* + * Free an extent in the realtime subvolume. Length is expressed in + * realtime extents, as is the block number. + */ +int /* error */ +xfs_rtfree_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to free */ + xfs_extlen_t len); /* length of extent freed */ + +/* + * Initialize realtime fields in the mount structure. + */ +int /* error */ +xfs_rtmount_init( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Get the bitmap and summary inodes into the mount structure + * at mount time. + */ +int /* error */ +xfs_rtmount_inodes( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Pick an extent for allocation at the start of a new realtime file. + * Use the sequence number stored in the atime field of the bitmap inode. + * Translate this to a fraction of the rtextents, and return the product + * of rtextents and the fraction. + * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... + */ +int /* error */ +xfs_rtpick_extent( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_extlen_t len, /* allocation length (rtextents) */ + xfs_rtblock_t *pick); /* result rt extent */ + +/* + * Debug code: print out the value of a range in the bitmap. + */ +void +xfs_rtprint_range( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to print */ + xfs_extlen_t len); /* length to print */ + +/* + * Debug code: print the summary file. + */ +void +xfs_rtprint_summary( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp); /* transaction pointer */ + +/* + * Grow the realtime area of the filesystem. + */ +int +xfs_growfs_rt( + struct xfs_mount *mp, /* file system mount structure */ + xfs_growfs_rt_t *in); /* user supplied growfs struct */ + +#else +# define xfs_rtallocate_extent(t,b,min,max,l,a,f,p,rb) (ENOSYS) +# define xfs_rtfree_extent(t,b,l) (ENOSYS) +# define xfs_rtpick_extent(m,t,l,rb) (ENOSYS) +# define xfs_growfs_rt(mp,in) (ENOSYS) +# define xfs_rtmount_init(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS)) +# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS)) +#endif /* CONFIG_XFS_RT */ + +#endif /* __KERNEL__ */ + +#endif /* __XFS_RTALLOC_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_rw.c linux-2.4.19-sgi211r3/fs/xfs/xfs_rw.c --- linux-2.4.19/fs/xfs/xfs_rw.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_rw.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * This is a subroutine for xfs_write() and other writers (xfs_ioctl) + * which clears the setuid and setgid bits when a file is written. + */ +int +xfs_write_clear_setuid( + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + xfs_trans_t *tp; + int error; + + mp = ip->i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); + if ((error = xfs_trans_reserve(tp, 0, + XFS_WRITEID_LOG_RES(mp), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + ip->i_d.di_mode &= ~ISUID; + + /* + * Note that we don't have to worry about mandatory + * file locking being disabled here because we only + * clear the ISGID bit if the Group execute bit is + * on, but if it was on then mandatory locking wouldn't + * have been enabled. + */ + if (ip->i_d.di_mode & (IEXEC >> 3)) { + ip->i_d.di_mode &= ~ISGID; + } + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return 0; +} + +/* + * Force a shutdown of the filesystem instantly while keeping + * the filesystem consistent. We don't do an unmount here; just shutdown + * the shop, make sure that absolutely nothing persistent happens to + * this filesystem after this point. + */ + +void +xfs_do_force_shutdown( + bhv_desc_t *bdp, + int flags, + char *fname, + int lnnum) +{ + int logerror; + xfs_mount_t *mp; + + mp = XFS_BHVTOM(bdp); + logerror = flags & XFS_LOG_IO_ERROR; + + if (!(flags & XFS_FORCE_UMOUNT)) { + cmn_err(CE_NOTE, + "xfs_force_shutdown(%s,0x%x) called from line %d of file %s. Return address = 0x%x", + mp->m_fsname,flags,lnnum,fname,__return_address); + } + /* + * No need to duplicate efforts. + */ + if (XFS_FORCED_SHUTDOWN(mp) && !logerror) + return; + + /* + * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't + * queue up anybody new on the log reservations, and wakes up + * everybody who's sleeping on log reservations and tells + * them the bad news. + */ + if (xfs_log_force_umount(mp, logerror)) + return; + + if (flags & XFS_CORRUPT_INCORE) { + cmn_err(CE_ALERT, + "Corruption of in-memory data detected. Shutting down filesystem: %s", + mp->m_fsname); + } else if (!(flags & XFS_FORCE_UMOUNT)) { + if (logerror) { + cmn_err(CE_ALERT, + "Log I/O Error Detected. Shutting down filesystem: %s", + mp->m_fsname); + } else if (!(flags & XFS_SHUTDOWN_REMOTE_REQ)) { + cmn_err(CE_ALERT, + "I/O Error Detected. Shutting down filesystem: %s", + mp->m_fsname); + } + } + if (!(flags & XFS_FORCE_UMOUNT)) { + cmn_err(CE_ALERT, + "Please umount the filesystem, and rectify the problem(s)"); + } +} + + +/* + * Called when we want to stop a buffer from getting written or read. + * We attach the EIO error, muck with its flags, and call biodone + * so that the proper iodone callbacks get called. + */ +int +xfs_bioerror( + xfs_buf_t *bp) +{ + +#ifdef XFSERRORDEBUG + ASSERT(XFS_BUF_ISREAD(bp) || bp->b_iodone); +#endif + + /* + * No need to wait until the buffer is unpinned. + * We aren't flushing it. + */ + xfs_buftrace("XFS IOERROR", bp); + XFS_BUF_ERROR(bp, EIO); + /* + * We're calling biodone, so delete B_DONE flag. Either way + * we have to call the iodone callback, and calling biodone + * probably is the best way since it takes care of + * GRIO as well. + */ + XFS_BUF_UNREAD(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_UNDONE(bp); + XFS_BUF_STALE(bp); + + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + xfs_biodone(bp); + + return (EIO); +} + +/* + * Same as xfs_bioerror, except that we are releasing the buffer + * here ourselves, and avoiding the biodone call. + * This is meant for userdata errors; metadata bufs come with + * iodone functions attached, so that we can track down errors. + */ +int +xfs_bioerror_relse( + xfs_buf_t *bp) +{ + int64_t fl; + + ASSERT(XFS_BUF_IODONE_FUNC(bp) != xfs_buf_iodone_callbacks); + ASSERT(XFS_BUF_IODONE_FUNC(bp) != xlog_iodone); + + xfs_buftrace("XFS IOERRELSE", bp); + fl = XFS_BUF_BFLAGS(bp); + /* + * No need to wait until the buffer is unpinned. + * We aren't flushing it. + * + * chunkhold expects B_DONE to be set, whether + * we actually finish the I/O or not. We don't want to + * change that interface. + */ + XFS_BUF_UNREAD(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_DONE(bp); + XFS_BUF_STALE(bp); + XFS_BUF_CLR_IODONE_FUNC(bp); + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + if (!(fl & XFS_B_ASYNC)) { + /* + * Mark b_error and B_ERROR _both_. + * Lot's of chunkcache code assumes that. + * There's no reason to mark error for + * ASYNC buffers. + */ + XFS_BUF_ERROR(bp, EIO); + XFS_BUF_V_IODONESEMA(bp); + } else { + xfs_buf_relse(bp); + } + return (EIO); +} +/* + * Prints out an ALERT message about I/O error. + */ +void +xfs_ioerror_alert( + char *func, + struct xfs_mount *mp, + xfs_buf_t *bp, + xfs_daddr_t blkno) +{ + cmn_err(CE_ALERT, + "I/O error in filesystem (\"%s\") meta-data dev 0x%x block 0x%llx" + " (\"%s\") error %d buf count %u", + (!mp || !mp->m_fsname) ? "(fs name not set)" : mp->m_fsname, + XFS_BUF_TARGET_DEV(bp), + (__uint64_t)blkno, + func, + XFS_BUF_GETERROR(bp), + XFS_BUF_COUNT(bp)); +} + +/* + * This isn't an absolute requirement, but it is + * just a good idea to call xfs_read_buf instead of + * directly doing a read_buf call. For one, we shouldn't + * be doing this disk read if we are in SHUTDOWN state anyway, + * so this stops that from happening. Secondly, this does all + * the error checking stuff and the brelse if appropriate for + * the caller, so the code can be a little leaner. + */ + +int +xfs_read_buf( + struct xfs_mount *mp, + xfs_buftarg_t *target, + xfs_daddr_t blkno, + int len, + uint flags, + xfs_buf_t **bpp) +{ + xfs_buf_t *bp; + int error; + + if (flags) + bp = xfs_buf_read_flags(target, blkno, len, flags); + else + bp = xfs_buf_read(target, blkno, len, flags); + if (!bp) + return XFS_ERROR(EIO); + error = XFS_BUF_GETERROR(bp); + if (bp && !error && !XFS_FORCED_SHUTDOWN(mp)) { + *bpp = bp; + } else { + *bpp = NULL; + if (error) { + xfs_ioerror_alert("xfs_read_buf", mp, bp, XFS_BUF_ADDR(bp)); + } else { + error = XFS_ERROR(EIO); + } + if (bp) { + XFS_BUF_UNDONE(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_STALE(bp); + /* + * brelse clears B_ERROR and b_error + */ + xfs_buf_relse(bp); + } + } + return (error); +} + +/* + * Wrapper around bwrite() so that we can trap + * write errors, and act accordingly. + */ +int +xfs_bwrite( + struct xfs_mount *mp, + struct xfs_buf *bp) +{ + int error; + + /* + * XXXsup how does this work for quotas. + */ + XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); + XFS_BUF_SET_FSPRIVATE3(bp, mp); + XFS_BUF_WRITE(bp); + + if ((error = XFS_bwrite(bp))) { + ASSERT(mp); + /* + * Cannot put a buftrace here since if the buffer is not + * B_HOLD then we will brelse() the buffer before returning + * from bwrite and we could be tracing a buffer that has + * been reused. + */ + xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); + } + return (error); +} + +/* + * xfs_inval_cached_pages() + * This routine is responsible for keeping direct I/O and buffered I/O + * somewhat coherent. From here we make sure that we're at least + * temporarily holding the inode I/O lock exclusively and then call + * the page cache to flush and invalidate any cached pages. If there + * are no cached pages this routine will be very quick. + */ +void +xfs_inval_cached_pages( + vnode_t *vp, + xfs_iocore_t *io, + xfs_off_t offset, + int write, + int relock) +{ + xfs_mount_t *mp; + + if (!VN_CACHED(vp)) { + return; + } + + mp = io->io_mount; + + /* + * We need to get the I/O lock exclusively in order + * to safely invalidate pages and mappings. + */ + if (relock) { + XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED); + XFS_ILOCK(mp, io, XFS_IOLOCK_EXCL); + } + + /* Writing beyond EOF creates a hole that must be zeroed */ + if (write && (offset > XFS_SIZE(mp, io))) { + xfs_fsize_t isize; + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + isize = XFS_SIZE(mp, io); + if (offset > isize) { + xfs_zero_eof(vp, io, offset, isize, offset, NULL); + } + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + } + + VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED); + if (relock) { + XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL); + } +} + + + +spinlock_t xfs_refcache_lock = SPIN_LOCK_UNLOCKED; +xfs_inode_t **xfs_refcache; +int xfs_refcache_size; +int xfs_refcache_index; +int xfs_refcache_busy; +int xfs_refcache_count; + +/* + * Timer callback to mark SB dirty, make sure we keep purging refcache + */ +void +xfs_refcache_sbdirty(struct super_block *sb) +{ + sb->s_dirt = 1; +} + +/* + * Insert the given inode into the reference cache. + */ +void +xfs_refcache_insert( + xfs_inode_t *ip) +{ + vnode_t *vp; + xfs_inode_t *release_ip; + xfs_inode_t **refcache; + + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE)); + + /* + * If an unmount is busy blowing entries out of the cache, + * then don't bother. + */ + if (xfs_refcache_busy) { + return; + } + + /* + * If we tuned the refcache down to zero, don't do anything. + */ + if (!xfs_refcache_size) { + return; + } + + /* + * The inode is already in the refcache, so don't bother + * with it. + */ + if (ip->i_refcache != NULL) { + return; + } + + vp = XFS_ITOV(ip); + /* ASSERT(vp->v_count > 0); */ + VN_HOLD(vp); + + /* + * We allocate the reference cache on use so that we don't + * waste the memory on systems not being used as NFS servers. + */ + if (xfs_refcache == NULL) { + refcache = (xfs_inode_t **)kmem_zalloc(XFS_REFCACHE_SIZE_MAX * + sizeof(xfs_inode_t *), + KM_SLEEP); + } else { + refcache = NULL; + } + + spin_lock(&xfs_refcache_lock); + + /* + * If we allocated memory for the refcache above and it still + * needs it, then use the memory we allocated. Otherwise we'll + * free the memory below. + */ + if (refcache != NULL) { + if (xfs_refcache == NULL) { + xfs_refcache = refcache; + refcache = NULL; + } + } + + /* + * If an unmount is busy clearing out the cache, don't add new + * entries to it. + */ + if (xfs_refcache_busy) { + spin_unlock(&xfs_refcache_lock); + VN_RELE(vp); + /* + * If we allocated memory for the refcache above but someone + * else beat us to using it, then free the memory now. + */ + if (refcache != NULL) { + kmem_free(refcache, + XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *)); + } + return; + } + release_ip = xfs_refcache[xfs_refcache_index]; + if (release_ip != NULL) { + release_ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + } + xfs_refcache[xfs_refcache_index] = ip; + ASSERT(ip->i_refcache == NULL); + ip->i_refcache = &(xfs_refcache[xfs_refcache_index]); + xfs_refcache_count++; + ASSERT(xfs_refcache_count <= xfs_refcache_size); + xfs_refcache_index++; + if (xfs_refcache_index == xfs_refcache_size) { + xfs_refcache_index = 0; + } + spin_unlock(&xfs_refcache_lock); + + /* + * Save the pointer to the inode to be released so that we can + * VN_RELE it once we've dropped our inode locks in xfs_rwunlock(). + * The pointer may be NULL, but that's OK. + */ + ip->i_release = release_ip; + + /* + * If we allocated memory for the refcache above but someone + * else beat us to using it, then free the memory now. + */ + if (refcache != NULL) { + kmem_free(refcache, + XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *)); + } + return; +} + + +/* + * If the given inode is in the reference cache, purge its entry and + * release the reference on the vnode. + */ +void +xfs_refcache_purge_ip( + xfs_inode_t *ip) +{ + vnode_t *vp; + int error; + + /* + * If we're not pointing to our entry in the cache, then + * we must not be in the cache. + */ + if (ip->i_refcache == NULL) { + return; + } + + spin_lock(&xfs_refcache_lock); + if (ip->i_refcache == NULL) { + spin_unlock(&xfs_refcache_lock); + return; + } + + /* + * Clear both our pointer to the cache entry and its pointer + * back to us. + */ + ASSERT(*(ip->i_refcache) == ip); + *(ip->i_refcache) = NULL; + ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + spin_unlock(&xfs_refcache_lock); + + vp = XFS_ITOV(ip); + /* ASSERT(vp->v_count > 1); */ + VOP_RELEASE(vp, error); + VN_RELE(vp); + + return; +} + + +/* + * This is called from the XFS unmount code to purge all entries for the + * given mount from the cache. It uses the refcache busy counter to + * make sure that new entries are not added to the cache as we purge them. + */ +void +xfs_refcache_purge_mp( + xfs_mount_t *mp) +{ + vnode_t *vp; + int error, i; + xfs_inode_t *ip; + + if (xfs_refcache == NULL) { + return; + } + + spin_lock(&xfs_refcache_lock); + /* + * Bumping the busy counter keeps new entries from being added + * to the cache. We use a counter since multiple unmounts could + * be in here simultaneously. + */ + xfs_refcache_busy++; + + for (i = 0; i < xfs_refcache_size; i++) { + ip = xfs_refcache[i]; + if ((ip != NULL) && (ip->i_mount == mp)) { + xfs_refcache[i] = NULL; + ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + spin_unlock(&xfs_refcache_lock); + vp = XFS_ITOV(ip); + VOP_RELEASE(vp, error); + VN_RELE(vp); + spin_lock(&xfs_refcache_lock); + } + } + + xfs_refcache_busy--; + ASSERT(xfs_refcache_busy >= 0); + spin_unlock(&xfs_refcache_lock); +} + + +/* + * This is called from the XFS sync code to ensure that the refcache + * is emptied out over time. We purge a small number of entries with + * each call. + */ +void +xfs_refcache_purge_some(xfs_mount_t *mp) +{ + int error, i; + xfs_inode_t *ip; + int iplist_index; + xfs_inode_t **iplist; + int purge_count; + + if ((xfs_refcache == NULL) || (xfs_refcache_count == 0)) { + return; + } + + iplist_index = 0; + purge_count = xfs_params.refcache_purge; + iplist = (xfs_inode_t **)kmem_zalloc(purge_count * + sizeof(xfs_inode_t *), KM_SLEEP); + + spin_lock(&xfs_refcache_lock); + + /* + * Store any inodes we find in the next several entries + * into the iplist array to be released after dropping + * the spinlock. We always start looking from the currently + * oldest place in the cache. We move the refcache index + * forward as we go so that we are sure to eventually clear + * out the entire cache when the system goes idle. + */ + for (i = 0; i < purge_count; i++) { + ip = xfs_refcache[xfs_refcache_index]; + if (ip != NULL) { + xfs_refcache[xfs_refcache_index] = NULL; + ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + iplist[iplist_index] = ip; + iplist_index++; + } + xfs_refcache_index++; + if (xfs_refcache_index == xfs_refcache_size) { + xfs_refcache_index = 0; + } + } + + spin_unlock(&xfs_refcache_lock); + + /* + * If there are still entries in the refcache, + * set timer to mark the SB dirty to make sure that + * we hit sync even if filesystem is idle, so that we'll + * purge some more later. + */ + if (xfs_refcache_count) { + del_timer_sync(&mp->m_sbdirty_timer); + mp->m_sbdirty_timer.data = + (unsigned long)LINVFS_GET_IP(XFS_ITOV(mp->m_rootip))->i_sb; + mp->m_sbdirty_timer.expires = jiffies + 2*HZ; + add_timer(&mp->m_sbdirty_timer); + } + + /* + * Now drop the inodes we collected. + */ + for (i = 0; i < iplist_index; i++) { + VOP_RELEASE(XFS_ITOV(iplist[i]), error); + VN_RELE(XFS_ITOV(iplist[i])); + } + + kmem_free(iplist, purge_count * + sizeof(xfs_inode_t *)); +} + +/* + * This is called when the refcache is dynamically resized + * via a sysctl. + * + * If the new size is smaller than the old size, purge all + * entries in slots greater than the new size, and move + * the index if necessary. + * + * If the refcache hasn't even been allocated yet, or the + * new size is larger than the old size, just set the value + * of xfs_refcache_size. + */ + +void +xfs_refcache_resize(int xfs_refcache_new_size) +{ + int i; + xfs_inode_t *ip; + int iplist_index = 0; + xfs_inode_t **iplist; + int error; + + /* + * If the new size is smaller than the current size, + * purge entries to create smaller cache, and + * reposition index if necessary. + * Don't bother if no refcache yet. + */ + if (xfs_refcache && (xfs_refcache_new_size < xfs_refcache_size)) { + + iplist = (xfs_inode_t **)kmem_zalloc(XFS_REFCACHE_SIZE_MAX * + sizeof(xfs_inode_t *), KM_SLEEP); + + spin_lock(&xfs_refcache_lock); + + for (i = xfs_refcache_new_size; i < xfs_refcache_size; i++) { + ip = xfs_refcache[i]; + if (ip != NULL) { + xfs_refcache[i] = NULL; + ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + iplist[iplist_index] = ip; + iplist_index++; + } + } + + xfs_refcache_size = xfs_refcache_new_size; + + /* + * Move index to beginning of cache if it's now past the end + */ + if (xfs_refcache_index >= xfs_refcache_new_size) + xfs_refcache_index = 0; + + spin_unlock(&xfs_refcache_lock); + + /* + * Now drop the inodes we collected. + */ + for (i = 0; i < iplist_index; i++) { + VOP_RELEASE(XFS_ITOV(iplist[i]), error); + VN_RELE(XFS_ITOV(iplist[i])); + } + + kmem_free(iplist, XFS_REFCACHE_SIZE_MAX * + sizeof(xfs_inode_t *)); + } else { + spin_lock(&xfs_refcache_lock); + xfs_refcache_size = xfs_refcache_new_size; + spin_unlock(&xfs_refcache_lock); + } +} diff -Nur linux-2.4.19/fs/xfs/xfs_rw.h linux-2.4.19-sgi211r3/fs/xfs/xfs_rw.h --- linux-2.4.19/fs/xfs/xfs_rw.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_rw.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_RW_H__ +#define __XFS_RW_H__ + +struct bhv_desc; +struct bmapval; +struct xfs_buf; +struct cred; +struct uio; +struct vnode; +struct xfs_inode; +struct xfs_iocore; +struct xfs_mount; +struct xfs_trans; +struct xfs_dio; +struct pm; + +/* + * Maximum count of bmaps used by read and write paths. + */ +#define XFS_MAX_RW_NBMAPS 4 + +/* + * Counts of readahead buffers to use based on physical memory size. + * None of these should be more than XFS_MAX_RW_NBMAPS. + */ +#define XFS_RW_NREADAHEAD_16MB 2 +#define XFS_RW_NREADAHEAD_32MB 3 +#define XFS_RW_NREADAHEAD_K32 4 +#define XFS_RW_NREADAHEAD_K64 4 + +/* + * Maximum size of a buffer that we\'ll map. Making this + * too big will degrade performance due to the number of + * pages which need to be gathered. Making it too small + * will prevent us from doing large I/O\'s to hardware that + * needs it. + * + * This is currently set to 512 KB. + */ +#define XFS_MAX_BMAP_LEN_BB 1024 +#define XFS_MAX_BMAP_LEN_BYTES 524288 + +/* + * Maximum size (in inodes) for the nfs refcache + */ +#define XFS_REFCACHE_SIZE_MAX 512 + + +/* + * Convert the given file system block to a disk block. + * We have to treat it differently based on whether the + * file is a real time file or not, because the bmap code + * does. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_DB) +xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb); +#define XFS_FSB_TO_DB(ip,fsb) xfs_fsb_to_db(ip,fsb) +#else +#define XFS_FSB_TO_DB(ip,fsb) \ + (((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) ? \ + (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \ + XFS_FSB_TO_DADDR((ip)->i_mount, (fsb))) +#endif + +#define XFS_FSB_TO_DB_IO(io,fsb) \ + (((io)->io_flags & XFS_IOCORE_RT) ? \ + XFS_FSB_TO_BB((io)->io_mount, (fsb)) : \ + XFS_FSB_TO_DADDR((io)->io_mount, (fsb))) + +/* + * Defines for the trace mechanisms in xfs_rw.c. + */ +#define XFS_RW_KTRACE_SIZE 64 +#define XFS_STRAT_KTRACE_SIZE 64 +#define XFS_STRAT_GTRACE_SIZE 512 + +#define XFS_READ_ENTER 1 +#define XFS_WRITE_ENTER 2 +#define XFS_IOMAP_READ_ENTER 3 +#define XFS_IOMAP_WRITE_ENTER 4 +#define XFS_IOMAP_READ_MAP 5 +#define XFS_IOMAP_WRITE_MAP 6 +#define XFS_IOMAP_WRITE_NOSPACE 7 +#define XFS_ITRUNC_START 8 +#define XFS_ITRUNC_FINISH1 9 +#define XFS_ITRUNC_FINISH2 10 +#define XFS_CTRUNC1 11 +#define XFS_CTRUNC2 12 +#define XFS_CTRUNC3 13 +#define XFS_CTRUNC4 14 +#define XFS_CTRUNC5 15 +#define XFS_CTRUNC6 16 +#define XFS_BUNMAPI 17 +#define XFS_INVAL_CACHED 18 +#define XFS_DIORD_ENTER 19 +#define XFS_DIOWR_ENTER 20 + +#if defined(XFS_ALL_TRACE) +#define XFS_RW_TRACE +#define XFS_STRAT_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_RW_TRACE +#undef XFS_STRAT_TRACE +#endif + +/* + * Prototypes for functions in xfs_rw.c. + */ + +int +xfs_write_clear_setuid( + struct xfs_inode *ip); + +int +xfs_bwrite( + struct xfs_mount *mp, + struct xfs_buf *bp); + +void +xfs_inval_cached_pages( + struct vnode *vp, + struct xfs_iocore *io, + xfs_off_t offset, + int write, + int relock); + +void +xfs_refcache_insert( + struct xfs_inode *ip); + +void +xfs_refcache_purge_ip( + struct xfs_inode *ip); + +void +xfs_refcache_purge_mp( + struct xfs_mount *mp); + +void +xfs_refcache_purge_some( + struct xfs_mount *mp); + +void +xfs_refcache_resize( + int xfs_refcache_new_size); + +int +xfs_bioerror( + struct xfs_buf *b); + +/* + * XFS I/O core functions + */ +extern int xfs_bioerror_relse(struct xfs_buf *); + + +/* + * Needed by xfs_rw.c + */ +int +xfs_rwlock( + bhv_desc_t *bdp, + vrwlock_t write_lock); + +void +xfs_rwunlock( + bhv_desc_t *bdp, + vrwlock_t write_lock); + +int +xfs_read_buf( + struct xfs_mount *mp, + xfs_buftarg_t *target, + xfs_daddr_t blkno, + int len, + uint flags, + struct xfs_buf **bpp); + +void +xfs_ioerror_alert( + char *func, + struct xfs_mount *mp, + xfs_buf_t *bp, + xfs_daddr_t blkno); + +#endif /* __XFS_RW_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_sb.h linux-2.4.19-sgi211r3/fs/xfs/xfs_sb.h --- linux-2.4.19/fs/xfs/xfs_sb.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_sb.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SB_H__ +#define __XFS_SB_H__ + +/* + * Super block + * Fits into a 512-byte buffer at daddr_t 0 of each allocation group. + * Only the first of these is ever updated except during growfs. + */ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ +#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ +#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ +#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ +#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ +#define XFS_SB_VERSION_NUMBITS 0x000f +#define XFS_SB_VERSION_ALLFBITS 0xfff0 +#define XFS_SB_VERSION_SASHFBITS 0xf000 +#define XFS_SB_VERSION_REALFBITS 0x0ff0 +#define XFS_SB_VERSION_ATTRBIT 0x0010 +#define XFS_SB_VERSION_NLINKBIT 0x0020 +#define XFS_SB_VERSION_QUOTABIT 0x0040 +#define XFS_SB_VERSION_ALIGNBIT 0x0080 +#define XFS_SB_VERSION_DALIGNBIT 0x0100 +#define XFS_SB_VERSION_SHAREDBIT 0x0200 +#define XFS_SB_VERSION_LOGV2BIT 0x0400 +#define XFS_SB_VERSION_EXTFLGBIT 0x1000 +#define XFS_SB_VERSION_DIRV2BIT 0x2000 +#define XFS_SB_VERSION_OKSASHFBITS \ + (XFS_SB_VERSION_EXTFLGBIT | \ + XFS_SB_VERSION_DIRV2BIT) +#define XFS_SB_VERSION_OKREALFBITS \ + (XFS_SB_VERSION_ATTRBIT | \ + XFS_SB_VERSION_NLINKBIT | \ + XFS_SB_VERSION_QUOTABIT | \ + XFS_SB_VERSION_ALIGNBIT | \ + XFS_SB_VERSION_DALIGNBIT | \ + XFS_SB_VERSION_SHAREDBIT | \ + XFS_SB_VERSION_LOGV2BIT) +#define XFS_SB_VERSION_OKSASHBITS \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_REALFBITS | \ + XFS_SB_VERSION_OKSASHFBITS) +#define XFS_SB_VERSION_OKREALBITS \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_OKREALFBITS | \ + XFS_SB_VERSION_OKSASHFBITS) +#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2,na) \ + (((ia) || (dia) || (extflag) || (dirv2) || (na)) ? \ + (XFS_SB_VERSION_4 | \ + ((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \ + ((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \ + ((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \ + ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0) | \ + ((na) ? XFS_SB_VERSION_LOGV2BIT : 0)) : \ + XFS_SB_VERSION_1) + +typedef struct xfs_sb +{ + __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ + __uint32_t sb_blocksize; /* logical block size, bytes */ + xfs_drfsbno_t sb_dblocks; /* number of data blocks */ + xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */ + xfs_drtbno_t sb_rextents; /* number of realtime extents */ + uuid_t sb_uuid; /* file system unique id */ + xfs_dfsbno_t sb_logstart; /* starting block of log if internal */ + xfs_ino_t sb_rootino; /* root inode number */ + xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ + xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ + xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ + xfs_agblock_t sb_agblocks; /* size of an allocation group */ + xfs_agnumber_t sb_agcount; /* number of allocation groups */ + xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ + xfs_extlen_t sb_logblocks; /* number of log blocks */ + __uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ + __uint16_t sb_sectsize; /* volume sector size, bytes */ + __uint16_t sb_inodesize; /* inode size, bytes */ + __uint16_t sb_inopblock; /* inodes per block */ + char sb_fname[12]; /* file system name */ + __uint8_t sb_blocklog; /* log2 of sb_blocksize */ + __uint8_t sb_sectlog; /* log2 of sb_sectsize */ + __uint8_t sb_inodelog; /* log2 of sb_inodesize */ + __uint8_t sb_inopblog; /* log2 of sb_inopblock */ + __uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ + __uint8_t sb_rextslog; /* log2 of sb_rextents */ + __uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ + __uint8_t sb_imax_pct; /* max % of fs for inode space */ + /* statistics */ + /* + * These fields must remain contiguous. If you really + * want to change their layout, make sure you fix the + * code in xfs_trans_apply_sb_deltas(). + */ + __uint64_t sb_icount; /* allocated inodes */ + __uint64_t sb_ifree; /* free inodes */ + __uint64_t sb_fdblocks; /* free data blocks */ + __uint64_t sb_frextents; /* free realtime extents */ + /* + * End contiguous fields. + */ + xfs_ino_t sb_uquotino; /* user quota inode */ + xfs_ino_t sb_gquotino; /* group quota inode */ + __uint16_t sb_qflags; /* quota flags */ + __uint8_t sb_flags; /* misc. flags */ + __uint8_t sb_shared_vn; /* shared version number */ + xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ + __uint32_t sb_unit; /* stripe or raid unit */ + __uint32_t sb_width; /* stripe or raid width */ + __uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ + __uint8_t sb_dummy[3]; /* padding */ + __uint32_t sb_logsunit; /* stripe unit size for the log */ +} xfs_sb_t; + +/* + * Sequence number values for the fields. + */ +typedef enum { + XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS, + XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO, + XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS, + XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS, + XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE, + XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG, + XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG, + XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT, + XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO, + XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN, + XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG, + XFS_SBS_DUMMY, XFS_SBS_LOGSUNIT, + XFS_SBS_FIELDCOUNT +} xfs_sb_field_t; + +/* + * Mask values, defined based on the xfs_sb_field_t values. + * Only define the ones we're using. + */ +#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x) +#define XFS_SB_UUID XFS_SB_MVAL(UUID) +#define XFS_SB_FNAME XFS_SB_MVAL(FNAME) +#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO) +#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO) +#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO) +#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM) +#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO) +#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO) +#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS) +#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN) +#define XFS_SB_UNIT XFS_SB_MVAL(UNIT) +#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH) +#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT) +#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1) +#define XFS_SB_MOD_BITS \ + (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \ + XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \ + XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH) + +/* + * Misc. Flags - warning - these will be cleared by xfs_repair unless + * a feature bit is set when the flag is used. + */ +#define XFS_SBF_NOFLAGS 0x00 /* no flags set */ +#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */ + +/* + * define max. shared version we can interoperate with + */ +#define XFS_SB_MAX_SHARED_VN 0 + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_NUM) +int xfs_sb_version_num(xfs_sb_t *sbp); +#define XFS_SB_VERSION_NUM(sbp) xfs_sb_version_num(sbp) +#else +#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_GOOD_VERSION) +int xfs_sb_good_version(xfs_sb_t *sbp); +#define XFS_SB_GOOD_VERSION(sbp) xfs_sb_good_version(sbp) +#else +#define XFS_SB_GOOD_VERSION_INT(sbp) \ + ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) +#ifdef __KERNEL__ +#define XFS_SB_GOOD_VERSION(sbp) \ + (XFS_SB_GOOD_VERSION_INT(sbp) && \ + (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN) )) +#else +/* + * extra 2 paren's here (( to unconfuse paren-matching editors + * like vi because XFS_SB_GOOD_VERSION_INT is a partial expression + * and the two XFS_SB_GOOD_VERSION's each 2 more close paren's to + * complete the expression. + */ +#define XFS_SB_GOOD_VERSION(sbp) \ + (XFS_SB_GOOD_VERSION_INT(sbp) && \ + (!((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) || \ + (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN)) )) +#endif /* __KERNEL__ */ +#endif + +#define XFS_SB_GOOD_SASH_VERSION(sbp) \ + ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKSASHBITS))) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TONEW) +unsigned xfs_sb_version_tonew(unsigned v); +#define XFS_SB_VERSION_TONEW(v) xfs_sb_version_tonew(v) +#else +#define XFS_SB_VERSION_TONEW(v) \ + ((((v) == XFS_SB_VERSION_1) ? \ + 0 : \ + (((v) == XFS_SB_VERSION_2) ? \ + XFS_SB_VERSION_ATTRBIT : \ + (XFS_SB_VERSION_ATTRBIT | XFS_SB_VERSION_NLINKBIT))) | \ + XFS_SB_VERSION_4) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TOOLD) +unsigned xfs_sb_version_toold(unsigned v); +#define XFS_SB_VERSION_TOOLD(v) xfs_sb_version_toold(v) +#else +#define XFS_SB_VERSION_TOOLD(v) \ + (((v) & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT)) ? \ + 0 : \ + (((v) & XFS_SB_VERSION_NLINKBIT) ? \ + XFS_SB_VERSION_3 : \ + (((v) & XFS_SB_VERSION_ATTRBIT) ? \ + XFS_SB_VERSION_2 : \ + XFS_SB_VERSION_1))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASATTR) +int xfs_sb_version_hasattr(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASATTR(sbp) xfs_sb_version_hasattr(sbp) +#else +#define XFS_SB_VERSION_HASATTR(sbp) \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_2) || \ + ((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_ATTRBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDATTR) +void xfs_sb_version_addattr(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDATTR(sbp) xfs_sb_version_addattr(sbp) +#else +#define XFS_SB_VERSION_ADDATTR(sbp) \ + ((sbp)->sb_versionnum = \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_1) ? \ + XFS_SB_VERSION_2 : \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) ? \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_ATTRBIT) : \ + (XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT)))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASNLINK) +int xfs_sb_version_hasnlink(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASNLINK(sbp) xfs_sb_version_hasnlink(sbp) +#else +#define XFS_SB_VERSION_HASNLINK(sbp) \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_NLINKBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDNLINK) +void xfs_sb_version_addnlink(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDNLINK(sbp) xfs_sb_version_addnlink(sbp) +#else +#define XFS_SB_VERSION_ADDNLINK(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_2 ? \ + XFS_SB_VERSION_3 : \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_NLINKBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASQUOTA) +int xfs_sb_version_hasquota(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASQUOTA(sbp) xfs_sb_version_hasquota(sbp) +#else +#define XFS_SB_VERSION_HASQUOTA(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_QUOTABIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDQUOTA) +void xfs_sb_version_addquota(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDQUOTA(sbp) xfs_sb_version_addquota(sbp) +#else +#define XFS_SB_VERSION_ADDQUOTA(sbp) \ + ((sbp)->sb_versionnum = \ + (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 ? \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_QUOTABIT) : \ + (XFS_SB_VERSION_TONEW((sbp)->sb_versionnum) | \ + XFS_SB_VERSION_QUOTABIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASALIGN) +int xfs_sb_version_hasalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASALIGN(sbp) xfs_sb_version_hasalign(sbp) +#else +#define XFS_SB_VERSION_HASALIGN(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_ALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBALIGN) +void xfs_sb_version_subalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBALIGN(sbp) xfs_sb_version_subalign(sbp) +#else +#define XFS_SB_VERSION_SUBALIGN(sbp) \ + ((sbp)->sb_versionnum = \ + XFS_SB_VERSION_TOOLD((sbp)->sb_versionnum & ~XFS_SB_VERSION_ALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDALIGN) +int xfs_sb_version_hasdalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASDALIGN(sbp) xfs_sb_version_hasdalign(sbp) +#else +#define XFS_SB_VERSION_HASDALIGN(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_DALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDDALIGN) +int xfs_sb_version_adddalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDDALIGN(sbp) xfs_sb_version_adddalign(sbp) +#else +#define XFS_SB_VERSION_ADDDALIGN(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_DALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASSHARED) +int xfs_sb_version_hasshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASSHARED(sbp) xfs_sb_version_hasshared(sbp) +#else +#define XFS_SB_VERSION_HASSHARED(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDSHARED) +int xfs_sb_version_addshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDSHARED(sbp) xfs_sb_version_addshared(sbp) +#else +#define XFS_SB_VERSION_ADDSHARED(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBSHARED) +int xfs_sb_version_subshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBSHARED(sbp) xfs_sb_version_subshared(sbp) +#else +#define XFS_SB_VERSION_SUBSHARED(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum & ~XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDIRV2) +int xfs_sb_version_hasdirv2(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASDIRV2(sbp) xfs_sb_version_hasdirv2(sbp) +#else +#define XFS_SB_VERSION_HASDIRV2(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASLOGV2) +int xfs_sb_version_haslogv2(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASLOGV2(sbp) xfs_sb_version_haslogv2(sbp) +#else +#define XFS_SB_VERSION_HASLOGV2(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_LOGV2BIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT) +int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) xfs_sb_version_hasextflgbit(sbp) +#else +#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDEXTFLGBIT) +int xfs_sb_version_addextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) xfs_sb_version_addextflgbit(sbp) +#else +#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_EXTFLGBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBEXTFLGBIT) +int xfs_sb_version_subextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) xfs_sb_version_subextflgbit(sbp) +#else +#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum & ~XFS_SB_VERSION_EXTFLGBIT)) +#endif + +/* + * end of superblock version macros + */ + +#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_BLOCK) +xfs_agblock_t xfs_sb_block(struct xfs_mount *mp); +#define XFS_SB_BLOCK(mp) xfs_sb_block(mp) +#else +#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_HDR_BLOCK) +xfs_agblock_t xfs_hdr_block(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_HDR_BLOCK(mp,d) xfs_hdr_block(mp,d) +#else +#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp,d))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_FSB) +xfs_fsblock_t xfs_daddr_to_fsb(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_FSB(mp,d) xfs_daddr_to_fsb(mp,d) +#else +#define XFS_DADDR_TO_FSB(mp,d) \ + XFS_AGB_TO_FSB(mp, XFS_DADDR_TO_AGNO(mp,d), XFS_DADDR_TO_AGBNO(mp,d)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_DADDR) +xfs_daddr_t xfs_fsb_to_daddr(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_DADDR(mp,fsbno) xfs_fsb_to_daddr(mp,fsbno) +#else +#define XFS_FSB_TO_DADDR(mp,fsbno) \ + XFS_AGB_TO_DADDR(mp, XFS_FSB_TO_AGNO(mp,fsbno), \ + XFS_FSB_TO_AGBNO(mp,fsbno)) +#endif + +/* + * File system block to basic block conversions. + */ +#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log) +#define XFS_BB_TO_FSB(mp,bb) \ + (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log) +#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log) +#define XFS_BB_FSB_OFFSET(mp,bb) ((bb) & ((mp)->m_bsize - 1)) + +/* + * File system block to byte conversions. + */ +#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << \ + (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSB(mp,b) \ + ((((__uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSBT(mp,b) (((__uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBP) +xfs_sb_t *xfs_buf_to_sbp(struct xfs_buf *bp); +#define XFS_BUF_TO_SBP(bp) xfs_buf_to_sbp(bp) +#else +#define XFS_BUF_TO_SBP(bp) ((xfs_sb_t *)XFS_BUF_PTR(bp)) +#endif + +#endif /* __XFS_SB_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_trans.c linux-2.4.19-sgi211r3/fs/xfs/xfs_trans.c --- linux-2.4.19/fs/xfs/xfs_trans.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,1269 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *); +STATIC uint xfs_trans_count_vecs(xfs_trans_t *); +STATIC void xfs_trans_fill_vecs(xfs_trans_t *, xfs_log_iovec_t *); +STATIC void xfs_trans_uncommit(xfs_trans_t *, uint); +STATIC void xfs_trans_committed(xfs_trans_t *, int); +STATIC void xfs_trans_chunk_committed(xfs_log_item_chunk_t *, xfs_lsn_t, int); +STATIC void xfs_trans_free(xfs_trans_t *); + +kmem_zone_t *xfs_trans_zone; + + +/* + * Initialize the precomputed transaction reservation values + * in the mount structure. + */ +void +xfs_trans_init( + xfs_mount_t *mp) +{ + xfs_trans_reservations_t *resp; + + resp = &(mp->m_reservations); + resp->tr_write = + (uint)(XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_itruncate = + (uint)(XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_rename = + (uint)(XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_link = (uint)XFS_CALC_LINK_LOG_RES(mp); + resp->tr_remove = + (uint)(XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_symlink = + (uint)(XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_create = + (uint)(XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_mkdir = + (uint)(XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_ifree = + (uint)(XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_ichange = + (uint)(XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_growdata = (uint)XFS_CALC_GROWDATA_LOG_RES(mp); + resp->tr_swrite = (uint)XFS_CALC_SWRITE_LOG_RES(mp); + resp->tr_writeid = (uint)XFS_CALC_WRITEID_LOG_RES(mp); + resp->tr_addafork = + (uint)(XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_attrinval = (uint)XFS_CALC_ATTRINVAL_LOG_RES(mp); + resp->tr_attrset = + (uint)(XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_attrrm = + (uint)(XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_clearagi = (uint)XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp); + resp->tr_growrtalloc = (uint)XFS_CALC_GROWRTALLOC_LOG_RES(mp); + resp->tr_growrtzero = (uint)XFS_CALC_GROWRTZERO_LOG_RES(mp); + resp->tr_growrtfree = (uint)XFS_CALC_GROWRTFREE_LOG_RES(mp); +} + +/* + * This routine is called to allocate a transaction structure. + * The type parameter indicates the type of the transaction. These + * are enumerated in xfs_trans.h. + * + * Dynamically allocate the transaction structure from the transaction + * zone, initialize it, and return it to the caller. + */ +xfs_trans_t * +xfs_trans_alloc( + xfs_mount_t *mp, + uint type) +{ + xfs_check_frozen(mp, NULL, XFS_FREEZE_TRANS); + return (_xfs_trans_alloc(mp, type)); + +} + +xfs_trans_t * +_xfs_trans_alloc( + xfs_mount_t *mp, + uint type) +{ + xfs_trans_t *tp; + ASSERT(xfs_trans_zone != NULL); + tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); + tp->t_dqinfo = NULL; + + /* + * Initialize the transaction structure. + */ + tp->t_magic = XFS_TRANS_MAGIC; + tp->t_type = type; + tp->t_mountp = mp; + tp->t_items_free = XFS_LIC_NUM_SLOTS; + tp->t_busy_free = XFS_LBC_NUM_SLOTS; + XFS_LIC_INIT(&(tp->t_items)); + XFS_LBC_INIT(&(tp->t_busy)); + + return (tp); +} + +/* + * This is called to create a new transaction which will share the + * permanent log reservation of the given transaction. The remaining + * unused block and rt extent reservations are also inherited. This + * implies that the original transaction is no longer allowed to allocate + * blocks. Locks and log items, however, are no inherited. They must + * be added to the new transaction explicitly. + */ +xfs_trans_t * +xfs_trans_dup( + xfs_trans_t *tp) +{ + xfs_trans_t *ntp; + + ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); + + /* + * Initialize the new transaction structure. + */ + ntp->t_magic = XFS_TRANS_MAGIC; + ntp->t_type = tp->t_type; + ntp->t_mountp = tp->t_mountp; + ntp->t_items_free = XFS_LIC_NUM_SLOTS; + ntp->t_busy_free = XFS_LBC_NUM_SLOTS; + XFS_LIC_INIT(&(ntp->t_items)); + XFS_LBC_INIT(&(ntp->t_busy)); + + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + +#if defined(XLOG_NOLOG) || defined(DEBUG) + ASSERT(!xlog_debug || tp->t_ticket != NULL); +#else + ASSERT(tp->t_ticket != NULL); +#endif + ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE); + ntp->t_ticket = tp->t_ticket; + ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; + tp->t_blk_res = tp->t_blk_res_used; + ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; + tp->t_rtx_res = tp->t_rtx_res_used; + + /* + * dup the dquot stuff too. + */ + if (tp->t_dqinfo) + xfs_trans_dup_dqinfo(tp, ntp); + + atomic_inc(&tp->t_mountp->m_active_trans); + return ntp; +} + +/* + * This is called to reserve free disk blocks and log space for the + * given transaction. This must be done before allocating any resources + * within the transaction. + * + * This will return ENOSPC if there are not enough blocks available. + * It will sleep waiting for available log space. + * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which + * is used by long running transactions. If any one of the reservations + * fails then they will all be backed out. + * + * This does not do quota reservations. That typically is done by the + * caller afterwards. + */ +int +xfs_trans_reserve( + xfs_trans_t *tp, + uint blocks, + uint logspace, + uint rtextents, + uint flags, + uint logcount) +{ + int log_flags; + int error; + int rsvd; + + error = 0; + rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; + + /* Mark this thread as being in a transaction */ + current->flags |= PF_FSTRANS; + + /* + * Attempt to reserve the needed disk blocks by decrementing + * the number needed from the number available. This will + * fail if the count would go below zero. + */ + if (blocks > 0) { + error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, + -blocks, rsvd); + if (error != 0) { + current->flags &= ~PF_FSTRANS; + return (XFS_ERROR(ENOSPC)); + } + tp->t_blk_res += blocks; + } + + /* + * Reserve the log space needed for this transaction. + */ + if (logspace > 0) { + ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace)); + ASSERT((tp->t_log_count == 0) || + (tp->t_log_count == logcount)); + if (flags & XFS_TRANS_PERM_LOG_RES) { + log_flags = XFS_LOG_PERM_RESERV; + tp->t_flags |= XFS_TRANS_PERM_LOG_RES; + } else { + ASSERT(tp->t_ticket == NULL); + ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); + log_flags = 0; + } + + error = xfs_log_reserve(tp->t_mountp, logspace, logcount, + &tp->t_ticket, + XFS_TRANSACTION, log_flags); + if (error) { + goto undo_blocks; + } + tp->t_log_res = logspace; + tp->t_log_count = logcount; + } + + /* + * Attempt to reserve the needed realtime extents by decrementing + * the number needed from the number available. This will + * fail if the count would go below zero. + */ + if (rtextents > 0) { + error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS, + -rtextents, rsvd); + if (error) { + error = XFS_ERROR(ENOSPC); + goto undo_log; + } + tp->t_rtx_res += rtextents; + } + + return 0; + + /* + * Error cases jump to one of these labels to undo any + * reservations which have already been performed. + */ +undo_log: + if (logspace > 0) { + if (flags & XFS_TRANS_PERM_LOG_RES) { + log_flags = XFS_LOG_REL_PERM_RESERV; + } else { + log_flags = 0; + } + xfs_log_done(tp->t_mountp, tp->t_ticket, log_flags); + tp->t_ticket = NULL; + tp->t_log_res = 0; + tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES; + } + +undo_blocks: + if (blocks > 0) { + (void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, + blocks, rsvd); + tp->t_blk_res = 0; + } + + current->flags &= ~PF_FSTRANS; + + return (error); +} + + +/* + * This is called to set the a callback to be called when the given + * transaction is committed to disk. The transaction pointer and the + * argument pointer will be passed to the callback routine. + * + * Only one callback can be associated with any single transaction. + */ +void +xfs_trans_callback( + xfs_trans_t *tp, + xfs_trans_callback_t callback, + void *arg) +{ + ASSERT(tp->t_callback == NULL); + tp->t_callback = callback; + tp->t_callarg = arg; +} + + +/* + * Record the indicated change to the given field for application + * to the file system's superblock when the transaction commits. + * For now, just store the change in the transaction structure. + * + * Mark the transaction structure to indicate that the superblock + * needs to be updated before committing. + */ +void +xfs_trans_mod_sb( + xfs_trans_t *tp, + uint field, + long delta) +{ + + switch (field) { + case XFS_TRANS_SB_ICOUNT: + ASSERT(delta > 0); + tp->t_icount_delta += delta; + break; + case XFS_TRANS_SB_IFREE: + tp->t_ifree_delta += delta; + break; + case XFS_TRANS_SB_FDBLOCKS: + /* + * Track the number of blocks allocated in the + * transaction. Make sure it does not exceed the + * number reserved. + */ + if (delta < 0) { + tp->t_blk_res_used += (uint)-delta; + ASSERT(tp->t_blk_res_used <= tp->t_blk_res); + } + tp->t_fdblocks_delta += delta; + break; + case XFS_TRANS_SB_RES_FDBLOCKS: + /* + * The allocation has already been applied to the + * in-core superblock's counter. This should only + * be applied to the on-disk superblock. + */ + ASSERT(delta < 0); + tp->t_res_fdblocks_delta += delta; + break; + case XFS_TRANS_SB_FREXTENTS: + /* + * Track the number of blocks allocated in the + * transaction. Make sure it does not exceed the + * number reserved. + */ + if (delta < 0) { + tp->t_rtx_res_used += (uint)-delta; + ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res); + } + tp->t_frextents_delta += delta; + break; + case XFS_TRANS_SB_RES_FREXTENTS: + /* + * The allocation has already been applied to the + * in-core superblocks's counter. This should only + * be applied to the on-disk superblock. + */ + ASSERT(delta < 0); + tp->t_res_frextents_delta += delta; + break; + case XFS_TRANS_SB_DBLOCKS: + ASSERT(delta > 0); + tp->t_dblocks_delta += delta; + break; + case XFS_TRANS_SB_AGCOUNT: + ASSERT(delta > 0); + tp->t_agcount_delta += delta; + break; + case XFS_TRANS_SB_IMAXPCT: + tp->t_imaxpct_delta += delta; + break; + case XFS_TRANS_SB_REXTSIZE: + tp->t_rextsize_delta += delta; + break; + case XFS_TRANS_SB_RBMBLOCKS: + tp->t_rbmblocks_delta += delta; + break; + case XFS_TRANS_SB_RBLOCKS: + tp->t_rblocks_delta += delta; + break; + case XFS_TRANS_SB_REXTENTS: + tp->t_rextents_delta += delta; + break; + case XFS_TRANS_SB_REXTSLOG: + tp->t_rextslog_delta += delta; + break; + default: + ASSERT(0); + return; + } + + tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY); +} + +/* + * xfs_trans_apply_sb_deltas() is called from the commit code + * to bring the superblock buffer into the current transaction + * and modify it as requested by earlier calls to xfs_trans_mod_sb(). + * + * For now we just look at each field allowed to change and change + * it if necessary. + */ +STATIC void +xfs_trans_apply_sb_deltas( + xfs_trans_t *tp) +{ + xfs_sb_t *sbp; + xfs_buf_t *bp; + int whole = 0; + + bp = xfs_trans_getsb(tp, tp->t_mountp, 0); + sbp = XFS_BUF_TO_SBP(bp); + + /* + * Check that superblock mods match the mods made to AGF counters. + */ + ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) == + (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + + tp->t_ag_btree_delta)); + + if (tp->t_icount_delta != 0) { + INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta); + } + if (tp->t_ifree_delta != 0) { + INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta); + } + + if (tp->t_fdblocks_delta != 0) { + INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta); + } + if (tp->t_res_fdblocks_delta != 0) { + INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta); + } + + if (tp->t_frextents_delta != 0) { + INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_frextents_delta); + } + if (tp->t_dblocks_delta != 0) { + INT_MOD(sbp->sb_dblocks, ARCH_CONVERT, tp->t_dblocks_delta); + whole = 1; + } + if (tp->t_agcount_delta != 0) { + INT_MOD(sbp->sb_agcount, ARCH_CONVERT, tp->t_agcount_delta); + whole = 1; + } + if (tp->t_imaxpct_delta != 0) { + INT_MOD(sbp->sb_imax_pct, ARCH_CONVERT, tp->t_imaxpct_delta); + whole = 1; + } + if (tp->t_rextsize_delta != 0) { + INT_MOD(sbp->sb_rextsize, ARCH_CONVERT, tp->t_rextsize_delta); + whole = 1; + } + if (tp->t_rbmblocks_delta != 0) { + INT_MOD(sbp->sb_rbmblocks, ARCH_CONVERT, tp->t_rbmblocks_delta); + whole = 1; + } + if (tp->t_rblocks_delta != 0) { + INT_MOD(sbp->sb_rblocks, ARCH_CONVERT, tp->t_rblocks_delta); + whole = 1; + } + if (tp->t_rextents_delta != 0) { + INT_MOD(sbp->sb_rextents, ARCH_CONVERT, tp->t_rextents_delta); + whole = 1; + } + if (tp->t_rextslog_delta != 0) { + INT_MOD(sbp->sb_rextslog, ARCH_CONVERT, tp->t_rextslog_delta); + whole = 1; + } + + if (whole) + /* + * Log the whole thing, the fields are discontiguous. + */ + xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_sb_t) - 1); + else + /* + * Since all the modifiable fields are contiguous, we + * can get away with this. + */ + xfs_trans_log_buf(tp, bp, offsetof(xfs_sb_t, sb_icount), + offsetof(xfs_sb_t, sb_frextents) + + sizeof(sbp->sb_frextents) - 1); + + XFS_MTOVFS(tp->t_mountp)->vfs_super->s_dirt = 1; +} + +/* + * xfs_trans_unreserve_and_mod_sb() is called to release unused + * reservations and apply superblock counter changes to the in-core + * superblock. + * + * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). + */ +void +xfs_trans_unreserve_and_mod_sb( + xfs_trans_t *tp) +{ + xfs_mod_sb_t msb[14]; /* If you add cases, add entries */ + xfs_mod_sb_t *msbp; + /* REFERENCED */ + int error; + int rsvd; + + msbp = msb; + rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; + + /* + * Release any reserved blocks. Any that were allocated + * will be taken back again by fdblocks_delta below. + */ + if (tp->t_blk_res > 0) { + msbp->msb_field = XFS_SBS_FDBLOCKS; + msbp->msb_delta = tp->t_blk_res; + msbp++; + } + + /* + * Release any reserved real time extents . Any that were + * allocated will be taken back again by frextents_delta below. + */ + if (tp->t_rtx_res > 0) { + msbp->msb_field = XFS_SBS_FREXTENTS; + msbp->msb_delta = tp->t_rtx_res; + msbp++; + } + + /* + * Apply any superblock modifications to the in-core version. + * The t_res_fdblocks_delta and t_res_frextents_delta fields are + * explicity NOT applied to the in-core superblock. + * The idea is that that has already been done. + */ + if (tp->t_flags & XFS_TRANS_SB_DIRTY) { + if (tp->t_icount_delta != 0) { + msbp->msb_field = XFS_SBS_ICOUNT; + msbp->msb_delta = (int)tp->t_icount_delta; + msbp++; + } + if (tp->t_ifree_delta != 0) { + msbp->msb_field = XFS_SBS_IFREE; + msbp->msb_delta = (int)tp->t_ifree_delta; + msbp++; + } + if (tp->t_fdblocks_delta != 0) { + msbp->msb_field = XFS_SBS_FDBLOCKS; + msbp->msb_delta = (int)tp->t_fdblocks_delta; + msbp++; + } + if (tp->t_frextents_delta != 0) { + msbp->msb_field = XFS_SBS_FREXTENTS; + msbp->msb_delta = (int)tp->t_frextents_delta; + msbp++; + } + if (tp->t_dblocks_delta != 0) { + msbp->msb_field = XFS_SBS_DBLOCKS; + msbp->msb_delta = (int)tp->t_dblocks_delta; + msbp++; + } + if (tp->t_agcount_delta != 0) { + msbp->msb_field = XFS_SBS_AGCOUNT; + msbp->msb_delta = (int)tp->t_agcount_delta; + msbp++; + } + if (tp->t_imaxpct_delta != 0) { + msbp->msb_field = XFS_SBS_IMAX_PCT; + msbp->msb_delta = (int)tp->t_imaxpct_delta; + msbp++; + } + if (tp->t_rextsize_delta != 0) { + msbp->msb_field = XFS_SBS_REXTSIZE; + msbp->msb_delta = (int)tp->t_rextsize_delta; + msbp++; + } + if (tp->t_rbmblocks_delta != 0) { + msbp->msb_field = XFS_SBS_RBMBLOCKS; + msbp->msb_delta = (int)tp->t_rbmblocks_delta; + msbp++; + } + if (tp->t_rblocks_delta != 0) { + msbp->msb_field = XFS_SBS_RBLOCKS; + msbp->msb_delta = (int)tp->t_rblocks_delta; + msbp++; + } + if (tp->t_rextents_delta != 0) { + msbp->msb_field = XFS_SBS_REXTENTS; + msbp->msb_delta = (int)tp->t_rextents_delta; + msbp++; + } + if (tp->t_rextslog_delta != 0) { + msbp->msb_field = XFS_SBS_REXTSLOG; + msbp->msb_delta = (int)tp->t_rextslog_delta; + msbp++; + } + } + + /* + * If we need to change anything, do it. + */ + if (msbp > msb) { + error = xfs_mod_incore_sb_batch(tp->t_mountp, msb, + (uint)(msbp - msb), rsvd); + ASSERT(error == 0); + } +} + + +/* + * xfs_trans_commit + * + * Commit the given transaction to the log a/synchronously. + * + * XFS disk error handling mechanism is not based on a typical + * transaction abort mechanism. Logically after the filesystem + * gets marked 'SHUTDOWN', we can't let any new transactions + * be durable - ie. committed to disk - because some metadata might + * be inconsistent. In such cases, this returns an error, and the + * caller may assume that all locked objects joined to the transaction + * have already been unlocked as if the commit had succeeded. + * It's illegal to reference the transaction structure after this call. + */ + /*ARGSUSED*/ +int +xfs_trans_commit( + xfs_trans_t *tp, + uint flags, + xfs_lsn_t *commit_lsn_p) +{ + xfs_log_iovec_t *log_vector; + int nvec; + xfs_mount_t *mp; + xfs_lsn_t commit_lsn; + /* REFERENCED */ + int error; + int log_flags; + int sync; +#define XFS_TRANS_LOGVEC_COUNT 16 + xfs_log_iovec_t log_vector_fast[XFS_TRANS_LOGVEC_COUNT]; +#if defined(XLOG_NOLOG) || defined(DEBUG) + static xfs_lsn_t trans_lsn = 1; +#endif + int shutdown; + + commit_lsn = -1; + + /* + * Determine whether this commit is releasing a permanent + * log reservation or not. + */ + if (flags & XFS_TRANS_RELEASE_LOG_RES) { + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + log_flags = XFS_LOG_REL_PERM_RESERV; + } else { + log_flags = 0; + } + mp = tp->t_mountp; + + /* + * If there is nothing to be logged by the transaction, + * then unlock all of the items associated with the + * transaction and free the transaction structure. + * Also make sure to return any reserved blocks to + * the free pool. + */ +shut_us_down: + shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0; + if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) { + xfs_trans_unreserve_and_mod_sb(tp); + /* + * It is indeed possible for the transaction to be + * not dirty but the dqinfo portion to be. All that + * means is that we have some (non-persistent) quota + * reservations that need to be unreserved. + */ + if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) { + xfs_trans_unreserve_and_mod_dquots(tp); + } + if (tp->t_ticket) { + commit_lsn = xfs_log_done(mp, tp->t_ticket, log_flags); + if (commit_lsn == -1 && !shutdown) + shutdown = XFS_ERROR(EIO); + } + xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0); + xfs_trans_free_busy(tp); + xfs_trans_free(tp); + XFS_STATS_INC(xfsstats.xs_trans_empty); + if (commit_lsn_p) + *commit_lsn_p = commit_lsn; + current->flags &= ~PF_FSTRANS; + return (shutdown); + } +#if defined(XLOG_NOLOG) || defined(DEBUG) + ASSERT(!xlog_debug || tp->t_ticket != NULL); +#else + ASSERT(tp->t_ticket != NULL); +#endif + + /* + * If we need to update the superblock, then do it now. + */ + if (tp->t_flags & XFS_TRANS_SB_DIRTY) { + xfs_trans_apply_sb_deltas(tp); + } + if (tp->t_flags & XFS_TRANS_DQ_DIRTY) { + xfs_trans_apply_dquot_deltas(tp); + } + + /* + * Ask each log item how many log_vector entries it will + * need so we can figure out how many to allocate. + * Try to avoid the kmem_alloc() call in the common case + * by using a vector from the stack when it fits. + */ + nvec = xfs_trans_count_vecs(tp); + + if (nvec == 0) { + xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); + goto shut_us_down; + } + + + if (nvec <= XFS_TRANS_LOGVEC_COUNT) { + log_vector = log_vector_fast; + } else { + log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec * + sizeof(xfs_log_iovec_t), + KM_SLEEP); + } + + /* + * Fill in the log_vector and pin the logged items, and + * then write the transaction to the log. + */ + xfs_trans_fill_vecs(tp, log_vector); + + /* + * Ignore errors here. xfs_log_done would do the right thing. + * We need to put the ticket, etc. away. + */ + error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, + &(tp->t_lsn)); + +#if defined(XLOG_NOLOG) || defined(DEBUG) + if (xlog_debug) { + commit_lsn = xfs_log_done(mp, tp->t_ticket, + log_flags); + } else { + commit_lsn = 0; + tp->t_lsn = trans_lsn++; + } +#else + /* + * This is the regular case. At this point (after the call finishes), + * the transaction is committed incore and could go out to disk at + * any time. However, all the items associated with the transaction + * are still locked and pinned in memory. + */ + commit_lsn = xfs_log_done(mp, tp->t_ticket, log_flags); +#endif + + tp->t_commit_lsn = commit_lsn; + if (nvec > XFS_TRANS_LOGVEC_COUNT) { + kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t)); + } + + if (commit_lsn_p) + *commit_lsn_p = commit_lsn; + + /* + * If we got a log write error. Unpin the logitems that we + * had pinned, clean up, free trans structure, and return error. + */ + if (error || commit_lsn == -1) { + xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT); + current->flags &= ~PF_FSTRANS; + return XFS_ERROR(EIO); + } + + /* + * Once all the items of the transaction have been copied + * to the in core log we can release them. Do that here. + * This will free descriptors pointing to items which were + * not logged since there is nothing more to do with them. + * For items which were logged, we will keep pointers to them + * so they can be unpinned after the transaction commits to disk. + * This will also stamp each modified meta-data item with + * the commit lsn of this transaction for dependency tracking + * purposes. + */ + xfs_trans_unlock_items(tp, commit_lsn); + + /* + * Once the transaction has committed, unused + * reservations need to be released and changes to + * the superblock need to be reflected in the in-core + * version. Do that now. + */ + xfs_trans_unreserve_and_mod_sb(tp); + + sync = tp->t_flags & XFS_TRANS_SYNC; + + /* + * Tell the LM to call the transaction completion routine + * when the log write with LSN commit_lsn completes (e.g. + * when the transaction commit really hits the on-disk log). + * After this call we cannot reference tp, because the call + * can happen at any time and the call will free the transaction + * structure pointed to by tp. The only case where we call + * the completion routine (xfs_trans_committed) directly is + * if the log is turned off on a debug kernel or we're + * running in simulation mode (the log is explicitly turned + * off). + */ +#if defined(XLOG_NOLOG) || defined(DEBUG) + if (xlog_debug) { + tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed; + tp->t_logcb.cb_arg = tp; + xfs_log_notify(mp, commit_lsn, &(tp->t_logcb)); + } else { + xfs_trans_committed(tp, 0); + } +#else + tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed; + tp->t_logcb.cb_arg = tp; + xfs_log_notify(mp, commit_lsn, &(tp->t_logcb)); +#endif + /* + * If the transaction needs to be synchronous, then force the + * log out now and wait for it. + */ + if (sync) { + error = xfs_log_force(mp, commit_lsn, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_STATS_INC(xfsstats.xs_trans_sync); + } else { + XFS_STATS_INC(xfsstats.xs_trans_async); + } + + /* mark this thread as no longer being in a transaction */ + current->flags &= ~PF_FSTRANS; + + return (error); +} + + +/* + * Total up the number of log iovecs needed to commit this + * transaction. The transaction itself needs one for the + * transaction header. Ask each dirty item in turn how many + * it needs to get the total. + */ +STATIC uint +xfs_trans_count_vecs( + xfs_trans_t *tp) +{ + int nvecs; + xfs_log_item_desc_t *lidp; + + nvecs = 1; + lidp = xfs_trans_first_item(tp); + ASSERT(lidp != NULL); + + /* In the non-debug case we need to start bailing out if we + * didn't find a log_item here, return zero and let trans_commit + * deal with it. + */ + if (lidp == NULL) + return 0; + + while (lidp != NULL) { + /* + * Skip items which aren't dirty in this transaction. + */ + if (!(lidp->lid_flags & XFS_LID_DIRTY)) { + lidp = xfs_trans_next_item(tp, lidp); + continue; + } + lidp->lid_size = IOP_SIZE(lidp->lid_item); + nvecs += lidp->lid_size; + lidp = xfs_trans_next_item(tp, lidp); + } + + return nvecs; +} + +/* + * Called from the trans_commit code when we notice that + * the filesystem is in the middle of a forced shutdown. + */ +STATIC void +xfs_trans_uncommit( + xfs_trans_t *tp, + uint flags) +{ + xfs_log_item_desc_t *lidp; + + for (lidp = xfs_trans_first_item(tp); + lidp != NULL; + lidp = xfs_trans_next_item(tp, lidp)) { + /* + * Unpin all but those that aren't dirty. + */ + if (lidp->lid_flags & XFS_LID_DIRTY) + IOP_UNPIN_REMOVE(lidp->lid_item, tp); + } + + xfs_trans_unreserve_and_mod_sb(tp); + if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) { + xfs_trans_unreserve_and_mod_dquots(tp); + } + + xfs_trans_free_items(tp, flags); + xfs_trans_free_busy(tp); + xfs_trans_free(tp); +} + +/* + * Fill in the vector with pointers to data to be logged + * by this transaction. The transaction header takes + * the first vector, and then each dirty item takes the + * number of vectors it indicated it needed in xfs_trans_count_vecs(). + * + * As each item fills in the entries it needs, also pin the item + * so that it cannot be flushed out until the log write completes. + */ +STATIC void +xfs_trans_fill_vecs( + xfs_trans_t *tp, + xfs_log_iovec_t *log_vector) +{ + xfs_log_item_desc_t *lidp; + xfs_log_iovec_t *vecp; + uint nitems; + + /* + * Skip over the entry for the transaction header, we'll + * fill that in at the end. + */ + vecp = log_vector + 1; /* pointer arithmetic */ + + nitems = 0; + lidp = xfs_trans_first_item(tp); + ASSERT(lidp != NULL); + while (lidp != NULL) { + /* + * Skip items which aren't dirty in this transaction. + */ + if (!(lidp->lid_flags & XFS_LID_DIRTY)) { + lidp = xfs_trans_next_item(tp, lidp); + continue; + } + /* + * The item may be marked dirty but not log anything. + * This can be used to get called when a transaction + * is committed. + */ + if (lidp->lid_size) { + nitems++; + } + IOP_FORMAT(lidp->lid_item, vecp); + vecp += lidp->lid_size; /* pointer arithmetic */ + IOP_PIN(lidp->lid_item); + lidp = xfs_trans_next_item(tp, lidp); + } + + /* + * Now that we've counted the number of items in this + * transaction, fill in the transaction header. + */ + tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC; + tp->t_header.th_type = tp->t_type; + tp->t_header.th_num_items = nitems; + log_vector->i_addr = (xfs_caddr_t)&tp->t_header; + log_vector->i_len = sizeof(xfs_trans_header_t); +} + + +/* + * Unlock all of the transaction's items and free the transaction. + * The transaction must not have modified any of its items, because + * there is no way to restore them to their previous state. + * + * If the transaction has made a log reservation, make sure to release + * it as well. + */ +void +xfs_trans_cancel( + xfs_trans_t *tp, + int flags) +{ + int log_flags; +#ifdef DEBUG + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + int i; +#endif + + /* + * See if the caller is being too lazy to figure out if + * the transaction really needs an abort. + */ + if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY)) + flags &= ~XFS_TRANS_ABORT; + /* + * See if the caller is relying on us to shut down the + * filesystem. This happens in paths where we detect + * corruption and decide to give up. + */ + if ((tp->t_flags & XFS_TRANS_DIRTY) && + !XFS_FORCED_SHUTDOWN(tp->t_mountp)) + xfs_force_shutdown(tp->t_mountp, XFS_CORRUPT_INCORE); +#ifdef DEBUG + if (!(flags & XFS_TRANS_ABORT)) { + licp = &(tp->t_items); + while (licp != NULL) { + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lip = lidp->lid_item; + if (!XFS_FORCED_SHUTDOWN(tp->t_mountp)) + ASSERT(!(lip->li_type == XFS_LI_EFD)); + } + licp = licp->lic_next; + } + } +#endif + xfs_trans_unreserve_and_mod_sb(tp); + + if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) + xfs_trans_unreserve_and_mod_dquots(tp); + + if (tp->t_ticket) { + if (flags & XFS_TRANS_RELEASE_LOG_RES) { + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + log_flags = XFS_LOG_REL_PERM_RESERV; + } else { + log_flags = 0; + } + xfs_log_done(tp->t_mountp, tp->t_ticket, log_flags); + } + xfs_trans_free_items(tp, flags); + xfs_trans_free_busy(tp); + xfs_trans_free(tp); + + /* mark this thread as no longer being in a transaction */ + current->flags &= ~PF_FSTRANS; +} + + +/* + * Free the transaction structure. If there is more clean up + * to do when the structure is freed, add it here. + */ +STATIC void +xfs_trans_free( + xfs_trans_t *tp) +{ + atomic_dec(&tp->t_mountp->m_active_trans); + if (tp->t_dqinfo) + xfs_trans_free_dqinfo(tp); + kmem_zone_free(xfs_trans_zone, tp); +} + + +/* + * THIS SHOULD BE REWRITTEN TO USE xfs_trans_next_item(). + * + * This is typically called by the LM when a transaction has been fully + * committed to disk. It needs to unpin the items which have + * been logged by the transaction and update their positions + * in the AIL if necessary. + * This also gets called when the transactions didn't get written out + * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then. + * + * Call xfs_trans_chunk_committed() to process the items in + * each chunk. + */ +STATIC void +xfs_trans_committed( + xfs_trans_t *tp, + int abortflag) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + xfs_log_busy_chunk_t *lbcp; + xfs_log_busy_slot_t *lbsp; + int i; + + /* + * Call the transaction's completion callback if there + * is one. + */ + if (tp->t_callback != NULL) { + tp->t_callback(tp, tp->t_callarg); + } + + /* + * Special case the chunk embedded in the transaction. + */ + licp = &(tp->t_items); + if (!(XFS_LIC_ARE_ALL_FREE(licp))) { + xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); + } + + /* + * Process the items in each chunk in turn. + */ + licp = licp->lic_next; + while (licp != NULL) { + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); + next_licp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + licp = next_licp; + } + + /* + * Clear all the per-AG busy list items listed in this transaction + */ + lbcp = &tp->t_busy; + while (lbcp != NULL) { + for (i = 0, lbsp = lbcp->lbc_busy; i < lbcp->lbc_unused; i++, lbsp++) { + if (!XFS_LBC_ISFREE(lbcp, i)) { + xfs_alloc_clear_busy(tp, lbsp->lbc_ag, + lbsp->lbc_idx); + } + } + lbcp = lbcp->lbc_next; + } + xfs_trans_free_busy(tp); + + /* + * That's it for the transaction structure. Free it. + */ + xfs_trans_free(tp); +} + +/* + * This is called to perform the commit processing for each + * item described by the given chunk. + * + * The commit processing consists of unlocking items which were + * held locked with the SYNC_UNLOCK attribute, calling the committed + * routine of each logged item, updating the item's position in the AIL + * if necessary, and unpinning each item. If the committed routine + * returns -1, then do nothing further with the item because it + * may have been freed. + * + * Since items are unlocked when they are copied to the incore + * log, it is possible for two transactions to be completing + * and manipulating the same item simultaneously. The AIL lock + * will protect the lsn field of each item. The value of this + * field can never go backwards. + * + * We unpin the items after repositioning them in the AIL, because + * otherwise they could be immediately flushed and we'd have to race + * with the flusher trying to pull the item from the AIL as we add it. + */ +STATIC void +xfs_trans_chunk_committed( + xfs_log_item_chunk_t *licp, + xfs_lsn_t lsn, + int aborted) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + xfs_lsn_t item_lsn; + struct xfs_mount *mp; + int i; + SPLDECL(s); + + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lip = lidp->lid_item; + if (aborted) + lip->li_flags |= XFS_LI_ABORTED; + + if (lidp->lid_flags & XFS_LID_SYNC_UNLOCK) { + IOP_UNLOCK(lip); + } + + /* + * Send in the ABORTED flag to the COMMITTED routine + * so that it knows whether the transaction was aborted + * or not. + */ + item_lsn = IOP_COMMITTED(lip, lsn); + + /* + * If the committed routine returns -1, make + * no more references to the item. + */ + if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) { + continue; + } + + /* + * If the returned lsn is greater than what it + * contained before, update the location of the + * item in the AIL. If it is not, then do nothing. + * Items can never move backwards in the AIL. + * + * While the new lsn should usually be greater, it + * is possible that a later transaction completing + * simultaneously with an earlier one using the + * same item could complete first with a higher lsn. + * This would cause the earlier transaction to fail + * the test below. + */ + mp = lip->li_mountp; + AIL_LOCK(mp,s); + if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) { + /* + * This will set the item's lsn to item_lsn + * and update the position of the item in + * the AIL. + * + * xfs_trans_update_ail() drops the AIL lock. + */ + xfs_trans_update_ail(mp, lip, item_lsn, s); + } else { + AIL_UNLOCK(mp, s); + } + + /* + * Now that we've repositioned the item in the AIL, + * unpin it so it can be flushed. + */ + IOP_UNPIN(lip); + } +} diff -Nur linux-2.4.19/fs/xfs/xfs_trans.h linux-2.4.19-sgi211r3/fs/xfs/xfs_trans.h --- linux-2.4.19/fs/xfs/xfs_trans.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans.h Fri Nov 1 12:24:39 2002 @@ -0,0 +1,1037 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_H__ +#define __XFS_TRANS_H__ + +/* + * This is the structure written in the log at the head of + * every transaction. It identifies the type and id of the + * transaction, and contains the number of items logged by + * the transaction so we know how many to expect during recovery. + * + * Do not change the below structure without redoing the code in + * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). + */ +typedef struct xfs_trans_header { + uint th_magic; /* magic number */ + uint th_type; /* transaction type */ + __int32_t th_tid; /* transaction id (unused) */ + uint th_num_items; /* num items logged by trans */ +} xfs_trans_header_t; + +#define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ + +/* + * Log item types. + */ +#define XFS_LI_5_3_BUF 0x1234 /* v1 bufs, 1-block inode buffers */ +#define XFS_LI_5_3_INODE 0x1235 /* 1-block inode buffers */ +#define XFS_LI_EFI 0x1236 +#define XFS_LI_EFD 0x1237 +#define XFS_LI_IUNLINK 0x1238 +#define XFS_LI_6_1_INODE 0x1239 /* 4K non-aligned inode bufs */ +#define XFS_LI_6_1_BUF 0x123a /* v1, 4K inode buffers */ +#define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ +#define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ +#define XFS_LI_DQUOT 0x123d +#define XFS_LI_QUOTAOFF 0x123e +#define XFS_LI_RPC 0x123f /* CXFS RPC return info */ + +/* + * Transaction types. Used to distinguish types of buffers. + */ +#define XFS_TRANS_SETATTR_NOT_SIZE 1 +#define XFS_TRANS_SETATTR_SIZE 2 +#define XFS_TRANS_INACTIVE 3 +#define XFS_TRANS_CREATE 4 +#define XFS_TRANS_CREATE_TRUNC 5 +#define XFS_TRANS_TRUNCATE_FILE 6 +#define XFS_TRANS_REMOVE 7 +#define XFS_TRANS_LINK 8 +#define XFS_TRANS_RENAME 9 +#define XFS_TRANS_MKDIR 10 +#define XFS_TRANS_RMDIR 11 +#define XFS_TRANS_SYMLINK 12 +#define XFS_TRANS_SET_DMATTRS 13 +#define XFS_TRANS_GROWFS 14 +#define XFS_TRANS_STRAT_WRITE 15 +#define XFS_TRANS_DIOSTRAT 16 +#define XFS_TRANS_WRITE_SYNC 17 +#define XFS_TRANS_WRITEID 18 +#define XFS_TRANS_ADDAFORK 19 +#define XFS_TRANS_ATTRINVAL 20 +#define XFS_TRANS_ATRUNCATE 21 +#define XFS_TRANS_ATTR_SET 22 +#define XFS_TRANS_ATTR_RM 23 +#define XFS_TRANS_ATTR_FLAG 24 +#define XFS_TRANS_CLEAR_AGI_BUCKET 25 +#define XFS_TRANS_QM_SBCHANGE 26 +/* + * Dummy entries since we use the transaction type to index into the + * trans_type[] in xlog_recover_print_trans_head() + */ +#define XFS_TRANS_DUMMY1 27 +#define XFS_TRANS_DUMMY2 28 +#define XFS_TRANS_QM_QUOTAOFF 29 +#define XFS_TRANS_QM_DQALLOC 30 +#define XFS_TRANS_QM_SETQLIM 31 +#define XFS_TRANS_QM_DQCLUSTER 32 +#define XFS_TRANS_QM_QINOCREATE 33 +#define XFS_TRANS_QM_QUOTAOFF_END 34 +#define XFS_TRANS_SB_UNIT 35 +#define XFS_TRANS_FSYNC_TS 36 +#define XFS_TRANS_GROWFSRT_ALLOC 37 +#define XFS_TRANS_GROWFSRT_ZERO 38 +#define XFS_TRANS_GROWFSRT_FREE 39 +#define XFS_TRANS_SWAPEXT 40 +/* new transaction types need to be reflected in xfs_logprint(8) */ + + +#ifdef __KERNEL__ +struct xfs_buf; +struct xfs_buftarg; +struct xfs_efd_log_item; +struct xfs_efi_log_item; +struct xfs_inode; +struct xfs_item_ops; +struct xfs_log_iovec; +struct xfs_log_item; +struct xfs_log_item_desc; +struct xfs_mount; +struct xfs_trans; +struct xfs_dquot_acct; + +typedef struct xfs_ail_entry { + struct xfs_log_item *ail_forw; /* AIL forw pointer */ + struct xfs_log_item *ail_back; /* AIL back pointer */ +} xfs_ail_entry_t; + +/* + * This structure is passed as a parameter to xfs_trans_push_ail() + * and is used to track the what LSN the waiting processes are + * waiting to become unused. + */ +typedef struct xfs_ail_ticket { + xfs_lsn_t at_lsn; /* lsn waitin for */ + struct xfs_ail_ticket *at_forw; /* wait list ptr */ + struct xfs_ail_ticket *at_back; /* wait list ptr */ + sv_t at_sema; /* wait sema */ +} xfs_ail_ticket_t; + + +typedef struct xfs_log_item { + xfs_ail_entry_t li_ail; /* AIL pointers */ + xfs_lsn_t li_lsn; /* last on-disk lsn */ + struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ + struct xfs_mount *li_mountp; /* ptr to fs mount */ + uint li_type; /* item type */ + uint li_flags; /* misc flags */ + struct xfs_log_item *li_bio_list; /* buffer item list */ + void (*li_cb)(struct xfs_buf *, + struct xfs_log_item *); + /* buffer item iodone */ + /* callback func */ + struct xfs_item_ops *li_ops; /* function list */ +} xfs_log_item_t; + +#define XFS_LI_IN_AIL 0x1 +#define XFS_LI_ABORTED 0x2 + +typedef struct xfs_item_ops { + uint (*iop_size)(xfs_log_item_t *); + void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *); + void (*iop_pin)(xfs_log_item_t *); + void (*iop_unpin)(xfs_log_item_t *); + void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *); + uint (*iop_trylock)(xfs_log_item_t *); + void (*iop_unlock)(xfs_log_item_t *); + xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); + void (*iop_push)(xfs_log_item_t *); + void (*iop_abort)(xfs_log_item_t *); + void (*iop_pushbuf)(xfs_log_item_t *); + void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); +} xfs_item_ops_t; + +#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip) +#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp) +#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) +#define IOP_UNPIN(ip) (*(ip)->li_ops->iop_unpin)(ip) +#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp) +#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip) +#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip) +#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn) +#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip) +#define IOP_ABORT(ip) (*(ip)->li_ops->iop_abort)(ip) +#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip) +#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn) + +/* + * Return values for the IOP_TRYLOCK() routines. + */ +#define XFS_ITEM_SUCCESS 0 +#define XFS_ITEM_PINNED 1 +#define XFS_ITEM_LOCKED 2 +#define XFS_ITEM_FLUSHING 3 +#define XFS_ITEM_PUSHBUF 4 + +#endif /* __KERNEL__ */ + +/* + * This structure is used to track log items associated with + * a transaction. It points to the log item and keeps some + * flags to track the state of the log item. It also tracks + * the amount of space needed to log the item it describes + * once we get to commit processing (see xfs_trans_commit()). + */ +typedef struct xfs_log_item_desc { + xfs_log_item_t *lid_item; + ushort lid_size; + unsigned char lid_flags; + unsigned char lid_index; +} xfs_log_item_desc_t; + +#define XFS_LID_DIRTY 0x1 +#define XFS_LID_PINNED 0x2 +#define XFS_LID_SYNC_UNLOCK 0x4 + +/* + * This structure is used to maintain a chunk list of log_item_desc + * structures. The free field is a bitmask indicating which descriptors + * in this chunk's array are free. The unused field is the first value + * not used since this chunk was allocated. + */ +#define XFS_LIC_NUM_SLOTS 15 +typedef struct xfs_log_item_chunk { + struct xfs_log_item_chunk *lic_next; + ushort lic_free; + ushort lic_unused; + xfs_log_item_desc_t lic_descs[XFS_LIC_NUM_SLOTS]; +} xfs_log_item_chunk_t; + +#define XFS_LIC_MAX_SLOT (XFS_LIC_NUM_SLOTS - 1) +#define XFS_LIC_FREEMASK ((1 << XFS_LIC_NUM_SLOTS) - 1) + + +/* + * Initialize the given chunk. Set the chunk's free descriptor mask + * to indicate that all descriptors are free. The caller gets to set + * lic_unused to the right value (0 matches all free). The + * lic_descs.lid_index values are set up as each desc is allocated. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_INIT) +void xfs_lic_init(xfs_log_item_chunk_t *cp); +#define XFS_LIC_INIT(cp) xfs_lic_init(cp) +#else +#define XFS_LIC_INIT(cp) ((cp)->lic_free = XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_INIT_SLOT) +void xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_INIT_SLOT(cp,slot) xfs_lic_init_slot(cp, slot) +#else +#define XFS_LIC_INIT_SLOT(cp,slot) \ + ((cp)->lic_descs[slot].lid_index = (unsigned char)(slot)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_VACANCY) +int xfs_lic_vacancy(xfs_log_item_chunk_t *cp); +#define XFS_LIC_VACANCY(cp) xfs_lic_vacancy(cp) +#else +#define XFS_LIC_VACANCY(cp) (((cp)->lic_free) & XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ALL_FREE) +void xfs_lic_all_free(xfs_log_item_chunk_t *cp); +#define XFS_LIC_ALL_FREE(cp) xfs_lic_all_free(cp) +#else +#define XFS_LIC_ALL_FREE(cp) ((cp)->lic_free = XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ARE_ALL_FREE) +int xfs_lic_are_all_free(xfs_log_item_chunk_t *cp); +#define XFS_LIC_ARE_ALL_FREE(cp) xfs_lic_are_all_free(cp) +#else +#define XFS_LIC_ARE_ALL_FREE(cp) (((cp)->lic_free & XFS_LIC_FREEMASK) ==\ + XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ISFREE) +int xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_ISFREE(cp,slot) xfs_lic_isfree(cp,slot) +#else +#define XFS_LIC_ISFREE(cp,slot) ((cp)->lic_free & (1 << (slot))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_CLAIM) +void xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_CLAIM(cp,slot) xfs_lic_claim(cp,slot) +#else +#define XFS_LIC_CLAIM(cp,slot) ((cp)->lic_free &= ~(1 << (slot))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_RELSE) +void xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_RELSE(cp,slot) xfs_lic_relse(cp,slot) +#else +#define XFS_LIC_RELSE(cp,slot) ((cp)->lic_free |= 1 << (slot)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_SLOT) +xfs_log_item_desc_t *xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_SLOT(cp,slot) xfs_lic_slot(cp,slot) +#else +#define XFS_LIC_SLOT(cp,slot) (&((cp)->lic_descs[slot])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_DESC_TO_SLOT) +int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp); +#define XFS_LIC_DESC_TO_SLOT(dp) xfs_lic_desc_to_slot(dp) +#else +#define XFS_LIC_DESC_TO_SLOT(dp) ((uint)((dp)->lid_index)) +#endif +/* + * Calculate the address of a chunk given a descriptor pointer: + * dp - dp->lid_index give the address of the start of the lic_descs array. + * From this we subtract the offset of the lic_descs field in a chunk. + * All of this yields the address of the chunk, which is + * cast to a chunk pointer. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_DESC_TO_CHUNK) +xfs_log_item_chunk_t *xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp); +#define XFS_LIC_DESC_TO_CHUNK(dp) xfs_lic_desc_to_chunk(dp) +#else +#define XFS_LIC_DESC_TO_CHUNK(dp) ((xfs_log_item_chunk_t*) \ + (((xfs_caddr_t)((dp) - (dp)->lid_index)) -\ + (xfs_caddr_t)(((xfs_log_item_chunk_t*) \ + 0)->lic_descs))) +#endif + +#ifdef __KERNEL__ +/* + * This structure is used to maintain a list of block ranges that have been + * freed in the transaction. The ranges are listed in the perag[] busy list + * between when they're freed and the transaction is committed to disk. + */ + +typedef struct xfs_log_busy_slot { + xfs_agnumber_t lbc_ag; + ushort lbc_idx; /* index in perag.busy[] */ +} xfs_log_busy_slot_t; + +#define XFS_LBC_NUM_SLOTS 31 +typedef struct xfs_log_busy_chunk { + struct xfs_log_busy_chunk *lbc_next; + uint lbc_free; /* bitmask of free slots */ + ushort lbc_unused; /* first unused */ + xfs_log_busy_slot_t lbc_busy[XFS_LBC_NUM_SLOTS]; +} xfs_log_busy_chunk_t; + +#define XFS_LBC_MAX_SLOT (XFS_LBC_NUM_SLOTS - 1) +#define XFS_LBC_FREEMASK ((1U << XFS_LBC_NUM_SLOTS) - 1) + +#define XFS_LBC_INIT(cp) ((cp)->lbc_free = XFS_LBC_FREEMASK) +#define XFS_LBC_CLAIM(cp, slot) ((cp)->lbc_free &= ~(1 << (slot))) +#define XFS_LBC_SLOT(cp, slot) (&((cp)->lbc_busy[(slot)])) +#define XFS_LBC_VACANCY(cp) (((cp)->lbc_free) & XFS_LBC_FREEMASK) +#define XFS_LBC_ISFREE(cp, slot) ((cp)->lbc_free & (1 << (slot))) + +/* + * This is the type of function which can be given to xfs_trans_callback() + * to be called upon the transaction's commit to disk. + */ +typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *); + +/* + * This is the structure maintained for every active transaction. + */ +typedef struct xfs_trans { + unsigned int t_magic; /* magic number */ + xfs_log_callback_t t_logcb; /* log callback struct */ + struct xfs_trans *t_forw; /* async list pointers */ + struct xfs_trans *t_back; /* async list pointers */ + unsigned int t_type; /* transaction type */ + unsigned int t_log_res; /* amt of log space resvd */ + unsigned int t_log_count; /* count for perm log res */ + unsigned int t_blk_res; /* # of blocks resvd */ + unsigned int t_blk_res_used; /* # of resvd blocks used */ + unsigned int t_rtx_res; /* # of rt extents resvd */ + unsigned int t_rtx_res_used; /* # of resvd rt extents used */ + xfs_log_ticket_t t_ticket; /* log mgr ticket */ + sema_t t_sema; /* sema for commit completion */ + xfs_lsn_t t_lsn; /* log seq num of start of + * transaction. */ + xfs_lsn_t t_commit_lsn; /* log seq num of end of + * transaction. */ + struct xfs_mount *t_mountp; /* ptr to fs mount struct */ + struct xfs_dquot_acct *t_dqinfo; /* accting info for dquots */ + xfs_trans_callback_t t_callback; /* transaction callback */ + void *t_callarg; /* callback arg */ + unsigned int t_flags; /* misc flags */ + long t_icount_delta; /* superblock icount change */ + long t_ifree_delta; /* superblock ifree change */ + long t_fdblocks_delta; /* superblock fdblocks chg */ + long t_res_fdblocks_delta; /* on-disk only chg */ + long t_frextents_delta;/* superblock freextents chg*/ + long t_res_frextents_delta; /* on-disk only chg */ + long t_ag_freeblks_delta; /* debugging counter */ + long t_ag_flist_delta; /* debugging counter */ + long t_ag_btree_delta; /* debugging counter */ + long t_dblocks_delta;/* superblock dblocks change */ + long t_agcount_delta;/* superblock agcount change */ + long t_imaxpct_delta;/* superblock imaxpct change */ + long t_rextsize_delta;/* superblock rextsize chg */ + long t_rbmblocks_delta;/* superblock rbmblocks chg */ + long t_rblocks_delta;/* superblock rblocks change */ + long t_rextents_delta;/* superblocks rextents chg */ + long t_rextslog_delta;/* superblocks rextslog chg */ + unsigned int t_items_free; /* log item descs free */ + xfs_log_item_chunk_t t_items; /* first log item desc chunk */ + xfs_trans_header_t t_header; /* header for in-log trans */ + unsigned int t_busy_free; /* busy descs free */ + xfs_log_busy_chunk_t t_busy; /* busy/async free blocks */ +} xfs_trans_t; + +#endif /* __KERNEL__ */ + + +#define XFS_TRANS_MAGIC 0x5452414E /* 'TRAN' */ +/* + * Values for t_flags. + */ +#define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ +#define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ +#define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ +#define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ +#define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ +#define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ + +/* + * Values for call flags parameter. + */ +#define XFS_TRANS_NOSLEEP 0x1 +#define XFS_TRANS_WAIT 0x2 +#define XFS_TRANS_RELEASE_LOG_RES 0x4 +#define XFS_TRANS_ABORT 0x8 + +/* + * Field values for xfs_trans_mod_sb. + */ +#define XFS_TRANS_SB_ICOUNT 0x00000001 +#define XFS_TRANS_SB_IFREE 0x00000002 +#define XFS_TRANS_SB_FDBLOCKS 0x00000004 +#define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 +#define XFS_TRANS_SB_FREXTENTS 0x00000010 +#define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 +#define XFS_TRANS_SB_DBLOCKS 0x00000040 +#define XFS_TRANS_SB_AGCOUNT 0x00000080 +#define XFS_TRANS_SB_IMAXPCT 0x00000100 +#define XFS_TRANS_SB_REXTSIZE 0x00000200 +#define XFS_TRANS_SB_RBMBLOCKS 0x00000400 +#define XFS_TRANS_SB_RBLOCKS 0x00000800 +#define XFS_TRANS_SB_REXTENTS 0x00001000 +#define XFS_TRANS_SB_REXTSLOG 0x00002000 + + +/* + * Various log reservation values. + * These are based on the size of the file system block + * because that is what most transactions manipulate. + * Each adds in an additional 128 bytes per item logged to + * try to account for the overhead of the transaction mechanism. + * + * Note: + * Most of the reservations underestimate the number of allocation + * groups into which they could free extents in the xfs_bmap_finish() + * call. This is because the number in the worst case is quite high + * and quite unusual. In order to fix this we need to change + * xfs_bmap_finish() to free extents in only a single AG at a time. + * This will require changes to the EFI code as well, however, so that + * the EFI for the extents not freed is logged again in each transaction. + * See bug 261917. + */ + +/* + * Per-extent log reservation for the allocation btree changes + * involved in freeing or allocating an extent. + * 2 trees * (2 blocks/level * max depth - 1) * block size + */ +#define XFS_ALLOCFREE_LOG_RES(mp,nx) \ + ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * XFS_AG_MAXLEVELS(mp) - 1))) +#define XFS_ALLOCFREE_LOG_COUNT(mp,nx) \ + ((nx) * (2 * (2 * XFS_AG_MAXLEVELS(mp) - 1))) + +/* + * Per-directory log reservation for any directory change. + * dir blocks: (1 btree block per level + data block + free block) * dblock size + * bmap btree: (levels + 2) * max depth * block size + * v2 directory blocks can be fragmented below the dirblksize down to the fsb + * size, so account for that in the DAENTER macros. + */ +#define XFS_DIROP_LOG_RES(mp) \ + (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ + (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) +#define XFS_DIROP_LOG_COUNT(mp) \ + (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ + XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) + +/* + * In a write transaction we can allocate a maximum of 2 + * extents. This gives: + * the inode getting the new extents: inode size + * the inode\'s bmap btree: max depth * block size + * the agfs of the ags from which the extents are allocated: 2 * sector + * the superblock free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + * And the bmap_finish transaction can free bmap blocks in a join: + * the agfs of the ags containing the blocks: 2 * sector size + * the agfls of the ags containing the blocks: 2 * sector size + * the super block free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_WRITE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (4 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))),\ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_WRITE_LOG_RES(mp) ((mp)->m_reservations.tr_write) + +/* + * In truncating a file we free up to two extents at once. We can modify: + * the inode being truncated: inode size + * the inode\'s bmap btree: (max depth + 1) * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ITRUNCATE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1) + \ + (128 * (2 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ + ((4 * (mp)->m_sb.sb_sectsize) + \ + (4 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 4) + \ + (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) + +#define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate) + +/* + * In renaming a files we can modify: + * the four inodes involved: 4 * inode size + * the two directory btrees: 2 * (max depth + v2) * dir block size + * the two directory bmap btrees: 2 * max depth * block size + * And the bmap_finish transaction can free dir and bmap blocks (two sets + * of bmap blocks) giving: + * the agf for the ags in which the blocks live: 3 * sector size + * the agfl for the ags in which the blocks live: 3 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_RENAME_LOG_RES(mp) \ + (MAX( \ + ((4 * (mp)->m_sb.sb_inodesize) + \ + (2 * XFS_DIROP_LOG_RES(mp)) + \ + (128 * (4 + 2 * XFS_DIROP_LOG_COUNT(mp)))), \ + ((3 * (mp)->m_sb.sb_sectsize) + \ + (3 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 3) + \ + (128 * (7 + XFS_ALLOCFREE_LOG_COUNT(mp, 3)))))) + +#define XFS_RENAME_LOG_RES(mp) ((mp)->m_reservations.tr_rename) + +/* + * For creating a link to an inode: + * the parent directory inode: inode size + * the linked inode: inode size + * the directory btree could split: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free some bmap blocks giving: + * the agf for the ag in which the blocks live: sector size + * the agfl for the ag in which the blocks live: sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_LINK_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ + ((mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_LINK_LOG_RES(mp) ((mp)->m_reservations.tr_link) + +/* + * For removing a directory entry we can modify: + * the parent directory inode: inode size + * the removed inode: inode size + * the directory btree could join: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free the dir and bmap blocks giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_REMOVE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_REMOVE_LOG_RES(mp) ((mp)->m_reservations.tr_remove) + +/* + * For symlink we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: 1 block + * the directory btree: (max depth + v2) * dir block size + * the directory inode\'s bmap btree: (max depth + v2) * block size + * the blocks for the symlink: 1 KB + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_SYMLINK_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B(mp, 1) + \ + XFS_DIROP_LOG_RES(mp) + \ + 1024 + \ + (128 * (4 + XFS_DIROP_LOG_COUNT(mp)))), \ + (2 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ + XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink) + +/* + * For create we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: block size + * the superblock for the nlink flag: sector size + * the directory btree: (max depth + v2) * dir block size + * the directory inode\'s bmap btree: (max depth + v2) * block size + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the superblock for the nlink flag: sector size + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (max depth - 1) * block size + */ +#define XFS_CALC_CREATE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B(mp, 1) + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (3 + XFS_DIROP_LOG_COUNT(mp)))), \ + (3 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ + XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_CREATE_LOG_RES(mp) ((mp)->m_reservations.tr_create) + +/* + * Making a new directory is the same as creating a new file. + */ +#define XFS_CALC_MKDIR_LOG_RES(mp) XFS_CALC_CREATE_LOG_RES(mp) + +#define XFS_MKDIR_LOG_RES(mp) ((mp)->m_reservations.tr_mkdir) + +/* + * In freeing an inode we can modify: + * the inode being freed: inode size + * the super block free inode counter: sector size + * the agi hash list and counters: sector size + * the inode btree entry: block size + * the on disk inode before ours in the agi hash list: inode cluster size + */ +#define XFS_CALC_IFREE_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), 1) + \ + MAX((__uint16_t)XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \ + (128 * 5)) + +#define XFS_IFREE_LOG_RES(mp) ((mp)->m_reservations.tr_ifree) + +/* + * When only changing the inode we log the inode and possibly the superblock + * We also add a bit of slop for the transaction stuff. + */ +#define XFS_CALC_ICHANGE_LOG_RES(mp) ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + 512) + +#define XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange) + +/* + * Growing the data section of the filesystem. + * superblock + * agi and agf + * allocation btrees + */ +#define XFS_CALC_GROWDATA_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize * 3 + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_GROWDATA_LOG_RES(mp) ((mp)->m_reservations.tr_growdata) + +/* + * Growing the rt section of the filesystem. + * In the first set of transactions (ALLOC) we allocate space to the + * bitmap or summary files. + * superblock: sector size + * agf of the ag from which the extent is allocated: sector size + * bmap btree for bitmap/summary inode: max depth * blocksize + * bitmap/summary inode: inode size + * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize + */ +#define XFS_CALC_GROWRTALLOC_LOG_RES(mp) \ + (2 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ + (mp)->m_sb.sb_inodesize + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * \ + (3 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_GROWRTALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_growrtalloc) + +/* + * Growing the rt section of the filesystem. + * In the second set of transactions (ZERO) we zero the new metadata blocks. + * one bitmap/summary block: blocksize + */ +#define XFS_CALC_GROWRTZERO_LOG_RES(mp) \ + ((mp)->m_sb.sb_blocksize + 128) + +#define XFS_GROWRTZERO_LOG_RES(mp) ((mp)->m_reservations.tr_growrtzero) + +/* + * Growing the rt section of the filesystem. + * In the third set of transactions (FREE) we update metadata without + * allocating any new blocks. + * superblock: sector size + * bitmap inode: inode size + * summary inode: inode size + * one bitmap block: blocksize + * summary blocks: new summary size + */ +#define XFS_CALC_GROWRTFREE_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize + \ + 2 * (mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_blocksize + \ + (mp)->m_rsumsize + \ + (128 * 5)) + +#define XFS_GROWRTFREE_LOG_RES(mp) ((mp)->m_reservations.tr_growrtfree) + +/* + * Logging the inode modification timestamp on a synchronous write. + * inode + */ +#define XFS_CALC_SWRITE_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + 128) + +#define XFS_SWRITE_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Logging the inode timestamps on an fsync -- same as SWRITE + * as long as SWRITE logs the entire inode core + */ +#define XFS_FSYNC_TS_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Logging the inode mode bits when writing a setuid/setgid file + * inode + */ +#define XFS_CALC_WRITEID_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + 128) + +#define XFS_WRITEID_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Converting the inode from non-attributed to attributed. + * the inode being converted: inode size + * agf block and superblock (for block allocation) + * the new block (directory sized) + * bmap blocks for the new directory block + * allocation btrees + */ +#define XFS_CALC_ADDAFORK_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize * 2 + \ + (mp)->m_dirblksize + \ + (XFS_DIR_IS_V1(mp) ? 0 : \ + XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1))) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (4 + \ + (XFS_DIR_IS_V1(mp) ? 0 : \ + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) + +/* + * Removing the attribute fork of a file + * the inode being truncated: inode size + * the inode\'s bmap btree: max depth * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ATTRINVAL_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ + (128 * (1 + XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)))), \ + ((4 * (mp)->m_sb.sb_sectsize) + \ + (4 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 4) + \ + (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) + +#define XFS_ATTRINVAL_LOG_RES(mp) ((mp)->m_reservations.tr_attrinval) + +/* + * Setting an attribute. + * the inode getting the attribute + * the superblock for allocations + * the agfs extents are allocated from + * the attribute btree * max depth + * the inode allocation btree + * Since attribute transaction space is dependent on the size of the attribute, + * the calculation is done partially at mount time and partially at runtime. + */ +#define XFS_CALC_ATTRSET_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ + (128 * (2 + XFS_DA_NODE_MAXDEPTH))) + +#define XFS_ATTRSET_LOG_RES(mp, ext) \ + ((mp)->m_reservations.tr_attrset + \ + (ext * (mp)->m_sb.sb_sectsize) + \ + (ext * XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))) + \ + (128 * (ext + (ext * XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))))) + +/* + * Removing an attribute. + * the inode: inode size + * the attribute btree could join: max depth * block size + * the inode bmap btree could join or split: max depth * block size + * And the bmap_finish transaction can free the attr blocks freed giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ATTRRM_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ + (128 * (1 + XFS_DA_NODE_MAXDEPTH + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm) + +/* + * Clearing a bad agino number in an agi hash bucket. + */ +#define XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize + 128) + +#define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi) + + +/* + * Various log count values. + */ +#define XFS_DEFAULT_LOG_COUNT 1 +#define XFS_DEFAULT_PERM_LOG_COUNT 2 +#define XFS_ITRUNCATE_LOG_COUNT 2 +#define XFS_CREATE_LOG_COUNT 2 +#define XFS_MKDIR_LOG_COUNT 3 +#define XFS_SYMLINK_LOG_COUNT 3 +#define XFS_REMOVE_LOG_COUNT 2 +#define XFS_LINK_LOG_COUNT 2 +#define XFS_RENAME_LOG_COUNT 2 +#define XFS_WRITE_LOG_COUNT 2 +#define XFS_ADDAFORK_LOG_COUNT 2 +#define XFS_ATTRINVAL_LOG_COUNT 1 +#define XFS_ATTRSET_LOG_COUNT 3 +#define XFS_ATTRRM_LOG_COUNT 3 + +/* + * Here we centralize the specification of XFS meta-data buffer + * reference count values. This determine how hard the buffer + * cache tries to hold onto the buffer. + */ +#define XFS_AGF_REF 4 +#define XFS_AGI_REF 4 +#define XFS_AGFL_REF 3 +#define XFS_INO_BTREE_REF 3 +#define XFS_ALLOC_BTREE_REF 2 +#define XFS_BMAP_BTREE_REF 2 +#define XFS_DIR_BTREE_REF 2 +#define XFS_ATTR_BTREE_REF 1 +#define XFS_INO_REF 1 +#define XFS_DQUOT_REF 1 + +#ifdef __KERNEL__ +/* + * XFS transaction mechanism exported interfaces that are + * actually macros. + */ +#define xfs_trans_get_log_res(tp) ((tp)->t_log_res) +#define xfs_trans_get_log_count(tp) ((tp)->t_log_count) +#define xfs_trans_get_block_res(tp) ((tp)->t_blk_res) +#define xfs_trans_set_sync(tp) ((tp)->t_flags |= XFS_TRANS_SYNC) + +#ifdef DEBUG +#define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (long)d) +#define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (long)d) +#define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (long)d) +#else +#define xfs_trans_agblocks_delta(tp, d) +#define xfs_trans_agflist_delta(tp, d) +#define xfs_trans_agbtree_delta(tp, d) +#endif + +/* + * XFS transaction mechanism exported interfaces. + */ +void xfs_trans_init(struct xfs_mount *); +xfs_trans_t *xfs_trans_alloc(struct xfs_mount *, uint); +xfs_trans_t *_xfs_trans_alloc(struct xfs_mount *, uint); +xfs_trans_t *xfs_trans_dup(xfs_trans_t *); +int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, + uint, uint); +void xfs_trans_callback(xfs_trans_t *, + void (*)(xfs_trans_t *, void *), void *); +void xfs_trans_mod_sb(xfs_trans_t *, uint, long); +struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct xfs_buftarg *, xfs_daddr_t, + int, uint); +int xfs_trans_read_buf(struct xfs_mount *, xfs_trans_t *, + struct xfs_buftarg *, xfs_daddr_t, int, uint, + struct xfs_buf **); +struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int); + +void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bhold_until_committed(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); +void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); +int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *, + xfs_ino_t , uint, struct xfs_inode **); +void xfs_trans_iput(xfs_trans_t *, struct xfs_inode *, uint); +void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint); +void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *); +void xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *); +void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); +void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); +struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); +void xfs_efi_release(struct xfs_efi_log_item *, uint); +void xfs_trans_log_efi_extent(xfs_trans_t *, + struct xfs_efi_log_item *, + xfs_fsblock_t, + xfs_extlen_t); +struct xfs_efd_log_item *xfs_trans_get_efd(xfs_trans_t *, + struct xfs_efi_log_item *, + uint); +void xfs_trans_log_efd_extent(xfs_trans_t *, + struct xfs_efd_log_item *, + xfs_fsblock_t, + xfs_extlen_t); +void xfs_trans_log_create_rpc(xfs_trans_t *, int, xfs_ino_t); +void xfs_trans_log_setattr_rpc(xfs_trans_t *, int); +int xfs_trans_commit(xfs_trans_t *, uint flags, xfs_lsn_t *); +void xfs_trans_commit_async(struct xfs_mount *); +void xfs_trans_cancel(xfs_trans_t *, int); +void xfs_trans_ail_init(struct xfs_mount *); +xfs_lsn_t xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); +xfs_lsn_t xfs_trans_tail_ail(struct xfs_mount *); +void xfs_trans_unlocked_item(struct xfs_mount *, + xfs_log_item_t *); +xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp, + xfs_agnumber_t ag, + xfs_extlen_t idx); + +/* + * Not necessarily exported, but used outside a single file. + */ +int xfs_trans_lsn_danger(struct xfs_mount *, xfs_lsn_t); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_TRANS_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_trans_ail.c linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_ail.c --- linux-2.4.19/fs/xfs/xfs_trans_ail.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_ail.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +STATIC void xfs_ail_insert(xfs_ail_entry_t *, xfs_log_item_t *); +STATIC xfs_log_item_t * xfs_ail_delete(xfs_ail_entry_t *, xfs_log_item_t *); +STATIC xfs_log_item_t * xfs_ail_min(xfs_ail_entry_t *); +STATIC xfs_log_item_t * xfs_ail_next(xfs_ail_entry_t *, xfs_log_item_t *); + +#ifdef XFSDEBUG +STATIC void xfs_ail_check(xfs_ail_entry_t *); +#else +#define xfs_ail_check(a) +#endif /* XFSDEBUG */ + + +/* + * This is called by the log manager code to determine the LSN + * of the tail of the log. This is exactly the LSN of the first + * item in the AIL. If the AIL is empty, then this function + * returns 0. + * + * We need the AIL lock in order to get a coherent read of the + * lsn of the last item in the AIL. + */ +xfs_lsn_t +xfs_trans_tail_ail( + xfs_mount_t *mp) +{ + xfs_lsn_t lsn; + xfs_log_item_t *lip; + SPLDECL(s); + + AIL_LOCK(mp,s); + lip = xfs_ail_min(&(mp->m_ail)); + if (lip == NULL) { + lsn = (xfs_lsn_t)0; + } else { + lsn = lip->li_lsn; + } + AIL_UNLOCK(mp, s); + + return lsn; +} + +/* + * xfs_trans_push_ail + * + * This routine is called to move the tail of the AIL + * forward. It does this by trying to flush items in the AIL + * whose lsns are below the given threshold_lsn. + * + * The routine returns the lsn of the tail of the log. + */ +xfs_lsn_t +xfs_trans_push_ail( + xfs_mount_t *mp, + xfs_lsn_t threshold_lsn) +{ + xfs_lsn_t lsn; + xfs_log_item_t *lip; + int gen; + int restarts; + int lock_result; + int flush_log; + SPLDECL(s); + +#define XFS_TRANS_PUSH_AIL_RESTARTS 10 + + AIL_LOCK(mp,s); + lip = xfs_trans_first_ail(mp, &gen); + if (lip == NULL || XFS_FORCED_SHUTDOWN(mp)) { + /* + * Just return if the AIL is empty. + */ + AIL_UNLOCK(mp, s); + return (xfs_lsn_t)0; + } + + XFS_STATS_INC(xfsstats.xs_push_ail); + + /* + * While the item we are looking at is below the given threshold + * try to flush it out. Make sure to limit the number of times + * we allow xfs_trans_next_ail() to restart scanning from the + * beginning of the list. We'd like not to stop until we've at least + * tried to push on everything in the AIL with an LSN less than + * the given threshold. However, we may give up before that if + * we realize that we've been holding the AIL_LOCK for 'too long', + * blocking interrupts. Currently, too long is < 500us roughly. + */ + flush_log = 0; + restarts = 0; + while (((restarts < XFS_TRANS_PUSH_AIL_RESTARTS) && + (XFS_LSN_CMP(lip->li_lsn, threshold_lsn) < 0))) { + /* + * If we can lock the item without sleeping, unlock + * the AIL lock and flush the item. Then re-grab the + * AIL lock so we can look for the next item on the + * AIL. Since we unlock the AIL while we flush the + * item, the next routine may start over again at the + * the beginning of the list if anything has changed. + * That is what the generation count is for. + * + * If we can't lock the item, either its holder will flush + * it or it is already being flushed or it is being relogged. + * In any of these case it is being taken care of and we + * can just skip to the next item in the list. + */ + lock_result = IOP_TRYLOCK(lip); + switch (lock_result) { + case XFS_ITEM_SUCCESS: + AIL_UNLOCK(mp, s); + XFS_STATS_INC(xfsstats.xs_push_ail_success); + IOP_PUSH(lip); + AIL_LOCK(mp,s); + break; + + case XFS_ITEM_PUSHBUF: + AIL_UNLOCK(mp, s); + XFS_STATS_INC(xfsstats.xs_push_ail_pushbuf); +#ifdef XFSRACEDEBUG + delay_for_intr(); + delay(300); +#endif + ASSERT(lip->li_ops->iop_pushbuf); + ASSERT(lip); + IOP_PUSHBUF(lip); + AIL_LOCK(mp,s); + break; + + case XFS_ITEM_PINNED: + XFS_STATS_INC(xfsstats.xs_push_ail_pinned); + flush_log = 1; + break; + + case XFS_ITEM_LOCKED: + XFS_STATS_INC(xfsstats.xs_push_ail_locked); + break; + + case XFS_ITEM_FLUSHING: + XFS_STATS_INC(xfsstats.xs_push_ail_flushing); + break; + + default: + ASSERT(0); + break; + } + + lip = xfs_trans_next_ail(mp, lip, &gen, &restarts); + if (lip == NULL) { + break; + } + if (XFS_FORCED_SHUTDOWN(mp)) { + /* + * Just return if we shut down during the last try. + */ + AIL_UNLOCK(mp, s); + return (xfs_lsn_t)0; + } + + } + + if (flush_log) { + /* + * If something we need to push out was pinned, then + * push out the log so it will become unpinned and + * move forward in the AIL. + */ + AIL_UNLOCK(mp, s); + XFS_STATS_INC(xfsstats.xs_push_ail_flush); + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + AIL_LOCK(mp, s); + } + + lip = xfs_ail_min(&(mp->m_ail)); + if (lip == NULL) { + lsn = (xfs_lsn_t)0; + } else { + lsn = lip->li_lsn; + } + + AIL_UNLOCK(mp, s); + return lsn; +} /* xfs_trans_push_ail */ + + +/* + * This is to be called when an item is unlocked that may have + * been in the AIL. It will wake up the first member of the AIL + * wait list if this item's unlocking might allow it to progress. + * If the item is in the AIL, then we need to get the AIL lock + * while doing our checking so we don't race with someone going + * to sleep waiting for this event in xfs_trans_push_ail(). + */ +void +xfs_trans_unlocked_item( + xfs_mount_t *mp, + xfs_log_item_t *lip) +{ + xfs_log_item_t *min_lip; + + /* + * If we're forcibly shutting down, we may have + * unlocked log items arbitrarily. The last thing + * we want to do is to move the tail of the log + * over some potentially valid data. + */ + if (!(lip->li_flags & XFS_LI_IN_AIL) || + XFS_FORCED_SHUTDOWN(mp)) { + return; + } + + /* + * This is the one case where we can call into xfs_ail_min() + * without holding the AIL lock because we only care about the + * case where we are at the tail of the AIL. If the object isn't + * at the tail, it doesn't matter what result we get back. This + * is slightly racy because since we were just unlocked, we could + * go to sleep between the call to xfs_ail_min and the call to + * xfs_log_move_tail, have someone else lock us, commit to us disk, + * move us out of the tail of the AIL, and then we wake up. However, + * the call to xfs_log_move_tail() doesn't do anything if there's + * not enough free space to wake people up so we're safe calling it. + */ + min_lip = xfs_ail_min(&mp->m_ail); + + if (min_lip == lip) + xfs_log_move_tail(mp, 1); +} /* xfs_trans_unlocked_item */ + + +/* + * Update the position of the item in the AIL with the new + * lsn. If it is not yet in the AIL, add it. Otherwise, move + * it to its new position by removing it and re-adding it. + * + * Wakeup anyone with an lsn less than the item's lsn. If the item + * we move in the AIL is the minimum one, update the tail lsn in the + * log manager. + * + * Increment the AIL's generation count to indicate that the tree + * has changed. + * + * This function must be called with the AIL lock held. The lock + * is dropped before returning, so the caller must pass in the + * cookie returned by AIL_LOCK. + */ +void +xfs_trans_update_ail( + xfs_mount_t *mp, + xfs_log_item_t *lip, + xfs_lsn_t lsn, + unsigned long s) +{ + xfs_ail_entry_t *ailp; + xfs_log_item_t *dlip=NULL; + xfs_log_item_t *mlip; /* ptr to minimum lip */ + + ailp = &(mp->m_ail); + mlip = xfs_ail_min(ailp); + + if (lip->li_flags & XFS_LI_IN_AIL) { + dlip = xfs_ail_delete(ailp, lip); + ASSERT(dlip == lip); + } else { + lip->li_flags |= XFS_LI_IN_AIL; + } + + lip->li_lsn = lsn; + + xfs_ail_insert(ailp, lip); + mp->m_ail_gen++; + + if (mlip == dlip) { + mlip = xfs_ail_min(&(mp->m_ail)); + AIL_UNLOCK(mp, s); + xfs_log_move_tail(mp, mlip->li_lsn); + } else { + AIL_UNLOCK(mp, s); + } + + +} /* xfs_trans_update_ail */ + +/* + * Delete the given item from the AIL. It must already be in + * the AIL. + * + * Wakeup anyone with an lsn less than item's lsn. If the item + * we delete in the AIL is the minimum one, update the tail lsn in the + * log manager. + * + * Clear the IN_AIL flag from the item, reset its lsn to 0, and + * bump the AIL's generation count to indicate that the tree + * has changed. + * + * This function must be called with the AIL lock held. The lock + * is dropped before returning, so the caller must pass in the + * cookie returned by AIL_LOCK. + */ +void +xfs_trans_delete_ail( + xfs_mount_t *mp, + xfs_log_item_t *lip, + unsigned long s) +{ + xfs_ail_entry_t *ailp; + xfs_log_item_t *dlip; + xfs_log_item_t *mlip; + + if (lip->li_flags & XFS_LI_IN_AIL) { + ailp = &(mp->m_ail); + mlip = xfs_ail_min(ailp); + dlip = xfs_ail_delete(ailp, lip); + ASSERT(dlip == lip); + + + lip->li_flags &= ~XFS_LI_IN_AIL; + lip->li_lsn = 0; + mp->m_ail_gen++; + + if (mlip == dlip) { + mlip = xfs_ail_min(&(mp->m_ail)); + AIL_UNLOCK(mp, s); + xfs_log_move_tail(mp, (mlip ? mlip->li_lsn : 0)); + } else { + AIL_UNLOCK(mp, s); + } + } + else { + /* + * If the file system is not being shutdown, we are in + * serious trouble if we get to this stage. + */ + if (XFS_FORCED_SHUTDOWN(mp)) + AIL_UNLOCK(mp, s); + else { + xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp, + "xfs_trans_delete_ail: attempting to delete a log item that is not in the AIL"); + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); + AIL_UNLOCK(mp, s); + } + } +} + + + +/* + * Return the item in the AIL with the smallest lsn. + * Return the current tree generation number for use + * in calls to xfs_trans_next_ail(). + */ +xfs_log_item_t * +xfs_trans_first_ail( + xfs_mount_t *mp, + int *gen) +{ + xfs_log_item_t *lip; + + lip = xfs_ail_min(&(mp->m_ail)); + *gen = (int)mp->m_ail_gen; + + return (lip); +} + +/* + * If the generation count of the tree has not changed since the + * caller last took something from the AIL, then return the elmt + * in the tree which follows the one given. If the count has changed, + * then return the minimum elmt of the AIL and bump the restarts counter + * if one is given. + */ +xfs_log_item_t * +xfs_trans_next_ail( + xfs_mount_t *mp, + xfs_log_item_t *lip, + int *gen, + int *restarts) +{ + xfs_log_item_t *nlip; + + ASSERT(mp && lip && gen); + if (mp->m_ail_gen == *gen) { + nlip = xfs_ail_next(&(mp->m_ail), lip); + } else { + nlip = xfs_ail_min(&(mp->m_ail)); + *gen = (int)mp->m_ail_gen; + if (restarts != NULL) { + XFS_STATS_INC(xfsstats.xs_push_ail_restarts); + (*restarts)++; + } + } + + return (nlip); +} + + +/* + * The active item list (AIL) is a doubly linked list of log + * items sorted by ascending lsn. The base of the list is + * a forw/back pointer pair embedded in the xfs mount structure. + * The base is initialized with both pointers pointing to the + * base. This case always needs to be distinguished, because + * the base has no lsn to look at. We almost always insert + * at the end of the list, so on inserts we search from the + * end of the list to find where the new item belongs. + */ + +/* + * Initialize the doubly linked list to point only to itself. + */ +void +xfs_trans_ail_init( + xfs_mount_t *mp) +{ + mp->m_ail.ail_forw = (xfs_log_item_t*)&(mp->m_ail); + mp->m_ail.ail_back = (xfs_log_item_t*)&(mp->m_ail); +} + +/* + * Insert the given log item into the AIL. + * We almost always insert at the end of the list, so on inserts + * we search from the end of the list to find where the + * new item belongs. + */ +STATIC void +xfs_ail_insert( + xfs_ail_entry_t *base, + xfs_log_item_t *lip) +/* ARGSUSED */ +{ + xfs_log_item_t *next_lip; + + /* + * If the list is empty, just insert the item. + */ + if (base->ail_back == (xfs_log_item_t*)base) { + base->ail_forw = lip; + base->ail_back = lip; + lip->li_ail.ail_forw = (xfs_log_item_t*)base; + lip->li_ail.ail_back = (xfs_log_item_t*)base; + return; + } + + next_lip = base->ail_back; + while ((next_lip != (xfs_log_item_t*)base) && + (XFS_LSN_CMP(next_lip->li_lsn, lip->li_lsn) > 0)) { + next_lip = next_lip->li_ail.ail_back; + } + ASSERT((next_lip == (xfs_log_item_t*)base) || + (XFS_LSN_CMP(next_lip->li_lsn, lip->li_lsn) <= 0)); + lip->li_ail.ail_forw = next_lip->li_ail.ail_forw; + lip->li_ail.ail_back = next_lip; + next_lip->li_ail.ail_forw = lip; + lip->li_ail.ail_forw->li_ail.ail_back = lip; + + xfs_ail_check(base); + return; +} + +/* + * Delete the given item from the AIL. Return a pointer to the item. + */ +/*ARGSUSED*/ +STATIC xfs_log_item_t * +xfs_ail_delete( + xfs_ail_entry_t *base, + xfs_log_item_t *lip) +/* ARGSUSED */ +{ + lip->li_ail.ail_forw->li_ail.ail_back = lip->li_ail.ail_back; + lip->li_ail.ail_back->li_ail.ail_forw = lip->li_ail.ail_forw; + lip->li_ail.ail_forw = NULL; + lip->li_ail.ail_back = NULL; + + xfs_ail_check(base); + return lip; +} + +/* + * Return a pointer to the first item in the AIL. + * If the AIL is empty, then return NULL. + */ +STATIC xfs_log_item_t * +xfs_ail_min( + xfs_ail_entry_t *base) +/* ARGSUSED */ +{ + register xfs_log_item_t *forw = base->ail_forw; + if (forw == (xfs_log_item_t*)base) { + return NULL; + } + return forw; +} + +/* + * Return a pointer to the item which follows + * the given item in the AIL. If the given item + * is the last item in the list, then return NULL. + */ +STATIC xfs_log_item_t * +xfs_ail_next( + xfs_ail_entry_t *base, + xfs_log_item_t *lip) +/* ARGSUSED */ +{ + if (lip->li_ail.ail_forw == (xfs_log_item_t*)base) { + return NULL; + } + return lip->li_ail.ail_forw; + +} + +#ifdef XFSDEBUG +/* + * Check that the list is sorted as it should be. + */ +STATIC void +xfs_ail_check( + xfs_ail_entry_t *base) +{ + xfs_log_item_t *lip; + xfs_log_item_t *prev_lip; + + lip = base->ail_forw; + if (lip == (xfs_log_item_t*)base) { + /* + * Make sure the pointers are correct when the list + * is empty. + */ + ASSERT(base->ail_back == (xfs_log_item_t*)base); + return; + } + + /* + * Walk the list checking forward and backward pointers, + * lsn ordering, and that every entry has the XFS_LI_IN_AIL + * flag set. + */ + prev_lip = (xfs_log_item_t*)base; + while (lip != (xfs_log_item_t*)base) { + if (prev_lip != (xfs_log_item_t*)base) { + ASSERT(prev_lip->li_ail.ail_forw == lip); + ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); + } + ASSERT(lip->li_ail.ail_back == prev_lip); + ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); + prev_lip = lip; + lip = lip->li_ail.ail_forw; + } + ASSERT(lip == (xfs_log_item_t*)base); + ASSERT(base->ail_back == prev_lip); +} +#endif /* XFSDEBUG */ + + + diff -Nur linux-2.4.19/fs/xfs/xfs_trans_buf.c linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_buf.c --- linux-2.4.19/fs/xfs/xfs_trans_buf.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_buf.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,1085 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC xfs_buf_t *xfs_trans_buf_item_match(xfs_trans_t *, xfs_buftarg_t *, + xfs_daddr_t, int); +STATIC xfs_buf_t *xfs_trans_buf_item_match_all(xfs_trans_t *, xfs_buftarg_t *, + xfs_daddr_t, int); + + +/* + * Get and lock the buffer for the caller if it is not already + * locked within the given transaction. If it is already locked + * within the transaction, just increment its lock recursion count + * and return a pointer to it. + * + * Use the fast path function xfs_trans_buf_item_match() or the buffer + * cache routine incore_match() to find the buffer + * if it is already owned by this transaction. + * + * If we don't already own the buffer, use get_buf() to get it. + * If it doesn't yet have an associated xfs_buf_log_item structure, + * then allocate one and add the item to this transaction. + * + * If the transaction pointer is NULL, make this just a normal + * get_buf() call. + */ +xfs_buf_t * +xfs_trans_get_buf(xfs_trans_t *tp, + xfs_buftarg_t *target_dev, + xfs_daddr_t blkno, + int len, + uint flags) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + + if (flags == 0) + flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; + + /* + * Default to a normal get_buf() call if the tp is NULL. + */ + if (tp == NULL) { + bp = xfs_buf_get_flags(target_dev, blkno, len, + flags | BUF_BUSY); + return(bp); + } + + /* + * If we find the buffer in the cache with this transaction + * pointer in its b_fsprivate2 field, then we know we already + * have it locked. In this case we just increment the lock + * recursion count and return the buffer to the caller. + */ + if (tp->t_items.lic_next == NULL) { + bp = xfs_trans_buf_item_match(tp, target_dev, blkno, len); + } else { + bp = xfs_trans_buf_item_match_all(tp, target_dev, blkno, len); + } + if (bp != NULL) { + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + if (XFS_FORCED_SHUTDOWN(tp->t_mountp)) { + xfs_buftrace("TRANS GET RECUR SHUT", bp); + XFS_BUF_SUPER_STALE(bp); + } + /* + * If the buffer is stale then it was binval'ed + * since last read. This doesn't matter since the + * caller isn't allowed to use the data anyway. + */ + else if (XFS_BUF_ISSTALE(bp)) { + xfs_buftrace("TRANS GET RECUR STALE", bp); + ASSERT(!XFS_BUF_ISDELAYWRITE(bp)); + } + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(bip != NULL); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + bip->bli_recur++; + xfs_buftrace("TRANS GET RECUR", bp); + xfs_buf_item_trace("GET RECUR", bip); + return (bp); + } + + /* + * We always specify the BUF_BUSY flag within a transaction so + * that get_buf does not try to push out a delayed write buffer + * which might cause another transaction to take place (if the + * buffer was delayed alloc). Such recursive transactions can + * easily deadlock with our current transaction as well as cause + * us to run out of stack space. + */ + bp = xfs_buf_get_flags(target_dev, blkno, len, flags | BUF_BUSY); + if (bp == NULL) { + return NULL; + } + + ASSERT(!XFS_BUF_GETERROR(bp)); + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, tp->t_mountp); + + /* + * Set the recursion count for the buffer within this transaction + * to 0. + */ + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + bip->bli_recur = 0; + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buftrace("TRANS GET", bp); + xfs_buf_item_trace("GET", bip); + return (bp); +} + +/* + * Get and lock the superblock buffer of this file system for the + * given transaction. + * + * We don't need to use incore_match() here, because the superblock + * buffer is a private buffer which we keep a pointer to in the + * mount structure. + */ +xfs_buf_t * +xfs_trans_getsb(xfs_trans_t *tp, + struct xfs_mount *mp, + int flags) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + + /* + * Default to just trying to lock the superblock buffer + * if tp is NULL. + */ + if (tp == NULL) { + return (xfs_getsb(mp, flags)); + } + + /* + * If the superblock buffer already has this transaction + * pointer in its b_fsprivate2 field, then we know we already + * have it locked. In this case we just increment the lock + * recursion count and return the buffer to the caller. + */ + bp = mp->m_sb_bp; + if (XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp) { + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(bip != NULL); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + bip->bli_recur++; + xfs_buf_item_trace("GETSB RECUR", bip); + return (bp); + } + + bp = xfs_getsb(mp, flags); + if (bp == NULL) { + return NULL; + } + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, mp); + + /* + * Set the recursion count for the buffer within this transaction + * to 0. + */ + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + bip->bli_recur = 0; + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buf_item_trace("GETSB", bip); + return (bp); +} + +#ifdef DEBUG +dev_t xfs_error_dev = 0; +int xfs_do_error; +int xfs_req_num; +int xfs_error_mod = 33; +#endif + +/* + * Get and lock the buffer for the caller if it is not already + * locked within the given transaction. If it has not yet been + * read in, read it from disk. If it is already locked + * within the transaction and already read in, just increment its + * lock recursion count and return a pointer to it. + * + * Use the fast path function xfs_trans_buf_item_match() or the buffer + * cache routine incore_match() to find the buffer + * if it is already owned by this transaction. + * + * If we don't already own the buffer, use read_buf() to get it. + * If it doesn't yet have an associated xfs_buf_log_item structure, + * then allocate one and add the item to this transaction. + * + * If the transaction pointer is NULL, make this just a normal + * read_buf() call. + */ +int +xfs_trans_read_buf( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_buftarg_t *target, + xfs_daddr_t blkno, + int len, + uint flags, + xfs_buf_t **bpp) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + int error; + + if (flags == 0) + flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; + + /* + * Default to a normal get_buf() call if the tp is NULL. + */ + if (tp == NULL) { + bp = xfs_buf_read_flags(target, blkno, len, flags | BUF_BUSY); + if (!bp) + return XFS_ERROR(ENOMEM); + + if ((bp != NULL) && (XFS_BUF_GETERROR(bp) != 0)) { + xfs_ioerror_alert("xfs_trans_read_buf", mp, + bp, blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + return error; + } +#ifdef DEBUG + if (xfs_do_error && (bp != NULL)) { + if (xfs_error_dev == target->pbr_dev) { + if (((xfs_req_num++) % xfs_error_mod) == 0) { + xfs_buf_relse(bp); + printk("Returning error!\n"); + return XFS_ERROR(EIO); + } + } + } +#endif + if (XFS_FORCED_SHUTDOWN(mp)) + goto shutdown_abort; + *bpp = bp; + return 0; + } + + /* + * If we find the buffer in the cache with this transaction + * pointer in its b_fsprivate2 field, then we know we already + * have it locked. If it is already read in we just increment + * the lock recursion count and return the buffer to the caller. + * If the buffer is not yet read in, then we read it in, increment + * the lock recursion count, and return it to the caller. + */ + if (tp->t_items.lic_next == NULL) { + bp = xfs_trans_buf_item_match(tp, target, blkno, len); + } else { + bp = xfs_trans_buf_item_match_all(tp, target, blkno, len); + } + if (bp != NULL) { + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT((XFS_BUF_ISERROR(bp)) == 0); + if (!(XFS_BUF_ISDONE(bp))) { + xfs_buftrace("READ_BUF_INCORE !DONE", bp); + ASSERT(!XFS_BUF_ISASYNC(bp)); + XFS_BUF_READ(bp); + xfsbdstrat(tp->t_mountp, bp); + xfs_iowait(bp); + if (XFS_BUF_GETERROR(bp) != 0) { + xfs_ioerror_alert("xfs_trans_read_buf", mp, + bp, blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + /* + * We can gracefully recover from most + * read errors. Ones we can't are those + * that happen after the transaction's + * already dirty. + */ + if (tp->t_flags & XFS_TRANS_DIRTY) + xfs_force_shutdown(tp->t_mountp, + XFS_METADATA_IO_ERROR); + return error; + } + } + /* + * We never locked this buf ourselves, so we shouldn't + * brelse it either. Just get out. + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + xfs_buftrace("READ_BUF_INCORE XFSSHUTDN", bp); + *bpp = NULL; + return XFS_ERROR(EIO); + } + + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + bip->bli_recur++; + + ASSERT(atomic_read(&bip->bli_refcount) > 0); + xfs_buf_item_trace("READ RECUR", bip); + *bpp = bp; + return 0; + } + + /* + * We always specify the BUF_BUSY flag within a transaction so + * that get_buf does not try to push out a delayed write buffer + * which might cause another transaction to take place (if the + * buffer was delayed alloc). Such recursive transactions can + * easily deadlock with our current transaction as well as cause + * us to run out of stack space. + */ + bp = xfs_buf_read_flags(target, blkno, len, flags | BUF_BUSY); + if (bp == NULL) { + *bpp = NULL; + return 0; + } + if (XFS_BUF_GETERROR(bp) != 0) { + XFS_BUF_SUPER_STALE(bp); + xfs_buftrace("READ ERROR", bp); + error = XFS_BUF_GETERROR(bp); + + xfs_ioerror_alert("xfs_trans_read_buf", mp, + bp, blkno); + if (tp->t_flags & XFS_TRANS_DIRTY) + xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR); + xfs_buf_relse(bp); + return error; + } +#ifdef DEBUG + if (xfs_do_error && !(tp->t_flags & XFS_TRANS_DIRTY)) { + if (xfs_error_dev == target->pbr_dev) { + if (((xfs_req_num++) % xfs_error_mod) == 0) { + xfs_force_shutdown(tp->t_mountp, + XFS_METADATA_IO_ERROR); + xfs_buf_relse(bp); + printk("Returning error in trans!\n"); + return XFS_ERROR(EIO); + } + } + } +#endif + if (XFS_FORCED_SHUTDOWN(mp)) + goto shutdown_abort; + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, tp->t_mountp); + + /* + * Set the recursion count for the buffer within this transaction + * to 0. + */ + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + bip->bli_recur = 0; + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buftrace("TRANS READ", bp); + xfs_buf_item_trace("READ", bip); + *bpp = bp; + return 0; + +shutdown_abort: + /* + * the theory here is that buffer is good but we're + * bailing out because the filesystem is being forcibly + * shut down. So we should leave the b_flags alone since + * the buffer's not staled and just get out. + */ +#if defined(DEBUG) + if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp)) + cmn_err(CE_NOTE, "about to pop assert, bp == 0x%x", bp); +#endif + ASSERT((XFS_BUF_BFLAGS(bp) & (XFS_B_STALE|XFS_B_DELWRI)) != + (XFS_B_STALE|XFS_B_DELWRI)); + + xfs_buftrace("READ_BUF XFSSHUTDN", bp); + xfs_buf_relse(bp); + *bpp = NULL; + return XFS_ERROR(EIO); +} + + +/* + * Release the buffer bp which was previously acquired with one of the + * xfs_trans_... buffer allocation routines if the buffer has not + * been modified within this transaction. If the buffer is modified + * within this transaction, do decrement the recursion count but do + * not release the buffer even if the count goes to 0. If the buffer is not + * modified within the transaction, decrement the recursion count and + * release the buffer if the recursion count goes to 0. + * + * If the buffer is to be released and it was not modified before + * this transaction began, then free the buf_log_item associated with it. + * + * If the transaction pointer is NULL, make this just a normal + * brelse() call. + */ +void +xfs_trans_brelse(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + xfs_log_item_t *lip; + xfs_log_item_desc_t *lidp; + + /* + * Default to a normal brelse() call if the tp is NULL. + */ + if (tp == NULL) { + ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); + /* + * If there's a buf log item attached to the buffer, + * then let the AIL know that the buffer is being + * unlocked. + */ + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + if (lip->li_type == XFS_LI_BUF) { + bip = XFS_BUF_FSPRIVATE(bp,xfs_buf_log_item_t*); + xfs_trans_unlocked_item( + bip->bli_item.li_mountp, + lip); + } + } + xfs_buf_relse(bp); + return; + } + + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(bip->bli_item.li_type == XFS_LI_BUF); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + /* + * Find the item descriptor pointing to this buffer's + * log item. It must be there. + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + + /* + * If the release is just for a recursive lock, + * then decrement the count and return. + */ + if (bip->bli_recur > 0) { + bip->bli_recur--; + xfs_buf_item_trace("RELSE RECUR", bip); + return; + } + + /* + * If the buffer is dirty within this transaction, we can't + * release it until we commit. + */ + if (lidp->lid_flags & XFS_LID_DIRTY) { + xfs_buf_item_trace("RELSE DIRTY", bip); + return; + } + + /* + * If the buffer has been invalidated, then we can't release + * it until the transaction commits to disk unless it is re-dirtied + * as part of this transaction. This prevents us from pulling + * the item from the AIL before we should. + */ + if (bip->bli_flags & XFS_BLI_STALE) { + xfs_buf_item_trace("RELSE STALE", bip); + return; + } + + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + xfs_buf_item_trace("RELSE", bip); + + /* + * Free up the log item descriptor tracking the released item. + */ + xfs_trans_free_item(tp, lidp); + + /* + * Clear the hold flag in the buf log item if it is set. + * We wouldn't want the next user of the buffer to + * get confused. + */ + if (bip->bli_flags & XFS_BLI_HOLD) { + bip->bli_flags &= ~XFS_BLI_HOLD; + } + + /* + * Drop our reference to the buf log item. + */ + atomic_dec(&bip->bli_refcount); + + /* + * If the buf item is not tracking data in the log, then + * we must free it before releasing the buffer back to the + * free pool. Before releasing the buffer to the free pool, + * clear the transaction pointer in b_fsprivate2 to dissolve + * its relation to this transaction. + */ + if (!xfs_buf_item_dirty(bip)) { +/*** + ASSERT(bp->b_pincount == 0); +***/ + ASSERT(atomic_read(&bip->bli_refcount) == 0); + ASSERT(!(bip->bli_item.li_flags & XFS_LI_IN_AIL)); + ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF)); + xfs_buf_item_relse(bp); + bip = NULL; + } + XFS_BUF_SET_FSPRIVATE2(bp, NULL); + + /* + * If we've still got a buf log item on the buffer, then + * tell the AIL that the buffer is being unlocked. + */ + if (bip != NULL) { + xfs_trans_unlocked_item(bip->bli_item.li_mountp, + (xfs_log_item_t*)bip); + } + + xfs_buf_relse(bp); + return; +} + +/* + * Add the locked buffer to the transaction. + * The buffer must be locked, and it cannot be associated with any + * transaction. + * + * If the buffer does not yet have a buf log item associated with it, + * then allocate one for it. Then add the buf item to the transaction. + */ +void +xfs_trans_bjoin(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, tp->t_mountp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t *)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * in xfs_trans_get_buf() and friends above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buf_item_trace("BJOIN", bip); +} + +/* + * Mark the buffer as not needing to be unlocked when the buf item's + * IOP_UNLOCK() routine is called. The buffer must already be locked + * and associated with the given transaction. + */ +/* ARGSUSED */ +void +xfs_trans_bhold(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + bip->bli_flags |= XFS_BLI_HOLD; + xfs_buf_item_trace("BHOLD", bip); +} + +/* + * This function is used to indicate that the buffer should not be + * unlocked until the transaction is committed to disk. Since we + * are going to keep the lock held, make the transaction synchronous + * so that the lock is not held too long. + * + * It uses the log item descriptor flag XFS_LID_SYNC_UNLOCK to + * delay the buf items's unlock call until the transaction is + * committed to disk or aborted. + */ +void +xfs_trans_bhold_until_committed(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + + lidp->lid_flags |= XFS_LID_SYNC_UNLOCK; + xfs_buf_item_trace("BHOLD UNTIL COMMIT", bip); + + xfs_trans_set_sync(tp); +} + +/* + * This is called to mark bytes first through last inclusive of the given + * buffer as needing to be logged when the transaction is committed. + * The buffer must already be associated with the given transaction. + * + * First and last are numbers relative to the beginning of this buffer, + * so the first byte in the buffer is numbered 0 regardless of the + * value of b_blkno. + */ +void +xfs_trans_log_buf(xfs_trans_t *tp, + xfs_buf_t *bp, + uint first, + uint last) +{ + xfs_buf_log_item_t *bip; + xfs_log_item_desc_t *lidp; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp))); + ASSERT((XFS_BUF_IODONE_FUNC(bp) == NULL) || + (XFS_BUF_IODONE_FUNC(bp) == xfs_buf_iodone_callbacks)); + + /* + * Mark the buffer as needing to be written out eventually, + * and set its iodone function to remove the buffer's buf log + * item from the AIL and free it when the buffer is flushed + * to disk. See xfs_buf_attach_iodone() for more details + * on li_cb and xfs_buf_iodone_callbacks(). + * If we end up aborting this transaction, we trap this buffer + * inside the b_bdstrat callback so that this won't get written to + * disk. + */ + XFS_BUF_DELAYWRITE(bp); + XFS_BUF_DONE(bp); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks); + bip->bli_item.li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*))xfs_buf_iodone; + + /* + * If we invalidated the buffer within this transaction, then + * cancel the invalidation now that we're dirtying the buffer + * again. There are no races with the code in xfs_buf_item_unpin(), + * because we have a reference to the buffer this entire time. + */ + if (bip->bli_flags & XFS_BLI_STALE) { + xfs_buf_item_trace("BLOG UNSTALE", bip); + bip->bli_flags &= ~XFS_BLI_STALE; + /* note this will have to change for page_buf interface... unstale isn't really an option RMC */ + ASSERT(XFS_BUF_ISSTALE(bp)); + XFS_BUF_UNSTALE(bp); + bip->bli_format.blf_flags &= ~XFS_BLI_CANCEL; + } + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + bip->bli_flags |= XFS_BLI_LOGGED; + xfs_buf_item_log(bip, first, last); + xfs_buf_item_trace("BLOG", bip); +} + + +/* + * This called to invalidate a buffer that is being used within + * a transaction. Typically this is because the blocks in the + * buffer are being freed, so we need to prevent it from being + * written out when we're done. Allowing it to be written again + * might overwrite data in the free blocks if they are reallocated + * to a file. + * + * We prevent the buffer from being written out by clearing the + * B_DELWRI flag. We can't always + * get rid of the buf log item at this point, though, because + * the buffer may still be pinned by another transaction. If that + * is the case, then we'll wait until the buffer is committed to + * disk for the last time (we can tell by the ref count) and + * free it in xfs_buf_item_unpin(). Until it is cleaned up we + * will keep the buffer locked so that the buffer and buf log item + * are not reused. + */ +void +xfs_trans_binval( + xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + if (bip->bli_flags & XFS_BLI_STALE) { + /* + * If the buffer is already invalidated, then + * just return. + */ + ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); + ASSERT(XFS_BUF_ISSTALE(bp)); + ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY))); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_INODE_BUF)); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + ASSERT(lidp->lid_flags & XFS_LID_DIRTY); + ASSERT(tp->t_flags & XFS_TRANS_DIRTY); + xfs_buftrace("XFS_BINVAL RECUR", bp); + xfs_buf_item_trace("BINVAL RECUR", bip); + return; + } + + /* + * Clear the dirty bit in the buffer and set the STALE flag + * in the buf log item. The STALE flag will be used in + * xfs_buf_item_unpin() to determine if it should clean up + * when the last reference to the buf item is given up. + * We set the XFS_BLI_CANCEL flag in the buf log format structure + * and log the buf item. This will be used at recovery time + * to determine that copies of the buffer in the log before + * this should not be replayed. + * We mark the item descriptor and the transaction dirty so + * that we'll hold the buffer until after the commit. + * + * Since we're invalidating the buffer, we also clear the state + * about which parts of the buffer have been logged. We also + * clear the flag indicating that this is an inode buffer since + * the data in the buffer will no longer be valid. + * + * We set the stale bit in the buffer as well since we're getting + * rid of it. + */ + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_STALE(bp); + bip->bli_flags |= XFS_BLI_STALE; + bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_DIRTY); + bip->bli_format.blf_flags &= ~XFS_BLI_INODE_BUF; + bip->bli_format.blf_flags |= XFS_BLI_CANCEL; + bzero((char *)(bip->bli_format.blf_data_map), + (bip->bli_format.blf_map_size * sizeof(uint))); + lidp->lid_flags |= XFS_LID_DIRTY; + tp->t_flags |= XFS_TRANS_DIRTY; + xfs_buftrace("XFS_BINVAL", bp); + xfs_buf_item_trace("BINVAL", bip); +} + +/* + * This call is used to indicate that the buffer contains on-disk + * inodes which must be handled specially during recovery. They + * require special handling because only the di_next_unlinked from + * the inodes in the buffer should be recovered. The rest of the + * data in the buffer is logged via the inodes themselves. + * + * All we do is set the XFS_BLI_INODE_BUF flag in the buffer's log + * format structure so that we'll know what to do at recovery time. + */ +/* ARGSUSED */ +void +xfs_trans_inode_buf( + xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + bip->bli_format.blf_flags |= XFS_BLI_INODE_BUF; +} + + +/* + * Mark the buffer as being one which contains newly allocated + * inodes. We need to make sure that even if this buffer is + * relogged as an 'inode buf' we still recover all of the inode + * images in the face of a crash. This works in coordination with + * xfs_buf_item_committed() to ensure that the buffer remains in the + * AIL at its original location even after it has been relogged. + */ +/* ARGSUSED */ +void +xfs_trans_inode_alloc_buf( + xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF)); + + bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; +} + + +/* + * Similar to xfs_trans_inode_buf(), this marks the buffer as a cluster of + * dquots. However, unlike in inode buffer recovery, dquot buffers get + * recovered in their entirety. (Hence, no XFS_BLI_DQUOT_ALLOC_BUF flag). + * The only thing that makes dquot buffers different from regular + * buffers is that we must not replay dquot bufs when recovering + * if a _corresponding_ quotaoff has happened. We also have to distinguish + * between usr dquot bufs and grp dquot bufs, because usr and grp quotas + * can be turned off independently. + */ +/* ARGSUSED */ +void +xfs_trans_dquot_buf( + xfs_trans_t *tp, + xfs_buf_t *bp, + uint type) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT(type == XFS_BLI_UDQUOT_BUF || + type == XFS_BLI_GDQUOT_BUF); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + bip->bli_format.blf_flags |= type; +} + +/* + * Check to see if a buffer matching the given parameters is already + * a part of the given transaction. Only check the first, embedded + * chunk, since we don't want to spend all day scanning large transactions. + */ +STATIC xfs_buf_t * +xfs_trans_buf_item_match( + xfs_trans_t *tp, + xfs_buftarg_t *target, + xfs_daddr_t blkno, + int len) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *blip; + xfs_buf_t *bp; + int i; + + bp = NULL; + len = BBTOB(len); + licp = &tp->t_items; + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + for (i = 0; i < licp->lic_unused; i++) { + /* + * Skip unoccupied slots. + */ + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + blip = (xfs_buf_log_item_t *)lidp->lid_item; + if (blip->bli_item.li_type != XFS_LI_BUF) { + continue; + } + + bp = blip->bli_buf; + if ((XFS_BUF_TARGET_DEV(bp) == target->pbr_dev) && + (XFS_BUF_ADDR(bp) == blkno) && + (XFS_BUF_COUNT(bp) == len)) { + /* + * We found it. Break out and + * return the pointer to the buffer. + */ + break; + } else { + bp = NULL; + } + } + } + return bp; +} + +/* + * Check to see if a buffer matching the given parameters is already + * a part of the given transaction. Check all the chunks, we + * want to be thorough. + */ +STATIC xfs_buf_t * +xfs_trans_buf_item_match_all( + xfs_trans_t *tp, + xfs_buftarg_t *target, + xfs_daddr_t blkno, + int len) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *blip; + xfs_buf_t *bp; + int i; + + bp = NULL; + len = BBTOB(len); + for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) { + if (XFS_LIC_ARE_ALL_FREE(licp)) { + ASSERT(licp == &tp->t_items); + ASSERT(licp->lic_next == NULL); + return NULL; + } + for (i = 0; i < licp->lic_unused; i++) { + /* + * Skip unoccupied slots. + */ + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + blip = (xfs_buf_log_item_t *)lidp->lid_item; + if (blip->bli_item.li_type != XFS_LI_BUF) { + continue; + } + + bp = blip->bli_buf; + if ((XFS_BUF_TARGET_DEV(bp) == target->pbr_dev) && + (XFS_BUF_ADDR(bp) == blkno) && + (XFS_BUF_COUNT(bp) == len)) { + /* + * We found it. Break out and + * return the pointer to the buffer. + */ + return bp; + } + } + } + return NULL; +} diff -Nur linux-2.4.19/fs/xfs/xfs_trans_dquot.c linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_dquot.c --- linux-2.4.19/fs/xfs/xfs_trans_dquot.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_dquot.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,852 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + * Add the locked dquot to the transaction. + * The dquot must be locked, and it cannot be associated with any + * transaction. + */ +void +xfs_trans_dqjoin( + xfs_trans_t *tp, + xfs_dquot_t *dqp) +{ + xfs_dq_logitem_t *lp; + + ASSERT(! XFS_DQ_IS_ADDEDTO_TRX(tp, dqp)); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_LOGITEM_INITD(dqp)); + lp = &dqp->q_logitem; + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp)); + + /* + * Initialize i_transp so we can later determine if this dquot is + * associated with this transaction. + */ + dqp->q_transp = tp; +} + + +/* + * This is called to mark the dquot as needing + * to be logged when the transaction is committed. The dquot must + * already be associated with the given transaction. + * Note that it marks the entire transaction as dirty. In the ordinary + * case, this gets called via xfs_trans_commit, after the transaction + * is already dirty. However, there's nothing stop this from getting + * called directly, as done by xfs_qm_scall_setqlim. Hence, the TRANS_DIRTY + * flag. + */ +void +xfs_trans_log_dquot( + xfs_trans_t *tp, + xfs_dquot_t *dqp) +{ + xfs_log_item_desc_t *lidp; + + ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp)); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem)); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; +} + +/* + * Carry forward whatever is left of the quota blk reservation to + * the spanky new transaction + */ +void +xfs_trans_dup_dqinfo( + xfs_trans_t *otp, + xfs_trans_t *ntp) +{ + xfs_dqtrx_t *oq, *nq; + int i,j; + xfs_dqtrx_t *oqa, *nqa; + + xfs_trans_alloc_dqinfo(ntp); + oqa = otp->t_dqinfo->dqa_usrdquots; + nqa = ntp->t_dqinfo->dqa_usrdquots; + + /* + * Because the quota blk reservation is carried forward, + * it is also necessary to carry forward the DQ_DIRTY flag. + */ + if(otp->t_flags & XFS_TRANS_DQ_DIRTY) + ntp->t_flags |= XFS_TRANS_DQ_DIRTY; + + for (j = 0; j < 2; j++) { + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + if (oqa[i].qt_dquot == NULL) + break; + oq = &oqa[i]; + nq = &nqa[i]; + + nq->qt_dquot = oq->qt_dquot; + nq->qt_bcount_delta = nq->qt_icount_delta = 0; + nq->qt_rtbcount_delta = 0; + + /* + * Transfer whatever is left of the reservations. + */ + nq->qt_blk_res = oq->qt_blk_res - oq->qt_blk_res_used; + oq->qt_blk_res = oq->qt_blk_res_used; + + nq->qt_rtblk_res = oq->qt_rtblk_res - + oq->qt_rtblk_res_used; + oq->qt_rtblk_res = oq->qt_rtblk_res_used; + + nq->qt_ino_res = oq->qt_ino_res - oq->qt_ino_res_used; + oq->qt_ino_res = oq->qt_ino_res_used; + + } + oqa = otp->t_dqinfo->dqa_grpdquots; + nqa = ntp->t_dqinfo->dqa_grpdquots; + } +} + +/* + * Wrap around mod_dquot to account for both user and group quotas. + */ +void +xfs_trans_mod_dquot_byino( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint field, + long delta) +{ + ASSERT(tp); + + if (tp->t_dqinfo == NULL) + xfs_trans_alloc_dqinfo(tp); + + if (XFS_IS_UQUOTA_ON(tp->t_mountp) && ip->i_udquot) { + (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta); + } + if (XFS_IS_GQUOTA_ON(tp->t_mountp) && ip->i_gdquot) { + (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta); + } +} + +STATIC xfs_dqtrx_t * +xfs_trans_get_dqtrx( + xfs_trans_t *tp, + xfs_dquot_t *dqp) +{ + int i; + xfs_dqtrx_t *qa; + + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + qa = XFS_QM_DQP_TO_DQACCT(tp, dqp); + + if (qa[i].qt_dquot == NULL || + qa[i].qt_dquot == dqp) { + return (&qa[i]); + } + } + + return (NULL); +} + +/* + * Make the changes in the transaction structure. + * The moral equivalent to xfs_trans_mod_sb(). + * We don't touch any fields in the dquot, so we don't care + * if it's locked or not (most of the time it won't be). + */ +void +xfs_trans_mod_dquot( + xfs_trans_t *tp, + xfs_dquot_t *dqp, + uint field, + long delta) +{ + xfs_dqtrx_t *qtrx; + + ASSERT(tp); + qtrx = NULL; + + if (tp->t_dqinfo == NULL) + xfs_trans_alloc_dqinfo(tp); + /* + * Find either the first free slot or the slot that belongs + * to this dquot. + */ + qtrx = xfs_trans_get_dqtrx(tp, dqp); + ASSERT(qtrx); + if (qtrx->qt_dquot == NULL) + qtrx->qt_dquot = dqp; + + switch (field) { + + /* + * regular disk blk reservation + */ + case XFS_TRANS_DQ_RES_BLKS: + qtrx->qt_blk_res += (ulong)delta; + break; + + /* + * inode reservation + */ + case XFS_TRANS_DQ_RES_INOS: + qtrx->qt_ino_res += (ulong)delta; + break; + + /* + * disk blocks used. + */ + case XFS_TRANS_DQ_BCOUNT: + if (qtrx->qt_blk_res && delta > 0) { + qtrx->qt_blk_res_used += (ulong)delta; + ASSERT(qtrx->qt_blk_res >= qtrx->qt_blk_res_used); + } + qtrx->qt_bcount_delta += delta; + break; + + case XFS_TRANS_DQ_DELBCOUNT: + qtrx->qt_delbcnt_delta += delta; + break; + + /* + * Inode Count + */ + case XFS_TRANS_DQ_ICOUNT: + if (qtrx->qt_ino_res && delta > 0) { + qtrx->qt_ino_res_used += (ulong)delta; + ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used); + } + qtrx->qt_icount_delta += delta; + break; + + /* + * rtblk reservation + */ + case XFS_TRANS_DQ_RES_RTBLKS: + qtrx->qt_rtblk_res += (ulong)delta; + break; + + /* + * rtblk count + */ + case XFS_TRANS_DQ_RTBCOUNT: + if (qtrx->qt_rtblk_res && delta > 0) { + qtrx->qt_rtblk_res_used += (ulong)delta; + ASSERT(qtrx->qt_rtblk_res >= qtrx->qt_rtblk_res_used); + } + qtrx->qt_rtbcount_delta += delta; + break; + + case XFS_TRANS_DQ_DELRTBCOUNT: + qtrx->qt_delrtb_delta += delta; + break; + + default: + ASSERT(0); + } + tp->t_flags |= XFS_TRANS_DQ_DIRTY; +} + + +/* + * Given an array of dqtrx structures, lock all the dquots associated + * and join them to the transaction, provided they have been modified. + * We know that the highest number of dquots (of one type - usr OR grp), + * involved in a transaction is 2 and that both usr and grp combined - 3. + * So, we don't attempt to make this very generic. + */ +STATIC void +xfs_trans_dqlockedjoin( + xfs_trans_t *tp, + xfs_dqtrx_t *q) +{ + ASSERT(q[0].qt_dquot != NULL); + if (q[1].qt_dquot == NULL) { + xfs_dqlock(q[0].qt_dquot); + xfs_trans_dqjoin(tp, q[0].qt_dquot); + } else { + ASSERT(XFS_QM_TRANS_MAXDQS == 2); + xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot); + xfs_trans_dqjoin(tp, q[0].qt_dquot); + xfs_trans_dqjoin(tp, q[1].qt_dquot); + } +} + + +/* + * Called by xfs_trans_commit() and similar in spirit to + * xfs_trans_apply_sb_deltas(). + * Go thru all the dquots belonging to this transaction and modify the + * INCORE dquot to reflect the actual usages. + * Unreserve just the reservations done by this transaction + * dquot is still left locked at exit. + */ +void +xfs_trans_apply_dquot_deltas( + xfs_trans_t *tp) +{ + int i, j; + xfs_dquot_t *dqp; + xfs_dqtrx_t *qtrx, *qa; + xfs_disk_dquot_t *d; + long totalbdelta; + long totalrtbdelta; + + ASSERT(tp->t_dqinfo); + qa = tp->t_dqinfo->dqa_usrdquots; + for (j = 0; j < 2; j++) { + if (qa[0].qt_dquot == NULL) { + qa = tp->t_dqinfo->dqa_grpdquots; + continue; + } + + /* + * Lock all of the dquots and join them to the transaction. + */ + xfs_trans_dqlockedjoin(tp, qa); + + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + qtrx = &qa[i]; + /* + * The array of dquots is filled + * sequentially, not sparsely. + */ + if ((dqp = qtrx->qt_dquot) == NULL) + break; + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp)); + + /* + * adjust the actual number of blocks used + */ + d = &dqp->q_core; + + /* + * The issue here is - sometimes we don't make a blkquota + * reservation intentionally to be fair to users + * (when the amount is small). On the other hand, + * delayed allocs do make reservations, but that's + * outside of a transaction, so we have no + * idea how much was really reserved. + * So, here we've accumulated delayed allocation blks and + * non-delay blks. The assumption is that the + * delayed ones are always reserved (outside of a + * transaction), and the others may or may not have + * quota reservations. + */ + totalbdelta = qtrx->qt_bcount_delta + + qtrx->qt_delbcnt_delta; + totalrtbdelta = qtrx->qt_rtbcount_delta + + qtrx->qt_delrtb_delta; +#ifdef QUOTADEBUG + if (totalbdelta < 0) + ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >= + (xfs_qcnt_t) -totalbdelta); + + if (totalrtbdelta < 0) + ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >= + (xfs_qcnt_t) -totalrtbdelta); + + if (qtrx->qt_icount_delta < 0) + ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >= + (xfs_qcnt_t) -qtrx->qt_icount_delta); +#endif + if (totalbdelta) + INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta); + + if (qtrx->qt_icount_delta) + INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta); + + if (totalrtbdelta) + INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta); + + /* + * Start/reset the timer(s) if needed. + */ + xfs_qm_adjust_dqtimers(tp->t_mountp, d); + + dqp->dq_flags |= XFS_DQ_DIRTY; + /* + * add this to the list of items to get logged + */ + xfs_trans_log_dquot(tp, dqp); + /* + * Take off what's left of the original reservation. + * In case of delayed allocations, there's no + * reservation that a transaction structure knows of. + */ + if (qtrx->qt_blk_res != 0) { + if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { + if (qtrx->qt_blk_res > + qtrx->qt_blk_res_used) + dqp->q_res_bcount -= (xfs_qcnt_t) + (qtrx->qt_blk_res - + qtrx->qt_blk_res_used); + else + dqp->q_res_bcount -= (xfs_qcnt_t) + (qtrx->qt_blk_res_used - + qtrx->qt_blk_res); + } + } else { + /* + * These blks were never reserved, either inside + * a transaction or outside one (in a delayed + * allocation). Also, this isn't always a + * negative number since we sometimes + * deliberately skip quota reservations. + */ + if (qtrx->qt_bcount_delta) { + dqp->q_res_bcount += + (xfs_qcnt_t)qtrx->qt_bcount_delta; + } + } + /* + * Adjust the RT reservation. + */ + if (qtrx->qt_rtblk_res != 0) { + if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { + if (qtrx->qt_rtblk_res > + qtrx->qt_rtblk_res_used) + dqp->q_res_rtbcount -= (xfs_qcnt_t) + (qtrx->qt_rtblk_res - + qtrx->qt_rtblk_res_used); + else + dqp->q_res_rtbcount -= (xfs_qcnt_t) + (qtrx->qt_rtblk_res_used - + qtrx->qt_rtblk_res); + } + } else { + if (qtrx->qt_rtbcount_delta) + dqp->q_res_rtbcount += + (xfs_qcnt_t)qtrx->qt_rtbcount_delta; + } + + /* + * Adjust the inode reservation. + */ + if (qtrx->qt_ino_res != 0) { + ASSERT(qtrx->qt_ino_res >= + qtrx->qt_ino_res_used); + if (qtrx->qt_ino_res > qtrx->qt_ino_res_used) + dqp->q_res_icount -= (xfs_qcnt_t) + (qtrx->qt_ino_res - + qtrx->qt_ino_res_used); + } else { + if (qtrx->qt_icount_delta) + dqp->q_res_icount += + (xfs_qcnt_t)qtrx->qt_icount_delta; + } + + +#ifdef QUOTADEBUG + if (qtrx->qt_rtblk_res != 0) + printk("RT res %d for 0x%p\n", + (int) qtrx->qt_rtblk_res, + dqp); +#endif + ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); + ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); + ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT)); + } + /* + * Do the group quotas next + */ + qa = tp->t_dqinfo->dqa_grpdquots; + } +} + +/* + * Release the reservations, and adjust the dquots accordingly. + * This is called only when the transaction is being aborted. If by + * any chance we have done dquot modifications incore (ie. deltas) already, + * we simply throw those away, since that's the expected behavior + * when a transaction is curtailed without a commit. + */ +void +xfs_trans_unreserve_and_mod_dquots( + xfs_trans_t *tp) +{ + int i, j; + xfs_dquot_t *dqp; + xfs_dqtrx_t *qtrx, *qa; + boolean_t locked; + + ASSERT(tp->t_dqinfo); + qa = tp->t_dqinfo->dqa_usrdquots; + + for (j = 0; j < 2; j++) { + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + qtrx = &qa[i]; + /* + * We assume that the array of dquots is filled + * sequentially, not sparsely. + */ + if ((dqp = qtrx->qt_dquot) == NULL) + break; + /* + * Unreserve the original reservation. We don't care + * about the number of blocks used field, or deltas. + * Also we don't bother to zero the fields. + */ + locked = B_FALSE; + if (qtrx->qt_blk_res) { + xfs_dqlock(dqp); + locked = B_TRUE; + dqp->q_res_bcount -= + (xfs_qcnt_t)qtrx->qt_blk_res; + } + if (qtrx->qt_ino_res) { + if (!locked) { + xfs_dqlock(dqp); + locked = B_TRUE; + } + dqp->q_res_icount -= + (xfs_qcnt_t)qtrx->qt_ino_res; + } + + if (qtrx->qt_rtblk_res) { + if (!locked) { + xfs_dqlock(dqp); + locked = B_TRUE; + } + dqp->q_res_rtbcount -= + (xfs_qcnt_t)qtrx->qt_rtblk_res; + } + if (locked) + xfs_dqunlock(dqp); + + } + qa = tp->t_dqinfo->dqa_grpdquots; + } +} + +/* + * This reserves disk blocks and inodes against a dquot. + * Flags indicate if the dquot is to be locked here and also + * if the blk reservation is for RT or regular blocks. + * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check. + * Returns EDQUOT if quota is exceeded. + */ +STATIC int +xfs_trans_dqresv( + xfs_trans_t *tp, + xfs_dquot_t *dqp, + long nblks, + long ninos, + uint flags) +{ + int error; + xfs_qcnt_t hardlimit; + xfs_qcnt_t softlimit; + time_t btimer; + xfs_qcnt_t *resbcountp; + + if (! (flags & XFS_QMOPT_DQLOCK)) { + xfs_dqlock(dqp); + } + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (flags & XFS_TRANS_DQ_RES_BLKS) { + hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT); + softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); + btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); + resbcountp = &dqp->q_res_bcount; + } else { + ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); + hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT); + softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); + btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); + resbcountp = &dqp->q_res_rtbcount; + } + error = 0; + + if ((flags & XFS_QMOPT_FORCE_RES) == 0 && + !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) && + XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) { +#ifdef QUOTADEBUG + printk("BLK Res: nblks=%ld + resbcount=%Ld > hardlimit=%Ld?\n", + nblks, *resbcountp, hardlimit); +#endif + if (nblks > 0) { + /* + * dquot is locked already. See if we'd go over the + * hardlimit or exceed the timelimit if we allocate + * nblks. + */ + if (hardlimit > 0ULL && + (hardlimit <= nblks + *resbcountp)) { + error = EDQUOT; + goto error_return; + } + + if (softlimit > 0ULL && + (softlimit <= nblks + *resbcountp)) { + /* + * If timer or warnings has expired, + * return EDQUOT + */ + if ((btimer != 0 && CURRENT_TIME > btimer) || + (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) && + INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >= + XFS_QI_BWARNLIMIT(dqp->q_mount))) { + error = EDQUOT; + goto error_return; + } + } + } + if (ninos > 0) { + if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= + INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) { + error = EDQUOT; + goto error_return; + } else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= + INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) { + /* + * If timer or warnings has expired, + * return EDQUOT + */ + if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) && + CURRENT_TIME > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) || + (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) && + INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >= + XFS_QI_IWARNLIMIT(dqp->q_mount))) { + error = EDQUOT; + goto error_return; + } + } + } + } + + /* + * Change the reservation, but not the actual usage. + * Note that q_res_bcount = q_core.d_bcount + resv + */ + (*resbcountp) += (xfs_qcnt_t)nblks; + if (ninos != 0) + dqp->q_res_icount += (xfs_qcnt_t)ninos; + + /* + * note the reservation amt in the trans struct too, + * so that the transaction knows how much was reserved by + * it against this particular dquot. + * We don't do this when we are reserving for a delayed allocation, + * because we don't have the luxury of a transaction envelope then. + */ + if (tp) { + ASSERT(tp->t_dqinfo); + ASSERT(flags & XFS_QMOPT_RESBLK_MASK); + if (nblks != 0) + xfs_trans_mod_dquot(tp, dqp, + flags & XFS_QMOPT_RESBLK_MASK, + nblks); + if (ninos != 0) + xfs_trans_mod_dquot(tp, dqp, + XFS_TRANS_DQ_RES_INOS, + ninos); + } + ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); + ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT)); + ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); + +error_return: + if (! (flags & XFS_QMOPT_DQLOCK)) { + xfs_dqunlock(dqp); + } + return (error); +} + + +/* + * Given a dquot(s), make disk block and/or inode reservations against them. + * The fact that this does the reservation against both the usr and + * grp quotas is important, because this follows a both-or-nothing + * approach. + * + * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked. + * XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown. + * XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks + * XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks + * dquots are unlocked on return, if they were not locked by caller. + */ +int +xfs_trans_reserve_quota_bydquots( + xfs_trans_t *tp, + xfs_dquot_t *udqp, + xfs_dquot_t *gdqp, + long nblks, + long ninos, + uint flags) +{ + int resvd; + + if (tp && tp->t_dqinfo == NULL) + xfs_trans_alloc_dqinfo(tp); + + ASSERT(flags & XFS_QMOPT_RESBLK_MASK); + resvd = 0; + + if (udqp) { + if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags)) + return (EDQUOT); + resvd = 1; + } + + if (gdqp) { + if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) { + /* + * can't do it, so backout previous reservation + */ + if (resvd) { + xfs_trans_dqresv(tp, udqp, -nblks, -ninos, + flags); + } + return (EDQUOT); + } + } + + /* + * Didnt change anything critical, so, no need to log + */ + return (0); +} + + +/* + * Lock the dquot and change the reservation if we can. + * This doesnt change the actual usage, just the reservation. + * The inode sent in is locked. + * + * Returns 0 on success, EDQUOT or other errors otherwise + */ +int +xfs_trans_reserve_quota_nblks( + xfs_trans_t *tp, + xfs_inode_t *ip, + long nblks, + long ninos, + uint type) +{ + int error; + +#ifdef QUOTADEBUG + if (ip->i_udquot) + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot)); + if (ip->i_gdquot) + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot)); +#endif + + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); + ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS || + (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS); + + /* + * Reserve nblks against these dquots, with trans as the mediator. + */ + error = xfs_trans_reserve_quota_bydquots(tp, + ip->i_udquot, ip->i_gdquot, + nblks, ninos, + type); + return (error); +} + +/* + * This routine is called to allocate a quotaoff log item. + */ +xfs_qoff_logitem_t * +xfs_trans_get_qoff_item( + xfs_trans_t *tp, + xfs_qoff_logitem_t *startqoff, + uint flags) +{ + xfs_qoff_logitem_t *q; + + ASSERT(tp != NULL); + + q = xfs_qm_qoff_logitem_init(tp->t_mountp, startqoff, flags); + ASSERT(q != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)q); + + return (q); +} + + +/* + * This is called to mark the quotaoff logitem as needing + * to be logged when the transaction is committed. The logitem must + * already be associated with the given transaction. + */ +void +xfs_trans_log_quotaoff_item( + xfs_trans_t *tp, + xfs_qoff_logitem_t *qlp) +{ + xfs_log_item_desc_t *lidp; + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; +} + +void +xfs_trans_alloc_dqinfo( + xfs_trans_t *tp) +{ + (tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP); +} + +void +xfs_trans_free_dqinfo( + xfs_trans_t *tp) +{ + kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo); + (tp)->t_dqinfo = NULL; +} diff -Nur linux-2.4.19/fs/xfs/xfs_trans_extfree.c linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_extfree.c --- linux-2.4.19/fs/xfs/xfs_trans_extfree.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_extfree.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * This routine is called to allocate an "extent free intention" + * log item that will hold nextents worth of extents. The + * caller must use all nextents extents, because we are not + * flexible about this at all. + */ +xfs_efi_log_item_t * +xfs_trans_get_efi(xfs_trans_t *tp, + uint nextents) +{ + xfs_efi_log_item_t *efip; + + ASSERT(tp != NULL); + ASSERT(nextents > 0); + + efip = xfs_efi_init(tp->t_mountp, nextents); + ASSERT(efip != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efip); + + return (efip); +} + +/* + * This routine is called to indicate that the described + * extent is to be logged as needing to be freed. It should + * be called once for each extent to be freed. + */ +void +xfs_trans_log_efi_extent(xfs_trans_t *tp, + xfs_efi_log_item_t *efip, + xfs_fsblock_t start_block, + xfs_extlen_t ext_len) +{ + xfs_log_item_desc_t *lidp; + uint next_extent; + xfs_extent_t *extp; + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efip); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + + next_extent = efip->efi_next_extent; + ASSERT(next_extent < efip->efi_format.efi_nextents); + extp = &(efip->efi_format.efi_extents[next_extent]); + extp->ext_start = start_block; + extp->ext_len = ext_len; + efip->efi_next_extent++; +} + + +/* + * This routine is called to allocate an "extent free done" + * log item that will hold nextents worth of extents. The + * caller must use all nextents extents, because we are not + * flexible about this at all. + */ +xfs_efd_log_item_t * +xfs_trans_get_efd(xfs_trans_t *tp, + xfs_efi_log_item_t *efip, + uint nextents) +{ + xfs_efd_log_item_t *efdp; + + ASSERT(tp != NULL); + ASSERT(nextents > 0); + + efdp = xfs_efd_init(tp->t_mountp, efip, nextents); + ASSERT(efdp != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efdp); + + return (efdp); +} + +/* + * This routine is called to indicate that the described + * extent is to be logged as having been freed. It should + * be called once for each extent freed. + */ +void +xfs_trans_log_efd_extent(xfs_trans_t *tp, + xfs_efd_log_item_t *efdp, + xfs_fsblock_t start_block, + xfs_extlen_t ext_len) +{ + xfs_log_item_desc_t *lidp; + uint next_extent; + xfs_extent_t *extp; + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efdp); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + + next_extent = efdp->efd_next_extent; + ASSERT(next_extent < efdp->efd_format.efd_nextents); + extp = &(efdp->efd_format.efd_extents[next_extent]); + extp->ext_start = start_block; + extp->ext_len = ext_len; + efdp->efd_next_extent++; +} + + + + + diff -Nur linux-2.4.19/fs/xfs/xfs_trans_inode.c linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_inode.c --- linux-2.4.19/fs/xfs/xfs_trans_inode.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_inode.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +#ifdef XFS_TRANS_DEBUG +STATIC void +xfs_trans_inode_broot_debug( + xfs_inode_t *ip); +#else +#define xfs_trans_inode_broot_debug(ip) +#endif + + +/* + * Get and lock the inode for the caller if it is not already + * locked within the given transaction. If it is already locked + * within the transaction, just increment its lock recursion count + * and return a pointer to it. + * + * For an inode to be locked in a transaction, the inode lock, as + * opposed to the io lock, must be taken exclusively. This ensures + * that the inode can be involved in only 1 transaction at a time. + * Lock recursion is handled on the io lock, but only for lock modes + * of equal or lesser strength. That is, you can recur on the io lock + * held EXCL with a SHARED request but not vice versa. Also, if + * the inode is already a part of the transaction then you cannot + * go from not holding the io lock to having it EXCL or SHARED. + * + * Use the inode cache routine xfs_inode_incore() to find the inode + * if it is already owned by this transaction. + * + * If we don't already own the inode, use xfs_iget() to get it. + * Since the inode log item structure is embedded in the incore + * inode structure and is initialized when the inode is brought + * into memory, there is nothing to do with it here. + * + * If the given transaction pointer is NULL, just call xfs_iget(). + * This simplifies code which must handle both cases. + */ +int +xfs_trans_iget( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + uint lock_flags, + xfs_inode_t **ipp) +{ + int error; + xfs_inode_t *ip; + xfs_inode_log_item_t *iip; + + /* + * If the transaction pointer is NULL, just call the normal + * xfs_iget(). + */ + if (tp == NULL) { + return (xfs_iget(mp, NULL, ino, lock_flags, ipp, 0)); + } + + /* + * If we find the inode in core with this transaction + * pointer in its i_transp field, then we know we already + * have it locked. In this case we just increment the lock + * recursion count and return the inode to the caller. + * Assert that the inode is already locked in the mode requested + * by the caller. We cannot do lock promotions yet, so + * die if someone gets this wrong. + */ + if ((ip = xfs_inode_incore(tp->t_mountp, ino, tp)) != NULL) { + /* + * Make sure that the inode lock is held EXCL and + * that the io lock is never upgraded when the inode + * is already a part of the transaction. + */ + ASSERT(ip->i_itemp != NULL); + ASSERT(lock_flags & XFS_ILOCK_EXCL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || + ismrlocked(&ip->i_iolock, MR_UPDATE)); + ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || + (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_EXCL)); + ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || + ismrlocked(&ip->i_iolock, (MR_UPDATE | MR_ACCESS))); + ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || + (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_ANY)); + + if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) { + ip->i_itemp->ili_iolock_recur++; + } + if (lock_flags & XFS_ILOCK_EXCL) { + ip->i_itemp->ili_ilock_recur++; + } + *ipp = ip; + return 0; + } + + ASSERT(lock_flags & XFS_ILOCK_EXCL); + error = xfs_iget(tp->t_mountp, tp, ino, lock_flags, &ip, 0); + if (error) { + return error; + } + ASSERT(ip != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + if (ip->i_itemp == NULL) + xfs_inode_item_init(ip, mp); + iip = ip->i_itemp; + (void) xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); + + xfs_trans_inode_broot_debug(ip); + + /* + * If the IO lock has been acquired, mark that in + * the inode log item so we'll know to unlock it + * when the transaction commits. + */ + ASSERT(iip->ili_flags == 0); + if (lock_flags & XFS_IOLOCK_EXCL) { + iip->ili_flags |= XFS_ILI_IOLOCKED_EXCL; + } else if (lock_flags & XFS_IOLOCK_SHARED) { + iip->ili_flags |= XFS_ILI_IOLOCKED_SHARED; + } + + /* + * Initialize i_transp so we can find it with xfs_inode_incore() + * above. + */ + ip->i_transp = tp; + + *ipp = ip; + return 0; +} + + +/* + * Release the inode ip which was previously acquired with xfs_trans_iget() + * or added with xfs_trans_ijoin(). This will decrement the lock + * recursion count of the inode item. If the count goes to less than 0, + * the inode will be unlocked and disassociated from the transaction. + * + * If the inode has been modified within the transaction, it will not be + * unlocked until the transaction commits. + */ +void +xfs_trans_iput( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint lock_flags) +{ + xfs_inode_log_item_t *iip; + xfs_log_item_desc_t *lidp; + + /* + * If the transaction pointer is NULL, just call xfs_iput(). + */ + if (tp == NULL) { + xfs_iput(ip, lock_flags); + } + + ASSERT(ip->i_transp == tp); + iip = ip->i_itemp; + ASSERT(iip != NULL); + + /* + * Find the item descriptor pointing to this inode's + * log item. It must be there. + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)iip); + ASSERT(lidp != NULL); + ASSERT(lidp->lid_item == (xfs_log_item_t*)iip); + + /* + * Be consistent about the bookkeeping for the inode's + * io lock, but it doesn't mean much really. + */ + ASSERT((iip->ili_flags & XFS_ILI_IOLOCKED_ANY) != XFS_ILI_IOLOCKED_ANY); + if (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) { + ASSERT(iip->ili_flags & XFS_ILI_IOLOCKED_ANY); + ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || + (iip->ili_flags & XFS_ILI_IOLOCKED_EXCL)); + ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || + (iip->ili_flags & + (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED))); + if (iip->ili_iolock_recur > 0) { + iip->ili_iolock_recur--; + } + } + + /* + * If the release is just for a recursive lock on the inode lock, + * then decrement the count and return. We can assert that + * the caller is dropping an EXCL lock on the inode, because + * inode must be locked EXCL within transactions. + */ + ASSERT(lock_flags & XFS_ILOCK_EXCL); + if (iip->ili_ilock_recur > 0) { + iip->ili_ilock_recur--; + return; + } + ASSERT(iip->ili_iolock_recur == 0); + + /* + * If the inode was dirtied within this transaction, it cannot + * be released until the transaction commits. + */ + if (lidp->lid_flags & XFS_LID_DIRTY) { + return; + } + + xfs_trans_free_item(tp, lidp); + + /* + * Clear the hold and iolocked flags in the inode log item. + * We wouldn't want the next user of the inode to + * get confused. Assert that if the iolocked flag is set + * in the item then we are unlocking it in the call to xfs_iput() + * below. + */ + ASSERT((!(iip->ili_flags & XFS_ILI_IOLOCKED_ANY)) || + (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED))); + if (iip->ili_flags & (XFS_ILI_HOLD | XFS_ILI_IOLOCKED_ANY)) { + iip->ili_flags &= ~(XFS_ILI_HOLD | XFS_ILI_IOLOCKED_ANY); + } + + /* + * Unlike xfs_brelse() the inode log item cannot be + * freed, because it is embedded within the inode. + * All we have to do is release the inode. + */ + xfs_iput(ip, lock_flags); + return; +} + + +/* + * Add the locked inode to the transaction. + * The inode must be locked, and it cannot be associated with any + * transaction. The caller must specify the locks already held + * on the inode. + */ +void +xfs_trans_ijoin( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint lock_flags) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_transp == NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(lock_flags & XFS_ILOCK_EXCL); + if (ip->i_itemp == NULL) + xfs_inode_item_init(ip, ip->i_mount); + iip = ip->i_itemp; + ASSERT(iip->ili_flags == 0); + ASSERT(iip->ili_ilock_recur == 0); + ASSERT(iip->ili_iolock_recur == 0); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(iip)); + + xfs_trans_inode_broot_debug(ip); + + /* + * If the IO lock is already held, mark that in the inode log item. + */ + if (lock_flags & XFS_IOLOCK_EXCL) { + iip->ili_flags |= XFS_ILI_IOLOCKED_EXCL; + } else if (lock_flags & XFS_IOLOCK_SHARED) { + iip->ili_flags |= XFS_ILI_IOLOCKED_SHARED; + } + + /* + * Initialize i_transp so we can find it with xfs_inode_incore() + * in xfs_trans_iget() above. + */ + ip->i_transp = tp; +} + + + +/* + * Mark the inode as not needing to be unlocked when the inode item's + * IOP_UNLOCK() routine is called. The inode must already be locked + * and associated with the given transaction. + */ +/*ARGSUSED*/ +void +xfs_trans_ihold( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + + ip->i_itemp->ili_flags |= XFS_ILI_HOLD; +} + +/* + * Cancel the previous inode hold request made on this inode + * for this transaction. + */ +/*ARGSUSED*/ +void +xfs_trans_ihold_release( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD); + + ip->i_itemp->ili_flags &= ~XFS_ILI_HOLD; +} + + +/* + * This is called to mark the fields indicated in fieldmask as needing + * to be logged when the transaction is committed. The inode must + * already be associated with the given transaction. + * + * The values for fieldmask are defined in xfs_inode_item.h. We always + * log all of the core inode if any of it has changed, and we always log + * all of the inline data/extents/b-tree root if any of them has changed. + */ +void +xfs_trans_log_inode( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint flags) +{ + xfs_log_item_desc_t *lidp; + + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(ip->i_itemp)); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + + /* + * Always OR in the bits from the ili_last_fields field. + * This is to coordinate with the xfs_iflush() and xfs_iflush_done() + * routines in the eventual clearing of the ilf_fields bits. + * See the big comment in xfs_iflush() for an explanation of + * this coorination mechanism. + */ + flags |= ip->i_itemp->ili_last_fields; + ip->i_itemp->ili_format.ilf_fields |= flags; +} + +#ifdef XFS_TRANS_DEBUG +/* + * Keep track of the state of the inode btree root to make sure we + * log it properly. + */ +STATIC void +xfs_trans_inode_broot_debug( + xfs_inode_t *ip) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_itemp != NULL); + iip = ip->i_itemp; + if (iip->ili_root_size != 0) { + ASSERT(iip->ili_orig_root != NULL); + kmem_free(iip->ili_orig_root, iip->ili_root_size); + iip->ili_root_size = 0; + iip->ili_orig_root = NULL; + } + if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) { + ASSERT((ip->i_df.if_broot != NULL) && + (ip->i_df.if_broot_bytes > 0)); + iip->ili_root_size = ip->i_df.if_broot_bytes; + iip->ili_orig_root = + (char*)kmem_alloc(iip->ili_root_size, KM_SLEEP); + bcopy((char*)(ip->i_df.if_broot), iip->ili_orig_root, + iip->ili_root_size); + } +} +#endif + + + + + + + + + + + + diff -Nur linux-2.4.19/fs/xfs/xfs_trans_item.c linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_item.c --- linux-2.4.19/fs/xfs/xfs_trans_item.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_item.c Sun Aug 4 23:38:44 2002 @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC int xfs_trans_unlock_chunk(xfs_log_item_chunk_t *, + int, int, xfs_lsn_t); + +/* + * This is called to add the given log item to the transaction's + * list of log items. It must find a free log item descriptor + * or allocate a new one and add the item to that descriptor. + * The function returns a pointer to item descriptor used to point + * to the new item. The log item will now point to its new descriptor + * with its li_desc field. + */ +xfs_log_item_desc_t * +xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_chunk_t *licp; + int i=0; + + /* + * If there are no free descriptors, allocate a new chunk + * of them and put it at the front of the chunk list. + */ + if (tp->t_items_free == 0) { + licp = (xfs_log_item_chunk_t*) + kmem_alloc(sizeof(xfs_log_item_chunk_t), KM_SLEEP); + ASSERT(licp != NULL); + /* + * Initialize the chunk, and then + * claim the first slot in the newly allocated chunk. + */ + XFS_LIC_INIT(licp); + XFS_LIC_CLAIM(licp, 0); + licp->lic_unused = 1; + XFS_LIC_INIT_SLOT(licp, 0); + lidp = XFS_LIC_SLOT(licp, 0); + + /* + * Link in the new chunk and update the free count. + */ + licp->lic_next = tp->t_items.lic_next; + tp->t_items.lic_next = licp; + tp->t_items_free = XFS_LIC_NUM_SLOTS - 1; + + /* + * Initialize the descriptor and the generic portion + * of the log item. + * + * Point the new slot at this item and return it. + * Also point the log item at its currently active + * descriptor and set the item's mount pointer. + */ + lidp->lid_item = lip; + lidp->lid_flags = 0; + lidp->lid_size = 0; + lip->li_desc = lidp; + lip->li_mountp = tp->t_mountp; + return (lidp); + } + + /* + * Find the free descriptor. It is somewhere in the chunklist + * of descriptors. + */ + licp = &tp->t_items; + while (licp != NULL) { + if (XFS_LIC_VACANCY(licp)) { + if (licp->lic_unused <= XFS_LIC_MAX_SLOT) { + i = licp->lic_unused; + ASSERT(XFS_LIC_ISFREE(licp, i)); + break; + } + for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) { + if (XFS_LIC_ISFREE(licp, i)) + break; + } + ASSERT(i <= XFS_LIC_MAX_SLOT); + break; + } + licp = licp->lic_next; + } + ASSERT(licp != NULL); + /* + * If we find a free descriptor, claim it, + * initialize it, and return it. + */ + XFS_LIC_CLAIM(licp, i); + if (licp->lic_unused <= i) { + licp->lic_unused = i + 1; + XFS_LIC_INIT_SLOT(licp, i); + } + lidp = XFS_LIC_SLOT(licp, i); + tp->t_items_free--; + lidp->lid_item = lip; + lidp->lid_flags = 0; + lidp->lid_size = 0; + lip->li_desc = lidp; + lip->li_mountp = tp->t_mountp; + return (lidp); +} + +/* + * Free the given descriptor. + * + * This requires setting the bit in the chunk's free mask corresponding + * to the given slot. + */ +void +xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) +{ + uint slot; + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t **licpp; + + slot = XFS_LIC_DESC_TO_SLOT(lidp); + licp = XFS_LIC_DESC_TO_CHUNK(lidp); + XFS_LIC_RELSE(licp, slot); + lidp->lid_item->li_desc = NULL; + tp->t_items_free++; + + /* + * If there are no more used items in the chunk and this is not + * the chunk embedded in the transaction structure, then free + * the chunk. First pull it from the chunk list and then + * free it back to the heap. We didn't bother with a doubly + * linked list here because the lists should be very short + * and this is not a performance path. It's better to save + * the memory of the extra pointer. + * + * Also decrement the transaction structure's count of free items + * by the number in a chunk since we are freeing an empty chunk. + */ + if (XFS_LIC_ARE_ALL_FREE(licp) && (licp != &(tp->t_items))) { + licpp = &(tp->t_items.lic_next); + while (*licpp != licp) { + ASSERT(*licpp != NULL); + licpp = &((*licpp)->lic_next); + } + *licpp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + tp->t_items_free -= XFS_LIC_NUM_SLOTS; + } +} + +/* + * This is called to find the descriptor corresponding to the given + * log item. It returns a pointer to the descriptor. + * The log item MUST have a corresponding descriptor in the given + * transaction. This routine does not return NULL, it panics. + * + * The descriptor pointer is kept in the log item's li_desc field. + * Just return it. + */ +/*ARGSUSED*/ +xfs_log_item_desc_t * +xfs_trans_find_item(xfs_trans_t *tp, xfs_log_item_t *lip) +{ + ASSERT(lip->li_desc != NULL); + + return (lip->li_desc); +} + + +/* + * Return a pointer to the first descriptor in the chunk list. + * This does not return NULL if there are none, it panics. + * + * The first descriptor must be in either the first or second chunk. + * This is because the only chunk allowed to be empty is the first. + * All others are freed when they become empty. + * + * At some point this and xfs_trans_next_item() should be optimized + * to quickly look at the mask to determine if there is anything to + * look at. + */ +xfs_log_item_desc_t * +xfs_trans_first_item(xfs_trans_t *tp) +{ + xfs_log_item_chunk_t *licp; + int i; + + licp = &tp->t_items; + /* + * If it's not in the first chunk, skip to the second. + */ + if (XFS_LIC_ARE_ALL_FREE(licp)) { + licp = licp->lic_next; + } + + /* + * Return the first non-free descriptor in the chunk. + */ + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + for (i = 0; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + return (XFS_LIC_SLOT(licp, i)); + } + cmn_err(CE_WARN, "xfs_trans_first_item() -- no first item"); + return(NULL); +} + + +/* + * Given a descriptor, return the next descriptor in the chunk list. + * This returns NULL if there are no more used descriptors in the list. + * + * We do this by first locating the chunk in which the descriptor resides, + * and then scanning forward in the chunk and the list for the next + * used descriptor. + */ +/*ARGSUSED*/ +xfs_log_item_desc_t * +xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) +{ + xfs_log_item_chunk_t *licp; + int i; + + licp = XFS_LIC_DESC_TO_CHUNK(lidp); + + /* + * First search the rest of the chunk. The for loop keeps us + * from referencing things beyond the end of the chunk. + */ + for (i = (int)XFS_LIC_DESC_TO_SLOT(lidp) + 1; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + return (XFS_LIC_SLOT(licp, i)); + } + + /* + * Now search the next chunk. It must be there, because the + * next chunk would have been freed if it were empty. + * If there is no next chunk, return NULL. + */ + if (licp->lic_next == NULL) { + return (NULL); + } + + licp = licp->lic_next; + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + for (i = 0; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + return (XFS_LIC_SLOT(licp, i)); + } + ASSERT(0); + /* NOTREACHED */ + return 0; /* keep gcc quite */ +} + +/* + * This is called to unlock all of the items of a transaction and to free + * all the descriptors of that transaction. + * + * It walks the list of descriptors and unlocks each item. It frees + * each chunk except that embedded in the transaction as it goes along. + */ +void +xfs_trans_free_items( + xfs_trans_t *tp, + int flags) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + int abort; + + abort = flags & XFS_TRANS_ABORT; + licp = &tp->t_items; + /* + * Special case the embedded chunk so we don't free it below. + */ + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); + XFS_LIC_ALL_FREE(licp); + licp->lic_unused = 0; + } + licp = licp->lic_next; + + /* + * Unlock each item in each chunk and free the chunks. + */ + while (licp != NULL) { + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); + next_licp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + licp = next_licp; + } + + /* + * Reset the transaction structure's free item count. + */ + tp->t_items_free = XFS_LIC_NUM_SLOTS; + tp->t_items.lic_next = NULL; +} + + + +/* + * This is called to unlock the items associated with a transaction. + * Items which were not logged should be freed. + * Those which were logged must still be tracked so they can be unpinned + * when the transaction commits. + */ +void +xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + xfs_log_item_chunk_t **licpp; + int freed; + + freed = 0; + licp = &tp->t_items; + + /* + * Special case the embedded chunk so we don't free. + */ + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + freed = xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); + } + licpp = &(tp->t_items.lic_next); + licp = licp->lic_next; + + /* + * Unlock each item in each chunk, free non-dirty descriptors, + * and free empty chunks. + */ + while (licp != NULL) { + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + freed += xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); + next_licp = licp->lic_next; + if (XFS_LIC_ARE_ALL_FREE(licp)) { + *licpp = next_licp; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + freed -= XFS_LIC_NUM_SLOTS; + } else { + licpp = &(licp->lic_next); + } + ASSERT(*licpp == next_licp); + licp = next_licp; + } + + /* + * Fix the free descriptor count in the transaction. + */ + tp->t_items_free += freed; +} + +/* + * Unlock each item pointed to by a descriptor in the given chunk. + * Stamp the commit lsn into each item if necessary. + * Free descriptors pointing to items which are not dirty if freeing_chunk + * is zero. If freeing_chunk is non-zero, then we need to unlock all + * items in the chunk including those with XFS_LID_SYNC_UNLOCK set. + * Return the number of descriptors freed. + */ +STATIC int +xfs_trans_unlock_chunk( + xfs_log_item_chunk_t *licp, + int freeing_chunk, + int abort, + xfs_lsn_t commit_lsn) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + int i; + int freed; + + freed = 0; + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + lip = lidp->lid_item; + lip->li_desc = NULL; + + if (commit_lsn != NULLCOMMITLSN) + IOP_COMMITTING(lip, commit_lsn); + + /* XXXsup */ + if (abort) + lip->li_flags |= XFS_LI_ABORTED; + + /* if (abort) { + IOP_ABORT(lip); + } else */ + if (!(lidp->lid_flags & XFS_LID_SYNC_UNLOCK) || + freeing_chunk || abort) { + IOP_UNLOCK(lip); + } + + /* + * Free the descriptor if the item is not dirty + * within this transaction and the caller is not + * going to just free the entire thing regardless. + */ + if (!(freeing_chunk) && + (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) { + XFS_LIC_RELSE(licp, i); + freed++; + } + } + + return (freed); +} + + +/* + * This is called to add the given busy item to the transaction's + * list of busy items. It must find a free busy item descriptor + * or allocate a new one and add the item to that descriptor. + * The function returns a pointer to busy descriptor used to point + * to the new busy entry. The log busy entry will now point to its new + * descriptor with its ???? field. + */ +xfs_log_busy_slot_t * +xfs_trans_add_busy(xfs_trans_t *tp, xfs_agnumber_t ag, xfs_extlen_t idx) +{ + xfs_log_busy_chunk_t *lbcp; + xfs_log_busy_slot_t *lbsp; + int i=0; + + /* + * If there are no free descriptors, allocate a new chunk + * of them and put it at the front of the chunk list. + */ + if (tp->t_busy_free == 0) { + lbcp = (xfs_log_busy_chunk_t*) + kmem_alloc(sizeof(xfs_log_busy_chunk_t), KM_SLEEP); + ASSERT(lbcp != NULL); + /* + * Initialize the chunk, and then + * claim the first slot in the newly allocated chunk. + */ + XFS_LBC_INIT(lbcp); + XFS_LBC_CLAIM(lbcp, 0); + lbcp->lbc_unused = 1; + lbsp = XFS_LBC_SLOT(lbcp, 0); + + /* + * Link in the new chunk and update the free count. + */ + lbcp->lbc_next = tp->t_busy.lbc_next; + tp->t_busy.lbc_next = lbcp; + tp->t_busy_free = XFS_LIC_NUM_SLOTS - 1; + + /* + * Initialize the descriptor and the generic portion + * of the log item. + * + * Point the new slot at this item and return it. + * Also point the log item at its currently active + * descriptor and set the item's mount pointer. + */ + lbsp->lbc_ag = ag; + lbsp->lbc_idx = idx; + return (lbsp); + } + + /* + * Find the free descriptor. It is somewhere in the chunklist + * of descriptors. + */ + lbcp = &tp->t_busy; + while (lbcp != NULL) { + if (XFS_LBC_VACANCY(lbcp)) { + if (lbcp->lbc_unused <= XFS_LBC_MAX_SLOT) { + i = lbcp->lbc_unused; + break; + } else { + /* out-of-order vacancy */ + printk("OOO vacancy lbcp 0x%p\n", lbcp); + ASSERT(0); + } + } + lbcp = lbcp->lbc_next; + } + ASSERT(lbcp != NULL); + /* + * If we find a free descriptor, claim it, + * initialize it, and return it. + */ + XFS_LBC_CLAIM(lbcp, i); + if (lbcp->lbc_unused <= i) { + lbcp->lbc_unused = i + 1; + } + lbsp = XFS_LBC_SLOT(lbcp, i); + tp->t_busy_free--; + lbsp->lbc_ag = ag; + lbsp->lbc_idx = idx; + return (lbsp); +} + + +/* + * xfs_trans_free_busy + * Free all of the busy lists from a transaction + */ +void +xfs_trans_free_busy(xfs_trans_t *tp) +{ + xfs_log_busy_chunk_t *lbcp; + xfs_log_busy_chunk_t *lbcq; + + lbcp = tp->t_busy.lbc_next; + while (lbcp != NULL) { + lbcq = lbcp->lbc_next; + kmem_free(lbcp, sizeof(xfs_log_busy_chunk_t)); + lbcp = lbcq; + } + + XFS_LBC_INIT(&tp->t_busy); + tp->t_busy.lbc_unused = 0; +} diff -Nur linux-2.4.19/fs/xfs/xfs_trans_priv.h linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_priv.h --- linux-2.4.19/fs/xfs/xfs_trans_priv.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_priv.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_PRIV_H__ +#define __XFS_TRANS_PRIV_H__ + +struct xfs_log_item; +struct xfs_log_item_desc; +struct xfs_mount; +struct xfs_trans; + +/* + * From xfs_trans_item.c + */ +struct xfs_log_item_desc *xfs_trans_add_item(struct xfs_trans *, + struct xfs_log_item *); +void xfs_trans_free_item(struct xfs_trans *, + struct xfs_log_item_desc *); +struct xfs_log_item_desc *xfs_trans_find_item(struct xfs_trans *, + struct xfs_log_item *); +struct xfs_log_item_desc *xfs_trans_first_item(struct xfs_trans *); +struct xfs_log_item_desc *xfs_trans_next_item(struct xfs_trans *, + struct xfs_log_item_desc *); +void xfs_trans_free_items(struct xfs_trans *, int); +void xfs_trans_unlock_items(struct xfs_trans *, + xfs_lsn_t); +void xfs_trans_free_busy(xfs_trans_t *tp); +xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp, + xfs_agnumber_t ag, + xfs_extlen_t idx); + +/* + * From xfs_trans_ail.c + */ +void xfs_trans_update_ail(struct xfs_mount *, + struct xfs_log_item *, xfs_lsn_t, + unsigned long); +void xfs_trans_delete_ail(struct xfs_mount *, + struct xfs_log_item *, unsigned long); +struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *, int *); +struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *, + struct xfs_log_item *, int *, int *); + + +#endif /* __XFS_TRANS_PRIV_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_trans_space.h linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_space.h --- linux-2.4.19/fs/xfs/xfs_trans_space.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_trans_space.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_SPACE_H__ +#define __XFS_TRANS_SPACE_H__ + +/* + * Components of space reservations. + */ +#define XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) \ + (((mp)->m_alloc_mxr[0]) - ((mp)->m_alloc_mnr[0])) +#define XFS_EXTENTADD_SPACE_RES(mp,w) (XFS_BM_MAXLEVELS(mp,w) - 1) +#define XFS_NEXTENTADD_SPACE_RES(mp,b,w)\ + (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \ + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \ + XFS_EXTENTADD_SPACE_RES(mp,w)) +#define XFS_DAENTER_1B(mp,w) ((w) == XFS_DATA_FORK ? (mp)->m_dirblkfsbs : 1) +#define XFS_DAENTER_DBS(mp,w) \ + (XFS_DA_NODE_MAXDEPTH + \ + ((XFS_DIR_IS_V2(mp) && (w) == XFS_DATA_FORK) ? 2 : 0)) +#define XFS_DAENTER_BLOCKS(mp,w) \ + (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) +#define XFS_DAENTER_BMAP1B(mp,w) \ + XFS_NEXTENTADD_SPACE_RES(mp, XFS_DAENTER_1B(mp, w), w) +#define XFS_DAENTER_BMAPS(mp,w) \ + (XFS_DAENTER_DBS(mp,w) * XFS_DAENTER_BMAP1B(mp,w)) +#define XFS_DAENTER_SPACE_RES(mp,w) \ + (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) +#define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) +#define XFS_DIRENTER_MAX_SPLIT(mp,nl) \ + (((mp)->m_sb.sb_blocksize == 512 && \ + XFS_DIR_IS_V1(mp) && \ + (nl) >= XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN) ? 2 : 1) +#define XFS_DIRENTER_SPACE_RES(mp,nl) \ + (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ + XFS_DIRENTER_MAX_SPLIT(mp,nl)) +#define XFS_DIRREMOVE_SPACE_RES(mp) \ + XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) +#define XFS_IALLOC_SPACE_RES(mp) \ + (XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp)-1) + +/* + * Space reservation values for various transactions. + */ +#define XFS_ADDAFORK_SPACE_RES(mp) \ + ((mp)->m_dirblkfsbs + \ + (XFS_DIR_IS_V1(mp) ? 0 : XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK))) +#define XFS_ATTRRM_SPACE_RES(mp) \ + XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) +/* This macro is not used - see inline code in xfs_attr_set */ +#define XFS_ATTRSET_SPACE_RES(mp, v) \ + (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) +#define XFS_CREATE_SPACE_RES(mp,nl) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_DIOSTRAT_SPACE_RES(mp, v) \ + (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) +#define XFS_GROWFS_SPACE_RES(mp) \ + (2 * XFS_AG_MAXLEVELS(mp)) +#define XFS_GROWFSRT_SPACE_RES(mp,b) \ + ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) +#define XFS_LINK_SPACE_RES(mp,nl) \ + XFS_DIRENTER_SPACE_RES(mp,nl) +#define XFS_MKDIR_SPACE_RES(mp,nl) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_QM_DQALLOC_SPACE_RES(mp) \ + (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ + XFS_DQUOT_CLUSTER_SIZE_FSB) +#define XFS_QM_QINOCREATE_SPACE_RES(mp) \ + XFS_IALLOC_SPACE_RES(mp) +#define XFS_REMOVE_SPACE_RES(mp) \ + XFS_DIRREMOVE_SPACE_RES(mp) +#define XFS_RENAME_SPACE_RES(mp,nl) \ + (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) + +#endif /* __XFS_TRANS_SPACE_H__ */ diff -Nur linux-2.4.19/fs/xfs/xfs_types.h linux-2.4.19-sgi211r3/fs/xfs/xfs_types.h --- linux-2.4.19/fs/xfs/xfs_types.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_types.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TYPES_H__ +#define __XFS_TYPES_H__ + +#ifdef __KERNEL__ + +#include + +/* + * POSIX Extensions + */ +typedef unsigned char uchar_t; +typedef unsigned short ushort_t; +typedef unsigned int uint_t; +typedef unsigned long ulong_t; + +/* + * Additional type declarations for XFS + */ +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef signed short int __int16_t; +typedef unsigned short int __uint16_t; +typedef signed int __int32_t; +typedef unsigned int __uint32_t; +typedef signed long long int __int64_t; +typedef unsigned long long int __uint64_t; + +typedef enum { B_FALSE, B_TRUE } boolean_t; + + +typedef __int64_t prid_t; /* project ID */ +typedef __uint32_t inst_t; /* an instruction */ + +typedef __u64 xfs_off_t; +typedef __u64 xfs_ino_t; /* type */ +typedef __s64 xfs_daddr_t; /* type */ +typedef char * xfs_caddr_t; /* type */ +typedef __u32 xfs_dev_t; + +typedef struct timespec timespec_t; + +typedef struct { + unsigned char __u_bits[16]; +} uuid_t; + +/* __psint_t is the same size as a pointer */ +#if (BITS_PER_LONG == 32) +typedef __int32_t __psint_t; +typedef __uint32_t __psunsigned_t; +#elif (BITS_PER_LONG == 64) +typedef __int64_t __psint_t; +typedef __uint64_t __psunsigned_t; +#else +#error BITS_PER_LONG must be 32 or 64 +#endif + +#endif /* __KERNEL__ */ + +/* + * Some types are conditional based on the selected configuration. + * Set XFS_BIG_FILESYSTEMS=1 or 0 depending on the desired configuration. + * XFS_BIG_FILESYSTEMS needs daddr_t to be 64 bits + * + * On linux right now we are limited to 2^32 512 byte blocks in a + * filesystem, Once this limit is changed, setting this to 1 + * will allow XFS to go larger. With BIG_FILESYSTEMS set to 0 + * a 4K block filesystem could still theoretically be 16Gbytes + * long, so on an ia32 box the 32 bit page index will then be + * the limiting factor. + */ + +#ifndef XFS_BIG_FILESYSTEMS +#define XFS_BIG_FILESYSTEMS 0 +#endif + +typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ +typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ +typedef __uint32_t xfs_agnumber_t; /* allocation group number */ +typedef __int32_t xfs_extnum_t; /* # of extents in a file */ +typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ +typedef __int64_t xfs_fsize_t; /* bytes in a file */ +typedef __uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ + +typedef __int32_t xfs_suminfo_t; /* type of bitmap summary info */ +typedef __int32_t xfs_rtword_t; /* word type for bitmap manipulations */ + +typedef __int64_t xfs_lsn_t; /* log sequence number */ +typedef __int32_t xfs_tid_t; /* transaction identifier */ + +typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ +typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ + +typedef __uint16_t xfs_prid_t; /* prid_t truncated to 16bits in XFS */ + +/* + * These types are 64 bits on disk but are either 32 or 64 bits in memory. + * Disk based types: + */ +typedef __uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_drtbno_t; /* extent (block) in realtime area */ +typedef __uint64_t xfs_dfiloff_t; /* block number in a file */ +typedef __uint64_t xfs_dfilblks_t; /* number of blocks in a file */ + +/* + * Memory based types are conditional. + */ +#if XFS_BIG_FILESYSTEMS +typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef __int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ +#else +typedef __uint32_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint32_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef __uint32_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef __int32_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ +#endif +typedef __uint64_t xfs_fileoff_t; /* block number in a file */ +typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */ +typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ + +typedef __uint8_t xfs_arch_t; /* architecutre of an xfs fs */ + +/* + * Null values for the types. + */ +#define NULLDFSBNO ((xfs_dfsbno_t)-1) +#define NULLDRFSBNO ((xfs_drfsbno_t)-1) +#define NULLDRTBNO ((xfs_drtbno_t)-1) +#define NULLDFILOFF ((xfs_dfiloff_t)-1) + +#define NULLFSBLOCK ((xfs_fsblock_t)-1) +#define NULLRFSBLOCK ((xfs_rfsblock_t)-1) +#define NULLRTBLOCK ((xfs_rtblock_t)-1) +#define NULLFILEOFF ((xfs_fileoff_t)-1) + +#define NULLAGBLOCK ((xfs_agblock_t)-1) +#define NULLAGNUMBER ((xfs_agnumber_t)-1) +#define NULLEXTNUM ((xfs_extnum_t)-1) + +#define NULLCOMMITLSN ((xfs_lsn_t)-1) + +/* + * Max values for extlen, extnum, aextnum. + */ +#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ +#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ +#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ + +/* + * MAXNAMELEN is the length (including the terminating null) of + * the longest permissible file (component) name. + */ +#define MAXNAMELEN 256 + +typedef enum { + XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi +} xfs_lookup_t; + +typedef enum { + XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, + XFS_BTNUM_MAX +} xfs_btnum_t; + + +#if defined(CONFIG_PROC_FS) && defined(__KERNEL__) && !defined(XFS_STATS_OFF) +/* + * XFS global statistics + */ +struct xfsstats { +# define XFSSTAT_END_EXTENT_ALLOC 4 + __uint32_t xs_allocx; + __uint32_t xs_allocb; + __uint32_t xs_freex; + __uint32_t xs_freeb; +# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4) + __uint32_t xs_abt_lookup; + __uint32_t xs_abt_compare; + __uint32_t xs_abt_insrec; + __uint32_t xs_abt_delrec; +# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7) + __uint32_t xs_blk_mapr; + __uint32_t xs_blk_mapw; + __uint32_t xs_blk_unmap; + __uint32_t xs_add_exlist; + __uint32_t xs_del_exlist; + __uint32_t xs_look_exlist; + __uint32_t xs_cmp_exlist; +# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4) + __uint32_t xs_bmbt_lookup; + __uint32_t xs_bmbt_compare; + __uint32_t xs_bmbt_insrec; + __uint32_t xs_bmbt_delrec; +# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4) + __uint32_t xs_dir_lookup; + __uint32_t xs_dir_create; + __uint32_t xs_dir_remove; + __uint32_t xs_dir_getdents; +# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3) + __uint32_t xs_trans_sync; + __uint32_t xs_trans_async; + __uint32_t xs_trans_empty; +# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7) + __uint32_t xs_ig_attempts; + __uint32_t xs_ig_found; + __uint32_t xs_ig_frecycle; + __uint32_t xs_ig_missed; + __uint32_t xs_ig_dup; + __uint32_t xs_ig_reclaims; + __uint32_t xs_ig_attrchg; +# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5) + __uint32_t xs_log_writes; + __uint32_t xs_log_blocks; + __uint32_t xs_log_noiclogs; + __uint32_t xs_log_force; + __uint32_t xs_log_force_sleep; +# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10) + __uint32_t xs_try_logspace; + __uint32_t xs_sleep_logspace; + __uint32_t xs_push_ail; + __uint32_t xs_push_ail_success; + __uint32_t xs_push_ail_pushbuf; + __uint32_t xs_push_ail_pinned; + __uint32_t xs_push_ail_locked; + __uint32_t xs_push_ail_flushing; + __uint32_t xs_push_ail_restarts; + __uint32_t xs_push_ail_flush; +# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2) + __uint32_t xs_xstrat_quick; + __uint32_t xs_xstrat_split; +# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2) + __uint32_t xs_write_calls; + __uint32_t xs_read_calls; +# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4) + __uint32_t xs_attr_get; + __uint32_t xs_attr_set; + __uint32_t xs_attr_remove; + __uint32_t xs_attr_list; +# define XFSSTAT_END_QUOTA_OPS (XFSSTAT_END_ATTRIBUTE_OPS+8) + __uint32_t xs_qm_dqreclaims; + __uint32_t xs_qm_dqreclaim_misses; + __uint32_t xs_qm_dquot_dups; + __uint32_t xs_qm_dqcachemisses; + __uint32_t xs_qm_dqcachehits; + __uint32_t xs_qm_dqwants; + __uint32_t xs_qm_dqshake_reclaims; + __uint32_t xs_qm_dqinact_reclaims; +# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_QUOTA_OPS+3) + __uint32_t xs_iflush_count; + __uint32_t xs_icluster_flushcnt; + __uint32_t xs_icluster_flushinode; +# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8) + __uint32_t vn_active; /* # vnodes not on free lists */ + __uint32_t vn_alloc; /* # times vn_alloc called */ + __uint32_t vn_get; /* # times vn_get called */ + __uint32_t vn_hold; /* # times vn_hold called */ + __uint32_t vn_rele; /* # times vn_rele called */ + __uint32_t vn_reclaim; /* # times vn_reclaim called */ + __uint32_t vn_remove; /* # times vn_remove called */ + __uint32_t vn_free; /* # times vn_free called */ +/* Extra precision counters */ + __uint64_t xs_xstrat_bytes; + __uint64_t xs_write_bytes; + __uint64_t xs_read_bytes; +}; + +extern struct xfsstats xfsstats; + +# define XFS_STATS_INC(count) ( (count)++ ) +# define XFS_STATS_DEC(count) ( (count)-- ) +# define XFS_STATS_ADD(count, inc) ( (count) += (inc) ) +#else /* !CONFIG_PROC_FS */ +# define XFS_STATS_INC(count) +# define XFS_STATS_DEC(count) +# define XFS_STATS_ADD(count, inc) +#endif /* !CONFIG_PROC_FS */ + + + +/* juggle IRIX device numbers - still used in ondisk structures */ + +#ifndef __KERNEL__ +#define MKDEV(major, minor) makedev(major, minor) +#endif + +#define IRIX_DEV_BITSMAJOR 14 +#define IRIX_DEV_BITSMINOR 18 +#define IRIX_DEV_MAXMAJ 0x1ff +#define IRIX_DEV_MAXMIN 0x3ffff +#define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>IRIX_DEV_BITSMINOR) \ + & IRIX_DEV_MAXMAJ)) +#define IRIX_DEV_MINOR(dev) ((int)((dev)&IRIX_DEV_MAXMIN)) +#define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major)< + +#ifdef CONFIG_PROC_FS +struct xfsstats xfsstats; +#endif + +/* + * xfs_get_dir_entry is used to get a reference to an inode given + * its parent directory inode and the name of the file. It does + * not lock the child inode, and it unlocks the directory before + * returning. The directory's generation number is returned for + * use by a later call to xfs_lock_dir_and_entry. + */ +int +xfs_get_dir_entry( + struct dentry *dentry, + xfs_inode_t **ipp) +{ + vnode_t *vp; + bhv_desc_t *bdp; + + ASSERT(dentry->d_inode); + + vp = LINVFS_GET_VP(dentry->d_inode); + bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops); + if (!bdp) { + *ipp = NULL; + return XFS_ERROR(ENOENT); + } + VN_HOLD(vp); + *ipp = XFS_BHVTOI(bdp); + return 0; +} + +/* + * Wrapper around xfs_dir_lookup. + * + * If DLF_IGET is set, then this routine will also return the inode. + * Note that the inode will not be locked. Note, however, that the + * vnode will have an additional reference in this case. + */ +int +xfs_dir_lookup_int( + bhv_desc_t *dir_bdp, + int flags, + struct dentry *dentry, + xfs_ino_t *inum, + xfs_inode_t **ipp) +{ + vnode_t *dir_vp; + xfs_inode_t *dp; + char *name = (char *) dentry->d_name.name; + int name_len = dentry->d_name.len; + int error; + int do_iget; + uint lock_mode; + bhv_desc_t *bdp; + + dir_vp = BHV_TO_VNODE(dir_bdp); + vn_trace_entry(dir_vp, "xfs_dir_lookup_int", + (inst_t *)__return_address); + + do_iget = flags & DLF_IGET; + error = 0; + + if (flags & DLF_LOCK_SHARED) { + lock_mode = XFS_ILOCK_SHARED; + } else { + lock_mode = XFS_ILOCK_EXCL; + } + + dp = XFS_BHVTOI(dir_bdp); + bdp = NULL; + + /* + * If all else fails, call the directory code. + */ + + error = XFS_DIR_LOOKUP(dp->i_mount, NULL, dp, name, name_len, inum); + if (!error && do_iget) { + /* + * Unlock the directory. We do this because we can't + * hold the directory lock while doing the vn_get() + * in xfs_iget(). Doing so could cause us to hold + * a lock while waiting for the inode to finish + * being inactive while it's waiting for a log + * reservation in the inactive routine. + */ + xfs_iunlock(dp, lock_mode); + + if (bdp) { + VN_RELE(BHV_TO_VNODE(bdp)); + bdp = NULL; + } + + error = xfs_iget(dp->i_mount, NULL, *inum, 0, ipp, 0); + + xfs_ilock(dp, lock_mode); + + if (error) { + *ipp = NULL; + return error; + } + + if ((*ipp)->i_d.di_mode == 0) { + /* + * The inode has been freed. Something is + * wrong so just get out of here. + */ + xfs_iunlock(dp, lock_mode); + xfs_iput_new(*ipp, 0); + *ipp = NULL; + xfs_ilock(dp, lock_mode); + error = XFS_ERROR(ENOENT); + } else { + bdp = XFS_ITOBHV(*ipp); + bdp = NULL; + } + } + if (bdp) { + /* The only time we should get here is if the dir_lookup + * failed. + */ + ASSERT(error); + xfs_iunlock(dp, lock_mode); + VN_RELE(BHV_TO_VNODE(bdp)); + xfs_ilock(dp, lock_mode); + } + return error; +} + +/* + * Allocates a new inode from disk and return a pointer to the + * incore copy. This routine will internally commit the current + * transaction and allocate a new one if the Space Manager needed + * to do an allocation to replenish the inode free-list. + * + * This routine is designed to be called from xfs_create and + * xfs_create_dir. + * + */ +int +xfs_dir_ialloc( + xfs_trans_t **tpp, /* input: current transaction; + output: may be a new transaction. */ + xfs_inode_t *dp, /* directory within whose allocate + the inode. */ + mode_t mode, + nlink_t nlink, + dev_t rdev, + cred_t *credp, + prid_t prid, /* project id */ + int okalloc, /* ok to allocate new space */ + xfs_inode_t **ipp, /* pointer to inode; it will be + locked. */ + int *committed) + +{ + xfs_trans_t *tp; + xfs_trans_t *ntp; + xfs_inode_t *ip; + xfs_buf_t *ialloc_context = NULL; + boolean_t call_again = B_FALSE; + int code; + uint log_res; + uint log_count; + void *dqinfo; + uint tflags; + + tp = *tpp; + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + + /* + * xfs_ialloc will return a pointer to an incore inode if + * the Space Manager has an available inode on the free + * list. Otherwise, it will do an allocation and replenish + * the freelist. Since we can only do one allocation per + * transaction without deadlocks, we will need to commit the + * current transaction and start a new one. We will then + * need to call xfs_ialloc again to get the inode. + * + * If xfs_ialloc did an allocation to replenish the freelist, + * it returns the bp containing the head of the freelist as + * ialloc_context. We will hold a lock on it across the + * transaction commit so that no other process can steal + * the inode(s) that we've just allocated. + */ + code = xfs_ialloc(tp, dp, mode, nlink, rdev, credp, prid, okalloc, + &ialloc_context, &call_again, &ip); + + /* + * Return an error if we were unable to allocate a new inode. + * This should only happen if we run out of space on disk or + * encounter a disk error. + */ + if (code) { + *ipp = NULL; + return code; + } + if (!call_again && (ip == NULL)) { + *ipp = NULL; + return XFS_ERROR(ENOSPC); + } + + /* + * If call_again is set, then we were unable to get an + * inode in one operation. We need to commit the current + * transaction and call xfs_ialloc() again. It is guaranteed + * to succeed the second time. + */ + if (call_again) { + + /* + * Normally, xfs_trans_commit releases all the locks. + * We call bhold to hang on to the ialloc_context across + * the commit. Holding this buffer prevents any other + * processes from doing any allocations in this + * allocation group. + */ + xfs_trans_bhold(tp, ialloc_context); + /* + * Save the log reservation so we can use + * them in the next transaction. + */ + log_res = xfs_trans_get_log_res(tp); + log_count = xfs_trans_get_log_count(tp); + + /* + * We want the quota changes to be associated with the next + * transaction, NOT this one. So, detach the dqinfo from this + * and attach it to the next transaction. + */ + dqinfo = NULL; + tflags = 0; + if (tp->t_dqinfo) { + dqinfo = (void *)tp->t_dqinfo; + tp->t_dqinfo = NULL; + tflags = tp->t_flags & XFS_TRANS_DQ_DIRTY; + tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY); + } + + ntp = xfs_trans_dup(tp); + code = xfs_trans_commit(tp, 0, NULL); + tp = ntp; + if (committed != NULL) { + *committed = 1; + } + /* + * If we get an error during the commit processing, + * release the buffer that is still held and return + * to the caller. + */ + if (code) { + xfs_buf_relse(ialloc_context); + if (dqinfo) { + tp->t_dqinfo = dqinfo; + xfs_trans_free_dqinfo(tp); + } + *tpp = ntp; + *ipp = NULL; + return code; + } + code = xfs_trans_reserve(tp, 0, log_res, 0, + XFS_TRANS_PERM_LOG_RES, log_count); + /* + * Re-attach the quota info that we detached from prev trx. + */ + if (dqinfo) { + tp->t_dqinfo = dqinfo; + tp->t_flags |= tflags; + } + + if (code) { + xfs_buf_relse(ialloc_context); + *tpp = ntp; + *ipp = NULL; + return code; + } + xfs_trans_bjoin (tp, ialloc_context); + + /* + * Call ialloc again. Since we've locked out all + * other allocations in this allocation group, + * this call should always succeed. + */ + code = xfs_ialloc(tp, dp, mode, nlink, rdev, credp, prid, + okalloc, &ialloc_context, &call_again, &ip); + + /* + * If we get an error at this point, return to the caller + * so that the current transaction can be aborted. + */ + if (code) { + *tpp = tp; + *ipp = NULL; + return code; + } + ASSERT ((!call_again) && (ip != NULL)); + + } else { + if (committed != NULL) { + *committed = 0; + } + } + + *ipp = ip; + *tpp = tp; + + return 0; +} + +/* + * Decrement the link count on an inode & log the change. + * If this causes the link count to go to zero, initiate the + * logging activity required to truncate a file. + */ +int /* error */ +xfs_droplink( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + int error; + + xfs_ichgtime(ip, XFS_ICHGTIME_CHG); + + ASSERT (ip->i_d.di_nlink > 0); + ip->i_d.di_nlink--; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + error = 0; + if (ip->i_d.di_nlink == 0) { + /* + * We're dropping the last link to this file. + * Move the on-disk inode to the AGI unlinked list. + * From xfs_inactive() we will pull the inode from + * the list and free it. + */ + error = xfs_iunlink(tp, ip); + } + return error; +} + +/* + * This gets called when the inode's version needs to be changed from 1 to 2. + * Currently this happens when the nlink field overflows the old 16-bit value + * or when chproj is called to change the project for the first time. + * As a side effect the superblock version will also get rev'd + * to contain the NLINK bit. + */ +void +xfs_bump_ino_vers2( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + unsigned long s; + + ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); + ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1); + + ip->i_d.di_version = XFS_DINODE_VERSION_2; + ip->i_d.di_onlink = 0; + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + mp = tp->t_mountp; + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + s = XFS_SB_LOCK(mp); + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + XFS_SB_VERSION_ADDNLINK(&mp->m_sb); + XFS_SB_UNLOCK(mp, s); + xfs_mod_sb(tp, XFS_SB_VERSIONNUM); + } else { + XFS_SB_UNLOCK(mp, s); + } + } + /* Caller must log the inode */ +} + +/* + * Increment the link count on an inode & log the change. + */ +int +xfs_bumplink( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + if (ip->i_d.di_nlink >= XFS_MAXLINK) + return XFS_ERROR(EMLINK); + xfs_ichgtime(ip, XFS_ICHGTIME_CHG); + + ASSERT(ip->i_d.di_nlink > 0); + ip->i_d.di_nlink++; + if ((ip->i_d.di_version == XFS_DINODE_VERSION_1) && + (ip->i_d.di_nlink > XFS_MAXLINK_1)) { + /* + * The inode has increased its number of links beyond + * what can fit in an old format inode. It now needs + * to be converted to a version 2 inode with a 32 bit + * link count. If this is the first inode in the file + * system to do this, then we need to bump the superblock + * version number as well. + */ + xfs_bump_ino_vers2(tp, ip); + } + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + return 0; +} + +/* + * Try to truncate the given file to 0 length. Currently called + * only out of xfs_remove when it has to truncate a file to free + * up space for the remove to proceed. + */ +int +xfs_truncate_file( + xfs_mount_t *mp, + xfs_inode_t *ip) +{ + xfs_trans_t *tp; + int error; + +#ifdef QUOTADEBUG + /* + * This is called to truncate the quotainodes too. + */ + if (XFS_IS_UQUOTA_ON(mp)) { + if (ip->i_ino != mp->m_sb.sb_uquotino) + ASSERT(ip->i_udquot); + } + if (XFS_IS_GQUOTA_ON(mp)) { + if (ip->i_ino != mp->m_sb.sb_gquotino) + ASSERT(ip->i_gdquot); + } +#endif + /* + * Make the call to xfs_itruncate_start before starting the + * transaction, because we cannot make the call while we're + * in a transaction. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0); + + tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE); + if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + } + + /* + * Follow the normal truncate locking protocol. Since we + * hold the inode in the transaction, we know that it's number + * of references will stay constant. + */ + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(tp, ip); + /* + * Signal a sync xaction. The only case where that isn't + * the case is if we're truncating an already unlinked file + * on a wsync fs. In that case, we know the blocks can't + * reappear in the file because the links to file are + * permanently toast. Currently, we're always going to + * want a sync transaction because this code is being + * called from places where nlink is guaranteed to be 1 + * but I'm leaving the tests in to protect against future + * changes -- rcc. + */ + error = xfs_itruncate_finish(&tp, ip, (xfs_fsize_t)0, + XFS_DATA_FORK, + ((ip->i_d.di_nlink != 0 || + !(mp->m_flags & XFS_MOUNT_WSYNC)) + ? 1 : 0)); + if (error) { + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT); + } else { + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, + NULL); + } + xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + + return error; +} diff -Nur linux-2.4.19/fs/xfs/xfs_utils.h linux-2.4.19-sgi211r3/fs/xfs/xfs_utils.h --- linux-2.4.19/fs/xfs/xfs_utils.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_utils.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_UTILS_H__ +#define __XFS_UTILS_H__ + +#define IRELE(ip) VN_RELE(XFS_ITOV(ip)) +#define IHOLD(ip) VN_HOLD(XFS_ITOV(ip)) +#define ITRACE(ip) vn_trace_ref(XFS_ITOV(ip), __FILE__, __LINE__, \ + (inst_t *)__return_address) + +#define DLF_IGET 0x01 /* get entry inode if name lookup succeeds */ +#define DLF_LOCK_SHARED 0x02 /* directory locked shared */ + +struct bhv_desc; +struct cred; +struct vnode; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +extern int +xfs_rename( + struct bhv_desc *src_dir_bdp, + struct dentry *src_dentry, + struct vnode *target_dir_vp, + struct dentry *target_dentry, + struct cred *credp); + +extern int +xfs_get_dir_entry( + struct dentry *dentry, + xfs_inode_t **ipp); + +extern int +xfs_dir_lookup_int( + struct bhv_desc *dir_bdp, + int flags, + struct dentry *dentry, + xfs_ino_t *inum, + struct xfs_inode **ipp); + +extern int +xfs_truncate_file( + struct xfs_mount *mp, + struct xfs_inode *ip); + +extern int +xfs_dir_ialloc( + struct xfs_trans **tpp, + struct xfs_inode *dp, + mode_t mode, + nlink_t nlink, + dev_t rdev, + struct cred *credp, + prid_t prid, + int okalloc, + struct xfs_inode **ipp, + int *committed); + +extern int +xfs_droplink( + struct xfs_trans *tp, + struct xfs_inode *ip); + +extern int +xfs_bumplink( + struct xfs_trans *tp, + struct xfs_inode *ip); + +extern void +xfs_bump_ino_vers2( + struct xfs_trans *tp, + struct xfs_inode *ip); + +#endif /* XFS_UTILS_H */ + diff -Nur linux-2.4.19/fs/xfs/xfs_vfsops.c linux-2.4.19-sgi211r3/fs/xfs/xfs_vfsops.c --- linux-2.4.19/fs/xfs/xfs_vfsops.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_vfsops.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,1666 @@ +/* + * XFS filesystem operations. + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +STATIC int xfs_ibusy(xfs_mount_t *); +STATIC int xfs_sync(bhv_desc_t *, int, cred_t *); +STATIC int xfs_unmount(bhv_desc_t *, int, cred_t *); + +int +xfs_init(void) +{ + extern kmem_zone_t *xfs_da_state_zone; + extern kmem_zone_t *xfs_bmap_free_item_zone; + extern kmem_zone_t *xfs_btree_cur_zone; + extern kmem_zone_t *xfs_inode_zone; + extern kmem_zone_t *xfs_chashlist_zone; + extern kmem_zone_t *xfs_trans_zone; + extern kmem_zone_t *xfs_buf_item_zone; + extern kmem_zone_t *xfs_efd_zone; + extern kmem_zone_t *xfs_efi_zone; + extern kmem_zone_t *xfs_dabuf_zone; + extern mutex_t xfs_uuidtabmon; +#ifdef DEBUG_NOT + extern ktrace_t *xfs_alloc_trace_buf; + extern ktrace_t *xfs_bmap_trace_buf; + extern ktrace_t *xfs_bmbt_trace_buf; + extern ktrace_t *xfs_dir_trace_buf; + extern ktrace_t *xfs_attr_trace_buf; + extern ktrace_t *xfs_dir2_trace_buf; +#endif /* DEBUG */ +#ifdef XFS_DABUF_DEBUG + extern lock_t xfs_dabuf_global_lock; +#endif + extern int xfs_refcache_size; + +#ifdef XFS_DABUF_DEBUG + spinlock_init(&xfs_dabuf_global_lock, "xfsda"); +#endif + mutex_init(&xfs_uuidtabmon, MUTEX_DEFAULT, "xfs_uuidtab"); + mutex_init(&xfs_Gqm_lock, MUTEX_DEFAULT, "xfs_qmlock"); + + /* + * Initialize all of the zone allocators we use. + */ + xfs_bmap_free_item_zone = kmem_zone_init(sizeof(xfs_bmap_free_item_t), + "xfs_bmap_free_item"); + xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t), + "xfs_btree_cur"); + xfs_inode_zone = kmem_zone_init(sizeof(xfs_inode_t), "xfs_inode"); + xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans"); + xfs_da_state_zone = + kmem_zone_init(sizeof(xfs_da_state_t), "xfs_da_state"); + xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf"); + + /* + * The size of the zone allocated buf log item is the maximum + * size possible under XFS. This wastes a little bit of memory, + * but it is much faster. + */ + xfs_buf_item_zone = + kmem_zone_init((sizeof(xfs_buf_log_item_t) + + (((XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK) / + NBWORD) * sizeof(int))), + "xfs_buf_item"); + xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) + + ((XFS_EFD_MAX_FAST_EXTENTS - 1) * sizeof(xfs_extent_t))), + "xfs_efd_item"); + xfs_efi_zone = kmem_zone_init((sizeof(xfs_efi_log_item_t) + + ((XFS_EFI_MAX_FAST_EXTENTS - 1) * sizeof(xfs_extent_t))), + "xfs_efi_item"); + xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); + xfs_ili_zone = kmem_zone_init(sizeof(xfs_inode_log_item_t), "xfs_ili"); + xfs_chashlist_zone = kmem_zone_init(sizeof(xfs_chashlist_t), + "xfs_chashlist"); + _ACL_ZONE_INIT(xfs_acl_zone, "xfs_acl"); + +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_init(VNODE_TRACE_SIZE); +#else +#ifdef DEBUG + ktrace_init(64); +#endif +#endif + + /* + * Allocate global trace buffers. + */ +#ifdef XFS_ALLOC_TRACE + xfs_alloc_trace_buf = ktrace_alloc(XFS_ALLOC_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_BMAP_TRACE + xfs_bmap_trace_buf = ktrace_alloc(XFS_BMAP_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_BMBT_TRACE + xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_DIR_TRACE + xfs_dir_trace_buf = ktrace_alloc(XFS_DIR_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_ATTR_TRACE + xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_DIR2_TRACE + xfs_dir2_trace_buf = ktrace_alloc(XFS_DIR2_GTRACE_SIZE, KM_SLEEP); +#endif + + xfs_dir_startup(); + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) + xfs_error_test_init(); +#endif /* DEBUG || INDUCE_IO_ERROR */ + + xfs_init_procfs(); + xfs_sysctl_register(); + + xfs_refcache_size = xfs_params.refcache_size; + + /* + * The inode hash table is created on a per mounted + * file system bases. + */ + + return 0; +} + +void +xfs_cleanup(void) +{ + extern kmem_zone_t *xfs_bmap_free_item_zone; + extern kmem_zone_t *xfs_btree_cur_zone; + extern kmem_zone_t *xfs_inode_zone; + extern kmem_zone_t *xfs_trans_zone; + extern kmem_zone_t *xfs_da_state_zone; + extern kmem_zone_t *xfs_dabuf_zone; + extern kmem_zone_t *xfs_efd_zone; + extern kmem_zone_t *xfs_efi_zone; + extern kmem_zone_t *xfs_buf_item_zone; + extern kmem_zone_t *xfs_chashlist_zone; + extern xfs_inode_t **xfs_refcache; + + xfs_cleanup_procfs(); + xfs_sysctl_unregister(); + if (xfs_refcache) { + kmem_free(xfs_refcache, + XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *)); + } + + kmem_cache_destroy(xfs_bmap_free_item_zone); + kmem_cache_destroy(xfs_btree_cur_zone); + kmem_cache_destroy(xfs_inode_zone); + kmem_cache_destroy(xfs_trans_zone); + kmem_cache_destroy(xfs_da_state_zone); + kmem_cache_destroy(xfs_dabuf_zone); + kmem_cache_destroy(xfs_buf_item_zone); + kmem_cache_destroy(xfs_efd_zone); + kmem_cache_destroy(xfs_efi_zone); + kmem_cache_destroy(xfs_ifork_zone); + kmem_cache_destroy(xfs_ili_zone); + kmem_cache_destroy(xfs_chashlist_zone); + _XQM_ZONE_DESTROY(qm_dqzone); + _XQM_ZONE_DESTROY(qm_dqtrxzone); + _ACL_ZONE_DESTROY(xfs_acl_zone); +#if (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) + ktrace_uninit(); +#endif +} + +/* + * xfs_cmountfs + * + * This function is the common mount file system function for XFS. + */ +STATIC int +xfs_cmountfs( + vfs_t *vfsp, + dev_t ddev, + dev_t logdev, + dev_t rtdev, + struct xfs_mount_args *ap, + struct cred *cr) +{ + xfs_mount_t *mp; + int error = 0; + + + /* + * Allocate VFS private data (xfs mount structure). + */ + mp = xfs_mount_init(); + + vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp); + + /* + * Open data, real time, and log devices now - order is important. + */ + mp->m_ddev_targp = pagebuf_lock_enable(ddev, 0); + if (IS_ERR(mp->m_ddev_targp)) { + error = PTR_ERR(mp->m_ddev_targp); + goto error2; + } + + if (rtdev != 0) { + mp->m_rtdev_targp = + pagebuf_lock_enable(rtdev, 1); + if (IS_ERR(mp->m_rtdev_targp)) { + error = PTR_ERR(mp->m_rtdev_targp); + pagebuf_lock_disable(mp->m_ddev_targp, 0); + goto error2; + } + } + + if (logdev != ddev) { + mp->m_logdev_targp = + pagebuf_lock_enable(logdev, 1); + if (IS_ERR(mp->m_logdev_targp)) { + error = PTR_ERR(mp->m_logdev_targp); + pagebuf_lock_disable(mp->m_ddev_targp, 1); + if (mp->m_rtdev_targp) + pagebuf_lock_disable(mp->m_rtdev_targp, 1); + goto error2; + } + } + + /* Values are in BBs */ + if ((ap->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { + /* + * At this point the superblock has not been read + * in, therefore we do not know the block size. + * Before, the mount call ends we will convert + * these to FSBs. + */ + mp->m_dalign = ap->sunit; + mp->m_swidth = ap->swidth; + } else { + mp->m_dalign = 0; + mp->m_swidth = 0; + } + + if (logdev != 0) { + if (logdev == ddev) { + mp->m_logdev_targp = mp->m_ddev_targp; + } else { + /* Set the log device's block size */ + set_blocksize(logdev, 512); + } + + if (ap->logbufs != 0 && ap->logbufs != -1 && + (ap->logbufs < XLOG_NUM_ICLOGS || + ap->logbufs > XLOG_MAX_ICLOGS)) { + cmn_err(CE_WARN, + "XFS: invalid logbufs value: %d [not %d-%d]", + ap->logbufs, XLOG_NUM_ICLOGS, XLOG_MAX_ICLOGS); + error = XFS_ERROR(EINVAL); + goto error3; + } + mp->m_logbufs = ap->logbufs; + if (ap->logbufsize != -1 && + ap->logbufsize != 16 * 1024 && + ap->logbufsize != 32 * 1024 && + ap->logbufsize != 64 * 1024 && + ap->logbufsize != 128 * 1024 && + ap->logbufsize != 256 * 1024) { + cmn_err(CE_WARN, + "XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", + ap->logbufsize); + error = XFS_ERROR(EINVAL); + goto error3; + } + mp->m_logbsize = ap->logbufsize; + mp->m_fsname_len = strlen(ap->fsname) + 1; + mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP); + strcpy(mp->m_fsname, ap->fsname); + } + if (rtdev != 0) { + if (rtdev == ddev || rtdev == logdev) { + cmn_err(CE_WARN, + "XFS: Cannot mount filesystem with identical rtdev and logdev."); + error = XFS_ERROR(EINVAL); + goto error3; + } else { + /* Set the realtime device's block size */ + set_blocksize(rtdev, 512); + } + } + + /* + * Pull in the 'wsync' and 'ino64' mount options before we do the real + * work of mounting and recovery. The arg pointer will + * be NULL when we are being called from the root mount code. + */ +#if XFS_BIG_FILESYSTEMS + mp->m_inoadd = 0; +#endif + if (ap != NULL) { + if (ap->flags & XFSMNT_WSYNC) + mp->m_flags |= XFS_MOUNT_WSYNC; +#if XFS_BIG_FILESYSTEMS + if (ap->flags & XFSMNT_INO64) { + mp->m_flags |= XFS_MOUNT_INO64; + mp->m_inoadd = XFS_INO64_OFFSET; + } +#endif + if (ap->flags & XFSMNT_NOATIME) + mp->m_flags |= XFS_MOUNT_NOATIME; + + if (ap->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA)) + xfs_qm_mount_quotainit(mp, ap->flags); + + if (ap->flags & XFSMNT_RETERR) + mp->m_flags |= XFS_MOUNT_RETERR; + + if (ap->flags & XFSMNT_NOALIGN) + mp->m_flags |= XFS_MOUNT_NOALIGN; + + if (ap->flags & XFSMNT_OSYNCISOSYNC) + mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC; + + /* Default on Linux */ + if ( 1 || ap->flags & XFSMNT_32BITINODES) + mp->m_flags |= XFS_MOUNT_32BITINODES; + + if (ap->flags & XFSMNT_IOSIZE) { + if (ap->iosizelog > XFS_MAX_IO_LOG || + ap->iosizelog < XFS_MIN_IO_LOG) { + cmn_err(CE_WARN, + "XFS: invalid log iosize: %d [not %d-%d]", + ap->iosizelog, XFS_MIN_IO_LOG, + XFS_MAX_IO_LOG); + error = XFS_ERROR(EINVAL); + goto error3; + } + + mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; + mp->m_readio_log = mp->m_writeio_log = ap->iosizelog; + } + + /* + * no recovery flag requires a read-only mount + */ + if (ap->flags & XFSMNT_NORECOVERY) { + if (!(vfsp->vfs_flag & VFS_RDONLY)) { + cmn_err(CE_WARN, + "XFS: tried to mount a FS read-write without recovery!"); + error = XFS_ERROR(EINVAL); + goto error3; + } + mp->m_flags |= XFS_MOUNT_NORECOVERY; + } + + if (ap->flags & XFSMNT_NOUUID) + mp->m_flags |= XFS_MOUNT_NOUUID; + if (ap->flags & XFSMNT_NOLOGFLUSH) + mp->m_flags |= XFS_MOUNT_NOLOGFLUSH; + } + + /* + * read in superblock to check read-only flags and shared + * mount status + */ + if ((error = xfs_readsb(mp))) + goto error3; + + /* Fail a mount where the logbuf is smaller then the log stripe */ + if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb)) { + if (((ap->logbufsize == -1) && + (mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)) || + (ap->logbufsize < mp->m_sb.sb_logsunit)) { + cmn_err(CE_WARN, "XFS: " + "logbuf size must be greater than or equal to log stripe size"); + xfs_freesb(mp); + error = XFS_ERROR(EINVAL); + goto error3; + } + } else { + /* Fail a mount if the logbuf is larger than 32K */ + if (ap->logbufsize > XLOG_BIG_RECORD_BSIZE) { + cmn_err(CE_WARN, "XFS: " + "XFS: logbuf size for version 1 logs must be 16K or 32K"); + xfs_freesb(mp); + error = XFS_ERROR(EINVAL); + goto error3; + } + } + + pagebuf_target_blocksize(mp->m_ddev_targp, mp->m_sb.sb_blocksize); + if (logdev != 0 && logdev != ddev) + pagebuf_target_blocksize(mp->m_logdev_targp, mp->m_sb.sb_blocksize); + if (rtdev != 0) + pagebuf_target_blocksize(mp->m_rtdev_targp, mp->m_sb.sb_blocksize); + + /* + * prohibit r/w mounts of read-only filesystems + */ + if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && + !(vfsp->vfs_flag & VFS_RDONLY)) { + cmn_err(CE_WARN, "XFS: " + "cannot mount a read-only filesystem as read-write"); + error = XFS_ERROR(EROFS); + xfs_freesb(mp); + goto error3; + } + + /* + * check for shared mount. + */ + if (ap && ap->flags & XFSMNT_SHARED) { + if (!XFS_SB_VERSION_HASSHARED(&mp->m_sb)) { + error = XFS_ERROR(EINVAL); + xfs_freesb(mp); + goto error3; + } + + /* + * For IRIX 6.5, shared mounts must have the shared + * version bit set, have the persistent readonly + * field set, must be version 0 and can only be mounted + * read-only. + */ + if (!(vfsp->vfs_flag & VFS_RDONLY) || + !(mp->m_sb.sb_flags & XFS_SBF_READONLY) || + mp->m_sb.sb_shared_vn != 0) { + error = XFS_ERROR(EINVAL); + xfs_freesb(mp); + goto error3; + } + + mp->m_flags |= XFS_MOUNT_SHARED; + + /* + * Shared XFS V0 can't deal with DMI. Return EINVAL. + */ + if (mp->m_sb.sb_shared_vn == 0 && (ap->flags & XFSMNT_DMAPI)) { + error = XFS_ERROR(EINVAL); + xfs_freesb(mp); + goto error3; + } + } + + if ((error = xfs_mountfs(vfsp, mp, ddev, 0)) == 0) + return 0; + + /* + * Be careful not to clobber the value of 'error' here. + */ + error3: + /* It's impossible to get here before buftargs are filled */ + xfs_binval(mp->m_ddev_targp); + pagebuf_lock_disable(mp->m_ddev_targp, 0); + if (logdev && logdev != ddev) { + xfs_binval(mp->m_logdev_targp); + pagebuf_lock_disable(mp->m_logdev_targp, 1); + } + if (rtdev != 0) { + xfs_binval(mp->m_rtdev_targp); + pagebuf_lock_disable(mp->m_rtdev_targp, 1); + } + error2: + if (error) { + xfs_mount_free(mp, 1); + } + return error; +} + +/* + * xfs_mount + * + * The file system configurations are: + * (1) device (partition) with data and internal log + * (2) logical volume with data and log subvolumes. + * (3) logical volume with data, log, and realtime subvolumes. + */ +STATIC int +xfs_mount( + vfs_t *vfsp, + struct xfs_mount_args *args, + cred_t *credp) +{ + dev_t ddev; + dev_t logdev; + dev_t rtdev; + int error; + + error = spectodevs(vfsp->vfs_super, args, &ddev, &logdev, &rtdev); + if (!error) + error = xfs_cmountfs(vfsp, ddev, logdev, rtdev, args, credp); + return (error); +} + +/* + * xfs_ibusy searches for a busy inode in the mounted file system. + * + * Return 0 if there are no active inodes otherwise return 1. + */ +STATIC int +xfs_ibusy( + xfs_mount_t *mp) +{ + xfs_inode_t *ip; + vnode_t *vp; + int busy; + + busy = 0; + + XFS_MOUNT_ILOCK(mp); + + ip = mp->m_inodes; + if (ip == NULL) { + XFS_MOUNT_IUNLOCK(mp); + return busy; + } + + do { + /* Skip markers inserted by xfs_sync */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + vp = XFS_ITOV_NULL(ip); + + if (vp && vn_count(vp) != 0) { + if (xfs_ibusy_check(ip, vn_count(vp)) == 0) { + ip = ip->i_mnext; + continue; + } +#ifdef DEBUG + printk("busy vp=0x%p ip=0x%p inum %Ld count=%d\n", + vp, ip, ip->i_ino, vn_count(vp)); +#endif + busy++; + } + ip = ip->i_mnext; + } while ((ip != mp->m_inodes) && !busy); + + XFS_MOUNT_IUNLOCK(mp); + + return busy; +} + + +STATIC int +xfs_unmount( + bhv_desc_t *bdp, + int flags, + cred_t *credp) +{ + xfs_mount_t *mp; + xfs_inode_t *rip; + vnode_t *rvp = 0; + struct vfs *vfsp = bhvtovfs(bdp); + int unmount_event_wanted = 0; + int unmount_event_flags = 0; + int xfs_unmountfs_needed = 0; + int error; + + mp = XFS_BHVTOM(bdp); + rip = mp->m_rootip; + rvp = XFS_ITOV(rip); + + if (vfsp->vfs_flag & VFS_DMI) { + bhv_desc_t *rbdp; + + rbdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(rvp), &xfs_vnodeops); + error = dm_send_namesp_event(DM_EVENT_PREUNMOUNT, + rbdp, DM_RIGHT_NULL, rbdp, DM_RIGHT_NULL, + NULL, NULL, 0, 0, + (mp->m_dmevmask & (1<m_dmevmask & (1<m_sbdirty_timer); + + /* + * Make sure there are no active users. + */ + if (xfs_ibusy(mp)) { + error = XFS_ERROR(EBUSY); + printk("xfs_unmount: xfs_ibusy says error/%d\n", error); + goto out; + } + + XFS_bflush(mp->m_ddev_targp); + error = xfs_unmount_flush(mp, 0); + if (error) + goto out; + + ASSERT(vn_count(rvp) == 1); + + /* + * Drop the reference count, and then + * run the vnode through vn_remove. + */ + rvp->v_flag |= VPURGE; /* OK for vn_purge */ + VN_RELE(rvp); + + vn_remove(rvp); + + /* + * If we're forcing a shutdown, typically because of a media error, + * we want to make sure we invalidate dirty pages that belong to + * referenced vnodes as well. + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + error = xfs_sync(&mp->m_bhv, + (SYNC_WAIT | SYNC_CLOSE), credp); + ASSERT(error != EFSCORRUPTED); + } + xfs_unmountfs_needed = 1; + +out: + /* Send DMAPI event, if required. + * Then do xfs_unmountfs() if needed. + * Then return error (or zero). + */ + if (unmount_event_wanted) { + /* Note: mp structure must still exist for + * dm_send_unmount_event() call. + */ + dm_send_unmount_event(vfsp, error == 0 ? rvp : NULL, + DM_RIGHT_NULL, 0, error, unmount_event_flags); + } + if (xfs_unmountfs_needed) { + /* + * Call common unmount function to flush to disk + * and free the super block buffer & mount structures. + */ + xfs_unmountfs(mp, credp); + } + + return XFS_ERROR(error); +} + +/* + * xfs_unmount_flush implements a set of flush operation on special + * inodes, which are needed as a separate set of operations so that + * they can be called as part of relocation process. + */ +int +xfs_unmount_flush( + xfs_mount_t *mp, /* Mount structure we are getting + rid of. */ + int relocation) /* Called from vfs relocation. */ +{ + xfs_inode_t *rip = mp->m_rootip; + xfs_inode_t *rbmip; + xfs_inode_t *rsumip=NULL; + vnode_t *rvp = XFS_ITOV(rip); + int error; + + xfs_ilock(rip, XFS_ILOCK_EXCL); + xfs_iflock(rip); + + /* + * Flush out the real time inodes. + */ + if ((rbmip = mp->m_rbmip) != NULL) { + xfs_ilock(rbmip, XFS_ILOCK_EXCL); + xfs_iflock(rbmip); + error = xfs_iflush(rbmip, XFS_IFLUSH_SYNC); + xfs_iunlock(rbmip, XFS_ILOCK_EXCL); + + if (error == EFSCORRUPTED) + goto fscorrupt_out; + + ASSERT(vn_count(XFS_ITOV(rbmip)) == 1); + + rsumip = mp->m_rsumip; + xfs_ilock(rsumip, XFS_ILOCK_EXCL); + xfs_iflock(rsumip); + error = xfs_iflush(rsumip, XFS_IFLUSH_SYNC); + xfs_iunlock(rsumip, XFS_ILOCK_EXCL); + + if (error == EFSCORRUPTED) + goto fscorrupt_out; + + ASSERT(vn_count(XFS_ITOV(rsumip)) == 1); + } + + /* + * synchronously flush root inode to disk + */ + error = xfs_iflush(rip, XFS_IFLUSH_SYNC); + + if (error == EFSCORRUPTED) + goto fscorrupt_out2; + + if (vn_count(rvp) != 1 && !relocation) { + xfs_iunlock(rip, XFS_ILOCK_EXCL); + error = XFS_ERROR(EBUSY); + return (error); + } + /* + * Release dquot that rootinode, rbmino and rsumino might be holding, + * flush and purge the quota inodes. + */ + error = xfs_qm_unmount_quotas(mp); + if (error == EFSCORRUPTED) + goto fscorrupt_out2; + + if (rbmip) { + VN_RELE(XFS_ITOV(rbmip)); + VN_RELE(XFS_ITOV(rsumip)); + } + + xfs_iunlock(rip, XFS_ILOCK_EXCL); + return (0); + +fscorrupt_out: + xfs_ifunlock(rip); + +fscorrupt_out2: + xfs_iunlock(rip, XFS_ILOCK_EXCL); + + error = XFS_ERROR(EFSCORRUPTED); + return (error); +} + +/* + * xfs_root extracts the root vnode from a vfs. + * + * vfsp -- the vfs struct for the desired file system + * vpp -- address of the caller's vnode pointer which should be + * set to the desired fs root vnode + */ +STATIC int +xfs_root( + bhv_desc_t *bdp, + vnode_t **vpp) +{ + vnode_t *vp; + + vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip); + VN_HOLD(vp); + *vpp = vp; + + return 0; +} + +/* + * xfs_statvfs + * + * Fill in the statvfs structure for the given file system. We use + * the superblock lock in the mount structure to ensure a consistent + * snapshot of the counters returned. + */ +STATIC int +xfs_statvfs( + bhv_desc_t *bdp, + struct statfs *statp, + vnode_t *vp) +{ + __uint64_t fakeinos; + xfs_extlen_t lsize; + xfs_mount_t *mp; + xfs_sb_t *sbp; + unsigned long s; + + mp = XFS_BHVTOM(bdp); + sbp = &(mp->m_sb); + + statp->f_type = XFS_SB_MAGIC; + + s = XFS_SB_LOCK(mp); + statp->f_bsize = sbp->sb_blocksize; + lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; + statp->f_blocks = sbp->sb_dblocks - lsize; + statp->f_bfree = statp->f_bavail = sbp->sb_fdblocks; + fakeinos = statp->f_bfree << sbp->sb_inopblog; +#if XFS_BIG_FILESYSTEMS + fakeinos += mp->m_inoadd; +#endif + statp->f_files = + MIN(sbp->sb_icount + fakeinos, (__uint64_t)XFS_MAXINUMBER); + if (mp->m_maxicount) +#if XFS_BIG_FILESYSTEMS + if (!mp->m_inoadd) +#endif + statp->f_files = + MIN(statp->f_files, (long)mp->m_maxicount); + statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree); + XFS_SB_UNLOCK(mp, s); + + statp->f_fsid.val[0] = mp->m_dev; + statp->f_fsid.val[1] = 0; + statp->f_namelen = MAXNAMELEN - 1; + + return 0; +} + + +/* + * xfs_sync flushes any pending I/O to file system vfsp. + * + * This routine is called by vfs_sync() to make sure that things make it + * out to disk eventually, on sync() system calls to flush out everything, + * and when the file system is unmounted. For the vfs_sync() case, all + * we really need to do is sync out the log to make all of our meta-data + * updates permanent (except for timestamps). For calls from pflushd(), + * dirty pages are kept moving by calling pdflush() on the inodes + * containing them. We also flush the inodes that we can lock without + * sleeping and the superblock if we can lock it without sleeping from + * vfs_sync() so that items at the tail of the log are always moving out. + * + * Flags: + * SYNC_BDFLUSH - We're being called from vfs_sync() so we don't want + * to sleep if we can help it. All we really need + * to do is ensure that the log is synced at least + * periodically. We also push the inodes and + * superblock if we can lock them without sleeping + * and they are not pinned. + * SYNC_ATTR - We need to flush the inodes. If SYNC_BDFLUSH is not + * set, then we really want to lock each inode and flush + * it. + * SYNC_WAIT - All the flushes that take place in this call should + * be synchronous. + * SYNC_DELWRI - This tells us to push dirty pages associated with + * inodes. SYNC_WAIT and SYNC_BDFLUSH are used to + * determine if they should be flushed sync, async, or + * delwri. + * SYNC_CLOSE - This flag is passed when the system is being + * unmounted. We should sync and invalidate everthing. + * SYNC_FSDATA - This indicates that the caller would like to make + * sure the superblock is safe on disk. We can ensure + * this by simply makeing sure the log gets flushed + * if SYNC_BDFLUSH is set, and by actually writing it + * out otherwise. + * + */ +/*ARGSUSED*/ +STATIC int +xfs_sync( + bhv_desc_t *bdp, + int flags, + cred_t *credp) +{ + xfs_mount_t *mp; + + mp = XFS_BHVTOM(bdp); + return (xfs_syncsub(mp, flags, 0, NULL)); +} + +/* + * xfs sync routine for internal use + * + * This routine supports all of the flags defined for the generic VFS_SYNC + * interface as explained above under xys_sync. In the interests of not + * changing interfaces within the 6.5 family, additional internallly- + * required functions are specified within a separate xflags parameter, + * only available by calling this routine. + * + * xflags: + * XFS_XSYNC_RELOC - Sync for relocation. Don't try to get behavior + * locks as this will cause you to hang. Not all + * combinations of flags are necessarily supported + * when this is specified. + */ +int +xfs_syncsub( + xfs_mount_t *mp, + int flags, + int xflags, + int *bypassed) +{ + xfs_inode_t *ip = NULL; + xfs_inode_t *ip_next; + xfs_buf_t *bp; + vnode_t *vp = NULL; + vmap_t vmap; + int error; + int last_error; + uint64_t fflag; + uint lock_flags; + uint base_lock_flags; + uint log_flags; + boolean_t mount_locked; + boolean_t vnode_refed; + int preempt; + int do_mmap_flush; + xfs_dinode_t *dip; + xfs_buf_log_item_t *bip; + xfs_iptr_t *ipointer; +#ifdef DEBUG + boolean_t ipointer_in = B_FALSE; + +#define IPOINTER_SET ipointer_in = B_TRUE +#define IPOINTER_CLR ipointer_in = B_FALSE +#else +#define IPOINTER_SET +#define IPOINTER_CLR +#endif + + +/* Insert a marker record into the inode list after inode ip. The list + * must be locked when this is called. After the call the list will no + * longer be locked. + */ +#define IPOINTER_INSERT(ip, mp) { \ + ASSERT(ipointer_in == B_FALSE); \ + ipointer->ip_mnext = ip->i_mnext; \ + ipointer->ip_mprev = ip; \ + ip->i_mnext = (xfs_inode_t *)ipointer; \ + ipointer->ip_mnext->i_mprev = (xfs_inode_t *)ipointer; \ + preempt = 0; \ + XFS_MOUNT_IUNLOCK(mp); \ + mount_locked = B_FALSE; \ + IPOINTER_SET; \ + } + +/* Remove the marker from the inode list. If the marker was the only item + * in the list then there are no remaining inodes and we should zero out + * the whole list. If we are the current head of the list then move the head + * past us. + */ +#define IPOINTER_REMOVE(ip, mp) { \ + ASSERT(ipointer_in == B_TRUE); \ + if (ipointer->ip_mnext != (xfs_inode_t *)ipointer) { \ + ip = ipointer->ip_mnext; \ + ip->i_mprev = ipointer->ip_mprev; \ + ipointer->ip_mprev->i_mnext = ip; \ + if (mp->m_inodes == (xfs_inode_t *)ipointer) { \ + mp->m_inodes = ip; \ + } \ + } else { \ + ASSERT(mp->m_inodes == (xfs_inode_t *)ipointer); \ + mp->m_inodes = NULL; \ + ip = NULL; \ + } \ + IPOINTER_CLR; \ + } + +#define PREEMPT_MASK 0x7f + + if (bypassed) + *bypassed = 0; + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + return 0; + error = 0; + last_error = 0; + preempt = 0; + + /* Allocate a reference marker */ + ipointer = (xfs_iptr_t *)kmem_zalloc(sizeof(xfs_iptr_t), KM_SLEEP); + + fflag = XFS_B_ASYNC; /* default is don't wait */ + if (flags & SYNC_BDFLUSH) + fflag = XFS_B_DELWRI; + if (flags & SYNC_WAIT) + fflag = 0; /* synchronous overrides all */ + do_mmap_flush = (flags & (SYNC_DELWRI|SYNC_BDFLUSH)) != + (SYNC_DELWRI|SYNC_BDFLUSH); + + base_lock_flags = XFS_ILOCK_SHARED; + if (flags & (SYNC_DELWRI | SYNC_CLOSE)) { + /* + * We need the I/O lock if we're going to call any of + * the flush/inval routines. + */ + base_lock_flags |= XFS_IOLOCK_SHARED; + } + + /* + * Sync out the log. This ensures that the log is periodically + * flushed even if there is not enough activity to fill it up. + */ + if (flags & SYNC_WAIT) { + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + } else { + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + } + + XFS_MOUNT_ILOCK(mp); + + ip = mp->m_inodes; + + mount_locked = B_TRUE; + vnode_refed = B_FALSE; + + IPOINTER_CLR; + + do { + ASSERT(ipointer_in == B_FALSE); + ASSERT(vnode_refed == B_FALSE); + + lock_flags = base_lock_flags; + + /* + * There were no inodes in the list, just break out + * of the loop. + */ + if (ip == NULL) { + break; + } + + /* + * We found another sync thread marker - skip it + */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + vp = XFS_ITOV_NULL(ip); + + /* + * If the vnode is gone then this is being torn down, + * call reclaim if it is flushed, else let regular flush + * code deal with it later in the loop. + */ + + if (vp == NULL) { + /* Skip ones already in reclaim */ + if (ip->i_flags & XFS_IRECLAIM) { + ip = ip->i_mnext; + continue; + } + if ((ip->i_update_core == 0) && + ((ip->i_itemp == NULL) || + !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL))) { + if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) { + ip = ip->i_mnext; + } else if ((xfs_ipincount(ip) == 0) && + xfs_iflock_nowait(ip)) { + IPOINTER_INSERT(ip, mp); + + xfs_finish_reclaim(ip, 1, + XFS_IFLUSH_DELWRI_ELSE_SYNC); + + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + IPOINTER_REMOVE(ip, mp); + } else { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + ip = ip->i_mnext; + } + continue; + } + } + + if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) { + XFS_MOUNT_IUNLOCK(mp); + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return 0; + } + + /* + * If this is just vfs_sync() or pflushd() calling + * then we can skip inodes for which it looks like + * there is nothing to do. Since we don't have the + * inode locked this is racey, but these are periodic + * calls so it doesn't matter. For the others we want + * to know for sure, so we at least try to lock them. + */ + if (flags & SYNC_BDFLUSH) { + if (((ip->i_itemp == NULL) || + !(ip->i_itemp->ili_format.ilf_fields & + XFS_ILOG_ALL)) && + (ip->i_update_core == 0)) { + ip = ip->i_mnext; + continue; + } + } + + /* + * Try to lock without sleeping. We're out of order with + * the inode list lock here, so if we fail we need to drop + * the mount lock and try again. If we're called from + * bdflush() here, then don't bother. + * + * The inode lock here actually coordinates with the + * almost spurious inode lock in xfs_ireclaim() to prevent + * the vnode we handle here without a reference from + * being freed while we reference it. If we lock the inode + * while it's on the mount list here, then the spurious inode + * lock in xfs_ireclaim() after the inode is pulled from + * the mount list will sleep until we release it here. + * This keeps the vnode from being freed while we reference + * it. It is also cheaper and simpler than actually doing + * a vn_get() for every inode we touch here. + */ + if (xfs_ilock_nowait(ip, lock_flags) == 0) { + + if ((flags & SYNC_BDFLUSH) || (vp == NULL)) { + ip = ip->i_mnext; + continue; + } + + /* + * We need to unlock the inode list lock in order + * to lock the inode. Insert a marker record into + * the inode list to remember our position, dropping + * the lock is now done inside the IPOINTER_INSERT + * macro. + * + * We also use the inode list lock to protect us + * in taking a snapshot of the vnode version number + * for use in calling vn_get(). + */ + VMAP(vp, ip, vmap); + IPOINTER_INSERT(ip, mp); + + vp = vn_get(vp, &vmap); + if (vp == NULL) { + /* + * The vnode was reclaimed once we let go + * of the inode list lock. Skip to the + * next list entry. Remove the marker. + */ + + XFS_MOUNT_ILOCK(mp); + + mount_locked = B_TRUE; + vnode_refed = B_FALSE; + + IPOINTER_REMOVE(ip, mp); + + continue; + } + + xfs_ilock(ip, lock_flags); + + ASSERT(vp == XFS_ITOV(ip)); + ASSERT(ip->i_mount == mp); + + vnode_refed = B_TRUE; + } + + /* From here on in the loop we may have a marker record + * in the inode list. + */ + + if ((flags & SYNC_CLOSE) && (vp != NULL)) { + /* + * This is the shutdown case. We just need to + * flush and invalidate all the pages associated + * with the inode. Drop the inode lock since + * we can't hold it across calls to the buffer + * cache. + * + * We don't set the VREMAPPING bit in the vnode + * here, because we don't hold the vnode lock + * exclusively. It doesn't really matter, though, + * because we only come here when we're shutting + * down anyway. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + if (XFS_FORCED_SHUTDOWN(mp)) { + if (xflags & XFS_XSYNC_RELOC) { + fs_tosspages(XFS_ITOBHV(ip), 0, -1, + FI_REMAPF); + } + else { + VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF); + } + } else { + if (xflags & XFS_XSYNC_RELOC) { + fs_flushinval_pages(XFS_ITOBHV(ip), + 0, -1, FI_REMAPF); + } + else { + VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF); + } + } + + xfs_ilock(ip, XFS_ILOCK_SHARED); + + } else if ((flags & SYNC_DELWRI) && (vp != NULL)) { + if (VN_DIRTY(vp)) { + /* We need to have dropped the lock here, + * so insert a marker if we have not already + * done so. + */ + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + /* + * Drop the inode lock since we can't hold it + * across calls to the buffer cache. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + if (do_mmap_flush) { + VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, + fflag, FI_NONE, error); + } else { + fsync_inode_data_buffers(LINVFS_GET_IP(vp)); + } + xfs_ilock(ip, XFS_ILOCK_SHARED); + } + + } + + if (flags & SYNC_BDFLUSH) { + if ((flags & SYNC_ATTR) && + ((ip->i_update_core) || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0)))) { + + /* Insert marker and drop lock if not already + * done. + */ + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + /* + * We don't want the periodic flushing of the + * inodes by vfs_sync() to interfere with + * I/O to the file, especially read I/O + * where it is only the access time stamp + * that is being flushed out. To prevent + * long periods where we have both inode + * locks held shared here while reading the + * inode's buffer in from disk, we drop the + * inode lock while reading in the inode + * buffer. We have to release the buffer + * and reacquire the inode lock so that they + * are acquired in the proper order (inode + * locks first). The buffer will go at the + * end of the lru chain, though, so we can + * expect it to still be there when we go + * for it again in xfs_iflush(). + */ + if ((xfs_ipincount(ip) == 0) && + xfs_iflock_nowait(ip)) { + + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + error = xfs_itobp(mp, NULL, ip, + &dip, &bp, 0); + if (!error) { + xfs_buf_relse(bp); + } else { + /* Bailing out, remove the + * marker and free it. + */ + XFS_MOUNT_ILOCK(mp); + + IPOINTER_REMOVE(ip, mp); + + XFS_MOUNT_IUNLOCK(mp); + + ASSERT(!(lock_flags & + XFS_IOLOCK_SHARED)); + + kmem_free(ipointer, + sizeof(xfs_iptr_t)); + return (0); + } + + /* + * Since we dropped the inode lock, + * the inode may have been reclaimed. + * Therefore, we reacquire the mount + * lock and check to see if we were the + * inode reclaimed. If this happened + * then the ipointer marker will no + * longer point back at us. In this + * case, move ip along to the inode + * after the marker, remove the marker + * and continue. + */ + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + + if (ip != ipointer->ip_mprev) { + IPOINTER_REMOVE(ip, mp); + + ASSERT(!vnode_refed); + ASSERT(!(lock_flags & + XFS_IOLOCK_SHARED)); + continue; + } + + ASSERT(ip->i_mount == mp); + + if (xfs_ilock_nowait(ip, + XFS_ILOCK_SHARED) == 0) { + ASSERT(ip->i_mount == mp); + /* + * We failed to reacquire + * the inode lock without + * sleeping, so just skip + * the inode for now. We + * clear the ILOCK bit from + * the lock_flags so that we + * won't try to drop a lock + * we don't hold below. + */ + lock_flags &= ~XFS_ILOCK_SHARED; + IPOINTER_REMOVE(ip_next, mp); + } else if ((xfs_ipincount(ip) == 0) && + xfs_iflock_nowait(ip)) { + ASSERT(ip->i_mount == mp); + /* + * Since this is vfs_sync() + * calling we only flush the + * inode out if we can lock + * it without sleeping and + * it is not pinned. Drop + * the mount lock here so + * that we don't hold it for + * too long. We already have + * a marker in the list here. + */ + XFS_MOUNT_IUNLOCK(mp); + mount_locked = B_FALSE; + error = xfs_iflush(ip, + XFS_IFLUSH_DELWRI); + } else { + ASSERT(ip->i_mount == mp); + IPOINTER_REMOVE(ip_next, mp); + } + } + + } + + } else { + if ((flags & SYNC_ATTR) && + ((ip->i_update_core) || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0)))) { + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + if (flags & SYNC_WAIT) { + xfs_iflock(ip); + error = xfs_iflush(ip, + XFS_IFLUSH_SYNC); + } else { + /* + * If we can't acquire the flush + * lock, then the inode is already + * being flushed so don't bother + * waiting. If we can lock it then + * do a delwri flush so we can + * combine multiple inode flushes + * in each disk write. + */ + if (xfs_iflock_nowait(ip)) { + error = xfs_iflush(ip, + XFS_IFLUSH_DELWRI); + } + else if (bypassed) + (*bypassed)++; + } + } + } + + if (lock_flags != 0) { + xfs_iunlock(ip, lock_flags); + } + + if (vnode_refed) { + /* + * If we had to take a reference on the vnode + * above, then wait until after we've unlocked + * the inode to release the reference. This is + * because we can be already holding the inode + * lock when VN_RELE() calls xfs_inactive(). + * + * Make sure to drop the mount lock before calling + * VN_RELE() so that we don't trip over ourselves if + * we have to go for the mount lock again in the + * inactive code. + */ + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + VN_RELE(vp); + + vnode_refed = B_FALSE; + } + + if (error) { + last_error = error; + } + + /* + * bail out if the filesystem is corrupted. + */ + if (error == EFSCORRUPTED) { + if (!mount_locked) { + XFS_MOUNT_ILOCK(mp); + IPOINTER_REMOVE(ip, mp); + } + XFS_MOUNT_IUNLOCK(mp); + ASSERT(ipointer_in == B_FALSE); + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return XFS_ERROR(error); + } + + /* Let other threads have a chance at the mount lock + * if we have looped many times without dropping the + * lock. + */ + if ((++preempt & PREEMPT_MASK) == 0) { + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + } + + if (mount_locked == B_FALSE) { + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + IPOINTER_REMOVE(ip, mp); + continue; + } + + ASSERT(ipointer_in == B_FALSE); + ip = ip->i_mnext; + + } while (ip != mp->m_inodes); + + XFS_MOUNT_IUNLOCK(mp); + + ASSERT(ipointer_in == B_FALSE); + + /* + * Get the Quota Manager to flush the dquots in a similar manner. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if ((error = xfs_qm_sync(mp, flags))) { + /* + * If we got an IO error, we will be shutting down. + * So, there's nothing more for us to do here. + */ + ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp)); + if (XFS_FORCED_SHUTDOWN(mp)) { + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return XFS_ERROR(error); + } + } + } + + /* + * Flushing out dirty data above probably generated more + * log activity, so if this isn't vfs_sync() then flush + * the log again. If SYNC_WAIT is set then do it synchronously. + */ + if (!(flags & SYNC_BDFLUSH)) { + log_flags = XFS_LOG_FORCE; + if (flags & SYNC_WAIT) { + log_flags |= XFS_LOG_SYNC; + } + xfs_log_force(mp, (xfs_lsn_t)0, log_flags); + } + + if (flags & SYNC_FSDATA) { + /* + * If this is vfs_sync() then only sync the superblock + * if we can lock it without sleeping and it is not pinned. + */ + if (flags & SYNC_BDFLUSH) { + bp = xfs_getsb(mp, XFS_BUF_TRYLOCK); + if (bp != NULL) { + bip = XFS_BUF_FSPRIVATE(bp,xfs_buf_log_item_t*); + if ((bip != NULL) && + xfs_buf_item_dirty(bip)) { + if (!(XFS_BUF_ISPINNED(bp))) { + XFS_BUF_ASYNC(bp); + error = xfs_bwrite(mp, bp); + } else { + xfs_buf_relse(bp); + } + } else { + xfs_buf_relse(bp); + } + } + } else { + bp = xfs_getsb(mp, 0); + /* + * If the buffer is pinned then push on the log so + * we won't get stuck waiting in the write for + * someone, maybe ourselves, to flush the log. + * Even though we just pushed the log above, we + * did not have the superblock buffer locked at + * that point so it can become pinned in between + * there and here. + */ + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + XFS_BUF_BFLAGS(bp) |= fflag; + error = xfs_bwrite(mp, bp); + } + if (error) { + last_error = error; + } + } + + /* + * If this is the 30 second sync, then kick some entries out of + * the reference cache. This ensures that idle entries are + * eventually kicked out of the cache. + */ + if (flags & SYNC_BDFLUSH) { + xfs_refcache_purge_some(mp); + } + + /* + * Now check to see if the log needs a "dummy" transaction. + */ + + if (xfs_log_need_covered(mp)) { + xfs_trans_t *tp; + + /* + * Put a dummy transaction in the log to tell + * recovery that all others are OK. + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); + if ((error = xfs_trans_reserve(tp, 0, + XFS_ICHANGE_LOG_RES(mp), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return error; + } + + ip = mp->m_rootip; + xfs_ilock(ip, XFS_ILOCK_EXCL); + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + error = xfs_trans_commit(tp, 0, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + /* + * When shutting down, we need to insure that the AIL is pushed + * to disk or the filesystem can appear corrupt from the PROM. + */ + if ((flags & (SYNC_CLOSE|SYNC_WAIT)) == (SYNC_CLOSE|SYNC_WAIT)) { + XFS_bflush(mp->m_ddev_targp); + if (mp->m_rtdev_targp) { + XFS_bflush(mp->m_rtdev_targp); + } + } + + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return XFS_ERROR(last_error); +} + + +/* + * xfs_vget - called by DMAPI to get vnode from file handle + */ +STATIC int +xfs_vget( + bhv_desc_t *bdp, + vnode_t **vpp, + fid_t *fidp) +{ + xfs_fid_t *xfid; + xfs_inode_t *ip; + int error; + xfs_ino_t ino; + unsigned int igen; + xfs_mount_t *mp; + struct inode *inode = NULL; + + xfid = (struct xfs_fid *)fidp; + + if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { + ino = xfid->xfs_fid_ino; + igen = xfid->xfs_fid_gen; + } else { + /* + * Invalid. Since handles can be created in user space + * and passed in via gethandle(), this is not cause for + * a panic. + */ + return XFS_ERROR(EINVAL); + } + mp = XFS_BHVTOM(bdp); + error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + if (error) { + *vpp = NULL; + return error; + } + if (ip == NULL) { + *vpp = NULL; + return XFS_ERROR(EIO); + } + + if (ip->i_d.di_mode == 0 || (igen && (ip->i_d.di_gen != igen))) { + xfs_iput_new(ip, XFS_ILOCK_SHARED); + *vpp = NULL; + return XFS_ERROR(ENOENT); + } + + *vpp = XFS_ITOV(ip); + inode = LINVFS_GET_IP((*vpp)); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + error = linvfs_revalidate_core(inode, ATTR_COMM); + if (error) { + iput(inode); + return XFS_ERROR(error); + } + return 0; +} + + +vfsops_t xfs_vfsops = { + .vfs_mount = xfs_mount, + .vfs_dounmount = fs_dounmount, + .vfs_unmount = xfs_unmount, + .vfs_root = xfs_root, + .vfs_statvfs = xfs_statvfs, + .vfs_sync = xfs_sync, + .vfs_vget = xfs_vget, + .vfs_force_shutdown = xfs_do_force_shutdown, +#ifdef CONFIG_XFS_DMAPI + .vfs_dmapi_mount = xfs_dm_mount, + .vfs_dmapi_fsys_vector = xfs_dm_get_fsys_vector, +#endif +}; diff -Nur linux-2.4.19/fs/xfs/xfs_vnodeops.c linux-2.4.19-sgi211r3/fs/xfs/xfs_vnodeops.c --- linux-2.4.19/fs/xfs/xfs_vnodeops.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfs_vnodeops.c Tue Jan 7 21:41:51 2003 @@ -0,0 +1,5083 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + * The maximum pathlen is 1024 bytes. Since the minimum file system + * blocksize is 512 bytes, we can get a max of 2 extents back from + * bmapi. + */ +#define SYMLINK_MAPS 2 + +extern int xfs_ioctl(bhv_desc_t *, struct inode *, struct file *, + unsigned int, unsigned long); + + +#ifdef XFS_RW_TRACE +STATIC void +xfs_ctrunc_trace( + int tag, + xfs_inode_t *ip); +#else +#define xfs_ctrunc_trace(tag, ip) +#endif /* DEBUG */ + +/* + * For xfs, we check that the file isn't too big to be opened by this kernel. + * No other open action is required for regular files. Devices are handled + * through the specfs file system, pipes through fifofs. Device and + * fifo vnodes are "wrapped" by specfs and fifofs vnodes, respectively, + * when a new vnode is first looked up or created. + */ +/*ARGSUSED*/ +STATIC int +xfs_open( + bhv_desc_t *bdp, + cred_t *credp) +{ + int mode; + vnode_t *vp; + xfs_inode_t *ip; + + vp = BHV_TO_VNODE(bdp); + ip = XFS_BHVTOI(bdp); + + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return XFS_ERROR(EIO); + + /* + * If it's a directory with any blocks, read-ahead block 0 + * as we're almost certain to have the next operation be a read there. + */ + if (vp->v_type == VDIR && ip->i_d.di_nextents > 0) { + mode = xfs_ilock_map_shared(ip); + (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK); + xfs_iunlock(ip, mode); + } + return 0; +} + + +/* + * xfs_getattr + */ +/*ARGSUSED*/ +int +xfs_getattr( + bhv_desc_t *bdp, + vattr_t *vap, + int flags, + cred_t *credp) +{ + xfs_inode_t *ip; + xfs_mount_t *mp; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_getattr", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + if (!(flags & ATTR_LAZY)) + xfs_ilock(ip, XFS_ILOCK_SHARED); + + vap->va_size = ip->i_d.di_size; + if (vap->va_mask == AT_SIZE) { + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; + } + vap->va_nblocks = + XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); + vap->va_fsid = mp->m_dev; +#if XFS_BIG_FILESYSTEMS + vap->va_nodeid = ip->i_ino + mp->m_inoadd; +#else + vap->va_nodeid = ip->i_ino; +#endif + vap->va_nlink = ip->i_d.di_nlink; + + /* + * Quick exit for non-stat callers + */ + if ((vap->va_mask & ~(AT_SIZE|AT_FSID|AT_NODEID|AT_NLINK)) == 0) { + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; + } + + /* + * Copy from in-core inode. + */ + vap->va_type = vp->v_type; + vap->va_mode = ip->i_d.di_mode & MODEMASK; + vap->va_uid = ip->i_d.di_uid; + vap->va_gid = ip->i_d.di_gid; + vap->va_projid = ip->i_d.di_projid; + + /* + * Check vnode type block/char vs. everything else. + * Do it with bitmask because that's faster than looking + * for multiple values individually. + */ + if (((1 << vp->v_type) & ((1<va_rdev = 0; + + if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + +#if 0 + /* Large block sizes confuse various + * user space programs, so letting the + * stripe size through is not a good + * idea for now. + */ + vap->va_blksize = mp->m_swidth ? + /* + * If the underlying volume is a stripe, then + * return the stripe width in bytes as the + * recommended I/O size. + */ + (mp->m_swidth << mp->m_sb.sb_blocklog) : + /* + * Return the largest of the preferred buffer + * sizes since doing small I/Os into larger + * buffers causes buffers to be decommissioned. + * The value returned is in bytes. + */ + (1 << (int)MAX(mp->m_readio_log, + mp->m_writeio_log)); + +#else + vap->va_blksize = + /* + * Return the largest of the preferred buffer + * sizes since doing small I/Os into larger + * buffers causes buffers to be decommissioned. + * The value returned is in bytes. + */ + 1 << (int)MAX(mp->m_readio_log, + mp->m_writeio_log); +#endif + } else { + + /* + * If the file blocks are being allocated from a + * realtime partition, then return the inode's + * realtime extent size or the realtime volume's + * extent size. + */ + vap->va_blksize = ip->i_d.di_extsize ? + (ip->i_d.di_extsize << mp->m_sb.sb_blocklog) : + (mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog); + } + } else { + vap->va_rdev = IRIX_DEV_TO_KDEVT(ip->i_df.if_u2.if_rdev); + vap->va_blksize = BLKDEV_IOSIZE; + } + + vap->va_atime.tv_sec = ip->i_d.di_atime.t_sec; + vap->va_atime.tv_nsec = ip->i_d.di_atime.t_nsec; + vap->va_mtime.tv_sec = ip->i_d.di_mtime.t_sec; + vap->va_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; + vap->va_ctime.tv_sec = ip->i_d.di_ctime.t_sec; + vap->va_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; + + /* + * Exit for stat callers. See if any of the rest of the fields + * to be filled in are needed. + */ + if ((vap->va_mask & + (AT_XFLAGS|AT_EXTSIZE|AT_NEXTENTS|AT_ANEXTENTS| + AT_GENCOUNT|AT_VCODE)) == 0) { + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; + } + /* + * convert di_flags to xflags + */ + vap->va_xflags = + ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? + XFS_XFLAG_REALTIME : 0) | + ((ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) ? + XFS_XFLAG_PREALLOC : 0); + vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; + vap->va_nextents = + (ip->i_df.if_flags & XFS_IFEXTENTS) ? + ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_nextents; + if (ip->i_afp != NULL) + vap->va_anextents = + (ip->i_afp->if_flags & XFS_IFEXTENTS) ? + ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_anextents; + else + vap->va_anextents = 0; + vap->va_gencount = ip->i_d.di_gen; + vap->va_vcode = 0L; + + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; +} + + +/* + * xfs_setattr + */ +STATIC int +xfs_setattr( + bhv_desc_t *bdp, + vattr_t *vap, + int flags, + cred_t *credp) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int mask; + int code; + uint lock_flags; + uint commit_flags=0; + uid_t uid=0, iuid=0; + gid_t gid=0, igid=0; + int timeflags = 0; + vnode_t *vp; + xfs_prid_t projid=0, iprojid=0; + int privileged; + int mandlock_before, mandlock_after; + uint qflags; + struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; + int file_owner; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_setattr", (inst_t *)__return_address); + /* + * Cannot set certain attributes. + */ + mask = vap->va_mask; + if (mask & AT_NOSET) { + return XFS_ERROR(EINVAL); + } + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + /* + * Timestamps do not need to be logged and hence do not + * need to be done within a transaction. + */ + if (mask & AT_UPDTIMES) { + ASSERT((mask & ~AT_UPDTIMES) == 0); + timeflags = ((mask & AT_UPDATIME) ? XFS_ICHGTIME_ACC : 0) | + ((mask & AT_UPDCTIME) ? XFS_ICHGTIME_CHG : 0) | + ((mask & AT_UPDMTIME) ? XFS_ICHGTIME_MOD : 0); + xfs_ichgtime(ip, timeflags); + return 0; + } + + olddquot1 = olddquot2 = NULL; + udqp = gdqp = NULL; + + /* + * If disk quotas is on, we make sure that the dquots do exist on disk, + * before we start any other transactions. Trying to do this later + * is messy. We don't care to take a readlock to look at the ids + * in inode here, because we can't hold it across the trans_reserve. + * If the IDs do change before we take the ilock, we're covered + * because the i_*dquot fields will get updated anyway. + */ + if (XFS_IS_QUOTA_ON(mp) && (mask & (AT_UID|AT_GID))) { + qflags = 0; + if (mask & AT_UID) { + uid = vap->va_uid; + qflags |= XFS_QMOPT_UQUOTA; + } else { + uid = ip->i_d.di_uid; + } + if (mask & AT_GID) { + gid = vap->va_gid; + qflags |= XFS_QMOPT_GQUOTA; + } else { + gid = ip->i_d.di_gid; + } + /* + * We take a reference when we initialize udqp and gdqp, + * so it is important that we never blindly double trip on + * the same variable. See xfs_create() for an example. + */ + ASSERT(udqp == NULL); + ASSERT(gdqp == NULL); + if ((code = xfs_qm_vop_dqalloc(mp, ip, uid, gid, qflags, + &udqp, &gdqp))) + return (code); + } + + /* + * For the other attributes, we acquire the inode lock and + * first do an error checking pass. + */ + tp = NULL; + lock_flags = XFS_ILOCK_EXCL; + if (!(mask & AT_SIZE)) { + if ((mask != (AT_CTIME|AT_ATIME|AT_MTIME)) || + (mp->m_flags & XFS_MOUNT_WSYNC)) { + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); + commit_flags = 0; + if ((code = xfs_trans_reserve(tp, 0, + XFS_ICHANGE_LOG_RES(mp), 0, + 0, 0))) { + lock_flags = 0; + goto error_return; + } + } + } else { + if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_TRUNCATE) && + !(flags & ATTR_DMI)) { + code = xfs_dm_send_data_event (DM_EVENT_TRUNCATE, bdp, + vap->va_size, 0, AT_DELAY_FLAG(flags), NULL); + if (code) { + lock_flags = 0; + goto error_return; + } + } + lock_flags |= XFS_IOLOCK_EXCL; + } + + xfs_ilock(ip, lock_flags); + + if (_MAC_XFS_IACCESS(ip, MACWRITE, credp)) { + code = XFS_ERROR(EACCES); + goto error_return; + } + + /* boolean: are we the file owner? */ + file_owner = (current->fsuid == ip->i_d.di_uid); + + /* + * Change various properties of a file. + * Only the owner or users with CAP_FOWNER + * capability may do these things. + */ + if (mask & (AT_MODE|AT_XFLAGS|AT_EXTSIZE|AT_UID|AT_GID|AT_PROJID)) { + /* + * CAP_FOWNER overrides the following restrictions: + * + * The user ID of the calling process must be equal + * to the file owner ID, except in cases where the + * CAP_FSETID capability is applicable. + */ + if (!file_owner && !capable(CAP_FOWNER)) { + code = XFS_ERROR(EPERM); + goto error_return; + } + + /* + * CAP_FSETID overrides the following restrictions: + * + * The effective user ID of the calling process shall match + * the file owner when setting the set-user-ID and + * set-group-ID bits on that file. + * + * The effective group ID or one of the supplementary group + * IDs of the calling process shall match the group owner of + * the file when setting the set-group-ID bit on that file + */ + if (mask & AT_MODE) { + mode_t m = 0; + + if ((vap->va_mode & ISUID) && !file_owner) + m |= ISUID; + if ((vap->va_mode & ISGID) && + !in_group_p((gid_t)ip->i_d.di_gid)) + m |= ISGID; +#if 0 + /* Linux allows this, Irix doesn't. */ + if ((vap->va_mode & ISVTX) && vp->v_type != VDIR) + m |= ISVTX; +#endif + if (m && !capable(CAP_FSETID)) + vap->va_mode &= ~m; + } + } + + /* + * Change file ownership. Must be the owner or privileged. + * If the system was configured with the "restricted_chown" + * option, the owner is not permitted to give away the file, + * and can change the group id only to a group of which he + * or she is a member. + */ + if (mask & (AT_UID|AT_GID|AT_PROJID)) { + /* + * These IDs could have changed since we last looked at them. + * But, we're assured that if the ownership did change + * while we didn't have the inode locked, inode's dquot(s) + * would have changed also. + */ + iuid = ip->i_d.di_uid; + iprojid = ip->i_d.di_projid; + igid = ip->i_d.di_gid; + gid = (mask & AT_GID) ? vap->va_gid : igid; + uid = (mask & AT_UID) ? vap->va_uid : iuid; + projid = (mask & AT_PROJID) ? (xfs_prid_t)vap->va_projid : + iprojid; + + /* + * CAP_CHOWN overrides the following restrictions: + * + * If _POSIX_CHOWN_RESTRICTED is defined, this capability + * shall override the restriction that a process cannot + * change the user ID of a file it owns and the restriction + * that the group ID supplied to the chown() function + * shall be equal to either the group ID or one of the + * supplementary group IDs of the calling process. + * + * XXX: How does restricted_chown affect projid? + */ + if (restricted_chown && + (iuid != uid || (igid != gid && + !in_group_p((gid_t)gid))) && + !capable(CAP_CHOWN)) { + code = XFS_ERROR(EPERM); + goto error_return; + } + /* + * Do a quota reservation only if uid or gid is actually + * going to change. + */ + if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || + (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { + ASSERT(tp); + /* + * XXX:casey - This may result in unnecessary auditing. + */ + privileged = capable(CAP_FOWNER); + if ((code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp, + privileged ? + XFS_QMOPT_FORCE_RES : + 0))) + /* out of quota */ + goto error_return; + } + } + + /* + * Truncate file. Must have write permission and not be a directory. + */ + if (mask & AT_SIZE) { + /* Short circuit the truncate case for zero length files */ + if ((vap->va_size == 0) && + (ip->i_d.di_size == 0) && (ip->i_d.di_nextents == 0)) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + lock_flags &= ~XFS_ILOCK_EXCL; + if (mask & AT_CTIME) + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + code = 0; + goto error_return; + } + + if (vp->v_type == VDIR) { + code = XFS_ERROR(EISDIR); + goto error_return; + } else if (vp->v_type != VREG) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + /* + * Make sure that the dquots are attached to the inode. + */ + if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) { + if ((code = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) + goto error_return; + } + } + + /* + * Change file access or modified times. + */ + if (mask & (AT_ATIME|AT_MTIME)) { + if (!file_owner) { + if ((flags & ATTR_UTIME) && + !capable(CAP_FOWNER)) { + code = XFS_ERROR(EPERM); + goto error_return; + } + } + } + + /* + * Change extent size or realtime flag. + */ + if (mask & (AT_EXTSIZE|AT_XFLAGS)) { + /* + * Can't change extent size if any extents are allocated. + */ + if (ip->i_d.di_nextents && (mask & AT_EXTSIZE) && + ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != + vap->va_extsize) ) { + code = XFS_ERROR(EINVAL); /* EFBIG? */ + goto error_return; + } + + /* + * Can't set extent size unless the file is marked, or + * about to be marked as a realtime file. + * + * This check will be removed when fixed size extents + * with buffered data writes is implemented. + * + */ + if ((mask & AT_EXTSIZE) && + ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != + vap->va_extsize) && + (!((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) || + ((mask & AT_XFLAGS) && + (vap->va_xflags & XFS_XFLAG_REALTIME))))) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + + /* + * Can't change realtime flag if any extents are allocated. + */ + if (ip->i_d.di_nextents && (mask & AT_XFLAGS) && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != + (vap->va_xflags & XFS_XFLAG_REALTIME)) { + code = XFS_ERROR(EINVAL); /* EFBIG? */ + goto error_return; + } + /* + * Extent size must be a multiple of the appropriate block + * size, if set at all. + */ + if ((mask & AT_EXTSIZE) && vap->va_extsize != 0) { + xfs_extlen_t size; + + if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) || + ((mask & AT_XFLAGS) && + (vap->va_xflags & XFS_XFLAG_REALTIME))) { + size = mp->m_sb.sb_rextsize << + mp->m_sb.sb_blocklog; + } else { + size = mp->m_sb.sb_blocksize; + } + if (vap->va_extsize % size) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + } + /* + * If realtime flag is set then must have realtime data. + */ + if ((mask & AT_XFLAGS) && + (vap->va_xflags & XFS_XFLAG_REALTIME)) { + if ((mp->m_sb.sb_rblocks == 0) || + (mp->m_sb.sb_rextsize == 0) || + (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + } + } + + /* + * Now we can make the changes. Before we join the inode + * to the transaction, if AT_SIZE is set then take care of + * the part of the truncation that must be done without the + * inode lock. This needs to be done before joining the inode + * to the transaction, because the inode cannot be unlocked + * once it is a part of the transaction. + */ + if (mask & AT_SIZE) { + if (vap->va_size > ip->i_d.di_size) { + code = xfs_igrow_start(ip, vap->va_size, credp); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } else if (vap->va_size < ip->i_d.di_size) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, + (xfs_fsize_t)vap->va_size); + code = 0; + } else { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + code = 0; + } + if (code) { + ASSERT(tp == NULL); + lock_flags &= ~XFS_ILOCK_EXCL; + ASSERT(lock_flags == XFS_IOLOCK_EXCL); + goto error_return; + } + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); + if ((code = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return code; + } + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + xfs_ilock(ip, XFS_ILOCK_EXCL); + } + + if (tp) { + xfs_trans_ijoin(tp, ip, lock_flags); + xfs_trans_ihold(tp, ip); + } + + /* determine whether mandatory locking mode changes */ + mandlock_before = MANDLOCK(vp, ip->i_d.di_mode); + + /* + * Truncate file. Must have write permission and not be a directory. + */ + if (mask & AT_SIZE) { + if (vap->va_size > ip->i_d.di_size) { + xfs_igrow_finish(tp, ip, vap->va_size, + !(flags & ATTR_DMI)); + } else if ((vap->va_size < ip->i_d.di_size) || + ((vap->va_size == 0) && ip->i_d.di_nextents)) { + /* + * signal a sync transaction unless + * we're truncating an already unlinked + * file on a wsync filesystem + */ + code = xfs_itruncate_finish(&tp, ip, + (xfs_fsize_t)vap->va_size, + XFS_DATA_FORK, + ((ip->i_d.di_nlink != 0 || + !(mp->m_flags & XFS_MOUNT_WSYNC)) + ? 1 : 0)); + if (code) { + goto abort_return; + } + } + /* + * Have to do this even if the file's size doesn't change. + */ + timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; + } + + /* + * Change file access modes. + */ + if (mask & AT_MODE) { + ip->i_d.di_mode &= IFMT; + ip->i_d.di_mode |= vap->va_mode & ~IFMT; + + xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); + timeflags |= XFS_ICHGTIME_CHG; + } + + /* + * Change file ownership. Must be the owner or privileged. + * If the system was configured with the "restricted_chown" + * option, the owner is not permitted to give away the file, + * and can change the group id only to a group of which he + * or she is a member. + */ + if (mask & (AT_UID|AT_GID|AT_PROJID)) { + /* + * CAP_FSETID overrides the following restrictions: + * + * The set-user-ID and set-group-ID bits of a file will be + * cleared upon successful return from chown() + */ + if ((ip->i_d.di_mode & (ISUID|ISGID)) && + !capable(CAP_FSETID)) { + ip->i_d.di_mode &= ~(ISUID|ISGID); + } + + /* + * Change the ownerships and register quota modifications + * in the transaction. + */ + if (iuid != uid) { + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(mask & AT_UID); + ASSERT(udqp); + ASSERT(xfs_qm_dqid(udqp) == (xfs_dqid_t)uid); + olddquot1 = xfs_qm_vop_chown(tp, ip, + &ip->i_udquot, + udqp); + /* + * We'll dqrele olddquot at the end. + */ + } + ip->i_d.di_uid = uid; + } + if (igid != gid) { + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(mask & AT_GID); + ASSERT(gdqp); + ASSERT(xfs_qm_dqid(gdqp) == gid); + olddquot2 = xfs_qm_vop_chown(tp, ip, + &ip->i_gdquot, + gdqp); + } + ip->i_d.di_gid = gid; + } + if (iprojid != projid) { + ip->i_d.di_projid = projid; + /* + * We may have to rev the inode as well as + * the superblock version number since projids didn't + * exist before DINODE_VERSION_2 and SB_VERSION_NLINK. + */ + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) + xfs_bump_ino_vers2(tp, ip); + } + + xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); + timeflags |= XFS_ICHGTIME_CHG; + } + + + /* + * Change file access or modified times. + */ + if (mask & (AT_ATIME|AT_MTIME)) { + if (mask & AT_ATIME) { + ip->i_d.di_atime.t_sec = vap->va_atime.tv_sec; + ip->i_d.di_atime.t_nsec = vap->va_atime.tv_nsec; + ip->i_update_core = 1; + timeflags &= ~XFS_ICHGTIME_ACC; + } + if (mask & AT_MTIME) { + ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec; + ip->i_d.di_mtime.t_nsec = vap->va_mtime.tv_nsec; + timeflags &= ~XFS_ICHGTIME_MOD; + timeflags |= XFS_ICHGTIME_CHG; + } + if (tp && (flags & ATTR_UTIME)) + xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); + } + + /* + * Change XFS-added attributes. + */ + if (mask & (AT_EXTSIZE|AT_XFLAGS)) { + if (mask & AT_EXTSIZE) { + /* + * Converting bytes to fs blocks. + */ + ip->i_d.di_extsize = vap->va_extsize >> + mp->m_sb.sb_blocklog; + } + if (mask & AT_XFLAGS) { + ip->i_d.di_flags = 0; + if (vap->va_xflags & XFS_XFLAG_REALTIME) { + ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; + /* This is replicated in the io core for + * CXFS use + */ + ip->i_iocore.io_flags |= XFS_IOCORE_RT; + } + /* can't set PREALLOC this way, just ignore it */ + } + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + timeflags |= XFS_ICHGTIME_CHG; + } + + /* + * Change file inode change time only if AT_CTIME set + * AND we have been called by a DMI function. + */ + + if ( (flags & ATTR_DMI) && (mask & AT_CTIME) ) { + ip->i_d.di_ctime.t_sec = vap->va_ctime.tv_sec; + ip->i_d.di_ctime.t_nsec = vap->va_ctime.tv_nsec; + ip->i_update_core = 1; + timeflags &= ~XFS_ICHGTIME_CHG; + } + + /* + * Send out timestamp changes that need to be set to the + * current time. Not done when called by a DMI function. + */ + if (timeflags && !(flags & ATTR_DMI)) + xfs_ichgtime(ip, timeflags); + + XFS_STATS_INC(xfsstats.xs_ig_attrchg); + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + * This is slightly sub-optimal in that truncates require + * two sync transactions instead of one for wsync filesytems. + * One for the truncate and one for the timestamps since we + * don't want to change the timestamps unless we're sure the + * truncate worked. Truncates are less than 1% of the laddis + * mix so this probably isn't worth the trouble to optimize. + */ + code = 0; + if (tp) { + if (mp->m_flags & XFS_MOUNT_WSYNC) + xfs_trans_set_sync(tp); + + code = xfs_trans_commit(tp, commit_flags, NULL); + } + + /* + * If the (regular) file's mandatory locking mode changed, then + * notify the vnode. We do this under the inode lock to prevent + * racing calls to vop_vnode_change. + */ + mandlock_after = MANDLOCK(vp, ip->i_d.di_mode); + if (mandlock_before != mandlock_after) { + VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_ENF_LOCKING, + mandlock_after); + } + + xfs_iunlock(ip, lock_flags); + + /* + * release any dquot(s) inode had kept before chown + */ + if (olddquot1) + xfs_qm_dqrele(olddquot1); + if (olddquot2) + xfs_qm_dqrele(olddquot2); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (code) { + return code; + } + + if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_ATTRIBUTE) && + !(flags & ATTR_DMI)) { + (void) dm_send_namesp_event (DM_EVENT_ATTRIBUTE, bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, NULL, NULL, + 0, 0, AT_DELAY_FLAG(flags)); + } + return 0; + + abort_return: + commit_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + if (tp) { + xfs_trans_cancel(tp, commit_flags); + } + if (lock_flags != 0) { + xfs_iunlock(ip, lock_flags); + } + return code; +} /* xfs_setattr */ + + +/* + * xfs_access + * Null conversion from vnode mode bits to inode mode bits, as in efs. + */ +/*ARGSUSED*/ +STATIC int +xfs_access( + bhv_desc_t *bdp, + int mode, + cred_t *credp) +{ + xfs_inode_t *ip; + int error; + + vn_trace_entry(BHV_TO_VNODE(bdp), "xfs_access", + (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_iaccess(ip, mode, credp); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return error; +} + + +/* + * xfs_readlink + * + */ +/*ARGSUSED*/ +STATIC int +xfs_readlink( + bhv_desc_t *bdp, + uio_t *uiop, + cred_t *credp) +{ + xfs_inode_t *ip; + int count; + xfs_off_t offset; + int pathlen; + vnode_t *vp; + int error = 0; + xfs_mount_t *mp; + int nmaps; + xfs_bmbt_irec_t mval[SYMLINK_MAPS]; + xfs_daddr_t d; + int byte_cnt; + int n; + xfs_buf_t *bp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_readlink", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + xfs_ilock(ip, XFS_ILOCK_SHARED); + + ASSERT((ip->i_d.di_mode & IFMT) == IFLNK); + + offset = uiop->uio_offset; + count = uiop->uio_resid; + + if (offset < 0) { + error = XFS_ERROR(EINVAL); + goto error_return; + } + if (count <= 0) { + error = 0; + goto error_return; + } + + if (!(uiop->uio_fmode & FINVIS)) { + xfs_ichgtime(ip, XFS_ICHGTIME_ACC); + } + + /* + * See if the symlink is stored inline. + */ + pathlen = (int)ip->i_d.di_size; + + if (ip->i_df.if_flags & XFS_IFINLINE) { + error = uiomove(ip->i_df.if_u1.if_data, pathlen, UIO_READ, uiop); + } + else { + /* + * Symlink not inline. Call bmap to get it in. + */ + nmaps = SYMLINK_MAPS; + + error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), + 0, NULL, 0, mval, &nmaps, NULL); + + if (error) { + goto error_return; + } + + for (n = 0; n < nmaps; n++) { + d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); + byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); + bp = xfs_buf_read(mp->m_ddev_targp, d, + BTOBB(byte_cnt), 0); + error = XFS_BUF_GETERROR(bp); + if (error) { + xfs_ioerror_alert("xfs_readlink", + ip->i_mount, bp, XFS_BUF_ADDR(bp)); + xfs_buf_relse(bp); + goto error_return; + } + if (pathlen < byte_cnt) + byte_cnt = pathlen; + pathlen -= byte_cnt; + + error = uiomove(XFS_BUF_PTR(bp), byte_cnt, + UIO_READ, uiop); + xfs_buf_relse (bp); + } + + } + + +error_return: + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + return error; +} + +/* + * xfs_fsync + * + * This is called to sync the inode and its data out to disk. + * We need to hold the I/O lock while flushing the data, and + * the inode lock while flushing the inode. The inode lock CANNOT + * be held while flushing the data, so acquire after we're done + * with that. + */ +/*ARGSUSED*/ +STATIC int +xfs_fsync( + bhv_desc_t *bdp, + int flag, + cred_t *credp, + xfs_off_t start, + xfs_off_t stop) +{ + xfs_inode_t *ip; + int error; + /* REFERENCED */ + int error2; + /* REFERENCED */ + int syncall; + vnode_t *vp; + xfs_trans_t *tp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_fsync", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + + ASSERT(start >= 0 && stop >= -1); + + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return XFS_ERROR(EIO); + + xfs_ilock(ip, XFS_IOLOCK_EXCL); + + syncall = error = error2 = 0; + + if (stop == -1) { + ASSERT(start >= 0); + if (start == 0) + syncall = 1; + stop = xfs_file_last_byte(ip); + } + + /* + * If we're invalidating, always flush since we want to + * tear things down. Otherwise, don't flush anything if + * we're not dirty. + */ + if (flag & FSYNC_INVAL) { + if (ip->i_df.if_flags & XFS_IFEXTENTS && + ip->i_df.if_bytes > 0) { + VOP_FLUSHINVAL_PAGES(vp, start, -1, FI_REMAPF_LOCKED); + } + ASSERT(syncall == 0 || (VN_CACHED(vp) == 0)); + } else { + /* + * In the non-invalidating case, calls to fsync() do not + * flush all the dirty mmap'd pages. That requires a + * call to msync(). + */ + VOP_FLUSH_PAGES(vp, start, -1, + (flag & FSYNC_WAIT) ? 0 : XFS_B_ASYNC, + FI_NONE, error2); + } + + if (error2) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return XFS_ERROR(error2); + } + + /* + * We always need to make sure that the required inode state + * is safe on disk. The vnode might be clean but because + * of committed transactions that haven't hit the disk yet. + * Likewise, there could be unflushed non-transactional + * changes to the inode core that have to go to disk. + * + * The following code depends on one assumption: that + * any transaction that changes an inode logs the core + * because it has to change some field in the inode core + * (typically nextents or nblocks). That assumption + * implies that any transactions against an inode will + * catch any non-transactional updates. If inode-altering + * transactions exist that violate this assumption, the + * code breaks. Right now, it figures that if the involved + * update_* field is clear and the inode is unpinned, the + * inode is clean. Either it's been flushed or it's been + * committed and the commit has hit the disk unpinning the inode. + * (Note that xfs_inode_item_format() called at commit clears + * the update_* fields.) + */ + if (!(flag & FSYNC_DATA)) { + xfs_ilock(ip, XFS_ILOCK_SHARED); + + if (ip->i_update_core == 0) { + /* + * Timestamps/size haven't changed since last inode + * flush or inode transaction commit. That means + * either nothing got written or a transaction + * committed which caught the updates. If the + * latter happened and the transaction hasn't + * hit the disk yet, the inode will be still + * be pinned. If it is, force the log. + */ + if (xfs_ipincount(ip) == 0) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + } else { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + xfs_log_force(ip->i_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | + ((flag & FSYNC_WAIT) + ? XFS_LOG_SYNC : 0)); + } + error = 0; + } else { + /* + * Kick off a transaction to log the inode + * core to get the updates. Make it + * sync if FSYNC_WAIT is passed in (which + * is done by everybody but specfs). The + * sync transaction will also force the log. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); + if ((error = xfs_trans_reserve(tp, 0, + XFS_FSYNC_TS_LOG_RES(ip->i_mount), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Note - it's possible that we might have pushed + * ourselves out of the way during trans_reserve + * which would flush the inode. But there's no + * guarantee that the inode buffer has actually + * gone out yet (it's delwri). Plus the buffer + * could be pinned anyway if it's part of an + * inode in another recent transaction. So we + * play it safe and fire off the transaction anyway. + */ + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + if (flag & FSYNC_WAIT) + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + + xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + } + } else { + /* + * We don't care about the timestamps here. We + * only care about the size field growing on us + * and forcing any space allocation transactions. + * We have to flush changes to the size fields + * otherwise we could write out data that + * becomes inaccessible after a crash. + */ + xfs_ilock(ip, XFS_ILOCK_SHARED); + + if (ip->i_update_size == 0) { + /* + * Force the log if the inode is pinned. + * That ensures that all transactions committed + * against the inode hit the disk. This may do + * too much work but it's safe. + */ + if (xfs_ipincount(ip) == 0) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + } else { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + xfs_log_force(ip->i_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | + ((flag & FSYNC_WAIT) + ? XFS_LOG_SYNC : 0)); + } + error = 0; + } else { + /* + * Kick off a sync transaction to log the inode + * core. The transaction has to be sync since + * we need these updates to guarantee that the + * data written will be seen. The sync + * transaction will also force the log. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); + if ((error = xfs_trans_reserve(tp, 0, + XFS_FSYNC_TS_LOG_RES(ip->i_mount), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Note - it's possible that we might have pushed + * ourselves out of the way during trans_reserve + * which would flush the inode. But there's no + * guarantee that the inode buffer has actually + * gone out yet (it's delwri). Plus the buffer + * could be pinned anyway if it's part of an + * inode in another recent transaction. So we + * play it safe and fire off the transaction anyway. + */ + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + if (flag & FSYNC_WAIT) + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + + xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + } + } + return error; +} + + +#if 0 +/* + * This is a utility routine for xfs_inactive. It is called when a + * transaction attempting to free up the disk space for a file encounters + * an error. It cancels the old transaction and starts up a new one + * to be used to free up the inode. It also sets the inode size and extent + * counts to 0 and frees up any memory being used to store inline data, + * extents, or btree roots. + */ +STATIC void +xfs_itruncate_cleanup( + xfs_trans_t **tpp, + xfs_inode_t *ip, + int commit_flags, + int fork) +{ + xfs_mount_t *mp; + /* REFERENCED */ + int error; + + mp = ip->i_mount; + if (*tpp) { + xfs_trans_cancel(*tpp, commit_flags | XFS_TRANS_ABORT); + } + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + *tpp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + error = xfs_trans_reserve(*tpp, 0, XFS_IFREE_LOG_RES(mp), 0, 0, + XFS_DEFAULT_LOG_COUNT); + if (error) { + return; + } + + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ijoin(*tpp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(*tpp, ip); + + xfs_idestroy_fork(ip, fork); + + if (fork == XFS_DATA_FORK) { + ip->i_d.di_nblocks = 0; + ip->i_d.di_nextents = 0; + ip->i_d.di_size = 0; + } else { + ip->i_d.di_anextents = 0; + } + xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); +} +#endif + +/* + * This is called by xfs_inactive to free any blocks beyond eof, + * when the link count isn't zero. + */ +STATIC int +xfs_inactive_free_eofblocks( + xfs_mount_t *mp, + xfs_inode_t *ip) +{ + xfs_trans_t *tp; + int error; + xfs_fileoff_t end_fsb; + xfs_fileoff_t last_fsb; + xfs_filblks_t map_len; + int nimaps; + xfs_bmbt_irec_t imap; + + /* + * Figure out if there are any blocks beyond the end + * of the file. If not, then there is nothing to do. + */ + end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_d.di_size)); + last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET); + map_len = last_fsb - end_fsb; + if (map_len <= 0) + return (0); + + nimaps = 1; + xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, + NULL, 0, &imap, &nimaps, NULL); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + if (!error && (nimaps != 0) && + (imap.br_startblock != HOLESTARTBLOCK)) { + /* + * Attach the dquots to the inode up front. + */ + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return (error); + } + } + + /* + * There are blocks after the end of file. + * Free them up now by truncating the file to + * its current size. + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + + /* + * Do the xfs_itruncate_start() call before + * reserving any log space because + * itruncate_start will call into the buffer + * cache and we can't + * do that within a transaction. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, + ip->i_d.di_size); + + error = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (error); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, + XFS_IOLOCK_EXCL | + XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + error = xfs_itruncate_finish(&tp, ip, + ip->i_d.di_size, + XFS_DATA_FORK, + 0); + /* + * If we get an error at this point we + * simply don't bother truncating the file. + */ + if (error) { + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + } else { + error = xfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES, + NULL); + } + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + } + return (error); +} + +/* + * Free a symlink that has blocks associated with it. + */ +STATIC int +xfs_inactive_symlink_rmt( + xfs_inode_t *ip, + xfs_trans_t **tpp) +{ + xfs_buf_t *bp; + int committed; + int done; + int error; + xfs_fsblock_t first_block; + xfs_bmap_free_t free_list; + int i; + xfs_mount_t *mp; + xfs_bmbt_irec_t mval[SYMLINK_MAPS]; + int nmaps; + xfs_trans_t *ntp; + int size; + xfs_trans_t *tp; + + tp = *tpp; + mp = ip->i_mount; + ASSERT(ip->i_d.di_size > XFS_IFORK_DSIZE(ip)); + /* + * We're freeing a symlink that has some + * blocks allocated to it. Free the + * blocks here. We know that we've got + * either 1 or 2 extents and that we can + * free them all in one bunmapi call. + */ + ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); + if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + *tpp = NULL; + return error; + } + /* + * Lock the inode, fix the size, and join it to the transaction. + * Hold it so in the normal path, we still have it locked for + * the second transaction. In the error paths we need it + * held so the cancel won't rele it, see below. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + size = (int)ip->i_d.di_size; + ip->i_d.di_size = 0; + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + /* + * Find the block(s) so we can inval and unmap them. + */ + done = 0; + XFS_BMAP_INIT(&free_list, &first_block); + nmaps = sizeof(mval) / sizeof(mval[0]); + if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size), + XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps, + &free_list))) + goto error0; + /* + * Invalidate the block(s). + */ + for (i = 0; i < nmaps; i++) { + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, mval[i].br_startblock), + XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0); + xfs_trans_binval(tp, bp); + } + /* + * Unmap the dead block(s) to the free_list. + */ + if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps, + &first_block, &free_list, &done))) + goto error1; + ASSERT(done); + /* + * Commit the first transaction. This logs the EFI and the inode. + */ + if ((error = xfs_bmap_finish(&tp, &free_list, first_block, &committed))) + goto error1; + /* + * The transaction must have been committed, since there were + * actually extents freed by xfs_bunmapi. See xfs_bmap_finish. + * The new tp has the extent freeing and EFDs. + */ + ASSERT(committed); + /* + * The first xact was committed, so add the inode to the new one. + * Mark it dirty so it will be logged and moved forward in the log as + * part of every commit. + */ + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + /* + * Get a new, empty transaction to return to our caller. + */ + ntp = xfs_trans_dup(tp); + /* + * Commit the transaction containing extent freeing and EFD's. + * If we get an error on the commit here or on the reserve below, + * we need to unlock the inode since the new transaction doesn't + * have the inode attached. + */ + error = xfs_trans_commit(tp, 0, NULL); + tp = ntp; + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + goto error0; + } + /* + * Remove the memory for extent descriptions (just bookkeeping). + */ + if (ip->i_df.if_bytes) + xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK); + ASSERT(ip->i_df.if_bytes == 0); + /* + * Put an itruncate log reservation in the new transaction + * for our caller. + */ + if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + goto error0; + } + /* + * Return with the inode locked but not joined to the transaction. + */ + *tpp = tp; + return 0; + + error1: + xfs_bmap_cancel(&free_list); + error0: + /* + * Have to come here with the inode locked and either + * (held and in the transaction) or (not in the transaction). + * If the inode isn't held then cancel would iput it, but + * that's wrong since this is inactive and the vnode ref + * count is 0 already. + * Cancel won't do anything to the inode if held, but it still + * needs to be locked until the cancel is done, if it was + * joined to the transaction. + */ + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + *tpp = NULL; + return error; + +} + +STATIC int +xfs_inactive_symlink_local( + xfs_inode_t *ip, + xfs_trans_t **tpp) +{ + int error; + ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip)); + /* + * We're freeing a symlink which fit into + * the inode. Just free the memory used + * to hold the old symlink. + */ + error = xfs_trans_reserve(*tpp, 0, + XFS_ITRUNCATE_LOG_RES(ip->i_mount), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + + if (error) { + xfs_trans_cancel(*tpp, 0); + *tpp = NULL; + return (error); + } + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + + /* + * Zero length symlinks _can_ exist. + */ + if (ip->i_df.if_bytes > 0) { + xfs_idata_realloc(ip, + -(ip->i_df.if_bytes), + XFS_DATA_FORK); + ASSERT(ip->i_df.if_bytes == 0); + } + return (0); +} + +/* + * + */ +STATIC int +xfs_inactive_attrs( + xfs_inode_t *ip, + xfs_trans_t **tpp, + int *commitflags) +{ + xfs_trans_t *tp; + int error; + xfs_mount_t *mp; + + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + tp = *tpp; + mp = ip->i_mount; + ASSERT(ip->i_d.di_forkoff != 0); + xfs_trans_commit(tp, *commitflags, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + *commitflags = 0; + + error = xfs_attr_inactive(ip); + if (error) { + *tpp = NULL; + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (error); /* goto out*/ + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + error = xfs_trans_reserve(tp, 0, + XFS_IFREE_LOG_RES(mp), + 0, 0, + XFS_DEFAULT_LOG_COUNT); + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + *tpp = NULL; + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (error); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_idestroy_fork(ip, XFS_ATTR_FORK); + + ASSERT(ip->i_d.di_anextents == 0); + + *tpp = tp; + return (0); +} + +/*ARGSUSED*/ +STATIC int +xfs_release( + bhv_desc_t *bdp) +{ + xfs_inode_t *ip; + vnode_t *vp; + xfs_mount_t *mp; + int error; + + vp = BHV_TO_VNODE(bdp); + ip = XFS_BHVTOI(bdp); + + if ((vp->v_type != VREG) || (ip->i_d.di_mode == 0)) { + return 0; + } + + /* If this is a read-only mount, don't do this (would generate I/O) */ + if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + return 0; + + /* If we are in the NFS reference cache then don't do this now */ + if (ip->i_refcache) + return 0; + + mp = ip->i_mount; + + if (ip->i_d.di_nlink != 0) { + if ((((ip->i_d.di_mode & IFMT) == IFREG) && + ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && + (ip->i_df.if_flags & XFS_IFEXTENTS)) && + (!(ip->i_d.di_flags & XFS_DIFLAG_PREALLOC))) { + if ((error = xfs_inactive_free_eofblocks(mp, ip))) + return (error); + /* Update linux inode block count after free above */ + LINVFS_GET_IP(vp)->i_blocks = XFS_FSB_TO_BB(mp, + ip->i_d.di_nblocks + ip->i_delayed_blks); + } + } + + return 0; +} + +/* + * xfs_inactive + * + * This is called when the vnode reference count for the vnode + * goes to zero. If the file has been unlinked, then it must + * now be truncated. Also, we clear all of the read-ahead state + * kept for the inode here since the file is now closed. + */ +/*ARGSUSED*/ +STATIC int +xfs_inactive( + bhv_desc_t *bdp, + cred_t *credp) +{ + xfs_inode_t *ip; + /* REFERENCED */ + vnode_t *vp; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error; + int commit_flags; + int truncate; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_inactive", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + + /* + * If the inode is already free, then there can be nothing + * to clean up here. + */ + if (ip->i_d.di_mode == 0) { + ASSERT(ip->i_df.if_real_bytes == 0); + ASSERT(ip->i_df.if_broot_bytes == 0); + return VN_INACTIVE_CACHE; + } + + /* + * Only do a truncate if it's a regular file with + * some actual space in it. It's OK to look at the + * inode's fields without the lock because we're the + * only one with a reference to the inode. + */ + truncate = ((ip->i_d.di_nlink == 0) && + ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0)) && + ((ip->i_d.di_mode & IFMT) == IFREG)); + + mp = ip->i_mount; + + if (ip->i_d.di_nlink == 0 && + DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_DESTROY)) { + (void) dm_send_destroy_event(bdp, DM_RIGHT_NULL); + } + + error = 0; + + /* If this is a read-only mount, don't do this (would generate I/O) */ + if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + goto out; + + if (ip->i_d.di_nlink != 0) { + if ((((ip->i_d.di_mode & IFMT) == IFREG) && + ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && + (ip->i_df.if_flags & XFS_IFEXTENTS)) && + (!(ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) || + (ip->i_delayed_blks != 0))) { + if ((error = xfs_inactive_free_eofblocks(mp, ip))) + return (VN_INACTIVE_CACHE); + /* Update linux inode block count after free above */ + LINVFS_GET_IP(vp)->i_blocks = XFS_FSB_TO_BB(mp, + ip->i_d.di_nblocks + ip->i_delayed_blks); + } + goto out; + } + + ASSERT(ip->i_d.di_nlink == 0); + + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return (VN_INACTIVE_CACHE); + } + } + tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + if (truncate) { + /* + * Do the xfs_itruncate_start() call before + * reserving any log space because itruncate_start + * will call into the buffer cache and we can't + * do that within a transaction. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); + + error = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + if (error) { + /* Don't call itruncate_cleanup */ + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (VN_INACTIVE_CACHE); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * normally, we have to run xfs_itruncate_finish sync. + * But if filesystem is wsync and we're in the inactive + * path, then we know that nlink == 0, and that the + * xaction that made nlink == 0 is permanently committed + * since xfs_remove runs as a synchronous transaction. + */ + error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK, + (!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0)); + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + + if (error) { + xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + return (VN_INACTIVE_CACHE); + } + } else if ((ip->i_d.di_mode & IFMT) == IFLNK) { + + /* + * If we get an error while cleaning up a + * symlink we bail out. + */ + error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ? + xfs_inactive_symlink_rmt(ip, &tp) : + xfs_inactive_symlink_local(ip, &tp); + + if (error) { + ASSERT(tp == NULL); + return (VN_INACTIVE_CACHE); + } + + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + + } else { + error = xfs_trans_reserve(tp, 0, + XFS_IFREE_LOG_RES(mp), + 0, 0, + XFS_DEFAULT_LOG_COUNT); + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + return (VN_INACTIVE_CACHE); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + commit_flags = 0; + } + + /* + * If there are attributes associated with the file + * then blow them away now. The code calls a routine + * that recursively deconstructs the attribute fork. + * We need to just commit the current transaction + * because we can't use it for xfs_attr_inactive(). + */ + if (ip->i_d.di_anextents > 0) { + error = xfs_inactive_attrs(ip, &tp, &commit_flags); + /* + * If we got an error, the transaction is already + * cancelled, and the inode is unlocked. Just get out. + */ + if (error) + return (VN_INACTIVE_CACHE); + } else if (ip->i_afp) { + xfs_idestroy_fork(ip, XFS_ATTR_FORK); + } + + /* + * Free the inode. + */ + error = xfs_ifree(tp, ip); + if (error) { + /* + * If we fail to free the inode, shut down. The cancel + * might do that, we need to make sure. Otherwise the + * inode might be lost for a long time or forever. + */ + if (!XFS_FORCED_SHUTDOWN(tp->t_mountp)) { + cmn_err(CE_NOTE, + "xfs_inactive: xfs_ifree() returned an error = %d on %s", + error,tp->t_mountp->m_fsname); + xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR); + } + xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT); + } else { + /* + * Credit the quota account(s). The inode is gone. + */ + if (XFS_IS_QUOTA_ON(tp->t_mountp)) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, + -1); + + /* + * Just ignore errors at this point. There is + * nothing we can do except to try to keep going. + */ + (void) xfs_trans_commit(tp, commit_flags, NULL); + } + /* + * Release the dquots held by inode, if any. + */ + if (ip->i_udquot || ip->i_gdquot) + xfs_qm_dqdettach_inode(ip); + + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + + out: + return VN_INACTIVE_CACHE; +} + + +/* + * xfs_lookup + */ +/*ARGSUSED*/ +STATIC int +xfs_lookup( + bhv_desc_t *dir_bdp, + struct dentry *dentry, + vnode_t **vpp, + int flags, + vnode_t *rdir, + cred_t *credp) +{ + xfs_inode_t *dp, *ip; + struct vnode *vp; + xfs_ino_t e_inum; + int error; + uint lock_mode; + uint lookup_flags; + vnode_t *dir_vp; + + dir_vp = BHV_TO_VNODE(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_lookup", (inst_t *)__return_address); + + dp = XFS_BHVTOI(dir_bdp); + + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) + return XFS_ERROR(EIO); + + lock_mode = xfs_ilock_map_shared(dp); + + lookup_flags = DLF_IGET; + if (lock_mode == XFS_ILOCK_SHARED) { + lookup_flags |= DLF_LOCK_SHARED; + } + error = xfs_dir_lookup_int(dir_bdp, lookup_flags, dentry, &e_inum, &ip); + if (error) { + xfs_iunlock_map_shared(dp, lock_mode); + return error; + } + + vp = XFS_ITOV(ip); + + ITRACE(ip); + + xfs_iunlock_map_shared(dp, lock_mode); + + *vpp = vp; + + return 0; +} + +#ifdef XFS_RW_TRACE +STATIC void +xfs_ctrunc_trace( + int tag, + xfs_inode_t *ip) +{ + if (ip->i_rwtrace == NULL) { + return; + } + + ktrace_enter(ip->i_rwtrace, + (void*)((long)tag), + (void*)ip, + (void*)((long)private.p_cpuid), + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0); +} +#endif /* XFS_RW_TRACE */ + +#define XFS_CREATE_NEW_MAXTRIES 10000 + +/* + * xfs_create (create a new file). + * It might still find name exists out there, though. + * But vpp, doens't point at a vnode. + */ +STATIC int +xfs_create( + bhv_desc_t *dir_bdp, + struct dentry *dentry, + vattr_t *vap, + vnode_t **vpp, + cred_t *credp) +{ + char *name = (char *)dentry->d_name.name; + vnode_t *dir_vp; + xfs_inode_t *dp, *ip; + vnode_t *vp=NULL; + xfs_trans_t *tp; + xfs_mount_t *mp; + dev_t rdev; + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + boolean_t dp_joined_to_trans; + int dm_event_sent = 0; + uint cancel_flags; + int committed; + xfs_prid_t prid; + struct xfs_dquot *udqp, *gdqp; + uint resblks; + int dm_di_mode; + int namelen; + + ASSERT(!*vpp); + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_create", (inst_t *)__return_address); + + dm_di_mode = vap->va_mode|VTTOIF(vap->va_type); + namelen = dentry->d_name.len; + if (namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) { + error = xfs_dm_send_create_event(dir_bdp, name, + dm_di_mode, &dm_event_sent); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + udqp = gdqp = NULL; + if (vap->va_mask & AT_PROJID) + prid = (xfs_prid_t)vap->va_projid; + else + prid = (xfs_prid_t)dfltprid; + + /* + * Make sure that we have allocated dquot(s) on disk. + */ + if (XFS_IS_QUOTA_ON(mp)) { + error = xfs_qm_vop_dqalloc(mp, dp, + current->fsuid, current->fsgid, + XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, + &udqp, &gdqp); + if (error) + goto std_return; + } + + ip = NULL; + dp_joined_to_trans = B_FALSE; + + tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + resblks = XFS_CREATE_SPACE_RES(mp, namelen); + /* + * Initially assume that the file does not exist and + * reserve the resources for that case. If that is not + * the case we'll drop the one we have and get a more + * appropriate transaction later. + */ + error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + dp = NULL; + goto error_return; + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + XFS_BMAP_INIT(&free_list, &first_block); + + ASSERT(ip == NULL); + + /* + * Reserve disk quota and the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, + 1, 0)) { + error = EDQUOT; + goto error_return; + } + } + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen))) + goto error_return; + rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : 0; + error = xfs_dir_ialloc(&tp, dp, + MAKEIMODE(vap->va_type,vap->va_mode), 1, + rdev, credp, prid, resblks > 0, + &ip, &committed); + if (error) { + if (error == ENOSPC) + goto error_return; + goto abort_return; + } + ITRACE(ip); + + /* + * At this point, we've gotten a newly allocated inode. + * It is locked (and joined to the transaction). + */ + + ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); + + /* + * Now we join the directory inode to the transaction. + * We do not do it earlier because xfs_dir_ialloc + * might commit the previous transaction (and release + * all the locks). + */ + + VN_HOLD(dir_vp); + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + dp_joined_to_trans = B_TRUE; + + error = XFS_DIR_CREATENAME(mp, tp, dp, name, namelen, ip->i_ino, + &first_block, &free_list, + resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0); + if (error) { + ASSERT(error != ENOSPC); + goto abort_return; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + /* + * If this is a synchronous mount, make sure that the + * create transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + dp->i_gen++; + + /* + * Attach the dquot(s) to the inodes and modify them incore. + * These ids of the inode couldn't have changed since the new + * inode has been locked ever since it was created. + */ + if (XFS_IS_QUOTA_ON(mp)) + xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp, + gdqp); + + /* + * xfs_trans_commit normally decrements the vnode ref count + * when it unlocks the inode. Since we want to return the + * vnode to the caller, we bump the vnode ref count now. + */ + IHOLD(ip); + vp = XFS_ITOV(ip); + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + goto abort_rele; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + IRELE(ip); + tp = NULL; + goto error_return; + } + + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + /* + * Propogate the fact that the vnode changed after the + * xfs_inode locks have been released. + */ + VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_TRUNCATED, 3); + + *vpp = vp; + + /* Fallthrough to std_return with error = 0 */ + +std_return: + if ((error != 0 && dm_event_sent != 0) && + DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), + DM_EVENT_POSTCREATE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTCREATE, + dir_bdp, DM_RIGHT_NULL, + vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops), + DM_RIGHT_NULL, name, NULL, + dm_di_mode, error, 0); + } + return error; + + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + + if (tp != NULL) + xfs_trans_cancel(tp, cancel_flags); + + if (!dp_joined_to_trans && (dp != NULL)) + xfs_iunlock(dp, XFS_ILOCK_EXCL); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + goto std_return; + + abort_rele: + /* + * Wait until after the current transaction is aborted to + * release the inode. This prevents recursive transactions + * and deadlocks from xfs_inactive. + */ + cancel_flags |= XFS_TRANS_ABORT; + xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); + + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + goto std_return; +} + +#ifdef DEBUG + +/* + * Some counters to see if (and how often) we are hitting some deadlock + * prevention code paths. + */ + +int xfs_rm_locks; +int xfs_rm_lock_delays; +int xfs_rm_attempts; +#endif + +/* + * The following routine will lock the inodes associated with the + * directory and the named entry in the directory. The locks are + * acquired in increasing inode number. + * + * If the entry is "..", then only the directory is locked. The + * vnode ref count will still include that from the .. entry in + * this case. + * + * The inode passed in will have been looked up using xfs_get_dir_entry(). + * Since that lookup the directory lock will have been dropped, so + * we need to validate that the inode given is still pointed to by the + * directory. We use the directory inode in memory generation count + * as an optimization to tell if a new lookup is necessary. If the + * directory no longer points to the given inode with the given name, + * then we drop the directory lock, set the entry_changed parameter to 1, + * and return. It is up to the caller to drop the reference to the inode. + * + * There is a dealock we need to worry about. If the locked directory is + * in the AIL, it might be blocking up the log. The next inode we lock + * could be already locked by another thread waiting for log space (e.g + * a permanent log reservation with a long running transaction (see + * xfs_itruncate_finish)). To solve this, we must check if the directory + * is in the ail and use lock_nowait. If we can't lock, we need to + * drop the inode lock on the directory and try again. xfs_iunlock will + * potentially push the tail if we were holding up the log. + */ +STATIC int +xfs_lock_dir_and_entry( + xfs_inode_t *dp, + struct dentry *dentry, + xfs_inode_t *ip, /* inode of entry 'name' */ + int *entry_changed) +{ + int attempts; + xfs_ino_t e_inum; + xfs_inode_t *ips[2]; + xfs_log_item_t *lp; + +#ifdef DEBUG + xfs_rm_locks++; +#endif + attempts = 0; + +again: + *entry_changed = 0; + xfs_ilock(dp, XFS_ILOCK_EXCL); + + e_inum = ip->i_ino; + + ITRACE(ip); + + /* + * We want to lock in increasing inum. Since we've already + * acquired the lock on the directory, we may need to release + * if if the inum of the entry turns out to be less. + */ + if (e_inum > dp->i_ino) { + /* + * We are already in the right order, so just + * lock on the inode of the entry. + * We need to use nowait if dp is in the AIL. + */ + + lp = (xfs_log_item_t *)dp->i_itemp; + if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { + if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { + attempts++; +#ifdef DEBUG + xfs_rm_attempts++; +#endif + + /* + * Unlock dp and try again. + * xfs_iunlock will try to push the tail + * if the inode is in the AIL. + */ + + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + if ((attempts % 5) == 0) { + delay(1); /* Don't just spin the CPU */ +#ifdef DEBUG + xfs_rm_lock_delays++; +#endif + } + goto again; + } + } else { + xfs_ilock(ip, XFS_ILOCK_EXCL); + } + } else if (e_inum < dp->i_ino) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + ips[0] = ip; + ips[1] = dp; + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); + } + /* else e_inum == dp->i_ino */ + /* This can happen if we're asked to lock /x/.. + * the entry is "..", which is also the parent directory. + */ + + return 0; +} + +#ifdef DEBUG +int xfs_locked_n; +int xfs_small_retries; +int xfs_middle_retries; +int xfs_lots_retries; +int xfs_lock_delays; +#endif + +/* + * The following routine will lock n inodes in exclusive mode. + * We assume the caller calls us with the inodes in i_ino order. + * + * We need to detect deadlock where an inode that we lock + * is in the AIL and we start waiting for another inode that is locked + * by a thread in a long running transaction (such as truncate). This can + * result in deadlock since the long running trans might need to wait + * for the inode we just locked in order to push the tail and free space + * in the log. + */ +void +xfs_lock_inodes (xfs_inode_t **ips, + int inodes, + int first_locked, + uint lock_mode) +{ + int attempts = 0, i, j, try_lock; + xfs_log_item_t *lp; + + ASSERT(ips && (inodes >= 2)); /* we need at least two */ + + if (first_locked) { + try_lock = 1; + i = 1; + } else { + try_lock = 0; + i = 0; + } + +again: + for (; i < inodes; i++) { + ASSERT(ips[i]); + + if (i && (ips[i] == ips[i-1])) /* Already locked */ + continue; + + /* + * If try_lock is not set yet, make sure all locked inodes + * are not in the AIL. + * If any are, set try_lock to be used later. + */ + + if (!try_lock) { + for (j = (i - 1); j >= 0 && !try_lock; j--) { + lp = (xfs_log_item_t *)ips[j]->i_itemp; + if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { + try_lock++; + } + } + } + + /* + * If any of the previous locks we have locked is in the AIL, + * we must TRY to get the second and subsequent locks. If + * we can't get any, we must release all we have + * and try again. + */ + + if (try_lock) { + /* try_lock must be 0 if i is 0. */ + /* + * try_lock means we have an inode locked + * that is in the AIL. + */ + ASSERT(i != 0); + if (!xfs_ilock_nowait(ips[i], lock_mode)) { + attempts++; + + /* + * Unlock all previous guys and try again. + * xfs_iunlock will try to push the tail + * if the inode is in the AIL. + */ + + for(j = i - 1; j >= 0; j--) { + + /* + * Check to see if we've already + * unlocked this one. + * Not the first one going back, + * and the inode ptr is the same. + */ + if ((j != (i - 1)) && ips[j] == + ips[j+1]) + continue; + + xfs_iunlock(ips[j], lock_mode); + } + + if ((attempts % 5) == 0) { + delay(1); /* Don't just spin the CPU */ +#ifdef DEBUG + xfs_lock_delays++; +#endif + } + i = 0; + try_lock = 0; + goto again; + } + } else { + xfs_ilock(ips[i], lock_mode); + } + } + +#ifdef DEBUG + if (attempts) { + if (attempts < 5) xfs_small_retries++; + else if (attempts < 100) xfs_middle_retries++; + else xfs_lots_retries++; + } else { + xfs_locked_n++; + } +#endif +} + +#ifdef DEBUG +#define REMOVE_DEBUG_TRACE(x) {remove_which_error_return = (x);} +int remove_which_error_return = 0; +#else /* ! DEBUG */ +#define REMOVE_DEBUG_TRACE(x) +#endif /* ! DEBUG */ + +/* + * xfs_remove + * + */ +STATIC int +xfs_remove( + bhv_desc_t *dir_bdp, + struct dentry *dentry, + cred_t *credp) +{ + vnode_t *dir_vp; + char *name = (char *) dentry->d_name.name; + xfs_inode_t *dp, *ip; + xfs_trans_t *tp = NULL; + xfs_mount_t *mp; + int error = 0; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + int entry_changed; + int dm_di_mode = 0; + int link_zero; + uint resblks; + int namelen; +/* bhv_desc_t *bdp; */ + + dir_vp = BHV_TO_VNODE(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_remove", (inst_t *)__return_address); + + dp = XFS_BHVTOI(dir_bdp); + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + namelen = dentry->d_name.len; + if (namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) { + error = dm_send_namesp_event(DM_EVENT_REMOVE, dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, 0, 0, 0); + if (error) + return error; + } + + /* From this point on, return through std_return */ + retry: + ip = NULL; + + /* + * We need to get a reference to ip before we get our log + * reservation. The reason for this is that we cannot call + * xfs_iget for an inode for which we do not have a reference + * once we've acquired a log reservation. This is because the + * inode we are trying to get might be in xfs_inactive going + * for a log reservation. Since we'll have to wait for the + * inactive code to complete before returning from xfs_iget, + * we need to make sure that we don't have log space reserved + * when we call xfs_iget. Instead we get an unlocked referece + * to the inode before getting our log reservation. + */ + error = xfs_get_dir_entry(dentry, &ip); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto std_return; + } + + dm_di_mode = ip->i_d.di_mode; + + vn_trace_entry(XFS_ITOV(ip), "xfs_remove", (inst_t *)__return_address); + + ITRACE(ip); + + if (XFS_IS_QUOTA_ON(mp)) { + ASSERT(! error); + if (XFS_NOT_DQATTACHED(mp, dp)) + error = xfs_qm_dqattach(dp, 0); + if (!error && dp != ip && XFS_NOT_DQATTACHED(mp, ip)) + error = xfs_qm_dqattach(ip, 0); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + IRELE(ip); + goto std_return; + } + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + /* + * We try to get the real space reservation first, + * allowing for directory btree deletion(s) implying + * possible bmap insert(s). If we can't get the space + * reservation then we use 0 instead, and avoid the bmap + * btree insert(s) in the directory code by, if the bmap + * insert tries to happen, instead trimming the LAST + * block from the directory. + */ + resblks = XFS_REMOVE_SPACE_RES(mp); + error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + } + if (error) { + ASSERT(error != ENOSPC); + REMOVE_DEBUG_TRACE(__LINE__); + xfs_trans_cancel(tp, 0); + IRELE(ip); + return error; + } + + error = xfs_lock_dir_and_entry(dp, dentry, ip, &entry_changed); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); + goto std_return; + } + + /* + * If the inode we found in the first pass is no longer + * the entry with the given name, then drop our transaction and + * inode reference and start over. + */ + if (entry_changed) { + xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); + goto retry; + } + + /* + * At this point, we've gotten both the directory and the entry + * inodes locked. + */ + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + if (dp != ip) { + /* + * Increment vnode ref count only in this case since + * there's an extra vnode reference in the case where + * dp == ip. + */ + IHOLD(dp); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + } + + if ((error = _MAC_XFS_IACCESS(ip, MACWRITE, credp))) { + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + + if ((ip->i_d.di_mode & IFMT) == IFDIR) { + error = XFS_ERROR(EPERM); + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + + /* + * Return error when removing . and .. + */ + if (name[0] == '.') { + if (name[1] == '\0') { + error = XFS_ERROR(EINVAL); + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + else if (name[1] == '.' && name[2] == '\0') { + error = XFS_ERROR(EEXIST); + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + } + + /* + * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. + */ + XFS_BMAP_INIT(&free_list, &first_block); + error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, ip->i_ino, + &first_block, &free_list, 0); + if (error) { + ASSERT(error != ENOENT); + REMOVE_DEBUG_TRACE(__LINE__); + goto error1; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + dp->i_gen++; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + error = xfs_droplink(tp, ip); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto error1; + } + + /* Determine if this is the last link while + * we are in the transaction. + */ + link_zero = (ip)->i_d.di_nlink==0; + + /* + * Take an extra ref on the inode so that it doesn't + * go to xfs_inactive() from within the commit. + */ + IHOLD(ip); + + /* + * If this is a synchronous mount, make sure that the + * remove transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto error_rele; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + IRELE(ip); + goto std_return; + } + + /* + * Before we drop our extra reference to the inode, purge it + * from the refcache if it is there. By waiting until afterwards + * to do the IRELE, we ensure that we won't go inactive in the + * xfs_refcache_purge_ip routine (although that would be OK). + */ + xfs_refcache_purge_ip(ip); + + vn_trace_exit(XFS_ITOV(ip), "xfs_remove", + (inst_t *)__return_address); + + /* + * Let interposed file systems know about removed links. + */ + VOP_LINK_REMOVED(XFS_ITOV(ip), dir_vp, link_zero); + + IRELE(ip); + +/* Fall through to std_return with error = 0 */ + +std_return: + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, + DM_EVENT_POSTREMOVE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTREMOVE, + dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, dm_di_mode, error, 0); + } + return error; + + error1: + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + + error_return: + xfs_trans_cancel(tp, cancel_flags); + goto std_return; + + error_rele: + /* + * In this case make sure to not release the inode until after + * the current transaction is aborted. Releasing it beforehand + * can cause us to go to xfs_inactive and start a recursive + * transaction which can easily deadlock with the current one. + */ + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + xfs_trans_cancel(tp, cancel_flags); + + /* + * Before we drop our extra reference to the inode, purge it + * from the refcache if it is there. By waiting until afterwards + * to do the IRELE, we ensure that we won't go inactive in the + * xfs_refcache_purge_ip routine (although that would be OK). + */ + xfs_refcache_purge_ip(ip); + + IRELE(ip); + + goto std_return; +} + + +/* + * xfs_link + * + */ +STATIC int +xfs_link( + bhv_desc_t *target_dir_bdp, + vnode_t *src_vp, + struct dentry *dentry, + cred_t *credp) +{ + xfs_inode_t *tdp, *sip; + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_inode_t *ips[2]; + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + vnode_t *target_dir_vp; + bhv_desc_t *src_bdp; + int resblks; + char *target_name = (char *)dentry->d_name.name; + int target_namelen; + + target_dir_vp = BHV_TO_VNODE(target_dir_bdp); + + vn_trace_entry(target_dir_vp, "xfs_link", (inst_t *)__return_address); + + target_namelen = dentry->d_name.len; + if (target_namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + + vn_trace_entry(src_vp, "xfs_link", (inst_t *)__return_address); + + if (src_vp->v_type == VDIR) { + return XFS_ERROR(EPERM); + } + + /* + * For now, manually find the XFS behavior descriptor for + * the source vnode. If it doesn't exist then something + * is wrong and we should just return an error. + * Eventually we need to figure out how link is going to + * work in the face of stacked vnodes. + */ + src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops); + if (src_bdp == NULL) { + return XFS_ERROR(EXDEV); + } + sip = XFS_BHVTOI(src_bdp); + tdp = XFS_BHVTOI(target_dir_bdp); + mp = tdp->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + if (DM_EVENT_ENABLED(src_vp->v_vfsp, tdp, DM_EVENT_LINK)) { + error = dm_send_namesp_event(DM_EVENT_LINK, + target_dir_bdp, DM_RIGHT_NULL, + src_bdp, DM_RIGHT_NULL, + target_name, NULL, 0, 0, 0); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + if (XFS_IS_QUOTA_ON(mp)) { + error = 0; + if (XFS_NOT_DQATTACHED(mp, sip)) + error = xfs_qm_dqattach(sip, 0); + if (!error && sip != tdp && XFS_NOT_DQATTACHED(mp, tdp)) + error = xfs_qm_dqattach(tdp, 0); + if (error) + goto std_return; + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_LINK); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + resblks = XFS_LINK_SPACE_RES(mp, target_namelen); + error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + goto error_return; + } + + if (sip->i_ino < tdp->i_ino) { + ips[0] = sip; + ips[1] = tdp; + } else { + ips[0] = tdp; + ips[1] = sip; + } + + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); + + /* + * Increment vnode ref counts since xfs_trans_commit & + * xfs_trans_cancel will both unlock the inodes and + * decrement the associated ref counts. + */ + VN_HOLD(src_vp); + VN_HOLD(target_dir_vp); + xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL); + + /* + * If the source has too many links, we can't make any more to it. + */ + if (sip->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + goto error_return; + } + + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name, + target_namelen))) + goto error_return; + + XFS_BMAP_INIT(&free_list, &first_block); + + error = XFS_DIR_CREATENAME(mp, tp, tdp, target_name, target_namelen, + sip->i_ino, &first_block, &free_list, + resblks); + if (error) + goto abort_return; + xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + tdp->i_gen++; + xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); + + error = xfs_bumplink(tp, sip); + if (error) { + goto abort_return; + } + + /* + * If this is a synchronous mount, make sure that the + * link transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish (&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + goto abort_return; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + goto std_return; + } + + /* Fall through to std_return with error = 0. */ +std_return: + if (DM_EVENT_ENABLED(src_vp->v_vfsp, sip, + DM_EVENT_POSTLINK)) { + (void) dm_send_namesp_event(DM_EVENT_POSTLINK, + target_dir_bdp, DM_RIGHT_NULL, + src_bdp, DM_RIGHT_NULL, + target_name, NULL, 0, error, 0); + } + return error; + + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + xfs_trans_cancel(tp, cancel_flags); + + goto std_return; +} + + + + +/* + * xfs_mkdir + * + */ +STATIC int +xfs_mkdir( + bhv_desc_t *dir_bdp, + struct dentry *dentry, + vattr_t *vap, + vnode_t **vpp, + cred_t *credp) +{ + char *dir_name = (char *)dentry->d_name.name; + xfs_inode_t *dp; + xfs_inode_t *cdp; /* inode of created dir */ + vnode_t *cvp; /* vnode of created dir */ + xfs_trans_t *tp; + dev_t rdev; + mode_t mode; + xfs_mount_t *mp; + int cancel_flags; + int error; + int committed; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + vnode_t *dir_vp; + boolean_t dp_joined_to_trans; + boolean_t created = B_FALSE; + int dm_event_sent = 0; + xfs_prid_t prid; + struct xfs_dquot *udqp, *gdqp; + uint resblks; + int dm_di_mode; + int dir_namelen; + + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + dir_namelen = dentry->d_name.len; + if (dir_namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + + tp = NULL; + dp_joined_to_trans = B_FALSE; + dm_di_mode = vap->va_mode|VTTOIF(vap->va_type); + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) { + error = xfs_dm_send_create_event(dir_bdp, dir_name, + dm_di_mode, &dm_event_sent); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + vn_trace_entry(dir_vp, "xfs_mkdir", (inst_t *)__return_address); + + mp = dp->i_mount; + udqp = gdqp = NULL; + if (vap->va_mask & AT_PROJID) + prid = (xfs_prid_t)vap->va_projid; + else + prid = (xfs_prid_t)dfltprid; + + /* + * Make sure that we have allocated dquot(s) on disk. + */ + if (XFS_IS_QUOTA_ON(mp)) { + error = xfs_qm_vop_dqalloc(mp, dp, + current->fsuid, current->fsgid, + XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, + &udqp, &gdqp); + if (error) + goto std_return; + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + resblks = XFS_MKDIR_SPACE_RES(mp, dir_namelen); + error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_MKDIR_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + dp = NULL; + goto error_return; + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * Check for directory link count overflow. + */ + if (dp->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + goto error_return; + } + + /* + * Reserve disk quota and the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) { + error = XFS_ERROR(EDQUOT); + goto error_return; + } + } + + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, dp, dir_name, dir_namelen))) + goto error_return; + /* + * create the directory inode. + */ + rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : 0; + mode = IFDIR | (vap->va_mode & ~IFMT); + error = xfs_dir_ialloc(&tp, dp, mode, 2, rdev, credp, prid, resblks > 0, + &cdp, NULL); + if (error) { + if (error == ENOSPC) + goto error_return; + goto abort_return; + } + ITRACE(cdp); + + /* + * Now we add the directory inode to the transaction. + * We waited until now since xfs_dir_ialloc might start + * a new transaction. Had we joined the transaction + * earlier, the locks might have gotten released. + */ + VN_HOLD(dir_vp); + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + dp_joined_to_trans = B_TRUE; + + XFS_BMAP_INIT(&free_list, &first_block); + + error = XFS_DIR_CREATENAME(mp, tp, dp, dir_name, dir_namelen, + cdp->i_ino, &first_block, &free_list, + resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0); + if (error) { + ASSERT(error != ENOSPC); + goto error1; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Bump the in memory version number of the parent directory + * so that other processes accessing it will recognize that + * the directory has changed. + */ + dp->i_gen++; + + error = XFS_DIR_INIT(mp, tp, cdp, dp); + if (error) { + goto error2; + } + + cdp->i_gen = 1; + error = xfs_bumplink(tp, dp); + if (error) { + goto error2; + } + + cvp = XFS_ITOV(cdp); + + created = B_TRUE; + + *vpp = cvp; + IHOLD(cdp); + + /* + * Attach the dquots to the new inode and modify the icount incore. + */ + if (XFS_IS_QUOTA_ON(mp)) { + xfs_qm_vop_dqattach_and_dqmod_newinode(tp, cdp, udqp, gdqp); + } + + /* + * If this is a synchronous mount, make sure that the + * mkdir transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + IRELE(cdp); + goto error2; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (error) { + IRELE(cdp); + } + + /* Fall through to std_return with error = 0 or errno from + * xfs_trans_commit. */ + +std_return: + if ( (created || (error != 0 && dm_event_sent != 0)) && + DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), + DM_EVENT_POSTCREATE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTCREATE, + dir_bdp, DM_RIGHT_NULL, + created ? XFS_ITOBHV(cdp):NULL, + DM_RIGHT_NULL, + dir_name, NULL, + dm_di_mode, error, 0); + } + return error; + + error2: + error1: + xfs_bmap_cancel(&free_list); + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + error_return: + xfs_trans_cancel(tp, cancel_flags); + + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (!dp_joined_to_trans && (dp != NULL)) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + } + + goto std_return; +} + + +/* + * xfs_rmdir + * + */ +STATIC int +xfs_rmdir( + bhv_desc_t *dir_bdp, + struct dentry *dentry, + cred_t *credp) +{ + char *name = (char *)dentry->d_name.name; + xfs_inode_t *dp; + xfs_inode_t *cdp; /* child directory */ + xfs_trans_t *tp; + xfs_mount_t *mp; +/* bhv_desc_t *bdp;*/ + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + int entry_changed; + vnode_t *dir_vp; + int dm_di_mode = 0; + int last_cdp_link; + int namelen; + uint resblks; + + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_rmdir", (inst_t *)__return_address); + + if (XFS_FORCED_SHUTDOWN(XFS_BHVTOI(dir_bdp)->i_mount)) + return XFS_ERROR(EIO); + namelen = dentry->d_name.len; + if (namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) { + error = dm_send_namesp_event(DM_EVENT_REMOVE, + dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, 0, 0, 0); + if (error) + return XFS_ERROR(error); + } + + /* Return through std_return after this point. */ + + retry: + cdp = NULL; + + /* + * We need to get a reference to cdp before we get our log + * reservation. The reason for this is that we cannot call + * xfs_iget for an inode for which we do not have a reference + * once we've acquired a log reservation. This is because the + * inode we are trying to get might be in xfs_inactive going + * for a log reservation. Since we'll have to wait for the + * inactive code to complete before returning from xfs_iget, + * we need to make sure that we don't have log space reserved + * when we call xfs_iget. Instead we get an unlocked referece + * to the inode before getting our log reservation. + */ + error = xfs_get_dir_entry(dentry, &cdp); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto std_return; + } + mp = dp->i_mount; + dm_di_mode = cdp->i_d.di_mode; + + /* + * Get the dquots for the inodes. + */ + if (XFS_IS_QUOTA_ON(mp)) { + ASSERT(! error); + if (XFS_NOT_DQATTACHED(mp, dp)) + error = xfs_qm_dqattach(dp, 0); + if (!error && dp != cdp && XFS_NOT_DQATTACHED(mp, cdp)) + error = xfs_qm_dqattach(cdp, 0); + if (error) { + IRELE(cdp); + REMOVE_DEBUG_TRACE(__LINE__); + goto std_return; + } + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + /* + * We try to get the real space reservation first, + * allowing for directory btree deletion(s) implying + * possible bmap insert(s). If we can't get the space + * reservation then we use 0 instead, and avoid the bmap + * btree insert(s) in the directory code by, if the bmap + * insert tries to happen, instead trimming the LAST + * block from the directory. + */ + resblks = XFS_REMOVE_SPACE_RES(mp); + error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); + } + if (error) { + ASSERT(error != ENOSPC); + cancel_flags = 0; + IRELE(cdp); + goto error_return; + } + XFS_BMAP_INIT(&free_list, &first_block); + + /* + * Now lock the child directory inode and the parent directory + * inode in the proper order. This will take care of validating + * that the directory entry for the child directory inode has + * not changed while we were obtaining a log reservation. + */ + error = xfs_lock_dir_and_entry(dp, dentry, cdp, &entry_changed); + if (error) { + xfs_trans_cancel(tp, cancel_flags); + IRELE(cdp); + goto std_return; + } + + /* + * If the inode we found in the first pass is no longer + * the entry with the given name, then drop our transaction and + * inode reference and start over. + */ + if (entry_changed) { + xfs_trans_cancel(tp, cancel_flags); + IRELE(cdp); + goto retry; + } + + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + if (dp != cdp) { + /* + * Only increment the parent directory vnode count if + * we didn't bump it in looking up cdp. The only time + * we don't bump it is when we're looking up ".". + */ + VN_HOLD(dir_vp); + } + + ITRACE(cdp); + xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); + + if ((error = _MAC_XFS_IACCESS(cdp, MACWRITE, credp))) { + goto error_return; + } + + ASSERT(cdp->i_d.di_nlink >= 2); + if (cdp->i_d.di_nlink != 2) { + error = XFS_ERROR(ENOTEMPTY); + goto error_return; + } + if (!XFS_DIR_ISEMPTY(mp, cdp)) { + error = XFS_ERROR(ENOTEMPTY); + goto error_return; + } + + error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, cdp->i_ino, + &first_block, &free_list, resblks); + if (error) { + goto error1; + } + + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Bump the in memory generation count on the parent + * directory so that other can know that it has changed. + */ + dp->i_gen++; + + /* + * Drop the link from cdp's "..". + */ + error = xfs_droplink(tp, dp); + if (error) { + goto error1; + } + + /* + * Drop the link from dp to cdp. + */ + error = xfs_droplink(tp, cdp); + if (error) { + goto error1; + } + + /* + * Drop the "." link from cdp to self. + */ + error = xfs_droplink(tp, cdp); + if (error) { + goto error1; + } + + /* Determine these before committing transaction */ + last_cdp_link = (cdp)->i_d.di_nlink==0; + + /* + * Take an extra ref on the child vnode so that it + * does not go to xfs_inactive() from within the commit. + */ + IHOLD(cdp); + + /* + * If this is a synchronous mount, make sure that the + * rmdir transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish (&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + IRELE(cdp); + goto std_return; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + IRELE(cdp); + goto std_return; + } + + + /* + * Let interposed file systems know about removed links. + */ + VOP_LINK_REMOVED(XFS_ITOV(cdp), dir_vp, last_cdp_link); + + IRELE(cdp); + + /* Fall through to std_return with error = 0 or the errno + * from xfs_trans_commit. */ +std_return: + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, + DM_EVENT_POSTREMOVE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTREMOVE, + dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, dm_di_mode, + error, 0); + } + return error; + + error1: + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + error_return: + xfs_trans_cancel(tp, cancel_flags); + goto std_return; +} + + + +/* + * xfs_readdir + * + * Read dp's entries starting at uiop->uio_offset and translate them into + * bufsize bytes worth of struct dirents starting at bufbase. + */ +/*ARGSUSED*/ +STATIC int +xfs_readdir( + bhv_desc_t *dir_bdp, + uio_t *uiop, + cred_t *credp, + int *eofp) +{ + xfs_inode_t *dp; + xfs_trans_t *tp = NULL; + int error = 0; + uint lock_mode; + xfs_off_t start_offset; + + vn_trace_entry(BHV_TO_VNODE(dir_bdp), "xfs_readdir", + (inst_t *)__return_address); + dp = XFS_BHVTOI(dir_bdp); + + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) { + return XFS_ERROR(EIO); + } + + lock_mode = xfs_ilock_map_shared(dp); + + if ((dp->i_d.di_mode & IFMT) != IFDIR) { + xfs_iunlock_map_shared(dp, lock_mode); + return XFS_ERROR(ENOTDIR); + } + + start_offset = uiop->uio_offset; + error = XFS_DIR_GETDENTS(dp->i_mount, tp, dp, uiop, eofp); + if (start_offset != uiop->uio_offset) { + xfs_ichgtime(dp, XFS_ICHGTIME_ACC); + } + + xfs_iunlock_map_shared(dp, lock_mode); + + return error; +} + +/* + * xfs_symlink + * + */ +STATIC int +xfs_symlink( + bhv_desc_t *dir_bdp, + struct dentry *dentry, + vattr_t *vap, + char *target_path, + vnode_t **vpp, + cred_t *credp) +{ + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_inode_t *dp; + xfs_inode_t *ip; + int error; + int pathlen; + dev_t rdev; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + boolean_t dp_joined_to_trans; + vnode_t *dir_vp; + uint cancel_flags; + int committed; + xfs_fileoff_t first_fsb; + xfs_filblks_t fs_blocks; + int nmaps; + xfs_bmbt_irec_t mval[SYMLINK_MAPS]; + xfs_daddr_t d; + char *cur_chunk; + int byte_cnt; + int n; + xfs_buf_t *bp; + xfs_prid_t prid; + struct xfs_dquot *udqp, *gdqp; + uint resblks; + char *link_name = (char *)dentry->d_name.name; + int link_namelen; + + *vpp = NULL; + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + dp_joined_to_trans = B_FALSE; + error = 0; + ip = NULL; + tp = NULL; + + vn_trace_entry(dir_vp, "xfs_symlink", (inst_t *)__return_address); + + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + link_namelen = dentry->d_name.len; + if (link_namelen >= MAXNAMELEN) + return XFS_ERROR(ENAMETOOLONG); + /* + * Check component lengths of the target path name. + */ + pathlen = strlen(target_path); + if (pathlen >= MAXPATHLEN) /* total string too long */ + return XFS_ERROR(ENAMETOOLONG); + if (pathlen >= MAXNAMELEN) { /* is any component too long? */ + int len, total; + char *path; + + for(total = 0, path = target_path; total < pathlen;) { + /* + * Skip any slashes. + */ + while(*path == '/') { + total++; + path++; + } + + /* + * Count up to the next slash or end of path. + * Error out if the component is bigger than MAXNAMELEN. + */ + for(len = 0; *path != '/' && total < pathlen;total++, path++) { + if (++len >= MAXNAMELEN) { + error = ENAMETOOLONG; + return error; + } + } + } + } + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_SYMLINK)) { + error = dm_send_namesp_event(DM_EVENT_SYMLINK, dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + link_name, target_path, + 0, 0, 0); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + udqp = gdqp = NULL; + if (vap->va_mask & AT_PROJID) + prid = (xfs_prid_t)vap->va_projid; + else + prid = (xfs_prid_t)dfltprid; + + /* + * Make sure that we have allocated dquot(s) on disk. + */ + if (XFS_IS_QUOTA_ON(mp)) { + error = xfs_qm_vop_dqalloc(mp, dp, + current->fsuid, current->fsgid, + XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, + &udqp, &gdqp); + if (error) + goto std_return; + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + /* + * The symlink will fit into the inode data fork? + * There can't be any attributes so we get the whole variable part. + */ + if (pathlen <= XFS_LITINO(mp)) + fs_blocks = 0; + else + fs_blocks = XFS_B_TO_FSB(mp, pathlen); + resblks = XFS_SYMLINK_SPACE_RES(mp, link_namelen, fs_blocks); + error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); + if (error == ENOSPC && fs_blocks == 0) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + dp = NULL; + goto error_return; + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * Reserve disk quota : blocks and inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) { + error = XFS_ERROR(EDQUOT); + goto error_return; + } + } + + /* + * Check for ability to enter directory entry, if no space reserved. + */ + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, dp, link_name, link_namelen))) + goto error_return; + /* + * Initialize the bmap freelist prior to calling either + * bmapi or the directory create code. + */ + XFS_BMAP_INIT(&free_list, &first_block); + + /* + * Allocate an inode for the symlink. + */ + rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : 0; + + error = xfs_dir_ialloc(&tp, dp, IFLNK | (vap->va_mode&~IFMT), + 1, rdev, credp, prid, resblks > 0, &ip, NULL); + if (error) { + if (error == ENOSPC) + goto error_return; + goto error1; + } + ITRACE(ip); + + VN_HOLD(dir_vp); + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + dp_joined_to_trans = B_TRUE; + + /* + * Also attach the dquot(s) to it, if applicable. + */ + if (XFS_IS_QUOTA_ON(mp)) { + xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp, gdqp); + } + + if (resblks) + resblks -= XFS_IALLOC_SPACE_RES(mp); + /* + * If the symlink will fit into the inode, write it inline. + */ + if (pathlen <= XFS_IFORK_DSIZE(ip)) { + xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK); + bcopy(target_path, ip->i_df.if_u1.if_data, pathlen); + ip->i_d.di_size = pathlen; + + /* + * The inode was initially created in extent format. + */ + ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); + ip->i_df.if_flags |= XFS_IFINLINE; + + ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); + + } else { + first_fsb = 0; + nmaps = SYMLINK_MAPS; + + error = xfs_bmapi(tp, ip, first_fsb, fs_blocks, + XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, + &first_block, resblks, mval, &nmaps, + &free_list); + if (error) { + goto error1; + } + + if (resblks) + resblks -= fs_blocks; + ip->i_d.di_size = pathlen; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + cur_chunk = target_path; + for (n = 0; n < nmaps; n++) { + d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); + byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, + BTOBB(byte_cnt), 0); + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + if (pathlen < byte_cnt) { + byte_cnt = pathlen; + } + pathlen -= byte_cnt; + + bcopy(cur_chunk, XFS_BUF_PTR(bp), byte_cnt); + cur_chunk += byte_cnt; + + xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1); + } + } + + /* + * Create the directory entry for the symlink. + */ + error = XFS_DIR_CREATENAME(mp, tp, dp, link_name, link_namelen, + ip->i_ino, &first_block, &free_list, resblks); + if (error) { + goto error1; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + /* + * Bump the in memory version number of the parent directory + * so that other processes accessing it will recognize that + * the directory has changed. + */ + dp->i_gen++; + + /* + * If this is a synchronous mount, make sure that the + * symlink transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + /* + * xfs_trans_commit normally decrements the vnode ref count + * when it unlocks the inode. Since we want to return the + * vnode to the caller, we bump the vnode ref count now. + */ + IHOLD(ip); + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + goto error2; + } + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + /* Fall through to std_return with error = 0 or errno from + * xfs_trans_commit */ +std_return: + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), + DM_EVENT_POSTSYMLINK)) { + (void) dm_send_namesp_event(DM_EVENT_POSTSYMLINK, + dir_bdp, DM_RIGHT_NULL, + error? NULL:XFS_ITOBHV(ip), + DM_RIGHT_NULL, + link_name, target_path, + 0, error, 0); + } + + if (!error) { + vnode_t *vp; + + ASSERT(ip); + vp = XFS_ITOV(ip); + *vpp = vp; + } + return error; + + error2: + IRELE(ip); + error1: + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + error_return: + xfs_trans_cancel(tp, cancel_flags); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (!dp_joined_to_trans && (dp != NULL)) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + } + + goto std_return; +} + + +/* + * xfs_fid2 + * + * A fid routine that takes a pointer to a previously allocated + * fid structure (like xfs_fast_fid) but uses a 64 bit inode number. + */ +STATIC int +xfs_fid2( + bhv_desc_t *bdp, + fid_t *fidp) +{ + xfs_inode_t *ip; + xfs_fid2_t *xfid; + + vn_trace_entry(BHV_TO_VNODE(bdp), "xfs_fid2", + (inst_t *)__return_address); + ASSERT(sizeof(fid_t) >= sizeof(xfs_fid2_t)); + + xfid = (xfs_fid2_t *)fidp; + ip = XFS_BHVTOI(bdp); + xfid->fid_len = sizeof(xfs_fid2_t) - sizeof(xfid->fid_len); + xfid->fid_pad = 0; + /* + * use bcopy because the inode is a long long and there's no + * assurance that xfid->fid_ino is properly aligned. + */ + bcopy(&ip->i_ino, &xfid->fid_ino, sizeof xfid->fid_ino); + xfid->fid_gen = ip->i_d.di_gen; + + return 0; +} + + +/* + * xfs_rwlock + */ +int +xfs_rwlock( + bhv_desc_t *bdp, + vrwlock_t locktype) +{ + xfs_inode_t *ip; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + if (vp->v_type == VDIR) + return 1; + ip = XFS_BHVTOI(bdp); + if (locktype == VRWLOCK_WRITE) { + xfs_ilock(ip, XFS_IOLOCK_EXCL); + } else if (locktype == VRWLOCK_TRY_READ) { + return (xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)); + } else if (locktype == VRWLOCK_TRY_WRITE) { + return (xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)); + } else { + ASSERT((locktype == VRWLOCK_READ) || + (locktype == VRWLOCK_WRITE_DIRECT)); + xfs_ilock(ip, XFS_IOLOCK_SHARED); + } + + return 1; +} + + +/* + * xfs_rwunlock + */ +void +xfs_rwunlock( + bhv_desc_t *bdp, + vrwlock_t locktype) +{ + xfs_inode_t *ip; + xfs_inode_t *release_ip; + vnode_t *vp; + int error; + + vp = BHV_TO_VNODE(bdp); + if (vp->v_type == VDIR) + return; + ip = XFS_BHVTOI(bdp); + if (locktype == VRWLOCK_WRITE) { + /* + * In the write case, we may have added a new entry to + * the reference cache. This might store a pointer to + * an inode to be released in this inode. If it is there, + * clear the pointer and release the inode after unlocking + * this one. + */ + release_ip = ip->i_release; + ip->i_release = NULL; + xfs_iunlock (ip, XFS_IOLOCK_EXCL); + + if (release_ip != NULL) { + VOP_RELEASE(XFS_ITOV(release_ip), error); + VN_RELE(XFS_ITOV(release_ip)); + } + } else { + ASSERT((locktype == VRWLOCK_READ) || + (locktype == VRWLOCK_WRITE_DIRECT)); + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + } + return; +} + +STATIC int +xfs_inode_flush(bhv_desc_t *bdp, + int flags) +{ + xfs_inode_t *ip; + xfs_dinode_t *dip; + xfs_mount_t *mp; + xfs_buf_t *bp; + int error = 0; + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + /* Bypass inodes which have already been cleaned by + * the inode flush clustering code inside xfs_iflush + */ + if ((ip->i_update_core == 0) && + ((ip->i_itemp == NULL) || + !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL))) + return 0; + + if (flags & FLUSH_LOG) { + xfs_inode_log_item_t *iip = ip->i_itemp; + + if (iip && iip->ili_last_lsn) { + xlog_t *log = mp->m_log; + xfs_lsn_t sync_lsn; + int s, log_flags = XFS_LOG_FORCE; + + s = GRANT_LOCK(log); + sync_lsn = log->l_last_sync_lsn; + GRANT_UNLOCK(log, s); + + if ((XFS_LSN_CMP(iip->ili_last_lsn, sync_lsn) <= 0)) + return 0; + + if (flags & FLUSH_SYNC) + log_flags |= XFS_LOG_SYNC; + return xfs_log_force(mp, iip->ili_last_lsn, + log_flags); + } + } + + /* We make this non-blocking if the inode is contended, + * return EAGAIN to indicate to the caller that they + * did not succeed. This prevents the flush path from + * blocking on inodes inside another operation right + * now, they get caught later by xfs_sync. + */ + if (flags & FLUSH_INODE) { + if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) { + if ((xfs_ipincount(ip) == 0) && xfs_iflock_nowait(ip)) { + int flush_flags; + +#if 0 + /* not turning this on until some + * performance analysis is done + */ + if (flags & FLUSH_SYNC) + flush_flags = XFS_IFLUSH_SYNC; + else +#endif + flush_flags = XFS_IFLUSH_DELWRI; + + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0); + if (error) + goto eagain; + xfs_buf_relse(bp); + + if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED) == 0) + goto eagain; + + if ((xfs_ipincount(ip) == 0) && + xfs_iflock_nowait(ip)) + error = xfs_iflush(ip, flush_flags); + } else { + error = EAGAIN; + } + xfs_iunlock(ip, XFS_ILOCK_SHARED); + } else { +eagain: + error = EAGAIN; + } + } + + return error; +} + + +int +xfs_set_dmattrs ( + bhv_desc_t *bdp, + u_int evmask, + u_int16_t state, + cred_t *credp) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + + ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask = evmask; + ip->i_iocore.io_dmstate = ip->i_d.di_dmstate = state; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + IHOLD(ip); + error = xfs_trans_commit(tp, 0, NULL); + + return error; +} + + +/* + * xfs_reclaim + */ +STATIC int +xfs_reclaim( + bhv_desc_t *bdp) +{ + xfs_inode_t *ip; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_reclaim", (inst_t *)__return_address); + + ASSERT(!VN_MAPPED(vp)); + ip = XFS_BHVTOI(bdp); + + if ((ip->i_d.di_mode & IFMT) == IFREG) { + if (ip->i_d.di_size > 0) { + /* + * Flush and invalidate any data left around that is + * a part of this file. + * + * Get the inode's i/o lock so that buffers are pushed + * out while holding the proper lock. We can't hold + * the inode lock here since flushing out buffers may + * cause us to try to get the lock in xfs_strategy(). + * + * We don't have to call remapf() here, because there + * cannot be any mapped file references to this vnode + * since it is being reclaimed. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + + /* + * If we hit an IO error, we need to make sure that the + * buffer and page caches of file data for + * the file are tossed away. We don't want to use + * VOP_FLUSHINVAL_PAGES here because we don't want dirty + * pages to stay attached to the vnode, but be + * marked P_BAD. pdflush/vnode_pagebad + * hates that. + */ + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_NONE); + } else { + VOP_TOSS_PAGES(vp, 0, -1, FI_NONE); + } + + ASSERT(VN_CACHED(vp) == 0); + ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || + ip->i_delayed_blks == 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + } else if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { + /* + * di_size field may not be quite accurate if we're + * shutting down. + */ + VOP_TOSS_PAGES(vp, 0, -1, FI_NONE); + ASSERT(VN_CACHED(vp) == 0); + } + } + + /* If we have nothing to flush with this inode then complete the + * teardown now, otherwise break the link between the xfs inode + * and the linux inode and clean up the xfs inode later. This + * avoids flushing the inode to disk during the delete operation + * itself. + */ + if (!ip->i_update_core && (ip->i_itemp == NULL)) { + xfs_ilock(ip, XFS_ILOCK_EXCL); + return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); + } else { + xfs_mount_t *mp = ip->i_mount; + + /* Protect sync from us */ + XFS_MOUNT_ILOCK(mp); + vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); + XFS_MOUNT_IUNLOCK(mp); + } + return 0; +} + +int +xfs_finish_reclaim( + xfs_inode_t *ip, + int locked, + int sync_mode) +{ + xfs_ihash_t *ih = ip->i_hash; + int error; + + if (!locked) + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* The hash lock here protects a thread in xfs_iget_core from + * racing with us on linking the inode back with a vnode. + * Once we have the XFS_IRECLAIM flag set it will not touch + * us. + */ + write_lock(&ih->ih_lock); + if (ip->i_flags & XFS_IRECLAIM || (!locked && XFS_ITOV_NULL(ip))) { + write_unlock(&ih->ih_lock); + if (!locked) + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return(1); + } + ip->i_flags |= XFS_IRECLAIM; + write_unlock(&ih->ih_lock); + + /* + * If the inode is still dirty, then flush it out. If the inode + * is not in the AIL, then it will be OK to flush it delwri as + * long as xfs_iflush() does not keep any references to the inode. + * We leave that decision up to xfs_iflush() since it has the + * knowledge of whether it's OK to simply do a delwri flush of + * the inode or whether we need to wait until the inode is + * pulled from the AIL. + * We get the flush lock regardless, though, just to make sure + * we don't free it while it is being flushed. + */ + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + if (!locked) { + xfs_iflock(ip); + } + + if (ip->i_update_core || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0))) { + error = xfs_iflush(ip, sync_mode); + /* + * If we hit an error, typically because of filesystem + * shutdown, we don't need to let vn_reclaim to know + * because we're gonna reclaim the inode anyway. + */ + if (error) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_ireclaim(ip); + return (0); + } + xfs_iflock(ip); /* synchronize with xfs_iflush_done */ + } + + ASSERT(ip->i_update_core == 0); + ASSERT(ip->i_itemp == NULL || + ip->i_itemp->ili_format.ilf_fields == 0); + } + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + xfs_ireclaim(ip); + return 0; +} + +int +xfs_finish_reclaim_all(xfs_mount_t *mp) +{ + int purged; + xfs_inode_t *ip; + vnode_t *vp; + int done = 0; + + while (!done) { + purged = 0; + XFS_MOUNT_ILOCK(mp); + ip = mp->m_inodes; + if (ip == NULL) { + break; + } + do { + /* Make sure we skip markers inserted by sync */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + /* + * It's up to our caller to purge the root + * and quota vnodes later. + */ + vp = XFS_ITOV_NULL(ip); + + if (!vp) { + XFS_MOUNT_IUNLOCK(mp); + xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); + purged = 1; + break; + } + } while (ip != mp->m_inodes); + + done = !purged; + } + + XFS_MOUNT_IUNLOCK(mp); + return 0; +} + +/* + * xfs_alloc_file_space() + * This routine allocates disk space for the given file. + * + * If alloc_type == 0, this request is for an ALLOCSP type + * request which will change the file size. In this case, no + * DMAPI event will be generated by the call. A TRUNCATE event + * will be generated later by xfs_setattr. + * + * If alloc_type != 0, this request is for a RESVSP type + * request, and a DMAPI DM_EVENT_WRITE will be generated if the + * lower block boundary byte address is less than the file's + * length. + * + * RETURNS: + * 0 on success + * errno on error + * + */ +int +xfs_alloc_file_space( + xfs_inode_t *ip, + xfs_off_t offset, + xfs_off_t len, + int alloc_type, + int attr_flags) +{ + xfs_filblks_t allocated_fsb; + xfs_filblks_t allocatesize_fsb; + int committed; + xfs_off_t count; + xfs_filblks_t datablocks; + int error; + xfs_fsblock_t firstfsb; + xfs_bmap_free_t free_list; + xfs_bmbt_irec_t *imapp; + xfs_bmbt_irec_t imaps[1]; + xfs_mount_t *mp; + int numrtextents; + int reccount; + uint resblks; + int rt; + int rtextsize; + xfs_fileoff_t startoffset_fsb; + xfs_trans_t *tp; + int xfs_bmapi_flags; + + vn_trace_entry(XFS_ITOV(ip), "xfs_alloc_file_space", + (inst_t *)__return_address); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + /* + * determine if this is a realtime file + */ + if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) { + if (ip->i_d.di_extsize) + rtextsize = ip->i_d.di_extsize; + else + rtextsize = mp->m_sb.sb_rextsize; + } else + rtextsize = 0; + + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return error; + } + } + + if (len <= 0) + return XFS_ERROR(EINVAL); + + count = len; + error = 0; + imapp = &imaps[0]; + reccount = 1; + xfs_bmapi_flags = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0); + startoffset_fsb = XFS_B_TO_FSBT(mp, offset); + allocatesize_fsb = XFS_B_TO_FSB(mp, count); + + /* Generate a DMAPI event if needed. */ + if (alloc_type != 0 && offset < ip->i_d.di_size && + (attr_flags&ATTR_DMI) == 0 && + DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { + xfs_off_t end_dmi_offset; + + end_dmi_offset = offset+len; + if (end_dmi_offset > ip->i_d.di_size) + end_dmi_offset = ip->i_d.di_size; + error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip), + offset, end_dmi_offset - offset, + 0, NULL); + if (error) + return(error); + } + + /* + * allocate file space until done or until there is an error + */ +retry: + while (allocatesize_fsb && !error) { + /* + * determine if reserving space on + * the data or realtime partition. + */ + if (rt) { + xfs_fileoff_t s, e; + + s = startoffset_fsb; + do_div(s, rtextsize); + s *= rtextsize; + e = roundup_64(startoffset_fsb + allocatesize_fsb, + rtextsize); + numrtextents = (int)(e - s) / mp->m_sb.sb_rextsize; + datablocks = 0; + } else { + datablocks = allocatesize_fsb; + numrtextents = 0; + } + + /* + * allocate and setup the transaction + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); + resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks); + error = xfs_trans_reserve(tp, + resblks, + XFS_WRITE_LOG_RES(mp), + numrtextents, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + + /* + * check for running out of space + */ + if (error) { + /* + * Free the transaction structure. + */ + ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + break; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, + ip->i_udquot, + ip->i_gdquot, + resblks, 0, 0)) { + error = XFS_ERROR(EDQUOT); + goto error1; + } + } + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * issue the bmapi() call to allocate the blocks + */ + XFS_BMAP_INIT(&free_list, &firstfsb); + error = xfs_bmapi(tp, ip, startoffset_fsb, + allocatesize_fsb, xfs_bmapi_flags, + &firstfsb, 0, imapp, &reccount, + &free_list); + if (error) { + goto error0; + } + + /* + * complete the transaction + */ + error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + if (error) { + goto error0; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + if (error) { + break; + } + + allocated_fsb = imapp->br_blockcount; + + if (reccount == 0) { + error = XFS_ERROR(ENOSPC); + break; + } + + startoffset_fsb += allocated_fsb; + allocatesize_fsb -= allocated_fsb; + } +dmapi_enospc_check: + if (error == ENOSPC && (attr_flags&ATTR_DMI) == 0 && + DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_NOSPACE)) { + + error = dm_send_namesp_event(DM_EVENT_NOSPACE, + XFS_ITOBHV(ip), DM_RIGHT_NULL, + XFS_ITOBHV(ip), DM_RIGHT_NULL, + NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */ + if (error == 0) + goto retry; /* Maybe DMAPI app. has made space */ + /* else fall through with error = xfs_dm_send_data_event result. */ + } + + return error; + + error0: + xfs_bmap_cancel(&free_list); + error1: + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + goto dmapi_enospc_check; +} + +/* + * Zero file bytes between startoff and endoff inclusive. + * The iolock is held exclusive and no blocks are buffered. + */ +STATIC int +xfs_zero_remaining_bytes( + xfs_inode_t *ip, + xfs_off_t startoff, + xfs_off_t endoff) +{ + xfs_buf_t *bp; + int error=0; + xfs_bmbt_irec_t imap; + xfs_off_t lastoffset; + xfs_mount_t *mp; + int nimap; + xfs_off_t offset; + xfs_fileoff_t offset_fsb; + + mp = ip->i_mount; + bp = XFS_ngetrbuf(mp->m_sb.sb_blocksize,mp); + ASSERT(!XFS_BUF_GETERROR(bp)); + + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + XFS_BUF_SET_TARGET(bp, mp->m_rtdev_targp); + } else { + XFS_BUF_SET_TARGET(bp, mp->m_ddev_targp); + } + + for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { + offset_fsb = XFS_B_TO_FSBT(mp, offset); + nimap = 1; + error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, NULL, 0, &imap, + &nimap, NULL); + if (error || nimap < 1) + break; + ASSERT(imap.br_blockcount >= 1); + ASSERT(imap.br_startoff == offset_fsb); + lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1; + if (lastoffset > endoff) + lastoffset = endoff; + if (imap.br_startblock == HOLESTARTBLOCK) + continue; + ASSERT(imap.br_startblock != DELAYSTARTBLOCK); + if (imap.br_state == XFS_EXT_UNWRITTEN) + continue; + XFS_BUF_UNDONE(bp); + XFS_BUF_UNWRITE(bp); + XFS_BUF_READ(bp); + XFS_BUF_SET_ADDR(bp, XFS_FSB_TO_DB(ip, imap.br_startblock)); + xfsbdstrat(mp, bp); + if ((error = xfs_iowait(bp))) { + xfs_ioerror_alert("xfs_zero_remaining_bytes(read)", + mp, bp, XFS_BUF_ADDR(bp)); + break; + } + bzero(XFS_BUF_PTR(bp) + + (offset - XFS_FSB_TO_B(mp, imap.br_startoff)), + lastoffset - offset + 1); + XFS_BUF_UNDONE(bp); + XFS_BUF_UNREAD(bp); + XFS_BUF_WRITE(bp); + xfsbdstrat(mp, bp); + if ((error = xfs_iowait(bp))) { + xfs_ioerror_alert("xfs_zero_remaining_bytes(write)", + mp, bp, XFS_BUF_ADDR(bp)); + break; + } + } + XFS_nfreerbuf(bp); + return error; +} + +/* + * xfs_free_file_space() + * This routine frees disk space for the given file. + * + * This routine is only called by xfs_change_file_space + * for an UNRESVSP type call. + * + * RETURNS: + * 0 on success + * errno on error + * + */ +STATIC int +xfs_free_file_space( + xfs_inode_t *ip, + xfs_off_t offset, + xfs_off_t len, + int attr_flags) +{ + int committed; + int done; + xfs_off_t end_dmi_offset; + xfs_fileoff_t endoffset_fsb; + int error; + xfs_fsblock_t firstfsb; + xfs_bmap_free_t free_list; + xfs_off_t ilen; + xfs_bmbt_irec_t imap; + xfs_off_t ioffset; + xfs_extlen_t mod=0; + xfs_mount_t *mp; + int nimap; + uint resblks; + int rounding; + int specrt; + xfs_fileoff_t startoffset_fsb; + xfs_trans_t *tp; + + vn_trace_entry(XFS_ITOV(ip), "xfs_free_file_space", + (inst_t *)__return_address); + mp = ip->i_mount; + + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return error; + } + } + + error = 0; + if (len <= 0) /* if nothing being freed */ + return error; + specrt = + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb); + startoffset_fsb = XFS_B_TO_FSB(mp, offset); + end_dmi_offset = offset + len; + endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); + + if (offset < ip->i_d.di_size && + (attr_flags&ATTR_DMI) == 0 && + DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { + if (end_dmi_offset > ip->i_d.di_size) + end_dmi_offset = ip->i_d.di_size; + error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip), + offset, end_dmi_offset - offset, + AT_DELAY_FLAG(attr_flags), NULL); + if (error) + return(error); + } + + xfs_ilock(ip, XFS_IOLOCK_EXCL); + rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog), + (__uint8_t)NBPP); + ilen = len + (offset & (rounding - 1)); + ioffset = offset & ~(rounding - 1); + if (ilen & (rounding - 1)) + ilen = (ilen + rounding) & ~(rounding - 1); + xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), ioffset, 0, 0); + /* + * Need to zero the stuff we're not freeing, on disk. + * If its specrt (realtime & can't use unwritten extents) then + * we actually need to zero the extent edges. Otherwise xfs_bunmapi + * will take care of it for us. + */ + if (specrt) { + nimap = 1; + error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0, + &imap, &nimap, NULL); + if (error) + return error; + ASSERT(nimap == 0 || nimap == 1); + if (nimap && imap.br_startblock != HOLESTARTBLOCK) { + xfs_daddr_t block; + + ASSERT(imap.br_startblock != DELAYSTARTBLOCK); + block = imap.br_startblock; + mod = do_div(block, mp->m_sb.sb_rextsize); + if (mod) + startoffset_fsb += mp->m_sb.sb_rextsize - mod; + } + nimap = 1; + error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0, + &imap, &nimap, NULL); + if (error) + return error; + ASSERT(nimap == 0 || nimap == 1); + if (nimap && imap.br_startblock != HOLESTARTBLOCK) { + ASSERT(imap.br_startblock != DELAYSTARTBLOCK); + mod++; + if (mod && (mod != mp->m_sb.sb_rextsize)) + endoffset_fsb -= mod; + } + } + if ((done = (endoffset_fsb <= startoffset_fsb))) + /* + * One contiguous piece to clear + */ + error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1); + else { + /* + * Some full blocks, possibly two pieces to clear + */ + if (offset < XFS_FSB_TO_B(mp, startoffset_fsb)) + error = xfs_zero_remaining_bytes(ip, offset, + XFS_FSB_TO_B(mp, startoffset_fsb) - 1); + if (!error && + XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len) + error = xfs_zero_remaining_bytes(ip, + XFS_FSB_TO_B(mp, endoffset_fsb), + offset + len - 1); + } + + /* + * free file space until done or until there is an error + */ + resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); + while (!error && !done) { + + /* + * allocate and setup the transaction + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); + error = xfs_trans_reserve(tp, + resblks, + XFS_WRITE_LOG_RES(mp), + 0, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + + /* + * check for running out of space + */ + if (error) { + /* + * Free the transaction structure. + */ + ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + break; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, + ip->i_udquot, + ip->i_gdquot, + resblks, 0, 0)) { + error = XFS_ERROR(EDQUOT); + goto error1; + } + } + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * issue the bunmapi() call to free the blocks + */ + XFS_BMAP_INIT(&free_list, &firstfsb); + error = xfs_bunmapi(tp, ip, startoffset_fsb, + endoffset_fsb - startoffset_fsb, + 0, 2, &firstfsb, &free_list, &done); + if (error) { + goto error0; + } + + /* + * complete the transaction + */ + error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + if (error) { + goto error0; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + + error0: + xfs_bmap_cancel(&free_list); + error1: + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + return error; +} + +/* + * xfs_change_file_space() + * This routine allocates or frees disk space for the given file. + * The user specified parameters are checked for alignment and size + * limitations. + * + * RETURNS: + * 0 on success + * errno on error + * + */ +int +xfs_change_file_space( + bhv_desc_t *bdp, + int cmd, + xfs_flock64_t *bf, + xfs_off_t offset, + cred_t *credp, + int attr_flags) +{ + int clrprealloc; + int error; + xfs_fsize_t fsize; + xfs_inode_t *ip; + xfs_mount_t *mp; + int setprealloc; + xfs_off_t startoffset; + xfs_off_t llen; + xfs_trans_t *tp; + vattr_t va; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_change_file_space", + (inst_t *)__return_address); + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + /* + * must be a regular file and have write permission + */ + if (vp->v_type != VREG) + return XFS_ERROR(EINVAL); + + xfs_ilock(ip, XFS_ILOCK_SHARED); + + if ((error = xfs_iaccess(ip, IWRITE, credp))) { + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return error; + } + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + switch (bf->l_whence) { + case 0: /*SEEK_SET*/ + break; + case 1: /*SEEK_CUR*/ + bf->l_start += offset; + break; + case 2: /*SEEK_END*/ + bf->l_start += ip->i_d.di_size; + break; + default: + return XFS_ERROR(EINVAL); + } + + llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len; + + if ( (bf->l_start < 0) + || (bf->l_start > XFS_MAX_FILE_OFFSET) + || (bf->l_start + llen < 0) + || (bf->l_start + llen > XFS_MAX_FILE_OFFSET)) + return XFS_ERROR(EINVAL); + + bf->l_whence = 0; + + startoffset = bf->l_start; + fsize = ip->i_d.di_size; + + /* + * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve + * file space. + * These calls do NOT zero the data space allocated to the file, + * nor do they change the file size. + * + * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file + * space. + * These calls cause the new file data to be zeroed and the file + * size to be changed. + */ + setprealloc = clrprealloc = 0; + + switch (cmd) { + case XFS_IOC_RESVSP: + case XFS_IOC_RESVSP64: + error = xfs_alloc_file_space(ip, startoffset, bf->l_len, + 1, attr_flags); + if (error) + return error; + setprealloc = 1; + break; + + case XFS_IOC_UNRESVSP: + case XFS_IOC_UNRESVSP64: + if ((error = xfs_free_file_space(ip, startoffset, bf->l_len, + attr_flags))) + return error; + break; + + case XFS_IOC_ALLOCSP: + case XFS_IOC_ALLOCSP64: + case XFS_IOC_FREESP: + case XFS_IOC_FREESP64: + if (startoffset > fsize) { + error = xfs_alloc_file_space(ip, fsize, + startoffset - fsize, 0, attr_flags); + if (error) + break; + } + + va.va_mask = AT_SIZE; + va.va_size = startoffset; + + error = xfs_setattr(bdp, &va, attr_flags, credp); + + if (error) + return error; + + clrprealloc = 1; + break; + + default: + ASSERT(0); + return XFS_ERROR(EINVAL); + } + + /* + * update the inode timestamp, mode, and prealloc flag bits + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); + + if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp), + 0, 0, 0))) { + /* ASSERT(0); */ + xfs_trans_cancel(tp, 0); + return error; + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + ip->i_d.di_mode &= ~ISUID; + + /* + * Note that we don't have to worry about mandatory + * file locking being disabled here because we only + * clear the ISGID bit if the Group execute bit is + * on, but if it was on then mandatory locking wouldn't + * have been enabled. + */ + if (ip->i_d.di_mode & (IEXEC >> 3)) + ip->i_d.di_mode &= ~ISGID; + + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + if (setprealloc) + ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; + else if (clrprealloc) + ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + + error = xfs_trans_commit(tp, 0, NULL); + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return error; +} + +vnodeops_t xfs_vnodeops = { + .vop_open = xfs_open, + .vop_read = xfs_read, + .vop_write = xfs_write, + .vop_ioctl = xfs_ioctl, + .vop_getattr = xfs_getattr, + .vop_setattr = xfs_setattr, + .vop_access = xfs_access, + .vop_lookup = xfs_lookup, + .vop_create = xfs_create, + .vop_remove = xfs_remove, + .vop_link = xfs_link, + .vop_rename = xfs_rename, + .vop_mkdir = xfs_mkdir, + .vop_rmdir = xfs_rmdir, + .vop_readdir = xfs_readdir, + .vop_symlink = xfs_symlink, + .vop_readlink = xfs_readlink, + .vop_fsync = xfs_fsync, + .vop_inactive = xfs_inactive, + .vop_fid2 = xfs_fid2, + .vop_rwlock = xfs_rwlock, + .vop_rwunlock = xfs_rwunlock, + .vop_bmap = xfs_bmap, + .vop_strategy = xfs_strategy, + .vop_reclaim = xfs_reclaim, + .vop_attr_get = xfs_attr_get, + .vop_attr_set = xfs_attr_set, + .vop_attr_remove = xfs_attr_remove, + .vop_attr_list = xfs_attr_list, + .vop_link_removed = (vop_link_removed_t)fs_noval, + .vop_vnode_change = (vop_vnode_change_t)fs_noval, + .vop_tosspages = fs_tosspages, + .vop_flushinval_pages = fs_flushinval_pages, + .vop_flush_pages = fs_flush_pages, + .vop_release = xfs_release, + .vop_iflush = xfs_inode_flush, +}; diff -Nur linux-2.4.19/fs/xfs/xfsidbg.c linux-2.4.19-sgi211r3/fs/xfs/xfsidbg.c --- linux-2.4.19/fs/xfs/xfsidbg.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/fs/xfs/xfsidbg.c Fri Nov 1 12:24:39 2002 @@ -0,0 +1,5231 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include "pagebuf/page_buf_internal.h" + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI "); +MODULE_DESCRIPTION("Additional kdb commands for debugging XFS"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + +/* + * Command table functions. + */ +static void xfsidbg_xagf(xfs_agf_t *); +static void xfsidbg_xagi(xfs_agi_t *); +static void xfsidbg_xaildump(xfs_mount_t *); +static void xfsidbg_xalloc(xfs_alloc_arg_t *); +static void xfsidbg_xattrcontext(xfs_attr_list_context_t *); +static void xfsidbg_xattrleaf(xfs_attr_leafblock_t *); +static void xfsidbg_xattrsf(xfs_attr_shortform_t *); +static void xfsidbg_xbirec(xfs_bmbt_irec_t *r); +static void xfsidbg_xbmalla(xfs_bmalloca_t *); +static void xfsidbg_xbrec(xfs_bmbt_rec_64_t *); +static void xfsidbg_xbroot(xfs_inode_t *); +static void xfsidbg_xbroota(xfs_inode_t *); +static void xfsidbg_xbtcur(xfs_btree_cur_t *); +static void xfsidbg_xbuf(xfs_buf_t *); +static void xfsidbg_xbuf_real(xfs_buf_t *, int); +static void xfsidbg_xchash(xfs_mount_t *mp); +static void xfsidbg_xchashlist(xfs_chashlist_t *chl); +static void xfsidbg_xdaargs(xfs_da_args_t *); +static void xfsidbg_xdabuf(xfs_dabuf_t *); +static void xfsidbg_xdanode(xfs_da_intnode_t *); +static void xfsidbg_xdastate(xfs_da_state_t *); +static void xfsidbg_xdirleaf(xfs_dir_leafblock_t *); +static void xfsidbg_xdirsf(xfs_dir_shortform_t *); +static void xfsidbg_xdir2free(xfs_dir2_free_t *); +static void xfsidbg_xdir2sf(xfs_dir2_sf_t *); +static void xfsidbg_xexlist(xfs_inode_t *); +static void xfsidbg_xflist(xfs_bmap_free_t *); +static void xfsidbg_xhelp(void); +static void xfsidbg_xiclog(xlog_in_core_t *); +static void xfsidbg_xiclogall(xlog_in_core_t *); +static void xfsidbg_xiclogcb(xlog_in_core_t *); +static void xfsidbg_xihash(xfs_mount_t *mp); +static void xfsidbg_xinodes(xfs_mount_t *); +static void xfsidbg_delayed_blocks(xfs_mount_t *); +static void xfsidbg_xinodes_quiesce(xfs_mount_t *); +static void xfsidbg_xlog(xlog_t *); +static void xfsidbg_xlog_ritem(xlog_recover_item_t *); +static void xfsidbg_xlog_rtrans(xlog_recover_t *); +static void xfsidbg_xlog_rtrans_entire(xlog_recover_t *); +static void xfsidbg_xlog_tic(xlog_ticket_t *); +static void xfsidbg_xlogitem(xfs_log_item_t *); +static void xfsidbg_xmount(xfs_mount_t *); +static void xfsidbg_xnode(xfs_inode_t *ip); +static void xfsidbg_xcore(xfs_iocore_t *io); +static void xfsidbg_xperag(xfs_mount_t *); +static void xfsidbg_xqm_diskdq(xfs_disk_dquot_t *); +static void xfsidbg_xqm_dqattached_inos(xfs_mount_t *); +static void xfsidbg_xqm_dquot(xfs_dquot_t *); +static void xfsidbg_xqm_mplist(xfs_mount_t *); +static void xfsidbg_xqm_qinfo(xfs_mount_t *mp); +static void xfsidbg_xqm_tpdqinfo(xfs_trans_t *tp); +static void xfsidbg_xsb(xfs_sb_t *, int convert); +static void xfsidbg_xtp(xfs_trans_t *); +static void xfsidbg_xtrans_res(xfs_mount_t *); +#ifdef CONFIG_XFS_QUOTA +static void xfsidbg_xqm(void); +static void xfsidbg_xqm_htab(void); +static void xfsidbg_xqm_freelist_print(xfs_frlist_t *qlist, char *title); +static void xfsidbg_xqm_freelist(void); +#endif + +/* kdb wrappers */ + +static int kdbm_xfs_xagf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xagf((xfs_agf_t *)addr); + return 0; +} + +static int kdbm_xfs_xagi( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xagi((xfs_agi_t *)addr); + return 0; +} + +static int kdbm_xfs_xaildump( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xaildump((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xalloc( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xalloc((xfs_alloc_arg_t *) addr); + return 0; +} + +static int kdbm_xfs_xattrcontext( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xattrcontext((xfs_attr_list_context_t *) addr); + return 0; +} + +static int kdbm_xfs_xattrleaf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xattrleaf((xfs_attr_leafblock_t *) addr); + return 0; +} + +static int kdbm_xfs_xattrsf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xattrsf((xfs_attr_shortform_t *) addr); + return 0; +} + +static int kdbm_xfs_xbirec( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbirec((xfs_bmbt_irec_t *) addr); + return 0; +} + +static int kdbm_xfs_xbmalla( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbmalla((xfs_bmalloca_t *)addr); + return 0; +} + +static int kdbm_xfs_xbrec( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbrec((xfs_bmbt_rec_64_t *) addr); + return 0; +} + +static int kdbm_xfs_xbroot( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbroot((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xbroota( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbroota((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xbtcur( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbtcur((xfs_btree_cur_t *) addr); + return 0; +} + +static int kdbm_xfs_xbuf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbuf((xfs_buf_t *) addr); + return 0; +} + + +static int kdbm_xfs_xchash( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xchash((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xchashlist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xchashlist((xfs_chashlist_t *) addr); + return 0; +} + + +static int kdbm_xfs_xdaargs( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdaargs((xfs_da_args_t *) addr); + return 0; +} + +static int kdbm_xfs_xdabuf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdabuf((xfs_dabuf_t *) addr); + return 0; +} + +static int kdbm_xfs_xdanode( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdanode((xfs_da_intnode_t *) addr); + return 0; +} + +static int kdbm_xfs_xdastate( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdastate((xfs_da_state_t *) addr); + return 0; +} + +static int kdbm_xfs_xdirleaf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdirleaf((xfs_dir_leafblock_t *) addr); + return 0; +} + +static int kdbm_xfs_xdirsf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdirsf((xfs_dir_shortform_t *) addr); + return 0; +} + +static int kdbm_xfs_xdir2free( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdir2free((xfs_dir2_free_t *) addr); + return 0; +} + +static int kdbm_xfs_xdir2sf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdir2sf((xfs_dir2_sf_t *) addr); + return 0; +} + +static int kdbm_xfs_xexlist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xexlist((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xflist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xflist((xfs_bmap_free_t *) addr); + return 0; +} + +static int kdbm_xfs_xhelp( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xhelp(); + return 0; +} + +static int kdbm_xfs_xiclog( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xiclog((xlog_in_core_t *) addr); + return 0; +} + +static int kdbm_xfs_xiclogall( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xiclogall((xlog_in_core_t *) addr); + return 0; +} + +static int kdbm_xfs_xiclogcb( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xiclogcb((xlog_in_core_t *) addr); + return 0; +} + +static int kdbm_xfs_xihash( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xihash((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xinodes( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xinodes((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_delayed_blocks( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_delayed_blocks((xfs_mount_t *) addr); + return 0; +} + + +static int kdbm_xfs_xinodes_quiesce( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xinodes_quiesce((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog((xlog_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_ritem( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_ritem((xlog_recover_item_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_rtrans( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_rtrans((xlog_recover_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_rtrans_entire( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_rtrans_entire((xlog_recover_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_tic( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_tic((xlog_ticket_t *) addr); + return 0; +} + +static int kdbm_xfs_xlogitem( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlogitem((xfs_log_item_t *) addr); + return 0; +} + +static int kdbm_xfs_xmount( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xmount((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xnode( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xnode((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xcore( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xcore((xfs_iocore_t *) addr); + return 0; +} + +static int kdbm_xfs_xperag( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xperag((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_diskdq( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_diskdq((xfs_disk_dquot_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_dqattached_inos( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_dqattached_inos((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_dquot( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_dquot((xfs_dquot_t *) addr); + return 0; +} + +#ifdef CONFIG_XFS_QUOTA +static int kdbm_xfs_xqm( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xqm(); + return 0; +} + +static int kdbm_xfs_xqm_freelist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xqm_freelist(); + return 0; +} + +static int kdbm_xfs_xqm_htab( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xqm_htab(); + return 0; +} +#endif + +static int kdbm_xfs_xqm_mplist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_mplist((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_qinfo( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_qinfo((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_tpdqinfo( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_tpdqinfo((xfs_trans_t *) addr); + return 0; +} + +static int kdbm_xfs_xsb( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + unsigned long convert=0; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1 && argc!=2) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + if (argc==2) { + /* extra argument - conversion flag */ + diag = kdbgetaddrarg(argc, argv, &nextarg, &convert, &offset, NULL, regs); + if (diag) + return diag; + } + + xfsidbg_xsb((xfs_sb_t *) addr, (int)convert); + return 0; +} + +static int kdbm_xfs_xtp( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xtp((xfs_trans_t *) addr); + return 0; +} + +static int kdbm_xfs_xtrans_res( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xtrans_res((xfs_mount_t *) addr); + return 0; +} + +/* + * Vnode descriptor dump. + * This table is a string version of all the flags defined in vnode.h. + */ +char *tab_vflags[] = { + /* local only flags */ + "VINACT", /* 0x01 */ + "VRECLM", /* 0x02 */ + "VWAIT", /* 0x04 */ + "VMODIFIED", /* 0x08 */ + "INVALID0x10", /* 0x10 */ + "INVALID0x20", /* 0x20 */ + "INVALID0x40", /* 0x40 */ + "INVALID0x80", /* 0x80 */ + "INVALID0x100", /* 0x100 */ + "INVALID0x200", /* 0x200 */ + "INVALID0x400", /* 0x400 */ + "INVALID0x800", /* 0x800 */ + "INVALID0x1000", /* 0x1000 */ + "INVALID0x2000", /* 0x2000 */ + "INVALID0x4000", /* 0x4000 */ + "INVALID0x8000", /* 0x8000 */ + "INVALID0x10000", /* 0x10000 */ + "INVALID0x20000", /* 0x20000 */ + "INVALID0x40000", /* 0x40000 */ + "INVALID0x80000", /* 0x80000 */ + "VROOT", /* 0x100000 */ + "VNOSWAP", /* 0x200000 */ + "VISSWAP", /* 0x400000 */ + "VREPLICABLE", /* 0x800000 */ + "VNOTREPLICABLE", /* 0x1000000 */ + "VDOCMP", /* 0x2000000 */ + "VSHARE", /* 0x4000000 */ + "VFRLOCKS", /* 0x8000000 */ + "VENF_LOCKING", /* 0x10000000 */ + "VOPLOCK", /* 0x20000000 */ + "VPURGE", /* 0x40000000 */ + "INVALID0x80000000", /* 0x80000000 */ + 0 +}; + + +static char *vnode_type[] = { + "VNON", "VREG", "VDIR", "VBLK", "VLNK", "VFIFO", "VBAD", "VSOCK" +}; + +static void +printflags(register uint64_t flags, + register char **strings, + register char *name) +{ + register uint64_t mask = 1; + + if (name) + kdb_printf("%s 0x%llx <", name, (unsigned long long)flags); + + while (flags != 0 && *strings) { + if (mask & flags) { + kdb_printf("%s ", *strings); + flags &= ~mask; + } + mask <<= 1; + strings++; + } + + if (name) + kdb_printf("> "); + + return; +} + + +static void printvnode(vnode_t *vp) +{ + bhv_desc_t *bh; + kdb_symtab_t symtab; + + + kdb_printf("vnode: 0x%p type ", vp); + if ((size_t)vp->v_type >= sizeof(vnode_type)/sizeof(vnode_type[0])) + kdb_printf("out of range 0x%x\n", vp->v_type); + else + kdb_printf("%s\n", vnode_type[vp->v_type]); + + if ((bh = vp->v_bh.bh_first)) { + kdb_printf(" v_inode 0x%p v_bh->bh_first 0x%p pobj 0x%p\n", + LINVFS_GET_IP(vp), bh, bh->bd_pdata); + + if (kdbnearsym((unsigned long)bh->bd_ops, &symtab)) + kdb_printf(" ops %s ", symtab.sym_name); + else + kdb_printf(" ops %s/0x%p ", + "???", (void *)bh->bd_ops); + } else { + kdb_printf(" v_inode 0x%p v_bh->bh_first = NULLBHV ", + LINVFS_GET_IP(vp)); + } + + printflags((__psunsigned_t)vp->v_flag, tab_vflags, "flag ="); + kdb_printf("\n"); + +#ifdef CONFIG_XFS_VNODE_TRACING + kdb_printf(" v_trace 0x%p\n", vp->v_trace); +#endif /* CONFIG_XFS_VNODE_TRACING */ +} + + +static int kdbm_vnode( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + vnode_t *vp; +/* bhv_desc_t *bh; */ +/* kdb_symtab_t symtab;*/ + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + vp = (vnode_t *)addr; + + printvnode(vp); + + return 0; +} + +#ifdef CONFIG_XFS_VNODE_TRACING +/* + * Print a vnode trace entry. + */ +static int +vn_trace_pr_entry(ktrace_entry_t *ktep) +{ + char funcname[128]; + kdb_symtab_t symtab; + + + if ((__psint_t)ktep->val[0] == 0) + return 0; + + if (kdbnearsym((unsigned int)ktep->val[8], &symtab)) { + unsigned long offval; + + offval = (unsigned int)ktep->val[8] - symtab.sym_start; + + if (offval) + sprintf(funcname, "%s+0x%lx", symtab.sym_name, offval); + else + sprintf(funcname, "%s", symtab.sym_name); + } else + funcname[0] = '\0'; + + + switch ((__psint_t)ktep->val[0]) { + case VNODE_KTRACE_ENTRY: + kdb_printf("entry to %s i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_EXIT: + kdb_printf("exit from %s i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_HOLD: + if ((__psint_t)ktep->val[3] != 1) + kdb_printf("hold @%s:%d(%s) i_count %d => %d ", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3] - 1, + (__psint_t)ktep->val[3]); + else + kdb_printf("get @%s:%d(%s) i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_REF: + kdb_printf("ref @%s:%d(%s) i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_RELE: + if ((__psint_t)ktep->val[3] != 1) + kdb_printf("rele @%s:%d(%s) i_count %d => %d ", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3], + (__psint_t)ktep->val[3] - 1); + else + kdb_printf("free @%s:%d(%s) i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3]); + break; + + default: + kdb_printf("unknown vntrace record\n"); + return 1; + } + + kdb_printf("\n"); + + kdb_printf(" cpu = %d pid = %d ", + (__psint_t)ktep->val[6], (pid_t)ktep->val[7]); + + printflags((__psunsigned_t)ktep->val[5], tab_vflags, "flag ="); + + if (kdbnearsym((unsigned int)ktep->val[4], &symtab)) { + unsigned long offval; + + offval = (unsigned int)ktep->val[4] - symtab.sym_start; + + if (offval) + kdb_printf(" ra = %s+0x%lx", symtab.sym_name, offval); + else + kdb_printf(" ra = %s", symtab.sym_name); + } else + kdb_printf(" ra = ?? 0x%p", (void *)ktep->val[4]); + + return 1; +} + + +/* + * Print out the trace buffer attached to the given vnode. + */ +static int kdbm_vntrace( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + int diag; + int nextarg = 1; + long offset = 0; + unsigned long addr; + vnode_t *vp; + ktrace_entry_t *ktep; + ktrace_snap_t kts; + + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + vp = (vnode_t *)addr; + + if (vp->v_trace == NULL) { + kdb_printf("The vnode trace buffer is not initialized\n"); + + return 0; + } + + kdb_printf("vntrace vp 0x%p\n", vp); + + ktep = ktrace_first(vp->v_trace, &kts); + + while (ktep != NULL) { + if (vn_trace_pr_entry(ktep)) + kdb_printf("\n"); + + ktep = ktrace_next(vp->v_trace, &kts); + } + + return 0; +} +/* + * Print out the trace buffer attached to the given vnode. + */ +static int kdbm_vntraceaddr( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + int diag; + int nextarg = 1; + long offset = 0; + unsigned long addr; + struct ktrace *kt; + ktrace_entry_t *ktep; + ktrace_snap_t kts; + + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + kt = (struct ktrace *)addr; + + kdb_printf("vntraceaddr kt 0x%p\n", kt); + + ktep = ktrace_first(kt, &kts); + + while (ktep != NULL) { + if (vn_trace_pr_entry(ktep)) + kdb_printf("\n"); + + ktep = ktrace_next(kt, &kts); + } + + return 0; +} +#endif /* CONFIG_XFS_VNODE_TRACING */ + + +static void printinode(struct inode *ip) +{ + unsigned long addr; + + + if (ip == NULL) + return; + + kdb_printf(" i_ino = %lu i_count = %u i_dev = 0x%x i_size %Ld\n", + ip->i_ino, atomic_read(&ip->i_count), + kdev_t_to_nr(ip->i_dev), ip->i_size); + + kdb_printf( + " i_mode = 0x%x i_nlink = %d i_rdev = 0x%x i_state = 0x%lx\n", + ip->i_mode, ip->i_nlink, + kdev_t_to_nr(ip->i_rdev), ip->i_state); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + ip->i_hash.next, ip->i_hash.prev); + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + ip->i_list.next, ip->i_list.prev); + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + ip->i_dentry.next, + ip->i_dentry.prev); + + addr = (unsigned long)ip; + + kdb_printf(" i_sb = 0x%p i_op = 0x%p i_data = 0x%lx nrpages = %lu\n", + ip->i_sb, ip->i_op, + addr + offsetof(struct inode, i_data), + ip->i_data.nrpages); + + kdb_printf(" vnode ptr 0x%p\n", LINVFS_GET_VP(ip)); +} + + +static int kdbm_vn( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + int diag; + int nextarg = 1; +/* char *symname; */ + long offset = 0; + unsigned long addr; + struct inode *ip; +/* bhv_desc_t *bh; */ +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_entry_t *ktep; + ktrace_snap_t kts; +#endif + vnode_t *vp; + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + vp = (vnode_t *)addr; + + ip = LINVFS_GET_IP(vp); + + kdb_printf("--> Inode @ 0x%p\n", ip); + printinode(ip); + + kdb_printf("--> Vnode @ 0x%p\n", vp); + printvnode(vp); + +#ifdef CONFIG_XFS_VNODE_TRACING + + kdb_printf("--> Vntrace @ 0x%p/0x%p\n", vp, vp->v_trace); + + if (vp->v_trace == NULL) + return 0; + + ktep = ktrace_first(vp->v_trace, &kts); + + while (ktep != NULL) { + if (vn_trace_pr_entry(ktep)) + kdb_printf("\n"); + + ktep = ktrace_next(vp->v_trace, &kts); + } +#endif /* CONFIG_XFS_VNODE_TRACING */ + + return 0; +} + + +/* pagebuf stuff */ + +static char *pb_flag_vals[] = { + "READ", "WRITE", "MAPPED", "PARTIAL", + "ASYNC", "NONE", "DELWRI", "FREED", "SYNC", + "MAPPABLE", "STALE", "FS_MANAGED", "RELEASE", + "LOCK", "TRYLOCK", "ALLOCATE", "FILE_ALLOCATE", "DONT_BLOCK", + "DIRECT", "LOCKABLE", "NEXT_KEY", "ENTER_PAGES", + "ALL_PAGES_MAPPED", "SOME_INVALID_PAGES", "ADDR_ALLOCATED", + "MEM_ALLOCATED", "GRIO", "FORCEIO", "SHUTDOWN", + NULL }; + +static char *pbm_flag_vals[] = { + "EOF", "HOLE", "DELAY", "FLUSH_OVERLAPS", + "READAHEAD", "UNWRITTEN", "DONTALLOC", "NEW", + NULL }; + + +static char *map_flags(unsigned long flags, char *mapping[]) +{ + static char buffer[256]; + int index; + int offset = 12; + + buffer[0] = '\0'; + + for (index = 0; flags && mapping[index]; flags >>= 1, index++) { + if (flags & 1) { + if ((offset + strlen(mapping[index]) + 1) >= 80) { + strcat(buffer, "\n "); + offset = 12; + } else if (offset > 12) { + strcat(buffer, " "); + offset++; + } + strcat(buffer, mapping[index]); + offset += strlen(mapping[index]); + } + } + + return (buffer); +} + +static char *pb_flags(page_buf_flags_t pb_flag) +{ + return(map_flags((unsigned long) pb_flag, pb_flag_vals)); +} + +static int +kdbm_pb_flags(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long flags; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetularg(argv[1], &flags); + if (diag) + return diag; + + kdb_printf("pb flags 0x%lx = %s\n", flags, pb_flags(flags)); + + return 0; +} + +static int +kdbm_pb(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + page_buf_private_t bp; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(bp, addr))) + return diag; + + kdb_printf("page_buf_t at 0x%lx\n", addr); + kdb_printf(" pb_flags %s\n", pb_flags(bp.pb_common.pb_flags)); + kdb_printf(" pb_target 0x%p pb_hold %d pb_next 0x%p pb_prev 0x%p\n", + bp.pb_common.pb_target, bp.pb_common.pb_hold.counter, + bp.pb_common.pb_list.next, bp.pb_common.pb_list.prev); + kdb_printf(" pb_hash_index %d pb_hash_next 0x%p pb_hash_prev 0x%p\n", + bp.pb_common.pb_hash_index, + bp.pb_common.pb_hash_list.next, + bp.pb_common.pb_hash_list.prev); + kdb_printf(" pb_file_offset 0x%llx pb_buffer_length 0x%llx pb_addr 0x%p\n", + (unsigned long long) bp.pb_common.pb_file_offset, + (unsigned long long) bp.pb_common.pb_buffer_length, + bp.pb_common.pb_addr); + kdb_printf(" pb_bn 0x%Lx pb_count_desired 0x%lx\n", + bp.pb_common.pb_bn, + (unsigned long) bp.pb_common.pb_count_desired); + kdb_printf(" pb_io_remaining %d pb_error %u\n", + bp.pb_io_remaining.counter, bp.pb_common.pb_error); + kdb_printf(" pb_page_count %u pb_offset 0x%x pb_pages 0x%p\n", + bp.pb_common.pb_page_count, bp.pb_common.pb_offset, + bp.pb_common.pb_pages); +#ifdef PAGEBUF_LOCK_TRACKING + kdb_printf(" pb_iodonesema (%d,%d) pb_sema (%d,%d) pincount (%d) last holder %d\n", + bp.pb_common.pb_iodonesema.count.counter, + bp.pb_common.pb_iodonesema.sleepers, + bp.pb_sema.count.counter, bp.pb_sema.sleepers, + bp.pb_pin_count.counter, bp.pb_last_holder); +#else + kdb_printf(" pb_iodonesema (%d,%d) pb_sema (%d,%d) pincount (%d)\n", + bp.pb_common.pb_iodonesema.count.counter, + bp.pb_common.pb_iodonesema.sleepers, + bp.pb_sema.count.counter, bp.pb_sema.sleepers, + bp.pb_pin_count.counter); +#endif + if (bp.pb_common.pb_fspriv || bp.pb_common.pb_fspriv2) { + kdb_printf( "pb_fspriv 0x%p pb_fspriv2 0x%p\n", + bp.pb_common.pb_fspriv, bp.pb_common.pb_fspriv2); + } + + return 0; +} + +/* XXXXXXXXXXXXXXXXXXXXXX */ +/* The start of this deliberately looks like a read_descriptor_t in layout */ +typedef struct { + read_descriptor_t io_rdesc; + + /* 0x10 */ + page_buf_rw_t io_dir; /* read or write */ + loff_t io_offset; /* Starting offset of I/O */ + int io_iovec_nr; /* Number of entries in iovec */ + + /* 0x20 */ + struct iovec **io_iovec; /* iovec list indexed by iovec_index */ + loff_t io_iovec_offset; /* offset into current iovec. */ + int io_iovec_index; /* current iovec being processed */ + unsigned int io_sshift; /* sector bit shift */ + loff_t io_i_size; /* size of the file */ +} pb_io_desc_t; + +static int +kdbm_pbiodesc(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + pb_io_desc_t pbio; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(pbio, addr))) + + kdb_printf("pb_io_desc_t at 0x%lx\n", addr); + kdb_printf(" io_rdesc [ written 0x%lx count 0x%lx buf 0x%p error %d ]\n", + (unsigned long) pbio.io_rdesc.written, + (unsigned long) pbio.io_rdesc.count, + pbio.io_rdesc.buf, pbio.io_rdesc.error); + + kdb_printf(" io_dir %d io_offset 0x%Lx io_iovec_nr 0x%d\n", + pbio.io_dir, pbio.io_offset, pbio.io_iovec_nr); + + kdb_printf(" io_iovec 0x%p io_iovec_offset 0x%Lx io_iovec_index 0x%d\n", + pbio.io_iovec, pbio.io_iovec_offset, pbio.io_iovec_index); + + kdb_printf(" io_sshift 0x%d io_i_size 0x%Lx\n", + pbio.io_sshift, pbio.io_i_size); + + return 0; +} + +static int +kdbm_pbmap(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + page_buf_bmap_t pbm; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(pbm, addr))) + + kdb_printf("page_buf_bmap_t at 0x%lx\n", addr); + kdb_printf(" pbm_bn 0x%llx pbm_offset 0x%Lx pbm_delta 0x%lx pbm_bsize 0x%lx\n", + (long long) pbm.pbm_bn, pbm.pbm_offset, + (unsigned long) pbm.pbm_delta, (unsigned long) pbm.pbm_bsize); + + kdb_printf(" pbm_flags %s\n", map_flags(pbm.pbm_flags, pbm_flag_vals)); + + return 0; +} + +#ifdef PAGEBUF_TRACE +# ifdef __PAGEBUF_TRACE__ +# undef __PAGEBUF_TRACE__ +# undef PB_DEFINE_TRACES +# undef PB_TRACE_START +# undef PB_TRACE_REC +# undef PB_TRACE_END +# endif +#include "pagebuf/page_buf_trace.h" + +#define EV_SIZE (sizeof(event_names)/sizeof(char *)) + +void +pb_trace_core( + unsigned long match, + char *event_match, + unsigned long long offset, + long long mask) +{ + extern struct pagebuf_trace_buf pb_trace; + int i, total, end; + pagebuf_trace_t *trace; + char *event; + char value[10]; + + end = pb_trace.start - 1; + if (end < 0) + end = PB_TRACE_BUFSIZE - 1; + + if (match && (match < PB_TRACE_BUFSIZE)) { + for (i = pb_trace.start, total = 0; i != end; i = CIRC_INC(i)) { + trace = &pb_trace.buf[i]; + if (trace->pb == 0) + continue; + total++; + } + total = total - match; + for (i = pb_trace.start; i != end && total; i = CIRC_INC(i)) { + trace = &pb_trace.buf[i]; + if (trace->pb == 0) + continue; + total--; + } + match = 0; + } else + i = pb_trace.start; + for ( ; i != end; i = CIRC_INC(i)) { + trace = &pb_trace.buf[i]; + + if (offset) { + if ((trace->offset & ~mask) != offset) + continue; + } + + if (trace->pb == 0) + continue; + + if ((match != 0) && (trace->pb != match)) + continue; + + if ((trace->event < EV_SIZE-1) && event_names[trace->event]) { + event = event_names[trace->event]; + } else if (trace->event == EV_SIZE) { + event = (char *)trace->misc; + } else { + event = value; + sprintf(value, "%8d", trace->event); + } + + if (event_match && strcmp(event, event_match)) { + continue; + } + + + kdb_printf("pb 0x%lx [%s] (hold %u lock %d) misc 0x%p", + trace->pb, event, + trace->hold, trace->lock_value, + trace->misc); + kdb_symbol_print((unsigned int)trace->ra, NULL, + KDB_SP_SPACEB|KDB_SP_PAREN|KDB_SP_NEWLINE); + kdb_printf(" offset 0x%Lx size 0x%x task 0x%p\n", + trace->offset, trace->size, trace->task); + kdb_printf(" flags: %s\n", + pb_flags(trace->flags)); + } +} + + +static int +kdbm_pbtrace_offset(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + long mask = 0; + unsigned long offset = 0; + int diag; + + if (argc > 2) + return KDB_ARGCOUNT; + + if (argc > 0) { + diag = kdbgetularg(argv[1], &offset); + if (diag) + return diag; + } + + if (argc > 1) { + diag = kdbgetularg(argv[1], &mask); + if (diag) + return diag; + } + + pb_trace_core(0, NULL, (unsigned long long)offset, + (long long)mask); /* sign extent mask */ + return 0; +} + +static int +kdbm_pbtrace(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + unsigned long addr = 0; + int diag, nextarg; + long offset = 0; + char *event_match = NULL; + + if (argc > 1) + return KDB_ARGCOUNT; + + if (argc == 1) { + if (isupper(argv[1][0]) || islower(argv[1][0])) { + event_match = (char *)argv[1]; + printk("event match on \"%s\"\n", event_match); + argc = 0; + } else { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) { + printk("failed to parse %s as a number\n", + argv[1]); + return diag; + } + } + } + + pb_trace_core(addr, event_match, 0LL, 0LL); + return 0; +} + +#else /* PAGEBUF_TRACE */ +static int +kdbm_pbtrace(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + kdb_printf("pagebuf tracing not compiled in\n"); + + return 0; +} +#endif /* PAGEBUF_TRACE */ + +static struct xif { + char *name; + int (*func)(int, const char **, const char **, struct pt_regs *); + char *args; + char *help; +} xfsidbg_funcs[] = { + { "vn", kdbm_vn, "", "Dump inode/vnode/trace"}, + { "vnode", kdbm_vnode, "", "Dump vnode"}, +#ifdef CONFIG_XFS_VNODE_TRACING + { "vntrace", kdbm_vntrace, "", "Dump vnode Trace"}, + { "vntraceaddr", kdbm_vntraceaddr, "", "Dump vnode Trace by Address"}, +#endif /* CONFIG_XFS_VNODE_TRACING */ + { "xagf", kdbm_xfs_xagf, "", + "Dump XFS allocation group freespace" }, + { "xagi", kdbm_xfs_xagi, "", + "Dump XFS allocation group inode" }, + { "xail", kdbm_xfs_xaildump, "", + "Dump XFS AIL for a mountpoint" }, + { "xalloc", kdbm_xfs_xalloc, "", + "Dump XFS allocation args structure" }, + { "xattrcx", kdbm_xfs_xattrcontext, "", + "Dump XFS attr_list context struct"}, + { "xattrlf", kdbm_xfs_xattrleaf, "", + "Dump XFS attribute leaf block"}, + { "xattrsf", kdbm_xfs_xattrsf, "", + "Dump XFS attribute shortform"}, + { "xbirec", kdbm_xfs_xbirec, "", + "Dump XFS bmalloc args structure"}, + { "xbrec", kdbm_xfs_xbrec, "", + "Dump XFS bmap btree root (data)"}, + { "xbroota", kdbm_xfs_xbroota, "", + "Dump XFS bmap btree root (attr)"}, + { "xbtcur", kdbm_xfs_xbtcur, "", + "Dump XFS btree cursor"}, + { "xbuf", kdbm_xfs_xbuf, "", + "Dump XFS data from a buffer"}, + { "xchash", kdbm_xfs_xchash, "", + "Dump XFS cluster hash"}, + { "xchlist", kdbm_xfs_xchashlist, "", + "Dump XFS cluster hash list"}, + { "xd2free", kdbm_xfs_xdir2free, "", + "Dump XFS directory v2 freemap"}, + { "xdaargs", kdbm_xfs_xdaargs, "", + "Dump XFS dir/attr args structure"}, + { "xdabuf", kdbm_xfs_xdabuf, "", + "Dump XFS dir/attr buf structure"}, + { "xdanode", kdbm_xfs_xdanode, "", + "Dump XFS dir/attr node block"}, + { "xdastat", kdbm_xfs_xdastate, "", + "Dump XFS dir/attr state_blk struct"}, + { "xdelay", kdbm_xfs_delayed_blocks, "", + "Dump delayed block totals"}, + { "xdirlf", kdbm_xfs_xdirleaf, "", + "Dump XFS directory leaf block"}, + { "xdirsf", kdbm_xfs_xdirsf, "", + "Dump XFS directory shortform"}, + { "xdir2sf", kdbm_xfs_xdir2sf, "", + "Dump XFS directory v2 shortform"}, + { "xdiskdq", kdbm_xfs_xqm_diskdq, "", + "Dump XFS ondisk dquot (quota) struct"}, + { "xdqatt", kdbm_xfs_xqm_dqattached_inos, "", + "All incore inodes with dquots"}, + { "xdqinfo", kdbm_xfs_xqm_tpdqinfo, "", + "Dump dqinfo structure of a trans"}, + { "xdquot", kdbm_xfs_xqm_dquot, "", + "Dump XFS dquot (quota) structure"}, + { "xexlist", kdbm_xfs_xexlist, "", + "Dump XFS bmap extents in inode"}, + { "xflist", kdbm_xfs_xflist, "", + "Dump XFS to-be-freed extent list"}, + { "xhelp", kdbm_xfs_xhelp, "", + "Print idbg-xfs help"}, + { "xicall", kdbm_xfs_xiclogall, "", + "Dump All XFS in-core logs"}, + { "xiclog", kdbm_xfs_xiclog, "", + "Dump XFS in-core log"}, + { "xihash", kdbm_xfs_xihash, "", + "Dump XFS inode hash statistics"}, + { "xinodes", kdbm_xfs_xinodes, "", + "Dump XFS inodes per mount"}, + { "xquiesce",kdbm_xfs_xinodes_quiesce, "", + "Dump non-quiesced XFS inodes per mount"}, + { "xl_rcit", kdbm_xfs_xlog_ritem, "", + "Dump XFS recovery item"}, + { "xl_rctr", kdbm_xfs_xlog_rtrans, "", + "Dump XFS recovery transaction"}, + { "xl_rctr2",kdbm_xfs_xlog_rtrans_entire, "", + "Dump entire recovery transaction"}, + { "xl_tic", kdbm_xfs_xlog_tic, "", + "Dump XFS log ticket"}, + { "xlog", kdbm_xfs_xlog, "", + "Dump XFS log"}, + { "xlogcb", kdbm_xfs_xiclogcb, "", + "Dump XFS in-core log callbacks"}, + { "xlogitm", kdbm_xfs_xlogitem, "", + "Dump XFS log item structure"}, + { "xmount", kdbm_xfs_xmount, "", + "Dump XFS mount structure"}, + { "xnode", kdbm_xfs_xnode, "", + "Dump XFS inode"}, + { "xiocore", kdbm_xfs_xcore, "", + "Dump XFS iocore"}, + { "xperag", kdbm_xfs_xperag, "", + "Dump XFS per-allocation group data"}, + { "xqinfo", kdbm_xfs_xqm_qinfo, "", + "Dump mount->m_quotainfo structure"}, +#ifdef CONFIG_XFS_QUOTA + { "xqm", kdbm_xfs_xqm, "", + "Dump XFS quota manager structure"}, + { "xqmfree", kdbm_xfs_xqm_freelist, "", + "Dump XFS global freelist of dquots"}, + { "xqmhtab", kdbm_xfs_xqm_htab, "", + "Dump XFS hashtable of dquots"}, +#endif /* CONFIG_XFS_QUOTA */ + { "xqmplist",kdbm_xfs_xqm_mplist, "", + "Dump XFS all dquots of a f/s"}, + { "xsb", kdbm_xfs_xsb, " ", + "Dump XFS superblock"}, + { "xtp", kdbm_xfs_xtp, "", + "Dump XFS transaction structure"}, + { "xtrres", kdbm_xfs_xtrans_res, "", + "Dump XFS reservation values"}, + { 0, 0, 0 } +}; + +static int +__init xfsidbg_init(void) +{ + struct xif *p; + + for (p = xfsidbg_funcs; p->name; p++) + kdb_register(p->name, p->func, p->args, p->help, 0); + + kdb_register("pb", kdbm_pb, "", "Display page_buf_t", 0); + kdb_register("pbflags", kdbm_pb_flags, "", + "Display page buf flags", 0); + kdb_register("pbiodesc", kdbm_pbiodesc, "", + "Display I/O Descriptor", 0); + kdb_register("pbmap", kdbm_pbmap, "", + "Display Bmap", 0); + kdb_register("pbtrace", kdbm_pbtrace, "|", + "page_buf_t trace", 0); +#ifdef PAGEBUF_TRACE + kdb_register("pboffset", kdbm_pbtrace_offset, " []", + "page_buf_t trace", 0); +#endif + return 0; +} + +static void +__exit xfsidbg_exit(void) +{ + struct xif *p; + + for (p = xfsidbg_funcs; p->name; p++) + kdb_unregister(p->name); + + kdb_unregister("pb"); + kdb_unregister("pbflags"); + kdb_unregister("pbmap"); + kdb_unregister("pbiodesc"); + kdb_unregister("pbtrace"); +#ifdef PAGEBUF_TRACE + kdb_unregister("pboffset"); +#endif + +} + +/* + * Argument to xfs_alloc routines, for allocation type. + */ +static char *xfs_alloctype[] = { + "any_ag", "first_ag", "start_ag", "this_ag", + "start_bno", "near_bno", "this_bno" +}; + + +/* + * Prototypes for static functions. + */ +static void xfs_broot(xfs_inode_t *ip, xfs_ifork_t *f); +static void xfs_btalloc(xfs_alloc_block_t *bt, int bsz); +static void xfs_btbmap(xfs_bmbt_block_t *bt, int bsz); +static void xfs_btino(xfs_inobt_block_t *bt, int bsz); +static void xfs_buf_item_print(xfs_buf_log_item_t *blip, int summary); +static void xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op, + xfs_dfsbno_t *sp, xfs_dfilblks_t *cp, int *fp); +static void xfs_dastate_path(xfs_da_state_path_t *p); +static void xfs_dir2data(void *addr, int size); +static void xfs_dir2leaf(xfs_dir2_leaf_t *leaf, int size); +static void xfs_dquot_item_print(xfs_dq_logitem_t *lip, int summary); +static void xfs_efd_item_print(xfs_efd_log_item_t *efdp, int summary); +static void xfs_efi_item_print(xfs_efi_log_item_t *efip, int summary); +static char *xfs_fmtformat(xfs_dinode_fmt_t f); +static char *xfs_fmtfsblock(xfs_fsblock_t bno, xfs_mount_t *mp); +static char *xfs_fmtino(xfs_ino_t ino, xfs_mount_t *mp); +static char *xfs_fmtlsn(xfs_lsn_t *lsnp); +static char *xfs_fmtmode(int m); +static char *xfs_fmtsize(size_t i); +static char *xfs_fmtuuid(uuid_t *); +static void xfs_inode_item_print(xfs_inode_log_item_t *ilip, int summary); +static void xfs_inodebuf(xfs_buf_t *bp); +static void xfs_prdinode(xfs_dinode_t *di, int coreonly, int convert); +static void xfs_prdinode_core(xfs_dinode_core_t *dip, int convert); +static void xfs_qoff_item_print(xfs_qoff_logitem_t *lip, int summary); +static void xfs_xexlist_fork(xfs_inode_t *ip, int whichfork); +static void xfs_xnode_fork(char *name, xfs_ifork_t *f); + +/* + * Static functions. + */ + + +/* + * Print an xfs in-inode bmap btree root. + */ +static void +xfs_broot(xfs_inode_t *ip, xfs_ifork_t *f) +{ + xfs_bmbt_block_t *broot; + int format; + int i; + xfs_bmbt_key_t *kp; + xfs_bmbt_ptr_t *pp; + + format = f == &ip->i_df ? ip->i_d.di_format : ip->i_d.di_aformat; + if ((f->if_flags & XFS_IFBROOT) == 0 || + format != XFS_DINODE_FMT_BTREE) { + kdb_printf("inode 0x%p not btree format\n", ip); + return; + } + broot = f->if_broot; + kdb_printf("block @0x%p magic %x level %d numrecs %d\n", + broot, INT_GET(broot->bb_magic, ARCH_CONVERT), INT_GET(broot->bb_level, ARCH_CONVERT), INT_GET(broot->bb_numrecs, ARCH_CONVERT)); + kp = XFS_BMAP_BROOT_KEY_ADDR(broot, 1, f->if_broot_bytes); + pp = XFS_BMAP_BROOT_PTR_ADDR(broot, 1, f->if_broot_bytes); + for (i = 1; i <= INT_GET(broot->bb_numrecs, ARCH_CONVERT); i++) + kdb_printf("\t%d: startoff %Ld ptr %Lx %s\n", + i, INT_GET(kp[i - 1].br_startoff, ARCH_CONVERT), INT_GET(pp[i - 1], ARCH_CONVERT), + xfs_fmtfsblock(INT_GET(pp[i - 1], ARCH_CONVERT), ip->i_mount)); +} + +/* + * Print allocation btree block. + */ +static void +xfs_btalloc(xfs_alloc_block_t *bt, int bsz) +{ + int i; + + kdb_printf("magic 0x%x level %d numrecs %d leftsib 0x%x rightsib 0x%x\n", + INT_GET(bt->bb_magic, ARCH_CONVERT), INT_GET(bt->bb_level, ARCH_CONVERT), INT_GET(bt->bb_numrecs, ARCH_CONVERT), + INT_GET(bt->bb_leftsib, ARCH_CONVERT), INT_GET(bt->bb_rightsib, ARCH_CONVERT)); + if (INT_ISZERO(bt->bb_level, ARCH_CONVERT)) { + + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_alloc_rec_t *r; + + r = XFS_BTREE_REC_ADDR(bsz, xfs_alloc, bt, i, 0); + kdb_printf("rec %d startblock 0x%x blockcount %d\n", + i, INT_GET(r->ar_startblock, ARCH_CONVERT), INT_GET(r->ar_blockcount, ARCH_CONVERT)); + } + } else { + int mxr; + + mxr = XFS_BTREE_BLOCK_MAXRECS(bsz, xfs_alloc, 0); + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_alloc_key_t *k; + xfs_alloc_ptr_t *p; + + k = XFS_BTREE_KEY_ADDR(bsz, xfs_alloc, bt, i, mxr); + p = XFS_BTREE_PTR_ADDR(bsz, xfs_alloc, bt, i, mxr); + kdb_printf("key %d startblock 0x%x blockcount %d ptr 0x%x\n", + i, INT_GET(k->ar_startblock, ARCH_CONVERT), INT_GET(k->ar_blockcount, ARCH_CONVERT), *p); + } + } +} + +/* + * Print a bmap btree block. + */ +static void +xfs_btbmap(xfs_bmbt_block_t *bt, int bsz) +{ + int i; + + kdb_printf("magic 0x%x level %d numrecs %d leftsib %Lx ", + INT_GET(bt->bb_magic, ARCH_CONVERT), + INT_GET(bt->bb_level, ARCH_CONVERT), + INT_GET(bt->bb_numrecs, ARCH_CONVERT), + INT_GET(bt->bb_leftsib, ARCH_CONVERT)); + kdb_printf("rightsib %Lx\n", INT_GET(bt->bb_rightsib, ARCH_CONVERT)); + if (INT_ISZERO(bt->bb_level, ARCH_CONVERT)) { + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_bmbt_rec_64_t *r; + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int fl; + + r = (xfs_bmbt_rec_64_t *)XFS_BTREE_REC_ADDR(bsz, + xfs_bmbt, bt, i, 0); + xfs_convert_extent(r, &o, &s, &c, &fl); + kdb_printf("rec %d startoff %Ld ", i, o); + kdb_printf("startblock %Lx ", s); + kdb_printf("blockcount %Ld flag %d\n", c, fl); + } + } else { + int mxr; + + mxr = XFS_BTREE_BLOCK_MAXRECS(bsz, xfs_bmbt, 0); + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_bmbt_key_t *k; + xfs_bmbt_ptr_t *p; + + k = XFS_BTREE_KEY_ADDR(bsz, xfs_bmbt, bt, i, mxr); + p = XFS_BTREE_PTR_ADDR(bsz, xfs_bmbt, bt, i, mxr); + kdb_printf("key %d startoff %Ld ", + i, INT_GET(k->br_startoff, ARCH_CONVERT)); + kdb_printf("ptr %Lx\n", INT_GET(*p, ARCH_CONVERT)); + } + } +} + +/* + * Print an inode btree block. + */ +static void +xfs_btino(xfs_inobt_block_t *bt, int bsz) +{ + int i; + + kdb_printf("magic 0x%x level %d numrecs %d leftsib 0x%x rightsib 0x%x\n", + INT_GET(bt->bb_magic, ARCH_CONVERT), INT_GET(bt->bb_level, ARCH_CONVERT), INT_GET(bt->bb_numrecs, ARCH_CONVERT), + INT_GET(bt->bb_leftsib, ARCH_CONVERT), INT_GET(bt->bb_rightsib, ARCH_CONVERT)); + if (INT_ISZERO(bt->bb_level, ARCH_CONVERT)) { + + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_inobt_rec_t *r; + + r = XFS_BTREE_REC_ADDR(bsz, xfs_inobt, bt, i, 0); + kdb_printf("rec %d startino 0x%x freecount %d, free %Lx\n", + i, INT_GET(r->ir_startino, ARCH_CONVERT), INT_GET(r->ir_freecount, ARCH_CONVERT), + INT_GET(r->ir_free, ARCH_CONVERT)); + } + } else { + int mxr; + + mxr = XFS_BTREE_BLOCK_MAXRECS(bsz, xfs_inobt, 0); + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_inobt_key_t *k; + xfs_inobt_ptr_t *p; + + k = XFS_BTREE_KEY_ADDR(bsz, xfs_inobt, bt, i, mxr); + p = XFS_BTREE_PTR_ADDR(bsz, xfs_inobt, bt, i, mxr); + kdb_printf("key %d startino 0x%x ptr 0x%x\n", + i, INT_GET(k->ir_startino, ARCH_CONVERT), INT_GET(*p, ARCH_CONVERT)); + } + } +} + +/* + * Print a buf log item. + */ +static void +xfs_buf_item_print(xfs_buf_log_item_t *blip, int summary) +{ + static char *bli_flags[] = { + "hold", /* 0x1 */ + "dirty", /* 0x2 */ + "stale", /* 0x4 */ + "logged", /* 0x8 */ + "ialloc", /* 0x10 */ + 0 + }; + static char *blf_flags[] = { + "inode", /* 0x1 */ + "cancel", /* 0x2 */ + 0 + }; + + if (summary) { + kdb_printf("buf 0x%p blkno 0x%Lx ", blip->bli_buf, + blip->bli_format.blf_blkno); + printflags(blip->bli_flags, bli_flags, "flags:"); + kdb_printf("\n "); + xfsidbg_xbuf_real(blip->bli_buf, 1); + return; + } + kdb_printf("buf 0x%p recur %d refcount %d flags:", + blip->bli_buf, blip->bli_recur, + atomic_read(&blip->bli_refcount)); + printflags(blip->bli_flags, bli_flags, NULL); + kdb_printf("\n"); + kdb_printf("size %d blkno 0x%Lx len 0x%x map size %d map 0x%p\n", + blip->bli_format.blf_size, blip->bli_format.blf_blkno, + (uint) blip->bli_format.blf_len, blip->bli_format.blf_map_size, + &(blip->bli_format.blf_data_map[0])); + kdb_printf("blf flags: "); + printflags((uint)blip->bli_format.blf_flags, blf_flags, NULL); +#ifdef XFS_TRANS_DEBUG + kdb_printf("orig 0x%x logged 0x%x", + blip->bli_orig, blip->bli_logged); +#endif + kdb_printf("\n"); +} + +/* + * Convert an external extent descriptor to internal form. + */ +static void +xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op, xfs_dfsbno_t *sp, + xfs_dfilblks_t *cp, int *fp) +{ + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int flag; + + flag = (int)((INT_GET(rp->l0, ARCH_CONVERT)) >> (64 - 1 )); + o = ((xfs_fileoff_t)INT_GET(rp->l0, ARCH_CONVERT) & + (((__uint64_t)1 << ( 64 - 1 )) - 1) ) >> 9; + s = (((xfs_fsblock_t)INT_GET(rp->l0, ARCH_CONVERT) & (((__uint64_t)1 << ( 9 )) - 1) ) << 43) | + (((xfs_fsblock_t)INT_GET(rp->l1, ARCH_CONVERT)) >> 21); + c = (xfs_filblks_t)(INT_GET(rp->l1, ARCH_CONVERT) & (((__uint64_t)1 << ( 21 )) - 1) ); + *op = o; + *sp = s; + *cp = c; + *fp = flag; +} + + +/* + * Print an xfs_da_state_path structure. + */ +static void +xfs_dastate_path(xfs_da_state_path_t *p) +{ + int i; + + kdb_printf("active %d\n", p->active); + for (i = 0; i < XFS_DA_NODE_MAXDEPTH; i++) { + kdb_printf(" blk %d bp 0x%p blkno 0x%x", + i, p->blk[i].bp, p->blk[i].blkno); + kdb_printf(" index %d hashval 0x%x ", + p->blk[i].index, (uint_t)p->blk[i].hashval); + switch(p->blk[i].magic) { + case XFS_DA_NODE_MAGIC: kdb_printf("NODE\n"); break; + case XFS_DIR_LEAF_MAGIC: kdb_printf("DIR\n"); break; + case XFS_ATTR_LEAF_MAGIC: kdb_printf("ATTR\n"); break; + case XFS_DIR2_LEAFN_MAGIC: kdb_printf("DIR2\n"); break; + default: kdb_printf("type ??\n"); break; + } + } +} + + +/* + * Print an efd log item. + */ +static void +xfs_efd_item_print(xfs_efd_log_item_t *efdp, int summary) +{ + int i; + xfs_extent_t *ep; + + if (summary) { + kdb_printf("Extent Free Done: ID 0x%Lx nextents %d (at 0x%p)\n", + efdp->efd_format.efd_efi_id, + efdp->efd_format.efd_nextents, efdp); + return; + } + kdb_printf("size %d nextents %d next extent %d efip 0x%p\n", + efdp->efd_format.efd_size, efdp->efd_format.efd_nextents, + efdp->efd_next_extent, efdp->efd_efip); + kdb_printf("efi_id 0x%Lx\n", efdp->efd_format.efd_efi_id); + kdb_printf("efd extents:\n"); + ep = &(efdp->efd_format.efd_extents[0]); + for (i = 0; i < efdp->efd_next_extent; i++, ep++) { + kdb_printf(" block %Lx len %d\n", + ep->ext_start, ep->ext_len); + } +} + +/* + * Print an efi log item. + */ +static void +xfs_efi_item_print(xfs_efi_log_item_t *efip, int summary) +{ + int i; + xfs_extent_t *ep; + static char *efi_flags[] = { + "recovered", /* 0x1 */ + "committed", /* 0x2 */ + "cancelled", /* 0x4 */ + 0, + }; + + if (summary) { + kdb_printf("Extent Free Intention: ID 0x%Lx nextents %d (at 0x%p)\n", + efip->efi_format.efi_id, + efip->efi_format.efi_nextents, efip); + return; + } + kdb_printf("size %d nextents %d next extent %d\n", + efip->efi_format.efi_size, efip->efi_format.efi_nextents, + efip->efi_next_extent); + kdb_printf("id %Lx", efip->efi_format.efi_id); + printflags(efip->efi_flags, efi_flags, "flags :"); + kdb_printf("\n"); + kdb_printf("efi extents:\n"); + ep = &(efip->efi_format.efi_extents[0]); + for (i = 0; i < efip->efi_next_extent; i++, ep++) { + kdb_printf(" block %Lx len %d\n", + ep->ext_start, ep->ext_len); + } +} + +/* + * Format inode "format" into a static buffer & return it. + */ +static char * +xfs_fmtformat(xfs_dinode_fmt_t f) +{ + static char *t[] = { + "dev", + "local", + "extents", + "btree", + "uuid" + }; + + return t[f]; +} + +/* + * Format fsblock number into a static buffer & return it. + */ +static char * +xfs_fmtfsblock(xfs_fsblock_t bno, xfs_mount_t *mp) +{ + static char rval[50]; + + if (bno == NULLFSBLOCK) + sprintf(rval, "NULLFSBLOCK"); + else if (ISNULLSTARTBLOCK(bno)) + sprintf(rval, "NULLSTARTBLOCK(%Ld)", STARTBLOCKVAL(bno)); + else if (mp) + sprintf(rval, "%Ld[%x:%x]", (xfs_dfsbno_t)bno, + XFS_FSB_TO_AGNO(mp, bno), XFS_FSB_TO_AGBNO(mp, bno)); + else + sprintf(rval, "%Ld", (xfs_dfsbno_t)bno); + return rval; +} + +/* + * Format inode number into a static buffer & return it. + */ +static char * +xfs_fmtino(xfs_ino_t ino, xfs_mount_t *mp) +{ + static char rval[50]; + + if (mp) + sprintf(rval, "%llu[%x:%x:%x]", + (unsigned long long) ino, + XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGBNO(mp, ino), + XFS_INO_TO_OFFSET(mp, ino)); + else + sprintf(rval, "%llu", (unsigned long long) ino); + return rval; +} + +/* + * Format an lsn for printing into a static buffer & return it. + */ +static char * +xfs_fmtlsn(xfs_lsn_t *lsnp) +{ + uint *wordp; + uint *word2p; + static char buf[20]; + + wordp = (uint *)lsnp; + word2p = wordp++; + sprintf(buf, "[%u:%u]", *wordp, *word2p); + + return buf; +} + +/* + * Format file mode into a static buffer & return it. + */ +static char * +xfs_fmtmode(int m) +{ + static char rval[16]; + + sprintf(rval, "%c%c%c%c%c%c%c%c%c%c%c%c%c", + "?fc?dxb?r?l?S?m?"[(m & IFMT) >> 12], + m & ISUID ? 'u' : '-', + m & ISGID ? 'g' : '-', + m & ISVTX ? 'v' : '-', + m & IREAD ? 'r' : '-', + m & IWRITE ? 'w' : '-', + m & IEXEC ? 'x' : '-', + m & (IREAD >> 3) ? 'r' : '-', + m & (IWRITE >> 3) ? 'w' : '-', + m & (IEXEC >> 3) ? 'x' : '-', + m & (IREAD >> 6) ? 'r' : '-', + m & (IWRITE >> 6) ? 'w' : '-', + m & (IEXEC >> 6) ? 'x' : '-'); + return rval; +} + +/* + * Format a size into a static buffer & return it. + */ +static char * +xfs_fmtsize(size_t i) +{ + static char rval[20]; + + /* size_t is 32 bits in 32-bit kernel, 64 bits in 64-bit kernel */ + sprintf(rval, "0x%lx", (unsigned long) i); + return rval; +} + +/* + * Format a uuid into a static buffer & return it. + */ +static char * +xfs_fmtuuid(uuid_t *uu) +{ + static char rval[40]; + char *o = rval; + char *i = (unsigned char*)uu; + int b; + + for (b=0;b<16;b++) { + o+=sprintf(o, "%02x", *i++); + if (b==3||b==5||b==7||b==9) *o++='-'; + } + *o='\0'; + + return rval; +} + +/* + * Print an inode log item. + */ +static void +xfs_inode_item_print(xfs_inode_log_item_t *ilip, int summary) +{ + static char *ili_flags[] = { + "hold", /* 0x1 */ + "iolock excl", /* 0x2 */ + "iolock shrd", /* 0x4 */ + 0 + }; + static char *ilf_fields[] = { + "core", /* 0x001 */ + "ddata", /* 0x002 */ + "dexts", /* 0x004 */ + "dbroot", /* 0x008 */ + "dev", /* 0x010 */ + "uuid", /* 0x020 */ + "adata", /* 0x040 */ + "aext", /* 0x080 */ + "abroot", /* 0x100 */ + 0 + }; + + if (summary) { + kdb_printf("inode 0x%p logged %d ", + ilip->ili_inode, ilip->ili_logged); + printflags(ilip->ili_flags, ili_flags, "flags:"); + printflags(ilip->ili_format.ilf_fields, ilf_fields, "format:"); + printflags(ilip->ili_last_fields, ilf_fields, "lastfield:"); + kdb_printf("\n"); + return; + } + kdb_printf("inode 0x%p ino 0x%llu logged %d flags: ", + ilip->ili_inode, (unsigned long long) ilip->ili_format.ilf_ino, + ilip->ili_logged); + printflags(ilip->ili_flags, ili_flags, NULL); + kdb_printf("\n"); + kdb_printf("ilock recur %d iolock recur %d ext buf 0x%p\n", + ilip->ili_ilock_recur, ilip->ili_iolock_recur, + ilip->ili_extents_buf); +#ifdef XFS_TRANS_DEBUG + kdb_printf("root bytes %d root orig 0x%x\n", + ilip->ili_root_size, ilip->ili_orig_root); +#endif + kdb_printf("size %d fields: ", ilip->ili_format.ilf_size); + printflags(ilip->ili_format.ilf_fields, ilf_fields, "formatfield"); + kdb_printf(" last fields: "); + printflags(ilip->ili_last_fields, ilf_fields, "lastfield"); + kdb_printf("\n"); + kdb_printf(" flush lsn %s last lsn %s\n", + xfs_fmtlsn(&(ilip->ili_flush_lsn)), + xfs_fmtlsn(&(ilip->ili_last_lsn))); + kdb_printf("dsize %d, asize %d, rdev 0x%x\n", + ilip->ili_format.ilf_dsize, + ilip->ili_format.ilf_asize, + ilip->ili_format.ilf_u.ilfu_rdev); + kdb_printf("blkno 0x%Lx len 0x%x boffset 0x%x\n", + ilip->ili_format.ilf_blkno, + ilip->ili_format.ilf_len, + ilip->ili_format.ilf_boffset); +} + +/* + * Print a dquot log item. + */ +/* ARGSUSED */ +static void +xfs_dquot_item_print(xfs_dq_logitem_t *lip, int summary) +{ + kdb_printf("dquot 0x%p\n", + lip->qli_dquot); + +} + +/* + * Print a quotaoff log item. + */ +/* ARGSUSED */ +static void +xfs_qoff_item_print(xfs_qoff_logitem_t *lip, int summary) +{ + kdb_printf("start qoff item 0x%p flags 0x%x\n", + lip->qql_start_lip, lip->qql_format.qf_flags); + +} + +/* + * Print buffer full of inodes. + */ +static void +xfs_inodebuf(xfs_buf_t *bp) +{ + xfs_dinode_t *di; + int n, i; + + n = XFS_BUF_COUNT(bp) >> 8; + for (i = 0; i < n; i++) { + di = (xfs_dinode_t *)xfs_buf_offset(bp, + i * 256); + xfs_prdinode(di, 0, ARCH_CONVERT); + } +} + + +/* + * Print disk inode. + */ +static void +xfs_prdinode(xfs_dinode_t *di, int coreonly, int convert) +{ + xfs_prdinode_core(&di->di_core, convert); + if (!coreonly) + kdb_printf("next_unlinked 0x%x u@0x%p\n", + INT_GET(di->di_next_unlinked, convert), + &di->di_u); +} + +/* + * Print disk inode core. + */ +static void +xfs_prdinode_core(xfs_dinode_core_t *dip, int convert) +{ + static char *diflags[] = { + "realtime", /* XFS_DIFLAG_REALTIME */ + "prealloc", /* XFS_DIFLAG_PREALLOC */ + NULL + }; + + kdb_printf("magic 0x%x mode 0%o (%s) version 0x%x format 0x%x (%s)\n", + INT_GET(dip->di_magic, convert), + INT_GET(dip->di_mode, convert), + xfs_fmtmode(INT_GET(dip->di_mode, convert)), + INT_GET(dip->di_version, convert), + INT_GET(dip->di_format, convert), + xfs_fmtformat( + (xfs_dinode_fmt_t)INT_GET(dip->di_format, convert))); + kdb_printf("nlink 0x%x uid 0x%x gid 0x%x projid 0x%x\n", + INT_GET(dip->di_nlink, convert), + INT_GET(dip->di_uid, convert), + INT_GET(dip->di_gid, convert), + (uint)INT_GET(dip->di_projid, convert)); + kdb_printf("atime 0x%x:%x mtime 0x%x:%x ctime 0x%x:%x\n", + INT_GET(dip->di_atime.t_sec, convert), + INT_GET(dip->di_atime.t_nsec, convert), + INT_GET(dip->di_mtime.t_sec, convert), + INT_GET(dip->di_mtime.t_nsec, convert), + INT_GET(dip->di_ctime.t_sec, convert), + INT_GET(dip->di_ctime.t_nsec, convert)); + kdb_printf("size 0x%Lx ", INT_GET(dip->di_size, convert)); + kdb_printf("nblocks %Ld extsize 0x%x nextents 0x%x anextents 0x%x\n", + INT_GET(dip->di_nblocks, convert), + INT_GET(dip->di_extsize, convert), + INT_GET(dip->di_nextents, convert), + INT_GET(dip->di_anextents, convert)); + kdb_printf("forkoff %d aformat 0x%x (%s) dmevmask 0x%x dmstate 0x%x ", + INT_GET(dip->di_forkoff, convert), + INT_GET(dip->di_aformat, convert), + xfs_fmtformat( + (xfs_dinode_fmt_t)INT_GET(dip->di_aformat, convert)), + INT_GET(dip->di_dmevmask, convert), + INT_GET(dip->di_dmstate, convert)); + printflags(INT_GET(dip->di_flags, convert), diflags, "flags"); + kdb_printf("gen 0x%x\n", INT_GET(dip->di_gen, convert)); +} + +/* + * Print xfs extent list for a fork. + */ +static void +xfs_xexlist_fork(xfs_inode_t *ip, int whichfork) +{ + int nextents, i; + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int flag; + xfs_ifork_t *ifp; + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (ifp->if_flags & XFS_IFEXTENTS) { + nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_64_t); + kdb_printf("inode 0x%p %cf extents 0x%p nextents 0x%x\n", + ip, "da"[whichfork], ifp->if_u1.if_extents, nextents); + for (i = 0; i < nextents; i++) { + xfs_convert_extent( + (xfs_bmbt_rec_64_t *)&ifp->if_u1.if_extents[i], + &o, &s, &c, &flag); + kdb_printf( + "%d: startoff %Ld startblock %s blockcount %Ld flag %d\n", + i, o, xfs_fmtfsblock(s, ip->i_mount), c, flag); + } + } +} + +static void +xfs_xnode_fork(char *name, xfs_ifork_t *f) +{ + static char *tab_flags[] = { + "inline", /* XFS_IFINLINE */ + "extents", /* XFS_IFEXTENTS */ + "broot", /* XFS_IFBROOT */ + NULL + }; + int *p; + + kdb_printf("%s fork", name); + if (f == NULL) { + kdb_printf(" empty\n"); + return; + } else + kdb_printf("\n"); + kdb_printf(" bytes %s ", xfs_fmtsize(f->if_bytes)); + kdb_printf("real_bytes %s lastex 0x%x u1:%s 0x%p\n", + xfs_fmtsize(f->if_real_bytes), f->if_lastex, + f->if_flags & XFS_IFINLINE ? "data" : "extents", + f->if_flags & XFS_IFINLINE ? + f->if_u1.if_data : + (char *)f->if_u1.if_extents); + kdb_printf(" broot 0x%p broot_bytes %s ext_max %d ", + f->if_broot, xfs_fmtsize(f->if_broot_bytes), f->if_ext_max); + printflags(f->if_flags, tab_flags, "flags"); + kdb_printf("\n"); + kdb_printf(" u2"); + for (p = (int *)&f->if_u2; + p < (int *)((char *)&f->if_u2 + XFS_INLINE_DATA); + p++) + kdb_printf(" 0x%x", *p); + kdb_printf("\n"); +} + +/* + * Command-level xfs-idbg functions. + */ + +/* + * Print xfs allocation group freespace header. + */ +static void +xfsidbg_xagf(xfs_agf_t *agf) +{ + kdb_printf("magicnum 0x%x versionnum 0x%x seqno 0x%x length 0x%x\n", + INT_GET(agf->agf_magicnum, ARCH_CONVERT), + INT_GET(agf->agf_versionnum, ARCH_CONVERT), + INT_GET(agf->agf_seqno, ARCH_CONVERT), + INT_GET(agf->agf_length, ARCH_CONVERT)); + kdb_printf("roots b 0x%x c 0x%x levels b %d c %d\n", + INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), + INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_BNO], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_CNT], ARCH_CONVERT)); + kdb_printf("flfirst %d fllast %d flcount %d freeblks %d longest %d\n", + INT_GET(agf->agf_flfirst, ARCH_CONVERT), + INT_GET(agf->agf_fllast, ARCH_CONVERT), + INT_GET(agf->agf_flcount, ARCH_CONVERT), + INT_GET(agf->agf_freeblks, ARCH_CONVERT), + INT_GET(agf->agf_longest, ARCH_CONVERT)); +} + +/* + * Print xfs allocation group inode header. + */ +static void +xfsidbg_xagi(xfs_agi_t *agi) +{ + int i; + int j; + + kdb_printf("magicnum 0x%x versionnum 0x%x seqno 0x%x length 0x%x\n", + INT_GET(agi->agi_magicnum, ARCH_CONVERT), + INT_GET(agi->agi_versionnum, ARCH_CONVERT), + INT_GET(agi->agi_seqno, ARCH_CONVERT), + INT_GET(agi->agi_length, ARCH_CONVERT)); + kdb_printf("count 0x%x root 0x%x level 0x%x\n", + INT_GET(agi->agi_count, ARCH_CONVERT), + INT_GET(agi->agi_root, ARCH_CONVERT), + INT_GET(agi->agi_level, ARCH_CONVERT)); + kdb_printf("freecount 0x%x newino 0x%x dirino 0x%x\n", + INT_GET(agi->agi_freecount, ARCH_CONVERT), + INT_GET(agi->agi_newino, ARCH_CONVERT), + INT_GET(agi->agi_dirino, ARCH_CONVERT)); + + kdb_printf("unlinked buckets\n"); + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { + for (j = 0; j < 4; j++, i++) { + kdb_printf("0x%08x ", + INT_GET(agi->agi_unlinked[i], ARCH_CONVERT)); + } + kdb_printf("\n"); + } +} + + +/* + * Print an allocation argument structure for XFS. + */ +static void +xfsidbg_xalloc(xfs_alloc_arg_t *args) +{ + kdb_printf("tp 0x%p mp 0x%p agbp 0x%p pag 0x%p fsbno %s\n", + args->tp, args->mp, args->agbp, args->pag, + xfs_fmtfsblock(args->fsbno, args->mp)); + kdb_printf("agno 0x%x agbno 0x%x minlen 0x%x maxlen 0x%x mod 0x%x\n", + args->agno, args->agbno, args->minlen, args->maxlen, args->mod); + kdb_printf("prod 0x%x minleft 0x%x total 0x%x alignment 0x%x\n", + args->prod, args->minleft, args->total, args->alignment); + kdb_printf("minalignslop 0x%x len 0x%x type %s otype %s wasdel %d\n", + args->minalignslop, args->len, xfs_alloctype[args->type], + xfs_alloctype[args->otype], args->wasdel); + kdb_printf("wasfromfl %d isfl %d userdata %d\n", + args->wasfromfl, args->isfl, args->userdata); +} + + + +/* + * Print an attr_list() context structure. + */ +static void +xfsidbg_xattrcontext(xfs_attr_list_context_t *context) +{ + static char *attr_arg_flags[] = { + "DONTFOLLOW", /* 0x0001 */ + "?", /* 0x0002 */ + "?", /* 0x0004 */ + "?", /* 0x0008 */ + "CREATE", /* 0x0010 */ + "?", /* 0x0020 */ + "?", /* 0x0040 */ + "?", /* 0x0080 */ + "?", /* 0x0100 */ + "?", /* 0x0200 */ + "?", /* 0x0400 */ + "?", /* 0x0800 */ + "KERNOTIME", /* 0x1000 */ + NULL + }; + + kdb_printf("dp 0x%p, dupcnt %d, resynch %d", + context->dp, context->dupcnt, context->resynch); + printflags((__psunsigned_t)context->flags, attr_arg_flags, ", flags"); + kdb_printf("\ncursor h/b/o 0x%x/0x%x/%d -- p/p/i 0x%x/0x%x/0x%x\n", + context->cursor->hashval, context->cursor->blkno, + context->cursor->offset, context->cursor->pad1, + context->cursor->pad2, context->cursor->initted); + kdb_printf("alist 0x%p, bufsize 0x%x, count %d, firstu 0x%x\n", + context->alist, context->bufsize, context->count, + context->firstu); +} + +/* + * Print attribute leaf block. + */ +static void +xfsidbg_xattrleaf(xfs_attr_leafblock_t *leaf) +{ + xfs_attr_leaf_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_attr_leaf_map_t *m; + xfs_attr_leaf_entry_t *e; + xfs_attr_leaf_name_local_t *l; + xfs_attr_leaf_name_remote_t *r; + int j, k; + + h = &leaf->hdr; + i = &h->info; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + i->forw, i->back, i->magic); + kdb_printf("hdr count %d usedbytes %d firstused %d holes %d\n", + INT_GET(h->count, ARCH_CONVERT), + INT_GET(h->usedbytes, ARCH_CONVERT), + INT_GET(h->firstused, ARCH_CONVERT), h->holes); + for (j = 0, m = h->freemap; j < XFS_ATTR_LEAF_MAPSIZE; j++, m++) { + kdb_printf("hdr freemap %d base %d size %d\n", + j, INT_GET(m->base, ARCH_CONVERT), + INT_GET(m->size, ARCH_CONVERT)); + } + for (j = 0, e = leaf->entries; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + kdb_printf("[%2d] hash 0x%x nameidx %d flags 0x%x", + j, INT_GET(e->hashval, ARCH_CONVERT), + INT_GET(e->nameidx, ARCH_CONVERT), e->flags); + if (e->flags & XFS_ATTR_LOCAL) + kdb_printf("LOCAL "); + if (e->flags & XFS_ATTR_ROOT) + kdb_printf("ROOT "); + if (e->flags & XFS_ATTR_INCOMPLETE) + kdb_printf("INCOMPLETE "); + k = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_INCOMPLETE); + if ((e->flags & k) != 0) + kdb_printf("0x%x", e->flags & k); + kdb_printf(">\n name \""); + if (e->flags & XFS_ATTR_LOCAL) { + l = XFS_ATTR_LEAF_NAME_LOCAL(leaf, j); + for (k = 0; k < l->namelen; k++) + kdb_printf("%c", l->nameval[k]); + kdb_printf("\"(%d) value \"", l->namelen); + for (k = 0; (k < INT_GET(l->valuelen, ARCH_CONVERT)) && (k < 32); k++) + kdb_printf("%c", l->nameval[l->namelen + k]); + if (k == 32) + kdb_printf("..."); + kdb_printf("\"(%d)\n", + INT_GET(l->valuelen, ARCH_CONVERT)); + } else { + r = XFS_ATTR_LEAF_NAME_REMOTE(leaf, j); + for (k = 0; k < r->namelen; k++) + kdb_printf("%c", r->name[k]); + kdb_printf("\"(%d) value blk 0x%x len %d\n", + r->namelen, + INT_GET(r->valueblk, ARCH_CONVERT), + INT_GET(r->valuelen, ARCH_CONVERT)); + } + } +} + +/* + * Print a shortform attribute list. + */ +static void +xfsidbg_xattrsf(xfs_attr_shortform_t *s) +{ + xfs_attr_sf_hdr_t *sfh; + xfs_attr_sf_entry_t *sfe; + int i, j; + + sfh = &s->hdr; + kdb_printf("hdr count %d\n", INT_GET(sfh->count, ARCH_CONVERT)); + for (i = 0, sfe = s->list; i < INT_GET(sfh->count, ARCH_CONVERT); i++) { + kdb_printf("entry %d namelen %d name \"", i, sfe->namelen); + for (j = 0; j < sfe->namelen; j++) + kdb_printf("%c", sfe->nameval[j]); + kdb_printf("\" valuelen %d value \"", INT_GET(sfe->valuelen, ARCH_CONVERT)); + for (j = 0; (j < INT_GET(sfe->valuelen, ARCH_CONVERT)) && (j < 32); j++) + kdb_printf("%c", sfe->nameval[sfe->namelen + j]); + if (j == 32) + kdb_printf("..."); + kdb_printf("\"\n"); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + } +} + + +/* + * Print xfs bmap internal record + */ +static void +xfsidbg_xbirec(xfs_bmbt_irec_t *r) +{ + kdb_printf( + "startoff %Ld startblock %Lx blockcount %Ld state %Ld\n", + (__uint64_t)r->br_startoff, + (__uint64_t)r->br_startblock, + (__uint64_t)r->br_blockcount, + (__uint64_t)r->br_state); +} + + +/* + * Print a bmap alloc argument structure for XFS. + */ +static void +xfsidbg_xbmalla(xfs_bmalloca_t *a) +{ + kdb_printf("tp 0x%p ip 0x%p eof %d prevp 0x%p\n", + a->tp, a->ip, a->eof, a->prevp); + kdb_printf("gotp 0x%p firstblock %s alen %d total %d\n", + a->gotp, xfs_fmtfsblock(a->firstblock, a->ip->i_mount), + a->alen, a->total); + kdb_printf("off %s wasdel %d userdata %d minlen %d\n", + xfs_fmtfsblock(a->off, a->ip->i_mount), a->wasdel, + a->userdata, a->minlen); + kdb_printf("minleft %d low %d rval %s aeof %d\n", + a->minleft, a->low, xfs_fmtfsblock(a->rval, a->ip->i_mount), + a->aeof); +} + + +/* + * Print xfs bmap record + */ +static void +xfsidbg_xbrec(xfs_bmbt_rec_64_t *r) +{ + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int flag; + + xfs_convert_extent(r, &o, &s, &c, &flag); + kdb_printf("startoff %Ld startblock %Lx blockcount %Ld flag %d\n", + o, s, c, flag); +} + +/* + * Print an xfs in-inode bmap btree root (data fork). + */ +static void +xfsidbg_xbroot(xfs_inode_t *ip) +{ + xfs_broot(ip, &ip->i_df); +} + +/* + * Print an xfs in-inode bmap btree root (attribute fork). + */ +static void +xfsidbg_xbroota(xfs_inode_t *ip) +{ + if (ip->i_afp) + xfs_broot(ip, ip->i_afp); +} + +/* + * Print xfs btree cursor. + */ +static void +xfsidbg_xbtcur(xfs_btree_cur_t *c) +{ + int l; + + kdb_printf("tp 0x%p mp 0x%p\n", + c->bc_tp, + c->bc_mp); + if (c->bc_btnum == XFS_BTNUM_BMAP) { + kdb_printf("rec.b "); + xfsidbg_xbirec(&c->bc_rec.b); + } else if (c->bc_btnum == XFS_BTNUM_INO) { + kdb_printf("rec.i startino 0x%x freecount 0x%x free %Lx\n", + c->bc_rec.i.ir_startino, c->bc_rec.i.ir_freecount, + c->bc_rec.i.ir_free); + } else { + kdb_printf("rec.a startblock 0x%x blockcount 0x%x\n", + c->bc_rec.a.ar_startblock, + c->bc_rec.a.ar_blockcount); + } + kdb_printf("bufs"); + for (l = 0; l < c->bc_nlevels; l++) + kdb_printf(" 0x%p", c->bc_bufs[l]); + kdb_printf("\n"); + kdb_printf("ptrs"); + for (l = 0; l < c->bc_nlevels; l++) + kdb_printf(" 0x%x", c->bc_ptrs[l]); + kdb_printf(" ra"); + for (l = 0; l < c->bc_nlevels; l++) + kdb_printf(" %d", c->bc_ra[l]); + kdb_printf("\n"); + kdb_printf("nlevels %d btnum %s blocklog %d\n", + c->bc_nlevels, + c->bc_btnum == XFS_BTNUM_BNO ? "bno" : + (c->bc_btnum == XFS_BTNUM_CNT ? "cnt" : + (c->bc_btnum == XFS_BTNUM_BMAP ? "bmap" : "ino")), + c->bc_blocklog); + if (c->bc_btnum == XFS_BTNUM_BMAP) { + kdb_printf("private forksize 0x%x whichfork %d ip 0x%p flags %d\n", + c->bc_private.b.forksize, + c->bc_private.b.whichfork, + c->bc_private.b.ip, + c->bc_private.b.flags); + kdb_printf("private firstblock %s flist 0x%p allocated 0x%x\n", + xfs_fmtfsblock(c->bc_private.b.firstblock, c->bc_mp), + c->bc_private.b.flist, + c->bc_private.b.allocated); + } else if (c->bc_btnum == XFS_BTNUM_INO) { + kdb_printf("private agbp 0x%p agno 0x%x\n", + c->bc_private.i.agbp, + c->bc_private.i.agno); + } else { + kdb_printf("private agbp 0x%p agno 0x%x\n", + c->bc_private.a.agbp, + c->bc_private.a.agno); + } +} + +/* + * Figure out what kind of xfs block the buffer contains, + * and invoke a print routine. + */ +static void +xfsidbg_xbuf(xfs_buf_t *bp) +{ + xfsidbg_xbuf_real(bp, 0); +} + +/* + * Figure out what kind of xfs block the buffer contains, + * and invoke a print routine (if asked to). + */ +static void +xfsidbg_xbuf_real(xfs_buf_t *bp, int summary) +{ + void *d; + xfs_agf_t *agf; + xfs_agi_t *agi; + xfs_sb_t *sb; + xfs_alloc_block_t *bta; + xfs_bmbt_block_t *btb; + xfs_inobt_block_t *bti; + xfs_attr_leafblock_t *aleaf; + xfs_dir_leafblock_t *dleaf; + xfs_da_intnode_t *node; + xfs_dinode_t *di; + xfs_disk_dquot_t *dqb; + xfs_dir2_block_t *d2block; + xfs_dir2_data_t *d2data; + xfs_dir2_leaf_t *d2leaf; + xfs_dir2_free_t *d2free; + + d = XFS_BUF_PTR(bp); + if (INT_GET((agf = d)->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC) { + if (summary) { + kdb_printf("freespace hdr for AG %d (at 0x%p)\n", + INT_GET(agf->agf_seqno, ARCH_CONVERT), agf); + } else { + kdb_printf("buf 0x%p agf 0x%p\n", bp, agf); + xfsidbg_xagf(agf); + } + } else if (INT_GET((agi = d)->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC) { + if (summary) { + kdb_printf("Inode hdr for AG %d (at 0x%p)\n", + INT_GET(agi->agi_seqno, ARCH_CONVERT), agi); + } else { + kdb_printf("buf 0x%p agi 0x%p\n", bp, agi); + xfsidbg_xagi(agi); + } + } else if (INT_GET((bta = d)->bb_magic, ARCH_CONVERT) == XFS_ABTB_MAGIC) { + if (summary) { + kdb_printf("Alloc BNO Btree blk, level %d (at 0x%p)\n", + INT_GET(bta->bb_level, ARCH_CONVERT), bta); + } else { + kdb_printf("buf 0x%p abtbno 0x%p\n", bp, bta); + xfs_btalloc(bta, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((bta = d)->bb_magic, ARCH_CONVERT) == XFS_ABTC_MAGIC) { + if (summary) { + kdb_printf("Alloc COUNT Btree blk, level %d (at 0x%p)\n", + INT_GET(bta->bb_level, ARCH_CONVERT), bta); + } else { + kdb_printf("buf 0x%p abtcnt 0x%p\n", bp, bta); + xfs_btalloc(bta, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((btb = d)->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC) { + if (summary) { + kdb_printf("Bmap Btree blk, level %d (at 0x%p)\n", + INT_GET(btb->bb_level, ARCH_CONVERT), btb); + } else { + kdb_printf("buf 0x%p bmapbt 0x%p\n", bp, btb); + xfs_btbmap(btb, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((bti = d)->bb_magic, ARCH_CONVERT) == XFS_IBT_MAGIC) { + if (summary) { + kdb_printf("Inode Btree blk, level %d (at 0x%p)\n", + INT_GET(bti->bb_level, ARCH_CONVERT), bti); + } else { + kdb_printf("buf 0x%p inobt 0x%p\n", bp, bti); + xfs_btino(bti, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((aleaf = d)->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { + if (summary) { + kdb_printf("Attr Leaf, 1st hash 0x%x (at 0x%p)\n", + INT_GET(aleaf->entries[0].hashval, ARCH_CONVERT), aleaf); + } else { + kdb_printf("buf 0x%p attr leaf 0x%p\n", bp, aleaf); + xfsidbg_xattrleaf(aleaf); + } + } else if (INT_GET((dleaf = d)->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + if (summary) { + kdb_printf("Dir Leaf, 1st hash 0x%x (at 0x%p)\n", + dleaf->entries[0].hashval, dleaf); + } else { + kdb_printf("buf 0x%p dir leaf 0x%p\n", bp, dleaf); + xfsidbg_xdirleaf(dleaf); + } + } else if (INT_GET((node = d)->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + if (summary) { + kdb_printf("Dir/Attr Node, level %d, 1st hash 0x%x (at 0x%p)\n", + node->hdr.level, node->btree[0].hashval, node); + } else { + kdb_printf("buf 0x%p dir/attr node 0x%p\n", bp, node); + xfsidbg_xdanode(node); + } + } else if (INT_GET((di = d)->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC) { + if (summary) { + kdb_printf("Disk Inode (at 0x%p)\n", di); + } else { + kdb_printf("buf 0x%p dinode 0x%p\n", bp, di); + xfs_inodebuf(bp); + } + } else if (INT_GET((sb = d)->sb_magicnum, ARCH_CONVERT) == XFS_SB_MAGIC) { + if (summary) { + kdb_printf("Superblock (at 0x%p)\n", sb); + } else { + kdb_printf("buf 0x%p sb 0x%p\n", bp, sb); + /* SB in a buffer - we need to convert */ + xfsidbg_xsb(sb, 1); + } + } else if ((dqb = d)->d_magic == XFS_DQUOT_MAGIC) { +#define XFSIDBG_DQTYPESTR(d) \ + ((INT_GET((d)->d_flags, ARCH_CONVERT) & XFS_DQ_USER) ? "USR" : \ + ((INT_GET((d)->d_flags, ARCH_CONVERT) & XFS_DQ_GROUP) ? "GRP" : "???")) + kdb_printf("Quota blk starting ID [%d], type %s at 0x%p\n", + INT_GET(dqb->d_id, ARCH_CONVERT), XFSIDBG_DQTYPESTR(dqb), dqb); + + } else if (INT_GET((d2block = d)->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + if (summary) { + kdb_printf("Dir2 block (at 0x%p)\n", d2block); + } else { + kdb_printf("buf 0x%p dir2 block 0x%p\n", bp, d2block); + xfs_dir2data((void *)d2block, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((d2data = d)->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) { + if (summary) { + kdb_printf("Dir2 data (at 0x%p)\n", d2data); + } else { + kdb_printf("buf 0x%p dir2 data 0x%p\n", bp, d2data); + xfs_dir2data((void *)d2data, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((d2leaf = d)->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC) { + if (summary) { + kdb_printf("Dir2 leaf(1) (at 0x%p)\n", d2leaf); + } else { + kdb_printf("buf 0x%p dir2 leaf 0x%p\n", bp, d2leaf); + xfs_dir2leaf(d2leaf, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET(d2leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + if (summary) { + kdb_printf("Dir2 leaf(n) (at 0x%p)\n", d2leaf); + } else { + kdb_printf("buf 0x%p dir2 leaf 0x%p\n", bp, d2leaf); + xfs_dir2leaf(d2leaf, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((d2free = d)->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC) { + if (summary) { + kdb_printf("Dir2 free (at 0x%p)\n", d2free); + } else { + kdb_printf("buf 0x%p dir2 free 0x%p\n", bp, d2free); + xfsidbg_xdir2free(d2free); + } + } else { + kdb_printf("buf 0x%p unknown 0x%p\n", bp, d); + } +} + + +/* + * Print an xfs_da_args structure. + */ +static void +xfsidbg_xdaargs(xfs_da_args_t *n) +{ + char *ch; + int i; + + kdb_printf(" name \""); + for (i = 0; i < n->namelen; i++) { + kdb_printf("%c", n->name[i]); + } + kdb_printf("\"(%d) value ", n->namelen); + if (n->value) { + kdb_printf("\""); + ch = n->value; + for (i = 0; (i < n->valuelen) && (i < 32); ch++, i++) { + switch(*ch) { + case '\n': kdb_printf("\n"); break; + case '\b': kdb_printf("\b"); break; + case '\t': kdb_printf("\t"); break; + default: kdb_printf("%c", *ch); break; + } + } + if (i == 32) + kdb_printf("..."); + kdb_printf("\"(%d)\n", n->valuelen); + } else { + kdb_printf("(NULL)(%d)\n", n->valuelen); + } + kdb_printf(" hashval 0x%x whichfork %d flags <", + (uint_t)n->hashval, n->whichfork); + if (n->flags & ATTR_ROOT) + kdb_printf("ROOT "); + if (n->flags & ATTR_CREATE) + kdb_printf("CREATE "); + if (n->flags & ATTR_REPLACE) + kdb_printf("REPLACE "); + if (n->flags & XFS_ATTR_INCOMPLETE) + kdb_printf("INCOMPLETE "); + i = ~(ATTR_ROOT | ATTR_CREATE | ATTR_REPLACE | XFS_ATTR_INCOMPLETE); + if ((n->flags & i) != 0) + kdb_printf("0x%x", n->flags & i); + kdb_printf(">\n"); + kdb_printf(" rename %d justcheck %d addname %d oknoent %d\n", + n->rename, n->justcheck, n->addname, n->oknoent); + kdb_printf(" leaf: blkno %d index %d rmtblkno %d rmtblkcnt %d\n", + n->blkno, n->index, n->rmtblkno, n->rmtblkcnt); + kdb_printf(" leaf2: blkno %d index %d rmtblkno %d rmtblkcnt %d\n", + n->blkno2, n->index2, n->rmtblkno2, n->rmtblkcnt2); + kdb_printf(" inumber %llu dp 0x%p firstblock 0x%p flist 0x%p\n", + (unsigned long long) n->inumber, + n->dp, n->firstblock, n->flist); + kdb_printf(" trans 0x%p total %d\n", + n->trans, n->total); +} + +/* + * Print a da buffer structure. + */ +static void +xfsidbg_xdabuf(xfs_dabuf_t *dabuf) +{ + int i; + + kdb_printf("nbuf %d dirty %d bbcount %d data 0x%p bps", + dabuf->nbuf, dabuf->dirty, dabuf->bbcount, dabuf->data); + for (i = 0; i < dabuf->nbuf; i++) + kdb_printf(" %d:0x%p", i, dabuf->bps[i]); + kdb_printf("\n"); +#ifdef XFS_DABUF_DEBUG + kdb_printf(" ra 0x%x prev 0x%x next 0x%x dev 0x%x blkno 0x%x\n", + dabuf->ra, dabuf->prev, dabuf->next, dabuf->dev, dabuf->blkno); +#endif +} + +/* + * Print a directory/attribute internal node block. + */ +static void +xfsidbg_xdanode(xfs_da_intnode_t *node) +{ + xfs_da_node_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_da_node_entry_t *e; + int j; + + h = &node->hdr; + i = &h->info; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + INT_GET(i->forw, ARCH_CONVERT), INT_GET(i->back, ARCH_CONVERT), INT_GET(i->magic, ARCH_CONVERT)); + kdb_printf("hdr count %d level %d\n", + INT_GET(h->count, ARCH_CONVERT), INT_GET(h->level, ARCH_CONVERT)); + for (j = 0, e = node->btree; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + kdb_printf("btree %d hashval 0x%x before 0x%x\n", + j, (uint_t)INT_GET(e->hashval, ARCH_CONVERT), INT_GET(e->before, ARCH_CONVERT)); + } +} + +/* + * Print an xfs_da_state_blk structure. + */ +static void +xfsidbg_xdastate(xfs_da_state_t *s) +{ + xfs_da_state_blk_t *eblk; + + kdb_printf("args 0x%p mp 0x%p blocksize %d inleaf %d\n", + s->args, s->mp, s->blocksize, s->inleaf); + if (s->args) + xfsidbg_xdaargs(s->args); + + kdb_printf("path: "); + xfs_dastate_path(&s->path); + + kdb_printf("altpath: "); + xfs_dastate_path(&s->altpath); + + eblk = &s->extrablk; + kdb_printf("extra: valid %d, after %d\n", s->extravalid, s->extraafter); + kdb_printf(" bp 0x%p blkno 0x%x ", eblk->bp, eblk->blkno); + kdb_printf("index %d hashval 0x%x\n", eblk->index, (uint_t)eblk->hashval); +} + +/* + * Print a directory leaf block. + */ +static void +xfsidbg_xdirleaf(xfs_dir_leafblock_t *leaf) +{ + xfs_dir_leaf_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_dir_leaf_map_t *m; + xfs_dir_leaf_entry_t *e; + xfs_dir_leaf_name_t *n; + int j, k; + xfs_ino_t ino; + + h = &leaf->hdr; + i = &h->info; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + INT_GET(i->forw, ARCH_CONVERT), INT_GET(i->back, ARCH_CONVERT), INT_GET(i->magic, ARCH_CONVERT)); + kdb_printf("hdr count %d namebytes %d firstused %d holes %d\n", + INT_GET(h->count, ARCH_CONVERT), INT_GET(h->namebytes, ARCH_CONVERT), INT_GET(h->firstused, ARCH_CONVERT), h->holes); + for (j = 0, m = h->freemap; j < XFS_DIR_LEAF_MAPSIZE; j++, m++) { + kdb_printf("hdr freemap %d base %d size %d\n", + j, INT_GET(m->base, ARCH_CONVERT), INT_GET(m->size, ARCH_CONVERT)); + } + for (j = 0, e = leaf->entries; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + n = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(e->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_GET_DIRINO_ARCH(&n->inumber, &ino, ARCH_CONVERT); + kdb_printf("leaf %d hashval 0x%x nameidx %d inumber %llu ", + j, (uint_t)INT_GET(e->hashval, ARCH_CONVERT), + INT_GET(e->nameidx, ARCH_CONVERT), + (unsigned long long)ino); + kdb_printf("namelen %d name \"", e->namelen); + for (k = 0; k < e->namelen; k++) + kdb_printf("%c", n->name[k]); + kdb_printf("\"\n"); + } +} + +/* + * Print a directory v2 data block, single or multiple. + */ +static void +xfs_dir2data(void *addr, int size) +{ + xfs_dir2_data_t *db; + xfs_dir2_block_t *bb; + xfs_dir2_data_hdr_t *h; + xfs_dir2_data_free_t *m; + xfs_dir2_data_entry_t *e; + xfs_dir2_data_unused_t *u; + xfs_dir2_leaf_entry_t *l=NULL; + int j, k; + char *p; + char *t; + xfs_dir2_block_tail_t *tail=NULL; + + db = (xfs_dir2_data_t *)addr; + bb = (xfs_dir2_block_t *)addr; + h = &db->hdr; + kdb_printf("hdr magic 0x%x (%s)\nhdr bestfree", INT_GET(h->magic, ARCH_CONVERT), + INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ? "DATA" : + (INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC ? "BLOCK" : "")); + for (j = 0, m = h->bestfree; j < XFS_DIR2_DATA_FD_COUNT; j++, m++) { + kdb_printf(" %d: 0x%x@0x%x", j, INT_GET(m->length, ARCH_CONVERT), INT_GET(m->offset, ARCH_CONVERT)); + } + kdb_printf("\n"); + if (INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) + t = (char *)db + size; + else { + /* XFS_DIR2_BLOCK_TAIL_P */ + tail = (xfs_dir2_block_tail_t *) + ((char *)bb + size - sizeof(xfs_dir2_block_tail_t)); + l = XFS_DIR2_BLOCK_LEAF_P_ARCH(tail, ARCH_CONVERT); + t = (char *)l; + } + for (p = (char *)(h + 1); p < t; ) { + u = (xfs_dir2_data_unused_t *)p; + if (u->freetag == XFS_DIR2_DATA_FREE_TAG) { + kdb_printf("0x%lx unused freetag 0x%x length 0x%x tag 0x%x\n", + (unsigned long) (p - (char *)addr), + INT_GET(u->freetag, ARCH_CONVERT), + INT_GET(u->length, ARCH_CONVERT), + INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(u, ARCH_CONVERT), ARCH_CONVERT)); + p += INT_GET(u->length, ARCH_CONVERT); + continue; + } + e = (xfs_dir2_data_entry_t *)p; + kdb_printf("0x%lx entry inumber %llu namelen %d name \"", + (unsigned long) (p - (char *)addr), + (unsigned long long) INT_GET(e->inumber, ARCH_CONVERT), + e->namelen); + for (k = 0; k < e->namelen; k++) + kdb_printf("%c", e->name[k]); + kdb_printf("\" tag 0x%x\n", INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(e), ARCH_CONVERT)); + p += XFS_DIR2_DATA_ENTSIZE(e->namelen); + } + if (INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) + return; + for (j = 0; j < INT_GET(tail->count, ARCH_CONVERT); j++, l++) { + kdb_printf("0x%lx leaf %d hashval 0x%x address 0x%x (byte 0x%x)\n", + (unsigned long) ((char *)l - (char *)addr), j, + (uint_t)INT_GET(l->hashval, ARCH_CONVERT), + INT_GET(l->address, ARCH_CONVERT), + /* XFS_DIR2_DATAPTR_TO_BYTE */ + INT_GET(l->address, ARCH_CONVERT) << XFS_DIR2_DATA_ALIGN_LOG); + } + kdb_printf("0x%lx tail count %d\n", + (unsigned long) ((char *)tail - (char *)addr), + INT_GET(tail->count, ARCH_CONVERT)); +} + +static void +xfs_dir2leaf(xfs_dir2_leaf_t *leaf, int size) +{ + xfs_dir2_leaf_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_dir2_leaf_entry_t *e; + xfs_dir2_data_off_t *b; + xfs_dir2_leaf_tail_t *t; + int j; + + h = &leaf->hdr; + i = &h->info; + e = leaf->ents; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + INT_GET(i->forw, ARCH_CONVERT), INT_GET(i->back, ARCH_CONVERT), INT_GET(i->magic, ARCH_CONVERT)); + kdb_printf("hdr count %d stale %d\n", INT_GET(h->count, ARCH_CONVERT), INT_GET(h->stale, ARCH_CONVERT)); + for (j = 0; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + kdb_printf("0x%lx ent %d hashval 0x%x address 0x%x (byte 0x%x)\n", + (unsigned long) ((char *)e - (char *)leaf), j, + (uint_t)INT_GET(e->hashval, ARCH_CONVERT), + INT_GET(e->address, ARCH_CONVERT), + /* XFS_DIR2_DATAPTR_TO_BYTE */ + INT_GET(e->address, ARCH_CONVERT) << XFS_DIR2_DATA_ALIGN_LOG); + } + if (INT_GET(i->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) + return; + /* XFS_DIR2_LEAF_TAIL_P */ + t = (xfs_dir2_leaf_tail_t *)((char *)leaf + size - sizeof(*t)); + b = XFS_DIR2_LEAF_BESTS_P_ARCH(t, ARCH_CONVERT); + for (j = 0; j < INT_GET(t->bestcount, ARCH_CONVERT); j++, b++) { + kdb_printf("0x%lx best %d 0x%x\n", + (unsigned long) ((char *)b - (char *)leaf), j, + INT_GET(*b, ARCH_CONVERT)); + } + kdb_printf("tail bestcount %d\n", INT_GET(t->bestcount, ARCH_CONVERT)); +} + +/* + * Print a shortform directory. + */ +static void +xfsidbg_xdirsf(xfs_dir_shortform_t *s) +{ + xfs_dir_sf_hdr_t *sfh; + xfs_dir_sf_entry_t *sfe; + xfs_ino_t ino; + int i, j; + + sfh = &s->hdr; + XFS_DIR_SF_GET_DIRINO_ARCH(&sfh->parent, &ino, ARCH_CONVERT); + kdb_printf("hdr parent %llu", (unsigned long long)ino); + kdb_printf(" count %d\n", sfh->count); + for (i = 0, sfe = s->list; i < sfh->count; i++) { + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &ino, ARCH_CONVERT); + kdb_printf("entry %d inumber %llu", i, (unsigned long long)ino); + kdb_printf(" namelen %d name \"", sfe->namelen); + for (j = 0; j < sfe->namelen; j++) + kdb_printf("%c", sfe->name[j]); + kdb_printf("\"\n"); + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } +} + +/* + * Print a shortform v2 directory. + */ +static void +xfsidbg_xdir2sf(xfs_dir2_sf_t *s) +{ + xfs_dir2_sf_hdr_t *sfh; + xfs_dir2_sf_entry_t *sfe; + xfs_ino_t ino; + int i, j; + + sfh = &s->hdr; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(s, &sfh->parent, ARCH_CONVERT); + kdb_printf("hdr count %d i8count %d parent %llu\n", + sfh->count, sfh->i8count, (unsigned long long) ino); + for (i = 0, sfe = XFS_DIR2_SF_FIRSTENTRY(s); i < sfh->count; i++) { + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(s, XFS_DIR2_SF_INUMBERP(sfe), ARCH_CONVERT); + kdb_printf("entry %d inumber %llu offset 0x%x namelen %d name \"", + i, (unsigned long long) ino, + XFS_DIR2_SF_GET_OFFSET_ARCH(sfe, ARCH_CONVERT), + sfe->namelen); + for (j = 0; j < sfe->namelen; j++) + kdb_printf("%c", sfe->name[j]); + kdb_printf("\"\n"); + sfe = XFS_DIR2_SF_NEXTENTRY(s, sfe); + } +} + +/* + * Print a node-form v2 directory freemap block. + */ +static void +xfsidbg_xdir2free(xfs_dir2_free_t *f) +{ + int i; + + kdb_printf("hdr magic 0x%x firstdb %d nvalid %d nused %d\n", + INT_GET(f->hdr.magic, ARCH_CONVERT), INT_GET(f->hdr.firstdb, ARCH_CONVERT), INT_GET(f->hdr.nvalid, ARCH_CONVERT), INT_GET(f->hdr.nused, ARCH_CONVERT)); + for (i = 0; i < INT_GET(f->hdr.nvalid, ARCH_CONVERT); i++) { + kdb_printf("entry %d db %d count %d\n", + i, i + INT_GET(f->hdr.firstdb, ARCH_CONVERT), INT_GET(f->bests[i], ARCH_CONVERT)); + } +} + + +/* + * Print xfs extent list. + */ +static void +xfsidbg_xexlist(xfs_inode_t *ip) +{ + xfs_xexlist_fork(ip, XFS_DATA_FORK); + if (XFS_IFORK_Q(ip)) + xfs_xexlist_fork(ip, XFS_ATTR_FORK); +} + +/* + * Print an xfs free-extent list. + */ +static void +xfsidbg_xflist(xfs_bmap_free_t *flist) +{ + xfs_bmap_free_item_t *item; + + kdb_printf("flist@0x%p: first 0x%p count %d low %d\n", flist, + flist->xbf_first, flist->xbf_count, flist->xbf_low); + for (item = flist->xbf_first; item; item = item->xbfi_next) { + kdb_printf("item@0x%p: startblock %Lx blockcount %d", item, + (xfs_dfsbno_t)item->xbfi_startblock, + item->xbfi_blockcount); + } +} + +/* + * Print out the help messages for these functions. + */ +static void +xfsidbg_xhelp(void) +{ + struct xif *p; + + for (p = xfsidbg_funcs; p->name; p++) + kdb_printf("%-16s %s %s\n", p->name, p->args, p->help); +} + +/* + * Print out an XFS in-core log structure. + */ +static void +xfsidbg_xiclog(xlog_in_core_t *iclog) +{ + int i; + static char *ic_flags[] = { + "ACTIVE", /* 0x0001 */ + "WANT_SYNC", /* 0x0002 */ + "SYNCING", /* 0X0004 */ + "DONE_SYNC", /* 0X0008 */ + "DO_CALLBACK", /* 0X0010 */ + "CALLBACK", /* 0X0020 */ + "DIRTY", /* 0X0040 */ + "IOERROR", /* 0X0080 */ + "NOTUSED", /* 0X8000 */ + 0 + }; + + kdb_printf("xlog_in_core/header at 0x%p/0x%p\n", + iclog, iclog->hic_data); + kdb_printf("magicno: %x cycle: %d version: %d lsn: 0x%Lx\n", + INT_GET(iclog->ic_header.h_magicno, ARCH_CONVERT), INT_GET(iclog->ic_header.h_cycle, ARCH_CONVERT), + INT_GET(iclog->ic_header.h_version, ARCH_CONVERT), INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT)); + kdb_printf("tail_lsn: 0x%Lx len: %d prev_block: %d num_ops: %d\n", + INT_GET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT), INT_GET(iclog->ic_header.h_len, ARCH_CONVERT), + INT_GET(iclog->ic_header.h_prev_block, ARCH_CONVERT), INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT)); + kdb_printf("cycle_data: "); + for (i=0; i<(iclog->ic_size>>BBSHIFT); i++) { + kdb_printf("%x ", INT_GET(iclog->ic_header.h_cycle_data[i], ARCH_CONVERT)); + } + kdb_printf("\n"); + kdb_printf("size: %d\n", INT_GET(iclog->ic_header.h_size, ARCH_CONVERT)); + kdb_printf("\n"); + kdb_printf("--------------------------------------------------\n"); + kdb_printf("data: 0x%p &forcesema: 0x%p next: 0x%p bp: 0x%p\n", + iclog->ic_datap, &iclog->ic_forcesema, iclog->ic_next, + iclog->ic_bp); + kdb_printf("log: 0x%p callb: 0x%p callb_tail: 0x%p roundoff: %d\n", + iclog->ic_log, iclog->ic_callback, iclog->ic_callback_tail, + iclog->ic_roundoff); + kdb_printf("size: %d (OFFSET: %d) refcnt: %d bwritecnt: %d", + iclog->ic_size, iclog->ic_offset, + iclog->ic_refcnt, iclog->ic_bwritecnt); + if (iclog->ic_state & XLOG_STATE_ALL) + printflags(iclog->ic_state, ic_flags, "state:"); + else + kdb_printf("state: ILLEGAL 0x%x", iclog->ic_state); + kdb_printf("\n"); +} /* xfsidbg_xiclog */ + + +/* + * Print all incore logs. + */ +static void +xfsidbg_xiclogall(xlog_in_core_t *iclog) +{ + xlog_in_core_t *first_iclog = iclog; + + do { + xfsidbg_xiclog(iclog); + kdb_printf("=================================================\n"); + iclog = iclog->ic_next; + } while (iclog != first_iclog); +} /* xfsidbg_xiclogall */ + +/* + * Print out the callback structures attached to an iclog. + */ +static void +xfsidbg_xiclogcb(xlog_in_core_t *iclog) +{ + xfs_log_callback_t *cb; + kdb_symtab_t symtab; + + for (cb = iclog->ic_callback; cb != NULL; cb = cb->cb_next) { + + if (kdbnearsym((unsigned long)cb->cb_func, &symtab)) { + unsigned long offval; + + offval = (unsigned long)cb->cb_func - symtab.sym_start; + + if (offval) + kdb_printf("func = %s+0x%lx", + symtab.sym_name, + offval); + else + kdb_printf("func = %s", symtab.sym_name); + } else + kdb_printf("func = ?? 0x%p", (void *)cb->cb_func); + + kdb_printf(" arg 0x%p next 0x%p\n", cb->cb_arg, cb->cb_next); + } +} + + +/* + * Print all of the inodes attached to the given mount structure. + */ +static void +xfsidbg_xinodes(xfs_mount_t *mp) +{ + xfs_inode_t *ip; + + kdb_printf("xfs_mount at 0x%p\n", mp); + ip = mp->m_inodes; + if (ip != NULL) { + do { + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + kdb_printf("\n"); + xfsidbg_xnode(ip); + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + } + kdb_printf("\nEnd of Inodes\n"); +} + +static void +xfsidbg_delayed_blocks(xfs_mount_t *mp) +{ + xfs_inode_t *ip; + unsigned int total = 0; + unsigned int icount = 0; + + ip = mp->m_inodes; + if (ip != NULL) { + do { + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + if (ip->i_delayed_blks) { + total += ip->i_delayed_blks; + icount++; + } + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + } + kdb_printf("delayed blocks total: %d in %d inodes\n", total, icount); +} + +static void +xfsidbg_xinodes_quiesce(xfs_mount_t *mp) +{ + xfs_inode_t *ip; + + kdb_printf("xfs_mount at 0x%p\n", mp); + ip = mp->m_inodes; + if (ip != NULL) { + do { + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + if (!(ip->i_flags & XFS_IQUIESCE)) { + kdb_printf("ip 0x%p not quiesced\n", ip); + } else if (!BHV_IS_WRITE_LOCKED(VN_BHV_HEAD(XFS_ITOV(ip)))) { + kdb_printf("ip 0x%p not write locked\n", ip); + } + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + } + kdb_printf("\nEnd of Inodes\n"); +} + +static char * +xfsidbg_get_cstate(int state) +{ + switch(state) { + case XLOG_STATE_COVER_IDLE: + return("idle"); + case XLOG_STATE_COVER_NEED: + return("need"); + case XLOG_STATE_COVER_DONE: + return("done"); + case XLOG_STATE_COVER_NEED2: + return("need2"); + case XLOG_STATE_COVER_DONE2: + return("done2"); + default: + return("unknown"); + } +} + +/* + * Print out an XFS log structure. + */ +static void +xfsidbg_xlog(xlog_t *log) +{ + int rbytes; + int wbytes; + static char *t_flags[] = { + "CHKSUM_MISMATCH", /* 0x01 */ + "ACTIVE_RECOVERY", /* 0x02 */ + "RECOVERY_NEEDED", /* 0x04 */ + "IO_ERROR", /* 0x08 */ + 0 + }; + + kdb_printf("xlog at 0x%p\n", log); + kdb_printf("&flushsm: 0x%p tic_cnt: %d tic_tcnt: %d \n", + &log->l_flushsema, log->l_ticket_cnt, log->l_ticket_tcnt); + kdb_printf("freelist: 0x%p tail: 0x%p ICLOG: 0x%p \n", + log->l_freelist, log->l_tail, log->l_iclog); + kdb_printf("&icloglock: 0x%p tail_lsn: %s last_sync_lsn: %s \n", + &log->l_icloglock, xfs_fmtlsn(&log->l_tail_lsn), + xfs_fmtlsn(&log->l_last_sync_lsn)); + kdb_printf("mp: 0x%p xbuf: 0x%p roundoff: %d l_covered_state: %s \n", + log->l_mp, log->l_xbuf, log->l_roundoff, + xfsidbg_get_cstate(log->l_covered_state)); + kdb_printf("flags: "); + printflags(log->l_flags, t_flags,"log"); + kdb_printf(" dev: 0x%x logBBstart: %lld logsize: %d logBBsize: %d\n", + log->l_dev, (long long) log->l_logBBstart, + log->l_logsize,log->l_logBBsize); + kdb_printf("curr_cycle: %d prev_cycle: %d curr_block: %d prev_block: %d\n", + log->l_curr_cycle, log->l_prev_cycle, log->l_curr_block, + log->l_prev_block); + kdb_printf("iclog_bak: 0x%p iclog_size: 0x%x (%d) num iclogs: %d\n", + log->l_iclog_bak, log->l_iclog_size, log->l_iclog_size, + log->l_iclog_bufs); + kdb_printf("l_iclog_hsize %d l_iclog_heads %d\n", + log->l_iclog_hsize, log->l_iclog_heads); + kdb_printf("&grant_lock: 0x%p resHeadQ: 0x%p wrHeadQ: 0x%p\n", + &log->l_grant_lock, log->l_reserve_headq, log->l_write_headq); + kdb_printf("GResCycle: %d GResBytes: %d GWrCycle: %d GWrBytes: %d\n", + log->l_grant_reserve_cycle, log->l_grant_reserve_bytes, + log->l_grant_write_cycle, log->l_grant_write_bytes); + rbytes = log->l_grant_reserve_bytes + log->l_roundoff; + wbytes = log->l_grant_write_bytes + log->l_roundoff; + kdb_printf("GResBlocks: %d GResRemain: %d GWrBlocks: %d GWrRemain: %d\n", + rbytes / BBSIZE, rbytes % BBSIZE, + wbytes / BBSIZE, wbytes % BBSIZE); +} /* xfsidbg_xlog */ + + +/* + * Print out an XFS recovery transaction + */ +static void +xfsidbg_xlog_ritem(xlog_recover_item_t *item) +{ + int i = XLOG_MAX_REGIONS_IN_ITEM; + + kdb_printf("(xlog_recover_item 0x%p) ", item); + kdb_printf("next: 0x%p prev: 0x%p type: %d cnt: %d ttl: %d\n", + item->ri_next, item->ri_prev, ITEM_TYPE(item), item->ri_cnt, + item->ri_total); + for ( ; i > 0; i--) { + if (!item->ri_buf[XLOG_MAX_REGIONS_IN_ITEM-i].i_addr) + break; + kdb_printf("a: 0x%p l: %d ", + item->ri_buf[XLOG_MAX_REGIONS_IN_ITEM-i].i_addr, + item->ri_buf[XLOG_MAX_REGIONS_IN_ITEM-i].i_len); + } + kdb_printf("\n"); +} /* xfsidbg_xlog_ritem */ + +/* + * Print out an XFS recovery transaction + */ +static void +xfsidbg_xlog_rtrans(xlog_recover_t *trans) +{ + xlog_recover_item_t *rip, *first_rip; + + kdb_printf("(xlog_recover 0x%p) ", trans); + kdb_printf("tid: %x type: %d items: %d ttid: 0x%x ", + trans->r_log_tid, trans->r_theader.th_type, + trans->r_theader.th_num_items, trans->r_theader.th_tid); + kdb_printf("itemq: 0x%p\n", trans->r_itemq); + if (trans->r_itemq) { + rip = first_rip = trans->r_itemq; + do { + kdb_printf("(recovery item: 0x%p) ", rip); + kdb_printf("type: %d cnt: %d total: %d\n", + ITEM_TYPE(rip), rip->ri_cnt, rip->ri_total); + rip = rip->ri_next; + } while (rip != first_rip); + } +} /* xfsidbg_xlog_rtrans */ + +static void +xfsidbg_xlog_buf_logitem(xlog_recover_item_t *item) +{ + xfs_buf_log_format_t *buf_f; + int i, j; + int bit; + int nbits; + unsigned int *data_map; + unsigned int map_size; + int size; + + buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; + if (buf_f->blf_flags & XFS_BLI_INODE_BUF) { + kdb_printf("\tINODE BUF \n", + buf_f->blf_blkno, buf_f->blf_len); + } else if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF | XFS_BLI_GDQUOT_BUF)) { + kdb_printf("\tDQUOT BUF \n", + buf_f->blf_blkno, buf_f->blf_len); + } else { + data_map = buf_f->blf_data_map; + map_size = buf_f->blf_map_size; + kdb_printf("\tREG BUF \n", + buf_f->blf_blkno, buf_f->blf_len, data_map, map_size); + bit = 0; + i = 0; /* 0 is the buf format structure */ + while (1) { + bit = xfs_next_bit(data_map, map_size, bit); + if (bit == -1) + break; + nbits = xfs_contig_bits(data_map, map_size, bit); + size = ((uint)bit << XFS_BLI_SHIFT)+(nbits<ri_buf[i].i_addr, size); + kdb_printf("\t\t\t\""); + for (j=0; j<8 && jri_buf[i].i_addr)[j]); + } + kdb_printf("...\"\n"); + i++; + bit += nbits; + } + + } +} + +/* + * Print out an ENTIRE XFS recovery transaction + */ +static void +xfsidbg_xlog_rtrans_entire(xlog_recover_t *trans) +{ + xlog_recover_item_t *item, *first_rip; + + kdb_printf("(Recovering Xact 0x%p) ", trans); + kdb_printf("tid: %x type: %d nitems: %d ttid: 0x%x ", + trans->r_log_tid, trans->r_theader.th_type, + trans->r_theader.th_num_items, trans->r_theader.th_tid); + kdb_printf("itemq: 0x%p\n", trans->r_itemq); + if (trans->r_itemq) { + item = first_rip = trans->r_itemq; + do { + /* + kdb_printf("(recovery item: 0x%x) ", item); + kdb_printf("type: %d cnt: %d total: %d\n", + item->ri_type, item->ri_cnt, item->ri_total); + */ + if ((ITEM_TYPE(item) == XFS_LI_BUF) || + (ITEM_TYPE(item) == XFS_LI_6_1_BUF) || + (ITEM_TYPE(item) == XFS_LI_5_3_BUF)) { + kdb_printf("BUF:"); + xfsidbg_xlog_buf_logitem(item); + } else if ((ITEM_TYPE(item) == XFS_LI_INODE) || + (ITEM_TYPE(item) == XFS_LI_6_1_INODE) || + (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) { + kdb_printf("INODE:\n"); + } else if (ITEM_TYPE(item) == XFS_LI_EFI) { + kdb_printf("EFI:\n"); + } else if (ITEM_TYPE(item) == XFS_LI_EFD) { + kdb_printf("EFD:\n"); + } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) { + kdb_printf("DQUOT:\n"); + } else if ((ITEM_TYPE(item) == XFS_LI_QUOTAOFF)) { + kdb_printf("QUOTAOFF:\n"); + } else { + kdb_printf("UNKNOWN LOGITEM 0x%x\n", ITEM_TYPE(item)); + } + item = item->ri_next; + } while (item != first_rip); + } +} /* xfsidbg_xlog_rtrans */ + +/* + * Print out an XFS ticket structure. + */ +static void +xfsidbg_xlog_tic(xlog_ticket_t *tic) +{ + static char *t_flags[] = { + "INIT", /* 0x1 */ + "PERM_RES", /* 0x2 */ + "IN_Q", /* 0x4 */ + 0 + }; + + kdb_printf("xlog_ticket at 0x%p\n", tic); + kdb_printf("next: 0x%p prev: 0x%p tid: 0x%x \n", + tic->t_next, tic->t_prev, tic->t_tid); + kdb_printf("curr_res: %d unit_res: %d ocnt: %d cnt: %d\n", + tic->t_curr_res, tic->t_unit_res, (int)tic->t_ocnt, + (int)tic->t_cnt); + kdb_printf("clientid: %c \n", tic->t_clientid); + printflags(tic->t_flags, t_flags,"ticket"); + kdb_printf("\n"); +} /* xfsidbg_xlog_tic */ + +/* + * Print out a single log item. + */ +static void +xfsidbg_xlogitem(xfs_log_item_t *lip) +{ + xfs_log_item_t *bio_lip; + static char *lid_type[] = { + "???", /* 0 */ + "5-3-buf", /* 1 */ + "5-3-inode", /* 2 */ + "efi", /* 3 */ + "efd", /* 4 */ + "iunlink", /* 5 */ + "6-1-inode", /* 6 */ + "6-1-buf", /* 7 */ + "inode", /* 8 */ + "buf", /* 9 */ + "dquot", /* 10 */ + 0 + }; + static char *li_flags[] = { + "in ail", /* 0x1 */ + 0 + }; + + kdb_printf("type %s mountp 0x%p flags ", + lid_type[lip->li_type - XFS_LI_5_3_BUF + 1], + lip->li_mountp); + printflags((uint)(lip->li_flags), li_flags,"log"); + kdb_printf("\n"); + kdb_printf("ail forw 0x%p ail back 0x%p lsn %s desc %p ops 0x%p\n", + lip->li_ail.ail_forw, lip->li_ail.ail_back, + xfs_fmtlsn(&(lip->li_lsn)), lip->li_desc, lip->li_ops); + kdb_printf("iodonefunc &0x%p\n", lip->li_cb); + if (lip->li_type == XFS_LI_BUF) { + bio_lip = lip->li_bio_list; + if (bio_lip != NULL) { + kdb_printf("iodone list:\n"); + } + while (bio_lip != NULL) { + kdb_printf("item 0x%p func 0x%p\n", + bio_lip, bio_lip->li_cb); + bio_lip = bio_lip->li_bio_list; + } + } + switch (lip->li_type) { + case XFS_LI_BUF: + xfs_buf_item_print((xfs_buf_log_item_t *)lip, 0); + break; + case XFS_LI_INODE: + xfs_inode_item_print((xfs_inode_log_item_t *)lip, 0); + break; + case XFS_LI_EFI: + xfs_efi_item_print((xfs_efi_log_item_t *)lip, 0); + break; + case XFS_LI_EFD: + xfs_efd_item_print((xfs_efd_log_item_t *)lip, 0); + break; + case XFS_LI_DQUOT: + xfs_dquot_item_print((xfs_dq_logitem_t *)lip, 0); + break; + case XFS_LI_QUOTAOFF: + xfs_qoff_item_print((xfs_qoff_logitem_t *)lip, 0); + break; + + default: + kdb_printf("Unknown item type %d\n", lip->li_type); + break; + } +} + +/* + * Print out a summary of the AIL hanging off of a mount struct. + */ +static void +xfsidbg_xaildump(xfs_mount_t *mp) +{ + xfs_log_item_t *lip; + static char *lid_type[] = { + "???", /* 0 */ + "5-3-buf", /* 1 */ + "5-3-inode", /* 2 */ + "efi", /* 3 */ + "efd", /* 4 */ + "iunlink", /* 5 */ + "6-1-inode", /* 6 */ + "6-1-buf", /* 7 */ + "inode", /* 8 */ + "buf", /* 9 */ + "dquot", /* 10 */ + 0 + }; + static char *li_flags[] = { + "in ail", /* 0x1 */ + 0 + }; + int count; + + if ((mp->m_ail.ail_forw == NULL) || + (mp->m_ail.ail_forw == (xfs_log_item_t *)&mp->m_ail)) { + kdb_printf("AIL is empty\n"); + return; + } + kdb_printf("AIL for mp 0x%p, oldest first\n", mp); + lip = (xfs_log_item_t*)mp->m_ail.ail_forw; + for (count = 0; lip; count++) { + kdb_printf("[%d] type %s ", count, + lid_type[lip->li_type - XFS_LI_5_3_BUF + 1]); + printflags((uint)(lip->li_flags), li_flags, "flags:"); + kdb_printf(" lsn %s\n ", xfs_fmtlsn(&(lip->li_lsn))); + switch (lip->li_type) { + case XFS_LI_BUF: + xfs_buf_item_print((xfs_buf_log_item_t *)lip, 1); + break; + case XFS_LI_INODE: + xfs_inode_item_print((xfs_inode_log_item_t *)lip, 1); + break; + case XFS_LI_EFI: + xfs_efi_item_print((xfs_efi_log_item_t *)lip, 1); + break; + case XFS_LI_EFD: + xfs_efd_item_print((xfs_efd_log_item_t *)lip, 1); + break; + case XFS_LI_DQUOT: + xfs_dquot_item_print((xfs_dq_logitem_t *)lip, 1); + break; + case XFS_LI_QUOTAOFF: + xfs_qoff_item_print((xfs_qoff_logitem_t *)lip, 1); + break; + default: + kdb_printf("Unknown item type %d\n", lip->li_type); + break; + } + + if (lip->li_ail.ail_forw == (xfs_log_item_t*)&mp->m_ail) { + lip = NULL; + } else { + lip = lip->li_ail.ail_forw; + } + } +} + +/* + * Print xfs mount structure. + */ +static void +xfsidbg_xmount(xfs_mount_t *mp) +{ + static char *xmount_flags[] = { + "WSYNC", /* 0x0001 */ + "INO64", /* 0x0002 */ + "RQCHK", /* 0x0004 */ + "FSCLEAN", /* 0x0008 */ + "FSSHUTDN", /* 0x0010 */ + "NOATIME", /* 0x0020 */ + "RETERR", /* 0x0040 */ + "NOALIGN", /* 0x0080 */ + "UNSHRD", /* 0x0100 */ + "RGSTRD", /* 0x0200 */ + "NORECVR", /* 0x0400 */ + "SHRD", /* 0x0800 */ + "IOSZ", /* 0x1000 */ + "OSYNC", /* 0x2000 */ + "NOUUID", /* 0x4000 */ + "32BIT", /* 0x8000 */ + "NOLOGFLUSH", /* 0x10000 */ + 0 + }; + + static char *quota_flags[] = { + "UQ", /* 0x0001 */ + "UQE", /* 0x0002 */ + "UQCHKD", /* 0x0004 */ + "PQ", /* 0x0008 (IRIX ondisk) */ + "GQE", /* 0x0010 */ + "GQCHKD", /* 0x0020 */ + "GQ", /* 0x0040 */ + "UQACTV", /* 0x0080 */ + "GQACTV", /* 0x0100 */ + "QMAYBE", /* 0x0200 */ + 0 + }; + + kdb_printf("xfs_mount at 0x%p\n", mp); + kdb_printf("vfsp 0x%p tid 0x%x ail_lock 0x%p &ail 0x%p\n", + XFS_MTOVFS(mp), mp->m_tid, &mp->m_ail_lock, &mp->m_ail); + kdb_printf("ail_gen 0x%x &sb 0x%p\n", + mp->m_ail_gen, &mp->m_sb); + kdb_printf("sb_lock 0x%p sb_bp 0x%p dev 0x%x logdev 0x%x rtdev 0x%x\n", + &mp->m_sb_lock, mp->m_sb_bp, + mp->m_ddev_targp->pbr_dev, + mp->m_logdev_targp->pbr_dev, + mp->m_rtdev_targp->pbr_dev); + kdb_printf("bsize %d agfrotor %d agirotor %d ihash 0x%p ihsize %d\n", + mp->m_bsize, mp->m_agfrotor, mp->m_agirotor, + mp->m_ihash, mp->m_ihsize); + kdb_printf("inodes 0x%p ilock 0x%p ireclaims 0x%x\n", + mp->m_inodes, &mp->m_ilock, mp->m_ireclaims); + kdb_printf("readio_log 0x%x readio_blocks 0x%x ", + mp->m_readio_log, mp->m_readio_blocks); + kdb_printf("writeio_log 0x%x writeio_blocks 0x%x\n", + mp->m_writeio_log, mp->m_writeio_blocks); + kdb_printf("logbufs %d logbsize %d LOG 0x%p\n", mp->m_logbufs, + mp->m_logbsize, mp->m_log); + kdb_printf("rsumlevels 0x%x rsumsize 0x%x rbmip 0x%p rsumip 0x%p\n", + mp->m_rsumlevels, mp->m_rsumsize, mp->m_rbmip, mp->m_rsumip); + kdb_printf("rootip 0x%p\n", mp->m_rootip); + kdb_printf("dircook_elog %d blkbit_log %d blkbb_log %d agno_log %d\n", + mp->m_dircook_elog, mp->m_blkbit_log, mp->m_blkbb_log, + mp->m_agno_log); + kdb_printf("agino_log %d nreadaheads %d inode cluster size %d\n", + mp->m_agino_log, mp->m_nreadaheads, + mp->m_inode_cluster_size); + kdb_printf("blockmask 0x%x blockwsize 0x%x blockwmask 0x%x\n", + mp->m_blockmask, mp->m_blockwsize, mp->m_blockwmask); + kdb_printf("alloc_mxr[lf,nd] %d %d alloc_mnr[lf,nd] %d %d\n", + mp->m_alloc_mxr[0], mp->m_alloc_mxr[1], + mp->m_alloc_mnr[0], mp->m_alloc_mnr[1]); + kdb_printf("bmap_dmxr[lfnr,ndnr] %d %d bmap_dmnr[lfnr,ndnr] %d %d\n", + mp->m_bmap_dmxr[0], mp->m_bmap_dmxr[1], + mp->m_bmap_dmnr[0], mp->m_bmap_dmnr[1]); + kdb_printf("inobt_mxr[lf,nd] %d %d inobt_mnr[lf,nd] %d %d\n", + mp->m_inobt_mxr[0], mp->m_inobt_mxr[1], + mp->m_inobt_mnr[0], mp->m_inobt_mnr[1]); + kdb_printf("ag_maxlevels %d bm_maxlevels[d,a] %d %d in_maxlevels %d\n", + mp->m_ag_maxlevels, mp->m_bm_maxlevels[0], + mp->m_bm_maxlevels[1], mp->m_in_maxlevels); + kdb_printf("perag 0x%p &peraglock 0x%p &growlock 0x%p\n", + mp->m_perag, &mp->m_peraglock, &mp->m_growlock); + printflags(mp->m_flags, xmount_flags,"flags"); + kdb_printf("ialloc_inos %d ialloc_blks %d litino %d\n", + mp->m_ialloc_inos, mp->m_ialloc_blks, mp->m_litino); + kdb_printf("attroffset %d da_node_ents %d maxicount %Ld inoalign_mask %d\n", + mp->m_attroffset, mp->m_da_node_ents, mp->m_maxicount, + mp->m_inoalign_mask); + kdb_printf("resblks %Ld resblks_avail %Ld\n", mp->m_resblks, + mp->m_resblks_avail); +#if XFS_BIG_FILESYSTEMS + kdb_printf(" inoadd %llx\n", (unsigned long long) mp->m_inoadd); +#else + kdb_printf("\n"); +#endif + if (mp->m_quotainfo) + kdb_printf("quotainfo 0x%p (uqip = 0x%p, gqip = 0x%p)\n", + mp->m_quotainfo, + mp->m_quotainfo->qi_uquotaip, + mp->m_quotainfo->qi_gquotaip); + else + kdb_printf("quotainfo NULL\n"); + printflags(mp->m_qflags, quota_flags,"quotaflags"); + kdb_printf("\n"); + kdb_printf("dalign %d swidth %d sinoalign %d attr_magicpct %d dir_magicpct %d\n", + mp->m_dalign, mp->m_swidth, mp->m_sinoalign, + mp->m_attr_magicpct, mp->m_dir_magicpct); + kdb_printf("mk_sharedro %d dirversion %d dirblkfsbs %d &dirops 0x%p\n", + mp->m_mk_sharedro, mp->m_dirversion, mp->m_dirblkfsbs, + &mp->m_dirops); + kdb_printf("dirblksize %d dirdatablk 0x%Lx dirleafblk 0x%Lx dirfreeblk 0x%Lx\n", + mp->m_dirblksize, + (xfs_dfiloff_t)mp->m_dirdatablk, + (xfs_dfiloff_t)mp->m_dirleafblk, + (xfs_dfiloff_t)mp->m_dirfreeblk); + kdb_printf("chsize %d chash 0x%p\n", + mp->m_chsize, mp->m_chash); + kdb_printf("m_lstripemask %d\n", mp->m_lstripemask); + kdb_printf("m_frozen %d m_active_trans %d\n", + mp->m_frozen, mp->m_active_trans.counter); + if (mp->m_fsname != NULL) + kdb_printf("mountpoint \"%s\"\n", mp->m_fsname); + else + kdb_printf("No name!!!\n"); + +} + +static void +xfsidbg_xihash(xfs_mount_t *mp) +{ + xfs_ihash_t *ih; + int i; + int j; + int total; + int numzeros; + xfs_inode_t *ip; + int *hist; + int hist_bytes = mp->m_ihsize * sizeof(int); + int hist2[21]; + + hist = (int *) kmalloc(hist_bytes, GFP_KERNEL); + + if (hist == NULL) { + kdb_printf("xfsidbg_xihash: kmalloc(%d) failed!\n", + hist_bytes); + return; + } + + for (i = 0; i < mp->m_ihsize; i++) { + ih = mp->m_ihash + i; + j = 0; + for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) + j++; + hist[i] = j; + } + + numzeros = total = 0; + + for (i = 0; i < 21; i++) + hist2[i] = 0; + + for (i = 0; i < mp->m_ihsize; i++) { + kdb_printf("%d ", hist[i]); + total += hist[i]; + numzeros += hist[i] == 0 ? 1 : 0; + if (hist[i] > 20) + j = 20; + else + j = hist[i]; + + if (! (j <= 20)) { + kdb_printf("xfsidbg_xihash: (j > 20)/%d @ line # %d\n", + j, __LINE__); + return; + } + + hist2[j]++; + } + + kdb_printf("\n"); + + kdb_printf("total inodes = %d, average length = %d, adjusted average = %d \n", + total, total / mp->m_ihsize, + total / (mp->m_ihsize - numzeros)); + + for (i = 0; i < 21; i++) { + kdb_printf("%d - %d , ", i, hist2[i]); + } + kdb_printf("\n"); + kfree(hist); +} + +/* + * Command to print xfs inodes: kp xnode + */ +static void +xfsidbg_xnode(xfs_inode_t *ip) +{ + static char *tab_flags[] = { + "grio", /* XFS_IGRIO */ + "uiosize", /* XFS_IUIOSZ */ + "quiesce", /* XFS_IQUIESCE */ + "reclaim", /* XFS_IRECLAIM */ + NULL + }; + + kdb_printf("hash 0x%p next 0x%p prevp 0x%p mount 0x%p\n", + ip->i_hash, + ip->i_next, + ip->i_prevp, + ip->i_mount); + kdb_printf("mnext 0x%p mprev 0x%p vnode 0x%p \n", + ip->i_mnext, + ip->i_mprev, + XFS_ITOV_NULL(ip)); + kdb_printf("dev %x ino %s\n", + ip->i_mount->m_dev, + xfs_fmtino(ip->i_ino, ip->i_mount)); + kdb_printf("blkno 0x%llx len 0x%x boffset 0x%x\n", + (long long) ip->i_blkno, + ip->i_len, + ip->i_boffset); + kdb_printf("transp 0x%p &itemp 0x%p\n", + ip->i_transp, + ip->i_itemp); + kdb_printf("&lock 0x%p &iolock 0x%p", + &ip->i_lock, + &ip->i_iolock); + kdb_printf("&flock 0x%p (%d) pincount 0x%x\n", + &ip->i_flock, valusema(&ip->i_flock), + xfs_ipincount(ip)); + kdb_printf("udquotp 0x%p gdquotp 0x%p\n", + ip->i_udquot, ip->i_gdquot); + kdb_printf("new_size %Lx\n", ip->i_iocore.io_new_size); + printflags((int)ip->i_flags, tab_flags, "flags"); + kdb_printf("\n"); + kdb_printf("update_core 0x%x update size 0x%x\n", + (int)(ip->i_update_core), (int) ip->i_update_size); + kdb_printf("gen 0x%x delayed blks %d", + ip->i_gen, + ip->i_delayed_blks); + kdb_printf("\n"); + kdb_printf("chash 0x%p cnext 0x%p cprev 0x%p\n", + ip->i_chash, + ip->i_cnext, + ip->i_cprev); + xfs_xnode_fork("data", &ip->i_df); + xfs_xnode_fork("attr", ip->i_afp); + kdb_printf("\n"); + xfs_prdinode_core(&ip->i_d, ARCH_NOCONVERT); +} + +static void +xfsidbg_xcore(xfs_iocore_t *io) +{ + if (IO_IS_XFS(io)) { + kdb_printf("io_obj 0x%p (xinode) io_mount 0x%p\n", + io->io_obj, io->io_mount); + } else { + kdb_printf("io_obj 0x%p (dcxvn) io_mount 0x%p\n", + io->io_obj, io->io_mount); + } + kdb_printf("new_size %Lx\n", io->io_new_size); +} + +/* + * Command to print xfs inode cluster hash table: kp xchash + */ +static void +xfsidbg_xchash(xfs_mount_t *mp) +{ + int i; + xfs_chash_t *ch; + + kdb_printf("m_chash 0x%p size %d\n", + mp->m_chash, mp->m_chsize); + for (i = 0; i < mp->m_chsize; i++) { + ch = mp->m_chash + i; + kdb_printf("[%3d] ch 0x%p chashlist 0x%p\n", i, ch, ch->ch_list); + xfsidbg_xchashlist(ch->ch_list); + } +} + +/* + * Command to print xfs inode cluster hash list: kp xchashlist + */ +static void +xfsidbg_xchashlist(xfs_chashlist_t *chl) +{ + xfs_inode_t *ip; + + while (chl != NULL) { +#ifdef DEBUG + kdb_printf("hashlist inode 0x%p blkno %Ld buf 0x%p", + chl->chl_ip, chl->chl_blkno, chl->chl_buf); +#else + kdb_printf("hashlist inode 0x%p blkno %lld", + chl->chl_ip, (long long) chl->chl_blkno); +#endif + + kdb_printf("\n"); + + /* print inodes on chashlist */ + ip = chl->chl_ip; + do { + kdb_printf("0x%p ", ip); + ip = ip->i_cnext; + } while (ip != chl->chl_ip); + kdb_printf("\n"); + + chl=chl->chl_next; + } +} + +/* + * Print xfs per-ag data structures for filesystem. + */ +static void +xfsidbg_xperag(xfs_mount_t *mp) +{ + xfs_agnumber_t agno; + xfs_perag_t *pag; + int busy; + + pag = mp->m_perag; + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++, pag++) { + kdb_printf("ag %d f_init %d i_init %d\n", + agno, pag->pagf_init, pag->pagi_init); + if (pag->pagf_init) + kdb_printf( + " f_levels[b,c] %d,%d f_flcount %d f_freeblks %d f_longest %d\n" + " f__metadata %d\n", + pag->pagf_levels[XFS_BTNUM_BNOi], + pag->pagf_levels[XFS_BTNUM_CNTi], + pag->pagf_flcount, pag->pagf_freeblks, + pag->pagf_longest, pag->pagf_metadata); + if (pag->pagi_init) + kdb_printf(" i_freecount %d i_inodeok %d\n", + pag->pagi_freecount, pag->pagi_inodeok); + + for (busy = 0; busy < XFS_PAGB_NUM_SLOTS; busy++) { + kdb_printf(" %04d: start %d length %d tp 0x%p\n", + busy, + pag->pagb_list[busy].busy_start, + pag->pagb_list[busy].busy_length, + pag->pagb_list[busy].busy_tp); + } + } +} + +#ifdef CONFIG_XFS_QUOTA +static void +xfsidbg_xqm() +{ + if (xfs_Gqm == NULL) { + kdb_printf("NULL XQM!!\n"); + return; + } + + kdb_printf("usrhtab 0x%p\tgrphtab 0x%p\tndqfree 0x%x\thashmask 0x%x\n", + xfs_Gqm->qm_usr_dqhtable, + xfs_Gqm->qm_grp_dqhtable, + xfs_Gqm->qm_dqfreelist.qh_nelems, + xfs_Gqm->qm_dqhashmask); + kdb_printf("&freelist 0x%p, totaldquots 0x%x nrefs 0x%x\n", + &xfs_Gqm->qm_dqfreelist, + atomic_read(&xfs_Gqm->qm_totaldquots), + xfs_Gqm->qm_nrefs); +} +#endif + +static void +xfsidbg_xqm_diskdq(xfs_disk_dquot_t *d) +{ + kdb_printf("magic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n", + INT_GET(d->d_magic, ARCH_CONVERT), + INT_GET(d->d_version, ARCH_CONVERT), + INT_GET(d->d_id, ARCH_CONVERT), + INT_GET(d->d_id, ARCH_CONVERT)); + kdb_printf("bhard 0x%llx\tbsoft 0x%llx\tihard 0x%llx\tisoft 0x%llx\n", + (unsigned long long)INT_GET(d->d_blk_hardlimit, ARCH_CONVERT), + (unsigned long long)INT_GET(d->d_blk_softlimit, ARCH_CONVERT), + (unsigned long long)INT_GET(d->d_ino_hardlimit, ARCH_CONVERT), + (unsigned long long)INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); + kdb_printf("bcount 0x%llx icount 0x%llx\n", + (unsigned long long)INT_GET(d->d_bcount, ARCH_CONVERT), + (unsigned long long)INT_GET(d->d_icount, ARCH_CONVERT)); + kdb_printf("btimer 0x%x itimer 0x%x \n", + (int)INT_GET(d->d_btimer, ARCH_CONVERT), + (int)INT_GET(d->d_itimer, ARCH_CONVERT)); +} + +static void +xfsidbg_xqm_dquot(xfs_dquot_t *dqp) +{ + static char *qflags[] = { + "USR", + "GRP", + "LCKD", + "FLKD", + "DIRTY", + "WANT", + "INACT", + "MARKER", + 0 + }; + kdb_printf("mount 0x%p hash 0x%p gdquotp 0x%p HL_next 0x%p HL_prevp 0x%p\n", + dqp->q_mount, + dqp->q_hash, + dqp->q_gdquot, + dqp->HL_NEXT, + dqp->HL_PREVP); + kdb_printf("MPL_next 0x%p MPL_prevp 0x%p FL_next 0x%p FL_prev 0x%p\n", + dqp->MPL_NEXT, + dqp->MPL_PREVP, + dqp->dq_flnext, + dqp->dq_flprev); + + kdb_printf("nrefs 0x%x, res_bcount %d, ", + dqp->q_nrefs, (int) dqp->q_res_bcount); + printflags(dqp->dq_flags, qflags, "flags:"); + kdb_printf("\nblkno 0x%llx\tboffset 0x%x\n", + (unsigned long long) dqp->q_blkno, (int) dqp->q_bufoffset); + kdb_printf("qlock 0x%p flock 0x%p (%s) pincount 0x%x\n", + &dqp->q_qlock, + &dqp->q_flock, + (valusema(&dqp->q_flock) <= 0) ? "LCK" : "UNLKD", + dqp->q_pincount); + kdb_printf("disk-dquot 0x%p\n", &dqp->q_core); + xfsidbg_xqm_diskdq(&dqp->q_core); + +} + + +#define XQMIDBG_LIST_PRINT(l, NXT) \ +{ \ + xfs_dquot_t *dqp;\ + int i = 0; \ + kdb_printf("[#%d dquots]\n", (int) (l)->qh_nelems); \ + for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) {\ + kdb_printf( \ + "\t%d. [0x%p] \"%d (%s)\"\t blks = %d, inos = %d refs = %d\n", \ + ++i, dqp, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \ + DQFLAGTO_TYPESTR(dqp), \ + (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \ + (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \ + (int) dqp->q_nrefs); }\ + kdb_printf("\n"); \ +} + +static void +xfsidbg_xqm_dqattached_inos(xfs_mount_t *mp) +{ + xfs_inode_t *ip; + int n = 0; + + ip = mp->m_inodes; + do { + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + if (ip->i_udquot || ip->i_gdquot) { + n++; + kdb_printf("inode = 0x%p, ino %d: udq 0x%p, gdq 0x%p\n", + ip, (int)ip->i_ino, ip->i_udquot, ip->i_gdquot); + } + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + kdb_printf("\nNumber of inodes with dquots attached: %d\n", n); +} + +#ifdef CONFIG_XFS_QUOTA +static void +xfsidbg_xqm_freelist_print(xfs_frlist_t *qlist, char *title) +{ + xfs_dquot_t *dq; + int i = 0; + kdb_printf("%s (#%d)\n", title, (int) qlist->qh_nelems); + FOREACH_DQUOT_IN_FREELIST(dq, qlist) { + kdb_printf("\t%d.\t\"%d (%s:0x%p)\"\t bcnt = %d, icnt = %d " + "refs = %d\n", + ++i, (int) INT_GET(dq->q_core.d_id, ARCH_CONVERT), + DQFLAGTO_TYPESTR(dq), dq, + (int) INT_GET(dq->q_core.d_bcount, ARCH_CONVERT), + (int) INT_GET(dq->q_core.d_icount, ARCH_CONVERT), + (int) dq->q_nrefs); + } +} + +static void +xfsidbg_xqm_freelist(void) +{ + if (xfs_Gqm) { + xfsidbg_xqm_freelist_print(&(xfs_Gqm->qm_dqfreelist), "Freelist"); + } else + kdb_printf("NULL XQM!!\n"); +} + +static void +xfsidbg_xqm_htab(void) +{ + int i; + xfs_dqhash_t *h; + + if (xfs_Gqm == NULL) { + kdb_printf("NULL XQM!!\n"); + return; + } + for (i = 0; i <= xfs_Gqm->qm_dqhashmask; i++) { + h = &xfs_Gqm->qm_usr_dqhtable[i]; + if (h->qh_next) { + kdb_printf("USR %d: ", i); + XQMIDBG_LIST_PRINT(h, HL_NEXT); + } + } + for (i = 0; i <= xfs_Gqm->qm_dqhashmask; i++) { + h = &xfs_Gqm->qm_grp_dqhtable[i]; + if (h->qh_next) { + kdb_printf("GRP %d: ", i); + XQMIDBG_LIST_PRINT(h, HL_NEXT); + } + } +} +#endif + +static void +xfsidbg_xqm_mplist(xfs_mount_t *mp) +{ + if (mp->m_quotainfo == NULL) { + kdb_printf("NULL quotainfo\n"); + return; + } + + XQMIDBG_LIST_PRINT(&(mp->m_quotainfo->qi_dqlist), MPL_NEXT); + +} + + +static void +xfsidbg_xqm_qinfo(xfs_mount_t *mp) +{ + if (mp == NULL || mp->m_quotainfo == NULL) { + kdb_printf("NULL quotainfo\n"); + return; + } + + kdb_printf("uqip 0x%p, gqip 0x%p, &pinlock 0x%p &dqlist 0x%p\n", + mp->m_quotainfo->qi_uquotaip, + mp->m_quotainfo->qi_gquotaip, + &mp->m_quotainfo->qi_pinlock, + &mp->m_quotainfo->qi_dqlist); + + kdb_printf("nreclaims %d, btmlimit 0x%x, itmlimit 0x%x, RTbtmlim 0x%x\n", + (int)mp->m_quotainfo->qi_dqreclaims, + (int)mp->m_quotainfo->qi_btimelimit, + (int)mp->m_quotainfo->qi_itimelimit, + (int)mp->m_quotainfo->qi_rtbtimelimit); + + kdb_printf("bwarnlim 0x%x, iwarnlim 0x%x, &qofflock 0x%p, " + "chunklen 0x%x, dqperchunk 0x%x\n", + (int)mp->m_quotainfo->qi_bwarnlimit, + (int)mp->m_quotainfo->qi_iwarnlimit, + &mp->m_quotainfo->qi_quotaofflock, + (int)mp->m_quotainfo->qi_dqchunklen, + (int)mp->m_quotainfo->qi_dqperchunk); +} + +static void +xfsidbg_xqm_tpdqinfo(xfs_trans_t *tp) +{ + xfs_dqtrx_t *qa, *q; + int i,j; + + kdb_printf("dqinfo 0x%p\n", tp->t_dqinfo); + if (! tp->t_dqinfo) + return; + kdb_printf("USR: \n"); + qa = tp->t_dqinfo->dqa_usrdquots; + for (j = 0; j < 2; j++) { + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + if (qa[i].qt_dquot == NULL) + break; + q = &qa[i]; + kdb_printf( + "\"%d\"[0x%p]: bres %d, bres-used %d, bdelta %d, del-delta %d, icnt-delta %d\n", + (int) q->qt_dquot->q_core.d_id, + q->qt_dquot, + (int) q->qt_blk_res, + (int) q->qt_blk_res_used, + (int) q->qt_bcount_delta, + (int) q->qt_delbcnt_delta, + (int) q->qt_icount_delta); + } + if (j == 0) { + qa = tp->t_dqinfo->dqa_grpdquots; + kdb_printf("GRP: \n"); + } + } + +} + + + +/* + * Print xfs superblock. + */ +static void +xfsidbg_xsb(xfs_sb_t *sbp, int convert) +{ + xfs_arch_t arch=convert?ARCH_CONVERT:ARCH_NOCONVERT; + + kdb_printf(convert?"\n":"\n"); + + kdb_printf("magicnum 0x%x blocksize 0x%x dblocks %Ld rblocks %Ld\n", + INT_GET(sbp->sb_magicnum, arch), INT_GET(sbp->sb_blocksize, arch), + INT_GET(sbp->sb_dblocks, arch), INT_GET(sbp->sb_rblocks, arch)); + kdb_printf("rextents %Ld uuid %s logstart %s\n", + INT_GET(sbp->sb_rextents, arch), + xfs_fmtuuid(&sbp->sb_uuid), + xfs_fmtfsblock(INT_GET(sbp->sb_logstart, arch), NULL)); + kdb_printf("rootino %s ", + xfs_fmtino(INT_GET(sbp->sb_rootino, arch), NULL)); + kdb_printf("rbmino %s ", + xfs_fmtino(INT_GET(sbp->sb_rbmino, arch), NULL)); + kdb_printf("rsumino %s\n", + xfs_fmtino(INT_GET(sbp->sb_rsumino, arch), NULL)); + kdb_printf("rextsize 0x%x agblocks 0x%x agcount 0x%x rbmblocks 0x%x\n", + INT_GET(sbp->sb_rextsize, arch), + INT_GET(sbp->sb_agblocks, arch), + INT_GET(sbp->sb_agcount, arch), + INT_GET(sbp->sb_rbmblocks, arch)); + kdb_printf("logblocks 0x%x versionnum 0x%x sectsize 0x%x inodesize 0x%x\n", + INT_GET(sbp->sb_logblocks, arch), + INT_GET(sbp->sb_versionnum, arch), + INT_GET(sbp->sb_sectsize, arch), + INT_GET(sbp->sb_inodesize, arch)); + kdb_printf("inopblock 0x%x blocklog 0x%x sectlog 0x%x inodelog 0x%x\n", + INT_GET(sbp->sb_inopblock, arch), + INT_GET(sbp->sb_blocklog, arch), + INT_GET(sbp->sb_sectlog, arch), + INT_GET(sbp->sb_inodelog, arch)); + kdb_printf("inopblog %d agblklog %d rextslog %d inprogress %d imax_pct %d\n", + INT_GET(sbp->sb_inopblog, arch), + INT_GET(sbp->sb_agblklog, arch), + INT_GET(sbp->sb_rextslog, arch), + INT_GET(sbp->sb_inprogress, arch), + INT_GET(sbp->sb_imax_pct, arch)); + kdb_printf("icount %Lx ifree %Lx fdblocks %Lx frextents %Lx\n", + INT_GET(sbp->sb_icount, arch), + INT_GET(sbp->sb_ifree, arch), + INT_GET(sbp->sb_fdblocks, arch), + INT_GET(sbp->sb_frextents, arch)); + kdb_printf("uquotino %s ", xfs_fmtino(INT_GET(sbp->sb_uquotino, arch), NULL)); + kdb_printf("gquotino %s ", xfs_fmtino(INT_GET(sbp->sb_gquotino, arch), NULL)); + kdb_printf("qflags 0x%x flags 0x%x shared_vn %d inoaligmt %d\n", + INT_GET(sbp->sb_qflags, arch), INT_GET(sbp->sb_flags, arch), INT_GET(sbp->sb_shared_vn, arch), + INT_GET(sbp->sb_inoalignmt, arch)); + kdb_printf("unit %d width %d dirblklog %d\n", + INT_GET(sbp->sb_unit, arch), INT_GET(sbp->sb_width, arch), INT_GET(sbp->sb_dirblklog, arch)); + kdb_printf("log sunit %d\n", INT_GET(sbp->sb_logsunit, arch)); +} + + +/* + * Print out an XFS transaction structure. Print summaries for + * each of the items. + */ +static void +xfsidbg_xtp(xfs_trans_t *tp) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_log_busy_chunk_t *lbcp; + int i; + int chunk; + static char *xtp_flags[] = { + "dirty", /* 0x1 */ + "sb_dirty", /* 0x2 */ + "perm_log_res", /* 0x4 */ + "sync", /* 0x08 */ + "dq_dirty", /* 0x10 */ + 0 + }; + static char *lid_flags[] = { + "dirty", /* 0x1 */ + "pinned", /* 0x2 */ + "sync unlock", /* 0x4 */ + 0 + }; + + kdb_printf("tp 0x%p type ", tp); + switch (tp->t_type) { + case XFS_TRANS_SETATTR_NOT_SIZE: kdb_printf("SETATTR_NOT_SIZE"); break; + case XFS_TRANS_SETATTR_SIZE: kdb_printf("SETATTR_SIZE"); break; + case XFS_TRANS_INACTIVE: kdb_printf("INACTIVE"); break; + case XFS_TRANS_CREATE: kdb_printf("CREATE"); break; + case XFS_TRANS_CREATE_TRUNC: kdb_printf("CREATE_TRUNC"); break; + case XFS_TRANS_TRUNCATE_FILE: kdb_printf("TRUNCATE_FILE"); break; + case XFS_TRANS_REMOVE: kdb_printf("REMOVE"); break; + case XFS_TRANS_LINK: kdb_printf("LINK"); break; + case XFS_TRANS_RENAME: kdb_printf("RENAME"); break; + case XFS_TRANS_MKDIR: kdb_printf("MKDIR"); break; + case XFS_TRANS_RMDIR: kdb_printf("RMDIR"); break; + case XFS_TRANS_SYMLINK: kdb_printf("SYMLINK"); break; + case XFS_TRANS_SET_DMATTRS: kdb_printf("SET_DMATTRS"); break; + case XFS_TRANS_GROWFS: kdb_printf("GROWFS"); break; + case XFS_TRANS_STRAT_WRITE: kdb_printf("STRAT_WRITE"); break; + case XFS_TRANS_DIOSTRAT: kdb_printf("DIOSTRAT"); break; + case XFS_TRANS_WRITE_SYNC: kdb_printf("WRITE_SYNC"); break; + case XFS_TRANS_WRITEID: kdb_printf("WRITEID"); break; + case XFS_TRANS_ADDAFORK: kdb_printf("ADDAFORK"); break; + case XFS_TRANS_ATTRINVAL: kdb_printf("ATTRINVAL"); break; + case XFS_TRANS_ATRUNCATE: kdb_printf("ATRUNCATE"); break; + case XFS_TRANS_ATTR_SET: kdb_printf("ATTR_SET"); break; + case XFS_TRANS_ATTR_RM: kdb_printf("ATTR_RM"); break; + case XFS_TRANS_ATTR_FLAG: kdb_printf("ATTR_FLAG"); break; + case XFS_TRANS_CLEAR_AGI_BUCKET: kdb_printf("CLEAR_AGI_BUCKET"); break; + case XFS_TRANS_QM_SBCHANGE: kdb_printf("QM_SBCHANGE"); break; + case XFS_TRANS_QM_QUOTAOFF: kdb_printf("QM_QUOTAOFF"); break; + case XFS_TRANS_QM_DQALLOC: kdb_printf("QM_DQALLOC"); break; + case XFS_TRANS_QM_SETQLIM: kdb_printf("QM_SETQLIM"); break; + case XFS_TRANS_QM_DQCLUSTER: kdb_printf("QM_DQCLUSTER"); break; + case XFS_TRANS_QM_QINOCREATE: kdb_printf("QM_QINOCREATE"); break; + case XFS_TRANS_QM_QUOTAOFF_END: kdb_printf("QM_QOFF_END"); break; + case XFS_TRANS_SB_UNIT: kdb_printf("SB_UNIT"); break; + case XFS_TRANS_FSYNC_TS: kdb_printf("FSYNC_TS"); break; + case XFS_TRANS_GROWFSRT_ALLOC: kdb_printf("GROWFSRT_ALLOC"); break; + case XFS_TRANS_GROWFSRT_ZERO: kdb_printf("GROWFSRT_ZERO"); break; + case XFS_TRANS_GROWFSRT_FREE: kdb_printf("GROWFSRT_FREE"); break; + + default: kdb_printf("0x%x", tp->t_type); break; + } + kdb_printf(" mount 0x%p\n", tp->t_mountp); + kdb_printf("flags "); + printflags(tp->t_flags, xtp_flags,"xtp"); + kdb_printf("\n"); + kdb_printf("callback 0x%p forw 0x%p back 0x%p\n", + &tp->t_logcb, tp->t_forw, tp->t_back); + kdb_printf("log res %d block res %d block res used %d\n", + tp->t_log_res, tp->t_blk_res, tp->t_blk_res_used); + kdb_printf("rt res %d rt res used %d\n", tp->t_rtx_res, + tp->t_rtx_res_used); + kdb_printf("ticket 0x%lx lsn %s commit_lsn %s\n", + (unsigned long) tp->t_ticket, + xfs_fmtlsn(&tp->t_lsn), + xfs_fmtlsn(&tp->t_commit_lsn)); + kdb_printf("callback 0x%p callarg 0x%p\n", + tp->t_callback, tp->t_callarg); + kdb_printf("icount delta %ld ifree delta %ld\n", + tp->t_icount_delta, tp->t_ifree_delta); + kdb_printf("blocks delta %ld res blocks delta %ld\n", + tp->t_fdblocks_delta, tp->t_res_fdblocks_delta); + kdb_printf("rt delta %ld res rt delta %ld\n", + tp->t_frextents_delta, tp->t_res_frextents_delta); + kdb_printf("ag freeblks delta %ld ag flist delta %ld ag btree delta %ld\n", + tp->t_ag_freeblks_delta, tp->t_ag_flist_delta, + tp->t_ag_btree_delta); + kdb_printf("dblocks delta %ld agcount delta %ld imaxpct delta %ld\n", + tp->t_dblocks_delta, tp->t_agcount_delta, tp->t_imaxpct_delta); + kdb_printf("rextsize delta %ld rbmblocks delta %ld\n", + tp->t_rextsize_delta, tp->t_rbmblocks_delta); + kdb_printf("rblocks delta %ld rextents delta %ld rextslog delta %ld\n", + tp->t_rblocks_delta, tp->t_rextents_delta, + tp->t_rextslog_delta); + kdb_printf("dqinfo 0x%p\n", tp->t_dqinfo); + kdb_printf("log items:\n"); + licp = &tp->t_items; + chunk = 0; + while (licp != NULL) { + if (XFS_LIC_ARE_ALL_FREE(licp)) { + licp = licp->lic_next; + chunk++; + continue; + } + for (i = 0; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + kdb_printf("\n"); + kdb_printf("chunk %d index %d item 0x%p size %d\n", + chunk, i, lidp->lid_item, lidp->lid_size); + kdb_printf("flags "); + printflags(lidp->lid_flags, lid_flags,"lic"); + kdb_printf("\n"); + xfsidbg_xlogitem(lidp->lid_item); + } + chunk++; + licp = licp->lic_next; + } + + kdb_printf("log busy free %d, list:\n", tp->t_busy_free); + lbcp = &tp->t_busy; + chunk = 0; + while (lbcp != NULL) { + kdb_printf("Chunk %d at 0x%p next 0x%p free 0x%08x unused %d\n", + chunk, lbcp, lbcp->lbc_next, lbcp->lbc_free, + lbcp->lbc_unused); + for (i = 0; i < XFS_LBC_NUM_SLOTS; i++) { + kdb_printf(" %02d: ag %d idx %d\n", + i, + lbcp->lbc_busy[i].lbc_ag, + lbcp->lbc_busy[i].lbc_idx); + } + lbcp = lbcp->lbc_next; + } +} + +static void +xfsidbg_xtrans_res( + xfs_mount_t *mp) +{ + xfs_trans_reservations_t *xtrp; + + xtrp = &mp->m_reservations; + kdb_printf("write: %d\ttruncate: %d\trename: %d\n", + xtrp->tr_write, xtrp->tr_itruncate, xtrp->tr_rename); + kdb_printf("link: %d\tremove: %d\tsymlink: %d\n", + xtrp->tr_link, xtrp->tr_remove, xtrp->tr_symlink); + kdb_printf("create: %d\tmkdir: %d\tifree: %d\n", + xtrp->tr_create, xtrp->tr_mkdir, xtrp->tr_ifree); + kdb_printf("ichange: %d\tgrowdata: %d\tswrite: %d\n", + xtrp->tr_ichange, xtrp->tr_growdata, xtrp->tr_swrite); + kdb_printf("addafork: %d\twriteid: %d\tattrinval: %d\n", + xtrp->tr_addafork, xtrp->tr_writeid, xtrp->tr_attrinval); + kdb_printf("attrset: %d\tattrrm: %d\tclearagi: %d\n", + xtrp->tr_attrset, xtrp->tr_attrrm, xtrp->tr_clearagi); + kdb_printf("growrtalloc: %d\tgrowrtzero: %d\tgrowrtfree: %d\n", + xtrp->tr_growrtalloc, xtrp->tr_growrtzero, xtrp->tr_growrtfree); +} + +module_init(xfsidbg_init) +module_exit(xfsidbg_exit) diff -Nur linux-2.4.19/include/asm-alpha/dump.h linux-2.4.19-sgi211r3/include/asm-alpha/dump.h --- linux-2.4.19/include/asm-alpha/dump.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-alpha/dump.h Tue Jan 28 18:24:28 2003 @@ -0,0 +1,61 @@ +/* + * Kernel header file for Linux crash dumps. + * + * Created by: Matt Robinson (yakker@sgi.com) + * + * Copyright 1999 Silicon Graphics, Inc. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* This header file holds the architecture specific crash dump header */ +#ifndef _ASM_DUMP_H +#define _ASM_DUMP_H + +/* necessary header files */ +#include /* for pt_regs */ + +/* definitions */ +#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ +#define DUMP_ASM_VERSION_NUMBER 0x2 /* version number */ + + +/* + * Structure: dump_header_asm_t + * Function: This is the header for architecture-specific stuff. It + * follows right after the dump header. + */ +typedef struct _dump_header_asm_s { + + /* the dump magic number -- unique to verify dump is valid */ + uint64_t dha_magic_number; + + /* the version number of this dump */ + uint32_t dha_version; + + /* the size of this header (in case we can't read it) */ + uint32_t dha_header_size; + + /* the stack pointer for Alpha systems */ + uint64_t dha_sp; + + /* the return address for Alpha systems */ + uint64_t dha_ra; + + /* the dump registers */ + struct pt_regs dha_regs; + +} dump_header_asm_t; + +extern dump_header_asm_t dump_header_asm; + +#ifdef __KERNEL__ +#define get_current() \ +({ \ + register unsigned long sp; \ + asm("bis $30,$30,%0" : "=r" (sp)); \ + sp; \ +}) +#endif + +#endif /* _ASM_DUMP_H */ diff -Nur linux-2.4.19/include/asm-alpha/ioctls.h linux-2.4.19-sgi211r3/include/asm-alpha/ioctls.h --- linux-2.4.19/include/asm-alpha/ioctls.h Fri Apr 13 20:26:07 2001 +++ linux-2.4.19-sgi211r3/include/asm-alpha/ioctls.h Fri Apr 26 11:07:18 2002 @@ -9,6 +9,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) #define TIOCGETP _IOR('t', 8, struct sgttyb) #define TIOCSETP _IOW('t', 9, struct sgttyb) diff -Nur linux-2.4.19/include/asm-alpha/system.h linux-2.4.19-sgi211r3/include/asm-alpha/system.h --- linux-2.4.19/include/asm-alpha/system.h Thu Oct 4 18:47:08 2001 +++ linux-2.4.19-sgi211r3/include/asm-alpha/system.h Mon Oct 28 20:43:23 2002 @@ -130,7 +130,6 @@ extern void halt(void) __attribute__((noreturn)); #define __halt() __asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt)) -#define prepare_to_switch() do { } while(0) #define switch_to(prev,next,last) \ do { \ unsigned long pcbb; \ @@ -146,6 +145,9 @@ __asm__ __volatile__("mb": : :"memory") #define rmb() \ +__asm__ __volatile__("mb": : :"memory") + +#define read_barrier_depends() \ __asm__ __volatile__("mb": : :"memory") #define wmb() \ diff -Nur linux-2.4.19/include/asm-arm/page.h linux-2.4.19-sgi211r3/include/asm-arm/page.h --- linux-2.4.19/include/asm-arm/page.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-arm/page.h Wed Oct 16 14:02:58 2002 @@ -106,6 +106,9 @@ #define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + #endif #endif diff -Nur linux-2.4.19/include/asm-arm/system.h linux-2.4.19-sgi211r3/include/asm-arm/system.h --- linux-2.4.19/include/asm-arm/system.h Mon Nov 27 17:07:59 2000 +++ linux-2.4.19-sgi211r3/include/asm-arm/system.h Mon Oct 28 20:43:23 2002 @@ -38,6 +38,7 @@ #define mb() __asm__ __volatile__ ("" : : : "memory") #define rmb() mb() +#define read_barrier_depends() do { } while(0) #define wmb() mb() #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); diff -Nur linux-2.4.19/include/asm-cris/ioctls.h linux-2.4.19-sgi211r3/include/asm-cris/ioctls.h --- linux-2.4.19/include/asm-cris/ioctls.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-cris/ioctls.h Wed Oct 16 14:02:58 2002 @@ -69,6 +69,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 #define TIOCSERSETRS485 0x5460 /* enable rs-485 */ #define TIOCSERWRRS485 0x5461 /* write rs-485 */ diff -Nur linux-2.4.19/include/asm-cris/system.h linux-2.4.19-sgi211r3/include/asm-cris/system.h --- linux-2.4.19/include/asm-cris/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-cris/system.h Mon Oct 28 20:43:23 2002 @@ -149,6 +149,7 @@ #define mb() __asm__ __volatile__ ("" : : : "memory") #define rmb() mb() +#define read_barrier_depends() do { } while(0) #define wmb() mb() #ifdef CONFIG_SMP diff -Nur linux-2.4.19/include/asm-generic/tlb.h linux-2.4.19-sgi211r3/include/asm-generic/tlb.h --- linux-2.4.19/include/asm-generic/tlb.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-generic/tlb.h Fri Feb 7 12:02:39 2003 @@ -31,28 +31,33 @@ pte_t ptes[FREE_PTE_NR]; } mmu_gather_t; +#if defined(CONFIG_NUMA) && defined(CONFIG_IA64) /* Users of the generic TLB shootdown code must declare this storage space. */ +#define local_mmu_gathers local_cpu_data->mmu_gathers +#else extern mmu_gather_t mmu_gathers[NR_CPUS]; +#define local_mmu_gathers &mmu_gathers[smp_processor_id()] +#endif /* tlb_gather_mmu * Return a pointer to an initialized mmu_gather_t. */ static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm) { - mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()]; + mmu_gather_t *tlb = local_mmu_gathers; tlb->mm = mm; /* Use fast mode if there is only one user of this mm (this process) */ - tlb->nr = (atomic_read(&(mm)->mm_users) == 1) ? ~0UL : 0UL; + tlb->nr = (atomic_read(&(mm)->mm_users) <= 1) ? ~0UL : 0UL; return tlb; } -/* void tlb_remove_page(mmu_gather_t *tlb, pte_t *ptep, unsigned long addr) +/* void tlb_remove_page(mmu_gather_t *tlb, struct page *page, pte_t *ptep, unsigned long addr) * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while * handling the additional races in SMP caused by other CPUs caching valid * mappings in their TLBs. */ -#define tlb_remove_page(ctxp, pte, addr) do {\ +#define tlb_remove_page(ctxp, page, pte, addr) do {\ /* Handle the common case fast, first. */\ if ((ctxp)->nr == ~0UL) {\ pte_t __pte = *(pte);\ @@ -62,8 +67,10 @@ }\ if (!(ctxp)->nr) \ (ctxp)->start_addr = (addr);\ - (ctxp)->ptes[(ctxp)->nr++] = ptep_get_and_clear(pte);\ (ctxp)->end_addr = (addr) + PAGE_SIZE;\ + (ctxp)->ptes[(ctxp)->nr] = ptep_get_and_clear(pte);\ + if ((ctxp)->nr == 0 || (VALID_PAGE(page) && !PageReserved(page))) \ + (ctxp)->nr++; \ if ((ctxp)->nr >= FREE_PTE_NR)\ tlb_finish_mmu((ctxp), 0, 0);\ } while (0) @@ -71,6 +78,8 @@ /* tlb_finish_mmu * Called at the end of the shootdown operation to free up any resources * that were required. The page talbe lock is still held at this point. + * Note that no TLB flushes are needed if there are no users of the mm + * context. */ static inline void tlb_finish_mmu(struct free_pte_ctx *ctx, unsigned long start, unsigned long end) { @@ -78,7 +87,8 @@ /* Handle the fast case first. */ if (ctx->nr == ~0UL) { - flush_tlb_range(ctx->mm, start, end); + if (ctx->mm->mmap) + flush_tlb_range(ctx->mm, start, end); return; } nr = ctx->nr; @@ -101,7 +111,7 @@ #define tlb_gather_mmu(mm) (mm) #define tlb_finish_mmu(tlb, start, end) flush_tlb_range(tlb, start, end) -#define tlb_remove_page(tlb, ptep, addr) do {\ +#define tlb_remove_page(tlb, page, ptep, addr) do {\ pte_t __pte = *(ptep);\ pte_clear(ptep);\ __free_pte(__pte);\ diff -Nur linux-2.4.19/include/asm-i386/bitops.h linux-2.4.19-sgi211r3/include/asm-i386/bitops.h --- linux-2.4.19/include/asm-i386/bitops.h Thu Nov 22 11:46:18 2001 +++ linux-2.4.19-sgi211r3/include/asm-i386/bitops.h Mon Oct 28 20:43:23 2002 @@ -75,6 +75,14 @@ :"=m" (ADDR) :"Ir" (nr)); } + +static __inline__ void __clear_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( + "btrl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() @@ -284,6 +292,34 @@ } /** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first set bit, not the number of the byte + * containing a bit. + */ +static __inline__ int find_first_bit(void * addr, unsigned size) +{ + int d0, d1; + int res; + + /* This looks at memory. Mark it volatile to tell gcc not to move it around */ + __asm__ __volatile__( + "xorl %%eax,%%eax\n\t" + "repe; scasl\n\t" + "jz 1f\n\t" + "leal -4(%%edi),%%edi\n\t" + "bsfl (%%edi),%%eax\n" + "1:\tsubl %%ebx,%%edi\n\t" + "shll $3,%%edi\n\t" + "addl %%edi,%%eax" + :"=a" (res), "=&c" (d0), "=&D" (d1) + :"1" ((size + 31) >> 5), "2" (addr), "b" (addr)); + return res; +} + +/** * find_next_zero_bit - find the first zero bit in a memory region * @addr: The address to base the search on * @offset: The bitnumber to start searching at @@ -296,7 +332,7 @@ if (bit) { /* - * Look for zero in first byte + * Look for zero in the first 32 bits. */ __asm__("bsfl %1,%0\n\t" "jne 1f\n\t" @@ -317,6 +353,39 @@ } /** + * find_next_bit - find the first set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static __inline__ int find_next_bit (void * addr, int size, int offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* + * Look for nonzero in the first 32 bits: + */ + __asm__("bsfl %1,%0\n\t" + "jne 1f\n\t" + "movl $32, %0\n" + "1:" + : "=r" (set) + : "r" (*p >> bit)); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* + * No set bit yet, search remaining full words for a bit + */ + res = find_first_bit (p, size - 32 * (p - (unsigned long *) addr)); + return (offset + set + res); +} + +/** * ffz - find first zero in word. * @word: The word to search * @@ -330,6 +399,20 @@ return word; } +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static __inline__ unsigned long __ffs(unsigned long word) +{ + __asm__("bsfl %1,%0" + :"=r" (word) + :"rm" (word)); + return word; +} + #ifdef __KERNEL__ /** @@ -347,7 +430,7 @@ __asm__("bsfl %1,%0\n\t" "jnz 1f\n\t" "movl $-1,%0\n" - "1:" : "=r" (r) : "g" (x)); + "1:" : "=r" (r) : "rm" (x)); return r+1; } diff -Nur linux-2.4.19/include/asm-i386/byteorder.h linux-2.4.19-sgi211r3/include/asm-i386/byteorder.h --- linux-2.4.19/include/asm-i386/byteorder.h Thu Nov 22 11:46:18 2001 +++ linux-2.4.19-sgi211r3/include/asm-i386/byteorder.h Fri Nov 1 12:24:39 2002 @@ -24,21 +24,41 @@ return x; } +/* gcc should generate this for open coded C now too. May be worth switching to + it because inline assembly cannot be scheduled. -AK */ static __inline__ __const__ __u16 ___arch__swab16(__u16 x) { - __asm__("xchgb %b0,%h0" /* swap bytes */ \ - : "=q" (x) \ - : "0" (x)); \ + __asm__("xchgb %b0,%h0" /* swap bytes */ + : "=q" (x) + : "0" (x)); return x; } + +static inline __u64 ___arch__swab64(__u64 val) +{ + union { + struct { __u32 a,b; } s; + __u64 u; + } v; + v.u = val; +#ifdef CONFIG_X86_BSWAP + asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1" + : "=r" (v.s.a), "=r" (v.s.b) + : "0" (v.s.a), "1" (v.s.b)); +#else + v.s.a = ___arch__swab32(v.s.a); + v.s.b = ___arch__swab32(v.s.b); + asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b)); +#endif + return v.u; +} + +#define __arch__swab64(x) ___arch__swab64(x) #define __arch__swab32(x) ___arch__swab32(x) #define __arch__swab16(x) ___arch__swab16(x) -#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) -# define __BYTEORDER_HAS_U64__ -# define __SWAB_64_THRU_32__ -#endif +#define __BYTEORDER_HAS_U64__ #endif /* __GNUC__ */ diff -Nur linux-2.4.19/include/asm-i386/dump.h linux-2.4.19-sgi211r3/include/asm-i386/dump.h --- linux-2.4.19/include/asm-i386/dump.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-i386/dump.h Thu Oct 24 05:25:29 2002 @@ -0,0 +1,88 @@ +/* + * Kernel header file for Linux crash dumps. + * + * Created by: Matt Robinson (yakker@sgi.com) + * + * Copyright 1999 Silicon Graphics, Inc. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* This header file holds the architecture specific crash dump header */ +#ifndef _ASM_DUMP_H +#define _ASM_DUMP_H + +/* necessary header files */ +#include /* for pt_regs */ +#include + +/* definitions */ +#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ +#define DUMP_ASM_VERSION_NUMBER 0x2 /* version number */ + + +/* + * Structure: dump_header_asm_t + * Function: This is the header for architecture-specific stuff. It + * follows right after the dump header. + */ +typedef struct _dump_header_asm_s { + + /* the dump magic number -- unique to verify dump is valid */ + uint64_t dha_magic_number; + + /* the version number of this dump */ + uint32_t dha_version; + + /* the size of this header (in case we can't read it) */ + uint32_t dha_header_size; + + /* the esp for i386 systems */ + uint32_t dha_esp; + + /* the eip for i386 systems */ + uint32_t dha_eip; + + /* the dump registers */ + struct pt_regs dha_regs; + + /* smp specific */ + uint32_t dha_smp_num_cpus; + int dha_dumping_cpu; + struct pt_regs dha_smp_regs[NR_CPUS]; + void * dha_smp_current_task[NR_CPUS]; + void * dha_stack[NR_CPUS]; +} dump_header_asm_t; + +#ifdef __KERNEL__ +static inline void get_current_regs(struct pt_regs *regs) +{ + __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx)); + __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx)); + __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx)); + __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi)); + __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi)); + __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp)); + __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax)); + __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp)); + __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss)); + __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs)); + __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds)); + __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes)); + __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags)); + regs->eip = (unsigned long)current_text_addr(); + +} + +extern dump_header_asm_t dump_header_asm; + +#ifdef CONFIG_SMP +extern unsigned long irq_affinity[]; +extern int (*dump_ipi_function_ptr)(struct pt_regs *); +extern void dump_send_ipi(void); +#else +#define dump_send_ipi() +#endif +#endif /* __KERNEL__ */ + +#endif /* _ASM_DUMP_H */ diff -Nur linux-2.4.19/include/asm-i386/hw_irq.h linux-2.4.19-sgi211r3/include/asm-i386/hw_irq.h --- linux-2.4.19/include/asm-i386/hw_irq.h Thu Nov 22 11:46:18 2001 +++ linux-2.4.19-sgi211r3/include/asm-i386/hw_irq.h Fri Nov 1 07:16:07 2002 @@ -23,6 +23,7 @@ #define FIRST_EXTERNAL_VECTOR 0x20 #define SYSCALL_VECTOR 0x80 +#define KDBENTER_VECTOR 0x81 /* * Vectors 0x20-0x2f are used for ISA interrupts. @@ -42,6 +43,10 @@ #define INVALIDATE_TLB_VECTOR 0xfd #define RESCHEDULE_VECTOR 0xfc #define CALL_FUNCTION_VECTOR 0xfb +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#define DUMP_VECTOR 0xfa +#endif +#define KDB_VECTOR 0xf9 /* * Local APIC timer IRQ vector is on a different priority level, @@ -221,5 +226,7 @@ #else static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {} #endif + +extern irq_desc_t irq_desc [NR_IRQS]; #endif /* _ASM_HW_IRQ_H */ diff -Nur linux-2.4.19/include/asm-i386/io.h linux-2.4.19-sgi211r3/include/asm-i386/io.h --- linux-2.4.19/include/asm-i386/io.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-i386/io.h Wed Oct 16 14:02:58 2002 @@ -306,6 +306,8 @@ #endif +#define mmiob() do { } while(0) + #endif /* __KERNEL__ */ #ifdef SLOW_IO_BY_JUMPING diff -Nur linux-2.4.19/include/asm-i386/ioctls.h linux-2.4.19-sgi211r3/include/asm-i386/ioctls.h --- linux-2.4.19/include/asm-i386/ioctls.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-i386/ioctls.h Wed Oct 16 14:02:58 2002 @@ -67,6 +67,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -Nur linux-2.4.19/include/asm-i386/kdb.h linux-2.4.19-sgi211r3/include/asm-i386/kdb.h --- linux-2.4.19/include/asm-i386/kdb.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-i386/kdb.h Tue Feb 4 15:36:30 2003 @@ -0,0 +1,143 @@ +#ifndef _ASM_KDB_H +#define _ASM_KDB_H + +/* + * Kernel Debugger Architecture Dependent Global Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + /* + * KDB_ENTER() is a macro which causes entry into the kernel + * debugger from any point in the kernel code stream. If it + * is intended to be used from interrupt level, it must use + * a non-maskable entry method. + */ +#define KDB_ENTER() if (kdb_on && !KDB_IS_RUNNING()) { asm("\tint $129\n"); } + + /* + * Needed for exported symbols. + */ +typedef unsigned long kdb_machreg_t; + +#define kdb_machreg_fmt "0x%lx" +#define kdb_machreg_fmt0 "0x%08lx" +#define kdb_bfd_vma_fmt "0x%lx" +#define kdb_bfd_vma_fmt0 "0x%08lx" +#define kdb_elfw_addr_fmt "0x%x" +#define kdb_elfw_addr_fmt0 "0x%08x" + + /* + * Per cpu arch specific kdb state. Must be in range 0xff000000. + */ +#define KDB_STATE_A_IF 0x01000000 /* Saved IF flag */ + + /* + * Functions to safely read and write kernel areas. The {to,from}_xxx + * addresses are not necessarily valid, these functions must check for + * validity. If the arch already supports get and put routines with + * suitable validation and/or recovery on invalid addresses then use + * those routines, otherwise check it yourself. + */ + + /* + * asm-i386 uaccess.h supplies __copy_to_user which relies on MMU to + * trap invalid addresses in the _xxx fields. Verify the other address + * of the pair is valid by accessing the first and last byte ourselves, + * then any access violations should only be caused by the _xxx + * addresses, + */ + +#include + +static inline int +__kdba_putarea_size(unsigned long to_xxx, void *from, size_t size) +{ + mm_segment_t oldfs = get_fs(); + int r; + char c; + c = *((volatile char *)from); + c = *((volatile char *)from + size - 1); + set_fs(KERNEL_DS); + r = __copy_to_user((void *)to_xxx, from, size); + set_fs(oldfs); + return r; +} + +static inline int +__kdba_getarea_size(void *to, unsigned long from_xxx, size_t size) +{ + mm_segment_t oldfs = get_fs(); + int r; + *((volatile char *)to) = '\0'; + *((volatile char *)to + size - 1) = '\0'; + set_fs(KERNEL_DS); + switch (size) { + case 1: + r = __copy_to_user(to, (void *)from_xxx, 1); + break; + case 2: + r = __copy_to_user(to, (void *)from_xxx, 2); + break; + case 4: + r = __copy_to_user(to, (void *)from_xxx, 4); + break; + case 8: + r = __copy_to_user(to, (void *)from_xxx, 8); + break; + default: + r = __copy_to_user(to, (void *)from_xxx, size); + break; + } + set_fs(oldfs); + return r; +} + +/* For numa with replicated code/data, the platform must supply its own + * kdba_putarea_size and kdba_getarea_size routines. Without replication kdb + * uses the standard architecture routines. + */ +#ifdef CONFIG_NUMA_REPLICATE +extern int kdba_putarea_size(unsigned long to_xxx, void *from, size_t size); +extern int kdba_getarea_size(void *to, unsigned long from_xxx, size_t size); +#else +#define kdba_putarea_size __kdba_putarea_size +#define kdba_getarea_size __kdba_getarea_size +#endif + +static inline int +kdba_verify_rw(unsigned long addr, size_t size) +{ + unsigned char data[size]; + return(kdba_getarea_size(data, addr, size) || kdba_putarea_size(addr, data, size)); +} + +#endif /* !_ASM_KDB_H */ diff -Nur linux-2.4.19/include/asm-i386/kdbprivate.h linux-2.4.19-sgi211r3/include/asm-i386/kdbprivate.h --- linux-2.4.19/include/asm-i386/kdbprivate.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-i386/kdbprivate.h Tue Feb 4 15:36:30 2003 @@ -0,0 +1,187 @@ +#ifndef _ASM_KDBPRIVATE_H +#define _ASM_KDBPRIVATE_H + +/* + * Kernel Debugger Architecture Dependent Private Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +typedef unsigned char kdb_machinst_t; + + /* + * KDB_MAXBPT describes the total number of breakpoints + * supported by this architecure. + */ +#define KDB_MAXBPT 16 + + /* + * KDB_MAXHARDBPT describes the total number of hardware + * breakpoint registers that exist. + */ +#define KDB_MAXHARDBPT 4 + + /* + * Platform specific environment entries + */ +#define KDB_PLATFORM_ENV "IDMODE=x86", "BYTESPERWORD=4", "IDCOUNT=16" + + /* + * Define the direction that the stack grows + */ +#define KDB_STACK_DIRECTION (-1) /* Stack grows down */ + + /* + * Support for ia32 debug registers + */ +typedef struct _kdbhard_bp { + kdb_machreg_t bph_reg; /* Register this breakpoint uses */ + + unsigned int bph_free:1; /* Register available for use */ + unsigned int bph_data:1; /* Data Access breakpoint */ + + unsigned int bph_write:1; /* Write Data breakpoint */ + unsigned int bph_mode:2; /* 0=inst, 1=write, 2=io, 3=read */ + unsigned int bph_length:2; /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */ +} kdbhard_bp_t; + +extern kdbhard_bp_t kdb_hardbreaks[/* KDB_MAXHARDBPT */]; + +#define IA32_BREAKPOINT_INSTRUCTION 0xcc + +#define DR6_BT 0x00008000 +#define DR6_BS 0x00004000 +#define DR6_BD 0x00002000 + +#define DR6_B3 0x00000008 +#define DR6_B2 0x00000004 +#define DR6_B1 0x00000002 +#define DR6_B0 0x00000001 + +#define DR7_RW_VAL(dr, drnum) \ + (((dr) >> (16 + (4 * (drnum)))) & 0x3) + +#define DR7_RW_SET(dr, drnum, rw) \ + do { \ + (dr) &= ~(0x3 << (16 + (4 * (drnum)))); \ + (dr) |= (((rw) & 0x3) << (16 + (4 * (drnum)))); \ + } while (0) + +#define DR7_RW0(dr) DR7_RW_VAL(dr, 0) +#define DR7_RW0SET(dr,rw) DR7_RW_SET(dr, 0, rw) +#define DR7_RW1(dr) DR7_RW_VAL(dr, 1) +#define DR7_RW1SET(dr,rw) DR7_RW_SET(dr, 1, rw) +#define DR7_RW2(dr) DR7_RW_VAL(dr, 2) +#define DR7_RW2SET(dr,rw) DR7_RW_SET(dr, 2, rw) +#define DR7_RW3(dr) DR7_RW_VAL(dr, 3) +#define DR7_RW3SET(dr,rw) DR7_RW_SET(dr, 3, rw) + + +#define DR7_LEN_VAL(dr, drnum) \ + (((dr) >> (18 + (4 * (drnum)))) & 0x3) + +#define DR7_LEN_SET(dr, drnum, rw) \ + do { \ + (dr) &= ~(0x3 << (18 + (4 * (drnum)))); \ + (dr) |= (((rw) & 0x3) << (18 + (4 * (drnum)))); \ + } while (0) +#define DR7_LEN0(dr) DR7_LEN_VAL(dr, 0) +#define DR7_LEN0SET(dr,len) DR7_LEN_SET(dr, 0, len) +#define DR7_LEN1(dr) DR7_LEN_VAL(dr, 1) +#define DR7_LEN1SET(dr,len) DR7_LEN_SET(dr, 1, len) +#define DR7_LEN2(dr) DR7_LEN_VAL(dr, 2) +#define DR7_LEN2SET(dr,len) DR7_LEN_SET(dr, 2, len) +#define DR7_LEN3(dr) DR7_LEN_VAL(dr, 3) +#define DR7_LEN3SET(dr,len) DR7_LEN_SET(dr, 3, len) + +#define DR7_G0(dr) (((dr)>>1)&0x1) +#define DR7_G0SET(dr) ((dr) |= 0x2) +#define DR7_G0CLR(dr) ((dr) &= ~0x2) +#define DR7_G1(dr) (((dr)>>3)&0x1) +#define DR7_G1SET(dr) ((dr) |= 0x8) +#define DR7_G1CLR(dr) ((dr) &= ~0x8) +#define DR7_G2(dr) (((dr)>>5)&0x1) +#define DR7_G2SET(dr) ((dr) |= 0x20) +#define DR7_G2CLR(dr) ((dr) &= ~0x20) +#define DR7_G3(dr) (((dr)>>7)&0x1) +#define DR7_G3SET(dr) ((dr) |= 0x80) +#define DR7_G3CLR(dr) ((dr) &= ~0x80) + +#define DR7_L0(dr) (((dr))&0x1) +#define DR7_L0SET(dr) ((dr) |= 0x1) +#define DR7_L0CLR(dr) ((dr) &= ~0x1) +#define DR7_L1(dr) (((dr)>>2)&0x1) +#define DR7_L1SET(dr) ((dr) |= 0x4) +#define DR7_L1CLR(dr) ((dr) &= ~0x4) +#define DR7_L2(dr) (((dr)>>4)&0x1) +#define DR7_L2SET(dr) ((dr) |= 0x10) +#define DR7_L2CLR(dr) ((dr) &= ~0x10) +#define DR7_L3(dr) (((dr)>>6)&0x1) +#define DR7_L3SET(dr) ((dr) |= 0x40) +#define DR7_L3CLR(dr) ((dr) &= ~0x40) + +#define DR7_GD 0x00002000 /* General Detect Enable */ +#define DR7_GE 0x00000200 /* Global exact */ +#define DR7_LE 0x00000100 /* Local exact */ + +extern kdb_machreg_t kdba_getdr6(void); +extern void kdba_putdr6(kdb_machreg_t); + +extern kdb_machreg_t kdba_getdr7(void); + +extern kdb_machreg_t kdba_getdr(int); +extern void kdba_putdr(int, kdb_machreg_t); + +extern kdb_machreg_t kdb_getcr(int); + +#define KDB_HAVE_LONGJMP +#ifdef KDB_HAVE_LONGJMP +/* + * Support for setjmp/longjmp + */ +#define JB_BX 0 +#define JB_SI 1 +#define JB_DI 2 +#define JB_BP 3 +#define JB_SP 4 +#define JB_PC 5 + +typedef struct __kdb_jmp_buf { + unsigned long regs[6]; /* kdba_setjmp assumes fixed offsets here */ +} kdb_jmp_buf; + +extern int kdba_setjmp(kdb_jmp_buf *); +extern void kdba_longjmp(kdb_jmp_buf *, int); + +extern kdb_jmp_buf kdbjmpbuf[]; +#endif /* KDB_HAVE_LONGJMP */ + +#endif /* !_ASM_KDBPRIVATE_H */ diff -Nur linux-2.4.19/include/asm-i386/keyboard.h linux-2.4.19-sgi211r3/include/asm-i386/keyboard.h --- linux-2.4.19/include/asm-i386/keyboard.h Thu Nov 22 11:47:23 2001 +++ linux-2.4.19-sgi211r3/include/asm-i386/keyboard.h Wed Jan 30 15:32:11 2002 @@ -42,6 +42,7 @@ #define kbd_sysrq_xlate pckbd_sysrq_xlate #define SYSRQ_KEY 0x54 +#define E1_PAUSE 119 /* PAUSE key */ /* resource allocation */ #define kbd_request_region() diff -Nur linux-2.4.19/include/asm-i386/mmu_context.h linux-2.4.19-sgi211r3/include/asm-i386/mmu_context.h --- linux-2.4.19/include/asm-i386/mmu_context.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-i386/mmu_context.h Mon Oct 28 20:43:23 2002 @@ -7,6 +7,25 @@ #include /* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is cleared. + */ +static inline int sched_find_first_bit(unsigned long *b) +{ + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (b[3]) + return __ffs(b[3]) + 96; + return __ffs(b[4]) + 128; +} + +/* * possibly do the LDT unload here? */ #define destroy_context(mm) do { } while(0) @@ -27,13 +46,13 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) { - if (prev != next) { + if (likely(prev != next)) { /* stop flush ipis for the previous mm */ clear_bit(cpu, &prev->cpu_vm_mask); /* * Re-load LDT if necessary */ - if (prev->context.segments != next->context.segments) + if (unlikely(prev->context.segments != next->context.segments)) load_LDT(next); #ifdef CONFIG_SMP cpu_tlbstate[cpu].state = TLBSTATE_OK; diff -Nur linux-2.4.19/include/asm-i386/page.h linux-2.4.19-sgi211r3/include/asm-i386/page.h --- linux-2.4.19/include/asm-i386/page.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-i386/page.h Wed Oct 16 14:02:58 2002 @@ -30,8 +30,8 @@ #endif -#define clear_user_page(page, vaddr) clear_page(page) -#define copy_user_page(to, from, vaddr) copy_page(to, from) +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) /* * These are used to make use of C type-checking.. diff -Nur linux-2.4.19/include/asm-i386/pgalloc.h linux-2.4.19-sgi211r3/include/asm-i386/pgalloc.h --- linux-2.4.19/include/asm-i386/pgalloc.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-i386/pgalloc.h Mon Oct 28 20:43:23 2002 @@ -224,6 +224,7 @@ { struct mm_struct *active_mm; int state; + char __cacheline_padding[24]; }; extern struct tlb_state cpu_tlbstate[NR_CPUS]; diff -Nur linux-2.4.19/include/asm-i386/ptrace.h linux-2.4.19-sgi211r3/include/asm-i386/ptrace.h --- linux-2.4.19/include/asm-i386/ptrace.h Fri Sep 14 14:04:08 2001 +++ linux-2.4.19-sgi211r3/include/asm-i386/ptrace.h Wed Jan 30 15:32:11 2002 @@ -54,10 +54,34 @@ /* options set using PTRACE_SETOPTIONS */ #define PTRACE_O_TRACESYSGOOD 0x00000001 +enum EFLAGS { + EF_CF = 0x00000001, + EF_PF = 0x00000004, + EF_AF = 0x00000010, + EF_ZF = 0x00000040, + EF_SF = 0x00000080, + EF_TF = 0x00000100, + EF_IE = 0x00000200, + EF_DF = 0x00000400, + EF_OF = 0x00000800, + EF_IOPL = 0x00003000, + EF_IOPL_RING0 = 0x00000000, + EF_IOPL_RING1 = 0x00001000, + EF_IOPL_RING2 = 0x00002000, + EF_NT = 0x00004000, /* nested task */ + EF_RF = 0x00010000, /* resume */ + EF_VM = 0x00020000, /* virtual mode */ + EF_AC = 0x00040000, /* alignment */ + EF_VIF = 0x00080000, /* virtual interrupt */ + EF_VIP = 0x00100000, /* virtual interrupt pending */ + EF_ID = 0x00200000, /* id */ +}; + #ifdef __KERNEL__ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) extern void show_regs(struct pt_regs *); +#define force_successful_syscall_return() #endif #endif diff -Nur linux-2.4.19/include/asm-i386/smp.h linux-2.4.19-sgi211r3/include/asm-i386/smp.h --- linux-2.4.19/include/asm-i386/smp.h Fri Dec 21 09:42:03 2001 +++ linux-2.4.19-sgi211r3/include/asm-i386/smp.h Mon Oct 28 20:43:23 2002 @@ -54,7 +54,11 @@ extern void smp_alloc_memory(void); extern unsigned long phys_cpu_present_map; -extern unsigned long cpu_online_map; +extern +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + volatile +#endif + unsigned long cpu_online_map; extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; extern int smp_num_siblings; @@ -63,6 +67,7 @@ extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); +extern void smp_send_reschedule_all(void); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); @@ -104,7 +109,7 @@ * so this is correct in the x86 case. */ -#define smp_processor_id() (current->processor) +#define smp_processor_id() (current->cpu) static __inline int hard_smp_processor_id(void) { @@ -121,18 +126,6 @@ #endif /* !__ASSEMBLY__ */ #define NO_PROC_ID 0xFF /* No processor magic marker */ - -/* - * This magic constant controls our willingness to transfer - * a process across CPUs. Such a transfer incurs misses on the L1 - * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My - * gut feeling is this will vary by board in value. For a board - * with separate L2 cache it probably depends also on the RSS, and - * for a board with shared L2 cache it ought to decay fast as other - * processes are run. - */ - -#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ #endif #endif diff -Nur linux-2.4.19/include/asm-i386/spinlock.h linux-2.4.19-sgi211r3/include/asm-i386/spinlock.h --- linux-2.4.19/include/asm-i386/spinlock.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-i386/spinlock.h Wed Oct 16 14:02:58 2002 @@ -49,7 +49,7 @@ * We make no fairness assumptions. They have a cost. */ -#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0) +#define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0) #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) #define spin_lock_string \ diff -Nur linux-2.4.19/include/asm-i386/system.h linux-2.4.19-sgi211r3/include/asm-i386/system.h --- linux-2.4.19/include/asm-i386/system.h Thu Nov 22 11:46:18 2001 +++ linux-2.4.19-sgi211r3/include/asm-i386/system.h Wed Feb 5 15:21:59 2003 @@ -12,7 +12,6 @@ struct task_struct; /* one of the stranger aspects of C forward declarations.. */ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); -#define prepare_to_switch() do { } while(0) #define switch_to(prev,next,last) do { \ asm volatile("pushl %%esi\n\t" \ "pushl %%edi\n\t" \ @@ -33,6 +32,10 @@ "b" (prev)); \ } while (0) +#define prepare_arch_switch(rq, next) do {spin_lock(&(next)->switch_lock); spin_unlock(&(rq)->lock);} while(0) +#define finish_arch_switch(rq, prev) do {spin_unlock_irq(&(prev)->switch_lock);} while(0) +#define task_running(rq, p) (((rq)->curr == (p)) || spin_is_locked(&(p)->switch_lock)) + #define _set_base(addr,base) do { unsigned long __pr; \ __asm__ __volatile__ ("movw %%dx,%1\n\t" \ "rorl $16,%%edx\n\t" \ @@ -289,6 +292,7 @@ #define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") #define rmb() mb() +#define read_barrier_depends() do { } while(0) #ifdef CONFIG_X86_OOSTORE #define wmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") diff -Nur linux-2.4.19/include/asm-i386/unistd.h linux-2.4.19-sgi211r3/include/asm-i386/unistd.h --- linux-2.4.19/include/asm-i386/unistd.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-i386/unistd.h Wed Oct 16 14:02:58 2002 @@ -247,6 +247,12 @@ #define __NR_futex 240 #define __NR_sched_setaffinity 241 #define __NR_sched_getaffinity 242 +#if defined(CONFIG_PAGG) +#define __NR_paggctl 253 +#endif +#if defined(CONFIG_CSA_JOB_ACCT) || defined(CONFIG_CSA_JOB_ACCT_MODULE) +#define __NR_acctctl 254 +#endif /* user-visible error numbers are in the range -1 - -124: see */ diff -Nur linux-2.4.19/include/asm-ia64/a.out.h linux-2.4.19-sgi211r3/include/asm-ia64/a.out.h --- linux-2.4.19/include/asm-ia64/a.out.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/a.out.h Fri Sep 6 10:54:59 2002 @@ -11,6 +11,7 @@ * David Mosberger-Tang */ +#include #include struct exec { @@ -31,8 +32,16 @@ #ifdef __KERNEL__ # include +#ifdef CONFIG_IA64_PAGE_SIZE_64KB +# define STACK_TOP (0x6000000000000000UL + (1UL << 50) - PAGE_SIZE) +#else # define STACK_TOP (0x6000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) -# define IA64_RBS_BOT (STACK_TOP - 0x80000000L + PAGE_SIZE) /* bottom of reg. backing store */ +#endif +#ifdef CONFIG_IA64_PAGE_SIZE_4KB +# define IA64_RBS_BOT (STACK_TOP - 0x800000000UL + PAGE_SIZE) /* bottom of reg. backing store */ +#else +# define IA64_RBS_BOT (STACK_TOP - 0x8000000000UL + PAGE_SIZE) /* bottom of reg. backing store */ +#endif #endif #endif /* _ASM_IA64_A_OUT_H */ diff -Nur linux-2.4.19/include/asm-ia64/acpi-ext.h linux-2.4.19-sgi211r3/include/asm-ia64/acpi-ext.h --- linux-2.4.19/include/asm-ia64/acpi-ext.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/acpi-ext.h Wed Dec 31 16:00:00 1969 @@ -1,323 +0,0 @@ -#ifndef _ASM_IA64_ACPI_EXT_H -#define _ASM_IA64_ACPI_EXT_H - -/* - * Advanced Configuration and Power Infterface - * Based on 'ACPI Specification 1.0b' Febryary 2, 1999 - * and 'IA-64 Extensions to the ACPI Specification' Rev 0.6 - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - * Copyright (C) 2000 Intel Corp. - * Copyright (C) 2000,2001 J.I. Lee - * ACPI 2.0 specification - */ - -#include -#include -#include - -#pragma pack(1) -#define ACPI_RSDP_SIG "RSD PTR " /* Trailing space required */ -#define ACPI_RSDP_SIG_LEN 8 -typedef struct { - char signature[8]; - u8 checksum; - char oem_id[6]; - u8 revision; - u32 rsdt; - u32 length; - struct acpi_xsdt *xsdt; - u8 ext_checksum; - u8 reserved[3]; -} acpi20_rsdp_t; - -typedef struct { - char signature[4]; - u32 length; - u8 revision; - u8 checksum; - char oem_id[6]; - char oem_table_id[8]; - u32 oem_revision; - u32 creator_id; - u32 creator_revision; -} acpi_desc_table_hdr_t; - -#define ACPI_RSDT_SIG "RSDT" -#define ACPI_RSDT_SIG_LEN 4 -typedef struct { - acpi_desc_table_hdr_t header; - u8 reserved[4]; - u32 entry_ptrs[1]; /* Not really . . . */ -} acpi20_rsdt_t; - -#define ACPI_XSDT_SIG "XSDT" -#define ACPI_XSDT_SIG_LEN 4 -typedef struct acpi_xsdt { - acpi_desc_table_hdr_t header; - unsigned long entry_ptrs[1]; /* Not really . . . */ -} acpi_xsdt_t; - -/* Common structures for ACPI 2.0 and 0.71 */ - -typedef struct acpi_entry_iosapic { - u8 type; - u8 length; - u8 id; - u8 reserved; - u32 irq_base; /* start of IRQ's this IOSAPIC is responsible for. */ - unsigned long address; /* Address of this IOSAPIC */ -} acpi_entry_iosapic_t; - -/* Local SAPIC flags */ -#define LSAPIC_ENABLED (1<<0) -#define LSAPIC_PERFORMANCE_RESTRICTED (1<<1) -#define LSAPIC_PRESENT (1<<2) - -/* Defines legacy IRQ->pin mapping */ -typedef struct { - u8 type; - u8 length; - u8 bus; /* Constant 0 == ISA */ - u8 isa_irq; /* ISA IRQ # */ - u32 pin; /* called vector in spec; really IOSAPIC pin number */ - u16 flags; /* Edge/Level trigger & High/Low active */ -} acpi_entry_int_override_t; - -#define INT_OVERRIDE_ACTIVE_LOW 0x03 -#define INT_OVERRIDE_LEVEL_TRIGGER 0x0d - -/* IA64 ext 0.71 */ - -typedef struct { - char signature[8]; - u8 checksum; - char oem_id[6]; - char reserved; /* Must be 0 */ - struct acpi_rsdt *rsdt; -} acpi_rsdp_t; - -typedef struct acpi_rsdt { - acpi_desc_table_hdr_t header; - u8 reserved[4]; - unsigned long entry_ptrs[1]; /* Not really . . . */ -} acpi_rsdt_t; - -#define ACPI_SAPIC_SIG "SPIC" -#define ACPI_SAPIC_SIG_LEN 4 -typedef struct { - acpi_desc_table_hdr_t header; - u8 reserved[4]; - unsigned long interrupt_block; -} acpi_sapic_t; - -/* SAPIC structure types */ -#define ACPI_ENTRY_LOCAL_SAPIC 0 -#define ACPI_ENTRY_IO_SAPIC 1 -#define ACPI_ENTRY_INT_SRC_OVERRIDE 2 -#define ACPI_ENTRY_PLATFORM_INT_SOURCE 3 /* Unimplemented */ - -typedef struct acpi_entry_lsapic { - u8 type; - u8 length; - u16 acpi_processor_id; - u16 flags; - u8 id; - u8 eid; -} acpi_entry_lsapic_t; - -typedef struct { - u8 type; - u8 length; - u16 flags; - u8 int_type; - u8 id; - u8 eid; - u8 iosapic_vector; - u8 reserved[4]; - u32 global_vector; -} acpi_entry_platform_src_t; - -/* ACPI 2.0 with 1.3 errata specific structures */ - -#define ACPI_MADT_SIG "APIC" -#define ACPI_MADT_SIG_LEN 4 -typedef struct { - acpi_desc_table_hdr_t header; - u32 lapic_address; - u32 flags; -} acpi_madt_t; - -/* acpi 2.0 MADT flags */ -#define MADT_PCAT_COMPAT (1<<0) - -/* acpi 2.0 MADT structure types */ -#define ACPI20_ENTRY_LOCAL_APIC 0 -#define ACPI20_ENTRY_IO_APIC 1 -#define ACPI20_ENTRY_INT_SRC_OVERRIDE 2 -#define ACPI20_ENTRY_NMI_SOURCE 3 -#define ACPI20_ENTRY_LOCAL_APIC_NMI 4 -#define ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE 5 -#define ACPI20_ENTRY_IO_SAPIC 6 -#define ACPI20_ENTRY_LOCAL_SAPIC 7 -#define ACPI20_ENTRY_PLATFORM_INT_SOURCE 8 - -typedef struct acpi20_entry_lsapic { - u8 type; - u8 length; - u8 acpi_processor_id; - u8 id; - u8 eid; - u8 reserved[3]; - u32 flags; -} acpi20_entry_lsapic_t; - -typedef struct acpi20_entry_lapic_addr_override { - u8 type; - u8 length; - u8 reserved[2]; - unsigned long lapic_address; -} acpi20_entry_lapic_addr_override_t; - -typedef struct { - u8 type; - u8 length; - u16 flags; - u8 int_type; - u8 id; - u8 eid; - u8 iosapic_vector; - u32 global_vector; -} acpi20_entry_platform_src_t; - -/* constants for interrupt routing API for device drivers */ -#define ACPI20_ENTRY_PIS_PMI 1 -#define ACPI20_ENTRY_PIS_INIT 2 -#define ACPI20_ENTRY_PIS_CPEI 3 -#define ACPI_MAX_PLATFORM_IRQS 4 - -#define ACPI_SPCRT_SIG "SPCR" -#define ACPI_SPCRT_SIG_LEN 4 - -#define ACPI_DBGPT_SIG "DBGP" -#define ACPI_DBGPT_SIG_LEN 4 - -extern int acpi20_parse(acpi20_rsdp_t *); -extern int acpi20_early_parse(acpi20_rsdp_t *); -extern int acpi_parse(acpi_rsdp_t *); -extern const char *acpi_get_sysname (void); -extern int acpi_request_vector(u32 int_type); -extern void (*acpi_idle) (void); /* power-management idle function, if any */ -#ifdef CONFIG_NUMA -extern cnodeid_t paddr_to_nid(unsigned long paddr); -#endif - -/* - * ACPI 2.0 SRAT Table - * http://www.microsoft.com/HWDEV/design/SRAT.htm - */ - -typedef struct acpi_srat { - acpi_desc_table_hdr_t header; - u32 table_revision; - u64 reserved; -} acpi_srat_t; - -typedef struct srat_cpu_affinity { - u8 type; - u8 length; - u8 proximity_domain; - u8 apic_id; - u32 flags; - u8 local_sapic_eid; - u8 reserved[7]; -} srat_cpu_affinity_t; - -typedef struct srat_memory_affinity { - u8 type; - u8 length; - u8 proximity_domain; - u8 reserved[5]; - u32 base_addr_lo; - u32 base_addr_hi; - u32 length_lo; - u32 length_hi; - u32 memory_type; - u32 flags; - u64 reserved2; -} srat_memory_affinity_t; - -/* ACPI 2.0 SRAT structure */ -#define ACPI_SRAT_SIG "SRAT" -#define ACPI_SRAT_SIG_LEN 4 -#define ACPI_SRAT_REVISION 1 - -#define SRAT_CPU_STRUCTURE 0 -#define SRAT_MEMORY_STRUCTURE 1 - -/* Only 1 flag for cpu affinity structure! */ -#define SRAT_CPU_FLAGS_ENABLED 0x00000001 - -#define SRAT_MEMORY_FLAGS_ENABLED 0x00000001 -#define SRAT_MEMORY_FLAGS_HOTREMOVABLE 0x00000002 - -/* ACPI 2.0 address range types */ -#define ACPI_ADDRESS_RANGE_MEMORY 1 -#define ACPI_ADDRESS_RANGE_RESERVED 2 -#define ACPI_ADDRESS_RANGE_ACPI 3 -#define ACPI_ADDRESS_RANGE_NVS 4 - -#define NODE_ARRAY_INDEX(x) ((x) / 8) /* 8 bits/char */ -#define NODE_ARRAY_OFFSET(x) ((x) % 8) /* 8 bits/char */ -#define MAX_PXM_DOMAINS (256) - -#ifdef CONFIG_DISCONTIGMEM -/* - * List of node memory chunks. Filled when parsing SRAT table to - * obtain information about memory nodes. -*/ - -struct node_memory_chunk_s { - unsigned long start_paddr; - unsigned long size; - int pxm; // proximity domain of node - int nid; // which cnode contains this chunk? - int bank; // which mem bank on this node -}; - -extern struct node_memory_chunk_s node_memory_chunk[PLAT_MAXCLUMPS]; // temporary? - -struct node_cpuid_s { - u16 phys_id; /* id << 8 | eid */ - int pxm; // proximity domain of cpu - int nid; -}; -extern struct node_cpuid_s node_cpuid[NR_CPUS]; - -extern int pxm_to_nid_map[MAX_PXM_DOMAINS]; /* _PXM to logical node ID map */ -extern int nid_to_pxm_map[PLAT_MAX_COMPACT_NODES]; /* logical node ID to _PXM map */ -extern int numnodes; /* total number of nodes in system */ -extern int num_memory_chunks; /* total number of memory chunks */ - -/* - * ACPI 2.0 SLIT Table - * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf - */ - -typedef struct acpi_slit { - acpi_desc_table_hdr_t header; - u64 localities; - u8 entries[1]; /* dummy, real size = locality^2 */ -} acpi_slit_t; - -extern u8 acpi20_slit[PLAT_MAX_COMPACT_NODES * PLAT_MAX_COMPACT_NODES]; - -#define ACPI_SLIT_SIG "SLIT" -#define ACPI_SLIT_SIG_LEN 4 -#define ACPI_SLIT_REVISION 1 -#define ACPI_SLIT_LOCAL 10 -#endif /* CONFIG_DISCONTIGMEM */ - -#pragma pack() -#endif /* _ASM_IA64_ACPI_EXT_H */ diff -Nur linux-2.4.19/include/asm-ia64/acpi.h linux-2.4.19-sgi211r3/include/asm-ia64/acpi.h --- linux-2.4.19/include/asm-ia64/acpi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/acpi.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,163 @@ +/* + * asm-ia64/acpi.h + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 2000,2001 J.I. Lee + * Copyright (C) 2001,2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#ifndef _ASM_ACPI_H +#define _ASM_ACPI_H + +#ifdef __KERNEL__ + +#define COMPILER_DEPENDENT_INT64 long +#define COMPILER_DEPENDENT_UINT64 unsigned long + +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + +/* Asm macros */ + +#define ACPI_ASM_MACROS +#define BREAKPOINT3 +#define ACPI_DISABLE_IRQS() __cli() +#define ACPI_ENABLE_IRQS() __sti() +#define ACPI_FLUSH_CPU_CACHE() + +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ + do { \ + __asm__ volatile ("1: ld4 r29=%1\n" \ + ";;\n" \ + "mov ar.ccv=r29\n" \ + "mov r2=r29\n" \ + "shr.u r30=r29,1\n" \ + "and r29=-4,r29\n" \ + ";;\n" \ + "add r29=2,r29\n" \ + "and r30=1,r30\n" \ + ";;\n" \ + "add r29=r29,r30\n" \ + ";;\n" \ + "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ + ";;\n" \ + "cmp.eq p6,p7=r2,r30\n" \ + "(p7) br.dpnt.few 1b\n" \ + "cmp.gt p8,p9=3,r29\n" \ + ";;\n" \ + "(p8) mov %0=-1\n" \ + "(p9) mov %0=r0\n" \ + :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ + } while (0) + +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ + do { \ + __asm__ volatile ("1: ld4 r29=%1\n" \ + ";;\n" \ + "mov ar.ccv=r29\n" \ + "mov r2=r29\n" \ + "and r29=-4,r29\n" \ + ";;\n" \ + "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ + ";;\n" \ + "cmp.eq p6,p7=r2,r30\n" \ + "(p7) br.dpnt.few 1b\n" \ + "and %0=1,r2\n" \ + ";;\n" \ + :"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \ + } while (0) + +const char *acpi_get_sysname (void); +int acpi_boot_init (char *cdline); +int acpi_early_init(void); +int acpi_request_vector (u32 int_type); +int acpi_get_prt (struct pci_vector_struct **vectors, int *count); +int acpi_get_interrupt_model (int *type); +int acpi_irq_to_vector (u32 irq); + +#ifdef CONFIG_DISCONTIGMEM +#define NODE_ARRAY_INDEX(x) ((x) / 8) /* 8 bits/char */ +#define NODE_ARRAY_OFFSET(x) ((x) % 8) /* 8 bits/char */ + +#include + +#if defined(CONFIG_IA64_SGI_SN1) +#include +#elif defined(CONFIG_IA64_SGI_SN2) +#include +#elif defined(CONFIG_IA64_DIG) +#include +#else +#error "Unknown architecture" +#endif + +#define MAX_PXM_DOMAINS (PLAT_MAX_COMPACT_NODES) + +/* + * List of node memory chunks. Filled when parsing SRAT table to + * obtain information about memory nodes. +*/ + +struct node_memory_chunk_s { + unsigned long start_paddr; + unsigned long size; + int pxm; // proximity domain of node + int nid; // which cnode contains this chunk? + int bank; // which mem bank on this node +}; + +extern struct node_memory_chunk_s node_memory_chunk[PLAT_MAXCLUMPS]; // temporary? + +struct node_cpuid_s { + u16 phys_id; /* id << 8 | eid */ + int pxm; // proximity domain of cpu + int nid; +}; +extern struct node_cpuid_s node_cpuid[NR_CPUS]; + +/* ACPI _PXM <=> logical node ID map (-1 means no mapping) */ +extern int pxm_to_nid_map[MAX_PXM_DOMAINS]; /* _PXM to logical node ID map */ +extern int nid_to_pxm_map[PLAT_MAX_COMPACT_NODES]; /* logical node ID to _PXM map */ +extern int numnodes; /* total number of nodes in system */ +extern int num_memory_chunks; /* total number of memory chunks */ + +extern u8 acpi20_slit[PLAT_MAX_COMPACT_NODES * PLAT_MAX_COMPACT_NODES]; + +#endif /* CONFIG_DISCONTIGMEM */ + +#ifdef CONFIG_NUMA +extern int paddr_to_nid(unsigned long paddr); +#endif + +#endif /*__KERNEL__*/ + +#endif /*_ASM_ACPI_H*/ diff -Nur linux-2.4.19/include/asm-ia64/acpikcfg.h linux-2.4.19-sgi211r3/include/asm-ia64/acpikcfg.h --- linux-2.4.19/include/asm-ia64/acpikcfg.h Tue Jul 31 10:30:09 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/acpikcfg.h Wed Dec 31 16:00:00 1969 @@ -1,30 +0,0 @@ -#ifndef _ASM_IA64_ACPIKCFG_H -#define _ASM_IA64_ACPIKCFG_H - -/* - * acpikcfg.h - ACPI based Kernel Configuration Manager External Interfaces - * - * Copyright (C) 2000 Intel Corp. - * Copyright (C) 2000 J.I. Lee - */ - - -u32 __init acpi_cf_init (void * rsdp); -u32 __init acpi_cf_terminate (void ); - -u32 __init -acpi_cf_get_pci_vectors ( - struct pci_vector_struct **vectors, - int *num_pci_vectors - ); - - -#ifdef CONFIG_ACPI_KERNEL_CONFIG_DEBUG -void __init -acpi_cf_print_pci_vectors ( - struct pci_vector_struct *vectors, - int num_pci_vectors - ); -#endif - -#endif /* _ASM_IA64_ACPIKCFG_H */ diff -Nur linux-2.4.19/include/asm-ia64/asmmacro.h linux-2.4.19-sgi211r3/include/asm-ia64/asmmacro.h --- linux-2.4.19/include/asm-ia64/asmmacro.h Thu Apr 5 12:51:47 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/asmmacro.h Thu Jan 31 08:22:43 2002 @@ -38,17 +38,17 @@ #if __GNUC__ >= 3 # define EX(y,x...) \ - .xdata4 "__ex_table", @gprel(99f), @gprel(y); \ + .xdata8 "__ex_table", 99f, y; \ [99:] x # define EXCLR(y,x...) \ - .xdata4 "__ex_table", @gprel(99f), @gprel(y)+4; \ + .xdata8 "__ex_table", 99f, y+4; \ [99:] x #else # define EX(y,x...) \ - .xdata4 "__ex_table", @gprel(99f), @gprel(y); \ + .xdata8 "__ex_table", 99f, y; \ 99: x # define EXCLR(y,x...) \ - .xdata4 "__ex_table", @gprel(99f), @gprel(y)+4; \ + .xdata8 "__ex_table", 99f, y+4; \ 99: x #endif diff -Nur linux-2.4.19/include/asm-ia64/atomic.h linux-2.4.19-sgi211r3/include/asm-ia64/atomic.h --- linux-2.4.19/include/asm-ia64/atomic.h Mon Jul 9 21:30:19 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/atomic.h Mon Dec 9 08:35:45 2002 @@ -5,12 +5,8 @@ * Atomic operations that C can't guarantee us. Useful for * resource counting etc.. * - * NOTE: don't mess with the types below! The "unsigned long" and - * "int" types were carefully placed so as to ensure proper operation - * of the macros. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include @@ -21,63 +17,62 @@ * memory accesses are ordered. */ typedef struct { volatile __s32 counter; } atomic_t; +typedef struct { volatile __s64 counter; } atomic64_t; #define ATOMIC_INIT(i) ((atomic_t) { (i) }) +#define ATOMIC64_INIT(i) ((atomic64_t) { (i) }) #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) -static __inline__ int -ia64_atomic_add (int i, atomic_t *v) -{ - __s32 old, new; - CMPXCHG_BUGCHECK_DECL - - do { - CMPXCHG_BUGCHECK(v); - old = atomic_read(v); - new = old + i; - } while (ia64_cmpxchg("acq", v, old, old + i, sizeof(atomic_t)) != old); - return new; -} - -static __inline__ int -ia64_atomic_sub (int i, atomic_t *v) -{ - __s32 old, new; - CMPXCHG_BUGCHECK_DECL - - do { - CMPXCHG_BUGCHECK(v); - old = atomic_read(v); - new = old - i; - } while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old); - return new; -} +#define atomic64_read(v) atomic_read(v) +#define atomic64_set(v,i) atomic_set((v), (i)) + +#define ia64_atomic_add(i,v) \ +({ \ + __typeof__((v)->counter) _old, _new; \ + CMPXCHG_BUGCHECK_DECL \ + \ + do { \ + CMPXCHG_BUGCHECK(v); \ + _old = atomic_read(v); \ + _new = _old + (i); \ + } while (ia64_cmpxchg("acq", (v), _old, _new, sizeof(*(v))) != _old); \ + _new; /* return new value */ \ +}) + +#define ia64_atomic_sub(i,v) \ +({ \ + __typeof__((v)->counter) _old, _new; \ + CMPXCHG_BUGCHECK_DECL \ + \ + do { \ + CMPXCHG_BUGCHECK(v); \ + _old = atomic_read(v); \ + _new = _old - (i); \ + } while (ia64_cmpxchg("acq", (v), _old, _new, sizeof(*(v))) != _old); \ + _new; /* return new value */ \ +}) /* * Atomically add I to V and return TRUE if the resulting value is * negative. */ -static __inline__ int -atomic_add_negative (int i, atomic_t *v) -{ - return ia64_atomic_add(i, v) < 0; -} +#define atomic_add_negative(i,v) (ia64_atomic_add((i), (v)) < 0) #define atomic_add_return(i,v) \ ((__builtin_constant_p(i) && \ ( (i == 1) || (i == 4) || (i == 8) || (i == 16) \ || (i == -1) || (i == -4) || (i == -8) || (i == -16))) \ ? ia64_fetch_and_add(i, &(v)->counter) \ - : ia64_atomic_add(i, v)) + : ia64_atomic_add((i), (v))) #define atomic_sub_return(i,v) \ ((__builtin_constant_p(i) && \ ( (i == 1) || (i == 4) || (i == 8) || (i == 16) \ || (i == -1) || (i == -4) || (i == -8) || (i == -16))) \ ? ia64_fetch_and_add(-(i), &(v)->counter) \ - : ia64_atomic_sub(i, v)) + : ia64_atomic_sub((i), (v))) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) @@ -90,6 +85,18 @@ #define atomic_sub(i,v) atomic_sub_return((i), (v)) #define atomic_inc(v) atomic_add(1, (v)) #define atomic_dec(v) atomic_sub(1, (v)) + +#define atomic64_dec_return(v) atomic_dec_return(v) +#define atomic64_inc_return(v) atomic_inc_return(v) + +#define atomic64_sub_and_test(i,v) atomic_sub_and_test((i), (v)) +#define atomic64_dec_and_test(v) atomic_dec_and_test(v) +#define atomic64_inc_and_test(v) atomic_inc_and_test(v) + +#define atomic64_add(i,v) atomic_add((i), (v)) +#define atomic64_sub(i,v) atomic_sub((i), (v)) +#define atomic64_inc(v) atomic_inc(v) +#define atomic64_dec(v) atomic_dec(v) /* Atomic operations are already serializing */ #define smp_mb__before_atomic_dec() barrier() diff -Nur linux-2.4.19/include/asm-ia64/bitops.h linux-2.4.19-sgi211r3/include/asm-ia64/bitops.h --- linux-2.4.19/include/asm-ia64/bitops.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/bitops.h Fri Feb 7 14:19:27 2003 @@ -280,20 +280,36 @@ return result; } +/** + * __ffs - find first bit in a 64 bit long. + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static inline unsigned long +__ffs (unsigned long x) +{ + unsigned long result; + + __asm__ ("popcnt %0=%1" : "=r" (result) : "r" (~x & (x - 1))); + return result; +} + #ifdef __KERNEL__ /* - * find_last_zero_bit - find the last zero bit in a 64 bit quantity + * find_last_set_bit - find the last set bit in a non-zero 64 bit quantity * @x: The value to search + * returns -1 if the input is all zeroes, else the bit number of the most + * significant one-bit */ static inline unsigned long ia64_fls (unsigned long x) { - double d = x; + long double d = x; long exp; __asm__ ("getf.exp %0=%1" : "=r"(exp) : "f"(d)); - return exp - 0xffff; + return x ? (exp - 0xffff) : -1L; } /* @@ -325,7 +341,7 @@ /* * Find next zero bit in a bitmap reasonably efficiently.. */ -static inline int +static inline unsigned long find_next_zero_bit (void *addr, unsigned long size, unsigned long offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 6); @@ -368,8 +384,52 @@ */ #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) +/* + * Find next bit in a bitmap reasonably efficiently.. + */ +static inline int +find_next_bit (void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp &= ~0UL << offset; + if (size < 64) + goto found_first; + if (tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if ((tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; +found_first: + tmp &= ~0UL >> (64-size); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __ffs(tmp); +} + +#define find_first_bit(addr, size) find_next_bit((addr), (size), 0) + #ifdef __KERNEL__ +#define __clear_bit(nr, addr) clear_bit(nr, addr) #define ext2_set_bit test_and_set_bit #define ext2_clear_bit test_and_clear_bit #define ext2_test_bit test_bit diff -Nur linux-2.4.19/include/asm-ia64/cache.h linux-2.4.19-sgi211r3/include/asm-ia64/cache.h --- linux-2.4.19/include/asm-ia64/cache.h Thu Apr 5 12:51:47 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/cache.h Fri Apr 26 11:07:18 2002 @@ -5,7 +5,7 @@ /* * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * David Mosberger-Tang */ /* Bytes per L1 (data) cache line. */ diff -Nur linux-2.4.19/include/asm-ia64/current.h linux-2.4.19-sgi211r3/include/asm-ia64/current.h --- linux-2.4.19/include/asm-ia64/current.h Fri Apr 21 15:21:24 2000 +++ linux-2.4.19-sgi211r3/include/asm-ia64/current.h Fri Apr 26 11:07:18 2002 @@ -3,7 +3,7 @@ /* * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * David Mosberger-Tang */ /* In kernel mode, thread pointer (r13) is used to point to the diff -Nur linux-2.4.19/include/asm-ia64/delay.h linux-2.4.19-sgi211r3/include/asm-ia64/delay.h --- linux-2.4.19/include/asm-ia64/delay.h Thu Apr 5 12:51:47 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/delay.h Wed Apr 24 12:21:39 2002 @@ -17,6 +17,9 @@ #include #include +#ifdef CONFIG_IA64_SGI_SN +#include +#endif static __inline__ void ia64_set_itm (unsigned long val) @@ -77,6 +80,14 @@ { unsigned long start = ia64_get_itc(); unsigned long cycles = usecs*local_cpu_data->cyc_per_usec; + +#ifdef CONFIG_IA64_SGI_SN_SIM + if (IS_RUNNING_ON_SIMULATOR()) { + while (usecs--) + ; + return; + } +#endif while (ia64_get_itc() - start < cycles) /* skip */; diff -Nur linux-2.4.19/include/asm-ia64/dump.h linux-2.4.19-sgi211r3/include/asm-ia64/dump.h --- linux-2.4.19/include/asm-ia64/dump.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/dump.h Tue Jan 28 18:24:28 2003 @@ -0,0 +1,146 @@ +/* + * Kernel header file for Linux crash dumps. + * + * Created by: Matt Robinson (yakker@sgi.com) + * + * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved. + * + * This code is released under version 2 of the GNU GPL. + */ + +/* This header file holds the architecture specific crash dump header */ +#ifndef _ASM_DUMP_H +#define _ASM_DUMP_H + +/* definitions */ +#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ +#define DUMP_ASM_VERSION_NUMBER 0x4 /* version number */ + +#ifdef __KERNEL__ +#include +#include +#ifdef CONFIG_SMP +extern unsigned long irq_affinity[]; +extern int (*dump_ipi_function_ptr)(struct pt_regs *); +extern void dump_send_ipi(void); +#else /* !CONFIG_SMP */ +#define dump_send_ipi() +#endif + +#else /* !__KERNEL__ */ +/* necessary header files */ +#include /* for pt_regs */ +#include +#endif /* __KERNEL__ */ + +/* + * mkswap.c calls getpagesize() to get the system page size, + * which is not necessarily the same as the hardware page size. + * + * For ia64 the kernel PAGE_SIZE can be configured from 4KB ... 16KB. + * + * The physical memory is organized in the hardware/minimal pages. + * This is the size we need to use for dumping physical pages. + * + * Note the hardware/minimal page size being use in: + * + * arch/ia64/kernel/efi.c`efi_memmap_walk(): + * curr.end = curr.start + (md->num_pages << 12); + * + * Since the system page size could change between the kernel we boot + * on the the kernel that cause the core dump we may want to have something + * more constant like the maximum system page size (See include/asm-ia64/page.h). + */ +#define DUMP_MIN_PAGE_SHIFT 12 +#define DUMP_MIN_PAGE_SIZE (1UL << DUMP_MIN_PAGE_SHIFT) +#define DUMP_MIN_PAGE_MASK (~(DUMP_MIN_PAGE_SIZE - 1)) +#define DUMP_MIN_PAGE_ALIGN(addr) (((addr) + DUMP_MIN_PAGE_SIZE - 1) & DUMP_MIN_PAGE_MASK) + +#define DUMP_MAX_PAGE_SHIFT 16 +#define DUMP_MAX_PAGE_SIZE (1UL << DUMP_MAX_PAGE_SHIFT) +#define DUMP_MAX_PAGE_MASK (~(DUMP_MAX_PAGE_SIZE - 1)) +#define DUMP_MAX_PAGE_ALIGN(addr) (((addr) + DUMP_MAX_PAGE_SIZE - 1) & DUMP_MAX_PAGE_MASK) + + +#undef DUMP_PAGE_SHIFT /* Redefining Default for ia64 */ +#undef DUMP_PAGE_SIZE /* " " " " */ +#undef DUMP_PAGE_MASK /* " " " " */ +#undef DUMP_PAGE_ALIGN /* " " " " */ +#undef DUMP_HEADER_OFFSET /* " " " " */ + +#define DUMP_HEADER_OFFSET DUMP_MAX_PAGE_SIZE + +#define DUMP_EF_PAGE_SHIFT DUMP_MIN_PAGE_SHIFT + +#define DUMP_PAGE_SHIFT DUMP_MIN_PAGE_SHIFT +#define DUMP_PAGE_SIZE DUMP_MIN_PAGE_SIZE +#define DUMP_PAGE_MASK DUMP_MIN_PAGE_MASK +#define DUMP_PAGE_ALIGN(addr) DUMP_MIN_PAGE_ALIGN(addr) + +/* + * Structure: dump_header_asm_t: + * + * Function: This is the header for architecture-specific stuff; + * It follows right after the dump header. + */ +typedef struct _dump_header_asm_s { + + /* the dump magic number -- unique to verify dump is valid */ + uint64_t dha_magic_number; + + /* the version number of this dump */ + uint32_t dha_version; + + /* the size of this header (in case we can't read it) */ + uint32_t dha_header_size; + + /* load address of kernel */ + unsigned long dha_kernel_addr; + + /* pointer to pt_regs */ + struct pt_regs *dha_pt_regs; + + /* the dump registers */ + struct pt_regs dha_regs; + + /* the rnat register saved after flushrs */ + uint64_t dha_rnat; + + /* the pfs register saved after flushrs */ + uint64_t dha_pfs; + + /* the bspstore register saved after flushrs */ + uint64_t dha_bspstore; + + /* smp specific */ + uint32_t dha_smp_num_cpus; + int dha_dumping_cpu; + struct pt_regs dha_smp_regs[NR_CPUS]; + void * dha_smp_current_task[NR_CPUS]; + void * dha_stack[NR_CPUS]; + +} dump_header_asm_t; + +extern dump_header_asm_t dump_header_asm; + +#ifdef __KERNEL__ +static inline void get_current_regs(struct pt_regs *regs) +{ + /* + * REMIND: Looking at functions/Macros like: + * DO_SAVE_SWITCH_STACK + * ia64_switch_to() + * ia64_save_extra() + * switch_to() + * to implement this new feature that Matt seem to have added + * to panic.c; seems all platforms are now expected to provide + * this function to dump the current registers into the pt_regs + * structure. + */ +} + +/* Perhaps added to Common Arch Specific Functions and moved to dump.h some day */ +extern void * __dump_memcpy(void *, const void *, size_t); +#endif /* __KERNEL__ */ + +#endif /* _ASM_DUMP_H */ diff -Nur linux-2.4.19/include/asm-ia64/efi.h linux-2.4.19-sgi211r3/include/asm-ia64/efi.h --- linux-2.4.19/include/asm-ia64/efi.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/efi.h Wed Dec 31 16:00:00 1969 @@ -1,262 +0,0 @@ -#ifndef _ASM_IA64_EFI_H -#define _ASM_IA64_EFI_H - -/* - * Extensible Firmware Interface - * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999 - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999 Hewlett-Packard Co. - * Copyright (C) 1999 David Mosberger-Tang - * Copyright (C) 1999 Stephane Eranian - */ -#include -#include -#include -#include -#include - -#include -#include - -#define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR (1L | (1L << 63)) -#define EFI_INVALID_PARAMETER (2L | (1L << 63)) -#define EFI_UNSUPPORTED (3L | (1L << 63)) -#define EFI_BAD_BUFFER_SIZE (4L | (1L << 63)) -#define EFI_BUFFER_TOO_SMALL (5L | (1L << 63)) -#define EFI_NOT_FOUND (14L | (1L << 63)) - -typedef unsigned long efi_status_t; -typedef u8 efi_bool_t; -typedef u16 efi_char16_t; /* UNICODE character */ - -typedef struct { - u32 data1; - u16 data2; - u16 data3; - u8 data4[8]; -} efi_guid_t; - -/* - * Generic EFI table header - */ -typedef struct { - u64 signature; - u32 revision; - u32 headersize; - u32 crc32; - u32 reserved; -} efi_table_hdr_t; - -/* - * Memory map descriptor: - */ - -/* Memory types: */ -#define EFI_RESERVED_TYPE 0 -#define EFI_LOADER_CODE 1 -#define EFI_LOADER_DATA 2 -#define EFI_BOOT_SERVICES_CODE 3 -#define EFI_BOOT_SERVICES_DATA 4 -#define EFI_RUNTIME_SERVICES_CODE 5 -#define EFI_RUNTIME_SERVICES_DATA 6 -#define EFI_CONVENTIONAL_MEMORY 7 -#define EFI_UNUSABLE_MEMORY 8 -#define EFI_ACPI_RECLAIM_MEMORY 9 -#define EFI_ACPI_MEMORY_NVS 10 -#define EFI_MEMORY_MAPPED_IO 11 -#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 -#define EFI_PAL_CODE 13 -#define EFI_MAX_MEMORY_TYPE 14 - -/* Attribute values: */ -#define EFI_MEMORY_UC 0x0000000000000001 /* uncached */ -#define EFI_MEMORY_WC 0x0000000000000002 /* write-coalescing */ -#define EFI_MEMORY_WT 0x0000000000000004 /* write-through */ -#define EFI_MEMORY_WB 0x0000000000000008 /* write-back */ -#define EFI_MEMORY_WP 0x0000000000001000 /* write-protect */ -#define EFI_MEMORY_RP 0x0000000000002000 /* read-protect */ -#define EFI_MEMORY_XP 0x0000000000004000 /* execute-protect */ -#define EFI_MEMORY_RUNTIME 0x8000000000000000 /* range requires runtime mapping */ -#define EFI_MEMORY_DESCRIPTOR_VERSION 1 - -typedef struct { - u32 type; - u32 pad; - u64 phys_addr; - u64 virt_addr; - u64 num_pages; - u64 attribute; -} efi_memory_desc_t; - -typedef int efi_freemem_callback_t (u64 start, u64 end, void *arg); - -/* - * Types and defines for Time Services - */ -#define EFI_TIME_ADJUST_DAYLIGHT 0x1 -#define EFI_TIME_IN_DAYLIGHT 0x2 -#define EFI_UNSPECIFIED_TIMEZONE 0x07ff - -typedef struct { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 minute; - u8 second; - u8 pad1; - u32 nanosecond; - s16 timezone; - u8 daylight; - u8 pad2; -} efi_time_t; - -typedef struct { - u32 resolution; - u32 accuracy; - u8 sets_to_zero; -} efi_time_cap_t; - -/* - * Types and defines for EFI ResetSystem - */ -#define EFI_RESET_COLD 0 -#define EFI_RESET_WARM 1 - -/* - * EFI Runtime Services table - */ -#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552 -#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 - -typedef struct { - efi_table_hdr_t hdr; - u64 get_time; - u64 set_time; - u64 get_wakeup_time; - u64 set_wakeup_time; - u64 set_virtual_address_map; - u64 convert_pointer; - u64 get_variable; - u64 get_next_variable; - u64 set_variable; - u64 get_next_high_mono_count; - u64 reset_system; -} efi_runtime_services_t; - -typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); -typedef efi_status_t efi_set_time_t (efi_time_t *tm); -typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, - efi_time_t *tm); -typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm); -typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, - unsigned long *data_size, void *data); -typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, - efi_guid_t *vendor); -typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 attr, - unsigned long data_size, void *data); -typedef efi_status_t efi_get_next_high_mono_count_t (u64 *count); -typedef void efi_reset_system_t (int reset_type, efi_status_t status, - unsigned long data_size, efi_char16_t *data); - -/* - * EFI Configuration Table and GUID definitions - */ - -#define MPS_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d2f, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) - -#define ACPI_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d30, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) - -#define ACPI_20_TABLE_GUID \ - ((efi_guid_t) { 0x8868e871, 0xe4f1, 0x11d3, { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 }}) - -#define SMBIOS_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d31, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) - -#define SAL_SYSTEM_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) - -#define HCDP_TABLE_GUID \ - ((efi_guid_t) { 0xf951938d, 0x620b, 0x42ef, {0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98}}) - -typedef struct { - efi_guid_t guid; - u64 table; -} efi_config_table_t; - -#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 -#define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00) - -typedef struct { - efi_table_hdr_t hdr; - u64 fw_vendor; /* physical addr of CHAR16 vendor string */ - u32 fw_revision; - u64 con_in_handle; - u64 con_in; - u64 con_out_handle; - u64 con_out; - u64 stderr_handle; - u64 stderr; - u64 runtime; - u64 boottime; - u64 nr_tables; - u64 tables; -} efi_system_table_t; - -/* - * All runtime access to EFI goes through this structure: - */ -extern struct efi { - efi_system_table_t *systab; /* EFI system table */ - void *mps; /* MPS table */ - void *acpi; /* ACPI table (IA64 ext 0.71) */ - void *acpi20; /* ACPI table (ACPI 2.0) */ - void *smbios; /* SM BIOS table */ - void *sal_systab; /* SAL system table */ - void *hcdp; /* HCDP table */ - void *boot_info; /* boot info table */ - efi_get_time_t *get_time; - efi_set_time_t *set_time; - efi_get_wakeup_time_t *get_wakeup_time; - efi_set_wakeup_time_t *set_wakeup_time; - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_get_next_high_mono_count_t *get_next_high_mono_count; - efi_reset_system_t *reset_system; -} efi; - -static inline int -efi_guidcmp (efi_guid_t left, efi_guid_t right) -{ - return memcmp(&left, &right, sizeof (efi_guid_t)); -} - -extern void efi_init (void); -extern void efi_map_pal_code (void); -extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); -extern void efi_gettimeofday (struct timeval *tv); -extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ -extern u64 efi_get_iobase (void); - -/* - * Variable Attributes - */ -#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 -#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 -#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 - - -/* - * efi_dir is allocated in arch/ia64/kernel/efi.c. - */ -#ifdef CONFIG_PROC_FS -extern struct proc_dir_entry *efi_dir; -#endif - -#endif /* _ASM_IA64_EFI_H */ diff -Nur linux-2.4.19/include/asm-ia64/elf.h linux-2.4.19-sgi211r3/include/asm-ia64/elf.h --- linux-2.4.19/include/asm-ia64/elf.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/elf.h Thu Jun 27 13:12:26 2002 @@ -39,7 +39,7 @@ * the way of the program that it will "exec", and that there is * sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) +#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x800000000) /* diff -Nur linux-2.4.19/include/asm-ia64/errno.h linux-2.4.19-sgi211r3/include/asm-ia64/errno.h --- linux-2.4.19/include/asm-ia64/errno.h Tue Apr 10 12:23:06 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/errno.h Wed Oct 16 14:02:58 2002 @@ -14,7 +14,7 @@ #define EINTR 4 /* Interrupted system call */ #define EIO 5 /* I/O error */ #define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Arg list too long */ +#define E2BIG 7 /* Argument list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file number */ #define ECHILD 10 /* No child processes */ diff -Nur linux-2.4.19/include/asm-ia64/hw_irq.h linux-2.4.19-sgi211r3/include/asm-ia64/hw_irq.h --- linux-2.4.19/include/asm-ia64/hw_irq.h Tue Jul 31 10:30:09 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/hw_irq.h Mon Oct 28 20:43:23 2002 @@ -2,8 +2,8 @@ #define _ASM_IA64_HW_IRQ_H /* - * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang + * Copyright (C) 2001, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include @@ -52,6 +52,10 @@ #define IA64_IPI_RESCHEDULE 0xfd /* SMP reschedule */ #define IA64_IPI_VECTOR 0xfe /* inter-processor interrupt vector */ +/* Used for encoding redirected irqs */ + +#define IA64_IRQ_REDIRECTED (1 << 31) + /* IA64 inter-cpu interrupt related definitions */ #define IA64_IPI_DEFAULT_BASE_ADDR 0xfee00000 @@ -65,6 +69,9 @@ IA64_IPI_DM_EXTINT = 0x7, /* pend an 8259-compatible interrupt. */ }; +/* bit for masking and discarding timer interrupts on IA64 */ +#define IA64_TIMER_MASK (1<<16) + extern __u8 isa_irq_to_vector_map[16]; #define isa_irq_to_vector(x) isa_irq_to_vector_map[(x)] @@ -72,7 +79,7 @@ extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */ -extern int ia64_alloc_irq (void); /* allocate a free irq */ +extern int ia64_alloc_vector (void); /* allocate a free vector */ extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); @@ -86,8 +93,9 @@ * Default implementations for the irq-descriptor API: */ -extern struct irq_desc _irq_desc[NR_IRQS]; +extern struct irq_desc _irq_desc[]; +#ifndef CONFIG_IA64_GENERIC static inline struct irq_desc * __ia64_irq_desc (unsigned int irq) { @@ -104,6 +112,13 @@ __ia64_local_vector_to_irq (ia64_vector vec) { return (unsigned int) vec; +} +#endif + +static inline int +__ia64_valid_irq(unsigned int irq) +{ + return(irq < NR_IRQS); } /* diff -Nur linux-2.4.19/include/asm-ia64/ia32.h linux-2.4.19-sgi211r3/include/asm-ia64/ia32.h --- linux-2.4.19/include/asm-ia64/ia32.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/ia32.h Tue Oct 29 14:53:41 2002 @@ -73,6 +73,17 @@ unsigned short exponent; }; +struct _fpxreg_ia32 { + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}; + +struct _xmmreg_ia32 { + unsigned int element[4]; +}; + + struct _fpstate_ia32 { unsigned int cw, sw, @@ -82,7 +93,16 @@ dataoff, datasel; struct _fpreg_ia32 _st[8]; - unsigned int status; + unsigned short status; + unsigned short magic; /* 0xffff = regular FPU data only */ + + /* FXSR FPU environment */ + unsigned int _fxsr_env[6]; /* FXSR FPU env is ignored */ + unsigned int mxcsr; + unsigned int reserved; + struct _fpxreg_ia32 _fxsr_st[8]; /* FXSR FPU reg data is ignored */ + struct _xmmreg_ia32 _xmm[8]; + unsigned int padding[56]; }; struct sigcontext_ia32 { @@ -484,6 +504,18 @@ extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t); extern void ia32_load_segment_descriptors (struct task_struct *task); + +#define ia32f2ia64f(dst,src) \ + do { \ + register double f6 asm ("f6"); \ + asm volatile ("ldfe f6=[%2];; stf.spill [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ + } while(0) + +#define ia64f2ia32f(dst,src) \ + do { \ + register double f6 asm ("f6"); \ + asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ + } while(0) #endif /* !CONFIG_IA32_SUPPORT */ diff -Nur linux-2.4.19/include/asm-ia64/ide.h linux-2.4.19-sgi211r3/include/asm-ia64/ide.h --- linux-2.4.19/include/asm-ia64/ide.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/ide.h Wed Oct 16 14:02:58 2002 @@ -17,6 +17,10 @@ #include +#ifdef CONFIG_IA64_SGI_SN_SIM +#define MAX_HWIFS 1 +#else + #ifndef MAX_HWIFS # ifdef CONFIG_BLK_DEV_IDEPCI #define MAX_HWIFS 10 @@ -25,10 +29,11 @@ # endif #endif +#endif /* CONFIG_IA64_SGI_SN_SIM */ + #define ide__sti() __sti() -static __inline__ int -ide_default_irq (ide_ioreg_t base) +static __inline__ int ide_default_irq(ide_ioreg_t base) { switch (base) { case 0x1f0: return isa_irq_to_vector(14); @@ -42,8 +47,7 @@ } } -static __inline__ ide_ioreg_t -ide_default_io_base (int index) +static __inline__ ide_ioreg_t ide_default_io_base(int index) { switch (index) { case 0: return 0x1f0; @@ -57,8 +61,7 @@ } } -static __inline__ void -ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) +static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { ide_ioreg_t reg = data_port; int i; @@ -77,8 +80,7 @@ hw->io_ports[IDE_IRQ_OFFSET] = 0; } -static __inline__ void -ide_init_default_hwifs (void) +static __inline__ void ide_init_default_hwifs(void) { #ifndef CONFIG_BLK_DEV_IDEPCI hw_regs_t hw; diff -Nur linux-2.4.19/include/asm-ia64/io.h linux-2.4.19-sgi211r3/include/asm-ia64/io.h --- linux-2.4.19/include/asm-ia64/io.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/io.h Thu Oct 31 10:53:27 2002 @@ -69,6 +69,21 @@ */ #define __ia64_mf_a() __asm__ __volatile__ ("mf.a" ::: "memory") +/** + * __ia64_mmiob - I/O space memory barrier + * + * Acts as a memory mapped I/O barrier for platforms that queue writes to + * I/O space. This ensures that subsequent writes to I/O space arrive after + * all previous writes. For most ia64 platforms, this is a simple + * 'mf.a' instruction. For other platforms, mmiob() may have to read + * a chipset register to ensure ordering. + */ +static inline void +__ia64_mmiob (void) +{ + __ia64_mf_a(); +} + static inline const unsigned long __ia64_get_io_port_base (void) { @@ -271,6 +286,7 @@ #define __outb platform_outb #define __outw platform_outw #define __outl platform_outl +#define __mmiob platform_mmiob #define inb __inb #define inw __inw @@ -284,6 +300,7 @@ #define outsb __outsb #define outsw __outsw #define outsl __outsl +#define mmiob __mmiob /* * The address passed to these functions are ioremap()ped already. diff -Nur linux-2.4.19/include/asm-ia64/ioctls.h linux-2.4.19-sgi211r3/include/asm-ia64/ioctls.h --- linux-2.4.19/include/asm-ia64/ioctls.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.19-sgi211r3/include/asm-ia64/ioctls.h Wed Oct 16 14:02:58 2002 @@ -11,7 +11,7 @@ /* 0x54 is just a magic number to make these relatively unique ('T') */ #define TCGETS 0x5401 -#define TCSETS 0x5402 +#define TCSETS 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ #define TCSETSW 0x5403 #define TCSETSF 0x5404 #define TCGETA 0x5405 @@ -72,6 +72,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -Nur linux-2.4.19/include/asm-ia64/iosapic.h linux-2.4.19-sgi211r3/include/asm-ia64/iosapic.h --- linux-2.4.19/include/asm-ia64/iosapic.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/iosapic.h Wed Oct 16 14:02:58 2002 @@ -51,17 +51,24 @@ #ifndef __ASSEMBLY__ -extern void __init iosapic_init (unsigned long address, unsigned int base_irq, - int pcat_compat); -extern int iosapic_register_irq (u32 global_vector, unsigned long polarity, - unsigned long edge_triggered, u32 base_irq, - char *iosapic_address); -extern void iosapic_register_legacy_irq (unsigned long irq, unsigned long pin, - unsigned long polarity, unsigned long trigger); -extern int iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector, - u16 eid, u16 id, unsigned long polarity, - unsigned long edge_triggered, u32 base_irq, - char *iosapic_address); +extern void __devinit iosapic_init (unsigned long address, + unsigned int gsi_base, + int pcat_compat); +extern int gsi_to_vector (unsigned int gsi); +extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity, + unsigned long edge_triggered, + u32 gsi_base, char *iosapic_address); +extern void iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, + unsigned long polarity, + unsigned long edge_triggered); +extern int iosapic_register_platform_intr (u32 int_type, + unsigned int gsi, + int pmi_vector, + u16 eid, u16 id, + unsigned long polarity, + unsigned long edge_triggered, + unsigned int gsi_base, + char *iosapic_address); extern unsigned int iosapic_version (char *addr); extern void iosapic_pci_fixup (int); diff -Nur linux-2.4.19/include/asm-ia64/irq.h linux-2.4.19-sgi211r3/include/asm-ia64/irq.h --- linux-2.4.19/include/asm-ia64/irq.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/irq.h Wed Jun 5 13:00:57 2002 @@ -11,7 +11,12 @@ * 02/29/00 D.Mosberger moved most things into hw_irq.h */ +#ifdef CONFIG_IA64_SGI_SN +#define NR_IRQS (256 * NR_CPUS) +#define NR_IVECS (256) +#else // CONFIG_IA64_SGI_SN #define NR_IRQS 256 +#endif //CONFIG_IA64_SGI_SN static __inline__ int irq_cannonicalize (int irq) diff -Nur linux-2.4.19/include/asm-ia64/kdb.h linux-2.4.19-sgi211r3/include/asm-ia64/kdb.h --- linux-2.4.19/include/asm-ia64/kdb.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/kdb.h Tue Feb 4 15:36:30 2003 @@ -0,0 +1,147 @@ +#ifndef _ASM_KDB_H +#define _ASM_KDB_H + +/* + * Kernel Debugger Architecture Dependent Global Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + /* + * KDB_ENTER() is a macro which causes entry into the kernel + * debugger from any point in the kernel code stream. If it + * is intended to be used from interrupt level, it must use + * a non-maskable entry method. + */ +#define KDB_BREAK_BREAK 0x80100 /* kdb breakpoint in kernel */ +#define KDB_BREAK_ENTER 0x80101 /* KDB_ENTER() */ +#define KDB_ENTER2(b) asm("\tbreak "#b"\n") +#define KDB_ENTER1(b) KDB_ENTER2(b) +#define KDB_ENTER() if (kdb_on && !KDB_IS_RUNNING()) { KDB_ENTER1(KDB_BREAK_ENTER); } + + /* + * Needed for exported symbols. + */ +typedef unsigned long kdb_machreg_t; + +#define kdb_machreg_fmt "0x%lx" +#define kdb_machreg_fmt0 "0x%016lx" +#define kdb_bfd_vma_fmt "0x%lx" +#define kdb_bfd_vma_fmt0 "0x%016lx" +#define kdb_elfw_addr_fmt "0x%lx" +#define kdb_elfw_addr_fmt0 "0x%016lx" + + /* + * Functions to safely read and write kernel areas. The {to,from}_xxx + * addresses are not necessarily valid, these functions must check for + * validity. If the arch already supports get and put routines with + * suitable validation and/or recovery on invalid addresses then use + * those routines, otherwise check it yourself. + */ + + /* + * asm-ia64 uaccess.h supplies __copy_to_user which relies on MMU to + * trap invalid addresses in the _xxx fields. Verify the other address + * of the pair is valid by accessing the first and last byte ourselves, + * then any access violations should only be caused by the _xxx + * addresses, + */ + +#include + +static inline int +__kdba_putarea_size(unsigned long to_xxx, void *from, size_t size) +{ + mm_segment_t oldfs = get_fs(); + int r; + char c; + c = *((volatile char *)from); + c = *((volatile char *)from + size - 1); +#ifdef VPERNODE_BASE /* if present, the new CONFIG_NUMA code */ + if (to_xxx >= VPERNODE_BASE && to_xxx < VGLOBAL_BASE) { + to_xxx = __imva(to_xxx); + } +#endif + set_fs(KERNEL_DS); + r = __copy_to_user((void *)to_xxx, from, size); + set_fs(oldfs); + return r; +} + +static inline int +__kdba_getarea_size(void *to, unsigned long from_xxx, size_t size) +{ + mm_segment_t oldfs = get_fs(); + int r; + *((volatile char *)to) = '\0'; + *((volatile char *)to + size - 1) = '\0'; + set_fs(KERNEL_DS); + switch (size) { + case 1: + r = __copy_to_user(to, (void *)from_xxx, 1); + break; + case 2: + r = __copy_to_user(to, (void *)from_xxx, 2); + break; + case 4: + r = __copy_to_user(to, (void *)from_xxx, 4); + break; + case 8: + r = __copy_to_user(to, (void *)from_xxx, 8); + break; + default: + r = __copy_to_user(to, (void *)from_xxx, size); + break; + } + set_fs(oldfs); + return r; +} + +/* For numa with replicated code/data, the platform must supply its own + * kdba_putarea_size and kdba_getarea_size routines. Without replication kdb + * uses the standard architecture routines. + */ +#ifdef CONFIG_NUMA_REPLICATE +extern int kdba_putarea_size(unsigned long to_xxx, void *from, size_t size); +extern int kdba_getarea_size(void *to, unsigned long from_xxx, size_t size); +#else +#define kdba_putarea_size __kdba_putarea_size +#define kdba_getarea_size __kdba_getarea_size +#endif + +static inline int +kdba_verify_rw(unsigned long addr, size_t size) +{ + unsigned char data[size]; + return(kdba_getarea_size(data, addr, size) || kdba_putarea_size(addr, data, size)); +} + +#endif /* !_ASM_KDB_H */ diff -Nur linux-2.4.19/include/asm-ia64/kdbprivate.h linux-2.4.19-sgi211r3/include/asm-ia64/kdbprivate.h --- linux-2.4.19/include/asm-ia64/kdbprivate.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/kdbprivate.h Tue Feb 4 15:36:30 2003 @@ -0,0 +1,133 @@ +#ifndef _ASM_KDBPRIVATE_H +#define _ASM_KDBPRIVATE_H + +/* + * Kernel Debugger Architecture Dependent Private Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* Definition of an machine instruction. + * Takes care of VLIW processors like Itanium + */ + +typedef struct { + unsigned long inst[2]; + } kdb_machinst_t; + + /* + * KDB_MAXBPT describes the total number of breakpoints + * supported by this architecure. + */ +#define KDB_MAXBPT 16 + + /* + * KDB_MAXHARDBPT describes the total number of hardware + * breakpoint registers that exist. + */ +#define KDB_MAXHARDBPT 4 + + /* + * Platform specific environment entries + */ +#define KDB_PLATFORM_ENV "IDMODE=ia64", "BYTESPERWORD=4", "IDCOUNT=8" + + /* + * Define the direction that the stack grows + */ +#define KDB_STACK_DIRECTION (-1) /* Stack grows down */ + + /* + * Support for IA64 debug registers + */ +typedef struct _kdbhard_bp { + kdb_machreg_t bph_reg; /* Register this breakpoint uses */ + + unsigned int bph_free:1; /* Register available for use */ + unsigned int bph_data:1; /* Data Access breakpoint */ + + unsigned int bph_write:1; /* Write Data breakpoint */ + unsigned int bph_mode:2; /* 0=inst, 1=write, 2=io, 3=read */ + unsigned int bph_length:2; /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */ +} kdbhard_bp_t; + +extern kdbhard_bp_t kdb_hardbreaks[/* KDB_MAXHARDBPT */]; + +#define getprsregs(regs) ((struct switch_stack *)regs -1) + +extern struct switch_stack *kdb_sw[ /*NR_CPUS*/ ]; + +/* bkpt support using break inst instead of IBP reg */ + +/* + * Define certain specific instructions + */ +#define BREAK_INSTR (long)(KDB_BREAK_BREAK << (5+6)) +#define INST_SLOT0_MASK (0x1ffffffffffL << 5) + +#define BKPTMODE_DATAR 3 +#define BKPTMODE_IO 2 +#define BKPTMODE_DATAW 1 +#define BKPTMODE_INST 0 + +/* Some of the fault registers needed by kdb but not passed with + * regs or switch stack. + */ +typedef struct fault_regs { + unsigned long isr ; + unsigned long ifa ; + unsigned long iim ; + unsigned long itir ; +} fault_regs_t ; + +#define KDB_HAVE_LONGJMP +#ifdef KDB_HAVE_LONGJMP +/* + * Support for setjmp/longjmp + */ + +/* __jmp_buf definition copied from libc/sysdeps/unix/sysv/linux/ia64/bits/setjmp.h */ + +#define _JBLEN 70 + +typedef struct __kdb_jmp_buf { + unsigned long __jmp_buf[_JBLEN]; +} kdb_jmp_buf __attribute__ ((aligned (16))); + +extern int kdba_setjmp(kdb_jmp_buf *); +extern int kdba_setjmp_asm(kdb_jmp_buf *); +extern void kdba_longjmp(kdb_jmp_buf *, int); +extern void kdba_longjmp_asm(kdb_jmp_buf *, int); + +extern kdb_jmp_buf kdbjmpbuf[]; +#endif /* KDB_HAVE_LONGJMP */ + +#endif /* !_ASM_KDBPRIVATE_H */ diff -Nur linux-2.4.19/include/asm-ia64/keyboard.h linux-2.4.19-sgi211r3/include/asm-ia64/keyboard.h --- linux-2.4.19/include/asm-ia64/keyboard.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/keyboard.h Wed Oct 16 14:02:58 2002 @@ -16,6 +16,7 @@ #define KEYBOARD_IRQ isa_irq_to_vector(1) #define DISABLE_KBD_DURING_INTERRUPTS 0 +extern unsigned char acpi_kbd_controller_present; extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); @@ -26,6 +27,7 @@ extern void pckbd_init_hw(void); extern unsigned char pckbd_sysrq_xlate[128]; +#define kbd_controller_present() acpi_kbd_controller_present #define kbd_setkeycode pckbd_setkeycode #define kbd_getkeycode pckbd_getkeycode #define kbd_pretranslate pckbd_pretranslate diff -Nur linux-2.4.19/include/asm-ia64/kregs.h linux-2.4.19-sgi211r3/include/asm-ia64/kregs.h --- linux-2.4.19/include/asm-ia64/kregs.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/kregs.h Tue Aug 27 19:53:13 2002 @@ -2,8 +2,8 @@ #define _ASM_IA64_KREGS_H /* - * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang + * Copyright (C) 2001-2002 Hewlett-Packard Co + * David Mosberger-Tang */ /* * This file defines the kernel register usage convention used by Linux/ia64. @@ -26,9 +26,138 @@ /* * Translation registers: */ -#define IA64_TR_KERNEL 0 /* itr0, dtr0: maps kernel image (code & data) */ +#define IA64_TR_KERNEL 0 /* itr0, dtr0: maps pernode kernel image (code & rodata) */ #define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */ #define IA64_TR_PERCPU_DATA 1 /* dtr1: percpu data */ #define IA64_TR_CURRENT_STACK 2 /* dtr2: maps kernel's memory- & register-stacks */ +#define IA64_TR_KERNEL_GLOBAL 3 /* dtr3: maps kernel global data*/ -#endif /* _ASM_IA64_kREGS_H */ +/* Processor status register bits: */ +#define IA64_PSR_BE_BIT 1 +#define IA64_PSR_UP_BIT 2 +#define IA64_PSR_AC_BIT 3 +#define IA64_PSR_MFL_BIT 4 +#define IA64_PSR_MFH_BIT 5 +#define IA64_PSR_IC_BIT 13 +#define IA64_PSR_I_BIT 14 +#define IA64_PSR_PK_BIT 15 +#define IA64_PSR_DT_BIT 17 +#define IA64_PSR_DFL_BIT 18 +#define IA64_PSR_DFH_BIT 19 +#define IA64_PSR_SP_BIT 20 +#define IA64_PSR_PP_BIT 21 +#define IA64_PSR_DI_BIT 22 +#define IA64_PSR_SI_BIT 23 +#define IA64_PSR_DB_BIT 24 +#define IA64_PSR_LP_BIT 25 +#define IA64_PSR_TB_BIT 26 +#define IA64_PSR_RT_BIT 27 +/* The following are not affected by save_flags()/restore_flags(): */ +#define IA64_PSR_CPL0_BIT 32 +#define IA64_PSR_CPL1_BIT 33 +#define IA64_PSR_IS_BIT 34 +#define IA64_PSR_MC_BIT 35 +#define IA64_PSR_IT_BIT 36 +#define IA64_PSR_ID_BIT 37 +#define IA64_PSR_DA_BIT 38 +#define IA64_PSR_DD_BIT 39 +#define IA64_PSR_SS_BIT 40 +#define IA64_PSR_RI_BIT 41 +#define IA64_PSR_ED_BIT 43 +#define IA64_PSR_BN_BIT 44 +#define IA64_PSR_IA_BIT 45 + +#define IA64_PSR_BE (__IA64_UL(1) << IA64_PSR_BE_BIT) +#define IA64_PSR_UP (__IA64_UL(1) << IA64_PSR_UP_BIT) +#define IA64_PSR_AC (__IA64_UL(1) << IA64_PSR_AC_BIT) +#define IA64_PSR_MFL (__IA64_UL(1) << IA64_PSR_MFL_BIT) +#define IA64_PSR_MFH (__IA64_UL(1) << IA64_PSR_MFH_BIT) +#define IA64_PSR_IC (__IA64_UL(1) << IA64_PSR_IC_BIT) +#define IA64_PSR_I (__IA64_UL(1) << IA64_PSR_I_BIT) +#define IA64_PSR_PK (__IA64_UL(1) << IA64_PSR_PK_BIT) +#define IA64_PSR_DT (__IA64_UL(1) << IA64_PSR_DT_BIT) +#define IA64_PSR_DFL (__IA64_UL(1) << IA64_PSR_DFL_BIT) +#define IA64_PSR_DFH (__IA64_UL(1) << IA64_PSR_DFH_BIT) +#define IA64_PSR_SP (__IA64_UL(1) << IA64_PSR_SP_BIT) +#define IA64_PSR_PP (__IA64_UL(1) << IA64_PSR_PP_BIT) +#define IA64_PSR_DI (__IA64_UL(1) << IA64_PSR_DI_BIT) +#define IA64_PSR_SI (__IA64_UL(1) << IA64_PSR_SI_BIT) +#define IA64_PSR_DB (__IA64_UL(1) << IA64_PSR_DB_BIT) +#define IA64_PSR_LP (__IA64_UL(1) << IA64_PSR_LP_BIT) +#define IA64_PSR_TB (__IA64_UL(1) << IA64_PSR_TB_BIT) +#define IA64_PSR_RT (__IA64_UL(1) << IA64_PSR_RT_BIT) +/* The following are not affected by save_flags()/restore_flags(): */ +#define IA64_PSR_CPL (__IA64_UL(3) << IA64_PSR_CPL0_BIT) +#define IA64_PSR_IS (__IA64_UL(1) << IA64_PSR_IS_BIT) +#define IA64_PSR_MC (__IA64_UL(1) << IA64_PSR_MC_BIT) +#define IA64_PSR_IT (__IA64_UL(1) << IA64_PSR_IT_BIT) +#define IA64_PSR_ID (__IA64_UL(1) << IA64_PSR_ID_BIT) +#define IA64_PSR_DA (__IA64_UL(1) << IA64_PSR_DA_BIT) +#define IA64_PSR_DD (__IA64_UL(1) << IA64_PSR_DD_BIT) +#define IA64_PSR_SS (__IA64_UL(1) << IA64_PSR_SS_BIT) +#define IA64_PSR_RI (__IA64_UL(3) << IA64_PSR_RI_BIT) +#define IA64_PSR_ED (__IA64_UL(1) << IA64_PSR_ED_BIT) +#define IA64_PSR_BN (__IA64_UL(1) << IA64_PSR_BN_BIT) +#define IA64_PSR_IA (__IA64_UL(1) << IA64_PSR_IA_BIT) + +/* A mask of PSR bits that we generally don't want to inherit across a clone2() or an + execve(). Only list flags here that need to be cleared/set for BOTH clone2() and + execve(). */ +#define IA64_PSR_BITS_TO_CLEAR (IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_DB | IA64_PSR_LP | \ + IA64_PSR_TB | IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ + IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA) +#define IA64_PSR_BITS_TO_SET (IA64_PSR_DFH) + +/* User mask bits: */ +#define IA64_PSR_UM (IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH) + +/* Default Control Register */ +#define IA64_DCR_PP_BIT 0 /* privileged performance monitor default */ +#define IA64_DCR_BE_BIT 1 /* big-endian default */ +#define IA64_DCR_LC_BIT 2 /* ia32 lock-check enable */ +#define IA64_DCR_DM_BIT 8 /* defer TLB miss faults */ +#define IA64_DCR_DP_BIT 9 /* defer page-not-present faults */ +#define IA64_DCR_DK_BIT 10 /* defer key miss faults */ +#define IA64_DCR_DX_BIT 11 /* defer key permission faults */ +#define IA64_DCR_DR_BIT 12 /* defer access right faults */ +#define IA64_DCR_DA_BIT 13 /* defer access bit faults */ +#define IA64_DCR_DD_BIT 14 /* defer debug faults */ + +#define IA64_DCR_PP (__IA64_UL(1) << IA64_DCR_PP_BIT) +#define IA64_DCR_BE (__IA64_UL(1) << IA64_DCR_BE_BIT) +#define IA64_DCR_LC (__IA64_UL(1) << IA64_DCR_LC_BIT) +#define IA64_DCR_DM (__IA64_UL(1) << IA64_DCR_DM_BIT) +#define IA64_DCR_DP (__IA64_UL(1) << IA64_DCR_DP_BIT) +#define IA64_DCR_DK (__IA64_UL(1) << IA64_DCR_DK_BIT) +#define IA64_DCR_DX (__IA64_UL(1) << IA64_DCR_DX_BIT) +#define IA64_DCR_DR (__IA64_UL(1) << IA64_DCR_DR_BIT) +#define IA64_DCR_DA (__IA64_UL(1) << IA64_DCR_DA_BIT) +#define IA64_DCR_DD (__IA64_UL(1) << IA64_DCR_DD_BIT) + +/* Interrupt Status Register */ +#define IA64_ISR_X_BIT 32 /* execute access */ +#define IA64_ISR_W_BIT 33 /* write access */ +#define IA64_ISR_R_BIT 34 /* read access */ +#define IA64_ISR_NA_BIT 35 /* non-access */ +#define IA64_ISR_SP_BIT 36 /* speculative load exception */ +#define IA64_ISR_RS_BIT 37 /* mandatory register-stack exception */ +#define IA64_ISR_IR_BIT 38 /* invalid register frame exception */ +#define IA64_ISR_CODE_MASK 0xf + +#define IA64_ISR_X (__IA64_UL(1) << IA64_ISR_X_BIT) +#define IA64_ISR_W (__IA64_UL(1) << IA64_ISR_W_BIT) +#define IA64_ISR_R (__IA64_UL(1) << IA64_ISR_R_BIT) +#define IA64_ISR_NA (__IA64_UL(1) << IA64_ISR_NA_BIT) +#define IA64_ISR_SP (__IA64_UL(1) << IA64_ISR_SP_BIT) +#define IA64_ISR_RS (__IA64_UL(1) << IA64_ISR_RS_BIT) +#define IA64_ISR_IR (__IA64_UL(1) << IA64_ISR_IR_BIT) + +/* ISR code field for non-access instructions */ +#define IA64_ISR_CODE_TPA 0 +#define IA64_ISR_CODE_FC 1 +#define IA64_ISR_CODE_PROBE 2 +#define IA64_ISR_CODE_TAK 3 +#define IA64_ISR_CODE_LFETCH 4 +#define IA64_ISR_CODE_PROBEF 5 + +#endif /* _ASM_IA64_KREGS_H */ diff -Nur linux-2.4.19/include/asm-ia64/machvec.h linux-2.4.19-sgi211r3/include/asm-ia64/machvec.h --- linux-2.4.19/include/asm-ia64/machvec.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/machvec.h Wed Oct 16 14:02:58 2002 @@ -18,11 +18,13 @@ struct pt_regs; struct scatterlist; struct irq_desc; +struct page; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_cpu_init_t(void); typedef void ia64_mv_irq_init_t (void); typedef void ia64_mv_pci_fixup_t (int); +typedef void ia64_mv_pci_enable_device_t (struct pci_dev *); typedef unsigned long ia64_mv_map_nr_t (unsigned long); typedef void ia64_mv_mca_init_t (void); typedef void ia64_mv_mca_handler_t (void); @@ -45,6 +47,8 @@ typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int); typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int); typedef unsigned long ia64_mv_pci_dma_address (struct scatterlist *); +typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64); + /* * WARNING: The legacy I/O space is _architected_. Platforms are * expected to follow this architected model (see Section 10.7 in the @@ -60,6 +64,7 @@ typedef void ia64_mv_outb_t (unsigned char, unsigned long); typedef void ia64_mv_outw_t (unsigned short, unsigned long); typedef void ia64_mv_outl_t (unsigned int, unsigned long); +typedef void ia64_mv_mmiob_t (void); extern void machvec_noop (void); @@ -67,6 +72,8 @@ # include # elif defined (CONFIG_IA64_DIG) # include +# elif defined (CONFIG_IA64_HP_ZX1) +# include # elif defined (CONFIG_IA64_SGI_SN1) # include # elif defined (CONFIG_IA64_SGI_SN2) @@ -86,7 +93,8 @@ # define platform_cmci_handler ia64_mv.cmci_handler # define platform_log_print ia64_mv.log_print # define platform_pci_fixup ia64_mv.pci_fixup -# define platform_send_ipi ia64_mv.send_ipi +# define platform_pci_enable_device ia64_mv.pci_enable_device +# define platform_send_ipi ia64_mv.send_ipi # define platform_global_tlb_purge ia64_mv.global_tlb_purge # define platform_pci_dma_init ia64_mv.dma_init # define platform_pci_alloc_consistent ia64_mv.alloc_consistent @@ -98,6 +106,7 @@ # define platform_pci_dma_sync_single ia64_mv.sync_single # define platform_pci_dma_sync_sg ia64_mv.sync_sg # define platform_pci_dma_address ia64_mv.dma_address +# define platform_pci_dma_supported ia64_mv.dma_supported # define platform_irq_desc ia64_mv.irq_desc # define platform_irq_to_vector ia64_mv.irq_to_vector # define platform_local_vector_to_irq ia64_mv.local_vector_to_irq @@ -107,6 +116,7 @@ # define platform_outb ia64_mv.outb # define platform_outw ia64_mv.outw # define platform_outl ia64_mv.outl +# define platofrm_mmiob ia64_mv.mmiob # endif struct ia64_machine_vector { @@ -115,12 +125,14 @@ ia64_mv_cpu_init_t *cpu_init; ia64_mv_irq_init_t *irq_init; ia64_mv_pci_fixup_t *pci_fixup; + ia64_mv_pci_enable_device_t *pci_enable_device; ia64_mv_map_nr_t *map_nr; ia64_mv_mca_init_t *mca_init; ia64_mv_mca_handler_t *mca_handler; ia64_mv_cmci_handler_t *cmci_handler; ia64_mv_log_print_t *log_print; ia64_mv_send_ipi_t *send_ipi; + ia64_mv_global_tlb_purge_t *global_tlb_purge; ia64_mv_pci_dma_init *dma_init; ia64_mv_pci_alloc_consistent *alloc_consistent; ia64_mv_pci_free_consistent *free_consistent; @@ -131,6 +143,7 @@ ia64_mv_pci_dma_sync_single *sync_single; ia64_mv_pci_dma_sync_sg *sync_sg; ia64_mv_pci_dma_address *dma_address; + ia64_mv_pci_dma_supported *dma_supported; ia64_mv_irq_desc *irq_desc; ia64_mv_irq_to_vector *irq_to_vector; ia64_mv_local_vector_to_irq *local_vector_to_irq; @@ -140,14 +153,17 @@ ia64_mv_outb_t *outb; ia64_mv_outw_t *outw; ia64_mv_outl_t *outl; + ia64_mv_mmiob_t *mmiob; }; #define MACHVEC_INIT(name) \ { \ #name, \ platform_setup, \ + platform_cpu_init, \ platform_irq_init, \ platform_pci_fixup, \ + platform_pci_enable_device, \ platform_map_nr, \ platform_mca_init, \ platform_mca_handler, \ @@ -165,6 +181,7 @@ platform_pci_dma_sync_single, \ platform_pci_dma_sync_sg, \ platform_pci_dma_address, \ + platform_pci_dma_supported, \ platform_irq_desc, \ platform_irq_to_vector, \ platform_local_vector_to_irq, \ @@ -173,7 +190,8 @@ platform_inl, \ platform_outb, \ platform_outw, \ - platform_outl \ + platform_outl, \ + platform_mmiob \ } extern struct ia64_machine_vector ia64_mv; @@ -196,6 +214,7 @@ extern ia64_mv_pci_dma_sync_single swiotlb_sync_single; extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg; extern ia64_mv_pci_dma_address swiotlb_dma_address; +extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported; /* * Define default versions so we can extend machvec for new platforms without having @@ -225,6 +244,9 @@ #ifndef platform_pci_fixup # define platform_pci_fixup ((ia64_mv_pci_fixup_t *) machvec_noop) #endif +#ifndef platform_pci_enable_device +# define platform_pci_enable_device ((ia64_mv_pci_enable_device_t *) machvec_noop) +#endif #ifndef platform_send_ipi # define platform_send_ipi ia64_send_ipi /* default to architected version */ #endif @@ -261,6 +283,9 @@ #ifndef platform_pci_dma_address # define platform_pci_dma_address swiotlb_dma_address #endif +#ifndef platform_pci_dma_supported +# define platform_pci_dma_supported swiotlb_pci_dma_supported +#endif #ifndef platform_irq_desc # define platform_irq_desc __ia64_irq_desc #endif @@ -287,6 +312,9 @@ #endif #ifndef platform_outl # define platform_outl __ia64_outl +#endif +#ifndef platform_mmiob +# define platform_mmiob __ia64_mmiob #endif #endif /* _ASM_IA64_MACHVEC_H */ diff -Nur linux-2.4.19/include/asm-ia64/machvec_hpzx1.h linux-2.4.19-sgi211r3/include/asm-ia64/machvec_hpzx1.h --- linux-2.4.19/include/asm-ia64/machvec_hpzx1.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/machvec_hpzx1.h Wed Oct 16 14:02:58 2002 @@ -0,0 +1,41 @@ +#ifndef _ASM_IA64_MACHVEC_HPZX1_h +#define _ASM_IA64_MACHVEC_HPZX1_h + +extern ia64_mv_setup_t dig_setup; +extern ia64_mv_pci_fixup_t hpzx1_pci_fixup; +extern ia64_mv_pci_enable_device_t sba_enable_device; +extern ia64_mv_map_nr_t map_nr_dense; +extern ia64_mv_pci_alloc_consistent sba_alloc_consistent; +extern ia64_mv_pci_free_consistent sba_free_consistent; +extern ia64_mv_pci_map_single sba_map_single; +extern ia64_mv_pci_unmap_single sba_unmap_single; +extern ia64_mv_pci_map_sg sba_map_sg; +extern ia64_mv_pci_unmap_sg sba_unmap_sg; +extern ia64_mv_pci_dma_address sba_dma_address; +extern ia64_mv_pci_dma_supported sba_dma_supported; + +/* + * This stuff has dual use! + * + * For a generic kernel, the macros are used to initialize the + * platform's machvec structure. When compiling a non-generic kernel, + * the macros are used directly. + */ +#define platform_name "hpzx1" +#define platform_setup dig_setup +#define platform_pci_fixup hpzx1_pci_fixup +#define platform_pci_enable_device sba_enable_device +#define platform_map_nr map_nr_dense +#define platform_pci_dma_init ((ia64_mv_pci_dma_init *) machvec_noop) +#define platform_pci_alloc_consistent sba_alloc_consistent +#define platform_pci_free_consistent sba_free_consistent +#define platform_pci_map_single sba_map_single +#define platform_pci_unmap_single sba_unmap_single +#define platform_pci_map_sg sba_map_sg +#define platform_pci_unmap_sg sba_unmap_sg +#define platform_pci_dma_sync_single ((ia64_mv_pci_dma_sync_single *) machvec_noop) +#define platform_pci_dma_sync_sg ((ia64_mv_pci_dma_sync_sg *) machvec_noop) +#define platform_pci_dma_address sba_dma_address +#define platform_pci_dma_supported sba_dma_supported + +#endif /* _ASM_IA64_MACHVEC_HPZX1_h */ diff -Nur linux-2.4.19/include/asm-ia64/machvec_init.h linux-2.4.19-sgi211r3/include/asm-ia64/machvec_init.h --- linux-2.4.19/include/asm-ia64/machvec_init.h Thu Jan 4 12:50:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/machvec_init.h Fri Apr 26 11:07:18 2002 @@ -5,6 +5,11 @@ #include extern ia64_mv_send_ipi_t ia64_send_ipi; +extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge; +extern ia64_mv_irq_desc __ia64_irq_desc; +extern ia64_mv_irq_to_vector __ia64_irq_to_vector; +extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq; + extern ia64_mv_inb_t __ia64_inb; extern ia64_mv_inw_t __ia64_inw; extern ia64_mv_inl_t __ia64_inl; diff -Nur linux-2.4.19/include/asm-ia64/machvec_sn1.h linux-2.4.19-sgi211r3/include/asm-ia64/machvec_sn1.h --- linux-2.4.19/include/asm-ia64/machvec_sn1.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/machvec_sn1.h Mon Dec 30 14:16:56 2002 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -42,7 +42,6 @@ extern ia64_mv_irq_desc sn_irq_desc; extern ia64_mv_irq_to_vector sn_irq_to_vector; extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq; -extern ia64_mv_valid_irq sn_valid_irq; extern ia64_mv_pci_fixup_t sn_pci_fixup; extern ia64_mv_inb_t sn_inb; extern ia64_mv_inw_t sn_inw; @@ -50,6 +49,7 @@ extern ia64_mv_outb_t sn_outb; extern ia64_mv_outw_t sn_outw; extern ia64_mv_outl_t sn_outl; +extern ia64_mv_mmiob_t sn1_mmiob; extern ia64_mv_pci_alloc_consistent sn_pci_alloc_consistent; extern ia64_mv_pci_free_consistent sn_pci_free_consistent; extern ia64_mv_pci_map_single sn_pci_map_single; @@ -59,6 +59,7 @@ extern ia64_mv_pci_dma_sync_single sn_pci_dma_sync_single; extern ia64_mv_pci_dma_sync_sg sn_pci_dma_sync_sg; extern ia64_mv_pci_dma_address sn_dma_address; +extern ia64_mv_pci_dma_supported sn_pci_dma_supported; /* * This stuff has dual use! @@ -80,11 +81,11 @@ #define platform_inl sn_inl #define platform_outb sn_outb #define platform_outw sn_outw -#define platform_oul sn_outl +#define platform_outl sn_outl +#define platform_mmiob sn1_mmiob #define platform_irq_desc sn_irq_desc #define platform_irq_to_vector sn_irq_to_vector #define platform_local_vector_to_irq sn_local_vector_to_irq -#define platform_valid_irq sn_valid_irq #define platform_pci_dma_init machvec_noop #define platform_pci_alloc_consistent sn_pci_alloc_consistent #define platform_pci_free_consistent sn_pci_free_consistent @@ -95,5 +96,6 @@ #define platform_pci_dma_sync_single sn_pci_dma_sync_single #define platform_pci_dma_sync_sg sn_pci_dma_sync_sg #define platform_pci_dma_address sn_dma_address +#define platform_pci_dma_supported sn_pci_dma_supported #endif /* _ASM_IA64_MACHVEC_SN1_h */ diff -Nur linux-2.4.19/include/asm-ia64/machvec_sn2.h linux-2.4.19-sgi211r3/include/asm-ia64/machvec_sn2.h --- linux-2.4.19/include/asm-ia64/machvec_sn2.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/machvec_sn2.h Mon Dec 30 14:16:56 2002 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -42,7 +42,6 @@ extern ia64_mv_irq_desc sn_irq_desc; extern ia64_mv_irq_to_vector sn_irq_to_vector; extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq; -extern ia64_mv_valid_irq sn_valid_irq; extern ia64_mv_pci_fixup_t sn_pci_fixup; extern ia64_mv_inb_t sn_inb; extern ia64_mv_inw_t sn_inw; @@ -50,6 +49,7 @@ extern ia64_mv_outb_t sn_outb; extern ia64_mv_outw_t sn_outw; extern ia64_mv_outl_t sn_outl; +extern ia64_mv_mmiob_t sn2_mmiob; extern ia64_mv_pci_alloc_consistent sn_pci_alloc_consistent; extern ia64_mv_pci_free_consistent sn_pci_free_consistent; extern ia64_mv_pci_map_single sn_pci_map_single; @@ -59,6 +59,7 @@ extern ia64_mv_pci_dma_sync_single sn_pci_dma_sync_single; extern ia64_mv_pci_dma_sync_sg sn_pci_dma_sync_sg; extern ia64_mv_pci_dma_address sn_dma_address; +extern ia64_mv_pci_dma_supported sn_pci_dma_supported; /* * This stuff has dual use! @@ -80,11 +81,11 @@ #define platform_inl sn_inl #define platform_outb sn_outb #define platform_outw sn_outw -#define platform_oul sn_outl +#define platform_outl sn_outl +#define platform_mmiob sn2_mmiob #define platform_irq_desc sn_irq_desc #define platform_irq_to_vector sn_irq_to_vector #define platform_local_vector_to_irq sn_local_vector_to_irq -#define platform_valid_irq sn_valid_irq #define platform_pci_dma_init machvec_noop #define platform_pci_alloc_consistent sn_pci_alloc_consistent #define platform_pci_free_consistent sn_pci_free_consistent @@ -95,5 +96,6 @@ #define platform_pci_dma_sync_single sn_pci_dma_sync_single #define platform_pci_dma_sync_sg sn_pci_dma_sync_sg #define platform_pci_dma_address sn_dma_address +#define platform_pci_dma_supported sn_pci_dma_supported #endif /* _ASM_IA64_MACHVEC_SN2_H */ diff -Nur linux-2.4.19/include/asm-ia64/mca.h linux-2.4.19-sgi211r3/include/asm-ia64/mca.h --- linux-2.4.19/include/asm-ia64/mca.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/mca.h Fri Nov 8 18:02:01 2002 @@ -141,7 +141,14 @@ #define platform_mem_dev_err_print ia64_log_prt_oem_data #define platform_pci_bus_err_print ia64_log_prt_oem_data #define platform_pci_comp_err_print ia64_log_prt_oem_data +#ifdef CONFIG_IA64_SGI_SN2 +#define IA64_DUMP_ALL_PROC_INFO 1 +#define IA64_DUMP_INIT_RECORDS_AT_BOOT 1 +void ia64_sn2_platform_plat_specific_err_print(int, int, u8*, prfunc_t); +#define platform_plat_specific_err_print ia64_sn2_platform_plat_specific_err_print +#else #define platform_plat_specific_err_print ia64_log_prt_oem_data +#endif #define platform_host_ctlr_err_print ia64_log_prt_oem_data #define platform_plat_bus_err_print ia64_log_prt_oem_data diff -Nur linux-2.4.19/include/asm-ia64/mca_asm.h linux-2.4.19-sgi211r3/include/asm-ia64/mca_asm.h --- linux-2.4.19/include/asm-ia64/mca_asm.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/mca_asm.h Tue May 14 09:10:56 2002 @@ -26,7 +26,8 @@ * 1. Lop off bits 61 thru 63 in the virtual address */ #define INST_VA_TO_PA(addr) \ - dep addr = 0, addr, 61, 3 + tpa addr = addr; + /* * This macro converts a data virtual address to a physical address * Right now for simulation purposes the virtual addresses are @@ -34,7 +35,22 @@ * 1. Lop off bits 61 thru 63 in the virtual address */ #define DATA_VA_TO_PA(addr) \ - dep addr = 0, addr, 61, 3 + tpa addr = addr; + +/* + * This macro converts a data text virtual address to a physical address + * This macro is used ONLY when running in physical addressing mode & does + * not require the TLB to do conversion. + * Conversion relies on the fact that GP & the symbol address being converted reside + * in the same GRANULE (large page size used for kernel mappings). + */ +#define DATA_SYM_TO_PA(reg,addr,tmp) \ + movl reg=addr;; \ + dep reg=0,reg,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT;; \ + dep tmp=0,gp,0,KERNEL_TR_PAGE_SHIFT;; \ + or reg=reg,tmp + + /* * This macro converts a data physical address to a virtual address * Right now for simulation purposes the virtual addresses are diff -Nur linux-2.4.19/include/asm-ia64/mmu_context.h linux-2.4.19-sgi211r3/include/asm-ia64/mmu_context.h --- linux-2.4.19/include/asm-ia64/mmu_context.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/mmu_context.h Mon Oct 28 20:43:23 2002 @@ -44,16 +44,34 @@ { } +/* + * When the context counter wraps around all TLBs need to be flushed because + * an old context number might have been reused. This is signalled by a bit + * set in ia64_ctx.flush, which is checked in the routine below. Called by + * activate_mm(). + */ +static inline void +delayed_tlb_flush (void) +{ + extern void __flush_tlb_all (void); + + if (unlikely(local_cpu_data->tlb_flush)) { + __flush_tlb_all(); + local_cpu_data->tlb_flush = 0; + } +} + static inline void get_new_mmu_context (struct mm_struct *mm) { - spin_lock(&ia64_ctx.lock); + unsigned long flags; + spin_lock_irqsave(&ia64_ctx.lock,flags); { if (ia64_ctx.next >= ia64_ctx.limit) wrap_mmu_context(mm); mm->context = ia64_ctx.next++; } - spin_unlock(&ia64_ctx.lock); + spin_unlock_irqrestore(&ia64_ctx.lock,flags); } @@ -113,9 +131,26 @@ * We may get interrupts here, but that's OK because interrupt * handlers cannot touch user-space. */ + delayed_tlb_flush(); ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd)); get_mmu_context(next); reload_context(next); +} + +/* + * Needed for the O(1) MQ scheduler. + */ +#if MAX_PRIO >= 192 +# error update this function. */ +#endif + +static inline int sched_find_first_bit(unsigned long *b) +{ + if (unlikely(b[0])) + return __ffs(b[0]); + if (b[1]) + return 64 + __ffs(b[1]); + return __ffs(b[2]) + 128; } #define switch_mm(prev_mm,next_mm,next_task,cpu) activate_mm(prev_mm, next_mm) diff -Nur linux-2.4.19/include/asm-ia64/mmzone.h linux-2.4.19-sgi211r3/include/asm-ia64/mmzone.h --- linux-2.4.19/include/asm-ia64/mmzone.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/mmzone.h Thu Jan 2 15:16:59 2003 @@ -0,0 +1,218 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ +#ifndef _ASM_IA64_SN_MMZONE_H +#define _ASM_IA64_SN_MMZONE_H + +#include +#include + +#if defined(CONFIG_IA64_SGI_SN1) +#include +#elif defined(CONFIG_IA64_SGI_SN2) +#include +#elif defined(CONFIG_IA64_DIG) +#include +#else +#error "Unknown architecture" +#endif + + +/* + * General Concepts: + * + * - Nodes are numbered several ways: + * + * compact node numbers - compact node numbers are a dense numbering of + * all the nodes in the system. An N node system will have compact + * nodes numbered 0 .. N-1. There is no significance to the node + * numbers. The compact node number assigned to a specific physical + * node may vary from boot to boot. The boot node is not necessarily + * node 0. + * + * physical node numbers - Physical node numbers may not be dense + * nor do they necessarily start with 0. The exact significance of + * a physical node number is platform specific. + * + * proximity domain numbers - these numbers are assigned by ACPI. + * Each platform must provide a platform specific function + * for mapping proximity node numbers to physical node numbers. + * + * Most of the code in the kernel uses compact node numbers to identify nodes. + * + * + * - Memory is conceptually divided into chunks. A chunk is either + * completely present, or else the kernel assumes it is completely + * absent. Each node consists of a number of possibly discontiguous chunks. + * + * - A contiguous group of memory chunks that reside on the same node + * are referred to as a clump. Note that a clump may be partially present. + * (Note, on some hardware implementations, a clump is the same as a memory + * bank or a DIMM). + * + * - a node consists of multiple clumps of memory. From a NUMA perspective, + * accesses to all clumps on the node have the same latency. Except for zone issues, + * the clumps are treated as equivalent for allocation/performance purposes. + * + * - each node has a single contiguous mem_map array. The array contains page struct + * entries for every page on the node. There are no "holes" in the mem_map array. + * The node data area (see below) has pointers to the start of the mem_map entries + * for each clump on the node. + * + * - associated with each node is a pg_data_t structure. This structure contains the + * information used by the linux memory allocator for managing the memory on the + * node. The pg_data_t structure for a node is located on the node. + * + * - to minimize offnode memory references, a "node directory" is maintained on each + * node. This directory replicates frequently used read-only data structures that + * are used in macro evaluation. Examples include the addresses of the + * pernode pg_data structures for each node. + * + * - the MAP_NR function has been modified to be "clump aware" & uses the clump_mem_map_base + * array in the node data area for generating MAP_NR numbers. + * + * - the node data area contains array of pointers to the mem_map entries for each clump + * of memory. The array is indexed by a platform specific function. + * + * - each cpu has a pointer it's node data area contained in it's cpu_data structure. + * + * - each platform is responsible for defining the following constants & functions: + * + * PLAT_BOOTMEM_ALLOC_GOAL(cnode,kaddr) - Calculate a "goal" value to be passed + * to __alloc_bootmem_node for allocating structures on nodes so that + * they dont alias to the same line in the cache as the previous + * allocated structure. You can return 0 if your platform doesnt have + * this problem. + * (Note: need better solution but works for now ZZZ). + * + * PLAT_CHUNKSIZE - defines the size of the platform memory chunk. + * + * PLAT_CHUNKNUM(kaddr) - takes a kaddr & returns its chunk number + * + * PLAT_CLUMP_MEM_MAP_INDEX(kaddr) - Given a kaddr, find the index into the + * clump_mem_map_base array of the page struct entry for the first page + * of the clump. + * + * PLAT_CLUMP_OFFSET(kaddr) - find the byte offset of a kaddr within the clump that + * contains it. + * + * PLAT_CLUMPSIZE - defines the size in bytes of the smallest clump supported on the platform. + * + * PLAT_CLUMPS_PER_NODE - maximum number of clumps per node + * + * PLAT_MAXCLUMPS - maximum number of clumps on all node combined + * + * PLAT_MAX_COMPACT_NODES - maximum number of nodes in a system. (do not confuse this + * with the maximum node number. Nodes can be sparsely numbered). + * + * PLAT_MAX_NODE_NUMBER - maximum physical node number plus 1 + * + * PLAT_MAX_PHYS_MEMORY - maximum physical memory address + * + * PLAT_PXM_TO_PHYS_NODE_NUMBER(pxm) - convert a proximity_domain number (from ACPI) + * into a physical node number + * + * PLAT_VALID_MEM_KADDR(kaddr) - tests a kaddr to see if it potentially represents a + * valid physical memory address. Return 1 if potentially valid, 0 otherwise. + * (This function generally tests to see if any invalid bits are set in + * the address). + * + * + * - each platform is responsible for defining the following typedefs:: + * + * cnodeid_t - compact node number + * + */ + + +extern struct page *invalid_mem_map; /* value returned by virt_to_page for bad addresses */ + + + +/* + * Chunk related macros + * Note: It is not clear if VALIDCHUNK is really needed. It is currently used + * ONLY in kern_address_valid. The non-NUMA variant of this always + * returns 1. + * ZZZ Fixme???? + */ +#define VALIDCHUNK(cnum) 1 + + + +/* + * Given a kaddr, find the base mem_map address for the start of the mem_map + * entries for the clump containing the kaddr. + */ +#define CLUMP_MEM_MAP_BASE(kaddr) local_node_data->clump_mem_map_base[PLAT_CLUMP_MEM_MAP_INDEX(kaddr)] + + + +/* + * Given a kaddr, this macro return the relative map number + * within the clump. + */ +#define CLUMP_MAP_NR(kaddr) (PLAT_CLUMP_OFFSET(kaddr) >> PAGE_SHIFT) + + + +/* + * Finally.... This is the MAP_NR function for the platform. + */ +#define MAP_NR_DISCONTIG(kaddr) ({long _kmns=(long)(kaddr); \ + CLUMP_MAP_NR(_kmns) + \ + CLUMP_MEM_MAP_BASE(_kmns) - mem_map;}) + +/* + * Given a pte, this macro returns a pointer to the page struct for the pte. + */ +#define pte_page(pte) virt_to_page(PAGE_OFFSET | (pte_val(pte)&_PFN_MASK)) + + + +/* + * Determine if a kaddr is a valid memory address of memory that + * actually exists. + * + * The check consists of 2 parts: + * - verify that the address is a region 7 address & does not + * contain any bits that preclude it from being a valid platform + * memory address + * - verify that the chunk actually exists. + * + * Note that IO addresses are NOT considered valid addresses. + * + * Note, many platforms can simply check if kaddr exceeds a specific size. + * (However, this wont work on SGI platforms since IO space is embedded + * within the range of valid memory addresses & nodes have holes in the + * address range between clumps). + */ +#define kern_addr_valid(kaddr) ({long _kav=(long)(kaddr); \ + PLAT_VALID_MEM_KADDR(_kav) && VALIDCHUNK(PLAT_CHUNKNUM(_kav));}) + + +/* + * Given a kaddr, return a pointer to the page struct for the page. + * If the kaddr does not represent RAM memory that potentially exists, return + * a pointer the page struct for max_mapnr. IO addresses will + * return the page for max_nr. Addresses in unpopulated RAM banks may + * return undefined results OR may panic the system. + * + */ +#define virt_to_page(kaddr) ({long _kvtp=(long)(kaddr); \ + (PLAT_VALID_MEM_KADDR(_kvtp)) \ + ? CLUMP_MEM_MAP_BASE(_kvtp) + CLUMP_MAP_NR(_kvtp) \ + : invalid_mem_map;}) + +/* + * Given a page struct entry, return the physical address that the page struct represents. + * Since IA64 has all memory in the DMA zone, the following works: + */ +#define page_to_phys(page) __pa(page_address(page)) + + +#endif /* _ASM_IA64_SN_MMZONE_H */ diff -Nur linux-2.4.19/include/asm-ia64/mmzone_dig_numa.h linux-2.4.19-sgi211r3/include/asm-ia64/mmzone_dig_numa.h --- linux-2.4.19/include/asm-ia64/mmzone_dig_numa.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/mmzone_dig_numa.h Thu Jan 2 15:16:59 2003 @@ -0,0 +1,84 @@ +#ifndef _ASM_IA64_MMZONE_AEGL_H +#define _ASM_IA64_MMZONE_AEGL_H + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + */ + +typedef short cnodeid_t; + + + +/* + * Platform definitions for AEGL platform + */ + + +#define PLAT_MAX_NODE_NUMBER 16 /* Maximum node number +1 */ +#define PLAT_MAX_COMPACT_NODES 16 /* Maximum number of nodes in SSI */ + +#define PLAT_MAX_PHYS_MEMORY (1UL << 40) + + + +/* + * Clump definitions. + */ +#define PLAT_CLUMPS_PER_NODE 4 +#define PLAT_CLUMP_OFFSET(addr) ((unsigned long)(addr) & (PLAT_CLUMPSIZE-1)) +#define PLAT_CLUMPSIZE (1UL << 27) +#define PLAT_MAXCLUMPS (PLAT_CLUMPS_PER_NODE*PLAT_MAX_COMPACT_NODES) + + + + +/* + * PLAT_VALID_MEM_KADDR returns a boolean to indicate if a kaddr is potentially a + * valid cacheable identity mapped RAM memory address. + * Note that the RAM may or may not actually be present!! + */ +#define PLAT_VALID_MEM_KADDR(kaddr) 1 + + + +/* + * Memory is conceptually divided into chunks. A chunk is either + * completely present, or else the kernel assumes it is completely + * absent. Each node consists of a number of possibly discontiguous chunks. + */ +#define AEGL_CHUNKSHIFT 27 +#define PLAT_CHUNKSIZE (1UL << AEGL_CHUNKSHIFT) +#define PLAT_CHUNKNUM(addr) (((addr) & (PLAT_MAX_PHYS_MEMORY-1)) >> AEGL_CHUNKSHIFT) + + + + +/* + * Given a compact nodeid & a clump number, find the address of the mem_map + * entry for the first page of the clump. + */ +#define PLAT_CLUMP_MEM_MAP_INDEX(kaddr) (((unsigned long)(kaddr) & (PLAT_MAX_PHYS_MEMORY-1)) >> AEGL_CHUNKSHIFT) + + +/* + * Calculate a "goal" value to be passed to __alloc_bootmem_node for allocating structures on + * nodes so that they dont alias to the same line in the cache as the previous allocated structure. + * This macro takes an address of the end of previous allocation, rounds it to a page boundary & + * changes the node number. + */ +#define PLAT_BOOTMEM_ALLOC_GOAL(cnode,kaddr) 0 /* not used yet */ + + + + +/* + * Convert a proximity domain number (from the ACPI tables) into a physical node number. + */ + +#define PLAT_PXM_TO_PHYS_NODE_NUMBER(pxm) (pxm) + +#endif /* _ASM_IA64_MMZONE_AEGL_H */ diff -Nur linux-2.4.19/include/asm-ia64/module.h linux-2.4.19-sgi211r3/include/asm-ia64/module.h --- linux-2.4.19/include/asm-ia64/module.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/module.h Fri Apr 26 11:07:18 2002 @@ -51,6 +51,9 @@ return 0; archdata = (struct archdata *)(mod->archdata_start); + if (archdata->unw_start == 0) + return 0; + /* * Make sure the unwind pointers are sane. */ diff -Nur linux-2.4.19/include/asm-ia64/nodedata.h linux-2.4.19-sgi211r3/include/asm-ia64/nodedata.h --- linux-2.4.19/include/asm-ia64/nodedata.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/nodedata.h Thu Jan 2 15:16:59 2003 @@ -0,0 +1,96 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2000-2001 Silicon Graphics, Inc. All rights reserved. + */ + + +#ifndef _ASM_IA64_NODEDATA_H +#define _ASM_IA64_NODEDATA_H + + +#include + + +/* + * Node Data. One of these structures is located on each node of a NUMA system. + */ + +struct pglist_data; + +typedef struct ia64_node_data_s { + cnodeid_t cnodeid; + short active_cpu_count; + + /* + * The fields are read-only (after boot). They containing pointers to various structures + * located on other nodes. Ths data is replicated on each node in order to reduce + * off-node references. + */ + struct pglist_data *pg_data_ptrs[PLAT_MAX_COMPACT_NODES]; + cnodeid_t physical_node_map[PLAT_MAX_NODE_NUMBER]; + struct page *clump_mem_map_base[PLAT_MAXCLUMPS]; + struct ia64_node_data_s *node_data_ptrs[PLAT_MAX_COMPACT_NODES]; +} ia64_node_data_t; + + +/* + * Return a pointer to the node_data structure for the executing cpu. + */ +#define local_node_data (local_cpu_data->node_data) + + +/* + * Return a pointer to the node_data structure for the specified cnodeid. + */ +#define node_data(cnodeid) (local_node_data->node_data_ptrs[cnodeid]) + + +/* + * Convert a physical node number to a cnodeid + */ +#define phys_node_to_cnodeid(pnode) (local_node_data->physical_node_map[pnode]) + + +/* + * Determine if a physical node is present. + */ +#define phys_node_present(pnode) (local_node_data->physical_node_map[pnode] != (cnodeid_t) -1) + + +/* + * Get a pointer to the node_data for the current cpu. + * (boot time only) + */ +ia64_node_data_t* get_node_data_ptr(void); + + +/* + * Given a compact node id, return a pointer to the pg_data_t for the node. + * The following 2 macros are similar. + * + * NODE_DATA - should be used in all code not related to system + * initialization. It uses pernode data structures to minimize + * offnode memory references. However, these structure are not + * present during boot. This macro can be used once cpu_init + * completes. + * + * BOOT_NODE_DATA - should be used during system initialization + * prior to freeing __initdata. It does not depend on the percpu + * area being present. + * + * NOTE: The names of these macros are misleading but are difficult to change + * since they are used in generic linux & on other architecures. + * We should consider chnaging these names in 2.5.x. + */ +#define NODE_DATA(nid) (local_node_data->pg_data_ptrs[nid]) +#define BOOT_NODE_DATA(nid) boot_get_pg_data_ptr((long)(nid)) + +struct pglist_data; +extern struct pglist_data * __init boot_get_pg_data_ptr(long); + +#endif /* _ASM_IA64_NODEDATA_H */ + + diff -Nur linux-2.4.19/include/asm-ia64/offsets.h linux-2.4.19-sgi211r3/include/asm-ia64/offsets.h --- linux-2.4.19/include/asm-ia64/offsets.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/offsets.h Tue Aug 27 19:53:13 2002 @@ -8,7 +8,7 @@ */ #define PT_PTRACED_BIT 0 #define PT_TRACESYS_BIT 1 -#define IA64_TASK_SIZE 3936 /* 0xf60 */ +#define IA64_TASK_SIZE 3424 /* 0xd60 */ #define IA64_PT_REGS_SIZE 400 /* 0x190 */ #define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */ #define IA64_SIGINFO_SIZE 128 /* 0x80 */ @@ -20,9 +20,9 @@ #define IA64_TASK_SIGPENDING_OFFSET 16 /* 0x10 */ #define IA64_TASK_NEED_RESCHED_OFFSET 40 /* 0x28 */ #define IA64_TASK_PROCESSOR_OFFSET 96 /* 0x60 */ -#define IA64_TASK_THREAD_OFFSET 1488 /* 0x5d0 */ -#define IA64_TASK_THREAD_KSP_OFFSET 1488 /* 0x5d0 */ -#define IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET 2112 /* 0x840 */ +#define IA64_TASK_THREAD_OFFSET 992 /* 0x3e0 */ +#define IA64_TASK_THREAD_KSP_OFFSET 992 /* 0x3e0 */ +#define IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET 1616 /* 0x650 */ #define IA64_TASK_PID_OFFSET 228 /* 0xe4 */ #define IA64_TASK_MM_OFFSET 88 /* 0x58 */ #define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */ @@ -115,6 +115,7 @@ #define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536 /* 0x218 */ #define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544 /* 0x220 */ #define IA64_SWITCH_STACK_PR_OFFSET 552 /* 0x228 */ +#define IA64_SIGCONTEXT_IP_OFFSET 40 /* 0x28 */ #define IA64_SIGCONTEXT_AR_BSP_OFFSET 72 /* 0x48 */ #define IA64_SIGCONTEXT_AR_FPSR_OFFSET 104 /* 0x68 */ #define IA64_SIGCONTEXT_AR_RNAT_OFFSET 80 /* 0x50 */ diff -Nur linux-2.4.19/include/asm-ia64/page.h linux-2.4.19-sgi211r3/include/asm-ia64/page.h --- linux-2.4.19/include/asm-ia64/page.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/page.h Thu Dec 12 12:39:32 2002 @@ -31,6 +31,12 @@ #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) #ifdef __ASSEMBLY__ +/* + * NOTE: These macros DO NOT work for kernel text/data addresses on all platforms + * since kernel text/static-data is not necessarily identity mapped. + * Use these macros ONLY for identity mapped addresses. + * (See __tpa & __imva) + */ # define __pa(x) ((x) - PAGE_OFFSET) # define __va(x) ((x) + PAGE_OFFSET) #else /* !__ASSEMBLY */ @@ -52,20 +58,25 @@ */ #define MAP_NR_DENSE(addr) (((unsigned long) (addr) - PAGE_OFFSET) >> PAGE_SHIFT) +#ifdef CONFIG_IA64_SGI_SN +#define WANT_PAGE_VIRTUAL 1 +#endif + #ifdef CONFIG_IA64_GENERIC # include # define virt_to_page(kaddr) (mem_map + platform_map_nr(kaddr)) -# define page_to_phys(page) XXX fix me -#elif defined (CONFIG_IA64_SGI_SN1) -# ifndef CONFIG_DISCONTIGMEM -# define virt_to_page(kaddr) (mem_map + MAP_NR_DENSE(kaddr)) -# define page_to_phys(page) XXX fix me -# endif -#else +# define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) +#elif !defined (CONFIG_DISCONTIGMEM) # define virt_to_page(kaddr) (mem_map + MAP_NR_DENSE(kaddr)) # define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) #endif -#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) +#ifdef CONFIG_VIRTUAL_MEM_MAP + struct page; + extern int ia64_page_valid (struct page *); +# define VALID_PAGE(page) (((page - mem_map) < max_mapnr) && ia64_page_valid(page)) +#else +# define VALID_PAGE(page) ((page - mem_map) < max_mapnr) +#endif typedef union ia64_va { struct { @@ -77,13 +88,47 @@ } ia64_va; /* - * Note: These macros depend on the fact that PAGE_OFFSET has all + * __pa(vaddr) - convert identity mapped reg 7 virtual address to a physical address. + * __va(paddr) - convert identity mapped reg 7 physical address to a virtual address. + * + * NOTE: These macros DO NOT work for kernel text/data addresses on all platforms + * since kernel text/static-data is not necessarily identity mapped. + * Use these macros ONLY for identify mapped addresses. + * + * NOTE: These macros depend on the fact that PAGE_OFFSET has all * region bits set to 1 and all other bits set to zero. They are * expressed in this way to ensure they result in a single "dep" - * instruction. + * instruction. The __pa & __va macros also work only for addresses that are + * identity mapped. Use the __tpa & __imva addresses for kernel text/static-data addresses. + * + * + * __imva(vaddr) - convert a kernel text/static-data virtual address to an identity mapped + * virtual address. + * __tpa(vaddr) - convert a kernel text/static-data virtual address to a physical address + * This macro works for all region 7 addresses, whether identity mapped or not. + * (performance may be slightly slower - only an issue in highly performance + * critical areas). + * + * Note: these macros work for all region 7 addresses. + * + * Note: turn on DEBUG_PA_VA to get additional debugging on these macros. */ + +#ifdef CONFIG_IA64_SGI_SN_DEBUG +extern unsigned long __pa_debug(long); +extern void * __va_debug(long); +extern unsigned long __tpa_debug(long); +extern unsigned long __imva_debug(long); +#define __pa(x) __pa_debug((long)(x)) +#define __va(x) __va_debug((long)(x)) +#define __tpa(x) __tpa_debug((long)(x)) +#define __imva(x) __imva_debug((long)(x)) +#else #define __pa(x) ({ia64_va _v; _v.l = (long) (x); _v.f.reg = 0; _v.l;}) #define __va(x) ({ia64_va _v; _v.l = (long) (x); _v.f.reg = -1; _v.p;}) +#define __tpa(x) ({ia64_va _v; asm("tpa %0=%1" : "=r"(_v.l) : "r"(x)); _v.l;}) +#define __imva(x) ((long)__va(__tpa(x))) +#endif #define REGION_NUMBER(x) ({ia64_va _v; _v.l = (long) (x); _v.f.reg;}) #define REGION_OFFSET(x) ({ia64_va _v; _v.l = (long) (x); _v.f.off;}) @@ -150,9 +195,17 @@ #define PAGE_OFFSET 0xe000000000000000 +#ifdef SGI_SN_EXECUTABLE_STACKS +extern int Vm_executable_stacks; +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | \ + (((current->thread.flags & IA64_THREAD_XSTACK) != 0 || \ + Vm_executable_stacks) \ + ? VM_EXEC : 0)) +#else #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | \ (((current->thread.flags & IA64_THREAD_XSTACK) != 0) \ ? VM_EXEC : 0)) - +#endif #endif /* _ASM_IA64_PAGE_H */ diff -Nur linux-2.4.19/include/asm-ia64/pal.h linux-2.4.19-sgi211r3/include/asm-ia64/pal.h --- linux-2.4.19/include/asm-ia64/pal.h Fri Dec 21 09:42:03 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/pal.h Mon Jan 13 15:32:26 2003 @@ -78,6 +78,8 @@ #ifndef __ASSEMBLY__ #include +#include +#include /* * Data types needed to pass information into PAL procedures and @@ -650,11 +652,43 @@ extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64); -#define PAL_CALL(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_static(a0, a1, a2, a3, 0) -#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_static(a0, a1, a2, a3, 1) -#define PAL_CALL_STK(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_stacked(a0, a1, a2, a3) -#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_static(a0, a1, a2, a3) -#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3) +extern void ia64_save_scratch_fpregs(struct ia64_fpreg *); +extern void ia64_load_scratch_fpregs(struct ia64_fpreg *); + +#define PAL_CALL(iprv,a0,a1,a2,a3) do { \ + struct ia64_fpreg fr[6]; \ + ia64_save_scratch_fpregs(fr); \ + iprv = ia64_pal_call_static(a0, a1, a2, a3, 0); \ + ia64_load_scratch_fpregs(fr); \ +} while (0) + +#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) do { \ + struct ia64_fpreg fr[6]; \ + ia64_save_scratch_fpregs(fr); \ + iprv = ia64_pal_call_static(a0, a1, a2, a3, 1); \ + ia64_load_scratch_fpregs(fr); \ +} while (0) + +#define PAL_CALL_STK(iprv,a0,a1,a2,a3) do { \ + struct ia64_fpreg fr[6]; \ + ia64_save_scratch_fpregs(fr); \ + iprv = ia64_pal_call_stacked(a0, a1, a2, a3); \ + ia64_load_scratch_fpregs(fr); \ +} while (0) + +#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) do { \ + struct ia64_fpreg fr[6]; \ + ia64_save_scratch_fpregs(fr); \ + iprv = ia64_pal_call_phys_static(a0, a1, a2, a3);\ + ia64_load_scratch_fpregs(fr); \ +} while (0) + +#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) do { \ + struct ia64_fpreg fr[6]; \ + ia64_save_scratch_fpregs(fr); \ + iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3); \ + ia64_load_scratch_fpregs(fr); \ +} while (0) typedef int (*ia64_pal_handler) (u64, ...); extern ia64_pal_handler ia64_pal; @@ -1016,10 +1050,10 @@ /* Return processor machine check information */ static inline s64 -ia64_pal_mc_error_info (u64 info_index, u64 type_index, u64 *size, u64 *error_info) +ia64_pal_mc_error_info (u64 info_index, u64 level_index, u64 type_index, u64 *size, u64 *error_info) { struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_MC_ERROR_INFO, info_index, type_index, 0); + PAL_CALL(iprv, PAL_MC_ERROR_INFO, info_index, level_index, type_index); if (size) *size = iprv.v0; if (error_info) diff -Nur linux-2.4.19/include/asm-ia64/pci.h linux-2.4.19-sgi211r3/include/asm-ia64/pci.h --- linux-2.4.19/include/asm-ia64/pci.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/pci.h Wed Oct 16 14:02:58 2002 @@ -19,6 +19,11 @@ #define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_MEM 0x10000000 +void pcibios_config_init(void); +struct pci_bus *pcibios_scan_root(void *acpi_handle, int segment, int bus); +extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); +extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); + struct pci_dev; static inline void @@ -45,6 +50,7 @@ #define pci_dma_sync_single platform_pci_dma_sync_single #define pci_dma_sync_sg platform_pci_dma_sync_sg #define sg_dma_address platform_pci_dma_address +#define pci_dma_supported platform_pci_dma_supported /* pci_unmap_{single,page} is not a nop, thus... */ #define DECLARE_PCI_UNMAP_ADDR(addr_name) dma_addr_t addr_name; @@ -54,17 +60,6 @@ #define pci_unmap_len(ptr, len_name) ((ptr)->len_name) #define pci_unmap_len_set(ptr, len_name, val) (((ptr)->len_name) = (val)) -/* - * Return whether the given PCI device DMA address mask can be supported properly. For - * example, if your device can only drive the low 24-bits during PCI bus mastering, then - * you would pass 0x00ffffff as the mask to this function. - */ -static inline int -pci_dma_supported (struct pci_dev *hwdev, u64 mask) -{ - return 1; -} - #define pci_map_page(dev,pg,off,size,dir) \ pci_map_single((dev), page_address(pg) + (off), (size), (dir)) #define pci_unmap_page(dev,dma_addr,size,dir) \ @@ -73,7 +68,7 @@ /* The ia64 platform always supports 64-bit addressing. */ #define pci_dac_dma_supported(pci_dev, mask) (1) -#define pci_dac_page_to_dma(dev,pg,off,dir) ((dma64_addr_t) page_to_bus(pg) + (off)) +#define pci_dac_page_to_dma(dev,pg,off,dir) ((dma_addr_t) page_to_bus(pg) + (off)) #define pci_dac_dma_to_page(dev,dma_addr) (virt_to_page(bus_to_virt(dma_addr))) #define pci_dac_dma_to_offset(dev,dma_addr) ((dma_addr) & ~PAGE_MASK) #define pci_dac_dma_sync_single(dev,dma_addr,len,dir) do { /* nothing */ } while (0) @@ -86,5 +81,18 @@ #define HAVE_PCI_MMAP extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); + +struct pci_controller { + void *acpi_handle; + void *iommu; + int segment; + + u64 mem_offset; + + void *platform_data; +}; + +#define PCI_CONTROLLER(dev) ((struct pci_controller *) dev->sysdata) +#define PCI_SEGMENT(dev) (PCI_CONTROLLER(dev)->segment) #endif /* _ASM_IA64_PCI_H */ diff -Nur linux-2.4.19/include/asm-ia64/perfmon.h linux-2.4.19-sgi211r3/include/asm-ia64/perfmon.h --- linux-2.4.19/include/asm-ia64/perfmon.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/perfmon.h Tue Aug 27 19:53:13 2002 @@ -23,6 +23,7 @@ #define PFM_GET_FEATURES 0x0c #define PFM_DEBUG 0x0d #define PFM_UNPROTECT_CONTEXT 0x0e +#define PFM_GET_PMC_RESET_VAL 0x0f /* @@ -171,6 +172,7 @@ extern int pfm_release_debug_registers(struct task_struct *); extern int pfm_cleanup_smpl_buf(struct task_struct *); extern void pfm_syst_wide_update_task(struct task_struct *, int); +extern void perfmon_init_percpu(void); #endif /* __KERNEL__ */ diff -Nur linux-2.4.19/include/asm-ia64/pgalloc.h linux-2.4.19-sgi211r3/include/asm-ia64/pgalloc.h --- linux-2.4.19/include/asm-ia64/pgalloc.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/pgalloc.h Fri Nov 15 07:43:49 2002 @@ -8,13 +8,14 @@ * This hopefully works with any (fixed) ia-64 page-size, as defined * in (currently 8192). * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2002 Hewlett-Packard Co * David Mosberger-Tang * Copyright (C) 2000, Goutham Rao */ #include +#include #include #include @@ -160,9 +161,12 @@ #ifdef CONFIG_SMP extern void smp_flush_tlb_all (void); + extern void smp_flush_tlb_all_nowait (void); # define flush_tlb_all() smp_flush_tlb_all() +# define flush_tlb_all_nowait() smp_flush_tlb_all_nowait() #else # define flush_tlb_all() __flush_tlb_all() +# define flush_tlb_all_nowait() __flush_tlb_all() #endif /* @@ -173,6 +177,11 @@ { if (mm) { mm->context = 0; +#ifdef CONFIG_SMP + if (atomic_read(&mm->mm_users) > 1) + flush_tlb_all(); + else +#endif if (mm == current->active_mm) { /* This is called, e.g., as a result of exec(). */ get_new_mmu_context(mm); @@ -194,6 +203,8 @@ #else if (vma->vm_mm == current->active_mm) asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(PAGE_SHIFT << 2) : "memory"); + else + vma->vm_mm->context = 0; #endif } @@ -204,30 +215,41 @@ static inline void flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end) { - if (rgn_index(start) != rgn_index(end)) - printk("flush_tlb_pgtables: can't flush across regions!!\n"); - flush_tlb_range(mm, ia64_thash(start), ia64_thash(end)); + if (unlikely(end - start >= 1024*1024*1024*1024UL + || rgn_index(start) != rgn_index(end - 1))) + /* + * This condition is very rare and normal applications shouldn't get + * here. No attempt has been made to optimize for this case. + */ + flush_tlb_all(); + else + flush_tlb_range(mm, ia64_thash(start), ia64_thash(end)); } /* - * Now for some cache flushing routines. This is the kind of stuff - * that can be very expensive, so try to avoid them whenever possible. + * Cache flushing routines. This is the kind of stuff that can be very expensive, so try + * to avoid them whenever possible. */ -/* Caches aren't brain-dead on the IA-64. */ #define flush_cache_all() do { } while (0) #define flush_cache_mm(mm) do { } while (0) #define flush_cache_range(mm, start, end) do { } while (0) #define flush_cache_page(vma, vmaddr) do { } while (0) #define flush_page_to_ram(page) do { } while (0) +#define flush_icache_page(vma,page) do { } while (0) + +#define flush_dcache_page(page) \ +do { \ + clear_bit(PG_arch_1, &(page)->flags); \ +} while (0) extern void flush_icache_range (unsigned long start, unsigned long end); -static inline void -flush_dcache_page (struct page *page) -{ - clear_bit(PG_arch_1, &page->flags); -} +#define flush_icache_user_range(vma, page, user_addr, len) \ +do { \ + unsigned long _addr = (unsigned long) page_address(page) + ((user_addr) & ~PAGE_MASK); \ + flush_icache_range(_addr, _addr + (len)); \ +} while (0) static inline void clear_user_page (void *addr, unsigned long vaddr, struct page *page) diff -Nur linux-2.4.19/include/asm-ia64/pgtable.h linux-2.4.19-sgi211r3/include/asm-ia64/pgtable.h --- linux-2.4.19/include/asm-ia64/pgtable.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/pgtable.h Fri Jan 10 09:03:47 2003 @@ -156,12 +156,6 @@ #define pte_ERROR(e) printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) -/* - * Some definitions to translate between mem_map, PTEs, and page - * addresses: - */ - - /* Quick test to see if ADDR is a (potentially) valid physical address. */ static inline long ia64_phys_addr_valid (unsigned long addr) @@ -204,12 +198,27 @@ #define VMALLOC_START (0xa000000000000000 + 3*PAGE_SIZE) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +#ifdef CONFIG_VIRTUAL_MEM_MAP +# define VMALLOC_END_INIT (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +# define VMALLOC_END vmalloc_end + extern unsigned long vmalloc_end; +#else +# define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +#endif /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ +#ifdef CONFIG_DISCONTIGMEM +#define mk_pte(page,pgprot) \ +({ \ + pte_t __pte; \ + \ + pte_val(__pte) = (unsigned long)page_address(page) - PAGE_OFFSET + pgprot_val(pgprot); \ + __pte; \ +}) +#else #define mk_pte(page,pgprot) \ ({ \ pte_t __pte; \ @@ -217,6 +226,7 @@ pte_val(__pte) = ((page - mem_map) << PAGE_SHIFT) | pgprot_val(pgprot); \ __pte; \ }) +#endif /* This takes a physical page address that is used by the remapping functions */ #define mk_pte_phys(physpage, pgprot) \ @@ -438,7 +448,8 @@ * for zero-mapped memory areas etc.. */ extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) +extern struct page *zero_page_memmap_ptr; +#define ZERO_PAGE(vaddr) (zero_page_memmap_ptr) /* We provide our own get_unmapped_area to cope with VA holes for userland */ #define HAVE_ARCH_UNMAPPED_AREA @@ -448,6 +459,20 @@ */ #define pgtable_cache_init() do { } while (0) +#ifdef CONFIG_VIRTUAL_MEM_MAP + +/* arch mem_map init routines are needed due to holes in a virtual mem_map */ +#define HAVE_ARCH_MEMMAP_INIT + +typedef unsigned long memmap_init_callback_t(struct page *start, + struct page *end, int zone, unsigned long start_paddr, int highmem); + +extern unsigned long arch_memmap_init (memmap_init_callback_t *callback, + struct page *start, struct page *end, int zone, + unsigned long start_paddr, int highmem); + +#endif /* CONFIG_VIRTUAL_MEM_MAP */ + # endif /* !__ASSEMBLY__ */ /* @@ -461,16 +486,17 @@ # define IA64_GRANULE_SHIFT _PAGE_SIZE_16M #endif #define IA64_GRANULE_SIZE (1 << IA64_GRANULE_SHIFT) + /* - * log2() of the page size we use to map the kernel image (IA64_TR_KERNEL): + * Page size used for Alternate D-TLB mapping for granule 0 on each node. */ -#define KERNEL_TR_PAGE_SHIFT _PAGE_SIZE_64M -#define KERNEL_TR_PAGE_SIZE (1 << KERNEL_TR_PAGE_SHIFT) -#define KERNEL_TR_PAGE_NUM ((KERNEL_START - PAGE_OFFSET) / KERNEL_TR_PAGE_SIZE) +#define IA64_GRANULE_0_SHIFT _PAGE_SIZE_4K +#define IA64_GRANULE_0_SIZE (1 << IA64_GRANULE_0_SHIFT) /* - * No page table caches to initialise + * log2() of the page size we use to map the kernel image (IA64_TR_KERNEL): */ -#define pgtable_cache_init() do { } while (0) +#define KERNEL_TR_PAGE_SHIFT _PAGE_SIZE_64M +#define KERNEL_TR_PAGE_SIZE (1 << KERNEL_TR_PAGE_SHIFT) #endif /* _ASM_IA64_PGTABLE_H */ diff -Nur linux-2.4.19/include/asm-ia64/processor.h linux-2.4.19-sgi211r3/include/asm-ia64/processor.h --- linux-2.4.19/include/asm-ia64/processor.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/processor.h Fri Feb 7 12:02:39 2003 @@ -18,7 +18,6 @@ #include #include -#include #include #define IA64_NUM_DBG_REGS 8 @@ -54,114 +53,6 @@ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ -/* Processor status register bits: */ -#define IA64_PSR_BE_BIT 1 -#define IA64_PSR_UP_BIT 2 -#define IA64_PSR_AC_BIT 3 -#define IA64_PSR_MFL_BIT 4 -#define IA64_PSR_MFH_BIT 5 -#define IA64_PSR_IC_BIT 13 -#define IA64_PSR_I_BIT 14 -#define IA64_PSR_PK_BIT 15 -#define IA64_PSR_DT_BIT 17 -#define IA64_PSR_DFL_BIT 18 -#define IA64_PSR_DFH_BIT 19 -#define IA64_PSR_SP_BIT 20 -#define IA64_PSR_PP_BIT 21 -#define IA64_PSR_DI_BIT 22 -#define IA64_PSR_SI_BIT 23 -#define IA64_PSR_DB_BIT 24 -#define IA64_PSR_LP_BIT 25 -#define IA64_PSR_TB_BIT 26 -#define IA64_PSR_RT_BIT 27 -/* The following are not affected by save_flags()/restore_flags(): */ -#define IA64_PSR_CPL0_BIT 32 -#define IA64_PSR_CPL1_BIT 33 -#define IA64_PSR_IS_BIT 34 -#define IA64_PSR_MC_BIT 35 -#define IA64_PSR_IT_BIT 36 -#define IA64_PSR_ID_BIT 37 -#define IA64_PSR_DA_BIT 38 -#define IA64_PSR_DD_BIT 39 -#define IA64_PSR_SS_BIT 40 -#define IA64_PSR_RI_BIT 41 -#define IA64_PSR_ED_BIT 43 -#define IA64_PSR_BN_BIT 44 - -#define IA64_PSR_BE (__IA64_UL(1) << IA64_PSR_BE_BIT) -#define IA64_PSR_UP (__IA64_UL(1) << IA64_PSR_UP_BIT) -#define IA64_PSR_AC (__IA64_UL(1) << IA64_PSR_AC_BIT) -#define IA64_PSR_MFL (__IA64_UL(1) << IA64_PSR_MFL_BIT) -#define IA64_PSR_MFH (__IA64_UL(1) << IA64_PSR_MFH_BIT) -#define IA64_PSR_IC (__IA64_UL(1) << IA64_PSR_IC_BIT) -#define IA64_PSR_I (__IA64_UL(1) << IA64_PSR_I_BIT) -#define IA64_PSR_PK (__IA64_UL(1) << IA64_PSR_PK_BIT) -#define IA64_PSR_DT (__IA64_UL(1) << IA64_PSR_DT_BIT) -#define IA64_PSR_DFL (__IA64_UL(1) << IA64_PSR_DFL_BIT) -#define IA64_PSR_DFH (__IA64_UL(1) << IA64_PSR_DFH_BIT) -#define IA64_PSR_SP (__IA64_UL(1) << IA64_PSR_SP_BIT) -#define IA64_PSR_PP (__IA64_UL(1) << IA64_PSR_PP_BIT) -#define IA64_PSR_DI (__IA64_UL(1) << IA64_PSR_DI_BIT) -#define IA64_PSR_SI (__IA64_UL(1) << IA64_PSR_SI_BIT) -#define IA64_PSR_DB (__IA64_UL(1) << IA64_PSR_DB_BIT) -#define IA64_PSR_LP (__IA64_UL(1) << IA64_PSR_LP_BIT) -#define IA64_PSR_TB (__IA64_UL(1) << IA64_PSR_TB_BIT) -#define IA64_PSR_RT (__IA64_UL(1) << IA64_PSR_RT_BIT) -/* The following are not affected by save_flags()/restore_flags(): */ -#define IA64_PSR_IS (__IA64_UL(1) << IA64_PSR_IS_BIT) -#define IA64_PSR_MC (__IA64_UL(1) << IA64_PSR_MC_BIT) -#define IA64_PSR_IT (__IA64_UL(1) << IA64_PSR_IT_BIT) -#define IA64_PSR_ID (__IA64_UL(1) << IA64_PSR_ID_BIT) -#define IA64_PSR_DA (__IA64_UL(1) << IA64_PSR_DA_BIT) -#define IA64_PSR_DD (__IA64_UL(1) << IA64_PSR_DD_BIT) -#define IA64_PSR_SS (__IA64_UL(1) << IA64_PSR_SS_BIT) -#define IA64_PSR_RI (__IA64_UL(3) << IA64_PSR_RI_BIT) -#define IA64_PSR_ED (__IA64_UL(1) << IA64_PSR_ED_BIT) -#define IA64_PSR_BN (__IA64_UL(1) << IA64_PSR_BN_BIT) - -/* User mask bits: */ -#define IA64_PSR_UM (IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH) - -/* Default Control Register */ -#define IA64_DCR_PP_BIT 0 /* privileged performance monitor default */ -#define IA64_DCR_BE_BIT 1 /* big-endian default */ -#define IA64_DCR_LC_BIT 2 /* ia32 lock-check enable */ -#define IA64_DCR_DM_BIT 8 /* defer TLB miss faults */ -#define IA64_DCR_DP_BIT 9 /* defer page-not-present faults */ -#define IA64_DCR_DK_BIT 10 /* defer key miss faults */ -#define IA64_DCR_DX_BIT 11 /* defer key permission faults */ -#define IA64_DCR_DR_BIT 12 /* defer access right faults */ -#define IA64_DCR_DA_BIT 13 /* defer access bit faults */ -#define IA64_DCR_DD_BIT 14 /* defer debug faults */ - -#define IA64_DCR_PP (__IA64_UL(1) << IA64_DCR_PP_BIT) -#define IA64_DCR_BE (__IA64_UL(1) << IA64_DCR_BE_BIT) -#define IA64_DCR_LC (__IA64_UL(1) << IA64_DCR_LC_BIT) -#define IA64_DCR_DM (__IA64_UL(1) << IA64_DCR_DM_BIT) -#define IA64_DCR_DP (__IA64_UL(1) << IA64_DCR_DP_BIT) -#define IA64_DCR_DK (__IA64_UL(1) << IA64_DCR_DK_BIT) -#define IA64_DCR_DX (__IA64_UL(1) << IA64_DCR_DX_BIT) -#define IA64_DCR_DR (__IA64_UL(1) << IA64_DCR_DR_BIT) -#define IA64_DCR_DA (__IA64_UL(1) << IA64_DCR_DA_BIT) -#define IA64_DCR_DD (__IA64_UL(1) << IA64_DCR_DD_BIT) - -/* Interrupt Status Register */ -#define IA64_ISR_X_BIT 32 /* execute access */ -#define IA64_ISR_W_BIT 33 /* write access */ -#define IA64_ISR_R_BIT 34 /* read access */ -#define IA64_ISR_NA_BIT 35 /* non-access */ -#define IA64_ISR_SP_BIT 36 /* speculative load exception */ -#define IA64_ISR_RS_BIT 37 /* mandatory register-stack exception */ -#define IA64_ISR_IR_BIT 38 /* invalid register frame exception */ - -#define IA64_ISR_X (__IA64_UL(1) << IA64_ISR_X_BIT) -#define IA64_ISR_W (__IA64_UL(1) << IA64_ISR_W_BIT) -#define IA64_ISR_R (__IA64_UL(1) << IA64_ISR_R_BIT) -#define IA64_ISR_NA (__IA64_UL(1) << IA64_ISR_NA_BIT) -#define IA64_ISR_SP (__IA64_UL(1) << IA64_ISR_SP_BIT) -#define IA64_ISR_RS (__IA64_UL(1) << IA64_ISR_RS_BIT) -#define IA64_ISR_IR (__IA64_UL(1) << IA64_ISR_IR_BIT) - #define IA64_THREAD_FPH_VALID (__IA64_UL(1) << 0) /* floating-point high state valid? */ #define IA64_THREAD_DBG_VALID (__IA64_UL(1) << 1) /* debug registers valid? */ #define IA64_THREAD_PM_VALID (__IA64_UL(1) << 2) /* performance registers valid? */ @@ -188,6 +79,7 @@ #ifndef __ASSEMBLY__ #include +#include #include #include @@ -195,6 +87,10 @@ #include #include #include +#ifdef CONFIG_NUMA +#include +#endif + /* like above but expressed as bitfields for more efficient access: */ struct ia64_psr { @@ -259,6 +155,7 @@ /* CPUID-derived information: */ __u64 ppn; __u64 features; + __u8 tlb_flush; /* flush TLB before next context switch if non-zero */ __u8 number; __u8 revision; __u8 model; @@ -281,19 +178,28 @@ __u64 ipi_count; __u64 prof_counter; __u64 prof_multiplier; +# ifdef CONFIG_PERFMON __u32 pfm_syst_wide; __u32 pfm_dcr_pp; - /* this is written to by *other* CPUs: */ - __u64 ipi_operation ____cacheline_aligned; +# endif + union { + /* + * This is written to by *other* CPUs, + * so isolate it in its own cacheline. + */ + __u64 operation; + char pad[SMP_CACHE_BYTES] ____cacheline_aligned; + } ipi; #endif #ifdef CONFIG_NUMA - void *node_directory; - int numa_node_id; + void* mmu_gathers; + ia64_node_data_t *node_data; + int cnodeid; struct cpuinfo_ia64 *cpu_data[NR_CPUS]; #endif /* Platform specific word. MUST BE LAST IN STRUCT */ __u64 platform_specific; -} __attribute__ ((aligned (PAGE_SIZE))) ; +} __attribute__ ((aligned (PAGE_SIZE))); /* * The "local" data pointer. It points to the per-CPU data of the currently executing @@ -313,7 +219,9 @@ */ #ifdef CONFIG_NUMA # define cpu_data(cpu) local_cpu_data->cpu_data[cpu] -# define numa_node_id() (local_cpu_data->numa_node_id) +# define local_cnodeid() (local_cpu_data->cnodeid) +# define numa_node_id() local_cnodeid() /* obsolete */ + extern int boot_get_local_cnodeid(void); /* early boot only */ #else extern struct cpuinfo_ia64 _cpu_data[NR_CPUS]; # define cpu_data(cpu) (&_cpu_data[cpu]) @@ -388,6 +296,7 @@ __u64 dbr[IA64_NUM_DBG_REGS]; __u64 ibr[IA64_NUM_DBG_REGS]; struct ia64_fpreg fph[96]; /* saved/loaded on demand */ + int last_fph_cpu; }; #define INIT_THREAD { \ @@ -405,12 +314,8 @@ #define start_thread(regs,new_ip,new_sp) do { \ set_fs(USER_DS); \ - ia64_psr(regs)->dfh = 1; /* disable fph */ \ - ia64_psr(regs)->mfh = 0; /* clear mfh */ \ - ia64_psr(regs)->cpl = 3; /* set user mode */ \ - ia64_psr(regs)->ri = 0; /* clear return slot number */ \ - ia64_psr(regs)->is = 0; /* IA-64 instruction set */ \ - ia64_psr(regs)->sp = 1; /* enforce secure perfmon */ \ + regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL | IA64_PSR_SP)) \ + & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS)); \ regs->cr_iip = new_ip; \ regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ regs->ar_rnat = 0; \ @@ -528,8 +433,6 @@ } } -#ifndef CONFIG_SMP - static inline struct task_struct * ia64_get_fpu_owner (void) { @@ -542,8 +445,6 @@ ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t); } -#endif /* !CONFIG_SMP */ - extern void __ia64_init_fpu (void); extern void __ia64_save_fpu (struct ia64_fpreg *fph); extern void __ia64_load_fpu (struct ia64_fpreg *fph); @@ -654,9 +555,22 @@ * interrupt enable bits. Don't trigger any mandatory RSE references while this bit is * off! */ -#define ia64_clear_ic(flags) \ - asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" \ - : "=r"(flags) :: "memory"); +static inline __u64 +ia64_clear_ic (void) +{ + __u64 psr; + asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" : "=r"(psr) :: "memory"); + return psr; +} + +/* + * Restore the psr. + */ +static inline void +ia64_set_psr (__u64 psr) +{ + asm volatile (";; mov psr.l=%0;; srlz.d" :: "r" (psr) : "memory"); +} /* * Insert a translation into an instruction and/or data translation @@ -1043,13 +957,13 @@ #define ARCH_HAS_SPINLOCK_PREFETCH #define PREFETCH_STRIDE 256 -extern inline void +static inline void prefetch (const void *x) { __asm__ __volatile__ ("lfetch [%0]" : : "r"(x)); } -extern inline void +static inline void prefetchw (const void *x) { __asm__ __volatile__ ("lfetch.excl [%0]" : : "r"(x)); diff -Nur linux-2.4.19/include/asm-ia64/sal.h linux-2.4.19-sgi211r3/include/asm-ia64/sal.h --- linux-2.4.19/include/asm-ia64/sal.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sal.h Mon Jan 13 15:32:26 2003 @@ -24,9 +24,9 @@ */ #include +#include #include -#include #include #include @@ -38,9 +38,19 @@ # define SAL_CALL(result,args...) do { \ unsigned long flags; \ + struct ia64_fpreg fr[6]; \ + ia64_save_scratch_fpregs(fr); \ spin_lock_irqsave(&sal_lock, flags); \ __SAL_CALL(result,args); \ spin_unlock_irqrestore(&sal_lock, flags); \ + ia64_load_scratch_fpregs(fr); \ +} while (0) + +# define SAL_CALL_NOLOCK(result,args...) do { \ + unsigned long flags; \ + local_irq_save(flags); \ + __SAL_CALL(result,args); \ + local_irq_restore(flags); \ } while (0) #define SAL_SET_VECTORS 0x01000000 @@ -241,32 +251,32 @@ /* SAL Error Record Section GUID Definitions */ #define SAL_PROC_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf1, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID ( 0xe429faf1, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_MEM_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf2, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf2, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_SEL_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf3, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf3, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_PCI_BUS_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf4, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf4, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf5, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf5, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_PCI_COMP_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf6, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf6, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_SPECIFIC_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf7, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf7, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_HOST_CTLR_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf8, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf8, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_BUS_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf9, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf9, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define MAX_CACHE_ERRORS 6 #define MAX_TLB_ERRORS 6 diff -Nur linux-2.4.19/include/asm-ia64/serial.h linux-2.4.19-sgi211r3/include/asm-ia64/serial.h --- linux-2.4.19/include/asm-ia64/serial.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/serial.h Wed Oct 16 14:02:58 2002 @@ -35,7 +35,9 @@ #else #define RS_TABLE_SIZE #endif - + +#define MCA_COM_FLAGS STD_COM_FLAGS + /* * The following define the access methods for the HUB6 card. All * access is through two ports for all 24 possible chips. The card is @@ -60,16 +62,16 @@ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ /* - * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot - * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in + * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot + * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in * include/linux/serial.h */ -#define HCDP_SERIAL_PORT_DEFNS \ +#define HCDP_SERIAL_PORT_DEFNS \ { 0, BASE_BAUD, -1, 0, STD_COM_FLAGS}, /* ttySx device in comments sucks. You add an entry - and you get to edit - boatloads of these + and you get to edit + boatloads of these comments. Not worth it */ @@ -131,12 +133,12 @@ #ifdef CONFIG_MCA #define MCA_SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS }, + { 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS }, #else #define MCA_SERIAL_PORT_DFNS #endif diff -Nur linux-2.4.19/include/asm-ia64/siginfo.h linux-2.4.19-sgi211r3/include/asm-ia64/siginfo.h --- linux-2.4.19/include/asm-ia64/siginfo.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/siginfo.h Wed Oct 16 14:02:58 2002 @@ -153,7 +153,8 @@ #define ILL_BADSTK (__SI_FAULT|8) /* internal stack error */ #define ILL_BADIADDR (__SI_FAULT|9) /* unimplemented instruction address */ #define __ILL_BREAK (__SI_FAULT|10) /* illegal break */ -#define NSIGILL 10 +#define __ILL_BNDMOD (__SI_FAULT|11) /* bundle-update (modification) in progress */ +#define NSIGILL 11 /* * SIGFPE si_codes diff -Nur linux-2.4.19/include/asm-ia64/smp.h linux-2.4.19-sgi211r3/include/asm-ia64/smp.h --- linux-2.4.19/include/asm-ia64/smp.h Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/smp.h Mon Oct 28 20:43:23 2002 @@ -27,7 +27,7 @@ #define SMP_IRQ_REDIRECTION (1 << 0) #define SMP_IPI_REDIRECTION (1 << 1) -#define smp_processor_id() (current->processor) +#define smp_processor_id() (current->cpu) extern struct smp_boot_data { int cpu_count; @@ -109,12 +109,6 @@ } #define NO_PROC_ID 0xffffffff /* no processor magic marker */ - -/* - * Extra overhead to move a task from one cpu to another (due to TLB and cache misses). - * Expressed in "negative nice value" units (larger number means higher priority/penalty). - */ -#define PROC_CHANGE_PENALTY 20 extern void __init init_smp_config (void); extern void smp_do_timer (struct pt_regs *regs); diff -Nur linux-2.4.19/include/asm-ia64/sn/addrs.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/addrs.h --- linux-2.4.19/include/asm-ia64/sn/addrs.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/addrs.h Mon Dec 30 14:16:56 2002 @@ -1,14 +1,11 @@ - /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1992-1999,2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1999,2001-2003 Silicon Graphics, Inc. All rights reserved. */ - #ifndef _ASM_IA64_SN_ADDRS_H #define _ASM_IA64_SN_ADDRS_H @@ -58,14 +55,14 @@ #define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) #endif -#define NODE_CAC_BASE(_n) (CAC_BASE + NODE_OFFSET(_n)) +#define NODE_CAC_BASE(_n) (CAC_BASE + NODE_OFFSET(_n)) #define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) #define NODE_IO_BASE(_n) (IO_BASE + NODE_OFFSET(_n)) #define NODE_MSPEC_BASE(_n) (MSPEC_BASE + NODE_OFFSET(_n)) #define NODE_UNCAC_BASE(_n) (UNCAC_BASE + NODE_OFFSET(_n)) #define TO_NODE(_n, _x) (NODE_OFFSET(_n) | ((_x) )) -#define TO_NODE_CAC(_n, _x) (NODE_CAC_BASE(_n) | ((_x) & TO_PHYS_MASK)) +#define TO_NODE_CAC(_n, _x) (NODE_CAC_BASE(_n) | ((_x) & TO_PHYS_MASK)) #define TO_NODE_UNCAC(_n, _x) (NODE_UNCAC_BASE(_n) | ((_x) & TO_PHYS_MASK)) #define TO_NODE_MSPEC(_n, _x) (NODE_MSPEC_BASE(_n) | ((_x) & TO_PHYS_MASK)) #define TO_NODE_HSPEC(_n, _x) (NODE_HSPEC_BASE(_n) | ((_x) & TO_PHYS_MASK)) @@ -227,8 +224,8 @@ #ifndef __ASSEMBLY__ -#define HUB_L(_a) *(_a) -#define HUB_S(_a, _d) *(_a) = (_d) +#define HUB_L(_a) (*((volatile typeof(*_a) *)_a)) +#define HUB_S(_a, _d) (*((volatile typeof(*_a) *)_a) = (_d)) #define LOCAL_HUB_L(_r) HUB_L(LOCAL_HUB_ADDR(_r)) #define LOCAL_HUB_S(_r, _d) HUB_S(LOCAL_HUB_ADDR(_r), (_d)) @@ -326,7 +323,7 @@ #define GDA_SIZE(nasid) KLD_GDA(nasid)->size #define NODE_OFFSET_TO_K0(_nasid, _off) \ - (PAGE_OFFSET | NODE_OFFSET(_nasid) | (_off)) + (CACHEABLE_MEM_SPACE | NODE_OFFSET(_nasid) | (_off)) #endif /* __ASSEMBLY__ */ diff -Nur linux-2.4.19/include/asm-ia64/sn/alenlist.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/alenlist.h --- linux-2.4.19/include/asm-ia64/sn/alenlist.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/alenlist.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_ALENLIST_H #define _ASM_IA64_SN_ALENLIST_H diff -Nur linux-2.4.19/include/asm-ia64/sn/arc/hinv.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/arc/hinv.h --- linux-2.4.19/include/asm-ia64/sn/arc/hinv.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/arc/hinv.h Mon Dec 30 14:16:56 2002 @@ -1,12 +1,10 @@ /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ - /* $Id$ * diff -Nur linux-2.4.19/include/asm-ia64/sn/arc/types.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/arc/types.h --- linux-2.4.19/include/asm-ia64/sn/arc/types.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/arc/types.h Mon Dec 30 14:16:56 2002 @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * + * Copyright (c) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright 1999 Ralf Baechle (ralf@gnu.org) - * Copyright 1999,2001 Silicon Graphics, Inc. */ #ifndef _ASM_SN_ARC_TYPES_H #define _ASM_SN_ARC_TYPES_H diff -Nur linux-2.4.19/include/asm-ia64/sn/arch.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/arch.h --- linux-2.4.19/include/asm-ia64/sn/arch.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/arch.h Mon Dec 30 14:16:56 2002 @@ -6,7 +6,7 @@ * * SGI specific setup. * - * Copyright (C) 1995-1997,1999,2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1995-1997,1999,2001-2003 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) */ #ifndef _ASM_IA64_SN_ARCH_H @@ -43,6 +43,7 @@ #define INVALID_NASID ((nasid_t)-1) #define INVALID_CNODEID ((cnodeid_t)-1) #define INVALID_PNODEID ((pnodeid_t)-1) +#define INVALID_SLAB (slabid_t)-1 #define INVALID_MODULE ((moduleid_t)-1) #define INVALID_PARTID ((partid_t)-1) diff -Nur linux-2.4.19/include/asm-ia64/sn/ate_utils.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ate_utils.h --- linux-2.4.19/include/asm-ia64/sn/ate_utils.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ate_utils.h Mon Dec 30 14:16:56 2002 @@ -7,7 +7,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* diff -Nur linux-2.4.19/include/asm-ia64/sn/bte.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/bte.h --- linux-2.4.19/include/asm-ia64/sn/bte.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/bte.h Tue Jan 14 15:58:22 2003 @@ -1,23 +1,49 @@ /* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ + #ifndef _ASM_IA64_SN_BTE_H #define _ASM_IA64_SN_BTE_H #ident "$Revision: 1.1 $" +#include #include #include #include - -#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) /* Mask to retrieve - * the offset into this - * cache line.*/ +#include +#include /* BTE status register only supports 16 bits for length field */ #define BTE_LEN_BITS (16) @@ -57,10 +83,128 @@ #define BTE_NORMAL BTE_NOTIFY #define BTE_ZERO_FILL (BTE_NOTIFY | IBCT_ZFIL_MODE) +#define BTE_IS_BUSY(_x) ((_x) & IBLS_BUSY) +#define BTE_ERROR(_x) ((_x) & IBLS_ERROR) +#define BTE_BUSY_OR_ERROR(_x) ((_x) & (IBLS_BUSY | IBLS_ERROR)) +#define BTE_BUSY_NO_ERROR(_x) ((BTE_IS_BUSY(_x)) && !BTE_ERROR(_x)) +#define BTE_LENGTH(_x) ((_x) & IBLS_LENGTH_MASK) +#define BTE_LENGTH_ZERO(_x) (!((_x) & IBLS_LENGTH_MASK)) + /* Use a reserved bit to let the caller specify a wait for any BTE */ #define BTE_WACQUIRE (0x4000) /* + * BTE_LOCKING support - When CONFIG_IA64_SGI_BTE_LOCKING is + * not defined, the bte_copy code supports one bte per cpu in + * synchronous mode. Even if bte_copy is called with a + * notify address, the bte will spin and wait for the transfer + * to complete. By defining the following, spin_locks and + * busy checks are placed around the initiation of a BTE + * transfer and multiple bte's per cpu are supported. + */ + +#if 0 +#define CONFIG_IA64_SGI_BTE_LOCKING 1 +#endif + +/* + * Handle locking of the bte interfaces. + * + * All transfers spinlock the interface before setting up the SHUB + * registers. Sync transfers hold the lock until all processing is + * complete. Async transfers release the lock as soon as the transfer + * is initiated. + * + * To determine if an interface is available, we must check both the + * busy bit and the spinlock for that interface. + */ +#define BTE_LOCK_IF_AVAIL(_x) (\ + (*pda.cpu_bte_if[_x]->most_rcnt_na & IBLS_BUSY) && \ + (!(spin_trylock(&(pda.cpu_bte_if[_x]->spinlock)))) \ + ) + +/* + * Some macros to simplify reading. + * Start with macros to locate the BTE control registers. + */ +#define BTEREG_LNSTAT_ADDR ((u64 *)(bte->bte_base_addr)) +#define BTEREG_SRC_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_SRC)) +#define BTEREG_DEST_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_DEST)) +#define BTEREG_CTRL_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_CTRL)) +#define BTEREG_NOTIF_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_NOTIFY)) + +/* Some macros to force the IBCT0 value valid. */ + +#define BTE_VALID_MODES BTE_NOTIFY +#define BTE_VLD_MODE(x) (x & BTE_VALID_MODES) + +// #define BTE_DEBUG +// // #define BTE_DEBUG_VERBOSE +// // #define BTE_TIME + +#ifdef BTE_DEBUG +# define BTE_PRINTK(x) printk x /* Terse */ +# ifdef BTE_DEBUG_VERBOSE +# define BTE_PRINTKV(x) printk x /* Verbose */ +# else +# define BTE_PRINTKV(x) +# endif /* BTE_DEBUG_VERBOSE */ +#else +# define BTE_PRINTK(x) +# define BTE_PRINTKV(x) +#endif /* BTE_DEBUG */ + +#define BTE_IDEAL_TMO(x) (jiffies + \ + (HZ / BTE_MAXT_LINES_PER_SECOND * x)) + +#ifdef BTE_TIME + volatile extern u64 bte_setup_time; + volatile extern u64 bte_transfer_time; + volatile extern u64 bte_tear_down_time; + volatile extern u64 bte_execute_time; + +#define BTE_TIME_DECLARE() \ + u64 btcp_strt_tm = 0; \ + u64 btcp_cplt_tm = 0; \ + u64 xfr_strt_tm = 0; \ + u64 xfr_cplt_tm = 0; \ + +#define BTE_TIME_START() \ + btcp_strt_tm = xfr_strt_tm = xfr_cplt_tm = ia64_get_itc(); + +#define BTE_TIME_XFR_START() \ + xfr_strt_tm = ia64_get_itc(); + +#define BTE_TIME_XFR_STOP() \ + xfr_cplt_tm = ia64_get_itc(); + +#define BTE_TIME_STOP() \ + btcp_cplt_tm = ia64_get_itc(); \ + bte_setup_time = xfr_strt_tm - btcp_strt_tm; \ + bte_transfer_time = xfr_cplt_tm - xfr_strt_tm; \ + bte_tear_down_time = btcp_cplt_tm - xfr_cplt_tm; \ + bte_execute_time = btcp_cplt_tm - btcp_strt_tm; \ + +#else /* BTE_TIME */ +#define BTE_TIME_DECLARE() +#define BTE_TIME_START() +#define BTE_TIME_XFR_START() +#define BTE_TIME_XFR_STOP() +#define BTE_TIME_STOP() +#endif /* BTE_TIME */ + + +/* + * BTE error recovery structure. + * There is one structure per node. All of the BTE interfaces point + * at this structure. Cleaning up the BTE will effect all the BTE + * interfaces on the node, so this is used to synchronize the clean up. + */ +typedef struct bte_recover_s { + spinlock_t bte_recover_lock; /* One recovery at a time */ +} bte_recover_t; + +/* * Structure defining a bte. An instance of this * structure is created in the nodepda for each * bte on that node (as defined by BTES_PER_NODE) @@ -68,25 +212,105 @@ * to work with a BTE. */ typedef struct bteinfo_s { + u64 volatile crb_flush ____cacheline_aligned; u64 volatile notify ____cacheline_aligned; char *bte_base_addr ____cacheline_aligned; spinlock_t spinlock; - u64 idealTransferTimeout; - u64 idealTransferTimeoutReached; - u64 mostRecentSrc; - u64 mostRecentDest; - u64 mostRecentLen; - u64 mostRecentMode; - u64 volatile *mostRecentNotification; - void *bteTestBuf; + u64 ideal_xfr_tmo; /* Time out */ + u64 ideal_xfr_tmo_cnt; + cnodeid_t bte_cnode; /* cnode */ + int bte_error_count;/* Number of errors encountered */ + int bte_num; /* 0 --> BTE0, 1 --> BTE1 */ + bte_recover_t *bte_recover; /* BTE recovery info, one stuct per */ + /* node, both bteinfo_t point at it.*/ + short bh_error; /* error (crb "ecode") */ + void *npda; /* pointer to my node pda. */ + int bte_timeout; /* BTE timeout value */ + /* u64 most_recent_src; + * u64 most_recent_dest; + * u64 most_recent_len; + * u64 most_recent_mode; */ + u64 volatile *most_rcnt_na; + void *bte_test_buf; } bteinfo_t; +/* + * BTE Locking mechanism. The spinlock is only held for the duration of the + * transfer setup, hence we're only splhi for that time as well. + */ + +#define BTE_TRYLOCK(_b) spin_trylock(&(_b)->spinlock) +#define BTE_UNLOCK(_b) spin_unlock(&(_b)->spinlock) +#define BTE_LOCK(_b) spin_lock_irqsave(&(_b)->spinlock) + +/* + * BTE recovery Locking mechanism. The spinlock is only held for the + * duration of the recovery, hence we're only splhi for that time as well. + */ +#define BTE_RECOVER_TRYLOCK(_b) \ + spin_trylock(&(_b)->bte_recover->bte_recover_lock) +#define BTE_RECOVER_UNLOCK(_b) \ + spin_unlock(&(_b)->bte_recover->bte_recover_lock) +#define BTE_RECOVER_LOCK(_b) \ + spin_lock(&(_b)->bte_recover->bte_recover_lock) + + /* Possible results from bte_copy and bte_unaligned_copy */ typedef enum { BTE_SUCCESS, /* 0 is success */ BTEFAIL_NOTAVAIL, /* BTE not available */ + BTEFAIL_POISON, /* poison page */ + BTEFAIL_PROT, /* Protection violation */ + BTEFAIL_ACCESS, /* access error */ + BTEFAIL_TOUT, /* Time out */ BTEFAIL_ERROR, /* Generic error */ BTEFAIL_DIR /* Diretory error */ } bte_result_t; + +void bte_reset_nasid(nasid_t); + +#define NODE_BTE_INFO(_nodepda, id) (bteinfo_t *)&((_nodepda)->bte_if[id]) +#ifdef CONFIG_IA64_SGI_SN2 +#define BTE_LOAD(_b, _x) \ + HUB_L((volatile shubreg_t *)(_b + (_x))) +#define BTE_STORE(_b, _x, _y) \ + HUB_S((volatile shubreg_t *)(_b + (_x)), (_y)) +#else +#define BTE_LOAD(_b, _x) \ + HUB_L((volatile u64 *)(_b + (_x))) +#define BTE_STORE(_b, _x, _y) \ + HUB_S((volatile u64 *)(_b + (_x)), (_y)) +#endif + +/* + * Function prototypes (functions defined in bte.c, used elsewhere) + */ +int bte_get_all_interfaces(bteinfo_t *); +void bte_free_interfaces(bteinfo_t *, int); +bte_result_t bte_copy(u64, u64, u64, u64, void *); + + +bte_result_t bte_error_handler(bteinfo_t *); + + +/* + * Define the bte_unaligned_copy as an extern. + */ +extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64); + +/* + * The following is the prefered way of calling bte_unaligned_copy + * If the copy is fully cache line aligned, then bte_copy is + * used instead. Since bte_copy is inlined, this saves a call + * stack. NOTE: bte_copy is called synchronously and does block + * until the transfer is complete. In order to get the asynch + * version of bte_copy, you must perform this check yourself. + */ +#define BTE_UNALIGNED_COPY(src, dest, len, mode) \ + (((len & L1_CACHE_MASK) || (src & L1_CACHE_MASK) || \ + (dest & L1_CACHE_MASK)) ? \ + bte_unaligned_copy(src, dest, len, mode) : \ + bte_copy(src, dest, len, mode, NULL)) + #endif /* _ASM_IA64_SN_BTE_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/bte_copy.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/bte_copy.h --- linux-2.4.19/include/asm-ia64/sn/bte_copy.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/bte_copy.h Tue Jan 14 10:15:52 2003 @@ -1,9 +1,35 @@ /* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ #ifndef _ASM_IA64_SN_BTE_COPY_H @@ -11,21 +37,40 @@ #ident "$Revision: 1.1 $" +#include #include #include #include #include /* - * BTE_LOCKING support - Undefining the following line will - * adapt the bte_copy code to support one bte per cpu in + * BTE_LOCKING support - When CONFIG_IA64_SGI_BTE_LOCKING is + * not defined, the bte_copy code supports one bte per cpu in * synchronous mode. Even if bte_copy is called with a * notify address, the bte will spin and wait for the transfer * to complete. By defining the following, spin_locks and * busy checks are placed around the initiation of a BTE * transfer and multiple bte's per cpu are supported. */ +#if 0 #define CONFIG_IA64_SGI_BTE_LOCKING 1 +#endif + +/* + * Handle locking of the bte interfaces. + * + * All transfers spinlock the interface before setting up the SHUB + * registers. Sync transfers hold the lock until all processing is + * complete. Async transfers release the lock as soon as the transfer + * is initiated. + * + * To determine if an interface is available, we must check both the + * busy bit and the spinlock for that interface. + */ +#define BTE_LOCK_IF_AVAIL(_x) (\ + (*pda.cpu_bte_if[_x]->most_rcnt_na & IBLS_BUSY) && \ + (!(spin_trylock(&(pda.cpu_bte_if[_x]->spinlock)))) \ + ) /* * Some macros to simplify reading. @@ -33,263 +78,74 @@ * Start with macros to locate the BTE control registers. */ -#define BTEREG_LNSTAT_ADDR (bte->bte_base_addr) -#define BTEREG_SOURCE_ADDR (bte->bte_base_addr + IIO_IBSA0 - IIO_IBLS0) -#define BTEREG_DEST_ADDR (bte->bte_base_addr + IIO_IBDA0 - IIO_IBLS0) -#define BTEREG_CTRL_ADDR ((volatile char *)bte->bte_base_addr + IIO_IBCT0 - IIO_IBLS0) -#define BTEREG_NOTIF_ADDR (bte->bte_base_addr + IIO_IBNA0 - IIO_IBLS0) +#define BTEREG_LNSTAT_ADDR ((u64 *)(bte->bte_base_addr)) +#define BTEREG_SRC_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_SRC)) +#define BTEREG_DEST_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_DEST)) +#define BTEREG_CTRL_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_CTRL)) +#define BTEREG_NOTIF_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_NOTIFY)) /* Some macros to force the IBCT0 value valid. */ #define BTE_VALID_MODES BTE_NOTIFY #define BTE_VLD_MODE(x) (x & BTE_VALID_MODES) -// #define DEBUG_BTE -// #define DEBUG_BTE_VERBOSE -// #define DEBUG_TIME_BTE - -#ifdef DEBUG_BTE -# define DPRINTK(x) printk x // Terse -# ifdef DEBUG_BTE_VERBOSE -# define DPRINTKV(x) printk x // Verbose +// #define BTE_DEBUG +// #define BTE_DEBUG_VERBOSE +// #define BTE_TIME + +#ifdef BTE_DEBUG +# define BTE_PRINTK(x) printk x /* Terse */ +# ifdef BTE_DEBUG_VERBOSE +# define BTE_PRINTKV(x) printk x /* Verbose */ # else -# define DPRINTKV(x) -# endif -#else -# define DPRINTK(x) -# define DPRINTKV(x) -#endif - -#ifdef DEBUG_TIME_BTE -extern u64 BteSetupTime; -extern u64 BteTransferTime; -extern u64 BteTeardownTime; -extern u64 BteExecuteTime; -#endif - -/* - * bte_copy(src, dest, len, mode, notification) - * - * use the block transfer engine to move kernel - * memory from src to dest using the assigned mode. - * - * Paramaters: - * src - physical address of the transfer source. - * dest - physical address of the transfer destination. - * len - number of bytes to transfer from source to dest. - * mode - hardware defined. See reference information - * for IBCT0/1 in the SHUB Programmers Reference - * notification - kernel virtual address of the notification cache - * line. If NULL, the default is used and - * the bte_copy is synchronous. - * - * NOTE: This function requires src, dest, and len to - * be cache line aligned. - */ -extern __inline__ bte_result_t -bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) -{ -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - int bte_to_use; -#endif - -#ifdef DEBUG_TIME_BTE - u64 invokeTime = 0; - u64 completeTime = 0; - u64 xferStartTime = 0; - u64 xferCompleteTime = 0; -#endif - u64 transferSize; - bteinfo_t *bte; - -#ifdef DEBUG_TIME_BTE - invokeTime = ia64_get_itc(); -#endif - - DPRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", - src, dest, len, mode, notification)); - - if (len == 0) { - return (BTE_SUCCESS); - } - - ASSERT(!((len & L1_CACHE_MASK) || - (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK))); - - ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)); - -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - { - bte_to_use = 0; - - /* Attempt to lock one of the BTE interfaces */ - while ((*pda.cpubte[bte_to_use]-> - mostRecentNotification & IBLS_BUSY) - && - (!(spin_trylock - (&(pda.cpubte[bte_to_use]->spinlock)))) - && (bte_to_use < BTES_PER_NODE)) { - bte_to_use++; - } - - if ((bte_to_use >= BTES_PER_NODE) && - !(mode & BTE_WACQUIRE)) { - return (BTEFAIL_NOTAVAIL); - } - - /* Wait until a bte is available. */ - } - while (bte_to_use >= BTES_PER_NODE); - - bte = pda.cpubte[bte_to_use]; - DPRINTKV(("Got a lock on bte %d\n", bte_to_use)); +# define BTE_PRINTKV(x) +# endif /* BTE_DEBUG_VERBOSE */ #else - /* Assuming one BTE per CPU. */ - bte = pda.cpubte[0]; -#endif +# define BTE_PRINTK(x) +# define BTE_PRINTKV(x) +#endif /* BTE_DEBUG */ + +#define BTE_IDEAL_TMO(x) (jiffies + \ + (HZ / BTE_MAXT_LINES_PER_SECOND * x)) + +#ifdef BTE_TIME +volatile extern u64 bte_setup_time; +volatile extern u64 bte_transfer_time; +volatile extern u64 bte_tear_down_time; +volatile extern u64 bte_execute_time; + +#define BTE_TIME_DECLARE() \ + u64 btcp_strt_tm = 0; \ + u64 btcp_cplt_tm = 0; \ + u64 xfr_strt_tm = 0; \ + u64 xfr_cplt_tm = 0; \ + +#define BTE_TIME_START() \ + btcp_strt_tm = xfr_strt_tm = xfr_cplt_tm = ia64_get_itc(); + +#define BTE_TIME_XFR_START() \ + xfr_strt_tm = ia64_get_itc(); + +#define BTE_TIME_XFR_STOP() \ + xfr_cplt_tm = ia64_get_itc(); + +#define BTE_TIME_STOP() \ + btcp_cplt_tm = ia64_get_itc(); \ + bte_setup_time = xfr_strt_tm - btcp_strt_tm; \ + bte_transfer_time = xfr_cplt_tm - xfr_strt_tm; \ + bte_tear_down_time = btcp_cplt_tm - xfr_cplt_tm; \ + bte_execute_time = btcp_cplt_tm - btcp_strt_tm; \ + +#else /* BTE_TIME */ +#define BTE_TIME_DECLARE() +#define BTE_TIME_START() +#define BTE_TIME_XFR_START() +#define BTE_TIME_XFR_STOP() +#define BTE_TIME_STOP() +#endif /* BTE_TIME */ - /* - * The following are removed for optimization but is - * available in the event that the SHUB exhibits - * notification problems similar to the hub, bedrock et al. - * - * bte->mostRecentSrc = src; - * bte->mostRecentDest = dest; - * bte->mostRecentLen = len; - * bte->mostRecentMode = mode; - */ - if (notification == NULL) { - /* User does not want to be notified. */ - bte->mostRecentNotification = &bte->notify; - } else { - bte->mostRecentNotification = notification; - } - - /* Calculate the number of cache lines to transfer. */ - transferSize = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); - - DPRINTKV(("Calculated transfer size of %d cache lines\n", - transferSize)); - - /* Initialize the notification to a known value. */ - *bte->mostRecentNotification = -1L; - - - DPRINTKV(("Before, status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->mostRecentNotification)); - - /* Set the status reg busy bit and transfer length */ - DPRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)\n", - BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize)); - HUB_S(BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize); - - - DPRINTKV(("After setting status, status is 0x%lx and notify is 0x%lx\n", HUB_L(BTEREG_LNSTAT_ADDR), *bte->mostRecentNotification)); - - /* Set the source and destination registers */ - DPRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_SOURCE_ADDR, - src)); - HUB_S(BTEREG_SOURCE_ADDR, src); - DPRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_DEST_ADDR, dest)); - HUB_S(BTEREG_DEST_ADDR, dest); - - - /* Set the notification register */ - DPRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_NOTIF_ADDR, - __pa(bte->mostRecentNotification))); - HUB_S(BTEREG_NOTIF_ADDR, (__pa(bte->mostRecentNotification))); - - - DPRINTKV(("Set Notify, status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->mostRecentNotification)); - - /* Initiate the transfer */ - DPRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)\n", BTEREG_CTRL_ADDR, mode)); -#ifdef DEBUG_TIME_BTE - xferStartTime = ia64_get_itc(); -#endif - HUB_S(BTEREG_CTRL_ADDR, BTE_VLD_MODE(mode)); - - DPRINTKV(("Initiated, status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->mostRecentNotification)); - - // >>> Temporarily work around not getting a notification - // from medusa. - // *bte->mostRecentNotification = HUB_L(bte->bte_base_addr); - - if (notification == NULL) { - /* - * Calculate our timeout - * - * What are we doing here? We are trying to determine - * the fastest time the BTE could have transfered our - * block of data. By takine the clock frequency (ticks/sec) - * divided by the BTE MaxT Transfer Rate (lines/sec) - * times the transfer size (lines), we get a tick - * offset from current time that the transfer should - * complete. - * - * Why do this? We are watching for a notification - * failure from the BTE. This behaviour has been - * seen in the SN0 and SN1 hardware on rare circumstances - * and is expected in SN2. By checking at the - * ideal transfer timeout, we minimize our time - * delay from hardware completing our request and - * our detecting the failure. - */ - bte->idealTransferTimeout = jiffies + - (HZ / BTE_MAXT_LINES_PER_SECOND * transferSize); - - while ((IBLS_BUSY & bte->notify)) { - /* - * Notification Workaround: When the max - * theoretical time has elapsed, read the hub - * status register into the notification area. - * This fakes the shub performing the copy. - */ - if (jiffies > bte->idealTransferTimeout) { - bte->notify = HUB_L(bte->bte_base_addr); - bte->idealTransferTimeoutReached++; - bte->idealTransferTimeout = jiffies + - (HZ / BTE_MAXT_LINES_PER_SECOND * - (bte->notify & BTE_LEN_MASK)); - } - } -#ifdef DEBUG_TIME_BTE - xferCompleteTime = ia64_get_itc(); -#endif - if (bte->notify & IBLS_ERROR) { - /* >>> Need to do real error checking. */ - transferSize = 0; - -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_unlock(&(bte->spinlock)); -#endif - return (BTEFAIL_ERROR); - } - - } -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_unlock(&(bte->spinlock)); -#endif -#ifdef DEBUG_TIME_BTE - completeTime = ia64_get_itc(); - - BteSetupTime = xferStartTime - invokeTime; - BteTransferTime = xferCompleteTime - xferStartTime; - BteTeardownTime = completeTime - xferCompleteTime; - BteExecuteTime = completeTime - invokeTime; -#endif - return (BTE_SUCCESS); -} - -/* - * Define the bte_unaligned_copy as an extern. - */ -extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64, char *); +extern bte_result_t bte_copy(u64, u64, u64, u64, void *); +extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64); /* * The following is the prefered way of calling bte_unaligned_copy @@ -299,13 +155,10 @@ * until the transfer is complete. In order to get the asynch * version of bte_copy, you must perform this check yourself. */ -#define BTE_UNALIGNED_COPY(src, dest, len, mode, bteBlock) \ - if ((len & L1_CACHE_MASK) || \ - (src & L1_CACHE_MASK) || \ - (dest & L1_CACHE_MASK)) { \ - bte_unaligned_copy (src, dest, len, mode, bteBlock); \ - } else { \ - bte_copy(src, dest, len, mode, NULL); \ - } +#define BTE_UNALIGNED_COPY(src, dest, len, mode) \ + (((len & L1_CACHE_MASK) || (src & L1_CACHE_MASK) || \ + (dest & L1_CACHE_MASK)) ? \ + bte_unaligned_copy(src, dest, len, mode) : \ + bte_copy(src, dest, len, mode, NULL)) -#endif /* _ASM_IA64_SN_BTE_COPY_H */ +#endif /* _ASM_IA64_SN_BTE_COPY_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/cdl.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/cdl.h --- linux-2.4.19/include/asm-ia64/sn/cdl.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/cdl.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_CDL_H #define _ASM_IA64_SN_CDL_H diff -Nur linux-2.4.19/include/asm-ia64/sn/clksupport.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/clksupport.h --- linux-2.4.19/include/asm-ia64/sn/clksupport.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/clksupport.h Fri Feb 14 13:25:16 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* @@ -29,22 +29,30 @@ #include typedef long clkreg_t; -extern long sn_rtc_cycles_per_second; +extern unsigned long sn_rtc_cycles_per_second; #if defined(CONFIG_IA64_SGI_SN1) #include #include + +extern nasid_t master_nasid; + +#define RTC_MASK (0x007fffffffffffff) /* clocks are not synchronized yet on SN1 - used node 0 (problem if no NASID 0) */ -#define RTC_COUNTER_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_COUNTER)) -#define RTC_COMPARE_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_COMPARE_A)) -#define RTC_COMPARE_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_COMPARE_B)) -#define RTC_INT_PENDING_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_PEND_A)) -#define RTC_INT_PENDING_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_PEND_B)) -#define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_EN_A)) -#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_EN_B)) -#else +#define RTC_COUNTER_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COUNTER)) +#define RTC_COMPARE_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_A)) +#define RTC_COMPARE_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_B)) +#define RTC_INT_PENDING_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_A)) +#define RTC_INT_PENDING_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_B)) +#define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_A)) +#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_B)) +#else /* !CONFIG_IA64_SGI_SN1 */ +#include +#include +#include #include +#define RTC_MASK (SH_RTC_MASK) #define RTC_COUNTER_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) @@ -52,7 +60,7 @@ #define RTC_INT_PENDING_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) -#endif +#endif /* CONFIG_IA64_SGI_SN1 */ #define GET_RTC_COUNTER() (*RTC_COUNTER_ADDR) diff -Nur linux-2.4.19/include/asm-ia64/sn/dmamap.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/dmamap.h --- linux-2.4.19/include/asm-ia64/sn/dmamap.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/dmamap.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_DMAMAP_H #define _ASM_IA64_SN_DMAMAP_H diff -Nur linux-2.4.19/include/asm-ia64/sn/driver.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/driver.h --- linux-2.4.19/include/asm-ia64/sn/driver.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/driver.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_DRIVER_H #define _ASM_IA64_SN_DRIVER_H diff -Nur linux-2.4.19/include/asm-ia64/sn/eeprom.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/eeprom.h --- linux-2.4.19/include/asm-ia64/sn/eeprom.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/eeprom.h Mon Dec 30 14:16:56 2002 @@ -6,11 +6,12 @@ * * Public interface for reading Atmel EEPROMs via L1 system controllers * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_EEPROM_H #define _ASM_IA64_SN_EEPROM_H +#include #include #include #include @@ -291,6 +292,8 @@ /* functions & macros for obtaining "NIC-like" strings from EEPROMs */ +#ifdef CONFIG_IA64_SGI_SN1 + int eeprom_str( char *nic_str, nasid_t nasid, int component ); int vector_eeprom_str( char *nic_str, nasid_t nasid, int component, net_vec_t path ); @@ -300,6 +303,7 @@ #define RBRICK_EEPROM_STR(s,n,p) vector_eeprom_str((s),(n),R_BRICK,p) #define VECTOR_EEPROM_STR(s,n,p) vector_eeprom_str((s),(n),VECTOR,p) +#endif /* CONFIG_IA64_SGI_SN1 */ /* functions for obtaining formatted records from EEPROMs @@ -313,13 +317,6 @@ net_vec_t path, int component ); -/* functions providing unique id's for duplonet and i/o discovery - */ - -int cbrick_uid_get( nasid_t nasid, uint64_t *uid ); -int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ); -int iobrick_uid_get( nasid_t nasid, uint64_t *uid ); - /* retrieve the ethernet MAC address for an I-brick */ @@ -383,9 +380,5 @@ ( IS_IOBRICK((r)) ? eeprom_vertex_info_set \ ( IO_BRICK, NASID_GET((r)), (v), 0 ) \ : nic_bridge_vertex_info((v), (r)) ) - -#define HUB_UID_GET(n,v,p) cbrick_uid_get((n),(p)) -#define ROUTER_UID_GET(d,p) rbrick_uid_get(get_nasid(),(d),(p)) -#define XBOW_UID_GET(n,p) iobrick_uid_get((n),(p)) #endif /* _ASM_IA64_SN_EEPROM_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/fetchop.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/fetchop.h --- linux-2.4.19/include/asm-ia64/sn/fetchop.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/fetchop.h Fri Feb 7 08:55:45 2003 @@ -4,13 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ - #ifndef _ASM_IA64_SN_FETCHOP_H #define _ASM_IA64_SN_FETCHOP_H +#include + #define FETCHOP_BASENAME "sgi_fetchop" #define FETCHOP_FULLNAME "/dev/sgi_fetchop" @@ -30,11 +31,53 @@ #define FETCHOP_CLEAR_CACHE 56 #define FETCHOP_LOAD_OP(addr, op) ( \ - *(long *)((char*) (addr) + (op))) + *(volatile long *)((char*) (addr) + (op))) #define FETCHOP_STORE_OP(addr, op, x) ( \ - *(long *)((char*) (addr) + (op)) = \ - (long) (x)) + *(volatile long *)((char*) (addr) + (op)) = (long) (x)) + +#ifdef __KERNEL__ + +/* + * Convert a region 6 (kaddr) address to the address of the fetchop variable + */ +#define FETCHOP_KADDR_TO_MSPEC_ADDR(kaddr) TO_MSPEC(kaddr) + + +/* + * Each Atomic Memory Operation (AMO formerly known as fetchop) + * variable is 64 bytes long. The first 8 bytes are used. The + * remaining 56 bytes are unaddressable due to the operation taking + * that portion of the address. + * + * NOTE: The AMO_t _MUST_ be placed in either the first or second half + * of the cache line. The cache line _MUST NOT_ be used for anything + * other than additional AMO_t entries. This is because there are two + * addresses which reference the same physical cache line. One will + * be a cached entry with the memory type bits all set. This address + * may be loaded into processor cache. The AMO_t will be referenced + * uncached via the memory special memory type. If any portion of the + * cached cache-line is modified, when that line is flushed, it will + * overwrite the uncached value in physical memory and lead to + * inconsistency. + */ +typedef struct { + u64 variable; + u64 unused[7]; +} AMO_t; + + +/* + * The following APIs are externalized to the kernel to allocate/free fetchop variables. + * fetchop_kalloc_one - Allocate/initialize 1 fetchop variable on the specified cnode. + * fetchop_kfree_one - Free a previously allocated fetchop variable + */ + +unsigned long fetchop_kalloc_one(int nid); +void fetchop_kfree_one(unsigned long maddr); + + +#endif /* __KERNEL__ */ #endif /* _ASM_IA64_SN_FETCHOP_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/gda.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/gda.h --- linux-2.4.19/include/asm-ia64/sn/gda.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/gda.h Mon Dec 30 14:16:56 2002 @@ -6,7 +6,7 @@ * * Derived from IRIX . * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. * * gda.h -- Contains the data structure for the global data area, * The GDA contains information communicated between the diff -Nur linux-2.4.19/include/asm-ia64/sn/geo.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/geo.h --- linux-2.4.19/include/asm-ia64/sn/geo.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/geo.h Mon Dec 30 14:16:56 2002 @@ -0,0 +1,54 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef __SYS_GEO_H__ +#define __SYS_GEO_H__ + +/* Include a platform-specific geo.h. It must define at least: + * geoid_t: Geographic identifier data type + * geo_type_t: Data type for the kind of geoid this is + * GEO_TYPE_xxx: Values for geo_type_t vars, eg. GEO_TYPE_NODE + * GEO_MAX_LEN: The maximum length of a geoid, formatted for printing + */ + +#include + +#ifdef CONFIG_IA64_SGI_SN2 +#include +#else + +#error <> + +#endif /* !SN2 && ... */ + +/* Declarations applicable to all platforms */ + +/* parameter for hwcfg_format_geoid() */ +#define GEO_FORMAT_HWGRAPH 1 +#define GEO_FORMAT_BRIEF 2 + +/* (the parameter for hwcfg_format_geoid_compt() is defined in the + * platform-specific geo.h file) */ + +/* Routines for manipulating geoid_t values */ + +extern moduleid_t geo_module(geoid_t g); +extern slabid_t geo_slab(geoid_t g); +extern geo_type_t geo_type(geoid_t g); +extern int geo_valid(geoid_t g); +extern int geo_cmp(geoid_t g0, geoid_t g1); +extern geoid_t geo_new(geo_type_t type, ...); + +extern geoid_t hwcfg_parse_geoid(char *buffer); +extern void hwcfg_format_geoid(char *buffer, geoid_t m, int fmt); +extern void hwcfg_format_geoid_compt(char *buffer, geoid_t m, int compt); +extern geoid_t hwcfg_geo_get_self(geo_type_t type); +extern geoid_t hwcfg_geo_get_by_nasid(geo_type_t type, nasid_t nasid); + +#endif /* __SYS_GEO_H__ */ diff -Nur linux-2.4.19/include/asm-ia64/sn/hack.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/hack.h --- linux-2.4.19/include/asm-ia64/sn/hack.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/hack.h Mon Dec 30 14:16:56 2002 @@ -1,10 +1,9 @@ /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -21,9 +20,6 @@ typedef int cred_t; /* This is for compilation reasons */ struct cred { int x; }; - -#define mrlock(_s, _t, _u) -#define mrunlock(_s) /* * Hardware Graph routines that are currently stubbed! diff -Nur linux-2.4.19/include/asm-ia64/sn/hcl.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/hcl.h --- linux-2.4.19/include/asm-ia64/sn/hcl.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/hcl.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_HCL_H #define _ASM_IA64_SN_HCL_H diff -Nur linux-2.4.19/include/asm-ia64/sn/hcl_util.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/hcl_util.h --- linux-2.4.19/include/asm-ia64/sn/hcl_util.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/hcl_util.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_HCL_UTIL_H diff -Nur linux-2.4.19/include/asm-ia64/sn/hires_clock.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/hires_clock.h --- linux-2.4.19/include/asm-ia64/sn/hires_clock.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/hires_clock.h Wed Dec 31 16:00:00 1969 @@ -1,52 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved. - * - * SGI Hi Resolution Clock - * - * SGI SN platforms provide a high resolution clock that is - * synchronized across all nodes. The clock can be memory mapped - * and directly read from user space. - * - * Access to the clock is thru the following: - * (error checking not shown) - * - * (Note: should library routines be provided to encapsulate this??) - * - * int fd: - * volatile long *clk; - * - * fd = open (HIRES_FULLNAME, O_RDONLY); - * clk = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); - * clk += ioctl(fd, HIRES_IOCQGETOFFSET, 0); - * - * At this point, clk is a pointer to the high resolution clock. - * - * The clock period can be obtained via: - * - * long picosec_per_tick; - * picosec_per_tick = ioctl(fd, HIRES_IOCQGETPICOSEC, 0); - */ - -#ifndef _ASM_IA64_SN_HIRES_CLOCK_H -#define _ASM_IA64_SN_HIRES_CLOCK_H - - -#define HIRES_BASENAME "sgi_hires_clock" -#define HIRES_FULLNAME "/dev/sgi_hires_clock" -#define HIRES_IOC_BASE 's' - - -/* Get page offset of hires timer */ -#define HIRES_IOCQGETOFFSET _IO( HIRES_IOC_BASE, 0 ) - -/* get clock period in picoseconds per tick */ -#define HIRES_IOCQGETPICOSEC _IO( HIRES_IOC_BASE, 1 ) - -/* get number of significant bits in clock counter */ -#define HIRES_IOCQGETCLOCKBITS _IO( HIRES_IOC_BASE, 2 ) - -#endif /* _ASM_IA64_SN_HIRES_CLOCK_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/idle.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/idle.h --- linux-2.4.19/include/asm-ia64/sn/idle.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/idle.h Mon Dec 30 14:16:56 2002 @@ -6,7 +6,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/include/asm-ia64/sn/ifconfig_net.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ifconfig_net.h --- linux-2.4.19/include/asm-ia64/sn/ifconfig_net.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ifconfig_net.h Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IFCONFIG_NET_H diff -Nur linux-2.4.19/include/asm-ia64/sn/intr.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/intr.h --- linux-2.4.19/include/asm-ia64/sn/intr.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/intr.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_INTR_H #define _ASM_IA64_SN_INTR_H diff -Nur linux-2.4.19/include/asm-ia64/sn/intr_public.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/intr_public.h --- linux-2.4.19/include/asm-ia64/sn/intr_public.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/intr_public.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_INTR_PUBLIC_H #define _ASM_IA64_SN_INTR_PUBLIC_H diff -Nur linux-2.4.19/include/asm-ia64/sn/invent.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/invent.h --- linux-2.4.19/include/asm-ia64/sn/invent.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/invent.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_INVENT_H #define _ASM_IA64_SN_INVENT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/io.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/io.h --- linux-2.4.19/include/asm-ia64/sn/io.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/io.h Mon Dec 30 14:16:56 2002 @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 2000 Ralf Baechle - * Copyright (C) 2000-2001 Silicon Graphics, Inc. */ #ifndef _ASM_IA64_SN_IO_H #define _ASM_IA64_SN_IO_H diff -Nur linux-2.4.19/include/asm-ia64/sn/ioc3.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioc3.h --- linux-2.4.19/include/asm-ia64/sn/ioc3.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioc3.h Mon Dec 30 14:16:56 2002 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff -Nur linux-2.4.19/include/asm-ia64/sn/ioc4.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioc4.h --- linux-2.4.19/include/asm-ia64/sn/ioc4.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioc4.h Mon Dec 30 14:16:56 2002 @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + */ + +#ifndef _ASM_IA64_SN_IOC4_H +#define _ASM_IA64_SN_IOC4_H + +#if 0 + +/* + * ioc4.h - IOC4 chip header file + */ + +/* Notes: + * The IOC4 chip is a 32-bit PCI device that provides 4 serial ports, + * an IDE bus interface, a PC keyboard/mouse interface, and a real-time + * external interrupt interface. + * + * It includes an optimized DMA buffer management, and a store-and-forward + * buffer RAM. + * + * All IOC4 registers are 32 bits wide. + */ +typedef __uint32_t ioc4reg_t; + +/* + * PCI Configuration Space Register Address Map, use offset from IOC4 PCI + * configuration base such that this can be used for multiple IOC4s + */ +#define IOC4_PCI_ID 0x0 /* ID */ + +#define IOC4_VENDOR_ID_NUM 0x10A9 +#define IOC4_DEVICE_ID_NUM 0x100A +#define IOC4_ADDRSPACE_MASK 0xfff00000ULL + +#define IOC4_PCI_SCR 0x4 /* Status/Command */ +#define IOC4_PCI_REV 0x8 /* Revision */ +#define IOC4_PCI_LAT 0xC /* Latency Timer */ +#define IOC4_PCI_BAR0 0x10 /* IOC4 base address 0 */ +#define IOC4_PCI_SIDV 0x2c /* Subsys ID and vendor */ +#define IOC4_PCI_CAP 0x34 /* Capability pointer */ +#define IOC4_PCI_LATGNTINT 0x3c /* Max_lat, min_gnt, int_pin, int_line */ + +/* + * PCI Memory Space Map + */ +#define IOC4_PCI_ERR_ADDR_L 0x000 /* Low Error Address */ +#define IOC4_PCI_ERR_ADDR_VLD (0x1 << 0) +#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1) +#define IOC4_PCI_ERR_ADDR_MUL_ERR (0x1 << 5) +#define IOC4_PCI_ERR_ADDR_ADDR_MSK (0x3ffffff << 6) + +/* Master IDs contained in PCI_ERR_ADDR_MST_ID_MSK */ +#define IOC4_MST_ID_S0_TX 0 +#define IOC4_MST_ID_S0_RX 1 +#define IOC4_MST_ID_S1_TX 2 +#define IOC4_MST_ID_S1_RX 3 +#define IOC4_MST_ID_S2_TX 4 +#define IOC4_MST_ID_S2_RX 5 +#define IOC4_MST_ID_S3_TX 6 +#define IOC4_MST_ID_S3_RX 7 +#define IOC4_MST_ID_ATA 8 + +#define IOC4_PCI_ERR_ADDR_H 0x004 /* High Error Address */ + +#define IOC4_SIO_IR 0x008 /* SIO Interrupt Register */ +#define IOC4_OTHER_IR 0x00C /* Other Interrupt Register */ + +/* These registers are read-only for general kernel code. To modify + * them use the functions in ioc4.c + */ +#define IOC4_SIO_IES_RO 0x010 /* SIO Interrupt Enable Set Reg */ +#define IOC4_OTHER_IES_RO 0x014 /* Other Interrupt Enable Set Reg */ +#define IOC4_SIO_IEC_RO 0x018 /* SIO Interrupt Enable Clear Reg */ +#define IOC4_OTHER_IEC_RO 0x01C /* Other Interrupt Enable Clear Reg */ + +#define IOC4_SIO_CR 0x020 /* SIO Control Reg */ +#define IOC4_INT_OUT 0x028 /* INT_OUT Reg (realtime interrupt) */ +#define IOC4_GPCR_S 0x030 /* GenericPIO Cntrl Set Register */ +#define IOC4_GPCR_C 0x034 /* GenericPIO Cntrl Clear Register */ +#define IOC4_GPDR 0x038 /* GenericPIO Data Register */ +#define IOC4_GPPR_0 0x040 /* GenericPIO Pin Registers */ +#define IOC4_GPPR_OFF 0x4 +#define IOC4_GPPR(x) (IOC4_GPPR_0+(x)*IOC4_GPPR_OFF) + +/* ATAPI Registers */ +#define IOC4_ATA_0 0x100 /* Data w/timing */ +#define IOC4_ATA_1 0x104 /* Error/Features w/timing */ +#define IOC4_ATA_2 0x108 /* Sector Count w/timing */ +#define IOC4_ATA_3 0x10C /* Sector Number w/timing */ +#define IOC4_ATA_4 0x110 /* Cyliner Low w/timing */ +#define IOC4_ATA_5 0x114 /* Cylinder High w/timing */ +#define IOC4_ATA_6 0x118 /* Device/Head w/timing */ +#define IOC4_ATA_7 0x11C /* Status/Command w/timing */ +#define IOC4_ATA_0_AUX 0x120 /* Aux Status/Device Cntrl w/timing */ +#define IOC4_ATA_TIMING 0x140 /* Timing value register 0 */ +#define IOC4_ATA_DMA_PTR_L 0x144 /* Low Memory Pointer to DMA List */ +#define IOC4_ATA_DMA_PTR_H 0x148 /* High Memory Pointer to DMA List */ +#define IOC4_ATA_DMA_ADDR_L 0x14C /* Low Memory DMA Address */ +#define IOC4_ATA_DMA_ADDR_H 0x150 /* High Memory DMA Addresss */ +#define IOC4_ATA_BC_DEV 0x154 /* DMA Byte Count at Device */ +#define IOC4_ATA_BC_MEM 0x158 /* DMA Byte Count at Memory */ +#define IOC4_ATA_DMA_CTRL 0x15C /* DMA Control/Status */ + +/* Keyboard and Mouse Registers */ +#define IOC4_KM_CSR 0x200 /* Kbd and Mouse Cntrl/Status Reg */ +#define IOC4_K_RD 0x204 /* Kbd Read Data Register */ +#define IOC4_M_RD 0x208 /* Mouse Read Data Register */ +#define IOC4_K_WD 0x20C /* Kbd Write Data Register */ +#define IOC4_M_WD 0x210 /* Mouse Write Data Register */ + +/* Serial Port Registers used for DMA mode serial I/O */ +#define IOC4_SBBR01_H 0x300 /* Serial Port Ring Buffers + Base Reg High for Channels 0 1*/ +#define IOC4_SBBR01_L 0x304 /* Serial Port Ring Buffers + Base Reg Low for Channels 0 1 */ +#define IOC4_SBBR23_H 0x308 /* Serial Port Ring Buffers + Base Reg High for Channels 2 3*/ +#define IOC4_SBBR23_L 0x30C /* Serial Port Ring Buffers + Base Reg Low for Channels 2 3 */ + +#define IOC4_SSCR_0 0x310 /* Serial Port 0 Control */ +#define IOC4_STPIR_0 0x314 /* Serial Port 0 TX Produce */ +#define IOC4_STCIR_0 0x318 /* Serial Port 0 TX Consume */ +#define IOC4_SRPIR_0 0x31C /* Serial Port 0 RX Produce */ +#define IOC4_SRCIR_0 0x320 /* Serial Port 0 RX Consume */ +#define IOC4_SRTR_0 0x324 /* Serial Port 0 Receive Timer Reg */ +#define IOC4_SHADOW_0 0x328 /* Serial Port 0 16550 Shadow Reg */ + +#define IOC4_SSCR_1 0x32C /* Serial Port 1 Control */ +#define IOC4_STPIR_1 0x330 /* Serial Port 1 TX Produce */ +#define IOC4_STCIR_1 0x334 /* Serial Port 1 TX Consume */ +#define IOC4_SRPIR_1 0x338 /* Serial Port 1 RX Produce */ +#define IOC4_SRCIR_1 0x33C /* Serial Port 1 RX Consume */ +#define IOC4_SRTR_1 0x340 /* Serial Port 1 Receive Timer Reg */ +#define IOC4_SHADOW_1 0x344 /* Serial Port 1 16550 Shadow Reg */ + +#define IOC4_SSCR_2 0x348 /* Serial Port 2 Control */ +#define IOC4_STPIR_2 0x34C /* Serial Port 2 TX Produce */ +#define IOC4_STCIR_2 0x350 /* Serial Port 2 TX Consume */ +#define IOC4_SRPIR_2 0x354 /* Serial Port 2 RX Produce */ +#define IOC4_SRCIR_2 0x358 /* Serial Port 2 RX Consume */ +#define IOC4_SRTR_2 0x35C /* Serial Port 2 Receive Timer Reg */ +#define IOC4_SHADOW_2 0x360 /* Serial Port 2 16550 Shadow Reg */ + +#define IOC4_SSCR_3 0x364 /* Serial Port 3 Control */ +#define IOC4_STPIR_3 0x368 /* Serial Port 3 TX Produce */ +#define IOC4_STCIR_3 0x36C /* Serial Port 3 TX Consume */ +#define IOC4_SRPIR_3 0x370 /* Serial Port 3 RX Produce */ +#define IOC4_SRCIR_3 0x374 /* Serial Port 3 RX Consume */ +#define IOC4_SRTR_3 0x378 /* Serial Port 3 Receive Timer Reg */ +#define IOC4_SHADOW_3 0x37C /* Serial Port 3 16550 Shadow Reg */ + +#define IOC4_UART0_BASE 0x380 /* UART 0 */ +#define IOC4_UART1_BASE 0x388 /* UART 1 */ +#define IOC4_UART2_BASE 0x390 /* UART 2 */ +#define IOC4_UART3_BASE 0x398 /* UART 3 */ + +/* Private page address aliases for usermode mapping */ +#define IOC4_INT_OUT_P 0x04000 /* INT_OUT Reg */ + +#define IOC4_SSCR_0_P 0x08000 /* Serial Port 0 */ +#define IOC4_STPIR_0_P 0x08004 +#define IOC4_STCIR_0_P 0x08008 /* (read-only) */ +#define IOC4_SRPIR_0_P 0x0800C /* (read-only) */ +#define IOC4_SRCIR_0_P 0x08010 +#define IOC4_SRTR_0_P 0x08014 +#define IOC4_UART_LSMSMCR_0_P 0x08018 /* (read-only) */ + +#define IOC4_SSCR_1_P 0x0C000 /* Serial Port 1 */ +#define IOC4_STPIR_1_P 0x0C004 +#define IOC4_STCIR_1_P 0x0C008 /* (read-only) */ +#define IOC4_SRPIR_1_P 0x0C00C /* (read-only) */ +#define IOC4_SRCIR_1_P 0x0C010 +#define IOC4_SRTR_1_P 0x0C014 +#define IOC4_UART_LSMSMCR_1_P 0x0C018 /* (read-only) */ + +#define IOC4_SSCR_2_P 0x10000 /* Serial Port 2 */ +#define IOC4_STPIR_2_P 0x10004 +#define IOC4_STCIR_2_P 0x10008 /* (read-only) */ +#define IOC4_SRPIR_2_P 0x1000C /* (read-only) */ +#define IOC4_SRCIR_2_P 0x10010 +#define IOC4_SRTR_2_P 0x10014 +#define IOC4_UART_LSMSMCR_2_P 0x10018 /* (read-only) */ + +#define IOC4_SSCR_3_P 0x14000 /* Serial Port 3 */ +#define IOC4_STPIR_3_P 0x14004 +#define IOC4_STCIR_3_P 0x14008 /* (read-only) */ +#define IOC4_SRPIR_3_P 0x1400C /* (read-only) */ +#define IOC4_SRCIR_3_P 0x14010 +#define IOC4_SRTR_3_P 0x14014 +#define IOC4_UART_LSMSMCR_3_P 0x14018 /* (read-only) */ + +#define IOC4_ALIAS_PAGE_SIZE 0x4000 + +/* Interrupt types */ +typedef enum ioc4_intr_type_e { + ioc4_sio_intr_type, + ioc4_other_intr_type, + ioc4_num_intr_types +} ioc4_intr_type_t; +#define ioc4_first_intr_type ioc4_sio_intr_type + +/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES */ +#define IOC4_SIO_IR_S0_TX_MT 0x00000001 /* Serial port 0 TX empty */ +#define IOC4_SIO_IR_S0_RX_FULL 0x00000002 /* Port 0 RX buf full */ +#define IOC4_SIO_IR_S0_RX_HIGH 0x00000004 /* Port 0 RX hiwat */ +#define IOC4_SIO_IR_S0_RX_TIMER 0x00000008 /* Port 0 RX timeout */ +#define IOC4_SIO_IR_S0_DELTA_DCD 0x00000010 /* Port 0 delta DCD */ +#define IOC4_SIO_IR_S0_DELTA_CTS 0x00000020 /* Port 0 delta CTS */ +#define IOC4_SIO_IR_S0_INT 0x00000040 /* Port 0 pass-thru intr */ +#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080 /* Port 0 explicit TX thru */ +#define IOC4_SIO_IR_S1_TX_MT 0x00000100 /* Serial port 1 */ +#define IOC4_SIO_IR_S1_RX_FULL 0x00000200 /* */ +#define IOC4_SIO_IR_S1_RX_HIGH 0x00000400 /* */ +#define IOC4_SIO_IR_S1_RX_TIMER 0x00000800 /* */ +#define IOC4_SIO_IR_S1_DELTA_DCD 0x00001000 /* */ +#define IOC4_SIO_IR_S1_DELTA_CTS 0x00002000 /* */ +#define IOC4_SIO_IR_S1_INT 0x00004000 /* */ +#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000 /* */ +#define IOC4_SIO_IR_S2_TX_MT 0x00010000 /* Serial port 2 */ +#define IOC4_SIO_IR_S2_RX_FULL 0x00020000 /* */ +#define IOC4_SIO_IR_S2_RX_HIGH 0x00040000 /* */ +#define IOC4_SIO_IR_S2_RX_TIMER 0x00080000 /* */ +#define IOC4_SIO_IR_S2_DELTA_DCD 0x00100000 /* */ +#define IOC4_SIO_IR_S2_DELTA_CTS 0x00200000 /* */ +#define IOC4_SIO_IR_S2_INT 0x00400000 /* */ +#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000 /* */ +#define IOC4_SIO_IR_S3_TX_MT 0x01000000 /* Serial port 3 */ +#define IOC4_SIO_IR_S3_RX_FULL 0x02000000 /* */ +#define IOC4_SIO_IR_S3_RX_HIGH 0x04000000 /* */ +#define IOC4_SIO_IR_S3_RX_TIMER 0x08000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_DCD 0x10000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_CTS 0x20000000 /* */ +#define IOC4_SIO_IR_S3_INT 0x40000000 /* */ +#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000 /* */ + +/* Per device interrupt masks */ +#define IOC4_SIO_IR_S0 (IOC4_SIO_IR_S0_TX_MT | \ + IOC4_SIO_IR_S0_RX_FULL | \ + IOC4_SIO_IR_S0_RX_HIGH | \ + IOC4_SIO_IR_S0_RX_TIMER | \ + IOC4_SIO_IR_S0_DELTA_DCD | \ + IOC4_SIO_IR_S0_DELTA_CTS | \ + IOC4_SIO_IR_S0_INT | \ + IOC4_SIO_IR_S0_TX_EXPLICIT) +#define IOC4_SIO_IR_S1 (IOC4_SIO_IR_S1_TX_MT | \ + IOC4_SIO_IR_S1_RX_FULL | \ + IOC4_SIO_IR_S1_RX_HIGH | \ + IOC4_SIO_IR_S1_RX_TIMER | \ + IOC4_SIO_IR_S1_DELTA_DCD | \ + IOC4_SIO_IR_S1_DELTA_CTS | \ + IOC4_SIO_IR_S1_INT | \ + IOC4_SIO_IR_S1_TX_EXPLICIT) +#define IOC4_SIO_IR_S2 (IOC4_SIO_IR_S2_TX_MT | \ + IOC4_SIO_IR_S2_RX_FULL | \ + IOC4_SIO_IR_S2_RX_HIGH | \ + IOC4_SIO_IR_S2_RX_TIMER | \ + IOC4_SIO_IR_S2_DELTA_DCD | \ + IOC4_SIO_IR_S2_DELTA_CTS | \ + IOC4_SIO_IR_S2_INT | \ + IOC4_SIO_IR_S2_TX_EXPLICIT) +#define IOC4_SIO_IR_S3 (IOC4_SIO_IR_S3_TX_MT | \ + IOC4_SIO_IR_S3_RX_FULL | \ + IOC4_SIO_IR_S3_RX_HIGH | \ + IOC4_SIO_IR_S3_RX_TIMER | \ + IOC4_SIO_IR_S3_DELTA_DCD | \ + IOC4_SIO_IR_S3_DELTA_CTS | \ + IOC4_SIO_IR_S3_INT | \ + IOC4_SIO_IR_S3_TX_EXPLICIT) + +/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ +#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ +#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ +#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ +#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ +#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ +#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Kbd/mouse intr */ +#define IOC4_OTHER_IR_ATA_DMAINT 0x00000089 /* ATAPI DMA intr */ +#define IOC4_OTHER_IR_RT_INT 0x00800000 /* RT output pulse */ +#define IOC4_OTHER_IR_GEN_INT1 0x02000000 /* RT input pulse */ +#define IOC4_OTHER_IR_GEN_INT_SHIFT 25 + +/* Per device interrupt masks */ +#define IOC4_OTHER_IR_ATA (IOC4_OTHER_IR_ATA_INT | \ + IOC4_OTHER_IR_ATA_MEMERR | \ + IOC4_OTHER_IR_ATA_DMAINT) +#define IOC4_OTHER_IR_RT (IOC4_OTHER_IR_RT_INT | IOC4_OTHER_IR_GEN_INT1) + +/* Macro to load pending interrupts */ +#define IOC4_PENDING_SIO_INTRS(mem) (PCI_INW(&((mem)->sio_ir)) & \ + PCI_INW(&((mem)->sio_ies_ro))) +#define IOC4_PENDING_OTHER_INTRS(mem) (PCI_INW(&((mem)->other_ir)) & \ + PCI_INW(&((mem)->other_ies_ro))) + +/* Bitmasks for IOC4_SIO_CR */ +#define IOC4_SIO_SR_CMD_PULSE 0x00000004 /* Byte bus strobe length */ +#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 +#define IOC4_SIO_CR_ARB_DIAG 0x00000070 /* Current non-ATA PCI bus + requester (ro) */ +#define IOC4_SIO_CR_ARB_DIAG_TX0 0x00000000 +#define IOC4_SIO_CR_ARB_DIAG_RX0 0x00000010 +#define IOC4_SIO_CR_ARB_DIAG_TX1 0x00000020 +#define IOC4_SIO_CR_ARB_DIAG_RX1 0x00000030 +#define IOC4_SIO_CR_ARB_DIAG_TX2 0x00000040 +#define IOC4_SIO_CR_ARB_DIAG_RX2 0x00000050 +#define IOC4_SIO_CR_ARB_DIAG_TX3 0x00000060 +#define IOC4_SIO_CR_ARB_DIAG_RX3 0x00000070 +#define IOC4_SIO_CR_SIO_DIAG_IDLE 0x00000080 /* 0 -> active request among + serial ports (ro) */ +#define IOC4_SIO_CR_ATA_DIAG_IDLE 0x00000100 /* 0 -> active request from + ATA port */ +#define IOC4_SIO_CR_ATA_DIAG_ACTIVE 0x00000200 /* 1 -> ATA request is winner */ + +/* Bitmasks for IOC4_INT_OUT */ +#define IOC4_INT_OUT_COUNT 0x0000ffff /* Pulse interval timer */ +#define IOC4_INT_OUT_MODE 0x00070000 /* Mode mask */ +#define IOC4_INT_OUT_MODE_0 0x00000000 /* Set output to 0 */ +#define IOC4_INT_OUT_MODE_1 0x00040000 /* Set output to 1 */ +#define IOC4_INT_OUT_MODE_1PULSE 0x00050000 /* Send 1 pulse */ +#define IOC4_INT_OUT_MODE_PULSES 0x00060000 /* Send 1 pulse every interval */ +#define IOC4_INT_OUT_MODE_SQW 0x00070000 /* Toggle output every interval */ +#define IOC4_INT_OUT_DIAG 0x40000000 /* Diag mode */ +#define IOC4_INT_OUT_INT_OUT 0x80000000 /* Current state of INT_OUT */ + +/* Time constants for IOC4_INT_OUT */ +#define IOC4_INT_OUT_NS_PER_TICK (15 * 520) /* 15 ns PCI clock, multi=520 */ +#define IOC4_INT_OUT_TICKS_PER_PULSE 3 /* Outgoing pulse lasts 3 + ticks */ +#define IOC4_INT_OUT_US_TO_COUNT(x) /* Convert uS to a count value */ \ + (((x) * 10 + IOC4_INT_OUT_NS_PER_TICK / 200) * \ + 100 / IOC4_INT_OUT_NS_PER_TICK - 1) +#define IOC4_INT_OUT_COUNT_TO_US(x) /* Convert count value to uS */ \ + (((x) + 1) * IOC4_INT_OUT_NS_PER_TICK / 1000) +#define IOC4_INT_OUT_MIN_TICKS 3 /* Min period is width of + pulse in "ticks" */ +#define IOC4_INT_OUT_MAX_TICKS IOC4_INT_OUT_COUNT /* Largest possible count */ + +/* Bitmasks for IOC4_GPCR */ +#define IOC4_GPCR_DIR 0x000000ff /* Tristate pin in or out */ +#define IOC4_GPCR_DIR_PIN(x) (1<<(x)) /* Access one of the DIR bits */ +#define IOC4_GPCR_EDGE 0x0000ff00 /* Extint edge or level + sensitive */ +#define IOC4_GPCR_EDGE_PIN(x) (1<<((x)+7 )) /* Access one of the EDGE bits */ + +/* Values for IOC4_GPCR */ +#define IOC4_GPCR_INT_OUT_EN 0x00100000 /* Enable INT_OUT to pin 0 */ +#define IOC4_GPCR_DIR_SER0_XCVR 0x00000010 /* Port 0 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER1_XCVR 0x00000020 /* Port 1 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER2_XCVR 0x00000040 /* Port 2 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER3_XCVR 0x00000080 /* Port 3 Transceiver select + enable */ + +/* Defs for some of the generic I/O pins */ +#define IOC4_GPCR_UART0_MODESEL 0x10 /* Pin is output to port 0 + mode sel */ +#define IOC4_GPCR_UART1_MODESEL 0x20 /* Pin is output to port 1 + mode sel */ +#define IOC4_GPCR_UART2_MODESEL 0x40 /* Pin is output to port 2 + mode sel */ +#define IOC4_GPCR_UART3_MODESEL 0x80 /* Pin is output to port 3 + mode sel */ + +#define IOC4_GPPR_UART0_MODESEL_PIN 4 /* GIO pin controlling + uart 0 mode select */ +#define IOC4_GPPR_UART1_MODESEL_PIN 5 /* GIO pin controlling + uart 1 mode select */ +#define IOC4_GPPR_UART2_MODESEL_PIN 6 /* GIO pin controlling + uart 2 mode select */ +#define IOC4_GPPR_UART3_MODESEL_PIN 7 /* GIO pin controlling + uart 3 mode select */ + +/* Bitmasks for IOC4_ATA_TIMING */ +#define IOC4_ATA_TIMING_ADR_SETUP 0x00000003 /* Clocks of addr set-up */ +#define IOC4_ATA_TIMING_PULSE_WIDTH 0x000001f8 /* Clocks of read or write + pulse width */ +#define IOC4_ATA_TIMING_RECOVERY 0x0000fe00 /* Clocks before next read + or write */ +#define IOC4_ATA_TIMING_USE_IORDY 0x00010000 /* PIO uses IORDY */ + +/* Bitmasks for address list elements pointed to by IOC4_ATA_DMA_PTR_ */ +#define IOC4_ATA_ALE_DMA_ADDRESS 0xfffffffffffffffe + +/* Bitmasks for byte count list elements pointed to by IOC4_ATA_DMA_PTR_ */ +#define IOC4_ATA_BCLE_BYTE_COUNT 0x000000000000fffe +#define IOC4_ATA_BCLE_LIST_END 0x0000000080000000 + +/* Bitmasks for IOC4_ATA_BC_ */ +#define IOC4_ATA_BC_BYTE_CNT 0x0001fffe /* Byte count */ + +/* Bitmasks for IOC4_ATA_DMA_CTRL */ +#define IOC4_ATA_DMA_CTRL_STRAT 0x00000001 /* 1 -> start DMA engine */ +#define IOC4_ATA_DMA_CTRL_STOP 0x00000002 /* 1 -> stop DMA engine */ +#define IOC4_ATA_DMA_CTRL_DIR 0x00000004 /* 1 -> ATA bus data copied + to memory */ +#define IOC4_ATA_DMA_CTRL_ACTIVE 0x00000008 /* DMA channel is active */ +#define IOC4_ATA_DMA_CTRL_MEM_ERROR 0x00000010 /* DMA engine encountered + a PCI error */ +/* Bitmasks for IOC4_KM_CSR */ +#define IOC4_KM_CSR_K_WRT_PEND 0x00000001 /* Kbd port xmitting or resetting */ +#define IOC4_KM_CSR_M_WRT_PEND 0x00000002 /* Mouse port xmitting or resetting */ +#define IOC4_KM_CSR_K_LCB 0x00000004 /* Line Cntrl Bit for last KBD write */ +#define IOC4_KM_CSR_M_LCB 0x00000008 /* Same for mouse */ +#define IOC4_KM_CSR_K_DATA 0x00000010 /* State of kbd data line */ +#define IOC4_KM_CSR_K_CLK 0x00000020 /* State of kbd clock line */ +#define IOC4_KM_CSR_K_PULL_DATA 0x00000040 /* Pull kbd data line low */ +#define IOC4_KM_CSR_K_PULL_CLK 0x00000080 /* Pull kbd clock line low */ +#define IOC4_KM_CSR_M_DATA 0x00000100 /* State of mouse data line */ +#define IOC4_KM_CSR_M_CLK 0x00000200 /* State of mouse clock line */ +#define IOC4_KM_CSR_M_PULL_DATA 0x00000400 /* Pull mouse data line low */ +#define IOC4_KM_CSR_M_PULL_CLK 0x00000800 /* Pull mouse clock line low */ +#define IOC4_KM_CSR_EMM_MODE 0x00001000 /* Emulation mode */ +#define IOC4_KM_CSR_SIM_MODE 0x00002000 /* Clock X8 */ +#define IOC4_KM_CSR_K_SM_IDLE 0x00004000 /* Keyboard is idle */ +#define IOC4_KM_CSR_M_SM_IDLE 0x00008000 /* Mouse is idle */ +#define IOC4_KM_CSR_K_TO 0x00010000 /* Keyboard trying to send/receive */ +#define IOC4_KM_CSR_M_TO 0x00020000 /* Mouse trying to send/receive */ +#define IOC4_KM_CSR_K_TO_EN 0x00040000 /* KM_CSR_K_TO + KM_CSR_K_TO_EN = + cause SIO_IR to assert */ +#define IOC4_KM_CSR_M_TO_EN 0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN = + cause SIO_IR to assert */ +#define IOC4_KM_CSR_K_CLAMP_ONE 0x00100000 /* Pull K_CLK low after rec. one char */ +#define IOC4_KM_CSR_M_CLAMP_ONE 0x00200000 /* Pull M_CLK low after rec. one char */ +#define IOC4_KM_CSR_K_CLAMP_THREE \ + 0x00400000 /* Pull K_CLK low after rec. three chars */ +#define IOC4_KM_CSR_M_CLAMP_THREE \ + 0x00800000 /* Pull M_CLK low after rec. three char */ + +/* Bitmasks for IOC4_K_RD and IOC4_M_RD */ +#define IOC4_KM_RD_DATA_2 0x000000ff /* 3rd char recvd since last read */ +#define IOC4_KM_RD_DATA_2_SHIFT 0 +#define IOC4_KM_RD_DATA_1 0x0000ff00 /* 2nd char recvd since last read */ +#define IOC4_KM_RD_DATA_1_SHIFT 8 +#define IOC4_KM_RD_DATA_0 0x00ff0000 /* 1st char recvd since last read */ +#define IOC4_KM_RD_DATA_0_SHIFT 16 +#define IOC4_KM_RD_FRAME_ERR_2 0x01000000 /* Framing or parity error in byte 2 */ +#define IOC4_KM_RD_FRAME_ERR_1 0x02000000 /* Same for byte 1 */ +#define IOC4_KM_RD_FRAME_ERR_0 0x04000000 /* Same for byte 0 */ + +#define IOC4_KM_RD_KBD_MSE 0x08000000 /* 0 if from kbd, 1 if from mouse */ +#define IOC4_KM_RD_OFLO 0x10000000 /* 4th char recvd before this read */ +#define IOC4_KM_RD_VALID_2 0x20000000 /* DATA_2 valid */ +#define IOC4_KM_RD_VALID_1 0x40000000 /* DATA_1 valid */ +#define IOC4_KM_RD_VALID_0 0x80000000 /* DATA_0 valid */ +#define IOC4_KM_RD_VALID_ALL (IOC4_KM_RD_VALID_0 | IOC4_KM_RD_VALID_1 | \ + IOC4_KM_RD_VALID_2) + +/* Bitmasks for IOC4_K_WD & IOC4_M_WD */ +#define IOC4_KM_WD_WRT_DATA 0x000000ff /* Write to keyboard/mouse port */ +#define IOC4_KM_WD_WRT_DATA_SHIFT 0 + +/* Bitmasks for serial RX status byte */ +#define IOC4_RXSB_OVERRUN 0x01 /* Char(s) lost */ +#define IOC4_RXSB_PAR_ERR 0x02 /* Parity error */ +#define IOC4_RXSB_FRAME_ERR 0x04 /* Framing error */ +#define IOC4_RXSB_BREAK 0x08 /* Break character */ +#define IOC4_RXSB_CTS 0x10 /* State of CTS */ +#define IOC4_RXSB_DCD 0x20 /* State of DCD */ +#define IOC4_RXSB_MODEM_VALID 0x40 /* DCD, CTS, and OVERRUN are valid */ +#define IOC4_RXSB_DATA_VALID 0x80 /* Data byte, FRAME_ERR PAR_ERR & BREAK valid */ + +/* Bitmasks for serial TX control byte */ +#define IOC4_TXCB_INT_WHEN_DONE 0x20 /* Interrupt after this byte is sent */ +#define IOC4_TXCB_INVALID 0x00 /* Byte is invalid */ +#define IOC4_TXCB_VALID 0x40 /* Byte is valid */ +#define IOC4_TXCB_MCR 0x80 /* Data<7:0> to modem control register */ +#define IOC4_TXCB_DELAY 0xc0 /* Delay data<7:0> mSec */ + +/* Bitmasks for IOC4_SBBR_L */ +#define IOC4_SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */ +#define IOC4_SBBR_L_BASE 0xfffff000 /* Lower serial ring base addr */ + +/* Bitmasks for IOC4_SSCR_<3:0> */ +#define IOC4_SSCR_RX_THRESHOLD 0x000001ff /* Hiwater mark */ +#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ +#define IOC4_SSCR_HFC_EN 0x00020000 /* Hardware flow control enabled */ +#define IOC4_SSCR_RX_RING_DCD 0x00040000 /* Post RX record on delta-DCD */ +#define IOC4_SSCR_RX_RING_CTS 0x00080000 /* Post RX record on delta-CTS */ +#define IOC4_SSCR_DIAG 0x00200000 /* Bypass clock divider for sim */ +#define IOC4_SSCR_RX_DRAIN 0x08000000 /* Drain RX buffer to memory */ +#define IOC4_SSCR_DMA_EN 0x10000000 /* Enable ring buffer DMA */ +#define IOC4_SSCR_DMA_PAUSE 0x20000000 /* Pause DMA */ +#define IOC4_SSCR_PAUSE_STATE 0x40000000 /* Sets when PAUSE takes effect */ +#define IOC4_SSCR_RESET 0x80000000 /* Reset DMA channels */ + +/* All producer/comsumer pointers are the same bitfield */ +#define IOC4_PROD_CONS_PTR_4K 0x00000ff8 /* For 4K buffers */ +#define IOC4_PROD_CONS_PTR_1K 0x000003f8 /* For 1K buffers */ +#define IOC4_PROD_CONS_PTR_OFF 3 + +/* Bitmasks for IOC4_STPIR_<3:0> */ +/* Reserved for future register definitions */ + +/* Bitmasks for IOC4_STCIR_<3:0> */ +#define IOC4_STCIR_BYTE_CNT 0x0f000000 /* Bytes in unpacker */ +#define IOC4_STCIR_BYTE_CNT_SHIFT 24 + +/* Bitmasks for IOC4_SRPIR_<3:0> */ +#define IOC4_SRPIR_BYTE_CNT 0x0f000000 /* Bytes in packer */ +#define IOC4_SRPIR_BYTE_CNT_SHIFT 24 + +/* Bitmasks for IOC4_SRCIR_<3:0> */ +#define IOC4_SRCIR_ARM 0x80000000 /* Arm RX timer */ + +/* Bitmasks for IOC4_SHADOW_<3:0> */ +#define IOC4_SHADOW_DR 0x00000001 /* Data ready */ +#define IOC4_SHADOW_OE 0x00000002 /* Overrun error */ +#define IOC4_SHADOW_PE 0x00000004 /* Parity error */ +#define IOC4_SHADOW_FE 0x00000008 /* Framing error */ +#define IOC4_SHADOW_BI 0x00000010 /* Break interrupt */ +#define IOC4_SHADOW_THRE 0x00000020 /* Xmit holding register empty */ +#define IOC4_SHADOW_TEMT 0x00000040 /* Xmit shift register empty */ +#define IOC4_SHADOW_RFCE 0x00000080 /* Char in RX fifo has an error */ +#define IOC4_SHADOW_DCTS 0x00010000 /* Delta clear to send */ +#define IOC4_SHADOW_DDCD 0x00080000 /* Delta data carrier detect */ +#define IOC4_SHADOW_CTS 0x00100000 /* Clear to send */ +#define IOC4_SHADOW_DCD 0x00800000 /* Data carrier detect */ +#define IOC4_SHADOW_DTR 0x01000000 /* Data terminal ready */ +#define IOC4_SHADOW_RTS 0x02000000 /* Request to send */ +#define IOC4_SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ +#define IOC4_SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ +#define IOC4_SHADOW_LOOP 0x10000000 /* Loopback enabled */ + +/* Bitmasks for IOC4_SRTR_<3:0> */ +#define IOC4_SRTR_CNT 0x00000fff /* Reload value for RX timer */ +#define IOC4_SRTR_CNT_VAL 0x0fff0000 /* Current value of RX timer */ +#define IOC4_SRTR_CNT_VAL_SHIFT 16 +#define IOC4_SRTR_HZ 16000 /* SRTR clock frequency */ + +/* Serial port register map used for DMA and PIO serial I/O */ +typedef volatile struct ioc4_serialregs { + ioc4reg_t sscr; + ioc4reg_t stpir; + ioc4reg_t stcir; + ioc4reg_t srpir; + ioc4reg_t srcir; + ioc4reg_t srtr; + ioc4reg_t shadow; +} ioc4_sregs_t; + +/* IOC4 UART register map */ +typedef volatile struct ioc4_uartregs { + union { + char rbr; /* read only, DLAB == 0 */ + char thr; /* write only, DLAB == 0 */ + char dll; /* DLAB == 1 */ + } u1; + union { + char ier; /* DLAB == 0 */ + char dlm; /* DLAB == 1 */ + } u2; + union { + char iir; /* read only */ + char fcr; /* write only */ + } u3; + char i4u_lcr; + char i4u_mcr; + char i4u_lsr; + char i4u_msr; + char i4u_scr; +} ioc4_uart_t; + +#define i4u_rbr u1.rbr +#define i4u_thr u1.thr +#define i4u_dll u1.dll +#define i4u_ier u2.ier +#define i4u_dlm u2.dlm +#define i4u_iir u3.iir +#define i4u_fcr u3.fcr + +/* PCI config space register map */ +typedef volatile struct ioc4_configregs { + ioc4reg_t pci_id; + ioc4reg_t pci_scr; + ioc4reg_t pci_rev; + ioc4reg_t pci_lat; + ioc4reg_t pci_bar0; + ioc4reg_t pci_bar1; + ioc4reg_t pci_bar2_not_implemented; + ioc4reg_t pci_cis_ptr_not_implemented; + ioc4reg_t pci_sidv; + ioc4reg_t pci_rom_bar_not_implemented; + ioc4reg_t pci_cap; + ioc4reg_t pci_rsv; + ioc4reg_t pci_latgntint; + + char pci_fill1[0x58 - 0x3c - 4]; + + ioc4reg_t pci_pcix; + ioc4reg_t pci_pcixstatus; +} ioc4_cfg_t; + +/* PCI memory space register map addressed using pci_bar0 */ +typedef volatile struct ioc4_memregs { + + /* Miscellaneous IOC4 registers */ + ioc4reg_t pci_err_addr_l; + ioc4reg_t pci_err_addr_h; + ioc4reg_t sio_ir; + ioc4reg_t other_ir; + + /* These registers are read-only for general kernel code. To + * modify them use the functions in ioc4.c. + */ + ioc4reg_t sio_ies_ro; + ioc4reg_t other_ies_ro; + ioc4reg_t sio_iec_ro; + ioc4reg_t other_iec_ro; + ioc4reg_t sio_cr; + ioc4reg_t misc_fill1; + ioc4reg_t int_out; + ioc4reg_t misc_fill2; + ioc4reg_t gpcr_s; + ioc4reg_t gpcr_c; + ioc4reg_t gpdr; + ioc4reg_t misc_fill3; + ioc4reg_t gppr_0; + ioc4reg_t gppr_1; + ioc4reg_t gppr_2; + ioc4reg_t gppr_3; + ioc4reg_t gppr_4; + ioc4reg_t gppr_5; + ioc4reg_t gppr_6; + ioc4reg_t gppr_7; + + char misc_fill4[0x100 - 0x5C - 4]; + + /* ATA/ATAP registers */ + ioc4reg_t ata_0; + ioc4reg_t ata_1; + ioc4reg_t ata_2; + ioc4reg_t ata_3; + ioc4reg_t ata_4; + ioc4reg_t ata_5; + ioc4reg_t ata_6; + ioc4reg_t ata_7; + ioc4reg_t ata_aux; + + char ata_fill1[0x140 - 0x120 - 4]; + + ioc4reg_t ata_timing; + ioc4reg_t ata_dma_ptr_l; + ioc4reg_t ata_dma_ptr_h; + ioc4reg_t ata_dma_addr_l; + ioc4reg_t ata_dma_addr_h; + ioc4reg_t ata_bc_dev; + ioc4reg_t ata_bc_mem; + ioc4reg_t ata_dma_ctrl; + + char ata_fill2[0x200 - 0x15C - 4]; + + /* Keyboard and mouse registers */ + ioc4reg_t km_csr; + ioc4reg_t k_rd; + ioc4reg_t m_rd; + ioc4reg_t k_wd; + ioc4reg_t m_wd; + + char km_fill1[0x300 - 0x210 - 4]; + + /* Serial port registers used for DMA serial I/O */ + ioc4reg_t sbbr01_l; + ioc4reg_t sbbr01_h; + ioc4reg_t sbbr23_l; + ioc4reg_t sbbr23_h; + + ioc4_sregs_t port_0; + ioc4_sregs_t port_1; + ioc4_sregs_t port_2; + ioc4_sregs_t port_3; + + ioc4_uart_t uart_0; + ioc4_uart_t uart_1; + ioc4_uart_t uart_2; + ioc4_uart_t uart_3; +} ioc4_mem_t; + +#endif /* 0 */ + +/* + * Bytebus device space + */ +#define IOC4_BYTEBUS_DEV0 0x80000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV1 0xA0000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV2 0xC0000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV3 0xE0000L /* Addressed using pci_bar0 */ + +#if 0 +/* UART clock speed */ +#define IOC4_SER_XIN_CLK 66000000 + +typedef enum ioc4_subdevs_e { + ioc4_subdev_generic, + ioc4_subdev_kbms, + ioc4_subdev_tty0, + ioc4_subdev_tty1, + ioc4_subdev_tty2, + ioc4_subdev_tty3, + ioc4_subdev_rt, + ioc4_nsubdevs +} ioc4_subdev_t; + +/* Subdevice disable bits, + * from the standard INFO_LBL_SUBDEVS + */ +#define IOC4_SDB_TTY0 (1 << ioc4_subdev_tty0) +#define IOC4_SDB_TTY1 (1 << ioc4_subdev_tty1) +#define IOC4_SDB_TTY2 (1 << ioc4_subdev_tty2) +#define IOC4_SDB_TTY3 (1 << ioc4_subdev_tty3) +#define IOC4_SDB_KBMS (1 << ioc4_subdev_kbms) +#define IOC4_SDB_RT (1 << ioc4_subdev_rt) +#define IOC4_SDB_GENERIC (1 << ioc4_subdev_generic) + +#define IOC4_ALL_SUBDEVS ((1 << ioc4_nsubdevs) - 1) + +#define IOC4_SDB_SERIAL (IOC4_SDB_TTY0 | IOC4_SDB_TTY1 | IOC4_SDB_TTY2 | IOC4_SDB_TTY3) + +#define IOC4_STD_SUBDEVS IOC4_ALL_SUBDEVS + +#define IOC4_INTA_SUBDEVS (IOC4_SDB_SERIAL | IOC4_SDB_KBMS | IOC4_SDB_RT | IOC4_SDB_GENERIC) + +extern int ioc4_subdev_enabled(vertex_hdl_t, ioc4_subdev_t); +extern void ioc4_subdev_enables(vertex_hdl_t, ulong_t); +extern void ioc4_subdev_enable(vertex_hdl_t, ioc4_subdev_t); +extern void ioc4_subdev_disable(vertex_hdl_t, ioc4_subdev_t); + +/* Macros to read and write the SIO_IEC and SIO_IES registers (see the + * comments in ioc4.c for details on why this is necessary + */ +#define IOC4_W_IES 0 +#define IOC4_W_IEC 1 +extern void ioc4_write_ireg(void *, ioc4reg_t, int, ioc4_intr_type_t); + +#define IOC4_WRITE_IES(ioc4, val, type) ioc4_write_ireg(ioc4, val, IOC4_W_IES, type) +#define IOC4_WRITE_IEC(ioc4, val, type) ioc4_write_ireg(ioc4, val, IOC4_W_IEC, type) + +typedef void +ioc4_intr_func_f (intr_arg_t, ioc4reg_t); + +typedef void +ioc4_intr_connect_f (vertex_hdl_t conn_vhdl, + ioc4_intr_type_t, + ioc4reg_t, + ioc4_intr_func_f *, + intr_arg_t info, + vertex_hdl_t owner_vhdl, + vertex_hdl_t intr_dev_vhdl, + int (*)(intr_arg_t)); + +typedef void +ioc4_intr_disconnect_f (vertex_hdl_t conn_vhdl, + ioc4_intr_type_t, + ioc4reg_t, + ioc4_intr_func_f *, + intr_arg_t info, + vertex_hdl_t owner_vhdl); + +ioc4_intr_disconnect_f ioc4_intr_disconnect; +ioc4_intr_connect_f ioc4_intr_connect; + +extern int ioc4_is_console(vertex_hdl_t conn_vhdl); + +extern void ioc4_mlreset(ioc4_cfg_t *, ioc4_mem_t *); + +extern intr_func_f ioc4_intr; + +extern ioc4_mem_t *ioc4_mem_ptr(void *ioc4_fastinfo); + +typedef ioc4_intr_func_f *ioc4_intr_func_t; + +#endif /* 0 */ +#endif /* _ASM_IA64_SN_IOC4_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/ioconfig_bus.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioconfig_bus.h --- linux-2.4.19/include/asm-ia64/sn/ioconfig_bus.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioconfig_bus.h Fri Jan 3 19:33:41 2003 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#define IOCONFIG_PCIBUS "/boot/efi/ioconfig_pcibus" +#define POUND_CHAR '#' +#define MAX_LINE_LEN 128 +#define MAXPATHLEN 128 + +struct ioconfig_parm { + unsigned long ioconfig_activated; + unsigned long number; + void *buffer; +}; + +struct ascii_moduleid{ + unsigned char io_moduleid[8]; /* pci path name */ +}; diff -Nur linux-2.4.19/include/asm-ia64/sn/ioerror.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioerror.h --- linux-2.4.19/include/asm-ia64/sn/ioerror.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioerror.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOERROR_H #define _ASM_IA64_SN_IOERROR_H @@ -121,7 +121,7 @@ */ typedef struct io_error_s { - /* Bit fields indicating which sturcture fields are valid */ + /* Bit fields indicating which structure fields are valid */ union { struct { unsigned ievb_errortype:1; @@ -138,6 +138,7 @@ unsigned ievb_memaddr:1; unsigned ievb_epc:1; unsigned ievb_ef:1; + unsigned ievb_tnum:1; } iev_b; unsigned iev_a; } ie_v; @@ -156,13 +157,14 @@ paddr_t ie_memaddr; /* Physical memory address */ caddr_t ie_epc; /* pc when error reported */ caddr_t ie_ef; /* eframe when error reported */ - + short ie_tnum; /* Xtalk TNUM field */ } ioerror_t; #define IOERROR_INIT(e) do { (e)->ie_v.iev_a = 0; } while (0) #define IOERROR_SETVALUE(e,f,v) do { (e)->ie_ ## f = (v); (e)->ie_v.iev_b.ievb_ ## f = 1; } while (0) -#define IOERROR_FIELDVALID(e,f) (((e)->ie_v.iev_b.ievb_ ## f) != 0) -#define IOERROR_GETVALUE(e,f) (ASSERT(IOERROR_FIELDVALID(e,f)),((e)->ie_ ## f)) +#define IOERROR_FIELDVALID(e,f) ((unsigned long long)((e)->ie_v.iev_b.ievb_ ## f) != (unsigned long long) 0) +#define IOERROR_NOGETVALUE(e,f) (ASSERT(IOERROR_FIELDVALID(e,f)), ((e)->ie_ ## f)) +#define IOERROR_GETVALUE(p,e,f) ASSERT(IOERROR_FIELDVALID(e,f)); p=((e)->ie_ ## f) /* hub code likes to call the SysAD address "hubaddr" ... */ #define ie_hubaddr ie_sysioaddr diff -Nur linux-2.4.19/include/asm-ia64/sn/ioerror_handling.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioerror_handling.h --- linux-2.4.19/include/asm-ia64/sn/ioerror_handling.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ioerror_handling.h Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOERROR_HANDLING_H #define _ASM_IA64_SN_IOERROR_HANDLING_H diff -Nur linux-2.4.19/include/asm-ia64/sn/iograph.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/iograph.h --- linux-2.4.19/include/asm-ia64/sn/iograph.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/iograph.h Tue Feb 11 17:20:34 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOGRAPH_H #define _ASM_IA64_SN_IOGRAPH_H @@ -32,6 +32,7 @@ #define EDGE_LBL_CONTROLLER "controller" #define EDGE_LBL_CPU "cpu" #define EDGE_LBL_CPUNUM "cpunum" +#define EDGE_LBL_DIRECT "direct" #define EDGE_LBL_DISABLED "disabled" #define EDGE_LBL_DISK "disk" #define EDGE_LBL_DMA_ENGINE "dma_engine" /* Only available on @@ -67,6 +68,7 @@ #define EDGE_LBL_HPC "hpc" #define EDGE_LBL_GFX "gfx" #define EDGE_LBL_HUB "hub" /* For SN0 */ +#define EDGE_LBL_HW "hw" #define EDGE_LBL_SYNERGY "synergy" /* For SNIA only */ #define EDGE_LBL_IBUS "ibus" /* For EVEREST */ #define EDGE_LBL_INTERCONNECT "link" @@ -74,6 +76,8 @@ #define EDGE_LBL_IO4 "io4" /* For EVEREST */ #define EDGE_LBL_IOC3 "ioc3" #define EDGE_LBL_LUN "lun" +#define EDGE_LBL_LINUX "linux" +#define EDGE_LBL_LINUX_BUS EDGE_LBL_LINUX "/bus/pci-x" #define EDGE_LBL_MACE "mace" /* O2 mace */ #define EDGE_LBL_MACHDEP "machdep" /* Platform depedent devices */ #define EDGE_LBL_MASTER ".master" @@ -86,6 +90,9 @@ #define EDGE_LBL_NVRAM "nvram" #define EDGE_LBL_PARTITION "partition" #define EDGE_LBL_PCI "pci" +#define EDGE_LBL_PCIX "pci-x" +#define EDGE_LBL_PCIX_0 EDGE_LBL_PCIX "/0" +#define EDGE_LBL_PCIX_1 EDGE_LBL_PCIX "/1" #define EDGE_LBL_PORT "port" #define EDGE_LBL_PROM "prom" #define EDGE_LBL_RACK "rack" @@ -112,6 +119,7 @@ #define EDGE_LBL_XPLINK "xplink" /* Cross partition */ #define EDGE_LBL_XPLINK_NET "net" /* XP network devs */ #define EDGE_LBL_XPLINK_RAW "raw" /* XP Raw devs */ +#define EDGE_LBL_SLAB "slab" /* Slab of a module */ #define EDGE_LBL_XPLINK_KERNEL "kernel" /* XP kernel devs */ #define EDGE_LBL_XPLINK_ADMIN "admin" /* Partition admin */ #define EDGE_LBL_KAIO "kaio" /* Kernel async i/o poll */ @@ -119,8 +127,12 @@ #define EDGE_LBL_XBOX_RPS "xbox_rps" /* redundant power supply for xbox unit */ #define EDGE_LBL_IOBRICK "iobrick" #define EDGE_LBL_PBRICK "Pbrick" +#define EDGE_LBL_PEBRICK "PEbrick" +#define EDGE_LBL_PXBRICK "PXbrick" +#define EDGE_LBL_IXBRICK "IXbrick" #define EDGE_LBL_IBRICK "Ibrick" #define EDGE_LBL_XBRICK "Xbrick" +#define EDGE_LBL_CGBRICK "CGbrick" #define EDGE_LBL_CPUBUS "cpubus" /* CPU Interfaces (SysAd) */ /* vertex info labels in hwgraph */ @@ -202,7 +214,7 @@ #include /* For get MAX_PORT_NUM */ -int io_brick_map_widget(char, int); +int io_brick_map_widget(int, int); int io_path_map_widget(devfs_handle_t); /* @@ -210,8 +222,7 @@ */ struct io_brick_map_s { - char ibm_type; /* brick type, e.g. */ - /* 'I' for Ibrick */ + int ibm_type; /* brick type */ int ibm_map_wid[MAX_PORT_NUM]; /* wid to int map */ }; diff -Nur linux-2.4.19/include/asm-ia64/sn/klclock.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/klclock.h --- linux-2.4.19/include/asm-ia64/sn/klclock.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/klclock.h Mon Dec 30 14:16:56 2002 @@ -3,13 +3,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1996, 2001-2003 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 2001 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLCLOCK_H #define _ASM_IA64_SN_KLCLOCK_H #include +#include #define RTC_BASE_ADDR (unsigned char *)(nvram_base) diff -Nur linux-2.4.19/include/asm-ia64/sn/klconfig.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/klconfig.h --- linux-2.4.19/include/asm-ia64/sn/klconfig.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/klconfig.h Tue Feb 11 17:20:34 2003 @@ -6,7 +6,7 @@ * * Derived from IRIX . * - * Copyright (C) 1992-1997,1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLCONFIG_H @@ -55,6 +55,10 @@ #include #endif +#ifdef CONFIG_IA64_SGI_SN2 +#include +#endif + #define KLCFGINFO_MAGIC 0xbeedbabe typedef s32 klconf_off_t; @@ -335,8 +339,8 @@ #define KLCLASS_IOBRICK 0x70 /* IP35 iobrick */ -#define KLCLASS_MAX 7 /* Bump this if a new CLASS is added */ -#define KLTYPE_MAX 10 /* Bump this if a new CLASS is added */ +#define KLCLASS_MAX 8 /* Bump this if a new CLASS is added */ +#define KLTYPE_MAX 11 /* Bump this if a new CLASS is added */ #define KLCLASS_UNKNOWN 0xf0 @@ -353,7 +357,7 @@ #define KLTYPE_WEIRDCPU (KLCLASS_CPU | 0x0) #define KLTYPE_SNIA (KLCLASS_CPU | 0x1) -#define KLTYPE_WEIRDIO (KLCLASS_IO | 0x0) +#define KLTYPE_WEIRDIO (KLCLASS_IOBRICK | 0x0) #define KLTYPE_BASEIO (KLCLASS_IO | 0x1) /* IOC3, SuperIO, Bridge, SCSI */ #define KLTYPE_IO6 KLTYPE_BASEIO /* Additional name */ #define KLTYPE_4CHSCSI (KLCLASS_IO | 0x2) @@ -394,6 +398,12 @@ #define KLTYPE_IBRICK (KLCLASS_IOBRICK | 0x1) #define KLTYPE_PBRICK (KLCLASS_IOBRICK | 0x2) #define KLTYPE_XBRICK (KLCLASS_IOBRICK | 0x3) +#define KLTYPE_NBRICK (KLCLASS_IOBRICK | 0x4) +#define KLTYPE_PEBRICK (KLCLASS_IOBRICK | 0x5) +#define KLTYPE_PXBRICK (KLCLASS_IOBRICK | 0x6) +#define KLTYPE_IXBRICK (KLCLASS_IOBRICK | 0x7) +#define KLTYPE_CGBRICK (KLCLASS_IOBRICK | 0x8) + #define KLTYPE_PBRICK_BRIDGE KLTYPE_PBRICK @@ -433,7 +443,11 @@ unsigned char brd_flags; /* Enabled, Disabled etc */ unsigned char brd_slot; /* slot number */ unsigned short brd_debugsw; /* Debug switches */ +#ifdef CONFIG_IA64_SGI_SN2 + geoid_t brd_geoid; /* geo id */ +#else moduleid_t brd_module; /* module to which it belongs */ +#endif partid_t brd_partition; /* Partition number */ unsigned short brd_diagval; /* diagnostic value */ unsigned short brd_diagparm; /* diagnostic parameter */ @@ -448,6 +462,9 @@ confidence_t brd_confidence; /* confidence that the board is bad */ nasid_t brd_owner; /* who owns this board */ unsigned char brd_nic_flags; /* To handle 8 more NICs */ +#ifdef CONFIG_IA64_SGI_SN2 + char pad[32]; /* future expansion */ +#endif char brd_name[32]; } lboard_t; @@ -570,6 +587,10 @@ #define KLSTRUCT_USB 34 #define KLSTRUCT_USBKBD 35 #define KLSTRUCT_USBMS 36 +#define KLSTRUCT_SCSI_CTLR 37 +#define KLSTRUCT_PEBRICK 38 +#define KLSTRUCT_GIGE 39 +#define KLSTRUCT_IDE 40 /* * These are the indices of various components within a lboard structure. @@ -611,6 +632,9 @@ nasid_t port_nasid; unsigned char port_flag; klconf_off_t port_offset; +#ifdef CONFIG_IA64_SGI_SN2 + short port_num; +#endif } klport_t; typedef struct klcpu_s { /* CPU */ @@ -620,6 +644,9 @@ unsigned short cpu_speed; /* Speed in MHZ */ unsigned short cpu_scachesz; /* secondary cache size in MB */ unsigned short cpu_scachespeed;/* secondary cache speed in MHz */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klcpu_t ; #define CPU_STRUCT_VERSION 2 @@ -627,16 +654,28 @@ typedef struct klhub_s { /* HUB */ klinfo_t hub_info; uint hub_flags; /* PCFG_HUB_xxx flags */ +#ifdef CONFIG_IA64_SGI_SN2 +#define MAX_NI_PORTS 2 + klport_t hub_port[MAX_NI_PORTS + 1];/* hub is connected to this */ +#else klport_t hub_port; /* hub is connected to this */ +#endif nic_t hub_box_nic; /* nic of containing box */ klconf_off_t hub_mfg_nic; /* MFG NIC string */ u64 hub_speed; /* Speed of hub in HZ */ +#ifdef CONFIG_IA64_SGI_SN2 + moduleid_t hub_io_module; /* attached io module */ + unsigned long pad; +#endif } klhub_t ; typedef struct klhub_uart_s { /* HUB */ klinfo_t hubuart_info; uint hubuart_flags; /* PCFG_HUB_xxx flags */ nic_t hubuart_box_nic; /* nic of containing box */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klhub_uart_t ; #define MEMORY_STRUCT_VERSION 2 @@ -647,6 +686,9 @@ short membnk_dimm_select; /* bank to physical addr mapping*/ short membnk_bnksz[MD_MEM_BANKS]; /* Memory bank sizes */ short membnk_attr; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klmembnk_t ; #define KLCONFIG_MEMBNK_SIZE(_info, _bank) \ @@ -665,6 +707,9 @@ char snum_str[MAX_SERIAL_NUM_SIZE]; unsigned long long snum_int; } snum; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klmod_serial_num_t; /* Macros needed to access serial number structure in lboard_t. @@ -682,6 +727,9 @@ klport_t xbow_port_info[MAX_XBOW_LINKS] ; /* Module number */ int xbow_master_hub_link; /* type of brd connected+component struct ptr+flags */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klxbow_t ; #define MAX_PCI_SLOTS 8 @@ -700,6 +748,9 @@ pci_t pci_specific ; /* PCI Board config info */ klpci_device_t bri_devices[MAX_PCI_DEVS] ; /* PCI IDs */ klconf_off_t bri_mfg_nic ; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klbri_t ; #define MAX_IOC3_TTY 2 @@ -713,6 +764,9 @@ klinfo_t ioc3_enet ; klconf_off_t ioc3_enet_off ; klconf_off_t ioc3_kbd_off ; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klioc3_t ; #define MAX_VME_SLOTS 8 @@ -721,12 +775,18 @@ klinfo_t vmeb_info ; vmeb_t vmeb_specific ; klconf_off_t vmeb_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klvmeb_t ; typedef struct klvmed_s { /* VME DEVICE - VME BOARD */ klinfo_t vmed_info ; vmed_t vmed_specific ; klconf_off_t vmed_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klvmed_t ; #define ROUTER_VECTOR_VERS 2 @@ -739,6 +799,9 @@ klport_t rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */ klconf_off_t rou_mfg_nic ; /* MFG NIC string */ u64 rou_vector; /* vector from master node */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klrou_t ; /* @@ -763,16 +826,25 @@ graphics_t gfx_specific; klconf_off_t pad0; /* for compatibility with older proms */ klconf_off_t gfx_mfg_nic; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klgfx_t; typedef struct klxthd_s { klinfo_t xthd_info ; klconf_off_t xthd_mfg_nic ; /* MFG NIC string */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klxthd_t ; typedef struct kltpu_s { /* TPU board */ klinfo_t tpu_info ; klconf_off_t tpu_mfg_nic ; /* MFG NIC string */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } kltpu_t ; typedef struct klgsn_s { /* GSN board */ @@ -789,36 +861,64 @@ * that as the size to be klmalloced. */ -typedef struct klscsi_s { /* SCSI Controller */ +typedef struct klscsi_s { /* SCSI Bus */ klinfo_t scsi_info ; scsi_t scsi_specific ; unsigned char scsi_numdevs ; klconf_off_t scsi_devinfo[MAX_SCSI_DEVS] ; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klscsi_t ; +typedef struct klscctl_s { /* SCSI Controller */ + klinfo_t scsi_info ; + uint type; + uint scsi_buscnt; /* # busses this cntlr */ + void *scsi_bus[2]; /* Pointer to 2 klscsi_t's */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif +} klscctl_t ; + typedef struct klscdev_s { /* SCSI device */ klinfo_t scdev_info ; struct scsidisk_data *scdev_cfg ; /* driver fills up this */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klscdev_t ; typedef struct klttydev_s { /* TTY device */ klinfo_t ttydev_info ; struct terminal_data *ttydev_cfg ; /* driver fills up this */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klttydev_t ; typedef struct klenetdev_s { /* ENET device */ klinfo_t enetdev_info ; struct net_data *enetdev_cfg ; /* driver fills up this */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klenetdev_t ; typedef struct klkbddev_s { /* KBD device */ klinfo_t kbddev_info ; struct keyboard_data *kbddev_cfg ; /* driver fills up this */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klkbddev_t ; typedef struct klmsdev_s { /* mouse device */ klinfo_t msdev_info ; void *msdev_cfg ; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klmsdev_t ; #define MAX_FDDI_DEVS 10 /* XXX Is this true */ @@ -827,11 +927,17 @@ klinfo_t fddi_info ; fddi_t fddi_specific ; klconf_off_t fddi_devinfo[MAX_FDDI_DEVS] ; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klfddi_t ; typedef struct klmio_s { /* MIO */ klinfo_t mio_info ; mio_t mio_specific ; +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klmio_t ; /* @@ -842,6 +948,9 @@ klinfo_t usb_info; /* controller info */ void *usb_bus; /* handle to usb_bus_t */ uint64_t usb_controller; /* ptr to controller info */ +#ifdef CONFIG_IA64_SGI_SN2 + unsigned long pad; +#endif } klusb_t ; typedef union klcomp_s { @@ -856,6 +965,7 @@ klrou_t kc_rou; klgfx_t kc_gfx; klscsi_t kc_scsi; + klscctl_t kc_scsi_ctl; klscdev_t kc_scsi_dev; klfddi_t kc_fddi; klmio_t kc_mio; @@ -929,26 +1039,38 @@ extern lboard_t *find_gfxpipe(int pipenum); extern void setup_gfxpipe_link(devfs_handle_t vhdl,int pipenum); extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class); +#ifdef CONFIG_IA64_SGI_SN2 +extern lboard_t *find_lboard_module_class(lboard_t *start, geoid_t geoid, + unsigned char brd_class); +#else extern lboard_t *find_lboard_module_class(lboard_t *start, moduleid_t mod, unsigned char brd_class); +#endif extern lboard_t *find_nic_lboard(lboard_t *, nic_t); extern lboard_t *find_nic_type_lboard(nasid_t, unsigned char, nic_t); +#ifdef CONFIG_IA64_SGI_SN2 +extern lboard_t *find_lboard_modslot(lboard_t *start, geoid_t geoid); +extern lboard_t *find_lboard_module(lboard_t *start, geoid_t geoid); +extern lboard_t *get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name); +#else extern lboard_t *find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot); extern lboard_t *find_lboard_module(lboard_t *start, moduleid_t mod); extern lboard_t *get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name); +#endif extern int config_find_nic_router(nasid_t, nic_t, lboard_t **, klrou_t**); extern int config_find_nic_hub(nasid_t, nic_t, lboard_t **, klhub_t**); extern int config_find_xbow(nasid_t, lboard_t **, klxbow_t**); extern int update_klcfg_cpuinfo(nasid_t, int); extern void board_to_path(lboard_t *brd, char *path); +#ifdef CONFIG_IA64_SGI_SN2 extern moduleid_t get_module_id(nasid_t nasid); +#endif extern void nic_name_convert(char *old_name, char *new_name); extern int module_brds(nasid_t nasid, lboard_t **module_brds, int n); extern lboard_t *brd_from_key(uint64_t key); extern void device_component_canonical_name_get(lboard_t *,klinfo_t *, char *); extern int board_serial_number_get(lboard_t *,char *); -extern int is_master_baseio(nasid_t,moduleid_t,slotid_t); extern nasid_t get_actual_nasid(lboard_t *brd) ; extern net_vec_t klcfg_discover_route(lboard_t *, lboard_t *, int); diff -Nur linux-2.4.19/include/asm-ia64/sn/kldir.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/kldir.h --- linux-2.4.19/include/asm-ia64/sn/kldir.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/kldir.h Mon Dec 30 14:16:56 2002 @@ -5,7 +5,7 @@ * * Derived from IRIX , revision 1.21. * - * Copyright (C) 1992-1997,1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLDIR_H diff -Nur linux-2.4.19/include/asm-ia64/sn/ksys/elsc.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ksys/elsc.h --- linux-2.4.19/include/asm-ia64/sn/ksys/elsc.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ksys/elsc.h Mon Dec 30 14:16:56 2002 @@ -4,13 +4,16 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_KSYS_ELSC_H #define _ASM_SN_KSYS_ELSC_H +#include #include +#ifdef CONFIG_IA64_SGI_SN1 + #define ELSC_ACP_MAX 86 /* 84+cr+lf */ #define ELSC_LINE_MAX (ELSC_ACP_MAX - 2) @@ -73,7 +76,6 @@ int elsc_power_cycle(elsc_t *e); int elsc_system_reset(elsc_t *e); int elsc_dip_switches(elsc_t *e); -int elsc_nic_get(elsc_t *e, uint64_t *nic, int verbose); int _elsc_hbt(elsc_t *e, int ival, int rdly); @@ -82,6 +84,9 @@ #define elsc_hbt_send(e) _elsc_hbt(e, 0, 1) elsc_t *get_elsc(void); + +#endif /* CONFIG_IA64_SGI_SN1 */ + /* * Error codes diff -Nur linux-2.4.19/include/asm-ia64/sn/ksys/l1.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/ksys/l1.h --- linux-2.4.19/include/asm-ia64/sn/ksys/l1.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/ksys/l1.h Tue Feb 11 17:20:34 2003 @@ -4,17 +4,21 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_KSYS_L1_H #define _ASM_SN_KSYS_L1_H +#include #include #include #include #include + +#ifdef CONFIG_IA64_SGI_SN1 + #define BRL1_QSIZE 128 /* power of 2 is more efficient */ #define BRL1_BUFSZ 264 /* needs to be large enough * to hold 2 flags, escaped @@ -109,8 +113,6 @@ #define BRL1_RESET 7 -#ifndef __ASSEMBLY__ - /* * l1sc_t structure-- tracks protocol state, open subchannels, etc. */ @@ -148,7 +150,6 @@ sc_cq_t garbage_q; /* a place to put unsolicited packets */ sc_cq_t oq[BRL1_OQS]; /* elscuart output queues */ - } l1sc_t; @@ -169,6 +170,7 @@ #define SC_TIMEDOUT (-9) #define SC_NSUBCH (-10) +#endif /* CONFIG_IA64_SGI_SN1 */ /* L1 Target Addresses */ /* @@ -179,21 +181,27 @@ * id (L1 functionality is divided into several independent "tasks" * that can each receive command requests and transmit responses) */ +#ifdef CONFIG_IA64_SGI_SN1 #define L1_ADDR_TYPE_SHFT 28 #define L1_ADDR_TYPE_MASK 0xF0000000 +#endif /* CONFIG_IA64_SGI_SN1 */ #define L1_ADDR_TYPE_L1 0x00 /* L1 system controller */ #define L1_ADDR_TYPE_L2 0x01 /* L2 system controller */ #define L1_ADDR_TYPE_L3 0x02 /* L3 system controller */ #define L1_ADDR_TYPE_CBRICK 0x03 /* attached C brick */ #define L1_ADDR_TYPE_IOBRICK 0x04 /* attached I/O brick */ +#ifdef CONFIG_IA64_SGI_SN1 #define L1_ADDR_RACK_SHFT 18 #define L1_ADDR_RACK_MASK 0x0FFC0000 #define L1_ADDR_RACK_LOCAL 0x3ff /* local brick's rack */ +#endif /* CONFIG_IA64_SGI_SN1 */ +#ifdef CONFIG_IA64_SGI_SN1 #define L1_ADDR_BAY_SHFT 12 #define L1_ADDR_BAY_MASK 0x0003F000 #define L1_ADDR_BAY_LOCAL 0x3f /* local brick's bay */ +#endif /* CONFIG_IA64_SGI_SN1 */ #define L1_ADDR_TASK_SHFT 0 #define L1_ADDR_TASK_MASK 0x0000001F @@ -268,13 +276,18 @@ #define L1_REQ_EXEC_CMD 0x0000 /* interpret and execute an ASCII command string */ - /* brick type response codes */ -#define L1_BRICKTYPE_C 0x43 -#define L1_BRICKTYPE_I 0x49 -#define L1_BRICKTYPE_P 0x50 -#define L1_BRICKTYPE_R 0x52 -#define L1_BRICKTYPE_X 0x58 +#define L1_BRICKTYPE_IP45 0x34 /* 4 */ +#define L1_BRICKTYPE_C 0x43 /* C */ +#define L1_BRICKTYPE_I 0x49 /* I */ +#define L1_BRICKTYPE_P 0x50 /* P */ +#define L1_BRICKTYPE_R 0x52 /* R */ +#define L1_BRICKTYPE_X 0x58 /* X */ +#define L1_BRICKTYPE_X2 0x59 /* Y */ +#define L1_BRICKTYPE_N 0x4e /* N */ +#define L1_BRICKTYPE_PE 0x25 /* % */ +#define L1_BRICKTYPE_PX 0x23 /* # */ +#define L1_BRICKTYPE_IX 0x3d /* = */ /* EEPROM codes (for the "read EEPROM" request) */ /* c brick */ @@ -306,7 +319,6 @@ (*(l1addr_t *)(addr) = (l1addr_t)(trb) | \ ((l1addr_t)(tsk) << L1_ADDR_TASK_SHFT)) - #define L1_DISPLAY_LINE_LENGTH 12 /* L1 display characters/line */ #ifdef L1_DISP_2LINES @@ -316,10 +328,12 @@ * to system software */ #endif -#define SC_EVENT_CLASS_MASK ((unsigned short)0xff00) - #define bzero(d, n) memset((d), 0, (n)) +#ifdef CONFIG_IA64_SGI_SN1 + +#define SC_EVENT_CLASS_MASK ((unsigned short)0xff00) + /* public interfaces to L1 system controller */ int sc_open( l1sc_t *sc, uint target ); @@ -348,15 +362,18 @@ #define get_l1sc get_elsc #define get_master_l1sc get_l1sc -int router_module_get( nasid_t nasid, net_vec_t path ); - int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, uint *bay, uint *brick_type ); int iobrick_module_get( l1sc_t *sc ); int iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ); int iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ); int iobrick_sc_version( l1sc_t *sc, char *result ); +#else +int elsc_display_line(nasid_t nasid, char *line, int lnum); +int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, + uint *bay, uint *brick_type ); +int iobrick_module_get( nasid_t nasid ); +#endif /* CONFIG_IA64_SGI_SN1 */ -#endif /* !__ASSEMBLY__ */ #endif /* _ASM_SN_KSYS_L1_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/labelcl.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/labelcl.h --- linux-2.4.19/include/asm-ia64/sn/labelcl.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/labelcl.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_LABELCL_H #define _ASM_IA64_SN_LABELCL_H diff -Nur linux-2.4.19/include/asm-ia64/sn/leds.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/leds.h --- linux-2.4.19/include/asm-ia64/sn/leds.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/leds.h Mon Dec 30 14:16:56 2002 @@ -5,7 +5,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -15,7 +15,7 @@ #include #ifdef CONFIG_IA64_SGI_SN1 -#define LED0 0xc0000b00100000c0LL /* ZZZ fixme */ +#define LED0 0xc0000b00100000c0LL #define LED_CPU_SHIFT 3 #else #include @@ -25,7 +25,13 @@ #define LED_CPU_HEARTBEAT 0x01 #define LED_CPU_ACTIVITY 0x02 +#ifdef LED_WAR +#define LED_ALWAYS_SET 0x64 /* SN2 hw workaround: always set 0x60 */ +#define LED_MASK_AUTOTEST 0x9e +#else /* LED_WAR */ +#define LED_ALWAYS_SET 0x00 #define LED_MASK_AUTOTEST 0xfe +#endif /* LED_WAR */ /* * Basic macros for flashing the LEDS on an SGI, SN1. diff -Nur linux-2.4.19/include/asm-ia64/sn/mca.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/mca.h --- linux-2.4.19/include/asm-ia64/sn/mca.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/mca.h Wed Dec 31 16:00:00 1969 @@ -1,128 +0,0 @@ -/* - * File: mca.h - * Purpose: Machine check handling specific to the SN platform defines - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include - -#ifdef CONFIG_IA64_SGI_SN - -typedef u64 __uint64_t; - -typedef struct { - __uint64_t sh_event_occurred; - __uint64_t sh_first_error; - __uint64_t sh_event_overflow; - __uint64_t sh_pi_first_error; - __uint64_t sh_pi_error_summary; - __uint64_t sh_pi_error_overflow; - __uint64_t sh_pi_error_detail_1; - __uint64_t sh_pi_error_detail_2; - __uint64_t sh_pi_hw_time_stamp; - __uint64_t sh_pi_uncorrected_detail_1; - __uint64_t sh_pi_uncorrected_detail_2; - __uint64_t sh_pi_uncorrected_detail_3; - __uint64_t sh_pi_uncorrected_detail_4; - __uint64_t sh_pi_uncor_time_stamp; - __uint64_t sh_pi_corrected_detail_1; - __uint64_t sh_pi_corrected_detail_2; - __uint64_t sh_pi_corrected_detail_3; - __uint64_t sh_pi_corrected_detail_4; - __uint64_t sh_pi_cor_time_stamp; - __uint64_t sh_mem_error_summary; - __uint64_t sh_mem_error_overflow; - __uint64_t sh_misc_err_hdr_lower; - __uint64_t sh_misc_err_hdr_upper; - __uint64_t sh_dir_uc_err_hdr_lower; - __uint64_t sh_dir_uc_err_hdr_upper; - __uint64_t sh_dir_cor_err_hdr_lower; - __uint64_t sh_dir_cor_err_hdr_upper; - __uint64_t sh_mem_error_mask; - __uint64_t sh_md_uncor_time_stamp; - __uint64_t sh_md_cor_time_stamp; - __uint64_t sh_md_hw_time_stamp; - __uint64_t sh_xn_error_summary; - __uint64_t sh_xn_first_error; - __uint64_t sh_xn_error_overflow; - __uint64_t sh_xniilb_error_summary; - __uint64_t sh_xniilb_first_error; - __uint64_t sh_xniilb_error_overflow; - __uint64_t sh_xniilb_error_detail_1; - __uint64_t sh_xniilb_error_detail_2; - __uint64_t sh_xniilb_error_detail_3; - __uint64_t sh_xnpi_error_summary; - __uint64_t sh_xnpi_first_error; - __uint64_t sh_xnpi_error_overflow; - __uint64_t sh_xnpi_error_detail_1; - __uint64_t sh_xnmd_error_summary; - __uint64_t sh_xnmd_first_error; - __uint64_t sh_xnmd_error_overflow; - __uint64_t sh_xnmd_ecc_err_report; - __uint64_t sh_xnmd_error_detail_1; - __uint64_t sh_lb_error_summary; - __uint64_t sh_lb_first_error; - __uint64_t sh_lb_error_overflow; - __uint64_t sh_lb_error_detail_1; - __uint64_t sh_lb_error_detail_2; - __uint64_t sh_lb_error_detail_3; - __uint64_t sh_lb_error_detail_4; - __uint64_t sh_lb_error_detail_5; -} sal_log_shub_state_t; - -typedef struct { -sal_log_section_hdr_t header; - struct - { - __uint64_t err_status : 1, - guid : 1, - oem_data : 1, - reserved : 61; - } valid; - __uint64_t err_status; - efi_guid_t guid; - __uint64_t shub_nic; - sal_log_shub_state_t shub_state; -} sal_log_plat_info_t; - - -extern void sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc); - -#ifdef platform_plat_specific_err_print -#undef platform_plat_specific_err_print -#endif -#define platform_plat_specific_err_print sal_log_plat_print - -#endif /* CONFIG_IA64_SGI_SN */ diff -Nur linux-2.4.19/include/asm-ia64/sn/mmtimer_private.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/mmtimer_private.h --- linux-2.4.19/include/asm-ia64/sn/mmtimer_private.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/mmtimer_private.h Mon Dec 30 14:16:56 2002 @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. * * Helper file for the SN implementation of mmtimers * diff -Nur linux-2.4.19/include/asm-ia64/sn/module.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/module.h --- linux-2.4.19/include/asm-ia64/sn/module.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/module.h Tue Feb 11 17:20:34 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_MODULE_H #define _ASM_IA64_SN_MODULE_H @@ -13,12 +13,13 @@ #endif +#include #include #include #include #define MODULE_MAX 128 -#define MODULE_MAX_NODES 1 +#define MODULE_MAX_NODES 2 #define MODULE_HIST_CNT 16 #define MAX_MODULE_LEN 16 @@ -32,6 +33,128 @@ #define MODULE_FORMAT_LONG 2 +#ifdef CONFIG_IA64_SGI_SN2 + +/* + * Module id format + * + * 31-16 Rack ID (encoded class, group, number - 16-bit unsigned int) + * 15-8 Brick type (8-bit ascii character) + * 7-0 Bay (brick position in rack (0-63) - 8-bit unsigned int) + * + */ + +/* + * Macros for getting the brick type + */ +#define MODULE_BTYPE_MASK 0xff00 +#define MODULE_BTYPE_SHFT 8 +#define MODULE_GET_BTYPE(_m) (((_m) & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT) +#define MODULE_BT_TO_CHAR(_b) ((char)(_b)) +#define MODULE_GET_BTCHAR(_m) (MODULE_BT_TO_CHAR(MODULE_GET_BTYPE(_m))) + +/* + * Macros for getting the rack ID. + */ +#define MODULE_RACK_MASK 0xffff0000 +#define MODULE_RACK_SHFT 16 +#define MODULE_GET_RACK(_m) (((_m) & MODULE_RACK_MASK) >> MODULE_RACK_SHFT) + +/* + * Macros for getting the brick position + */ +#define MODULE_BPOS_MASK 0x00ff +#define MODULE_BPOS_SHFT 0 +#define MODULE_GET_BPOS(_m) (((_m) & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT) + +/* + * Macros for constructing moduleid_t's + */ +#define RBT_TO_MODULE(_r, _b, _t) ((_r) << MODULE_RACK_SHFT | \ + (_b) << MODULE_BPOS_SHFT | \ + (_t) << MODULE_BTYPE_SHFT) + +/* + * Macros for encoding and decoding rack IDs + * A rack number consists of three parts: + * class (0==CPU/mixed, 1==I/O), group, number + * + * Rack number is stored just as it is displayed on the screen: + * a 3-decimal-digit number. + */ +#define RACK_CLASS_DVDR 100 +#define RACK_GROUP_DVDR 10 +#define RACK_NUM_DVDR 1 + +#define RACK_CREATE_RACKID(_c, _g, _n) ((_c) * RACK_CLASS_DVDR + \ + (_g) * RACK_GROUP_DVDR + (_n) * RACK_NUM_DVDR) + +#define RACK_GET_CLASS(_r) ((_r) / RACK_CLASS_DVDR) +#define RACK_GET_GROUP(_r) (((_r) - RACK_GET_CLASS(_r) * \ + RACK_CLASS_DVDR) / RACK_GROUP_DVDR) +#define RACK_GET_NUM(_r) (((_r) - RACK_GET_CLASS(_r) * \ + RACK_CLASS_DVDR - RACK_GET_GROUP(_r) * \ + RACK_GROUP_DVDR) / RACK_NUM_DVDR) + +/* + * Macros for encoding and decoding rack IDs + * A rack number consists of three parts: + * class 1 bit, 0==CPU/mixed, 1==I/O + * group 2 bits for CPU/mixed, 3 bits for I/O + * number 3 bits for CPU/mixed, 2 bits for I/O (1 based) + */ +#define RACK_GROUP_BITS(_r) (RACK_GET_CLASS(_r) ? 3 : 2) +#define RACK_NUM_BITS(_r) (RACK_GET_CLASS(_r) ? 2 : 3) + +#define RACK_CLASS_MASK(_r) 0x20 +#define RACK_CLASS_SHFT(_r) 5 +#define RACK_ADD_CLASS(_r, _c) \ + ((_r) |= (_c) << RACK_CLASS_SHFT(_r) & RACK_CLASS_MASK(_r)) + +#define RACK_GROUP_SHFT(_r) RACK_NUM_BITS(_r) +#define RACK_GROUP_MASK(_r) \ + ( (((unsigned)1<geoid)) +#else #define NODE_MODULEID(cnode) (NODEPDA(cnode)->module_id) +#endif #define NODE_SLOTID(cnode) (NODEPDA(cnode)->slotdesc) diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/bridge.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/bridge.h --- linux-2.4.19/include/asm-ia64/sn/pci/bridge.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/bridge.h Mon Jan 13 08:03:32 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_BRIDGE_H #define _ASM_SN_PCI_BRIDGE_H @@ -12,9 +12,40 @@ /* * bridge.h - header file for bridge chip and bridge portion of xbridge chip + * + * Also including offsets for unique PIC registers. + * The PIC asic is a follow-on to Xbridge and most of it's registers are + * identical to those of Xbridge. PIC is different than Xbridge in that + * it will accept 64 bit register access and that, in some cases, data + * is kept in bits 63:32. PIC registers that are identical to Xbridge + * may be accessed identically to the Xbridge registers, allowing for lots + * of code reuse. Here are the access rules as described in the PIC + * manual: + * + * o Read a word on a DW boundary returns D31:00 of reg. + * o Read a DW on a DW boundary returns D63:00 of reg. + * o Write a word on a DW boundary loads D31:00 of reg. + * o Write a DW on a DW boundary loads D63:00 of reg. + * o No support for word boundary access that is not double word + * aligned. + * + * So we can reuse a lot of bridge_s for PIC. In bridge_s are included + * #define tags and unions for 64 bit access to PIC registers. + * For a detailed PIC register layout see pic.h. */ +#include #include +#ifndef CONFIG_IA64_SGI_SN1 +#include + +extern int io_get_sh_swapper(nasid_t); +#define BRIDGE_REG_GET32(reg) \ + __swab32( *(volatile uint32_t *) (((uint64_t)reg)^4) ) + +#define BRIDGE_REG_SET32(reg) \ + *(volatile uint32_t *) (((uint64_t)reg)^4) +#endif /* CONFIG_IA64_SGI_SN1 */ /* I/O page size */ @@ -36,6 +67,8 @@ #define BRIDGE_ATE_RAM_SIZE (BRIDGE_INTERNAL_ATES<<3) /* 1kB ATE */ #define XBRIDGE_ATE_RAM_SIZE (XBRIDGE_INTERNAL_ATES<<3) /* 8kB ATE */ +#define PIC_WR_REQ_BUFSIZE 256 + #define BRIDGE_CONFIG_BASE 0x20000 /* start of bridge's */ /* map to each device's */ /* config space */ @@ -78,7 +111,502 @@ * Generated from Bridge spec dated 04oct95 */ -#ifdef LITTLE_ENDIAN +#ifndef CONFIG_IA64_SGI_SN1 + +/* + * pic_widget_cfg_s is a local definition of widget_cfg_t but with + * a union of 64bit & 32bit registers, since PIC has 64bit widget + * registers but BRIDGE and XBRIDGE have 32bit. PIC registers that + * have valid bits (ie. not just reserved) in the upper 32bits are + * defined as a union so we can access them as 64bit for PIC and + * as 32bit for BRIDGE and XBRIDGE. + */ +typedef volatile struct pic_widget_cfg_s { + bridgereg_t _b_wid_id; /* 0x000004 */ + bridgereg_t _pad_000000; + + union { + picreg_t _p_wid_stat; /* 0x000008 */ + struct { + bridgereg_t _b_wid_stat; /* 0x00000C */ + bridgereg_t _b_pad_000008; + } _b; + } u_wid_stat; + #define __p_wid_stat_64 u_wid_stat._p_wid_stat + #define __b_wid_stat u_wid_stat._b._b_wid_stat + + bridgereg_t _b_wid_err_upper; /* 0x000014 */ + bridgereg_t _pad_000010; + + union { + picreg_t _p_wid_err_lower; /* 0x000018 */ + struct { + bridgereg_t _b_wid_err_lower; /* 0x00001C */ + bridgereg_t _b_pad_000018; + } _b; + } u_wid_err_lower; + #define __p_wid_err_64 u_wid_err_lower._p_wid_err_lower + #define __b_wid_err_lower u_wid_err_lower._b._b_wid_err_lower + + union { + picreg_t _p_wid_control; /* 0x000020 */ + struct { + bridgereg_t _b_wid_control; /* 0x000024 */ + bridgereg_t _b_pad_000020; + } _b; + } u_wid_control; + #define __p_wid_control_64 u_wid_control._p_wid_control + #define __b_wid_control u_wid_control._b._b_wid_control + + bridgereg_t _b_wid_req_timeout; /* 0x00002C */ + bridgereg_t _pad_000028; + + bridgereg_t _b_wid_int_upper; /* 0x000034 */ + bridgereg_t _pad_000030; + + union { + picreg_t _p_wid_int_lower; /* 0x000038 */ + struct { + bridgereg_t _b_wid_int_lower; /* 0x00003C */ + bridgereg_t _b_pad_000038; + } _b; + } u_wid_int_lower; + #define __p_wid_int_64 u_wid_int_lower._p_wid_int_lower + #define __b_wid_int_lower u_wid_int_lower._b._b_wid_int_lower + + bridgereg_t _b_wid_err_cmdword; /* 0x000044 */ + bridgereg_t _pad_000040; + + bridgereg_t _b_wid_llp; /* 0x00004C */ + bridgereg_t _pad_000048; + + bridgereg_t _b_wid_tflush; /* 0x000054 */ + bridgereg_t _pad_000050; +} pic_widget_cfg_t; + +/* + * BRIDGE, XBRIDGE, PIC register definitions. NOTE: Prior to PIC, registers + * were a 32bit quantity and double word aligned (and only accessable as a + * 32bit word. PIC registers are 64bits and accessable as words or double + * words. PIC registers that have valid bits (ie. not just reserved) in the + * upper 32bits are defined as a union of one 64bit picreg_t and two 32bit + * bridgereg_t so we can access them both ways. + * + * It is generally preferred that hardware registers on the bridge are + * located from C code via this structure. + * + * Generated from Bridge spec dated 04oct95 + */ + +typedef volatile struct bridge_s { + + /* 0x000000-0x00FFFF -- Local Registers */ + + /* 0x000000-0x000057 -- Standard Widget Configuration */ + union { + widget_cfg_t xtalk_widget_def; /* 0x000000 */ + pic_widget_cfg_t local_widget_def; /* 0x000000 */ + } u_wid; + + /* 32bit widget register access via the widget_cfg_t */ + #define b_widget u_wid.xtalk_widget_def + + /* 32bit widget register access via the pic_widget_cfg_t */ + #define b_wid_id u_wid.local_widget_def._b_wid_id + #define b_wid_stat u_wid.local_widget_def.__b_wid_stat + #define b_wid_err_upper u_wid.local_widget_def._b_wid_err_upper + #define b_wid_err_lower u_wid.local_widget_def.__b_wid_err_lower + #define b_wid_control u_wid.local_widget_def.__b_wid_control + #define b_wid_req_timeout u_wid.local_widget_def._b_wid_req_timeout + #define b_wid_int_upper u_wid.local_widget_def._b_wid_int_upper + #define b_wid_int_lower u_wid.local_widget_def.__b_wid_int_lower + #define b_wid_err_cmdword u_wid.local_widget_def._b_wid_err_cmdword + #define b_wid_llp u_wid.local_widget_def._b_wid_llp + #define b_wid_tflush u_wid.local_widget_def._b_wid_tflush + + /* 64bit widget register access via the pic_widget_cfg_t */ + #define p_wid_stat_64 u_wid.local_widget_def.__p_wid_stat_64 + #define p_wid_err_64 u_wid.local_widget_def.__p_wid_err_64 + #define p_wid_control_64 u_wid.local_widget_def.__p_wid_control_64 + #define p_wid_int_64 u_wid.local_widget_def.__p_wid_int_64 + + /* 0x000058-0x00007F -- Bridge-specific Widget Configuration */ + bridgereg_t b_wid_aux_err; /* 0x00005C */ + bridgereg_t _pad_000058; + + bridgereg_t b_wid_resp_upper; /* 0x000064 */ + bridgereg_t _pad_000060; + + union { + picreg_t _p_wid_resp_lower; /* 0x000068 */ + struct { + bridgereg_t _b_wid_resp_lower; /* 0x00006C */ + bridgereg_t _b_pad_000068; + } _b; + } u_wid_resp_lower; + #define p_wid_resp_64 u_wid_resp_lower._p_wid_resp_lower + #define b_wid_resp_lower u_wid_resp_lower._b._b_wid_resp_lower + + bridgereg_t b_wid_tst_pin_ctrl; /* 0x000074 */ + bridgereg_t _pad_000070; + + union { + picreg_t _p_addr_lkerr; /* 0x000078 */ + struct { + bridgereg_t _b_pad_00007C; + bridgereg_t _b_pad_000078; + } _b; + } u_addr_lkerr; + #define p_addr_lkerr_64 u_addr_lkerr._p_addr_lkerr + + /* 0x000080-0x00008F -- PMU */ + bridgereg_t b_dir_map; /* 0x000084 */ + bridgereg_t _pad_000080; + + bridgereg_t _pad_00008C; + bridgereg_t _pad_000088; + + /* 0x000090-0x00009F -- SSRAM */ + bridgereg_t b_ram_perr_or_map_fault;/* 0x000094 */ + bridgereg_t _pad_000090; + #define b_ram_perr b_ram_perr_or_map_fault /* Bridge */ + #define b_map_fault b_ram_perr_or_map_fault /* Xbridge & PIC */ + + bridgereg_t _pad_00009C; + bridgereg_t _pad_000098; + + /* 0x0000A0-0x0000AF -- Arbitration */ + bridgereg_t b_arb; /* 0x0000A4 */ + bridgereg_t _pad_0000A0; + + bridgereg_t _pad_0000AC; + bridgereg_t _pad_0000A8; + + /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */ + union { + picreg_t _p_ate_parity_err; /* 0x0000B0 */ + struct { + bridgereg_t _b_nic; /* 0x0000B4 */ + bridgereg_t _b_pad_0000B0; + } _b; + } u_ate_parity_err_or_nic; + #define p_ate_parity_err_64 u_ate_parity_err_or_nic._p_ate_parity_err + #define b_nic u_ate_parity_err_or_nic._b._b_nic + + bridgereg_t _pad_0000BC; + bridgereg_t _pad_0000B8; + + /* 0x0000C0-0x0000FF -- PCI/GIO */ + bridgereg_t b_bus_timeout; /* 0x0000C4 */ + bridgereg_t _pad_0000C0; + #define b_pci_bus_timeout b_bus_timeout + + bridgereg_t b_pci_cfg; /* 0x0000CC */ + bridgereg_t _pad_0000C8; + + bridgereg_t b_pci_err_upper; /* 0x0000D4 */ + bridgereg_t _pad_0000D0; + #define b_gio_err_upper b_pci_err_upper + + union { + picreg_t _p_pci_err_lower; /* 0x0000D8 */ + struct { + bridgereg_t _b_pci_err_lower; /* 0x0000DC */ + bridgereg_t _b_pad_0000D8; + } _b; + } u_pci_err_lower; + #define p_pci_err_64 u_pci_err_lower._p_pci_err_lower + #define b_pci_err_lower u_pci_err_lower._b._b_pci_err_lower + #define b_gio_err_lower b_pci_err_lower + + bridgereg_t _pad_0000E0[8]; + + /* 0x000100-0x0001FF -- Interrupt */ + union { + picreg_t _p_int_status; /* 0x000100 */ + struct { + bridgereg_t _b_int_status; /* 0x000104 */ + bridgereg_t _b_pad_000100; + } _b; + } u_int_status; + #define p_int_status_64 u_int_status._p_int_status + #define b_int_status u_int_status._b._b_int_status + + union { + picreg_t _p_int_enable; /* 0x000108 */ + struct { + bridgereg_t _b_int_enable; /* 0x00010C */ + bridgereg_t _b_pad_000108; + } _b; + } u_int_enable; + #define p_int_enable_64 u_int_enable._p_int_enable + #define b_int_enable u_int_enable._b._b_int_enable + + union { + picreg_t _p_int_rst_stat; /* 0x000110 */ + struct { + bridgereg_t _b_int_rst_stat; /* 0x000114 */ + bridgereg_t _b_pad_000110; + } _b; + } u_int_rst_stat; + #define p_int_rst_stat_64 u_int_rst_stat._p_int_rst_stat + #define b_int_rst_stat u_int_rst_stat._b._b_int_rst_stat + + bridgereg_t b_int_mode; /* 0x00011C */ + bridgereg_t _pad_000118; + + bridgereg_t b_int_device; /* 0x000124 */ + bridgereg_t _pad_000120; + + bridgereg_t b_int_host_err; /* 0x00012C */ + bridgereg_t _pad_000128; + + union { + picreg_t _p_int_addr[8]; /* 0x0001{30,,,68} */ + struct { + bridgereg_t addr; /* 0x0001{34,,,6C} */ + bridgereg_t _b_pad; + } _b[8]; + } u_int_addr; + #define p_int_addr_64 u_int_addr._p_int_addr + #define b_int_addr u_int_addr._b + + union { + picreg_t _p_err_int_view; /* 0x000170 */ + struct { + bridgereg_t _b_err_int_view; /* 0x000174 */ + bridgereg_t _b_pad_000170; + } _b; + } u_err_int_view; + #define p_err_int_view_64 u_err_int_view._p_err_int_view + #define b_err_int_view u_err_int_view._b._b_err_int_view + + union { + picreg_t _p_mult_int; /* 0x000178 */ + struct { + bridgereg_t _b_mult_int; /* 0x00017C */ + bridgereg_t _b_pad_000178; + } _b; + } u_mult_int; + #define p_mult_int_64 u_mult_int._p_mult_int + #define b_mult_int u_mult_int._b._b_mult_int + + struct { + bridgereg_t intr; /* 0x0001{84,,,BC} */ + bridgereg_t __pad; + } b_force_always[8]; + + struct { + bridgereg_t intr; /* 0x0001{C4,,,FC} */ + bridgereg_t __pad; + } b_force_pin[8]; + + /* 0x000200-0x0003FF -- Device */ + struct { + bridgereg_t reg; /* 0x0002{04,,,3C} */ + bridgereg_t __pad; + } b_device[8]; + + struct { + bridgereg_t reg; /* 0x0002{44,,,7C} */ + bridgereg_t __pad; + } b_wr_req_buf[8]; + + struct { + bridgereg_t reg; /* 0x0002{84,,,8C} */ + bridgereg_t __pad; + } b_rrb_map[2]; + #define b_even_resp b_rrb_map[0].reg /* 0x000284 */ + #define b_odd_resp b_rrb_map[1].reg /* 0x00028C */ + + bridgereg_t b_resp_status; /* 0x000294 */ + bridgereg_t _pad_000290; + + bridgereg_t b_resp_clear; /* 0x00029C */ + bridgereg_t _pad_000298; + + bridgereg_t _pad_0002A0[24]; + + /* Xbridge/PIC only */ + union { + struct { + picreg_t lower; /* 0x0003{08,,,F8} */ + picreg_t upper; /* 0x0003{00,,,F0} */ + } _p[16]; + struct { + bridgereg_t upper; /* 0x0003{04,,,F4} */ + bridgereg_t _b_pad1; + bridgereg_t lower; /* 0x0003{0C,,,FC} */ + bridgereg_t _b_pad2; + } _b[16]; + } u_buf_addr_match; + #define p_buf_addr_match_64 u_buf_addr_match._p + #define b_buf_addr_match u_buf_addr_match._b + + /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */ + struct { + bridgereg_t flush_w_touch; /* 0x000{404,,,5C4} */ + bridgereg_t __pad1; + bridgereg_t flush_wo_touch; /* 0x000{40C,,,5CC} */ + bridgereg_t __pad2; + bridgereg_t inflight; /* 0x000{414,,,5D4} */ + bridgereg_t __pad3; + bridgereg_t prefetch; /* 0x000{41C,,,5DC} */ + bridgereg_t __pad4; + bridgereg_t total_pci_retry; /* 0x000{424,,,5E4} */ + bridgereg_t __pad5; + bridgereg_t max_pci_retry; /* 0x000{42C,,,5EC} */ + bridgereg_t __pad6; + bridgereg_t max_latency; /* 0x000{434,,,5F4} */ + bridgereg_t __pad7; + bridgereg_t clear_all; /* 0x000{43C,,,5FC} */ + bridgereg_t __pad8; + } b_buf_count[8]; + + /* + * "PCI/X registers that are specific to PIC". See pic.h. + */ + + /* 0x000600-0x0009FF -- PCI/X registers */ + picreg_t p_pcix_bus_err_addr_64; /* 0x000600 */ + picreg_t p_pcix_bus_err_attr_64; /* 0x000608 */ + picreg_t p_pcix_bus_err_data_64; /* 0x000610 */ + picreg_t p_pcix_pio_split_addr_64; /* 0x000618 */ + picreg_t p_pcix_pio_split_attr_64; /* 0x000620 */ + picreg_t p_pcix_dma_req_err_attr_64; /* 0x000628 */ + picreg_t p_pcix_dma_req_err_addr_64; /* 0x000630 */ + picreg_t p_pcix_timeout_64; /* 0x000638 */ + + picreg_t _pad_000600[120]; + + /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */ + struct { + picreg_t p_buf_attr; /* 0X000{A08,,,AF8} */ + picreg_t p_buf_addr; /* 0x000{A00,,,AF0} */ + } p_pcix_read_buf_64[16]; + + struct { + picreg_t p_buf_attr; /* 0x000{B08,,,BE8} */ + picreg_t p_buf_addr; /* 0x000{B00,,,BE0} */ + picreg_t __pad1; /* 0x000{B18,,,BF8} */ + picreg_t p_buf_valid; /* 0x000{B10,,,BF0} */ + } p_pcix_write_buf_64[8]; + + /* + * end "PCI/X registers that are specific to PIC" + */ + + char _pad_000c00[0x010000 - 0x000c00]; + + /* 0x010000-0x011fff -- Internal Address Translation Entry RAM */ + /* + * Xbridge and PIC have 1024 internal ATE's and the Bridge has 128. + * Make enough room for the Xbridge/PIC ATE's and depend on runtime + * checks to limit access to bridge ATE's. + * + * In [X]bridge the internal ATE Ram is writen as double words only, + * but due to internal design issues it is read back as single words. + * i.e: + * b_int_ate_ram[index].hi.rd << 32 | xb_int_ate_ram_lo[index].rd + */ + union { + bridge_ate_t wr; /* write-only */ /* 0x01{0000,,,1FF8} */ + struct { + bridgereg_t rd; /* read-only */ /* 0x01{0004,,,1FFC} */ + bridgereg_t _p_pad; + } hi; + } b_int_ate_ram[XBRIDGE_INTERNAL_ATES]; + #define b_int_ate_ram_lo(idx) b_int_ate_ram[idx+512].hi.rd + + /* 0x012000-0x013fff -- Internal Address Translation Entry RAM LOW */ + struct { + bridgereg_t rd; /* read-only */ /* 0x01{2004,,,3FFC} */ + bridgereg_t _p_pad; + } xb_int_ate_ram_lo[XBRIDGE_INTERNAL_ATES]; + + char _pad_014000[0x18000 - 0x014000]; + + /* 0x18000-0x197F8 -- PIC Write Request Ram */ + /* 0x18000 - 0x187F8 */ + picreg_t p_wr_req_lower[PIC_WR_REQ_BUFSIZE]; + /* 0x18800 - 0x18FF8 */ + picreg_t p_wr_req_upper[PIC_WR_REQ_BUFSIZE]; + /* 0x19000 - 0x197F8 */ + picreg_t p_wr_req_parity[PIC_WR_REQ_BUFSIZE]; + + char _pad_019800[0x20000 - 0x019800]; + + /* 0x020000-0x027FFF -- PCI Device Configuration Spaces */ + union { /* make all access sizes available. */ + uchar_t c[0x1000 / 1]; /* 0x02{0000,,,7FFF} */ + uint16_t s[0x1000 / 2]; /* 0x02{0000,,,7FFF} */ + uint32_t l[0x1000 / 4]; /* 0x02{0000,,,7FFF} */ + uint64_t d[0x1000 / 8]; /* 0x02{0000,,,7FFF} */ + union { + uchar_t c[0x100 / 1]; + uint16_t s[0x100 / 2]; + uint32_t l[0x100 / 4]; + uint64_t d[0x100 / 8]; + } f[8]; + } b_type0_cfg_dev[8]; /* 0x02{0000,,,7FFF} */ + + /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */ + union { /* make all access sizes available. */ + uchar_t c[0x1000 / 1]; + uint16_t s[0x1000 / 2]; + uint32_t l[0x1000 / 4]; + uint64_t d[0x1000 / 8]; + union { + uchar_t c[0x100 / 1]; + uint16_t s[0x100 / 2]; + uint32_t l[0x100 / 4]; + uint64_t d[0x100 / 8]; + } f[8]; + } b_type1_cfg; /* 0x028000-0x029000 */ + + char _pad_029000[0x007000]; /* 0x029000-0x030000 */ + + /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */ + union { + uchar_t c[8 / 1]; + uint16_t s[8 / 2]; + uint32_t l[8 / 4]; + uint64_t d[8 / 8]; + } b_pci_iack; /* 0x030000-0x030007 */ + + uchar_t _pad_030007[0x04fff8]; /* 0x030008-0x07FFFF */ + + /* 0x080000-0x0FFFFF -- External Address Translation Entry RAM */ + bridge_ate_t b_ext_ate_ram[0x10000]; + + /* 0x100000-0x1FFFFF -- Reserved */ + char _pad_100000[0x200000-0x100000]; + + /* 0x200000-0xBFFFFF -- PCI/GIO Device Spaces */ + union { /* make all access sizes available. */ + uchar_t c[0x100000 / 1]; + uint16_t s[0x100000 / 2]; + uint32_t l[0x100000 / 4]; + uint64_t d[0x100000 / 8]; + } b_devio_raw[10]; + + /* b_devio macro is a bit strange; it reflects the + * fact that the Bridge ASIC provides 2M for the + * first two DevIO windows and 1M for the other six. + */ + #define b_devio(n) b_devio_raw[((n)<2)?(n*2):(n+2)] + + /* 0xC00000-0xFFFFFF -- External Flash Proms 1,0 */ + union { /* make all access sizes available. */ + uchar_t c[0x400000 / 1]; /* read-only */ + uint16_t s[0x400000 / 2]; /* read-write */ + uint32_t l[0x400000 / 4]; /* read-only */ + uint64_t d[0x400000 / 8]; /* read-only */ + } b_external_flash; +} bridge_t; + +#else /* CONFIG_IA64_SGI_SN1 */ + typedef volatile struct bridge_s { @@ -311,6 +839,12 @@ uint16_t s[0x1000 / 2]; uint32_t l[0x1000 / 4]; uint64_t d[0x1000 / 8]; + union { + uchar_t c[0x100 / 1]; + uint16_t s[0x100 / 2]; + uint32_t l[0x100 / 4]; + uint64_t d[0x100 / 8]; + } f[8]; } b_type1_cfg; /* 0x028000-0x029000 */ char _pad_029000[0x007000]; /* 0x029000-0x030000 */ @@ -354,286 +888,7 @@ } b_external_flash; /* 0xC00000 */ } bridge_t; -#else - -/* - * Field formats for Error Command Word and Auxillary Error Command Word - * of bridge. - */ -typedef struct bridge_err_cmdword_s { - union { - uint32_t cmd_word; - struct { - uint32_t didn:4, /* Destination ID */ - sidn:4, /* SOurce ID */ - pactyp:4, /* Packet type */ - tnum:5, /* Trans Number */ - coh:1, /* Coh Transacti */ - ds:2, /* Data size */ - gbr:1, /* GBR enable */ - vbpm:1, /* VBPM message */ - error:1, /* Error occurred */ - barr:1, /* Barrier op */ - rsvd:8; - } berr_st; - } berr_un; -} bridge_err_cmdword_t; - -typedef volatile struct bridge_s { - - /* Local Registers 0x000000-0x00FFFF */ - - /* standard widget configuration 0x000000-0x000057 */ - widget_cfg_t b_widget; /* 0x000000 */ - - /* helper fieldnames for accessing bridge widget */ - -#define b_wid_id b_widget.w_id -#define b_wid_stat b_widget.w_status -#define b_wid_err_upper b_widget.w_err_upper_addr -#define b_wid_err_lower b_widget.w_err_lower_addr -#define b_wid_control b_widget.w_control -#define b_wid_req_timeout b_widget.w_req_timeout -#define b_wid_int_upper b_widget.w_intdest_upper_addr -#define b_wid_int_lower b_widget.w_intdest_lower_addr -#define b_wid_err_cmdword b_widget.w_err_cmd_word -#define b_wid_llp b_widget.w_llp_cfg -#define b_wid_tflush b_widget.w_tflush - - /* bridge-specific widget configuration 0x000058-0x00007F */ - bridgereg_t _pad_000058; - bridgereg_t b_wid_aux_err; /* 0x00005C */ - bridgereg_t _pad_000060; - bridgereg_t b_wid_resp_upper; /* 0x000064 */ - bridgereg_t _pad_000068; - bridgereg_t b_wid_resp_lower; /* 0x00006C */ - bridgereg_t _pad_000070; - bridgereg_t b_wid_tst_pin_ctrl; /* 0x000074 */ - bridgereg_t _pad_000078[2]; - - /* PMU & Map 0x000080-0x00008F */ - bridgereg_t _pad_000080; - bridgereg_t b_dir_map; /* 0x000084 */ - bridgereg_t _pad_000088[2]; - - /* SSRAM 0x000090-0x00009F */ - bridgereg_t _pad_000090; - bridgereg_t b_ram_perr_or_map_fault;/* 0x000094 */ -#define b_ram_perr b_ram_perr_or_map_fault /* Bridge */ -#define b_map_fault b_ram_perr_or_map_fault /* Xbridge */ - bridgereg_t _pad_000098[2]; - - /* Arbitration 0x0000A0-0x0000AF */ - bridgereg_t _pad_0000A0; - bridgereg_t b_arb; /* 0x0000A4 */ - bridgereg_t _pad_0000A8[2]; - - /* Number In A Can 0x0000B0-0x0000BF */ - bridgereg_t _pad_0000B0; - bridgereg_t b_nic; /* 0x0000B4 */ - bridgereg_t _pad_0000B8[2]; - - /* PCI/GIO 0x0000C0-0x0000FF */ - bridgereg_t _pad_0000C0; - bridgereg_t b_bus_timeout; /* 0x0000C4 */ -#define b_pci_bus_timeout b_bus_timeout - - bridgereg_t _pad_0000C8; - bridgereg_t b_pci_cfg; /* 0x0000CC */ - bridgereg_t _pad_0000D0; - bridgereg_t b_pci_err_upper; /* 0x0000D4 */ - bridgereg_t _pad_0000D8; - bridgereg_t b_pci_err_lower; /* 0x0000DC */ - bridgereg_t _pad_0000E0[8]; -#define b_gio_err_lower b_pci_err_lower -#define b_gio_err_upper b_pci_err_upper - - /* Interrupt 0x000100-0x0001FF */ - bridgereg_t _pad_000100; - bridgereg_t b_int_status; /* 0x000104 */ - bridgereg_t _pad_000108; - bridgereg_t b_int_enable; /* 0x00010C */ - bridgereg_t _pad_000110; - bridgereg_t b_int_rst_stat; /* 0x000114 */ - bridgereg_t _pad_000118; - bridgereg_t b_int_mode; /* 0x00011C */ - bridgereg_t _pad_000120; - bridgereg_t b_int_device; /* 0x000124 */ - bridgereg_t _pad_000128; - bridgereg_t b_int_host_err; /* 0x00012C */ - - struct { - bridgereg_t __pad; /* 0x0001{30,,,68} */ - bridgereg_t addr; /* 0x0001{34,,,6C} */ - } b_int_addr[8]; /* 0x000130 */ - - bridgereg_t _pad_000170; - bridgereg_t b_err_int_view; /* 0x000174 */ - bridgereg_t _pad_000178; - bridgereg_t b_mult_int; /* 0x00017c */ - - struct { - bridgereg_t __pad; /* 0x0001{80,,,B8} */ - bridgereg_t intr; /* 0x0001{84,,,BC} */ - } b_force_always[8]; /* 0x000180 */ - - struct { - bridgereg_t __pad; /* 0x0001{C0,,,F8} */ - bridgereg_t intr; /* 0x0001{C4,,,FC} */ - } b_force_pin[8]; /* 0x0001C0 */ - - /* Device 0x000200-0x0003FF */ - struct { - bridgereg_t __pad; /* 0x0002{00,,,38} */ - bridgereg_t reg; /* 0x0002{04,,,3C} */ - } b_device[8]; /* 0x000200 */ - - struct { - bridgereg_t __pad; /* 0x0002{40,,,78} */ - bridgereg_t reg; /* 0x0002{44,,,7C} */ - } b_wr_req_buf[8]; /* 0x000240 */ - - struct { - bridgereg_t __pad; /* 0x0002{80,,,88} */ - bridgereg_t reg; /* 0x0002{84,,,8C} */ - } b_rrb_map[2]; /* 0x000280 */ -#define b_even_resp b_rrb_map[0].reg /* 0x000284 */ -#define b_odd_resp b_rrb_map[1].reg /* 0x00028C */ - - bridgereg_t _pad_000290; - bridgereg_t b_resp_status; /* 0x000294 */ - bridgereg_t _pad_000298; - bridgereg_t b_resp_clear; /* 0x00029C */ - - bridgereg_t _pad_0002A0[24]; - - /* Xbridge only */ - struct { - bridgereg_t __pad1; /* 0x0003{00,,,F0} */ - bridgereg_t upper; /* 0x0003{04,,,F4} */ - bridgereg_t __pad2; /* 0x0003{08,,,F8} */ - bridgereg_t lower; /* 0x0003{0C,,,FC} */ - } b_buf_addr_match[16]; - - /* Performance Monitor Registers (even only) */ - struct { - bridgereg_t __pad1; /* 0x000400,,,5C0 */ - bridgereg_t flush_w_touch; /* 0x000404,,,5C4 */ - bridgereg_t __pad2; /* 0x000408,,,5C8 */ - bridgereg_t flush_wo_touch; /* 0x00040C,,,5CC */ - bridgereg_t __pad3; /* 0x000410,,,5D0 */ - bridgereg_t inflight; /* 0x000414,,,5D4 */ - bridgereg_t __pad4; /* 0x000418,,,5D8 */ - bridgereg_t prefetch; /* 0x00041C,,,5DC */ - bridgereg_t __pad5; /* 0x000420,,,5E0 */ - bridgereg_t total_pci_retry; /* 0x000424,,,5E4 */ - bridgereg_t __pad6; /* 0x000428,,,5E8 */ - bridgereg_t max_pci_retry; /* 0x00042C,,,5EC */ - bridgereg_t __pad7; /* 0x000430,,,5F0 */ - bridgereg_t max_latency; /* 0x000434,,,5F4 */ - bridgereg_t __pad8; /* 0x000438,,,5F8 */ - bridgereg_t clear_all; /* 0x00043C,,,5FC */ - } b_buf_count[8]; - - char _pad_000600[0x010000 - 0x000600]; - - /* - * The Xbridge has 1024 internal ATE's and the Bridge has 128. - * Make enough room for the Xbridge ATE's and depend on runtime - * checks to limit access to bridge ATE's. - */ - - /* Internal Address Translation Entry RAM 0x010000-0x011fff */ - union { - bridge_ate_t wr; /* write-only */ - struct { - bridgereg_t _p_pad; - bridgereg_t rd; /* read-only */ - } hi; - } b_int_ate_ram[XBRIDGE_INTERNAL_ATES]; - -#define b_int_ate_ram_lo(idx) b_int_ate_ram[idx+512].hi.rd - - /* the xbridge read path for internal ates starts at 0x12000. - * I don't believe we ever try to read the ates. - */ - /* Internal Address Translation Entry RAM LOW 0x012000-0x013fff */ - struct { - bridgereg_t _p_pad; - bridgereg_t rd; /* read-only */ - } xb_int_ate_ram_lo[XBRIDGE_INTERNAL_ATES]; - - char _pad_014000[0x20000 - 0x014000]; - - /* PCI Device Configuration Spaces 0x020000-0x027FFF */ - union { /* make all access sizes available. */ - uchar_t c[0x1000 / 1]; - uint16_t s[0x1000 / 2]; - uint32_t l[0x1000 / 4]; - uint64_t d[0x1000 / 8]; - union { - uchar_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } b_type0_cfg_dev[8]; /* 0x020000 */ - - - /* PCI Type 1 Configuration Space 0x028000-0x028FFF */ - union { /* make all access sizes available. */ - uchar_t c[0x1000 / 1]; - uint16_t s[0x1000 / 2]; - uint32_t l[0x1000 / 4]; - uint64_t d[0x1000 / 8]; - } b_type1_cfg; /* 0x028000-0x029000 */ - - char _pad_029000[0x007000]; /* 0x029000-0x030000 */ - - /* PCI Interrupt Acknowledge Cycle 0x030000 */ - union { - uchar_t c[8 / 1]; - uint16_t s[8 / 2]; - uint32_t l[8 / 4]; - uint64_t d[8 / 8]; - } b_pci_iack; /* 0x030000 */ - - uchar_t _pad_030007[0x04fff8]; /* 0x030008-0x07FFFF */ - - /* External Address Translation Entry RAM 0x080000-0x0FFFFF */ - bridge_ate_t b_ext_ate_ram[0x10000]; - - /* Reserved 0x100000-0x1FFFFF */ - char _pad_100000[0x200000-0x100000]; - - /* PCI/GIO Device Spaces 0x200000-0xBFFFFF */ - union { /* make all access sizes available. */ - uchar_t c[0x100000 / 1]; - uint16_t s[0x100000 / 2]; - uint32_t l[0x100000 / 4]; - uint64_t d[0x100000 / 8]; - } b_devio_raw[10]; /* 0x200000 */ - - /* b_devio macro is a bit strange; it reflects the - * fact that the Bridge ASIC provides 2M for the - * first two DevIO windows and 1M for the other six. - */ -#define b_devio(n) b_devio_raw[((n)<2)?(n*2):(n+2)] - - /* External Flash Proms 1,0 0xC00000-0xFFFFFF */ - union { /* make all access sizes available. */ - uchar_t c[0x400000 / 1]; /* read-only */ - uint16_t s[0x400000 / 2]; /* read-write */ - uint32_t l[0x400000 / 4]; /* read-only */ - uint64_t d[0x400000 / 8]; /* read-only */ - } b_external_flash; /* 0xC00000 */ -} bridge_t; - -#endif - - - - +#endif /* CONFIG_IA64_SGI_SN1 */ #define berr_field berr_un.berr_st @@ -873,7 +1128,12 @@ /* end of Performance Monitor Registers */ -/* Byte offset macros for Bridge I/O space */ +/* Byte offset macros for Bridge I/O space. + * + * NOTE: Where applicable please use the PCIBR_xxx or PCIBRIDGE_xxx + * macros (below) as they will handle [X]Bridge and PIC. For example, + * PCIBRIDGE_TYPE0_CFG_DEV0() vs BRIDGE_TYPE0_CFG_DEV0 + */ #define BRIDGE_ATE_RAM 0x00010000 /* Internal Addr Xlat Ram */ @@ -905,7 +1165,55 @@ #ifndef __ASSEMBLY__ #define BRIDGE_DEVIO(x) ((x)<=1 ? BRIDGE_DEVIO0+(x)*BRIDGE_DEVIO_2MB : BRIDGE_DEVIO2+((x)-2)*BRIDGE_DEVIO_1MB) -#endif /* __ASSEMBLY__ */ + +/* + * The device space macros for PIC are more complicated because the PIC has + * two PCI/X bridges under the same widget. For PIC bus 0, the addresses are + * basically the same as for the [X]Bridge. For PIC bus 1, the addresses are + * offset by 0x800000. Here are two sets of macros. They are + * "PCIBRIDGE_xxx" that return the address based on the supplied bus number + * and also equivalent "PCIBR_xxx" macros that may be used with a + * pcibr_soft_s structure. Both should work with all bridges. + */ +#define PIC_BUS1_OFFSET 0x800000 + +#define PCIBRIDGE_TYPE0_CFG_DEV0(busnum) \ + ((busnum) ? BRIDGE_TYPE0_CFG_DEV0 + PIC_BUS1_OFFSET : \ + BRIDGE_TYPE0_CFG_DEV0) +#define PCIBRIDGE_TYPE1_CFG(busnum) \ + ((busnum) ? BRIDGE_TYPE1_CFG + PIC_BUS1_OFFSET : BRIDGE_TYPE1_CFG) +#define PCIBRIDGE_TYPE0_CFG_DEV(busnum, s) \ + (PCIBRIDGE_TYPE0_CFG_DEV0(busnum)+\ + (s)*BRIDGE_TYPE0_CFG_SLOT_OFF) +#define PCIBRIDGE_TYPE0_CFG_DEVF(busnum, s, f) \ + (PCIBRIDGE_TYPE0_CFG_DEV0(busnum)+\ + (s)*BRIDGE_TYPE0_CFG_SLOT_OFF+\ + (f)*BRIDGE_TYPE0_CFG_FUNC_OFF) +#define PCIBRIDGE_DEVIO0(busnum) ((busnum) ? \ + (BRIDGE_DEVIO0 + PIC_BUS1_OFFSET) : BRIDGE_DEVIO0) +#define PCIBRIDGE_DEVIO1(busnum) ((busnum) ? \ + (BRIDGE_DEVIO1 + PIC_BUS1_OFFSET) : BRIDGE_DEVIO1) +#define PCIBRIDGE_DEVIO2(busnum) ((busnum) ? \ + (BRIDGE_DEVIO2 + PIC_BUS1_OFFSET) : BRIDGE_DEVIO2) +#define PCIBRIDGE_DEVIO(busnum, x) \ + ((x)<=1 ? PCIBRIDGE_DEVIO0(busnum)+(x)*BRIDGE_DEVIO_2MB : \ + PCIBRIDGE_DEVIO2(busnum)+((x)-2)*BRIDGE_DEVIO_1MB) + +#define PCIBR_BRIDGE_DEVIO0(ps) PCIBRIDGE_DEVIO0((ps)->bs_busnum) +#define PCIBR_BRIDGE_DEVIO1(ps) PCIBRIDGE_DEVIO1((ps)->bs_busnum) +#define PCIBR_BRIDGE_DEVIO2(ps) PCIBRIDGE_DEVIO2((ps)->bs_busnum) +#define PCIBR_BRIDGE_DEVIO(ps, s) PCIBRIDGE_DEVIO((ps)->bs_busnum, s) + +#define PCIBR_TYPE1_CFG(ps) PCIBRIDGE_TYPE1_CFG((ps)->bs_busnum) +#define PCIBR_BUS_TYPE0_CFG_DEV0(ps) PCIBR_TYPE0_CFG_DEV(ps, 0) +#define PCIBR_TYPE0_CFG_DEV(ps, s) \ + ((IS_PIC_SOFT(ps)) ? PCIBRIDGE_TYPE0_CFG_DEV((ps)->bs_busnum, s+1) : \ + PCIBRIDGE_TYPE0_CFG_DEV((ps)->bs_busnum, s)) +#define PCIBR_BUS_TYPE0_CFG_DEVF(ps,s,f) \ + ((IS_PIC_SOFT(ps)) ? PCIBRIDGE_TYPE0_CFG_DEVF((ps)->bs_busnum,(s+1),f) : \ + PCIBRIDGE_TYPE0_CFG_DEVF((ps)->bs_busnum,s,f)) + +#endif /* LANGUAGE_C */ #define BRIDGE_EXTERNAL_FLASH 0x00C00000 /* External Flash PROMS */ @@ -929,6 +1237,17 @@ #define XBRIDGE_REV_A 0x1 #define XBRIDGE_REV_B 0x2 +/* macros to determine bridge type. 'wid' == widget identification */ +#define IS_BRIDGE(wid) (XWIDGET_PART_NUM(wid) == BRIDGE_WIDGET_PART_NUM && \ + XWIDGET_MFG_NUM(wid) == BRIDGE_WIDGET_MFGR_NUM) +#define IS_XBRIDGE(wid) (XWIDGET_PART_NUM(wid) == XBRIDGE_WIDGET_PART_NUM && \ + XWIDGET_MFG_NUM(wid) == XBRIDGE_WIDGET_MFGR_NUM) +#define IS_PIC_BUS0(wid) (XWIDGET_PART_NUM(wid) == PIC_WIDGET_PART_NUM_BUS0 && \ + XWIDGET_MFG_NUM(wid) == PIC_WIDGET_MFGR_NUM) +#define IS_PIC_BUS1(wid) (XWIDGET_PART_NUM(wid) == PIC_WIDGET_PART_NUM_BUS1 && \ + XWIDGET_MFG_NUM(wid) == PIC_WIDGET_MFGR_NUM) +#define IS_PIC_BRIDGE(wid) (IS_PIC_BUS0(wid) || IS_PIC_BUS1(wid)) + /* Part + Rev numbers allows distinction and acscending sequence */ #define BRIDGE_PART_REV_A (BRIDGE_WIDGET_PART_NUM << 4 | BRIDGE_REV_A) #define BRIDGE_PART_REV_B (BRIDGE_WIDGET_PART_NUM << 4 | BRIDGE_REV_B) @@ -938,7 +1257,8 @@ #define XBRIDGE_PART_REV_B (XBRIDGE_WIDGET_PART_NUM << 4 | XBRIDGE_REV_B) /* Bridge widget status register bits definition */ - +#define PIC_STAT_PCIX_SPEED (0x3ull << 34) +#define PIC_STAT_PCIX_ACTIVE (0x1ull << 33) #define BRIDGE_STAT_LLP_REC_CNT (0xFFu << 24) #define BRIDGE_STAT_LLP_TX_CNT (0xFF << 16) #define BRIDGE_STAT_FLASH_SELECT (0x1 << 6) @@ -946,7 +1266,18 @@ #define BRIDGE_STAT_PENDING (0x1F << 0) /* Bridge widget control register bits definition */ -#define BRIDGE_CTRL_FLASH_WR_EN (0x1ul << 31) +#define PIC_CTRL_NO_SNOOP (0x1ull << 62) +#define PIC_CTRL_RELAX_ORDER (0x1ull << 61) +#define PIC_CTRL_BUS_NUM(x) ((unsigned long long)(x) << 48) +#define PIC_CTRL_BUS_NUM_MASK (PIC_CTRL_BUS_NUM(0xff)) +#define PIC_CTRL_DEV_NUM(x) ((unsigned long long)(x) << 43) +#define PIC_CTRL_DEV_NUM_MASK (PIC_CTRL_DEV_NUM(0x1f)) +#define PIC_CTRL_FUN_NUM(x) ((unsigned long long)(x) << 40) +#define PIC_CTRL_FUN_NUM_MASK (PIC_CTRL_FUN_NUM(0x7)) +#define PIC_CTRL_PAR_EN_REQ (0x1ull << 29) +#define PIC_CTRL_PAR_EN_RESP (0x1ull << 30) +#define PIC_CTRL_PAR_EN_ATE (0x1ull << 31) +#define BRIDGE_CTRL_FLASH_WR_EN (0x1ul << 31) /* bridge only */ #define BRIDGE_CTRL_EN_CLK50 (0x1 << 30) #define BRIDGE_CTRL_EN_CLK40 (0x1 << 29) #define BRIDGE_CTRL_EN_CLK33 (0x1 << 28) @@ -970,6 +1301,8 @@ #define BRIDGE_CTRL_CLR_RLLP_CNT (0x1 << 11) #define BRIDGE_CTRL_CLR_TLLP_CNT (0x1 << 10) #define BRIDGE_CTRL_SYS_END (0x1 << 9) +#define BRIDGE_CTRL_PCI_SPEED (0x3 << 4) + #define BRIDGE_CTRL_BUS_SPEED(n) ((n) << 4) #define BRIDGE_CTRL_BUS_SPEED_MASK (BRIDGE_CTRL_BUS_SPEED(0x3)) #define BRIDGE_CTRL_BUS_SPEED_33 0x00 @@ -1023,6 +1356,20 @@ #define BRIDGE_BUS_PCI_RETRY_MASK BRIDGE_BUS_PCI_RETRY_CNT(0x3ff) /* Bridge interrupt status register bits definition */ +#define PIC_ISR_PCIX_SPLIT_MSG_PE (0x1ull << 45) +#define PIC_ISR_PCIX_SPLIT_EMSG (0x1ull << 44) +#define PIC_ISR_PCIX_SPLIT_TO (0x1ull << 43) +#define PIC_ISR_PCIX_UNEX_COMP (0x1ull << 42) +#define PIC_ISR_INT_RAM_PERR (0x1ull << 41) +#define PIC_ISR_PCIX_ARB_ERR (0x1ull << 40) +#define PIC_ISR_PCIX_REQ_TOUT (0x1ull << 39) +#define PIC_ISR_PCIX_TABORT (0x1ull << 38) +#define PIC_ISR_PCIX_PERR (0x1ull << 37) +#define PIC_ISR_PCIX_SERR (0x1ull << 36) +#define PIC_ISR_PCIX_MRETRY (0x1ull << 35) +#define PIC_ISR_PCIX_MTOUT (0x1ull << 34) +#define PIC_ISR_PCIX_DA_PARITY (0x1ull << 33) +#define PIC_ISR_PCIX_AD_PARITY (0x1ull << 32) #define BRIDGE_ISR_MULTI_ERR (0x1u << 31) /* bridge only */ #define BRIDGE_ISR_PMU_ESIZE_FAULT (0x1 << 30) /* bridge only */ #define BRIDGE_ISR_PAGE_FAULT (0x1 << 30) /* xbridge only */ @@ -1058,12 +1405,18 @@ BRIDGE_ISR_LLP_TCTY) #define BRIDGE_ISR_PCIBUS_PIOERR \ - (BRIDGE_ISR_PCI_MST_TIMEOUT|BRIDGE_ISR_PCI_ABORT) + (BRIDGE_ISR_PCI_MST_TIMEOUT|BRIDGE_ISR_PCI_ABORT| \ + PIC_ISR_PCIX_MTOUT|PIC_ISR_PCIX_TABORT) #define BRIDGE_ISR_PCIBUS_ERROR \ (BRIDGE_ISR_PCIBUS_PIOERR|BRIDGE_ISR_PCI_PERR| \ BRIDGE_ISR_PCI_SERR|BRIDGE_ISR_PCI_RETRY_CNT| \ - BRIDGE_ISR_PCI_PARITY) + BRIDGE_ISR_PCI_PARITY|PIC_ISR_PCIX_PERR| \ + PIC_ISR_PCIX_SERR|PIC_ISR_PCIX_MRETRY| \ + PIC_ISR_PCIX_AD_PARITY|PIC_ISR_PCIX_DA_PARITY| \ + PIC_ISR_PCIX_REQ_TOUT|PIC_ISR_PCIX_UNEX_COMP| \ + PIC_ISR_PCIX_SPLIT_TO|PIC_ISR_PCIX_SPLIT_EMSG| \ + PIC_ISR_PCIX_SPLIT_MSG_PE) #define BRIDGE_ISR_XTALK_ERROR \ (BRIDGE_ISR_XREAD_REQ_TIMEOUT|BRIDGE_ISR_XREQ_FIFO_OFLOW|\ @@ -1075,20 +1428,38 @@ #define BRIDGE_ISR_ERRORS \ (BRIDGE_ISR_LINK_ERROR|BRIDGE_ISR_PCIBUS_ERROR| \ BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR| \ - BRIDGE_ISR_PMU_ESIZE_FAULT) + BRIDGE_ISR_PMU_ESIZE_FAULT|PIC_ISR_INT_RAM_PERR) /* * List of Errors which are fatal and kill the sytem */ #define BRIDGE_ISR_ERROR_FATAL \ ((BRIDGE_ISR_XTALK_ERROR & ~BRIDGE_ISR_XREAD_REQ_TIMEOUT)|\ - BRIDGE_ISR_PCI_SERR|BRIDGE_ISR_PCI_PARITY ) + BRIDGE_ISR_PCI_SERR|BRIDGE_ISR_PCI_PARITY| \ + PIC_ISR_PCIX_SERR|PIC_ISR_PCIX_AD_PARITY| \ + PIC_ISR_PCIX_DA_PARITY| \ + PIC_ISR_INT_RAM_PERR|PIC_ISR_PCIX_SPLIT_MSG_PE ) #define BRIDGE_ISR_ERROR_DUMP \ (BRIDGE_ISR_PCIBUS_ERROR|BRIDGE_ISR_PMU_ESIZE_FAULT| \ - BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR) + BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR| \ + PIC_ISR_PCIX_ARB_ERR|PIC_ISR_INT_RAM_PERR) /* Bridge interrupt enable register bits definition */ +#define PIC_IMR_PCIX_SPLIT_MSG_PE PIC_ISR_PCIX_SPLIT_MSG_PE +#define PIC_IMR_PCIX_SPLIT_EMSG PIC_ISR_PCIX_SPLIT_EMSG +#define PIC_IMR_PCIX_SPLIT_TO PIC_ISR_PCIX_SPLIT_TO +#define PIC_IMR_PCIX_UNEX_COMP PIC_ISR_PCIX_UNEX_COMP +#define PIC_IMR_INT_RAM_PERR PIC_ISR_INT_RAM_PERR +#define PIC_IMR_PCIX_ARB_ERR PIC_ISR_PCIX_ARB_ERR +#define PIC_IMR_PCIX_REQ_TOUR PIC_ISR_PCIX_REQ_TOUT +#define PIC_IMR_PCIX_TABORT PIC_ISR_PCIX_TABORT +#define PIC_IMR_PCIX_PERR PIC_ISR_PCIX_PERR +#define PIC_IMR_PCIX_SERR PIC_ISR_PCIX_SERR +#define PIC_IMR_PCIX_MRETRY PIC_ISR_PCIX_MRETRY +#define PIC_IMR_PCIX_MTOUT PIC_ISR_PCIX_MTOUT +#define PIC_IMR_PCIX_DA_PARITY PIC_ISR_PCIX_DA_PARITY +#define PIC_IMR_PCIX_AD_PARITY PIC_ISR_PCIX_AD_PARITY #define BRIDGE_IMR_UNEXP_RESP BRIDGE_ISR_UNEXP_RESP #define BRIDGE_IMR_PMU_ESIZE_FAULT BRIDGE_ISR_PMU_ESIZE_FAULT #define BRIDGE_IMR_BAD_XRESP_PKT BRIDGE_ISR_BAD_XRESP_PKT @@ -1116,7 +1487,46 @@ #define BRIDGE_IMR_INT_MSK BRIDGE_ISR_INT_MSK #define BRIDGE_IMR_INT(x) BRIDGE_ISR_INT(x) -/* Bridge interrupt reset register bits definition */ +/* + * Bridge interrupt reset register bits definition. Note, PIC can + * reset indiviual error interrupts, BRIDGE & XBRIDGE can only do + * groups of them. + */ +#define PIC_IRR_PCIX_SPLIT_MSG_PE PIC_ISR_PCIX_SPLIT_MSG_PE +#define PIC_IRR_PCIX_SPLIT_EMSG PIC_ISR_PCIX_SPLIT_EMSG +#define PIC_IRR_PCIX_SPLIT_TO PIC_ISR_PCIX_SPLIT_TO +#define PIC_IRR_PCIX_UNEX_COMP PIC_ISR_PCIX_UNEX_COMP +#define PIC_IRR_INT_RAM_PERR PIC_ISR_INT_RAM_PERR +#define PIC_IRR_PCIX_ARB_ERR PIC_ISR_PCIX_ARB_ERR +#define PIC_IRR_PCIX_REQ_TOUT PIC_ISR_PCIX_REQ_TOUT +#define PIC_IRR_PCIX_TABORT PIC_ISR_PCIX_TABORT +#define PIC_IRR_PCIX_PERR PIC_ISR_PCIX_PERR +#define PIC_IRR_PCIX_SERR PIC_ISR_PCIX_SERR +#define PIC_IRR_PCIX_MRETRY PIC_ISR_PCIX_MRETRY +#define PIC_IRR_PCIX_MTOUT PIC_ISR_PCIX_MTOUT +#define PIC_IRR_PCIX_DA_PARITY PIC_ISR_PCIX_DA_PARITY +#define PIC_IRR_PCIX_AD_PARITY PIC_ISR_PCIX_AD_PARITY +#define PIC_IRR_PAGE_FAULT BRIDGE_ISR_PAGE_FAULT +#define PIC_IRR_UNEXP_RESP BRIDGE_ISR_UNEXP_RESP +#define PIC_IRR_BAD_XRESP_PKT BRIDGE_ISR_BAD_XRESP_PKT +#define PIC_IRR_BAD_XREQ_PKT BRIDGE_ISR_BAD_XREQ_PKT +#define PIC_IRR_RESP_XTLK_ERR BRIDGE_ISR_RESP_XTLK_ERR +#define PIC_IRR_REQ_XTLK_ERR BRIDGE_ISR_REQ_XTLK_ERR +#define PIC_IRR_INVLD_ADDR BRIDGE_ISR_INVLD_ADDR +#define PIC_IRR_UNSUPPORTED_XOP BRIDGE_ISR_UNSUPPORTED_XOP +#define PIC_IRR_XREQ_FIFO_OFLOW BRIDGE_ISR_XREQ_FIFO_OFLOW +#define PIC_IRR_LLP_REC_SNERR BRIDGE_ISR_LLP_REC_SNERR +#define PIC_IRR_LLP_REC_CBERR BRIDGE_ISR_LLP_REC_CBERR +#define PIC_IRR_LLP_RCTY BRIDGE_ISR_LLP_RCTY +#define PIC_IRR_LLP_TX_RETRY BRIDGE_ISR_LLP_TX_RETRY +#define PIC_IRR_LLP_TCTY BRIDGE_ISR_LLP_TCTY +#define PIC_IRR_PCI_ABORT BRIDGE_ISR_PCI_ABORT +#define PIC_IRR_PCI_PARITY BRIDGE_ISR_PCI_PARITY +#define PIC_IRR_PCI_SERR BRIDGE_ISR_PCI_SERR +#define PIC_IRR_PCI_PERR BRIDGE_ISR_PCI_PERR +#define PIC_IRR_PCI_MST_TIMEOUT BRIDGE_ISR_PCI_MST_TIMEOUT +#define PIC_IRR_PCI_RETRY_CNT BRIDGE_ISR_PCI_RETRY_CNT +#define PIC_IRR_XREAD_REQ_TIMEOUT BRIDGE_ISR_XREAD_REQ_TIMEOUT #define BRIDGE_IRR_MULTI_CLR (0x1 << 6) #define BRIDGE_IRR_CRP_GRP_CLR (0x1 << 5) #define BRIDGE_IRR_RESP_BUF_GRP_CLR (0x1 << 4) @@ -1153,6 +1563,21 @@ #define BRIDGE_IRR_GIO_GRP (BRIDGE_ISR_GIO_B_ENBL_ERR | \ BRIDGE_ISR_GIO_MST_TIMEOUT) +#define PIC_IRR_RAM_GRP PIC_ISR_INT_RAM_PERR + +#define PIC_PCIX_GRP_CLR (PIC_IRR_PCIX_AD_PARITY | \ + PIC_IRR_PCIX_DA_PARITY | \ + PIC_IRR_PCIX_MTOUT | \ + PIC_IRR_PCIX_MRETRY | \ + PIC_IRR_PCIX_SERR | \ + PIC_IRR_PCIX_PERR | \ + PIC_IRR_PCIX_TABORT | \ + PIC_ISR_PCIX_REQ_TOUT | \ + PIC_ISR_PCIX_UNEX_COMP | \ + PIC_ISR_PCIX_SPLIT_TO | \ + PIC_ISR_PCIX_SPLIT_EMSG | \ + PIC_ISR_PCIX_SPLIT_MSG_PE) + /* Bridge INT_DEV register bits definition */ #define BRIDGE_INT_DEV_SHFT(n) ((n)*3) #define BRIDGE_INT_DEV_MASK(n) (0x7 << BRIDGE_INT_DEV_SHFT(n)) @@ -1162,6 +1587,10 @@ #define BRIDGE_INT_ADDR_HOST 0x0003FF00 #define BRIDGE_INT_ADDR_FLD 0x000000FF +/* PIC interrupt(x) register bits definition */ +#define PIC_INT_ADDR_FLD 0x00FF000000000000 +#define PIC_INT_ADDR_HOST 0x0000FFFFFFFFFFFF + #define BRIDGE_TMO_PCI_RETRY_HLD_MASK 0x1f0000 #define BRIDGE_TMO_GIO_TIMEOUT_MASK 0x001000 #define BRIDGE_TMO_PCI_RETRY_CNT_MASK 0x0003ff @@ -1239,8 +1668,13 @@ /* RRB assignment register */ #define BRIDGE_RRB_EN 0x8 /* after shifting down */ #define BRIDGE_RRB_DEV 0x7 /* after shifting down */ -#define BRIDGE_RRB_VDEV 0x4 /* after shifting down */ -#define BRIDGE_RRB_PDEV 0x3 /* after shifting down */ +#define BRIDGE_RRB_VDEV 0x4 /* after shifting down, 2 virtual channels */ +#define BRIDGE_RRB_PDEV 0x3 /* after shifting down, 8 devices */ + +#define PIC_RRB_EN 0x8 /* after shifting down */ +#define PIC_RRB_DEV 0x7 /* after shifting down */ +#define PIC_RRB_VDEV 0x6 /* after shifting down, 4 virtual channels */ +#define PIC_RRB_PDEV 0x1 /* after shifting down, 4 devices */ /* RRB status register */ #define BRIDGE_RRB_VALID(r) (0x00010000<<(r)) @@ -1249,6 +1683,15 @@ /* RRB clear register */ #define BRIDGE_RRB_CLEAR(r) (0x00000001<<(r)) +/* Defines for the virtual channels so we dont hardcode 0-3 within code */ +#define VCHAN0 0 /* virtual channel 0 (ie. the "normal" channel) */ +#define VCHAN1 1 /* virtual channel 1 */ +#define VCHAN2 2 /* virtual channel 2 - PIC only */ +#define VCHAN3 3 /* virtual channel 3 - PIC only */ + +/* PIC: PCI-X Read Buffer Attribute Register (RBAR) */ +#define NUM_RBAR 16 /* number of RBAR registers */ + /* xbox system controller declarations */ #define XBOX_BRIDGE_WID 8 #define FLASH_PROM1_BASE 0xE00000 /* To read the xbox sysctlr status */ @@ -1284,6 +1727,38 @@ #define BRIDGE_PCI_IO_LIMIT BRIDGE_PCIIO_XTALK_ALIAS_LIMIT /* + * Macros for Xtalk to Bridge bus (PCI) PIO + * refer to section 5.2.1 Figure 4 of the "PCI Interface Chip (PIC) Volume II + * Programmer's Reference" (Revision 0.8 as of this writing). + * + * These are PIC bridge specific. A separate set of macros was defined + * because PIC deviates from Bridge/Xbridge by not supporting a big-window + * alias for PCI I/O space, and also redefines XTALK addresses + * 0x0000C0000000L and 0x000100000000L to be PCI MEM aliases for the second + * bus. + */ + +/* XTALK addresses that map into PIC Bridge Bus addr space */ +#define PICBRIDGE0_PIO32_XTALK_ALIAS_BASE 0x000040000000L +#define PICBRIDGE0_PIO32_XTALK_ALIAS_LIMIT 0x00007FFFFFFFL +#define PICBRIDGE0_PIO64_XTALK_ALIAS_BASE 0x000080000000L +#define PICBRIDGE0_PIO64_XTALK_ALIAS_LIMIT 0x0000BFFFFFFFL +#define PICBRIDGE1_PIO32_XTALK_ALIAS_BASE 0x0000C0000000L +#define PICBRIDGE1_PIO32_XTALK_ALIAS_LIMIT 0x0000FFFFFFFFL +#define PICBRIDGE1_PIO64_XTALK_ALIAS_BASE 0x000100000000L +#define PICBRIDGE1_PIO64_XTALK_ALIAS_LIMIT 0x00013FFFFFFFL + +/* XTALK addresses that map into PCI addresses */ +#define PICBRIDGE0_PCI_MEM32_BASE PICBRIDGE0_PIO32_XTALK_ALIAS_BASE +#define PICBRIDGE0_PCI_MEM32_LIMIT PICBRIDGE0_PIO32_XTALK_ALIAS_LIMIT +#define PICBRIDGE0_PCI_MEM64_BASE PICBRIDGE0_PIO64_XTALK_ALIAS_BASE +#define PICBRIDGE0_PCI_MEM64_LIMIT PICBRIDGE0_PIO64_XTALK_ALIAS_LIMIT +#define PICBRIDGE1_PCI_MEM32_BASE PICBRIDGE1_PIO32_XTALK_ALIAS_BASE +#define PICBRIDGE1_PCI_MEM32_LIMIT PICBRIDGE1_PIO32_XTALK_ALIAS_LIMIT +#define PICBRIDGE1_PCI_MEM64_BASE PICBRIDGE1_PIO64_XTALK_ALIAS_BASE +#define PICBRIDGE1_PCI_MEM64_LIMIT PICBRIDGE1_PIO64_XTALK_ALIAS_LIMIT + +/* * Macros for Bridge bus (PCI/GIO) to Xtalk DMA */ /* Bridge Bus DMA addresses */ @@ -1401,8 +1876,10 @@ #define ATE_SWAP_ON(x) ((x) |= (1 << ATE_SWAPSHIFT)) #define ATE_SWAP_OFF(x) ((x) &= ~(1 << ATE_SWAPSHIFT)) -#define is_xbridge(bridge) \ - (XWIDGET_PART_NUM(bridge->b_wid_id) == XBRIDGE_WIDGET_PART_NUM) +#define is_xbridge(bridge) IS_XBRIDGE(bridge->b_wid_id) +#define is_pic(bridge) IS_PIC_BRIDGE(bridge->b_wid_id) + +/* extern declarations */ #ifndef __ASSEMBLY__ diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pci_bus_cvlink.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pci_bus_cvlink.h --- linux-2.4.19/include/asm-ia64/sn/pci/pci_bus_cvlink.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pci_bus_cvlink.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_CVLINK_H #define _ASM_SN_PCI_CVLINK_H @@ -41,6 +41,8 @@ #define IS_PCI32G(dev) ((dev)->dma_mask >= 0xffffffff) #define IS_PCI32L(dev) ((dev)->dma_mask < 0xffffffff) +#define IS_PIC_DEVICE(dev) ((struct sn_device_sysdata *)dev->sysdata)->isPIC + #define PCIDEV_VERTEX(pci_dev) \ (((struct sn_device_sysdata *)((pci_dev)->sysdata))->vhdl) @@ -54,6 +56,7 @@ struct sn_device_sysdata { devfs_handle_t vhdl; int isa64; + int isPIC; volatile unsigned int *dma_buf_sync; volatile unsigned int *xbow_buf_sync; }; diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pci_defs.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pci_defs.h --- linux-2.4.19/include/asm-ia64/sn/pci/pci_defs.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pci_defs.h Mon Jan 13 20:36:58 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCI_DEFS_H #define _ASM_SN_PCI_PCI_DEFS_H @@ -39,7 +39,7 @@ * the PCI spec. */ #define PCI_TYPE1_BUS_MASK 0x00FF0000 -#define PCI_TYPE1_SLOT_MASK 0x0000F100 +#define PCI_TYPE1_SLOT_MASK 0x0000F800 #define PCI_TYPE1_FUNC_MASK 0x00000700 #define PCI_TYPE1_REG_MASK 0x000000FF @@ -68,14 +68,14 @@ /* NOTE: if you are using a C "switch" statement to * differentiate between the Config space registers, be - * aware that PCI_CFG_CLASS_CODE and PCI_CFG_BASE_CLASS + * aware that PCI_CFG_CLASS_CODE and PCI_CFG_PROG_IF * are the same offset. */ #define PCI_CFG_REV_ID 0x08 /* Revision Id (1 byte) */ #define PCI_CFG_CLASS_CODE 0x09 /* Class Code (3 bytes) */ -#define PCI_CFG_BASE_CLASS 0x09 /* Base Class (1 byte) */ +#define PCI_CFG_PROG_IF 0x09 /* Prog Interface (1 byte) */ #define PCI_CFG_SUB_CLASS 0x0A /* Sub Class (1 byte) */ -#define PCI_CFG_PROG_IF 0x0B /* Prog Interface (1 byte) */ +#define PCI_CFG_BASE_CLASS 0x0B /* Base Class (1 byte) */ #define PCI_CFG_CACHE_LINE 0x0C /* Cache line size (1 byte) */ #define PCI_CFG_LATENCY_TIMER 0x0D /* Latency Timer (1 byte) */ @@ -99,11 +99,10 @@ #define PCI_CFG_SUBSYS_ID 0x2E /* Subsystem ID */ #define PCI_EXPANSION_ROM 0x30 /* Expansion Rom Base (4B) */ +#define PCI_CAPABILITIES_PTR 0x34 /* Capabilities Pointer */ #define PCI_INTR_LINE 0x3C /* Interrupt Line (1B) */ #define PCI_INTR_PIN 0x3D /* Interrupt Pin (1B) */ -#define PCI_MIN_GNT 0x3E /* Minimum Grant (1B) */ -#define PCI_MAX_LAT 0x3F /* Maximum Latency (1B) */ #define PCI_CFG_VEND_SPECIFIC 0x40 /* first vendor specific reg */ @@ -126,6 +125,8 @@ #define PCI_CFG_PPB_IOLIMHI 0x32 /* IO Limit Addr bits 16..31 */ #define PCI_CFG_PPB_SUB_VENDOR 0x34 /* Subsystem Vendor ID */ #define PCI_CFG_PPB_SUB_DEVICE 0x36 /* Subsystem Device ID */ +#define PCI_CFG_PPB_ROM_BASE 0x38 /* ROM base address */ +#define PCI_CFG_PPB_INT_LINE 0x3C /* Interrupt Line */ #define PCI_CFG_PPB_INT_PIN 0x3D /* Interrupt Pin */ #define PCI_CFG_PPB_BRIDGE_CTRL 0x3E /* Bridge Control */ /* XXX- these might be DEC 21152 specific */ @@ -165,6 +166,7 @@ #define PCI_STAT_F_BK_BK_CAP 0x0080 /* Fast Back-to-Back Capable */ #define PCI_STAT_UDF_SUPP 0x0040 /* UDF Supported */ #define PCI_STAT_66MHZ_CAP 0x0020 /* 66 MHz Capable */ +#define PCI_STAT_CAP_LIST 0x0010 /* Capabilities List */ /* BIST Register Layout (0x0F) */ #define PCI_BIST_BIST_CAP 0x80 /* BIST Capable */ @@ -173,13 +175,63 @@ #define PCI_BIST_CMPL_OK 0x00 /* 0 value is completion OK */ /* Base Address Register 0x10 */ +#define PCI_BA_IO_CODEMASK 0x3 /* bottom 2 bits encode I/O BAR type */ #define PCI_BA_IO_SPACE 0x1 /* I/O Space Marker */ + +#define PCI_BA_MEM_CODEMASK 0xf /* bottom 4 bits encode MEM BAR type */ #define PCI_BA_MEM_LOCATION 0x6 /* 2 bits for location avail */ #define PCI_BA_MEM_32BIT 0x0 /* Anywhere in 32bit space */ #define PCI_BA_MEM_1MEG 0x2 /* Locate below 1 Meg */ #define PCI_BA_MEM_64BIT 0x4 /* Anywhere in 64bit space */ #define PCI_BA_PREFETCH 0x8 /* Prefetchable, no side effect */ +#define PCI_BA_ROM_CODEMASK 0x1 /* bottom bit control expansion ROM enable */ +#define PCI_BA_ROM_ENABLE 0x1 /* enable expansion ROM */ + +/* Bridge Control Register 0x3e */ +#define PCI_BCTRL_DTO_SERR 0x0800 /* Discard Timer timeout generates SERR on primary bus */ +#define PCI_BCTRL_DTO 0x0400 /* Discard Timer timeout status */ +#define PCI_BCTRL_DTO_SEC 0x0200 /* Secondary Discard Timer: 0 => 2^15 PCI clock cycles, 1 => 2^10 */ +#define PCI_BCTRL_DTO_PRI 0x0100 /* Primary Discard Timer: 0 => 2^15 PCI clock cycles, 1 => 2^10 */ +#define PCI_BCTRL_F_BK_BK_ENABLE 0x0080 /* Enable Fast Back-to-Back on secondary bus */ +#define PCI_BCTRL_RESET_SEC 0x0040 /* Reset Secondary bus */ +#define PCI_BCTRL_MSTR_ABT_MODE 0x0020 /* Master Abort Mode: 0 => do not report Master-Aborts */ +#define PCI_BCTRL_VGA_AF_ENABLE 0x0008 /* Enable VGA Address Forwarding */ +#define PCI_BCTRL_ISA_AF_ENABLE 0x0004 /* Enable ISA Address Forwarding */ +#define PCI_BCTRL_SERR_ENABLE 0x0002 /* Enable forwarding of SERR from secondary bus to primary bus */ +#define PCI_BCTRL_PAR_ERR_RESP 0x0001 /* Enable Parity Error Response reporting on secondary interface */ + +/* + * PCI 2.2 introduces the concept of ``capability lists.'' Capability lists + * provide a flexible mechanism for a device or bridge to advertise one or + * more standardized capabilities such as the presense of a power management + * interface, etc. The presense of a capability list is indicated by + * PCI_STAT_CAP_LIST being non-zero in the PCI_CFG_STATUS register. If + * PCI_STAT_CAP_LIST is set, then PCI_CFG_CAP_PTR is a ``pointer'' into the + * device-specific portion of the configuration header where the first + * capability block is stored. This ``pointer'' is a single byte which + * contains an offset from the beginning of the configuration header. The + * bottom two bits of the pointer are reserved and should be masked off to + * determine the offset. Each capability block contains a capability ID, a + * ``pointer'' to the next capability (another offset where a zero terminates + * the list) and capability-specific data. Each capability block starts with + * the capability ID and the ``next capability pointer.'' All data following + * this are capability-dependent. + */ +#define PCI_CAP_ID 0x00 /* Capability ID (1B) */ +#define PCI_CAP_PTR 0x01 /* Capability ``pointer'' (1B) */ + +/* PCI Capability IDs */ +#define PCI_CAP_PM 0x01 /* PCI Power Management */ +#define PCI_CAP_AGP 0x02 /* Accelerated Graphics Port */ +#define PCI_CAP_VPD 0x03 /* Vital Product Data (VPD) */ +#define PCI_CAP_SID 0x04 /* Slot Identification */ +#define PCI_CAP_MSI 0x05 /* Message Signaled Intr */ +#define PCI_CAP_HS 0x06 /* CompactPCI Hot Swap */ +#define PCI_CAP_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ + + /* PIO interface macros */ #ifndef IOC3_EMULATION @@ -210,10 +262,6 @@ #endif /* !IOC3_EMULATION */ /* effects on reads, merges */ -#ifdef CONFIG_SGI_IP22 -#define BYTECOUNT_W_GIO 0xbf400000 -#endif - /* * Definition of address layouts for PCI Config mechanism #1 * XXX- These largely duplicate PCI_TYPE1 constants at the top @@ -240,4 +288,248 @@ #define PCI_IO_MAP_INCR 0x1000 #endif /* CONFIG_SGI_IP32 */ +/* + * Class codes + */ +#define PCI_CFG_CLASS_PRE20 0x00 +#define PCI_CFG_CLASS_STORAGE 0x01 +#define PCI_CFG_CLASS_NETWORK 0x02 +#define PCI_CFG_CLASS_DISPLAY 0x03 +#define PCI_CFG_CLASS_MMEDIA 0x04 +#define PCI_CFG_CLASS_MEMORY 0x05 +#define PCI_CFG_CLASS_BRIDGE 0x06 +#define PCI_CFG_CLASS_COMM 0x07 +#define PCI_CFG_CLASS_BASE 0x08 +#define PCI_CFG_CLASS_INPUT 0x09 +#define PCI_CFG_CLASS_DOCK 0x0A +#define PCI_CFG_CLASS_PROC 0x0B +#define PCI_CFG_CLASS_SERIALBUS 0x0C +#define PCI_CFG_CLASS_OTHER 0xFF + +/* + * Important Subclasses + */ +#define PCI_CFG_SUBCLASS_BRIDGE_HOST 0x00 +#define PCI_CFG_SUBCLASS_BRIDGE_ISA 0x01 +#define PCI_CFG_SUBCLASS_BRIDGE_EISA 0x02 +#define PCI_CFG_SUBCLASS_BRIDGE_MC 0x03 +#define PCI_CFG_SUBCLASS_BRIDGE_PCI 0x04 +#define PCI_CFG_SUBCLASS_BRIDGE_PCMCIA 0x05 +#define PCI_CFG_SUBCLASS_BRIDGE_NUBUS 0x06 +#define PCI_CFG_SUBCLASS_BRIDGE_CARDBUS 0x07 +#define PCI_CFG_SUBCLASS_BRIDGE_OTHER 0x80 + +#ifndef __ASSEMBLY__ + +#ifdef LITTLE_ENDIAN + +/* + * PCI config space definition + */ +typedef volatile struct pci_cfg_s { + uint16_t vendor_id; + uint16_t dev_id; + uint16_t cmd; + uint16_t status; + uchar_t rev; + uchar_t prog_if; + uchar_t sub_class; + uchar_t class; + uchar_t line_size; + uchar_t lt; + uchar_t hdr_type; + uchar_t bist; + uint32_t bar[6]; + uint32_t cardbus; + uint16_t subsys_vendor_id; + uint16_t subsys_dev_id; + uint32_t exp_rom; + uint32_t res[2]; + uchar_t int_line; + uchar_t int_pin; + uchar_t min_gnt; + uchar_t max_lat; +} pci_cfg_t; + +/* + * PCI Type 1 config space definition for PCI to PCI Bridges (PPBs) + */ +typedef volatile struct pci_cfg1_s { + uint16_t vendor_id; + uint16_t dev_id; + uint16_t cmd; + uint16_t status; + uchar_t rev; + uchar_t prog_if; + uchar_t sub_class; + uchar_t class; + uchar_t line_size; + uchar_t lt; + uchar_t hdr_type; + uchar_t bist; + uint32_t bar[2]; + uchar_t pri_bus_num; + uchar_t snd_bus_num; + uchar_t sub_bus_num; + uchar_t slt; + uchar_t io_base; + uchar_t io_limit; + uint16_t snd_status; + uint16_t mem_base; + uint16_t mem_limit; + uint16_t pmem_base; + uint16_t pmem_limit; + uint32_t pmem_base_upper; + uint32_t pmem_limit_upper; + uint16_t io_base_upper; + uint16_t io_limit_upper; + uint32_t res; + uint32_t exp_rom; + uchar_t int_line; + uchar_t int_pin; + uint16_t ppb_control; + +} pci_cfg1_t; + +/* + * PCI-X Capability + */ +typedef volatile struct cap_pcix_cmd_reg_s { + uint16_t data_parity_enable: 1, + enable_relaxed_order: 1, + max_mem_read_cnt: 2, + max_split: 3, + reserved1: 9; +} cap_pcix_cmd_reg_t; + +typedef volatile struct cap_pcix_stat_reg_s { + uint32_t func_num: 3, + dev_num: 5, + bus_num: 8, + bit64_device: 1, + mhz133_capable: 1, + split_complt_discard: 1, + unexpect_split_complt: 1, + device_complex: 1, + max_mem_read_cnt: 2, + max_out_split: 3, + max_cum_read: 3, + split_complt_err: 1, + reserved1: 2; +} cap_pcix_stat_reg_t; + +typedef volatile struct cap_pcix_type0_s { + uchar_t pcix_cap_id; + uchar_t pcix_cap_nxt; + cap_pcix_cmd_reg_t pcix_type0_command; + cap_pcix_stat_reg_t pcix_type0_status; +} cap_pcix_type0_t; + +#else + +/* + * PCI config space definition + */ +typedef volatile struct pci_cfg_s { + uint16_t dev_id; + uint16_t vendor_id; + uint16_t status; + uint16_t cmd; + uchar_t class; + uchar_t sub_class; + uchar_t prog_if; + uchar_t rev; + uchar_t bist; + uchar_t hdr_type; + uchar_t lt; + uchar_t line_size; + uint32_t bar[6]; + uint32_t cardbus; + uint16_t subsys_dev_id; + uint16_t subsys_vendor_id; + uint32_t exp_rom; + uint32_t res[2]; + uchar_t max_lat; + uchar_t min_gnt; + uchar_t int_pin; + uchar_t int_line; +} pci_cfg_t; + +/* + * PCI Type 1 config space definition for PCI to PCI Bridges (PPBs) + */ +typedef volatile struct pci_cfg1_s { + uint16_t dev_id; + uint16_t vendor_id; + uint16_t status; + uint16_t cmd; + uchar_t class; + uchar_t sub_class; + uchar_t prog_if; + uchar_t rev; + uchar_t bist; + uchar_t hdr_type; + uchar_t lt; + uchar_t line_size; + uint32_t bar[2]; + uchar_t slt; + uchar_t sub_bus_num; + uchar_t snd_bus_num; + uchar_t pri_bus_num; + uint16_t snd_status; + uchar_t io_limit; + uchar_t io_base; + uint16_t mem_limit; + uint16_t mem_base; + uint16_t pmem_limit; + uint16_t pmem_base; + uint32_t pmem_limit_upper; + uint32_t pmem_base_upper; + uint16_t io_limit_upper; + uint16_t io_base_upper; + uint32_t res; + uint32_t exp_rom; + uint16_t ppb_control; + uchar_t int_pin; + uchar_t int_line; +} pci_cfg1_t; + + + +/* + * PCI-X Capability + */ +typedef volatile struct cap_pcix_cmd_reg_s { + uint16_t reserved1: 9, + max_split: 3, + max_mem_read_cnt: 2, + enable_relaxed_order: 1, + data_parity_enable: 1; +} cap_pcix_cmd_reg_t; + +typedef volatile struct cap_pcix_stat_reg_s { + uint32_t reserved1: 2, + split_complt_err: 1, + max_cum_read: 3, + max_out_split: 3, + max_mem_read_cnt: 2, + device_complex: 1, + unexpect_split_complt: 1, + split_complt_discard: 1, + mhz133_capable: 1, + bit64_device: 1, + bus_num: 8, + dev_num: 5, + func_num: 3; +} cap_pcix_stat_reg_t; + +typedef volatile struct cap_pcix_type0_s { + cap_pcix_cmd_reg_t pcix_type0_command; + uchar_t pcix_cap_nxt; + uchar_t pcix_cap_id; + cap_pcix_stat_reg_t pcix_type0_status; +} cap_pcix_type0_t; + +#endif +#endif /* __ASSEMBLY__ */ #endif /* _ASM_SN_PCI_PCI_DEFS_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pciba.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pciba.h --- linux-2.4.19/include/asm-ia64/sn/pci/pciba.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pciba.h Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * Public License. See the file "COPYING" in the main directory of * this archive for more details. * - * Copyright (C) 1997, 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1997, 2001-2003 Silicon Graphics, Inc. All rights reserved. * */ @@ -90,6 +90,13 @@ */ #define PCIIOCDMAALLOC _IOWR(0,1,uint64_t) #define PCIIOCDMAFREE _IOW(0,1,uint64_t) + +/* pio cache-mode ioctl defines. current only uncached accelerated */ +#define PCIBA_CACHE_MODE_SET 1 +#define PCIBA_CACHE_MODE_CLEAR 2 +#ifdef PIOMAP_UNC_ACC +#define PCIBA_UNCACHED_ACCEL PIOMAP_UNC_ACC +#endif /* The parameter for PCIIOCDMAALLOC needs to contain * both the size of the request and the flag values diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pcibr.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pcibr.h --- linux-2.4.19/include/asm-ia64/sn/pci/pcibr.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pcibr.h Mon Dec 30 14:16:56 2002 @@ -4,13 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIBR_H #define _ASM_SN_PCI_PCIBR_H #if defined(__KERNEL__) +#include #include #include #include @@ -75,6 +76,7 @@ */ extern pciio_provider_t pcibr_provider; +extern pciio_provider_t pci_pic_provider; /* ===================================================================== * secondary entry points: pcibr PCI bus provider @@ -182,7 +184,11 @@ extern void pcibr_intr_free(pcibr_intr_t intr); +#ifdef CONFIG_IA64_SGI_SN1 extern int pcibr_intr_connect(pcibr_intr_t intr); +#else +extern int pcibr_intr_connect(pcibr_intr_t intr, intr_func_t, intr_arg_t); +#endif extern void pcibr_intr_disconnect(pcibr_intr_t intr); @@ -215,9 +221,11 @@ extern int pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code); +#ifdef PIC_LATER extern pciio_slot_t pcibr_error_extract(devfs_handle_t pcibr_vhdl, pciio_space_t *spacep, iopaddr_t *addrp); +#endif extern int pcibr_wrb_flush(devfs_handle_t pconn_vhdl); extern int pcibr_rrb_check(devfs_handle_t pconn_vhdl, @@ -226,11 +234,13 @@ int *count_reserved, int *count_pool); +#ifndef CONFIG_IA64_SGI_SN1 extern int pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4); +#endif typedef void rrb_alloc_funct_f (devfs_handle_t xconn_vhdl, @@ -340,7 +350,11 @@ extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); extern void pcibr_hints_handsoff(devfs_handle_t); +#ifdef CONFIG_IA64_SGI_SN1 typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t); +#else +typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t, int); +#endif extern void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); extern int pcibr_asic_rev(devfs_handle_t); @@ -414,13 +428,9 @@ char resp_l1_msg[L1_QSIZE + 1]; }; -struct pcibr_slot_info_req_s { - int req_slot; - pcibr_slot_info_resp_t req_respp; - int req_size; -}; - struct pcibr_slot_info_resp_s { + short resp_bs_bridge_type; + short resp_bs_bridge_mode; int resp_has_host; char resp_host_slot; devfs_handle_t resp_slot_conn; @@ -438,17 +448,22 @@ unsigned resp_bss_d64_flags; iopaddr_t resp_bss_d32_base; unsigned resp_bss_d32_flags; - int resp_bss_ext_ates_active; + atomic_t resp_bss_ext_ates_active; volatile unsigned *resp_bss_cmd_pointer; unsigned resp_bss_cmd_shadow; int resp_bs_rrb_valid; - int resp_bs_rrb_valid_v; + int resp_bs_rrb_valid_v1; + int resp_bs_rrb_valid_v2; + int resp_bs_rrb_valid_v3; int resp_bs_rrb_res; bridgereg_t resp_b_resp; bridgereg_t resp_b_int_device; bridgereg_t resp_b_int_enable; bridgereg_t resp_b_int_host; - +#ifndef CONFIG_IA64_SGI_SN1 + picreg_t resp_p_int_enable; + picreg_t resp_p_int_host; +#endif struct pcibr_slot_func_info_resp_s { int resp_f_status; char resp_f_slot_name[MAXDEVNAME]; @@ -507,6 +522,9 @@ #define PCI_SLOT_RRB_ALLOC_ERR 24 /* slot initial rrb alloc error */ #define PCI_SLOT_DRV_ATTACH_ERR 25 /* driver attach error */ #define PCI_SLOT_DRV_DETACH_ERR 26 /* driver detach error */ +/* EFBIG 27 */ +#define PCI_MULTI_FUNC_ERR 28 /* multi-function card error */ +#define PCI_SLOT_RBAR_ALLOC_ERR 29 /* slot PCI-X RBAR alloc error */ /* ERANGE 34 */ /* EUNATCH 42 */ diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pcibr_private.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pcibr_private.h --- linux-2.4.19/include/asm-ia64/sn/pci/pcibr_private.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pcibr_private.h Tue Dec 31 07:55:59 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIBR_PRIVATE_H #define _ASM_SN_PCI_PCIBR_PRIVATE_H @@ -15,6 +15,7 @@ * should ever peek into this file. */ +#include #include #include #include @@ -34,6 +35,68 @@ typedef struct pcibr_intr_wrap_s *pcibr_intr_wrap_t; typedef struct pcibr_intr_cbuf_s *pcibr_intr_cbuf_t; +typedef volatile unsigned *cfg_p; +typedef volatile bridgereg_t *reg_p; + +/* + * extern functions + */ +cfg_p pcibr_slot_config_addr(bridge_t *, pciio_slot_t, int); +cfg_p pcibr_func_config_addr(bridge_t *, pciio_bus_t bus, pciio_slot_t, pciio_function_t, int); +unsigned pcibr_slot_config_get(bridge_t *, pciio_slot_t, int); +unsigned pcibr_func_config_get(bridge_t *, pciio_slot_t, pciio_function_t, int); +void pcibr_debug(uint32_t, devfs_handle_t, char *, ...); +void pcibr_slot_config_set(bridge_t *, pciio_slot_t, int, unsigned); +void pcibr_func_config_set(bridge_t *, pciio_slot_t, pciio_function_t, int, + unsigned); +/* + * PCIBR_DEBUG() macro and debug bitmask defines + */ +/* low freqency debug events (ie. initialization, resource allocation,...) */ +#define PCIBR_DEBUG_INIT 0x00000001 /* bridge init */ +#define PCIBR_DEBUG_HINTS 0x00000002 /* bridge hints */ +#define PCIBR_DEBUG_ATTACH 0x00000004 /* bridge attach */ +#define PCIBR_DEBUG_DETACH 0x00000008 /* bridge detach */ +#define PCIBR_DEBUG_ATE 0x00000010 /* bridge ATE allocation */ +#define PCIBR_DEBUG_RRB 0x00000020 /* bridge RRB allocation */ +#define PCIBR_DEBUG_RBAR 0x00000040 /* bridge RBAR allocation */ +#define PCIBR_DEBUG_PROBE 0x00000080 /* bridge device probing */ +#define PCIBR_DEBUG_INTR_ERROR 0x00000100 /* bridge error interrupt */ +#define PCIBR_DEBUG_ERROR_HDLR 0x00000200 /* bridge error handler */ +#define PCIBR_DEBUG_CONFIG 0x00000400 /* device's config space */ +#define PCIBR_DEBUG_BAR 0x00000800 /* device's BAR allocations */ +#define PCIBR_DEBUG_INTR_ALLOC 0x00001000 /* device's intr allocation */ +#define PCIBR_DEBUG_DEV_ATTACH 0x00002000 /* device's attach */ +#define PCIBR_DEBUG_DEV_DETACH 0x00004000 /* device's detach */ +#define PCIBR_DEBUG_HOTPLUG 0x00008000 + +/* high freqency debug events (ie. map allocation, direct translation,...) */ +#define PCIBR_DEBUG_DEVREG 0x04000000 /* bridges device reg sets */ +#define PCIBR_DEBUG_PIOMAP 0x08000000 /* pcibr_piomap */ +#define PCIBR_DEBUG_PIODIR 0x10000000 /* pcibr_piotrans */ +#define PCIBR_DEBUG_DMAMAP 0x20000000 /* pcibr_dmamap */ +#define PCIBR_DEBUG_DMADIR 0x40000000 /* pcibr_dmatrans */ +#define PCIBR_DEBUG_INTR 0x80000000 /* interrupts */ + +extern char *pcibr_debug_module; +extern int pcibr_debug_widget; +extern int pcibr_debug_slot; +extern uint32_t pcibr_debug_mask; + +/* For low frequency events (ie. initialization, resource allocation,...) */ +#define PCIBR_DEBUG_ALWAYS(args) pcibr_debug args ; + +/* XXX: habeck: maybe make PCIBR_DEBUG() always available? Even in non- + * debug kernels? If tracing isn't enabled (i.e pcibr_debug_mask isn't + * set, then the overhead for this macro is just an extra 'if' check. + */ +/* For high frequency events (ie. map allocation, direct translation,...) */ +#if 1 || DEBUG +#define PCIBR_DEBUG(args) PCIBR_DEBUG_ALWAYS(args) +#else /* DEBUG */ +#define PCIBR_DEBUG(args) +#endif /* DEBUG */ + /* * Bridge sets up PIO using this information. */ @@ -100,6 +163,8 @@ #define bi_flags bi_pi.pi_flags /* PCIBR_INTR flags */ #define bi_dev bi_pi.pi_dev /* associated pci card */ #define bi_lines bi_pi.pi_lines /* which PCI interrupt line(s) */ +#define bi_func bi_pi.pi_func /* handler function (when connected) */ +#define bi_arg bi_pi.pi_arg /* handler parameter (when connected) */ #define bi_mustruncpu bi_pi.pi_mustruncpu /* Where we must run. */ #define bi_irq bi_pi.pi_irq /* IRQ assigned. */ #define bi_cpu bi_pi.pi_cpu /* cpu assigned. */ @@ -108,9 +173,43 @@ struct pcibr_intr_cbuf_s bi_ibuf; /* circular buffer of wrap ptrs */ }; + +/* + * PCIBR_INFO_SLOT_GET_EXT returns the external slot number that the card + * resides in. (i.e the slot number silk screened on the back of the I/O + * brick). PCIBR_INFO_SLOT_GET_INT returns the internal slot (or device) + * number used by the pcibr code to represent that external slot (i.e to + * set bit patterns in BRIDGE/PIC registers to represent the device, or to + * offset into an array, or ...). + * + * In BRIDGE and XBRIDGE the external slot and internal device numbering + * are the same. (0->0, 1->1, 2->2,... 7->7) BUT in the PIC the external + * slot number is always 1 greater than the internal device number (1->0, + * 2->1, 3->2, 4->3). This is due to the fact that the PCI-X spec requires + * that the 'bridge' (i.e PIC) be designated as 'device 0', thus external + * slot numbering can't start at zero. + * + * PCIBR_DEVICE_TO_SLOT converts an internal device number to an external + * slot number. NOTE: PCIIO_SLOT_NONE stays as PCIIO_SLOT_NONE. + * + * PCIBR_SLOT_TO_DEVICE converts an external slot number to an internal + * device number. NOTE: PCIIO_SLOT_NONE stays as PCIIO_SLOT_NONE. + */ +#define PCIBR_INFO_SLOT_GET_EXT(info) (((pcibr_info_t)info)->f_slot) +#define PCIBR_INFO_SLOT_GET_INT(info) (((pcibr_info_t)info)->f_dev) + +#define PCIBR_DEVICE_TO_SLOT(pcibr_soft, dev_num) \ + (((dev_num) != PCIIO_SLOT_NONE) ? \ + (IS_PIC_SOFT((pcibr_soft)) ? ((dev_num) + 1) : (dev_num)) : \ + PCIIO_SLOT_NONE) + +#define PCIBR_SLOT_TO_DEVICE(pcibr_soft, slot) \ + (((slot) != PCIIO_SLOT_NONE) ? \ + (IS_PIC_SOFT((pcibr_soft)) ? ((slot) - 1) : (slot)) : \ + PCIIO_SLOT_NONE) + /* - * per-connect point pcibr data, including - * standard pciio data in-line: + * per-connect point pcibr data, including standard pciio data in-line: */ struct pcibr_info_s { struct pciio_info_s f_c; /* MUST BE FIRST. */ @@ -125,15 +224,18 @@ #define f_pops f_c.c_pops /* cached provider from c_master */ #define f_efunc f_c.c_efunc /* error handling function */ #define f_einfo f_c.c_einfo /* first parameter for efunc */ -#define f_window f_c.c_window /* state of BASE regs */ -#define f_rbase f_c.c_rbase /* expansion rom base */ -#define f_rsize f_c.c_rsize /* expansion rom size */ -#define f_piospace f_c.c_piospace /* additional I/O spaces allocated */ +#define f_window f_c.c_window /* state of BASE regs */ +#define f_rwindow f_c.c_rwindow /* expansion ROM BASE regs */ +#define f_rbase f_c.c_rbase /* expansion ROM base */ +#define f_rsize f_c.c_rsize /* expansion ROM size */ +#define f_piospace f_c.c_piospace /* additional I/O spaces allocated */ /* pcibr-specific connection state */ int f_ibit[4]; /* Bridge bit for each INTx */ pcibr_piomap_t f_piomap; int f_att_det_error; + pciio_slot_t f_dev; /* which device the card represents */ + cap_pcix_type0_t *f_pcix_cap; /* pointer to the pcix capability */ }; /* ===================================================================== @@ -152,15 +254,93 @@ struct pcibr_intr_wrap_s { pcibr_soft_t iw_soft; /* which bridge */ volatile bridgereg_t *iw_stat; /* ptr to b_int_status */ +#ifdef CONFIG_IA64_SGI_SN1 bridgereg_t iw_intr; /* bit in b_int_status */ +#else + bridgereg_t iw_ibit; /* bit in b_int_status */ +#endif pcibr_intr_list_t iw_list; /* ghostbusters! */ int iw_hdlrcnt; /* running handler count */ int iw_shared; /* if Bridge bit is shared */ int iw_connected; /* if already connected */ }; -#define PCIBR_ISR_ERR_START 8 -#define PCIBR_ISR_MAX_ERRS 32 +#define PCIBR_ISR_ERR_START 8 +#define PCIBR_ISR_MAX_ERRS_BRIDGE 32 +#define PCIBR_ISR_MAX_ERRS_PIC 45 +#define PCIBR_ISR_MAX_ERRS PCIBR_ISR_MAX_ERRS_PIC + +/* + * PCI Base Address Register window allocation constants. + * To reduce the size of the internal resource mapping structures, do + * not use the entire PCI bus I/O address space + */ +#define PCIBR_BUS_IO_BASE 0x100000 +#define PCIBR_BUS_IO_MAX 0x0FFFFFFF +#define PCIBR_BUS_IO_PAGE 0x100000 + +#define PCIBR_BUS_SWIN_BASE _PAGESZ +#define PCIBR_BUS_SWIN_MAX 0x000FFFFF +#define PCIBR_BUS_SWIN_PAGE _PAGESZ + +#define PCIBR_BUS_MEM_BASE 0x200000 +#define PCIBR_BUS_MEM_MAX 0x3FFFFFFF +#define PCIBR_BUS_MEM_PAGE 0x100000 + +/* defines for pcibr_soft_s->bs_bridge_type */ +#define PCIBR_BRIDGETYPE_BRIDGE 0 +#define PCIBR_BRIDGETYPE_XBRIDGE 1 +#define PCIBR_BRIDGETYPE_PIC 2 +#define IS_XBRIDGE_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_XBRIDGE) +#define IS_PIC_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_PIC) +#define IS_PIC_BUSNUM_SOFT(ps, bus) \ + (IS_PIC_SOFT(ps) && ((ps)->bs_busnum == (bus))) +#define IS_BRIDGE_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_BRIDGE) +#define IS_XBRIDGE_OR_PIC_SOFT(ps) (IS_XBRIDGE_SOFT(ps) || IS_PIC_SOFT(ps)) + +/* + * Runtime checks for workarounds. + */ +#define PCIBR_WAR_ENABLED(pv, pcibr_soft) \ + ((1 << XWIDGET_PART_REV_NUM_REV(pcibr_soft->bs_rev_num)) & pv) +/* + * Defines for individual WARs. Each is a bitmask of applicable + * part revision numbers. (1 << 1) == rev A, (1 << 2) == rev B, etc. + */ +#define PV854697 (~0) /* PIC: write 64bit regs as 64bits. permanent */ +#define PV854827 (~0) /* PIC: fake widget 0xf presence bit. permanent */ +#define PV855271 (~0) /* PIC: use virt chan iff 64-bit device. permanent */ +#define PV855272 (1 << 1) /* PIC: runaway interrupt WAR */ +#define PV856155 (1 << 1) /* PIC: arbitration WAR */ +#define PV856864 (1 << 1) /* PIC: lower timeout to free TNUMs quicker */ +#define PV856866 (1 << 1) /* PIC: avoid rrb's 0/1/8/9. */ +#define PV862253 (1 << 1) /* PIC: don't enable write req RAM parity checking */ +#define PV867308 (3 << 1) /* PIC: make LLP error interrupts FATAL for PIC */ + + +/* defines for pcibr_soft_s->bs_bridge_mode */ +#define PCIBR_BRIDGEMODE_PCI_33 0x0 +#define PCIBR_BRIDGEMODE_PCI_66 0x2 +#define PCIBR_BRIDGEMODE_PCIX_66 0x3 +#define PCIBR_BRIDGEMODE_PCIX_100 0x5 +#define PCIBR_BRIDGEMODE_PCIX_133 0x7 +#define BUSSPEED_MASK 0x6 +#define BUSTYPE_MASK 0x1 + +#define IS_PCI(ps) (!IS_PCIX(ps)) +#define IS_PCIX(ps) ((ps)->bs_bridge_mode & BUSTYPE_MASK) + +#define IS_33MHZ(ps) ((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCI_33) +#define IS_66MHZ(ps) (((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCI_66) || \ + ((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_66)) +#define IS_100MHZ(ps) ((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_100) +#define IS_133MHZ(ps) ((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_133) + + +/* Number of PCI slots. NOTE: this works as long as the first slot + * is zero. Otherwise use ((ps->bs_max_slot+1) - ps->bs_min_slot) + */ +#define PCIBR_NUM_SLOTS(ps) (ps->bs_max_slot+1) /* ===================================================================== * Bridge Device State structure @@ -172,7 +352,7 @@ struct pcibr_soft_s { devfs_handle_t bs_conn; /* xtalk connection point */ devfs_handle_t bs_vhdl; /* vertex owned by pcibr */ - int bs_int_enable; /* Mask of enabled intrs */ + uint64_t bs_int_enable; /* Mask of enabled intrs */ bridge_t *bs_base; /* PIO pointer to Bridge chip */ char *bs_name; /* hw graph name */ xwidgetnum_t bs_xid; /* Bridge's xtalk ID number */ @@ -180,7 +360,11 @@ xwidgetnum_t bs_mxid; /* master's xtalk ID number */ pciio_slot_t bs_first_slot; /* first existing slot */ pciio_slot_t bs_last_slot; /* last existing slot */ - + pciio_slot_t bs_last_reset; /* last slot to reset */ + pciio_slot_t bs_min_slot; /* lowest possible slot */ + pciio_slot_t bs_max_slot; /* highest possible slot */ + pcibr_soft_t bs_peers_soft; /* PICs other bus's soft */ + int bs_busnum; /* PIC has two pci busses */ iopaddr_t bs_dir_xbase; /* xtalk address for 32-bit PCI direct map */ xwidgetnum_t bs_dir_xport; /* xtalk port for 32-bit PCI direct map */ @@ -188,14 +372,23 @@ struct map *bs_int_ate_map; /* rmalloc map for internal ATEs */ struct map *bs_ext_ate_map; /* rmalloc map for external ATEs */ short bs_int_ate_size; /* number of internal ates */ - short bs_xbridge; /* if 1 then xbridge */ - + short bs_bridge_type; /* see defines above */ + short bs_bridge_mode; /* see defines above */ +#ifdef CONFIG_IA64_SGI_SN1 +#define bs_xbridge bs_bridge_type +#endif int bs_rev_num; /* revision number of Bridge */ - unsigned bs_dma_flags; /* revision-implied DMA flags */ + /* bs_dma_flags are the forced dma flags used on all DMAs. Used for + * working around ASIC rev issues and protocol specific requirements + */ + unsigned bs_dma_flags; /* forced DMA flags */ +#ifdef CONFIG_IA64_SGI_SN1 l1sc_t *bs_l1sc; /* io brick l1 system cntr */ +#endif moduleid_t bs_moduleid; /* io brick moduleid */ + short bs_bricktype; /* io brick type */ /* * Lock used primarily to get mutual exclusion while managing any @@ -222,7 +415,8 @@ pciio_slot_t host_slot; devfs_handle_t slot_conn; - int slot_status; + /* PCI Hot-Plug status word */ + int slot_status; /* Potentially several connection points * for this slot. bss_ninfo is how many, @@ -299,24 +493,53 @@ pcibr_intr_bits_f *bs_intr_bits; + /* PIC PCI-X Read Buffer Management : + * bs_pcix_num_funcs: the total number of PCI-X functions + * on the bus + * bs_pcix_split_tot: total number of outstanding split + * transactions requested by all functions on the bus + * bs_pcix_rbar_percent_allowed: the percentage of the + * total number of buffers a function requested that are + * available to it, not including the 1 RBAR guaranteed + * to it. + * bs_pcix_rbar_inuse: number of RBARs in use. + * bs_pcix_rbar_avail: number of RBARs available. NOTE: + * this value can go negative if we oversubscribe the + * RBARs. (i.e. We have 16 RBARs but 17 functions). + */ + int bs_pcix_num_funcs; + int bs_pcix_split_tot; + int bs_pcix_rbar_percent_allowed; + + int bs_pcix_rbar_inuse; + int bs_pcix_rbar_avail; + + /* RRB MANAGEMENT * bs_rrb_fixed: bitmap of slots whose RRB * allocations we should not "automatically" change * bs_rrb_avail: number of RRBs that have not * been allocated or reserved for {even,odd} slots - * bs_rrb_res: number of RRBs reserved for the + * bs_rrb_res: number of RRBs currently reserved for the * use of the index slot number - * bs_rrb_valid: number of RRBs marked valid - * for the indexed slot number; indexes 8-15 - * are for the virtual channels for slots 0-7. + * bs_rrb_res_dflt: number of RRBs reserved at boot + * time for the use of the index slot number + * bs_rrb_valid: number of RRBs currently marked valid + * for the indexed slot/vchan number; array[slot][vchan] + * bs_rrb_valid_dflt: number of RRBs marked valid at boot + * time for the indexed slot/vchan number; array[slot][vchan] */ int bs_rrb_fixed; - int bs_rrb_avail[2]; - int bs_rrb_res[8]; + int bs_rrb_avail[2]; + int bs_rrb_res[8]; int bs_rrb_res_dflt[8]; +#ifdef CONFIG_IA64_SGI_SN1 int bs_rrb_valid[16]; int bs_rrb_valid_dflt[16]; - +#else + int bs_rrb_valid[8][4]; + int bs_rrb_valid_dflt[8][4]; +#endif struct { /* Each Bridge interrupt bit has a single XIO * interrupt channel allocated. @@ -347,35 +570,55 @@ * Note that there is no locking while looking at this data structure. * There should not be any race between bus error code and * error interrupt code.. will look into this if needed. + * + * NOTE: The above discussion of error interrupt processing is + * no longer true. Whether it should again be true, is + * being looked into. */ struct br_errintr_info { int bserr_toutcnt; #ifdef LATER toid_t bserr_toutid; /* Timeout started by errintr */ -#endif - iopaddr_t bserr_addr; /* Address where error occurred */ - bridgereg_t bserr_intstat; /* interrupts active at error time */ +#endif /* LATER */ + iopaddr_t bserr_addr; /* Address where error occured */ + uint64_t bserr_intstat; /* interrupts active at error dump */ } bs_errinfo; /* * PCI Bus Space allocation data structure. - * This info is used to satisfy the callers of pcibr_piospace_alloc - * interface. Most of these users need "large" amounts of PIO - * space (typically in Megabytes), and they generally tend to - * take once and never release.. - * For Now use a simple algorithm to manage it. On allocation, - * Update the _base field to reflect next free address. * - * Freeing does nothing.. So, once allocated, it's gone for good. + * The resource mapping functions rmalloc() and rmfree() are used + * to manage the PCI bus I/O, small window, and memory address + * spaces. + * + * This info is used to assign PCI bus space addresses to cards + * via their BARs and to the callers of the pcibr_piospace_alloc() + * interface. + * + * Users of the pcibr_piospace_alloc() interface, such as the VME + * Universe chip, need PCI bus space that is not acquired by BARs. + * Most of these users need "large" amounts of PIO space (typically + * in Megabytes), and they generally tend to take once and never + * release. */ +#ifdef CONFIG_IA64_SGI_SN1 struct br_pcisp_info { - iopaddr_t pci_io_base; - iopaddr_t pci_io_last; - iopaddr_t pci_swin_base; - iopaddr_t pci_swin_last; - iopaddr_t pci_mem_base; - iopaddr_t pci_mem_last; + iopaddr_t pci_io_base; + iopaddr_t pci_io_last; + iopaddr_t pci_swin_base; + iopaddr_t pci_swin_last; + iopaddr_t pci_mem_base; + iopaddr_t pci_mem_last; } bs_spinfo; +#endif /* CONFIG_IA64_SGI_SN1 */ + struct pciio_win_map_s bs_io_win_map; /* I/O addr space */ + struct pciio_win_map_s bs_swin_map; /* Small window addr space */ + struct pciio_win_map_s bs_mem_win_map; /* Memory addr space */ + + int bs_bus_addr_status; /* Bus space status */ + +#define PCIBR_BUS_ADDR_MEM_FREED 1 /* Reserved PROM mem addr freed */ +#define PCIBR_BUS_ADDR_IO_FREED 2 /* Reserved PROM I/O addr freed */ struct bs_errintr_stat_s { uint32_t bs_errcount_total; @@ -437,13 +680,6 @@ #define pcibr_soft_get(v) ((pcibr_soft_t)hwgraph_fastinfo_get((v))) #define pcibr_soft_set(v,i) (hwgraph_fastinfo_set((v), (arbitrary_info_t)(i))) -/* Use io spin locks. This ensures that all the PIO writes from a particular - * CPU to a particular IO device are synched before the start of the next - * set of PIO operations to the same device. - */ -#define pcibr_lock(pcibr_soft) io_splock(&pcibr_soft->bs_lock) -#define pcibr_unlock(pcibr_soft,s) io_spunlock(&pcibr_soft->bs_lock,s) - /* * mem alloc/free macros */ @@ -455,13 +691,37 @@ #define NEW(ptr) NEWA(ptr,1) #define DEL(ptr) DELA(ptr,1) -typedef volatile unsigned *cfg_p; -typedef volatile bridgereg_t *reg_p; +#ifndef CONFIG_IA64_SGI_SN1 +/* + * Additional PIO spaces per slot are + * recorded in this structure. + */ +struct pciio_piospace_s { + pciio_piospace_t next; /* another space for this device */ + char free; /* 1 if free, 0 if in use */ + pciio_space_t space; /* Which space is in use */ + iopaddr_t start; /* Starting address of the PIO space */ + size_t count; /* size of PIO space */ +}; +#endif /* CONFIG_IA64_SGI_SN1 */ -#define PCIBR_RRB_SLOT_VIRTUAL 8 -#define PCIBR_VALID_SLOT(s) (s < 8) +/* Use io spin locks. This ensures that all the PIO writes from a particular + * CPU to a particular IO device are synched before the start of the next + * set of PIO operations to the same device. + */ +#ifdef PCI_LATER +#define pcibr_lock(pcibr_soft) io_splock(pcibr_soft->bs_lock) +#define pcibr_unlock(pcibr_soft, s) io_spunlock(pcibr_soft->bs_lock,s) +#else +#define pcibr_lock(pcibr_soft) 1 +#define pcibr_unlock(pcibr_soft, s) +#endif /* PCI_LATER */ + +#ifndef CONFIG_IA64_SGI_SN1 +#define PCIBR_VALID_SLOT(ps, s) (s < PCIBR_NUM_SLOTS(ps)) #define PCIBR_D64_BASE_UNSET (0xFFFFFFFFFFFFFFFF) #define PCIBR_D32_BASE_UNSET (0xFFFFFFFF) +#endif #define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev" #define PCIBR_SOFT_LIST 1 diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pciio.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pciio.h --- linux-2.4.19/include/asm-ia64/sn/pci/pciio.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pciio.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIIO_H #define _ASM_SN_PCI_PCIIO_H @@ -13,6 +13,7 @@ * pciio.h -- platform-independent PCI interface */ +#include #include #include #include @@ -207,6 +208,9 @@ typedef struct pciio_intr_s *pciio_intr_t; typedef struct pciio_info_s *pciio_info_t; typedef struct pciio_piospace_s *pciio_piospace_t; +typedef struct pciio_win_info_s *pciio_win_info_t; +typedef struct pciio_win_map_s *pciio_win_map_t; +typedef struct pciio_win_alloc_s *pciio_win_alloc_t; /* PIO MANAGEMENT */ @@ -382,8 +386,13 @@ typedef void pciio_intr_free_f (pciio_intr_t intr_hdl); +#ifdef CONFIG_IA64_SGI_SN1 typedef int pciio_intr_connect_f (pciio_intr_t intr_hdl); /* pciio intr resource handle */ +#else +typedef int +pciio_intr_connect_f (pciio_intr_t intr_hdl, intr_func_t intr_func, intr_arg_t intr_arg); /* pciio intr resource handle */ +#endif typedef void pciio_intr_disconnect_f (pciio_intr_t intr_hdl); @@ -627,6 +636,44 @@ devfs_handle_t pcicard, /* vertex created by pciio_device_register */ int drv_flags); + +/* create and initialize empty window mapping resource */ +extern pciio_win_map_t +pciio_device_win_map_new(pciio_win_map_t win_map, /* preallocated win map structure */ + size_t region_size, /* size of region to be tracked */ + size_t page_size); /* allocation page size */ + +/* destroy window mapping resource freeing up ancillary resources */ +extern void +pciio_device_win_map_free(pciio_win_map_t win_map); /* preallocated win map structure */ + +/* populate window mapping with free range of addresses */ +extern void +pciio_device_win_populate(pciio_win_map_t win_map, /* win map */ + iopaddr_t ioaddr, /* base address of free range */ + size_t size); /* size of free range */ + +/* allocate window from mapping resource */ +#ifdef CONFIG_IA64_SGI_SN1 +extern iopaddr_t +pciio_device_win_alloc(pciio_win_map_t win_map, /* win map */ + pciio_win_alloc_t win_alloc, /* opaque allocation cookie */ + size_t size, /* size of allocation */ + size_t align); /* alignment of allocation */ +#else +extern iopaddr_t +pciio_device_win_alloc(pciio_win_map_t win_map, /* win map */ + pciio_win_alloc_t win_alloc, /* opaque allocation cookie */ + size_t start, /* start unit, or 0 */ + size_t size, /* size of allocation */ + size_t align); /* alignment of allocation */ +#endif + +/* free previously allocated window */ +extern void +pciio_device_win_free(pciio_win_alloc_t win_alloc); /* opaque allocation cookie */ + + /* * Generic PCI interface, for use with all PCI providers * and all PCI devices. @@ -644,52 +691,6 @@ extern ulong pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap); extern caddr_t pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap); -#ifdef LATER -#ifdef USE_PCI_PIO -extern uint8_t pciio_pio_read8(volatile uint8_t *addr); -extern uint16_t pciio_pio_read16(volatile uint16_t *addr); -extern uint32_t pciio_pio_read32(volatile uint32_t *addr); -extern uint64_t pciio_pio_read64(volatile uint64_t *addr); -extern void pciio_pio_write8(uint8_t val, volatile uint8_t *addr); -extern void pciio_pio_write16(uint16_t val, volatile uint16_t *addr); -extern void pciio_pio_write32(uint32_t val, volatile uint32_t *addr); -extern void pciio_pio_write64(uint64_t val, volatile uint64_t *addr); -#else /* !USE_PCI_PIO */ -__inline uint8_t pciio_pio_read8(volatile uint8_t *addr) -{ - return *addr; -} -__inline uint16_t pciio_pio_read16(volatile uint16_t *addr) -{ - return *addr; -} -__inline uint32_t pciio_pio_read32(volatile uint32_t *addr) -{ - return *addr; -} -__inline uint64_t pciio_pio_read64(volatile uint64_t *addr) -{ - return *addr; -} -__inline void pciio_pio_write8(uint8_t val, volatile uint8_t *addr) -{ - *addr = val; -} -__inline void pciio_pio_write16(uint16_t val, volatile uint16_t *addr) -{ - *addr = val; -} -__inline void pciio_pio_write32(uint32_t val, volatile uint32_t *addr) -{ - *addr = val; -} -__inline void pciio_pio_write64(uint64_t val, volatile uint64_t *addr) -{ - *addr = val; -} -#endif /* USE_PCI_PIO */ -#endif /* LATER */ - /* Generic PCI dma interfaces */ extern devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap); @@ -701,8 +702,10 @@ /* Generic pci slot information access interface */ extern pciio_info_t pciio_info_chk(devfs_handle_t vhdl); extern pciio_info_t pciio_info_get(devfs_handle_t vhdl); +extern pciio_info_t pciio_hostinfo_get(devfs_handle_t vhdl); extern void pciio_info_set(devfs_handle_t vhdl, pciio_info_t widget_info); extern devfs_handle_t pciio_info_dev_get(pciio_info_t pciio_info); +extern devfs_handle_t pciio_info_hostdev_get(pciio_info_t pciio_info); extern pciio_bus_t pciio_info_bus_get(pciio_info_t pciio_info); extern pciio_slot_t pciio_info_slot_get(pciio_info_t pciio_info); extern pciio_function_t pciio_info_function_get(pciio_info_t pciio_info); @@ -718,7 +721,7 @@ extern size_t pciio_info_bar_size_get(pciio_info_t, int); extern iopaddr_t pciio_info_rom_base_get(pciio_info_t); extern size_t pciio_info_rom_size_get(pciio_info_t); - +extern int pciio_info_type1_get(pciio_info_t); extern int pciio_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); extern int pciio_dma_enabled(devfs_handle_t); diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pciio_private.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pciio_private.h --- linux-2.4.19/include/asm-ia64/sn/pci/pciio_private.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pciio_private.h Mon Dec 30 14:16:56 2002 @@ -4,12 +4,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIIO_PRIVATE_H #define _ASM_SN_PCI_PCIIO_PRIVATE_H #include +#include /* * pciio_private.h -- private definitions for pciio @@ -49,6 +50,8 @@ devfs_handle_t pi_dev; /* associated pci card */ device_desc_t pi_dev_desc; /* override device descriptor */ pciio_intr_line_t pi_lines; /* which interrupt line(s) */ + intr_func_t pi_func; /* handler function (when connected) */ + intr_arg_t pi_arg; /* handler parameter (when connected) */ cpuid_t pi_mustruncpu; /* Where we must run. */ int pi_irq; /* IRQ assigned */ int pi_cpu; /* cpu assigned */ @@ -59,6 +62,39 @@ #define PCIIO_INTR_NOTHREAD 2 /* interrupt handler wants to be called at interrupt level */ /* + * Some PCI provider implementations keep track of PCI window Base Address + * Register (BAR) address range assignment via the rmalloc()/rmfree() arena + * management routines. These implementations use the following data + * structure for each allocation address space (e.g. memory, I/O, small + * window, etc.). + * + * The ``page size'' encodes the minimum allocation unit and must be a power + * of 2. The main use of this allocation ``page size'' is to control the + * number of free address ranges that the mapping allocation software will + * need to track. Smaller values will allow more efficient use of the address + * ranges but will result in much larger allocation map structures ... For + * instance, if we want to manage allocations for a 256MB address range, + * choosing a 1MB allocation page size will result in up to 1MB being wasted + * for allocation requests smaller than 1MB. The worst case allocation + * pattern for the allocation software to track would be a pattern of 1MB + * allocated, 1MB free. This results in the need to track up to 128 free + * ranges. + */ +struct pciio_win_map_s { + struct map *wm_map; /* window address map */ + int wm_page_size; /* allocation ``page size'' */ +}; + +/* + * Opaque structure used to keep track of window allocation information. + */ +struct pciio_win_alloc_s { + pciio_win_map_t wa_map; /* window map allocation is from */ + unsigned long wa_base; /* allocation starting page number */ + size_t wa_pages; /* number of pages in allocation */ +}; + +/* * Each PCI Card has one of these. */ @@ -76,17 +112,17 @@ error_handler_f *c_efunc; /* error handling function */ error_handler_arg_t c_einfo; /* first parameter for efunc */ - struct { /* state of BASE regs */ - pciio_space_t w_space; - iopaddr_t w_base; - size_t w_size; - int w_devio_index; /* DevIO[] register used to - access this window */ - } c_window[6]; - - unsigned c_rbase; /* EXPANSION ROM base addr */ - unsigned c_rsize; /* EXPANSION ROM size (bytes) */ - + struct pciio_win_info_s { /* state of BASE regs */ + pciio_space_t w_space; + iopaddr_t w_base; + size_t w_size; + int w_devio_index; /* DevIO[] register used to + access this window */ + struct pciio_win_alloc_s w_win_alloc; /* window allocation cookie */ + } c_window[PCI_CFG_BASE_ADDRS + 1]; +#define c_rwindow c_window[PCI_CFG_BASE_ADDRS] /* EXPANSION ROM window */ +#define c_rbase c_rwindow.w_base /* EXPANSION ROM base addr */ +#define c_rsize c_rwindow.w_size /* EXPANSION ROM size (bytes) */ pciio_piospace_t c_piospace; /* additional I/O spaces allocated */ }; diff -Nur linux-2.4.19/include/asm-ia64/sn/pci/pic.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pic.h --- linux-2.4.19/include/asm-ia64/sn/pci/pic.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pci/pic.h Mon Dec 30 14:16:56 2002 @@ -0,0 +1,2001 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ +#ifndef _ASM_SN_PCI_PIC_H +#define _ASM_SN_PCI_PIC_H + + +/* + * The PIC ASIC is a follow-on to the Bridge and Xbridge ASICs. + * It shares many of the same registers as those chips and therefore + * the primary structure for the PIC will be bridge_s as defined + * in irix/kern/sys/PCI/bridge.h. This file is intended as a complement + * to bridge.h, which includes this file. + */ + +/* + * PIC AS DEVICE ZERO + * ------------------ + * + * PIC handles PCI/X busses. PCI/X requires that the 'bridge' (i.e. PIC) + * be designated as 'device 0'. That is a departure from earlier SGI + * PCI bridges. Because of that we use config space 1 to access the + * config space of the first actual PCI device on the bus. + * Here's what the PIC manual says: + * + * The current PCI-X bus specification now defines that the parent + * hosts bus bridge (PIC for example) must be device 0 on bus 0. PIC + * reduced the total number of devices from 8 to 4 and removed the + * device registers and windows, now only supporting devices 0,1,2, and + * 3. PIC did leave all 8 configuration space windows. The reason was + * there was nothing to gain by removing them. Here in lies the problem. + * The device numbering we do using 0 through 3 is unrelated to the device + * numbering which PCI-X requires in configuration space. In the past we + * correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc. + * PCI-X requires we start a 1, not 0 and currently the PX brick + * does associate our: + * + * device 0 with configuration space window 1, + * device 1 with configuration space window 2, + * device 2 with configuration space window 3, + * device 3 with configuration space window 4. + * + * The net effect is that all config space access are off-by-one with + * relation to other per-slot accesses on the PIC. + * Here is a table that shows some of that: + * + * Internal Slot# + * | + * | 0 1 2 3 + * ----------|--------------------------------------- + * config | 0x21000 0x22000 0x23000 0x24000 + * | + * even rrb | 0[0] n/a 1[0] n/a [] == implied even/odd + * | + * odd rrb | n/a 0[1] n/a 1[1] + * | + * int dev | 00 01 10 11 + * | + * ext slot# | 1 2 3 4 + * ----------|--------------------------------------- + */ + + +#ifndef __ASSEMBLY__ + +#ifdef __cplusplus +extern "C" { +#endif + +// #include +#include + + +/********************************************************************* + * bus provider function table + * + * Normally, this table is only handed off explicitly + * during provider initialization, and the PCI generic + * layer will stash a pointer to it in the vertex; however, + * exporting it explicitly enables a performance hack in + * the generic PCI provider where if we know at compile + * time that the only possible PCI provider is a + * pcibr, we can go directly to this ops table. + */ + +extern pciio_provider_t pci_pic_provider; + + +/********************************************************************* + * misc defines + * + */ +#define PIC_WIDGET_PART_NUM_BUS0 0xd102 +#define PIC_WIDGET_PART_NUM_BUS1 0xd112 +#define PIC_WIDGET_MFGR_NUM 0x24 +#define PIC_WIDGET_REV_A 0x1 + +#define IS_PIC_PART_REV_A(rev) \ + ((rev == (PIC_WIDGET_PART_NUM_BUS0 << 4 | PIC_WIDGET_REV_A)) || \ + (rev == (PIC_WIDGET_PART_NUM_BUS1 << 4 | PIC_WIDGET_REV_A))) + +/********************************************************************* + * register offset defines + * + */ + /* Identification Register -- read-only */ +#define PIC_IDENTIFICATION 0x00000000 + + /* Status Register -- read-only */ +#define PIC_STATUS 0x00000008 + + /* Upper Address Holding Register Bus Side Errors -- read-only */ +#define PIC_UPPER_ADDR_REG_BUS_SIDE_ERRS 0x00000010 + + /* Lower Address Holding Register Bus Side Errors -- read-only */ +#define PIC_LOWER_ADDR_REG_BUS_SIDE_ERRS 0x00000018 + + /* Control Register -- read/write */ +#define PIC_CONTROL 0x00000020 + + /* PCI Request Time-out Value Register -- read/write */ +#define PIC_PCI_REQ_TIME_OUT_VALUE 0x00000028 + + /* Interrupt Destination Upper Address Register -- read/write */ +#define PIC_INTR_DEST_UPPER_ADDR 0x00000030 + + /* Interrupt Destination Lower Address Register -- read/write */ +#define PIC_INTR_DEST_LOWER_ADDR 0x00000038 + + /* Command Word Holding Register Bus Side -- read-only */ +#define PIC_CMD_WORD_REG_BUS_SIDE 0x00000040 + + /* LLP Configuration Register (Bus 0 Only) -- read/write */ +#define PIC_LLP_CFG_REG_(BUS_0_ONLY) 0x00000048 + + /* PCI Target Flush Register -- read-only */ +#define PIC_PCI_TARGET_FLUSH 0x00000050 + + /* Command Word Holding Register Link Side -- read-only */ +#define PIC_CMD_WORD_REG_LINK_SIDE 0x00000058 + + /* Response Buffer Error Upper Address Holding -- read-only */ +#define PIC_RESP_BUF_ERR_UPPER_ADDR_ 0x00000060 + + /* Response Buffer Error Lower Address Holding -- read-only */ +#define PIC_RESP_BUF_ERR_LOWER_ADDR_ 0x00000068 + + /* Test Pin Control Register -- read/write */ +#define PIC_TEST_PIN_CONTROL 0x00000070 + + /* Address Holding Register Link Side Errors -- read-only */ +#define PIC_ADDR_REG_LINK_SIDE_ERRS 0x00000078 + + /* Direct Map Register -- read/write */ +#define PIC_DIRECT_MAP 0x00000080 + + /* PCI Map Fault Address Register -- read-only */ +#define PIC_PCI_MAP_FAULT_ADDR 0x00000090 + + /* Arbitration Priority Register -- read/write */ +#define PIC_ARBITRATION_PRIORITY 0x000000A0 + + /* Internal Ram Parity Error Register -- read-only */ +#define PIC_INTERNAL_RAM_PARITY_ERR 0x000000B0 + + /* PCI Time-out Register -- read/write */ +#define PIC_PCI_TIME_OUT 0x000000C0 + + /* PCI Type 1 Configuration Register -- read/write */ +#define PIC_PCI_TYPE_1_CFG 0x000000C8 + + /* PCI Bus Error Upper Address Holding Register -- read-only */ +#define PIC_PCI_BUS_ERR_UPPER_ADDR_ 0x000000D0 + + /* PCI Bus Error Lower Address Holding Register -- read-only */ +#define PIC_PCI_BUS_ERR_LOWER_ADDR_ 0x000000D8 + + /* PCIX Error Address Register -- read-only */ +#define PIC_PCIX_ERR_ADDR 0x000000E0 + + /* PCIX Error Attribute Register -- read-only */ +#define PIC_PCIX_ERR_ATTRIBUTE 0x000000E8 + + /* PCIX Error Data Register -- read-only */ +#define PIC_PCIX_ERR_DATA 0x000000F0 + + /* PCIX Read Request Timeout Error Register -- read-only */ +#define PIC_PCIX_READ_REQ_TIMEOUT_ERR 0x000000F8 + + /* Interrupt Status Register -- read-only */ +#define PIC_INTR_STATUS 0x00000100 + + /* Interrupt Enable Register -- read/write */ +#define PIC_INTR_ENABLE 0x00000108 + + /* Reset Interrupt Status Register -- write-only */ +#define PIC_RESET_INTR_STATUS 0x00000110 + + /* Interrupt Mode Register -- read/write */ +#define PIC_INTR_MODE 0x00000118 + + /* Interrupt Device Register -- read/write */ +#define PIC_INTR_DEVICE 0x00000120 + + /* Host Error Field Register -- read/write */ +#define PIC_HOST_ERR_FIELD 0x00000128 + + /* Interrupt Pin 0 Host Address Register -- read/write */ +#define PIC_INTR_PIN_0_HOST_ADDR 0x00000130 + + /* Interrupt Pin 1 Host Address Register -- read/write */ +#define PIC_INTR_PIN_1_HOST_ADDR 0x00000138 + + /* Interrupt Pin 2 Host Address Register -- read/write */ +#define PIC_INTR_PIN_2_HOST_ADDR 0x00000140 + + /* Interrupt Pin 3 Host Address Register -- read/write */ +#define PIC_INTR_PIN_3_HOST_ADDR 0x00000148 + + /* Interrupt Pin 4 Host Address Register -- read/write */ +#define PIC_INTR_PIN_4_HOST_ADDR 0x00000150 + + /* Interrupt Pin 5 Host Address Register -- read/write */ +#define PIC_INTR_PIN_5_HOST_ADDR 0x00000158 + + /* Interrupt Pin 6 Host Address Register -- read/write */ +#define PIC_INTR_PIN_6_HOST_ADDR 0x00000160 + + /* Interrupt Pin 7 Host Address Register -- read/write */ +#define PIC_INTR_PIN_7_HOST_ADDR 0x00000168 + + /* Error Interrupt View Register -- read-only */ +#define PIC_ERR_INTR_VIEW 0x00000170 + + /* Multiple Interrupt Register -- read-only */ +#define PIC_MULTIPLE_INTR 0x00000178 + + /* Force Always Interrupt 0 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_0 0x00000180 + + /* Force Always Interrupt 1 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_1 0x00000188 + + /* Force Always Interrupt 2 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_2 0x00000190 + + /* Force Always Interrupt 3 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_3 0x00000198 + + /* Force Always Interrupt 4 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_4 0x000001A0 + + /* Force Always Interrupt 5 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_5 0x000001A8 + + /* Force Always Interrupt 6 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_6 0x000001B0 + + /* Force Always Interrupt 7 Register -- write-only */ +#define PIC_FORCE_ALWAYS_INTR_7 0x000001B8 + + /* Force w/Pin Interrupt 0 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_0 0x000001C0 + + /* Force w/Pin Interrupt 1 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_1 0x000001C8 + + /* Force w/Pin Interrupt 2 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_2 0x000001D0 + + /* Force w/Pin Interrupt 3 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_3 0x000001D8 + + /* Force w/Pin Interrupt 4 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_4 0x000001E0 + + /* Force w/Pin Interrupt 5 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_5 0x000001E8 + + /* Force w/Pin Interrupt 6 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_6 0x000001F0 + + /* Force w/Pin Interrupt 7 Register -- write-only */ +#define PIC_FORCE_PIN_INTR_7 0x000001F8 + + /* Device 0 Register -- read/write */ +#define PIC_DEVICE_0 0x00000200 + + /* Device 1 Register -- read/write */ +#define PIC_DEVICE_1 0x00000208 + + /* Device 2 Register -- read/write */ +#define PIC_DEVICE_2 0x00000210 + + /* Device 3 Register -- read/write */ +#define PIC_DEVICE_3 0x00000218 + + /* Device 0 Write Request Buffer Register -- read-only */ +#define PIC_DEVICE_0_WRITE_REQ_BUF 0x00000240 + + /* Device 1 Write Request Buffer Register -- read-only */ +#define PIC_DEVICE_1_WRITE_REQ_BUF 0x00000248 + + /* Device 2 Write Request Buffer Register -- read-only */ +#define PIC_DEVICE_2_WRITE_REQ_BUF 0x00000250 + + /* Device 3 Write Request Buffer Register -- read-only */ +#define PIC_DEVICE_3_WRITE_REQ_BUF 0x00000258 + + /* Even Device Response Buffer Register -- read/write */ +#define PIC_EVEN_DEVICE_RESP_BUF 0x00000280 + + /* Odd Device Response Buffer Register -- read/write */ +#define PIC_ODD_DEVICE_RESP_BUF 0x00000288 + + /* Read Response Buffer Status Register -- read-only */ +#define PIC_READ_RESP_BUF_STATUS 0x00000290 + + /* Read Response Buffer Clear Register -- write-only */ +#define PIC_READ_RESP_BUF_CLEAR 0x00000298 + + /* PCI RR 0 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_0_UPPER_ADDR_MATCH 0x00000300 + + /* PCI RR 0 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_0_LOWER_ADDR_MATCH 0x00000308 + + /* PCI RR 1 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_1_UPPER_ADDR_MATCH 0x00000310 + + /* PCI RR 1 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_1_LOWER_ADDR_MATCH 0x00000318 + + /* PCI RR 2 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_2_UPPER_ADDR_MATCH 0x00000320 + + /* PCI RR 2 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_2_LOWER_ADDR_MATCH 0x00000328 + + /* PCI RR 3 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_3_UPPER_ADDR_MATCH 0x00000330 + + /* PCI RR 3 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_3_LOWER_ADDR_MATCH 0x00000338 + + /* PCI RR 4 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_4_UPPER_ADDR_MATCH 0x00000340 + + /* PCI RR 4 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_4_LOWER_ADDR_MATCH 0x00000348 + + /* PCI RR 5 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_5_UPPER_ADDR_MATCH 0x00000350 + + /* PCI RR 5 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_5_LOWER_ADDR_MATCH 0x00000358 + + /* PCI RR 6 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_6_UPPER_ADDR_MATCH 0x00000360 + + /* PCI RR 6 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_6_LOWER_ADDR_MATCH 0x00000368 + + /* PCI RR 7 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_7_UPPER_ADDR_MATCH 0x00000370 + + /* PCI RR 7 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_7_LOWER_ADDR_MATCH 0x00000378 + + /* PCI RR 8 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_8_UPPER_ADDR_MATCH 0x00000380 + + /* PCI RR 8 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_8_LOWER_ADDR_MATCH 0x00000388 + + /* PCI RR 9 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_9_UPPER_ADDR_MATCH 0x00000390 + + /* PCI RR 9 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_9_LOWER_ADDR_MATCH 0x00000398 + + /* PCI RR 10 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_10_UPPER_ADDR_MATCH 0x000003A0 + + /* PCI RR 10 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_10_LOWER_ADDR_MATCH 0x000003A8 + + /* PCI RR 11 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_11_UPPER_ADDR_MATCH 0x000003B0 + + /* PCI RR 11 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_11_LOWER_ADDR_MATCH 0x000003B8 + + /* PCI RR 12 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_12_UPPER_ADDR_MATCH 0x000003C0 + + /* PCI RR 12 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_12_LOWER_ADDR_MATCH 0x000003C8 + + /* PCI RR 13 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_13_UPPER_ADDR_MATCH 0x000003D0 + + /* PCI RR 13 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_13_LOWER_ADDR_MATCH 0x000003D8 + + /* PCI RR 14 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_14_UPPER_ADDR_MATCH 0x000003E0 + + /* PCI RR 14 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_14_LOWER_ADDR_MATCH 0x000003E8 + + /* PCI RR 15 Upper Address Match Register -- read-only */ +#define PIC_PCI_RR_15_UPPER_ADDR_MATCH 0x000003F0 + + /* PCI RR 15 Lower Address Match Register -- read-only */ +#define PIC_PCI_RR_15_LOWER_ADDR_MATCH 0x000003F8 + + /* Buffer 0 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_0_FLUSH_CNT_WITH_DATA_TOUCH 0x00000400 + + /* Buffer 0 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_0_FLUSH_CNT_W_O_DATA_TOUCH 0x00000408 + + /* Buffer 0 Request in Flight Count Register -- read/write */ +#define PIC_BUF_0_REQ_IN_FLIGHT_CNT 0x00000410 + + /* Buffer 0 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_0_PREFETCH_REQ_CNT 0x00000418 + + /* Buffer 0 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_0_TOTAL_PCI_RETRY_CNT 0x00000420 + + /* Buffer 0 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_0_MAX_PCI_RETRY_CNT 0x00000428 + + /* Buffer 0 Max Latency Count Register -- read/write */ +#define PIC_BUF_0_MAX_LATENCY_CNT 0x00000430 + + /* Buffer 0 Clear All Register -- read/write */ +#define PIC_BUF_0_CLEAR_ALL 0x00000438 + + /* Buffer 2 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_2_FLUSH_CNT_WITH_DATA_TOUCH 0x00000440 + + /* Buffer 2 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_2_FLUSH_CNT_W_O_DATA_TOUCH 0x00000448 + + /* Buffer 2 Request in Flight Count Register -- read/write */ +#define PIC_BUF_2_REQ_IN_FLIGHT_CNT 0x00000450 + + /* Buffer 2 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_2_PREFETCH_REQ_CNT 0x00000458 + + /* Buffer 2 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_2_TOTAL_PCI_RETRY_CNT 0x00000460 + + /* Buffer 2 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_2_MAX_PCI_RETRY_CNT 0x00000468 + + /* Buffer 2 Max Latency Count Register -- read/write */ +#define PIC_BUF_2_MAX_LATENCY_CNT 0x00000470 + + /* Buffer 2 Clear All Register -- read/write */ +#define PIC_BUF_2_CLEAR_ALL 0x00000478 + + /* Buffer 4 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_4_FLUSH_CNT_WITH_DATA_TOUCH 0x00000480 + + /* Buffer 4 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_4_FLUSH_CNT_W_O_DATA_TOUCH 0x00000488 + + /* Buffer 4 Request in Flight Count Register -- read/write */ +#define PIC_BUF_4_REQ_IN_FLIGHT_CNT 0x00000490 + + /* Buffer 4 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_4_PREFETCH_REQ_CNT 0x00000498 + + /* Buffer 4 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_4_TOTAL_PCI_RETRY_CNT 0x000004A0 + + /* Buffer 4 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_4_MAX_PCI_RETRY_CNT 0x000004A8 + + /* Buffer 4 Max Latency Count Register -- read/write */ +#define PIC_BUF_4_MAX_LATENCY_CNT 0x000004B0 + + /* Buffer 4 Clear All Register -- read/write */ +#define PIC_BUF_4_CLEAR_ALL 0x000004B8 + + /* Buffer 6 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_6_FLUSH_CNT_WITH_DATA_TOUCH 0x000004C0 + + /* Buffer 6 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_6_FLUSH_CNT_W_O_DATA_TOUCH 0x000004C8 + + /* Buffer 6 Request in Flight Count Register -- read/write */ +#define PIC_BUF_6_REQ_IN_FLIGHT_CNT 0x000004D0 + + /* Buffer 6 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_6_PREFETCH_REQ_CNT 0x000004D8 + + /* Buffer 6 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_6_TOTAL_PCI_RETRY_CNT 0x000004E0 + + /* Buffer 6 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_6_MAX_PCI_RETRY_CNT 0x000004E8 + + /* Buffer 6 Max Latency Count Register -- read/write */ +#define PIC_BUF_6_MAX_LATENCY_CNT 0x000004F0 + + /* Buffer 6 Clear All Register -- read/write */ +#define PIC_BUF_6_CLEAR_ALL 0x000004F8 + + /* Buffer 8 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_8_FLUSH_CNT_WITH_DATA_TOUCH 0x00000500 + + /* Buffer 8 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_8_FLUSH_CNT_W_O_DATA_TOUCH 0x00000508 + + /* Buffer 8 Request in Flight Count Register -- read/write */ +#define PIC_BUF_8_REQ_IN_FLIGHT_CNT 0x00000510 + + /* Buffer 8 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_8_PREFETCH_REQ_CNT 0x00000518 + + /* Buffer 8 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_8_TOTAL_PCI_RETRY_CNT 0x00000520 + + /* Buffer 8 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_8_MAX_PCI_RETRY_CNT 0x00000528 + + /* Buffer 8 Max Latency Count Register -- read/write */ +#define PIC_BUF_8_MAX_LATENCY_CNT 0x00000530 + + /* Buffer 8 Clear All Register -- read/write */ +#define PIC_BUF_8_CLEAR_ALL 0x00000538 + + /* Buffer 10 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_10_FLUSH_CNT_WITH_DATA_TOUCH 0x00000540 + + /* Buffer 10 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_10_FLUSH_CNT_W_O_DATA_TOUCH 0x00000548 + + /* Buffer 10 Request in Flight Count Register -- read/write */ +#define PIC_BUF_10_REQ_IN_FLIGHT_CNT 0x00000550 + + /* Buffer 10 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_10_PREFETCH_REQ_CNT 0x00000558 + + /* Buffer 10 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_10_TOTAL_PCI_RETRY_CNT 0x00000560 + + /* Buffer 10 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_10_MAX_PCI_RETRY_CNT 0x00000568 + + /* Buffer 10 Max Latency Count Register -- read/write */ +#define PIC_BUF_10_MAX_LATENCY_CNT 0x00000570 + + /* Buffer 10 Clear All Register -- read/write */ +#define PIC_BUF_10_CLEAR_ALL 0x00000578 + + /* Buffer 12 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_12_FLUSH_CNT_WITH_DATA_TOUCH 0x00000580 + + /* Buffer 12 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_12_FLUSH_CNT_W_O_DATA_TOUCH 0x00000588 + + /* Buffer 12 Request in Flight Count Register -- read/write */ +#define PIC_BUF_12_REQ_IN_FLIGHT_CNT 0x00000590 + + /* Buffer 12 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_12_PREFETCH_REQ_CNT 0x00000598 + + /* Buffer 12 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_12_TOTAL_PCI_RETRY_CNT 0x000005A0 + + /* Buffer 12 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_12_MAX_PCI_RETRY_CNT 0x000005A8 + + /* Buffer 12 Max Latency Count Register -- read/write */ +#define PIC_BUF_12_MAX_LATENCY_CNT 0x000005B0 + + /* Buffer 12 Clear All Register -- read/write */ +#define PIC_BUF_12_CLEAR_ALL 0x000005B8 + + /* Buffer 14 Flush Count with Data Touch Register -- read/write */ +#define PIC_BUF_14_FLUSH_CNT_WITH_DATA_TOUCH 0x000005C0 + + /* Buffer 14 Flush Count w/o Data Touch Register -- read/write */ +#define PIC_BUF_14_FLUSH_CNT_W_O_DATA_TOUCH 0x000005C8 + + /* Buffer 14 Request in Flight Count Register -- read/write */ +#define PIC_BUF_14_REQ_IN_FLIGHT_CNT 0x000005D0 + + /* Buffer 14 Prefetch Request Count Register -- read/write */ +#define PIC_BUF_14_PREFETCH_REQ_CNT 0x000005D8 + + /* Buffer 14 Total PCI Retry Count Register -- read/write */ +#define PIC_BUF_14_TOTAL_PCI_RETRY_CNT 0x000005E0 + + /* Buffer 14 Max PCI Retry Count Register -- read/write */ +#define PIC_BUF_14_MAX_PCI_RETRY_CNT 0x000005E8 + + /* Buffer 14 Max Latency Count Register -- read/write */ +#define PIC_BUF_14_MAX_LATENCY_CNT 0x000005F0 + + /* Buffer 14 Clear All Register -- read/write */ +#define PIC_BUF_14_CLEAR_ALL 0x000005F8 + + /* PCIX Read Buffer 0 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_0_ADDR 0x00000A00 + + /* PCIX Read Buffer 0 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_0_ATTRIBUTE 0x00000A08 + + /* PCIX Read Buffer 1 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_1_ADDR 0x00000A10 + + /* PCIX Read Buffer 1 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_1_ATTRIBUTE 0x00000A18 + + /* PCIX Read Buffer 2 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_2_ADDR 0x00000A20 + + /* PCIX Read Buffer 2 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_2_ATTRIBUTE 0x00000A28 + + /* PCIX Read Buffer 3 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_3_ADDR 0x00000A30 + + /* PCIX Read Buffer 3 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_3_ATTRIBUTE 0x00000A38 + + /* PCIX Read Buffer 4 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_4_ADDR 0x00000A40 + + /* PCIX Read Buffer 4 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_4_ATTRIBUTE 0x00000A48 + + /* PCIX Read Buffer 5 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_5_ADDR 0x00000A50 + + /* PCIX Read Buffer 5 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_5_ATTRIBUTE 0x00000A58 + + /* PCIX Read Buffer 6 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_6_ADDR 0x00000A60 + + /* PCIX Read Buffer 6 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_6_ATTRIBUTE 0x00000A68 + + /* PCIX Read Buffer 7 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_7_ADDR 0x00000A70 + + /* PCIX Read Buffer 7 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_7_ATTRIBUTE 0x00000A78 + + /* PCIX Read Buffer 8 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_8_ADDR 0x00000A80 + + /* PCIX Read Buffer 8 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_8_ATTRIBUTE 0x00000A88 + + /* PCIX Read Buffer 9 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_9_ADDR 0x00000A90 + + /* PCIX Read Buffer 9 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_9_ATTRIBUTE 0x00000A98 + + /* PCIX Read Buffer 10 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_10_ADDR 0x00000AA0 + + /* PCIX Read Buffer 10 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_10_ATTRIBUTE 0x00000AA8 + + /* PCIX Read Buffer 11 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_11_ADDR 0x00000AB0 + + /* PCIX Read Buffer 11 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_11_ATTRIBUTE 0x00000AB8 + + /* PCIX Read Buffer 12 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_12_ADDR 0x00000AC0 + + /* PCIX Read Buffer 12 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_12_ATTRIBUTE 0x00000AC8 + + /* PCIX Read Buffer 13 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_13_ADDR 0x00000AD0 + + /* PCIX Read Buffer 13 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_13_ATTRIBUTE 0x00000AD8 + + /* PCIX Read Buffer 14 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_14_ADDR 0x00000AE0 + + /* PCIX Read Buffer 14 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_14_ATTRIBUTE 0x00000AE8 + + /* PCIX Read Buffer 15 Address Register -- read-only */ +#define PIC_PCIX_READ_BUF_15_ADDR 0x00000AF0 + + /* PCIX Read Buffer 15 Attribute Register -- read-only */ +#define PIC_PCIX_READ_BUF_15_ATTRIBUTE 0x00000AF8 + + /* PCIX Write Buffer 0 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_0_ADDR 0x00000B00 + + /* PCIX Write Buffer 0 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_0_ATTRIBUTE 0x00000B08 + + /* PCIX Write Buffer 0 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_0_VALID 0x00000B10 + + /* PCIX Write Buffer 1 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_1_ADDR 0x00000B20 + + /* PCIX Write Buffer 1 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_1_ATTRIBUTE 0x00000B28 + + /* PCIX Write Buffer 1 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_1_VALID 0x00000B30 + + /* PCIX Write Buffer 2 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_2_ADDR 0x00000B40 + + /* PCIX Write Buffer 2 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_2_ATTRIBUTE 0x00000B48 + + /* PCIX Write Buffer 2 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_2_VALID 0x00000B50 + + /* PCIX Write Buffer 3 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_3_ADDR 0x00000B60 + + /* PCIX Write Buffer 3 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_3_ATTRIBUTE 0x00000B68 + + /* PCIX Write Buffer 3 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_3_VALID 0x00000B70 + + /* PCIX Write Buffer 4 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_4_ADDR 0x00000B80 + + /* PCIX Write Buffer 4 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_4_ATTRIBUTE 0x00000B88 + + /* PCIX Write Buffer 4 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_4_VALID 0x00000B90 + + /* PCIX Write Buffer 5 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_5_ADDR 0x00000BA0 + + /* PCIX Write Buffer 5 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_5_ATTRIBUTE 0x00000BA8 + + /* PCIX Write Buffer 5 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_5_VALID 0x00000BB0 + + /* PCIX Write Buffer 6 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_6_ADDR 0x00000BC0 + + /* PCIX Write Buffer 6 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_6_ATTRIBUTE 0x00000BC8 + + /* PCIX Write Buffer 6 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_6_VALID 0x00000BD0 + + /* PCIX Write Buffer 7 Address Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_7_ADDR 0x00000BE0 + + /* PCIX Write Buffer 7 Attribute Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_7_ATTRIBUTE 0x00000BE8 + + /* PCIX Write Buffer 7 Valid Register -- read-only */ +#define PIC_PCIX_WRITE_BUF_7_VALID 0x00000BF0 + +/********************************************************************* + * misc typedefs + * + */ +typedef uint64_t picreg_t; + +/********************************************************************* + * PIC register structures + * + */ + +/* + * Identification Register + * + * The Identification register is a read only register used by the host CPU + * during configuration to determine the type of the widget. The format is + * the same as defined in IEEE 1149.1 JTAG Device Identification Register. + */ + typedef union pic_id_reg_u { + picreg_t pic_id_reg_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t rev_num : 4; /* 31:28 */ + picreg_t part_num : 16; /* 27:12 */ + picreg_t mfg_num : 11; /* 11:1 */ + picreg_t : 1; /* 0:0 */ + } pic_id_reg_fld_s; + } pic_id_reg_u_t; +/* + * Status Register + * + * The status register is a read register which holds status information of the + * Bus Subsection. + */ + typedef union pic_stat_reg_u { + picreg_t pic_stat_reg_regval; + struct { + picreg_t : 28; /* 63:36 */ + picreg_t pci_x_speed : 2; /* 35:34 */ + picreg_t pci_x_active : 1; /* 33:33 */ + picreg_t : 1; /* 32:32 */ + picreg_t llp_rec_cnt : 8; /* 31:24 */ + picreg_t llp_tx_cnt : 8; /* 23:16 */ + picreg_t rx_credit_cnt : 4; /* 15:12 */ + picreg_t tx_credit_cnt : 4; /* 11:8 */ + picreg_t pci_misc_input : 8; /* 7:0 */ + } pic_stat_reg_fld_s; + } pic_stat_reg_u_t; +/* + * Upper Address Holding Register Bus Side Errors + * + * The upper address holding register is a read only register which contains + * the upper 16-bits of the address when certain error occurs (see error cases + * chapter). Subsequent errors are not logged until the error is cleared. The + * last logged value is held until the group is cleared and enabled. + */ + typedef union pic_upper_bus_err_u { + picreg_t pic_upper_bus_err_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t upp_addr : 16; /* 15:0 */ + } pic_upper_bus_err_fld_s; + } pic_upper_bus_err_u_t; +/* + * Lower Address Holding Register Bus Side Errors + * + * The lower address holding register is a read only register which contains + * the address which either can be accessed as a word or double word. Sub- + * sequent errors are not logged until the error is cleared. The last logged + * value is held until the group is cleared and enabled. + */ + typedef union pic_lower_bus_err_u { + picreg_t pic_lower_bus_err_regval; + struct { + picreg_t : 16; /* 63:48 */ + picreg_t upp_addr : 16; /* 47:32 */ + picreg_t low_addr : 32; /* 31:0 */ + } pic_lower_bus_err_fld_s; + } pic_lower_bus_err_u_t; +/* + * Control Register + * + * The control register is a read/write register which holds control informa- + * tion for the bus subsection. + */ + typedef union pic_control_reg_u { + picreg_t pic_control_reg_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 4; /* 31:28 */ + picreg_t rst_pin_n : 4; /* 27:24 */ + picreg_t : 1; /* 23:23 */ + picreg_t mem_swap : 1; /* 22:22 */ + picreg_t page_size : 1; /* 21:21 */ + picreg_t : 4; /* 20:17 */ + picreg_t f_bad_pkt : 1; /* 16:16 */ + picreg_t llp_xbar_crd : 4; /* 15:12 */ + picreg_t clr_rllp_cnt : 1; /* 11:11 */ + picreg_t clr_tllp_cnt : 1; /* 10:10 */ + picreg_t sys_end : 1; /* 9:9 */ + picreg_t : 3; /* 8:6 */ + picreg_t pci_speed : 2; /* 5:4 */ + picreg_t widget_id : 4; /* 3:0 */ + } pic_control_reg_fld_s; + } pic_control_reg_u_t; +/* + * PCI/PCI-X Request Time-out Value Register + * + * This register contains the reload value for the response timer. The request + * timer counts every 960 nS (32 PCI clocks) + */ + typedef union pic_pci_req_to_u { + picreg_t pic_pci_req_to_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 12; /* 31:20 */ + picreg_t time_out : 20; /* 19:0 */ + } pic_pci_req_to_fld_s; + } pic_pci_req_to_u_t; +/* + * Interrupt Destination Upper Address Register + * + * The interrupt destination upper address register is a read/write register + * containing the upper 16-bits of address of the host to which the interrupt + * is targeted. In addition the target ID is also contained in this register for + * use in Crosstalk mode. + */ + typedef union pic_int_desc_upper_u { + picreg_t pic_int_desc_upper_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 12; /* 31:20 */ + picreg_t target_id : 4; /* 19:16 */ + picreg_t upp_addr : 16; /* 15:0 */ + } pic_int_desc_upper_fld_s; + } pic_int_desc_upper_u_t; +/* + * Interrupt Destination Lower Address Register + * + * The interrupt destination lower address register is a read/write register + * which contains the entire address of the host to which the interrupt is tar- + * geted. In addition the target ID is also contained in this register for use in + * Crosstalk mode. + */ + typedef union pic_int_desc_lower_u { + picreg_t pic_int_desc_lower_regval; + struct { + picreg_t : 12; /* 63:52 */ + picreg_t target_id : 4; /* 51:48 */ + picreg_t upp_addr : 16; /* 47:32 */ + picreg_t low_addr : 32; /* 31:0 */ + } pic_int_desc_lower_fld_s; + } pic_int_desc_lower_u_t; +/* + * Command Word Holding Register Bus Side Errors + * + * The command word holding is a read register that holds the command + * word of a Crosstalk packet when errors occur on the link side (see error + * chapter). Errors are indicated with error bits in the interrupt status regis- + * ter. Subsequent errors are not logged until the interrupt is cleared.. + */ + typedef union pic_cmd_word_bus_err_u { + picreg_t pic_cmd_word_bus_err_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t didn : 4; /* 31:28 */ + picreg_t sidn : 4; /* 27:24 */ + picreg_t pactyp : 4; /* 23:20 */ + picreg_t tnum : 5; /* 19:15 */ + picreg_t coherent : 1; /* 14:14 */ + picreg_t ds : 2; /* 13:12 */ + picreg_t gbr : 1; /* 11:11 */ + picreg_t vbpm : 1; /* 10:10 */ + picreg_t error : 1; /* 9:9 */ + picreg_t barrier : 1; /* 8:8 */ + picreg_t : 8; /* 7:0 */ + } pic_cmd_word_bus_err_fld_s; + } pic_cmd_word_bus_err_u_t; +/* + * LLP Configuration Register + * + * This register contains the configuration information for the LLP modules + * and is only valid on bus 0 side. + */ + typedef union pic_llp_cfg_u { + picreg_t pic_llp_cfg_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 6; /* 31:26 */ + picreg_t llp_maxretry : 10; /* 25:16 */ + picreg_t llp_nulltimeout : 6; /* 15:10 */ + picreg_t llp_maxburst : 10; /* 9:0 */ + } pic_llp_cfg_fld_s; + } pic_llp_cfg_u_t; +/* + * PCI/PCI-X Target Flush Register + * + * When read, this register will return a 0x00 after all previous transfers to + * the PCI bus subsection have completed. + */ + +/* + * Command Word Holding Register Link Side Errors + * + * The command word holding is a read-only register that holds the com- + * mand word of a Crosstalk packet when request fifo overflow or unexpect- + * ed response errors occur. Errors are indicated with error bits in the + * interrupt status register. Subsequent errors are not logged until this inter- + * rupt is cleared. + */ + typedef union pic_cmd_word_link_err_u { + picreg_t pic_cmd_word_link_err_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t didn : 4; /* 31:28 */ + picreg_t sidn : 4; /* 27:24 */ + picreg_t pactyp : 4; /* 23:20 */ + picreg_t tnum : 5; /* 19:15 */ + picreg_t coherent : 1; /* 14:14 */ + picreg_t ds : 2; /* 13:12 */ + picreg_t gbr : 1; /* 11:11 */ + picreg_t vbpm : 1; /* 10:10 */ + picreg_t error : 1; /* 9:9 */ + picreg_t barrier : 1; /* 8:8 */ + picreg_t : 8; /* 7:0 */ + } pic_cmd_word_link_err_fld_s; + } pic_cmd_word_link_err_u_t; +/* + * PCI Response Buffer Error Upper Address Holding Reg + * + * The response buffer error upper address holding register is a read only + * register which contains the upper 16-bits of the address when error asso- + * ciated with response buffer entries occur. Subsequent errors are not + * logged until the interrupt is cleared. + */ + typedef union pic_pci_rbuf_err_upper_u { + picreg_t pic_pci_rbuf_err_upper_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 9; /* 31:23 */ + picreg_t dev_num : 3; /* 22:20 */ + picreg_t buff_num : 4; /* 19:16 */ + picreg_t upp_addr : 16; /* 15:0 */ + } pic_pci_rbuf_err_upper_fld_s; + } pic_pci_rbuf_err_upper_u_t; +/* + * PCI Response Buffer Error Lower Address Holding Reg + * + * The response buffer error lower address holding register is a read only + * register which contains the address of the error associated with response + * buffer entries. Subsequent errors are not logged until the interrupt is + * cleared. + */ + typedef union pic_pci_rbuf_err_lower_u { + picreg_t pic_pci_rbuf_err_lower_regval; + struct { + picreg_t : 9; /* 63:55 */ + picreg_t dev_num : 3; /* 54:52 */ + picreg_t buff_num : 4; /* 51:48 */ + picreg_t upp_addr : 16; /* 47:32 */ + picreg_t low_addr : 32; /* 31:0 */ + } pic_pci_rbuf_err_lower_fld_s; + } pic_pci_rbuf_err_lower_u_t; +/* + * Test Pin Control Register + * + * This register selects the output function and value to the four test pins on + * the PIC . + */ + typedef union pic_test_pin_cntl_u { + picreg_t pic_test_pin_cntl_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 8; /* 31:24 */ + picreg_t tdata_out : 8; /* 23:16 */ + picreg_t sel_tpin_7 : 2; /* 15:14 */ + picreg_t sel_tpin_6 : 2; /* 13:12 */ + picreg_t sel_tpin_5 : 2; /* 11:10 */ + picreg_t sel_tpin_4 : 2; /* 9:8 */ + picreg_t sel_tpin_3 : 2; /* 7:6 */ + picreg_t sel_tpin_2 : 2; /* 5:4 */ + picreg_t sel_tpin_1 : 2; /* 3:2 */ + picreg_t sel_tpin_0 : 2; /* 1:0 */ + } pic_test_pin_cntl_fld_s; + } pic_test_pin_cntl_u_t; +/* + * Address Holding Register Link Side Errors + * + * The address holding register is a read only register which contains the ad- + * dress which either can be accessed as a word or double word. Subsequent + * errors are not logged until the error is cleared. The last logged value is + * held until the group is cleared and enabled. + */ + typedef union pic_p_addr_lkerr_u { + picreg_t pic_p_addr_lkerr_regval; + struct { + picreg_t : 16; /* 63:48 */ + picreg_t upp_addr : 16; /* 47:32 */ + picreg_t low_addr : 32; /* 31:0 */ + } pic_p_addr_lkerr_fld_s; + } pic_p_addr_lkerr_u_t; +/* + * PCI Direct Mapping Register + * + * This register is used to relocate a 2 GByte region for PCI to Crosstalk + * transfers. + */ + typedef union pic_p_dir_map_u { + picreg_t pic_p_dir_map_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 8; /* 31:24 */ + picreg_t dir_w_id : 4; /* 23:20 */ + picreg_t : 2; /* 19:18 */ + picreg_t dir_add512 : 1; /* 17:17 */ + picreg_t dir_off : 17; /* 16:0 */ + } pic_p_dir_map_fld_s; + } pic_p_dir_map_u_t; +/* + * PCI Page Map Fault Address Register + * + * This register contains the address and device number when a page map + * fault occurred. + */ + typedef union pic_p_map_fault_u { + picreg_t pic_p_map_fault_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 10; /* 31:22 */ + picreg_t pci_addr : 18; /* 21:4 */ + picreg_t : 1; /* 3:3 */ + picreg_t pci_dev_num : 3; /* 2:0 */ + } pic_p_map_fault_fld_s; + } pic_p_map_fault_u_t; +/* + * Arbitration Register + * + * This register defines the priority and bus time out timing in PCI bus arbi- + * tration. + */ + typedef union pic_p_arb_u { + picreg_t pic_p_arb_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 8; /* 31:24 */ + picreg_t dev_broke : 4; /* 23:20 */ + picreg_t : 2; /* 19:18 */ + picreg_t req_wait_tick : 2; /* 17:16 */ + picreg_t : 4; /* 15:12 */ + picreg_t req_wait_en : 4; /* 11:8 */ + picreg_t disarb : 1; /* 7:7 */ + picreg_t freeze_gnt : 1; /* 6:6 */ + picreg_t : 1; /* 5:5 */ + picreg_t en_bridge_hi : 2; /* 4:3 */ + picreg_t : 1; /* 2:2 */ + picreg_t en_bridge_lo : 2; /* 1:0 */ + } pic_p_arb_fld_s; + } pic_p_arb_u_t; +/* + * Internal Ram Parity Error Register + * + * This register logs information about parity errors on internal ram access. + */ + typedef union pic_p_ram_perr_u { + picreg_t pic_p_ram_perr_regval; + struct { + picreg_t : 6; /* 63:58 */ + picreg_t ate_err_addr : 10; /* 57:48 */ + picreg_t : 7; /* 47:41 */ + picreg_t rd_resp_err_addr : 9; /* 40:32 */ + picreg_t wrt_resp_err_addr : 8; /* 31:24 */ + picreg_t : 2; /* 23:22 */ + picreg_t ate_err : 1; /* 21:21 */ + picreg_t rd_resp_err : 1; /* 20:20 */ + picreg_t wrt_resp_err : 1; /* 19:19 */ + picreg_t dbe_ate : 3; /* 18:16 */ + picreg_t dbe_rd : 8; /* 15:8 */ + picreg_t dbe_wrt : 8; /* 7:0 */ + } pic_p_ram_perr_fld_s; + } pic_p_ram_perr_u_t; +/* + * Time-out Register + * + * This register determines retry hold off and max retries allowed for PIO + * accesses to PCI/PCI-X. + */ + typedef union pic_p_bus_timeout_u { + picreg_t pic_p_bus_timeout_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 11; /* 31:21 */ + picreg_t pci_retry_hld : 5; /* 20:16 */ + picreg_t : 6; /* 15:10 */ + picreg_t pci_retry_cnt : 10; /* 9:0 */ + } pic_p_bus_timeout_fld_s; + } pic_p_bus_timeout_u_t; +/* + * PCI/PCI-X Type 1 Configuration Register + * + * This register is use during accesses to the PCI/PCI-X type 1 configuration + * space. The bits in this register are used to supplement the address during + * the configuration cycle to select the correct secondary bus and device. + */ + typedef union pic_type1_cfg_u { + picreg_t pic_type1_cfg_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 8; /* 31:24 */ + picreg_t bus_num : 8; /* 23:16 */ + picreg_t dev_num : 5; /* 15:11 */ + picreg_t : 11; /* 10:0 */ + } pic_type1_cfg_fld_s; + } pic_type1_cfg_u_t; +/* + * PCI Bus Error Upper Address Holding Register + * + * This register holds the value of the upper address on the PCI Bus when an + * error occurs. + */ + typedef union pic_p_pci_err_upper_u { + picreg_t pic_p_pci_err_upper_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 4; /* 31:28 */ + picreg_t pci_xtalk_did : 4; /* 27:24 */ + picreg_t : 2; /* 23:22 */ + picreg_t pci_dac : 1; /* 21:21 */ + picreg_t pci_dev_master : 1; /* 20:20 */ + picreg_t pci_vdev : 1; /* 19:19 */ + picreg_t pci_dev_num : 3; /* 18:16 */ + picreg_t pci_uaddr_err : 16; /* 15:0 */ + } pic_p_pci_err_upper_fld_s; + } pic_p_pci_err_upper_u_t; +/* + * PCI Bus Error Lower Address Holding Register + * + * This register holds the value of the lower address on the PCI Bus when an + * error occurs. + */ + typedef union pic_p_pci_err_lower_u { + picreg_t pic_p_pci_err_lower_regval; + struct { + picreg_t : 4; /* 63:60 */ + picreg_t pci_xtalk_did : 4; /* 59:56 */ + picreg_t : 2; /* 55:54 */ + picreg_t pci_dac : 1; /* 53:53 */ + picreg_t pci_dev_master : 1; /* 52:52 */ + picreg_t pci_vdev : 1; /* 51:51 */ + picreg_t pci_dev_num : 3; /* 50:48 */ + picreg_t pci_uaddr_err : 16; /* 47:32 */ + picreg_t pci_laddr_err : 32; /* 31:0 */ + } pic_p_pci_err_lower_fld_s; + } pic_p_pci_err_lower_u_t; +/* + * PCI-X Error Address Register + * + * This register contains the address on the PCI-X bus when an error oc- + * curred. + */ + typedef union pic_p_pcix_err_addr_u { + picreg_t pic_p_pcix_err_addr_regval; + struct { + picreg_t pcix_err_addr : 64; /* 63:0 */ + } pic_p_pcix_err_addr_fld_s; + } pic_p_pcix_err_addr_u_t; +/* + * PCI-X Error Attribute Register + * + * This register contains the attribute data on the PCI-X bus when an error + * occurred. + */ + typedef union pic_p_pcix_err_attr_u { + picreg_t pic_p_pcix_err_attr_regval; + struct { + picreg_t : 16; /* 63:48 */ + picreg_t bus_cmd : 4; /* 47:44 */ + picreg_t byte_cnt : 12; /* 43:32 */ + picreg_t : 1; /* 31:31 */ + picreg_t ns : 1; /* 30:30 */ + picreg_t ro : 1; /* 29:29 */ + picreg_t tag : 5; /* 28:24 */ + picreg_t bus_num : 8; /* 23:16 */ + picreg_t dev_num : 5; /* 15:11 */ + picreg_t fun_num : 3; /* 10:8 */ + picreg_t l_byte_cnt : 8; /* 7:0 */ + } pic_p_pcix_err_attr_fld_s; + } pic_p_pcix_err_attr_u_t; +/* + * PCI-X Error Data Register + * + * This register contains the Data on the PCI-X bus when an error occurred. + */ + typedef union pic_p_pcix_err_data_u { + picreg_t pic_p_pcix_err_data_regval; + struct { + picreg_t pcix_err_data : 64; /* 63:0 */ + } pic_p_pcix_err_data_fld_s; + } pic_p_pcix_err_data_u_t; +/* + * PCI-X Read Request Timeout Error Register + * + * This register contains a pointer into the PCI-X read data structure. + */ + typedef union pic_p_pcix_read_req_to_u { + picreg_t pic_p_pcix_read_req_to_regval; + struct { + picreg_t : 55; /* 63:9 */ + picreg_t rd_buff_loc : 5; /* 8:4 */ + picreg_t rd_buff_struct : 4; /* 3:0 */ + } pic_p_pcix_read_req_to_fld_s; + } pic_p_pcix_read_req_to_u_t; +/* + * INT_STATUS Register + * + * This is the current interrupt status register which maintains the current + * status of all the interrupting devices which generated a n interrupt. This + * register is read only and all the bits are active high. A high bit at + * INT_STATE means the corresponding INT_N pin has been asserted + * (low). + */ + typedef union pic_p_int_status_u { + picreg_t pic_p_int_status_regval; + struct { + picreg_t : 22; /* 63:42 */ + picreg_t int_ram_perr : 1; /* 41:41 */ + picreg_t bus_arb_broke : 1; /* 40:40 */ + picreg_t pci_x_req_tout : 1; /* 39:39 */ + picreg_t pci_x_tabort : 1; /* 38:38 */ + picreg_t pci_x_perr : 1; /* 37:37 */ + picreg_t pci_x_serr : 1; /* 36:36 */ + picreg_t pci_x_mretry : 1; /* 35:35 */ + picreg_t pci_x_mtout : 1; /* 34:34 */ + picreg_t pci_x_da_parity : 1; /* 33:33 */ + picreg_t pci_x_ad_parity : 1; /* 32:32 */ + picreg_t : 1; /* 31:31 */ + picreg_t pmu_page_fault : 1; /* 30:30 */ + picreg_t unexpected_resp : 1; /* 29:29 */ + picreg_t bad_xresp_packet : 1; /* 28:28 */ + picreg_t bad_xreq_packet : 1; /* 27:27 */ + picreg_t resp_xtalk_error : 1; /* 26:26 */ + picreg_t req_xtalk_error : 1; /* 25:25 */ + picreg_t invalid_access : 1; /* 24:24 */ + picreg_t unsupported_xop : 1; /* 23:23 */ + picreg_t xreq_fifo_oflow : 1; /* 22:22 */ + picreg_t llp_rec_snerror : 1; /* 21:21 */ + picreg_t llp_rec_cberror : 1; /* 20:20 */ + picreg_t llp_rcty : 1; /* 19:19 */ + picreg_t llp_tx_retry : 1; /* 18:18 */ + picreg_t llp_tcty : 1; /* 17:17 */ + picreg_t : 1; /* 16:16 */ + picreg_t pci_abort : 1; /* 15:15 */ + picreg_t pci_parity : 1; /* 14:14 */ + picreg_t pci_serr : 1; /* 13:13 */ + picreg_t pci_perr : 1; /* 12:12 */ + picreg_t pci_master_tout : 1; /* 11:11 */ + picreg_t pci_retry_cnt : 1; /* 10:10 */ + picreg_t xread_req_tout : 1; /* 9:9 */ + picreg_t : 1; /* 8:8 */ + picreg_t int_state : 8; /* 7:0 */ + } pic_p_int_status_fld_s; + } pic_p_int_status_u_t; +/* + * Interrupt Enable Register + * + * This register enables the reporting of interrupt to the host. Each bit in this + * register corresponds to the same bit in Interrupt Status register. All bits + * are zero after reset. + */ + typedef union pic_p_int_enable_u { + picreg_t pic_p_int_enable_regval; + struct { + picreg_t : 22; /* 63:42 */ + picreg_t en_int_ram_perr : 1; /* 41:41 */ + picreg_t en_bus_arb_broke : 1; /* 40:40 */ + picreg_t en_pci_x_req_tout : 1; /* 39:39 */ + picreg_t en_pci_x_tabort : 1; /* 38:38 */ + picreg_t en_pci_x_perr : 1; /* 37:37 */ + picreg_t en_pci_x_serr : 1; /* 36:36 */ + picreg_t en_pci_x_mretry : 1; /* 35:35 */ + picreg_t en_pci_x_mtout : 1; /* 34:34 */ + picreg_t en_pci_x_da_parity : 1; /* 33:33 */ + picreg_t en_pci_x_ad_parity : 1; /* 32:32 */ + picreg_t : 1; /* 31:31 */ + picreg_t en_pmu_page_fault : 1; /* 30:30 */ + picreg_t en_unexpected_resp : 1; /* 29:29 */ + picreg_t en_bad_xresp_packet : 1; /* 28:28 */ + picreg_t en_bad_xreq_packet : 1; /* 27:27 */ + picreg_t en_resp_xtalk_error : 1; /* 26:26 */ + picreg_t en_req_xtalk_error : 1; /* 25:25 */ + picreg_t en_invalid_access : 1; /* 24:24 */ + picreg_t en_unsupported_xop : 1; /* 23:23 */ + picreg_t en_xreq_fifo_oflow : 1; /* 22:22 */ + picreg_t en_llp_rec_snerror : 1; /* 21:21 */ + picreg_t en_llp_rec_cberror : 1; /* 20:20 */ + picreg_t en_llp_rcty : 1; /* 19:19 */ + picreg_t en_llp_tx_retry : 1; /* 18:18 */ + picreg_t en_llp_tcty : 1; /* 17:17 */ + picreg_t : 1; /* 16:16 */ + picreg_t en_pci_abort : 1; /* 15:15 */ + picreg_t en_pci_parity : 1; /* 14:14 */ + picreg_t en_pci_serr : 1; /* 13:13 */ + picreg_t en_pci_perr : 1; /* 12:12 */ + picreg_t en_pci_master_tout : 1; /* 11:11 */ + picreg_t en_pci_retry_cnt : 1; /* 10:10 */ + picreg_t en_xread_req_tout : 1; /* 9:9 */ + picreg_t : 1; /* 8:8 */ + picreg_t en_int_state : 8; /* 7:0 */ + } pic_p_int_enable_fld_s; + } pic_p_int_enable_u_t; +/* + * Reset Interrupt Register + * + * A write of a "1" clears the bit and rearms the error registers. Writes also + * clear the error view register. + */ + typedef union pic_p_int_rst_u { + picreg_t pic_p_int_rst_regval; + struct { + picreg_t : 22; /* 63:42 */ + picreg_t logv_int_ram_perr : 1; /* 41:41 */ + picreg_t logv_bus_arb_broke : 1; /* 40:40 */ + picreg_t logv_pci_x_req_tout : 1; /* 39:39 */ + picreg_t logv_pci_x_tabort : 1; /* 38:38 */ + picreg_t logv_pci_x_perr : 1; /* 37:37 */ + picreg_t logv_pci_x_serr : 1; /* 36:36 */ + picreg_t logv_pci_x_mretry : 1; /* 35:35 */ + picreg_t logv_pci_x_mtout : 1; /* 34:34 */ + picreg_t logv_pci_x_da_parity : 1; /* 33:33 */ + picreg_t logv_pci_x_ad_parity : 1; /* 32:32 */ + picreg_t : 1; /* 31:31 */ + picreg_t logv_pmu_page_fault : 1; /* 30:30 */ + picreg_t logv_unexpected_resp : 1; /* 29:29 */ + picreg_t logv_bad_xresp_packet : 1; /* 28:28 */ + picreg_t logv_bad_xreq_packet : 1; /* 27:27 */ + picreg_t logv_resp_xtalk_error : 1; /* 26:26 */ + picreg_t logv_req_xtalk_error : 1; /* 25:25 */ + picreg_t logv_invalid_access : 1; /* 24:24 */ + picreg_t logv_unsupported_xop : 1; /* 23:23 */ + picreg_t logv_xreq_fifo_oflow : 1; /* 22:22 */ + picreg_t logv_llp_rec_snerror : 1; /* 21:21 */ + picreg_t logv_llp_rec_cberror : 1; /* 20:20 */ + picreg_t logv_llp_rcty : 1; /* 19:19 */ + picreg_t logv_llp_tx_retry : 1; /* 18:18 */ + picreg_t logv_llp_tcty : 1; /* 17:17 */ + picreg_t : 1; /* 16:16 */ + picreg_t logv_pci_abort : 1; /* 15:15 */ + picreg_t logv_pci_parity : 1; /* 14:14 */ + picreg_t logv_pci_serr : 1; /* 13:13 */ + picreg_t logv_pci_perr : 1; /* 12:12 */ + picreg_t logv_pci_master_tout : 1; /* 11:11 */ + picreg_t logv_pci_retry_cnt : 1; /* 10:10 */ + picreg_t logv_xread_req_tout : 1; /* 9:9 */ + picreg_t : 2; /* 8:7 */ + picreg_t multi_clr : 1; /* 6:6 */ + picreg_t : 6; /* 5:0 */ + } pic_p_int_rst_fld_s; + } pic_p_int_rst_u_t; + +/* + * Interrupt Mode Register + * + * This register defines the interrupting mode of the INT_N pins. + */ + typedef union pic_p_int_mode_u { + picreg_t pic_p_int_mode_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 24; /* 31:8 */ + picreg_t en_clr_pkt : 8; /* 7:0 */ + } pic_p_int_mode_fld_s; + } pic_p_int_mode_u_t; +/* + * Interrupt Device Select Register + * + * This register associates interrupt pins with devices thus allowing buffer + * management (flushing) when a device interrupt occurs. + */ + typedef union pic_p_int_device_u { + picreg_t pic_p_int_device_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 8; /* 31:24 */ + picreg_t int7_dev : 3; /* 23:21 */ + picreg_t int6_dev : 3; /* 20:18 */ + picreg_t int5_dev : 3; /* 17:15 */ + picreg_t int4_dev : 3; /* 14:12 */ + picreg_t int3_dev : 3; /* 11:9 */ + picreg_t int2_dev : 3; /* 8:6 */ + picreg_t int1_dev : 3; /* 5:3 */ + picreg_t int0_dev : 3; /* 2:0 */ + } pic_p_int_device_fld_s; + } pic_p_int_device_u_t; +/* + * Host Error Interrupt Field Register + * + * This register tells which bit location in the host's Interrupt Status register + * to set or reset when any error condition happens. + */ + typedef union pic_p_int_host_err_u { + picreg_t pic_p_int_host_err_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 24; /* 31:8 */ + picreg_t bridge_err_fld : 8; /* 7:0 */ + } pic_p_int_host_err_fld_s; + } pic_p_int_host_err_u_t; +/* + * Interrupt (x) Host Address Register + * + * This register allow different host address to be assigned to each interrupt + * pin and the bit in the host. + */ + typedef union pic_p_int_addr_u { + picreg_t pic_p_int_addr_regval; + struct { + picreg_t : 8; /* 63:56 */ + picreg_t int_fld : 8; /* 55:48 */ + picreg_t int_addr : 48; /* 47:0 */ + } pic_p_int_addr_fld_s; + } pic_p_int_addr_u_t; +/* + * Error Interrupt View Register + * + * This register contains the view of which interrupt occur even if they are + * not currently enabled. The group clear is used to clear these bits just like + * the interrupt status register bits. + */ + typedef union pic_p_err_int_view_u { + picreg_t pic_p_err_int_view_regval; + struct { + picreg_t : 22; /* 63:42 */ + picreg_t int_ram_perr : 1; /* 41:41 */ + picreg_t bus_arb_broke : 1; /* 40:40 */ + picreg_t pci_x_req_tout : 1; /* 39:39 */ + picreg_t pci_x_tabort : 1; /* 38:38 */ + picreg_t pci_x_perr : 1; /* 37:37 */ + picreg_t pci_x_serr : 1; /* 36:36 */ + picreg_t pci_x_mretry : 1; /* 35:35 */ + picreg_t pci_x_mtout : 1; /* 34:34 */ + picreg_t pci_x_da_parity : 1; /* 33:33 */ + picreg_t pci_x_ad_parity : 1; /* 32:32 */ + picreg_t : 1; /* 31:31 */ + picreg_t pmu_page_fault : 1; /* 30:30 */ + picreg_t unexpected_resp : 1; /* 29:29 */ + picreg_t bad_xresp_packet : 1; /* 28:28 */ + picreg_t bad_xreq_packet : 1; /* 27:27 */ + picreg_t resp_xtalk_error : 1; /* 26:26 */ + picreg_t req_xtalk_error : 1; /* 25:25 */ + picreg_t invalid_access : 1; /* 24:24 */ + picreg_t unsupported_xop : 1; /* 23:23 */ + picreg_t xreq_fifo_oflow : 1; /* 22:22 */ + picreg_t llp_rec_snerror : 1; /* 21:21 */ + picreg_t llp_rec_cberror : 1; /* 20:20 */ + picreg_t llp_rcty : 1; /* 19:19 */ + picreg_t llp_tx_retry : 1; /* 18:18 */ + picreg_t llp_tcty : 1; /* 17:17 */ + picreg_t : 1; /* 16:16 */ + picreg_t pci_abort : 1; /* 15:15 */ + picreg_t pci_parity : 1; /* 14:14 */ + picreg_t pci_serr : 1; /* 13:13 */ + picreg_t pci_perr : 1; /* 12:12 */ + picreg_t pci_master_tout : 1; /* 11:11 */ + picreg_t pci_retry_cnt : 1; /* 10:10 */ + picreg_t xread_req_tout : 1; /* 9:9 */ + picreg_t : 9; /* 8:0 */ + } pic_p_err_int_view_fld_s; + } pic_p_err_int_view_u_t; + + +/* + * Multiple Interrupt Register + * + * This register indicates if any interrupt occurs more than once without be- + * ing cleared. + */ + typedef union pic_p_mult_int_u { + picreg_t pic_p_mult_int_regval; + struct { + picreg_t : 22; /* 63:42 */ + picreg_t int_ram_perr : 1; /* 41:41 */ + picreg_t bus_arb_broke : 1; /* 40:40 */ + picreg_t pci_x_req_tout : 1; /* 39:39 */ + picreg_t pci_x_tabort : 1; /* 38:38 */ + picreg_t pci_x_perr : 1; /* 37:37 */ + picreg_t pci_x_serr : 1; /* 36:36 */ + picreg_t pci_x_mretry : 1; /* 35:35 */ + picreg_t pci_x_mtout : 1; /* 34:34 */ + picreg_t pci_x_da_parity : 1; /* 33:33 */ + picreg_t pci_x_ad_parity : 1; /* 32:32 */ + picreg_t : 1; /* 31:31 */ + picreg_t pmu_page_fault : 1; /* 30:30 */ + picreg_t unexpected_resp : 1; /* 29:29 */ + picreg_t bad_xresp_packet : 1; /* 28:28 */ + picreg_t bad_xreq_packet : 1; /* 27:27 */ + picreg_t resp_xtalk_error : 1; /* 26:26 */ + picreg_t req_xtalk_error : 1; /* 25:25 */ + picreg_t invalid_access : 1; /* 24:24 */ + picreg_t unsupported_xop : 1; /* 23:23 */ + picreg_t xreq_fifo_oflow : 1; /* 22:22 */ + picreg_t llp_rec_snerror : 1; /* 21:21 */ + picreg_t llp_rec_cberror : 1; /* 20:20 */ + picreg_t llp_rcty : 1; /* 19:19 */ + picreg_t llp_tx_retry : 1; /* 18:18 */ + picreg_t llp_tcty : 1; /* 17:17 */ + picreg_t : 1; /* 16:16 */ + picreg_t pci_abort : 1; /* 15:15 */ + picreg_t pci_parity : 1; /* 14:14 */ + picreg_t pci_serr : 1; /* 13:13 */ + picreg_t pci_perr : 1; /* 12:12 */ + picreg_t pci_master_tout : 1; /* 11:11 */ + picreg_t pci_retry_cnt : 1; /* 10:10 */ + picreg_t xread_req_tout : 1; /* 9:9 */ + picreg_t : 1; /* 8:8 */ + picreg_t int_state : 8; /* 7:0 */ + } pic_p_mult_int_fld_s; + } pic_p_mult_int_u_t; +/* + * Force Always Interrupt (x) Register + * + * A write to this data independent write only register will force a set inter- + * rupt to occur as if the interrupt line had transitioned. If the interrupt line + * is already active an addition set interrupt packet is set. All buffer flush op- + * erations also occur on this operation. + */ + + +/* + * Force Interrupt (x) Register + * + * A write to this data independent write only register in conjunction with + * the assertion of the corresponding interrupt line will force a set interrupt + * to occur as if the interrupt line had transitioned. The interrupt line must + * be active for this operation to generate a set packet, otherwise the write + * PIO is ignored. All buffer flush operations also occur when the set packet + * is sent on this operation. + */ + + +/* + * Device Registers + * + * The Device registers contain device specific and mapping information. + */ + typedef union pic_device_reg_u { + picreg_t pic_device_reg_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 2; /* 31:30 */ + picreg_t en_virtual1 : 1; /* 29:29 */ + picreg_t en_error_lock : 1; /* 28:28 */ + picreg_t en_page_chk : 1; /* 27:27 */ + picreg_t force_pci_par : 1; /* 26:26 */ + picreg_t en_virtual0 : 1; /* 25:25 */ + picreg_t : 1; /* 24:24 */ + picreg_t dir_wrt_gen : 1; /* 23:23 */ + picreg_t dev_size : 1; /* 22:22 */ + picreg_t real_time : 1; /* 21:21 */ + picreg_t : 1; /* 20:20 */ + picreg_t swap_direct : 1; /* 19:19 */ + picreg_t prefetch : 1; /* 18:18 */ + picreg_t precise : 1; /* 17:17 */ + picreg_t coherent : 1; /* 16:16 */ + picreg_t barrier : 1; /* 15:15 */ + picreg_t gbr : 1; /* 14:14 */ + picreg_t dev_swap : 1; /* 13:13 */ + picreg_t dev_io_mem : 1; /* 12:12 */ + picreg_t dev_off : 12; /* 11:0 */ + } pic_device_reg_fld_s; + } pic_device_reg_u_t; +/* + * Device (x) Write Request Buffer Flush + * + * When read, this register will return a 0x00 after the write buffer associat- + * ed with the device has been flushed. (PCI Only) + */ + + +/* + * Even Device Read Response Buffer Register (PCI Only) + * + * This register is use to allocate the read response buffers for the even num- + * bered devices. (0,2) + */ + typedef union pic_p_even_resp_u { + picreg_t pic_p_even_resp_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t buff_14_en : 1; /* 31:31 */ + picreg_t buff_14_vdev : 2; /* 30:29 */ + picreg_t buff_14_pdev : 1; /* 28:28 */ + picreg_t buff_12_en : 1; /* 27:27 */ + picreg_t buff_12_vdev : 2; /* 26:25 */ + picreg_t buff_12_pdev : 1; /* 24:24 */ + picreg_t buff_10_en : 1; /* 23:23 */ + picreg_t buff_10_vdev : 2; /* 22:21 */ + picreg_t buff_10_pdev : 1; /* 20:20 */ + picreg_t buff_8_en : 1; /* 19:19 */ + picreg_t buff_8_vdev : 2; /* 18:17 */ + picreg_t buff_8_pdev : 1; /* 16:16 */ + picreg_t buff_6_en : 1; /* 15:15 */ + picreg_t buff_6_vdev : 2; /* 14:13 */ + picreg_t buff_6_pdev : 1; /* 12:12 */ + picreg_t buff_4_en : 1; /* 11:11 */ + picreg_t buff_4_vdev : 2; /* 10:9 */ + picreg_t buff_4_pdev : 1; /* 8:8 */ + picreg_t buff_2_en : 1; /* 7:7 */ + picreg_t buff_2_vdev : 2; /* 6:5 */ + picreg_t buff_2_pdev : 1; /* 4:4 */ + picreg_t buff_0_en : 1; /* 3:3 */ + picreg_t buff_0_vdev : 2; /* 2:1 */ + picreg_t buff_0_pdev : 1; /* 0:0 */ + } pic_p_even_resp_fld_s; + } pic_p_even_resp_u_t; +/* + * Odd Device Read Response Buffer Register (PCI Only) + * + * This register is use to allocate the read response buffers for the odd num- + * bered devices. (1,3)) + */ + typedef union pic_p_odd_resp_u { + picreg_t pic_p_odd_resp_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t buff_15_en : 1; /* 31:31 */ + picreg_t buff_15_vdev : 2; /* 30:29 */ + picreg_t buff_15_pdev : 1; /* 28:28 */ + picreg_t buff_13_en : 1; /* 27:27 */ + picreg_t buff_13_vdev : 2; /* 26:25 */ + picreg_t buff_13_pdev : 1; /* 24:24 */ + picreg_t buff_11_en : 1; /* 23:23 */ + picreg_t buff_11_vdev : 2; /* 22:21 */ + picreg_t buff_11_pdev : 1; /* 20:20 */ + picreg_t buff_9_en : 1; /* 19:19 */ + picreg_t buff_9_vdev : 2; /* 18:17 */ + picreg_t buff_9_pdev : 1; /* 16:16 */ + picreg_t buff_7_en : 1; /* 15:15 */ + picreg_t buff_7_vdev : 2; /* 14:13 */ + picreg_t buff_7_pdev : 1; /* 12:12 */ + picreg_t buff_5_en : 1; /* 11:11 */ + picreg_t buff_5_vdev : 2; /* 10:9 */ + picreg_t buff_5_pdev : 1; /* 8:8 */ + picreg_t buff_3_en : 1; /* 7:7 */ + picreg_t buff_3_vdev : 2; /* 6:5 */ + picreg_t buff_3_pdev : 1; /* 4:4 */ + picreg_t buff_1_en : 1; /* 3:3 */ + picreg_t buff_1_vdev : 2; /* 2:1 */ + picreg_t buff_1_pdev : 1; /* 0:0 */ + } pic_p_odd_resp_fld_s; + } pic_p_odd_resp_u_t; +/* + * Read Response Buffer Status Register (PCI Only) + * + * This read only register contains the current response buffer status. + */ + typedef union pic_p_resp_status_u { + picreg_t pic_p_resp_status_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t rrb_valid : 16; /* 31:16 */ + picreg_t rrb_inuse : 16; /* 15:0 */ + } pic_p_resp_status_fld_s; + } pic_p_resp_status_u_t; +/* + * Read Response Buffer Clear Register (PCI Only) + * + * A write to this register clears the current contents of the buffer. + */ + typedef union pic_p_resp_clear_u { + picreg_t pic_p_resp_clear_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t rrb_clear : 16; /* 15:0 */ + } pic_p_resp_clear_fld_s; + } pic_p_resp_clear_u_t; +/* + * PCI Read Response Buffer (x) Upper Address Match + * + * The PCI Bridge read response buffer upper address register is a read only + * register which contains the upper 16-bits of the address and status used to + * select the buffer for a PCI transaction. + */ + typedef union pic_p_buf_upper_addr_match_u { + picreg_t pic_p_buf_upper_addr_match_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t filled : 1; /* 31:31 */ + picreg_t armed : 1; /* 30:30 */ + picreg_t flush : 1; /* 29:29 */ + picreg_t xerr : 1; /* 28:28 */ + picreg_t pkterr : 1; /* 27:27 */ + picreg_t timeout : 1; /* 26:26 */ + picreg_t prefetch : 1; /* 25:25 */ + picreg_t precise : 1; /* 24:24 */ + picreg_t dw_be : 8; /* 23:16 */ + picreg_t upp_addr : 16; /* 15:0 */ + } pic_p_buf_upper_addr_match_fld_s; + } pic_p_buf_upper_addr_match_u_t; +/* + * PCI Read Response Buffer (x) Lower Address Match + * + * The PCI Bridge read response buffer lower address Match register is a + * read only register which contains the address and status used to select the + * buffer for a PCI transaction. + */ + typedef union pic_p_buf_lower_addr_match_u { + picreg_t pic_p_buf_lower_addr_match_regval; + struct { + picreg_t filled : 1; /* 63:63 */ + picreg_t armed : 1; /* 62:62 */ + picreg_t flush : 1; /* 61:61 */ + picreg_t xerr : 1; /* 60:60 */ + picreg_t pkterr : 1; /* 59:59 */ + picreg_t timeout : 1; /* 58:58 */ + picreg_t prefetch : 1; /* 57:57 */ + picreg_t precise : 1; /* 56:56 */ + picreg_t dw_be : 8; /* 55:48 */ + picreg_t upp_addr : 16; /* 47:32 */ + picreg_t low_addr : 32; /* 31:0 */ + } pic_p_buf_lower_addr_match_fld_s; + } pic_p_buf_lower_addr_match_u_t; +/* + * PCI Buffer (x) Flush Count with Data Touch Register + * + * This counter is incremented each time the corresponding response buffer + * is flushed after at least a single data element in the buffer is used. A word + * write to this address clears the count. + */ + typedef union pic_flush_w_touch_u { + picreg_t pic_flush_w_touch_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t touch_cnt : 16; /* 15:0 */ + } pic_flush_w_touch_fld_s; + } pic_flush_w_touch_u_t; +/* + * PCI Buffer (x) Flush Count w/o Data Touch Register + * + * This counter is incremented each time the corresponding response buffer + * is flushed without any data element in the buffer being used. A word + * write to this address clears the count. + */ + typedef union pic_flush_wo_touch_u { + picreg_t pic_flush_wo_touch_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t notouch_cnt : 16; /* 15:0 */ + } pic_flush_wo_touch_fld_s; + } pic_flush_wo_touch_u_t; +/* + * PCI Buffer (x) Request in Flight Count Register + * + * This counter is incremented on each bus clock while the request is in- + * flight. A word write to this address clears the count. ] + */ + typedef union pic_inflight_u { + picreg_t pic_inflight_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t inflight_cnt : 16; /* 15:0 */ + } pic_inflight_fld_s; + } pic_inflight_u_t; +/* + * PCI Buffer (x) Prefetch Request Count Register + * + * This counter is incremented each time the request using this buffer was + * generated from the prefetcher. A word write to this address clears the + * count. + */ + typedef union pic_prefetch_u { + picreg_t pic_prefetch_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t prefetch_cnt : 16; /* 15:0 */ + } pic_prefetch_fld_s; + } pic_prefetch_u_t; +/* + * PCI Buffer (x) Total PCI Retry Count Register + * + * This counter is incremented each time a PCI bus retry occurs and the ad- + * dress matches the tag for the selected buffer. The buffer must also has this + * request in-flight. A word write to this address clears the count. + */ + typedef union pic_total_pci_retry_u { + picreg_t pic_total_pci_retry_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t retry_cnt : 16; /* 15:0 */ + } pic_total_pci_retry_fld_s; + } pic_total_pci_retry_u_t; +/* + * PCI Buffer (x) Max PCI Retry Count Register + * + * This counter is contains the maximum retry count for a single request + * which was in-flight for this buffer. A word write to this address clears the + * count. + */ + typedef union pic_max_pci_retry_u { + picreg_t pic_max_pci_retry_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t max_retry_cnt : 16; /* 15:0 */ + } pic_max_pci_retry_fld_s; + } pic_max_pci_retry_u_t; +/* + * PCI Buffer (x) Max Latency Count Register + * + * This counter is contains the maximum count (in bus clocks) for a single + * request which was in-flight for this buffer. A word write to this address + * clears the count. + */ + typedef union pic_max_latency_u { + picreg_t pic_max_latency_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t : 16; /* 31:16 */ + picreg_t max_latency_cnt : 16; /* 15:0 */ + } pic_max_latency_fld_s; + } pic_max_latency_u_t; +/* + * PCI Buffer (x) Clear All Register + * + * Any access to this register clears all the count values for the (x) registers. + */ + + +/* + * PCI-X Registers + * + * This register contains the address in the read buffer structure. There are + * 16 read buffer structures. + */ + typedef union pic_rd_buf_addr_u { + picreg_t pic_rd_buf_addr_regval; + struct { + picreg_t pcix_err_addr : 64; /* 63:0 */ + } pic_rd_buf_addr_fld_s; + } pic_rd_buf_addr_u_t; +/* + * PCI-X Read Buffer (x) Attribute Register + * + * This register contains the attribute data in the read buffer structure. There + * are 16 read buffer structures. + */ + typedef union pic_px_read_buf_attr_u { + picreg_t pic_px_read_buf_attr_regval; + struct { + picreg_t : 16; /* 63:48 */ + picreg_t bus_cmd : 4; /* 47:44 */ + picreg_t byte_cnt : 12; /* 43:32 */ + picreg_t entry_valid : 1; /* 31:31 */ + picreg_t ns : 1; /* 30:30 */ + picreg_t ro : 1; /* 29:29 */ + picreg_t tag : 5; /* 28:24 */ + picreg_t bus_num : 8; /* 23:16 */ + picreg_t dev_num : 5; /* 15:11 */ + picreg_t fun_num : 3; /* 10:8 */ + picreg_t : 2; /* 7:6 */ + picreg_t f_buffer_index : 6; /* 5:0 */ + } pic_px_read_buf_attr_fld_s; + } pic_px_read_buf_attr_u_t; +/* + * PCI-X Write Buffer (x) Address Register + * + * This register contains the address in the write buffer structure. There are + * 8 write buffer structures. + */ + typedef union pic_px_write_buf_addr_u { + picreg_t pic_px_write_buf_addr_regval; + struct { + picreg_t pcix_err_addr : 64; /* 63:0 */ + } pic_px_write_buf_addr_fld_s; + } pic_px_write_buf_addr_u_t; +/* + * PCI-X Write Buffer (x) Attribute Register + * + * This register contains the attribute data in the write buffer structure. + * There are 8 write buffer structures. + */ + typedef union pic_px_write_buf_attr_u { + picreg_t pic_px_write_buf_attr_regval; + struct { + picreg_t : 16; /* 63:48 */ + picreg_t bus_cmd : 4; /* 47:44 */ + picreg_t byte_cnt : 12; /* 43:32 */ + picreg_t entry_valid : 1; /* 31:31 */ + picreg_t ns : 1; /* 30:30 */ + picreg_t ro : 1; /* 29:29 */ + picreg_t tag : 5; /* 28:24 */ + picreg_t bus_num : 8; /* 23:16 */ + picreg_t dev_num : 5; /* 15:11 */ + picreg_t fun_num : 3; /* 10:8 */ + picreg_t : 2; /* 7:6 */ + picreg_t f_buffer_index : 6; /* 5:0 */ + } pic_px_write_buf_attr_fld_s; + } pic_px_write_buf_attr_u_t; +/* + * PCI-X Write Buffer (x) Valid Register + * + * This register contains the valid or inuse cache lines for this buffer struc- + * ture. + */ + typedef union pic_px_write_buf_valid_u { + picreg_t pic_px_write_buf_valid_regval; + struct { + picreg_t : 32; /* 63:32 */ + picreg_t wrt_valid_buff : 32; /* 31:0 */ + } pic_px_write_buf_valid_fld_s; + } pic_px_write_buf_valid_u_t; + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_SN_PCI_PIC_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/pda.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pda.h --- linux-2.4.19/include/asm-ia64/sn/pda.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pda.h Thu Feb 13 10:59:52 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PDA_H #define _ASM_IA64_SN_PDA_H @@ -25,7 +25,14 @@ * all SN per-cpu data structures. */ - +#ifdef BUS_INT_WAR +#define POLL_ENTRIES 50 +typedef struct { + int irq; + int interval; + short tick; +} sn_poll_entry_t; +#endif typedef struct pda_s { @@ -56,8 +63,17 @@ #endif volatile unsigned long *bedrock_rev_id; volatile unsigned long *pio_write_status_addr; + volatile unsigned long *pio_shub_war_cam_addr; + volatile unsigned long *mem_write_status_addr; + + bteinfo_t *cpu_bte_if[BTES_PER_NODE]; /* cpu interface order */ - bteinfo_t *cpubte[BTES_PER_NODE]; +#ifdef BUS_INT_WAR + sn_poll_entry_t pda_poll_entries[POLL_ENTRIES]; + int pda_poll_entry_count; +#endif + unsigned long sn_soft_irr[4]; + short cnodeid_to_nasid_table[PLAT_MAX_COMPACT_NODES]; } pda_t; @@ -79,6 +95,8 @@ #define PDAADDR (PERCPU_ADDR+CPU_DATA_END) #define pda (*((pda_t *) PDAADDR)) + +#define pdacpu(cpu) (*((pda_t *) ((long)cpu_data(cpu) + CPU_DATA_END))) #endif /* _ASM_IA64_SN_PDA_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/pio.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/pio.h --- linux-2.4.19/include/asm-ia64/sn/pio.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/pio.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PIO_H #define _ASM_IA64_SN_PIO_H diff -Nur linux-2.4.19/include/asm-ia64/sn/prio.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/prio.h --- linux-2.4.19/include/asm-ia64/sn/prio.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/prio.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PRIO_H #define _ASM_IA64_SN_PRIO_H diff -Nur linux-2.4.19/include/asm-ia64/sn/router.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/router.h --- linux-2.4.19/include/asm-ia64/sn/router.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/router.h Mon Dec 30 14:16:56 2002 @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_ROUTER_H diff -Nur linux-2.4.19/include/asm-ia64/sn/rw_mmr.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/rw_mmr.h --- linux-2.4.19/include/asm-ia64/sn/rw_mmr.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/rw_mmr.h Mon Dec 30 14:16:56 2002 @@ -0,0 +1,73 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + */ +#ifndef _ASM_IA64_SN_RW_MMR_H +#define _ASM_IA64_SN_RW_MMR_H + + +/* + * This file contains macros used to access MMR registers via + * uncached physical addresses. + * pio_phys_read_mmr - read an MMR + * pio_phys_write_mmr - write an MMR + * pio_atomic_phys_write_mmrs - atomically write 2 MMRs with psr.ic=0 + * (interrupt collection) + * + * Addresses passed to these routines should be uncached physical addresses + * ie., 0x80000.... + */ + + +extern inline long +pio_phys_read_mmr(volatile long *mmr) +{ + long val; + asm volatile + ("mov r2=psr;;" + "rsm psr.i | psr.dt;;" + "srlz.i;;" + "ld8.acq %0=[%1];;" + "mov psr.l=r2;;" + "srlz.i;;" + : "=r"(val) + : "r"(mmr) + : "r2"); + return val; +} + + + +extern inline void +pio_phys_write_mmr(volatile long *mmr, long val) +{ + asm volatile + ("mov r2=psr;;" + "rsm psr.i | psr.dt;;" + "srlz.i;;" + "st8.rel [%0]=%1;;" + "mov psr.l=r2;;" + "srlz.i;;" + :: "r"(mmr), "r"(val) + : "r2", "memory"); +} + +extern inline void +pio_atomic_phys_write_mmrs(volatile long *mmr1, long val1, volatile long *mmr2, long val2) +{ + asm volatile + ("mov r2=psr;;" + "rsm psr.i | psr.dt | psr.ic;;" + "srlz.i;;" + "st8.rel [%0]=%1;" + "st8.rel [%2]=%3;;" + "mov psr.l=r2;;" + "srlz.i;;" + :: "r"(mmr1), "r"(val1), "r"(mmr2), "r"(val2) + : "r2", "memory"); +} + +#endif /* _ASM_IA64_SN_RW_MMR_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sgi.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sgi.h --- linux-2.4.19/include/asm-ia64/sn/sgi.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sgi.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -18,82 +18,6 @@ #include #include -// This devfs stuff needs a better home ..... - -struct directory_type -{ - struct devfs_entry *first; - struct devfs_entry *last; - unsigned int num_removable; -}; - -struct file_type -{ - unsigned long size; -}; - -struct device_type -{ - unsigned short major; - unsigned short minor; -}; - -struct fcb_type /* File, char, block type */ -{ - uid_t default_uid; - gid_t default_gid; - void *ops; - union - { - struct file_type file; - struct device_type device; - } - u; - unsigned char auto_owner:1; - unsigned char aopen_notify:1; - unsigned char removable:1; /* Belongs in device_type, but save space */ - unsigned char open:1; /* Not entirely correct */ -}; - -struct symlink_type -{ - unsigned int length; /* Not including the NULL-termimator */ - char *linkname; /* This is NULL-terminated */ -}; - -struct fifo_type -{ - uid_t uid; - gid_t gid; -}; - -struct devfs_entry -{ - void *info; - union - { - struct directory_type dir; - struct fcb_type fcb; - struct symlink_type symlink; - struct fifo_type fifo; - } - u; - struct devfs_entry *prev; /* Previous entry in the parent directory */ - struct devfs_entry *next; /* Next entry in the parent directory */ - struct devfs_entry *parent; /* The parent directory */ - struct devfs_entry *slave; /* Another entry to unregister */ - struct devfs_inode *first_inode; - struct devfs_inode *last_inode; - umode_t mode; - unsigned short namelen; /* I think 64k+ filenames are a way off... */ - unsigned char registered:1; - unsigned char show_unreg:1; - unsigned char hide:1; - unsigned char no_persistence /*:1*/; - char name[1]; /* This is just a dummy: the allocated array is - bigger. This is NULL-terminated */ -}; - typedef int64_t __psint_t; /* needed by klgraph.c */ typedef enum { B_FALSE, B_TRUE } boolean_t; @@ -222,6 +146,31 @@ #else #define cpu_enabled(cpu) (1) #endif + +/* print_register() defs */ + +/* + * register values + * map between numeric values and symbolic values + */ +struct reg_values { + unsigned long long rv_value; + char *rv_name; +}; + +/* + * register descriptors are used for formatted prints of register values + * rd_mask and rd_shift must be defined, other entries may be null + */ +struct reg_desc { + unsigned long long rd_mask; /* mask to extract field */ + int rd_shift; /* shift for extracted value, - >>, + << */ + char *rd_name; /* field name */ + char *rd_format; /* format to print field */ + struct reg_values *rd_values; /* symbolic names of values */ +}; + +extern void print_register(unsigned long long, struct reg_desc *); #include /* for now */ diff -Nur linux-2.4.19/include/asm-ia64/sn/simulator.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/simulator.h --- linux-2.4.19/include/asm-ia64/sn/simulator.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/simulator.h Mon Dec 30 14:16:56 2002 @@ -5,7 +5,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/include/asm-ia64/sn/slotnum.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/slotnum.h --- linux-2.4.19/include/asm-ia64/sn/slotnum.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/slotnum.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SLOTNUM_H #define _ASM_IA64_SN_SLOTNUM_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/addrs.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/addrs.h --- linux-2.4.19/include/asm-ia64/sn/sn1/addrs.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/addrs.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_ADDRS_H @@ -41,7 +41,8 @@ * use some new ANSI preprocessor stuff to paste these on where needed. */ -#define CAC_BASE 0xe000000000000000 +#define CACHEABLE_MEM_SPACE 0xe000000000000000 +#define CAC_BASE CACHEABLE_MEM_SPACE #define HSPEC_BASE 0xc0000b0000000000 #define HSPEC_SWIZ_BASE 0xc000030000000000 #define IO_BASE 0xc0000a0000000000 diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/arch.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/arch.h --- linux-2.4.19/include/asm-ia64/sn/sn1/arch.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/arch.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_ARCH_H #define _ASM_IA64_SN_SN1_ARCH_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/bedrock.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/bedrock.h --- linux-2.4.19/include/asm-ia64/sn/sn1/bedrock.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/bedrock.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_BEDROCK_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubdev.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubdev.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubdev.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubdev.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBDEV_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubio.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubio.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubio.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubio.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ /************************************************************************ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubio_next.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubio_next.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubio_next.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubio_next.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBIO_NEXT_H #define _ASM_IA64_SN_SN1_HUBIO_NEXT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hublb.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hublb.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hublb.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hublb.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ /************************************************************************ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hublb_next.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hublb_next.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hublb_next.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hublb_next.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBLB_NEXT_H #define _ASM_IA64_SN_SN1_HUBLB_NEXT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubmd.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubmd.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubmd.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubmd.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBMD_H #define _ASM_IA64_SN_SN1_HUBMD_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubmd_next.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubmd_next.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubmd_next.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubmd_next.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBMD_NEXT_H #define _ASM_IA64_SN_SN1_HUBMD_NEXT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubni.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubni.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubni.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubni.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBNI_H #define _ASM_IA64_SN_SN1_HUBNI_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubni_next.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubni_next.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubni_next.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubni_next.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBNI_NEXT_H #define _ASM_IA64_SN_SN1_HUBNI_NEXT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubpi.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubpi.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubpi.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubpi.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBPI_H #define _ASM_IA64_SN_SN1_HUBPI_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubpi_next.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubpi_next.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubpi_next.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubpi_next.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBPI_NEXT_H #define _ASM_IA64_SN_SN1_HUBPI_NEXT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubspc.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubspc.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubspc.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubspc.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBSPC_H #define _ASM_IA64_SN_SN1_HUBSPC_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubstat.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubstat.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubstat.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubstat.h Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000 - 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBSTAT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubxb.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubxb.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubxb.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubxb.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBXB_H #define _ASM_IA64_SN_SN1_HUBXB_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hubxb_next.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubxb_next.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hubxb_next.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hubxb_next.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HUBXB_NEXT_H #define _ASM_IA64_SN_SN1_HUBXB_NEXT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/hwcntrs.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hwcntrs.h --- linux-2.4.19/include/asm-ia64/sn/sn1/hwcntrs.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/hwcntrs.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_HWCNTRS_H #define _ASM_IA64_SN_SN1_HWCNTRS_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/intr.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/intr.h --- linux-2.4.19/include/asm-ia64/sn/sn1/intr.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/intr.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_INTR_H #define _ASM_IA64_SN_SN1_INTR_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/intr_public.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/intr_public.h --- linux-2.4.19/include/asm-ia64/sn/sn1/intr_public.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/intr_public.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_INTR_PUBLIC_H #define _ASM_IA64_SN_SN1_INTR_PUBLIC_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/ip27config.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/ip27config.h --- linux-2.4.19/include/asm-ia64/sn/sn1/ip27config.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/ip27config.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_IP27CONFIG_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/mem_refcnt.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/mem_refcnt.h --- linux-2.4.19/include/asm-ia64/sn/sn1/mem_refcnt.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/mem_refcnt.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_MEM_REFCNT_H #define _ASM_IA64_SN_SN1_MEM_REFCNT_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/mmzone_sn1.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/mmzone_sn1.h --- linux-2.4.19/include/asm-ia64/sn/sn1/mmzone_sn1.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/mmzone_sn1.h Mon Dec 30 14:16:56 2002 @@ -6,7 +6,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/slotnum.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/slotnum.h --- linux-2.4.19/include/asm-ia64/sn/sn1/slotnum.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/slotnum.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_SLOTNUM_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/sn_private.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/sn_private.h --- linux-2.4.19/include/asm-ia64/sn/sn1/sn_private.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/sn_private.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN1_SN_PRIVATE_H #define _ASM_IA64_SN_SN1_SN_PRIVATE_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn1/synergy.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/synergy.h --- linux-2.4.19/include/asm-ia64/sn/sn1/synergy.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn1/synergy.h Mon Dec 30 14:16:56 2002 @@ -16,7 +16,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -53,9 +53,6 @@ #define GBL_PERF_B_ADDR (0x338 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) #define WRITE_LOCAL_SYNERGY_REG(addr, value) __synergy_out(addr, value) - -#define HUB_L(_a) *(_a) -#define HUB_S(_a, _d) *(_a) = (_d) #define HSPEC_SYNERGY0_0 0x04000000 /* Synergy0 Registers */ #define HSPEC_SYNERGY1_0 0x05000000 /* Synergy1 Registers */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/addrs.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/addrs.h --- linux-2.4.19/include/asm-ia64/sn/sn2/addrs.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/addrs.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_ADDRS_H @@ -53,19 +53,26 @@ /* Regions determined by AS */ #define LOCAL_MMR_SPACE 0xc000008000000000 /* Local MMR space */ +#define LOCAL_PHYS_MMR_SPACE 0x8000008000000000 /* Local PhysicalMMR space */ #define LOCAL_MEM_SPACE 0xc000010000000000 /* Local Memory space */ #define GLOBAL_MMR_SPACE 0xc000000800000000 /* Global MMR space */ +#define GLOBAL_PHYS_MMR_SPACE 0x0000000800000000 /* Global Physical MMR space */ #define GET_SPACE 0xc000001000000000 /* GET space */ #define AMO_SPACE 0xc000002000000000 /* AMO space */ #define CACHEABLE_MEM_SPACE 0xe000003000000000 /* Cacheable memory space */ #define UNCACHED 0xc000000000000000 /* UnCacheable memory space */ +#define UNCACHED_PHYS 0x8000000000000000 /* UnCacheable physical memory space */ + +#define PHYS_MEM_SPACE 0x0000003000000000 /* physical memory space */ /* SN2 address macros */ #define NID_SHFT 38 #define LOCAL_MMR_ADDR(a) (UNCACHED | LOCAL_MMR_SPACE | (a)) +#define LOCAL_MMR_PHYS_ADDR(a) (UNCACHED_PHYS | LOCAL_PHYS_MMR_SPACE | (a)) #define LOCAL_MEM_ADDR(a) (LOCAL_MEM_SPACE | (a)) #define REMOTE_ADDR(n,a) ((((unsigned long)(n))<> \ NASID_SHFT) & NASID_BITMASK) -#ifdef __IA64 #define PHYS_TO_DMA(x) ( ((x & NASID_MASK) >> 2) | \ (x & (NODE_ADDRSPACE_SIZE - 1)) ) -#else -#define PHYS_TO_DMA(x) ( (x) ) -#endif #define CHANGE_NASID(n,x) ({ia64_sn2_pa_t _v; _v.l = (long) (x); _v.f.nasid = n; _v.p;}) + +/* + * Determine if a physical address should be referenced as cached or uncached. + * For now, assume all memory is cached and everything else is noncached. + * (Later, we may need to special case areas of memory to be reference uncached). + */ +#define IS_CACHED_ADDRESS(x) (((x) & PHYS_MEM_SPACE) == PHYS_MEM_SPACE) + #ifndef __ASSEMBLY__ #define NODE_SWIN_BASE(nasid, widget) \ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/arch.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/arch.h --- linux-2.4.19/include/asm-ia64/sn/sn2/arch.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/arch.h Tue Jan 14 10:12:15 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_ARCH_H #define _ASM_IA64_SN_SN2_ARCH_H @@ -46,6 +46,7 @@ #define NASID_MASK_BYTES ((MAX_NASIDS + 7) / 8) +#define CNASID_MASK_BYTES (NASID_MASK_BYTES / 2) /* @@ -60,7 +61,5 @@ #define LOCALCPU(slice) (((slice) & LOCALCPU_MASK) >> LOCALCPU_SHFT) #define TO_SLICE(subn, local) (((subn) << SUBNODE_SHFT) | \ ((local) << LOCALCPU_SHFT)) - -typedef u64 mmr_t; #endif /* _ASM_IA64_SN_SN2_ARCH_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/geo.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/geo.h --- linux-2.4.19/include/asm-ia64/sn/sn2/geo.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/geo.h Mon Dec 30 14:16:56 2002 @@ -0,0 +1,109 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef __SYS_SN_SN2_GEO_H__ +#define __SYS_SN_SN2_GEO_H__ + +/* Headers required by declarations in this file */ + +#include + + +/* The geoid_t implementation below is based loosely on the pcfg_t + implementation in sys/SN/promcfg.h. */ + +/* Type declaractions */ + +/* Size of a geoid_t structure (must be before decl. of geoid_u) */ +#define GEOID_SIZE 8 /* Would 16 be better? The size can + be different on different platforms. */ + +#define MAX_SLABS 0xe /* slabs per module */ + +typedef unsigned char geo_type_t; + +/* Fields common to all substructures */ +typedef struct geo_any_s { + moduleid_t module; /* The module (box) this h/w lives in */ + geo_type_t type; /* What type of h/w is named by this geoid_t */ + slabid_t slab; /* The logical assembly within the module */ +} geo_any_t; + +/* Additional fields for particular types of hardware */ +typedef struct geo_node_s { + geo_any_t any; /* No additional fields needed */ +} geo_node_t; + +typedef struct geo_rtr_s { + geo_any_t any; /* No additional fields needed */ +} geo_rtr_t; + +typedef struct geo_iocntl_s { + geo_any_t any; /* No additional fields needed */ +} geo_iocntl_t; + +typedef struct geo_pcicard_s { + geo_iocntl_t any; + char bus; /* Bus/widget number */ + slotid_t slot; /* PCI slot number */ +} geo_pcicard_t; + +/* Subcomponents of a node */ +typedef struct geo_cpu_s { + geo_node_t node; + char slice; /* Which CPU on the node */ +} geo_cpu_t; + +typedef struct geo_mem_s { + geo_node_t node; + char membus; /* The memory bus on the node */ + char memslot; /* The memory slot on the bus */ +} geo_mem_t; + + +typedef union geoid_u { + geo_any_t any; + geo_node_t node; + geo_iocntl_t iocntl; + geo_pcicard_t pcicard; + geo_rtr_t rtr; + geo_cpu_t cpu; + geo_mem_t mem; + char padsize[GEOID_SIZE]; +} geoid_t; + + +/* Preprocessor macros */ + +#define GEO_MAX_LEN 48 /* max. formatted length, plus some pad: + module/001c07/slab/5/node/memory/2/slot/4 */ + +/* Values for geo_type_t */ +#define GEO_TYPE_INVALID 0 +#define GEO_TYPE_MODULE 1 +#define GEO_TYPE_NODE 2 +#define GEO_TYPE_RTR 3 +#define GEO_TYPE_IOCNTL 4 +#define GEO_TYPE_IOCARD 5 +#define GEO_TYPE_CPU 6 +#define GEO_TYPE_MEM 7 +#define GEO_TYPE_MAX (GEO_TYPE_MEM+1) + +/* Parameter for hwcfg_format_geoid_compt() */ +#define GEO_COMPT_MODULE 1 +#define GEO_COMPT_SLAB 2 +#define GEO_COMPT_IOBUS 3 +#define GEO_COMPT_IOSLOT 4 +#define GEO_COMPT_CPU 5 +#define GEO_COMPT_MEMBUS 6 +#define GEO_COMPT_MEMSLOT 7 + +#define GEO_INVALID_STR "" + +#endif /* __SYS_SN_SN2_GEO_H__ */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/intr.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/intr.h --- linux-2.4.19/include/asm-ia64/sn/sn2/intr.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/intr.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_INTR_H #define _ASM_IA64_SN_SN2_INTR_H @@ -13,13 +13,15 @@ #define SGI_SHUB_ERROR_VECTOR (0xea) // These two IRQ's are used by partitioning. +#define SGI_XPC_ACTIVATE (0x30) #define SGI_XPC_NOTIFY (0xe7) -#define SGI_XPART_ACTIVATE (0x30) #define IA64_SN2_FIRST_DEVICE_VECTOR (0x31) #define IA64_SN2_LAST_DEVICE_VECTOR (0xe6) #define SN2_IRQ_RESERVED (0x1) #define SN2_IRQ_CONNECTED (0x2) + +#define SN2_IRQ_PER_HUB (2048) #endif /* _ASM_IA64_SN_SN2_INTR_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/mmzone_sn2.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/mmzone_sn2.h --- linux-2.4.19/include/asm-ia64/sn/sn2/mmzone_sn2.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/mmzone_sn2.h Fri Feb 7 08:55:45 2003 @@ -6,7 +6,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -123,6 +123,7 @@ #define KVADDR_TO_NID(kaddr) (local_node_data->physical_node_map[SN2_NODE_NUMBER(kaddr)]) #endif +#define MSPEC_TO_NID(maddr) (local_node_data->physical_node_map[SN2_NODE_NUMBER(maddr)]) /* diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/shub.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub.h --- linux-2.4.19/include/asm-ia64/sn/sn2/shub.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/shub_md.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub_md.h --- linux-2.4.19/include/asm-ia64/sn/sn2/shub_md.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub_md.h Mon Dec 30 14:16:56 2002 @@ -1,14 +1,12 @@ -/************************************************************************** - * * - * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved. * - * * - * These coded instructions, statements, and computer programs contain * - * unpublished proprietary information of Silicon Graphics, Inc., and * - * are protected by Federal copyright law. They may not be disclosed * - * to third parties or copied or duplicated in any form, in whole or * - * in part, without the prior written consent of Silicon Graphics, Inc. * - * * - **************************************************************************/ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001, 2002-2003 Silicon Graphics, Inc. All rights reserved. + */ + #ifndef _SHUB_MD_H #define _SHUB_MD_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/shub_mmr.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub_mmr.h --- linux-2.4.19/include/asm-ia64/sn/sn2/shub_mmr.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub_mmr.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/shub_mmr_t.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub_mmr_t.h --- linux-2.4.19/include/asm-ia64/sn/sn2/shub_mmr_t.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shub_mmr_t.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/shubio.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shubio.h --- linux-2.4.19/include/asm-ia64/sn/sn2/shubio.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/shubio.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SHUBIO_H @@ -3089,11 +3089,11 @@ #define IIO_FIRST_PC_ENTRY 12 */ -#define IIO_ICRB_A(_x) (IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x))) -#define IIO_ICRB_B(_x) (IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET) -#define IIO_ICRB_C(_x) (IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET) -#define IIO_ICRB_D(_x) (IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET) -#define IIO_ICRB_E(_x) (IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET) +#define IIO_ICRB_A(_x) ((u64)(IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x)))) +#define IIO_ICRB_B(_x) ((u64)((char *)IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET)) +#define IIO_ICRB_C(_x) ((u64)((char *)IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET)) +#define IIO_ICRB_D(_x) ((u64)((char *)IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET)) +#define IIO_ICRB_E(_x) ((u64)((char *)IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET)) #define TNUM_TO_WIDGET_DEV(_tnum) (_tnum & 0x7) @@ -3288,12 +3288,9 @@ #ifndef __ASSEMBLY__ /* - * Easy access macros for CRBs, all 4 registers (A-D) + * Easy access macros for CRBs, all 5 registers (A-E) */ typedef ii_icrb0_a_u_t icrba_t; -#define a_lnetuce ii_icrb0_a_fld_s.ia_ln_uce -#define a_mark ii_icrb0_a_fld_s.ia_mark -#define a_xerr ii_icrb0_a_fld_s.ia_xt_err #define a_sidn ii_icrb0_a_fld_s.ia_sidn #define a_tnum ii_icrb0_a_fld_s.ia_tnum #define a_addr ii_icrb0_a_fld_s.ia_addr @@ -3302,35 +3299,56 @@ #define a_regvalue ii_icrb0_a_regval typedef ii_icrb0_b_u_t icrbb_t; -#define b_error ii_icrb0_b_fld_s.ib_error -#define b_ecode ii_icrb0_b_fld_s.ib_errcode -#define b_cohtrans ii_icrb0_b_fld_s.ib_ct -#define b_xtsize ii_icrb0_b_fld_s.ib_size -#define b_source ii_icrb0_b_fld_s.ib_source +#define b_use_old ii_icrb0_b_fld_s.ib_use_old #define b_imsgtype ii_icrb0_b_fld_s.ib_imsgtype #define b_imsg ii_icrb0_b_fld_s.ib_imsg #define b_initiator ii_icrb0_b_fld_s.ib_init +#define b_exc ii_icrb0_b_fld_s.ib_exc +#define b_ackcnt ii_icrb0_b_fld_s.ib_ack_cnt +#define b_resp ii_icrb0_b_fld_s.ib_resp +#define b_ack ii_icrb0_b_fld_s.ib_ack +#define b_hold ii_icrb0_b_fld_s.ib_hold +#define b_wb ii_icrb0_b_fld_s.ib_wb +#define b_intvn ii_icrb0_b_fld_s.ib_intvn +#define b_stall_ib ii_icrb0_b_fld_s.ib_stall_ib +#define b_stall_int ii_icrb0_b_fld_s.ib_stall__intr +#define b_stall_bte_0 ii_icrb0_b_fld_s.ib_stall__bte_0 +#define b_stall_bte_1 ii_icrb0_b_fld_s.ib_stall__bte_1 +#define b_error ii_icrb0_b_fld_s.ib_error +#define b_ecode ii_icrb0_b_fld_s.ib_errcode +#define b_lnetuce ii_icrb0_b_fld_s.ib_ln_uce +#define b_mark ii_icrb0_b_fld_s.ib_mark +#define b_xerr ii_icrb0_b_fld_s.ib_xt_err #define b_regvalue ii_icrb0_b_regval typedef ii_icrb0_c_u_t icrbc_t; -#define c_btenum ii_icrb0_c_fld_s.ic_bte_num -#define c_pricnt ii_icrb0_c_fld_s.ic_pr_cnt -#define c_pripsc ii_icrb0_c_fld_s.ic_pr_psc -#define c_bteaddr ii_icrb0_c_fld_s.ic_pa_be /* ic_pa_be fld has 2 names*/ -#define c_benable ii_icrb0_c_fld_s.ic_pa_be /* ic_pa_be fld has 2 names*/ #define c_suppl ii_icrb0_c_fld_s.ic_suppl #define c_barrop ii_icrb0_c_fld_s.ic_bo #define c_doresp ii_icrb0_c_fld_s.ic_resprqd #define c_gbr ii_icrb0_c_fld_s.ic_gbr +#define c_btenum ii_icrb0_c_fld_s.ic_bte_num +#define c_cohtrans ii_icrb0_c_fld_s.ic_ct +#define c_xtsize ii_icrb0_c_fld_s.ic_size +#define c_source ii_icrb0_c_fld_s.ic_source #define c_regvalue ii_icrb0_c_regval + typedef ii_icrb0_d_u_t icrbd_t; +#define d_sleep ii_icrb0_d_fld_s.id_sleep +#define d_pricnt ii_icrb0_d_fld_s.id_pr_cnt +#define d_pripsc ii_icrb0_d_fld_s.id_pr_psc #define d_bteop ii_icrb0_d_fld_s.id_bte_op -#define icrbd_ctxtvld ii_icrb0_d_fld_s.id_cvld -#define icrbd_toutvld ii_icrb0_d_fld_s.id_tvld -#define icrbd_context ii_icrb0_d_fld_s.id_context +#define d_bteaddr ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/ +#define d_benable ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/ #define d_regvalue ii_icrb0_d_regval +typedef ii_icrb0_e_u_t icrbe_t; +#define icrbe_ctxtvld ii_icrb0_e_fld_s.ie_cvld +#define icrbe_toutvld ii_icrb0_e_fld_s.ie_tvld +#define icrbe_context ii_icrb0_e_fld_s.ie_context +#define icrbe_timeout ii_icrb0_e_fld_s.ie_timeout +#define e_regvalue ii_icrb0_e_regval + #endif /* __ASSEMBLY__ */ /* Number of widgets supported by shub */ @@ -3570,8 +3588,9 @@ extern int hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource hndl */ - xtalk_intr_setfunc_t setfunc, - /* func to set intr hw */ + intr_func_t intr_func, /* xtalk intr handler */ + void *intr_arg, /* arg to intr handler */ + xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ void *setfunc_arg); /* arg to setfunc */ extern void diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/slotnum.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/slotnum.h --- linux-2.4.19/include/asm-ia64/sn/sn2/slotnum.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/slotnum.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1992 - 1997,2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SLOTNUM_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn2/sn_private.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/sn_private.h --- linux-2.4.19/include/asm-ia64/sn/sn2/sn_private.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn2/sn_private.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SN_PRIVATE_H #define _ASM_IA64_SN_SN2_SN_PRIVATE_H @@ -27,7 +27,7 @@ extern nasid_t get_console_nasid(void); extern char get_console_pcislot(void); -extern int is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid); +extern int is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid); /* memsupport.c */ extern void poison_state_alter_range(__psunsigned_t start, int len, int poison); @@ -43,8 +43,10 @@ extern void set_dir_state_UNOWNED(paddr_t); extern int is_POISONED_dir_state(paddr_t); extern int is_UNOWNED_dir_state(paddr_t); +#ifdef LATER extern void get_dir_ent(paddr_t paddr, int *state, uint64_t *vec_ptr, hubreg_t *elo); +#endif /* intr.c */ extern int intr_reserve_level(cpuid_t cpu, int level, int err, devfs_handle_t owner_dev, char *name); diff -Nur linux-2.4.19/include/asm-ia64/sn/sn_cpuid.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_cpuid.h --- linux-2.4.19/include/asm-ia64/sn/sn_cpuid.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_cpuid.h Tue Feb 4 10:57:27 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -18,6 +18,7 @@ #include #include #include +#include /* @@ -121,13 +122,19 @@ #endif /* - * NOTE: id & eid refer to Intels definitions of the LID register - * (id = NASID, eid = slice) + * NOTE: id & eid refer to Intel's definitions of the LID register + * * NOTE: on non-MP systems, only cpuid 0 exists */ -#define id_eid_to_cpu_physical_id(id,eid) (((id)<<8) | (eid)) -#define id_eid_to_cpuid(id,eid) (cpu_logical_id(id_eid_to_cpu_physical_id((id),(eid)))) +#define id_eid_to_cpu_physical_id(id,eid) (((id)<<8) | (eid)) + +#define nasid_slice_to_cpuid(nasid,slice) (cpu_logical_id(nasid_slice_to_cpu_physical_id((nasid),(slice)))) +#ifdef CONFIG_IA64_SGI_SN1 +#define nasid_slice_to_cpu_physical_id(nasid, slice) (((nasid)<<8) | (slice)) +#else +#define nasid_slice_to_cpu_physical_id(nasid, slice) (((slice)<<12) | (nasid)) +#endif /* * The following table/struct is used for managing PTC coherency domains. @@ -184,7 +191,7 @@ * Just extract the NASID from the pointer. * */ -#define cnodeid_to_nasid(cnodeid) (get_node_number(local_node_data->pg_data_ptrs[cnodeid])) +#define cnodeid_to_nasid(cnodeid) pda.cnodeid_to_nasid_table[cnodeid] /* @@ -196,7 +203,8 @@ /* * cnode_slice_to_cpuid - convert a codeid & slice to a cpuid */ -#define cnode_slice_to_cpuid(cnodeid,slice) (id_eid_to_cpuid(cnodeid_to_nasid(cnodeid),(slice))) + +#define cnode_slice_to_cpuid(cnodeid,slice) (nasid_slice_to_cpuid(cnodeid_to_nasid(cnodeid),(slice))) /* diff -Nur linux-2.4.19/include/asm-ia64/sn/sn_fru.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_fru.h --- linux-2.4.19/include/asm-ia64/sn/sn_fru.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_fru.h Mon Dec 30 14:16:56 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 1999-2001 Silicon Graphics, Inc. - * All rights reserved. + * Copyright (C) 1992-1997,1999-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN_FRU_H #define _ASM_IA64_SN_SN_FRU_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn_pio_sync.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_pio_sync.h --- linux-2.4.19/include/asm-ia64/sn/sn_pio_sync.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_pio_sync.h Wed Dec 31 16:00:00 1969 @@ -1,53 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#ifndef _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H -#define _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H - -#include -#ifdef CONFIG_IA64_SGI_SN2 -#include -#include -#include -#include - -/* - * This macro flushes all outstanding PIOs performed by this cpu to the - * intended destination SHUB. This in essence ensures that all PIO's - * issues by this cpu has landed at it's destination. - * - * This macro expects the caller: - * 1. The thread is locked. - * 2. All prior PIO operations has been fenced with __ia64_mf_a(). - * - * The expectation is that get_slice() will return either 0 or 2. - * When we have multi-core cpu's, the expectation is get_slice() will - * return either 0,1 or 2,3. - */ - -#define SN_PIO_WRITE_SYNC \ - { \ - volatile unsigned long sn_pio_writes_done; \ - do { \ - sn_pio_writes_done = (volatile unsigned long) (SH_PIO_WRITE_STATUS_0_WRITES_OK_MASK & HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(get_nasid(), (get_slice() < 2) ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ))); \ - } while (!sn_pio_writes_done); \ - __ia64_mf_a(); \ - } -#else - -/* - * For all ARCHITECTURE type, this is a NOOP. - */ - -#define SN_PIO_WRITE_SYNC - -#endif - -#endif /* _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/sn_private.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_private.h --- linux-2.4.19/include/asm-ia64/sn/sn_private.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_private.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN_PRIVATE_H #define _ASM_IA64_SN_SN_PRIVATE_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sn_sal.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_sal.h --- linux-2.4.19/include/asm-ia64/sn/sn_sal.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sn_sal.h Wed Jan 22 08:57:07 2003 @@ -8,22 +8,26 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ +#include #include #include +#include // SGI Specific Calls #define SN_SAL_POD_MODE 0x02000001 #define SN_SAL_SYSTEM_RESET 0x02000002 #define SN_SAL_PROBE 0x02000003 -#define SN_SAL_GET_CONSOLE_NASID 0x02000004 +#define SN_SAL_GET_MASTER_NASID 0x02000004 #define SN_SAL_GET_KLCONFIG_ADDR 0x02000005 #define SN_SAL_LOG_CE 0x02000006 #define SN_SAL_REGISTER_CE 0x02000007 +#define SN_SAL_GET_PARTITION_ADDR 0x02000009 +#define SN_SAL_PRINT_ERROR 0x02000012 #define SN_SAL_CONSOLE_PUTC 0x02000021 #define SN_SAL_CONSOLE_GETC 0x02000022 #define SN_SAL_CONSOLE_PUTS 0x02000023 @@ -31,6 +35,19 @@ #define SN_SAL_CONSOLE_GETS_TIMEOUT 0x02000025 #define SN_SAL_CONSOLE_POLL 0x02000026 #define SN_SAL_CONSOLE_INTR 0x02000027 +#define SN_SAL_CONSOLE_PUTB 0x02000028 +#define SN_SAL_SYSCTL_MODID_GET 0x02000031 +#define SN_SAL_SYSCTL_GET 0x02000032 +#define SN_SAL_SYSCTL_IOBRICK_MODULE_GET 0x02000033 +#define SN_SAL_SYSCTL_IO_PORTSPEED_GET 0x02000035 +#define SN_SAL_SYSCTL_SLAB_GET 0x02000036 +#define SN_SAL_BUS_CONFIG 0x02000037 +#define SN_SAL_SYS_SERIAL_GET 0x02000038 +#define SN_SAL_PARTITION_SERIAL_GET 0x02000039 +#define SN_SAL_SYSCTL_PARTITION_GET 0x0200003a +#define SN_SAL_SYSTEM_POWER_DOWN 0x0200003b +#define SN_SAL_GET_MASTER_BASEIO_NASID 0x0200003c + /* * Service-specific constants @@ -43,7 +60,58 @@ #define SAL_CONSOLE_INTR_ON 1 /* turn the interrupt on */ +/* + * SN_SAL_GET_PARTITION_ADDR return constants + */ +#define SALRET_MORE_PASSES 1 +#define SALRET_OK 0 +#define SALRET_INVALID_ARG -2 +#define SALRET_ERROR -3 + + +/** + * sn_sal_rev_major - get the major SGI SAL revision number + * + * The SGI PROM stores its version in sal_[ab]_rev_(major|minor). + * This routine simply extracts the major value from the + * @ia64_sal_systab structure constructed by ia64_sal_init(). + */ +static inline int +sn_sal_rev_major(void) +{ + struct ia64_sal_systab *systab = efi.sal_systab; + + return (int)systab->sal_b_rev_major; +} + +/** + * sn_sal_rev_minor - get the minor SGI SAL revision number + * + * The SGI PROM stores its version in sal_[ab]_rev_(major|minor). + * This routine simply extracts the minor value from the + * @ia64_sal_systab structure constructed by ia64_sal_init(). + */ +static inline int +sn_sal_rev_minor(void) +{ + struct ia64_sal_systab *systab = efi.sal_systab; + + return (int)systab->sal_b_rev_minor; +} +/* + * Specify the minimum PROM revsion required for this kernel. + * Note that they're stored in hex format... + */ +#ifdef CONFIG_IA64_SGI_SN1 +#define SN_SAL_MIN_MAJOR 0x0 +#define SN_SAL_MIN_MINOR 0x03 /* SN1 PROMs are stuck at rev 0.03 */ +#elif defined(CONFIG_IA64_SGI_SN2) +#define SN_SAL_MIN_MAJOR 0x1 /* SN2 kernels need at least PROM 1.0 */ +#define SN_SAL_MIN_MINOR 0x0 +#else +#error "must specify which PROM revisions this kernel needs" +#endif /* CONFIG_IA64_SGI_SN1 */ u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr); @@ -60,7 +128,7 @@ ret_stuff.v0 = (uint64_t)0; ret_stuff.v1 = (uint64_t)0; ret_stuff.v2 = (uint64_t)0; - SAL_CALL(ret_stuff, SN_SAL_GET_CONSOLE_NASID, 0, 0, 0, 0, 0, 0, 0); + SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_NASID, 0, 0, 0, 0, 0, 0, 0); if (ret_stuff.status < 0) return ret_stuff.status; @@ -69,6 +137,28 @@ return ret_stuff.v0; } +/* + * Returns the master baseio nasid, if the call fails, return an illegal + * value. + */ +static inline u64 +ia64_sn_get_master_baseio_nasid(void) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_BASEIO_NASID, 0, 0, 0, 0, 0, 0, 0); + + if (ret_stuff.status < 0) + return ret_stuff.status; + + /* Master baseio nasid is in 'v0' */ + return ret_stuff.v0; +} + static inline u64 ia64_sn_get_klconfig_addr(nasid_t nasid) { @@ -109,7 +199,7 @@ ret_stuff.v0 = (uint64_t)0; ret_stuff.v1 = (uint64_t)0; ret_stuff.v2 = (uint64_t)0; - SAL_CALL(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0); + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0); /* character is in 'v0' */ *ch = (int)ret_stuff.v0; @@ -129,7 +219,58 @@ ret_stuff.v0 = (uint64_t)0; ret_stuff.v1 = (uint64_t)0; ret_stuff.v2 = (uint64_t)0; - SAL_CALL(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0); + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0); + + return ret_stuff.status; +} + +/* + * Sends the given buffer to the console. + */ +static inline u64 +ia64_sn_console_putb(char *buf, int len) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTB, (uint64_t)buf, (uint64_t)len, 0, 0, 0, 0, 0); + + return ret_stuff.status; +} + +/* + * Print a platform error record + */ +static inline u64 +ia64_sn_plat_specific_err_print(int (*hook)(const char*, ...), char *rec) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_PRINT_ERROR, (uint64_t)hook, (uint64_t)rec, 0, 0, 0, 0, 0); + + return ret_stuff.status; +} + +/* + * Check for Platform errors + */ +static inline u64 +ia64_sn_plat_cpei_handler(void) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -146,12 +287,143 @@ ret_stuff.v0 = (uint64_t)0; ret_stuff.v1 = (uint64_t)0; ret_stuff.v2 = (uint64_t)0; - SAL_CALL(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0); + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0); + + /* result is in 'v0' */ + *result = (int)ret_stuff.v0; + + return ret_stuff.status; +} + +/* + * Returns the iobrick module Id + */ +static inline u64 +ia64_sn_sysctl_iobrick_module_get(nasid_t nasid, int *result) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + SAL_CALL(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0); /* result is in 'v0' */ *result = (int)ret_stuff.v0; return ret_stuff.status; } + +/** + * ia64_sn_pod_mode - call the SN_SAL_POD_MODE function + * + * SN_SAL_POD_MODE actually takes an argument, but it's always + * 0 when we call it from the kernel, so we don't have to expose + * it to the caller. + */ +static inline u64 +ia64_sn_pod_mode(void) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0); + if (isrv.status) + return 0; + return isrv.v0; +} + +/* + * Retrieve the system serial number as an ASCII string. + */ +static inline u64 +ia64_sn_sys_serial_get(char *buf) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0); + return ret_stuff.status; +} + +extern char sn_system_serial_number_string[]; +extern u64 sn_partition_serial_number; + +static inline char * +sn_system_serial_number(void) { + if (sn_system_serial_number_string[0]) { + return(sn_system_serial_number_string); + } else { + ia64_sn_sys_serial_get(sn_system_serial_number_string); + return(sn_system_serial_number_string); + } +} + + +/* + * Returns a unique id number for this system and partition (suitable for + * use with license managers), based in part on the system serial number. + */ +static inline u64 +ia64_sn_partition_serial_get(void) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_PARTITION_SERIAL_GET, 0, 0, 0, 0, 0, 0, 0); + if (ret_stuff.status != 0) + return 0; + return ret_stuff.v0; +} + +static inline u64 +sn_partition_serial_number_val(void) { + if (sn_partition_serial_number) { + return(sn_partition_serial_number); + } else { + return(sn_partition_serial_number = ia64_sn_partition_serial_get()); + } +} + +/* + * Returns the partition id of the nasid passed in as an argument, + * or INVALID_PARTID if the partition id cannot be retrieved. + */ +static inline partid_t +ia64_sn_sysctl_partition_get(nasid_t nasid) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid, + 0, 0, 0, 0, 0, 0); + if (ret_stuff.status != 0) + return INVALID_PARTID; + return ((partid_t)ret_stuff.v0); +} + +#ifdef CONFIG_IA64_SGI_SN2 +/* + * Returns the partition id of the current processor. + */ + +extern partid_t sn_partid; + +static inline partid_t +sn_local_partid(void) { + if (sn_partid < 0) { + return (sn_partid = ia64_sn_sysctl_partition_get(cpuid_to_nasid(smp_processor_id()))); + } else { + return sn_partid; + } +} + +#endif /* CONFIG_IA64_SGI_SN2 */ + +/* + * Turns off system power. + */ +static inline void +ia64_sn_power_down(void) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_SYSTEM_POWER_DOWN, 0, 0, 0, 0, 0, 0, 0); + while(1); + /* never returns */ +} + #endif /* _ASM_IA64_SN_SN_SAL_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/snconfig.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/snconfig.h --- linux-2.4.19/include/asm-ia64/sn/snconfig.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/snconfig.h Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_IA64_SN_SNCONFIG_H #define _ASM_IA64_SN_SNCONFIG_H diff -Nur linux-2.4.19/include/asm-ia64/sn/sndrv.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sndrv.h --- linux-2.4.19/include/asm-ia64/sn/sndrv.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sndrv.h Mon Dec 30 14:16:56 2002 @@ -1,3 +1,35 @@ +/* + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + #ifndef _ASM_IA64_SN_SNDRV_H #define _ASM_IA64_SN_SNDRV_H @@ -26,6 +58,13 @@ #define SNDRV_SYNERGY_APPEND 33 #define SNDRV_SYNERGY_ENABLE 34 #define SNDRV_SYNERGY_FREQ 35 + +/* see shubstats_ioctl() */ +#define SNDRV_SHUB_INFOSIZE 40 +#define SNDRV_SHUB_CONFIGURE 41 +#define SNDRV_SHUB_RESETSTATS 42 +#define SNDRV_SHUB_GETSTATS 43 +#define SNDRV_SHUB_GETNASID 44 /* Devices */ #define SNDRV_UKNOWN_DEVICE -1 diff -Nur linux-2.4.19/include/asm-ia64/sn/sv.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/sv.h --- linux-2.4.19/include/asm-ia64/sn/sv.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/sv.h Mon Dec 30 14:16:56 2002 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This implemenation of synchronization variables is heavily based on * one done by Steve Lord diff -Nur linux-2.4.19/include/asm-ia64/sn/systeminfo.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/systeminfo.h --- linux-2.4.19/include/asm-ia64/sn/systeminfo.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/systeminfo.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SYSTEMINFO_H #define _ASM_IA64_SN_SYSTEMINFO_H diff -Nur linux-2.4.19/include/asm-ia64/sn/types.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/types.h --- linux-2.4.19/include/asm-ia64/sn/types.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/types.h Mon Dec 30 14:16:56 2002 @@ -3,20 +3,27 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_TYPES_H #define _ASM_IA64_SN_TYPES_H +#include #include typedef unsigned long cpuid_t; typedef unsigned long cpumask_t; typedef signed short nasid_t; /* node id in numa-as-id space */ typedef signed char partid_t; /* partition ID type */ +#ifdef CONFIG_IA64_SGI_SN2 +typedef unsigned int moduleid_t; /* user-visible module number type */ +typedef unsigned int cmoduleid_t; /* kernel compact module id type */ +#else typedef signed short moduleid_t; /* user-visible module number type */ typedef signed short cmoduleid_t; /* kernel compact module id type */ +#endif +typedef signed char slabid_t; typedef unsigned char clusterid_t; /* Clusterid of the cell */ typedef uint64_t __psunsigned_t; diff -Nur linux-2.4.19/include/asm-ia64/sn/uart16550.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/uart16550.h --- linux-2.4.19/include/asm-ia64/sn/uart16550.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/uart16550.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_UART16550_H diff -Nur linux-2.4.19/include/asm-ia64/sn/vector.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/vector.h --- linux-2.4.19/include/asm-ia64/sn/vector.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/vector.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_VECTOR_H #define _ASM_IA64_SN_VECTOR_H diff -Nur linux-2.4.19/include/asm-ia64/sn/xtalk/xbow.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xbow.h --- linux-2.4.19/include/asm-ia64/sn/xtalk/xbow.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xbow.h Mon Dec 30 14:16:56 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_SN_XTALK_XBOW_H #define _ASM_SN_SN_XTALK_XBOW_H @@ -14,6 +13,7 @@ * xbow.h - header file for crossbow chip and xbow section of xbridge */ +#include #include #include #include @@ -42,6 +42,13 @@ #define MAX_PORT_NUM 0x10 /* maximum port number + 1 */ #define XBOW_WIDGET_ID 0 /* xbow is itself widget 0 */ +#define XBOW_HUBLINK_LOW 0xa +#define XBOW_HUBLINK_HIGH 0xb + +#define XBOW_PEER_LINK(link) (link == XBOW_HUBLINK_LOW) ? \ + XBOW_HUBLINK_HIGH : XBOW_HUBLINK_LOW + + #define XBOW_CREDIT 4 #define MAX_XBOW_NAME 16 @@ -384,6 +391,7 @@ #define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbridge */ #define XBOW_WIDGET_MFGR_NUM 0x0 #define XXBOW_WIDGET_MFGR_NUM 0x0 +#define PXBOW_WIDGET_PART_NUM 0xd100 /* PIC */ #define XBOW_REV_1_0 0x1 /* xbow rev 1.0 is "1" */ #define XBOW_REV_1_1 0x2 /* xbow rev 1.1 is "2" */ @@ -398,8 +406,22 @@ #define XBOW_WID_ARB_RELOAD_INT 0x3f /* GBR reload interval */ -#define nasid_has_xbridge(nasid) \ - (XWIDGET_PART_NUM(XWIDGET_ID_READ(nasid, 0)) == XXBOW_WIDGET_PART_NUM) +#ifdef CONFIG_IA64_SGI_SN1 +#define nasid_has_xbridge(nasid) \ + (XWIDGET_PART_NUM(XWIDGET_ID_READ(nasid, 0)) == XXBOW_WIDGET_PART_NUM) +#endif + +#define IS_XBRIDGE_XBOW(wid) \ + (XWIDGET_PART_NUM(wid) == XXBOW_WIDGET_PART_NUM && \ + XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM) + +#define IS_PIC_XBOW(wid) \ + (XWIDGET_PART_NUM(wid) == PXBOW_WIDGET_PART_NUM && \ + XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM) + +#define XBOW_WAR_ENABLED(pv, widid) ((1 << XWIDGET_REV_NUM(widid)) & pv) +#define PV854827 (~0) /* PIC: fake widget 0xf presence bit. permanent */ +#define PV863579 (1 << 1) /* PIC: PIO to PIC register */ #ifndef __ASSEMBLY__ diff -Nur linux-2.4.19/include/asm-ia64/sn/xtalk/xbow_info.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xbow_info.h --- linux-2.4.19/include/asm-ia64/sn/xtalk/xbow_info.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xbow_info.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XBOW_INFO_H #define _ASM_SN_XTALK_XBOW_INFO_H diff -Nur linux-2.4.19/include/asm-ia64/sn/xtalk/xswitch.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xswitch.h --- linux-2.4.19/include/asm-ia64/sn/xtalk/xswitch.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xswitch.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XSWITCH_H #define _ASM_SN_XTALK_XSWITCH_H diff -Nur linux-2.4.19/include/asm-ia64/sn/xtalk/xtalk.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xtalk.h --- linux-2.4.19/include/asm-ia64/sn/xtalk/xtalk.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xtalk.h Mon Dec 30 14:16:56 2002 @@ -4,10 +4,11 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALK_H #define _ASM_SN_XTALK_XTALK_H +#include /* * xtalk.h -- platform-independent crosstalk interface @@ -202,10 +203,19 @@ typedef void xtalk_intr_free_f (xtalk_intr_t intr_hdl); +#ifdef CONFIG_IA64_SGI_SN1 typedef int xtalk_intr_connect_f (xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ xtalk_intr_setfunc_f *setfunc, /* func to set intr hw */ void *setfunc_arg); /* arg to setfunc */ +#else +typedef int +xtalk_intr_connect_f (xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ + intr_func_t intr_func, /* xtalk intr handler */ + void *intr_arg, /* arg to intr handler */ + xtalk_intr_setfunc_f *setfunc, /* func to set intr hw */ + void *setfunc_arg); /* arg to setfunc */ +#endif typedef void xtalk_intr_disconnect_f (xtalk_intr_t intr_hdl); @@ -390,9 +400,6 @@ typedef void xtalk_iter_f(devfs_handle_t vhdl); extern void xtalk_iterate(char *prefix, xtalk_iter_f *func); - -extern int xtalk_device_powerup(devfs_handle_t, xwidgetnum_t); -extern int xtalk_device_shutdown(devfs_handle_t, xwidgetnum_t); #endif /* __KERNEL__ */ #endif /* _ASM_SN_XTALK_XTALK_H */ diff -Nur linux-2.4.19/include/asm-ia64/sn/xtalk/xtalk_private.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xtalk_private.h --- linux-2.4.19/include/asm-ia64/sn/xtalk/xtalk_private.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xtalk_private.h Mon Dec 30 14:16:56 2002 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALK_PRIVATE_H #define _ASM_SN_XTALK_XTALK_PRIVATE_H @@ -60,12 +60,12 @@ ((_hwid)->mfg_num == XBOW_WIDGET_MFGR_NUM )) #define xwidget_hwid_is_sn1_xswitch(_hwid) \ - (((_hwid)->part_num == XXBOW_WIDGET_PART_NUM ) && \ + (((_hwid)->part_num == XXBOW_WIDGET_PART_NUM || \ + (_hwid)->part_num == PXBOW_WIDGET_PART_NUM) && \ ((_hwid)->mfg_num == XXBOW_WIDGET_MFGR_NUM )) #define xwidget_hwid_is_xswitch(_hwid) \ - (xwidget_hwid_is_sn0_xswitch(_hwid) || \ - xwidget_hwid_is_sn1_xswitch(_hwid)) + xwidget_hwid_is_sn1_xswitch(_hwid) /* common iograph info for all widgets, * stashed in FASTINFO of widget connection points. diff -Nur linux-2.4.19/include/asm-ia64/sn/xtalk/xtalkaddrs.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xtalkaddrs.h --- linux-2.4.19/include/asm-ia64/sn/xtalk/xtalkaddrs.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xtalkaddrs.h Mon Dec 30 14:16:56 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALKADDRS_H #define _ASM_SN_XTALK_XTALKADDRS_H diff -Nur linux-2.4.19/include/asm-ia64/sn/xtalk/xwidget.h linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xwidget.h --- linux-2.4.19/include/asm-ia64/sn/xtalk/xwidget.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/sn/xtalk/xwidget.h Mon Dec 30 14:16:56 2002 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef __ASM_SN_XTALK_XWIDGET_H__ #define __ASM_SN_XTALK_XWIDGET_H__ @@ -58,6 +57,7 @@ #define XWIDGET_MFG_NUM(widgetid) (((widgetid) & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT) #define XWIDGET_PART_REV_NUM(widgetid) ((XWIDGET_PART_NUM(widgetid) << 4) | \ XWIDGET_REV_NUM(widgetid)) +#define XWIDGET_PART_REV_NUM_REV(partrev) (partrev & 0xf) /* WIDGET_STATUS */ #define WIDGET_LLP_REC_CNT 0xff000000 diff -Nur linux-2.4.19/include/asm-ia64/string.h linux-2.4.19-sgi211r3/include/asm-ia64/string.h --- linux-2.4.19/include/asm-ia64/string.h Tue Jul 31 10:30:09 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/string.h Tue Aug 27 19:53:13 2002 @@ -5,8 +5,8 @@ * Here is where we want to put optimized versions of the string * routines. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2000, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #include /* remove this once we remove the A-step workaround... */ @@ -17,7 +17,7 @@ #define __HAVE_ARCH_BCOPY 1 /* see arch/ia64/lib/memcpy.S */ extern __kernel_size_t strlen (const char *); -extern void *memset (void *, int, __kernel_size_t); extern void *memcpy (void *, const void *, __kernel_size_t); +extern void *memset (void *, int, __kernel_size_t); #endif /* _ASM_IA64_STRING_H */ diff -Nur linux-2.4.19/include/asm-ia64/system.h linux-2.4.19-sgi211r3/include/asm-ia64/system.h --- linux-2.4.19/include/asm-ia64/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/system.h Wed Feb 5 15:21:59 2003 @@ -14,17 +14,35 @@ */ #include +#include #include +#ifdef __KERNEL__ +#include +#endif -#define KERNEL_START (PAGE_OFFSET + 68*1024*1024) - /* - * The following #defines must match with vmlinux.lds.S: + * Virtual base address of per-node private space (used for kernel + * code and read-only data) + */ +#if 0 +#define VPERNODE_BASE 0xfffffffe00000000 +#else +#define VPERNODE_BASE 0xe002000000000000 +#endif +/* + * Virtual base address of kernel global space (read-write data) */ -#define IVT_ADDR (KERNEL_START) -#define IVT_END_ADDR (KERNEL_START + 0x8000) -#define ZERO_PAGE_ADDR PAGE_ALIGN(IVT_END_ADDR) -#define SWAPPER_PGD_ADDR (ZERO_PAGE_ADDR + 1*PAGE_SIZE) +#if 0 +#define VGLOBAL_BASE 0xffffffff00000000 +#else +#define VGLOBAL_BASE 0xe002100000000000 +#endif + +/* physical address to load kernel */ +#define KERNPHYSBASE (64*1024*1024) + +/* virtual address to load kernel */ +#define KERNEL_START (VPERNODE_BASE) #define GATE_ADDR (0xa000000000000000 + PAGE_SIZE) #define PERCPU_ADDR (0xa000000000000000 + 2*PAGE_SIZE) @@ -35,10 +53,11 @@ #include struct pci_vector_struct { + __u16 segment; /* PCI Segment number */ __u16 bus; /* PCI Bus number */ __u32 pci_id; /* ACPI split 16 bits device, 16 bits function (see section 6.1.1) */ __u8 pin; /* PCI PIN (0 = A, 1 = B, 2 = C, 3 = D) */ - __u8 irq; /* IRQ assigned */ + __u32 irq; /* IRQ assigned */ }; extern struct ia64_boot_param { @@ -89,6 +108,7 @@ */ #define mb() __asm__ __volatile__ ("mf" ::: "memory") #define rmb() mb() +#define read_barrier_depends() do { } while(0) #define wmb() mb() #ifdef CONFIG_SMP @@ -109,6 +129,8 @@ #define set_mb(var, value) do { (var) = (value); mb(); } while (0) #define set_wmb(var, value) do { (var) = (value); mb(); } while (0) +#define safe_halt() ia64_pal_halt(1) /* PAL_HALT */ + /* * The group barrier in front of the rsm & ssm are necessary to ensure * that none of the previous instructions in the same group are @@ -143,16 +165,21 @@ } \ } while (0) -# define local_irq_restore(x) \ -do { \ - unsigned long ip, old_psr, psr = (x); \ - \ - __asm__ __volatile__ (";;mov %0=psr; mov psr.l=%1;; srlz.d" \ - : "=&r" (old_psr) : "r" (psr) : "memory"); \ - if ((old_psr & (1UL << 14)) && !(psr & (1UL << 14))) { \ - __asm__ ("mov %0=ip" : "=r"(ip)); \ - last_cli_ip = ip; \ - } \ +# define local_irq_restore(x) \ +do { \ + unsigned long ip, old_psr, psr = (x); \ + \ + __asm__ __volatile__ ("mov %0=psr;" \ + "cmp.ne p6,p7=%1,r0;;" \ + "(p6) ssm psr.i;" \ + "(p7) rsm psr.i;;" \ + "srlz.d" \ + : "=&r" (old_psr) : "r"((psr) & IA64_PSR_I) \ + : "p6", "p7", "memory"); \ + if ((old_psr & IA64_PSR_I) && !(psr & IA64_PSR_I)) { \ + __asm__ ("mov %0=ip" : "=r"(ip)); \ + last_cli_ip = ip; \ + } \ } while (0) #else /* !CONFIG_IA64_DEBUG_IRQ */ @@ -161,8 +188,12 @@ : "=r" (x) :: "memory") # define local_irq_disable() __asm__ __volatile__ (";; rsm psr.i;;" ::: "memory") /* (potentially) setting psr.i requires data serialization: */ -# define local_irq_restore(x) __asm__ __volatile__ (";; mov psr.l=%0;; srlz.d" \ - :: "r" (x) : "memory") +# define local_irq_restore(x) __asm__ __volatile__ ("cmp.ne p6,p7=%0,r0;;" \ + "(p6) ssm psr.i;" \ + "(p7) rsm psr.i;;" \ + "srlz.d" \ + :: "r"((x) & IA64_PSR_I) \ + : "p6", "p7", "memory") #endif /* !CONFIG_IA64_DEBUG_IRQ */ #define local_irq_enable() __asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory") @@ -355,8 +386,6 @@ #ifdef __KERNEL__ -#define prepare_to_switch() do { } while(0) - #ifdef CONFIG_IA32_SUPPORT # define IS_IA32_PROCESS(regs) (ia64_psr(regs)->is != 0) #else @@ -395,28 +424,50 @@ } while (0) #ifdef CONFIG_SMP - /* - * In the SMP case, we save the fph state when context-switching - * away from a thread that modified fph. This way, when the thread - * gets scheduled on another CPU, the CPU can pick up the state from - * task->thread.fph, avoiding the complication of having to fetch - * the latest fph state from another CPU. - */ -# define switch_to(prev,next,last) do { \ - if (ia64_psr(ia64_task_regs(prev))->mfh) { \ - ia64_psr(ia64_task_regs(prev))->mfh = 0; \ - (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ - __ia64_save_fpu((prev)->thread.fph); \ - } \ - ia64_psr(ia64_task_regs(prev))->dfh = 1; \ - __switch_to(prev,next,last); \ + +/* Return true if this CPU can call the console drivers in printk() */ +#ifdef CONFIG_IA64_SGI_SN +#define arch_consoles_callable() 1 +#else +#define arch_consoles_callable() (cpu_online_map & (1UL << smp_processor_id())) +#endif + +/* + * In the SMP case, we save the fph state when context-switching + * away from a thread that modified fph. This way, when the thread + * gets scheduled on another CPU, the CPU can pick up the state from + * task->thread.fph, avoiding the complication of having to fetch + * the latest fph state from another CPU. + */ +# define switch_to(prev,next,last) do { \ + if (ia64_psr(ia64_task_regs(prev))->mfh) { \ + ia64_psr(ia64_task_regs(prev))->mfh = 0; \ + (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ + __ia64_save_fpu((prev)->thread.fph); \ + (prev)->thread.last_fph_cpu = smp_processor_id(); \ + } \ + if ((next)->thread.flags & IA64_THREAD_FPH_VALID) { \ + if (((next)->thread.last_fph_cpu == smp_processor_id()) \ + && (ia64_get_fpu_owner() == next)) { \ + ia64_psr(ia64_task_regs(next))->dfh = 0; \ + ia64_psr(ia64_task_regs(next))->mfh = 0; \ + } else { \ + ia64_psr(ia64_task_regs(next))->dfh = 1; \ + } \ + } \ + __switch_to(prev,next,last); \ } while (0) #else -# define switch_to(prev,next,last) do { \ +# define switch_to(prev,next,last) do { \ ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next)); \ - __switch_to(prev,next,last); \ + __switch_to(prev,next,last); \ } while (0) #endif + +#define prepare_arch_switch(rq, next) do {spin_lock(&(next)->switch_lock); spin_unlock(&(rq)->lock);} while(0) +#define finish_arch_switch(rq, prev) do {spin_unlock_irq(&(prev)->switch_lock);} while(0) +#define task_running(rq, p) (((rq)->curr == (p)) || spin_is_locked(&(p)->switch_lock)) +#define idle_needs_wakeup 0 #endif /* __KERNEL__ */ diff -Nur linux-2.4.19/include/asm-ia64/timex.h linux-2.4.19-sgi211r3/include/asm-ia64/timex.h --- linux-2.4.19/include/asm-ia64/timex.h Thu Apr 5 12:51:47 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/timex.h Mon Jun 10 10:46:51 2002 @@ -9,9 +9,17 @@ * 2001/01/18 davidm Removed CLOCK_TICK_RATE. It makes no sense on IA-64. * Also removed cacheflush_time as it's entirely unused. */ +#include +#define time_keeper_id 0 /* smp_processor_id() of time-keeper */ typedef unsigned long cycles_t; +#ifdef CONFIG_IA64_HAVE_SYNCHRONIZED_ITC +/** + * get_cycles - return a non-decreasing timestamp + * + * A simple read of ar.itc on machines where it doesn't drift + */ static inline cycles_t get_cycles (void) { @@ -20,5 +28,28 @@ __asm__ __volatile__ ("mov %0=ar.itc" : "=r"(ret)); return ret; } + +#else /* CONFIG_IA64_HAVE_SYNCHRONIZED_ITC is not set */ + +/* + * Platforms w/o synchronized ITCs must define a get_cycles() + * function and a gettimeoffset() function that returns the + * number of microseconds that have elapsed since the last + * update to jiffies. + */ +extern cycles_t get_cycles(void); +extern unsigned long gettimeoffset(void); + +/* contains the value of the RTC at the last clock tick */ +extern volatile unsigned long last_rtc_val; + +/* + * contains elapsed usec from the time that the last clock tick + * was scheduled to occur (itm value) to the point that + * last_rtc_val was read. + */ +extern volatile unsigned long last_itc_lost_usec; + +#endif /* CONFIG_IA64_HAVE_SYNCHRONIZED_ITC */ #endif /* _ASM_IA64_TIMEX_H */ diff -Nur linux-2.4.19/include/asm-ia64/uaccess.h linux-2.4.19-sgi211r3/include/asm-ia64/uaccess.h --- linux-2.4.19/include/asm-ia64/uaccess.h Thu Apr 5 12:51:47 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/uaccess.h Fri Apr 26 11:07:18 2002 @@ -139,25 +139,25 @@ #define __get_user_64(addr) \ asm ("\n"_LL"\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f+4\n" \ _LL \ : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_32(addr) \ asm ("\n"_LL"\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f+4\n" \ _LL \ : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_16(addr) \ asm ("\n"_LL"\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f+4\n" \ _LL \ : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_8(addr) \ asm ("\n"_LL"\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f+4\n" \ _LL \ : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); @@ -201,28 +201,28 @@ #define __put_user_64(x,addr) \ asm volatile ( \ "\n"_LL"\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f\n" \ _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_32(x,addr) \ asm volatile ( \ "\n"_LL"\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f\n" \ _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_16(x,addr) \ asm volatile ( \ "\n"_LL"\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f\n" \ _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_8(x,addr) \ asm volatile ( \ "\n"_LL"\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f\n" \ _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) @@ -309,8 +309,8 @@ }) struct exception_table_entry { - int addr; /* gp-relative address of insn this fixup is for */ - int cont; /* gp-relative continuation address; if bit 2 is set, r9 is set to 0 */ + unsigned long addr; /* address of insn this fixup is for */ + unsigned long cont; /* continuation address; if bit 2 is set, r9 is set to 0 */ }; struct exception_fixup { @@ -319,5 +319,23 @@ extern struct exception_fixup search_exception_table (unsigned long addr); extern void handle_exception (struct pt_regs *regs, struct exception_fixup fixup); + +#ifdef GAS_HAS_LOCAL_TAGS +#define SEARCH_EXCEPTION_TABLE(regs) search_exception_table(regs->cr_iip + ia64_psr(regs)->ri); +#else +#define SEARCH_EXCEPTION_TABLE(regs) search_exception_table(regs->cr_iip); +#endif + +static inline int +done_with_exception (struct pt_regs *regs) +{ + struct exception_fixup fix; + fix = SEARCH_EXCEPTION_TABLE(regs); + if (fix.cont) { + handle_exception(regs, fix); + return 1; + } + return 0; +} #endif /* _ASM_IA64_UACCESS_H */ diff -Nur linux-2.4.19/include/asm-ia64/unistd.h linux-2.4.19-sgi211r3/include/asm-ia64/unistd.h --- linux-2.4.19/include/asm-ia64/unistd.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ia64/unistd.h Wed Oct 16 14:02:58 2002 @@ -206,7 +206,30 @@ #define __NR_getdents64 1214 #define __NR_getunwind 1215 #define __NR_readahead 1216 +#define __NR_setxattr 1217 +#define __NR_lsetxattr 1218 +#define __NR_fsetxattr 1219 +#define __NR_getxattr 1220 +#define __NR_lgetxattr 1221 +#define __NR_fgetxattr 1222 +#define __NR_listxattr 1223 +#define __NR_llistxattr 1224 +#define __NR_flistxattr 1225 +#define __NR_removexattr 1226 +#define __NR_lremovexattr 1227 +#define __NR_fremovexattr 1228 + +/* + * 1230-1232: reserved for futex and sched_[sg]etaffinity. + */ #define __NR_tkill 1229 +#define __NR_security 1233 /* syscall for security modules */ +#if defined(CONFIG_PAGG) +#define __NR_paggctl 1263 +#endif +#if defined(CONFIG_CSA_JOB_ACCT) || defined(CONFIG_CSA_JOB_ACCT_MODULE) +#define __NR_acctctl 1264 +#endif #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff -Nur linux-2.4.19/include/asm-ia64/unwind.h linux-2.4.19-sgi211r3/include/asm-ia64/unwind.h --- linux-2.4.19/include/asm-ia64/unwind.h Tue Jul 31 10:30:09 2001 +++ linux-2.4.19-sgi211r3/include/asm-ia64/unwind.h Fri Dec 13 13:38:05 2002 @@ -60,6 +60,7 @@ unsigned long ip; /* instruction pointer value */ unsigned long pr; /* current predicate values */ unsigned long *cfm_loc; /* cfm save location (or NULL) */ + unsigned long pt; /* struct pt_regs location */ struct task_struct *task; struct switch_stack *sw; diff -Nur linux-2.4.19/include/asm-ia64/vga.h linux-2.4.19-sgi211r3/include/asm-ia64/vga.h --- linux-2.4.19/include/asm-ia64/vga.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.19-sgi211r3/include/asm-ia64/vga.h Tue Aug 27 19:53:13 2002 @@ -1,22 +1,39 @@ +#ifndef _ASM_IA64_VGA_H +#define _ASM_IA64_VGA_H + /* * Access to VGA videoram * * (c) 1998 Martin Mares * (c) 1999 Asit Mallick * (c) 1999 Don Dugger + * Copyright (C) 2002 Hewlett-Packard Co */ - -#ifndef __ASM_IA64_VGA_H_ -#define __ASM_IA64_VGA_H_ - /* - * On the PC, we can just recalculate addresses and then access the - * videoram directly without any black magic. + * 2002/07/19 davidm@hpl.hp.com Access frame-buffer memory via readX/writeX. */ +#include + +#define VT_BUF_HAVE_RW + #define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0)) -#define vga_readb(x) (*(x)) -#define vga_writeb(x,y) (*(y) = (x)) +#define vga_readb __raw_readb +#define vga_writeb __raw_writeb + +extern inline void +scr_writew (u16 val, volatile u16 *addr) +{ + /* Note: ADDR may point to normal memory. That's OK on ia64. */ + __raw_writew(val, (unsigned long) addr); +} + +extern inline u16 +scr_readw (volatile const u16 *addr) +{ + /* Note: ADDR may point to normal memory. That's OK on ia64. */ + return __raw_readw((unsigned long) addr); +} -#endif /* __ASM_IA64_VGA_H_ */ +#endif /* _ASM_IA64_VGA_H */ diff -Nur linux-2.4.19/include/asm-m68k/ioctls.h linux-2.4.19-sgi211r3/include/asm-m68k/ioctls.h --- linux-2.4.19/include/asm-m68k/ioctls.h Thu Feb 12 16:25:04 1998 +++ linux-2.4.19-sgi211r3/include/asm-m68k/ioctls.h Fri Apr 26 11:07:18 2002 @@ -65,6 +65,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -Nur linux-2.4.19/include/asm-m68k/system.h linux-2.4.19-sgi211r3/include/asm-m68k/system.h --- linux-2.4.19/include/asm-m68k/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-m68k/system.h Mon Oct 28 20:43:23 2002 @@ -81,6 +81,7 @@ #define nop() do { asm volatile ("nop"); barrier(); } while (0) #define mb() barrier() #define rmb() barrier() +#define read_barrier_depends() do { } while(0) #define wmb() barrier() #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) diff -Nur linux-2.4.19/include/asm-mips/system.h linux-2.4.19-sgi211r3/include/asm-mips/system.h --- linux-2.4.19/include/asm-mips/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-mips/system.h Mon Oct 28 20:43:23 2002 @@ -202,6 +202,7 @@ #define smp_rmb() barrier() #define smp_wmb() barrier() #endif +#define read_barrier_depends() do { } while(0) #define set_mb(var, value) \ do { var = value; mb(); } while (0) diff -Nur linux-2.4.19/include/asm-mips64/system.h linux-2.4.19-sgi211r3/include/asm-mips64/system.h --- linux-2.4.19/include/asm-mips64/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-mips64/system.h Mon Oct 28 20:43:23 2002 @@ -174,6 +174,7 @@ : /* no input */ \ : "memory") #define rmb() mb() +#define read_barrier_depends() do { } while(0) #define wmb() mb() #ifdef CONFIG_SMP diff -Nur linux-2.4.19/include/asm-parisc/ioctls.h linux-2.4.19-sgi211r3/include/asm-parisc/ioctls.h --- linux-2.4.19/include/asm-parisc/ioctls.h Tue Dec 5 12:29:39 2000 +++ linux-2.4.19-sgi211r3/include/asm-parisc/ioctls.h Fri Apr 26 11:07:18 2002 @@ -67,6 +67,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 /* Get exact space used by quota */ /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -Nur linux-2.4.19/include/asm-parisc/system.h linux-2.4.19-sgi211r3/include/asm-parisc/system.h --- linux-2.4.19/include/asm-parisc/system.h Wed Dec 6 11:46:39 2000 +++ linux-2.4.19-sgi211r3/include/asm-parisc/system.h Mon Oct 28 20:43:23 2002 @@ -60,6 +60,7 @@ #define smp_rmb() __asm__ __volatile__("":::"memory"); #define smp_wmb() __asm__ __volatile__("":::"memory"); #endif +#define read_barrier_depends() do { } while(0) /* interrupt control */ #define __save_flags(x) __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory") diff -Nur linux-2.4.19/include/asm-ppc/system.h linux-2.4.19-sgi211r3/include/asm-ppc/system.h --- linux-2.4.19/include/asm-ppc/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-ppc/system.h Mon Oct 28 20:43:23 2002 @@ -32,6 +32,7 @@ */ #define mb() __asm__ __volatile__ ("sync" : : : "memory") #define rmb() __asm__ __volatile__ ("sync" : : : "memory") +#define read_barrier_depends() do { } while(0) #define wmb() __asm__ __volatile__ ("eieio" : : : "memory") #define set_mb(var, value) do { var = value; mb(); } while (0) diff -Nur linux-2.4.19/include/asm-s390/system.h linux-2.4.19-sgi211r3/include/asm-s390/system.h --- linux-2.4.19/include/asm-s390/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-s390/system.h Mon Oct 28 20:43:23 2002 @@ -116,6 +116,7 @@ # define SYNC_OTHER_CORES(x) eieio() #define mb() eieio() #define rmb() eieio() +#define read_barrier_depends() do { } while(0) #define wmb() eieio() #define smp_mb() mb() #define smp_rmb() rmb() diff -Nur linux-2.4.19/include/asm-s390x/system.h linux-2.4.19-sgi211r3/include/asm-s390x/system.h --- linux-2.4.19/include/asm-s390x/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-s390x/system.h Mon Oct 28 20:43:23 2002 @@ -129,6 +129,7 @@ # define SYNC_OTHER_CORES(x) eieio() #define mb() eieio() #define rmb() eieio() +#define read_barrier_depends() do { } while(0) #define wmb() eieio() #define smp_mb() mb() #define smp_rmb() rmb() diff -Nur linux-2.4.19/include/asm-sh/ioctl.h linux-2.4.19-sgi211r3/include/asm-sh/ioctl.h --- linux-2.4.19/include/asm-sh/ioctl.h Mon Oct 15 13:36:48 2001 +++ linux-2.4.19-sgi211r3/include/asm-sh/ioctl.h Wed Oct 16 14:02:58 2002 @@ -1,4 +1,4 @@ -/* $Id: ioctl.h,v 1.1 2000/04/14 16:48:21 mjd Exp $ +/* $Id: ioctl.h,v 1.1 1999/09/18 17:29:53 gniibe Exp $ * * linux/ioctl.h for Linux by H.H. Bergman. */ diff -Nur linux-2.4.19/include/asm-sh/ioctls.h linux-2.4.19-sgi211r3/include/asm-sh/ioctls.h --- linux-2.4.19/include/asm-sh/ioctls.h Sat Nov 6 10:40:31 1999 +++ linux-2.4.19-sgi211r3/include/asm-sh/ioctls.h Fri Apr 26 11:07:18 2002 @@ -9,6 +9,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) #define TCGETS 0x5401 #define TCSETS 0x5402 diff -Nur linux-2.4.19/include/asm-sh/system.h linux-2.4.19-sgi211r3/include/asm-sh/system.h --- linux-2.4.19/include/asm-sh/system.h Sat Sep 8 12:29:09 2001 +++ linux-2.4.19-sgi211r3/include/asm-sh/system.h Mon Oct 28 20:43:23 2002 @@ -88,6 +88,7 @@ #define mb() __asm__ __volatile__ ("": : :"memory") #define rmb() mb() +#define read_barrier_depends() do { } while(0) #define wmb() __asm__ __volatile__ ("": : :"memory") #ifdef CONFIG_SMP diff -Nur linux-2.4.19/include/asm-sparc/ioctls.h linux-2.4.19-sgi211r3/include/asm-sparc/ioctls.h --- linux-2.4.19/include/asm-sparc/ioctls.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-sparc/ioctls.h Wed Oct 16 14:02:58 2002 @@ -86,6 +86,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it * someday. This is completely bogus, I know... diff -Nur linux-2.4.19/include/asm-sparc/system.h linux-2.4.19-sgi211r3/include/asm-sparc/system.h --- linux-2.4.19/include/asm-sparc/system.h Tue Oct 30 15:08:11 2001 +++ linux-2.4.19-sgi211r3/include/asm-sparc/system.h Mon Oct 28 20:43:23 2002 @@ -278,6 +278,7 @@ #define mb() __asm__ __volatile__ ("" : : : "memory") #define rmb() mb() #define wmb() mb() +#define read_barrier_depends() do { } while(0) #define set_mb(__var, __value) do { __var = __value; mb(); } while(0) #define set_wmb(__var, __value) set_mb(__var, __value) #define smp_mb() __asm__ __volatile__("":::"memory"); diff -Nur linux-2.4.19/include/asm-sparc64/ioctls.h linux-2.4.19-sgi211r3/include/asm-sparc64/ioctls.h --- linux-2.4.19/include/asm-sparc64/ioctls.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-sparc64/ioctls.h Wed Oct 16 14:02:58 2002 @@ -87,6 +87,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it * someday. This is completely bogus, I know... diff -Nur linux-2.4.19/include/asm-sparc64/system.h linux-2.4.19-sgi211r3/include/asm-sparc64/system.h --- linux-2.4.19/include/asm-sparc64/system.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/asm-sparc64/system.h Mon Oct 28 20:43:23 2002 @@ -99,6 +99,7 @@ #define mb() \ membar("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad"); #define rmb() membar("#LoadLoad") +#define read_barrier_depends() do { } while(0) #define wmb() membar("#StoreStore") #define set_mb(__var, __value) \ do { __var = __value; membar("#StoreLoad | #StoreStore"); } while(0) @@ -143,7 +144,11 @@ #define flush_user_windows flushw_user #define flush_register_windows flushw_all -#define prepare_to_switch flushw_all + +#define prepare_arch_schedule(prev) task_lock(prev) +#define finish_arch_schedule(prev) task_unlock(prev) +#define prepare_arch_switch(rq) do { spin_unlock(&(rq)->lock); flushw_all(); } +#define finish_arch_switch(rq) __sti() #ifndef CONFIG_DEBUG_SPINLOCK #define CHECK_LOCKS(PREV) do { } while(0) diff -Nur linux-2.4.19/include/linux/acpi.h linux-2.4.19-sgi211r3/include/linux/acpi.h --- linux-2.4.19/include/linux/acpi.h Thu Oct 11 13:53:22 2001 +++ linux-2.4.19-sgi211r3/include/linux/acpi.h Wed Oct 16 14:02:58 2002 @@ -1,180 +1,387 @@ /* - * acpi.h - ACPI driver interface + * acpi.h - ACPI Interface * - * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Paul Diefenbaugh * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #ifndef _LINUX_ACPI_H #define _LINUX_ACPI_H -#include -#include -#ifdef __KERNEL__ -#include -#include -#endif /* __KERNEL__ */ +#ifndef _LINUX +#define _LINUX +#endif + +#include /* - * Device states + * Yes this is ugly, but moving all of ACPI's private headers to include/acpi + * isn't the right answer either. Please just ignore it for now. */ -typedef enum { - ACPI_D0, /* fully-on */ - ACPI_D1, /* partial-on */ - ACPI_D2, /* partial-on */ - ACPI_D3, /* fully-off */ -} acpi_dstate_t; - -typedef enum { - ACPI_S0, /* working state */ - ACPI_S1, /* power-on suspend */ - ACPI_S2, /* suspend to ram, with devices */ - ACPI_S3, /* suspend to ram */ - ACPI_S4, /* suspend to disk */ - ACPI_S5, /* soft-off */ -} acpi_sstate_t; - -/* RSDP location */ -#define ACPI_BIOS_ROM_BASE (0x0e0000) -#define ACPI_BIOS_ROM_END (0x100000) - -/* Table signatures */ -#define ACPI_RSDP1_SIG 0x20445352 /* 'RSD ' */ -#define ACPI_RSDP2_SIG 0x20525450 /* 'PTR ' */ -#define ACPI_RSDT_SIG 0x54445352 /* 'RSDT' */ -#define ACPI_FADT_SIG 0x50434146 /* 'FACP' */ -#define ACPI_DSDT_SIG 0x54445344 /* 'DSDT' */ -#define ACPI_FACS_SIG 0x53434146 /* 'FACS' */ - -#define ACPI_SIG_LEN 4 -#define ACPI_FADT_SIGNATURE "FACP" - -/* PM1_STS/EN flags */ -#define ACPI_TMR 0x0001 -#define ACPI_BM 0x0010 -#define ACPI_GBL 0x0020 -#define ACPI_PWRBTN 0x0100 -#define ACPI_SLPBTN 0x0200 -#define ACPI_RTC 0x0400 -#define ACPI_WAK 0x8000 - -/* PM1_CNT flags */ -#define ACPI_SCI_EN 0x0001 -#define ACPI_BM_RLD 0x0002 -#define ACPI_GBL_RLS 0x0004 -#define ACPI_SLP_TYP0 0x0400 -#define ACPI_SLP_TYP1 0x0800 -#define ACPI_SLP_TYP2 0x1000 -#define ACPI_SLP_EN 0x2000 - -#define ACPI_SLP_TYP_MASK 0x1c00 -#define ACPI_SLP_TYP_SHIFT 10 - -/* PM_TMR masks */ -#define ACPI_TMR_VAL_EXT 0x00000100 -#define ACPI_TMR_MASK 0x00ffffff -#define ACPI_TMR_HZ 3579545 /* 3.58 MHz */ -#define ACPI_TMR_KHZ (ACPI_TMR_HZ / 1000) - -#define ACPI_MICROSEC_TO_TMR_TICKS(val) \ - (((val) * (ACPI_TMR_KHZ)) / 1000) - -/* PM2_CNT flags */ -#define ACPI_ARB_DIS 0x01 - -/* FADT flags */ -#define ACPI_WBINVD 0x00000001 -#define ACPI_WBINVD_FLUSH 0x00000002 -#define ACPI_PROC_C1 0x00000004 -#define ACPI_P_LVL2_UP 0x00000008 -#define ACPI_PWR_BUTTON 0x00000010 -#define ACPI_SLP_BUTTON 0x00000020 -#define ACPI_FIX_RTC 0x00000040 -#define ACPI_RTC_64 0x00000080 -#define ACPI_TMR_VAL_EXT 0x00000100 -#define ACPI_DCK_CAP 0x00000200 - -/* FADT BOOT_ARCH flags */ -#define FADT_BOOT_ARCH_LEGACY_DEVICES 0x0001 -#define FADT_BOOT_ARCH_KBD_CONTROLLER 0x0002 - -/* FACS flags */ -#define ACPI_S4BIOS 0x00000001 - -/* processor block offsets */ -#define ACPI_P_CNT 0x00000000 -#define ACPI_P_LVL2 0x00000004 -#define ACPI_P_LVL3 0x00000005 - -/* C-state latencies (microseconds) */ -#define ACPI_MAX_P_LVL2_LAT 100 -#define ACPI_MAX_P_LVL3_LAT 1000 -#define ACPI_INFINITE_LAT (~0UL) +#include "../../drivers/acpi/include/acpi.h" +#include "../../drivers/acpi/acpi_drivers.h" +#include + + +#ifdef CONFIG_ACPI_BOOT + +enum acpi_irq_model_id { + ACPI_IRQ_MODEL_PIC = 0, + ACPI_IRQ_MODEL_IOAPIC, + ACPI_IRQ_MODEL_IOSAPIC, + ACPI_IRQ_MODEL_COUNT +}; + +extern enum acpi_irq_model_id acpi_irq_model; + + +/* Root System Description Pointer (RSDP) */ + +struct acpi_table_rsdp { + char signature[8]; + u8 checksum; + char oem_id[6]; + u8 revision; + u32 rsdt_address; +} __attribute__ ((packed)); + +struct acpi20_table_rsdp { + char signature[8]; + u8 checksum; + char oem_id[6]; + u8 revision; + u32 rsdt_address; + u32 length; + u64 xsdt_address; + u8 ext_checksum; + u8 reserved[3]; +} __attribute__ ((packed)); + +/* Common table header */ + +struct acpi_table_header { + char signature[4]; + u32 length; + u8 revision; + u8 checksum; + char oem_id[6]; + char oem_table_id[8]; + u32 oem_revision; + char asl_compiler_id[4]; + u32 asl_compiler_revision; +} __attribute__ ((packed)); + +typedef struct { + u8 type; + u8 length; +} acpi_table_entry_header __attribute__ ((packed)); + +/* Root System Description Table (RSDT) */ + +struct acpi_table_rsdt { + struct acpi_table_header header; + u32 entry[1]; +} __attribute__ ((packed)); + +/* Extended System Description Table (XSDT) */ + +struct acpi_table_xsdt { + struct acpi_table_header header; + u64 entry[1]; +} __attribute__ ((packed)); + +/* Multiple APIC Description Table (MADT) */ + +struct acpi_table_madt { + struct acpi_table_header header; + u32 lapic_address; + struct { + u32 pcat_compat:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +enum acpi_madt_entry_id { + ACPI_MADT_LAPIC = 0, + ACPI_MADT_IOAPIC, + ACPI_MADT_INT_SRC_OVR, + ACPI_MADT_NMI_SRC, + ACPI_MADT_LAPIC_NMI, + ACPI_MADT_LAPIC_ADDR_OVR, + ACPI_MADT_IOSAPIC, + ACPI_MADT_LSAPIC, + ACPI_MADT_PLAT_INT_SRC, + ACPI_MADT_ENTRY_COUNT +}; + +typedef struct { + u16 polarity:2; + u16 trigger:2; + u16 reserved:12; +} acpi_interrupt_flags __attribute__ ((packed)); + +struct acpi_table_lapic { + acpi_table_entry_header header; + u8 acpi_id; + u8 id; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +struct acpi_table_ioapic { + acpi_table_entry_header header; + u8 id; + u8 reserved; + u32 address; + u32 global_irq_base; +} __attribute__ ((packed)); + +struct acpi_table_int_src_ovr { + acpi_table_entry_header header; + u8 bus; + u8 bus_irq; + u32 global_irq; + acpi_interrupt_flags flags; +} __attribute__ ((packed)); + +struct acpi_table_nmi_src { + acpi_table_entry_header header; + acpi_interrupt_flags flags; + u32 global_irq; +} __attribute__ ((packed)); + +struct acpi_table_lapic_nmi { + acpi_table_entry_header header; + u8 acpi_id; + acpi_interrupt_flags flags; + u8 lint; +} __attribute__ ((packed)); + +struct acpi_table_lapic_addr_ovr { + acpi_table_entry_header header; + u8 reserved[2]; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_iosapic { + acpi_table_entry_header header; + u8 id; + u8 reserved; + u32 global_irq_base; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_lsapic { + acpi_table_entry_header header; + u8 acpi_id; + u8 id; + u8 eid; + u8 reserved[3]; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +struct acpi_table_plat_int_src { + acpi_table_entry_header header; + acpi_interrupt_flags flags; + u8 type; /* See acpi_interrupt_type */ + u8 id; + u8 eid; + u8 iosapic_vector; + u32 global_irq; + u32 reserved; +} __attribute__ ((packed)); + +enum acpi_interrupt_id { + ACPI_INTERRUPT_PMI = 1, + ACPI_INTERRUPT_INIT, + ACPI_INTERRUPT_CPEI, + ACPI_INTERRUPT_COUNT +}; /* - * Sysctl declarations + * System Resource Affinity Table (SRAT) + * see http://www.microsoft.com/hwdev/design/srat.htm */ -enum -{ - CTL_ACPI = 10 +struct acpi_table_srat { + struct acpi_table_header header; + u32 table_revision; + u64 reserved; +} __attribute__ ((packed)); + +enum acpi_srat_entry_id { + ACPI_SRAT_PROCESSOR_AFFINITY = 0, + ACPI_SRAT_MEMORY_AFFINITY, + ACPI_SRAT_ENTRY_COUNT +}; + +struct acpi_table_processor_affinity { + acpi_table_entry_header header; + u8 proximity_domain; + u8 apic_id; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; + u8 lsapic_eid; + u8 reserved[7]; +} __attribute__ ((packed)); + +struct acpi_table_memory_affinity { + acpi_table_entry_header header; + u8 proximity_domain; + u8 reserved1[5]; + u32 base_addr_lo; + u32 base_addr_hi; + u32 length_lo; + u32 length_hi; + u32 memory_type; /* See acpi_address_range_id */ + struct { + u32 enabled:1; + u32 hot_pluggable:1; + u32 reserved:30; + } flags; + u64 reserved2; +} __attribute__ ((packed)); + +enum acpi_address_range_id { + ACPI_ADDRESS_RANGE_MEMORY = 1, + ACPI_ADDRESS_RANGE_RESERVED = 2, + ACPI_ADDRESS_RANGE_ACPI = 3, + ACPI_ADDRESS_RANGE_NVS = 4, + ACPI_ADDRESS_RANGE_COUNT }; -enum -{ - ACPI_FADT = 1, +/* + * System Locality Information Table (SLIT) + * see http://devresource.hp.com/devresource/docs/techpapers/ia64/slit.pdf + */ + +struct acpi_table_slit { + struct acpi_table_header header; + u64 localities; + u8 entry[1]; /* real size = localities^2 */ +} __attribute__ ((packed)); + +/* Smart Battery Description Table (SBST) */ + +struct acpi_table_sbst { + struct acpi_table_header header; + u32 warning; /* Warn user */ + u32 low; /* Critical sleep */ + u32 critical; /* Critical shutdown */ +} __attribute__ ((packed)); + +/* Embedded Controller Boot Resources Table (ECDT) */ + +struct acpi_table_ecdt { + struct acpi_table_header header; + acpi_generic_address ec_control; + acpi_generic_address ec_data; + u32 uid; + u8 gpe_bit; + char *ec_id; +} __attribute__ ((packed)); + +/* Table Handlers */ + +enum acpi_table_id { + ACPI_TABLE_UNKNOWN = 0, + ACPI_APIC, + ACPI_BOOT, + ACPI_DBGP, ACPI_DSDT, - ACPI_PM1_ENABLE, - ACPI_GPE_ENABLE, - ACPI_GPE_LEVEL, - ACPI_EVENT, - ACPI_P_BLK, - ACPI_ENTER_LVL2_LAT, - ACPI_ENTER_LVL3_LAT, - ACPI_P_LVL2_LAT, - ACPI_P_LVL3_LAT, - ACPI_C1_TIME, - ACPI_C2_TIME, - ACPI_C3_TIME, - ACPI_C1_COUNT, - ACPI_C2_COUNT, - ACPI_C3_COUNT, - ACPI_S0_SLP_TYP, - ACPI_S1_SLP_TYP, - ACPI_S5_SLP_TYP, - ACPI_SLEEP, + ACPI_ECDT, + ACPI_ETDT, + ACPI_FACP, ACPI_FACS, - ACPI_XSDT, - ACPI_PMTIMER, - ACPI_BATT, + ACPI_OEMX, + ACPI_PSDT, + ACPI_SBST, + ACPI_SLIT, + ACPI_SPCR, + ACPI_SRAT, + ACPI_SSDT, + ACPI_SPMI, + ACPI_TABLE_COUNT }; -#define ACPI_SLP_TYP_DISABLED (~0UL) +typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size); + +extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT]; + +typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header); + +char * __acpi_map_table (unsigned long phys_addr, unsigned long size); +unsigned long acpi_find_rsdp (void); +int acpi_boot_init (char *cmdline); -#ifdef __KERNEL__ +int acpi_table_init (char *cmdline); +int acpi_table_parse (enum acpi_table_id, acpi_table_handler); +int acpi_table_parse_madt (enum acpi_table_id, acpi_madt_entry_handler); +void acpi_table_print (struct acpi_table_header *, unsigned long); +void acpi_table_print_madt_entry (acpi_table_entry_header *); -/* routines for saving/restoring kernel state */ -FASTCALL(extern unsigned long acpi_save_state_mem(unsigned long return_point)); -FASTCALL(extern int acpi_save_state_disk(unsigned long return_point)); -extern void acpi_restore_state(void); +#endif /*CONFIG_ACPI_BOOT*/ -extern unsigned long acpi_wakeup_address; -#endif /* __KERNEL__ */ +#ifdef CONFIG_ACPI_PCI + +struct acpi_prt_entry { + struct list_head node; + acpi_pci_id id; + u8 pin; + struct { + acpi_handle handle; + u32 index; + } link; + u32 irq; +}; + +struct acpi_prt_list { + int count; + struct list_head entries; +}; + +extern struct acpi_prt_list acpi_prt; + +struct pci_dev; + +int acpi_pci_irq_enable (struct pci_dev *dev); +int acpi_pci_irq_init (void); + +#endif /*CONFIG_ACPI_PCI*/ + + +#ifdef CONFIG_ACPI int acpi_init(void); +acpi_status acpi_hp_csr_space(acpi_handle, u64 *base, u64 *length); +acpi_status acpi_get_addr_space(acpi_handle, u8 type, u64 *base, u64 *length, u64 *tra); + +#endif /*CONFIG_ACPI*/ + -#endif /* _LINUX_ACPI_H */ +#endif /*_LINUX_ACPI_H*/ diff -Nur linux-2.4.19/include/linux/acpi_serial.h linux-2.4.19-sgi211r3/include/linux/acpi_serial.h --- linux-2.4.19/include/linux/acpi_serial.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/acpi_serial.h Fri Apr 26 11:07:18 2002 @@ -0,0 +1,105 @@ +/* + * linux/include/linux/acpi_serial.h + * + * Copyright (C) 2000 Hewlett-Packard Co. + * Copyright (C) 2000 Khalid Aziz + * + * Definitions for ACPI defined serial ports (headless console and + * debug ports) + * + */ + +extern void setup_serial_acpi(void *); + +#define ACPI_SIG_LEN 4 + +/* ACPI table signatures */ +#define ACPI_SPCRT_SIGNATURE "SPCR" +#define ACPI_DBGPT_SIGNATURE "DBGP" + +/* Interface type as defined in ACPI serial port tables */ +#define ACPI_SERIAL_INTFC_16550 0 +#define ACPI_SERIAL_INTFC_16450 1 + +/* Interrupt types for ACPI serial port tables */ +#define ACPI_SERIAL_INT_PCAT 0x01 +#define ACPI_SERIAL_INT_APIC 0x02 +#define ACPI_SERIAL_INT_SAPIC 0x04 + +/* Baud rates as defined in ACPI serial port tables */ +#define ACPI_SERIAL_BAUD_9600 3 +#define ACPI_SERIAL_BAUD_19200 4 +#define ACPI_SERIAL_BAUD_57600 6 +#define ACPI_SERIAL_BAUD_115200 7 + +/* Parity as defined in ACPI serial port tables */ +#define ACPI_SERIAL_PARITY_NONE 0 + +/* Flow control methods as defined in ACPI serial port tables */ +#define ACPI_SERIAL_FLOW_DCD 0x01 +#define ACPI_SERIAL_FLOW_RTS 0x02 +#define ACPI_SERIAL_FLOW_XON 0x04 + +/* Terminal types as defined in ACPI serial port tables */ +#define ACPI_SERIAL_TERM_VT100 0 +#define ACPI_SERIAL_TERM_VT100X 1 + +/* PCI Flags as defined by SPCR table */ +#define ACPI_SERIAL_PCIFLAG_PNP 0x00000001 + +/* Space ID as defined in base address structure in ACPI serial port tables */ +#define ACPI_SERIAL_MEM_SPACE 0 +#define ACPI_SERIAL_IO_SPACE 1 +#define ACPI_SERIAL_PCICONF_SPACE 2 + +/* + * Generic Register Address Structure - as defined by Microsoft + * in http://www.microsoft.com/hwdev/onnow/download/LFreeACPI.doc + * +*/ +typedef struct { + u8 space_id; + u8 bit_width; + u8 bit_offset; + u8 resv; + u32 addrl; + u32 addrh; +} gen_regaddr; + +/* Space ID for generic register address structure */ +#define REGADDR_SPACE_SYSMEM 0 +#define REGADDR_SPACE_SYSIO 1 +#define REGADDR_SPACE_PCICONFIG 2 + +/* Serial Port Console Redirection and Debug Port Table formats */ +typedef struct { + u8 signature[4]; + u32 length; + u8 rev; + u8 chksum; + u8 oemid[6]; + u8 oem_tabid[8]; + u32 oem_rev; + u8 creator_id[4]; + u32 creator_rev; + u8 intfc_type; + u8 resv1[3]; + gen_regaddr base_addr; + u8 int_type; + u8 irq; + u8 global_int[4]; + u8 baud; + u8 parity; + u8 stop_bits; + u8 flow_ctrl; + u8 termtype; + u8 language; + u16 pci_dev_id; + u16 pci_vendor_id; + u8 pci_bus; + u8 pci_dev; + u8 pci_func; + u8 pci_flags[4]; + u8 pci_seg; + u32 resv2; +} acpi_ser_t; diff -Nur linux-2.4.19/include/linux/agp_backend.h linux-2.4.19-sgi211r3/include/linux/agp_backend.h --- linux-2.4.19/include/linux/agp_backend.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/agp_backend.h Wed Oct 16 14:02:58 2002 @@ -27,6 +27,8 @@ #ifndef _AGP_BACKEND_H #define _AGP_BACKEND_H 1 +#include + #ifndef TRUE #define TRUE 1 #endif @@ -53,6 +55,7 @@ INTEL_I845, INTEL_I850, INTEL_I860, + INTEL_460GX, VIA_GENERIC, VIA_VP3, VIA_MVP3, @@ -119,6 +122,7 @@ size_t page_count; int num_scratch_pages; unsigned long *memory; + void *vmptr; off_t pg_start; u32 type; u32 physical; diff -Nur linux-2.4.19/include/linux/cache.h linux-2.4.19-sgi211r3/include/linux/cache.h --- linux-2.4.19/include/linux/cache.h Fri Dec 21 09:42:03 2001 +++ linux-2.4.19-sgi211r3/include/linux/cache.h Thu Aug 8 15:12:42 2002 @@ -4,8 +4,16 @@ #include #include +#ifndef L1_CACHE_MASK +#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) +#endif + #ifndef L1_CACHE_ALIGN -#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) +#define L1_CACHE_ALIGN(x) (((x) + L1_CACHE_MASK) & ~L1_CACHE_MASK) +#endif + +#ifndef L1_CACHE_ALIGNED +#define L1_CACHE_ALIGNED(_p) (((u64)(_p) & L1_CACHE_MASK) == 0) #endif #ifndef SMP_CACHE_BYTES diff -Nur linux-2.4.19/include/linux/cpumemset.h linux-2.4.19-sgi211r3/include/linux/cpumemset.h --- linux-2.4.19/include/linux/cpumemset.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/cpumemset.h Wed Feb 5 20:48:13 2003 @@ -0,0 +1,488 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * CpuMemSets provide task-by-task control of which cpus a task + * may be scheduled on, and page-by-page control of which memory + * nodes a page may be allocated on. All tasks, all vm areas, + * and the kernel, have a CpuMemSet. Hooks into the main kernel + * scheduling and allocation code are minimized, in order to + * make it easy to change that code, independent of CpuMemSets. + * + * A CpuMemSet provides two layers - cpumemsets and cpumemmaps. + * The upper layer, cpumemsets, provides a list of cpus on + * which a task may be scheduled, and lists of memory nodes + * on which memory may be allocated varying both by vm area + * and by which cpu took the page fault. The underlying layer, + * cpumemmaps, maps application to system cpu and memory numbers, + * for hot plug support and flexible system resource management + * transparent to applications. + * + * System numbers are those known in much of the rest of the + * kernel, such as in the cpus_allowed and mems_allowed bit + * vectors. Application numbers are presented to applications + * manipulating CpuMemSets via the system call API. By default, + * on a non-hot-swap system, unless changed perhaps by a system + * management service, these two numberings are identical. + * + * The current scheduler and allocator hooks depend on long + * bit masks cpus_allowed and mems_allowed, and will need + * adaption when we extend these past 64 bits (64 cpu systems). + * The system call API seen by applications manipulating + * CpuMemSets, as well as the bulk of the kernel CpuMemSet + * code that handles these calls, uses arbitrary length lists, + * and should extend to any number of cpus without change. + * + * See the user level include file "cpumemsets.h" for more + * substantial documentation of CpuMemSets. + */ + +#ifndef _CPUMEMSET_H +#define _CPUMEMSET_H + +#include +#include +#include +#include + +#ifdef CONFIG_CPUMEMSET + +/* Policy flags for CpuMemSets */ +#define CMS_DEFAULT 0x01 /* Memory list order (first-touch, typically) */ +#define CMS_SHARE 0x04 /* Inherit virtual memory area CMS, not task */ +typedef int cms_setpol_t; /* Type of policy argument for sets */ + +/* 16 bits gets us 64K cpus ... no one will ever need more than that! */ +typedef uint16_t cms_acpu_t; /* Type of application cpu number */ +typedef uint16_t cms_amem_t; /* Type of application memory node number */ +typedef uint16_t cms_scpu_t; /* Type of system cpu number */ +typedef uint16_t cms_smem_t; /* Type of system memory node number */ + +#define CMS_DEFAULT_CPU ((cms_acpu_t)-1) /* Marks default Memory List */ + +/* Calls to query and set cmm and cms need to specify which one ... */ +#define CMS_CURRENT 0 /* cmm or *current* cms of this process */ +#define CMS_CHILD 1 /* *child* cms of this process */ +#define CMS_VMAREA 2 /* cmm or cms of vmarea at given virtual addr */ +#define CMS_KERNEL 3 /* cmm or cms of kernel (root-only) */ +typedef int cms_choice_t; /* Type of cmm/cms choice argument */ + +typedef struct cms_memory_list { + int nr_cpus; /* Number of cpu's sharing this memory list */ + int nr_mems; /* Number of memory nodes in this list */ + cms_acpu_t *cpus; /* Array of cpu's sharing this memory list */ + cms_amem_t *mems; /* Array of 'nr_mems' memory nodes */ +} cms_memory_list_t; + +/* CpuMemMap: Type for the pair of maps ... */ +typedef struct cpumemmap { + int nr_cpus; /* number of cpus in map */ + int nr_mems; /* number of mems in map */ + cms_scpu_t *cpus; /* array maps application to system cpu num */ + cms_smem_t *mems; /* array maps application to system mem num */ + atomic_t counter; /* reference counter */ +} cpumemmap_t; + +typedef struct cpumemset { + cms_setpol_t policy; /* above CMS_* policy flag */ + int nr_cpus; /* Number of cpus in this CpuMemSet */ + int nr_mems; /* Number of Memory Lists in this CpuMemSet */ + cms_acpu_t *cpus; /* The 'nr_cpus' app cpu nums in this set */ + cms_memory_list_t *mems; /* Array 'nr_mems' Memory Lists */ + unsigned long mems_allowed; /* memory_allowed vector used by vmas */ + cpumemmap_t *cmm; /* associated cpumemmap */ + atomic_t counter; /* reference counter */ +} cpumemset_t; + +/* System calls to query/change CpuMemSets go here from prctl */ +int cms_query_cmm_size (unsigned long *preq, int *psize); +int cms_query_cms_size (unsigned long *preq, int *psize); +int cms_query_cmm (unsigned long *preq, char *rec, int size); +int cms_query_cms (unsigned long *preq, char *rec, int size); +int cms_set_cmm (unsigned long *preq, char *rec, int size); +int cms_set_cms (unsigned long *preq, char *rec, int size); +int cms_getcpu(void); + +/* Called from init/main.c during boot */ +void cms_cmm_static_init(void) __init; +void cms_cmm_init(void) __init; + +/* Used in Short Circuit Handle Macros */ +void free_cms(cpumemset_t *cms); +void free_cmm(cpumemmap_t *cmm); +void update_cpus_allowed(struct task_struct *p); + +/* Boot time argument - minimal or full (default) initial CpuMemSet? */ +extern int cms_boot_arg; + +/* Kernel Cpumemset and Granddaddy of user cms's */ +extern cpumemset_t *kernel_cms; + +/* + * Debug and Trace Hooks: + * + * Most of the DEBUG_CMS code is in kernel/cpumemset.c. + * The Short Circuit Handle Macros below also have CMS_TRACE_HOOK + * enabled iff DEBUG_CMS is defined. + * + * Normally: #undef DEBUG_CMS + * Debugging: #define DEBUG_CMS + */ + +#undef DEBUG_CMS +#ifdef DEBUG_CMS + +/* + * Only do real tracing every so often - too expensive. + * Count number times a Short Circuit Handle Macro is called, + * and after CMS_TRACE_THRESHOLD calls, call the real trace + * routine: cms_trace_hook(). The cms_num_short_circuit_calls + * counter is reset to zero inside cms_trace_hook(). + */ + +void cms_trace_hook(char *name, cpumemset_t *cms); +extern int cms_num_short_circuit_calls; +#define CMS_TRACE_THRESHOLD 100 + +#define CMS_TRACE_HOOK(name,cms) do { \ + if (cms_num_short_circuit_calls++ > CMS_TRACE_THRESHOLD)\ + cms_trace_hook((name), (cms)); \ + } while (0) + +#else + +#define CMS_TRACE_HOOK(name,cms) do {} while (0) + +#endif /* DEBUG_CMS */ + +/* Call when freeing a single (current or child) cpumemset */ +#define CMS_FREE_SINGLE_CMS(cms) do { \ + CMS_TRACE_HOOK("free cms", cms); \ + if (atomic_dec_and_test(&cms->counter)) { \ + cpumemmap_t *cmm = cms->cmm; \ + free_cms(cms); \ + if (atomic_dec_and_test(&cmm->counter)) \ + free_cmm(cmm); \ + } \ + } while (0) + +/* Call when freeing a task, to free its cms's */ +#define CMS_FREE_TASK(p) do { \ + CMS_FREE_SINGLE_CMS((p)->current_cms); \ + CMS_FREE_SINGLE_CMS((p)->child_cms); \ + } while (0) + +/* Init init_task cms fields: cms_cmm_static_init() fills later */ +#define INIT_TASK_CPUMEMSET() \ + current_cms: 0, \ + child_cms: 0, \ + interrupt_mems_allowed: -1, \ + +/* + * Set child's current, child and alloc cpumemset + * from parent's child_cms (used in fork). + */ + +#define SET_CHILD_CMS(child, parent) do { \ + cpumemset_t *cms = (parent)->child_cms; \ + CMS_TRACE_HOOK("fork task", cms); \ + atomic_inc(&cms->counter); \ + (child)->current_cms = cms; \ + update_cpus_allowed(p); \ + atomic_inc(&cms->counter); \ + (child)->child_cms = cms; \ + } while (0) + +/* + * Obtain the current tasks CMS_CURRENT cpumemset value of mems_allowed. + * Used to set the mems_allowed field of vm_area_struct's. + */ +unsigned long cms_current_mems_allowed(void); + +/* Used in __alloc_pages() to see if we can allocate from a node */ +#define CHECK_MEMS_ALLOWED(mems_allowed, zone) \ + ((1UL << (zone)->zone_pgdat->node_id) & (mems_allowed)) + +/* + * CpuMemSet Locking: + * + * Safe access and updating of CpuMemSets is a little tricky. + * + * There are multiple reference counted pointers to each CpuMemSet + * (set) from tasksand the kernel, and in turn multiple + * sets can have reference counted pointers to the same CpuMemMap + * (map). Multiple tasks may simultaneously be trying to access, + * attach, discard or change any given set or map. + * + * All multi-threaded access, change, creation and deletion of + * cpumemset_t's (sets) and cpumemmap_t's (maps) is handled by + * the following routines (or the Short Circuit Handle Macros + * above, which provide fast paths for certain combinations): + * + * Get a handle: + * cmsGetHandleTask() - Safely get a handle to a tasks set and map pair. + * cmsGetHandlePid() - Safely get a handle to a pid's set and map pair. + * cmsGetHandleKern() - Safely get a handle to the kernels set and map pair. + * cmsNewHandle() - Create a handle for a new set and map pair. + * cmsNewHandleOldSetNewMap - Create new handle, cloning old set. + * cmsNewHandleNewSetOldMap - Create new handle, referencing old map. + * + * Consume a handle (or two, in the case of cmsExchange*): + * cmsAttachNewTask() - Attach a set and map to a new task. + * cmsAttachNewKern() - Attach a set and map to the kernel at boot. + * cmsDiscard() - Discard a set and map (on exit or vma delete). + * cmsExchangeTask() - Replace a tasks set and map pair with another. + * cmsExchangePid() - Replace a pid's set and map pair with another. + * cmsExchangeKern() - Replace the kernels set and map pair with another. + * cmsReleaseHandle() - Relinquish a handle no longer needed. + * + * These routines are responsible for safely managing the locks + * and reference counters used to track memory and references. + * These routines do however have specific knowledge, specified + * in comments within their source code, of what locks are + * understood to be already held by the caller. New callers of + * any of these routines must satisfy these lock preconditions. + * + * These routines can operate on the current and child sets of + * tasks, on the kernel's set, and on the sets attached to vm areas. + * They can operate on any task, as specified by a pid. The special + * case of pid == 0 refers to the current task. + * + * All uses of these routines involve a pair of calls, the first + * to cmsGetHandle*() or cmsNewHandle*(), to get a handle, and the + * second to one of the cmsAttachNew*(), cmsDiscard(), cmsExchange*() + * and cmsReleaseHandle() routines to consume the handle or handles. + * + * The routines to obtain a handle may fail and return an + * error, if they cannot obtain the requested handle. The + * routines that consume handles return nothing and always + * appear to succeed. + * + * Change operations are done in a three step process: + * + * 1) Safely obtain a handle to the current set and map, using + * the appropriate cmsGetHandle*() routine. + * 2) Compute a new set and map, using the current values as needed. + * 3) Safely exchange the current set and map for the new ones, + * using the appropriate cmsExchange*() routine, which does + * nothing but releasing the handles if the current ones + * changed during step (2), + * + * Accessing the data in a task or vm area set or map is + * done in a similar three step process: + * + * 1) Safely obtain a handle to the current set and map, using + * the cmsGetHandle*() routine. + * 2) Use the data as needed. Unless some other lock ensures it, + * there is no guarantee that the task or vm area from which + * the set and map handle was obtained will continue to use + * that same set and map during this step. + * 3) Release the handle, using the cmsRelease() routine. + * + * Other attach and discard operations are done in a two + * step process: + * + * 1) Safely obtain a handle to the current or new set and map, using + * the cmsGetHandle*() or cmsNewHandle*() routines. + * 2) Pass that handle to the appropriate cmsAttachNew*() or cmsDiscard() + * routine. + * + * New sets and maps are created by filling in the rest of (all + * but the locks and counters) the cpumemset_t and cpumemmap_t + * structures, and passing them to the cmsNewHandle*() routine, + * to obtain a handle for the set and map pair. cmsNewHandle() + * assumes that there are _no_ known references to the passed in + * set and map, and returns a handle that owns a single reference + * to them (internally, it sets their reference counts to one). + * cmsNewHandleNewSetOldMap() assumes that there are _no_ + * known references to the passed in set, so sets its reference + * counter to one, but assumes that there are other references + * to the map, so increments its counter. Caller must ensure + * that the passed in map doesn't disappear in passing, likely + * by obtaining that map reference from another handle that + * it is holding, which handle owns one reference count on the + * map. The alternative routine "cmsNewHandleOldSetNewMap()" + * has to make a copy (clone) of the old set, because once a set + * is bound to a given map, that binding cannot change. + * + * The set and map pointers passed to cmsNewHandle*() must + * point to memory from the slab allocator (cpumemset_cache and + * cpumemmap_cache), with other dynamically allocated elements of + * these structures obtained from kmalloc(), or else the kernel + * is likely to oops when these sets and maps are cmsDiscard'd + * later on. + * + * For the duration of the time that a set and map are + * referred to by such a handle, they have their reference + * counts bumped by one. That is, each handle "owns" one + * reference to the set and map it contains. The cmsAttachNew*() + * routines pass ownership of one set and map count to the new + * task, vma or kernel to which it attaches. The cmsDiscard(), + * cmsExchange*() and cmsReleaseHandle() routines all "consume" + * handles -- they decrement the reference counts of the handle + * (or for cmsExchange*(), handles) passed them, freeing the + * associated set or map if its count goes to zero. Once a + * handle is passed to one of these routines, it is no longer + * valid upon return of the routine. The cmsDiscard() routine + * actually decrements the reference counts twice, once for + * the count associated with the handle passed to it, and once + * for the count associated with the former use of that set and + * map by whatever task is exiting or vm area is being deleted. + * + * Passing a handle just returned by cmsNewHandle*() to + * cmsDiscard() doesn't make sense -- it's asking to discard + * something that is not yet attached, and internally will + * result in the reference counts going negative, likely + * causing a kernel panic or memory leak later on. + * + * When invoked on a task, cmsExchangePid() looks up the task + * by its pid again, verifies that that task is still using the + * old set and map, increments the reference counts on the new + * set and map, and swaps the old with the new, all atomically. + * It then releases both the new and old handles passed to it. + * If the swap didn't occur (pid no longer valid or task not + * using same old set or map) then the reference count on the + * new set and map is not incremented, but the subsequent release + * (decrement and possible free) still happens. Thus if a handle + * just obtained from cmsNewHandle(), which would have reference + * counts of just 1, for the handle itself, on its set and map, + * were passed to cmsExchangePid(), and the swap didn't happen + * successfully, that new handle, and the set and map it referred + * to, would be released and freed within cmsExchangePid(). + * The other cmsExchange*() routines behave similarly. + * + * There is no need to tell the requestor of a cmsExchange*() + * if the swap was successfully made, because a failed swap + * (due to task exit, vma deletion, or a parallel change) + * is indistinguishable to the caller from a successful swap + * that was nullified immediately thereafter by such an exit, + * deletion or change. + * + * Attaches occur once for the kernel at boot, twice for each + * task at fork (current and child cms), and once for each vm + * area at its creation. Discards occur on task exit (twice) + * and vma deletion. Attaches and Discards are easier because + * the referencing task or vm area is not visible to other + * processes at that moment. + * + * Attach requires a handle to a set and map that won't go away. + * Attach passes ownership of one reference count from the + * handle passed it, to the new task or vmarea or kernel to + * which the set and map are attached. + * + * Attach of a tasks current and child set and map occurs in + * the context of the parent during fork. The parent attaches + * its child cpumemset to both the childs current and child + * references. So the parent should first use cmsGetHandle*() + * before each of the two cmsAttachNew*() calls, to obtain a handle + * for each set and map pair it will attach to its new child. + * The parent cannot just access the cms or cms->cmm pointers + * in its task structure, for risk that another process might + * be changing these at the same time causing an inconsistent + * set or map for the child. + * + * cmsGetHandle*() returns both a set pointer (cpumemset_t *) + * and the map pointer (cpumemmap_t *) that was referenced by + * that set at the time of the call. Do not modify the map (cmm) + * pointer embedded in the returned set (cms). Do not trust + * nor modify the reference counts in either the set or map. + * Do not trust that either the set or map will continue to be + * used by the referencing task, vm area or kernel described + * in the cmsGetHandle*() call, nor trust that said user + * will even continue to exist, unless you have some other + * assurance of that. Do not modify the set or map pointers in + * a handle, and only obtain handles using the cmsGetHandle*() + * or cmsNewHandle*() routines. + * + * cmsGetHandle*() bumps the reference count on both the returned + * set and map and passes ownership of these two extra counts + * back to the caller. The caller hence forth can trust that the + * returned set and map will not disappear out from under it, + * and can safely perform calculations on and make copies of + * these set and map, without concern that either of them will + * be freed, reallocated and overwritten behind their back. + * The caller can also trust that the given set will continue + * to refer to the given map, not some other map. Technically, + * this means that for a given handle, set->cmm == map, always, + * and the map field in the handle is redundant. Oh well. + * + * The callers of cmsGetHandle*() are responsible for relinquishing + * ownership of the set and map returned from a successful + * cmsGetHandle*() call. This must be done by calling one of the + * cmsAttachNew*(), cmsDiscard(), cmsExchange*() and cmsReleaseHandle() + * routines to consume (aka release) the handle. + * + * The reference counter in each set (cpumemset_t) holds a total + * count of: + * user references - number of tasks, vmareas, kernels pointing to this set + * handle references - number of handles temporarily pointing to this set + * The reference counter in each map (cpumemmap_t) holds a total + * count of: + * set references - number of sets pointing to this map + * handle references - number of handles temporarily pointing to this map + */ + +typedef struct cmshandle { + cpumemset_t *set; + cpumemmap_t *map; + int error; +} cmshandle_t; + +/* + * Get a handle: + * cmsGetHandleTask() - Safely get a handle to a tasks set and map pair. + * cmsGetHandlePid() - Safely get a handle to a pid's set and map pair. + * cmsGetHandleKern() - Safely get a handle to the kernels set and map pair. + * cmsNewHandle() - Create a handle for a new set and map pair. + * cmsNewHandleOldSetNewMap - Create new handle, cloning old set. + * cmsNewHandleNewSetOldMap - Create new handle, using old map. + * These return a handle structure, with the 'error' field set + * to zero (0) on success, or -errno on failure. The set and + * map pointers are valid on success, zero (0) on error. + */ + +cmshandle_t cmsGetHandleTask (int choice, struct task_struct *p); +cmshandle_t cmsGetHandlePid (int choice, pid_t pid, int do_check_perm); +cmshandle_t cmsGetHandleKern (void); +cmshandle_t cmsNewHandle (cpumemset_t *set, cpumemmap_t *map); +cmshandle_t cmsNewHandleOldSetNewMap (cpumemset_t *oldset, cpumemmap_t *newmap); +cmshandle_t cmsNewHandleNewSetOldMap (cpumemset_t *newset, cpumemmap_t *oldmap); + +/* + * Consume a handle (or two, in the case of cmsExchange*): + * cmsAttachNewTask() - Attach a set and map to a new task. + * cmsAttachNewKern() - Attach a set and map to the kernel at boot. + * cmsDiscard() - Discard a set and map on task exit or vm area deletion. + * cmsExchangeTask() - Replace a tasks set and map pair with another. + * cmsExchangePid() - Replace a pid's set and map pair with another. + * cmsExchangeKern() - Replace the kernels set and map pair with another. + * cmsReleaseHandle() - Relinquish a handle no longer needed. + * No return, no error, but all handles deposited (dereferenced). + */ + +void cmsAttachNewTask (int choice, cmshandle_t han, struct task_struct *p); +void cmsAttachNewKern (cmshandle_t han); +void cmsDiscard (cmshandle_t han); +void cmsExchangeTask (cmshandle_t oldhan, cmshandle_t newhan, + int choice, struct task_struct *p); +void cmsExchangePid (cmshandle_t oldhan, cmshandle_t newhan, + int choice, pid_t pid); +void cmsExchangeKern (cmshandle_t oldhan, cmshandle_t newhan); +void cmsReleaseHandle (cmshandle_t han); + +#else + +#define INIT_TASK_CPUMEMSET() +#define GET_MEMS_ALLOWED(mems_allowed) ((unsigned long)-1) +#define CHECK_MEMS_ALLOWED(mems_allowed, zone) (1) +#define CMS_FREE_TASK(p) do {} while(0) +#define SET_CHILD_CMS(child, parent) do {} while(0) +#endif /* CONFIG_CPUMEMSET */ + +#endif /* _CPUMEMSET_H */ diff -Nur linux-2.4.19/include/linux/csa.h linux-2.4.19-sgi211r3/include/linux/csa.h --- linux-2.4.19/include/linux/csa.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/csa.h Thu Aug 8 09:26:58 2002 @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc and LANL All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + */ + +/* + * CSA (Comprehensive System Accounting) + * Job Accounting for Linux + * + * This header file contains the definitions needed for job + * accounting. The kernel CSA accounting module code and all + * user-level programs that try to write or process the binary job + * accounting data must include this file. + * + * + */ + +#ifndef _LINUX_CSA_H +#define _LINUX_CSA_H + +#ifndef __KERNEL__ +#include +#include +#endif + +/* + * accounting flags per-process + */ +#define AFORK 0x01 /* fork, but did not exec */ +#define ASU 0x02 /* super-user privileges */ +#define ACKPT 0x04 /* process has been checkpointed */ +#define ACORE 0x08 /* produced corefile */ +#define AXSIG 0x10 /* killed by a signal */ +#define AMORE 0x20 /* more CSA acct records for this process */ +#define AINC 0x40 /* incremental accounting record */ + +#define AHZ 100 + +/* + * Magic number - for achead.ah_magic in the 1st header. The magic number + * in the 2nd header is the inverse of this. + */ +#define ACCT_MAGIC_BIG 030510 /* big-endian */ +#define ACCT_MAGIC_LITTLE 030512 /* little-endian */ +#ifdef __LITTLE_ENDIAN +#define ACCT_MAGIC ACCT_MAGIC_LITTLE +#else +#define ACCT_MAGIC ACCT_MAGIC_BIG +#endif + +/* + * Record types - for achead.ah_type in the 1st header. + */ +#define ACCT_KERNEL_CSA 0001 /* Kernel: CSA base record */ +#define ACCT_KERNEL_MEM 0002 /* Kernel: memory record */ +#define ACCT_KERNEL_IO 0004 /* Kernel: input/output record */ +#define ACCT_KERNEL_MT 0006 /* Kernel: multi-tasking record */ +#define ACCT_KERNEL_MPP 0010 /* Kernel: multi-PE appl record */ +#define ACCT_KERNEL_SOJ 0012 /* Kernel: start-of-job record */ +#define ACCT_KERNEL_EOJ 0014 /* Kernel: end-of-job record */ +#define ACCT_KERNEL_CFG 0020 /* Kernel: configuration record */ + +#define ACCT_KERNEL_SITE0 0100 /* Kernel: reserved for site */ +#define ACCT_KERNEL_SITE1 0101 /* Kernel: reserved for site */ + +#define ACCT_DAEMON_NQS 0120 /* Daemon: NQS record */ +#define ACCT_DAEMON_WKMG 0122 /* Daemon: workload management record, + i.e., LSF */ +#define ACCT_DAEMON_TAPE 0124 /* Daemon: tape record */ +#define ACCT_DAEMON_DMIG 0126 /* Daemon: data migration record */ +#define ACCT_DAEMON_SOCKET 0130 /* Daemon: socket record */ + +#define ACCT_DAEMON_SITE0 0200 /* Daemon: reserved for site */ +#define ACCT_DAEMON_SITE1 0201 /* Daemon: reserved for site */ + +#define ACCT_JOB_HEADER 0220 /* csabuild: job header record */ +#define ACCT_CACCT 0222 /* cacct: consolidated data */ +#define ACCT_CMS 0224 /* cms: command summary data */ + +/* Record types - for achead.ah_type in the 2nd header. */ +#define ACCT_MEM 1<<0 /* Process generated memory record */ +#define ACCT_IO 1<<1 /* Process generated I/O record */ +#define ACCT_MT 1<<2 /* Process used multi-tasking */ +#define ACCT_MPP 1<<3 /* Process used multi-PE */ + +/* + * Record revision levels. + * + * These are incremented to indicate that a record's format has changed since + * a previous release. + */ +#define REV_CSA 02400 /* Kernel: CSA base record */ +#define REV_MEM 02400 /* Kernel: memory record */ +#define REV_IO 02400 /* Kernel: I/O record */ +#define REV_MT 02400 /* Kernel: multi-tasking record */ +#define REV_MPP 02400 /* Kernel: multi-PE appl record */ +#define REV_SOJ 02400 /* Kernel: start-of-job record */ +#define REV_EOJ 02400 /* Kernel: end-of-job record */ +#define REV_CFG 02400 /* Kernel: configuration record */ + +#define REV_NQS 02400 /* Daemon: NQS record */ +#define REV_WKMG 02400 /* Daemon: workload management (i.e., LSF) + record */ +#define REV_TAPE 02400 /* Daemon: tape record */ +#define REV_DMIG 02400 /* Daemon: data migration record */ +#define REV_SOCKET 02400 /* Daemon: socket record */ + +#define REV_JOB 02400 /* csabuild: job header record */ +#define REV_CACCT 02400 /* cacct: consolidated data */ +#define REV_CMS 02400 /* cms: command summary data */ + +/* + * Record header + */ +struct achead +{ + unsigned int ah_magic:17; /* Magic */ + unsigned int ah_revision:15; /* Revision */ + unsigned int ah_type:8; /* Record type */ + unsigned int ah_flag:8; /* Record flags */ + unsigned int ah_size:16; /* Size of record */ +}; + +/* + * In order to keep the accounting records the same size across different + * machine types, record fields will be defined to types that won't + * vary (i.e. uint_32_t instead of uid_t). +*/ + +/* + * Per process base accounting record. + */ +struct acctcsa +{ + struct achead ac_hdr1; /* Header */ + struct achead ac_hdr2; /* 2nd header for continued records */ + double ac_sbu; /* System billing units */ + unsigned int ac_stat:8; /* Exit status */ + unsigned int ac_nice:8; /* Nice value */ + unsigned char ac_sched; /* Scheduling discipline */ + unsigned int :8; /* Unused */ + uint32_t ac_uid; /* User ID */ + uint32_t ac_gid; /* Group ID */ + uint64_t ac_ash; /* Array session handle */ + uint64_t ac_jid; /* Job ID */ + uint64_t ac_prid; /* Project ID -> account ID */ + uint32_t ac_pid; /* Process ID */ + uint32_t ac_ppid; /* Parent process ID */ + time_t ac_btime; /* Beginning time [sec since 1970] */ + char ac_comm[16]; /* Command name */ +/* CPU resource usage information. */ + uint64_t ac_etime; /* Elapsed time [usecs] */ + uint64_t ac_utime; /* User CPU time [usec] */ + uint64_t ac_stime; /* System CPU time [usec] */ + uint64_t ac_spare; /* Spare field */ + uint64_t ac_spare1; /* Spare field */ +}; + +/* + * Memory accounting structure + * This structure is part of the acctmem record. + */ +struct memint +{ + uint64_t himem; /* Hiwater memory usage [Kbytes] */ + uint64_t mem1; /* Memory integral 1 [Mbytes/uSec] */ + uint64_t mem2; /* Memory integral 2 - not used */ + uint64_t mem3; /* Memory integral 3 - not used */ +}; + +/* + * Memory accounting record + */ +struct acctmem +{ + struct achead ac_hdr; /* Header */ + double ac_sbu; /* System billing units */ + struct memint ac_core; /* Core memory integrals */ + struct memint ac_virt; /* Virtual memory integrals */ + uint64_t ac_pgswap; /* # of pages swapped */ + uint64_t ac_minflt; /* # of minor page faults */ + uint64_t ac_majflt; /* # of major page faults */ + uint64_t ac_spare; /* Spare field */ +}; + +/* + * Input/Output accounting record + */ +struct acctio +{ + struct achead ac_hdr; /* Header */ + double ac_sbu; /* System billing units */ + uint64_t ac_bwtime; /* Block I/O wait time [usecs] */ + uint64_t ac_rwtime; /* Raw I/O wait time [usecs] */ + uint64_t ac_chr; /* Number of chars (bytes) read */ + uint64_t ac_chw; /* Number of chars (bytes) written */ + uint64_t ac_bkr; /* Number of blocks read */ + uint64_t ac_bkw; /* Number of blocks written */ + uint64_t ac_scr; /* Number of read system calls */ + uint64_t ac_scw; /* Number of write system calls */ + uint64_t ac_spare; /* Spare field */ +}; + +/* + * Multi-tasking accounting structure + * This structure is part of the acctmt record. + */ +struct mtask +{ + uint64_t mt; /* CPU+1 connect time [usecs] */ + uint64_t spare1; /* Spare field */ + uint64_t spare2; /* Spare field */ +}; + +/* + * Multi-tasking accounting record - currently not used, adapted from UNICOS. + */ +#define ACCT_MAXCPUS 512 /* Maximum number of CPUs supported */ + +struct acctmt +{ + struct achead ac_hdr; /* Header */ + double ac_sbu; /* System billing units */ + unsigned int ac_numcpu:16; /* Max number of CPUs used */ + unsigned int ac_maxcpu:16; /* Max number of CPUs available */ + unsigned int :32; /* Unused */ + int64_t ac_smwtime; /* Semaphore wait time [usec] */ + struct mtask ac_mttime[ACCT_MAXCPUS]; /* Time connected to (i+1) + CPUs [usec] */ +}; + +/* + * MPP PE accounting structure - MPP hardware specific. + * This structure is part of the acctmpp record. + */ +struct acctpe +{ + uint64_t utime; /* User CPU time [usecs] */ + uint64_t srtime; /* System & remote CPU time [usecs] */ + uint64_t io; /* Number of chars transferred */ +}; + +/* + * MPP accounting record - MPP hardware specific; currently not used. + */ +#define ACCT_MAXPES 1024 /* Maximum number of PEs */ + +struct acctmpp +{ + struct achead ac_hdr; /* Header */ + double ac_sbu; /* System billing units */ + unsigned int ac_mpbesu:8; /* Number of BESUs used */ + unsigned int ac_mppe:24; /* Number of PEs used */ + uint64_t ac_himem; /* Maximum memory hiwater [Mbytes] */ + + struct acctpe ac_mpp[ACCT_MAXPES]; /* Per PE information */ +}; + +/* + * MPP Detailed PE accounting structure - currently not used + */ +struct acctdpe +{ + struct achead ac_hdr; /* Header */ + + uint64_t utime; /* User CPU time [usecs] */ + uint64_t stime; /* System CPU time [usecs] */ + uint64_t rtime; /* Remote CPU time [usecs] */ + + uint64_t ctime; /* Connect CPU time [usecs] */ + uint64_t io; /* Number of chars transferred */ + uint64_t spare; /* Spare field */ +}; + +/* + * Start-of-job record + * Written when a job is created. + */ + +typedef enum +{ + AC_INIT_LOGIN, /* Initiated by login */ + AC_INIT_NQS, /* Initiated by NQS */ + AC_INIT_LSF, /* Initiated by LSF */ + AC_INIT_CROND, /* Initiated by crond */ + AC_INIT_FTPD, /* Initiated by ftpd */ + AC_INIT_INETD, /* Initiated by inetd */ + AC_INIT_TELNETD, /* Initiated by telnetd */ + AC_INIT_MAX +} ac_inittype; + + +#define AC_SOJ 1 /* Start-of-job record type */ +#define AC_ROJ 2 /* Restart-of-job record type */ + +struct acctsoj +{ + struct achead ac_hdr; /* Header */ + unsigned int ac_type:8; /* Record type (AC_SOJ, AC_ROJ) */ + ac_inittype ac_init:8; /* Initiator - currently not used */ + unsigned int :16; /* Unused */ + uint32_t ac_uid; /* User ID */ + uint64_t ac_jid; /* Job ID */ + time_t ac_btime; /* Start time [secs since 1970] */ + time_t ac_rstime; /* Restart time [secs since 1970] */ +}; + +/* + * End-of-job record + * Written when the last process of a job exits. + */ +struct accteoj +{ + struct achead ac_hdr1; /* Header */ + struct achead ac_hdr2; /* 2nd header for continued records */ + double ac_sbu; /* System billing units */ + ac_inittype ac_init:8; /* Initiator - currently not used */ + unsigned int ac_nice:8; /* Nice value */ + unsigned int :16; /* Unused */ + uint32_t ac_uid; /* User ID */ + uint32_t ac_gid; /* Group ID */ + uint64_t ac_ash; /* Array session handle; not used */ + uint64_t ac_jid; /* Job ID */ + uint64_t ac_prid; /* Project ID; not used */ + time_t ac_btime; /* Job start time [secs since 1970] */ + time_t ac_etime; /* Job end time [secs since 1970] */ + uint64_t ac_corehimem; /* Hiwater core mem [Kbytes] */ + uint64_t ac_virthimem; /* Hiwater virt mem [Kbytes] */ +/* CPU resource usage information. */ + uint64_t ac_utime; /* User CPU time [usec] */ + uint64_t ac_stime; /* System CPU time [usec] */ + uint32_t ac_spare; +}; + +/* + * Accounting configuration uname structure + * This structure is part of the acctcfg record. + */ +struct ac_utsname +{ + char sysname[26]; + char nodename[26]; + char release[42]; + char version[41]; + char machine[26]; +}; + +/* + * Accounting configuration record + * Written for accounting configuration changes. + */ +typedef enum +{ + AC_CONFCHG_BOOT, /* Boot time (always first) */ + AC_CONFCHG_FILE, /* Reporting pacct file change */ + AC_CONFCHG_ON, /* Reporting xxx ON */ + AC_CONFCHG_OFF, /* Reporting xxx OFF */ + AC_CONFCHG_INC_DELTA, /* Report incremental acct clock delta change */ AC_CONFCHG_INC_EVENT, /* Report incremental accounting event */ + AC_CONFCHG_MAX +} ac_eventtype; + +struct acctcfg +{ + struct achead ac_hdr; /* Header */ + unsigned int ac_kdmask; /* Kernel and daemon config mask */ + unsigned int ac_rmask; /* Record configuration mask */ + int64_t ac_uptimelen; /* Bytes from the end of the boot + record to the next boot record */ + ac_eventtype ac_event:8; /* Accounting configuration event */ + unsigned int :24; /* Unused */ + time_t ac_boottime; /* System boot time [secs since 1970]*/ + time_t ac_curtime; /* Current time [secs since 1970] */ + struct ac_utsname ac_uname; /* Condensed uname information */ +}; + + +/* + * Accounting control status values. + */ +typedef enum +{ + ACS_OFF, /* Accounting stopped for this entry */ + ACS_ERROFF, /* Accounting turned off by kernel */ + ACS_ON /* Accounting started for this entry */ +} ac_status; + +/* + * Function codes for acctctl(int, void *) system call. + */ +typedef enum +{ + AC_START, /* Start kernel, daemon, or record accounting */ + AC_STOP, /* Stop kernel, daemon, or record accounting */ + AC_HALT, /* Stop all kernel, daemon, and record accounting */ + AC_CHECK, /* Check a kernel, daemon, or record accounting state*/ + AC_KDSTAT, /* Check all kernel & daemon accounting states */ + AC_RCDSTAT, /* Check all record accounting states */ + AC_JASTART, /* Start user job accounting */ + AC_JASTOP, /* Stop user job accounting */ + AC_WRACCT, /* Write accounting record for daemon */ + AC_AUTH, /* Verify executing user is authorized */ + AC_INCACCT, /* Control incremental accounting */ + AC_MREQ +} ac_request; + +/* + * Define the acctctl(int, void *) accounting record indices. + */ +typedef enum +{ + ACCT_KERN_CSA, /* Kernel CSA accounting */ + ACCT_KERN_JOB_PROC, /* Kernel job process summary accounting */ + ACCT_KERN_ASH, /* Kernel array session summary accounting */ + ACCT_DMD_NQS, /* Daemon NQS accounting */ + ACCT_DMD_WKMG, /* Daemon workload management (i.e. LSF) acct */ + ACCT_DMD_TAPE, /* Daemon tape accounting */ + ACCT_DMD_DMIG, /* Daemon data migration accounting */ + ACCT_DMD_SOCKET, /* Daemon socket accounting */ + ACCT_DMD_SITE1, /* Site reserved daemon acct */ + ACCT_DMD_SITE2, /* Site reserved daemon acct */ + ACCT_MAXKDS, /* Max # kernel and daemon entries */ + + ACCT_RCD_MPPDET, /* Record acct for MPP detail exit info */ + ACCT_RCD_MEM, /* Record acct for memory */ + ACCT_RCD_IO, /* Record acct for input/output */ + ACCT_RCD_MT, /* Record acct for multi-tasking */ + ACCT_RCD_MPP, /* Record acct for MPP accumulated info */ + ACCT_THD_MEM, /* Record acct for memory size threshhold */ + ACCT_THD_TIME, /* Record acct for CPU time threshhold */ + ACCT_RCD_INCACCT, /* Record acct for incremental accounting */ + ACCT_RCD_APPACCT, /* Record acct for application accounting */ + ACCT_RCD_SITE1, /* Site reserved record acct */ + ACCT_RCD_SITE2, /* Site reserved record acct */ + ACCT_MAXRCDS /* Max # record entries */ +} ac_kdrcd; + +#define ACCT_RCDS ACCT_RCD_MPPDET /* Record acct low range definition */ +#define NUM_KDS (ACCT_MAXKDS - ACCT_KERN_CSA) +#define NUM_RCDS (ACCT_MAXRCDS - ACCT_RCDS) +#define NUM_KDRCDS (NUM_KDS + NUM_RCDS) + + +/* + * The following structures are used by the acctctl system call. + */ + +/* + * Accounting entry status structure + */ +struct actstat +{ + ac_kdrcd ac_ind; /* Entry index */ + ac_status ac_state; /* Entry status */ + int64_t ac_param; /* Entry parameter */ +}; + +/* + * Accounting control and status structure + */ +#define ACCT_PATH 128 /* Max path length for accounting file */ + +struct actctl +{ + int ac_sttnum; /* Number of status array entries */ + char ac_path[ACCT_PATH]; /* Path name for accounting file */ + struct actstat ac_stat[NUM_KDRCDS]; /* Entry status array */ +}; + +/* + * Function codes for incremental accounting; currently not used + */ +typedef enum +{ + IA_NONE, /* Zero entry place holder */ + IA_DELTA, /* Change clock delta for incremental accounting */ + IA_EVENT, /* Cause incremental accounting event now */ + IA_MAX +} ac_iafnc; + +/* + * Incremental accounting structure; currently not used + */ +struct actinc +{ + int ac_ind; /* Entry index */ + ac_iafnc ac_fnc; /* Entry function */ + int64_t ac_param; /* Entry parameter */ +}; + +/* + * Daemon write accounting structure + */ +#define MAX_WRACCT 1024 /* Maximum buffer size of wracct() */ + +struct actwra +{ + int ac_did; /* Daemon index */ + int ac_len; /* Length of buffer (bytes) */ + uint64_t ac_jid; /* Job ID */ + char *ac_buf; /* Daemon accounting buffer */ +}; + +#ifndef __KERNEL__ +extern int acctctl(int func, void *act); +#endif + +#endif /* _LINUX_CSA_H */ diff -Nur linux-2.4.19/include/linux/csa_internal.h linux-2.4.19-sgi211r3/include/linux/csa_internal.h --- linux-2.4.19/include/linux/csa_internal.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/csa_internal.h Thu Aug 8 09:26:58 2002 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc and LANL All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + */ + +/* + * CSA (Comprehensive System Accounting) + * Job Accounting for Linux + * + * This header file contains the definitions needed for communication + * between the kernel and the CSA module. + */ + +#ifndef _LINUX_CSA_INTERNAL_H +#define _LINUX_CSA_INTERNAL_H + +#include + +#if defined (CONFIG_CSA_JOB_ACCT) || defined (CONFIG_CSA_JOB_ACCT_MODULE) + +#include +#include + +/* + * Used by the CSA module to define the procedure callbacks into the + * CSA module. CSA module callbacks related to start-of-job and + * end-of-job accounting records are defined in the job.h header file. + * + * do_acctctl: Procedure pointer to acctctl() syscall handler + * do_csa_acct: Procedure pointer to procedure which writes a CSA + * end-of-process record when a task exits + * module: Pointer to kernel module struct. Used to + * increment/decrement the CSA module use count + */ +struct csa_module_s { + int (*do_acctctl) (int, void *); + void (*do_csa_acct) (int, struct task_struct *); + struct module *module; +}; + +static inline void csa_update_integrals(void) +{ + long delta; + + if (current->mm) { + delta = current->times.tms_stime - current->csa_stimexpd; + current->csa_stimexpd = current->times.tms_stime; + current->csa_rss_mem1 += delta * current->mm->rss; + current->csa_vm_mem1 += delta * current->mm->total_vm; + } +} + +static inline void csa_clear_integrals(struct task_struct *tsk) +{ + if (tsk) { + tsk->csa_stimexpd = 0; + tsk->csa_rss_mem1 = 0; + tsk->csa_vm_mem1 = 0; + } +} + +extern int register_csa(struct csa_module_s *); +extern void unregister_csa(void); +extern void csa_acct(int, struct task_struct *); + +#else + +#define csa_update_integrals() do { } while (0); +#define csa_clear_integrals(task) do { } while (0); +#define csa_acct(exitcode, task) do { } while (0); +#endif /* CONFIG_CSA_JOB_ACCT */ + +#endif /* _LINUX_CSA_INTERNAL_H */ diff -Nur linux-2.4.19/include/linux/dbgtk.h linux-2.4.19-sgi211r3/include/linux/dbgtk.h --- linux-2.4.19/include/linux/dbgtk.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/dbgtk.h Fri Feb 7 11:28:43 2003 @@ -0,0 +1,441 @@ +/* + * + * + * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +/* + * >>> Update these comments!!! + + + * dbgtk module - provides three methods for controlling the kind of + * debugging information collected and reported. + * + * The methods are: + * 1) DPRINTK - interface to printk that allows runtime configuration + * of which printk's actually produce output. + * >>> and a history of all + * >>> printk's which could have been issued. + * 2) DTRACE_[SL] - interface to record timestamps of when events + * occurred and provide a runtime method for retrieving and + * coalescing the trace information. + * 3) DCOUNT - interface to atomic counters which are readable + * through a runtime interface. + * + * + * DPRINTK + * This tool provides a slightly modified printk. The developer + * creates a "set" scheme. The scheme indicates a condition + * under which a specific printk should be displayed on the + * console. + * + * While the system is running, an administrator can modify the + * currently selected sets to get more or less information + * about specific events. + * + * Using this tool requires the developer to declare the tool in + * the global declaration section of their code, register it + * during startup, and unregister it at exit. Existing printk's + * can then be slightly modified and replaced with calls to + * DPRINTK. + * + * Usage: DECLARE_DPRINTK(tool_name, def_capture_sets, def_print_sets) + * NOTE: This must be in the global section of the source file. + * Where: + * tool_name: name by which this print set will be referenced. + * def_capture_sets: sets to capture by default. + * def_print_sets: sets to print by default. + * NOTE: in order for a record to print, it must be in both + * the capture and print set. + * + * + * Usage: REG_DPRINTK(tool_name); + * Where: + * tool_name: specifies a declared tool. + * + * + * Usage: DPRINTK(tool_name, set_mbr, fmt, args...) + * Where: + * tool_name: specifies a declared tool. + * set_mbr: specifies set membership for this message. + * fmt, args: as specified by printk. + * + * + * Usage: UNREG_DPRINTK(tool_name); + * Where: + * tool_name: specifies a declared tool. + * + * >>> Fix this to reflect capture and print sets. + * The runtime interface is created in the /proc filesystem. The + * /proc/dbgtk directory contains one subdir for each tool. + * Under the tools directory is a dprintk subdir which has a + * print_sets file. Reading this file will return the currently + * selected sets. Writing a value into this file will replace + * the currently selected sets with the new value. For modules, + * the default_sets specified in the DECLARE_DPRINTK macro can + * also be overridden during module load. There is an additional + * module parameter created called dbgtk_dprintk_ + * which will take effect following the REG_DPRINTK macro. + * + * + * + * + * + * + * + * + */ + + +#ifndef _LINUX_DBGTK_H +#define _LINUX_DBGTK_H + + +#include + +#if defined(CONFIG_DBGTK) || defined(CONFIG_DBGTK_MODULE) + + +#include +#include +#include +#include +#include +#ifdef CONFIG_IA64_SGI_SN +#include +#endif /* CONFIG_IA64_SGI_SN */ + + +/* + * /proc directory entry names. + */ +#define DBGTK_PROC_ROOT "dbgtk" +#define DBGTK_DPRINTK_DIR "dprintk" +#define DBGTK_DPRINTK_CONSOLE_SETS_FILE "console_sets" +#define DBGTK_DPRINTK_CAPTURE_SETS_FILE "capture_sets" +#define DBGTK_DPRINTK_BUFFER_SETS_FILE "buffer_sets" +#define DBGTK_DTRACE_DIR "dtrace" +#define DBGTK_DTRACE_TRACE_FILE "trace" +#define DBGTK_DTRACE_TRACE_MASK_FILE "trace_mask" +#define DBGTK_DCOUNT_DIR "dcount" + + + +/* + * A DTRACE record consists of eight u64 values. The first value is + * always a clock. The second is an eight character string. The + * third through eighth are all u64 values which the user supplies. + * + * The reason it was stated as _a_ clock above is SGI SN systems + * provide two very high-speed and accurate clocks. One is provided + * by the processor (the ITC or Interval Timer Clock) and is accurate + * for an individual bus. The second is the HiRes Clock. This is a + * synchronized clock for all the nodes on Numa-Link. It is not as + * precise as the ITC, but is globally synchronized. + * + * Since a u64 clock won't wrap for an incredibly long time, the top + * few bits are also being used to flag some additional information. + */ + +struct dbgtk_trace_rec_s { + u64 clock; /* either itc or rtc/jiffies */ + u64 text; /* 8 character fixed width field */ + u64 v1; /* values 1-6 */ + u64 v2; + u64 v3; + u64 v4; + u64 v5; + u64 v6; +}; +#define DBGTK_REC_SIZE sizeof(struct dbgtk_trace_rec_s) +#define DBGTK_REC_ENTRIES (DBGTK_REC_SIZE / sizeof(u64)) + +/* max records in a per-cpu buffer for a trace group */ +#define DBGTK_CPU_RECS(_g) (((_g)->trace_buf_size / DBGTK_REC_SIZE) - 1) + + +struct dbgtk_trace_head_s { + u64 head_idx; /* index to the current head of buffer */ + u64 rec_count; /* ever increasing counter of recs */ + u64 format_count; /* temp used during formatting only */ + u64 max_recs; /* #of records this buffer can hold */ + u64 fill[4]; + struct dbgtk_trace_rec_s trace_recs[0]; +}; + + +/* + * DBGTK_SHORT_REC will be ORed onto the timestamp to indicate that + * this record as two integer payload items to display. + * + * DBGTK_ITC_REC will be ORed onto the timestamp to indicate + * that this record was using the processor interval timer + * instead of the global real time counter. This is important + * to the consumer as the global real time counter remains + * synchronized across bricks in the partition. ITC is + * Front Side Bus specific and is not synchronized across an + * entire NUMA machine. + * + * DBGTK_ACTUAL_CLOCK removes the above two items from the + * clock reading to get the timestamp. + */ +#define DBGTK_SHORT_REC (1UL << 63) +#define DBGTK_ITC_REC (1UL << 62) +#define DBGTK_ACTUAL_CLOCK(_c) ((_c) & ~(DBGTK_SHORT_REC | DBGTK_ITC_REC)) + +/* + * Determine the source of the global clock. If we are on SN hardware, + * make the global clock the SHUB RTC. On other hardware, use the + * kernel's jiffies counter. + */ +#ifdef CONFIG_IA64_SGI_SN +#define DBGTK_GLOBAL_CLOCK (HUB_L(RTC_COUNTER_ADDR)) +#else +#define DBGTK_GLOBAL_CLOCK (jiffies) +#endif + + +struct dbgtk_group_s { + char proc_dir[32]; + struct proc_dir_entry *proc_base; + atomic_t base_use_count; + struct proc_dir_entry *proc_dcounter_base; + atomic_t dcounter_use_count; + struct list_head groups_list; +}; + + +struct dbgtk_dprintk_s { + unsigned long console_sets; + unsigned long capture_sets; + unsigned long buffer_sets; + char proc_dir[32]; + char set_description[256]; + struct dbgtk_group_s *group; + struct proc_dir_entry *proc_dprintk_base; + struct proc_dir_entry *proc_dprintk_console_sets; + struct proc_dir_entry *proc_dprintk_capture_sets; + struct proc_dir_entry *proc_dprintk_buffer_sets; + int num_recs; + struct list_head dprintk_list; + spinlock_t msg_lock; + struct list_head msg_hist; + struct list_head free_msgs; +}; + + +struct dbgtk_dprintk_rec_s { + struct list_head attached_list; + u64 member_of_sets; + struct timeval rec_time; + char file[40]; + char func[40]; + int line; + int pid; + char message[160]; +}; + +struct dbgtk_dtrace_s { + unsigned long trace_mask; + char proc_dir[32]; + char set_description[256]; + struct dbgtk_group_s *group; + struct proc_dir_entry *proc_dtrace_base; + struct proc_dir_entry *proc_dtrace_mask; + struct proc_dir_entry *proc_dtrace_trace; + struct list_head dtrace_list; + int trace_buf_size; + struct dbgtk_trace_head_s *cpu_trace_bufs[NR_CPUS] + ____cacheline_aligned; + struct dbgtk_trace_head_s *old_trace_bufs[NR_CPUS]; +}; + + +struct dbgtk_dcounter_s { + atomic_t counter; + char proc_dir[32]; + char proc_name[32]; + struct dbgtk_group_s *group; + struct proc_dir_entry *proc_entry; + struct list_head dcount_list; +}; + + +extern void dbgtk_dprintk_reg(struct dbgtk_dprintk_s *, void *, + unsigned long, unsigned long, unsigned long); +extern void dbgtk_dprintk_unreg(struct dbgtk_dprintk_s *); +extern void dbgtk_dprintk_record(struct dbgtk_dprintk_s *, u64, + const char *, int, const char *, + const char *, ...) + __attribute__ ((format (printf, 6, 7))); + +extern void dbgtk_dtrace_reg(struct dbgtk_dtrace_s *, void *, + unsigned long); +extern void dbgtk_dtrace_unreg(struct dbgtk_dtrace_s *); +extern void dbgtk_record_short(struct dbgtk_dtrace_s *, char *, u64, u64, + u64); +extern void dbgtk_record_long(struct dbgtk_dtrace_s *, char *, u64, u64, + u64, u64, u64, u64, u64); + +extern void dbgtk_dcounter_reg(struct dbgtk_dcounter_s *, void *); +extern void dbgtk_dcounter_unreg(struct dbgtk_dcounter_s *); + + +#define DECLARE_DPRINTK(_mn, _hl, _dcs, _dps, _sd) \ + static struct dbgtk_dprintk_s dbgtk_dprintk_##_mn = { \ + proc_dir: #_mn, \ + console_sets: _dps, \ + capture_sets: _dcs, \ + buffer_sets: _dcs, \ + set_description: _sd, \ + }; \ + static unsigned long dprintk_def_recs_##_mn = (_hl); \ +MODULE_PARM(dprintk_def_recs_##_mn, "1l"); \ +MODULE_PARM_DESC(dprintk_def_recs_##_mn, \ + "Number of history records for debug toolkit's " \ + "DPRINTK function"); \ + static unsigned long dprintk_def_csets_##_mn = (_dcs); \ +MODULE_PARM(dprintk_def_csets_##_mn, "1l"); \ +MODULE_PARM_DESC(dprintk_def_csets_##_mn, \ + "Sets to capture for debug toolkit's DPRINTK function " \ + _sd); \ + static unsigned long dprintk_def_psets_##_mn = (_dps); \ +MODULE_PARM(dprintk_def_psets_##_mn, "1l"); \ +MODULE_PARM_DESC(dprintk_def_psets_##_mn, \ + "Sets to print for debug toolkit's DPRINTK function"); \ + +#define REG_DPRINTK(_mn) \ + dbgtk_dprintk_reg(&dbgtk_dprintk_##_mn, THIS_MODULE, \ + dprintk_def_recs_##_mn, \ + dprintk_def_csets_##_mn, dprintk_def_psets_##_mn); + +#define UNREG_DPRINTK(_mn) \ + dbgtk_dprintk_unreg(&dbgtk_dprintk_##_mn); + +#define DPRINTK(_mn, mask, fmt...) \ + if (dbgtk_dprintk_##_mn.capture_sets & mask) { \ + dbgtk_dprintk_record(&(dbgtk_dprintk_##_mn), mask, \ + __FILE__, __LINE__, __FUNCTION__, fmt); \ + } +#define DPRINTK_ALWAYS(_mn, mask, fmt...) DPRINTK(_mn, mask, fmt) + + +#define DECLARE_DTRACE(_mn, _dtm, _sd) \ + static struct dbgtk_dtrace_s dbgtk_dtrace_##_mn = { \ + proc_dir: #_mn, \ + trace_mask: _dtm, \ + trace_buf_size: (PAGE_SIZE * 1), \ + set_description: _sd, \ + }; \ + static unsigned long dtrace_def_mask_##_mn = (_dtm); \ +MODULE_PARM(dtrace_def_mask_##_mn, "1l"); \ +MODULE_PARM_DESC(dtrace_def_mask_##_mn, \ + "Initial mask for debug toolkit's DTRACE function " \ + _sd); + +#define REG_DTRACE(_mn) \ + dbgtk_dtrace_reg(&dbgtk_dtrace_##_mn, THIS_MODULE, \ + dtrace_def_mask_##_mn); + +#define UNREG_DTRACE(_mn) \ + dbgtk_dtrace_unreg(&dbgtk_dtrace_##_mn); + +#define DTRACE(_mn, mask, cs, p1, p2) \ + if (dbgtk_dtrace_##_mn.trace_mask & mask) { \ + dbgtk_record_short(&dbgtk_dtrace_##_mn, cs, p1, p2, \ + DBGTK_GLOBAL_CLOCK); \ + } + +#define DTRACEI(_mn, mask, cs, p1, p2) \ + if (dbgtk_dtrace_##_mn.trace_mask & mask) {\ + dbgtk_record_short(&dbgtk_dtrace_##_mn, cs, p1, p2, \ + (DBGTK_ITC_REC | ia64_get_itc())); \ + } + +#define DTRACE_L(_mn, mask, cs, p1, p2, p3, p4, p5, p6) \ + if (dbgtk_dtrace_##_mn.trace_mask & mask) {\ + dbgtk_record_long(&dbgtk_dtrace_##_mn, cs, \ + p1, p2, p3, p4, p5, p6, DBGTK_GLOBAL_CLOCK); \ + } + +#define DTRACEI_L(_mn, mask, cs, p1, p2, p3, p4, p5, p6) \ + if (dbgtk_dtrace_##_mn.trace_mask & mask) {\ + dbgtk_record_long(&dbgtk_dtrace_##_mn, cs, \ + p1, p2, p3, p4, p5, p6, \ + (DBGTK_ITC_REC | ia64_get_itc())); \ + } + + +#define DECLARE_DCOUNTER(_pd, _cn) \ + static struct dbgtk_dcounter_s dbgtk_dcounter_##_cn = { \ + proc_dir: #_pd, \ + proc_name: #_cn, \ + }; + +#define REG_DCOUNTER(_cn) \ + dbgtk_dcounter_reg(&dbgtk_dcounter_##_cn, THIS_MODULE); + +#define UNREG_DCOUNTER(_cn) \ + dbgtk_dcounter_unreg(&dbgtk_dcounter_##_cn); + + +#define DCOUNT(_cn) atomic_inc(&dbgtk_dcounter_##_cn.counter) +#define DCOUNT_CLEAR(_cn) atomic_set(&dbgtk_dcounter_##_cn.counter, 0) + + +#else /* defined(CONFIG_DBGTK) || defined(CONFIG_DBGTK_MODULE) */ + + +#define DECLARE_DPRINTK(_mn, _hl, _dcs, _dps, _sd) +#define REG_DPRINTK(_mn) +#define UNREG_DPRINTK(_mn) +#define DPRINTK(_mn, mask, fmt...) +#define DPRINTK_ALWAYS(_mn, mask, fmt...) printk(fmt) + +#define DECLARE_DTRACE(_mn, _dtm, _sd) +#define REG_DTRACE(_mn) +#define UNREG_DTRACE(_mn) +#define DTRACE(_mn, mask, cs, p1, p2) +#define DTRACEI(_mn, mask, cs, p1, p2) +#define DTRACE_L(_mn, mask, cs, p1, p2, p3, p4, p5, p6) +#define DTRACEI_L(_mn, mask, cs, p1, p2, p3, p4, p5, p6) + +#define DECLARE_DCOUNTER(_proc_dir, _counter_name) +#define REG_DCOUNTER(_counter_name) +#define UNREG_DCOUNTER(_counter_name) +#define DCOUNT(_counter_name) +#define DCOUNT_CLEAR(_counter_name) + + +#endif /* defined(CONFIG_DBGTK) || defined(CONFIG_DBGTK_MODULE) */ + +#endif /* _LINUX_DBGTK_H */ diff -Nur linux-2.4.19/include/linux/dcache.h linux-2.4.19-sgi211r3/include/linux/dcache.h --- linux-2.4.19/include/linux/dcache.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/dcache.h Tue Dec 3 16:31:18 2002 @@ -125,6 +125,7 @@ #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ extern spinlock_t dcache_lock; +extern rwlock_t dparent_lock; /** * d_drop - drop a dentry diff -Nur linux-2.4.19/include/linux/dis-asm.h linux-2.4.19-sgi211r3/include/linux/dis-asm.h --- linux-2.4.19/include/linux/dis-asm.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/dis-asm.h Wed Jan 30 15:22:45 2002 @@ -0,0 +1,307 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +/* Hacked by Scott Lurndal at SGI (02/1999) for linux kernel debugger */ +/* Upgraded to cygnus CVS Keith Owens 30 Oct 2000 */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * Misc definitions + */ +#ifndef PARAMS +#define PARAMS(x) x +#endif +#define PTR void * +#define FILE int +#if !defined(NULL) +#define NULL 0 +#endif + +#define abort() dis_abort(__LINE__) + +static inline void +dis_abort(int line) +{ + panic("Aborting disassembler @ line %d\n", line); +} + +#include +#include +#define xstrdup(string) ({ char *res = kdb_strdup(string, GFP_ATOMIC); if (!res) BUG(); res; }) +#define xmalloc(size) ({ void *res = kmalloc(size, GFP_ATOMIC); if (!res) BUG(); res; }) +#define free(address) kfree(address) + +#include + +typedef int (*fprintf_ftype) PARAMS((PTR, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + fprintf_ftype fprintf_dummy; + PTR stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + + /* An array of pointers to symbols either at the location being disassembled + or at the start of the function being disassembled. The array is sorted + so that the first symbol is intended to be the one used. The others are + present for any misc. purposes. This is not set reliably, but if it is + not NULL, it is correct. */ + asymbol **symbols; + /* Number of symbols in array. */ + int num_symbols; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info * info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + unsigned int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Number of octets per incremented target address + Normally one, but some DSPs have byte sizes of 16 or 32 bits + */ + unsigned int octets_per_byte; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_att PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_intel PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ia64 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i370 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc11 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc12 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern disassembler_ftype arc_get_disassembler PARAMS ((int, int)); +extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i860 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_fr30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mcore PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); +extern disassembler_ftype cris_get_disassembler PARAMS ((bfd *)); +extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d30v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_vax PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic54x PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic80 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_pj PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_avr PARAMS ((bfd_vma, disassemble_info*)); + +extern void print_arm_disassembler_options PARAMS ((FILE *)); +extern void parse_arm_disassembler_option PARAMS ((char *)); +extern int get_arm_regname_num_options PARAMS ((void)); +extern int set_arm_regname_option PARAMS ((int)); +extern int get_arm_regnames PARAMS ((int, const char **, const char **, const char ***)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + +/* Document any target specific options available from the disassembler. */ +extern void disassembler_usage PARAMS ((FILE *)); + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Always true. */ +extern int generic_symbol_at_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).octets_per_byte = 1, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things separately. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (fprintf_ftype)(FPRINTF_FUNC), \ + (INFO).stream = (PTR)(STREAM), \ + (INFO).symbols = NULL, \ + (INFO).num_symbols = 0, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).insn_info_valid = 0 + +#ifdef __cplusplus +}; +#endif + +#endif /* ! defined (DIS_ASM_H) */ diff -Nur linux-2.4.19/include/linux/dnotify.h linux-2.4.19-sgi211r3/include/linux/dnotify.h --- linux-2.4.19/include/linux/dnotify.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/dnotify.h Mon Oct 28 20:43:23 2002 @@ -30,13 +30,13 @@ static inline void dnotify_parent(struct dentry *dentry, unsigned long event) { struct dentry *parent; - spin_lock(&dcache_lock); + read_lock(&dparent_lock); parent = dentry->d_parent; if (parent->d_inode->i_dnotify_mask & event) { dget(parent); - spin_unlock(&dcache_lock); + read_unlock(&dparent_lock); __inode_dir_notify(parent->d_inode, event); dput(parent); } else - spin_unlock(&dcache_lock); + read_unlock(&dparent_lock); } diff -Nur linux-2.4.19/include/linux/dqblk_v1.h linux-2.4.19-sgi211r3/include/linux/dqblk_v1.h --- linux-2.4.19/include/linux/dqblk_v1.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/dqblk_v1.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,18 @@ +/* + * File with in-memory structures of old quota format + */ + +#ifndef _LINUX_DQBLK_V1_H +#define _LINUX_DQBLK_V1_H + +/* Id of quota format */ +#define QFMT_VFS_OLD 1 + +/* Root squash turned on */ +#define V1_DQF_RSQUASH 1 + +/* Special information about quotafile */ +struct v1_mem_dqinfo { +}; + +#endif /* _LINUX_DQBLK_V1_H */ diff -Nur linux-2.4.19/include/linux/dqblk_v2.h linux-2.4.19-sgi211r3/include/linux/dqblk_v2.h --- linux-2.4.19/include/linux/dqblk_v2.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/dqblk_v2.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,20 @@ +/* + * Definitions of structures for vfsv0 quota format + */ + +#ifndef _LINUX_DQBLK_V2_H +#define _LINUX_DQBLK_V2_H + +#include + +/* id numbers of quota format */ +#define QFMT_VFS_V0 2 + +/* Inmemory copy of version specific information */ +struct v2_mem_dqinfo { + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +#endif /* _LINUX_DQBLK_V2_H */ diff -Nur linux-2.4.19/include/linux/dqblk_xfs.h linux-2.4.19-sgi211r3/include/linux/dqblk_xfs.h --- linux-2.4.19/include/linux/dqblk_xfs.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/dqblk_xfs.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + * USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _LINUX_DQBLK_XFS_H +#define _LINUX_DQBLK_XFS_H + +#include + +/* + * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM). + */ + +#define XQM_CMD(x) (('X'<<8)+(x)) /* note: forms first QCMD argument */ +#define Q_XQUOTAON XQM_CMD(0x1) /* enable accounting/enforcement */ +#define Q_XQUOTAOFF XQM_CMD(0x2) /* disable accounting/enforcement */ +#define Q_XGETQUOTA XQM_CMD(0x3) /* get disk limits and usage */ +#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits */ +#define Q_XGETQSTAT XQM_CMD(0x5) /* get quota subsystem status */ +#define Q_XQUOTARM XQM_CMD(0x6) /* free disk space used by dquots */ + +/* + * fs_disk_quota structure: + * + * This contains the current quota information regarding a user/proj/group. + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of + * 512 bytes. + */ +#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ +typedef struct fs_disk_quota { + __s8 d_version; /* version of this structure */ + __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ + __u16 d_fieldmask; /* field specifier */ + __u32 d_id; /* user, project, or group ID */ + __u64 d_blk_hardlimit;/* absolute limit on disk blks */ + __u64 d_blk_softlimit;/* preferred limit on disk blks */ + __u64 d_ino_hardlimit;/* maximum # allocated inodes */ + __u64 d_ino_softlimit;/* preferred inode limit */ + __u64 d_bcount; /* # disk blocks owned by the user */ + __u64 d_icount; /* # inodes owned by the user */ + __s32 d_itimer; /* zero if within inode limits */ + /* if not, we refuse service */ + __s32 d_btimer; /* similar to above; for disk blocks */ + __u16 d_iwarns; /* # warnings issued wrt num inodes */ + __u16 d_bwarns; /* # warnings issued wrt disk blocks */ + __s32 d_padding2; /* padding2 - for future use */ + __u64 d_rtb_hardlimit;/* absolute limit on realtime blks */ + __u64 d_rtb_softlimit;/* preferred limit on RT disk blks */ + __u64 d_rtbcount; /* # realtime blocks owned */ + __s32 d_rtbtimer; /* similar to above; for RT disk blks */ + __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ + __s16 d_padding3; /* padding3 - for future use */ + char d_padding4[8]; /* yet more padding */ +} fs_disk_quota_t; + +/* + * These fields are sent to Q_XSETQLIM to specify fields that need to change. + */ +#define FS_DQ_ISOFT (1<<0) +#define FS_DQ_IHARD (1<<1) +#define FS_DQ_BSOFT (1<<2) +#define FS_DQ_BHARD (1<<3) +#define FS_DQ_RTBSOFT (1<<4) +#define FS_DQ_RTBHARD (1<<5) +#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ + FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) +/* + * These timers can only be set in super user's dquot. For others, timers are + * automatically started and stopped. Superusers timer values set the limits + * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values + * defined below are used. + * These values also apply only to the d_fieldmask field for Q_XSETQLIM. + */ +#define FS_DQ_BTIMER (1<<6) +#define FS_DQ_ITIMER (1<<7) +#define FS_DQ_RTBTIMER (1<<8) +#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). These may be modified by the quotactl(2) + * system call with the Q_XSETQLIM command. + */ +#define DQ_FTIMELIMIT (7 * 24*60*60) /* 1 week */ +#define DQ_BTIMELIMIT (7 * 24*60*60) /* 1 week */ + +/* + * Various flags related to quotactl(2). Only relevant to XFS filesystems. + */ +#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ +#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ +#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ +#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ + +#define XFS_USER_QUOTA (1<<0) /* user quota type */ +#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ +#define XFS_GROUP_QUOTA (1<<2) /* group quota type */ + +/* + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. + * Provides a centralized way to get meta infomation about the quota subsystem. + * eg. space taken up for user and group quotas, number of dquots currently + * incore. + */ +#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ + +/* + * Some basic infomation about 'quota files'. + */ +typedef struct fs_qfilestat { + __u64 qfs_ino; /* inode number */ + __u64 qfs_nblks; /* number of BBs 512-byte-blks */ + __u32 qfs_nextents; /* number of extents */ +} fs_qfilestat_t; + +typedef struct fs_quota_stat { + __s8 qs_version; /* version number for future changes */ + __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ + __s8 qs_pad; /* unused */ + fs_qfilestat_t qs_uquota; /* user quota storage information */ + fs_qfilestat_t qs_gquota; /* group quota storage information */ + __u32 qs_incoredqs; /* number of dquots incore */ + __s32 qs_btimelimit; /* limit for blks timer */ + __s32 qs_itimelimit; /* limit for inodes timer */ + __s32 qs_rtbtimelimit;/* limit for rt blks timer */ + __u16 qs_bwarnlimit; /* limit for num warnings */ + __u16 qs_iwarnlimit; /* limit for num warnings */ +} fs_quota_stat_t; + +#endif /* _LINUX_DQBLK_XFS_H */ diff -Nur linux-2.4.19/include/linux/dump.h linux-2.4.19-sgi211r3/include/linux/dump.h --- linux-2.4.19/include/linux/dump.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/dump.h Thu Jan 16 18:45:04 2003 @@ -0,0 +1,402 @@ +/* + * Kernel header file for Linux crash dumps. + * + * Created by: Matt Robinson (yakker@sgi.com) + * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved. + * + * vmdump.h to dump.h by: Matt D. Robinson (yakker@sourceforge.net) + * Copyright 2001 - 2002 Matt D. Robinson. All rights reserved. + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved. + * + * Most of this is the same old stuff from vmdump.h, except now we're + * actually a stand-alone driver plugged into the block layer interface, + * with the exception that we now allow for compression modes externally + * loaded (e.g., someone can come up with their own). + * + * This code is released under version 2 of the GNU GPL. + */ + +/* This header file includes all structure definitions for crash dumps. */ +#ifndef _DUMP_H +#define _DUMP_H + +#include +#include +#include + +/* define TRUE and FALSE for use in our dump modules */ +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * DUMP_DEBUG: a debug level for the kernel dump code and + * the supporting lkcd libraries in user space. + * + * 0: FALSE: No Debug Added + * 1: TRUE: Break Points + * . + * . + * . + * 6: Add Debug Data to Structures + * . + * . + * 9: Max + */ +#ifndef DUMP_DEBUG +#define DUMP_DEBUG FALSE +#endif + +#if DUMP_DEBUG +void dump_bp(void); /* Called when something exceptional occurs */ +#define DUMP_BP() dump_bp() /* Breakpoint */ +#include +#else +#define DUMP_BP() +#endif + +#if defined(CONFIG_SMP) && (defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)) && (defined(CONFIG_IA64_SGI_SN1) || defined(PTCG_WAR)) +#define DUMP_IPI_FLUSH_TLB +#endif /* long expression for DUMP_IPI_FLUSH_TLB */ + +/* + * Predefine default DUMP_PAGE constants, asm header may override. + * + * On ia64 discontinuous memory systems it's possible for the memory + * banks to stop at 2**12 page alignments, the smallest possible page + * size. But the system page size, PAGE_SIZE, is in fact larger. + */ +#define DUMP_PAGE_SHIFT PAGE_SHIFT +#define DUMP_PAGE_SIZE PAGE_SIZE +#define DUMP_PAGE_MASK PAGE_MASK +#define DUMP_PAGE_ALIGN(addr) PAGE_ALIGN(addr) +#define DUMP_HEADER_OFFSET PAGE_SIZE + +/* + * Predefined default memcpy() to use when copying memory to the dump buffer. + * + * On ia64 there is a heads up function that can be called to let the prom + * machine check monitor know that the current activity is risky and it should + * ignore the fault (nofault). In this case the ia64 header will redefine this + * macro to __dump_memcpy() and use it's arch specific version. + */ +#define DUMP_memcpy memcpy + + +/* necessary header files */ +#include /* for architecture-specific header */ + +/* necessary header definitions in all cases */ +#define DUMP_KIOBUF_NUMBER 0xdeadbeef /* special number for kiobuf maps */ + +/* + * Size of the buffer that's used to hold: + * + * 1. the dump header (padded to fill the complete buffer) + * 2. the possibly compressed page headers and data + */ +#define DUMP_BUFFER_SIZE (64 * 1024) /* size of dump buffer (0x10000) */ +#define DUMP_HEADER_SIZE DUMP_BUFFER_SIZE + +/* header definitions for s390 dump */ +#define DUMP_MAGIC_S390 0xa8190173618f23fdULL /* s390 magic number */ +#define S390_DUMP_HEADER_SIZE 4096 + +/* standard header definitions */ +#define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* dump magic number */ +#define DUMP_MAGIC_LIVE 0xa8190173618f23cdULL /* live magic number */ +#define DUMP_VERSION_NUMBER 0x7 /* dump version number */ +#define DUMP_PANIC_LEN 0x100 /* dump panic string length */ + +/* dump levels - type specific stuff added later -- add as necessary */ +#define DUMP_LEVEL_NONE 0x0 /* no dumping at all -- just bail */ +#define DUMP_LEVEL_HEADER 0x1 /* kernel dump header only */ +#define DUMP_LEVEL_KERN 0x2 /* dump header and kernel pages */ +#define DUMP_LEVEL_USED 0x4 /* dump header, kernel/user pages */ +#define DUMP_LEVEL_ALL_RAM 0x8 /* dump header, all RAM pages */ +#define DUMP_LEVEL_ALL 0x10 /* dump all memory RAM and firmware */ + + +/* dump compression options -- add as necessary */ +#define DUMP_COMPRESS_NONE 0x0 /* don't compress this dump */ +#define DUMP_COMPRESS_RLE 0x1 /* use RLE compression */ +#define DUMP_COMPRESS_GZIP 0x2 /* use GZIP compression */ + +/* dump flags - any dump-type specific flags -- add as necessary */ +#define DUMP_FLAGS_NONE 0x0 /* no flags are set for this dump */ +#define DUMP_FLAGS_NONDISRUPT 0x1 /* try to keep running after dump */ + +/* dump header flags -- add as necessary */ +#define DUMP_DH_FLAGS_NONE 0x0 /* no flags set (error condition!) */ +#define DUMP_DH_RAW 0x1 /* raw page (no compression) */ +#define DUMP_DH_COMPRESSED 0x2 /* page is compressed */ +#define DUMP_DH_END 0x4 /* end marker on a full dump */ +#define DUMP_DH_TRUNCATED 0x8 /* dump is incomplete */ +#define DUMP_DH_TEST_PATTERN 0x10 /* dump page is a test pattern */ +#define DUMP_DH_NOT_USED 0x20 /* 1st bit not used in flags */ + +/* names for various dump tunables (they are now all read-only) */ +#define DUMP_ROOT_NAME "sys/dump" +#define DUMP_DEVICE_NAME "dump_device" +#define DUMP_COMPRESS_NAME "dump_compress" +#define DUMP_LEVEL_NAME "dump_level" +#define DUMP_FLAGS_NAME "dump_flags" + +/* page size for gzip compression -- buffered slightly beyond hardware PAGE_SIZE used by DUMP */ +#define DUMP_DPC_PAGE_SIZE (DUMP_PAGE_SIZE + 512) + +/* dump ioctl() control options */ +#define DIOSDUMPDEV 1 /* set the dump device */ +#define DIOGDUMPDEV 2 /* get the dump device */ +#define DIOSDUMPLEVEL 3 /* set the dump level */ +#define DIOGDUMPLEVEL 4 /* get the dump level */ +#define DIOSDUMPFLAGS 5 /* set the dump flag parameters */ +#define DIOGDUMPFLAGS 6 /* get the dump flag parameters */ +#define DIOSDUMPCOMPRESS 7 /* set the dump compress level */ +#define DIOGDUMPCOMPRESS 8 /* get the dump compress level */ +#define DIOGKERNELADDR 9 /* get the kernel load address */ +#define DIODUMPTEST 99 /* test the dump facility (panic/dump) */ + +/* the major number used for the dumping device */ +#ifndef DUMP_MAJOR +#define DUMP_MAJOR 227 +#endif + +/* + * Structure: dump_header_t + * Function: This is the header dumped at the top of every valid crash + * dump. + * easy reassembly of each crash dump page. The address bits + * are split to make things easier for 64-bit/32-bit system + * conversions. + */ +typedef struct _dump_header_s { + /* the dump magic number -- unique to verify dump is valid */ + uint64_t dh_magic_number; + + /* the version number of this dump */ + uint32_t dh_version; + + /* the size of this header (in case we can't read it) */ + uint32_t dh_header_size; + + /* the level of this dump (just a header?) */ + uint32_t dh_dump_level; + + /* + * The size of a hardware/physical memory page (DUMP_PAGE_SIZE). + * NB: Not the configurable system page (PAGE_SIZE) (4K, 8K, 16K, etc.) + */ + uint32_t dh_dump_page_size; + + /* the size of all physical memory */ + uint64_t dh_memory_size; + + /* the start of physical memory */ + uint64_t dh_memory_start; + + /* the end of physical memory */ + uint64_t dh_memory_end; + +#if DUMP_DEBUG >= 6 + /* the number of bytes in this dump specifically */ + uint64_t dh_num_bytes; +#endif + + /* the number of hardware/physical pages in this dump specifically */ + uint32_t dh_num_dump_pages; + + /* the panic string, if available */ + char dh_panic_string[DUMP_PANIC_LEN]; + + /* the time of the system crash */ + struct timeval dh_time; + + /* the NEW utsname (uname) information -- in character form */ + /* we do this so we don't have to include utsname.h */ + /* plus it helps us be more architecture independent */ + /* now maybe one day soon they'll make the [65] a #define! */ + char dh_utsname_sysname[65]; + char dh_utsname_nodename[65]; + char dh_utsname_release[65]; + char dh_utsname_version[65]; + char dh_utsname_machine[65]; + char dh_utsname_domainname[65]; + + /* the address of current task (OLD = task_struct *, NEW = void *) */ + void *dh_current_task; + + /* what type of compression we're using in this dump (if any) */ + uint32_t dh_dump_compress; + + /* any additional flags */ + uint32_t dh_dump_flags; + + /* any additional flags */ + uint32_t dh_dump_device; + +} dump_header_t; + +/* + * Structure: dump_page_t + * Function: To act as the header associated to each physical page of + * memory saved in the system crash dump. This allows for + * easy reassembly of each crash dump page. The address bits + * are split to make things easier for 64-bit/32-bit system + * conversions. + * + * dp_byte_offset and dp_page_index are landmarks that are helpful when + * looking at a hex dump of /dev/vmdump, + */ +typedef struct _dump_page_s { + +#if DUMP_DEBUG >= 6 + /* byte offset */ + uint64_t dp_byte_offset; + + /* page index */ + uint64_t dp_page_index; +#endif + /* the address of this dump page */ + uint64_t dp_address; + + /* the size of this dump page */ + uint32_t dp_size; + + /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */ + uint32_t dp_flags; +} dump_page_t; + +/* + * This structure contains information needed for the lkcdutils + * package (particularly lcrash) to determine what information is + * associated to this kernel, specifically. + */ +typedef struct lkcdinfo_s { + int arch; + int ptrsz; + int byte_order; + int linux_release; + int page_shift; + int page_size; + uint64_t page_mask; + uint64_t page_offset; + int stack_offset; +} lkcdinfo_t; + +#ifdef __KERNEL__ + +/* + * Structure: dump_compress_t + * Function: This is what an individual compression mechanism can use + * to plug in their own compression techniques. It's always + * best to build these as individual modules so that people + * can put in whatever they want. + */ +typedef struct dump_compress_s { + /* the list_head structure for list storage */ + struct list_head list; + + /* the type of compression to use (DUMP_COMPRESS_XXX) */ + int compress_type; + + /* the compression function to call */ + int (*compress_func)(char *, int, char *, int); +} dump_compress_t; + +/* functions for dump compression registration */ +extern void dump_register_compression(dump_compress_t *); +extern void dump_unregister_compression(int); + +/* + * Structure dump_mbank[]: + * + * For CONFIG_DISCONTIGMEM systems this array specifies the + * memory banks/chunks that need to be dumped after a panic. + * + * For classic systems it specifies a single set of pages from + * 0 to max_mapnr. + */ +typedef struct dump_mbank { + u64 start; + u64 end; + int type; + int pad1; + long pad2; +} dump_mbank_t; + +#define DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY 1 +#define DUMP_MBANK_TYPE_OTHER 2 + + +#define MAXCHUNKS 256 +extern int dump_mbanks; +extern dump_mbank_t dump_mbank[MAXCHUNKS]; + +extern struct notifier_block *dump_notifier_list; +extern int register_dump_notifier(struct notifier_block *); +extern int unregister_dump_notifier(struct notifier_block *); + +/* notification event codes */ +#define DUMP_BEGIN_NONDISRUPT 0x0000 /* Notify of non-disruptive dump beginning */ +#define DUMP_BEGIN 0x0001 /* Notify of distuptive dump beginning */ +#define DUMP_END 0x0002 /* Notify of dump ending */ +#define DUMP_TEST 0x0003 /* Notify Just probeing for capability callbacks */ + +extern int dump_init(void); +int dump_execute(char *, struct pt_regs *); +extern volatile int dump_in_progress; +extern volatile int dumping_cpu; +extern int (*dump_function_ptr)(char *, struct pt_regs *); +extern volatile int dump_started; + +/* + * dump notifier callbacks to tune the dump driver for + * the disk driver that will be used for the dump. They + * are used to modify the dump driver from it's default + * behavior. + * + * NOTE: To support changing the dump device between a + * non-disruptive dump and a future dump we would + * need to provide the inverse functions also. + */ +extern void dump_scheduler_enable(void); +extern void dump_interrupts_disable(void); +extern void dump_nondisruptive_disable(void); + +#if defined(CONFIG_X86) || defined(CONFIG_ALPHA) +extern int page_is_ram(unsigned long); +#endif + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +static inline void dump(char * str, struct pt_regs * regs) +{ + if (dump_function_ptr) { + dump_function_ptr((char *)str, regs); + } +} +#else +static inline void dump(char * str, struct pt_regs * regs) +{ +} +#endif /* CONFIG_DUMP */ + +/* + * Common Arch Specific Functions should be declared here. + * This allows the C compiler to detect discrepancies. + */ +extern void __dump_open(void); +extern void __dump_cleanup(void); +extern void __dump_init(uint64_t); +extern unsigned long __dump_kernel_addr(void); +extern int __dump_configure_header(struct pt_regs *); +extern unsigned int __dump_silence_system(unsigned int); +extern unsigned int __dump_resume_system(unsigned int); +#endif /* __KERNEL__ */ + +#endif /* _DUMP_H */ diff -Nur linux-2.4.19/include/linux/efi.h linux-2.4.19-sgi211r3/include/linux/efi.h --- linux-2.4.19/include/linux/efi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/efi.h Fri Feb 7 08:55:45 2003 @@ -0,0 +1,285 @@ +#ifndef _LINUX_EFI_H +#define _LINUX_EFI_H + +/* + * Extensible Firmware Interface + * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999, 2002 Hewlett-Packard Co. + * David Mosberger-Tang + * Stephane Eranian + */ +#include +#include +#include +#include +#include + +#include +#include + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR (1L | (1L << 63)) +#define EFI_INVALID_PARAMETER (2L | (1L << 63)) +#define EFI_UNSUPPORTED (3L | (1L << 63)) +#define EFI_BAD_BUFFER_SIZE (4L | (1L << 63)) +#define EFI_BUFFER_TOO_SMALL (5L | (1L << 63)) +#define EFI_NOT_FOUND (14L | (1L << 63)) + +typedef unsigned long efi_status_t; +typedef u8 efi_bool_t; +typedef u16 efi_char16_t; /* UNICODE character */ + + +typedef struct { + u8 b[16]; +} efi_guid_t; + +#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ +((efi_guid_t) \ +{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ + (b) & 0xff, ((b) >> 8) & 0xff, \ + (c) & 0xff, ((c) >> 8) & 0xff, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) + +/* + * Generic EFI table header + */ +typedef struct { + u64 signature; + u32 revision; + u32 headersize; + u32 crc32; + u32 reserved; +} efi_table_hdr_t; + +/* + * Memory map descriptor: + */ + +/* Memory types: */ +#define EFI_RESERVED_TYPE 0 +#define EFI_LOADER_CODE 1 +#define EFI_LOADER_DATA 2 +#define EFI_BOOT_SERVICES_CODE 3 +#define EFI_BOOT_SERVICES_DATA 4 +#define EFI_RUNTIME_SERVICES_CODE 5 +#define EFI_RUNTIME_SERVICES_DATA 6 +#define EFI_CONVENTIONAL_MEMORY 7 +#define EFI_UNUSABLE_MEMORY 8 +#define EFI_ACPI_RECLAIM_MEMORY 9 +#define EFI_ACPI_MEMORY_NVS 10 +#define EFI_MEMORY_MAPPED_IO 11 +#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 +#define EFI_PAL_CODE 13 +#define EFI_MAX_MEMORY_TYPE 14 + +/* Attribute values: */ +#define EFI_MEMORY_UC 0x0000000000000001 /* uncached */ +#define EFI_MEMORY_WC 0x0000000000000002 /* write-coalescing */ +#define EFI_MEMORY_WT 0x0000000000000004 /* write-through */ +#define EFI_MEMORY_WB 0x0000000000000008 /* write-back */ +#define EFI_MEMORY_WP 0x0000000000001000 /* write-protect */ +#define EFI_MEMORY_RP 0x0000000000002000 /* read-protect */ +#define EFI_MEMORY_XP 0x0000000000004000 /* execute-protect */ +#define EFI_MEMORY_RUNTIME 0x8000000000000000 /* range requires runtime mapping */ +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 + +#define EFI_PAGE_SHIFT 12 + +typedef struct { + u32 type; + u32 pad; + u64 phys_addr; + u64 virt_addr; + u64 num_pages; + u64 attribute; +} efi_memory_desc_t; + +typedef int efi_freemem_callback_t (u64 start, u64 end, void *arg); + +/* + * Types and defines for Time Services + */ +#define EFI_TIME_ADJUST_DAYLIGHT 0x1 +#define EFI_TIME_IN_DAYLIGHT 0x2 +#define EFI_UNSPECIFIED_TIMEZONE 0x07ff + +typedef struct { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 pad1; + u32 nanosecond; + s16 timezone; + u8 daylight; + u8 pad2; +} efi_time_t; + +typedef struct { + u32 resolution; + u32 accuracy; + u8 sets_to_zero; +} efi_time_cap_t; + +/* + * Types and defines for EFI ResetSystem + */ +#define EFI_RESET_COLD 0 +#define EFI_RESET_WARM 1 + +/* + * EFI Runtime Services table + */ +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552 +#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 + +typedef struct { + efi_table_hdr_t hdr; + u64 get_time; + u64 set_time; + u64 get_wakeup_time; + u64 set_wakeup_time; + u64 set_virtual_address_map; + u64 convert_pointer; + u64 get_variable; + u64 get_next_variable; + u64 set_variable; + u64 get_next_high_mono_count; + u64 reset_system; +} efi_runtime_services_t; + +typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); +typedef efi_status_t efi_set_time_t (efi_time_t *tm); +typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, + efi_time_t *tm); +typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm); +typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, + unsigned long *data_size, void *data); +typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, + efi_guid_t *vendor); +typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 attr, + unsigned long data_size, void *data); +typedef efi_status_t efi_get_next_high_mono_count_t (u64 *count); +typedef void efi_reset_system_t (int reset_type, efi_status_t status, + unsigned long data_size, efi_char16_t *data); + +/* + * EFI Configuration Table and GUID definitions + */ +#define NULL_GUID \ + EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) + +#define MPS_TABLE_GUID \ + EFI_GUID( 0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define ACPI_TABLE_GUID \ + EFI_GUID( 0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define ACPI_20_TABLE_GUID \ + EFI_GUID( 0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 ) + +#define SMBIOS_TABLE_GUID \ + EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define SAL_SYSTEM_TABLE_GUID \ + EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define HCDP_TABLE_GUID \ + EFI_GUID( 0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 ) + +typedef struct { + efi_guid_t guid; + u64 table; +} efi_config_table_t; + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00) + +typedef struct { + efi_table_hdr_t hdr; + u64 fw_vendor; /* physical addr of CHAR16 vendor string */ + u32 fw_revision; + u64 con_in_handle; + u64 con_in; + u64 con_out_handle; + u64 con_out; + u64 stderr_handle; + u64 stderr; + u64 runtime; + u64 boottime; + u64 nr_tables; + u64 tables; +} efi_system_table_t; + +/* + * All runtime access to EFI goes through this structure: + */ +extern struct efi { + efi_system_table_t *systab; /* EFI system table */ + void *mps; /* MPS table */ + void *acpi; /* ACPI table (IA64 ext 0.71) */ + void *acpi20; /* ACPI table (ACPI 2.0) */ + void *smbios; /* SM BIOS table */ + void *sal_systab; /* SAL system table */ + void *hcdp; /* HCDP table */ + void *boot_info; /* boot info table */ + efi_get_time_t *get_time; + efi_set_time_t *set_time; + efi_get_wakeup_time_t *get_wakeup_time; + efi_set_wakeup_time_t *set_wakeup_time; + efi_get_variable_t *get_variable; + efi_get_next_variable_t *get_next_variable; + efi_set_variable_t *set_variable; + efi_get_next_high_mono_count_t *get_next_high_mono_count; + efi_reset_system_t *reset_system; +} efi; + +static inline int +efi_guidcmp (efi_guid_t left, efi_guid_t right) +{ + return memcmp(&left, &right, sizeof (efi_guid_t)); +} + +static inline char * +efi_guid_unparse(efi_guid_t *guid, char *out) +{ + sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->b[3], guid->b[2], guid->b[1], guid->b[0], + guid->b[5], guid->b[4], guid->b[7], guid->b[6], + guid->b[8], guid->b[9], guid->b[10], guid->b[11], + guid->b[12], guid->b[13], guid->b[14], guid->b[15]); + return out; +} + +extern void efi_init (void); +extern void efi_map_pal_code (void); +extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); +extern void efi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg); +extern void efi_gettimeofday (struct timeval *tv); +extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ +extern u64 efi_get_iobase (void); +extern u32 efi_mem_type (unsigned long phys_addr); +extern u64 efi_mem_attributes (unsigned long phys_addr); + +/* + * Variable Attributes + */ +#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 + + +/* + * efi_dir is allocated in arch/ia64/kernel/efi.c. + */ +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry *efi_dir; +#endif + +#endif /* _LINUX_EFI_H */ diff -Nur linux-2.4.19/include/linux/ext2_fs_i.h linux-2.4.19-sgi211r3/include/linux/ext2_fs_i.h --- linux-2.4.19/include/linux/ext2_fs_i.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/ext2_fs_i.h Mon Oct 28 20:43:23 2002 @@ -35,6 +35,7 @@ __u32 i_prealloc_count; __u32 i_dir_start_lookup; int i_new_inode:1; /* Is a freshly allocated inode */ + rwlock_t i_meta_lock; }; #endif /* _LINUX_EXT2_FS_I */ diff -Nur linux-2.4.19/include/linux/frlock.h linux-2.4.19-sgi211r3/include/linux/frlock.h --- linux-2.4.19/include/linux/frlock.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/frlock.h Fri Feb 14 13:25:16 2003 @@ -0,0 +1,99 @@ +#ifndef __LINUX_FRLOCK_H +#define __LINUX_FRLOCK_H + +/* + * Fast read-write spinlocks. + * + * Fast reader/writer locks without starving writers. This type of + * lock for data where the reader wants a consitent set of information + * and is willing to retry if the information changes. Readers never + * block but they may have to retry if a writer is in + * progress. Writers do not wait for readers. + * + * Generalization on sequence variables used for gettimeofday on x86-64 + * by Andrea Arcangeli + * + * This is not as cache friendly as brlock. Also, this will not work + * for data that contains pointers, because any writer could + * invalidate a pointer that a reader was following. + * + * + * Expected reader usage: + * do { + * seq = fr_read_begin(); + * ... + * } while (seq != fr_read_end()); + * + * On non-SMP the spin locks disappear but the writer still needs + * to increment the sequence variables because an interrupt routine could + * change the state of the data. + */ + +#include +#include + +typedef struct { + spinlock_t lock; + unsigned pre_sequence; + unsigned post_sequence; +} frlock_t; + +#define FR_LOCK_UNLOCKED { SPIN_LOCK_UNLOCKED, 0, 0 } +#define frlock_init(x) do { *(x) = FR_LOCK_UNLOCKED; } while (0) + +static inline void fr_write_lock(frlock_t *rw) +{ + spin_lock(&rw->lock); + rw->pre_sequence++; + wmb(); +} + +static inline void fr_write_unlock(frlock_t *rw) +{ + wmb(); + rw->post_sequence++; + spin_unlock(&rw->lock); +} + +static inline int fr_write_trylock(frlock_t *rw) +{ + int ret = spin_trylock(&rw->lock); + + if (ret) { + ++rw->pre_sequence; + wmb(); + } + return ret; +} + +static inline unsigned fr_read_begin(frlock_t *rw) +{ + rmb(); + return rw->post_sequence; + +} + +static inline unsigned fr_read_end(frlock_t *rw) +{ + rmb(); + return rw->pre_sequence; +} + +/* + * Possible sw/hw IRQ protected versions of the interfaces. + */ +#define fr_write_lock_irqsave(lock, flags) \ +do { local_irq_save(flags); fr_write_lock(lock); } while (0) +#define fr_write_lock_irq(lock) \ +do { local_irq_disable(); fr_write_lock(lock); } while (0) +#define fr_write_lock_bh(lock) \ + do { local_bh_disable(); fr_write_lock(lock); } while (0) + +#define fr_write_unlock_irqrestore(lock, flags)\ +do { fr_write_unlock(lock); local_irq_restore(flags); } while(0) +#define fr_write_unlock_irq(lock) \ +do { fr_write_unlock(lock); local_irq_enable(); } while(0) +#define fr_write_unlock_bh(lock) \ +do { fr_write_unlock(lock); local_bh_enable(); } while(0) + +#endif /* __LINUX_FRLOCK_H */ diff -Nur linux-2.4.19/include/linux/fs.h linux-2.4.19-sgi211r3/include/linux/fs.h --- linux-2.4.19/include/linux/fs.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/fs.h Thu Dec 19 08:34:59 2002 @@ -111,6 +111,7 @@ #define MS_MOVE 8192 #define MS_REC 16384 #define MS_VERBOSE 32768 +#define MS_POSIXACL 65536 /* VFS does not apply the umask */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -161,6 +162,7 @@ #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) #define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME)) #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME) +#define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) @@ -206,6 +208,7 @@ extern void buffer_init(unsigned long); extern void inode_init(unsigned long); extern void mnt_init(unsigned long); +extern void files_init(unsigned long); /* bh state bits */ enum bh_state_bits { @@ -219,6 +222,7 @@ BH_Wait_IO, /* 1 if we should write out this buffer */ BH_Launder, /* 1 if we can throttle on this buffer */ BH_JBD, /* 1 if it has an attached journal_head */ + BH_Delay, /* 1 if the buffer is delayed allocate */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities @@ -242,7 +246,7 @@ /* First cache line: */ struct buffer_head *b_next; /* Hash queue list */ unsigned long b_blocknr; /* block number */ - unsigned short b_size; /* block size */ + unsigned int b_size; /* block size */ unsigned short b_list; /* List that this buffer appears */ kdev_t b_dev; /* device (B_FREE = free) */ @@ -282,6 +286,7 @@ #define buffer_new(bh) __buffer_state(bh,New) #define buffer_async(bh) __buffer_state(bh,Async) #define buffer_launder(bh) __buffer_state(bh,Launder) +#define buffer_delay(bh) __buffer_state(bh,Delay) #define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) @@ -335,6 +340,8 @@ #define ATTR_MTIME_SET 256 #define ATTR_FORCE 512 /* Not a change, but a change it */ #define ATTR_ATTR_FLAG 1024 +#define ATTR_KILL_SUID 2048 +#define ATTR_KILL_SGID 4096 /* * This is the Inode Attributes structure, used for notify_change(). It @@ -453,6 +460,7 @@ unsigned long i_blksize; unsigned long i_blocks; unsigned long i_version; + unsigned short i_bytes; struct semaphore i_sem; struct semaphore i_zombie; struct inode_operations *i_op; @@ -513,6 +521,39 @@ } u; }; +static inline void inode_add_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks += bytes >> 9; + bytes &= 511; + inode->i_bytes += bytes; + if (inode->i_bytes >= 512) { + inode->i_blocks++; + inode->i_bytes -= 512; + } +} + +static inline void inode_sub_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks -= bytes >> 9; + bytes &= 511; + if (inode->i_bytes < bytes) { + inode->i_blocks--; + inode->i_bytes += 512; + } + inode->i_bytes -= bytes; +} + +static inline loff_t inode_get_bytes(struct inode *inode) +{ + return (((loff_t)inode->i_blocks) << 9) + inode->i_bytes; +} + +static inline void inode_set_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks = bytes >> 9; + inode->i_bytes = bytes & 511; +} + struct fown_struct { int pid; /* pid or -pgrp where SIGIO should be sent */ uid_t uid, euid; /* uid/euid of process setting the owner */ @@ -560,6 +601,8 @@ #elif BITS_PER_LONG==64 #define MAX_LFS_FILESIZE 0x7fffffffffffffff #endif +#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ +#define BLKSETLASTSECT _IO(0x12,109) /* get last sector of block device */ #define FL_POSIX 1 #define FL_FLOCK 2 @@ -657,20 +700,6 @@ int last_type; }; -#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ -#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ - -struct quota_mount_options -{ - unsigned int flags; /* Flags for diskquotas on this device */ - struct semaphore dqio_sem; /* lock device while I/O in progress */ - struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */ - struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ - time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */ - time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */ - char rsquash[MAXQUOTAS]; /* for quotas threat root as any other user */ -}; - /* * Umount options */ @@ -718,6 +747,7 @@ struct file_system_type *s_type; struct super_operations *s_op; struct dquot_operations *dq_op; + struct quotactl_ops *s_qcop; unsigned long s_flags; unsigned long s_magic; struct dentry *s_root; @@ -732,7 +762,7 @@ struct block_device *s_bdev; struct list_head s_instances; - struct quota_mount_options s_dquot; /* Diskquota specific options */ + struct quota_info s_dquot; /* Diskquota specific options */ union { struct minix_sb_info minix_sb; @@ -864,6 +894,10 @@ int (*revalidate) (struct dentry *); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct dentry *, struct iattr *); + int (*setxattr) (struct dentry *, const char *, void *, size_t, int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); }; struct seq_file; @@ -873,6 +907,9 @@ * without the big kernel lock held in all filesystems. */ struct super_operations { + struct inode *(*alloc_inode)(struct super_block *sb); + void (*destroy_inode)(struct inode *); + void (*read_inode) (struct inode *); /* reiserfs kludge. reiserfs needs 64 bits of information to @@ -929,6 +966,7 @@ #define I_LOCK 8 #define I_FREEING 16 #define I_CLEAR 32 +#define I_NEW 64 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) @@ -948,16 +986,6 @@ __mark_inode_dirty(inode, I_DIRTY_PAGES); } -struct dquot_operations { - void (*initialize) (struct inode *, short); - void (*drop) (struct inode *); - int (*alloc_block) (struct inode *, unsigned long, char); - int (*alloc_inode) (const struct inode *, unsigned long); - void (*free_block) (struct inode *, unsigned long); - void (*free_inode) (const struct inode *, unsigned long); - int (*transfer) (struct inode *, struct iattr *); -}; - struct file_system_type { const char *name; int fs_flags; @@ -1336,32 +1364,57 @@ #define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd) #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd) +extern void inode_init_once(struct inode *); extern void iput(struct inode *); extern void force_delete(struct inode *); extern struct inode * igrab(struct inode *); extern ino_t iunique(struct super_block *, ino_t); +extern void unlock_new_inode(struct inode *); typedef int (*find_inode_t)(struct inode *, unsigned long, void *); -extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *); -static inline struct inode *iget(struct super_block *sb, unsigned long ino) + +extern struct inode * iget4_locked(struct super_block *, unsigned long, + find_inode_t, void *); + +static inline struct inode *iget4(struct super_block *sb, unsigned long ino, + find_inode_t find_actor, void *opaque) { - return iget4(sb, ino, NULL, NULL); -} + struct inode *inode = iget4_locked(sb, ino, find_actor, opaque); -extern void clear_inode(struct inode *); -extern struct inode * get_empty_inode(void); + if (inode && (inode->i_state & I_NEW)) { + /* + * reiserfs-specific kludge that is expected to go away ASAP. + */ + if (sb->s_op->read_inode2) + sb->s_op->read_inode2(inode, opaque); + else + sb->s_op->read_inode(inode); + unlock_new_inode(inode); + } -static inline struct inode * new_inode(struct super_block *sb) + return inode; +} + +static inline struct inode *iget(struct super_block *sb, unsigned long ino) { - struct inode *inode = get_empty_inode(); - if (inode) { - inode->i_sb = sb; - inode->i_dev = sb->s_dev; - inode->i_blkbits = sb->s_blocksize_bits; + struct inode *inode = iget4_locked(sb, ino, NULL, NULL); + + if (inode && (inode->i_state & I_NEW)) { + sb->s_op->read_inode(inode); + unlock_new_inode(inode); } + return inode; } -extern void remove_suid(struct inode *inode); + +static inline struct inode *iget_locked(struct super_block *sb, unsigned long ino) +{ + return iget4_locked(sb, ino, NULL, NULL); +} + +extern void clear_inode(struct inode *); +extern struct inode *new_inode(struct super_block *sb); +extern void remove_suid(struct dentry *); extern void insert_inode_hash(struct inode *); extern void remove_inode_hash(struct inode *); @@ -1434,9 +1487,11 @@ extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *); +extern ssize_t generic_file_write_nolock(struct file *, const char *, size_t, loff_t *); extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); extern loff_t no_llseek(struct file *file, loff_t offset, int origin); extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin); +extern loff_t remote_llseek(struct file *file, loff_t offset, int origin); extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *); extern int generic_file_open(struct inode * inode, struct file * filp); @@ -1620,6 +1675,15 @@ double_up(&d1->d_inode->i_sem,&d2->d_inode->i_sem); dput(d1); dput(d2); +} + +static inline ino_t parent_ino(struct dentry *dentry) +{ + ino_t res; + read_lock(&dparent_lock); + res = dentry->d_parent->d_inode->i_ino; + read_unlock(&dparent_lock); + return res; } #endif /* __KERNEL__ */ diff -Nur linux-2.4.19/include/linux/genhd.h linux-2.4.19-sgi211r3/include/linux/genhd.h --- linux-2.4.19/include/linux/genhd.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/genhd.h Wed Oct 16 14:02:58 2002 @@ -112,6 +112,8 @@ #endif /* __KERNEL__ */ +extern struct gendisk *major_gendisk[]; + #ifdef CONFIG_SOLARIS_X86_PARTITION #define SOLARIS_X86_NUMSLICE 8 diff -Nur linux-2.4.19/include/linux/highmem.h linux-2.4.19-sgi211r3/include/linux/highmem.h --- linux-2.4.19/include/linux/highmem.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/highmem.h Wed Oct 16 14:02:58 2002 @@ -46,7 +46,7 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr) { void *addr = kmap_atomic(page, KM_USER0); - clear_user_page(addr, vaddr); + clear_user_page(addr, vaddr, page); kunmap_atomic(addr, KM_USER0); } @@ -78,7 +78,7 @@ vfrom = kmap_atomic(from, KM_USER0); vto = kmap_atomic(to, KM_USER1); - copy_user_page(vto, vfrom, vaddr); + copy_user_page(vto, vfrom, vaddr, to); kunmap_atomic(vfrom, KM_USER0); kunmap_atomic(vto, KM_USER1); } diff -Nur linux-2.4.19/include/linux/iobuf.h linux-2.4.19-sgi211r3/include/linux/iobuf.h --- linux-2.4.19/include/linux/iobuf.h Thu Nov 22 11:46:26 2001 +++ linux-2.4.19-sgi211r3/include/linux/iobuf.h Fri Feb 1 11:39:38 2002 @@ -73,6 +73,8 @@ void simple_wakeup_kiobuf(struct kiobuf *); int alloc_kiovec(int nr, struct kiobuf **); void free_kiovec(int nr, struct kiobuf **); +int alloc_kiovec_sz(int nr, struct kiobuf **, int *); +void free_kiovec_sz(int nr, struct kiobuf **, int *); int expand_kiobuf(struct kiobuf *, int); void kiobuf_wait_for_io(struct kiobuf *); extern int alloc_kiobuf_bhs(struct kiobuf *); diff -Nur linux-2.4.19/include/linux/ipc.h linux-2.4.19-sgi211r3/include/linux/ipc.h --- linux-2.4.19/include/linux/ipc.h Thu Nov 22 11:46:18 2001 +++ linux-2.4.19-sgi211r3/include/linux/ipc.h Thu Aug 8 15:12:42 2002 @@ -65,6 +65,8 @@ unsigned long seq; }; +extern int ipcperms(struct kern_ipc_perm *, short); + #endif /* __KERNEL__ */ #endif /* _LINUX_IPC_H */ diff -Nur linux-2.4.19/include/linux/irq.h linux-2.4.19-sgi211r3/include/linux/irq.h --- linux-2.4.19/include/linux/irq.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/irq.h Wed Oct 16 14:02:58 2002 @@ -56,7 +56,7 @@ * * Pad this out to 32 bytes for cache and indexing reasons. */ -typedef struct { +typedef struct irq_desc { unsigned int status; /* IRQ status */ hw_irq_controller *handler; struct irqaction *action; /* IRQ action list */ @@ -64,9 +64,11 @@ spinlock_t lock; } ____cacheline_aligned irq_desc_t; -extern irq_desc_t irq_desc [NR_IRQS]; - #include /* the arch dependent stuff */ + +#ifndef NR_IVECS +#define NR_IVECS NR_IRQS +#endif extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); extern int setup_irq(unsigned int , struct irqaction * ); diff -Nur linux-2.4.19/include/linux/irq_cpustat.h linux-2.4.19-sgi211r3/include/linux/irq_cpustat.h --- linux-2.4.19/include/linux/irq_cpustat.h Thu Nov 22 11:46:18 2001 +++ linux-2.4.19-sgi211r3/include/linux/irq_cpustat.h Wed Oct 16 14:02:58 2002 @@ -23,15 +23,31 @@ #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member) #else #define __IRQ_STAT(cpu, member) ((void)(cpu), irq_stat[0].member) -#endif +#endif /* arch independent irq_stat fields */ #define softirq_pending(cpu) __IRQ_STAT((cpu), __softirq_pending) -#define local_irq_count(cpu) __IRQ_STAT((cpu), __local_irq_count) -#define local_bh_count(cpu) __IRQ_STAT((cpu), __local_bh_count) +#define irq_count(cpu) __IRQ_STAT((cpu), __local_irq_count) +#define bh_count(cpu) __IRQ_STAT((cpu), __local_bh_count) #define syscall_count(cpu) __IRQ_STAT((cpu), __syscall_count) #define ksoftirqd_task(cpu) __IRQ_STAT((cpu), __ksoftirqd_task) /* arch dependent irq_stat fields */ #define nmi_count(cpu) __IRQ_STAT((cpu), __nmi_count) /* i386, ia64 */ + +#define local_hardirq_trylock() hardirq_trylock(smp_processor_id()) +#define local_hardirq_endlock() hardirq_trylock(smp_processor_id()) +#define local_irq_enter(irq) irq_enter(smp_processor_id(), (irq)) +#define local_irq_exit(irq) irq_exit(smp_processor_id(), (irq)) +#define local_softirq_pending() softirq_pending(smp_processor_id()) +#define local_ksoftirqd_task() ksoftirqd_task(smp_processor_id()) + +/* These will lose the "really_" prefix when the interim macros below are removed. */ +#define really_local_irq_count()irq_count(smp_processor_id()) +#define really_local_bh_count() bh_count(smp_processor_id()) + +/* Interim macros for backward compatibility. They are deprecated. Use irq_count() and + bh_count() instead. --davidm 01/11/28 */ +#define local_irq_count(cpu) irq_count(cpu) +#define local_bh_count(cpu) bh_count(cpu) #endif /* __irq_cpustat_h */ diff -Nur linux-2.4.19/include/linux/job.h linux-2.4.19-sgi211r3/include/linux/job.h --- linux-2.4.19/include/linux/job.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/job.h Tue Oct 22 03:48:45 2002 @@ -0,0 +1,125 @@ +/* + * PAGG Job kernel definitions & interfaces + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + * + * Description: This file, include/linux/job.h, contains the data + * structure definitions and functions prototypes used + * by other kernel bits that communicate with the job + * module. One such example is Comprehensive System + * Accounting (CSA). + * + * Created: + * + * 2000.07.15 Sam Watters + * + * Changes: + * + * 2001.01.30 Sam Watters + * Moved file to include/linux/job.h + * + */ + +/* + * ================ + * GENERAL USE INFO + * ================ + */ + +/* + * The job start/stop events: These will identify the + * the reason the do_jobstart and do_jobend callbacks are being + * called. + */ +#define JOB_EVENT_IGNORE 0 +#define JOB_EVENT_START 1 +#define JOB_EVENT_RESTART 2 +#define JOB_EVENT_END 3 + + + +/* + * ========================================= + * INTERFACE INFO FOR ACCOUNTING SUBSCRIBERS + * ========================================= + */ + +/* To register as a job dependent accounting module */ +typedef struct job_acctmod_s { + int type; /* CSA or something else */ + int (*do_jobstart)(int event, void *data); + int (*do_jobend)(int event, void *data); + struct module *module; +} job_acctmod_t; + + +/* + * Subscriber type: Each module that registers as a accounting data + * "subscriber" has to have a type. This type will identify the + * the appropriate structs and macros to use when exchanging data. + */ +#define JOB_ACCT_CSA 0 +#define JOB_ACCT_COUNT 1 /* Number of entries available */ + +/* + * -------------- + * CSA ACCOUNTING + * -------------- + */ + + +/* + * For data exchange betwee job and csa. The embedded defines + * identify the sub-fields + */ +typedef struct job_csa_s { +#define JOB_CSA_JID 001 + uint64_t job_id; +#define JOB_CSA_UID 002 + uid_t job_uid; +#define JOB_CSA_START 004 + time_t job_start; +#define JOB_CSA_COREHIMEM 010 + uint64_t job_corehimem; +#define JOB_CSA_VIRTHIMEM 020 + uint64_t job_virthimem; +#define JOB_CSA_ACCTFILE 040 + struct file *job_acctfile; +} job_csa_t; + + + +/* + * =================== + * FUNCTION PROTOTYPES + * =================== + */ +int job_register_acct(job_acctmod_t *); +int job_unregister_acct(job_acctmod_t *); +uint64_t job_getjid(struct task_struct *); +int job_getacct(uint64_t, int, void *); +int job_setacct(uint64_t, int, int, void *); diff -Nur linux-2.4.19/include/linux/kallsyms.h linux-2.4.19-sgi211r3/include/linux/kallsyms.h --- linux-2.4.19/include/linux/kallsyms.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/kallsyms.h Tue Feb 4 15:36:30 2003 @@ -0,0 +1,169 @@ +/* kallsyms headers + Copyright 2000 Keith Owens + + This file is part of the Linux modutils. It is exported to kernel + space so debuggers can access the kallsyms data. + + The kallsyms data contains all the non-stack symbols from a kernel + or a module. The kernel symbols are held between __start___kallsyms + and __stop___kallsyms. The symbols for a module are accessed via + the struct module chain which is based at module_list. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MODUTILS_KALLSYMS_H +#define MODUTILS_KALLSYMS_H 1 + +/* Have to (re)define these ElfW entries here because external kallsyms + * code does not have access to modutils/include/obj.h. This code is + * included from user spaces tools (modutils) and kernel, they need + * different includes. + */ + +#ifndef ELFCLASS32 +#ifdef __KERNEL__ +#include +#else /* __KERNEL__ */ +#include +#endif /* __KERNEL__ */ +#endif /* ELFCLASS32 */ + +#ifndef ELFCLASSM +#define ELFCLASSM ELF_CLASS +#endif + +#ifndef ElfW +# if ELFCLASSM == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +/* Format of data in the kallsyms section. + * Most of the fields are small numbers but the total size and all + * offsets can be large so use the 32/64 bit types for these fields. + * + * Do not use sizeof() on these structures, modutils may be using extra + * fields. Instead use the size fields in the header to access the + * other bits of data. + */ + +struct kallsyms_header { + int size; /* Size of this header */ + ElfW(Word) total_size; /* Total size of kallsyms data */ + int sections; /* Number of section entries */ + ElfW(Off) section_off; /* Offset to first section entry */ + int section_size; /* Size of one section entry */ + int symbols; /* Number of symbol entries */ + ElfW(Off) symbol_off; /* Offset to first symbol entry */ + int symbol_size; /* Size of one symbol entry */ + ElfW(Off) string_off; /* Offset to first string */ + ElfW(Addr) start; /* Start address of first section */ + ElfW(Addr) end; /* End address of last section */ +}; + +struct kallsyms_section { + ElfW(Addr) start; /* Start address of section */ + ElfW(Word) size; /* Size of this section */ + ElfW(Off) name_off; /* Offset to section name */ + ElfW(Word) flags; /* Flags from section */ +}; + +struct kallsyms_symbol { + ElfW(Off) section_off; /* Offset to section that owns this symbol */ + ElfW(Addr) symbol_addr; /* Address of symbol */ + ElfW(Off) name_off; /* Offset to symbol name */ +}; + +#define KALLSYMS_SEC_NAME "__kallsyms" +#define KALLSYMS_IDX 2 /* obj_kallsyms creates kallsyms as section 2 */ + +#define kallsyms_next_sec(h,s) \ + ((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size)) +#define kallsyms_next_sym(h,s) \ + ((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size)) + +#ifdef CONFIG_KALLSYMS + +int kallsyms_symbol_to_address( + const char *name, /* Name to lookup */ + unsigned long *token, /* Which module to start with */ + const char **mod_name, /* Set to module name or "kernel" */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ); + +int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ); + +int kallsyms_sections(void *token, + int (*callback)(void *, /* token */ + const char *, /* module name */ + const char *, /* section name */ + ElfW(Addr), /* Section start */ + ElfW(Addr), /* Section end */ + ElfW(Word) /* Section flags */ + ) + ); + +#else + +static inline int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + return -ESRCH; +} + +#endif + +int kallsyms_symbol_complete( + char *prefix_name /* Prefix of a symbol name to lookup */ + ); +int kallsyms_symbol_next( + char *prefix_name, /* Prefix of a symbol name to lookup */ + int flag /* Indicate if search from the head */ + ); + +#endif /* kallsyms.h */ diff -Nur linux-2.4.19/include/linux/kdb.h linux-2.4.19-sgi211r3/include/linux/kdb.h --- linux-2.4.19/include/linux/kdb.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/kdb.h Tue Feb 4 15:36:30 2003 @@ -0,0 +1,304 @@ +#ifndef _KDB_H +#define _KDB_H + +/* + * Kernel Debugger Architecture Independent Global Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * Copyright (C) 2000 Stephane Eranian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include + +#define KDB_MAJOR_VERSION 3 +#define KDB_MINOR_VERSION 0 +#define KDB_TEST_VERSION "" + + /* + * kdb_initial_cpu is initialized to -1, and is set to the cpu + * number whenever the kernel debugger is entered. + */ +extern volatile int kdb_initial_cpu; +#ifdef CONFIG_KDB +#define KDB_IS_RUNNING() (kdb_initial_cpu != -1) +#else +#define KDB_IS_RUNNING() (0) +#endif /* CONFIG_KDB */ + + /* + * kdb_on + * + * Defines whether kdb is on or not. Default value + * is set by CONFIG_KDB_OFF. Boot with kdb=on/off + * or echo "[01]" > /proc/sys/kernel/kdb to change it. + */ +extern int kdb_on; + + /* + * kdb_serial.iobase is initialized to zero, and is set to the I/O + * address of the serial port when the console is setup in + * serial_console_setup. + */ +extern struct kdb_serial { + int io_type; + unsigned long iobase; + unsigned long ioreg_shift; +} kdb_serial; + + /* + * kdb_diemsg + * + * Contains a pointer to the last string supplied to the + * kernel 'die' panic function. + */ +extern const char *kdb_diemsg; + + /* + * KDB_FLAG_EARLYKDB is set when the 'kdb' option is specified + * as a boot parameter (e.g. via lilo). It indicates that the + * kernel debugger should be entered as soon as practical. + */ +#define KDB_FLAG_EARLYKDB 0x00000001 + + /* + * Internal debug flags + */ +#define KDB_DEBUG_FLAG_BT 0x0001 /* Stack traceback debug */ +#define KDB_DEBUG_FLAG_BP 0x0002 /* Breakpoint subsystem debug */ +#define KDB_DEBUG_FLAG_LBR 0x0004 /* Print last branch register */ +#define KDB_DEBUG_FLAG_AR 0x0008 /* Activation record, generic */ +#define KDB_DEBUG_FLAG_ARA 0x0010 /* Activation record, arch specific */ +/* KDB_DEBUG_FLAG_CALLBACK 0x0020 WAS Event callbacks to kdb */ +#define KDB_DEBUG_FLAG_STATE 0x0040 /* State flags */ +#define KDB_DEBUG_FLAG_MASK 0xffff /* All debug flags */ +#define KDB_DEBUG_FLAG_SHIFT 16 /* Shift factor for dbflags */ + +extern volatile int kdb_flags; /* Global flags, see kdb_state for per cpu state */ + +#define KDB_FLAG(flag) (kdb_flags & KDB_FLAG_##flag) +#define KDB_FLAG_SET(flag) ((void)(kdb_flags |= KDB_FLAG_##flag)) +#define KDB_FLAG_CLEAR(flag) ((void)(kdb_flags &= ~KDB_FLAG_##flag)) +#define KDB_DEBUG(flag) (kdb_flags & (KDB_DEBUG_FLAG_##flag << KDB_DEBUG_FLAG_SHIFT)) +#define KDB_DEBUG_STATE(text,value) if (KDB_DEBUG(STATE)) kdb_print_state(text, value) + + /* + * Per cpu kdb state. A cpu can be under kdb control but outside kdb, + * for example when doing single step. + */ +volatile extern int kdb_state[ /*NR_CPUS*/ ]; +#define KDB_STATE_KDB 0x00000001 /* Cpu is inside kdb */ +#define KDB_STATE_LEAVING 0x00000002 /* Cpu is leaving kdb */ +#define KDB_STATE_CMD 0x00000004 /* Running a kdb command */ +#define KDB_STATE_KDB_CONTROL 0x00000008 /* This cpu is under kdb control */ +#define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */ +#define KDB_STATE_DOING_SS 0x00000020 /* Doing ss command */ +#define KDB_STATE_DOING_SSB 0x00000040 /* Doing ssb command, DOING_SS is also set */ +#define KDB_STATE_SSBPT 0x00000080 /* Install breakpoint after one ss, independent of DOING_SS */ +#define KDB_STATE_REENTRY 0x00000100 /* Valid re-entry into kdb */ +#define KDB_STATE_SUPPRESS 0x00000200 /* Suppress error messages */ +#define KDB_STATE_LONGJMP 0x00000400 /* longjmp() data is available */ +#define KDB_STATE_GO_SWITCH 0x00000800 /* go is switching back to initial cpu */ +#define KDB_STATE_PRINTF_LOCK 0x00001000 /* Holds kdb_printf lock */ +#define KDB_STATE_WAIT_IPI 0x00002000 /* Waiting for kdb_ipi() NMI */ +#define KDB_STATE_RECURSE 0x00004000 /* Recursive entry to kdb */ +#define KDB_STATE_IP_ADJUSTED 0x00008000 /* Restart IP has been adjusted */ +#define KDB_STATE_GO1 0x00010000 /* go only releases one cpu */ +#define KDB_STATE_ARCH 0xff000000 /* Reserved for arch specific use */ + +#define KDB_STATE_CPU(flag,cpu) (kdb_state[cpu] & KDB_STATE_##flag) +#define KDB_STATE_SET_CPU(flag,cpu) ((void)(kdb_state[cpu] |= KDB_STATE_##flag)) +#define KDB_STATE_CLEAR_CPU(flag,cpu) ((void)(kdb_state[cpu] &= ~KDB_STATE_##flag)) + +#define KDB_STATE(flag) KDB_STATE_CPU(flag,smp_processor_id()) +#define KDB_STATE_SET(flag) KDB_STATE_SET_CPU(flag,smp_processor_id()) +#define KDB_STATE_CLEAR(flag) KDB_STATE_CLEAR_CPU(flag,smp_processor_id()) + + /* + * External entry point for the kernel debugger. The pt_regs + * at the time of entry are supplied along with the reason for + * entry to the kernel debugger. + */ + +typedef enum { + KDB_REASON_CALL = 1, /* Call kdb() directly - regs should be valid */ + KDB_REASON_FAULT, /* Kernel fault - regs valid */ + KDB_REASON_BREAK, /* Breakpoint inst. - regs valid */ + KDB_REASON_DEBUG, /* Debug Fault - regs valid */ + KDB_REASON_OOPS, /* Kernel Oops - regs valid */ + KDB_REASON_SWITCH, /* CPU switch - regs valid*/ + KDB_REASON_ENTER, /* KDB_ENTER() trap/fault - regs valid */ + KDB_REASON_KEYBOARD, /* Keyboard entry - regs valid */ + KDB_REASON_NMI, /* Non-maskable interrupt; regs valid */ + KDB_REASON_WATCHDOG, /* Watchdog interrupt; regs valid */ + KDB_REASON_RECURSE, /* Recursive entry to kdb; regs probably valid */ + KDB_REASON_SILENT, /* Silent entry/exit to kdb; regs invalid */ +} kdb_reason_t; + +typedef enum { + KDB_REPEAT_NONE = 0, /* Do not repeat this command */ + KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */ + KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */ +} kdb_repeat_t; + +#ifdef CONFIG_KDB +extern int kdb(kdb_reason_t, int, struct pt_regs *); +#else +#define kdb(reason,error_code,frame) (0) +#endif + +typedef int (*kdb_func_t)(int, const char **, const char **, struct pt_regs *); + + /* + * Symbol table format returned by kallsyms. + */ + +typedef struct __ksymtab { + unsigned long value; /* Address of symbol */ + const char *mod_name; /* Module containing symbol or "kernel" */ + unsigned long mod_start; + unsigned long mod_end; + const char *sec_name; /* Section containing symbol */ + unsigned long sec_start; + unsigned long sec_end; + const char *sym_name; /* Full symbol name, including any version */ + unsigned long sym_start; + unsigned long sym_end; + } kdb_symtab_t; + + /* + * Exported Symbols for kernel loadable modules to use. + */ +extern int kdb_register(char *, kdb_func_t, char *, char *, short); +extern int kdb_register_repeat(char *, kdb_func_t, char *, char *, short, kdb_repeat_t); +extern int kdb_unregister(char *); + +extern int kdb_getarea_size(void *, unsigned long, size_t); +extern int kdb_putarea_size(unsigned long, void *, size_t); + +/* Like get_user and put_user, kdb_getarea and kdb_putarea take variable + * names, not pointers. The underlying *_size functions take pointers. + */ +#define kdb_getarea(x,addr) kdb_getarea_size(&(x), addr, sizeof((x))) +#define kdb_putarea(addr,x) kdb_putarea_size(addr, &(x), sizeof((x))) + +extern int kdb_getword(unsigned long *, unsigned long, size_t); +extern int kdb_putword(unsigned long, unsigned long, size_t); + +extern int kdbgetularg(const char *, unsigned long *); +extern char *kdbgetenv(const char *); +extern int kdbgetintenv(const char *, int *); +extern int kdbgetaddrarg(int, const char**, int*, unsigned long *, + long *, char **, struct pt_regs *); +extern int kdbgetsymval(const char *, kdb_symtab_t *); +extern int kdbnearsym(unsigned long, kdb_symtab_t *); +extern void kdb_printf(const char *,...) + __attribute__ ((format (printf, 1, 2))); +extern void kdb_init(void); +extern void kdb_symbol_print(kdb_machreg_t, const kdb_symtab_t *, unsigned int); +extern char *kdb_read(char *buffer, size_t bufsize); +extern char *kdb_strdup(const char *str, int type); + +#if defined(CONFIG_SMP) + /* + * Kernel debugger non-maskable IPI handler. + */ +extern int kdb_ipi(struct pt_regs *, void (*ack_interrupt)(void)); +extern void smp_kdb_stop(void); +#else /* CONFIG_SMP */ +#define smp_kdb_stop() +#endif /* CONFIG_SMP */ + + /* + * Interface from general kernel to enable any hardware + * error reporting mechanisms. Such as the Intel Machine + * Check Architecture, for example. + */ +extern void kdb_enablehwfault(void); + + /* + * Let other code know that kdb is in control. Routines registered + * on this list are called from the initial cpu with 1 when kdb is + * entered and 0 when kdb exits. + * + * WARNING: If a module registers itself on this list (or any notifier + * list) then there is a race condition. The module could be in the + * middle of removal on one cpu when it is called via the notifier + * chain on another cpu. It is the responsibility of the module to + * prevent this race. The safest way is for the module to define a + * 'can_unload' function which unregisters the module from all + * notifier chains before allowing the module to be unloaded. + */ + +extern struct notifier_block *kdb_notifier_list; + + /* + * Do we have a set of registers? + */ + +#define KDB_NULL_REGS(regs) \ + (regs == (struct pt_regs *)NULL ? kdb_printf("%s: null regs - should never happen\n", __FUNCTION__), 1 : 0) + + /* + * Routine for debugging the debugger state. + */ + +extern void kdb_print_state(const char *, int); + +#ifdef CONFIG_KDB_USB +#include +#define KDB_USB_ACTIVE 1 /* Keyboard driver is usbkbd */ +#define HID_ACTIVE 2 /* Keyboard driver is hid */ + +struct kdb_usb_exchange { + void *uhci; /* pointer to the UHCI structure */ + struct urb *urb; /* pointer to the URB */ + unsigned char *buffer; /* pointer to buffer */ + void (*poll_func)(void *, struct urb *); /* pointer to the polling function */ + void (*reset_timer)(void); /* pointer to the reset timer function */ + int driver; /* driver mode, see above KDB_USB_KBD */ +}; +extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */ +#endif /* CONFIG_KDB_USB */ + +#ifdef MODULE +#define kdb_module_init(fn) module_init(fn) +#define kdb_module_exit(fn) module_exit(fn) +#else /* !MODULE */ +extern initcall_t __kdb_initcall_start, __kdb_initcall_end; +#define kdb_module_init(fn) \ + static initcall_t __kdb_initcall_##fn __attribute__ ((unused,__section__ (".kdb_initcall.init"))) = fn; +#define kdb_module_exit(fn) \ + static exitcall_t __kdb_exitcall_##fn __attribute__ ((unused,__section__ (".kdb_exitcall.exit"))) = fn; +#endif /* MODULE */ + +#endif /* !_KDB_H */ diff -Nur linux-2.4.19/include/linux/kdbprivate.h linux-2.4.19-sgi211r3/include/linux/kdbprivate.h --- linux-2.4.19/include/linux/kdbprivate.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/kdbprivate.h Tue Feb 4 15:36:30 2003 @@ -0,0 +1,333 @@ +#ifndef _KDBPRIVATE_H +#define _KDBPRIVATE_H + +/* + * Kernel Debugger Architecture Independent Private Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include + +#include "bfd.h" + +/* + * Kernel Debugger Error codes. Must not overlap with command codes. + */ + +#define KDB_NOTFOUND (-1) +#define KDB_ARGCOUNT (-2) +#define KDB_BADWIDTH (-3) +#define KDB_BADRADIX (-4) +#define KDB_NOTENV (-5) +#define KDB_NOENVVALUE (-6) +#define KDB_NOTIMP (-7) +#define KDB_ENVFULL (-8) +#define KDB_ENVBUFFULL (-9 ) +#define KDB_TOOMANYBPT (-10) +#define KDB_TOOMANYDBREGS (-11) +#define KDB_DUPBPT (-12) +#define KDB_BPTNOTFOUND (-13) +#define KDB_BADMODE (-14) +#define KDB_BADINT (-15) +#define KDB_INVADDRFMT (-16) +#define KDB_BADREG (-17) +#define KDB_BADCPUNUM (-18) +#define KDB_BADLENGTH (-19) +#define KDB_NOBP (-20) +#define KDB_BADADDR (-21) + +/* + * Kernel Debugger Command codes. Must not overlap with error codes. + */ +#define KDB_CMD_GO (-1001) +#define KDB_CMD_CPU (-1002) +#define KDB_CMD_SS (-1003) +#define KDB_CMD_SSB (-1004) + + /* + * kdb_nextline + * + * Contains the current line number on the screen. Used + * to handle the built-in pager (LINES env variable) + */ +extern volatile int kdb_nextline; + + /* + * Breakpoint state + * + * Each active and inactive breakpoint is represented by + * an instance of the following data structure. + */ + +typedef struct _kdb_bp { + bfd_vma bp_addr; /* Address breakpoint is present at */ + kdb_machinst_t bp_inst; /* Replaced instruction */ + + unsigned int bp_free:1; /* This entry is available */ + + unsigned int bp_enabled:1; /* Breakpoint is active in register */ + unsigned int bp_global:1; /* Global to all processors */ + + unsigned int bp_hardtype:1; /* Uses hardware register */ + unsigned int bp_forcehw:1; /* Force hardware register */ + unsigned int bp_installed:1; /* Breakpoint is installed */ + unsigned int bp_delay:1; /* Do delayed bp handling */ + unsigned int bp_delayed:1; /* Delayed breakpoint */ + + int bp_cpu; /* Cpu # (if bp_global == 0) */ + kdbhard_bp_t bp_template; /* Hardware breakpoint template */ + kdbhard_bp_t *bp_hard; /* Hardware breakpoint structure */ + int bp_adjust; /* Adjustment to PC for real instruction */ +} kdb_bp_t; + + /* + * Breakpoint handling subsystem global variables + */ +extern kdb_bp_t kdb_breakpoints[/* KDB_MAXBPT */]; + + /* + * Breakpoint architecture dependent functions. Must be provided + * in some form for all architectures. + */ +extern void kdba_initbp(void); +extern void kdba_printbp(kdb_bp_t *); +extern void kdba_printbpreg(kdbhard_bp_t *); +extern kdbhard_bp_t *kdba_allocbp(kdbhard_bp_t *, int *); +extern void kdba_freebp(kdbhard_bp_t *); +extern int kdba_parsebp(int, const char**, int *, kdb_bp_t*); +extern char *kdba_bptype(kdbhard_bp_t *); +extern void kdba_setsinglestep(struct pt_regs *); +extern void kdba_clearsinglestep(struct pt_regs *); + + /* + * Adjust instruction pointer architecture dependent function. Must be + * provided in some form for all architectures. + */ +extern void kdba_adjust_ip(kdb_reason_t, int, struct pt_regs *); + + /* + * KDB-only global function prototypes. + */ +extern void kdb_id1(unsigned long); +extern void kdb_id_init(void); + + /* + * Architecture dependent function to enable any + * processor machine check exception handling modes. + */ +extern void kdba_enable_mce(void); + +extern void kdba_enable_lbr(void); +extern void kdba_disable_lbr(void); +extern void kdba_print_lbr(void); + + /* + * Initialization functions. + */ +extern void kdba_init(void); +extern void kdb_io_init(void); + + /* + * Architecture specific function to read a string. + */ +typedef int (*get_char_func)(void); +extern get_char_func poll_funcs[]; + + /* + * Data for a single activation record on stack. + */ + +typedef struct __kdb_activation_record { + kdb_machreg_t start; /* -> start of activation record */ + kdb_machreg_t end; /* -> end+1 of activation record */ + kdb_machreg_t ret; /* Return address to caller */ + kdb_machreg_t oldfp; /* Frame pointer for caller's frame */ + kdb_machreg_t fp; /* Frame pointer for callee's frame */ + kdb_machreg_t arg0; /* -> First argument on stack (in previous ar) */ + unsigned long locals; /* Bytes allocated for local variables */ + unsigned long regs; /* Bytes allocated for saved registers */ + unsigned long args; /* Bytes allocated for arguments (in previous ar) */ + unsigned long setup; /* Bytes allocated for setup data */ +} kdb_ar_t; + + /* + * General Stack Traceback functions. + */ + +extern int kdb_get_next_ar(kdb_machreg_t, kdb_machreg_t, + kdb_machreg_t, kdb_machreg_t, + kdb_machreg_t, + kdb_ar_t *, kdb_symtab_t *); + + /* + * Architecture specific Stack Traceback functions. + */ + +struct task_struct; + +extern int kdba_bt_stack(struct pt_regs *, kdb_machreg_t *, + int, struct task_struct *); +extern int kdba_bt_process(struct task_struct *, int); +extern int kdba_prologue(const kdb_symtab_t *, kdb_machreg_t, + kdb_machreg_t, kdb_machreg_t, kdb_machreg_t, + int, kdb_ar_t *); + /* + * KDB Command Table + */ + +typedef struct _kdbtab { + char *cmd_name; /* Command name */ + kdb_func_t cmd_func; /* Function to execute command */ + char *cmd_usage; /* Usage String for this command */ + char *cmd_help; /* Help message for this command */ + short cmd_flags; /* Parsing flags */ + short cmd_minlen; /* Minimum legal # command chars required */ + kdb_repeat_t cmd_repeat; /* Does command auto repeat on enter? */ +} kdbtab_t; + + /* + * External command function declarations + */ + +extern int kdb_id(int, const char **, const char **, struct pt_regs *); +extern int kdb_bp(int, const char **, const char **, struct pt_regs *); +extern int kdb_bc(int, const char **, const char **, struct pt_regs *); +extern int kdb_bt(int, const char **, const char **, struct pt_regs *); +extern int kdb_ss(int, const char **, const char **, struct pt_regs *); + + /* + * External utility function declarations + */ +extern char* kdb_getstr(char *, size_t, char *); + + /* + * Register contents manipulation + */ +extern int kdba_getregcontents(const char *, struct pt_regs *, kdb_machreg_t *); +extern int kdba_setregcontents(const char *, struct pt_regs *, kdb_machreg_t); +extern int kdba_dumpregs(struct pt_regs *, const char *, const char *); +extern int kdba_setpc(struct pt_regs *, kdb_machreg_t); +extern kdb_machreg_t kdba_getpc(struct pt_regs *); + + /* + * Debug register handling. + */ +extern void kdba_installdbreg(kdb_bp_t*); +extern void kdba_removedbreg(kdb_bp_t*); + + /* + * Breakpoint handling - External interfaces + */ +extern void kdb_initbptab(void); +extern void kdb_bp_install_global(struct pt_regs *); +extern void kdb_bp_install_local(struct pt_regs *); +extern void kdb_bp_remove_global(void); +extern void kdb_bp_remove_local(void); + + /* + * Breakpoint handling - Internal to kdb_bp.c/kdba_bp.c + */ +extern int kdba_installbp(struct pt_regs *regs, kdb_bp_t *); +extern int kdba_removebp(kdb_bp_t *); + + +typedef enum { + KDB_DB_BPT, /* Breakpoint */ + KDB_DB_SS, /* Single-step trap */ + KDB_DB_SSB, /* Single step to branch */ + KDB_DB_SSBPT, /* Single step over breakpoint */ + KDB_DB_NOBPT /* Spurious breakpoint */ +} kdb_dbtrap_t; + +extern kdb_dbtrap_t kdba_db_trap(struct pt_regs *, int); /* DEBUG trap/fault handler */ +extern kdb_dbtrap_t kdba_bp_trap(struct pt_regs *, int); /* Breakpoint trap/fault hdlr */ + + /* + * Interrupt Handling + */ +typedef int kdb_intstate_t; + +extern void kdba_disableint(kdb_intstate_t *); +extern void kdba_restoreint(kdb_intstate_t *); + + /* + * SMP and process stack manipulation routines. + */ +extern int kdba_ipi(struct pt_regs *, void (*)(void)); +extern int kdba_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, struct pt_regs *); +extern int kdb_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, struct pt_regs *); + + /* + * General Disassembler interfaces + */ +extern int kdb_dis_fprintf(PTR, const char *, ...) __attribute__ ((format (printf, 2, 3))); +extern int kdb_dis_fprintf_dummy(PTR, const char *, ...) __attribute__ ((format (printf, 2, 3))); +extern disassemble_info kdb_di; + + /* + * Architecture Dependent Disassembler interfaces + */ +extern void kdba_printaddress(kdb_machreg_t, disassemble_info *, int); +extern int kdba_id_printinsn(kdb_machreg_t, disassemble_info *); +extern int kdba_id_parsemode(const char *, disassemble_info*); +extern void kdba_id_init(disassemble_info *); +extern void kdba_check_pc(kdb_machreg_t *); + + /* + * Miscellaneous functions and data areas + */ +extern char *kdb_cmds[]; +extern void kdb_syslog_data(char *syslog_data[]); +extern unsigned long kdb_task_state_string(int argc, const char **argv, const char **envp); +extern unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask); +extern void kdb_ps1(struct task_struct *p); +extern int kdb_parse(const char *cmdstr, struct pt_regs *regs); + + /* + * Architecture Dependant Local Processor setup & cleanup interfaces + */ +extern void kdba_local_arch_setup(void); +extern void kdba_local_arch_cleanup(void); + + /* + * Defines for kdb_symbol_print. + */ +#define KDB_SP_SPACEB 0x0001 /* Space before string */ +#define KDB_SP_SPACEA 0x0002 /* Space after string */ +#define KDB_SP_PAREN 0x0004 /* Parenthesis around string */ +#define KDB_SP_VALUE 0x0008 /* Print the value of the address */ +#define KDB_SP_SYMSIZE 0x0010 /* Print the size of the symbol */ +#define KDB_SP_NEWLINE 0x0020 /* Newline after string */ +#define KDB_SP_DEFAULT (KDB_SP_VALUE|KDB_SP_PAREN) + +#endif /* !_KDBPRIVATE_H */ diff -Nur linux-2.4.19/include/linux/kernel.h linux-2.4.19-sgi211r3/include/linux/kernel.h --- linux-2.4.19/include/linux/kernel.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/kernel.h Tue Nov 26 20:21:42 2002 @@ -107,6 +107,8 @@ extern int tainted; extern const char *print_tainted(void); +extern void dump_stack(void); + #if DEBUG #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg) diff -Nur linux-2.4.19/include/linux/kernel_stat.h linux-2.4.19-sgi211r3/include/linux/kernel_stat.h --- linux-2.4.19/include/linux/kernel_stat.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/kernel_stat.h Mon Oct 28 20:43:23 2002 @@ -2,7 +2,7 @@ #define _LINUX_KERNEL_STAT_H #include -#include +#include #include #include @@ -27,12 +27,13 @@ unsigned int pgpgin, pgpgout; unsigned int pswpin, pswpout; #if !defined(CONFIG_ARCH_S390) - unsigned int irqs[NR_CPUS][NR_IRQS]; + unsigned int irqs[NR_CPUS][NR_IVECS]; #endif - unsigned int context_swtch; }; extern struct kernel_stat kstat; + +extern unsigned long nr_context_switches(void); #if !defined(CONFIG_ARCH_S390) /* diff -Nur linux-2.4.19/include/linux/libsgi/arch.h linux-2.4.19-sgi211r3/include/linux/libsgi/arch.h --- linux-2.4.19/include/linux/libsgi/arch.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/arch.h Sun May 26 21:57:45 2002 @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_ARCH_H__ +#define __LIBSGI_ARCH_H__ + +#ifdef __KERNEL__ + +#include + +#ifdef __LITTLE_ENDIAN +# define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#ifdef __BIG_ENDIAN +# define __BYTE_ORDER __BIG_ENDIAN +#endif + +#endif /* __KERNEL__ */ + +/* do we need conversion? */ + +#define ARCH_NOCONVERT 1 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ARCH_CONVERT 0 +#else +#define ARCH_CONVERT ARCH_NOCONVERT +#endif + +/* generic swapping macros */ + +#define INT_SWAP16(type,var) ((typeof(type))(__swab16((__u16)(var)))) +#define INT_SWAP32(type,var) ((typeof(type))(__swab32((__u32)(var)))) +#define INT_SWAP64(type,var) ((typeof(type))(__swab64((__u64)(var)))) + +#define INT_SWAP(type, var) \ + ((sizeof(type) == 8) ? INT_SWAP64(type,var) : \ + ((sizeof(type) == 4) ? INT_SWAP32(type,var) : \ + ((sizeof(type) == 2) ? INT_SWAP16(type,var) : \ + (var)))) + +#define INT_SWAP_UNALIGNED_32(from,to) \ + { \ + ((__u8*)(to))[0] = ((__u8*)(from))[3]; \ + ((__u8*)(to))[1] = ((__u8*)(from))[2]; \ + ((__u8*)(to))[2] = ((__u8*)(from))[1]; \ + ((__u8*)(to))[3] = ((__u8*)(from))[0]; \ + } + +#define INT_SWAP_UNALIGNED_64(from,to) \ + { \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)) + 4, ((__u8*)(to))); \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)), ((__u8*)(to)) + 4); \ + } + +/* + * get and set integers from potentially unaligned locations + */ + +#define INT_GET_UNALIGNED_16_LE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ))) +#define INT_GET_UNALIGNED_16_BE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] << 8) | (((__u8*)(pointer))[1]))) +#define INT_SET_UNALIGNED_16_LE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) ) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) >> 8) & 0xff); \ + } +#define INT_SET_UNALIGNED_16_BE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) >> 8) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) ) & 0xff); \ + } + +#define INT_GET_UNALIGNED_32_LE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ) \ + |(((__u8*)(pointer))[2] << 16) | (((__u8*)(pointer))[3] << 24))) +#define INT_GET_UNALIGNED_32_BE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] << 24) | (((__u8*)(pointer))[1] << 16) \ + |(((__u8*)(pointer))[2] << 8) | (((__u8*)(pointer))[3] ))) + +#define INT_GET_UNALIGNED_64_LE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer))+4)) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer)) )) )) +#define INT_GET_UNALIGNED_64_BE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer)) )) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer))+4)) )) + +/* + * now pick the right ones for our MACHINE ARCHITECTURE + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_LE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_LE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_LE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_LE(pointer) +#else +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_BE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_BE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_BE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_BE(pointer) +#endif + +/* define generic INT_ macros */ + +#define INT_GET(reference,arch) \ + (((arch) == ARCH_NOCONVERT) \ + ? \ + (reference) \ + : \ + INT_SWAP((reference),(reference)) \ + ) + +/* does not return a value */ +#define INT_SET(reference,arch,valueref) \ + (__builtin_constant_p(valueref) ? \ + (void)( (reference) = ( ((arch) != ARCH_NOCONVERT) ? (INT_SWAP((reference),(valueref))) : (valueref)) ) : \ + (void)( \ + ((reference) = (valueref)), \ + ( ((arch) != ARCH_NOCONVERT) ? (reference) = INT_SWAP((reference),(reference)) : 0 ) \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD_EXPR(reference,arch,code) \ + (void)(((arch) == ARCH_NOCONVERT) \ + ? \ + ((reference) code) \ + : \ + ( \ + (reference) = INT_GET((reference),arch) , \ + ((reference) code), \ + INT_SET(reference, arch, reference) \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD(reference,arch,delta) \ + (void)( \ + INT_MOD_EXPR(reference,arch,+=(delta)) \ + ) + +/* + * INT_COPY - copy a value between two locations with the + * _same architecture_ but _potentially different sizes_ + * + * if the types of the two parameters are equal or they are + * in native architecture, a simple copy is done + * + * otherwise, architecture conversions are done + * + */ + +/* does not return a value */ +#define INT_COPY(dst,src,arch) \ + (void)( \ + ((sizeof(dst) == sizeof(src)) || ((arch) == ARCH_NOCONVERT)) \ + ? \ + ((dst) = (src)) \ + : \ + INT_SET(dst, arch, INT_GET(src, arch)) \ + ) + +/* + * INT_XLATE - copy a value in either direction between two locations + * with different architectures + * + * dir < 0 - copy from memory to buffer (native to arch) + * dir > 0 - copy from buffer to memory (arch to native) + */ + +/* does not return a value */ +#define INT_XLATE(buf,mem,dir,arch) {\ + ASSERT(dir); \ + if (dir>0) { \ + (mem)=INT_GET(buf, arch); \ + } else { \ + INT_SET(buf, arch, mem); \ + } \ +} + +#define INT_ISZERO(reference,arch) \ + ((reference) == 0) + +#define INT_ZERO(reference,arch) \ + ((reference) = 0) + +#define INT_GET_UNALIGNED_16_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_16(pointer)) \ + : \ + (INT_GET_UNALIGNED_16_BE(pointer)) \ + ) +#define INT_SET_UNALIGNED_16_ARCH(pointer,value,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + INT_SET_UNALIGNED_16(pointer,value); \ + } else { \ + INT_SET_UNALIGNED_16_BE(pointer,value); \ + } + +#endif /* __LIBSGI_ARCH_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/atomic.h linux-2.4.19-sgi211r3/include/linux/libsgi/atomic.h --- linux-2.4.19/include/linux/libsgi/atomic.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/atomic.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_ATOMIC_H__ +#define __LIBSGI_ATOMIC_H__ + +#include +#include +#include +#include +#include +#include + +#define Atomic_spin libsgi_Atomic_spin +extern spinlock_t Atomic_spin; + +static __inline__ int atomicIncWithWrap(int *ip, int val) +{ + unsigned long flags; + int ret; + spin_lock_irqsave(&Atomic_spin, flags); + ret = *ip; + (*ip)++; + if (*ip == val) *ip = 0; + spin_unlock_irqrestore(&Atomic_spin, flags); + return ret; +} + +#endif /* __LIBSGI_ATOMIC_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/debug.h linux-2.4.19-sgi211r3/include/linux/libsgi/debug.h --- linux-2.4.19/include/linux/libsgi/debug.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/debug.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_DEBUG_H__ +#define __LIBSGI_DEBUG_H__ + +#include + +#define CE_DEBUG 7 /* debug */ +#define CE_CONT 6 /* continuation */ +#define CE_NOTE 5 /* notice */ +#define CE_WARN 4 /* warning */ +#define CE_ALERT 1 /* alert */ +#define CE_PANIC 0 /* panic */ + +#define icmn_err libsgi_icmn_err +extern void icmn_err(int, char *, va_list); +#define cmn_err libsgi_cmn_err +extern void cmn_err(int, char *, ...); + +#if defined(DEBUG) +# ifdef lint +# define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */ +# else +# define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__)) +# endif /* lint */ +#else /* !DEBUG */ +# define ASSERT(x) ((void)0) +#endif /* !DEBUG */ + +#define doass libsgi_doass +extern int doass; /* dynamically turn off asserts */ +#define assfail libsgi_assfail +extern void assfail(char *, char *, int); +#ifdef DEBUG /* XXX - should be able to move DEBUG up 2 lines */ +#define random libsgi_random +extern unsigned long random(void); +#define get_thread_id libsgi_get_thread_id +extern int get_thread_id(void); +#endif + +#define ASSERT_ALWAYS(EX) ((EX)?((void)0):assfail(#EX, __FILE__, __LINE__)) +#define debug_stop_all_cpus(param) /* param is "cpumask_t *" */ + +#endif /* __LIBSGI_DEBUG_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/kmem.h linux-2.4.19-sgi211r3/include/linux/libsgi/kmem.h --- linux-2.4.19/include/linux/libsgi/kmem.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/kmem.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_KMEM_H__ +#define __LIBSGI_KMEM_H__ + +/* + * memory management routines + */ +#define KM_SLEEP 0x0001 +#define KM_NOSLEEP 0x0002 /* must match VM_NOSLEEP */ +#define KM_PHYSCONTIG 0x0008 +#define KM_CACHEALIGN 0x0010 /* guarantee that memory is cache aligned */ + +#define VM_NOSLEEP KM_NOSLEEP +#define VM_PHYSCONTIG KM_PHYSCONTIG +#define VM_CACHEALIGN KM_CACHEALIGN +#define VM_DIRECT KM_PHYSCONTIG +#define VM_UNCACHED 0x0020 + +typedef struct kmem_cache_s kmem_zone_t; + +#define kmem_zone_init libsgi_kmem_zone_init +extern kmem_zone_t *kmem_zone_init(int, char *); +#define kmem_zone_zalloc libsgi_kmem_zone_zalloc +extern void *kmem_zone_zalloc(kmem_zone_t *, int); +#define kmem_zone_alloc libsgi_kmem_zone_alloc +extern void *kmem_zone_alloc(kmem_zone_t *, int); +#define kmem_zone_free libsgi_kmem_zone_free +extern void kmem_zone_free(kmem_zone_t *, void *); + +#define kmem_alloc libsgi_kmem_alloc +extern void *kmem_alloc(size_t, int); +#define kmem_realloc libsgi_kmem_realloc +extern void *kmem_realloc(void *, size_t, size_t, int); +#define kmem_zalloc libsgi_kmem_zalloc +extern void *kmem_zalloc(size_t, int); +#define kmem_free libsgi_kmem_free +extern void kmem_free(void *, size_t); + +typedef void (*kmem_shake_func_t)(void); + +#define kmem_shake_register libsgi_kmem_shake_register +extern void kmem_shake_register(kmem_shake_func_t); +#define kmem_shake_deregister libsgi_kmem_shake_deregister +extern void kmem_shake_deregister(kmem_shake_func_t); + +#endif /* __LIBSGI_KMEM_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/ktrace.h linux-2.4.19-sgi211r3/include/linux/libsgi/ktrace.h --- linux-2.4.19/include/linux/libsgi/ktrace.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/ktrace.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_KTRACE_H__ +#define __LIBSGI_KTRACE_H__ + +/* + * Trace buffer entry structure. + */ +typedef struct ktrace_entry { + void *val[16]; +} ktrace_entry_t; + +/* + * Trace buffer header structure. + */ +typedef struct ktrace { + lock_t kt_lock; /* mutex to guard counters */ + int kt_nentries; /* number of entries in trace buf */ + int kt_index; /* current index in entries */ + int kt_rollover; + ktrace_entry_t *kt_entries; /* buffer of entries */ +} ktrace_t; + +/* + * Trace buffer snapshot structure. + */ +typedef struct ktrace_snap { + int ks_start; /* kt_index at time of snap */ + int ks_index; /* current index */ +} ktrace_snap_t; + +/* + * Exported interfaces. + */ +#define ktrace_alloc libsgi_ktrace_alloc +extern ktrace_t *ktrace_alloc(int, int); + +#if (defined(DEBUG)) + +#define ktrace_init libsgi_ktrace_init +extern void ktrace_init(int zentries); +#define ktrace_uninit libsgi_ktrace_uninit +extern void ktrace_uninit(void); + +#define ktrace_free libsgi_ktrace_free +extern void ktrace_free(ktrace_t *); + +#define ktrace_enter libsgi_ktrace_enter +extern void ktrace_enter( + ktrace_t *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *); + +#define ktrace_first libsgi_ktrace_first +extern ktrace_entry_t *ktrace_first(ktrace_t *, ktrace_snap_t *); +#define ktrace_nentries libsgi_ktrace_nentries +extern int ktrace_nentries(ktrace_t *); +#define ktrace_next libsgi_ktrace_next +extern ktrace_entry_t *ktrace_next(ktrace_t *, ktrace_snap_t *); +#define ktrace_skip libsgi_ktrace_skip +extern ktrace_entry_t *ktrace_skip(ktrace_t *, int, ktrace_snap_t *); + +#else /* ! (defined(DEBUG)) */ + +#define ktrace_free(ktp) +#define ktrace_enter(ktp,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15) + +#endif /* ! (defined(DEBUG)) */ + +#endif /* __LIBSGI_KTRACE_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/libsgi.h linux-2.4.19-sgi211r3/include/linux/libsgi/libsgi.h --- linux-2.4.19/include/linux/libsgi/libsgi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/libsgi.h Sun Aug 4 22:21:57 2002 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_H__ +#define __LIBSGI_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __LIBSGI_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/move.h linux-2.4.19-sgi211r3/include/linux/libsgi/move.h --- linux-2.4.19/include/linux/libsgi/move.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/move.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_MOVE_H__ +#define __LIBSGI_MOVE_H__ + +#include +#include + +#define bzero(p,s) memset((p), 0, (s)) +#define bcopy(s,d,n) memcpy((d),(s),(n)) +#define bcmp(s1,s2,l) memcmp(s1,s2,l) +#define ovbcopy(from,to,count) memmove(to,from,count) + +typedef struct iovec iovec_t; + +typedef struct uio { + iovec_t *uio_iov; /* pointer to array of iovecs */ + int uio_iovcnt; /* number of iovecs */ + int uio_fmode; /* file mode flags */ + __u64 uio_offset; /* file offset */ + short uio_segflg; /* address space (kernel or user) */ + ssize_t uio_resid; /* residual count */ + + struct file * uio_fp; /* file associated with io */ +} uio_t; + +/* + * I/O direction. + */ +typedef enum uio_rw { UIO_READ, UIO_WRITE } uio_rw_t; + +/* + * Segment flag values. + */ +typedef enum uio_seg { + UIO_NOSPACE = -1, /* no data movement (used for pagein) */ + UIO_USERSPACE, /* uio_iov describes user space */ + UIO_SYSSPACE, /* uio_iov describes system space */ + UIO_USERISPACE /* uio_iov describes instruction space */ +} uio_seg_t; + + +#define uiomove libsgi_uiomove +extern int uiomove (void *, size_t, uio_rw_t, uio_t *); + +/* + * map these directly... trying to use a #define causes + * many strange side affects + */ +/* + * copyin/copyout on irix return 0 on success, -1 on failure + */ +static __inline__ int +copyout( void* from, void* to, int size ) +{ + return copy_to_user(to, from, size ) ? -1 : 0; +} + +static __inline__ int +copyin( void* from, void* to, int size ) +{ + return copy_from_user(to, from, size ) ? -1 : 0; +} + +#endif /* __LIBSGI_MOVE_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/mrlock.h linux-2.4.19-sgi211r3/include/linux/libsgi/mrlock.h --- linux-2.4.19/include/linux/libsgi/mrlock.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/mrlock.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_MRLOCK_H__ +#define __LIBSGI_MRLOCK_H__ + +#include +#include +#include +#include +#include + +/* + * These are sleep locks and not spinlocks. If one wants read/write spinlocks, + * use read_lock, write_lock, ... see spinlock.h. + */ + +typedef struct mrlock_s { + int mr_count; + unsigned short mr_reads_waiting; + unsigned short mr_writes_waiting; + wait_queue_head_t mr_readerq; + wait_queue_head_t mr_writerq; + spinlock_t mr_lock; +} mrlock_t; + +#define MR_ACCESS 1 +#define MR_UPDATE 2 + +#define MRLOCK_BARRIER 0x1 +#define MRLOCK_ALLOW_EQUAL_PRI 0x8 + +/* + * mraccessf/mrupdatef take flags to be passed in while sleeping; + * only PLTWAIT is currently supported. + */ + +#define mraccessf libsgi_mraccessf +extern void mraccessf(mrlock_t *, int); +#define mrupdatef libsgi_mrupdatef +extern void mrupdatef(mrlock_t *, int); +#define mrlock libsgi_mrlock +extern void mrlock(mrlock_t *, int, int); +#define mrunlock libsgi_mrunlock +extern void mrunlock(mrlock_t *); +#define mraccunlock libsgi_mraccunlock +extern void mraccunlock(mrlock_t *); +#define mrtryupdate libsgi_mrtryupdate +extern int mrtryupdate(mrlock_t *); +#define mrtryaccess libsgi_mrtryaccess +extern int mrtryaccess(mrlock_t *); +#define mrtrypromote libsgi_mrtrypromote +extern int mrtrypromote(mrlock_t *); +#define mrdemote libsgi_mrdemote +extern void mrdemote(mrlock_t *); + +#define ismrlocked libsgi_ismrlocked +extern int ismrlocked(mrlock_t *, int); +#define mrlock_init libsgi_mrlock_init +extern void mrlock_init(mrlock_t *, int type, char *name, long sequence); +#define mrfree libsgi_mrfree +extern void mrfree(mrlock_t *); + +#define mrinit(mrp, name) mrlock_init(mrp, MRLOCK_BARRIER, name, -1) +#define mraccess(mrp) mraccessf(mrp, 0) /* grab for READ/ACCESS */ +#define mrupdate(mrp) mrupdatef(mrp, 0) /* grab for WRITE/UPDATE */ + +#endif /* __LIBSGI_MRLOCK_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/mutex.h linux-2.4.19-sgi211r3/include/linux/libsgi/mutex.h --- linux-2.4.19/include/linux/libsgi/mutex.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/mutex.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_MUTEX_H__ +#define __LIBSGI_MUTEX_H__ + +#include +#include +#include +#include +#include +#include + +/* + * Map the mutex'es from IRIX to Linux semaphores. + * + * Destroy just simply initializes to -99 which should block all other + * callers. + */ + +typedef struct mutex_s { + struct semaphore sema; + int state; +} mutex_t; + + +#define init_mutex(ptr, type, name, sequence) mutex_init(ptr, type, name) + +#define _mutex_init libsgi__mutex_init +extern void _mutex_init( mutex_t *mutex); +#define _mutex_lock libsgi__mutex_lock +extern void _mutex_lock( mutex_t *mutex); +#define _mutex_unlock libsgi__mutex_unlock +extern void _mutex_unlock( mutex_t *mutex); +#define _mutex_trylock libsgi__mutex_trylock +extern int _mutex_trylock( mutex_t *mutex); +#define _mutex_destroy libsgi__mutex_destroy +extern void _mutex_destroy( mutex_t *mutex); + +#define mutex_init(lock, type, name) _mutex_init(lock) +#define mutex_lock(lock, num) _mutex_lock(lock) +#define mutex_trylock(lock) _mutex_trylock(lock) +#define mutex_unlock(lock) _mutex_unlock(lock) +#define mutex_destroy(lock) _mutex_destroy(lock) + +/* + * mp_mutex_spinlock might be used during an interrupt thread so it + * must be irq safe. + * + * mutex_spinlock is also called extensively by interrupt threads. + * + */ + +static __inline__ unsigned long mutex_spinlock(spinlock_t *l) +{ + unsigned long flags; + spin_lock_irqsave(l, flags); + return(flags); +} + +#define mutex_spinunlock(lockp,flags) spin_unlock_irqrestore(lockp, flags) + +#define mp_mutex_spinlock(lockp) mutex_spinlock(lockp) +#define mp_mutex_spinunlock(lockp,flags) spin_unlock_irqrestore(lockp, flags) + + +/* + * Types for mutex_init(), mutex_alloc() + */ +#define MUTEX_DEFAULT 0x0 + +/* + * void mutex_init(mutex_t *mp, int type, char *name); + * void init_mutex(mutex_t *mp, int type, char *name, long sequence); + * + * Name may be null -- it is only used when metering mutexes are installed, + * tag the metering structure with an ascii name. + * Only METER_NAMSZ-1 characters are recorded. + * + * If init_mutex interface is used to initialize, metering name is + * constructed from 'name' prefix and and ascii suffix generated from + * the 'sequence' argument: [ "MyLock", 12 ] becomes "MyLock00012" + */ + + +#endif /* __LIBSGI_MUTEX_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/sema.h linux-2.4.19-sgi211r3/include/linux/libsgi/sema.h --- linux-2.4.19/include/linux/libsgi/sema.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/sema.h Sun May 26 21:57:45 2002 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_SEMA_H__ +#define __LIBSGI_SEMA_H__ + +#include +#include +#include +#include +#include + +/* + * sema_t structure just maps to struct semaphore in Linux kernel. + */ + +typedef struct semaphore sema_t; + +#define init_sema(sp, val, c, d) sema_init(sp, val) +#define initsema(sp, val) sema_init(sp, val) +#define initnsema(sp, val, name) sema_init(sp, val) +#define psema(sp, b) down(sp) +#define vsema(sp) up(sp) +#define valusema(sp) (atomic_read(&(sp)->count)) +#define freesema(sema) + +/* + * Map cpsema (try to get the sema) to down_trylock. We need to switch + * the return values since cpsema returns 1 (acquired) 0 (failed) and + * down_trylock returns the reverse 0 (acquired) 1 (failed). + */ + +#define cpsema(sp) (down_trylock(sp) ? 0 : 1) + +/* + * Didn't do cvsema(sp). Not sure how to map this to up/down/... + * It does a vsema if the values is < 0 other wise nothing. + */ + +#endif /* __LIBSGI_SEMA_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/spin.h linux-2.4.19-sgi211r3/include/linux/libsgi/spin.h --- linux-2.4.19/include/linux/libsgi/spin.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/spin.h Sun May 26 21:57:45 2002 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_SPIN_H__ +#define __LIBSGI_SPIN_H__ + +#include +#include +#include +#include +#include +#include + +/* + * Map the spinlocks from IRIX to Linux. + * For now, make them all as if they were used in interrupt thread (irq safe). + */ +#define spinlock_init(lock, name) spin_lock_init(lock) +#define init_spinlock(lock, name, ll) spin_lock_init(lock) +#define spinlock_destroy(lock) + +/* + * Map lock_t from IRIX to Linux spinlocks. + * + * Note that linux turns on/off spinlocks depending on CONFIG_SMP. + * We don't need to worry about SMP or not here. + * + * The irq safe calls get mapped from spinlocks and IRQ safe calls + * to just spls. + */ + +typedef spinlock_t lock_t; + +#define nested_spinunlock(a) spin_unlock(a) +#define nested_spinlock(a) spin_lock(a) +#define nested_spintrylock(a) spin_trylock(a) + +#endif /* __LIBSGI_SPIN_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/sv.h linux-2.4.19-sgi211r3/include/linux/libsgi/sv.h --- linux-2.4.19/include/linux/libsgi/sv.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/sv.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_SV_H__ +#define __LIBSGI_SV_H__ + +#include +#include +#include +#include +#include + +/* + * Synchronisation variables + * + * parameters "pri", "svf" and "rts" are not (yet?) implemented + * + */ + +#define init_sv(sv,type,name,flag) \ + _sv_init(sv) +#define sv_init(sv,flag,name) \ + _sv_init(sv) +#define sv_wait(sv, pri, lock, s) \ + _sv_wait(sv, lock, s, 0, NULL) +#define sv_wait_sig(sv, pri, lock, s) \ + _sv_wait(sv, lock, s, 1, NULL) +#define sv_timedwait(sv, pri, lock, s, svf, ts, rts) \ + _sv_wait(sv, lock, s, 0, ts) +#define sv_timedwait_sig(sv, pri, lock, s, svf, ts, rts) \ + _sv_wait(sv, lock, s, 1, ts) +#define mp_sv_wait(sv, pri, lock, s) \ + _sv_wait(sv, lock, s, 0, NULL) +#define mp_sv_wait_sig(sv, pri, lock, s) \ + _sv_wait(sv, lock, s, 1, NULL) +#define sv_broadcast(sv) \ + _sv_broadcast(sv) + +typedef struct sv_s { + wait_queue_head_t waiters; + spinlock_t lock; +} sv_t; + +#define _sv_init libsgi__sv_init +extern void _sv_init(sv_t *sv); +#define _sv_wait libsgi__sv_wait +extern void _sv_wait(sv_t *sv, spinlock_t *lock, unsigned long s, int intr, struct timespec *timeout); +#define _sv_broadcast libsgi__sv_broadcast +extern void _sv_broadcast(sv_t *sv); +#define _sv_signal libsgi__sv_signal +extern void _sv_signal(sv_t *sv); + +#define sv_signal(sv) _sv_signal(sv) +#define sv_broadcast(sv) _sv_broadcast(sv) +#define sv_destroy(sv) + +/* + * Initialize sync variables. + * + * void sv_init(sv_t *svp, int type, char *name); + * void init_sv(sv_t *svp, int type, char *name, long sequencer); + * + * Name may be null; used only when metering routines are installed + * (see mutex_init, init_mutex above). + */ + +#define SV_FIFO 0x0 /* sv_t is FIFO type */ +#define SV_LIFO 0x2 /* sv_t is LIFO type */ +#define SV_PRIO 0x4 /* sv_t is PRIO type */ +#define SV_KEYED 0x6 /* sv_t is KEYED type */ +#define SV_DEFAULT SV_FIFO + +#endif /* __LIBSGI_SV_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/time.h linux-2.4.19-sgi211r3/include/linux/libsgi/time.h --- linux-2.4.19/include/linux/libsgi/time.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/time.h Sun May 26 21:57:45 2002 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_TIME_H__ +#define __LIBSGI_TIME_H__ + +#include + +static inline void delay(long ticks) +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(ticks); +} + +static inline void nanotime(timespec_t *tvp) +{ + tvp->tv_sec = xtime.tv_sec; + tvp->tv_nsec = xtime.tv_usec * 1000; +} + +#endif /* __LIBSGI_TIME_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/types.h linux-2.4.19-sgi211r3/include/linux/libsgi/types.h --- linux-2.4.19/include/linux/libsgi/types.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/types.h Sun May 26 21:57:45 2002 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_TYPES_H__ +#define __LIBSGI_TYPES_H__ + +#include + +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef signed short int __int16_t; +typedef unsigned short int __uint16_t; +typedef signed int __int32_t; +typedef unsigned int __uint32_t; +typedef signed long long int __int64_t; +typedef unsigned long long int __uint64_t; + +/* POSIX Extensions */ +typedef unsigned char uchar_t; +typedef unsigned short ushort_t; +typedef unsigned int uint_t; +typedef unsigned long ulong_t; + +typedef enum { B_FALSE, B_TRUE } boolean_t; + +typedef __int64_t prid_t; /* project ID */ +typedef __uint32_t inst_t; /* an instruction */ + +typedef __uint32_t app32_ulong_t; +typedef __uint32_t app32_ptr_t; + +#if (BITS_PER_LONG == 32) +typedef __int64_t sysarg_t; +#elif (BITS_PER_LONG == 64) +typedef long sysarg_t; +#else +#error BITS_PER_LONG must be 32 or 64 +#endif + +typedef struct timespec timespec_t; + +typedef off_t linux_off_t; +typedef __kernel_ino_t linux_ino_t; + +typedef struct { + unsigned char __u_bits[16]; +} uuid_t; + +#endif /* __LIBSGI_TYPES_H__ */ diff -Nur linux-2.4.19/include/linux/libsgi/uuid.h linux-2.4.19-sgi211r3/include/linux/libsgi/uuid.h --- linux-2.4.19/include/linux/libsgi/uuid.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/libsgi/uuid.h Tue Jul 30 16:25:42 2002 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBSGI_UUID_H__ +#define __LIBSGI_UUID_H__ + +#define uuid_create_nil libsgi_uuid_create_nil +extern void uuid_create_nil(uuid_t *uuid); +#define uuid_is_nil libsgi_uuid_is_nil +extern int uuid_is_nil(uuid_t *uuid); +#define uuid_equal libsgi_uuid_equal +extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2); +#define uuid_getnodeuniq libsgi_uuid_getnodeuniq +extern void uuid_getnodeuniq(uuid_t *uuid, int fsid [2]); +#define uuid_hash64 libsgi_uuid_hash64 +extern __uint64_t uuid_hash64(uuid_t *uuid); +#define uuid_compare libsgi_uuid_compare +extern int uuid_compare(uuid_t *uuid1, uuid_t *uuid2); +#define uuid_create libsgi_uuid_create +extern void uuid_create(uuid_t *uuid); +#define uuid_init libsgi_uuid_init +extern void uuid_init(void); + +#endif /* __LIBSGI_UUID_H__ */ diff -Nur linux-2.4.19/include/linux/limits.h linux-2.4.19-sgi211r3/include/linux/limits.h --- linux-2.4.19/include/linux/limits.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-sgi211r3/include/linux/limits.h Fri Apr 26 11:07:18 2002 @@ -13,6 +13,9 @@ #define NAME_MAX 255 /* # chars in a file name */ #define PATH_MAX 4096 /* # chars in a path name including nul */ #define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */ +#define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */ +#define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */ +#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */ #define RTSIG_MAX 32 diff -Nur linux-2.4.19/include/linux/list.h linux-2.4.19-sgi211r3/include/linux/list.h --- linux-2.4.19/include/linux/list.h Fri Dec 21 09:42:03 2001 +++ linux-2.4.19-sgi211r3/include/linux/list.h Mon Oct 28 20:43:23 2002 @@ -19,6 +19,8 @@ struct list_head *next, *prev; }; +typedef struct list_head list_t; + #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ diff -Nur linux-2.4.19/include/linux/loop.h linux-2.4.19-sgi211r3/include/linux/loop.h --- linux-2.4.19/include/linux/loop.h Mon Sep 17 13:16:30 2001 +++ linux-2.4.19-sgi211r3/include/linux/loop.h Mon Mar 18 10:53:34 2002 @@ -48,6 +48,10 @@ int old_gfp_mask; + int lo_blksize; + int lo_current; + unsigned long lo_pending_reads[2]; + struct semaphore *lo_change; spinlock_t lo_lock; struct buffer_head *lo_bh; struct buffer_head *lo_bhtail; @@ -151,5 +155,6 @@ #define LOOP_CLR_FD 0x4C01 #define LOOP_SET_STATUS 0x4C02 #define LOOP_GET_STATUS 0x4C03 +#define LOOP_CHANGE_FD 0x4C04 #endif diff -Nur linux-2.4.19/include/linux/miscdevice.h linux-2.4.19-sgi211r3/include/linux/miscdevice.h --- linux-2.4.19/include/linux/miscdevice.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/miscdevice.h Wed Oct 16 14:02:58 2002 @@ -19,6 +19,7 @@ #define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ #define SUN_OPENPROM_MINOR 139 +#define DMAPI_MINOR 140 /* DMAPI */ #define NVRAM_MINOR 144 #define I2O_MINOR 166 #define MICROCODE_MINOR 184 diff -Nur linux-2.4.19/include/linux/mm.h linux-2.4.19-sgi211r3/include/linux/mm.h --- linux-2.4.19/include/linux/mm.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/mm.h Wed Feb 5 20:48:13 2003 @@ -12,6 +12,7 @@ #include #include #include +#include extern unsigned long max_mapnr; extern unsigned long num_physpages; @@ -72,6 +73,11 @@ struct file * vm_file; /* File we map to (can be NULL). */ unsigned long vm_raend; /* XXX: put full readahead info here. */ void * vm_private_data; /* was vm_pte (shared mem) */ +#ifdef CONFIG_CPUMEMSET + unsigned long vm_mems_allowed; /* cpumemset managed memory placement */ +#else + unsigned long vm_unused_mems_allowed; +#endif }; /* @@ -103,8 +109,10 @@ #define VM_DONTCOPY 0x00020000 /* Do not copy this vma on fork */ #define VM_DONTEXPAND 0x00040000 /* Cannot expand with mremap() */ #define VM_RESERVED 0x00080000 /* Don't unmap it from swap_out */ +#define VM_WRITECOMBINED 0x00100000 /* Write-combined */ +#define VM_NONCACHED 0x00200000 /* Noncached access */ -#define VM_STACK_FLAGS 0x00000177 +#define VM_STACK_FLAGS (VM_DATA_DEFAULT_FLAGS | VM_GROWSDOWN) #define VM_READHINTMASK (VM_SEQ_READ | VM_RAND_READ) #define VM_ClearReadHint(v) (v)->vm_flags &= ~VM_READHINTMASK @@ -132,6 +140,8 @@ void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int unused); +#define HAVE_VMOP_MPROTECT + int (*mprotect)(struct vm_area_struct * area, unsigned int newflags); }; /* @@ -173,7 +183,7 @@ * Architectures with slow multiplication can define * WANT_PAGE_VIRTUAL in asm/page.h */ -#if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL) +#if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL) || defined(CONFIG_DISCONTIGMEM) void *virtual; /* Kernel virtual address (NULL if not kmapped, ie. highmem) */ #endif /* CONFIG_HIGMEM || WANT_PAGE_VIRTUAL */ @@ -297,6 +307,11 @@ #define PG_arch_1 13 #define PG_reserved 14 #define PG_launder 15 /* written out by VM pressure.. */ +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#define PG_inuse 16 /* set for all pages(including higher + order partial-pages) allocated + by the kernel. */ +#endif /* defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) */ /* Make it prettier to test the above... */ #define UnlockPage(page) unlock_page(page) @@ -369,6 +384,43 @@ #endif /* CONFIG_HIGHMEM || WANT_PAGE_VIRTUAL */ +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +/* + * Using the non-atomic version __set_bit as per Andi Kleen's suggestion. + * Currently __clear_bit is not available on all architectures in 2.4. + */ +#define PageInuse(page) test_bit(PG_inuse, &(page)->flags) + +static inline void SetPageInuseOrder(struct page *page, unsigned int order) +{ + unsigned int i = 1UL << order; + page += i; + do { + page--; + __set_bit(PG_inuse, &(page)->flags); + } while (--i); +} + +static inline void ClearPageInuseOrder(struct page *page, unsigned int order) +{ + unsigned int i = 1UL << order; + page += i; + do { + page--; + /* Replace this by __clear_bit in 2.5 */ + clear_bit(PG_inuse, &(page)->flags); + } while (--i); +} + +#else /* !(defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)) */ +static inline void SetPageInuseOrder(struct page *page, unsigned int order) +{ +} +static inline void ClearPageInuseOrder(struct page *page, unsigned int order) +{ +} +#endif /* defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) */ + extern void FASTCALL(set_page_dirty(struct page *)); /* @@ -432,7 +484,8 @@ */ if (order >= MAX_ORDER) return NULL; - return _alloc_pages(gfp_mask, order); + return __alloc_pages(gfp_mask, order, + NODE_DATA(numa_node_id())->node_zonelists + (gfp_mask & GFP_ZONEMASK) ); } #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) @@ -460,6 +513,8 @@ #define __free_page(page) __free_pages((page), 0) #define free_page(addr) free_pages((addr),0) +extern int start_aggressive_readahead(int); + extern void show_free_areas(void); extern void show_free_areas_node(pg_data_t *pgdat); @@ -568,14 +623,32 @@ mm->mmap_cache = prev; } -static inline int can_vma_merge(struct vm_area_struct * vma, unsigned long vm_flags) +/* + * Ok to merge CpuMemSet if there is no vma2 or it has same mems_allowed + */ +static inline int can_cms_merge(struct vm_area_struct * vma, struct vm_area_struct * vma2) { - if (!vma->vm_file && vma->vm_flags == vm_flags) + #ifdef CONFIG_CPUMEMSET + return !vma2 || vma->vm_mems_allowed == vma2->vm_mems_allowed; + #else return 1; - else - return 0; + #endif } +/* + * Is vma mergable (not file), consistent with vm_flags and vma2? + * "vma2" is 0 if extending vma into hole, else the other vma. + */ +static inline int can_vma_merge(struct vm_area_struct * vma, + struct vm_area_struct * vma2, + unsigned long vm_flags) +{ + return !vma->vm_file && vma->vm_flags == vm_flags && can_cms_merge(vma, vma2); +} + +extern int vma_split_range (struct mm_struct *, unsigned long, size_t); +extern void vma_remerge_range (struct mm_struct *, unsigned long, size_t); + struct zone_t; /* filemap.c */ extern void remove_inode_page(struct page *); @@ -648,6 +721,9 @@ vma->vm_mm->total_vm += grow; if (vma->vm_flags & VM_LOCKED) vma->vm_mm->locked_vm += grow; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); spin_unlock(&vma->vm_mm->page_table_lock); return 0; } diff -Nur linux-2.4.19/include/linux/mmtimer.h linux-2.4.19-sgi211r3/include/linux/mmtimer.h --- linux-2.4.19/include/linux/mmtimer.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/mmtimer.h Thu Jan 9 10:30:30 2003 @@ -0,0 +1,170 @@ +/* + * Intel Multimedia Timer device interface + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. + * + * This file should define an interface compatible with the IA-PC Multimedia + * Timers Draft Specification (rev. 0.97) from Intel. Note that some + * hardware may not be able to safely export its registers to userspace, + * so the ioctl interface should support all necessary functionality. + * + * 11/01/01 - jbarnes - initial revision + */ + +#ifndef _LINUX_MMTIMER_H +#define _LINUX_MMTIMER_H + +/* name of the device, usually in /dev */ +#define MMTIMER_NAME "mmtimer" +#define MMTIMER_FULLNAME "/dev/mmtimer" +#define MMTIMER_DESC "IA-PC Multimedia Timer" +#define MMTIMER_VERSION "1.0" + +/* + * Used by the user to setup an alarm + */ +typedef struct mmtimer_alarm { + int id; + unsigned long value; + int signo; +} mmtimer_alarm_t; + +/* + * Breakdown of the ioctl's available. An 'optional' next to the command + * indicates that supporting this command is optional, while 'required' + * commands must be implemented if conformance is desired. + * + * MMTIMER_GETOFFSET - optional + * Should return the offset (relative to the start of the page where the + * registers are mapped) for the counter in question. + * + * MMTIMER_GETRES - required + * The resolution of the clock in femto (10^-15) seconds + * + * MMTIMER_GETFREQ - required + * Frequency of the clock in Hz + * + * MMTIMER_GETBITS - required + * Number of bits in the clock's counter + * + * MMTIMER_GETNUM - required + * Number of comparators available + * + * MMTIMER_MMAPAVAIL - required + * Returns nonzero if the registers can be mmap'd into userspace, 0 otherwise + * + * MMTIMER_SETPERIODIC - required + * Sets the comparator in question to the value specified. + * The interrupt handler will add the value specified to the + * comparator after a match. + * + * MMTIMER_SETONESHOT - required + * Like the above, but the comparator is not updated after the match. + * + * MMTIMER_GETCOUNTER - required + * Gets the current value in the counter + */ +#define MMTIMER_IOCTL_BASE 'm' + +#define MMTIMER_GETOFFSET _IO(MMTIMER_IOCTL_BASE, 0) +#define MMTIMER_GETRES _IOR(MMTIMER_IOCTL_BASE, 1, unsigned long) +#define MMTIMER_GETFREQ _IOR(MMTIMER_IOCTL_BASE, 2, unsigned long) +#define MMTIMER_GETBITS _IO(MMTIMER_IOCTL_BASE, 4) +#define MMTIMER_GETNUM _IO(MMTIMER_IOCTL_BASE, 5) +#define MMTIMER_MMAPAVAIL _IO(MMTIMER_IOCTL_BASE, 6) +#define MMTIMER_SETPERIODIC _IOW(MMTIMER_IOCTL_BASE, 7, mmtimer_alarm_t) +#define MMTIMER_SETONESHOT _IOW(MMTIMER_IOCTL_BASE, 8, mmtimer_alarm_t) +#define MMTIMER_GETCOUNTER _IOR(MMTIMER_IOCTL_BASE, 9, unsigned long) + +/* + * An mmtimer verification program. WARNINGs are ok, but ERRORs indicate + * that the device doesn't fully support the interface defined here. + */ +#ifdef _MMTIMER_TEST_PROGRAM + +#include +#include +#include +#include +#include +#include + +#include + +#include "mmtimer.h" + +int main(int argc, char *argv[]) +{ + int result, fd; + unsigned long val = 0; + unsigned long i; + + if((fd = open("/dev/"MMTIMER_NAME, O_RDONLY)) == -1) { + printf("failed to open /dev/%s", MMTIMER_NAME); + return 1; + } + + /* + * How many comparators are there? + */ + if((result = ioctl(fd, MMTIMER_GETNUM, 0)) != -ENOSYS) + printf("comparators available: %d\n", result); + else + printf("ERROR: no comparators available\n"); + + /* + * Can we mmap in the counter? + */ + if((result = ioctl(fd, MMTIMER_MMAPAVAIL, 0)) == 1) { + printf("mmap available\n"); + /* ... so try getting the offset for each clock */ + if((result = ioctl(fd, MMTIMER_GETOFFSET, 0)) != -ENOSYS) + printf("offset: %d\n", result); + else + printf("WARNING: offset unavailable for clock\n"); + } + else + printf("WARNING: mmap unavailable\n"); + + /* + * Get the resolution in femtoseconds + */ + if((result = ioctl(fd, MMTIMER_GETRES, &val)) != -ENOSYS) + printf("resolution: %ld femtoseconds\n", val); + else + printf("ERROR: failed to get resolution\n"); + + /* + * Get the frequency in Hz + */ + if((result = ioctl(fd, MMTIMER_GETFREQ, &val)) != -ENOSYS) + if(val < 10000000) /* less than 10 MHz? */ + printf("ERROR: frequency only %ld MHz, should be >= 10 MHz\n", val/1000000); + else + printf("frequency: %ld MHz\n", val/1000000); + else + printf("ERROR: failed to get frequency\n"); + + /* + * How many bits in the counter? + */ + if((result = ioctl(fd, MMTIMER_GETBITS, 0)) != -ENOSYS) + printf("bits in counter: %d\n", result); + else + printf("ERROR: can't get number of bits in counter\n"); + + if((result = ioctl(fd, MMTIMER_GETCOUNTER, &val)) != -ENOSYS) + printf("counter value: %ld\n", val); + else + printf("ERROR: can't get counter value\n"); + + return 0; +} + +#endif /* _MMTIMER_TEST_PROGRM */ + +#endif /* _LINUX_MMTIMER_H */ diff -Nur linux-2.4.19/include/linux/mmzone.h linux-2.4.19-sgi211r3/include/linux/mmzone.h --- linux-2.4.19/include/linux/mmzone.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/mmzone.h Wed Oct 16 14:02:58 2002 @@ -89,7 +89,8 @@ * rarely used fields: */ char *name; - unsigned long size; + unsigned long totalsize; + unsigned long memsize; } zone_t; #define ZONE_DMA 0 @@ -108,8 +109,21 @@ * so despite the zonelist table being relatively big, the cache * footprint of this construct is very small. */ +#ifndef CONFIG_DISCONTIGMEM +#define PLAT_MAX_COMPACT_NODES 1 +#elif defined(CONFIG_IA64_SGI_SN1) +#include +#elif defined(CONFIG_IA64_SGI_SN2) +#include +#elif defined(CONFIG_IA64_DIG) +#include +#else +#error "Unknown architecture" +#endif /* !CONFIG_DISCONTIGMEM */ + + typedef struct zonelist_struct { - zone_t * zones [MAX_NR_ZONES+1]; // NULL delimited + zone_t * zones [PLAT_MAX_COMPACT_NODES * MAX_NR_ZONES+1]; // NULL delimited } zonelist_t; #define GFP_ZONEMASK 0x0f @@ -143,9 +157,8 @@ extern int numnodes; extern pg_data_t *pgdat_list; -#define memclass(pgzone, classzone) (((pgzone)->zone_pgdat == (classzone)->zone_pgdat) \ - && ((pgzone) <= (classzone))) - +#define memclass(pgzone, classzone) (((pgzone) - (pgzone)->zone_pgdat->node_zones) <= \ +((classzone) - (classzone)->zone_pgdat->node_zones)) /* * The following two are not meant for general usage. They are here as * prototypes for the discontig memory code. diff -Nur linux-2.4.19/include/linux/module.h linux-2.4.19-sgi211r3/include/linux/module.h --- linux-2.4.19/include/linux/module.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/module.h Sun Feb 9 17:13:48 2003 @@ -412,4 +412,29 @@ #define SET_MODULE_OWNER(some_struct) do { } while (0) #endif +extern void print_modules(void); + +#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) + +extern struct module *module_list; + +/* + * print_symbols takes a format string containing one %s. + * If support for resolving symbols is compiled in, the %s will + * be replaced by the closest symbol to the address and the entire + * string is printk()ed. Otherwise, nothing is printed. + */ +extern void print_symbol(const char *fmt, unsigned long address); + +#else + +#include +static inline int +print_symbol(const char *fmt, unsigned long address) +{ + return -ESRCH; +} + +#endif + #endif /* _LINUX_MODULE_H */ diff -Nur linux-2.4.19/include/linux/netfilter_ipv4/lockhelp.h linux-2.4.19-sgi211r3/include/linux/netfilter_ipv4/lockhelp.h --- linux-2.4.19/include/linux/netfilter_ipv4/lockhelp.h Mon Jan 1 10:37:41 2001 +++ linux-2.4.19-sgi211r3/include/linux/netfilter_ipv4/lockhelp.h Tue Aug 13 14:22:06 2002 @@ -44,20 +44,20 @@ /* Write locked OK as well. */ \ #define MUST_BE_READ_LOCKED(l) \ -do { if (!((l)->read_locked_map & (1 << smp_processor_id())) \ - && !((l)->write_locked_map & (1 << smp_processor_id()))) \ +do { if (!((l)->read_locked_map & (1UL << smp_processor_id())) \ + && !((l)->write_locked_map & (1UL << smp_processor_id()))) \ printk("ASSERT %s:%u %s not readlocked\n", __FILE__, __LINE__, #l); \ } while(0) #define MUST_BE_WRITE_LOCKED(l) \ -do { if (!((l)->write_locked_map & (1 << smp_processor_id()))) \ +do { if (!((l)->write_locked_map & (1UL << smp_processor_id()))) \ printk("ASSERT %s:%u %s not writelocked\n", __FILE__, __LINE__, #l); \ } while(0) #define MUST_BE_READ_WRITE_UNLOCKED(l) \ -do { if ((l)->read_locked_map & (1 << smp_processor_id())) \ +do { if ((l)->read_locked_map & (1UL << smp_processor_id())) \ printk("ASSERT %s:%u %s readlocked\n", __FILE__, __LINE__, #l); \ - else if ((l)->write_locked_map & (1 << smp_processor_id())) \ + else if ((l)->write_locked_map & (1UL << smp_processor_id())) \ printk("ASSERT %s:%u %s writelocked\n", __FILE__, __LINE__, #l); \ } while(0) @@ -91,7 +91,7 @@ #define READ_UNLOCK(lk) \ do { \ - if (!((lk)->read_locked_map & (1 << smp_processor_id()))) \ + if (!((lk)->read_locked_map & (1UL << smp_processor_id()))) \ printk("ASSERT: %s:%u %s not readlocked\n", \ __FILE__, __LINE__, #lk); \ clear_bit(smp_processor_id(), &(lk)->read_locked_map); \ diff -Nur linux-2.4.19/include/linux/pagg.h linux-2.4.19-sgi211r3/include/linux/pagg.h --- linux-2.4.19/include/linux/pagg.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/pagg.h Thu Aug 8 09:26:58 2002 @@ -0,0 +1,259 @@ +/* + * PAGG (Process Aggregates) interface + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + * + * Description: This file, include/linux/pagg.h, contains the data + * structure definitions and function prototypes used to + * implement process aggrefates (paggs). Paggs provides a + * generalized was to implement process groupings or + * containers. Modules use these functions to register + * with the kernel as providers of process aggregation + * containers. The pagg data structures define the + * callback functions and data access pointers back into + * the pagg modules. + * + * Created: 2000.05.23 Sam Watters + * + * Changes: 2000.07.15 Sam Watters + * Changed definitions of structures. + * 2001.04.15 Sam Watters + * Added macros to use when handling pagg_s structs. + * Changed names of some existing macros to better + * describe what is being manipulated. Added pagg_list_s + * struct definition. + */ +#ifndef _PAGG_H +#define _PAGG_H + +#include + +#ifdef CONFIG_PAGG + +#include +#include + +/* + * Used by task_struct to manage a list of pagg attachments for the task. + * The list will be used to hold references to pagg_s structures. + * These structures define the pagg attachments for the task. + * + * STRUCT MEMBERS: + * list: The list head pointer for the list of pagg_s + * structures. + * sem: The semaphore used to lock the list. + */ +struct pagg_list_s { + struct list_head head; + struct rw_semaphore sem; +}; /* pagg_list_s */ + + +/* + * Macro used to initialize the pagg_list_s structure at declaration + * + * Macro arguments: + * l: the pagg list (struct pagg_list_s) + */ +#define PAGG_LIST_INIT(l) \ +{ \ + LIST_HEAD_INIT(l.head), \ + __RWSEM_INITIALIZER(l.sem), \ +} + +/* Macro used to initialize a pagg_list_s structure after declaration + * + * Macro arguments: + * l: the pagg list (struct pagg_list_s) + */ +#define INIT_PAGG_LIST(l) \ +do { \ + INIT_LIST_HEAD(l.head); \ + init_rwsem(l.sem); \ +} while(0); + + +#define INIT_TASK_PAGG_LIST_INIT(l) \ + pagg_list: PAGG_LIST_INIT(l.pagg_list), + +/* + * Used by task_struct to manage list of pagg attachments for the process. + * Each pagg_s provides the link between the process and the + * correct pagg container. + * + * STRUCT MEMBERS: + * hook: Reference to pagg module structure. That struct + * holds the name key and function pointers. + * data: Opaque data pointer - defined by pagg modules. + * entry: List pointers + */ +struct pagg_s { + struct pagg_hook_s *hook; + void *data; + struct list_head entry; +}; /* pagg_s */ + +/* + * Used by pagg modules to define the callback functions into the + * module. + * + * STRUCT MEMBERS: + * name: The name of the pagg container type provided by + * the module. This will be set by the pagg module. + * do_attach: Function pointer to function used when attaching + * a process to the pagg container referenced by + * this struct. + * do_detach: Function pointer to function used when detaching + * a process to the pagg container referenced by + * this struct. + * do_init: Function pointer to initialization function. This + * function is used when the module is loaded to attach + * existing processes to a default container as defined by + * the pagg module. This is optional and may be set to + * NULL if it is not needed by the pagg module. + * do_paggctl: Function pointer to paggctl() system call handler + * for the pagg module. This is optional and may be set + * to NULL if it is not needed by the pagg module. + * data: Opaque data pointer - defined by pagg modules. + * module: Pointer to kernel module struct. Used to increment & + * decrement the use count for the module. + * entry: List pointers + */ +struct pagg_hook_s { + /* Name Key - restricted to 32 characters */ + char *name; + /* Function pointers */ + int (*do_attach)(struct task_struct *, + struct pagg_s *, + void *); + int (*do_detach)(struct task_struct *, + struct pagg_s *); + int (*do_init)(struct task_struct *, + struct pagg_s *); + int (*do_paggctl)(int, void *); + /* Opaque module specific data */ + void *data; + /* Module reference */ + struct module *module; + /* List pointers */ + struct list_head entry; +}; /* pagg_hook_s */ + + +/* Kernel service functions for providing PAGG support */ +extern struct pagg_s *get_pagg(struct task_struct *task, char *key); +extern struct pagg_s *alloc_pagg(struct task_struct *task, + struct pagg_hook_s *pt); +extern void free_pagg(struct pagg_s *pagg); +extern int register_pagg_hook(struct pagg_hook_s *pt_new); +extern int unregister_pagg_hook(struct pagg_hook_s *pt_old); +extern int attach_pagg_list(struct task_struct *to_task, + struct task_struct *from_task); +extern int detach_pagg_list(struct task_struct *task); + +/* + * Macro used when a child process must inherit attachment to pagg + * containers from the parent. + * + * Arguments: + * ct: child (struct task_struct *) + * pt: parent (struct task_struct *) + * cf: clone_flags + */ +#define attach_pagg_list_chk(ct, pt, cf) \ +do { \ + INIT_PAGG_LIST(&ct->pagg_list); \ + if (!(cf & CLONE_PID) && !list_empty(&pt->pagg_list.head)) { \ + if (attach_pagg_list(ct, pt) != 0) \ + goto bad_fork_cleanup; \ + } \ +} while(0); + +/* + * Macro used when a process must detach form pagg containers to which it + * is currenlty a member. + * + * Aguments: + * t: task (struct task_struct *) + */ +#define detach_pagg_list_chk(t) \ +do { \ + if (!list_empty(&t->pagg_list.head)) { \ + detach_pagg_list(t); \ + } \ +} while(0); + + +/* + * Utility macros for pagg handling and locking pagg lists. + * + * Arguments: + * t: task (struct task_list *) + * p: pagg (struct pagg_s *) + * d: data (ptr to data maintained by the + * pagg module - converts to void ptr) + */ + /* Invoke module detach callback for the pagg & task */ +#define detach_pagg(t, p) p->hook->do_detach(t, p) + /* Invoke module attach callback for the pagg & task */ +#define attach_pagg(t, p, d) p->hook->do_attach(t, p, (void *)d) + /* Allows module to set data item for pagg */ +#define set_pagg(p, d) p->data = (void *)d + /* Down the read semaphore for the task's pagg_list */ +#define read_lock_pagg_list(t) down_read(&t->pagg_list.sem) + /* Up the read semaphore for the task's pagg_list */ +#define read_unlock_pagg_list(t) up_read(&t->pagg_list.sem) + /* Down the write semaphore for the task's pagg_list */ +#define write_lock_pagg_list(t) down_write(&t->pagg_list.sem) + /* Up the write semaphore for the task's pagg_list */ +#define write_unlock_pagg_list(t) up_write(&t->pagg_list.sem) + + + + + +#else /* CONFIG_PAGG */ + + +#define INIT_TASK_PAGG_LIST_INIT(l) +#define INIT_PAGG_LIST(l) + +/* + * Replacement macros used when PAGG (Process Aggregates) support is not + * compiled into the kernel. + */ +#define attach_pagg_list_chk(ct, pt, cf) do { } while(0); +#define detach_pagg_list_chk(t) do { } while(0); + +#endif /* CONFIG_PAGG */ + +#endif /* _PAGG_H */ diff -Nur linux-2.4.19/include/linux/paggctl.h linux-2.4.19-sgi211r3/include/linux/paggctl.h --- linux-2.4.19/include/linux/paggctl.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/paggctl.h Thu Aug 8 09:26:58 2002 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + * + * Description: This file, include/linux/paggctl.h, contains the data + * structure definitions used by user-mode programs to + * communicate with the PAGG modules via the paggctl + * function. + * + * Created: 2000.07.15 Sam Watters + * + * Changes: 2001.01.30 Sam Watters + * Moved file to include/linux/paggctl.h & cleanup + * 2001.04.15 Sam Watters + * Added definitions PAGG_MOD, PAGG_HOOK_* and pagg_hook_*_s structs. + * 2001.12.12 Sam Watters + * Changed PAGG_HOOK_* and pagg_hook_*_s names to PAGG_HOOK_* and + * pagg_hook_*_s. + */ + +#ifndef _LINUX_PAGGCTL_H +#define _LINUX_PAGGCTL_H +#ifndef __KERNEL__ +#include +#include +#include +#endif + +#define PAGG_NAMELN 32 /* Max chars in PAGG module name */ +#define PAGG_NAMESTR PAGG_NAMELN+1 /* PAGG mod name string including + * room for end-of-string = '\0' */ + +/* + * ========================================== + * PAGG hook registration Query definitions + * ========================================== + */ + +#define PAGG_HOOK NULL /* No string indicates, PAGG module query */ + +#define PAGG_HOOK_GETCNT 0 /* Get number of registered PAGG modules */ +#define PAGG_HOOK_GETLST 1 /* Get list of registered PAGG modules */ +#define PAGG_HOOK_GETCHK 2 /* Check if specific PAGG module exists */ + +/* + * ==================== + * JOB PAGG definitions + * ==================== + */ + +/* + * Module identifier string + */ +#define PAGG_JOB "job" + +/* + * + * Define paggctl options available in the job module + * + */ + +#define JOB_NOOP 0 /* No-op options */ + +#define JOB_CREATE 1 /* Create a job - uid = 0 only */ +#define JOB_ATTACH 2 /* RESERVED */ +#define JOB_DETACH 3 /* RESERVER */ +#define JOB_GETJID 4 /* Get Job ID for specificed pid */ +#define JOB_WAITJID 5 /* Wait for job to complete */ +#define JOB_KILLJID 6 /* Send signal to job */ +#define JOB_GETJIDCNT 9 /* Get number of JIDs on system */ +#define JOB_GETJIDLST 10 /* Get list of JIDs on system */ +#define JOB_GETPIDCNT 11 /* Get number of PIDs in JID */ +#define JOB_GETPIDLST 12 /* Get list of PIDs in JID */ +#define JOB_SETJLIMIT 13 /* Future: set job limits info */ +#define JOB_GETJLIMIT 14 /* Future: get job limits info */ +#define JOB_GETJUSAGE 15 /* Future: get job res. usage */ +#define JOB_FREE 16 /* Future: Free job entry */ +#define JOB_GETUSER 17 /* Get owner for job */ +#define JOB_GETPRIMEPID 18 /* Get prime pid for job */ +#define JOB_SETHID 19 /* Set HID for jid values */ +#define JOB_DETACHJID 20 /* Detach all tasks from job */ +#define JOB_DETACHPID 21 /* Detach a task from job */ +#define JOB_OPT_MAX 22 /* Should always be highest number */ + + +/* + * + * Define paggctl request structures for job module + * + */ + +typedef struct job_create_s { + uint64_t r_jid; /* Return value of JID */ + uint64_t jid; /* Jid value requested */ + uid_t user; /* UID of user associated with job */ + int options;/* creation options - unused */ +} job_create_t; + + +typedef struct job_getjid_s { + uint64_t r_jid; /* Returned value of JID */ + pid_t pid; /* Info requested for PID */ +} job_getjid_t; + + +typedef struct job_waitjid_s { + uint64_t r_jid; /* Returned value of JID */ + uint64_t jid; /* Waiting on specified JID */ + int stat; /* Status information on JID */ + int options;/* Waiting options */ +} job_waitjid_t; + + +typedef struct job_killjid_s { + int r_val; /* Return value of kill request */ + uint64_t jid; /* Sending signal to all PIDs in JID */ + int sig; /* Signal to send */ +} job_killjid_t; + + +typedef struct job_jidcnt_s { + int r_val; /* Number of JIDs on system */ +} job_jidcnt_t; + + +typedef struct job_jidlst_s { + int r_val; /* Number of JIDs in list */ + uint64_t *jid; /* List of JIDs */ +} job_jidlst_t; + + +typedef struct job_pidcnt_s { + int r_val; /* Number of PIDs in JID */ + uint64_t jid; /* Getting count of JID */ +} job_pidcnt_t; + + +typedef struct job_pidlst_s { + int r_val; /* Number of PIDs in list */ + pid_t *pid; /* List of PIDs */ + uint64_t jid; +} job_pidlst_t; + + +typedef struct job_user_s { + uint16_t r_user; /* The UID of the owning user */ + uint64_t jid; /* Get the UID for this job */ +} job_user_t; + +typedef struct job_primepid_s { + pid_t r_pid; /* The prime pid */ + uint64_t jid; /* Get the prime pid for this job */ +} job_primepid_t; + +typedef struct job_sethid_s { + unsigned long r_hid; /* Value that was set */ + unsigned long hid; /* Value to set to */ +} job_sethid_t; + + +typedef struct job_detachjid_s { + int r_val; /* Number of tasks detached from job */ + uint64_t jid; /* Job to detach processes from */ +} job_detachjid_t; + +typedef struct job_detachpid_s { + uint64_t r_jid; /* Jod ID task was attached to */ + pid_t pid; /* Task to detach from job */ +} job_detachpid_t; + + +typedef char pagg_namestr_t[PAGG_NAMESTR]; + +typedef struct pagg_hook_getlst_s { + int r_val; /* Count of names in list */ + pagg_namestr_t *list; /* List of PAGG module names */ +} pagg_hook_getlst_t; + +typedef struct pagg_hook_getchk_s { + int r_val; /* 1 = found, 0 = not found */ + pagg_namestr_t name; /* PAGG module name to find */ +} pagg_hook_getchk_t; + + +/* + * ===================================================== + * NEW definitions for PAGG module support would go here + * ===================================================== + */ +#endif /* _LINUX_PAGGCTL_H */ diff -Nur linux-2.4.19/include/linux/pci_ids.h linux-2.4.19-sgi211r3/include/linux/pci_ids.h --- linux-2.4.19/include/linux/pci_ids.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/pci_ids.h Thu Nov 7 08:44:57 2002 @@ -509,6 +509,8 @@ #define PCI_DEVICE_ID_HP_DIVA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA2 0x104A #define PCI_DEVICE_ID_HP_SP2_0 0x104B +#define PCI_DEVICE_ID_HP_REO_SBA 0x10f0 +#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 #define PCI_DEVICE_ID_HP_ZX1_SBA 0x1229 #define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a #define PCI_DEVICE_ID_HP_ZX1_LBA 0x122e @@ -752,6 +754,10 @@ #define PCI_VENDOR_ID_SGI 0x10a9 #define PCI_DEVICE_ID_SGI_IOC3 0x0003 +#define PCI_DEVICE_ID_SGI_IOC4 0x100a +#define PCI_DEVICE_ID_SGI_IO9_ETH 0x8010 +#define PCI_DEVICE_ID_SGI_570XC 0x8011 +#define PCI_DEVICE_ID_SGI_570XF 0x8012 #define PCI_VENDOR_ID_ACC 0x10aa #define PCI_DEVICE_ID_ACC_2056 0x0000 @@ -882,6 +888,7 @@ #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 #define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4 0x0258 #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_8849 0x8849 @@ -1547,6 +1554,10 @@ #define PCI_VENDOR_ID_PDC 0x15e9 #define PCI_DEVICE_ID_PDC_1841 0x1841 + +#define PCI_VENDOR_ID_ALTIMA 0x173b +#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8 +#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea #define PCI_VENDOR_ID_ALTIMA 0x173b #define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8 diff -Nur linux-2.4.19/include/linux/posix_acl_xattr.h linux-2.4.19-sgi211r3/include/linux/posix_acl_xattr.h --- linux-2.4.19/include/linux/posix_acl_xattr.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/posix_acl_xattr.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,66 @@ +/* + File: linux/posix_acl_xattr.h + + Extended attribute system call representation of Access Control Lists. + + Copyright (C) 2000 by Andreas Gruenbacher + */ +#ifndef _POSIX_ACL_XATTR_H +#define _POSIX_ACL_XATTR_H + +/* Extended attribute names */ +#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access" +#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default" + +/* Supported ACL a_version fields */ +#define POSIX_ACL_XATTR_VERSION 0x0002 + + +/* An undefined entry e_id value */ +#define ACL_UNDEFINED_ID (-1) + +/* ACL entry e_tag field values */ +#define ACL_USER_OBJ (0x01) +#define ACL_USER (0x02) +#define ACL_GROUP_OBJ (0x04) +#define ACL_GROUP (0x08) +#define ACL_MASK (0x10) +#define ACL_OTHER (0x20) + +/* ACL entry e_perm bitfield values */ +#define ACL_READ (0x04) +#define ACL_WRITE (0x02) +#define ACL_EXECUTE (0x01) + + +typedef struct { + __u16 e_tag; + __u16 e_perm; + __u32 e_id; +} posix_acl_xattr_entry; + +typedef struct { + __u32 a_version; + posix_acl_xattr_entry a_entries[0]; +} posix_acl_xattr_header; + + +static inline size_t +posix_acl_xattr_size(int count) +{ + return (sizeof(posix_acl_xattr_header) + + (count * sizeof(posix_acl_xattr_entry))); +} + +static inline int +posix_acl_xattr_count(size_t size) +{ + if (size < sizeof(posix_acl_xattr_header)) + return -1; + size -= sizeof(posix_acl_xattr_header); + if (size % sizeof(posix_acl_xattr_entry)) + return -1; + return size / sizeof(posix_acl_xattr_entry); +} + +#endif /* _POSIX_ACL_XATTR_H */ diff -Nur linux-2.4.19/include/linux/posix_cap_xattr.h linux-2.4.19-sgi211r3/include/linux/posix_cap_xattr.h --- linux-2.4.19/include/linux/posix_cap_xattr.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/posix_cap_xattr.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,27 @@ +/* + File: linux/posix_cap_xattr.h + + Extended attribute representation of capabilities +*/ +#ifndef _POSIX_CAP_XATTR_H +#define _POSIX_CAP_XATTR_H + +#define POSIX_CAP_XATTR "system.posix_capabilities" +#define POSIX_CAP_XATTR_VERSION 0x0001 + +typedef __u64 posix_cap_xattr_value; + +typedef struct { + __u32 c_version; + __u32 c_abiversion; + posix_cap_xattr_value c_effective; + posix_cap_xattr_value c_permitted; + posix_cap_xattr_value c_inheritable; +} posix_cap_xattr; + +static inline size_t posix_cap_xattr_size(void) +{ + return (sizeof(posix_cap_xattr)); +} + +#endif /* _POSIX_CAP_XATTR_H */ diff -Nur linux-2.4.19/include/linux/prctl.h linux-2.4.19-sgi211r3/include/linux/prctl.h --- linux-2.4.19/include/linux/prctl.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-sgi211r3/include/linux/prctl.h Mon Jun 3 15:32:58 2002 @@ -26,4 +26,227 @@ # define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */ # define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */ +#define SGI_PRCTL_EXTENSIONS 1 +#ifdef SGI_PRCTL_EXTENSIONS + +/* + * Get/Set process affinity. These system calls allow a user process to + * control the cpus that the cpu will run on. + * + * long cpuset; + * + * To select cpus that a process can execute on: + * cpuset = cpu 0, bit n -> cpu n, etc + * prctl(PR_SET_RUNON, cpuset) + * + * To get the current cpuset that the proces is allowed to execute on: + * prctl(PR_GET_RUNON, &cpuset) + * + * CPU affinity selections are inherited across fork(). + * + * NOTE: this interface is temporary & will be replaced!!!! + */ +#define PR_GET_RUNON 500 +#define PR_SET_RUNON 501 + + +/* + * Translate user virtual address to a physical address + * (This request is available ONLY on IA64) + * + * long paddr, vaddr; + * int status; + * + * status = prctl(PR_GET_PHYSICAL_ADDRESS, vaddr, &paddr); + * + * + * Input: + * vaddr - address to be translated. If the vaddr is valid but + * no memory is currently assigned to the vaddr, it will + * be assigned (or paged in) as part of the prctl request. + * Note, however, that unless the page is locked, the physical + * address can change at any time. + * + * Output: + * paddr - Contains the physical address that corresponds to vaddr. If + * vaddr is invalid, a -1 is returned. + * status- 0 or ERRNO. + * + */ +#define PR_GET_PHYSICAL_ADDRESS 502 + +/* + * Trigger the logic analyzer + * + * prctl(PR_TRIGGER_LOGIC_ANALYZER, data) + * + * Writes the value of to the cpuid register + */ +#define PR_TRIGGER_LOGIC_ANALYZER 503 + +/* + * Get the value of the LID register + * + * int lid; + * + * prctl(PR_GET_LID_REGISTER, &lid); + */ +#define PR_GET_LID_REGISTER 504 + +/* + * PR calls 600-607 provide a system call interface to support + * CpuMemSets. See the user include file cpumemsets.h for more + * documentation. The nested struct and array data structures + * provided at the user API of CpuMemSets are passed into the + * kernel via packed records of ints, using the following prctl + * calls. + * + * These prctl(2) calls are not pretty. At some point, an entirely + * different mechanism may be used by the user level CpuMemSets + * code to make the needed system calls. Do -not- rely on the + * following interface; rather rely on the libcpumemsets API, + * as documented in /usr/include/cpumemsets.h. + */ + +/* + * Get the packed record size of a cpumemmap. + * + * unsigned long req[3]; + * int size; + * int error; + * error = prctl(PR_QUERY_CMM_SIZE, req, &size); + * + * Input: req[0] is cms_choice_t (CMS_CURRENT, CMS_CHILD, CMS_VMAREA, CMS_KERNEL) + * req[1] is pid_t + * req[2] is start (for CMS_VMAREA) + * Output: packed record size of cpumemmap copied to &size + */ +#define PR_QUERY_CMM_SIZE 600 + +/* + * Get the packed record size of a cpumemset. + * + * unsigned long req[3]; + * int size; + * int error; + * error = prctl(PR_QUERY_CMS_SIZE, req, &size); + * + * Input: req[0] is cms_choice_t (CMS_CURRENT, CMS_CHILD, CMS_VMAREA, CMS_KERNEL) + * req[1] is pid_t + * req[2] is start (for CMS_VMAREA) + * Output: packed record size of cpumemset copied to &size + */ +#define PR_QUERY_CMS_SIZE 601 + +/* + * Get the packed record of a cpumemmap. + * + * unsigned long req[3]; + * int *rec; -- int alligned buffer to receive packed record of size bytes -- + * int size; + * int error; + * error = prctl(PR_QUERY_CMM, req, rec, size); + * + * Input: req[0] is cms_choice_t (CMS_CURRENT, CMS_CHILD, CMS_VMAREA, CMS_KERNEL) + * req[1] is pid_t + * req[2] is start (for CMS_VMAREA) + * + * Output: If the cmm packed record is larger than size, the call fails. + * Else the packed record is copied to rec. + * + * Packed record 'rec' format (all integers): + * cms_mappol_t, + * nr_cpus, + * cpus[0]...cpus[nr_cpus-1], + * nr_mems, + * mems[0]...mems[nr_cpus-1] + */ +#define PR_QUERY_CMM 602 + +/* + * Get the packed record of a cpumemset. + * + * unsigned long req[3]; + * int *rec; -- int alligned buffer to receive packed record of size bytes -- + * int size; + * int error; + * error = prctl(PR_QUERY_CMS, req, rec, size); + * + * Input: req[0] is cms_choice_t (CMS_CURRENT, CMS_CHILD, CMS_VMAREA, CMS_KERNEL) + * req[1] is pid_t + * req[2] is start (for CMS_VMAREA) + * + * Output: If the cms packed record is larger than size, the call fails. + * Else the packed record is copied to rec. + * + * Packed record 'rec' format (all integers): + * cms_setpol_t, + * nr_cpus, + * cpus[0]...cpus[nr_cpus-1], + * nr_mems, + * mems[0]->nr_cpus, + * mems[0]->cpus[0]...mems[0]->cpus[mems[0]->nr_cpus-1], + * mems[0]->nr_mems, + * mems[0]->mems[0]...mems[0]->mems[mems[0]->nr_mems-1], + * ..., + * mems[nr_mems-1]->nr_cpus, + * mems[nr_mems-1]->cpus[0]...mems[nr_mems-1]->cpus[mems[nr_mems-1]->nr_mems-1] + */ +#define PR_QUERY_CMS 603 + +/* + * Set the cpumemmap. + * int *data; + * int size; + * int error; + * error = prctl(PR_SET_CMM, req, rec, size); + * + * Input: req[0] is cms_choice_t (CMS_CURRENT, CMS_CHILD, CMS_VMAREA, CMS_KERNEL) + * req[1] is pid_t + * req[2] is start (for CMS_VMAREA) + * + * rec is the address of a memory buffer of size 'size'. + * Packed record 'rec' format same as in PR_QUERY_CMM. + * + * Output: on success, error = 0, else error < 0 + */ +#define PR_SET_CMM 604 + +/* + * Set the cpumemset. + * int *data; + * int size; + * int error; + * error = prctl(PR_SET_CMS, req, rec, size); + * + * Input: req[0] is cms_choice_t (CMS_CURRENT, CMS_CHILD, CMS_VMAREA, CMS_KERNEL) + * req[1] is pid_t + * req[2] is start (for CMS_VMAREA) + * + * rec is the address of a memory buffer of size 'size'. + * Packed record 'rec' format same as in PR_QUERY_CMS. + * + * Output: on success, error = 0, else error < 0 + */ +#define PR_SET_CMS 605 + +/* + * "606" was intended for PR_CMS_BULK: Bulk Remap of cpumemmap. + * But this facility is not supported. + */ +#define PR_CMS_UNUSED 606 + +/* + * Return number of cpumemsets application CPU on which executing + * int error; + * error = prctl(PR_GET_CPU); + * + * Input: none + * + * Output: application CPU number (or -1 if not implemented) + */ +#define PR_GET_CPU 607 + +#endif + #endif /* _LINUX_PRCTL_H */ diff -Nur linux-2.4.19/include/linux/quota.h linux-2.4.19-sgi211r3/include/linux/quota.h --- linux-2.4.19/include/linux/quota.h Thu Nov 22 10:38:31 2001 +++ linux-2.4.19-sgi211r3/include/linux/quota.h Wed Oct 16 14:02:58 2002 @@ -40,30 +40,22 @@ #define _LINUX_QUOTA_ #include +#include -/* - * Convert diskblocks to blocks and the other way around. - */ -#define dbtob(num) (num << BLOCK_SIZE_BITS) -#define btodb(num) (num >> BLOCK_SIZE_BITS) +#define __DQUOT_VERSION__ "dquot_6.5.1" +#define __DQUOT_NUM_VERSION__ 6*10000+5*100+1 -/* - * Convert count of filesystem blocks to diskquota blocks, meant - * for filesystems where i_blksize != BLOCK_SIZE - */ -#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE) +typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */ +typedef __u64 qsize_t; /* Type in which we store sizes */ -/* - * Definitions for disk quotas imposed on the average user - * (big brother finally hits Linux). - * - * The following constants define the amount of time given a user - * before the soft limits are treated as hard limits (usually resulting - * in an allocation failure). The timer is started when the user crosses - * their soft limit, it is reset when they go below their soft limit. - */ -#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ -#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ +/* Size of blocks in which are counted size limits */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +/* Conversion routines from and to quota blocks */ +#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) +#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) #define MAXQUOTAS 2 #define USRQUOTA 0 /* element used for user quotas */ @@ -78,9 +70,6 @@ "undefined", \ }; -#define QUOTAFILENAME "quota" -#define QUOTAGROUP "staff" - /* * Command definitions for the 'quotactl' system call. * The commands are broken into a main command defined below @@ -91,61 +80,122 @@ #define SUBCMDSHIFT 8 #define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) -#define Q_QUOTAON 0x0100 /* enable quotas */ -#define Q_QUOTAOFF 0x0200 /* disable quotas */ -#define Q_GETQUOTA 0x0300 /* get limits and usage */ -#define Q_SETQUOTA 0x0400 /* set limits and usage */ -#define Q_SETUSE 0x0500 /* set usage */ -#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ -#define Q_SETQLIM 0x0700 /* set limits */ -#define Q_GETSTATS 0x0800 /* get collected stats */ -#define Q_RSQUASH 0x1000 /* set root_squash option */ - -/* - * The following structure defines the format of the disk quota file - * (as it appears on disk) - the file is an array of these structures - * indexed by user or group number. +#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */ +#define Q_QUOTAON 0x800002 /* turn quotas on */ +#define Q_QUOTAOFF 0x800003 /* turn quotas off */ +#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ +#define Q_GETINFO 0x800005 /* get information about quota files */ +#define Q_SETINFO 0x800006 /* set information about quota files */ +#define Q_GETQUOTA 0x800007 /* get user quota structure */ +#define Q_SETQUOTA 0x800008 /* set user quota structure */ + +/* + * Quota structure used for communication with userspace via quotactl + * Following flags are used to specify which fields are valid */ -struct dqblk { +#define QIF_BLIMITS 1 +#define QIF_SPACE 2 +#define QIF_ILIMITS 4 +#define QIF_INODES 8 +#define QIF_BTIME 16 +#define QIF_ITIME 32 +#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) +#define QIF_USAGE (QIF_SPACE | QIF_INODES) +#define QIF_TIMES (QIF_BTIME | QIF_ITIME) +#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) + +struct if_dqblk { + __u64 dqb_bhardlimit; + __u64 dqb_bsoftlimit; + __u64 dqb_curspace; + __u64 dqb_ihardlimit; + __u64 dqb_isoftlimit; + __u64 dqb_curinodes; + __u64 dqb_btime; + __u64 dqb_itime; + __u32 dqb_valid; +}; + +/* + * Structure used for setting quota information about file via quotactl + * Following flags are used to specify which fields are valid + */ +#define IIF_BGRACE 1 +#define IIF_IGRACE 2 +#define IIF_FLAGS 4 +#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) + +struct if_dqinfo { + __u64 dqi_bgrace; + __u64 dqi_igrace; + __u32 dqi_flags; + __u32 dqi_valid; +}; + +#ifdef __KERNEL__ + +#include +#include +#include + +/* + * Data for one user/group kept in memory + */ +struct mem_dqblk { __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ - __u32 dqb_curblocks; /* current block count */ + qsize_t dqb_curspace; /* current used space */ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ __u32 dqb_isoftlimit; /* preferred inode limit */ __u32 dqb_curinodes; /* current # allocated inodes */ - time_t dqb_btime; /* time limit for excessive disk use */ - time_t dqb_itime; /* time limit for excessive inode use */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive inode use */ }; /* - * Shorthand notation. + * Data for one quotafile kept in memory */ -#define dq_bhardlimit dq_dqb.dqb_bhardlimit -#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit -#define dq_curblocks dq_dqb.dqb_curblocks -#define dq_ihardlimit dq_dqb.dqb_ihardlimit -#define dq_isoftlimit dq_dqb.dqb_isoftlimit -#define dq_curinodes dq_dqb.dqb_curinodes -#define dq_btime dq_dqb.dqb_btime -#define dq_itime dq_dqb.dqb_itime +struct quota_format_type; + +struct mem_dqinfo { + struct quota_format_type *dqi_format; + int dqi_flags; + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + union { + struct v1_mem_dqinfo v1_i; + struct v2_mem_dqinfo v2_i; + } u; +}; + +#define DQF_MASK 0xffff /* Mask for format specific flags */ +#define DQF_INFO_DIRTY 0x10000 /* Is info dirty? */ +#define DQF_ANY_DQUOT_DIRTY 0x20000 /* Is any dquot dirty? */ -#define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk))) +extern inline void mark_info_dirty(struct mem_dqinfo *info) +{ + info->dqi_flags |= DQF_INFO_DIRTY; +} + +#define info_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY) + +#define info_any_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY ||\ + (info)->dqi_flags & DQF_ANY_DQUOT_DIRTY) + +#define sb_dqopt(sb) (&(sb)->s_dquot) struct dqstats { - __u32 lookups; - __u32 drops; - __u32 reads; - __u32 writes; - __u32 cache_hits; - __u32 allocated_dquots; - __u32 free_dquots; - __u32 syncs; + int lookups; + int drops; + int reads; + int writes; + int cache_hits; + int allocated_dquots; + int free_dquots; + int syncs; }; -#ifdef __KERNEL__ - -extern int nr_dquots, nr_free_dquots; -extern int dquot_root_squash; +extern struct dqstats dqstats; #define NR_DQHASH 43 /* Just an arbitrary number */ @@ -162,37 +212,113 @@ struct list_head dq_free; /* Free list element */ wait_queue_head_t dq_wait_lock; /* Pointer to waitqueue on dquot lock */ wait_queue_head_t dq_wait_free; /* Pointer to waitqueue for quota to be unused */ - int dq_count; /* Reference count */ + int dq_count; /* Use count */ + int dq_dup_ref; /* Number of duplicated refences */ /* fields after this point are cleared when invalidating */ struct super_block *dq_sb; /* superblock this applies to */ unsigned int dq_id; /* ID this applies to (uid, gid) */ kdev_t dq_dev; /* Device this applies to */ + loff_t dq_off; /* Offset of dquot on disk */ short dq_type; /* Type of quota */ short dq_flags; /* See DQ_* */ unsigned long dq_referenced; /* Number of times this dquot was referenced during its lifetime */ - struct dqblk dq_dqb; /* Diskquota usage */ + struct mem_dqblk dq_dqb; /* Diskquota usage */ }; #define NODQUOT (struct dquot *)NULL -/* - * Flags used for set_dqblk. - */ -#define SET_QUOTA 0x02 -#define SET_USE 0x04 -#define SET_QLIMIT 0x08 - #define QUOTA_OK 0 #define NO_QUOTA 1 +/* Operations which must be implemented by each quota format */ +struct quota_format_ops { + int (*check_quota_file)(struct super_block *sb, int type); /* Detect whether file is in our format */ + int (*read_file_info)(struct super_block *sb, int type); /* Read main info about file - called on quotaon() */ + int (*write_file_info)(struct super_block *sb, int type); /* Write main info about file */ + int (*free_file_info)(struct super_block *sb, int type); /* Called on quotaoff() */ + int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ + int (*commit_dqblk)(struct dquot *dquot); /* Write (or delete) structure for one user */ +}; + +/* Operations working with dquots */ +struct dquot_operations { + void (*initialize) (struct inode *, int); + void (*drop) (struct inode *); + int (*alloc_space) (struct inode *, qsize_t, int); + int (*alloc_inode) (const struct inode *, unsigned long); + void (*free_space) (struct inode *, qsize_t); + void (*free_inode) (const struct inode *, unsigned long); + int (*transfer) (struct inode *, struct iattr *); +}; + +/* Operations handling requests from userspace */ +struct quotactl_ops { + int (*quota_on)(struct super_block *, int, int, char *); + int (*quota_off)(struct super_block *, int); + int (*quota_sync)(struct super_block *, int); + int (*get_info)(struct super_block *, int, struct if_dqinfo *); + int (*set_info)(struct super_block *, int, struct if_dqinfo *); + int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); + int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); + int (*get_xstate)(struct super_block *, struct fs_quota_stat *); + int (*set_xstate)(struct super_block *, unsigned int, int); + int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); + int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); +}; + +struct quota_format_type { + int qf_fmt_id; /* Quota format id */ + struct quota_format_ops *qf_ops; /* Operations of format */ + struct module *qf_owner; /* Module implementing quota format */ + struct quota_format_type *qf_next; +}; + +#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ +#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ + +struct quota_info { + unsigned int flags; /* Flags for diskquotas on this device */ + struct semaphore dqio_sem; /* lock device while I/O in progress */ + struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */ + struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ + struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ + struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ +}; + +/* Inline would be better but we need to dereference super_block which is not defined yet */ +#define mark_dquot_dirty(dquot) do {\ + dquot->dq_flags |= DQ_MOD;\ + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_flags |= DQF_ANY_DQUOT_DIRTY;\ +} while (0) + +#define dquot_dirty(dquot) ((dquot)->dq_flags & DQ_MOD) + +static inline int is_enabled(struct quota_info *dqopt, int type) +{ + switch (type) { + case USRQUOTA: + return dqopt->flags & DQUOT_USR_ENABLED; + case GRPQUOTA: + return dqopt->flags & DQUOT_GRP_ENABLED; + } + return 0; +} + +#define sb_any_quota_enabled(sb) (is_enabled(sb_dqopt(sb), USRQUOTA) | is_enabled(sb_dqopt(sb), GRPQUOTA)) + +#define sb_has_quota_enabled(sb, type) (is_enabled(sb_dqopt(sb), type)) + +int register_quota_format(struct quota_format_type *fmt); +void unregister_quota_format(struct quota_format_type *fmt); + #else # /* nodep */ include __BEGIN_DECLS -long quotactl __P ((int, const char *, int, caddr_t)); +long quotactl __P ((unsigned int, const char *, int, caddr_t)); __END_DECLS #endif /* __KERNEL__ */ diff -Nur linux-2.4.19/include/linux/quotacompat.h linux-2.4.19-sgi211r3/include/linux/quotacompat.h --- linux-2.4.19/include/linux/quotacompat.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/quotacompat.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,86 @@ +/* + * Definition of symbols used for backward compatible interface + */ + +#ifndef _LINUX_QUOTACOMPAT_ +#define _LINUX_QUOTACOMPAT_ + +#include +#include + +struct v1c_mem_dqblk { + __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ + __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ + __u32 dqb_curblocks; /* current block count */ + __u32 dqb_ihardlimit; /* maximum # allocated inodes */ + __u32 dqb_isoftlimit; /* preferred inode limit */ + __u32 dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +}; + +struct v1c_dqstats { + __u32 lookups; + __u32 drops; + __u32 reads; + __u32 writes; + __u32 cache_hits; + __u32 allocated_dquots; + __u32 free_dquots; + __u32 syncs; +}; + +struct v2c_mem_dqblk { + unsigned int dqb_ihardlimit; + unsigned int dqb_isoftlimit; + unsigned int dqb_curinodes; + unsigned int dqb_bhardlimit; + unsigned int dqb_bsoftlimit; + qsize_t dqb_curspace; + __kernel_time_t dqb_btime; + __kernel_time_t dqb_itime; +}; + +struct v2c_mem_dqinfo { + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + unsigned int dqi_flags; + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +struct v2c_dqstats { + __u32 lookups; + __u32 drops; + __u32 reads; + __u32 writes; + __u32 cache_hits; + __u32 allocated_dquots; + __u32 free_dquots; + __u32 syncs; + __u32 version; +}; + +#define Q_COMP_QUOTAON 0x0100 /* enable quotas */ +#define Q_COMP_QUOTAOFF 0x0200 /* disable quotas */ +#define Q_COMP_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ + +#define Q_V1_GETQUOTA 0x0300 /* get limits and usage */ +#define Q_V1_SETQUOTA 0x0400 /* set limits and usage */ +#define Q_V1_SETUSE 0x0500 /* set usage */ +#define Q_V1_SETQLIM 0x0700 /* set limits */ +#define Q_V1_GETSTATS 0x0800 /* get collected stats */ +#define Q_V1_RSQUASH 0x1000 /* set root_squash option */ + +#define Q_V2_SETQLIM 0x0700 /* set limits */ +#define Q_V2_GETINFO 0x0900 /* get info about quotas - graces, flags... */ +#define Q_V2_SETINFO 0x0A00 /* set info about quotas */ +#define Q_V2_SETGRACE 0x0B00 /* set inode and block grace */ +#define Q_V2_SETFLAGS 0x0C00 /* set flags for quota */ +#define Q_V2_GETQUOTA 0x0D00 /* get limits and usage */ +#define Q_V2_SETQUOTA 0x0E00 /* set limits and usage */ +#define Q_V2_SETUSE 0x0F00 /* set usage */ +#define Q_V2_GETSTATS 0x1100 /* get collected stats */ + +#endif diff -Nur linux-2.4.19/include/linux/quotaio_v1.h linux-2.4.19-sgi211r3/include/linux/quotaio_v1.h --- linux-2.4.19/include/linux/quotaio_v1.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/quotaio_v1.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,33 @@ +#ifndef _LINUX_QUOTAIO_V1_H +#define _LINUX_QUOTAIO_V1_H + +#include + +/* + * The following constants define the amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). The timer is started when the user crosses + * their soft limit, it is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +/* + * The following structure defines the format of the disk quota file + * (as it appears on disk) - the file is an array of these structures + * indexed by user or group number. + */ +struct v1_disk_dqblk { + __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ + __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ + __u32 dqb_curblocks; /* current block count */ + __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __u32 dqb_isoftlimit; /* preferred inode limit */ + __u32 dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive inode use */ +}; + +#define v1_dqoff(UID) ((loff_t)((UID) * sizeof (struct v1_disk_dqblk))) + +#endif /* _LINUX_QUOTAIO_V1_H */ diff -Nur linux-2.4.19/include/linux/quotaio_v2.h linux-2.4.19-sgi211r3/include/linux/quotaio_v2.h --- linux-2.4.19/include/linux/quotaio_v2.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/quotaio_v2.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,79 @@ +/* + * Definitions of structures for vfsv0 quota format + */ + +#ifndef _LINUX_QUOTAIO_V2_H +#define _LINUX_QUOTAIO_V2_H + +#include +#include + +/* + * Definitions of magics and versions of current quota files + */ +#define V2_INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +#define V2_INITQVERSIONS {\ + 0, /* USRQUOTA */\ + 0 /* GRPQUOTA */\ +} + +/* + * The following structure defines the format of the disk quota file + * (as it appears on disk) - the file is a radix tree whose leaves point + * to blocks of these structures. + */ +struct v2_disk_dqblk { + __u32 dqb_id; /* id this quota applies to */ + __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __u32 dqb_isoftlimit; /* preferred inode limit */ + __u32 dqb_curinodes; /* current # allocated inodes */ + __u32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ + __u32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ + __u64 dqb_curspace; /* current space occupied (in bytes) */ + __u64 dqb_btime; /* time limit for excessive disk use */ + __u64 dqb_itime; /* time limit for excessive inode use */ +}; + +/* + * Here are header structures as written on disk and their in-memory copies + */ +/* First generic header */ +struct v2_disk_dqheader { + __u32 dqh_magic; /* Magic number identifying file */ + __u32 dqh_version; /* File version */ +}; + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + __u32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ + __u32 dqi_igrace; /* Time before inode soft limit becomes hard limit */ + __u32 dqi_flags; /* Flags for quotafile (DQF_*) */ + __u32 dqi_blocks; /* Number of blocks in file */ + __u32 dqi_free_blk; /* Number of first free block in the list */ + __u32 dqi_free_entry; /* Number of block with at least one free entry */ +}; + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes so + * there will be space for exactly 18 quota-entries in a block + */ +struct v2_disk_dqdbheader { + __u32 dqdh_next_free; /* Number of next block with free entry */ + __u32 dqdh_prev_free; /* Number of previous block with free entry */ + __u16 dqdh_entries; /* Number of valid entries in block */ + __u16 dqdh_pad1; + __u32 dqdh_pad2; +}; + +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ +#define V2_DQBLKSIZE_BITS 10 +#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ +#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */ +#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ +#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ + +#endif /* _LINUX_QUOTAIO_V2_H */ diff -Nur linux-2.4.19/include/linux/quotaops.h linux-2.4.19-sgi211r3/include/linux/quotaops.h --- linux-2.4.19/include/linux/quotaops.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/quotaops.h Wed Oct 16 14:02:58 2002 @@ -20,15 +20,16 @@ /* * declaration of quota_function calls in kernel. */ -extern void dquot_initialize(struct inode *inode, short type); +extern void sync_dquots_dev(kdev_t dev, int type); +extern void sync_dquots_sb(struct super_block *sb, int type); + +extern void dquot_initialize(struct inode *inode, int type); extern void dquot_drop(struct inode *inode); -extern int quota_off(struct super_block *sb, short type); -extern int sync_dquots(kdev_t dev, short type); -extern int dquot_alloc_block(struct inode *inode, unsigned long number, char prealloc); +extern int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc); extern int dquot_alloc_inode(const struct inode *inode, unsigned long number); -extern void dquot_free_block(struct inode *inode, unsigned long number); +extern void dquot_free_space(struct inode *inode, qsize_t number); extern void dquot_free_inode(const struct inode *inode, unsigned long number); extern int dquot_transfer(struct inode *inode, struct iattr *iattr); @@ -36,7 +37,11 @@ /* * Operations supported for diskquotas. */ -#define sb_any_quota_enabled(sb) ((sb)->s_dquot.flags & (DQUOT_USR_ENABLED | DQUOT_GRP_ENABLED)) +extern struct dquot_operations dquot_operations; +extern struct quotactl_ops vfs_quotactl_ops; + +#define sb_dquot_ops (&dquot_operations) +#define sb_quotactl_ops (&vfs_quotactl_ops) static __inline__ void DQUOT_INIT(struct inode *inode) { @@ -59,50 +64,50 @@ unlock_kernel(); } -static __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) { - /* Number of used blocks is updated in alloc_block() */ - if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 1) == NO_QUOTA) { + /* Used space is updated in alloc_space() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) { unlock_kernel(); return 1; } } else - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -static __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr) +static __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) { int ret; - if (!(ret = DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr))) + if (!(ret = DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr))) mark_inode_dirty(inode); return ret; } -static __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) { - /* Number of used blocks is updated in alloc_block() */ - if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 0) == NO_QUOTA) { + /* Used space is updated in alloc_space() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) { unlock_kernel(); return 1; } } else - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -static __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr) +static __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) { int ret; - if (!(ret = DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr))) + if (!(ret = DQUOT_ALLOC_SPACE_NODIRTY(inode, nr))) mark_inode_dirty(inode); return ret; } @@ -121,19 +126,19 @@ return 0; } -static __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr) +static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) - inode->i_sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize)); + inode->i_sb->dq_op->free_space(inode, nr); else - inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9); + inode_sub_bytes(inode, nr); unlock_kernel(); } -static __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr) +static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_FREE_BLOCK_NODIRTY(inode, nr); + DQUOT_FREE_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); } @@ -159,63 +164,85 @@ return 0; } -#define DQUOT_SYNC(dev) sync_dquots(dev, -1) -#define DQUOT_OFF(sb) quota_off(sb, -1) +#define DQUOT_SYNC_DEV(dev) sync_dquots_dev(dev, -1) +#define DQUOT_SYNC_SB(sb) sync_dquots_sb(sb, -1) + +static __inline__ int DQUOT_OFF(struct super_block *sb) +{ + int ret = -ENOSYS; + + lock_kernel(); + if (sb->s_qcop && sb->s_qcop->quota_off) + ret = sb->s_qcop->quota_off(sb, -1); + unlock_kernel(); + return ret; +} #else /* * NO-OP when quota not configured. */ +#define sb_dquot_ops (NULL) +#define sb_quotactl_ops (NULL) #define DQUOT_INIT(inode) do { } while(0) #define DQUOT_DROP(inode) do { } while(0) #define DQUOT_ALLOC_INODE(inode) (0) #define DQUOT_FREE_INODE(inode) do { } while(0) -#define DQUOT_SYNC(dev) do { } while(0) +#define DQUOT_SYNC_DEV(dev) do { } while(0) +#define DQUOT_SYNC_SB(sb) do { } while(0) #define DQUOT_OFF(sb) do { } while(0) #define DQUOT_TRANSFER(inode, iattr) (0) -extern __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -extern __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr) +extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr); + DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); return 0; } -extern __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +extern __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -extern __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr) +extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr); + DQUOT_ALLOC_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); return 0; } -extern __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr) +extern __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); - inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9); + inode_sub_bytes(inode, nr); unlock_kernel(); } -extern __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr) +extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_FREE_BLOCK_NODIRTY(inode, nr); + DQUOT_FREE_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); } #endif /* CONFIG_QUOTA */ + +#define DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_PREALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_PREALLOC_BLOCK(inode, nr) DQUOT_PREALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_ALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_ALLOC_BLOCK(inode, nr) DQUOT_ALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_FREE_BLOCK_NODIRTY(inode, nr) DQUOT_FREE_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_FREE_BLOCK(inode, nr) DQUOT_FREE_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) + #endif /* _LINUX_QUOTAOPS_ */ diff -Nur linux-2.4.19/include/linux/rcupdate.h linux-2.4.19-sgi211r3/include/linux/rcupdate.h --- linux-2.4.19/include/linux/rcupdate.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/rcupdate.h Mon Oct 28 20:43:23 2002 @@ -0,0 +1,136 @@ +/* + * Read-Copy Update mechanism for mutual exclusion + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (c) IBM Corporation, 2001 + * + * Author: Dipankar Sarma + * + * Based on the original work by Paul McKenney + * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. + * Papers: + * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf + * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) + * + * For detailed explanation of Read-Copy Update mechanism see - + * http://lse.sourceforge.net/locking/rcupdate.html + * + */ + +#ifndef _LINUX_RCUPDATE_H +#define _LINUX_RCUPDATE_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include + + +/* + * Callback structure for use with call_rcu(). + */ +struct rcu_head { + struct list_head list; + void (*func)(void *obj); + void *arg; +}; + +#define RCU_HEAD_INIT(head) { LIST_HEAD_INIT(head.list), NULL, NULL } +#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT(head) +#define INIT_RCU_HEAD(ptr) do { \ + INIT_LIST_HEAD(&(ptr)->list); (ptr)->func = NULL; (ptr)->arg = NULL; \ +} while (0) + + + +/* Control variables for rcupdate callback mechanism. */ +struct rcu_ctrlblk { + spinlock_t mutex; /* Guard this struct */ + long curbatch; /* Current batch number. */ + long maxbatch; /* Max requested batch number. */ + unsigned long rcu_cpu_mask; /* CPUs that need to switch in order */ + /* for current batch to proceed. */ +}; + +/* Is batch a before batch b ? */ +static inline int rcu_batch_before(long a, long b) +{ + return (a - b) < 0; +} + +/* Is batch a after batch b ? */ +static inline int rcu_batch_after(long a, long b) +{ + return (a - b) > 0; +} + +/* + * Per-CPU data for Read-Copy UPdate. + * nxtlist - new callbacks are added here + * curlist - current batch for which quiescent cycle started if any + */ +struct rcu_data { + long qsctr; /* User-mode/idle loop etc. */ + long last_qsctr; /* value of qsctr at beginning */ + /* of rcu grace period */ + long batch; /* Batch # for current RCU batch */ + struct list_head nxtlist; + struct list_head curlist; +} ____cacheline_aligned_in_smp; + +extern struct rcu_data rcu_data[NR_CPUS]; +extern struct rcu_ctrlblk rcu_ctrlblk; + +#define RCU_qsctr(cpu) (rcu_data[(cpu)].qsctr) +#define RCU_last_qsctr(cpu) (rcu_data[(cpu)].last_qsctr) +#define RCU_batch(cpu) (rcu_data[(cpu)].batch) +#define RCU_nxtlist(cpu) (rcu_data[(cpu)].nxtlist) +#define RCU_curlist(cpu) (rcu_data[(cpu)].curlist) + +#define RCU_QSCTR_INVALID 0 + +static inline int rcu_pending(int cpu) +{ + if ((!list_empty(&RCU_curlist(cpu)) && + rcu_batch_before(RCU_batch(cpu), rcu_ctrlblk.curbatch)) || + (list_empty(&RCU_curlist(cpu)) && + !list_empty(&RCU_nxtlist(cpu))) || + test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) + return 1; + else + return 0; +} + +#ifdef CONFIG_PREEMPTION +#define rcu_read_lock() preempt_disable() +#define rcu_read_unlock() preempt_enable() +#else +#define rcu_read_lock() do {} while(0) +#define rcu_read_unlock() do {} while(0) +#endif + +extern void rcu_init(void); +extern void rcu_check_callbacks(int cpu, int user); + +/* Exported interfaces */ +extern void FASTCALL(call_rcu(struct rcu_head *head, + void (*func)(void *arg), void *arg)); +extern void synchronize_kernel(void); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_RCUPDATE_H */ diff -Nur linux-2.4.19/include/linux/sched.h linux-2.4.19-sgi211r3/include/linux/sched.h --- linux-2.4.19/include/linux/sched.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/sched.h Wed Feb 5 20:48:13 2003 @@ -6,6 +6,7 @@ extern unsigned long event; #include +#include #include #include #include @@ -26,6 +27,8 @@ #include #include #include +#include +#include struct exec_domain; @@ -73,8 +76,10 @@ #define CT_TO_SECS(x) ((x) / HZ) #define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) -extern int nr_running, nr_threads; +extern int nr_threads; extern int last_pid; +extern unsigned long nr_running(void); +extern unsigned long nr_uninterruptible(void); #include #include @@ -119,12 +124,6 @@ #define SCHED_FIFO 1 #define SCHED_RR 2 -/* - * This is an additional bit set when we want to - * yield the CPU for one re-schedule.. - */ -#define SCHED_YIELD 0x10 - struct sched_param { int sched_priority; }; @@ -142,17 +141,22 @@ * a separate lock). */ extern rwlock_t tasklist_lock; -extern spinlock_t runqueue_lock; extern spinlock_t mmlist_lock; +typedef struct task_struct task_t; + extern void sched_init(void); -extern void init_idle(void); +extern void init_idle(task_t *idle, int cpu); extern void show_state(void); extern void cpu_init (void); extern void trap_init(void); extern void update_process_times(int user); -extern void update_one_process(struct task_struct *p, unsigned long user, +extern void update_one_process(task_t *p, unsigned long user, unsigned long system, int cpu); +extern void resched_cpu(int cpu); +extern void scheduler_tick(int user_tick, int system); +extern void migration_init(void); +extern unsigned long cache_decay_ticks; #define MAX_SCHEDULE_TIMEOUT LONG_MAX extern signed long FASTCALL(schedule_timeout(signed long timeout)); @@ -162,6 +166,7 @@ extern void flush_scheduled_tasks(void); extern int start_context_thread(void); extern int current_is_keventd(void); +extern int task_has_cpu(task_t *p); /* * The default fd array needs to be at least BITS_PER_LONG, @@ -235,6 +240,7 @@ /* Architecture-specific MM context */ mm_context_t context; + unsigned long hiwater_rss, hiwater_vm; }; extern int mmlist_nr; @@ -263,6 +269,7 @@ siglock: SPIN_LOCK_UNLOCKED \ } +struct namespace; /* * Some day this will be a full-fledged user tracking system.. */ @@ -284,6 +291,8 @@ extern struct user_struct root_user; #define INIT_USER (&root_user) +typedef struct prio_array prio_array_t; + struct task_struct { /* * offsets of these are hardcoded elsewhere - touch with care @@ -301,35 +310,34 @@ int lock_depth; /* Lock depth */ -/* - * offset 32 begins here on 32-bit platforms. We keep - * all fields in a single cacheline that are needed for - * the goodness() loop in schedule(). - */ - long counter; - long nice; - unsigned long policy; - struct mm_struct *mm; - int processor; /* - * cpus_runnable is ~0 if the process is not running on any - * CPU. It's (1 << cpu) if it's running on a CPU. This mask - * is updated under the runqueue lock. - * - * To determine whether a process might run on a CPU, this - * mask is AND-ed with cpus_allowed. + * offset 32 begins here on 32-bit platforms */ - unsigned long cpus_runnable, cpus_allowed; + unsigned int cpu; + int prio, static_prio; + list_t run_list; + prio_array_t *array; + + unsigned long sleep_avg; + unsigned long sleep_timestamp; + + unsigned long policy; + unsigned long cpus_allowed; + unsigned int time_slice; +#ifdef CONFIG_IA64 /* - * (only the 'next' pointer fits into the cacheline, but - * that's just fine.) + * Placing this field here used previously unused space. + * It is ok to move this field if the space is needed for something + * else. */ - struct list_head run_list; - unsigned long sleep_time; + int dplace_processor; +#endif + + task_t *next_task, *prev_task; - struct task_struct *next_task, *prev_task; - struct mm_struct *active_mm; + struct mm_struct *mm, *active_mm; struct list_head local_pages; + unsigned int allocation_order, nr_local_pages; /* task state */ @@ -351,15 +359,16 @@ * older sibling, respectively. (p->father can be replaced with * p->p_pptr->pid) */ - struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + task_t *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; struct list_head thread_group; /* PID hash table linkage. */ - struct task_struct *pidhash_next; - struct task_struct **pidhash_pprev; + task_t *pidhash_next; + task_t **pidhash_pprev; wait_queue_head_t wait_chldexit; /* for wait4() */ struct completion *vfork_done; /* for vfork() */ + unsigned long rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; @@ -410,14 +419,38 @@ void *notifier_data; sigset_t *notifier_mask; +#ifdef CONFIG_CPUMEMSET +/* CpuMemSets */ + cpumemset_t * current_cms; + cpumemset_t * child_cms; + /* stash mems_allowed of most recent vma to page fault here */ + unsigned long interrupt_mems_allowed; +#else + void * unused_current_cms; + void * unused_child_cms; + unsigned long unused_interrupt_mems_allowed; +#endif /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; /* Protection of (de-)allocation: mm, files, fs, tty */ spinlock_t alloc_lock; +/* context-switch lock */ + spinlock_t switch_lock; /* journalling filesystem info */ void *journal_info; + +#if defined(CONFIG_PAGG) +/* List of pagg (process aggregate) attachments */ + struct pagg_list_s pagg_list; +#endif +/* i/o counters(bytes read/written, blocks read/written, #syscalls, waittime */ + unsigned long rchar, wchar, rblk, wblk, syscr, syscw, bwtime; +#if defined(CONFIG_CSA_JOB_ACCT) || defined(CONFIG_CSA_JOB_ACCT_MODULE) + unsigned long csa_rss_mem1, csa_vm_mem1; + clock_t csa_stimexpd; +#endif }; /* @@ -435,6 +468,7 @@ #define PF_MEMDIE 0x00001000 /* Killed for out-of-memory */ #define PF_FREE_PAGES 0x00002000 /* per process page freeing */ #define PF_NOIO 0x00004000 /* avoid generating further I/O */ +#define PF_FSTRANS 0x00008000 /* inside a filesystem transaction */ #define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ @@ -454,9 +488,15 @@ */ #define _STK_LIM (8*1024*1024) -#define DEF_COUNTER (10*HZ/100) /* 100 ms time slice */ -#define MAX_COUNTER (20*HZ/100) -#define DEF_NICE (0) +#ifdef CONFIG_SMP +extern void set_cpus_allowed(task_t *p, unsigned long new_mask); +#else +# define set_cpus_allowed(p, new_mask) do { } while (0) +#endif + +extern void set_user_nice(task_t *p, long nice); +extern int task_prio(task_t *p); +extern int task_nice(task_t *p); asmlinkage long sys_sched_yield(void); #define yield() sys_sched_yield() @@ -478,14 +518,14 @@ addr_limit: KERNEL_DS, \ exec_domain: &default_exec_domain, \ lock_depth: -1, \ - counter: DEF_COUNTER, \ - nice: DEF_NICE, \ + prio: 120, \ + static_prio: 120, \ policy: SCHED_OTHER, \ + cpus_allowed: -1L, \ mm: NULL, \ active_mm: &init_mm, \ - cpus_runnable: -1, \ - cpus_allowed: -1, \ run_list: LIST_HEAD_INIT(tsk.run_list), \ + time_slice: HZ, \ next_task: &tsk, \ prev_task: &tsk, \ p_opptr: &tsk, \ @@ -509,8 +549,11 @@ sig: &init_signals, \ pending: { NULL, &tsk.pending.head, {{0}}}, \ blocked: {{0}}, \ + INIT_TASK_CPUMEMSET() \ alloc_lock: SPIN_LOCK_UNLOCKED, \ + switch_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ + INIT_TASK_PAGG_LIST_INIT(tsk) /* COMMA included if defined */ \ } @@ -519,24 +562,24 @@ #endif union task_union { - struct task_struct task; + task_t task; unsigned long stack[INIT_TASK_SIZE/sizeof(long)]; }; extern union task_union init_task_union; extern struct mm_struct init_mm; -extern struct task_struct *init_tasks[NR_CPUS]; +extern task_t *init_tasks[NR_CPUS]; /* PID hashing. (shouldnt this be dynamic?) */ #define PIDHASH_SZ (4096 >> 2) -extern struct task_struct *pidhash[PIDHASH_SZ]; +extern task_t *pidhash[PIDHASH_SZ]; #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) -static inline void hash_pid(struct task_struct *p) +static inline void hash_pid(task_t *p) { - struct task_struct **htable = &pidhash[pid_hashfn(p->pid)]; + task_t **htable = &pidhash[pid_hashfn(p->pid)]; if((p->pidhash_next = *htable) != NULL) (*htable)->pidhash_pprev = &p->pidhash_next; @@ -544,16 +587,16 @@ p->pidhash_pprev = htable; } -static inline void unhash_pid(struct task_struct *p) +static inline void unhash_pid(task_t *p) { if(p->pidhash_next) p->pidhash_next->pidhash_pprev = p->pidhash_pprev; *p->pidhash_pprev = p->pidhash_next; } -static inline struct task_struct *find_task_by_pid(int pid) +static inline task_t *find_task_by_pid(int pid) { - struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)]; + task_t *p, **htable = &pidhash[pid_hashfn(pid)]; for(p = *htable; p && p->pid != pid; p = p->pidhash_next) ; @@ -561,19 +604,6 @@ return p; } -#define task_has_cpu(tsk) ((tsk)->cpus_runnable != ~0UL) - -static inline void task_set_cpu(struct task_struct *tsk, unsigned int cpu) -{ - tsk->processor = cpu; - tsk->cpus_runnable = 1UL << cpu; -} - -static inline void task_release_cpu(struct task_struct *tsk) -{ - tsk->cpus_runnable = ~0UL; -} - /* per-UID process charging. */ extern struct user_struct * alloc_uid(uid_t); extern void free_uid(struct user_struct *); @@ -593,54 +623,58 @@ #define CURRENT_TIME (xtime.tv_sec) extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr)); -extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)); extern void FASTCALL(sleep_on(wait_queue_head_t *q)); extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); extern void FASTCALL(interruptible_sleep_on(wait_queue_head_t *q)); extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); -extern int FASTCALL(wake_up_process(struct task_struct * tsk)); +extern int FASTCALL(wake_up_process(task_t * tsk)); +extern void FASTCALL(wake_up_forked_process(task_t * tsk)); +extern void FASTCALL(sched_exit(task_t * p)); #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) #define wake_up_nr(x, nr) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) #define wake_up_all(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0) -#define wake_up_sync(x) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) -#define wake_up_sync_nr(x, nr) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) #define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE, 1) #define wake_up_interruptible_nr(x, nr) __wake_up((x),TASK_INTERRUPTIBLE, nr) #define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE, 0) +#ifdef CONFIG_SMP +extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)); #define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1) -#define wake_up_interruptible_sync_nr(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, nr) +#else +#define wake_up_interruptible_sync(x) __wake_up((x),TASK_INTERRUPTIBLE, 1) +#endif + asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); extern int in_group_p(gid_t); extern int in_egroup_p(gid_t); extern void proc_caches_init(void); -extern void flush_signals(struct task_struct *); -extern void flush_signal_handlers(struct task_struct *); +extern void flush_signals(task_t *); +extern void flush_signal_handlers(task_t *); extern void sig_exit(int, int, struct siginfo *); extern int dequeue_signal(sigset_t *, siginfo_t *); extern void block_all_signals(int (*notifier)(void *priv), void *priv, sigset_t *mask); extern void unblock_all_signals(void); -extern int send_sig_info(int, struct siginfo *, struct task_struct *); -extern int force_sig_info(int, struct siginfo *, struct task_struct *); +extern int send_sig_info(int, struct siginfo *, task_t *); +extern int force_sig_info(int, struct siginfo *, task_t *); extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_sl_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); -extern void notify_parent(struct task_struct *, int); -extern void do_notify_parent(struct task_struct *, int); -extern void force_sig(int, struct task_struct *); -extern int send_sig(int, struct task_struct *, int); +extern void notify_parent(task_t *, int); +extern void do_notify_parent(task_t *, int); +extern void force_sig(int, task_t *); +extern int send_sig(int, task_t *, int); extern int kill_pg(pid_t, int, int); extern int kill_sl(pid_t, int, int); extern int kill_proc(pid_t, int, int); extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long); -static inline int signal_pending(struct task_struct *p) +static inline int signal_pending(task_t *p) { return (p->sigpending != 0); } @@ -679,7 +713,7 @@ This is required every time the blocked sigset_t changes. All callers should have t->sigmask_lock. */ -static inline void recalc_sigpending(struct task_struct *t) +static inline void recalc_sigpending(task_t *t) { t->sigpending = has_pending_signals(&t->pending.signal, &t->blocked); } @@ -775,6 +809,19 @@ /* Remove the current tasks stale references to the old mm_struct */ extern void mm_release(void); +/* Update highwater values */ +static inline void update_mem_hiwater(void) +{ + if (current->mm) { + if (current->mm->hiwater_rss < current->mm->rss) { + current->mm->hiwater_rss = current->mm->rss; + } + if (current->mm->hiwater_vm < current->mm->total_vm) { + current->mm->hiwater_vm = current->mm->total_vm; + } + } +} + /* * Routines for handling the fd arrays */ @@ -786,16 +833,17 @@ extern int expand_fdset(struct files_struct *, int nr); extern void free_fdset(fd_set *, int); -extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); +extern int copy_thread(int, unsigned long, unsigned long, unsigned long, task_t *, struct pt_regs *); extern void flush_thread(void); extern void exit_thread(void); -extern void exit_mm(struct task_struct *); -extern void exit_files(struct task_struct *); -extern void exit_sighand(struct task_struct *); +extern void exit_mm(task_t *); +extern void exit_files(task_t *); +extern void exit_sighand(task_t *); extern void reparent_to_init(void); extern void daemonize(void); +extern task_t *child_reaper; extern int do_execve(char *, char **, char **, struct pt_regs *); extern int do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long); @@ -804,6 +852,9 @@ extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); +extern void wait_task_inactive(task_t * p); +extern void kick_if_running(task_t * p); + #define __wait_event(wq, condition) \ do { \ wait_queue_t __wait; \ @@ -885,27 +936,12 @@ for (task = next_thread(current) ; task != current ; task = next_thread(task)) #define next_thread(p) \ - list_entry((p)->thread_group.next, struct task_struct, thread_group) + list_entry((p)->thread_group.next, task_t, thread_group) #define thread_group_leader(p) (p->pid == p->tgid) -static inline void del_from_runqueue(struct task_struct * p) -{ - nr_running--; - p->sleep_time = jiffies; - list_del(&p->run_list); - p->run_list.next = NULL; -} - -static inline int task_on_runqueue(struct task_struct *p) -{ - return (p->run_list.next != NULL); -} - -static inline void unhash_process(struct task_struct *p) +static inline void unhash_process(task_t *p) { - if (task_on_runqueue(p)) - out_of_line_bug(); write_lock_irq(&tasklist_lock); nr_threads--; unhash_pid(p); @@ -915,12 +951,12 @@ } /* Protects ->fs, ->files, ->mm, and synchronises with wait4(). Nests inside tasklist_lock */ -static inline void task_lock(struct task_struct *p) +static inline void task_lock(task_t *p) { spin_lock(&p->alloc_lock); } -static inline void task_unlock(struct task_struct *p) +static inline void task_unlock(task_t *p) { spin_unlock(&p->alloc_lock); } @@ -942,6 +978,31 @@ dput(root); mntput(rootmnt); return res; +} + +static inline void set_need_resched(void) +{ + current->need_resched = 1; +} + +static inline void clear_need_resched(void) +{ + current->need_resched = 0; +} + +static inline void set_tsk_need_resched(task_t *tsk) +{ + tsk->need_resched = 1; +} + +static inline void clear_tsk_need_resched(task_t *tsk) +{ + tsk->need_resched = 0; +} + +static inline int need_resched(void) +{ + return unlikely(current->need_resched); } #endif /* __KERNEL__ */ diff -Nur linux-2.4.19/include/linux/serial.h linux-2.4.19-sgi211r3/include/linux/serial.h --- linux-2.4.19/include/linux/serial.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/serial.h Wed Oct 16 14:02:58 2002 @@ -181,6 +181,12 @@ /* Allow complicated architectures to specify rs_table[] at run time */ extern int early_serial_setup(struct serial_struct *req); +#ifdef CONFIG_SERIAL_ACPI +/* tty ports reserved for the ACPI serial console port and debug port */ +#define ACPI_SERIAL_CONSOLE_PORT 4 +#define ACPI_SERIAL_DEBUG_PORT 5 +#endif + /* tty port reserved for the HCDP serial console port */ #define HCDP_SERIAL_CONSOLE_PORT 4 diff -Nur linux-2.4.19/include/linux/serialP.h linux-2.4.19-sgi211r3/include/linux/serialP.h --- linux-2.4.19/include/linux/serialP.h Fri Aug 2 17:39:45 2002 +++ linux-2.4.19-sgi211r3/include/linux/serialP.h Wed Oct 16 14:02:58 2002 @@ -42,7 +42,11 @@ int revision; /* Chip revision (950) */ int xmit_fifo_size; int custom_divisor; +#ifdef CONFIG_IA64_SGI_SN + atomic_t count; +#else int count; +#endif u8 *iomem_base; u16 iomem_reg_shift; unsigned short close_delay; diff -Nur linux-2.4.19/include/linux/slab.h linux-2.4.19-sgi211r3/include/linux/slab.h --- linux-2.4.19/include/linux/slab.h Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/include/linux/slab.h Tue Jan 14 22:12:30 2003 @@ -56,7 +56,9 @@ extern int kmem_cache_destroy(kmem_cache_t *); extern int kmem_cache_shrink(kmem_cache_t *); extern void *kmem_cache_alloc(kmem_cache_t *, int); +extern void *kmem_cache_zalloc(kmem_cache_t *, int); extern void kmem_cache_free(kmem_cache_t *, void *); +extern unsigned int kmem_cache_size(kmem_cache_t *); extern void *kmalloc(size_t, int); extern void kfree(const void *); @@ -73,6 +75,16 @@ extern kmem_cache_t *bh_cachep; extern kmem_cache_t *fs_cachep; extern kmem_cache_t *sigact_cachep; + + +struct vm_area_struct; + +static inline void free_vm_area(struct vm_area_struct * vma) +{ + kmem_cache_free(vm_area_cachep, vma); + +} + #endif /* __KERNEL__ */ diff -Nur linux-2.4.19/include/linux/smp.h linux-2.4.19-sgi211r3/include/linux/smp.h --- linux-2.4.19/include/linux/smp.h Thu Nov 22 11:46:19 2001 +++ linux-2.4.19-sgi211r3/include/linux/smp.h Mon Oct 28 20:43:23 2002 @@ -28,18 +28,12 @@ */ extern void FASTCALL(smp_send_reschedule(int cpu)); - /* * Boot processor call to load the other CPU's */ extern void smp_boot_cpus(void); /* - * Processor call in. Must hold processors until .. - */ -extern void smp_callin(void); - -/* * Multiprocessors may now schedule */ extern void smp_commence(void); @@ -57,10 +51,6 @@ extern int smp_num_cpus; -extern volatile unsigned long smp_msg_data; -extern volatile int smp_src_cpu; -extern volatile int smp_msg_id; - #define MSG_ALL_BUT_SELF 0x8000 /* Assume <32768 CPU's */ #define MSG_ALL 0x8001 @@ -86,6 +76,14 @@ #define cpu_number_map(cpu) 0 #define smp_call_function(func,info,retry,wait) ({ 0; }) #define cpu_online_map 1 +static inline void smp_send_reschedule(int cpu) { } +static inline void smp_send_reschedule_all(void) { } #endif + +/* + * Common definitions: + */ +#define cpu() smp_processor_id() + #endif diff -Nur linux-2.4.19/include/linux/swap.h linux-2.4.19-sgi211r3/include/linux/swap.h --- linux-2.4.19/include/linux/swap.h Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/include/linux/swap.h Wed Oct 16 14:02:58 2002 @@ -10,6 +10,8 @@ #define MAX_SWAPFILES 32 +#define MAX_SWAPDEV_BLKSIZE 32768 /* limited by b_size in buffer_head */ + /* * Magic header for a swap area. The first part of the union is * what the swap magic looks like for the old (limited to 128MB) diff -Nur linux-2.4.19/include/linux/sysctl.h linux-2.4.19-sgi211r3/include/linux/sysctl.h --- linux-2.4.19/include/linux/sysctl.h Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/include/linux/sysctl.h Thu Dec 12 12:39:32 2002 @@ -124,6 +124,7 @@ KERN_CORE_USES_PID=52, /* int: use core or core.%pid */ KERN_TAINTED=53, /* int: various kernel tainted flags */ KERN_CADPID=54, /* int: PID of the process to notify on CAD */ + KERN_KDB=55, /* int: kdb on/off */ }; @@ -143,6 +144,8 @@ VM_MAX_MAP_COUNT=11, /* int: Maximum number of active map areas */ VM_MIN_READAHEAD=12, /* Min file readahead */ VM_MAX_READAHEAD=13, /* Max file readahead */ + VM_PAGEBUF=14, /* struct: Control pagebuf parameters */ + VM_EXECUTABLE_STACKS=15,/* int: control executable attribute of stacks */ }; @@ -535,7 +538,7 @@ FS_STATINODE=2, FS_MAXINODE=3, /* int:maximum number of inodes that can be allocated */ FS_NRDQUOT=4, /* int:current number of allocated dquots */ - FS_MAXDQUOT=5, /* int:maximum number of dquots that can be allocated */ + /* was FS_MAXDQUOT */ FS_NRFILE=6, /* int:current number of allocated filedescriptors */ FS_MAXFILE=7, /* int:maximum number of filedescriptors that can be allocated */ FS_DENTRY=8, @@ -546,6 +549,20 @@ FS_LEASES=13, /* int: leases enabled */ FS_DIR_NOTIFY=14, /* int: directory notification enabled */ FS_LEASE_TIME=15, /* int: maximum time to wait for a lease break */ + FS_DQSTATS=16, /* dir: disc quota usage statistics */ + FS_XFS=17, /* struct: control xfs parameters */ +}; + +/* /proc/sys/fs/quota/ */ +enum { + FS_DQ_LOOKUPS = 1, + FS_DQ_DROPS = 2, + FS_DQ_READS = 3, + FS_DQ_WRITES = 4, + FS_DQ_CACHE_HITS = 5, + FS_DQ_ALLOCATED = 6, + FS_DQ_FREE = 7, + FS_DQ_SYNCS = 8, }; /* CTL_DEBUG names: */ diff -Nur linux-2.4.19/include/linux/threads.h linux-2.4.19-sgi211r3/include/linux/threads.h --- linux-2.4.19/include/linux/threads.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-sgi211r3/include/linux/threads.h Fri Apr 26 11:07:18 2002 @@ -9,7 +9,11 @@ */ #ifdef CONFIG_SMP +#ifdef CONFIG_IA64_SGI_SN +#define NR_CPUS 64 /* Max processors that can be running in SMP SNIA */ +#else #define NR_CPUS 32 /* Max processors that can be running in SMP */ +#endif #else #define NR_CPUS 1 #endif diff -Nur linux-2.4.19/include/linux/tty.h linux-2.4.19-sgi211r3/include/linux/tty.h --- linux-2.4.19/include/linux/tty.h Thu Nov 22 11:46:19 2001 +++ linux-2.4.19-sgi211r3/include/linux/tty.h Wed Feb 5 13:36:49 2003 @@ -242,6 +242,18 @@ #define L_PENDIN(tty) _L_FLAG((tty),PENDIN) #define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN) +#ifdef CONFIG_IA64_SGI_SN +#define INC_THE_COUNTER(_x) atomic_inc(&(_x)) +#define DEC_THE_COUNTER(_x) atomic_dec(&(_x)) +#define SET_THE_COUNTER(_x,_y) (void)atomic_set(&(_x), _y) +#define READ_THE_COUNTER(_x) atomic_read(&(_x)) +#else +#define INC_THE_COUNTER(_x) ++(_x) +#define DEC_THE_COUNTER(_x) --(_x) +#define SET_THE_COUNTER(_x,_y) _x = _y +#define READ_THE_COUNTER(_x) _x +#endif + /* * Where all of the state associated with a tty is kept while the tty * is open. Since the termios state should be kept even if the tty @@ -265,7 +277,11 @@ int session; kdev_t device; unsigned long flags; +#ifdef CONFIG_IA64_SGI_SN + atomic_t count; +#else int count; +#endif struct winsize winsize; unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1; unsigned char low_latency:1, warned:1; @@ -307,6 +323,7 @@ struct semaphore atomic_read; struct semaphore atomic_write; spinlock_t read_lock; + spinlock_t struct_lock; /* If the tty has a pending do_SAK, queue it here - akpm */ struct tq_struct SAK_tq; }; diff -Nur linux-2.4.19/include/linux/vmalloc.h linux-2.4.19-sgi211r3/include/linux/vmalloc.h --- linux-2.4.19/include/linux/vmalloc.h Thu Nov 22 11:46:20 2001 +++ linux-2.4.19-sgi211r3/include/linux/vmalloc.h Wed Oct 16 14:02:58 2002 @@ -5,6 +5,7 @@ #include #include +#include /* several arch define VMALLOC_END via PKMAP_BASE */ #include /* bits in vm_struct->flags */ @@ -20,6 +21,8 @@ extern struct vm_struct * get_vm_area (unsigned long size, unsigned long flags); extern void vfree(void * addr); +#define vunmap(addr) vfree(addr) +extern void * vmap(struct page **pages, int count); extern void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot); extern long vread(char *buf, char *addr, unsigned long count); extern void vmfree_area_pages(unsigned long address, unsigned long size); diff -Nur linux-2.4.19/include/linux/wait.h linux-2.4.19-sgi211r3/include/linux/wait.h --- linux-2.4.19/include/linux/wait.h Thu Nov 22 11:46:19 2001 +++ linux-2.4.19-sgi211r3/include/linux/wait.h Mon Oct 28 20:43:23 2002 @@ -59,6 +59,7 @@ # define wq_write_lock_irq write_lock_irq # define wq_write_lock_irqsave write_lock_irqsave # define wq_write_unlock_irqrestore write_unlock_irqrestore +# define wq_write_unlock_irq write_unlock_irq # define wq_write_unlock write_unlock #else # define wq_lock_t spinlock_t @@ -71,6 +72,7 @@ # define wq_write_lock_irq spin_lock_irq # define wq_write_lock_irqsave spin_lock_irqsave # define wq_write_unlock_irqrestore spin_unlock_irqrestore +# define wq_write_unlock_irq spin_unlock_irq # define wq_write_unlock spin_unlock #endif diff -Nur linux-2.4.19/include/linux/xattr.h linux-2.4.19-sgi211r3/include/linux/xattr.h --- linux-2.4.19/include/linux/xattr.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/xattr.h Sun Aug 4 23:38:44 2002 @@ -0,0 +1,15 @@ +/* + File: linux/xattr.h + + Extended attributes handling. + + Copyright (C) 2001 by Andreas Gruenbacher + Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. +*/ +#ifndef _LINUX_XATTR_H +#define _LINUX_XATTR_H + +#define XATTR_CREATE 0x1 /* set the value, fail if attr already exists */ +#define XATTR_REPLACE 0x2 /* set the value, fail if attr does not exist */ + +#endif /* _LINUX_XATTR_H */ diff -Nur linux-2.4.19/include/linux/xscsi/alenlist.h linux-2.4.19-sgi211r3/include/linux/xscsi/alenlist.h --- linux-2.4.19/include/linux/xscsi/alenlist.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/xscsi/alenlist.h Mon Oct 28 14:49:09 2002 @@ -0,0 +1,217 @@ +/* + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +#ifndef _ALENLIST_H +#define _ALENLIST_H + +#include +#include + +#define ALENLIST_FAILURE (-1) +#define ALENLIST_SUCCESS 0 + +#define AL_NOSLEEP 0x01 +#define AL_NOCOMPACT 0x02 +#define AL_LEAVE_CURSOR 0x04 +#define AL_UNALIGNED_OK 0x08 +typedef unsigned long long alenaddr_t; + +typedef struct alenlist_s *alenlist_t; +typedef struct alenlist_cursor_s *alenlist_cursor_t; + +struct alenlist_cursor_s { + int pos; +}; + +struct alenlist_s { + struct alenlist_cursor_s cursor; + struct page *page; + struct page **maplist; + unsigned long offset; + unsigned long pages; + size_t len; + struct buffer_head *bhstart; + struct buffer_head *bhcursor; +}; + +static __inline__ alenlist_t +alenlist_create(unsigned int flags) +{ + alenlist_t alist; + + alist = kmalloc(sizeof(struct alenlist_s), GFP_KERNEL); + if (!alist) + return NULL; + memset(alist, 0, sizeof(struct alenlist_s)); + + return alist; +} + +static __inline__ void +alenlist_done(alenlist_t alist) +{ + kfree(alist); +} + +static __inline__ int +alenlist_grow(alenlist_t alist, size_t npairs) +{ + return ALENLIST_SUCCESS; +} + + +#ifdef CONFIG_X86 +static __inline__ unsigned long long +alen_page_to_phys(struct page *page) +{ + unsigned long long addr; + unsigned long mapnr; + + mapnr = page - page_zone(page)->zone_mem_map; + + addr = ((unsigned long long) mapnr << PAGE_SHIFT) + + page_zone(page)->zone_start_paddr; + + return addr; +} +#else +#define alen_page_to_phys page_to_phys +#endif + +static __inline__ int +alenlist_get(alenlist_t alist, alenlist_cursor_t cursor, + size_t maxlength, alenaddr_t *addr, size_t *len, + unsigned flags) +{ + int page; + + if (alist == NULL) + return ALENLIST_FAILURE; + + if (alist->bhstart) { + struct buffer_head *bh = alist->bhcursor; + + *addr = alen_page_to_phys(bh->b_page) + bh_offset(bh); + *len = bh->b_size; + alist->bhcursor = bh->b_reqnext; + } + else if (alist->maplist) { + page = (alist->cursor.pos + alist->offset) >> PAGE_SHIFT; + *addr = (alenaddr_t) alen_page_to_phys(alist->maplist[page]); + *len = PAGE_SIZE; + if (page == 0) { + *len -= alist->offset; + *addr += alist->offset; + } + if (*len > alist->len - alist->cursor.pos) + *len = alist->len - alist->cursor.pos; + alist->cursor.pos += *len; + } + else + return ALENLIST_FAILURE; + + return ALENLIST_SUCCESS; +} + +static __inline__ void +alenlist_setup(alenlist_t alist, struct page **maplist, int offset, int length) +{ + int pages; + + pages = ((offset & ~PAGE_MASK) + length + PAGE_SIZE - 1) >> PAGE_SHIFT; + alist->pages = pages; + alist->maplist = maplist; + alist->bhstart = NULL; + alist->offset = offset; + alist->len = length; +} + +static __inline__ void +alenlist_setup_bh(alenlist_t alist, struct buffer_head *bh) +{ + int pages=0; + int length=0; + + alist->bhstart = bh; + alist->maplist = NULL; + while (bh != NULL) { + pages++; + length += bh->b_size; + bh = bh->b_reqnext; + } + alist->pages = pages; + alist->len = length; +} + +static __inline__ int +alenlist_size(alenlist_t alist) +{ + return alist->pages; +} + +static __inline__ int +alenlist_cursor_init(alenlist_t alist, size_t offset, + alenlist_cursor_t cursorp) +{ + if (alist->bhstart) + alist->bhcursor = alist->bhstart; + alist->cursor.pos = 0; + return ALENLIST_SUCCESS; +} + +static __inline__ alenlist_t +buf_to_alenlist(alenlist_t alist, void * buf, + unsigned int flags) +{ + BUG(); + return NULL; +} + +static __inline__ alenlist_t +kvaddr_to_alenlist(alenlist_t alist, void * kvaddr, + size_t len, unsigned int flags) +{ + alist->cursor.pos = 0; + alist->page = virt_to_page(kvaddr); + alist->maplist = &alist->page; + alist->len = len; + alist->pages = 1; + alist->offset = (unsigned long) kvaddr & ~PAGE_MASK; + alist->bhstart = NULL; + + return alist; +} + +#endif diff -Nur linux-2.4.19/include/linux/xscsi/fc.h linux-2.4.19-sgi211r3/include/linux/xscsi/fc.h --- linux-2.4.19/include/linux/xscsi/fc.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/xscsi/fc.h Tue Aug 6 12:17:53 2002 @@ -0,0 +1,99 @@ +/* + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* + * This is a conversion table used for converting from target_ID to AL_PA. + * Note that target_ID's greater than 0x7E are illegal and 0x7E (aka AL_PA=0) + * is reserved for a fabric port. + * + * Be advised that this file is also present in the IP35 prom build area + * as stand/arcs/lib/libsk/io/fcal.c + */ +#if 0 +static u_char tid_to_alpa[] = { + 0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, /* 00 - 07 */ + 0xD9, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, /* 08 - 0F */ + 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC7, 0xC6, 0xC5, /* 10 - 17 */ + 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, 0xB4, 0xB3, /* 18 - 1F */ + 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, /* 20 - 27 */ + 0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, /* 28 - 2F */ + 0x98, 0x97, 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, /* 30 - 37 */ + 0x80, 0x7C, 0x7A, 0x79, 0x76, 0x75, 0x74, 0x73, /* 38 - 3F */ + 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, /* 40 - 47 */ + 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56, /* 48 - 4F */ + 0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, /* 50 - 57 */ + 0x4B, 0x4A, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, /* 58 - 5F */ + 0x3A, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, /* 60 - 67 */ + 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x27, 0x26, /* 68 - 6F */ + 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17, /* 70 - 77 */ + 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x00, /* 78 - 7E .. 7F is illegal */ +}; +#endif + +static u_char alpa_to_tid[] = { + 0x7e, 0x7d, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, /* 00 - 07 */ + 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, /* 08 - 0f */ + 0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, /* 10 - 17 */ + 0x76, 0xff, 0xff, 0x75, 0xff, 0x74, 0x73, 0x72, /* 18 - 1f */ + 0xff, 0xff, 0xff, 0x71, 0xff, 0x70, 0x6f, 0x6e, /* 20 - 27 */ + 0xff, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0xff, /* 28 - 2f */ + 0xff, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0xff, /* 30 - 37 */ + 0xff, 0x61, 0x60, 0xff, 0x5f, 0xff, 0xff, 0xff, /* 38 - 3f */ + 0xff, 0xff, 0xff, 0x5e, 0xff, 0x5d, 0x5c, 0x5b, /* 40 - 47 */ + 0xff, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0xff, /* 48 - 4f */ + 0xff, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0xff, /* 50 - 57 */ + 0xff, 0x4e, 0x4d, 0xff, 0x4c, 0xff, 0xff, 0xff, /* 58 - 5f */ + 0xff, 0xff, 0xff, 0x4b, 0xff, 0x4a, 0x49, 0x48, /* 60 - 67 */ + 0xff, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0xff, /* 68 - 6f */ + 0xff, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0xff, /* 70 - 77 */ + 0xff, 0x3b, 0x3a, 0xff, 0x39, 0xff, 0xff, 0xff, /* 78 - 7f */ + 0x38, 0x37, 0x36, 0xff, 0x35, 0xff, 0xff, 0xff, /* 80 - 87 */ + 0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, /* 88 - 8f */ + 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, /* 90 - 97 */ + 0x30, 0xff, 0xff, 0x2f, 0xff, 0x2e, 0x2d, 0x2c, /* 98 - 9f */ + 0xff, 0xff, 0xff, 0x2b, 0xff, 0x2a, 0x29, 0x28, /* a0 - a7 */ + 0xff, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0xff, /* a8 - af */ + 0xff, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0xff, /* b0 - b7 */ + 0xff, 0x1b, 0x1a, 0xff, 0x19, 0xff, 0xff, 0xff, /* b8 - bf */ + 0xff, 0xff, 0xff, 0x18, 0xff, 0x17, 0x16, 0x15, /* c0 - c7 */ + 0xff, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0xff, /* c8 - cf */ + 0xff, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0xff, /* d0 - d7 */ + 0xff, 0x08, 0x07, 0xff, 0x06, 0xff, 0xff, 0xff, /* d8 - df */ + 0x05, 0x04, 0x03, 0xff, 0x02, 0xff, 0xff, 0xff, /* e0 - e7 */ + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* e8 - ef */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* f0 - f7 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* f8 - ff */ +}; + +#define ALPA_2_TID(alpa) (((alpa) > 255) ? 0xFF : alpa_to_tid[alpa]) diff -Nur linux-2.4.19/include/linux/xscsi/osdep_linux.h linux-2.4.19-sgi211r3/include/linux/xscsi/osdep_linux.h --- linux-2.4.19/include/linux/xscsi/osdep_linux.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/xscsi/osdep_linux.h Fri Feb 7 12:23:12 2003 @@ -0,0 +1,496 @@ +/* + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifndef _OSDEP_LINUX_H +#define _OSDEP_LINUX_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +typedef unsigned long uintptr_t; +typedef uintptr_t __psunsigned_t; +typedef long intptr_t; +typedef intptr_t __psint_t; + +/* Byte order and bitfield order */ + +#if defined(__LITTLE_ENDIAN) +#define USE_LE32_ORDERING +#elif defined(__BIG_ENDIAN) +#else +#error No byteorder information. Please include asm/byteorder.h! +#endif + +#if defined(IP32) || defined(XSCSI) +#ifdef CONFIG_IA64_SGI_SN +#define USE_MAPPED_PCI_TRANSLATION +#else +#define USE_DIRECT_PCI_TRANSLATION +#endif +#else +#define USE_MAPPED_PCI_TRANSLATION +#endif /* IP32 */ + +typedef unsigned long long paddr_t; +typedef unsigned long long iopaddr_t; + +#define NBPP PAGE_SIZE +#define D_MP 0x1 + +/* Memory management */ + +#define kern_malloc(size) kmem_alloc(size, KM_SLEEP) +#define kern_calloc(size, c) kmem_zalloc((size) * (c), KM_SLEEP) +#define kern_free(addr) xfree(addr) + +static __inline__ void xfree(void *addr) +{ + if (((unsigned long) addr < VMALLOC_START) || + ((unsigned long) addr >= VMALLOC_END)) + kfree(addr); + else + vfree(addr); +} + +static __inline__ void * kvpalloc(size_t size, int flags, int colour) +{ + if (flags & (VM_DIRECT|VM_PHYSCONTIG)) { + /* We want physically contiguous pages. */ + int order = 0; + while ((PAGE_SIZE << order) < (size << PAGE_SHIFT)) + order++; + return (void *) __get_free_pages(GFP_KERNEL, order); + } else + return vmalloc(size << PAGE_SHIFT); +} + +static __inline__ void kvpfree(void *ptr, size_t size) +{ + if (((unsigned long) ptr < VMALLOC_START) || + ((unsigned long) ptr >= VMALLOC_END)) { + int order = 0; + while ((PAGE_SIZE << order) < (size << PAGE_SHIFT)) + order++; + free_pages((unsigned long) ptr, order); + } else + vfree(ptr); +} + +/* Cache coherence */ + +#define dki_dcache_inval dma_cache_inv +#define dki_dcache_wb dma_cache_wback +#define dki_dcache_wbinval dma_cache_wback_inv +#ifdef CONFIG_IA64_SGI_SN +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) +#endif + +/* hwgraph is mapped to devfs */ + +typedef void* arbitrary_info_t; + +typedef int graph_error_t; + +/* Wait queues */ + +#define mutex_mine(lock) 1 + +#define MUTEX_INIT(lock,type,name) mutex_init(lock,type, name) +#define MUTEX_LOCK(lock,num) mutex_lock(lock,num) +#define MUTEX_TRYLOCK(lock) mutex_trylock(lock) +#define MUTEX_UNLOCK(lock) mutex_unlock(lock) +#define MUTEX_MINE(lock) 1 +#define MUTEX_DESTROY(lock) mutex_destroy(lock) + +#define SV_INIT(sv,flag,name) sv_init(sv,flag,name) +#define SV_WAIT(sv,lock,spl) sv_wait(sv,0,lock,spl) +#define SV_BROADCAST(sv) sv_broadcast(sv) + +#define SV_WAIT_MUTEX(sv,lock,number) sv_wait_mutex(sv,lock) +#define SV_BROADCAST_MUTEX(sv) sv_broadcast_mutex(sv) + +static inline void sv_wait_mutex(sv_t *sv, mutex_t *lock) +{ + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + + spin_lock_irqsave(&sv->lock, flags); + MUTEX_UNLOCK(lock); + add_wait_queue(&sv->waiters, &wait); + current->state |= TASK_INTERRUPTIBLE; + spin_unlock_irqrestore(&sv->lock, flags); + schedule(); + remove_wait_queue(&sv->waiters, &wait); +} + +#define sv_broadcast_mutex(sv) wake_up_interruptible(&(sv)->waiters) + + +#define kvtophys(addr) virt_to_bus(addr) + +#define PHYS_TO_K1(addr) (addr) +#define btoc(addr) ((((unsigned long) addr)+(PAGE_SIZE-1))>>PAGE_SHIFT) +#define poff(addr) (((unsigned long) addr) & (PAGE_SIZE-1)) + +#define MAXDMASIZE (1<<17) + +static inline void *v_getaddr( struct vm_area_struct *vt ) +{ + return (void *)vt->vm_start; +} + +#define PCI_CFG_VENDOR_ID PCI_VENDOR_ID +#define PCI_CFG_DEVICE_ID PCI_DEVICE_ID +#define PCI_CFG_COMMAND PCI_COMMAND +#define PCI_CFG_STATUS PCI_STATUS +#define PCI_CFG_REV_ID PCI_REVISION_ID +#define PCI_CFG_CLASS_CODE PCI_CLASS_PROG +#define PCI_CFG_BASE_CLASS PCI_CLASS_PROG +#define PCI_CFG_SUB_CLASS PCI_CLASS_DEVICE +#define PCI_CFG_CACHE_LINE PCI_CACHE_LINE_SIZE +#define PCI_CFG_LATENCY_TIMER PCI_LATENCY_TIMER +#define PCI_CFG_HEADER_TYPE PCI_HEADER_TYPE +#define PCI_CFG_BIST PCI_BIST + +#define PCI_CMD_IO_SPACE PCI_COMMAND_IO +#define PCI_CMD_MEM_SPACE PCI_COMMAND_MEMORY +#define PCI_CMD_BUS_MASTER PCI_COMMAND_MASTER +#define PCI_CMD_SPEC_CYCLES PCI_COMMAND_SPECIAL +#define PCI_CMD_MEMW_INV_ENAB PCI_COMMAND_INVALIDATE +#define PCI_CMD_VGA_PALETTE_SNP PCI_COMMAND_VGA_ALETTE +#define PCI_CMD_PAR_ERR_RESP PCI_COMMAND_PARITY +#define PCI_CMD_WAIT_CYCLE_CTL PCI_COMMAND_WAIT +#define PCI_CMD_SERR_ENABLE PCI_COMMAND_SERR +#define PCI_CMD_F_BK_BK_ENABLE PCI_COMMAND_FAST_BACK + +extern struct pci_dev *ctlr_pci_devs[]; + +void pciio_config_get_unknown(void); +void pciio_config_set_unknown(void); + +static inline uint64_t +pciio_config_get(struct pci_dev *dev, + unsigned int reg, + unsigned int size) +{ + switch (size) { + case 1: + { + u8 val; + pci_read_config_byte(dev, reg, &val); + return val; + } + case 2: + { + u16 val; + pci_read_config_word(dev, reg, &val); + return val; + } + case 4: + { + u32 val; + pci_read_config_dword(dev, reg, &val); + return val; + } + default: + pciio_config_get_unknown(); + return 0; + } +} +static inline uint64_t +pciio_config_set(struct pci_dev *dev, + unsigned int reg, + unsigned int size, + uint64_t arg) +{ + switch (size) { + case 1: + { + u8 val = arg; + pci_write_config_byte(dev, reg, val); + return val; + } + case 2: + { + u16 val = arg; + pci_write_config_word(dev, reg, val); + return val; + } + case 4: + { + u32 val = arg; + pci_write_config_dword(dev, reg, val); + return val; + } + default: + pciio_config_set_unknown(); + return 0; + } +} + +/* + * Physical address conversion glue + */ +#ifdef CONFIG_IA64_SGI_SN +#define PCIBR_NO_ATE_ROUNDUP 0x00008000 +#define PCIBR_WRITE_GATHER 0x00010000 /* please use PCIIO version */ +#define PCIBR_NOWRITE_GATHER 0x00020000 /* please use PCIIO version */ +#define PCIBR_PREFETCH 0x00040000 /* please use PCIIO version */ +#define PCIBR_NOPREFETCH 0x00080000 /* please use PCIIO version */ +#define PCIBR_PRECISE 0x00100000 +#define PCIBR_NOPRECISE 0x00200000 +#define PCIBR_BARRIER 0x00400000 +#define PCIBR_NOBARRIER 0x00800000 +#define PCIBR_VCHAN0 0x01000000 +#define PCIBR_VCHAN1 0x02000000 +#define PCIBR_64BIT 0x04000000 +#define PCIBR_NO64BIT 0x08000000 +#define PCIBR_SWAP 0x10000000 +#define PCIBR_NOSWAP 0x20000000 +#define PCIIO_DMA_CMD 0x0010 +#define PCIIO_DMA_DATA 0x0020 +#define PCIIO_DMA_A64 0x0040 +#define PCIIO_PREFETCH 0x0400 +#define PCIIO_BYTE_STREAM 0x1000 /* set BYTE SWAP for "byte stream" */ +#define PCIIO_WORD_VALUES 0x2000 /* set BYTE SWAP for "word values" */ + +typedef void * device_desc_t; +typedef void * pciio_dmamap_t; + +#define pciio_dmatrans_addr snia_pciio_dmatrans_addr +#define pciio_dmamap_alloc snia_pciio_dmamap_alloc +#define pciio_dmamap_free snia_pciio_dmamap_free +#define pciio_dmamap_addr snia_pciio_dmamap_addr +#define pciio_endian_set snia_pciio_endian_set +#define pcibr_rrb_alloc snia_pcibr_rrb_alloc + +/* + * Copied definition from arch/ia64/sn/io/pciio.c + */ +iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); +pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); +void snia_pciio_dmamap_free(pciio_dmamap_t); +iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); +int snia_pciio_endian_set(struct pci_dev *pci_dev, int device_end, int desired_end); +int snia_pcibr_rrb_alloc(struct pci_dev *pci_dev, int *count_vchan0, int *count_vchan1); +#else +#define pciio_dmatrans_addr(pci_vertex, a_ptr, addr, val1, val2) addr +#endif + +#define PCIIO_SPACE_WIN(n) resource[n].start + +#define pciio_piotrans_addr(vertex, devflag, config, offset, len, flag) \ + ioremap_nocache(vertex -> config, len) + +#define pciio_dmatrans_list(pci, x, alen, flags) alen + +/* Flow of time, delays */ + +#define TICK 10000000 + +#define us_delay(d) \ + (((d) > (MAX_UDELAY_MS * 1000)) ? \ + mdelay((d) / 1000) : udelay(d)) +#define DELAY(d) us_delay(d) +#define us_delaybus(d) us_delay(d) /* XXX - flushbus? */ +#define DELAYBUS(d) us_delay(d) /* XXX - flushbus? */ +#define pltimeout 0 +#define splhi 0 +#define lbolt ((int) jiffies) +#define nvdelay(d) udelay(d) /* XXX - flushbus? */ +#define flushbus() udelay(10) /* How is this supposed to work? */ + +typedef struct irix_timer * toid_t; + +struct irix_timer * timeout(void *handler, void *ptr, long delay, ...); +void untimeout(struct irix_timer *timer); + +#define itimeout(handler, ptr, delay, level) timeout(handler, ptr, delay) + +/* Output functions */ + +#define printf printk + +#define cmn_err_tag(tag, level, fmt, args...) /* XXX - broken (%v) */ + +/* Misc */ + +typedef int (st_func_t)(void *); +#define sthread_create(name, stackaddr, stacksize, flags, pri, \ + schedflags, func, arg1, arg2, arg3, arg4) \ +kernel_thread(func, arg1, 0) + +#define sthread_exit() return + +typedef int (xt_func_t)(void *); +#define xthread_create(name, fl1, stacksize, fl2, pri, ktps, func, fl3) \ +kernel_thread(func, NULL, 0); + +#define device_inventory_add(vertex, subsys, drv, num1, num2, rev_level) do; while(0) +#define device_info_set(a,b) do; while(0) +#define MIN min +#define MAX max +#define debug(args...) +#define MAXDEVNAME 256 + +#define initpollhead(a) init_waitqueue_head(a) +#define pollwakeup(pollq,flag) wake_up(pollq) +#define POLL_WAIT(a,b,c) poll_wait(a,b,c) + +typedef int *cdl_p; + +/* Other */ + +#define L_I(a,b) a +#define RETURN_FROM_THREAD() return(0) +#define RETURN_FROM_POLL(mask) return(mask) +#define PCIIO_DMAMAP(map) +#define PCIIO_INTR_HANDLE(ih) +#define POLLQUEUE(pq) wait_queue_head_t pq +#define IRIX_SET(lv,rv) +#define LINUX_SET(lv,rv) ((lv) = (rv)) +#define IRIX_ONLY(stmt) +#define LINUX_ONLY(stmt) stmt + +#define BPCSHIFT PAGE_SHIFT /* FIXME check that */ + +static __inline__ void swab32_region(uint32_t *datap, unsigned long len) +{ + uint32_t *ptr = datap; + int i; + + for (i = len/sizeof(uint32_t); i--; ) + ptr[i] = be32_to_cpu( ptr[i] ); + +} + +static __inline__ void swab64_32(uint64_t *datap) +{ + uint32_t temp; + uint32_t *new = (uint32_t *)datap; + temp = new[1]; + new[1] = new[0]; + new[0] = temp; +} + +/* Atomic operations */ + +#ifdef __HAVE_ARCH_CMPXCHG +#define compare_and_swap_int(p, o, n) cmpxchg((p), (o), (n)) + +/* In these macros `a' is pointing to the memory, `b' is the the + argument to the operation. When we are done `c' is set to the old + value pointed to by `a'. */ + +#define __add_and_fetch(a, b, c) \ +do { \ + (c) = *(a); \ +} while (cmpxchg((a), (c), (c) + (b)) != (c)) + +#define __fetch_and_and(a, b, c) \ +do { \ + (c) = *(a); \ +} while (cmpxchg((a), (c), (c) & (b)) != (c)) + +#define __fetch_and_or(a, b, c) \ +do { \ + (c) = *(a); \ +} while (cmpxchg((a), (c), (c) | (b)) != (c)) + +#else +#error "No non-cmpxchg code yet..." +#endif + +/* Note that these functions return the old value. */ + +#define atomic_type(name, type) \ +static __inline__ type atomicAdd##name(volatile type *ptr, type val) \ +{ \ + type r; \ + __add_and_fetch(ptr, val, r); \ + return r; \ +} \ +static __inline__ type atomicSet##name(volatile type *ptr, type val) \ +{ \ + type r; \ + __fetch_and_or(ptr, val, r); \ + return r; \ +} \ +static __inline__ type atomicClear##name(volatile type *ptr, type val) \ +{ \ + type r; \ + __fetch_and_and(ptr, ~val, r); \ + return r; \ +} + +atomic_type(Int, int) +atomic_type(UInt, unsigned int) +atomic_type(Uint, unsigned int) +atomic_type(Long, long) +atomic_type(ULong, unsigned long) + +#undef atomic_type + +/* PCI */ + +#define PCI_INB(port) inb((unsigned long) (port)) +#define PCI_INH(port) inw((unsigned long) (port)) +#define PCI_INW(port) inl((unsigned long) (port)) +#define PCI_OUTB(port,val) outb(val, (unsigned long) (port)) +#define PCI_OUTH(port,val) outw(val, (unsigned long) (port)) +#define PCI_OUTW(port,val) outl(val, (unsigned long) (port)) + +static __inline__ void +xscsi_disable_signals(void) +{ + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); +} + +#endif diff -Nur linux-2.4.19/include/linux/xscsi/xfailover.h linux-2.4.19-sgi211r3/include/linux/xscsi/xfailover.h --- linux-2.4.19/include/linux/xscsi/xfailover.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/xscsi/xfailover.h Tue Nov 19 17:03:03 2002 @@ -0,0 +1,191 @@ +/* + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#ifndef _FAILOVER_H_ +#define _FAILOVER_H_ + +struct fo_ioctl_args { + unsigned long arg1; + unsigned long arg2; +}; + +#if !__KERNEL__ +typedef void * vertex_hdl_t; +static int +fo_ioctl (int cmd, unsigned long arg1, unsigned long arg2) +{ + int fd; + int err=-1; + fd = open ("/dev/xscsi/failover", O_RDONLY); + if (fd <= 0) fd = open ("/devfs/xscsi/failover", O_RDONLY); + if (fd>0) { + struct fo_ioctl_args args; + args.arg1 = arg1; + args.arg2 = arg2; + err = ioctl (fd, cmd, &args); + close (fd); + } + else { + printf ("xscsifo: couldn't open failover device.\n"); + } + return err; +} +#endif + +/* + * Structure definitions for failover specific syssgi routines + * Usage: + * To force a failover switch: + * vertex_hdl_t p_vhdl, s_vhdl; + * syssgi(SGI_FO_SWITCH, p_vhdl, &s_vhdl); + * To get failover instance information: + * struct user_fo_instance *buf; + * int len; + * syssgi(SGI_FO_DUMP, buf, &len); + */ +struct user_fo_instance { + int foi_primary; + vertex_hdl_t foi_path_vhdl[0]; +}; + +typedef struct user_fo_generic_info { + int fgi_revision; + char fgi_instance_name[32]; /* cast to scsi_name_t */ + struct user_fo_generic_lun_data { + vertex_hdl_t fgi_lun_vhdl; + u_char fgi_inq_data[SCSI_INQUIRY_LEN]; + }fgi_lun_data[0]; +} user_fo_generic_info_t; + +#if __KERNEL__ +extern int fo_max_paths; +typedef void *scsi_name_t; + +#define FOI_PATHSTAT_INVALID 0 +#define FOI_PATHSTAT_VALID 1 +#define FOI_PATHSTAT_FAILED 2 /* Failed but maybe still usable */ +#define FOI_PATHSTAT_UNCLUN 3 + +#define FOI_NO_PRIMARY (-1) + +struct scsi_fo_instance { + struct scsi_fo_instance *foi_next; + struct scsi_candidate *foi_foc; + scsi_name_t foi_grp_name; + int foi_primary; + char foi_restrict; + struct foi_path_info { + vertex_hdl_t foi_path_vhdl; + u_char foi_path_status; + } foi_path[0]; +}; +typedef struct scsi_fo_instance scsi_fo_instance_struct_t; +typedef struct scsi_candidate *scsi_fo_instance_t; + +#define FO_NAMECMP_FAIL 0 +#define FO_NAMECMP_SUCCESS 1 +#define FO_NAMECMP_REPLACE 2 + +#define FO_VH_COH_POLICY_INVALID 0 +#define FO_VH_COH_POLICY_LAZY 1 +#define FO_VH_COH_POLICY_EAGER 2 + +struct scsi_candidate { + char *scsi_match_str1; /* First string used for matching */ + char *scsi_match_str2; /* Second string used for matching */ + u_char scsi_match_off1; /* Offset of 1st string in inventory */ + u_char scsi_match_off2; /* Offset of 2nd string in inventory */ + int (*scsi_validlun_func)(u_char *, vertex_hdl_t); + int (*scsi_getname_func)(vertex_hdl_t, scsi_name_t *, u_char *); + int (*scsi_cmpname_func)(scsi_name_t, scsi_name_t); + int (*scsi_freename_func)(scsi_name_t); + char *(*scsi_sprintf_func)(scsi_name_t); + int (*scsi_switch_func)(vertex_hdl_t, vertex_hdl_t); + int (*scsi_primary_func)(struct scsi_candidate *, + struct user_fo_generic_info *); + int (*scsi_reportwarnings_func)(vertex_hdl_t); + int scsi_vh_coherency_policy; + sema_t *scsi_foi_sema4; + struct scsi_fo_instance *scsi_foi; +}; +typedef struct scsi_candidate scsi_candidate_struct_t; +typedef struct scsi_candidate *scsi_candidate_t; + +extern struct scsi_candidate fo_candidates[]; + +/* + * Primary entry points to FAILOVER module + */ +#ifdef CONFIG_XSCSI_DKSC +void fo_scsi_lun_remove(vertex_hdl_t lun_vhdl); +void fo_scsi_device_update(u_char *inv, vertex_hdl_t lun_vhdl); +int fo_is_failover_candidate(u_char *inv, vertex_hdl_t unused_arg); +#else +#define fo_scsi_lun_remove(L) +#define fo_scsi_device_update(I,L) +#define fo_is_failover_candidate(I,U) 0 +#endif +int fo_scsi_device_switch(vertex_hdl_t p_vhdl, vertex_hdl_t *s_vhdl); +int fo_scsi_device_switch_new(vertex_hdl_t, vertex_hdl_t *, int); +int fo_scsi_device_pathcount(vertex_hdl_t vhdl); +int fo_scsi_device_path_state (vertex_hdl_t p_vhdl); +int fo_scsi_device_update_generic (user_fo_generic_info_t *fgi); +void fo_init(void); + +#define FO_SWITCH_SUCCESS 0 +#define FO_SWITCH_INVALID_PATH 1 +#define FO_SWITCH_NOPATH 2 /* degenerate case - no longer a possible return code */ +#define FO_SWITCH_ONEPATHONLY 3 +#define FO_SWITCH_PATHS_EXHAUSTED 4 +#define FO_SWITCH_FAIL -1 + +/* +** Values returned to caller via fo_scsi_device_path_state(). +*/ +#define FO_PRIMARY_PATH 5 +#define FO_ALTERNATE_PATH 6 +#define FO_UNKNOWN_DEVICE 7 +#define FO_INVALID_PATH FO_SWITCH_INVALID_PATH + + +#define FO_PATHCOUNT_FAIL -1 + +/* + * IDBG routines + */ +void idbg_foi(vertex_hdl_t lun_vhdl); + +#endif /* _KERNEL */ + +#endif diff -Nur linux-2.4.19/include/linux/xscsi/xscsi.h linux-2.4.19-sgi211r3/include/linux/xscsi/xscsi.h --- linux-2.4.19/include/linux/xscsi/xscsi.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/include/linux/xscsi/xscsi.h Tue Nov 19 16:55:03 2002 @@ -0,0 +1,936 @@ +/* + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +#ifndef _XSCSI_H +#define _XSCSI_H + +#define INV_FCNODE 0 +#define INV_SCSI 0 +#define INV_RAIDCTLR 0 +#define INV_SCSI_MASK 0 +#define INV_SCSIDRIVE 0 +#define INV_RAID5_LUN 0 +#define INV_CDROM 2 +#define INV_REMOVE 0 +#define INV_SCSIFLOPPY 0 +#define INV_DISK 0 +#define INV_PRIMARY 0 +#define INV_ALTERNATE 0 +#define INV_FAILED 0 +#define INV_OPTICAL 3 +#define INV_1394NODE 0 +#define INV_WORM 4 +#define INV_QL_2200 5 +#define INV_QL_2200A 22 +#define INV_QL_2300 24 +#define INV_QL_2310 25 +#define INV_QL_2342A 26 +#define INV_QL_2342B 27 +#define INV_QL_2340 28 + +#define XSCSI_PT_DISK 0 +#define XSCSI_PT_TAPE 1 +#define XSCSI_PT_PRINTER 2 +#define XSCSI_PT_PROC 3 +#define XSCSI_PT_WORM 4 +#define XSCSI_PT_CDROM 5 +#define XSCSI_PT_SCANNER 6 +#define XSCSI_PT_OPTICAL 7 +#define XSCSI_PT_JUKE 8 +#define XSCSI_PT_COMM 9 + +/* + * Calls from high level driver to low level driver + * + * scsi_command() issues a SCSI command to the low level SCSI driver. + * + * If a contingent allegiance condition is entered (check condition + * command status), a request sense will be automatically performed. + * If the sr_sense field of the request is not null, the sense data + * will be copied to the sr_sense address, but not more than + * sr_senselen bytes. + * + * In addition, whenever there is a contingent allegiance or SCSI bus + * reset, all commands queued in the driver and on the device (except + * for the command causing or noticing the error) will be returned + * with the sr_status field set to SC_ATTN. New commands will continue + * to be returned with this status until the flag bit SRF_AEN_ACK is + * set in sr_flags. + * + * Before any command queueing is done, the device driver should do + * a mode sense on mode page 0xA (control mode page) to discover the + * QErr bit setting. Error handling will not work correctly in a + * queued environment unless the QErr bit is set. + * + * scsi_alloc() initializes a connection between a device level driver and + * a host adaptor driver for a given controller, target, and lun. It + * will cause the low level driver to initialize structures needed for + * communication if it has not already done so. + * + * The opt argument gives additional information about how the driver + * would like to talk to the device. Currently, three options are + * allowed. + * SCSIALLOC_EXCLUSIVE causes the device to be allocated + * exclusively for the use of the calling driver. If a device is + * allocated for exclusive use, no other driver may access it. Also, + * if a device is already in use by another driver, exclusive or not, + * an exclusive alloc will fail. + * SCSIALLOC_NOSYNC will prevent future synchronous negotiations from + * being attempted on this device (where possible; not all adapters + * support this capability); only applies when no other driver already + * has the device open. Also see the SRF_NEG_SYNC flag below. + * SCSIALLOC_QDEPTH is a mask for an eight bit value + * specifying how many commands a device driver would like to + * queue (that is, the low bits of opt are used to pass the max + * depth the upper layer driver will use). It is to be + * considered advice only; the depth used may be less, but will + * never be greater. + * + * The cb argument is used as a callback if a request sense was done + * as a result of a check condition from a command. If the cb + * argument is NULL, no callbacks will be done. Note that having + * a callback set may result in a driver seeing the error twice. + * The purpose of the callback is to give make sure that a given + * driver gets all sense data from a device, even if it is returned + * with a command issued by a different driver. Only one driver is + * allowed to have a callback. scsi_alloc() will fail if a callback + * is requested, and another driver currently has a callback + * registered. + * + * A return value of SCSIALLOCOK indicates success; any other value + * indicates an error. 0 indicates a generic error such as bad + * values for the adapter or target; values > 1 typically are an + * errno value from errno.h, indicating the cause of the error + * (such as EBUSY if SCSIALLOC_EXCLUSIVE is used, and the device + * is already allocated), or EINVAL, if a non-null callback is + * passed, but a callback is already registered for the device. + * Note that this is a change introduced in IRIX 5.1.1; previously + * any non-0 return value was success. The change was made to + * allow the upper level drivers to better handle errors. + * + * scsi_free() terminates a connection between a device level driver and + * the host adaptor driver. The host adaptor driver will free any + * structures that it does not need. + * + * The callback argument should be the same as that given to + * scsi_alloc(). If it does not match, the callback will not be + * freed up. + * + * scsi_info() issues an inquiry to the given controller, target, and lun, + * returning a pointer to the scsi_target_info structure. It should + * be used to see if the device is appropriate to the driver making + * the call. + * + * The si_maxq field in the scsi_target_info structure (returned by + * scsi_info()) will give queueing information. + * + * scsi_abort() aborts the request passed as an argument. If it is + * currently active, an abort message will be sent to the device. + * A non-zero return indicates that the abort was successful. Not + * all host adaptors support this function. + * + * + * The way this is implemented using the hwgraph is as follows. + * The controller vertex in the hwgraph has the scsi function pointers + * stored as a part of information associated with the vertex. + * Eg:- /hw/scsi_ctlr/#1/target/#2/lun/#3/... + * + * Let the controller vertex handle be cvhdl pointed to by #1 & + * let the pointer to info hanging off the controller vertex be cinfo. + * Now the scsi functions can be accessed as follows. + * cinfo = scsi_ctlr_info_get(cvhdl); + * + * scsi_alloc(..) SCI_ALLOC(cinfo)(..) + * scsi_command(..) SCI_COMMAND(cinfo)(..) + * scsi_free(..) SCI_FREE(cinfo)(..) + * scsi_dump(..) SCI_DUMP(cinfo)(..) + * scsi_info(..) SCI_INQ(cinfo)(..) + * scsi_ioctl(..) SCI_IOCTL(cinfo)(..) + * scsi_abort(..) SCI_ABORT(cinfo)(..) + * + * There are backward pointers which finally get to the controller + * info from the vertices below the controller. + * For example scsi_command function can be called from the lun vertex + * handle pointed to by #3 above as follows. + * lun_info = scsi_lun_info_get(lun_vhdl); + * SLI_COMMAND(lun_info)(...) + * + * Sample code for initializing the controller info with these + * function pointers follows: + * + * Allocate the controller info structure. This hangs off the + * controller vertex. + + * scsi_ctlr_info_t *ctlr_info = scsi_ctlr_info_init(); + * . + * . + * . + * Initialize the function pointers in addition to other initializations + * + * SCI_ALLOC(ctlr_info) = your_alloc; + * SCI_COMMAND(ctlr_info) = your_command; + * SCI_FREE(ctlr_info) = your_free; + * SCI_DUMP(ctlr_info) = your_dump; + * SCI_INQ(ctlr_info) = your_info; + * SCI_IOCTL(ctlr_info) = your_ioctl; + * . + * . + * . + * Hang the information off the controller vertex + * + * scsi_ctlr_info_put(ctlr_vhdl,ctlr_info); + */ + +extern char *scsi_adaperrs_tab[]; + +#define SCSIALLOC_EXCLUSIVE 0x100 +#define SCSIALLOCOK 1 /* succesful return value from scsi_alloc function */ +#define SCSIDRIVER_NULL 0 + +#define SCSI_MAXLUN 64 + +/* + * SCSI sense defines and message external declarations + */ +#define SC_NUMSENSE 0x10 /* # of messages in scsi_key_msgtab */ +#define SC_NUMADDSENSE 0x71 /* # of messages in scsi_addit_msgtab */ +extern char *scsi_key_msgtab[], *scsi_addit_msgtab[]; + +/* base sense error codes */ +#define SC_NOSENSE 0x0 +#define SC_ERR_RECOVERED 0x1 +#define SC_NOT_READY 0x2 +#define SC_MEDIA_ERR 0x3 +#define SC_HARDW_ERR 0x4 +#define SC_ILLEGALREQ 0x5 +#define SC_UNIT_ATTN 0x6 +#define SC_DATA_PROT 0x7 +#define SC_BLANKCHK 0x8 +#define SC_VENDUNIQ 0x9 +#define SC_COPY_ABORT 0xA +#define SC_CMD_ABORT 0xB +#define SC_EQUAL 0xC +#define SC_VOL_OVERFL 0xD +#define SC_MISCMP 0xE + +/* some common extended sense error codes */ +#define SC_NO_ADD 0x0 /* no extended sense code */ +#define SC_NOINDEX 0x1 +#define SC_NOSEEKCOMP 0x2 +#define SC_WRITEFAULT 0x3 +#define SC_NOTREADY 0x4 +#define SC_NOTSEL 0x5 +#define SC_ECC 0x10 +#define SC_READERR 0x11 +#define SC_NOADDRID 0x12 +#define SC_NOADDRDATA 0x13 +#define SC_DEFECT_ERR 0x19 +#define SC_WRITEPROT 0x27 +#define SC_RESET 0x29 +#define SC_MEDIA_ABSENT 0x3a +/* Possible status bytes returned after a scsi command */ +#define ST_GOOD 0 +#define ST_CHECK 2 +#define ST_COND_MET 4 +#define ST_BUSY 8 +#define ST_INT_GOOD 16 +#define ST_INT_COND_MET 20 +#define ST_RES_CONF 24 + +/* Size of different scsi command classes */ +#define SC_CLASS0_SZ 6 +#define SC_CLASS1_SZ 10 +#define SC_CLASS2_SZ 12 +#define SC_CLASS4_SZ 16 +#define SC_CLASS5_SZ 12 + + +/* + * SCSI host adapter independent target information structure + * This structure is used to pass information between the host adapter drivers + * and the device drivers (disk, tape, etc.). + */ +struct scsi_target_info +{ + u_char *si_inq; /* inquiry data */ + u_char *si_sense; /* sense data from last request sense */ + u_char si_maxq; /* maximum queue depth for driver */ + u_char si_qdepth; /* max queue depth so far */ + u_char si_qlimit:1; /* boolean "max queue depth reached"? */ + uint si_ha_status; /* SRH_* status bits, if supported */ +}; +typedef struct scsi_target_info scsi_target_info_t; + +#define SCSI_INQUIRY_LEN 64 +#define SCSI_SENSE_LEN 64 +#define SCSI_MODESEL_PARAMLIST_LEN 12 + +/* + * Definitions for scsi_target_info.si_ha_status -- host adapter status bits + * Not all host adapter drivers will set or use these bits. + */ +#define SRH_CANTSYNC 0x01 /* sync xfer negotiations attempted, but + * device doesn't support sync; BADSYNC will be set if the negotation + * itself also failed */ +#define SRH_SYNCXFR 0x02 /* sync xfer mode in effect; async if not set; + * async mode is the default for all devscsi devices. */ +#define SRH_TRIEDSYNC 0x04 /* did sync negotations at some point. If + * SRH_CANTSYNC is not also set, the device supports sync mode. */ +#define SRH_BADSYNC 0x08 /* device doesn't handle sync negotations + * correctly; SRH_CANTSYNC will normally be set whenever this bit + * is set */ +#define SRH_NOADAPSYNC 0x10 /* scsi adapter doesn't handle sync + * negotations or system has been configured to not allow sync xfers + * on this target */ +#define SRH_WIDE 0x20 /* scsi adapter supports wide SCSI */ +#define SRH_DISC 0x40 /* scsi adapter supports disconnect and is configured + * for it */ +#define SRH_TAGQ 0x80 /* scsi adapter supports tagged queuing and is + * configured for it */ +#define SRH_MAPUSER 0x100 /* host adapter driver can map user addrs */ +#define SRH_QERR0 0x200 /* host adapter supports QERR==0 */ +#define SRH_QERR1 0x400 /* host adapter supports QERR==1 */ +#define SRH_ALENLIST 0x800 /* host adapter understands alenlists */ +#define SRH_MULTCMDS 0x1000 /* adapter wants queued commands */ +#define SRH_ATAPI 0x2000 /* is ATAPI (IDE) device. mode 10 byte + * cmds only, no settable blksize */ + +typedef struct scsi_disk_info scsi_disk_info_t; + +/* + * Definitions for operations on a SCSI bus or FC loop + * These structures and #defines are used with the scsi_ioctl interface. + */ +struct scsi_ha_op +{ + uint sb_opt; /* command option */ + uint sb_arg; /* usually data count */ + caddr_t sb_addr; /* usually user address */ +}; +typedef struct scsi_ha_op scsi_ha_op_t; + +/* + * Definition of array element filled in by SOP_GETMAP. Call SOP_GETMAP_SZ + * to get number of elements returned by SOP_GETMAP. + */ +struct fc_targ_map { + __u32 port_id; + __u32 reserved; + __u64 node_name; + __u64 port_name; + __u64 short_port_name; +}; + +/* + * Definition of structure filled in by SOP_GET_TARGET_PARMS + */ +struct scsi_parms +{ + uint sp_selection_timeout; /* Bus selection timeout (in uS) */ + ushort sp_scsi_host_id; /* Bus SCSI host ID */ + ushort sp_is_diff:8, /* Bus is differential, low voltage diff, single ended */ + :8; + struct scsi_target_parms { + ushort stp_is_present:1, /* Device present at this address */ + :7, + stp_is_sync:1, /* Device has negotiated synchronous */ + stp_is_wide:1; /* Device has negotiated wide */ + ushort stp_sync_period; /* Synchronous period (in nS) if stp_is_sync */ + ushort stp_sync_offset; /* Synchronous offset (in nS) if stp_is_sync */ + } sp_target_parms[16]; +}; +typedef struct scsi_parms scsi_parms_t; + +/* + * Structures used by SOP_GET_LNK_STS + */ +struct link_status { + __u32 link_failure_count; + __u32 loss_of_sync_count; + __u32 loss_of_signal_count; + __u32 primitive_sequence_protocol_error_count; + __u32 invalid_transmission_word_count; + __u32 invalid_crc_count; + __u64 reserved; +}; +typedef struct link_status link_status_t; + +struct port_link_statistics { + __u64 id; /* loop id/port name */ + __u64 name; /* node name */ + link_status_t link_status; + __s32 topology; /* topology */ + __u32 reserved[3]; +}; +typedef struct port_link_statistics port_link_statistics_t; + +/* FC topologies */ +#define LOOP_TOPOLOGY 1 /* FC-AL topology */ +#define SWITCH_TOPOLOGY 2 /* Fabric topology */ +#define P2P_TOPOLOGY 3 /* point-to-point topology */ + +/* link statistics options */ +#define GET_LNK_STATS_MAP_SZ 0 /* get max target count */ +#define GET_CTLR_LNK_STATS 1 /* controller link statistics */ +#define GET_LOOP_TARG_LNK_STATS 2 /* loop target link statistics */ +#define GET_FABRIC_TARG_LNK_STATS 3 /* fabric target link statistics */ +#define GET_ALL_TARGS_LNK_STATS 4 /* all targets link statistics */ + +#define SCIO 's' +#define _SCIO(X) ((SCIO << 8) | (X)) +/* + * SCSI bus and Fibrechannel loop commands: + * To download firmware, one would use the SOP_SENDDATA operation. + * To get operational statistics, use the SOP_GETDATA operation. + */ +#define SOP_RESET _SCIO(1) /* SCSI bus reset */ +#define SOP_SCAN _SCIO(2) /* scan for devices (inquiry) */ +#define SOP_QUIESCE _SCIO(3) /* queiece bus */ +#define SOP_UN_QUIESCE _SCIO(4) /* release bus from quesce state */ +#define SOP_QUIESCE_STATE _SCIO(5) /* get queisce state */ +#define SOP_MAKE_CTL_ALIAS _SCIO(6) /* make controler HWG aliases */ +#define SOP_GET_SCSI_PARMS _SCIO(7) /* get SCSI bus/target parameters */ +#define SOP_SET_BEHAVE _SCIO(8) /* set various controller behaviours */ +#define SOP_ENABLE _SCIO(9) /* enable a controller to execute commands */ +#define SOP_DISABLE _SCIO(10) /* disable a controller from executing commands */ + + /* For DEBUGLEVEL, level is sb_arg */ +#define SOP_DEBUGLEVEL _SCIO(11) /* set debug level in host adapter driver */ +#define SOP_GET_WWN _SCIO(12) /* get controller WWN */ + +#define SOP_LIP _SCIO(21) /* initiate FC lip */ +#define SOP_ENABLE_PBC _SCIO(22) /* Bypass a device -- turn on LRC */ +#define SOP_LPB SOP_ENABLE_PBC /* Bypass a device -- turn on LRC */ +#define SOP_DISABLE_PBC _SCIO(23) /* Unbypass a device -- turn off LRC */ +#define SOP_LPE SOP_DISABLE_PBC /* Unbypass a device -- turn off LRC */ +#define SOP_LPEALL _SCIO(24) /* Unbypass all devices on loop */ +#define SOP_LIPRST _SCIO(25) /* LIP with selective device RESET */ +#define SOP_GETMAP_SZ _SCIO(26) /* retrieve the target map max element count*/ +#define SOP_GETMAP _SCIO(27) /* retrieve the ctlr's target map */ +#define SOP_GET_LNK_STS _SCIO(28) /* get link error statistics */ +#define SOP_CTLR_STATE _SCIO(29) /* get controller state information */ + +/* for ATAPI / IDE */ +#define SOP_BLKSZ _SCIO(31) /* set/get blocksize */ + +/* SOP_CTLR_STATE result for qlfc driver */ +/* +** Note: this is a bit field and should be tested by examining +** the specified bit below. Other bits are undefined and should +** NOT be presumed to be zero! +*/ +#define CTLR_ENABLED 0x00000001 /* see SOP_ENABLE/SOP_DISABLE */ +/* For failover */ +#define SOP_FO_GET_MAX_PATHS _SCIO(41) /* return maximum failover paths */ +#define SGI_FO_GET_MAX_PATHS SOP_FO_GET_MAX_PATHS + +#define SOP_FO_DUMP _SCIO(42) /* retrieve failover group information */ +#define SGI_FO_DUMP SOP_FO_DUMP + +#define SOP_FO_SWITCH _SCIO(43) /* switch paths without performing tresspass */ +#define SGI_FO_SWITCH SOP_FO_SWITCH + +#define SOP_FO_TRESSPASS _SCIO(44) /* switch paths allowing tresspass */ +#define SGI_FO_TRESSPASS SOP_FO_TRESSPASS + +#define SOP_FO_GET_VERTEX_NAME _SCIO(45) /* return pathname for a given vertex hdl */ +#define SGI_FO_GET_VERTEX_NAME SOP_FO_GET_VERTEX_NAME + +#define SOP_FOUPDATE _SCIO(46) /* configure generic failover */ +#define DIOCFOUPDATE SOP_FOUPDATE + +/* SOP_QUIESCE_STATE ioctl write one of the following states to sb_addr */ +#define NO_QUIESCE_IN_PROGRESS 0x1 +#define QUIESCE_IN_PROGRESS 0x2 +#define QUIESCE_IS_COMPLETE 0x4 + +/* SOP_SET_BEHAVE behaviour subcodes in sb_opt */ +#define LUN_QERR 0x1 + +/* + * Encoding of sb_arg when sb_opt == LUN_QERR + * 00ttllqq tt = target number + * ll = lun number + * qq = 0/1 - QERR setting + */ +#define SOP_QERR_TARGET_SHFT 16 +#define SOP_QERR_LUN_SHFT 8 +#define SOP_QERR_VAL_SHFT 0 + + /* + * For GETDATA and SENDDATA: + * sb_opt is sub operation, + * sb_arg is count, and + * sb_addr is user address + */ +#define SOP_GETDATA 101 /* get data from host adapter driver */ +#define SOP_SENDDATA 102 /* send data to host adapter driver */ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +typedef devfs_handle_t vertex_hdl_t; + +#define device_controller_num_get(vhdl) +#define device_controller_num_set(vhdl, number) + +/* + * SCSI request structure + * This structure is used by a SCSI device driver to make a request to a + * SCSI host adapter. + * + * Return values from the host adapter driver are in the fields sr_status, + * sr_scsi_status, sr_sensegotten, and sr_resid. The sr_status field + * indicates the success or failure in circumstances that are outside the + * traditional SCSI protocol (like HW errors, cable errors, DMA errors, etc.). + * The sr_scsi_status field contains the SCSI status byte. If the command + * generated a check condition, a request sense will be attempted. If it + * fails, the sr_status and sr_scsi_status fields will apply to the request + * sense command, and the sr_sensegotten field will be -1. If it succeeds, + * the sr_status and sr_scsi_status fields will be 0, and the sr_sensegotten + * will contain the number of bytes of sense data received. The sr_resid + * field will be the difference between the number of bytes of data expected + * (in the sr_buflen field) and the number actually transferred in executing + * the command. + */ +struct scsi_request +{ + /* + * values filled in by device driver + */ + int sr_ctlr; + int sr_target; + uint64_t sr_lun; + vertex_hdl_t sr_lun_vhdl; /* dev_t for hba lun device */ + uint8_t sr_tag; /* first byte of tag message */ + + u_char *sr_command; /* scsi command */ + ushort sr_cmdlen; /* length of scsi command */ + ushort sr_flags; /* direction of data transfer */ + uint sr_timeout; /* in HZ */ + + u_char *sr_buffer; /* location of data */ + u_char *sr_sense; /* where to put sense data in case of CC */ + + uint sr_buflen; /* amount of data to transfer */ + uint sr_senselen; /* size of buffer allocated for sense data */ + + void (*sr_notify)(struct scsi_request *); /* callback pointer */ + void *sr_alenlist; /* pointer to alenlist created by dev driver */ + + /* + * fields used by device driver to reference structures at + * notify time or to keep track of retry counts, etc. + */ + void *sr_dev; + + /* + * spare fields used by host adapter driver + */ + void *sr_ha; /* usually used for linked list of req's */ + uint64_t sr_spare; /* used as spare pointer, int, etc. */ + + /* + * results filled in by host adapter driver + */ + uint sr_status; /* Status of command */ + u_char sr_scsi_status; /* SCSI status byte */ + u_char sr_ha_flags; /* flags used by host adaptor driver */ + short sr_sensegotten; /* number of sense bytes received; -1 == err */ + uint sr_resid; /* amount of sr_buflen not transferred */ + + +}; +typedef struct scsi_request scsi_request_t; +typedef uint64_t sr_spare_t; + +/* + * constants for scsirequest.sr_flags + */ +#define SRF_DIR_IN 0x0001 /* data xfer into memory (DMA write) if set */ +#define SRF_FLUSH 0x0002 /* data writeback/inval required */ +#define SRF_MAP 0x0004 /* map virtual address in sr_buffer */ +#define SRF_MAPBP 0x0008 +#define SRF_MAPUSER 0x0010 +#define SRF_ALENLIST 0x0020 /* Use alenlist provided in sr_alenlist */ +#define SRF_CONTINGENT_ALLEGIANCE_CLEAR \ + 0x0040 /* allow new command to be issued */ +#define SRF_AEN_ACK SRF_CONTINGENT_ALLEGIANCE_CLEAR +#define SRF_NEG_SYNC 0x0080 /* attempt to negotiate sync xfer mode on + * this command (if currently async; may be ignored by some + * adapter drivers, either always, or if the driver has previously + * failed to negotiate sync xfer mode with this target); this will + * override the SCSIALLOC_NOSYNC flag to scsi_alloc, if it was + * specified. */ +#define SRF_NEG_ASYNC 0x0100 /* attempt to negotiate async xfer mode on + * this command (if currently using sync xfers). */ +#define SRF_PRIORITY_REQUEST \ + 0x0200 /* "priority" scsi request */ + +/* + * constants for scsirequest.sr_status; corresponding text msgs in scsi.c + */ +#define SC_GOOD 0 /* No error */ +#define SC_TIMEOUT 1 /* Timeout on scsi bus (no response to selection) */ +#define SC_HARDERR 2 /* Hardware or scsi device error */ +#define SC_PARITY 3 /* Parity error on the SCSI bus during xfer */ +#define SC_MEMERR 4 /* Parity/ECC error on host memory */ +#define SC_CMDTIME 5 /* the command timed out (did not complete) */ +#define SC_ALIGN 6 /* i/o address wasn't properly aligned */ +#define SC_ATTN 7 /* unit attention received on other command + * or new command received after a unit attn + * without SRF_AEN_ACK set in sr_flags. */ +#define SC_REQUEST 8 /* error in request; malformed, for + * non-existent device; no alloc done, + * sr_notify not set, etc. */ +#define NUM_ADAP_ERRS (SC_REQUEST+1) + + +/* + * constants for scsirequest.sr_tag + */ +#define SC_TAG_SIMPLE 0x20 /* Simple tag message */ +#define SC_TAG_HEAD 0x21 /* Head of queue tag message */ +#define SC_TAG_ORDERED 0x22 /* Ordered tag message */ + +#define LOC_STR_MAX_LEN 50 /* max. length of the locator string */ + +typedef int ctlr_t; /* type for the adapter */ +typedef int targ_t; /* type for the target */ +typedef int lun_t; /* type for the lun */ +typedef uint64_t fw_targ_t; /* type for 1394 (global ID) */ +typedef struct pci_dev * scsi_pci_vhdl_t; + +#define GRAPH_VERTEX_NONE NULL + +typedef struct scsi_ctlr_info { + vertex_hdl_t sci_ctlr_vhdl; /* vertex handle of the controller */ + vertex_hdl_t sci_base_vhdl; /* attach point for this controller */ + int sci_if_number; /* interface number on chip */ + + /* + * scsi functional interface + */ + int (*sci_alloc)(vertex_hdl_t, int, + void (*)(vertex_hdl_t, uint8_t *)); + void (*sci_free)(vertex_hdl_t, + void (*)(vertex_hdl_t, uint8_t *)); + struct scsi_target_info * (*sci_inq)(vertex_hdl_t); + + int (*sci_dump)(vertex_hdl_t ctlr_vhdl); + int (*sci_ioctl)(vertex_hdl_t ctlr_vhdl, + unsigned int cmd, + struct scsi_ha_op *op); + + void (*sci_command)(scsi_request_t *); + int (*sci_abort)(scsi_request_t *); + + uint64_t sci_initiator_id; + int sci_adap; /* adapter number */ + u_char sci_scsi_type; /* type of interface */ + struct pci_dev *sci_pci; + void *sci_info; /* info maintained for the controller */ +} scsi_ctlr_info_t; + +/* + * macros associated with the controller info + */ +#define SCI_CTLR_VHDL(p) (p->sci_ctlr_vhdl) /* controller vertex handle */ +#define SCI_BASE_VHDL(p) (p->sci_base_vhdl) +#define SCI_IF_NUMBER(p) (p->sci_if_number) +#define SCI_ADAP(p) (p->sci_adap) /* adapter number */ + +#define SCI_ALLOC(p) (p->sci_alloc) +#define SCI_FREE(p) (p->sci_free) +#define SCI_INQ(p) (p->sci_inq) +#define SCI_DUMP(p) (p->sci_dump) +#define SCI_IOCTL(p) (p->sci_ioctl) +#define SCI_COMMAND(p) (p->sci_command) +#define SCI_ABORT(p) (p->sci_abort) +#define SCI_SCSI_TYPE(p) (p->sci_scsi_type) +#define SCI_PCI(p) (p->sci_pci) +#define SCI_INFO(p) (p->sci_info) + +#define SCI_SCSI_TYPE_UNSPECIFIED 0 /* unspecified */ +#define SCI_SCSI_TYPE_1394 1 /* firewire, ie SBP2 on OHCI over 1394 */ +#define SCI_SCSI_TYPE_PARALLEL 2 /* parallel scsi */ +#define SCI_SCSI_TYPE_FC 3 /* fibre channel */ + +#include +static inline void +scsi_ctlr_vertex_sprintf(char *name, struct pci_dev *pci, int channel) +{ + if (channel > 0) + sprintf(name, "pci%02x.%02x.%d-%d", pci->bus->number, + PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn), channel); + else + sprintf(name, "pci%02x.%02x.%d", pci->bus->number, + PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn)); +} + +/* + * information maintained for the scsi target vertex + */ +typedef struct scsi_targ_info { + vertex_hdl_t sti_targ_vhdl; + scsi_ctlr_info_t *sti_ctlr_info; /* scsi controller info */ + targ_t sti_targ; /* unit number */ + void *sti_info; /* info maintained for the target */ + uint64_t sti_node; /* FC node name */ + uint64_t sti_port; /* FC port name */ +} scsi_targ_info_t; + +/* + * macros associated with the target info + */ +#define STI_TARG_VHDL(p) (p->sti_targ_vhdl) +#define STI_CTLR_INFO(p) (p->sti_ctlr_info) /* controller info */ +#define STI_TARG(p) (p->sti_targ) /* unit number */ +#define STI_INFO(p) (p->sti_info) /* driver specific target info */ +#define STI_NODE(p) (p->sti_node) +#define STI_PORT(p) (p->sti_port) + +#define EDGE_LBL_TARGET "target" + +/* + * information associated with a scsi lun vertex + */ +#define SLI_VENDOR_ID_LEN 8 +#define SLI_PRODUCT_ID_LEN 16 +typedef struct scsi_lun_info { + vertex_hdl_t sli_lun_vhdl; /* lun vertex handle */ + scsi_targ_info_t *sli_targ_info; /* scsi target info */ + lun_t sli_lun; /* lun */ + void *sli_info; /* info maintained for the HBA driver */ + void *sli_fo_info; /* pointer to failover info */ + uint8_t sli_device_type; /* SCSI device type */ + uint8_t sli_vendor_id[SLI_VENDOR_ID_LEN+1]; /* null terminated */ + uint8_t sli_product_id[SLI_PRODUCT_ID_LEN+1]; /* null terminated */ +} scsi_lun_info_t; + +/* + * macros associated with the lun info + */ +#define SLI_LUN_VHDL(p) (p->sli_lun_vhdl) /* lun vhdl */ +#define SLI_TARG_INFO(p) (p->sli_targ_info) /* target info */ +#define SLI_LUN(p) (p->sli_lun) /* lun */ +#define SLI_INFO(p) (p->sli_info) +#define SLI_FO_INFO(p) (p->sli_fo_info) +#define SLI_DEVICE_TYPE(p) (p->sli_device_type) +#define SLI_VENDOR_ID(p) (p->sli_vendor_id) +#define SLI_PRODUCT_ID(p) (p->sli_product_id) + +#define SLI_TARG(p) (STI_TARG(SLI_TARG_INFO(p))) /* unit number */ +#define SLI_NODE(p) (STI_NODE(SLI_TARG_INFO(p))) +#define SLI_PORT(p) (STI_PORT(SLI_TARG_INFO(p))) +#define SLI_CTLR_INFO(p) (STI_CTLR_INFO(SLI_TARG_INFO(p))) /* controller info from + * lun info pointer + */ + +#define SLI_CTLR_VHDL(p) (SCI_CTLR_VHDL(STI_CTLR_INFO(SLI_TARG_INFO(p)))) +#define SLI_ADAP(p) (SCI_ADAP(STI_CTLR_INFO(SLI_TARG_INFO(p)))) +#define SLI_SCSI_TYPE(p) (SCI_SCSI_TYPE(STI_CTLR_INFO(SLI_TARG_INFO(p)))) + /* controller number + * from lun info ptr + */ +#define SLI_INQ(p) (*(SCI_INQ(STI_CTLR_INFO(SLI_TARG_INFO(p))))) +#define SLI_ALLOC(p) (*(SCI_ALLOC(STI_CTLR_INFO(SLI_TARG_INFO(p))))) +#define SLI_FREE(p) (*(SCI_FREE(STI_CTLR_INFO(SLI_TARG_INFO(p))))) +#define SLI_COMMAND(p) (*(SCI_COMMAND(STI_CTLR_INFO(SLI_TARG_INFO(p))))) +#define SLI_IOCTL(p) (*(SCI_IOCTL(STI_CTLR_INFO(SLI_TARG_INFO(p))))) + +#define EDGE_LBL_LUN "lun" + +/* + * information associated with an devscsi vertex + */ +typedef struct scsi_dev_info { + scsi_lun_info_t *sdevi_lun_info; +} scsi_dev_info_t; + +#define SDEVI_LUN_INFO(p) (p->sdevi_lun_info) +#define SDEVI_ADAP(p) (SLI_ADAP(SDEVI_LUN_INFO(p))) +#define SDEVI_SCSI_TYPE(p) (SLI_SCSI_TYPE(SDEVI_LUN_INFO(p))) +#define SDEVI_TARG(p) (SLI_TARG(SDEVI_LUN_INFO(p))) +#define SDEVI_LUN(p) (SLI_LUN(SDEVI_LUN_INFO(p))) +#define SDEVI_LUN_VHDL(p) (SLI_LUN_VHDL(SDEVI_LUN_INFO(p))) +#define SDEVI_NODE(p) (SLI_NODE(SDEVI_LUN_INFO(p))) +#define SDEVI_PORT(p) (SLI_PORT(SDEVI_LUN_INFO(p))) + +#define SDEVI_ALLOC(p) (*(SCI_ALLOC(STI_CTLR_INFO(SLI_TARG_INFO(SDEVI_LUN_INFO(p)))))) + /* alloc function pointer from scsi info */ +#define SDEVI_FREE(p) (*(SCI_FREE(STI_CTLR_INFO(SLI_TARG_INFO(SDEVI_LUN_INFO(p)))))) + /* free function pointer from scsi info */ +#define SDEVI_INQ(dev) (*(SCI_INQ(STI_CTLR_INFO(SLI_TARG_INFO(SDEVI_LUN_INFO(scsi_dev_info_get(dev))))))) + /* info function pointer from scsi info */ +#define SDEVI_IOCTL(dev) (*(SCI_IOCTL(STI_CTLR_INFO(SLI_TARG_INFO(SDEVI_LUN_INFO(scsi_dev_info_get(dev))))))) + /* ioctl function pointer from scsi info */ +#define SDEVI_COMMAND(p) (*(SCI_COMMAND(STI_CTLR_INFO(SLI_TARG_INFO(SDEVI_LUN_INFO(p)))))) + /* command function ptr from scsi info*/ +#define SDEVI_ABORT(dev) (*(SCI_ABORT(STI_CTLR_INFO(SLI_TARG_INFO(SDEVI_LUN_INFO(scsi_dev_info_get(dev))))))) + +extern void scsi_device_update(u_char *, vertex_hdl_t); + +#if 0 +/* + * These aren't used. They are here for tags and text searches. The + * real definitions are below in the scsi_struct_type macro invocations. + */ +int scsi_ctlr_info_init, scsi_ctlr_info_free, scsi_ctlr_info_put, scsi_ctlr_info_get, + scsi_targ_info_init, scsi_targ_info_free, scsi_targ_info_put, scsi_targ_info_get, + scsi_lun_info_init, scsi_lun_info_free, scsi_lun_info_put, scsi_lun_info_get, + scsi_dev_info_init, scsi_dev_info_free, scsi_dev_info_put, scsi_dev_info_get; +#endif + +#define scsi_struct_type(type) \ +static __inline__ scsi_##type##_info_t * \ +scsi_##type##_info_init(void) \ +{ \ + return kmem_zalloc(sizeof(scsi_##type##_info_t), KM_SLEEP); \ +} \ +static __inline__ void \ +scsi_##type##_info_free(devfs_handle_t de) \ +{ \ + scsi_##type##_info_t *p; \ + p = devfs_get_info(de); \ + devfs_set_info(de, NULL); \ + kmem_free(p, sizeof(scsi_##type##_info_t)); \ +} \ +static __inline__ void \ +scsi_##type##_info_put(devfs_handle_t de, scsi_##type##_info_t *p) \ +{ \ + devfs_set_info(de, p); \ +} \ +static __inline__ scsi_##type##_info_t * \ +scsi_##type##_info_get(devfs_handle_t de) \ +{ \ + return devfs_get_info(de); \ +} + +scsi_struct_type(ctlr) +scsi_struct_type(targ) +scsi_struct_type(lun) +scsi_struct_type(dev) + +#undef scsi_struct_type + +extern vertex_hdl_t scsi_ctlr_vertex_exist(vertex_hdl_t, int); +extern vertex_hdl_t scsi_ctlr_vertex_add(struct pci_dev *pci, int); +extern vertex_hdl_t scsi_targ_vertex_exist(vertex_hdl_t, targ_t); +extern vertex_hdl_t scsi_node_port_vertex_exist(vertex_hdl_t, + uint64_t, uint64_t); +extern vertex_hdl_t scsi_targ_vertex_add(vertex_hdl_t,targ_t); +extern vertex_hdl_t scsi_node_port_vertex_add(vertex_hdl_t, + uint64_t, uint64_t); +extern void scsi_targ_vertex_remove(vertex_hdl_t,targ_t); +extern void scsi_node_port_vertex_remove(vertex_hdl_t, + uint64_t, uint64_t); + +extern vertex_hdl_t scsi_lun_vertex_exist(vertex_hdl_t, lun_t); +extern vertex_hdl_t scsi_lun_vertex_add(vertex_hdl_t,lun_t); +extern void scsi_lun_vertex_remove(vertex_hdl_t,lun_t); + +extern void scsi_bus_create(vertex_hdl_t); +extern vertex_hdl_t scsi_lun_vhdl_get(vertex_hdl_t,targ_t,lun_t); +extern vertex_hdl_t scsi_fabric_lun_vhdl_get(vertex_hdl_t, uint64_t, + uint64_t, lun_t); + +extern void xscsi_notify(void); + +extern uint64_t fc_short_portname(uint64_t, uint64_t); + +typedef struct { + char *str; + u_char offset; + unsigned long arg; +} single_inq_str_s; +typedef single_inq_str_s *single_inq_str_t; + +typedef struct { + char *str1; + u_char offset1; + char *str2; + u_char offset2; + unsigned long arg; +} double_inq_str_s; +typedef double_inq_str_s *double_inq_str_t; + +/* + * Lock defines for access of vertices by the device drivers (dksc, + * ds, tpsc, smfd, 3rd party), and removal of vertices by the hba + * drivers. + */ +extern struct rw_semaphore scsi_hwgraph_lock; +#define SCSI_HWG_ACCESS() down_read(&scsi_hwgraph_lock); +#define SCSI_HWG_UPDATE() down_write(&scsi_hwgraph_lock); +#define SCSI_HWG_UNACCESS() up_read(&scsi_hwgraph_lock); +#define SCSI_HWG_UNUPDATE() up_write(&scsi_hwgraph_lock); + +#ifdef CONFIG_XSCSI_DKSC +void dksc_disk_remove(vertex_hdl_t); +void *dksc_disk_add(vertex_hdl_t); +void dksc_notify(void); +int dksc_proc_info(char *, char **, off_t, int); +void dkscinit(void); +void dksc_reprobe(vertex_hdl_t lun_vhdl); +int dk_set_flags (vertex_hdl_t lun_vhdl, int dk_flags); +int dk_clr_flags (vertex_hdl_t lun_vhdl, int dk_flags); +#else +#define dksc_disk_remove(X) +#define dksc_disk_add(X) 0 +#define dksc_notify() +#endif + +#ifdef CONFIG_XSCSI_MMSC +void mmsc_disk_remove(vertex_hdl_t); +void *mmsc_disk_add(vertex_hdl_t); +void mmsc_notify(void); +void mmscinit(void); +#else +#define mmsc_disk_remove(X) +#define mmsc_disk_add(X) 0 +#define mmsc_notify() +#endif + +#define cdrom_inquiry_test(X) 0 +extern struct file_operations scsiha_ops; +extern struct file_operations xscsids_ops; + +#endif +#endif /* _XSCSI_H */ diff -Nur linux-2.4.19/include/net/tcp_ecn.h linux-2.4.19-sgi211r3/include/net/tcp_ecn.h --- linux-2.4.19/include/net/tcp_ecn.h Fri Nov 2 17:43:26 2001 +++ linux-2.4.19-sgi211r3/include/net/tcp_ecn.h Fri Feb 1 11:39:38 2002 @@ -1,6 +1,7 @@ #ifndef _NET_TCP_ECN_H_ #define _NET_TCP_ECN_H_ 1 +#include #include #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) @@ -44,6 +45,14 @@ th->ece = 1; } +#ifdef CONFIG_NET + +/* + * This function references fields in a socket structure that dont exist if NETWORKS + * is not configured. Fortunately, the function is not used if networks + * are not configured. + * note: SGI patch but problem exists in generic linux + */ static __inline__ void TCP_ECN_send(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb, int tcp_header_len) { @@ -64,7 +73,7 @@ skb->h.th->ece = 1; } } - +#endif /* Input functions */ static __inline__ void diff -Nur linux-2.4.19/init/do_mounts.c linux-2.4.19-sgi211r3/init/do_mounts.c --- linux-2.4.19/init/do_mounts.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/init/do_mounts.c Mon Oct 28 20:43:23 2002 @@ -368,7 +368,11 @@ if (!do_devfs) return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev)); - handle = devfs_find_handle(NULL, dev ? NULL : devfs_name, + // Original code: handle = devfs_find_handle(NULL, dev ? NULL : devfs_name, + // When devfs is on SN, and if we are using a devfs mapped name for root, + // we need to create this mapped name MAJOR/MINOR instead of the default + // Major/Minor for something like /dev/sda3. + handle = devfs_find_handle(NULL, devfs_name, MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1); if (!handle) return -1; @@ -777,8 +781,7 @@ pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) { while (pid != wait(&i)) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } diff -Nur linux-2.4.19/init/kerntypes.c linux-2.4.19-sgi211r3/init/kerntypes.c --- linux-2.4.19/init/kerntypes.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/init/kerntypes.c Wed Jan 15 09:11:41 2003 @@ -0,0 +1,127 @@ +/* + * kerntypes.c + * + * Copyright (C) 2000 Tom Morano (tjm@sgi.com) and + * Matt D. Robinson (yakker@alacritech.com) + * + * Dummy module that includes headers for all kernel types of interest. + * The kernel type information is used by the lcrash utility when + * analyzing system crash dumps or the live system. Using the type + * information for the running system, rather than kernel header files, + * makes for a more flexible and robust analysis tool. + * + * This source code is released under version 2 of the GNU GPL. + */ +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +#include +#include +#include +#include +#include +#include + +/* The following includes and structures are needed for SGI's SN + * platform. + */ +#if defined(CONFIG_IA64_SGI_SN) +#include +#include +#include +#include +#include +#include +#include +#include + +/** + ** Various devfs type definitions lifted from fs/devfs/base.c + **/ + +struct directory_type +{ + rwlock_t lock; /* Lock for searching(R)/updating(W) */ + struct devfs_entry *first; + struct devfs_entry *last; + unsigned short num_removable; /* Lock for writing but not reading */ + unsigned char no_more_additions:1; +}; + +struct file_type +{ + unsigned long size; +}; + +struct device_type +{ + unsigned short major; + unsigned short minor; +}; + +struct fcb_type /* File, char, block type */ +{ + void *ops; + union + { + struct file_type file; + struct device_type device; + } + u; + unsigned char auto_owner:1; + unsigned char aopen_notify:1; + unsigned char removable:1; /* Belongs in device_type, but save space */ + unsigned char open:1; /* Not entirely correct */ + unsigned char autogen:1; /* Belongs in device_type, but save space */ +}; + +struct symlink_type +{ + unsigned int length; /* Not including the NULL-termimator */ + char *linkname; /* This is NULL-terminated */ +}; + +struct devfs_inode /* This structure is for "persistent" inode storage */ +{ + struct dentry *dentry; + time_t atime; + time_t mtime; + time_t ctime; + unsigned int ino; /* Inode number as seen in the VFS */ + uid_t uid; + gid_t gid; +}; + +struct devfs_entry +{ +#ifdef CONFIG_DEVFS_DEBUG + unsigned int magic_number; +#endif + void *info; + atomic_t refcount; /* When this drops to zero, it's unused */ + union + { + struct directory_type dir; + struct fcb_type fcb; + struct symlink_type symlink; + const char *name; /* Only used for (mode == 0) */ + } + u; + struct devfs_entry *prev; /* Previous entry in the parent directory */ + struct devfs_entry *next; /* Next entry in the parent directory */ + struct devfs_entry *parent; /* The parent directory */ + struct devfs_entry *slave; /* Another entry to unregister */ + struct devfs_inode inode; + umode_t mode; + unsigned short namelen; /* I think 64k+ filenames are a way off... */ + unsigned char hide:1; + unsigned char vfs_deletable:1;/* Whether the VFS may delete the entry */ + char name[1]; /* This is just a dummy: the allocated array + is bigger. This is NULL-terminated */ +}; +#endif + +void +kerntypes_dummy(void) +{ +} diff -Nur linux-2.4.19/init/main.c linux-2.4.19-sgi211r3/init/main.c --- linux-2.4.19/init/main.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/init/main.c Mon Oct 28 20:43:23 2002 @@ -25,8 +25,11 @@ #include #include #include +#include #include #include +#include +#include #include #include @@ -36,6 +39,10 @@ #include #endif +#ifdef CONFIG_ACPI +#include +#endif + #ifdef CONFIG_PCI #include #endif @@ -69,6 +76,15 @@ #include #endif +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ + +#ifdef CONFIG_IA64_SGI_AUTOTEST +extern void sgi_mcatest(int); +extern int autotest_enabled; +#endif + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -97,6 +113,8 @@ extern void free_initmem(void); +extern void kiobuf_setup(void); + #ifdef CONFIG_TC extern void tc_init(void); #endif @@ -118,6 +136,20 @@ int rows, cols; +/* + * The kernel_magic value represents the address of _end, which allows + * namelist tools to "match" each other respectively. That way a tool + * that looks at /dev/mem can verify that it is using the right System.map + * file -- if kernel_magic doesn't equal the namelist value of _end, + * something's wrong. + */ +#if defined(CONFIG_ARCH_S390) || defined(CONFIG_ARCH_S390X) || defined(CONFIG_ARCH_ARM) +extern unsigned long _end; +#else +extern char _end; +#endif +unsigned long *kernel_magic = &_end; + char *execute_command; static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; @@ -251,6 +283,34 @@ } if (next != NULL) *next++ = 0; +#ifdef CONFIG_KDB + /* kdb, kdb=on, kdb=off, kdb=early */ + if (strncmp(line, "kdb", 3) == 0) { + if (line[3] == '\0') { + /* Backward compatibility, kdb with no option means early activation */ + printk("Boot flag kdb with no options is obsolete, use kdb=early\n"); + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + if (line[3] == '=') { + if (strcmp(line+4, "on") == 0) { + kdb_on = 1; + continue; + } + if (strcmp(line+4, "off") == 0) { + kdb_on = 0; + continue; + } + if (strcmp(line+4, "early") == 0) { + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + printk("Boot flag %s not recognised, assumed to be environment variable\n", line); + } + } +#endif /* CONFIG_KDB */ if (!strncmp(line,"init=",5)) { line += 5; execute_command = line; @@ -288,8 +348,6 @@ extern void setup_arch(char **); extern void cpu_idle(void); -unsigned long wait_init_idle; - #ifndef CONFIG_SMP #ifdef CONFIG_X86_LOCAL_APIC @@ -303,29 +361,19 @@ #else - /* Called by boot processor to activate the rest. */ static void __init smp_init(void) { /* Get other processors into their bootup holding patterns. */ smp_boot_cpus(); - wait_init_idle = cpu_online_map; - clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */ smp_threads_ready=1; smp_commence(); - - /* Wait for the other cpus to set up their idle processes */ - printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle); - while (wait_init_idle) { - cpu_relax(); - barrier(); - } - printk("All processors have done init_idle\n"); } #endif + /* * We need to finalize in a non-__init function or else race conditions * between the root thread and the init thread may cause start_kernel to @@ -335,11 +383,13 @@ static void rest_init(void) { +#ifdef CONFIG_IA64_SGI_AUTOTEST + if (!autotest_enabled) +#endif kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); unlock_kernel(); - current->need_resched = 1; - cpu_idle(); -} + cpu_idle(); +} /* * Activate the first processor. @@ -358,11 +408,27 @@ setup_arch(&command_line); printk("Kernel command line: %s\n", saved_command_line); parse_options(command_line); +#ifdef CONFIG_CPUMEMSET + cms_cmm_static_init(); +#endif +#ifdef CONFIG_IA64_SGI_AUTOTEST + sgi_mcatest(0); +#endif trap_init(); + rcu_init(); init_IRQ(); sched_init(); softirq_init(); time_init(); +#ifdef CONFIG_PERFMON + // HACK: We need to make sure that the pmv gets initialized + // on the BSP, so we do it real early to be sure. This hack + // will be replaced by the real fix from Stephane Eranian at + // some point in the future. The pmv may get initialized twice + // on the BSP, but that doesn't matter, just so it gets + // initialized at least once. + perfmon_init_percpu(); +#endif /* * HACK ALERT! This is early. We're enabling the console before @@ -398,6 +464,13 @@ kmem_cache_sizes_init(); pgtable_cache_init(); +#ifdef CONFIG_KDB + kdb_init(); + if (KDB_FLAG(EARLYKDB)) { + KDB_ENTER(); + } +#endif /* CONFIG_KDB */ + /* * For architectures that have highmem, num_mappedpages represents * the amount of memory the kernel can use. For other architectures @@ -413,6 +486,8 @@ vfs_caches_init(num_physpages); buffer_init(num_physpages); page_cache_init(num_physpages); + kiobuf_setup(); + #if defined(CONFIG_ARCH_S390) ccwcache_init(); #endif @@ -423,15 +498,23 @@ #if defined(CONFIG_SYSVIPC) ipc_init(); #endif +#if defined(CONFIG_DUMP) + dump_init(); +#endif check_bugs(); + printk("POSIX conformance testing by UNIFIX\n"); - /* - * We count on the initial thread going ok - * Like idlers init is an unlocked kernel thread, which will - * make syscalls (and thus be locked). + init_idle(current, smp_processor_id()); + /* + * We count on the initial thread going ok + * Like idlers init is an unlocked kernel thread, which will + * make syscalls (and thus be locked). */ smp_init(); +#ifdef CONFIG_CPUMEMSET + cms_cmm_init(); +#endif rest_init(); } @@ -460,7 +543,12 @@ */ static void __init do_basic_setup(void) { - + /* + * Let the per-CPU migration threads start up: + */ +#if CONFIG_SMP + migration_init(); +#endif /* * Tell the world that we're going to be the grim * reaper of innocent orphaned children. @@ -492,7 +580,13 @@ s390_init_machine_check(); #endif +#ifdef CONFIG_ACPI_INTERPRETER + acpi_init(); +#endif #ifdef CONFIG_PCI +#ifdef CONFIG_IA64_SGI_SN_SIM + if (!IS_RUNNING_ON_SIMULATOR()) +#endif pci_init(); #endif #ifdef CONFIG_SBUS diff -Nur linux-2.4.19/ipc/sem.c linux-2.4.19-sgi211r3/ipc/sem.c --- linux-2.4.19/ipc/sem.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/ipc/sem.c Mon Oct 28 20:43:23 2002 @@ -62,6 +62,7 @@ #include #include #include +#include #include #include "util.h" @@ -996,6 +997,8 @@ struct sem_array *sma; int nsems, i; + lock_kernel(); + /* If the current process was sleeping for a semaphore, * remove it from the queue. */ @@ -1052,6 +1055,8 @@ sem_unlock(semid); } current->semundo = NULL; + + unlock_kernel(); } #ifdef CONFIG_PROC_FS diff -Nur linux-2.4.19/kdb/ChangeLog linux-2.4.19-sgi211r3/kdb/ChangeLog --- linux-2.4.19/kdb/ChangeLog Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/ChangeLog Tue Feb 4 15:36:30 2003 @@ -0,0 +1,625 @@ +2003-02-04 Keith Owens + + * Backport to 2.4.19. + * kdb v3.0-2.4.19-common-1. + +2003-02-03 Keith Owens + + * Register kdb commands early. + * Decode oops via kallsyms if it is available. + * Update copyright notices to 2003. + * Add defcmd/endefcmd to allow users to package their own macros. + * kdb commands that fail are ignored when prefixed with '-'. + * Add selection options to bta command. + * Add btc command (switch to each cpu and backtrace). + * Do real time detection of dead cpus. + * Clear ip adjusted flag when leaving kdb. + * Clean up ps command. + * Print ps output for each task when backtracing. + * Bump to version v3.0 to reduce confusion between kdb and kernel + version numbers. + * Add kdba_local_arch_setup/kdba_local_arch_cleanup to correct + keyboard freeze. Ashish Kalra. + * Refuse multiple breakpoints at the same address. + * Add fl (file_lock) command, from XFS development tree. + * Correct inode_pages, from XFS development tree. + * Add command history and editing. Sonic Zhang. + * Extend command history and editing to handle vt100 escape sequences. + * Allow tab completion at start of line. + * Touch nmi watchdog on long running bta and btc commands. + * Clean up ps output and standardize with bta codes. + * Correctly handle escaped characters in commands. + * Update man pages for btc and command history/editing. + * kdb v3.0-2.4.20-common-1. + +2002-11-29 Keith Owens + + * Upgrade to 2.4.20. + * Correct Documentation/kdb/kdb_sr.man. + * Remove leading zeroes from pids, they are decimal, not octal. + * kdb v2.5-2.4.20-common-1. + +2002-11-14 Keith Owens + + * Upgrade to 2.4.20-rc1. + * kdb v2.5-2.4.20-rc1-common-1. + +2002-11-14 Keith Owens + + * Fix processing with O(1) scheduler. + * 'go' switches back to initial cpu first. + * 'go
' only allowed on initial cpu. + * 'go' installs the global breakpoints from the initial cpu before + releasing the other cpus. + * If 'go' has to single step over a breakpoint then it single steps just + the initial cpu, installs the global breakpoints then releases the + other cpus. + * General clean up of handling for breakpoints and single stepping over + software breakpoints. + * Add kdb_notifier_block so other code can tell when kdb is in control. + * kdb v2.5-2.4.19-common-1. + +2002-11-02 Keith Owens + + * Correct build without CONFIG_KDB. + * kdb v2.4-2.4.19-common-3. + +2002-11-01 Keith Owens + + * Minimize differences from 2.5.44. + * kdb v2.4-2.4.19-common-2. + +2002-10-31 Keith Owens + + * Add defcmd/endefcmd feature. + * Remove kdb_eframe_t. + * Clear bp data before using. + * Sanity check if we have pt_regs. + * Force LINES > 1. + * Remove special case for KDB_REASON_PANIC, use KDB_ENTER() instead. + * Remove kdba_getcurrentframe(). + * Coexist with O(1) scheduler. + * Add lines option to dmesg, speed up dmesg. + * kdb v2.4-2.4.19-common-1. + +2002-10-17 Keith Owens + + * Add selection critera to ps and bta commands. + * kdb v2.3-2.4.19-common-4. + +2002-10-07 Keith Owens + + * New man page, Documentation/kdb/kdb_sr.man. + +2002-10-04 Keith Owens + + * Minimize differences between patches for 2.4 and 2.5 kernels. + * Add Configure.help for CONFIG_KDB_USB. + * Reduce stack usage. + * kdb v2.3-2.4.19-common-3. + +2002-08-10 Keith Owens + + * Replace kdb_port with kdb_serial to support memory mapped I/O. + David Mosberger. + * kdb v2.3-2.4.19-common-2. + +2002-08-07 Keith Owens + + * Upgrade to 2.4.19. + * Remove individual SGI copyrights, the general SGI copyright applies. + * Handle md0. Reported by Hugh Dickins, different fix by Keith Owens. + * Use page_address() in kdbm_pg.c. Hugh Dickins. + * Remove debugging printk from kdbm_pg.c. Hugh Dickins. + * Move breakpoint address verification into arch dependent code. + * Dynamically resize kdb command table as required. + * Common code to support USB keyboard. Sebastien Lelarge. + * kdb v2.3-2.4.19-common-1. + +2002-07-09 Keith Owens + + * Upgrade to 2.4.19-rc1. + * Add dmesg command. + * Clean up copyrights, Eric Sandeen. + * kdb v2.2-2.4.19-rc1-common-1. + +2002-06-14 Keith Owens + + * Upgrade to 2.4.19-pre10. + * Sync with XFS. + * kdb v2.1-2.4.19-pre10-common-1. + +2002-04-09 Keith Owens + + * Upgrade to 2.4.19-pre6. + * kdb v2.1-2.4.19-pre6-common-1. + +2002-03-18 Keith Owens + + * Syntax check mdWcN commands. + +2002-03-01 Keith Owens + + * Sync with XFS 2.4.18. + * kdb v2.1-2.4.18-common-2. + +2002-02-26 Keith Owens + + * Upgrade to 2.4.18. + * Add Paul Dorwin (IBM) magicpoint slides on using kdb as + Documentation/kdb/slides. + * kdb v2.1-2.4.18-common-1. + +2002-01-23 Keith Owens + + * Sync with XFS pagebuf changes. + * kdb v2.1-2.4.17-common-2. + +2002-01-18 Keith Owens + + * Ignore single stepping during panic. + * Remove kdba_getword, kdba_putword. Replace with kdb_getword, + kdb_putword that rely on copy_xx_user. The new functions return + an error code, like copy_xx_user. + * New functions kdb_getarea, kdb_putarea for copying areas of data + such as structures. These functions also return an error code. + * Change all common code to use the new functions. + * bp command checks that it can read and write the word at the + breakpoint before accepting the address. + * Break points are now set FIFO and cleared LIFO so overlapping + entries give sensible results. + * Verify address before disassembling code. + * Common changes for sparc64. Ethan Solomita, Tom Duffy. + * Remove ss , never supported. + * Remove kallsyms entries from arch vmlinux.lds files. + * Specify which commands auto repeat. + * kdb v2.1-2.4.17-common-1. + +2002-01-07 Keith Owens + + * Remove console semaphore code, not good in interrupt. + * Remove fragment of ia64 patch that had crept into kdb. + * Release as kdb v2.0-2.4.17-common-3. + +2002-01-04 Keith Owens + + * Sync xfs <-> kdb common code. + +2001-12-22 Keith Owens + + * Upgrade to 2.4.17. + * Clean up ifdef CONFIG_KDB. + * Add ifdef CONFIG_KDB around include kdb.h. + * Delete dummy kdb.h files for unsupported architectures. + * Delete arch i386 and ia64 specific files. This changelog now + applies to kdb common code only. + * Release as kdb v2.0-2.4.17-common-1. + +2001-12-03 Keith Owens + + * Upgrade to 2.4.16. + * Add include/asm-um/kdb.h stub to allow XFS to be tested under UML. + * Check if an interrupt frame on i386 came from user space. + * Out of scope bug fix in kdb_id.c. Ethan Solomita. + * Changes to common code to support sparc64. Ethan Solomita. + * Change GFP_KERNEL to GFP_ATOMIC in disasm. Ethan Solomita. + +2001-11-16 Keith Owens + + * Upgrade to 2.4.15-pre5. + * Wrap () around #define expressions with unary operators. + +2001-11-13 Keith Owens + + * Upgrade to 2.4.15-pre4. + * kbdm_pg.c patch from Hugh Dickins. + +2001-11-07 Keith Owens + + * Upgrade to 2.4.14-ia64-011105. + * Change name of l1 serial I/O routine, add ia64 init command. SGI. + * Sync kdbm_pg with XFS. + +2001-11-06 Keith Owens + + * Upgrade to kernel 2.4.14. + +2001-11-02 Keith Owens + + * Sync kdbm_pg.c with XFS. + +2001-10-24 Keith Owens + + * Upgrade to kernel 2.4.13. + +2001-10-14 Keith Owens + + * More use of TMPPREFIX in top level Makefile to speed up NFS compiles. + + * Correct repeat calculations in md/mds commands. + +2001-10-10 Keith Owens + + * Copy bfd.h and ansidecl.h to arch/$(ARCH)/kdb, remove dependecies on + user space includes. + + * Update kdb v1.9 to kernel 2.4.11. + +2001-10-01 Keith Owens + + * Update kdb v1.9 to kernel 2.4.11-pre1 and 2.4.10-ac1. + + * Correct loop in kdb_parse, reported by Tachino Nobuhiro. + +2001-09-25 Keith Owens + + * Update kdb v1.8 to kernel 2.4.10. + + * kdbm_pg patch from Hugh Dickens. + + * DProbes patch from Bharata B Rao. + + * mdWcn and mmW patch from Vamsi Krishna S. + + * i386 disasm layout patch from Jean-Marc Saffroy. + + * Work around for 64 bit binutils, Simon Munton. + + * kdb.mm doc correction by Chris Pascoe. + + * Enter repeats the last command, IA64 disasm only prints one + instruction. Don Dugger. + + * Allow kdb/modules to be linked into vmlinux. + + * Remove obsolete code from kdb/modules/kdbm_{pg,vm}.c. + + * Warn when commands are entered at more prompt. + + * Add MODULE_AUTHOR, DESCRIPTION, LICENSE. + + * Release as kdb v1.9. + +2001-02-27 Keith Owens + + * Update kdb v1.8 to kernel 2.4.2, sync kdb/modules with XFS. + + * Hook into panic() call. + +2000-12-18 Keith Owens + + * Update kdb v1.7 to kernel 2.4.0-test13-pre3, sync kdb/modules with + XFS. + +2000-11-18 Keith Owens + + * Update to kernel 2.4.0-test11-pre7, including forward port of + bug fixes from WIP 2.4.0-test9 tree. + + * Update to Cygnus CVS trees for disassembly code. + + * Bump to kdb v1.6. + +2000-10-19 Keith Owens + + * Update to kernel 2.4.0-test10-pre4. + +2000-10-15 Keith Owens + + * kdb/kdbmain.c (kdb_parse): Correctly handle blank input. + + * kdb/kdbmain.c (kdb_local, kdb): Reason SILENT can have NULL regs. + +2000-10-13 Keith Owens + + * kdb/kdbmain.c: Reduce CMD_LEN to avoid overflowing kdb_printf buffer. + +2000-10-11 Keith Owens + + * kdb/kdbmain.c (kdb): Test for userspace breakpoints before driving + other cpus into kdb. Speeds up gdb and avoids SMP race. + + * arch/i386/kdb/kdba_io.c (get_serial_char, get_kbd_char): Ignore + unprintable characters. + + * arch/i386/kdb/kdba_io.c (kdba_read): Better handling of buffer size. + +2000-10-04 Keith Owens + + * arch/i386/kdb/kdba_bt.c (kdba_bt_process): Verify that esp is inside + task_struct. Original patch by Mike Galbraith. + + * kdb/kdb_io.c (kdb_getstr): Reset output line counter, remove + unnecessary prompts. + + * arch/i386/kdb/kdbasupport.c (kdb_getregcontents): Change " cs" to + "xcs", ditto ss, ds, es. gdb2kdb does not like leading spaces. + + * include/asm-xxx/kdb.h: Add dummy kdb.h for all architectures except + ix86. This allows #include to appear in arch independent + code without causing compile errors. + + * kdb/modules/kdbm_pg: Sync with XFS. + +2000-10-03 Keith Owens + + * kdb/kdb_io.c (kdb_read): Ignore NMI while waiting for input. + + * kdb/kdb_io.c, kdb/Makefile: Export kdb_read. + +2000-10-02 Keith Owens + + * arch/i386/kernel/smpboot.c (do_boot_cpu): Set nmi_watchdog_source to 2 + to avoid premature NMI oops during cpu bring up. We have to assume that + a box with more than 1 cpu has a working IO-APIC. + + * Documentation/kdb/{kdb.mm,kdb_md.man}: Add mdr command. + + * kdb/kdbmain.c (kdb_md): Add mdr command. + + * Release as kdb v1.5 against 2.4.0-test9-pre8. + + * arch/i386/kdb/kdba_io.c, arch/i386/kdb/kdbasupport.c, kdb/kdbmain.c, + kdb/kdb_io.c, kdb/kdb_id.c: Remove zero initializers for static + variables. + +2000-09-28 Keith Owens + + * various: Add nmi_watchdog_source, 1 local APIC, 2 IO-APIC. + Test nmi_watchdog_source instead of nr_ioapics so UP works on SMP hardware. + + * arch/i386/kernel/io_apic.c: Rename setup_nmi to setup_nmi_io for clarity. + + * kdb/kdbmain.c (kdb_parse): Only set NO_WATCHDOG if it was already set. + + * kdb/kdbmain.c (kdb): Clear NO_WATCHDOG on all exit paths. + + * include/linux/kdb.h: Add KDB_REASON_SILENT. + + * kdb/kdbmain.c (kdb_local): Treat reason SILENT as immediate 'go'. + + * kdb/kdbmain.c (kdb_init): Invoke kdb with reason SILENT to instantiate + any breakpoints on boot cpu. + + * arch/i386/kernel/smpboot.c (smp_callin): Invoke kdb with reason SILENT + to instantiate any global breakpoints on this cpu. + + * kdb/kdb_cmds: Remove comment that said initial commands only worked on + boot cpu. + +2000-09-27 Keith Owens + + * arch/i386/kernel/msr.c: Move {rd,wr}msr_eio to include/asm-i386/apic.h. + + * include/asm-i386/apic.h: Define NMI interfaces. + + * kernel/sysctl.c (kern_table): + * kernel/sysctl.c (do_proc_set_nmi_watchdog): + Add /proc/sys/kernel/nmi_watchdog. + + * arch/i386/kernel/apic.c: New routines set_nmi_counter_local, + setup_apic_nmi_watchdog. + + * arch/i386/kernel/traps.c: New routine set_nmi_watchdog(). Call apic + routines to set/clear local apic timer. + +2000-09-26 Keith Owens + + * include/linux/sysctl.h (enum): Add NMI_WATCHDOG. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check nmi_watchdog is + still on. + + * arch/i386/config.in: Add CONFIG_UP_NMI_WATCHDOG. + + * Documentation/Configure.help: Add CONFIG_UP_NMI_WATCHDOG. + + * Documentation/nmi_watchdog.txt: Update for UP NMI watchdog. + +2000-09-25 Keith Owens + + * arch/i386/kernel/apic.c (init_apic_mappings): + * arch/i386/kernel/io_apic.c (IO_APIC_init_uniprocessor): + Merge Keir Fraser's local APIC for uniprocessors patch. + +2000-09-24 Keith Owens + + * Various: Declare initialization routines as __init. + + * Makefile: Define and export AWK. + + * kdb/Makefile: Generate gen-kdb_cmds.c from kdb/kdb_cmds. + + * kdb/kdbmain.c (kdb_init): Call new routine kdb_cmds_init to execute + whatever the user put in kdb/kdb_cmds. + + * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): New parameter to + indicate if esp in regs is known to be valid or not. + + * kdb/kdb_bp.c, arch/i386/kdb/kdba_bp.c: More trace prints for + breakpoint handling. + + * arch/i386/kdb/kdba_bp.c (kdba_installbp): Finally found and fixed the + annoying breakpoint bug where breakpoints where not always installed + after 'go'. + + * Documentation/kdb: Update man pages kdb.mm, kdb_env.man, kdb_ss.man. + + * Released as kdb-v1.5-beta1-2.4.0-test8. + + * Sync to 2.4.0-test9-pre6 and release as kdb-v1.5-beta1-2.4.0-test9-pre6. + +2000-09-23 Keith Owens + + * arch/i386/kdb/kdbasupport.c (kdba_getregcontents): New pseudo + registers cesp and ceflags to help with debugging the debugger. + + * kdb/kdbmain.c (kdb_local, kdb): Add KDB_REASON_RECURSE. Add + environment variable RECURSE. Add code to cope with some types of + recursion. + + * kdb/kdbmain.c (kdb), arch/i386/kdba/kdba_bp.c: Add + kdba_clearsinglestep. + +2000-09-22 Keith Owens + + * drivers/video/vgacon.c (write_vga): No cli() if kdb is running, avoid + console deadlock. + + * arch/i386/kernel/irq.c (get_irqlock): Warn if kdb is running, may hang. + + * include/linux/kdb.h: Define KDB_IS_RUNNING as (0) if no CONFIG_KDB. + + * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): Do not attempt a backtrace if + the code segment is not in the kernel. + + * kdb/modules: Change modules from MX_OBJS to M_OBJS. Remove EXPORT_NOSYMBOLS. + +2000-09-21 Keith Owens + + * arch/i386/kernel/i386_ksyms.c: Move EXPORT_SYMBOLS for kdb to kdb/kdbmain.c. + + * kdb/Makefile: Change kdb/kdbmain.o from O_OBJS to OX_OBJS. + + * arch/i386/kernel/smp.c: Remove some #ifdef CONFIG_KDB. Remove kdbprivate.h. + + * include/linux/kdb.h: Add kdb_print_state. Add KDB_STATE_WAIT_IPI. + + * kdb/kdbmain.c (kdb): Only mark cpu as leaving if it is in KDB state. Maintain + WAIT_IPI state so a cpu is only driven through NMI once. + + * arch/i386/kernel/smp.c (smp_kdb_stop): All state fiddling moved to kdb(). + +2000-09-20 Keith Owens + + * include/linux/kdb.h: #define kdb() as (0) if kdb is not configured. + + * arch/i386/kernel/traps.c: Remove some #ifdef CONFIG_KDB. + + * include/linux/kdbprivate.h: Move per cpu state to kdb.h. + + * include/linux/kdb.h: Add KDB_STATE_NO_WATCHDOG, KDB_STATE_PRINTF_LOCK. + Rename KDB_DEBUG_xxx to KDB_DEBUG_FLAG_xxx. Clean up debug flag + definitions. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check no watchdog. + + * kdb/kdbmain.c (kdb): Set no watchdog in normal kdb code. + + * kdb/kdbmain.c (kdb_parse): Allow watchdog in commands. + + * kdb/kdb_io.c (kdb_printf): No watchdog during printing. Clean up lock handling. + + * kdb/kdbmain.c (kdb_set): Clean up debug flag handling. + +2000-09-19 Juan J. Quintela + + * kdb/arch/i386/kdb/kdba_io.c: Allow kdb to compile without CONFIG_VT and/or + serial console. + +2000-09-19 Keith Owens + + * include/linux/kdb.h: Define KDB_DEBUG_STATE(). + + * kdb/kdbmain.c (kdb): Add kdb_print_state(), calls to KDB_DEBUG_STATE(). + +2000-09-16 Keith Owens + + * Move to finer grained control over individual processors in kdb with + per cpu kdb state. Needed to allow ss[b] to only release one processor, + previously ss[b] released all processors. Also need to recover from + errors inside kdb commands, e.g. oops in kdbm_pg code. + + * various: + Move global flags KDB_FLAG_SSB, KDB_FLAG_SUPRESS, KDB_FLAG_FAULT, + KDB_FLAG_SS, KDB_FLAG_SSBPT, kdb_active, to per cpu state and macros + KDB_STATE(xxx). + Replace kdb_flags & KDB_FLAG_xxx with KDB_FLAG(xxx). + Replace kdb_flags & KDB_DEBUG_xxx with KDB_DEBUG(xxx). + Replace specific tests with wrapper KDB_IS_RUNNING(). + + * various: Remove #ifdef CONFIG_SMP from kdb code wherever + possible. Simplifies the code and makes it much more readable. + + * arch/i386/kdb/kdbasupport.c (kdb_setjmp): Record if we have reliable + longjmp data instead of assuming it is always set. + + * various: Replace smp_kdb_wait with per cpu state, HOLD_CPU. + + * init/main.c : Replace #ifdef KDB_DEBUG with KDB_DEBUG(CALLBACK). + + * include/linux/kdbprivate.h: Separate command return codes from error + codes. Add more detailed command codes. + + * arch/i386/kernel/traps.c (die): Change spin_lock_irq to + spin_lock_irqsave. Why did I do this? + + * kdb/kdbmain.c (kdb_parse): Set per cpu flag CMD before executing kdb + command. More detailed return codes for commands that affect + processors. + + * kdb/kdbmain.c (kdb_previous_event): New, check if any processors are + still executing the previous kdb event. Removes a race window where a + second event could enter kdb before the first had completely ended. + + * kdb/kdbmain.c (kdb): Document all the concurrency conditions and how + kdb handles them. ss[b] now releases only the current cpu. Do not set + breakpoints when releasing for ss[b]. Recover from errors in kdb + commands. Check that we have reliable longjmp data before using it. + + * various: Update return code documentation. + + * kdb/kdb_bp.c (kdb_ss): Separate ss and ssb return codes. + + * kdb/kdbsupport.c (kdb_ipi): Finer grained algorithm for deciding + whether to call send a stop signal to a cpu. + + * arch/i386/kdb/kdba_bp.c (kdba_db_trap): Separate ss and ssb return + codes. Reinstall delayed software breakpoints per cpu instead of + globally. Changed algorithm for handling ss[b]. + + * arch/i386/kdb/kdba_bp.c (kdba_bp_trap): Match software breakpoints per + cpu instead of globally. + + * include/linux/kdb.h: Bump version to kdb v1.5. + +2000-09-16 Keith Owens + + * kernel/sysctl.c (kern_table): add /proc/sys/kernel/kdb. + + * init/main.c (parse_options): add boot flags kdb=on, kdb=off, + kdb=early. + + * include/linux/sysctl.h (enum): add KERN_KDB. + + * drivers/char/serial.c (receive_chars): check kdb_on. + + * drivers/char/keyboard.c (handle_scancode): check kdb_on. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): check kdb_on. + + * arch/i386/config.in: add CONFIG_KDB_OFF. + + * Documentation/Configure.help: add CONFIG_KDB_OFF. + + * kdb/kdbmain.c: add kdb_initial_cpu, kdb_on. + + * kdb/kdbmain.c (kdb): check kdb_on, set kdb_initial_cpu. + + * kdb/kdbmain.c (kdb_init): add Keith Owens to kdb banner. + + * kdb/kdb_io.c (kdb_printf): serialize kdb_printf output. + + * kdb/kdb_bt.c (kdb_bt): check environment variable BTAPROMPT. + + * kdb/kdbsupport.c (kdb_ipi): ignore NMI for kdb_initial_cpu. + + * kdb/modules/kdbm_pg.c (kdbm_page): merge updates from 2.4.0-test5-xfs. + + * kdb/kdb_bt.man: add btp, bta, BTAPROMPT. + + * kdb/kdb.mm: add CONFIG_KDB_OFF, boot flags, btp, bta. + + * include/linux/kdbprivate.h: add kdb_initial_cpu. + + * include/linux/kdb.h: add kdb_on, bump version to kdb v1.4. diff -Nur linux-2.4.19/kdb/Makefile linux-2.4.19-sgi211r3/kdb/Makefile --- linux-2.4.19/kdb/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/Makefile Tue Feb 4 15:36:30 2003 @@ -0,0 +1,53 @@ +# +# Copyright (c) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +O_TARGET := kdb.o +export-objs := kdbmain.o kdb_io.o +obj-y := kdb_bt.o kdb_bp.o kdb_id.o kdbsupport.o gen-kdb_cmds.o kdbmain.o kdb_io.o + +subdir-$(CONFIG_KDB_MODULES) := modules +obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y)) + +override CFLAGS := $(CFLAGS:%-pg=% ) + +EXTRA_CFLAGS += -I $(TOPDIR)/arch/$(ARCH)/kdb + +include $(TOPDIR)/Rules.make + +gen-kdb_cmds.c: kdb_cmds Makefile + $(AWK) 'BEGIN {print "#include "} \ + /^ *#/{next} \ + /^[ \t]*$$/{next} \ + {gsub(/"/, "\\\"", $$0); \ + print "static __initdata char kdb_cmd" cmds++ "[] = \"" $$0 "\\n\";"} \ + END {print "char __initdata *kdb_cmds[] = {"; for (i = 0; i < cmds; ++i) {print " kdb_cmd" i ","}; print(" 0\n};");}' \ + kdb_cmds > gen-kdb_cmds.c diff -Nur linux-2.4.19/kdb/kdb_bp.c linux-2.4.19-sgi211r3/kdb/kdb_bp.c --- linux-2.4.19/kdb/kdb_bp.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/kdb_bp.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,644 @@ +/* + * Kernel Debugger Architecture Independent Breakpoint Handler + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Table of kdb_breakpoints + */ +kdb_bp_t kdb_breakpoints[KDB_MAXBPT]; + +/* + * kdb_bp_install_global + * + * Install global kdb_breakpoints prior to returning from the + * kernel debugger. This allows the kdb_breakpoints to be set + * upon functions that are used internally by kdb, such as + * printk(). + * + * Parameters: + * regs Execution frame. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + * This function is only called once per kdb session. + */ + +void +kdb_bp_install_global(struct pt_regs *regs) +{ + int i; + + for(i=0; i=0; i--) { + if (KDB_DEBUG(BP)) { + kdb_printf("kdb_bp_remove_global bp %d bp_enabled %d bp_global %d\n", + i, kdb_breakpoints[i].bp_enabled, kdb_breakpoints[i].bp_global); + } + if (kdb_breakpoints[i].bp_enabled + && kdb_breakpoints[i].bp_global) { + kdba_removebp(&kdb_breakpoints[i]); + } + } +} + + +/* + * kdb_bp_remove_local + * + * Remove local kdb_breakpoints upon entry to the kernel debugger. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdb_bp_remove_local(void) +{ + int i; + + for(i=KDB_MAXBPT-1; i>=0; i--) { + if (KDB_DEBUG(BP)) { + kdb_printf("kdb_bp_remove_local bp %d bp_enabled %d bp_global %d cpu %d bp_cpu %d\n", + i, kdb_breakpoints[i].bp_enabled, kdb_breakpoints[i].bp_global, + smp_processor_id(), kdb_breakpoints[i].bp_cpu); + } + if (kdb_breakpoints[i].bp_enabled + && kdb_breakpoints[i].bp_cpu == smp_processor_id() + && !kdb_breakpoints[i].bp_global){ + kdba_removebp(&kdb_breakpoints[i]); + } + } +} + +/* + * kdb_printbp + * + * Internal function to format and print a breakpoint entry. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +static void +kdb_printbp(kdb_bp_t *bp, int i) +{ + if (bp->bp_forcehw) { + kdb_printf("Forced "); + } + + if (!bp->bp_template.bph_free) { + kdb_printf("%s ", kdba_bptype(&bp->bp_template)); + } else { + kdb_printf("Instruction(i) "); + } + + kdb_printf("BP #%d at ", i); + kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT); + + if (bp->bp_enabled) { + kdba_printbp(bp); + if (bp->bp_global) + kdb_printf(" globally"); + else + kdb_printf(" on cpu %d", bp->bp_cpu); + if (bp->bp_adjust) + kdb_printf(" adjust %d", bp->bp_adjust); + } else { + kdb_printf("\n is disabled"); + } + + kdb_printf("\n"); +} + +/* + * kdb_bp + * + * Handle the bp, and bpa commands. + * + * [bp|bpa|bph] [DATAR|DATAW|IO [length]] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + * + * bp Set breakpoint. Only use hardware assist if necessary. + * bpa Set breakpoint on all cpus, only use hardware regs if necessary + * bph Set breakpoint - force hardware register + * bpha Set breakpoint on all cpus, force hardware register + */ + +int +kdb_bp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i, bpno; + kdb_bp_t *bp, *bp_check; + int diag; + int free, same; + kdb_machreg_t addr; + char *symname = NULL; + long offset = 0ul; + int nextarg; + int hardware; + int global; + + if (argc == 0) { + /* + * Display breakpoint table + */ + for(bpno=0,bp=kdb_breakpoints; bpnobp_free) continue; + + kdb_printbp(bp, bpno); + } + + return 0; + } + + global = ((strcmp(argv[0], "bpa") == 0) + || (strcmp(argv[0], "bpha") == 0)); + hardware = ((strcmp(argv[0], "bph") == 0) + || (strcmp(argv[0], "bpha") == 0)); + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, &symname, regs); + if (diag) + return diag; + + /* + * Allocate a new bp structure + */ + free = same = KDB_MAXBPT; + for(bpno=0,bp=kdb_breakpoints; bpnobp_free) { + break; + } + } + + if (bpno == KDB_MAXBPT) + return KDB_TOOMANYBPT; + + memset(bp, 0, sizeof(*bp)); + kdba_check_pc(&addr); + for(i=0,bp_check=kdb_breakpoints; ibp_free && bp_check->bp_addr == addr) { + kdb_printf("You already have a breakpoint at " kdb_bfd_vma_fmt0 "\n", addr); + return KDB_TOOMANYBPT; + } + } + bp->bp_addr = addr; + + bp->bp_forcehw = hardware; + if (KDB_DEBUG(BP)) + kdb_printf("kdb_bp: forcehw is %d hardware is %d\n", bp->bp_forcehw, hardware); + + /* + * Handle architecture dependent parsing + */ + diag = kdba_parsebp(argc, argv, &nextarg, bp); + if (diag) { + return diag; + } + + bp->bp_enabled = 1; + bp->bp_global = 1; /* Most breakpoints are global */ + + if (hardware && !global) { + bp->bp_global = 0; + bp->bp_cpu = smp_processor_id(); + } + + /* + * Allocate a hardware breakpoint. If one is not available, + * disable the breakpoint, but leave it in the breakpoint + * table. When the breakpoint is re-enabled (via 'be'), we'll + * attempt to allocate a hardware register for it. + */ + if (!bp->bp_template.bph_free) { + bp->bp_hard = kdba_allocbp(&bp->bp_template, &diag); + if (diag) { + bp->bp_enabled = 0; + return diag; + } + bp->bp_hardtype = 1; + } + + kdb_printbp(bp, bpno); + + return 0; +} + +/* + * kdb_bc + * + * Handles the 'bc', 'be', and 'bd' commands + * + * [bd|bc|be] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + */ + +#define KDBCMD_BC 0 +#define KDBCMD_BE 1 +#define KDBCMD_BD 2 + +int +kdb_bc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_machreg_t addr; + kdb_bp_t *bp = 0; + int lowbp = KDB_MAXBPT; + int highbp = 0; + int done = 0; + int i; + int diag; + int cmd; /* KDBCMD_B? */ + + if (strcmp(argv[0], "be") == 0) { + cmd = KDBCMD_BE; + } else if (strcmp(argv[0], "bd") == 0) { + cmd = KDBCMD_BD; + } else + cmd = KDBCMD_BC; + + if (argc != 1) + return KDB_ARGCOUNT; + + if (strcmp(argv[1], "*") == 0) { + lowbp = 0; + highbp = KDB_MAXBPT; + } else { + diag = kdbgetularg(argv[1], &addr); + if (diag) + return diag; + + /* + * For addresses less than the maximum breakpoint number, + * assume that the breakpoint number is desired. + */ + if (addr < KDB_MAXBPT) { + bp = &kdb_breakpoints[addr]; + lowbp = highbp = addr; + highbp++; + } else { + for(i=0, bp=kdb_breakpoints; ibp_addr == addr) { + lowbp = highbp = i; + highbp++; + break; + } + } + } + } + + /* + * Now operate on the set of breakpoints matching the input + * criteria (either '*' for all, or an individual breakpoint). + */ + for(bp=&kdb_breakpoints[lowbp], i=lowbp; + i < highbp; + i++, bp++) { + if (bp->bp_free) + continue; + + done++; + + switch (cmd) { + case KDBCMD_BC: + if (bp->bp_hardtype) { + kdba_freebp(bp->bp_hard); + bp->bp_hard = 0; + bp->bp_hardtype = 0; + } + + bp->bp_enabled = 0; + bp->bp_global = 0; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " cleared\n", + i, bp->bp_addr); + + bp->bp_addr = 0; + bp->bp_free = 1; + + break; + case KDBCMD_BE: + /* + * Allocate a hardware breakpoint. If one is not + * available, don't enable the breakpoint. + */ + if (!bp->bp_template.bph_free + && !bp->bp_hardtype) { + bp->bp_hard = kdba_allocbp(&bp->bp_template, &diag); + if (diag) { + bp->bp_enabled = 0; + return diag; + } + bp->bp_hardtype = 1; + } + + bp->bp_enabled = 1; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " in enabled", + i, bp->bp_addr); + + kdb_printf("\n"); + break; + case KDBCMD_BD: + if (!bp->bp_enabled) { + return 0; + } + + /* + * Since this breakpoint is now disabled, we can + * give up the hardware register which is allocated + * to it. + */ + if (bp->bp_hardtype) { + kdba_freebp(bp->bp_hard); + bp->bp_hard = 0; + bp->bp_hardtype = 0; + } + + bp->bp_enabled = 0; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " disabled\n", + i, bp->bp_addr); + + break; + } + if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) { + bp->bp_delay = 0; + KDB_STATE_CLEAR(SSBPT); + } + } + + return (!done)?KDB_BPTNOTFOUND:0; +} + +/* + * kdb_ss + * + * Process the 'ss' (Single Step) and 'ssb' (Single Step to Branch) + * commands. + * + * ss + * ssb + * + * Parameters: + * argc Argument count + * argv Argument vector + * envp Environment vector + * regs Registers at time of entry to kernel debugger + * Outputs: + * None. + * Returns: + * KDB_CMD_SS[B] for success, a kdb error if failure. + * Locking: + * None. + * Remarks: + * + * Set the arch specific option to trigger a debug trap after the next + * instruction. + * + * For 'ssb', set the trace flag in the debug trap handler + * after printing the current insn and return directly without + * invoking the kdb command processor, until a branch instruction + * is encountered. + */ + +int +kdb_ss(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int ssb = 0; + + ssb = (strcmp(argv[0], "ssb") == 0); + if (argc != 0) + return KDB_ARGCOUNT; + + if (!regs) { + kdb_printf("%s: pt_regs not available\n", __FUNCTION__); + return KDB_BADREG; + } + + /* + * Set trace flag and go. + */ + KDB_STATE_SET(DOING_SS); + if (ssb) + KDB_STATE_SET(DOING_SSB); + + kdba_setsinglestep(regs); /* Enable single step */ + + if (ssb) + return KDB_CMD_SSB; + return KDB_CMD_SS; +} + +/* + * kdb_initbptab + * + * Initialize the breakpoint table. Register breakpoint commands. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void __init +kdb_initbptab(void) +{ + int i; + kdb_bp_t *bp; + + /* + * First time initialization. + */ + memset(&kdb_breakpoints, '\0', sizeof(kdb_breakpoints)); + + for (i=0, bp=kdb_breakpoints; ibp_free = 1; + /* + * The bph_free flag is architecturally required. It + * is set by architecture-dependent code to false (zero) + * in the event a hardware breakpoint register is required + * for this breakpoint. + * + * The rest of the template is reserved to the architecture + * dependent code and _must_ not be touched by the architecture + * independent code. + */ + bp->bp_template.bph_free = 1; + } + + kdb_register_repeat("bp", kdb_bp, "[]", "Set/Display breakpoints", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bl", kdb_bp, "[]", "Display breakpoints", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bpa", kdb_bp, "[]", "Set/Display global breakpoints", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bph", kdb_bp, "[]", "Set hardware breakpoint", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bpha", kdb_bp, "[]", "Set global hardware breakpoint", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bc", kdb_bc, "", "Clear Breakpoint", 0, KDB_REPEAT_NONE); + kdb_register_repeat("be", kdb_bc, "", "Enable Breakpoint", 0, KDB_REPEAT_NONE); + kdb_register_repeat("bd", kdb_bc, "", "Disable Breakpoint", 0, KDB_REPEAT_NONE); + + kdb_register_repeat("ss", kdb_ss, "", "Single Step", 1, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("ssb", kdb_ss, "", "Single step to branch/call", 0, KDB_REPEAT_NO_ARGS); + /* + * Architecture dependent initialization. + */ + kdba_initbp(); +} + diff -Nur linux-2.4.19/kdb/kdb_bt.c linux-2.4.19-sgi211r3/kdb/kdb_bt.c --- linux-2.4.19/kdb/kdb_bt.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/kdb_bt.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,179 @@ +/* + * Kernel Debugger Architecture Independent Stack Traceback + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * kdb_bt + * + * This function implements the 'bt' command. Print a stack + * traceback. + * + * bt [] (addr-exp is for alternate stacks) + * btp Kernel stack for + * bta [DRSTZU] All processes, optionally filtered by state + * btc The current process on each cpu + * + * address expression refers to a return address on the stack. It + * is expected to be preceeded by a frame pointer. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Backtrack works best when the code uses frame pointers. But + * even without frame pointers we should get a reasonable trace. + * + * mds comes in handy when examining the stack to do a manual + * traceback. + */ + +int kdb_btc_next = -1; + +int +kdb_bt(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int argcount = 5; + int btaprompt = 1; + char buffer[2]; + int nextarg; + unsigned long addr; + long offset; + unsigned long mask; + + kdbgetintenv("BTARGS", &argcount); /* Arguments to print */ + kdbgetintenv("BTAPROMPT", &btaprompt); /* Prompt after each proc in bta */ + + if (strcmp(argv[0], "bta") == 0) { + struct task_struct *p; + mask = kdb_task_state_string(argc, argv, envp); + + for_each_task(p) { + if (!kdb_task_state(p, mask)) + continue; + kdb_printf("Stack traceback for pid %d\n", p->pid); + kdb_ps1(p); + diag = kdba_bt_process(p, argcount); + + if (btaprompt) { + kdb_getstr(buffer, sizeof(buffer), + "Enter to end, to continue:"); + + if (buffer[0] == 'q') { + return 0; + } + } + else { + /* Reset NMI watchdog once per process */ + touch_nmi_watchdog(); + } + } + } else if (strcmp(argv[0], "btp") == 0) { + struct task_struct *p; + unsigned long pid; + + if (argc < 1) + return KDB_ARGCOUNT; + + diag = kdbgetularg((char *)argv[1], &pid); + if (diag) + return diag; + + for_each_task(p) { + if (p->pid == (pid_t)pid) { + kdb_ps1(p); + return kdba_bt_process(p, argcount); + } + } + + kdb_printf("No process with pid == %ld found\n", pid); + return 0; + } else if (strcmp(argv[0], "btc") == 0) { + /* backtrace all cpus is tricky. Each cpu has to backtrace + * itself then put itself into hold state and release the next + * cpu. As each cpu is released it detects that btc is in + * progress and repeats the process, until the last cpu is + * reached. This code just starts the process, see kdb_local + * for the switch and bt on each cpu. + * + * Holy switching cpus, Batman! + */ + int i; + if (argc != 0) + return KDB_ARGCOUNT; + kdb_printf("btc: "); + kdb_parse("cpu\n", regs); /* list active cpus and check they are still live */ + for (i=0; i +#include +#include +#include +#include +#include +#include + +disassemble_info kdb_di; + +/* + * kdb_id + * + * Handle the id (instruction display) command. + * + * id [] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + */ + +int +kdb_id(int argc, const char **argv, const char **envp, struct pt_regs* regs) +{ + kdb_machreg_t pc; + int icount; + int diag; + int i; + char * mode; + int nextarg; + long offset = 0; + static kdb_machreg_t lastpc; + struct disassemble_info *dip = &kdb_di; + char lastbuf[50]; + unsigned long word; + + if (argc != 1) { + if (lastpc == 0) { + return KDB_ARGCOUNT; + } else { + sprintf(lastbuf, "0x%lx", lastpc); + argv[1] = lastbuf; + argc = 1; + } + } + + + /* + * Fetch PC. First, check to see if it is a symbol, if not, + * try address. + */ + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &pc, &offset, NULL, regs); + if (diag) + return diag; + kdba_check_pc(&pc); + if (kdb_getarea(word, pc)) + return(0); + + /* + * Number of lines to display + */ + diag = kdbgetintenv("IDCOUNT", &icount); + if (diag) + return diag; + + dip->fprintf_dummy = kdb_dis_fprintf; + + mode = kdbgetenv("IDMODE"); + diag = kdba_id_parsemode(mode, dip); + if (diag) { + return diag; + } + + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_SPARC64 +#include +#else +static struct console *kdbcons; +#endif + + +#define CMD_BUFLEN 256 +char kdb_prompt_str[CMD_BUFLEN]; + +/* + * kdb_read + * + * This function reads a string of characters, terminated by + * a newline, or by reaching the end of the supplied buffer, + * from the current kernel debugger console device. + * Parameters: + * buffer - Address of character buffer to receive input characters. + * bufsize - size, in bytes, of the character buffer + * Returns: + * Returns a pointer to the buffer containing the received + * character string. This string will be terminated by a + * newline character. + * Locking: + * No locks are required to be held upon entry to this + * function. It is not reentrant - it relies on the fact + * that while kdb is running on any one processor all other + * processors will be spinning at the kdb barrier. + * Remarks: + * + * Davidm asks, why doesn't kdb use the console abstraction; + * here are some reasons: + * - you cannot debug the console abstraction with kdb if + * kdb uses it. + * - you rely on the correct functioning of the abstraction + * in the presence of general system failures. + * - You must acquire the console spinlock thus restricting + * the usability - what if the kernel fails with the spinlock + * held - one still wishes to debug such situations. + * - How about debugging before the console(s) are registered? + * - None of the current consoles (sercons, vt_console_driver) + * have read functions defined. + * - The standard pc keyboard and terminal drivers are interrupt + * driven. We cannot enable interrupts while kdb is active, + * so the standard input functions cannot be used by kdb. + * + * An implementation could be improved by removing the need for + * lock acquisition - just keep a 'struct console *kdbconsole;' global + * variable which refers to the preferred kdb console. + * + * The bulk of this function is architecture dependent. + * + * The buffer size must be >= 2. A buffer size of 2 means that the caller only + * wants a single key. + * + * An escape key could be the start of a vt100 control sequence such as \e[D + * (left arrow) or it could be a character in its own right. The standard + * method for detecting the difference is to wait for 2 seconds to see if there + * are any other characters. kdb is complicated by the lack of a timer service + * (interrupts are off), by multiple input sources and by the need to sometimes + * return after just one key. Escape sequence processing has to be done as + * states in the polling loop. + */ + +char * +kdb_read(char *buffer, size_t bufsize) +{ + char *cp = buffer; + char *bufend = buffer+bufsize-2; /* Reserve space for newline and null byte */ + + char *lastchar; + char *p_tmp; + char tmp; + static char tmpbuffer[CMD_BUFLEN]; + int len = strlen(buffer); + int len_tmp; + int tab=0; + int count; + int i; + int diag, dtab_count; + +#define ESCAPE_UDELAY 1000 +#define ESCAPE_DELAY 2*1000000/ESCAPE_UDELAY /* 2 seconds worth of udelays */ + char escape_data[5]; /* longest vt100 escape sequence is 4 bytes */ + char *ped = escape_data; + int escape_delay = 0; + get_char_func *f, *f_escape = NULL; + + diag = kdbgetintenv("DTABCOUNT",&dtab_count); + if (diag) + dtab_count = 30; + + if (len > 0 ) { + cp += len; + if (*(buffer+len-1) == '\n') + cp--; + } + + lastchar = cp; + *cp = '\0'; + kdb_printf("%s", buffer); + + for (;;) { + int key; + for (f = &poll_funcs[0]; ; ++f) { + if (*f == NULL) { + /* Reset NMI watchdog once per poll loop */ + touch_nmi_watchdog(); + f = &poll_funcs[0]; + } + if (escape_delay == 2) { + *ped = '\0'; + ped = escape_data; + --escape_delay; + } + if (escape_delay == 1) { + key = *ped++; + if (!*ped) + --escape_delay; + break; + } + key = (*f)(); + if (key == -1) { + if (escape_delay) { + udelay(ESCAPE_UDELAY); + --escape_delay; + } + continue; + } + if (bufsize <= 2) { + if (key == '\r') + key = '\n'; + kdb_printf("%c", key); + *buffer++ = key; + *buffer = '\0'; + return buffer; + } + if (escape_delay == 0 && key == '\e') { + escape_delay = ESCAPE_DELAY; + ped = escape_data; + f_escape = f; + } + if (escape_delay) { + *ped++ = key; + if (f_escape != f) { + escape_delay = 2; + continue; + } + if (ped - escape_data == 1) { + /* \e */ + continue; + } + else if (ped - escape_data == 2) { + /* \e */ + if (key != '[') + escape_delay = 2; + continue; + } else if (ped - escape_data == 3) { + /* \e[ */ + int mapkey = 0; + switch (key) { + case 'A': mapkey = 16; break; /* \e[A, up arrow */ + case 'B': mapkey = 14; break; /* \e[B, down arrow */ + case 'C': mapkey = 6; break; /* \e[C, right arrow */ + case 'D': mapkey = 2; break; /* \e[D, left arrow */ + case '1': /* dropthrough */ + case '3': /* dropthrough */ + case '4': mapkey = -1; break; /* \e[<1,3,4>], may be home, del, end */ + } + if (mapkey != -1) { + if (mapkey > 0) { + escape_data[0] = mapkey; + escape_data[1] = '\0'; + } + escape_delay = 2; + } + continue; + } else if (ped - escape_data == 4) { + /* \e[<1,3,4> */ + int mapkey = 0; + if (key == '~') { + switch (escape_data[2]) { + case '1': mapkey = 1; break; /* \e[1~, home */ + case '3': mapkey = 4; break; /* \e[3~, del */ + case '4': mapkey = 5; break; /* \e[4~, end */ + } + } + if (mapkey > 0) { + escape_data[0] = mapkey; + escape_data[1] = '\0'; + } + escape_delay = 2; + continue; + } + } + break; /* A key to process */ + } + + if (key != 9) + tab = 0; + switch (key) { + case 8: /* backspace */ + if (cp > buffer) { + if (cp < lastchar) { + memcpy(tmpbuffer, cp, lastchar - cp); + memcpy(cp-1, tmpbuffer, lastchar - cp); + } + *(--lastchar) = '\0'; + --cp; + kdb_printf("\b%s \r", cp); + tmp = *cp; + *cp = '\0'; + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + *cp = tmp; + } + break; + case 13: /* enter */ + *lastchar++ = '\n'; + *lastchar++ = '\0'; + kdb_printf("\n"); + return buffer; + case 4: /* Del */ + if(cp < lastchar) { + memcpy(tmpbuffer, cp+1, lastchar - cp -1); + memcpy(cp, tmpbuffer, lastchar - cp -1); + *(--lastchar) = '\0'; + kdb_printf("%s \r", cp); + tmp = *cp; + *cp = '\0'; + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + *cp = tmp; + } + break; + case 1: /* Home */ + if(cp > buffer) { + kdb_printf("\r"); + kdb_printf(kdb_prompt_str); + cp = buffer; + } + break; + case 5: /* End */ + if(cp < lastchar) { + kdb_printf("%s", cp); + cp = lastchar; + } + break; + case 2: /* Left */ + if (cp > buffer) { + kdb_printf("\b"); + --cp; + } + break; + case 14: /* Down */ + memset(tmpbuffer, ' ', strlen(kdb_prompt_str)+(lastchar-buffer)); + *(tmpbuffer+strlen(kdb_prompt_str)+(lastchar-buffer)) = '\0'; + kdb_printf("\r%s\r", tmpbuffer); + *lastchar = (char)key; + *(lastchar+1) = '\0'; + return lastchar; + case 6: /* Right */ + if (cp < lastchar) { + kdb_printf("%c", *cp); + ++cp; + } + break; + case 16: /* Up */ + memset(tmpbuffer, ' ', strlen(kdb_prompt_str)+(lastchar-buffer)); + *(tmpbuffer+strlen(kdb_prompt_str)+(lastchar-buffer)) = '\0'; + kdb_printf("\r%s\r", tmpbuffer); + *lastchar = (char)key; + *(lastchar+1) = '\0'; + return lastchar; + case 9: /* Tab */ + if (tab < 2) + ++tab; + p_tmp = buffer; + while(*p_tmp==' ') p_tmp++; + if (p_tmp<=cp) { + memcpy(tmpbuffer, p_tmp, cp-p_tmp); + *(tmpbuffer + (cp-p_tmp)) = '\0'; + p_tmp = strrchr(tmpbuffer, ' '); + if (p_tmp) + ++p_tmp; + else + p_tmp = tmpbuffer; + len = strlen(p_tmp); + if (tab == 2) { + if((count=kallsyms_symbol_complete(p_tmp))>0) { + kdb_printf("\n%d symbols are found.", count); + if(count>dtab_count) { + count=dtab_count; + kdb_printf(" But only first %d symbols will be printed.\nYou can change the environment variable DTABCOUNT.", count); + } + kdb_printf("\n"); + for(i=0;i=dtab_count)kdb_printf("..."); + kdb_printf("\n"); + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + } + } + else { + if(kallsyms_symbol_complete(p_tmp)>0) { + len_tmp = strlen(p_tmp); + strncpy(p_tmp+len_tmp,cp, lastchar-cp+1); + len_tmp = strlen(p_tmp); + strncpy(cp, p_tmp+len, len_tmp-len+1); + len = len_tmp - len; + kdb_printf("%s", cp); + cp+=len; + lastchar+=len; + } + } + kdb_nextline = 1; /* reset output line number */ + } + break; + default: + if (key >= 32 &&lastchar < bufend) { + if (cp < lastchar) { + memcpy(tmpbuffer, cp, lastchar - cp); + memcpy(cp+1, tmpbuffer, lastchar - cp); + } + *(++lastchar) = '\0'; + *cp = key; + kdb_printf("%s\r", cp); + ++cp; + tmp = *cp; + *cp = '\0'; + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + *cp = tmp; + } + break; + } + } +} + +/* + * kdb_getstr + * + * Print the prompt string and read a command from the + * input device. + * + * Parameters: + * buffer Address of buffer to receive command + * bufsize Size of buffer in bytes + * prompt Pointer to string to use as prompt string + * Returns: + * Pointer to command buffer. + * Locking: + * None. + * Remarks: + * For SMP kernels, the processor number will be + * substituted for %d, %x or %o in the prompt. + */ + +char * +kdb_getstr(char *buffer, size_t bufsize, char *prompt) +{ + if(prompt && kdb_prompt_str!=prompt) + strncpy(kdb_prompt_str, prompt, CMD_BUFLEN); + kdb_printf(kdb_prompt_str); + kdb_nextline = 1; /* Prompt and input resets line number */ + return kdb_read(buffer, bufsize); +} + +/* + * kdb_printf + * + * Print a string to the output device(s). + * + * Parameters: + * printf-like format and optional args. + * Returns: + * 0 + * Locking: + * None. + * Remarks: + * use 'kdbcons->write()' to avoid polluting 'log_buf' with + * kdb output. + */ + +static char kdb_buffer[256]; /* A bit too big to go on stack */ + +void +kdb_printf(const char *fmt, ...) +{ + va_list ap; + int diag; + int linecount; + int logging, saved_loglevel = 0; + int do_longjmp = 0; + struct console *c = console_drivers; + static spinlock_t kdb_printf_lock = SPIN_LOCK_UNLOCKED; + + /* Serialize kdb_printf if multiple cpus try to write at once. + * But if any cpu goes recursive in kdb, just print the output, + * even if it is interleaved with any other text. + */ + if (!KDB_STATE(PRINTF_LOCK)) { + KDB_STATE_SET(PRINTF_LOCK); + spin_lock(&kdb_printf_lock); + } + + diag = kdbgetintenv("LINES", &linecount); + if (diag || linecount <= 1) + linecount = 22; + + diag = kdbgetintenv("LOGGING", &logging); + if (diag) + logging = 0; + + va_start(ap, fmt); + vsnprintf(kdb_buffer, sizeof(kdb_buffer), fmt, ap); + va_end(ap); + + /* + * Write to all consoles. + */ +#ifdef CONFIG_SPARC64 + if (c == NULL) + prom_printf("%s", kdb_buffer); + else +#endif + while (c) { + c->write(c, kdb_buffer, strlen(kdb_buffer)); + c = c->next; + } + if (logging) { + saved_loglevel = console_loglevel; + console_loglevel = 0; + printk("%s", kdb_buffer); + } + + if (strchr(kdb_buffer, '\n') != NULL) { + kdb_nextline++; + } + + if (kdb_nextline == linecount) { +#ifdef KDB_HAVE_LONGJMP + char buf1[16]=""; +#if defined(CONFIG_SMP) + char buf2[32]; +#endif + char *moreprompt; + + /* Watch out for recursion here. Any routine that calls + * kdb_printf will come back through here. And kdb_read + * uses kdb_printf to echo on serial consoles ... + */ + kdb_nextline = 1; /* In case of recursion */ + + /* + * Pause until cr. + */ + moreprompt = kdbgetenv("MOREPROMPT"); + if (moreprompt == NULL) { + moreprompt = "more> "; + } + +#if defined(CONFIG_SMP) + if (strchr(moreprompt, '%')) { + sprintf(buf2, moreprompt, smp_processor_id()); + moreprompt = buf2; + } +#endif + + c = console_drivers; +#ifdef CONFIG_SPARC64 + if (c == NULL) + prom_printf("%s", moreprompt); + else +#endif + while (c) { + c->write(c, moreprompt, strlen(moreprompt)); + c = c->next; + } + + if (logging) + printk("%s", moreprompt); + + kdb_read(buf1, 2); /* '2' indicates to return immediately after getting one key. */ + kdb_nextline = 1; /* Really set output line 1 */ + + if ((buf1[0] == 'q') || (buf1[0] == 'Q')) { + do_longjmp = 1; + kdb_printf("\n"); + } + else if (buf1[0] && buf1[0] != '\n') + kdb_printf("\nOnly 'q' or 'Q' are processed at more prompt, input ignored\n"); +#endif /* KDB_HAVE_LONGJMP */ + } + + if (logging) { + console_loglevel = saved_loglevel; + } + if (KDB_STATE(PRINTF_LOCK)) { + spin_unlock(&kdb_printf_lock); + KDB_STATE_CLEAR(PRINTF_LOCK); + } + if (do_longjmp) +#ifdef KDB_HAVE_LONGJMP + kdba_longjmp(&kdbjmpbuf[smp_processor_id()], 1); +#else + ; +#endif /* KDB_HAVE_LONGJMP */ +} + +/* + * kdb_io_init + * + * Initialize kernel debugger output environment. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * Select a console device. + */ + +void __init +kdb_io_init(void) +{ +#ifndef CONFIG_SPARC64 /* we don't register serial consoles in time */ + /* + * Select a console. + */ + struct console *c = console_drivers; + + while (c) { + if ((c->flags & CON_CONSDEV)) { + kdbcons = c; + break; + } + c = c->next; + } + + if (kdbcons == NULL) { + long long i; + + printk("kdb: Initialization failed - no console\n"); + while (1) i++; + } +#endif + return; +} + +EXPORT_SYMBOL(kdb_read); diff -Nur linux-2.4.19/kdb/kdbmain.c linux-2.4.19-sgi211r3/kdb/kdbmain.c --- linux-2.4.19/kdb/kdbmain.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/kdbmain.c Sun Feb 9 17:13:48 2003 @@ -0,0 +1,3293 @@ +/* + * Kernel Debugger Architecture Independent Main Code + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2000 Stephane Eranian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(CONFIG_MODULES) +extern struct module *module_list; +#endif + + /* + * Kernel debugger state flags + */ +volatile int kdb_flags; + + /* + * kdb_lock protects updates to kdb_initial_cpu. Used to + * single thread processors through the kernel debugger. + */ +spinlock_t kdb_lock = SPIN_LOCK_UNLOCKED; +volatile int kdb_initial_cpu = -1; /* cpu number that owns kdb */ + +volatile int kdb_nextline = 1; +static volatile int kdb_new_cpu; /* Which cpu to switch to */ + +volatile int kdb_state[NR_CPUS]; /* Per cpu state */ + +#ifdef CONFIG_KDB_OFF +int kdb_on = 0; /* Default is off */ +#else +int kdb_on = 1; /* Default is on */ +#endif /* CONFIG_KDB_OFF */ + +const char *kdb_diemsg; +struct notifier_block *kdb_notifier_list; /* racy for modules, see comments in kdb.h */ + +#ifdef KDB_HAVE_LONGJMP + /* + * Must have a setjmp buffer per CPU. Switching cpus will + * cause the jump buffer to be setup for the new cpu, and + * subsequent switches (and pager aborts) will use the + * appropriate per-processor values. + */ +kdb_jmp_buf kdbjmpbuf[NR_CPUS]; +#endif /* KDB_HAVE_LONGJMP */ + + /* + * kdb_commands describes the available commands. + */ +static kdbtab_t *kdb_commands; +static int kdb_max_commands; + +typedef struct _kdbmsg { + int km_diag; /* kdb diagnostic */ + char *km_msg; /* Corresponding message text */ +} kdbmsg_t; + +#define KDBMSG(msgnum, text) \ + { KDB_##msgnum, text } + +static kdbmsg_t kdbmsgs[] = { + KDBMSG(NOTFOUND,"Command Not Found"), + KDBMSG(ARGCOUNT, "Improper argument count, see usage."), + KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, 8 is only allowed on 64 bit systems"), + KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"), + KDBMSG(NOTENV, "Cannot find environment variable"), + KDBMSG(NOENVVALUE, "Environment variable should have value"), + KDBMSG(NOTIMP, "Command not implemented"), + KDBMSG(ENVFULL, "Environment full"), + KDBMSG(ENVBUFFULL, "Environment buffer full"), + KDBMSG(TOOMANYBPT, "Too many breakpoints defined"), + KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"), + KDBMSG(DUPBPT, "Duplicate breakpoint address"), + KDBMSG(BPTNOTFOUND, "Breakpoint not found"), + KDBMSG(BADMODE, "Invalid IDMODE"), + KDBMSG(BADINT, "Illegal numeric value"), + KDBMSG(INVADDRFMT, "Invalid symbolic address format"), + KDBMSG(BADREG, "Invalid register name"), + KDBMSG(BADCPUNUM, "Invalid cpu number"), + KDBMSG(BADLENGTH, "Invalid length field"), + KDBMSG(NOBP, "No Breakpoint exists"), + KDBMSG(BADADDR, "Invalid address"), +}; +#undef KDBMSG + +static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t); + + +/* + * Initial environment. This is all kept static and local to + * this file. We don't want to rely on the memory allocation + * mechanisms in the kernel, so we use a very limited allocate-only + * heap for new and altered environment variables. The entire + * environment is limited to a fixed number of entries (add more + * to __env[] if required) and a fixed amount of heap (add more to + * KDB_ENVBUFSIZE if required). + */ + +static char *__env[] = { +#if defined(CONFIG_SMP) + "PROMPT=[%d]kdb> ", + "MOREPROMPT=[%d]more> ", +#else + "PROMPT=kdb> ", + "MOREPROMPT=more> ", +#endif + "RADIX=16", + "LINES=24", + "COLUMNS=80", + "MDCOUNT=8", /* lines of md output */ + "BTARGS=5", /* 5 possible args in bt */ + KDB_PLATFORM_ENV, + "DTABCOUNT=30", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, +}; + +static const int __nenv = (sizeof(__env) / sizeof(char *)); + +/* + * kdbgetenv + * + * This function will return the character string value of + * an environment variable. + * + * Parameters: + * match A character string representing an environment variable. + * Outputs: + * None. + * Returns: + * NULL No environment variable matches 'match' + * char* Pointer to string value of environment variable. + * Locking: + * No locking considerations required. + * Remarks: + */ +char * +kdbgetenv(const char *match) +{ + char **ep = __env; + int matchlen = strlen(match); + int i; + + for(i=0; i<__nenv; i++) { + char *e = *ep++; + + if (!e) continue; + + if ((strncmp(match, e, matchlen) == 0) + && ((e[matchlen] == '\0') + ||(e[matchlen] == '='))) { + char *cp = strchr(e, '='); + return (cp)?++cp:""; + } + } + return (char *)0; +} + +/* + * kdballocenv + * + * This function is used to allocate bytes for environment entries. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. Must be called with all + * processors halted. + * Remarks: + * We use a static environment buffer (envbuffer) to hold the values + * of dynamically generated environment variables (see kdb_set). Buffer + * space once allocated is never free'd, so over time, the amount of space + * (currently 512 bytes) will be exhausted if env variables are changed + * frequently. + */ +static char * +kdballocenv(size_t bytes) +{ +#define KDB_ENVBUFSIZE 512 + static char envbuffer[KDB_ENVBUFSIZE]; + static int envbufsize; + char *ep = (char *)0; + + if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) { + ep = &envbuffer[envbufsize]; + envbufsize += bytes; + } + return ep; +} + +/* + * kdbgetulenv + * + * This function will return the value of an unsigned long-valued + * environment variable. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetulenv(const char *match, unsigned long *value) +{ + char *ep; + + ep = kdbgetenv(match); + if (!ep) return KDB_NOTENV; + if (strlen(ep) == 0) return KDB_NOENVVALUE; + + *value = simple_strtoul(ep, 0, 0); + + return 0; +} + +/* + * kdbgetintenv + * + * This function will return the value of an integer-valued + * environment variable. + * + * Parameters: + * match A character string representing an integer-valued env variable + * Outputs: + * *value the integer representation of the environment variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetintenv(const char *match, int *value) { + unsigned long val; + int diag; + + diag = kdbgetulenv(match, &val); + if (!diag) { + *value = (int) val; + } + return diag; +} + +/* + * kdbgetularg + * + * This function will convert a numeric string + * into an unsigned long value. + * + * Parameters: + * arg A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of arg. + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetularg(const char *arg, unsigned long *value) +{ + char *endp; + unsigned long val; + + val = simple_strtoul(arg, &endp, 0); + + if (endp == arg) { + /* + * Try base 16, for us folks too lazy to type the + * leading 0x... + */ + val = simple_strtoul(arg, &endp, 16); + if (endp == arg) + return KDB_BADINT; + } + + *value = val; + + return 0; +} + +/* + * kdbgetaddrarg + * + * This function is responsible for parsing an + * address-expression and returning the value of + * the expression, symbol name, and offset to the caller. + * + * The argument may consist of a numeric value (decimal or + * hexidecimal), a symbol name, a register name (preceeded + * by the percent sign), an environment variable with a numeric + * value (preceeded by a dollar sign) or a simple arithmetic + * expression consisting of a symbol name, +/-, and a numeric + * constant value (offset). + * + * Parameters: + * argc - count of arguments in argv + * argv - argument vector + * *nextarg - index to next unparsed argument in argv[] + * regs - Register state at time of KDB entry + * Outputs: + * *value - receives the value of the address-expression + * *offset - receives the offset specified, if any + * *name - receives the symbol name, if any + * *nextarg - index to next unparsed argument in argv[] + * + * Returns: + * zero is returned on success, a kdb diagnostic code is + * returned on error. + * + * Locking: + * No locking requirements. + * + * Remarks: + * + */ + +int +kdbgetaddrarg(int argc, const char **argv, int *nextarg, + kdb_machreg_t *value, long *offset, + char **name, struct pt_regs *regs) +{ + kdb_machreg_t addr; + long off = 0; + int positive; + int diag; + int found = 0; + char *symname; + char symbol = '\0'; + char *cp; + kdb_symtab_t symtab; + + /* + * Process arguments which follow the following syntax: + * + * symbol | numeric-address [+/- numeric-offset] + * %register + * $environment-variable + */ + + if (*nextarg > argc) { + return KDB_ARGCOUNT; + } + + symname = (char *)argv[*nextarg]; + + /* + * If there is no whitespace between the symbol + * or address and the '+' or '-' symbols, we + * remember the character and replace it with a + * null so the symbol/value can be properly parsed + */ + if ((cp = strpbrk(symname, "+-")) != NULL) { + symbol = *cp; + *cp++ = '\0'; + } + + if (symname[0] == '$') { + diag = kdbgetulenv(&symname[1], &addr); + if (diag) + return diag; + } else if (symname[0] == '%') { + diag = kdba_getregcontents(&symname[1], regs, &addr); + if (diag) + return diag; + } else { + found = kdbgetsymval(symname, &symtab); + if (found) { + addr = symtab.sym_start; + } else { + diag = kdbgetularg(argv[*nextarg], &addr); + if (diag) + return diag; + } + } + + if (!found) + found = kdbnearsym(addr, &symtab); + + (*nextarg)++; + + if (name) + *name = symname; + if (value) + *value = addr; + if (offset && name && *name) + *offset = addr - symtab.sym_start; + + if ((*nextarg > argc) + && (symbol == '\0')) + return 0; + + /* + * check for +/- and offset + */ + + if (symbol == '\0') { + if ((argv[*nextarg][0] != '+') + && (argv[*nextarg][0] != '-')) { + /* + * Not our argument. Return. + */ + return 0; + } else { + positive = (argv[*nextarg][0] == '+'); + (*nextarg)++; + } + } else + positive = (symbol == '+'); + + /* + * Now there must be an offset! + */ + if ((*nextarg > argc) + && (symbol == '\0')) { + return KDB_INVADDRFMT; + } + + if (!symbol) { + cp = (char *)argv[*nextarg]; + (*nextarg)++; + } + + diag = kdbgetularg(cp, &off); + if (diag) + return diag; + + if (!positive) + off = -off; + + if (offset) + *offset += off; + + if (value) + *value += off; + + return 0; +} + +static void +kdb_cmderror(int diag) +{ + int i; + + if (diag >= 0) { + kdb_printf("no error detected\n"); + return; + } + + for(i=0; i<__nkdb_err; i++) { + if (kdbmsgs[i].km_diag == diag) { + kdb_printf("diag: %d: %s\n", diag, kdbmsgs[i].km_msg); + return; + } + } + + kdb_printf("Unknown diag %d\n", -diag); +} + +/* + * kdb_defcmd, kdb_defcmd2 + * + * This function implements the 'defcmd' command which defines one + * command as a set of other commands, terminated by endefcmd. + * kdb_defcmd processes the initial 'defcmd' command, kdb_defcmd2 + * is invoked from kdb_parse for the following commands until + * 'endefcmd'. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +struct defcmd_set { + int count; + int usable; + char *name; + char *usage; + char *help; + char **command; +}; +static struct defcmd_set *defcmd_set; +static int defcmd_set_count; +static int defcmd_in_progress; + +/* Forward references */ +static int kdb_exec_defcmd(int argc, const char **argv, const char **envp, struct pt_regs *regs); + +static int +kdb_defcmd2(const char *cmdstr, const char *argv0) +{ + struct defcmd_set *s = defcmd_set + defcmd_set_count - 1; + char **save_command = s->command; + if (strcmp(argv0, "endefcmd") == 0) { + defcmd_in_progress = 0; + if (!s->count) + s->usable = 0; + if (s->usable) + kdb_register(s->name, kdb_exec_defcmd, s->usage, s->help, 0); + return 0; + } + if (!s->usable) + return KDB_NOTIMP; + s->command = kmalloc((s->count + 1) * sizeof(*(s->command)), GFP_KERNEL); + if (!s->command) { + kdb_printf("Could not allocate new kdb_defcmd table for %s\n", cmdstr); + s->usable = 0; + return KDB_NOTIMP; + } + memcpy(s->command, save_command, s->count * sizeof(*(s->command))); + s->command[s->count++] = kdb_strdup(cmdstr, GFP_KERNEL); + kfree(save_command); + return 0; +} + +static int +kdb_defcmd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct defcmd_set *save_defcmd_set = defcmd_set, *s; + if (argc != 3) + return KDB_ARGCOUNT; + if (defcmd_in_progress) { + kdb_printf("kdb: nested defcmd detected, assuming missing endefcmd\n"); + kdb_defcmd2("endefcmd", "endefcmd"); + } + defcmd_set = kmalloc((defcmd_set_count + 1) * sizeof(*defcmd_set), GFP_KERNEL); + if (!defcmd_set) { + kdb_printf("Could not allocate new defcmd_set entry for %s\n", argv[1]); + defcmd_set = save_defcmd_set; + return KDB_NOTIMP; + } + memcpy(defcmd_set, save_defcmd_set, defcmd_set_count * sizeof(*defcmd_set)); + kfree(save_defcmd_set); + s = defcmd_set + defcmd_set_count; + memset(s, 0, sizeof(*s)); + s->usable = 1; + s->name = kdb_strdup(argv[1], GFP_KERNEL); + s->usage = kdb_strdup(argv[2], GFP_KERNEL); + s->help = kdb_strdup(argv[3], GFP_KERNEL); + if (s->usage[0] == '"') { + strcpy(s->usage, s->usage+1); + s->usage[strlen(s->usage)-1] = '\0'; + } + if (s->help[0] == '"') { + strcpy(s->help, s->help+1); + s->help[strlen(s->help)-1] = '\0'; + } + ++defcmd_set_count; + defcmd_in_progress = 1; + return 0; +} + +/* + * kdb_exec_defcmd + * + * Execute the set of commands associated with this defcmd name. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_exec_defcmd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i, ret; + struct defcmd_set *s; + if (argc != 0) + return KDB_ARGCOUNT; + for (s = defcmd_set, i = 0; i < defcmd_set_count; ++i, ++s) { + if (strcmp(s->name, argv[0]) == 0) + break; + } + if (i == defcmd_set_count) { + kdb_printf("kdb_exec_defcmd: could not find commands for %s\n", argv[0]); + return KDB_NOTIMP; + } + for (i = 0; i < s->count; ++i) { + /* Recursive use of kdb_parse, argv is now unreliable */ + argv = NULL; + kdb_printf("[%s]kdb> %s\n", s->name, s->command[i]); + if ((ret = kdb_parse(s->command[i], regs))) + return ret; + } + return 0; +} + +/* The command history feature is not functional at the moment. It + * will be replaced by something that understands editting keys, + * including left, right, insert, delete as well as up, down. + * Keith Owens, November 18 2000 + */ +#define KDB_CMD_HISTORY_COUNT 32 +#define CMD_BUFLEN 200 /* kdb_printf: max printline size == 256 */ +static unsigned int cmd_head=0, cmd_tail=0; +static unsigned int cmdptr; +static char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN]; +static char cmd_cur[CMD_BUFLEN]; + +/* + * kdb_parse + * + * Parse the command line, search the command table for a + * matching command and invoke the command function. + * This function may be called recursively, if it is, the second call + * will overwrite argv and cbuf. It is the caller's responsibility to + * save their argv if they recursively call kdb_parse(). + * + * Parameters: + * cmdstr The input command line to be parsed. + * regs The registers at the time kdb was entered. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + * Limited to 20 tokens. + * + * Real rudimentary tokenization. Basically only whitespace + * is considered a token delimeter (but special consideration + * is taken of the '=' sign as used by the 'set' command). + * + * The algorithm used to tokenize the input string relies on + * there being at least one whitespace (or otherwise useless) + * character between tokens as the character immediately following + * the token is altered in-place to a null-byte to terminate the + * token string. + */ + +#define MAXARGC 20 + +int +kdb_parse(const char *cmdstr, struct pt_regs *regs) +{ + static char *argv[MAXARGC]; + static int argc = 0; + static char cbuf[CMD_BUFLEN+2]; + const char *cp; + char *cpp, quoted; + kdbtab_t *tp; + int i, escaped, ignore_errors = 0; + + /* + * First tokenize the command string. + */ + cp = cmdstr; + + if (*cp != '\n' && *cp != '\0') { + argc = 0; + cpp = cbuf; + while (*cp) { + /* skip whitespace */ + while (isspace(*cp)) cp++; + if ((*cp == '\0') || (*cp == '\n')) + break; + if (cpp >= cbuf + CMD_BUFLEN) { + kdb_printf("kdb_parse: command buffer overflow, command ignored\n%s\n", cmdstr); + return KDB_NOTFOUND; + } + if (argc >= MAXARGC - 1) { + kdb_printf("kdb_parse: too many arguments, command ignored\n%s\n", cmdstr); + return KDB_NOTFOUND; + } + argv[argc++] = cpp; + escaped = 0; + quoted = '\0'; + /* Copy to next unquoted and unescaped whitespace or '=' */ + while (*cp && *cp != '\n' && (escaped || quoted || !isspace(*cp))) { + if (cpp >= cbuf + CMD_BUFLEN) + break; + if (escaped) { + escaped = 0; + *cpp++ = *cp++; + continue; + } + if (*cp == '\\') { + escaped = 1; + ++cp; + continue; + } + if (*cp == quoted) { + quoted = '\0'; + } else if (*cp == '\'' || *cp == '"') { + quoted = *cp; + } + if ((*cpp = *cp++) == '=' && !quoted) + break; + ++cpp; + } + *cpp++ = '\0'; /* Squash a ws or '=' character */ + } + } + if (!argc) + return 0; + if (defcmd_in_progress) { + int result = kdb_defcmd2(cmdstr, argv[0]); + if (!defcmd_in_progress) { + argc = 0; /* avoid repeat on endefcmd */ + *(argv[0]) = '\0'; + } + return result; + } + if (argv[0][0] == '-' && argv[0][1] && (argv[0][1] < '0' || argv[0][1] > '9')) { + ignore_errors = 1; + ++argv[0]; + } + + for(tp=kdb_commands, i=0; i < kdb_max_commands; i++,tp++) { + if (tp->cmd_name) { + /* + * If this command is allowed to be abbreviated, + * check to see if this is it. + */ + + if (tp->cmd_minlen + && (strlen(argv[0]) <= tp->cmd_minlen)) { + if (strncmp(argv[0], + tp->cmd_name, + tp->cmd_minlen) == 0) { + break; + } + } + + if (strcmp(argv[0], tp->cmd_name)==0) { + break; + } + } + } + + /* + * If we don't find a command by this name, see if the first + * few characters of this match any of the known commands. + * e.g., md1c20 should match md. + */ + if (i == kdb_max_commands) { + for(tp=kdb_commands, i=0; i < kdb_max_commands; i++,tp++) { + if (tp->cmd_name) { + if (strncmp(argv[0], + tp->cmd_name, + strlen(tp->cmd_name))==0) { + break; + } + } + } + } + + if (i < kdb_max_commands) { + int result; + KDB_STATE_SET(CMD); + result = (*tp->cmd_func)(argc-1, + (const char**)argv, + (const char**)__env, + regs); + if (result && ignore_errors && result > KDB_CMD_GO) + result = 0; + KDB_STATE_CLEAR(CMD); + switch (tp->cmd_repeat) { + case KDB_REPEAT_NONE: + argc = 0; + if (argv[0]) + *(argv[0]) = '\0'; + break; + case KDB_REPEAT_NO_ARGS: + argc = 1; + if (argv[1]) + *(argv[1]) = '\0'; + break; + case KDB_REPEAT_WITH_ARGS: + break; + } + return result; + } + + /* + * If the input with which we were presented does not + * map to an existing command, attempt to parse it as an + * address argument and display the result. Useful for + * obtaining the address of a variable, or the nearest symbol + * to an address contained in a register. + */ + { + kdb_machreg_t value; + char *name = NULL; + long offset; + int nextarg = 0; + + if (kdbgetaddrarg(0, (const char **)argv, &nextarg, + &value, &offset, &name, regs)) { + return KDB_NOTFOUND; + } + + kdb_printf("%s = ", argv[0]); + kdb_symbol_print(value, NULL, KDB_SP_DEFAULT); + kdb_printf("\n"); + return 0; + } +} + + +static int +handle_ctrl_cmd(char *cmd) +{ +#define CTRL_P 16 +#define CTRL_N 14 + + /* initial situation */ + if (cmd_head == cmd_tail) return 0; + + switch(*cmd) { + case CTRL_P: + if (cmdptr != cmd_tail) + cmdptr = (cmdptr-1) % KDB_CMD_HISTORY_COUNT; + strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN); + return 1; + case CTRL_N: + if (cmdptr != cmd_head) + cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT; + strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN); + return 1; + } + return 0; +} + + +/* + * kdb_local + * + * The main code for kdb. This routine is invoked on a specific + * processor, it is not global. The main kdb() routine ensures + * that only one processor at a time is in this routine. This + * code is called with the real reason code on the first entry + * to a kdb session, thereafter it is called with reason SWITCH, + * even if the user goes back to the original cpu. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * regs The exception frame at time of fault/breakpoint. NULL + * for reason SILENT, otherwise valid. + * db_result Result code from the break or debug point. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * KDB_CMD_GO User typed 'go'. + * KDB_CMD_CPU User switched to another cpu. + * KDB_CMD_SS Single step. + * KDB_CMD_SSB Single step until branch. + * Locking: + * none + * Remarks: + * none + */ + +extern int kdb_btc_next; +extern char kdb_prompt_str[]; + +static int +kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, kdb_dbtrap_t db_result) +{ + char *cmdbuf; + int diag; + + if (reason != KDB_REASON_DEBUG && + reason != KDB_REASON_SILENT) { + kdb_printf("\nEntering kdb (current=0x%p, pid %d) ", (void *)current, current->pid); +#if defined(CONFIG_SMP) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + } + + switch (reason) { + case KDB_REASON_DEBUG: + { + /* + * If re-entering kdb after a single step + * command, don't print the message. + */ + switch(db_result) { + case KDB_DB_BPT: + kdb_printf("\nEntering kdb (0x%p) ", (void *)current); +#if defined(CONFIG_SMP) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + kdb_printf("due to Debug @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + break; + case KDB_DB_SSB: + /* + * In the midst of ssb command. Just return. + */ + return KDB_CMD_SSB; /* Continue with SSB command */ + + break; + case KDB_DB_SS: + break; + case KDB_DB_SSBPT: + return 1; /* kdba_db_trap did the work */ + default: + kdb_printf("kdb: Bad result from kdba_db_trap: %d\n", + db_result); + break; + } + + } + break; + case KDB_REASON_FAULT: + break; + case KDB_REASON_ENTER: + kdb_printf("due to KDB_ENTER()\n"); + break; + case KDB_REASON_KEYBOARD: + kdb_printf("due to Keyboard Entry\n"); + break; + case KDB_REASON_SWITCH: + kdb_printf("due to cpu switch\n"); + if (KDB_STATE(GO_SWITCH)) { + KDB_STATE_CLEAR(GO_SWITCH); + return KDB_CMD_GO; + } + break; + case KDB_REASON_CALL: + if (!regs) + kdb_printf("kdb() called with no registers, restricted function\n"); + break; + case KDB_REASON_OOPS: + kdb_printf("Oops: %s\n", kdb_diemsg); + kdb_printf("due to oops @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + kdba_dumpregs(regs, NULL, NULL); + break; + case KDB_REASON_NMI: + kdb_printf("due to NonMaskable Interrupt @ " kdb_machreg_fmt "\n", + kdba_getpc(regs)); + kdba_dumpregs(regs, NULL, NULL); + break; + case KDB_REASON_WATCHDOG: + kdb_printf("due to WatchDog Interrupt @ " kdb_machreg_fmt "\n", + kdba_getpc(regs)); + kdba_dumpregs(regs, NULL, NULL); + break; + case KDB_REASON_BREAK: + kdb_printf("due to Breakpoint @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + /* + * Determine if this breakpoint is one that we + * are interested in. + */ + if (db_result != KDB_DB_BPT) { + kdb_printf("kdb: error return from kdba_bp_trap: %d\n", db_result); + return 0; /* Not for us, dismiss it */ + } + break; + case KDB_REASON_RECURSE: + kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + break; + case KDB_REASON_SILENT: + return KDB_CMD_GO; /* Silent entry, silent exit */ + break; + default: + kdb_printf("kdb: unexpected reason code: %d\n", reason); + return 0; /* Not for us, dismiss it */ + } + + kdba_local_arch_setup(); + + while (1) { + /* + * Initialize pager context. + */ + kdb_nextline = 1; + KDB_STATE_CLEAR(SUPPRESS); +#ifdef KDB_HAVE_LONGJMP + /* + * Use kdba_setjmp/kdba_longjmp to break out of + * the pager early and to attempt to recover from kdb errors. + */ + KDB_STATE_CLEAR(LONGJMP); + if (kdba_setjmp(&kdbjmpbuf[smp_processor_id()])) { + /* Command aborted (usually in pager) */ + kdb_btc_next = -1; + continue; + } + else + KDB_STATE_SET(LONGJMP); +#endif /* KDB_HAVE_LONGJMP */ + + cmdbuf = cmd_cur; + *cmdbuf = '\0'; + *(cmd_hist[cmd_head])='\0'; + +do_full_getstr: +#if defined(CONFIG_SMP) + snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"), smp_processor_id()); +#else + snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT")); +#endif + if (defcmd_in_progress) + strncat(kdb_prompt_str, "[defcmd]", CMD_BUFLEN); + + /* + * Autogenerate command or fetch command from keyboard + */ + if (kdb_btc_next == -1) { + cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, kdb_prompt_str); + } else { + if (kdb_btc_next != smp_processor_id()) { + if (kdb_btc_next == NR_CPUS) + kdb_btc_next = -1; + snprintf(cmdbuf, CMD_BUFLEN, "cpu %d\n", kdb_btc_next == -1 ? kdb_initial_cpu : kdb_btc_next); + } + else { + snprintf(cmdbuf, CMD_BUFLEN, "bt\n"); + /* Reset NMI watchdog once per cpu */ + touch_nmi_watchdog(); + /* which cpu is next? */ + for (++kdb_btc_next; kdb_btc_next < NR_CPUS; ++kdb_btc_next) { + if (KDB_STATE_CPU(KDB, kdb_btc_next)) + break; + } + } + kdb_printf("%s", cmdbuf); + } + + if (*cmdbuf != '\n' && kdb_btc_next == -1) { + if (*cmdbuf < 32) { + if(cmdptr == cmd_head) { + strncpy(cmd_hist[cmd_head], cmd_cur, CMD_BUFLEN); + *(cmd_hist[cmd_head]+strlen(cmd_hist[cmd_head])-1) = '\0'; + } + if(!handle_ctrl_cmd(cmdbuf)) + *(cmd_cur+strlen(cmd_cur)-1) = '\0'; + cmdbuf = cmd_cur; + goto do_full_getstr; + } + else + strncpy(cmd_hist[cmd_head], cmd_cur, CMD_BUFLEN); + + cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT; + if (cmd_head == cmd_tail) cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT; + + } + + cmdptr = cmd_head; + diag = kdb_parse(cmdbuf, regs); + if (diag == KDB_NOTFOUND) { + kdb_printf("Unknown kdb command: '%s'\n", cmdbuf); + kdb_btc_next = -1; + diag = 0; + } + if (diag == KDB_CMD_GO + || diag == KDB_CMD_CPU + || diag == KDB_CMD_SS + || diag == KDB_CMD_SSB) + break; + + if (diag) { + kdb_cmderror(diag); + kdb_btc_next = -1; + } + } + + kdba_local_arch_cleanup(); + + return(diag); +} + + +/* + * kdb_print_state + * + * Print the state data for the current processor for debugging. + * + * Inputs: + * text Identifies the debug point + * value Any integer value to be printed, e.g. reason code. + * Returns: + * None. + * Locking: + * none + * Remarks: + * none + */ + +void kdb_print_state(const char *text, int value) +{ + kdb_printf("state: %s cpu %d value %d initial %d state %x\n", + text, smp_processor_id(), value, kdb_initial_cpu, kdb_state[smp_processor_id()]); +} + +/* + * kdb_previous_event + * + * Return a count of cpus that are leaving kdb, i.e. the number + * of processors that are still handling the previous kdb event. + * + * Inputs: + * None. + * Returns: + * Count of cpus in previous event. + * Locking: + * none + * Remarks: + * none + */ + +static int +kdb_previous_event(void) +{ + int i, leaving = 0; + for (i = 0; i < NR_CPUS; ++i) { + if (KDB_STATE_CPU(LEAVING, i)) + ++leaving; + } + return(leaving); +} + +/* + * kdb_main_loop + * + * The main kdb loop. After initial setup and assignment of the controlling + * cpu, all cpus are in this loop. One cpu is in control and will issue the kdb + * prompt, the others will spin until 'go' or cpu switch. + * + * To get a consistent view of the kernel stacks for all processes, this routine + * is invoked from the main kdb code via an architecture specific routine. + * kdba_main_loop is responsible for making the kernel stacks consistent for all + * processes, there should be no difference between a blocked process and a + * running process as far as kdb is concerned. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * reason2 kdb's current reason code. Initially error but can change + * acording to kdb state. + * db_result Result code from break or debug point. + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it + * should always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Locking: + * none + * Remarks: + * none + */ + +int +kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, + kdb_dbtrap_t db_result, struct pt_regs *regs) +{ + int result = 1; + /* Stay in kdb() until 'go', 'ss[b]' or an error */ + while (1) { + /* + * All processors except the one that is in control + * will spin here. + */ + KDB_DEBUG_STATE("kdb_main_loop 1", reason); + while (KDB_STATE(HOLD_CPU)) { + /* state KDB is turned off by kdb_cpu to see if the + * other cpus are still live, each cpu in this loop + * turns it back on. + */ + if (!KDB_STATE(KDB)) { + KDB_STATE_SET(KDB); + } + } + KDB_STATE_CLEAR(SUPPRESS); + KDB_DEBUG_STATE("kdb_main_loop 2", reason); + if (KDB_STATE(LEAVING)) + break; /* Another cpu said 'go' */ + + /* Still using kdb, this processor is in control */ + result = kdb_local(reason2, error, regs, db_result); + KDB_DEBUG_STATE("kdb_main_loop 3", result); + + if (result == KDB_CMD_CPU) { + /* Cpu switch, hold the current cpu, release the target one. */ + reason2 = KDB_REASON_SWITCH; + KDB_STATE_SET(HOLD_CPU); + KDB_STATE_CLEAR_CPU(HOLD_CPU, kdb_new_cpu); + continue; + } + + if (result == KDB_CMD_SS) { + KDB_STATE_SET(DOING_SS); + break; + } + + if (result == KDB_CMD_SSB) { + KDB_STATE_SET(DOING_SS); + KDB_STATE_SET(DOING_SSB); + break; + } + + if (result && result != 1 && result != KDB_CMD_GO) + kdb_printf("\nUnexpected kdb_local return code %d\n", result); + + KDB_DEBUG_STATE("kdb_main_loop 4", reason); + break; + } + if (KDB_STATE(DOING_SS)) + KDB_STATE_CLEAR(SSBPT); + return(result); +} + +/* + * kdb + * + * This function is the entry point for the kernel debugger. It + * provides a command parser and associated support functions to + * allow examination and control of an active kernel. + * + * This function may be invoked directly from any + * point in the kernel by calling with reason == KDB_REASON_CALL + * + * The breakpoint trap code should invoke this function with + * one of KDB_REASON_BREAK (int 03) or KDB_REASON_DEBUG (debug register) + * + * the die_if_kernel function should invoke this function with + * KDB_REASON_OOPS. + * + * The kernel fault handler should invoke this function with + * reason == KDB_REASON_FAULT and error == trap vector #. + * + * In single step mode, one cpu is released to run without + * breakpoints. Interrupts and NMI are reset to their original values, + * the cpu is allowed to do one instruction which causes a trap + * into kdb with KDB_REASON_DEBUG. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it + * should always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Locking: + * none + * Remarks: + * No assumptions of system state. This function may be invoked + * with arbitrary locks held. It will stop all other processors + * in an SMP environment, disable all interrupts and does not use + * the operating systems keyboard driver. + * + * This code is reentrant but only for cpu switch. Any other + * reentrancy is an error, although kdb will attempt to recover. + * + * At the start of a kdb session the initial processor is running + * kdb() and the other processors can be doing anything. When the + * initial processor calls smp_kdb_stop() the other processors are + * driven through kdb_ipi which calls kdb() with reason SWITCH. + * That brings all processors into this routine, one with a "real" + * reason code, the other with SWITCH. + * + * Because the other processors are driven via smp_kdb_stop(), + * they enter here from the NMI handler. Until the other + * processors exit from here and exit from kdb_ipi, they will not + * take any more NMI requests. The initial cpu will still take NMI. + * + * Multiple race and reentrancy conditions, each with different + * advoidance mechanisms. + * + * Two cpus hit debug points at the same time. + * + * kdb_lock and kdb_initial_cpu ensure that only one cpu gets + * control of kdb. The others spin on kdb_initial_cpu until + * they are driven through NMI into kdb_ipi. When the initial + * cpu releases the others from NMI, they resume trying to get + * kdb_initial_cpu to start a new event. + * + * A cpu is released from kdb and starts a new event before the + * original event has completely ended. + * + * kdb_previous_event() prevents any cpu from entering + * kdb_initial_cpu state until the previous event has completely + * ended on all cpus. + * + * An exception occurs inside kdb. + * + * kdb_initial_cpu detects recursive entry to kdb and attempts + * to recover. The recovery uses longjmp() which means that + * recursive calls to kdb never return. Beware of assumptions + * like + * + * ++depth; + * kdb(); + * --depth; + * + * If the kdb call is recursive then longjmp takes over and + * --depth is never executed. + * + * NMI handling. + * + * NMI handling is tricky. The initial cpu is invoked by some kdb event, + * this event could be NMI driven but usually is not. The other cpus are + * driven into kdb() via kdb_ipi which uses NMI so at the start the other + * cpus will not accept NMI. Some operations such as SS release one cpu + * but hold all the others. Releasing a cpu means it drops back to + * whatever it was doing before the kdb event, this means it drops out of + * kdb_ipi and hence out of NMI status. But the software watchdog uses + * NMI and we do not want spurious watchdog calls into kdb. kdba_read() + * resets the watchdog counters in its input polling loop, when a kdb + * command is running it is subject to NMI watchdog events. + * + * Another problem with NMI handling is the NMI used to drive the other + * cpus into kdb cannot be distinguished from the watchdog NMI. State + * flag WAIT_IPI indicates that a cpu is waiting for NMI via kdb_ipi, + * if not set then software NMI is ignored by kdb_ipi. + * + * Cpu switching. + * + * All cpus are in kdb (or they should be), all but one are + * spinning on KDB_STATE(HOLD_CPU). Only one cpu is not in + * HOLD_CPU state, only that cpu can handle commands. + * + * Go command entered. + * + * If necessary, go will switch to the initial cpu first. If the event + * was caused by a software breakpoint (assumed to be global) that + * requires single-step to get over the breakpoint then only release the + * initial cpu, after the initial cpu has single-stepped the breakpoint + * then release the rest of the cpus. If SSBPT is not required then + * release all the cpus at once. + */ + +int +kdb(kdb_reason_t reason, int error, struct pt_regs *regs) +{ + kdb_intstate_t int_state; /* Interrupt state */ + kdb_reason_t reason2 = reason; + int result = 1; /* Default is kdb handled it */ + int ss_event; + kdb_dbtrap_t db_result=KDB_DB_NOBPT; + + if (!kdb_on) + return 0; + + KDB_DEBUG_STATE("kdb 1", reason); + KDB_STATE_CLEAR(SUPPRESS); + + /* Filter out userspace breakpoints first, no point in doing all + * the kdb smp fiddling when it is really a gdb trap. + * Save the single step status first, kdba_db_trap clears ss status. + * kdba_b[dp]_trap sets SSBPT if required. + */ + ss_event = KDB_STATE(DOING_SS) || KDB_STATE(SSBPT); + if (reason == KDB_REASON_BREAK) + db_result = kdba_bp_trap(regs, error); /* Only call this once */ + if (reason == KDB_REASON_DEBUG) + db_result = kdba_db_trap(regs, error); /* Only call this once */ + + if ((reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) + && db_result == KDB_DB_NOBPT) { + KDB_DEBUG_STATE("kdb 2", reason); + return 0; /* Not one of mine */ + } + + /* Turn off single step if it was being used */ + if (ss_event) { + kdba_clearsinglestep(regs); + /* Single step after a breakpoint removes the need for a delayed reinstall */ + if (reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) + KDB_STATE_CLEAR(SSBPT); + } + + /* kdb can validly reenter but only for certain well defined conditions */ + if (reason == KDB_REASON_DEBUG + && !KDB_STATE(HOLD_CPU) + && ss_event) + KDB_STATE_SET(REENTRY); + else + KDB_STATE_CLEAR(REENTRY); + + /* Wait for previous kdb event to completely exit before starting + * a new event. + */ + while (kdb_previous_event()) + ; + KDB_DEBUG_STATE("kdb 3", reason); + + /* + * If kdb is already active, print a message and try to recover. + * If recovery is not possible and recursion is allowed or + * forced recursion without recovery is set then try to recurse + * in kdb. Not guaranteed to work but it makes an attempt at + * debugging the debugger. + */ + if (reason != KDB_REASON_SWITCH) { + if (KDB_IS_RUNNING() && !KDB_STATE(REENTRY)) { + int recover = 1; + unsigned long recurse = 0; + kdb_printf("kdb: Debugger re-entered on cpu %d, new reason = %d\n", + smp_processor_id(), reason); + /* Should only re-enter from released cpu */ + + if (KDB_STATE(HOLD_CPU)) { + kdb_printf(" Strange, cpu %d should not be running\n", smp_processor_id()); + recover = 0; + } + if (!KDB_STATE(CMD)) { + kdb_printf(" Not executing a kdb command\n"); + recover = 0; + } + if (!KDB_STATE(LONGJMP)) { + kdb_printf(" No longjmp available for recovery\n"); + recover = 0; + } + kdbgetulenv("RECURSE", &recurse); + if (recurse > 1) { + kdb_printf(" Forced recursion is set\n"); + recover = 0; + } + if (recover) { + kdb_printf(" Attempting to abort command and recover\n"); +#ifdef KDB_HAVE_LONGJMP + kdba_longjmp(&kdbjmpbuf[smp_processor_id()], 0); +#endif + } + if (recurse) { + if (KDB_STATE(RECURSE)) { + kdb_printf(" Already in recursive mode\n"); + } else { + kdb_printf(" Attempting recursive mode\n"); + KDB_STATE_SET(RECURSE); + KDB_STATE_SET(REENTRY); + reason2 = KDB_REASON_RECURSE; + recover = 1; + } + } + if (!recover) { + kdb_printf(" Cannot recover, allowing event to proceed\n"); + return(0); + } + } + } else if (!KDB_IS_RUNNING()) { + kdb_printf("kdb: CPU switch without kdb running, I'm confused\n"); + return(0); + } + + /* + * Disable interrupts, breakpoints etc. on this processor + * during kdb command processing + */ + KDB_STATE_SET(KDB); + kdba_disableint(&int_state); + if (!ss_event) { + /* bh not re-enabled during single step */ + local_bh_disable(); + } + if (!KDB_STATE(KDB_CONTROL)) { + kdb_bp_remove_local(); + kdba_disable_lbr(); + KDB_STATE_SET(KDB_CONTROL); + } + else if (KDB_DEBUG(LBR)) + kdba_print_lbr(); + + /* + * If not entering the debugger due to CPU switch or single step + * reentry, serialize access here. + * The processors may race getting to this point - if, + * for example, more than one processor hits a breakpoint + * at the same time. We'll serialize access to kdb here - + * other processors will loop here, and the NMI from the stop + * IPI will take them into kdb as switch candidates. Once + * the initial processor releases the debugger, the rest of + * the processors will race for it. + */ + if (reason == KDB_REASON_SWITCH + || KDB_STATE(REENTRY)) + ; /* drop through */ + else { + KDB_DEBUG_STATE("kdb 4", reason); + spin_lock(&kdb_lock); + + while (KDB_IS_RUNNING() || kdb_previous_event()) { + spin_unlock(&kdb_lock); + + while (KDB_IS_RUNNING() || kdb_previous_event()) + ; + + spin_lock(&kdb_lock); + } + KDB_DEBUG_STATE("kdb 5", reason); + + kdb_initial_cpu = smp_processor_id(); + spin_unlock(&kdb_lock); + notifier_call_chain(&kdb_notifier_list, 1, NULL); + } + + if (smp_processor_id() == kdb_initial_cpu + && !KDB_STATE(REENTRY)) { + KDB_STATE_CLEAR(HOLD_CPU); + KDB_STATE_CLEAR(WAIT_IPI); + /* + * Remove the global breakpoints. This is only done + * once from the initial processor on initial entry. + */ + kdb_bp_remove_global(); + + /* + * If SMP, stop other processors. The other processors + * will enter kdb() with KDB_REASON_SWITCH and spin in + * kdb_main_loop(). + */ + KDB_DEBUG_STATE("kdb 6", reason); + if (smp_num_cpus > 1) { + int i; + for (i = 0; i < NR_CPUS; ++i) { + if (!(cpu_online_map & (1UL << i))) + continue; + if (i != kdb_initial_cpu) { + KDB_STATE_SET_CPU(HOLD_CPU, i); + KDB_STATE_SET_CPU(WAIT_IPI, i); + } + } + KDB_DEBUG_STATE("kdb 7", reason); + smp_kdb_stop(); + KDB_DEBUG_STATE("kdb 8", reason); + } + } + + if (KDB_STATE(GO1)) { + kdb_bp_remove_global(); /* They were set for single-step purposes */ + KDB_STATE_CLEAR(GO1); + reason = KDB_REASON_SILENT; /* Now silently go */ + } + + /* Set up a consistent set of process stacks before talking to the user */ + KDB_DEBUG_STATE("kdb 9", result); + result = kdba_main_loop(reason, reason2, error, db_result, regs); + + KDB_DEBUG_STATE("kdb 10", result); + kdba_adjust_ip(reason, error, regs); + KDB_STATE_CLEAR(LONGJMP); + KDB_DEBUG_STATE("kdb 11", result); + /* go which requires single-step over a breakpoint must only release + * one cpu. + */ + if (result == KDB_CMD_GO && KDB_STATE(SSBPT)) + KDB_STATE_SET(GO1); + + /* No breakpoints installed for SS */ + if (!KDB_STATE(DOING_SS) && + !KDB_STATE(SSBPT) && + !KDB_STATE(RECURSE)) { + KDB_DEBUG_STATE("kdb 12", result); + kdba_enable_lbr(); + kdb_bp_install_local(regs); + local_bh_enable(); + KDB_STATE_CLEAR(KDB_CONTROL); + } + + KDB_DEBUG_STATE("kdb 13", result); + kdba_restoreint(&int_state); + + if (smp_processor_id() == kdb_initial_cpu && + !KDB_STATE(DOING_SS) && + !KDB_STATE(RECURSE)) { + /* + * (Re)install the global breakpoints. This is only done + * once from the initial processor on go. + */ + KDB_DEBUG_STATE("kdb 14", reason); + kdb_bp_install_global(regs); + if (!KDB_STATE(GO1)) { + /* + * Release all other cpus which will see KDB_STATE(LEAVING) is set. + */ + int i; + for (i = 0; i < NR_CPUS; ++i) { + if (KDB_STATE_CPU(KDB, i)) + KDB_STATE_SET_CPU(LEAVING, i); + KDB_STATE_CLEAR_CPU(WAIT_IPI, i); + KDB_STATE_CLEAR_CPU(HOLD_CPU, i); + } + /* Wait until all the other processors leave kdb */ + while (kdb_previous_event() != 1) + ; + notifier_call_chain(&kdb_notifier_list, 0, NULL); + kdb_initial_cpu = -1; /* release kdb control */ + KDB_DEBUG_STATE("kdb 15", reason); + } + } + + KDB_DEBUG_STATE("kdb 16", result); + KDB_STATE_CLEAR(IP_ADJUSTED); /* Re-adjust ip next time in */ + KDB_STATE_CLEAR(KDB); /* Main kdb state has been cleared */ + KDB_STATE_CLEAR(RECURSE); + KDB_STATE_CLEAR(LEAVING); /* No more kdb work after this */ + KDB_DEBUG_STATE("kdb 17", reason); + return(result != 0); +} + +/* + * kdb_mdr + * + * This function implements the guts of the 'mdr' command. + * + * mdr , + * + * Inputs: + * addr Start address + * count Number of bytes + * Outputs: + * None. + * Returns: + * Always 0. Any errors are detected and printed by kdb_getarea. + * Locking: + * none. + * Remarks: + */ + +static int +kdb_mdr(kdb_machreg_t addr, unsigned int count) +{ + unsigned char c; + while (count--) { + if (kdb_getarea(c, addr)) + return(0); + kdb_printf("%02x", c); + addr++; + } + kdb_printf("\n"); + return(0); +} + +/* + * kdb_md + * + * This function implements the 'md', 'md1', 'md2', 'md4', 'md8' + * 'mdr' and 'mds' commands. + * + * md|mds [ [ []]] + * mdWcN [ [ []]] + * where W = is the width (1, 2, 4 or 8) and N is the count. + * for eg., md1c20 reads 20 bytes, 1 at a time. + * mdr , + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_md(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + static kdb_machreg_t last_addr; + static int last_radix, last_bytesperword, last_repeat; + int radix = 16, mdcount = 8, bytesperword = sizeof(kdb_machreg_t), repeat; + int nosect = 0; + char fmtchar, fmtstr[64]; + kdb_machreg_t addr; + unsigned long word; + long offset = 0; + kdb_symtab_t symtab; + int symbolic = 0; + int valid = 0; + + kdbgetintenv("MDCOUNT", &mdcount); + kdbgetintenv("RADIX", &radix); + kdbgetintenv("BYTESPERWORD", &bytesperword); + + /* Assume 'md ' and start with environment values */ + repeat = mdcount * 16 / bytesperword; + + if (strcmp(argv[0], "mdr") == 0) { + if (argc != 2) + return KDB_ARGCOUNT; + valid = 1; + } else if (isdigit(argv[0][2])) { + bytesperword = (int)(argv[0][2] - '0'); + if (bytesperword == 0) { + bytesperword = last_bytesperword; + if (bytesperword == 0) { + bytesperword = 4; + } + } + last_bytesperword = bytesperword; + repeat = mdcount * 16 / bytesperword; + if (!argv[0][3]) + valid = 1; + else if (argv[0][3] == 'c' && argv[0][4]) { + char *p; + repeat = simple_strtoul(argv[0]+4, &p, 10); + mdcount = ((repeat * bytesperword) + 15) / 16; + valid = !*p; + } + last_repeat = repeat; + } else if (strcmp(argv[0], "md") == 0) + valid = 1; + else if (strcmp(argv[0], "mds") == 0) + valid = 1; + if (!valid) + return KDB_NOTFOUND; + + if (argc == 0) { + if (last_addr == 0) + return KDB_ARGCOUNT; + addr = last_addr; + radix = last_radix; + bytesperword = last_bytesperword; + repeat = last_repeat; + mdcount = ((repeat * bytesperword) + 15) / 16; + } + + if (argc) { + kdb_machreg_t val; + int diag, nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + if (argc > nextarg+2) + return KDB_ARGCOUNT; + + if (argc >= nextarg) { + diag = kdbgetularg(argv[nextarg], &val); + if (!diag) { + mdcount = (int) val; + repeat = mdcount * 16 / bytesperword; + } + } + if (argc >= nextarg+1) { + diag = kdbgetularg(argv[nextarg+1], &val); + if (!diag) + radix = (int) val; + } + } + + if (strcmp(argv[0], "mdr") == 0) { + return(kdb_mdr(addr, mdcount)); + } + + switch (radix) { + case 10: + fmtchar = 'd'; + break; + case 16: + fmtchar = 'x'; + break; + case 8: + fmtchar = 'o'; + break; + default: + return KDB_BADRADIX; + } + + last_radix = radix; + + if (bytesperword > sizeof(kdb_machreg_t)) + return KDB_BADWIDTH; + + switch (bytesperword) { + case 8: + sprintf(fmtstr, "%%16.16l%c ", fmtchar); + break; + case 4: + sprintf(fmtstr, "%%8.8l%c ", fmtchar); + break; + case 2: + sprintf(fmtstr, "%%4.4l%c ", fmtchar); + break; + case 1: + sprintf(fmtstr, "%%2.2l%c ", fmtchar); + break; + default: + return KDB_BADWIDTH; + } + + last_repeat = repeat; + last_bytesperword = bytesperword; + + if (strcmp(argv[0], "mds") == 0) { + symbolic = 1; + /* Do not save these changes as last_*, they are temporary mds + * overrides. + */ + bytesperword = sizeof(kdb_machreg_t); + repeat = mdcount; + kdbgetintenv("NOSECT", &nosect); + } + + /* Round address down modulo BYTESPERWORD */ + + addr &= ~(bytesperword-1); + + while (repeat > 0) { + int num = (symbolic?1 :(16 / bytesperword)); + char cbuf[32]; + char *c = cbuf; + int i; + + memset(cbuf, '\0', sizeof(cbuf)); + kdb_printf(kdb_machreg_fmt0 " ", addr); + + for(i = 0; i < num && repeat--; i++) { + if (kdb_getword(&word, addr, bytesperword)) + return 0; + + kdb_printf(fmtstr, word); + if (symbolic) { + kdbnearsym(word, &symtab); + } + else { + memset(&symtab, 0, sizeof(symtab)); + } + if (symtab.sym_name) { + kdb_symbol_print(word, &symtab, 0); + if (!nosect) { + kdb_printf("\n"); + kdb_printf(" %s %s " + kdb_machreg_fmt " " kdb_machreg_fmt " " kdb_machreg_fmt, + symtab.mod_name, + symtab.sec_name, + symtab.sec_start, + symtab.sym_start, + symtab.sym_end); + } + addr += bytesperword; + } else { +#define printable_char(addr) ({char __c = '\0'; unsigned long __addr = (addr); kdb_getarea(__c, __addr); isprint(__c) ? __c : '.';}) + switch (bytesperword) { + case 8: + *c++ = printable_char(addr++); + *c++ = printable_char(addr++); + *c++ = printable_char(addr++); + *c++ = printable_char(addr++); + case 4: + *c++ = printable_char(addr++); + *c++ = printable_char(addr++); + case 2: + *c++ = printable_char(addr++); + case 1: + *c++ = printable_char(addr++); + break; + } +#undef printable_char + } + } + kdb_printf("%*s %s\n", (int)((num-i)*(2*bytesperword + 1)+1), " ", cbuf); + } + last_addr = addr; + + return 0; +} + +/* + * kdb_mm + * + * This function implements the 'mm' command. + * + * mm address-expression new-value + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * mm works on machine words, mmW works on bytes. + */ + +int +kdb_mm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset = 0; + unsigned long contents; + int nextarg; + int width; + + if (argv[0][2] && !isdigit(argv[0][2])) + return KDB_NOTFOUND; + + if (argc < 2) { + return KDB_ARGCOUNT; + } + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + return diag; + + if (nextarg > argc) + return KDB_ARGCOUNT; + + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL, regs))) + return diag; + + if (nextarg != argc + 1) + return KDB_ARGCOUNT; + + width = argv[0][2] ? (argv[0][2] - '0') : (sizeof(kdb_machreg_t)); + if ((diag = kdb_putword(addr, contents, width))) + return(diag); + + kdb_printf(kdb_machreg_fmt " = " kdb_machreg_fmt "\n", addr, contents); + + return 0; +} + +/* + * kdb_go + * + * This function implements the 'go' command. + * + * go [address-expression] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * KDB_CMD_GO for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_go(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_machreg_t addr; + int diag; + int nextarg; + long offset; + + if (argc == 1) { + if (smp_processor_id() != kdb_initial_cpu) { + kdb_printf("go
must be issued from the initial cpu, do cpu %d first\n", kdb_initial_cpu); + return KDB_ARGCOUNT; + } + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, + &addr, &offset, NULL, regs); + if (diag) + return diag; + + kdba_setpc(regs, addr); + } else if (argc) + return KDB_ARGCOUNT; + + diag = KDB_CMD_GO; + if (smp_processor_id() != kdb_initial_cpu) { + char buf[80]; + kdb_printf("go was not issued from initial cpu, switching back to cpu %d\n", kdb_initial_cpu); + sprintf(buf, "cpu %d\n", kdb_initial_cpu); + diag = kdb_parse(buf, regs); + if (diag == KDB_CMD_CPU) + KDB_STATE_SET_CPU(GO_SWITCH, kdb_initial_cpu); + } + return diag; +} + +/* + * kdb_rd + * + * This function implements the 'rd' command. + * + * rd display all general registers. + * rd c display all control registers. + * rd d display all debug registers. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_rd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + /* + */ + + if (argc == 0) { + return kdba_dumpregs(regs, NULL, NULL); + } + + if (argc > 2) { + return KDB_ARGCOUNT; + } + + return kdba_dumpregs(regs, argv[1], argv[2]); +} + +/* + * kdb_rm + * + * This function implements the 'rm' (register modify) command. + * + * rm register-name new-contents + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Currently doesn't allow modification of control or + * debug registers, nor does it allow modification + * of model-specific registers (MSR). + */ + +int +kdb_rm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int ind = 0; + kdb_machreg_t contents; + + if (argc != 2) { + return KDB_ARGCOUNT; + } + + /* + * Allow presence or absence of leading '%' symbol. + */ + + if (argv[1][0] == '%') + ind = 1; + + diag = kdbgetularg(argv[2], &contents); + if (diag) + return diag; + + diag = kdba_setregcontents(&argv[1][ind], regs, contents); + if (diag) + return diag; + + return 0; +} + +#if defined(CONFIG_MAGIC_SYSRQ) +/* + * kdb_sr + * + * This function implements the 'sr' (SYSRQ key) command which + * interfaces to the soi-disant MAGIC SYSRQ functionality. + * + * sr + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * None. + */ +int +kdb_sr(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + if (argc != 1) { + return KDB_ARGCOUNT; + } + + handle_sysrq(*argv[1], regs, 0, 0); + + return 0; +} +#endif /* CONFIG_MAGIC_SYSRQ */ + +/* + * kdb_ef + * + * This function implements the 'regs' (display exception frame) + * command. This command takes an address and expects to find + * an exception frame at that address, formats and prints it. + * + * regs address-expression + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Not done yet. + */ + +int +kdb_ef(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset; + int nextarg; + + if (argc == 1) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + return kdba_dumpregs((struct pt_regs *)addr, NULL, NULL); + } + + return KDB_ARGCOUNT; +} + +/* + * kdb_reboot + * + * This function implements the 'reboot' command. Reboot the system + * immediately. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Shouldn't return from this function. + */ + +int +kdb_reboot(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + machine_restart(0); + /* NOTREACHED */ + return 0; +} + +#if defined(CONFIG_MODULES) +extern struct module *find_module(const char *); +extern void free_module(struct module *, int); + +/* + * kdb_lsmod + * + * This function implements the 'lsmod' command. Lists currently + * loaded kernel modules. + * + * Mostly taken from userland lsmod. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_lsmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct module *mod; + struct module_ref *mr; + + if (argc != 0) + return KDB_ARGCOUNT; + + kdb_printf("Module Size modstruct Used by\n"); + for (mod = module_list; mod && mod->next ;mod = mod->next) { + kdb_printf("%-20s%8lu 0x%p %4ld ", mod->name, mod->size, (void *)mod, + (long)atomic_read(&mod->uc.usecount)); + + if (mod->flags & MOD_DELETED) + kdb_printf(" (deleted)"); + else if (mod->flags & MOD_INITIALIZING) + kdb_printf(" (initializing)"); + else if (!(mod->flags & MOD_RUNNING)) + kdb_printf(" (uninitialized)"); + else { + if (mod->flags & MOD_AUTOCLEAN) + kdb_printf(" (autoclean)"); + if (!(mod->flags & MOD_USED_ONCE)) + kdb_printf(" (unused)"); + } + + if (mod->refs) { + kdb_printf(" [ "); + + mr = mod->refs; + while (mr) { + kdb_printf("%s ", mr->ref->name); + mr = mr->next_ref; + } + + kdb_printf("]"); + } + + kdb_printf("\n"); + } + + return 0; +} + +/* + * kdb_rmmod + * + * This function implements the 'rmmod' command. Removes a given + * kernel module. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Danger: free_module() calls mod->cleanup(). If the cleanup routine + * relies on interrupts then it will hang, kdb has interrupts disabled. + */ + +int +kdb_rmmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct module *mod; + + + if (argc != 1) + return KDB_ARGCOUNT; + + kdb_printf("Attempting to remove module: [%s]\n", argv[1]); + if ((mod = find_module(argv[1])) == NULL) { + kdb_printf("Unable to find a module by that name\n"); + return 0; + } + + if (mod->refs != NULL || __MOD_IN_USE(mod)) { + kdb_printf("Module is in use, unable to unload\n"); + return 0; + } + + free_module(mod, 0); + kdb_printf("Module successfully unloaded\n"); + + return 0; +} +#endif /* CONFIG_MODULES */ + +/* + * kdb_env + * + * This function implements the 'env' command. Display the current + * environment variables. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_env(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + + for(i=0; i<__nenv; i++) { + if (__env[i]) { + kdb_printf("%s\n", __env[i]); + } + } + + if (KDB_DEBUG(MASK)) + kdb_printf("KDBFLAGS=0x%x\n", kdb_flags); + + return 0; +} + +/* + * kdb_set + * + * This function implements the 'set' command. Alter an existing + * environment variable or create a new one. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_set(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + char *ep; + size_t varlen, vallen; + + /* + * we can be invoked two ways: + * set var=value argv[1]="var", argv[2]="value" + * set var = value argv[1]="var", argv[2]="=", argv[3]="value" + * - if the latter, shift 'em down. + */ + if (argc == 3) { + argv[2] = argv[3]; + argc--; + } + + if (argc != 2) + return KDB_ARGCOUNT; + + /* + * Check for internal variables + */ + if (strcmp(argv[1], "KDBDEBUG") == 0) { + unsigned int debugflags; + char *cp; + + debugflags = simple_strtoul(argv[2], &cp, 0); + if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) { + kdb_printf("kdb: illegal debug flags '%s'\n", + argv[2]); + return 0; + } + kdb_flags = (kdb_flags & ~(KDB_DEBUG_FLAG_MASK << KDB_DEBUG_FLAG_SHIFT)) + | (debugflags << KDB_DEBUG_FLAG_SHIFT); + + return 0; + } + + /* + * Tokenizer squashed the '=' sign. argv[1] is variable + * name, argv[2] = value. + */ + varlen = strlen(argv[1]); + vallen = strlen(argv[2]); + ep = kdballocenv(varlen + vallen + 2); + if (ep == (char *)0) + return KDB_ENVBUFFULL; + + sprintf(ep, "%s=%s", argv[1], argv[2]); + + ep[varlen+vallen+1]='\0'; + + for(i=0; i<__nenv; i++) { + if (__env[i] + && ((strncmp(__env[i], argv[1], varlen)==0) + && ((__env[i][varlen] == '\0') + || (__env[i][varlen] == '=')))) { + __env[i] = ep; + return 0; + } + } + + /* + * Wasn't existing variable. Fit into slot. + */ + for(i=0; i<__nenv-1; i++) { + if (__env[i] == (char *)0) { + __env[i] = ep; + return 0; + } + } + + return KDB_ENVFULL; +} + +/* + * kdb_dmesg + * + * This function implements the 'dmesg' command to display the contents + * of the syslog buffer. + * + * dmesg [lines] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * None. + */ + +int +kdb_dmesg(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char *syslog_data[4], *start, *end, c; + int diag, logging, logsize, lines = 0; + + if (argc > 1) + return KDB_ARGCOUNT; + if (argc) { + char *cp; + lines = simple_strtoul(argv[1], &cp, 0); + if (*cp || lines < 0) + lines = 0; + } + + /* disable LOGGING if set */ + diag = kdbgetintenv("LOGGING", &logging); + if (!diag && logging) { + const char *setargs[] = { "set", "LOGGING", "0" }; + kdb_set(2, setargs, envp, regs); + } + + /* syslog_data[0,1] physical start, end+1. syslog_data[2,3] logical start, end+1. */ + kdb_syslog_data(syslog_data); + if (syslog_data[2] == syslog_data[3]) + return 0; + logsize = syslog_data[1] - syslog_data[0]; + start = syslog_data[0] + (syslog_data[2] - syslog_data[0]) % logsize; + end = syslog_data[0] + (syslog_data[3] - syslog_data[0]) % logsize; +#define WRAP(p) if (p < syslog_data[0]) p = syslog_data[1]-1; else if (p >= syslog_data[1]) p = syslog_data[0] + if (lines) { + char *p = end; + ++lines; + do { + --p; + WRAP(p); + if (*p == '\n') { + if (--lines == 0) { + ++p; + WRAP(p); + break; + } + } + } while (p != start); + start = p; + } + /* Do a line at a time (max 200 chars) to reduce protocol overhead */ + c = '\0'; + while(1) { + char *p; + int chars = 0; + if (!*start) { + while (!*start) { + ++start; + WRAP(start); + if (start == end) + break; + } + if (start == end) + break; + } + p = start; + while (*start && chars < 200) { + c = *start; + ++chars; + ++start; + WRAP(start); + if (start == end || c == '\n') + break; + } + if (chars) + kdb_printf("%.*s", chars, p); + if (start == end) + break; + } + if (c != '\n') + kdb_printf("\n"); + + return 0; +} + +/* + * kdb_cpu + * + * This function implements the 'cpu' command. + * + * cpu [] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * KDB_CMD_CPU for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * All cpu's should be spinning in kdb(). However just in case + * a cpu did not take the smp_kdb_stop NMI, check that a cpu + * entered kdb() before passing control to it. + */ + +int +kdb_cpu(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long cpunum; + int diag, first = 1, i; + + /* ask the other cpus if they are still active */ + for (i=0; i NR_CPUS) + || !(cpu_online_map & (1UL << cpunum)) + || !KDB_STATE_CPU(KDB, cpunum)) + return KDB_BADCPUNUM; + + kdb_new_cpu = cpunum; + + /* + * Switch to other cpu + */ + return KDB_CMD_CPU; +} + +/* + * kdb_ps + * + * This function implements the 'ps' command which shows + * a list of the active processes. + * + * ps [DRSTZU] All processes, optionally filtered by state + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +void +kdb_ps1(struct task_struct *p) +{ + kdb_printf("0x%p %8d %8d %d %4d %c 0x%p %c%s\n", + (void *)p, p->pid, p->p_pptr->pid, + task_has_cpu(p), p->cpu, + (p->state == 0) ? 'R' : + (p->state < 0) ? 'U' : + (p->state & TASK_UNINTERRUPTIBLE) ? 'D' : + (p->state & TASK_STOPPED || p->ptrace & PT_PTRACED) ? 'T' : + (p->state & TASK_ZOMBIE) ? 'Z' : + (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?', + (void *)(&p->thread), + (p == current) ? '*': ' ', + p->comm); +} + +int +kdb_ps(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct task_struct *p; + unsigned long mask; + + kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n", + (int)(2*sizeof(void *))+2, "Task Addr", + (int)(2*sizeof(void *))+2, "Thread"); + mask = kdb_task_state_string(argc, argv, envp); + for_each_task(p) { + if (!kdb_task_state(p, mask)) + continue; + kdb_ps1(p); + } + + return 0; +} + +/* + * kdb_ll + * + * This function implements the 'll' command which follows a linked + * list and executes an arbitrary command for each element. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_ll(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset = 0; + kdb_machreg_t va; + unsigned long linkoffset; + int nextarg; + + if (argc != 3) { + return KDB_ARGCOUNT; + } + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + diag = kdbgetularg(argv[2], &linkoffset); + if (diag) + return diag; + + /* + * Using the starting address as + * the first element in the list, and assuming that + * the list ends with a null pointer. + */ + + va = addr; + + while (va) { + char buf[80]; + + sprintf(buf, "%s " kdb_machreg_fmt "\n", argv[3], va); + diag = kdb_parse(buf, regs); + if (diag) + return diag; + + addr = va + linkoffset; + if (kdb_getword(&va, addr, sizeof(va))) + return(0); + } + + return 0; +} + +/* + * kdb_sections_callback + * + * Invoked from kallsyms_sections for each section. + * + * Inputs: + * prevmod Previous module name + * modname Module name + * secname Section name + * secstart Start of section + * secend End of section + * secflags Section flags + * Outputs: + * None. + * Returns: + * Always zero + * Locking: + * none. + * Remarks: + */ + +static int +kdb_sections_callback(void *token, const char *modname, const char *secname, + ElfW(Addr) secstart, ElfW(Addr) secend, ElfW(Word) secflags) +{ + const char **prevmod = (const char **)token; + if (*prevmod != modname) { + *prevmod = modname; + kdb_printf("\n%s", modname); + } + kdb_printf(" %s " kdb_elfw_addr_fmt0 " " kdb_elfw_addr_fmt0 " 0x%x", + secname, secstart, secend, secflags); + return(0); +} + +/* + * kdb_sections + * + * This function implements the 'sections' command which prints the + * kernel and module sections. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_sections(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char *prev_mod = NULL; + if (argc != 0) { + return KDB_ARGCOUNT; + } + kallsyms_sections(&prev_mod, kdb_sections_callback); + kdb_printf("\n"); /* End last module */ + return(0); +} + +/* + * kdb_help + * + * This function implements the 'help' and '?' commands. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_help(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdbtab_t *kt; + + kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description"); + kdb_printf("----------------------------------------------------------\n"); + for(kt=kdb_commands; kt->cmd_name; kt++) { + kdb_printf("%-15.15s %-20.20s %s\n", kt->cmd_name, + kt->cmd_usage, kt->cmd_help); + } + return 0; +} + +/* + * kdb_register_repeat + * + * This function is used to register a kernel debugger command. + * + * Inputs: + * cmd Command name + * func Function to execute the command + * usage A simple usage string showing arguments + * help A simple help string describing command + * repeat Does the command auto repeat on enter? + * Outputs: + * None. + * Returns: + * zero for success, one if a duplicate command. + * Locking: + * none. + * Remarks: + * + */ + +#define kdb_command_extend 50 /* arbitrary */ +int +kdb_register_repeat(char *cmd, + kdb_func_t func, + char *usage, + char *help, + short minlen, + kdb_repeat_t repeat) +{ + int i; + kdbtab_t *kp; + + /* + * Brute force method to determine duplicates + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kdb_printf("Duplicate kdb command registered: '%s'\n", + cmd); + return 1; + } + } + + /* + * Insert command into first available location in table + */ + for (i=0, kp=kdb_commands; icmd_name == NULL) { + break; + } + } + + if (i >= kdb_max_commands) { + kdbtab_t *new = kmalloc((kdb_max_commands + kdb_command_extend) * sizeof(*new), GFP_KERNEL); + if (!new) { + kdb_printf("Could not allocate new kdb_command table\n"); + return 1; + } + if (kdb_commands) { + memcpy(new, kdb_commands, kdb_max_commands * sizeof(*new)); + kfree(kdb_commands); + } + memset(new + kdb_max_commands, 0, kdb_command_extend * sizeof(*new)); + kdb_commands = new; + kp = kdb_commands + kdb_max_commands; + kdb_max_commands += kdb_command_extend; + } + + kp->cmd_name = cmd; + kp->cmd_func = func; + kp->cmd_usage = usage; + kp->cmd_help = help; + kp->cmd_flags = 0; + kp->cmd_minlen = minlen; + kp->cmd_repeat = repeat; + + return 0; +} + +/* + * kdb_register + * + * Compatibility register function for commands that do not need to + * specify a repeat state. Equivalent to kdb_register_repeat with + * KDB_REPEAT_NONE. + * + * Inputs: + * cmd Command name + * func Function to execute the command + * usage A simple usage string showing arguments + * help A simple help string describing command + * Outputs: + * None. + * Returns: + * zero for success, one if a duplicate command. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_register(char *cmd, + kdb_func_t func, + char *usage, + char *help, + short minlen) +{ + return kdb_register_repeat(cmd, func, usage, help, minlen, KDB_REPEAT_NONE); +} + +/* + * kdb_unregister + * + * This function is used to unregister a kernel debugger command. + * It is generally called when a module which implements kdb + * commands is unloaded. + * + * Inputs: + * cmd Command name + * Outputs: + * None. + * Returns: + * zero for success, one command not registered. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_unregister(char *cmd) +{ + int i; + kdbtab_t *kp; + + /* + * find the command. + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kp->cmd_name = NULL; + return 0; + } + } + + /* + * Couldn't find it. + */ + return 1; +} + +/* + * kdb_inittab + * + * This function is called by the kdb_init function to initialize + * the kdb command table. It must be called prior to any other + * call to kdb_register_repeat. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +static void __init +kdb_inittab(void) +{ + int i; + kdbtab_t *kp; + initcall_t *call; + + for(i=0, kp=kdb_commands; i < kdb_max_commands; i++,kp++) { + kp->cmd_name = NULL; + } + + kdb_register_repeat("md", kdb_md, "", "Display Memory Contents, also mdWcN, e.g. md8c1", 1, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("mdr", kdb_md, " ", "Display Raw Memory", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("mds", kdb_md, "", "Display Memory Symbolically", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("mm", kdb_mm, " ", "Modify Memory Contents", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("id", kdb_id, "", "Display Instructions", 1, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("go", kdb_go, "[]", "Continue Execution", 1, KDB_REPEAT_NONE); + kdb_register_repeat("rd", kdb_rd, "", "Display Registers", 1, KDB_REPEAT_NONE); + kdb_register_repeat("rm", kdb_rm, " ", "Modify Registers", 0, KDB_REPEAT_NONE); + kdb_register_repeat("ef", kdb_ef, "", "Display exception frame", 0, KDB_REPEAT_NONE); + kdb_register_repeat("bt", kdb_bt, "[]", "Stack traceback", 1, KDB_REPEAT_NONE); + kdb_register_repeat("btp", kdb_bt, "", "Display stack for process ", 0, KDB_REPEAT_NONE); + kdb_register_repeat("bta", kdb_bt, "[DRSTZU]", "Display stack all processes", 0, KDB_REPEAT_NONE); + kdb_register_repeat("btc", kdb_bt, "", "Backtrace current process on each cpu", 0, KDB_REPEAT_NONE); + kdb_register_repeat("ll", kdb_ll, " ", "Execute cmd for each element in linked list", 0, KDB_REPEAT_NONE); + kdb_register_repeat("env", kdb_env, "", "Show environment variables", 0, KDB_REPEAT_NONE); + kdb_register_repeat("set", kdb_set, "", "Set environment variables", 0, KDB_REPEAT_NONE); + kdb_register_repeat("help", kdb_help, "", "Display Help Message", 1, KDB_REPEAT_NONE); + kdb_register_repeat("?", kdb_help, "", "Display Help Message", 0, KDB_REPEAT_NONE); + kdb_register_repeat("cpu", kdb_cpu, "","Switch to new cpu", 0, KDB_REPEAT_NONE); + kdb_register_repeat("ps", kdb_ps, "", "Display active task list", 0, KDB_REPEAT_NONE); + kdb_register_repeat("reboot", kdb_reboot, "", "Reboot the machine immediately", 0, KDB_REPEAT_NONE); + kdb_register_repeat("sections", kdb_sections, "", "List kernel and module sections", 0, KDB_REPEAT_NONE); +#if defined(CONFIG_MODULES) + kdb_register_repeat("lsmod", kdb_lsmod, "", "List loaded kernel modules", 0, KDB_REPEAT_NONE); + kdb_register_repeat("rmmod", kdb_rmmod, "", "Remove a kernel module", 0, KDB_REPEAT_NONE); +#endif +#if defined(CONFIG_MAGIC_SYSRQ) + kdb_register_repeat("sr", kdb_sr, "", "Magic SysRq key", 0, KDB_REPEAT_NONE); +#endif + kdb_register_repeat("dmesg", kdb_dmesg, "[lines]", "Display syslog buffer", 0, KDB_REPEAT_NONE); + kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"", "Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE); + + /* Any kdb commands that are not in the base code but are required + * earlier than normal initcall processing. + */ + call = &__kdb_initcall_start; + while (call < &__kdb_initcall_end) { + (*call)(); + call++; + }; +} + +/* + * kdb_cmd_init + * + * This function is called by the kdb_init function to execute any + * commands defined in kdb_cmds. + * + * Inputs: + * Commands in *kdb_cmds[]; + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +static void __init +kdb_cmd_init(void) +{ + int i, diag; + for (i = 0; kdb_cmds[i]; ++i) { + kdb_printf("kdb_cmd[%d]%s: %s", + i, defcmd_in_progress ? "[defcmd]" : "", kdb_cmds[i]); + diag = kdb_parse(kdb_cmds[i], NULL); + if (diag) + kdb_printf("command failed, kdb diag %d\n", diag); + } + if (defcmd_in_progress) { + kdb_printf("Incomplete 'defcmd' set, forcing endefcmd\n"); + kdb_parse("endefcmd", NULL); + } +} + +/* + * kdb_panic + * + * Invoked via the panic_notifier_list. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * Zero. + * Locking: + * None. + * Remarks: + * When this function is called from panic(), the other cpus have already + * been stopped. + * + */ + +static int +kdb_panic(struct notifier_block *self, unsigned long command, void *ptr) +{ + KDB_ENTER(); + return(0); +} + +static struct notifier_block kdb_block = { kdb_panic, NULL, 0 }; + +/* + * kdb_init + * + * Initialize the kernel debugger environment. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +void __init +kdb_init(void) +{ + /* + * This must be called before any calls to kdb_printf. + */ + kdb_io_init(); + + kdb_inittab(); /* Initialize Command Table */ + kdb_initbptab(); /* Initialize Breakpoint Table */ + kdb_id_init(); /* Initialize Disassembler */ + kdba_init(); /* Architecture Dependent Initialization */ + + /* + * Use printk() to get message in log_buf[]; + */ + printk("kdb version %d.%d%s by Keith Owens, Scott Lurndal. "\ + "Copyright SGI, All Rights Reserved\n", + KDB_MAJOR_VERSION, KDB_MINOR_VERSION, KDB_TEST_VERSION); + + kdb_cmd_init(); /* Preset commands from kdb_cmds */ + kdb(KDB_REASON_SILENT, 0, 0); /* Activate any preset breakpoints on boot cpu */ + notifier_chain_register(&panic_notifier_list, &kdb_block); +} + +EXPORT_SYMBOL(kdb_register); +EXPORT_SYMBOL(kdb_register_repeat); +EXPORT_SYMBOL(kdb_unregister); +EXPORT_SYMBOL(kdb_getarea_size); +EXPORT_SYMBOL(kdb_putarea_size); +EXPORT_SYMBOL(kdb_getword); +EXPORT_SYMBOL(kdb_putword); +EXPORT_SYMBOL(kdbgetularg); +EXPORT_SYMBOL(kdbgetenv); +EXPORT_SYMBOL(kdbgetintenv); +EXPORT_SYMBOL(kdbgetaddrarg); +EXPORT_SYMBOL(kdb); +EXPORT_SYMBOL(kdb_on); +EXPORT_SYMBOL(kdb_initial_cpu); +EXPORT_SYMBOL(kdbgetsymval); +EXPORT_SYMBOL(kdbnearsym); +EXPORT_SYMBOL(kdb_printf); +EXPORT_SYMBOL(kdb_symbol_print); +EXPORT_SYMBOL(kdb_notifier_list); diff -Nur linux-2.4.19/kdb/kdbsupport.c linux-2.4.19-sgi211r3/kdb/kdbsupport.c --- linux-2.4.19/kdb/kdbsupport.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/kdbsupport.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,725 @@ +/* + * Kernel Debugger Architecture Independent Support Functions + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Symbol table functions. + */ + +/* + * kdbgetsymval + * + * Return the address of the given symbol. + * + * Parameters: + * symname Character string containing symbol name + * symtab Structure to receive results + * Outputs: + * Returns: + * 0 Symbol not found, symtab zero filled + * 1 Symbol mapped to module/symbol/section, data in symtab + * Locking: + * None. + * Remarks: + */ + +int +kdbgetsymval(const char *symname, kdb_symtab_t *symtab) +{ + memset(symtab, 0, sizeof(*symtab)); + return(kallsyms_symbol_to_address( + symname, + NULL, + &symtab->mod_name, + &symtab->mod_start, + &symtab->mod_end, + &symtab->sec_name, + &symtab->sec_start, + &symtab->sec_end, + &symtab->sym_name, + &symtab->sym_start, + &symtab->sym_end)); +} + +/* + * kdbnearsym + * + * Return the name of the symbol with the nearest address + * less than 'addr'. + * + * Parameters: + * addr Address to check for symbol near + * symtab Structure to receive results + * Outputs: + * Returns: + * 0 No sections contain this address, symtab zero filled + * 1 Address mapped to module/symbol/section, data in symtab + * Locking: + * None. + * Remarks: + */ + +int +kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) +{ + int ret; + memset(symtab, 0, sizeof(*symtab)); + ret = kallsyms_address_to_symbol( + addr, + &symtab->mod_name, + &symtab->mod_start, + &symtab->mod_end, + &symtab->sec_name, + &symtab->sec_start, + &symtab->sec_end, + &symtab->sym_name, + &symtab->sym_start, + &symtab->sym_end); + if (symtab->mod_name && *symtab->mod_name == '\0') + symtab->mod_name = "kernel"; + return ret; +} + +#if defined(CONFIG_SMP) +/* + * kdb_ipi + * + * This function is called from the non-maskable interrupt + * handler to handle a kdb IPI instruction. + * + * Inputs: + * regs = Exception frame pointer + * Outputs: + * None. + * Returns: + * 0 - Did not handle NMI + * 1 - Handled NMI + * Locking: + * None. + * Remarks: + * Initially one processor is invoked in the kdb() code. That + * processor sends an ipi which drives this routine on the other + * processors. All this does is call kdb() with reason SWITCH. + * This puts all processors into the kdb() routine and all the + * code for breakpoints etc. is in one place. + * One problem with the way the kdb NMI is sent, the NMI has no + * identification that says it came from kdb. If the cpu's kdb state is + * marked as "waiting for kdb_ipi" then the NMI is treated as coming from + * kdb, otherwise it is assumed to be for another reason and is ignored. + */ + +int +kdb_ipi(struct pt_regs *regs, void (*ack_interrupt)(void)) +{ + /* Do not print before checking and clearing WAIT_IPI, IPIs are + * going all the time. + */ + if (KDB_STATE(WAIT_IPI)) { + /* + * Stopping other processors via smp_kdb_stop(). + */ + if (ack_interrupt) + (*ack_interrupt)(); /* Acknowledge the interrupt */ + KDB_STATE_CLEAR(WAIT_IPI); + KDB_DEBUG_STATE("kdb_ipi 1", 0); + kdb(KDB_REASON_SWITCH, 0, regs); /* Spin in kdb() */ + KDB_DEBUG_STATE("kdb_ipi 2", 0); + return 1; + } + return 0; +} +#endif /* CONFIG_SMP */ + +void +kdb_enablehwfault(void) +{ + kdba_enable_mce(); +} + +/* + * kdb_get_next_ar + * + * Get the next activation record from the stack. + * + * Inputs: + * arend Last byte +1 of the activation record. sp for the first + * frame, start of callee's activation record otherwise. + * func Start address of function. + * pc Current program counter within this function. pc for + * the first frame, caller's return address otherwise. + * fp Current frame pointer. Register fp for the first + * frame, oldfp otherwise. 0 if not known. + * ss Start of stack for the current process. + * Outputs: + * ar Activation record. + * symtab kallsyms symbol table data for the calling function. + * Returns: + * 1 if ar is usable, 0 if not. + * Locking: + * None. + * Remarks: + * Activation Record format, assuming a stack that grows down + * (KDB_STACK_DIRECTION == -1). + * + * +-----------------------------+ ^ ===================== + * | Return address, frame 3 | | + * +-----------------------------+ | + * | Frame Pointer, frame 3 |>--' + * +-----------------------------+<--. + * | Locals and automatics, | | + * | frame 2. (variable size) | | AR 2 + * +-----------------------------+ | + * | Save registers, | | + * | frame 2. (variable size) | | + * +-----------------------------+ | + * | Arguments to frame 1, | | + * | (variable size) | | + * +-----------------------------+ | ===================== + * | Return address, frame 2 | | + * +-----------------------------+ | + * | Frame Pointer, frame 2 |>--' + * +-----------------------------+<--. + * | Locals and automatics, | | + * | frame 1. (variable size) | | AR 1 + * +-----------------------------+ | + * | Save registers, | | + * | frame 1. (variable size) | | + * +-----------------------------+ | + * | Arguments to frame 0, | | + * | (variable size) | | + * +-----------------------------+ | -- (5) ===================== + * | Return address, frame 1 | | + * +-----------------------------+ | -- (0) + * | Frame Pointer, frame 1 |>--' + * +-----------------------------+ -- (1), (2) + * | Locals and automatics, | + * | frame 0. (variable size) | AR 0 + * +-----------------------------+ -- (3) + * | Save registers, | + * | frame 0. (variable size) | + * +-----------------------------+ -- (4) ===================== + * + * The stack for the top frame can be in one of several states. + * (0) Immediately on entry to the function, stack pointer (sp) is + * here. + * (1) If the function was compiled with frame pointers and the 'push + * fp' instruction has been executed then the pointer to the + * previous frame is on the stack. However there is no guarantee + * that this saved pointer is valid, the calling function might + * not have frame pointers. sp is adjusted by wordsize after + * 'push fp'. + * (2) If the function was compiled with frame pointers and the 'copy + * sp to fp' instruction has been executed then fp points here. + * (3) If the function startup has 'adjust sp by 0xnn bytes' and that + * instruction has been executed then sp has been adjusted by + * 0xnn bytes for local and automatic variables. + * (4) If the function startup has one or more 'push reg' instructions + * and any have been executed then sp has been adjusted by + * wordsize bytes for each register saved. + * + * As the function exits it rewinds the stack, typically to (1) then (0). + * + * The stack entries for the lower frames is normally are in state (5). + * (5) Arguments for the called frame are on to the stack. + * However lower frames can be incomplete if there is an interrupt in + * progress. + * + * An activation record runs from the return address for a function + * through to the return address for the next function or sp, whichever + * comes first. For each activation record we extract :- + * + * start Address of the activation record. + * end Address of the last byte+1 in the activation record. + * ret Return address to caller. + * oldfp Frame pointer to previous frame, 0 if this function was + * not compiled with frame pointers. + * fp Frame pointer for the current frame, 0 if this function + * was not compiled with frame pointers or fp has not been + * set yet. + * arg0 Address of the first argument (in the previous activation + * record). + * locals Bytes allocated to locals and automatics. + * regs Bytes allocated to saved registers. + * args Bytes allocated to arguments (in the previous activation + * record). + * setup Bytes allocated to setup data on stack (return address, + * frame pointer). + * + * Although the kernel might be compiled with frame pointers, we still + * have to assume the worst and validate the frame. Some calls from + * asm code to C code might not use frame pointers. Third party binary + * only modules might be compiled without frame pointers, even when the + * rest of the kernel has frame pointers. Some routines are always + * compiled with frame pointers, even if the overall kernel is not. A + * routine compiled with frame pointers can be called from a routine + * without frame pointers, the previous "frame pointer" is saved on + * stack but it contains garbage. + * + * We check the object code to see if it saved a frame pointer and we + * validate that pointer. Basically frame pointers are hints. + */ + +#define FORCE_ARG(ar,n) (ar)->setup = (ar)->locals = (ar)->regs = \ + (ar)->fp = (ar)->oldfp = (ar)->ret = 0; \ + (ar)->start = (ar)->end - KDB_STACK_DIRECTION*(n)*sizeof(unsigned long); + +int +kdb_get_next_ar(kdb_machreg_t arend, kdb_machreg_t func, + kdb_machreg_t pc, kdb_machreg_t fp, kdb_machreg_t ss, + kdb_ar_t *ar, kdb_symtab_t *symtab) +{ + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: arend=0x%lx func=0x%lx pc=0x%lx fp=0x%lx\n", + arend, func, pc, fp); + } + + memset(ar, 0, sizeof(*ar)); + if (!kdbnearsym(pc, symtab)) { + symtab->sym_name = symtab->sec_name = ""; + symtab->mod_name = "kernel"; + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee not in kernel\n"); + } + pc = 0; + } + + if (!kdba_prologue(symtab, pc, arend, fp, ss, 0, ar)) { + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee prologue failed\n"); + } + return(0); + } + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee activation record\n"); + kdb_printf(" start=0x%lx end=0x%lx ret=0x%lx oldfp=0x%lx fp=0x%lx\n", + ar->start, ar->end, ar->ret, ar->oldfp, ar->fp); + kdb_printf(" locals=%ld regs=%ld setup=%ld\n", + ar->locals, ar->regs, ar->setup); + } + + if (ar->ret) { + /* Run the caller code to get arguments to callee function */ + kdb_symtab_t caller_symtab; + kdb_ar_t caller_ar; + memset(&caller_ar, 0, sizeof(caller_ar)); + if (!kdbnearsym(ar->ret, &caller_symtab)) { + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller not in kernel\n"); + } + } else if (kdba_prologue(&caller_symtab, ar->ret, + ar->start, ar->oldfp, ss, 1, &caller_ar)) { + /* some caller data extracted */ ; + } else if (strcmp(symtab->sym_name, "do_exit") == 0) { + /* non-standard caller, force one argument */ + FORCE_ARG(&caller_ar, 1); + } else if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller prologue failed\n"); + } + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller activation record\n"); + kdb_printf(" start=0x%lx end=0x%lx ret=0x%lx" + " oldfp=0x%lx fp=0x%lx\n", + caller_ar.start, caller_ar.end, caller_ar.ret, + caller_ar.oldfp, caller_ar.fp); + kdb_printf(" locals=%ld regs=%ld args=%ld setup=%ld\n", + caller_ar.locals, caller_ar.regs, + caller_ar.args, caller_ar.setup); + } + if (caller_ar.start) { + ar->args = KDB_STACK_DIRECTION*(caller_ar.end - caller_ar.start) - + (caller_ar.setup + caller_ar.locals + caller_ar.regs); + if (ar->args < 0) + ar->args = 0; + if (ar->args) { + ar->arg0 = ar->start - + KDB_STACK_DIRECTION*(ar->args - 4); + if (KDB_DEBUG(AR)) { + kdb_printf(" callee arg0=0x%lx args=%ld\n", + ar->arg0, ar->args); + } + } + } + } + + return(1); +} + +/* + * kdb_symbol_print + * + * Standard method for printing a symbol name and offset. + * Inputs: + * addr Address to be printed. + * symtab Address of symbol data, if NULL this routine does its + * own lookup. + * punc Punctuation for string, bit field. + * Outputs: + * None. + * Returns: + * Always 0. + * Locking: + * none. + * Remarks: + * The string and its punctuation is only printed if the address + * is inside the kernel, except that the value is always printed + * when requested. + */ + +void +kdb_symbol_print(kdb_machreg_t addr, const kdb_symtab_t *symtab_p, unsigned int punc) +{ + kdb_symtab_t symtab, *symtab_p2; + if (symtab_p) { + symtab_p2 = (kdb_symtab_t *)symtab_p; + } + else { + symtab_p2 = &symtab; + kdbnearsym(addr, symtab_p2); + } + if (symtab_p2->sym_name || (punc & KDB_SP_VALUE)) { + ; /* drop through */ + } + else { + return; + } + if (punc & KDB_SP_SPACEB) { + kdb_printf(" "); + } + if (punc & KDB_SP_VALUE) { + kdb_printf(kdb_machreg_fmt0, addr); + } + if (!symtab_p2->sym_name) { + return; + } + if (punc & KDB_SP_VALUE) { + kdb_printf(" "); + } + if (punc & KDB_SP_PAREN) { + kdb_printf("("); + } + if (strcmp(symtab_p2->mod_name, "kernel")) { + kdb_printf("[%s]", symtab_p2->mod_name); + } + kdb_printf("%s", symtab_p2->sym_name); + if (addr != symtab_p2->sym_start) { + kdb_printf("+0x%lx", addr - symtab_p2->sym_start); + } + if (punc & KDB_SP_SYMSIZE) { + kdb_printf("/0x%lx", symtab_p2->sym_end - symtab_p2->sym_start); + } + if (punc & KDB_SP_PAREN) { + kdb_printf(")"); + } + if (punc & KDB_SP_SPACEA) { + kdb_printf(" "); + } + if (punc & KDB_SP_NEWLINE) { + kdb_printf("\n"); + } +} + +/* + * kdb_strdup + * + * kdb equivalent of strdup, for disasm code. + * Inputs: + * str The string to duplicate. + * type Flags to kmalloc for the new string. + * Outputs: + * None. + * Returns: + * Address of the new string, NULL if storage could not be allocated. + * Locking: + * none. + * Remarks: + * This is not in lib/string.c because it uses kmalloc which is not + * available when string.o is used in boot loaders. + */ + +char *kdb_strdup(const char *str, int type) +{ + int n = strlen(str)+1; + char *s = kmalloc(n, type); + if (!s) return NULL; + return strcpy(s, str); +} + +/* + * kdb_getarea_size + * + * Read an area of data. The kdb equivalent of copy_from_user, with + * kdb messages for invalid addresses. + * Inputs: + * res Pointer to the area to receive the result. + * addr Address of the area to copy. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_getarea_size(void *res, unsigned long addr, size_t size) +{ + int ret = kdba_getarea_size(res, addr, size); + if (ret) { + if (!KDB_STATE(SUPPRESS)) { + kdb_printf("kdb_getarea: Bad address 0x%lx\n", addr); + KDB_STATE_SET(SUPPRESS); + } + ret = KDB_BADADDR; + } + else { + KDB_STATE_CLEAR(SUPPRESS); + } + return(ret); +} + +/* + * kdb_putarea_size + * + * Write an area of data. The kdb equivalent of copy_to_user, with + * kdb messages for invalid addresses. + * Inputs: + * addr Address of the area to write to. + * res Pointer to the area holding the data. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_putarea_size(unsigned long addr, void *res, size_t size) +{ + int ret = kdba_putarea_size(addr, res, size); + if (ret) { + if (!KDB_STATE(SUPPRESS)) { + kdb_printf("kdb_putarea: Bad address 0x%lx\n", addr); + KDB_STATE_SET(SUPPRESS); + } + ret = KDB_BADADDR; + } + else { + KDB_STATE_CLEAR(SUPPRESS); + } + return(ret); +} + +/* + * kdb_getword + * + * Read a binary value. Unlike kdb_getarea, this treats data as numbers. + * Inputs: + * word Pointer to the word to receive the result. + * addr Address of the area to copy. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_getword(unsigned long *word, unsigned long addr, size_t size) +{ + int diag; + __u8 w1; + __u16 w2; + __u32 w4; + __u64 w8; + *word = 0; /* Default value if addr or size is invalid */ + switch (size) { + case 1: + if (!(diag = kdb_getarea(w1, addr))) + *word = w1; + break; + case 2: + if (!(diag = kdb_getarea(w2, addr))) + *word = w2; + break; + case 4: + if (!(diag = kdb_getarea(w4, addr))) + *word = w4; + break; + case 8: + if (size <= sizeof(*word)) { + if (!(diag = kdb_getarea(w8, addr))) + *word = w8; + break; + } + /* drop through */ + default: + diag = KDB_BADWIDTH; + kdb_printf("kdb_getword: bad width %ld\n", (long) size); + } + return(diag); +} + +/* + * kdb_putword + * + * Write a binary value. Unlike kdb_putarea, this treats data as numbers. + * Inputs: + * addr Address of the area to write to.. + * word The value to set. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_putword(unsigned long addr, unsigned long word, size_t size) +{ + int diag; + __u8 w1; + __u16 w2; + __u32 w4; + __u64 w8; + switch (size) { + case 1: + w1 = word; + diag = kdb_putarea(addr, w1); + break; + case 2: + w2 = word; + diag = kdb_putarea(addr, w2); + break; + case 4: + w4 = word; + diag = kdb_putarea(addr, w4); + break; + case 8: + if (size <= sizeof(word)) { + w8 = word; + diag = kdb_putarea(addr, w8); + break; + } + /* drop through */ + default: + diag = KDB_BADWIDTH; + kdb_printf("kdb_putword: bad width %ld\n", (long) size); + } + return(diag); +} + +/* + * kdb_task_state_string + * + * Convert a string containing any of the letters DRSTZU to a mask for + * the process state field and return the value. If no argument is + * supplied, return ~0. + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * Outputs: + * none. + * Returns: + * Mask for process state. + * Locking: + * none. + */ + +#define UNRUNNABLE (1UL << (8*sizeof(unsigned long) - 1)) /* unrunnable is < 0 */ +#define RUNNING (1UL << (8*sizeof(unsigned long) - 2)) +#define TRACED (1UL << (8*sizeof(unsigned long) - 3)) + +unsigned long +kdb_task_state_string(int argc, const char **argv, const char **envp) +{ + long res = ~0; + if (argc >= 1) { + const char *s = argv[1]; + res = 0; + while (*s) { + switch (*s) { + case 'D': res |= TASK_UNINTERRUPTIBLE; break; + case 'R': res |= RUNNING; break; + case 'S': res |= TASK_INTERRUPTIBLE; break; + case 'T': res |= TASK_STOPPED | TRACED; break; + case 'Z': res |= TASK_ZOMBIE; break; + case 'U': res |= UNRUNNABLE; break; + default: + kdb_printf("kdb_task_state unknown flag '%c' ignored\n", *s); + break; + } + ++s; + } + } + return res; +} + +/* + * kdb_task_state + * + * Return true if a process has the desired state given by the mask. + * Inputs: + * p struct task for the process + * mask mask from kdb_task_state_string to select processes + * Outputs: + * none. + * Returns: + * True if the process matches at least one criteria defined by the mask. + * Locking: + * none. + */ + +unsigned long +kdb_task_state(const struct task_struct *p, unsigned long mask) +{ + return ((mask & p->state) || + (mask & RUNNING && p->state == 0) || + (mask & TRACED && p->ptrace & PT_PTRACED)); +} diff -Nur linux-2.4.19/kdb/modules/Makefile linux-2.4.19-sgi211r3/kdb/modules/Makefile --- linux-2.4.19/kdb/modules/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/modules/Makefile Sun Feb 9 19:17:26 2003 @@ -0,0 +1,39 @@ +# +# Copyright (c) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +O_TARGET := vmlinux-obj.o +obj-$(CONFIG_KDB_MODULES) += kdbm_vm.o kdbm_pg.o kdbm_task.o +CFLAGS_kdbm_vm.o += -I $(TOPDIR)/drivers/scsi + +EXTRA_CFLAGS += -I $(TOPDIR)/arch/$(ARCH)/kdb + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/kdb/modules/kdbm_pg.c linux-2.4.19-sgi211r3/kdb/modules/kdbm_pg.c --- linux-2.4.19/kdb/modules/kdbm_pg.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/modules/kdbm_pg.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,588 @@ +/* + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug page information"); +MODULE_LICENSE("GPL"); + +/* Standard Linux page stuff */ + +static char *pg_flag_vals[] = { + "PG_locked", "PG_error", "PG_referenced", "PG_uptodate", + "PG_dirty", "PG_unused_5", "PG_lru", "PG_active", + "PG_slab", "PG_unused_9", "PG_skip", "PG_highmem", + "PG_checked", "PG_arch_1", "PG_reserved", "PG_launder", + NULL }; + +static char *bh_state_vals[] = { + "Uptodate", "Dirty", "Lock", "Req", + "Mapped", "New", "Async", "Wait_IO", + "Launder", "JBD", + /*XFS*/ "Delay", + "Private", + NULL }; + +static char *inode_flag_vals[] = { + "I_DIRTY_SYNC", "I_DIRTY_DATASYNC", "I_DIRTY_PAGES", "I_LOCK", + "I_FREEING", "I_CLEAR", + /*XFS*/ "I_NEW", + NULL }; + +static char *map_flags(unsigned long flags, char *mapping[]) +{ + static char buffer[256]; + int index; + int offset = 12; + + buffer[0] = '\0'; + + for (index = 0; flags && mapping[index]; flags >>= 1, index++) { + if (flags & 1) { + if ((offset + strlen(mapping[index]) + 1) >= 80) { + strcat(buffer, "\n "); + offset = 12; + } else if (offset > 12) { + strcat(buffer, " "); + offset++; + } + strcat(buffer, mapping[index]); + offset += strlen(mapping[index]); + } + } + + return (buffer); +} + +static char *page_flags(unsigned long flags) +{ + return(map_flags(flags, pg_flag_vals)); +} + +static int +kdbm_buffers(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct buffer_head bh; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(bh, addr))) + return(diag); + + kdb_printf("buffer_head at 0x%lx\n", addr); + kdb_printf(" next 0x%p bno %ld rsec %ld size %d dev 0x%x rdev 0x%x\n", + bh.b_next, bh.b_blocknr, bh.b_rsector, + bh.b_size, bh.b_dev, bh.b_rdev); + kdb_printf(" count %d state 0x%lx [%s] ftime 0x%lx b_list %d\n", + bh.b_count.counter, bh.b_state, map_flags(bh.b_state, bh_state_vals), + bh.b_flushtime, bh.b_list); + kdb_printf(" b_next_free 0x%p b_prev_free 0x%p b_reqnext 0x%p b_data 0x%p\n", + bh.b_next_free, bh.b_prev_free, bh.b_reqnext, bh.b_data); + kdb_printf(" b_page 0x%p b_this_page 0x%p b_private 0x%p\n", + bh.b_page, bh.b_this_page, bh.b_private); + + return 0; +} + +static int +kdbm_page(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct page page; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + if (addr < PAGE_OFFSET) + addr = (unsigned long) &mem_map[addr]; + + if ((diag = kdb_getarea(page, addr))) + return(diag); + + kdb_printf("struct page at 0x%lx\n", addr); + kdb_printf(" next 0x%p prev 0x%p addr space 0x%p index %lu (offset 0x%x)\n", + page.list.next, page.list.prev, page.mapping, page.index, + (int)(page.index << PAGE_CACHE_SHIFT)); + kdb_printf(" count %d flags %s\n", + page.count.counter, page_flags(page.flags)); + kdb_printf(" virtual 0x%p\n", page_address((struct page *)addr)); + if (page.buffers) + kdb_printf(" buffers 0x%p\n", page.buffers); + + return 0; +} + +unsigned long +print_request(unsigned long addr) +{ + struct request rq; + + if (kdb_getarea(rq, addr)) + return(0); + + kdb_printf("struct request at 0x%lx\n", addr); + kdb_printf(" rq_dev 0x%x cmd %d errors %d sector %ld nr_sectors %ld\n", + rq.rq_dev, rq.cmd, rq.errors, rq.sector, + rq.nr_sectors); + + kdb_printf(" hsect %ld hnrsect %ld nrseg %d nrhwseg %d currnrsect %ld seq %d\n", + rq.hard_sector, rq.hard_nr_sectors, + rq.nr_segments, rq.nr_hw_segments, + rq.current_nr_sectors, rq.elevator_sequence); + kdb_printf(" "); + kdb_printf("bh 0x%p bhtail 0x%p req_q 0x%p\n\n", + rq.bh, rq.bhtail, rq.q); + + return (unsigned long) rq.queue.next; +} + +static int +kdbm_request(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + long offset=0; + unsigned long addr; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + print_request(addr); + return 0; +} + + +static int +kdbm_rqueue(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct request_queue rq; + unsigned long addr, head_addr, next; + long offset=0; + int nextarg; + int i, diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(rq, addr))) + return(diag); + + kdb_printf("struct request_queue at 0x%lx [%s]\n", addr, + rq.plugged ? "plugged" : "running"); + kdb_printf(" read free_list [0x%p, 0x%p]\n", + rq.rq[READ].free.prev, + rq.rq[READ].free.next); + kdb_printf(" write free_list [0x%p, 0x%p]\n", + rq.rq[WRITE].free.prev, + rq.rq[WRITE].free.next); + + i = 0; + next = (unsigned long)rq.queue_head.next; + head_addr = addr + offsetof(struct request_queue, queue_head); + kdb_printf(" request queue: %s\n", next == head_addr ? + "empty" : ""); + while (next != head_addr) { + i++; + next = print_request(next); + } + + if (i) + kdb_printf("%d requests found\n", i); + + return 0; +} + + +static void +do_buffer(unsigned long addr) +{ + struct buffer_head bh; + + if (kdb_getarea(bh, addr)) + return; + + kdb_printf("bh 0x%lx bno %8ld [%s]\n", addr, bh.b_blocknr, + map_flags(bh.b_state, bh_state_vals)); +} + +static int +kdbm_inode_pages(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct inode *inode = NULL; + struct address_space *ap = NULL; + unsigned long addr, addr1 = 0; + long offset=0; + int nextarg; + int diag; + int which=0; + + struct list_head *head, *curr; + + if (argc < 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + goto out; + + if (argc == 2) { + nextarg = 2; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr1, + &offset, NULL, regs); + if (diag) + goto out; + kdb_printf("Looking for page index 0x%lx ... \n", addr1); + } + + if (!(inode = kmalloc(sizeof(*inode), GFP_ATOMIC))) { + kdb_printf("kdbm_inode_pages: cannot kmalloc inode\n"); + goto out; + } + if (!(ap = kmalloc(sizeof(*ap), GFP_ATOMIC))) { + kdb_printf("kdbm_inode_pages: cannot kmalloc ap\n"); + goto out; + } + if ((diag = kdb_getarea(*inode, addr))) + goto out; + if (!inode->i_mapping) { + kdb_printf("inode has no mapping\n"); + goto out; + } + if ((diag = kdb_getarea(*ap, (unsigned long) inode->i_mapping))) + goto out; + + again: + if (which == 0){ + which=1; + head = &inode->i_mapping->clean_pages; + kdb_printf("CLEAN page_struct index cnt flags\n"); + } else if (which == 1) { + which=2; + head = &inode->i_mapping->dirty_pages; + kdb_printf("DIRTY page_struct index cnt flags\n"); + } else if (which == 2) { + which=3; + head = &inode->i_mapping->locked_pages; + kdb_printf("LOCKED page_struct index cnt flags\n"); + } else { + goto out; + } + + curr = head->next; + while (curr != head) { + struct page page; + struct list_head curr_struct; + + addr = (unsigned long) list_entry(curr, struct page, list); + if ((diag = kdb_getarea(page, addr))) + goto out; + + if (!addr1 || page.index == addr1 || + (addr1 == -1 && (page.flags & ( 1 << PG_locked)))) + { + kdb_printf(" 0x%lx %6lu %5d 0x%lx ", + addr, page.index, page.count.counter, + page.flags); + if (page.buffers) + do_buffer((unsigned long) page.buffers); + else + kdb_printf("bh [NULL]\n"); + } + + if ((diag = kdb_getarea(curr_struct, (unsigned long) curr))) + goto out; + + curr = curr_struct.next; + } + goto again; + out: + if (inode) + kfree(inode); + if (ap) + kfree(ap); + return diag; +} + +static int +kdbm_inode(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct inode *inode = NULL; + unsigned long addr; + unsigned char *iaddr; + long offset=0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(inode = kmalloc(sizeof(*inode), GFP_ATOMIC))) { + kdb_printf("kdbm_inode: cannot kmalloc inode\n"); + goto out; + } + if ((diag = kdb_getarea(*inode, addr))) + goto out; + + kdb_printf("struct inode at 0x%lx\n", addr); + + kdb_printf(" i_ino = %lu i_count = %u i_dev = 0x%x i_size %Ld\n", + inode->i_ino, atomic_read(&inode->i_count), + inode->i_dev, inode->i_size); + + kdb_printf(" i_mode = 0%o i_nlink = %d i_rdev = 0x%x\n", + inode->i_mode, inode->i_nlink, + inode->i_rdev); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + inode->i_hash.next, inode->i_hash.prev); + + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + inode->i_list.next, inode->i_list.prev); + + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + inode->i_dentry.next, + inode->i_dentry.prev); + + kdb_printf(" i_dirty_buffers.nxt = 0x%p i_dirty_buffers.prv = 0x%p\n", + inode->i_dirty_buffers.next, + inode->i_dirty_buffers.prev); + + kdb_printf(" i_sb = 0x%p i_op = 0x%p i_data = 0x%lx nrpages = %lu\n", + inode->i_sb, inode->i_op, + addr + offsetof(struct inode, i_data), + inode->i_data.nrpages); + kdb_printf(" i_mapping = 0x%p\n i_flags 0x%x i_state 0x%lx [%s]", + inode->i_mapping, inode->i_flags, + inode->i_state, + map_flags(inode->i_state, inode_flag_vals)); + + iaddr = (char *)addr; + iaddr += offsetof(struct inode, u); + + kdb_printf(" fs specific info @ 0x%p\n", iaddr); +out: + if (inode) + kfree(inode); + return diag; +} + +static int +kdbm_kiobuf(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct kiobuf *kiobuf = NULL; + struct page page; + struct page **page_array = NULL; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(kiobuf = kmalloc(sizeof(*kiobuf), GFP_ATOMIC))) { + kdb_printf("kdbm_kiobuf: cannot kmalloc kiobuf\n"); + goto out; + } + if ((diag = kdb_getarea(*kiobuf, addr))) + goto out; + + kdb_printf("kiobuf at 0x%lx\n", addr); + kdb_printf(" nr_pages %d array_len %d offset 0x%x length 0x%x\n", + kiobuf->nr_pages, kiobuf->array_len, + kiobuf->offset, kiobuf->length); + kdb_printf(" errno %d\n", kiobuf->errno); + kdb_printf(" page_struct page_addr cnt flags\n"); + if (kiobuf->maplist != (((struct kiobuf *)addr)->map_array)) { + int s = kiobuf->nr_pages*sizeof(*page_array); + if (!(page_array = kmalloc(s, GFP_ATOMIC))) { + kdb_printf("kdbm_kiobuf: cannot kmalloc page_array\n"); + goto out; + } + if ((diag = kdb_getarea_size(page_array, (unsigned long)kiobuf->maplist, s))) + goto out; + kiobuf->maplist = page_array; + } + for (i = 0; i < kiobuf->nr_pages; i++) { + if ((diag = kdb_getarea(page, (unsigned long) kiobuf->maplist[i]))) + goto out; + kdb_printf(" 0x%p", kiobuf->maplist[i]); + kdb_printf(" 0x%p", page_address(kiobuf->maplist[i])); + kdb_printf(" %d 0x%lx\n", page.count.counter, page.flags); + } +out: + if (kiobuf) + kfree(kiobuf); + if (page_array) + kfree(page_array); + return diag; +} + +static int +kdbm_memmap(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct page page; + int i, page_count; + int slab_count = 0; + int dirty_count = 0; + int locked_count = 0; + int page_counts[9]; + int buffered_count = 0; +#ifdef buffer_delay + int delay_count = 0; +#endif + int diag; + unsigned long addr; + + addr = (unsigned long)mem_map; + page_count = max_mapnr; + memset(page_counts, 0, sizeof(page_counts)); + + for (i = 0; i < page_count; i++) { + if ((diag = kdb_getarea(page, addr))) + return(diag); + addr += sizeof(page); + + if (PageSlab(&page)) + slab_count++; + if (PageDirty(&page)) + dirty_count++; + if (PageLocked(&page)) + locked_count++; + if (page.count.counter < 8) + page_counts[page.count.counter]++; + else + page_counts[8]++; + if (page.buffers) { + buffered_count++; +#ifdef buffer_delay + if (buffer_delay(page.buffers)) + delay_count++; +#endif + } + + } + + kdb_printf(" Total pages: %6d\n", page_count); + kdb_printf(" Slab pages: %6d\n", slab_count); + kdb_printf(" Dirty pages: %6d\n", dirty_count); + kdb_printf(" Locked pages: %6d\n", locked_count); + kdb_printf(" Buffer pages: %6d\n", buffered_count); +#ifdef buffer_delay + kdb_printf(" Delalloc pages: %6d\n", delay_count); +#endif + for (i = 0; i < 8; i++) { + kdb_printf(" %d page count: %6d\n", + i, page_counts[i]); + } + kdb_printf(" high page count: %6d\n", page_counts[8]); + return 0; +} + +static int __init kdbm_pg_init(void) +{ + kdb_register("kiobuf", kdbm_kiobuf, "", "Display kiobuf", 0); + kdb_register("page", kdbm_page, "", "Display page", 0); + kdb_register("inode", kdbm_inode, "", "Display inode", 0); + kdb_register("bh", kdbm_buffers, "", "Display buffer", 0); + kdb_register("inode_pages", kdbm_inode_pages, "", "Display pages in an inode", 0); + kdb_register("req", kdbm_request, "", "dump request struct", 0); + kdb_register("rqueue", kdbm_rqueue, "", "dump request queue", 0); + kdb_register("memmap", kdbm_memmap, "", "page table summary", 0); + + return 0; +} + + +static void __exit kdbm_pg_exit(void) +{ + kdb_unregister("kiobuf"); + kdb_unregister("page"); + kdb_unregister("inode"); + kdb_unregister("bh"); + kdb_unregister("inode_pages"); + kdb_unregister("req"); + kdb_unregister("rqueue"); + kdb_unregister("memmap"); +} + +module_init(kdbm_pg_init) +module_exit(kdbm_pg_exit) diff -Nur linux-2.4.19/kdb/modules/kdbm_task.c linux-2.4.19-sgi211r3/kdb/modules/kdbm_task.c --- linux-2.4.19/kdb/modules/kdbm_task.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/modules/kdbm_task.c Sun Feb 9 19:17:26 2003 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug struct task and sigset information"); +MODULE_LICENSE("GPL"); + +static int +kdbm_task(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long addr; + long offset=0; + int nextarg; + int e = 0; + struct task_struct *tp = NULL; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((e = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) != 0) + return(e); + + if (!(tp = kmalloc(sizeof(*tp), GFP_ATOMIC))) { + kdb_printf("%s: cannot kmalloc tp\n", __FUNCTION__); + goto out; + } + if ((e = kdb_getarea(*tp, addr))) { + kdb_printf("%s: invalid task address\n", __FUNCTION__); + goto out; + } + + kdb_printf( + "struct task at 0x%p, pid=%d flags=0x%lx state=%ld comm=\"%s\"\n", + tp, tp->pid, tp->flags, tp->state, tp->comm); + + kdb_printf( + " cpu=%d prio=%d static_prio=%d cpus_allowed=0x%016lx &thread=0x%p\n", + tp->cpu, + tp->prio, tp->static_prio, tp->cpus_allowed, &tp->thread); + + kdb_printf( + " need_resched=%ld sleep_timestamp=%lu time_slice=%u lock_depth=%d\n", + tp->need_resched, tp->sleep_timestamp, tp->time_slice, tp->lock_depth); + + kdb_printf( + " fs=0x%p files=0x%p mm=0x%p nr_local_pages=%u\n", + tp->fs, tp->files, tp->mm, tp->nr_local_pages); + + kdb_printf( + " uid=%d euid=%d suid=%d fsuid=%d gid=%d egid=%d sgid=%d fsgid=%d\n", + tp->uid, tp->euid, tp->suid, tp->fsuid, tp->gid, tp->egid, tp->sgid, tp->fsgid); + + kdb_printf( + " user=0x%p locks=%d semundo=0x%p semsleeping=0x%p\n", + tp->user, tp->locks, tp->semundo, tp->semsleeping); + + kdb_printf( + " sig=0x%p &blocked=0x%p &sigpending=0x%p\n", + tp->sig, &tp->blocked, &tp->sigpending); + + kdb_printf( + " times.utime=%ld times_stime=%ld times_cutime=%ld times_cstime=%ld\n", + tp->times.tms_utime, tp->times.tms_stime, tp->times.tms_cutime, + tp->times.tms_cstime); + +out: + if (tp) + kfree(tp); + return e; +} + +static int +kdbm_sigset(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + sigset_t *sp = NULL; + unsigned long addr; + long offset=0; + int nextarg; + int e = 0; + int i; + char fmt[32]; + + if (argc != 1) + return KDB_ARGCOUNT; + +#ifndef _NSIG_WORDS + kdb_printf("unavailable on this platform, _NSIG_WORDS not defined.\n"); +#else + nextarg = 1; + if ((e = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) != 0) + return(e); + + if (!(sp = kmalloc(sizeof(*sp), GFP_ATOMIC))) { + kdb_printf("%s: cannot kmalloc sp\n", __FUNCTION__); + goto out; + } + if ((e = kdb_getarea(*sp, addr))) { + kdb_printf("%s: invalid sigset address\n", __FUNCTION__); + goto out; + } + + sprintf(fmt, "[%%d]=0x%%0%dlx ", (int)sizeof(sp->sig[0])*2); + kdb_printf("sigset at 0x%p : ", sp); + for (i=_NSIG_WORDS-1; i >= 0; i--) { + if (i == 0 || sp->sig[i]) { + kdb_printf(fmt, i, sp->sig[i]); + } + } + kdb_printf("\n"); +#endif /* _NSIG_WORDS */ + +out: + if (sp) + kfree(sp); + return e; +} + +static int __init kdbm_task_init(void) +{ + kdb_register("task", kdbm_task, "", "Display task_struct", 0); + kdb_register("sigset", kdbm_sigset, "", "Display sigset_t", 0); + + return 0; +} + +static void __exit kdbm_task_exit(void) +{ + kdb_unregister("task"); + kdb_unregister("sigset"); +} + +kdb_module_init(kdbm_task_init) +kdb_module_exit(kdbm_task_exit) diff -Nur linux-2.4.19/kdb/modules/kdbm_vm.c linux-2.4.19-sgi211r3/kdb/modules/kdbm_vm.c --- linux-2.4.19/kdb/modules/kdbm_vm.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kdb/modules/kdbm_vm.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,477 @@ +/* + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug VM information"); +MODULE_LICENSE("GPL"); + +struct __vmflags { + unsigned long mask; + char *name; +} vmflags[] = { + { VM_READ, "READ" }, + { VM_WRITE, "WRITE" }, + { VM_EXEC, "EXEC" }, + { VM_SHARED, "SHARED" }, + { VM_MAYREAD, "MAYREAD" }, + { VM_MAYWRITE, "MAYWRITE" }, + { VM_MAYEXEC, "MAYEXEC" }, + { VM_MAYSHARE, "MAYSHARE" }, + { VM_GROWSDOWN, "GROWSDOWN" }, + { VM_GROWSUP, "GROWSUP" }, + { VM_SHM, "SHM" }, + { VM_DENYWRITE, "DENYWRITE" }, + { VM_EXECUTABLE, "EXECUTABLE" }, + { VM_LOCKED, "LOCKED" }, + { VM_IO , "IO " }, + { 0, "" } +}; + +static int +kdbm_vm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct vm_area_struct vp; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + struct __vmflags *tp; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(vp, addr))) + return(diag); + + kdb_printf("struct vm_area_struct at 0x%lx for %d bytes\n", + addr, (int)sizeof(struct vm_area_struct)); + kdb_printf("vm_start = 0x%lx vm_end = 0x%lx\n", vp.vm_start, vp.vm_end); + kdb_printf("page_prot = 0x%lx\n", pgprot_val(vp.vm_page_prot)); + kdb_printf("flags: "); + for(tp=vmflags; tp->mask; tp++) { + if (vp.vm_flags & tp->mask) { + kdb_printf("%s ", tp->name); + } + } + kdb_printf("\n"); + + return 0; +} + +static int +kdbm_fp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct file f; + struct inode *i = NULL; + struct dentry d; + int nextarg; + unsigned long addr; + long offset; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(f, addr)) || + (diag = kdb_getarea(d, (unsigned long)f.f_dentry))) + goto out; + if (!(i = kmalloc(sizeof(*i), GFP_ATOMIC))) { + kdb_printf("kdbm_fp: cannot kmalloc inode\n"); + goto out; + } + if ((diag = kdb_getarea(i, (unsigned long)d.d_inode))) + goto out; + + kdb_printf("name.name 0x%p name.len %d\n", + d.d_name.name, d.d_name.len); + + kdb_printf("File Pointer at 0x%lx\n", addr); + + kdb_printf(" f_list.nxt = 0x%p f_list.prv = 0x%p\n", + f.f_list.next, f.f_list.prev); + + kdb_printf(" f_dentry = 0x%p f_op = 0x%p\n", + f.f_dentry, f.f_op); + + kdb_printf(" f_count = %d f_flags = 0x%x f_mode = 0x%x\n", + f.f_count.counter, f.f_flags, f.f_mode); + + kdb_printf(" f_pos = %Ld f_reada = %ld f_ramax = %ld\n", + f.f_pos, f.f_reada, f.f_ramax); + + kdb_printf(" f_raend = %ld f_ralen = %ld f_rawin = %ld\n\n", + f.f_raend, f.f_ralen, f.f_rawin); + + + kdb_printf("\nDirectory Entry at 0x%p\n", f.f_dentry); + kdb_printf(" d_name.len = %d d_name.name = 0x%p>\n", + d.d_name.len, d.d_name.name); + + kdb_printf(" d_count = %d d_flags = 0x%x d_inode = 0x%p\n", + atomic_read(&d.d_count), d.d_flags, d.d_inode); + + kdb_printf(" d_hash.nxt = 0x%p d_hash.prv = 0x%p\n", + d.d_hash.next, d.d_hash.prev); + + kdb_printf(" d_lru.nxt = 0x%p d_lru.prv = 0x%p\n", + d.d_lru.next, d.d_lru.prev); + + kdb_printf(" d_child.nxt = 0x%p d_child.prv = 0x%p\n", + d.d_child.next, d.d_child.prev); + + kdb_printf(" d_subdirs.nxt = 0x%p d_subdirs.prv = 0x%p\n", + d.d_subdirs.next, d.d_subdirs.prev); + + kdb_printf(" d_alias.nxt = 0x%p d_alias.prv = 0x%p\n", + d.d_alias.next, d.d_alias.prev); + + kdb_printf(" d_op = 0x%p d_sb = 0x%p\n\n", + d.d_op, d.d_sb); + + + kdb_printf("\nInode Entry at 0x%p\n", d.d_inode); + + kdb_printf(" i_mode = 0%o i_nlink = %d i_rdev = 0x%x\n", + i->i_mode, i->i_nlink, i->i_rdev); + + kdb_printf(" i_ino = %ld i_count = %d i_dev = 0x%x\n", + i->i_ino, atomic_read(&i->i_count), i->i_dev); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + i->i_hash.next, i->i_hash.prev); + + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + i->i_list.next, i->i_list.prev); + + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + i->i_dentry.next, i->i_dentry.prev); + +out: + if (i) + kfree(i); + return diag; +} + +static int +kdbm_fl(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct file_lock fl; + int nextarg; + unsigned long addr; + long offset; + int diag; + + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(fl, addr))) + return diag; + + kdb_printf("File_lock at 0x%lx\n", addr); + + kdb_printf(" fl_next = 0x%p fl_link.nxt = 0x%p fl_link.prv = 0x%p\n", + fl.fl_next, fl.fl_link.next, fl.fl_link.prev); + kdb_printf(" fl_block.nxt = 0x%p fl_block.prv = 0x%p\n", + fl.fl_block.next, fl.fl_block.prev); + kdb_printf(" fl_owner = 0x%p fl_pid = %d fl_wait = 0x%p\n", + fl.fl_owner, fl.fl_pid, &fl.fl_wait); + kdb_printf(" fl_file = 0x%p fl_flags = 0x%x\n", + fl.fl_file, fl.fl_flags); + kdb_printf(" fl_type = %d fl_start = 0x%llx fl_end = 0x%llx\n", + fl.fl_type, fl.fl_start, fl.fl_end); + + kdb_printf(" fl_notify = 0x%p fl_insert = 0x%p fl_remove = 0x%p\n", + fl.fl_notify, fl.fl_insert, fl.fl_remove); + + kdb_printf(" fl_fasync = 0x%p\n", + fl.fl_fasync); + + return 0; +} + + +static int +kdbm_dentry(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct dentry d; + int nextarg; + unsigned long addr; + long offset; + int diag; + char buf[256]; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(d, addr))) + return diag; + + + kdb_printf("Dentry at 0x%lx\n", addr); + + if ((d.d_name.len > sizeof(buf)) || (diag = kdb_getarea_size(buf, (unsigned long)(d.d_name.name), d.d_name.len))) + kdb_printf(" d_name.len = %d d_name.name = 0x%p\n", + d.d_name.len, d.d_name.name); + else + kdb_printf(" d_name.len = %d d_name.name = 0x%p <%.*s>\n", + d.d_name.len, d.d_name.name, + d.d_name.len, d.d_name.name); + + kdb_printf(" d_count = %d d_flags = 0x%x d_inode = 0x%p\n", + atomic_read(&d.d_count), d.d_flags, d.d_inode); + + kdb_printf(" d_parent = 0x%p\n", d.d_parent); + + kdb_printf(" d_hash.nxt = 0x%p d_hash.prv = 0x%p\n", + d.d_hash.next, d.d_hash.prev); + + kdb_printf(" d_lru.nxt = 0x%p d_lru.prv = 0x%p\n", + d.d_lru.next, d.d_lru.prev); + + kdb_printf(" d_child.nxt = 0x%p d_child.prv = 0x%p\n", + d.d_child.next, d.d_child.prev); + + kdb_printf(" d_subdirs.nxt = 0x%p d_subdirs.prv = 0x%p\n", + d.d_subdirs.next, d.d_subdirs.prev); + + kdb_printf(" d_alias.nxt = 0x%p d_alias.prv = 0x%p\n", + d.d_alias.next, d.d_alias.prev); + + kdb_printf(" d_op = 0x%p d_sb = 0x%p\n\n", + d.d_op, d.d_sb); + + return 0; +} + +static int +kdbm_sh(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + struct Scsi_Host sh; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(sh, addr))) + return diag; + + kdb_printf("Scsi_Host at 0x%lx\n", addr); + kdb_printf("next = 0x%p host_queue = 0x%p\n", + sh.next, sh.host_queue); + kdb_printf("ehandler = 0x%p eh_wait = 0x%p en_notify = 0x%p eh_action = 0x%p\n", + sh.ehandler, sh.eh_wait, sh.eh_notify, sh.eh_action); + kdb_printf("eh_active = 0x%d host_wait = 0x%p hostt = 0x%p host_busy = %d\n", + sh.eh_active, &sh.host_wait, sh.hostt, sh.host_active.counter); + kdb_printf("host_failed = %d extra_bytes = %d host_no = %d resetting = %d\n", + sh.host_failed, sh.extra_bytes, sh.host_no, sh.resetting); + kdb_printf("max id/lun/channel = [%d/%d/%d] this_id = %d\n", + sh.max_id, sh.max_lun, sh.max_channel, sh.this_id); + kdb_printf("can_queue = %d cmd_per_lun = %d sg_tablesize = %d u_isa_dma = %d\n", + sh.can_queue, sh.cmd_per_lun, sh.sg_tablesize, sh.unchecked_isa_dma); + kdb_printf("host_blocked = %d reverse_ordering = %d \n", + sh.host_blocked, sh.reverse_ordering); + + return 0; +} + +static int +kdbm_sd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + struct scsi_device *sd = NULL; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(sd = kmalloc(sizeof(*sd), GFP_ATOMIC))) { + kdb_printf("kdbm_sd: cannot kmalloc sd\n"); + goto out; + } + if ((diag = kdb_getarea(*sd, addr))) + goto out; + + kdb_printf("scsi_device at 0x%lx\n", addr); + kdb_printf("next = 0x%p prev = 0x%p host = 0x%p\n", + sd->next, sd->prev, sd->host); + kdb_printf("device_busy = %d device_queue 0x%p\n", + sd->device_busy, sd->device_queue); + kdb_printf("id/lun/chan = [%d/%d/%d] single_lun = %d device_blocked = %d\n", + sd->id, sd->lun, sd->channel, sd->single_lun, sd->device_blocked); + kdb_printf("queue_depth = %d current_tag = %d scsi_level = %d\n", + sd->queue_depth, sd->current_tag, sd->scsi_level); + kdb_printf("%8.8s %16.16s %4.4s\n", sd->vendor, sd->model, sd->rev); +out: + if (sd) + kfree(sd); + return diag; +} + +static char * +str_rq_status(int rq_status) +{ + switch (rq_status) { + case RQ_INACTIVE: + return "RQ_INACTIVE"; + case RQ_ACTIVE: + return "RQ_ACTIVE"; + case RQ_SCSI_BUSY: + return "RQ_SCSI_BUSY"; + case RQ_SCSI_DONE: + return "RQ_SCSI_DONE"; + case RQ_SCSI_DISCONNECTING: + return "RQ_SCSI_DISCONNECTING"; + default: + return "UNKNOWN"; + } +} + +static int +kdbm_sc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + struct scsi_cmnd *sc = NULL; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(sc = kmalloc(sizeof(*sc), GFP_ATOMIC))) { + kdb_printf("kdbm_sc: cannot kmalloc sc\n"); + goto out; + } + if ((diag = kdb_getarea(*sc, addr))) + goto out; + + kdb_printf("scsi_cmnd at 0x%lx\n", addr); + kdb_printf("host = 0x%p state = %d owner = %d device = 0x%p\nb", + sc->host, sc->state, sc->owner, sc->device); + kdb_printf("next = 0x%p reset_chain = 0x%p eh_state = %d done = 0x%p\n", + sc->next, sc->reset_chain, sc->eh_state, sc->done); + kdb_printf("serial_number = %ld serial_num_at_to = %ld retries = %d timeout = %d\n", + sc->serial_number, sc->serial_number_at_timeout, sc->retries, sc->timeout); + kdb_printf("id/lun/cmnd = [%d/%d/%d] cmd_len = %d old_cmd_len = %d\n", + sc->target, sc->lun, sc->channel, sc->cmd_len, sc->old_cmd_len); + kdb_printf("cmnd = [%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x]\n", + sc->cmnd[0], sc->cmnd[1], sc->cmnd[2], sc->cmnd[3], sc->cmnd[4], + sc->cmnd[5], sc->cmnd[6], sc->cmnd[7], sc->cmnd[8], sc->cmnd[9], + sc->cmnd[10], sc->cmnd[11]); + kdb_printf("data_cmnd = [%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x]\n", + sc->data_cmnd[0], sc->data_cmnd[1], sc->data_cmnd[2], sc->data_cmnd[3], sc->data_cmnd[4], + sc->data_cmnd[5], sc->data_cmnd[6], sc->data_cmnd[7], sc->data_cmnd[8], sc->data_cmnd[9], + sc->data_cmnd[10], sc->data_cmnd[11]); + kdb_printf("request_buffer = 0x%p bh_next = 0x%p request_bufflen = %d\n", + sc->request_buffer, sc->bh_next, sc->request_bufflen); + kdb_printf("use_sg = %d old_use_sg = %d sglist_len = %d abore_reason = %d\n", + sc->use_sg, sc->old_use_sg, sc->sglist_len, sc->abort_reason); + kdb_printf("bufflen = %d buffer = 0x%p underflow = %d transfersize = %d\n", + sc->bufflen, sc->buffer, sc->underflow, sc->transfersize); + kdb_printf("tag = %d pid = %ld\n", + sc->tag, sc->pid); + kdb_printf("request struct\n"); + kdb_printf("rq_status = %s rq_dev = [%d/%d] errors = %d cmd = %d\n", + str_rq_status(sc->request.rq_status), + MAJOR(sc->request.rq_dev), + MINOR(sc->request.rq_dev), sc->request.cmd, + sc->request.errors); + kdb_printf("sector = %ld nr_sectors = %ld current_nr_sectors = %ld\n", + sc->request.sector, sc->request.nr_sectors, sc->request.current_nr_sectors); + kdb_printf("buffer = 0x%p bh = 0x%p bhtail = 0x%p\n", + sc->request.buffer, sc->request.bh, sc->request.bhtail); + +out: + if (sc) + kfree(sc); + return diag; +} + +static int __init kdbm_vm_init(void) +{ + kdb_register("vm", kdbm_vm, "", "Display vm_area_struct", 0); + kdb_register("dentry", kdbm_dentry, "", "Display interesting dentry stuff", 0); + kdb_register("filp", kdbm_fp, "", "Display interesting filp stuff", 0); + kdb_register("fl", kdbm_fl, "", "Display interesting file_lock stuff", 0); + kdb_register("sh", kdbm_sh, "", "Show scsi_host", 0); + kdb_register("sd", kdbm_sd, "", "Show scsi_device", 0); + kdb_register("sc", kdbm_sc, "", "Show scsi_cmnd", 0); + + return 0; +} + +static void __exit kdbm_vm_exit(void) +{ + kdb_unregister("vm"); + kdb_unregister("dentry"); + kdb_unregister("filp"); + kdb_unregister("fl"); + kdb_unregister("sh"); + kdb_unregister("sd"); + kdb_unregister("sc"); +} + +module_init(kdbm_vm_init) +module_exit(kdbm_vm_exit) diff -Nur linux-2.4.19/kernel/Makefile linux-2.4.19-sgi211r3/kernel/Makefile --- linux-2.4.19/kernel/Makefile Sun Sep 16 21:22:40 2001 +++ linux-2.4.19-sgi211r3/kernel/Makefile Mon Oct 28 20:43:23 2002 @@ -9,16 +9,23 @@ O_TARGET := kernel.o -export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o +export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o rcupdate.o obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ sysctl.o acct.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o context.o + signal.o sys.o kmod.o context.o rcupdate.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_KALLSYMS) += kallsyms.o +obj-$(CONFIG_PAGG) += pagg.o + +ifneq ($(CONFIG_CSA_JOB_ACCT),n) +obj-y += csa.o +endif +obj-$(CONFIG_CPUMEMSET) += cpumemset.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -Nur linux-2.4.19/kernel/acct.c linux-2.4.19-sgi211r3/kernel/acct.c --- linux-2.4.19/kernel/acct.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/acct.c Mon Oct 28 20:43:23 2002 @@ -24,7 +24,7 @@ * Now we silently close acct_file on attempt to reopen. Cleaned sys_acct(). * XTerms and EMACS are manifestations of pure evil. 21/10/98, AV. * - * Fixed a nasty interaction with with sys_umount(). If the accointing + * Fixed a nasty interaction with with sys_umount(). If the accounting * was suspeneded we failed to stop it on umount(). Messy. * Another one: remount to readonly didn't stop accounting. * Question: what should we do if we have CAP_SYS_ADMIN but not @@ -51,7 +51,6 @@ #include #include #include -#include #include #include @@ -72,19 +71,29 @@ /* * External references and all of the globals. */ - -static volatile int acct_active; -static volatile int acct_needcheck; -static struct file *acct_file; -static struct timer_list acct_timer; static void do_acct_process(long, struct file *); /* + * This structure is used so that all the data protected by lock + * can be placed in the same cache line as the lock. This primes + * the cache line to have the data after getting the lock. + */ +struct acct_glbs { + spinlock_t lock; + volatile int active; + volatile int needcheck; + struct file *file; + struct timer_list timer; +}; + +static struct acct_glbs acct_globals __cacheline_aligned = {SPIN_LOCK_UNLOCKED}; + +/* * Called whenever the timer says to check the free space. */ static void acct_timeout(unsigned long unused) { - acct_needcheck = 1; + acct_globals.needcheck = 1; } /* @@ -96,11 +105,11 @@ int res; int act; - lock_kernel(); - res = acct_active; - if (!file || !acct_needcheck) + spin_lock(&acct_globals.lock); + res = acct_globals.active; + if (!file || !acct_globals.needcheck) goto out; - unlock_kernel(); + spin_unlock(&acct_globals.lock); /* May block */ if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf)) @@ -114,39 +123,74 @@ act = 0; /* - * If some joker switched acct_file under us we'ld better be + * If some joker switched acct_globals.file under us we'd better be * silent and _not_ touch anything. */ - lock_kernel(); - if (file != acct_file) { + spin_lock(&acct_globals.lock); + if (file != acct_globals.file) { if (act) res = act>0; goto out; } - if (acct_active) { + if (acct_globals.active) { if (act < 0) { - acct_active = 0; + acct_globals.active = 0; printk(KERN_INFO "Process accounting paused\n"); } } else { if (act > 0) { - acct_active = 1; + acct_globals.active = 1; printk(KERN_INFO "Process accounting resumed\n"); } } - del_timer(&acct_timer); - acct_needcheck = 0; - acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ; - add_timer(&acct_timer); - res = acct_active; + del_timer(&acct_globals.timer); + acct_globals.needcheck = 0; + acct_globals.timer.expires = jiffies + ACCT_TIMEOUT*HZ; + add_timer(&acct_globals.timer); + res = acct_globals.active; out: - unlock_kernel(); + spin_unlock(&acct_globals.lock); return res; } /* + * Close the old accounting file (if currently open) and then replace + * it with file (if non-NULL). + * + * NOTE: acct_globals.lock MUST be held on entry and exit. + */ +static void acct_file_reopen(struct file *file) +{ + struct file *old_acct = NULL; + + if (acct_globals.file) { + old_acct = acct_globals.file; + del_timer(&acct_globals.timer); + acct_globals.active = 0; + acct_globals.needcheck = 0; + acct_globals.file = NULL; + } + if (file) { + acct_globals.file = file; + acct_globals.needcheck = 0; + acct_globals.active = 1; + /* It's been deleted if it was used before so this is safe */ + init_timer(&acct_globals.timer); + acct_globals.timer.function = acct_timeout; + acct_globals.timer.expires = jiffies + ACCT_TIMEOUT*HZ; + add_timer(&acct_globals.timer); + } + if (old_acct) { + spin_unlock(&acct_globals.lock); + do_acct_process(0, old_acct); + filp_close(old_acct, NULL); + spin_lock(&acct_globals.lock); + } +} + +/* * sys_acct() is the only system call needed to implement process * accounting. It takes the name of the file where accounting records * should be written. If the filename is NULL, accounting will be @@ -154,71 +198,52 @@ */ asmlinkage long sys_acct(const char *name) { - struct file *file = NULL, *old_acct = NULL; + struct file *file = NULL; char *tmp; - int error; if (!capable(CAP_SYS_PACCT)) return -EPERM; if (name) { tmp = getname(name); - error = PTR_ERR(tmp); - if (IS_ERR(tmp)) - goto out; + if (IS_ERR(tmp)) { + return (PTR_ERR(tmp)); + } /* Difference from BSD - they don't do O_APPEND */ file = filp_open(tmp, O_WRONLY|O_APPEND, 0); putname(tmp); if (IS_ERR(file)) { - error = PTR_ERR(file); - goto out; + return (PTR_ERR(file)); + } + if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { + filp_close(file, NULL); + return (-EACCES); } - error = -EACCES; - if (!S_ISREG(file->f_dentry->d_inode->i_mode)) - goto out_err; - - error = -EIO; - if (!file->f_op->write) - goto out_err; - } - error = 0; - lock_kernel(); - if (acct_file) { - old_acct = acct_file; - del_timer(&acct_timer); - acct_active = 0; - acct_needcheck = 0; - acct_file = NULL; - } - if (name) { - acct_file = file; - acct_needcheck = 0; - acct_active = 1; - /* It's been deleted if it was used before so this is safe */ - init_timer(&acct_timer); - acct_timer.function = acct_timeout; - acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ; - add_timer(&acct_timer); - } - unlock_kernel(); - if (old_acct) { - do_acct_process(0,old_acct); - filp_close(old_acct, NULL); + if (!file->f_op->write) { + filp_close(file, NULL); + return (-EIO); + } } -out: - return error; -out_err: - filp_close(file, NULL); - goto out; + + spin_lock(&acct_globals.lock); + acct_file_reopen(file); + spin_unlock(&acct_globals.lock); + + return (0); } +/* + * If the accounting is turned on for a file in the filesystem pointed + * to by dev, turn accounting off. + */ void acct_auto_close(kdev_t dev) { - lock_kernel(); - if (acct_file && acct_file->f_dentry->d_inode->i_dev == dev) - sys_acct(NULL); - unlock_kernel(); + spin_lock(&acct_globals.lock); + if (acct_globals.file && + acct_globals.file->f_dentry->d_inode->i_dev == dev) + acct_file_reopen((struct file *)NULL); + spin_unlock(&acct_globals.lock); } /* @@ -356,15 +381,15 @@ int acct_process(long exitcode) { struct file *file = NULL; - lock_kernel(); - if (acct_file) { - file = acct_file; + spin_lock(&acct_globals.lock); + if (acct_globals.file) { + file = acct_globals.file; get_file(file); - unlock_kernel(); + spin_unlock(&acct_globals.lock); do_acct_process(exitcode, file); fput(file); } else - unlock_kernel(); + spin_unlock(&acct_globals.lock); return 0; } diff -Nur linux-2.4.19/kernel/capability.c linux-2.4.19-sgi211r3/kernel/capability.c --- linux-2.4.19/kernel/capability.c Fri Jun 23 21:06:37 2000 +++ linux-2.4.19-sgi211r3/kernel/capability.c Mon Oct 28 20:43:23 2002 @@ -8,6 +8,8 @@ #include #include +unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ + kernel_cap_t cap_bset = CAP_INIT_EFF_SET; /* Note: never hold tasklist_lock while spinning for this one */ diff -Nur linux-2.4.19/kernel/cpumemset.c linux-2.4.19-sgi211r3/kernel/cpumemset.c --- linux-2.4.19/kernel/cpumemset.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kernel/cpumemset.c Wed Feb 12 20:39:35 2003 @@ -0,0 +1,1865 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_IA64_SGI_SN) +#include +#endif + +kmem_cache_t *cpumemset_cache; +kmem_cache_t *cpumemmap_cache; +cpumemset_t *kernel_cms; +static cmshandle_t kern_init_han; +static rwlock_t kernel_cms_lock = RW_LOCK_UNLOCKED; + +static int injective_map(cpumemmap_t *cmm); +static cpumemmap_t *clone_cmm(cpumemmap_t *cmm); +static cpumemset_t *clone_cms(cpumemset_t *cms); +static int cms_cmm_bind_checking(cpumemset_t *cms, cpumemmap_t *cmm); +static cmshandle_t cmsDupHandle(cmshandle_t); +static unsigned long mems_allowed_build(cpumemset_t *cms); + +static int cpumemset_minimal = 0; + +static int __init +cpumemset_setup(char *str) +{ + get_option(&str, &cpumemset_minimal); + return 1; +} + +__setup("cpumemset_minimal=", cpumemset_setup); + +#if 0 +static int +cpumemset_cpuhotplug_callback(struct notifier_block *nfb, unsigned long action, + void *ocpu) +{ + int hotcpu = (unsigned long) ocpu; + int ret = NOTIFY_OK; + + if (action == CPU_ONLINE) { + /* + * We should add this cpu to the max cms, if it's not + * already there. + */ + } + if (action == CPU_OFFLINE) { + /* + * We need to do several checks : + * - See if some cms/cmm is made of a single cpu + * - If a cms/cmm has n cpus, and _needs_ to run + * on n cpus, we need to check if the unpluged + * cpus has to be replaced. + * - Something else ?? + */ + } + return ret; +} + +static struct notifier_block cpuhotplug_callback_nfb = + { &cpumemset_cpuhotplug_callback, NULL, 0 } static int __init + cpumemset_cpuhotplug_callback_init(void) { + register_cpu_notifier(&cpuhotplug_callback_nfb); + return 0; +} + +__initcall(cpumemset_cpuhotplug_callback_init); +#endif + + +#ifdef DEBUG_CMS /* defined (or undef'd) in cpumemset.h */ + +/* + * "Handle X-Ray debugging - extra validation and dumping of + * CpuMemSets - controlled by secondary define, due to its + * substantial additional overhead. + */ + +static void +printk_array_ushort(char *label, int cnt, uint16_t * ptr) +{ + int i; + printk(" Array %s[%d] = [", label, cnt); + for (i = 0; i < cnt; i++) + printk("%s%d", (i ? ", ":""), ptr[i]); + printk("]\n"); +} + +static void +printk_memlist(cms_memory_list_t * ml) +{ + printk_array_ushort("memlist cpus", ml->nr_cpus, ml->cpus); + printk_array_ushort(" mems", ml->nr_mems, ml->mems); +} + +static void printk_cmm(cpumemmap_t * cmm); + +static void +printk_cms(cpumemset_t * cms) +{ + int i; + printk("======== Begin CpuMemSet %p ========\n", (void *) cms); + printk(" policy %d\n", cms->policy); + + printk_array_ushort("cpus", cms->nr_cpus, cms->cpus); + for (i = 0; i < cms->nr_mems; i++) + printk_memlist(cms->mems + i); + printk(" mems_allowed : 0x%lx\n", cms->mems_allowed); + if (cms->cmm) + printk_cmm(cms->cmm); + else + printk(" CpuMemMap is null\n"); + printk(" cms->counter : %d\n", cms->counter.counter); + printk("======== end of CpuMemSet %p ========\n", (void *) cms); +} + +static void +printk_cmm(cpumemmap_t * cmm) +{ + int i; + printk(" CpuMemMap at %p:\n", (void *) cmm); + printk(" app to sys cpu["); + for (i = 0; i < cmm->nr_cpus; i++) + printk("%s%d", (i ? ", ":""), cmm->cpus[i]); + printk("]\n"); + printk(" app to sys mem["); + for (i = 0; i < cmm->nr_mems; i++) + printk("%s%d", (i ? ", ":""), cmm->mems[i]); + printk("]\n"); + printk(" cmm->counter : %d\n", cmm->counter.counter); +} + +void +cmsDie(cmshandle_t han, char *msg) +{ + printk("cmsDie: %s\n", msg); + printk_cms(han.set); + do_exit(SIGSEGV); +} + +static void +validate_one_handle(cmshandle_t han) +{ + /* + * The set counter must be at least one, for the reference + * from the handle. The map counter must be at least two, + * for the reference from this handle and the reference from + * the set. Also the set must refer to the map, it should + * not have error set and it should pass a bind_checking(). + */ + if (han.set->counter.counter < 1) + cmsDie(han,"CpuMemSets kernel botch: set counter too low"); + if (han.map->counter.counter < 2) + cmsDie(han,"CpuMemSets kernel botch: map counter too low"); + if (han.set->cmm != han.map) + cmsDie(han,"CpuMemSets kernel botch: mismatched set and map"); + if (han.error != 0) + cmsDie(han,"CpuMemSets kernel botch: handle error not zero"); + if (cms_cmm_bind_checking(han.set, han.map) < 0) + cmsDie(han,"CpuMemSets kernel botch: invalid bind check"); +} + + +#undef DEBUG_HX_CMS /* 'define' or 'undef' additional tracing/validation */ +#ifdef DEBUG_HX_CMS + +/* + * Every HX_WHEN'th call to validate_handle, track down and get + * handles to all (well, first HX_N) cpumemsets. Validate and + * dump each distinct handle once. The 'h' in "hx" stands for + * handle; the 'x' for "X-Ray". + */ + +#define HX_N 100 /* How many cms we can dump/validate */ +#define HX_WHEN 100 /* check_all_cms every WHEN'th validate */ + +static int hx_cnt; /* count handles we find */ +static struct { + cmshandle_t x_han; /* distinct handles we find */ + int x_n; /* how many times ea. handle seen */ +} hx[HX_N]; + +static int hx_num_validate_calls = 0; /* num validate_handle() calls */ +static rwlock_t hx_lock = RW_LOCK_UNLOCKED; /* lock guards hx_* data */ + + +/* + * Add one handle to the hx array - just bump hx[].n if seen before. + */ + +static void +hxAddHandle(cmshandle_t han) +{ + int i; /* iterate over hx[].x_han */ + + /* If we've seen this han before, just bump hx[].n for it. */ + for (i = 0; i < hx_cnt; i++) { + if (han.set == hx[i].x_han.set) { + hx[i].x_n++; + break; + } + } + + /* If it's new and if room, add it, with hx[].n set to 1 */ + if (i == hx_cnt && i < HX_N) { + hx[i].x_han = han; + hx[i].x_n = 1; + hx_cnt++; + } +} + +/* + * Find every kernel and task cpumemset in system, and for each + * distinct cpummemset, validate and dump it, with count of + * number of times seen (hx[].n). + * If more than HX_N distinct cpumemsets, we just ignore the + * rest of them. Call while holding hx_lock, to guard hx_* + * global data. + */ + +static void +check_all_cms(void) +{ + struct task_struct *p; /* iterate over all tasks */ + int i; /* iterate over all handles seen */ + + hx_cnt = 0; + + /* Add kernel handle */ + hxAddHandle(cmsGetHandleKern()); + hxAddHandle(cmsDupHandle(kern_init_han)); + + /* Add each tasks current and child handles */ + read_lock(&tasklist_lock); + for_each_task(p) { + hxAddHandle(cmsGetHandleTask(CMS_CURRENT, p)); + hxAddHandle(cmsGetHandleTask(CMS_CHILD, p)); + } + read_unlock(&tasklist_lock); + + /* Validate, dump and release each handle seen */ + printk("######## Begin CMS Dump on %d'th validate ########\n", + hx_num_validate_calls); + for (i = 0; i < hx_cnt; i++) { + cmshandle_t han = hx[i].x_han; + int n = hx[i].x_n; + /* + * The counters shown in printk_cms() include + * the 'n' handles we're currently holding. + * So, for example, if printk_cms() displays + * cmm->counter at 67, and 'n' is 65, then when + * we exit this function, cmm->counter will be + * back down to 2. + */ + printk("Seen %d times: ", n); + printk_cms(han.set); + validate_one_handle(han); + while (n--) { + /* Poor man's cmsReleaseHandle, w/o recursive VALIDATE */ + atomic_dec(&han.set->counter); /* handle reference */ + atomic_dec(&han.map->counter); /* handle reference */ + } + } + printk("######## End CMS Dump on %d'th validate ########\n", + hx_num_validate_calls); +} + +#endif /* DEBUG_HX_CMS */ + +static void validate_handle(cmshandle_t han); +int cms_num_short_circuit_calls = 0; + +/* + * Called from Short Circuit Handle Macros in cpumemset.h. + */ + +void +cms_trace_hook (char *name, cpumemset_t *cms) +{ + cmshandle_t han; + + cms_num_short_circuit_calls = 0; + printk("cms trace: %s (%p) cms->counter %d\n", + name, (void*)cms, cms->counter.counter); + han.set = cms; + han.map = cms->cmm; + atomic_inc(&han.set->counter); /* handle reference */ + atomic_inc(&han.map->counter); /* handle reference */ + han.error = 0; + validate_handle(han); + /* Poor man's cmsReleaseHandle, w/o recursive VALIDATE */ + atomic_dec(&han.set->counter); /* handle reference */ + atomic_dec(&han.map->counter); /* handle reference */ +} + +static void +validate_handle(cmshandle_t han) +{ +#ifdef DEBUG_HX_CMS + static int ncalls = 0; +#endif + validate_one_handle(han); + +#ifdef DEBUG_HX_CMS + /* + * The first few times after booting, calling check_all_cms() + * crashes the kernel - something's not ready yet. + */ + if (ncalls < 10) { + ncalls++; + return; + } + if (ncalls == 10) { + ncalls++; + printk("\n\tCpuMemSet validation enabled.\n\n"); + } + /* + * Every HX_WHEN-th call, check all cpumemsets. Too + * painful to do every call, unless one is desperate. + */ + write_lock(&hx_lock); + if (hx_num_validate_calls++ % HX_WHEN == 0) + check_all_cms(); + write_unlock(&hx_lock); +#endif /* DEBUG_HX_CMS */ +} + +#define VALIDATE_HANDLE(han) validate_handle(han) + +#else + +#define VALIDATE_HANDLE(han) do {} while (0) + +#endif + +/* + * In order to bind cms and cmm, the cpus and mems in cms should be able + * to be dereferenced in the cmm. Simply put: cms <= cmm + */ +static int +cms_cmm_bind_checking(cpumemset_t *cms, cpumemmap_t *cmm) +{ + int i, j; + + if (cms->nr_cpus == 0) + goto out; + for (i = 0; i < cms->nr_cpus; i++) { + if (cms->cpus[i] >= cmm->nr_cpus) + goto out; + } + for (i = 0; i < cms->nr_mems; i++) { + for (j = 0; j < cms->mems[i].nr_cpus; j++) { + cms_acpu_t c = cms->mems[i].cpus[j]; + if (c >= cmm->nr_cpus && c != CMS_DEFAULT_CPU) + goto out; + } + for (j = 0; j < cms->mems[i].nr_mems; j++) { + if (cms->mems[i].mems[j] >= cmm->nr_mems) + goto out; + } + } + return 0; + out: + return -ENOENT; +} + +/* + * For following cmshandle_t routines, see long comment in cpumemset.h + */ + +/* cmsGetHandleTask() - Safely get a handle to a tasks set and map pair. */ + +cmshandle_t +cmsGetHandleTask(int choice, struct task_struct *p) +{ + cmshandle_t han; + + /* + * choice is one of CMS_CURRENT or CMS_CHILD. + * Call with task_lock'd p -- no further locking needed. + */ + if (choice == CMS_CURRENT) + han.set = p->current_cms; + else + han.set = p->child_cms; + han.map = han.set->cmm; + atomic_inc(&han.set->counter); /* handle reference */ + atomic_inc(&han.map->counter); /* handle reference */ + han.error = 0; + return han; +} + +/* cmsGetHandlePid() - Safely get a handle to a pid's set and map pair. */ + +cmshandle_t +cmsGetHandlePid(int choice, pid_t pid, int do_check_perm) +{ + cmshandle_t han; + struct task_struct *p; + + /* choice is one of CMS_CURRENT or CMS_CHILD */ + if (pid) { + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + } else { + p = current; + } + if (p) { + task_lock(p); + han.error = 0; + if (pid && + do_check_perm && + (current->euid ^ p->suid) && + (current->euid ^ p->uid) && + (current->uid ^ p->suid) && + (current->uid ^ p->uid) && + !capable(CAP_SYS_ADMIN)) + han.error = -EPERM; + if (han.error == 0) + han = cmsGetHandleTask(choice, p); + task_unlock(p); + } else { + han.error = -ESRCH; + } + if (pid) + read_unlock(&tasklist_lock); + return han; +} + +/* cmsGetHandleKern() - Safely get a handle to the kernels set and map pair. */ + +cmshandle_t +cmsGetHandleKern(void) +{ + cmshandle_t han; + + /* + * Use kernel_cms_lock - established just for this purpose. + */ + write_lock(&kernel_cms_lock); + han.set = kernel_cms; + han.map = han.set->cmm; + atomic_inc(&han.set->counter); /* handle reference */ + atomic_inc(&han.map->counter); /* handle reference */ + write_unlock(&kernel_cms_lock); + han.error = 0; + return han; +} + +/* cmsNewHandle() - Create a handle for a new set and map pair. */ + +cmshandle_t +cmsNewHandle(cpumemset_t * set, cpumemmap_t * map) +{ + cmshandle_t han; + + /* + * Only our caller can see set or map, so no locking needed. + */ + han.error = cms_cmm_bind_checking (set, map); + if (han.error < 0) + return han; + atomic_set(&set->counter, 1); /* handle reference */ + atomic_set(&map->counter, 1); /* handle reference */ + atomic_inc(&map->counter); /* set reference */ + set->cmm = map; + han.set = set; + han.map = map; + han.error = 0; + han.set->mems_allowed = mems_allowed_build(han.set); + return han; +} + +/* cmsNewHandleOldSetNewMap - Create new handle, cloning old set. */ + +cmshandle_t +cmsNewHandleOldSetNewMap(cpumemset_t *oldset, cpumemmap_t *newmap) +{ + cmshandle_t han; + + /* + * Only our caller can see map, so no locking needed. + * Caller responsible for ensuring oldset doesn't vanish, + * which is all we rely on here. + */ + han.error = cms_cmm_bind_checking (oldset, newmap); + if (han.error < 0) + return han; + han.set = clone_cms(oldset); + + if (han.set == 0) { + han.error = -ENOMEM; + return han; + } + atomic_set(&han.set->counter, 1); /* handle reference */ + han.map = newmap; + atomic_set(&han.map->counter, 1); /* handle reference */ + han.set->cmm = han.map; + atomic_inc(&han.map->counter); /* set reference */ + han.error = 0; + han.set->mems_allowed = mems_allowed_build(han.set); + return han; +} + +/* cmsNewHandleNewSetOldMap - Create new handle, using old map. */ + +cmshandle_t +cmsNewHandleNewSetOldMap(cpumemset_t *newset, cpumemmap_t *oldmap) +{ + cmshandle_t han; + + /* + * Only our caller can see set, so no locking needed. + * Caller responsible for ensuring oldmap doesn't vanish, + * which is all we rely on here. + */ + han.error = cms_cmm_bind_checking (newset, oldmap); + if (han.error < 0) + return han; + han.set = newset; + atomic_set(&han.set->counter, 1); /* handle reference */ + han.map = oldmap; + atomic_inc(&han.map->counter); /* handle reference */ + han.set->cmm = han.map; + atomic_inc(&han.map->counter); /* set reference */ + han.error = 0; + han.set->mems_allowed = mems_allowed_build(han.set); + return han; +} + +/* + * Duplicate handle referring to same cpumemset. + */ + +static cmshandle_t +cmsDupHandle(cmshandle_t oldhan) +{ + cmshandle_t newhan; + + newhan = oldhan; + atomic_inc(&newhan.set->counter); /* handle reference */ + atomic_inc(&newhan.map->counter); /* handle reference */ + return newhan; +} + +unsigned long cms_current_mems_allowed() +{ + char *baddie; + if (current) { + if (current->current_cms) { + if (current->current_cms->mems_allowed) { + return current->current_cms->mems_allowed; + } else { + baddie = "mems_allowed"; + } + } else { + baddie = "current_cms"; + } + } else { + baddie = "current"; + } + printk (KERN_DEBUG "workaround zero %s in cms_current_mems_allowed\n", baddie); + return -1UL; +} + +/* + * Given a handle for a task p's current cpumemset, and + * task locked p, update the cpus_allowed setting for p. + */ + +void +update_cpus_allowed(struct task_struct *p) +{ + int i; + cpumemset_t *cms = p->current_cms; + unsigned long cpus_allowed = 0; + + for (i = 0; i < cms->nr_cpus; i++) + cpus_allowed |= 1UL << cms->cmm->cpus[cms->cpus[i]]; + if (cpu_online_map) { + /* + * Do not call: + * set_cpus_allowed(p, cpus_allowed); + * here in a 2.4 kernel for (p == current) with any + * locks held. It can deadlock. For (p != current), + * locks can and should be held, and the actual migration + * of a target process that is actually executing will + * occur in a lazy mode. + * In 2.5 kernels, one can drop any task or tasklist + * locks (first bumping the task_struct usage count, + * if need be to keep it from vanishing). But there + * is no support for a task_struct usage count in 2.4. + */ + set_cpus_allowed(p, cpus_allowed); + } +} + +/* cmsAttachNewTask() - Attach a set and map to a new task. */ + +void +cmsAttachNewTask(int choice, cmshandle_t han, struct task_struct *p) +{ + /* + * choice is one of CMS_CURRENT or CMS_CHILD. + * Only our caller can see this task, so no locking needed. + */ + VALIDATE_HANDLE(han); + if (choice == CMS_CURRENT) { + atomic_inc(&han.set->counter); /* user reference */ + p->current_cms = han.set; + update_cpus_allowed(p); + } else if (choice == CMS_CHILD) { + atomic_inc(&han.set->counter); /* user reference */ + p->child_cms = han.set; + } + cmsReleaseHandle(han); +} + +/* cmsAttachNewKern() - Attach a set and map to the kernel at boot. */ + +void +cmsAttachNewKern(cmshandle_t han) +{ + /* + * Early boot, so no locking needed. + */ + VALIDATE_HANDLE(han); + atomic_inc(&han.set->counter); /* user reference */ + kernel_cms = han.set; + cmsReleaseHandle(han); +} + +/* cmsDiscard() - Discard a set and map on task exit deletion. */ + +void +cmsDiscard(cmshandle_t han) +{ + /* + * Only call with handle that's been in use (set counter >= 2). + */ + VALIDATE_HANDLE(han); + atomic_dec(&han.set->counter); /* user reference */ + cmsReleaseHandle(han); +} + +/* cmsExchangeTask() - Replace a tasks set and map pair with another. */ + +void +cmsExchangeTask(cmshandle_t oldhan, cmshandle_t newhan, + int choice, struct task_struct *p) +{ + VALIDATE_HANDLE(oldhan); + VALIDATE_HANDLE(newhan); + + /* + * choice is one of CMS_CURRENT or CMS_CHILD. + * Call with task_lock'd p -- no further locking needed. + */ + if (choice == CMS_CURRENT && p->current_cms == oldhan.set) { + atomic_inc(&newhan.set->counter); /* user reference */ + p->current_cms = newhan.set; + atomic_dec(&oldhan.set->counter); /* user reference */ + update_cpus_allowed(p); + } else if (choice == CMS_CHILD && p->child_cms == oldhan.set) { + atomic_inc(&newhan.set->counter); /* user reference */ + p->child_cms = newhan.set; + atomic_dec(&oldhan.set->counter); /* user reference */ + } + + cmsReleaseHandle(oldhan); + cmsReleaseHandle(newhan); +} + +/* cmsExchangePid() - Replace a pid's set and map pair with another. */ + +void +cmsExchangePid(cmshandle_t oldhan, cmshandle_t newhan, int choice, pid_t pid) +{ + struct task_struct *p; + + VALIDATE_HANDLE(oldhan); + VALIDATE_HANDLE(newhan); + + /* + * choice is one of CMS_CURRENT or CMS_CHILD. + * If pid == 0, changes current task. Otherwise, locks + * tasklist and finds task by pid. Must _not_ be called + * with task_lock on specified task already set, nor with + * tasklist_lock set, or else will deadlock. + */ + if (pid && current->pid != pid) { + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + /* Lock task in 2.4 kernels; bump task usage in 2.5 */ + if (p) { + task_lock(p); + read_unlock(&tasklist_lock); + } else { + read_unlock(&tasklist_lock); + goto out; + } + + if ((current->euid ^ p->suid) && + (current->euid ^ p->uid) && + (current->uid ^ p->suid) && + (current->uid ^ p->uid) && + !capable(CAP_SYS_ADMIN)) + goto out; /* nevermind - no longer allowed */ + } else { + p = current; + } + + if (choice == CMS_CURRENT && p->current_cms == oldhan.set) { + atomic_inc(&newhan.set->counter); /* user reference */ + p->current_cms = newhan.set; + atomic_dec(&oldhan.set->counter); /* user reference */ + update_cpus_allowed(p); + } else if (choice == CMS_CHILD && p->child_cms == oldhan.set) { + atomic_inc(&newhan.set->counter); /* user reference */ + p->child_cms = newhan.set; + atomic_dec(&oldhan.set->counter); /* user reference */ + } + + out: + if (p && p != current) { + /* Unlock task in 2.4; decrement task usage in 2.5 */ + task_unlock(p); + } + cmsReleaseHandle(oldhan); + cmsReleaseHandle(newhan); +} + +/* cmsExchangeKern() - Replace the kernels set and map pair with another. */ + +void +cmsExchangeKern(cmshandle_t oldhan, cmshandle_t newhan) +{ + /* + * Use kernel_cms_lock - established just for this purpose. + */ + VALIDATE_HANDLE(oldhan); + VALIDATE_HANDLE(newhan); + write_lock(&kernel_cms_lock); + if (kernel_cms == oldhan.set) { + atomic_inc(&newhan.set->counter); /* user reference */ + kernel_cms = newhan.set; + atomic_dec(&oldhan.set->counter); /* user reference */ + } + write_unlock(&kernel_cms_lock); + cmsReleaseHandle(oldhan); + cmsReleaseHandle(newhan); +} + +/* + * cmsdrophandle() - relinquish handle + * + * Handle might not be quite valid. The cms->cmm pointer and + * the usage counters should be valid, but the amems_allowed[] + * array might be missing. + */ + +static void +cmsdrophandle(cmshandle_t han) +{ + if (atomic_dec_and_test(&han.set->counter)) { /* handle reference */ + free_cms(han.set); + atomic_dec(&han.map->counter); /* set reference */ + } + if (atomic_dec_and_test(&han.map->counter)) /* handle reference */ + free_cmm(han.map); +} + +/* cmsReleaseHandle() - Relinquish a handle no longer needed. */ + +void +cmsReleaseHandle(cmshandle_t han) +{ + VALIDATE_HANDLE(han); + cmsdrophandle(han); +} + +/* + * =========================================================== + * No code in the rest of this file should reference the cms + * or cmm counters, nor change the cms->cmm link, nor directly + * link to or unlink from cpumemsets. Use the above handle + * routines for that as described in the kernel's cpumemset.h. + * =========================================================== + */ + +/* + * cms_cmm_static_init - Initialization of the first cms and cmm + * + * This CpuMemSet is required to allocate the slab data structures, + * so can't dynamically allocate memory. Chicken and egg stuff... + * This function is called by start_kernel() from init/main.c. + */ +void __init +cms_cmm_static_init(void) +{ + cmshandle_t han; + + static cms_scpu_t initial_cmmcpu_array[1]; + static cms_smem_t initial_cmmmem_array[1]; + static cms_memory_list_t initial_mem_list; + static cms_acpu_t initial_cmscpu_array[1]; + static cms_acpu_t initial_memlist_cpu_array[1]; + static cms_amem_t initial_memlist_mem_array[1]; + static cpumemmap_t initial_kernel_cmm; + static cpumemset_t initial_kernel_cms; + + initial_cmmcpu_array[0] = smp_processor_id(); +#if defined(CONFIG_IA64_SGI_SN) + initial_cmmmem_array[0] = cpuid_to_cnodeid(smp_processor_id()); +#else + initial_cmmmem_array[0] = 0; +#endif + + initial_kernel_cmm.nr_cpus = 1; + initial_kernel_cmm.cpus = initial_cmmcpu_array; + initial_kernel_cmm.nr_mems = 1; + initial_kernel_cmm.mems = initial_cmmmem_array; + + initial_mem_list.nr_cpus = 1; + initial_memlist_cpu_array[0] = CMS_DEFAULT_CPU; + initial_mem_list.cpus = initial_memlist_cpu_array; + initial_mem_list.nr_mems = 1; + initial_memlist_mem_array[0] = 0; + initial_mem_list.mems = initial_memlist_mem_array; + + initial_kernel_cms.policy = CMS_DEFAULT; + initial_kernel_cms.nr_cpus = 1; + initial_cmscpu_array[0] = 0; + initial_kernel_cms.cpus = initial_cmscpu_array; + initial_kernel_cms.nr_mems = 1; + initial_kernel_cms.mems = &initial_mem_list; + + /* Keep one kernel cms handle -- can't free static memory */ + kern_init_han = cmsNewHandle(&initial_kernel_cms, &initial_kernel_cmm); + + han = cmsDupHandle(kern_init_han); + if (han.error < 0) + panic("CpuMemSets static init botch"); + cmsAttachNewKern(han); + + han = cmsGetHandleKern(); + cmsAttachNewTask(CMS_CURRENT, han, &init_task); + han = cmsGetHandleKern(); + cmsAttachNewTask(CMS_CHILD, han, &init_task); + + /* Let kernel have any memory it wants during cpu_init() */ + kernel_cms->mems_allowed = -1UL; +} + +/* + * cms_cmm_build_max_cms - Builds the default cms and cmm + * + * This function gets called by default. However, if we boot with + * cpumemset_minimal as a boot argument, we won't call it. + * It build the "max" cms and cmm. Both structures contains all cpus + * and all nodes. + * + * XXX We have to build balanced memory lists. Right now, they are + * all the same, beginning with node 0. + */ + +static void +cms_cmm_build_max_cms(void) +{ + int i; + cms_memory_list_t *temp_mem_list; + cpumemmap_t *temp_max_map; + cpumemset_t *temp_max_set; + cmshandle_t oldhan, newhan; + + /* + * cmm and cms allocation + */ + if (!(temp_max_map = kmem_cache_alloc(cpumemmap_cache, GFP_KERNEL))) + panic("Couldn't allocate cpumemset max map\n"); + if (!(temp_max_set = kmem_cache_alloc(cpumemset_cache, GFP_KERNEL))) + panic("Couldn't allocate cpumemset max set\n"); + + /* + * temp_mem_list init + */ + if (! + (temp_mem_list = + (cms_memory_list_t *) kmalloc(sizeof (cms_memory_list_t), + GFP_KERNEL))) + panic("Couldn't allocate cpumemset array\n"); + + temp_mem_list->nr_cpus = smp_num_cpus + 1; + if (! + (temp_mem_list->cpus = + (cms_acpu_t *) kmalloc((smp_num_cpus + 1) * + sizeof (cms_acpu_t), GFP_KERNEL))) + panic("Couldn't allocate cpumemset map\n"); + for (i = 0; i < smp_num_cpus; i++) + temp_mem_list->cpus[i] = i; + temp_mem_list->cpus[smp_num_cpus] = CMS_DEFAULT_CPU; + + temp_mem_list->nr_mems = numnodes; + if (! + (temp_mem_list->mems = + (cms_amem_t *) kmalloc(temp_mem_list->nr_mems * + sizeof (cms_amem_t), GFP_KERNEL))) + panic("Couldn't allocate cpumemset array\n"); + + for (i = 0; i < numnodes; i++) + temp_mem_list->mems[i] = i; + + /* + * Map initialization + */ + temp_max_map->nr_cpus = smp_num_cpus; + temp_max_map->nr_mems = numnodes; + + if (! + (temp_max_map->cpus = + (cms_scpu_t *) kmalloc(smp_num_cpus * sizeof (cms_scpu_t), + GFP_KERNEL))) + panic("Couldn't allocate cpumemset map\n"); + for (i = 0; i < smp_num_cpus; i++) + temp_max_map->cpus[i] = i; + + if (! + (temp_max_map->mems = + (cms_smem_t *) kmalloc(numnodes * sizeof (cms_smem_t), + GFP_KERNEL))) + panic("Couldn't allocate cpumemset array\n"); + for (i = 0; i < numnodes; i++) + temp_max_map->mems[i] = i; + + /* + * Set initialization + */ + temp_max_set->policy = CMS_DEFAULT; + temp_max_set->nr_cpus = smp_num_cpus; + + if (! + (temp_max_set->cpus = + (cms_acpu_t *) kmalloc(smp_num_cpus * sizeof (cms_acpu_t), + GFP_KERNEL))) + panic("Couldn't allocate cpumemset map\n"); + for (i = 0; i < smp_num_cpus; i++) + temp_max_set->cpus[i] = i; + temp_max_set->nr_mems = 1; + temp_max_set->mems = temp_mem_list; + + oldhan = cmsGetHandleKern(); + newhan = cmsNewHandle(temp_max_set, temp_max_map); + if (newhan.error < 0) + panic("CpuMemSets maxset init botch"); + VALIDATE_HANDLE(oldhan); + VALIDATE_HANDLE(newhan); + cmsExchangeKern(oldhan, newhan); + + newhan = cmsGetHandleKern(); + oldhan = cmsGetHandleTask(CMS_CURRENT, &init_task); + cmsExchangeTask(oldhan, newhan, CMS_CURRENT, &init_task); + newhan = cmsGetHandleKern(); + oldhan = cmsGetHandleTask(CMS_CHILD, &init_task); + cmsExchangeTask(oldhan, newhan, CMS_CHILD, &init_task); +} + +/* + * cms_cmm_init - This is the main init function. + * + * It allocates slabs for the cms and the cmm. It also + * get the boot argument (cpumemset_minimal = 1 or 0), and sets + * everything according to it. + */ + +void __init +cms_cmm_init(void) +{ + /* Restore kernel_cms to minimal - we're past cpu_init() */ + kernel_cms->mems_allowed = mems_allowed_build(kernel_cms); + + cpumemset_cache = + kmem_cache_create("cpumemset_cache", sizeof (cpumemset_t), + __alignof__(struct cpumemset), + SLAB_HWCACHE_ALIGN | SLAB_NO_REAP, NULL, NULL); + if (!cpumemset_cache) + panic("Cannot create CpuMemSet SLAB cache"); + cpumemmap_cache = + kmem_cache_create("cpumemmap_cache", sizeof (cpumemmap_t), + __alignof__(struct cpumemmap), + SLAB_HWCACHE_ALIGN | SLAB_NO_REAP, NULL, NULL); + if (!cpumemmap_cache) + panic("Cannot create CpuMemMap SLAB cache"); + + if (!cpumemset_minimal) + cms_cmm_build_max_cms(); + else { + /* was no-op in cms_cmm_static_init if cpu_online_map == 0 */ + update_cpus_allowed(&init_task); + } +} + +#ifndef roundup +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#endif + +static int +size_cmm(cpumemmap_t * cmm) +{ + int size; + + size = 0; + size += sizeof (cmm->nr_cpus); + size += roundup(sizeof (uint16_t) * cmm->nr_cpus, sizeof (int)); + size += sizeof (cmm->nr_mems); + size += roundup(sizeof (uint16_t) * cmm->nr_mems, sizeof (int)); + return size; +} + +static int +size_cms(cpumemset_t * cms) +{ + int size; + int i; + + size = 0; + size += sizeof (cms->policy); + size += sizeof (cms->nr_cpus); + size += roundup(sizeof (uint16_t) * cms->nr_cpus, sizeof (int)); + size += sizeof (cms->nr_mems); + for (i = 0; i < cms->nr_mems; i++) { + cms_memory_list_t *mem = cms->mems + i; + size += sizeof (mem->nr_cpus); + size += roundup(sizeof (uint16_t) * mem->nr_cpus, sizeof (int)); + size += sizeof (mem->nr_mems); + size += roundup(sizeof (uint16_t) * mem->nr_mems, sizeof (int)); + } + return size; +} + +/* + * Some code below is mostly common between cmm and cms uses. + * This target option is used in that code to distinguish between + * these two uses. + */ + +typedef enum { + cmm_target = 0, + cms_target = 1 +} target_option; + +/* + * Common code for cms_querysize() and cms_query(). Returns a + * cpumemset handle via *phan, and its size in return value. + * In case of error, returns -errno and no handle. + */ + +static int +cms_getcpumemset(unsigned long *preq, cmshandle_t *phan, target_option cmm_or_cms) +{ + unsigned long req[3]; + int choice; + pid_t pid; + unsigned long start; + cmshandle_t han; + int size; + + if (copy_from_user(req, preq, sizeof (req))) + return -EFAULT; + + choice = (cms_choice_t) req[0]; + pid = (pid_t) req[1]; + start = req[2]; + + if (choice == CMS_CURRENT || choice == CMS_CHILD) { + han = cmsGetHandlePid(choice, pid, 0); + } else if (choice == CMS_VMAREA) { + if (pid != 0) + return -ENOSYS; + han = cmsGetHandleTask(CMS_CURRENT, current); + } else if (choice == CMS_KERNEL) { + han = cmsGetHandleKern(); + } else { + return -EINVAL; + } + if (han.error) + return han.error; + + if (cmm_or_cms == cms_target) + size = size_cms(han.set); + else + size = size_cmm(han.map); + + *phan = han; + return size; +} + +static int +cms_querysize(unsigned long *preq, int *psize, target_option cmm_or_cms) +{ + cmshandle_t han; + int size; + + size = cms_getcpumemset(preq, &han, cmm_or_cms); + if (size < 0) + return size; /* -errno */ + cmsReleaseHandle(han); + return put_user(size, psize); +} + +int +cms_query_cmm_size(unsigned long *preq, int *psize) +{ + return cms_querysize(preq, psize, cmm_target); +} + +int +cms_query_cms_size(unsigned long *preq, int *psize) +{ + return cms_querysize(preq, psize, cms_target); +} + +static void +pack_int(int val, char **pptr) +{ + *((int *) (*pptr)) = val; + *pptr += sizeof (int); +} + +static void +pack_uint16_array(uint16_t * src, int cnt, char **pptr) +{ + int nbytes = sizeof (uint16_t) * cnt; + + memcpy(*pptr, src, nbytes); + *pptr += roundup(nbytes, sizeof (int)); +} + +static void +pack_memlist_array(cms_memory_list_t * mems, int cnt, char **pptr) +{ + int i; + + for (i = 0; i < cnt; i++) { + pack_int(mems[i].nr_cpus, pptr); + pack_uint16_array(mems[i].cpus, mems[i].nr_cpus, pptr); + pack_int(mems[i].nr_mems, pptr); + pack_uint16_array(mems[i].mems, mems[i].nr_mems, pptr); + } +} + +static void +pack_cmm(cpumemmap_t * cmm, char *ptr) +{ + pack_int(cmm->nr_cpus, &ptr); + pack_uint16_array(cmm->cpus, cmm->nr_cpus, &ptr); + pack_int(cmm->nr_mems, &ptr); + pack_uint16_array(cmm->mems, cmm->nr_mems, &ptr); +} + +static void +pack_cms(cpumemset_t * cms, char *ptr) +{ + pack_int(cms->policy, &ptr); + pack_int(cms->nr_cpus, &ptr); + pack_uint16_array(cms->cpus, cms->nr_cpus, &ptr); + pack_int(cms->nr_mems, &ptr); + pack_memlist_array(cms->mems, cms->nr_mems, &ptr); +} + +/* + * Handle system call to query the cms or cmm for one of + * the kernel, some tasks current or child cms. + */ + +static int +cms_query(unsigned long *preq, char *rec, int usize, target_option cmm_or_cms) +{ + cmshandle_t han; + int ksize; + char *kaddr; + int error; + + ksize = cms_getcpumemset(preq, &han, cmm_or_cms); + if (ksize < 0) + return ksize; /* -errno */ + + if (ksize > usize) { + cmsReleaseHandle(han); + return -E2BIG; + } + + if ((kaddr = (char *) kmalloc(ksize, GFP_KERNEL)) == 0) { + cmsReleaseHandle(han); + return -ENOMEM; + } + if (cmm_or_cms == cms_target) + pack_cms(han.set, kaddr); + else + pack_cmm(han.map, kaddr); + + cmsReleaseHandle(han); + error = copy_to_user(rec, kaddr, ksize) ? -EFAULT : 0; + kfree(kaddr); + return error; +} + +int +cms_query_cmm(unsigned long *preq, char *rec, int size) +{ + return cms_query(preq, rec, size, cmm_target); +} + +int +cms_query_cms(unsigned long *preq, char *rec, int size) +{ + return cms_query(preq, rec, size, cms_target); +} + +static int +unpack_int(int *pret, char **pbp, char *maxbp) +{ + char *newbp = *pbp + sizeof (int); + if (newbp >= maxbp) + return -EINVAL; + *pret = *((int *) (*pbp)); + *pbp = newbp; + return 0; +} + +static int +unpack_uint16_array(int cnt, uint16_t ** pret, char **pbp, char *maxbp) +{ + int nbytes = sizeof (uint16_t) * cnt; + char *newbp = *pbp + roundup(nbytes, sizeof (int)); + if (newbp > maxbp) + return -EINVAL; + if ((*pret = (uint16_t *) kmalloc(nbytes, GFP_KERNEL)) == 0) + return -ENOMEM; + memcpy(*pret, *pbp, nbytes); + *pbp = newbp; + return 0; +} + +static int +unpack_memlist_array(int cnt, cms_memory_list_t ** pret, char **pbp, + char *maxbp) +{ + cms_memory_list_t *mems; + int nbytes; + int i; + int error; + + nbytes = cnt * sizeof (*mems); + if ((*pret = (cms_memory_list_t *) kmalloc(nbytes, GFP_KERNEL)) == 0) + return -ENOMEM; + memset(*pret, 0, nbytes); + mems = *pret; + + for (i = 0; i < cnt; i++) { + if ((error = unpack_int(&(mems[i].nr_cpus), pbp, maxbp)) < 0) + goto out; + if ((error = + unpack_uint16_array(mems[i].nr_cpus, &(mems[i].cpus), pbp, + maxbp)) < 0) + goto out; + + if ((error = unpack_int(&(mems[i].nr_mems), pbp, maxbp)) < 0) + goto out; + if ((error = + unpack_uint16_array(mems[i].nr_mems, &(mems[i].mems), pbp, + maxbp)) < 0) + goto out; + } + return 0; + out: + return error; /* caller will do free_cms() on error */ +} + +static int +cms_unpack_construct(char *bp, int size, cpumemset_t ** pcms) +{ + int i, j; + int error = 0; + int found = 0; + char *maxbp = bp + size; /* dont read past maxbp */ + cpumemset_t *cms; + + cms = (cpumemset_t *) kmem_cache_alloc(cpumemset_cache, SLAB_KERNEL); + if (!cms) { + error = -ENOMEM; + goto out; + } + *pcms = cms; + + memset(cms, 0, sizeof (*cms)); /* so free_cms() works */ + + if ((error = unpack_int(&cms->policy, &bp, maxbp)) < 0) + goto out; + if ((error = unpack_int(&cms->nr_cpus, &bp, maxbp)) < 0) + goto out; + if (cms->nr_cpus > smp_num_cpus) { + error = -EINVAL; + goto out; + } + if ((error = + unpack_uint16_array(cms->nr_cpus, &cms->cpus, &bp, maxbp)) < 0) + goto out; + if ((error = unpack_int(&cms->nr_mems, &bp, maxbp)) < 0) + goto out; + if ((error = + unpack_memlist_array(cms->nr_mems, &cms->mems, &bp, maxbp)) < 0) + goto out; + + /* Verify passed in CPU and memory block numbers valid */ + error = -EINVAL; + for (i = 0; i < cms->nr_cpus; i++) { + cms_acpu_t c = cms->cpus[i]; + if (c != CMS_DEFAULT_CPU && !(cpu_online_map & (1UL << c))) + goto out; + } + for (i = 0; i < cms->nr_mems; i++) { + for (j = 0; j < cms->mems[i].nr_cpus; j++) { + cms_acpu_t c = cms->mems[i].cpus[j]; + if (c != CMS_DEFAULT_CPU && !(cpu_online_map & (1UL << c))) + goto out; + if (c == CMS_DEFAULT_CPU) + found = 1; + } + for (j = 0; j < cms->mems[i].nr_mems; j++) { + cms_amem_t m = cms->mems[i].mems[j]; + if (m >= numnodes) + goto out; + } + } + if (!found) + goto out; + /* mems_allowed set by cms_set() */ + return 0; + out: + if(cms) + free_cms(cms); + *pcms = 0; + return error; +} + +static int +cmm_unpack_construct(char *bp, int size, cpumemmap_t ** pcmm) +{ + int i; + int error = 0; + char *maxbp = bp + size; /* dont read past maxbp */ + cpumemmap_t *cmm; + + cmm = (cpumemmap_t *) kmem_cache_alloc(cpumemmap_cache, SLAB_KERNEL); + if (!cmm) { + error = -ENOMEM; + goto out; + } + *pcmm = cmm; + + memset(cmm, 0, sizeof (*cmm)); /* so free_cmm() works */ + + if ((error = unpack_int(&cmm->nr_cpus, &bp, maxbp)) < 0) + goto out; + if ((error = + unpack_uint16_array(cmm->nr_cpus, &cmm->cpus, &bp, maxbp)) < 0) + goto out; + + if ((error = unpack_int(&cmm->nr_mems, &bp, maxbp)) < 0) + goto out; + + if (cmm->nr_mems > numnodes) { + error = -EINVAL; + goto out; + } + if ((error = + unpack_uint16_array(cmm->nr_mems, &cmm->mems, &bp, maxbp)) < 0) + goto out; + + + /* Verify passed in CPU and memory block numbers valid */ + error = -EINVAL; + for (i = 0; i < cmm->nr_cpus; i++) { + if (!(cpu_online_map & (1UL << cmm->cpus[i]))) + goto out; + } + for (i = 0; i < cmm->nr_mems; i++) { + if (cmm->mems[i] >= numnodes) + goto out; + } + + if (!injective_map(cmm)) + goto out; + + return 0; + out: + if (cmm) + free_cmm(cmm); + *pcmm = 0; + return error; +} + +/* + * Is cpumemmap injective (one-to-one)? + * + * Return success (non-zero) iff there are no duplicate + * cpu numbers and no duplicate memory block numbers + * in the cpumemmap_t cmm. + */ + +static int +injective_map(cpumemmap_t * cmm) +{ + int i, j; + + for (i = 0; i < cmm->nr_cpus; i++) + for (j = i + 1; j < cmm->nr_cpus; j++) + if (cmm->cpus[i] == cmm->cpus[j]) + return 0; + + for (i = 0; i < cmm->nr_mems; i++) + for (j = i + 1; j < cmm->nr_mems; j++) + if (cmm->mems[i] == cmm->mems[j]) + return 0; + return 1; +} + +/* + * Return true (1) if 'elem' is in 'array[0..len-1]', else false (0). + */ + +static int +foundin(int elem, uint16_t *array, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (elem == array[i]) + return 1; + return 0; +} + +/* + * Unless you have CAP_SYS_ADMIN capability, you can only shrink cmm. + */ + +static int +cmm_restrict_checking(cpumemmap_t *oldmap, cpumemmap_t *newmap) +{ + int i; + + if (capable(CAP_SYS_ADMIN)) + return 0; + + /* newmap must be a subset of oldmap */ + for (i = 0; i < newmap->nr_cpus; i++) + if (!foundin (newmap->cpus[i], oldmap->cpus, oldmap->nr_cpus)) + return -EINVAL; + for (i = 0; i < newmap->nr_mems; i++) + if (!foundin (newmap->mems[i], oldmap->mems, oldmap->nr_mems)) + return -EINVAL; + return 0; +} + +/* + * Crude upper bound on memory required to copy in any user's + * CpuMemSet. We take roughly 3 * (numnodes+NR_CPUs) bytes of + * memory for largest CpuMemSet. Round up an order of magnitude, + * to ensure that any plausible CpuMemSet can be passed into + * the kernel, while discouraging bogus claims for the kernel + * to allocate gigabytes, possibly crashing it. + */ + +static int +waytoobig(int size) +{ + return size > 1000 + 40 * numnodes * NR_CPUS; +} + +/* + * This takes a memory_list and returns a mems_allowed bit + * vector, corresponding to the system nodes we are allowed to + * allocate from. + */ + +static unsigned long +mems_allowed_value(cpumemset_t *cms, cms_memory_list_t *ml) +{ + int j; + unsigned long mems_allowed = 0; + + for (j = 0; j < ml->nr_mems; j++) { + int node_id = cms->cmm->mems[ml->mems[j]]; + mems_allowed |= 1UL << node_id; + } + return mems_allowed; +} + +/* + * mems_allowed_build() - Build cpumemset_t mems_allowed. + */ + +static unsigned long +mems_allowed_build(cpumemset_t *cms) +{ + int i; + unsigned long mems_allowed = 0; + + for (i = 0; i < cms->nr_mems; i++) + mems_allowed |= mems_allowed_value(cms, cms->mems + i); + return mems_allowed; +} + +void +free_cms(cpumemset_t * cms) +{ + int i; + + if (!cms) + return; + if (cms->cpus) + kfree(cms->cpus); + if (cms->mems){ + for (i = 0; i < cms->nr_mems; i++) { + if (cms->mems[i].cpus) + kfree(cms->mems[i].cpus); + if (cms->mems[i].mems) + kfree(cms->mems[i].mems); + } + kfree(cms->mems); + } + kmem_cache_free(cpumemset_cache, cms); +} + +void +free_cmm(cpumemmap_t * cmm) +{ + if (!cmm) + return; + if (cmm->cpus) + kfree(cmm->cpus); + if (cmm->mems) + kfree(cmm->mems); + kmem_cache_free(cpumemmap_cache, cmm); +} + +static cpumemmap_t * +clone_cmm(cpumemmap_t * cmm) +{ + cpumemmap_t *new_cmm; + + new_cmm = kmem_cache_alloc(cpumemmap_cache, SLAB_KERNEL); + if (!new_cmm) + return 0; + memset(new_cmm, 0, sizeof (*new_cmm)); /* so free_cmm() works */ + new_cmm->nr_cpus = cmm->nr_cpus; + new_cmm->cpus = kmalloc(sizeof (cms_scpu_t) * cmm->nr_cpus, GFP_KERNEL); + if (!new_cmm->cpus) + goto out; + memcpy(new_cmm->cpus, cmm->cpus, sizeof (cms_scpu_t) * cmm->nr_cpus); + new_cmm->nr_mems = cmm->nr_mems; + new_cmm->mems = kmalloc(sizeof (cms_smem_t) * cmm->nr_mems, GFP_KERNEL); + if (!new_cmm->mems) + goto out; + memcpy(new_cmm->mems, cmm->mems, sizeof (cms_smem_t) * cmm->nr_mems); + return new_cmm; + out: + free_cmm(new_cmm); + return 0; +} + +static cpumemset_t * +clone_cms(cpumemset_t * cms) +{ + cpumemset_t *new_cms; + int i; + int memsz; + + new_cms = kmem_cache_alloc(cpumemset_cache, SLAB_KERNEL); + if (!new_cms) + return 0; + memset(new_cms, 0, sizeof (*new_cms)); /* so free_cms() works */ + new_cms->policy = cms->policy; + new_cms->nr_cpus = cms->nr_cpus; + memsz = sizeof (cms_acpu_t) * cms->nr_cpus; + new_cms->cpus = kmalloc(memsz, GFP_KERNEL); + if (!new_cms->cpus) + goto out; + memcpy(new_cms->cpus, cms->cpus, memsz); + new_cms->nr_mems = cms->nr_mems; + memsz = sizeof (cms_memory_list_t) * cms->nr_mems; + new_cms->mems = kmalloc(memsz, GFP_KERNEL); + if (!new_cms->mems) + goto out; + memset(new_cms->mems, 0, memsz); /* so free_cms() works */ + + for (i = 0; i < cms->nr_mems; i++) { + cms_memory_list_t *mp = cms->mems + i; + cms_memory_list_t *new_mp = new_cms->mems + i; + int ncpu = mp->nr_cpus; + int nmem = mp->nr_mems; + + new_mp->nr_cpus = ncpu; + new_mp->cpus = kmalloc(sizeof (cms_acpu_t) * ncpu, GFP_KERNEL); + if (!new_mp->cpus) + goto out; + memcpy(new_mp->cpus, mp->cpus, sizeof (cms_acpu_t) * ncpu); + new_mp->nr_mems = nmem; + new_mp->mems = kmalloc(sizeof (cms_amem_t) * nmem, GFP_KERNEL); + if (!new_mp->mems) + goto out; + memcpy(new_mp->mems, mp->mems, sizeof (cms_amem_t) * nmem); + } + /* mems_allowed set by cms_set() or cmsNewHandleOldSetNewMap() */ + return new_cms; + out: + free_cms(new_cms); + return 0; +} + +/* + * Handle system call to set a new cms or cmm for one of + * the kernel or some tasks current. + */ + +static int +cms_set(unsigned long *preq, char *rec, int size, target_option cmm_or_cms) +{ + cpumemmap_t *new_cmm; /* construct new cmm here, or ... */ + cpumemset_t *new_cms; /* ... construct new cms here */ + int choice; /* cur, child, kernel or vm area? */ + pid_t pid; /* change cmm of task with this pid */ + unsigned long start; /* start of address range to change */ + int len; /* length address range to change */ + unsigned long req[4]; /* args from invoking system call */ + char *kbuf; /* kernel buffer to rcv cms/cmm data */ + cmshandle_t oldhan; /* exchange this handle ... */ + cmshandle_t newhan; /* ... for this handle */ + int error; /* 0 or -errno return value */ + + if (waytoobig (size)) + return -E2BIG; + if (copy_from_user(req, preq, sizeof (req))) + return -EFAULT; + + choice = (cms_choice_t) req[0]; + if (choice < CMS_CURRENT || choice > CMS_KERNEL) + return -EINVAL; + pid = (pid_t) req[1]; + start = req[2]; + len = req[3]; + + if (choice == CMS_VMAREA && pid != 0) + return -ENOSYS; + if ((kbuf = (char *) kmalloc(size, GFP_KERNEL)) == 0) + return -ENOMEM; + error = copy_from_user(kbuf, rec, size) ? -EFAULT : 0; + if (error < 0) { + kfree(kbuf); + return error; + } + if (cmm_or_cms == cms_target) + error = cms_unpack_construct(kbuf, size, &new_cms); + else + error = cmm_unpack_construct(kbuf, size, &new_cmm); + kfree(kbuf); + if (error < 0) + return error; + + /* + * For vmareas, we split any existing vmarea that straddles + * the lower and/or upper boundary of the [start, end) range, + * and apply the change to each vma in that range. For the + * other cases, we have just one cms or cmm to change, the + * current, child or kernel. + */ + + if (choice == CMS_VMAREA) { + struct vm_area_struct *vma; /* iterate over vm areas in range */ + int fault_error = 0; /* EFAULT: range not all mapped */ + int bind_error = 0; /* cumulative binding errno */ + int clone_error = 0; /* clone_cm[ms] failed */ + int err; /* latest binding errno */ + unsigned long end; /* end of overall range */ + unsigned long prev_end; /* where previous vm area ended */ + + /* Must be 'current' task: see first -ENOSYS above. */ + down_write(¤t->mm->mmap_sem); + error = vma_split_range(current->mm, start, len); + if (error < 0) + goto done; + prev_end = start; + end = start + len; + oldhan = cmsGetHandleTask(CMS_CURRENT, current); + if (oldhan.error < 0) { + error = -EFAULT; + goto done2; + } + vma = find_vma(current->mm, start); + while (vma->vm_end <= end) { + /* We know vma is _entirely_ within [start, end). */ + if (vma->vm_start > prev_end) + fault_error = -EFAULT; + if (cmm_or_cms == cms_target) { + cpumemset_t *set2 = clone_cms(new_cms); + if (set2 == 0) { + clone_error = -ENOMEM; + goto loop; + } + newhan = cmsNewHandleNewSetOldMap( + set2, oldhan.map); + if (newhan.error < 0) { + clone_error = newhan.error; + free_cms(set2); + goto loop; + } + } else { + cpumemmap_t *map2 = clone_cmm(new_cmm); + if (map2 == 0) { + clone_error = -ENOMEM; + goto loop; + } + newhan = cmsNewHandleOldSetNewMap( + oldhan.set, map2); + if (newhan.error < 0) { + clone_error = newhan.error; + free_cmm(map2); + goto loop; + } + } + err = cmm_restrict_checking(oldhan.map, newhan.map); + if (err < 0) { + bind_error = err; + cmsdrophandle(newhan); + goto loop; + } + vma->vm_mems_allowed = mems_allowed_build(newhan.set); + loop: + prev_end = vma->vm_end; + vma = vma->vm_next; + } + if (prev_end < end) + fault_error = -EFAULT; + error = clone_error ? clone_error : + bind_error ? bind_error : + fault_error ? fault_error : + 0; + cmsReleaseHandle(oldhan); + done2: + vma_remerge_range(current->mm, start, len); + done: + up_write(¤t->mm->mmap_sem); + if (cmm_or_cms == cms_target) + free_cms(new_cms); + else + free_cmm(new_cmm); + } else { + if (choice == CMS_KERNEL) { + if (!capable(CAP_SYS_ADMIN)) { + error = -EPERM; + goto out1; + } + oldhan = cmsGetHandleKern(); + if (oldhan.error < 0) { + error = oldhan.error; + goto out1; + } + } else { + oldhan = cmsGetHandlePid(choice, pid, 1); + if (oldhan.error < 0) { + error = oldhan.error; + goto out1; + } + } + if (cmm_or_cms == cms_target) + newhan = cmsNewHandleNewSetOldMap(new_cms, oldhan.map); + else + newhan = cmsNewHandleOldSetNewMap(oldhan.set, new_cmm); + + if (newhan.error < 0) { + error = newhan.error; + goto out2; + } + error = cmm_restrict_checking(oldhan.map, newhan.map); + if (error < 0) + goto out3; + newhan.set->mems_allowed = mems_allowed_build(newhan.set); + /* success */ + if (choice == CMS_KERNEL) + cmsExchangeKern(oldhan, newhan); + else + cmsExchangePid(oldhan, newhan, choice, pid); + goto out0; + + out3: + cmsdrophandle(newhan); + out2: + cmsReleaseHandle(oldhan); + out1: + if (cmm_or_cms == cms_target) + free_cms(new_cms); + else + free_cmm(new_cmm); + out0: + } + return error; +} + +int +cms_set_cms(unsigned long *preq, char *rec, int size) +{ + return cms_set(preq, rec, size, cms_target); +} + +int +cms_set_cmm(unsigned long *preq, char *rec, int size) +{ + return cms_set(preq, rec, size, cmm_target); +} + +int +cms_getcpu(void) +{ + cmshandle_t han; + cpumemmap_t *cmm; + cms_scpu_t mysyscpu = smp_processor_id(); + cms_acpu_t myappcpu = 0; /* White lie appcpu is 0 */ + int i; + + /* + * Return what app cpu we're running on, which is the + * index into our cpumemmap of the sys cpu we're on. + * Given the injective_map check above, there should be + * only one such entry, but we don't verify that here. + * Rather, we just take the first matching entry. If no + * entries on map for our current cpu, we tell a white + * lie and return app cpu 0 (API provides no way to tell + * hapless user they are running where its unmapped). + */ + + han = cmsGetHandlePid(CMS_CURRENT, (pid_t)0, 0); + cmm = han.map; + for (i = 0; i < cmm->nr_cpus; i++) { + if (mysyscpu == cmm->cpus[i]) { + myappcpu = i; + break; + } + } + cmsReleaseHandle(han); + return myappcpu; +} diff -Nur linux-2.4.19/kernel/csa.c linux-2.4.19-sgi211r3/kernel/csa.c --- linux-2.4.19/kernel/csa.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kernel/csa.c Tue Oct 22 03:48:45 2002 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2000-2002 Silicon Graphics, Inc and LANL All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + */ + +/* + * Description: + * This file (kernel/csa.c) contains the procedures to handle kernel CSA + * job accounting. The drivers/misc/csa_job_acct.c code does the real work. + * That code can be either built into the kernel or compiled as a loadable + * module. When that code is initialized, it registers here with its + * procedure callbacks. The acctctl syscall processing and + * the request to write CSA accounting records comes into here + * and is handed off to the csa_job_acct.c code via the procedure + * callbacks. + * + * Author: + * Marlys Kohnke (kohnke@sgi.com) + * + * Contributors: + * + * Changes: + * February 2, 2001 (kohnke) Modified to handle the csa_job_acct.c code + * compiled into the kernel or compiled as a loadable module + */ + +#include + +#if defined (CONFIG_CSA_JOB_ACCT) || defined (CONFIG_CSA_JOB_ACCT_MODULE) + +#include +#include +#include +#include + +static struct csa_module_s csa_operations = { + NULL, /* do_acctctl */ + NULL, /* do_csa_acct */ + NULL /* pointer to kernel module struct for CSA module */ +}; +static struct csa_module_s *csa_op = &csa_operations; +static int csa_registered = 0; + +/* + * register_csa + * + * The CSA csa_job_acct.c code calls this during initialization to set its + * procedure callback addresses: + * + * do_acctctl(): processing of the acctctl syscall + * do_csa_acct(): write a CSA record when a task exits + */ +int +register_csa(struct csa_module_s *csa_callbacks) +{ + + char *func_id = "register_csa"; + + if (csa_callbacks == (struct csa_module_s *)NULL) { + return -EINVAL; + } + + if (csa_registered) { + /* + * incorrectly using csa_job_acct.c as a loadable module and + * compiled into the kernel?? + */ + printk(KERN_WARNING "%s: %s\n", + func_id, "Multiple attempts to register CSA support\n"); + return -EBUSY; + } else { + csa_registered = 1; + } + + memcpy((char *)csa_op, (char *)csa_callbacks, + sizeof(struct csa_module_s)); + + printk(KERN_INFO "%s: %s\n", func_id, "CSA support registered"); + + return 0; +} + +void +unregister_csa() +{ + char *func_id = "unregister_csa"; + + memset((char *)csa_op, 0, sizeof(struct csa_module_s)); + csa_registered = 0; + + printk(KERN_INFO "%s: %s\n", func_id, "CSA support unregistered"); +} + +/* + * This is the acctctl syscall. The two arguments are passed to the CSA + * csa_job_acct.c code for processing. Use the module use count to prevent the + * CSA module from being unloaded during processing. + */ +asmlinkage int +sys_acctctl(int req, void *act) +{ + int ret; + + if (csa_op->do_acctctl == NULL) { + /* the CSA csa_job_acct.c code hasn't registered yet */ + return -ENOSYS; + } else { + if (csa_op->module) { + __MOD_INC_USE_COUNT(csa_op->module); + } + ret = csa_op->do_acctctl(req, act); + if (csa_op->module) { + __MOD_DEC_USE_COUNT(csa_op->module); + } + } + return ret; +} + +/* + * This is the wrapper for the CSA end-of-process accounting record, which + * is written by the CSA csa_job_acct.c code when a task within a job exits. + * Use the module use count to prevent the CSA module from being + * unloaded during processing. + */ +void +csa_acct(int exitcode, struct task_struct *p) +{ + + if (csa_op->do_csa_acct != NULL) { + if (csa_op->module) { + __MOD_INC_USE_COUNT(csa_op->module); + } + csa_op->do_csa_acct(exitcode, p); + if (csa_op->module) { + __MOD_DEC_USE_COUNT(csa_op->module); + } + } +} + +#endif diff -Nur linux-2.4.19/kernel/exec_domain.c linux-2.4.19-sgi211r3/kernel/exec_domain.c --- linux-2.4.19/kernel/exec_domain.c Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-sgi211r3/kernel/exec_domain.c Fri Apr 26 11:07:18 2002 @@ -196,8 +196,10 @@ put_exec_domain(oep); +#if 0 printk(KERN_DEBUG "[%s:%d]: set personality to %lx\n", current->comm, current->pid, personality); +#endif return 0; } diff -Nur linux-2.4.19/kernel/exit.c linux-2.4.19-sgi211r3/kernel/exit.c --- linux-2.4.19/kernel/exit.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/exit.c Mon Oct 28 20:43:23 2002 @@ -13,9 +13,11 @@ #include #include #include +#include #ifdef CONFIG_BSD_PROCESS_ACCT #include #endif +#include #include #include @@ -28,49 +30,24 @@ static void release_task(struct task_struct * p) { - if (p != current) { + if (p == current) + BUG(); #ifdef CONFIG_SMP - /* - * Wait to make sure the process isn't on the - * runqueue (active on some other CPU still) - */ - for (;;) { - task_lock(p); - if (!task_has_cpu(p)) - break; - task_unlock(p); - do { - cpu_relax(); - barrier(); - } while (task_has_cpu(p)); - } - task_unlock(p); + wait_task_inactive(p); #endif - atomic_dec(&p->user->processes); - free_uid(p->user); - unhash_process(p); - - release_thread(p); - current->cmin_flt += p->min_flt + p->cmin_flt; - current->cmaj_flt += p->maj_flt + p->cmaj_flt; - current->cnswap += p->nswap + p->cnswap; - /* - * Potentially available timeslices are retrieved - * here - this way the parent does not get penalized - * for creating too many processes. - * - * (this cannot be used to artificially 'generate' - * timeslices, because any timeslice recovered here - * was given away by the parent in the first place.) - */ - current->counter += p->counter; - if (current->counter >= MAX_COUNTER) - current->counter = MAX_COUNTER; - p->pid = 0; - free_task_struct(p); - } else { - printk("task releasing itself\n"); - } + CMS_FREE_TASK(p); + + atomic_dec(&p->user->processes); + free_uid(p->user); + unhash_process(p); + + release_thread(p); + current->cmin_flt += p->min_flt + p->cmin_flt; + current->cmaj_flt += p->maj_flt + p->cmaj_flt; + current->cnswap += p->nswap + p->cnswap; + sched_exit(p); + p->pid = 0; + free_task_struct(p); } /* @@ -150,6 +127,79 @@ return retval; } +/** + * reparent_to_init() - Reparent the calling kernel thread to the init task. + * + * If a kernel thread is launched as a result of a system call, or if + * it ever exits, it should generally reparent itself to init so that + * it is correctly cleaned up on exit. + * + * The various task state such as scheduling policy and priority may have + * been inherited from a user process, so we reset them to sane values here. + * + * NOTE that reparent_to_init() gives the caller full capabilities. + */ +void reparent_to_init(void) +{ + write_lock_irq(&tasklist_lock); + + /* Reparent to init */ + REMOVE_LINKS(current); + current->p_pptr = child_reaper; + current->p_opptr = child_reaper; + SET_LINKS(current); + + /* Set the exit signal to SIGCHLD so we signal init on exit */ + current->exit_signal = SIGCHLD; + + current->ptrace = 0; + if ((current->policy == SCHED_OTHER) && (task_nice(current) < 0)) + set_user_nice(current, 0); + /* cpus_allowed? */ + /* rt_priority? */ + /* signals? */ + current->cap_effective = CAP_INIT_EFF_SET; + current->cap_inheritable = CAP_INIT_INH_SET; + current->cap_permitted = CAP_FULL_SET; + current->keep_capabilities = 0; + memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim))); + current->user = INIT_USER; + + write_unlock_irq(&tasklist_lock); +} + +/* + * Put all the gunge required to become a kernel thread without + * attached user resources in one place where it belongs. + */ + +void daemonize(void) +{ + struct fs_struct *fs; + + + /* + * If we were started as result of loading a module, close all of the + * user space pages. We don't need them, and if we didn't close them + * they would be locked into memory. + */ + exit_mm(current); + + current->session = 1; + current->pgrp = 1; + current->tty = NULL; + + /* Become as one with the init task */ + + exit_fs(current); /* current->fs->count--; */ + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); + exit_files(current); + current->files = init_task.files; + atomic_inc(¤t->files->count); +} + /* * When we die, we re-parent all our children. * Try to give them to another thread in our thread @@ -450,12 +500,16 @@ del_timer_sync(&tsk->real_timer); fake_volatile: + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_acct(code, tsk); __exit_mm(tsk); - lock_kernel(); sem_exit(); __exit_files(tsk); __exit_fs(tsk); @@ -471,7 +525,18 @@ __MOD_DEC_USE_COUNT(tsk->binfmt->module); tsk->exit_code = code; + + /* + * If config'd for PAGG support: + * call pagg modules to detach + * from process aggregates to which the current process is + * attached. + * Else + * This is a no-op. + */ + detach_pagg_list_chk(tsk); exit_notify(); + schedule(); BUG(); /* diff -Nur linux-2.4.19/kernel/fork.c linux-2.4.19-sgi211r3/kernel/fork.c --- linux-2.4.19/kernel/fork.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/fork.c Thu Feb 13 10:27:52 2003 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,6 @@ /* The idle threads do not count.. */ int nr_threads; -int nr_running; int max_threads; unsigned long total_forks; /* Handle normal Linux uptimes. */ @@ -38,6 +38,8 @@ struct task_struct *pidhash[PIDHASH_SZ]; +rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ + void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -78,6 +80,13 @@ init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2; + + /* + * If Process Aggregates (paggs) are compiled into the kernel, we + * need to initialize the PID 0 before it can clone itself. + * This is a no-op if paggs are not compiled into the kernel. + */ + INIT_PAGG_LIST(¤t->pagg_list); } /* Protects next_safe and last_pid. */ @@ -175,6 +184,7 @@ if (!tmp) goto fail_nomem; *tmp = *mpnt; + tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; tmp->vm_next = NULL; @@ -363,6 +373,9 @@ */ copy_segments(tsk, mm); + mm->hiwater_rss = mm->rss; + mm->hiwater_vm = mm->total_vm; + good_mm: tsk->mm = mm; tsk->active_mm = mm; @@ -638,8 +651,7 @@ if (p->pid == 0 && current->pid != 0) goto bad_fork_cleanup; - p->run_list.next = NULL; - p->run_list.prev = NULL; + INIT_LIST_HEAD(&p->run_list); p->p_cptr = NULL; init_waitqueue_head(&p->wait_chldexit); @@ -649,6 +661,7 @@ init_completion(&vfork); } spin_lock_init(&p->alloc_lock); + spin_lock_init(&p->switch_lock); p->sigpending = 0; init_sigpending(&p->pending); @@ -662,17 +675,26 @@ p->tty_old_pgrp = 0; p->times.tms_utime = p->times.tms_stime = 0; p->times.tms_cutime = p->times.tms_cstime = 0; + p->rchar = p->wchar = p->rblk = p->wblk = p->syscr = p->syscw = 0; + p->bwtime = 0; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_clear_integrals(p); #ifdef CONFIG_SMP { int i; - p->cpus_runnable = ~0UL; - p->processor = current->processor; + + if (likely(p->cpus_allowed & (1UL<cpu = smp_processor_id(); + else + p->cpu = __ffs(p->cpus_allowed); /* ?? should we just memset this ?? */ for(i = 0; i < smp_num_cpus; i++) - p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + p->per_cpu_utime[cpu_logical_map(i)] = + p->per_cpu_stime[cpu_logical_map(i)] = 0; spin_lock_init(&p->sigmask_lock); } #endif + p->array = NULL; p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; @@ -695,26 +717,49 @@ goto bad_fork_cleanup_namespace; p->semundo = NULL; + SET_CHILD_CMS(p, current); + /* Our parent execution domain becomes current domain These must match for thread signalling to apply */ p->parent_exec_id = p->self_exec_id; + /* + * If config'd for PAGG support: + * call pagg modules to properly attach new process + * to the same process aggregate containers as the + * parent process. + * Else + * this is a no-op. + */ + attach_pagg_list_chk(p, current, clone_flags); + /* ok, now we should be set up.. */ p->swappable = 1; p->exit_signal = clone_flags & CSIGNAL; p->pdeath_signal = 0; /* - * "share" dynamic priority between parent and child, thus the - * total amount of dynamic priorities in the system doesnt change, - * more scheduling fairness. This is only important in the first - * timeslice, on the long run the scheduling behaviour is unchanged. - */ - p->counter = (current->counter + 1) >> 1; - current->counter >>= 1; - if (!current->counter) - current->need_resched = 1; + * Share the timeslice between parent and child, thus the + * total amount of pending timeslices in the system doesnt change, + * resulting in more scheduling fairness. + */ + __cli(); + if (!current->time_slice) + BUG(); + p->time_slice = (current->time_slice + 1) >> 1; + current->time_slice >>= 1; + if (!current->time_slice) { + /* + * This case is rare, it happens when the parent has only + * a single jiffy left from its timeslice. Taking the + * runqueue lock is not a problem. + */ + current->time_slice = 1; + scheduler_tick(0,0); + } + p->sleep_timestamp = jiffies; + __sti(); /* * Ok, add it to the run-queues and make it @@ -751,10 +796,23 @@ if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); +#define RUN_CHILD_FIRST 1 +#if RUN_CHILD_FIRST + wake_up_forked_process(p); /* do this last */ +#else wake_up_process(p); /* do this last */ +#endif ++total_forks; if (clone_flags & CLONE_VFORK) wait_for_completion(&vfork); +#if RUN_CHILD_FIRST + else + /* + * Let the child process run first, to avoid most of the + * COW overhead when the child exec()s afterwards. + */ + resched_cpu(p->cpu); +#endif fork_out: return retval; diff -Nur linux-2.4.19/kernel/kallsyms.c linux-2.4.19-sgi211r3/kernel/kallsyms.c --- linux-2.4.19/kernel/kallsyms.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kernel/kallsyms.c Tue Feb 4 15:36:30 2003 @@ -0,0 +1,420 @@ +/* An example of using kallsyms data in a kernel debugger. + + Copyright 2000 Keith Owens April 2000 + + This file is part of the Linux modutils. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + This code uses the list of all kernel and module symbols to :- + + * Find any non-stack symbol in a kernel or module. Symbols do + not have to be exported for debugging. + + * Convert an address to the module (or kernel) that owns it, the + section it is in and the nearest symbol. This finds all non-stack + symbols, not just exported ones. + + You need modutils >= 2.3.11 and a kernel with the kallsyms patch + which was compiled with CONFIG_KALLSYMS. + */ + +#include +#include +#include +#include +#include +#include + +/* These external symbols are only set on kernels compiled with + * CONFIG_KALLSYMS. + */ + +extern const char __start___kallsyms[]; +extern const char __stop___kallsyms[]; + +static struct module **kallsyms_module_list; + +static void kallsyms_get_module_list(void) +{ + const struct kallsyms_header *ka_hdr; + const struct kallsyms_section *ka_sec; + const struct kallsyms_symbol *ka_sym; + const char *ka_str; + int i; + const char *p; + + if (__start___kallsyms >= __stop___kallsyms) + return; + ka_hdr = (struct kallsyms_header *)__start___kallsyms; + ka_sec = (struct kallsyms_section *) + ((char *)(ka_hdr) + ka_hdr->section_off); + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + + for (i = 0; i < ka_hdr->symbols; kallsyms_next_sym(ka_hdr, ka_sym), ++i) { + p = ka_str + ka_sym->name_off; + if (strcmp(p, "module_list") == 0) { + if (ka_sym->symbol_addr) + kallsyms_module_list = (struct module **)(ka_sym->symbol_addr); + break; + } + } +} + +static inline void kallsyms_do_first_time(void) +{ + static int first_time = 1; + if (first_time) + kallsyms_get_module_list(); + first_time = 0; +} + +/* A symbol can appear in more than one module. A token is used to + * restart the scan at the next module, set the token to 0 for the + * first scan of each symbol. + */ + +int kallsyms_symbol_to_address( + const char *name, /* Name to lookup */ + unsigned long *token, /* Which module to start at */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec; + const struct kallsyms_symbol *ka_sym = NULL; + const char *ka_str = NULL; + const struct module *m; + int i = 0, l; + const char *p, *pt_R; + char *p2; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + /* Restart? */ + m = *kallsyms_module_list; + if (token && *token) { + for (; m; m = m->next) + if ((unsigned long)m == *token) + break; + if (m) + m = m->next; + } + + for (; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + p = ka_str + ka_sym->name_off; + if (strcmp(p, name) == 0) + break; + /* Unversioned requests match versioned names */ + if (!(pt_R = strstr(p, "_R"))) + continue; + l = strlen(pt_R); + if (l < 10) + continue; /* Not _R.*xxxxxxxx */ + (void)simple_strtoul(pt_R+l-8, &p2, 16); + if (*p2) + continue; /* Not _R.*xxxxxxxx */ + if (strncmp(p, name, pt_R-p) == 0) + break; /* Match with version */ + } + if (i < ka_hdr->symbols) + break; + } + + if (token) + *token = (unsigned long)m; + if (!m) + return(0); /* not found */ + + ka_sec = (const struct kallsyms_section *) + ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off); + *mod_name = *(m->name) ? m->name : "kernel"; + *mod_start = ka_hdr->start; + *mod_end = ka_hdr->end; + *sec_name = ka_sec->name_off + ka_str; + *sec_start = ka_sec->start; + *sec_end = ka_sec->start + ka_sec->size; + *sym_name = ka_sym->name_off + ka_str; + *sym_start = ka_sym->symbol_addr; + if (i < ka_hdr->symbols-1) { + const struct kallsyms_symbol *ka_symn = ka_sym; + kallsyms_next_sym(ka_hdr, ka_symn); + *sym_end = ka_symn->symbol_addr; + } + else + *sym_end = *sec_end; + return(1); +} + +int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec = NULL; + const struct kallsyms_symbol *ka_sym; + const char *ka_str; + const struct module *m; + int i; + unsigned long end; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sec = (const struct kallsyms_section *) + ((char *)ka_hdr + ka_hdr->section_off); + /* Is the address in any section in this module? */ + for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) { + if (ka_sec->start <= address && + (ka_sec->start + ka_sec->size) > address) + break; + } + if (i < ka_hdr->sections) + break; /* Found a matching section */ + } + + if (!m) + return(0); /* not found */ + + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + *mod_name = *(m->name) ? m->name : "kernel"; + *mod_start = ka_hdr->start; + *mod_end = ka_hdr->end; + *sec_name = ka_sec->name_off + ka_str; + *sec_start = ka_sec->start; + *sec_end = ka_sec->start + ka_sec->size; + *sym_name = *sec_name; /* In case we find no matching symbol */ + *sym_start = *sec_start; + *sym_end = *sec_end; + + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + if (ka_sym->symbol_addr > address) + continue; + if (i < ka_hdr->symbols-1) { + const struct kallsyms_symbol *ka_symn = ka_sym; + kallsyms_next_sym(ka_hdr, ka_symn); + end = ka_symn->symbol_addr; + } + else + end = *sec_end; + if (end <= address) + continue; + if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off + != (char *)ka_sec) + continue; /* wrong section */ + *sym_name = ka_str + ka_sym->name_off; + *sym_start = ka_sym->symbol_addr; + *sym_end = end; + break; + } + return(1); +} + +/* List all sections in all modules. The callback routine is invoked with + * token, module name, section name, section start, section end, section flags. + */ +int kallsyms_sections(void *token, + int (*callback)(void *, const char *, const char *, ElfW(Addr), ElfW(Addr), ElfW(Word))) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec = NULL; + const char *ka_str; + const struct module *m; + int i; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sec = (const struct kallsyms_section *) ((char *)ka_hdr + ka_hdr->section_off); + ka_str = ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) { + if (callback( + token, + *(m->name) ? m->name : "kernel", + ka_sec->name_off + ka_str, + ka_sec->start, + ka_sec->start + ka_sec->size, + ka_sec->flags)) + return(0); + } + } + return(1); +} + + +/* paramter prefix_name is a buffer provided by the caller, it must ends with '\0'. */ +/* return the extra string together with the given prefix of a symbol name. */ +/* return 0 means no prefix string is found. */ +/* return >0 means prefix string is found. */ +int kallsyms_symbol_complete( + char *prefix_name /* Prefix of a symbol name to lookup */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_symbol *ka_sym = NULL; + const char *ka_str = NULL; + const struct module *m; + int i = 0; + int prefix_len=strlen(prefix_name); + int cur_pos=0, last_pos=0; + int find=0; + int number=0; + const char *p; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + p = ka_str + ka_sym->name_off; + if (strncmp(p, prefix_name,prefix_len) == 0) { + ++number; + if (find == 0) { + last_pos = strlen(p); + strncpy(prefix_name, p, last_pos+1); + find = 1; + } + else { + for (cur_pos = prefix_len ; cur_pos < last_pos; cur_pos++) { + if (*(p + cur_pos) == '\0' + || *(p + cur_pos) != prefix_name[cur_pos]) { + last_pos = cur_pos; + prefix_name[cur_pos] = '\0'; + break; + } + } + } + } + } + } + + return number; +} + +/* paramter prefix_name is a buffer provided by the caller, it must ends with '\0'. */ +/* parameter flag = 0 means search from the head, flag = 1 means continue search. */ +/* return a symbol string which matches the given prefix. */ +/* return 0 means no prefix string is found. */ +/* return >0 means prefix string is found. */ +int kallsyms_symbol_next( + char *prefix_name, /* Prefix of a symbol name to lookup */ + int flag /* Indicate if search from the head */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const char *ka_str = NULL; + static const struct kallsyms_symbol *ka_sym; + static const struct module *m; + static int i; + int prefix_len=strlen(prefix_name); + const char *p; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + if(!flag) { + m = *kallsyms_module_list; + } + + for (; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + if(!flag) { + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + i = 0; + } + ka_str = ((char *)(ka_hdr) + ka_hdr->string_off); + + for (; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + p = ka_str + ka_sym->name_off; + if (strncmp(p, prefix_name,prefix_len) == 0) { + strncpy(prefix_name, p, strlen(p)+1); + ++i; + kallsyms_next_sym(ka_hdr, ka_sym); + return 1; + } + } + } + + return 0; +} + + diff -Nur linux-2.4.19/kernel/ksyms.c linux-2.4.19-sgi211r3/kernel/ksyms.c --- linux-2.4.19/kernel/ksyms.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/ksyms.c Fri Dec 13 10:22:56 2002 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include #if defined(CONFIG_PROC_FS) @@ -55,6 +57,11 @@ #ifdef CONFIG_KMOD #include #endif +#ifdef CONFIG_KALLSYMS +#include +#endif +#include +#include extern void set_device_ro(kdev_t dev,int flag); @@ -64,6 +71,7 @@ extern int request_dma(unsigned int dmanr, char * deviceID); extern void free_dma(unsigned int dmanr); extern spinlock_t dma_spin_lock; +extern int panic_timeout; #ifdef CONFIG_MODVERSIONS const struct module_symbol __export_Using_Versions @@ -80,6 +88,15 @@ EXPORT_SYMBOL(inter_module_put); EXPORT_SYMBOL(try_inc_mod_count); +#ifdef CONFIG_KALLSYMS +extern const char __start___kallsyms[]; +extern const char __stop___kallsyms[]; +EXPORT_SYMBOL(__start___kallsyms); +EXPORT_SYMBOL(__stop___kallsyms); +EXPORT_SYMBOL(kallsyms_symbol_to_address); +EXPORT_SYMBOL(kallsyms_address_to_symbol); +#endif + /* process memory management */ EXPORT_SYMBOL(do_mmap_pgoff); EXPORT_SYMBOL(do_munmap); @@ -88,9 +105,13 @@ EXPORT_SYMBOL(exit_files); EXPORT_SYMBOL(exit_fs); EXPORT_SYMBOL(exit_sighand); +EXPORT_SYMBOL(zap_page_range); /* internal kernel memory management */ +EXPORT_SYMBOL(start_aggressive_readahead); +#ifndef CONFIG_DISCONTIGMEM EXPORT_SYMBOL(_alloc_pages); +#endif EXPORT_SYMBOL(__alloc_pages); EXPORT_SYMBOL(alloc_pages_node); EXPORT_SYMBOL(__get_free_pages); @@ -104,10 +125,12 @@ EXPORT_SYMBOL(kmem_cache_shrink); EXPORT_SYMBOL(kmem_cache_alloc); EXPORT_SYMBOL(kmem_cache_free); +EXPORT_SYMBOL(kmem_cache_size); EXPORT_SYMBOL(kmalloc); EXPORT_SYMBOL(kfree); EXPORT_SYMBOL(vfree); EXPORT_SYMBOL(__vmalloc); +EXPORT_SYMBOL(vmap); EXPORT_SYMBOL(vmalloc_to_page); EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(remap_page_range); @@ -117,6 +140,8 @@ EXPORT_SYMBOL(find_vma); EXPORT_SYMBOL(get_unmapped_area); EXPORT_SYMBOL(init_mm); +EXPORT_SYMBOL(mmput); +EXPORT_SYMBOL(numnodes); #ifdef CONFIG_HIGHMEM EXPORT_SYMBOL(kmap_high); EXPORT_SYMBOL(kunmap_high); @@ -136,8 +161,10 @@ EXPORT_SYMBOL(fget); EXPORT_SYMBOL(igrab); EXPORT_SYMBOL(iunique); -EXPORT_SYMBOL(iget4); +EXPORT_SYMBOL(iget4_locked); +EXPORT_SYMBOL(unlock_new_inode); EXPORT_SYMBOL(iput); +EXPORT_SYMBOL(inode_init_once); EXPORT_SYMBOL(force_delete); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(follow_down); @@ -150,6 +177,7 @@ EXPORT_SYMBOL(lookup_hash); EXPORT_SYMBOL(sys_close); EXPORT_SYMBOL(dcache_lock); +EXPORT_SYMBOL(dparent_lock); EXPORT_SYMBOL(d_alloc_root); EXPORT_SYMBOL(d_delete); EXPORT_SYMBOL(dget_locked); @@ -217,6 +245,7 @@ EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(do_generic_file_read); EXPORT_SYMBOL(generic_file_write); +EXPORT_SYMBOL(generic_file_write_nolock); EXPORT_SYMBOL(generic_file_mmap); EXPORT_SYMBOL(generic_ro_fops); EXPORT_SYMBOL(generic_buffer_fdatasync); @@ -241,6 +270,7 @@ EXPORT_SYMBOL(find_inode_number); EXPORT_SYMBOL(is_subdir); EXPORT_SYMBOL(get_unused_fd); +EXPORT_SYMBOL(put_unused_fd); EXPORT_SYMBOL(vfs_create); EXPORT_SYMBOL(vfs_mkdir); EXPORT_SYMBOL(vfs_mknod); @@ -252,12 +282,14 @@ EXPORT_SYMBOL(vfs_statfs); EXPORT_SYMBOL(generic_read_dir); EXPORT_SYMBOL(generic_file_llseek); +EXPORT_SYMBOL(remote_llseek); EXPORT_SYMBOL(no_llseek); EXPORT_SYMBOL(__pollwait); EXPORT_SYMBOL(poll_freewait); EXPORT_SYMBOL(ROOT_DEV); EXPORT_SYMBOL(__find_get_page); EXPORT_SYMBOL(__find_lock_page); +EXPORT_SYMBOL(find_or_create_page); EXPORT_SYMBOL(grab_cache_page); EXPORT_SYMBOL(grab_cache_page_nowait); EXPORT_SYMBOL(read_cache_page); @@ -359,6 +391,22 @@ EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); EXPORT_SYMBOL(proc_doulongvec_minmax); +/* dump (system crash dump) functions and needed parameters */ +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +EXPORT_SYMBOL(get_blkfops); +EXPORT_SYMBOL(dump_function_ptr); +#if defined(CONFIG_X86) || defined(CONFIG_ALPHA) +EXPORT_SYMBOL(page_is_ram); +#endif +EXPORT_SYMBOL(dump_started); +EXPORT_SYMBOL(dump_in_progress); +EXPORT_SYMBOL(dumping_cpu); +EXPORT_SYMBOL(panic_timeout); +EXPORT_SYMBOL(register_dump_notifier); +EXPORT_SYMBOL(unregister_dump_notifier); +EXPORT_SYMBOL(dump_notifier_list); +#endif + /* interrupt handling */ EXPORT_SYMBOL(add_timer); EXPORT_SYMBOL(del_timer); @@ -439,7 +487,9 @@ /* process management */ EXPORT_SYMBOL(complete_and_exit); EXPORT_SYMBOL(__wake_up); +#ifdef CONFIG_SMP EXPORT_SYMBOL(__wake_up_sync); +#endif EXPORT_SYMBOL(wake_up_process); EXPORT_SYMBOL(sleep_on); EXPORT_SYMBOL(sleep_on_timeout); @@ -448,6 +498,10 @@ EXPORT_SYMBOL(schedule); EXPORT_SYMBOL(schedule_timeout); EXPORT_SYMBOL(sys_sched_yield); +EXPORT_SYMBOL(set_user_nice); +#ifdef CONFIG_SMP +EXPORT_SYMBOL(set_cpus_allowed); +#endif EXPORT_SYMBOL(jiffies); EXPORT_SYMBOL(xtime); EXPORT_SYMBOL(do_gettimeofday); @@ -459,6 +513,7 @@ EXPORT_SYMBOL(kstat); EXPORT_SYMBOL(nr_running); +EXPORT_SYMBOL(nr_context_switches); /* misc */ EXPORT_SYMBOL(panic); @@ -497,6 +552,7 @@ EXPORT_SYMBOL(seq_release); EXPORT_SYMBOL(seq_read); EXPORT_SYMBOL(seq_lseek); +EXPORT_SYMBOL(ipcperms); /* Program loader interfaces */ EXPORT_SYMBOL(setup_arg_pages); @@ -508,6 +564,24 @@ /* Miscellaneous access points */ EXPORT_SYMBOL(si_meminfo); +#if defined(CONFIG_PAGG) +EXPORT_SYMBOL(get_pagg); +EXPORT_SYMBOL(alloc_pagg); +EXPORT_SYMBOL(free_pagg); +EXPORT_SYMBOL(attach_pagg_list); +EXPORT_SYMBOL(detach_pagg_list); +EXPORT_SYMBOL(register_pagg_hook); +EXPORT_SYMBOL(unregister_pagg_hook); +#endif + +/* job accounting */ +#if defined(CONFIG_CSA_JOB_ACCT) || defined(CONFIG_CSA_JOB_ACCT_MODULE) +EXPORT_SYMBOL(register_csa); +EXPORT_SYMBOL(unregister_csa); +EXPORT_SYMBOL(csa_acct); +#endif + + /* Added to make file system as module */ EXPORT_SYMBOL(sys_tz); @@ -518,7 +592,7 @@ EXPORT_SYMBOL(init_special_inode); EXPORT_SYMBOL(read_ahead); EXPORT_SYMBOL(get_hash_table); -EXPORT_SYMBOL(get_empty_inode); +EXPORT_SYMBOL(new_inode); EXPORT_SYMBOL(insert_inode_hash); EXPORT_SYMBOL(remove_inode_hash); EXPORT_SYMBOL(buffer_insert_inode_queue); @@ -570,3 +644,15 @@ EXPORT_SYMBOL(tasklist_lock); EXPORT_SYMBOL(pidhash); + +/* debug */ +EXPORT_SYMBOL(dump_stack); + +#if defined(CONFIG_KDB_USB) +#include +EXPORT_SYMBOL(kdb_usb_infos); +#endif + +/* To match ksyms with System.map */ +extern const char _end[]; +EXPORT_SYMBOL(_end); diff -Nur linux-2.4.19/kernel/module.c linux-2.4.19-sgi211r3/kernel/module.c --- linux-2.4.19/kernel/module.c Sun Nov 11 11:23:14 2001 +++ linux-2.4.19-sgi211r3/kernel/module.c Sun Dec 15 19:24:50 2002 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -307,6 +308,11 @@ error = -EINVAL; goto err1; } + if ((size >> PAGE_SHIFT) > num_physpages) { + error = -ENOMEM; + goto err1; + } + if (find_module(name) != NULL) { error = -EEXIST; goto err1; @@ -1235,6 +1241,30 @@ show: s_show }; +#define MODLIST_SIZE 4096 + +/* + * this function isn't smp safe but that's not really a problem; it's + * called from oops context only and any locking could actually prevent + * the oops from going out; the line that is generated is informational + * only and should NEVER prevent the real oops from going out. + */ +void print_modules(void) +{ + static char modlist[MODLIST_SIZE]; + struct module *this_mod; + int pos = 0; + + this_mod = module_list; + while (this_mod) { + if (this_mod->name) + pos += snprintf(modlist+pos, MODLIST_SIZE-pos-1, + "%s ", this_mod->name); + this_mod = this_mod->next; + } + printk("%s\n",modlist); +} + #else /* CONFIG_MODULES */ /* Dummy syscalls for people who don't want modules */ @@ -1280,4 +1310,81 @@ return 1; } +void print_modules(void) +{ +} + #endif /* CONFIG_MODULES */ + + +#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) + +#define MAX_SYMBOL_SIZE 512 + +static void +address_to_exported_symbol(unsigned long address, const char **mod_name, + const char **sym_name, unsigned long *sym_start, + unsigned long *sym_end) +{ + struct module *this_mod; + int i; + + for (this_mod = module_list; this_mod; this_mod = this_mod->next) { + /* walk the symbol list of this module. Only symbols + who's address is smaller than the searched for address + are relevant; and only if it's better than the best so far */ + for (i = 0; i < this_mod->nsyms; i++) + if ((this_mod->syms[i].value <= address) && + (*sym_start < this_mod->syms[i].value)) { + *sym_start = this_mod->syms[i].value; + *sym_name = this_mod->syms[i].name; + *mod_name = this_mod->name; + if (i + 1 < this_mod->nsyms) + *sym_end = this_mod->syms[i+1].value; + else + *sym_end = (unsigned long) this_mod + this_mod->size; + } + } +} + +void +print_symbol(const char *fmt, unsigned long address) +{ + /* static to not take up stackspace; if we race here too bad */ + static char buffer[MAX_SYMBOL_SIZE]; + + const char *mod_name = NULL, *sec_name = NULL, *sym_name = NULL; + unsigned long mod_start, mod_end, sec_start, sec_end, + sym_start, sym_end; + char *tag = ""; + + memset(buffer, 0, MAX_SYMBOL_SIZE); + + sym_start = 0; + if (!kallsyms_address_to_symbol(address, &mod_name, &mod_start, &mod_end, &sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) { + tag = "E "; + address_to_exported_symbol(address, &mod_name, &sym_name, &sym_start, &sym_end); + } + + if (sym_start) { + if (*mod_name) + snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x [%s]", + tag, sym_name, + (unsigned int)(address - sym_start), + (unsigned int)(sym_end - sym_start), + mod_name); + else + snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x", + tag, sym_name, + (unsigned int)(address - sym_start), + (unsigned int)(sym_end - sym_start)); + printk(fmt, buffer); + } +#if 0 + else { + printk(fmt, "[unresolved]"); + } +#endif +} + +#endif diff -Nur linux-2.4.19/kernel/pagg.c linux-2.4.19-sgi211r3/kernel/pagg.c --- linux-2.4.19/kernel/pagg.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kernel/pagg.c Tue Oct 22 03:48:45 2002 @@ -0,0 +1,585 @@ +/* + * PAGG (Process Aggregates) interface + * + * + * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + * + * Description: This file, kernel/pagg.c, contains the routines used + * to implement process aggregates (paggs). The pagg + * extends the task_struct to allow for various process + * aggregation continers. Examples of such containers + * include "jobs" and cluster applications IDs. Process + * sessions and groups could have been implemented using + * paggs (although there would be little purpose in + * making that change at this juncture). The pagg + * structure maintains pointers to callback functions and + * data strucures maintained in modules that have + * registered with the kernel as pagg container + * providers. + * + * Created: 2000.05.23 Sam Watters + * + * Changes: 2001.01.30 Sam Watters + * Changes so PAGG modules can be compiled into the kernel + * 2001.03.22 Sam Watters + * Changed pagg module table to list & the lost protecting + * the list no longer disables interrupts. + * 2001.04.15 Sam Watters + * Changed locking to use read/write semaphores. Added + * alloc_pagg/free_pagg functions for use by PAGG modules. + * Hides the implementation of the pagg_s so it can + * be changed without requiring code changes in the modules. + * 2001.12.12 Sam Watters + * Changed references to pagg_module* to pagg_hook*. Updates + * for moving patches to 2.4.16 kernel. + */ + +#include + +#if defined(CONFIG_PAGG) + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* List of pagg hook entries that reference the "module" implementations */ +static LIST_HEAD(pagg_hook_list); +static DECLARE_RWSEM(pagg_hook_list_sem); + +/* + * get_pagg + * + * Given a pagg_list_s list structure, this function will return + * a pointer to the pagg_s struct that matches the search + * key. If the key is not found, the function will return NULL. + * + * The caller should hold at least a read lock on the pagg_list + * for task using read_lock_pagg_list(task). + */ +struct pagg_s * +get_pagg(struct task_struct *task, char *key) +{ + struct list_head *entry; + + list_for_each(entry, &task->pagg_list.head) { + struct pagg_s *pagg = list_entry(entry, struct pagg_s, entry); + if (!strcmp(pagg->hook->name,key)) { + return pagg; + } + } + return NULL; +} + + +/* + * alloc_pagg + * + * Given a task and a pagg hook, this function will allocate + * a new pagg structure, initialize the settings, and insert the pagg into + * the pagg_list for the task. + * + * The caller for this function should hold at least a read lock on the + * pagg_hook_list_sem - or ensure that the pagg hook entry cannot be + * removed. If this function was called from the pagg module (usually the + * case), then the caller need not hold this lock. The caller should hold + * a write lock on for the tasks pagg_list.sem. This can be locked using the + * write_lock_pagg_list(task) macro. + */ +struct pagg_s * +alloc_pagg(struct task_struct *task, struct pagg_hook_s *pagg_hook) +{ + struct pagg_s *pagg; + + pagg = (struct pagg_s *)kmalloc(sizeof(struct pagg_s), + GFP_KERNEL); + if (!pagg) + return NULL; + + pagg->hook = pagg_hook; + pagg->data = NULL; + list_add_tail(&pagg->entry, &task->pagg_list.head); + return pagg; +} + + + +/* + * free_pagg + * + * This function will ensure the pagg is deleted form + * the list of pagg entries for the task. Finally, the memory for the + * pagg is discarded. + * + * The caller of this function should hold a write lock on the pagg_list.sem + * for the task. This can be locke dusing the write_lock_pagg_list(task) + * macro. + * + * Prior to calling free_pagg, the pagg should have been detached from the + * pagg container represented by this pagg. That is usually done using the + * macro detach_pagg(pagg). + */ +void +free_pagg(struct pagg_s *pagg) +{ + + list_del(&pagg->entry); + kfree(pagg); +} + + + +/* + * get_pagg_hook + * + * Given a pagg hook name key, this function will return a pointer + * to the pagg_hook_s struct that contains that matches the name. + * + * You should hold either the write or read lock for pagg_hook_list_sem + * before using this function. This will ensure that the pagg_hook_list + * does not change while iterating through the list entries. + */ +static struct pagg_hook_s * +get_pagg_hook(char *key) +{ + struct list_head *entry; + struct pagg_hook_s *pagg_hook; + + list_for_each(entry, &pagg_hook_list) { + pagg_hook = list_entry(entry, struct pagg_hook_s, entry); + if (!strcmp(pagg_hook->name, key)) { + return pagg_hook; + } + } + return NULL; +} + + +/* + * register_pagg_hook + * + * Used to register a new pagg hook and enter it into the pagg_hook_list. + * The service name for a pagg hook is restricted to 32 characters. + * + * In the future an initialization function may also be defined so that all + * existing tasks can be assigned to a default pagg entry for the hook. + * However, this would require iterating through the tasklist. To do that + * requires that the tasklist_lock be read locked. Since the initialization + * function might be in a module, and therefore it might sleep (implementors + * decision), holding the tasklist_lock seems like a bad idea. It may be a + * requirement that the initialization function will be strictly forbidden + * from locking - by gentlemans agreement... + * + * If a memory error is encountered, the pagg hook is unregistered and any + * tasks that have been attached to the initial pagg container are detached + * from that container. + */ +int register_pagg_hook(struct pagg_hook_s *pagg_hook_new) +{ + struct pagg_hook_s *pagg_hook = NULL; + + /* ADD NEW PAGG MODULE TO ACCESS LIST */ + if (!pagg_hook_new) + return -EINVAL; /* error */ + if (!list_empty(&pagg_hook_new->entry)) + return -EINVAL; /* error */ + if (pagg_hook_new->name == NULL || strlen(pagg_hook_new->name) > PAGG_NAMELN) + return -EINVAL; /* error */ + + /* Try to insert new hook entry into the pagg hook list */ + down_write(&pagg_hook_list_sem); + + pagg_hook = get_pagg_hook(pagg_hook_new->name); + + if (pagg_hook) { + up_write(&pagg_hook_list_sem); + printk(KERN_WARNING "Attempt to register duplicate" + " PAGG support (name=%s)\n", pagg_hook_new->name); + return -EBUSY; + } + + /* Okay, we can insert into the pagg hook list */ + list_add_tail(&pagg_hook_new->entry, &pagg_hook_list); + up_write(&pagg_hook_list_sem); + + printk(KERN_INFO "Registering PAGG support for (name=%s)\n", + pagg_hook_new->name); + + return 0; /* success */ + +} + + +/* + * unregister_pagg_hook + * + * Used to unregister pagg hooks and remove them from the pagg_hook_list. + * Once the pagg hook entry in the pagg_hook_list is found, all of the + * tasks are scanned and detached from any pagg containers defined by the + * pagg implementation module. + */ +int unregister_pagg_hook(struct pagg_hook_s *pagg_hook_old) +{ + struct pagg_hook_s *pagg_hook; + struct task_struct *task; + + + /* Check the validity of the arguments */ + if (!pagg_hook_old) + return -EINVAL; /* error */ + if (list_empty(&pagg_hook_old->entry)) + return -EINVAL; /* error */ + if (pagg_hook_old->name == NULL) + return -EINVAL; /* error */ + + down_write(&pagg_hook_list_sem); + + pagg_hook = get_pagg_hook(pagg_hook_old->name); + if (pagg_hook && pagg_hook == pagg_hook_old) { + /* + * Scan through processes on system and check for + * references to pagg containers for this pagg hook. + * + * The module cannot be unloaded if there are references. + */ + read_lock(&tasklist_lock); + for_each_task(task) { + struct pagg_s *pagg = NULL; + + read_lock_pagg_list(task); + pagg = get_pagg(task, pagg_hook_old->name); + /* + * We won't be accessing pagg's memory, just need + * to see if one existed - so we can release the task + * lock now. + */ + read_unlock_pagg_list(task); + if (pagg) { + read_unlock(&tasklist_lock); + up_read(&pagg_hook_list_sem); + return -EBUSY; + } + } + list_del_init(&pagg_hook->entry); + read_unlock(&tasklist_lock); + + up_write(&pagg_hook_list_sem); + + printk(KERN_INFO "Unregistering PAGG support for" + " (name=%s)\n", pagg_hook_old->name); + + return 0; /* success */ + } + + up_write(&pagg_hook_list_sem); + + printk(KERN_WARNING "Attempt to unregister PAGG support (name=%s)" + " failed - not found\n", pagg_hook_old->name); + + return -EINVAL; /* error */ +} + + +/* + * attach_pagg_list + * + * Used to attach a new task to the same pagg containers to which it's parent + * is attached. + * + * The "from" argument is the parent task. The "to" argument is the child + * task. + * + */ +int attach_pagg_list(struct task_struct *to_task, + struct task_struct *from_task) +{ + struct list_head *entry; + int retcode = 0; + + + + /* lock the parents pagg_list we are copying from */ + read_lock_pagg_list(from_task); + + list_for_each(entry, &from_task->pagg_list.head) { + struct pagg_s *to_pagg = NULL; + struct pagg_s *from_pagg = list_entry(entry, struct pagg_s, + entry); + to_pagg = alloc_pagg(to_task, from_pagg->hook); + if (!to_pagg) { + retcode = -ENOMEM; + goto error_return; + } + retcode = attach_pagg(to_task, to_pagg, from_pagg->data); + if (retcode != 0) { + /* attach should issue error message */ + goto error_return; + } + } + + read_unlock_pagg_list(from_task); + + return 0; /* success */ + + error_return: + /* + * Clean up all the pagg attachments made on behalf of the new + * task. Set new task pagg ptr to NULL for return. + */ + read_unlock_pagg_list(from_task); + detach_pagg_list(to_task); + return retcode; /* failure */ +} + + +/* + * detach_pagg_list + * + * Used to detach a task from all pagg containers to which it is attached. + */ +int detach_pagg_list(struct task_struct *task) +{ + struct list_head *entry; + int retcode = 0; + int rettmp = 0; + + /* Remove ref. to paggs from task immediately */ + write_lock_pagg_list(task); + + if (list_empty(&task->pagg_list.head)) { + write_unlock_pagg_list(task); + return retcode; + } + + list_for_each(entry, &task->pagg_list.head) { + int rettemp = 0; + struct pagg_s *pagg = list_entry(entry, struct pagg_s, entry); + + entry = &task->pagg_list.head; + + rettemp = detach_pagg(task, pagg); + if (rettmp) { + /* an error message should be logged in free_pagg */ + retcode = rettmp; + } + free_pagg(pagg); + } + + write_unlock_pagg_list(task); + + return retcode; /* 0 = success, else return last code for failure */ +} + +/* + * pagg_hook_getcnt + * + * Function used to handle a request to get the number of PAGG hooks + * currently registered. + */ +static int pagg_hook_getcnt(int *cnt_arg) +{ + int cnt = 0; + struct list_head *entry; + + list_for_each(entry, &pagg_hook_list) { + ++cnt; + } + + if (copy_to_user(cnt_arg, &cnt, sizeof(cnt))) { + return -EFAULT; + } + return 0; +} + + +/* + * pagg_hook_getlst + * + * Function used to handle a request to get a list of the PAGG hooks + * currently registered. + */ +static int pagg_hook_getlst(pagg_hook_getlst_t *getlst_arg) +{ + int cnt = 0; + pagg_hook_getlst_t getlst; + struct pagg_hook_s *pagg_hook; + struct list_head *entry; + + if (copy_from_user(&getlst, getlst_arg, sizeof(getlst))) { + return -EFAULT; + } + + cnt = 0; + list_for_each(entry, &pagg_hook_list) { + pagg_hook = list_entry(entry, struct pagg_hook_s, entry); + if (copy_to_user(getlst.list+cnt, pagg_hook->name, + strlen(pagg_hook->name)*sizeof(char)+1)) { + return -EFAULT; + } + ++cnt; + if (cnt == getlst.r_val) break; + } + + getlst.r_val = cnt; + if (copy_to_user(getlst_arg, &getlst, sizeof(getlst))) { + return -EFAULT; + } + + return 0; +} + + +/* + * pagg_hook_getchk + * + * Function used to handle a request to determine if a specific PAGG hook is + * currently registered. + */ +static int pagg_hook_getchk(pagg_hook_getchk_t *getchk_arg) +{ + pagg_hook_getchk_t getchk; + + if (copy_from_user(&getchk, getchk_arg, sizeof(getchk))) { + return -EFAULT; + } + + if (get_pagg_hook(getchk.name)) { + getchk.r_val = 1; + } else { + getchk.r_val = 0; + } + + if (copy_to_user(getchk_arg, &getchk, sizeof(getchk))) { + return -EFAULT; + } + + return 0; +} + + + +/* + * pagg_hook_paggctl + * + * Function for handling pagg hook query requests via the paggctl + * system call. + */ +static int pagg_hook_paggctl(int request, void *data) +{ + switch (request) { + case PAGG_HOOK_GETCNT: + return pagg_hook_getcnt((int *)data); + case PAGG_HOOK_GETLST: + return pagg_hook_getlst((pagg_hook_getlst_t *)data); + case PAGG_HOOK_GETCHK: + return pagg_hook_getchk((pagg_hook_getchk_t *)data); + } + return -EINVAL; +} + + +/* + * sys_paggctl + * + * The paggctl() system call. This system call uses "name" to determine + * which pagg hook will handle the system call. The "request" and "data" + * arguments are passed to the implementation module via the module's + * do_paggctl() function pointer in the pagg_hook entry for the module. + */ +asmlinkage int sys_paggctl(char *name, int request, void *data) +{ + struct pagg_hook_s *pagg_hook = NULL; + int len = 0; + char namebuf[PAGG_NAMESTR]; + + if (name == NULL) { + /* + * If requested hook name is NULL, the caller + * is performing a pagg hooks query + * + * We handle those directly. + */ + return pagg_hook_paggctl(request, data); + } + + len = strlen_user(name); + + if (len > PAGG_NAMELN) { + return -EINVAL; + } + + if (strncpy_from_user(&namebuf[0], name, len) < 0) { + return -EFAULT; + } + + + /* Find the pagg hook entry and issue the callback function */ + down_read(&pagg_hook_list_sem); + pagg_hook = get_pagg_hook(namebuf); + if (pagg_hook) { + /* We found the target pagg hook */ + int retcode = 0; + + /* + * Increment module use count so that it cannot be + * removed. At this point the read lock on the + * pagg_hook_list can be released. + */ + if (pagg_hook->module) + __MOD_INC_USE_COUNT(pagg_hook->module); + up_read(&pagg_hook_list_sem); + if (pagg_hook->do_paggctl == NULL) + /* pagg hook does not provide callback (address) */ + retcode = -ENXIO; + else + /* return result of pagg hook callback */ + retcode = pagg_hook->do_paggctl(request, data); + if (pagg_hook->module) + __MOD_DEC_USE_COUNT(pagg_hook->module); + return retcode; + + } + + /* + * If we are here, we didn't find the appropriate pagg hook entry. + * release the read lock on the pagg_hook_list and return + * ENXIO (no such device or address). + */ + up_read(&pagg_hook_list_sem); + return -ENODEV; +} + +#endif /* CONFIG_PAGG */ diff -Nur linux-2.4.19/kernel/panic.c linux-2.4.19-sgi211r3/kernel/panic.c --- linux-2.4.19/kernel/panic.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/panic.c Thu Oct 24 05:25:29 2002 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,12 @@ asmlinkage void sys_sync(void); /* it's really int */ int panic_timeout; +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +int (*dump_function_ptr)(char *, struct pt_regs *) = 0; +volatile int dump_started = 0; /* Indicated we are about to dump */ +volatile int dump_in_progress = 0; +volatile int dumping_cpu = 0; +#endif struct notifier_block *panic_notifier_list; @@ -49,6 +56,11 @@ unsigned long caller = (unsigned long) __builtin_return_address(0); #endif +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + struct pt_regs regs; + get_current_regs(®s); +#endif + bust_spinlocks(1); va_start(args, fmt); vsprintf(buf, fmt, args); @@ -62,11 +74,17 @@ sys_sync(); bust_spinlocks(0); +#if !defined(CONFIG_DUMP) && !defined(CONFIG_DUMP_MODULE) #ifdef CONFIG_SMP smp_send_stop(); #endif +#endif notifier_call_chain(&panic_notifier_list, 0, NULL); + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + dump(buf, ®s); +#endif if (panic_timeout > 0) { diff -Nur linux-2.4.19/kernel/printk.c linux-2.4.19-sgi211r3/kernel/printk.c --- linux-2.4.19/kernel/printk.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/printk.c Tue Dec 3 07:13:51 2002 @@ -26,10 +26,13 @@ #include #include /* For in_interrupt() */ #include +#include #include -#if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) +#if defined(CONFIG_IA64_SGI_SN) +#define LOG_BUF_LEN (65536*8) +#elif defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) #define LOG_BUF_LEN (65536) #elif defined(CONFIG_ARCH_S390) #define LOG_BUF_LEN (131072) @@ -292,6 +295,20 @@ return error; } +#ifdef CONFIG_KDB +/* kdb dmesg command needs access to the syslog buffer. do_syslog() uses locks + * so it cannot be used during debugging. Just tell kdb where the start and + * end of the physical and logical logs are. This is equivalent to do_syslog(3). + */ +void kdb_syslog_data(char *syslog_data[4]) +{ + syslog_data[0] = log_buf; + syslog_data[1] = log_buf + sizeof(log_buf); + syslog_data[2] = log_buf + log_end - (logged_chars < LOG_BUF_LEN ? logged_chars : LOG_BUF_LEN); + syslog_data[3] = log_buf + log_end; +} +#endif + asmlinkage long sys_syslog(int type, char * buf, int len) { if ((type != 3) && !capable(CAP_SYS_ADMIN)) @@ -326,6 +343,12 @@ __call_console_drivers(start, end); } } +#ifdef CONFIG_IA64_EARLY_PRINTK + if (!console_drivers) { + static void early_printk (const char *str, size_t len); + early_printk(&LOG_BUF(start), end - start); + } +#endif } /* @@ -632,7 +655,11 @@ * release_cosole_sem() will print out the buffered messages for us. */ spin_lock_irqsave(&logbuf_lock, flags); +#if defined(CONFIG_IA64_SGI_SN) && defined(CONFIG_IA64_EARLY_PRINTK) + con_start = log_end; +#else con_start = log_start; +#endif spin_unlock_irqrestore(&logbuf_lock, flags); } release_console_sem(); @@ -685,3 +712,141 @@ tty->driver.write(tty, 0, msg, strlen(msg)); return; } + +#ifdef CONFIG_IA64_EARLY_PRINTK + +#include + +#ifdef CONFIG_IA64_EARLY_PRINTK_UART + +#include +#include + +static void early_printk_uart(const char *str, size_t len) +{ + static char *uart = 0; + unsigned long uart_base; + char c; + + if (!uart) { +#ifdef CONFIG_SERIAL_HCDP + extern unsigned long hcdp_early_uart(void); + uart_base = hcdp_early_uart(); +#endif +#if CONFIG_IA64_EARLY_PRINTK_UART_BASE + uart_base = CONFIG_IA64_EARLY_PRINTK_UART_BASE; +#endif + if (uart_base) + uart = ioremap(uart_base, 64); + } + + if (!uart) + return; + + while (len-- > 0) { + c = *str++; + while (!(UART_LSR_TEMT & readb(uart + UART_LSR))) + ; /* spin */ + + writeb(c, uart + UART_TX); + + if (c == '\n') + writeb('\r', uart + UART_TX); + } +} +#endif /* CONFIG_IA64_EARLY_PRINTK_UART */ + +#ifdef CONFIG_IA64_EARLY_PRINTK_VGA + +#define VGABASE ((char *)0xc0000000000b8000) +#define VGALINES 24 +#define VGACOLS 80 + +static int current_ypos = VGALINES, current_xpos = 0; + +static void early_printk_vga(const char *str, size_t len) +{ + char c; + int i, k, j; + + while (len-- > 0) { + c = *str++; + if (current_ypos >= VGALINES) { + /* scroll 1 line up */ + for (k = 1, j = 0; k < VGALINES; k++, j++) { + for (i = 0; i < VGACOLS; i++) { + writew(readw(VGABASE + 2*(VGACOLS*k + i)), + VGABASE + 2*(VGACOLS*j + i)); + } + } + for (i = 0; i < VGACOLS; i++) { + writew(0x720, VGABASE + 2*(VGACOLS*j + i)); + } + current_ypos = VGALINES-1; + } + if (c == '\n') { + current_xpos = 0; + current_ypos++; + } else if (c != '\r') { + writew(((0x7 << 8) | (unsigned short) c), + VGABASE + 2*(VGACOLS*current_ypos + current_xpos++)); + if (current_xpos >= VGACOLS) { + current_xpos = 0; + current_ypos++; + } + } + } +} +#endif /* CONFIG_IA64_EARLY_PRINTK_VGA */ + + +#if defined(CONFIG_IA64_SGI_SN) +#include + +void +early_printk_sgi (const char *str, size_t len) +{ + int l1_serial_out(char *, int); + +#ifdef CONFIG_IA64_SGI_SN1 + if ( IS_RUNNING_ON_SIMULATOR() ) { + char c; + extern u64 master_node_bedrock_address; + extern void early_sn_setup(void); + + while (len-- > 0) { + c = *str++; + + /* here we silently discard characters printed before + * the UART address has been calculated + */ + if (!master_node_bedrock_address) + early_sn_setup(); + if (!master_node_bedrock_address) + return; + writeb(c, ((char *)master_node_bedrock_address + 0x80)); + } + } + else +#endif /* CONFIG_IA64_SGI_SN1 */ + + + (void)l1_serial_out((char *)str, len); +} +#endif /* CONFIG_IA64_SGI_SN */ + + +void early_printk(const char *str, size_t len) +{ +#ifdef CONFIG_IA64_EARLY_PRINTK_UART + early_printk_uart(str, len); +#endif +#ifdef CONFIG_IA64_EARLY_PRINTK_VGA + early_printk_vga(str, len); +#endif +#ifdef CONFIG_IA64_SGI_SN + early_printk_sgi(str, len); +#endif +} + +#endif /* CONFIG_IA64_EARLY_PRINTK */ diff -Nur linux-2.4.19/kernel/ptrace.c linux-2.4.19-sgi211r3/kernel/ptrace.c --- linux-2.4.19/kernel/ptrace.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/ptrace.c Mon Oct 28 20:43:23 2002 @@ -31,20 +31,7 @@ if (child->state != TASK_STOPPED) return -ESRCH; #ifdef CONFIG_SMP - /* Make sure the child gets off its CPU.. */ - for (;;) { - task_lock(child); - if (!task_has_cpu(child)) - break; - task_unlock(child); - do { - if (child->state != TASK_STOPPED) - return -ESRCH; - barrier(); - cpu_relax(); - } while (task_has_cpu(child)); - } - task_unlock(child); + wait_task_inactive(child); #endif } diff -Nur linux-2.4.19/kernel/rcupdate.c linux-2.4.19-sgi211r3/kernel/rcupdate.c --- linux-2.4.19/kernel/rcupdate.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/kernel/rcupdate.c Mon Oct 28 20:43:23 2002 @@ -0,0 +1,248 @@ +/* + * Read-Copy Update mechanism for mutual exclusion + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (c) IBM Corporation, 2001 + * + * Author: Dipankar Sarma + * + * Based on the original work by Paul McKenney + * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. + * Papers: + * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf + * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) + * + * For detailed explanation of Read-Copy Update mechanism see - + * http://lse.sourceforge.net/locking/rcupdate.html + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef local_irq_count +#define local_irq_count(c) irq_count(c) +#endif + +/* Definition for rcupdate control block. */ +struct rcu_ctrlblk rcu_ctrlblk = + { + mutex: SPIN_LOCK_UNLOCKED, + curbatch: 1, + maxbatch: 1, + rcu_cpu_mask: 0UL + }; +struct rcu_data rcu_data[NR_CPUS] __cacheline_aligned; + +struct rcu_local_data { + struct tasklet_struct rcu_tasklet; +} ____cacheline_aligned_in_smp; + +static struct rcu_local_data rcu_local_data[NR_CPUS] __cacheline_aligned; + +#define RCU_tasklet(cpu) (rcu_local_data[(cpu)].rcu_tasklet) + +extern int idle_cpu(int cpu); + +/* + * Register a new rcu callback. The callback will be invoked as soon + * as all CPUs have performed a context switch or been seen in the + * idle loop or in a user process. + */ +void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg) +{ + int cpu = smp_processor_id(); + unsigned long flags; + + head->func = func; + head->arg = arg; + local_irq_save(flags); + list_add_tail(&head->list, &RCU_nxtlist(cpu)); + local_irq_restore(flags); +} + +/* + * Invoke the completed RCU callbacks. They are expected to be in + * a per-cpu list. + */ +static void rcu_do_batch(struct list_head *list) +{ + struct list_head *entry; + struct rcu_head *head; + + while (!list_empty(list)) { + entry = list->next; + list_del(entry); + head = list_entry(entry, struct rcu_head, list); + head->func(head->arg); + } +} + +/* + * Register a new batch of callbacks, and start it up if there is currently no + * active batch and the batch to be registered has not already occurred. + * Caller must hold the rcu_ctrlblk lock. + */ +static void rcu_start_batch(long newbatch) +{ + if (rcu_batch_before(rcu_ctrlblk.maxbatch, newbatch)) { + rcu_ctrlblk.maxbatch = newbatch; + } + if (rcu_batch_before(rcu_ctrlblk.maxbatch, rcu_ctrlblk.curbatch) || + (rcu_ctrlblk.rcu_cpu_mask != 0)) { + return; + } + rcu_ctrlblk.rcu_cpu_mask = cpu_online_map; +} + +/* + * Check if the cpu has gone through a quiescent state (say context + * switch). If so and if it already hasn't done so in this RCU + * quiescent cycle, then indicate that it has done so. + */ +static void rcu_check_quiescent_state(void) +{ + int cpu = smp_processor_id(); + + if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) { + return; + } + + /* + * Races with local timer interrupt - in the worst case + * we may miss one quiescent state of that CPU. That is + * tolerable. So no need to disable interrupts. + */ + if (RCU_last_qsctr(cpu) == RCU_QSCTR_INVALID) { + RCU_last_qsctr(cpu) = RCU_qsctr(cpu); + return; + } + if (RCU_qsctr(cpu) == RCU_last_qsctr(cpu)) { + return; + } + + spin_lock(&rcu_ctrlblk.mutex); + if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) { + spin_unlock(&rcu_ctrlblk.mutex); + return; + } + clear_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask); + RCU_last_qsctr(cpu) = RCU_QSCTR_INVALID; + if (rcu_ctrlblk.rcu_cpu_mask != 0) { + spin_unlock(&rcu_ctrlblk.mutex); + return; + } + rcu_ctrlblk.curbatch++; + rcu_start_batch(rcu_ctrlblk.maxbatch); + spin_unlock(&rcu_ctrlblk.mutex); +} + + +/* + * This does the RCU processing work from tasklet context. + */ +static void rcu_process_callbacks(unsigned long unused) +{ + int cpu = smp_processor_id(); + LIST_HEAD(list); + + if (!list_empty(&RCU_curlist(cpu)) && + rcu_batch_after(rcu_ctrlblk.curbatch, RCU_batch(cpu))) { + list_splice(&RCU_curlist(cpu), &list); + INIT_LIST_HEAD(&RCU_curlist(cpu)); + } + + local_irq_disable(); + if (!list_empty(&RCU_nxtlist(cpu)) && list_empty(&RCU_curlist(cpu))) { + list_splice(&RCU_nxtlist(cpu), &RCU_curlist(cpu)); + INIT_LIST_HEAD(&RCU_nxtlist(cpu)); + local_irq_enable(); + + /* + * start the next batch of callbacks + */ + spin_lock(&rcu_ctrlblk.mutex); + RCU_batch(cpu) = rcu_ctrlblk.curbatch + 1; + rcu_start_batch(RCU_batch(cpu)); + spin_unlock(&rcu_ctrlblk.mutex); + } else { + local_irq_enable(); + } + rcu_check_quiescent_state(); + if (!list_empty(&list)) + rcu_do_batch(&list); +} + +void rcu_check_callbacks(int cpu, int user) +{ + if (user || + (idle_cpu(cpu) && !in_softirq() && local_irq_count(cpu) <= 1)) + RCU_qsctr(cpu)++; + tasklet_schedule(&RCU_tasklet(cpu)); +} + +/* + * Initializes rcu mechanism. Assumed to be called early. + * That is before local timer(SMP) or jiffie timer (uniproc) is setup. + * Note that rcu_qsctr and friends are implicitly + * initialized due to the choice of ``0'' for RCU_CTR_INVALID. + */ +void rcu_init(void) +{ + int i; + + memset(&rcu_data[0], 0, sizeof(rcu_data)); + for (i = 0; i < NR_CPUS; i++) { + tasklet_init(&RCU_tasklet(i), rcu_process_callbacks, 0UL); + INIT_LIST_HEAD(&RCU_nxtlist(i)); + INIT_LIST_HEAD(&RCU_curlist(i)); + } +} + +/* Because of FASTCALL declaration of complete, we use this wrapper */ +static void wakeme_after_rcu(void *completion) +{ + complete(completion); +} + +/* + * Wait until all the CPUs have gone through a "quiescent" state. + */ +void synchronize_kernel(void) +{ + struct rcu_head rcu; + DECLARE_COMPLETION(completion); + + /* Will wake me after RCU finished */ + call_rcu(&rcu, wakeme_after_rcu, &completion); + + /* Wait for it */ + wait_for_completion(&completion); +} + + +EXPORT_SYMBOL(call_rcu); +EXPORT_SYMBOL(synchronize_kernel); diff -Nur linux-2.4.19/kernel/sched.c linux-2.4.19-sgi211r3/kernel/sched.c --- linux-2.4.19/kernel/sched.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/sched.c Fri Feb 14 10:42:13 2003 @@ -12,334 +12,426 @@ * 1998-12-28 Implemented better SMP scheduling by Ingo Molnar */ -/* - * 'sched.c' is the main kernel file. It contains scheduling primitives - * (sleep_on, wakeup, schedule etc) as well as a number of simple system - * call functions (type getpid()), which just extract a field from - * current-task - */ - -#include #include +#include #include +#include #include -#include #include +#include +#include #include #include -#include -#include - -#include -#include +#include -extern void timer_bh(void); -extern void tqueue_bh(void); -extern void immediate_bh(void); +/* + * Priority of a process goes from 0 to 139. The 0-99 + * priority range is allocated to RT tasks, the 100-139 + * range is for SCHED_OTHER tasks. Priority values are + * inverted: lower p->prio value means higher priority. + */ +#define MAX_RT_PRIO 100 +#define MAX_PRIO (MAX_RT_PRIO + 40) /* - * scheduler variables + * Convert user-nice values [ -20 ... 0 ... 19 ] + * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], + * and back. */ +#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) +#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) +#define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio) -unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ +/* + * 'User priority' is the nice value converted to something we + * can work with better when scaling various scheduler parameters, + * it's a [ 0 ... 39 ] range. + */ +#define USER_PRIO(p) ((p)-MAX_RT_PRIO) +#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio) +#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) -extern void mem_use(void); +/* + * These are the 'tuning knobs' of the scheduler: + * + * Minimum timeslice is 12 msecs, default timeslice is 150 msecs, + * maximum timeslice is 300 msecs. Timeslices get refilled after + * they expire. + */ +#define MIN_TIMESLICE ( 12 * HZ / 1000) +#define MAX_TIMESLICE (300 * HZ / 1000) +#define CHILD_PENALTY 95 +#define PARENT_PENALTY 100 +#define EXIT_WEIGHT 3 +#define PRIO_BONUS_RATIO 25 +#define INTERACTIVE_DELTA 2 +#define MAX_SLEEP_AVG (2*HZ) +#define STARVATION_LIMIT (2*HZ) +#define MAX_LOADBAL_REJECTS 100 /* max num processes to examine */ /* - * Scheduling quanta. + * If a task is 'interactive' then we reinsert it in the active + * array after it has expired its current timeslice. (it will not + * continue to run immediately, it will still roundrobin with + * other interactive tasks.) * - * NOTE! The unix "nice" value influences how long a process - * gets. The nice value ranges from -20 to +19, where a -20 - * is a "high-priority" task, and a "+10" is a low-priority - * task. + * This part scales the interactivity limit depending on niceness. * - * We want the time-slice to be around 50ms or so, so this - * calculation depends on the value of HZ. + * We scale it linearly, offset by the INTERACTIVE_DELTA delta. + * Here are a few examples of different nice levels: + * + * TASK_INTERACTIVE(-20): [1,1,1,1,1,1,1,1,1,0,0] + * TASK_INTERACTIVE(-10): [1,1,1,1,1,1,1,0,0,0,0] + * TASK_INTERACTIVE( 0): [1,1,1,1,0,0,0,0,0,0,0] + * TASK_INTERACTIVE( 10): [1,1,0,0,0,0,0,0,0,0,0] + * TASK_INTERACTIVE( 19): [0,0,0,0,0,0,0,0,0,0,0] + * + * (the X axis represents the possible -5 ... 0 ... +5 dynamic + * priority range a task can explore, a value of '1' means the + * task is rated interactive.) + * + * Ie. nice +19 tasks can never get 'interactive' enough to be + * reinserted into the active array. And only heavily CPU-hog nice -20 + * tasks will be expired. Default nice 0 tasks are somewhere between, + * it takes some effort for them to get interactive, but it's not + * too hard. */ -#if HZ < 200 -#define TICK_SCALE(x) ((x) >> 2) -#elif HZ < 400 -#define TICK_SCALE(x) ((x) >> 1) -#elif HZ < 800 -#define TICK_SCALE(x) (x) -#elif HZ < 1600 -#define TICK_SCALE(x) ((x) << 1) -#else -#define TICK_SCALE(x) ((x) << 2) -#endif -#define NICE_TO_TICKS(nice) (TICK_SCALE(20-(nice))+1) +#define SCALE(v1,v1_max,v2_max) \ + (v1) * (v2_max) / (v1_max) +#define DELTA(p) \ + (SCALE(TASK_NICE(p), 40, MAX_USER_PRIO*PRIO_BONUS_RATIO/100) + \ + INTERACTIVE_DELTA) -/* - * Init task must be ok at boot for the ix86 as we will check its signals - * via the SMP irq return path. - */ - -struct task_struct * init_tasks[NR_CPUS] = {&init_task, }; +#define TASK_INTERACTIVE(p) \ + ((p)->prio <= (p)->static_prio - DELTA(p)) /* - * The tasklist_lock protects the linked list of processes. + * TASK_TIMESLICE scales user-nice values [ -20 ... 19 ] + * to time slice values. * - * The runqueue_lock locks the parts that actually access - * and change the run-queues, and have to be interrupt-safe. - * - * If both locks are to be concurrently held, the runqueue_lock - * nests inside the tasklist_lock. - * - * task->alloc_lock nests inside tasklist_lock. + * The higher a process's priority, the bigger timeslices + * it gets during one round of execution. But even the lowest + * priority process gets MIN_TIMESLICE worth of execution time. */ -spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* inner */ -rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ -static LIST_HEAD(runqueue_head); +#define TASK_TIMESLICE(p) (MIN_TIMESLICE + \ + ((MAX_TIMESLICE - MIN_TIMESLICE) * (MAX_PRIO-1-(p)->static_prio)/39)) /* - * We align per-CPU scheduling data on cacheline boundaries, - * to prevent cacheline ping-pong. + * These are the runqueue data structures: */ -static union { - struct schedule_data { - struct task_struct * curr; - cycles_t last_schedule; - } schedule_data; - char __pad [SMP_CACHE_BYTES]; -} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}}; -#define cpu_curr(cpu) aligned_data[(cpu)].schedule_data.curr -#define last_schedule(cpu) aligned_data[(cpu)].schedule_data.last_schedule +#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long)) -struct kernel_stat kstat; -extern struct task_struct *child_reaper; +typedef struct runqueue runqueue_t; -#ifdef CONFIG_SMP +struct prio_array { + int nr_active; + unsigned long bitmap[BITMAP_SIZE]; + list_t queue[MAX_PRIO]; +}; -#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)]) -#define can_schedule(p,cpu) \ - ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu)) +/* + * This is the main, per-CPU runqueue data structure. + * + * Locking rule: those places that want to lock multiple runqueues + * (such as the load balancing or the process migration code), lock + * acquire operations must be ordered by ascending &runqueue. + */ +struct runqueue { + spinlock_t lock; + task_t *curr, *idle; + prio_array_t *active, *expired, arrays[2]; + unsigned long nr_running, nr_switches, expired_timestamp; + long nr_uninterruptible; + int prev_nr_running[NR_CPUS]; + task_t *migration_thread; + list_t migration_queue; + int busier_cpu_num [NR_CPUS]; /* a 'heap' list of cpuids and their */ + int busier_cpu_load[NR_CPUS]; /* calculated loads, and the number */ + int num_busier_cpus; /* of elements in heap */ +} ____cacheline_aligned; + +static struct runqueue runqueues[NR_CPUS] __cacheline_aligned; + +spinlock_t idle_loadbalance_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; + +#define cpu_rq(cpu) (runqueues + (cpu)) +#define this_rq() cpu_rq(smp_processor_id()) +#define task_rq(p) cpu_rq((p)->cpu) +#define cpu_curr(cpu) (cpu_rq(cpu)->curr) +#define rt_task(p) ((p)->prio < MAX_RT_PRIO) -#else +/* needed on IA64, arch/ia64/kernel/head.S relies on it (EF) */ +struct task_struct * init_tasks[NR_CPUS] __initdata = {&init_task, }; -#define idle_task(cpu) (&init_task) -#define can_schedule(p,cpu) (1) +/* needed in kdb (EF) */ +int task_has_cpu(task_t *p) +{ + return (p == task_rq(p)->curr); +} +/* + * Default context-switch locking: + */ +#ifndef prepare_arch_switch +# define prepare_arch_switch(rq, next) do { } while(0) +# define finish_arch_switch(rq, prev) spin_unlock_irq(&(rq)->lock) +# define task_running(rq, p) ((rq)->curr == (p)) #endif -void scheduling_functions_start_here(void) { } +/* Unless specifically set otherwise, always send IPI to idle CPU on resched */ +#ifndef idle_needs_wakeup +# define idle_needs_wakeup 1 +#endif /* - * This is the function that decides how desirable a process is.. - * You can weigh different processes against each other depending - * on what CPU they've run on lately etc to try to handle cache - * and TLB miss penalties. - * - * Return values: - * -1000: never select this - * 0: out of time, recalculate counters (but it might still be - * selected) - * +ve: "goodness" value (the larger, the better) - * +1000: realtime process, select this. + * task_rq_lock - lock the runqueue a given task resides on and disable + * interrupts. Note the ordering: we can safely lookup the task_rq without + * explicitly disabling preemption. */ - -static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm) +static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags) { - int weight; - - /* - * select the current process after every other - * runnable process, but before the idle thread. - * Also, dont trigger a counter recalculation. - */ - weight = -1; - if (p->policy & SCHED_YIELD) - goto out; + struct runqueue *rq; - /* - * Non-RT process - normal case first. - */ - if (p->policy == SCHED_OTHER) { - /* - * Give the process a first-approximation goodness value - * according to the number of clock-ticks it has left. - * - * Don't do any other calculations if the time slice is - * over.. - */ - weight = p->counter; - if (!weight) - goto out; - -#ifdef CONFIG_SMP - /* Give a largish advantage to the same processor... */ - /* (this is equivalent to penalizing other processors) */ - if (p->processor == this_cpu) - weight += PROC_CHANGE_PENALTY; -#endif - - /* .. and a slight advantage to the current MM */ - if (p->mm == this_mm || !p->mm) - weight += 1; - weight += 20 - p->nice; - goto out; +repeat_lock_task: + local_irq_save(*flags); + rq = task_rq(p); + spin_lock(&rq->lock); + if (unlikely(rq != task_rq(p))) { + spin_unlock_irqrestore(&rq->lock, *flags); + goto repeat_lock_task; } + return rq; +} - /* - * Realtime process, select the first one on the - * runqueue (taking priorities within processes - * into account). - */ - weight = 1000 + p->rt_priority; -out: - return weight; +static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags) +{ + spin_unlock_irqrestore(&rq->lock, *flags); } /* - * the 'goodness value' of replacing a process on a given CPU. - * positive value means 'replace', zero or negative means 'dont'. + * rq_lock - lock a given runqueue and disable interrupts. */ -static inline int preemption_goodness(struct task_struct * prev, struct task_struct * p, int cpu) +static inline runqueue_t *this_rq_lock(void) +{ + runqueue_t *rq; + + local_irq_disable(); + rq = this_rq(); + spin_lock(&rq->lock); + + return rq; +} + +static inline void rq_unlock(runqueue_t *rq) { - return goodness(p, cpu, prev->active_mm) - goodness(prev, cpu, prev->active_mm); + spin_unlock_irq(&rq->lock); } /* - * This is ugly, but reschedule_idle() is very timing-critical. - * We are called with the runqueue spinlock held and we must - * not claim the tasklist_lock. + * Adding/removing a task to/from a priority array: */ -static FASTCALL(void reschedule_idle(struct task_struct * p)); +static inline void dequeue_task(struct task_struct *p, prio_array_t *array) +{ + array->nr_active--; + list_del(&p->run_list); + if (list_empty(array->queue + p->prio)) + __clear_bit(p->prio, array->bitmap); +} -static void reschedule_idle(struct task_struct * p) +static inline void enqueue_task(struct task_struct *p, prio_array_t *array) { -#ifdef CONFIG_SMP - int this_cpu = smp_processor_id(); - struct task_struct *tsk, *target_tsk; - int cpu, best_cpu, i, max_prio; - cycles_t oldest_idle; + list_add_tail(&p->run_list, array->queue + p->prio); + __set_bit(p->prio, array->bitmap); + array->nr_active++; + p->array = array; +} - /* - * shortcut if the woken up task's last CPU is - * idle now. - */ - best_cpu = p->processor; - if (can_schedule(p, best_cpu)) { - tsk = idle_task(best_cpu); - if (cpu_curr(best_cpu) == tsk) { - int need_resched; -send_now_idle: - /* - * If need_resched == -1 then we can skip sending - * the IPI altogether, tsk->need_resched is - * actively watched by the idle thread. - */ - need_resched = tsk->need_resched; - tsk->need_resched = 1; - if ((best_cpu != this_cpu) && !need_resched) - smp_send_reschedule(best_cpu); - return; - } - } +static inline int effective_prio(task_t *p) +{ + int bonus, prio; /* - * We know that the preferred CPU has a cache-affine current - * process, lets try to find a new idle CPU for the woken-up - * process. Select the least recently active idle CPU. (that - * one will have the least active cache context.) Also find - * the executing process which has the least priority. - */ - oldest_idle = (cycles_t) -1; - target_tsk = NULL; - max_prio = 0; - - for (i = 0; i < smp_num_cpus; i++) { - cpu = cpu_logical_map(i); - if (!can_schedule(p, cpu)) - continue; - tsk = cpu_curr(cpu); + * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG] + * into the -5 ... 0 ... +5 bonus/penalty range. + * + * We use 25% of the full 0...39 priority range so that: + * + * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs. + * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks. + * + * Both properties are important to certain workloads. + */ + bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/MAX_SLEEP_AVG/100 - + MAX_USER_PRIO*PRIO_BONUS_RATIO/100/2; + + prio = p->static_prio - bonus; + if (prio < MAX_RT_PRIO) + prio = MAX_RT_PRIO; + if (prio > MAX_PRIO-1) + prio = MAX_PRIO-1; + return prio; +} + +static inline void activate_task(task_t *p, runqueue_t *rq) +{ + unsigned long sleep_time = jiffies - p->sleep_timestamp; + prio_array_t *array = rq->active; + + if (!rt_task(p) && sleep_time) { /* - * We use the first available idle CPU. This creates - * a priority list between idle CPUs, but this is not - * a problem. + * This code gives a bonus to interactive tasks. We update + * an 'average sleep time' value here, based on + * sleep_timestamp. The more time a task spends sleeping, + * the higher the average gets - and the higher the priority + * boost gets as well. */ - if (tsk == idle_task(cpu)) { -#if defined(__i386__) && defined(CONFIG_SMP) - /* - * Check if two siblings are idle in the same - * physical package. Use them if found. - */ - if (smp_num_siblings == 2) { - if (cpu_curr(cpu_sibling_map[cpu]) == - idle_task(cpu_sibling_map[cpu])) { - oldest_idle = last_schedule(cpu); - target_tsk = tsk; - break; - } - - } -#endif - if (last_schedule(cpu) < oldest_idle) { - oldest_idle = last_schedule(cpu); - target_tsk = tsk; - } - } else { - if (oldest_idle == -1ULL) { - int prio = preemption_goodness(tsk, p, cpu); - - if (prio > max_prio) { - max_prio = prio; - target_tsk = tsk; - } - } - } - } - tsk = target_tsk; - if (tsk) { - if (oldest_idle != -1ULL) { - best_cpu = tsk->processor; - goto send_now_idle; - } - tsk->need_resched = 1; - if (tsk->processor != this_cpu) - smp_send_reschedule(tsk->processor); + p->sleep_avg += sleep_time; + if (p->sleep_avg > MAX_SLEEP_AVG) + p->sleep_avg = MAX_SLEEP_AVG; + p->prio = effective_prio(p); } - return; - + enqueue_task(p, array); + rq->nr_running++; +} -#else /* UP */ - int this_cpu = smp_processor_id(); - struct task_struct *tsk; +static inline void deactivate_task(struct task_struct *p, runqueue_t *rq) +{ + rq->nr_running--; + if (p->state == TASK_UNINTERRUPTIBLE) + rq->nr_uninterruptible++; + dequeue_task(p, p->array); + p->array = NULL; +} + +static inline void resched_task(task_t *p) +{ +#ifdef CONFIG_SMP + int need_resched; - tsk = cpu_curr(this_cpu); - if (preemption_goodness(tsk, p, this_cpu) > 0) - tsk->need_resched = 1; + need_resched = p->need_resched; + set_tsk_need_resched(p); + if (!need_resched && (p->cpu != smp_processor_id()) + && (task_rq(p)->curr != task_rq(p)->idle || idle_needs_wakeup)) { + smp_send_reschedule(p->cpu); + } +#else + set_tsk_need_resched(p); #endif } +void resched_cpu(int cpu) +{ + resched_task(cpu_rq(cpu)->curr); +} + /* - * Careful! + * double_rq_lock - safely lock two runqueues * - * This has to add the process to the _beginning_ of the - * run-queue, not the end. See the comment about "This is - * subtle" in the scheduler proper.. + * Note this does not disable interrupts like task_rq_lock, + * you need to do so manually before calling. */ -static inline void add_to_runqueue(struct task_struct * p) +static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2) { - list_add(&p->run_list, &runqueue_head); - nr_running++; + if (rq1 == rq2) + spin_lock(&rq1->lock); + else { + if (rq1 < rq2) { + spin_lock(&rq1->lock); + spin_lock(&rq2->lock); + } else { + spin_lock(&rq2->lock); + spin_lock(&rq1->lock); + } + } } -static inline void move_last_runqueue(struct task_struct * p) +static inline void double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2) { - list_del(&p->run_list); - list_add_tail(&p->run_list, &runqueue_head); + spin_unlock(&rq1->lock); + if (rq1 != rq2) + spin_unlock(&rq2->lock); } -static inline void move_first_runqueue(struct task_struct * p) +static void migrate_task(task_t * p) { - list_del(&p->run_list); - list_add(&p->run_list, &runqueue_head); + runqueue_t *rq_src, *rq_dest; + int cpu_src, cpu_dest; + unsigned long flags; + + cpu_dest = __ffs(p->cpus_allowed); + rq_dest = cpu_rq(cpu_dest); +repeat: + cpu_src = p->cpu; + rq_src = cpu_rq(cpu_src); + + local_irq_save(flags); + double_rq_lock(rq_src, rq_dest); + if (p->cpu != cpu_src) { + double_rq_unlock(rq_src, rq_dest); + local_irq_restore(flags); + goto repeat; + } + if (rq_src == this_rq()) { + p->cpu = cpu_dest; + if (p->array) { + deactivate_task(p, rq_src); + if (p->state == TASK_UNINTERRUPTIBLE) + rq_dest->nr_uninterruptible--; + activate_task(p, rq_dest); + if (p->prio < rq_dest->curr->prio) + resched_task(rq_dest->curr); + } + } + double_rq_unlock(rq_src, rq_dest); + local_irq_restore(flags); } +#ifdef CONFIG_SMP + +/* + * Wait for a process to unschedule. This is used by the exit() and + * ptrace() code. + */ +void wait_task_inactive(task_t * p) +{ + unsigned long flags; + runqueue_t *rq; + +repeat: + rq = task_rq(p); + if (unlikely(task_running(rq, p))) { + cpu_relax(); + barrier(); + goto repeat; + } + rq = task_rq_lock(p, &flags); + if (unlikely(task_running(rq, p))) { + task_rq_unlock(rq, &flags); + goto repeat; + } + task_rq_unlock(rq, &flags); +} + +/* + * Kick the remote CPU if the task is running currently, + * this code is used by the signal code to signal tasks + * which are in user-mode as quickly as possible. + * + * (Note that we do this lockless - if the task does anything + * while the message is in flight then it will notice the + * sigpending condition anyway.) + */ +void kick_if_running(task_t * p) +{ + if ((task_running(task_rq(p), p)) && (p->cpu != smp_processor_id())) + resched_task(p); +} +#endif + /* * Wake up a process. Put it on the run-queue if it's not * already there. The "current" process is always on the @@ -348,428 +440,765 @@ * "current->state = TASK_RUNNING" to mark yourself runnable * without the overhead of this. */ -static inline int try_to_wake_up(struct task_struct * p, int synchronous) +static int try_to_wake_up(task_t * p, int sync) { unsigned long flags; int success = 0; + long old_state; + runqueue_t *rq; - /* - * We want the common case fall through straight, thus the goto. - */ - spin_lock_irqsave(&runqueue_lock, flags); +repeat_lock_task: + rq = task_rq_lock(p, &flags); + old_state = p->state; + if (!p->array) { + if (unlikely(sync && !task_running(rq, p) && + (p->cpu != smp_processor_id()) && + (p->cpus_allowed & (1UL << smp_processor_id())))) { + p->cpu = smp_processor_id(); + task_rq_unlock(rq, &flags); + goto repeat_lock_task; + } + if (old_state == TASK_UNINTERRUPTIBLE) + rq->nr_uninterruptible--; + activate_task(p, rq); + if (p->prio < rq->curr->prio) + resched_task(rq->curr); + success = 1; + } p->state = TASK_RUNNING; - if (task_on_runqueue(p)) - goto out; - add_to_runqueue(p); - if (!synchronous || !(p->cpus_allowed & (1 << smp_processor_id()))) - reschedule_idle(p); - success = 1; -out: - spin_unlock_irqrestore(&runqueue_lock, flags); + task_rq_unlock(rq, &flags); return success; } -inline int wake_up_process(struct task_struct * p) +int wake_up_process(task_t * p) { return try_to_wake_up(p, 0); } -static void process_timeout(unsigned long __data) +void wake_up_forked_process(task_t * p) { - struct task_struct * p = (struct task_struct *) __data; + unsigned long flags; + runqueue_t *rq = task_rq_lock(p, &flags); - wake_up_process(p); + p->state = TASK_RUNNING; + if (!rt_task(p)) { + /* + * We decrease the sleep average of forking parents + * and children as well, to keep max-interactive tasks + * from forking tasks that are max-interactive. + */ + current->sleep_avg = current->sleep_avg * PARENT_PENALTY / 100; + p->sleep_avg = p->sleep_avg * CHILD_PENALTY / 100; + p->prio = effective_prio(p); + } + activate_task(p, rq); + task_rq_unlock(rq, &flags); } -/** - * schedule_timeout - sleep until timeout - * @timeout: timeout value in jiffies - * - * Make the current task sleep until @timeout jiffies have - * elapsed. The routine will return immediately unless - * the current task state has been set (see set_current_state()). - * - * You can set the task state as follows - - * - * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to - * pass before the routine returns. The routine will return 0 - * - * %TASK_INTERRUPTIBLE - the routine may return early if a signal is - * delivered to the current task. In this case the remaining time - * in jiffies will be returned, or 0 if the timer expired in time - * - * The current task state is guaranteed to be TASK_RUNNING when this - * routine returns. - * - * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule - * the CPU away without a bound on the timeout. In this case the return - * value will be %MAX_SCHEDULE_TIMEOUT. +/* + * Potentially available exiting-child timeslices are + * retrieved here - this way the parent does not get + * penalized for creating too many processes. * - * In all cases the return value is guaranteed to be non-negative. + * (this cannot be used to 'generate' timeslices + * artificially, because any timeslice recovered here + * was given away by the parent in the first place.) */ -signed long schedule_timeout(signed long timeout) +void sched_exit(task_t * p) { - struct timer_list timer; - unsigned long expire; + __cli(); + current->time_slice += p->time_slice; + if (unlikely(current->time_slice > MAX_TIMESLICE)) + current->time_slice = MAX_TIMESLICE; + __sti(); + /* + * If the child was a (relative-) CPU hog then decrease + * the sleep_avg of the parent as well. + */ + if (p->sleep_avg < current->sleep_avg) + current->sleep_avg = (current->sleep_avg * EXIT_WEIGHT + + p->sleep_avg) / (EXIT_WEIGHT + 1); +} - switch (timeout) - { - case MAX_SCHEDULE_TIMEOUT: - /* - * These two special cases are useful to be comfortable - * in the caller. Nothing more. We could take - * MAX_SCHEDULE_TIMEOUT from one of the negative value - * but I' d like to return a valid offset (>=0) to allow - * the caller to do everything it want with the retval. - */ - schedule(); - goto out; - default: - /* - * Another bit of PARANOID. Note that the retval will be - * 0 since no piece of kernel is supposed to do a check - * for a negative retval of schedule_timeout() (since it - * should never happens anyway). You just have the printk() - * that will tell you if something is gone wrong and where. - */ - if (timeout < 0) - { - printk(KERN_ERR "schedule_timeout: wrong timeout " - "value %lx from %p\n", timeout, - __builtin_return_address(0)); - current->state = TASK_RUNNING; - goto out; - } +asmlinkage void schedule_tail(task_t *prev) +{ +#if CONFIG_SMP + finish_arch_switch(this_rq(), prev); +#endif +} + +static inline task_t * context_switch(task_t *prev, task_t *next) +{ + struct mm_struct *mm = next->mm; + struct mm_struct *oldmm = prev->active_mm; + + if (unlikely(!mm)) { + next->active_mm = oldmm; + atomic_inc(&oldmm->mm_count); + enter_lazy_tlb(oldmm, next, smp_processor_id()); + } else + switch_mm(oldmm, mm, next, smp_processor_id()); + + if (unlikely(!prev->mm)) { + prev->active_mm = NULL; + mmdrop(oldmm); } - expire = timeout + jiffies; + /* + * Here we just switch the register state and the stack. There are + * 3 processes affected by a context switch: + * + * prev ==> .... ==> (last => next) + * + * It's the 'much more previous' 'prev' that is on next's stack, + * but prev is set to (the just run) 'last' process by switch_to(). + * This might sound slightly confusing but makes tons of sense. + */ + switch_to(prev, next, prev); - init_timer(&timer); - timer.expires = expire; - timer.data = (unsigned long) current; - timer.function = process_timeout; + return prev; +} - add_timer(&timer); - schedule(); - del_timer_sync(&timer); +unsigned long nr_running(void) +{ + unsigned long i, sum = 0; - timeout = expire - jiffies; + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(cpu_logical_map(i))->nr_running; - out: - return timeout < 0 ? 0 : timeout; + return sum; } -/* - * schedule_tail() is getting called from the fork return path. This - * cleans up all remaining scheduler things, without impacting the - * common case. - */ -static inline void __schedule_tail(struct task_struct *prev) +/* Note: the per-cpu information is useful only to get the cumulative result */ +unsigned long nr_uninterruptible(void) { -#ifdef CONFIG_SMP - int policy; + unsigned long i, sum = 0; - /* - * prev->policy can be written from here only before `prev' - * can be scheduled (before setting prev->cpus_runnable to ~0UL). - * Of course it must also be read before allowing prev - * to be rescheduled, but since the write depends on the read - * to complete, wmb() is enough. (the spin_lock() acquired - * before setting cpus_runnable is not enough because the spin_lock() - * common code semantics allows code outside the critical section - * to enter inside the critical section) - */ - policy = prev->policy; - prev->policy = policy & ~SCHED_YIELD; - wmb(); - - /* - * fast path falls through. We have to clear cpus_runnable before - * checking prev->state to avoid a wakeup race. Protect against - * the task exiting early. - */ - task_lock(prev); - task_release_cpu(prev); - mb(); - if (prev->state == TASK_RUNNING) - goto needs_resched; + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(cpu_logical_map(i))->nr_uninterruptible; -out_unlock: - task_unlock(prev); /* Synchronise here with release_task() if prev is TASK_ZOMBIE */ - return; + return sum; +} - /* - * Slow path - we 'push' the previous process and - * reschedule_idle() will attempt to find a new - * processor for it. (but it might preempt the - * current process as well.) We must take the runqueue - * lock and re-check prev->state to be correct. It might - * still happen that this process has a preemption - * 'in progress' already - but this is not a problem and - * might happen in other circumstances as well. - */ -needs_resched: - { - unsigned long flags; +unsigned long nr_context_switches(void) +{ + unsigned long i, sum = 0; - /* - * Avoid taking the runqueue lock in cases where - * no preemption-check is necessery: - */ - if ((prev == idle_task(smp_processor_id())) || - (policy & SCHED_YIELD)) - goto out_unlock; + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(cpu_logical_map(i))->nr_switches; - spin_lock_irqsave(&runqueue_lock, flags); - if ((prev->state == TASK_RUNNING) && !task_has_cpu(prev)) - reschedule_idle(prev); - spin_unlock_irqrestore(&runqueue_lock, flags); - goto out_unlock; - } -#else - prev->policy &= ~SCHED_YIELD; -#endif /* CONFIG_SMP */ + return sum; } -asmlinkage void schedule_tail(struct task_struct *prev) +#if CONFIG_SMP +static inline int calculate_my_load(int idle, runqueue_t *this_rq) { - __schedule_tail(prev); + int my_load; + int this_cpu = smp_processor_id(); + + if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu])) + my_load = this_rq->nr_running; + else + my_load = this_rq->prev_nr_running[this_cpu]; + + this_rq->prev_nr_running[this_cpu] = this_rq->nr_running; + + return my_load; +} + +/* + * Lock the busiest runqueue as well, this_rq is locked already. + * Recalculate nr_running if we have to drop the runqueue lock. + */ +static inline unsigned int double_lock_balance(runqueue_t *this_rq, + runqueue_t *busiest, int idle, unsigned int nr_running) +{ + if (unlikely(!spin_trylock(&busiest->lock))) { + if (busiest < this_rq) { + spin_unlock(&this_rq->lock); + spin_lock(&busiest->lock); + spin_lock(&this_rq->lock); + /* Need to recalculate nr_running */ + nr_running = calculate_my_load(idle, this_rq); + } else + spin_lock(&busiest->lock); + } + return nr_running; } +#define NOT_BUSIER_CPU -1 +#define BUSIER_LIST_UNINITIALIZED -2 + /* - * 'schedule()' is the scheduler function. It's a very simple and nice - * scheduler: it's not perfect, but certainly works for most things. - * - * The goto is "interesting". + * For small loads, for efficiency and clarity, use a table of minimum + * load-deltas to decide whether or not a difference in loads is worthy enough + * to lock the other CPU's runqueue and search for a process to pull-migrate + */ +#define NR_MIN_LOADBAL_DELTA 12 +int min_delta_gt_my_load[NR_MIN_LOADBAL_DELTA] = { +/* 0 1 2 3 4 5 6 7 8 9 10 11 my load value */ + 2, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5 /* --> min threshold delta load */ +}; + +/* + * Build and use a per-CPU list of nr_running loads. + * First time through, build the list and find the max in one pass. + * If a CPU's load is <= this CPU's load, then mark the load as -1, which + * marks it for the search phase as "don't even bother to look at this CPU." + * On subsequent passes, just scan the list and find the max. * - * NOTE!! Task 0 is the 'idle' task, which gets called when no other - * tasks can run. It can not be killed, and it cannot sleep. The 'state' - * information in task[0] is never used. + * If this "max CPU" cannot offer up a candidate process for migration, then + * the caller will mark the load value with -1, and a subsequent call to this + * routine will pass over this already-considered CPU and find the next + * higheset loaded CPU. */ -asmlinkage void schedule(void) +static inline int find_busiest_cpu_idx(int my_load, int idle) { - struct schedule_data * sched_data; - struct task_struct *prev, *next, *p; - struct list_head *tmp; - int this_cpu, c; + int i; + int delta_load, max_load = 0; + int busiest_cpu_idx = NOT_BUSIER_CPU; + runqueue_t *rq = this_rq(); + + if (rq->busier_cpu_load[0] == BUSIER_LIST_UNINITIALIZED) { + rq->num_busier_cpus = 0; + for (i = 0; i < smp_num_cpus; i++) { + int load; + runqueue_t *try_rq = cpu_rq(i); + if (unlikely(rq == try_rq)) + continue; + + if (idle || (try_rq->nr_running < rq->prev_nr_running[i])) + load = try_rq->nr_running; + else + load = rq->prev_nr_running[i]; + rq->prev_nr_running[i] = try_rq->nr_running; + + /* Is this an interesting load on the other CPU? */ + if (idle) { + if (load <= 1) { + load = NOT_BUSIER_CPU; + } + } else { + delta_load = load - my_load; + if (my_load < NR_MIN_LOADBAL_DELTA) { + if (delta_load < min_delta_gt_my_load[my_load]) + load = NOT_BUSIER_CPU; + } else { + if (delta_load < my_load/2) + load = NOT_BUSIER_CPU; + } + } + if (load != NOT_BUSIER_CPU) { + rq->busier_cpu_load[rq->num_busier_cpus] = load; + rq->busier_cpu_num [rq->num_busier_cpus] = i; + if (load > max_load) { + max_load = load; + busiest_cpu_idx = rq->num_busier_cpus; + } + rq->num_busier_cpus++; + } + } + } else { + /* Rescan list to find remaining max_load CPU */ + for (i = 0; i < rq->num_busier_cpus; i++) { + if (rq->busier_cpu_load[i] > max_load) { + max_load = rq->busier_cpu_load[i]; + busiest_cpu_idx = i; + } + } + } - spin_lock_prefetch(&runqueue_lock); + return busiest_cpu_idx; +} - BUG_ON(!current->active_mm); -need_resched_back: - prev = current; - this_cpu = prev->processor; +/* + * Current runqueue is empty, or rebalance tick: if there is an + * inbalance (current runqueue is too short) then pull from + * busiest runqueue(s). + * + * We call this with the current runqueue locked, + * irqs disabled. + */ +static void load_balance(runqueue_t *this_rq, int idle) +{ + int nr_running, idx, this_cpu = smp_processor_id(); + task_t *next = this_rq->idle, *tmp; + runqueue_t *busiest; + prio_array_t *array; + list_t *head, *curr; + int busiest_cpu_idx, busiest_cpuid; + int num_process_rejects = 0; + + if (!this_rq->migration_thread) /* if not yet fully initialized, */ + return; /* then leave immediately. */ + + /* + * We search all runqueues to find the most busy one. + * We do this lockless to reduce cache-bouncing overhead, + * we re-check the 'best' source CPU later on again, with + * the lock held. + * + * We fend off statistical fluctuations in runqueue lengths by + * saving the runqueue length during the previous load-balancing + * operation and using the smaller one the current and saved lengths. + * If a runqueue is long enough for a longer amount of time then + * we recognize it and pull tasks from it. + * + * The 'current runqueue length' is a statistical maximum variable, + * for that one we take the longer one - to avoid fluctuations in + * the other direction. So for a load-balance to happen it needs + * stable long runqueue on the target CPU and stable short runqueue + * on the local runqueue. + * + * We make an exception if this CPU is about to become idle - in + * that case we are less picky about moving a task across CPUs and + * take what can be taken. + */ + nr_running = calculate_my_load(idle, this_rq); - if (unlikely(in_interrupt())) { - printk("Scheduling in interrupt\n"); - BUG(); - } + this_rq->busier_cpu_load[0] = BUSIER_LIST_UNINITIALIZED; - release_kernel_lock(prev, this_cpu); +try_another_cpu: + busiest_cpu_idx = find_busiest_cpu_idx(nr_running, idle); + if (busiest_cpu_idx == NOT_BUSIER_CPU) /* if no other CPUs busier */ + return; /* than me, then leave now */ + + busiest_cpuid = this_rq->busier_cpu_num[busiest_cpu_idx]; + busiest = cpu_rq(busiest_cpuid); + nr_running = double_lock_balance(this_rq, busiest, idle, nr_running); /* - * 'sched_data' is protected by the fact that we can run - * only one process per CPU. + * Make sure nothing changed since we checked the + * runqueue length. */ - sched_data = & aligned_data[this_cpu].schedule_data; + if (busiest->nr_running <= nr_running + 1) { + spin_unlock(&busiest->lock); + this_rq->busier_cpu_load[busiest_cpu_idx] = NOT_BUSIER_CPU; + goto try_another_cpu; + } - spin_lock_irq(&runqueue_lock); + /* + * We first consider expired tasks. Those will likely not be + * executed in the near future, and they are most likely to + * be cache-cold, thus switching CPUs has the least effect + * on them. + */ + if (busiest->expired->nr_active) + array = busiest->expired; + else + array = busiest->active; - /* move an exhausted RR process to be last.. */ - if (unlikely(prev->policy == SCHED_RR)) - if (!prev->counter) { - prev->counter = NICE_TO_TICKS(prev->nice); - move_last_runqueue(prev); +new_array: + /* Start searching at priority 0: */ + idx = 0; +skip_bitmap: + if (!idx) + idx = sched_find_first_bit(array->bitmap); + else + idx = find_next_bit(array->bitmap, MAX_PRIO, idx); + if (idx == MAX_PRIO) { + if (array == busiest->expired) { + array = busiest->active; + goto new_array; } - - switch (prev->state) { - case TASK_INTERRUPTIBLE: - if (signal_pending(prev)) { - prev->state = TASK_RUNNING; - break; - } - default: - del_from_runqueue(prev); - case TASK_RUNNING:; + /* + * Could not find anything to migrate on this busiest CPU, + * so find the next less busy CPU in the list of busy CPUs. + */ + spin_unlock(&busiest->lock); + this_rq->busier_cpu_load[busiest_cpu_idx] = NOT_BUSIER_CPU; + goto try_another_cpu; } - prev->need_resched = 0; + + head = array->queue + idx; + curr = head->prev; +skip_queue: + tmp = list_entry(curr, task_t, run_list); /* - * this is the scheduler proper: + * We do not migrate tasks that are: + * 1) running (obviously), or + * 2) cannot be migrated to this CPU due to cpus_allowed, or + * 3) are cache-hot on their current CPU. */ -repeat_schedule: +#define CAN_MIGRATE_TASK(p,rq,this_cpu) \ + ((jiffies - (p)->sleep_timestamp > cache_decay_ticks) && \ + !task_running(rq, p) && \ + ((p)->cpus_allowed & (1UL << (this_cpu)))) + + if (!CAN_MIGRATE_TASK(tmp, busiest, this_cpu)) { + if (++num_process_rejects > MAX_LOADBAL_REJECTS) + goto out_unlock; + curr = curr->prev; + if (curr != head) + goto skip_queue; + idx++; + goto skip_bitmap; + } + next = tmp; + + /* + * take the task out of the other runqueue and + * put it into this one: + */ + dequeue_task(next, array); + busiest->nr_running--; + next->cpu = this_cpu; + this_rq->nr_running++; + enqueue_task(next, this_rq->active); + if (next->prio < current->prio) + set_need_resched(); +out_unlock: + spin_unlock(&busiest->lock); +} + +/* + * One of the idle_cpu_tick() or the busy_cpu_tick() function will + * gets called every timer tick, on every CPU. Our balancing action + * frequency and balancing agressivity depends on whether the CPU is + * idle or not. + * + * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on + * systems with HZ=100, every 10 msecs.) + */ +#define BUSY_REBALANCE_TICK (HZ/4 ?: 1) +#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1) + +static inline void idle_tick(runqueue_t *rq) +{ + int own_loadbalance_lock = 0; + + if (jiffies % IDLE_REBALANCE_TICK) + return; + /* - * Default process to select.. + * Try to serialize the idle CPUs that do load-balancing to reduce + * potential mass contention on the "busiest" runqueue lock. This + * doesn't completely serialize system load-balancing, just greatly + * reduces it on behalf of idle CPUs which may all sync on + * IDLE_REBALANCE_TICK. + * It just seems safer to grab the idle_loadbalance_lock before the + * runqueue lock than vice versa. */ - next = idle_task(this_cpu); - c = -1000; - list_for_each(tmp, &runqueue_head) { - p = list_entry(tmp, struct task_struct, run_list); - if (can_schedule(p, this_cpu)) { - int weight = goodness(p, this_cpu, prev->active_mm); - if (weight > c) - c = weight, next = p; - } + if (!rq->nr_running) { + /* + * This runqueue seems to still be idle (though we need the + * runqueue lock to know for sure). That timing window is + * tiny and not critical. The tradeoff is a small delay in + * context-switching to a new arrival in the runqueue, vs. + * avoiding grabbing a usually-unnecessary runqueue lock if + * we're not going to be load-balancing anyway. + * First probe the spinlock first with a lightweight Load to + * see if it is presently locked, and only if it seems free + * bring out the heavyweight trylock. + */ + if (!spin_is_locked(&idle_loadbalance_lock) && + spin_trylock(&idle_loadbalance_lock)) + own_loadbalance_lock = 1; + else + return; } - /* Do we need to re-calculate counters? */ - if (unlikely(!c)) { - struct task_struct *p; - - spin_unlock_irq(&runqueue_lock); - read_lock(&tasklist_lock); - for_each_task(p) - p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice); - read_unlock(&tasklist_lock); - spin_lock_irq(&runqueue_lock); - goto repeat_schedule; + spin_lock(&rq->lock); + if (!rq->nr_running) + load_balance(rq, 1); + else + set_tsk_need_resched(rq->curr); + spin_unlock(&rq->lock); + + if (own_loadbalance_lock) + spin_unlock(&idle_loadbalance_lock); +} +#endif + +/* + * We place interactive tasks back into the active array, if possible. + * + * To guarantee that this does not starve expired tasks we ignore the + * interactivity of a task if the first expired task had to wait more + * than a 'reasonable' amount of time. This deadline timeout is + * load-dependent, as the frequency of array switched decreases with + * increasing number of running tasks: + */ +#define EXPIRED_STARVING(rq) \ + ((rq)->expired_timestamp && \ + (jiffies - (rq)->expired_timestamp >= \ + STARVATION_LIMIT * ((rq)->nr_running) + 1)) + +/* + * This function gets called by the timer code, with HZ frequency. + * We call it with interrupts disabled. + */ +void scheduler_tick(int user_tick, int system) +{ + int cpu = smp_processor_id(); + runqueue_t *rq = this_rq(); + task_t *p = current; + + if (rcu_pending(cpu)) + rcu_check_callbacks(cpu, user_tick); + + if (p == rq->idle) { +#ifdef CONFIG_IA64 + if (really_local_bh_count() || really_local_irq_count() > 1) +#else + if (local_bh_count(cpu) || local_irq_count(cpu) > 1) +#endif + kstat.per_cpu_system[cpu] += system; +#if CONFIG_SMP + idle_tick(rq); +#endif + return; } + if (TASK_NICE(p) > 0) + kstat.per_cpu_nice[cpu] += user_tick; + else + kstat.per_cpu_user[cpu] += user_tick; + kstat.per_cpu_system[cpu] += system; + /* Task might have expired already, but not scheduled off yet */ + if (p->array != rq->active) { + set_tsk_need_resched(p); + return; + } + spin_lock(&rq->lock); + if (unlikely(rt_task(p))) { + /* + * RR tasks need a special form of timeslice management. + * FIFO tasks have no timeslices. + */ + if ((p->policy == SCHED_RR) && !--p->time_slice) { + p->time_slice = TASK_TIMESLICE(p); + p->need_resched = 1; + + /* put it at the end of the queue: */ + dequeue_task(p, rq->active); + enqueue_task(p, rq->active); + } + goto out; + } /* - * from this point on nothing can prevent us from - * switching to the next task, save this fact in - * sched_data. - */ - sched_data->curr = next; - task_set_cpu(next, this_cpu); - spin_unlock_irq(&runqueue_lock); - - if (unlikely(prev == next)) { - /* We won't go through the normal tail, so do this by hand */ - prev->policy &= ~SCHED_YIELD; - goto same_process; + * The task was running during this tick - update the + * time slice counter and the sleep average. Note: we + * do not update a process's priority until it either + * goes to sleep or uses up its timeslice. This makes + * it possible for interactive tasks to use up their + * timeslices at their highest priority levels. + */ + if (p->sleep_avg) + p->sleep_avg--; + if (!--p->time_slice) { + dequeue_task(p, rq->active); + p->need_resched = 1; + p->prio = effective_prio(p); + p->time_slice = TASK_TIMESLICE(p); + + if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) { + if (!rq->expired_timestamp) + rq->expired_timestamp = jiffies; + enqueue_task(p, rq->expired); + } else + enqueue_task(p, rq->active); } +out: +#if CONFIG_SMP + if (!((jiffies + cpu) % BUSY_REBALANCE_TICK)) { + /* + * Stagger the calls to load_balance a bit, to reduce + * a thundering herd race for the "busiest" runqueue lock. + */ + load_balance(rq, 0); + } +#endif + spin_unlock(&rq->lock); +} -#ifdef CONFIG_SMP - /* - * maintain the per-process 'last schedule' value. - * (this has to be recalculated even if we reschedule to - * the same process) Currently this is only used on SMP, - * and it's approximate, so we do not have to maintain - * it while holding the runqueue spinlock. - */ - sched_data->last_schedule = get_cycles(); +void scheduling_functions_start_here(void) { } - /* - * We drop the scheduler lock early (it's a global spinlock), - * thus we have to lock the previous process from getting - * rescheduled during switch_to(). - */ +/* + * 'schedule()' is the main scheduler function. + */ +asmlinkage void schedule(void) +{ + task_t *prev, *next; + runqueue_t *rq; + prio_array_t *array; + list_t *queue; + int idx; -#endif /* CONFIG_SMP */ + if (unlikely(in_interrupt())) + BUG(); - kstat.context_swtch++; - /* - * there are 3 processes which are affected by a context switch: - * - * prev == .... ==> (last => next) - * - * It's the 'much more previous' 'prev' that is on next's stack, - * but prev is set to (the just run) 'last' process by switch_to(). - * This might sound slightly confusing but makes tons of sense. - */ - prepare_to_switch(); - { - struct mm_struct *mm = next->mm; - struct mm_struct *oldmm = prev->active_mm; - if (!mm) { - BUG_ON(next->active_mm); - next->active_mm = oldmm; - atomic_inc(&oldmm->mm_count); - enter_lazy_tlb(oldmm, next, this_cpu); - } else { - BUG_ON(next->active_mm != mm); - switch_mm(oldmm, mm, next, this_cpu); - } +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) + if (dump_in_progress) { + goto dump_scheduling_disabled; + } +#endif + +need_resched: + prev = current; + rq = this_rq(); + + release_kernel_lock(prev, smp_processor_id()); + prev->sleep_timestamp = jiffies; + spin_lock_irq(&rq->lock); - if (!prev->mm) { - prev->active_mm = NULL; - mmdrop(oldmm); + switch (prev->state) { + case TASK_INTERRUPTIBLE: + if (unlikely(signal_pending(prev))) { + prev->state = TASK_RUNNING; + break; } + default: + deactivate_task(prev, rq); + case TASK_RUNNING: + ; + } +#if CONFIG_SMP +pick_next_task: +#endif + if (unlikely(!rq->nr_running)) { +#if CONFIG_SMP + load_balance(rq, 1); + if (rq->nr_running) + goto pick_next_task; +#endif + next = rq->idle; + rq->expired_timestamp = 0; + goto switch_tasks; } - /* - * This just switches the register state and the - * stack. - */ - switch_to(prev, next, prev); - __schedule_tail(prev); + array = rq->active; + if (unlikely(!array->nr_active)) { + /* + * Switch the active and expired arrays. + */ + rq->active = rq->expired; + rq->expired = array; + array = rq->active; + rq->expired_timestamp = 0; + } + + idx = sched_find_first_bit(array->bitmap); + queue = array->queue + idx; + next = list_entry(queue->next, task_t, run_list); + +switch_tasks: + prefetch(next); + clear_tsk_need_resched(prev); + RCU_qsctr(prev->cpu)++; + + if (likely(prev != next)) { + rq->nr_switches++; + rq->curr = next; + + prepare_arch_switch(rq, next); + prev = context_switch(prev, next); + barrier(); + rq = this_rq(); + if (unlikely(!(prev->cpus_allowed & (1UL << prev->cpu)))) { + /* + * Prev process isn't where it is supposed to be, so + * do a "lazy migration" now. We know the process + * is still alive because we still hold the + * switch_lock. Only works for architectures that + * support the switch_lock (ia64 and i386 for now). + */ + migrate_task(prev); + } + finish_arch_switch(rq, prev); + } else + spin_unlock_irq(&rq->lock); -same_process: reacquire_kernel_lock(current); - if (current->need_resched) - goto need_resched_back; + if (need_resched()) + goto need_resched; return; + +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +dump_scheduling_disabled: + + BUG_ON(!current->active_mm); + + /* + * If this is not the dumping cpu, then spin right here + * till the dump is complete + */ + if (smp_processor_id() != dumping_cpu) { + while (dump_in_progress); + } +#endif } /* - * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just wake everything - * up. If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the - * non-exclusive tasks and one exclusive task. + * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just + * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve + * number) then we wake all the non-exclusive tasks and one exclusive task. * * There are circumstances in which we can try to wake a task which has already - * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns zero - * in this (rare) case, and we handle it by contonuing to scan the queue. + * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns + * zero in this (rare) case, and we handle it by continuing to scan the queue. */ -static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, const int sync) +static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,int nr_exclusive, int sync) { struct list_head *tmp; - struct task_struct *p; - - CHECK_MAGIC_WQHEAD(q); - WQ_CHECK_LIST_HEAD(&q->task_list); - - list_for_each(tmp,&q->task_list) { - unsigned int state; - wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); + unsigned int state; + wait_queue_t *curr; + task_t *p; - CHECK_MAGIC(curr->__magic); + list_for_each(tmp, &q->task_list) { + curr = list_entry(tmp, wait_queue_t, task_list); p = curr->task; state = p->state; - if (state & mode) { - WQ_NOTE_WAKER(curr); - if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) + if ((state & mode) && try_to_wake_up(p, sync) && + ((curr->flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)) break; - } } } -void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr) +void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { - if (q) { - unsigned long flags; - wq_read_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr, 0); - wq_read_unlock_irqrestore(&q->lock, flags); - } + unsigned long flags; + if (unlikely(!q)) + return; + + wq_read_lock_irqsave(&q->lock, flags); + __wake_up_common(q, mode, nr_exclusive, 0); + wq_read_unlock_irqrestore(&q->lock, flags); } -void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr) +#if CONFIG_SMP +void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { - if (q) { - unsigned long flags; - wq_read_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr, 1); - wq_read_unlock_irqrestore(&q->lock, flags); - } -} + unsigned long flags; + + if (unlikely(!q)) + return; + + wq_read_lock_irqsave(&q->lock, flags); + if (likely(nr_exclusive)) + __wake_up_common(q, mode, nr_exclusive, 1); + else + __wake_up_common(q, mode, nr_exclusive, 0); + wq_read_unlock_irqrestore(&q->lock, flags); + } +#endif void complete(struct completion *x) { unsigned long flags; - spin_lock_irqsave(&x->wait.lock, flags); + wq_write_lock_irqsave(&x->wait.lock, flags); x->done++; __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, 0); - spin_unlock_irqrestore(&x->wait.lock, flags); + wq_write_unlock_irqrestore(&x->wait.lock, flags); } void wait_for_completion(struct completion *x) { - spin_lock_irq(&x->wait.lock); + wq_write_lock_irq(&x->wait.lock); if (!x->done) { DECLARE_WAITQUEUE(wait, current); @@ -777,14 +1206,14 @@ __add_wait_queue_tail(&x->wait, &wait); do { __set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&x->wait.lock); + wq_write_unlock_irq(&x->wait.lock); schedule(); - spin_lock_irq(&x->wait.lock); + wq_write_lock_irq(&x->wait.lock); } while (!x->done); __remove_wait_queue(&x->wait, &wait); } x->done--; - spin_unlock_irq(&x->wait.lock); + wq_write_unlock_irq(&x->wait.lock); } #define SLEEP_ON_VAR \ @@ -852,6 +1281,41 @@ void scheduling_functions_end_here(void) { } +void set_user_nice(task_t *p, long nice) +{ + unsigned long flags; + prio_array_t *array; + runqueue_t *rq; + + if (TASK_NICE(p) == nice || nice < -20 || nice > 19) + return; + /* + * We have to be careful, if called from sys_setpriority(), + * the task might be in the middle of scheduling on another CPU. + */ + rq = task_rq_lock(p, &flags); + if (rt_task(p)) { + p->static_prio = NICE_TO_PRIO(nice); + goto out_unlock; + } + array = p->array; + if (array) + dequeue_task(p, array); + p->static_prio = NICE_TO_PRIO(nice); + p->prio = NICE_TO_PRIO(nice); + if (array) { + enqueue_task(p, array); + /* + * If the task is running and lowered its priority, + * or increased its priority then reschedule its CPU: + */ + if ((NICE_TO_PRIO(nice) < p->static_prio) || task_running(rq, p)) + resched_task(rq->curr); + } +out_unlock: + task_rq_unlock(rq, &flags); +} + #ifndef __alpha__ /* @@ -862,7 +1326,7 @@ asmlinkage long sys_nice(int increment) { - long newprio; + long nice; /* * Setpriority might change our priority at the same moment. @@ -878,32 +1342,51 @@ if (increment > 40) increment = 40; - newprio = current->nice + increment; - if (newprio < -20) - newprio = -20; - if (newprio > 19) - newprio = 19; - current->nice = newprio; + nice = PRIO_TO_NICE(current->static_prio) + increment; + if (nice < -20) + nice = -20; + if (nice > 19) + nice = 19; + set_user_nice(current, nice); return 0; } #endif -static inline struct task_struct *find_process_by_pid(pid_t pid) +/* + * This is the priority value as seen by users in /proc + * + * RT tasks are offset by -200. Normal tasks are centered + * around 0, value goes from -16 to +15. + */ +int task_prio(task_t *p) +{ + return p->prio - MAX_RT_PRIO; +} + +int task_nice(task_t *p) +{ + return TASK_NICE(p); +} + +int idle_cpu(int cpu) { - struct task_struct *tsk = current; + return cpu_curr(cpu) == cpu_rq(cpu)->idle; +} - if (pid) - tsk = find_task_by_pid(pid); - return tsk; +static inline task_t *find_process_by_pid(pid_t pid) +{ + return pid ? find_task_by_pid(pid) : current; } -static int setscheduler(pid_t pid, int policy, - struct sched_param *param) +static int setscheduler(pid_t pid, int policy, struct sched_param *param) { struct sched_param lp; - struct task_struct *p; + prio_array_t *array; + unsigned long flags; + runqueue_t *rq; int retval; + task_t *p; retval = -EINVAL; if (!param || pid < 0) @@ -917,14 +1400,19 @@ * We play safe to avoid deadlocks. */ read_lock_irq(&tasklist_lock); - spin_lock(&runqueue_lock); p = find_process_by_pid(pid); retval = -ESRCH; if (!p) - goto out_unlock; - + goto out_unlock_tasklist; + + /* + * To be able to change p->policy safely, the apropriate + * runqueue lock must be held. + */ + rq = task_rq_lock(p, &flags); + if (policy < 0) policy = p->policy; else { @@ -935,40 +1423,46 @@ } /* - * Valid priorities for SCHED_FIFO and SCHED_RR are 1..99, valid - * priority for SCHED_OTHER is 0. + * Valid priorities for SCHED_FIFO and SCHED_RR are + * 1..MAX_USER_RT_PRIO, valid priority for SCHED_OTHER is 0. */ retval = -EINVAL; - if (lp.sched_priority < 0 || lp.sched_priority > 99) + if (lp.sched_priority < 0 || lp.sched_priority > MAX_RT_PRIO - 1) goto out_unlock; if ((policy == SCHED_OTHER) != (lp.sched_priority == 0)) goto out_unlock; retval = -EPERM; - if ((policy == SCHED_FIFO || policy == SCHED_RR) && + if ((policy == SCHED_FIFO || policy == SCHED_RR) && !capable(CAP_SYS_NICE)) goto out_unlock; if ((current->euid != p->euid) && (current->euid != p->uid) && !capable(CAP_SYS_NICE)) goto out_unlock; + array = p->array; + if (array) + deactivate_task(p, task_rq(p)); retval = 0; p->policy = policy; p->rt_priority = lp.sched_priority; - if (task_on_runqueue(p)) - move_first_runqueue(p); - - current->need_resched = 1; + if (policy != SCHED_OTHER) + p->prio = (MAX_RT_PRIO - 1) - p->rt_priority; + else + p->prio = p->static_prio; + if (array) + activate_task(p, task_rq(p)); out_unlock: - spin_unlock(&runqueue_lock); + task_rq_unlock(rq, &flags); +out_unlock_tasklist: read_unlock_irq(&tasklist_lock); out_nounlock: return retval; } -asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, +asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param) { return setscheduler(pid, policy, param); @@ -981,7 +1475,7 @@ asmlinkage long sys_sched_getscheduler(pid_t pid) { - struct task_struct *p; + task_t *p; int retval; retval = -EINVAL; @@ -992,7 +1486,7 @@ read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (p) - retval = p->policy & ~SCHED_YIELD; + retval = p->policy; read_unlock(&tasklist_lock); out_nounlock: @@ -1001,7 +1495,7 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param) { - struct task_struct *p; + task_t *p; struct sched_param lp; int retval; @@ -1032,42 +1526,37 @@ asmlinkage long sys_sched_yield(void) { - /* - * Trick. sched_yield() first counts the number of truly - * 'pending' runnable processes, then returns if it's - * only the current processes. (This test does not have - * to be atomic.) In threaded applications this optimization - * gets triggered quite often. - */ - - int nr_pending = nr_running; + runqueue_t *rq = this_rq_lock(); + prio_array_t *array = current->array; + + /* + * Decrease the yielding task's priority by one, to avoid + * livelocks. This priority loss is temporary, it's recovered + * once the current timeslice expires. + * + * If priority is already MAX_PRIO-1 then we still + * roundrobin the task within the runlist. + */ + + /* + * If the task has reached maximum priority (or is a RT task) + * then just requeue the task to the end of the runqueue: + */ + if (likely(current->prio == MAX_PRIO-1 || rt_task(current))) { + list_del(¤t->run_list); + list_add_tail(¤t->run_list, array->queue + current->prio); + } else { + list_del(¤t->run_list); + if (list_empty(array->queue + current->prio)) + __clear_bit(current->prio, array->bitmap); + current->prio++; + list_add_tail(¤t->run_list, array->queue + current->prio); + __set_bit(current->prio, array->bitmap); + } + spin_unlock(&rq->lock); -#if CONFIG_SMP - int i; + schedule(); - // Subtract non-idle processes running on other CPUs. - for (i = 0; i < smp_num_cpus; i++) { - int cpu = cpu_logical_map(i); - if (aligned_data[cpu].schedule_data.curr != idle_task(cpu)) - nr_pending--; - } -#else - // on UP this process is on the runqueue as well - nr_pending--; -#endif - if (nr_pending) { - /* - * This process can only be rescheduled by us, - * so this is safe without any locking. - */ - if (current->policy == SCHED_OTHER) - current->policy |= SCHED_YIELD; - current->need_resched = 1; - - spin_lock_irq(&runqueue_lock); - move_last_runqueue(current); - spin_unlock_irq(&runqueue_lock); - } return 0; } @@ -1078,7 +1567,7 @@ switch (policy) { case SCHED_FIFO: case SCHED_RR: - ret = 99; + ret = MAX_RT_PRIO - 1; break; case SCHED_OTHER: ret = 0; @@ -1105,7 +1594,7 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) { struct timespec t; - struct task_struct *p; + task_t *p; int retval = -EINVAL; if (pid < 0) @@ -1115,8 +1604,8 @@ read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (p) - jiffies_to_timespec(p->policy & SCHED_FIFO ? 0 : NICE_TO_TICKS(p->nice), - &t); + jiffies_to_timespec(p->policy & SCHED_FIFO ? + 0 : TASK_TIMESLICE(p), &t); read_unlock(&tasklist_lock); if (p) retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; @@ -1124,14 +1613,14 @@ return retval; } -static void show_task(struct task_struct * p) +static void show_task(task_t * p) { unsigned long free = 0; int state; static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" }; printk("%-13.13s ", p->comm); - state = p->state ? ffz(~p->state) + 1 : 0; + state = p->state ? __ffs(p->state) + 1 : 0; if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *)) printk(stat_nam[state]); else @@ -1172,7 +1661,7 @@ printk(" (NOTLB)\n"); { - extern void show_trace_task(struct task_struct *tsk); + extern void show_trace_task(task_t *tsk); show_trace_task(p); } } @@ -1194,7 +1683,7 @@ void show_state(void) { - struct task_struct *p; + task_t *p; #if (BITS_PER_LONG == 32) printk("\n" @@ -1217,128 +1706,233 @@ read_unlock(&tasklist_lock); } -/** - * reparent_to_init() - Reparent the calling kernel thread to the init task. - * - * If a kernel thread is launched as a result of a system call, or if - * it ever exits, it should generally reparent itself to init so that - * it is correctly cleaned up on exit. - * - * The various task state such as scheduling policy and priority may have - * been inherited fro a user process, so we reset them to sane values here. - * - * NOTE that reparent_to_init() gives the caller full capabilities. - */ -void reparent_to_init(void) +void __init init_idle(task_t *idle, int cpu) { - struct task_struct *this_task = current; + runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(idle->cpu); + unsigned long flags; - write_lock_irq(&tasklist_lock); + __save_flags(flags); + __cli(); + double_rq_lock(idle_rq, rq); + + idle_rq->curr = idle_rq->idle = idle; + deactivate_task(idle, rq); + idle->array = NULL; + idle->prio = MAX_PRIO; + idle->state = TASK_RUNNING; + idle->cpu = cpu; + idle->cpus_allowed = 1UL << cpu; + double_rq_unlock(idle_rq, rq); + set_tsk_need_resched(idle); + __restore_flags(flags); +} - /* Reparent to init */ - REMOVE_LINKS(this_task); - this_task->p_pptr = child_reaper; - this_task->p_opptr = child_reaper; - SET_LINKS(this_task); +extern void init_timervecs(void); +extern void timer_bh(void); +extern void tqueue_bh(void); +extern void immediate_bh(void); - /* Set the exit signal to SIGCHLD so we signal init on exit */ - this_task->exit_signal = SIGCHLD; +void __init sched_init(void) +{ + runqueue_t *rq; + int i, j, k; - /* We also take the runqueue_lock while altering task fields - * which affect scheduling decisions */ - spin_lock(&runqueue_lock); + for (i = 0; i < NR_CPUS; i++) { + prio_array_t *array; - this_task->ptrace = 0; - this_task->nice = DEF_NICE; - this_task->policy = SCHED_OTHER; - /* cpus_allowed? */ - /* rt_priority? */ - /* signals? */ - this_task->cap_effective = CAP_INIT_EFF_SET; - this_task->cap_inheritable = CAP_INIT_INH_SET; - this_task->cap_permitted = CAP_FULL_SET; - this_task->keep_capabilities = 0; - memcpy(this_task->rlim, init_task.rlim, sizeof(*(this_task->rlim))); - this_task->user = INIT_USER; + rq = cpu_rq(i); + rq->active = rq->arrays; + rq->expired = rq->arrays + 1; + spin_lock_init(&rq->lock); + INIT_LIST_HEAD(&rq->migration_queue); + + for (j = 0; j < 2; j++) { + array = rq->arrays + j; + for (k = 0; k < MAX_PRIO; k++) { + INIT_LIST_HEAD(array->queue + k); + __clear_bit(k, array->bitmap); + } + // delimiter for bitsearch + __set_bit(MAX_PRIO, array->bitmap); + } + } + /* + * We have to do a little magic to get the first + * process right in SMP mode. + */ + rq = this_rq(); + rq->curr = current; + rq->idle = current; + wake_up_process(current); - spin_unlock(&runqueue_lock); - write_unlock_irq(&tasklist_lock); + init_timervecs(); + init_bh(TIMER_BH, timer_bh); + init_bh(TQUEUE_BH, tqueue_bh); + init_bh(IMMEDIATE_BH, immediate_bh); + + /* + * The boot idle thread does lazy MMU switching as well: + */ + atomic_inc(&init_mm.mm_count); + enter_lazy_tlb(&init_mm, current, smp_processor_id()); } +#if CONFIG_SMP + /* - * Put all the gunge required to become a kernel thread without - * attached user resources in one place where it belongs. + * This is how migration works (to migrate process "p"): + * + * 1) Reset p->cpus_allowed. + * 2) If (p) is not currently executing, then assign a p->cpu, and we're done. + * 3) If (p == current) and is currently executing, then we do the actual + * migration with-wait: enqueue a migration_req_t struct in p's CPU's + * runqueue, wake up that CPU's migration thread in order to preempt + * the current process (p), and wait for the migration thread to complete. + * 4) If (p != current) and is currently executing, then we do the migration + * nowait: wake up the migration thread to cause the preemption, but + * don't wait for the migration thread to do its work -- just exit. + * + * When schedule() is doing a context-switch from the migrating task to the + * migration_thread, it recognizes that the migrating task needs to migrate + * to an appropriate CPU, and schedule() performs the necessary queue + * manipulations on this now-not-executing task. */ -void daemonize(void) +typedef struct { + list_t list; + struct completion done; +} migration_req_t; + +/* + * Change a given task's CPU affinity. Migrate the process to a + * proper CPU and schedule it away if the CPU it's executing on + * is removed from the allowed bitmask. + * + * NOTE: the caller must have a valid reference to the task, and the task must + * not exit() & deallocate itself prematurely. + * If (p == current), then the caller must not hold any spinlocks. Upon exit, + * the process is guaranteed to have been moved to an appropriate CPU. + * If (p != current), then the caller should be holding locks that guarantee + * the validity of (task_t *p). Therefore, if (p != current) is currently + * executing (i.e., on another CPU), the migration will be done in a "lazy" + * manner at the first available time, and this routine exits with that + * operation still pending. + */ +void set_cpus_allowed(task_t *p, unsigned long new_mask) +{ + unsigned long flags; + migration_req_t req; + runqueue_t *rq; + + if (cpu_online_map) + new_mask &= cpu_online_map; + /* else just take new_mask verbatim */ + + if (!new_mask) + BUG(); + + rq = task_rq_lock(p, &flags); + p->cpus_allowed = new_mask; + /* + * Can the task run on the task's current CPU? If not then + * migrate the process off to a proper CPU. + */ + if (new_mask & (1UL << p->cpu)) { + task_rq_unlock(rq, &flags); + return; + } + /* + * If the task is not on a runqueue, then it is safe to + * simply update the task's cpu field. + */ + if (!p->array && !task_running(rq, p)) { + p->cpu = __ffs(p->cpus_allowed); + task_rq_unlock(rq, &flags); + return; + } + + if (p == current) { + init_completion(&req.done); + list_add(&req.list, &rq->migration_queue); + } + resched_task(p); /* be emphatic */ + task_rq_unlock(rq, &flags); + /* + * Wake up the migration_thread. Even if we're doing this in a "lazy + * migration" way, the migration_thread will preempt the target task + * and will see the task->cpu vs. task->cpus_allowed mismatch and + * do the migration. + */ + wake_up_process(rq->migration_thread); + + if (p == current) + wait_for_completion(&req.done); +} + +static int migration_thread(void * unused) { - struct fs_struct *fs; + int bind_cpu = (int) (long) unused; + int cpu = cpu_logical_map(bind_cpu); + struct sched_param param = { sched_priority: 99 }; + runqueue_t *rq; + int ret; + daemonize(); + sigfillset(¤t->blocked); + set_fs(KERNEL_DS); /* - * If we were started as result of loading a module, close all of the - * user space pages. We don't need them, and if we didn't close them - * they would be locked into memory. + * The first migration task is started on CPU #0. This one can migrate + * the tasks to their destination CPUs. */ - exit_mm(current); - - current->session = 1; - current->pgrp = 1; - current->tty = NULL; + if (cpu != 0) { + while (!cpu_rq(cpu_logical_map(0))->migration_thread) + yield(); + } + set_cpus_allowed(current, 1UL << cpu); +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) + printk("migration_task %d on cpu=%d\n",cpu,smp_processor_id()); +#endif + ret = setscheduler(0, SCHED_FIFO, ¶m); - /* Become as one with the init task */ + rq = this_rq(); + rq->migration_thread = current; - exit_fs(current); /* current->fs->count--; */ - fs = init_task.fs; - current->fs = fs; - atomic_inc(&fs->count); - exit_files(current); - current->files = init_task.files; - atomic_inc(¤t->files->count); -} + sprintf(current->comm, "migration_CPU%d", smp_processor_id()); -extern unsigned long wait_init_idle; + for (;;) { + struct list_head *head; + migration_req_t *req; + unsigned long flags; -void __init init_idle(void) -{ - struct schedule_data * sched_data; - sched_data = &aligned_data[smp_processor_id()].schedule_data; + spin_lock_irqsave(&rq->lock, flags); + head = &rq->migration_queue; + current->state = TASK_INTERRUPTIBLE; + if (list_empty(head)) { + spin_unlock_irqrestore(&rq->lock, flags); + schedule(); + continue; + } + req = list_entry(head->next, migration_req_t, list); + list_del_init(head->next); + spin_unlock_irqrestore(&rq->lock, flags); - if (current != &init_task && task_on_runqueue(current)) { - printk("UGH! (%d:%d) was on the runqueue, removing.\n", - smp_processor_id(), current->pid); - del_from_runqueue(current); + complete(&req->done); } - sched_data->curr = current; - sched_data->last_schedule = get_cycles(); - clear_bit(current->processor, &wait_init_idle); } -extern void init_timervecs (void); - -void __init sched_init(void) +void __init migration_init(void) { - /* - * We have to do a little magic to get the first - * process right in SMP mode. - */ - int cpu = smp_processor_id(); - int nr; - - init_task.processor = cpu; - - for(nr = 0; nr < PIDHASH_SZ; nr++) - pidhash[nr] = NULL; + int cpu; - init_timervecs(); - - init_bh(TIMER_BH, timer_bh); - init_bh(TQUEUE_BH, tqueue_bh); - init_bh(IMMEDIATE_BH, immediate_bh); + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (kernel_thread(migration_thread, (void *) (long) cpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) + BUG(); + } - /* - * The boot idle thread does lazy MMU switching as well: - */ - atomic_inc(&init_mm.mm_count); - enter_lazy_tlb(&init_mm, current, cpu); + for (cpu = 0; cpu < smp_num_cpus; cpu++) + while (!cpu_rq(cpu)->migration_thread) + schedule_timeout(2); } +#endif diff -Nur linux-2.4.19/kernel/signal.c linux-2.4.19-sgi211r3/kernel/signal.c --- linux-2.4.19/kernel/signal.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/signal.c Mon Oct 28 20:43:23 2002 @@ -507,12 +507,9 @@ * process of changing - but no harm is done by that * other than doing an extra (lightweight) IPI interrupt. */ - spin_lock(&runqueue_lock); - if (task_has_cpu(t) && t->processor != smp_processor_id()) - smp_send_reschedule(t->processor); - spin_unlock(&runqueue_lock); -#endif /* CONFIG_SMP */ - + if ((t->state == TASK_RUNNING)) + kick_if_running(t); +#endif if (t->state & TASK_INTERRUPTIBLE) { wake_up_process(t); return; @@ -1171,8 +1168,19 @@ ss_sp = NULL; } else { error = -ENOMEM; +#ifdef __ia64__ + /* + * XXX fix me: due to an oversight, MINSIGSTKSZ used to be defined + * as 2KB, which is far too small. This was after Linux kernel + * 2.4.9 but since there are a fair number of ia64 apps out there, + * we continue to allow "too" small sigaltstacks for a while. + */ + if (ss_size < 2048) + goto out; +#else if (ss_size < MINSIGSTKSZ) goto out; +#endif } current->sas_ss_sp = (unsigned long) ss_sp; diff -Nur linux-2.4.19/kernel/softirq.c linux-2.4.19-sgi211r3/kernel/softirq.c --- linux-2.4.19/kernel/softirq.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/softirq.c Fri Nov 1 16:08:31 2002 @@ -16,6 +16,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* - No shared variables, all the data are CPU local. @@ -40,7 +43,10 @@ - Bottom halves: globally serialized, grr... */ +/* No separate irq_stat for ia64, it is part of PSA */ +#if !defined(CONFIG_IA64) irq_cpustat_t irq_stat[NR_CPUS]; +#endif /* CONFIG_IA64 */ static struct softirq_action softirq_vec[32] __cacheline_aligned; @@ -60,17 +66,20 @@ asmlinkage void do_softirq() { - int cpu = smp_processor_id(); __u32 pending; unsigned long flags; __u32 mask; if (in_interrupt()) return; +#ifdef CONFIG_KDB + if (KDB_IS_RUNNING()) + return; +#endif /*CONFIG_KDB */ local_irq_save(flags); - pending = softirq_pending(cpu); + pending = local_softirq_pending(); if (pending) { struct softirq_action *h; @@ -79,7 +88,7 @@ local_bh_disable(); restart: /* Reset the pending bitmask before enabling irqs */ - softirq_pending(cpu) = 0; + local_softirq_pending() = 0; local_irq_enable(); @@ -94,7 +103,7 @@ local_irq_disable(); - pending = softirq_pending(cpu); + pending = local_softirq_pending(); if (pending & mask) { mask &= ~pending; goto restart; @@ -102,7 +111,7 @@ __local_bh_enable(); if (pending) - wakeup_softirqd(cpu); + wakeup_softirqd(smp_processor_id()); } local_irq_restore(flags); @@ -124,7 +133,7 @@ * Otherwise we wake up ksoftirqd to make sure we * schedule the softirq soon. */ - if (!(local_irq_count(cpu) | local_bh_count(cpu))) + if (!(irq_count(cpu) | bh_count(cpu))) wakeup_softirqd(cpu); } @@ -259,10 +268,9 @@ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { current->state = TASK_RUNNING; - do { - current->policy |= SCHED_YIELD; - schedule(); - } while (test_bit(TASKLET_STATE_SCHED, &t->state)); + do + sys_sched_yield(); + while (test_bit(TASKLET_STATE_SCHED, &t->state)); } tasklet_unlock_wait(t); clear_bit(TASKLET_STATE_SCHED, &t->state); @@ -288,18 +296,16 @@ static void bh_action(unsigned long nr) { - int cpu = smp_processor_id(); - if (!spin_trylock(&global_bh_lock)) goto resched; - if (!hardirq_trylock(cpu)) + if (!local_hardirq_trylock()) goto resched_unlock; if (bh_base[nr]) bh_base[nr](); - hardirq_endlock(cpu); + local_hardirq_endlock(); spin_unlock(&global_bh_lock); return; @@ -365,28 +371,28 @@ int cpu = cpu_logical_map(bind_cpu); daemonize(); - current->nice = 19; + set_user_nice(current, 19); sigfillset(¤t->blocked); /* Migrate to the right CPU */ - current->cpus_allowed = 1UL << cpu; - while (smp_processor_id() != cpu) - schedule(); + set_cpus_allowed(current, 1UL << cpu); + while (cpu() != cpu) + BUG(); sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu); __set_current_state(TASK_INTERRUPTIBLE); mb(); - ksoftirqd_task(cpu) = current; + local_ksoftirqd_task() = current; for (;;) { - if (!softirq_pending(cpu)) + if (!local_softirq_pending()) schedule(); __set_current_state(TASK_RUNNING); - while (softirq_pending(cpu)) { + while (local_softirq_pending()) { do_softirq(); if (current->need_resched) schedule(); @@ -396,7 +402,7 @@ } } -static __init int spawn_ksoftirqd(void) +__init int spawn_ksoftirqd(void) { int cpu; @@ -405,10 +411,8 @@ CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) printk("spawn_ksoftirqd() failed for cpu %d\n", cpu); else { - while (!ksoftirqd_task(cpu_logical_map(cpu))) { - current->policy |= SCHED_YIELD; - schedule(); - } + while (!ksoftirqd_task(cpu_logical_map(cpu))) + sys_sched_yield(); } } diff -Nur linux-2.4.19/kernel/sys.c linux-2.4.19-sgi211r3/kernel/sys.c --- linux-2.4.19/kernel/sys.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/sys.c Fri Nov 1 12:08:15 2002 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -14,10 +15,60 @@ #include #include #include +#include +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#include +#endif #include #include + +#ifdef SGI_PRCTL_EXTENSIONS +#ifdef CONFIG_IA64 +/* + * Add a temp hack for diagnostics so they can translate virtual + * addresses to physical addresses. This hack will be replaced later + * by code that is being developed by the propack folks. + * + * As currently written, the system call is available ONLY on IA64. + * This (I assume) will change later. + * + * (Note: since this code is throwaway, I took the opportunity to + * learn more about asm statements & exception handling. I _know_ + * that this code should be architecture independent). + */ + +/* + * These macros probably belong in . + */ + + +#define user_tpa(x,ptr) __user_tpa_check((x),(ptr),sizeof(*(ptr)),get_fs()) + +#define __user_tpa_check(x,ptr,size,segment) \ +({ \ + register long __gu_err __asm__ ("r8") = -EFAULT; \ + register long __gu_val __asm__ ("r9") = 0; \ + const __typeof__(*(ptr)) *__gu_addr = (ptr); \ + if (__access_ok((long)__gu_addr,size,segment)) { \ + __gu_err = 0; \ + __user_tpa(__gu_addr); \ + } \ + (x) = __gu_val; \ + __gu_err; \ +}) + +#define __user_tpa(addr) \ + __asm__ ("\n"_LL"\ttpa %0=%2\t// %0 and %1 get overwritten by exc handler\n" \ + "\t.xdata8 \"__ex_table\", 1b, 1f+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "r"(addr), "1"(__gu_err)); + + +#endif +#endif + /* * this is where the system-wide overflow UID and GID are defined, for * architectures that now have 32-bit UID/GID but didn't in the past @@ -49,6 +100,9 @@ */ static struct notifier_block *reboot_notifier_list; +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +struct notifier_block *dump_notifier_list; +#endif rwlock_t notifier_lock = RW_LOCK_UNLOCKED; /** @@ -167,6 +221,39 @@ return notifier_chain_unregister(&reboot_notifier_list, nb); } +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +/** + * register_dump_notifier - Register function to be called at dump time + * @nb: Info about notifier function to be called + * + * Registers a function with the list of functions + * to be called at dump time. + * + * Currently always returns zero, as notifier_chain_register + * always returns zero. + */ + +int register_dump_notifier(struct notifier_block * nb) +{ + return notifier_chain_register(&dump_notifier_list, nb); +} + +/** + * unregister_dump_notifier - Unregister previously registered dump notifier + * @nb: Hook to be unregistered + * + * Unregisters a previously registered dump + * notifier function. + * + * Returns zero on success, or %-ENOENT on failure. + */ + +int unregister_dump_notifier(struct notifier_block * nb) +{ + return notifier_chain_unregister(&dump_notifier_list, nb); +} +#endif + asmlinkage long sys_ni_syscall(void) { return -ENOSYS; @@ -220,10 +307,10 @@ } if (error == -ESRCH) error = 0; - if (niceval < p->nice && !capable(CAP_SYS_NICE)) + if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) error = -EACCES; else - p->nice = niceval; + set_user_nice(p, niceval); } read_unlock(&tasklist_lock); @@ -249,7 +336,7 @@ long niceval; if (!proc_sel(p, which, who)) continue; - niceval = 20 - p->nice; + niceval = 20 - task_nice(p); if (niceval > retval) retval = niceval; } @@ -1205,6 +1292,7 @@ { int error = 0; int sig; + long paddr, *paddrp, val; switch (option) { case PR_SET_PDEATHSIG: @@ -1272,6 +1360,64 @@ } current->keep_capabilities = arg2; break; +#ifdef SGI_PRCTL_EXTENSIONS +#ifdef CONFIG_IA64 + case PR_TRIGGER_LOGIC_ANALYZER: + paddrp = (long*)0xc0000a0001000020UL; /* PI_CPU_NUM */ + *paddrp = arg2; + break; + case PR_GET_PHYSICAL_ADDRESS: + user_tpa(paddr, (char*)arg2); + error = put_user(paddr, (long*)arg3); + break; + case PR_GET_LID_REGISTER: + val = ia64_get_lid() | (smp_num_cpus << 8) | smp_processor_id(); + error = put_user(val, (int *)arg2); + break; +#endif /* CONFIG_IA64 */ + case PR_GET_RUNON: + error = put_user(current->cpus_allowed, (long *)arg2); + break; + case PR_SET_RUNON: + if (arg2 == 0) + arg2 = 1UL << smp_processor_id(); + arg2 &= cpu_online_map; + if (!arg2) + error = -EINVAL; + else { + set_cpus_allowed(current, arg2); + } + + break; + + +#ifdef CONFIG_CPUMEMSET + case PR_QUERY_CMM_SIZE: + error = cms_query_cmm_size((unsigned long *)arg2, (int *)arg3); + break; + case PR_QUERY_CMS_SIZE: + error = cms_query_cms_size((unsigned long *)arg2, (int *)arg3); + break; + case PR_QUERY_CMM: + error = cms_query_cmm((unsigned long *)arg2, (char *)arg3, (int)arg4); + break; + case PR_QUERY_CMS: + error = cms_query_cms((unsigned long *)arg2, (char *)arg3, (int)arg4); + break; + case PR_SET_CMM: + error = cms_set_cmm((unsigned long *)arg2, (char *)arg3, (int)arg4); + break; + case PR_SET_CMS: + error = cms_set_cms((unsigned long *)arg2, (char *)arg3, (int)arg4); + break; + case PR_CMS_UNUSED: + error = -ENOSYS; + break; + case PR_GET_CPU: + error = cms_getcpu(); + break; +#endif /* CONFIG_CPUMEMSET */ +#endif /* SGI_PRCTL_EXTENSIONS */ default: error = -EINVAL; break; diff -Nur linux-2.4.19/kernel/sysctl.c linux-2.4.19-sgi211r3/kernel/sysctl.c --- linux-2.4.19/kernel/sysctl.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/sysctl.c Thu Dec 12 12:39:32 2002 @@ -30,6 +30,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include @@ -55,6 +58,10 @@ static int maxolduid = 65535; static int minolduid; +#ifdef SGI_SN_EXECUTABLE_STACKS +int Vm_executable_stacks=1; +#endif + #ifdef CONFIG_KMOD extern char modprobe_path[]; #endif @@ -256,6 +263,10 @@ {KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug", &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec}, #endif +#ifdef CONFIG_KDB + {KERN_KDB, "kdb", &kdb_on, sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif /* CONFIG_KDB */ {0} }; @@ -277,6 +288,10 @@ &vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec}, {VM_MAX_MAP_COUNT, "max_map_count", &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec}, +#ifdef SGI_SN_EXECUTABLE_STACKS + {VM_EXECUTABLE_STACKS, "executable_stacks", + &Vm_executable_stacks, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif {0} }; @@ -293,8 +308,6 @@ 0444, NULL, &proc_dointvec}, {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int), 0644, NULL, &proc_dointvec}, - {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int), - 0444, NULL, &proc_dointvec}, {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int), 0444, NULL, &proc_dointvec}, {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL, diff -Nur linux-2.4.19/kernel/time.c linux-2.4.19-sgi211r3/kernel/time.c --- linux-2.4.19/kernel/time.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/time.c Mon Oct 28 09:18:11 2002 @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -38,7 +39,8 @@ /* The xtime_lock is not only serializing the xtime read/writes but it's also serializing all accesses to the global NTP variables now. */ -extern rwlock_t xtime_lock; +extern frlock_t xtime_lock; +extern unsigned long last_time_offset; #if !defined(__alpha__) && !defined(__ia64__) @@ -79,14 +81,15 @@ return -EPERM; if (get_user(value, tptr)) return -EFAULT; - write_lock_irq(&xtime_lock); + fr_write_lock_irq(&xtime_lock); xtime.tv_sec = value; xtime.tv_usec = 0; + last_time_offset = 0; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - write_unlock_irq(&xtime_lock); + fr_write_unlock_irq(&xtime_lock); return 0; } @@ -125,9 +128,10 @@ */ inline static void warp_clock(void) { - write_lock_irq(&xtime_lock); + fr_write_lock_irq(&xtime_lock); xtime.tv_sec += sys_tz.tz_minuteswest * 60; - write_unlock_irq(&xtime_lock); + last_time_offset = 0; + fr_write_unlock_irq(&xtime_lock); } /* @@ -213,7 +217,7 @@ /* In order to modify anything, you gotta be super-user! */ if (txc->modes && !capable(CAP_SYS_TIME)) return -EPERM; - + /* Now we validate the data before disabling interrupts */ if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) @@ -224,14 +228,14 @@ if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET)) /* adjustment Offset limited to +- .512 seconds */ if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE ) - return -EINVAL; + return -EINVAL; /* if the quartz is off by more than 10% something is VERY wrong ! */ if (txc->modes & ADJ_TICK) if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) return -EINVAL; - write_lock_irq(&xtime_lock); + fr_write_lock_irq(&xtime_lock); result = time_state; /* mostly `TIME_OK' */ /* Save for later - semantics of adjtime is to return old value */ @@ -361,7 +365,7 @@ && (time_status & (STA_PPSWANDER|STA_PPSERROR)) != 0)) /* p. 24, (d) */ result = TIME_ERROR; - + if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) txc->offset = save_adjust; else { @@ -386,7 +390,8 @@ txc->calcnt = pps_calcnt; txc->errcnt = pps_errcnt; txc->stbcnt = pps_stbcnt; - write_unlock_irq(&xtime_lock); + last_time_offset = 0; + fr_write_unlock_irq(&xtime_lock); do_gettimeofday(&txc->time); return(result); } diff -Nur linux-2.4.19/kernel/timer.c linux-2.4.19-sgi211r3/kernel/timer.c --- linux-2.4.19/kernel/timer.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/kernel/timer.c Mon Oct 28 20:43:23 2002 @@ -22,9 +22,12 @@ #include #include #include +#include #include +struct kernel_stat kstat; + /* * Timekeeping variables */ @@ -598,18 +601,7 @@ int cpu = smp_processor_id(), system = user_tick ^ 1; update_one_process(p, user_tick, system, cpu); - if (p->pid) { - if (--p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->nice > 0) - kstat.per_cpu_nice[cpu] += user_tick; - else - kstat.per_cpu_user[cpu] += user_tick; - kstat.per_cpu_system[cpu] += system; - } else if (local_bh_count(cpu) || local_irq_count(cpu) > 1) - kstat.per_cpu_system[cpu] += system; + scheduler_tick(user_tick, system); } /* @@ -617,17 +609,7 @@ */ static unsigned long count_active_tasks(void) { - struct task_struct *p; - unsigned long nr = 0; - - read_lock(&tasklist_lock); - for_each_task(p) { - if ((p->state == TASK_RUNNING || - (p->state & TASK_UNINTERRUPTIBLE))) - nr += FIXED_1; - } - read_unlock(&tasklist_lock); - return nr; + return (nr_running() + nr_uninterruptible()) * FIXED_1; } /* @@ -659,7 +641,8 @@ /* * This spinlock protect us from races in SMP while playing with xtime. -arca */ -rwlock_t xtime_lock = RW_LOCK_UNLOCKED; +frlock_t xtime_lock __cacheline_aligned_in_smp = FR_LOCK_UNLOCKED; +unsigned long last_time_offset; static inline void update_times(void) { @@ -670,14 +653,15 @@ * just know that the irqs are locally enabled and so we don't * need to save/restore the flags of the local CPU here. -arca */ - write_lock_irq(&xtime_lock); + fr_write_lock_irq(&xtime_lock); ticks = jiffies - wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); } - write_unlock_irq(&xtime_lock); + last_time_offset = 0; + fr_write_unlock_irq(&xtime_lock); calc_load(ticks); } @@ -689,7 +673,7 @@ void do_timer(struct pt_regs *regs) { - (*(unsigned long *)&jiffies)++; + (*(volatile unsigned long *)&jiffies)++; #ifndef CONFIG_SMP /* SMP process accounting uses the local APIC timer */ @@ -810,6 +794,89 @@ #endif +static void process_timeout(unsigned long __data) +{ + wake_up_process((task_t *)__data); +} + +/** + * schedule_timeout - sleep until timeout + * @timeout: timeout value in jiffies + * + * Make the current task sleep until @timeout jiffies have + * elapsed. The routine will return immediately unless + * the current task state has been set (see set_current_state()). + * + * You can set the task state as follows - + * + * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to + * pass before the routine returns. The routine will return 0 + * + * %TASK_INTERRUPTIBLE - the routine may return early if a signal is + * delivered to the current task. In this case the remaining time + * in jiffies will be returned, or 0 if the timer expired in time + * + * The current task state is guaranteed to be TASK_RUNNING when this + * routine returns. + * + * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule + * the CPU away without a bound on the timeout. In this case the return + * value will be %MAX_SCHEDULE_TIMEOUT. + * + * In all cases the return value is guaranteed to be non-negative. + */ +signed long schedule_timeout(signed long timeout) +{ + struct timer_list timer; + unsigned long expire; + + switch (timeout) + { + case MAX_SCHEDULE_TIMEOUT: + /* + * These two special cases are useful to be comfortable + * in the caller. Nothing more. We could take + * MAX_SCHEDULE_TIMEOUT from one of the negative value + * but I' d like to return a valid offset (>=0) to allow + * the caller to do everything it want with the retval. + */ + schedule(); + goto out; + default: + /* + * Another bit of PARANOID. Note that the retval will be + * 0 since no piece of kernel is supposed to do a check + * for a negative retval of schedule_timeout() (since it + * should never happens anyway). You just have the printk() + * that will tell you if something is gone wrong and where. + */ + if (timeout < 0) + { + printk(KERN_ERR "schedule_timeout: wrong timeout " + "value %lx from %p\n", timeout, + __builtin_return_address(0)); + current->state = TASK_RUNNING; + goto out; + } + } + + expire = timeout + jiffies; + + init_timer(&timer); + timer.expires = expire; + timer.data = (unsigned long) current; + timer.function = process_timeout; + + add_timer(&timer); + schedule(); + del_timer_sync(&timer); + + timeout = expire - jiffies; + + out: + return timeout < 0 ? 0 : timeout; +} + /* Thread ID - the internal kernel "pid" */ asmlinkage long sys_gettid(void) { @@ -827,7 +894,7 @@ if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0) return -EINVAL; - +#if !defined(__ia64__) if (t.tv_sec == 0 && t.tv_nsec <= 2000000L && current->policy != SCHED_OTHER) { @@ -840,6 +907,7 @@ udelay((t.tv_nsec + 999) / 1000); return 0; } +#endif expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); @@ -856,4 +924,3 @@ } return 0; } - diff -Nur linux-2.4.19/lib/Makefile linux-2.4.19-sgi211r3/lib/Makefile --- linux-2.4.19/lib/Makefile Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/lib/Makefile Wed Oct 16 14:02:58 2002 @@ -19,4 +19,12 @@ obj-y += dec_and_lock.o endif +# lib/sgi/Makefile uses shorthand forms that assume the directory is processed +# only once. Work out how to process libsgi once, based on its consumers. +CONFIG_LIBSGI := $(subst m y,y,$(sort $(CONFIG_XSCSI) $(CONFIG_XVM))) +subdir-$(CONFIG_LIBSGI) += sgi +ifeq ($(CONFIG_LIBSGI),y) + obj-y += sgi/libsgi.o +endif + include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/lib/sgi/Makefile linux-2.4.19-sgi211r3/lib/sgi/Makefile --- linux-2.4.19/lib/sgi/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/Makefile Sun Aug 4 22:21:57 2002 @@ -0,0 +1,9 @@ +#EXTRA_CFLAGS += -DDEBUG +SGIOBJS = debug.o kmem.o ktrace.o move.o mrlock.o mutex.o sv.o uuid.o + +O_TARGET := libsgi.o +obj-m := $(O_TARGET) +export-objs := $(SGIOBJS) +obj-y := sgi.o $(SGIOBJS) + +include $(TOPDIR)/Rules.make diff -Nur linux-2.4.19/lib/sgi/debug.c linux-2.4.19-sgi211r3/lib/sgi/debug.c --- linux-2.4.19/lib/sgi/debug.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/debug.c Sun May 26 21:57:45 2002 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +/* XXX we really should be able to move this into DEBUG below */ + +int doass = 1; + +void +assfail(char *a, char *f, int l) +{ + printk("Assertion failed: %s, file: %s, line: %d\n", a, f, l); + BUG(); +} + +#ifdef DEBUG + +unsigned long +random(void) +{ + static unsigned long RandomValue = 1; + /* cycles pseudo-randomly through all values between 1 and 2^31 - 2 */ + register long rv = RandomValue; + register long lo; + register long hi; + + hi = rv / 127773; + lo = rv % 127773; + rv = 16807 * lo - 2836 * hi; + if( rv <= 0 ) rv += 2147483647; + return( RandomValue = rv ); +} + +int +get_thread_id(void) +{ + return current->pid; +} + +EXPORT_SYMBOL(random); +EXPORT_SYMBOL(get_thread_id); + +# define xdprintk(format...) printk(format) +#else +# define xdprintk(format...) do { } while (0) +#endif + +void +cmn_err(register int level, char *fmt, ...) +{ + char *fp = fmt; + char message[256]; + va_list ap; + + va_start(ap, fmt); + if (*fmt == '!') fp++; + vsprintf(message, fp, ap); + switch (level) { + case CE_CONT: + printk("%s", message); + break; + case CE_DEBUG: + xdprintk("%s", message); + break; + default: + printk("%s\n", message); + break; + } + va_end(ap); +} + + +void +icmn_err(register int level, char *fmt, va_list ap) +{ + char message[256]; + + vsprintf(message, fmt, ap); + switch (level) { + case CE_CONT: + printk("%s", message); + break; + case CE_DEBUG: + xdprintk("%s", message); + break; + default: + printk("cmn_err level %d ", level); + printk("%s\n", message); + break; + } +} + +EXPORT_SYMBOL(icmn_err); +EXPORT_SYMBOL(cmn_err); +EXPORT_SYMBOL(doass); +EXPORT_SYMBOL(assfail); diff -Nur linux-2.4.19/lib/sgi/kmem.c linux-2.4.19-sgi211r3/lib/sgi/kmem.c --- linux-2.4.19/lib/sgi/kmem.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/kmem.c Tue Jul 30 16:25:42 2002 @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) +#define SLAB_NOFS SLAB_BUFFER +#define GFP_NOFS GFP_BUFFER +#endif + +#define DEF_PRIORITY (6) +#define MAX_SLAB_SIZE 0x10000 + +static __inline__ unsigned int flag_convert(int flags) +{ + if (flags & KM_NOSLEEP) return GFP_ATOMIC; + /* If we're in a transaction, FS activity is not ok */ + if (current->flags & PF_FSTRANS) return GFP_NOFS; + return GFP_KERNEL; +} + +#define MAX_SHAKE 8 + +static kmem_shake_func_t shake_list[MAX_SHAKE]; +static DECLARE_MUTEX(shake_sem); + +void kmem_shake_register(kmem_shake_func_t sfunc) +{ + int i; + + down(&shake_sem); + for (i = 0; i < MAX_SHAKE; i++) { + if (shake_list[i] == NULL) { + shake_list[i] = sfunc; + break; + } + } + if (i == MAX_SHAKE) + BUG(); + up(&shake_sem); +} + +void kmem_shake_deregister(kmem_shake_func_t sfunc) +{ + int i; + + down(&shake_sem); + for (i = 0; i < MAX_SHAKE; i++) { + if (shake_list[i] == sfunc) + break; + } + if (i == MAX_SHAKE) + BUG(); + for (; i < MAX_SHAKE - 1; i++) { + shake_list[i] = shake_list[i+1]; + } + shake_list[i] = NULL; + up(&shake_sem); +} + +static __inline__ void kmem_shake(void) +{ + int i; + + down(&shake_sem); + for (i = 0; i < MAX_SHAKE && shake_list[i]; i++) + (*shake_list[i])(); + up(&shake_sem); + delay(10); +} + +void * +kmem_alloc(size_t size, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *rval; + +repeat: + if (MAX_SLAB_SIZE < size) { + /* Avoid doing filesystem sensitive stuff to get this */ + rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); + } else { + rval = kmalloc(size, flag_convert(flags)); + } + + if (rval || (flags & KM_NOSLEEP)) + return rval; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(); + + shrink--; + goto repeat; + } + + rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); + if (!rval && !(flags & KM_SLEEP)) + panic("kmem_alloc: NULL memory on KM_SLEEP request!"); + + return rval; +} + +void * +kmem_zalloc(size_t size, int flags) +{ + void *ptr; + + ptr = kmem_alloc(size, flags); + + if (ptr) + memset((char *)ptr, 0, (int)size); + + return (ptr); +} + +void +kmem_free(void *ptr, size_t size) +{ + struct page *p = virt_to_page(ptr); + if (VALID_PAGE(p) && PageSlab(p)) { + kfree(ptr); + } else { + vfree(ptr); + } +} + +void * +kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags) +{ + void *new; + + new = kmem_alloc(newsize, flags); + if (ptr) { + memcpy(new, ptr, ((oldsize < newsize) ? oldsize : newsize)); + kmem_free(ptr, oldsize); + } + + return new; +} + +kmem_zone_t * +kmem_zone_init(int size, char *zone_name) +{ + return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL); +} + +void * +kmem_zone_alloc(kmem_zone_t *zone, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *ptr = NULL; + +repeat: + ptr = kmem_cache_alloc(zone, flag_convert(flags)); + + if (ptr || (flags & KM_NOSLEEP)) + return ptr; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(); + + shrink--; + goto repeat; + } + + if (flags & KM_SLEEP) + panic("kmem_zone_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} + +void * +kmem_zone_zalloc(kmem_zone_t *zone, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *ptr = NULL; + +repeat: + ptr = kmem_cache_zalloc(zone, flag_convert(flags)); + + if (ptr || (flags & KM_NOSLEEP)) + return ptr; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(); + + shrink--; + goto repeat; + } + + if (flags & KM_SLEEP) + panic("kmem_zone_zalloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} + +void +kmem_zone_free(kmem_zone_t *zone, void *ptr) +{ + kmem_cache_free(zone, ptr); +} + +EXPORT_SYMBOL(kmem_zone_init); +EXPORT_SYMBOL(kmem_zone_zalloc); +EXPORT_SYMBOL(kmem_zone_alloc); +EXPORT_SYMBOL(kmem_zone_free); +EXPORT_SYMBOL(kmem_alloc); +EXPORT_SYMBOL(kmem_realloc); +EXPORT_SYMBOL(kmem_zalloc); +EXPORT_SYMBOL(kmem_free); +EXPORT_SYMBOL(kmem_shake_register); +EXPORT_SYMBOL(kmem_shake_deregister); diff -Nur linux-2.4.19/lib/sgi/ktrace.c linux-2.4.19-sgi211r3/lib/sgi/ktrace.c --- linux-2.4.19/lib/sgi/ktrace.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/ktrace.c Sun May 26 21:57:45 2002 @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include + +#if defined(DEBUG) + +static kmem_zone_t *ktrace_hdr_zone; +static kmem_zone_t *ktrace_ent_zone; +static int ktrace_zentries; + +void +ktrace_init(int zentries) +{ + ktrace_zentries = zentries; + + ktrace_hdr_zone = kmem_zone_init(sizeof(ktrace_t), + "ktrace_hdr"); + ASSERT(ktrace_hdr_zone); + + ktrace_ent_zone = kmem_zone_init(ktrace_zentries + * sizeof(ktrace_entry_t), + "ktrace_ent"); + ASSERT(ktrace_ent_zone); +} + +void +ktrace_uninit(void) +{ + kmem_cache_destroy(ktrace_hdr_zone); + kmem_cache_destroy(ktrace_ent_zone); +} + +/* + * ktrace_alloc() + * + * Allocate a ktrace header and enough buffering for the given + * number of entries. + */ +ktrace_t * +ktrace_alloc(int nentries, int sleep) +{ + ktrace_t *ktp; + ktrace_entry_t *ktep; + + ktp = (ktrace_t*)kmem_zone_alloc(ktrace_hdr_zone, sleep); + + if (ktp == (ktrace_t*)NULL) { + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; + } + + /* + * Special treatment for buffers with the ktrace_zentries entries + */ + if (nentries == ktrace_zentries) { + ktep = (ktrace_entry_t*)kmem_zone_zalloc(ktrace_ent_zone, + sleep); + } else { + ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)), + sleep); + } + + if (ktep == NULL) { + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + kmem_free(ktp, sizeof(*ktp)); + + return NULL; + } + + spinlock_init(&(ktp->kt_lock), "kt_lock"); + + ktp->kt_entries = ktep; + ktp->kt_nentries = nentries; + ktp->kt_index = 0; + ktp->kt_rollover = 0; + + return ktp; +} + + +/* + * ktrace_free() + * + * Free up the ktrace header and buffer. It is up to the caller + * to ensure that no-one is referencing it. + */ +void +ktrace_free(ktrace_t *ktp) +{ + int entries_size; + + if (ktp == (ktrace_t *)NULL) + return; + + spinlock_destroy(&ktp->kt_lock); + + /* + * Special treatment for the Vnode trace buffer. + */ + if (ktp->kt_nentries == ktrace_zentries) { + kmem_zone_free(ktrace_ent_zone, ktp->kt_entries); + } else { + entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t)); + + kmem_free(ktp->kt_entries, entries_size); + } + + kmem_zone_free(ktrace_hdr_zone, ktp); +} + + +/* + * Enter the given values into the "next" entry in the trace buffer. + * kt_index is always the index of the next entry to be filled. + */ +void +ktrace_enter( + ktrace_t *ktp, + void *val0, + void *val1, + void *val2, + void *val3, + void *val4, + void *val5, + void *val6, + void *val7, + void *val8, + void *val9, + void *val10, + void *val11, + void *val12, + void *val13, + void *val14, + void *val15) +{ + int index; + ktrace_entry_t *ktep; + + ASSERT(ktp != NULL); + + /* + * Grab an entry by pushing the index up to the next one. + */ + index = atomicIncWithWrap(&ktp->kt_index, ktp->kt_nentries); + + if (!ktp->kt_rollover && index == ktp->kt_nentries - 1) + ktp->kt_rollover = 1; + + ASSERT((index >= 0) && (index < ktp->kt_nentries)); + + ktep = &(ktp->kt_entries[index]); + + ktep->val[0] = val0; + ktep->val[1] = val1; + ktep->val[2] = val2; + ktep->val[3] = val3; + ktep->val[4] = val4; + ktep->val[5] = val5; + ktep->val[6] = val6; + ktep->val[7] = val7; + ktep->val[8] = val8; + ktep->val[9] = val9; + ktep->val[10] = val10; + ktep->val[11] = val11; + ktep->val[12] = val12; + ktep->val[13] = val13; + ktep->val[14] = val14; + ktep->val[15] = val15; +} + +/* + * Return the number of entries in the trace buffer. + */ +int +ktrace_nentries( + ktrace_t *ktp) +{ + if (ktp == NULL) { + return 0; + } + + return (ktp->kt_rollover ? ktp->kt_nentries : ktp->kt_index); +} + + +/* + * ktrace_first() + * + * This is used to find the start of the trace buffer. + * In conjunction with ktrace_next() it can be used to + * iterate through the entire trace buffer. This code does + * not do any locking because it is assumed that it is called + * from the debugger. + * + * The caller must pass in a pointer to a ktrace_snap + * structure in which we will keep some state used to + * iterate through the buffer. This state must not touched + * by any code outside of this module. + */ +ktrace_entry_t * +ktrace_first(ktrace_t *ktp, ktrace_snap_t *ktsp) +{ + ktrace_entry_t *ktep; + int index; + int nentries; + + if (ktp->kt_rollover) + index = ktp->kt_index; + else + index = 0; + + ktsp->ks_start = index; + ktep = &(ktp->kt_entries[index]); + + nentries = ktrace_nentries(ktp); + index++; + if (index < nentries) { + ktsp->ks_index = index; + } else { + ktsp->ks_index = 0; + if (index > nentries) + ktep = NULL; + } + return ktep; +} + + +/* + * ktrace_next() + * + * This is used to iterate through the entries of the given + * trace buffer. The caller must pass in the ktrace_snap_t + * structure initialized by ktrace_first(). The return value + * will be either a pointer to the next ktrace_entry or NULL + * if all of the entries have been traversed. + */ +ktrace_entry_t * +ktrace_next( + ktrace_t *ktp, + ktrace_snap_t *ktsp) +{ + int index; + ktrace_entry_t *ktep; + + index = ktsp->ks_index; + if (index == ktsp->ks_start) { + ktep = NULL; + } else { + ktep = &ktp->kt_entries[index]; + } + + index++; + if (index == ktrace_nentries(ktp)) { + ktsp->ks_index = 0; + } else { + ktsp->ks_index = index; + } + + return ktep; +} + +/* + * ktrace_skip() + * + * Skip the next "count" entries and return the entry after that. + * Return NULL if this causes us to iterate past the beginning again. + */ + +ktrace_entry_t * +ktrace_skip( + ktrace_t *ktp, + int count, + ktrace_snap_t *ktsp) +{ + int index; + int new_index; + ktrace_entry_t *ktep; + int nentries = ktrace_nentries(ktp); + + index = ktsp->ks_index; + new_index = index + count; + while (new_index >= nentries) { + new_index -= nentries; + } + if (index == ktsp->ks_start) { + /* + * We've iterated around to the start, so we're done. + */ + ktep = NULL; + } else if ((new_index < index) && (index < ktsp->ks_index)) { + /* + * We've skipped past the start again, so we're done. + */ + ktep = NULL; + ktsp->ks_index = ktsp->ks_start; + } else { + ktep = &(ktp->kt_entries[new_index]); + new_index++; + if (new_index == nentries) { + ktsp->ks_index = 0; + } else { + ktsp->ks_index = new_index; + } + } + return ktep; +} + +EXPORT_SYMBOL(ktrace_init); +EXPORT_SYMBOL(ktrace_uninit); +EXPORT_SYMBOL(ktrace_enter); +EXPORT_SYMBOL(ktrace_free); +EXPORT_SYMBOL(ktrace_nentries); +EXPORT_SYMBOL(ktrace_first); +EXPORT_SYMBOL(ktrace_next); +EXPORT_SYMBOL(ktrace_skip); + +#else /* ! (defined(DEBUG) */ + +ktrace_t * +ktrace_alloc(int nentries, int sleep) +{ + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} +#endif /* ! (defined(DEBUG) */ + +EXPORT_SYMBOL(ktrace_alloc); diff -Nur linux-2.4.19/lib/sgi/move.c linux-2.4.19-sgi211r3/lib/sgi/move.c --- linux-2.4.19/lib/sgi/move.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/move.c Sun May 26 21:57:45 2002 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include /* for EXPORT_SYMBOL */ +#include + +/* + * Move "n" bytes at byte address "cp"; "rw" indicates the direction + * of the move, and the I/O parameters are provided in "uio", which is + * update to reflect the data which was moved. Returns 0 on success or + * a non-zero errno on failure. + */ +int +uiomove(void *cp, size_t n, enum uio_rw rw, struct uio *uio) +{ + register struct iovec *iov; + u_int cnt; + int error; + + while (n > 0 && uio->uio_resid) { + iov = uio->uio_iov; + cnt = (u_int)iov->iov_len; + if (cnt == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + continue; + } + if (cnt > n) + cnt = (u_int)n; + switch (uio->uio_segflg) { + + case UIO_USERSPACE: + if (rw == UIO_READ) + error = copyout(cp, iov->iov_base, cnt); + else + error = copyin(iov->iov_base, cp, cnt); + if (error) + return EFAULT; + break; + + case UIO_USERISPACE: + ASSERT(0); + break; + + case UIO_SYSSPACE: + if (rw == UIO_READ) + bcopy(cp, iov->iov_base, cnt); + else + bcopy(iov->iov_base, cp, cnt); + break; + } + iov->iov_base = (void *)((char *)iov->iov_base + cnt); + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + cp = (void *)((char *)cp + cnt); + n -= cnt; + } + return 0; +} + +EXPORT_SYMBOL(uiomove); diff -Nur linux-2.4.19/lib/sgi/mrlock.c linux-2.4.19-sgi211r3/lib/sgi/mrlock.c --- linux-2.4.19/lib/sgi/mrlock.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/mrlock.c Tue Jul 30 16:25:42 2002 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include + +spinlock_t Atomic_spin = SPIN_LOCK_UNLOCKED; + + +#if USE_RW_WAIT_QUEUE_SPINLOCK +# define wq_write_lock write_lock +#else +# define wq_write_lock spin_lock +#endif + +/* + * We don't seem to need lock_type (only one supported), name, or + * sequence. But, may be passed in so let's leave them here for now. + */ +/* ARGSUSED */ +void +mrlock_init(mrlock_t *mrp, int lock_type, char *name, long sequence) +{ + mrp->mr_count = 0; + mrp->mr_reads_waiting = 0; + mrp->mr_writes_waiting = 0; + init_waitqueue_head(&mrp->mr_readerq); + init_waitqueue_head(&mrp->mr_writerq); + mrp->mr_lock = SPIN_LOCK_UNLOCKED; +} + +/* + * Macros to lock/unlock the mrlock_t. + */ + +#define MRLOCK_INT(m, s) spin_lock_irqsave(&(m)->mr_lock, s); +#define MRUNLOCK_INT(m, s) spin_unlock_irqrestore(&(m)->mr_lock, s); +#define MRLOCK(m) spin_lock_irq(&(m)->mr_lock); +#define MRUNLOCK(m) spin_unlock_irq(&(m)->mr_lock); + + +/* + * lock_wait should never be called in an interrupt thread. + * + * mrlocks can sleep (i.e. call schedule) and so they can't ever + * be called from an interrupt thread. + * + * threads that wake-up should also never be invoked from interrupt threads. + * + * But, waitqueue_lock is locked from interrupt threads - and we are + * called with interrupts disabled, so it is all OK. + */ + +/* ARGSUSED */ +static void +lock_wait(wait_queue_head_t *q, spinlock_t *lock, int rw) +{ + DECLARE_WAITQUEUE( wait, current ); + + set_current_state(TASK_UNINTERRUPTIBLE); + + wq_write_lock(&q->lock); + if (rw) { + __add_wait_queue_tail(q, &wait); + } else { + __add_wait_queue(q, &wait); + } + + wq_write_unlock(&q->lock); + spin_unlock_irq(lock); /* Interrupts reenabled */ + + schedule(); + + set_current_state(TASK_RUNNING); + + wq_write_lock_irq(&q->lock); + __remove_wait_queue(q, &wait); + wq_write_unlock(&q->lock); + + spin_lock(lock); + + /* return with interrupts off and lock held */ +} + +/* ARGSUSED */ +void +mrfree(mrlock_t *mrp) +{ +} + +/* ARGSUSED */ +void +mrlock(mrlock_t *mrp, int type, int flags) +{ + if (type == MR_ACCESS) + mraccess(mrp); + else + mrupdate(mrp); +} + +/* ARGSUSED */ +void +mraccessf(mrlock_t *mrp, int flags) +{ + MRLOCK(mrp); + if(mrp->mr_writes_waiting > 0) { + mrp->mr_reads_waiting++; + lock_wait(&mrp->mr_readerq, &mrp->mr_lock, 0); + mrp->mr_reads_waiting--; + } + while (mrp->mr_count < 0) { + mrp->mr_reads_waiting++; + lock_wait(&mrp->mr_readerq, &mrp->mr_lock, 0); + mrp->mr_reads_waiting--; + } + mrp->mr_count++; + MRUNLOCK(mrp); +} + +/* ARGSUSED */ +void +mrupdatef(mrlock_t *mrp, int flags) +{ + MRLOCK(mrp); + while(mrp->mr_count) { + mrp->mr_writes_waiting++; + lock_wait(&mrp->mr_writerq, &mrp->mr_lock, 1); + mrp->mr_writes_waiting--; + } + + mrp->mr_count = -1; /* writer on it */ + MRUNLOCK(mrp); +} + +int +mrtryaccess(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + /* + * If anyone is waiting for update access or the lock is held for update + * fail the request. + */ + if(mrp->mr_writes_waiting > 0 || mrp->mr_count < 0) { + MRUNLOCK_INT(mrp, s); + return 0; + } + mrp->mr_count++; + MRUNLOCK_INT(mrp, s); + return 1; +} + +int +mrtrypromote(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + + if(mrp->mr_count == 1) { /* We are the only thread with the lock */ + mrp->mr_count = -1; /* writer on it */ + MRUNLOCK_INT(mrp, s); + return 1; + } + + MRUNLOCK_INT(mrp, s); + return 0; +} + +int +mrtryupdate(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + + if(mrp->mr_count) { + MRUNLOCK_INT(mrp, s); + return 0; + } + + mrp->mr_count = -1; /* writer on it */ + MRUNLOCK_INT(mrp, s); + return 1; +} + +static __inline__ void mrwake(mrlock_t *mrp) +{ + /* + * First, if the count is now 0, we need to wake-up anyone waiting. + */ + if (!mrp->mr_count) { + if (mrp->mr_writes_waiting) { /* Wake-up first writer waiting */ + wake_up(&mrp->mr_writerq); + } else if (mrp->mr_reads_waiting) { /* Wakeup any readers waiting */ + wake_up(&mrp->mr_readerq); + } + } +} + +void +mraccunlock(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + mrp->mr_count--; + mrwake(mrp); + MRUNLOCK_INT(mrp, s); +} + +void +mrunlock(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + if (mrp->mr_count < 0) { + mrp->mr_count = 0; + } else { + mrp->mr_count--; + } + mrwake(mrp); + MRUNLOCK_INT(mrp, s); +} + +int +ismrlocked(mrlock_t *mrp, int type) /* No need to lock since info can change */ +{ + if (type == MR_ACCESS) + return (mrp->mr_count > 0); /* Read lock */ + else if (type == MR_UPDATE) + return (mrp->mr_count < 0); /* Write lock */ + else if (type == (MR_UPDATE | MR_ACCESS)) + return (mrp->mr_count); /* Any type of lock held */ + else /* Any waiters */ + return (mrp->mr_reads_waiting | mrp->mr_writes_waiting); +} + +/* + * Demote from update to access. We better be the only thread with the + * lock in update mode so it should be easy to set to 1. + * Wake-up any readers waiting. + */ + +void +mrdemote(mrlock_t *mrp) +{ + MRLOCK(mrp); + mrp->mr_count = 1; + if (mrp->mr_reads_waiting) { /* Wakeup all readers waiting */ + wake_up(&mrp->mr_readerq); + } + MRUNLOCK(mrp); +} + +EXPORT_SYMBOL(mraccessf); +EXPORT_SYMBOL(mrupdatef); +EXPORT_SYMBOL(mrlock); +EXPORT_SYMBOL(mrunlock); +EXPORT_SYMBOL(mraccunlock); +EXPORT_SYMBOL(mrtryupdate); +EXPORT_SYMBOL(mrtryaccess); +EXPORT_SYMBOL(mrtrypromote); +EXPORT_SYMBOL(mrdemote); +EXPORT_SYMBOL(ismrlocked); +EXPORT_SYMBOL(mrlock_init); +EXPORT_SYMBOL(mrfree); +EXPORT_SYMBOL(Atomic_spin); diff -Nur linux-2.4.19/lib/sgi/mutex.c linux-2.4.19-sgi211r3/lib/sgi/mutex.c --- linux-2.4.19/lib/sgi/mutex.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/mutex.c Sun May 26 21:57:45 2002 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include + +/* Mutex locks ------------------------------------------------------ */ + + +void _mutex_init( mutex_t *mutex) +{ + mutex->state = 1; + sema_init( &mutex->sema, 1 ); +} + +void _mutex_destroy( mutex_t *mutex) +{ + mutex->state = 0xdead; + sema_init( &mutex->sema, -99); /* Anyone using it again will block */ +} + +void _mutex_lock( mutex_t *mutex) +{ + mutex->state--; + down( &mutex->sema ); +} + +void _mutex_unlock( mutex_t *mutex) +{ + mutex->state++; + up( &mutex->sema ); +} + +int _mutex_trylock( mutex_t *mutex) +{ + int ret; + + ret = down_trylock( &mutex->sema ); + if (ret == 0) { + mutex->state--; + } + return (ret==0) ? 1 : 0; +} + +EXPORT_SYMBOL(_mutex_init); +EXPORT_SYMBOL(_mutex_lock); +EXPORT_SYMBOL(_mutex_unlock); +EXPORT_SYMBOL(_mutex_trylock); +EXPORT_SYMBOL(_mutex_destroy); diff -Nur linux-2.4.19/lib/sgi/sgi.c linux-2.4.19-sgi211r3/lib/sgi/sgi.c --- linux-2.4.19/lib/sgi/sgi.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/sgi.c Sun May 26 21:57:45 2002 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI "); +MODULE_DESCRIPTION("Support library for SGI"); +MODULE_LICENSE("GPL"); diff -Nur linux-2.4.19/lib/sgi/sv.c linux-2.4.19-sgi211r3/lib/sgi/sv.c --- linux-2.4.19/lib/sgi/sv.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/sv.c Sun May 26 21:57:45 2002 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include + +/* Synchronisation variables ---------------------------------------- */ + +void _sv_init( sv_t *sv) +{ + init_waitqueue_head( &sv->waiters ); + spin_lock_init(&sv->lock); +} + +void _sv_wait( sv_t *sv, spinlock_t *lock, unsigned long s, int intr, struct timespec *timeout) +{ + DECLARE_WAITQUEUE( wait, current ); + + spin_lock(&sv->lock); /* No need to do interrupts since + they better be disabled */ + + /* Don't restore interrupts until we are done with both locks */ + spin_unlock( lock ); + add_wait_queue_exclusive( &sv->waiters, &wait ); +#if 0 + if (intr) { + set_current_state(TASK_INTERRUPTIBLE | TASK_EXCLUSIVE); + } else { + set_current_state(TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + } +#endif + if (intr) { + set_current_state(TASK_INTERRUPTIBLE ); + } else { + set_current_state(TASK_UNINTERRUPTIBLE ); + } + spin_unlock_irqrestore( & sv->lock, (long)s ); + + if (timeout) { + schedule_timeout(timespec_to_jiffies(timeout)); + } else { + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue( &sv->waiters, &wait ); +} + +void +_sv_broadcast(sv_t *sv) +{ + unsigned long flags; + + spin_lock_irqsave(&sv->lock, flags); + + wake_up_all(&sv->waiters ); + spin_unlock_irqrestore(&sv->lock, flags); +} + +/* + * Set runnable, at most, one thread waiting on sync variable. + * Returns # of threads set runnable (0 or 1). + */ +void +_sv_signal(sv_t *svp) +{ + unsigned long flags; + + spin_lock_irqsave(&svp->lock, flags); + wake_up(&svp->waiters); + spin_unlock_irqrestore(&svp->lock, flags); +} + +EXPORT_SYMBOL(_sv_init); +EXPORT_SYMBOL(_sv_wait); +EXPORT_SYMBOL(_sv_broadcast); +EXPORT_SYMBOL(_sv_signal); + diff -Nur linux-2.4.19/lib/sgi/uuid.c linux-2.4.19-sgi211r3/lib/sgi/uuid.c --- linux-2.4.19/lib/sgi/uuid.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/lib/sgi/uuid.c Tue Jul 30 16:25:42 2002 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include /* for EXPORT_SYMBOL */ +#include +#include + +#ifndef CONFIG_NET +#define dev_get_by_name(x) (NULL) +#define dev_put(x) do { } while (0) +#endif + +/* NODE_SIZE is the number of bytes used for the node identifier portion. */ +#define NODE_SIZE 6 + +/* + * Total size must be 128 bits. N.B. definition of uuid_t in uuid.h! + */ +typedef struct { + u_int32_t uu_timelow; /* time "low" */ + u_int16_t uu_timemid; /* time "mid" */ + u_int16_t uu_timehi; /* time "hi" and version */ + u_int16_t uu_clockseq; /* "reserved" and clock sequence */ + u_int16_t uu_node[NODE_SIZE / 2]; /* ethernet hardware address */ +} uu_t; + +/* + * The Time Base Correction is the amount to add on to a UNIX-based + * time value (i.e. seconds since 1 Jan. 1970) to convert it to the + * time base for UUIDs (15 Oct. 1582). + */ +#define UUID_TBC 0x01B21DD2138140LL + +static short uuid_eaddr[NODE_SIZE / 2]; /* ethernet address */ +static __int64_t uuid_time; /* last time basis used */ +static u_int16_t uuid_clockseq; /* boot-time randomizer */ +#define uuid_lock libsgi_uuid_lock +DECLARE_MUTEX(uuid_lock); + +/* + * uuid_init - called from out of init_tbl[] + */ +void +uuid_init(void) +{ +} + +/* + * uuid_getnodeuniq - obtain the node unique fields of a UUID. + * + * This is not in any way a standard or condoned UUID function; + * it just something that's needed for user-level file handles. + */ +void +uuid_getnodeuniq(uuid_t *uuid, int fsid [2]) +{ + char *uu=(char*)uuid; + + /* on IRIX, this function assumes big-endian fields within + * the uuid, so we use INT_GET to get the same result on + * little-endian systems + */ + + fsid[0] = (INT_GET(*(u_int16_t*)(uu+8), ARCH_CONVERT) << 16) + + INT_GET(*(u_int16_t*)(uu+4), ARCH_CONVERT); + fsid[1] = INT_GET(*(u_int32_t*)(uu ), ARCH_CONVERT); +} + +void +uuid_create_nil(uuid_t *uuid) +{ + bzero(uuid, sizeof *uuid); +} + +int +uuid_is_nil(uuid_t *uuid) +{ + int i; + char *cp = (char *)uuid; + + if (uuid == NULL) + return B_TRUE; + /* implied check of version number here... */ + for (i = 0; i < sizeof *uuid; i++) + if (*cp++) return B_FALSE; /* not nil */ + return B_TRUE; /* is nil */ +} + +int +uuid_equal(uuid_t *uuid1, uuid_t *uuid2) +{ + return bcmp(uuid1, uuid2, sizeof(uuid_t)) ? B_FALSE : B_TRUE; +} + +/* + * Given a 128-bit uuid, return a 64-bit value by adding the top and bottom + * 64-bit words. NOTE: This function can not be changed EVER. Although + * brain-dead, some applications depend on this 64-bit value remaining + * persistent. Specifically, DMI vendors store the value as a persistent + * filehandle. + */ +__uint64_t +uuid_hash64(uuid_t *uuid) +{ + __uint64_t *sp = (__uint64_t *)uuid; + + return sp[0] + sp[1]; +} /* uuid_hash64 */ + +static void +get_eaddr(char *junk) +{ + struct net_device *dev; + + dev = dev_get_by_name("eth0"); + if (!dev || !dev->addr_len) { + get_random_bytes(uuid_eaddr, sizeof(uuid_eaddr)); + } else { + memcpy(uuid_eaddr, dev->dev_addr, + dev->addr_lenaddr_len:sizeof(uuid_eaddr)); + dev_put(dev); + } +} + +/* + * uuid_create - kernel version, does the actual work + */ +void +uuid_create(uuid_t *uuid) +{ + int i; + uu_t *uu = (uu_t *)uuid; + static int uuid_have_eaddr = 0; /* ethernet addr inited? */ + static int uuid_is_init = 0; /* time/clockseq inited? */ + + down(&uuid_lock); + if (!uuid_is_init) { + timespec_t ts; + + nanotime(&ts); + /* + * The clock sequence must be initialized randomly. + */ + uuid_clockseq = ((unsigned long)jiffies & 0xfff) | 0x8000; + /* + * Initialize the uuid time, it's in 100 nanosecond + * units since a time base in 1582. + */ + uuid_time = ts.tv_sec * 10000000LL + + ts.tv_nsec / 100LL + + UUID_TBC; + uuid_is_init = 1; + } + if (!uuid_have_eaddr) { + uuid_have_eaddr = 1; + get_eaddr((char *)uuid_eaddr); + } + uuid_time++; + uu->uu_timelow = (u_int32_t)(uuid_time & 0x00000000ffffffffLL); + uu->uu_timemid = (u_int16_t)((uuid_time >> 32) & 0x0000ffff); + uu->uu_timehi = (u_int16_t)((uuid_time >> 48) & 0x00000fff) | 0x1000; + up(&uuid_lock); + uu->uu_clockseq = uuid_clockseq; + for (i = 0; i < (NODE_SIZE / 2); i++) + uu->uu_node [i] = uuid_eaddr [i]; +} + +int +uuid_compare(uuid_t *uuid1, uuid_t *uuid2) +{ + int i; + char *cp1 = (char *) uuid1; + char *cp2 = (char *) uuid2; + + if (uuid1 == NULL) { + if (uuid2 == NULL) { + return 0; /* equal because both are nil */ + } else { + return -1; /* uuid1 nil, so precedes uuid2 */ + } + } else if (uuid2 == NULL) { + return 1; + } + + /* implied check of version number here... */ + for (i = 0; i < sizeof(uuid_t); i++) { + if (*cp1 < *cp2) + return -1; + if (*cp1++ > *cp2++) + return 1; + } + return 0; /* they're equal */ +} + +EXPORT_SYMBOL(uuid_create_nil); +EXPORT_SYMBOL(uuid_is_nil); +EXPORT_SYMBOL(uuid_equal); +EXPORT_SYMBOL(uuid_getnodeuniq); +EXPORT_SYMBOL(uuid_hash64); +EXPORT_SYMBOL(uuid_compare); +EXPORT_SYMBOL(uuid_create); diff -Nur linux-2.4.19/mm/Makefile linux-2.4.19-sgi211r3/mm/Makefile --- linux-2.4.19/mm/Makefile Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/Makefile Wed Oct 16 14:02:58 2002 @@ -9,7 +9,7 @@ O_TARGET := mm.o -export-objs := shmem.o filemap.o memory.o page_alloc.o +export-objs := shmem.o filemap.o memory.o numa.o page_alloc.o obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ diff -Nur linux-2.4.19/mm/bootmem.c linux-2.4.19-sgi211r3/mm/bootmem.c --- linux-2.4.19/mm/bootmem.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/bootmem.c Tue Feb 4 10:57:27 2003 @@ -20,6 +20,9 @@ #include #include +#define in_bdata(b, a, s) (((a) >= (b)->node_boot_start) && \ + ((((a) + (s) + PAGE_SIZE - 1) / PAGE_SIZE) <= (b)->node_low_pfn)) + /* * Access to this subsystem has to be serialized externally. (this is * true for the boot process anyway) @@ -48,13 +51,22 @@ bootmem_data_t *bdata = pgdat->bdata; unsigned long mapsize = ((end - start)+7)/8; - pgdat->node_next = pgdat_list; - pgdat_list = pgdat; + /* find the right bank */ + while (bdata->node_low_pfn && end != bdata->node_low_pfn) + bdata++; + + if (bdata->node_low_pfn == 0) { BUG(); return 0; } + +#ifndef CONFIG_DISCONTIGMEM + /* first bank? add this pgdat to the list of all pgdats */ + if (bdata == pgdat->bdata) { + pgdat->node_next = pgdat_list; + pgdat_list = pgdat; + } +#endif mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL); bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); - bdata->node_boot_start = (start << PAGE_SHIFT); - bdata->node_low_pfn = end; /* * Initially all pages are reserved - setup_arch() has to @@ -143,6 +155,7 @@ static void * __init __alloc_bootmem_core (bootmem_data_t *bdata, unsigned long size, unsigned long align, unsigned long goal) { + static unsigned long last_success; unsigned long i, start = 0; void *ret; unsigned long offset, remaining_size; @@ -168,6 +181,9 @@ if (goal && (goal >= bdata->node_boot_start) && ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) { preferred = goal - bdata->node_boot_start; + + if (last_success >= preferred) + preferred = last_success; } else preferred = 0; @@ -179,6 +195,8 @@ restart_scan: for (i = preferred; i < eidx; i += incr) { unsigned long j; + i = find_next_zero_bit((char *)bdata->node_bootmem_map, eidx, i); + i = (i + incr - 1) & -incr; if (test_bit(i, bdata->node_bootmem_map)) continue; for (j = i + 1; j < i + areasize; ++j) { @@ -197,6 +215,7 @@ } return NULL; found: + last_success = start << PAGE_SHIFT; if (start >= eidx) BUG(); @@ -243,39 +262,45 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) { - struct page *page = pgdat->node_mem_map; bootmem_data_t *bdata = pgdat->bdata; unsigned long i, count, total = 0; - unsigned long idx; + struct page *page; + unsigned long idx, ibase=0; - if (!bdata->node_bootmem_map) BUG(); + while (bdata->node_low_pfn) { + if (!bdata->node_bootmem_map) BUG(); - count = 0; - idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); - for (i = 0; i < idx; i++, page++) { - if (!test_bit(i, bdata->node_bootmem_map)) { + count = 0; + idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); + for (i = find_first_zero_bit(bdata->node_bootmem_map, idx); + i < idx; + i = find_next_zero_bit(bdata->node_bootmem_map, idx, i + 1)) + { + page = pgdat->node_mem_map + i + ibase; count++; ClearPageReserved(page); set_page_count(page, 1); __free_page(page); } - } - total += count; + total += count; + ibase += idx; - /* - * Now free the allocator bitmap itself, it's not - * needed anymore: - */ - page = virt_to_page(bdata->node_bootmem_map); - count = 0; - for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) { - count++; - ClearPageReserved(page); - set_page_count(page, 1); - __free_page(page); + /* + * Now free the allocator bitmap itself, it's not + * needed anymore: + */ + page = virt_to_page(bdata->node_bootmem_map); + count = bootmem_bootmap_pages(bdata->node_low_pfn - + (bdata->node_boot_start >> PAGE_SHIFT)); + for (i = 0; i < count; i++,page++) { + ClearPageReserved(page); + set_page_count(page, 1); + __free_page(page); + } + total += count; + bdata->node_bootmem_map = NULL; + bdata++; } - total += count; - bdata->node_bootmem_map = NULL; return total; } @@ -287,12 +312,34 @@ void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) { - reserve_bootmem_core(pgdat->bdata, physaddr, size); + bootmem_data_t *bdata = pgdat->bdata; + + /* find the right bank */ + while (bdata->node_low_pfn && !in_bdata(bdata, physaddr, size)) + bdata++; + + if (bdata->node_low_pfn == 0) { + BUG(); + return; + } + + reserve_bootmem_core(bdata, physaddr, size); } void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) { - return(free_bootmem_core(pgdat->bdata, physaddr, size)); + bootmem_data_t *bdata = pgdat->bdata; + + /* find the right bank */ + while (bdata->node_low_pfn && !in_bdata(bdata, physaddr, size)) + bdata++; + + if (bdata->node_low_pfn == 0) { + BUG(); + return; + } + + return(free_bootmem_core(bdata, physaddr, size)); } unsigned long __init free_all_bootmem_node (pg_data_t *pgdat) @@ -304,33 +351,86 @@ { max_low_pfn = pages; min_low_pfn = start; + contig_page_data.bdata->node_boot_start = 0; + contig_page_data.bdata->node_low_pfn = pages; return(init_bootmem_core(&contig_page_data, start, 0, pages)); } void __init reserve_bootmem (unsigned long addr, unsigned long size) { - reserve_bootmem_core(contig_page_data.bdata, addr, size); + pg_data_t *pgdat = pgdat_list; + bootmem_data_t *bdata; + + while (pgdat) { + bdata = pgdat->bdata; + while (bdata->node_low_pfn != 0 && !in_bdata(bdata, addr, size)) + bdata++; + if (bdata->node_low_pfn) + return(reserve_bootmem_core(bdata, addr, size)); + pgdat = pgdat->node_next; + } + BUG(); } void __init free_bootmem (unsigned long addr, unsigned long size) { - return(free_bootmem_core(contig_page_data.bdata, addr, size)); + pg_data_t *pgdat = pgdat_list; + bootmem_data_t *bdata; + + while (pgdat) { + bdata = pgdat->bdata; + while (bdata->node_low_pfn != 0 && !in_bdata(bdata, addr, size)) + bdata++; + if (bdata->node_low_pfn) + return(free_bootmem_core(bdata, addr, size)); + pgdat = pgdat->node_next; + } + BUG(); } unsigned long __init free_all_bootmem (void) { - return(free_all_bootmem_core(&contig_page_data)); + pg_data_t *pgdat = pgdat_list; + unsigned long ret = 0; + + while (pgdat) { + ret += free_all_bootmem_core(pgdat); + pgdat = pgdat->node_next; + } + return(ret); } void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) { pg_data_t *pgdat = pgdat_list; + bootmem_data_t *bdata; void *ptr; + if (goal) { + while (pgdat) { + bdata = pgdat->bdata; + while (bdata->node_low_pfn != 0 && !in_bdata(bdata, goal, size)) + bdata++; + if (bdata->node_low_pfn) { + ptr = __alloc_bootmem_core(bdata, size, align, goal); + if (ptr) + return ptr; + break; + } + pgdat = pgdat->node_next; + } + goal = 0; + } + + pgdat = pgdat_list; while (pgdat) { - if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, - align, goal))) - return(ptr); + bdata = pgdat->bdata; + while (bdata->node_low_pfn) { + ptr = __alloc_bootmem_core(bdata, size, align, goal); + if (ptr) + return(ptr); + bdata++; + } pgdat = pgdat->node_next; } /* @@ -344,16 +444,27 @@ void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) { void *ptr; + bootmem_data_t *bdata = pgdat->bdata; - ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal); - if (ptr) - return (ptr); + if (goal) { + while (bdata->node_low_pfn != 0 && !in_bdata(bdata, goal, size)) + bdata++; + if (bdata->node_low_pfn) { + ptr = __alloc_bootmem_core(bdata, size, align, goal); + if (ptr) + return ptr; + } + goal = 0; + } - /* - * Whoops, we cannot satisfy the allocation request. - */ - printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); - panic("Out of memory"); - return NULL; + bdata = pgdat->bdata; + while (bdata->node_low_pfn) { + ptr = __alloc_bootmem_core(bdata, size, align, goal); + if (ptr) + return (ptr); + bdata++; + } + + return __alloc_bootmem(size, align, goal); } diff -Nur linux-2.4.19/mm/filemap.c linux-2.4.19-sgi211r3/mm/filemap.c --- linux-2.4.19/mm/filemap.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/filemap.c Tue Jan 14 22:12:30 2003 @@ -1308,6 +1308,8 @@ SetPageReferenced(page); } +EXPORT_SYMBOL(mark_page_accessed); + /* * This is a generic file read routine, and uses the * inode->i_op->readpage() function for the actual low-level @@ -1534,6 +1536,7 @@ struct kiobuf * iobuf; struct address_space * mapping = filp->f_dentry->d_inode->i_mapping; struct inode * inode = mapping->host; + loff_t size = inode->i_size; new_iobuf = 0; iobuf = filp->f_iobuf; @@ -1559,6 +1562,9 @@ if (!mapping->a_ops->direct_IO) goto out_free; + if ((rw == READ) && (offset + count > size)) + count = size - offset; + /* * Flush to disk exclusively the _data_, metadata must remain * completly asynchronous or performance will go to /dev/null. @@ -1678,8 +1684,6 @@ goto out; /* skip atime */ size = inode->i_size; if (pos < size) { - if (pos + count > size) - count = size - pos; retval = generic_file_direct_IO(READ, filp, buf, count, pos); if (retval > 0) *ppos = pos + retval; @@ -2883,18 +2887,19 @@ return page; } -inline void remove_suid(struct inode *inode) +inline void remove_suid(struct dentry *dentry) { - unsigned int mode; + struct iattr newattrs; + struct inode *inode = dentry->d_inode; + unsigned int mode = inode->i_mode & (S_ISUID|S_ISGID|S_IXGRP); - /* set S_IGID if S_IXGRP is set, and always set S_ISUID */ - mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID; + if (!(mode & S_IXGRP)) + mode &= S_ISUID; /* was any of the uid bits set? */ - mode &= inode->i_mode; if (mode && !capable(CAP_FSETID)) { - inode->i_mode &= ~mode; - mark_inode_dirty(inode); + newattrs.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID; + notify_change(dentry, &newattrs); } } @@ -2913,8 +2918,8 @@ * file system has to do this all by itself, unfortunately. * okir@monad.swb.de */ -ssize_t -generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos) +ssize_t generic_file_write_nolock(struct file * file, const char *buf, + size_t count, loff_t *ppos) { struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct inode *inode = mapping->host; @@ -2934,8 +2939,6 @@ cached_page = NULL; - down(&inode->i_sem); - pos = *ppos; err = -EINVAL; if (pos < 0) @@ -3026,7 +3029,7 @@ if (count == 0) goto out; - remove_suid(inode); + remove_suid(file->f_dentry); inode->i_ctime = inode->i_mtime = CURRENT_TIME; mark_inode_dirty_sync(inode); @@ -3114,7 +3117,6 @@ err = written ? written : status; out: - up(&inode->i_sem); return err; fail_write: status = -EFAULT; @@ -3150,6 +3152,19 @@ if (written >= 0 && file->f_flags & O_SYNC) status = generic_osync_inode(inode, OSYNC_METADATA); goto out_status; +} + +ssize_t generic_file_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode->i_mapping->host; + int err; + + down(&inode->i_sem); + err = generic_file_write_nolock(file, buf, count, ppos); + up(&inode->i_sem); + + return err; } void __init page_cache_init(unsigned long mempages) diff -Nur linux-2.4.19/mm/highmem.c linux-2.4.19-sgi211r3/mm/highmem.c --- linux-2.4.19/mm/highmem.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/highmem.c Mon Oct 28 20:43:23 2002 @@ -355,9 +355,8 @@ /* we need to wait I/O completion */ run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; __set_current_state(TASK_RUNNING); - schedule(); + yield(); goto repeat_alloc; } @@ -393,9 +392,8 @@ /* we need to wait I/O completion */ run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; __set_current_state(TASK_RUNNING); - schedule(); + yield(); goto repeat_alloc; } diff -Nur linux-2.4.19/mm/memory.c linux-2.4.19-sgi211r3/mm/memory.c --- linux-2.4.19/mm/memory.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/memory.c Tue Jan 14 22:12:30 2003 @@ -45,10 +45,12 @@ #include #include #include +#include #include #include #include +#include unsigned long max_mapnr; unsigned long num_physpages; @@ -121,7 +123,7 @@ pmd = pmd_offset(dir, 0); pgd_clear(dir); for (j = 0; j < PTRS_PER_PMD ; j++) { - prefetchw(pmd+j+(PREFETCH_STRIDE/16)); + prefetchw(pmd + j + PREFETCH_STRIDE/sizeof(*pmd)); free_one_pmd(pmd+j); } pmd_free(pmd); @@ -146,7 +148,6 @@ void clear_page_tables(struct mm_struct *mm, unsigned long first, int nr) { pgd_t * page_dir = mm->pgd; - unsigned long last = first + nr; spin_lock(&mm->page_table_lock); page_dir += first; @@ -156,8 +157,6 @@ } while (--nr); spin_unlock(&mm->page_table_lock); - flush_tlb_pgtables(mm, first * PGDIR_SIZE, last * PGDIR_SIZE); - /* keep the page table cache within bounds */ check_pgt_cache(); } @@ -321,7 +320,7 @@ if (VALID_PAGE(page) && !PageReserved(page)) freed ++; /* This will eventually call __free_pte on the pte. */ - tlb_remove_page(tlb, ptep, address + offset); + tlb_remove_page(tlb, page, ptep, address + offset); } else { free_swap_and_cache(pte_to_swp_entry(pte)); pte_clear(ptep); @@ -399,6 +398,8 @@ mm->rss -= freed; else mm->rss = 0; + /* no-op unless CONFIG_CSA_JOB_ACCT is set */ + csa_update_integrals(); spin_unlock(&mm->page_table_lock); } @@ -982,8 +983,12 @@ */ spin_lock(&mm->page_table_lock); if (pte_same(*page_table, pte)) { - if (PageReserved(old_page)) + if (PageReserved(old_page)) { ++mm->rss; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); + } break_cow(vma, new_page, address, page_table); lru_cache_add(new_page); @@ -1168,6 +1173,10 @@ remove_exclusive_swap_page(page); mm->rss++; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); + pte = mk_pte(page, vma->vm_page_prot); if (write_access && can_share_swap_page(page)) pte = pte_mkdirty(pte_mkwrite(pte)); @@ -1214,6 +1223,9 @@ return 1; } mm->rss++; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); flush_page_to_ram(page); entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); lru_cache_add(page); @@ -1289,6 +1301,10 @@ /* Only go through if we didn't race with anybody else... */ if (pte_none(*page_table)) { ++mm->rss; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); + flush_page_to_ram(new_page); flush_icache_page(vma, new_page); entry = mk_pte(new_page, vma->vm_page_prot); @@ -1367,6 +1383,19 @@ { pgd_t *pgd; pmd_t *pmd; + +#ifdef CONFIG_CPUMEMSET + /* + * We set the mems_allowed field of the current task as + * the one pointed by the faulting vma. The current + * process will then allocate memory for this vma's + * address range according to this vma. We are in an interrupt + * if and only if we are allocating memory for user pages. + * The kernel calls alloc_pages() directly, on the stack. + */ + if(in_interrupt()) + current->interrupt_mems_allowed = vma->vm_mems_allowed; +#endif current->state = TASK_RUNNING; pgd = pgd_offset(mm, address); diff -Nur linux-2.4.19/mm/mmap.c linux-2.4.19-sgi211r3/mm/mmap.c --- linux-2.4.19/mm/mmap.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/mmap.c Wed Feb 5 20:48:13 2003 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -205,6 +206,12 @@ _trans(prot, PROT_WRITE, VM_WRITE) | _trans(prot, PROT_EXEC, VM_EXEC); flag_bits = +#ifdef MAP_WRITECOMBINED + _trans(flags, MAP_WRITECOMBINED, VM_WRITECOMBINED) | +#endif +#ifdef MAP_NONCACHED + _trans(flags, MAP_NONCACHED, VM_NONCACHED) | +#endif _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) | _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) | _trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE); @@ -347,6 +354,138 @@ validate_mm(mm); } +/* + * Split vma into 2 similar vma's at address splitaddr. + * Return: + * zero - success + * -ENOMEM - this process already owns > MAX_MAP_COUNT vma's. + * -EAGAIN - a kernel resource was temporarily unavailable. + * + * Must be called with vma->vm_start < splitaddr < vma->vm_end. + */ + +static int vma_split (struct vm_area_struct *vma, unsigned long splitaddr) +{ + struct vm_area_struct * n; /* new vma >= splitaddr */ + struct mm_struct * mm = vma->vm_mm; + + /* This caps the number of vma's this process can own */ + if (vma->vm_mm->map_count > max_map_count) + return -ENOMEM; + + n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!n) + return -EAGAIN; + *n = *vma; + n->vm_start = splitaddr; + n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT; + n->vm_raend = 0; + if (n->vm_file) + get_file(n->vm_file); + if (n->vm_ops && n->vm_ops->open) + n->vm_ops->open(n); + lock_vma_mappings(vma); + spin_lock(&mm->page_table_lock); + vma->vm_end = splitaddr; + vma->vm_raend = 0; + __insert_vm_struct(mm, n); + spin_unlock(&mm->page_table_lock); + unlock_vma_mappings(vma); + return 0; +} + +/* + * If a vma straddles either end of the specified address + * range (start, start+len), split it at the range boundary. + * Return: + * zero - Success + * -EINVAL - Start of range not page alligned or invalid range. + * -ENOMEM - This process already owns > MAX_MAP_COUNT vma's. + * -EAGAIN - A kernel resource was temporarily unavailable. + * + * Caller should be holding vma->mm->mmap_sem so that a parallel + * vma_merge won't undo these split(s) before they are put to use, + * and to otherwise protect these vma list operations. + * + * This single routine should replace the duplicated portions + * of the several fixup_{start,end,middle} routines otherwise + * needed by mlock, mprotect, madvise and CpuMemSet's + * cms_set_cmm(CMS_VMAREA, ..). + * + * The caller of vma_split_range typically does three steps: + * 1) First ensure that every vma in the process address space + * is either entirely within, or entirely outside, the desired + * range, by calling vma_split_range() to split any vma that + * that straddles either boundary of the range. + * 2) Then for each vma in the range, apply the desired mlock, + * mprotect, madvise or cms policy, without the complications + * of vma boundary conditions. + * 3) Then finally, if it has a chance, such as with mprotect, + * see if it can_vma_merge() at either end of the range. + */ + +int vma_split_range (struct mm_struct * mm, unsigned long start, size_t len) +{ + unsigned long end; + struct vm_area_struct * vma; + int error; + + if (start & ~PAGE_MASK) + return -EINVAL; + len = PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + + vma = find_vma(mm, start); + /* Here we know: vma == 0 || start < vma->vm_end */ + if (vma && vma->vm_start < start) { + error = vma_split (vma, start); + if (error < 0) + return error; + } + + vma = find_vma(mm, end); + /* Here we know: vma == 0 || end < vma->vm_end */ + if (vma && vma->vm_start < end) { + error = vma_split (vma, end); + if (error < 0) + return error; + } + + return 0; +} + +/* + * Rejoin any adjacent vmas in specified range that have + * the same flags, same cms, no file, not shared. + */ + +void vma_remerge_range (struct mm_struct * mm, unsigned long start, size_t len) +{ + unsigned long end; + struct vm_area_struct * vma; + + end = start + len; + vma = find_vma(mm, start); + while (vma->vm_end <= end) { + struct vm_area_struct * next; + next = vma->vm_next; + if (next && vma->vm_end == next->vm_start && + can_vma_merge (vma, next, vma->vm_flags) && + !next->vm_file && !(next->vm_flags & VM_SHARED)) { + struct mm_struct * mm = next->vm_mm; + spin_lock(&mm->page_table_lock); + vma->vm_end = next->vm_end; + __vma_unlink(mm, next, vma); + spin_unlock(&mm->page_table_lock); + free_vm_area(next); + mm->map_count--; + } + vma = next; + } +} + static int vma_merge(struct mm_struct * mm, struct vm_area_struct * prev, rb_node_t * rb_parent, unsigned long addr, unsigned long end, unsigned long vm_flags) { @@ -355,19 +494,19 @@ prev = rb_entry(rb_parent, struct vm_area_struct, vm_rb); goto merge_next; } - if (prev->vm_end == addr && can_vma_merge(prev, vm_flags)) { + if (prev->vm_end == addr && can_vma_merge(prev, 0, vm_flags)) { struct vm_area_struct * next; spin_lock(lock); prev->vm_end = end; next = prev->vm_next; - if (next && prev->vm_end == next->vm_start && can_vma_merge(next, vm_flags)) { + if (next && prev->vm_end == next->vm_start && can_vma_merge(next, prev, vm_flags)) { prev->vm_end = next->vm_end; __vma_unlink(mm, next, prev); spin_unlock(lock); mm->map_count--; - kmem_cache_free(vm_area_cachep, next); + free_vm_area(next); return 1; } spin_unlock(lock); @@ -377,7 +516,7 @@ prev = prev->vm_next; if (prev) { merge_next: - if (!can_vma_merge(prev, vm_flags)) + if (!can_vma_merge(prev, 0, vm_flags)) return 0; if (end == prev->vm_start) { spin_lock(lock); @@ -520,6 +659,9 @@ vma->vm_pgoff = pgoff; vma->vm_file = NULL; vma->vm_private_data = NULL; +#ifdef CONFIG_CPUMEMSET + vma->vm_mems_allowed = cms_current_mems_allowed(); +#endif vma->vm_raend = 0; if (file) { @@ -583,6 +725,9 @@ mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); } + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); return addr; unmap_and_free_vma: @@ -594,7 +739,7 @@ /* Undo any partial mapping done by a device driver. */ zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start); free_vma: - kmem_cache_free(vm_area_cachep, vma); + free_vm_area(vma); return error; } @@ -799,7 +944,7 @@ area->vm_ops->close(area); if (area->vm_file) fput(area->vm_file); - kmem_cache_free(vm_area_cachep, area); + free_vm_area(area); return extra; } @@ -834,6 +979,9 @@ mpnt->vm_pgoff = area->vm_pgoff + ((end - area->vm_start) >> PAGE_SHIFT); mpnt->vm_file = area->vm_file; mpnt->vm_private_data = area->vm_private_data; +#ifdef CONFIG_CPUMEMSET + mpnt->vm_mems_allowed = cms_current_mems_allowed(); +#endif if (mpnt->vm_file) get_file(mpnt->vm_file); if (mpnt->vm_ops && mpnt->vm_ops->open) @@ -900,6 +1048,8 @@ break; } no_mmaps: + if (last < first) + return; /* * If the PGD bits are not consecutive in the virtual address, the * old method of shifting the VA >> by PGDIR_SHIFT doesn't work. @@ -908,6 +1058,7 @@ end_index = pgd_index(last); if (end_index > start_index) { clear_page_tables(mm, start_index, end_index - start_index); + flush_tlb_pgtables(mm, first & PGDIR_MASK, last & PGDIR_MASK); } } @@ -1002,7 +1153,7 @@ /* Release the extra vma struct if it wasn't used */ if (extra) - kmem_cache_free(vm_area_cachep, extra); + free_vm_area(extra); free_pgtables(mm, prev, addr, addr+len); @@ -1090,6 +1241,9 @@ vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; +#ifdef CONFIG_CPUMEMSET + vma->vm_mems_allowed = cms_current_mems_allowed(); +#endif vma_link(mm, vma, prev, rb_link, rb_parent); @@ -1099,6 +1253,9 @@ mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); } + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); return addr; } @@ -1149,7 +1306,7 @@ zap_page_range(mm, start, size); if (mpnt->vm_file) fput(mpnt->vm_file); - kmem_cache_free(vm_area_cachep, mpnt); + free_vm_area(mpnt); mpnt = next; } flush_tlb_mm(mm); diff -Nur linux-2.4.19/mm/mprotect.c linux-2.4.19-sgi211r3/mm/mprotect.c --- linux-2.4.19/mm/mprotect.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/mprotect.c Tue Jan 14 22:12:30 2003 @@ -97,14 +97,14 @@ struct vm_area_struct * prev = *pprev; struct mm_struct * mm = vma->vm_mm; - if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, newflags) && + if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, vma, newflags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { spin_lock(&mm->page_table_lock); prev->vm_end = vma->vm_end; __vma_unlink(mm, vma, prev); spin_unlock(&mm->page_table_lock); - kmem_cache_free(vm_area_cachep, vma); + free_vm_area(vma); mm->map_count--; return 0; @@ -128,7 +128,7 @@ *pprev = vma; - if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, newflags) && + if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, vma, newflags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { spin_lock(&vma->vm_mm->page_table_lock); prev->vm_end = end; @@ -202,7 +202,7 @@ return -ENOMEM; right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!right) { - kmem_cache_free(vm_area_cachep, left); + free_vm_area(left); return -ENOMEM; } *left = *vma; @@ -300,6 +300,11 @@ goto out; } + if (vma->vm_ops && vma->vm_ops->mprotect) { + error = vma->vm_ops->mprotect(vma, newflags); + if (error < 0) + goto out; + } if (vma->vm_end > end) { error = mprotect_fixup(vma, &prev, nstart, end, newflags); goto out; @@ -321,14 +326,14 @@ goto out; } } - if (next && prev->vm_end == next->vm_start && can_vma_merge(next, prev->vm_flags) && + if (next && prev->vm_end == next->vm_start && can_vma_merge(next, prev, prev->vm_flags) && !prev->vm_file && !(prev->vm_flags & VM_SHARED)) { spin_lock(&prev->vm_mm->page_table_lock); prev->vm_end = next->vm_end; __vma_unlink(prev->vm_mm, next, prev); spin_unlock(&prev->vm_mm->page_table_lock); - kmem_cache_free(vm_area_cachep, next); + free_vm_area(next); prev->vm_mm->map_count--; } out: diff -Nur linux-2.4.19/mm/mremap.c linux-2.4.19-sgi211r3/mm/mremap.c --- linux-2.4.19/mm/mremap.c Thu Sep 20 20:31:26 2001 +++ linux-2.4.19-sgi211r3/mm/mremap.c Tue Jan 14 22:12:30 2003 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -134,24 +135,24 @@ next = find_vma_prev(mm, new_addr, &prev); if (next) { if (prev && prev->vm_end == new_addr && - can_vma_merge(prev, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { + can_vma_merge(prev, vma, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { spin_lock(&mm->page_table_lock); prev->vm_end = new_addr + new_len; spin_unlock(&mm->page_table_lock); new_vma = prev; if (next != prev->vm_next) BUG(); - if (prev->vm_end == next->vm_start && can_vma_merge(next, prev->vm_flags)) { + if (prev->vm_end == next->vm_start && can_vma_merge(next, prev, prev->vm_flags)) { spin_lock(&mm->page_table_lock); prev->vm_end = next->vm_end; __vma_unlink(mm, next, prev); spin_unlock(&mm->page_table_lock); mm->map_count--; - kmem_cache_free(vm_area_cachep, next); + free_vm_area(next); } } else if (next->vm_start == new_addr + new_len && - can_vma_merge(next, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { + can_vma_merge(next, vma, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { spin_lock(&mm->page_table_lock); next->vm_start = new_addr; spin_unlock(&mm->page_table_lock); @@ -160,7 +161,7 @@ } else { prev = find_vma(mm, new_addr-1); if (prev && prev->vm_end == new_addr && - can_vma_merge(prev, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { + can_vma_merge(prev, vma, vma->vm_flags) && !vma->vm_file && !(vma->vm_flags & VM_SHARED)) { spin_lock(&mm->page_table_lock); prev->vm_end = new_addr + new_len; spin_unlock(&mm->page_table_lock); @@ -196,10 +197,14 @@ make_pages_present(new_vma->vm_start, new_vma->vm_end); } + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); + return new_addr; } if (allocated_vma) - kmem_cache_free(vm_area_cachep, new_vma); + free_vm_area(new_vma); out: return -ENOMEM; } @@ -312,6 +317,9 @@ make_pages_present(addr + old_len, addr + new_len); } + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); ret = addr; goto out; } diff -Nur linux-2.4.19/mm/numa.c linux-2.4.19-sgi211r3/mm/numa.c --- linux-2.4.19/mm/numa.c Mon Sep 17 16:15:02 2001 +++ linux-2.4.19-sgi211r3/mm/numa.c Thu Oct 31 10:53:27 2002 @@ -2,6 +2,7 @@ * Written by Kanoj Sarcar, SGI, Aug 1999 */ #include +#include #include #include #include @@ -13,6 +14,7 @@ static bootmem_data_t contig_bootmem_data; pg_data_t contig_page_data = { bdata: &contig_bootmem_data }; +EXPORT_SYMBOL(contig_page_data); #ifndef CONFIG_DISCONTIGMEM @@ -40,6 +42,17 @@ #endif } +#ifdef CONFIG_NUMA + +/* + * This call is for allocating memory before the cpu_data structure is setup. + */ +struct page * __init boot_alloc_pages_node(int nid, int gfp_mask, unsigned long order) +{ + return __alloc_pages(gfp_mask, order, BOOT_NODE_DATA(nid)->node_zonelists + (gfp_mask & GFP_ZONEMASK)); +} +#endif + #ifdef CONFIG_DISCONTIGMEM #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) @@ -82,49 +95,32 @@ memset(pgdat->valid_addr_bitmap, 0, size); } -static struct page * alloc_pages_pgdat(pg_data_t *pgdat, unsigned int gfp_mask, - unsigned int order) -{ - return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK)); -} -/* - * This can be refined. Currently, tries to do round robin, instead - * should do concentratic circle search, starting from current node. - */ -struct page * _alloc_pages(unsigned int gfp_mask, unsigned int order) +int get_discontig_info(char * page) { - struct page *ret = 0; - pg_data_t *start, *temp; -#ifndef CONFIG_NUMA - unsigned long flags; - static pg_data_t *next = 0; -#endif + char *start = page; + int nid; + unsigned long free = 0; + pg_data_t *pgdat; + zone_t *zone; + + page += sprintf(page, "%4s %7s %7s\n", "node", "total", "free"); - if (order >= MAX_ORDER) - return NULL; -#ifdef CONFIG_NUMA - temp = NODE_DATA(numa_node_id()); -#else - spin_lock_irqsave(&node_lock, flags); - if (!next) next = pgdat_list; - temp = next; - next = next->node_next; - spin_unlock_irqrestore(&node_lock, flags); -#endif - start = temp; - while (temp) { - if ((ret = alloc_pages_pgdat(temp, gfp_mask, order))) - return(ret); - temp = temp->node_next; - } - temp = pgdat_list; - while (temp != start) { - if ((ret = alloc_pages_pgdat(temp, gfp_mask, order))) - return(ret); - temp = temp->node_next; + /* + * Get some basic memory info for each node. + */ + for(nid = 0; nid < numnodes; nid++) { + pgdat = NODE_DATA(nid); + + for (free=0, zone = pgdat->node_zones; zone < pgdat->node_zones + MAX_NR_ZONES; zone++) + free += zone->free_pages; + + page += sprintf(page, "%4d ", pgdat->node_id); + page += sprintf(page, "%7ld ", pgdat->node_size); + page += sprintf(page, "%7ld\n", free); } - return(0); + + return page - start; } #endif /* CONFIG_DISCONTIGMEM */ diff -Nur linux-2.4.19/mm/oom_kill.c linux-2.4.19-sgi211r3/mm/oom_kill.c --- linux-2.4.19/mm/oom_kill.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/oom_kill.c Mon Oct 28 20:43:23 2002 @@ -82,7 +82,7 @@ * Niced processes are most likely less important, so double * their badness points. */ - if (p->nice > 0) + if (task_nice(p) > 0) points *= 2; /* @@ -146,7 +146,7 @@ * all the memory it needs. That way it should be able to * exit() and clear out its resources quickly... */ - p->counter = 5 * HZ; + p->time_slice = HZ; p->flags |= PF_MEMALLOC | PF_MEMDIE; /* This process has hardware access, be more careful. */ @@ -188,8 +188,7 @@ * killing itself before someone else gets the chance to ask * for more memory. */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); return; } diff -Nur linux-2.4.19/mm/page_alloc.c linux-2.4.19-sgi211r3/mm/page_alloc.c --- linux-2.4.19/mm/page_alloc.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/page_alloc.c Thu Feb 13 15:07:55 2003 @@ -21,6 +21,7 @@ #include #include #include +#include int nr_swap_pages; int nr_active_pages; @@ -41,11 +42,11 @@ /* * Temporary debugging check. */ -#define BAD_RANGE(zone, page) \ -( \ - (((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->size)) \ - || (((page) - mem_map) < (zone)->zone_start_mapnr) \ - || ((zone) != page_zone(page)) \ +#define BAD_RANGE(zone, page) \ +( \ + (((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->totalsize)) \ + || (((page) - mem_map) < (zone)->zone_start_mapnr) \ + || ((zone) != page_zone(page)) \ ) /* @@ -79,6 +80,8 @@ struct page *base; zone_t *zone; + ClearPageInuseOrder(page, order); /* controlled by CONFIG_DUMP for lkcd */ + /* Yes, think what happens when other parts of the kernel take * a reference to a page in order to pin it for io. -ben */ @@ -213,6 +216,8 @@ page = expand(zone, page, index, order, curr_order, area); spin_unlock_irqrestore(&zone->lock, flags); + SetPageInuseOrder(page, order); /* controlled by CONFIG_DUMP for lkcd */ + set_page_count(page, 1); if (BAD_RANGE(zone,page)) BUG(); @@ -274,6 +279,8 @@ set_page_count(tmp, 1); page = tmp; + SetPageInuseOrder(page, order); /* controlled by CONFIG_DUMP for lkcd */ + if (page->buffers) BUG(); if (page->mapping) @@ -315,11 +322,21 @@ */ struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist) { - unsigned long min; + unsigned long min, mems_allowed; zone_t **zone, * classzone; struct page * page; int freed; +#ifdef CONFIG_CPUMEMSET + if (in_interrupt()) + mems_allowed = current->interrupt_mems_allowed; + else + mems_allowed = kernel_cms->mems_allowed; + if (mems_allowed == 0) { + printk(KERN_DEBUG "workaround zero mems_allowed in alloc_pages\n"); + mems_allowed = -1UL; + } +#endif zone = zonelist->zones; classzone = *zone; if (classzone == NULL) @@ -330,6 +347,8 @@ if (!z) break; + if(!CHECK_MEMS_ALLOWED(mems_allowed, z)) + continue; min += z->pages_low; if (z->free_pages > min) { page = rmqueue(z, order); @@ -351,6 +370,8 @@ if (!z) break; + if(!CHECK_MEMS_ALLOWED(mems_allowed, z)) + continue; local_min = z->pages_min; if (!(gfp_mask & __GFP_WAIT)) local_min >>= 2; @@ -372,6 +393,8 @@ if (!z) break; + if(!CHECK_MEMS_ALLOWED(mems_allowed, z)) + continue; page = rmqueue(z, order); if (page) return page; @@ -394,6 +417,9 @@ if (!z) break; + /* Don't CHECK_MEMS_ALLOWED() here, until swapper smart + * enough not to thrash all the wrong nodes for memory. */ + min += z->pages_min; if (z->free_pages > min) { page = rmqueue(z, order); @@ -407,9 +433,8 @@ return NULL; /* Yield for kswapd, and try again */ - current->policy |= SCHED_YIELD; __set_current_state(TASK_RUNNING); - schedule(); + yield(); goto rebalance; } @@ -456,16 +481,25 @@ */ unsigned int nr_free_pages (void) { + static unsigned long jiffies_last_compute = 0; + static unsigned int free_pages_last_compute = 0; unsigned int sum; zone_t *zone; pg_data_t *pgdat = pgdat_list; sum = 0; + if (jiffies == jiffies_last_compute) + return free_pages_last_compute; + else { + /* The comment in nr_free_buffer_pages() applies here, too. */ + jiffies_last_compute = jiffies; + } while (pgdat) { for (zone = pgdat->node_zones; zone < pgdat->node_zones + MAX_NR_ZONES; zone++) sum += zone->free_pages; pgdat = pgdat->node_next; } + free_pages_last_compute = sum; return sum; } @@ -474,16 +508,34 @@ */ unsigned int nr_free_buffer_pages (void) { + static unsigned long jiffies_last_compute = 0; + static unsigned int free_buffer_pages_last_compute = 0; pg_data_t *pgdat = pgdat_list; unsigned int sum = 0; + if (jiffies == jiffies_last_compute) + return free_buffer_pages_last_compute; + else { + /* + * Reset the jiffies_last_compute now, not after the recalc. + * Another call (from another CPU) coming in after this jiffies + * reset and before we recalc will continue to get the last + * value, which is only slightly stale, until we recalc a new + * value. A call coming in before this jiffies reset will + * trigger a concurrent recalc, but the timing window is + * narrower than if we do the jiffies reset after the recalc, + * and we don't want to use a spinlock to close the window. + */ + jiffies_last_compute = jiffies; + } + do { zonelist_t *zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK); zone_t **zonep = zonelist->zones; zone_t *zone; for (zone = *zonep++; zone; zone = *zonep++) { - unsigned long size = zone->size; + unsigned long size = zone->memsize; unsigned long high = zone->pages_high; if (size > high) sum += size - high; @@ -492,6 +544,7 @@ pgdat = pgdat->node_next; } while (pgdat); + free_buffer_pages_last_compute = sum; return sum; } @@ -509,6 +562,39 @@ } #endif +/* + * If it returns non zero it means there's lots of ram "free" + * (note: not in cache!) so any caller will know that + * he can allocate some memory to do some more aggressive + * (possibly wasteful) readahead. The state of the memory + * should be rechecked after every few pages allocated for + * doing this aggressive readahead. + * + * NOTE: caller passes in gfp_mask of zones to check + */ +#define for_each_pgdat(pgdat) \ + for (pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next) + +int start_aggressive_readahead(int gfp_mask) +{ + pg_data_t *pgdat; + zonelist_t *zonelist; + zone_t **zonep, *zone; + int ret = 0; + + for_each_pgdat(pgdat) { + zonelist = pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK); + zonep = zonelist->zones; + + for (zone = *zonep++; zone; zone = *zonep++) { + if (zone->free_pages > zone->pages_high * 2) + ret = 1; + } + } + + return ret; +} + #define K(x) ((x) << (PAGE_SHIFT-10)) /* @@ -552,7 +638,7 @@ unsigned long nr, total, flags; total = 0; - if (zone->size) { + if (zone->memsize) { spin_lock_irqsave(&zone->lock, flags); for (order = 0; order < MAX_ORDER; order++) { head = &(zone->free_area + order)->free_list; @@ -610,7 +696,7 @@ */ case ZONE_HIGHMEM: zone = pgdat->node_zones + ZONE_HIGHMEM; - if (zone->size) { + if (zone->memsize) { #ifndef CONFIG_HIGHMEM BUG(); #endif @@ -618,11 +704,11 @@ } case ZONE_NORMAL: zone = pgdat->node_zones + ZONE_NORMAL; - if (zone->size) + if (zone->memsize) zonelist->zones[j++] = zone; case ZONE_DMA: zone = pgdat->node_zones + ZONE_DMA; - if (zone->size) + if (zone->memsize) zonelist->zones[j++] = zone; } zonelist->zones[j++] = NULL; @@ -671,6 +757,31 @@ return ffz(~size); } +static unsigned long memmap_init(struct page *start, struct page *end, + int zone, unsigned long start_paddr, int highmem) +{ + struct page *page; + + for (page = start; page < end; page++) { + set_page_zone(page, zone); + set_page_count(page, 0); + SetPageReserved(page); + INIT_LIST_HEAD(&page->list); + if (!highmem) + set_page_address(page, __va(start_paddr)); + start_paddr += PAGE_SIZE; + } + return start_paddr; +} + +#ifdef HAVE_ARCH_MEMMAP_INIT +#define MEMMAP_INIT(start, end, zone, paddr, highmem) \ + arch_memmap_init(memmap_init, start, end, zone, paddr, highmem) +#else +#define MEMMAP_INIT(start, end, zone, paddr, highmem) \ + memmap_init(start, end, zone, paddr, highmem) +#endif + #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) /* @@ -692,19 +803,19 @@ BUG(); totalpages = 0; - for (i = 0; i < MAX_NR_ZONES; i++) { - unsigned long size = zones_size[i]; - totalpages += size; - } + for (i = 0; i < MAX_NR_ZONES; i++) + totalpages += zones_size[i]; realtotalpages = totalpages; if (zholes_size) for (i = 0; i < MAX_NR_ZONES; i++) realtotalpages -= zholes_size[i]; +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) printk("On node %d totalpages: %lu\n", nid, realtotalpages); +#endif /* - * Some architectures (with lots of mem and discontinous memory + * Some architectures (with lots of mem and discontigous memory * maps) have to search for a good mem_map area: * For discontigmem, the conceptual mem map array starts from * PAGE_OFFSET, we need to align the actual array onto a mem map @@ -733,8 +844,11 @@ if (zholes_size) realsize -= zholes_size[j]; - printk("zone(%lu): %lu pages.\n", j, size); - zone->size = size; +#if !defined(CONFIG_IA64_SGI_SN) || defined(CONFIG_IA64_SGI_SN_DEBUG) + printk("zone(%lu): %lu pages.\n", j, realsize); +#endif + zone->totalsize = size; + zone->memsize = realsize; zone->name = zone_names[j]; zone->lock = SPIN_LOCK_UNLOCKED; zone->zone_pgdat = pgdat; @@ -780,16 +894,10 @@ * up by free_all_bootmem() once the early boot process is * done. Non-atomic initialization, single-pass. */ - for (i = 0; i < size; i++) { - struct page *page = mem_map + offset + i; - set_page_zone(page, nid * MAX_NR_ZONES + j); - set_page_count(page, 0); - SetPageReserved(page); - INIT_LIST_HEAD(&page->list); - if (j != ZONE_HIGHMEM) - set_page_address(page, __va(zone_start_paddr)); - zone_start_paddr += PAGE_SIZE; - } + zone_start_paddr = MEMMAP_INIT(mem_map + offset, + mem_map + offset + size, + nid * MAX_NR_ZONES + j, zone_start_paddr, + (j == ZONE_HIGHMEM ? 1 : 0)); offset += size; for (i = 0; ; i++) { diff -Nur linux-2.4.19/mm/page_io.c linux-2.4.19-sgi211r3/mm/page_io.c --- linux-2.4.19/mm/page_io.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/page_io.c Wed Oct 16 14:02:58 2002 @@ -50,9 +50,17 @@ get_swaphandle_info(entry, &offset, &dev, &swapf); if (dev) { - zones[0] = offset; - zones_used = 1; - block_size = PAGE_SIZE; + if (PAGE_SIZE > MAX_SWAPDEV_BLKSIZE) { + int i; + for (i=0; if_dentry); inode->i_ctime = inode->i_mtime = CURRENT_TIME; } diff -Nur linux-2.4.19/mm/slab.c linux-2.4.19-sgi211r3/mm/slab.c --- linux-2.4.19/mm/slab.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/slab.c Wed Oct 16 14:02:58 2002 @@ -1588,6 +1588,29 @@ } /** + * kmem_cache_zalloc - allocate an object and zero it + * @cachep: The cache the allocation was from. + * @flags: the type of memory to allocate. + * + * Just like kmem_cache_alloc, only it zeros the new object. + */ +void * +kmem_cache_zalloc(kmem_cache_t *cachep, int flags) +{ + void *ptr; + ptr = __kmem_cache_alloc(cachep, flags); + if (ptr) +#if DEBUG + memset(ptr, 0, cachep->objsize - + (cachep->flags & SLAB_RED_ZONE ? 2*BYTES_PER_WORD : 0)); +#else + memset(ptr, 0, cachep->objsize); +#endif + + return ptr; +} + +/** * kfree - free previously allocated memory * @objp: pointer returned by kmalloc. * @@ -1606,6 +1629,15 @@ c = GET_PAGE_CACHE(virt_to_page(objp)); __kmem_cache_free(c, (void*)objp); local_irq_restore(flags); +} + +unsigned int kmem_cache_size(kmem_cache_t *cachep) +{ +#if DEBUG + if (cachep->flags & SLAB_RED_ZONE) + return (cachep->objsize - 2*BYTES_PER_WORD); +#endif + return cachep->objsize; } kmem_cache_t * kmem_find_general_cachep (size_t size, int gfpflags) diff -Nur linux-2.4.19/mm/swapfile.c linux-2.4.19-sgi211r3/mm/swapfile.c --- linux-2.4.19/mm/swapfile.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/swapfile.c Thu Feb 13 07:12:33 2003 @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -33,6 +34,25 @@ #define SWAPFILE_CLUSTER 256 + +/* + * Throttle out of swap messages. + * Pace it with jiffies. + * This isn't really MP-safe, but it doesn't really have to be either... + */ +static inline int within_logging_rate_limit (void) +{ + static unsigned long count, last_time; + + if (jiffies - last_time > 5*HZ) + count = 0; + if (++count < 5) { + last_time = jiffies; + return 1; + } + return 0; +} + static inline int scan_swap_map(struct swap_info_struct *si) { unsigned long offset; @@ -141,6 +161,9 @@ } out: swap_list_unlock(); + if (entry.val == 0 && within_logging_rate_limit()) + printk(KERN_CRIT "get_swap_page: out of swap space\n"); + return entry; } @@ -375,6 +398,9 @@ set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot))); swap_free(entry); ++vma->vm_mm->rss; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); + update_mem_hiwater(); } /* mmlist_lock and vma->vm_mm->page_table_lock are held */ @@ -911,12 +937,14 @@ error = -EINVAL; if (S_ISBLK(swap_inode->i_mode)) { + int block_size; kdev_t dev = swap_inode->i_rdev; struct block_device_operations *bdops; devfs_handle_t de; p->swap_device = dev; - set_blocksize(dev, PAGE_SIZE); + block_size = (PAGE_SIZE < MAX_SWAPDEV_BLKSIZE) ? PAGE_SIZE : MAX_SWAPDEV_BLKSIZE; + set_blocksize(dev, block_size); bd_acquire(swap_inode); bdev = swap_inode->i_bdev; @@ -928,7 +956,7 @@ devfs_put_ops(de);/*Decrement module use count now we're safe*/ if (error) goto bad_swap_2; - set_blocksize(dev, PAGE_SIZE); + set_blocksize(dev, block_size); error = -ENODEV; if (!dev || (blk_size[MAJOR(dev)] && !blk_size[MAJOR(dev)][MINOR(dev)])) diff -Nur linux-2.4.19/mm/vmalloc.c linux-2.4.19-sgi211r3/mm/vmalloc.c --- linux-2.4.19/mm/vmalloc.c Mon Feb 25 11:38:14 2002 +++ linux-2.4.19-sgi211r3/mm/vmalloc.c Wed Oct 16 14:02:58 2002 @@ -93,7 +93,8 @@ } static inline int alloc_area_pte (pte_t * pte, unsigned long address, - unsigned long size, int gfp_mask, pgprot_t prot) + unsigned long size, int gfp_mask, + pgprot_t prot, struct page ***pages) { unsigned long end; @@ -103,9 +104,20 @@ end = PMD_SIZE; do { struct page * page; - spin_unlock(&init_mm.page_table_lock); - page = alloc_page(gfp_mask); - spin_lock(&init_mm.page_table_lock); + + if (!pages) { + spin_unlock(&init_mm.page_table_lock); + page = alloc_page(gfp_mask); + spin_lock(&init_mm.page_table_lock); + } else { + page = (**pages); + (*pages)++; + + /* Add a reference to the page so we can free later */ + if (page) + atomic_inc(&page->count); + + } if (!pte_none(*pte)) printk(KERN_ERR "alloc_area_pte: page already exists\n"); if (!page) @@ -117,7 +129,9 @@ return 0; } -static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot) +static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, + unsigned long size, int gfp_mask, + pgprot_t prot, struct page ***pages) { unsigned long end; @@ -129,7 +143,8 @@ pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; - if (alloc_area_pte(pte, address, end - address, gfp_mask, prot)) + if (alloc_area_pte(pte, address, end - address, + gfp_mask, prot, pages)) return -ENOMEM; address = (address + PMD_SIZE) & PMD_MASK; pmd++; @@ -137,8 +152,11 @@ return 0; } -inline int vmalloc_area_pages (unsigned long address, unsigned long size, - int gfp_mask, pgprot_t prot) +static inline int __vmalloc_area_pages (unsigned long address, + unsigned long size, + int gfp_mask, + pgprot_t prot, + struct page ***pages) { pgd_t * dir; unsigned long end = address + size; @@ -155,7 +173,7 @@ break; ret = -ENOMEM; - if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot)) + if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages)) break; address = (address + PGDIR_SIZE) & PGDIR_MASK; @@ -168,6 +186,12 @@ return ret; } +int vmalloc_area_pages(unsigned long address, unsigned long size, + int gfp_mask, pgprot_t prot) +{ + return __vmalloc_area_pages(address, size, gfp_mask, prot, NULL); +} + struct vm_struct * get_vm_area(unsigned long size, unsigned long flags) { unsigned long addr; @@ -240,7 +264,29 @@ if (!area) return NULL; addr = area->addr; - if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot)) { + if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, + prot, NULL)) { + vfree(addr); + return NULL; + } + return addr; +} + +void * vmap(struct page **pages, int count) +{ + void * addr; + struct vm_struct *area; + unsigned long size = count << PAGE_SHIFT; + + if (!size || size > (max_mapnr << PAGE_SHIFT)) + return NULL; + area = get_vm_area(size, VM_ALLOC); + if (!area) { + return NULL; + } + addr = area->addr; + if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, 0, + PAGE_KERNEL, &pages)) { vfree(addr); return NULL; } diff -Nur linux-2.4.19/mm/vmscan.c linux-2.4.19-sgi211r3/mm/vmscan.c --- linux-2.4.19/mm/vmscan.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/mm/vmscan.c Wed Oct 16 14:02:58 2002 @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -87,6 +88,8 @@ set_pte(page_table, swp_entry_to_pte(entry)); drop_pte: mm->rss--; + /* no-op if CONFIG_CSA_JOB_ACCT not set */ + csa_update_integrals(); UnlockPage(page); { int freeable = page_count(page) - !!page->buffers <= 2; diff -Nur linux-2.4.19/net/ipv4/ip_output.c linux-2.4.19-sgi211r3/net/ipv4/ip_output.c --- linux-2.4.19/net/ipv4/ip_output.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/net/ipv4/ip_output.c Wed Jan 1 17:26:29 2003 @@ -520,8 +520,18 @@ /* * Get the memory we require with some space left for alignment. */ - - skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, flags&MSG_DONTWAIT, &err); + if (!(flags & MSG_DONTWAIT) || nfrags == 0) { + skb = sock_alloc_send_skb(sk, fraglen + hh_len + 15, + (flags & MSG_DONTWAIT), &err); + } else { + /* On a non-blocking write, we check for send buffer + * usage on the first fragment only. + */ + skb = sock_wmalloc(sk, fraglen + hh_len + 15, 1, + sk->allocation); + if (!skb) + err = -ENOBUFS; + } if (skb == NULL) goto error; diff -Nur linux-2.4.19/net/ipv4/tcp_output.c linux-2.4.19-sgi211r3/net/ipv4/tcp_output.c --- linux-2.4.19/net/ipv4/tcp_output.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/net/ipv4/tcp_output.c Mon Oct 28 20:43:23 2002 @@ -1010,8 +1010,7 @@ skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL); if (skb) break; - current->policy |= SCHED_YIELD; - schedule(); + yield(); } /* Reserve space for headers and prepare control bits. */ diff -Nur linux-2.4.19/net/sched/sch_generic.c linux-2.4.19-sgi211r3/net/sched/sch_generic.c --- linux-2.4.19/net/sched/sch_generic.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/net/sched/sch_generic.c Mon Oct 28 20:43:23 2002 @@ -475,10 +475,8 @@ dev_watchdog_down(dev); - while (test_bit(__LINK_STATE_SCHED, &dev->state)) { - current->policy |= SCHED_YIELD; - schedule(); - } + while (test_bit(__LINK_STATE_SCHED, &dev->state)) + yield(); spin_unlock_wait(&dev->xmit_lock); } diff -Nur linux-2.4.19/net/socket.c linux-2.4.19-sgi211r3/net/socket.c --- linux-2.4.19/net/socket.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/net/socket.c Mon Oct 28 20:43:23 2002 @@ -147,8 +147,7 @@ while (atomic_read(&net_family_lockct) != 0) { spin_unlock(&net_family_lock); - current->policy |= SCHED_YIELD; - schedule(); + yield(); spin_lock(&net_family_lock); } @@ -437,11 +436,11 @@ struct inode * inode; struct socket * sock; - inode = get_empty_inode(); + inode = new_inode(sock_mnt->mnt_sb); if (!inode) return NULL; - inode->i_sb = sock_mnt->mnt_sb; + inode->i_dev = NODEV; sock = socki_lookup(inode); inode->i_mode = S_IFSOCK|S_IRWXUGO; diff -Nur linux-2.4.19/net/sunrpc/sched.c linux-2.4.19-sgi211r3/net/sunrpc/sched.c --- linux-2.4.19/net/sunrpc/sched.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/net/sunrpc/sched.c Mon Oct 28 20:43:23 2002 @@ -770,8 +770,7 @@ } if (flags & RPC_TASK_ASYNC) return NULL; - current->policy |= SCHED_YIELD; - schedule(); + yield(); } while (!signalled()); return NULL; @@ -1112,8 +1111,7 @@ __rpc_schedule(); if (all_tasks) { dprintk("rpciod_killall: waiting for tasks to exit\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } @@ -1183,8 +1181,7 @@ * wait briefly before checking the process id. */ current->sigpending = 0; - current->policy |= SCHED_YIELD; - schedule(); + yield(); /* * Display a message if we're going to wait longer. */ diff -Nur linux-2.4.19/net/unix/af_unix.c linux-2.4.19-sgi211r3/net/unix/af_unix.c --- linux-2.4.19/net/unix/af_unix.c Fri Aug 2 17:39:46 2002 +++ linux-2.4.19-sgi211r3/net/unix/af_unix.c Mon Oct 28 20:43:23 2002 @@ -565,10 +565,8 @@ addr->hash)) { write_unlock(&unix_table_lock); /* Sanity yield. It is unusual case, but yet... */ - if (!(ordernum&0xFF)) { - current->policy |= SCHED_YIELD; - schedule(); - } + if (!(ordernum&0xFF)) + yield(); goto retry; } addr->hash ^= sk->type; diff -Nur linux-2.4.19/scripts/ia64_unwind_fix.pl linux-2.4.19-sgi211r3/scripts/ia64_unwind_fix.pl --- linux-2.4.19/scripts/ia64_unwind_fix.pl Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-sgi211r3/scripts/ia64_unwind_fix.pl Tue Dec 17 13:44:38 2002 @@ -0,0 +1,827 @@ +#!/usr/bin/perl -w + +# Identify ia64 unwind entries where the body length is wrong and +# correct them. + +# Needs readelf command, preferably an ia64 version although the ia32 version +# may work. Specify the location of readelf with environment variable READELF, +# default is 'readelf'. + +# Addresses and offsets are hex strings, sizes and indices are decimal numbers. + +require 5; +use strict; +use integer; + +my $readelf = 'readelf'; +if (exists($ENV{'READELF'})) { + $readelf = $ENV{'READELF'}; +} + +######################################################################### + +# Not all versions of Perl support 64 bit integers, especially when cross +# compiling. val64 takes a hex string and returns a reference to an array +# containing two 32 bit values, most significant and least significant word. + +sub val64($) +{ + my $v = $_[0]; + $v =~ s/^0[xX]//; + $v = substr('0000000000000000' . $v, -16); + my @v = ( hex(substr($v, 0, 8)), hex(substr($v, 8, 8)) ); + return \@v; +} + +# Convert val64 to a hex string. + +sub val64s(\@) +{ + return '0' if ($_[0]->[0] == 0 && $_[0]->[1] == 0); + my $v = sprintf("%08x%08x", $_[0]->[0], $_[0]->[1]); + $v =~ s/^0+//; + return $v; +} + +# Calculate the difference of two val64 entries. To avoid carry problems on +# ix86, do it in 16 byte chunks. + +sub val64diff(\@\@) +{ + my $w00 = $_[0]->[0]; + my $w01 = $_[0]->[1]; + my $w10 = $_[1]->[0]; + my $w11 = $_[1]->[1]; + my @v = ( + (($w00 >> 16) & 0xffff) - (($w10 >> 16) & 0xffff), + ($w00 & 0xffff) - ($w10 & 0xffff), + (($w01 >> 16) & 0xffff) - (($w11 >> 16) & 0xffff), + ($w01 & 0xffff) - ($w11 & 0xffff) + ); + my $i; + for ($i = 3; $i > 0; --$i) { + --$v[$i-1] if ($v[$i] & 0x10000); + $v[$i] &= 0xffff; + } + @v = ( ($v[0] << 16) | $v[1], ($v[2] << 16) | $v[3] ); + return \@v; +} + +# Calculate the sum of two val64 entries. + +sub val64sum(\@\@) +{ + my $w00 = $_[0]->[0]; + my $w01 = $_[0]->[1]; + my $w10 = $_[1]->[0]; + my $w11 = $_[1]->[1]; + my @v = ( + (($w00 >> 16) & 0xffff) + (($w10 >> 16) & 0xffff), + ($w00 & 0xffff) + ($w10 & 0xffff), + (($w01 >> 16) & 0xffff) + (($w11 >> 16) & 0xffff), + ($w01 & 0xffff) + ($w11 & 0xffff) + ); + my $i; + for ($i = 3; $i > 0; --$i) { + ++$v[$i-1] if ($v[$i] & 0x10000); + $v[$i] &= 0xffff; + } + @v = ( ($v[0] << 16) | $v[1], ($v[2] << 16) | $v[3] ); + return \@v; +} + +sub rlz($) +{ + return(val64s(@{val64($_[0])})); # Remove leading zeros from hex numbers +} + +# +# Convert a value which might be a structure (even nested) to a string that is +# readable. +# NOTE: assumes no loops in the structures. +# + +sub pretty_print +{ + my $value = $_[0]; + my $type = ref $value ? ref $value : ''; + if (! $type) { + my $scalar = $value; + if (! defined $scalar) { + return " "; + } + $scalar =~ s/(['\\])/\\1/g; + return sprintf("'%s'", $scalar); + } + elsif ($value =~ /SCALAR\(/) { + return sprintf("ref '%s'", $$value); + } + elsif ($value =~ /ARRAY\(/) { + my @array = @{$_[0]}; + my ($i, $string); + $string = '['; + for ($i = 0; $i <= $#array; ++$i) { + $value = $array[$i]; + if (defined $value) { + $string .= &pretty_print($value); + } + $string .= ','; + } + chop($string) if ($string =~ ','); + $string .= ']'; + return $string; + } + elsif ($value =~ /HASH\(/) { + my %hash = %{$_[0]}; + my ($key, $string); + $string = '{'; + foreach $key (keys(%hash)) { + $value = $hash{$key}; + $key =~ s/(['\\])/\\1/g; + $string .= sprintf("'%s'=>", $key); + if (defined $value) { + $string .= &pretty_print($value); + } + $string .= ','; + } + chop($string) if ($string =~ ','); + $string .= '}'; + return $string; + } + else { + die "pretty_print: cannot convert data type $value"; + } +} + +######################################################################### + +# Extract the sections, symbols and unwind headers from the object. + +sub extract_data($\*\%\%\@) +{ + my ($object, $OBJECT, $section, $symaddr, $unwind) = @_; + undef(%{$section}); + undef(%{$symaddr}); + undef(@{$unwind}); + my @data; + my $in_section_data = 0; # processing section data from readelf + my $in_symbol_data = 0; # processing symbol data from readelf + my $num = 0; # which multi line is being processed + my @mult; # hold section data over multiple lines + my @f; # split fields from one line + # 0 unknown, 1 extracting relocation data, 2 extracted relocation data, + # 3 executable. + my $relocatable = 0; + my @secnum; # map section number to name + + @data = `$readelf -S -s -r $object`; # make readelf do most of the work + die("$0 no readelf output for $object\n") if ($#data < 0); + push(@data, ""); # trailing blank line removes test for EOF + foreach (@data) { + chomp(); + + # Two lines of data for each section. Sample output + # Section Headers: + # [Nr] Name Type Address Offset + # Size EntSize Flags Link Info Align + # [ 0] NULL 0000000000000000 00000000 + # 0000000000000000 0000000000000000 0 0 0 + # [ 1] .text PROGBITS e002000000000000 00010000 + # 00000000005f6fe0 0000000000000000 AX 0 0 32768 + # ... + # [25] .strtab STRTAB 0000000000000000 00adca90 + # 0000000000062a54 0000000000000000 0 0 1 + # Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) + # + # Address is non-zero for executables, zero for relocatables. + + if (/^Section Headers:/) { + $in_section_data = 1; + $num = 0; + next; + } + if ($in_section_data == 1) { + if (/^Key/) { + # End of section data. Map section number to name. + $in_section_data = 0; + foreach (keys(%{$section})) { + $secnum[$section->{$_}->{'number'}] = $_; + } + next; + } + s/[][]//g; + (@f) = split(); + if (++$num == 1) { + if ($f[0] eq 'Nr' || $f[0] eq '0') { + @mult = ('Nr'); + } else { + $f[1] = '.IA_64.unwind_info' if ($f[1] eq '.IA_64.unwind_inf'); # truncated output :( + $relocatable = 3 if ($f[3] !~ /^0+$/); + # Use section number and file offset to generate a pseudo address + if ($relocatable != 3) { + $f[3] = sprintf("%x%04x%08x", $f[0], @{val64($f[4])}); + } + @mult = ($f[0], $f[1], rlz($f[3]), rlz($f[4])); # section number, name, address, file offset + } + } elsif ($num == 2) { + if ($mult[0] ne "Nr") { + $section->{$mult[1]} = { # key is section name + 'number' => $mult[0], + 'address' => "$mult[2]", + 'file_offset' => $mult[3], + 'size' => hex($f[0]), + }; + } + $num = 0; + } + next; + } + + # One line of data for each symbol. Sample output + # Symbol table '.symtab' contains 22794 entries: + # Num: Value Size Type Bind Vis Ndx Name + # 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + # 1: e002000000000000 0 SECTION LOCAL DEFAULT 1 + # 2: e0020000005f6fe0 0 SECTION LOCAL DEFAULT 2 + # 3: e0020000005fad00 0 SECTION LOCAL DEFAULT 3 + # 4: e002000000666170 0 SECTION LOCAL DEFAULT 4 + # 5: e0020000006aba20 0 SECTION LOCAL DEFAULT 5 + # 6: e0020000006e4000 0 SECTION LOCAL DEFAULT 6 + # 7: e002100000714f40 0 SECTION LOCAL DEFAULT 7 + # 8: e00210000071bd50 0 SECTION LOCAL DEFAULT 8 + # 9: e00210000071bfe0 0 SECTION LOCAL DEFAULT 9 + # 10: e002100000720000 0 SECTION LOCAL DEFAULT 10 + # 11: e002100000728000 0 SECTION LOCAL DEFAULT 11 + # 12: e0021000007b0000 0 SECTION LOCAL DEFAULT 12 + # 13: e0021000007b4250 0 SECTION LOCAL DEFAULT 13 + # 14: e0021000007ba6f0 0 SECTION LOCAL DEFAULT 14 + # 15: e00210000089a6a8 0 SECTION LOCAL DEFAULT 15 + # 16: e0021000008a21b0 0 SECTION LOCAL DEFAULT 16 + # 17: e0021000008b1c80 0 SECTION LOCAL DEFAULT 17 + # 18: e0021000008dea40 0 SECTION LOCAL DEFAULT 18 + # 19: e002100000a2da70 0 SECTION LOCAL DEFAULT 19 + # 20: e002100000a44a70 0 SECTION LOCAL DEFAULT 20 + # 21: e002100000a469f8 0 SECTION LOCAL DEFAULT 21 + # 22: e002100000a47540 0 SECTION LOCAL DEFAULT 22 + # 23: 0000000000000000 0 SECTION LOCAL DEFAULT 23 + # 24: 0000000000000000 0 SECTION LOCAL DEFAULT 24 + # 25: 0000000000000000 0 SECTION LOCAL DEFAULT 25 + # 26: 0000000000000000 0 FILE LOCAL DEFAULT ABS acpi.c + # 27: e002100000a46a48 4 OBJECT LOCAL DEFAULT 21 layer_save.0 + # 28: e002100000a46a4c 4 OBJECT LOCAL DEFAULT 21 level_save.1 + # 29: e00200000000da40 0 FUNC LOCAL DEFAULT 1 acpi_get_crs_addr + # ... + # 22792: e0020000000900a0 0 FUNC GLOBAL DEFAULT 1 proc_dointvec_minmax + # 22793: e002000000291b20 0 FUNC GLOBAL DEFAULT 1 xfs_btree_readahead_core + # Blank line + # + # Value is an address for executables, offset within section for relocatables. + + if (/Symbol table '.symtab'/) { + $in_symbol_data = 1; + $num = 0; + next; + } + if ($in_symbol_data == 1) { + next if (/Num:/); + if (!/^ *[0-9]+:/) { + $in_symbol_data = 0; + next; + } + (@f) = split(); + next if ($#f <= 6); # no symbol name + next if ($f[6] !~ /^[0-9]+/); # ignore abs, und etc. + if (!defined($secnum[$f[6]])) { + die("$0 cannot find section data for symbol $_\n"); + } + my $section_name = $secnum[$f[6]]; + # If relocatable then $f[1] is an offset, convert it to an address + # using the section data. Not a real address, but as long as it + # uniquely identifies the symbol, it is good enough. + my $offset; + if ($relocatable != 3) { + $offset = rlz($f[1]); + $f[1] = val64s(@{val64sum(@{val64($f[1])}, @{val64($section->{$section_name}->{'address'})})}); + } + else { + $offset = val64s(@{val64diff(@{val64($f[1])}, @{val64($section->{$section_name}->{'address'})})}); + $f[1] = val64s(@{val64($f[1])}); # executables have real addresses, canonicalize it + } + # Duplicate symbol names, symbol address is master key + $symaddr->{$f[1]} = { 'name' => $f[7], + 'address' => $f[1], + 'offset' => $offset, + 'section_number' => $f[6], + 'section_name' => $section_name, + }; + next; + } + + # Three lines of unwind relocation data for each function. Sample output. + # Relocation section '.rela.IA_64.unwind' at offset 0x3770 contains 39 entries: + # Offset Info Type Symbol's Value Symbol's Name Addend + # 00000000 0005f R_IA64_SEGREL64LSB 0000000000000000 .text + 0 + # 00000008 0005f R_IA64_SEGREL64LSB 0000000000000000 .text + 10 + # 00000010 0005f R_IA64_SEGREL64LSB 0000000000000000 .IA_64.unwind_info + 0 + # 00000018 0005f R_IA64_SEGREL64LSB 0000000000000000 .text.init + 0 + # 00000020 0005f R_IA64_SEGREL64LSB 0000000000000000 .text.init + 90 + # ... + # Blank line + + if ($relocatable == 0 && /^Relocation section '.rela.IA_64.unwind'/) { + $relocatable = 1; + $num = 0; + next; + } + if ($relocatable == 1) { + if (/R_IA64_SEGREL64L/) { # ia32 readelf truncates the name + ++$num; + (@f) = split(); + if (!exists($section->{$f[4]})) { + die("$0 cannot find section data for reloc $_\n"); + } + # convert section name + offset to an address + my $addr = val64s(@{val64sum(@{val64($section->{$f[4]}->{'address'})}, @{val64($f[6])})}); + if ($num == 1) { + @mult = ($f[4], rlz($f[6]), $addr); + } + if ($num == 2) { + if ($mult[0] ne $f[4]) { + die("$0 start and end relocatable sections are different in $object ($mult[0], $f[4])\n"); + } + push(@mult, $addr, hex($f[6]) - hex($mult[1])); # end address, function size (dec) + } elsif ($num == 3) { + if ($f[4] ne '.IA_64.unwind_info') { + die("$0 relocatable data is not for .IA_64.unwind_info in $object ($f[4])\n"); + } + # need offset into .IA_64.unwind_info, not address + push(@mult, rlz($f[6])); + # dummy symbol name, start section name, start section offset, start address, end address, function size, info offset + push(@{$unwind}, { + 'symbol_name' => '??-' . $mult[0] . '+' . $mult[1], + 'section_name' => $mult[0], + 'start_offset' => $mult[1], + 'start_address' => $mult[2], + 'end_address' => $mult[3], + 'function_size' => $mult[4], + 'info_offset' => $mult[5], + }); + $num = 0; + } + } + $relocatable = 2 if (/^\s*$/); + next; + } + + } # loop over readelf data + + if (!exists($section->{'.IA_64.unwind_info'})) { + print(" **** Warning: could not find .IA_64.unwind_info section, object skipped\n"); + return; + } + die("$0 could not find .IA_64.unwind section in $object\n") if (!exists($section->{'.IA_64.unwind'})); + + # For executables we get no relocation data so we have no unwind data yet. + # Read the unwind section directly from the file. + # Note: assumes that the segment base starts at section 1. + if ($relocatable == 3) { + my ($i, $u); + my $unwsect = $section->{'.IA_64.unwind'}; + my $infosect = $section->{'.IA_64.unwind_info'}; + my $segbase = val64($section->{$secnum[1]}->{'address'}); + my $inforel = val64diff(@{val64($infosect->{'address'})}, @{$segbase}); + my $start = hex($unwsect->{'file_offset'}); + seek($OBJECT, $start, 0) || die("$0 cannot seek to $start in $object for .IA_64.unwind\n"); + for ($i = $unwsect->{'size'} / 24; $i > 0; --$i) { + if (read($OBJECT, $u, 24) != 24) { + die("$0 error $! reading .IA_64.unwind entry from $object\n"); + } + @mult = unpack('LLLLLL', $u); # unpack Q is optional, don't rely on it + my $sa = [$mult[1], $mult[0]]; # val64 format + my $ea = [$mult[3], $mult[2]]; + my $ia = [$mult[5], $mult[4]]; + my $size = hex(val64s(@{val64diff(@{$ea}, @{$sa})})); + next if ($size == 0); + push(@{$unwind}, { + 'symbol_name' => '??-' . val64s(@{$sa}), + 'start_address' => val64s(@{val64sum(@{$segbase}, @{$sa})}), + 'end_address' => val64s(@{val64sum(@{$segbase}, @{$ea})}), + 'function_size' => $size, + 'info_offset' => val64s(@{val64diff(@{$ia}, @{$inforel})}), + }); + } + } + + # Map unwind start address to symbol + foreach (@{$unwind}) { + if (exists($symaddr->{$_->{'start_address'}})) { + $_->{'symbol_name'} = $symaddr->{$_->{'start_address'}}->{'name'}; + } + } + +} + +sub decode_uleb128($$$) +{ + my $data = $_[0]; + my $i = $_[1]; + my $n = 0; + my $shift = 0; + my $c; + while(1) { + $c = unpack("\@${i}C", $data); + $n += ($c & 0x7f) << $shift; + $shift += 7; + ++$i; + last if (!($c & 0x80)); + } + $_[2] = $n; + return $i; +} + +sub encode_uleb128($) +{ + my $n = $_[0]; + my $c; + my $hex = ''; + while(1) { + $c = $n & 0x7f; + $n >>= 7; + $c |= 0x80 if ($n); + $hex .= sprintf("%02x", $c); + last if (!$n); + } + return $hex; +} + +my @decode_type; + +sub set_decode_type() +{ + my ($i, $mask, $type, $start, $end); + for ($i = 0; $i < 256; ++$i) { + $decode_type[0][$i] = '?'; + $decode_type[1][$i] = '?'; + } + foreach ( + # prologue body + [ 0, '00-- ----', 'R1' ], [ 1, '00-- ----', 'R1' ], + [ 0, '0100 0---', 'R2' ], [ 1, '0100 0---', 'R2' ], + [ 0, '0110 00--', 'R3' ], [ 1, '0110 00--', 'R3' ], + [ 0, '100- ----', 'P1' ], + [ 0, '1010 ----', 'P2' ], + [ 0, '1011 0---', 'P3' ], + [ 0, '1011 1000', 'P4' ], + [ 0, '1011 1001', 'P5' ], + [ 0, '110- ----', 'P6' ], + [ 0, '1110 ----', 'P7' ], + [ 0, '1111 0000', 'P8' ], + [ 0, '1111 0001', 'P9' ], + [ 0, '1111 1001', 'X1' ], + [ 0, '1111 1010', 'X2' ], + [ 0, '1111 1011', 'X3' ], + [ 0, '1111 1100', 'X4' ], + [ 0, '1111 1111', 'P10' ], + [ 1, '10-- ----', 'B1' ], + [ 1, '110- ----', 'B2' ], + [ 1, '1110 0000', 'B3' ], # manual only lists this form for B3 ... + [ 1, '1110 1010', 'ea' ], # ... but this one is used as well :( + [ 1, '1111 0000', 'B4' ], + [ 1, '1111 1000', 'B4' ], + [ 1, '1111 1001', 'X1' ], + [ 1, '1111 1010', 'X2' ], + [ 1, '1111 1011', 'X3' ], + [ 1, '1111 1100', 'X4' ], + ) { + $mask = '0b' . $_->[1]; + $mask =~ s/ //g; + $start = $end = $mask; + $start =~ s/-/0/g; + $end =~ s/-/1/g; + for ($i = oct($start); $i <= oct($end); ++$i) { + if ($decode_type[$_->[0]][$i] ne '?') { + die("$0 decode_type[$_->[0]][$i] already set to $decode_type[$_->[0]][$i], ignoring $_->[2]\n"); + } + $decode_type[$_->[0]][$i] = $_->[2]; + } + } +} + +# return bytes to skip +# 0 inbody +# 1 byte +# 2 data +# 3 value return 1 +# 4 value return 2 + +sub decode_r1() +{ + $_[0] = ($_[1] & 0x20) != 0; + $_[3] = $_[1] & 0x1f; + return 1; +} + +sub decode_r2() +{ + $_[0] = 0; + return decode_uleb128($_[2], 2, $_[3]); +} + +sub decode_r3() +{ + $_[0] = ($_[1] & 0x01) != 0; + return decode_uleb128($_[2], 1, $_[3]); +} + +sub decode_p1() +{ + return 1; +} + +sub decode_p2() +{ + return 2; +} + +sub decode_p3() +{ + return 2; +} + +sub decode_p5() +{ + return 4; +} + +sub decode_p6() +{ + return 1; +} + +sub decode_p7() +{ + my $l = decode_uleb128($_[2], 1, $_[3]); + if (($_[1] & 0x0f) == 0) { + $l = decode_uleb128($_[2], $l, $_[4]); + } + return $l; +} + +sub decode_p8() +{ + return decode_uleb128($_[2], 2, $_[3]); +} + +sub decode_p9() +{ + return 3; +} + +sub decode_p10() +{ + return 3; +} + +sub decode_b1() +{ + return 1; +} + +sub decode_b2() +{ + $_[3] = $_[1] & 0x1f; + return decode_uleb128($_[2], 1, $_[3]); +} + +sub decode_b3() +{ + my $l = decode_uleb128($_[2], 1, $_[3]); + return decode_uleb128($_[2], $l, $_[4]); +} + +sub decode_b4() +{ + return decode_uleb128($_[2], 1, $_[3]); +} + +sub decode_x1() +{ + my $l = decode_uleb128($_[2], 2, $_[3]); + return decode_uleb128($_[2], $l, $_[4]); +} + +sub decode_x2() +{ + return decode_uleb128($_[2], 3, $_[3]); +} + +sub decode_x3() +{ + my $l = decode_uleb128($_[2], 3, $_[3]); + return decode_uleb128($_[2], $l, $_[4]); +} + +sub decode_x4() +{ + return decode_uleb128($_[2], 4, $_[3]); +} + +my %decode_func = ( + 'R1' => \&decode_r1, + 'R2' => \&decode_r2, + 'R3' => \&decode_r3, + 'P1' => \&decode_p1, + 'P2' => \&decode_p2, + 'P3' => \&decode_p3, + 'P4' => sub { return 0; }, # Do not want to cope with P4 + 'P5' => \&decode_p5, + 'P6' => \&decode_p6, + 'P7' => \&decode_p7, + 'P8' => \&decode_p8, + 'P9' => \&decode_p9, + 'P10' => \&decode_p10, + 'X1' => \&decode_x1, + 'X2' => \&decode_x2, + 'X3' => \&decode_x3, + 'X4' => \&decode_x4, + 'B1' => \&decode_b1, + 'B2' => \&decode_b2, + 'B3' => \&decode_b3, + 'B4' => \&decode_b4, + 'ea' => sub { return 0; }, # yet another gas bug + ); + +my %ret1_name = ( 'R1' => 'rlen', + 'R2' => 'rlen', + 'R3' => 'rlen', + 'P7' => 't/spoff/pspoff', + 'P8' => 't/spoff/pspoff', + 'B2' => 't', + 'B3' => 't', + 'B4' => 'label', + 'X1' => 't', + 'X2' => 't', + 'X3' => 't', + 'X4' => 't', + ); + +my %ret2_name = ( 'P7' => 'size', + 'B3' => 'ecount', + 'X1' => 'spoff,pspoff', + 'X3' => 'spoff,pspoff', + ); + +# Extract the unwind info for each unwind entry. + +sub extract_info($\*$\@) +{ + my ($object, $OBJECT, $info_file_offset, $unwind) = @_; + die("$0 cannot handle objects > 4GB\n") if ($info_file_offset =~ /.{9,}$/); + $info_file_offset = hex($info_file_offset); + my $u; + $| = 1; + UNWIND: foreach $u (@{$unwind}) { + my $seek = $info_file_offset + hex($u->{'info_offset'}); + die("$0 cannot handle objects > 4GB\n") if ($seek < $info_file_offset); + seek($OBJECT, $seek, 0) || die("$0 cannot seek to $seek in $object for unwind info\n"); + my $data; + if (read($OBJECT, $data, 8) != 8) { + die("$0 error $! reading .IA_64.unwind_info header from $object at $seek\n"); + } + my $ulen; + ($ulen, $u->{'flags'}, $u->{'ver'}) = unpack('Vvv', $data); + next if ($ulen == 0); + $u->{'padding'} = 0; + $ulen *= 8; + if (read($OBJECT, $data, $ulen) != $ulen) { + die("$0 error $! reading .IA_64.unwind_info data from $object at $seek\n"); + } + my $inbody = 0; + my $i; + my @info_list; + for ($i = 0; $i < $ulen;) { + my $c = unpack('C', $data); + my $l; + my $ret1 = undef; + my $ret2 = undef; + if ($c == 0) { + $u->{'padding'}++; + $l = 1; + } + else { + while ($u->{'padding'}--) { + my %info_data = ( 'hex' => '00', + 'type' => 'PR1', + 'rlen' => '0', + ); + push(@info_list, \%info_data); + } + $u->{'padding'} = 0; + my $type = $decode_type[$inbody][$c]; + die("$0 no decode function for type $type, $c " . sprintf("0x%x", $seek) . "\n") if (!exists($decode_func{$type})); + $l = $decode_func{$type}($inbody, $c, $data, $ret1, $ret2); + next UNWIND if ($l == 0); # Do not want to cope with this type + my ($j, $h); + for ($j = 0; $j < $l; ++$j) { + $h .= sprintf("%02x", unpack("\@${j}C", $data)); + } + my %info_data = ( 'hex' => $h, + 'type' => ($inbody ? 'B' : 'P') . $type + ); + $info_data{$ret1_name{$type}} = $ret1 if (defined($ret1)); + $info_data{$ret2_name{$type}} = $ret2 if (defined($ret2)); + push(@info_list, \%info_data); + } + $data = substr($data, $l); + $i += $l; + } + $u->{'info'} = \@info_list; + } +} + +# Correct any unwind info that looks wrong. + +sub fix_info($\*$\@) +{ + my ($object, $OBJECT, $info_file_offset, $unwind) = @_; + my $u; + foreach $u (@{$unwind}) { + next if (!exists($u->{'info'})); + my $recs = $u->{'info'}; + my $adjust = $u->{'function_size'} / 16 * 3; + my $pr = 0; + my $br = 0; + my ($rec, $ref_br); + foreach $rec (@{$recs}) { + if ($rec->{'type'} =~ /^PR/) { + $adjust -= $rec->{'rlen'}; + ++$pr; + } + if ($rec->{'type'} =~ /^BR/) { + $adjust -= $rec->{'rlen'}; + ++$br; + $ref_br = $rec; + } + } + next if ($br != 1 || $pr != 1 || $adjust == 0); + my $new_rlen = $ref_br->{'rlen'} + $adjust; + printf("Adjusting %s by %s (%s %d -> %d)\n", $u->{'symbol_name'}, $adjust, $ref_br->{'type'}, $ref_br->{'rlen'}, $new_rlen); + my $hex = encode_uleb128($new_rlen); + if ($ref_br->{'type'} eq 'BR1') { + if ($new_rlen > 31) { + $hex = sprintf('%02x', oct('0b01100001')) . $hex; + printf(" Replacing BR1 with BR3\n"); + $ref_br->{'type'} = 'BR3'; + } + else { + $hex = sprintf('%02x', oct('0b00100000') + $new_rlen); + } + } else { + $hex = substr($ref_br->{'hex'}, 0, ($ref_br->{'type'} eq 'BR2' ? 4 : 2)) . $hex; + } + my $l = (length($hex) - length($ref_br->{'hex'})) / 2; + if ($u->{'padding'} < $l) { + printf("\n **** Warning: insufficient padding bytes, record not converted\n"); + printf("%s\n\n", &pretty_print($u)); + next; + } + $ref_br->{'rlen'} = $new_rlen; + printf(" Replacing '%s' with '%s'\n", $ref_br->{'hex'}, $hex); + $ref_br->{'hex'} = $hex; + $u->{'padding'} -= $l; + my $seek = hex($info_file_offset) + hex($u->{'info_offset'}) + 8; + seek($OBJECT, $seek, 0) || die("$0 cannot seek to $seek in $object for update of unwind info\n"); + foreach $rec (@{$recs}) { + print($OBJECT pack("H*", $rec->{'hex'})); + } + } +} + +# Extract and fix the unwind info in a single object. + +sub fix_object($) +{ + my $object = $_[0]; + my %section; + my %symaddr; + my @unwind; + + print($object, "\n"); + open(OBJECT, "+<$object") || die("$0 cannot object $object for read/write\n"); + extract_data($object, *OBJECT, %section, %symaddr, @unwind); + if (exists($section{'.IA_64.unwind_info'})) { + my $info_file_offset = $section{'.IA_64.unwind_info'}->{'file_offset'}; + extract_info($object, *OBJECT, $info_file_offset, @unwind); + fix_info($object, *OBJECT, $info_file_offset, @unwind); + } + close(OBJECT); + print("\n"); +} + +# Mainline is trivial. + +die("$0 requires a list of objects to be fixed\n") if($#ARGV < 0); +set_decode_type(); +foreach (@ARGV) { + fix_object($_); +}